diff --git a/.gitignore b/.gitignore index ae8de00a8b9fdb6d730f2fffac31e11ec280dd3b..c62842976bdb7b9651aa0984472c9aa5d6e36e00 100644 --- a/.gitignore +++ b/.gitignore @@ -135,9 +135,3 @@ all.config # fetched Android config fragments kernel/configs/android-*.cfg - -# vendor device tree directories -arch/arm64/boot/dts/vendor/ - -# Tech package directories -techpack/ diff --git a/Makefile b/Makefile index c240b20902bca6fc19aef68169289e9072304b1b..f90ffe28db7d01a504429498fb008b35b7fcc420 100644 --- a/Makefile +++ b/Makefile @@ -418,6 +418,7 @@ LINUXINCLUDE := \ -I$(objtree)/arch/$(SRCARCH)/include/generated \ $(if $(KBUILD_SRC), -I$(srctree)/include) \ -I$(objtree)/include \ + -I$(srctree)/drivers/oneplus/include \ $(USERINCLUDE) KBUILD_AFLAGS := -D__ASSEMBLY__ @@ -590,7 +591,7 @@ export KBUILD_MODULES KBUILD_BUILTIN ifeq ($(KBUILD_EXTMOD),) # Objects we will link into vmlinux / subdirs we need to visit init-y := init/ -drivers-y := drivers/ sound/ firmware/ techpack/ +drivers-y := drivers/ sound/ firmware/ techpack/ opslalib/ net-y := net/ libs-y := lib/ core-y := usr/ diff --git a/arch/arm64/boot/dts/vendor/Makefile b/arch/arm64/boot/dts/vendor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..855132a4d23dfd832337d53d5d1da602bd9b69d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/Makefile @@ -0,0 +1,5 @@ +vendor := $(srctree)/$(src) + +ifneq "$(wildcard $(vendor)/qcom)" "" + subdir-y += qcom +endif diff --git a/arch/arm64/boot/dts/vendor/bindings/ABI.txt b/arch/arm64/boot/dts/vendor/bindings/ABI.txt new file mode 100644 index 0000000000000000000000000000000000000000..d25f8d3796806eee10a38e33187807489eea25b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ABI.txt @@ -0,0 +1,39 @@ + + Devicetree (DT) ABI + +I. Regarding stable bindings/ABI, we quote from the 2013 ARM mini-summit + summary document: + + "That still leaves the question of, what does a stable binding look + like? Certainly a stable binding means that a newer kernel will not + break on an older device tree, but that doesn't mean the binding is + frozen for all time. Grant said there are ways to change bindings that + don't result in breakage. For instance, if a new property is added, + then default to the previous behaviour if it is missing. If a binding + truly needs an incompatible change, then change the compatible string + at the same time. The driver can bind against both the old and the + new. These guidelines aren't new, but they desperately need to be + documented." + +II. General binding rules + + 1) Maintainers, don't let perfect be the enemy of good. Don't hold up a + binding because it isn't perfect. + + 2) Use specific compatible strings so that if we need to add a feature (DMA) + in the future, we can create a new compatible string. See I. + + 3) Bindings can be augmented, but the driver shouldn't break when given + the old binding. ie. add additional properties, but don't change the + meaning of an existing property. For drivers, default to the original + behaviour when a newly added property is missing. + + 4) Don't submit bindings for staging or unstable. That will be decided by + the devicetree maintainers *after* discussion on the mailinglist. + +III. Notes + + 1) This document is intended as a general familiarization with the process as + decided at the 2013 Kernel Summit. When in doubt, the current word of the + devicetree maintainers overrules this document. In that situation, a patch + updating this document would be appreciated. diff --git a/arch/arm64/boot/dts/vendor/bindings/arc/archs-pct.txt b/arch/arm64/boot/dts/vendor/bindings/arc/archs-pct.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4b9dcee6d41a12579969691dab40289f21bfe58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arc/archs-pct.txt @@ -0,0 +1,17 @@ +* ARC HS Performance Counters + +The ARC HS can be configured with a pipeline performance monitor for counting +CPU and cache events like cache misses and hits. Like conventional PCT there +are 100+ hardware conditions dynamically mapped to up to 32 counters. +It also supports overflow interrupts. + +Required properties: + +- compatible : should contain + "snps,archs-pct" + +Example: + +pmu { + compatible = "snps,archs-pct"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arc/axs101.txt b/arch/arm64/boot/dts/vendor/bindings/arc/axs101.txt new file mode 100644 index 0000000000000000000000000000000000000000..48290d5178b549aa0bc92bdfb2d3df90e7cee028 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arc/axs101.txt @@ -0,0 +1,7 @@ +Synopsys DesignWare ARC Software Development Platforms Device Tree Bindings +--------------------------------------------------------------------------- + +SDP Main Board with an AXC001 CPU Card hoisting ARC700 core in silicon + +Required root node properties: + - compatible = "snps,axs101", "snps,arc-sdp"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arc/axs103.txt b/arch/arm64/boot/dts/vendor/bindings/arc/axs103.txt new file mode 100644 index 0000000000000000000000000000000000000000..6eea862e72b94d7f309363cc80a95b8182dc9d8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arc/axs103.txt @@ -0,0 +1,8 @@ +Synopsys DesignWare ARC Software Development Platforms Device Tree Bindings +--------------------------------------------------------------------------- + +SDP Main Board with an AXC003 FPGA Card which can contain various flavours of +HS38x cores. + +Required root node properties: + - compatible = "snps,axs103", "snps,arc-sdp"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arc/eznps.txt b/arch/arm64/boot/dts/vendor/bindings/arc/eznps.txt new file mode 100644 index 0000000000000000000000000000000000000000..1aa50c6406781ba3e02b7d1e4665184e5038326a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arc/eznps.txt @@ -0,0 +1,7 @@ +EZchip NPS Network Processor Platforms Device Tree Bindings +--------------------------------------------------------------------------- + +Appliance main board with NPS400 ASIC. + +Required root node properties: + - compatible = "ezchip,arc-nps"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arc/hsdk.txt b/arch/arm64/boot/dts/vendor/bindings/arc/hsdk.txt new file mode 100644 index 0000000000000000000000000000000000000000..be50654bbf61c185d334ac2b055ec66d6c88838c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arc/hsdk.txt @@ -0,0 +1,7 @@ +Synopsys DesignWare ARC HS Development Kit Device Tree Bindings +--------------------------------------------------------------------------- + +ARC HSDK Board with quad-core ARC HS38x4 in silicon. + +Required root node properties: + - compatible = "snps,hsdk"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arc/pct.txt b/arch/arm64/boot/dts/vendor/bindings/arc/pct.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e874d9a38a6e5cd4a60ba2651fc24a42285dc2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arc/pct.txt @@ -0,0 +1,20 @@ +* ARC Performance Counters + +The ARC700 can be configured with a pipeline performance monitor for counting +CPU and cache events like cache misses and hits. Like conventional PCT there +are 100+ hardware conditions dynamically mapped to up to 32 counters + +Note that: + * The ARC 700 PCT does not support interrupts; although HW events may be + counted, the HW events themselves cannot serve as a trigger for a sample. + +Required properties: + +- compatible : should contain + "snps,arc700-pct" + +Example: + +pmu { + compatible = "snps,arc700-pct"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/actions.txt b/arch/arm64/boot/dts/vendor/bindings/arm/actions.txt new file mode 100644 index 0000000000000000000000000000000000000000..d54f33c4e0daa7331e341c7c98eeac3bbf74a381 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/actions.txt @@ -0,0 +1,56 @@ +Actions Semi platforms device tree bindings +------------------------------------------- + + +S500 SoC +======== + +Required root node properties: + + - compatible : must contain "actions,s500" + + +Modules: + +Root node property compatible must contain, depending on module: + + - LeMaker Guitar: "lemaker,guitar" + + +Boards: + +Root node property compatible must contain, depending on board: + + - Allo.com Sparky: "allo,sparky" + - Cubietech CubieBoard6: "cubietech,cubieboard6" + - LeMaker Guitar Base Board rev. B: "lemaker,guitar-bb-rev-b", "lemaker,guitar" + + +S700 SoC +======== + +Required root node properties: + +- compatible : must contain "actions,s700" + + +Boards: + +Root node property compatible must contain, depending on board: + + - Cubietech CubieBoard7: "cubietech,cubieboard7" + + +S900 SoC +======== + +Required root node properties: + +- compatible : must contain "actions,s900" + + +Boards: + +Root node property compatible must contain, depending on board: + + - uCRobotics Bubblegum-96: "ucrobotics,bubblegum-96" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/al,alpine.txt b/arch/arm64/boot/dts/vendor/bindings/arm/al,alpine.txt new file mode 100644 index 0000000000000000000000000000000000000000..f404a4f9b165592b62562aea0c45b52ba19e477a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/al,alpine.txt @@ -0,0 +1,88 @@ +Annapurna Labs Alpine Platform Device Tree Bindings +--------------------------------------------------------------- + +Boards in the Alpine family shall have the following properties: + +* Required root node properties: +compatible: must contain "al,alpine" + +* Example: + +/ { + model = "Annapurna Labs Alpine Dev Board"; + compatible = "al,alpine"; + + ... +} + +* CPU node: + +The Alpine platform includes cortex-a15 cores. +enable-method: must be "al,alpine-smp" to allow smp [1] + +Example: + +cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "al,alpine-smp"; + + cpu@0 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <1>; + }; + + cpu@2 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <2>; + }; + + cpu@3 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <3>; + }; +}; + + +* Alpine CPU resume registers + +The CPU resume register are used to define required resume address after +reset. + +Properties: +- compatible : Should contain "al,alpine-cpu-resume". +- reg : Offset and length of the register set for the device + +Example: + +cpu_resume { + compatible = "al,alpine-cpu-resume"; + reg = <0xfbff5ed0 0x30>; +}; + +* Alpine System-Fabric Service Registers + +The System-Fabric Service Registers allow various operation on CPU and +system fabric, like powering CPUs off. + +Properties: +- compatible : Should contain "al,alpine-sysfabric-service" and "syscon". +- reg : Offset and length of the register set for the device + +Example: + +nb_service { + compatible = "al,alpine-sysfabric-service", "syscon"; + reg = <0xfb070000 0x10000>; +}; + +[1] arm/cpu-enable-method/al,alpine-smp diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/altera.txt b/arch/arm64/boot/dts/vendor/bindings/arm/altera.txt new file mode 100644 index 0000000000000000000000000000000000000000..558735aacca8981d0392fb1f3e0df3f3d50cf28b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/altera.txt @@ -0,0 +1,14 @@ +Altera's SoCFPGA platform device tree bindings +--------------------------------------------- + +Boards with Cyclone 5 SoC: +Required root node properties: +compatible = "altr,socfpga-cyclone5", "altr,socfpga"; + +Boards with Arria 5 SoC: +Required root node properties: +compatible = "altr,socfpga-arria5", "altr,socfpga"; + +Boards with Arria 10 SoC: +Required root node properties: +compatible = "altr,socfpga-arria10", "altr,socfpga"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-clk-manager.txt b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-clk-manager.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c28f1d12f45acf187130cebd6402df34c58d539 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-clk-manager.txt @@ -0,0 +1,11 @@ +Altera SOCFPGA Clock Manager + +Required properties: +- compatible : "altr,clk-mgr" +- reg : Should contain base address and length for Clock Manager + +Example: + clkmgr@ffd04000 { + compatible = "altr,clk-mgr"; + reg = <0xffd04000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-sdram-controller.txt b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-sdram-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..77ca635765e1323beeac680ea427efbd4252cef3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-sdram-controller.txt @@ -0,0 +1,12 @@ +Altera SOCFPGA SDRAM Controller + +Required properties: +- compatible : Should contain "altr,sdr-ctl" and "syscon". + syscon is required by the Altera SOCFPGA SDRAM EDAC. +- reg : Should contain 1 register range (address and length) + +Example: + sdr: sdr@ffc25000 { + compatible = "altr,sdr-ctl", "syscon"; + reg = <0xffc25000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-sdram-edac.txt b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-sdram-edac.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5ad0ff69faeffc7cf27928e2bffaadf7b9da6f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-sdram-edac.txt @@ -0,0 +1,15 @@ +Altera SOCFPGA SDRAM Error Detection & Correction [EDAC] +The EDAC accesses a range of registers in the SDRAM controller. + +Required properties: +- compatible : should contain "altr,sdram-edac" or "altr,sdram-edac-a10" +- altr,sdr-syscon : phandle of the sdr module +- interrupts : Should contain the SDRAM ECC IRQ in the + appropriate format for the IRQ controller. + +Example: + sdramedac { + compatible = "altr,sdram-edac"; + altr,sdr-syscon = <&sdr>; + interrupts = <0 39 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-system.txt b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-system.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4d04a0672824087de6987b6be4dfd5c4fd2bf84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/altera/socfpga-system.txt @@ -0,0 +1,13 @@ +Altera SOCFPGA System Manager + +Required properties: +- compatible : "altr,sys-mgr" +- reg : Should contain 1 register ranges(address and length) +- cpu1-start-addr : CPU1 start address in hex. + +Example: + sysmgr@ffd08000 { + compatible = "altr,sys-mgr"; + reg = <0xffd08000 0x1000>; + cpu1-start-addr = <0xffd080c4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic,scpi.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic,scpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b9a861e9306dbf705f19af8bec94f46b011fcb1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic,scpi.txt @@ -0,0 +1,20 @@ +System Control and Power Interface (SCPI) Message Protocol +(in addition to the standard binding in [0]) +---------------------------------------------------------- +Required properties + +- compatible : should be "amlogic,meson-gxbb-scpi" + +AMLOGIC SRAM and Shared Memory for SCPI +------------------------------------ + +Required properties: +- compatible : should be "amlogic,meson-gxbb-sram" + +Each sub-node represents the reserved area for SCPI. + +Required sub-node properties: +- compatible : should be "amlogic,meson-gxbb-scp-shmem" for SRAM based shared + memory on Amlogic GXBB SoC. + +[0] Documentation/devicetree/bindings/arm/arm,scpi.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5c2b5c35766f8db4fb8a3dd66d9cf9b4a395209 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic.txt @@ -0,0 +1,131 @@ +Amlogic MesonX device tree bindings +------------------------------------------- + +Work in progress statement: + +Device tree files and bindings applying to Amlogic SoCs and boards are +considered "unstable". Any Amlogic device tree binding may change at +any time. Be sure to use a device tree binary and a kernel image +generated from the same source tree. + +Please refer to Documentation/devicetree/bindings/ABI.txt for a definition of a +stable binding/ABI. + +--------------------------------------------------------------- + +Boards with the Amlogic Meson6 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson6" + +Boards with the Amlogic Meson8 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson8"; + +Boards with the Amlogic Meson8b SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson8b"; + +Boards with the Amlogic Meson8m2 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson8m2"; + +Boards with the Amlogic Meson GXBaby SoC shall have the following properties: + Required root node property: + compatible: "amlogic,meson-gxbb"; + +Boards with the Amlogic Meson GXL S905X SoC shall have the following properties: + Required root node property: + compatible: "amlogic,s905x", "amlogic,meson-gxl"; + +Boards with the Amlogic Meson GXL S905D SoC shall have the following properties: + Required root node property: + compatible: "amlogic,s905d", "amlogic,meson-gxl"; + +Boards with the Amlogic Meson GXL S805X SoC shall have the following properties: + Required root node property: + compatible: "amlogic,s805x", "amlogic,meson-gxl"; + +Boards with the Amlogic Meson GXL S905W SoC shall have the following properties: + Required root node property: + compatible: "amlogic,s905w", "amlogic,meson-gxl"; + +Boards with the Amlogic Meson GXM S912 SoC shall have the following properties: + Required root node property: + compatible: "amlogic,s912", "amlogic,meson-gxm"; + +Boards with the Amlogic Meson AXG A113D SoC shall have the following properties: + Required root node property: + compatible: "amlogic,a113d", "amlogic,meson-axg"; + +Board compatible values (alphabetically, grouped by SoC): + + - "geniatech,atv1200" (Meson6) + + - "minix,neo-x8" (Meson8) + + - "hardkernel,odroid-c1" (Meson8b) + - "tronfy,mxq" (Meson8b) + + - "tronsmart,mxiii-plus" (Meson8m2) + + - "amlogic,p200" (Meson gxbb) + - "amlogic,p201" (Meson gxbb) + - "friendlyarm,nanopi-k2" (Meson gxbb) + - "hardkernel,odroid-c2" (Meson gxbb) + - "nexbox,a95x" (Meson gxbb or Meson gxl s905x) + - "tronsmart,vega-s95-pro", "tronsmart,vega-s95" (Meson gxbb) + - "tronsmart,vega-s95-meta", "tronsmart,vega-s95" (Meson gxbb) + - "tronsmart,vega-s95-telos", "tronsmart,vega-s95" (Meson gxbb) + - "wetek,hub" (Meson gxbb) + - "wetek,play2" (Meson gxbb) + + - "amlogic,p212" (Meson gxl s905x) + - "hwacom,amazetv" (Meson gxl s905x) + - "khadas,vim" (Meson gxl s905x) + - "libretech,cc" (Meson gxl s905x) + + - "amlogic,p230" (Meson gxl s905d) + - "amlogic,p231" (Meson gxl s905d) + + - "amlogic,p241" (Meson gxl s805x) + + - "amlogic,p281" (Meson gxl s905w) + - "oranth,tx3-mini" (Meson gxl s905w) + + - "amlogic,q200" (Meson gxm s912) + - "amlogic,q201" (Meson gxm s912) + - "khadas,vim2" (Meson gxm s912) + - "kingnovel,r-box-pro" (Meson gxm S912) + - "nexbox,a1" (Meson gxm s912) + - "tronsmart,vega-s96" (Meson gxm s912) + + - "amlogic,s400" (Meson axg a113d) + +Amlogic Meson Firmware registers Interface +------------------------------------------ + +The Meson SoCs have a register bank with status and data shared with the +secure firmware. + +Required properties: + - compatible: For Meson GX SoCs, must be "amlogic,meson-gx-ao-secure", "syscon" + +Properties should indentify components of this register interface : + +Meson GX SoC Information +------------------------ +A firmware register encodes the SoC type, package and revision information on +the Meson GX SoCs. +If present, the following property should be added : + +Optional properties: + - amlogic,has-chip-id: If present, the interface gives the current SoC version. + +Example +------- + +ao-secure@140 { + compatible = "amlogic,meson-gx-ao-secure", "syscon"; + reg = <0x0 0x140 0x0 0x140>; + amlogic,has-chip-id; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/analog-top.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/analog-top.txt new file mode 100644 index 0000000000000000000000000000000000000000..101dc21014ece985dc8d33921769f0ab924023e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/analog-top.txt @@ -0,0 +1,20 @@ +Amlogic Meson8 and Meson8b "analog top" registers: +-------------------------------------------------- + +The analog top registers contain information about the so-called +"metal revision" (which encodes the "minor version") of the SoC. + +Required properties: +- reg: the register range of the analog top registers +- compatible: depending on the SoC this should be one of: + - "amlogic,meson8-analog-top" + - "amlogic,meson8b-analog-top" + along with "syscon" + + +Example: + + analog_top: analog-top@81a8 { + compatible = "amlogic,meson8-analog-top", "syscon"; + reg = <0x81a8 0x14>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/assist.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/assist.txt new file mode 100644 index 0000000000000000000000000000000000000000..7656812b67b9dbfa9b51a5d06e70274101bad1d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/assist.txt @@ -0,0 +1,17 @@ +Amlogic Meson6/Meson8/Meson8b assist registers: +----------------------------------------------- + +The assist registers contain basic information about the SoC, +for example the encoded SoC part number. + +Required properties: +- reg: the register range of the assist registers +- compatible: should be "amlogic,meson-mx-assist" along with "syscon" + + +Example: + + assist: assist@7c00 { + compatible = "amlogic,meson-mx-assist", "syscon"; + reg = <0x7c00 0x200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/bootrom.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/bootrom.txt new file mode 100644 index 0000000000000000000000000000000000000000..407e27f230aba202619ffd077b8e0cf70f9ce3b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/bootrom.txt @@ -0,0 +1,17 @@ +Amlogic Meson6/Meson8/Meson8b bootrom: +-------------------------------------- + +The bootrom register area can be used to access SoC specific +information, such as the "misc version". + +Required properties: +- reg: the register range of the bootrom registers +- compatible: should be "amlogic,meson-mx-bootrom" along with "syscon" + + +Example: + + bootrom: bootrom@d9040000 { + compatible = "amlogic,meson-mx-bootrom", "syscon"; + reg = <0xd9040000 0x10000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/pmu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..72f8d08198b6fbf4b826e0457a62b84f2251879f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/pmu.txt @@ -0,0 +1,18 @@ +Amlogic Meson8 and Meson8b power-management-unit: +------------------------------------------------- + +The pmu is used to turn off and on different power domains of the SoCs +This includes the power to the CPU cores. + +Required node properties: +- compatible value : depending on the SoC this should be one of: + "amlogic,meson8-pmu" + "amlogic,meson8b-pmu" +- reg : physical base address and the size of the registers window + +Example: + + pmu@c81000e4 { + compatible = "amlogic,meson8b-pmu", "syscon"; + reg = <0xc81000e0 0x18>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/smp-sram.txt b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/smp-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..3473ddaadfac2c19c8feeb603752de054d98598f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/amlogic/smp-sram.txt @@ -0,0 +1,32 @@ +Amlogic Meson8 and Meson8b SRAM for smp bringup: +------------------------------------------------ + +Amlogic's SMP-capable SoCs use part of the sram for the bringup of the cores. +Once the core gets powered up it executes the code that is residing at a +specific location. + +Therefore a reserved section sub-node has to be added to the mmio-sram +declaration. + +Required sub-node properties: +- compatible : depending on the SoC this should be one of: + "amlogic,meson8-smp-sram" + "amlogic,meson8b-smp-sram" + +The rest of the properties should follow the generic mmio-sram discription +found in ../../misc/sram.txt + +Example: + + sram: sram@d9000000 { + compatible = "mmio-sram"; + reg = <0xd9000000 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0xd9000000 0x20000>; + + smp-sram@1ff80 { + compatible = "amlogic,meson8b-smp-sram"; + reg = <0x1ff80 0x8>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/apm/scu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/apm/scu.txt new file mode 100644 index 0000000000000000000000000000000000000000..b45be06625fdd70da7625b30b75755d808cecc69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/apm/scu.txt @@ -0,0 +1,17 @@ +APM X-GENE SoC series SCU Registers + +This system clock unit contain various register that control block resets, +clock enable/disables, clock divisors and other deepsleep registers. + +Properties: + - compatible : should contain two values. First value must be: + - "apm,xgene-scu" + second value must be always "syscon". + + - reg : offset and length of the register set. + +Example : + scu: system-clk-controller@17000000 { + compatible = "apm,xgene-scu","syscon"; + reg = <0x0 0x17000000 0x0 0x400>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/arm,scmi.txt b/arch/arm64/boot/dts/vendor/bindings/arm/arm,scmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f3719ab7075af8952864e4156e28f29c8abb943 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/arm,scmi.txt @@ -0,0 +1,179 @@ +System Control and Management Interface (SCMI) Message Protocol +---------------------------------------------------------- + +The SCMI is intended to allow agents such as OSPM to manage various functions +that are provided by the hardware platform it is running on, including power +and performance functions. + +This binding is intended to define the interface the firmware implementing +the SCMI as described in ARM document number ARM DUI 0922B ("ARM System Control +and Management Interface Platform Design Document")[0] provide for OSPM in +the device tree. + +Required properties: + +The scmi node with the following properties shall be under the /firmware/ node. + +- compatible : shall be "arm,scmi" +- mboxes: List of phandle and mailbox channel specifiers. It should contain + exactly one or two mailboxes, one for transmitting messages("tx") + and another optional for receiving the notifications("rx") if + supported. +- shmem : List of phandle pointing to the shared memory(SHM) area as per + generic mailbox client binding. +- #address-cells : should be '1' if the device has sub-nodes, maps to + protocol identifier for a given sub-node. +- #size-cells : should be '0' as 'reg' property doesn't have any size + associated with it. + +Optional properties: + +- mbox-names: shall be "tx" or "rx" depending on mboxes entries. + +See Documentation/devicetree/bindings/mailbox/mailbox.txt for more details +about the generic mailbox controller and client driver bindings. + +The mailbox is the only permitted method of calling the SCMI firmware. +Mailbox doorbell is used as a mechanism to alert the presence of a +messages and/or notification. + +Each protocol supported shall have a sub-node with corresponding compatible +as described in the following sections. If the platform supports dedicated +communication channel for a particular protocol, the 3 properties namely: +mboxes, mbox-names and shmem shall be present in the sub-node corresponding +to that protocol. + +Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol +------------------------------------------------------------ + +This binding uses the common clock binding[1]. + +Required properties: +- #clock-cells : Should be 1. Contains the Clock ID value used by SCMI commands. + +Power domain bindings for the power domains based on SCMI Message Protocol +------------------------------------------------------------ + +This binding for the SCMI power domain providers uses the generic power +domain binding[2]. + +Required properties: + - #power-domain-cells : Should be 1. Contains the device or the power + domain ID value used by SCMI commands. + +Sensor bindings for the sensors based on SCMI Message Protocol +-------------------------------------------------------------- +SCMI provides an API to access the various sensors on the SoC. + +Required properties: +- #thermal-sensor-cells: should be set to 1. This property follows the + thermal device tree bindings[3]. + + Valid cell values are raw identifiers (Sensor ID) + as used by the firmware. Refer to platform details + for your implementation for the IDs to use. + +SRAM and Shared Memory for SCMI +------------------------------- + +A small area of SRAM is reserved for SCMI communication between application +processors and SCP. + +The properties should follow the generic mmio-sram description found in [4] + +Each sub-node represents the reserved area for SCMI. + +Required sub-node properties: +- reg : The base offset and size of the reserved area with the SRAM +- compatible : should be "arm,scmi-shmem" for Non-secure SRAM based + shared memory + +[0] http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/index.html +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/power/power_domain.txt +[3] Documentation/devicetree/bindings/thermal/thermal.txt +[4] Documentation/devicetree/bindings/sram/sram.txt + +Example: + +sram@50000000 { + compatible = "mmio-sram"; + reg = <0x0 0x50000000 0x0 0x10000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x50000000 0x10000>; + + cpu_scp_lpri: scp-shmem@0 { + compatible = "arm,scmi-shmem"; + reg = <0x0 0x200>; + }; + + cpu_scp_hpri: scp-shmem@200 { + compatible = "arm,scmi-shmem"; + reg = <0x200 0x200>; + }; +}; + +mailbox@40000000 { + .... + #mbox-cells = <1>; + reg = <0x0 0x40000000 0x0 0x10000>; +}; + +firmware { + + ... + + scmi { + compatible = "arm,scmi"; + mboxes = <&mailbox 0 &mailbox 1>; + mbox-names = "tx", "rx"; + shmem = <&cpu_scp_lpri &cpu_scp_hpri>; + #address-cells = <1>; + #size-cells = <0>; + + scmi_devpd: protocol@11 { + reg = <0x11>; + #power-domain-cells = <1>; + }; + + scmi_dvfs: protocol@13 { + reg = <0x13>; + #clock-cells = <1>; + }; + + scmi_clk: protocol@14 { + reg = <0x14>; + #clock-cells = <1>; + }; + + scmi_sensors0: protocol@15 { + reg = <0x15>; + #thermal-sensor-cells = <1>; + }; + }; +}; + +cpu@0 { + ... + reg = <0 0>; + clocks = <&scmi_dvfs 0>; +}; + +hdlcd@7ff60000 { + ... + reg = <0 0x7ff60000 0 0x1000>; + clocks = <&scmi_clk 4>; + power-domains = <&scmi_devpd 1>; +}; + +thermal-zones { + soc_thermal { + polling-delay-passive = <100>; + polling-delay = <1000>; + /* sensor ID */ + thermal-sensors = <&scmi_sensors0 3>; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/arm,scpi.txt b/arch/arm64/boot/dts/vendor/bindings/arm/arm,scpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..401831973638d6c9d22dc8432313cbd2956a1246 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/arm,scpi.txt @@ -0,0 +1,219 @@ +System Control and Power Interface (SCPI) Message Protocol +---------------------------------------------------------- + +Firmware implementing the SCPI described in ARM document number ARM DUI 0922B +("ARM Compute Subsystem SCP: Message Interface Protocols")[0] can be used +by Linux to initiate various system control and power operations. + +Required properties: + +- compatible : should be + * "arm,scpi" : For implementations complying to SCPI v1.0 or above + * "arm,scpi-pre-1.0" : For implementations complying to all + unversioned releases prior to SCPI v1.0 +- mboxes: List of phandle and mailbox channel specifiers + All the channels reserved by remote SCP firmware for use by + SCPI message protocol should be specified in any order +- shmem : List of phandle pointing to the shared memory(SHM) area between the + processors using these mailboxes for IPC, one for each mailbox + SHM can be any memory reserved for the purpose of this communication + between the processors. + +See Documentation/devicetree/bindings/mailbox/mailbox.txt +for more details about the generic mailbox controller and +client driver bindings. + +Clock bindings for the clocks based on SCPI Message Protocol +------------------------------------------------------------ + +This binding uses the common clock binding[1]. + +Container Node +============== +Required properties: +- compatible : should be "arm,scpi-clocks" + All the clocks provided by SCP firmware via SCPI message + protocol much be listed as sub-nodes under this node. + +Sub-nodes +========= +Required properties: +- compatible : shall include one of the following + "arm,scpi-dvfs-clocks" - all the clocks that are variable and index based. + These clocks don't provide an entire range of values between the + limits but only discrete points within the range. The firmware + provides the mapping for each such operating frequency and the + index associated with it. The firmware also manages the + voltage scaling appropriately with the clock scaling. + "arm,scpi-variable-clocks" - all the clocks that are variable and provide full + range within the specified range. The firmware provides the + range of values within a specified range. + +Other required properties for all clocks(all from common clock binding): +- #clock-cells : Should be 1. Contains the Clock ID value used by SCPI commands. +- clock-output-names : shall be the corresponding names of the outputs. +- clock-indices: The identifying number for the clocks(i.e.clock_id) in the + node. It can be non linear and hence provide the mapping of identifiers + into the clock-output-names array. + +SRAM and Shared Memory for SCPI +------------------------------- + +A small area of SRAM is reserved for SCPI communication between application +processors and SCP. + +The properties should follow the generic mmio-sram description found in [3] + +Each sub-node represents the reserved area for SCPI. + +Required sub-node properties: +- reg : The base offset and size of the reserved area with the SRAM +- compatible : should be "arm,scp-shmem" for Non-secure SRAM based + shared memory + +Sensor bindings for the sensors based on SCPI Message Protocol +-------------------------------------------------------------- +SCPI provides an API to access the various sensors on the SoC. + +Required properties: +- compatible : should be "arm,scpi-sensors". +- #thermal-sensor-cells: should be set to 1. This property follows the + thermal device tree bindings[2]. + + Valid cell values are raw identifiers (Sensor ID) + as used by the firmware. Refer to platform details + for your implementation for the IDs to use. + +Power domain bindings for the power domains based on SCPI Message Protocol +------------------------------------------------------------ + +This binding uses the generic power domain binding[4]. + +PM domain providers +=================== + +Required properties: + - #power-domain-cells : Should be 1. Contains the device or the power + domain ID value used by SCPI commands. + - num-domains: Total number of power domains provided by SCPI. This is + needed as the SCPI message protocol lacks a mechanism to + query this information at runtime. + +PM domain consumers +=================== + +Required properties: + - power-domains : A phandle and PM domain specifier as defined by bindings of + the power controller specified by phandle. + +[0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/thermal/thermal.txt +[3] Documentation/devicetree/bindings/sram/sram.txt +[4] Documentation/devicetree/bindings/power/power_domain.txt + +Example: + +sram: sram@50000000 { + compatible = "arm,juno-sram-ns", "mmio-sram"; + reg = <0x0 0x50000000 0x0 0x10000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x50000000 0x10000>; + + cpu_scp_lpri: scp-shmem@0 { + compatible = "arm,juno-scp-shmem"; + reg = <0x0 0x200>; + }; + + cpu_scp_hpri: scp-shmem@200 { + compatible = "arm,juno-scp-shmem"; + reg = <0x200 0x200>; + }; +}; + +mailbox: mailbox0@40000000 { + .... + #mbox-cells = <1>; +}; + +scpi_protocol: scpi@2e000000 { + compatible = "arm,scpi"; + mboxes = <&mailbox 0 &mailbox 1>; + shmem = <&cpu_scp_lpri &cpu_scp_hpri>; + + clocks { + compatible = "arm,scpi-clocks"; + + scpi_dvfs: scpi_clocks@0 { + compatible = "arm,scpi-dvfs-clocks"; + #clock-cells = <1>; + clock-indices = <0>, <1>, <2>; + clock-output-names = "atlclk", "aplclk","gpuclk"; + }; + scpi_clk: scpi_clocks@3 { + compatible = "arm,scpi-variable-clocks"; + #clock-cells = <1>; + clock-indices = <3>, <4>; + clock-output-names = "pxlclk0", "pxlclk1"; + }; + }; + + scpi_sensors0: sensors { + compatible = "arm,scpi-sensors"; + #thermal-sensor-cells = <1>; + }; + + scpi_devpd: scpi-power-domains { + compatible = "arm,scpi-power-domains"; + num-domains = <2>; + #power-domain-cells = <1>; + }; +}; + +cpu@0 { + ... + reg = <0 0>; + clocks = <&scpi_dvfs 0>; +}; + +hdlcd@7ff60000 { + ... + reg = <0 0x7ff60000 0 0x1000>; + clocks = <&scpi_clk 4>; + power-domains = <&scpi_devpd 1>; +}; + +thermal-zones { + soc_thermal { + polling-delay-passive = <100>; + polling-delay = <1000>; + + /* sensor ID */ + thermal-sensors = <&scpi_sensors0 3>; + ... + }; +}; + +In the above example, the #clock-cells is set to 1 as required. +scpi_dvfs has 3 output clocks namely: atlclk, aplclk, and gpuclk with 0, +1 and 2 as clock-indices. scpi_clk has 2 output clocks namely: pxlclk0 +and pxlclk1 with 3 and 4 as clock-indices. + +The first consumer in the example is cpu@0 and it has '0' as the clock +specifier which points to the first entry in the output clocks of +scpi_dvfs i.e. "atlclk". + +Similarly the second example is hdlcd@7ff60000 and it has pxlclk1 as input +clock. '4' in the clock specifier here points to the second entry +in the output clocks of scpi_clocks i.e. "pxlclk1" + +The thermal-sensors property in the soc_thermal node uses the +temperature sensor provided by SCP firmware to setup a thermal +zone. The ID "3" is the sensor identifier for the temperature sensor +as used by the firmware. + +The num-domains property in scpi-power-domains domain specifies that +SCPI provides 2 power domains. The hdlcd node uses the power domain with +domain ID 1. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/arm-boards b/arch/arm64/boot/dts/vendor/bindings/arm/arm-boards new file mode 100644 index 0000000000000000000000000000000000000000..b6e810c2781a4ec855a34fc0e8c5eb85c8f7e5b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/arm-boards @@ -0,0 +1,237 @@ +ARM Integrator/AP (Application Platform) and Integrator/CP (Compact Platform) +----------------------------------------------------------------------------- +ARM's oldest Linux-supported platform with connectors for different core +tiles of ARMv4, ARMv5 and ARMv6 type. + +Required properties (in root node): + compatible = "arm,integrator-ap"; /* Application Platform */ + compatible = "arm,integrator-cp"; /* Compact Platform */ + +FPGA type interrupt controllers, see the versatile-fpga-irq binding doc. + +Required nodes: + +- core-module: the root node to the Integrator platforms must have + a core-module with regs and the compatible string + "arm,core-module-integrator" +- external-bus-interface: the root node to the Integrator platforms + must have an external bus interface with regs and the + compatible-string "arm,external-bus-interface" + + Required properties for the core module: + - regs: the location and size of the core module registers, one + range of 0x200 bytes. + +- syscon: the root node of the Integrator platforms must have a + system controller node pointing to the control registers, + with the compatible string + "arm,integrator-ap-syscon" + "arm,integrator-cp-syscon" + respectively. + + Required properties for the system controller: + - regs: the location and size of the system controller registers, + one range of 0x100 bytes. + + Required properties for the AP system controller: + - interrupts: the AP syscon node must include the logical module + interrupts, stated in order of module instance , + , ... for the CP system controller this + is not required not of any use. + +/dts-v1/; +/include/ "integrator.dtsi" + +/ { + model = "ARM Integrator/AP"; + compatible = "arm,integrator-ap"; + + core-module@10000000 { + compatible = "arm,core-module-integrator"; + reg = <0x10000000 0x200>; + }; + + ebi@12000000 { + compatible = "arm,external-bus-interface"; + reg = <0x12000000 0x100>; + }; + + syscon { + compatible = "arm,integrator-ap-syscon"; + reg = <0x11000000 0x100>; + interrupt-parent = <&pic>; + /* These are the logic module IRQs */ + interrupts = <9>, <10>, <11>, <12>; + }; +}; + + +ARM Versatile Application and Platform Baseboards +------------------------------------------------- +ARM's development hardware platform with connectors for customizable +core tiles. The hardware configuration of the Versatile boards is +highly customizable. + +Required properties (in root node): + compatible = "arm,versatile-ab"; /* Application baseboard */ + compatible = "arm,versatile-pb"; /* Platform baseboard */ + +Interrupt controllers: +- VIC required properties: + compatible = "arm,versatile-vic"; + interrupt-controller; + #interrupt-cells = <1>; + +- SIC required properties: + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; + +Required nodes: + +- core-module: the root node to the Versatile platforms must have + a core-module with regs and the compatible strings + "arm,core-module-versatile", "syscon" + +Optional nodes: + +- arm,versatile-ib2-syscon : if the Versatile has an IB2 interface + board mounted, this has a separate system controller that is + defined in this node. + Required properties: + compatible = "arm,versatile-ib2-syscon", "syscon" + +ARM RealView Boards +------------------- +The RealView boards cover tailored evaluation boards that are used to explore +the ARM11 and Cortex A-8 and Cortex A-9 processors. + +Required properties (in root node): + /* RealView Emulation Baseboard */ + compatible = "arm,realview-eb"; + /* RealView Platform Baseboard for ARM1176JZF-S */ + compatible = "arm,realview-pb1176"; + /* RealView Platform Baseboard for ARM11 MPCore */ + compatible = "arm,realview-pb11mp"; + /* RealView Platform Baseboard for Cortex A-8 */ + compatible = "arm,realview-pba8"; + /* RealView Platform Baseboard Explore for Cortex A-9 */ + compatible = "arm,realview-pbx"; + +Required nodes: + +- soc: some node of the RealView platforms must be the SoC + node that contain the SoC-specific devices, withe the compatible + string set to one of these tuples: + "arm,realview-eb-soc", "simple-bus" + "arm,realview-pb1176-soc", "simple-bus" + "arm,realview-pb11mp-soc", "simple-bus" + "arm,realview-pba8-soc", "simple-bus" + "arm,realview-pbx-soc", "simple-bus" + +- syscon: some subnode of the RealView SoC node must be a + system controller node pointing to the control registers, + with the compatible string set to one of these: + "arm,realview-eb11mp-revb-syscon", "arm,realview-eb-syscon", "syscon" + "arm,realview-eb11mp-revc-syscon", "arm,realview-eb-syscon", "syscon" + "arm,realview-eb-syscon", "syscon" + "arm,realview-pb1176-syscon", "syscon" + "arm,realview-pb11mp-syscon", "syscon" + "arm,realview-pba8-syscon", "syscon" + "arm,realview-pbx-syscon", "syscon" + + Required properties for the system controller: + - regs: the location and size of the system controller registers, + one range of 0x1000 bytes. + +Example: + +/dts-v1/; +#include + +/ { + model = "ARM RealView PB1176 with device tree"; + compatible = "arm,realview-pb1176"; + #address-cells = <1>; + #size-cells = <1>; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "arm,realview-pb1176-soc", "simple-bus"; + ranges; + + syscon: syscon@10000000 { + compatible = "arm,realview-syscon", "syscon"; + reg = <0x10000000 0x1000>; + }; + + }; +}; + +ARM Versatile Express Boards +----------------------------- +For details on the device tree bindings for ARM Versatile Express boards +please consult the vexpress.txt file in the same directory as this file. + +ARM Juno Boards +---------------- +The Juno boards are targeting development for AArch64 systems. The first +iteration, Juno r0, is a vehicle for evaluating big.LITTLE on AArch64, +with the second iteration, Juno r1, mainly aimed at development of PCIe +based systems. Juno r1 also has support for AXI masters placed on the TLX +connectors to join the coherency domain. + +Juno boards are described in a similar way to ARM Versatile Express boards, +with the motherboard part of the hardware being described in a separate file +to highlight the fact that is part of the support infrastructure for the SoC. +Juno device tree bindings also share the Versatile Express bindings as +described under the RS1 memory mapping. + +Required properties (in root node): + compatible = "arm,juno"; /* For Juno r0 board */ + compatible = "arm,juno-r1"; /* For Juno r1 board */ + compatible = "arm,juno-r2"; /* For Juno r2 board */ + +Required nodes: +The description for the board must include: + - a "psci" node describing the boot method used for the secondary CPUs. + A detailed description of the bindings used for "psci" nodes is present + in the psci.txt file. + - a "cpus" node describing the available cores and their associated + "enable-method"s. For more details see cpus.txt file. + +Example: + +/dts-v1/; +/ { + model = "ARM Juno development board (r0)"; + compatible = "arm,juno", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + A57_0: cpu@0 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x0 0x0>; + device_type = "cpu"; + enable-method = "psci"; + }; + + ..... + + A53_0: cpu@100 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x100>; + device_type = "cpu"; + enable-method = "psci"; + }; + + ..... + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/arm-dsu-pmu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/arm-dsu-pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..6efabba530f1938be2caf43bd08bf706ff556e1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/arm-dsu-pmu.txt @@ -0,0 +1,27 @@ +* ARM DynamIQ Shared Unit (DSU) Performance Monitor Unit (PMU) + +ARM DyanmIQ Shared Unit (DSU) integrates one or more CPU cores +with a shared L3 memory system, control logic and external interfaces to +form a multicore cluster. The PMU enables to gather various statistics on +the operations of the DSU. The PMU provides independent 32bit counters that +can count any of the supported events, along with a 64bit cycle counter. +The PMU is accessed via CPU system registers and has no MMIO component. + +** DSU PMU required properties: + +- compatible : should be one of : + + "arm,dsu-pmu" + +- interrupts : Exactly 1 SPI must be listed. + +- cpus : List of phandles for the CPUs connected to this DSU instance. + + +** Example: + +dsu-pmu-0 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&cpu_0>, <&cpu_1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/armadeus.txt b/arch/arm64/boot/dts/vendor/bindings/arm/armadeus.txt new file mode 100644 index 0000000000000000000000000000000000000000..9821283ff516774c0300699c873216b4bb72a1d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/armadeus.txt @@ -0,0 +1,6 @@ +Armadeus i.MX Platforms Device Tree Bindings +----------------------------------------------- + +APF51: i.MX51 based module. +Required root node properties: + - compatible = "armadeus,imx51-apf51", "fsl,imx51"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/atmel-at91.txt b/arch/arm64/boot/dts/vendor/bindings/arm/atmel-at91.txt new file mode 100644 index 0000000000000000000000000000000000000000..31220b54d85df1fa660ea4c9aba8bc90b254765e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/atmel-at91.txt @@ -0,0 +1,242 @@ +Atmel AT91 device tree bindings. +================================ + +Boards with a SoC of the Atmel AT91 or SMART family shall have the following +properties: + +Required root node properties: +compatible: must be one of: + * "atmel,at91rm9200" + + * "atmel,at91sam9" for SoCs using an ARM926EJ-S core, shall be extended with + the specific SoC family or compatible: + o "atmel,at91sam9260" + o "atmel,at91sam9261" + o "atmel,at91sam9263" + o "atmel,at91sam9x5" for the 5 series, shall be extended with the specific + SoC compatible: + - "atmel,at91sam9g15" + - "atmel,at91sam9g25" + - "atmel,at91sam9g35" + - "atmel,at91sam9x25" + - "atmel,at91sam9x35" + o "atmel,at91sam9g20" + o "atmel,at91sam9g45" + o "atmel,at91sam9n12" + o "atmel,at91sam9rl" + o "atmel,at91sam9xe" + * "atmel,sama5" for SoCs using a Cortex-A5, shall be extended with the specific + SoC family: + o "atmel,sama5d2" shall be extended with the specific SoC compatible: + - "atmel,sama5d27" + o "atmel,sama5d3" shall be extended with the specific SoC compatible: + - "atmel,sama5d31" + - "atmel,sama5d33" + - "atmel,sama5d34" + - "atmel,sama5d35" + - "atmel,sama5d36" + o "atmel,sama5d4" shall be extended with the specific SoC compatible: + - "atmel,sama5d41" + - "atmel,sama5d42" + - "atmel,sama5d43" + - "atmel,sama5d44" + + * "atmel,samv7" for MCUs using a Cortex-M7, shall be extended with the specific + SoC family: + o "atmel,sams70" shall be extended with the specific MCU compatible: + - "atmel,sams70j19" + - "atmel,sams70j20" + - "atmel,sams70j21" + - "atmel,sams70n19" + - "atmel,sams70n20" + - "atmel,sams70n21" + - "atmel,sams70q19" + - "atmel,sams70q20" + - "atmel,sams70q21" + o "atmel,samv70" shall be extended with the specific MCU compatible: + - "atmel,samv70j19" + - "atmel,samv70j20" + - "atmel,samv70n19" + - "atmel,samv70n20" + - "atmel,samv70q19" + - "atmel,samv70q20" + o "atmel,samv71" shall be extended with the specific MCU compatible: + - "atmel,samv71j19" + - "atmel,samv71j20" + - "atmel,samv71j21" + - "atmel,samv71n19" + - "atmel,samv71n20" + - "atmel,samv71n21" + - "atmel,samv71q19" + - "atmel,samv71q20" + - "atmel,samv71q21" + +Chipid required properties: +- compatible: Should be "atmel,sama5d2-chipid" +- reg : Should contain registers location and length + +PIT Timer required properties: +- compatible: Should be "atmel,at91sam9260-pit" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt for the PIT which is the IRQ line + shared across all System Controller members. + +System Timer (ST) required properties: +- compatible: Should be "atmel,at91rm9200-st", "syscon", "simple-mfd" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt for the ST which is the IRQ line + shared across all System Controller members. +- clocks: phandle to input clock. +Its subnodes can be: +- watchdog: compatible should be "atmel,at91rm9200-wdt" + +RSTC Reset Controller required properties: +- compatible: Should be "atmel,-rstc". + can be "at91sam9260" or "at91sam9g45" or "sama5d3" +- reg: Should contain registers location and length +- clocks: phandle to input clock. + +Example: + + rstc@fffffd00 { + compatible = "atmel,at91sam9260-rstc"; + reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; + }; + +RAMC SDRAM/DDR Controller required properties: +- compatible: Should be "atmel,at91rm9200-sdramc", "syscon" + "atmel,at91sam9260-sdramc", + "atmel,at91sam9g45-ddramc", + "atmel,sama5d3-ddramc", +- reg: Should contain registers location and length + +Examples: + + ramc0: ramc@ffffe800 { + compatible = "atmel,at91sam9g45-ddramc"; + reg = <0xffffe800 0x200>; + }; + +SHDWC Shutdown Controller + +required properties: +- compatible: Should be "atmel,-shdwc". + can be "at91sam9260", "at91sam9rl" or "at91sam9x5". +- reg: Should contain registers location and length +- clocks: phandle to input clock. + +optional properties: +- atmel,wakeup-mode: String, operation mode of the wakeup mode. + Supported values are: "none", "high", "low", "any". +- atmel,wakeup-counter: Counter on Wake-up 0 (between 0x0 and 0xf). + +optional at91sam9260 properties: +- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. + +optional at91sam9rl properties: +- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up. +- atmel,wakeup-rtt-timer: boolean to enable Real-time Timer Wake-up. + +optional at91sam9x5 properties: +- atmel,wakeup-rtc-timer: boolean to enable Real-time Clock Wake-up. + +Example: + + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; + }; + +SHDWC SAMA5D2-Compatible Shutdown Controller + +1) shdwc node + +required properties: +- compatible: should be "atmel,sama5d2-shdwc". +- reg: should contain registers location and length +- clocks: phandle to input clock. +- #address-cells: should be one. The cell is the wake-up input index. +- #size-cells: should be zero. + +optional properties: + +- debounce-delay-us: minimum wake-up inputs debouncer period in + microseconds. It's usually a board-related property. +- atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up. + +The node contains child nodes for each wake-up input that the platform uses. + +2) input nodes + +Wake-up input nodes are usually described in the "board" part of the Device +Tree. Note also that input 0 is linked to the wake-up pin and is frequently +used. + +Required properties: +- reg: should contain the wake-up input index [0 - 15]. + +Optional properties: +- atmel,wakeup-active-high: boolean, the corresponding wake-up input described + by the child, forces the wake-up of the core power supply on a high level. + The default is to be active low. + +Example: + +On the SoC side: + shdwc@f8048010 { + compatible = "atmel,sama5d2-shdwc"; + reg = <0xf8048010 0x10>; + clocks = <&clk32k>; + #address-cells = <1>; + #size-cells = <0>; + atmel,wakeup-rtc-timer; + }; + +On the board side: + shdwc@f8048010 { + debounce-delay-us = <976>; + + input@0 { + reg = <0>; + }; + + input@1 { + reg = <1>; + atmel,wakeup-active-high; + }; + }; + +Special Function Registers (SFR) + +Special Function Registers (SFR) manage specific aspects of the integrated +memory, bridge implementations, processor and other functionality not controlled +elsewhere. + +required properties: +- compatible: Should be "atmel,-sfr", "syscon" or + "atmel,-sfrbu", "syscon" + can be "sama5d3", "sama5d4" or "sama5d2". +- reg: Should contain registers location and length + + sfr@f0038000 { + compatible = "atmel,sama5d3-sfr", "syscon"; + reg = <0xf0038000 0x60>; + }; + +Security Module (SECUMOD) + +The Security Module macrocell provides all necessary secure functions to avoid +voltage, temperature, frequency and mechanical attacks on the chip. It also +embeds secure memories that can be scrambled + +required properties: +- compatible: Should be "atmel,-secumod", "syscon". + can be "sama5d2". +- reg: Should contain registers location and length + + secumod@fc040000 { + compatible = "atmel,sama5d2-secumod", "syscon"; + reg = <0xfc040000 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/axentia.txt b/arch/arm64/boot/dts/vendor/bindings/arm/axentia.txt new file mode 100644 index 0000000000000000000000000000000000000000..de58f24638805de6f3e21beb1f125c9a17362529 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/axentia.txt @@ -0,0 +1,28 @@ +Device tree bindings for Axentia ARM devices +============================================ + +Linea CPU module +---------------- + +Required root node properties: +compatible = "axentia,linea", + "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; +and following the rules from atmel-at91.txt for a sama5d31 SoC. + + +Nattis v2 board with Natte v2 power board +----------------------------------------- + +Required root node properties: +compatible = "axentia,nattis-2", "axentia,natte-2", "axentia,linea", + "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; +and following the rules from above for the axentia,linea CPU module. + + +TSE-850 v3 board +---------------- + +Required root node properties: +compatible = "axentia,tse850v3", "axentia,linea", + "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; +and following the rules from above for the axentia,linea CPU module. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/axis.txt b/arch/arm64/boot/dts/vendor/bindings/arm/axis.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae345e1c8d2b8f514865f70374cada6e4b868654 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/axis.txt @@ -0,0 +1,29 @@ +Axis Communications AB +ARTPEC series SoC Device Tree Bindings + +ARTPEC-6 ARM SoC +================ + +Required root node properties: +- compatible = "axis,artpec6"; + +ARTPEC-6 System Controller +-------------------------- + +The ARTPEC-6 has a system controller with mixed functions controlling DMA, PCIe +and resets. + +Required properties: +- compatible: "axis,artpec6-syscon", "syscon" +- reg: Address and length of the register bank. + +Example: + syscon { + compatible = "axis,artpec6-syscon", "syscon"; + reg = <0xf8000000 0x48>; + }; + +ARTPEC-6 Development board: +--------------------------- +Required root node properties: +- compatible = "axis,artpec6-dev-board", "axis,artpec6"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/axxia.txt b/arch/arm64/boot/dts/vendor/bindings/arm/axxia.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b4ef9c076962bbf46dd91c468356073bceeefea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/axxia.txt @@ -0,0 +1,12 @@ +Axxia AXM55xx device tree bindings + +Boards using the AXM55xx SoC need to have the following properties: + +Required root node property: + + - compatible = "lsi,axm5516" + +Boards: + + LSI AXM5516 Validation board (Amarillo) + compatible = "lsi,axm5516-amarillo", "lsi,axm5516" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3f99692040365fe16c6cb0fd35bdf1a8c1b75f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm11351-cpu-method.txt @@ -0,0 +1,36 @@ +Broadcom Kona Family CPU Enable Method +-------------------------------------- +This binding defines the enable method used for starting secondary +CPUs in the following Broadcom SoCs: + BCM11130, BCM11140, BCM11351, BCM28145, BCM28155, BCM21664 + +The enable method is specified by defining the following required +properties in the "cpu" device tree node: + - enable-method = "brcm,bcm11351-cpu-method"; + - secondary-boot-reg = <...>; + +The secondary-boot-reg property is a u32 value that specifies the +physical address of the register used to request the ROM holding pen +code release a secondary CPU. The value written to the register is +formed by encoding the target CPU id into the low bits of the +physical start address it should jump to. + +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <1>; + enable-method = "brcm,bcm11351-cpu-method"; + secondary-boot-reg = <0x3500417c>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm11351.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm11351.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ff6560e6094717b93a57219d7b8a07b5a6ef3ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm11351.txt @@ -0,0 +1,10 @@ +Broadcom BCM11351 device tree bindings +------------------------------------------- + +Boards with the bcm281xx SoC family (which includes bcm11130, bcm11140, +bcm11351, bcm28145, bcm28155 SoCs) shall have the following properties: + +Required root node property: + +compatible = "brcm,bcm11351"; +DEPRECATED: compatible = "bcm,bcm11351"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm21664.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm21664.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0774255e1a6436793118f78d60b2f365bd8a745 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm21664.txt @@ -0,0 +1,15 @@ +Broadcom BCM21664 device tree bindings +-------------------------------------- + +This document describes the device tree bindings for boards with the BCM21664 +SoC. + +Required root node property: + - compatible: brcm,bcm21664 + +Example: + / { + model = "BCM21664 SoC"; + compatible = "brcm,bcm21664"; + [...] + } diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm23550-cpu-method.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm23550-cpu-method.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3af54c0e404d7cd86a7939de2b381c196946db5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm23550-cpu-method.txt @@ -0,0 +1,36 @@ +Broadcom Kona Family CPU Enable Method +-------------------------------------- +This binding defines the enable method used for starting secondary +CPUs in the following Broadcom SoCs: + BCM23550 + +The enable method is specified by defining the following required +properties in the "cpu" device tree node: + - enable-method = "brcm,bcm23550"; + - secondary-boot-reg = <...>; + +The secondary-boot-reg property is a u32 value that specifies the +physical address of the register used to request the ROM holding pen +code release a secondary CPU. The value written to the register is +formed by encoding the target CPU id into the low bits of the +physical start address it should jump to. + +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <0>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + reg = <1>; + enable-method = "brcm,bcm23550"; + secondary-boot-reg = <0x3500417c>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm23550.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm23550.txt new file mode 100644 index 0000000000000000000000000000000000000000..080baad923d6f05044f54ccd7feb867b37f41ceb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm23550.txt @@ -0,0 +1,15 @@ +Broadcom BCM23550 device tree bindings +-------------------------------------- + +This document describes the device tree bindings for boards with the BCM23550 +SoC. + +Required root node property: + - compatible: brcm,bcm23550 + +Example: + / { + model = "BCM23550 SoC"; + compatible = "brcm,bcm23550"; + [...] + } diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm2835.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm2835.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e3e29a545e263470fff686f036361ddaf48abfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm2835.txt @@ -0,0 +1,55 @@ +Broadcom BCM2835 device tree bindings +------------------------------------------- + +Raspberry Pi Model A +Required root node properties: +compatible = "raspberrypi,model-a", "brcm,bcm2835"; + +Raspberry Pi Model A+ +Required root node properties: +compatible = "raspberrypi,model-a-plus", "brcm,bcm2835"; + +Raspberry Pi Model B +Required root node properties: +compatible = "raspberrypi,model-b", "brcm,bcm2835"; + +Raspberry Pi Model B (no P5) +early model B with I2C0 rather than I2C1 routed to the expansion header +Required root node properties: +compatible = "raspberrypi,model-b-i2c0", "brcm,bcm2835"; + +Raspberry Pi Model B rev2 +Required root node properties: +compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835"; + +Raspberry Pi Model B+ +Required root node properties: +compatible = "raspberrypi,model-b-plus", "brcm,bcm2835"; + +Raspberry Pi 2 Model B +Required root node properties: +compatible = "raspberrypi,2-model-b", "brcm,bcm2836"; + +Raspberry Pi 3 Model B +Required root node properties: +compatible = "raspberrypi,3-model-b", "brcm,bcm2837"; + +Raspberry Pi 3 Model B+ +Required root node properties: +compatible = "raspberrypi,3-model-b-plus", "brcm,bcm2837"; + +Raspberry Pi Compute Module +Required root node properties: +compatible = "raspberrypi,compute-module", "brcm,bcm2835"; + +Raspberry Pi Zero +Required root node properties: +compatible = "raspberrypi,model-zero", "brcm,bcm2835"; + +Raspberry Pi Zero W +Required root node properties: +compatible = "raspberrypi,model-zero-w", "brcm,bcm2835"; + +Generic BCM2835 board +Required root node properties: +compatible = "brcm,bcm2835"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm4708.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm4708.txt new file mode 100644 index 0000000000000000000000000000000000000000..8608a776caa71a2ff52eca594fabd059ea65e94d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm4708.txt @@ -0,0 +1,15 @@ +Broadcom BCM4708 device tree bindings +------------------------------------------- + +Boards with the BCM4708 SoC shall have the following properties: + +Required root node property: + +bcm4708 +compatible = "brcm,bcm4708"; + +bcm4709 +compatible = "brcm,bcm4709"; + +bcm53012 +compatible = "brcm,bcm53012"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm63138.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm63138.txt new file mode 100644 index 0000000000000000000000000000000000000000..b82b6a0ae6f725cee5f6138657e05bdb92e138f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,bcm63138.txt @@ -0,0 +1,85 @@ +Broadcom BCM63138 DSL System-on-a-Chip device tree bindings +----------------------------------------------------------- + +Boards compatible with the BCM63138 DSL System-on-a-Chip should have the +following properties: + +Required root node property: + +compatible: should be "brcm,bcm63138" + +An optional Boot lookup table Device Tree node is required for secondary CPU +initialization as well as a 'resets' phandle to the correct PMB controller as +defined in reset/brcm,bcm63138-pmb.txt for this secondary CPU, and an +'enable-method' property. + +Required properties for the Boot lookup table node: +- compatible: should be "brcm,bcm63138-bootlut" +- reg: register base address and length for the Boot Lookup table + +Optional properties for the primary CPU node: +- enable-method: should be "brcm,bcm63138" + +Optional properties for the secondary CPU node: +- enable-method: should be "brcm,bcm63138" +- resets: phandle to the relevant PMB controller, one integer indicating the internal + bus number, and a second integer indicating the address of the CPU in the PMB + internal bus number. + +Example: + + cpus { + cpu@0 { + compatible = "arm,cotex-a9"; + reg = <0>; + ... + enable-method = "brcm,bcm63138"; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + ... + enable-method = "brcm,bcm63138"; + resets = <&pmb0 4 1>; + }; + }; + + bootlut: bootlut@8000 { + compatible = "brcm,bcm63138-bootlut"; + reg = <0x8000 0x50>; + }; + +======= +reboot +------ +Two nodes are required for software reboot: a timer node and a syscon-reboot node. + +Timer node: + +- compatible: Must be "brcm,bcm6328-timer", "syscon" +- reg: Register base address and length + +Syscon reboot node: + +See Documentation/devicetree/bindings/power/reset/syscon-reboot.txt for the +detailed list of properties, the two values defined below are specific to the +BCM6328-style timer: + +- offset: Should be 0x34 to denote the offset of the TIMER_WD_TIMER_RESET register + from the beginning of the TIMER block +- mask: Should be 1 for the SoftRst bit. + +Example: + + timer: timer@80 { + compatible = "brcm,bcm6328-timer", "syscon"; + reg = <0x80 0x3c>; + }; + + reboot { + compatible = "syscon-reboot"; + regmap = <&timer>; + offset = <0x34>; + mask = <0x1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,brcmstb.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,brcmstb.txt new file mode 100644 index 0000000000000000000000000000000000000000..104cc9b41df46bebb2d8db5cdd4fb7843a677f9c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,brcmstb.txt @@ -0,0 +1,265 @@ +ARM Broadcom STB platforms Device Tree Bindings +----------------------------------------------- +Boards with Broadcom Brahma15 ARM-based BCMxxxx (generally BCM7xxx variants) +SoC shall have the following DT organization: + +Required root node properties: + - compatible: "brcm,bcm", "brcm,brcmstb" + +example: +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "Broadcom STB (bcm7445)"; + compatible = "brcm,bcm7445", "brcm,brcmstb"; + +Further, syscon nodes that map platform-specific registers used for general +system control is required: + + - compatible: "brcm,bcm-sun-top-ctrl", "syscon" + - compatible: "brcm,bcm-cpu-biu-ctrl", + "brcm,brcmstb-cpu-biu-ctrl", + "syscon" + - compatible: "brcm,bcm-hif-continuation", "syscon" + +cpu-biu-ctrl node +------------------- +SoCs with Broadcom Brahma15 ARM-based and Brahma53 ARM64-based CPUs have a +specific Bus Interface Unit (BIU) block which controls and interfaces the CPU +complex to the different Memory Controller Ports (MCP), one per memory +controller (MEMC). This BIU block offers a feature called Write Pairing which +consists in collapsing two adjacent cache lines into a single (bursted) write +transaction towards the memory controller (MEMC) to maximize write bandwidth. + +Required properties: + + - compatible: must be "brcm,bcm7445-cpu-biu-ctrl", "brcm,brcmstb-cpu-biu-ctrl", "syscon" + +Optional properties: + + - brcm,write-pairing: + Boolean property, which when present indicates that the chip + supports write-pairing. + +example: + rdb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0 0x00 0xf0000000 0x1000000>; + + sun_top_ctrl: syscon@404000 { + compatible = "brcm,bcm7445-sun-top-ctrl", "syscon"; + reg = <0x404000 0x51c>; + }; + + hif_cpubiuctrl: syscon@3e2400 { + compatible = "brcm,bcm7445-cpu-biu-ctrl", "brcm,brcmstb-cpu-biu-ctrl", "syscon"; + reg = <0x3e2400 0x5b4>; + brcm,write-pairing; + }; + + hif_continuation: syscon@452000 { + compatible = "brcm,bcm7445-hif-continuation", "syscon"; + reg = <0x452000 0x100>; + }; + }; + +Nodes that allow for support of SMP initialization and reboot are required: + +smpboot +------- +Required properties: + + - compatible + The string "brcm,brcmstb-smpboot". + + - syscon-cpu + A phandle / integer array property which lets the BSP know the location + of certain CPU power-on registers. + + The layout of the property is as follows: + o a phandle to the "hif_cpubiuctrl" syscon node + o offset to the base CPU power zone register + o offset to the base CPU reset register + + - syscon-cont + A phandle pointing to the syscon node which describes the CPU boot + continuation registers. + o a phandle to the "hif_continuation" syscon node + +example: + smpboot { + compatible = "brcm,brcmstb-smpboot"; + syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>; + syscon-cont = <&hif_continuation>; + }; + +reboot +------- +Required properties + + - compatible + The string property "brcm,brcmstb-reboot" for 40nm/28nm chips with + the new SYS_CTRL interface, or "brcm,bcm7038-reboot" for 65nm + chips with the old SUN_TOP_CTRL interface. + + - syscon + A phandle / integer array that points to the syscon node which describes + the general system reset registers. + o a phandle to "sun_top_ctrl" + o offset to the "reset source enable" register + o offset to the "software master reset" register + +example: + reboot { + compatible = "brcm,brcmstb-reboot"; + syscon = <&sun_top_ctrl 0x304 0x308>; + }; + + + +Power management +---------------- + +For power management (particularly, S2/S3/S5 system suspend), the following SoC +components are needed: + += Always-On control block (AON CTRL) + +This hardware provides control registers for the "always-on" (even in low-power +modes) hardware, such as the Power Management State Machine (PMSM). + +Required properties: +- compatible : should contain "brcm,brcmstb-aon-ctrl" +- reg : the register start and length for the AON CTRL block + +Example: + +aon-ctrl@410000 { + compatible = "brcm,brcmstb-aon-ctrl"; + reg = <0x410000 0x400>; +}; + += Memory controllers + +A Broadcom STB SoC typically has a number of independent memory controllers, +each of which may have several associated hardware blocks, which are versioned +independently (control registers, DDR PHYs, etc.). One might consider +describing these controllers as a parent "memory controllers" block, which +contains N sub-nodes (one for each controller in the system), each of which is +associated with a number of hardware register resources (e.g., its PHY). See +the example device tree snippet below. + +== MEMC (MEMory Controller) + +Represents a single memory controller instance. + +Required properties: +- compatible : should contain "brcm,brcmstb-memc" and "simple-bus" + +Should contain subnodes for any of the following relevant hardware resources: + +== DDR PHY control + +Control registers for this memory controller's DDR PHY. + +Required properties: +- compatible : should contain one of these + "brcm,brcmstb-ddr-phy-v71.1" + "brcm,brcmstb-ddr-phy-v72.0" + "brcm,brcmstb-ddr-phy-v225.1" + "brcm,brcmstb-ddr-phy-v240.1" + "brcm,brcmstb-ddr-phy-v240.2" + +- reg : the DDR PHY register range + +== DDR SHIMPHY + +Control registers for this memory controller's DDR SHIMPHY. + +Required properties: +- compatible : should contain "brcm,brcmstb-ddr-shimphy-v1.0" +- reg : the DDR SHIMPHY register range + +== MEMC DDR control + +Sequencer DRAM parameters and control registers. Used for Self-Refresh +Power-Down (SRPD), among other things. + +Required properties: +- compatible : should contain one of these + "brcm,brcmstb-memc-ddr-rev-b.2.1" + "brcm,brcmstb-memc-ddr-rev-b.2.2" + "brcm,brcmstb-memc-ddr-rev-b.2.3" + "brcm,brcmstb-memc-ddr-rev-b.3.0" + "brcm,brcmstb-memc-ddr-rev-b.3.1" + "brcm,brcmstb-memc-ddr" +- reg : the MEMC DDR register range + +Example: + +memory_controllers { + ranges; + compatible = "simple-bus"; + + memc@0 { + compatible = "brcm,brcmstb-memc", "simple-bus"; + ranges; + + ddr-phy@f1106000 { + compatible = "brcm,brcmstb-ddr-phy-v240.1"; + reg = <0xf1106000 0x21c>; + }; + + shimphy@f1108000 { + compatible = "brcm,brcmstb-ddr-shimphy-v1.0"; + reg = <0xf1108000 0xe4>; + }; + + memc-ddr@f1102000 { + reg = <0xf1102000 0x800>; + compatible = "brcm,brcmstb-memc-ddr"; + }; + }; + + memc@1 { + compatible = "brcm,brcmstb-memc", "simple-bus"; + ranges; + + ddr-phy@f1186000 { + compatible = "brcm,brcmstb-ddr-phy-v240.1"; + reg = <0xf1186000 0x21c>; + }; + + shimphy@f1188000 { + compatible = "brcm,brcmstb-ddr-shimphy-v1.0"; + reg = <0xf1188000 0xe4>; + }; + + memc-ddr@f1182000 { + reg = <0xf1182000 0x800>; + compatible = "brcm,brcmstb-memc-ddr"; + }; + }; + + memc@2 { + compatible = "brcm,brcmstb-memc", "simple-bus"; + ranges; + + ddr-phy@f1206000 { + compatible = "brcm,brcmstb-ddr-phy-v240.1"; + reg = <0xf1206000 0x21c>; + }; + + shimphy@f1208000 { + compatible = "brcm,brcmstb-ddr-shimphy-v1.0"; + reg = <0xf1208000 0xe4>; + }; + + memc-ddr@f1202000 { + reg = <0xf1202000 0x800>; + compatible = "brcm,brcmstb-memc-ddr"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,cygnus.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,cygnus.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c77169bb5346bdf4fa18d91499978fd4d83dc25 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,cygnus.txt @@ -0,0 +1,31 @@ +Broadcom Cygnus device tree bindings +------------------------------------ + + +Boards with Cygnus SoCs shall have the following properties: + +Required root node property: + +BCM11300 +compatible = "brcm,bcm11300", "brcm,cygnus"; + +BCM11320 +compatible = "brcm,bcm11320", "brcm,cygnus"; + +BCM11350 +compatible = "brcm,bcm11350", "brcm,cygnus"; + +BCM11360 +compatible = "brcm,bcm11360", "brcm,cygnus"; + +BCM58300 +compatible = "brcm,bcm58300", "brcm,cygnus"; + +BCM58302 +compatible = "brcm,bcm58302", "brcm,cygnus"; + +BCM58303 +compatible = "brcm,bcm58303", "brcm,cygnus"; + +BCM58305 +compatible = "brcm,bcm58305", "brcm,cygnus"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,hr2.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,hr2.txt new file mode 100644 index 0000000000000000000000000000000000000000..a124c7fc4dcdc25b4f61925e5fd6f5e10533d89f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,hr2.txt @@ -0,0 +1,14 @@ +Broadcom Hurricane 2 device tree bindings +--------------------------------------- + +Broadcom Hurricane 2 family of SoCs are used for switching control. These SoCs +are based on Broadcom's iProc SoC architecture and feature a single core Cortex +A9 ARM CPUs, DDR2/DDR3 memory, PCIe GEN-2, USB 2.0 and USB 3.0, serial and NAND +flash and a PCIe attached integrated switching engine. + +Boards with Hurricane SoCs shall have the following properties: + +Required root node property: + +BCM53342 +compatible = "brcm,bcm53342", "brcm,hr2"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,ns2.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,ns2.txt new file mode 100644 index 0000000000000000000000000000000000000000..35f056f4a1c35b2b98216ac8db81f8a07a1ae7a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,ns2.txt @@ -0,0 +1,9 @@ +Broadcom North Star 2 (NS2) device tree bindings +------------------------------------------------ + +Boards with NS2 shall have the following properties: + +Required root node property: + +NS2 SVK board +compatible = "brcm,ns2-svk", "brcm,ns2"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,nsp-cpu-method.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,nsp-cpu-method.txt new file mode 100644 index 0000000000000000000000000000000000000000..677ef9d9f445b3c53268fe09d3cdabd6c9af5336 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,nsp-cpu-method.txt @@ -0,0 +1,39 @@ +Broadcom Northstar Plus SoC CPU Enable Method +--------------------------------------------- +This binding defines the enable method used for starting secondary +CPU in the following Broadcom SoCs: + BCM58522, BCM58525, BCM58535, BCM58622, BCM58623, BCM58625, BCM88312 + +The enable method is specified by defining the following required +properties in the corresponding secondary "cpu" device tree node: + - enable-method = "brcm,bcm-nsp-smp"; + - secondary-boot-reg = <...>; + +The secondary-boot-reg property is a u32 value that specifies the +physical address of the register which should hold the common +entry point for a secondary CPU. This entry is cpu node specific +and should be added per cpu. E.g., in case of NSP (BCM58625) which +is a dual core CPU SoC, this entry should be added to cpu1 node. + + +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + reg = <0>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + next-level-cache = <&L2>; + enable-method = "brcm,bcm-nsp-smp"; + secondary-boot-reg = <0xffff042c>; + reg = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,nsp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,nsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..eae53e4556be0a85fbfdb2888d383338147663cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,nsp.txt @@ -0,0 +1,34 @@ +Broadcom Northstar Plus device tree bindings +-------------------------------------------- + +Broadcom Northstar Plus family of SoCs are used for switching control +and management applications as well as residential router/gateway +applications. The SoC features dual core Cortex A9 ARM CPUs, integrating +several peripheral interfaces including multiple Gigabit Ethernet PHYs, +DDR3 memory, PCIE Gen-2, USB 2.0 and USB 3.0, serial and NAND flash, +SATA and several other IO controllers. + +Boards with Northstar Plus SoCs shall have the following properties: + +Required root node property: + +BCM58522 +compatible = "brcm,bcm58522", "brcm,nsp"; + +BCM58525 +compatible = "brcm,bcm58525", "brcm,nsp"; + +BCM58535 +compatible = "brcm,bcm58535", "brcm,nsp"; + +BCM58622 +compatible = "brcm,bcm58622", "brcm,nsp"; + +BCM58623 +compatible = "brcm,bcm58623", "brcm,nsp"; + +BCM58625 +compatible = "brcm,bcm58625", "brcm,nsp"; + +BCM88312 +compatible = "brcm,bcm88312", "brcm,nsp"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,stingray.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,stingray.txt new file mode 100644 index 0000000000000000000000000000000000000000..23a02178dd44bc42adb605f81f8ce04df6a8dbec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,stingray.txt @@ -0,0 +1,12 @@ +Broadcom Stingray device tree bindings +------------------------------------------------ + +Boards with Stingray shall have the following properties: + +Required root node property: + +Stingray Combo SVK board +compatible = "brcm,bcm958742k", "brcm,stingray"; + +Stingray SST100 board +compatible = "brcm,bcm958742t", "brcm,stingray"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,vulcan-soc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,vulcan-soc.txt new file mode 100644 index 0000000000000000000000000000000000000000..223ed3471c0846f6d23068d6512a00a8c54aec25 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/brcm,vulcan-soc.txt @@ -0,0 +1,10 @@ +Broadcom Vulcan device tree bindings +------------------------------------ + +Boards with Broadcom Vulcan shall have the following root property: + +Broadcom Vulcan Evaluation Board: + compatible = "brcm,vulcan-eval", "brcm,vulcan-soc"; + +Generic Vulcan board: + compatible = "brcm,vulcan-soc"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt new file mode 100644 index 0000000000000000000000000000000000000000..6824b3180ffb72e55d3f6951ae14c2a58af24bf4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt @@ -0,0 +1,14 @@ +Raspberry Pi VideoCore firmware driver + +Required properties: + +- compatible: Should be "raspberrypi,bcm2835-firmware" +- mboxes: Phandle to the firmware device's Mailbox. + (See: ../mailbox/mailbox.txt for more information) + +Example: + +firmware { + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/bhf.txt b/arch/arm64/boot/dts/vendor/bindings/arm/bhf.txt new file mode 100644 index 0000000000000000000000000000000000000000..886b503caf9cc07b30c92f3027853e24ced181d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/bhf.txt @@ -0,0 +1,6 @@ +Beckhoff Automation Platforms Device Tree Bindings +-------------------------------------------------- + +CX9020 Embedded PC +Required root node properties: + - compatible = "bhf,cx9020", "fsl,imx53"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cache.txt b/arch/arm64/boot/dts/vendor/bindings/arm/cache.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9594f02650661237391b3ceb0f71bb2add9bde7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cache.txt @@ -0,0 +1,195 @@ +========================================== +ARM processors cache binding description +========================================== + +Device tree bindings for ARM processor caches adhere to the cache bindings +described in [3], in section 3.8 for multi-level and shared caches. +On ARM based systems most of the cache properties related to cache +geometry are probeable in HW, hence, unless otherwise stated, the properties +defined in ePAPR for multi-level and shared caches are to be considered +optional by default. + +On ARM, caches are either architected (directly controlled by the processor +through coprocessor instructions and tightly coupled with the processor +implementation) or unarchitected (controlled through a memory mapped +interface, implemented as a stand-alone IP external to the processor +implementation). + +This document provides the device tree bindings for ARM architected caches. + +- ARM architected cache node + + Description: must be a direct child of the cpu node. A system + can contain multiple architected cache nodes per cpu node, + linked through the next-level-cache phandle. The + next-level-cache property in the cpu node points to + the first level of architected cache for the CPU. + The next-level-cache property in architected cache nodes + points to the respective next level of caching in the + hierarchy. An architected cache node with an empty or + missing next-level-cache property represents the last + architected cache level for the CPU. + On ARM v7 and v8 architectures, the order in which cache + nodes are linked through the next-level-cache phandle must + follow the ordering specified in the processors CLIDR (v7) + and CLIDR_EL1 (v8) registers, as described in [1][2], + implying that a cache node pointed at by a + next-level-cache phandle must correspond to a level + defined in CLIDR (v7) and CLIDR_EL1 (v8) greater than the + one the cache node containing the next-level-cache + phandle corresponds to. + + Since on ARM most of the cache properties are probeable in HW the + properties described in [3] - section 3.8 multi-level and shared + caches - shall be considered optional, with the following properties + updates, specific for the ARM architected cache node. + + - compatible + Usage: Required + Value type: + Definition: value shall be "arm,arch-cache". + + - interrupts + Usage: Optional + Value type: See definition + Definition: standard device tree property [3] that defines + the interrupt line associated with the cache. + The property can be accompanied by an + interrupt-names property, as described in [4]. + + - power-domain + Usage: Optional + Value type: phandle + Definition: A phandle and power domain specifier as defined by + bindings of power controller specified by the + phandle [5]. + + - qcom,dump-size + Usage: Optional + Value type: + Definition: The memory size needed to contain a copy of the + cache data and associated tag ram. + size = nways * nsets * (bytes per cache line + + bytes tag ram per line) + +Example(dual-cluster big.LITTLE system 32-bit) + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + next-level-cache = <&L1_0>; + + L1_0: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_0>; + }; + + L2_0: l2-cache { + compatible = "arm,arch-cache"; + }; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x1>; + next-level-cache = <&L1_1>; + + L1_1: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_0>; + }; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x2>; + next-level-cache = <&L1_2>; + + L1_2: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_0>; + }; + }; + + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x3>; + next-level-cache = <&L1_3>; + + L1_3: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_0>; + }; + }; + + cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x100>; + next-level-cache = <&L1_4>; + + L1_4: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_1>; + }; + + L2_1: l2-cache { + compatible = "arm,arch-cache"; + }; + }; + + cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x101>; + next-level-cache = <&L1_5>; + + L1_5: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_1>; + }; + }; + + cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x102>; + next-level-cache = <&L1_6>; + + L1_6: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_1>; + }; + }; + + cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x103>; + next-level-cache = <&L1_7>; + + L1_7: l1-cache { + compatible = "arm,arch-cache"; + next-level-cache = <&L2_1>; + }; + }; + }; + +[1] ARMv7-AR Reference Manual + http://infocenter.arm.com/help/index.jsp +[2] ARMv8-A Reference Manual + http://infocenter.arm.com/help/index.jsp +[3] ePAPR standard + https://www.power.org/documentation/epapr-version-1-1/ +[4] Kernel documentation - resource property bindings + Documentation/devicetree/bindings/resource-names.txt +[5] Kernel documentation - power domain bindings + Documentation/devicetree/bindings/power/power_domain.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/calxeda.txt b/arch/arm64/boot/dts/vendor/bindings/arm/calxeda.txt new file mode 100644 index 0000000000000000000000000000000000000000..25fcf96795cad9db60eea2640380c88116ed8511 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/calxeda.txt @@ -0,0 +1,15 @@ +Calxeda Platforms Device Tree Bindings +----------------------------------------------- + +Boards with Calxeda Cortex-A9 based ECX-1000 (Highbank) SOC shall have the +following properties. + +Required root node properties: + - compatible = "calxeda,highbank"; + + +Boards with Calxeda Cortex-A15 based ECX-2000 SOC shall have the following +properties. + +Required root node properties: + - compatible = "calxeda,ecx-2000"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/calxeda/l2ecc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/calxeda/l2ecc.txt new file mode 100644 index 0000000000000000000000000000000000000000..94e642a33db0388c8fcf5fc9f1e7a8d45d4643ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/calxeda/l2ecc.txt @@ -0,0 +1,15 @@ +Calxeda Highbank L2 cache ECC + +Properties: +- compatible : Should be "calxeda,hb-sregs-l2-ecc" +- reg : Address and size for ECC error interrupt clear registers. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt. + +Example: + + sregs@fff3c200 { + compatible = "calxeda,hb-sregs-l2-ecc"; + reg = <0xfff3c200 0x100>; + interrupts = <0 71 4 0 72 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cavium-thunder.txt b/arch/arm64/boot/dts/vendor/bindings/arm/cavium-thunder.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f63a58669021f9ca0c294c505df256a7ff6688f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cavium-thunder.txt @@ -0,0 +1,10 @@ +Cavium Thunder platform device tree bindings +-------------------------------------------- + +Boards with Cavium's Thunder SoC shall have following properties. + +Root Node +--------- +Required root node properties: + + - compatible = "cavium,thunder-88xx"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cavium-thunder2.txt b/arch/arm64/boot/dts/vendor/bindings/arm/cavium-thunder2.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc5dd65cbce7a13a46eb4ef3e3ca172074509775 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cavium-thunder2.txt @@ -0,0 +1,8 @@ +Cavium ThunderX2 CN99XX platform tree bindings +---------------------------------------------- + +Boards with Cavium ThunderX2 CN99XX SoC shall have the root property: + compatible = "cavium,thunderx2-cn9900", "brcm,vulcan-soc"; + +These SoC uses the "cavium,thunder2" core which will be compatible +with "brcm,vulcan". diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cci.txt b/arch/arm64/boot/dts/vendor/bindings/arm/cci.txt new file mode 100644 index 0000000000000000000000000000000000000000..9600761f2d5bb8b0b69fbc0334edfd9714930f88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cci.txt @@ -0,0 +1,224 @@ +======================================================= +ARM CCI cache coherent interconnect binding description +======================================================= + +ARM multi-cluster systems maintain intra-cluster coherency through a +cache coherent interconnect (CCI) that is capable of monitoring bus +transactions and manage coherency, TLB invalidations and memory barriers. + +It allows snooping and distributed virtual memory message broadcast across +clusters, through memory mapped interface, with a global control register +space and multiple sets of interface control registers, one per slave +interface. + +* CCI interconnect node + + Description: Describes a CCI cache coherent Interconnect component + + Node name must be "cci". + Node's parent must be the root node /, and the address space visible + through the CCI interconnect is the same as the one seen from the + root node (ie from CPUs perspective as per DT standard). + Every CCI node has to define the following properties: + + - compatible + Usage: required + Value type: + Definition: must contain one of the following: + "arm,cci-400" + "arm,cci-500" + "arm,cci-550" + + - reg + Usage: required + Value type: Integer cells. A register entry, expressed as a pair + of cells, containing base and size. + Definition: A standard property. Specifies base physical + address of CCI control registers common to all + interfaces. + + - ranges: + Usage: required + Value type: Integer cells. An array of range entries, expressed + as a tuple of cells, containing child address, + parent address and the size of the region in the + child address space. + Definition: A standard property. Follow rules in the Devicetree + Specification for hierarchical bus addressing. CCI + interfaces addresses refer to the parent node + addressing scheme to declare their register bases. + + CCI interconnect node can define the following child nodes: + + - CCI control interface nodes + + Node name must be "slave-if". + Parent node must be CCI interconnect node. + + A CCI control interface node must contain the following + properties: + + - compatible + Usage: required + Value type: + Definition: must be set to + "arm,cci-400-ctrl-if" + + - interface-type: + Usage: required + Value type: + Definition: must be set to one of {"ace", "ace-lite"} + depending on the interface type the node + represents. + + - reg: + Usage: required + Value type: Integer cells. A register entry, expressed + as a pair of cells, containing base and + size. + Definition: the base address and size of the + corresponding interface programming + registers. + + - CCI PMU node + + Parent node must be CCI interconnect node. + + A CCI pmu node must contain the following properties: + + - compatible + Usage: required + Value type: + Definition: Must contain one of: + "arm,cci-400-pmu,r0" + "arm,cci-400-pmu,r1" + "arm,cci-400-pmu" - DEPRECATED, permitted only where OS has + secure access to CCI registers + "arm,cci-500-pmu,r0" + "arm,cci-550-pmu,r0" + - reg: + Usage: required + Value type: Integer cells. A register entry, expressed + as a pair of cells, containing base and + size. + Definition: the base address and size of the + corresponding interface programming + registers. + + - interrupts: + Usage: required + Value type: Integer cells. Array of interrupt specifier + entries, as defined in + ../interrupt-controller/interrupts.txt. + Definition: list of counter overflow interrupts, one per + counter. The interrupts must be specified + starting with the cycle counter overflow + interrupt, followed by counter0 overflow + interrupt, counter1 overflow interrupt,... + ,counterN overflow interrupt. + + The CCI PMU has an interrupt signal for each + counter. The number of interrupts must be + equal to the number of counters. + +* CCI interconnect bus masters + + Description: masters in the device tree connected to a CCI port + (inclusive of CPUs and their cpu nodes). + + A CCI interconnect bus master node must contain the following + properties: + + - cci-control-port: + Usage: required + Value type: + Definition: a phandle containing the CCI control interface node + the master is connected to. + +Example: + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + cci-control-port = <&cci_control1>; + reg = <0x0>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + cci-control-port = <&cci_control1>; + reg = <0x1>; + }; + + CPU2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + cci-control-port = <&cci_control2>; + reg = <0x100>; + }; + + CPU3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + cci-control-port = <&cci_control2>; + reg = <0x101>; + }; + + }; + + dma0: dma@3000000 { + compatible = "arm,pl330", "arm,primecell"; + cci-control-port = <&cci_control0>; + reg = <0x0 0x3000000 0x0 0x1000>; + interrupts = <10>; + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <32>; + }; + + cci@2c090000 { + compatible = "arm,cci-400"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x2c090000 0 0x1000>; + ranges = <0x0 0x0 0x2c090000 0x10000>; + + cci_control0: slave-if@1000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace-lite"; + reg = <0x1000 0x1000>; + }; + + cci_control1: slave-if@4000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x4000 0x1000>; + }; + + cci_control2: slave-if@5000 { + compatible = "arm,cci-400-ctrl-if"; + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; + + pmu@9000 { + compatible = "arm,cci-400-pmu"; + reg = <0x9000 0x5000>; + interrupts = <0 101 4>, + <0 102 4>, + <0 103 4>, + <0 104 4>, + <0 105 4>; + }; + }; + +This CCI node corresponds to a CCI component whose control registers sits +at address 0x000000002c090000. +CCI slave interface @0x000000002c091000 is connected to dma controller dma0. +CCI slave interface @0x000000002c094000 is connected to CPUs {CPU0, CPU1}; +CCI slave interface @0x000000002c095000 is connected to CPUs {CPU2, CPU3}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/compulab-boards.txt b/arch/arm64/boot/dts/vendor/bindings/arm/compulab-boards.txt new file mode 100644 index 0000000000000000000000000000000000000000..42a10285af9cfdc867574c575fd6ac089a3f4167 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/compulab-boards.txt @@ -0,0 +1,25 @@ +CompuLab SB-SOM is a multi-module baseboard capable of carrying: + - CM-T43 + - CM-T54 + - CM-QS600 + - CL-SOM-AM57x + - CL-SOM-iMX7 +modules with minor modifications to the SB-SOM assembly. + +Required root node properties: + - compatible = should be "compulab,sb-som" + +Compulab CL-SOM-iMX7 is a miniature System-on-Module (SoM) based on +Freescale i.MX7 ARM Cortex-A7 System-on-Chip. + +Required root node properties: + - compatible = "compulab,cl-som-imx7", "fsl,imx7d"; + +Compulab SBC-iMX7 is a single board computer based on the +Freescale i.MX7 system-on-chip. SBC-iMX7 is implemented with +the CL-SOM-iMX7 System-on-Module providing most of the functions, +and SB-SOM-iMX7 carrier board providing additional peripheral +functions and connectors. + +Required root node properties: + - compatible = "compulab,sbc-imx7", "compulab,cl-som-imx7", "fsl,imx7d"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/coresight-cpu-debug.txt b/arch/arm64/boot/dts/vendor/bindings/arm/coresight-cpu-debug.txt new file mode 100644 index 0000000000000000000000000000000000000000..298291211ea4dd8f647d47cc80f077d19fe82249 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/coresight-cpu-debug.txt @@ -0,0 +1,49 @@ +* CoreSight CPU Debug Component: + +CoreSight CPU debug component are compliant with the ARMv8 architecture +reference manual (ARM DDI 0487A.k) Chapter 'Part H: External debug'. The +external debug module is mainly used for two modes: self-hosted debug and +external debug, and it can be accessed from mmio region from Coresight +and eventually the debug module connects with CPU for debugging. And the +debug module provides sample-based profiling extension, which can be used +to sample CPU program counter, secure state and exception level, etc; +usually every CPU has one dedicated debug module to be connected. + +Required properties: + +- compatible : should be "arm,coresight-cpu-debug"; supplemented with + "arm,primecell" since this driver is using the AMBA bus + interface. + +- reg : physical base address and length of the register set. + +- clocks : the clock associated to this component. + +- clock-names : the name of the clock referenced by the code. Since we are + using the AMBA framework, the name of the clock providing + the interconnect should be "apb_pclk" and the clock is + mandatory. The interface between the debug logic and the + processor core is clocked by the internal CPU clock, so it + is enabled with CPU clock by default. + +- cpu : the CPU phandle the debug module is affined to. When omitted + the module is considered to belong to CPU0. + +Optional properties: + +- power-domains: a phandle to the debug power domain. We use "power-domains" + binding to turn on the debug logic if it has own dedicated + power domain and if necessary to use "cpuidle.off=1" or + "nohlt" in the kernel command line or sysfs node to + constrain idle states to ensure registers in the CPU power + domain are accessible. + +Example: + + debug@f6590000 { + compatible = "arm,coresight-cpu-debug","arm,primecell"; + reg = <0 0xf6590000 0 0x1000>; + clocks = <&sys_ctrl HI6220_DAPB_CLK>; + clock-names = "apb_pclk"; + cpu = <&cpu0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/coresight.txt b/arch/arm64/boot/dts/vendor/bindings/arm/coresight.txt new file mode 100644 index 0000000000000000000000000000000000000000..776678a3bbf017d158f4f88e3e710f3abbbb7f1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/coresight.txt @@ -0,0 +1,491 @@ +* CoreSight Components: + +CoreSight components are compliant with the ARM CoreSight architecture +specification and can be connected in various topologies to suit a particular +SoCs tracing needs. These trace components can generally be classified as +sinks, links and sources. Trace data produced by one or more sources flows +through the intermediate links connecting the source to the currently selected +sink. Each CoreSight component device should use these properties to describe +its hardware characteristcs. + +* Required properties for all components *except* non-configurable replicators: + + * compatible: These have to be supplemented with "arm,primecell" as + drivers are using the AMBA bus interface. Possible values include: + - Embedded Trace Buffer (version 1.0): + "arm,coresight-etb10", "arm,primecell"; + + - Trace Port Interface Unit: + "arm,coresight-tpiu", "arm,primecell"; + + - Trace Memory Controller, used for Embedded Trace Buffer(ETB), + Embedded Trace FIFO(ETF) and Embedded Trace Router(ETR) + configuration. The configuration mode (ETB, ETF, ETR) is + discovered at boot time when the device is probed. + "arm,coresight-tmc", "arm,primecell"; + + - Trace Funnel: + "arm,coresight-funnel", "arm,primecell"; + + - Embedded Trace Macrocell (version 3.x) and + Program Flow Trace Macrocell: + "arm,coresight-etm3x", "arm,primecell"; + + - Embedded Trace Macrocell (version 4.x): + "arm,coresight-etm4x", "arm,primecell"; + + - Coresight programmable Replicator : + "arm,coresight-dynamic-replicator", "arm,primecell"; + + - System Trace Macrocell: + "arm,coresight-stm", "arm,primecell"; [1] + - Coresight Address Translation Unit (CATU) + "arm,coresight-catu", "arm,primecell"; + + - Trigger Generation Unit: + "arm,primecell"; + + * reg: physical base address and length of the register + set(s) of the component. + + * clocks: the clocks associated to this component. + + * clock-names: the name of the clocks referenced by the code. + Since we are using the AMBA framework, the name of the clock + providing the interconnect should be "apb_pclk", and some + coresight blocks also have an additional clock "atclk", which + clocks the core of that coresight component. The latter clock + is optional. + + * port or ports: The representation of the component's port + layout using the generic DT graph presentation found in + "bindings/graph.txt". + + * coresight-name: unique descriptive name of the component. + +* Additional required properties for System Trace Macrocells (STM): + * reg: along with the physical base address and length of the register + set as described above, another entry is required to describe the + mapping of the extended stimulus port area. + + * reg-names: the only acceptable values are "stm-base" and + "stm-stimulus-base", each corresponding to the areas defined in "reg". + +* Required properties for devices that don't show up on the AMBA bus, such as + non-configurable replicators: + + * compatible: Currently supported value is (note the absence of the + AMBA markee): + - "arm,coresight-replicator" + - "arm,coresight-cti" + - "qcom,coresight-tpda" + - "qcom,coresight-tpdm" + - "qcom,coresight-csr" + - "qcom,coresight-hwevent" + - "qcom,coresight-dummy" + - "qcom,coresight-remote-etm" + + * port or ports: same as above. + + * coresight-name: unique descriptive name of the component. + +* Additional required property for coresight-tgu devices: + * tgu-steps: must be present. Indicates number of steps supported + by the TGU. + * tgu-conditions: must be present. Indicates the number of conditions + supported by the TGU. + * tgu-regs: must be present. Indicates the number of regs supported + by the TGU. + * tgu-timer-counters: must be present. Indicates the number of timers and + counters available in the TGU to do a comparision. + +* Optional properties for all components: + * reg-names: names corresponding to each reg property value. + + * qcom,proxy-regs: List of regulators required. + + * qcom,proxy-clks: List of additional clocks required. + +* Optional properties for ETM/PTMs: + + * arm,cp14: must be present if the system accesses ETM/PTM management + registers via co-processor 14. + + * cpu: the cpu phandle this ETM/PTM is affined to. When omitted the + source is considered to belong to CPU0. + + * qcom,tupwr-disable: For ETM, don't keep trace unit powered across power + collapse. + +* Optional property for TMC: + + * arm,buffer-size: size of contiguous buffer space for TMC ETR + (embedded trace router). This property is obsolete. The buffer size + can be configured dynamically via buffer_size property in sysfs. + + * arm,scatter-gather: boolean. Indicates that the TMC-ETR can safely + use the SG mode on this system. + + * arm,default-sink: represents the default compile time CoreSight sink + + * coresight-ctis: represents flush and reset CTIs for TMC buffer + + * qcom,force-reg-dump: enables TMC reg dump support + + * qcom,sw-usb: enables SW mode USB support for TMC ETR + + * arm,sg-enable : indicates whether scatter gather feature is enabled + by default for TMC ETR configuration. + +* Optional property for CATU : + * interrupts : Exactly one SPI may be listed for reporting the address + error + +* Required property for TPDAs: + + * qcom,tpda-atid: must be present. Specifies the ATID for TPDA. + +* Optional properties for TPDAs: + + * qcom,bc-elem-size: specifies the BC element size supported by each + monitor connected to the aggregator on each port. Should be specified + in pairs (port, bc element size). + + * qcom,tc-elem-size: specifies the TC element size supported by each + monitor connected to the aggregator on each port. Should be specified + in pairs (port, tc element size). + + * qcom,dsb-elem-size: specifies the DSB element size supported by each + monitor connected to the aggregator on each port. Should be specified + in pairs (port, dsb element size). + + * qcom,cmb-elem-size: specifies the CMB element size supported by each + monitor connected to the aggregator on each port. Should be specified + in pairs (port, cmb element size). + +* Optional properties for TPDM: + + * qcom,clk-enable: specifies whether additional clock bit needs to be + set for M4M TPDM. + + * qcom,msr-fix-req: boolean, indicating if MSRs need to be programmed + after enabling the subunit. + + * qcom,hw-enable-check: Check if the tpdm need to be probed as some tpdms + are not enabled in secure device. + +* Optional properties for CSRs: + + * qcom,usb-bam-support: boolean, indicates CSR has the ability to operate on + usb bam, include enable,disable and flush. + + * qcom,hwctrl-set-support: boolean, indicates CSR has the ability to operate on + to "HWCTRL" register. + + * qcom,set-byte-cntr-support:boolean, indicates CSR has the ability to operate on + to "BYTECNT" register. + + * qcom,timestamp-support:boolean, indicates CSR support sys interface to read + timestamp value. + * qcom,aodbg-csr-support: boolean, indicates this CSR is AODBG CSR. + +* Required property for Remote ETMs: + + * qcom,inst-id: must be present. QMI instance id for remote ETMs. + +* Optional properties for funnels: + + * source: specifies the source that binds to this output port. Only + trace from that source routes to this output port. + + * qcom,duplicate-funnel: boolean, indicates its a duplicate of an + existing funnel. Funnel devices are now capable of supporting + multiple-input and multiple-output configuration with in built + hardware filtering for TPDM devices. Each set of input-output + combination is treated as independent funnel device. + funnel-base-dummy and funnel-base-real reg-names must be specified + when this property is enabled. + + * reg-names: funnel-base-dummy: dummy register space used by a + duplicate funnel. Should be a valid register address space that + no other device is using. + + * reg-names: funnel-base-real: actual register space for the + duplicate funnel. + +Example: + +1. Sinks + etb@20010000 { + compatible = "arm,coresight-etb10", "arm,primecell"; + reg = <0 0x20010000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + etb_in_port: endpoint@0 { + slave-mode; + remote-endpoint = <&replicator_out_port0>; + }; + }; + }; + + tpiu@20030000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0 0x20030000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + tpiu_in_port: endpoint@0 { + slave-mode; + remote-endpoint = <&replicator_out_port1>; + }; + }; + }; + + etr@20070000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0 0x20070000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* input port */ + port@0 { + reg = <0>; + etr_in_port: endpoint { + slave-mode; + remote-endpoint = <&replicator2_out_port0>; + }; + }; + + /* CATU link represented by output port */ + port@1 { + reg = <1>; + etr_out_port: endpoint { + remote-endpoint = <&catu_in_port>; + }; + }; + }; + }; + +2. Links + replicator { + /* non-configurable replicators don't show up on the + * AMBA bus. As such no need to add "arm,primecell". + */ + compatible = "arm,coresight-replicator"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* replicator output ports */ + port@0 { + reg = <0>; + replicator_out_port0: endpoint { + remote-endpoint = <&etb_in_port>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_port1: endpoint { + remote-endpoint = <&tpiu_in_port>; + }; + }; + + /* replicator input port */ + port@2 { + reg = <0>; + replicator_in_port0: endpoint { + slave-mode; + remote-endpoint = <&funnel_out_port0>; + }; + }; + }; + }; + + funnel@20040000 { + compatible = "arm,coresight-funnel", "arm,primecell"; + reg = <0 0x20040000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* funnel output port */ + port@0 { + reg = <0>; + funnel_out_port0: endpoint { + remote-endpoint = + <&replicator_in_port0>; + }; + }; + + /* funnel input ports */ + port@1 { + reg = <0>; + funnel_in_port0: endpoint { + slave-mode; + remote-endpoint = <&ptm0_out_port>; + }; + }; + + port@2 { + reg = <1>; + funnel_in_port1: endpoint { + slave-mode; + remote-endpoint = <&ptm1_out_port>; + }; + }; + + port@3 { + reg = <2>; + funnel_in_port2: endpoint { + slave-mode; + remote-endpoint = <&etm0_out_port>; + }; + }; + + }; + }; + + tpda_mss: tpda@7043000 { + compatible = "qcom,coresight-tpda", "arm,primecell"; + reg = <0x7043000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-mss"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop qdss_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_mss_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpda_mss>; + }; + }; + port@1 { + reg = <0>; + tpda_mss_in_tpdm_mss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mss_out_tpda_mss>; + }; + }; + }; + }; +3. Sources + ptm@2201c000 { + compatible = "arm,coresight-etm3x", "arm,primecell"; + reg = <0 0x2201c000 0 0x1000>; + + cpu = <&cpu0>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + ptm0_out_port: endpoint { + remote-endpoint = <&funnel_in_port0>; + }; + }; + }; + + ptm@2201d000 { + compatible = "arm,coresight-etm3x", "arm,primecell"; + reg = <0 0x2201d000 0 0x1000>; + + cpu = <&cpu1>; + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + port { + ptm1_out_port: endpoint { + remote-endpoint = <&funnel_in_port1>; + }; + }; + }; + +4. STM + stm@20100000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0 0x20100000 0 0x1000>, + <0 0x28000000 0 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + port { + stm_out_port: endpoint { + remote-endpoint = <&main_funnel_in_port2>; + }; + }; + }; + +5. CATU + + catu@207e0000 { + compatible = "arm,coresight-catu", "arm,primecell"; + reg = <0 0x207e0000 0 0x1000>; + + clocks = <&oscclk6a>; + clock-names = "apb_pclk"; + + interrupts = ; + port { + catu_in_port: endpoint { + slave-mode; + remote-endpoint = <&etr_out_port>; + }; + }; + }; + + tpdm_mss: tpdm@7042000 { + compatible = "qcom,coresight-tpdm", "arm,primecell"; + reg = <0x7042000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mss"; + + clocks = <&clock_aop qdss_clk>; + clock-names = "apb_pclk"; + + port{ + tpdm_mss_out_tpda_mss: endpoint { + remote-endpoint = <&tpda_mss_in_tpdm_mss>; + }; + }; +}; + +5. TGUs + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06B0C000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; +[1]. There is currently two version of STM: STM32 and STM500. Both +have the same HW interface and as such don't need an explicit binding name. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cpu-capacity.txt b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-capacity.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b5685a1d15d9821efb9dd6d34a29ae1f788e31f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-capacity.txt @@ -0,0 +1,236 @@ +========================================== +ARM CPUs capacity bindings +========================================== + +========================================== +1 - Introduction +========================================== + +ARM systems may be configured to have cpus with different power/performance +characteristics within the same chip. In this case, additional information has +to be made available to the kernel for it to be aware of such differences and +take decisions accordingly. + +========================================== +2 - CPU capacity definition +========================================== + +CPU capacity is a number that provides the scheduler information about CPUs +heterogeneity. Such heterogeneity can come from micro-architectural differences +(e.g., ARM big.LITTLE systems) or maximum frequency at which CPUs can run +(e.g., SMP systems with multiple frequency domains). Heterogeneity in this +context is about differing performance characteristics; this binding tries to +capture a first-order approximation of the relative performance of CPUs. + +CPU capacities are obtained by running a suitable benchmark. This binding makes +no guarantees on the validity or suitability of any particular benchmark, the +final capacity should, however, be: + +* A "single-threaded" or CPU affine benchmark +* Divided by the running frequency of the CPU executing the benchmark +* Not subject to dynamic frequency scaling of the CPU + +For the time being we however advise usage of the Dhrystone benchmark. What +above thus becomes: + +CPU capacities are obtained by running the Dhrystone benchmark on each CPU at +max frequency (with caches enabled). The obtained DMIPS score is then divided +by the frequency (in MHz) at which the benchmark has been run, so that +DMIPS/MHz are obtained. Such values are then normalized w.r.t. the highest +score obtained in the system. + +========================================== +3 - capacity-dmips-mhz +========================================== + +capacity-dmips-mhz is an optional cpu node [1] property: u32 value +representing CPU capacity expressed in normalized DMIPS/MHz. At boot time, the +maximum frequency available to the cpu is then used to calculate the capacity +value internally used by the kernel. + +capacity-dmips-mhz property is all-or-nothing: if it is specified for a cpu +node, it has to be specified for every other cpu nodes, or the system will +fall back to the default capacity value for every CPU. If cpufreq is not +available, final capacities are calculated by directly using capacity-dmips- +mhz values (normalized w.r.t. the highest value found while parsing the DT). + +=========================================== +4 - Examples +=========================================== + +Example 1 (ARM 64-bit, 6-cpu system, two clusters): +capacities-dmips-mhz are scaled w.r.t. 1024 (cpu@0 and cpu@1) +supposing cluster0@max-freq=1100 and custer1@max-freq=850, +final capacities are 1024 for cluster0 and 446 for cluster1 + +cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&A57_0>; + }; + core1 { + cpu = <&A57_1>; + }; + }; + + cluster1 { + core0 { + cpu = <&A53_0>; + }; + core1 { + cpu = <&A53_1>; + }; + core2 { + cpu = <&A53_2>; + }; + core3 { + cpu = <&A53_3>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + CPU_SLEEP_0: cpu-sleep-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + local-timer-stop; + entry-latency-us = <100>; + exit-latency-us = <250>; + min-residency-us = <150>; + }; + + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x1010000>; + local-timer-stop; + entry-latency-us = <800>; + exit-latency-us = <700>; + min-residency-us = <2500>; + }; + }; + + A57_0: cpu@0 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x0 0x0>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A57_L2>; + clocks = <&scpi_dvfs 0>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + capacity-dmips-mhz = <1024>; + }; + + A57_1: cpu@1 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x0 0x1>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A57_L2>; + clocks = <&scpi_dvfs 0>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + capacity-dmips-mhz = <1024>; + }; + + A53_0: cpu@100 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x100>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + capacity-dmips-mhz = <578>; + }; + + A53_1: cpu@101 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x101>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + capacity-dmips-mhz = <578>; + }; + + A53_2: cpu@102 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x102>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + capacity-dmips-mhz = <578>; + }; + + A53_3: cpu@103 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x103>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + clocks = <&scpi_dvfs 1>; + cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; + capacity-dmips-mhz = <578>; + }; + + A57_L2: l2-cache0 { + compatible = "cache"; + }; + + A53_L2: l2-cache1 { + compatible = "cache"; + }; +}; + +Example 2 (ARM 32-bit, 4-cpu system, two clusters, + cpus 0,1@1GHz, cpus 2,3@500MHz): +capacities-dmips-mhz are scaled w.r.t. 2 (cpu@0 and cpu@1), this means that first +cpu@0 and cpu@1 are twice fast than cpu@2 and cpu@3 (at the same frequency) + +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0>; + capacity-dmips-mhz = <2>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <1>; + capacity-dmips-mhz = <2>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x100>; + capacity-dmips-mhz = <1>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x101>; + capacity-dmips-mhz = <1>; + }; +}; + +=========================================== +5 - References +=========================================== + +[1] ARM Linux Kernel documentation - CPUs bindings + Documentation/devicetree/bindings/arm/cpus.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/al,alpine-smp b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/al,alpine-smp new file mode 100644 index 0000000000000000000000000000000000000000..c2e0cc5e4cfdd39e08d4e34f06cf9c4a6d04e8f6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/al,alpine-smp @@ -0,0 +1,52 @@ +======================================================== +Secondary CPU enable-method "al,alpine-smp" binding +======================================================== + +This document describes the "al,alpine-smp" method for +enabling secondary CPUs. To apply to all CPUs, a single +"al,alpine-smp" enable method should be defined in the +"cpus" node. + +Enable method name: "al,alpine-smp" +Compatible machines: "al,alpine" +Compatible CPUs: "arm,cortex-a15" +Related properties: (none) + +Note: +This enable method requires valid nodes compatible with +"al,alpine-cpu-resume" and "al,alpine-nb-service"[1]. + +Example: + +cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "al,alpine-smp"; + + cpu@0 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <0>; + }; + + cpu@1 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <1>; + }; + + cpu@2 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <2>; + }; + + cpu@3 { + compatible = "arm,cortex-a15"; + device_type = "cpu"; + reg = <3>; + }; +}; + +-- +[1] arm/al,alpine.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/marvell,berlin-smp b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/marvell,berlin-smp new file mode 100644 index 0000000000000000000000000000000000000000..cd236b727e2a12b0339c56998136302fce2daddb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/marvell,berlin-smp @@ -0,0 +1,41 @@ +======================================================== +Secondary CPU enable-method "marvell,berlin-smp" binding +======================================================== + +This document describes the "marvell,berlin-smp" method for enabling secondary +CPUs. To apply to all CPUs, a single "marvell,berlin-smp" enable method should +be defined in the "cpus" node. + +Enable method name: "marvell,berlin-smp" +Compatible machines: "marvell,berlin2" and "marvell,berlin2q" +Compatible CPUs: "marvell,pj4b" and "arm,cortex-a9" +Related properties: (none) + +Note: +This enable method needs valid nodes compatible with "arm,cortex-a9-scu" and +"marvell,berlin-cpu-ctrl"[1]. + +Example: + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "marvell,berlin-smp"; + + cpu@0 { + compatible = "marvell,pj4b"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <0>; + }; + + cpu@1 { + compatible = "marvell,pj4b"; + device_type = "cpu"; + next-level-cache = <&l2>; + reg = <1>; + }; + }; + +-- +[1] arm/marvell,berlin.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/nuvoton,npcm750-smp b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/nuvoton,npcm750-smp new file mode 100644 index 0000000000000000000000000000000000000000..8e043301e28e58e153eb5896cf277614d54d6dc1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cpu-enable-method/nuvoton,npcm750-smp @@ -0,0 +1,42 @@ +========================================================= +Secondary CPU enable-method "nuvoton,npcm750-smp" binding +========================================================= + +To apply to all CPUs, a single "nuvoton,npcm750-smp" enable method should be +defined in the "cpus" node. + +Enable method name: "nuvoton,npcm750-smp" +Compatible machines: "nuvoton,npcm750" +Compatible CPUs: "arm,cortex-a9" +Related properties: (none) + +Note: +This enable method needs valid nodes compatible with "arm,cortex-a9-scu" and +"nuvoton,npcm750-gcr". + +Example: + + cpus { + #address-cells = <1>; + #size-cells = <0>; + enable-method = "nuvoton,npcm750-smp"; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + clocks = <&clk NPCM7XX_CLK_CPU>; + clock-names = "clk_cpu"; + reg = <0>; + next-level-cache = <&L2>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a9"; + clocks = <&clk NPCM7XX_CLK_CPU>; + clock-names = "clk_cpu"; + reg = <1>; + next-level-cache = <&L2>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/cpus.txt b/arch/arm64/boot/dts/vendor/bindings/arm/cpus.txt new file mode 100644 index 0000000000000000000000000000000000000000..96dfccc0faa8d9471d52900150b6dea9ad96ff62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/cpus.txt @@ -0,0 +1,490 @@ +================= +ARM CPUs bindings +================= + +The device tree allows to describe the layout of CPUs in a system through +the "cpus" node, which in turn contains a number of subnodes (ie "cpu") +defining properties for every cpu. + +Bindings for CPU nodes follow the Devicetree Specification, available from: + +https://www.devicetree.org/specifications/ + +with updates for 32-bit and 64-bit ARM systems provided in this document. + +================================ +Convention used in this document +================================ + +This document follows the conventions described in the Devicetree +Specification, with the addition: + +- square brackets define bitfields, eg reg[7:0] value of the bitfield in + the reg property contained in bits 7 down to 0 + +===================================== +cpus and cpu node bindings definition +===================================== + +The ARM architecture, in accordance with the Devicetree Specification, +requires the cpus and cpu nodes to be present and contain the properties +described below. + +- cpus node + + Description: Container of cpu nodes + + The node name must be "cpus". + + A cpus node must define the following properties: + + - #address-cells + Usage: required + Value type: + + Definition depends on ARM architecture version and + configuration: + + # On uniprocessor ARM architectures previous to v7 + value must be 1, to enable a simple enumeration + scheme for processors that do not have a HW CPU + identification register. + # On 32-bit ARM 11 MPcore, ARM v7 or later systems + value must be 1, that corresponds to CPUID/MPIDR + registers sizes. + # On ARM v8 64-bit systems value should be set to 2, + that corresponds to the MPIDR_EL1 register size. + If MPIDR_EL1[63:32] value is equal to 0 on all CPUs + in the system, #address-cells can be set to 1, since + MPIDR_EL1[63:32] bits are not used for CPUs + identification. + - #size-cells + Usage: required + Value type: + Definition: must be set to 0 + +- cpu node + + Description: Describes a CPU in an ARM based system + + PROPERTIES + + - device_type + Usage: required + Value type: + Definition: must be "cpu" + - reg + Usage and definition depend on ARM architecture version and + configuration: + + # On uniprocessor ARM architectures previous to v7 + this property is required and must be set to 0. + + # On ARM 11 MPcore based systems this property is + required and matches the CPUID[11:0] register bits. + + Bits [11:0] in the reg cell must be set to + bits [11:0] in CPU ID register. + + All other bits in the reg cell must be set to 0. + + # On 32-bit ARM v7 or later systems this property is + required and matches the CPU MPIDR[23:0] register + bits. + + Bits [23:0] in the reg cell must be set to + bits [23:0] in MPIDR. + + All other bits in the reg cell must be set to 0. + + # On ARM v8 64-bit systems this property is required + and matches the MPIDR_EL1 register affinity bits. + + * If cpus node's #address-cells property is set to 2 + + The first reg cell bits [7:0] must be set to + bits [39:32] of MPIDR_EL1. + + The second reg cell bits [23:0] must be set to + bits [23:0] of MPIDR_EL1. + + * If cpus node's #address-cells property is set to 1 + + The reg cell bits [23:0] must be set to bits [23:0] + of MPIDR_EL1. + + All other bits in the reg cells must be set to 0. + + - compatible: + Usage: required + Value type: + Definition: should be one of: + "arm,arm710t" + "arm,arm720t" + "arm,arm740t" + "arm,arm7ej-s" + "arm,arm7tdmi" + "arm,arm7tdmi-s" + "arm,arm9es" + "arm,arm9ej-s" + "arm,arm920t" + "arm,arm922t" + "arm,arm925" + "arm,arm926e-s" + "arm,arm926ej-s" + "arm,arm940t" + "arm,arm946e-s" + "arm,arm966e-s" + "arm,arm968e-s" + "arm,arm9tdmi" + "arm,arm1020e" + "arm,arm1020t" + "arm,arm1022e" + "arm,arm1026ej-s" + "arm,arm1136j-s" + "arm,arm1136jf-s" + "arm,arm1156t2-s" + "arm,arm1156t2f-s" + "arm,arm1176jzf" + "arm,arm1176jz-s" + "arm,arm1176jzf-s" + "arm,arm11mpcore" + "arm,cortex-a5" + "arm,cortex-a7" + "arm,cortex-a8" + "arm,cortex-a9" + "arm,cortex-a12" + "arm,cortex-a15" + "arm,cortex-a17" + "arm,cortex-a53" + "arm,cortex-a57" + "arm,cortex-a72" + "arm,cortex-a73" + "arm,cortex-m0" + "arm,cortex-m0+" + "arm,cortex-m1" + "arm,cortex-m3" + "arm,cortex-m4" + "arm,cortex-r4" + "arm,cortex-r5" + "arm,cortex-r7" + "brcm,brahma-b15" + "brcm,brahma-b53" + "brcm,vulcan" + "cavium,thunder" + "cavium,thunder2" + "faraday,fa526" + "intel,sa110" + "intel,sa1100" + "marvell,feroceon" + "marvell,mohawk" + "marvell,pj4a" + "marvell,pj4b" + "marvell,sheeva-v5" + "nvidia,tegra132-denver" + "nvidia,tegra186-denver" + "nvidia,tegra194-carmel" + "qcom,krait" + "qcom,kryo" + "qcom,kryo385" + "qcom,scorpion" + - enable-method + Value type: + Usage and definition depend on ARM architecture version. + # On ARM v8 64-bit this property is required and must + be one of: + "psci" + "spin-table" + # On ARM 32-bit systems this property is optional and + can be one of: + "actions,s500-smp" + "allwinner,sun6i-a31" + "allwinner,sun8i-a23" + "allwinner,sun9i-a80-smp" + "amlogic,meson8-smp" + "amlogic,meson8b-smp" + "arm,realview-smp" + "brcm,bcm11351-cpu-method" + "brcm,bcm23550" + "brcm,bcm2836-smp" + "brcm,bcm-nsp-smp" + "brcm,brahma-b15" + "marvell,armada-375-smp" + "marvell,armada-380-smp" + "marvell,armada-390-smp" + "marvell,armada-xp-smp" + "marvell,98dx3236-smp" + "mediatek,mt6589-smp" + "mediatek,mt81xx-tz-smp" + "qcom,gcc-msm8660" + "qcom,kpss-acc-v1" + "qcom,kpss-acc-v2" + "renesas,apmu" + "renesas,r9a06g032-smp" + "rockchip,rk3036-smp" + "rockchip,rk3066-smp" + "ste,dbx500-smp" + + - cpu-release-addr + Usage: required for systems that have an "enable-method" + property value of "spin-table". + Value type: + Definition: + # On ARM v8 64-bit systems must be a two cell + property identifying a 64-bit zero-initialised + memory location. + + - qcom,saw + Usage: required for systems that have an "enable-method" + property value of "qcom,kpss-acc-v1" or + "qcom,kpss-acc-v2" + Value type: + Definition: Specifies the SAW[1] node associated with this CPU. + + - qcom,acc + Usage: required for systems that have an "enable-method" + property value of "qcom,kpss-acc-v1" or + "qcom,kpss-acc-v2" + Value type: + Definition: Specifies the ACC[2] node associated with this CPU. + + - cpu-idle-states + Usage: Optional + Value type: + Definition: + # List of phandles to idle state nodes supported + by this cpu [3]. + + - capacity-dmips-mhz + Usage: Optional + Value type: + Definition: + # u32 value representing CPU capacity [4] in + DMIPS/MHz, relative to highest capacity-dmips-mhz + in the system. + + - rockchip,pmu + Usage: optional for systems that have an "enable-method" + property value of "rockchip,rk3066-smp" + While optional, it is the preferred way to get access to + the cpu-core power-domains. + Value type: + Definition: Specifies the syscon node controlling the cpu core + power domains. + + - dynamic-power-coefficient + Usage: optional + Value type: + Definition: A u32 value that represents the running time dynamic + power coefficient in units of mW/MHz/uV^2. The + coefficient can either be calculated from power + measurements or derived by analysis. + + The dynamic power consumption of the CPU is + proportional to the square of the Voltage (V) and + the clock frequency (f). The coefficient is used to + calculate the dynamic power as below - + + Pdyn = dynamic-power-coefficient * V^2 * f + + where voltage is in uV, frequency is in MHz. + +Example 1 (dual-cluster big.LITTLE system 32-bit): + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x1>; + }; + + cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x100>; + }; + + cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x101>; + }; + }; + +Example 2 (Cortex-A8 uniprocessor 32-bit system): + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a8"; + reg = <0x0>; + }; + }; + +Example 3 (ARM 926EJ-S uniprocessor 32-bit system): + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,arm926ej-s"; + reg = <0x0>; + }; + }; + +Example 4 (ARM Cortex-A57 64-bit system): + +cpus { + #size-cells = <0>; + #address-cells = <2>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@10000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10000>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@10001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10001>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@10100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@10101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100000000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100000001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100000100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100000101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100010000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10000>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100010001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10001>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100010100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + cpu@100010101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; +}; + +-- +[1] arm/msm/qcom,saw2.txt +[2] arm/msm/qcom,kpss-acc.txt +[3] ARM Linux kernel documentation - idle states bindings + Documentation/devicetree/bindings/arm/idle-states.txt +[4] ARM Linux kernel documentation - cpu capacity bindings + Documentation/devicetree/bindings/arm/cpu-capacity.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/davinci.txt b/arch/arm64/boot/dts/vendor/bindings/arm/davinci.txt new file mode 100644 index 0000000000000000000000000000000000000000..715622c36260396a54d4934addf4c8645a29e2ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/davinci.txt @@ -0,0 +1,25 @@ +Texas Instruments DaVinci Platforms Device Tree Bindings +-------------------------------------------------------- + +DA850/OMAP-L138/AM18x Evaluation Module (EVM) board +Required root node properties: + - compatible = "ti,da850-evm", "ti,da850"; + +DA850/OMAP-L138/AM18x L138/C6748 Development Kit (LCDK) board +Required root node properties: + - compatible = "ti,da850-lcdk", "ti,da850"; + +EnBW AM1808 based CMC board +Required root node properties: + - compatible = "enbw,cmc", "ti,da850; + +LEGO MINDSTORMS EV3 (AM1808 based) +Required root node properties: + - compatible = "lego,ev3", "ti,da850"; + +Generic DaVinci Boards +---------------------- + +DA850/OMAP-L138/AM18x generic board +Required root node properties: + - compatible = "ti,da850"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/digicolor.txt b/arch/arm64/boot/dts/vendor/bindings/arm/digicolor.txt new file mode 100644 index 0000000000000000000000000000000000000000..658553f40b238e01499ed40cde8b0bc96fdfe065 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/digicolor.txt @@ -0,0 +1,6 @@ +Conexant Digicolor Platforms Device Tree Bindings + +Each device tree must specify which Conexant Digicolor SoC it uses. +Must be the following compatible string: + + cnxt,cx92755 diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/firmware/linaro,optee-tz.txt b/arch/arm64/boot/dts/vendor/bindings/arm/firmware/linaro,optee-tz.txt new file mode 100644 index 0000000000000000000000000000000000000000..d38834c67dffe910af59fa15531b9fcd2303a33b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/firmware/linaro,optee-tz.txt @@ -0,0 +1,31 @@ +OP-TEE Device Tree Bindings + +OP-TEE is a piece of software using hardware features to provide a Trusted +Execution Environment. The security can be provided with ARM TrustZone, but +also by virtualization or a separate chip. + +We're using "linaro" as the first part of the compatible property for +the reference implementation maintained by Linaro. + +* OP-TEE based on ARM TrustZone required properties: + +- compatible : should contain "linaro,optee-tz" + +- method : The method of calling the OP-TEE Trusted OS. Permitted + values are: + + "smc" : SMC #0, with the register assignments specified + in drivers/tee/optee/optee_smc.h + + "hvc" : HVC #0, with the register assignments specified + in drivers/tee/optee/optee_smc.h + + + +Example: + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/firmware/sdei.txt b/arch/arm64/boot/dts/vendor/bindings/arm/firmware/sdei.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee3f0ff49889452a5ece6cb4cc79abcaa001be4f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/firmware/sdei.txt @@ -0,0 +1,42 @@ +* Software Delegated Exception Interface (SDEI) + +Firmware implementing the SDEI functions described in ARM document number +ARM DEN 0054A ("Software Delegated Exception Interface") can be used by +Linux to receive notification of events such as those generated by +firmware-first error handling, or from an IRQ that has been promoted to +a firmware-assisted NMI. + +The interface provides a number of API functions for registering callbacks +and enabling/disabling events. Functions are invoked by trapping to the +privilege level of the SDEI firmware (specified as part of the binding +below) and passing arguments in a manner specified by the "SMC Calling +Convention (ARM DEN 0028B): + + r0 => 32-bit Function ID / return value + {r1 - r3} => Parameters + +Note that the immediate field of the trapping instruction must be set +to #0. + +The SDEI_EVENT_REGISTER function registers a callback in the kernel +text to handle the specified event number. + +The sdei node should be a child node of '/firmware' and have required +properties: + + - compatible : should contain: + * "arm,sdei-1.0" : For implementations complying to SDEI version 1.x. + + - method : The method of calling the SDEI firmware. Permitted + values are: + * "smc" : SMC #0, with the register assignments specified in this + binding. + * "hvc" : HVC #0, with the register assignments specified in this + binding. +Example: + firmware { + sdei { + compatible = "arm,sdei-1.0"; + method = "smc"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/firmware/tlm,trusted-foundations.txt b/arch/arm64/boot/dts/vendor/bindings/arm/firmware/tlm,trusted-foundations.txt new file mode 100644 index 0000000000000000000000000000000000000000..780d0392a66b537ba6e0780c5daa8269a3c7f121 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/firmware/tlm,trusted-foundations.txt @@ -0,0 +1,20 @@ +Trusted Foundations +------------------- + +Boards that use the Trusted Foundations secure monitor can signal its +presence by declaring a node compatible with "tlm,trusted-foundations" +under the /firmware/ node + +Required properties: +- compatible: "tlm,trusted-foundations" +- tlm,version-major: major version number of Trusted Foundations firmware +- tlm,version-minor: minor version number of Trusted Foundations firmware + +Example: + firmware { + trusted-foundations { + compatible = "tlm,trusted-foundations"; + tlm,version-major = <2>; + tlm,version-minor = <8>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..44aa3c451ccf70f6d7e3e3a5fbc47f2b67cb5bf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt @@ -0,0 +1,14 @@ +Freescale Vybrid Miscellaneous System Control - CPU Configuration + +The MSCM IP contains multiple sub modules, this binding describes the first +block of registers which contains CPU configuration information. + +Required properties: +- compatible: "fsl,vf610-mscm-cpucfg", "syscon" +- reg: the register range of the MSCM CPU configuration registers + +Example: + mscm_cpucfg: cpucfg@40001000 { + compatible = "fsl,vf610-mscm-cpucfg", "syscon"; + reg = <0x40001000 0x800>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/freescale/fsl,vf610-mscm-ir.txt b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/fsl,vf610-mscm-ir.txt new file mode 100644 index 0000000000000000000000000000000000000000..6dd6f399236d5c51c0497cefeffc58407a79443f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/fsl,vf610-mscm-ir.txt @@ -0,0 +1,30 @@ +Freescale Vybrid Miscellaneous System Control - Interrupt Router + +The MSCM IP contains multiple sub modules, this binding describes the second +block of registers which control the interrupt router. The interrupt router +allows to configure the recipient of each peripheral interrupt. Furthermore +it controls the directed processor interrupts. The module is available in all +Vybrid SoC's but is only really useful in dual core configurations (VF6xx +which comes with a Cortex-A5/Cortex-M4 combination). + +Required properties: +- compatible: "fsl,vf610-mscm-ir" +- reg: the register range of the MSCM Interrupt Router +- fsl,cpucfg: The handle to the MSCM CPU configuration node, required + to get the current CPU ID +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: Two cells, interrupt number and cells. + The hardware interrupt number according to interrupt + assignment of the interrupt router is required. + Flags get passed only when using GIC as parent. Flags + encoding as documented by the GIC bindings. + +Example: + mscm_ir: interrupt-controller@40001800 { + compatible = "fsl,vf610-mscm-ir"; + reg = <0x40001800 0x400>; + fsl,cpucfg = <&mscm_cpucfg>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/freescale/m4if.txt b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/m4if.txt new file mode 100644 index 0000000000000000000000000000000000000000..93bd7b867a5367dc2009f0b34f6c3d27c71e0dca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/m4if.txt @@ -0,0 +1,12 @@ +* Freescale Multi Master Multi Memory Interface (M4IF) module + +Required properties: +- compatible : Should be "fsl,imx51-m4if" +- reg : Address and length of the register set for the device + +Example: + +m4if: m4if@83fd8000 { + compatible = "fsl,imx51-m4if"; + reg = <0x83fd8000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/freescale/tigerp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/tigerp.txt new file mode 100644 index 0000000000000000000000000000000000000000..19e2aad63d6efb35cbd21edd530d057278d4fb57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/freescale/tigerp.txt @@ -0,0 +1,12 @@ +* Freescale Tigerp platform module + +Required properties: +- compatible : Should be "fsl,imx51-tigerp" +- reg : Address and length of the register set for the device + +Example: + +tigerp: tigerp@83fa0000 { + compatible = "fsl,imx51-tigerp"; + reg = <0x83fa0000 0x28>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/fsl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/fsl.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a1baa2b9723aa4014701260ab2597f2b8215281 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/fsl.txt @@ -0,0 +1,224 @@ +Freescale i.MX Platforms Device Tree Bindings +----------------------------------------------- + +i.MX23 Evaluation Kit +Required root node properties: + - compatible = "fsl,imx23-evk", "fsl,imx23"; + +i.MX25 Product Development Kit +Required root node properties: + - compatible = "fsl,imx25-pdk", "fsl,imx25"; + +i.MX27 Product Development Kit +Required root node properties: + - compatible = "fsl,imx27-pdk", "fsl,imx27"; + +i.MX28 Evaluation Kit +Required root node properties: + - compatible = "fsl,imx28-evk", "fsl,imx28"; + +i.MX51 Babbage Board +Required root node properties: + - compatible = "fsl,imx51-babbage", "fsl,imx51"; + +i.MX53 Automotive Reference Design Board +Required root node properties: + - compatible = "fsl,imx53-ard", "fsl,imx53"; + +i.MX53 Evaluation Kit +Required root node properties: + - compatible = "fsl,imx53-evk", "fsl,imx53"; + +i.MX53 Quick Start Board +Required root node properties: + - compatible = "fsl,imx53-qsb", "fsl,imx53"; + +i.MX53 Smart Mobile Reference Design Board +Required root node properties: + - compatible = "fsl,imx53-smd", "fsl,imx53"; + +i.MX6 Quad Armadillo2 Board +Required root node properties: + - compatible = "fsl,imx6q-arm2", "fsl,imx6q"; + +i.MX6 Quad SABRE Lite Board +Required root node properties: + - compatible = "fsl,imx6q-sabrelite", "fsl,imx6q"; + +i.MX6 Quad SABRE Smart Device Board +Required root node properties: + - compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; + +i.MX6 Quad SABRE Automotive Board +Required root node properties: + - compatible = "fsl,imx6q-sabreauto", "fsl,imx6q"; + +i.MX6SLL EVK board +Required root node properties: + - compatible = "fsl,imx6sll-evk", "fsl,imx6sll"; + +Generic i.MX boards +------------------- + +No iomux setup is done for these boards, so this must have been configured +by the bootloader for boards to work with the generic bindings. + +i.MX27 generic board +Required root node properties: + - compatible = "fsl,imx27"; + +i.MX51 generic board +Required root node properties: + - compatible = "fsl,imx51"; + +i.MX53 generic board +Required root node properties: + - compatible = "fsl,imx53"; + +i.MX6q generic board +Required root node properties: + - compatible = "fsl,imx6q"; + +Freescale Vybrid Platform Device Tree Bindings +---------------------------------------------- + +For the Vybrid SoC familiy all variants with DDR controller are supported, +which is the VF5xx and VF6xx series. Out of historical reasons, in most +places the kernel uses vf610 to refer to the whole familiy. +The compatible string "fsl,vf610m4" is used for the secondary Cortex-M4 +core support. + +Required root node compatible property (one of them): + - compatible = "fsl,vf500"; + - compatible = "fsl,vf510"; + - compatible = "fsl,vf600"; + - compatible = "fsl,vf610"; + - compatible = "fsl,vf610m4"; + +Freescale LS1021A Platform Device Tree Bindings +------------------------------------------------ + +Required root node compatible properties: + - compatible = "fsl,ls1021a"; + +Freescale SoC-specific Device Tree Bindings +------------------------------------------- + +Freescale SCFG + SCFG is the supplemental configuration unit, that provides SoC specific +configuration and status registers for the chip. Such as getting PEX port +status. + Required properties: + - compatible: Should contain a chip-specific compatible string, + Chip-specific strings are of the form "fsl,-scfg", + The following s are known to be supported: + ls1012a, ls1021a, ls1043a, ls1046a, ls2080a. + + - reg: should contain base address and length of SCFG memory-mapped registers + +Example: + scfg: scfg@1570000 { + compatible = "fsl,ls1021a-scfg"; + reg = <0x0 0x1570000 0x0 0x10000>; + }; + +Freescale DCFG + DCFG is the device configuration unit, that provides general purpose +configuration and status for the device. Such as setting the secondary +core start address and release the secondary core from holdoff and startup. + Required properties: + - compatible: Should contain a chip-specific compatible string, + Chip-specific strings are of the form "fsl,-dcfg", + The following s are known to be supported: + ls1012a, ls1021a, ls1043a, ls1046a, ls2080a. + + - reg : should contain base address and length of DCFG memory-mapped registers + +Example: + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1021a-dcfg"; + reg = <0x0 0x1ee0000 0x0 0x10000>; + }; + +Freescale ARMv8 based Layerscape SoC family Device Tree Bindings +---------------------------------------------------------------- + +LS1012A SoC +Required root node properties: + - compatible = "fsl,ls1012a"; + +LS1012A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls1012a-rdb", "fsl,ls1012a"; + +LS1012A ARMv8 based FRDM Board +Required root node properties: + - compatible = "fsl,ls1012a-frdm", "fsl,ls1012a"; + +LS1012A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls1012a-qds", "fsl,ls1012a"; + +LS1043A SoC +Required root node properties: + - compatible = "fsl,ls1043a"; + +LS1043A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls1043a-rdb", "fsl,ls1043a"; + +LS1043A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls1043a-qds", "fsl,ls1043a"; + +LS1046A SoC +Required root node properties: + - compatible = "fsl,ls1046a"; + +LS1046A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls1046a-qds", "fsl,ls1046a"; + +LS1046A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls1046a-rdb", "fsl,ls1046a"; + +LS1088A SoC +Required root node properties: + - compatible = "fsl,ls1088a"; + +LS1088A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls1088a-qds", "fsl,ls1088a"; + +LS1088A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls1088a-rdb", "fsl,ls1088a"; + +LS2080A SoC +Required root node properties: + - compatible = "fsl,ls2080a"; + +LS2080A ARMv8 based Simulator model +Required root node properties: + - compatible = "fsl,ls2080a-simu", "fsl,ls2080a"; + +LS2080A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls2080a-qds", "fsl,ls2080a"; + +LS2080A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls2080a-rdb", "fsl,ls2080a"; + +LS2088A SoC +Required root node properties: + - compatible = "fsl,ls2088a"; + +LS2088A ARMv8 based QDS Board +Required root node properties: + - compatible = "fsl,ls2088a-qds", "fsl,ls2088a"; + +LS2088A ARMv8 based RDB Board +Required root node properties: + - compatible = "fsl,ls2088a-rdb", "fsl,ls2088a"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/fw-cfg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/fw-cfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd54e1db215652e73606fd899856727f08f8e9e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/fw-cfg.txt @@ -0,0 +1,38 @@ +* QEMU Firmware Configuration bindings for ARM + +QEMU's arm-softmmu and aarch64-softmmu emulation / virtualization targets +provide the following Firmware Configuration interface on the "virt" machine +type: + +- A write-only, 16-bit wide selector (or control) register, +- a read-write, 64-bit wide data register. + +QEMU exposes the control and data register to ARM guests as memory mapped +registers; their location is communicated to the guest's UEFI firmware in the +DTB that QEMU places at the bottom of the guest's DRAM. + +The authoritative guest-side hardware interface documentation to the fw_cfg +device can be found in "docs/specs/fw_cfg.txt" in the QEMU source tree. + + +Required properties: + +- compatible: "qemu,fw-cfg-mmio". + +- reg: the MMIO region used by the device. + * Bytes 0x0 to 0x7 cover the data register. + * Bytes 0x8 to 0x9 cover the selector register. + * Further registers may be appended to the region in case of future interface + revisions / feature bits. + +Example: + +/ { + #size-cells = <0x2>; + #address-cells = <0x2>; + + fw-cfg@9020000 { + compatible = "qemu,fw-cfg-mmio"; + reg = <0x0 0x9020000 0x0 0xa>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/gemini.txt b/arch/arm64/boot/dts/vendor/bindings/arm/gemini.txt new file mode 100644 index 0000000000000000000000000000000000000000..55bf7ce96c4407d11a60210eb4e3644e7f041cb2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/gemini.txt @@ -0,0 +1,108 @@ +Cortina systems Gemini platforms + +The Gemini SoC is the project name for an ARMv4 FA525-based SoC originally +produced by Storlink Semiconductor around 2005. The company was renamed +later renamed Storm Semiconductor. The chip product name is Storlink SL3516. +It was derived from earlier products from Storm named SL3316 (Centroid) and +SL3512 (Bulverde). + +Storm Semiconductor was acquired by Cortina Systems in 2008 and the SoC was +produced and used for NAS and similar usecases. In 2014 Cortina Systems was +in turn acquired by Inphi, who seem to have discontinued this product family. + +Many of the IP blocks used in the SoC comes from Faraday Technology. + +Required properties (in root node): + compatible = "cortina,gemini"; + +Required nodes: + +- soc: the SoC should be represented by a simple bus encompassing all the + onchip devices, this is referred to as the soc bus node. + +- syscon: the soc bus node must have a system controller node pointing to the + global control registers, with the compatible string + "cortina,gemini-syscon", "syscon"; + + Required properties on the syscon: + - reg: syscon register location and size. + - #clock-cells: should be set to <1> - the system controller is also a + clock provider. + - #reset-cells: should be set to <1> - the system controller is also a + reset line provider. + + The clock sources have shorthand defines in the include file: + + + The reset lines have shorthand defines in the include file: + + +- timer: the soc bus node must have a timer node pointing to the SoC timer + block, with the compatible string "cortina,gemini-timer" + See: clocksource/cortina,gemini-timer.txt + +- interrupt-controller: the sob bus node must have an interrupt controller + node pointing to the SoC interrupt controller block, with the compatible + string "cortina,gemini-interrupt-controller" + See interrupt-controller/cortina,gemini-interrupt-controller.txt + +Example: + +/ { + model = "Foo Gemini Machine"; + compatible = "cortina,gemini"; + #address-cells = <1>; + #size-cells = <1>; + + memory { + device_type = "memory"; + reg = <0x00000000 0x8000000>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "simple-bus"; + interrupt-parent = <&intcon>; + + syscon: syscon@40000000 { + compatible = "cortina,gemini-syscon", "syscon"; + reg = <0x40000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + uart0: serial@42000000 { + compatible = "ns16550a"; + reg = <0x42000000 0x100>; + resets = <&syscon GEMINI_RESET_UART>; + clocks = <&syscon GEMINI_CLK_UART>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + reg-shift = <2>; + }; + + timer@43000000 { + compatible = "cortina,gemini-timer"; + reg = <0x43000000 0x1000>; + interrupt-parent = <&intcon>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>, /* Timer 1 */ + <15 IRQ_TYPE_EDGE_FALLING>, /* Timer 2 */ + <16 IRQ_TYPE_EDGE_FALLING>; /* Timer 3 */ + resets = <&syscon GEMINI_RESET_TIMER>; + /* APB clock or RTC clock */ + clocks = <&syscon GEMINI_CLK_APB>, + <&syscon GEMINI_CLK_RTC>; + clock-names = "PCLK", "EXTCLK"; + syscon = <&syscon>; + }; + + intcon: interrupt-controller@48000000 { + compatible = "cortina,gemini-interrupt-controller"; + reg = <0x48000000 0x1000>; + resets = <&syscon GEMINI_RESET_INTCON0>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hi3519-sysctrl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hi3519-sysctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..115c5be0bd0b0a3db9d6fc8df048bfd33ec81622 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hi3519-sysctrl.txt @@ -0,0 +1,14 @@ +* Hisilicon Hi3519 System Controller Block + +This bindings use the following binding: +Documentation/devicetree/bindings/mfd/syscon.txt + +Required properties: +- compatible: "hisilicon,hi3519-sysctrl". +- reg: the register region of this block + +Examples: +sysctrl: system-controller@12010000 { + compatible = "hisilicon,hi3519-sysctrl", "syscon"; + reg = <0x12010000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hisilicon-low-pin-count.txt new file mode 100644 index 0000000000000000000000000000000000000000..10bd35f9207f2eef34be1e97780156f719d960ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hisilicon-low-pin-count.txt @@ -0,0 +1,33 @@ +Hisilicon Hip06 Low Pin Count device + Hisilicon Hip06 SoCs implement a Low Pin Count (LPC) controller, which + provides I/O access to some legacy ISA devices. + Hip06 is based on arm64 architecture where there is no I/O space. So, the + I/O ports here are not CPU addresses, and there is no 'ranges' property in + LPC device node. + +Required properties: +- compatible: value should be as follows: + (a) "hisilicon,hip06-lpc" + (b) "hisilicon,hip07-lpc" +- #address-cells: must be 2 which stick to the ISA/EISA binding doc. +- #size-cells: must be 1 which stick to the ISA/EISA binding doc. +- reg: base memory range where the LPC register set is mapped. + +Note: + The node name before '@' must be "isa" to represent the binding stick to the + ISA/EISA binding specification. + +Example: + +isa@a01b0000 { + compatible = "hisilicon,hip06-lpc"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x0 0xa01b0000 0x0 0x1000>; + + ipmi0: bt@e4 { + compatible = "ipmi-bt"; + device_type = "ipmi"; + reg = <0x01 0xe4 0x04>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hisilicon.txt b/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hisilicon.txt new file mode 100644 index 0000000000000000000000000000000000000000..199cd36fe1ba44b4efe750aa72d179d0e1bbc666 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/hisilicon/hisilicon.txt @@ -0,0 +1,311 @@ +Hisilicon Platforms Device Tree Bindings +---------------------------------------------------- +Hi3660 SoC +Required root node properties: + - compatible = "hisilicon,hi3660"; + +HiKey960 Board +Required root node properties: + - compatible = "hisilicon,hi3660-hikey960", "hisilicon,hi3660"; + +Hi3798cv200 SoC +Required root node properties: + - compatible = "hisilicon,hi3798cv200"; + +Hi3798cv200 Poplar Board +Required root node properties: + - compatible = "hisilicon,hi3798cv200-poplar", "hisilicon,hi3798cv200"; + +Hi4511 Board +Required root node properties: + - compatible = "hisilicon,hi3620-hi4511"; + +Hi6220 SoC +Required root node properties: + - compatible = "hisilicon,hi6220"; + +HiKey Board +Required root node properties: + - compatible = "hisilicon,hi6220-hikey", "hisilicon,hi6220"; + +HiP01 ca9x2 Board +Required root node properties: + - compatible = "hisilicon,hip01-ca9x2"; + +HiP04 D01 Board +Required root node properties: + - compatible = "hisilicon,hip04-d01"; + +HiP05 D02 Board +Required root node properties: + - compatible = "hisilicon,hip05-d02"; + +HiP06 D03 Board +Required root node properties: + - compatible = "hisilicon,hip06-d03"; + +HiP07 D05 Board +Required root node properties: + - compatible = "hisilicon,hip07-d05"; + +Hisilicon system controller + +Required properties: +- compatible : "hisilicon,sysctrl" +- reg : Register address and size + +Optional properties: +- smp-offset : offset in sysctrl for notifying slave cpu booting + cpu 1, reg; + cpu 2, reg + 0x4; + cpu 3, reg + 0x8; + If reg value is not zero, cpun exit wfi and go +- resume-offset : offset in sysctrl for notifying cpu0 when resume +- reboot-offset : offset in sysctrl for system reboot + +Example: + + /* for Hi3620 */ + sysctrl: system-controller@fc802000 { + compatible = "hisilicon,sysctrl"; + reg = <0xfc802000 0x1000>; + smp-offset = <0x31c>; + resume-offset = <0x308>; + reboot-offset = <0x4>; + }; + +----------------------------------------------------------------------- +Hisilicon Hi3798CV200 Peripheral Controller + +The Hi3798CV200 Peripheral Controller controls peripherals, queries +their status, and configures some functions of peripherals. + +Required properties: +- compatible: Should contain "hisilicon,hi3798cv200-perictrl", "syscon" + and "simple-mfd". +- reg: Register address and size of Peripheral Controller. +- #address-cells: Should be 1. +- #size-cells: Should be 1. + +Examples: + + perictrl: peripheral-controller@8a20000 { + compatible = "hisilicon,hi3798cv200-perictrl", "syscon", + "simple-mfd"; + reg = <0x8a20000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + }; + +----------------------------------------------------------------------- +Hisilicon Hi6220 system controller + +Required properties: +- compatible : "hisilicon,hi6220-sysctrl" +- reg : Register address and size +- #clock-cells: should be set to 1, many clock registers are defined + under this controller and this property must be present. + +Hisilicon designs this controller as one of the system controllers, +its main functions are the same as Hisilicon system controller, but +the register offset of some core modules are different. + +Example: + /*for Hi6220*/ + sys_ctrl: sys_ctrl@f7030000 { + compatible = "hisilicon,hi6220-sysctrl", "syscon"; + reg = <0x0 0xf7030000 0x0 0x2000>; + #clock-cells = <1>; + }; + + +Hisilicon Hi6220 Power Always ON domain controller + +Required properties: +- compatible : "hisilicon,hi6220-aoctrl" +- reg : Register address and size +- #clock-cells: should be set to 1, many clock registers are defined + under this controller and this property must be present. + +Hisilicon designs this system controller to control the power always +on domain for mobile platform. + +Example: + /*for Hi6220*/ + ao_ctrl: ao_ctrl@f7800000 { + compatible = "hisilicon,hi6220-aoctrl", "syscon"; + reg = <0x0 0xf7800000 0x0 0x2000>; + #clock-cells = <1>; + }; + + +Hisilicon Hi6220 Media domain controller + +Required properties: +- compatible : "hisilicon,hi6220-mediactrl" +- reg : Register address and size +- #clock-cells: should be set to 1, many clock registers are defined + under this controller and this property must be present. + +Hisilicon designs this system controller to control the multimedia +domain(e.g. codec, G3D ...) for mobile platform. + +Example: + /*for Hi6220*/ + media_ctrl: media_ctrl@f4410000 { + compatible = "hisilicon,hi6220-mediactrl", "syscon"; + reg = <0x0 0xf4410000 0x0 0x1000>; + #clock-cells = <1>; + }; + + +Hisilicon Hi6220 Power Management domain controller + +Required properties: +- compatible : "hisilicon,hi6220-pmctrl" +- reg : Register address and size +- #clock-cells: should be set to 1, some clock registers are define + under this controller and this property must be present. + +Hisilicon designs this system controller to control the power management +domain for mobile platform. + +Example: + /*for Hi6220*/ + pm_ctrl: pm_ctrl@f7032000 { + compatible = "hisilicon,hi6220-pmctrl", "syscon"; + reg = <0x0 0xf7032000 0x0 0x1000>; + #clock-cells = <1>; + }; + + +Hisilicon Hi6220 SRAM controller + +Required properties: +- compatible : "hisilicon,hi6220-sramctrl", "syscon" +- reg : Register address and size + +Hisilicon's SoCs use sram for multiple purpose; on Hi6220 there have several +SRAM banks for power management, modem, security, etc. Further, use "syscon" +managing the common sram which can be shared by multiple modules. + +Example: + /*for Hi6220*/ + sram: sram@fff80000 { + compatible = "hisilicon,hi6220-sramctrl", "syscon"; + reg = <0x0 0xfff80000 0x0 0x12000>; + }; + +----------------------------------------------------------------------- +Hisilicon HiP01 system controller + +Required properties: +- compatible : "hisilicon,hip01-sysctrl" +- reg : Register address and size + +The HiP01 system controller is mostly compatible with hisilicon +system controller,but it has some specific control registers for +HIP01 SoC family, such as slave core boot, and also some same +registers located at different offset. + +Example: + + /* for hip01-ca9x2 */ + sysctrl: system-controller@10000000 { + compatible = "hisilicon,hip01-sysctrl", "hisilicon,sysctrl"; + reg = <0x10000000 0x1000>; + reboot-offset = <0x4>; + }; + +----------------------------------------------------------------------- +Hisilicon HiP05/HiP06 PCIe-SAS sub system controller + +Required properties: +- compatible : "hisilicon,pcie-sas-subctrl", "syscon"; +- reg : Register address and size + +The PCIe-SAS sub system controller is shared by PCIe and SAS controllers in +HiP05 or HiP06 Soc to implement some basic configurations. + +Example: + /* for HiP05 PCIe-SAS sub system */ + pcie_sas: system_controller@b0000000 { + compatible = "hisilicon,pcie-sas-subctrl", "syscon"; + reg = <0xb0000000 0x10000>; + }; + +Hisilicon HiP05/HiP06 PERI sub system controller + +Required properties: +- compatible : "hisilicon,peri-subctrl", "syscon"; +- reg : Register address and size + +The PERI sub system controller is shared by peripheral controllers in +HiP05 or HiP06 Soc to implement some basic configurations. The peripheral +controllers include mdio, ddr, iic, uart, timer and so on. + +Example: + /* for HiP05 sub peri system */ + peri_c_subctrl: syscon@80000000 { + compatible = "hisilicon,peri-subctrl", "syscon"; + reg = <0x0 0x80000000 0x0 0x10000>; + }; + +Hisilicon HiP05/HiP06 DSA sub system controller + +Required properties: +- compatible : "hisilicon,dsa-subctrl", "syscon"; +- reg : Register address and size + +The DSA sub system controller is shared by peripheral controllers in +HiP05 or HiP06 Soc to implement some basic configurations. + +Example: + /* for HiP05 dsa sub system */ + pcie_sas: system_controller@a0000000 { + compatible = "hisilicon,dsa-subctrl", "syscon"; + reg = <0xa0000000 0x10000>; + }; + +----------------------------------------------------------------------- +Hisilicon CPU controller + +Required properties: +- compatible : "hisilicon,cpuctrl" +- reg : Register address and size + +The clock registers and power registers of secondary cores are defined +in CPU controller, especially in HIX5HD2 SoC. + +----------------------------------------------------------------------- +PCTRL: Peripheral misc control register + +Required Properties: +- compatible: "hisilicon,pctrl" +- reg: Address and size of pctrl. + +Example: + + /* for Hi3620 */ + pctrl: pctrl@fca09000 { + compatible = "hisilicon,pctrl"; + reg = <0xfca09000 0x1000>; + }; + +----------------------------------------------------------------------- +Fabric: + +Required Properties: +- compatible: "hisilicon,hip04-fabric"; +- reg: Address and size of Fabric + +----------------------------------------------------------------------- +Bootwrapper boot method (software protocol on SMP): + +Required Properties: +- compatible: "hisilicon,hip04-bootwrapper"; +- boot-method: Address and size of boot method. + [0]: bootwrapper physical address + [1]: bootwrapper size + [2]: relocation physical address + [3]: relocation size diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/i2se.txt b/arch/arm64/boot/dts/vendor/bindings/arm/i2se.txt new file mode 100644 index 0000000000000000000000000000000000000000..dbd54a3aa07da1f1cd9de71b2ece851803ed4709 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/i2se.txt @@ -0,0 +1,22 @@ +I2SE Device Tree Bindings +------------------------- + +Duckbill Board +Required root node properties: + - compatible = "i2se,duckbill", "fsl,imx28"; + +Duckbill 2 Board +Required root node properties: + - compatible = "i2se,duckbill-2", "fsl,imx28"; + +Duckbill 2 485 Board +Required root node properties: + - compatible = "i2se,duckbill-2-485", "i2se,duckbill-2", "fsl,imx28"; + +Duckbill 2 EnOcean Board +Required root node properties: + - compatible = "i2se,duckbill-2-enocean", "i2se,duckbill-2", "fsl,imx28"; + +Duckbill 2 SPI Board +Required root node properties: + - compatible = "i2se,duckbill-2-spi", "i2se,duckbill-2", "fsl,imx28"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/idle-states.txt b/arch/arm64/boot/dts/vendor/bindings/arm/idle-states.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c73847499abc8d73cfdd64c987d6896f804b5c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/idle-states.txt @@ -0,0 +1,699 @@ +========================================== +ARM idle states binding description +========================================== + +========================================== +1 - Introduction +========================================== + +ARM systems contain HW capable of managing power consumption dynamically, +where cores can be put in different low-power states (ranging from simple +wfi to power gating) according to OS PM policies. The CPU states representing +the range of dynamic idle states that a processor can enter at run-time, can be +specified through device tree bindings representing the parameters required +to enter/exit specific idle states on a given processor. + +According to the Server Base System Architecture document (SBSA, [3]), the +power states an ARM CPU can be put into are identified by the following list: + +- Running +- Idle_standby +- Idle_retention +- Sleep +- Off + +The power states described in the SBSA document define the basic CPU states on +top of which ARM platforms implement power management schemes that allow an OS +PM implementation to put the processor in different idle states (which include +states listed above; "off" state is not an idle state since it does not have +wake-up capabilities, hence it is not considered in this document). + +Idle state parameters (eg entry latency) are platform specific and need to be +characterized with bindings that provide the required information to OS PM +code so that it can build the required tables and use them at runtime. + +The device tree binding definition for ARM idle states is the subject of this +document. + +=========================================== +2 - idle-states definitions +=========================================== + +Idle states are characterized for a specific system through a set of +timing and energy related properties, that underline the HW behaviour +triggered upon idle states entry and exit. + +The following diagram depicts the CPU execution phases and related timing +properties required to enter and exit an idle state: + +..__[EXEC]__|__[PREP]__|__[ENTRY]__|__[IDLE]__|__[EXIT]__|__[EXEC]__.. + | | | | | + + |<------ entry ------->| + | latency | + |<- exit ->| + | latency | + |<-------- min-residency -------->| + |<------- wakeup-latency ------->| + + Diagram 1: CPU idle state execution phases + +EXEC: Normal CPU execution. + +PREP: Preparation phase before committing the hardware to idle mode + like cache flushing. This is abortable on pending wake-up + event conditions. The abort latency is assumed to be negligible + (i.e. less than the ENTRY + EXIT duration). If aborted, CPU + goes back to EXEC. This phase is optional. If not abortable, + this should be included in the ENTRY phase instead. + +ENTRY: The hardware is committed to idle mode. This period must run + to completion up to IDLE before anything else can happen. + +IDLE: This is the actual energy-saving idle period. This may last + between 0 and infinite time, until a wake-up event occurs. + +EXIT: Period during which the CPU is brought back to operational + mode (EXEC). + +entry-latency: Worst case latency required to enter the idle state. The +exit-latency may be guaranteed only after entry-latency has passed. + +min-residency: Minimum period, including preparation and entry, for a given +idle state to be worthwhile energywise. + +wakeup-latency: Maximum delay between the signaling of a wake-up event and the +CPU being able to execute normal code again. If not specified, this is assumed +to be entry-latency + exit-latency. + +These timing parameters can be used by an OS in different circumstances. + +An idle CPU requires the expected min-residency time to select the most +appropriate idle state based on the expected expiry time of the next IRQ +(ie wake-up) that causes the CPU to return to the EXEC phase. + +An operating system scheduler may need to compute the shortest wake-up delay +for CPUs in the system by detecting how long will it take to get a CPU out +of an idle state, eg: + +wakeup-delay = exit-latency + max(entry-latency - (now - entry-timestamp), 0) + +In other words, the scheduler can make its scheduling decision by selecting +(eg waking-up) the CPU with the shortest wake-up latency. +The wake-up latency must take into account the entry latency if that period +has not expired. The abortable nature of the PREP period can be ignored +if it cannot be relied upon (e.g. the PREP deadline may occur much sooner than +the worst case since it depends on the CPU operating conditions, ie caches +state). + +An OS has to reliably probe the wakeup-latency since some devices can enforce +latency constraints guarantees to work properly, so the OS has to detect the +worst case wake-up latency it can incur if a CPU is allowed to enter an +idle state, and possibly to prevent that to guarantee reliable device +functioning. + +The min-residency time parameter deserves further explanation since it is +expressed in time units but must factor in energy consumption coefficients. + +The energy consumption of a cpu when it enters a power state can be roughly +characterised by the following graph: + + | + | + | + e | + n | /--- + e | /------ + r | /------ + g | /----- + y | /------ + | ---- + | /| + | / | + | / | + | / | + | / | + | / | + |/ | + -----|-------+---------------------------------- + 0| 1 time(ms) + + Graph 1: Energy vs time example + +The graph is split in two parts delimited by time 1ms on the X-axis. +The graph curve with X-axis values = { x | 0 < x < 1ms } has a steep slope +and denotes the energy costs incurred whilst entering and leaving the idle +state. +The graph curve in the area delimited by X-axis values = {x | x > 1ms } has +shallower slope and essentially represents the energy consumption of the idle +state. + +min-residency is defined for a given idle state as the minimum expected +residency time for a state (inclusive of preparation and entry) after +which choosing that state become the most energy efficient option. A good +way to visualise this, is by taking the same graph above and comparing some +states energy consumptions plots. + +For sake of simplicity, let's consider a system with two idle states IDLE1, +and IDLE2: + + | + | + | + | /-- IDLE1 + e | /--- + n | /---- + e | /--- + r | /-----/--------- IDLE2 + g | /-------/--------- + y | ------------ /---| + | / /---- | + | / /--- | + | / /---- | + | / /--- | + | --- | + | / | + | / | + |/ | time + ---/----------------------------+------------------------ + |IDLE1-energy < IDLE2-energy | IDLE2-energy < IDLE1-energy + | + IDLE2-min-residency + + Graph 2: idle states min-residency example + +In graph 2 above, that takes into account idle states entry/exit energy +costs, it is clear that if the idle state residency time (ie time till next +wake-up IRQ) is less than IDLE2-min-residency, IDLE1 is the better idle state +choice energywise. + +This is mainly down to the fact that IDLE1 entry/exit energy costs are lower +than IDLE2. + +However, the lower power consumption (ie shallower energy curve slope) of idle +state IDLE2 implies that after a suitable time, IDLE2 becomes more energy +efficient. + +The time at which IDLE2 becomes more energy efficient than IDLE1 (and other +shallower states in a system with multiple idle states) is defined +IDLE2-min-residency and corresponds to the time when energy consumption of +IDLE1 and IDLE2 states breaks even. + +The definitions provided in this section underpin the idle states +properties specification that is the subject of the following sections. + +=========================================== +3 - idle-states node +=========================================== + +ARM processor idle states are defined within the idle-states node, which is +a direct child of the cpus node [1] and provides a container where the +processor idle states, defined as device tree nodes, are listed. + +- idle-states node + + Usage: Optional - On ARM systems, it is a container of processor idle + states nodes. If the system does not provide CPU + power management capabilities or the processor just + supports idle_standby an idle-states node is not + required. + + Description: idle-states node is a container node, where its + subnodes describe the CPU idle states. + + Node name must be "idle-states". + + The idle-states node's parent node must be the cpus node. + + The idle-states node's child nodes can be: + + - one or more state nodes + + Any other configuration is considered invalid. + + An idle-states node defines the following properties: + + - entry-method + Value type: + Usage and definition depend on ARM architecture version. + # On ARM v8 64-bit this property is required and must + be: + - "psci" + # On ARM 32-bit systems this property is optional + +The nodes describing the idle states (state) can only be defined within the +idle-states node, any other configuration is considered invalid and therefore +must be ignored. + +=========================================== +4 - state node +=========================================== + +A state node represents an idle state description and must be defined as +follows: + +- state node + + Description: must be child of the idle-states node + + The state node name shall follow standard device tree naming + rules ([5], 2.2.1 "Node names"), in particular state nodes which + are siblings within a single common parent must be given a unique name. + + The idle state entered by executing the wfi instruction (idle_standby + SBSA,[3][4]) is considered standard on all ARM platforms and therefore + must not be listed. + + With the definitions provided above, the following list represents + the valid properties for a state node: + + - compatible + Usage: Required + Value type: + Definition: Must be "arm,idle-state". + + - local-timer-stop + Usage: See definition + Value type: + Definition: if present the CPU local timer control logic is + lost on state entry, otherwise it is retained. + + - entry-latency-us + Usage: Required + Value type: + Definition: u32 value representing worst case latency in + microseconds required to enter the idle state. + The exit-latency-us duration may be guaranteed + only after entry-latency-us has passed. + + - exit-latency-us + Usage: Required + Value type: + Definition: u32 value representing worst case latency + in microseconds required to exit the idle state. + + - min-residency-us + Usage: Required + Value type: + Definition: u32 value representing minimum residency duration + in microseconds, inclusive of preparation and + entry, for this idle state to be considered + worthwhile energy wise (refer to section 2 of + this document for a complete description). + + - wakeup-latency-us: + Usage: Optional + Value type: + Definition: u32 value representing maximum delay between the + signaling of a wake-up event and the CPU being + able to execute normal code again. If omitted, + this is assumed to be equal to: + + entry-latency-us + exit-latency-us + + It is important to supply this value on systems + where the duration of PREP phase (see diagram 1, + section 2) is non-neglibigle. + In such systems entry-latency-us + exit-latency-us + will exceed wakeup-latency-us by this duration. + + - status: + Usage: Optional + Value type: + Definition: A standard device tree property [5] that indicates + the operational status of an idle-state. + If present, it shall be: + "okay": to indicate that the idle state is + operational. + "disabled": to indicate that the idle state has + been disabled in firmware so it is not + operational. + If the property is not present the idle-state must + be considered operational. + + - idle-state-name: + Usage: Optional + Value type: + Definition: A string used as a descriptive name for the idle + state. + + In addition to the properties listed above, a state node may require + additional properties specifics to the entry-method defined in the + idle-states node, please refer to the entry-method bindings + documentation for properties definitions. + +=========================================== +4 - Examples +=========================================== + +Example 1 (ARM 64-bit, 16-cpu system, PSCI enable-method): + +cpus { + #size-cells = <0>; + #address-cells = <2>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x0>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x1>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU4: cpu@10000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10000>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU5: cpu@10001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10001>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU6: cpu@10100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU7: cpu@10101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 + &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; + }; + + CPU8: cpu@100000000 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x0>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU9: cpu@100000001 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x1>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU10: cpu@100000100 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU11: cpu@100000101 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU12: cpu@100010000 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x10000>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU13: cpu@100010001 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x10001>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU14: cpu@100010100 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x10100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + CPU15: cpu@100010101 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x1 0x10101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 + &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; + }; + + idle-states { + entry-method = "psci"; + + CPU_RETENTION_0_0: cpu-retention-0-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <20>; + exit-latency-us = <40>; + min-residency-us = <80>; + }; + + CLUSTER_RETENTION_0: cluster-retention-0 { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x1010000>; + entry-latency-us = <50>; + exit-latency-us = <100>; + min-residency-us = <250>; + wakeup-latency-us = <130>; + }; + + CPU_SLEEP_0_0: cpu-sleep-0-0 { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <250>; + exit-latency-us = <500>; + min-residency-us = <950>; + }; + + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x1010000>; + entry-latency-us = <600>; + exit-latency-us = <1100>; + min-residency-us = <2700>; + wakeup-latency-us = <1500>; + }; + + CPU_RETENTION_1_0: cpu-retention-1-0 { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <20>; + exit-latency-us = <40>; + min-residency-us = <90>; + }; + + CLUSTER_RETENTION_1: cluster-retention-1 { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x1010000>; + entry-latency-us = <50>; + exit-latency-us = <100>; + min-residency-us = <270>; + wakeup-latency-us = <100>; + }; + + CPU_SLEEP_1_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <70>; + exit-latency-us = <100>; + min-residency-us = <300>; + wakeup-latency-us = <150>; + }; + + CLUSTER_SLEEP_1: cluster-sleep-1 { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x1010000>; + entry-latency-us = <500>; + exit-latency-us = <1200>; + min-residency-us = <3500>; + wakeup-latency-us = <1300>; + }; + }; + +}; + +Example 2 (ARM 32-bit, 8-cpu system, two clusters): + +cpus { + #size-cells = <0>; + #address-cells = <1>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x1>; + cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x2>; + cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x3>; + cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x100>; + cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x101>; + cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x102>; + cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x103>; + cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; + }; + + idle-states { + CPU_SLEEP_0_0: cpu-sleep-0-0 { + compatible = "arm,idle-state"; + local-timer-stop; + entry-latency-us = <200>; + exit-latency-us = <100>; + min-residency-us = <400>; + wakeup-latency-us = <250>; + }; + + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "arm,idle-state"; + local-timer-stop; + entry-latency-us = <500>; + exit-latency-us = <1500>; + min-residency-us = <2500>; + wakeup-latency-us = <1700>; + }; + + CPU_SLEEP_1_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + local-timer-stop; + entry-latency-us = <300>; + exit-latency-us = <500>; + min-residency-us = <900>; + wakeup-latency-us = <600>; + }; + + CLUSTER_SLEEP_1: cluster-sleep-1 { + compatible = "arm,idle-state"; + local-timer-stop; + entry-latency-us = <800>; + exit-latency-us = <2000>; + min-residency-us = <6500>; + wakeup-latency-us = <2300>; + }; + }; + +}; + +=========================================== +5 - References +=========================================== + +[1] ARM Linux Kernel documentation - CPUs bindings + Documentation/devicetree/bindings/arm/cpus.txt + +[2] ARM Linux Kernel documentation - PSCI bindings + Documentation/devicetree/bindings/arm/psci.txt + +[3] ARM Server Base System Architecture (SBSA) + http://infocenter.arm.com/help/index.jsp + +[4] ARM Architecture Reference Manuals + http://infocenter.arm.com/help/index.jsp + +[5] Devicetree Specification + https://www.devicetree.org/specifications/ diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/juno,scpi.txt b/arch/arm64/boot/dts/vendor/bindings/arm/juno,scpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ace8696bbee99187198bd797a473f3cb79a6a02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/juno,scpi.txt @@ -0,0 +1,26 @@ +System Control and Power Interface (SCPI) Message Protocol +(in addition to the standard binding in [0]) + +Juno SRAM and Shared Memory for SCPI +------------------------------------ + +Required properties: +- compatible : should be "arm,juno-sram-ns" for Non-secure SRAM + +Each sub-node represents the reserved area for SCPI. + +Required sub-node properties: +- reg : The base offset and size of the reserved area with the SRAM +- compatible : should be "arm,juno-scp-shmem" for Non-secure SRAM based + shared memory on Juno platforms + +Sensor bindings for the sensors based on SCPI Message Protocol +-------------------------------------------------------------- +Required properties: +- compatible : should be "arm,scpi-sensors". +- #thermal-sensor-cells: should be set to 1. + For Juno R0 and Juno R1 refer to [1] for the + sensor identifiers + +[0] Documentation/devicetree/bindings/arm/arm,scpi.txt +[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/keystone/keystone.txt b/arch/arm64/boot/dts/vendor/bindings/arm/keystone/keystone.txt new file mode 100644 index 0000000000000000000000000000000000000000..f310bad0448307e3d11038492ebbf1f3b0e70bc5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/keystone/keystone.txt @@ -0,0 +1,42 @@ +TI Keystone Platforms Device Tree Bindings +----------------------------------------------- + +Boards with Keystone2 based devices (TCI66xxK2H) SOC shall have the +following properties. + +Required properties: + - compatible: All TI specific devices present in Keystone SOC should be in + the form "ti,keystone-*". Generic devices like gic, arch_timers, ns16550 + type UART should use the specified compatible for those devices. + +SoC families: + +- Keystone 2 generic SoC: + compatible = "ti,keystone" + +SoCs: + +- Keystone 2 Hawking/Kepler + compatible = "ti,k2hk", "ti,keystone" +- Keystone 2 Lamarr + compatible = "ti,k2l", "ti,keystone" +- Keystone 2 Edison + compatible = "ti,k2e", "ti,keystone" +- K2G + compatible = "ti,k2g", "ti,keystone" + +Boards: +- Keystone 2 Hawking/Kepler EVM + compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone" + +- Keystone 2 Lamarr EVM + compatible = "ti,k2l-evm", "ti, k2l", "ti,keystone" + +- Keystone 2 Edison EVM + compatible = "ti,k2e-evm", "ti,k2e", "ti,keystone" + +- K2G EVM + compatible = "ti,k2g-evm", "ti,k2g", "ti-keystone" + +- K2G Industrial Communication Engine EVM + compatible = "ti,k2g-ice", "ti,k2g", "ti-keystone" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/keystone/ti,sci.txt b/arch/arm64/boot/dts/vendor/bindings/arm/keystone/ti,sci.txt new file mode 100644 index 0000000000000000000000000000000000000000..31f5f9a104cca5f24cd4cd3c240b791530257524 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/keystone/ti,sci.txt @@ -0,0 +1,81 @@ +Texas Instruments System Control Interface (TI-SCI) Message Protocol +-------------------------------------------------------------------- + +Texas Instrument's processors including those belonging to Keystone generation +of processors have separate hardware entity which is now responsible for the +management of the System on Chip (SoC) system. These include various system +level functions as well. + +An example of such an SoC is K2G, which contains the system control hardware +block called Power Management Micro Controller (PMMC). This hardware block is +initialized early into boot process and provides services to Operating Systems +on multiple processors including ones running Linux. + +See http://processors.wiki.ti.com/index.php/TISCI for protocol definition. + +TI-SCI controller Device Node: +============================= + +The TI-SCI node describes the Texas Instrument's System Controller entity node. +This parent node may optionally have additional children nodes which describe +specific functionality such as clocks, power domain, reset or additional +functionality as may be required for the SoC. This hierarchy also describes the +relationship between the TI-SCI parent node to the child node. + +Required properties: +------------------- +- compatible: should be "ti,k2g-sci" +- mbox-names: + "rx" - Mailbox corresponding to receive path + "tx" - Mailbox corresponding to transmit path + +- mboxes: Mailboxes corresponding to the mbox-names. Each value of the mboxes + property should contain a phandle to the mailbox controller device + node and an args specifier that will be the phandle to the intended + sub-mailbox child node to be used for communication. + +See Documentation/devicetree/bindings/mailbox/mailbox.txt for more details +about the generic mailbox controller and client driver bindings. Also see +Documentation/devicetree/bindings/mailbox/ti,message-manager.txt for typical +controller that is used to communicate with this System controllers. + +Optional Properties: +------------------- +- reg-names: + debug_messages - Map the Debug message region +- reg: register space corresponding to the debug_messages +- ti,system-reboot-controller: If system reboot can be triggered by SoC reboot + +Example (K2G): +------------- + pmmc: pmmc { + compatible = "ti,k2g-sci"; + mbox-names = "rx", "tx"; + mboxes= <&msgmgr &msgmgr_proxy_pmmc_rx>, + <&msgmgr &msgmgr_proxy_pmmc_tx>; + reg-names = "debug_messages"; + reg = <0x02921800 0x800>; + }; + + +TI-SCI Client Device Node: +========================= + +Client nodes are maintained as children of the relevant TI-SCI device node. + +Example (K2G): +------------- + pmmc: pmmc { + compatible = "ti,k2g-sci"; + ... + + my_clk_node: clk_node { + ... + ... + }; + + my_pd_node: pd_node { + ... + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/l2c2x0.txt b/arch/arm64/boot/dts/vendor/bindings/arm/l2c2x0.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbe6cb21f4cff85a9a0e4b3727bc6c496fe14716 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/l2c2x0.txt @@ -0,0 +1,114 @@ +* ARM L2 Cache Controller + +ARM cores often have a separate L2C210/L2C220/L2C310 (also known as PL210/PL220/ +PL310 and variants) based level 2 cache controller. All these various implementations +of the L2 cache controller have compatible programming models (Note 1). +Some of the properties that are just prefixed "cache-*" are taken from section +3.7.3 of the Devicetree Specification which can be found at: +https://www.devicetree.org/specifications/ + +The ARM L2 cache representation in the device tree should be done as follows: + +Required properties: + +- compatible : should be one of: + "arm,pl310-cache" + "arm,l220-cache" + "arm,l210-cache" + "bcm,bcm11351-a2-pl310-cache": DEPRECATED by "brcm,bcm11351-a2-pl310-cache" + "brcm,bcm11351-a2-pl310-cache": For Broadcom bcm11351 chipset where an + offset needs to be added to the address before passing down to the L2 + cache controller + "marvell,aurora-system-cache": Marvell Controller designed to be + compatible with the ARM one, with system cache mode (meaning + maintenance operations on L1 are broadcasted to the L2 and L2 + performs the same operation). + "marvell,aurora-outer-cache": Marvell Controller designed to be + compatible with the ARM one with outer cache mode. + "marvell,tauros3-cache": Marvell Tauros3 cache controller, compatible + with arm,pl310-cache controller. +- cache-unified : Specifies the cache is a unified cache. +- cache-level : Should be set to 2 for a level 2 cache. +- reg : Physical base address and size of cache controller's memory mapped + registers. + +Optional properties: + +- arm,data-latency : Cycles of latency for Data RAM accesses. Specifies 3 cells of + read, write and setup latencies. Minimum valid values are 1. Controllers + without setup latency control should use a value of 0. +- arm,tag-latency : Cycles of latency for Tag RAM accesses. Specifies 3 cells of + read, write and setup latencies. Controllers without setup latency control + should use 0. Controllers without separate read and write Tag RAM latency + values should only use the first cell. +- arm,dirty-latency : Cycles of latency for Dirty RAMs. This is a single cell. +- arm,filter-ranges : Starting address and length of window to + filter. Addresses in the filter window are directed to the M1 port. Other + addresses will go to the M0 port. +- arm,io-coherent : indicates that the system is operating in an hardware + I/O coherent mode. Valid only when the arm,pl310-cache compatible + string is used. +- interrupts : 1 combined interrupt. +- cache-size : specifies the size in bytes of the cache +- cache-sets : specifies the number of associativity sets of the cache +- cache-block-size : specifies the size in bytes of a cache block +- cache-line-size : specifies the size in bytes of a line in the cache, + if this is not specified, the line size is assumed to be equal to the + cache block size +- cache-id-part: cache id part number to be used if it is not present + on hardware +- wt-override: If present then L2 is forced to Write through mode +- arm,double-linefill : Override double linefill enable setting. Enable if + non-zero, disable if zero. +- arm,double-linefill-incr : Override double linefill on INCR read. Enable + if non-zero, disable if zero. +- arm,double-linefill-wrap : Override double linefill on WRAP read. Enable + if non-zero, disable if zero. +- arm,prefetch-drop : Override prefetch drop enable setting. Enable if non-zero, + disable if zero. +- arm,prefetch-offset : Override prefetch offset value. Valid values are + 0-7, 15, 23, and 31. +- arm,shared-override : The default behavior of the L220 or PL310 cache + controllers with respect to the shareable attribute is to transform "normal + memory non-cacheable transactions" into "cacheable no allocate" (for reads) + or "write through no write allocate" (for writes). + On systems where this may cause DMA buffer corruption, this property must be + specified to indicate that such transforms are precluded. +- arm,parity-enable : enable parity checking on the L2 cache (L220 or PL310). +- arm,parity-disable : disable parity checking on the L2 cache (L220 or PL310). +- arm,outer-sync-disable : disable the outer sync operation on the L2 cache. + Some core tiles, especially ARM PB11MPCore have a faulty L220 cache that + will randomly hang unless outer sync operations are disabled. +- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1> + (forcibly enable), property absent (retain settings set by firmware) +- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable), + <1> (forcibly enable), property absent (retain settings set by + firmware) +- arm,dynamic-clock-gating : L2 dynamic clock gating. Value: <0> (forcibly + disable), <1> (forcibly enable), property absent (OS specific behavior, + preferably retain firmware settings) +- arm,standby-mode: L2 standby mode enable. Value <0> (forcibly disable), + <1> (forcibly enable), property absent (OS specific behavior, + preferably retain firmware settings) +- arm,early-bresp-disable : Disable the CA9 optimization Early BRESP (PL310) +- arm,full-line-zero-disable : Disable the CA9 optimization Full line of zero + write (PL310) + +Example: + +L2: cache-controller { + compatible = "arm,pl310-cache"; + reg = <0xfff12000 0x1000>; + arm,data-latency = <1 1 1>; + arm,tag-latency = <2 2 2>; + arm,filter-ranges = <0x80000000 0x8000000>; + cache-unified; + cache-level = <2>; + interrupts = <45>; +}; + +Note 1: The description in this document doesn't apply to integrated L2 + cache controllers as found in e.g. Cortex-A15/A7/A57/A53. These + integrated L2 controllers are assumed to be all preconfigured by + early secure boot code. Thus no need to deal with their configuration + in the kernel at all. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/98dx3236-resume-ctrl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/98dx3236-resume-ctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..26eb9d3aa6308ef96e440d6895085e8fb8375509 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/98dx3236-resume-ctrl.txt @@ -0,0 +1,16 @@ +Resume Control +-------------- +Available on Marvell SOCs: 98DX3336 and 98DX4251 + +Required properties: + +- compatible: must be "marvell,98dx3336-resume-ctrl" + +- reg: Should contain resume control registers location and length + +Example: + +resume@20980 { + compatible = "marvell,98dx3336-resume-ctrl"; + reg = <0x20980 0x10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/98dx3236.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/98dx3236.txt new file mode 100644 index 0000000000000000000000000000000000000000..64e8c73fc5ab8b1074323287181948a3f2293187 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/98dx3236.txt @@ -0,0 +1,23 @@ +Marvell 98DX3236, 98DX3336 and 98DX4251 Platforms Device Tree Bindings +---------------------------------------------------------------------- + +Boards with a SoC of the Marvell 98DX3236, 98DX3336 and 98DX4251 families +shall have the following property: + +Required root node property: + +compatible: must contain "marvell,armadaxp-98dx3236" + +In addition, boards using the Marvell 98DX3336 SoC shall have the +following property: + +Required root node property: + +compatible: must contain "marvell,armadaxp-98dx3336" + +In addition, boards using the Marvell 98DX4251 SoC shall have the +following property: + +Required root node property: + +compatible: must contain "marvell,armadaxp-98dx4251" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/ap806-system-controller.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/ap806-system-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fd21bb7cb376b7527a547839069646ab24c1b46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/ap806-system-controller.txt @@ -0,0 +1,138 @@ +Marvell Armada AP806 System Controller +====================================== + +The AP806 is one of the two core HW blocks of the Marvell Armada 7K/8K +SoCs. It contains system controllers, which provide several registers +giving access to numerous features: clocks, pin-muxing and many other +SoC configuration items. This DT binding allows to describe these +system controllers. + +For the top level node: + - compatible: must be: "syscon", "simple-mfd"; + - reg: register area of the AP806 system controller + +SYSTEM CONTROLLER 0 +=================== + +Clocks: +------- + + +The Device Tree node representing the AP806 system controller provides +a number of clocks: + + - 0: clock of CPU cluster 0 + - 1: clock of CPU cluster 1 + - 2: fixed PLL at 1200 Mhz + - 3: MSS clock, derived from the fixed PLL + +Required properties: + + - compatible: must be: "marvell,ap806-clock" + - #clock-cells: must be set to 1 + +Pinctrl: +-------- + +For common binding part and usage, refer to +Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt. + +Required properties: +- compatible must be "marvell,ap806-pinctrl", + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, sdio(clk), spi0(clk) +mpp1 1 gpio, sdio(cmd), spi0(miso) +mpp2 2 gpio, sdio(d0), spi0(mosi) +mpp3 3 gpio, sdio(d1), spi0(cs0n) +mpp4 4 gpio, sdio(d2), i2c0(sda) +mpp5 5 gpio, sdio(d3), i2c0(sdk) +mpp6 6 gpio, sdio(ds) +mpp7 7 gpio, sdio(d4), uart1(rxd) +mpp8 8 gpio, sdio(d5), uart1(txd) +mpp9 9 gpio, sdio(d6), spi0(cs1n) +mpp10 10 gpio, sdio(d7) +mpp11 11 gpio, uart0(txd) +mpp12 12 gpio, sdio(pw_off), sdio(hw_rst) +mpp13 13 gpio +mpp14 14 gpio +mpp15 15 gpio +mpp16 16 gpio +mpp17 17 gpio +mpp18 18 gpio +mpp19 19 gpio, uart0(rxd), sdio(pw_off) + +GPIO: +----- +For common binding part and usage, refer to +Documentation/devicetree/bindings/gpio/gpio-mvebu.txt. + +Required properties: + +- compatible: "marvell,armada-8k-gpio" + +- offset: offset address inside the syscon block + +Example: +ap_syscon: system-controller@6f4000 { + compatible = "syscon", "simple-mfd"; + reg = <0x6f4000 0x1000>; + + ap_clk: clock { + compatible = "marvell,ap806-clock"; + #clock-cells = <1>; + }; + + ap_pinctrl: pinctrl { + compatible = "marvell,ap806-pinctrl"; + }; + + ap_gpio: gpio { + compatible = "marvell,armada-8k-gpio"; + offset = <0x1040>; + ngpios = <19>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&ap_pinctrl 0 0 19>; + }; +}; + +SYSTEM CONTROLLER 1 +=================== + +Thermal: +-------- + +For common binding part and usage, refer to +Documentation/devicetree/bindings/thermal/thermal.txt + +The thermal IP can probe the temperature all around the processor. It +may feature several channels, each of them wired to one sensor. + +Required properties: +- compatible: must be one of: + * marvell,armada-ap806-thermal +- reg: register range associated with the thermal functions. + +Optional properties: +- #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer + to this IP and represents the channel ID. There is one sensor per + channel. O refers to the thermal IP internal channel, while positive + IDs refer to each CPU. + +Example: +ap_syscon1: system-controller@6f8000 { + compatible = "syscon", "simple-mfd"; + reg = <0x6f8000 0x1000>; + + ap_thermal: thermal-sensor@80 { + compatible = "marvell,armada-ap806-thermal"; + reg = <0x80 0x10>; + #thermal-sensor-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-370-xp-pmsu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-370-xp-pmsu.txt new file mode 100644 index 0000000000000000000000000000000000000000..26799ef562df1a00451df7426b3df70ef9e84363 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-370-xp-pmsu.txt @@ -0,0 +1,21 @@ +Power Management Service Unit(PMSU) +----------------------------------- +Available on Marvell SOCs: Armada 370, Armada 38x and Armada XP + +Required properties: + +- compatible: should be one of: + - "marvell,armada-370-pmsu" for Armada 370 or Armada XP + - "marvell,armada-380-pmsu" for Armada 38x + - "marvell,armada-370-xp-pmsu" was used for Armada 370/XP but is now + deprecated and will be removed + +- reg: Should contain PMSU registers location and length. + +Example: + +armada-370-xp-pmsu@22000 { + compatible = "marvell,armada-370-pmsu"; + reg = <0x22000 0x1000>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-370-xp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-370-xp.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6ed90ea6e17c8fb4618de8e6d3b201c3bf98479 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-370-xp.txt @@ -0,0 +1,24 @@ +Marvell Armada 370 and Armada XP Platforms Device Tree Bindings +--------------------------------------------------------------- + +Boards with a SoC of the Marvell Armada 370 and Armada XP families +shall have the following property: + +Required root node property: + +compatible: must contain "marvell,armada-370-xp" + +In addition, boards using the Marvell Armada 370 SoC shall have the +following property: + +Required root node property: + +compatible: must contain "marvell,armada370" + +In addition, boards using the Marvell Armada XP SoC shall have the +following property: + +Required root node property: + +compatible: must contain "marvell,armadaxp" + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-375.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-375.txt new file mode 100644 index 0000000000000000000000000000000000000000..867d0b80cb8f6c4107308cdbfcd1811c1a955cb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-375.txt @@ -0,0 +1,9 @@ +Marvell Armada 375 Platforms Device Tree Bindings +------------------------------------------------- + +Boards with a SoC of the Marvell Armada 375 family shall have the +following property: + +Required root node property: + +compatible: must contain "marvell,armada375" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-37xx.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-37xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..eddde4faef01584ad96c4298b667aa7c276c00d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-37xx.txt @@ -0,0 +1,50 @@ +Marvell Armada 37xx Platforms Device Tree Bindings +-------------------------------------------------- + +Boards using a SoC of the Marvell Armada 37xx family must carry the +following root node property: + + - compatible: must contain "marvell,armada3710" + +In addition, boards using the Marvell Armada 3720 SoC shall have the +following property before the previous one: + + - compatible: must contain "marvell,armada3720" + +Example: + +compatible = "marvell,armada-3720-db", "marvell,armada3720", "marvell,armada3710"; + + +Power management +---------------- + +For power management (particularly DVFS and AVS), the North Bridge +Power Management component is needed: + +Required properties: +- compatible : should contain "marvell,armada-3700-nb-pm", "syscon"; +- reg : the register start and length for the North Bridge + Power Management + +Example: + +nb_pm: syscon@14000 { + compatible = "marvell,armada-3700-nb-pm", "syscon"; + reg = <0x14000 0x60>; +} + +AVS +--- + +For AVS an other component is needed: + +Required properties: +- compatible : should contain "marvell,armada-3700-avs", "syscon"; +- reg : the register start and length for the AVS + +Example: +avs: avs@11500 { + compatible = "marvell,armada-3700-avs", "syscon"; + reg = <0x11500 0x40>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-380-mpcore-soc-ctrl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-380-mpcore-soc-ctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..8781073029e9f376a16e7911eaa86bf3efebd7ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-380-mpcore-soc-ctrl.txt @@ -0,0 +1,14 @@ +Marvell Armada 38x CA9 MPcore SoC Controller +============================================ + +Required properties: + +- compatible: Should be "marvell,armada-380-mpcore-soc-ctrl". + +- reg: should be the register base and length as documented in the + datasheet for the CA9 MPcore SoC Control registers + +mpcore-soc-ctrl@20d20 { + compatible = "marvell,armada-380-mpcore-soc-ctrl"; + reg = <0x20d20 0x6c>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-38x.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-38x.txt new file mode 100644 index 0000000000000000000000000000000000000000..202953f1887e6014f2dbc84e145cfb00038ad5c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-38x.txt @@ -0,0 +1,27 @@ +Marvell Armada 38x Platforms Device Tree Bindings +------------------------------------------------- + +Boards with a SoC of the Marvell Armada 38x family shall have the +following property: + +Required root node property: + + - compatible: must contain "marvell,armada380" + +In addition, boards using the Marvell Armada 385 SoC shall have the +following property before the previous one: + +Required root node property: + +compatible: must contain "marvell,armada385" + +In addition, boards using the Marvell Armada 388 SoC shall have the +following property before the previous one: + +Required root node property: + +compatible: must contain "marvell,armada388" + +Example: + +compatible = "marvell,a385-rd", "marvell,armada385", "marvell,armada380"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-39x.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-39x.txt new file mode 100644 index 0000000000000000000000000000000000000000..89468664f6ea4f73e7e30f966955e64dff4a6068 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-39x.txt @@ -0,0 +1,31 @@ +Marvell Armada 39x Platforms Device Tree Bindings +------------------------------------------------- + +Boards with a SoC of the Marvell Armada 39x family shall have the +following property: + +Required root node property: + + - compatible: must contain "marvell,armada390" + +In addition, boards using the Marvell Armada 395 SoC shall have the +following property before the common "marvell,armada390" one: + +Required root node property: + +compatible: must contain "marvell,armada395" + +Example: + +compatible = "marvell,a395-gp", "marvell,armada395", "marvell,armada390"; + +Boards using the Marvell Armada 398 SoC shall have the following +property before the common "marvell,armada390" one: + +Required root node property: + +compatible: must contain "marvell,armada398" + +Example: + +compatible = "marvell,a398-db", "marvell,armada398", "marvell,armada390"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-7k-8k.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-7k-8k.txt new file mode 100644 index 0000000000000000000000000000000000000000..df98a9c82a8c7ce4352457ba96c63c0a5cc19fb9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-7k-8k.txt @@ -0,0 +1,24 @@ +Marvell Armada 7K/8K Platforms Device Tree Bindings +--------------------------------------------------- + +Boards using a SoC of the Marvell Armada 7K or 8K families must carry +the following root node property: + + - compatible, with one of the following values: + + - "marvell,armada7020", "marvell,armada-ap806-dual", "marvell,armada-ap806" + when the SoC being used is the Armada 7020 + + - "marvell,armada7040", "marvell,armada-ap806-quad", "marvell,armada-ap806" + when the SoC being used is the Armada 7040 + + - "marvell,armada8020", "marvell,armada-ap806-dual", "marvell,armada-ap806" + when the SoC being used is the Armada 8020 + + - "marvell,armada8040", "marvell,armada-ap806-quad", "marvell,armada-ap806" + when the SoC being used is the Armada 8040 + +Example: + +compatible = "marvell,armada7040-db", "marvell,armada7040", + "marvell,armada-ap806-quad", "marvell,armada-ap806"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-8kp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-8kp.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3e9624534c6baf30cca4dc41fff5d65a1be129b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-8kp.txt @@ -0,0 +1,15 @@ +Marvell Armada 8KPlus Platforms Device Tree Bindings +---------------------------------------------------- + +Boards using a SoC of the Marvell Armada 8KP families must carry +the following root node property: + + - compatible, with one of the following values: + + - "marvell,armada-8080", "marvell,armada-ap810-octa", "marvell,armada-ap810" + when the SoC being used is the Armada 8080 + +Example: + +compatible = "marvell,armada-8080-db", "marvell,armada-8080", + "marvell,armada-ap810-octa", "marvell,armada-ap810" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-cpu-reset.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-cpu-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..b63a7b6ab998e58692b388f2d948aba33b2d4c19 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/armada-cpu-reset.txt @@ -0,0 +1,14 @@ +Marvell Armada CPU reset controller +=================================== + +Required properties: + +- compatible: Should be "marvell,armada-370-cpu-reset". + +- reg: should be register base and length as documented in the + datasheet for the CPU reset registers + +cpurst: cpurst@20800 { + compatible = "marvell,armada-370-cpu-reset"; + reg = <0x20800 0x20>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/coherency-fabric.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/coherency-fabric.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b5c3f620e65ea348ac57eed59a63c1c61d2e3a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/coherency-fabric.txt @@ -0,0 +1,48 @@ +Coherency fabric +---------------- +Available on Marvell SOCs: Armada 370, Armada 375, Armada 38x and Armada XP + +Required properties: + +- compatible: the possible values are: + + * "marvell,coherency-fabric", to be used for the coherency fabric of + the Armada 370 and Armada XP. + + * "marvell,armada-375-coherency-fabric", for the Armada 375 coherency + fabric. + + * "marvell,armada-380-coherency-fabric", for the Armada 38x coherency + fabric. + +- reg: Should contain coherency fabric registers location and + length. + + * For "marvell,coherency-fabric", the first pair for the coherency + fabric registers, second pair for the per-CPU fabric registers. + + * For "marvell,armada-375-coherency-fabric", only one pair is needed + for the per-CPU fabric registers. + + * For "marvell,armada-380-coherency-fabric", only one pair is needed + for the per-CPU fabric registers. + +Optional properties: + +- broken-idle: boolean to set when the Idle mode is not supported by the + hardware. + +Examples: + +coherency-fabric@d0020200 { + compatible = "marvell,coherency-fabric"; + reg = <0xd0020200 0xb0>, + <0xd0021810 0x1c>; + +}; + +coherency-fabric@21810 { + compatible = "marvell,armada-375-coherency-fabric"; + reg = <0x21810 0x1c>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/cp110-system-controller.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/cp110-system-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..81ce742d2760c3ca3d76faeaea68da94850414e1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/cp110-system-controller.txt @@ -0,0 +1,225 @@ +Marvell Armada CP110 System Controller +====================================== + +The CP110 is one of the two core HW blocks of the Marvell Armada 7K/8K +SoCs. It contains system controllers, which provide several registers +giving access to numerous features: clocks, pin-muxing and many other +SoC configuration items. This DT binding allows to describe these +system controllers. + +For the top level node: + - compatible: must be: "syscon", "simple-mfd"; + - reg: register area of the CP110 system controller + +SYSTEM CONTROLLER 0 +=================== + +Clocks: +------- + +The Device Tree node representing this System Controller 0 provides a +number of clocks: + + - a set of core clocks + - a set of gatable clocks + +Those clocks can be referenced by other Device Tree nodes using two +cells: + - The first cell must be 0 or 1. 0 for the core clocks and 1 for the + gatable clocks. + - The second cell identifies the particular core clock or gatable + clocks. + +The following clocks are available: + - Core clocks + - 0 0 APLL + - 0 1 PPv2 core + - 0 2 EIP + - 0 3 Core + - 0 4 NAND core + - 0 5 SDIO core + - Gatable clocks + - 1 0 Audio + - 1 1 Comm Unit + - 1 2 NAND + - 1 3 PPv2 + - 1 4 SDIO + - 1 5 MG Domain + - 1 6 MG Core + - 1 7 XOR1 + - 1 8 XOR0 + - 1 9 GOP DP + - 1 11 PCIe x1 0 + - 1 12 PCIe x1 1 + - 1 13 PCIe x4 + - 1 14 PCIe / XOR + - 1 15 SATA + - 1 16 SATA USB + - 1 17 Main + - 1 18 SD/MMC/GOP + - 1 21 Slow IO (SPI, NOR, BootROM, I2C, UART) + - 1 22 USB3H0 + - 1 23 USB3H1 + - 1 24 USB3 Device + - 1 25 EIP150 + - 1 26 EIP197 + +Required properties: + + - compatible: must be: + "marvell,cp110-clock" + - #clock-cells: must be set to 2 + +Pinctrl: +-------- + +For common binding part and usage, refer to the file +Documentation/devicetree/bindings/pinctrl/marvell,mvebu-pinctrl.txt. + +Required properties: + +- compatible: "marvell,armada-7k-pinctrl", + "marvell,armada-8k-cpm-pinctrl" or "marvell,armada-8k-cps-pinctrl" + depending on the specific variant of the SoC being used. + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, dev(ale1), au(i2smclk), ge0(rxd3), tdm(pclk), ptp(pulse), mss_i2c(sda), uart0(rxd), sata0(present_act), ge(mdio) +mpp1 1 gpio, dev(ale0), au(i2sdo_spdifo), ge0(rxd2), tdm(drx), ptp(clk), mss_i2c(sck), uart0(txd), sata1(present_act), ge(mdc) +mpp2 2 gpio, dev(ad15), au(i2sextclk), ge0(rxd1), tdm(dtx), mss_uart(rxd), ptp(pclk_out), i2c1(sck), uart1(rxd), sata0(present_act), xg(mdc) +mpp3 3 gpio, dev(ad14), au(i2slrclk), ge0(rxd0), tdm(fsync), mss_uart(txd), pcie(rstoutn), i2c1(sda), uart1(txd), sata1(present_act), xg(mdio) +mpp4 4 gpio, dev(ad13), au(i2sbclk), ge0(rxctl), tdm(rstn), mss_uart(rxd), uart1(cts), pcie0(clkreq), uart3(rxd), ge(mdc) +mpp5 5 gpio, dev(ad12), au(i2sdi), ge0(rxclk), tdm(intn), mss_uart(txd), uart1(rts), pcie1(clkreq), uart3(txd), ge(mdio) +mpp6 6 gpio, dev(ad11), ge0(txd3), spi0(csn2), au(i2sextclk), sata1(present_act), pcie2(clkreq), uart0(rxd), ptp(pulse) +mpp7 7 gpio, dev(ad10), ge0(txd2), spi0(csn1), spi1(csn1), sata0(present_act), led(data), uart0(txd), ptp(clk) +mpp8 8 gpio, dev(ad9), ge0(txd1), spi0(csn0), spi1(csn0), uart0(cts), led(stb), uart2(rxd), ptp(pclk_out), synce1(clk) +mpp9 9 gpio, dev(ad8), ge0(txd0), spi0(mosi), spi1(mosi), pcie(rstoutn), synce2(clk) +mpp10 10 gpio, dev(readyn), ge0(txctl), spi0(miso), spi1(miso), uart0(cts), sata1(present_act) +mpp11 11 gpio, dev(wen1), ge0(txclkout), spi0(clk), spi1(clk), uart0(rts), led(clk), uart2(txd), sata0(present_act) +mpp12 12 gpio, dev(clk_out), nf(rbn1), spi1(csn1), ge0(rxclk) +mpp13 13 gpio, dev(burstn), nf(rbn0), spi1(miso), ge0(rxctl), mss_spi(miso) +mpp14 14 gpio, dev(bootcsn), dev(csn0), spi1(csn0), spi0(csn3), au(i2sextclk), spi0(miso), sata0(present_act), mss_spi(csn) +mpp15 15 gpio, dev(ad7), spi1(mosi), spi0(mosi), mss_spi(mosi), ptp(pulse_cp2cp) +mpp16 16 gpio, dev(ad6), spi1(clk), mss_spi(clk) +mpp17 17 gpio, dev(ad5), ge0(txd3) +mpp18 18 gpio, dev(ad4), ge0(txd2), ptp(clk_cp2cp) +mpp19 19 gpio, dev(ad3), ge0(txd1), wakeup(out_cp2cp) +mpp20 20 gpio, dev(ad2), ge0(txd0) +mpp21 21 gpio, dev(ad1), ge0(txctl), sei(in_cp2cp) +mpp22 22 gpio, dev(ad0), ge0(txclkout), wakeup(in_cp2cp) +mpp23 23 gpio, dev(a1), au(i2smclk), link(rd_in_cp2cp) +mpp24 24 gpio, dev(a0), au(i2slrclk) +mpp25 25 gpio, dev(oen), au(i2sdo_spdifo) +mpp26 26 gpio, dev(wen0), au(i2sbclk) +mpp27 27 gpio, dev(csn0), spi1(miso), mss_gpio4, ge0(rxd3), spi0(csn4), ge(mdio), sata0(present_act), uart0(rts), rei(in_cp2cp) +mpp28 28 gpio, dev(csn1), spi1(csn0), mss_gpio5, ge0(rxd2), spi0(csn5), pcie2(clkreq), ptp(pulse), ge(mdc), sata1(present_act), uart0(cts), led(data) +mpp29 29 gpio, dev(csn2), spi1(mosi), mss_gpio6, ge0(rxd1), spi0(csn6), pcie1(clkreq), ptp(clk), mss_i2c(sda), sata0(present_act), uart0(rxd), led(stb) +mpp30 30 gpio, dev(csn3), spi1(clk), mss_gpio7, ge0(rxd0), spi0(csn7), pcie0(clkreq), ptp(pclk_out), mss_i2c(sck), sata1(present_act), uart0(txd), led(clk) +mpp31 31 gpio, dev(a2), mss_gpio4, pcie(rstoutn), ge(mdc) +mpp32 32 gpio, mii(col), mii(txerr), mss_spi(miso), tdm(drx), au(i2sextclk), au(i2sdi), ge(mdio), sdio(v18_en), pcie1(clkreq), mss_gpio0 +mpp33 33 gpio, mii(txclk), sdio(pwr10), mss_spi(csn), tdm(fsync), au(i2smclk), sdio(bus_pwr), xg(mdio), pcie2(clkreq), mss_gpio1 +mpp34 34 gpio, mii(rxerr), sdio(pwr11), mss_spi(mosi), tdm(dtx), au(i2slrclk), sdio(wr_protect), ge(mdc), pcie0(clkreq), mss_gpio2 +mpp35 35 gpio, sata1(present_act), i2c1(sda), mss_spi(clk), tdm(pclk), au(i2sdo_spdifo), sdio(card_detect), xg(mdio), ge(mdio), pcie(rstoutn), mss_gpio3 +mpp36 36 gpio, synce2(clk), i2c1(sck), ptp(clk), synce1(clk), au(i2sbclk), sata0(present_act), xg(mdc), ge(mdc), pcie2(clkreq), mss_gpio5 +mpp37 37 gpio, uart2(rxd), i2c0(sck), ptp(pclk_out), tdm(intn), mss_i2c(sck), sata1(present_act), ge(mdc), xg(mdc), pcie1(clkreq), mss_gpio6, link(rd_out_cp2cp) +mpp38 38 gpio, uart2(txd), i2c0(sda), ptp(pulse), tdm(rstn), mss_i2c(sda), sata0(present_act), ge(mdio), xg(mdio), au(i2sextclk), mss_gpio7, ptp(pulse_cp2cp) +mpp39 39 gpio, sdio(wr_protect), au(i2sbclk), ptp(clk), spi0(csn1), sata1(present_act), mss_gpio0 +mpp40 40 gpio, sdio(pwr11), synce1(clk), mss_i2c(sda), au(i2sdo_spdifo), ptp(pclk_out), spi0(clk), uart1(txd), ge(mdio), sata0(present_act), mss_gpio1 +mpp41 41 gpio, sdio(pwr10), sdio(bus_pwr), mss_i2c(sck), au(i2slrclk), ptp(pulse), spi0(mosi), uart1(rxd), ge(mdc), sata1(present_act), mss_gpio2, rei(out_cp2cp) +mpp42 42 gpio, sdio(v18_en), sdio(wr_protect), synce2(clk), au(i2smclk), mss_uart(txd), spi0(miso), uart1(cts), xg(mdc), sata0(present_act), mss_gpio4 +mpp43 43 gpio, sdio(card_detect), synce1(clk), au(i2sextclk), mss_uart(rxd), spi0(csn0), uart1(rts), xg(mdio), sata1(present_act), mss_gpio5, wakeup(out_cp2cp) +mpp44 44 gpio, ge1(txd2), uart0(rts), ptp(clk_cp2cp) +mpp45 45 gpio, ge1(txd3), uart0(txd), pcie(rstoutn) +mpp46 46 gpio, ge1(txd1), uart1(rts) +mpp47 47 gpio, ge1(txd0), spi1(clk), uart1(txd), ge(mdc) +mpp48 48 gpio, ge1(txctl_txen), spi1(mosi), xg(mdc), wakeup(in_cp2cp) +mpp49 49 gpio, ge1(txclkout), mii(crs), spi1(miso), uart1(rxd), ge(mdio), pcie0(clkreq), sdio(v18_en), sei(out_cp2cp) +mpp50 50 gpio, ge1(rxclk), mss_i2c(sda), spi1(csn0), uart2(txd), uart0(rxd), xg(mdio), sdio(pwr11) +mpp51 51 gpio, ge1(rxd0), mss_i2c(sck), spi1(csn1), uart2(rxd), uart0(cts), sdio(pwr10) +mpp52 52 gpio, ge1(rxd1), synce1(clk), synce2(clk), spi1(csn2), uart1(cts), led(clk), pcie(rstoutn), pcie0(clkreq) +mpp53 53 gpio, ge1(rxd2), ptp(clk), spi1(csn3), uart1(rxd), led(stb), sdio(led) +mpp54 54 gpio, ge1(rxd3), synce2(clk), ptp(pclk_out), synce1(clk), led(data), sdio(hw_rst), sdio(wr_protect) +mpp55 55 gpio, ge1(rxctl_rxdv), ptp(pulse), sdio(led), sdio(card_detect) +mpp56 56 gpio, tdm(drx), au(i2sdo_spdifo), spi0(clk), uart1(rxd), sata1(present_act), sdio(clk) +mpp57 57 gpio, mss_i2c(sda), ptp(pclk_out), tdm(intn), au(i2sbclk), spi0(mosi), uart1(txd), sata0(present_act), sdio(cmd) +mpp58 58 gpio, mss_i2c(sck), ptp(clk), tdm(rstn), au(i2sdi), spi0(miso), uart1(cts), led(clk), sdio(d0) +mpp59 59 gpio, mss_gpio7, synce2(clk), tdm(fsync), au(i2slrclk), spi0(csn0), uart0(cts), led(stb), uart1(txd), sdio(d1) +mpp60 60 gpio, mss_gpio6, ptp(pulse), tdm(dtx), au(i2smclk), spi0(csn1), uart0(rts), led(data), uart1(rxd), sdio(d2) +mpp61 61 gpio, mss_gpio5, ptp(clk), tdm(pclk), au(i2sextclk), spi0(csn2), uart0(txd), uart2(txd), sata1(present_act), ge(mdio), sdio(d3) +mpp62 62 gpio, mss_gpio4, synce1(clk), ptp(pclk_out), sata1(present_act), spi0(csn3), uart0(rxd), uart2(rxd), sata0(present_act), ge(mdc) + +GPIO: +----- + +For common binding part and usage, refer to +Documentation/devicetree/bindings/gpio/gpio-mvebu.txt. + +Required properties: + +- compatible: "marvell,armada-8k-gpio" + +- offset: offset address inside the syscon block + +Example: + +CP110_LABEL(syscon0): system-controller@440000 { + compatible = "syscon", "simple-mfd"; + reg = <0x440000 0x1000>; + + CP110_LABEL(clk): clock { + compatible = "marvell,cp110-clock"; + #clock-cells = <2>; + }; + + CP110_LABEL(pinctrl): pinctrl { + compatible = "marvell,armada-8k-cpm-pinctrl"; + }; + + CP110_LABEL(gpio1): gpio@100 { + compatible = "marvell,armada-8k-gpio"; + offset = <0x100>; + ngpios = <32>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&CP110_LABEL(pinctrl) 0 0 32>; + }; + +}; + +SYSTEM CONTROLLER 1 +=================== + +Thermal: +-------- + +The thermal IP can probe the temperature all around the processor. It +may feature several channels, each of them wired to one sensor. + +For common binding part and usage, refer to +Documentation/devicetree/bindings/thermal/thermal.txt + +Required properties: +- compatible: must be one of: + * marvell,armada-cp110-thermal +- reg: register range associated with the thermal functions. + +Optional properties: +- #thermal-sensor-cells: shall be <1> when thermal-zones subnodes refer + to this IP and represents the channel ID. There is one sensor per + channel. O refers to the thermal IP internal channel. + +Example: +CP110_LABEL(syscon1): system-controller@6f8000 { + compatible = "syscon", "simple-mfd"; + reg = <0x6f8000 0x1000>; + + CP110_LABEL(thermal): thermal-sensor@70 { + compatible = "marvell,armada-cp110-thermal"; + reg = <0x70 0x10>; + #thermal-sensor-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/kirkwood.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/kirkwood.txt new file mode 100644 index 0000000000000000000000000000000000000000..98cce9a653ebfba870398c5936d91f0af39b3076 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/kirkwood.txt @@ -0,0 +1,27 @@ +Marvell Kirkwood Platforms Device Tree Bindings +----------------------------------------------- + +Boards with a SoC of the Marvell Kirkwood +shall have the following property: + +Required root node property: + +compatible: must contain "marvell,kirkwood"; + +In order to support the kirkwood cpufreq driver, there must be a node +cpus/cpu@0 with three clocks, "cpu_clk", "ddrclk" and "powersave", +where the "powersave" clock is a gating clock used to switch the CPU +between the "cpu_clk" and the "ddrclk". + +Example: + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "marvell,sheeva-88SV131"; + clocks = <&core_clk 1>, <&core_clk 3>, <&gate_clk 11>; + clock-names = "cpu_clk", "ddrclk", "powersave"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,berlin.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,berlin.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bab18409b7acabfdfda8bba05b9da53436773b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,berlin.txt @@ -0,0 +1,96 @@ +Marvell Berlin SoC Family Device Tree Bindings +--------------------------------------------------------------- + +Work in progress statement: + +Device tree files and bindings applying to Marvell Berlin SoCs and boards are +considered "unstable". Any Marvell Berlin device tree binding may change at any +time. Be sure to use a device tree binary and a kernel image generated from the +same source tree. + +Please refer to Documentation/devicetree/bindings/ABI.txt for a definition of a +stable binding/ABI. + +--------------------------------------------------------------- + +Boards with a SoC of the Marvell Berlin family, e.g. Armada 1500 +shall have the following properties: + +* Required root node properties: +compatible: must contain "marvell,berlin" + +In addition, the above compatible shall be extended with the specific +SoC and board used. Currently known SoC compatibles are: + "marvell,berlin2" for Marvell Armada 1500 (BG2, 88DE3100), + "marvell,berlin2cd" for Marvell Armada 1500-mini (BG2CD, 88DE3005) + "marvell,berlin2ct" for Marvell Armada ? (BG2CT, 88DE????) + "marvell,berlin2q" for Marvell Armada 1500-pro (BG2Q, 88DE3114) + "marvell,berlin3" for Marvell Armada ? (BG3, 88DE????) + +* Example: + +/ { + model = "Sony NSZ-GS7"; + compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin"; + + ... +} + +* Marvell Berlin CPU control bindings + +CPU control register allows various operations on CPUs, like resetting them +independently. + +Required properties: +- compatible: should be "marvell,berlin-cpu-ctrl" +- reg: address and length of the register set + +Example: + +cpu-ctrl@f7dd0000 { + compatible = "marvell,berlin-cpu-ctrl"; + reg = <0xf7dd0000 0x10000>; +}; + +* Marvell Berlin2 chip control binding + +Marvell Berlin SoCs have a chip control register set providing several +individual registers dealing with pinmux, padmux, clock, reset, and secondary +CPU boot address. Unfortunately, the individual registers are spread among the +chip control registers, so there should be a single DT node only providing the +different functions which are described below. + +Required properties: +- compatible: + * the first and second values must be: + "simple-mfd", "syscon" +- reg: address and length of following register sets for + BG2/BG2CD: chip control register set + BG2Q: chip control register set and cpu pll registers + +* Marvell Berlin2 system control binding + +Marvell Berlin SoCs have a system control register set providing several +individual registers dealing with pinmux, padmux, and reset. + +Required properties: +- compatible: + * the first and second values must be: + "simple-mfd", "syscon" +- reg: address and length of the system control register set + +Example: + +chip: chip-control@ea0000 { + compatible = "simple-mfd", "syscon"; + reg = <0xea0000 0x400>; + + /* sub-device nodes */ +}; + +sysctrl: system-controller@d000 { + compatible = "simple-mfd", "syscon"; + reg = <0xd000 0x100>; + + /* sub-device nodes */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,dove.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,dove.txt new file mode 100644 index 0000000000000000000000000000000000000000..aaaf64c56e448d87ad353724ac0a0ed07c910858 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,dove.txt @@ -0,0 +1,22 @@ +Marvell Dove Platforms Device Tree Bindings +----------------------------------------------- + +Boards with a Marvell Dove SoC shall have the following properties: + +Required root node property: +- compatible: must contain "marvell,dove"; + +* Global Configuration registers + +Global Configuration registers of Dove SoC are shared by a syscon node. + +Required properties: +- compatible: must contain "marvell,dove-global-config" and "syscon". +- reg: base address and size of the Global Configuration registers. + +Example: + +gconf: global-config@e802c { + compatible = "marvell,dove-global-config", "syscon"; + reg = <0xe802c 0x14>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,kirkwood.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,kirkwood.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d28fe4bf654e8d1fa9c1a3cc06a8fab0631ef9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,kirkwood.txt @@ -0,0 +1,105 @@ +Marvell Kirkwood SoC Family Device Tree Bindings +------------------------------------------------ + +Boards with a SoC of the Marvell Kirkwook family, eg 88f6281 + +* Required root node properties: +compatible: must contain "marvell,kirkwood" + +In addition, the above compatible shall be extended with the specific +SoC. Currently known SoC compatibles are: + +"marvell,kirkwood-88f6192" +"marvell,kirkwood-88f6281" +"marvell,kirkwood-88f6282" +"marvell,kirkwood-88f6283" +"marvell,kirkwood-88f6702" +"marvell,kirkwood-98DX4122" + +And in addition, the compatible shall be extended with the specific +board. Currently known boards are: + +"buffalo,linkstation-lsqvl" +"buffalo,linkstation-lsvl" +"buffalo,linkstation-lswsxl" +"buffalo,linkstation-lswxl" +"buffalo,linkstation-lswvl" +"buffalo,lschlv2" +"buffalo,lsxhl" +"buffalo,lsxl" +"cloudengines,pogo02" +"cloudengines,pogoplugv4" +"dlink,dns-320" +"dlink,dns-320-a1" +"dlink,dns-325" +"dlink,dns-325-a1" +"dlink,dns-kirkwood" +"excito,b3" +"globalscale,dreamplug-003-ds2001" +"globalscale,guruplug" +"globalscale,guruplug-server-plus" +"globalscale,sheevaplug" +"globalscale,sheevaplug" +"globalscale,sheevaplug-esata" +"globalscale,sheevaplug-esata-rev13" +"iom,iconnect" +"iom,iconnect-1.1" +"iom,ix2-200" +"keymile,km_kirkwood" +"lacie,cloudbox" +"lacie,inetspace_v2" +"lacie,laplug" +"lacie,nas2big" +"lacie,netspace_lite_v2" +"lacie,netspace_max_v2" +"lacie,netspace_mini_v2" +"lacie,netspace_v2" +"marvell,db-88f6281-bp" +"marvell,db-88f6282-bp" +"marvell,mv88f6281gtw-ge" +"marvell,rd88f6281" +"marvell,rd88f6281" +"marvell,rd88f6281-a0" +"marvell,rd88f6281-a1" +"mpl,cec4" +"mpl,cec4-10" +"netgear,readynas" +"netgear,readynas" +"netgear,readynas-duo-v2" +"netgear,readynas-nv+-v2" +"plathome,openblocks-a6" +"plathome,openblocks-a7" +"raidsonic,ib-nas6210" +"raidsonic,ib-nas6210-b" +"raidsonic,ib-nas6220" +"raidsonic,ib-nas6220-b" +"raidsonic,ib-nas62x0" +"seagate,dockstar" +"seagate,goflexnet" +"synology,ds109" +"synology,ds110jv10" +"synology,ds110jv20" +"synology,ds110jv30" +"synology,ds111" +"synology,ds209" +"synology,ds210jv10" +"synology,ds210jv20" +"synology,ds212" +"synology,ds212jv10" +"synology,ds212jv20" +"synology,ds212pv10" +"synology,ds409" +"synology,ds409slim" +"synology,ds410j" +"synology,ds411" +"synology,ds411j" +"synology,ds411slim" +"synology,ds413jv10" +"synology,rs212" +"synology,rs409" +"synology,rs411" +"synology,rs812" +"usi,topkick" +"usi,topkick-1281P2" +"zyxel,nsa310" +"zyxel,nsa310a" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,orion5x.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,orion5x.txt new file mode 100644 index 0000000000000000000000000000000000000000..748a8f28746259599e535f304b936f7f287ac552 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/marvell,orion5x.txt @@ -0,0 +1,25 @@ +Marvell Orion SoC Family Device Tree Bindings +--------------------------------------------- + +Boards with a SoC of the Marvell Orion family, eg 88f5181 + +* Required root node properties: +compatible: must contain "marvell,orion5x" + +In addition, the above compatible shall be extended with the specific +SoC. Currently known SoC compatibles are: + +"marvell,orion5x-88f5181" +"marvell,orion5x-88f5182" + +And in addition, the compatible shall be extended with the specific +board. Currently known boards are: + +"buffalo,lsgl" +"buffalo,lswsgl" +"buffalo,lswtgl" +"lacie,ethernet-disk-mini-v2" +"lacie,d2-network" +"marvell,rd-88f5182-nas" +"maxtor,shared-storage-2" +"netgear,wnr854t" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/mvebu-cpu-config.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/mvebu-cpu-config.txt new file mode 100644 index 0000000000000000000000000000000000000000..2cdcd716da404914f7243e629f8ffbf63f4ee7e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/mvebu-cpu-config.txt @@ -0,0 +1,20 @@ +MVEBU CPU Config registers +-------------------------- + +MVEBU (Marvell SOCs: Armada 370/XP) + +Required properties: + +- compatible: one of: + - "marvell,armada-370-cpu-config" + - "marvell,armada-xp-cpu-config" + +- reg: Should contain CPU config registers location and length, in + their per-CPU variant + +Example: + + cpu-config@21000 { + compatible = "marvell,armada-xp-cpu-config"; + reg = <0x21000 0x8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/marvell/mvebu-system-controller.txt b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/mvebu-system-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..d24ab2ebf8a721f630868de9d3f4b85f07c2f1e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/marvell/mvebu-system-controller.txt @@ -0,0 +1,18 @@ +MVEBU System Controller +----------------------- +MVEBU (Marvell SOCs: Armada 370/375/XP, Dove, mv78xx0, Kirkwood, Orion5x) + +Required properties: + +- compatible: one of: + - "marvell,orion-system-controller" + - "marvell,armada-370-xp-system-controller" + - "marvell,armada-375-system-controller" +- reg: Should contain system controller registers location and length. + +Example: + + system-controller@d0018200 { + compatible = "marvell,armada-370-xp-system-controller"; + reg = <0xd0018200 0x500>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f260e5cfd1695dcce638fc7333eeca0a58d7035 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek.txt @@ -0,0 +1,79 @@ +MediaTek SoC based Platforms Device Tree Bindings + +Boards with a MediaTek SoC shall have the following property: + +Required root node property: + +compatible: Must contain one of + "mediatek,mt2701" + "mediatek,mt2712" + "mediatek,mt6580" + "mediatek,mt6589" + "mediatek,mt6592" + "mediatek,mt6755" + "mediatek,mt6765" + "mediatek,mt6795" + "mediatek,mt6797" + "mediatek,mt7622" + "mediatek,mt7623" which is referred to MT7623N SoC + "mediatek,mt7623a" + "mediatek,mt8127" + "mediatek,mt8135" + "mediatek,mt8173" + + +Supported boards: + +- Evaluation board for MT2701: + Required root node properties: + - compatible = "mediatek,mt2701-evb", "mediatek,mt2701"; +- Evaluation board for MT2712: + Required root node properties: + - compatible = "mediatek,mt2712-evb", "mediatek,mt2712"; +- Evaluation board for MT6580: + Required root node properties: + - compatible = "mediatek,mt6580-evbp1", "mediatek,mt6580"; +- bq Aquaris5 smart phone: + Required root node properties: + - compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589"; +- Evaluation board for MT6592: + Required root node properties: + - compatible = "mediatek,mt6592-evb", "mediatek,mt6592"; +- Evaluation phone for MT6755(Helio P10): + Required root node properties: + - compatible = "mediatek,mt6755-evb", "mediatek,mt6755"; +- Evaluation board for MT6765(Helio P22): + Required root node properties: + - compatible = "mediatek,mt6765-evb", "mediatek,mt6765"; +- Evaluation board for MT6795(Helio X10): + Required root node properties: + - compatible = "mediatek,mt6795-evb", "mediatek,mt6795"; +- Evaluation board for MT6797(Helio X20): + Required root node properties: + - compatible = "mediatek,mt6797-evb", "mediatek,mt6797"; +- Mediatek X20 Development Board: + Required root node properties: + - compatible = "archermind,mt6797-x20-dev", "mediatek,mt6797"; +- Reference board variant 1 for MT7622: + Required root node properties: + - compatible = "mediatek,mt7622-rfb1", "mediatek,mt7622"; +- Reference board for MT7623a with eMMC: + Required root node properties: + - compatible = "mediatek,mt7623a-rfb-emmc", "mediatek,mt7623"; +- Reference board for MT7623a with NAND: + Required root node properties: + - compatible = "mediatek,mt7623a-rfb-nand", "mediatek,mt7623"; +- Reference board for MT7623n with eMMC: + Required root node properties: + - compatible = "mediatek,mt7623n-rfb-emmc", "mediatek,mt7623"; +- Bananapi BPI-R2 board: + - compatible = "bananapi,bpi-r2", "mediatek,mt7623"; +- MTK mt8127 tablet moose EVB: + Required root node properties: + - compatible = "mediatek,mt8127-moose", "mediatek,mt8127"; +- MTK mt8135 tablet EVB: + Required root node properties: + - compatible = "mediatek,mt8135-evbp1", "mediatek,mt8135"; +- MTK mt8173 tablet EVB: + Required root node properties: + - compatible = "mediatek,mt8173-evb", "mediatek,mt8173"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,apmixedsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,apmixedsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..b404d592ce58a6f129b6d652482b85c2ebbab21f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,apmixedsys.txt @@ -0,0 +1,27 @@ +Mediatek apmixedsys controller +============================== + +The Mediatek apmixedsys controller provides the PLLs to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-apmixedsys" + - "mediatek,mt2712-apmixedsys", "syscon" + - "mediatek,mt6797-apmixedsys" + - "mediatek,mt7622-apmixedsys" + - "mediatek,mt8135-apmixedsys" + - "mediatek,mt8173-apmixedsys" +- #clock-cells: Must be 1 + +The apmixedsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +apmixedsys: clock-controller@10209000 { + compatible = "mediatek,mt8173-apmixedsys"; + reg = <0 0x10209000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,audsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,audsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..34a69ba67f13f0f90fabb67de3d1ab3de1c4b6be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,audsys.txt @@ -0,0 +1,32 @@ +MediaTek AUDSYS controller +============================ + +The MediaTek AUDSYS controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-audsys", "syscon" + - "mediatek,mt7622-audsys", "syscon" +- #clock-cells: Must be 1 + +The AUDSYS controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Required sub-nodes: +------- +For common binding part and usage, refer to +../sonud/mt2701-afe-pcm.txt. + +Example: + + audsys: clock-controller@11220000 { + compatible = "mediatek,mt7622-audsys", "syscon"; + reg = <0 0x11220000 0 0x2000>; + #clock-cells = <1>; + + afe: audio-controller { + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,bdpsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,bdpsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..4010e37c53a0218554edfb5885262a168ba73108 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,bdpsys.txt @@ -0,0 +1,23 @@ +Mediatek bdpsys controller +============================ + +The Mediatek bdpsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-bdpsys", "syscon" + - "mediatek,mt2712-bdpsys", "syscon" +- #clock-cells: Must be 1 + +The bdpsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +bdpsys: clock-controller@1c000000 { + compatible = "mediatek,mt2701-bdpsys", "syscon"; + reg = <0 0x1c000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,ethsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,ethsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f5335b480aca6377826138aa39ad4153e98eb46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,ethsys.txt @@ -0,0 +1,25 @@ +Mediatek ethsys controller +============================ + +The Mediatek ethsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-ethsys", "syscon" + - "mediatek,mt7622-ethsys", "syscon" +- #clock-cells: Must be 1 +- #reset-cells: Must be 1 + +The ethsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +ethsys: clock-controller@1b000000 { + compatible = "mediatek,mt2701-ethsys", "syscon"; + reg = <0 0x1b000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,g3dsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,g3dsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..7de43bf41fdc5f4cf5c409559f8301431216c4d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,g3dsys.txt @@ -0,0 +1,30 @@ +MediaTek g3dsys controller +============================ + +The MediaTek g3dsys controller provides various clocks and reset controller to +the GPU. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-g3dsys", "syscon": + for MT2701 SoC + - "mediatek,mt7623-g3dsys", "mediatek,mt2701-g3dsys", "syscon": + for MT7623 SoC +- #clock-cells: Must be 1 +- #reset-cells: Must be 1 + +The g3dsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +g3dsys: clock-controller@13000000 { + compatible = "mediatek,mt7623-g3dsys", + "mediatek,mt2701-g3dsys", + "syscon"; + reg = <0 0x13000000 0 0x200>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,hifsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,hifsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5629d64cef2d2dfa218dabb7646abd50b135a08 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,hifsys.txt @@ -0,0 +1,25 @@ +Mediatek hifsys controller +============================ + +The Mediatek hifsys controller provides various clocks and reset +outputs to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2701-hifsys", "syscon" + - "mediatek,mt7622-hifsys", "syscon" +- #clock-cells: Must be 1 + +The hifsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +hifsys: clock-controller@1a000000 { + compatible = "mediatek,mt2701-hifsys", "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,imgsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,imgsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..868bd51a98befcb5d901bf67995525e9dceb8173 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,imgsys.txt @@ -0,0 +1,25 @@ +Mediatek imgsys controller +============================ + +The Mediatek imgsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-imgsys", "syscon" + - "mediatek,mt2712-imgsys", "syscon" + - "mediatek,mt6797-imgsys", "syscon" + - "mediatek,mt8173-imgsys", "syscon" +- #clock-cells: Must be 1 + +The imgsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +imgsys: clock-controller@15000000 { + compatible = "mediatek,mt8173-imgsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,infracfg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,infracfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..566f153f9f83b29ef7677ea7cd8412486e4154d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,infracfg.txt @@ -0,0 +1,34 @@ +Mediatek infracfg controller +============================ + +The Mediatek infracfg controller provides various clocks and reset +outputs to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-infracfg", "syscon" + - "mediatek,mt2712-infracfg", "syscon" + - "mediatek,mt6797-infracfg", "syscon" + - "mediatek,mt7622-infracfg", "syscon" + - "mediatek,mt8135-infracfg", "syscon" + - "mediatek,mt8173-infracfg", "syscon" +- #clock-cells: Must be 1 +- #reset-cells: Must be 1 + +The infracfg controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. +Also it uses the common reset controller binding from +Documentation/devicetree/bindings/reset/reset.txt. +The available reset outputs are defined in +dt-bindings/reset/mt*-resets.h + +Example: + +infracfg: power-controller@10001000 { + compatible = "mediatek,mt8173-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,jpgdecsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,jpgdecsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..2df799cd06a742a0b8d1186c296c5c8d7c618baf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,jpgdecsys.txt @@ -0,0 +1,22 @@ +Mediatek jpgdecsys controller +============================ + +The Mediatek jpgdecsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt2712-jpgdecsys", "syscon" +- #clock-cells: Must be 1 + +The jpgdecsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +jpgdecsys: syscon@19000000 { + compatible = "mediatek,mt2712-jpgdecsys", "syscon"; + reg = <0 0x19000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mcucfg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mcucfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8fb03f3613e39123a1b94270850c4b481b7d172 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mcucfg.txt @@ -0,0 +1,22 @@ +Mediatek mcucfg controller +============================ + +The Mediatek mcucfg controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2712-mcucfg", "syscon" +- #clock-cells: Must be 1 + +The mcucfg controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +mcucfg: syscon@10220000 { + compatible = "mediatek,mt2712-mcucfg", "syscon"; + reg = <0 0x10220000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mfgcfg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mfgcfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..859e67b416d5006ae2851b80352e32493f9c4c7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mfgcfg.txt @@ -0,0 +1,22 @@ +Mediatek mfgcfg controller +============================ + +The Mediatek mfgcfg controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2712-mfgcfg", "syscon" +- #clock-cells: Must be 1 + +The mfgcfg controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +mfgcfg: syscon@13000000 { + compatible = "mediatek,mt2712-mfgcfg", "syscon"; + reg = <0 0x13000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mmsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mmsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..4eb8bbe15c01cd4828a75a9acb1d8913e231e515 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,mmsys.txt @@ -0,0 +1,25 @@ +Mediatek mmsys controller +============================ + +The Mediatek mmsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-mmsys", "syscon" + - "mediatek,mt2712-mmsys", "syscon" + - "mediatek,mt6797-mmsys", "syscon" + - "mediatek,mt8173-mmsys", "syscon" +- #clock-cells: Must be 1 + +The mmsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +mmsys: clock-controller@14000000 { + compatible = "mediatek,mt8173-mmsys", "syscon"; + reg = <0 0x14000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,pciesys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,pciesys.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fe5dc6097a6a35b7d25f63cbbc0d5ae3bb9870c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,pciesys.txt @@ -0,0 +1,24 @@ +MediaTek PCIESYS controller +============================ + +The MediaTek PCIESYS controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt7622-pciesys", "syscon" +- #clock-cells: Must be 1 +- #reset-cells: Must be 1 + +The PCIESYS controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +pciesys: pciesys@1a100800 { + compatible = "mediatek,mt7622-pciesys", "syscon"; + reg = <0 0x1a100800 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,pericfg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,pericfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb58ca8c2770b5924baf3b624fb6828260553a0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,pericfg.txt @@ -0,0 +1,33 @@ +Mediatek pericfg controller +=========================== + +The Mediatek pericfg controller provides various clocks and reset +outputs to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-pericfg", "syscon" + - "mediatek,mt2712-pericfg", "syscon" + - "mediatek,mt7622-pericfg", "syscon" + - "mediatek,mt8135-pericfg", "syscon" + - "mediatek,mt8173-pericfg", "syscon" +- #clock-cells: Must be 1 +- #reset-cells: Must be 1 + +The pericfg controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. +Also it uses the common reset controller binding from +Documentation/devicetree/bindings/reset/reset.txt. +The available reset outputs are defined in +dt-bindings/reset/mt*-resets.h + +Example: + +pericfg: power-controller@10003000 { + compatible = "mediatek,mt8173-pericfg", "syscon"; + reg = <0 0x10003000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,sgmiisys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,sgmiisys.txt new file mode 100644 index 0000000000000000000000000000000000000000..d113b8e741f30aefbe67fc58b1025aaa2988b13b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,sgmiisys.txt @@ -0,0 +1,22 @@ +MediaTek SGMIISYS controller +============================ + +The MediaTek SGMIISYS controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt7622-sgmiisys", "syscon" +- #clock-cells: Must be 1 + +The SGMIISYS controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +sgmiisys: sgmiisys@1b128000 { + compatible = "mediatek,mt7622-sgmiisys", "syscon"; + reg = <0 0x1b128000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,ssusbsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,ssusbsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8184da2508c01c66b0013de00c075ccb794bcad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,ssusbsys.txt @@ -0,0 +1,24 @@ +MediaTek SSUSBSYS controller +============================ + +The MediaTek SSUSBSYS controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt7622-ssusbsys", "syscon" +- #clock-cells: Must be 1 +- #reset-cells: Must be 1 + +The SSUSBSYS controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +ssusbsys: ssusbsys@1a000000 { + compatible = "mediatek,mt7622-ssusbsys", "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,topckgen.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,topckgen.txt new file mode 100644 index 0000000000000000000000000000000000000000..24014a7e2332370202fcbf2ffc31ede87df571f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,topckgen.txt @@ -0,0 +1,27 @@ +Mediatek topckgen controller +============================ + +The Mediatek topckgen controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-topckgen" + - "mediatek,mt2712-topckgen", "syscon" + - "mediatek,mt6797-topckgen" + - "mediatek,mt7622-topckgen" + - "mediatek,mt8135-topckgen" + - "mediatek,mt8173-topckgen" +- #clock-cells: Must be 1 + +The topckgen controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +topckgen: power-controller@10000000 { + compatible = "mediatek,mt8173-topckgen"; + reg = <0 0x10000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vdecsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vdecsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea40d05089f8306b2b15e2b0cd304ef61b8f8602 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vdecsys.txt @@ -0,0 +1,25 @@ +Mediatek vdecsys controller +============================ + +The Mediatek vdecsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2701-vdecsys", "syscon" + - "mediatek,mt2712-vdecsys", "syscon" + - "mediatek,mt6797-vdecsys", "syscon" + - "mediatek,mt8173-vdecsys", "syscon" +- #clock-cells: Must be 1 + +The vdecsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +vdecsys: clock-controller@16000000 { + compatible = "mediatek,mt8173-vdecsys", "syscon"; + reg = <0 0x16000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vencltsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vencltsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cc299fd7857f08389d765e0660cbf24a556f6d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vencltsys.txt @@ -0,0 +1,22 @@ +Mediatek vencltsys controller +============================ + +The Mediatek vencltsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be: + - "mediatek,mt8173-vencltsys", "syscon" +- #clock-cells: Must be 1 + +The vencltsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +vencltsys: clock-controller@19000000 { + compatible = "mediatek,mt8173-vencltsys", "syscon"; + reg = <0 0x19000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vencsys.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vencsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..851545357e94af7f3ec4a96ac882cded0d166d7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mediatek/mediatek,vencsys.txt @@ -0,0 +1,24 @@ +Mediatek vencsys controller +============================ + +The Mediatek vencsys controller provides various clocks to the system. + +Required Properties: + +- compatible: Should be one of: + - "mediatek,mt2712-vencsys", "syscon" + - "mediatek,mt6797-vencsys", "syscon" + - "mediatek,mt8173-vencsys", "syscon" +- #clock-cells: Must be 1 + +The vencsys controller uses the common clk binding from +Documentation/devicetree/bindings/clock/clock-bindings.txt +The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +Example: + +vencsys: clock-controller@18000000 { + compatible = "mediatek,mt8173-vencsys", "syscon"; + reg = <0 0x18000000 0 0x1000>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/moxart.txt b/arch/arm64/boot/dts/vendor/bindings/arm/moxart.txt new file mode 100644 index 0000000000000000000000000000000000000000..11087edb065827168cf0447bceb56aab4522b114 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/moxart.txt @@ -0,0 +1,12 @@ +MOXA ART device tree bindings + +Boards with the MOXA ART SoC shall have the following properties: + +Required root node property: + +compatible = "moxa,moxart"; + +Boards: + +- UC-7112-LX: embedded computer + compatible = "moxa,moxart-uc-7112-lx", "moxa,moxart" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/feroceon.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/feroceon.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d244b999d1035992e48a4b144cc8527f0446f88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/feroceon.txt @@ -0,0 +1,16 @@ +* Marvell Feroceon Cache + +Required properties: +- compatible : Should be either "marvell,feroceon-cache" or + "marvell,kirkwood-cache". + +Optional properties: +- reg : Address of the L2 cache control register. Mandatory for + "marvell,kirkwood-cache", not used by "marvell,feroceon-cache" + + +Example: + l2: l2-cache@20128 { + compatible = "marvell,kirkwood-cache"; + reg = <0x20128 0x4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/mrvl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/mrvl.txt new file mode 100644 index 0000000000000000000000000000000000000000..117d741a2e4ff1c529818887e62a3308a193e944 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/mrvl.txt @@ -0,0 +1,14 @@ +Marvell Platforms Device Tree Bindings +---------------------------------------------------- + +PXA168 Aspenite Board +Required root node properties: + - compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168"; + +PXA910 DKB Board +Required root node properties: + - compatible = "mrvl,pxa910-dkb"; + +MMP2 Brownstone Board +Required root node properties: + - compatible = "mrvl,mmp2-brownstone"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/tauros2.txt b/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/tauros2.txt new file mode 100644 index 0000000000000000000000000000000000000000..31af1cbb60bde85fbff5d20f7e681009611fd08a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/mrvl/tauros2.txt @@ -0,0 +1,17 @@ +* Marvell Tauros2 Cache + +Required properties: +- compatible : Should be "marvell,tauros2-cache". +- marvell,tauros2-cache-features : Specify the features supported for the + tauros2 cache. + The features including + CACHE_TAUROS2_PREFETCH_ON (1 << 0) + CACHE_TAUROS2_LINEFILL_BURST8 (1 << 1) + The definition can be found at + arch/arm/include/asm/hardware/cache-tauros2.h + +Example: + L2: l2-cache { + compatible = "marvell,tauros2-cache"; + marvell,tauros2-cache-features = <0x3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/android.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/android.txt new file mode 100644 index 0000000000000000000000000000000000000000..32e418fd01fb1f573868d4ef603d4cfc20daaa4a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/android.txt @@ -0,0 +1,118 @@ +Android firmware + +Node to specify early mount of vendor and system partition. + +Required properties + +-compatible: "android,firmware" + +Child nodes: +------------ + +fstab: +------------------------------ + +fstab entry to specify mount attributes of vendor partition. + +Required properties: + +-compatible: "android,fstab" + +Child nodes: +------------ + +vendor: +----------------- + +vendor partition specification. + +Required properties: + +-compatible: "android, vendor" +-dev: block device corresponding to vendor partition +-type: file system type of vendor partition +-mnt_flags: mount flags +-fsmgr_flags: fsmgr flags + +Example: + + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; + +odm: +----------------- + +odm partition specification. + +Required properties: + +-compatible: "android, odm" +-dev: block device corresponding to odm partition +-type: file system type of odm partition +-mnt_flags: mount flags +-fsmgr_flags: fsmgr flags + +Example: + + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + odm { + compatible = "android,odm"; + dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/odm"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; + +system: +----------------- + +system partition specification. + +Required properties: + +-compatible: "android,system" +-dev: block device corresponding to system partition +-type: file system type of system partition +-mnt_flags: mount flags +-fsmgr_flags: fsmgr flags + +Example: + + firmware: firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + system { + compatible = "android,system"; + dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/system"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/board-id.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/board-id.txt new file mode 100644 index 0000000000000000000000000000000000000000..e07a1c9e6dcb06f0a7e24fda496eb308b73045f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/board-id.txt @@ -0,0 +1,64 @@ +* BOARD-ID + +The qcom,board-id entry specifies the MSM platform and subtype revision. +It can optionally be an array of these to indicate multiple hardware that use +the same device tree. It is expected that the bootloader will use this +information at boot-up to decide which device tree to use when given multiple +device trees, some of which may not be compatible with the actual hardware. It +is the bootloader's responsibility to pass the correct device tree to the kernel. + +Legacy format: + +It is expected that the qcom,board-id entry be at the top level of the device +tree structure. The format of the entry is: + + qcom,board-id = [, ...] + +where platform_id and subtype_id are the numeric values for the platform and +subtype of the current hardware. + +The "subtype_id" cell is a 32-bit integer whose bit values are defined as follows: + bits 31-20 = Reserved bits + bits 19-16 = Boot Device Type. + MSM: + 0: default (eMMC) + 2: EMMC_SDC1 + 4: BOOT_UFS + MDM: + 0: default (NAND) + 3: EMMC_SDC1 + bits 15-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1, default value as 0x0 + bits 7-0 = Platform Subtype + +In the event that a given device tree is applicable to all hardware versions +matching a given Platform Type / Subtype ID, the major/minior platform version +fields in the board_id property shall both be specified as 0xff. + +Modern format: +The cell layout of the qcom,board-id property is as follows: + + qcom,board-id = + +where board_id is a 32-bit integer whose bit values are defined as follows: + bits 31-24 = Platform Subtype ID + bits 23-16 = Platform Version (Major) + bits 15-8 = Platform Version (Minor) + bits 7-0 = Platform Type ID + +and the 'reserved' cell is a 32-bit integer whose bit values are defined as follows: + bits 31-13 = Reserved Bits + bits 12-11 = Panel Detection. 00 - limit to HD, 01 - limit to 720p, + 10 - limit to qHD, 11 - limit to FWVGA + bits 10-8 = DDR Size. For devices with DDR Size as 512MB the value is 0x1, + default value as 0x0 + bits 7-0 = Platform Subtype + +In the event that a given device tree is applicable to all hardware versions +matching a given Platform Type / Subtype ID, the major/minior platform version +fields in the board_id property shall both be specified as 0xff. + +Example: + qcom,board-id = <15 0>; + qcom,board-id = <0x01040708, 0>; + qcom,board-id = <0x01ffff08, 0>; + qcom,board-id = <8, 0x100>; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/ddr_stats.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/ddr_stats.txt new file mode 100644 index 0000000000000000000000000000000000000000..c59375908c0b0dca24e5f55760099154aea01b01 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/ddr_stats.txt @@ -0,0 +1,31 @@ +* DDR Stats + +AOP maintains DDR statistics like DDR LPMs and frequency stats. DDR stats +driver gives sysfs interface to display this. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,ddr-stats". + +- reg: + Usage: required + Value type: + Definition: The address on the AOP Message RAM from where the stats + are read should be provided as "phys_addr_base". + The offset from which the stats are available should be + provided as "offset_addr". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. + +EXAMPLE: + qcom,ddr-stats@c300000 { + compatible = "qcom,ddr-stats"; + reg = <0xc300000 0x1000>, <0xc3f001c 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/heap-sharing.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/heap-sharing.txt new file mode 100644 index 0000000000000000000000000000000000000000..03b1efdd60f0f10f1fc0e4678bdd6f5bc4f17c9d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/heap-sharing.txt @@ -0,0 +1,65 @@ +* Memory Share Driver (MEMSHARE) + +The Memshare driver implements a Kernel QMI service on the +LA-APSS, which is responsible for providing contiguous physical +memory to MPSS for use cases when the modem requires additional +memory (e.g. GPS). + +Required properties for Memshare + +-Root Node- + +- compatible: Must be "qcom,memshare" + +Required properties for child nodes: + +- compatible: Must be "qcom,memshare-peripheral" + +- qcom,peripheral-size: Indicates the size (in bytes) required for that child. + +- qcom,client-id: Indicates the client id of the child node. + +- label: Indicates the peripheral information for the node. Should be one of + the following: + - modem /* Represent Modem Peripheral */ + - adsp /* Represent ADSP Peripheral */ + - wcnss /* Represent WCNSS Peripheral */ + +Optional properties for child nodes: + +- qcom,allocate-boot-time: Indicates whether clients needs boot time memory allocation. + +- qcom,allocate-on-request: Indicates memory allocation happens only upon client request + +Note: qcom,allocate-boot-time and qcom,allocate-on-request are mutually exclusive rite now. + +- qcom,guard-band: Indicates addition of a guard band memory allocation in addition to the client's memory region. + +Example 1: + +qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x200000>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; +}; + +Example 2: + +qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-on-request; + qcom,guard-band; + label = "modem"; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/hidqvr-smp2p.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/hidqvr-smp2p.txt new file mode 100644 index 0000000000000000000000000000000000000000..84af8d212ee9528a1f0ddf115c74e5b38e9104ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/hidqvr-smp2p.txt @@ -0,0 +1,15 @@ +Qualcomm Technologies, Inc. HID QVR (hid-qvr) driver + +Required properties: +-compatible : + To communicate with cdsp + qcom,smp2p_interrupt_qvrexternal_5_out (outbound) + +Example: + qcom,smp2p_interrupt_qvrexternal_5_out { + compatible = "qcom,smp2p-interrupt-qvrexternal-5-out"; + qcom,smem-states = <&smp2p_qvrexternal5_out 0>; + qcom,smem-state-names = "qvrexternal-smp2p-out"; + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/hwkm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/hwkm.txt new file mode 100644 index 0000000000000000000000000000000000000000..25ddc158e665ee4af2ef2dd7c0aa16074ec90c67 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/hwkm.txt @@ -0,0 +1,28 @@ +HWKM (Hardware Key Manager) + +The HWKM driver is a platform device driver that helps +communicating with both the master and slave blocks of the +hardware key manager to issue commands to perform key operations +mainly required for storage encryption. + +Required properties: +- compatible : Should be "qcom,hwkm". +- reg: Register set for both master and slaves. +- reg-names : Identifiers for parsing master and slave regs. +- clocks : clocks needed for operating master and the slave. +- clock-names : name identifiers corresponding to the clocks. +- qcom,enable-hwkm-clk: to ensure clocks can be handled by HLOS. +- qcom,op-freq-hz: Max frequency of the listed clocks. + +Example: + + qcom_hwkm: hwkm@10c0000 { + compatible = "qcom,hwkm"; + reg = <0x10c0000 0x9000>, <0x1d90000 0x9000>; + reg-names = "km_master", "ice_slave"; + qcom,enable-hwkm-clk; + + clock-names = "km_clk_src"; + clocks = <&clock_rpmh RPMH_HWKM_CLK>; + qcom,op-freq-hz = <75000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/hyp_core_ctl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/hyp_core_ctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..31a915fa40184fae7fd7ec26a32121ec54c9ab93 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/hyp_core_ctl.txt @@ -0,0 +1,15 @@ +Qualcomm Technologies, Inc. Core Control for Hypervisor + +Required properties: +- compatible: should be "qcom,hyp-core-ctl" +- reg: An array of u32 values. reg[0] contains the token id to be used + for hyp core_ctl system calls to set/get physical CPUs corresponding + to the virtual CPUs. reg[1] ... reg[n] indicate the token ids + to be used while referring to the virtual CPUs respectively. + +Example: + + hyp-core-ctl@346 { + compatible = "qcom,hyp-core-ctl"; + reg = <0x346 0x347 0x348>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/imem.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/imem.txt new file mode 100644 index 0000000000000000000000000000000000000000..cdc8c6cef8b114d50d93a4ce84fb685c8549c57b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/imem.txt @@ -0,0 +1,134 @@ +QTI IMEM + +IMEM is fast on-chip memory used for various debug features and dma transactions. + +Required properties + +-compatible: "qcom,msm-imem" +-reg: start address and size of imem memory + +If any children nodes exist the following properties are required: +-#address-cells: should be 1 +-#size-cells: should be 1 +-ranges: A triplet that includes the child address, parent address, & + length. The child address is assumed to be 0. + +Child nodes: +------------ + +Peripheral Image Loader (pil): +------------------------------ +Required properties: +-compatible: "qcom,msm-imem-pil" +-reg: start address and size of PIL region in imem + +Bootloader Stats: +----------------- +Required properties: +-compatible: "qcom,msm-imem-boot_stats" +-reg: start address and size of boot_stats region in imem + +Cache error reporting: +----------------- +Required properties: +-compatible: "qcom,msm-imem-cache_erp" +-reg: start address and size of cache_erp region in imem + +Memory Dump: +------------ +Required properties: +-compatible: "qcom,msm-imem-mem_dump_table" +-reg: start address and size of mem_dump_table region in imem + +Restart Reason: +--------------- +Required properties: +-compatible: "qcom,msm-imem-restart_reason +-reg: start address and size of restart_reason region in imem + +Download Mode Type: +------------------- +Required properties: +-compatible: "qcom,msm-imem-dload-type" +-reg: start address and size of dload type region in imem + +Download Mode: +-------------- +Required properties: +-compatible: "qcom,msm-imem-download_mode" +-reg: start address and size of download_mode region in imem + +Emergency Download Mode: +------------------------ +-compatible: "qcom,msm-imem-emergency_download_mode" +-reg: start address and size of emergency_download_mode region in imem + +Kaslr Offset: +------------------------ +-compatible: "qcom,msm-imem-kaslr_offset" +-reg: start address and size of kaslr_offset region in imem + +USB Diag Cookies: +----------------- +Memory region used to store USB PID and serial numbers to be used by +bootloader in download mode. + +SSR Minidump Offset +------------------- +-Compatible: "qcom,msm-imem-minidump" +-reg: start address and size of ssr imem region + +Required properties: +-compatible: "qcom,msm-imem-diag-dload" +-reg: start address and size of USB Diag download mode region in imem + +Example: + + qcom,msm-imem { + compatible = "qcom,msm-imem"; + reg = <0xdeadbeef 0x1000>; /* < start_address size > */ + ranges = <0x0 0xdeadbeef 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + download_mode@0 { + compatible = "qcom,msm-imem-download_mode"; + reg = <0x0 8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + imem_cache_erp: cache_erp@6a4 { + compatible = "qcom,msm-imem-cache_erp"; + reg = <0x6a4 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + emergency_download_mode@fe0 { + compatible = "qcom,msm-imem-emergency_download_mode"; + reg = <0xfe0 12>; + }; + + ss_mdump@b88 { + compatible = "qcom,msm-imem-minidump"; + reg = <0xb88 28>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/jtag-mm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/jtag-mm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f57d0ad9e23d1c4604264d0e4b85eea208c1200 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/jtag-mm.txt @@ -0,0 +1,32 @@ +* JTAG-MM + +The jtag-mm entry specifies the memory mapped addresses for the debug and ETM +registers. The jtag-mm driver uses these to save and restore the registers +using memory mapped access during power collapse so as to retain their state +across power collapse. This is necessary in case cp14 access to the registers +is not permitted. + +Required Properties: +compatible: component name used for driver matching, should be: + "qcom,jtag-mm" - for jtag-mm device + "qcom,jtagv8-mm" - for jtagv8-mm device supporting ARMv8 targets + + reg: physical base address and length of the register set + reg-names: should be "etm-base" for etm register set and "debug-base" + for debug register set. + qcom,coresight-jtagmm-cpu: specifies phandle for the cpu associated + with the jtag-mm device + qcom,si-enable : boolean, indicating etm save and restore is + supported via system instructions + qcom,save-restore-disable : boolean, to disable etm save and restore + functionality + +Example: +jtag_mm: jtagmm@fc332000 { + compatible = "qcom,jtag-mm"; + reg = <0xfc332000 0x1000>, + <0xfc333000 0x1000>; + reg-names = "etm-base","debug-base"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/lpm-levels.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/lpm-levels.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec7f7ff08bd1e330492742c14328f4e7ec3339f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/lpm-levels.txt @@ -0,0 +1,282 @@ +* Low Power Management Levels + +The application processor in MSM can do a variety of C-States for low power +management. The LPM module performs the System low power modes based on +the latency/residency information of the individual CPUs and clusters. + +LPM-levels defines a hierarchy of low power modes that a cluster and +clusters/cpus within that cluster can enter. The bottom hierarchy level +represents the low power modes that a CPU can enter. The CPU low power nodes +are associated with a cluster that defines the low power modes that a cluster +can enter. For system involving a hierarchy of clusters, the cluster low power +modes can be contained within another cluster. + +[Top Level Node] +Required properties: + +- compatible: "qcom,lpm-levels" + +[Node bindings for qcom,pm-cluster] + Required properties: + - reg - The numeric cluster id + - label: Identifies the cluster name. The name is used when reporting + the stats for each low power mode. + - qcom,psci-mode-shift: The property is used to determine with bit + location of the cluster mode in the composite state ID used to define + cluster low power modes in PSCI. + - qcom,psci-mode-mask: The property is used to determine with bit + mask of the cluster mode in the composite state ID used to define + cluster low power modes in PSCI. + +Optional properties: + - qcom,disable-prediction: This property is used to indicate the LPM + governor will not use LPM prediction for this cluster. + - qcom,clstr-tmr-add: This property is used as correction timer for + wrong prediction by lpm prediction algorithm for cluster predictions. + This value should be between 100 to 1500. Higher values would mean + longer time staying in shallower state before waking up to select a + deeper state in case of wrong prediction. + qcom,pm-cluster contains qcom,pm-cluster-level nodes which identify + the various low power modes that the cluster can enter. The + qcom,pm-cluster node should also include another cluster node or a cpu + node that defines their respective low power modes. + +[Node bindings for qcom,pm-cluster-level] + Required properties: + - reg: The numeric cluster level id + - label: Name to identify the low power mode in stats + module. + - qcom,psci-mode: ID to be passed into the PSCI firmware. + - qcom,min-child-idx: The minimum level that a child CPU should be in + before this level can be chosen. This property is required for all + non-default level. + - qcom,entry-latency-us: The latency to enter LPM level, in uSec + - qcom,exit-latency-us: The latency to exit LPM level, in uSec + - qcom,min-residency-us: The minimum residency value from which entering + to low power mode is beneficial, in uSec + + Optional properties: + - qcom,notify-rpm: When set, the driver configures the sleep and wake + sets. It also configures the next wakeup time for APPS. + - qcom,is-reset: This boolean property tells whether cluster level need + power management notifications to be sent out or not for the drivers to + prepare for cluster collapse. + - qcom,reset-level: This property is used to determine in this + low power mode only control logic power collapse happens or memory + logic power collapse aswell happens or retention state. + The accepted values for this property are: + "LPM_RESET_LVL_NONE" - No power collapse + "LPM_RESET_LVL_RET" - Retention state + "LPM_RESET_LVL_GDHS" - Only control logic power collapse (GDHS) + "LPM_RESET_LVL_PC" - Control logic and memory logic + power collapse (PC) + +[Node bindings for qcom,pm-cpu] +qcom,pm-cpu contains the low power modes that a cpu could enter and the CPUs +that share the parameters.It contains the following properties. + - qcom,cpu: List of CPU phandles to identify the CPUs associated with + this cluster. + - qcom,psci-mode-shift: Same as cluster level fields. + - qcom,psci-mode-mask: Same as cluster level fields. + - qcom,pm-cpu-levels: The different low power modes that a CPU could + enter. The following section explains the required properties of this + node. + +Optional properties: + - qcom,disable-ipi-prediction: This property is used to indicate the + LPM governor to disable ipi based LPM prediction on CPUs. + - qcom,disable-prediction: This property is used to indicate the + LPM governor is to disable sleep prediction to this cpu. + - qcom,ref-stddev: This property is used as reference standard deviation + in lpm prediction algorithm. This value should be between 100 to 1000. + Higher value would result in more predictions and thereby resulting in + shallower low power modes. + - qcom,tmr-add: This property is used as correction timer for wrong + prediction by lpm prediction algorithm. This value should be between + 100 to 1500. Higher values would mean longer time staying in shallower + state before waking up to select a deeper state in case of wrong prediction. + - qcom,ref-premature-cnt: This property is used as reference premature + count to predict next sleep state by the prediction algorithm. This value + should be between 1 to 5. Higher value for this parameter would result in + less predictions to disallow deeper low power modes. + +[Node bindings for qcom,pm-cpu-levels] + Required properties: + - reg: The numeric cpu level id + - label: Name to identify the low power mode in stats + - qcom,psci-cpu-mode: ID to be passed into PSCI firmware. + - qcom,entry-latency-us: The latency to enter LPM level, in uSec + - qcom,exit-latency-us: The latency to exit LPM level, in uSec + - qcom,min-residency-us: The minimum residency value from which entering + to low power mode is beneficial, in uSec + + Optional properties: + - qcom,is-reset: This boolean property maps to "power state" bit in PSCI + state_id configuration. This property will tell whether CPU get reset for + a particular LPM or not. This property is also used to notify the drivers + in case of cpu reset. + - qcom,use-broadcast-timer: Indicates that the timer gets reset during + power collapse and the cpu relies on Broadcast timer for scheduled wakeups. + Required only for states where the CPUs internal timer state is lost. + +[Example dts] + + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "L3"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xfff>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "l3-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <48>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <99>; + }; + + qcom,pm-cluster-level@1 { /* D2 */ + reg = <1>; + label = "l3-dyn-ret"; + qcom,psci-mode = <0x2>; + qcom,entry-latency-us = <317>; + qcom,exit-latency-us = <659>; + qcom,min-residency-us = <4065>; + }; + + qcom,pm-cluster-level@2 { /* D4, D3 is not supported */ + reg = <2>; + label = "l3-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <814>; + qcom,exit-latency-us = <4562>; + qcom,min-residency-us = <7085>; + qcom,min-child-idx = <2>; + qcom,is-reset; + }; + + qcom,pm-cluster-level@3 { /* Cx off */ + reg = <3>; + label = "cx-off"; + qcom,psci-mode = <0x224>; + qcom,entry-latency-us = <814>; + qcom,exit-latency-us = <5562>; + qcom,min-residency-us = <9987>; + qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cluster-level@4 { /* LLCC off, AOSS sleep */ + reg = <4>; + label = "llcc-off"; + qcom,psci-mode = <0xC24>; + qcom,entry-latency-us = <814>; + qcom,exit-latency-us = <6562>; + qcom,min-residency-us = <10100>; + qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <40>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <100>; + }; + + qcom,pm-cpu-level@1 { /* C2D */ + reg = <1>; + label = "ret"; + qcom,psci-cpu-mode = <0x2>; + qcom,entry-latency-us = <81>; + qcom,exit-latency-us = <86>; + qcom,min-residency-us = <965>; + }; + + qcom,pm-cpu-level@2 { /* C3 */ + reg = <2>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <273>; + qcom,exit-latency-us = <612>; + qcom,min-residency-us = <1890>; + qcom,is-reset; + }; + + qcom,pm-cpu-level@3 { /* C4 */ + reg = <3>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <300>; + qcom,exit-latency-us = <700>; + qcom,min-residency-us = <3934>; + qcom,is-reset; + }; + }; + + qcom,pm-cpu@1 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <40>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <83>; + }; + + qcom,pm-cpu-level@1 { /* C2D */ + reg = <1>; + label = "ret"; + qcom,psci-cpu-mode = <0x2>; + qcom,entry-latency-us = <81>; + qcom,exit-latency-us = <86>; + qcom,min-residency-us = <637>; + }; + + qcom,pm-cpu-level@2 { /* C3 */ + reg = <2>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <273>; + qcom,exit-latency-us = <612>; + qcom,min-residency-us = <952>; + qcom,is-reset; + }; + + qcom,pm-cpu-level@3 { /* C4 */ + reg = <3>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <300>; + qcom,exit-latency-us = <700>; + qcom,min-residency-us = <4488>; + qcom,is-reset; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/mdm-modem.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/mdm-modem.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d99458164104ca0b6b6e435e6bbb8693727b791 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/mdm-modem.txt @@ -0,0 +1,166 @@ +Attached MDM Modem Devices + +External modems are devices that are attached to the msm and controlled by gpios. +There is also a data channel between the msm and the external modem that sometimes needs +to be reset. + +Required Properties: +- compatible: The bus devices need to be compatible with + "qcom,ext-mdm9x55", "qcom,ext-sdx50m", "qcom,ext-sdx55m". + +Required named gpio properties: +- qcom,mdm2ap-errfatal-gpio: gpio for the external modem to indicate to the apps processor + of an error fatal condition on the modem. +- qcom,ap2mdm-errfatal-gpio: gpio for the apps processor to indicate to the external modem + of an error fatal condition on the apps processor. +- qcom,mdm2ap-status-gpio: gpio to indicate to the apps processor when there is a watchdog + bite on the external modem. +- qcom,ap2mdm-status-gpio: gpio for the apps processor to indicate to the modem that an apps + processor watchdog bite has occurred. +- qcom,ap2mdm-soft-reset-gpio: gpio for the apps processor to use to soft-reset the external + modem. If the flags parameter has a value of 0x1 then the gpio is active LOW. + +Required Interrupts: +- "err_fatal_irq": Interrupt generated on the apps processor when the error fatal gpio is pulled + high by the external modem. +- "status_irq": Interrupt generated on the apps processor when the mdm2ap-status gpio falls low + on the external modem. This usually indicates a watchdog bite on the modem. +- "plbrdy_irq": Interrupt generated on the aps processor when the mdm2ap-pblrdy gpio is pulled + either high or low by the external modem. This is an indication that the modem + has rebooted. +- "mdm2ap_vddmin_irq": Interrupt generated on the apps processor when the external modem goes + into vddmin power state. + +Optional named gpio properties: +- qcom,mdm2ap-pblrdy-gpio: gpio used by some external modems to indicate when the modem has + booted into the PBL bootloader. +- qcom,ap2mdm-wakeup-gpio: gpio used by the apps processor to wake the external modem + out of a low power state. +- qcom,ap2mdm-chnl-rdy-gpio: gpio used by the apps processor to inform the external modem + that data link is ready. +- qcom,mdm2ap-wakeup-gpio: gpio from the external modem to the apps processor to wake it + out of a low power state. +- qcom,ap2mdm-vddmin-gpio: gpio to indicate to the external modem when the apps processor + is about to enter vddmin power state. +- qcom,mdm2ap-vddmin-gpio: gpio used by the external modem to inform the apps processor + when it is about to enter vddmin power state. +- qcom,ap2mdm-kpdpwr-gpio: gpio used to simulate a power button press on the external + modem. Some modems use this as part of their initial power-up sequence. + If the "flags" parameter has a value of 0x1 then it is active LOW. +- qcom,ap2mdm-pmic-pwr-en-gpio: Some modems need this gpio for the apps processor to enable + the pmic on the external modem. +- qcom,use-usb-port-gpio: some modems use this gpio to switch a port connection from uart to usb. + This is used during firmware upgrade of some modems. +- qcom,mdm-link-detect-gpio: some modems may support two interfaces. This gpio + indicates whether only one or both links can be used. + +Optional driver parameters: +- qcom,ramdump-delay-ms: time in milliseconds to wait before starting to collect ramdumps. + This interval is the time to wait after an error on the external modem is + signaled to the apps processor before starting to collect ramdumps. Its + value depends on the type of external modem (e.g. MDM vs QSC), and how + error fatal handing is done on the modem. + The default value is 2 seconds (2000 milliseconds) as specified by the + mdm9x15 software developer. Consultation with the developer of the modem + software is required to determine this value for that modem. +- qcom,ps-hold-delay-ms: minimum delay in milliseconds between consecutive PS_HOLD toggles. + SGLTE targets that use a QSC1215 modem require a minimum delay between consecutive + toggling of the PS_HOLD pmic input. For one target it is 500 milliseconds but it + may vary depending on the target and how the external modem is connected. The value + is specified by the hardware designers. +- qcom,early-power-on: boolean flag to indicate if to power on the modem when the device is probed. +- qcom,sfr-query: boolean flag to indicate if to query the modem for a reset reason. +- qcom,no-powerdown-after-ramdumps: boolean flag to indicate if to power down the modem after ramdumps. +- qcom,no-a2m-errfatal-on-ssr: boolean to tell driver not to raise ap2mdm errfatal during SSR. +- qcom,no-reset-on-first-powerup: boolean to tell driver not to reset the modem when first + powering up the modem. +- qcom,ramdump-timeout-ms: ramdump timeout interval in milliseconds. + This interval is the time to wait for collection of the external modem's ramdump + to complete. It's value depends on the speed of the data connection between the + external modem and the apps processor on the platform. If the connection is a + UART port then this delay needs to be longer in order to avoid premature timeout + of the ramdump collection. + The default value is 2 minutes (120000 milliseconds) which is based on the + measured time it takes over a UART connection. It is reduced when the data + connection is an HSIC port. The value is usually tuned empirically for a + particular target. +- qcom,image-upgrade-supported: boolean flag to indicate if software upgrade is supported. +- qcom,support-shutdown: boolean flag to indicate if graceful shutdown is supported. +- qcom,vddmin-drive-strength: drive strength in milliamps of the ap2mdm-vddmin gpio. + The ap2mdm_vddmin gpio is controlled by the RPM processor. It is pulled low + to indicate to the external modem that the apps processor has entered vddmin + state, and high to indicate the reverse. Its parameters are passed to the RPM + software from the HLOS because the RPM software has to way of saving this type + of configuration when an external modem is attached. + The value of the drive strength is specified by the hardware designers. A value + of 8 milliamps is typical. + This property is ignored if the property "qcom,ap2mdm-vddmin-gpio" is + not set. +- qcom,vddmin-modes: a string indicating the "modes" requested for the ap2mdm-vddmin gpio. + This value is passed to RPM and is used by the RPM module to determine the + gpio mux function. The only currently supported modes string is "normal" and + corresponds to the value 0x03 that is passed to RPM. +- qcom,restart-group: List of subsystems that will need to restart together. +- qcom,mdm-dual-link: Boolean indicates whether both links can used for + communication. +- qcom,ssctl-instance-id: Instance id used by the subsystem to connect with the SSCTL service. +- qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem. +- qcom,pil-force-shutdown: Boolean. If set, the SSR framework will not trigger graceful shutdown + on behalf of the subsystem driver. +- qcom,mdm-link-info: a string indicating additional info about the physical link. + For example: "devID_domain.bus.slot" in case of PCIe. +- qcom,mdm-auto-boot: Boolean. To indicate this instance of esoc boots independently. +- qcom,mdm-statusline-not-a-powersource: Boolean. If set, status line to esoc device is not a + power source. +- qcom,mdm-userspace-handle-shutdown: Boolean. If set, userspace handles shutdown requests. +- qcom,shutdown-timeout-ms: graceful shutdown timeout in milliseconds. + This interval is the time needed for the external modem to gracefully shutdown + after the host sends a shutdown command. The value depends on how long it takes + for the high level OS in the external modem to shutdown gracefully. The default + value is 10000 milliseconds. +- qcom,reset-time-ms: time it takes for the external modem to forcefully reset in milliseconds. + This interval is the time it takes to toggle the reset of an external modem by + holding down the reset pin. The value depends on the external modem's power + management boot options. The default value is 203 milliseconds. +- qcom,esoc-skip-restart-for-mdm-crash: Boolean. If set, the esoc framework would skip the warm + reboot phase during the momem crash. +- qcom,esoc-spmi-soft-reset: Boolean. If set, esoc framework will use qpnp apis to reset the + external modem chip instead of toggling gpios. + +Example: + mdm0: qcom,mdm0 { + compatible = "qcom,mdm2-modem"; + cell-index = <0>; + #address-cells = <0>; + interrupt-parent = <&mdm0>; + interrupts = <0 1 2 3>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = + <0 &msmgpio 82 0x3 + 1 &msmgpio 46 0x3 + 2 &msmgpio 80 0x3 + 3 &msmgpio 27 0x3>; + interrupt-names = + "err_fatal_irq", + "status_irq", + "plbrdy_irq", + "mdm2ap_vddmin_irq"; + + qcom,mdm2ap-errfatal-gpio = <&msmgpio 82 0x00>; + qcom,ap2mdm-errfatal-gpio = <&msmgpio 106 0x00>; + qcom,mdm2ap-status-gpio = <&msmgpio 46 0x00>; + qcom,ap2mdm-status-gpio = <&msmgpio 105 0x00>; + qcom,ap2mdm-soft-reset-gpio = <&msmgpio 24 0x00>; + qcom,mdm2ap-pblrdy-gpio = <&msmgpio 80 0x00>; + qcom,ap2mdm-wakeup-gpio = <&msmgpio 104 0x00>; + qcom,ap2mdm-vddmin-gpio = <&msmgpio 108 0x00>; + qcom,mdm2ap-vddmin-gpio = <&msmgpio 27 0x00>; + + qcom,ramdump-delay-ms = <2000>; + qcom,ramdump-timeout-ms = <120000>; + qcom,vddmin-modes = "normal"; + qcom,vddmin-drive-strength = <8>; + qcom,ssctl-instance-id = <10>; + qcom,sysmon-id = <20>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/memory-offline.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/memory-offline.txt new file mode 100644 index 0000000000000000000000000000000000000000..f57242b42c5247cba771a6407c54733e2c4d2806 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/memory-offline.txt @@ -0,0 +1,51 @@ +Memory offline driver +===================== + +The memory offline driver supports the onlining and offlining of DDR memory. +Through the mem-offline node you can configure how much of the DDR will +support being offlined/onlined. +By default all memory is onlined when the device has booted up. + +Note that offlinable memory can only support 'movable' memory allocations so +designating too much memory as offlinable can result in system performance and +stability issues. + +For more information on how to request the onlining and offlining of memory +see the memory hotplug documentation (Documentation/memory-hotplug.txt). + +Required properties: +- compatible: "qcom,mem-offline" +- granule: The minimum granule size in mega-bytes for memory onlining/offlining. +- offline-sizes: Array of offlinable memory region sizes to apply to targets + based on their DDR size. + + Each entry in the array is a pair of sizes, where the first size in the + pair is the minimum amount of DDR required in the system in bytes, and + the second item in the pair is the size of the offlinable region in + bytes which will be applied to the system. + + The offlinable memory region size from the entry where the minimum amount + of DDR required in the system is closest, but not greater, than the + amount of DDR in the system will be applied. + If there are no entries with a minimum amount of DDR required that is less + than the amount of DDR in the system then no offlinable region will be + created. + + For example, in the following configuration: + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>; + On a 4GB target no offlinable region will be created. + On a 6GB target a 1GB offlinable region will be created. + On an 8GB target a 2GB offlinable region will be created. + On a 12GB target a 2GB offlinable region will be created. +- mboxes: Reference to the mailbox used by the driver to make requests to + online/offline memory. + +Example: + mem-offline { + compatible = "qcom,mem-offline"; + granule = <512>; + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>; + mboxes = <&qmp_aop 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/mpm_counter.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/mpm_counter.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab0d3a0a48a15b0935b2fb6ff40ce294cc06b7bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/mpm_counter.txt @@ -0,0 +1,18 @@ +* MSM MPM sleep counter (mpm-v2) + +The MPM provides a timetick that starts when the device is powered up and +is not reset by any of the boot loaders or the HLOS. The MPM timetick counter +driver provides an api to get this value. + +The required nodes for the MPM timetick counter driver are: + +- compatible: "qcom,mpm2-sleep-counter" +- reg: Specifies the physical address of the timetick count register. +- clock-frequency: the physical counter frequency. + +Example: + qcom,mpm2-sleep-counter@4a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x4a3000 0x1000>; + clock-frequency = <32768>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm-id.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm-id.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2431541a144ac8097796d378d35a0e9fc0524bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm-id.txt @@ -0,0 +1,33 @@ +* MSM-ID + +The qcom,msm-id entry specifies the MSM chipset, platform, hardware revision +and optional manufactured foundry. It can optionally be an array of these to +indicate multiple hardware that use the same device tree. It is expected that +the bootloader will use this information at boot-up to decide which device tree +to use when given multiple device trees, some of which may not be compatible +with the actual hardware. It is the bootloader's responsibility to pass the +correct device tree to the kernel. + +Format: + +It is expected that the qcom,msm-id entry be at the top level of the device +tree structure. The format can take one of the two forms below: + + qcom,msm-id = [, ...] + qcom,msm-id = [, ...] + +If the second format is used one must also define the board-id. + +The "chipset_foundry_id" consists of three fields as below: + + bits 0-15 = The unique MSM chipset id. + bits 16-23 = The optional foundry id. If bootloader doesn't find a device + tree which has exact matching foundry-id with hardware it + chooses the device tree with foundry-id = 0. + bits 24-31 = Reserved. + +Example: + qcom,msm-id = <0x1007e 15 0>; + + qcom,board-id= <15 2>; + qcom,msm-id = <0x1007e 0>; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm.txt new file mode 100644 index 0000000000000000000000000000000000000000..d20166fb4be0be7c15777e3ddf68d9ec60ed8cd0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm.txt @@ -0,0 +1,249 @@ +* Qualcomm Technologies, Inc. MSM + +MSM uses a combination of DTS and DTSI files to describe the hardware on various +SoCs and boards. Typically, a SoC-specific DTSI file describes the devices +present on a given SoC, and a board-specific DTSI file describes the devices +external to the SoC, although some targets may follow a more simplified +approach. Additionally, the SoC-specific DTSI files may further consist of a +base chip-specific file and a version-specific DTSI file, to facilitate reuse +of device definitions among multiple revisions of the same SoC. + +Required properties: +- compatible: Every device present on the MSM SoC shall have a 'qcom,' prefix + in its compatible string + +Example: +restart@fc4ab000 { + compatible = "qcom,pshold"; + reg = <0xfc4ab000 0x4>; +}; + + +* Compatible strings: + +SoCs: + +- APQ8016 + compatible = "qcom,apq8016" + +- APQ8084 + compatible = "qcom,apq8084" + +- APQ8096 + compatible = "qcom,apq8096" + +- MSM8916 + compatible = "qcom,msm8916" + +- MSM8960 + compatible = "qcom,msm8960" + +- MSM8996 + compatible = "qcom,msm8996" + +- SM8150 + compatible = "qcom,sm8150" + +- KONA + compatible = "qcom,kona" + +- LITO + compatible = "qcom,lito" + +- ORCHID + compatible = "qcom,orchid" + +- LAGOON + compatible = "qcom,lagoon" + +- BENGAL + compatible = "qcom,bengal" + +- SCUBA + compatible = "qcom,scuba" + +- SCUBAIOT + compatible = "qcom,scuba-iot" + +- SCUBAPIOT + compatible = "qcom,scubap-iot" + +- SDMSHRIKE + compatible = "qcom,sdmshrike" + +- SM6150 + compatible = "qcom,sm6150" + +- QCS405 + compatible = "qcom,qcs405" + +- QCS403 + compatible = "qcom,qcs403" + +- SDXPRAIRIE + compatible = "qcom,sdxprairie" + +- SDMMAGPIE + compatible = "qcom,sdmmagpie" + +- SDM660 + compatible = "qcom,sdm660" + +- SDA660 + compatible = "qcom,sda660" + +- BENGAL_IOT + compatible = "qcom,bengal-iot" + +- BENGALP-IOT + compatible = "qcom,bengalp-iot" + +Generic board variants: + +- CDP device: + compatible = "qcom,cdp" + +- IDP device: + compatible = "qcom,idp" + +- MTP device: + compatible = "qcom,mtp" + +- ATP device: + compatible = "qcom,atp" + +- FLUID device: + compatible = "qcom,fluid" + +- LIQUID device: + compatible = "qcom,liquid" + +- Dragonboard device: + compatible = "qcom,dragonboard" + +- SBC device: + compatible = "qcom,sbc" + +- SURF device: + compatible = "qcom,surf" + +- QRD device: + compatible = "qcom,qrd" + +- HDK device: + compatible = "qcom,hdk" + +- ADP device: + compatible = "qcom,adp" + +- Simulator device: + compatible = "qcom,sim" + +- RUMI device: + compatible = "qcom,rumi" + +- IOT device: + compatible = "qcom,iot" + + +Boards (SoC type + board variant): + +compatible = "qcom,apq8016" +compatible = "qcom,apq8084-cdp" +compatible = "qcom,apq8084-liquid" +compatible = "qcom,apq8084-mtp" +compatible = "qcom,apq8084-sbc" +compatible = "qcom,apq8094-cdp" +compatible = "qcom,apq8096-cdp" +compatible = "qcom,apq8096-mtp" +compatible = "qcom,apq8096-dragonboard" +compatible = "qcom,apq8096-sbc" +compatible = "qcom,apq8096-liquid" +compatible = "qcom,msm8916-cdp" +compatible = "qcom,msm8916-mtp" +compatible = "qcom,msm8916-qrd-skuh" +compatible = "qcom,msm8916-qrd-skuhf" +compatible = "qcom,msm8916-qrd-skui" +compatible = "qcom,msm8916-qrd-skuic" +compatible = "qcom,msm8916-qrd-skuid" +compatible = "qcom,msm8916-qrd-skut1" +compatible = "qcom,msm8916-rumi" +compatible = "qcom,msm8916-sim" +compatible = "qcom,msm8960-cdp" +compatible = "qcom,msm8974-cdp" +compatible = "qcom,msm8974-fluid" +compatible = "qcom,msm8974-liquid" +compatible = "qcom,msm8974-mtp" +compatible = "qcom,msm8974-rumi" +compatible = "qcom,msm8974-sim" +compatible = "qcom,msm8996-rumi" +compatible = "qcom,msm8996-sim" +compatible = "qcom,msm8996-cdp" +compatible = "qcom,msm8996-dtp" +compatible = "qcom,msm8996-fluid" +compatible = "qcom,msm8996-liquid" +compatible = "qcom,msm8996-mtp" +compatible = "qcom,msm8996-adp" +compatible = "qcom,sm8150-rumi" +compatible = "qcom,sm8150-mtp" +compatible = "qcom,sm8150-cdp" +compatible = "qcom,sm8150-qrd" +compatible = "qcom,sm8150p-cdp" +compatible = "qcom,sm8150p-mtp" +compatible = "qcom,sm8150p-qrd" +compatible = "qcom,kona-rumi" +compatible = "qcom,kona-mtp" +compatible = "qcom,kona-cdp" +compatible = "qcom,kona-qrd" +compatible = "qcom,kona-hdk" +compatible = "qcom,kona-iot" +compatible = "qcom,lito-rumi" +compatible = "qcom,lito-mtp" +compatible = "qcom,lito-cdp" +compatible = "qcom,lito-atp" +compatible = "qcom,lito-qrd" +compatible = "qcom,orchid-mtp" +compatible = "qcom,orchid-cdp" +compatible = "qcom,lagoon-rumi" +compatible = "qcom,lagoon-mtp" +compatible = "qcom,lagoon-cdp" +compatible = "qcom,lagoon-atp" +compatible = "qcom,lagoon-qrd" +compatible = "qcom,bengal-rumi" +compatible = "qcom,bengal-qrd" +compatible = "qcom,bengal-idp" +compatible = "qcom,bengalp" +compatible = "qcom,bengalp-idp" +compatible = "qcom,scuba-rumi" +compatible = "qcom,scuba-idp" +compatible = "qcom,scuba-qrd" +compatible = "qcom,sdmshrike-rumi" +compatible = "qcom,sdmshrike-mtp" +compatible = "qcom,sdmshrike-cdp" +compatible = "qcom,sm6150-rumi" +compatible = "qcom,sm6150-mtp" +compatible = "qcom,sm6150-cdp" +compatible = "qcom,sm6150-qrd" +compatible = "qcom,sm6150-idp" +compatible = "qcom,qcs405-rumi" +compatible = "qcom,qcs405-iot" +compatible = "qcom,qcs403-iot" +compatible = "qcom,sa8150-adp-star" +compatible = "qcom,adp-star" +compatible = "qcom,sdxprairie-rumi" +compatible = "qcom,sdxprairie-mtp" +compatible = "qcom,sdxprairie-cdp" +compatible = "qcom,sdmmagpie-rumi" +compatible = "qcom,sdmmagpie-idp" +compatible = "qcom,sdmmagpie-qrd" +compatible = "qcom,sdm660-cdp" +compatible = "qcom,sdm660-mtp" +compatible = "qcom,sdm660-qrd" +compatible = "qcom,sdm660-sim" +compatible = "qcom,sda660-mtp" +compatible = "qcom,sda660-cdp" +compatible = "qcom,sda660-qrd" +compatible = "qcom,bengal-iot" +compatible = "qcom,bengalp-iot" +compatible = "qcom,bengal-iot-idp" +compatible = "qcom,bengalp-iot-idp" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c23b4b7d8e3d35cf674042af2c2e0a495621180 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus.txt @@ -0,0 +1,270 @@ +MSM Bus Devices + +The bus devices (fabrics/NoCs) are the interconnects between various +components on chipsets. These devices form the backbone of the chip +topology. Entire topology of the chipset is built using the +device-tree data of these bus devices. + +To add the bus devices following properties are required: + +compatible: The bus devices need to be compatible with + msm-bus-fabric +cell-id: A 32 bit integer unique per bus per chipset. The IDs + for buses are in multiples of 1024. +label: Bus name +qcom,fabclk-dual: Dual set (active/sleep) bus clock name +qcom,fabclk-active: Active set bus clock name +qcom,nfab: An integer property which specifies the total number + of buses on the chipset. + +The following properties are optional as a bus might not support +these features: + +qcom,ntieredslaves: Number of tiered slaves on the bus. +qcom,qos-freq: QoS frequency (In KHz) +qcom,hw-sel: A string which decides whether QoS data + should be sent to RPM, set using BIMC or NoCs. + It can be set to "RPM", "NoC" or "BIMC". +qcom,qos-baseoffset: Base address offset of QoS registers from the bus device + base address. +qcom,qos-delta: Address delta between QoS registers of different masters. +qcom,rpm-en: A boolean flag indicating whether RPM transactions are + supported for nodes of the bus. +qcom,ahb: A boolean flag indicating whether the bus is ahb type. +qcom,virt: A boolean property indicating this is a virtual bus. +reg: Register space of the bus device. Not required in case + the bus is virtual. +qom,nr-lim-thresh The threshold below which to apply throttling of non + real time masters. +qcom,eff-fact The DDR effeciency factor to be assumed. This only + comes into play for buses that connect to the DDR. + + +The following properties are optional as collecting data via coresight might +not be supported for every bus. The documentation for coresight properties +can be found in: +Documentation/devicetree/bindings/coresight/coresight.txt + +coreisght-id Unique integer identifier for the bus. +coresight-name Unique descriptive name of the bus. +coresight-nr-inports Number of input ports on the bus. +coresight-outports List of output port numbers on the bus. +coresight-child-list List of phandles pointing to the children of this + component. +coresight-child-ports List of input port numbers of the children. + + +Any interconnect on the bus is represented as a child node. +A child node can be of type: master, slave or a gateway. +A gateway is an interconnect between buses and can be of both +master and slave type. + +The following properties are available to characterize a child node. +The properties can be chosen depending on the type of child node. + +cell-id: For a master the ID is between 0 - 512 + For a slave the ID is between 512 - 1024 +label: Name of the master/slave/gateway +qcom,masterp: Hardware master port number(s) +qcom,tier: The tier to which a master/slave belongs. + Note that tiering might not be supported on + all architectures. +qcom,hw-sel: A string which decides whether QoS data should be sent + to RPM, set using BIMC or NoCs. + It can be set to "RPM", "NoC" or "BIMC". +qcom,mode: Used for masters on NoC/BIMC. Indicates which of the + four modes (Fixed/Limiter/Bypass/Regulator) the master + belongs to. +qcom,perm-mode: Permissible mode switches. Indicates which of the four + modes are supported of the master node. Generally, + modes are set at boot-up and not switched at run-time. +qcom,qport: QoS port number. This can be different from the + master-port number. +qcom,ws: Window size (in Hz), used for NoC/BIMC masters to + calculate saturation values. +qcom,mas-hw-id: A unique hardware ID agreed upon by processors across + the system. This ID is assigned to every master. It can + be used to send master specific data from + Apps/Modem/LPASS to RPM. +qcom,slv-hw-id: A unique hardware ID agreed upon by processors across + the system. This ID is assigned to every slave. It can + be used to send slave specific data from +qcom,slaveclk-dual: Dual set (active/sleep) slave clock name +qcom,slaveclk-active: Active set slave clock name + Apps/Modem/LPASS to RPM. +qcom,gateway: Flag indicating whether a particular node is a gateway. +qcom,slavep: Hardware slave port number(s). +qcom,buswidth: Width of the interconnect between a node and the bus. + (In Bytes). +qcom,prio-rd: Read priority for a BIMC bus master (Can be 0/1/2) +qcom,prio-wr: Write priority for a BIMC bus master (Can be 0/1/2) +qcom,prio0: Priority low signal for a NoC bus master + (Can be 0/1/2). +qcom,prio1: Priority high signal for a NoC bus master + (Can be 0/1/2) +qcom,dual-conf: Indicates whether a BIMC/NoC master can be configured + in multiple modes at run-time. (Boolean) +qcom,mode-thresh: Threshold mode for a BIMC/NoC master. Beyond a certain + threshold frequency, a threshold mode can be used. + (Can be Fixed/Limiter/Bypass/Regulator) +qcom,bimc,bw: Bandwidth limit for a BIMC master using dual modes. + This bandwidth is used to calculate Grant count and + other parameters used in Limiter and Regular mode. + for static BKE configuration. It is defined in KBytes/s. +qcom,bimc,gp: Grant Period for configuring a master in limiter + mode. This is an integer value in nano-seconds. +qcom,bimc,thmp: Medium threshold percentage for BIMC masters. + This percentage is used to calculate medium threshold + value for BIMC Masters in Limiter mode for static + configuration. This can be any integer value between + 1 and 100. +qcom,thresh: Beyond this threshold frequency, the mode usage is + switched from mode specified by property qcom,mode + to the one specified by qcom,mode-thresh. These thresholds + can be setup in increasing order of thresholds, so the + requested IB is evaluated at each threshold level before + making the decision to switch QoS modes and applying the + corresponding qcom,bimc,bw limitig bw as needed. + This is specified in KBytes/s. +qcom,rt-mas: Indicates if a master node is a realtime master with + hard deadlines. +qcom,nr-lim: Indicates that this is non-real time master which can + be throttled in case of concurrent scenarios. +qcom,floor-bw: Represents the floor bandwidth below which this master + cannot be throttled. This floor bandwidth is specified in + KBytes/s. +qcom,ff: The fudge factor used by clients when voting for + bandwidth from the node. +qcom,bcm-name: The name used to fetch details about the bcm device from + the command DB driver. +qcom,drv-id: The DRV id associated with the RSC, used to differentiate + between RSCS owned by different execution environments. +qcom,defer-init-qos: Flag to force defer initial QoS configuration at probe time. +qcom,sbm-offset: The offset used to determine location of Sideband + Manager used in the disconnect mechanism when clients + remove bandwidth votes. +qcom,disable-ports: The ports to disable on the sideband manager when the + requirement bandwidth affecting the node reduces to 0. +node-reg-names: Names of the regulator associated with bus node used + to grab the phandle of the regulator. + +Example: + + + msm-mmss-noc@fc478000 { + compatible = "msm-bus-fabric"; + reg = <0xfc478000 0x00004000>; + cell-id = <2048>; + label = "msm_mmss_noc"; + qcom,fabclk-dual = "bus_clk"; + qcom,fabclk-active = "bus_a_clk"; + qcom,ntieredslaves = <0>; + qcom,qos-freq = <4800>; + qcom,hw-sel = "NoC"; + qcom,rpm-en; + qcom,nfab = <6>; + qcom,sbm-offset = <20000>; + + mas-gfx3d { + cell-id = <26>; + label = "mas-gfx3d"; + qcom,masterp = <2 3>; + qcom,tier = <2>; + qcom,hw-sel = "NoC"; + qcom,perm-mode = "Bypass"; + qcom,mode = "Bypass"; + qcom,ws = <10000>; + qcom,qport = <2 3>; + qcom,mas-hw-id = <6>; + qcom,disable-ports = <1 2>; + }; + + mas-jpeg { + cell-id = <62>; + label = "mas-jpeg"; + qcom,masterp = <4>; + qcom,tier = <2>; + qcom,hw-sel = "NoC"; + qcom,perm-mode = "Bypass"; + qcom,mode = "Bypass"; + qcom,qport = <0>; + qcom,ws = <10000>; + qcom,mas-hw-id = <7>; + }; + }; + + msm-bimc@0xfc380000 { + compatible = "msm-bus-fabric"; + reg = <0xfc380000 0x0006A000>; + cell-id = <0>; + label = "msm_bimc"; + qcom,fabclk-dual = "mem_clk"; + qcom,fabclk-active = "mem_a_clk"; + qcom,ntieredslaves = <0>; + qcom,qos-freq = <19200>; + qcom,hw-sel = "BIMC"; + qcom,rpm-en; + + coresight-id = <55>; + coresight-name = "coresight-bimc"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in1>; + coresight-child-ports = <3>; + + mas-ampss-m0 { + cell-id = <1>; + label = "mas-ampss-m0"; + qcom,masterp = <0>; + qcom,tier = <2>; + qcom,hw-sel = "BIMC"; + qcom,mode = "Limiter"; + qcom,qport = <0>; + qcom,ws = <10000>; + qcom,mas-hw-id = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,mode-thresh = "Fixed"; + qcom,thresh = <2000000>; + qcom,dual-conf; + qcom,bimc,bw = <300000>; + qcom,bimc,gp = <5>; + qcom,bimc,thmp = <50>; + }; + }; + + + + +The bus scaling driver also provides the ability to configure +bus performance parameters across the entire chip-set. +Various clients use MSM scaling APIs to request bandwidth +between multiple master-slave pairs. The bus driver then finds +the optimal path between the master and the slave, and aggregates +the bandwidth and clock requests for all master-slave pairs on +that path, and programs hardware accordingly. + +The device-tree data required for bus-scaling can be embedded within +the clients' device nodes. The clients can register with the bus driver +using the following properties: + +- qcom,msm-bus,name: String representing the client-name +- qcom,msm-bus,num-cases: Total number of usecases +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex +- qcom,msm-bus,num-paths: Total number of master-slave pairs +- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing: + master-id, slave-id, arbitrated bandwidth + in KBps, instantaneous bandwidth in KBps + +Example: + + qcom,msm-bus,name = "client-name"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors = + <22 512 0 0>, <26 512 0 0>, + <22 512 320000 3200000>, <26 512 3200000 3200000>, + <22 512 160000 1600000>, <26 512 1600000 1600000>; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus_adhoc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus_adhoc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a4778ef71b53eeeb693b4fa400dabd51c4138b43 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus_adhoc.txt @@ -0,0 +1,270 @@ +MSM Bus Devices for adhoc bus topologies + +Buses are the interconnects between various devices. The devices are +connected in different topologies. The bus scaling driver accepts +bandwidth requests from clients and ensures that the bandwidth requests +can be met between the source and destination for that client. +In order to accept and honor bandwidth requests the bus scaling driver +needs to know about the bus topology. +This device tree binding represents the bus devices in the SOC, their +connections to other bus devices and the resources associated with each +node. The bus scaling driver uses this device tree to setup the bus +topology in order to apply client bandwidth requests. + +The mandatory properties for bus driver are: + +compatible: "qcom,msm-bus-device" +compatible: "qcom,msm-bus-rsc" + +The register space associated with the bus devices are represented with +the following optional properties: +reg: Register space for a bus device. +reg-name: Name of the register space for the bus device. + +The child nodes represent the devices on the bus. + +The following properties are mandatory for a child node + +cell-id: The unique device id of the child node. + For a master the ID is between 0 - 512 + For a slave the ID is between 512 - 1024 + For internal nodes the range is > 10000 + The range of ids for the different types of child + devices are chosen for convenience, the only + requirement is that the id's be unique among the + child devices. +label: Unique name of the device. + +The following are optional properties for child nodes: + + +qcom,fab-dev: Optional boolean parameter that states if the device + is a fabric device or not. + Typically these optional properties are used for + devices that represent fabric devices. +qcom,bypass-qos-prg: Optional debug parameter to avoid programming the QoS + HW registers for a given fabric device. + Typically these optional properties are used for + devices that represent fabric devices. +qcom,base-name: Parameter that specifies the physical base address for + accessing registers associated with the child device. + Typically these optional properties are used for + devices that represent fabric devices. +qcom,base-offset: Parameter that gives the offset from the base address to access + the QoS registers. + Typically these optional properties are used for + devices that represent fabric devices. +qcom,qos-off: Parameter that represents the delta between QoS register address + space for different devices. + Typically these optional properties are used for + devices that represent fabric devices. +qcom,agg-scheme: Parameter that represents the aggregation scheme to be used for the + node. This parameter defaults to LEGACY scheme. The valid options + are LEGACY/SCHEME_1. +qcom,util-fact: Parameter that represents the DDR utilization factor to be used in + LEGACY scheme. It is represented as actual util-factor * 100. +qcom,vrail-comp: Parameter that represents the voltage rail compensation to push + the bus to the next level if needed in LEGACY and SCHEME 1 aggregation + schemes. It is represented as actual vrail-comp * 100. +qcom,util-levels: Array of tuples that represent a bandwidth threshold and util factor + to be used uptil the given threshold. +qcom,bus-type: Parameter that represents the bus type such as BIMC or NOC. + Typically these optional properties are used for + devices that represent fabric devices. +bus-gdsc-supply: Optional fabric device parameter that is a reference to the dual + context GDSC supply that is needed before clock operations. +bus-a-gdsc-supply: Optional fabric device parameter that is a reference to an active + only context GDSC supply that is needed before clock operations. +bus-qos-gdsc-supply: Optional node or fabric device parameter that is a reference to a GDSC + supply that is needed before use of the clock needed to program + QoS registers. +node-gdsc-supply: Optional node device parameter that is a reference to a GDSC supply + that is needed before node-clock operations. +qcom,enable-only-clk: Optional property that is represents if the clock doesn't support + the clk_set_rate API and should only be enabled/disabled. +qcom,setrate-only-clk: Optional property that is indicates that bus driver should only + set a rate on a clock handle and not call the enable/disable + clock API. +clock-names: Optional property that represents the clock name associated + with the device "bus_clk", "bus_a_clk"; +clocks: Property pair that represents the clock controller and the clock + id. This in combimination with the clock-name is used to obtain + the handle for the clock associated with this device. +qcom,virt-dev: Parameter used for devices that represent virtual devices. Virtual + devices aren't real devices on the SOC but are used to aggregate + resources in some special cases. +qcom,qport: The offset index into the masters QoS register space. +qcom,num-ports: The number of ports that the device has. +qcom,ap-owned: Property that states if the device is "owned" by the Apps processor. + If true then the AP will program the QoS registers for the device + else it is done by RPM. +qcom,connections: An array of phandles that represent the devices this device is connected to.; +qcom,bus-dev: Phandle that represents the fabric device that this child node belongs to. +qcom,qos-mode: QoS mode to be programmed for this device, only applicable for AP owned resource. +qcom,prio-rd: Read priority for a BIMC bus master (Can be 0/1/2) +qcom,prio-wr: Write priority for a BIMC bus master (Can be 0/1/2) +qcom,prio0: Priority low signal for a NoC bus master + (Can be 0/1/2). +qcom,reg-prio1: Regulator mode Priority high signal for a NoC bus master if the master port is in + regulator QoS mode +qcom,reg-prio0: Regulator Priority low signal for a NoC bus master if the master port is in + regulator Qos mode. + (Can be 0/1/2). +qcom,prio1: Priority high signal for a NoC bus master +qcom,bw_buffer: Optional parameter in KBytes used to specify a buffer value that should be added to + the voted bandwidth value to figure out the limiting bandwidth for a master port. +qcom,buswidth: The buswidth at the device, default is 8 bytes. +qcom,mas-rpm-id: For non-AP owned device this is the RPM id for devices that are bus masters. + This is the id that is used when sending a message to RPM for this device. +qcom,slv-rpm-id: For non-AP owned device this is the RPM id for devices that are bus slaves. + This is the id that is used when sending a message to RPM for this device. +qcom,blacklist: An array of phandles that represent devices that this device + cannot connect to either directly or via any number of + intermediate nodes. +qcom,agg-ports: The number of aggregation ports on the bus. +qcom,node-qos-bcms: Optional property to target specific BCMs to toggle during QoS configuration, + this is to ensure QoS register space is clocked and accessible. Array is + defined as follows: BCM node ID, VoteX, VoteY. The vectors must be defined in + sets of the three values aforementioned. +qcom,prio: Default fixed priority for bus master. +qcom,qos-lim-params: Array containing QoS limiter configurations defined as: Bandwidth, Saturation. + Must define "qcom,qos-lim-en" for these settings to take effect. +qcom,qos-lim-en: Boolean to enable limiter settings, default is disabled. +qcom,qos-reg-params: Array containing QoS regulator configurations defined as: Low Priority, High + Priority, Bandwidth, Saturation. Must define "qcom,qos-reg-regmode" for these + settings to take effect. +qcom,qos-reg-mode: Array containing QoS regulator mode enablement: Read Enable, Write Enable, + default is disabled. +qcom,forwarding: Boolean indicate Urgent Forwarding enablement. + +The following properties are optional as collecting data via coresight might +and are present on child nodes that represent NOC devices. The documentation +for coresight properties can be found in: +Documentation/devicetree/bindings/coresight/coresight.txt + +coreisght-id Unique integer identifier for the bus. +coresight-name Unique descriptive name of the bus. +coresight-nr-inports Number of input ports on the bus. +coresight-outports List of output port numbers on the bus. +coresight-child-list List of phandles pointing to the children of this + component. +coresight-child-ports List of input port numbers of the children. + +The following sub-nodes are optional parameters: + +qcom,node-qos-clks: Optional node listing all the clocks and regulators required for programming of + QoS registers. Usually these are associated with fabric nodes. + clock-names: An array of clock names for QoS programming, + clocks: An array of clock phandles corresponding to the clock names listed above. + clock-name-gdsc: + An optional property listing the regulator associated with a given clock name. + +Example: + +&ad_hoc_bus { + compatible = "msm-bus-device"; + reg = <0x580000 0x62000>; + reg-names = "snoc-base"; + + fab_snoc: fab-snoc { + cell-id = <1024>; + label = "fab-snoc"; + qcom,fab-dev; + qcom,bypass-qos-prg; + qcom,agg-scheme = ; + qcom,util-levels = <450000 133>, + <750000 154>; + qcom,base-name = "snoc-base"; + qcom,base-offset = <0x7000>; + qcom,qos-off = <0x1000>; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpm clk_snoc_msmbus_clk>, + <&clock_rpm clk_snoc_msmbus_a_clk>; + qcom,node-qos-clks { + clock-names = "q0-clk", "q1-clk"; + clocks = <&clock_gcc clk_q0_clk>, + <&clock_gcc clk_q1_clk>; + q0-clk-supply = <&gdsc_q0_clk>; + }; + qcom,node-qos-bcms = <0x7011 0 1>; + qcom,prio = 1; + qcom,qos-lim-params = <1000 1000>; + qcom,qos-lim-en: + qcom,qos-reg-params = <1 2 1000 1000>; + qcom,qos-reg-mode = <1 1>; + }; + + mm_int_bimc: mm-int-bimc { + cell-id = <10003>; + label = "mm-int-bimc"; + qcom,util-fact = <154>; + qcom,vrail-comp = <100>; + qcom,ap-owned; + qcom,connections = <&snoc_bimc_1_mas>; + qcom,bus-dev = <&fab_snoc>; + qcom,buswidth = <16>; + }; + + snoc_int_0: snoc-int-0 { + cell-id = <10004>; + label = "snoc-int-0"; + qcom,connections = <&slv_qdss_stm &slv_imem &snoc_pnoc_mas>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = <99>; + qcom,slv-rpm-id = <130>; + qcom,buswidth = <8>; + }; +}; + + +The bus scaling driver also provides the ability to configure +bus performance parameters across the entire chip-set. +Various clients use MSM scaling APIs to request bandwidth +between multiple master-slave pairs. The bus driver then finds +the optimal path between the master and the slave, and aggregates +the bandwidth and clock requests for all master-slave pairs on +that path, and programs hardware accordingly. + +The device-tree data required for bus-scaling can be embedded within +the clients' device nodes. The clients can register with the bus driver +using the following properties: + +- qcom,msm-bus,name: String representing the client-name +- qcom,msm-bus,num-cases: Total number of usecases +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex +- qcom,msm-bus,num-paths: Total number of master-slave pairs +- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing: + master-id, slave-id, arbitrated bandwidth + in KBps, instantaneous bandwidth in KBps + +The following are optional properties for client's device nodes: + +- qcom,msm-bus,alc-voter: Boolean alc_voter flag to indicate that client + will vote as an Active Latency Client. +- qcom,msm-bus,vectors-alc: Arrays of unsigned integers representing: + first access latency, idle time in ns, this + property is required if qcom,msm-bus,alc-voter + is present. + +Example for default client: + + qcom,msm-bus,name = "client-name"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors = + <22 512 0 0>, <26 512 0 0>, + <22 512 320000 3200000>, <26 512 3200000 3200000>, + <22 512 160000 1600000>, <26 512 1600000 1600000>; + +Example for ALC client: + + qcom,msm-bus,name = "client-name"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,alc-voter; + qcom,msm-bus,vectors-alc = + <0 0>, + <500 1600>; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus_rules.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus_rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..b68284c8970d2d323e082eaf7eaf90a83aad879a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_bus_rules.txt @@ -0,0 +1,62 @@ +MSM Bus static bandwidth rules for adhoc bus topologies + +Buses are the interconnects between various devices. The devices are +connected in different topologies. The static bandwidth rules allow +setting up SOC specific rules to monitor certain bandwidth requests +at different bus nodes. When the conditions of the rule are met +the bus driver will be given a list of actions to be take on specific +bus master ports (throttle on/off, what bandwidth to throttle to etc). + +The mandatory properties for bus driver are: + +compatible: "qcom,msm-bus-static-bw-rules" + +The static_rules node can have numerous rules for the different bandwidth voting +conditions to be monitored. The mandatory properties for the rules are + +- qcom,src-nodes: An array of phandles denoting the source nodes + whose bandwidth votes need to be monitored. +- qcom,src-field: This field represents the voted field of the + source node to be monitored. Possible values + are FLD_IB/FLD_AB/FLD_CLK +- qcom,src-op: The operand to be used when evaluating a node's + bandwidth vote with a threshold.Possible values + are OP_LE/OP_LT/OP_GT/OP_GE. +- qcom,thresh: The threshold in Kbytes/s to be used in vote + evaluation. +- qcom,mode: The QoS mode to be applied when this rule's + criterion are satisfied. Possible values are + THROTTLE_ON/THROTTLE_OFF +- qcom,dest-node: An array of phandles representing the nodes to + which the QoS mode is to be applied. + +The optional properties for the rule node are: +- qcom,dest-bw: The destination bandwidth value in Kbytes/s to + be used toward the QoS mode for the destination + node. + +Example: + static-rules { + compatible = "qcom,msm-bus-static-bw-rules"; + #address-cells = <1>; + #size-cells = <0>; + + rule@0 { + qcom,src-nodes = <&mas_apss>; + qcom,src-field = ; + qcom,src-op = ; + qcom,thresh = <1599078>; + qcom,mode = ; + qcom,dest-node = <&mas_apss>; + qcom,dest-bw = <1599078>; + }; + + rule@1 { + qcom,src-nodes = <&mas_apss>; + qcom,src-field = ; + qcom,src-op = ; + qcom,thresh = <1599078>; + qcom,mode = ; + qcom,dest-node = <&mas_apss>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_gladiator_erp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_gladiator_erp.txt new file mode 100644 index 0000000000000000000000000000000000000000..73a48aae30990d0f5ec46d776e53b9dfb5746c05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_gladiator_erp.txt @@ -0,0 +1,21 @@ +* MSM Gladiator error reporting driver + +Required properties: +- compatible: Should be "qcom,msm-gladiator" or "qcom,msm-gladiator-v2" or +"qcom,msm-gladiator-v3" +- reg: I/O address Gladiator H/W block +- reg-names: Should be "gladiator_base" +- interrupts: Should contain the gladiator error interrupt number +- clock-names: Should be "atb_clk" +- clocks: Handles to clocks specified in "clock-names" property. + +Example: + +qcom,msm-gladiator-v2@b1c0000 { + compatible = "qcom,msm-gladiator"; + reg = <0xb1c0000 0xe000>; + reg-names = "gladiator_base"; + interrupts = <0 34 0>; + clock-names = "atb_clk"; + clocks = <&clock_gcc clk_qdss_clk>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_gladiator_hang_detect.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_gladiator_hang_detect.txt new file mode 100644 index 0000000000000000000000000000000000000000..352bbc950fa975f33d0951c9ddbad16021249226 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_gladiator_hang_detect.txt @@ -0,0 +1,41 @@ +Gladiator Hang Detection provides sysfs entries for configuring +thresholds and enable on ACE_port, IO_port, M1_port, M2_port, +and PCIO_port + +If gladiator is hung for threshold time (value * 5ns) and no +heart beat event from gladiator port to gladiator hang monitor +detection, gladiator hang interrupt would be generated to reset +the SOC to collect all cores context. + +Gladiator hang detection can be enabled on different ports. + +Writing 1 into ace_enabled sysfs entry, enables gladiator hang +detection on ACE port +Writing 1 into io_enabled sysfs entry, enables gladiator hang +detection on IO port +Writing 1 into ace_enabled sysfs entry, enables gladiator hang +detection on M1 port +Writing 1 into ace_enabled sysfs entry, enables gladiator hang +detection on M2 port +Writing 1 into pcio_enabled sysfs entry, enables gladiator hang +detection on PCIO port + +Required properties: +- compatible : "qcom,gladiator-hang-detect" or "qcom,gladiator-hang-detect-v2" + or "qcom,gladiator-hang-detect-v3" +- qcom, threshold-arr: + Array of APCS_COMMON_GLADIATOR_HANG_THRESHOLD_n register + address +- qcom, config-reg: + APCS_COMMON_GLADIATOR_HANG_CONFIG register address + +Optional properties: + +Example: + For msmcobalt: + qcom,ghd { + compatible = "qcom,gladiator-hang-detect"; + qcom,threshold-arr = <0x179d141c 0x179d1420 + 0x179d1424 0x179d1428 0x179d1420 0x179d1430>; + qcom,config-reg = <0x179d1434>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_hang_detect.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_hang_detect.txt new file mode 100644 index 0000000000000000000000000000000000000000..8aa687962cf99d6bf539818ea036e7b7e63ae71c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_hang_detect.txt @@ -0,0 +1,55 @@ +* QTI MSM Core Hang Detection + +Core Hang Detection provides the three sysfs entries for configuring +threshold, PMU event mux select and to enable hang detection. + +If core is hung for threshold time (value X 10ns) and no +heart beat event from pmu to core hang monitor detection, core hang +interrupt would be generated to reset the SOC via secure watchdog +to collect all cores context. + +PMU event mux select can be programmed to one of the supported +events, for example- +1) Load Instruction executed, +2) Store Instructions executed +3) Instruction architecturally executed and etc. + +Writing 1 into enable sysfs entry, enables core hang detection and +if there is no selected PMU mux event for 10ns core hang counter +gets incremented. Once counter reaches the programmed threshold value, +core hang interrupts generated to reset the SOC. + + +The device tree parameters for the core hang detection are: + +Required properties: + +- compatible : "qcom,core-hang-detect" +- label: unique name used to created sysfs entry +- qcom,threshold-arr : + Array of APCS_ALIAS*_CORE_HANG_THRESHOLD register address + for each core. +- qcom,config-arr : + Array of APCS_ALIAS*_CORE_HANG_CONFIG register address + for each core. + +Optional properties: + +Example: + For msm8937: + qcom,chd { + compatible = "qcom,core-hang-detect"; + qcom,threshold-arr = <0xB088094 0xB098094 0xB0A8094 + 0xB0B8094 0xB188094 0xB198094 0xB1A8094 0xB1B8094>; + qcom,config-arr = <0xB08809C 0xB09809C 0xB0A809C + 0xB0B809C 0xB18809C 0xB19809C 0xB1A809C 0xB1B809C>; + }; + + For msmtitanium: + qcom,chd { + compatible = "qcom,core-hang-detect"; + qcom,threshold-arr = <0xB1880B0 0xB1980B0 0xB1A80B0 + 0xB1B80B0 0xB0880B0 0xB0980B0 0xB0A80B0 0xB0B80B0>; + qcom,config-arr = <0xB1880B8 0xB1980B8 0xB1A80B8 + 0xB1B80B8 0xB0880B8 0xB0980B8 0xB0A80B8 0xB0B80B8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_ion.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_ion.txt new file mode 100644 index 0000000000000000000000000000000000000000..cc7d2bab612cc8354c23117f2da6e96f04b0156a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_ion.txt @@ -0,0 +1,89 @@ +ION Memory Manager (ION) + +ION is a memory manager that allows for sharing of buffers between different +processes and between user space and kernel space. ION manages different +memory spaces by separating the memory spaces into "heaps". + +Required properties for Ion + +- compatible: "qcom,msm-ion" + + +All child nodes of a qcom,msm-ion node are interpreted as Ion heap +configurations. + +Required properties for Ion heaps + +- reg: The ID of the ION heap. +- qcom,ion-heap-type: The heap type to use for this heap. Should be one of + the following: + - "SYSTEM" + - "CARVEOUT" + - "SECURE_CARVEOUT" + - "DMA" + - "HYP_CMA" + - "SYSTEM_SECURE" + - "SECURE_DMA" + +Optional properties for Ion heaps + +- memory-region: phandle to memory region associated with heap. + +Example: + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&adsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + + }; + +"SECURE_CARVEOUT" + +This heap type is expected to contain multiple child nodes. Each child node +shall contain the following required properties: + +- memory-region: +Refer to Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt + +- token: +A u32 containing the set of secure domains which will be able to access the +memory-region. + +Example: +qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,ion-heap@14 { + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + + node1 { + memory-region = <&cp_region>; + token = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_memory_dump.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_memory_dump.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2bb7b3e21d377f5db962625063e94889409ce93 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_memory_dump.txt @@ -0,0 +1,32 @@ +Qualcomm Technologies Inc. memory dump driver + +QTI memory dump driver allows various client subsystems to register and +allocate respective dump regions. At the time of deadlocks or cpu hangs +these dump regions are captured to give a snapshot of the system at the +time of the crash. + +Required properties: + +-compatible: "qcom,mem-dump" +-memory-region: phandle to the CMA region. The size of the CMA region + should be greater than sum of size of all child nodes + to account for padding. + +If any child nodes exist the following property are required: + +-qcom,dump-size: The size of memory that needs to be allocated for the + particular node. +-qcom,dump-id: The ID within the data dump table where this entry needs + to be added. + +Example: + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh_dump { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xEC>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_qmp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_qmp.txt new file mode 100644 index 0000000000000000000000000000000000000000..189b42b5cf5453f2d96ba37bdcf595c3b86fcd9f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_qmp.txt @@ -0,0 +1,60 @@ +Qualcomm Technologies, Inc. QTI Mailbox Protocol + +QMP Driver +=================== + +Required properties: +- compatible : should be "qcom,qmp-mbox". +- label : the name of the remote proc this link connects to. +- reg : The location and size of shared memory. + The irq register base address for triggering interrupts. +- reg-names : "msgram" - string to identify the shared memory region. + "irq-reg-base" - string to identify the irq register region. +- qcom,irq-mask : the bitmask to trigger an interrupt. +- mboxes: - Handle to outgoing interrupt if not using irq-reg-base +- interrupt : the receiving interrupt line. +- mbox-desc-offset : offset of mailbox descriptor from start of the msgram. +- priority : the priority of this mailbox compared to other mailboxes. +- #mbox-cells: Common mailbox binding property to identify the number of cells + required for the mailbox specifier, should be 1. + +Optional properties: +- qcom,early-boot : bool to indicate that this remote proc will boot before QMP. +- mbox-offset : offset of the mcore mailbox from the offset of msgram. If this + property is not used, qmp will use the configuration + provided by the ucore. +- mbox-size : size of the mcore mailbox. If this property is not used, qmp will + use the configuration provided by the ucore. + +Example: + qmp_aop: qcom,qmp-aop { + compatible = "qcom,qmp-mbox"; + label = "aop"; + qcom,early-boot; + reg = <0xc300000 0x100000>, + <0x1799000C 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x1>; + interrupt = <0 389 1>; + mbox-desc-offset = <0x100>; + priority = <1>; + mbox-offset = <0x500>; + mbox-size = <0x400>; + #mbox-cells = <1>; + }; + +Mailbox Client +============== +"mboxes" and the optional "mbox-names" (please see +Documentation/devicetree/bindings/mailbox/mailbox.txt for details). Each value +of the mboxes property should contain a phandle to the mailbox controller +device node and second argument is the channel index. It must be 0 (qmp +supports only one channel).The equivalent "mbox-names" property value can be +used to give a name to the communication channel to be used by the client user. + +Example: + qmp-client { + compatible = "qcom,qmp-client"; + mbox-names = "aop"; + mboxes = <&qmp_aop 0>, + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_rtb.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_rtb.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae61ebf771e4bda6202f8f30c59e88b3dacd75a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_rtb.txt @@ -0,0 +1,22 @@ +Register Trace Buffer (RTB) + +The RTB is used to log discrete events in the system in an uncached buffer that +can be post processed from RAM dumps. The RTB must reserve memory using +the msm specific memory reservation bindings (see +Documentation/devicetree/bindings/arm/msm/memory-reserve.txt). + +Required properties + +- compatible: "qcom,msm-rtb" +- qcom,rtb-size: size of the RTB buffer in bytes + +Optional properties: + +- linux,contiguous-region: phandle reference to a CMA region + +Example: + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_watchdog.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_watchdog.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c7f3fe62603331796de079c0bac514333ac523f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/msm_watchdog.txt @@ -0,0 +1,52 @@ +* QTI MSM Watchdog + +Watchdog timer is configured with a bark and a bite time. +If the watchdog is not "pet" at regular intervals, the system +is assumed to have become non responsive and needs to be reset. +A warning in the form of a bark timeout leads to a bark interrupt +and a kernel panic. If the watchdog timer is still not reset, +a bite timeout occurs, which is an interrupt in the secure mode, +which leads to a reset of the SOC via the secure watchdog. The +driver needs the petting time, and the bark timeout to be programmed +into the watchdog, as well as the bark and bite irqs. + +The device tree parameters for the watchdog are: + +Required properties: + +- compatible : "qcom,msm-watchdog" +- reg : offset and length of the register set for the watchdog block. +- reg-names : names corresponding to each reg property value. + "wdt-base" - physical base address of watchdog timer registers + "wdt-absent-base" - physical base address of watchdog absent register +- interrupts : should contain bark and bite irq numbers +- qcom,pet-time : Non zero time interval at which watchdog should be pet in ms. +- qcom,bark-time : Non zero timeout value for a watchdog bark in ms. +- qcom,userspace-watchdog : + (boolean) Allow enabling the userspace-watchdog feature. This feature + requires userspace to pet the watchdog every qcom,pet-time interval + in addition to the existing kernel-level checks. + This feature is supported through device sysfs files. + +Optional properties: + +- qcom,ipi-ping : (boolean) send keep alive ping to other cpus if present +- qcom,wakeup-enable : (boolean) enable non secure watchdog to freeze / unfreeze + automatically across suspend / resume path. +- qcom,scandump-sizes : an array of 32-bit values that contains the size of the + scandump memory region for each CPU, such that the nth + 32 bit value maps to the scandump size for CPU n. + +Example: + + qcom,wdt@f9017000 { + compatible = "qcom,msm-watchdog"; + reg = <0xf9017000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 3 0>, <0 4 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <10000>; + qcom,ipi-ping; + qcom,wakeup-enable; + qcom,scandump-size = <0x10100 0x10100 0x10100 0x10100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/proxy-client.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/proxy-client.txt new file mode 100644 index 0000000000000000000000000000000000000000..29cfaf90016c9a70034701a498863b7b25c015d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/proxy-client.txt @@ -0,0 +1,34 @@ +Bus Proxy Client Bindings + +Bus proxy client provides means to cast proxy bandwidth votes during bootup +which is removed at the end of boot. This feature can be used in situations +where a shared resource can be scaled between several possible perfomance +levels and hardware requires that it be at a high level at the beginning of +boot before the client has probed and voted for required bandwidth. + +Required properties: +- compatible: Must be "qcom,bus-proxy-client". + +Optional properties: +- qcom,msm-bus,name: String representing the client-name. +- qcom,msm-bus,num-cases: Total number of usecases. +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex. +- qcom,msm-bus,num-paths: Total number of master-slave pairs. +- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing: + master-id, slave-id, arbitrated bandwidth + in KBps, instantaneous bandwidth in KBps. + +Example: + + qcom,proxy-client { + compatible = "qcom,bus-proxy-client"; + qcom,msm-bus,name = "proxy_client"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,idle-state.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,idle-state.txt new file mode 100644 index 0000000000000000000000000000000000000000..06df04cc827a5eaba364f86f6800d1c0a84773d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,idle-state.txt @@ -0,0 +1,84 @@ +QCOM Idle States for cpuidle driver + +ARM provides idle-state node to define the cpuidle states, as defined in [1]. +cpuidle-qcom is the cpuidle driver for Qualcomm SoCs and uses these idle +states. Idle states have different enter/exit latency and residency values. +The idle states supported by the QCOM SoC are defined as - + + * Standby + * Retention + * Standalone Power Collapse (Standalone PC or SPC) + * Power Collapse (PC) + +Standby: Standby does a little more in addition to architectural clock gating. +When the WFI instruction is executed the ARM core would gate its internal +clocks. In addition to gating the clocks, QCOM cpus use this instruction as a +trigger to execute the SPM state machine. The SPM state machine waits for the +interrupt to trigger the core back in to active. This triggers the cache +hierarchy to enter standby states, when all cpus are idle. An interrupt brings +the SPM state machine out of its wait, the next step is to ensure that the +cache hierarchy is also out of standby, and then the cpu is allowed to resume +execution. This state is defined as a generic ARM WFI state by the ARM cpuidle +driver and is not defined in the DT. The SPM state machine should be +configured to execute this state by default and after executing every other +state below. + +Retention: Retention is a low power state where the core is clock gated and +the memory and the registers associated with the core are retained. The +voltage may be reduced to the minimum value needed to keep the processor +registers active. The SPM should be configured to execute the retention +sequence and would wait for interrupt, before restoring the cpu to execution +state. Retention may have a slightly higher latency than Standby. + +Standalone PC: A cpu can power down and warmboot if there is a sufficient time +between the time it enters idle and the next known wake up. SPC mode is used +to indicate a core entering a power down state without consulting any other +cpu or the system resources. This helps save power only on that core. The SPM +sequence for this idle state is programmed to power down the supply to the +core, wait for the interrupt, restore power to the core, and ensure the +system state including cache hierarchy is ready before allowing core to +resume. Applying power and resetting the core causes the core to warmboot +back into Elevation Level (EL) which trampolines the control back to the +kernel. Entering a power down state for the cpu, needs to be done by trapping +into a EL. Failing to do so, would result in a crash enforced by the warm boot +code in the EL for the SoC. On SoCs with write-back L1 cache, the cache has to +be flushed in s/w, before powering down the core. + +Power Collapse: This state is similar to the SPC mode, but distinguishes +itself in that the cpu acknowledges and permits the SoC to enter deeper sleep +modes. In a hierarchical power domain SoC, this means L2 and other caches can +be flushed, system bus, clocks - lowered, and SoC main XO clock gated and +voltages reduced, provided all cpus enter this state. Since the span of low +power modes possible at this state is vast, the exit latency and the residency +of this low power mode would be considered high even though at a cpu level, +this essentially is cpu power down. The SPM in this state also may handshake +with the Resource power manager (RPM) processor in the SoC to indicate a +complete application processor subsystem shut down. + +The idle-state for QCOM SoCs are distinguished by the compatible property of +the idle-states device node. + +The devicetree representation of the idle state should be - + +Required properties: + +- compatible: Must be one of - + "qcom,idle-state-ret", + "qcom,idle-state-spc", + "qcom,idle-state-pc", + and "arm,idle-state". + +Other required and optional properties are specified in [1]. + +Example: + + idle-states { + CPU_SPC: spc { + compatible = "qcom,idle-state-spc", "arm,idle-state"; + entry-latency-us = <150>; + exit-latency-us = <200>; + min-residency-us = <2000>; + }; + }; + +[1]. Documentation/devicetree/bindings/arm/idle-states.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,kpss-acc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,kpss-acc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1333db9acfee11aa47b9972ac9e41b0e081966ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,kpss-acc.txt @@ -0,0 +1,30 @@ +Krait Processor Sub-system (KPSS) Application Clock Controller (ACC) + +The KPSS ACC provides clock, power domain, and reset control to a Krait CPU. +There is one ACC register region per CPU within the KPSS remapped region as +well as an alias register region that remaps accesses to the ACC associated +with the CPU accessing the region. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: should be one of: + "qcom,kpss-acc-v1" + "qcom,kpss-acc-v2" + +- reg: + Usage: required + Value type: + Definition: the first element specifies the base address and size of + the register region. An optional second element specifies + the base address and size of the alias register region. + +Example: + + clock-controller@2088000 { + compatible = "qcom,kpss-acc-v2"; + reg = <0x02088000 0x1000>, + <0x02008000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,llcc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,llcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d03e47b0a67b0d84cf2c2d5fecadf67fc26c330 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,llcc.txt @@ -0,0 +1,48 @@ +== Introduction== + +LLCC (Last Level Cache Controller) provides last level of cache memory in SOC, +that can be shared by multiple clients. Clients here are different cores in the +SOC, the idea is to minimize the local caches at the clients and migrate to +common pool of memory. Cache memory is divided into partitions called slices +which are assigned to clients. Clients can query the slice details, activate +and deactivate them. + +Properties: +- compatible: + Usage: required + Value type: + Definition: must be "qcom,llcc-v1", "qcom,llcc-v2" or "lagoon-llcc-v1" + +- reg: + Usage: required + Value Type: + Definition: The first element specifies the llcc base start address and + the size of the register region. The second element specifies + the llcc broadcast base address and size of the register region. + +- reg-names: + Usage: required + Value Type: + Definition: Register region names. Must be "llcc_base", "llcc_broadcast_base". + +- interrupts: + Usage: required + Definition: The interrupt is associated with the llcc edac device. + It's used for llcc cache single and double bit error detection + and reporting. + +- cap-based-alloc-and-pwr-collapse: + Usage: optional + Value Type: Boolean + Definition: Property to express that HLOS can enable/disable capacity + based allocation and power collapse retention for a client. Include + this property to set it. If not set, it will be treated as false. + +Example: + + cache-controller@9200000 { + compatible = "qcom,llcc-v2"; + reg = <0x9200000 0x200000> <0x9600000 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,osm-sdm660.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,osm-sdm660.txt new file mode 100644 index 0000000000000000000000000000000000000000..614820e82b70540b5fcafd6607b3f6edc86508f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,osm-sdm660.txt @@ -0,0 +1,488 @@ +Qualcomm Technologies, Inc. OSM Bindings + +Operating State Manager (OSM) is a hardware engine used by some +Qualcomm Technologies, Inc. (QTI) SoCs to manage frequency and voltage scaling +in hardware. OSM is capable of controlling frequency and voltage requests +for multiple clusters via the existence of multiple OSM domains. + +Properties: +- compatible + Usage: required + Value type: + Definition: must be "qcom,clk-cpu-osm" or + "qcom,clk-cpu-osm-sdm630". + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the OSM controller, + cluster PLL management, and APCS common register regions. + Optionally, the address of the efuse registers used to + determine the pwrcl or perfcl speed-bins and/or the ACD + register space to initialize prior to enabling OSM. + +- reg-names + Usage: required + Value type: + Definition: Address names. Must be "osm", "pwrcl_pll", "perfcl_pll", + "apcs_common", and "debug". Optionally, "pwrcl_efuse", + "perfcl_efuse", "pwrcl_acd", or "perfcl_acd". + Must be specified in the same order as the corresponding + addresses are specified in the reg property. + +- vdd-pwrcl-supply + Usage: required + Value type: + Definition: phandle of the underlying regulator device that manages + the voltage supply of the Power cluster. + +- vdd-perfcl-supply + Usage: required + Value type: + Definition: phandle of the underlying regulator device that manages + the voltage supply of the Performance cluster. + +- interrupts + Usage: required + Value type: + Definition: OSM interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. this list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + "pwrcl-irq" and "perfcl-irq" must be specified. + +- qcom,pwrcl-speedbinX-v0 + Usage: required + Value type: + Definition: Array which defines the frequency in Hertz, frequency, + PLL override data, ACC level, and virtual corner used + by the OSM hardware for each supported DCVS setpoint + of the Power cluster. + +- qcom,perfcl-speedbinX-v0 + Usage: required + Value type: + Definition: Array which defines the frequency in Hertz, frequency, + PLL override data, ACC level and virtual corner used + by the OSM hardware for each supported DCVS setpoint + of the Performance cluster. + +- qcom,osm-no-tz + Usage: optional + Value type: + Definition: Boolean flag which indicates that there is no programming + of the OSM hardware performed by the secure world. + +- qcom,osm-pll-setup + Usage: optional + Value type: + Definition: Boolean flag which indicates that the PLL setup sequence + must be executed for each clock domain managed by the OSM + controller. + +- qcom,up-timer + Usage: optional + Value type: + Definition: Array which defines the DCVS up timer value in nanoseconds + for each of the two clusters managed by the OSM controller. + +- qcom,down-timer + Usage: optional + Value type: + Definition: Array which defines the DCVS down timer value in nanoseconds + for each of the two clusters managed by the OSM controller. + +- qcom,pc-override-index + Usage: optional + Value type: + Definition: Array which defines the OSM performance index to be used + when each cluster enters certain low power modes. + +- qcom,set-ret-inactive + Usage: optional + Value type: + Definition: Boolean flag which indicates if domains in retention must + be treated as inactive. + +- qcom,enable-llm-freq-vote + Usage: optional + Value type: + Definition: Boolean flag which indicates if Limits hardware frequency + votes must be honored by OSM. + +- qcom,llm-freq-up-timer + Usage: optional + Value type: + Definition: Array which defines the LLM frequency up timer value in + nanoseconds for each of the two clusters managed by the + OSM controller. + +- qcom,llm-freq-down-timer + Usage: optional + Value type: + Definition: Array which defines the LLM frequency down timer value in + nanoseconds for each of the two clusters managed by the + OSM controller. + +- qcom,enable-llm-volt-vote + Usage: optional + Value type: + Definition: Boolean flag which indicates if Limits hardware voltage + votes must be honored by OSM. + +- qcom,llm-volt-up-timer + Usage: optional + Value type: + Definition: Array which defines the LLM voltage up timer value in + nanoseconds for each of the two clusters managed by the + OSM controller. + +- qcom,llm-volt-down-timer + Usage: optional + Value type: + Definition: Array which defines the LLM voltage down timer value in + nanoseconds for each of the two clusters managed by the + OSM controller. + +- qcom,cc-reads + Usage: optional + Value type: + Definition: Defines the number of times the cycle counters must be + read to determine the performance level of each clock + domain. + +- qcom,l-val-base + Usage: required + Value type: + Definition: Array which defines the register addresses of the L_VAL + control register for each of the two clusters managed + by the OSM controller. + +- qcom,apcs-itm-present + Usage: required + Value type: + Definition: Array which defines the register addresses of the ITM + control register for each of the two clusters managed + by the OSM controller. + +- qcom,apcs-pll-user-ctl + Usage: required + Value type: + Definition: Array which defines the register addresses of the PLL + user control register for each of the two clusters managed + by the OSM controller. + +- qcom,apcs-cfg-rcgr + Usage: required + Value type: + Definition: Array which defines the register addresses of the RCGR + configuration register for each of the two clusters managed + by the OSM controller. + +- qcom,apcs-cmd-rcgr + Usage: required + Value type: + Definition: Array which defines the register addresses of the RCGR + command register for each of the two clusters managed + by the OSM controller. + +- qcom,apm-threshold-voltage + Usage: required + Value type: + Definition: Specifies the APM threshold voltage in microvolts. If the + VDD_APCC supply voltage is above or at this level, then the + APM is switched to use VDD_APCC. If VDD_APCC is below + this level, then the APM is switched to use VDD_MX. + +- qcom,apm-mode-ctl + Usage: required + Value type: + Definition: Array which defines the register addresses of the APM + control register for each of the two clusters managed + by the OSM controller. + +- qcom,apm-ctrl-status + Usage: required + Value type: + Definition: Array which defines the register addresses of the APM + controller status register for each of the two clusters + managed by the OSM controller. + +- qcom,llm-sw-overr + Usage: optional + Value type: + Definition: Array of tuples which defines the three non-zero LLM SW + override values to write to the OSM controller for each + of the two clusters. Each tuple must contain three elements. + +- qcom,acdtd-val + Usage: required if pwrcl_acd or perfcl_acd registers are specified + Value type: + Definition: Array which defines the values to program to the ACD + Tunable-Length Delay register for the power and performance + clusters. + +- qcom,acdcr-val + Usage: required if pwrcl_acd or perfcl_acd registers are specified + Value type: + Definition: Array which defines the values for the ACD control register + for the power and performance clusters. + +- qcom,acdsscr-val + Usage: required if pwrcl_acd or perfcl_acd registers are specified + Value type: + Definition: Array which defines the values for the ACD Soft Start Control + register for the power and performance clusters. + +- qcom,acdextint0-val + Usage: required if pwrcl_acd or perfcl_acd registers are specified + Value type: + Definition: Array which defines the initial values for the ACD + external interface configuration register for the power + and performance clusters. + +- qcom,acdextint1-val + Usage: required if pwrcl_acd or perfcl_acd registers are specified + Value type: + Definition: Array which defines the final values for the ACD + external interface configuration register for the power + and performance clusters. + +- qcom,acdautoxfer-val + Usage: required if pwrcl_acd or perfcl_acd registers are specified + Value type: + Definition: Array which defines the values for the ACD auto transfer + control register for the power and performance clusters. + +- qcom,pwrcl-apcs-mem-acc-cfg + Usage: required if qcom,osm-no-tz is specified + Value type: + Definition: Array which defines the addresses of the mem-acc + configuration registers for the Power cluster. + The array must contain exactly three elements. + +- qcom,perfcl-apcs-mem-acc-cfg + Usage: required if qcom,osm-no-tz is specified + Value type: + Definition: Array which defines the addresses of the mem-acc + configuration registers for the Performance cluster. + The array must contain exactly three elements. + +- qcom,pwrcl-apcs-mem-acc-val + Usage: required if qcom,osm-no-tz is specified + Value type: + Definition: List of integer tuples which define the mem-acc values + for each performance mode of the Power cluster. Each tuple + is of length 3 corresponding to the mem-acc values per + performance mode with a total of 4 tuples corresponding + to each supported performance mode. + +- qcom,pwrcl-apcs-mem-acc-threshold-voltage + Usage: optional + Value type: + Definition: Specifies the highest MEM ACC threshold voltage in + microvolts for the Power cluster. This voltage is + used to determine which MEM ACC setting is used for the + highest frequencies. If specified, the voltage must match + the MEM ACC threshold voltage specified for the + corresponding CPRh device. + +- qcom,perfcl-apcs-mem-acc-val + Usage: required if qcom,osm-no-tz is specified + Value type: + Definition: List of integer tuples which define the mem-acc values + for each performance mode of the Performance cluster. + Each tuple is of length 3 corresponding to the mem-acc + values per performance mode with a total of 4 tuples + corresponding to each supported performance mode. + +- qcom,perfcl-apcs-mem-acc-threshold-voltage + Usage: optional + Value type: + Definition: Specifies the highest MEM ACC threshold voltage in + microvolts for the Performance cluster. This voltage is + used to determine which MEM ACC setting is used for the + highest frequencies. If specified, the voltage must match + the MEM ACC threshold voltage specified for the + corresponding CPRh device. + +- qcom,red-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the reduction FSM + should be enabled. + +- qcom,boost-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the boost FSM should + be enabled. + +- qcom,safe-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the safe FSM should + be enabled. + +- qcom,ps-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the PS FSM should be + enabled. + +- qcom,droop-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the droop FSM should + be enabled. +- qcom,wfx-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the WFX FSM should + be enabled. + +- qcom,pc-fsm-en + Usage: optional + Value type: + Definition: Boolean flag which indicates if the PC/RET FSM should + be enabled. + +- clock-names + Usage: required + Value type: + Definition: Must be "aux_clk". + +- clocks + Usage: required + Value type: + Definition: Phandle to the aux clock device. + +Example: + + clock_cpu: qcom,clk-cpu-660@179c0000 { + compatible = "qcom,clk-cpu-osm"; + reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, + <0x17816000 0x1000>, <0x179d1000 0x1000>, + <0x00784130 0x8>, <0x00784130 0x8>; + reg-names = "osm", "pwrcl_pll", "perfcl_pll", + "apcs_common", "pwrcl_efuse", + "perfcl_efuse"; + + vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; + vdd-perfcl-supply = <&apc1_perfcl_vreg>; + + interrupts = , + ; + interrupt-names = "pwrcl-irq", "perfcl-irq"; + + qcom,pwrcl-speedbin0-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1747200000 0x0404005b 0x09480048 0x2 7 >, + < 1843200000 0x04040060 0x094c004c 0x3 8 >; + + qcom,pwrcl-speedbin1-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1747200000 0x0404005b 0x09480048 0x2 7 >, + < 1843200000 0x04040060 0x094c004c 0x3 8 >; + + qcom,pwrcl-speedbin3-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1612800000 0x04040054 0x09430043 0x2 7 >; + + qcom,pwrcl-speedbin4-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1747200000 0x0404005b 0x09480048 0x2 7 >, + < 1843200000 0x04040060 0x094c004c 0x3 8 >; + + qcom,perfcl-speedbin0-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1958400000 0x04040066 0x0a510051 0x2 5 >, + < 2150400000 0x04040070 0x0b590059 0x2 6 >, + < 2457600000 0x04040080 0x0c660066 0x3 7 >; + + qcom,perfcl-speedbin1-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1958400000 0x04040066 0x0a510051 0x2 5 >, + < 2150400000 0x04040070 0x0b590059 0x2 6 >, + < 2208000000 0x04040073 0x0b5c005c 0x3 7 >; + + qcom,perfcl-speedbin3-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1804800000 0x0404005e 0x094b004b 0x2 5 >; + + qcom,perfcl-speedbin4-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1958400000 0x04040066 0x0a510051 0x2 5 >; + + qcom,up-timer = <1000 1000>; + qcom,down-timer = <1000 1000>; + qcom,set-ret-inactive; + qcom,enable-llm-freq-vote; + qcom,llm-freq-up-timer = <327675 327675>; + qcom,llm-freq-down-timer = <327675 327675>; + qcom,enable-llm-volt-vote; + qcom,llm-volt-up-timer = <327675 327675>; + qcom,llm-volt-down-timer = <327675 327675>; + qcom,cc-reads = <10>; + qcom,cc-delay = <5>; + qcom,cc-factor = <100>; + qcom,osm-clk-rate = <200000000>; + qcom,xo-clk-rate = <19200000>; + + qcom,l-val-base = <0x17916004 0x17816004>; + qcom,apcs-itm-present = <0x179d143c 0x179d143c>; + qcom,apcs-pll-user-ctl = <0x1791600c 0x1781600c>; + qcom,apcs-cfg-rcgr = <0x17911054 0x17811054>; + qcom,apcs-cmd-rcgr = <0x17911050 0x17811050>; + qcom,apm-mode-ctl = <0x179d0004 0x179d0010>; + qcom,apm-ctrl-status = <0x179d000c 0x179d0018>; + + qcom,apm-threshold-voltage = <872000>; + qcom,boost-fsm-en; + qcom,safe-fsm-en; + qcom,ps-fsm-en; + qcom,droop-fsm-en; + qcom,wfx-fsm-en; + qcom,pc-fsm-en; + + clock-names = "aux_clk", "xo_a"; + clocks = <&clock_gcc HMSS_GPLL0_CLK_SRC>, + <&clock_rpmcc RPM_XO_A_CLK_SRC>; + + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,qsee_irq.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,qsee_irq.txt new file mode 100644 index 0000000000000000000000000000000000000000..768fc416b73811ffec40f0bfb6b35f779edd71ed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,qsee_irq.txt @@ -0,0 +1,82 @@ +Binding for the QTI Secure Execution Environment IRQ controller +=============================================================== + +The QTI Secure Execution Environment (QSEE) IRQ controller facilitates receiving +and clearing interrupts from QSEE. Each interrupt from QSEE has a set of control +registers to mask, clear and get the status of interrupts. This controller will +create an interrupt for clients to register with based on the bits available in +the control registers. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,sm8150-qsee-irq", + "qcom,kona-qsee-irq" + +- syscon: + usage: required + Value type: + Definition: phandle to a syscon node representing the scsr registers + +- interrupts: + Usage: required + Value type: + Definition: multiple entries specifying the interrupts from QSEE + +- interrupt-names: + Usage: required + Value type: + Definition: Interrupt names should be one of the following to map the + interrupt back to the correct registers. + - sp_ipc%d + - sp_rmb + +- interrupt-controller: + Usage: required + Value type: + Definition: Identifies this node as an interrupt controller + +- #interrupt-cells + Usage: required + Value type: + Definition: must be 3 - for interrupts to encode these properties: + - u32 denoting index of desired interrupt in @interrupts + - u32 denoting bit of interrupt bank + - u32 denoting IRQ flags + += EXAMPLE +The following example shows the QSEE_IRQ setup with the GLINK SPSS node, defined +from the sm8150 apps processor's point-of-view. In this example the GLINK node +registers for the sp_ipc0 interrupt(index 0 in interrupt-names) and the 0th +bit on the sp_ipc0 interrupt bank. + +sp_scsr_block: syscon@1880000 { + compatible = “sysconâ€; + reg = <0x1880000 0x10000>; +}; + +intsp: qcom,qsee_irq { + compatible = "qcom,sm8150-qsee-irq"; + + syscon = <&sp_scsr_block>; + interrupts = <0 348 IRQ_TYPE_LEVEL_HIGH>, + <0 349 IRQ_TYPE_LEVEL_HIGH>; + + interrupt-names = "sp_ipc0", + "sp_ipc1"; + + interrupt-controller; + #interrupt-cells = <3>; +}; + +spss { + ... + glink { + qcom,remote-pid = <8>; + mboxes = <&sp_scsr 0>; + mbox-names = "spss_spss"; + interrupts = <&intsp 0 0 IRQ_TYPE_EDGE_RISING>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,saw2.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,saw2.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae4afc6dcfe0a851a6264f50d633584f4f3a6cca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qcom,saw2.txt @@ -0,0 +1,57 @@ +SPM AVS Wrapper 2 (SAW2) + +The SAW2 is a wrapper around the Subsystem Power Manager (SPM) and the +Adaptive Voltage Scaling (AVS) hardware. The SPM is a programmable +power-controller that transitions a piece of hardware (like a processor or +subsystem) into and out of low power modes via a direct connection to +the PMIC. It can also be wired up to interact with other processors in the +system, notifying them when a low power state is entered or exited. + +Multiple revisions of the SAW hardware are supported using these Device Nodes. +SAW2 revisions differ in the register offset and configuration data. Also, the +same revision of the SAW in different SoCs may have different configuration +data due the the differences in hardware capabilities. Hence the SoC name, the +version of the SAW hardware in that SoC and the distinction between cpu (big +or Little) or cache, may be needed to uniquely identify the SAW register +configuration and initialization data. The compatible string is used to +indicate this parameter. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Must have + "qcom,saw2" + A more specific value could be one of: + "qcom,apq8064-saw2-v1.1-cpu" + "qcom,msm8974-saw2-v2.1-cpu" + "qcom,apq8084-saw2-v2.1-cpu" + +- reg: + Usage: required + Value type: + Definition: the first element specifies the base address and size of + the register region. An optional second element specifies + the base address and size of the alias register region. + +- regulator: + Usage: optional + Value type: boolean + Definition: Indicates that this SPM device acts as a regulator device + device for the core (CPU or Cache) the SPM is attached + to. + +Example 1: + + power-controller@2099000 { + compatible = "qcom,saw2"; + reg = <0x02099000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + +Example 2: + saw0: power-controller@f9089000 { + compatible = "qcom,apq8084-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qmp-debugfs-client.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qmp-debugfs-client.txt new file mode 100644 index 0000000000000000000000000000000000000000..655bf89559c55e568c86f40af66fe898860ed1b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qmp-debugfs-client.txt @@ -0,0 +1,17 @@ +QMP debugfs client: +----------------- + +QTI Messaging Protocol(QMP) debugfs client is an interface for clients to +send data to the Always on processor using QMP. + +Required properties : +- compatible : must be "qcom,debugfs-qmp-client" +- mboxes : list of QMP mailbox phandle and channel identifier tuples. +- mbox-names : names of the listed mboxes + +Example : + qcom,qmp-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/qsee_ipc_irq_bridge.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qsee_ipc_irq_bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..442ad52b4bf6e471d2c310db2ce053012b1b8163 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/qsee_ipc_irq_bridge.txt @@ -0,0 +1,30 @@ +Qualcomm Technologies, Inc. Secure Execution Environment IPC Interrupt Bridge + +[Root level node] +Required properties: +-compatible : should be "qcom,qsee-ipc-irq-bridge"; + +[Second level nodes] +qcom,qsee-ipc-irq-subsystem +Required properties: +-qcom,dev-name: the bridge device name +-interrupt: IPC interrupt line from remote subsystem to QSEE +-label : The name of this subsystem. + +Required properties if interrupt type is IRQ_TYPE_LEVEL_HIGH[4]: +-qcom,rx-irq-clr : the register to clear the level triggered rx interrupt +-qcom,rx-irq-clr-mask : the bitmask to clear the rx interrupt + +Example: + + qcom,qsee_ipc_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,rx-irq-clr = <0x1d08008 0x4>; + qcom,rx-irq-clr-mask = <0x2>; + qcom,dev-name = "qsee_ipc_irq_spss"; + interrupts = <0 349 4>; + label = "spss"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/rdbg-smp2p.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rdbg-smp2p.txt new file mode 100644 index 0000000000000000000000000000000000000000..3965ec54dacf01950d57bd0b35e2b1cb2fe489a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rdbg-smp2p.txt @@ -0,0 +1,15 @@ +Qualcomm Technologies, Inc. Remote Debugger (RDBG) driver + +Required properties: +-compatible : Should be one of + To communicate with adsp + qcom,smp2p-interrupt-rdbg-2-in (inbound) + qcom,smp2p-interrupt-rdbg-2-out (outbound) + To communicate with cdsp + qcom,smp2p-interrupt-rdbg-5-in (inbound) + qcom,smp2p-interrupt-rdbg-5-out (outbound) + +Example: + qcom,smp2p_interrupt_rdbg_2_in { + compatible = "qcom,smp2p-interrupt-rdbg-2-in"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm-smd.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm-smd.txt new file mode 100644 index 0000000000000000000000000000000000000000..79968810b96a618391fc636cac9527f6c1b01f17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm-smd.txt @@ -0,0 +1,40 @@ +Resource Power Manager(RPM) + +RPM is a dedicated hardware engine for managing shared SoC resources, +which includes buses, clocks, power rails, etc. The goal of RPM is +to achieve the maximum power savings while satisfying the SoC's +operational and performance requirements. RPM accepts resource +requests from multiple RPM masters. It arbitrates and aggregates +the requests, and configures the shared resources. The RPM masters +are the application processor, the modem processor, as well as hardware +accelerators. The RPM driver communicates with the hardware engine using +SMD. + +The devicetree representation of the RPM block should be: + +Required properties + +- compatible: "qcom,rpm-smd" +- rpm-channel-name: The string corresponding to the channel name of the + peripheral subsystem. Required for both smd and + glink transports. +- rpm-channel-type: The interal SMD edge for this subsystem found in + +- interrupts: The IRQ used by remote processor to inform APSS about + reception of response message packet. + +Optional properties +- rpm-standalone: Allow RPM driver to run in standalone mode irrespective of RPM + channel presence. +- reg: Contains the memory address at which rpm messaging format version is + stored. If this field is not present, the target only supports v0 format. + +Example: + + qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + interrupts = ; + qcom,rpm-channel-name = "rpm_requests"; + qcom,rpm-channel-type = 15; /* APPS_RPM_SMD */ + } +} diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm_master_stats.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm_master_stats.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfc6e3ab62432e7140fe9b4657722652b6a006f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm_master_stats.txt @@ -0,0 +1,47 @@ +* RPM Stats + +RPM maintains a counter of the masters i.e APPS, MPPS etc +number of times the SoC entered a deeper sleep mode involving +lowering or powering down the backbone rails - Cx and Mx and +the oscillator clock, XO. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,rpm-master-stats". + +- reg: + Usage: required + Value type: + Definition: The address on the RPM RAM from where the stats are read + should be provided as "phys_addr_base". The offset + from which the stats are available should be provided as + "offset_addr". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. + +- qcom,masters: + Usage: required + Value tye: + Defination: Provides the masters list. + +qcom,master-offset: + Usage: required + Value tye: + Defination: Provides the masters list + +EXAMPLE: + +qcom,rpm-master-stats@60150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x45f0150 0x5000>; + qcom,masters = "APSS", "MPSS", "ADSP", "CDSP", "TZ"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm_stats.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm_stats.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b4bc6a8ee5e597a32824ccbd9b5f5dd63272d28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpm_stats.txt @@ -0,0 +1,40 @@ +* RPM Stats + +RPM maintains a counter of the number of times the SoC entered a deeper sleep +mode involving lowering or powering down the backbone rails - Cx and Mx and +the oscillator clock, XO. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,rpm-stats". + +- reg: + Usage: required + Value type: + Definition: The address on the RPM RAM from where the stats are read + should be provided as "phys_addr_base". The offset from + which the stats are available should be provided as + "offset_addr". + +- reg-names: + Usage: required + Value type: + Definition: Provides labels for the reg property. + +- qcom,num-records: + Usage: optional + Value type: + Definition: Specifies number of records to read from RPM RAM. + +EXAMPLE: + + qcom,rpm-stats@c000000 { + compatible = "qcom,rpm-stats"; + reg = <0xC000000 0x1000>, <0x3F0000 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + qcom,num-records = <3>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpmh-master-stat.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpmh-master-stat.txt new file mode 100644 index 0000000000000000000000000000000000000000..a53eba57f89dbd255c056cdb0a290f7d97108ec3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/rpmh-master-stat.txt @@ -0,0 +1,31 @@ +* RPMH Master Stats + +Differet Subsystems maintains master data in SMEM. +It tells about the individual masters information at any given +time like "system sleep counts", "system sleep last entered at" +and "system sleep accumulated duration" etc. These stats can be +displayed using the sysfs interface. +To achieve this, device tree node has been added. + +Additionally, RPMH master stats also maintains application processor's +master stats. It uses profiling units to calculate power down and power +up stats. + +The required properties for rpmh-master-stats are: + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,rpmh-master-stats-v1". + +- reg: + Usage: required + Value type: + Definition: Specifies physical address of start of profiling unit. + +Example: + +qcom,rpmh-master-stats { + compatible = "qcom,rpmh-master-stats"; + reg = <0xb221200 0x60>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/sleepstate-smp2p.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/sleepstate-smp2p.txt new file mode 100644 index 0000000000000000000000000000000000000000..d82d521b60f00d515ec1c0ef39ece3827707a1f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/sleepstate-smp2p.txt @@ -0,0 +1,19 @@ +Qualcomm Technologies, Inc. SMSM Point-to-Point (SMP2P) Sleepstate driver + +Required properties: +-compatible : should be one of the following: +- "qcom,smp2p-sleepstate" +-qcom,smem-states : the relevant outgoing smp2p entry +- interrupt-parent: specifies the phandle to the parent interrupt controller + this one is cascaded from +- interrupts: specifies the interrupt number, the irq line to be used +- interrupt-names: Interrupt name string, must be "smp2p-sleepstate-in" + +Example: +qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/spcom.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/spcom.txt new file mode 100644 index 0000000000000000000000000000000000000000..dca2a47d530ca95679272c30bf864d06b4e4321e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/spcom.txt @@ -0,0 +1,26 @@ +Qualcomm Technologies, Inc. Secure Proccessor Communication (spcom) + +Required properties: +-compatible : should be "qcom,spcom" +-qcom,spcom-ch-names: predefined channels name string +-qcom,spcom-sp2soc-rmb-reg-addr: Secure Processor to SOC shared + register physical address +-qcom,spcom-sp2soc-rmb-initdone-bit: bit indicating Secure + Processor init-done +-qcom,spcom-sp2soc-rmb-pbldone-bit: bit indicating Secure + Processor bootloader-done +-qcom,spcom-soc2sp-rmb-reg-addr: SOC to Secure Processor shared + register physical address +-qcom,spcom-soc2sp-rmb-sp-ssr-bit: bit indicating Secure + Processor subsystem reset + +Example: + qcom,spcom { + compatible = "qcom,spcom"; + qcom,spcom-ch-names = "sp_kernel" , "sp_ssr"; + qcom,spcom-sp2soc-rmb-reg-addr = <0x01881020>; + qcom,spcom-sp2soc-rmb-initdone-bit = <24>; + qcom,spcom-sp2soc-rmb-pbldone-bit = <25>; + qcom,spcom-soc2sp-rmb-reg-addr = <0x01881030>; + qcom,spcom-soc2sp-rmb-sp-ssr-bit = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/spm-v2.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/spm-v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..d44ab56b9f48776ba0aa3469aa5b45af5bbdba68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/spm-v2.txt @@ -0,0 +1,173 @@ +* MSM Subsystem Power Manager (spm-v2) + +S4 generation of MSMs have SPM hardware blocks to control the Application +Processor Sub-System power. These SPM blocks run individual state machine +to determine what the core (L2 or Krait/Scorpion) would do when the WFI +instruction is executed by the core. The SAW hardware block handles SPM and +AVS functionality for the cores. + +The devicetree representation of the SPM block should be: + +Required properties + +- compatible: "qcom,spm-v2" +- reg: The physical address and the size of the SPM's memory mapped registers +- qcom,cpu: phandle for the CPU that the SPM block is attached to. This field +is required on only for SPMs that control the CPU. This field is not required +for SPMs that control L2/CCI/L3 +- qcom,saw2-ver-reg: The location of the version register +- qcom,name: The name with which a SPM device is identified by the power +management code. + +---------------------------------------------------- +Non-PSCI targets should follow the rules shown below +---------------------------------------------------- +Required properties for only Non-PSCI targets: + +- qcom,saw2-cfg: SAW2 configuration register +- qcom,saw2-spm-ctl: The SPM control register +- qcom,saw2-spm-dly: Provides the values for the SPM delay command in the SPM + sequence + +Optional properties for only Non-PSCI targets +- reg-names: Register names for the physical address required if spm device + has more than one physical addressed to be mapped. Allowed register + names are: "saw-base", "q2s", "hw-flush", "slpreq" +- qcom,saw2-avs-ctl: The AVS control register +- qcom,saw2-avs-hysterisis: The AVS hysterisis register to delay the AVS + controller requests +- qcom,vctl-timeout-us: The timeout value in us to wait for voltage to change + after sending the voltage command to the PMIC +- qcom,saw2-avs-limit: The AVS limit register +- qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values + between AVS controller requests +- qcom,saw2-pmic-data0..7: Specify the pmic data value and the associated FTS + index to send the PMIC data to +- qcom,vctl-port: The PVC (PMIC Virtual Channel) port used for changing + voltage +- qcom,vctl-port-ub: The PVC (PMIC Virtual Channel) port used for changing + voltage +- qcom,phase-port: The PVC port used for changing the number of phases +- qcom,pfm-port: The PVC port used for enabling PWM/PFM modes +- qcom,cpu-vctl-mask: Mask of cpus, whose voltage the spm device can control. + Depricated: Replaced with cpu-vctl-list when cpu phandles are available. +- qcom,cpu-vctl-list: List of cpu node phandles, whose voltage the spm device + can control. +- qcom,use-qchannel-for-pc: Boolean property to specify if qchannel should be + ignored when entering power collapse. If this property is set qchannel + will not be ignored in power collapse. +- qcom,supports-rpm-hs: Indicates that this SPM instance allow handshake with +RPM processor when executing the sleep command in the SPM sequence. Supported +only on SAW2 v3.0 and above. +- qcom,use-spm-clock-gating: This boolean property is used to indicate that + the SPM needs to be used for clock gating. Using the SPM for clock + gating would result in auto clock gating being disabled. Use this on + targets that do not support or do not use auto clock gating. +- qcom,use-qchannel-for-wfi: This boolean property is used to indicate + that the SPM gets triggerd by the qchannel and not by means of + wfi. So a wfe could trigger a spm for clock gating as well. +- modes: Lists all the available low power modes for the device + +Second level properties for modes + +Required properties (if modes node is available) +- qcom,label: Specifies the mode name such as: + qcom,saw2-spm-cmd-wfi: WFI mode + qcom,saw2-spm-cmd-ret: Retention mode + qcom,saw2-spm-cmd-spc: Standalone PC mode + qcom,saw2-spm-cmd-pc: Power Collapse mode + qcom,saw2-spm-cmd-gdhs: GDHS mode +- qcom,sequence: Specifies sequence for the low power mode +Optional properties +- qcom,pc_mode: Specifies pc_mode bit should be set in the SPM control register +- qcom,ret_mode: Specifies ret_mode bit should be set in the SPM control register +- qcom,spm_en: Specifies spm_en bit should be set in the SPM control register +- qcom,isar: Specifies isar bit should be set in the SPM control register + Specify this property only if SPM should retain its start address at + the end of the program. +- qcom,slp_cmd_mode: Specifies slp_cmd_mode bit should be set in SPM control register. + Adding this property results in SPM handshaking with RPM. Please remove + the RPM handshake command from the sleep sequence, replace that with + Sleep without RPM handshake command. +- qcom,event_sync: Specifies event_sync byte should be set in SPM control + register. + +---------------------------------------------------- +PSCI targets should follow the rules shown below +---------------------------------------------------- +Optional properties for only PSCI targets: + +- qcom,saw2-avs-ctl: The AVS control register +- qcom,saw2-avs-hysterisis: The AVS hysterisis register to delay the AVS + controller requests +- qcom,vctl-timeout-us: The timeout value in us to wait for voltage to change + after sending the voltage command to the PMIC +- qcom,saw2-avs-limit: The AVS limit register +- qcom,saw2-avs-dly: The AVS delay register is used to specify the delay values + between AVS controller requests +- qcom,vctl-port: The PVC (PMIC Virtual Channel) port used for changing + voltage +- qcom,vctl-port-ub: The PVC (PMIC Virtual Channel) port used for changing + voltage +- qcom,phase-port: The PVC port used for changing the number of phases +- qcom,pfm-port: The PVC port used for enabling PWM/PFM modes +- qcom,cpu-vctl-list: List of cpu node phandles, whose voltage the spm device + can control. + + +Example 1: + qcom,spm@f9089000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xf9089000 0x1000>; + qcom,cpu = <&CPU0>; + qcom,saw2-ver-reg = <0xfd0>; + qcom,saw2-cfg = <0x1b>; + qcom,saw2-avs-ctl = <0>; + qcom,saw2-avs-hysteresis = <0>; + qcom,saw2-avs-limit = <0>; + qcom,saw2-avs-dly= <0>; + qcom,saw2-spm-dly= <0x20000400>; + qcom,saw2-spm-ctl = <0x1>; + qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,mode0 { + qcom,label = "qcom,saw2-spm-cmd-wfi"; + qcom,sequence = [03 0b 0f]; + qcom,spm_en; + }; + + qcom,mode1 { + qcom,label = "qcom,saw2-spm-cmd-spc"; + qcom,sequence = [00 20 50 80 60 70 10 92 + a0 b0 03 68 70 3b 92 a0 b0 + 82 2b 50 10 30 02 22 30 0f]; + qcom,spm_en; + qcom,pc_mode; + }; + + qcom,mode2 { + qcom,label = "qcom,saw2-spm-cmd-pc"; + qcom,sequence = [00 20 10 92 a0 b0 07 3b 92 + a0 b0 82 10 30 02 22 30 0f]; + qcom,spm_en; + qcom,pc_mode; + }; + }; + +Example 2: + qcom,spm@9A10000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x9A10000 0x1000>; + qcom,name = "system-cbf"; /* CBF SAW */ + qcom,saw2-ver-reg = <0xFD0>; + qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,vctl-timeout-us = <50>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,saw2-avs-ctl = <0x1100>; + qcom,pfm-port = <0x2>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/spss_utils.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/spss_utils.txt new file mode 100644 index 0000000000000000000000000000000000000000..e46984c0591d29db9099d364c03e83a7009e5339 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/spss_utils.txt @@ -0,0 +1,55 @@ +Qualcomm Technologies, Inc. Secure Processor SubSystem Utilities (spss_utils) + +The Secure Processor SubSystem (SPSS) is a dedicated subsystem for security. +It has its own CPU, memories, and cryptographic engine. +It shall provide cryptographic services to other subsystems. +The SPSS firmware is loaded by PIL driver. +The communication with SPSS is done via spcom driver, using glink. + +The spss_utils driver selects the SPSS firmware file, +according to a dedicated fuse and the platform HW version. + +The spss_utils driver supports SPU Insider Attack Resistance (IAR) Feature. +SPU ROM code (PBL) expects a unique cmac for the spu firmware and spu apps. +The spss_utils driver registers an IAR callback to the PIL notification driver. +When SPU reset detected (SSR) the PIL calls the IAR callback to place the +required cmac in shared memory in DDR. + +Required properties: +-compatible : should be "qcom,spss_utils" +-qcom,spss-fuse1-addr: fuse1 register physical address +-qcom,spss-fuse1-bit: fuse1 relevant bit +-qcom,spss-fuse2-addr: fuse2 register physical address +-qcom,spss-fuse2-bit: fuse2 relevant bit +-qcom,spss-fuse3-addr: fuse3 register physical address +-qcom,spss-fuse3-bit: fuse3 relevant bit +-qcom,spss-fuse4-addr: fuse4 register physical address +-qcom,spss-fuse4-bit: fuse4 relevant bit +-qcom,spss-dev-firmware-name: dev firmware file name +-qcom,spss-test-firmware-name: test firmware file name +-qcom,spss-prod-firmware-name: production firmware file name +-qcom,spss-debug-reg-addr: debug register physical address +-qcom,spss-emul-type-reg-addr: soc emulation type register physical address +-qcom,pil-mem: pointer to pil_spss_mem node, to get PIL memory address +-qcom,pil-mem: PIL memory size, spu firmware size is padded to 960 KB + +Example: +spss_utils: qcom,spss_utils { + compatible = "qcom,spss-utils"; + + qcom,spss-fuse1-addr = <0x00780234>; + qcom,spss-fuse1-bit = <27>; + qcom,spss-fuse2-addr = <0x00780234>; + qcom,spss-fuse2-bit = <26>; + qcom,spss-fuse3-addr = <0x007801E8>; + qcom,spss-fuse3-bit = <10>; + qcom,spss-fuse4-addr = <0x00780218>; + qcom,spss-fuse4-bit = <1>; + qcom,spss-dev-firmware-name = "spss1d"; /* 8 chars max */ + qcom,spss-test-firmware-name = "spss1t"; /* 8 chars max */ + qcom,spss-prod-firmware-name = "spss1p"; /* 8 chars max */ + qcom,spss-debug-reg-addr = <0x01886020>; + qcom,spss-emul-type-reg-addr = <0x01fc8004>; + pil-mem = <&pil_spss_mem>; + qcom,pil-size = <0x0F0000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/ssbi.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/ssbi.txt new file mode 100644 index 0000000000000000000000000000000000000000..54fd5ced34014c773446ab0142f732225fced68f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/ssbi.txt @@ -0,0 +1,18 @@ +* Qualcomm SSBI + +Some Qualcomm MSM devices contain a point-to-point serial bus used to +communicate with a limited range of devices (mostly power management +chips). + +These require the following properties: + +- compatible: "qcom,ssbi" + +- qcom,controller-type + indicates the SSBI bus variant the controller should use to talk + with the slave device. This should be one of "ssbi", "ssbi2", or + "pmic-arbiter". The type chosen is determined by the attached + slave. + +The slave device should be the single child node of the ssbi device +with a compatible field. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/system_pm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/system_pm.txt new file mode 100644 index 0000000000000000000000000000000000000000..9628d9e64a81c83f466417d21fd835fe35cf9a11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/system_pm.txt @@ -0,0 +1,29 @@ +SYSTEM PM + +System PM device is a virtual device that handles all CPU subsystem low power +mode activties. When entering core shutdown, resource state that were requested +from the processor may be relinquished and set to idle and restored when the +cores are brought out of sleep. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,system-pm". + +-mboxes: + Usage: optional + Value type: + Definition: phandle the TCS mailbox controller for the CPU subsystem. + This property is generally set only for SoCs that use RPMH communication + through a mailbox controller. + +EXAMPLE + + system_pm { + compatible = "qcom,system-pm"; + mboxes = <&apps_rsc 0>; + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/tz-log.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/tz-log.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7e84a35e91d9b6ef3d5ef5a53e5b57fe4d6e09a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/tz-log.txt @@ -0,0 +1,24 @@ +* TZLOG (Trust Zone Log) + +The tz_log driver is a platform device driver that exposes a debugfs +interface for accessing and displaying diagnostic information +related to secure code (Trustzone/QSEE). + +Required properties: +- compatible : Should be "qcom,tz-log" +- reg : Offset and size of the register set for the device + +Optional properties: +- qcom,hyplog-enabled : (boolean) indicates if driver supports HYP logger service. +- hyplog-address-offset : Register offset to get the HYP log base address. +- hyplog-size-offset : Register offset to get the HYP log size parameter. + +Example: + + qcom,tz-log@fe805720 { + compatible = "qcom,tz-log"; + reg = <0xfe805720 0x1000>; + qcom,hyplog-enabled; + hyplog-address-offset = 0x410; + hyplog-size-offset = 0x414; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/msm/wil6210.txt b/arch/arm64/boot/dts/vendor/bindings/arm/msm/wil6210.txt new file mode 100644 index 0000000000000000000000000000000000000000..633a23cdab92961604ce3843f1acf7377861d3f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/msm/wil6210.txt @@ -0,0 +1,89 @@ +wil6210 - Qualcomm Technologies Inc. 802.11ad Wireless Driver + +wil6210 driver is responsible for managing 802.11ad chipset +connected to MSM over PCIe interface. + +The platform data is needed in order to perform proper +bus-scaling and SMMU initialization by the driver. + +Required properties: + +- compatible: "qcom,wil6210" +- qcom,pcie-parent: phandle for the PCIe root complex to which 11ad card is connected +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for + the below optional properties: + - qcom,msm-bus,name + - qcom,msm-bus,num-cases + - qcom,msm-bus,num-paths + - qcom,msm-bus,vectors-KBps + +Optional properties: +- qcom,sleep-clk-en: GPIO for sleep clock used for low power modes by 11ad card +- qcom,wigig-en: Enable GPIO connected to 11ad card +- qcom,wigig-dc: Enable DC to DC GPIO connected to 11ad card +- qcom,use-ext-supply: Boolean flag to indicate if 11ad SIP uses external power supply +- vdd-supply: phandle to 11ad VDD regulator node +- vddio-supply: phandle to 11ad VDDIO regulator node +- vdd-ldo-supply: phandle to 11ad VDD LDO regulator node +- qcom,use-ext-clocks: Boolean flag to indicate if 11ad SIP uses external clocks +- clocks : List of phandle and clock specifier pairs +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. +- qcom,keep-radio-on-during-sleep: Boolean flag to indicate if to suspend to d3hot + instead of turning off the device +- qcom,use-ap-power-save: Boolean flag to indicate if AP power save feature is + enabled + +Example: + wil6210: qcom,wil6210 { + compatible = "qcom,wil6210"; + qcom,pcie-parent = <&pcie1>; + qcom,wigig-en = <&tlmm 94 0>; + qcom,wigig-dc = <&tlmm 81 0>; + qcom,msm-bus,name = "wil6210"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 600000 800000>; /* ~4.6Gbps (MCS12) */ + qcom,use-ext-supply; + vdd-supply= <&pm8998_s7>; + vddio-supply= <&pm8998_s5>; + vdd-ldo-supply = <&pm8150_l15>; + qcom,use-ext-clocks; + clocks = <&clock_gcc clk_rf_clk3>, + <&clock_gcc clk_rf_clk3_pin>; + clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; + qcom,keep-radio-on-during-sleep; + qcom,use-ap-power-save; + }; + +Wil6210 client node under PCIe RP node needed for SMMU initialization by +PCI framework when devices are discovered. + +Required properties: + +- qcom,iommu-dma-addr-pool: specifies the base address and size of SMMU space +- qcom,iommu-dma: define the SMMU mode - bypass/fastmap/disabled +- qcom,iommu-pagetable: indicating SMMU dma and page table coherency + +Example: +&pcie1_rp { + #address-cells = <5>; + #size-cells = <0>; + + wil6210_pci: wil6210_pci { + reg = <0 0 0 0 0>; + + #address-cells = <1>; + #size-cells = <1>; + + qcom,iommu-group = <&wil6210_pci_iommu_group>; + + wil6210_pci_iommu_group: wil6210_pci_iommu_group { + qcom,iommu-dma-addr-pool = <0x20000000 0xe0000000>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-pagetable = "coherent"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/npcm/npcm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/npcm/npcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d87d9ecea85b67f10f1665f1355fe6cf85d4a2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/npcm/npcm.txt @@ -0,0 +1,6 @@ +NPCM Platforms Device Tree Bindings +----------------------------------- +NPCM750 SoC +Required root node properties: + - compatible = "nuvoton,npcm750"; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/nspire.txt b/arch/arm64/boot/dts/vendor/bindings/arm/nspire.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d08518bd176f117b786e1e602f2577517570528 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/nspire.txt @@ -0,0 +1,14 @@ +TI-NSPIRE calculators + +Required properties: +- compatible: Compatible property value should contain "ti,nspire". + CX models should have "ti,nspire-cx" + Touchpad models should have "ti,nspire-tp" + Clickpad models should have "ti,nspire-clp" + +Example: + +/ { + model = "TI-NSPIRE CX"; + compatible = "ti,nspire-cx"; + ... diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/nxp/lpc32xx.txt b/arch/arm64/boot/dts/vendor/bindings/arm/nxp/lpc32xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..56ec8ddc4a3b0402fca7897d478e407896b928cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/nxp/lpc32xx.txt @@ -0,0 +1,8 @@ +NXP LPC32xx Platforms Device Tree Bindings +------------------------------------------ + +Boards with the NXP LPC32xx SoC shall have the following properties: + +Required root node property: + +compatible: must be "nxp,lpc3220", "nxp,lpc3230", "nxp,lpc3240" or "nxp,lpc3250" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/olimex.txt b/arch/arm64/boot/dts/vendor/bindings/arm/olimex.txt new file mode 100644 index 0000000000000000000000000000000000000000..d726aeca56be1e6e5814668685ccb7742e809caf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/olimex.txt @@ -0,0 +1,10 @@ +Olimex Device Tree Bindings +--------------------------- + +SAM9-L9260 Board +Required root node properties: + - compatible = "olimex,sam9-l9260", "atmel,at91sam9260"; + +i.MX23 Olinuxino Low Cost Board +Required root node properties: + - compatible = "olimex,imx23-olinuxino", "fsl,imx23"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/counter.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/counter.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bd8aa0913157b6bf5cef98dd4cdad4e3e2e36e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/counter.txt @@ -0,0 +1,15 @@ +OMAP Counter-32K bindings + +Required properties: +- compatible: Must be "ti,omap-counter32k" for OMAP controllers +- reg: Contains timer register address range (base address and length) +- ti,hwmods: Name of the hwmod associated to the counter, which is typically + "counter_32k" + +Example: + +counter32k: counter@4a304000 { + compatible = "ti,omap-counter32k"; + reg = <0x4a304000 0x20>; + ti,hwmods = "counter_32k"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/crossbar.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/crossbar.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cd5d873fc3a9814fc522234361a64945c57d7e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/crossbar.txt @@ -0,0 +1,55 @@ +Some socs have a large number of interrupts requests to service +the needs of its many peripherals and subsystems. All of the +interrupt lines from the subsystems are not needed at the same +time, so they have to be muxed to the irq-controller appropriately. +In such places a interrupt controllers are preceded by an CROSSBAR +that provides flexibility in muxing the device requests to the controller +inputs. + +Required properties: +- compatible : Should be "ti,irq-crossbar" +- reg: Base address and the size of the crossbar registers. +- interrupt-controller: indicates that this block is an interrupt controller. +- ti,max-irqs: Total number of irqs available at the parent interrupt controller. +- ti,max-crossbar-sources: Maximum number of crossbar sources that can be routed. +- ti,reg-size: Size of a individual register in bytes. Every individual + register is assumed to be of same size. Valid sizes are 1, 2, 4. +- ti,irqs-reserved: List of the reserved irq lines that are not muxed using + crossbar. These interrupt lines are reserved in the soc, + so crossbar bar driver should not consider them as free + lines. + +Optional properties: +- ti,irqs-skip: This is similar to "ti,irqs-reserved", but these are for + SOC-specific hard-wiring of those irqs which unexpectedly bypasses the + crossbar. These irqs have a crossbar register, but still cannot be used. + +- ti,irqs-safe-map: integer which maps to a safe configuration to use + when the interrupt controller irq is unused (when not provided, default is 0) + +Examples: + crossbar_mpu: crossbar@4a002a48 { + compatible = "ti,irq-crossbar"; + reg = <0x4a002a48 0x130>; + ti,max-irqs = <160>; + ti,max-crossbar-sources = <400>; + ti,reg-size = <2>; + ti,irqs-reserved = <0 1 2 3 5 6 131 132>; + ti,irqs-skip = <10 133 139 140>; + }; + +Consumer: +======== +See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt and +Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt for +further details. + +An interrupt consumer on an SoC using crossbar will use: + interrupts = + +Example: + device_x@4a023000 { + /* Crossbar 8 used */ + interrupts = ; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/ctrl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/ctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..f35b77920786decfcda94a82aaf61c607c2c8722 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/ctrl.txt @@ -0,0 +1,82 @@ +OMAP Control Module bindings + +Control Module contains miscellaneous features under it based on SoC type. +Pincontrol is one common feature, and it has a specialized support +described in [1]. Typically some clock nodes are also under control module. +Syscon is used to share register level access to drivers external to +control module driver itself. + +See [2] for documentation about clock/clockdomain nodes. + +[1] Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt +[2] Documentation/devicetree/bindings/clock/ti/* + +Required properties: +- compatible: Must be one of: + "ti,am3-scm" + "ti,am4-scm" + "ti,dm814-scrm" + "ti,dm816-scrm" + "ti,omap2-scm" + "ti,omap3-scm" + "ti,omap4-scm-core" + "ti,omap4-scm-padconf-core" + "ti,omap4-scm-wkup" + "ti,omap4-scm-padconf-wkup" + "ti,omap5-scm-core" + "ti,omap5-scm-padconf-core" + "ti,omap5-scm-wkup-pad-conf" + "ti,dra7-scm-core" +- reg: Contains Control Module register address range + (base address and length) + +Optional properties: +- clocks: clocks for this module +- clockdomains: clockdomains for this module + +Examples: + +scm: scm@2000 { + compatible = "ti,omap3-scm", "simple-bus"; + reg = <0x2000 0x2000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x2000 0x2000>; + + omap3_pmx_core: pinmux@30 { + compatible = "ti,omap3-padconf", + "pinctrl-single"; + reg = <0x30 0x230>; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0xff1f>; + }; + + scm_conf: scm_conf@270 { + compatible = "syscon"; + reg = <0x270 0x330>; + #address-cells = <1>; + #size-cells = <1>; + + scm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + scm_clockdomains: clockdomains { + }; +} + +&scm_clocks { + mcbsp5_mux_fck: mcbsp5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + reg = <0x02d8>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/dmm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/dmm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8bd6d0a238a88ff243ed7478679e830f6423a989 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/dmm.txt @@ -0,0 +1,22 @@ +OMAP Dynamic Memory Manager (DMM) bindings + +The dynamic memory manager (DMM) is a module located immediately in front of the +SDRAM controllers (called EMIFs on OMAP). DMM manages various aspects of memory +accesses such as priority generation amongst initiators, configuration of SDRAM +interleaving, optimizing transfer of 2D block objects, and provide MMU-like page +translation for initiators which need contiguous dma bus addresses. + +Required properties: +- compatible: Should contain "ti,omap4-dmm" for OMAP4 family + Should contain "ti,omap5-dmm" for OMAP5 and DRA7x family +- reg: Contains DMM register address range (base address and length) +- interrupts: Should contain an interrupt-specifier for DMM_IRQ. +- ti,hwmods: Name of the hwmod associated to DMM, which is typically "dmm" + +Example: + +dmm@4e000000 { + compatible = "ti,omap4-dmm"; + reg = <0x4e000000 0x800>; + ti,hwmods = "dmm"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/dsp.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/dsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3830a32ce08596a32c3638e05ddd15877f7925d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/dsp.txt @@ -0,0 +1,14 @@ +* TI - DSP (Digital Signal Processor) + +TI DSP included in OMAP SoC + +Required properties: +- compatible : Should be "ti,omap3-c64" for OMAP3 & 4 +- ti,hwmods: "dsp" + +Examples: + +dsp { + compatible = "ti,omap3-c64"; + ti,hwmods = "dsp"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/iva.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/iva.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d629517135880cc5519280acc84768b076cbaa9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/iva.txt @@ -0,0 +1,19 @@ +* TI - IVA (Imaging and Video Accelerator) subsystem + +The IVA contain various audio, video or imaging HW accelerator +depending of the version. + +Required properties: +- compatible : Should be: + - "ti,ivahd" for OMAP4 + - "ti,iva2.2" for OMAP3 + - "ti,iva2.1" for OMAP2430 + - "ti,iva1" for OMAP2420 +- ti,hwmods: "iva" + +Examples: + +iva { + compatible = "ti,ivahd", "ti,iva"; + ti,hwmods = "iva"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/l3-noc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/l3-noc.txt new file mode 100644 index 0000000000000000000000000000000000000000..161448da959d26edeb19de7db2561564c4c473dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/l3-noc.txt @@ -0,0 +1,23 @@ +* TI - L3 Network On Chip (NoC) + +This version is an implementation of the generic NoC IP +provided by Arteris. + +Required properties: +- compatible : Should be "ti,omap3-l3-smx" for OMAP3 family + Should be "ti,omap4-l3-noc" for OMAP4 family + Should be "ti,omap5-l3-noc" for OMAP5 family + Should be "ti,dra7-l3-noc" for DRA7 family + Should be "ti,am4372-l3-noc" for AM43 family +- reg: Contains L3 register address range for each noc domain. +- ti,hwmods: "l3_main_1", ... One hwmod for each noc domain. + +Examples: + +ocp { + compatible = "ti,omap4-l3-noc", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/l4.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/l4.txt new file mode 100644 index 0000000000000000000000000000000000000000..6816adcdc15f5d83cada70c26293e5fd71fb4a6a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/l4.txt @@ -0,0 +1,37 @@ +L4 interconnect bindings + +These bindings describe the OMAP SoCs L4 interconnect bus. + +Required properties: +- compatible : Should be "ti,omap2-l4" for OMAP2 family l4 core bus + Should be "ti,omap2-l4-wkup" for OMAP2 family l4 wkup bus + Should be "ti,omap3-l4-core" for OMAP3 family l4 core bus + Should be "ti,omap4-l4-cfg" for OMAP4 family l4 cfg bus + Should be "ti,omap4-l4-per" for OMAP4 family l4 per bus + Should be "ti,omap4-l4-wkup" for OMAP4 family l4 wkup bus + Should be "ti,omap5-l4-cfg" for OMAP5 family l4 cfg bus + Should be "ti,omap5-l4-wkup" for OMAP5 family l4 wkup bus + Should be "ti,dra7-l4-cfg" for DRA7 family l4 cfg bus + Should be "ti,dra7-l4-wkup" for DRA7 family l4 wkup bus + Should be "ti,am3-l4-wkup" for AM33xx family l4 wkup bus + Should be "ti,am4-l4-wkup" for AM43xx family l4 wkup bus +- ranges : contains the IO map range for the bus +- reg : registers link agent and interconnect agent and access protection +- reg-names : "la" for link agent, "ia0" to "ia3" for one to three + interconnect agent instances, "ap" for access if it exists + +Examples: + +l4: interconnect@48000000 { + compatible "ti,omap4-l4-per", "simple-bus"; + reg = <0x48000000 0x800>, + <0x48000800 0x800>, + <0x48001000 0x400>, + <0x48001400 0x400>, + <0x48001800 0x400>, + <0x48001c00 0x400>; + reg-names = "ap", "la", "ia0", "ia1", "ia2", "ia3"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x48000000 0x100000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/mpu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/mpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..f301e636fd525b9dd9fd11bffe718332f38c0da9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/mpu.txt @@ -0,0 +1,54 @@ +* TI - MPU (Main Processor Unit) subsystem + +The MPU subsystem contain one or several ARM cores +depending of the version. +The MPU contain CPUs, GIC, L2 cache and a local PRCM. + +Required properties: +- compatible : Should be "ti,omap3-mpu" for OMAP3 + Should be "ti,omap4-mpu" for OMAP4 + Should be "ti,omap5-mpu" for OMAP5 +- ti,hwmods: "mpu" + +Optional properties: +- sram: Phandle to the ocmcram node + +am335x and am437x only: +- pm-sram: Phandles to ocmcram nodes to be used for power management. + First should be type 'protect-exec' for the driver to use to copy + and run PM functions, second should be regular pool to be used for + data region for code. See Documentation/devicetree/bindings/sram/sram.txt + for more details. + +Examples: + +- For an OMAP5 SMP system: + +mpu { + compatible = "ti,omap5-mpu"; + ti,hwmods = "mpu" +}; + +- For an OMAP4 SMP system: + +mpu { + compatible = "ti,omap4-mpu"; + ti,hwmods = "mpu"; +}; + + +- For an OMAP3 monocore system: + +mpu { + compatible = "ti,omap3-mpu"; + ti,hwmods = "mpu"; +}; + +- For an AM335x system: + +mpu { + compatible = "ti,omap3-mpu"; + ti,hwmods = "mpu"; + pm-sram = <&pm_sram_code + &pm_sram_data>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/omap.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ecc712bf7075da21bd29104024a9c0fc15186f6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/omap.txt @@ -0,0 +1,209 @@ +* Texas Instruments OMAP + +OMAP is currently using a static file per SoC family to describe the +IPs present in the SoC. +On top of that an omap_device is created to extend the platform_device +capabilities and to allow binding with one or several hwmods. +The hwmods will contain all the information to build the device: +address range, irq lines, dma lines, interconnect, PRCM register, +clock domain, input clocks. +For the moment just point to the existing hwmod, the next step will be +to move data from hwmod to device-tree representation. + + +Required properties: +- compatible: Every devices present in OMAP SoC should be in the + form: "ti,XXX" +- ti,hwmods: list of hwmod names (ascii strings), that comes from the OMAP + HW documentation, attached to a device. Must contain at least + one hwmod. + +Optional properties: +- ti,no_idle_on_suspend: When present, it prevents the PM to idle the module + during suspend. +- ti,no-reset-on-init: When present, the module should not be reset at init +- ti,no-idle-on-init: When present, the module should not be idled at init +- ti,no-idle: When present, the module is never allowed to idle. + +Example: + +spinlock@1 { + compatible = "ti,omap4-spinlock"; + ti,hwmods = "spinlock"; +}; + +SoC Type (optional): + +- General Purpose devices + compatible = "ti,gp" +- High Security devices + compatible = "ti,hs" + +SoC Families: + +- OMAP2 generic - defaults to OMAP2420 + compatible = "ti,omap2" +- OMAP3 generic - defaults to OMAP3430 + compatible = "ti,omap3" +- OMAP4 generic - defaults to OMAP4430 + compatible = "ti,omap4" +- OMAP5 generic - defaults to OMAP5430 + compatible = "ti,omap5" +- DRA7 generic - defaults to DRA742 + compatible = "ti,dra7" +- AM43x generic - defaults to AM4372 + compatible = "ti,am43" + +SoCs: + +- OMAP2420 + compatible = "ti,omap2420", "ti,omap2" +- OMAP2430 + compatible = "ti,omap2430", "ti,omap2" + +- OMAP3430 + compatible = "ti,omap3430", "ti,omap3" +- AM3517 + compatible = "ti,am3517", "ti,omap3" +- OMAP3630 + compatible = "ti,omap36xx", "ti,omap3" +- AM33xx + compatible = "ti,am33xx", "ti,omap3" + +- OMAP4430 + compatible = "ti,omap4430", "ti,omap4" +- OMAP4460 + compatible = "ti,omap4460", "ti,omap4" + +- OMAP5430 + compatible = "ti,omap5430", "ti,omap5" +- OMAP5432 + compatible = "ti,omap5432", "ti,omap5" + +- DRA762 + compatible = "ti,dra762", "ti,dra7" + +- DRA742 + compatible = "ti,dra742", "ti,dra74", "ti,dra7" + +- DRA722 + compatible = "ti,dra722", "ti,dra72", "ti,dra7" + +- DRA718 + compatible = "ti,dra718", "ti,dra722", "ti,dra72", "ti,dra7" + +- AM5728 + compatible = "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7" + +- AM5726 + compatible = "ti,am5726", "ti,dra742", "ti,dra74", "ti,dra7" + +- AM5718 + compatible = "ti,am5718", "ti,dra722", "ti,dra72", "ti,dra7" + +- AM5716 + compatible = "ti,am5716", "ti,dra722", "ti,dra72", "ti,dra7" + +- AM4372 + compatible = "ti,am4372", "ti,am43" + +Boards: + +- OMAP3 BeagleBoard : Low cost community board + compatible = "ti,omap3-beagle", "ti,omap3" + +- OMAP3 Tobi with Overo : Commercial expansion board with daughter board + compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3" + +- OMAP4 SDP : Software Development Board + compatible = "ti,omap4-sdp", "ti,omap4430" + +- OMAP4 PandaBoard : Low cost community board + compatible = "ti,omap4-panda", "ti,omap4430" + +- OMAP4 DuoVero with Parlor : Commercial expansion board with daughter board + compatible = "gumstix,omap4-duovero-parlor", "gumstix,omap4-duovero", "ti,omap4430", "ti,omap4"; + +- OMAP4 VAR-STK-OM44 : Commercial dev kit with VAR-OM44CustomBoard and VAR-SOM-OM44 w/WLAN + compatible = "variscite,var-stk-om44", "variscite,var-som-om44", "ti,omap4460", "ti,omap4"; + +- OMAP4 VAR-DVK-OM44 : Commercial dev kit with VAR-OM44CustomBoard, VAR-SOM-OM44 w/WLAN and LCD touchscreen + compatible = "variscite,var-dvk-om44", "variscite,var-som-om44", "ti,omap4460", "ti,omap4"; + +- OMAP3 EVM : Software Development Board for OMAP35x, AM/DM37x + compatible = "ti,omap3-evm", "ti,omap3" + +- AM335X EVM : Software Development Board for AM335x + compatible = "ti,am335x-evm", "ti,am33xx", "ti,omap3" + +- AM335X Bone : Low cost community board + compatible = "ti,am335x-bone", "ti,am33xx", "ti,omap3" + +- AM3359 ICEv2 : Low cost Industrial Communication Engine EVM. + compatible = "ti,am3359-icev2", "ti,am33xx", "ti,omap3" + +- AM335X OrionLXm : Substation Automation Platform + compatible = "novatech,am335x-lxm", "ti,am33xx" + +- AM335X phyBOARD-WEGA: Single Board Computer dev kit + compatible = "phytec,am335x-wega", "phytec,am335x-phycore-som", "ti,am33xx" + +- AM335X CM-T335 : System On Module, built around the Sitara AM3352/4 + compatible = "compulab,cm-t335", "ti,am33xx" + +- AM335X SBC-T335 : single board computer, built around the Sitara AM3352/4 + compatible = "compulab,sbc-t335", "compulab,cm-t335", "ti,am33xx" + +- AM335X phyCORE-AM335x: Development kit + compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx" + +- AM335X UC-8100-ME-T: Communication-centric industrial computing platform + compatible = "moxa,uc-8100-me-t", "ti,am33xx"; + +- OMAP5 EVM : Evaluation Module + compatible = "ti,omap5-evm", "ti,omap5" + +- AM437x CM-T43 + compatible = "compulab,am437x-cm-t43", "ti,am4372", "ti,am43" + +- AM437x SBC-T43 + compatible = "compulab,am437x-sbc-t43", "compulab,am437x-cm-t43", "ti,am4372", "ti,am43" + +- AM43x EPOS EVM + compatible = "ti,am43x-epos-evm", "ti,am43", "ti,am438x" + +- AM437x GP EVM + compatible = "ti,am437x-gp-evm", "ti,am4372", "ti,am43" + +- AM437x SK EVM: AM437x StarterKit Evaluation Module + compatible = "ti,am437x-sk-evm", "ti,am4372", "ti,am43" + +- AM57XX CL-SOM-AM57x + compatible = "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7" + +- AM57XX SBC-AM57x + compatible = "compulab,sbc-am57x", "compulab,cl-som-am57x", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7" + +- AM5728 IDK + compatible = "ti,am5728-idk", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7" + +- AM5718 IDK + compatible = "ti,am5718-idk", "ti,am5718", "ti,dra7" + +- DRA762 EVM: Software Development Board for DRA762 + compatible = "ti,dra76-evm", "ti,dra762", "ti,dra7" + +- DRA742 EVM: Software Development Board for DRA742 + compatible = "ti,dra7-evm", "ti,dra742", "ti,dra74", "ti,dra7" + +- DRA722 EVM: Software Development Board for DRA722 + compatible = "ti,dra72-evm", "ti,dra722", "ti,dra72", "ti,dra7" + +- DRA718 EVM: Software Development Board for DRA718 + compatible = "ti,dra718-evm", "ti,dra718", "ti,dra722", "ti,dra72", "ti,dra7" + +- DM3730 Logic PD Torpedo + Wireless: Commercial System on Module with WiFi and Bluetooth + compatible = "logicpd,dm3730-torpedo-devkit", "ti,omap3630", "ti,omap3" + +- DM3730 Logic PD SOM-LV: Commercial System on Module with WiFi and Bluetooth + compatible = "logicpd,dm3730-som-lv-devkit", "ti,omap3630", "ti,omap3" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/omap/prcm.txt b/arch/arm64/boot/dts/vendor/bindings/arm/omap/prcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..3eb6d7afff14395229b36e349f13c52e87a96be8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/omap/prcm.txt @@ -0,0 +1,63 @@ +OMAP PRCM bindings + +Power Reset and Clock Manager lists the device clocks and clockdomains under +a DT hierarchy. Each TI SoC can have multiple PRCM entities listed for it, +each describing one module and the clock hierarchy under it. see [1] for +documentation about the individual clock/clockdomain nodes. + +[1] Documentation/devicetree/bindings/clock/ti/* + +Required properties: +- compatible: Must be one of: + "ti,am3-prcm" + "ti,am4-prcm" + "ti,omap2-prcm" + "ti,omap3-prm" + "ti,omap3-cm" + "ti,omap4-cm1" + "ti,omap4-prm" + "ti,omap4-cm2" + "ti,omap4-scrm" + "ti,omap5-prm" + "ti,omap5-cm-core-aon" + "ti,omap5-scrm" + "ti,omap5-cm-core" + "ti,dra7-prm" + "ti,dra7-cm-core-aon" + "ti,dra7-cm-core" + "ti,dm814-prcm" + "ti,dm816-prcm" +- reg: Contains PRCM module register address range + (base address and length) +- clocks: clocks for this module +- clockdomains: clockdomains for this module + +Example: + +cm: cm@48004000 { + compatible = "ti,omap3-cm"; + reg = <0x48004000 0x4000>; + + cm_clocks: clocks { + #address-cells = <1>; + #size-cells = <0>; + }; + + cm_clockdomains: clockdomains { + }; +} + +&cm_clocks { + omap2_32k_fck: omap_32k_fck { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; +}; + +&cm_clockdomains { + core_l3_clkdm: core_l3_clkdm { + compatible = "ti,clockdomain"; + clocks = <&sdrc_ick>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/oxnas.txt b/arch/arm64/boot/dts/vendor/bindings/arm/oxnas.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac64e60f99f1659fb1438bcd4a7def68e1b6e1d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/oxnas.txt @@ -0,0 +1,14 @@ +Oxford Semiconductor OXNAS SoCs Family device tree bindings +------------------------------------------- + +Boards with the OX810SE SoC shall have the following properties: + Required root node property: + compatible: "oxsemi,ox810se" + +Boards with the OX820 SoC shall have the following properties: + Required root node property: + compatible: "oxsemi,ox820" + +Board compatible values: + - "wd,mbwe" (OX810SE) + - "cloudengines,pogoplugv3" (OX820) diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/picoxcell.txt b/arch/arm64/boot/dts/vendor/bindings/arm/picoxcell.txt new file mode 100644 index 0000000000000000000000000000000000000000..e75c0ef51e69fc05152236b7d3faa7038217fc11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/picoxcell.txt @@ -0,0 +1,24 @@ +Picochip picoXcell device tree bindings. +======================================== + +Required root node properties: + - compatible: + - "picochip,pc7302-pc3x3" : PC7302 development board with PC3X3 device. + - "picochip,pc7302-pc3x2" : PC7302 development board with PC3X2 device. + - "picochip,pc3x3" : picoXcell PC3X3 device based board. + - "picochip,pc3x2" : picoXcell PC3X2 device based board. + +Timers required properties: + - compatible = "picochip,pc3x2-timer" + - interrupts : The single IRQ line for the timer. + - clock-freq : The frequency in HZ of the timer. + - reg : The register bank for the timer. + +Note: two timers are required - one for the scheduler clock and one for the +event tick/NOHZ. + +VIC required properties: + - compatible = "arm,pl192-vic". + - interrupt-controller. + - reg : The register bank for the device. + - #interrupt-cells : Must be 1. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/pmu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..13611a8199bbf14626c8024d0d4b4098d65efc60 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/pmu.txt @@ -0,0 +1,70 @@ +* ARM Performance Monitor Units + +ARM cores often have a PMU for counting cpu and cache events like cache misses +and hits. The interface to the PMU is part of the ARM ARM. The ARM PMU +representation in the device tree should be done as under:- + +Required properties: + +- compatible : should be one of + "apm,potenza-pmu" + "arm,armv8-pmuv3" + "arm,cortex-a73-pmu" + "arm,cortex-a72-pmu" + "arm,cortex-a57-pmu" + "arm,cortex-a53-pmu" + "arm,cortex-a35-pmu" + "arm,cortex-a17-pmu" + "arm,cortex-a15-pmu" + "arm,cortex-a12-pmu" + "arm,cortex-a9-pmu" + "arm,cortex-a8-pmu" + "arm,cortex-a7-pmu" + "arm,cortex-a5-pmu" + "arm,arm11mpcore-pmu" + "arm,arm1176-pmu" + "arm,arm1136-pmu" + "brcm,vulcan-pmu" + "cavium,thunder-pmu" + "qcom,scorpion-pmu" + "qcom,scorpion-mp-pmu" + "qcom,krait-pmu" +- interrupts : 1 combined interrupt or 1 per core. If the interrupt is a per-cpu + interrupt (PPI) then 1 interrupt should be specified. + +Optional properties: + +- interrupt-affinity : When using SPIs, specifies a list of phandles to CPU + nodes corresponding directly to the affinity of + the SPIs listed in the interrupts property. + + When using a PPI, specifies a list of phandles to CPU + nodes corresponding to the set of CPUs which have + a PMU of this type signalling the PPI listed in the + interrupts property, unless this is already specified + by the PPI interrupt specifier itself (in which case + the interrupt-affinity property shouldn't be present). + + This property should be present when there is more than + a single SPI. + + +- qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd + events. + +- secure-reg-access : Indicates that the ARMv7 Secure Debug Enable Register + (SDER) is accessible. This will cause the driver to do + any setup required that is only possible in ARMv7 secure + state. If not present the ARMv7 SDER will not be touched, + which means the PMU may fail to operate unless external + code (bootloader or security monitor) has performed the + appropriate initialisation. Note that this property is + not valid for non-ARMv7 CPUs or ARMv7 CPUs booting Linux + in Non-secure state. + +Example: + +pmu { + compatible = "arm,cortex-a9-pmu"; + interrupts = <100 101>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/primecell.txt b/arch/arm64/boot/dts/vendor/bindings/arm/primecell.txt new file mode 100644 index 0000000000000000000000000000000000000000..0df6acacfaea689098b9539f1b3d1e32592021e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/primecell.txt @@ -0,0 +1,46 @@ +* ARM Primecell Peripherals + +ARM, Ltd. Primecell peripherals have a standard id register that can be used to +identify the peripheral type, vendor, and revision. This value can be used for +driver matching. + +Required properties: + +- compatible : should be a specific name for the peripheral and + "arm,primecell". The specific name will match the ARM + engineering name for the logic block in the form: "arm,pl???" + +Optional properties: + +- arm,primecell-periphid : Value to override the h/w value with +- clocks : From common clock binding. First clock is phandle to clock for apb + pclk. Additional clocks are optional and specific to those peripherals. +- clock-names : From common clock binding. Shall be "apb_pclk" for first clock. +- dmas : From common DMA binding. If present, refers to one or more dma channels. +- dma-names : From common DMA binding, needs to match the 'dmas' property. + Devices with exactly one receive and transmit channel shall name + these "rx" and "tx", respectively. +- pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt +- pinctrl-names : Names corresponding to the numbered pinctrl states +- interrupts : one or more interrupt specifiers +- interrupt-names : names corresponding to the interrupts properties + +Example: + +serial@fff36000 { + compatible = "arm,pl011", "arm,primecell"; + arm,primecell-periphid = <0x00341011>; + + clocks = <&pclk>; + clock-names = "apb_pclk"; + + dmas = <&dma-controller 4>, <&dma-controller 5>; + dma-names = "rx", "tx"; + + pinctrl-0 = <&uart0_default_mux>, <&uart0_default_mode>; + pinctrl-1 = <&uart0_sleep_mode>; + pinctrl-names = "default","sleep"; + + interrupts = <0 11 0x4>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/psci.txt b/arch/arm64/boot/dts/vendor/bindings/arm/psci.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2c4f1d524929bb788360542690061ade0c4f543 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/psci.txt @@ -0,0 +1,111 @@ +* Power State Coordination Interface (PSCI) + +Firmware implementing the PSCI functions described in ARM document number +ARM DEN 0022A ("Power State Coordination Interface System Software on ARM +processors") can be used by Linux to initiate various CPU-centric power +operations. + +Issue A of the specification describes functions for CPU suspend, hotplug +and migration of secure software. + +Functions are invoked by trapping to the privilege level of the PSCI +firmware (specified as part of the binding below) and passing arguments +in a manner similar to that specified by AAPCS: + + r0 => 32-bit Function ID / return value + {r1 - r3} => Parameters + +Note that the immediate field of the trapping instruction must be set +to #0. + + +Main node required properties: + + - compatible : should contain at least one of: + + * "arm,psci" : For implementations complying to PSCI versions prior + to 0.2. + For these cases function IDs must be provided. + + * "arm,psci-0.2" : For implementations complying to PSCI 0.2. + Function IDs are not required and should be ignored by + an OS with PSCI 0.2 support, but are permitted to be + present for compatibility with existing software when + "arm,psci" is later in the compatible list. + + * "arm,psci-1.0" : For implementations complying to PSCI 1.0. + PSCI 1.0 is backward compatible with PSCI 0.2 with + minor specification updates, as defined in the PSCI + specification[2]. + + - method : The method of calling the PSCI firmware. Permitted + values are: + + "smc" : SMC #0, with the register assignments specified + in this binding. + + "hvc" : HVC #0, with the register assignments specified + in this binding. + +Main node optional properties: + + - cpu_suspend : Function ID for CPU_SUSPEND operation + + - cpu_off : Function ID for CPU_OFF operation + + - cpu_on : Function ID for CPU_ON operation + + - migrate : Function ID for MIGRATE operation + +Device tree nodes that require usage of PSCI CPU_SUSPEND function (ie idle +state nodes, as per bindings in [1]) must specify the following properties: + +- arm,psci-suspend-param + Usage: Required for state nodes[1] if the corresponding + idle-states node entry-method property is set + to "psci". + Value type: + Definition: power_state parameter to pass to the PSCI + suspend call. + +Example: + +Case 1: PSCI v0.1 only. + + psci { + compatible = "arm,psci"; + method = "smc"; + cpu_suspend = <0x95c10000>; + cpu_off = <0x95c10001>; + cpu_on = <0x95c10002>; + migrate = <0x95c10003>; + }; + +Case 2: PSCI v0.2 only + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + +Case 3: PSCI v0.2 and PSCI v0.1. + + A DTB may provide IDs for use by kernels without PSCI 0.2 support, + enabling firmware and hypervisors to support existing and new kernels. + These IDs will be ignored by kernels with PSCI 0.2 support, which will + use the standard PSCI 0.2 IDs exclusively. + + psci { + compatible = "arm,psci-0.2", "arm,psci"; + method = "hvc"; + + cpu_on = < arbitrary value >; + cpu_off = < arbitrary value >; + + ... + }; + +[1] Kernel documentation - ARM idle states bindings + Documentation/devicetree/bindings/arm/idle-states.txt +[2] Power State Coordination Interface (PSCI) specification + http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/qcom.txt b/arch/arm64/boot/dts/vendor/bindings/arm/qcom.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee532e705d6cd215c1c8982c35fb2b6f209d9e08 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/qcom.txt @@ -0,0 +1,57 @@ +QCOM device tree bindings +------------------------- + +Some qcom based bootloaders identify the dtb blob based on a set of +device properties like SoC and platform and revisions of those components. +To support this scheme, we encode this information into the board compatible +string. + +Each board must specify a top-level board compatible string with the following +format: + + compatible = "qcom,[-][-]-[/][-]" + +The 'SoC' and 'board' elements are required. All other elements are optional. + +The 'SoC' element must be one of the following strings: + + apq8016 + apq8074 + apq8084 + apq8096 + msm8916 + msm8974 + msm8992 + msm8994 + msm8996 + mdm9615 + ipq8074 + sdm845 + +The 'board' element must be one of the following strings: + + cdp + liquid + dragonboard + mtp + sbc + hk01 + +The 'soc_version' and 'board_version' elements take the form of v. +where the minor number may be omitted when it's zero, i.e. v1.0 is the same +as v1. If all versions of the 'board_version' elements match, then a +wildcard '*' should be used, e.g. 'v*'. + +The 'foundry_id' and 'subtype' elements are one or more digits from 0 to 9. + +Examples: + + "qcom,msm8916-v1-cdp-pm8916-v2.1" + +A CDP board with an msm8916 SoC, version 1 paired with a pm8916 PMIC of version +2.1. + + "qcom,apq8074-v2.0-2-dragonboard/1-v0.1" + +A dragonboard board v0.1 of subtype 1 with an apq8074 SoC version 2, made in +foundry 2. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/realtek.txt b/arch/arm64/boot/dts/vendor/bindings/arm/realtek.txt new file mode 100644 index 0000000000000000000000000000000000000000..95839e19ae9267857589a48e6c3676187ebf1677 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/realtek.txt @@ -0,0 +1,22 @@ +Realtek platforms device tree bindings +-------------------------------------- + + +RTD1295 SoC +=========== + +Required root node properties: + + - compatible : must contain "realtek,rtd1295" + + +Root node property compatible must contain, depending on board: + + - MeLE V9: "mele,v9" + - ProBox2 AVA: "probox2,ava" + - Zidoo X9S: "zidoo,x9s" + + +Example: + + compatible = "zidoo,x9s", "realtek,rtd1295"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/arm/rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..acfd3c773dd0e40e6ec22ec7566fb433fe90c995 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/rockchip.txt @@ -0,0 +1,220 @@ +Rockchip platforms device tree bindings +--------------------------------------- + +- 96boards RK3399 Ficus (ROCK960 Enterprise Edition) + Required root node properties: + - compatible = "vamrs,ficus", "rockchip,rk3399"; + +- Amarula Vyasa RK3288 board + Required root node properties: + - compatible = "amarula,vyasa-rk3288", "rockchip,rk3288"; + +- Asus Tinker board + Required root node properties: + - compatible = "asus,rk3288-tinker", "rockchip,rk3288"; + +- Kylin RK3036 board: + Required root node properties: + - compatible = "rockchip,kylin-rk3036", "rockchip,rk3036"; + +- MarsBoard RK3066 board: + Required root node properties: + - compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a"; + +- bq Curie 2 tablet: + Required root node properties: + - compatible = "mundoreader,bq-curie2", "rockchip,rk3066a"; + +- ChipSPARK Rayeager PX2 board: + Required root node properties: + - compatible = "chipspark,rayeager-px2", "rockchip,rk3066a"; + +- Radxa Rock board: + Required root node properties: + - compatible = "radxa,rock", "rockchip,rk3188"; + +- Radxa Rock2 Square board: + Required root node properties: + - compatible = "radxa,rock2-square", "rockchip,rk3288"; + +- Rikomagic MK808 v1 board: + Required root node properties: + - compatible = "rikomagic,mk808", "rockchip,rk3066a"; + +- Firefly Firefly-RK3288 board: + Required root node properties: + - compatible = "firefly,firefly-rk3288", "rockchip,rk3288"; + or + - compatible = "firefly,firefly-rk3288-beta", "rockchip,rk3288"; + +- Firefly Firefly-RK3288 Reload board: + Required root node properties: + - compatible = "firefly,firefly-rk3288-reload", "rockchip,rk3288"; + +- Firefly Firefly-RK3399 board: + Required root node properties: + - compatible = "firefly,firefly-rk3399", "rockchip,rk3399"; + +- Firefly roc-rk3328-cc board: + Required root node properties: + - compatible = "firefly,roc-rk3328-cc", "rockchip,rk3328"; + +- ChipSPARK PopMetal-RK3288 board: + Required root node properties: + - compatible = "chipspark,popmetal-rk3288", "rockchip,rk3288"; + +- Netxeon R89 board: + Required root node properties: + - compatible = "netxeon,r89", "rockchip,rk3288"; + +- GeekBuying GeekBox: + Required root node properties: + - compatible = "geekbuying,geekbox", "rockchip,rk3368"; + +- Google Bob (Asus Chromebook Flip C101PA): + Required root node properties: + compatible = "google,bob-rev13", "google,bob-rev12", + "google,bob-rev11", "google,bob-rev10", + "google,bob-rev9", "google,bob-rev8", + "google,bob-rev7", "google,bob-rev6", + "google,bob-rev5", "google,bob-rev4", + "google,bob", "google,gru", "rockchip,rk3399"; + +- Google Brain (dev-board): + Required root node properties: + - compatible = "google,veyron-brain-rev0", "google,veyron-brain", + "google,veyron", "rockchip,rk3288"; + +- Google Gru (dev-board): + Required root node properties: + - compatible = "google,gru-rev15", "google,gru-rev14", + "google,gru-rev13", "google,gru-rev12", + "google,gru-rev11", "google,gru-rev10", + "google,gru-rev9", "google,gru-rev8", + "google,gru-rev7", "google,gru-rev6", + "google,gru-rev5", "google,gru-rev4", + "google,gru-rev3", "google,gru-rev2", + "google,gru", "rockchip,rk3399"; + +- Google Jaq (Haier Chromebook 11 and more): + Required root node properties: + - compatible = "google,veyron-jaq-rev5", "google,veyron-jaq-rev4", + "google,veyron-jaq-rev3", "google,veyron-jaq-rev2", + "google,veyron-jaq-rev1", "google,veyron-jaq", + "google,veyron", "rockchip,rk3288"; + +- Google Jerry (Hisense Chromebook C11 and more): + Required root node properties: + - compatible = "google,veyron-jerry-rev7", "google,veyron-jerry-rev6", + "google,veyron-jerry-rev5", "google,veyron-jerry-rev4", + "google,veyron-jerry-rev3", "google,veyron-jerry", + "google,veyron", "rockchip,rk3288"; + +- Google Kevin (Samsung Chromebook Plus): + Required root node properties: + - compatible = "google,kevin-rev15", "google,kevin-rev14", + "google,kevin-rev13", "google,kevin-rev12", + "google,kevin-rev11", "google,kevin-rev10", + "google,kevin-rev9", "google,kevin-rev8", + "google,kevin-rev7", "google,kevin-rev6", + "google,kevin", "google,gru", "rockchip,rk3399"; + +- Google Mickey (Asus Chromebit CS10): + Required root node properties: + - compatible = "google,veyron-mickey-rev8", "google,veyron-mickey-rev7", + "google,veyron-mickey-rev6", "google,veyron-mickey-rev5", + "google,veyron-mickey-rev4", "google,veyron-mickey-rev3", + "google,veyron-mickey-rev2", "google,veyron-mickey-rev1", + "google,veyron-mickey-rev0", "google,veyron-mickey", + "google,veyron", "rockchip,rk3288"; + +- Google Minnie (Asus Chromebook Flip C100P): + Required root node properties: + - compatible = "google,veyron-minnie-rev4", "google,veyron-minnie-rev3", + "google,veyron-minnie-rev2", "google,veyron-minnie-rev1", + "google,veyron-minnie-rev0", "google,veyron-minnie", + "google,veyron", "rockchip,rk3288"; + +- Google Pinky (dev-board): + Required root node properties: + - compatible = "google,veyron-pinky-rev2", "google,veyron-pinky", + "google,veyron", "rockchip,rk3288"; + +- Google Speedy (Asus C201 Chromebook): + Required root node properties: + - compatible = "google,veyron-speedy-rev9", "google,veyron-speedy-rev8", + "google,veyron-speedy-rev7", "google,veyron-speedy-rev6", + "google,veyron-speedy-rev5", "google,veyron-speedy-rev4", + "google,veyron-speedy-rev3", "google,veyron-speedy-rev2", + "google,veyron-speedy", "google,veyron", "rockchip,rk3288"; + +- mqmaker MiQi: + Required root node properties: + - compatible = "mqmaker,miqi", "rockchip,rk3288"; + +- Phytec phyCORE-RK3288: Rapid Development Kit + Required root node properties: + - compatible = "phytec,rk3288-pcm-947", "phytec,rk3288-phycore-som", "rockchip,rk3288"; + +- Pine64 Rock64 board: + Required root node properties: + - compatible = "pine64,rock64", "rockchip,rk3328"; + +- Rockchip PX3 Evaluation board: + Required root node properties: + - compatible = "rockchip,px3-evb", "rockchip,px3", "rockchip,rk3188"; + +- Rockchip PX5 Evaluation board: + Required root node properties: + - compatible = "rockchip,px5-evb", "rockchip,px5", "rockchip,rk3368"; + +- Rockchip RV1108 Evaluation board + Required root node properties: + - compatible = "rockchip,rv1108-evb", "rockchip,rv1108"; + +- Rockchip RK3368 evb: + Required root node properties: + - compatible = "rockchip,rk3368-evb-act8846", "rockchip,rk3368"; + +- Rockchip R88 board: + Required root node properties: + - compatible = "rockchip,r88", "rockchip,rk3368"; + +- Rockchip RK3228 Evaluation board: + Required root node properties: + - compatible = "rockchip,rk3228-evb", "rockchip,rk3228"; + +- Rockchip RK3229 Evaluation board: + - compatible = "rockchip,rk3229-evb", "rockchip,rk3229"; + +- Rockchip RK3288 Fennec board: + Required root node properties: + - compatible = "rockchip,rk3288-fennec", "rockchip,rk3288"; + +- Rockchip RK3328 evb: + Required root node properties: + - compatible = "rockchip,rk3328-evb", "rockchip,rk3328"; + +- Rockchip RK3399 evb: + Required root node properties: + - compatible = "rockchip,rk3399-evb", "rockchip,rk3399"; + +- Rockchip RK3399 Sapphire board standalone: + Required root node properties: + - compatible = "rockchip,rk3399-sapphire", "rockchip,rk3399"; + +- Rockchip RK3399 Sapphire Excavator board: + Required root node properties: + - compatible = "rockchip,rk3399-sapphire-excavator", "rockchip,rk3399"; + +- Theobroma Systems RK3368-uQ7 Haikou Baseboard: + Required root node properties: + - compatible = "tsd,rk3368-uq7-haikou", "rockchip,rk3368"; + +- Theobroma Systems RK3399-Q7 Haikou Baseboard: + Required root node properties: + - compatible = "tsd,rk3399-q7-haikou", "rockchip,rk3399"; + +- Tronsmart Orion R68 Meta + Required root node properties: + - compatible = "tronsmart,orion-r68-meta", "rockchip,rk3368"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/rockchip/pmu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/rockchip/pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ee9b428b2f74982738cb042be9383cd3dd5749f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/rockchip/pmu.txt @@ -0,0 +1,16 @@ +Rockchip power-management-unit: +------------------------------- + +The pmu is used to turn off and on different power domains of the SoCs +This includes the power to the CPU cores. + +Required node properties: +- compatible value : = "rockchip,rk3066-pmu"; +- reg : physical base address and the size of the registers window + +Example: + + pmu@20004000 { + compatible = "rockchip,rk3066-pmu"; + reg = <0x20004000 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/rtsm-dcscb.txt b/arch/arm64/boot/dts/vendor/bindings/arm/rtsm-dcscb.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b8fbf3c00c51616e168f6485c4906fc502fb6ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/rtsm-dcscb.txt @@ -0,0 +1,19 @@ +ARM Dual Cluster System Configuration Block +------------------------------------------- + +The Dual Cluster System Configuration Block (DCSCB) provides basic +functionality for controlling clocks, resets and configuration pins in +the Dual Cluster System implemented by the Real-Time System Model (RTSM). + +Required properties: + +- compatible : should be "arm,rtsm,dcscb" + +- reg : physical base address and the size of the registers window + +Example: + + dcscb@60000000 { + compatible = "arm,rtsm,dcscb"; + reg = <0x60000000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/samsung/exynos-chipid.txt b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/exynos-chipid.txt new file mode 100644 index 0000000000000000000000000000000000000000..85c5dfd4a7203de9d128cd3b087438718a80d40f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/exynos-chipid.txt @@ -0,0 +1,12 @@ +SAMSUNG Exynos SoCs Chipid driver. + +Required properties: +- compatible : Should at least contain "samsung,exynos4210-chipid". + +- reg: offset and length of the register set + +Example: + chipid@10000000 { + compatible = "samsung,exynos4210-chipid"; + reg = <0x10000000 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/samsung/pmu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..433bfd7593acdde2740bcaf545038121f0a18f75 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/pmu.txt @@ -0,0 +1,72 @@ +SAMSUNG Exynos SoC series PMU Registers + +Properties: + - compatible : should contain two values. First value must be one from following list: + - "samsung,exynos3250-pmu" - for Exynos3250 SoC, + - "samsung,exynos4210-pmu" - for Exynos4210 SoC, + - "samsung,exynos4412-pmu" - for Exynos4412 SoC, + - "samsung,exynos5250-pmu" - for Exynos5250 SoC, + - "samsung,exynos5260-pmu" - for Exynos5260 SoC. + - "samsung,exynos5410-pmu" - for Exynos5410 SoC, + - "samsung,exynos5420-pmu" - for Exynos5420 SoC. + - "samsung,exynos5433-pmu" - for Exynos5433 SoC. + - "samsung,exynos7-pmu" - for Exynos7 SoC. + second value must be always "syscon". + + - reg : offset and length of the register set. + + - #clock-cells : must be <1>, since PMU requires once cell as clock specifier. + The single specifier cell is used as index to list of clocks + provided by PMU, which is currently: + 0 : SoC clock output (CLKOUT pin) + + - clock-names : list of clock names for particular CLKOUT mux inputs in + following format: + "clkoutN", where N is a decimal number corresponding to + CLKOUT mux control bits value for given input, e.g. + "clkout0", "clkout7", "clkout15". + + - clocks : list of phandles and specifiers to all input clocks listed in + clock-names property. + +Optional properties: + +Some PMUs are capable of behaving as an interrupt controller (mostly +to wake up a suspended PMU). In which case, they can have the +following properties: + +- interrupt-controller: indicate that said PMU is an interrupt controller + +- #interrupt-cells: must be identical to the that of the parent interrupt + controller. + + +Optional nodes: + +- nodes defining the restart and poweroff syscon children + + +Example : +pmu_system_controller: system-controller@10040000 { + compatible = "samsung,exynos5250-pmu", "syscon"; + reg = <0x10040000 0x5000>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + #clock-cells = <1>; + clock-names = "clkout0", "clkout1", "clkout2", "clkout3", + "clkout4", "clkout8", "clkout9"; + clocks = <&clock CLK_OUT_DMC>, <&clock CLK_OUT_TOP>, + <&clock CLK_OUT_LEFTBUS>, <&clock CLK_OUT_RIGHTBUS>, + <&clock CLK_OUT_CPU>, <&clock CLK_XXTI>, + <&clock CLK_XUSBXTI>; +}; + +Example of clock consumer : + +usb3503: usb3503@8 { + /* ... */ + clock-names = "refclk"; + clocks = <&pmu_system_controller 0>; + /* ... */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/samsung/samsung-boards.txt b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/samsung-boards.txt new file mode 100644 index 0000000000000000000000000000000000000000..56021bf2a916a881388b573c40a13df0c65d4cf0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/samsung-boards.txt @@ -0,0 +1,83 @@ +* Samsung's Exynos and S5P SoC based boards + +Required root node properties: + - compatible = should be one or more of the following. + - "samsung,aries" - for S5PV210-based Samsung Aries board. + - "samsung,fascinate4g" - for S5PV210-based Samsung Galaxy S Fascinate 4G (SGH-T959P) board. + - "samsung,galaxys" - for S5PV210-based Samsung Galaxy S (i9000) board. + - "samsung,artik5" - for Exynos3250-based Samsung ARTIK5 module. + - "samsung,artik5-eval" - for Exynos3250-based Samsung ARTIK5 eval board. + - "samsung,monk" - for Exynos3250-based Samsung Simband board. + - "samsung,rinato" - for Exynos3250-based Samsung Gear2 board. + - "samsung,smdkv310" - for Exynos4210-based Samsung SMDKV310 eval board. + - "samsung,trats" - for Exynos4210-based Tizen Reference board. + - "samsung,universal_c210" - for Exynos4210-based Samsung board. + - "samsung,i9300" - for Exynos4412-based Samsung GT-I9300 board. + - "samsung,i9305" - for Exynos4412-based Samsung GT-I9305 board. + - "samsung,midas" - for Exynos4412-based Samsung Midas board. + - "samsung,smdk4412", - for Exynos4412-based Samsung SMDK4412 eval board. + - "samsung,n710x" - for Exynos4412-based Samsung GT-N7100/GT-N7105 board. + - "samsung,trats2" - for Exynos4412-based Tizen Reference board. + - "samsung,smdk5250" - for Exynos5250-based Samsung SMDK5250 eval board. + - "samsung,xyref5260" - for Exynos5260-based Samsung board. + - "samsung,smdk5410" - for Exynos5410-based Samsung SMDK5410 eval board. + - "samsung,smdk5420" - for Exynos5420-based Samsung SMDK5420 eval board. + - "samsung,tm2" - for Exynos5433-based Samsung TM2 board. + - "samsung,tm2e" - for Exynos5433-based Samsung TM2E board. + +* Other companies Exynos SoC based + * FriendlyARM + - "friendlyarm,tiny4412" - for Exynos4412-based FriendlyARM + TINY4412 board. + * TOPEET + - "topeet,itop4412-elite" - for Exynos4412-based TOPEET + Elite base board. + + * Google + - "google,pi" - for Exynos5800-based Google Peach Pi + Rev 10+ board, + also: "google,pi-rev16", "google,pi-rev15", "google,pi-rev14", + "google,pi-rev13", "google,pi-rev12", "google,pi-rev11", + "google,pi-rev10", "google,peach". + + - "google,pit" - for Exynos5420-based Google Peach Pit + Rev 6+ (Exynos5420), + also: "google,pit-rev16", "google,pit-rev15", "google,pit-rev14", + "google,pit-rev13", "google,pit-rev12", "google,pit-rev11", + "google,pit-rev10", "google,pit-rev9", "google,pit-rev8", + "google,pit-rev7", "google,pit-rev6", "google,peach". + + - "google,snow-rev4" - for Exynos5250-based Google Snow board, + also: "google,snow" + - "google,snow-rev5" - for Exynos5250-based Google Snow + Rev 5+ board. + - "google,spring" - for Exynos5250-based Google Spring board. + + * Hardkernel + - "hardkernel,odroid-u3" - for Exynos4412-based Hardkernel Odroid U3. + - "hardkernel,odroid-x" - for Exynos4412-based Hardkernel Odroid X. + - "hardkernel,odroid-x2" - for Exynos4412-based Hardkernel Odroid X2. + - "hardkernel,odroid-xu" - for Exynos5410-based Hardkernel Odroid XU. + - "hardkernel,odroid-xu3" - for Exynos5422-based Hardkernel Odroid XU3. + - "hardkernel,odroid-xu3-lite" - for Exynos5422-based Hardkernel + Odroid XU3 Lite board. + - "hardkernel,odroid-xu4" - for Exynos5422-based Hardkernel Odroid XU4. + - "hardkernel,odroid-hc1" - for Exynos5422-based Hardkernel Odroid HC1. + + * Insignal + - "insignal,arndale" - for Exynos5250-based Insignal Arndale board. + - "insignal,arndale-octa" - for Exynos5420-based Insignal Arndale + Octa board. + - "insignal,origen" - for Exynos4210-based Insignal Origen board. + - "insignal,origen4412" - for Exynos4412-based Insignal Origen board. + + +Optional nodes: + - firmware node, specifying presence and type of secure firmware: + - compatible: only "samsung,secure-firmware" is currently supported + - reg: address of non-secure SYSRAM used for communication with firmware + + firmware@203f000 { + compatible = "samsung,secure-firmware"; + reg = <0x0203F000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/samsung/sysreg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/sysreg.txt new file mode 100644 index 0000000000000000000000000000000000000000..4fced6e9d5e42d18a7d7f97ec78a6c5eed4b4e98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/samsung/sysreg.txt @@ -0,0 +1,19 @@ +SAMSUNG S5P/Exynos SoC series System Registers (SYSREG) + +Properties: + - compatible : should contain two values. First value must be one from following list: + - "samsung,exynos4-sysreg" - for Exynos4 based SoCs, + - "samsung,exynos5-sysreg" - for Exynos5 based SoCs. + second value must be always "syscon". + - reg : offset and length of the register set. + +Example: + syscon@10010000 { + compatible = "samsung,exynos4-sysreg", "syscon"; + reg = <0x10010000 0x400>; + }; + + syscon@10050000 { + compatible = "samsung,exynos5-sysreg", "syscon"; + reg = <0x10050000 0x5000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/scu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/scu.txt new file mode 100644 index 0000000000000000000000000000000000000000..08a587875996b47cf25dd20f7bd7cde81f61d5ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/scu.txt @@ -0,0 +1,28 @@ +* ARM Snoop Control Unit (SCU) + +As part of the MPCore complex, Cortex-A5 and Cortex-A9 are provided +with a Snoop Control Unit. The register range is usually 256 (0x100) +bytes. + +References: + +- Cortex-A9: see DDI0407E Cortex-A9 MPCore Technical Reference Manual + Revision r2p0 +- Cortex-A5: see DDI0434B Cortex-A5 MPCore Technical Reference Manual + Revision r0p1 +- ARM11 MPCore: see DDI0360F ARM 11 MPCore Processor Technical Reference + Manial Revision r2p0 + +- compatible : Should be: + "arm,cortex-a9-scu" + "arm,cortex-a5-scu" + "arm,arm11mp-scu" + +- reg : Specify the base address and the size of the SCU register window. + +Example: + +scu@a04100000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xa0410000 0x100>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/secure.txt b/arch/arm64/boot/dts/vendor/bindings/arm/secure.txt new file mode 100644 index 0000000000000000000000000000000000000000..e31303fb233add7a7ae163fd0407cae7229e7bb4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/secure.txt @@ -0,0 +1,53 @@ +* ARM Secure world bindings + +ARM CPUs with TrustZone support have two distinct address spaces, +"Normal" and "Secure". Most devicetree consumers (including the Linux +kernel) are not TrustZone aware and run entirely in either the Normal +world or the Secure world. However some devicetree consumers are +TrustZone aware and need to be able to determine whether devices are +visible only in the Secure address space, only in the Normal address +space, or visible in both. (One example of that situation would be a +virtual machine which boots Secure firmware and wants to tell the +firmware about the layout of the machine via devicetree.) + +The general principle of the naming scheme for Secure world bindings +is that any property that needs a different value in the Secure world +can be supported by prefixing the property name with "secure-". So for +instance "secure-foo" would override "foo". For property names with +a vendor prefix, the Secure variant of "vendor,foo" would be +"vendor,secure-foo". If there is no "secure-" property then the Secure +world value is the same as specified for the Normal world by the +non-prefixed property. However, only the properties listed below may +validly have "secure-" versions; this list will be enlarged on a +case-by-case basis. + +Defining the bindings in this way means that a device tree which has +been annotated to indicate the presence of Secure-only devices can +still be processed unmodified by existing Non-secure software (and in +particular by the kernel). + +Note that it is still valid for bindings intended for purely Secure +world consumers (like kernels that run entirely in Secure) to simply +describe the view of Secure world using the standard bindings. These +secure- bindings only need to be used where both the Secure and Normal +world views need to be described in a single device tree. + +Valid Secure world properties: + +- secure-status : specifies whether the device is present and usable + in the secure world. The combination of this with "status" allows + the various possible combinations of device visibility to be + specified. If "secure-status" is not specified it defaults to the + same value as "status"; if "status" is not specified either then + both default to "okay". This means the following combinations are + possible: + + /* Neither specified: default to visible in both S and NS */ + secure-status = "okay"; /* visible in both */ + status = "okay"; /* visible in both */ + status = "okay"; secure-status = "okay"; /* visible in both */ + secure-status = "disabled"; /* NS-only */ + status = "okay"; secure-status = "disabled"; /* NS-only */ + status = "disabled"; secure-status = "okay"; /* S-only */ + status = "disabled"; /* disabled in both */ + status = "disabled"; secure-status = "disabled"; /* disabled in both */ diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/shmobile.txt b/arch/arm64/boot/dts/vendor/bindings/arm/shmobile.txt new file mode 100644 index 0000000000000000000000000000000000000000..89b4a389fbc7cb3e886a7ecab2ac240adb3592f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/shmobile.txt @@ -0,0 +1,161 @@ +Renesas SH-Mobile, R-Mobile, and R-Car Platform Device Tree Bindings +-------------------------------------------------------------------- + +SoCs: + + - Emma Mobile EV2 + compatible = "renesas,emev2" + - RZ/A1H (R7S72100) + compatible = "renesas,r7s72100" + - SH-Mobile AG5 (R8A73A00/SH73A0) + compatible = "renesas,sh73a0" + - R-Mobile APE6 (R8A73A40) + compatible = "renesas,r8a73a4" + - R-Mobile A1 (R8A77400) + compatible = "renesas,r8a7740" + - RZ/G1H (R8A77420) + compatible = "renesas,r8a7742" + - RZ/G1M (R8A77430) + compatible = "renesas,r8a7743" + - RZ/G1N (R8A77440) + compatible = "renesas,r8a7744" + - RZ/G1E (R8A77450) + compatible = "renesas,r8a7745" + - RZ/G1C (R8A77470) + compatible = "renesas,r8a77470" + - R-Car M1A (R8A77781) + compatible = "renesas,r8a7778" + - R-Car H1 (R8A77790) + compatible = "renesas,r8a7779" + - R-Car H2 (R8A77900) + compatible = "renesas,r8a7790" + - R-Car M2-W (R8A77910) + compatible = "renesas,r8a7791" + - R-Car V2H (R8A77920) + compatible = "renesas,r8a7792" + - R-Car M2-N (R8A77930) + compatible = "renesas,r8a7793" + - R-Car E2 (R8A77940) + compatible = "renesas,r8a7794" + - R-Car H3 (R8A77950) + compatible = "renesas,r8a7795" + - R-Car M3-W (R8A77960) + compatible = "renesas,r8a7796" + - R-Car M3-N (R8A77965) + compatible = "renesas,r8a77965" + - R-Car V3M (R8A77970) + compatible = "renesas,r8a77970" + - R-Car V3H (R8A77980) + compatible = "renesas,r8a77980" + - R-Car E3 (R8A77990) + compatible = "renesas,r8a77990" + - R-Car D3 (R8A77995) + compatible = "renesas,r8a77995" + - RZ/N1D (R9A06G032) + compatible = "renesas,r9a06g032" + +Boards: + + - Alt (RTP0RC7794SEB00010S) + compatible = "renesas,alt", "renesas,r8a7794" + - APE6-EVM + compatible = "renesas,ape6evm", "renesas,r8a73a4" + - Atmark Techno Armadillo-800 EVA + compatible = "renesas,armadillo800eva", "renesas,r8a7740" + - Blanche (RTP0RC7792SEB00010S) + compatible = "renesas,blanche", "renesas,r8a7792" + - BOCK-W + compatible = "renesas,bockw", "renesas,r8a7778" + - Condor (RTP0RC77980SEB0010SS/RTP0RC77980SEB0010SA01) + compatible = "renesas,condor", "renesas,r8a77980" + - Draak (RTP0RC77995SEB0010S) + compatible = "renesas,draak", "renesas,r8a77995" + - Eagle (RTP0RC77970SEB0010S) + compatible = "renesas,eagle", "renesas,r8a77970" + - Ebisu (RTP0RC77990SEB0010S) + compatible = "renesas,ebisu", "renesas,r8a77990" + - Genmai (RTK772100BC00000BR) + compatible = "renesas,genmai", "renesas,r7s72100" + - GR-Peach (X28A-M01-E/F) + compatible = "renesas,gr-peach", "renesas,r7s72100" + - Gose (RTP0RC7793SEB00010S) + compatible = "renesas,gose", "renesas,r8a7793" + - H3ULCB (R-Car Starter Kit Premier, RTP0RC7795SKBX0010SA00 (H3 ES1.1)) + H3ULCB (R-Car Starter Kit Premier, RTP0RC77951SKBX010SA00 (H3 ES2.0)) + compatible = "renesas,h3ulcb", "renesas,r8a7795" + - Henninger + compatible = "renesas,henninger", "renesas,r8a7791" + - iWave Systems RZ/G1C Single Board Computer (iW-RainboW-G23S) + compatible = "iwave,g23s", "renesas,r8a77470" + - iWave Systems RZ/G1E SODIMM SOM Development Platform (iW-RainboW-G22D) + compatible = "iwave,g22d", "iwave,g22m", "renesas,r8a7745" + - iWave Systems RZ/G1E SODIMM System On Module (iW-RainboW-G22M-SM) + compatible = "iwave,g22m", "renesas,r8a7745" + - iWave Systems RZ/G1M Qseven Development Platform (iW-RainboW-G20D-Qseven) + compatible = "iwave,g20d", "iwave,g20m", "renesas,r8a7743" + - iWave Systems RZ/G1M Qseven System On Module (iW-RainboW-G20M-Qseven) + compatible = "iwave,g20m", "renesas,r8a7743" + - Kingfisher (SBEV-RCAR-KF-M03) + compatible = "shimafuji,kingfisher" + - Koelsch (RTP0RC7791SEB00010S) + compatible = "renesas,koelsch", "renesas,r8a7791" + - Kyoto Microcomputer Co. KZM-A9-Dual + compatible = "renesas,kzm9d", "renesas,emev2" + - Kyoto Microcomputer Co. KZM-A9-GT + compatible = "renesas,kzm9g", "renesas,sh73a0" + - Lager (RTP0RC7790SEB00010S) + compatible = "renesas,lager", "renesas,r8a7790" + - M3ULCB (R-Car Starter Kit Pro, RTP0RC7796SKBX0010SA09 (M3 ES1.0)) + compatible = "renesas,m3ulcb", "renesas,r8a7796" + - Marzen (R0P7779A00010S) + compatible = "renesas,marzen", "renesas,r8a7779" + - Porter (M2-LCDP) + compatible = "renesas,porter", "renesas,r8a7791" + - RSKRZA1 (YR0K77210C000BE) + compatible = "renesas,rskrza1", "renesas,r7s72100" + - RZN1D-DB (RZ/N1D Demo Board for the RZ/N1D 400 pins package) + compatible = "renesas,rzn1d400-db", "renesas,r9a06g032" + - Salvator-X (RTP0RC7795SIPB0010S) + compatible = "renesas,salvator-x", "renesas,r8a7795" + - Salvator-X (RTP0RC7796SIPB0011S) + compatible = "renesas,salvator-x", "renesas,r8a7796" + - Salvator-X (RTP0RC7796SIPB0011S (M3-N)) + compatible = "renesas,salvator-x", "renesas,r8a77965" + - Salvator-XS (Salvator-X 2nd version, RTP0RC7795SIPB0012S) + compatible = "renesas,salvator-xs", "renesas,r8a7795" + - Salvator-XS (Salvator-X 2nd version, RTP0RC7796SIPB0012S) + compatible = "renesas,salvator-xs", "renesas,r8a7796" + - Salvator-XS (Salvator-X 2nd version, RTP0RC77965SIPB012S) + compatible = "renesas,salvator-xs", "renesas,r8a77965" + - SILK (RTP0RC7794LCB00011S) + compatible = "renesas,silk", "renesas,r8a7794" + - SK-RZG1E (YR8A77450S000BE) + compatible = "renesas,sk-rzg1e", "renesas,r8a7745" + - SK-RZG1M (YR8A77430S000BE) + compatible = "renesas,sk-rzg1m", "renesas,r8a7743" + - Stout (ADAS Starterkit, Y-R-CAR-ADAS-SKH2-BOARD) + compatible = "renesas,stout", "renesas,r8a7790" + - V3HSK (Y-ASK-RCAR-V3H-WS10) + compatible = "renesas,v3hsk", "renesas,r8a77980" + - V3MSK (Y-ASK-RCAR-V3M-WS10) + compatible = "renesas,v3msk", "renesas,r8a77970" + - Wheat (RTP0RC7792ASKB0000JE) + compatible = "renesas,wheat", "renesas,r8a7792" + + +Most Renesas ARM SoCs have a Product Register that allows to retrieve SoC +product and revision information. If present, a device node for this register +should be added. + +Required properties: + - compatible: Must be "renesas,prr". + - reg: Base address and length of the register block. + + +Examples +-------- + + prr: chipid@ff000044 { + compatible = "renesas,prr"; + reg = <0 0xff000044 0 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/sirf.txt b/arch/arm64/boot/dts/vendor/bindings/arm/sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b28ee6fee91cb69fa32e63f35c9414dfb9b4585 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/sirf.txt @@ -0,0 +1,11 @@ +CSR SiRFprimaII and SiRFmarco device tree bindings. +======================================== + +Required root node properties: + - compatible: + - "sirf,atlas6-cb" : atlas6 "cb" evaluation board + - "sirf,atlas6" : atlas6 device based board + - "sirf,atlas7-cb" : atlas7 "cb" evaluation board + - "sirf,atlas7" : atlas7 device based board + - "sirf,prima2-cb" : prima2 "cb" evaluation board + - "sirf,prima2" : prima2 device based board diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/sp810.txt b/arch/arm64/boot/dts/vendor/bindings/arm/sp810.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b2ab1ff5587f0f01c6755238802cff157f4881c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/sp810.txt @@ -0,0 +1,46 @@ +SP810 System Controller +----------------------- + +Required properties: + +- compatible: standard compatible string for a Primecell peripheral, + see Documentation/devicetree/bindings/arm/primecell.txt + for more details + should be: "arm,sp810", "arm,primecell" + +- reg: standard registers property, physical address and size + of the control registers + +- clock-names: from the common clock bindings, for more details see + Documentation/devicetree/bindings/clock/clock-bindings.txt; + should be: "refclk", "timclk", "apb_pclk" + +- clocks: from the common clock bindings, phandle and clock + specifier pairs for the entries of clock-names property + +- #clock-cells: from the common clock bindings; + should be: <1> + +- clock-output-names: from the common clock bindings; + should be: "timerclken0", "timerclken1", "timerclken2", "timerclken3" + +- assigned-clocks: from the common clock binding; + should be: clock specifier for each output clock of this + provider node + +- assigned-clock-parents: from the common clock binding; + should be: phandle of input clock listed in clocks + property with the highest frequency + +Example: + v2m_sysctl: sysctl@20000 { + compatible = "arm,sp810", "arm,primecell"; + reg = <0x020000 0x1000>; + clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>; + clock-names = "refclk", "timclk", "apb_pclk"; + #clock-cells = <1>; + clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; + assigned-clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_sysctl 3>, <&v2m_sysctl 3>; + assigned-clock-parents = <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/spe-pmu.txt b/arch/arm64/boot/dts/vendor/bindings/arm/spe-pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..93372f2a7df92c1f7e957b549916b52505d6e710 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/spe-pmu.txt @@ -0,0 +1,20 @@ +* ARMv8.2 Statistical Profiling Extension (SPE) Performance Monitor Units (PMU) + +ARMv8.2 introduces the optional Statistical Profiling Extension for collecting +performance sample data using an in-memory trace buffer. + +** SPE Required properties: + +- compatible : should be one of: + "arm,statistical-profiling-extension-v1" + +- interrupts : Exactly 1 PPI must be listed. For heterogeneous systems where + SPE is only supported on a subset of the CPUs, please consult + the arm,gic-v3 binding for details on describing a PPI partition. + +** Example: + +spe-pmu { + compatible = "arm,statistical-profiling-extension-v1"; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/spear-misc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/spear-misc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e404e2556b4a3df2e4131ba64ff384c24a25a755 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/spear-misc.txt @@ -0,0 +1,9 @@ +SPEAr Misc configuration +=========================== +SPEAr SOCs have some miscellaneous registers which are used to configure +few properties of different peripheral controllers. + +misc node required properties: + +- compatible Should be "st,spear1340-misc", "syscon". +- reg: Address range of misc space up to 8K diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/spear.txt b/arch/arm64/boot/dts/vendor/bindings/arm/spear.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d42949df6c29aaee124655ec3a96f5224ce06c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/spear.txt @@ -0,0 +1,26 @@ +ST SPEAr Platforms Device Tree Bindings +--------------------------------------- + +Boards with the ST SPEAr600 SoC shall have the following properties: +Required root node property: +compatible = "st,spear600"; + +Boards with the ST SPEAr300 SoC shall have the following properties: +Required root node property: +compatible = "st,spear300"; + +Boards with the ST SPEAr310 SoC shall have the following properties: +Required root node property: +compatible = "st,spear310"; + +Boards with the ST SPEAr320 SoC shall have the following properties: +Required root node property: +compatible = "st,spear320"; + +Boards with the ST SPEAr1310 SoC shall have the following properties: +Required root node property: +compatible = "st,spear1310"; + +Boards with the ST SPEAr1340 SoC shall have the following properties: +Required root node property: +compatible = "st,spear1340"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/sprd.txt b/arch/arm64/boot/dts/vendor/bindings/arm/sprd.txt new file mode 100644 index 0000000000000000000000000000000000000000..3df034b13e284338df88af478101b4c4cd1542d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/sprd.txt @@ -0,0 +1,14 @@ +Spreadtrum SoC Platforms Device Tree Bindings +---------------------------------------------------- + +SC9836 openphone Board +Required root node properties: + - compatible = "sprd,sc9836-openphone", "sprd,sc9836"; + +SC9860 SoC +Required root node properties: + - compatible = "sprd,sc9860" + +SP9860G 3GFHD Board +Required root node properties: + - compatible = "sprd,sp9860g-1h10", "sprd,sc9860"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/ste-nomadik.txt b/arch/arm64/boot/dts/vendor/bindings/arm/ste-nomadik.txt new file mode 100644 index 0000000000000000000000000000000000000000..2fdff5a806cfb76b5c43de6a65bc0292898fd710 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/ste-nomadik.txt @@ -0,0 +1,38 @@ +ST-Ericsson Nomadik Device Tree Bindings + +For various board the "board" node may contain specific properties +that pertain to this particular board, such as board-specific GPIOs. + +Required root node property: src +- Nomadik System and reset controller used for basic chip control, clock + and reset line control. +- compatible: must be "stericsson,nomadik,src" + +Boards with the Nomadik SoC include: + +Nomadik NHK-15 board manufactured by ST Microelectronics: + +Required root node property: + +compatible="st,nomadik-nhk-15"; + +S8815 "MiniKit" manufactured by Calao Systems: + +Required root node property: + +compatible="calaosystems,usb-s8815"; + +Required node: usb-s8815 + +Example: + +usb-s8815 { + ethernet-gpio { + gpios = <&gpio3 19 0x1>; + interrupts = <19 0x1>; + interrupt-parent = <&gpio3>; + }; + mmcsd-gpio { + gpios = <&gpio3 16 0x1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/ste-u300.txt b/arch/arm64/boot/dts/vendor/bindings/arm/ste-u300.txt new file mode 100644 index 0000000000000000000000000000000000000000..d11d80006a19037b50d0922054185ffe6371373c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/ste-u300.txt @@ -0,0 +1,46 @@ +ST-Ericsson U300 Device Tree Bindings + +For various board the "board" node may contain specific properties +that pertain to this particular board, such as board-specific GPIOs +or board power regulator supplies. + +Required root node property: + +compatible="stericsson,u300"; + +Required node: syscon +This contains the system controller. +- compatible: must be "stericsson,u300-syscon". +- reg: the base address and size of the system controller. + +Boards with the U300 SoC include: + +S365 "Small Board U365": + +Required node: s365 +This contains the board-specific information. +- compatible: must be "stericsson,s365". +- vana15-supply: the regulator supplying the 1.5V to drive the + board. +- syscon: a pointer to the syscon node so we can access the + syscon registers to set the board as self-powered. + +Example: + +/ { + model = "ST-Ericsson U300"; + compatible = "stericsson,u300"; + #address-cells = <1>; + #size-cells = <1>; + + s365 { + compatible = "stericsson,s365"; + vana15-supply = <&ab3100_ldo_d_reg>; + syscon = <&syscon>; + }; + + syscon: syscon@c0011000 { + compatible = "stericsson,u300-syscon"; + reg = <0xc0011000 0x1000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/sti.txt b/arch/arm64/boot/dts/vendor/bindings/arm/sti.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d27f6b084c7bfd07fda2ffce59c18e9a76390f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/sti.txt @@ -0,0 +1,23 @@ +ST STi Platforms Device Tree Bindings +--------------------------------------- + +Boards with the ST STiH415 SoC shall have the following properties: +Required root node property: +compatible = "st,stih415"; + +Boards with the ST STiH416 SoC shall have the following properties: +Required root node property: +compatible = "st,stih416"; + +Boards with the ST STiH407 SoC shall have the following properties: +Required root node property: +compatible = "st,stih407"; + +Boards with the ST STiH410 SoC shall have the following properties: +Required root node property: +compatible = "st,stih410"; + +Boards with the ST STiH418 SoC shall have the following properties: +Required root node property: +compatible = "st,stih418"; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/stm32/stm32-syscon.txt b/arch/arm64/boot/dts/vendor/bindings/arm/stm32/stm32-syscon.txt new file mode 100644 index 0000000000000000000000000000000000000000..99980aee26e5fe748512ed78da9f50315ea1abb3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/stm32/stm32-syscon.txt @@ -0,0 +1,14 @@ +STMicroelectronics STM32 Platforms System Controller + +Properties: + - compatible : should contain two values. First value must be : + - " st,stm32mp157-syscfg " - for stm32mp157 based SoCs, + second value must be always "syscon". + - reg : offset and length of the register set. + + Example: + syscfg: syscon@50020000 { + compatible = "st,stm32mp157-syscfg", "syscon"; + reg = <0x50020000 0x400>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/stm32/stm32.txt b/arch/arm64/boot/dts/vendor/bindings/arm/stm32/stm32.txt new file mode 100644 index 0000000000000000000000000000000000000000..6808ed9ddfd53695450e6b6d9d8afd2512af6f8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/stm32/stm32.txt @@ -0,0 +1,10 @@ +STMicroelectronics STM32 Platforms Device Tree Bindings + +Each device tree must specify which STM32 SoC it uses, +using one of the following compatible strings: + + st,stm32f429 + st,stm32f469 + st,stm32f746 + st,stm32h743 + st,stm32mp157 diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/sunxi.txt b/arch/arm64/boot/dts/vendor/bindings/arm/sunxi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4beec3d9ad35710f6a44dec6f227dcf4b9f1622 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/sunxi.txt @@ -0,0 +1,21 @@ +Allwinner sunXi Platforms Device Tree Bindings + +Each device tree must specify which Allwinner SoC it uses, +using one of the following compatible strings: + + allwinner,sun4i-a10 + allwinner,sun5i-a10s + allwinner,sun5i-a13 + allwinner,sun5i-r8 + allwinner,sun6i-a31 + allwinner,sun7i-a20 + allwinner,sun8i-a23 + allwinner,sun8i-a33 + allwinner,sun8i-a83t + allwinner,sun8i-h2-plus + allwinner,sun8i-h3 + allwinner-sun8i-r40 + allwinner,sun8i-v3s + allwinner,sun9i-a80 + allwinner,sun50i-a64 + nextthing,gr8 diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/sunxi/smp-sram.txt b/arch/arm64/boot/dts/vendor/bindings/arm/sunxi/smp-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..082e6a9382d3b315d4c3ad79af7a52b7c494e47e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/sunxi/smp-sram.txt @@ -0,0 +1,44 @@ +Allwinner SRAM for smp bringup: +------------------------------------------------ + +Allwinner's A80 SoC uses part of the secure sram for hotplugging of the +primary core (cpu0). Once the core gets powered up it checks if a magic +value is set at a specific location. If it is then the BROM will jump +to the software entry address, instead of executing a standard boot. + +Therefore a reserved section sub-node has to be added to the mmio-sram +declaration. + +Note that this is separate from the Allwinner SRAM controller found in +../../sram/sunxi-sram.txt. This SRAM is secure only and not mappable to +any device. + +Also there are no "secure-only" properties. The implementation should +check if this SRAM is usable first. + +Required sub-node properties: +- compatible : depending on the SoC this should be one of: + "allwinner,sun9i-a80-smp-sram" + +The rest of the properties should follow the generic mmio-sram discription +found in ../../misc/sram.txt + +Example: + + sram_b: sram@20000 { + /* 256 KiB secure SRAM at 0x20000 */ + compatible = "mmio-sram"; + reg = <0x00020000 0x40000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x00020000 0x40000>; + + smp-sram@1000 { + /* + * This is checked by BROM to determine if + * cpu0 should jump to SMP entry vector + */ + compatible = "allwinner,sun9i-a80-smp-sram"; + reg = <0x1000 0x8>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/swir.txt b/arch/arm64/boot/dts/vendor/bindings/arm/swir.txt new file mode 100644 index 0000000000000000000000000000000000000000..042be73a95d3da1ac3ab06ba1f87dae194885fc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/swir.txt @@ -0,0 +1,12 @@ +Sierra Wireless Modules device tree bindings +-------------------------------------------- + +Supported Modules : + - WP8548 : Includes MDM9615 and PM8018 in a module + +Sierra Wireless modules shall have the following properties : + Required root node property + - compatible: "swir,wp8548" for the WP8548 CF3 Module + +Board compatible values: + - "swir,mangoh-green-wp8548" for the mangOH green board with the WP8548 module diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/technologic.txt b/arch/arm64/boot/dts/vendor/bindings/arm/technologic.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1cedc00dcab150728c209fb217b09cd7e8fa418 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/technologic.txt @@ -0,0 +1,23 @@ +Technologic Systems Platforms Device Tree Bindings +-------------------------------------------------- + +TS-4600 is a System-on-Module based on the Freescale i.MX28 System-on-Chip. +It can be mounted on a carrier board providing additional peripheral connectors. +Required root node properties: + - compatible = "technologic,imx28-ts4600", "fsl,imx28" + +TS-4800 board +Required root node properties: + - compatible = "technologic,imx51-ts4800", "fsl,imx51"; + +TS-4900 is a System-on-Module based on the Freescale i.MX6 System-on-Chip. +It can be mounted on a carrier board providing additional peripheral connectors. +Required root node properties: + - compatible = "technologic,imx6dl-ts4900", "fsl,imx6dl" + - compatible = "technologic,imx6q-ts4900", "fsl,imx6q" + +TS-7970 is a System-on-Module based on the Freescale i.MX6 System-on-Chip. +It can be mounted on a carrier board providing additional peripheral connectors. +Required root node properties: + - compatible = "technologic,imx6dl-ts7970", "fsl,imx6dl" + - compatible = "technologic,imx6q-ts7970", "fsl,imx6q" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra.txt new file mode 100644 index 0000000000000000000000000000000000000000..32f62bb7006d4480a5ba22de62619b319eab3a3d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra.txt @@ -0,0 +1,60 @@ +NVIDIA Tegra device tree bindings +------------------------------------------- + +SoCs +------------------------------------------- + +Each device tree must specify which Tegra SoC it uses, using one of the +following compatible values: + + nvidia,tegra20 + nvidia,tegra30 + nvidia,tegra114 + nvidia,tegra124 + nvidia,tegra132 + nvidia,tegra210 + nvidia,tegra186 + nvidia,tegra194 + +Boards +------------------------------------------- + +Each device tree must specify which one or more of the following +board-specific compatible values: + + ad,medcom-wide + ad,plutux + ad,tamonten + ad,tec + compal,paz00 + compulab,trimslice + nvidia,beaver + nvidia,cardhu + nvidia,cardhu-a02 + nvidia,cardhu-a04 + nvidia,dalmore + nvidia,harmony + nvidia,jetson-tk1 + nvidia,norrin + nvidia,p2371-0000 + nvidia,p2371-2180 + nvidia,p2571 + nvidia,p2771-0000 + nvidia,p2972-0000 + nvidia,roth + nvidia,seaboard + nvidia,tn7 + nvidia,ventana + toradex,apalis_t30 + toradex,apalis_t30-eval + toradex,apalis-tk1 + toradex,apalis-tk1-eval + toradex,colibri_t20-512 + toradex,colibri_t30 + toradex,colibri_t30-eval-v3 + toradex,iris + +Trusted Foundations +------------------------------------------- +Tegra supports the Trusted Foundation secure monitor. See the +"tlm,trusted-foundations" binding's documentation for more details. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,nvec.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,nvec.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ae601e7f51f313a5c0a0f4dbc0095151841a519 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,nvec.txt @@ -0,0 +1,21 @@ +NVIDIA compliant embedded controller + +Required properties: +- compatible : should be "nvidia,nvec". +- reg : the iomem of the i2c slave controller +- interrupts : the interrupt line of the i2c slave controller +- clock-frequency : the frequency of the i2c bus +- gpios : the gpio used for ec request +- slave-addr: the i2c address of the slave controller +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + Tegra20/Tegra30: + - div-clk + - fast-clk + Tegra114: + - div-clk +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2c diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra186-pmc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra186-pmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a3bf7c5a7a01ea5325c3b803d5f5d9f5bbc48ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra186-pmc.txt @@ -0,0 +1,36 @@ +NVIDIA Tegra Power Management Controller (PMC) + +Required properties: +- compatible: Should contain one of the following: + - "nvidia,tegra186-pmc": for Tegra186 + - "nvidia,tegra194-pmc": for Tegra194 +- reg: Must contain an (offset, length) pair of the register set for each + entry in reg-names. +- reg-names: Must include the following entries: + - "pmc" + - "wake" + - "aotag" + - "scratch" + - "misc" (Only for Tegra194) + +Optional properties: +- nvidia,invert-interrupt: If present, inverts the PMU interrupt signal. + +Example: + +SoC DTSI: + + pmc@c3600000 { + compatible = "nvidia,tegra186-pmc"; + reg = <0 0x0c360000 0 0x10000>, + <0 0x0c370000 0 0x10000>, + <0 0x0c380000 0 0x10000>, + <0 0x0c390000 0 0x10000>; + reg-names = "pmc", "wake", "aotag", "scratch"; + }; + +Board DTS: + + pmc@c360000 { + nvidia,invert-interrupt; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-ahb.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-ahb.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a4295b545395bb3673299e68d08cfad2a09365e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-ahb.txt @@ -0,0 +1,17 @@ +NVIDIA Tegra AHB + +Required properties: +- compatible : For Tegra20, must contain "nvidia,tegra20-ahb". For + Tegra30, must contain "nvidia,tegra30-ahb". Otherwise, must contain + '"nvidia,-ahb", "nvidia,tegra30-ahb"' where is tegra124, + tegra132, or tegra210. +- reg : Should contain 1 register ranges(address and length). For + Tegra20, Tegra30, and Tegra114 chips, the value must be <0x6000c004 + 0x10c>. For Tegra124, Tegra132 and Tegra210 chips, the value should + be be <0x6000c000 0x150>. + +Example (for a Tegra20 chip): + ahb: ahb@6000c004 { + compatible = "nvidia,tegra20-ahb"; + reg = <0x6000c004 0x10c>; /* AHB Arbitration + Gizmo Controller */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-emc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-emc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c33b29dc66070abe48bfb0f47d3f01aa9c81773 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-emc.txt @@ -0,0 +1,100 @@ +Embedded Memory Controller + +Properties: +- name : Should be emc +- #address-cells : Should be 1 +- #size-cells : Should be 0 +- compatible : Should contain "nvidia,tegra20-emc". +- reg : Offset and length of the register set for the device +- nvidia,use-ram-code : If present, the sub-nodes will be addressed + and chosen using the ramcode board selector. If omitted, only one + set of tables can be present and said tables will be used + irrespective of ram-code configuration. + +Child device nodes describe the memory settings for different configurations and clock rates. + +Example: + + memory-controller@7000f400 { + #address-cells = < 1 >; + #size-cells = < 0 >; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f4000 0x200>; + } + + +Embedded Memory Controller ram-code table + +If the emc node has the nvidia,use-ram-code property present, then the +next level of nodes below the emc table are used to specify which settings +apply for which ram-code settings. + +If the emc node lacks the nvidia,use-ram-code property, this level is omitted +and the tables are stored directly under the emc node (see below). + +Properties: + +- name : Should be emc-tables +- nvidia,ram-code : the binary representation of the ram-code board strappings + for which this node (and children) are valid. + + + +Embedded Memory Controller configuration table + +This is a table containing the EMC register settings for the various +operating speeds of the memory controller. They are always located as +subnodes of the emc controller node. + +There are two ways of specifying which tables to use: + +* The simplest is if there is just one set of tables in the device tree, + and they will always be used (based on which frequency is used). + This is the preferred method, especially when firmware can fill in + this information based on the specific system information and just + pass it on to the kernel. + +* The slightly more complex one is when more than one memory configuration + might exist on the system. The Tegra20 platform handles this during + early boot by selecting one out of possible 4 memory settings based + on a 2-pin "ram code" bootstrap setting on the board. The values of + these strappings can be read through a register in the SoC, and thus + used to select which tables to use. + +Properties: +- name : Should be emc-table +- compatible : Should contain "nvidia,tegra20-emc-table". +- reg : either an opaque enumerator to tell different tables apart, or + the valid frequency for which the table should be used (in kHz). +- clock-frequency : the clock frequency for the EMC at which this + table should be used (in kHz). +- nvidia,emc-registers : a 46 word array of EMC registers to be programmed + for operation at the 'clock-frequency' setting. + The order and contents of the registers are: + RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT, + WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR, + PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW, + TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE, + ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE, + ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0, + CFG_CLKTRIM_1, CFG_CLKTRIM_2 + + emc-table@166000 { + reg = <166000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 166000 >; + nvidia,emc-registers = < 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 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 >; + }; + + emc-table@333000 { + reg = <333000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 333000 >; + nvidia,emc-registers = < 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 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..a855c1bffc0f6695d5c0cd3f032019ea32d9d5e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-flowctrl.txt @@ -0,0 +1,18 @@ +NVIDIA Tegra Flow Controller + +Required properties: +- compatible: Should contain one of the following: + - "nvidia,tegra20-flowctrl": for Tegra20 + - "nvidia,tegra30-flowctrl": for Tegra30 + - "nvidia,tegra114-flowctrl": for Tegra114 + - "nvidia,tegra124-flowctrl": for Tegra124 + - "nvidia,tegra132-flowctrl", "nvidia,tegra124-flowctrl": for Tegra132 + - "nvidia,tegra210-flowctrl": for Tegra210 +- reg: Should contain one register range (address and length) + +Example: + + flow-controller@60007000 { + compatible = "nvidia,tegra20-flowctrl"; + reg = <0x60007000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-pmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a74b37b07e5c1576492245a9d70ed89f5cf89234 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -0,0 +1,197 @@ +NVIDIA Tegra Power Management Controller (PMC) + +== Power Management Controller Node == + +The PMC block interacts with an external Power Management Unit. The PMC +mostly controls the entry and exit of the system from different sleep +modes. It provides power-gating controllers for SoC and CPU power-islands. + +Required properties: +- name : Should be pmc +- compatible : Should contain one of the following: + For Tegra20 must contain "nvidia,tegra20-pmc". + For Tegra30 must contain "nvidia,tegra30-pmc". + For Tegra114 must contain "nvidia,tegra114-pmc" + For Tegra124 must contain "nvidia,tegra124-pmc" + For Tegra132 must contain "nvidia,tegra124-pmc" + For Tegra210 must contain "nvidia,tegra210-pmc" +- reg : Offset and length of the register set for the device +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + "pclk" (The Tegra clock of that name), + "clk32k_in" (The 32KHz clock input to Tegra). + +Optional properties: +- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal. + The PMU is an external Power Management Unit, whose interrupt output + signal is fed into the PMC. This signal is optionally inverted, and then + fed into the ARM GIC. The PMC is not involved in the detection or + handling of this interrupt signal, merely its inversion. +- nvidia,suspend-mode : The suspend mode that the platform should use. + Valid values are 0, 1 and 2: + 0 (LP0): CPU + Core voltage off and DRAM in self-refresh + 1 (LP1): CPU voltage off and DRAM in self-refresh + 2 (LP2): CPU voltage off +- nvidia,core-power-req-active-high : Boolean, core power request active-high +- nvidia,sys-clock-req-active-high : Boolean, system clock request active-high +- nvidia,combined-power-req : Boolean, combined power request for CPU & Core +- nvidia,cpu-pwr-good-en : Boolean, CPU power good signal (from PMIC to PMC) + is enabled. + +Required properties when nvidia,suspend-mode is specified: +- nvidia,cpu-pwr-good-time : CPU power good time in uS. +- nvidia,cpu-pwr-off-time : CPU power off time in uS. +- nvidia,core-pwr-good-time : + Core power good time in uS. +- nvidia,core-pwr-off-time : Core power off time in uS. + +Required properties when nvidia,suspend-mode=<0>: +- nvidia,lp0-vec : Starting address and length of LP0 vector + The LP0 vector contains the warm boot code that is executed by AVP when + resuming from the LP0 state. The AVP (Audio-Video Processor) is an ARM7 + processor and always being the first boot processor when chip is power on + or resume from deep sleep mode. When the system is resumed from the deep + sleep mode, the warm boot code will restore some PLLs, clocks and then + bring up CPU0 for resuming the system. + +Hardware-triggered thermal reset: +On Tegra30, Tegra114 and Tegra124, if the 'i2c-thermtrip' subnode exists, +hardware-triggered thermal reset will be enabled. + +Required properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'): +- nvidia,i2c-controller-id : ID of I2C controller to send poweroff command to. Valid values are + described in section 9.2.148 "APBDEV_PMC_SCRATCH53_0" of the + Tegra K1 Technical Reference Manual. +- nvidia,bus-addr : Bus address of the PMU on the I2C bus +- nvidia,reg-addr : I2C register address to write poweroff command to +- nvidia,reg-data : Poweroff command to write to PMU + +Optional properties for hardware-triggered thermal reset (inside 'i2c-thermtrip'): +- nvidia,pinmux-id : Pinmux used by the hardware when issuing poweroff command. + Defaults to 0. Valid values are described in section 12.5.2 + "Pinmux Support" of the Tegra4 Technical Reference Manual. + +Optional nodes: +- powergates : This node contains a hierarchy of power domain nodes, which + should match the powergates on the Tegra SoC. See "Powergate + Nodes" below. + +Example: + +/ SoC dts including file +pmc@7000f400 { + compatible = "nvidia,tegra20-pmc"; + reg = <0x7000e400 0x400>; + clocks = <&tegra_car 110>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; + nvidia,invert-interrupt; + nvidia,suspend-mode = <1>; + nvidia,cpu-pwr-good-time = <2000>; + nvidia,cpu-pwr-off-time = <100>; + nvidia,core-pwr-good-time = <3845 3845>; + nvidia,core-pwr-off-time = <458>; + nvidia,core-power-req-active-high; + nvidia,sys-clock-req-active-high; + nvidia,lp0-vec = <0xbdffd000 0x2000>; +}; + +/ Tegra board dts file +{ + ... + pmc@7000f400 { + i2c-thermtrip { + nvidia,i2c-controller-id = <4>; + nvidia,bus-addr = <0x40>; + nvidia,reg-addr = <0x36>; + nvidia,reg-data = <0x2>; + }; + }; + ... + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk32k_in: clock { + compatible = "fixed-clock"; + reg=<0>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + ... +}; + + +== Powergate Nodes == + +Each of the powergate nodes represents a power-domain on the Tegra SoC +that can be power-gated by the Tegra PMC. The name of the powergate node +should be one of the below. Note that not every powergate is applicable +to all Tegra devices and the following list shows which powergates are +applicable to which devices. Please refer to the Tegra TRM for more +details on the various powergates. + + Name Description Devices Applicable + 3d 3D Graphics Tegra20/114/124/210 + 3d0 3D Graphics 0 Tegra30 + 3d1 3D Graphics 1 Tegra30 + aud Audio Tegra210 + dfd Debug Tegra210 + dis Display A Tegra114/124/210 + disb Display B Tegra114/124/210 + heg 2D Graphics Tegra30/114/124/210 + iram Internal RAM Tegra124/210 + mpe MPEG Encode All + nvdec NVIDIA Video Decode Engine Tegra210 + nvjpg NVIDIA JPEG Engine Tegra210 + pcie PCIE Tegra20/30/124/210 + sata SATA Tegra30/124/210 + sor Display interfaces Tegra124/210 + ve2 Video Encode Engine 2 Tegra210 + venc Video Encode Engine All + vdec Video Decode Engine Tegra20/30/114/124 + vic Video Imaging Compositor Tegra124/210 + xusba USB Partition A Tegra114/124/210 + xusbb USB Partition B Tegra114/124/210 + xusbc USB Partition C Tegra114/124/210 + +Required properties: + - clocks: Must contain an entry for each clock required by the PMC for + controlling a power-gate. See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each reset required by the PMC for + controlling a power-gate. See ../reset/reset.txt for details. + - #power-domain-cells: Must be 0. + +Example: + + pmc: pmc@7000e400 { + compatible = "nvidia,tegra210-pmc"; + reg = <0x0 0x7000e400 0x0 0x400>; + clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>; + clock-names = "pclk", "clk32k_in"; + + powergates { + pd_audio: aud { + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + resets = <&tegra_car 198>; + #power-domain-cells = <0>; + }; + }; + }; + + +== Powergate Clients == + +Hardware blocks belonging to a power domain should contain a "power-domains" +property that is a phandle pointing to the corresponding powergate node. + +Example: + + adma: adma@702e2000 { + ... + power-domains = <&pd_audio>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra30-actmon.txt b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra30-actmon.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea670a5d7ee3e8cd67af0987695e830187ed3b65 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/tegra/nvidia,tegra30-actmon.txt @@ -0,0 +1,32 @@ +NVIDIA Tegra Activity Monitor + +The activity monitor block collects statistics about the behaviour of other +components in the system. This information can be used to derive the rate at +which the external memory needs to be clocked in order to serve all requests +from the monitored clients. + +Required properties: +- compatible: should be "nvidia,tegra-actmon" +- reg: offset and length of the register set for the device +- interrupts: standard interrupt property +- clocks: Must contain a phandle and clock specifier pair for each entry in +clock-names. See ../../clock/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - actmon + - emc +- resets: Must contain an entry for each entry in reset-names. See +../../reset/reset.txt for details. +- reset-names: Must include the following entries: + - actmon + +Example: + actmon@6000c800 { + compatible = "nvidia,tegra124-actmon"; + reg = <0x0 0x6000c800 0x0 0x400>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_ACTMON>, + <&tegra_car TEGRA124_CLK_EMC>; + clock-names = "actmon", "emc"; + resets = <&tegra_car 119>; + reset-names = "actmon"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/ti/k3.txt b/arch/arm64/boot/dts/vendor/bindings/arm/ti/k3.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a059cabb2da09bc842816d4f41a59983d5f2adf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/ti/k3.txt @@ -0,0 +1,23 @@ +Texas Instruments K3 Multicore SoC architecture device tree bindings +-------------------------------------------------------------------- + +Platforms based on Texas Instruments K3 Multicore SoC architecture +shall follow the following scheme: + +SoCs +---- + +Each device tree root node must specify which exact SoC in K3 Multicore SoC +architecture it uses, using one of the following compatible values: + +- AM654 + compatible = "ti,am654"; + +Boards +------ + +In addition, each device tree root node must specify which one or more +of the following board-specific compatible values: + +- AM654 EVM + compatible = "ti,am654-evm", "ti,am654"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/topology.txt b/arch/arm64/boot/dts/vendor/bindings/arm/topology.txt new file mode 100644 index 0000000000000000000000000000000000000000..de9eb0486630dd1b0e7b4418494f11a9ecc3a1bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/topology.txt @@ -0,0 +1,475 @@ +=========================================== +ARM topology binding description +=========================================== + +=========================================== +1 - Introduction +=========================================== + +In an ARM system, the hierarchy of CPUs is defined through three entities that +are used to describe the layout of physical CPUs in the system: + +- cluster +- core +- thread + +The cpu nodes (bindings defined in [1]) represent the devices that +correspond to physical CPUs and are to be mapped to the hierarchy levels. + +The bottom hierarchy level sits at core or thread level depending on whether +symmetric multi-threading (SMT) is supported or not. + +For instance in a system where CPUs support SMT, "cpu" nodes represent all +threads existing in the system and map to the hierarchy level "thread" above. +In systems where SMT is not supported "cpu" nodes represent all cores present +in the system and map to the hierarchy level "core" above. + +ARM topology bindings allow one to associate cpu nodes with hierarchical groups +corresponding to the system hierarchy; syntactically they are defined as device +tree nodes. + +The remainder of this document provides the topology bindings for ARM, based +on the Devicetree Specification, available from: + +https://www.devicetree.org/specifications/ + +If not stated otherwise, whenever a reference to a cpu node phandle is made its +value must point to a cpu node compliant with the cpu node bindings as +documented in [1]. +A topology description containing phandles to cpu nodes that are not compliant +with bindings standardized in [1] is therefore considered invalid. + +=========================================== +2 - cpu-map node +=========================================== + +The ARM CPU topology is defined within the cpu-map node, which is a direct +child of the cpus node and provides a container where the actual topology +nodes are listed. + +- cpu-map node + + Usage: Optional - On ARM SMP systems provide CPUs topology to the OS. + ARM uniprocessor systems do not require a topology + description and therefore should not define a + cpu-map node. + + Description: The cpu-map node is just a container node where its + subnodes describe the CPU topology. + + Node name must be "cpu-map". + + The cpu-map node's parent node must be the cpus node. + + The cpu-map node's child nodes can be: + + - one or more cluster nodes + + Any other configuration is considered invalid. + +The cpu-map node can only contain three types of child nodes: + +- cluster node +- core node +- thread node + +whose bindings are described in paragraph 3. + +The nodes describing the CPU topology (cluster/core/thread) can only +be defined within the cpu-map node and every core/thread in the system +must be defined within the topology. Any other configuration is +invalid and therefore must be ignored. + +=========================================== +2.1 - cpu-map child nodes naming convention +=========================================== + +cpu-map child nodes must follow a naming convention where the node name +must be "clusterN", "coreN", "threadN" depending on the node type (ie +cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes which +are siblings within a single common parent node must be given a unique and +sequential N value, starting from 0). +cpu-map child nodes which do not share a common parent node can have the same +name (ie same number N as other cpu-map child nodes at different device tree +levels) since name uniqueness will be guaranteed by the device tree hierarchy. + +=========================================== +3 - cluster/core/thread node bindings +=========================================== + +Bindings for cluster/cpu/thread nodes are defined as follows: + +- cluster node + + Description: must be declared within a cpu-map node, one node + per cluster. A system can contain several layers of + clustering and cluster nodes can be contained in parent + cluster nodes. + + The cluster node name must be "clusterN" as described in 2.1 above. + A cluster node can not be a leaf node. + + A cluster node's child nodes must be: + + - one or more cluster nodes; or + - one or more core nodes + + Any other configuration is considered invalid. + +- core node + + Description: must be declared in a cluster node, one node per core in + the cluster. If the system does not support SMT, core + nodes are leaf nodes, otherwise they become containers of + thread nodes. + + The core node name must be "coreN" as described in 2.1 above. + + A core node must be a leaf node if SMT is not supported. + + Properties for core nodes that are leaf nodes: + + - cpu + Usage: required + Value type: + Definition: a phandle to the cpu node that corresponds to the + core node. + + If a core node is not a leaf node (CPUs supporting SMT) a core node's + child nodes can be: + + - one or more thread nodes + + Any other configuration is considered invalid. + +- thread node + + Description: must be declared in a core node, one node per thread + in the core if the system supports SMT. Thread nodes are + always leaf nodes in the device tree. + + The thread node name must be "threadN" as described in 2.1 above. + + A thread node must be a leaf node. + + A thread node must contain the following property: + + - cpu + Usage: required + Value type: + Definition: a phandle to the cpu node that corresponds to + the thread node. + +=========================================== +4 - Example dts +=========================================== + +Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters): + +cpus { + #size-cells = <0>; + #address-cells = <2>; + + cpu-map { + cluster0 { + cluster0 { + core0 { + thread0 { + cpu = <&CPU0>; + }; + thread1 { + cpu = <&CPU1>; + }; + }; + + core1 { + thread0 { + cpu = <&CPU2>; + }; + thread1 { + cpu = <&CPU3>; + }; + }; + }; + + cluster1 { + core0 { + thread0 { + cpu = <&CPU4>; + }; + thread1 { + cpu = <&CPU5>; + }; + }; + + core1 { + thread0 { + cpu = <&CPU6>; + }; + thread1 { + cpu = <&CPU7>; + }; + }; + }; + }; + + cluster1 { + cluster0 { + core0 { + thread0 { + cpu = <&CPU8>; + }; + thread1 { + cpu = <&CPU9>; + }; + }; + core1 { + thread0 { + cpu = <&CPU10>; + }; + thread1 { + cpu = <&CPU11>; + }; + }; + }; + + cluster1 { + core0 { + thread0 { + cpu = <&CPU12>; + }; + thread1 { + cpu = <&CPU13>; + }; + }; + core1 { + thread0 { + cpu = <&CPU14>; + }; + thread1 { + cpu = <&CPU15>; + }; + }; + }; + }; + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU4: cpu@10000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10000>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU5: cpu@10001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10001>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU6: cpu@10100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU7: cpu@10101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU8: cpu@100000000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x0>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU9: cpu@100000001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x1>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU10: cpu@100000100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU11: cpu@100000101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU12: cpu@100010000 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10000>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU13: cpu@100010001 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10001>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU14: cpu@100010100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10100>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; + + CPU15: cpu@100010101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x1 0x10101>; + enable-method = "spin-table"; + cpu-release-addr = <0 0x20000000>; + }; +}; + +Example 2 (ARM 32-bit, dual-cluster, 8-cpu system, no SMT): + +cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + core1 { + cpu = <&CPU5>; + }; + core2 { + cpu = <&CPU6>; + }; + core3 { + cpu = <&CPU7>; + }; + }; + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x0>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x1>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x2>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0x3>; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x100>; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x101>; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x102>; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x103>; + }; +}; + +=============================================================================== +[1] ARM Linux kernel documentation + Documentation/devicetree/bindings/arm/cpus.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/uniphier/cache-uniphier.txt b/arch/arm64/boot/dts/vendor/bindings/arm/uniphier/cache-uniphier.txt new file mode 100644 index 0000000000000000000000000000000000000000..d27a646f48a9683382b32424ef34de1d84b04f7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/uniphier/cache-uniphier.txt @@ -0,0 +1,60 @@ +UniPhier outer cache controller + +UniPhier SoCs are integrated with a full-custom outer cache controller system. +All of them have a level 2 cache controller, and some have a level 3 cache +controller as well. + +Required properties: +- compatible: should be "socionext,uniphier-system-cache" +- reg: offsets and lengths of the register sets for the device. It should + contain 3 regions: control register, revision register, operation register, + in this order. +- cache-unified: specifies the cache is a unified cache. +- cache-size: specifies the size in bytes of the cache +- cache-sets: specifies the number of associativity sets of the cache +- cache-line-size: specifies the line size in bytes +- cache-level: specifies the level in the cache hierarchy. The value should + be 2 for L2 cache, 3 for L3 cache, etc. + +Optional properties: +- next-level-cache: phandle to the next level cache if present. The next level + cache should be also compatible with "socionext,uniphier-system-cache". + +The L2 cache must exist to use the L3 cache; the cache hierarchy must be +indicated correctly with "next-level-cache" properties. + +Example 1 (system with L2): + l2: l2-cache@500c0000 { + compatible = "socionext,uniphier-system-cache"; + reg = <0x500c0000 0x2000>, <0x503c0100 0x4>, + <0x506c0000 0x400>; + cache-unified; + cache-size = <0x80000>; + cache-sets = <256>; + cache-line-size = <128>; + cache-level = <2>; + }; + +Example 2 (system with L2 and L3): + l2: l2-cache@500c0000 { + compatible = "socionext,uniphier-system-cache"; + reg = <0x500c0000 0x2000>, <0x503c0100 0x8>, + <0x506c0000 0x400>; + cache-unified; + cache-size = <0x200000>; + cache-sets = <512>; + cache-line-size = <128>; + cache-level = <2>; + next-level-cache = <&l3>; + }; + + l3: l3-cache@500c8000 { + compatible = "socionext,uniphier-system-cache"; + reg = <0x500c8000 0x2000>, <0x503c8100 0x8>, + <0x506c8000 0x400>; + cache-unified; + cache-size = <0x400000>; + cache-sets = <512>; + cache-line-size = <256>; + cache-level = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/ux500/boards.txt b/arch/arm64/boot/dts/vendor/bindings/arm/ux500/boards.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fa429534f4910f79193ed177d8da974ee9caf24 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/ux500/boards.txt @@ -0,0 +1,83 @@ +ST-Ericsson Ux500 boards +------------------------ + +Required properties (in root node) one of these: + compatible = "st-ericsson,mop500" (legacy) + compatible = "st-ericsson,u8500" + +Required node (under root node): + +soc: represents the system-on-chip and contains the chip +peripherals + +Required property of soc node, one of these: + compatible = "stericsson,db8500" + +Required subnodes under soc node: + +backupram: (used for CPU spin tables and for storing data +during retention, system won't boot without this): + compatible = "ste,dbx500-backupram" + +scu: + see binding for arm/scu.txt + +interrupt-controller: + see binding for interrupt-controller/arm,gic.txt + +timer: + see binding for timer/arm,twd.txt + +clocks: + see binding for clocks/ux500.txt + +Example: + +/dts-v1/; + +/ { + model = "ST-Ericsson HREF (pre-v60) and ST UIB"; + compatible = "st-ericsson,mop500", "st-ericsson,u8500"; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "stericsson,db8500"; + interrupt-parent = <&intc>; + ranges; + + backupram@80150000 { + compatible = "ste,dbx500-backupram"; + reg = <0x80150000 0x2000>; + }; + + intc: interrupt-controller@a0411000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0xa0411000 0x1000>, + <0xa0410100 0x100>; + }; + + scu@a04100000 { + compatible = "arm,cortex-a9-scu"; + reg = <0xa0410000 0x100>; + }; + + timer@a0410600 { + compatible = "arm,cortex-a9-twd-timer"; + reg = <0xa0410600 0x20>; + interrupts = <1 13 0x304>; /* IRQ level high per-CPU */ + clocks = <&smp_twd_clk>; + }; + + clocks { + compatible = "stericsson,u8500-clks"; + + smp_twd_clk: smp-twd-clock { + #clock-cells = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/ux500/power_domain.txt b/arch/arm64/boot/dts/vendor/bindings/arm/ux500/power_domain.txt new file mode 100644 index 0000000000000000000000000000000000000000..5679d1742d3eeb8419ca55ff63d9dd5a8b687936 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/ux500/power_domain.txt @@ -0,0 +1,35 @@ +* ST-Ericsson UX500 PM Domains + +UX500 supports multiple PM domains which are used to gate power to one or +more peripherals on the SOC. + +The implementation of PM domains for UX500 are based upon the generic PM domain +and use the corresponding DT bindings. + +==PM domain providers== + +Required properties: + - compatible: Must be "stericsson,ux500-pm-domains". + - #power-domain-cells : Number of cells in a power domain specifier, must be 1. + +Example: + pm_domains: pm_domains0 { + compatible = "stericsson,ux500-pm-domains"; + #power-domain-cells = <1>; + }; + +==PM domain consumers== + +Required properties: + - power-domains: A phandle and PM domain specifier. Below are the list of + valid specifiers: + + Index Specifier + ----- --------- + 0 DOMAIN_VAPE + +Example: + sdi0_per1@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + power-domains = <&pm_domains DOMAIN_VAPE> + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/versatile-sysreg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/versatile-sysreg.txt new file mode 100644 index 0000000000000000000000000000000000000000..a4f15262d717a96b86b17640ee49915e3fe57d02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/versatile-sysreg.txt @@ -0,0 +1,10 @@ +ARM Versatile system registers +-------------------------------------- + +This is a system control registers block, providing multiple low level +platform functions like board detection and identification, software +interrupt generation, MMC and NOR Flash control etc. + +Required node properties: +- compatible value : = "arm,versatile-sysreg", "syscon" +- reg : physical base address and the size of the registers window diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/vexpress-scc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/vexpress-scc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae5043e42e5d5986bc161fba63cc1c2483e6284a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/vexpress-scc.txt @@ -0,0 +1,33 @@ +ARM Versatile Express Serial Configuration Controller +----------------------------------------------------- + +Test chips for ARM Versatile Express platform implement SCC (Serial +Configuration Controller) interface, used to set initial conditions +for the test chip. + +In some cases its registers are also mapped in normal address space +and can be used to obtain runtime information about the chip internals +(like silicon temperature sensors) and as interface to other subsystems +like platform configuration control and power management. + +Required properties: + +- compatible value: "arm,vexpress-scc,", "arm,vexpress-scc"; + where is the full tile model name (as used + in the tile's Technical Reference Manual), + eg. for Coretile Express A15x2 A7x3 (V2P-CA15_A7): + compatible = "arm,vexpress-scc,v2p-ca15_a7", "arm,vexpress-scc"; + +Optional properties: + +- reg: when the SCC is memory mapped, physical address and size of the + registers window +- interrupts: when the SCC can generate a system-level interrupt + +Example: + + scc@7fff0000 { + compatible = "arm,vexpress-scc,v2p-ca15_a7", "arm,vexpress-scc"; + reg = <0 0x7fff0000 0 0x1000>; + interrupts = <0 95 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/vexpress-sysreg.txt b/arch/arm64/boot/dts/vendor/bindings/arm/vexpress-sysreg.txt new file mode 100644 index 0000000000000000000000000000000000000000..50095802fb4accd2113870807d5edd7efa4853d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/vexpress-sysreg.txt @@ -0,0 +1,103 @@ +ARM Versatile Express system registers +-------------------------------------- + +This is a system control registers block, providing multiple low level +platform functions like board detection and identification, software +interrupt generation, MMC and NOR Flash control etc. + +Required node properties: +- compatible value : = "arm,vexpress,sysreg"; +- reg : physical base address and the size of the registers window + +Deprecated properties, replaced by GPIO subnodes (see below): +- gpio-controller : specifies that the node is a GPIO controller +- #gpio-cells : size of the GPIO specifier, should be 2: + - first cell is the pseudo-GPIO line number: + 0 - MMC CARDIN + 1 - MMC WPROT + 2 - NOR FLASH WPn + - second cell can take standard GPIO flags (currently ignored). + +Control registers providing pseudo-GPIO lines must be represented +by subnodes, each of them requiring the following properties: +- compatible value : one of + "arm,vexpress-sysreg,sys_led" + "arm,vexpress-sysreg,sys_mci" + "arm,vexpress-sysreg,sys_flash" +- gpio-controller : makes the node a GPIO controller +- #gpio-cells : size of the GPIO specifier, must be 2: + - first cell is the function number: + - for sys_led : 0..7 = LED 0..7 + - for sys_mci : 0 = MMC CARDIN, 1 = MMC WPROT + - for sys_flash : 0 = NOR FLASH WPn + - second cell can take standard GPIO flags (currently ignored). + +Example: + v2m_sysreg: sysreg@10000000 { + compatible = "arm,vexpress-sysreg"; + reg = <0x10000000 0x1000>; + + v2m_led_gpios: sys_led@8 { + compatible = "arm,vexpress-sysreg,sys_led"; + gpio-controller; + #gpio-cells = <2>; + }; + + v2m_mmc_gpios: sys_mci@48 { + compatible = "arm,vexpress-sysreg,sys_mci"; + gpio-controller; + #gpio-cells = <2>; + }; + + v2m_flash_gpios: sys_flash@4c { + compatible = "arm,vexpress-sysreg,sys_flash"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + +This block also can also act a bridge to the platform's configuration +bus via "system control" interface, addressing devices with site number, +position in the board stack, config controller, function and device +numbers - see motherboard's TRM for more details. All configuration +controller accessible via this interface must reference the sysreg +node via "arm,vexpress,config-bridge" phandle and define appropriate +topology properties - see main vexpress node documentation for more +details. Each child of such node describes one function and must +define the following properties: +- compatible value : must be one of (corresponding to the TRM): + "arm,vexpress-amp" + "arm,vexpress-dvimode" + "arm,vexpress-energy" + "arm,vexpress-muxfpga" + "arm,vexpress-osc" + "arm,vexpress-power" + "arm,vexpress-reboot" + "arm,vexpress-reset" + "arm,vexpress-scc" + "arm,vexpress-shutdown" + "arm,vexpress-temp" + "arm,vexpress-volt" +- arm,vexpress-sysreg,func : must contain a set of two cells long groups: + - first cell of each group defines the function number + (eg. 1 for clock generator, 2 for voltage regulators etc.) + - second cell of each group defines device number (eg. osc 0, + osc 1 etc.) + - some functions (eg. energy meter, with its 64 bit long counter) + are using more than one function/device number pair + +Example: + mcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + compatible = "arm,vexpress-osc"; + arm,vexpress-sysreg,func = <1 0>; + }; + + energy@0 { + compatible = "arm,vexpress-energy"; + arm,vexpress-sysreg,func = <13 0>, <13 1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/vexpress.txt b/arch/arm64/boot/dts/vendor/bindings/arm/vexpress.txt new file mode 100644 index 0000000000000000000000000000000000000000..39844cd0bccefd41a8d18dd42e3368c9df6d5488 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/vexpress.txt @@ -0,0 +1,229 @@ +ARM Versatile Express boards family +----------------------------------- + +ARM's Versatile Express platform consists of a motherboard and one +or more daughterboards (tiles). The motherboard provides a set of +peripherals. Processor and RAM "live" on the tiles. + +The motherboard and each core tile should be described by a separate +Device Tree source file, with the tile's description including +the motherboard file using a /include/ directive. As the motherboard +can be initialized in one of two different configurations ("memory +maps"), care must be taken to include the correct one. + + +Root node +--------- + +Required properties in the root node: +- compatible value: + compatible = "arm,vexpress,", "arm,vexpress"; + where is the full tile model name (as used in the tile's + Technical Reference Manual), eg.: + - for Coretile Express A5x2 (V2P-CA5s): + compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress"; + - for Coretile Express A9x4 (V2P-CA9): + compatible = "arm,vexpress,v2p-ca9", "arm,vexpress"; + If a tile comes in several variants or can be used in more then one + configuration, the compatible value should be: + compatible = "arm,vexpress,,", \ + "arm,vexpress,", "arm,vexpress"; + eg: + - Coretile Express A15x2 (V2P-CA15) with Tech Chip 1: + compatible = "arm,vexpress,v2p-ca15,tc1", \ + "arm,vexpress,v2p-ca15", "arm,vexpress"; + - LogicTile Express 13MG (V2F-2XV6) running Cortex-A7 (3 cores) SMM: + compatible = "arm,vexpress,v2f-2xv6,ca7x3", \ + "arm,vexpress,v2f-2xv6", "arm,vexpress"; + +Optional properties in the root node: +- tile model name (use name from the tile's Technical Reference + Manual, eg. "V2P-CA5s") + model = ""; +- tile's HBI number (unique ARM's board model ID, visible on the + PCB's silkscreen) in hexadecimal transcription: + arm,hbi = <0xhbi> + eg: + - for Coretile Express A5x2 (V2P-CA5s) HBI-0191: + arm,hbi = <0x191>; + - Coretile Express A9x4 (V2P-CA9) HBI-0225: + arm,hbi = <0x225>; + + +CPU nodes +--------- + +Top-level standard "cpus" node is required. It must contain a node +with device_type = "cpu" property for every available core, eg.: + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a5"; + reg = <0>; + }; + }; + + +Configuration infrastructure +---------------------------- + +The platform has an elaborated configuration system, consisting of +microcontrollers residing on the mother- and daughterboards known +as Motherboard/Daughterboard Configuration Controller (MCC and DCC). +The controllers are responsible for the platform initialization +(reset generation, flash programming, FPGA bitfiles loading etc.) +but also control clock generators, voltage regulators, gather +environmental data like temperature, power consumption etc. Even +the video output switch (FPGA) is controlled that way. + +The controllers are not mapped into normal memory address space +and must be accessed through bridges - other devices capable +of generating transactions on the configuration bus. + +The nodes describing configuration controllers must define +the following properties: +- compatible value: + compatible = "arm,vexpress,config-bus"; +- bridge phandle: + arm,vexpress,config-bridge = ; +and children describing available functions. + + +Platform topology +----------------- + +As Versatile Express can be configured in number of physically +different setups, the device tree should describe platform topology. +Root node and main motherboard node must define the following +property, describing physical location of the children nodes: +- site number: + arm,vexpress,site = ; + where 0 means motherboard, 1 or 2 are daugtherboard sites, + 0xf means "master" site (site containing main CPU tile) +- when daughterboards are stacked on one site, their position + in the stack be be described with: + arm,vexpress,position = ; +- when describing tiles consisting more than one DCC, its number + can be described with: + arm,vexpress,dcc = ; + +Any of the numbers above defaults to zero if not defined in +the node or any of its parent. + + +Motherboard +----------- + +The motherboard description file provides a single "motherboard" node +using 2 address cells corresponding to the Static Memory Bus used +between the motherboard and the tile. The first cell defines the Chip +Select (CS) line number, the second cell address offset within the CS. +All interrupt lines between the motherboard and the tile are active +high and are described using single cell. + +Optional properties of the "motherboard" node: +- motherboard's memory map variant: + arm,v2m-memory-map = ""; + where name is one of: + - "rs1" - for RS1 map (i.a. peripherals on CS3); this map is also + referred to as "ARM Cortex-A Series memory map": + arm,v2m-memory-map = "rs1"; + When this property is missing, the motherboard is using the original + memory map (also known as the "Legacy memory map", primarily used + with the original CoreTile Express A9x4) with peripherals on CS7. + +Motherboard .dtsi files provide a set of labelled peripherals that +can be used to obtain required phandle in the tile's "aliases" node: +- UARTs, note that the numbers correspond to the physical connectors + on the motherboard's back panel: + v2m_serial0, v2m_serial1, v2m_serial2 and v2m_serial3 +- I2C controllers: + v2m_i2c_dvi and v2m_i2c_pcie +- SP804 timers: + v2m_timer01 and v2m_timer23 + +The tile description should define a "smb" node, describing the +Static Memory Bus between the tile and motherboard. It must define +the following properties: +- "simple-bus" compatible value (to ensure creation of the children) + compatible = "simple-bus"; +- mapping of the SMB CS/offset addresses into main address space: + #address-cells = <2>; + #size-cells = <1>; + ranges = <...>; +- interrupts mapping: + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 63>; + interrupt-map = <...>; + + +Example of a VE tile description (simplified) +--------------------------------------------- + +/dts-v1/; + +/ { + model = "V2P-CA5s"; + arm,hbi = <0x225>; + arm,vexpress,site = <0xf>; + compatible = "arm,vexpress-v2p-ca5s", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <1>; + + chosen { }; + + aliases { + serial0 = &v2m_serial0; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a5"; + reg = <0>; + }; + }; + + gic: interrupt-controller@2c001000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x2c001000 0x1000>, + <0x2c000100 0x100>; + }; + + dcc { + compatible = "arm,vexpress,config-bus"; + arm,vexpress,config-bridge = <&v2m_sysreg>; + + osc@0 { + compatible = "arm,vexpress-osc"; + }; + }; + + smb { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <1>; + /* CS0 is visible at 0x08000000 */ + ranges = <0 0 0x08000000 0x04000000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 63>; + /* Active high IRQ 0 is connected to GIC's SPI0 */ + interrupt-map = <0 0 0 &gic 0 0 4>; + + /include/ "vexpress-v2m-rs1.dtsi" + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/vt8500.txt b/arch/arm64/boot/dts/vendor/bindings/arm/vt8500.txt new file mode 100644 index 0000000000000000000000000000000000000000..87dc1ddf47709ff4b46bf9f8fa5a078f482941d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/vt8500.txt @@ -0,0 +1,22 @@ +VIA/Wondermedia VT8500 Platforms Device Tree Bindings +--------------------------------------- + +Boards with the VIA VT8500 SoC shall have the following properties: +Required root node property: +compatible = "via,vt8500"; + +Boards with the Wondermedia WM8505 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8505"; + +Boards with the Wondermedia WM8650 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8650"; + +Boards with the Wondermedia WM8750 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8750"; + +Boards with the Wondermedia WM8850 SoC shall have the following properties: +Required root node property: +compatible = "wm,wm8850"; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/vt8500/via,vt8500-pmc.txt b/arch/arm64/boot/dts/vendor/bindings/arm/vt8500/via,vt8500-pmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..521b9c7de933a15c165df3a70f2b0003b238b8a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/vt8500/via,vt8500-pmc.txt @@ -0,0 +1,13 @@ +VIA/Wondermedia VT8500 Power Management Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-pmc" +- reg : Should contain 1 register ranges(address and length) + +Example: + + pmc@d8130000 { + compatible = "via,vt8500-pmc"; + reg = <0xd8130000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/xen.txt b/arch/arm64/boot/dts/vendor/bindings/arm/xen.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9b9321434ea07324b5d1b080efef7de5dc29bc6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/xen.txt @@ -0,0 +1,60 @@ +* Xen hypervisor device tree bindings + +Xen ARM virtual platforms shall have a top-level "hypervisor" node with +the following properties: + +- compatible: + compatible = "xen,xen-", "xen,xen"; + where is the version of the Xen ABI of the platform. + +- reg: specifies the base physical address and size of a region in + memory where the grant table should be mapped to, using an + HYPERVISOR_memory_op hypercall. The memory region is large enough to map + the whole grant table (it is larger or equal to gnttab_max_grant_frames()). + This property is unnecessary when booting Dom0 using ACPI. + +- interrupts: the interrupt used by Xen to inject event notifications. + A GIC node is also required. + This property is unnecessary when booting Dom0 using ACPI. + +To support UEFI on Xen ARM virtual platforms, Xen populates the FDT "uefi" node +under /hypervisor with following parameters: + +________________________________________________________________________________ +Name | Size | Description +================================================================================ +xen,uefi-system-table | 64-bit | Guest physical address of the UEFI System + | | Table. +-------------------------------------------------------------------------------- +xen,uefi-mmap-start | 64-bit | Guest physical address of the UEFI memory + | | map. +-------------------------------------------------------------------------------- +xen,uefi-mmap-size | 32-bit | Size in bytes of the UEFI memory map + | | pointed to in previous entry. +-------------------------------------------------------------------------------- +xen,uefi-mmap-desc-size | 32-bit | Size in bytes of each entry in the UEFI + | | memory map. +-------------------------------------------------------------------------------- +xen,uefi-mmap-desc-ver | 32-bit | Version of the mmap descriptor format. +-------------------------------------------------------------------------------- + +Example (assuming #address-cells = <2> and #size-cells = <2>): + +hypervisor { + compatible = "xen,xen-4.3", "xen,xen"; + reg = <0 0xb0000000 0 0x20000>; + interrupts = <1 15 0xf08>; + uefi { + xen,uefi-system-table = <0xXXXXXXXX>; + xen,uefi-mmap-start = <0xXXXXXXXX>; + xen,uefi-mmap-size = <0xXXXXXXXX>; + xen,uefi-mmap-desc-size = <0xXXXXXXXX>; + xen,uefi-mmap-desc-ver = <0xXXXXXXXX>; + }; +}; + +The format and meaning of the "xen,uefi-*" parameters are similar to those in +Documentation/arm/uefi.txt, which are provided by the regular UEFI stub. However +they differ because they are provided by the Xen hypervisor, together with a set +of UEFI runtime services implemented via hypercalls, see +http://xenbits.xen.org/docs/unstable/hypercall/x86_64/include,public,platform.h.html. diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/xilinx.txt b/arch/arm64/boot/dts/vendor/bindings/arm/xilinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..26fe5ecc4332631953cab9151708848e69eba6c6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/xilinx.txt @@ -0,0 +1,83 @@ +Xilinx Zynq Platforms Device Tree Bindings + +Boards with Zynq-7000 SOC based on an ARM Cortex A9 processor +shall have the following properties. + +Required root node properties: + - compatible = "xlnx,zynq-7000"; + +Additional compatible strings: + +- Adapteva Parallella board + "adapteva,parallella" + +- Avnet MicroZed board + "avnet,zynq-microzed" + "xlnx,zynq-microzed" + +- Avnet ZedBoard board + "avnet,zynq-zed" + "xlnx,zynq-zed" + +- Digilent Zybo board + "digilent,zynq-zybo" + +- Digilent Zybo Z7 board + "digilent,zynq-zybo-z7" + +- Xilinx CC108 internal board + "xlnx,zynq-cc108" + +- Xilinx ZC702 internal board + "xlnx,zynq-zc702" + +- Xilinx ZC706 internal board + "xlnx,zynq-zc706" + +- Xilinx ZC770 internal board, with different FMC cards + "xlnx,zynq-zc770-xm010" + "xlnx,zynq-zc770-xm011" + "xlnx,zynq-zc770-xm012" + "xlnx,zynq-zc770-xm013" + +--------------------------------------------------------------- + +Xilinx Zynq UltraScale+ MPSoC Platforms Device Tree Bindings + +Boards with ZynqMP SOC based on an ARM Cortex A53 processor +shall have the following properties. + +Required root node properties: + - compatible = "xlnx,zynqmp"; + + +Additional compatible strings: + +- Xilinx internal board zc1232 + "xlnx,zynqmp-zc1232-revA", "xlnx,zynqmp-zc1232" + +- Xilinx internal board zc1254 + "xlnx,zynqmp-zc1254-revA", "xlnx,zynqmp-zc1254" + +- Xilinx internal board zc1275 + "xlnx,zynqmp-zc1275-revA", "xlnx,zynqmp-zc1275" + +- Xilinx internal board zc1751 + "xlnx,zynqmp-zc1751" + +- Xilinx 96boards compatible board zcu100 + "xlnx,zynqmp-zcu100-revC", "xlnx,zynqmp-zcu100" + +- Xilinx evaluation board zcu102 + "xlnx,zynqmp-zcu102-revA", "xlnx,zynqmp-zcu102" + "xlnx,zynqmp-zcu102-revB", "xlnx,zynqmp-zcu102" + "xlnx,zynqmp-zcu102-rev1.0", "xlnx,zynqmp-zcu102" + +- Xilinx evaluation board zcu104 + "xlnx,zynqmp-zcu104-revA", "xlnx,zynqmp-zcu104" + +- Xilinx evaluation board zcu106 + "xlnx,zynqmp-zcu106-revA", "xlnx,zynqmp-zcu106" + +- Xilinx evaluation board zcu111 + "xlnx,zynqmp-zcu111-revA", "xlnx,zynqmp-zcu111" diff --git a/arch/arm64/boot/dts/vendor/bindings/arm/zte.txt b/arch/arm64/boot/dts/vendor/bindings/arm/zte.txt new file mode 100644 index 0000000000000000000000000000000000000000..83369785d29c7ff7f0bbbc8988f9dfa9cad59c8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/arm/zte.txt @@ -0,0 +1,39 @@ +ZTE platforms device tree bindings +--------------------------------------- + +- ZX296702 board: + Required root node properties: + - compatible = "zte,zx296702-ad1", "zte,zx296702" + +System management required properties: + - compatible = "zte,sysctrl" + +Low power management required properties: + - compatible = "zte,zx296702-pcu" + +Bus matrix required properties: + - compatible = "zte,zx-bus-matrix" + + +--------------------------------------- +- ZX296718 SoC: + Required root node properties: + - compatible = "zte,zx296718" + +ZX296718 EVB board: + - "zte,zx296718-evb" + +System management required properties: + - compatible = "zte,zx296718-aon-sysctrl" + - compatible = "zte,zx296718-sysctrl" + +Example: +aon_sysctrl: aon-sysctrl@116000 { + compatible = "zte,zx296718-aon-sysctrl", "syscon"; + reg = <0x116000 0x1000>; +}; + +sysctrl: sysctrl@1463000 { + compatible = "zte,zx296718-sysctrl", "syscon"; + reg = <0x1463000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-ceva.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-ceva.txt new file mode 100644 index 0000000000000000000000000000000000000000..7561cc4de371444ac4254e6848d5febb1b6fda45 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-ceva.txt @@ -0,0 +1,59 @@ +Binding for CEVA AHCI SATA Controller + +Required properties: + - reg: Physical base address and size of the controller's register area. + - compatible: Compatibility string. Must be 'ceva,ahci-1v84'. + - clocks: Input clock specifier. Refer to common clock bindings. + - interrupts: Interrupt specifier. Refer to interrupt binding. + - ceva,p0-cominit-params: OOB timing value for COMINIT parameter for port 0. + - ceva,p1-cominit-params: OOB timing value for COMINIT parameter for port 1. + The fields for the above parameter must be as shown below: + ceva,pN-cominit-params = /bits/ 8 ; + CINMP : COMINIT Negate Minimum Period. + CIBGN : COMINIT Burst Gap Nominal. + CIBGMX: COMINIT Burst Gap Maximum. + CIBGMN: COMINIT Burst Gap Minimum. + - ceva,p0-comwake-params: OOB timing value for COMWAKE parameter for port 0. + - ceva,p1-comwake-params: OOB timing value for COMWAKE parameter for port 1. + The fields for the above parameter must be as shown below: + ceva,pN-comwake-params = /bits/ 8 ; + CWBGMN: COMWAKE Burst Gap Minimum. + CWBGMX: COMWAKE Burst Gap Maximum. + CWBGN: COMWAKE Burst Gap Nominal. + CWNMP: COMWAKE Negate Minimum Period. + - ceva,p0-burst-params: Burst timing value for COM parameter for port 0. + - ceva,p1-burst-params: Burst timing value for COM parameter for port 1. + The fields for the above parameter must be as shown below: + ceva,pN-burst-params = /bits/ 8 ; + BMX: COM Burst Maximum. + BNM: COM Burst Nominal. + SFD: Signal Failure Detection value. + PTST: Partial to Slumber timer value. + - ceva,p0-retry-params: Retry interval timing value for port 0. + - ceva,p1-retry-params: Retry interval timing value for port 1. + The fields for the above parameter must be as shown below: + ceva,pN-retry-params = /bits/ 16 ; + RIT: Retry Interval Timer. + RCT: Rate Change Timer. + +Optional properties: + - ceva,broken-gen2: limit to gen1 speed instead of gen2. + +Examples: + ahci@fd0c0000 { + compatible = "ceva,ahci-1v84"; + reg = <0xfd0c0000 0x200>; + interrupt-parent = <&gic>; + interrupts = <0 133 4>; + clocks = <&clkc SATA_CLK_ID>; + ceva,p0-cominit-params = /bits/ 8 <0x0F 0x25 0x18 0x29>; + ceva,p0-comwake-params = /bits/ 8 <0x04 0x0B 0x08 0x0F>; + ceva,p0-burst-params = /bits/ 8 <0x0A 0x08 0x4A 0x06>; + ceva,p0-retry-params = /bits/ 16 <0x0216 0x7F06>; + + ceva,p1-cominit-params = /bits/ 8 <0x0F 0x25 0x18 0x29>; + ceva,p1-comwake-params = /bits/ 8 <0x04 0x0B 0x08 0x0F>; + ceva,p1-burst-params = /bits/ 8 <0x0A 0x08 0x4A 0x06>; + ceva,p1-retry-params = /bits/ 16 <0x0216 0x7F06>; + ceva,broken-gen2; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-da850.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-da850.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f8193417725f9ed7e95ab70111ec8f6b78fb750 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-da850.txt @@ -0,0 +1,18 @@ +Device tree binding for the TI DA850 AHCI SATA Controller +--------------------------------------------------------- + +Required properties: + - compatible: must be "ti,da850-ahci" + - reg: physical base addresses and sizes of the two register regions + used by the controller: the register map as defined by the + AHCI 1.1 standard and the Power Down Control Register (PWRDN) + for enabling/disabling the SATA clock receiver + - interrupts: interrupt specifier (refer to the interrupt binding) + +Example: + + sata: sata@218000 { + compatible = "ti,da850-ahci"; + reg = <0x218000 0x2000>, <0x22c018 0x4>; + interrupts = <67>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-dm816.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-dm816.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8c535f3541f57d4cbf7da9e938e0cebaade608c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-dm816.txt @@ -0,0 +1,21 @@ +Device tree binding for the TI DM816 AHCI SATA Controller +--------------------------------------------------------- + +Required properties: + - compatible: must be "ti,dm816-ahci" + - reg: physical base address and size of the register region used by + the controller (as defined by the AHCI 1.1 standard) + - interrupts: interrupt specifier (refer to the interrupt binding) + - clocks: list of phandle and clock specifier pairs (or only + phandles for clock providers with '0' defined for + #clock-cells); two clocks must be specified: the functional + clock and an external reference clock + +Example: + + sata: sata@4a140000 { + compatible = "ti,dm816-ahci"; + reg = <0x4a140000 0x10000>; + interrupts = <16>; + clocks = <&sysclk5_ck>, <&sata_refclk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-fsl-qoriq.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-fsl-qoriq.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c3ca0e13de05716aef7d850896a6ecbe0c74645 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-fsl-qoriq.txt @@ -0,0 +1,21 @@ +Binding for Freescale QorIQ AHCI SATA Controller + +Required properties: + - reg: Physical base address and size of the controller's register area. + - compatible: Compatibility string. Must be 'fsl,-ahci', where + chip could be ls1021a, ls1043a, ls1046a, ls1088a, ls2080a etc. + - clocks: Input clock specifier. Refer to common clock bindings. + - interrupts: Interrupt specifier. Refer to interrupt binding. + +Optional properties: + - dma-coherent: Enable AHCI coherent DMA operation. + - reg-names: register area names when there are more than 1 register area. + +Examples: + sata@3200000 { + compatible = "fsl,ls1021a-ahci"; + reg = <0x0 0x3200000 0x0 0x10000>; + interrupts = ; + clocks = <&platform_clk 1>; + dma-coherent; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-mtk.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-mtk.txt new file mode 100644 index 0000000000000000000000000000000000000000..d2aa696b161b3139210d5a7588af068a539b3040 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-mtk.txt @@ -0,0 +1,51 @@ +MediaTek Serial ATA controller + +Required properties: + - compatible : Must be "mediatek,-ahci", "mediatek,mtk-ahci". + When using "mediatek,mtk-ahci" compatible strings, you + need SoC specific ones in addition, one of: + - "mediatek,mt7622-ahci" + - reg : Physical base addresses and length of register sets. + - interrupts : Interrupt associated with the SATA device. + - interrupt-names : Associated name must be: "hostc". + - clocks : A list of phandle and clock specifier pairs, one for each + entry in clock-names. + - clock-names : Associated names must be: "ahb", "axi", "asic", "rbc", "pm". + - phys : A phandle and PHY specifier pair for the PHY port. + - phy-names : Associated name must be: "sata-phy". + - ports-implemented : See ./ahci-platform.txt for details. + +Optional properties: + - power-domains : A phandle and power domain specifier pair to the power + domain which is responsible for collapsing and restoring + power to the peripheral. + - resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names : Associated names must be: "axi", "sw", "reg". + - mediatek,phy-mode : A phandle to the system controller, used to enable + SATA function. + +Example: + + sata: sata@1a200000 { + compatible = "mediatek,mt7622-ahci", + "mediatek,mtk-ahci"; + reg = <0 0x1a200000 0 0x1100>; + interrupts = ; + interrupt-names = "hostc"; + clocks = <&pciesys CLK_SATA_AHB_EN>, + <&pciesys CLK_SATA_AXI_EN>, + <&pciesys CLK_SATA_ASIC_EN>, + <&pciesys CLK_SATA_RBC_EN>, + <&pciesys CLK_SATA_PM_EN>; + clock-names = "ahb", "axi", "asic", "rbc", "pm"; + phys = <&u3port1 PHY_TYPE_SATA>; + phy-names = "sata-phy"; + ports-implemented = <0x1>; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + resets = <&pciesys MT7622_SATA_AXI_BUS_RST>, + <&pciesys MT7622_SATA_PHY_SW_RST>, + <&pciesys MT7622_SATA_PHY_REG_RST>; + reset-names = "axi", "sw", "reg"; + mediatek,phy-mode = <&pciesys>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-platform.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-platform.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d5bd456d9d96303e9cbabf4fed97e8cef6b3277 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-platform.txt @@ -0,0 +1,87 @@ +* AHCI SATA Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA controller should have its own node. + +It is possible, but not required, to represent each port as a sub-node. +It allows to enable each port independently when dealing with multiple +PHYs. + +Required properties: +- compatible : compatible string, one of: + - "allwinner,sun4i-a10-ahci" + - "brcm,iproc-ahci" + - "hisilicon,hisi-ahci" + - "cavium,octeon-7130-ahci" + - "ibm,476gtr-ahci" + - "marvell,armada-380-ahci" + - "marvell,armada-3700-ahci" + - "snps,dwc-ahci" + - "snps,spear-ahci" + - "generic-ahci" +- interrupts : +- reg : + +Please note that when using "generic-ahci" you must also specify a SoC specific +compatible: + compatible = "manufacturer,soc-model-ahci", "generic-ahci"; + +Optional properties: +- dma-coherent : Present if dma operations are coherent +- clocks : a list of phandle + clock specifier pairs +- resets : a list of phandle + reset specifier pairs +- target-supply : regulator for SATA target power +- phys : reference to the SATA PHY node +- phy-names : must be "sata-phy" +- ports-implemented : Mask that indicates which ports that the HBA supports + are available for software to use. Useful if PORTS_IMPL + is not programmed by the BIOS, which is true with + some embedded SOC's. + +Required properties when using sub-nodes: +- #address-cells : number of cells to encode an address +- #size-cells : number of cells representing the size of an address + + +Sub-nodes required properties: +- reg : the port number +And at least one of the following properties: +- phys : reference to the SATA PHY node +- target-supply : regulator for SATA target power + +Examples: + sata@ffe08000 { + compatible = "snps,spear-ahci"; + reg = <0xffe08000 0x1000>; + interrupts = <115>; + }; + + ahci: sata@1c18000 { + compatible = "allwinner,sun4i-a10-ahci"; + reg = <0x01c18000 0x1000>; + interrupts = <56>; + clocks = <&pll6 0>, <&ahb_gates 25>; + target-supply = <®_ahci_5v>; + }; + +With sub-nodes: + sata@f7e90000 { + compatible = "marvell,berlin2q-achi", "generic-ahci"; + reg = <0xe90000 0x1000>; + interrupts = ; + clocks = <&chip CLKID_SATA>; + #address-cells = <1>; + #size-cells = <0>; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy 0>; + target-supply = <®_sata0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy 1>; + target-supply = <®_sata1>;; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/ahci-st.txt b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..909c9935360d673091f6593853e4fd580bfcc50a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/ahci-st.txt @@ -0,0 +1,35 @@ +STMicroelectronics STi SATA controller + +This binding describes a SATA device. + +Required properties: + - compatible : Must be "st,ahci" + - reg : Physical base addresses and length of register sets + - interrupts : Interrupt associated with the SATA device + - interrupt-names : Associated name must be; "hostc" + - clocks : The phandle for the clock + - clock-names : Associated name must be; "ahci_clk" + - phys : The phandle for the PHY port + - phy-names : Associated name must be; "ahci_phy" + +Optional properties: + - resets : The power-down, soft-reset and power-reset lines of SATA IP + - reset-names : Associated names must be; "pwr-dwn", "sw-rst" and "pwr-rst" + +Example: + + /* Example for stih407 family silicon */ + sata0: sata@9b20000 { + compatible = "st,ahci"; + reg = <0x9b20000 0x1000>; + interrupts = ; + interrupt-names = "hostc"; + phys = <&phy_port0 PHY_TYPE_SATA>; + phy-names = "ahci_phy"; + resets = <&powerdown STIH407_SATA0_POWERDOWN>, + <&softreset STIH407_SATA0_SOFTRESET>, + <&softreset STIH407_SATA0_PWR_SOFTRESET>; + reset-names = "pwr-dwn", "sw-rst", "pwr-rst"; + clocks = <&clk_s_c0_flexgen CLK_ICN_REG>; + clock-names = "ahci_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/apm-xgene.txt b/arch/arm64/boot/dts/vendor/bindings/ata/apm-xgene.txt new file mode 100644 index 0000000000000000000000000000000000000000..02e690a675db738dc98555112d4faad578254100 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/apm-xgene.txt @@ -0,0 +1,77 @@ +* APM X-Gene 6.0 Gb/s SATA host controller nodes + +SATA host controller nodes are defined to describe on-chip Serial ATA +controllers. Each SATA controller (pair of ports) have its own node. + +Required properties: +- compatible : Shall contain: + * "apm,xgene-ahci" +- reg : First memory resource shall be the AHCI memory + resource. + Second memory resource shall be the host controller + core memory resource. + Third memory resource shall be the host controller + diagnostic memory resource. + 4th memory resource shall be the host controller + AXI memory resource. + 5th optional memory resource shall be the host + controller MUX memory resource if required. +- interrupts : Interrupt-specifier for SATA host controller IRQ. +- clocks : Reference to the clock entry. +- phys : A list of phandles + phy-specifiers, one for each + entry in phy-names. +- phy-names : Should contain: + * "sata-phy" for the SATA 6.0Gbps PHY + +Optional properties: +- dma-coherent : Present if dma operations are coherent +- status : Shall be "ok" if enabled or "disabled" if disabled. + Default is "ok". + +Example: + sataclk: sataclk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000000>; + clock-output-names = "sataclk"; + }; + + phy2: phy@1f22a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f22a000 0x0 0x100>; + #phy-cells = <1>; + }; + + phy3: phy@1f23a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f23a000 0x0 0x100>; + #phy-cells = <1>; + }; + + sata2: sata@1a400000 { + compatible = "apm,xgene-ahci"; + reg = <0x0 0x1a400000 0x0 0x1000>, + <0x0 0x1f220000 0x0 0x1000>, + <0x0 0x1f22d000 0x0 0x1000>, + <0x0 0x1f22e000 0x0 0x1000>, + <0x0 0x1f227000 0x0 0x1000>; + interrupts = <0x0 0x87 0x4>; + dma-coherent; + clocks = <&sataclk 0>; + phys = <&phy2 0>; + phy-names = "sata-phy"; + }; + + sata3: sata@1a800000 { + compatible = "apm,xgene-ahci-pcie"; + reg = <0x0 0x1a800000 0x0 0x1000>, + <0x0 0x1f230000 0x0 0x1000>, + <0x0 0x1f23d000 0x0 0x1000>, + <0x0 0x1f23e000 0x0 0x1000>, + <0x0 0x1f237000 0x0 0x1000>; + interrupts = <0x0 0x88 0x4>; + dma-coherent; + clocks = <&sataclk 0>; + phys = <&phy3 0>; + phy-names = "sata-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/atmel-at91_cf.txt b/arch/arm64/boot/dts/vendor/bindings/ata/atmel-at91_cf.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1d22b3ae1348f1477a130c8469d41f614165f10 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/atmel-at91_cf.txt @@ -0,0 +1,19 @@ +Atmel AT91RM9200 CompactFlash + +Required properties: +- compatible : "atmel,at91rm9200-cf". +- reg : should specify localbus address and size used. +- gpios : specifies the gpio pins to control the CF device. Detect + and reset gpio's are mandatory while irq and vcc gpio's are + optional and may be set to 0 if not present. + +Example: +compact-flash@50000000 { + compatible = "atmel,at91rm9200-cf"; + reg = <0x50000000 0x30000000>; + gpios = <&pioC 13 0 /* irq */ + &pioC 15 0 /* detect */ + 0 /* vcc */ + &pioC 5 0 /* reset */ + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/brcm,sata-brcm.txt b/arch/arm64/boot/dts/vendor/bindings/ata/brcm,sata-brcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a5b3b47f21714525514b312c2c571ab41a6cb31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/brcm,sata-brcm.txt @@ -0,0 +1,37 @@ +* Broadcom SATA3 AHCI Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA controller should have its own node. + +Required properties: +- compatible : should be one or more of + "brcm,bcm7425-ahci" + "brcm,bcm7445-ahci" + "brcm,bcm-nsp-ahci" + "brcm,sata3-ahci" +- reg : register mappings for AHCI and SATA_TOP_CTRL +- reg-names : "ahci" and "top-ctrl" +- interrupts : interrupt mapping for SATA IRQ + +Also see ahci-platform.txt. + +Example: + + sata@f045a000 { + compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci"; + reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>; + reg-names = "ahci", "top-ctrl"; + interrupts = <0 30 0>; + #address-cells = <1>; + #size-cells = <0>; + + sata0: sata-port@0 { + reg = <0>; + phys = <&sata_phy 0>; + }; + + sata1: sata-port@1 { + reg = <1>; + phys = <&sata_phy 1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/cavium-compact-flash.txt b/arch/arm64/boot/dts/vendor/bindings/ata/cavium-compact-flash.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bacc8e0931eea59cea79810d18745f6f689e03f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/cavium-compact-flash.txt @@ -0,0 +1,30 @@ +* Compact Flash + +The Cavium Compact Flash device is connected to the Octeon Boot Bus, +and is thus a child of the Boot Bus device. It can read and write +industry standard compact flash devices. + +Properties: +- compatible: "cavium,ebt3000-compact-flash"; + + Compatibility with many Cavium evaluation boards. + +- reg: The base address of the CF chip select banks. Depending on + the device configuration, there may be one or two banks. + +- cavium,bus-width: The width of the connection to the CF devices. Valid + values are 8 and 16. + +- cavium,true-ide: Optional, if present the CF connection is in True IDE mode. + +- cavium,dma-engine-handle: Optional, a phandle for the DMA Engine connected + to this device. + +Example: + compact-flash@5,0 { + compatible = "cavium,ebt3000-compact-flash"; + reg = <5 0 0x10000>, <6 0 0x10000>; + cavium,bus-width = <16>; + cavium,true-ide; + cavium,dma-engine-handle = <&dma0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/cortina,gemini-sata-bridge.txt b/arch/arm64/boot/dts/vendor/bindings/ata/cortina,gemini-sata-bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c3d3cc70051b15aaf8751f2a90d8f1472fe2181 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/cortina,gemini-sata-bridge.txt @@ -0,0 +1,55 @@ +* Cortina Systems Gemini SATA Bridge + +The Gemini SATA bridge in a SoC-internal PATA to SATA bridge that +takes two Faraday Technology FTIDE010 PATA controllers and bridges +them in different configurations to two SATA ports. + +Required properties: +- compatible: should be + "cortina,gemini-sata-bridge" +- reg: registers and size for the block +- resets: phandles to the reset lines for both SATA bridges +- reset-names: must be "sata0", "sata1" +- clocks: phandles to the compulsory peripheral clocks +- clock-names: must be "SATA0_PCLK", "SATA1_PCLK" +- syscon: a phandle to the global Gemini system controller +- cortina,gemini-ata-muxmode: tell the desired multiplexing mode for + the ATA controller and SATA bridges. Values 0..3: + Mode 0: ata0 master <-> sata0 + ata1 master <-> sata1 + ata0 slave interface brought out on IDE pads + Mode 1: ata0 master <-> sata0 + ata1 master <-> sata1 + ata1 slave interface brought out on IDE pads + Mode 2: ata1 master <-> sata1 + ata1 slave <-> sata0 + ata0 master and slave interfaces brought out + on IDE pads + Mode 3: ata0 master <-> sata0 + ata0 slave <-> sata1 + ata1 master and slave interfaces brought out + on IDE pads + +Optional boolean properties: +- cortina,gemini-enable-ide-pins: enables the PATA to IDE connection. + The muxmode setting decides whether ATA0 or ATA1 is brought out, + and whether master, slave or both interfaces get brought out. +- cortina,gemini-enable-sata-bridge: enables the PATA to SATA bridge + inside the Gemnini SoC. The Muxmode decides what PATA blocks will + be muxed out and how. + +Example: + +sata: sata@46000000 { + compatible = "cortina,gemini-sata-bridge"; + reg = <0x46000000 0x100>; + resets = <&rcon 26>, <&rcon 27>; + reset-names = "sata0", "sata1"; + clocks = <&gcc GEMINI_CLK_GATE_SATA0>, + <&gcc GEMINI_CLK_GATE_SATA1>; + clock-names = "SATA0_PCLK", "SATA1_PCLK"; + syscon = <&syscon>; + cortina,gemini-ata-muxmode = <3>; + cortina,gemini-enable-ide-pins; + cortina,gemini-enable-sata-bridge; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/exynos-sata.txt b/arch/arm64/boot/dts/vendor/bindings/ata/exynos-sata.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb48448247ead3e34292bef11166a5074c9650c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/exynos-sata.txt @@ -0,0 +1,30 @@ +* Samsung AHCI SATA Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA controller should have its own node. + +Required properties: +- compatible : compatible list, contains "samsung,exynos5-sata" +- interrupts : +- reg : +- samsung,sata-freq : +- phys : Must contain exactly one entry as specified + in phy-bindings.txt +- phy-names : Must be "sata-phy" + +Optional properties: +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Shall be "sata" for the external SATA bus clock, + and "sclk_sata" for the internal controller clock. + +Example: + sata@122f0000 { + compatible = "snps,dwc-ahci"; + samsung,sata-freq = <66>; + reg = <0x122f0000 0x1ff>; + interrupts = <0 115 0>; + clocks = <&clock 277>, <&clock 143>; + clock-names = "sata", "sclk_sata"; + phys = <&sata_phy>; + phy-names = "sata-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/faraday,ftide010.txt b/arch/arm64/boot/dts/vendor/bindings/ata/faraday,ftide010.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0c64a29104d3e3db52969899f4754d7c45860c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/faraday,ftide010.txt @@ -0,0 +1,38 @@ +* Faraday Technology FTIDE010 PATA controller + +This controller is the first Faraday IDE interface block, used in the +StorLink SL2312 and SL3516, later known as the Cortina Systems Gemini +platform. The controller can do PIO modes 0 through 4, Multi-word DMA +(MWDM)modes 0 through 2 and Ultra DMA modes 0 through 6. + +On the Gemini platform, this PATA block is accompanied by a PATA to +SATA bridge in order to support SATA. This is why a phandle to that +controller is compulsory on that platform. + +The timing properties are unique per-SoC, not per-board. + +Required properties: +- compatible: should be one of + "cortina,gemini-pata", "faraday,ftide010" + "faraday,ftide010" +- interrupts: interrupt for the block +- reg: registers and size for the block + +Optional properties: +- clocks: a SoC clock running the peripheral. +- clock-names: should be set to "PCLK" for the peripheral clock. + +Required properties for "cortina,gemini-pata" compatible: +- sata: a phande to the Gemini PATA to SATA bridge, see + cortina,gemini-sata-bridge.txt for details. + +Example: + +ata@63000000 { + compatible = "cortina,gemini-pata", "faraday,ftide010"; + reg = <0x63000000 0x100>; + interrupts = <4 IRQ_TYPE_EDGE_RISING>; + clocks = <&gcc GEMINI_CLK_GATE_IDE>; + clock-names = "PCLK"; + sata = <&sata>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/fsl-sata.txt b/arch/arm64/boot/dts/vendor/bindings/ata/fsl-sata.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd63bb3becc9363c520a8fd06629fdc52c4d4299 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/fsl-sata.txt @@ -0,0 +1,28 @@ +* Freescale 8xxx/3.0 Gb/s SATA nodes + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA port should have its own node. + +Required properties: +- compatible : compatible list, contains 2 entries, first is + "fsl,CHIP-sata", where CHIP is the processor + (mpc8315, mpc8379, etc.) and the second is + "fsl,pq-sata" +- interrupts : +- cell-index : controller index. + 1 for controller @ 0x18000 + 2 for controller @ 0x19000 + 3 for controller @ 0x1a000 + 4 for controller @ 0x1b000 + +Optional properties: +- reg : + +Example: + sata@18000 { + compatible = "fsl,mpc8379-sata", "fsl,pq-sata"; + reg = <0x18000 0x1000>; + cell-index = <1>; + interrupts = <2c 8>; + interrupt-parent = < &ipic >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/imx-pata.txt b/arch/arm64/boot/dts/vendor/bindings/ata/imx-pata.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1172f00188aeba2ae7638a4acc4955c064e5624 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/imx-pata.txt @@ -0,0 +1,16 @@ +* Freescale i.MX PATA Controller + +Required properties: +- compatible: "fsl,imx27-pata" +- reg: Address range of the PATA Controller +- interrupts: The interrupt of the PATA Controller +- clocks: the clocks for the PATA Controller + +Example: + + pata: pata@83fe0000 { + compatible = "fsl,imx51-pata", "fsl,imx27-pata"; + reg = <0x83fe0000 0x4000>; + interrupts = <70>; + clocks = <&clks 161>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/imx-sata.txt b/arch/arm64/boot/dts/vendor/bindings/ata/imx-sata.txt new file mode 100644 index 0000000000000000000000000000000000000000..781f887517626ad83dc4ce010399dd41946d6bba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/imx-sata.txt @@ -0,0 +1,37 @@ +* Freescale i.MX AHCI SATA Controller + +The Freescale i.MX SATA controller mostly conforms to the AHCI interface +with some special extensions at integration level. + +Required properties: +- compatible : should be one of the following: + - "fsl,imx53-ahci" for i.MX53 SATA controller + - "fsl,imx6q-ahci" for i.MX6Q SATA controller + - "fsl,imx6qp-ahci" for i.MX6QP SATA controller +- interrupts : interrupt mapping for SATA IRQ +- reg : registers mapping +- clocks : list of clock specifiers, must contain an entry for each + required entry in clock-names +- clock-names : should include "sata", "sata_ref" and "ahb" entries + +Optional properties: +- fsl,transmit-level-mV : transmit voltage level, in millivolts. +- fsl,transmit-boost-mdB : transmit boost level, in milli-decibels +- fsl,transmit-atten-16ths : transmit attenuation, in 16ths +- fsl,receive-eq-mdB : receive equalisation, in milli-decibels + Please refer to the technical documentation or the driver source code + for the list of legal values for these options. +- fsl,no-spread-spectrum : disable spread-spectrum clocking on the SATA + link. + +Examples: + +sata@2200000 { + compatible = "fsl,imx6q-ahci"; + reg = <0x02200000 0x4000>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_SATA>, + <&clks IMX6QDL_CLK_SATA_REF_100M>, + <&clks IMX6QDL_CLK_AHB>; + clock-names = "sata", "sata_ref", "ahb"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/marvell.txt b/arch/arm64/boot/dts/vendor/bindings/ata/marvell.txt new file mode 100644 index 0000000000000000000000000000000000000000..b460edd12766082b5ed88676ad5d967d23f489be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/marvell.txt @@ -0,0 +1,22 @@ +* Marvell Orion SATA + +Required Properties: +- compatibility : "marvell,orion-sata" or "marvell,armada-370-sata" +- reg : Address range of controller +- interrupts : Interrupt controller is using +- nr-ports : Number of SATA ports in use. + +Optional Properties: +- phys : List of phandles to sata phys +- phy-names : Should be "0", "1", etc, one number per phandle + +Example: + + sata@80000 { + compatible = "marvell,orion-sata"; + reg = <0x80000 0x5000>; + interrupts = <21>; + phys = <&sata_phy0>, <&sata_phy1>; + phy-names = "0", "1"; + nr-ports = <2>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/nvidia,tegra124-ahci.txt b/arch/arm64/boot/dts/vendor/bindings/ata/nvidia,tegra124-ahci.txt new file mode 100644 index 0000000000000000000000000000000000000000..12ab2f723eb0614f7460409e667ccd13cba4e77d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/nvidia,tegra124-ahci.txt @@ -0,0 +1,44 @@ +Tegra SoC SATA AHCI controller + +Required properties : +- compatible : Must be one of: + - Tegra124 : "nvidia,tegra124-ahci" + - Tegra132 : "nvidia,tegra132-ahci", "nvidia,tegra124-ahci" + - Tegra210 : "nvidia,tegra210-ahci" +- reg : Should contain 2 entries: + - AHCI register set (SATA BAR5) + - SATA register set +- interrupts : Defines the interrupt used by SATA +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - sata + - sata-oob +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - sata + - sata-oob + - sata-cold +- phys : Must contain an entry for each entry in phy-names. + See ../phy/phy-bindings.txt for details. +- phy-names : Must include the following entries: + - For Tegra124 and Tegra132: + - sata-phy : XUSB PADCTL SATA PHY +- For Tegra124 and Tegra132: + - hvdd-supply : Defines the SATA HVDD regulator + - vddio-supply : Defines the SATA VDDIO regulator + - avdd-supply : Defines the SATA AVDD regulator + - target-5v-supply : Defines the SATA 5V power regulator + - target-12v-supply : Defines the SATA 12V power regulator + +Optional properties: +- reg : + - AUX register set +- clock-names : + - cml1 : + cml1 clock should be defined here if the PHY driver + doesn't manage them. If it does, they should not be. +- phy-names : + - For T210: + - sata-phy diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/pata-arasan.txt b/arch/arm64/boot/dts/vendor/bindings/ata/pata-arasan.txt new file mode 100644 index 0000000000000000000000000000000000000000..872edc105680536e1e119d649903f1b36a1dd4cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/pata-arasan.txt @@ -0,0 +1,37 @@ +* ARASAN PATA COMPACT FLASH CONTROLLER + +Required properties: +- compatible: "arasan,cf-spear1340" +- reg: Address range of the CF registers +- interrupt: Should contain the CF interrupt number +- clock-frequency: Interface clock rate, in Hz, one of + 25000000 + 33000000 + 40000000 + 50000000 + 66000000 + 75000000 + 100000000 + 125000000 + 150000000 + 166000000 + 200000000 + +Optional properties: +- arasan,broken-udma: if present, UDMA mode is unusable +- arasan,broken-mwdma: if present, MWDMA mode is unusable +- arasan,broken-pio: if present, PIO mode is unusable +- dmas: one DMA channel, as described in bindings/dma/dma.txt + required unless both UDMA and MWDMA mode are broken +- dma-names: the corresponding channel name, must be "data" + +Example: + + cf@fc000000 { + compatible = "arasan,cf-spear1340"; + reg = <0xfc000000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + dmas = <&dma-controller 23>; + dma-names = "data"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/qcom-sata.txt b/arch/arm64/boot/dts/vendor/bindings/ata/qcom-sata.txt new file mode 100644 index 0000000000000000000000000000000000000000..094de91cd9fd2ea6a270e7b8f9520baf142028da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/qcom-sata.txt @@ -0,0 +1,48 @@ +* Qualcomm AHCI SATA Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +Each SATA controller should have its own node. + +Required properties: +- compatible : compatible list, must contain "generic-ahci" +- interrupts : +- reg : +- phys : Must contain exactly one entry as specified + in phy-bindings.txt +- phy-names : Must be "sata-phy" + +Required properties for "qcom,ipq806x-ahci" compatible: +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Shall be: + "slave_iface" - Fabric port AHB clock for SATA + "iface" - AHB clock + "core" - core clock + "rxoob" - RX out-of-band clock + "pmalive" - Power Module Alive clock +- assigned-clocks : Shall be: + SATA_RXOOB_CLK + SATA_PMALIVE_CLK +- assigned-clock-rates : Shall be: + 100Mhz (100000000) for SATA_RXOOB_CLK + 100Mhz (100000000) for SATA_PMALIVE_CLK + +Example: + sata@29000000 { + compatible = "qcom,ipq806x-ahci", "generic-ahci"; + reg = <0x29000000 0x180>; + + interrupts = <0 209 0x0>; + + clocks = <&gcc SFAB_SATA_S_H_CLK>, + <&gcc SATA_H_CLK>, + <&gcc SATA_A_CLK>, + <&gcc SATA_RXOOB_CLK>, + <&gcc SATA_PMALIVE_CLK>; + clock-names = "slave_iface", "iface", "core", + "rxoob", "pmalive"; + assigned-clocks = <&gcc SATA_RXOOB_CLK>, <&gcc SATA_PMALIVE_CLK>; + assigned-clock-rates = <100000000>, <100000000>; + + phys = <&sata_phy>; + phy-names = "sata-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/sata_highbank.txt b/arch/arm64/boot/dts/vendor/bindings/ata/sata_highbank.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa83407cb7a4404e0cc57f20d13f81c9cc749230 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/sata_highbank.txt @@ -0,0 +1,44 @@ +* Calxeda AHCI SATA Controller + +SATA nodes are defined to describe on-chip Serial ATA controllers. +The Calxeda SATA controller mostly conforms to the AHCI interface +with some special extensions to add functionality. +Each SATA controller should have its own node. + +Required properties: +- compatible : compatible list, contains "calxeda,hb-ahci" +- interrupts : +- reg : + +Optional properties: +- dma-coherent : Present if dma operations are coherent +- calxeda,port-phys : phandle-combophy and lane assignment, which maps each + SATA port to a combophy and a lane within that + combophy +- calxeda,sgpio-gpio: phandle-gpio bank, bit offset, and default on or off, + which indicates that the driver supports SGPIO + indicator lights using the indicated GPIOs +- calxeda,led-order : a u32 array that map port numbers to offsets within the + SGPIO bitstream. +- calxeda,tx-atten : a u32 array that contains TX attenuation override + codes, one per port. The upper 3 bytes are always + 0 and thus ignored. +- calxeda,pre-clocks : a u32 that indicates the number of additional clock + cycles to transmit before sending an SGPIO pattern +- calxeda,post-clocks: a u32 that indicates the number of additional clock + cycles to transmit after sending an SGPIO pattern + +Example: + sata@ffe08000 { + compatible = "calxeda,hb-ahci"; + reg = <0xffe08000 0x1000>; + interrupts = <115>; + dma-coherent; + calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1 + &combophy0 2 &combophy0 3>; + calxeda,sgpio-gpio =<&gpioh 5 1 &gpioh 6 1 &gpioh 7 1>; + calxeda,led-order = <4 0 1 2 3>; + calxeda,tx-atten = <0xff 22 0xff 0xff 23>; + calxeda,pre-clocks = <10>; + calxeda,post-clocks = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ata/sata_rcar.txt b/arch/arm64/boot/dts/vendor/bindings/ata/sata_rcar.txt new file mode 100644 index 0000000000000000000000000000000000000000..4268e17d24116cec8e26806823ebd5ca458cc925 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ata/sata_rcar.txt @@ -0,0 +1,33 @@ +* Renesas R-Car SATA + +Required properties: +- compatible : should contain one or more of the following: + - "renesas,sata-r8a7779" for R-Car H1 + - "renesas,sata-r8a7790-es1" for R-Car H2 ES1 + - "renesas,sata-r8a7790" for R-Car H2 other than ES1 + - "renesas,sata-r8a7791" for R-Car M2-W + - "renesas,sata-r8a7793" for R-Car M2-N + - "renesas,sata-r8a7795" for R-Car H3 + - "renesas,sata-r8a77965" for R-Car M3-N + - "renesas,rcar-gen2-sata" for a generic R-Car Gen2 compatible device + - "renesas,rcar-gen3-sata" for a generic R-Car Gen3 compatible device + - "renesas,rcar-sata" is deprecated + + When compatible with the generic version nodes + must list the SoC-specific version corresponding + to the platform first followed by the generic + version. + +- reg : address and length of the SATA registers; +- interrupts : must consist of one interrupt specifier. +- clocks : must contain a reference to the functional clock. + +Example: + +sata0: sata@ee300000 { + compatible = "renesas,sata-r8a7791", "renesas,rcar-gen2-sata"; + reg = <0 0xee300000 0 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7791_CLK_SATA0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/auxdisplay/arm-charlcd.txt b/arch/arm64/boot/dts/vendor/bindings/auxdisplay/arm-charlcd.txt new file mode 100644 index 0000000000000000000000000000000000000000..e28e2aac47f156c60b1cbd75d69284659ed05e69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/auxdisplay/arm-charlcd.txt @@ -0,0 +1,18 @@ +ARM Versatile Character LCD +----------------------------------------------------- +This binding defines the character LCD interface found on ARM Versatile AB +and PB reference platforms. + +Required properties: +- compatible : "arm,versatile-clcd" +- reg : Location and size of character LCD registers + +Optional properties: +- interrupts - single interrupt for character LCD. The character LCD can + operate in polled mode without an interrupt. + +Example: + lcd@10008000 { + compatible = "arm,versatile-lcd"; + reg = <0x10008000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/auxdisplay/hit,hd44780.txt b/arch/arm64/boot/dts/vendor/bindings/auxdisplay/hit,hd44780.txt new file mode 100644 index 0000000000000000000000000000000000000000..2aa24b8899236882e2c74c99657bfa0d64b091ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/auxdisplay/hit,hd44780.txt @@ -0,0 +1,45 @@ +DT bindings for the Hitachi HD44780 Character LCD Controller + +The Hitachi HD44780 Character LCD Controller is commonly used on character LCDs +that can display one or more lines of text. It exposes an M6800 bus interface, +which can be used in either 4-bit or 8-bit mode. + +Required properties: + - compatible: Must contain "hit,hd44780", + - data-gpios: Must contain an array of either 4 or 8 GPIO specifiers, + referring to the GPIO pins connected to the data signal lines DB0-DB7 + (8-bit mode) or DB4-DB7 (4-bit mode) of the LCD Controller's bus interface, + - enable-gpios: Must contain a GPIO specifier, referring to the GPIO pin + connected to the "E" (Enable) signal line of the LCD Controller's bus + interface, + - rs-gpios: Must contain a GPIO specifier, referring to the GPIO pin + connected to the "RS" (Register Select) signal line of the LCD Controller's + bus interface, + - display-height-chars: Height of the display, in character cells, + - display-width-chars: Width of the display, in character cells. + +Optional properties: + - rw-gpios: Must contain a GPIO specifier, referring to the GPIO pin + connected to the "RW" (Read/Write) signal line of the LCD Controller's bus + interface, + - backlight-gpios: Must contain a GPIO specifier, referring to the GPIO pin + used for enabling the LCD's backlight, + - internal-buffer-width: Internal buffer width (default is 40 for displays + with 1 or 2 lines, and display-width-chars for displays with more than 2 + lines). + +Example: + + auxdisplay { + compatible = "hit,hd44780"; + + data-gpios = <&hc595 0 GPIO_ACTIVE_HIGH>, + <&hc595 1 GPIO_ACTIVE_HIGH>, + <&hc595 2 GPIO_ACTIVE_HIGH>, + <&hc595 3 GPIO_ACTIVE_HIGH>; + enable-gpios = <&hc595 4 GPIO_ACTIVE_HIGH>; + rs-gpios = <&hc595 5 GPIO_ACTIVE_HIGH>; + + display-height-chars = <2>; + display-width-chars = <16>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/auxdisplay/img-ascii-lcd.txt b/arch/arm64/boot/dts/vendor/bindings/auxdisplay/img-ascii-lcd.txt new file mode 100644 index 0000000000000000000000000000000000000000..b69bb68992fdf2a7626960ebf1911caa789222ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/auxdisplay/img-ascii-lcd.txt @@ -0,0 +1,17 @@ +Binding for ASCII LCD displays on Imagination Technologies boards + +Required properties: +- compatible : should be one of: + "img,boston-lcd" + "mti,malta-lcd" + "mti,sead3-lcd" + +Required properties for "img,boston-lcd": +- reg : memory region locating the device registers + +Required properties for "mti,malta-lcd" or "mti,sead3-lcd": +- regmap: phandle of the system controller containing the LCD registers +- offset: offset in bytes to the LCD registers within the system controller + +The layout of the registers & properties of the display are determined +from the compatible string, making this binding somewhat trivial. diff --git a/arch/arm64/boot/dts/vendor/bindings/batterydata/batterydata.txt b/arch/arm64/boot/dts/vendor/bindings/batterydata/batterydata.txt new file mode 100644 index 0000000000000000000000000000000000000000..29b75cd47b579db3457a3b4d16cb969c7dcc6dfd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/batterydata/batterydata.txt @@ -0,0 +1,321 @@ +Battery Profile Data + +Battery Data is a collection of battery profile data made available to +the QPNP Charger and BMS drivers via device tree. + +qcom,battery-data node required properties: +- qcom,rpull-up-kohm : The vadc pullup resistor's resistance value in kOhms. +- qcom,vref-batt-therm-uv : The vadc voltage used to make readings. + For Qualcomm Technologies, Inc. VADCs, this should be + 1800000uV. + +qcom,battery-data node optional properties: +- qcom,batt-id-range-pct : The area of variation between upper and lower bound + for which a given battery ID resistance is valid. This + value is expressed as a percentage of the specified kohm + resistance provided by qcom,batt-id-kohm. + +qcom,battery-data can also include any number of children nodes. These children +nodes will be treated as battery profile data nodes. + +Profile data node required properties: +- qcom,fcc-mah : Full charge count of the battery in milliamp-hours +- qcom,default-rbatt-mohm : The nominal battery resistance value +- qcom,rbatt-capacitive-mohm : The capacitive resistance of the battery. +- qcom,flat-ocv-threshold-uv : The threshold under which the battery can be + considered to be in the flat portion of the discharge + curve. +- qcom,max-voltage-uv : The maximum rated voltage of the battery +- qcom,v-cutoff-uv : The cutoff voltage of the battery at which the device + should shutdown gracefully. +- qcom,chg-term-ua : The termination charging current of the battery. +- qcom,batt-id-kohm : The battery id resistance of the battery. It can be + used as an array which could support multiple IDs for one battery + module when the ID resistance of some battery modules goes across + several ranges. +- qcom,battery-type : A string indicating the type of battery. +- qcom,fg-profile-data : An array of hexadecimal values used to configure more + complex fuel gauge peripherals which have a large amount + of coefficients used in hardware state machines and thus + influencing the final output of the state of charge read + by software. + +Profile data node optional properties: +- qcom,chg-rslow-comp-c1 : A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,chg-rslow-comp-c2 : A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,chg-rslow-comp-thr : A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,chg-rs-to-rslow: A constant for rslow compensation in the fuel gauge. + This will be provided by the profiling tool for + additional fuel gauge accuracy during charging. +- qcom,fastchg-current-ma: Specifies the maximum fastcharge current. +- qcom,fg-cc-cv-threshold-mv: Voltage threshold in mV for transition from constant + charge (CC) to constant voltage (CV). This value should + be 10 mV less than the float voltage. + This property should only be specified if + "qcom,autoadjust-vfloat" property is specified in the + charger driver to ensure a proper operation. +- qcom,thermal-coefficients: Byte array of thermal coefficients for reading + battery thermistor. This should be exactly 6 bytes + in length. + Example: [01 02 03 04 05 06] +- qcom,therm-coefficients: Array of thermal coefficients that will be used in + battery profile for GEN4 FG. This should be exactly of + size 5. +- qcom,therm-center-offset: Specifies the resistor divide ratio between pull-up + resistor and the thermistor for GEN4 FG. +- qcom,therm-pull-up: Specifies the thermistor pull-up resistor value in + KOhms. +- qcom,rslow-normal-coeffs: Array of Rslow coefficients that will be applied + when the battery temperature is greater than 0 degree + Celsius for GEN4 FG. This should be exactly of size 4. +- qcom,rslow-low-coeffs: Array of Rslow coefficients that will be applied + when the battery temperature is lower than 0 degree + Celsius for GEN4 FG. This should be exactly of size 4. +- qcom,soc-based-step-chg: A bool property to indicate if the battery will + perform SoC (State of Charge) based step charging. + If yes, the low and high thresholds defined in + "qcom,step-chg-ranges" tuples should be assigned as + SoC values in percentage. +- qcom,ocv-based-step-chg: A bool property to indicate if the battery will + perform OCV (Open Circuit Voltage) based step charging. + If yes, the low and high thresholds defined in + "qcom,step-chg-ranges" tuples should be assigned as + OCV values in microvolts. +- qcom,step-chg-ranges: Array of tuples in which a tuple describes a range + data of step charging setting. + A range contains following 3 integer elements: + [0]: the low threshold of battery voltage in uV + or SoC (State of Charge) in percentage when + SoC based step charge is used; + [1]: the high threshold of battery voltage in uV + or SoC in percentage when SoC based step charge + is used; + [2]: the FCC (full charging current) in uA when battery + voltage or SoC falls between the low and high + thresholds. + The threshold values in range should be in ascending + and shouldn't overlap. It support 8 ranges at max. +- qcom,jeita-fcc-ranges: Array of tuples in which a tuple describes a range + data of sw-jeita FCC (full charging current) setting. + A range contains following 3 integer elements: + [0]: the low threshold of battery temperature in deci-degree; + [1]: the high threshold of battery temperature in deci-degree; + [2]: the FCC in uA when battery temperature falls between + the low and high thresholds. + The threshold values in range should be in ascending + and shouldn't overlap. It support 8 ranges at max. +- qcom,jeita-fv-ranges: Array of tuples in which a tuple describes a range + data of sw-jeita FV (float voltage) setting. + A range contains following 3 integer elements: + [0]: the low threshold of battery temperature in deci-degree; + [1]: the high threshold of battery temperature in deci-degree; + [3]: the FV in uV when battery temperature falls between + the low and high thresholds. + The threshold values in range should be in ascending + and shouldn't overlap. It support 8 ranges at max. +- qcom,jeita-soft-thresholds: A tuple entry to specify ADC code for battery's soft JEITA + threshold. . +- qcom,jeita-hard-thresholds: A tuple entry to specify ADC code for battery's hard JEITA + threshold. . +- qcom,jeita-soft-hys-thresholds: A tuple entry to specify ADC code for battery's soft JEITA + threshold with hysteresis adjustment. + . + These "hysteresis" values should be specified if + "qcom,jeita-soft-thresholds" are specified. Without which SW JEITA + compensation won't function properly. +- qcom,jeita-soft-fcc-ua: A tuple entry to specify the values of Fast + charging current (in uA) that needs to be applied during + soft JEITA conditions (cool/warm). + Element 0 - FCC value for soft cool. + Element 1 - FCC value for soft warm. +- qcom,jeita-soft-fv-uv: A tuple entry to specify the values of Float + voltage (in uV) that needs to be applied during soft + JEITA conditions (cool/warm). + Element 0 - FV value for soft cool. + Element 1 - FV value for soft warm. +- qcom,batt-age-level: Battery age level. This is used only when multiple + profile loading is supported. +- qcom,soh-range: A tuple entry to specify the values of SOH range that + the battery profile has to be used for. This needs to + be specified along with "qcom,batt-age-level" for the + proper functionality. + Element 0 - SOH minimum level. + Element 1 - SOH maximum level. +- qcom,step-jeita-hysteresis: A tuple entry to allow configuring the rising + and falling hysteresis for better fine tuning of the + charge current across battery temperature thresholds. + This should be in decidegree and if not specified + default select value is 10 DeciDegC. + +Profile data node required subnodes: +- qcom,fcc-temp-lut : An 1-dimensional lookup table node that encodes + temperature to fcc lookup. The units for this lookup + table should be degrees celsius to milliamp-hours. +- qcom,pc-temp-ocv-lut : A 2-dimensional lookup table node that encodes + temperature and percent charge to open circuit voltage + lookup. The units for this lookup table should be + degrees celsius and percent to millivolts. +- qcom,rbatt-sf-lut : A 2-dimentional lookup table node that encodes + temperature and percent charge to battery internal + resistance lookup. The units for this lookup table + should be degrees celsius and percent to milliohms. + +Profile data node optional subnodes: +- qcom,ibat-acc-luit: A 2-dimentional lookup table that encodes temperature + and battery current to battery ACC (apparent charge + capacity). The units for this lookup table should be + temperature in degrees celsius, ibat in milli-amps + and ACC in milli-ampere-hour. + +Lookup table required properties: +- qcom,lut-col-legend : An array that encodes the legend of the lookup table's + columns. The length of this array will determine the + lookup table's width. +- qcom,lut-data : An array that encodes the lookup table's data. The size of this + array should be equal to the size of qcom,lut-col-legend + multiplied by 1 if it's a 1-dimensional table, or + the size of qcom,lut-row-legend if it's a 2-dimensional + table. The data should be in a flattened row-major + representation. + +Lookup table optional properties: +- qcom,lut-row-legend : An array that encodes the legend of the lookup table's rows. + If this property exists, then it is assumed that the + lookup table is a 2-dimensional table. + +Example: + +In msm8974-mtp.dtsi: + +mtp_batterydata: qcom,battery-data { + qcom,rpull-up-kohm = <100>; + qcom,vref-batt-therm-uv = <1800000>; + + /include/ "batterydata-palladium.dtsi" + /include/ "batterydata-mtp-3000mah.dtsi" +}; + +&pm8941_bms { + qcom,battery-data = <&mtp_batterydata>; +}; + +In batterydata-palladium.dtsi: + +qcom,palladium-batterydata { + qcom,fcc-mah = <1500>; + qcom,default-rbatt-mohm = <236>; + qcom,rbatt-capacitive-mohm = <50>; + qcom,flat-ocv-threshold-uv = <3800000>; + qcom,max-voltage-uv = <4200000>; + qcom,v-cutoff-uv = <3400000>; + qcom,chg-term-ua = <100000>; + qcom,batt-id-kohm = <75>; + qcom,jeita-soft-thresholds = <0x3ecc 0x1bff>; + qcom,jeita-hard-thresholds = <0x4aff 0x15aa>; + qcom,step-chg-ranges = <3600000 4000000 3000000 + 4001000 4200000 2800000 + 4201000 4400000 2000000>; + qcom,jeita-fcc-ranges = <0 100 600000 + 101 200 2000000 + 201 450 3000000 + 451 550 600000>; + qcom,jeita-fv-ranges = <0 100 4200000 + 101 450 4350000 + 451 550 4200000>; + qcom,battery-type = "palladium_1500mah"; + + qcom,fcc-temp-lut { + qcom,lut-col-legend = <(-20) 0 25 40 65>; + qcom,lut-data = <1492 1492 1493 1483 1502>; + }; + + qcom,pc-temp-ocv-lut { + qcom,lut-col-legend = <(-20) 0 25 40 65>; + qcom,lut-row-legend = <100 95 90 85 80 75 70>, + <65 60 55 50 45 40 35>, + <30 25 20 15 10 9 8>, + <7 6 5 4 3 2 1 0>; + qcom,lut-data = <4173 4167 4163 4156 4154>, + <4104 4107 4108 4102 4104>, + <4057 4072 4069 4061 4060>, + <3973 4009 4019 4016 4020>, + <3932 3959 3981 3982 3983>, + <3899 3928 3954 3950 3950>, + <3868 3895 3925 3921 3920>, + <3837 3866 3898 3894 3892>, + <3812 3841 3853 3856 3862>, + <3794 3818 3825 3823 3822>, + <3780 3799 3804 3804 3803>, + <3768 3787 3790 3788 3788>, + <3757 3779 3778 3775 3776>, + <3747 3772 3771 3766 3765>, + <3736 3763 3766 3760 3746>, + <3725 3749 3756 3747 3729>, + <3714 3718 3734 3724 3706>, + <3701 3703 3696 3689 3668>, + <3675 3695 3682 3675 3662>, + <3670 3691 3680 3673 3661>, + <3661 3686 3679 3672 3656>, + <3649 3680 3676 3669 3641>, + <3633 3669 3667 3655 3606>, + <3610 3647 3640 3620 3560>, + <3580 3607 3596 3572 3501>, + <3533 3548 3537 3512 3425>, + <3457 3468 3459 3429 3324>, + <3328 3348 3340 3297 3172>, + <3000 3000 3000 3000 3000>; + }; + + qcom,rbatt-sf-lut { + qcom,lut-col-legend = <(-20) 0 25 40 65>; + qcom,lut-row-legend = <100 95 90 85 80 75 70>, + <65 60 55 50 45 40 35>, + <30 25 20 15 10 9 8>, + <7 6 5 4 3 2 1 0>; + qcom,lut-data = <357 187 100 91 91>, + <400 208 105 94 94>, + <390 204 106 95 96>, + <391 201 108 98 98>, + <391 202 110 98 100>, + <390 200 110 99 102>, + <389 200 110 99 102>, + <393 202 101 93 100>, + <407 205 99 89 94>, + <428 208 100 91 96>, + <455 212 102 92 98>, + <495 220 104 93 101>, + <561 232 107 95 102>, + <634 245 112 98 98>, + <714 258 114 98 98>, + <791 266 114 97 100>, + <871 289 108 95 97>, + <973 340 124 108 105>, + <489 241 109 96 99>, + <511 246 110 96 99>, + <534 252 111 95 98>, + <579 263 112 96 96>, + <636 276 111 95 97>, + <730 294 109 96 99>, + <868 328 112 98 104>, + <1089 374 119 101 115>, + <1559 457 128 105 213>, + <12886 1026 637 422 3269>, + <170899 127211 98968 88907 77102>; + }; + + qcom,ibat-acc-lut { + qcom,lut-col-legend = <(-20) 0 25>; + qcom,lut-row-legend = <0 250 500 1000>; + qcom,lut-data = <1470 1470 1473>, + <1406 1406 1430>, + <1247 1247 1414>, + <764 764 1338>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/bluetooth/bluetooth_power.txt b/arch/arm64/boot/dts/vendor/bindings/bluetooth/bluetooth_power.txt new file mode 100644 index 0000000000000000000000000000000000000000..f18ce59469bcb63f3ebd7611dbde45935ba02197 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bluetooth/bluetooth_power.txt @@ -0,0 +1,72 @@ +* Bluetooth Controller +Bluetooth controller communicates with the Bluetooth Host using HCI Transport +layer. HCI Transport layer can be based on UART or USB serial communication +protocol. + +Required properties: + - compatible: Should be set to one of the following: + qca,ar3002 + qca,qca6174 + qca,wcn3990 + qca,qca6390 + qca,wcn6750 + - qca,bt-reset-gpio: GPIO pin to bring BT Controller out of reset + +Optional properties: + - qca,bt-vdd-pa-supply: Bluetooth VDD PA regulator handle + - qca,bt-vdd-io-supply: Bluetooth VDD IO regulator handle + - qca,bt-vdd-ldo-supply: Bluetooth VDD LDO regulator handle. Kept under + optional parameters as some of the chipsets doesn't require ldo + or it may use from same vddio. + - qca,bt-vdd-xtal-supply: Bluetooth VDD XTAL regulator handle + - qca,bt-vdd-core-supply: Bluetooth VDD CORE regulator handle + - qca,bt-vdd-asd-supply: Bluetooth VDD regulator handle for antenna switch + diversity. + - qca,bt-chip-pwd-supply: Chip power down gpio is required when bluetooth + module and other modules like wifi co-exist in a singe chip and + shares a common gpio to bring chip out of reset. + - qca,bt-vdd-pa-voltage-level: specifies VDD PA voltage levels for supply. + Should be specified in pairs (min, max), units uV + - qca,bt-vdd-io-voltage-level: specifies VDD IO voltage levels for supply. + Should be specified in pairs (min, max), units uV + - qca,bt-vdd-ldo-voltage-level: specifies VDD LDO voltage levels for supply. + Should be specified in pairs (min, max), units uV + - qca,bt-vdd-xtal-voltage-level: specifies VDD XTAL voltage levels for supply. + Should be specified in pairs (min, max), units uV + - qca,bt-vdd-core-voltage-level: specifies VDD CORE voltage levels for supply. + - qca,bt-vdd-asd-voltage-level: specifies VDD voltage levels for supply for + antenna switch diversity. Should be specified in pairs (min, max), units uV + - qca,bt-vdd-io-current-level: specifies VDD IO current level in microamps + - qca,bt-vdd-xtal-current-level: specifies VDD XTAL current level in microamps + - qca,bt-vdd-core-current-level: specifies VDD CORE current level in microamps. + - qca,bt-vdd-ldo-current-level: specifies VDD LDO current level in microamps. + - qca,bt-vdd-pa-current-level: specifies VDD PA current level in microamps. + - qca,bt-chip-pwd-current-level: specifies Chip Power current level in microamps. + - qca,bt-vdd-asd-current-level: specifies VDD ASD current level + +Example: + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bluetooth/btfm_slim.txt b/arch/arm64/boot/dts/vendor/bindings/bluetooth/btfm_slim.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e1524a40ba6bc0ad0be8bf0ef44f784e34746c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bluetooth/btfm_slim.txt @@ -0,0 +1,20 @@ +* BTFM Slimbus Slave Driver +BTFM Slimbus Slave driver configure and initialize slimbus slave device. +Bluetooth SCO and FM Audio data is transferred over slimbus interface. + +Required properties: + - compatible: Should be set to one of the following: + btfmslim_slave + - qcom,btfm-slim-ifd: BTFM slimbus slave device entry name + +Optional properties: + - qcom,btfm-slim-ifd-elemental-addr: BTFM slimbus slave device + enumeration address + +Example: + btfmslim_codec: qca6390 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/board/fsl-board.txt b/arch/arm64/boot/dts/vendor/bindings/board/fsl-board.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb52f6b35159d239529790c86ec215f67abc8694 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/board/fsl-board.txt @@ -0,0 +1,111 @@ +Freescale Reference Board Bindings + +This document describes device tree bindings for various devices that +exist on some Freescale reference boards. + +* Board Control and Status (BCSR) + +Required properties: + + - compatible : Should be "fsl,-bcsr" + - reg : Offset and length of the register set for the device + +Example: + + bcsr@f8000000 { + compatible = "fsl,mpc8360mds-bcsr"; + reg = ; + }; + +* Freescale on-board FPGA + +This is the memory-mapped registers for on board FPGA. + +Required properties: +- compatible: should be a board-specific string followed by a string + indicating the type of FPGA. Example: + "fsl,-fpga", "fsl,fpga-pixis", or + "fsl,-fpga", "fsl,fpga-qixis" +- reg: should contain the address and the length of the FPGA register set. + +Optional properties: +- interrupts: should specify event (wakeup) IRQ. + +Example (P1022DS): + + board-control@3,0 { + compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; + reg = <3 0 0x30>; + interrupt-parent = <&mpic>; + interrupts = <8 8 0 0>; + }; + +Example (LS2080A-RDB): + + cpld@3,0 { + compatible = "fsl,ls2080ardb-fpga", "fsl,fpga-qixis"; + reg = <0x3 0 0x10000>; + }; + +* Freescale BCSR GPIO banks + +Some BCSR registers act as simple GPIO controllers, each such +register can be represented by the gpio-controller node. + +Required properities: +- compatible : Should be "fsl,-bcsr-gpio". +- reg : Should contain the address and the length of the GPIO bank + register. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). +- gpio-controller : Marks the port as GPIO controller. + +Example: + + bcsr@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8360mds-bcsr"; + reg = <1 0 0x8000>; + ranges = <0 1 0 0x8000>; + + bcsr13: gpio-controller@d { + #gpio-cells = <2>; + compatible = "fsl,mpc8360mds-bcsr-gpio"; + reg = <0xd 1>; + gpio-controller; + }; + }; + +* Freescale on-board FPGA connected on I2C bus + +Some Freescale boards like BSC9132QDS have on board FPGA connected on +the i2c bus. + +Required properties: +- compatible: Should be a board-specific string followed by a string + indicating the type of FPGA. Example: + "fsl,-fpga", "fsl,fpga-qixis-i2c" +- reg: Should contain the address of the FPGA + +Example: + fpga: fpga@66 { + compatible = "fsl,bsc9132qds-fpga", "fsl,fpga-qixis-i2c"; + reg = <0x66>; + }; + +* Freescale on-board CPLD + +Some Freescale boards like T1040RDB have an on board CPLD connected. + +Required properties: +- compatible: Should be a board-specific string like "fsl,-cpld" + Example: + "fsl,t1040rdb-cpld", "fsl,t1042rdb-cpld", "fsl,t1042rdb_pi-cpld" +- reg: should describe CPLD registers + +Example: + cpld@3,0 { + compatible = "fsl,t1040rdb-cpld"; + reg = <3 0 0x300>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bt-fm/rtc6226_fm.txt b/arch/arm64/boot/dts/vendor/bindings/bt-fm/rtc6226_fm.txt new file mode 100644 index 0000000000000000000000000000000000000000..d77417bf5f024646f95e1805267da5b1fd5ed950 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bt-fm/rtc6226_fm.txt @@ -0,0 +1,13 @@ +Richwave FM radio device + +-FM RX playback with RDS +FM signal is demodulated then audio L/R samples are sent to external audio codec. +FM Rx RDS data received sent to host processor on I2C. + +Required Properties: +- compatible: "rtc6226" + +Example: + rtc6226 { + compatible = "rtc6226"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/brcm,bus-axi.txt b/arch/arm64/boot/dts/vendor/bindings/bus/brcm,bus-axi.txt new file mode 100644 index 0000000000000000000000000000000000000000..edd44d8021392f27b2f3fa1655068f4dbd3b2d8c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/brcm,bus-axi.txt @@ -0,0 +1,53 @@ +Driver for ARM AXI Bus with Broadcom Plugins (bcma) + +Required properties: + +- compatible : brcm,bus-axi + +- reg : iomem address range of chipcommon core + +The cores on the AXI bus are automatically detected by bcma with the +memory ranges they are using and they get registered afterwards. +Automatic detection of the IRQ number is not working on +BCM47xx/BCM53xx ARM SoCs. To assign IRQ numbers to the cores, provide +them manually through device tree. Use an interrupt-map to specify the +IRQ used by the devices on the bus. The first address is just an index, +because we do not have any special register. + +The top-level axi bus may contain children representing attached cores +(devices). This is needed since some hardware details can't be auto +detected (e.g. IRQ numbers). Also some of the cores may be responsible +for extra things, e.g. ChipCommon providing access to the GPIO chip. + +Example: + + axi@18000000 { + compatible = "brcm,bus-axi"; + reg = <0x18000000 0x1000>; + ranges = <0x00000000 0x18000000 0x00100000>; + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x000fffff 0xffff>; + interrupt-map = + /* Ethernet Controller 0 */ + <0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>, + + /* Ethernet Controller 1 */ + <0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; + + /* PCIe Controller 0 */ + <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; + + chipcommon { + reg = <0x00000000 0x1000>; + + gpio-controller; + #gpio-cells = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/brcm,gisb-arb.txt b/arch/arm64/boot/dts/vendor/bindings/bus/brcm,gisb-arb.txt new file mode 100644 index 0000000000000000000000000000000000000000..729def62f0c58a941480b7d760337a9ceb84708b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/brcm,gisb-arb.txt @@ -0,0 +1,33 @@ +Broadcom GISB bus Arbiter controller + +Required properties: + +- compatible: + "brcm,bcm7278-gisb-arb" for V7 28nm chips + "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for other 28nm chips + "brcm,bcm7435-gisb-arb" for newer 40nm chips + "brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips + "brcm,bcm7038-gisb-arb" for 130nm chips +- reg: specifies the base physical address and size of the registers +- interrupts: specifies the two interrupts (timeout and TEA) to be used from + the parent interrupt controller + +Optional properties: + +- brcm,gisb-arb-master-mask: 32-bits wide bitmask used to specify which GISB + masters are valid at the system level +- brcm,gisb-arb-master-names: string list of the litteral name of the GISB + masters. Should match the number of bits set in brcm,gisb-master-mask and + the order in which they appear + +Example: + +gisb-arb@f0400000 { + compatible = "brcm,gisb-arb"; + reg = <0xf0400000 0x800>; + interrupts = <0>, <2>; + interrupt-parent = <&sun_l2_intc>; + + brcm,gisb-arb-master-mask = <0x7>; + brcm,gisb-arb-master-names = "bsp_0", "scpu_0", "cpu_0"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/imx-weim.txt b/arch/arm64/boot/dts/vendor/bindings/bus/imx-weim.txt new file mode 100644 index 0000000000000000000000000000000000000000..683eaf3aed795c74a72348c6eee9ed924553c1e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/imx-weim.txt @@ -0,0 +1,82 @@ +Device tree bindings for i.MX Wireless External Interface Module (WEIM) + +The term "wireless" does not imply that the WEIM is literally an interface +without wires. It simply means that this module was originally designed for +wireless and mobile applications that use low-power technology. + +The actual devices are instantiated from the child nodes of a WEIM node. + +Required properties: + + - compatible: Should contain one of the following: + "fsl,imx1-weim" + "fsl,imx27-weim" + "fsl,imx51-weim" + "fsl,imx50-weim" + "fsl,imx6q-weim" + - reg: A resource specifier for the register space + (see the example below) + - clocks: the clock, see the example below. + - #address-cells: Must be set to 2 to allow memory address translation + - #size-cells: Must be set to 1 to allow CS address passing + - ranges: Must be set up to reflect the memory layout with four + integer values for each chip-select line in use: + + 0 + +Optional properties: + + - fsl,weim-cs-gpr: For "fsl,imx50-weim" and "fsl,imx6q-weim" type of + devices, it should be the phandle to the system General + Purpose Register controller that contains WEIM CS GPR + register, e.g. IOMUXC_GPR1 on i.MX6Q. IOMUXC_GPR1[11:0] + should be set up as one of the following 4 possible + values depending on the CS space configuration. + + IOMUXC_GPR1[11:0] CS0 CS1 CS2 CS3 + --------------------------------------------- + 05 128M 0M 0M 0M + 033 64M 64M 0M 0M + 0113 64M 32M 32M 0M + 01111 32M 32M 32M 32M + + In case that the property is absent, the reset value or + what bootloader sets up in IOMUXC_GPR1[11:0] will be + used. + +Timing property for child nodes. It is mandatory, not optional. + + - fsl,weim-cs-timing: The timing array, contains timing values for the + child node. We can get the CS index from the child + node's "reg" property. The number of registers depends + on the selected chip. + For i.MX1, i.MX21 ("fsl,imx1-weim") there are two + registers: CSxU, CSxL. + For i.MX25, i.MX27, i.MX31 and i.MX35 ("fsl,imx27-weim") + there are three registers: CSCRxU, CSCRxL, CSCRxA. + For i.MX50, i.MX53 ("fsl,imx50-weim"), + i.MX51 ("fsl,imx51-weim") and i.MX6Q ("fsl,imx6q-weim") + there are six registers: CSxGCR1, CSxGCR2, CSxRCR1, + CSxRCR2, CSxWCR1, CSxWCR2. + +Example for an imx6q-sabreauto board, the NOR flash connected to the WEIM: + + weim: weim@21b8000 { + compatible = "fsl,imx6q-weim"; + reg = <0x021b8000 0x4000>; + clocks = <&clks 196>; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x08000000 0x08000000>; + fsl,weim-cs-gpr = <&gpr>; + + nor@0,0 { + compatible = "cfi-flash"; + reg = <0 0 0x02000000>; + #address-cells = <1>; + #size-cells = <1>; + bank-width = <2>; + fsl,weim-cs-timing = <0x00620081 0x00000001 0x1c022000 + 0x0000c000 0x1404a38e 0x00000000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/mhi.txt b/arch/arm64/boot/dts/vendor/bindings/bus/mhi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e496d3bf249bd785d820718061111eb949306990 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/mhi.txt @@ -0,0 +1,360 @@ +MHI Host Interface + +MHI used by the host to control and communicate with modem over +high speed peripheral bus. + +============== +Node Structure +============== + +Main node properties: + +- mhi,max-channels + Usage: required + Value type: + Definition: Maximum number of channels supported by this controller + +- mhi,timeout + Usage: optional + Value type: + Definition: Maximum timeout in ms wait for state and cmd completion + +- mhi,use-bb + Usage: optional + Value type: + Definition: Set true, if PCIe controller does not have full access to host + DDR, and we're using a dedicated memory pool like cma, or + carveout pool. Pool must support atomic allocation. + +- mhi,buffer-len + Usage: optional + Value type: + Definition: MHI automatically pre-allocate buffers for some channel. + Set the length of buffer size to allocate. If not default + size MHI_MAX_MTU will be used. + +- mhi,name + Usage: optional + Value type: + Definition: Name assigned to the controller for cases where caller is not an + MHI client. + Use "esoc0" for qcom modems such as SDX*. + +- mhi,sfr-support + Usage: optional + Value type: + Definition: Set to true if MHI device supports sending subsystem failure + reason upon assert in case PCIe link is functional. + +============================ +mhi channel node properties: +============================ + +- reg + Usage: required + Value type: + Definition: physical channel number + +- label + Usage: required + Value type: + Definition: given name for the channel + +- mhi,num-elements + Usage: optional + Value type: + Definition: Number of elements transfer ring support + +- mhi,local-elements + Usage: optional + Value type: + Definition: Number of elements local ring should allocate. In most cases this + should be left empty. For channels such as RSC, number of elements + should be large enough such that next element in the ring should be + free to queue. + +- mhi,event-ring + Usage: required + Value type: + Definition: Event ring index associated with this channel + +- mhi,chan-dir + Usage: required + Value type: + Definition: Channel direction as defined by enum dma_data_direction + 0 = Bidirectional data transfer + 1 = UL data transfer + 2 = DL data transfer + 3 = No direction, not a regular data transfer channel + +- mhi,ee + Usage: required + Value type: + Definition: Channel execution enviornment (EE) mask as defined by enum + mhi_ch_ee_mask + BIT(0) = Channel supported in PBL EE + BIT(1) = Channel supported in SBL EE + BIT(2) = Channel supported in AMSS EE + BIT(3) = Channel supported in RDDM EE + BIT(4) = Channel supported in WFW EE + BIT(5) = Channel supported in PTHRU EE + BIT(6) = Channel supported in EDL EE + +- mhi,pollcfg + Usage: optional + Value type: + Definition: MHI poll configuration, valid only when burst mode is enabled + 0 = Use default (device specific) polling configuration + For UL channels, value specifies the timer to poll MHI context in + milliseconds. + For DL channels, the threshold to poll the MHI context in multiple of + eight ring element. + +- mhi,data-type + Usage: required + Value type: + Definition: Data transfer type accepted as defined by enum MHI_XFER_TYPE + 0 = accept cpu address for buffer + 1 = accept skb + 2 = accept scatterlist + 3 = offload channel, does not accept any transfer type + 4 = accept pre-mapped buffers + 5 = rsc channel type, accept pre-mapped buffers + +- mhi,doorbell-mode + Usage: required + Value type: + Definition: Channel doorbell mode configuration as defined by enum + MHI_BRSTMODE + 2 = burst mode disabled + 3 = burst mode enabled + +- mhi,lpm-notify + Usage: optional + Value type: + Definition: This channel master require low power mode enter and exit + notifications from mhi bus master. + +- mhi,offload-chan + Usage: optional + Value type: + Definition: Client managed channel, MHI host only involved in setting up + the data path, not involved in active data path. + +- mhi,db-mode-switch + Usage: optional + Value type: + Definition: Must switch to doorbell mode whenever MHI M0 state transition + happens. + +- mhi,auto-queue + Usage: optional + Value type: + Definition: MHI bus driver will pre-allocate buffers for this channel and + queue to hardware. If set, client not allowed to queue buffers. Valid + only for downlink direction. + +- mhi,auto-start + Usage: optional + Value type: + Definition: MHI host driver to automatically start channels once mhi device + driver probe is complete. This should be only set true if initial + handshake iniaitead by external modem. + +- mhi,wake-capable + Usage: optional + Value type: + Definition: Time sensitive data channel, host should process all pending data + before system suspend. + +- mhi,chan-type + Usage: optional + Value type: + Definition: By default, chan-type is same as 'chan,dir' property except + in some special channels, chan type supplement chan direction. + 3 = default no direction, or inbound coalesced channel + +========================== +mhi event node properties: +========================== + +- mhi,num-elements + Usage: required + Value type: + Definition: Number of elements event ring support + +- mhi,intmod + Usage: required + Value type: + Definition: interrupt moderation time in ms + +- mhi,msi + Usage: required + Value type: + Definition: MSI associated with this event ring + +- mhi,chan + Usage: optional + Value type: + Definition: Dedicated channel number, if it's a dedicated event ring + +- mhi,priority + Usage: required + Value type: + Definition: Event ring priority, set to 1 for now + +- mhi,brstmode + Usage: required + Value type: + Definition: Event doorbell mode configuration as defined by + enum MHI_BRSTMODE + 2 = burst mode disabled + 3 = burst mode enabled + +- mhi,data-type + Usage: optional + Value type: + Definition: Type of data this event ring will process as defined + by enum mhi_er_data_type + 0 = process data packets (default) + 1 = process mhi control packets + +- mhi,hw-ev + Usage: optional + Value type: + Definition: Event ring associated with hardware channels + +- mhi,client-manage + Usage: optional + Value type: + Definition: Client manages the event ring (use by napi_poll) + +- mhi,offload + Usage: optional + Value type: + Definition: Event ring associated with offload channel + + +Children node properties: + +MHI drivers that require DT can add driver specific information as a child node. + +- mhi,chan + Usage: Required + Value type: + Definition: Channel name + +======== +Example: +======== +mhi_controller { + mhi,max-channels = <105>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_event@0 { + mhi,num-elements = <32>; + mhi,intmod = <1>; + mhi,msi = <1>; + mhi,chan = <0>; + mhi,priority = <1>; + mhi,bstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <1>; + mhi,msi = <2>; + mhi,chan = <0>; + mhi,priority = <1>; + mhi,bstmode = <2>; + }; + + mhi,timeout = <500>; + + children_node { + mhi,chan = "LOOPBACK" + + }; +}; + +================ +Children Devices +================ + +MHI netdev properties + +- mhi,chan + Usage: required + Value type: + Definition: Channel name MHI netdev support + +- mhi,mru + Usage: required + Value type: + Definition: Largest packet size interface can receive in bytes. + +- mhi,interface-name + Usage: optional + Value type: + Definition: Interface name to be given so clients can identify it + +- aliases + Usage: required + Value type: + Definition: mhi net_device should have numbered alias in the alias node, + in the form of mhi_netdevN, N = 0, 1..n for each network interface. + +- mhi,disable-chain-skb + Usage: optional + Value type: + Definition: If true, netdev will not chain skbs. Set this flag to true + if netdev used as a standalone device. For example, for software IP + path, chaining should be disabled. + +- mhi,rsc-parent + Usage: required for rsc device + Value type: + Definition: RSC channel operate together with IP_HW0 device. If it's a rsc + device, assign phandle of parent device (IP_HW0). + +======== +Example: +======== + +aliases { + mhi_netdev0 = &mhi_netdev_0; +}; + +mhi_netdev_0: mhi_rmnet@0 { + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x4000>; +}; + +mhi_rmnet@1 { + mhi,chan = "IP_HW0_RSC"; + mhi,rsc-parent = <&mhi_netdev_0>; + mhi,mru = <0x8000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/mhi_qcom.txt b/arch/arm64/boot/dts/vendor/bindings/bus/mhi_qcom.txt new file mode 100644 index 0000000000000000000000000000000000000000..db2be634b3eafb3feba0544c62a9f3c12ecfe52f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/mhi_qcom.txt @@ -0,0 +1,98 @@ +Qualcomm Technologies Inc MHI Bus controller + +MHI control driver enables clients to communicate with external mode +using MHI protocol. + +============== +Node Structure +============== + +Main node properties: + +- reg + Usage: required + Value type: Array (5-cell PCI resource) of + Definition: First cell is devfn, which is determined by pci bus topology. + Assign the other cells 0 since they are not used. + +- qcom,smmu-cfg + Usage: required + Value type: + Definition: Required SMMU configuration bitmask for PCIe bus. + BIT mask: + BIT(0) : Attach address mapping to endpoint device + BIT(1) : Set attribute S1_BYPASS + BIT(2) : Set attribute FAST + BIT(3) : Set attribute ATOMIC + BIT(4) : Set attribute FORCE_COHERENT + +- qcom,addr-win + Usage: required if SMMU S1 translation is enabled + Value type: Array of + Definition: Pair of values describing iova start and stop address + +- qcom,msm-bus,name + Usage: required if bus scale used + Value type: + Definition: string representing the bus scale client name to register if + bus scale voting is supported and required. + +- qcom,msm-bus,num-cases + Usage: required if bus scale used + Value type: + Definition: Must be set to two, MHI support two scales + +- qcom,msm-bus,num-paths + Usage: required if bus scale used + Value type: + Definition: Total number of master-slave pairs MHI host will vote. Must be set + to one. + +- qcom,msm-bus,vectors-KBps + Usage: required if bus scale used + Value type: Array of + Definition: Array of tuples which define the bus bandwidth requirements. + Each tuple is of length 4, values are master-id, slave-id, + arbitrated bandwidth in KBps, and instantaneous bandwidth in + KBps. + +- esoc-names + Usage: optional + Value type: + Definition: if external modem managed by esoc framework, set string to "mdm" + +- esoc-0 + Usage: required if device is managed by esoc framework + Value type: phandle + Definition: A esoc phandle pointing to external modem + +- MHI bus settings + Usage: required + Values: as defined by mhi.txt + Definition: Per definition of devicetree/bindings/bus/mhi.txt, define device + specific MHI configuration parameters. + +======== +Example: +======== + +/* pcie domain (root complex) modem connected to */ +&pcie1 { + /* pcie bus modem connected to */ + pci,bus@1 { + reg = <0 0 0 0 0>; + + qcom,mhi { + reg = <0 0 0 0 0>; + qcom,smmu-cfg = <0x3d>; + qcom,addr-win = <0x0 0x20000000 0x0 0x3fffffff>; + qcom,msm-bus,name = "mhi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <45 512 0 0>, + <45 512 1200000000 650000000>; + + + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/mvebu-mbus.txt b/arch/arm64/boot/dts/vendor/bindings/bus/mvebu-mbus.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2ab7fd013bd514e1a4a6ef6a4094deaf65a2184 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/mvebu-mbus.txt @@ -0,0 +1,276 @@ + +* Marvell MBus + +Required properties: + +- compatible: Should be set to one of the following: + marvell,armada370-mbus + marvell,armadaxp-mbus + marvell,armada375-mbus + marvell,armada380-mbus + marvell,kirkwood-mbus + marvell,dove-mbus + marvell,orion5x-88f5281-mbus + marvell,orion5x-88f5182-mbus + marvell,orion5x-88f5181-mbus + marvell,orion5x-88f6183-mbus + marvell,mv78xx0-mbus + +- address-cells: Must be '2'. The first cell for the MBus ID encoding, + the second cell for the address offset within the window. + +- size-cells: Must be '1'. + +- ranges: Must be set up to provide a proper translation for each child. + See the examples below. + +- controller: Contains a single phandle referring to the MBus controller + node. This allows to specify the node that contains the + registers that control the MBus, which is typically contained + within the internal register window (see below). + +Optional properties: + +- pcie-mem-aperture: This optional property contains the aperture for + the memory region of the PCIe driver. + If it's defined, it must encode the base address and + size for the address decoding windows allocated for + the PCIe memory region. + +- pcie-io-aperture: Just as explained for the above property, this + optional property contains the aperture for the + I/O region of the PCIe driver. + +* Marvell MBus controller + +Required properties: + +- compatible: Should be set to "marvell,mbus-controller". + +- reg: Device's register space. + Two or three entries are expected (see the examples below): + the first one controls the devices decoding window, + the second one controls the SDRAM decoding window and + the third controls the MBus bridge (only with the + marvell,armada370-mbus and marvell,armadaxp-mbus + compatible strings) + +Example: + + soc { + compatible = "marvell,armada370-mbus", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + controller = <&mbusc>; + pcie-mem-aperture = <0xe0000000 0x8000000>; + pcie-io-aperture = <0xe8000000 0x100000>; + + internal-regs { + compatible = "simple-bus"; + + mbusc: mbus-controller@20000 { + compatible = "marvell,mbus-controller"; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; + }; + + /* more children ...*/ + }; + }; + +** MBus address decoding window specification + +The MBus children address space is comprised of two cells: the first one for +the window ID and the second one for the offset within the window. +In order to allow to describe valid and non-valid window entries, the +following encoding is used: + + 0xSIAA0000 0x00oooooo + +Where: + + S = 0x0 for a MBus valid window + S = 0xf for a non-valid window (see below) + +If S = 0x0, then: + + I = 4-bit window target ID + AA = windpw attribute + +If S = 0xf, then: + + I = don't care + AA = 1 for internal register + +Following the above encoding, for each ranges entry for a MBus valid window +(S = 0x0), an address decoding window is allocated. On the other side, +entries for translation that do not correspond to valid windows (S = 0xf) +are skipped. + + soc { + compatible = "marvell,armada370-mbus", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + controller = <&mbusc>; + + ranges = <0xf0010000 0 0 0xd0000000 0x100000 + 0x01e00000 0 0 0xfff00000 0x100000>; + + bootrom { + compatible = "marvell,bootrom"; + reg = <0x01e00000 0 0x100000>; + }; + + /* other children */ + ... + + internal-regs { + compatible = "simple-bus"; + ranges = <0 0xf0010000 0 0x100000>; + + mbusc: mbus-controller@20000 { + compatible = "marvell,mbus-controller"; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; + }; + + /* more children ...*/ + }; + }; + +In the shown example, the translation entry in the 'ranges' property is what +makes the MBus driver create a static decoding window for the corresponding +given child device. Note that the binding does not require child nodes to be +present. Of course, child nodes are needed to probe the devices. + +Since each window is identified by its target ID and attribute ID there's +a special macro that can be use to simplify the translation entries: + +#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16)) + +Using this macro, the above example would be: + + soc { + compatible = "marvell,armada370-mbus", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + controller = <&mbusc>; + + ranges = < MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000 + MBUS_ID(0x01, 0xe0) 0 0 0xfff00000 0x100000>; + + bootrom { + compatible = "marvell,bootrom"; + reg = ; + }; + + /* other children */ + ... + + internal-regs { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; + + mbusc: mbus-controller@20000 { + compatible = "marvell,mbus-controller"; + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; + }; + + /* other children */ + ... + }; + }; + + +** About the window base address + +Remember the MBus controller allows a great deal of flexibility for choosing +the decoding window base address. When planning the device tree layout it's +possible to choose any address as the base address, provided of course there's +a region large enough available, and with the required alignment. + +Yet in other words: there's nothing preventing us from setting a base address +of 0xf0000000, or 0xd0000000 for the NOR device shown above, if such region is +unused. + +** Window allocation policy + +The mbus-node ranges property defines a set of mbus windows that are expected +to be set by the operating system and that are guaranteed to be free of overlaps +with one another or with the system memory ranges. + +Each entry in the property refers to exactly one window. If the operating system +chooses to use a different set of mbus windows, it must ensure that any address +translations performed from downstream devices are adapted accordingly. + +The operating system may insert additional mbus windows that do not conflict +with the ones listed in the ranges, e.g. for mapping PCIe devices. +As a special case, the internal register window must be set up by the boot +loader at the address listed in the ranges property, since access to that region +is needed to set up the other windows. + +** Example + +See the example below, where a more complete device tree is shown: + + soc { + compatible = "marvell,armadaxp-mbus", "simple-bus"; + controller = <&mbusc>; + + ranges = ; + + bootrom { + compatible = "marvell,bootrom"; + reg = ; + }; + + devbus-bootcs { + ranges = <0 MBUS_ID(0x01, 0x2f) 0 0x8000000>; + + /* NOR */ + nor { + compatible = "cfi-flash"; + reg = <0 0x8000000>; + bank-width = <2>; + }; + }; + + pcie-controller { + compatible = "marvell,armada-xp-pcie"; + device_type = "pci"; + + #address-cells = <3>; + #size-cells = <2>; + + ranges = + <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */ + 0x82000000 0 0x42000 MBUS_ID(0xf0, 0x01) 0x42000 0 0x00002000 /* Port 2.0 registers */ + 0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 /* Port 0.1 registers */ + 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */ + 0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */ + 0x82000800 0 0xe0000000 MBUS_ID(0x04, 0xe8) 0xe0000000 0 0x08000000 /* Port 0.0 MEM */ + 0x81000800 0 0 MBUS_ID(0x04, 0xe0) 0xe8000000 0 0x00100000 /* Port 0.0 IO */>; + + + pcie@1,0 { + /* Port 0, Lane 0 */ + }; + }; + + internal-regs { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; + + mbusc: mbus-controller@20000 { + reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>; + }; + + interrupt-controller@20000 { + reg = <0x20a00 0x2d0>, <0x21070 0x58>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/nvidia,tegra20-gmi.txt b/arch/arm64/boot/dts/vendor/bindings/bus/nvidia,tegra20-gmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1e70621799b1f451e96e6f19446c67992a2b98a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/nvidia,tegra20-gmi.txt @@ -0,0 +1,128 @@ +Device tree bindings for NVIDIA Tegra Generic Memory Interface bus + +The Generic Memory Interface bus enables memory transfers between internal and +external memory. Can be used to attach various high speed devices such as +synchronous/asynchronous NOR, FPGA, UARTS and more. + +The actual devices are instantiated from the child nodes of a GMI node. + +Required properties: + - compatible : Should contain one of the following: + For Tegra20 must contain "nvidia,tegra20-gmi". + For Tegra30 must contain "nvidia,tegra30-gmi". + - reg: Should contain GMI controller registers location and length. + - clocks: Must contain an entry for each entry in clock-names. + - clock-names: Must include the following entries: "gmi" + - resets : Must contain an entry for each entry in reset-names. + - reset-names : Must include the following entries: "gmi" + - #address-cells: The number of cells used to represent physical base + addresses in the GMI address space. Should be 2. + - #size-cells: The number of cells used to represent the size of an address + range in the GMI address space. Should be 1. + - ranges: Must be set up to reflect the memory layout with three integer values + for each chip-select line in use (only one entry is supported, see below + comments): + + +Note that the GMI controller does not have any internal chip-select address +decoding, because of that chip-selects either need to be managed via software +or by employing external chip-select decoding logic. + +If external chip-select logic is used to support multiple devices it is assumed +that the devices use the same timing and so are probably the same type. It also +assumes that they can fit in the 256MB address range. In this case only one +child device is supported which represents the active chip-select line, see +examples for more insight. + +The chip-select number is decoded from the child nodes second address cell of +'ranges' property, if 'ranges' property is not present or empty chip-select will +then be decoded from the first cell of the 'reg' property. + +Optional child cs node properties: + + - nvidia,snor-data-width-32bit: Use 32bit data-bus, default is 16bit. + - nvidia,snor-mux-mode: Enable address/data MUX mode. + - nvidia,snor-rdy-active-before-data: Assert RDY signal one cycle before data. + If omitted it will be asserted with data. + - nvidia,snor-rdy-active-high: RDY signal is active high + - nvidia,snor-adv-active-high: ADV signal is active high + - nvidia,snor-oe-active-high: WE/OE signal is active high + - nvidia,snor-cs-active-high: CS signal is active high + + Note that there is some special handling for the timing values. + From Tegra TRM: + Programming 0 means 1 clock cycle: actual cycle = programmed cycle + 1 + + - nvidia,snor-muxed-width: Number of cycles MUX address/data asserted on the + bus. Valid values are 0-15, default is 1 + - nvidia,snor-hold-width: Number of cycles CE stays asserted after the + de-assertion of WR_N (in case of SLAVE/MASTER Request) or OE_N + (in case of MASTER Request). Valid values are 0-15, default is 1 + - nvidia,snor-adv-width: Number of cycles during which ADV stays asserted. + Valid values are 0-15, default is 1. + - nvidia,snor-ce-width: Number of cycles before CE is asserted. + Valid values are 0-15, default is 4 + - nvidia,snor-we-width: Number of cycles during which WE stays asserted. + Valid values are 0-15, default is 1 + - nvidia,snor-oe-width: Number of cycles during which OE stays asserted. + Valid values are 0-255, default is 1 + - nvidia,snor-wait-width: Number of cycles before READY is asserted. + Valid values are 0-255, default is 3 + +Example with two SJA1000 CAN controllers connected to the GMI bus. We wrap the +controllers with a simple-bus node since they are all connected to the same +chip-select (CS4), in this example external address decoding is provided: + +gmi@70009000 { + compatible = "nvidia,tegra20-gmi"; + reg = <0x70009000 0x1000>; + #address-cells = <2>; + #size-cells = <1>; + clocks = <&tegra_car TEGRA20_CLK_NOR>; + clock-names = "gmi"; + resets = <&tegra_car 42>; + reset-names = "gmi"; + ranges = <4 0 0xd0000000 0xfffffff>; + + bus@4,0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 4 0 0x40100>; + + nvidia,snor-mux-mode; + nvidia,snor-adv-active-high; + + can@0 { + reg = <0 0x100>; + ... + }; + + can@40000 { + reg = <0x40000 0x100>; + ... + }; + }; +}; + +Example with one SJA1000 CAN controller connected to the GMI bus +on CS4: + +gmi@70009000 { + compatible = "nvidia,tegra20-gmi"; + reg = <0x70009000 0x1000>; + #address-cells = <2>; + #size-cells = <1>; + clocks = <&tegra_car TEGRA20_CLK_NOR>; + clock-names = "gmi"; + resets = <&tegra_car 42>; + reset-names = "gmi"; + ranges = <4 0 0xd0000000 0xfffffff>; + + can@4,0 { + reg = <4 0 0x100>; + nvidia,snor-mux-mode; + nvidia,snor-adv-active-high; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/nvidia,tegra210-aconnect.txt b/arch/arm64/boot/dts/vendor/bindings/bus/nvidia,tegra210-aconnect.txt new file mode 100644 index 0000000000000000000000000000000000000000..3108d03802ee9c2d7e16de057f3ccfb9e999c455 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/nvidia,tegra210-aconnect.txt @@ -0,0 +1,44 @@ +NVIDIA Tegra ACONNECT Bus + +The Tegra ACONNECT bus is an AXI switch which is used to connnect various +components inside the Audio Processing Engine (APE). All CPU accesses to +the APE subsystem go through the ACONNECT via an APB to AXI wrapper. + +Required properties: +- compatible: Must be "nvidia,tegra210-aconnect". +- clocks: Must contain the entries for the APE clock (TEGRA210_CLK_APE), + and APE interface clock (TEGRA210_CLK_APB2APE). +- clock-names: Must contain the names "ape" and "apb2ape" for the corresponding + 'clocks' entries. +- power-domains: Must contain a phandle that points to the audio powergate + (namely 'aud') for Tegra210. +- #address-cells: The number of cells used to represent physical base addresses + in the aconnect address space. Should be 1. +- #size-cells: The number of cells used to represent the size of an address + range in the aconnect address space. Should be 1. +- ranges: Mapping of the aconnect address space to the CPU address space. + +All devices accessed via the ACONNNECT are described by child-nodes. + +Example: + + aconnect@702c0000 { + compatible = "nvidia,tegra210-aconnect"; + clocks = <&tegra_car TEGRA210_CLK_APE>, + <&tegra_car TEGRA210_CLK_APB2APE>; + clock-names = "ape", "apb2ape"; + power-domains = <&pd_audio>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x702c0000 0x0 0x702c0000 0x00040000>; + + + child1 { + ... + }; + + child2 { + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/omap-ocp2scp.txt b/arch/arm64/boot/dts/vendor/bindings/bus/omap-ocp2scp.txt new file mode 100644 index 0000000000000000000000000000000000000000..18729f6fe1e5fbc5dea3e36c98715b4c22e4315f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/omap-ocp2scp.txt @@ -0,0 +1,29 @@ +* OMAP OCP2SCP - ocp interface to scp interface + +properties: +- compatible : Should be "ti,am437x-ocp2scp" for AM437x processor + Should be "ti,omap-ocp2scp" for all others +- reg : Address and length of the register set for the device +- #address-cells, #size-cells : Must be present if the device has sub-nodes +- ranges : the child address space are mapped 1:1 onto the parent address space +- ti,hwmods : must be "ocp2scp_usb_phy" + +Sub-nodes: +All the devices connected to ocp2scp are described using sub-node to ocp2scp + +ocp2scp@4a0ad000 { + compatible = "ti,omap-ocp2scp"; + reg = <0x4a0ad000 0x1f>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + ti,hwmods = "ocp2scp_usb_phy"; + + subnode1 { + ... + }; + + subnode2 { + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/qcom,ebi2.txt b/arch/arm64/boot/dts/vendor/bindings/bus/qcom,ebi2.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a7d567f68339f537b99904860b46fe22be4529f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/qcom,ebi2.txt @@ -0,0 +1,138 @@ +Qualcomm External Bus Interface 2 (EBI2) + +The EBI2 contains two peripheral blocks: XMEM and LCDC. The XMEM handles any +external memory (such as NAND or other memory-mapped peripherals) whereas +LCDC handles LCD displays. + +As it says it connects devices to an external bus interface, meaning address +lines (up to 9 address lines so can only address 1KiB external memory space), +data lines (16 bits), OE (output enable), ADV (address valid, used on some +NOR flash memories), WE (write enable). This on top of 6 different chip selects +(CS0 thru CS5) so that in theory 6 different devices can be connected. + +Apparently this bus is clocked at 64MHz. It has dedicated pins on the package +and the bus can only come out on these pins, however if some of the pins are +unused they can be left unconnected or remuxed to be used as GPIO or in some +cases other orthogonal functions as well. + +Also CS1 and CS2 has -A and -B signals. Why they have that is unclear to me. + +The chip selects have the following memory range assignments. This region of +memory is referred to as "Chip Peripheral SS FPB0" and is 168MB big. + +Chip Select Physical address base +CS0 GPIO134 0x1a800000-0x1b000000 (8MB) +CS1 GPIO39 (A) / GPIO123 (B) 0x1b000000-0x1b800000 (8MB) +CS2 GPIO40 (A) / GPIO124 (B) 0x1b800000-0x1c000000 (8MB) +CS3 GPIO133 0x1d000000-0x25000000 (128 MB) +CS4 GPIO132 0x1c800000-0x1d000000 (8MB) +CS5 GPIO131 0x1c000000-0x1c800000 (8MB) + +The APQ8060 Qualcomm Application Processor User Guide, 80-N7150-14 Rev. A, +August 6, 2012 contains some incomplete documentation of the EBI2. + +FIXME: the manual mentions "write precharge cycles" and "precharge cycles". +We have not been able to figure out which bit fields these correspond to +in the hardware, or what valid values exist. The current hypothesis is that +this is something just used on the FAST chip selects and that the SLOW +chip selects are understood fully. There is also a "byte device enable" +flag somewhere for 8bit memories. + +FIXME: The chipselects have SLOW and FAST configuration registers. It's a bit +unclear what this means, if they are mutually exclusive or can be used +together, or if some chip selects are hardwired to be FAST and others are SLOW +by design. + +The XMEM registers are totally undocumented but could be partially decoded +because the Cypress AN49576 Antioch Westbridge apparently has suspiciously +similar register layout, see: http://www.cypress.com/file/105771/download + +Required properties: +- compatible: should be one of: + "qcom,msm8660-ebi2" + "qcom,apq8060-ebi2" +- #address-cells: should be <2>: the first cell is the chipselect, + the second cell is the offset inside the memory range +- #size-cells: should be <1> +- ranges: should be set to: + ranges = <0 0x0 0x1a800000 0x00800000>, + <1 0x0 0x1b000000 0x00800000>, + <2 0x0 0x1b800000 0x00800000>, + <3 0x0 0x1d000000 0x08000000>, + <4 0x0 0x1c800000 0x00800000>, + <5 0x0 0x1c000000 0x00800000>; +- reg: two ranges of registers: EBI2 config and XMEM config areas +- reg-names: should be "ebi2", "xmem" +- clocks: two clocks, EBI_2X and EBI +- clock-names: should be "ebi2x", "ebi2" + +Optional subnodes: +- Nodes inside the EBI2 will be considered device nodes. + +The following optional properties are properties that can be tagged onto +any device subnode. We are assuming that there can be only ONE device per +chipselect subnode, else the properties will become ambigous. + +Optional properties arrays for SLOW chip selects: +- qcom,xmem-recovery-cycles: recovery cycles is the time the memory continues to + drive the data bus after OE is de-asserted, in order to avoid contention on + the data bus. They are inserted when reading one CS and switching to another + CS or read followed by write on the same CS. Valid values 0 thru 15. Minimum + value is actually 1, so a value of 0 will still yield 1 recovery cycle. +- qcom,xmem-write-hold-cycles: write hold cycles, these are extra cycles + inserted after every write minimum 1. The data out is driven from the time + WE is asserted until CS is asserted. With a hold of 1 (value = 0), the CS + stays active for 1 extra cycle etc. Valid values 0 thru 15. +- qcom,xmem-write-delta-cycles: initial latency for write cycles inserted for + the first write to a page or burst memory. Valid values 0 thru 255. +- qcom,xmem-read-delta-cycles: initial latency for read cycles inserted for the + first read to a page or burst memory. Valid values 0 thru 255. +- qcom,xmem-write-wait-cycles: number of wait cycles for every write access, 0=1 + cycle. Valid values 0 thru 15. +- qcom,xmem-read-wait-cycles: number of wait cycles for every read access, 0=1 + cycle. Valid values 0 thru 15. + +Optional properties arrays for FAST chip selects: +- qcom,xmem-address-hold-enable: this is a boolean property stating that we + shall hold the address for an extra cycle to meet hold time requirements + with ADV assertion. +- qcom,xmem-adv-to-oe-recovery-cycles: the number of cycles elapsed before an OE + assertion, with respect to the cycle where ADV (address valid) is asserted. + 2 means 2 cycles between ADV and OE. Valid values 0, 1, 2 or 3. +- qcom,xmem-read-hold-cycles: the length in cycles of the first segment of a + read transfer. For a single read transfer this will be the time from CS + assertion to OE assertion. Valid values 0 thru 15. + + +Example: + +ebi2@1a100000 { + compatible = "qcom,apq8060-ebi2"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0x0 0x1a800000 0x00800000>, + <1 0x0 0x1b000000 0x00800000>, + <2 0x0 0x1b800000 0x00800000>, + <3 0x0 0x1d000000 0x08000000>, + <4 0x0 0x1c800000 0x00800000>, + <5 0x0 0x1c000000 0x00800000>; + reg = <0x1a100000 0x1000>, <0x1a110000 0x1000>; + reg-names = "ebi2", "xmem"; + clocks = <&gcc EBI2_2X_CLK>, <&gcc EBI2_CLK>; + clock-names = "ebi2x", "ebi2"; + /* Make sure to set up the pin control for the EBI2 */ + pinctrl-names = "default"; + pinctrl-0 = <&foo_ebi2_pins>; + + foo-ebi2@2,0 { + compatible = "foo"; + reg = <2 0x0 0x100>; + (...) + qcom,xmem-recovery-cycles = <0>; + qcom,xmem-write-hold-cycles = <3>; + qcom,xmem-write-delta-cycles = <31>; + qcom,xmem-read-delta-cycles = <28>; + qcom,xmem-write-wait-cycles = <9>; + qcom,xmem-read-wait-cycles = <9>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/renesas,bsc.txt b/arch/arm64/boot/dts/vendor/bindings/bus/renesas,bsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..90e94726943772c495942e39ebe86decf1d4d7f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/renesas,bsc.txt @@ -0,0 +1,46 @@ +Renesas Bus State Controller (BSC) +================================== + +The Renesas Bus State Controller (BSC, sometimes called "LBSC within Bus +Bridge", or "External Bus Interface") can be found in several Renesas ARM SoCs. +It provides an external bus for connecting multiple external devices to the +SoC, driving several chip select lines, for e.g. NOR FLASH, Ethernet and USB. + +While the BSC is a fairly simple memory-mapped bus, it may be part of a PM +domain, and may have a gateable functional clock. +Before a device connected to the BSC can be accessed, the PM domain +containing the BSC must be powered on, and the functional clock +driving the BSC must be enabled. + +The bindings for the BSC extend the bindings for "simple-pm-bus". + + +Required properties + - compatible: Must contain an SoC-specific value, and "renesas,bsc" and + "simple-pm-bus" as fallbacks. + SoC-specific values can be: + "renesas,bsc-r8a73a4" for R-Mobile APE6 (r8a73a4) + "renesas,bsc-sh73a0" for SH-Mobile AG5 (sh73a0) + - #address-cells, #size-cells, ranges: Must describe the mapping between + parent address and child address spaces. + - reg: Must contain the base address and length to access the bus controller. + +Optional properties: + - interrupts: Must contain a reference to the BSC interrupt, if available. + - clocks: Must contain a reference to the functional clock, if available. + - power-domains: Must contain a reference to the PM domain, if available. + + +Example: + + bsc: bus@fec10000 { + compatible = "renesas,bsc-sh73a0", "renesas,bsc", + "simple-pm-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x20000000>; + reg = <0xfec10000 0x400>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zb_clk>; + power-domains = <&pd_a4s>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/simple-pm-bus.txt b/arch/arm64/boot/dts/vendor/bindings/bus/simple-pm-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f15037131ed55664a5127087a62b091eae4a06a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/simple-pm-bus.txt @@ -0,0 +1,44 @@ +Simple Power-Managed Bus +======================== + +A Simple Power-Managed Bus is a transparent bus that doesn't need a real +driver, as it's typically initialized by the boot loader. + +However, its bus controller is part of a PM domain, or under the control of a +functional clock. Hence, the bus controller's PM domain and/or clock must be +enabled for child devices connected to the bus (either on-SoC or externally) +to function. + +While "simple-pm-bus" follows the "simple-bus" set of properties, as specified +in the Devicetree Specification, it is not an extension of "simple-bus". + + +Required properties: + - compatible: Must contain at least "simple-pm-bus". + Must not contain "simple-bus". + It's recommended to let this be preceded by one or more + vendor-specific compatible values. + - #address-cells, #size-cells, ranges: Must describe the mapping between + parent address and child address spaces. + +Optional platform-specific properties for clock or PM domain control (at least +one of them is required): + - clocks: Must contain a reference to the functional clock(s), + - power-domains: Must contain a reference to the PM domain. +Please refer to the binding documentation for the clock and/or PM domain +providers for more details. + + +Example: + + bsc: bus@fec10000 { + compatible = "renesas,bsc-sh73a0", "renesas,bsc", + "simple-pm-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0x20000000>; + reg = <0xfec10000 0x400>; + interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zb_clk>; + power-domains = <&pd_a4s>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/sun50i-de2-bus.txt b/arch/arm64/boot/dts/vendor/bindings/bus/sun50i-de2-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..87dfb33fb3bebd12a075f4e8d6b366337f0255d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/sun50i-de2-bus.txt @@ -0,0 +1,37 @@ +Device tree bindings for Allwinner A64 DE2 bus + +The Allwinner A64 DE2 is on a special bus, which needs a SRAM region (SRAM C) +to be claimed for enabling the access. + +Required properties: + + - compatible: Should contain "allwinner,sun50i-a64-de2" + - reg: A resource specifier for the register space + - #address-cells: Must be set to 1 + - #size-cells: Must be set to 1 + - ranges: Must be set up to map the address space inside the + DE2, for the sub-blocks of DE2. + - allwinner,sram: the SRAM that needs to be claimed + +Example: + + de2@1000000 { + compatible = "allwinner,sun50i-a64-de2"; + reg = <0x1000000 0x400000>; + allwinner,sram = <&de2_sram 1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1000000 0x400000>; + + display_clocks: clock@0 { + compatible = "allwinner,sun50i-a64-de2-clk"; + reg = <0x0 0x100000>; + clocks = <&ccu CLK_DE>, + <&ccu CLK_BUS_DE>; + clock-names = "mod", + "bus"; + resets = <&ccu RST_BUS_DE>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/sunxi-rsb.txt b/arch/arm64/boot/dts/vendor/bindings/bus/sunxi-rsb.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb3ed628c6f1a1b8894c392db472354f78a75bff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/sunxi-rsb.txt @@ -0,0 +1,47 @@ +Allwinner Reduced Serial Bus (RSB) controller + +The RSB controller found on later Allwinner SoCs is an SMBus like 2 wire +serial bus with 1 master and up to 15 slaves. It is represented by a node +for the controller itself, and child nodes representing the slave devices. + +Required properties : + + - reg : Offset and length of the register set for the controller. + - compatible : Shall be "allwinner,sun8i-a23-rsb". + - interrupts : The interrupt line associated to the RSB controller. + - clocks : The gate clk associated to the RSB controller. + - resets : The reset line associated to the RSB controller. + - #address-cells : shall be 1 + - #size-cells : shall be 0 + +Optional properties : + + - clock-frequency : Desired RSB bus clock frequency in Hz. Maximum is 20MHz. + If not set this defaults to 3MHz. + +Child nodes: + +An RSB controller node can contain zero or more child nodes representing +slave devices on the bus. Child 'reg' properties should contain the slave +device's hardware address. The hardware address is hardwired in the device, +which can normally be found in the datasheet. + +Example: + + rsb@1f03400 { + compatible = "allwinner,sun8i-a23-rsb"; + reg = <0x01f03400 0x400>; + interrupts = <0 39 4>; + clocks = <&apb0_gates 3>; + clock-frequency = <3000000>; + resets = <&apb0_rst 3>; + #address-cells = <1>; + #size-cells = <0>; + + pmic@3e3 { + compatible = "..."; + reg = <0x3e3>; + + /* ... */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/ti,da850-mstpri.txt b/arch/arm64/boot/dts/vendor/bindings/bus/ti,da850-mstpri.txt new file mode 100644 index 0000000000000000000000000000000000000000..72daefc6b4a1fcff2447ed839c7c091b6e6433fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/ti,da850-mstpri.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Texas Instruments da8xx master peripheral + priority driver + +DA8XX SoCs feature a set of registers allowing to change the priority of all +peripherals classified as masters. + +Documentation: +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf + +Required properties: + +- compatible: "ti,da850-mstpri" - for da850 based boards +- reg: offset and length of the mstpri registers + +Example for da850-lcdk is shown below. + +mstpri { + compatible = "ti,da850-mstpri"; + reg = <0x14110 0x0c>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/ti-sysc.txt b/arch/arm64/boot/dts/vendor/bindings/bus/ti-sysc.txt new file mode 100644 index 0000000000000000000000000000000000000000..91dc2333af012771e915981ed5df8bb8800d8d5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/ti-sysc.txt @@ -0,0 +1,135 @@ +Texas Instruments sysc interconnect target module wrapper binding + +Texas Instruments SoCs can have a generic interconnect target module +hardware for devices connected to various interconnects such as L3 +interconnect (Arteris NoC) and L4 interconnect (Sonics s3220). The sysc +is mostly used for interaction between module and PRCM. It participates +in the OCP Disconnect Protocol but other than that is mostly independent +of the interconnect. + +Each interconnect target module can have one or more devices connected to +it. There is a set of control registers for managing interconnect target +module clocks, idle modes and interconnect level resets for the module. + +These control registers are sprinkled into the unused register address +space of the first child device IP block managed by the interconnect +target module and typically are named REVISION, SYSCONFIG and SYSSTATUS. + +Required standard properties: + +- compatible shall be one of the following generic types: + + "ti,sysc" + "ti,sysc-omap2" + "ti,sysc-omap4" + "ti,sysc-omap4-simple" + + or one of the following derivative types for hardware + needing special workarounds: + + "ti,sysc-omap2-timer" + "ti,sysc-omap4-timer" + "ti,sysc-omap3430-sr" + "ti,sysc-omap3630-sr" + "ti,sysc-omap4-sr" + "ti,sysc-omap3-sham" + "ti,sysc-omap-aes" + "ti,sysc-mcasp" + "ti,sysc-usb-host-fs" + "ti,sysc-dra7-mcan" + +- reg shall have register areas implemented for the interconnect + target module in question such as revision, sysc and syss + +- reg-names shall contain the register names implemented for the + interconnect target module in question such as + "rev, "sysc", and "syss" + +- ranges shall contain the interconnect target module IO range + available for one or more child device IP blocks managed + by the interconnect target module, the ranges may include + multiple ranges such as device L4 range for control and + parent L3 range for DMA access + +Optional properties: + +- ti,sysc-mask shall contain mask of supported register bits for the + SYSCONFIG register as documented in the Technical Reference + Manual (TRM) for the interconnect target module + +- ti,sysc-midle list of master idle modes supported by the interconnect + target module as documented in the TRM for SYSCONFIG + register MIDLEMODE bits + +- ti,sysc-sidle list of slave idle modes supported by the interconnect + target module as documented in the TRM for SYSCONFIG + register SIDLEMODE bits + +- ti,sysc-delay-us delay needed after OCP softreset before accssing + SYSCONFIG register again + +- ti,syss-mask optional mask of reset done status bits as described in the + TRM for SYSSTATUS registers, typically 1 with some devices + having separate reset done bits for children like OHCI and + EHCI + +- clocks clock specifier for each name in the clock-names as + specified in the binding documentation for ti-clkctrl, + typically available for all interconnect targets on TI SoCs + based on omap4 except if it's read-only register in hwauto + mode as for example omap4 L4_CFG_CLKCTRL + +- clock-names should contain at least "fck", and optionally also "ick" + depending on the SoC and the interconnect target module, + some interconnect target modules also need additional + optional clocks that can be specified as listed in TRM + for the related CLKCTRL register bits 8 to 15 such as + "dbclk" or "clk32k" depending on their role + +- ti,hwmods optional TI interconnect module name to use legacy + hwmod platform data + +- ti,no-reset-on-init interconnect target module should not be reset at init + +- ti,no-idle-on-init interconnect target module should not be idled at init + +Example: Single instance of MUSB controller on omap4 using interconnect ranges +using offsets from l4_cfg second segment (0x4a000000 + 0x80000 = 0x4a0ab000): + + target-module@2b000 { /* 0x4a0ab000, ap 84 12.0 */ + compatible = "ti,sysc-omap2"; + ti,hwmods = "usb_otg_hs"; + reg = <0x2b400 0x4>, + <0x2b404 0x4>, + <0x2b408 0x4>; + reg-names = "rev", "sysc", "syss"; + clocks = <&l3_init_clkctrl OMAP4_USB_OTG_HS_CLKCTRL 0>; + clock-names = "fck"; + ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP | + SYSC_OMAP2_SOFTRESET | + SYSC_OMAP2_AUTOIDLE)>; + ti,sysc-midle = , + , + ; + ti,sysc-sidle = , + , + , + ; + ti,syss-mask = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x2b000 0x1000>; + + usb_otg_hs: otg@0 { + compatible = "ti,omap4-musb"; + reg = <0x0 0x7ff>; + interrupts = , + ; + usb-phy = <&usb2_phy>; + ... + }; + }; + +Note that other SoCs, such as am335x can have multipe child devices. On am335x +there are two MUSB instances, two USB PHY instances, and a single CPPI41 DMA +instance as children of a single interconnet target module. diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/ts-nbus.txt b/arch/arm64/boot/dts/vendor/bindings/bus/ts-nbus.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a10d065b9fab703e05bed7c7e012072cdab1574 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/ts-nbus.txt @@ -0,0 +1,50 @@ +Technologic Systems NBUS + +The NBUS is a bus used to interface with peripherals in the Technologic +Systems FPGA on the TS-4600 SoM. + +Required properties : + - compatible : "technologic,ts-nbus" + - #address-cells : must be 1 + - #size-cells : must be 0 + - pwms : The PWM bound to the FPGA + - ts,data-gpios : The 8 GPIO pins connected to the data lines on the FPGA + - ts,csn-gpios : The GPIO pin connected to the csn line on the FPGA + - ts,txrx-gpios : The GPIO pin connected to the txrx line on the FPGA + - ts,strobe-gpios : The GPIO pin connected to the stobe line on the FPGA + - ts,ale-gpios : The GPIO pin connected to the ale line on the FPGA + - ts,rdy-gpios : The GPIO pin connected to the rdy line on the FPGA + +Child nodes: + +The NBUS node can contain zero or more child nodes representing peripherals +on the bus. + +Example: + + nbus { + compatible = "technologic,ts-nbus"; + pinctrl-0 = <&nbus_pins>; + #address-cells = <1>; + #size-cells = <0>; + pwms = <&pwm 2 83>; + ts,data-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH + &gpio0 1 GPIO_ACTIVE_HIGH + &gpio0 2 GPIO_ACTIVE_HIGH + &gpio0 3 GPIO_ACTIVE_HIGH + &gpio0 4 GPIO_ACTIVE_HIGH + &gpio0 5 GPIO_ACTIVE_HIGH + &gpio0 6 GPIO_ACTIVE_HIGH + &gpio0 7 GPIO_ACTIVE_HIGH>; + ts,csn-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + ts,txrx-gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>; + ts,strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; + ts,ale-gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>; + ts,rdy-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + + watchdog@2a { + compatible = "..."; + + /* ... */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/bus/uniphier-system-bus.txt b/arch/arm64/boot/dts/vendor/bindings/bus/uniphier-system-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..68ef80afff168eaa0c9e0c58f31cb10e1cb3e14c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/bus/uniphier-system-bus.txt @@ -0,0 +1,66 @@ +UniPhier System Bus + +The UniPhier System Bus is an external bus that connects on-board devices to +the UniPhier SoC. It is a simple (semi-)parallel bus with address, data, and +some control signals. It supports up to 8 banks (chip selects). + +Before any access to the bus, the bus controller must be configured; the bus +controller registers provide the control for the translation from the offset +within each bank to the CPU-viewed address. The needed setup includes the base +address, the size of each bank. Optionally, some timing parameters can be +optimized for faster bus access. + +Required properties: +- compatible: should be "socionext,uniphier-system-bus". +- reg: offset and length of the register set for the bus controller device. +- #address-cells: should be 2. The first cell is the bank number (chip select). + The second cell is the address offset within the bank. +- #size-cells: should be 1. +- ranges: should provide a proper address translation from the System Bus to + the parent bus. + +Note: +The address region(s) that can be assigned for the System Bus is implementation +defined. Some SoCs can use 0x00000000-0x0fffffff and 0x40000000-0x4fffffff, +while other SoCs can only use 0x40000000-0x4fffffff. There might be additional +limitations depending on SoCs and the boot mode. The address translation is +arbitrary as long as the banks are assigned in the supported address space with +the required alignment and they do not overlap one another. +For example, it is possible to map: + bank 0 to 0x42000000-0x43ffffff, bank 5 to 0x46000000-0x46ffffff +It is also possible to map: + bank 0 to 0x48000000-0x49ffffff, bank 5 to 0x44000000-0x44ffffff +There is no reason to stick to a particular translation mapping, but the +"ranges" property should provide a "reasonable" default that is known to work. +The software should initialize the bus controller according to it. + +Example: + + system-bus { + compatible = "socionext,uniphier-system-bus"; + reg = <0x58c00000 0x400>; + #address-cells = <2>; + #size-cells = <1>; + ranges = <1 0x00000000 0x42000000 0x02000000 + 5 0x00000000 0x46000000 0x01000000>; + + ethernet@1,01f00000 { + compatible = "smsc,lan9115"; + reg = <1 0x01f00000 0x1000>; + interrupts = <0 48 4> + phy-mode = "mii"; + }; + + uart@5,00200000 { + compatible = "ns16550a"; + reg = <5 0x00200000 0x20>; + interrupts = <0 49 4> + clock-frequency = <12288000>; + }; + }; + +In this example, + - the Ethernet device is connected at the offset 0x01f00000 of CS1 and + mapped to 0x43f00000 of the parent bus. + - the UART device is connected at the offset 0x00200000 of CS5 and + mapped to 0x46200000 of the parent bus. diff --git a/arch/arm64/boot/dts/vendor/bindings/c6x/clocks.txt b/arch/arm64/boot/dts/vendor/bindings/c6x/clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..a04f5fd30122064f2a03f24441cf7b37b5e537f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/c6x/clocks.txt @@ -0,0 +1,40 @@ +C6X PLL Clock Controllers +------------------------- + +This is a first-cut support for the SoC clock controllers. This is still +under development and will probably change as the common device tree +clock support is added to the kernel. + +Required properties: + +- compatible: "ti,c64x+pll" + May also have SoC-specific value to support SoC-specific initialization + in the driver. One of: + "ti,c6455-pll" + "ti,c6457-pll" + "ti,c6472-pll" + "ti,c6474-pll" + +- reg: base address and size of register area +- clock-frequency: input clock frequency in hz + + +Optional properties: + +- ti,c64x+pll-bypass-delay: CPU cycles to delay when entering bypass mode + +- ti,c64x+pll-reset-delay: CPU cycles to delay after PLL reset + +- ti,c64x+pll-lock-delay: CPU cycles to delay after PLL frequency change + +Example: + + clock-controller@29a0000 { + compatible = "ti,c6472-pll", "ti,c64x+pll"; + reg = <0x029a0000 0x200>; + clock-frequency = <25000000>; + + ti,c64x+pll-bypass-delay = <200>; + ti,c64x+pll-reset-delay = <12000>; + ti,c64x+pll-lock-delay = <80000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/c6x/dscr.txt b/arch/arm64/boot/dts/vendor/bindings/c6x/dscr.txt new file mode 100644 index 0000000000000000000000000000000000000000..92672235de57a50d346ae91db0530abb7df8becd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/c6x/dscr.txt @@ -0,0 +1,127 @@ +Device State Configuration Registers +------------------------------------ + +TI C6X SoCs contain a region of miscellaneous registers which provide various +function for SoC control or status. Details vary considerably among from SoC +to SoC with no two being alike. + +In general, the Device State Configuration Registers (DSCR) will provide one or +more configuration registers often protected by a lock register where one or +more key values must be written to a lock register in order to unlock the +configuration register for writes. These configuration register may be used to +enable (and disable in some cases) SoC pin drivers, select peripheral clock +sources (internal or pin), etc. In some cases, a configuration register is +write once or the individual bits are write once. In addition to device config, +the DSCR block may provide registers which are used to reset peripherals, +provide device ID information, provide ethernet MAC addresses, as well as other +miscellaneous functions. + +For device state control (enable/disable), each device control is assigned an +id which is used by individual device drivers to control the state as needed. + +Required properties: + +- compatible: must be "ti,c64x+dscr" +- reg: register area base and size + +Optional properties: + + NOTE: These are optional in that not all SoCs will have all properties. For + SoCs which do support a given property, leaving the property out of the + device tree will result in reduced functionality or possibly driver + failure. + +- ti,dscr-devstat + offset of the devstat register + +- ti,dscr-silicon-rev + offset, start bit, and bitsize of silicon revision field + +- ti,dscr-rmii-resets + offset and bitmask of RMII reset field. May have multiple tuples if more + than one ethernet port is available. + +- ti,dscr-locked-regs + possibly multiple tuples describing registers which are write protected by + a lock register. Each tuple consists of the register offset, lock register + offsset, and the key value used to unlock the register. + +- ti,dscr-kick-regs + offset and key values of two "kick" registers used to write protect other + registers in DSCR. On SoCs using kick registers, the first key must be + written to the first kick register and the second key must be written to + the second register before other registers in the area are write-enabled. + +- ti,dscr-mac-fuse-regs + MAC addresses are contained in two registers. Each element of a MAC address + is contained in a single byte. This property has two tuples. Each tuple has + a register offset and four cells representing bytes in the register from + most significant to least. The value of these four cells is the MAC byte + index (1-6) of the byte within the register. A value of 0 means the byte + is unused in the MAC address. + +- ti,dscr-devstate-ctl-regs + This property describes the bitfields used to control the state of devices. + Each tuple describes a range of identical bitfields used to control one or + more devices (one bitfield per device). The layout of each tuple is: + + start_id num_ids reg enable disable start_bit nbits + + Where: + start_id is device id for the first device control in the range + num_ids is the number of device controls in the range + reg is the offset of the register holding the control bits + enable is the value to enable a device + disable is the value to disable a device (0xffffffff if cannot disable) + start_bit is the bit number of the first bit in the range + nbits is the number of bits per device control + +- ti,dscr-devstate-stat-regs + This property describes the bitfields used to provide device state status + for device states controlled by the DSCR. Each tuple describes a range of + identical bitfields used to provide status for one or more devices (one + bitfield per device). The layout of each tuple is: + + start_id num_ids reg enable disable start_bit nbits + + Where: + start_id is device id for the first device status in the range + num_ids is the number of devices covered by the range + reg is the offset of the register holding the status bits + enable is the value indicating device is enabled + disable is the value indicating device is disabled + start_bit is the bit number of the first bit in the range + nbits is the number of bits per device status + +- ti,dscr-privperm + Offset and default value for register used to set access privilege for + some SoC devices. + + +Example: + + device-state-config-regs@2a80000 { + compatible = "ti,c64x+dscr"; + reg = <0x02a80000 0x41000>; + + ti,dscr-devstat = <0>; + ti,dscr-silicon-rev = <8 28 0xf>; + ti,dscr-rmii-resets = <0x40020 0x00040000>; + + ti,dscr-locked-regs = <0x40008 0x40004 0x0f0a0b00>; + ti,dscr-devstate-ctl-regs = + <0 12 0x40008 1 0 0 2 + 12 1 0x40008 3 0 30 2 + 13 2 0x4002c 1 0xffffffff 0 1>; + ti,dscr-devstate-stat-regs = + <0 10 0x40014 1 0 0 3 + 10 2 0x40018 1 0 0 3>; + + ti,dscr-mac-fuse-regs = <0x700 1 2 3 4 + 0x704 5 6 0 0>; + + ti,dscr-privperm = <0x41c 0xaaaaaaaa>; + + ti,dscr-kick-regs = <0x38 0x83E70B13 + 0x3c 0x95A4F1E0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/c6x/emifa.txt b/arch/arm64/boot/dts/vendor/bindings/c6x/emifa.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ff6e9b9a13fa2f7abed53be7c74f4786af199ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/c6x/emifa.txt @@ -0,0 +1,62 @@ +External Memory Interface +------------------------- + +The emifa node describes a simple external bus controller found on some C6X +SoCs. This interface provides external busses with a number of chip selects. + +Required properties: + +- compatible: must be "ti,c64x+emifa", "simple-bus" +- reg: register area base and size +- #address-cells: must be 2 (chip-select + offset) +- #size-cells: must be 1 +- ranges: mapping from EMIFA space to parent space + + +Optional properties: + +- ti,dscr-dev-enable: Device ID if EMIF is enabled/disabled from DSCR + +- ti,emifa-burst-priority: + Number of memory transfers after which the EMIF will elevate the priority + of the oldest command in the command FIFO. Setting this field to 255 + disables this feature, thereby allowing old commands to stay in the FIFO + indefinitely. + +- ti,emifa-ce-config: + Configuration values for each of the supported chip selects. + +Example: + + emifa@70000000 { + compatible = "ti,c64x+emifa", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x70000000 0x100>; + ranges = <0x2 0x0 0xa0000000 0x00000008 + 0x3 0x0 0xb0000000 0x00400000 + 0x4 0x0 0xc0000000 0x10000000 + 0x5 0x0 0xD0000000 0x10000000>; + + ti,dscr-dev-enable = <13>; + ti,emifa-burst-priority = <255>; + ti,emifa-ce-config = <0x00240120 + 0x00240120 + 0x00240122 + 0x00240122>; + + flash@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x3 0x0 0x400000>; + bank-width = <1>; + device-width = <1>; + partition@0 { + reg = <0x0 0x400000>; + label = "NOR"; + }; + }; + }; + +This shows a flash chip attached to chip select 3. diff --git a/arch/arm64/boot/dts/vendor/bindings/c6x/soc.txt b/arch/arm64/boot/dts/vendor/bindings/c6x/soc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1e4973b5769ddcb9c75817598f7d37f6b3ca03c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/c6x/soc.txt @@ -0,0 +1,28 @@ +C6X System-on-Chip +------------------ + +Required properties: + +- compatible: "simple-bus" +- #address-cells: must be 1 +- #size-cells: must be 1 +- ranges + +Optional properties: + +- model: specific SoC model + +- nodes for IP blocks within SoC + + +Example: + + soc { + compatible = "simple-bus"; + model = "tms320c6455"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/chosen.txt b/arch/arm64/boot/dts/vendor/bindings/chosen.txt new file mode 100644 index 0000000000000000000000000000000000000000..45e79172a646c53729a881550d5f6e003013d2ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/chosen.txt @@ -0,0 +1,137 @@ +The chosen node +--------------- + +The chosen node does not represent a real device, but serves as a place +for passing data between firmware and the operating system, like boot +arguments. Data in the chosen node does not represent the hardware. + +The following properties are recognized: + + +kaslr-seed +----------- + +This property is used when booting with CONFIG_RANDOMIZE_BASE as the +entropy used to randomize the kernel image base address location. Since +it is used directly, this value is intended only for KASLR, and should +not be used for other purposes (as it may leak information about KASLR +offsets). It is parsed as a u64 value, e.g. + +/ { + chosen { + kaslr-seed = <0xfeedbeef 0xc0def00d>; + }; +}; + +Note that if this property is set from UEFI (or a bootloader in EFI +mode) when EFI_RNG_PROTOCOL is supported, it will be overwritten by +the Linux EFI stub (which will populate the property itself, using +EFI_RNG_PROTOCOL). + +stdout-path +----------- + +Device trees may specify the device to be used for boot console output +with a stdout-path property under /chosen, as described in the Devicetree +Specification, e.g. + +/ { + chosen { + stdout-path = "/serial@f00:115200"; + }; + + serial@f00 { + compatible = "vendor,some-uart"; + reg = <0xf00 0x10>; + }; +}; + +If the character ":" is present in the value, this terminates the path. +The meaning of any characters following the ":" is device-specific, and +must be specified in the relevant binding documentation. + +For UART devices, the preferred binding is a string in the form: + + {{{}}} + +where + + baud - baud rate in decimal + parity - 'n' (none), 'o', (odd) or 'e' (even) + bits - number of data bits + flow - 'r' (rts) + +For example: 115200n8r + +Implementation note: Linux will look for the property "linux,stdout-path" or +on PowerPC "stdout" if "stdout-path" is not found. However, the +"linux,stdout-path" and "stdout" properties are deprecated. New platforms +should only use the "stdout-path" property. + +linux,booted-from-kexec +----------------------- + +This property is set (currently only on PowerPC, and only needed on +book3e) by some versions of kexec-tools to tell the new kernel that it +is being booted by kexec, as the booting environment may differ (e.g. +a different secondary CPU release mechanism) + +linux,usable-memory-range +------------------------- + +This property (arm64 only) holds a base address and size, describing a +limited region in which memory may be considered available for use by +the kernel. Memory outside of this range is not available for use. + +This property describes a limitation: memory within this range is only +valid when also described through another mechanism that the kernel +would otherwise use to determine available memory (e.g. memory nodes +or the EFI memory map). Valid memory may be sparse within the range. +e.g. + +/ { + chosen { + linux,usable-memory-range = <0x9 0xf0000000 0x0 0x10000000>; + }; +}; + +The main usage is for crash dump kernel to identify its own usable +memory and exclude, at its boot time, any other memory areas that are +part of the panicked kernel's memory. + +While this property does not represent a real hardware, the address +and the size are expressed in #address-cells and #size-cells, +respectively, of the root node. + +linux,elfcorehdr +---------------- + +This property (currently used only on arm64) holds the memory range, +the address and the size, of the elf core header which mainly describes +the panicked kernel's memory layout as PT_LOAD segments of elf format. +e.g. + +/ { + chosen { + linux,elfcorehdr = <0x9 0xfffff000 0x0 0x800>; + }; +}; + +While this property does not represent a real hardware, the address +and the size are expressed in #address-cells and #size-cells, +respectively, of the root node. + +linux,initrd-start and linux,initrd-end +--------------------------------------- + +These properties hold the physical start and end address of an initrd that's +loaded by the bootloader. Note that linux,initrd-start is inclusive, but +linux,initrd-end is exclusive. +e.g. + +/ { + chosen { + linux,initrd-start = <0x82000000>; + linux,initrd-end = <0x82800000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/actions,owl-cmu.txt b/arch/arm64/boot/dts/vendor/bindings/clock/actions,owl-cmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1e60d2973874b9ffbc140cee9e7f34c2cfbe9d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/actions,owl-cmu.txt @@ -0,0 +1,49 @@ +* Actions Semi Owl Clock Management Unit (CMU) + +The Actions Semi Owl Clock Management Unit generates and supplies clock +to various controllers within the SoC. The clock binding described here is +applicable to S900 and S700 SoC's. + +Required Properties: + +- compatible: should be one of the following, + "actions,s900-cmu" + "actions,s700-cmu" +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: Reference to the parent clocks ("hosc", "losc") +- #clock-cells: should be 1. + +Each clock is assigned an identifier, and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in corresponding +dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h header and can be +used in device tree sources. + +External clocks: + +The hosc clock used as input for the plls is generated outside the SoC. It is +expected that it is defined using standard clock bindings as "hosc". + +Actions Semi S900 CMU also requires one more clock: + - "losc" - internal low frequency oscillator + +Example: Clock Management Unit node: + + cmu: clock-controller@e0160000 { + compatible = "actions,s900-cmu"; + reg = <0x0 0xe0160000 0x0 0x1000>; + clocks = <&hosc>, <&losc>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes clock generated by the clock +management unit: + + uart: serial@e012a000 { + compatible = "actions,s900-uart", "actions,owl-uart"; + reg = <0x0 0xe012a000 0x0 0x2000>; + interrupts = ; + clocks = <&cmu CLK_UART5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/alphascale,acc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/alphascale,acc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3205b21c9d03647a21715fd0c5574e4a49695c6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/alphascale,acc.txt @@ -0,0 +1,114 @@ +Alphascale Clock Controller + +The ACC (Alphascale Clock Controller) is responsible of choising proper +clock source, setting deviders and clock gates. + +Required properties for the ACC node: + - compatible: must be "alphascale,asm9260-clock-controller" + - reg: must contain the ACC register base and size + - #clock-cells : shall be set to 1. + +Simple one-cell clock specifier format is used, where the only cell is used +as an index of the clock inside the provider. +It is encouraged to use dt-binding for clock index definitions. SoC specific +dt-binding should be included to the device tree descriptor. For example +Alphascale ASM9260: +#include + +This binding contains two types of clock providers: + _AHB_ - AHB gate; + _SYS_ - adjustable clock source. Not all peripheral have _SYS_ clock provider. +All clock specific details can be found in the SoC documentation. +CLKID_AHB_ROM 0 +CLKID_AHB_RAM 1 +CLKID_AHB_GPIO 2 +CLKID_AHB_MAC 3 +CLKID_AHB_EMI 4 +CLKID_AHB_USB0 5 +CLKID_AHB_USB1 6 +CLKID_AHB_DMA0 7 +CLKID_AHB_DMA1 8 +CLKID_AHB_UART0 9 +CLKID_AHB_UART1 10 +CLKID_AHB_UART2 11 +CLKID_AHB_UART3 12 +CLKID_AHB_UART4 13 +CLKID_AHB_UART5 14 +CLKID_AHB_UART6 15 +CLKID_AHB_UART7 16 +CLKID_AHB_UART8 17 +CLKID_AHB_UART9 18 +CLKID_AHB_I2S0 19 +CLKID_AHB_I2C0 20 +CLKID_AHB_I2C1 21 +CLKID_AHB_SSP0 22 +CLKID_AHB_IOCONFIG 23 +CLKID_AHB_WDT 24 +CLKID_AHB_CAN0 25 +CLKID_AHB_CAN1 26 +CLKID_AHB_MPWM 27 +CLKID_AHB_SPI0 28 +CLKID_AHB_SPI1 29 +CLKID_AHB_QEI 30 +CLKID_AHB_QUADSPI0 31 +CLKID_AHB_CAMIF 32 +CLKID_AHB_LCDIF 33 +CLKID_AHB_TIMER0 34 +CLKID_AHB_TIMER1 35 +CLKID_AHB_TIMER2 36 +CLKID_AHB_TIMER3 37 +CLKID_AHB_IRQ 38 +CLKID_AHB_RTC 39 +CLKID_AHB_NAND 40 +CLKID_AHB_ADC0 41 +CLKID_AHB_LED 42 +CLKID_AHB_DAC0 43 +CLKID_AHB_LCD 44 +CLKID_AHB_I2S1 45 +CLKID_AHB_MAC1 46 + +CLKID_SYS_CPU 47 +CLKID_SYS_AHB 48 +CLKID_SYS_I2S0M 49 +CLKID_SYS_I2S0S 50 +CLKID_SYS_I2S1M 51 +CLKID_SYS_I2S1S 52 +CLKID_SYS_UART0 53 +CLKID_SYS_UART1 54 +CLKID_SYS_UART2 55 +CLKID_SYS_UART3 56 +CLKID_SYS_UART4 56 +CLKID_SYS_UART5 57 +CLKID_SYS_UART6 58 +CLKID_SYS_UART7 59 +CLKID_SYS_UART8 60 +CLKID_SYS_UART9 61 +CLKID_SYS_SPI0 62 +CLKID_SYS_SPI1 63 +CLKID_SYS_QUADSPI 64 +CLKID_SYS_SSP0 65 +CLKID_SYS_NAND 66 +CLKID_SYS_TRACE 67 +CLKID_SYS_CAMM 68 +CLKID_SYS_WDT 69 +CLKID_SYS_CLKOUT 70 +CLKID_SYS_MAC 71 +CLKID_SYS_LCD 72 +CLKID_SYS_ADCANA 73 + +Example of clock consumer with _SYS_ and _AHB_ sinks. +uart4: serial@80010000 { + compatible = "alphascale,asm9260-uart"; + reg = <0x80010000 0x4000>; + clocks = <&acc CLKID_SYS_UART4>, <&acc CLKID_AHB_UART4>; + interrupts = <19>; +}; + +Clock consumer with only one, _AHB_ sink. +timer0: timer@80088000 { + compatible = "alphascale,asm9260-timer"; + reg = <0x80088000 0x4000>; + clocks = <&acc CLKID_AHB_TIMER0>; + interrupts = <29>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/altr_socfpga.txt b/arch/arm64/boot/dts/vendor/bindings/clock/altr_socfpga.txt new file mode 100644 index 0000000000000000000000000000000000000000..f72e80e0dade820adb35db2498566c487e51b40a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/altr_socfpga.txt @@ -0,0 +1,30 @@ +Device Tree Clock bindings for Altera's SoCFPGA platform + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "altr,socfpga-pll-clock" - for a PLL clock + "altr,socfpga-perip-clock" - The peripheral clock divided from the + PLL clock. + "altr,socfpga-gate-clk" - Clocks that directly feed peripherals and + can get gated. + +- reg : shall be the control register offset from CLOCK_MANAGER's base for the clock. +- clocks : shall be the input parent clock phandle for the clock. This is + either an oscillator or a pll output. +- #clock-cells : from common clock binding, shall be set to 0. + +Optional properties: +- fixed-divider : If clocks have a fixed divider value, use this property. +- clk-gate : For "socfpga-gate-clk", clk-gate contains the gating register + and the bit index. +- div-reg : For "socfpga-gate-clk" and "socfpga-periph-clock", div-reg contains + the divider register, bit shift, and width. +- clk-phase : For the sdmmc_clk, contains the value of the clock phase that controls + the SDMMC CIU clock. The first value is the clk_sample(smpsel), and the second + value is the cclk_in_drv(drvsel). The clk-phase is used to enable the correct + hold/delay times that is needed for the SD/MMC CIU clock. The values of both + can be 0-315 degrees, in 45 degree increments. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,axg-audio-clkc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,axg-audio-clkc.txt new file mode 100644 index 0000000000000000000000000000000000000000..61777ad24f61c0657ce812151f910c24fa12b38a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,axg-audio-clkc.txt @@ -0,0 +1,56 @@ +* Amlogic AXG Audio Clock Controllers + +The Amlogic AXG audio clock controller generates and supplies clock to the +other elements of the audio subsystem, such as fifos, i2s, spdif and pdm +devices. + +Required Properties: + +- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D +- reg : physical base address of the clock controller and length of + memory mapped region. +- clocks : a list of phandle + clock-specifier pairs for the clocks listed + in clock-names. +- clock-names : must contain the following: + * "pclk" - Main peripheral bus clock + may contain the following: + * "mst_in[0-7]" - 8 input plls to generate clock signals + * "slv_sclk[0-9]" - 10 slave bit clocks provided by external + components. + * "slv_lrclk[0-9]" - 10 slave sample clocks provided by external + components. +- resets : phandle of the internal reset line +- #clock-cells : should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/axg-audio-clkc.h header and can be +used in device tree sources. + +Example: + +clkc_audio: clock-controller@0 { + compatible = "amlogic,axg-audio-clkc"; + reg = <0x0 0x0 0x0 0xb4>; + #clock-cells = <1>; + + clocks = <&clkc CLKID_AUDIO>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>, + <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL3>, + <&clkc CLKID_HIFI_PLL>, + <&clkc CLKID_FCLK_DIV3>, + <&clkc CLKID_FCLK_DIV4>, + <&clkc CLKID_GP0_PLL>; + clock-names = "pclk", + "mst_in0", + "mst_in1", + "mst_in2", + "mst_in3", + "mst_in4", + "mst_in5", + "mst_in6", + "mst_in7"; + resets = <&reset RESET_AUDIO>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,gxbb-aoclkc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,gxbb-aoclkc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a880528030ea61fd4c6d7f1a869a2ce7c3c3938 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,gxbb-aoclkc.txt @@ -0,0 +1,55 @@ +* Amlogic GXBB AO Clock and Reset Unit + +The Amlogic GXBB AO clock controller generates and supplies clock to various +controllers within the Always-On part of the SoC. + +Required Properties: + +- compatible: value should be different for each SoC family as : + - GXBB (S905) : "amlogic,meson-gxbb-aoclkc" + - GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc" + - GXM (S912) : "amlogic,meson-gxm-aoclkc" + - AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc" + followed by the common "amlogic,meson-gx-aoclkc" + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/gxbb-aoclkc.h header and can be +used in device tree sources. + +- #reset-cells: should be 1. + +Each reset is assigned an identifier and client nodes can use this identifier +to specify the reset which they consume. All available resets are defined as +preprocessor macros in the dt-bindings/reset/gxbb-aoclkc.h header and can be +used in device tree sources. + +Parent node should have the following properties : +- compatible: "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd" +- reg: base address and size of the AO system control register space. + +Example: AO Clock controller node: + +ao_sysctrl: sys-ctrl@0 { + compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"; + reg = <0x0 0x0 0x0 0x100>; + + clkc_AO: clock-controller { + compatible = "amlogic,meson-gxbb-aoclkc", "amlogic,meson-gx-aoclkc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; +}; + +Example: UART controller node that consumes the clock and reset generated + by the clock controller: + + uart_AO: serial@4c0 { + compatible = "amlogic,meson-uart"; + reg = <0x4c0 0x14>; + interrupts = <0 90 1>; + clocks = <&clkc_AO CLKID_AO_UART1>; + resets = <&clkc_AO RESET_AO_UART1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,gxbb-clkc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,gxbb-clkc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e950599566a99876b9be5e7536828e469fef4f80 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,gxbb-clkc.txt @@ -0,0 +1,45 @@ +* Amlogic GXBB Clock and Reset Unit + +The Amlogic GXBB clock controller generates and supplies clock to various +controllers within the SoC. + +Required Properties: + +- compatible: should be: + "amlogic,gxbb-clkc" for GXBB SoC, + "amlogic,gxl-clkc" for GXL and GXM SoC, + "amlogic,axg-clkc" for AXG SoC. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/gxbb-clkc.h header and can be +used in device tree sources. + +Parent node should have the following properties : +- compatible: "syscon", "simple-mfd, and "amlogic,meson-gx-hhi-sysctrl" or + "amlogic,meson-axg-hhi-sysctrl" +- reg: base address and size of the HHI system control register space. + +Example: Clock controller node: + +sysctrl: system-controller@0 { + compatible = "amlogic,meson-gx-hhi-sysctrl", "syscon", "simple-mfd"; + reg = <0 0 0 0x400>; + + clkc: clock-controller { + #clock-cells = <1>; + compatible = "amlogic,gxbb-clkc"; + }; +}; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart_AO: serial@c81004c0 { + compatible = "amlogic,meson-uart"; + reg = <0xc81004c0 0x14>; + interrupts = <0 90 1>; + clocks = <&clkc CLKID_CLK81>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,meson8b-clkc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,meson8b-clkc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b455c5aa9139edba0223ba9c25270255b60a0d86 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/amlogic,meson8b-clkc.txt @@ -0,0 +1,49 @@ +* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit + +The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and +supplies clock to various controllers within the SoC. + +Required Properties: + +- compatible: must be one of: + - "amlogic,meson8-clkc" for Meson8 (S802) SoCs + - "amlogic,meson8b-clkc" for Meson8 (S805) SoCs + - "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs +- reg: it must be composed by two tuples: + 0) physical base address of the xtal register and length of memory + mapped region. + 1) physical base address of the clock controller and length of memory + mapped region. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be +used in device tree sources. + +Similarly a preprocessor macro for each reset line is defined in +dt-bindings/reset/amlogic,meson8b-clkc-reset.h (which can be used from the +device tree sources). + + +Example: Clock controller node: + + clkc: clock-controller@c1104000 { + compatible = "amlogic,meson8b-clkc"; + reg = <0xc1108000 0x4>, <0xc1104000 0x460>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart_AO: serial@c81004c0 { + compatible = "amlogic,meson-uart"; + reg = <0xc81004c0 0x14>; + interrupts = <0 90 1>; + clocks = <&clkc CLKID_CLK81>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/arm-integrator.txt b/arch/arm64/boot/dts/vendor/bindings/clock/arm-integrator.txt new file mode 100644 index 0000000000000000000000000000000000000000..11f5f95f571bef74a2f0166e353b840ffd2ff580 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/arm-integrator.txt @@ -0,0 +1,34 @@ +Clock bindings for ARM Integrator and Versatile Core Module clocks + +Auxiliary Oscillator Clock + +This is a configurable clock fed from a 24 MHz chrystal, +used for generating e.g. video clocks. It is located on the +core module and there is only one of these. + +This clock node *must* be a subnode of the core module, since +it obtains the base address for it's address range from its +parent node. + + +Required properties: +- compatible: must be "arm,integrator-cm-auxosc" or "arm,versatile-cm-auxosc" +- #clock-cells: must be <0> + +Optional properties: +- clocks: parent clock(s) + +Example: + +core-module@10000000 { + xtal24mhz: xtal24mhz@24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + auxosc: cm_aux_osc@25M { + #clock-cells = <0>; + compatible = "arm,integrator-cm-auxosc"; + clocks = <&xtal24mhz>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/arm-syscon-icst.txt b/arch/arm64/boot/dts/vendor/bindings/clock/arm-syscon-icst.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cd81742038f1230e2e68d4d6b6c365abe0b1025 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/arm-syscon-icst.txt @@ -0,0 +1,70 @@ +ARM System Controller ICST clocks + +The ICS525 and ICS307 oscillators are produced by Integrated Devices +Technology (IDT). ARM integrated these oscillators deeply into their +reference designs by adding special control registers that manage such +oscillators to their system controllers. + +The various ARM system controllers contain logic to serialize and initialize +an ICST clock request after a write to the 32 bit register at an offset +into the system controller. Furthermore, to even be able to alter one of +these frequencies, the system controller must first be unlocked by +writing a special token to another offset in the system controller. + +Some ARM hardware contain special versions of the serial interface that only +connects the low 8 bits of the VDW (missing one bit), hardwires RDW to +different values and sometimes also hardwire the output divider. They +therefore have special compatible strings as per this table (the OD value is +the value on the pins, not the resulting output divider): + +Hardware variant: RDW OD VDW + +Integrator/AP 22 1 Bit 8 0, rest variable +integratorap-cm + +Integrator/AP 46 3 Bit 8 0, rest variable +integratorap-sys + +Integrator/AP 22 or 1 17 or (33 or 25 MHz) +integratorap-pci 14 1 14 + +Integrator/CP 22 variable Bit 8 0, rest variable +integratorcp-cm-core + +Integrator/CP 22 variable Bit 8 0, rest variable +integratorcp-cm-mem + +The ICST oscillator must be provided inside a system controller node. + +Required properties: +- compatible: must be one of + "arm,syscon-icst525" + "arm,syscon-icst307" + "arm,syscon-icst525-integratorap-cm" + "arm,syscon-icst525-integratorap-sys" + "arm,syscon-icst525-integratorap-pci" + "arm,syscon-icst525-integratorcp-cm-core" + "arm,syscon-icst525-integratorcp-cm-mem" +- lock-offset: the offset address into the system controller where the + unlocking register is located +- vco-offset: the offset address into the system controller where the + ICST control register is located (even 32 bit address) +- #clock-cells: must be <0> +- clocks: parent clock, since the ICST needs a parent clock to derive its + frequency from, this attribute is compulsory. + +Example: + +syscon: syscon@10000000 { + compatible = "syscon"; + reg = <0x10000000 0x1000>; + + oscclk0: osc0@c { + compatible = "arm,syscon-icst307"; + #clock-cells = <0>; + lock-offset = <0x20>; + vco-offset = <0x0c>; + clocks = <&xtal24mhz>; + }; + (...) +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-periph-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-periph-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e3370ba189f51fa713bc6b42fcf61bfed383c4b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-periph-clock.txt @@ -0,0 +1,70 @@ +* Peripheral Clock bindings for Marvell Armada 37xx SoCs + +Marvell Armada 37xx SoCs provide peripheral clocks which are +used as clock source for the peripheral of the SoC. + +There are two different blocks associated to north bridge and south +bridge. + +The peripheral clock consumer should specify the desired clock by +having the clock ID in its "clocks" phandle cell. + +The following is a list of provided IDs for Armada 370 North bridge clocks: +ID Clock name Description +----------------------------------- +0 mmc MMC controller +1 sata_host Sata Host +2 sec_at Security AT +3 sac_dap Security DAP +4 tsecm Security Engine +5 setm_tmx Serial Embedded Trace Module +6 avs Adaptive Voltage Scaling +7 sqf SPI +8 pwm PWM +9 i2c_2 I2C 2 +10 i2c_1 I2C 1 +11 ddr_phy DDR PHY +12 ddr_fclk DDR F clock +13 trace Trace +14 counter Counter +15 eip97 EIP 97 +16 cpu CPU + +The following is a list of provided IDs for Armada 370 South bridge clocks: +ID Clock name Description +----------------------------------- +0 gbe-50 50 MHz parent clock for Gigabit Ethernet +1 gbe-core parent clock for Gigabit Ethernet core +2 gbe-125 125 MHz parent clock for Gigabit Ethernet +3 gbe1-50 50 MHz clock for Gigabit Ethernet port 1 +4 gbe0-50 50 MHz clock for Gigabit Ethernet port 0 +5 gbe1-125 125 MHz clock for Gigabit Ethernet port 1 +6 gbe0-125 125 MHz clock for Gigabit Ethernet port 0 +7 gbe1-core Gigabit Ethernet core port 1 +8 gbe0-core Gigabit Ethernet core port 0 +9 gbe-bm Gigabit Ethernet Buffer Manager +10 sdio SDIO +11 usb32-sub2-sys USB 2 clock +12 usb32-ss-sys USB 3 clock + +Required properties: + +- compatible : shall be "marvell,armada-3700-periph-clock-nb" for the + north bridge block, or + "marvell,armada-3700-periph-clock-sb" for the south bridge block +- reg : must be the register address of North/South Bridge Clock register +- #clock-cells : from common clock binding; shall be set to 1 + +- clocks : list of the parent clock phandle in the following order: + TBG-A P, TBG-B P, TBG-A S, TBG-B S and finally the xtal clock. + + +Example: + +nb_perih_clk: nb-periph-clk@13000{ + compatible = "marvell,armada-3700-periph-clock-nb"; + reg = <0x13000 0x1000>; + clocks = <&tbg 0>, <&tbg 1>, <&tbg 2>, + <&tbg 3>, <&xtalclk>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-tbg-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-tbg-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ba1d83ff363aa3a40ae573a4dc56b8bd48c50d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-tbg-clock.txt @@ -0,0 +1,27 @@ +* Time Base Generator Clock bindings for Marvell Armada 37xx SoCs + +Marvell Armada 37xx SoCs provde Time Base Generator clocks which are +used as parent clocks for the peripheral clocks. + +The TBG clock consumer should specify the desired clock by having the +clock ID in its "clocks" phandle cell. + +The following is a list of provided IDs and clock names on Armada 3700: + 0 = TBG A P + 1 = TBG B P + 2 = TBG A S + 3 = TBG B S + +Required properties: +- compatible : shall be "marvell,armada-3700-tbg-clock" +- reg : must be the register address of North Bridge PLL register +- #clock-cells : from common clock binding; shall be set to 1 + +Example: + +tbg: tbg@13200 { + compatible = "marvell,armada-3700-tbg-clock"; + reg = <0x13200 0x1000>; + clocks = <&xtalclk>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-xtal-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-xtal-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c0807f28cfaa119a55a6f48fa061daca01f1f60 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/armada3700-xtal-clock.txt @@ -0,0 +1,29 @@ +* Xtal Clock bindings for Marvell Armada 37xx SoCs + +Marvell Armada 37xx SoCs allow to determine the xtal clock frequencies by +reading the gpio latch register. + +This node must be a subnode of the node exposing the register address +of the GPIO block where the gpio latch is located. +See Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt + +Required properties: +- compatible : shall be one of the following: + "marvell,armada-3700-xtal-clock" +- #clock-cells : from common clock binding; shall be set to 0 + +Optional properties: +- clock-output-names : from common clock binding; allows overwrite default clock + output names ("xtal") + +Example: +pinctrl_nb: pinctrl-nb@13800 { + compatible = "armada3710-nb-pinctrl", "syscon", "simple-mfd"; + reg = <0x13800 0x100>, <0x13C00 0x20>; + + xtalclk: xtal-clk { + compatible = "marvell,armada-3700-xtal-clock"; + clock-output-names = "xtal"; + #clock-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/artpec6.txt b/arch/arm64/boot/dts/vendor/bindings/clock/artpec6.txt new file mode 100644 index 0000000000000000000000000000000000000000..dff9cdf0009cc5a081ff7b9ddd51469e3fefcadf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/artpec6.txt @@ -0,0 +1,41 @@ +* Clock bindings for Axis ARTPEC-6 chip + +The bindings are based on the clock provider binding in +Documentation/devicetree/bindings/clock/clock-bindings.txt + +External clocks: +---------------- + +There are two external inputs to the main clock controller which should be +provided using the common clock bindings. +- "sys_refclk": External 50 Mhz oscillator (required) +- "i2s_refclk": Alternate audio reference clock (optional). + +Main clock controller +--------------------- + +Required properties: +- #clock-cells: Should be <1> + See dt-bindings/clock/axis,artpec6-clkctrl.h for the list of valid identifiers. +- compatible: Should be "axis,artpec6-clkctrl" +- reg: Must contain the base address and length of the system controller +- clocks: Must contain a phandle entry for each clock in clock-names +- clock-names: Must include the external oscillator ("sys_refclk"). Optional + ones are the audio reference clock ("i2s_refclk") and the audio fractional + dividers ("frac_clk0" and "frac_clk1"). + +Examples: + +ext_clk: ext_clk { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <50000000>; +}; + +clkctrl: clkctrl@f8000000 { + #clock-cells = <1>; + compatible = "axis,artpec6-clkctrl"; + reg = <0xf8000000 0x48>; + clocks = <&ext_clk>; + clock-names = "sys_refclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/at91-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/at91-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f8f95056f3d4d456fd62726055052a1e60277d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/at91-clock.txt @@ -0,0 +1,536 @@ +Device Tree Clock bindings for arch-at91 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "atmel,at91sam9x5-sckc" or + "atmel,sama5d4-sckc": + at91 SCKC (Slow Clock Controller) + This node contains the slow clock definitions. + + "atmel,at91sam9x5-clk-slow-osc": + at91 slow oscillator + + "atmel,at91sam9x5-clk-slow-rc-osc": + at91 internal slow RC oscillator + + "atmel,-pmc": + at91 PMC (Power Management Controller) + All at91 specific clocks (clocks defined below) must be child + node of the PMC node. + can be: at91rm9200, at91sam9260, at91sam9261, + at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9x5, + sama5d2, sama5d3 or sama5d4. + + "atmel,at91sam9x5-clk-slow" (under sckc node) + or + "atmel,at91sam9260-clk-slow" (under pmc node): + at91 slow clk + + "atmel,at91rm9200-clk-main-osc" + "atmel,at91sam9x5-clk-main-rc-osc" + at91 main clk sources + + "atmel,at91sam9x5-clk-main" + "atmel,at91rm9200-clk-main": + at91 main clock + + "atmel,at91rm9200-clk-master" or + "atmel,at91sam9x5-clk-master": + at91 master clock + + "atmel,at91sam9x5-clk-peripheral" or + "atmel,at91rm9200-clk-peripheral": + at91 peripheral clocks + + "atmel,at91rm9200-clk-pll" or + "atmel,at91sam9g45-clk-pll" or + "atmel,at91sam9g20-clk-pllb" or + "atmel,sama5d3-clk-pll": + at91 pll clocks + + "atmel,at91sam9x5-clk-plldiv": + at91 plla divisor + + "atmel,at91rm9200-clk-programmable" or + "atmel,at91sam9g45-clk-programmable" or + "atmel,at91sam9x5-clk-programmable": + at91 programmable clocks + + "atmel,at91sam9x5-clk-smd": + at91 SMD (Soft Modem) clock + + "atmel,at91rm9200-clk-system": + at91 system clocks + + "atmel,at91rm9200-clk-usb" or + "atmel,at91sam9x5-clk-usb" or + "atmel,at91sam9n12-clk-usb": + at91 usb clock + + "atmel,at91sam9x5-clk-utmi": + at91 utmi clock + + "atmel,sama5d4-clk-h32mx": + at91 h32mx clock + + "atmel,sama5d2-clk-generated": + at91 generated clock + + "atmel,sama5d2-clk-audio-pll-frac": + at91 audio fractional pll + + "atmel,sama5d2-clk-audio-pll-pad": + at91 audio pll CLK_AUDIO output pin + + "atmel,sama5d2-clk-audio-pll-pmc" + at91 audio pll output on AUDIOPLLCLK that feeds the PMC + and can be used by peripheral clock or generic clock + + "atmel,sama5d2-clk-i2s-mux" (under pmc node): + at91 I2S clock source selection + +Required properties for SCKC node: +- reg : defines the IO memory reserved for the SCKC. +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). + + +For example: + sckc: sckc@fffffe50 { + compatible = "atmel,sama5d3-pmc"; + reg = <0xfffffe50 0x4> + #size-cells = <0>; + #address-cells = <1>; + + /* put at91 slow clocks here */ + }; + + +Required properties for internal slow RC oscillator: +- #clock-cells : from common clock binding; shall be set to 0. +- clock-frequency : define the internal RC oscillator frequency. + +Optional properties: +- clock-accuracy : define the internal RC oscillator accuracy. + +For example: + slow_rc_osc: slow_rc_osc { + compatible = "atmel,at91sam9x5-clk-slow-rc-osc"; + clock-frequency = <32768>; + clock-accuracy = <50000000>; + }; + +Required properties for slow oscillator: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall encode the main osc source clk sources (see atmel datasheet). + +Optional properties: +- atmel,osc-bypass : boolean property. Set this when a clock signal is directly + provided on XIN. + +For example: + slow_osc: slow_osc { + compatible = "atmel,at91rm9200-clk-slow-osc"; + #clock-cells = <0>; + clocks = <&slow_xtal>; + }; + +Required properties for slow clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall encode the slow clk sources (see atmel datasheet). + +For example: + clk32k: slck { + compatible = "atmel,at91sam9x5-clk-slow"; + #clock-cells = <0>; + clocks = <&slow_rc_osc &slow_osc>; + }; + +Required properties for PMC node: +- reg : defines the IO memory reserved for the PMC. +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- interrupts : shall be set to PMC interrupt line. +- interrupt-controller : tell that the PMC is an interrupt controller. +- #interrupt-cells : must be set to 1. The first cell encodes the interrupt id, + and reflect the bit position in the PMC_ER/DR/SR registers. + You can use the dt macros defined in dt-bindings/clock/at91.h. + 0 (AT91_PMC_MOSCS) -> main oscillator ready + 1 (AT91_PMC_LOCKA) -> PLL A ready + 2 (AT91_PMC_LOCKB) -> PLL B ready + 3 (AT91_PMC_MCKRDY) -> master clock ready + 6 (AT91_PMC_LOCKU) -> UTMI PLL clock ready + 8 .. 15 (AT91_PMC_PCKRDY(id)) -> programmable clock ready + 16 (AT91_PMC_MOSCSELS) -> main oscillator selected + 17 (AT91_PMC_MOSCRCS) -> RC main oscillator stabilized + 18 (AT91_PMC_CFDEV) -> clock failure detected + +For example: + pmc: pmc@fffffc00 { + compatible = "atmel,sama5d3-pmc"; + interrupts = <1 4 7>; + interrupt-controller; + #interrupt-cells = <2>; + #size-cells = <0>; + #address-cells = <1>; + + /* put at91 clocks here */ + }; + +Required properties for main clock internal RC oscillator: +- interrupts : shall be set to "<0>". +- clock-frequency : define the internal RC oscillator frequency. + +Optional properties: +- clock-accuracy : define the internal RC oscillator accuracy. + +For example: + main_rc_osc: main_rc_osc { + compatible = "atmel,at91sam9x5-clk-main-rc-osc"; + interrupt-parent = <&pmc>; + interrupts = <0>; + clock-frequency = <12000000>; + clock-accuracy = <50000000>; + }; + +Required properties for main clock oscillator: +- interrupts : shall be set to "<0>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall encode the main osc source clk sources (see atmel datasheet). + +Optional properties: +- atmel,osc-bypass : boolean property. Specified if a clock signal is provided + on XIN. + + clock signal is directly provided on XIN pin. + +For example: + main_osc: main_osc { + compatible = "atmel,at91rm9200-clk-main-osc"; + interrupt-parent = <&pmc>; + interrupts = <0>; + #clock-cells = <0>; + clocks = <&main_xtal>; + }; + +Required properties for main clock: +- interrupts : shall be set to "<0>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall encode the main clk sources (see atmel datasheet). + +For example: + main: mainck { + compatible = "atmel,at91sam9x5-clk-main"; + interrupt-parent = <&pmc>; + interrupts = <0>; + #clock-cells = <0>; + clocks = <&main_rc_osc &main_osc>; + }; + +Required properties for master clock: +- interrupts : shall be set to "<3>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the master clock sources (see atmel datasheet) phandles. + e.g. "<&ck32k>, <&main>, <&plla>, <&pllb>". +- atmel,clk-output-range : minimum and maximum clock frequency (two u32 + fields). + e.g. output = <0 133000000>; <=> 0 to 133MHz. +- atmel,clk-divisors : master clock divisors table (four u32 fields). + 0 <=> reserved value. + e.g. divisors = <1 2 4 6>; +- atmel,master-clk-have-div3-pres : some SoC use the reserved value 7 in the + PRES field as CLOCK_DIV3 (e.g sam9x5). + +For example: + mck: mck { + compatible = "atmel,at91rm9200-clk-master"; + interrupt-parent = <&pmc>; + interrupts = <3>; + #clock-cells = <0>; + atmel,clk-output-range = <0 133000000>; + atmel,clk-divisors = <1 2 4 0>; + }; + +Required properties for peripheral clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the master clock phandle. + e.g. clocks = <&mck>; +- name: device tree node describing a specific peripheral clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: peripheral id. See Atmel's datasheets to get a full + list of peripheral ids. + * atmel,clk-output-range : minimum and maximum clock frequency + (two u32 fields). Only valid on at91sam9x5-clk-peripheral + compatible IPs. + +For example: + periph: periphck { + compatible = "atmel,at91sam9x5-clk-peripheral"; + #size-cells = <0>; + #address-cells = <1>; + clocks = <&mck>; + + ssc0_clk { + #clock-cells = <0>; + reg = <2>; + atmel,clk-output-range = <0 133000000>; + }; + + usart0_clk { + #clock-cells = <0>; + reg = <3>; + atmel,clk-output-range = <0 66000000>; + }; + }; + + +Required properties for pll clocks: +- interrupts : shall be set to "<1>". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the main clock phandle. +- reg : pll id. + 0 -> PLL A + 1 -> PLL B +- atmel,clk-input-range : minimum and maximum source clock frequency (two u32 + fields). + e.g. input = <1 32000000>; <=> 1 to 32MHz. +- #atmel,pll-clk-output-range-cells : number of cells reserved for pll output + range description. Sould be set to 2, 3 + or 4. + * 1st and 2nd cells represent the frequency range (min-max). + * 3rd cell is optional and represents the OUT field value for the given + range. + * 4th cell is optional and represents the ICPLL field (PLLICPR + register) +- atmel,pll-clk-output-ranges : pll output frequency ranges + optional parameter + depending on #atmel,pll-output-range-cells + property value. + +For example: + plla: pllack { + compatible = "atmel,at91sam9g45-clk-pll"; + interrupt-parent = <&pmc>; + interrupts = <1>; + #clock-cells = <0>; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <2000000 32000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <74500000 800000000 0 0 + 69500000 750000000 1 0 + 64500000 700000000 2 0 + 59500000 650000000 3 0 + 54500000 600000000 0 1 + 49500000 550000000 1 1 + 44500000 500000000 2 1 + 40000000 450000000 3 1>; + }; + +Required properties for plldiv clocks (plldiv = pll / 2): +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the plla clock phandle. + +The pll divisor is equal to 2 and cannot be changed. + +For example: + plladiv: plladivck { + compatible = "atmel,at91sam9x5-clk-plldiv"; + #clock-cells = <0>; + clocks = <&plla>; + }; + +Required properties for programmable clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the programmable clock source phandles. + e.g. clocks = <&clk32k>, <&main>, <&plla>, <&pllb>; +- name: device tree node describing a specific prog clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg : programmable clock id (register offset from PCKx + register). + * interrupts : shall be set to "<(8 + id)>". + +For example: + prog: progck { + compatible = "atmel,at91sam9g45-clk-programmable"; + #size-cells = <0>; + #address-cells = <1>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + + prog0 { + #clock-cells = <0>; + reg = <0>; + interrupts = <8>; + }; + + prog1 { + #clock-cells = <0>; + reg = <1>; + interrupts = <9>; + }; + }; + + +Required properties for smd clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the smd clock source phandles. + e.g. clocks = <&plladiv>, <&utmi>; + +For example: + smd: smdck { + compatible = "atmel,at91sam9x5-clk-smd"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + +Required properties for system clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- name: device tree node describing a specific system clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: system clock id (bit position in SCER/SCDR/SCSR registers). + See Atmel's datasheet to get a full list of system clock ids. + +For example: + system: systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + ddrck { + #clock-cells = <0>; + reg = <2>; + clocks = <&mck>; + }; + + uhpck { + #clock-cells = <0>; + reg = <6>; + clocks = <&usb>; + }; + + udpck { + #clock-cells = <0>; + reg = <7>; + clocks = <&usb>; + }; + }; + + +Required properties for usb clock: +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the smd clock source phandles. + e.g. clocks = <&pllb>; +- atmel,clk-divisors (only available for "atmel,at91rm9200-clk-usb"): + usb clock divisor table. + e.g. divisors = <1 2 4 0>; + +For example: + usb: usbck { + compatible = "atmel,at91sam9x5-clk-usb"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + + usb: usbck { + compatible = "atmel,at91rm9200-clk-usb"; + #clock-cells = <0>; + clocks = <&pllb>; + atmel,clk-divisors = <1 2 4 0>; + }; + + +Required properties for utmi clock: +- interrupts : shall be set to "". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the main clock source phandle. + +For example: + utmi: utmick { + compatible = "atmel,at91sam9x5-clk-utmi"; + interrupt-parent = <&pmc>; + interrupts = ; + #clock-cells = <0>; + clocks = <&main>; + }; + +Required properties for 32 bits bus Matrix clock (h32mx clock): +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : shall be the master clock source phandle. + +For example: + h32ck: h32mxck { + #clock-cells = <0>; + compatible = "atmel,sama5d4-clk-h32mx"; + clocks = <&mck>; + }; + +Required properties for generated clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the generated clock source phandles. + e.g. clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; +- name: device tree node describing a specific generated clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: peripheral id. See Atmel's datasheets to get a full + list of peripheral ids. + * atmel,clk-output-range : minimum and maximum clock frequency + (two u32 fields). + +For example: + gck { + compatible = "atmel,sama5d2-clk-generated"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; + + tcb0_gclk: tcb0_gclk { + #clock-cells = <0>; + reg = <35>; + atmel,clk-output-range = <0 83000000>; + }; + + pwm_gclk: pwm_gclk { + #clock-cells = <0>; + reg = <38>; + atmel,clk-output-range = <0 83000000>; + }; + }; + +Required properties for I2S mux clocks: +- #size-cells : shall be 0 (reg is used to encode I2S bus id). +- #address-cells : shall be 1 (reg is used to encode I2S bus id). +- name: device tree node describing a specific mux clock. + * #clock-cells : from common clock binding; shall be set to 0. + * clocks : shall be the mux clock parent phandles; shall be 2 phandles: + peripheral and generated clock; the first phandle shall belong to the + peripheral clock and the second one shall belong to the generated + clock; "clock-indices" property can be user to specify + the correct order. + * reg: I2S bus id of the corresponding mux clock. + e.g. reg = <0>; for i2s0, reg = <1>; for i2s1 + +For example: + i2s_clkmux { + compatible = "atmel,sama5d2-clk-i2s-mux"; + #address-cells = <1>; + #size-cells = <0>; + + i2s0muxck: i2s0_muxclk { + clocks = <&i2s0_clk>, <&i2s0_gclk>; + #clock-cells = <0>; + reg = <0>; + }; + + i2s1muxck: i2s1_muxclk { + clocks = <&i2s1_clk>, <&i2s1_gclk>; + #clock-cells = <0>; + reg = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/axi-clkgen.txt b/arch/arm64/boot/dts/vendor/bindings/clock/axi-clkgen.txt new file mode 100644 index 0000000000000000000000000000000000000000..aca94fe9416f009ef387e9f7b7880bc5b6b5127e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/axi-clkgen.txt @@ -0,0 +1,25 @@ +Binding for the axi-clkgen clock generator + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "adi,axi-clkgen-1.00.a" or "adi,axi-clkgen-2.00.a". +- #clock-cells : from common clock binding; Should always be set to 0. +- reg : Address and length of the axi-clkgen register set. +- clocks : Phandle and clock specifier for the parent clock(s). This must + either reference one clock if only the first clock input is connected or two + if both clock inputs are connected. For the later case the clock connected + to the first input must be specified first. + +Optional properties: +- clock-output-names : From common clock binding. + +Example: + clock@ff000000 { + compatible = "adi,axi-clkgen"; + #clock-cells = <0>; + reg = <0xff000000 0x1000>; + clocks = <&osc 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/axs10x-i2s-pll-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/axs10x-i2s-pll-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ffc8df7e6da6ce2cab1455f7bf5d00cbe7a8f64 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/axs10x-i2s-pll-clock.txt @@ -0,0 +1,25 @@ +Binding for the AXS10X I2S PLL clock + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: shall be "snps,axs10x-i2s-pll-clock" +- reg : address and length of the I2S PLL register set. +- clocks: shall be the input parent clock phandle for the PLL. +- #clock-cells: from common clock binding; Should always be set to 0. + +Example: + pll_clock: pll_clock { + compatible = "fixed-clock"; + clock-frequency = <27000000>; + #clock-cells = <0>; + }; + + i2s_clock@100a0 { + compatible = "snps,axs10x-i2s-pll-clock"; + reg = <0x100a0 0x10>; + clocks = <&pll_clock>; + #clock-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm2835-aux-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm2835-aux-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..4acfc8f641b63c83e6ad9c5e2efb510b43022213 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm2835-aux-clock.txt @@ -0,0 +1,31 @@ +Broadcom BCM2835 auxiliary peripheral support + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The auxiliary peripherals (UART, SPI1, and SPI2) have a small register +area controlling clock gating to the peripherals, and providing an IRQ +status register. + +Required properties: +- compatible: Should be "brcm,bcm2835-aux" +- #clock-cells: Should be <1>. The permitted clock-specifier values can be + found in include/dt-bindings/clock/bcm2835-aux.h +- reg: Specifies base physical address and size of the registers +- clocks: The parent clock phandle + +Example: + + clocks: cprman@7e101000 { + compatible = "brcm,bcm2835-cprman"; + #clock-cells = <1>; + reg = <0x7e101000 0x2000>; + clocks = <&clk_osc>; + }; + + aux: aux@7e215004 { + compatible = "brcm,bcm2835-aux"; + #clock-cells = <1>; + reg = <0x7e215000 0x8>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm2835-cprman.txt b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm2835-cprman.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd906db34b328a581e4f4d99d11284544ff817f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm2835-cprman.txt @@ -0,0 +1,58 @@ +Broadcom BCM2835 CPRMAN clocks + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CPRMAN clock controller generates clocks in the audio power domain +of the BCM2835. There is a level of PLLs deriving from an external +oscillator, a level of PLL dividers that produce channels off of the +few PLLs, and a level of mostly-generic clock generators sourcing from +the PLL channels. Most other hardware components source from the +clock generators, but a few (like the ARM or HDMI) will source from +the PLL dividers directly. + +Required properties: +- compatible: Should be "brcm,bcm2835-cprman" +- #clock-cells: Should be <1>. The permitted clock-specifier values can be + found in include/dt-bindings/clock/bcm2835.h +- reg: Specifies base physical address and size of the registers +- clocks: phandles to the parent clocks used as input to the module, in + the following order: + + - External oscillator + - DSI0 byte clock + - DSI0 DDR2 clock + - DSI0 DDR clock + - DSI1 byte clock + - DSI1 DDR2 clock + - DSI1 DDR clock + + Only external oscillator is required. The DSI clocks may + not be present, in which case their children will be + unusable. + +Example: + + clk_osc: clock@3 { + compatible = "fixed-clock"; + reg = <3>; + #clock-cells = <0>; + clock-output-names = "osc"; + clock-frequency = <19200000>; + }; + + clocks: cprman@7e101000 { + compatible = "brcm,bcm2835-cprman"; + #clock-cells = <1>; + reg = <0x7e101000 0x2000>; + clocks = <&clk_osc>; + }; + + i2c0: i2c@7e205000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e205000 0x1000>; + interrupts = <2 21>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm53573-ilp.txt b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm53573-ilp.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ebb107331dd85075599da691386404d445069a2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,bcm53573-ilp.txt @@ -0,0 +1,36 @@ +Broadcom BCM53573 ILP clock +=========================== + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +This binding is used for ILP clock (sometimes referred as "slow clock") +on Broadcom BCM53573 devices using Cortex-A7 CPU. + +ILP's rate has to be calculated on runtime and it depends on ALP clock +which has to be referenced. + +This clock is part of PMU (Power Management Unit), a Broadcom's device +handing power-related aspects. Its node must be sub-node of the PMU +device. + +Required properties: +- compatible: "brcm,bcm53573-ilp" +- clocks: has to reference an ALP clock +- #clock-cells: should be <0> +- clock-output-names: from common clock bindings, should contain clock + name + +Example: + +pmu@18012000 { + compatible = "simple-mfd", "syscon"; + reg = <0x18012000 0x00001000>; + + ilp { + compatible = "brcm,bcm53573-ilp"; + clocks = <&alp>; + #clock-cells = <0>; + clock-output-names = "ilp"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/brcm,iproc-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,iproc-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab730ea0a560f3b84a7c854bb1d7e13f468ed79c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,iproc-clocks.txt @@ -0,0 +1,313 @@ +Broadcom iProc Family Clocks + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +The iProc clock controller manages clocks that are common to the iProc family. +An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL, +LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL +comprises of several leaf clocks + +Required properties for a PLL and its leaf clocks: + +- compatible: + Should have a value of the form "brcm,-". For example, GENPLL on +Cygnus has a compatible string of "brcm,cygnus-genpll" + +- #clock-cells: + Have a value of <1> since there are more than 1 leaf clock of a given PLL + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for the PLL + +- clocks: + The input parent clock phandle for the PLL. For most iProc PLLs, this is an +onboard crystal with a fixed rate + +- clock-output-names: + An ordered list of strings defining the names of the clocks + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + genpll: genpll { + #clock-cells = <1>; + compatible = "brcm,cygnus-genpll"; + reg = <0x0301d000 0x2c>, <0x0301c020 0x4>; + clocks = <&osc>; + clock-output-names = "genpll", "axi21", "250mhz", "ihost_sys", + "enet_sw", "audio_125", "can"; + }; + +Required properties for ASIU clocks: + +ASIU clocks are a special case. These clocks are derived directly from the +reference clock of the onboard crystal + +- compatible: + Should have a value of the form "brcm,-asiu-clk". For example, ASIU +clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk" + +- #clock-cells: + Have a value of <1> since there are more than 1 ASIU clocks + +- reg: + Define the base and range of the I/O address space that contain the iProc +clock control registers required for ASIU clocks + +- clocks: + The input parent clock phandle for the ASIU clock, i.e., the onboard +crystal + +- clock-output-names: + An ordered list of strings defining the names of the ASIU clocks + +Example: + + osc: oscillator { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + }; + + asiu_clks: asiu_clks { + #clock-cells = <1>; + compatible = "brcm,cygnus-asiu-clk"; + reg = <0x0301d048 0xc>, <0x180aa024 0x4>; + clocks = <&osc>; + clock-output-names = "keypad", "adc/touch", "pwm"; + }; + +Cygnus +------ +PLL and leaf clock compatible strings for Cygnus are: + "brcm,cygnus-armpll" + "brcm,cygnus-genpll" + "brcm,cygnus-lcpll0" + "brcm,cygnus-mipipll" + "brcm,cygnus-asiu-clk" + "brcm,cygnus-audiopll" + +The following table defines the set of PLL/clock index and ID for Cygnus. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-cygnus.h" + + Clock Source (Parent) Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + + keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK + adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK + pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK + + genpll crystal 0 BCM_CYGNUS_GENPLL + axi21 genpll 1 BCM_CYGNUS_GENPLL_AXI21_CLK + 250mhz genpll 2 BCM_CYGNUS_GENPLL_250MHZ_CLK + ihost_sys genpll 3 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK + enet_sw genpll 4 BCM_CYGNUS_GENPLL_ENET_SW_CLK + audio_125 genpll 5 BCM_CYGNUS_GENPLL_AUDIO_125_CLK + can genpll 6 BCM_CYGNUS_GENPLL_CAN_CLK + + lcpll0 crystal 0 BCM_CYGNUS_LCPLL0 + pcie_phy lcpll0 1 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK + ddr_phy lcpll0 2 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK + sdio lcpll0 3 BCM_CYGNUS_LCPLL0_SDIO_CLK + usb_phy lcpll0 4 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK + smart_card lcpll0 5 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK + ch5_unused lcpll0 6 BCM_CYGNUS_LCPLL0_CH5_UNUSED + + mipipll crystal 0 BCM_CYGNUS_MIPIPLL + ch0_unused mipipll 1 BCM_CYGNUS_MIPIPLL_CH0_UNUSED + ch1_lcd mipipll 2 BCM_CYGNUS_MIPIPLL_CH1_LCD + ch2_v3d mipipll 3 BCM_CYGNUS_MIPIPLL_CH2_V3D + ch3_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH3_UNUSED + ch4_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH4_UNUSED + ch5_unused mipipll 6 BCM_CYGNUS_MIPIPLL_CH5_UNUSED + + audiopll crystal 0 BCM_CYGNUS_AUDIOPLL + ch0_audio audiopll 1 BCM_CYGNUS_AUDIOPLL_CH0 + ch1_audio audiopll 2 BCM_CYGNUS_AUDIOPLL_CH1 + ch2_audio audiopll 3 BCM_CYGNUS_AUDIOPLL_CH2 + +Hurricane 2 +------ +PLL and leaf clock compatible strings for Hurricane 2 are: + "brcm,hr2-armpll" + +The following table defines the set of PLL/clock for Hurricane 2: + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + + +Northstar and Northstar Plus +------ +PLL and leaf clock compatible strings for Northstar and Northstar Plus are: + "brcm,nsp-armpll" + "brcm,nsp-genpll" + "brcm,nsp-lcpll0" + +The following table defines the set of PLL/clock index and ID for Northstar and +Northstar Plus. These clock IDs are defined in: + "include/dt-bindings/clock/bcm-nsp.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + armpll crystal N/A N/A + + genpll crystal 0 BCM_NSP_GENPLL + phy genpll 1 BCM_NSP_GENPLL_PHY_CLK + ethernetclk genpll 2 BCM_NSP_GENPLL_ENET_SW_CLK + usbclk genpll 3 BCM_NSP_GENPLL_USB_PHY_REF_CLK + iprocfast genpll 4 BCM_NSP_GENPLL_IPROCFAST_CLK + sata1 genpll 5 BCM_NSP_GENPLL_SATA1_CLK + sata2 genpll 6 BCM_NSP_GENPLL_SATA2_CLK + + lcpll0 crystal 0 BCM_NSP_LCPLL0 + pcie_phy lcpll0 1 BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK + sdio lcpll0 2 BCM_NSP_LCPLL0_SDIO_CLK + ddr_phy lcpll0 3 BCM_NSP_LCPLL0_DDR_PHY_CLK + +Northstar 2 +----------- +PLL and leaf clock compatible strings for Northstar 2 are: + "brcm,ns2-genpll-scr" + "brcm,ns2-genpll-sw" + "brcm,ns2-lcpll-ddr" + "brcm,ns2-lcpll-ports" + +The following table defines the set of PLL/clock index and ID for Northstar 2. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-ns2.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + + genpll_scr crystal 0 BCM_NS2_GENPLL_SCR + scr genpll_scr 1 BCM_NS2_GENPLL_SCR_SCR_CLK + fs genpll_scr 2 BCM_NS2_GENPLL_SCR_FS_CLK + audio_ref genpll_scr 3 BCM_NS2_GENPLL_SCR_AUDIO_CLK + ch3_unused genpll_scr 4 BCM_NS2_GENPLL_SCR_CH3_UNUSED + ch4_unused genpll_scr 5 BCM_NS2_GENPLL_SCR_CH4_UNUSED + ch5_unused genpll_scr 6 BCM_NS2_GENPLL_SCR_CH5_UNUSED + + genpll_sw crystal 0 BCM_NS2_GENPLL_SW + rpe genpll_sw 1 BCM_NS2_GENPLL_SW_RPE_CLK + 250 genpll_sw 2 BCM_NS2_GENPLL_SW_250_CLK + nic genpll_sw 3 BCM_NS2_GENPLL_SW_NIC_CLK + chimp genpll_sw 4 BCM_NS2_GENPLL_SW_CHIMP_CLK + port genpll_sw 5 BCM_NS2_GENPLL_SW_PORT_CLK + sdio genpll_sw 6 BCM_NS2_GENPLL_SW_SDIO_CLK + + lcpll_ddr crystal 0 BCM_NS2_LCPLL_DDR + pcie_sata_usb lcpll_ddr 1 BCM_NS2_LCPLL_DDR_PCIE_SATA_USB_CLK + ddr lcpll_ddr 2 BCM_NS2_LCPLL_DDR_DDR_CLK + ch2_unused lcpll_ddr 3 BCM_NS2_LCPLL_DDR_CH2_UNUSED + ch3_unused lcpll_ddr 4 BCM_NS2_LCPLL_DDR_CH3_UNUSED + ch4_unused lcpll_ddr 5 BCM_NS2_LCPLL_DDR_CH4_UNUSED + ch5_unused lcpll_ddr 6 BCM_NS2_LCPLL_DDR_CH5_UNUSED + + lcpll_ports crystal 0 BCM_NS2_LCPLL_PORTS + wan lcpll_ports 1 BCM_NS2_LCPLL_PORTS_WAN_CLK + rgmii lcpll_ports 2 BCM_NS2_LCPLL_PORTS_RGMII_CLK + ch2_unused lcpll_ports 3 BCM_NS2_LCPLL_PORTS_CH2_UNUSED + ch3_unused lcpll_ports 4 BCM_NS2_LCPLL_PORTS_CH3_UNUSED + ch4_unused lcpll_ports 5 BCM_NS2_LCPLL_PORTS_CH4_UNUSED + ch5_unused lcpll_ports 6 BCM_NS2_LCPLL_PORTS_CH5_UNUSED + +BCM63138 +-------- +PLL and leaf clock compatible strings for BCM63138 are: + "brcm,bcm63138-armpll" + +Stingray +----------- +PLL and leaf clock compatible strings for Stingray are: + "brcm,sr-genpll0" + "brcm,sr-genpll1" + "brcm,sr-genpll2" + "brcm,sr-genpll3" + "brcm,sr-genpll4" + "brcm,sr-genpll5" + "brcm,sr-genpll6" + + "brcm,sr-lcpll0" + "brcm,sr-lcpll1" + "brcm,sr-lcpll-pcie" + + +The following table defines the set of PLL/clock index and ID for Stingray. +These clock IDs are defined in: + "include/dt-bindings/clock/bcm-sr.h" + + Clock Source Index ID + --- ----- ----- --------- + crystal N/A N/A N/A + crmu_ref25m crystal N/A N/A + + genpll0 crystal 0 BCM_SR_GENPLL0 + clk_125m genpll0 1 BCM_SR_GENPLL0_125M_CLK + clk_scr genpll0 2 BCM_SR_GENPLL0_SCR_CLK + clk_250 genpll0 3 BCM_SR_GENPLL0_250M_CLK + clk_pcie_axi genpll0 4 BCM_SR_GENPLL0_PCIE_AXI_CLK + clk_paxc_axi_x2 genpll0 5 BCM_SR_GENPLL0_PAXC_AXI_X2_CLK + clk_paxc_axi genpll0 6 BCM_SR_GENPLL0_PAXC_AXI_CLK + + genpll1 crystal 0 BCM_SR_GENPLL1 + clk_pcie_tl genpll1 1 BCM_SR_GENPLL1_PCIE_TL_CLK + clk_mhb_apb genpll1 2 BCM_SR_GENPLL1_MHB_APB_CLK + + genpll2 crystal 0 BCM_SR_GENPLL2 + clk_nic genpll2 1 BCM_SR_GENPLL2_NIC_CLK + clk_ts_500_ref genpll2 2 BCM_SR_GENPLL2_TS_500_REF_CLK + clk_125_nitro genpll2 3 BCM_SR_GENPLL2_125_NITRO_CLK + clk_chimp genpll2 4 BCM_SR_GENPLL2_CHIMP_CLK + clk_nic_flash genpll2 5 BCM_SR_GENPLL2_NIC_FLASH_CLK + clk_fs genpll2 6 BCM_SR_GENPLL2_FS_CLK + + genpll3 crystal 0 BCM_SR_GENPLL3 + clk_hsls genpll3 1 BCM_SR_GENPLL3_HSLS_CLK + clk_sdio genpll3 2 BCM_SR_GENPLL3_SDIO_CLK + + genpll4 crystal 0 BCM_SR_GENPLL4 + clk_ccn genpll4 1 BCM_SR_GENPLL4_CCN_CLK + clk_tpiu_pll genpll4 2 BCM_SR_GENPLL4_TPIU_PLL_CLK + clk_noc genpll4 3 BCM_SR_GENPLL4_NOC_CLK + clk_chclk_fs4 genpll4 4 BCM_SR_GENPLL4_CHCLK_FS4_CLK + clk_bridge_fscpu genpll4 5 BCM_SR_GENPLL4_BRIDGE_FSCPU_CLK + + genpll5 crystal 0 BCM_SR_GENPLL5 + clk_fs4_hf genpll5 1 BCM_SR_GENPLL5_FS4_HF_CLK + clk_crypto_ae genpll5 2 BCM_SR_GENPLL5_CRYPTO_AE_CLK + clk_raid_ae genpll5 3 BCM_SR_GENPLL5_RAID_AE_CLK + + genpll6 crystal 0 BCM_SR_GENPLL6 + clk_48_usb genpll6 1 BCM_SR_GENPLL6_48_USB_CLK + + lcpll0 crystal 0 BCM_SR_LCPLL0 + clk_sata_refp lcpll0 1 BCM_SR_LCPLL0_SATA_REFP_CLK + clk_sata_refn lcpll0 2 BCM_SR_LCPLL0_SATA_REFN_CLK + clk_sata_350 lcpll0 3 BCM_SR_LCPLL0_SATA_350_CLK + clk_sata_500 lcpll0 4 BCM_SR_LCPLL0_SATA_500_CLK + + lcpll1 crystal 0 BCM_SR_LCPLL1 + clk_wan lcpll1 1 BCM_SR_LCPLL1_WAN_CLK + clk_usb_ref lcpll1 2 BCM_SR_LCPLL1_USB_REF_CLK + clk_crmu_ts lcpll1 3 BCM_SR_LCPLL1_CRMU_TS_CLK + + lcpll_pcie crystal 0 BCM_SR_LCPLL_PCIE + clk_pcie_phy_ref lcpll1 1 BCM_SR_LCPLL_PCIE_PHY_REF_CLK diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/brcm,kona-ccu.txt b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,kona-ccu.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e5a7d868557bcfa9165b91a36f319823163eec4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/brcm,kona-ccu.txt @@ -0,0 +1,138 @@ +Broadcom Kona Family Clocks + +This binding is associated with Broadcom SoCs having "Kona" style +clock control units (CCUs). A CCU is a clock provider that manages +a set of clock signals. Each CCU is represented by a node in the +device tree. + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible + Shall have a value of the form "brcm,--ccu", + where is a Broadcom SoC model number and is + the name of a defined CCU. For example: + "brcm,bcm11351-root-ccu" + The compatible strings used for each supported SoC family + are defined below. +- reg + Shall define the base and range of the address space + containing clock control registers +- #clock-cells + Shall have value <1>. The permitted clock-specifier values + are defined below. +- clock-output-names + Shall be an ordered list of strings defining the names of + the clocks provided by the CCU. + +Device tree example: + + slave_ccu: slave_ccu { + compatible = "brcm,bcm11351-slave-ccu"; + reg = <0x3e011000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "uartb", + "uartb2", + "uartb3", + "uartb4"; + }; + + ref_crystal_clk: ref_crystal { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <26000000>; + }; + + uart@3e002000 { + compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; + reg = <0x3e002000 0x1000>; + clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; + +BCM281XX family +--------------- +CCU compatible string values for SoCs in the BCM281XX family are: + "brcm,bcm11351-root-ccu" + "brcm,bcm11351-aon-ccu" + "brcm,bcm11351-hub-ccu" + "brcm,bcm11351-master-ccu" + "brcm,bcm11351-slave-ccu" + +The following table defines the set of CCUs and clock specifiers for +BCM281XX family clocks. When a clock consumer references a clocks, +its symbolic specifier (rather than its numeric index value) should +be used. These specifiers are defined in: + "include/dt-bindings/clock/bcm281xx.h" + + CCU Clock Type Index Specifier + --- ----- ---- ----- --------- + root frac_1m peri 0 BCM281XX_ROOT_CCU_FRAC_1M + + aon hub_timer peri 0 BCM281XX_AON_CCU_HUB_TIMER + aon pmu_bsc peri 1 BCM281XX_AON_CCU_PMU_BSC + aon pmu_bsc_var peri 2 BCM281XX_AON_CCU_PMU_BSC_VAR + + hub tmon_1m peri 0 BCM281XX_HUB_CCU_TMON_1M + + master sdio1 peri 0 BCM281XX_MASTER_CCU_SDIO1 + master sdio2 peri 1 BCM281XX_MASTER_CCU_SDIO2 + master sdio3 peri 2 BCM281XX_MASTER_CCU_SDIO3 + master sdio4 peri 3 BCM281XX_MASTER_CCU_SDIO4 + master dmac peri 4 BCM281XX_MASTER_CCU_DMAC + master usb_ic peri 5 BCM281XX_MASTER_CCU_USB_IC + master hsic2_48m peri 6 BCM281XX_MASTER_CCU_HSIC_48M + master hsic2_12m peri 7 BCM281XX_MASTER_CCU_HSIC_12M + + slave uartb peri 0 BCM281XX_SLAVE_CCU_UARTB + slave uartb2 peri 1 BCM281XX_SLAVE_CCU_UARTB2 + slave uartb3 peri 2 BCM281XX_SLAVE_CCU_UARTB3 + slave uartb4 peri 3 BCM281XX_SLAVE_CCU_UARTB4 + slave ssp0 peri 4 BCM281XX_SLAVE_CCU_SSP0 + slave ssp2 peri 5 BCM281XX_SLAVE_CCU_SSP2 + slave bsc1 peri 6 BCM281XX_SLAVE_CCU_BSC1 + slave bsc2 peri 7 BCM281XX_SLAVE_CCU_BSC2 + slave bsc3 peri 8 BCM281XX_SLAVE_CCU_BSC3 + slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM + + +BCM21664 family +--------------- +CCU compatible string values for SoCs in the BCM21664 family are: + "brcm,bcm21664-root-ccu" + "brcm,bcm21664-aon-ccu" + "brcm,bcm21664-master-ccu" + "brcm,bcm21664-slave-ccu" + +The following table defines the set of CCUs and clock specifiers for +BCM21664 family clocks. When a clock consumer references a clocks, +its symbolic specifier (rather than its numeric index value) should +be used. These specifiers are defined in: + "include/dt-bindings/clock/bcm21664.h" + + CCU Clock Type Index Specifier + --- ----- ---- ----- --------- + root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M + + aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER + + master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1 + master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2 + master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3 + master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4 + master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP + master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP + master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP + master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP + + slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB + slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2 + slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3 + slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4 + slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1 + slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2 + slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3 + slave bsc4 peri 7 BCM21664_SLAVE_CCU_BSC4 diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/calxeda.txt b/arch/arm64/boot/dts/vendor/bindings/clock/calxeda.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a6ac1bdcda1acfeb1b451f34e87afc0496a9539 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/calxeda.txt @@ -0,0 +1,17 @@ +Device Tree Clock bindings for Calxeda highbank platform + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "calxeda,hb-pll-clock" - for a PLL clock + "calxeda,hb-a9periph-clock" - The A9 peripheral clock divided from the + A9 clock. + "calxeda,hb-a9bus-clock" - The A9 bus clock divided from the A9 clock. + "calxeda,hb-emmc-clock" - Divided clock for MMC/SD controller. +- reg : shall be the control register offset from SYSREGs base for the clock. +- clocks : shall be the input parent clock phandle for the clock. This is + either an oscillator or a pll output. +- #clock-cells : from common clock binding; shall be set to 0. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/clk-exynos-audss.txt b/arch/arm64/boot/dts/vendor/bindings/clock/clk-exynos-audss.txt new file mode 100644 index 0000000000000000000000000000000000000000..6030afb10b5c15558dfd27ed40f55d4f12171ec6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/clk-exynos-audss.txt @@ -0,0 +1,103 @@ +* Samsung Audio Subsystem Clock Controller + +The Samsung Audio Subsystem clock controller generates and supplies clocks +to Audio Subsystem block available in the S5PV210 and Exynos SoCs. The clock +binding described here is applicable to all SoCs in Exynos family. + +Required Properties: + +- compatible: should be one of the following: + - "samsung,exynos4210-audss-clock" - controller compatible with all Exynos4 SoCs. + - "samsung,exynos5250-audss-clock" - controller compatible with Exynos5250 + SoCs. + - "samsung,exynos5410-audss-clock" - controller compatible with Exynos5410 + SoCs. + - "samsung,exynos5420-audss-clock" - controller compatible with Exynos5420 + SoCs. +- reg: physical base address and length of the controller's register set. + +- #clock-cells: should be 1. + +- clocks: + - pll_ref: Fixed rate PLL reference clock, parent of mout_audss. "fin_pll" + is used if not specified. + - pll_in: Input PLL to the AudioSS block, parent of mout_audss. "fout_epll" + is used if not specified. + - cdclk: External i2s clock, parent of mout_i2s. "cdclk0" is used if not + specified. + - sclk_audio: Audio bus clock, parent of mout_i2s. "sclk_audio0" is used if + not specified. + - sclk_pcm_in: PCM clock, parent of sclk_pcm. "sclk_pcm0" is used if not + specified. + +- clock-names: Aliases for the above clocks. They should be "pll_ref", + "pll_in", "cdclk", "sclk_audio", and "sclk_pcm_in" respectively. + +Optional Properties: + + - power-domains: a phandle to respective power domain node as described by + generic PM domain bindings (see power/power_domain.txt for more + information). + +The following is the list of clocks generated by the controller. Each clock is +assigned an identifier and client nodes use this identifier to specify the +clock which they consume. Some of the clocks are available only on a particular +Exynos4 SoC and this is specified where applicable. + +Provided clocks: + +Clock ID SoC (if specific) +----------------------------------------------- + +mout_audss 0 +mout_i2s 1 +dout_srp 2 +dout_aud_bus 3 +dout_i2s 4 +srp_clk 5 +i2s_bus 6 +sclk_i2s 7 +pcm_bus 8 +sclk_pcm 9 +adma 10 Exynos5420 + +Example 1: An example of a clock controller node using the default input + clock names is listed below. + +clock_audss: audss-clock-controller@3810000 { + compatible = "samsung,exynos5250-audss-clock"; + reg = <0x03810000 0x0C>; + #clock-cells = <1>; +}; + +Example 2: An example of a clock controller node with the input clocks + specified. + +clock_audss: audss-clock-controller@3810000 { + compatible = "samsung,exynos5250-audss-clock"; + reg = <0x03810000 0x0C>; + #clock-cells = <1>; + clocks = <&clock 1>, <&clock 7>, <&clock 138>, <&clock 160>, + <&ext_i2s_clk>; + clock-names = "pll_ref", "pll_in", "sclk_audio", "sclk_pcm_in", "cdclk"; +}; + +Example 3: I2S controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + +i2s0: i2s@3830000 { + compatible = "samsung,i2s-v5"; + reg = <0x03830000 0x100>; + dmas = <&pdma0 10 + &pdma0 9 + &pdma0 8>; + dma-names = "tx", "rx", "tx-sec"; + clocks = <&clock_audss EXYNOS_I2S_BUS>, + <&clock_audss EXYNOS_I2S_BUS>, + <&clock_audss EXYNOS_SCLK_I2S>, + <&clock_audss EXYNOS_MOUT_AUDSS>, + <&clock_audss EXYNOS_MOUT_I2S>; + clock-names = "iis", "i2s_opclk0", "i2s_opclk1", + "mout_audss", "mout_i2s"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/clk-palmas-clk32kg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/clk-palmas-clk32kg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..4208886d834a03d787f870995fddc43b430510e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/clk-palmas-clk32kg-clocks.txt @@ -0,0 +1,35 @@ +* Palmas 32KHz clocks * + +Palmas device has two clock output pins for 32KHz, KG and KG_AUDIO. + +This binding uses the common clock binding ./clock-bindings.txt. + +Required properties: +- compatible : "ti,palmas-clk32kg" for clk32kg clock + "ti,palmas-clk32kgaudio" for clk32kgaudio clock +- #clock-cells : shall be set to 0. + +Optional property: +- ti,external-sleep-control: The external enable input pins controlled the + enable/disable of clocks. The external enable input pins ENABLE1, + ENABLE2 and NSLEEP. The valid values for the external pins are: + PALMAS_EXT_CONTROL_PIN_ENABLE1 for ENABLE1 pin + PALMAS_EXT_CONTROL_PIN_ENABLE2 for ENABLE2 pin + PALMAS_EXT_CONTROL_PIN_NSLEEP for NSLEEP pin + Option 0 or missing this property means the clock is enabled/disabled + via register access and these pins do not have any control. + The macros of external control pins for DTS is defined at + dt-bindings/mfd/palmas.h + +Example: + #include + ... + palmas: tps65913@58 { + ... + clk32kg: palmas_clk32k@0 { + compatible = "ti,palmas-clk32kg"; + #clock-cells = <0>; + ti,external-sleep-control = ; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/clk-s5pv210-audss.txt b/arch/arm64/boot/dts/vendor/bindings/clock/clk-s5pv210-audss.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6272dcd96f404095e35c854e531d8a6a58b7583 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/clk-s5pv210-audss.txt @@ -0,0 +1,53 @@ +* Samsung Audio Subsystem Clock Controller + +The Samsung Audio Subsystem clock controller generates and supplies clocks +to Audio Subsystem block available in the S5PV210 and compatible SoCs. + +Required Properties: + +- compatible: should be "samsung,s5pv210-audss-clock". +- reg: physical base address and length of the controller's register set. + +- #clock-cells: should be 1. + +- clocks: + - hclk: AHB bus clock of the Audio Subsystem. + - xxti: Optional fixed rate PLL reference clock, parent of mout_audss. If + not specified (i.e. xusbxti is used for PLL reference), it is fixed to + a clock named "xxti". + - fout_epll: Input PLL to the AudioSS block, parent of mout_audss. + - iiscdclk0: Optional external i2s clock, parent of mout_i2s. If not + specified, it is fixed to a clock named "iiscdclk0". + - sclk_audio0: Audio bus clock, parent of mout_i2s. + +- clock-names: Aliases for the above clocks. They should be "hclk", + "xxti", "fout_epll", "iiscdclk0", and "sclk_audio0" respectively. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s5pv210-audss-clk.h header and can be used in device +tree sources. + +Example: Clock controller node. + + clk_audss: clock-controller@c0900000 { + compatible = "samsung,s5pv210-audss-clock"; + reg = <0xc0900000 0x1000>; + #clock-cells = <1>; + clock-names = "hclk", "xxti", + "fout_epll", "sclk_audio0"; + clocks = <&clocks DOUT_HCLKP>, <&xxti>, + <&clocks FOUT_EPLL>, <&clocks SCLK_AUDIO0>; + }; + +Example: I2S controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + i2s0: i2s@3830000 { + /* ... */ + clock-names = "iis", "i2s_opclk0", + "i2s_opclk1"; + clocks = <&clk_audss CLK_I2S>, <&clk_audss CLK_I2S>, + <&clk_audss CLK_DOUT_AUD_BUS>; + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/clock-bindings.txt b/arch/arm64/boot/dts/vendor/bindings/clock/clock-bindings.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ec489eebe723afb0f6cf1700d7869e9d84f0ac6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/clock-bindings.txt @@ -0,0 +1,170 @@ +This binding is a work-in-progress, and are based on some experimental +work by benh[1]. + +Sources of clock signal can be represented by any node in the device +tree. Those nodes are designated as clock providers. Clock consumer +nodes use a phandle and clock specifier pair to connect clock provider +outputs to clock inputs. Similar to the gpio specifiers, a clock +specifier is an array of zero, one or more cells identifying the clock +output on a device. The length of a clock specifier is defined by the +value of a #clock-cells property in the clock provider node. + +[1] http://patchwork.ozlabs.org/patch/31551/ + +==Clock providers== + +Required properties: +#clock-cells: Number of cells in a clock specifier; Typically 0 for nodes + with a single clock output and 1 for nodes with multiple + clock outputs. + +Optional properties: +clock-output-names: Recommended to be a list of strings of clock output signal + names indexed by the first cell in the clock specifier. + However, the meaning of clock-output-names is domain + specific to the clock provider, and is only provided to + encourage using the same meaning for the majority of clock + providers. This format may not work for clock providers + using a complex clock specifier format. In those cases it + is recommended to omit this property and create a binding + specific names property. + + Clock consumer nodes must never directly reference + the provider's clock-output-names property. + +For example: + + oscillator { + #clock-cells = <1>; + clock-output-names = "ckil", "ckih"; + }; + +- this node defines a device with two clock outputs, the first named + "ckil" and the second named "ckih". Consumer nodes always reference + clocks by index. The names should reflect the clock output signal + names for the device. + +clock-indices: If the identifying number for the clocks in the node + is not linear from zero, then this allows the mapping of + identifiers into the clock-output-names array. + +For example, if we have two clocks <&oscillator 1> and <&oscillator 3>: + + oscillator { + compatible = "myclocktype"; + #clock-cells = <1>; + clock-indices = <1>, <3>; + clock-output-names = "clka", "clkb"; + } + + This ensures we do not have any empty strings in clock-output-names + + +==Clock consumers== + +Required properties: +clocks: List of phandle and clock specifier pairs, one pair + for each clock input to the device. Note: if the + clock provider specifies '0' for #clock-cells, then + only the phandle portion of the pair will appear. + +Optional properties: +clock-names: List of clock input name strings sorted in the same + order as the clocks property. Consumers drivers + will use clock-names to match clock input names + with clocks specifiers. +clock-ranges: Empty property indicating that child nodes can inherit named + clocks from this node. Useful for bus nodes to provide a + clock to their children. + +For example: + + device { + clocks = <&osc 1>, <&ref 0>; + clock-names = "baud", "register"; + }; + + +This represents a device with two clock inputs, named "baud" and "register". +The baud clock is connected to output 1 of the &osc device, and the register +clock is connected to output 0 of the &ref. + +==Example== + + /* external oscillator */ + osc: oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <32678>; + clock-output-names = "osc"; + }; + + /* phase-locked-loop device, generates a higher frequency clock + * from the external oscillator reference */ + pll: pll@4c000 { + compatible = "vendor,some-pll-interface" + #clock-cells = <1>; + clocks = <&osc 0>; + clock-names = "ref"; + reg = <0x4c000 0x1000>; + clock-output-names = "pll", "pll-switched"; + }; + + /* UART, using the low frequency oscillator for the baud clock, + * and the high frequency switched PLL output for register + * clocking */ + uart@a000 { + compatible = "fsl,imx-uart"; + reg = <0xa000 0x1000>; + interrupts = <33>; + clocks = <&osc 0>, <&pll 1>; + clock-names = "baud", "register"; + }; + +This DT fragment defines three devices: an external oscillator to provide a +low-frequency reference clock, a PLL device to generate a higher frequency +clock signal, and a UART. + +* The oscillator is fixed-frequency, and provides one clock output, named "osc". +* The PLL is both a clock provider and a clock consumer. It uses the clock + signal generated by the external oscillator, and provides two output signals + ("pll" and "pll-switched"). +* The UART has its baud clock connected the external oscillator and its + register clock connected to the PLL clock (the "pll-switched" signal) + +==Assigned clock parents and rates== + +Some platforms may require initial configuration of default parent clocks +and clock frequencies. Such a configuration can be specified in a device tree +node through assigned-clocks, assigned-clock-parents and assigned-clock-rates +properties. The assigned-clock-parents property should contain a list of parent +clocks in the form of a phandle and clock specifier pair and the +assigned-clock-rates property should contain a list of frequencies in Hz. Both +these properties should correspond to the clocks listed in the assigned-clocks +property. + +To skip setting parent or rate of a clock its corresponding entry should be +set to 0, or can be omitted if it is not followed by any non-zero entry. + + uart@a000 { + compatible = "fsl,imx-uart"; + reg = <0xa000 0x1000>; + ... + clocks = <&osc 0>, <&pll 1>; + clock-names = "baud", "register"; + + assigned-clocks = <&clkcon 0>, <&pll 2>; + assigned-clock-parents = <&pll 2>; + assigned-clock-rates = <0>, <460800>; + }; + +In this example the <&pll 2> clock is set as parent of clock <&clkcon 0> and +the <&pll 2> clock is assigned a frequency value of 460800 Hz. + +Configuring a clock's parent and rate through the device node that consumes +the clock can be done only for clocks that have a single user. Specifying +conflicting parent or rate configuration in multiple consumer nodes for +a shared clock is forbidden. + +Configuration of common clocks, which affect multiple consumer devices can +be similarly specified in the clock provider node. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/clps711x-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/clps711x-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1bd53f79d91cd249fe043fc990bc0fbd0ecc58c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/clps711x-clock.txt @@ -0,0 +1,19 @@ +* Clock bindings for the Cirrus Logic CLPS711X CPUs + +Required properties: +- compatible : Shall contain "cirrus,ep7209-clk". +- reg : Address of the internal register set. +- startup-frequency: Factory set CPU startup frequency in HZ. +- #clock-cells : Should be <1>. + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/clps711x-clock.h +for the full list of CLPS711X clock IDs. + +Example: + clks: clks@80000000 { + #clock-cells = <1>; + compatible = "cirrus,ep7312-clk", "cirrus,ep7209-clk"; + reg = <0x80000000 0xc000>; + startup-frequency = <73728000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/cs2000-cp.txt b/arch/arm64/boot/dts/vendor/bindings/clock/cs2000-cp.txt new file mode 100644 index 0000000000000000000000000000000000000000..54e6df0bee8a9fac4f728593341ea11c82292338 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/cs2000-cp.txt @@ -0,0 +1,22 @@ +CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier + +Required properties: + +- compatible: "cirrus,cs2000-cp" +- reg: The chip select number on the I2C bus +- clocks: common clock binding for CLK_IN, XTI/REF_CLK +- clock-names: CLK_IN : clk_in, XTI/REF_CLK : ref_clk +- #clock-cells: must be <0> + +Example: + +&i2c2 { + ... + cs2000: clk_multiplier@4f { + #clock-cells = <0>; + compatible = "cirrus,cs2000-cp"; + reg = <0x4f>; + clocks = <&rcar_sound 0>, <&x12_clk>; + clock-names = "clk_in", "ref_clk"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/csr,atlas7-car.txt b/arch/arm64/boot/dts/vendor/bindings/clock/csr,atlas7-car.txt new file mode 100644 index 0000000000000000000000000000000000000000..54d6d135833942fe241e4fcaaf5ea1211a9d483b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/csr,atlas7-car.txt @@ -0,0 +1,55 @@ +* Clock and reset bindings for CSR atlas7 + +Required properties: +- compatible: Should be "sirf,atlas7-car" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- #reset-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. +The ID list atlas7_clks defined in drivers/clk/sirf/clk-atlas7.c + +The reset consumer should specify the desired reset by having the reset +ID in its "reset" phandle cell. +The ID list atlas7_reset_unit defined in drivers/clk/sirf/clk-atlas7.c + +Examples: Clock and reset controller node: + +car: clock-controller@18620000 { + compatible = "sirf,atlas7-car"; + reg = <0x18620000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; + +Examples: Consumers using clock or reset: + +timer@10dc0000 { + compatible = "sirf,macro-tick"; + reg = <0x10dc0000 0x1000>; + clocks = <&car 54>; + interrupts = <0 0 0>, + <0 1 0>, + <0 2 0>, + <0 49 0>, + <0 50 0>, + <0 51 0>; +}; + +uart1: uart@18020000 { + cell-index = <1>; + compatible = "sirf,macro-uart"; + reg = <0x18020000 0x1000>; + clocks = <&clks 95>; + interrupts = <0 18 0>; + fifosize = <32>; +}; + +vpp@13110000 { + compatible = "sirf,prima2-vpp"; + reg = <0x13110000 0x10000>; + interrupts = <0 31 0>; + clocks = <&car 85>; + resets = <&car 29>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/dove-divider-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/dove-divider-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..217871f483c0bab75f4ebdffdddd19643bfa297a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/dove-divider-clock.txt @@ -0,0 +1,28 @@ +PLL divider based Dove clocks + +Marvell Dove has a 2GHz PLL, which feeds into a set of dividers to provide +high speed clocks for a number of peripherals. These dividers are part of +the PMU, and thus this node should be a child of the PMU node. + +The following clocks are provided: + +ID Clock +------------- +0 AXI bus clock +1 GPU clock +2 VMeta clock +3 LCD clock + +Required properties: +- compatible : shall be "marvell,dove-divider-clock" +- reg : shall be the register address of the Core PLL and Clock Divider + Control 0 register. This will cover that register, as well as the + Core PLL and Clock Divider Control 1 register. Thus, it will have + a size of 8. +- #clock-cells : from common clock binding; shall be set to 1 + +divider_clk: core-clock@64 { + compatible = "marvell,dove-divider-clock"; + reg = <0x0064 0x8>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/efm32-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/efm32-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..263d293f6a104d33e98b04f223648ed1272d1f06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/efm32-clock.txt @@ -0,0 +1,11 @@ +* Clock bindings for Energy Micro efm32 Giant Gecko's Clock Management Unit + +Required properties: +- compatible: Should be "efm32gg,cmu" +- reg: Base address and length of the register set +- interrupts: Interrupt used by the CMU +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock ID in +its "clocks" phandle cell. The header efm32-clk.h contains a list of available +IDs. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/emev2-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/emev2-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..268ca615459e754900f979bda8542b3c5d2cbac3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/emev2-clock.txt @@ -0,0 +1,98 @@ +Device tree Clock bindings for Renesas EMMA Mobile EV2 + +This binding uses the common clock binding. + +* SMU +System Management Unit described in user's manual R19UH0037EJ1000_SMU. +This is not a clock provider, but clocks under SMU depend on it. + +Required properties: +- compatible: Should be "renesas,emev2-smu" +- reg: Address and Size of SMU registers + +* SMU_CLKDIV +Function block with an input mux and a divider, which corresponds to +"Serial clock generator" in fig."Clock System Overview" of the manual, +and "xxx frequency division setting register" (XXXCLKDIV) registers. +This makes internal (neither input nor output) clock that is provided +to input of xxxGCLK block. + +Required properties: +- compatible: Should be "renesas,emev2-smu-clkdiv" +- reg: Byte offset from SMU base and Bit position in the register +- clocks: Parent clocks. Input clocks as described in clock-bindings.txt +- #clock-cells: Should be <0> + +* SMU_GCLK +Clock gating node shown as "Clock stop processing block" in the +fig."Clock System Overview" of the manual. +Registers are "xxx clock gate control register" (XXXGCLKCTRL). + +Required properties: +- compatible: Should be "renesas,emev2-smu-gclk" +- reg: Byte offset from SMU base and Bit position in the register +- clocks: Input clock as described in clock-bindings.txt +- #clock-cells: Should be <0> + +Example of provider: + +usia_u0_sclkdiv: usia_u0_sclkdiv { + compatible = "renesas,emev2-smu-clkdiv"; + reg = <0x610 0>; + clocks = <&pll3_fo>, <&pll4_fo>, <&pll1_fo>, <&osc1_fo>; + #clock-cells = <0>; +}; + +usia_u0_sclk: usia_u0_sclk { + compatible = "renesas,emev2-smu-gclk"; + reg = <0x4a0 1>; + clocks = <&usia_u0_sclkdiv>; + #clock-cells = <0>; +}; + +Example of consumer: + +serial@e1020000 { + compatible = "renesas,em-uart"; + reg = <0xe1020000 0x38>; + interrupts = <0 8 0>; + clocks = <&usia_u0_sclk>; + clock-names = "sclk"; +}; + +Example of clock-tree description: + + This describes a clock path in the clock tree + c32ki -> pll3_fo -> usia_u0_sclkdiv -> usia_u0_sclk + +smu@e0110000 { + compatible = "renesas,emev2-smu"; + reg = <0xe0110000 0x10000>; + #address-cells = <2>; + #size-cells = <0>; + + c32ki: c32ki { + compatible = "fixed-clock"; + clock-frequency = <32768>; + #clock-cells = <0>; + }; + pll3_fo: pll3_fo { + compatible = "fixed-factor-clock"; + clocks = <&c32ki>; + clock-div = <1>; + clock-mult = <7000>; + #clock-cells = <0>; + }; + usia_u0_sclkdiv: usia_u0_sclkdiv { + compatible = "renesas,emev2-smu-clkdiv"; + reg = <0x610 0>; + clocks = <&pll3_fo>; + #clock-cells = <0>; + }; + usia_u0_sclk: usia_u0_sclk { + compatible = "renesas,emev2-smu-gclk"; + reg = <0x4a0 1>; + clocks = <&usia_u0_sclkdiv>; + #clock-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos3250-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos3250-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..7441ed519f02d9f84c1ae5736ab4c7fb3fdd4cff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos3250-clock.txt @@ -0,0 +1,57 @@ +* Samsung Exynos3250 Clock Controller + +The Exynos3250 clock controller generates and supplies clock to various +controllers within the Exynos3250 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,exynos3250-cmu" - controller compatible with Exynos3250 SoC. + - "samsung,exynos3250-cmu-dmc" - controller compatible with + Exynos3250 SoC for Dynamic Memory Controller domain. + - "samsung,exynos3250-cmu-isp" - ISP block clock controller compatible + with Exynos3250 SOC + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos3250.h header and can be used in device +tree sources. + +Example 1: Examples of clock controller nodes are listed below. + + cmu: clock-controller@10030000 { + compatible = "samsung,exynos3250-cmu"; + reg = <0x10030000 0x20000>; + #clock-cells = <1>; + }; + + cmu_dmc: clock-controller@105c0000 { + compatible = "samsung,exynos3250-cmu-dmc"; + reg = <0x105C0000 0x2000>; + #clock-cells = <1>; + }; + + cmu_isp: clock-controller@10048000 { + compatible = "samsung,exynos3250-cmu-isp"; + reg = <0x10048000 0x1000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@13800000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13800000 0x100>; + interrupts = <0 109 0>; + clocks = <&cmu CLK_UART0>, <&cmu CLK_SCLK_UART0>; + clock-names = "uart", "clk_uart_baud0"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos4-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos4-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..17bb11365354d6d6126446874d562da2dfe7e45d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos4-clock.txt @@ -0,0 +1,86 @@ +* Samsung Exynos4 Clock Controller + +The Exynos4 clock controller generates and supplies clock to various controllers +within the Exynos4 SoC. The clock binding described here is applicable to all +SoC's in the Exynos4 family. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,exynos4210-clock" - controller compatible with Exynos4210 SoC. + - "samsung,exynos4412-clock" - controller compatible with Exynos4412 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos4.h header and can be used in device +tree sources. + +Example 1: An example of a clock controller node is listed below. + + clock: clock-controller@10030000 { + compatible = "samsung,exynos4210-clock"; + reg = <0x10030000 0x20000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@13820000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13820000 0x100>; + interrupts = <0 54 0>; + clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>; + clock-names = "uart", "clk_uart_baud0"; + }; + +Exynos4412 SoC contains some additional clocks for FIMC-ISP (Camera ISP) +subsystem. Registers for those clocks are located in the ISP power domain. +Because those registers are also located in a different memory region than +the main clock controller, a separate clock controller has to be defined for +handling them. + +Required Properties: + +- compatible: should be "samsung,exynos4412-isp-clock". + +- reg: physical base address of the ISP clock controller and length of memory + mapped region. + +- #clock-cells: should be 1. + +- clocks: list of the clock controller input clock identifiers, + from common clock bindings, should point to CLK_ACLK200 and + CLK_ACLK400_MCUISP clocks from the main clock controller. + +- clock-names: list of the clock controller input clock names, + as described in clock-bindings.txt, should be "aclk200" and + "aclk400_mcuisp". + +- power-domains: a phandle to ISP power domain node as described by + generic PM domain bindings. + +Example 3: The clock controllers bindings for Exynos4412 SoCs. + + clock: clock-controller@10030000 { + compatible = "samsung,exynos4412-clock"; + reg = <0x10030000 0x18000>; + #clock-cells = <1>; + }; + + isp_clock: clock-controller@10048000 { + compatible = "samsung,exynos4412-isp-clock"; + reg = <0x10048000 0x1000>; + #clock-cells = <1>; + power-domains = <&pd_isp>; + clocks = <&clock CLK_ACLK200>, <&clock CLK_ACLK400_MCUISP>; + clock-names = "aclk200", "aclk400_mcuisp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos5250-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5250-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..aff266a12eeb71bf7cf05a8cbeecbe4390f21ef4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5250-clock.txt @@ -0,0 +1,41 @@ +* Samsung Exynos5250 Clock Controller + +The Exynos5250 clock controller generates and supplies clock to various +controllers within the Exynos5250 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,exynos5250-clock" - controller compatible with Exynos5250 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos5250.h header and can be used in device +tree sources. + +Example 1: An example of a clock controller node is listed below. + + clock: clock-controller@10010000 { + compatible = "samsung,exynos5250-clock"; + reg = <0x10010000 0x30000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@13820000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13820000 0x100>; + interrupts = <0 54 0>; + clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>; + clock-names = "uart", "clk_uart_baud0"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos5260-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5260-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..c79d31f7f66e23f979960580737bdfcf19d0a12b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5260-clock.txt @@ -0,0 +1,190 @@ +* Samsung Exynos5260 Clock Controller + +Exynos5260 has 13 clock controllers which are instantiated +independently from the device-tree. These clock controllers +generate and supply clocks to various hardware blocks within +the SoC. + +Each clock is assigned an identifier and client nodes can use +this identifier to specify the clock which they consume. All +available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos5260-clk.h header and can be used in +device tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It +is expected that they are defined using standard clock bindings +with following clock-output-names: + + - "fin_pll" - PLL input clock from XXTI + - "xrtcxti" - input clock from XRTCXTI + - "ioclk_pcm_extclk" - pcm external operation clock + - "ioclk_spdif_extclk" - spdif external operation clock + - "ioclk_i2s_cdclk" - i2s0 codec clock + +Phy clocks: + +There are several clocks which are generated by specific PHYs. +These clocks are fed into the clock controller and then routed to +the hardware blocks. These clocks are defined as fixed clocks in the +driver with following names: + + - "phyclk_dptx_phy_ch3_txd_clk" - dp phy clock for channel 3 + - "phyclk_dptx_phy_ch2_txd_clk" - dp phy clock for channel 2 + - "phyclk_dptx_phy_ch1_txd_clk" - dp phy clock for channel 1 + - "phyclk_dptx_phy_ch0_txd_clk" - dp phy clock for channel 0 + - "phyclk_hdmi_phy_tmds_clko" - hdmi phy tmds clock + - "phyclk_hdmi_phy_pixel_clko" - hdmi phy pixel clock + - "phyclk_hdmi_link_o_tmds_clkhi" - hdmi phy for hdmi link + - "phyclk_dptx_phy_o_ref_clk_24m" - dp phy reference clock + - "phyclk_dptx_phy_clk_div2" + - "phyclk_mipi_dphy_4l_m_rxclkesc0" + - "phyclk_usbhost20_phy_phyclock" - usb 2.0 phy clock + - "phyclk_usbhost20_phy_freeclk" + - "phyclk_usbhost20_phy_clk48mohci" + - "phyclk_usbdrd30_udrd30_pipe_pclk" + - "phyclk_usbdrd30_udrd30_phyclock" - usb 3.0 phy clock + +Required Properties for Clock Controller: + + - compatible: should be one of the following. + 1) "samsung,exynos5260-clock-top" + 2) "samsung,exynos5260-clock-peri" + 3) "samsung,exynos5260-clock-egl" + 4) "samsung,exynos5260-clock-kfc" + 5) "samsung,exynos5260-clock-g2d" + 6) "samsung,exynos5260-clock-mif" + 7) "samsung,exynos5260-clock-mfc" + 8) "samsung,exynos5260-clock-g3d" + 9) "samsung,exynos5260-clock-fsys" + 10) "samsung,exynos5260-clock-aud" + 11) "samsung,exynos5260-clock-isp" + 12) "samsung,exynos5260-clock-gscl" + 13) "samsung,exynos5260-clock-disp" + + - reg: physical base address of the controller and the length of + memory mapped region. + + - #clock-cells: should be 1. + + - clocks: list of clock identifiers which are fed as the input to + the given clock controller. Please refer the next section to find + the input clocks for a given controller. + + - clock-names: list of names of clocks which are fed as the input + to the given clock controller. + +Input clocks for top clock controller: + - fin_pll + - dout_mem_pll + - dout_bus_pll + - dout_media_pll + +Input clocks for peri clock controller: + - fin_pll + - ioclk_pcm_extclk + - ioclk_i2s_cdclk + - ioclk_spdif_extclk + - phyclk_hdmi_phy_ref_cko + - dout_aclk_peri_66 + - dout_sclk_peri_uart0 + - dout_sclk_peri_uart1 + - dout_sclk_peri_uart2 + - dout_sclk_peri_spi0_b + - dout_sclk_peri_spi1_b + - dout_sclk_peri_spi2_b + - dout_aclk_peri_aud + - dout_sclk_peri_spi0_b + +Input clocks for egl clock controller: + - fin_pll + - dout_bus_pll + +Input clocks for kfc clock controller: + - fin_pll + - dout_media_pll + +Input clocks for g2d clock controller: + - fin_pll + - dout_aclk_g2d_333 + +Input clocks for mif clock controller: + - fin_pll + +Input clocks for mfc clock controller: + - fin_pll + - dout_aclk_mfc_333 + +Input clocks for g3d clock controller: + - fin_pll + +Input clocks for fsys clock controller: + - fin_pll + - phyclk_usbhost20_phy_phyclock + - phyclk_usbhost20_phy_freeclk + - phyclk_usbhost20_phy_clk48mohci + - phyclk_usbdrd30_udrd30_pipe_pclk + - phyclk_usbdrd30_udrd30_phyclock + - dout_aclk_fsys_200 + +Input clocks for aud clock controller: + - fin_pll + - fout_aud_pll + - ioclk_i2s_cdclk + - ioclk_pcm_extclk + +Input clocks for isp clock controller: + - fin_pll + - dout_aclk_isp1_266 + - dout_aclk_isp1_400 + - mout_aclk_isp1_266 + +Input clocks for gscl clock controller: + - fin_pll + - dout_aclk_gscl_400 + - dout_aclk_gscl_333 + +Input clocks for disp clock controller: + - fin_pll + - phyclk_dptx_phy_ch3_txd_clk + - phyclk_dptx_phy_ch2_txd_clk + - phyclk_dptx_phy_ch1_txd_clk + - phyclk_dptx_phy_ch0_txd_clk + - phyclk_hdmi_phy_tmds_clko + - phyclk_hdmi_phy_ref_clko + - phyclk_hdmi_phy_pixel_clko + - phyclk_hdmi_link_o_tmds_clkhi + - phyclk_mipi_dphy_4l_m_txbyte_clkhs + - phyclk_dptx_phy_o_ref_clk_24m + - phyclk_dptx_phy_clk_div2 + - phyclk_mipi_dphy_4l_m_rxclkesc0 + - phyclk_hdmi_phy_ref_cko + - ioclk_spdif_extclk + - dout_aclk_peri_aud + - dout_aclk_disp_222 + - dout_sclk_disp_pixel + - dout_aclk_disp_333 + +Example 1: An example of a clock controller node is listed below. + + clock_mfc: clock-controller@11090000 { + compatible = "samsung,exynos5260-clock-mfc"; + clock = <&fin_pll>, <&clock_top TOP_DOUT_ACLK_MFC_333>; + clock-names = "fin_pll", "dout_aclk_mfc_333"; + reg = <0x11090000 0x10000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the + peri clock controller. Refer to the standard clock bindings for + information about 'clocks' and 'clock-names' property. + + serial@12c00000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x12C00000 0x100>; + interrupts = <0 146 0>; + clocks = <&clock_peri PERI_PCLK_UART0>, <&clock_peri PERI_SCLK_UART0>; + clock-names = "uart", "clk_uart_baud0"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos5410-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5410-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..217beb27c30ea515f07b8eb09f88f18b92f10fa1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5410-clock.txt @@ -0,0 +1,50 @@ +* Samsung Exynos5410 Clock Controller + +The Exynos5410 clock controller generates and supplies clock to various +controllers within the Exynos5410 SoC. + +Required Properties: + +- compatible: should be "samsung,exynos5410-clock" + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +- clocks: should contain an entry specifying the root clock from external + oscillator supplied through XXTI or XusbXTI pin. This clock should be + defined using standard clock bindings with "fin_pll" clock-output-name. + That clock is being passed internally to the 9 PLLs. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos5410.h header and can be used in device +tree sources. + +Example 1: An example of a clock controller node is listed below. + + fin_pll: xxti { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + clock-output-names = "fin_pll"; + #clock-cells = <0>; + }; + + clock: clock-controller@10010000 { + compatible = "samsung,exynos5410-clock"; + reg = <0x10010000 0x30000>; + #clock-cells = <1>; + clocks = <&fin_pll>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@12c20000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x12C00000 0x100>; + interrupts = <0 51 0>; + clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>; + clock-names = "uart", "clk_uart_baud0"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos5420-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5420-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..717a7b1531c78278e606c16f545627651dce2ccd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5420-clock.txt @@ -0,0 +1,42 @@ +* Samsung Exynos5420 Clock Controller + +The Exynos5420 clock controller generates and supplies clock to various +controllers within the Exynos5420 SoC and for the Exynos5800 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,exynos5420-clock" - controller compatible with Exynos5420 SoC. + - "samsung,exynos5800-clock" - controller compatible with Exynos5800 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos5420.h header and can be used in device +tree sources. + +Example 1: An example of a clock controller node is listed below. + + clock: clock-controller@10010000 { + compatible = "samsung,exynos5420-clock"; + reg = <0x10010000 0x30000>; + #clock-cells = <1>; + }; + +Example 2: UART controller node that consumes the clock generated by the clock + controller. Refer to the standard clock bindings for information + about 'clocks' and 'clock-names' property. + + serial@13820000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13820000 0x100>; + interrupts = <0 54 0>; + clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>; + clock-names = "uart", "clk_uart_baud0"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos5433-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5433-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..50d5897c9849134cd9ebc30f5780de05ab5190e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos5433-clock.txt @@ -0,0 +1,484 @@ +* Samsung Exynos5433 CMU (Clock Management Units) + +The Exynos5433 clock controller generates and supplies clock to various +controllers within the Exynos5433 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,exynos5433-cmu-top" - clock controller compatible for CMU_TOP + which generates clocks for IMEM/FSYS/G3D/GSCL/HEVC/MSCL/G2D/MFC/PERIC/PERIS + domains and bus clocks. + - "samsung,exynos5433-cmu-cpif" - clock controller compatible for CMU_CPIF + which generates clocks for LLI (Low Latency Interface) IP. + - "samsung,exynos5433-cmu-mif" - clock controller compatible for CMU_MIF + which generates clocks for DRAM Memory Controller domain. + - "samsung,exynos5433-cmu-peric" - clock controller compatible for CMU_PERIC + which generates clocks for UART/I2C/SPI/I2S/PCM/SPDIF/PWM/SLIMBUS IPs. + - "samsung,exynos5433-cmu-peris" - clock controller compatible for CMU_PERIS + which generates clocks for PMU/TMU/MCT/WDT/RTC/SECKEY/TZPC IPs. + - "samsung,exynos5433-cmu-fsys" - clock controller compatible for CMU_FSYS + which generates clocks for USB/UFS/SDMMC/TSI/PDMA IPs. + - "samsung,exynos5433-cmu-g2d" - clock controller compatible for CMU_G2D + which generates clocks for G2D/MDMA IPs. + - "samsung,exynos5433-cmu-disp" - clock controller compatible for CMU_DISP + which generates clocks for Display (DECON/HDMI/DSIM/MIXER) IPs. + - "samsung,exynos5433-cmu-aud" - clock controller compatible for CMU_AUD + which generates clocks for Cortex-A5/BUS/AUDIO clocks. + - "samsung,exynos5433-cmu-bus0", "samsung,exynos5433-cmu-bus1" + and "samsung,exynos5433-cmu-bus2" - clock controller compatible for CMU_BUS + which generates global data buses clock and global peripheral buses clock. + - "samsung,exynos5433-cmu-g3d" - clock controller compatible for CMU_G3D + which generates clocks for 3D Graphics Engine IP. + - "samsung,exynos5433-cmu-gscl" - clock controller compatible for CMU_GSCL + which generates clocks for GSCALER IPs. + - "samsung,exynos5433-cmu-apollo"- clock controller compatible for CMU_APOLLO + which generates clocks for Cortex-A53 Quad-core processor. + - "samsung,exynos5433-cmu-atlas" - clock controller compatible for CMU_ATLAS + which generates clocks for Cortex-A57 Quad-core processor, CoreSight and + L2 cache controller. + - "samsung,exynos5433-cmu-mscl" - clock controller compatible for CMU_MSCL + which generates clocks for M2M (Memory to Memory) scaler and JPEG IPs. + - "samsung,exynos5433-cmu-mfc" - clock controller compatible for CMU_MFC + which generates clocks for MFC(Multi-Format Codec) IP. + - "samsung,exynos5433-cmu-hevc" - clock controller compatible for CMU_HEVC + which generates clocks for HEVC(High Efficiency Video Codec) decoder IP. + - "samsung,exynos5433-cmu-isp" - clock controller compatible for CMU_ISP + which generates clocks for FIMC-ISP/DRC/SCLC/DIS/3DNR IPs. + - "samsung,exynos5433-cmu-cam0" - clock controller compatible for CMU_CAM0 + which generates clocks for MIPI_CSIS{0|1}/FIMC_LITE_{A|B|D}/FIMC_3AA{0|1} + IPs. + - "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1 + which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +- clocks: list of the clock controller input clock identifiers, + from common clock bindings. Please refer the next section + to find the input clocks for a given controller. + +- clock-names: list of the clock controller input clock names, + as described in clock-bindings.txt. + + Input clocks for top clock controller: + - oscclk + - sclk_mphy_pll + - sclk_mfc_pll + - sclk_bus_pll + + Input clocks for cpif clock controller: + - oscclk + + Input clocks for mif clock controller: + - oscclk + - sclk_mphy_pll + + Input clocks for fsys clock controller: + - oscclk + - sclk_ufs_mphy + - aclk_fsys_200 + - sclk_pcie_100_fsys + - sclk_ufsunipro_fsys + - sclk_mmc2_fsys + - sclk_mmc1_fsys + - sclk_mmc0_fsys + - sclk_usbhost30_fsys + - sclk_usbdrd30_fsys + + Input clocks for g2d clock controller: + - oscclk + - aclk_g2d_266 + - aclk_g2d_400 + + Input clocks for disp clock controller: + - oscclk + - sclk_dsim1_disp + - sclk_dsim0_disp + - sclk_dsd_disp + - sclk_decon_tv_eclk_disp + - sclk_decon_vclk_disp + - sclk_decon_eclk_disp + - sclk_decon_tv_vclk_disp + - aclk_disp_333 + + Input clocks for audio clock controller: + - oscclk + - fout_aud_pll + + Input clocks for bus0 clock controller: + - aclk_bus0_400 + + Input clocks for bus1 clock controller: + - aclk_bus1_400 + + Input clocks for bus2 clock controller: + - oscclk + - aclk_bus2_400 + + Input clocks for g3d clock controller: + - oscclk + - aclk_g3d_400 + + Input clocks for gscl clock controller: + - oscclk + - aclk_gscl_111 + - aclk_gscl_333 + + Input clocks for apollo clock controller: + - oscclk + - sclk_bus_pll_apollo + + Input clocks for atlas clock controller: + - oscclk + - sclk_bus_pll_atlas + + Input clocks for mscl clock controller: + - oscclk + - sclk_jpeg_mscl + - aclk_mscl_400 + + Input clocks for mfc clock controller: + - oscclk + - aclk_mfc_400 + + Input clocks for hevc clock controller: + - oscclk + - aclk_hevc_400 + + Input clocks for isp clock controller: + - oscclk + - aclk_isp_dis_400 + - aclk_isp_400 + + Input clocks for cam0 clock controller: + - oscclk + - aclk_cam0_333 + - aclk_cam0_400 + - aclk_cam0_552 + + Input clocks for cam1 clock controller: + - oscclk + - sclk_isp_uart_cam1 + - sclk_isp_spi1_cam1 + - sclk_isp_spi0_cam1 + - aclk_cam1_333 + - aclk_cam1_400 + - aclk_cam1_552 + +Optional properties: + - power-domains: a phandle to respective power domain node as described by + generic PM domain bindings (see power/power_domain.txt for more + information). + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos5433.h header and can be used in device +tree sources. + +Example 1: Examples of 'oscclk' source clock node are listed below. + + xxti: xxti { + compatible = "fixed-clock"; + clock-output-names = "oscclk"; + #clock-cells = <0>; + }; + +Example 2: Examples of clock controller nodes are listed below. + + cmu_top: clock-controller@10030000 { + compatible = "samsung,exynos5433-cmu-top"; + reg = <0x10030000 0x0c04>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_mphy_pll", + "sclk_mfc_pll", + "sclk_bus_pll"; + clocks = <&xxti>, + <&cmu_cpif CLK_SCLK_MPHY_PLL>, + <&cmu_mif CLK_SCLK_MFC_PLL>, + <&cmu_mif CLK_SCLK_BUS_PLL>; + }; + + cmu_cpif: clock-controller@10fc0000 { + compatible = "samsung,exynos5433-cmu-cpif"; + reg = <0x10fc0000 0x0c04>; + #clock-cells = <1>; + + clock-names = "oscclk"; + clocks = <&xxti>; + }; + + cmu_mif: clock-controller@105b0000 { + compatible = "samsung,exynos5433-cmu-mif"; + reg = <0x105b0000 0x100c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_mphy_pll"; + clocks = <&xxti>, + <&cmu_cpif CLK_SCLK_MPHY_PLL>; + }; + + cmu_peric: clock-controller@14c80000 { + compatible = "samsung,exynos5433-cmu-peric"; + reg = <0x14c80000 0x0b08>; + #clock-cells = <1>; + }; + + cmu_peris: clock-controller@10040000 { + compatible = "samsung,exynos5433-cmu-peris"; + reg = <0x10040000 0x0b20>; + #clock-cells = <1>; + }; + + cmu_fsys: clock-controller@156e0000 { + compatible = "samsung,exynos5433-cmu-fsys"; + reg = <0x156e0000 0x0b04>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_ufs_mphy", + "aclk_fsys_200", + "sclk_pcie_100_fsys", + "sclk_ufsunipro_fsys", + "sclk_mmc2_fsys", + "sclk_mmc1_fsys", + "sclk_mmc0_fsys", + "sclk_usbhost30_fsys", + "sclk_usbdrd30_fsys"; + clocks = <&xxti>, + <&cmu_cpif CLK_SCLK_UFS_MPHY>, + <&cmu_top CLK_ACLK_FSYS_200>, + <&cmu_top CLK_SCLK_PCIE_100_FSYS>, + <&cmu_top CLK_SCLK_UFSUNIPRO_FSYS>, + <&cmu_top CLK_SCLK_MMC2_FSYS>, + <&cmu_top CLK_SCLK_MMC1_FSYS>, + <&cmu_top CLK_SCLK_MMC0_FSYS>, + <&cmu_top CLK_SCLK_USBHOST30_FSYS>, + <&cmu_top CLK_SCLK_USBDRD30_FSYS>; + }; + + cmu_g2d: clock-controller@12460000 { + compatible = "samsung,exynos5433-cmu-g2d"; + reg = <0x12460000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_g2d_266", + "aclk_g2d_400"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_G2D_266>, + <&cmu_top CLK_ACLK_G2D_400>; + power-domains = <&pd_g2d>; + }; + + cmu_disp: clock-controller@13b90000 { + compatible = "samsung,exynos5433-cmu-disp"; + reg = <0x13b90000 0x0c04>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_dsim1_disp", + "sclk_dsim0_disp", + "sclk_dsd_disp", + "sclk_decon_tv_eclk_disp", + "sclk_decon_vclk_disp", + "sclk_decon_eclk_disp", + "sclk_decon_tv_vclk_disp", + "aclk_disp_333"; + clocks = <&xxti>, + <&cmu_mif CLK_SCLK_DSIM1_DISP>, + <&cmu_mif CLK_SCLK_DSIM0_DISP>, + <&cmu_mif CLK_SCLK_DSD_DISP>, + <&cmu_mif CLK_SCLK_DECON_TV_ECLK_DISP>, + <&cmu_mif CLK_SCLK_DECON_VCLK_DISP>, + <&cmu_mif CLK_SCLK_DECON_ECLK_DISP>, + <&cmu_mif CLK_SCLK_DECON_TV_VCLK_DISP>, + <&cmu_mif CLK_ACLK_DISP_333>; + power-domains = <&pd_disp>; + }; + + cmu_aud: clock-controller@114c0000 { + compatible = "samsung,exynos5433-cmu-aud"; + reg = <0x114c0000 0x0b04>; + #clock-cells = <1>; + + clock-names = "oscclk", "fout_aud_pll"; + clocks = <&xxti>, <&cmu_top CLK_FOUT_AUD_PLL>; + power-domains = <&pd_aud>; + }; + + cmu_bus0: clock-controller@13600000 { + compatible = "samsung,exynos5433-cmu-bus0"; + reg = <0x13600000 0x0b04>; + #clock-cells = <1>; + + clock-names = "aclk_bus0_400"; + clocks = <&cmu_top CLK_ACLK_BUS0_400>; + }; + + cmu_bus1: clock-controller@14800000 { + compatible = "samsung,exynos5433-cmu-bus1"; + reg = <0x14800000 0x0b04>; + #clock-cells = <1>; + + clock-names = "aclk_bus1_400"; + clocks = <&cmu_top CLK_ACLK_BUS1_400>; + }; + + cmu_bus2: clock-controller@13400000 { + compatible = "samsung,exynos5433-cmu-bus2"; + reg = <0x13400000 0x0b04>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_bus2_400"; + clocks = <&xxti>, <&cmu_mif CLK_ACLK_BUS2_400>; + }; + + cmu_g3d: clock-controller@14aa0000 { + compatible = "samsung,exynos5433-cmu-g3d"; + reg = <0x14aa0000 0x1000>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_g3d_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_G3D_400>; + power-domains = <&pd_g3d>; + }; + + cmu_gscl: clock-controller@13cf0000 { + compatible = "samsung,exynos5433-cmu-gscl"; + reg = <0x13cf0000 0x0b10>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_gscl_111", + "aclk_gscl_333"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_GSCL_111>, + <&cmu_top CLK_ACLK_GSCL_333>; + power-domains = <&pd_gscl>; + }; + + cmu_apollo: clock-controller@11900000 { + compatible = "samsung,exynos5433-cmu-apollo"; + reg = <0x11900000 0x1088>; + #clock-cells = <1>; + + clock-names = "oscclk", "sclk_bus_pll_apollo"; + clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_APOLLO>; + }; + + cmu_atlas: clock-controller@11800000 { + compatible = "samsung,exynos5433-cmu-atlas"; + reg = <0x11800000 0x1088>; + #clock-cells = <1>; + + clock-names = "oscclk", "sclk_bus_pll_atlas"; + clocks = <&xxti>, <&cmu_mif CLK_SCLK_BUS_PLL_ATLAS>; + }; + + cmu_mscl: clock-controller@105d0000 { + compatible = "samsung,exynos5433-cmu-mscl"; + reg = <0x105d0000 0x0b10>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_jpeg_mscl", + "aclk_mscl_400"; + clocks = <&xxti>, + <&cmu_top CLK_SCLK_JPEG_MSCL>, + <&cmu_top CLK_ACLK_MSCL_400>; + power-domains = <&pd_mscl>; + }; + + cmu_mfc: clock-controller@15280000 { + compatible = "samsung,exynos5433-cmu-mfc"; + reg = <0x15280000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_mfc_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_MFC_400>; + power-domains = <&pd_mfc>; + }; + + cmu_hevc: clock-controller@14f80000 { + compatible = "samsung,exynos5433-cmu-hevc"; + reg = <0x14f80000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", "aclk_hevc_400"; + clocks = <&xxti>, <&cmu_top CLK_ACLK_HEVC_400>; + power-domains = <&pd_hevc>; + }; + + cmu_isp: clock-controller@146d0000 { + compatible = "samsung,exynos5433-cmu-isp"; + reg = <0x146d0000 0x0b0c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_isp_dis_400", + "aclk_isp_400"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_ISP_DIS_400>, + <&cmu_top CLK_ACLK_ISP_400>; + power-domains = <&pd_isp>; + }; + + cmu_cam0: clock-controller@120d0000 { + compatible = "samsung,exynos5433-cmu-cam0"; + reg = <0x120d0000 0x0b0c>; + #clock-cells = <1>; + + clock-names = "oscclk", + "aclk_cam0_333", + "aclk_cam0_400", + "aclk_cam0_552"; + clocks = <&xxti>, + <&cmu_top CLK_ACLK_CAM0_333>, + <&cmu_top CLK_ACLK_CAM0_400>, + <&cmu_top CLK_ACLK_CAM0_552>; + power-domains = <&pd_cam0>; + }; + + cmu_cam1: clock-controller@145d0000 { + compatible = "samsung,exynos5433-cmu-cam1"; + reg = <0x145d0000 0x0b08>; + #clock-cells = <1>; + + clock-names = "oscclk", + "sclk_isp_uart_cam1", + "sclk_isp_spi1_cam1", + "sclk_isp_spi0_cam1", + "aclk_cam1_333", + "aclk_cam1_400", + "aclk_cam1_552"; + clocks = <&xxti>, + <&cmu_top CLK_SCLK_ISP_UART_CAM1>, + <&cmu_top CLK_SCLK_ISP_SPI1_CAM1>, + <&cmu_top CLK_SCLK_ISP_SPI0_CAM1>, + <&cmu_top CLK_ACLK_CAM1_333>, + <&cmu_top CLK_ACLK_CAM1_400>, + <&cmu_top CLK_ACLK_CAM1_552>; + power-domains = <&pd_cam1>; + }; + +Example 3: UART controller node that consumes the clock generated by the clock + controller. + + serial_0: serial@14c10000 { + compatible = "samsung,exynos5433-uart"; + reg = <0x14C10000 0x100>; + interrupts = <0 421 0>; + clocks = <&cmu_peric CLK_PCLK_UART0>, + <&cmu_peric CLK_SCLK_UART0>; + clock-names = "uart", "clk_uart_baud0"; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_bus>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/exynos7-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/exynos7-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..6bf1e7493f61febb762a212d6306dcaa03fb00c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/exynos7-clock.txt @@ -0,0 +1,108 @@ +* Samsung Exynos7 Clock Controller + +Exynos7 clock controller has various blocks which are instantiated +independently from the device-tree. These clock controllers +generate and supply clocks to various hardware blocks within +the SoC. + +Each clock is assigned an identifier and client nodes can use +this identifier to specify the clock which they consume. All +available clocks are defined as preprocessor macros in +dt-bindings/clock/exynos7-clk.h header and can be used in +device tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It +is expected that they are defined using standard clock bindings +with following clock-output-names: + + - "fin_pll" - PLL input clock from XXTI + +Required Properties for Clock Controller: + + - compatible: clock controllers will use one of the following + compatible strings to indicate the clock controller + functionality. + + - "samsung,exynos7-clock-topc" + - "samsung,exynos7-clock-top0" + - "samsung,exynos7-clock-top1" + - "samsung,exynos7-clock-ccore" + - "samsung,exynos7-clock-peric0" + - "samsung,exynos7-clock-peric1" + - "samsung,exynos7-clock-peris" + - "samsung,exynos7-clock-fsys0" + - "samsung,exynos7-clock-fsys1" + - "samsung,exynos7-clock-mscl" + - "samsung,exynos7-clock-aud" + + - reg: physical base address of the controller and the length of + memory mapped region. + + - #clock-cells: should be 1. + + - clocks: list of clock identifiers which are fed as the input to + the given clock controller. Please refer the next section to + find the input clocks for a given controller. + +- clock-names: list of names of clocks which are fed as the input + to the given clock controller. + +Input clocks for top0 clock controller: + - fin_pll + - dout_sclk_bus0_pll + - dout_sclk_bus1_pll + - dout_sclk_cc_pll + - dout_sclk_mfc_pll + - dout_sclk_aud_pll + +Input clocks for top1 clock controller: + - fin_pll + - dout_sclk_bus0_pll + - dout_sclk_bus1_pll + - dout_sclk_cc_pll + - dout_sclk_mfc_pll + +Input clocks for ccore clock controller: + - fin_pll + - dout_aclk_ccore_133 + +Input clocks for peric0 clock controller: + - fin_pll + - dout_aclk_peric0_66 + - sclk_uart0 + +Input clocks for peric1 clock controller: + - fin_pll + - dout_aclk_peric1_66 + - sclk_uart1 + - sclk_uart2 + - sclk_uart3 + - sclk_spi0 + - sclk_spi1 + - sclk_spi2 + - sclk_spi3 + - sclk_spi4 + - sclk_i2s1 + - sclk_pcm1 + - sclk_spdif + +Input clocks for peris clock controller: + - fin_pll + - dout_aclk_peris_66 + +Input clocks for fsys0 clock controller: + - fin_pll + - dout_aclk_fsys0_200 + - dout_sclk_mmc2 + +Input clocks for fsys1 clock controller: + - fin_pll + - dout_aclk_fsys1_200 + - dout_sclk_mmc0 + - dout_sclk_mmc1 + +Input clocks for aud clock controller: + - fin_pll + - fout_aud_pll diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/fixed-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/fixed-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..0641a663ad692ef2697ac50199e1934adcfbdbad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/fixed-clock.txt @@ -0,0 +1,23 @@ +Binding for simple fixed-rate clock sources. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "fixed-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clock-frequency : frequency of clock in Hz. Should be a single cell. + +Optional properties: +- clock-accuracy : accuracy of clock in ppb (parts per billion). + Should be a single cell. +- clock-output-names : From common clock binding. + +Example: + clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000000>; + clock-accuracy = <100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/fixed-factor-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/fixed-factor-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..189467a7188af15fe16978839643b02cd217fd77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/fixed-factor-clock.txt @@ -0,0 +1,28 @@ +Binding for simple fixed factor rate clock sources. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "fixed-factor-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clock-div: fixed divider. +- clock-mult: fixed multiplier. +- clocks: parent clock. + +Optional properties: +- clock-output-names : From common clock binding. + +Some clocks that require special treatments are also handled by that +driver, with the compatibles: + - allwinner,sun4i-a10-pll3-2x-clk + +Example: + clock { + compatible = "fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + clock-div = <2>; + clock-mult = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/fujitsu,mb86s70-crg11.txt b/arch/arm64/boot/dts/vendor/bindings/clock/fujitsu,mb86s70-crg11.txt new file mode 100644 index 0000000000000000000000000000000000000000..33239626568920bb92f10efd6754fd4c3d7b7675 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/fujitsu,mb86s70-crg11.txt @@ -0,0 +1,26 @@ +Fujitsu CRG11 clock driver bindings +----------------------------------- + +Required properties : +- compatible : Shall contain "fujitsu,mb86s70-crg11" +- #clock-cells : Shall be 3 {cntrlr domain port} + +The consumer specifies the desired clock pointing to its phandle. + +Example: + + clock: crg11 { + compatible = "fujitsu,mb86s70-crg11"; + #clock-cells = <3>; + }; + + mhu: mhu0@2b1f0000 { + #mbox-cells = <1>; + compatible = "arm,mhu"; + reg = <0 0x2B1F0000 0x1000>; + interrupts = <0 36 4>, /* LP Non-Sec */ + <0 35 4>, /* HP Non-Sec */ + <0 37 4>; /* Secure */ + clocks = <&clock 0 2 1>; /* Cntrlr:0 Domain:2 Port:1 */ + clock-names = "clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/gpio-gate-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/gpio-gate-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3379ff9b84b120c9a2668e7a0ec8827ecc97965 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/gpio-gate-clock.txt @@ -0,0 +1,21 @@ +Binding for simple gpio gated clock. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "gpio-gate-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- enable-gpios : GPIO reference for enabling and disabling the clock. + +Optional properties: +- clocks: Maximum of one parent clock is supported. + +Example: + clock { + compatible = "gpio-gate-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + enable-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/gpio-mux-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/gpio-mux-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..2be1e038ca62907a3187afce23d46e2c7a62b639 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/gpio-mux-clock.txt @@ -0,0 +1,19 @@ +Binding for simple gpio clock multiplexer. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "gpio-mux-clock". +- clocks: list of two references to parent clocks. +- #clock-cells : from common clock binding; shall be set to 0. +- select-gpios : GPIO reference for selecting the parent clock. + +Example: + clock { + compatible = "gpio-mux-clock"; + clocks = <&parentclk1>, <&parentclk2>; + #clock-cells = <0>; + select-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/hi3620-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/hi3620-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..dad6269f52c5a6c6a2be5c7eb09aa1f4bcce9a9d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/hi3620-clock.txt @@ -0,0 +1,20 @@ +* Hisilicon Hi3620 Clock Controller + +The Hi3620 clock controller generates and supplies clock to various +controllers within the Hi3620 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC. + - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/hi3660-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/hi3660-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..946da7cee54f0d11c13086cb141b0d64b669b86c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/hi3660-clock.txt @@ -0,0 +1,47 @@ +* Hisilicon Hi3660 Clock Controller + +The Hi3660 clock controller generates and supplies clock to various +controllers within the Hi3660 SoC. + +Required Properties: + +- compatible: the compatible should be one of the following strings to + indicate the clock controller functionality. + + - "hisilicon,hi3660-crgctrl" + - "hisilicon,hi3660-pctrl" + - "hisilicon,hi3660-pmuctrl" + - "hisilicon,hi3660-sctrl" + - "hisilicon,hi3660-iomcu" + - "hisilicon,hi3660-stub-clk" + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Optional Properties: + +- mboxes: Phandle to the mailbox for sending message to MCU. + (See: ../mailbox/hisilicon,hi3660-mailbox.txt for more info) + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . + +Examples: + crg_ctrl: clock-controller@fff35000 { + compatible = "hisilicon,hi3660-crgctrl", "syscon"; + reg = <0x0 0xfff35000 0x0 0x1000>; + #clock-cells = <1>; + }; + + uart0: serial@fdf02000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xfdf02000 0x0 0x1000>; + interrupts = ; + clocks = <&crg_ctrl HI3660_CLK_MUX_UART0>, + <&crg_ctrl HI3660_PCLK>; + clock-names = "uartclk", "apb_pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/hi6220-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/hi6220-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef3deb7b86eaf18468a2b779c9b7786c92d158d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/hi6220-clock.txt @@ -0,0 +1,52 @@ +* Hisilicon Hi6220 Clock Controller + +Clock control registers reside in different Hi6220 system controllers, +please refer the following document to know more about the binding rules +for these system controllers: + +Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt + +Required Properties: + +- compatible: the compatible should be one of the following strings to + indicate the clock controller functionality. + + - "hisilicon,hi6220-acpu-sctrl" + - "hisilicon,hi6220-aoctrl" + - "hisilicon,hi6220-sysctrl" + - "hisilicon,hi6220-mediactrl" + - "hisilicon,hi6220-pmctrl" + - "hisilicon,hi6220-stub-clk" + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Optional Properties: + +- hisilicon,hi6220-clk-sram: phandle to the syscon managing the SoC internal sram; + the driver need use the sram to pass parameters for frequency change. + +- mboxes: use the label reference for the mailbox as the first parameter, the + second parameter is the channel number. + +Example 1: + sys_ctrl: sys_ctrl@f7030000 { + compatible = "hisilicon,hi6220-sysctrl", "syscon"; + reg = <0x0 0xf7030000 0x0 0x2000>; + #clock-cells = <1>; + }; + +Example 2: + stub_clock: stub_clock { + compatible = "hisilicon,hi6220-stub-clk"; + hisilicon,hi6220-clk-sram = <&sram>; + #clock-cells = <1>; + mboxes = <&mailbox 1>; + }; + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/hisi-crg.txt b/arch/arm64/boot/dts/vendor/bindings/clock/hisi-crg.txt new file mode 100644 index 0000000000000000000000000000000000000000..cc60b3d423f30916cd863fc938d19aa639f4643a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/hisi-crg.txt @@ -0,0 +1,50 @@ +* HiSilicon Clock and Reset Generator(CRG) + +The CRG module provides clock and reset signals to various +modules within the SoC. + +This binding uses the following bindings: + Documentation/devicetree/bindings/clock/clock-bindings.txt + Documentation/devicetree/bindings/reset/reset.txt + +Required Properties: + +- compatible: should be one of the following. + - "hisilicon,hi3516cv300-crg" + - "hisilicon,hi3516cv300-sysctrl" + - "hisilicon,hi3519-crg" + - "hisilicon,hi3798cv200-crg" + - "hisilicon,hi3798cv200-sysctrl" + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . + +- #reset-cells: should be 2. + +A reset signal can be controlled by writing a bit register in the CRG module. +The reset specifier consists of two cells. The first cell represents the +register offset relative to the base address. The second cell represents the +bit index in the register. + +Example: CRG nodes +CRG: clock-reset-controller@12010000 { + compatible = "hisilicon,hi3519-crg"; + reg = <0x12010000 0x10000>; + #clock-cells = <1>; + #reset-cells = <2>; +}; + +Example: consumer nodes +i2c0: i2c@12110000 { + compatible = "hisilicon,hi3519-i2c"; + reg = <0x12110000 0x1000>; + clocks = <&CRG HI3519_I2C0_RST>; + resets = <&CRG 0xe4 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/hix5hd2-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/hix5hd2-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..4733e58e491ba7e82cac0c5c41ba448b6fdb37d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/hix5hd2-clock.txt @@ -0,0 +1,30 @@ +* Hisilicon Hix5hd2 Clock Controller + +The hix5hd2 clock controller generates and supplies clock to various +controllers within the hix5hd2 SoC. + +Required Properties: + +- compatible: should be "hisilicon,hix5hd2-clock" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . + +Examples: + clock: clock@f8a22000 { + compatible = "hisilicon,hix5hd2-clock"; + reg = <0xf8a22000 0x1000>; + #clock-cells = <1>; + }; + + uart0: uart@f8b00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xf8b00000 0x1000>; + interrupts = <0 49 4>; + clocks = <&clock HIX5HD2_FIXED_83M>; + clock-names = "apb_pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/idt,versaclock5.txt b/arch/arm64/boot/dts/vendor/bindings/clock/idt,versaclock5.txt new file mode 100644 index 0000000000000000000000000000000000000000..05a245c9df08fe48738a1d3e27e6bd45711b4a50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/idt,versaclock5.txt @@ -0,0 +1,91 @@ +Binding for IDT VersaClock 5,6 programmable i2c clock generators. + +The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock +generators providing from 3 to 12 output clocks. + +==I2C device node== + +Required properties: +- compatible: shall be one of + "idt,5p49v5923" + "idt,5p49v5925" + "idt,5p49v5933" + "idt,5p49v5935" + "idt,5p49v6901" +- reg: i2c device address, shall be 0x68 or 0x6a. +- #clock-cells: from common clock binding; shall be set to 1. +- clocks: from common clock binding; list of parent clock handles, + - 5p49v5923 and + 5p49v5925 and + 5p49v6901: (required) either or both of XTAL or CLKIN + reference clock. + - 5p49v5933 and + - 5p49v5935: (optional) property not present (internal + Xtal used) or CLKIN reference + clock. +- clock-names: from common clock binding; clock input names, can be + - 5p49v5923 and + 5p49v5925 and + 5p49v6901: (required) either or both of "xin", "clkin". + - 5p49v5933 and + - 5p49v5935: (optional) property not present or "clkin". + +==Mapping between clock specifier and physical pins== + +When referencing the provided clock in the DT using phandle and +clock specifier, the following mapping applies: + +5P49V5923: + 0 -- OUT0_SEL_I2CB + 1 -- OUT1 + 2 -- OUT2 + +5P49V5933: + 0 -- OUT0_SEL_I2CB + 1 -- OUT1 + 2 -- OUT4 + +5P49V5925 and +5P49V5935: + 0 -- OUT0_SEL_I2CB + 1 -- OUT1 + 2 -- OUT2 + 3 -- OUT3 + 4 -- OUT4 + +5P49V6901: + 0 -- OUT0_SEL_I2CB + 1 -- OUT1 + 2 -- OUT2 + 3 -- OUT3 + 4 -- OUT4 + +==Example== + +/* 25MHz reference crystal */ +ref25: ref25m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; +}; + +i2c-master-node { + + /* IDT 5P49V5923 i2c clock generator */ + vc5: clock-generator@6a { + compatible = "idt,5p49v5923"; + reg = <0x6a>; + #clock-cells = <1>; + + /* Connect XIN input to 25MHz reference */ + clocks = <&ref25m>; + clock-names = "xin"; + }; +}; + +/* Consumer referencing the 5P49V5923 pin OUT1 */ +consumer { + ... + clocks = <&vc5 1>; + ... +} diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/img,boston-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/img,boston-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bc5e9ffb6244b5c38adaefe3880833425893912 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/img,boston-clock.txt @@ -0,0 +1,31 @@ +Binding for Imagination Technologies MIPS Boston clock sources. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +The device node must be a child node of the syscon node corresponding to the +Boston system's platform registers. + +Required properties: +- compatible : Should be "img,boston-clock". +- #clock-cells : Should be set to 1. + Values available for clock consumers can be found in the header file: + + +Example: + + system-controller@17ffd000 { + compatible = "img,boston-platform-regs", "syscon"; + reg = <0x17ffd000 0x1000>; + + clk_boston: clock { + compatible = "img,boston-clock"; + #clock-cells = <1>; + }; + }; + + uart0: uart@17ffe000 { + /* ... */ + clocks = <&clk_boston BOSTON_CLK_SYS>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx1-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx1-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..9823baf7acb645c8be7de75e37307af6a3cbc29c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx1-clock.txt @@ -0,0 +1,26 @@ +* Clock bindings for Freescale i.MX1 CPUs + +Required properties: +- compatible: Should be "fsl,imx1-ccm". +- reg: Address and length of the register set. +- #clock-cells: Should be <1>. + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx1-clock.h +for the full list of i.MX1 clock IDs. + +Examples: + clks: ccm@21b000 { + #clock-cells = <1>; + compatible = "fsl,imx1-ccm"; + reg = <0x0021b000 0x1000>; + }; + + pwm: pwm@208000 { + #pwm-cells = <2>; + compatible = "fsl,imx1-pwm"; + reg = <0x00208000 0x1000>; + interrupts = <34>; + clocks = <&clks IMX1_CLK_DUMMY>, <&clks IMX1_CLK_PER1>; + clock-names = "ipg", "per"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx21-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx21-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..806f63d628bdf8182fe6b974450804a31acd79e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx21-clock.txt @@ -0,0 +1,27 @@ +* Clock bindings for Freescale i.MX21 + +Required properties: +- compatible : Should be "fsl,imx21-ccm". +- reg : Address and length of the register set. +- interrupts : Should contain CCM interrupt. +- #clock-cells: Should be <1>. + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx21-clock.h +for the full list of i.MX21 clock IDs. + +Examples: + clks: ccm@10027000{ + compatible = "fsl,imx21-ccm"; + reg = <0x10027000 0x800>; + #clock-cells = <1>; + }; + + uart1: serial@1000a000 { + compatible = "fsl,imx21-uart"; + reg = <0x1000a000 0x1000>; + interrupts = <20>; + clocks = <&clks IMX21_CLK_UART1_IPG_GATE>, + <&clks IMX21_CLK_PER1>; + clock-names = "ipg", "per"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx23-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx23-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..8385348d3bd99f16db9bb3c13887edf8f83546a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx23-clock.txt @@ -0,0 +1,70 @@ +* Clock bindings for Freescale i.MX23 + +Required properties: +- compatible: Should be "fsl,imx23-clkctrl" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX23 +clocks and IDs. + + Clock ID + ------------------ + ref_xtal 0 + pll 1 + ref_cpu 2 + ref_emi 3 + ref_pix 4 + ref_io 5 + saif_sel 6 + lcdif_sel 7 + gpmi_sel 8 + ssp_sel 9 + emi_sel 10 + cpu 11 + etm_sel 12 + cpu_pll 13 + cpu_xtal 14 + hbus 15 + xbus 16 + lcdif_div 17 + ssp_div 18 + gpmi_div 19 + emi_pll 20 + emi_xtal 21 + etm_div 22 + saif_div 23 + clk32k_div 24 + rtc 25 + adc 26 + spdif_div 27 + clk32k 28 + dri 29 + pwm 30 + filt 31 + uart 32 + ssp 33 + gpmi 34 + spdif 35 + emi 36 + saif 37 + lcdif 38 + etm 39 + usb 40 + usb_phy 41 + +Examples: + +clks: clkctrl@80040000 { + compatible = "fsl,imx23-clkctrl"; + reg = <0x80040000 0x2000>; + #clock-cells = <1>; +}; + +auart0: serial@8006c000 { + compatible = "fsl,imx23-auart"; + reg = <0x8006c000 0x2000>; + interrupts = <24 25 23>; + clocks = <&clks 32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx25-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx25-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8135ea9ca4e2a371e95d12e5dcebccd40b3989a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx25-clock.txt @@ -0,0 +1,160 @@ +* Clock bindings for Freescale i.MX25 + +Required properties: +- compatible: Should be "fsl,imx25-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX25 +clocks and IDs. + + Clock ID + --------------------------- + dummy 0 + osc 1 + mpll 2 + upll 3 + mpll_cpu_3_4 4 + cpu_sel 5 + cpu 6 + ahb 7 + usb_div 8 + ipg 9 + per0_sel 10 + per1_sel 11 + per2_sel 12 + per3_sel 13 + per4_sel 14 + per5_sel 15 + per6_sel 16 + per7_sel 17 + per8_sel 18 + per9_sel 19 + per10_sel 20 + per11_sel 21 + per12_sel 22 + per13_sel 23 + per14_sel 24 + per15_sel 25 + per0 26 + per1 27 + per2 28 + per3 29 + per4 30 + per5 31 + per6 32 + per7 33 + per8 34 + per9 35 + per10 36 + per11 37 + per12 38 + per13 39 + per14 40 + per15 41 + csi_ipg_per 42 + epit_ipg_per 43 + esai_ipg_per 44 + esdhc1_ipg_per 45 + esdhc2_ipg_per 46 + gpt_ipg_per 47 + i2c_ipg_per 48 + lcdc_ipg_per 49 + nfc_ipg_per 50 + owire_ipg_per 51 + pwm_ipg_per 52 + sim1_ipg_per 53 + sim2_ipg_per 54 + ssi1_ipg_per 55 + ssi2_ipg_per 56 + uart_ipg_per 57 + ata_ahb 58 + reserved 59 + csi_ahb 60 + emi_ahb 61 + esai_ahb 62 + esdhc1_ahb 63 + esdhc2_ahb 64 + fec_ahb 65 + lcdc_ahb 66 + rtic_ahb 67 + sdma_ahb 68 + slcdc_ahb 69 + usbotg_ahb 70 + reserved 71 + reserved 72 + reserved 73 + reserved 74 + can1_ipg 75 + can2_ipg 76 + csi_ipg 77 + cspi1_ipg 78 + cspi2_ipg 79 + cspi3_ipg 80 + dryice_ipg 81 + ect_ipg 82 + epit1_ipg 83 + epit2_ipg 84 + reserved 85 + esdhc1_ipg 86 + esdhc2_ipg 87 + fec_ipg 88 + reserved 89 + reserved 90 + reserved 91 + gpt1_ipg 92 + gpt2_ipg 93 + gpt3_ipg 94 + gpt4_ipg 95 + reserved 96 + reserved 97 + reserved 98 + iim_ipg 99 + reserved 100 + reserved 101 + kpp_ipg 102 + lcdc_ipg 103 + reserved 104 + pwm1_ipg 105 + pwm2_ipg 106 + pwm3_ipg 107 + pwm4_ipg 108 + rngb_ipg 109 + reserved 110 + scc_ipg 111 + sdma_ipg 112 + sim1_ipg 113 + sim2_ipg 114 + slcdc_ipg 115 + spba_ipg 116 + ssi1_ipg 117 + ssi2_ipg 118 + tsc_ipg 119 + uart1_ipg 120 + uart2_ipg 121 + uart3_ipg 122 + uart4_ipg 123 + uart5_ipg 124 + reserved 125 + wdt_ipg 126 + cko_div 127 + cko_sel 128 + cko 129 + +Examples: + +clks: ccm@53f80000 { + compatible = "fsl,imx25-ccm"; + reg = <0x53f80000 0x4000>; + interrupts = <31>; +}; + +uart1: serial@43f90000 { + compatible = "fsl,imx25-uart", "fsl,imx21-uart"; + reg = <0x43f90000 0x4000>; + interrupts = <45>; + clocks = <&clks 79>, <&clks 50>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx27-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx27-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c95c048d3b294c154d0f2f7e0c1eb27fed01e14 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx27-clock.txt @@ -0,0 +1,27 @@ +* Clock bindings for Freescale i.MX27 + +Required properties: +- compatible: Should be "fsl,imx27-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx27-clock.h +for the full list of i.MX27 clock IDs. + +Examples: + clks: ccm@10027000{ + compatible = "fsl,imx27-ccm"; + reg = <0x10027000 0x1000>; + #clock-cells = <1>; + }; + + uart1: serial@1000a000 { + compatible = "fsl,imx27-uart", "fsl,imx21-uart"; + reg = <0x1000a000 0x1000>; + interrupts = <20>; + clocks = <&clks IMX27_CLK_UART1_IPG_GATE>, + <&clks IMX27_CLK_PER1_GATE>; + clock-names = "ipg", "per"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx28-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx28-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..d84a37d2885f6d2637e5285a9f69e904835287cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx28-clock.txt @@ -0,0 +1,93 @@ +* Clock bindings for Freescale i.MX28 + +Required properties: +- compatible: Should be "fsl,imx28-clkctrl" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX28 +clocks and IDs. + + Clock ID + ------------------ + ref_xtal 0 + pll0 1 + pll1 2 + pll2 3 + ref_cpu 4 + ref_emi 5 + ref_io0 6 + ref_io1 7 + ref_pix 8 + ref_hsadc 9 + ref_gpmi 10 + saif0_sel 11 + saif1_sel 12 + gpmi_sel 13 + ssp0_sel 14 + ssp1_sel 15 + ssp2_sel 16 + ssp3_sel 17 + emi_sel 18 + etm_sel 19 + lcdif_sel 20 + cpu 21 + ptp_sel 22 + cpu_pll 23 + cpu_xtal 24 + hbus 25 + xbus 26 + ssp0_div 27 + ssp1_div 28 + ssp2_div 29 + ssp3_div 30 + gpmi_div 31 + emi_pll 32 + emi_xtal 33 + lcdif_div 34 + etm_div 35 + ptp 36 + saif0_div 37 + saif1_div 38 + clk32k_div 39 + rtc 40 + lradc 41 + spdif_div 42 + clk32k 43 + pwm 44 + uart 45 + ssp0 46 + ssp1 47 + ssp2 48 + ssp3 49 + gpmi 50 + spdif 51 + emi 52 + saif0 53 + saif1 54 + lcdif 55 + etm 56 + fec 57 + can0 58 + can1 59 + usb0 60 + usb1 61 + usb0_phy 62 + usb1_phy 63 + enet_out 64 + +Examples: + +clks: clkctrl@80040000 { + compatible = "fsl,imx28-clkctrl"; + reg = <0x80040000 0x2000>; + #clock-cells = <1>; +}; + +auart0: serial@8006a000 { + compatible = "fsl,imx28-auart", "fsl,imx23-auart"; + reg = <0x8006a000 0x2000>; + interrupts = <112 70 71>; + clocks = <&clks 45>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx31-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx31-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a291090e56265090f0284b0a7823b8fb790780e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx31-clock.txt @@ -0,0 +1,90 @@ +* Clock bindings for Freescale i.MX31 + +Required properties: +- compatible: Should be "fsl,imx31-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX31 +clocks and IDs. + + Clock ID + ----------------------- + dummy 0 + ckih 1 + ckil 2 + mpll 3 + spll 4 + upll 5 + mcu_main 6 + hsp 7 + ahb 8 + nfc 9 + ipg 10 + per_div 11 + per 12 + csi_sel 13 + fir_sel 14 + csi_div 15 + usb_div_pre 16 + usb_div_post 17 + fir_div_pre 18 + fir_div_post 19 + sdhc1_gate 20 + sdhc2_gate 21 + gpt_gate 22 + epit1_gate 23 + epit2_gate 24 + iim_gate 25 + ata_gate 26 + sdma_gate 27 + cspi3_gate 28 + rng_gate 29 + uart1_gate 30 + uart2_gate 31 + ssi1_gate 32 + i2c1_gate 33 + i2c2_gate 34 + i2c3_gate 35 + hantro_gate 36 + mstick1_gate 37 + mstick2_gate 38 + csi_gate 39 + rtc_gate 40 + wdog_gate 41 + pwm_gate 42 + sim_gate 43 + ect_gate 44 + usb_gate 45 + kpp_gate 46 + ipu_gate 47 + uart3_gate 48 + uart4_gate 49 + uart5_gate 50 + owire_gate 51 + ssi2_gate 52 + cspi1_gate 53 + cspi2_gate 54 + gacc_gate 55 + emi_gate 56 + rtic_gate 57 + firi_gate 58 + +Examples: + +clks: ccm@53f80000{ + compatible = "fsl,imx31-ccm"; + reg = <0x53f80000 0x4000>; + interrupts = <31>, <53>; + #clock-cells = <1>; +}; + +uart1: serial@43f90000 { + compatible = "fsl,imx31-uart", "fsl,imx21-uart"; + reg = <0x43f90000 0x4000>; + interrupts = <45>; + clocks = <&clks 10>, <&clks 30>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx35-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx35-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..f49783213c56aa8d63f55f9730573e855654ea39 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx35-clock.txt @@ -0,0 +1,114 @@ +* Clock bindings for Freescale i.MX35 + +Required properties: +- compatible: Should be "fsl,imx35-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of i.MX35 +clocks and IDs. + + Clock ID + --------------------------- + ckih 0 + mpll 1 + ppll 2 + mpll_075 3 + arm 4 + hsp 5 + hsp_div 6 + hsp_sel 7 + ahb 8 + ipg 9 + arm_per_div 10 + ahb_per_div 11 + ipg_per 12 + uart_sel 13 + uart_div 14 + esdhc_sel 15 + esdhc1_div 16 + esdhc2_div 17 + esdhc3_div 18 + spdif_sel 19 + spdif_div_pre 20 + spdif_div_post 21 + ssi_sel 22 + ssi1_div_pre 23 + ssi1_div_post 24 + ssi2_div_pre 25 + ssi2_div_post 26 + usb_sel 27 + usb_div 28 + nfc_div 29 + asrc_gate 30 + pata_gate 31 + audmux_gate 32 + can1_gate 33 + can2_gate 34 + cspi1_gate 35 + cspi2_gate 36 + ect_gate 37 + edio_gate 38 + emi_gate 39 + epit1_gate 40 + epit2_gate 41 + esai_gate 42 + esdhc1_gate 43 + esdhc2_gate 44 + esdhc3_gate 45 + fec_gate 46 + gpio1_gate 47 + gpio2_gate 48 + gpio3_gate 49 + gpt_gate 50 + i2c1_gate 51 + i2c2_gate 52 + i2c3_gate 53 + iomuxc_gate 54 + ipu_gate 55 + kpp_gate 56 + mlb_gate 57 + mshc_gate 58 + owire_gate 59 + pwm_gate 60 + rngc_gate 61 + rtc_gate 62 + rtic_gate 63 + scc_gate 64 + sdma_gate 65 + spba_gate 66 + spdif_gate 67 + ssi1_gate 68 + ssi2_gate 69 + uart1_gate 70 + uart2_gate 71 + uart3_gate 72 + usbotg_gate 73 + wdog_gate 74 + max_gate 75 + admux_gate 76 + csi_gate 77 + csi_div 78 + csi_sel 79 + iim_gate 80 + gpu2d_gate 81 + ckli_gate 82 + +Examples: + +clks: ccm@53f80000 { + compatible = "fsl,imx35-ccm"; + reg = <0x53f80000 0x4000>; + interrupts = <31>; + #clock-cells = <1>; +}; + +esdhc1: esdhc@53fb4000 { + compatible = "fsl,imx35-esdhc"; + reg = <0x53fb4000 0x4000>; + interrupts = <7>; + clocks = <&clks 9>, <&clks 8>, <&clks 43>; + clock-names = "ipg", "ahb", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx5-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx5-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..a24ca9e582d2768380fef60819eb2e8820e6688c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx5-clock.txt @@ -0,0 +1,28 @@ +* Clock bindings for Freescale i.MX5 + +Required properties: +- compatible: Should be "fsl,-ccm" , where can be imx51 or imx53 +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx5-clock.h +for the full list of i.MX5 clock IDs. + +Examples (for mx53): + +clks: ccm@53fd4000{ + compatible = "fsl,imx53-ccm"; + reg = <0x53fd4000 0x4000>; + interrupts = <0 71 0x04 0 72 0x04>; + #clock-cells = <1>; +}; + +can1: can@53fc8000 { + compatible = "fsl,imx53-flexcan", "fsl,p1010-flexcan"; + reg = <0x53fc8000 0x4000>; + interrupts = <82>; + clocks = <&clks IMX5_CLK_CAN1_IPG_GATE>, <&clks IMX5_CLK_CAN1_SERIAL_GATE>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx6q-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx6q-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..a45ca67a9d5f26f72844e9cee49ffd434f9cd9c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx6q-clock.txt @@ -0,0 +1,30 @@ +* Clock bindings for Freescale i.MX6 Quad + +Required properties: +- compatible: Should be "fsl,imx6q-ccm" +- reg: Address and length of the register set +- interrupts: Should contain CCM interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6qdl-clock.h +for the full list of i.MX6 Quad and DualLite clock IDs. + +Examples: + +#include + +clks: ccm@20c4000 { + compatible = "fsl,imx6q-ccm"; + reg = <0x020c4000 0x4000>; + interrupts = <0 87 0x04 0 88 0x04>; + #clock-cells = <1>; +}; + +uart1: serial@2020000 { + compatible = "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; + interrupts = <0 26 0x04>; + clocks = <&clks IMX6QDL_CLK_UART_IPG>, <&clks IMX6QDL_CLK_UART_SERIAL>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx6sl-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx6sl-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..15e40bdf147d43afaf2d9ac144aa044e83edc08f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx6sl-clock.txt @@ -0,0 +1,10 @@ +* Clock bindings for Freescale i.MX6 SoloLite + +Required properties: +- compatible: Should be "fsl,imx6sl-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sl-clock.h +for the full list of i.MX6 SoloLite clock IDs. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx6sll-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx6sll-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..fee849d5fdd13ad26005c79f82258340c7000f8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx6sll-clock.txt @@ -0,0 +1,36 @@ +* Clock bindings for Freescale i.MX6 SLL + +Required properties: +- compatible: Should be "fsl,imx6sll-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include entries "ckil", "osc", "ipp_di0" and "ipp_di1" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sll-clock.h +for the full list of i.MX6 SLL clock IDs. + +Examples: + +#include + +clks: clock-controller@20c4000 { + compatible = "fsl,imx6sll-ccm"; + reg = <0x020c4000 0x4000>; + interrupts = , + ; + #clock-cells = <1>; + clocks = <&ckil>, <&osc>, <&ipp_di0>, <&ipp_di1>; + clock-names = "ckil", "osc", "ipp_di0", "ipp_di1"; +}; + +uart1: serial@2020000 { + compatible = "fsl,imx6sl-uart", "fsl,imx6q-uart", "fsl,imx21-uart"; + reg = <0x02020000 0x4000>; + interrupts = ; + clocks = <&clks IMX6SLL_CLK_UART1_IPG>, + <&clks IMX6SLL_CLK_UART1_SERIAL>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx6sx-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx6sx-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..22362b9b7ba31f3f63a9bd2c0758ad3451d14569 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx6sx-clock.txt @@ -0,0 +1,13 @@ +* Clock bindings for Freescale i.MX6 SoloX + +Required properties: +- compatible: Should be "fsl,imx6sx-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include entries "ckil", "osc", "ipp_di0" and "ipp_di1" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6sx-clock.h +for the full list of i.MX6 SoloX clock IDs. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx6ul-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx6ul-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..571d5039f663aa9c894331adb473e1adcfaa2f42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx6ul-clock.txt @@ -0,0 +1,13 @@ +* Clock bindings for Freescale i.MX6 UltraLite + +Required properties: +- compatible: Should be "fsl,imx6ul-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include entries "ckil", "osc", "ipp_di0" and "ipp_di1" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx6ul-clock.h +for the full list of i.MX6 UltraLite clock IDs. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/imx7d-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/imx7d-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d3026d81a68d2bf4f94b4bcada5a07c3b7dc7d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/imx7d-clock.txt @@ -0,0 +1,13 @@ +* Clock bindings for Freescale i.MX7 Dual + +Required properties: +- compatible: Should be "fsl,imx7d-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include entries "ckil", "osc" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx7d-clock.h +for the full list of i.MX7 Dual clock IDs. diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ingenic,cgu.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ingenic,cgu.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8d4134ae4095682182be5313148ddb2394ec017 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ingenic,cgu.txt @@ -0,0 +1,53 @@ +Ingenic SoC CGU binding + +The CGU in an Ingenic SoC provides all the clocks generated on-chip. It +typically includes a variety of PLLs, multiplexers, dividers & gates in order +to provide many different clock signals derived from only 2 external source +clocks. + +Required properties: +- compatible : Should be "ingenic,-cgu". + For example "ingenic,jz4740-cgu" or "ingenic,jz4780-cgu". +- reg : The address & length of the CGU registers. +- clocks : List of phandle & clock specifiers for clocks external to the CGU. + Two such external clocks should be specified - first the external crystal + "ext" and second the RTC clock source "rtc". +- clock-names : List of name strings for the external clocks. +- #clock-cells: Should be 1. + Clock consumers specify this argument to identify a clock. The valid values + may be found in -cgu.h>. + +Example SoC include file: + +/ { + cgu: jz4740-cgu { + compatible = "ingenic,jz4740-cgu"; + reg = <0x10000000 0x100>; + #clock-cells = <1>; + }; + + uart0: serial@10030000 { + clocks = <&cgu JZ4740_CLK_UART0>; + }; +}; + +Example board file: + +/ { + ext: clock@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + rtc: clock@1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + &cgu { + clocks = <&ext> <&rtc>; + clock-names: "ext", "rtc"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/intc_stratix10.txt b/arch/arm64/boot/dts/vendor/bindings/clock/intc_stratix10.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f4ec5cb5c6b0764d0fee3661cb718be8879a98e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/intc_stratix10.txt @@ -0,0 +1,20 @@ +Device Tree Clock bindings for Intel's SoCFPGA Stratix10 platform + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be + "intel,stratix10-clkmgr" + +- reg : shall be the control register offset from CLOCK_MANAGER's base for the clock. + +- #clock-cells : from common clock binding, shall be set to 1. + +Example: + clkmgr: clock-controller@ffd10000 { + compatible = "intel,stratix10-clkmgr"; + reg = <0xffd10000 0x1000>; + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/keystone-gate.txt b/arch/arm64/boot/dts/vendor/bindings/clock/keystone-gate.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5aa187026e3a53e1f1638f8808530cc5920df03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/keystone-gate.txt @@ -0,0 +1,29 @@ +Status: Unstable - ABI compatibility may be broken in the future + +Binding for Keystone gate control driver which uses PSC controller IP. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,keystone,psc-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : parent clock phandle +- reg : psc control and domain address address space +- reg-names : psc control and domain registers +- domain-id : psc domain id needed to check the transition state register + +Optional properties: +- clock-output-names : From common clock binding to override the + default output clock name +Example: + clkusb: clkusb { + #clock-cells = <0>; + compatible = "ti,keystone,psc-clock"; + clocks = <&chipclk16>; + clock-output-names = "usb"; + reg = <0x02350008 0xb00>, <0x02350000 0x400>; + reg-names = "control", "domain"; + domain-id = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/keystone-pll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/keystone-pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..47570d20721599a1c68e950ebf5598e913f0c8a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/keystone-pll.txt @@ -0,0 +1,84 @@ +Status: Unstable - ABI compatibility may be broken in the future + +Binding for keystone PLLs. The main PLL IP typically has a multiplier, +a divider and a post divider. The additional PLL IPs like ARMPLL, DDRPLL +and PAPLL are controlled by the memory mapped register where as the Main +PLL is controlled by a PLL controller registers along with memory mapped +registers. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- #clock-cells : from common clock binding; shall be set to 0. +- compatible : shall be "ti,keystone,main-pll-clock" or "ti,keystone,pll-clock" +- clocks : parent clock phandle +- reg - pll control0 and pll multipler registers +- reg-names : control, multiplier and post-divider. The multiplier and + post-divider registers are applicable only for main pll clock +- fixed-postdiv : fixed post divider value. If absent, use clkod register bits + for postdiv + +Example: + mainpllclk: mainpllclk@2310110 { + #clock-cells = <0>; + compatible = "ti,keystone,main-pll-clock"; + clocks = <&refclksys>; + reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>; + reg-names = "control", "multiplier", "post-divider"; + fixed-postdiv = <2>; + }; + + papllclk: papllclk@2620358 { + #clock-cells = <0>; + compatible = "ti,keystone,pll-clock"; + clocks = <&refclkpass>; + clock-output-names = "pa-pll-clk"; + reg = <0x02620358 4>; + reg-names = "control"; + }; + +Required properties: +- #clock-cells : from common clock binding; shall be set to 0. +- compatible : shall be "ti,keystone,pll-mux-clock" +- clocks : link phandles of parent clocks +- reg - pll mux register +- bit-shift : number of bits to shift the bit-mask +- bit-mask : arbitrary bitmask for programming the mux + +Optional properties: +- clock-output-names : From common clock binding. + +Example: + mainmuxclk: mainmuxclk@2310108 { + #clock-cells = <0>; + compatible = "ti,keystone,pll-mux-clock"; + clocks = <&mainpllclk>, <&refclkmain>; + reg = <0x02310108 4>; + bit-shift = <23>; + bit-mask = <1>; + clock-output-names = "mainmuxclk"; + }; + +Required properties: +- #clock-cells : from common clock binding; shall be set to 0. +- compatible : shall be "ti,keystone,pll-divider-clock" +- clocks : parent clock phandle +- reg - pll mux register +- bit-shift : number of bits to shift the bit-mask +- bit-mask : arbitrary bitmask for programming the divider + +Optional properties: +- clock-output-names : From common clock binding. + +Example: + gemtraceclk: gemtraceclk@2310120 { + #clock-cells = <0>; + compatible = "ti,keystone,pll-divider-clock"; + clocks = <&mainmuxclk>; + reg = <0x02310120 4>; + bit-shift = <0>; + bit-mask = <8>; + clock-output-names = "gemtraceclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-ccu.txt b/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-ccu.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa97c12014ac0d7698f1fdb811010d2fe42d57cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-ccu.txt @@ -0,0 +1,77 @@ +* NXP LPC1850 Clock Control Unit (CCU) + +Each CGU base clock has several clock branches which can be turned on +or off independently by the Clock Control Units CCU1 or CCU2. The +branch clocks are distributed between CCU1 and CCU2. + + - Above text taken from NXP LPC1850 User Manual. + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: + Should be "nxp,lpc1850-ccu" +- reg: + Shall define the base and range of the address space + containing clock control registers +- #clock-cells: + Shall have value <1>. The permitted clock-specifier values + are the branch clock names defined in table below. +- clocks: + Shall contain a list of phandles for the base clocks routed + from the CGU to the specific CCU. See mapping of base clocks + and CCU in table below. +- clock-names: + Shall contain a list of names for the base clock routed + from the CGU to the specific CCU. Valid CCU clock names: + "base_usb0_clk", "base_periph_clk", "base_usb1_clk", + "base_cpu_clk", "base_spifi_clk", "base_spi_clk", + "base_apb1_clk", "base_apb3_clk", "base_adchs_clk", + "base_sdio_clk", "base_ssp0_clk", "base_ssp1_clk", + "base_uart0_clk", "base_uart1_clk", "base_uart2_clk", + "base_uart3_clk", "base_audio_clk" + +Which branch clocks that are available on the CCU depends on the +specific LPC part. Check the user manual for your specific part. + +A list of CCU clocks can be found in dt-bindings/clock/lpc18xx-ccu.h. + +Example board file: + +soc { + ccu1: clock-controller@40051000 { + compatible = "nxp,lpc1850-ccu"; + reg = <0x40051000 0x1000>; + #clock-cells = <1>; + clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>, + <&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>, + <&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>, + <&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>; + clock-names = "base_apb3_clk", "base_apb1_clk", + "base_spifi_clk", "base_cpu_clk", + "base_periph_clk", "base_usb0_clk", + "base_usb1_clk", "base_spi_clk"; + }; + + ccu2: clock-controller@40052000 { + compatible = "nxp,lpc1850-ccu"; + reg = <0x40052000 0x1000>; + #clock-cells = <1>; + clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>, + <&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>, + <&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>, + <&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>; + clock-names = "base_audio_clk", "base_uart3_clk", + "base_uart2_clk", "base_uart1_clk", + "base_uart0_clk", "base_ssp1_clk", + "base_ssp0_clk", "base_sdio_clk"; + }; + + /* A user of CCU brach clocks */ + uart1: serial@40082000 { + ... + clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-cgu.txt b/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-cgu.txt new file mode 100644 index 0000000000000000000000000000000000000000..2cc32a9a945a7fa8446a223e20225f839296e712 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-cgu.txt @@ -0,0 +1,131 @@ +* NXP LPC1850 Clock Generation Unit (CGU) + +The CGU generates multiple independent clocks for the core and the +peripheral blocks of the LPC18xx. Each independent clock is called +a base clock and itself is one of the inputs to the two Clock +Control Units (CCUs) which control the branch clocks to the +individual peripherals. + +The CGU selects the inputs to the clock generators from multiple +clock sources, controls the clock generation, and routes the outputs +of the clock generators through the clock source bus to the output +stages. Each output stage provides an independent clock source and +corresponds to one of the base clocks for the LPC18xx. + + - Above text taken from NXP LPC1850 User Manual. + + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: + Should be "nxp,lpc1850-cgu" +- reg: + Shall define the base and range of the address space + containing clock control registers +- #clock-cells: + Shall have value <1>. The permitted clock-specifier values + are the base clock numbers defined below. +- clocks: + Shall contain a list of phandles for the external input + sources to the CGU. The list shall be in the following + order: xtal, 32khz, enet_rx_clk, enet_tx_clk, gp_clkin. +- clock-indices: + Shall be an ordered list of numbers defining the base clock + number provided by the CGU. +- clock-output-names: + Shall be an ordered list of strings defining the names of + the clocks provided by the CGU. + +Which base clocks that are available on the CGU depends on the +specific LPC part. Base clocks are numbered from 0 to 27. + +Number: Name: Description: + 0 BASE_SAFE_CLK Base safe clock (always on) for WWDT + 1 BASE_USB0_CLK Base clock for USB0 + 2 BASE_PERIPH_CLK Base clock for Cortex-M0SUB subsystem, + SPI, and SGPIO + 3 BASE_USB1_CLK Base clock for USB1 + 4 BASE_CPU_CLK System base clock for ARM Cortex-M core + and APB peripheral blocks #0 and #2 + 5 BASE_SPIFI_CLK Base clock for SPIFI + 6 BASE_SPI_CLK Base clock for SPI + 7 BASE_PHY_RX_CLK Base clock for Ethernet PHY Receive clock + 8 BASE_PHY_TX_CLK Base clock for Ethernet PHY Transmit clock + 9 BASE_APB1_CLK Base clock for APB peripheral block # 1 +10 BASE_APB3_CLK Base clock for APB peripheral block # 3 +11 BASE_LCD_CLK Base clock for LCD +12 BASE_ADCHS_CLK Base clock for ADCHS +13 BASE_SDIO_CLK Base clock for SD/MMC +14 BASE_SSP0_CLK Base clock for SSP0 +15 BASE_SSP1_CLK Base clock for SSP1 +16 BASE_UART0_CLK Base clock for UART0 +17 BASE_UART1_CLK Base clock for UART1 +18 BASE_UART2_CLK Base clock for UART2 +19 BASE_UART3_CLK Base clock for UART3 +20 BASE_OUT_CLK Base clock for CLKOUT pin +24-21 - Reserved +25 BASE_AUDIO_CLK Base clock for audio system (I2S) +26 BASE_CGU_OUT0_CLK Base clock for CGU_OUT0 clock output +27 BASE_CGU_OUT1_CLK Base clock for CGU_OUT1 clock output + +BASE_PERIPH_CLK and BASE_SPI_CLK is only available on LPC43xx. +BASE_ADCHS_CLK is only available on LPC4370. + + +Example board file: + +/ { + clocks { + xtal: xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + xtal32: xtal32 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + + enet_rx_clk: enet_rx_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "enet_rx_clk"; + }; + + enet_tx_clk: enet_tx_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "enet_tx_clk"; + }; + + gp_clkin: gp_clkin { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "gp_clkin"; + }; + }; + + soc { + cgu: clock-controller@40050000 { + compatible = "nxp,lpc1850-cgu"; + reg = <0x40050000 0x1000>; + #clock-cells = <1>; + clocks = <&xtal>, <&creg_clk 1>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>; + }; + + /* A CGU and CCU clock consumer */ + lcdc: lcdc@40008000 { + ... + clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>; + clock-names = "clcdclk", "apb_pclk"; + ... + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-creg-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-creg-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f1c7b4e4d2ca8419db996e105b86fd855cce173 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/lpc1850-creg-clk.txt @@ -0,0 +1,52 @@ +* NXP LPC1850 CREG clocks + +The NXP LPC18xx/43xx CREG (Configuration Registers) block contains +control registers for two low speed clocks. One of the clocks is a +32 kHz oscillator driver with power up/down and clock gating. Next +is a fixed divider that creates a 1 kHz clock from the 32 kHz osc. + +These clocks are used by the RTC and the Event Router peripherials. +The 32 kHz can also be routed to other peripherials to enable low +power modes. + +This binding uses the common clock binding: + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: + Should be "nxp,lpc1850-creg-clk" +- #clock-cells: + Shall have value <1>. +- clocks: + Shall contain a phandle to the fixed 32 kHz crystal. + +The creg-clk node must be a child of the creg syscon node. + +The following clocks are available from the clock node. + +Clock ID Name + 0 1 kHz clock + 1 32 kHz Oscillator + +Example: +soc { + creg: syscon@40043000 { + compatible = "nxp,lpc1850-creg", "syscon", "simple-mfd"; + reg = <0x40043000 0x1000>; + + creg_clk: clock-controller { + compatible = "nxp,lpc1850-creg-clk"; + clocks = <&xtal32>; + #clock-cells = <1>; + }; + + ... + }; + + rtc: rtc@40046000 { + ... + clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>; + clock-names = "rtc", "reg"; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/lsi,axm5516-clks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/lsi,axm5516-clks.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ce97cfe999b8f8931d50f3f6bdebc990562965d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/lsi,axm5516-clks.txt @@ -0,0 +1,29 @@ +AXM5516 clock driver bindings +----------------------------- + +Required properties : +- compatible : shall contain "lsi,axm5516-clks" +- reg : shall contain base register location and length +- #clock-cells : shall contain 1 + +The consumer specifies the desired clock by having the clock ID in its "clocks" +phandle cell. See for the list of +supported clock IDs. + +Example: + + clks: clock-controller@2010020000 { + compatible = "lsi,axm5516-clks"; + #clock-cells = <1>; + reg = <0x20 0x10020000 0 0x20000>; + }; + + serial0: uart@2010080000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x20 0x10080000 0 0x1000>; + interrupts = ; + clocks = <&clks AXXIA_CLK_PER>; + clock-names = "apb_pclk"; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/marvell,berlin.txt b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,berlin.txt new file mode 100644 index 0000000000000000000000000000000000000000..c611c495f3ffb2ac13613ebb6c1569db7d148252 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,berlin.txt @@ -0,0 +1,31 @@ +Device Tree Clock bindings for Marvell Berlin + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Clock related registers are spread among the chip control registers. Berlin +clock node should be a sub-node of the chip controller node. Marvell Berlin2 +(BG2, BG2CD, BG2Q) SoCs share the same IP for PLLs and clocks, with some +minor differences in features and register layout. + +Required properties: +- compatible: must be "marvell,berlin2-clk" or "marvell,berlin2q-clk" +- #clock-cells: must be 1 +- clocks: must be the input parent clock phandle +- clock-names: name of the input parent clock + Allowed clock-names for the reference clocks are + "refclk" for the SoCs oscillator input on all SoCs, + and SoC-specific input clocks for + BG2/BG2CD: "video_ext0" for the external video clock input + + +Example: + +chip_clk: clock { + compatible = "marvell,berlin2q-clk"; + + #clock-cells = <1>; + clocks = <&refclk>; + clock-names = "refclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/marvell,mmp2.txt b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,mmp2.txt new file mode 100644 index 0000000000000000000000000000000000000000..af376a01f2b7236a67ca69af2d2b84cdc5e09b3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,mmp2.txt @@ -0,0 +1,21 @@ +* Marvell MMP2 Clock Controller + +The MMP2 clock subsystem generates and supplies clock to various +controllers within the MMP2 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,mmp2-clock" - controller compatible with MMP2 SoC. + +- reg: physical base address of the clock subsystem and length of memory mapped + region. There are 3 places in SOC has clock control logic: + "mpmu", "apmu", "apbc". So three reg spaces need to be defined. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa168.txt b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa168.txt new file mode 100644 index 0000000000000000000000000000000000000000..c62eb1d173a6384744dcb395bc25a66f2198e5cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa168.txt @@ -0,0 +1,21 @@ +* Marvell PXA168 Clock Controller + +The PXA168 clock subsystem generates and supplies clock to various +controllers within the PXA168 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,pxa168-clock" - controller compatible with PXA168 SoC. + +- reg: physical base address of the clock subsystem and length of memory mapped + region. There are 3 places in SOC has clock control logic: + "mpmu", "apmu", "apbc". So three reg spaces need to be defined. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa1928.txt b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa1928.txt new file mode 100644 index 0000000000000000000000000000000000000000..809c5a2d8d9d1e845c77e6e8690c75986db38469 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa1928.txt @@ -0,0 +1,21 @@ +* Marvell PXA1928 Clock Controllers + +The PXA1928 clock subsystem generates and supplies clock to various +controllers within the PXA1928 SoC. The PXA1928 contains 3 clock controller +blocks called APMU, MPMU, and APBC roughly corresponding to internal buses. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,pxa1928-apmu" - APMU controller compatible + - "marvell,pxa1928-mpmu" - MPMU controller compatible + - "marvell,pxa1928-apbc" - APBC controller compatible +- reg: physical base address of the clock controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use the clock controller +phandle and this identifier to specify the clock which they consume. + +All these identifiers can be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa910.txt b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa910.txt new file mode 100644 index 0000000000000000000000000000000000000000..d9f41f3c03a0947c2c34f4ad61b0c6065e8016d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/marvell,pxa910.txt @@ -0,0 +1,21 @@ +* Marvell PXA910 Clock Controller + +The PXA910 clock subsystem generates and supplies clock to various +controllers within the PXA910 SoC. + +Required Properties: + +- compatible: should be one of the following. + - "marvell,pxa910-clock" - controller compatible with PXA910 SoC. + +- reg: physical base address of the clock subsystem and length of memory mapped + region. There are 4 places in SOC has clock control logic: + "mpmu", "apmu", "apbc", "apbcp". So four reg spaces need to be defined. + +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + +All these identifier could be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/maxim,max77686.txt b/arch/arm64/boot/dts/vendor/bindings/clock/maxim,max77686.txt new file mode 100644 index 0000000000000000000000000000000000000000..3472b461ca9354c6dda17b585dfeb6a0ec202375 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/maxim,max77686.txt @@ -0,0 +1,114 @@ +Binding for Maxim MAX77686/MAX77802/MAX77620 32k clock generator block + +This is a part of device tree bindings of MAX77686/MAX77802/MAX77620 +multi-function device. More information can be found in MFD DT binding +doc as follows: + bindings/mfd/max77686.txt for MAX77686 and + bindings/mfd/max77802.txt for MAX77802 and + bindings/mfd/max77620.txt for MAX77620. + +The MAX77686 contains three 32.768khz clock outputs that can be controlled +(gated/ungated) over I2C. Clocks are defined as preprocessor macros in +dt-bindings/clock/maxim,max77686.h. + + +The MAX77802 contains two 32.768khz clock outputs that can be controlled +(gated/ungated) over I2C. Clocks are defined as preprocessor macros in +dt-bindings/clock/maxim,max77802.h. + +The MAX77686 contains one 32.768khz clock outputs that can be controlled +(gated/ungated) over I2C. Clocks are defined as preprocessor macros in +dt-bindings/clock/maxim,max77620.h. + +Following properties should be presend in main device node of the MFD chip. + +Required properties: + +- #clock-cells: from common clock binding; shall be set to 1. + +Optional properties: +- clock-output-names: From common clock binding. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Following indices are allowed: + - 0: 32khz_ap clock (max77686, max77802), 32khz_out0 (max77620) + - 1: 32khz_cp clock (max77686, max77802), + - 2: 32khz_pmic clock (max77686). + +Clocks are defined as preprocessor macros in above dt-binding header for +respective chips. + +Example: + +1. With MAX77686: + +#include +/* ... */ + + Node of the MFD chip + max77686: max77686@9 { + compatible = "maxim,max77686"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + #clock-cells = <1>; + + /* ... */ + }; + + Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "my-clock"; + clocks = <&max77686 MAX77686_CLK_PMIC>; + }; + +2. With MAX77802: + +#include +/* ... */ + + Node of the MFD chip + max77802: max77802@9 { + compatible = "maxim,max77802"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + #clock-cells = <1>; + + /* ... */ + }; + + Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "my-clock"; + clocks = <&max77802 MAX77802_CLK_32K_AP>; + }; + + +3. With MAX77620: + +#include +/* ... */ + + Node of the MFD chip + max77620: max77620@3c { + compatible = "maxim,max77620"; + reg = <0x3c>; + #clock-cells = <1>; + /* ... */ + }; + + Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "my-clock"; + clocks = <&max77620 MAX77620_CLK_32K_OUT0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/maxim,max9485.txt b/arch/arm64/boot/dts/vendor/bindings/clock/maxim,max9485.txt new file mode 100644 index 0000000000000000000000000000000000000000..61bec1100a94c77c090578a1e25dff180bd8e3d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/maxim,max9485.txt @@ -0,0 +1,59 @@ +Devicetree bindings for Maxim MAX9485 Programmable Audio Clock Generator + +This device exposes 4 clocks in total: + +- MAX9485_MCLKOUT: A gated, buffered output of the input clock of 27 MHz +- MAX9485_CLKOUT: A PLL that can be configured to 16 different discrete + frequencies +- MAX9485_CLKOUT[1,2]: Two gated outputs for MAX9485_CLKOUT + +MAX9485_CLKOUT[1,2] are children of MAX9485_CLKOUT which upchain all rate set +requests. + +Required properties: +- compatible: "maxim,max9485" +- clocks: Input clock, must provice 27.000 MHz +- clock-names: Must be set to "xclk" +- #clock-cells: From common clock binding; shall be set to 1 + +Optional properties: +- reset-gpios: GPIO descriptor connected to the #RESET input pin +- vdd-supply: A regulator node for Vdd +- clock-output-names: Name of output clocks, as defined in common clock + bindings + +If not explicitly set, the output names are "mclkout", "clkout", "clkout1" +and "clkout2". + +Clocks are defined as preprocessor macros in the dt-binding header. + +Example: + + #include + + xo-27mhz: xo-27mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + }; + + &i2c0 { + max9485: audio-clock@63 { + reg = <0x63>; + compatible = "maxim,max9485"; + clock-names = "xclk"; + clocks = <&xo-27mhz>; + reset-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + vdd-supply = <&3v3-reg>; + #clock-cells = <1>; + }; + }; + + // Clock consumer node + + foo@0 { + compatible = "bar,foo"; + /* ... */ + clock-names = "foo-input-clk"; + clocks = <&max9485 MAX9485_CLKOUT1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/microchip,pic32.txt b/arch/arm64/boot/dts/vendor/bindings/clock/microchip,pic32.txt new file mode 100644 index 0000000000000000000000000000000000000000..c93d88fdd8586566ef155ff41f928cc3855facbb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/microchip,pic32.txt @@ -0,0 +1,39 @@ +Microchip PIC32 Clock Controller Binding +---------------------------------------- +Microchip clock controller is consists of few oscillators, PLL, multiplexer +and few divider modules. + +This binding uses common clock bindings. +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: shall be "microchip,pic32mzda-clk". +- reg: shall contain base address and length of clock registers. +- #clock-cells: shall be 1. + +Optional properties: +- microchip,pic32mzda-sosc: shall be added only if platform has + secondary oscillator connected. + +Example: + rootclk: clock-controller@1f801200 { + compatible = "microchip,pic32mzda-clk"; + reg = <0x1f801200 0x200>; + #clock-cells = <1>; + /* optional */ + microchip,pic32mzda-sosc; + }; + + +The clock consumer shall specify the desired clock-output of the clock +controller (as defined in [2]) by specifying output-id in its "clock" +phandle cell. +[2] include/dt-bindings/clock/microchip,pic32-clock.h + +For example for UART2: +uart2: serial@2 { + compatible = "microchip,pic32mzda-uart"; + reg = <>; + interrupts = <>; + clocks = <&rootclk PB2CLK>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/moxa,moxart-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/moxa,moxart-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..fedea84314a1c4dda2cb4661e43b68904cf3149a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/moxa,moxart-clock.txt @@ -0,0 +1,48 @@ +Device Tree Clock bindings for arch-moxart + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +MOXA ART SoCs allow to determine PLL output and APB frequencies +by reading registers holding multiplier and divisor information. + + +PLL: + +Required properties: +- compatible : Must be "moxa,moxart-pll-clock" +- #clock-cells : Should be 0 +- reg : Should contain registers location and length +- clocks : Should contain phandle + clock-specifier for the parent clock + +Optional properties: +- clock-output-names : Should contain clock name + + +APB: + +Required properties: +- compatible : Must be "moxa,moxart-apb-clock" +- #clock-cells : Should be 0 +- reg : Should contain registers location and length +- clocks : Should contain phandle + clock-specifier for the parent clock + +Optional properties: +- clock-output-names : Should contain clock name + + +For example: + + clk_pll: clk_pll@98100000 { + compatible = "moxa,moxart-pll-clock"; + #clock-cells = <0>; + reg = <0x98100000 0x34>; + }; + + clk_apb: clk_apb@98100000 { + compatible = "moxa,moxart-apb-clock"; + #clock-cells = <0>; + reg = <0x98100000 0x34>; + clocks = <&clk_pll>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-core-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-core-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..796c260c183d6af6d202752d453beb6363109c97 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-core-clock.txt @@ -0,0 +1,86 @@ +* Core Clock bindings for Marvell MVEBU SoCs + +Marvell MVEBU SoCs usually allow to determine core clock frequencies by +reading the Sample-At-Reset (SAR) register. The core clock consumer should +specify the desired clock by having the clock ID in its "clocks" phandle cell. + +The following is a list of provided IDs and clock names on Armada 370/XP: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU clock) + 2 = nbclk (L2 Cache clock) + 3 = hclk (DRAM control clock) + 4 = dramclk (DDR clock) + +The following is a list of provided IDs and clock names on Armada 375: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU clock) + 2 = l2clk (L2 Cache clock) + 3 = ddrclk (DDR clock) + +The following is a list of provided IDs and clock names on Armada 380/385: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU clock) + 2 = l2clk (L2 Cache clock) + 3 = ddrclk (DDR clock) + +The following is a list of provided IDs and clock names on Armada 39x: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU clock) + 2 = nbclk (Coherent Fabric clock) + 3 = hclk (SDRAM Controller Internal Clock) + 4 = dclk (SDRAM Interface Clock) + 5 = refclk (Reference Clock) + +The following is a list of provided IDs and clock names on 98dx3236: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU clock) + 2 = ddrclk (DDR clock) + 3 = mpll (MPLL Clock) + +The following is a list of provided IDs and clock names on Kirkwood and Dove: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU0 clock) + 2 = l2clk (L2 Cache clock derived from CPU0 clock) + 3 = ddrclk (DDR controller clock derived from CPU0 clock) + +The following is a list of provided IDs and clock names on Orion5x: + 0 = tclk (Internal Bus clock) + 1 = cpuclk (CPU0 clock) + 2 = ddrclk (DDR controller clock derived from CPU0 clock) + +Required properties: +- compatible : shall be one of the following: + "marvell,armada-370-core-clock" - For Armada 370 SoC core clocks + "marvell,armada-375-core-clock" - For Armada 375 SoC core clocks + "marvell,armada-380-core-clock" - For Armada 380/385 SoC core clocks + "marvell,armada-390-core-clock" - For Armada 39x SoC core clocks + "marvell,armada-xp-core-clock" - For Armada XP SoC core clocks + "marvell,mv98dx3236-core-clock" - For 98dx3236 family SoC core clocks + "marvell,dove-core-clock" - for Dove SoC core clocks + "marvell,kirkwood-core-clock" - for Kirkwood SoC (except mv88f6180) + "marvell,mv88f6180-core-clock" - for Kirkwood MV88f6180 SoC + "marvell,mv88f5181-core-clock" - for Orion MV88F5181 SoC + "marvell,mv88f5182-core-clock" - for Orion MV88F5182 SoC + "marvell,mv88f5281-core-clock" - for Orion MV88F5281 SoC + "marvell,mv88f6183-core-clock" - for Orion MV88F6183 SoC +- reg : shall be the register address of the Sample-At-Reset (SAR) register +- #clock-cells : from common clock binding; shall be set to 1 + +Optional properties: +- clock-output-names : from common clock binding; allows overwrite default clock + output names ("tclk", "cpuclk", "l2clk", "ddrclk") + +Example: + +core_clk: core-clocks@d0214 { + compatible = "marvell,dove-core-clock"; + reg = <0xd0214 0x4>; + #clock-cells = <1>; +}; + +spi0: spi@10600 { + compatible = "marvell,orion-spi"; + /* ... */ + /* get tclk from core clock provider */ + clocks = <&core_clk 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-corediv-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-corediv-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7b4e3a6b2c629b6c753e695e611ccb7f9eb2b98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-corediv-clock.txt @@ -0,0 +1,23 @@ +* Core Divider Clock bindings for Marvell MVEBU SoCs + +The following is a list of provided IDs and clock names on Armada 370/XP: + 0 = nand (NAND clock) + +Required properties: +- compatible : must be "marvell,armada-370-corediv-clock", + "marvell,armada-375-corediv-clock", + "marvell,armada-380-corediv-clock", + "marvell,mv98dx3236-corediv-clock", + +- reg : must be the register address of Core Divider control register +- #clock-cells : from common clock binding; shall be set to 1 +- clocks : must be set to the parent's phandle + +Example: + +corediv_clk: corediv-clocks@18740 { + compatible = "marvell,armada-370-corediv-clock"; + reg = <0x18740 0xc>; + #clock-cells = <1>; + clocks = <&pll>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-cpu-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-cpu-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f28506eaee77a652e9ccc37cb819e7a7b686489 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-cpu-clock.txt @@ -0,0 +1,23 @@ +Device Tree Clock bindings for cpu clock of Marvell EBU platforms + +Required properties: +- compatible : shall be one of the following: + "marvell,armada-xp-cpu-clock" - cpu clocks for Armada XP + "marvell,mv98dx3236-cpu-clock" - cpu clocks for 98DX3236 SoC +- reg : Address and length of the clock complex register set, followed + by address and length of the PMU DFS registers +- #clock-cells : should be set to 1. +- clocks : shall be the input parent clock phandle for the clock. + +cpuclk: clock-complex@d0018700 { + #clock-cells = <1>; + compatible = "marvell,armada-xp-cpu-clock"; + reg = <0xd0018700 0xA0>, <0x1c054 0x10>; + clocks = <&coreclk 1>; +} + +cpu@0 { + compatible = "marvell,sheeva-v7"; + reg = <0>; + clocks = <&cpuclk 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-gated-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-gated-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..de562da2ae77db48639d1a775ca5efd489e5de04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/mvebu-gated-clock.txt @@ -0,0 +1,205 @@ +* Gated Clock bindings for Marvell EBU SoCs + +Marvell Armada 370/375/380/385/39x/XP, Dove and Kirkwood allow some +peripheral clocks to be gated to save some power. The clock consumer +should specify the desired clock by having the clock ID in its +"clocks" phandle cell. The clock ID is directly mapped to the +corresponding clock gating control bit in HW to ease manual clock +lookup in datasheet. + +The following is a list of provided IDs for Armada 370: +ID Clock Peripheral +----------------------------------- +0 Audio AC97 Cntrl +1 pex0_en PCIe 0 Clock out +2 pex1_en PCIe 1 Clock out +3 ge1 Gigabit Ethernet 1 +4 ge0 Gigabit Ethernet 0 +5 pex0 PCIe Cntrl 0 +9 pex1 PCIe Cntrl 1 +15 sata0 SATA Host 0 +17 sdio SDHCI Host +23 crypto CESA (crypto engine) +25 tdm Time Division Mplx +28 ddr DDR Cntrl +30 sata1 SATA Host 0 + +The following is a list of provided IDs for Armada 375: +ID Clock Peripheral +----------------------------------- +2 mu Management Unit +3 pp Packet Processor +4 ptp PTP +5 pex0 PCIe 0 Clock out +6 pex1 PCIe 1 Clock out +8 audio Audio Cntrl +11 nd_clk Nand Flash Cntrl +14 sata0_link SATA 0 Link +15 sata0_core SATA 0 Core +16 usb3 USB3 Host +17 sdio SDHCI Host +18 usb USB Host +19 gop Gigabit Ethernet MAC +20 sata1_link SATA 1 Link +21 sata1_core SATA 1 Core +22 xor0 XOR DMA 0 +23 xor1 XOR DMA 0 +24 copro Coprocessor +25 tdm Time Division Mplx +28 crypto0_enc Cryptographic Unit Port 0 Encryption +29 crypto0_core Cryptographic Unit Port 0 Core +30 crypto1_enc Cryptographic Unit Port 1 Encryption +31 crypto1_core Cryptographic Unit Port 1 Core + +The following is a list of provided IDs for Armada 380/385: +ID Clock Peripheral +----------------------------------- +0 audio Audio +2 ge2 Gigabit Ethernet 2 +3 ge1 Gigabit Ethernet 1 +4 ge0 Gigabit Ethernet 0 +5 pex1 PCIe 1 +6 pex2 PCIe 2 +7 pex3 PCIe 3 +8 pex0 PCIe 0 +9 usb3h0 USB3 Host 0 +10 usb3h1 USB3 Host 1 +11 usb3d USB3 Device +13 bm Buffer Management +14 crypto0z Cryptographic 0 Z +15 sata0 SATA 0 +16 crypto1z Cryptographic 1 Z +17 sdio SDIO +18 usb2 USB 2 +21 crypto1 Cryptographic 1 +22 xor0 XOR 0 +23 crypto0 Cryptographic 0 +25 tdm Time Division Multiplexing +28 xor1 XOR 1 +30 sata1 SATA 1 + +The following is a list of provided IDs for Armada 39x: +ID Clock Peripheral +----------------------------------- +5 pex1 PCIe 1 +6 pex2 PCIe 2 +7 pex3 PCIe 3 +8 pex0 PCIe 0 +9 usb3h0 USB3 Host 0 +10 usb3h1 USB3 Host 1 +15 sata0 SATA 0 +17 sdio SDIO +22 xor0 XOR 0 +28 xor1 XOR 1 + +The following is a list of provided IDs for Armada XP: +ID Clock Peripheral +----------------------------------- +0 audio Audio Cntrl +1 ge3 Gigabit Ethernet 3 +2 ge2 Gigabit Ethernet 2 +3 ge1 Gigabit Ethernet 1 +4 ge0 Gigabit Ethernet 0 +5 pex0 PCIe Cntrl 0 +6 pex1 PCIe Cntrl 1 +7 pex2 PCIe Cntrl 2 +8 pex3 PCIe Cntrl 3 +13 bp +14 sata0lnk +15 sata0 SATA Host 0 +16 lcd LCD Cntrl +17 sdio SDHCI Host +18 usb0 USB Host 0 +19 usb1 USB Host 1 +20 usb2 USB Host 2 +22 xor0 XOR DMA 0 +23 crypto CESA engine +25 tdm Time Division Mplx +28 xor1 XOR DMA 1 +29 sata1lnk +30 sata1 SATA Host 1 + +The following is a list of provided IDs for 98dx3236: +ID Clock Peripheral +----------------------------------- +3 ge1 Gigabit Ethernet 1 +4 ge0 Gigabit Ethernet 0 +5 pex0 PCIe Cntrl 0 +17 sdio SDHCI Host +18 usb0 USB Host 0 +22 xor0 XOR DMA 0 + +The following is a list of provided IDs for Dove: +ID Clock Peripheral +----------------------------------- +0 usb0 USB Host 0 +1 usb1 USB Host 1 +2 ge Gigabit Ethernet +3 sata SATA Host +4 pex0 PCIe Cntrl 0 +5 pex1 PCIe Cntrl 1 +8 sdio0 SDHCI Host 0 +9 sdio1 SDHCI Host 1 +10 nand NAND Cntrl +11 camera Camera Cntrl +12 i2s0 I2S Cntrl 0 +13 i2s1 I2S Cntrl 1 +15 crypto CESA engine +21 ac97 AC97 Cntrl +22 pdma Peripheral DMA +23 xor0 XOR DMA 0 +24 xor1 XOR DMA 1 +30 gephy Gigabit Ethernel PHY +Note: gephy(30) is implemented as a parent clock of ge(2) + +The following is a list of provided IDs for Kirkwood: +ID Clock Peripheral +----------------------------------- +0 ge0 Gigabit Ethernet 0 +2 pex0 PCIe Cntrl 0 +3 usb0 USB Host 0 +4 sdio SDIO Cntrl +5 tsu Transp. Stream Unit +6 dunit SDRAM Cntrl +7 runit Runit +8 xor0 XOR DMA 0 +9 audio I2S Cntrl 0 +14 sata0 SATA Host 0 +15 sata1 SATA Host 1 +16 xor1 XOR DMA 1 +17 crypto CESA engine +18 pex1 PCIe Cntrl 1 +19 ge1 Gigabit Ethernet 1 +20 tdm Time Division Mplx + +Required properties: +- compatible : shall be one of the following: + "marvell,armada-370-gating-clock" - for Armada 370 SoC clock gating + "marvell,armada-375-gating-clock" - for Armada 375 SoC clock gating + "marvell,armada-380-gating-clock" - for Armada 380/385 SoC clock gating + "marvell,armada-390-gating-clock" - for Armada 39x SoC clock gating + "marvell,armada-xp-gating-clock" - for Armada XP SoC clock gating + "marvell,mv98dx3236-gating-clock" - for 98dx3236 SoC clock gating + "marvell,dove-gating-clock" - for Dove SoC clock gating + "marvell,kirkwood-gating-clock" - for Kirkwood SoC clock gating +- reg : shall be the register address of the Clock Gating Control register +- #clock-cells : from common clock binding; shall be set to 1 + +Optional properties: +- clocks : default parent clock phandle (e.g. tclk) + +Example: + +gate_clk: clock-gating-control@d0038 { + compatible = "marvell,dove-gating-clock"; + reg = <0xd0038 0x4>; + /* default parent clock is tclk */ + clocks = <&core_clk 0>; + #clock-cells = <1>; +}; + +sdio0: sdio@92000 { + compatible = "marvell,dove-sdhci"; + /* get clk gate bit 8 (sdio0) */ + clocks = <&gate_clk 8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nspire-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nspire-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c3bc8bb5b9f91fc800d0a4cc8e87bb11a04031c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nspire-clock.txt @@ -0,0 +1,24 @@ +TI-NSPIRE Clocks + +Required properties: +- compatible: Valid compatible properties include: + "lsi,nspire-cx-ahb-divider" for the AHB divider in the CX model + "lsi,nspire-classic-ahb-divider" for the AHB divider in the older model + "lsi,nspire-cx-clock" for the base clock in the CX model + "lsi,nspire-classic-clock" for the base clock in the older model + +- reg: Physical base address of the controller and length of memory mapped + region. + +Optional: +- clocks: For the "nspire-*-ahb-divider" compatible clocks, this is the parent + clock where it divides the rate from. + +Example: + +ahb_clk { + #clock-cells = <0>; + compatible = "lsi,nspire-cx-clock"; + reg = <0x900B0000 0x4>; + clocks = <&base_clk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nuvoton,npcm750-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nuvoton,npcm750-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..f82064546d1117519bfa1c9a6ca497e1821d0e0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nuvoton,npcm750-clk.txt @@ -0,0 +1,100 @@ +* Nuvoton NPCM7XX Clock Controller + +Nuvoton Poleg BMC NPCM7XX contains an integrated clock controller, which +generates and supplies clocks to all modules within the BMC. + +External clocks: + +There are six fixed clocks that are generated outside the BMC. All clocks are of +a known fixed value that cannot be changed. clk_refclk, clk_mcbypck and +clk_sysbypck are inputs to the clock controller. +clk_rg1refck, clk_rg2refck and clk_xin are external clocks suppling the +network. They are set on the device tree, but not used by the clock module. The +network devices use them directly. +Example can be found below. + +All available clocks are defined as preprocessor macros in: +dt-bindings/clock/nuvoton,npcm7xx-clock.h +and can be reused as DT sources. + +Required Properties of clock controller: + + - compatible: "nuvoton,npcm750-clk" : for clock controller of Nuvoton + Poleg BMC NPCM750 + + - reg: physical base address of the clock controller and length of + memory mapped region. + + - #clock-cells: should be 1. + +Example: Clock controller node: + + clk: clock-controller@f0801000 { + compatible = "nuvoton,npcm750-clk"; + #clock-cells = <1>; + reg = <0xf0801000 0x1000>; + clock-names = "refclk", "sysbypck", "mcbypck"; + clocks = <&clk_refclk>, <&clk_sysbypck>, <&clk_mcbypck>; + }; + +Example: Required external clocks for network: + + /* external reference clock */ + clk_refclk: clk-refclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "refclk"; + }; + + /* external reference clock for cpu. float in normal operation */ + clk_sysbypck: clk-sysbypck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <800000000>; + clock-output-names = "sysbypck"; + }; + + /* external reference clock for MC. float in normal operation */ + clk_mcbypck: clk-mcbypck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <800000000>; + clock-output-names = "mcbypck"; + }; + + /* external clock signal rg1refck, supplied by the phy */ + clk_rg1refck: clk-rg1refck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + clock-output-names = "clk_rg1refck"; + }; + + /* external clock signal rg2refck, supplied by the phy */ + clk_rg2refck: clk-rg2refck { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + clock-output-names = "clk_rg2refck"; + }; + + clk_xin: clk-xin { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "clk_xin"; + }; + + +Example: GMAC controller node that consumes two clocks: a generated clk by the +clock controller and a fixed clock from DT (clk_rg1refck). + + ethernet0: ethernet@f0802000 { + compatible = "snps,dwmac"; + reg = <0xf0802000 0x2000>; + interrupts = <0 14 4>; + interrupt-names = "macirq"; + clocks = <&clk_rg1refck>, <&clk NPCM7XX_CLK_AHB>; + clock-names = "stmmaceth", "clk_gmac"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra114-car.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra114-car.txt new file mode 100644 index 0000000000000000000000000000000000000000..9acea9d931600e01fe37ec0b40a25bcf82a2e864 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra114-car.txt @@ -0,0 +1,63 @@ +NVIDIA Tegra114 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra114-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in header file + . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra114-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA114_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra124-car.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra124-car.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f02fb4ca4adb020a9b7990e6db5532e0fc2abe5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra124-car.txt @@ -0,0 +1,107 @@ +NVIDIA Tegra124 and Tegra132 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra124-car" or "nvidia,tegra132-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in the header files + (which covers IDs common + to Tegra124 and Tegra132) and + (for Tegra124-specific clocks). +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. +- nvidia,external-memory-controller : phandle of the EMC driver. + +The node should contain a "emc-timings" subnode for each supported RAM type (see +field RAM_CODE in register PMC_STRAPPING_OPT_A). + +Required properties for "emc-timings" nodes : +- nvidia,ram-code : Should contain the value of RAM_CODE this timing set + is used for. + +Each "emc-timings" node should contain a "timing" subnode for every supported +EMC clock rate. + +Required properties for "timing" nodes : +- clock-frequency : Should contain the memory clock rate to which this timing +relates. +- nvidia,parent-clock-frequency : Should contain the rate at which the current +parent of the EMC clock should be running at this timing. +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - emc-parent : the clock that should be the parent of the EMC clock at this +timing. + +Example SoC include file: + +/ { + tegra_car: clock@60006000 { + compatible = "nvidia,tegra124-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + nvidia,external-memory-controller = <&emc>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA124_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <112400000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; + + clock@60006000 { + emc-timings-3 { + nvidia,ram-code = <3>; + + timing-12750000 { + clock-frequency = <12750000>; + nvidia,parent-clock-frequency = <408000000>; + clocks = <&tegra_car TEGRA124_CLK_PLL_P>; + clock-names = "emc-parent"; + }; + timing-20400000 { + clock-frequency = <20400000>; + nvidia,parent-clock-frequency = <408000000>; + clocks = <&tegra_car TEGRA124_CLK_PLL_P>; + clock-names = "emc-parent"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra124-dfll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra124-dfll.txt new file mode 100644 index 0000000000000000000000000000000000000000..dff236f524a73844f95cf945397edc3143fcc205 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra124-dfll.txt @@ -0,0 +1,78 @@ +NVIDIA Tegra124 DFLL FCPU clocksource + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The DFLL IP block on Tegra is a root clocksource designed for clocking +the fast CPU cluster. It consists of a free-running voltage controlled +oscillator connected to the CPU voltage rail (VDD_CPU), and a closed loop +control module that will automatically adjust the VDD_CPU voltage by +communicating with an off-chip PMIC either via an I2C bus or via PWM signals. +Currently only the I2C mode is supported by these bindings. + +Required properties: +- compatible : should be "nvidia,tegra124-dfll" +- reg : Defines the following set of registers, in the order listed: + - registers for the DFLL control logic. + - registers for the I2C output logic. + - registers for the integrated I2C master controller. + - look-up table RAM for voltage register values. +- interrupts: Should contain the DFLL block interrupt. +- clocks: Must contain an entry for each entry in clock-names. + See clock-bindings.txt for details. +- clock-names: Must include the following entries: + - soc: Clock source for the DFLL control logic. + - ref: The closed loop reference clock + - i2c: Clock source for the integrated I2C master. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - dvco: Reset control for the DFLL DVCO. +- #clock-cells: Must be 0. +- clock-output-names: Name of the clock output. +- vdd-cpu-supply: Regulator for the CPU voltage rail that the DFLL + hardware will start controlling. The regulator will be queried for + the I2C register, control values and supported voltages. + +Required properties for the control loop parameters: +- nvidia,sample-rate: Sample rate of the DFLL control loop. +- nvidia,droop-ctrl: See the register CL_DVFS_DROOP_CTRL in the TRM. +- nvidia,force-mode: See the field DFLL_PARAMS_FORCE_MODE in the TRM. +- nvidia,cf: Numeric value, see the field DFLL_PARAMS_CF_PARAM in the TRM. +- nvidia,ci: Numeric value, see the field DFLL_PARAMS_CI_PARAM in the TRM. +- nvidia,cg: Numeric value, see the field DFLL_PARAMS_CG_PARAM in the TRM. + +Optional properties for the control loop parameters: +- nvidia,cg-scale: Boolean value, see the field DFLL_PARAMS_CG_SCALE in the TRM. + +Required properties for I2C mode: +- nvidia,i2c-fs-rate: I2C transfer rate, if using full speed mode. + +Example: + +clock@70110000 { + compatible = "nvidia,tegra124-dfll"; + reg = <0 0x70110000 0 0x100>, /* DFLL control */ + <0 0x70110000 0 0x100>, /* I2C output control */ + <0 0x70110100 0 0x100>, /* Integrated I2C controller */ + <0 0x70110200 0 0x100>; /* Look-up table RAM */ + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_DFLL_SOC>, + <&tegra_car TEGRA124_CLK_DFLL_REF>, + <&tegra_car TEGRA124_CLK_I2C5>; + clock-names = "soc", "ref", "i2c"; + resets = <&tegra_car TEGRA124_RST_DFLL_DVCO>; + reset-names = "dvco"; + #clock-cells = <0>; + clock-output-names = "dfllCPU_out"; + vdd-cpu-supply = <&vdd_cpu>; + + nvidia,sample-rate = <12500>; + nvidia,droop-ctrl = <0x00000f00>; + nvidia,force-mode = <1>; + nvidia,cf = <10>; + nvidia,ci = <0>; + nvidia,cg = <2>; + + nvidia,i2c-fs-rate = <400000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra20-car.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra20-car.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c5901b503d019adfcd0f24bc8c99aed03fb50f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra20-car.txt @@ -0,0 +1,63 @@ +NVIDIA Tegra20 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra20-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in header file + . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra20-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA20_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra210-car.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra210-car.txt new file mode 100644 index 0000000000000000000000000000000000000000..26f237f641b71fe39a73da4ada6934068cf41273 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra210-car.txt @@ -0,0 +1,56 @@ +NVIDIA Tegra210 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra210-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in header file + . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra210-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA210_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra30-car.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra30-car.txt new file mode 100644 index 0000000000000000000000000000000000000000..63618cde12df16a7e842834799f6f058bd2ac7a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nvidia,tegra30-car.txt @@ -0,0 +1,63 @@ +NVIDIA Tegra30 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra30-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in header file + . +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra30-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA30_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nxp,lpc3220-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nxp,lpc3220-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..20cbca3f41d8b58955d6b301a6a87b3f285f6d1b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nxp,lpc3220-clk.txt @@ -0,0 +1,30 @@ +NXP LPC32xx Clock Controller + +Required properties: +- compatible: should be "nxp,lpc3220-clk" +- reg: should contain clock controller registers location and length +- #clock-cells: must be 1, the cell holds id of a clock provided by the + clock controller +- clocks: phandles of external oscillators, the list must contain one + 32768 Hz oscillator and may have one optional high frequency oscillator +- clock-names: list of external oscillator clock names, must contain + "xtal_32k" and may have optional "xtal" + +Examples: + + /* System Control Block */ + scb { + compatible = "simple-bus"; + ranges = <0x0 0x040004000 0x00001000>; + #address-cells = <1>; + #size-cells = <1>; + + clk: clock-controller@0 { + compatible = "nxp,lpc3220-clk"; + reg = <0x00 0x114>; + #clock-cells = <1>; + + clocks = <&xtal_32k>, <&xtal>; + clock-names = "xtal_32k", "xtal"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/nxp,lpc3220-usb-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/nxp,lpc3220-usb-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..0aa249409b511c0bb6d44f0d42f027298bf32b87 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/nxp,lpc3220-usb-clk.txt @@ -0,0 +1,22 @@ +NXP LPC32xx USB Clock Controller + +Required properties: +- compatible: should be "nxp,lpc3220-usb-clk" +- reg: should contain clock controller registers location and length +- #clock-cells: must be 1, the cell holds id of a clock provided by the + USB clock controller + +Examples: + + usb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + ranges = <0x0 0x31020000 0x00001000>; + + usbclk: clock-controller@f00 { + compatible = "nxp,lpc3220-usb-clk"; + reg = <0xf00 0x100>; + #clock-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/oxnas,stdclk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/oxnas,stdclk.txt new file mode 100644 index 0000000000000000000000000000000000000000..b652f3fb77965cf70318349c449904d72b31c86d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/oxnas,stdclk.txt @@ -0,0 +1,28 @@ +Oxford Semiconductor OXNAS SoC Family Standard Clocks +================================================ + +Please also refer to clock-bindings.txt in this directory for common clock +bindings usage. + +Required properties: +- compatible: For OX810SE, should be "oxsemi,ox810se-stdclk" + For OX820, should be "oxsemi,ox820-stdclk" +- #clock-cells: 1, see below + +Parent node should have the following properties : +- compatible: For OX810SE, should be + "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd" + For OX820, should be + "oxsemi,ox820-sys-ctrl", "syscon", "simple-mfd" + +example: + +sys: sys-ctrl@000000 { + compatible = "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd"; + reg = <0x000000 0x100000>; + + stdclk: stdclk { + compatible = "oxsemi,ox810se-stdclk"; + #clock-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/pistachio-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/pistachio-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..868db499eed2da4f3a1fad0530cc6b00080f0af1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/pistachio-clock.txt @@ -0,0 +1,123 @@ +Imagination Technologies Pistachio SoC clock controllers +======================================================== + +Pistachio has four clock controllers (core clock, peripheral clock, peripheral +general control, and top general control) which are instantiated individually +from the device-tree. + +External clocks: +---------------- + +There are three external inputs to the clock controllers which should be +defined with the following clock-output-names: +- "xtal": External 52Mhz oscillator (required) +- "audio_clk_in": Alternate audio reference clock (optional) +- "enet_clk_in": Alternate ethernet PHY clock (optional) + +Core clock controller: +---------------------- + +The core clock controller generates clocks for the CPU, RPU (WiFi + BT +co-processor), audio, and several peripherals. + +Required properties: +- compatible: Must be "img,pistachio-clk". +- reg: Must contain the base address and length of the core clock controller. +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Must include "xtal" (see "External clocks") and + "audio_clk_in_gate", "enet_clk_in_gate" which are generated by the + top-level general control. + +Example: + clk_core: clock-controller@18144000 { + compatible = "img,pistachio-clk"; + reg = <0x18144000 0x800>; + clocks = <&xtal>, <&cr_top EXT_CLK_AUDIO_IN>, + <&cr_top EXT_CLK_ENET_IN>; + clock-names = "xtal", "audio_clk_in_gate", "enet_clk_in_gate"; + + #clock-cells = <1>; + }; + +Peripheral clock controller: +---------------------------- + +The peripheral clock controller generates clocks for the DDR, ROM, and other +peripherals. The peripheral system clock ("periph_sys") generated by the core +clock controller is the input clock to the peripheral clock controller. + +Required properties: +- compatible: Must be "img,pistachio-periph-clk". +- reg: Must contain the base address and length of the peripheral clock + controller. +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Must include "periph_sys", the peripheral system clock generated + by the core clock controller. + +Example: + clk_periph: clock-controller@18144800 { + compatible = "img,pistachio-clk-periph"; + reg = <0x18144800 0x800>; + clocks = <&clk_core CLK_PERIPH_SYS>; + clock-names = "periph_sys"; + + #clock-cells = <1>; + }; + +Peripheral general control: +--------------------------- + +The peripheral general control block generates system interface clocks and +resets for various peripherals. It also contains miscellaneous peripheral +control registers. The system clock ("sys") generated by the peripheral clock +controller is the input clock to the system clock controller. + +Required properties: +- compatible: Must include "img,pistachio-periph-cr" and "syscon". +- reg: Must contain the base address and length of the peripheral general + control registers. +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Must include "sys", the system clock generated by the peripheral + clock controller. + +Example: + cr_periph: syscon@18144800 { + compatible = "img,pistachio-cr-periph", "syscon"; + reg = <0x18148000 0x1000>; + clocks = <&clock_periph PERIPH_CLK_PERIPH_SYS>; + clock-names = "sys"; + + #clock-cells = <1>; + }; + +Top-level general control: +-------------------------- + +The top-level general control block contains miscellaneous control registers and +gates for the external clocks "audio_clk_in" and "enet_clk_in". + +Required properties: +- compatible: Must include "img,pistachio-cr-top" and "syscon". +- reg: Must contain the base address and length of the top-level + control registers. +- clocks: Must contain an entry for each clock in clock-names. +- clock-names: Two optional clocks, "audio_clk_in" and "enet_clk_in" (see + "External clocks"). +- #clock-cells: Must be 1. The single cell is the clock identifier. + See dt-bindings/clock/pistachio-clk.h for the list of valid identifiers. + +Example: + cr_top: syscon@18144800 { + compatible = "img,pistachio-cr-top", "syscon"; + reg = <0x18149000 0x200>; + clocks = <&audio_refclk>, <&ext_enet_in>; + clock-names = "audio_clk_in", "enet_clk_in"; + + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/prima2-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/prima2-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..5016979c0f786bb3a01814d4f0c70b7d88be27ed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/prima2-clock.txt @@ -0,0 +1,73 @@ +* Clock bindings for CSR SiRFprimaII + +Required properties: +- compatible: Should be "sirf,prima2-clkc" +- reg: Address and length of the register set +- interrupts: Should contain clock controller interrupt +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. The following is a full list of prima2 +clocks and IDs. + + Clock ID + --------------------------- + rtc 0 + osc 1 + pll1 2 + pll2 3 + pll3 4 + mem 5 + sys 6 + security 7 + dsp 8 + gps 9 + mf 10 + io 11 + cpu 12 + uart0 13 + uart1 14 + uart2 15 + tsc 16 + i2c0 17 + i2c1 18 + spi0 19 + spi1 20 + pwmc 21 + efuse 22 + pulse 23 + dmac0 24 + dmac1 25 + nand 26 + audio 27 + usp0 28 + usp1 29 + usp2 30 + vip 31 + gfx 32 + mm 33 + lcd 34 + vpp 35 + mmc01 36 + mmc23 37 + mmc45 38 + usbpll 39 + usb0 40 + usb1 41 + +Examples: + +clks: clock-controller@88000000 { + compatible = "sirf,prima2-clkc"; + reg = <0x88000000 0x1000>; + interrupts = <3>; + #clock-cells = <1>; +}; + +i2c0: i2c@b00e0000 { + cell-index = <0>; + compatible = "sirf,prima2-i2c"; + reg = <0xb00e0000 0x10000>; + interrupts = <24>; + clocks = <&clks 17>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/pwm-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/pwm-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..83db876b3b9071a30faa981ec3ffb8c50b5867d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/pwm-clock.txt @@ -0,0 +1,26 @@ +Binding for an external clock signal driven by a PWM pin. + +This binding uses the common clock binding[1] and the common PWM binding[2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/pwm/pwm.txt + +Required properties: +- compatible : shall be "pwm-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- pwms : from common PWM binding; this determines the clock frequency + via the period given in the PWM specifier. + +Optional properties: +- clock-output-names : From common clock binding. +- clock-frequency : Exact output frequency, in case the PWM period + is not exact but was rounded to nanoseconds. + +Example: + clock { + compatible = "pwm-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "mipi_mclk"; + pwms = <&pwm2 0 40>; /* 1 / 40 ns = 25 MHz */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/pxa-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/pxa-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f67239411fee74af684f01d0d73913ba6884963 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/pxa-clock.txt @@ -0,0 +1,15 @@ +* Clock bindings for Marvell PXA chips + +Required properties: +- compatible: Should be "marvell,pxa-clocks" +- #clock-cells: Should be <1> + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell (see include/.../pxa-clock.h). + +Examples: + +pxa2xx_clks: pxa2xx_clks@41300004 { + compatible = "marvell,pxa-clocks"; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qca,ath79-pll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qca,ath79-pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..241fb0545b9eebce2bd70277d44fcffd77365a28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qca,ath79-pll.txt @@ -0,0 +1,33 @@ +Binding for Qualcomm Atheros AR7xxx/AR9XXX PLL controller + +The PPL controller provides the 3 main clocks of the SoC: CPU, DDR and AHB. + +Required Properties: +- compatible: has to be "qca,-pll" and one of the following + fallbacks: + - "qca,ar7100-pll" + - "qca,ar7240-pll" + - "qca,ar9130-pll" + - "qca,ar9330-pll" + - "qca,ar9340-pll" + - "qca,qca9550-pll" +- reg: Base address and size of the controllers memory area +- clock-names: Name of the input clock, has to be "ref" +- clocks: phandle of the external reference clock +- #clock-cells: has to be one + +Optional properties: +- clock-output-names: should be "cpu", "ddr", "ahb" + +Example: + + pll-controller@18050000 { + compatible = "qca,ar9132-pll", "qca,ar9130-pll"; + reg = <0x18050000 0x20>; + + clock-names = "ref"; + clocks = <&extosc>; + + #clock-cells = <1>; + clock-output-names = "cpu", "ddr", "ahb"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,a53pll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,a53pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3fa8118eaee16ec71ba58ab4cbb7f8422a1e68e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,a53pll.txt @@ -0,0 +1,22 @@ +Qualcomm MSM8916 A53 PLL Binding +-------------------------------- +The A53 PLL on MSM8916 platforms is the main CPU PLL used used for frequencies +above 1GHz. + +Required properties : +- compatible : Shall contain only one of the following: + + "qcom,msm8916-a53pll" + +- reg : shall contain base register location and length + +- #clock-cells : must be set to <0> + +Example: + + a53pll: clock@b016000 { + compatible = "qcom,msm8916-a53pll"; + reg = <0xb016000 0x40>; + #clock-cells = <0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,aop-qmp.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,aop-qmp.txt new file mode 100644 index 0000000000000000000000000000000000000000..231b8a36420ba90c06016ff4547c4f156540ab6c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,aop-qmp.txt @@ -0,0 +1,17 @@ +Qualcomm Technologies, Inc. Always On Processor Clock controller Binding +------------------------------------------------------------------------ + +Required properties : +- compatible : must be "qcom,aop-qmp-clk" +- #clock-cells : must contain 1 +- mboxes : list of QMP mailbox phandle and channel identifier tuples. +- mbox-names: List of identifier strings for each mailbox channel. + Must contain "qdss_clk". + +Example : + clock_qdss: qcom,aopclk { + compatible = "qcom,aop-qmp-clk"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,camcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,camcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7256364e39e648f8c2c1e3d7ecb2781ec6b1c37f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,camcc.txt @@ -0,0 +1,26 @@ +Qualcomm Technologies, Inc. Camera Clock & Reset Controller Binding +------------------------------------------------------------------- + +Required properties : +- compatible: must contain "qcom,camcc-sm8150", "qcom,camcc-sm8150-v2", + "qcom,camcc-kona", "qcom,camcc-kona-v2" or "qcom,lito-camcc" + or "qcom,lito-camcc-v2" or "qcom,lagoon-camcc". +- reg: shall contain base register location and length. +- reg-names: names of registers listed in the same order as in + the reg property. +- clock-names: Shall contain "cfg_ahb_clk" +- clocks: phandle + clock reference to the GCC AHB clock. +- vdd_-supply: The logic rail supply. +- #clock-cells: shall contain 1. + +Example: + clock_camcc: qcom,camcc@ad00000 { + compatible = "qcom,camcc-kona"; + reg = <0xad00000 0x10000>; + reg-names = "cc_base"; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,debugcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,debugcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..551bc05872dc634c758c2a96a5a81235f4eeffe4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,debugcc.txt @@ -0,0 +1,28 @@ +Qualcomm Technologies, Inc. Debug Clock Controller Binding +---------------------------------------------------------- + +Required properties : +- compatible: Shall contain "qcom,kona-debugcc", "qcom,lito-debugcc", + "qcom,bengal-debugcc", "qcom,lagoon-debugcc" + or "qcom,sdm660-debugcc". +- qcom,gcc: phandle to the GCC device node. +- qcom,videocc: phandle to the Video CC device node. +- qcom,camcc: phandle to the Camera CC device node. +- qcom,dispcc: phandle to the Display CC device node. +- qcom,npucc: phandle to the NPU CC device node. +- clock-names: Shall contain "xo_clk_src" +- clocks: phandle + clock reference to the CXO clock. +- #clock-cells : Shall contain 1. + +Example: + clock_debug: qcom,cc-debug { + compatible = "qcom,kona-debugcc"; + qcom,gcc = <&clock_gcc>; + qcom,videocc = <&clock_videocc>; + qcom,camcc = <&clock_camcc>; + qcom,dispcc = <&clock_dispcc>; + qcom,npucc = <&clock_npucc>; + clock-names = "xo_clk_src"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,dispcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,dispcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..de9da0833f1f583f03dbff9054b7f7df8cf8cf77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,dispcc.txt @@ -0,0 +1,44 @@ +Qualcomm Technologies, Inc. Display Clock Controller Binding +------------------------------------------------------------ + +Required properties : + +- compatible : Shall contain one of the following: + "qcom,kona-dispcc", + "qcom,sdm845-dispcc" + "qcom,lito-dispcc" + "qcom,bengal-dispcc" + "qcom,lagoon-dispcc" + "qcom,scuba-dispcc". +- reg : shall contain base register location and length. +- vdd_mm-supply: phandle to the MM_CX rail that needs to be voted on behalf +of the clocks. +- clock-names: Shall contain "cfg_ahb_clk" +- clocks: phandle clock reference to the GCC AHB clock. +- #clock-cells : from common clock binding, shall contain 1. +- #reset-cells : from common reset binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Optional properties : + +- reg-names: Address name. Must be "cc_base". + +Examples: + dispcc: clock-controller@af00000 { + compatible = "qcom,sdm845-dispcc"; + reg = <0xaf00000 0x100000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + clock_dispcc: qcom,dispcc@af00000 { + compatible = "qcom,kona-dispcc"; + reg = <0xaf00000 0x20000>; + reg-names = "cc_base"; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&clock_gcc GCC_DISP_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,dummycc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,dummycc.txt new file mode 100644 index 0000000000000000000000000000000000000000..9463fb6b7f570d78588c311cf4ff6a83fa1b5ed7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,dummycc.txt @@ -0,0 +1,26 @@ +Qualcomm Technologies, Inc. Dummy Clock Controller Binding + +Qualcomm Technologies, Inc. dummy clock controller devices provide +clock API support for driver development during pre-silicon stage. +The clock driver always returns a dummy clock that has no effect on +hardware. + +Required properties: +- compatible: Must be "qcom,dummycc" +- #clock-cells: Must be <1>. This will allow the common clock device + tree framework to recognize _this_ device node as a + clock provider. + +Optional properties: +- clock-output-names: Name of the clock or the clock type. +- #reset-cells: Must be <1>. This will allow the common reset device + tree framework to recognize _this_ device node as a + reset controller provider. + +Example: + clock_gcc: qcom,gcc { + compatible = "qcom,dummycc"; + clock-output-names = "gcc_clocks"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,gcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,gcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..974b5cbe2647f2d47b8e18fbc3694ee0e7597f19 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,gcc.txt @@ -0,0 +1,59 @@ +Qualcomm Global Clock & Reset Controller Binding +------------------------------------------------ + +Required properties : +- compatible : shall contain only one of the following: + + "qcom,gcc-apq8064" + "qcom,gcc-apq8084" + "qcom,gcc-ipq8064" + "qcom,gcc-ipq4019" + "qcom,gcc-ipq8074" + "qcom,gcc-msm8660" + "qcom,gcc-msm8916" + "qcom,gcc-msm8960" + "qcom,gcc-msm8974" + "qcom,gcc-msm8974pro" + "qcom,gcc-msm8974pro-ac" + "qcom,gcc-msm8994" + "qcom,gcc-msm8996" + "qcom,gcc-msm8998" + "qcom,gcc-mdm9615" + "qcom,gcc-sdm845" + "qcom,gcc-kona" + "qcom,gcc-lito" + "qcom,bengal-gcc" + "qcom,lagoon-gcc" + "qcom,gcc-sdm660" + +- reg : shall contain base register location and length +- #clock-cells : shall contain 1 +- #reset-cells : shall contain 1 + +Optional properties : +- #power-domain-cells : shall contain 1 +- Qualcomm TSENS (thermal sensor device) on some devices can +be part of GCC and hence the TSENS properties can also be +part of the GCC/clock-controller node. +For more details on the TSENS properties please refer +Documentation/devicetree/bindings/thermal/qcom-tsens.txt + +Example: + clock-controller@900000 { + compatible = "qcom,gcc-msm8960"; + reg = <0x900000 0x4000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +Example of GCC with TSENS properties: + clock-controller@900000 { + compatible = "qcom,gcc-apq8064"; + reg = <0x00900000 0x4000>; + nvmem-cells = <&tsens_calib>, <&tsens_backup>; + nvmem-cell-names = "calib", "calib_backup"; + #clock-cells = <1>; + #reset-cells = <1>; + #thermal-sensor-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,gpucc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,gpucc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d5a86e5f819fe839f3c094ceccf6140e9c6d03f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,gpucc.txt @@ -0,0 +1,36 @@ +Qualcomm Technologies, Inc. Graphics Clock & Reset Controller Binding +-------------------------------------------------------------------- + +Required properties : +- compatible: shall contain one of the following: + "qcom,gpucc-kona" + "qcom,lito-gpucc". + "qcom,bengal-gpucc" + "qcom,lagoon-gpucc", + "qcom,gpu-sdm660", + "qcom,gpucc-sdm660", + "qcom,gpucc-sdm630". + +- reg: shall contain base register offset and size. +- reg-names: names of registers listed in the same order as in the reg property. + Must contain "cc_base". +- #clock-cells: from common clock binding, shall contain 1. +- #reset-cells: from common reset binding, shall contain 1. +- vdd_cx-supply: The vdd_cx logic rail supply. +- vdd_mx-supply: The vdd_mx logic rail supply. + +Optional properties : +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Example: + + clock_gpucc: clock-controller@3d90000 { + compatible = "qcom,gpucc-kona"; + reg = <0x3d90000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,lcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,lcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3c78aa88038435eccde0b2840550ef8d817d560 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,lcc.txt @@ -0,0 +1,22 @@ +Qualcomm LPASS Clock & Reset Controller Binding +------------------------------------------------ + +Required properties : +- compatible : shall contain only one of the following: + + "qcom,lcc-msm8960" + "qcom,lcc-apq8064" + "qcom,lcc-ipq8064" + "qcom,lcc-mdm9615" + +- reg : shall contain base register location and length +- #clock-cells : shall contain 1 +- #reset-cells : shall contain 1 + +Example: + clock-controller@28000000 { + compatible = "qcom,lcc-ipq8064"; + reg = <0x28000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,mmcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,mmcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7b1bfd257fdfe9119ed18aecfd619b67b96603d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,mmcc.txt @@ -0,0 +1,30 @@ +Qualcomm Multimedia Clock & Reset Controller Binding +---------------------------------------------------- + +Required properties : +- compatible : shall contain only one of the following: + + "qcom,mmcc-apq8064" + "qcom,mmcc-apq8084" + "qcom,mmcc-msm8660" + "qcom,mmcc-msm8960" + "qcom,mmcc-msm8974" + "qcom,mmcc-msm8996" + "qcom,mmcc-sdm660" + "qcom,mmcc-sdm630" + +- reg : shall contain base register location and length +- #clock-cells : shall contain 1 +- #reset-cells : shall contain 1 + +Optional properties : +- #power-domain-cells : shall contain 1 + +Example: + clock-controller@4000000 { + compatible = "qcom,mmcc-msm8960"; + reg = <0x4000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,npucc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,npucc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c5be2b0274cdf9170a4b3e1af0d145d1f2a27c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,npucc.txt @@ -0,0 +1,36 @@ +Qualcomm Technologies, Inc. NPU Clock & Reset Controller Bindings +----------------------------------------------------------------- + +Required properties: +- compatible: Should be "qcom,npucc-kona", + "qcom,npucc-kona-v2", + "qcom,lito-npucc", + "qcom,lito-npucc-v2", + "qcom,lagoon-npucc". +- reg: Shall contain base register addresses and sizes. +- reg-names: Names of the register bases listed in the same order as + in the reg property. Shall include: "cc", "qdsp6ss", + and "qdsp6ss_pll". +- vdd_cx-supply: Phandle of the VDD_CX regulator supply rail that needs + to be voted on behalf of the NPU CC clocks. +- #clock-cells: Shall contain 1. +- #reset-cells: Shall contain 1. + +Optional properties: +- nvmem-cells: list of phandle to the nvmem data cells. +- nvmem-cell-names: names for the each nvmem-cells specified. + +Example: + +clock_npucc: qcom,npucc@9980000 { + compatible = "qcom,npucc-kona"; + reg = <0x9980000 0x10000>, + <0x9800000 0x10000>, + <0x9810000 0x10000>; + reg-names = "cc", "qdsp6ss", "qdsp6ss_pll"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + nvmem-cells = <&npu_efuse>; + nvmem-cell-names = "npu-bin"; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,rpmcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,rpmcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce66170dbd57e70c35fe14c56c41a75cc55f2c8c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,rpmcc.txt @@ -0,0 +1,51 @@ +Qualcomm RPM Clock Controller Binding +------------------------------------------------ +The RPM is a dedicated hardware engine for managing the shared +SoC resources in order to keep the lowest power profile. It +communicates with other hardware subsystems via shared memory +and accepts clock requests, aggregates the requests and turns +the clocks on/off or scales them on demand. + +Required properties : +- compatible : shall contain only one of the following. The generic + compatible "qcom,rpmcc" should be also included. + + "qcom,rpmcc-msm8660", "qcom,rpmcc" + "qcom,rpmcc-apq8060", "qcom,rpmcc" + "qcom,rpmcc-msm8916", "qcom,rpmcc" + "qcom,rpmcc-msm8974", "qcom,rpmcc" + "qcom,rpmcc-apq8064", "qcom,rpmcc" + "qcom,rpmcc-msm8996", "qcom,rpmcc" + "qcom,rpmcc-bengal", "qcom,rpmcc" + "qcom,rpmcc-sdm660", "qcom,rpmcc" + +- #clock-cells : shall contain 1 + +The clock enumerators are defined in +and come in pairs: FOO_CLK followed by FOO_A_CLK. The latter clock +is an "active" clock, which means that the consumer only care that the +clock is available when the apps CPU subsystem is active, i.e. not +suspended or in deep idle. If it is important that the clock keeps running +during system suspend, you need to specify the non-active clock, the one +not containing *_A_* in the enumerator name. + +Example: + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8916"; + qcom,smd-channels = "rpm_requests"; + + rpmcc: clock-controller { + compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc"; + #clock-cells = <1>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,rpmh-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,rpmh-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee15fbe01d82cb2e0afe236384f06554ad9f6d75 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,rpmh-clk.txt @@ -0,0 +1,33 @@ +Qualcomm Technologies, Inc. RPMh Clocks +------------------------------------------------------- + +Resource Power Manager Hardened (RPMh) manages shared resources on +some Qualcomm Technologies Inc. SoCs. It accepts clock requests from +other hardware subsystems via RSC to control clocks. + +Required properties : +- compatible : Shall contain one of the following: + "qcom,kona-rpmh-clk", + "qcom,sdm845-rpmh-clk" + "qcom,lito-rpmh-clk" + "qcom,lagoon-rpmh-clk" + +- #clock-cells : must contain 1 + +Example : + +#include + + &apps_rsc { + rpmhcc: clock-controller { + compatible = "qcom,sdm845-rpmh-clk"; + #clock-cells = <1>; + }; + }; + + &apps_rsc { + rpmhcc: clock-controller { + compatible = "qcom,kona-rpmh-clk"; + #clock-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,spmi-clkdiv.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,spmi-clkdiv.txt new file mode 100644 index 0000000000000000000000000000000000000000..7474aba366074a628c005bba2d051750d87c61c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,spmi-clkdiv.txt @@ -0,0 +1,59 @@ +Qualcomm Technologies, Inc. SPMI PMIC clock divider (clkdiv) + +clkdiv configures the clock frequency of a set of outputs on the PMIC. +These clocks are typically wired through alternate functions on +gpio pins. + +======================= +Properties +======================= + +- compatible + Usage: required + Value type: + Definition: must be "qcom,spmi-clkdiv". + +- reg + Usage: required + Value type: + Definition: base address of CLKDIV peripherals. + +- qcom,num-clkdivs + Usage: required + Value type: + Definition: number of CLKDIV peripherals. + +- clocks: + Usage: required + Value type: + Definition: reference to the xo clock. + +- clock-names: + Usage: required + Value type: + Definition: must be "xo". + +- #clock-cells: + Usage: required + Value type: + Definition: shall contain 1. + +======= +Example +======= + +pm8998_clk_divs: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00>; + #clock-cells = <1>; + qcom,num-clkdivs = <3>; + clocks = <&xo_board>; + clock-names = "xo"; + + assigned-clocks = <&pm8998_clk_divs 1>, + <&pm8998_clk_divs 2>, + <&pm8998_clk_divs 3>; + assigned-clock-rates = <9600000>, + <9600000>, + <9600000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qcom,videocc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,videocc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1fa262392d9c63dd7daed3f7f359cb565461743 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qcom,videocc.txt @@ -0,0 +1,43 @@ +Qualcomm Video Clock & Reset Controller Binding +----------------------------------------------- + +Required properties : +- compatible : shall contain "qcom,sdm845-videocc", "qcom,videocc-kona", + "qcom,videocc-kona-v2", "qcom,lito-videocc" or + "qcom,lagoon-videocc" +- reg : shall contain base register location and length +- clock-names : Shall contain "cfg_ahb_clk" +- clocks : phandle + clock reference to the GCC AHB clock. + +- #clock-cells : from common clock binding, shall contain 1. +- #power-domain-cells : from generic power domain binding, shall contain 1. + +Required properties (kona only): +- vdd_mm-supply : phandle of the voltage regulator supplying the logic rail +- vdd_mx-supply : phandle of the voltage regulator supplying the memory rail + +Optional properties : +- #reset-cells : from common reset binding, shall contain 1. +- nvmem-cells: list of phandle to the nvmem data cells. +- nvmem-cell-names: names for the each nvmem-cells specified. + +Example: + videocc: clock-controller@ab00000 { + compatible = "qcom,sdm845-videocc"; + reg = <0xab00000 0x10000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + }; + +Example with vdd mm/mx supply: + clock_videocc: qcom,videocc@abf0000 { + compatible = "qcom,videocc-kona"; + reg = <0xabf0000 0x10000>; + reg-names = "cc_base"; + vdd_mm-supply = <&pm8150a_s5_level>; + vdd_mx-supply = <&pm8150a_s5_level>; + clock-names = "cfg_ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/qoriq-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/qoriq-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..97f46adac85fa77acef501d640328ea5c3cbd8e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/qoriq-clock.txt @@ -0,0 +1,204 @@ +* Clock Block on Freescale QorIQ Platforms + +Freescale QorIQ chips take primary clocking input from the external +SYSCLK signal. The SYSCLK input (frequency) is multiplied using +multiple phase locked loops (PLL) to create a variety of frequencies +which can then be passed to a variety of internal logic, including +cores and peripheral IP blocks. +Please refer to the Reference Manual for details. + +All references to "1.0" and "2.0" refer to the QorIQ chassis version to +which the chip complies. + +Chassis Version Example Chips +--------------- ------------- +1.0 p4080, p5020, p5040 +2.0 t4240, b4860 + +1. Clock Block Binding + +Required properties: +- compatible: Should contain a chip-specific clock block compatible + string and (if applicable) may contain a chassis-version clock + compatible string. + + Chip-specific strings are of the form "fsl,-clockgen", such as: + * "fsl,p2041-clockgen" + * "fsl,p3041-clockgen" + * "fsl,p4080-clockgen" + * "fsl,p5020-clockgen" + * "fsl,p5040-clockgen" + * "fsl,t4240-clockgen" + * "fsl,b4420-clockgen" + * "fsl,b4860-clockgen" + * "fsl,ls1012a-clockgen" + * "fsl,ls1021a-clockgen" + * "fsl,ls1043a-clockgen" + * "fsl,ls1046a-clockgen" + * "fsl,ls1088a-clockgen" + * "fsl,ls2080a-clockgen" + Chassis-version clock strings include: + * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks + * "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks +- reg: Describes the address of the device's resources within the + address space defined by its parent bus, and resource zero + represents the clock register set + +Optional properties: +- ranges: Allows valid translation between child's address space and + parent's. Must be present if the device has sub-nodes. +- #address-cells: Specifies the number of cells used to represent + physical base addresses. Must be present if the device has + sub-nodes and set to 1 if present +- #size-cells: Specifies the number of cells used to represent + the size of an address. Must be present if the device has + sub-nodes and set to 1 if present +- clock-frequency: Input system clock frequency (SYSCLK) +- clocks: If clock-frequency is not specified, sysclk may be provided + as an input clock. Either clock-frequency or clocks must be + provided. + A second input clock, called "coreclk", may be provided if + core PLLs are based on a different input clock from the + platform PLL. +- clock-names: Required if a coreclk is present. Valid names are + "sysclk" and "coreclk". + +2. Clock Provider + +The clockgen node should act as a clock provider, though in older device +trees the children of the clockgen node are the clock providers. + +When the clockgen node is a clock provider, #clock-cells = <2>. +The first cell of the clock specifier is the clock type, and the +second cell is the clock index for the specified type. + + Type# Name Index Cell + 0 sysclk must be 0 + 1 cmux index (n in CLKCnCSR) + 2 hwaccel index (n in CLKCGnHWACSR) + 3 fman 0 for fm1, 1 for fm2 + 4 platform pll 0=pll, 1=pll/2, 2=pll/3, 3=pll/4 + 4=pll/5, 5=pll/6, 6=pll/7, 7=pll/8 + 5 coreclk must be 0 + +3. Example + + clockgen: global-utilities@e1000 { + compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0"; + clock-frequency = <133333333>; + reg = <0xe1000 0x1000>; + #clock-cells = <2>; + }; + + fman@400000 { + ... + clocks = <&clockgen 3 0>; + ... + }; +} +4. Legacy Child Nodes + +NOTE: These nodes are deprecated. Kernels should continue to support +device trees with these nodes, but new device trees should not use them. + +Most of the bindings are from the common clock binding[1]. + [1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : Should include one of the following: + * "fsl,qoriq-core-pll-1.0" for core PLL clocks (v1.0) + * "fsl,qoriq-core-pll-2.0" for core PLL clocks (v2.0) + * "fsl,qoriq-core-mux-1.0" for core mux clocks (v1.0) + * "fsl,qoriq-core-mux-2.0" for core mux clocks (v2.0) + * "fsl,qoriq-sysclk-1.0": for input system clock (v1.0). + It takes parent's clock-frequency as its clock. + * "fsl,qoriq-sysclk-2.0": for input system clock (v2.0). + It takes parent's clock-frequency as its clock. + * "fsl,qoriq-platform-pll-1.0" for the platform PLL clock (v1.0) + * "fsl,qoriq-platform-pll-2.0" for the platform PLL clock (v2.0) +- #clock-cells: From common clock binding. The number of cells in a + clock-specifier. Should be <0> for "fsl,qoriq-sysclk-[1,2].0" + clocks, or <1> for "fsl,qoriq-core-pll-[1,2].0" clocks. + For "fsl,qoriq-core-pll-[1,2].0" clocks, the single + clock-specifier cell may take the following values: + * 0 - equal to the PLL frequency + * 1 - equal to the PLL frequency divided by 2 + * 2 - equal to the PLL frequency divided by 4 + +Recommended properties: +- clocks: Should be the phandle of input parent clock +- clock-names: From common clock binding, indicates the clock name +- clock-output-names: From common clock binding, indicates the names of + output clocks +- reg: Should be the offset and length of clock block base address. + The length should be 4. + +Legacy Example: +/ { + clockgen: global-utilities@e1000 { + compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0"; + ranges = <0x0 0xe1000 0x1000>; + clock-frequency = <133333333>; + reg = <0xe1000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + sysclk: sysclk { + #clock-cells = <0>; + compatible = "fsl,qoriq-sysclk-1.0"; + clock-output-names = "sysclk"; + }; + + pll0: pll0@800 { + #clock-cells = <1>; + reg = <0x800 0x4>; + compatible = "fsl,qoriq-core-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "pll0", "pll0-div2"; + }; + + pll1: pll1@820 { + #clock-cells = <1>; + reg = <0x820 0x4>; + compatible = "fsl,qoriq-core-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "pll1", "pll1-div2"; + }; + + mux0: mux0@0 { + #clock-cells = <0>; + reg = <0x0 0x4>; + compatible = "fsl,qoriq-core-mux-1.0"; + clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>; + clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2"; + clock-output-names = "cmux0"; + }; + + mux1: mux1@20 { + #clock-cells = <0>; + reg = <0x20 0x4>; + compatible = "fsl,qoriq-core-mux-1.0"; + clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>; + clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2"; + clock-output-names = "cmux1"; + }; + + platform-pll: platform-pll@c00 { + #clock-cells = <1>; + reg = <0xc00 0x4>; + compatible = "fsl,qoriq-platform-pll-1.0"; + clocks = <&sysclk>; + clock-output-names = "platform-pll", "platform-pll-div2"; + }; + }; +}; + +Example for legacy clock consumer: + +/ { + cpu0: PowerPC,e5500@0 { + ... + clocks = <&mux0>; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-div6-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-div6-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae36ab84291988b730e077ce50d208ffaeea8dca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-div6-clocks.txt @@ -0,0 +1,40 @@ +* Renesas CPG DIV6 Clock + +The CPG DIV6 clocks are variable factor clocks provided by the Clock Pulse +Generator (CPG). Their clock input is divided by a configurable factor from 1 +to 64. + +Required Properties: + + - compatible: Must be one of the following + - "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks + - "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks + - "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks + - "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2-W) DIV6 clocks + - "renesas,r8a7793-div6-clock" for R8A7793 (R-Car M2-N) DIV6 clocks + - "renesas,r8a7794-div6-clock" for R8A7794 (R-Car E2) DIV6 clocks + - "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks + and "renesas,cpg-div6-clock" as a fallback. + - reg: Base address and length of the memory resource used by the DIV6 clock + - clocks: Reference to the parent clock(s); either one, four, or eight + clocks must be specified. For clocks with multiple parents, invalid + settings must be specified as "<0>". + - #clock-cells: Must be 0 + + +Optional Properties: + + - clock-output-names: The name of the clock as a free-form string + + +Example +------- + + sdhi2_clk: sdhi2_clk@e615007c { + compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock"; + reg = <0 0xe615007c 0 4>; + clocks = <&pll1_div2_clk>, <&cpg_clocks R8A73A4_CLK_PLL2S>, + <0>, <&extal2_clk>; + #clock-cells = <0>; + clock-output-names = "sdhi2ck"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-mssr.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-mssr.txt new file mode 100644 index 0000000000000000000000000000000000000000..db542abadb75bf0ca395ac0910506bce458fecee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-mssr.txt @@ -0,0 +1,92 @@ +* Renesas Clock Pulse Generator / Module Standby and Software Reset + +On Renesas ARM SoCs (SH/R-Mobile, R-Car, RZ), the CPG (Clock Pulse Generator) +and MSSR (Module Standby and Software Reset) blocks are intimately connected, +and share the same register block. + +They provide the following functionalities: + - The CPG block generates various core clocks, + - The MSSR block provides two functions: + 1. Module Standby, providing a Clock Domain to control the clock supply + to individual SoC devices, + 2. Reset Control, to perform a software reset of individual SoC devices. + +Required Properties: + - compatible: Must be one of: + - "renesas,r8a7743-cpg-mssr" for the r8a7743 SoC (RZ/G1M) + - "renesas,r8a7745-cpg-mssr" for the r8a7745 SoC (RZ/G1E) + - "renesas,r8a77470-cpg-mssr" for the r8a77470 SoC (RZ/G1C) + - "renesas,r8a7790-cpg-mssr" for the r8a7790 SoC (R-Car H2) + - "renesas,r8a7791-cpg-mssr" for the r8a7791 SoC (R-Car M2-W) + - "renesas,r8a7792-cpg-mssr" for the r8a7792 SoC (R-Car V2H) + - "renesas,r8a7793-cpg-mssr" for the r8a7793 SoC (R-Car M2-N) + - "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2) + - "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3) + - "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W) + - "renesas,r8a77965-cpg-mssr" for the r8a77965 SoC (R-Car M3-N) + - "renesas,r8a77970-cpg-mssr" for the r8a77970 SoC (R-Car V3M) + - "renesas,r8a77980-cpg-mssr" for the r8a77980 SoC (R-Car V3H) + - "renesas,r8a77990-cpg-mssr" for the r8a77990 SoC (R-Car E3) + - "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3) + + - reg: Base address and length of the memory resource used by the CPG/MSSR + block + + - clocks: References to external parent clocks, one entry for each entry in + clock-names + - clock-names: List of external parent clock names. Valid names are: + - "extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7792, + r8a7793, r8a7794, r8a7795, r8a7796, r8a77965, r8a77970, + r8a77980, r8a77990, r8a77995) + - "extalr" (r8a7795, r8a7796, r8a77965, r8a77970, r8a77980) + - "usb_extal" (r8a7743, r8a7745, r8a77470, r8a7790, r8a7791, r8a7793, + r8a7794) + + - #clock-cells: Must be 2 + - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" + and a core clock reference, as defined in + . + - For module clocks, the two clock specifier cells must be "CPG_MOD" and + a module number, as defined in the datasheet. + + - #power-domain-cells: Must be 0 + - SoC devices that are part of the CPG/MSSR Clock Domain and can be + power-managed through Module Standby should refer to the CPG device + node in their "power-domains" property, as documented by the generic PM + Domain bindings in + Documentation/devicetree/bindings/power/power_domain.txt. + + - #reset-cells: Must be 1 + - The single reset specifier cell must be the module number, as defined + in the datasheet. + + +Examples +-------- + + - CPG device node: + + cpg: clock-controller@e6150000 { + compatible = "renesas,r8a7795-cpg-mssr"; + reg = <0 0xe6150000 0 0x1000>; + clocks = <&extal_clk>, <&extalr_clk>; + clock-names = "extal", "extalr"; + #clock-cells = <2>; + #power-domain-cells = <0>; + #reset-cells = <1>; + }; + + + - CPG/MSSR Clock Domain member device node: + + scif2: serial@e6e88000 { + compatible = "renesas,scif-r8a7795", "renesas,scif"; + reg = <0 0xe6e88000 0 64>; + interrupts = ; + clocks = <&cpg CPG_MOD 310>; + clock-names = "fck"; + dmas = <&dmac1 0x13>, <&dmac1 0x12>; + dma-names = "tx", "rx"; + power-domains = <&cpg>; + resets = <&cpg 310>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-mstp-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-mstp-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..da578ebdda2889fc1dad50c671bc274af7d38169 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,cpg-mstp-clocks.txt @@ -0,0 +1,60 @@ +* Renesas CPG Module Stop (MSTP) Clocks + +The CPG can gate SoC device clocks. The gates are organized in groups of up to +32 gates. + +This device tree binding describes a single 32 gate clocks group per node. +Clocks are referenced by user nodes by the MSTP node phandle and the clock +index in the group, from 0 to 31. + +Required Properties: + + - compatible: Must be one of the following + - "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks + - "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks + - "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks + - "renesas,r8a7778-mstp-clocks" for R8A7778 (R-Car M1) MSTP gate clocks + - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks + - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks + - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2-W) MSTP gate clocks + - "renesas,r8a7792-mstp-clocks" for R8A7792 (R-Car V2H) MSTP gate clocks + - "renesas,r8a7793-mstp-clocks" for R8A7793 (R-Car M2-N) MSTP gate clocks + - "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks + - "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks + and "renesas,cpg-mstp-clocks" as a fallback. + - reg: Base address and length of the I/O mapped registers used by the MSTP + clocks. The first register is the clock control register and is mandatory. + The second register is the clock status register and is optional when not + implemented in hardware. + - clocks: Reference to the parent clocks, one per output clock. The parents + must appear in the same order as the output clocks. + - #clock-cells: Must be 1 + - clock-output-names: The name of the clocks as free-form strings + - clock-indices: Indices of the gate clocks into the group (0 to 31) + +The clocks, clock-output-names and clock-indices properties contain one entry +per gate clock. The MSTP groups are sparsely populated. Unimplemented gate +clocks must not be declared. + + +Example +------- + + #include + + mstp3_clks: mstp3_clks@e615013c { + compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; + reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>; + clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>, + <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, + <&mmc0_clk>; + #clock-cells = <1>; + clock-output-names = + "tpu0", "mmcif1", "sdhi3", "sdhi2", + "sdhi1", "sdhi0", "mmcif0"; + clock-indices = < + R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3 + R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 + R8A7790_CLK_MMCIF0 + >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,h8300-div-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,h8300-div-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..399e0da22348b19e03ca0dab5339d7f61e880e26 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,h8300-div-clock.txt @@ -0,0 +1,24 @@ +* Renesas H8/300 divider clock + +Required Properties: + + - compatible: Must be "renesas,h8300-div-clock" + + - clocks: Reference to the parent clocks ("extal1" and "extal2") + + - #clock-cells: Must be 1 + + - reg: Base address and length of the divide rate selector + + - renesas,width: bit width of selector + +Example +------- + + cclk: cclk { + compatible = "renesas,h8300-div-clock"; + clocks = <&xclk>; + #clock-cells = <0>; + reg = <0xfee01b 2>; + renesas,width = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,h8s2678-pll-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,h8s2678-pll-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..500cdadbceb731bbba2d3e87fa2e76428ca56951 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,h8s2678-pll-clock.txt @@ -0,0 +1,23 @@ +Renesas H8S2678 PLL clock + +This device is Clock multiplyer + +Required Properties: + + - compatible: Must be "renesas,h8s2678-pll-clock" + + - clocks: Reference to the parent clocks + + - #clock-cells: Must be 0 + + - reg: Two rate selector (Multiply / Divide) register address + +Example +------- + + pllclk: pllclk { + compatible = "renesas,h8s2678-pll-clock"; + clocks = <&xclk>; + #clock-cells = <0>; + reg = <0xfee03b 2>, <0xfee045 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a73a4-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a73a4-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..ece92393e80d464832f07e0c1fb798b672ec5e89 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a73a4-cpg-clocks.txt @@ -0,0 +1,33 @@ +* Renesas R8A73A4 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R8A73A4 SoC. It includes five PLLs +and several fixed ratio dividers. + +Required Properties: + + - compatible: Must be "renesas,r8a73a4-cpg-clocks" + + - reg: Base address and length of the memory resource used by the CPG + + - clocks: Reference to the parent clocks ("extal1" and "extal2") + + - #clock-cells: Must be 1 + + - clock-output-names: The names of the clocks. Supported clocks are "main", + "pll0", "pll1", "pll2", "pll2s", "pll2h", "z", "z2", "i", "m3", "b", + "m1", "m2", "zx", "zs", and "hp". + + +Example +------- + + cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,r8a73a4-cpg-clocks"; + reg = <0 0xe6150000 0 0x10000>; + clocks = <&extal1_clk>, <&extal2_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll0", "pll1", "pll2", + "pll2s", "pll2h", "z", "z2", + "i", "m3", "b", "m1", "m2", + "zx", "zs", "hp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7740-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7740-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c03302f86edfb836755ef7c747f81d0fca438f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7740-cpg-clocks.txt @@ -0,0 +1,41 @@ +These bindings should be considered EXPERIMENTAL for now. + +* Renesas R8A7740 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R8A7740 SoC. It includes three PLLs +and several fixed ratio and variable ratio dividers. + +Required Properties: + + - compatible: Must be "renesas,r8a7740-cpg-clocks" + + - reg: Base address and length of the memory resource used by the CPG + + - clocks: Reference to the three parent clocks + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are + "system", "pllc0", "pllc1", "pllc2", "r", "usb24s", "i", "zg", "b", + "m1", "hp", "hpp", "usbp", "s", "zb", "m3", and "cp". + + - renesas,mode: board-specific settings of the MD_CK* bits + + +Example +------- + +cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,r8a7740-cpg-clocks"; + reg = <0xe6150000 0x10000>; + clocks = <&extal1_clk>, <&extal2_clk>, <&extalr_clk>; + #clock-cells = <1>; + clock-output-names = "system", "pllc0", "pllc1", + "pllc2", "r", + "usb24s", + "i", "zg", "b", "m1", "hp", + "hpp", "usbp", "s", "zb", "m3", + "cp"; +}; + +&cpg_clocks { + renesas,mode = <0x05>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7778-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7778-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cc4c0330b534660d97758ce9a7e8f304670db8a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7778-cpg-clocks.txt @@ -0,0 +1,47 @@ +* Renesas R8A7778 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R8A7778. It includes two PLLs and +several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. + +Required Properties: + + - compatible: Must be "renesas,r8a7778-cpg-clocks" + - reg: Base address and length of the memory resource used by the CPG + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are + "plla", "pllb", "b", "out", "p", "s", and "s1". + - #power-domain-cells: Must be 0 + +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock should refer to the CPG device node in their +"power-domains" property, as documented by the generic PM domain bindings in +Documentation/devicetree/bindings/power/power_domain.txt. + + +Examples +-------- + + - CPG device node: + + cpg_clocks: cpg_clocks@ffc80000 { + compatible = "renesas,r8a7778-cpg-clocks"; + reg = <0xffc80000 0x80>; + #clock-cells = <1>; + clocks = <&extal_clk>; + clock-output-names = "plla", "pllb", "b", + "out", "p", "s", "s1"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + sdhi0: sd@ffe4c000 { + compatible = "renesas,sdhi-r8a7778"; + reg = <0xffe4c000 0x100>; + interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7778_CLK_SDHI0>; + power-domains = <&cpg_clocks>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7779-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7779-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c81547c29f568e8196537111891c19820b288f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r8a7779-cpg-clocks.txt @@ -0,0 +1,49 @@ +* Renesas R8A7779 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R8A7779. It includes one PLL and +several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. + +Required Properties: + + - compatible: Must be "renesas,r8a7779-cpg-clocks" + - reg: Base address and length of the memory resource used by the CPG + + - clocks: Reference to the parent clock + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are "plla", + "z", "zs", "s", "s1", "p", "b", "out". + - #power-domain-cells: Must be 0 + +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock should refer to the CPG device node in their +"power-domains" property, as documented by the generic PM domain bindings in +Documentation/devicetree/bindings/power/power_domain.txt. + + +Examples +-------- + + - CPG device node: + + cpg_clocks: cpg_clocks@ffc80000 { + compatible = "renesas,r8a7779-cpg-clocks"; + reg = <0xffc80000 0x30>; + clocks = <&extal_clk>; + #clock-cells = <1>; + clock-output-names = "plla", "z", "zs", "s", "s1", "p", + "b", "out"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + sata: sata@fc600000 { + compatible = "renesas,sata-r8a7779", "renesas,rcar-sata"; + reg = <0xfc600000 0x2000>; + interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7779_CLK_SATA>; + power-domains = <&cpg_clocks>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r9a06g032-sysctrl.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r9a06g032-sysctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..d60b99756bb9f792426a030af49a4c3a75c8ef47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,r9a06g032-sysctrl.txt @@ -0,0 +1,43 @@ +* Renesas R9A06G032 SYSCTRL + +Required Properties: + + - compatible: Must be: + - "renesas,r9a06g032-sysctrl" + - reg: Base address and length of the SYSCTRL IO block. + - #clock-cells: Must be 1 + - clocks: References to the parent clocks: + - external 40mhz crystal. + - external (optional) 32.768khz + - external (optional) jtag input + - external (optional) RGMII_REFCLK + - clock-names: Must be: + clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext"; + +Examples +-------- + + - SYSCTRL node: + + sysctrl: system-controller@4000c000 { + compatible = "renesas,r9a06g032-sysctrl"; + reg = <0x4000c000 0x1000>; + #clock-cells = <1>; + + clocks = <&ext_mclk>, <&ext_rtc_clk>, + <&ext_jtag_clk>, <&ext_rgmii_ref>; + clock-names = "mclk", "rtc", "jtag", "rgmii_ref_ext"; + }; + + - Other nodes can use the clocks provided by SYSCTRL as in: + + #include + uart0: serial@40060000 { + compatible = "snps,dw-apb-uart"; + reg = <0x40060000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&sysctrl R9A06G032_CLK_UART0>; + clock-names = "baudclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8c05bb4116eae54b663c821476f2eeaa6bb9415 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt @@ -0,0 +1,60 @@ +* Renesas R-Car Gen2 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R-Car Gen2 SoCs. It includes three PLLs +and several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. + +Required Properties: + + - compatible: Must be one of + - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG + - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG + - "renesas,r8a7792-cpg-clocks" for the r8a7792 CPG + - "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG + - "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG + and "renesas,rcar-gen2-cpg-clocks" as a fallback. + + - reg: Base address and length of the memory resource used by the CPG + + - clocks: References to the parent clocks: first to the EXTAL clock, second + to the USB_EXTAL clock + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are "main", + "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1", "z", "rcan", and + "adsp" + - #power-domain-cells: Must be 0 + +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock should refer to the CPG device node in their +"power-domains" property, as documented by the generic PM domain bindings in +Documentation/devicetree/bindings/power/power_domain.txt. + + +Examples +-------- + + - CPG device node: + + cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,r8a7790-cpg-clocks", + "renesas,rcar-gen2-cpg-clocks"; + reg = <0 0xe6150000 0 0x1000>; + clocks = <&extal_clk &usb_extal_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll0, "pll1", "pll3", + "lb", "qspi", "sdh", "sd0", "sd1", "z", + "rcan", "adsp"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + thermal@e61f0000 { + compatible = "renesas,thermal-r8a7790", "renesas,rcar-thermal"; + reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>; + interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks R8A7790_CLK_THERMAL>; + power-domains = <&cpg_clocks>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rcar-usb2-clock-sel.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rcar-usb2-clock-sel.txt new file mode 100644 index 0000000000000000000000000000000000000000..e96e085271c134f4889d08febddbab10141f6235 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rcar-usb2-clock-sel.txt @@ -0,0 +1,55 @@ +* Renesas R-Car USB 2.0 clock selector + +This file provides information on what the device node for the R-Car USB 2.0 +clock selector. + +If you connect an external clock to the USB_EXTAL pin only, you should set +the clock rate to "usb_extal" node only. +If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module +is not needed because this is default setting. (Of course, you can set the +clock rates to both "usb_extal" and "usb_xtal" nodes. + +Case 1: An external clock connects to R-Car SoC + +----------+ +--- R-Car ---------------------+ + |External |---|USB_EXTAL ---> all usb channels| + |clock | |USB_XTAL | + +----------+ +-------------------------------+ +In this case, we need this driver with "usb_extal" clock. + +Case 2: An oscillator connects to R-Car SoC + +----------+ +--- R-Car ---------------------+ + |Oscillator|---|USB_EXTAL -+-> all usb channels| + | |---|USB_XTAL --+ | + +----------+ +-------------------------------+ +In this case, we don't need this selector. + +Required properties: +- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of + an R8A7795 SoC. + "renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of + an R8A7796 SoC. + "renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3 + compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: offset and length of the USB 2.0 clock selector register block. +- clocks: A list of phandles and specifier pairs. +- clock-names: Name of the clocks. + - The functional clock must be "ehci_ohci" + - The USB_EXTAL clock pin must be "usb_extal" + - The USB_XTAL clock pin must be "usb_xtal" +- #clock-cells: Must be 0 + +Example (R-Car H3): + + usb2_clksel: clock-controller@e6590630 { + compatible = "renesas,r8a77950-rcar-usb2-clock-sel", + "renesas,rcar-gen3-usb2-clock-sel"; + reg = <0 0xe6590630 0 0x02>; + clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>; + clock-names = "ehci_ohci", "usb_extal", "usb_xtal"; + #clock-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rz-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rz-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ff3e2774ed8d1d0fd46cbf5895346f62252c5b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,rz-cpg-clocks.txt @@ -0,0 +1,53 @@ +* Renesas RZ/A1 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the RZ/A1 SoCs. It includes the PLL, variable +CPU and GPU clocks, and several fixed ratio dividers. +The CPG also provides a Clock Domain for SoC devices, in combination with the +CPG Module Stop (MSTP) Clocks. + +Required Properties: + + - compatible: Must be one of + - "renesas,r7s72100-cpg-clocks" for the r7s72100 CPG + and "renesas,rz-cpg-clocks" as a fallback. + - reg: Base address and length of the memory resource used by the CPG + - clocks: References to possible parent clocks. Order must match clock modes + in the datasheet. For the r7s72100, this is extal, usb_x1. + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are "pll", + "i", and "g" + - #power-domain-cells: Must be 0 + +SoC devices that are part of the CPG/MSTP Clock Domain and can be power-managed +through an MSTP clock should refer to the CPG device node in their +"power-domains" property, as documented by the generic PM domain bindings in +Documentation/devicetree/bindings/power/power_domain.txt. + + +Examples +-------- + + - CPG device node: + + cpg_clocks: cpg_clocks@fcfe0000 { + #clock-cells = <1>; + compatible = "renesas,r7s72100-cpg-clocks", + "renesas,rz-cpg-clocks"; + reg = <0xfcfe0000 0x18>; + clocks = <&extal_clk>, <&usb_x1_clk>; + clock-output-names = "pll", "i", "g"; + #power-domain-cells = <0>; + }; + + + - CPG/MSTP Clock Domain member device node: + + mtu2: timer@fcff0000 { + compatible = "renesas,mtu2-r7s72100", "renesas,mtu2"; + reg = <0xfcff0000 0x400>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tgi0a"; + clocks = <&mstp3_clks R7S72100_CLK_MTU2>; + clock-names = "fck"; + power-domains = <&cpg_clocks>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/renesas,sh73a0-cpg-clocks.txt b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,sh73a0-cpg-clocks.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8978ec94831fc6beb8787b0b12fd88b70920dcd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/renesas,sh73a0-cpg-clocks.txt @@ -0,0 +1,35 @@ +These bindings should be considered EXPERIMENTAL for now. + +* Renesas SH73A0 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the SH73A0 SoC. It includes four PLLs +and several fixed ratio dividers. + +Required Properties: + + - compatible: Must be "renesas,sh73a0-cpg-clocks" + + - reg: Base address and length of the memory resource used by the CPG + + - clocks: Reference to the parent clocks ("extal1" and "extal2") + + - #clock-cells: Must be 1 + + - clock-output-names: The names of the clocks. Supported clocks are "main", + "pll0", "pll1", "pll2", "pll3", "dsi0phy", "dsi1phy", "zg", "m3", "b", + "m1", "m2", "z", "zx", and "hp". + + +Example +------- + + cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,sh73a0-cpg-clocks"; + reg = <0 0xe6150000 0 0x10000>; + clocks = <&extal1_clk>, <&extal2_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll0", "pll1", "pll2", + "pll3", "dsi0phy", "dsi1phy", + "zg", "m3", "b", "m1", "m2", + "z", "zx", "hp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,px30-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,px30-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..39f0c1ac84ee0939263d1416f43c5831158d50d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,px30-cru.txt @@ -0,0 +1,65 @@ +* Rockchip PX30 Clock and Reset Unit + +The PX30 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: PMU for CRU should be "rockchip,px30-pmu-cru" +- compatible: CRU should be "rockchip,px30-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing, pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/px30-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "i2sx_clkin" - external I2S clock - optional, + - "gmac_clkin" - external GMAC clock - optional + +Example: Clock controller node: + + pmucru: clock-controller@ff2bc000 { + compatible = "rockchip,px30-pmucru"; + reg = <0x0 0xff2bc000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cru: clock-controller@ff2b0000 { + compatible = "rockchip,px30-cru"; + reg = <0x0 0xff2b0000 0x0 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@ff030000 { + compatible = "rockchip,px30-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff030000 0x0 0x100>; + interrupts = ; + clocks = <&pmucru SCLK_UART0_PMU>, <&pmucru PCLK_UART0_PMU>; + clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3036-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3036-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..20df350b9ef3d491b3e2e714f8877d74477afcd8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3036-cru.txt @@ -0,0 +1,56 @@ +* Rockchip RK3036 Clock and Reset Unit + +The RK3036 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3036-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3036-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "ext_i2s" - external I2S clock - optional, + - "rmii_clkin" - external EMAC clock - optional + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3036-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@20060000 { + compatible = "snps,dw-apb-uart"; + reg = <0x20060000 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3128-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3128-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f8744fd301b23609f924873f325b9fc4e0c98a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3128-cru.txt @@ -0,0 +1,58 @@ +* Rockchip RK3126/RK3128 Clock and Reset Unit + +The RK3126/RK3128 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3126-cru" or "rockchip,rk3128-cru" + "rockchip,rk3126-cru" - controller compatible with RK3126 SoC. + "rockchip,rk3128-cru" - controller compatible with RK3128 SoC. +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3128-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "ext_i2s" - external I2S clock - optional, + - "gmac_clkin" - external GMAC clock - optional + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3128-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart2: serial@20068000 { + compatible = "rockchip,serial"; + reg = <0x20068000 0x100>; + interrupts = ; + clock-frequency = <24000000>; + clocks = <&cru SCLK_UART2>, <&cru PCLK_UART2>; + clock-names = "sclk_uart", "pclk_uart"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3188-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3188-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f368530a2e4397653f1bc5069b0ed0587d507bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3188-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3188/RK3066 Clock and Reset Unit + +The RK3188/RK3066 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3188-cru", "rockchip,rk3188a-cru" or + "rockchip,rk3066a-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3188-cru.h and +dt-bindings/clock/rk3066-cru.h headers and can be used in device tree sources. +Similar macros exist for the reset sources in these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "xin27m" - 27mhz crystal input on rk3066 - optional, + - "ext_hsadc" - external HSADC clock - optional, + - "ext_cif0" - external camera clock - optional, + - "ext_rmii" - external RMII clock - optional, + - "ext_jtag" - externalJTAG clock - optional + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3188-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3228-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3228-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..f323048127eb0d8aa3adf72605792cc92c4dc7b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3228-cru.txt @@ -0,0 +1,58 @@ +* Rockchip RK3228 Clock and Reset Unit + +The RK3228 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3228-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3228-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "ext_i2s" - external I2S clock - optional, + - "ext_gmac" - external GMAC clock - optional + - "ext_hsadc" - external HSADC clock - optional + - "phy_50m_out" - output clock of the pll in the mac phy + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3228-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10110000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10110000 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3288-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3288-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..8cb47c39ba53922e100bff2efd10420ed5af626a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3288-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3288 Clock and Reset Unit + +The RK3288 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3288-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3288-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_hsadc" - external HSADC clock - optional, + - "ext_edp_24m" - external display port clock - optional, + - "ext_vip" - external VIP clock - optional, + - "ext_isp" - external ISP clock - optional, + - "ext_jtag" - external JTAG clock - optional + +Example: Clock controller node: + + cru: cru@20000000 { + compatible = "rockchip,rk3188-cru"; + reg = <0x20000000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3328-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3328-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..904ae682ea90216ad9c6f07d2f4d7666635693eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3328-cru.txt @@ -0,0 +1,58 @@ +* Rockchip RK3328 Clock and Reset Unit + +The RK3328 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3328-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "clkin_i2s" - external I2S clock - optional, + - "gmac_clkin" - external GMAC clock - optional + - "phy_50m_out" - output clock of the pll in the mac phy + - "hdmi_phy" - output clock of the hdmi phy pll - optional + +Example: Clock controller node: + + cru: clock-controller@ff440000 { + compatible = "rockchip,rk3328-cru"; + reg = <0x0 0xff440000 0x0 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@ff120000 { + compatible = "snps,dw-apb-uart"; + reg = <0xff120000 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3368-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3368-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c8bbcfed8d22f04a2690a72afdc643f177c318f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3368-cru.txt @@ -0,0 +1,61 @@ +* Rockchip RK3368 Clock and Reset Unit + +The RK3368 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rk3368-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing, pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3368-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_gmac" - external GMAC clock - optional + - "ext_hsadc" - external HSADC clock - optional, + - "ext_isp" - external ISP clock - optional, + - "ext_jtag" - external JTAG clock - optional + - "ext_vip" - external VIP clock - optional, + - "usbotg_out" - output clock of the pll in the otg phy + +Example: Clock controller node: + + cru: clock-controller@ff760000 { + compatible = "rockchip,rk3368-cru"; + reg = <0x0 0xff760000 0x0 0x1000>; + rockchip,grf = <&grf>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10124000 { + compatible = "snps,dw-apb-uart"; + reg = <0x10124000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3399-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3399-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bc56fae90ac98b4cf626e7d433210b952db815a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rk3399-cru.txt @@ -0,0 +1,68 @@ +* Rockchip RK3399 Clock and Reset Unit + +The RK3399 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: PMU for CRU should be "rockchip,rk3399-pmucru" +- compatible: CRU should be "rockchip,rk3399-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files". + It is used for GRF muxes, if missing any muxes present in the GRF will not + be available. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rk3399-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "xin32k" - rtc clock - optional, + - "clkin_gmac" - external GMAC clock - optional, + - "clkin_i2s" - external I2S clock - optional, + - "pclkin_cif" - external ISP clock - optional, + - "clk_usbphy0_480m" - output clock of the pll in the usbphy0 + - "clk_usbphy1_480m" - output clock of the pll in the usbphy1 + +Example: Clock controller node: + + pmucru: pmu-clock-controller@ff750000 { + compatible = "rockchip,rk3399-pmucru"; + reg = <0x0 0xff750000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cru: clock-controller@ff760000 { + compatible = "rockchip,rk3399-cru"; + reg = <0x0 0xff760000 0x0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@ff1a0000 { + compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart"; + reg = <0x0 0xff180000 0x0 0x100>; + clocks = <&cru SCLK_UART0>, <&cru PCLK_UART0>; + clock-names = "baudclk", "apb_pclk"; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rv1108-cru.txt b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rv1108-cru.txt new file mode 100644 index 0000000000000000000000000000000000000000..161326a4f9c1feebe41d0ee38e8089c769043dd1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/rockchip,rv1108-cru.txt @@ -0,0 +1,59 @@ +* Rockchip RV1108 Clock and Reset Unit + +The RV1108 clock controller generates and supplies clock to various +controllers within the SoC and also implements a reset controller for SoC +peripherals. + +Required Properties: + +- compatible: should be "rockchip,rv1108-cru" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. +- #reset-cells: should be 1. + +Optional Properties: + +- rockchip,grf: phandle to the syscon managing the "general register files" + If missing pll rates are not changeable, due to the missing pll lock status. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. All available clocks are defined as +preprocessor macros in the dt-bindings/clock/rv1108-cru.h headers and can be +used in device tree sources. Similar macros exist for the reset sources in +these files. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xin24m" - crystal input - required, + - "ext_vip" - external VIP clock - optional + - "ext_i2s" - external I2S clock - optional + - "ext_gmac" - external GMAC clock - optional + - "hdmiphy" - external clock input derived from HDMI PHY - optional + - "usbphy" - external clock input derived from USB PHY - optional + +Example: Clock controller node: + + cru: cru@20200000 { + compatible = "rockchip,rv1108-cru"; + reg = <0x20200000 0x1000>; + rockchip,grf = <&grf>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller: + + uart0: serial@10230000 { + compatible = "rockchip,rv1108-uart", "snps,dw-apb-uart"; + reg = <0x10230000 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&cru SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s2mps11.txt b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s2mps11.txt new file mode 100644 index 0000000000000000000000000000000000000000..2726c1d58a79dd6a1eb2dfb8a3555dccc0e17cf0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s2mps11.txt @@ -0,0 +1,49 @@ +Binding for Samsung S2M and S5M family clock generator block +============================================================ + +This is a part of device tree bindings for S2M and S5M family multi-function +devices. +More information can be found in bindings/mfd/sec-core.txt file. + +The S2MPS11/13/15 and S5M8767 provide three(AP/CP/BT) buffered 32.768 kHz +outputs. The S2MPS14 provides two (AP/BT) buffered 32.768 KHz outputs. + +To register these as clocks with common clock framework instantiate under +main device node a sub-node named "clocks". + +It uses the common clock binding documented in: + - Documentation/devicetree/bindings/clock/clock-bindings.txt + + +Required properties of the "clocks" sub-node: + - #clock-cells: should be 1. + - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps13-clk", + "samsung,s2mps14-clk", "samsung,s5m8767-clk" + The S2MPS15 uses the same compatible as S2MPS13, as both provides similar + clocks. + + +Each clock is assigned an identifier and client nodes use this identifier +to specify the clock which they consume. + Clock ID Devices + ---------------------------------------------------------- + 32KhzAP 0 S2MPS11/13/14/15, S5M8767 + 32KhzCP 1 S2MPS11/13/15, S5M8767 + 32KhzBT 2 S2MPS11/13/14/15, S5M8767 + +Include dt-bindings/clock/samsung,s2mps11.h file to use preprocessor defines +in device tree sources. + + +Example: + + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + + s2m_osc: clocks { + compatible = "samsung,s2mps11-clk"; + #clock-cells = <1>; + clock-output-names = "xx", "yy", "zz"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2410-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2410-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..2632d3f130045ff4523b07f676ed126200cdd4b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2410-clock.txt @@ -0,0 +1,49 @@ +* Samsung S3C2410 Clock Controller + +The S3C2410 clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to the s3c2410, +s3c2440 and s3c2442 SoCs in the s3c24x family. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,s3c2410-clock" - controller compatible with S3C2410 SoC. + - "samsung,s3c2440-clock" - controller compatible with S3C2440 SoC. + - "samsung,s3c2442-clock" - controller compatible with S3C2442 SoC. +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular SoC. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s3c2410.h header and can be used in device +tree sources. + +External clocks: + +The xti clock used as input for the plls is generated outside the SoC. It is +expected that is are defined using standard clock bindings with a +clock-output-names value of "xti". + +Example: Clock controller node: + + clocks: clock-controller@4c000000 { + compatible = "samsung,s3c2410-clock"; + reg = <0x4c000000 0x20>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + serial@50004000 { + compatible = "samsung,s3c2440-uart"; + reg = <0x50004000 0x4000>; + interrupts = <1 23 3 4>, <1 23 4 4>; + clock-names = "uart", "clk_uart_baud2"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2412-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2412-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..21a8c23e658f3458167124a20a3f700b5a8566b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2412-clock.txt @@ -0,0 +1,49 @@ +* Samsung S3C2412 Clock Controller + +The S3C2412 clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to the s3c2412 +and s3c2413 SoCs in the s3c24x family. + +Required Properties: + +- compatible: should be "samsung,s3c2412-clock" +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular SoC. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s3c2412.h header and can be used in device +tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xti" - crystal input - required, + - "ext" - external clock source - optional, + +Example: Clock controller node: + + clocks: clock-controller@4c000000 { + compatible = "samsung,s3c2412-clock"; + reg = <0x4c000000 0x20>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + serial@50004000 { + compatible = "samsung,s3c2412-uart"; + reg = <0x50004000 0x4000>; + interrupts = <1 23 3 4>, <1 23 4 4>; + clock-names = "uart", "clk_uart_baud2", "clk_uart_baud3"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, + <&clocks SCLK_UART>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2443-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2443-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..985c0f574e9a831cbef4a874587eb12c133c7625 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c2443-clock.txt @@ -0,0 +1,55 @@ +* Samsung S3C2443 Clock Controller + +The S3C2443 clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to all SoCs in +the s3c24x family starting with the s3c2443. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,s3c2416-clock" - controller compatible with S3C2416 SoC. + - "samsung,s3c2443-clock" - controller compatible with S3C2443 SoC. + - "samsung,s3c2450-clock" - controller compatible with S3C2450 SoC. +- reg: physical base address of the controller and length of memory mapped + region. +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular SoC. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s3c2443.h header and can be used in device +tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xti" - crystal input - required, + - "ext" - external clock source - optional, + - "ext_i2s" - external I2S clock - optional, + - "ext_uart" - external uart clock - optional, + +Example: Clock controller node: + + clocks: clock-controller@4c000000 { + compatible = "samsung,s3c2416-clock"; + reg = <0x4c000000 0x40>; + #clock-cells = <1>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + serial@50004000 { + compatible = "samsung,s3c2440-uart"; + reg = <0x50004000 0x4000>; + interrupts = <1 23 3 4>, <1 23 4 4>; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART0>, <&clocks PCLK_UART0>, + <&clocks SCLK_UART>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c64xx-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c64xx-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..872ee8e0f041258956a22ae31a1c4d2236597166 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s3c64xx-clock.txt @@ -0,0 +1,76 @@ +* Samsung S3C64xx Clock Controller + +The S3C64xx clock controller generates and supplies clock to various controllers +within the SoC. The clock binding described here is applicable to all SoCs in +the S3C64xx family. + +Required Properties: + +- compatible: should be one of the following. + - "samsung,s3c6400-clock" - controller compatible with S3C6400 SoC. + - "samsung,s3c6410-clock" - controller compatible with S3C6410 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Some of the clocks are available only +on a particular S3C64xx SoC and this is specified where applicable. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/samsung,s3c64xx-clock.h header and can be used in device +tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "fin_pll" - PLL input clock (xtal/extclk) - required, + - "xusbxti" - USB xtal - required, + - "iiscdclk0" - I2S0 codec clock - optional, + - "iiscdclk1" - I2S1 codec clock - optional, + - "iiscdclk2" - I2S2 codec clock - optional, + - "pcmcdclk0" - PCM0 codec clock - optional, + - "pcmcdclk1" - PCM1 codec clock - optional, only S3C6410. + +Example: Clock controller node: + + clock: clock-controller@7e00f000 { + compatible = "samsung,s3c6410-clock"; + reg = <0x7e00f000 0x1000>; + #clock-cells = <1>; + }; + +Example: Required external clocks: + + fin_pll: clock-fin-pll { + compatible = "fixed-clock"; + clock-output-names = "fin_pll"; + clock-frequency = <12000000>; + #clock-cells = <0>; + }; + + xusbxti: clock-xusbxti { + compatible = "fixed-clock"; + clock-output-names = "xusbxti"; + clock-frequency = <48000000>; + #clock-cells = <0>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + uart0: serial@7f005000 { + compatible = "samsung,s3c6400-uart"; + reg = <0x7f005000 0x100>; + interrupt-parent = <&vic1>; + interrupts = <5>; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clock PCLK_UART0>, <&clocks PCLK_UART0>, + <&clock SCLK_UART>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s5pv210-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s5pv210-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..15b48e20a061f8010a59209dadeca415b6d5dbb7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/samsung,s5pv210-clock.txt @@ -0,0 +1,77 @@ +* Samsung S5P6442/S5PC110/S5PV210 Clock Controller + +Samsung S5P6442, S5PC110 and S5PV210 SoCs contain integrated clock +controller, which generates and supplies clock to various controllers +within the SoC. + +Required Properties: + +- compatible: should be one of following: + - "samsung,s5pv210-clock" : for clock controller of Samsung + S5PC110/S5PV210 SoCs, + - "samsung,s5p6442-clock" : for clock controller of Samsung + S5P6442 SoC. + +- reg: physical base address of the controller and length of memory mapped + region. + +- #clock-cells: should be 1. + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/s5pv210.h header and can be used in device tree sources. + +External clocks: + +There are several clocks that are generated outside the SoC. It is expected +that they are defined using standard clock bindings with following +clock-output-names: + - "xxti": external crystal oscillator connected to XXTI and XXTO pins of +the SoC, + - "xusbxti": external crystal oscillator connected to XUSBXTI and XUSBXTO +pins of the SoC, + +A subset of above clocks available on given board shall be specified in +board device tree, including the system base clock, as selected by XOM[0] +pin of the SoC. Refer to generic fixed rate clock bindings +documentation[1] for more information how to specify these clocks. + +[1] Documentation/devicetree/bindings/clock/fixed-clock.txt + +Example: Clock controller node: + + clock: clock-controller@7e00f000 { + compatible = "samsung,s5pv210-clock"; + reg = <0x7e00f000 0x1000>; + #clock-cells = <1>; + }; + +Example: Required external clocks: + + xxti: clock-xxti { + compatible = "fixed-clock"; + clock-output-names = "xxti"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; + + xusbxti: clock-xusbxti { + compatible = "fixed-clock"; + clock-output-names = "xusbxti"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; + +Example: UART controller node that consumes the clock generated by the clock + controller (refer to the standard clock bindings for information about + "clocks" and "clock-names" properties): + + uart0: serial@e2900000 { + compatible = "samsung,s5pv210-uart"; + reg = <0xe2900000 0x400>; + interrupt-parent = <&vic1>; + interrupts = <10>; + clock-names = "uart", "clk_uart_baud0", + "clk_uart_baud1"; + clocks = <&clocks UART0>, <&clocks UART0>, + <&clocks SCLK_UART0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si514.txt b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si514.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea1a9dbc63b6a4e7e5acc9e4868754213fb509aa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si514.txt @@ -0,0 +1,24 @@ +Binding for Silicon Labs 514 programmable I2C clock generator. + +Reference +This binding uses the common clock binding[1]. Details about the device can be +found in the datasheet[2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Si514 datasheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf + +Required properties: + - compatible: Shall be "silabs,si514" + - reg: I2C device address. + - #clock-cells: From common clock bindings: Shall be 0. + +Optional properties: + - clock-output-names: From common clock bindings. Recommended to be "si514". + +Example: + si514: clock-generator@55 { + reg = <0x55>; + #clock-cells = <0>; + compatible = "silabs,si514"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si5351.txt b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si5351.txt new file mode 100644 index 0000000000000000000000000000000000000000..f00191cad8cdf4f3b8f4d2f6330521cf6173cc8d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si5351.txt @@ -0,0 +1,126 @@ +Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator. + +Reference +[1] Si5351A/B/C Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf + +The Si5351a/b/c are programmable i2c clock generators with up to 8 output +clocks. Si5351a also has a reduced pin-count package (MSOP10) where only +3 output clocks are accessible. The internal structure of the clock +generators can be found in [1]. + +==I2C device node== + +Required properties: +- compatible: shall be one of the following: + "silabs,si5351a" - Si5351a, QFN20 package + "silabs,si5351a-msop" - Si5351a, MSOP10 package + "silabs,si5351b" - Si5351b, QFN20 package + "silabs,si5351c" - Si5351c, QFN20 package +- reg: i2c device address, shall be 0x60 or 0x61. +- #clock-cells: from common clock binding; shall be set to 1. +- clocks: from common clock binding; list of parent clock + handles, shall be xtal reference clock or xtal and clkin for + si5351c only. Corresponding clock input names are "xtal" and + "clkin" respectively. +- #address-cells: shall be set to 1. +- #size-cells: shall be set to 0. + +Optional properties: +- silabs,pll-source: pair of (number, source) for each pll. Allows + to overwrite clock source of pll A (number=0) or B (number=1). + +==Child nodes== + +Each of the clock outputs can be overwritten individually by +using a child node to the I2C device node. If a child node for a clock +output is not set, the eeprom configuration is not overwritten. + +Required child node properties: +- reg: number of clock output. + +Optional child node properties: +- silabs,clock-source: source clock of the output divider stage N, shall be + 0 = multisynth N + 1 = multisynth 0 for output clocks 0-3, else multisynth4 + 2 = xtal + 3 = clkin (si5351c only) +- silabs,drive-strength: output drive strength in mA, shall be one of {2,4,6,8}. +- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth + divider. +- silabs,pll-master: boolean, multisynth can change pll frequency. +- silabs,pll-reset: boolean, clock output can reset its pll. +- silabs,disable-state : clock output disable state, shall be + 0 = clock output is driven LOW when disabled + 1 = clock output is driven HIGH when disabled + 2 = clock output is FLOATING (HIGH-Z) when disabled + 3 = clock output is NEVER disabled + +==Example== + +/* 25MHz reference crystal */ +ref25: ref25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; +}; + +i2c-master-node { + + /* Si5351a msop10 i2c clock generator */ + si5351a: clock-generator@60 { + compatible = "silabs,si5351a-msop"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + /* connect xtal input to 25MHz reference */ + clocks = <&ref25>; + clock-names = "xtal"; + + /* connect xtal input as source of pll0 and pll1 */ + silabs,pll-source = <0 0>, <1 0>; + + /* + * overwrite clkout0 configuration with: + * - 8mA output drive strength + * - pll0 as clock source of multisynth0 + * - multisynth0 as clock source of output divider + * - multisynth0 can change pll0 + * - set initial clock frequency of 74.25MHz + */ + clkout0 { + reg = <0>; + silabs,drive-strength = <8>; + silabs,multisynth-source = <0>; + silabs,clock-source = <0>; + silabs,pll-master; + clock-frequency = <74250000>; + }; + + /* + * overwrite clkout1 configuration with: + * - 4mA output drive strength + * - pll1 as clock source of multisynth1 + * - multisynth1 as clock source of output divider + * - multisynth1 can change pll1 + */ + clkout1 { + reg = <1>; + silabs,drive-strength = <4>; + silabs,multisynth-source = <1>; + silabs,clock-source = <0>; + pll-master; + }; + + /* + * overwrite clkout2 configuration with: + * - xtal as clock source of output divider + */ + clkout2 { + reg = <2>; + silabs,clock-source = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si544.txt b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si544.txt new file mode 100644 index 0000000000000000000000000000000000000000..b86535b80920959559b1a926912fbd4d3f672cd0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si544.txt @@ -0,0 +1,25 @@ +Binding for Silicon Labs 544 programmable I2C clock generator. + +Reference +This binding uses the common clock binding[1]. Details about the device can be +found in the datasheet[2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Si544 datasheet + https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf + +Required properties: + - compatible: One of "silabs,si514a", "silabs,si514b" "silabs,si514c" according + to the speed grade of the chip. + - reg: I2C device address. + - #clock-cells: From common clock bindings: Shall be 0. + +Optional properties: + - clock-output-names: From common clock bindings. Recommended to be "si544". + +Example: + si544: clock-controller@55 { + reg = <0x55>; + #clock-cells = <0>; + compatible = "silabs,si544b"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si570.txt b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si570.txt new file mode 100644 index 0000000000000000000000000000000000000000..c09f21e1d98f01aed334211936f04972d3acaf8c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/silabs,si570.txt @@ -0,0 +1,39 @@ +Binding for Silicon Labs 570, 571, 598 and 599 programmable +I2C clock generators. + +Reference +This binding uses the common clock binding[1]. Details about the devices can be +found in the data sheets[2][3]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Si570/571 Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si570.pdf +[3] Si598/599 Data Sheet + http://www.silabs.com/Support%20Documents/TechnicalDocs/si598-99.pdf + +Required properties: + - compatible: Shall be one of "silabs,si570", "silabs,si571", + "silabs,si598", "silabs,si599" + - reg: I2C device address. + - #clock-cells: From common clock bindings: Shall be 0. + - factory-fout: Factory set default frequency. This frequency is part specific. + The correct frequency for the part used has to be provided in + order to generate the correct output frequencies. For more + details, please refer to the data sheet. + - temperature-stability: Temperature stability of the device in PPM. Should be + one of: 7, 20, 50 or 100. + +Optional properties: + - clock-output-names: From common clock bindings. Recommended to be "si570". + - clock-frequency: Output frequency to generate. This defines the output + frequency set during boot. It can be reprogrammed during + runtime through the common clock framework. + +Example: + si570: clock-generator@5d { + #clock-cells = <0>; + compatible = "silabs,si570"; + temperature-stability = <50>; + reg = <0x5d>; + factory-fout = <156250000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/snps,hsdk-pll-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/snps,hsdk-pll-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..c56c7553c7300213cc2a12865eb0589a269b6fce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/snps,hsdk-pll-clock.txt @@ -0,0 +1,28 @@ +Binding for the HSDK Generic PLL clock + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: should be "snps,hsdk--pll-clock" + "snps,hsdk-core-pll-clock" + "snps,hsdk-gp-pll-clock" + "snps,hsdk-hdmi-pll-clock" +- reg : should contain base register location and length. +- clocks: shall be the input parent clock phandle for the PLL. +- #clock-cells: from common clock binding; Should always be set to 0. + +Example: + input_clk: input-clk { + clock-frequency = <33333333>; + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + cpu_clk: cpu-clk@0 { + compatible = "snps,hsdk-core-pll-clock"; + reg = <0x00 0x10>; + #clock-cells = <0>; + clocks = <&input_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/snps,pll-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/snps,pll-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..11fe4876612c46aef0c1fab910806e2d82e121ed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/snps,pll-clock.txt @@ -0,0 +1,28 @@ +Binding for the AXS10X Generic PLL clock + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible: should be "snps,axs10x--pll-clock" + "snps,axs10x-arc-pll-clock" + "snps,axs10x-pgu-pll-clock" +- reg: should always contain 2 pairs address - length: first for PLL config +registers and second for corresponding LOCK CGU register. +- clocks: shall be the input parent clock phandle for the PLL. +- #clock-cells: from common clock binding; Should always be set to 0. + +Example: + input-clk: input-clk { + clock-frequency = <33333333>; + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + core-clk: core-clk@80 { + compatible = "snps,axs10x-arc-pll-clock"; + reg = <0x80 0x10>, <0x100 0x10>; + #clock-cells = <0>; + clocks = <&input-clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/sprd.txt b/arch/arm64/boot/dts/vendor/bindings/clock/sprd.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9d179e882d95464818a0a3038652c8bf6a40dd5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/sprd.txt @@ -0,0 +1,63 @@ +Spreadtrum Clock Binding +------------------------ + +Required properties: +- compatible: should contain the following compatible strings: + - "sprd,sc9860-pmu-gate" + - "sprd,sc9860-pll" + - "sprd,sc9860-ap-clk" + - "sprd,sc9860-aon-prediv" + - "sprd,sc9860-apahb-gate" + - "sprd,sc9860-aon-gate" + - "sprd,sc9860-aonsecure-clk" + - "sprd,sc9860-agcp-gate" + - "sprd,sc9860-gpu-clk" + - "sprd,sc9860-vsp-clk" + - "sprd,sc9860-vsp-gate" + - "sprd,sc9860-cam-clk" + - "sprd,sc9860-cam-gate" + - "sprd,sc9860-disp-clk" + - "sprd,sc9860-disp-gate" + - "sprd,sc9860-apapb-gate" + +- #clock-cells: must be 1 + +- clocks : Should be the input parent clock(s) phandle for the clock, this + property here just simply shows which clock group the clocks' + parents are in, since each clk node would represent many clocks + which are defined in the driver. The detailed dependency + relationship (i.e. how many parents and which are the parents) + are implemented in driver code. + +Optional properties: + +- reg: Contain the registers base address and length. It must be configured + only if no 'sprd,syscon' under the node. + +- sprd,syscon: phandle to the syscon which is in the same address area with + the clock, and so we can get regmap for the clocks from the + syscon device. + +Example: + + pmu_gate: pmu-gate { + compatible = "sprd,sc9860-pmu-gate"; + sprd,syscon = <&pmu_regs>; + clocks = <&ext_26m>; + #clock-cells = <1>; + }; + + pll: pll { + compatible = "sprd,sc9860-pll"; + sprd,syscon = <&ana_regs>; + clocks = <&pmu_gate 0>; + #clock-cells = <1>; + }; + + ap_clk: clock-controller@20000000 { + compatible = "sprd,sc9860-ap-clk"; + reg = <0 0x20000000 0 0x400>; + clocks = <&ext_26m>, <&pll 0>, + <&pmu_gate 0>; + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st,nomadik.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st,nomadik.txt new file mode 100644 index 0000000000000000000000000000000000000000..40e0cf1f7b9911b5cb9450da49cab031d1dccada --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st,nomadik.txt @@ -0,0 +1,104 @@ +ST Microelectronics Nomadik SRC System Reset and Control + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The Nomadik SRC controller is responsible of controlling chrystals, +PLLs and clock gates. + +Required properties for the SRC node: +- compatible: must be "stericsson,nomadik-src" +- reg: must contain the SRC register base and size + +Optional properties for the SRC node: +- disable-sxtalo: if present this will disable the SXTALO + i.e. the driver output for the slow 32kHz chrystal, if the + board has its own circuitry for providing this oscillator +- disable-mxtal: if present this will disable the MXTALO, + i.e. the driver output for the main (~19.2 MHz) chrystal, + if the board has its own circuitry for providing this + oscillator + + +PLL nodes: these nodes represent the two PLLs on the system, +which should both have the main chrystal, represented as a +fixed frequency clock, as parent. + +Required properties for the two PLL nodes: +- compatible: must be "st,nomadik-pll-clock" +- clock-cells: must be 0 +- clock-id: must be 1 or 2 for PLL1 and PLL2 respectively +- clocks: this clock will have main chrystal as parent + + +HCLK nodes: these represent the clock gates on individual +lines from the HCLK clock tree and the gate for individual +lines from the PCLK clock tree. + +Requires properties for the HCLK nodes: +- compatible: must be "st,nomadik-hclk-clock" +- clock-cells: must be 0 +- clock-id: must be the clock ID from 0 to 63 according to + this table: + + 0: HCLKDMA0 + 1: HCLKSMC + 2: HCLKSDRAM + 3: HCLKDMA1 + 4: HCLKCLCD + 5: PCLKIRDA + 6: PCLKSSP + 7: PCLKUART0 + 8: PCLKSDI + 9: PCLKI2C0 + 10: PCLKI2C1 + 11: PCLKUART1 + 12: PCLMSP0 + 13: HCLKUSB + 14: HCLKDIF + 15: HCLKSAA + 16: HCLKSVA + 17: PCLKHSI + 18: PCLKXTI + 19: PCLKUART2 + 20: PCLKMSP1 + 21: PCLKMSP2 + 22: PCLKOWM + 23: HCLKHPI + 24: PCLKSKE + 25: PCLKHSEM + 26: HCLK3D + 27: HCLKHASH + 28: HCLKCRYP + 29: PCLKMSHC + 30: HCLKUSBM + 31: HCLKRNG + (32, 33, 34, 35 RESERVED) + 36: CLDCLK + 37: IRDACLK + 38: SSPICLK + 39: UART0CLK + 40: SDICLK + 41: I2C0CLK + 42: I2C1CLK + 43: UART1CLK + 44: MSPCLK0 + 45: USBCLK + 46: DIFCLK + 47: IPI2CCLK + 48: IPBMCCLK + 49: HSICLKRX + 50: HSICLKTX + 51: UART2CLK + 52: MSPCLK1 + 53: MSPCLK2 + 54: OWMCLK + (55 RESERVED) + 56: SKECLK + (57 RESERVED) + 58: 3DCLK + 59: PCLKMSP3 + 60: MSPCLK3 + 61: MSHCCLK + 62: USBMCLK + 63: RNGCCLK diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32-rcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32-rcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b240121d2ac940e4eef678b3769f1262a1d3cb1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32-rcc.txt @@ -0,0 +1,132 @@ +STMicroelectronics STM32 Reset and Clock Controller +=================================================== + +The RCC IP is both a reset and a clock controller. + +Please refer to clock-bindings.txt for common clock controller binding usage. +Please also refer to reset.txt for common reset controller binding usage. + +Required properties: +- compatible: Should be: + "st,stm32f42xx-rcc" + "st,stm32f469-rcc" + "st,stm32f746-rcc" +- reg: should be register base and length as documented in the + datasheet +- #reset-cells: 1, see below +- #clock-cells: 2, device nodes should specify the clock in their "clocks" + property, containing a phandle to the clock device node, an index selecting + between gated clocks and other clocks and an index specifying the clock to + use. +- clocks: External oscillator clock phandle + - high speed external clock signal (HSE) + - external I2S clock (I2S_CKIN) + +Example: + + rcc: rcc@40023800 { + #reset-cells = <1>; + #clock-cells = <2> + compatible = "st,stm32f42xx-rcc", "st,stm32-rcc"; + reg = <0x40023800 0x400>; + clocks = <&clk_hse>, <&clk_i2s_ckin>; + }; + +Specifying gated clocks +======================= + +The primary index must be set to 0. + +The secondary index is the bit number within the RCC register bank, starting +from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30). + +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31). + +To simplify the usage and to share bit definition with the reset and clock +drivers of the RCC IP, macros are available to generate the index in +human-readble format. + +For STM32F4 series, the macro are available here: + - include/dt-bindings/mfd/stm32f4-rcc.h + +Example: + + /* Gated clock, AHB1 bit 0 (GPIOA) */ + ... { + clocks = <&rcc 0 STM32F4_AHB1_CLOCK(GPIOA)> + }; + + /* Gated clock, AHB2 bit 4 (CRYP) */ + ... { + clocks = <&rcc 0 STM32F4_AHB2_CLOCK(CRYP)> + }; + +Specifying other clocks +======================= + +The primary index must be set to 1. + +The secondary index is bound with the following magic numbers: + + 0 SYSTICK + 1 FCLK + 2 CLK_LSI (low-power clock source) + 3 CLK_LSE (generated from a 32.768 kHz low-speed external + crystal or ceramic resonator) + 4 CLK_HSE_RTC (HSE division factor for RTC clock) + 5 CLK_RTC (real-time clock) + 6 PLL_VCO_I2S (vco frequency of I2S pll) + 7 PLL_VCO_SAI (vco frequency of SAI pll) + 8 CLK_LCD (LCD-TFT) + 9 CLK_I2S (I2S clocks) + 10 CLK_SAI1 (audio clocks) + 11 CLK_SAI2 + 12 CLK_I2SQ_PDIV (post divisor of pll i2s q divisor) + 13 CLK_SAIQ_PDIV (post divisor of pll sai q divisor) + + 14 CLK_HSI (Internal ocscillator clock) + 15 CLK_SYSCLK (System Clock) + 16 CLK_HDMI_CEC (HDMI-CEC clock) + 17 CLK_SPDIF (SPDIF-Rx clock) + 18 CLK_USART1 (U(s)arts clocks) + 19 CLK_USART2 + 20 CLK_USART3 + 21 CLK_UART4 + 22 CLK_UART5 + 23 CLK_USART6 + 24 CLK_UART7 + 25 CLK_UART8 + 26 CLK_I2C1 (I2S clocks) + 27 CLK_I2C2 + 28 CLK_I2C3 + 29 CLK_I2C4 + 30 CLK_LPTIMER (LPTimer1 clock) +) + +Example: + + /* Misc clock, FCLK */ + ... { + clocks = <&rcc 1 STM32F4_APB1_CLOCK(TIM2)> + }; + + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. +For example, for CRC reset: + crc = AHB1RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x10 / 4 * 32 + 12 = 140 + +example: + + timer2 { + resets = <&rcc STM32F4_APB1_RESET(TIM2)>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32h7-rcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32h7-rcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..cac24ee10b72ebc3765d29708fa27c5ae6848950 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32h7-rcc.txt @@ -0,0 +1,71 @@ +STMicroelectronics STM32H7 Reset and Clock Controller +===================================================== + +The RCC IP is both a reset and a clock controller. + +Please refer to clock-bindings.txt for common clock controller binding usage. +Please also refer to reset.txt for common reset controller binding usage. + +Required properties: +- compatible: Should be: + "st,stm32h743-rcc" + +- reg: should be register base and length as documented in the + datasheet + +- #reset-cells: 1, see below + +- #clock-cells : from common clock binding; shall be set to 1 + +- clocks: External oscillator clock phandle + - high speed external clock signal (HSE) + - low speed external clock signal (LSE) + - external I2S clock (I2S_CKIN) + +Optional properties: +- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain + write protection (RTC clock). + +Example: + + rcc: reset-clock-controller@58024400 { + compatible = "st,stm32h743-rcc", "st,stm32-rcc"; + reg = <0x58024400 0x400>; + #reset-cells = <1>; + #clock-cells = <1>; + clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>; + + st,syscfg = <&pwrcfg>; +}; + +The peripheral clock consumer should specify the desired clock by +having the clock ID in its "clocks" phandle cell. + +Example: + + timer5: timer@40000c00 { + compatible = "st,stm32-timer"; + reg = <0x40000c00 0x400>; + interrupts = <50>; + clocks = <&rcc TIM5_CK>; + }; + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. + +For example, for CRC reset: + crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107 + +Example: + + timer2 { + resets = <&rcc STM32H7_APB1L_RESET(TIM2)>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32mp1-rcc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32mp1-rcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb9495ea582c4b539fa5a06c8fad0fcb748a4cb6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st,stm32mp1-rcc.txt @@ -0,0 +1,60 @@ +STMicroelectronics STM32 Peripheral Reset Clock Controller +========================================================== + +The RCC IP is both a reset and a clock controller. + +RCC makes also power management (resume/supend and wakeup interrupt). + +Please also refer to reset.txt for common reset controller binding usage. + +Please also refer to clock-bindings.txt for common clock controller +binding usage. + + +Required properties: +- compatible: "st,stm32mp1-rcc", "syscon" +- reg: should be register base and length as documented in the datasheet +- #clock-cells: 1, device nodes should specify the clock in their + "clocks" property, containing a phandle to the clock device node, + an index specifying the clock to use. +- #reset-cells: Shall be 1 +- interrupts: Should contain a general interrupt line and a interrupt line + to the wake-up of processor (CSTOP). + +Example: + rcc: rcc@50000000 { + compatible = "st,stm32mp1-rcc", "syscon"; + reg = <0x50000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + interrupts = , + ; + }; + +Specifying clocks +================= + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/stm32mp1-clks.h header and can be used in device +tree sources. + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the reset device node and an index specifying +which channel to use. +The index is the bit number within the RCC registers bank, starting from RCC +base address. +It is calculated as: index = register_offset / 4 * 32 + bit_offset. +Where bit_offset is the bit offset within the register. + +For example on STM32MP1, for LTDC reset: + ltdc = APB4_RSTSETR_offset / 4 * 32 + LTDC_bit_offset + = 0x180 / 4 * 32 + 0 = 3072 + +The list of valid indices for STM32MP1 is available in: +include/dt-bindings/reset-controller/stm32mp1-resets.h + +This file implements defines like: +#define LTDC_R 3072 diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen-mux.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a46cb1d7a04ba9c5881f6775b7dc52d76dde013 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen-mux.txt @@ -0,0 +1,32 @@ +Binding for a ST multiplexed clock driver. + +This binding supports only simple indexed multiplexers, it does not +support table based parent index to hardware value translations. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: + +- compatible : shall be: + "st,stih407-clkgen-a9-mux" + +- #clock-cells : from common clock binding; shall be set to 0. + +- reg : A Base address and length of the register set. + +- clocks : from common clock binding + +Example: + + clk_m_a9: clk-m-a9@92b0000 { + #clock-cells = <0>; + compatible = "st,stih407-clkgen-a9-mux"; + reg = <0x92b0000 0x10000>; + + clocks = <&clockgen_a9_pll 0>, + <&clockgen_a9_pll 0>, + <&clk_s_c0_flexgen 13>, + <&clk_m_a9_ext2f_div2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen-pll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen-pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..f207053e0550668e027161784735d8063316d8ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen-pll.txt @@ -0,0 +1,37 @@ +Binding for a ST pll clock driver. + +This binding uses the common clock binding[1]. +Base address is located to the parent node. See clock binding[2] + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/st/st,clkgen.txt + +Required properties: + +- compatible : shall be: + "st,clkgen-pll0" + "st,clkgen-pll1" + "st,stih407-clkgen-plla9" + "st,stih418-clkgen-plla9" + +- #clock-cells : From common clock binding; shall be set to 1. + +- clocks : From common clock binding + +- clock-output-names : From common clock binding. + +Example: + + clockgen-a9@92b0000 { + compatible = "st,clkgen-c32"; + reg = <0x92b0000 0xffff>; + + clockgen_a9_pll: clockgen-a9-pll { + #clock-cells = <1>; + compatible = "st,stih407-clkgen-plla9"; + + clocks = <&clk_sysin>; + + clock-output-names = "clockgen-a9-pll-odf"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen.txt new file mode 100644 index 0000000000000000000000000000000000000000..45ac19bfa0a9ff4d73cb6cffcd16560dd0fe6b0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,clkgen.txt @@ -0,0 +1,68 @@ +Binding for a Clockgen hardware block found on +certain STMicroelectronics consumer electronics SoC devices. + +A Clockgen node can contain pll, diviser or multiplexer nodes. + +We will find only the base address of the Clockgen, this base +address is common of all subnode. + + clockgen_node { + reg = <>; + + pll_node { + ... + }; + + quadfs_node { + ... + }; + + mux_node { + ... + }; + + flexgen_node { + ... + }; + ... + }; + +This binding uses the common clock binding[1]. +Each subnode should use the binding described in [2]..[7] + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[3] Documentation/devicetree/bindings/clock/st/st,clkgen-mux.txt +[4] Documentation/devicetree/bindings/clock/st/st,clkgen-pll.txt +[7] Documentation/devicetree/bindings/clock/st/st,quadfs.txt +[8] Documentation/devicetree/bindings/clock/st/st,flexgen.txt + + +Required properties: +- reg : A Base address and length of the register set. + +Example: + + clockgen-a@90ff000 { + compatible = "st,clkgen-c32"; + reg = <0x90ff000 0x1000>; + + clk_s_a0_pll: clk-s-a0-pll { + #clock-cells = <1>; + compatible = "st,clkgen-pll0"; + + clocks = <&clk_sysin>; + + clock-output-names = "clk-s-a0-pll-ofd-0"; + }; + + clk_s_a0_flexgen: clk-s-a0-flexgen { + compatible = "st,flexgen"; + + #clock-cells = <1>; + + clocks = <&clk_s_a0_pll 0>, + <&clk_sysin>; + + clock-output-names = "clk-ic-lmi0"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st/st,flexgen.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,flexgen.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ff77fc57dff2fcd9bdd085ab2816d3c6d40c684 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,flexgen.txt @@ -0,0 +1,123 @@ +Binding for a type of flexgen structure found on certain +STMicroelectronics consumer electronics SoC devices + +This structure includes: +- a clock cross bar (represented by a mux element) +- a pre and final dividers (represented by a divider and gate elements) + +Flexgen structure is a part of Clockgen[1]. + +Please find an example below: + + Clockgen block diagram + ------------------------------------------------------------------- + | Flexgen structure | + | --------------------------------------------- | + | | ------- -------- -------- | | +clk_sysin | | | | | | | | | +---|-----------------|-->| | | | | | | | + | | | | | | | | | | | + | | ------- | | | |Pre | |Final | | | + | | |PLL0 | | | | |Dividers| |Dividers| | | + | |->| | | | | | x32 | | x32 | | | + | | | odf_0|----|-->| | | | | | | | + | | | | | | | | | | | | | + | | | | | | | | | | | | | + | | | | | | | | | | | | | + | | | | | | | | | | | | | + | | ------- | | | | | | | | | + | | | | | | | | | | | + | | ------- | | Clock | | | | | | | + | | |PLL1 | | | | | | | | | | + | |->| | | | Cross | | | | | | | + | | | odf_0|----|-->| | | | | | CLK_DIV[31:0] + | | | | | | Bar |====>| |====>| |===|=========> + | | | | | | | | | | | | | + | | | | | | | | | | | | | + | | | | | | | | | | | | | + | | ------- | | | | | | | | | + | | | | | | | | | | | + | | ------- | | | | | | | | | + | | |QUADFS | | | | | | | | | | + | |->| ch0|----|-->| | | | | | | | + | | | | | | | | | | | | + | | ch1|----|-->| | | | | | | | + | | | | | | | | | | | | + | | ch2|----|-->| | | DIV | | DIV | | | + | | | | | | | 1 to | | 1 to | | | + | | ch3|----|-->| | | 1024 | | 64 | | | + | ------- | | | | | | | | | + | | ------- -------- -------- | | + | -------------------------------------------- | + | | + ------------------------------------------------------------------- + +This binding uses the common clock binding[2]. + +[1] Documentation/devicetree/bindings/clock/st/st,clkgen.txt +[2] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be: + "st,flexgen" + "st,flexgen-audio", "st,flexgen" (enable clock propagation on parent for + audio use case) + "st,flexgen-video", "st,flexgen" (enable clock propagation on parent + and activate synchronous mode) + +- #clock-cells : from common clock binding; shall be set to 1 (multiple clock + outputs). + +- clocks : must be set to the parent's phandle. it's could be output clocks of + a quadsfs or/and a pll or/and clk_sysin (up to 7 clocks) + +- clock-output-names : List of strings used to name the clock outputs. + +Example: + + clk_s_c0_flexgen: clk-s-c0-flexgen { + + #clock-cells = <1>; + compatible = "st,flexgen"; + + clocks = <&clk_s_c0_pll0 0>, + <&clk_s_c0_pll1 0>, + <&clk_s_c0_quadfs 0>, + <&clk_s_c0_quadfs 1>, + <&clk_s_c0_quadfs 2>, + <&clk_s_c0_quadfs 3>, + <&clk_sysin>; + + clock-output-names = "clk-icn-gpu", + "clk-fdma", + "clk-nand", + "clk-hva", + "clk-proc-stfe", + "clk-proc-tp", + "clk-rx-icn-dmu", + "clk-rx-icn-hva", + "clk-icn-cpu", + "clk-tx-icn-dmu", + "clk-mmc-0", + "clk-mmc-1", + "clk-jpegdec", + "clk-ext2fa9", + "clk-ic-bdisp-0", + "clk-ic-bdisp-1", + "clk-pp-dmu", + "clk-vid-dmu", + "clk-dss-lpc", + "clk-st231-aud-0", + "clk-st231-gp-1", + "clk-st231-dmu", + "clk-icn-lmi", + "clk-tx-icn-disp-1", + "clk-icn-sbc", + "clk-stfe-frc2", + "clk-eth-phy", + "clk-eth-ref-phyclk", + "clk-flash-promip", + "clk-main-disp", + "clk-aux-disp", + "clk-compo-dvp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/st/st,quadfs.txt b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,quadfs.txt new file mode 100644 index 0000000000000000000000000000000000000000..d93d49342e60e8f2c67f8fa5491217e7bdeebb46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/st/st,quadfs.txt @@ -0,0 +1,45 @@ +Binding for a type of quad channel digital frequency synthesizer found on +certain STMicroelectronics consumer electronics SoC devices. + +This version contains a programmable PLL which can generate up to 216, 432 +or 660MHz (from a 30MHz oscillator input) as the input to the digital +synthesizers. + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be: + "st,quadfs" + "st,quadfs-pll" + + +- #clock-cells : from common clock binding; shall be set to 1. + +- reg : A Base address and length of the register set. + +- clocks : from common clock binding + +- clock-output-names : From common clock binding. The block has 4 + clock outputs but not all of them in a specific instance + have to be used in the SoC. If a clock name is left as + an empty string then no clock will be created for the + output associated with that string index. If fewer than + 4 strings are provided then no clocks will be created + for the remaining outputs. + +Example: + + clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 { + #clock-cells = <1>; + compatible = "st,quadfs-pll"; + reg = <0x9103000 0x1000>; + + clocks = <&clk_sysin>; + + clock-output-names = "clk-s-c0-fs0-ch0", + "clk-s-c0-fs0-ch1", + "clk-s-c0-fs0-ch2", + "clk-s-c0-fs0-ch3"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ste-u300-syscon-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ste-u300-syscon-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cafcb98ead79b89b1dd3938de7ff109c7128ef2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ste-u300-syscon-clock.txt @@ -0,0 +1,80 @@ +Clock bindings for ST-Ericsson U300 System Controller Clocks + +Bindings for the gated system controller clocks: + +Required properties: +- compatible: must be "stericsson,u300-syscon-clk" +- #clock-cells: must be <0> +- clock-type: specifies the type of clock: + 0 = slow clock + 1 = fast clock + 2 = rest/remaining clock +- clock-id: specifies the clock in the type range + +Optional properties: +- clocks: parent clock(s) + +The available clocks per type are as follows: + +Type: ID: Clock: +------------------- +0 0 Slow peripheral bridge clock +0 1 UART0 clock +0 4 GPIO clock +0 6 RTC clock +0 7 Application timer clock +0 8 Access timer clock + +1 0 Fast peripheral bridge clock +1 1 I2C bus 0 clock +1 2 I2C bus 1 clock +1 5 MMC interface peripheral (silicon) clock +1 6 SPI clock + +2 3 CPU clock +2 4 DMA controller clock +2 5 External Memory Interface (EMIF) clock +2 6 NAND flask interface clock +2 8 XGAM graphics engine clock +2 9 Shared External Memory Interface (SEMI) clock +2 10 AHB Subsystem Bridge clock +2 12 Interrupt controller clock + +Example: + +gpio_clk: gpio_clk@13M { + #clock-cells = <0>; + compatible = "stericsson,u300-syscon-clk"; + clock-type = <0>; /* Slow */ + clock-id = <4>; + clocks = <&slow_clk>; +}; + +gpio: gpio@c0016000 { + compatible = "stericsson,gpio-coh901"; + (...) + clocks = <&gpio_clk>; +}; + + +Bindings for the MMC/SD card clock: + +Required properties: +- compatible: must be "stericsson,u300-syscon-mclk" +- #clock-cells: must be <0> + +Optional properties: +- clocks: parent clock(s) + +mmc_mclk: mmc_mclk { + #clock-cells = <0>; + compatible = "stericsson,u300-syscon-mclk"; + clocks = <&mmc_pclk>; +}; + +mmcsd: mmcsd@c0001000 { + compatible = "arm,pl18x", "arm,primecell"; + clocks = <&mmc_pclk>, <&mmc_mclk>; + clock-names = "apb_pclk", "mclk"; + (...) +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/stericsson,abx500.txt b/arch/arm64/boot/dts/vendor/bindings/clock/stericsson,abx500.txt new file mode 100644 index 0000000000000000000000000000000000000000..dbaa886b223e3d902c4b0ef76a80fa44744843bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/stericsson,abx500.txt @@ -0,0 +1,20 @@ +Clock bindings for ST-Ericsson ABx500 clocks + +Required properties : +- compatible : shall contain the following: + "stericsson,ab8500-clk" +- #clock-cells should be <1> + +The ABx500 clocks need to be placed as a subnode of an AB8500 +device node, see mfd/ab8500.txt + +All available clocks are defined as preprocessor macros in +dt-bindings/clock/ste-ab8500.h header and can be used in device +tree sources. + +Example: + +clock-controller { + compatible = "stericsson,ab8500-clk"; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/sun8i-de2.txt b/arch/arm64/boot/dts/vendor/bindings/clock/sun8i-de2.txt new file mode 100644 index 0000000000000000000000000000000000000000..e94582e8b8a917ef04252d53caabeb4e4b3ea90f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/sun8i-de2.txt @@ -0,0 +1,33 @@ +Allwinner Display Engine 2.0 Clock Control Binding +-------------------------------------------------- + +Required properties : +- compatible: must contain one of the following compatibles: + - "allwinner,sun8i-a83t-de2-clk" + - "allwinner,sun8i-h3-de2-clk" + - "allwinner,sun8i-v3s-de2-clk" + - "allwinner,sun50i-a64-de2-clk" + - "allwinner,sun50i-h5-de2-clk" + +- reg: Must contain the registers base address and length +- clocks: phandle to the clocks feeding the display engine subsystem. + Three are needed: + - "mod": the display engine module clock (on A83T it's the DE PLL) + - "bus": the bus clock for the whole display engine subsystem +- clock-names: Must contain the clock names described just above +- resets: phandle to the reset control for the display engine subsystem. +- #clock-cells : must contain 1 +- #reset-cells : must contain 1 + +Example: +de2_clocks: clock@1000000 { + compatible = "allwinner,sun8i-h3-de2-clk"; + reg = <0x01000000 0x100000>; + clocks = <&ccu CLK_BUS_DE>, + <&ccu CLK_DE>; + clock-names = "bus", + "mod"; + resets = <&ccu RST_BUS_DE>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/sun9i-de.txt b/arch/arm64/boot/dts/vendor/bindings/clock/sun9i-de.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb18f327b97a77e83d0e0601c91e2e9aa510ebcd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/sun9i-de.txt @@ -0,0 +1,28 @@ +Allwinner A80 Display Engine Clock Control Binding +-------------------------------------------------- + +Required properties : +- compatible: must contain one of the following compatibles: + - "allwinner,sun9i-a80-de-clks" + +- reg: Must contain the registers base address and length +- clocks: phandle to the clocks feeding the display engine subsystem. + Three are needed: + - "mod": the display engine module clock + - "dram": the DRAM bus clock for the system + - "bus": the bus clock for the whole display engine subsystem +- clock-names: Must contain the clock names described just above +- resets: phandle to the reset control for the display engine subsystem. +- #clock-cells : must contain 1 +- #reset-cells : must contain 1 + +Example: +de_clocks: clock@3000000 { + compatible = "allwinner,sun9i-a80-de-clks"; + reg = <0x03000000 0x30>; + clocks = <&ccu CLK_DE>, <&ccu CLK_SDRAM>, <&ccu CLK_BUS_DE>; + clock-names = "mod", "dram", "bus"; + resets = <&ccu RST_BUS_DE>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/sun9i-usb.txt b/arch/arm64/boot/dts/vendor/bindings/clock/sun9i-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..3564bd4f2a20473a3a67ad4c8473eb75b79c5fc8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/sun9i-usb.txt @@ -0,0 +1,24 @@ +Allwinner A80 USB Clock Control Binding +--------------------------------------- + +Required properties : +- compatible: must contain one of the following compatibles: + - "allwinner,sun9i-a80-usb-clocks" + +- reg: Must contain the registers base address and length +- clocks: phandle to the clocks feeding the USB subsystem. Two are needed: + - "bus": the bus clock for the whole USB subsystem + - "hosc": the high frequency oscillator (usually at 24MHz) +- clock-names: Must contain the clock names described just above +- #clock-cells : must contain 1 +- #reset-cells : must contain 1 + +Example: +usb_clocks: clock@a08000 { + compatible = "allwinner,sun9i-a80-usb-clks"; + reg = <0x00a08000 0x8>; + clocks = <&ccu CLK_BUS_USB>, <&osc24M>; + clock-names = "bus", "hosc"; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/sunxi-ccu.txt b/arch/arm64/boot/dts/vendor/bindings/clock/sunxi-ccu.txt new file mode 100644 index 0000000000000000000000000000000000000000..47d2e902ced43018a1f58eab35260ffcca239129 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/sunxi-ccu.txt @@ -0,0 +1,61 @@ +Allwinner Clock Control Unit Binding +------------------------------------ + +Required properties : +- compatible: must contain one of the following compatibles: + - "allwinner,sun4i-a10-ccu" + - "allwinner,sun5i-a10s-ccu" + - "allwinner,sun5i-a13-ccu" + - "allwinner,sun6i-a31-ccu" + - "allwinner,sun7i-a20-ccu" + - "allwinner,sun8i-a23-ccu" + - "allwinner,sun8i-a33-ccu" + - "allwinner,sun8i-a83t-ccu" + - "allwinner,sun8i-a83t-r-ccu" + - "allwinner,sun8i-h3-ccu" + - "allwinner,sun8i-h3-r-ccu" ++ - "allwinner,sun8i-r40-ccu" + - "allwinner,sun8i-v3s-ccu" + - "allwinner,sun9i-a80-ccu" + - "allwinner,sun50i-a64-ccu" + - "allwinner,sun50i-a64-r-ccu" + - "allwinner,sun50i-h5-ccu" + - "allwinner,sun50i-h6-ccu" + - "allwinner,sun50i-h6-r-ccu" + - "nextthing,gr8-ccu" + +- reg: Must contain the registers base address and length +- clocks: phandle to the oscillators feeding the CCU. Two are needed: + - "hosc": the high frequency oscillator (usually at 24MHz) + - "losc": the low frequency oscillator (usually at 32kHz) + On the A83T, this is the internal 16MHz oscillator divided by 512 +- clock-names: Must contain the clock names described just above +- #clock-cells : must contain 1 +- #reset-cells : must contain 1 + +For the main CCU on H6, one more clock is needed: +- "iosc": the SoC's internal frequency oscillator + +For the PRCM CCUs on A83T/H3/A64/H6, two more clocks are needed: +- "pll-periph": the SoC's peripheral PLL from the main CCU +- "iosc": the SoC's internal frequency oscillator + +Example for generic CCU: +ccu: clock@1c20000 { + compatible = "allwinner,sun8i-h3-ccu"; + reg = <0x01c20000 0x400>; + clocks = <&osc24M>, <&osc32k>; + clock-names = "hosc", "losc"; + #clock-cells = <1>; + #reset-cells = <1>; +}; + +Example for PRCM CCU: +r_ccu: clock@1f01400 { + compatible = "allwinner,sun50i-a64-r-ccu"; + reg = <0x01f01400 0x100>; + clocks = <&osc24M>, <&osc32k>, <&iosc>, <&ccu CLK_PLL_PERIPH0>; + clock-names = "hosc", "losc", "iosc", "pll-periph"; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/sunxi.txt b/arch/arm64/boot/dts/vendor/bindings/clock/sunxi.txt new file mode 100644 index 0000000000000000000000000000000000000000..1a042e20b115fa785f50b0f5841f5425de65f39f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/sunxi.txt @@ -0,0 +1,225 @@ +Device Tree Clock bindings for arch-sunxi + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "allwinner,sun4i-a10-osc-clk" - for a gatable oscillator + "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4 + "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31 + "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23 + "allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10 + "allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80 + "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock + "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock + "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31 + "allwinner,sun9i-a80-gt-clk" - for the GT bus clock on A80 + "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock + "allwinner,sun4i-a10-axi-clk" - for the AXI clock + "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23 + "allwinner,sun4i-a10-gates-clk" - for generic gates on all compatible SoCs + "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates + "allwinner,sun4i-a10-ahb-clk" - for the AHB clock + "allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13 + "allwinner,sun9i-a80-ahb-clk" - for the AHB bus clocks on A80 + "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10 + "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 + "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s + "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20 + "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31 + "allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80 + "allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31 + "allwinner,sun8i-h3-ahb2-clk" - for the AHB2 clock on H3 + "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 + "allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23 + "allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80 + "allwinner,sun9i-a80-ahb1-gates-clk" - for the AHB1 gates on A80 + "allwinner,sun9i-a80-ahb2-gates-clk" - for the AHB2 gates on A80 + "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock + "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31 + "allwinner,sun8i-a23-apb0-clk" - for the APB0 clock on A23 + "allwinner,sun9i-a80-apb0-clk" - for the APB0 bus clock on A80 + "allwinner,sun8i-a83t-apb0-gates-clk" - for the APB0 gates on A83T + "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10 + "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13 + "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s + "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31 + "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 + "allwinner,sun8i-a23-apb0-gates-clk" - for the APB0 gates on A23 + "allwinner,sun8i-h3-apb0-gates-clk" - for the APB0 gates on H3 + "allwinner,sun9i-a80-apb0-gates-clk" - for the APB0 gates on A80 + "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock + "allwinner,sun9i-a80-apb1-clk" - for the APB1 bus clock on A80 + "allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10 + "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13 + "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s + "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31 + "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 + "allwinner,sun8i-a23-apb1-gates-clk" - for the APB1 gates on A23 + "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80 + "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 + "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 + "allwinner,sun8i-a83t-bus-gates-clk" - for the bus gates on A83T + "allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3 + "allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80 + "allwinner,sun4i-a10-display-clk" - for the display clocks on the A10 + "allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10 + "allwinner,sun5i-a13-dram-gates-clk" - for the DRAM gates on A13 + "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 + "allwinner,sun4i-a10-mmc-clk" - for the MMC clock + "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80 + "allwinner,sun9i-a80-mmc-config-clk" - for mmc gates + resets on A80 + "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks + "allwinner,sun9i-a80-mod0-clk" - for module 0 (storage) clocks on A80 + "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 + "allwinner,sun7i-a20-out-clk" - for the external output clocks + "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 + "allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10 + "allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10 + "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 + "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 + "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31 + "allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23 + "allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3 + "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80 + "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80 + "allwinner,sun4i-a10-ve-clk" - for the Video Engine clock + "allwinner,sun6i-a31-display-clk" - for the display clocks + +Required properties for all clocks: +- reg : shall be the control register address for the clock. +- clocks : shall be the input parent clock(s) phandle for the clock. For + multiplexed clocks, the list order must match the hardware + programming order. +- #clock-cells : from common clock binding; shall be set to 0 except for + the following compatibles where it shall be set to 1: + "allwinner,*-gates-clk", "allwinner,sun4i-pll5-clk", + "allwinner,sun4i-pll6-clk", "allwinner,sun6i-a31-pll6-clk", + "allwinner,*-usb-clk", "allwinner,*-mmc-clk", + "allwinner,*-mmc-config-clk" +- clock-output-names : shall be the corresponding names of the outputs. + If the clock module only has one output, the name shall be the + module name. + +And "allwinner,*-usb-clk" clocks also require: +- reset-cells : shall be set to 1 + +The "allwinner,sun4i-a10-ve-clk" clock also requires: +- reset-cells : shall be set to 0 + +The "allwinner,sun9i-a80-mmc-config-clk" clock also requires: +- #reset-cells : shall be set to 1 +- resets : shall be the reset control phandle for the mmc block. + +For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate +dummy clocks at 25 MHz and 125 MHz, respectively. See example. + +Clock consumers should specify the desired clocks they use with a +"clocks" phandle cell. Consumers that are using a gated clock should +provide an additional ID in their clock property. This ID is the +offset of the bit controlling this particular gate in the register. +For the other clocks with "#clock-cells" = 1, the additional ID shall +refer to the index of the output. + +For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output +is the normal PLL6 output, or "pll6". The second output is rate doubled +PLL6, or "pll6x2". + +The "allwinner,*-mmc-clk" clocks have three different outputs: the +main clock, with the ID 0, and the output and sample clocks, with the +IDs 1 and 2, respectively. + +The "allwinner,sun9i-a80-mmc-config-clk" clock has one clock/reset output +per mmc controller. The number of outputs is determined by the size of +the address block, which is related to the overall mmc block. + +For example: + +osc24M: clk@1c20050 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-a10-osc-clk"; + reg = <0x01c20050 0x4>; + clocks = <&osc24M_fixed>; + clock-output-names = "osc24M"; +}; + +pll1: clk@1c20000 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-a10-pll1-clk"; + reg = <0x01c20000 0x4>; + clocks = <&osc24M>; + clock-output-names = "pll1"; +}; + +pll5: clk@1c20020 { + #clock-cells = <1>; + compatible = "allwinner,sun4i-pll5-clk"; + reg = <0x01c20020 0x4>; + clocks = <&osc24M>; + clock-output-names = "pll5_ddr", "pll5_other"; +}; + +pll6: clk@1c20028 { + #clock-cells = <1>; + compatible = "allwinner,sun6i-a31-pll6-clk"; + reg = <0x01c20028 0x4>; + clocks = <&osc24M>; + clock-output-names = "pll6", "pll6x2"; +}; + +cpu: cpu@1c20054 { + #clock-cells = <0>; + compatible = "allwinner,sun4i-a10-cpu-clk"; + reg = <0x01c20054 0x4>; + clocks = <&osc32k>, <&osc24M>, <&pll1>; + clock-output-names = "cpu"; +}; + +mmc0_clk: clk@1c20088 { + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; + reg = <0x01c20088 0x4>; + clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; + clock-output-names = "mmc0", "mmc0_output", "mmc0_sample"; +}; + +mii_phy_tx_clk: clk@2 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; + clock-output-names = "mii_phy_tx"; +}; + +gmac_int_tx_clk: clk@3 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <125000000>; + clock-output-names = "gmac_int_tx"; +}; + +gmac_clk: clk@1c20164 { + #clock-cells = <0>; + compatible = "allwinner,sun7i-a20-gmac-clk"; + reg = <0x01c20164 0x4>; + /* + * The first clock must be fixed at 25MHz; + * the second clock must be fixed at 125MHz + */ + clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>; + clock-output-names = "gmac"; +}; + +mmc_config_clk: clk@1c13000 { + compatible = "allwinner,sun9i-a80-mmc-config-clk"; + reg = <0x01c13000 0x10>; + clocks = <&ahb0_gates 8>; + clock-names = "ahb"; + resets = <&ahb0_resets 8>; + reset-names = "ahb"; + #clock-cells = <1>; + #reset-cells = <1>; + clock-output-names = "mmc0_config", "mmc1_config", + "mmc2_config", "mmc3_config"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/tango4-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/tango4-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..19c580a7bda258adb15a49314bdf45cccba4b4e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/tango4-clock.txt @@ -0,0 +1,23 @@ +* Sigma Designs Tango4 Clock Generator + +The Tango4 clock generator outputs cpu_clk and sys_clk (the latter is used +for RAM and various peripheral devices). The clock binding described here +is applicable to all Tango4 SoCs. + +Required Properties: + +- compatible: should be "sigma,tango4-clkgen". +- reg: physical base address of the device and length of memory mapped region. +- clocks: phandle of the input clock (crystal oscillator). +- clock-output-names: should be "cpuclk" and "sysclk". +- #clock-cells: should be set to 1. + +Example: + + clkgen: clkgen@10000 { + compatible = "sigma,tango4-clkgen"; + reg = <0x10000 0x40>; + clocks = <&xtal>; + clock-output-names = "cpuclk", "sysclk"; + #clock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti,cdce706.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti,cdce706.txt new file mode 100644 index 0000000000000000000000000000000000000000..959d96632f5d20496285cadcb0da4d1253145b0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti,cdce706.txt @@ -0,0 +1,42 @@ +Bindings for Texas Instruments CDCE706 programmable 3-PLL clock +synthesizer/multiplier/divider. + +Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf + +I2C device node required properties: +- compatible: shall be "ti,cdce706". +- reg: i2c device address, shall be in range [0x68...0x6b]. +- #clock-cells: from common clock binding; shall be set to 1. +- clocks: from common clock binding; list of parent clock + handles, shall be reference clock(s) connected to CLK_IN0 + and CLK_IN1 pins. +- clock-names: shall be clk_in0 and/or clk_in1. Use clk_in0 + in case of crystal oscillator or differential signal input + configuration. Use clk_in0 and clk_in1 in case of independent + single-ended LVCMOS inputs configuration. + +Example: + + clocks { + clk54: clk54 { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <54000000>; + }; + }; + ... + i2c0: i2c-master@d090000 { + ... + cdce706: clock-synth@69 { + compatible = "ti,cdce706"; + #clock-cells = <1>; + reg = <0x69>; + clocks = <&clk54>; + clock-names = "clk_in0"; + }; + }; + ... + simple-audio-card,codec { + ... + clocks = <&cdce706 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti,cdce925.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti,cdce925.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d01f2d5cc36e8cd4aa636f365ed55482c50d1d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti,cdce925.txt @@ -0,0 +1,49 @@ +Binding for TI CDCE913/925/937/949 programmable I2C clock synthesizers. + +Reference +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] http://www.ti.com/product/cdce913 +[3] http://www.ti.com/product/cdce925 +[4] http://www.ti.com/product/cdce937 +[5] http://www.ti.com/product/cdce949 + +The driver provides clock sources for each output Y1 through Y5. + +Required properties: + - compatible: Shall be one of the following: + - "ti,cdce913": 1-PLL, 3 Outputs + - "ti,cdce925": 2-PLL, 5 Outputs + - "ti,cdce937": 3-PLL, 7 Outputs + - "ti,cdce949": 4-PLL, 9 Outputs + - reg: I2C device address. + - clocks: Points to a fixed parent clock that provides the input frequency. + - #clock-cells: From common clock bindings: Shall be 1. + +Optional properties: + - xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a + board, or to compensate for external influences. + +For all PLL1, PLL2, ... an optional child node can be used to specify spread +spectrum clocking parameters for a board. + - spread-spectrum: SSC mode as defined in the data sheet. + - spread-spectrum-center: Use "centered" mode instead of "max" mode. When + present, the clock runs at the requested frequency on average. Otherwise + the requested frequency is the maximum value of the SCC range. + + +Example: + + clockgen: cdce925pw@64 { + compatible = "cdce925"; + reg = <0x64>; + clocks = <&xtal_27Mhz>; + #clock-cells = <1>; + xtal-load-pf = <5>; + /* PLL options to get SSC 1% centered */ + PLL2 { + spread-spectrum = <4>; + spread-spectrum-center; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti,sci-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti,sci-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e59dc6b177897b3840388d7b192286e28d7e67b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti,sci-clk.txt @@ -0,0 +1,36 @@ +Texas Instruments TI-SCI Clocks +=============================== + +All clocks on Texas Instruments' SoCs that contain a System Controller, +are only controlled by this entity. Communication between a host processor +running an OS and the System Controller happens through a protocol known +as TI-SCI[1]. This clock implementation plugs into the common clock +framework and makes use of the TI-SCI protocol on clock API requests. + +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt + +Required properties: +------------------- +- compatible: Must be "ti,k2g-sci-clk" +- #clock-cells: Shall be 2. + In clock consumers, this cell represents the device ID and clock ID + exposed by the PM firmware. The list of valid values for the device IDs + and clocks IDs for 66AK2G SoC are documented at + http://processors.wiki.ti.com/index.php/TISCI#66AK2G02_Data + +Examples: +-------- + +pmmc: pmmc { + compatible = "ti,k2g-sci"; + + k2g_clks: clocks { + compatible = "ti,k2g-sci-clk"; + #clock-cells = <2>; + }; +}; + +uart0: serial@2530c00 { + compatible = "ns16550a"; + clocks = <&k2g_clks 0x2c 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti-clkctrl.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti-clkctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..48ee6991f2cc7cb3de83550030300536449bd92a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti-clkctrl.txt @@ -0,0 +1,56 @@ +Texas Instruments clkctrl clock binding + +Texas Instruments SoCs can have a clkctrl clock controller for each +interconnect target module. The clkctrl clock controller manages functional +and interface clocks for each module. Each clkctrl controller can also +gate one or more optional functional clocks for a module, and can have one +or more clock muxes. There is a clkctrl clock controller typically for each +interconnect target module on omap4 and later variants. + +The clock consumers can specify the index of the clkctrl clock using +the hardware offset from the clkctrl instance register space. The optional +clocks can be specified by clkctrl hardware offset and the index of the +optional clock. + +For more information, please see the Linux clock framework binding at +Documentation/devicetree/bindings/clock/clock-bindings.txt. + +Required properties : +- compatible : shall be "ti,clkctrl" +- #clock-cells : shall contain 2 with the first entry being the instance + offset from the clock domain base and the second being the + clock index + +Example: Clock controller node on omap 4430: + +&cm2 { + l4per: cm@1400 { + cm_l4per@0 { + cm_l4per_clkctrl: clk@20 { + compatible = "ti,clkctrl"; + reg = <0x20 0x1b0>; + #clock-cells = <2>; + }; + }; + }; +}; + +Example: Preprocessor helper macros in dt-bindings/clock/ti-clkctrl.h + +#define OMAP4_CLKCTRL_OFFSET 0x20 +#define OMAP4_CLKCTRL_INDEX(offset) ((offset) - OMAP4_CLKCTRL_OFFSET) +#define MODULEMODE_HWCTRL 1 +#define MODULEMODE_SWCTRL 2 + +#define OMAP4_GPTIMER10_CLKTRL OMAP4_CLKCTRL_INDEX(0x28) +#define OMAP4_GPTIMER11_CLKTRL OMAP4_CLKCTRL_INDEX(0x30) +#define OMAP4_GPTIMER2_CLKTRL OMAP4_CLKCTRL_INDEX(0x38) +... +#define OMAP4_GPIO2_CLKCTRL OMAP_CLKCTRL_INDEX(0x60) + +Example: Clock consumer node for GPIO2: + +&gpio2 { + clocks = <&cm_l4per_clkctrl OMAP4_GPIO2_CLKCTRL 0 + &cm_l4per_clkctrl OMAP4_GPIO2_CLKCTRL 8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti-keystone-pllctrl.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti-keystone-pllctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c35cb6c4af4d9fd7e681de3c9d6a5bdbe629e034 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti-keystone-pllctrl.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Texas Instruments keystone pll controller + +The main pll controller used to drive theC66x CorePacs, the switch fabric, +and a majority of the peripheral clocks (all but the ARM CorePacs, DDR3 and +the NETCP modules) requires a PLL Controller to manage the various clock +divisions, gating, and synchronization. + +Required properties: + +- compatible: "ti,keystone-pllctrl", "syscon" + +- reg: contains offset/length value for pll controller + registers space. + +Example: + +pllctrl: pll-controller@02310000 { + compatible = "ti,keystone-pllctrl", "syscon"; + reg = <0x02310000 0x200>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/adpll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/adpll.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c8a2ce2cd70181ead140f3df75472fdc0151bdb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/adpll.txt @@ -0,0 +1,41 @@ +Binding for Texas Instruments ADPLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped ADPLL with two to three selectable input clocks +and three to four children. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of "ti,dm814-adpll-s-clock" or + "ti,dm814-adpll-lj-clock" depending on the type of the ADPLL +- #clock-cells : from common clock binding; shall be set to 1. +- clocks : link phandles of parent clocks clkinp and clkinpulow, note + that the adpll-s-clock also has an optional clkinphif +- reg : address and length of the register set for controlling the ADPLL. + +Examples: + adpll_mpu_ck: adpll@40 { + #clock-cells = <1>; + compatible = "ti,dm814-adpll-s-clock"; + reg = <0x40 0x40>; + clocks = <&devosc_ck &devosc_ck &devosc_ck>; + clock-names = "clkinp", "clkinpulow", "clkinphif"; + clock-output-names = "481c5040.adpll.dcoclkldo", + "481c5040.adpll.clkout", + "481c5040.adpll.clkoutx2", + "481c5040.adpll.clkouthif"; + }; + + adpll_dsp_ck: adpll@80 { + #clock-cells = <1>; + compatible = "ti,dm814-adpll-lj-clock"; + reg = <0x80 0x30>; + clocks = <&devosc_ck &devosc_ck>; + clock-names = "clkinp", "clkinpulow"; + clock-output-names = "481c5080.adpll.dcoclkldo", + "481c5080.adpll.clkout", + "481c5080.adpll.clkoutldo"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/apll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/apll.txt new file mode 100644 index 0000000000000000000000000000000000000000..ade4dd4c30f0e12804a94845b71ee462e30f1d99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/apll.txt @@ -0,0 +1,45 @@ +Binding for Texas Instruments APLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped APLL with usually two selectable input clocks +(reference clock and bypass clock), with analog phase locked +loop logic for multiplying the input clock to a desired output +clock. This clock also typically supports different operation +modes (locked, low power stop etc.) APLL mostly behaves like +a subtype of a DPLL [2], although a simplified one at that. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/dpll.txt + +Required properties: +- compatible : shall be "ti,dra7-apll-clock" or "ti,omap2-apll-clock" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks (clk-ref and clk-bypass) +- reg : address and length of the register set for controlling the APLL. + It contains the information of registers in the following order: + "control" - contains the control register offset + "idlest" - contains the idlest register offset + "autoidle" - contains the autoidle register offset (OMAP2 only) +- ti,clock-frequency : static clock frequency for the clock (OMAP2 only) +- ti,idlest-shift : bit-shift for the idlest field (OMAP2 only) +- ti,bit-shift : bit-shift for enable and autoidle fields (OMAP2 only) + +Examples: + apll_pcie_ck: apll_pcie_ck { + #clock-cells = <0>; + clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>; + reg = <0x021c>, <0x0220>; + compatible = "ti,dra7-apll-clock"; + }; + + apll96_ck: apll96_ck { + #clock-cells = <0>; + compatible = "ti,omap2-apll-clock"; + clocks = <&sys_ck>; + ti,bit-shift = <2>; + ti,idlest-shift = <8>; + ti,clock-frequency = <96000000>; + reg = <0x0500>, <0x0530>, <0x0520>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/autoidle.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/autoidle.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c735dde9fe971d7ad20f6c6b403581421b2b4c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/autoidle.txt @@ -0,0 +1,39 @@ +Binding for Texas Instruments autoidle clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a register mapped +clock which can be put to idle automatically by hardware based on the usage +and a configuration bit setting. Autoidle clock is never an individual +clock, it is always a derivative of some basic clock like a gate, divider, +or fixed-factor. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- reg : offset for the register controlling the autoidle +- ti,autoidle-shift : bit shift of the autoidle enable bit +- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0 + +Examples: + dpll_core_m4_ck: dpll_core_m4_ck { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + ti,autoidle-shift = <8>; + reg = <0x2d38>; + ti,index-starts-at-one; + ti,invert-autoidle-bit; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/clockdomain.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/clockdomain.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb76b3f2b3415af3fbccda56dcbddc6368d2323d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/clockdomain.txt @@ -0,0 +1,24 @@ +Binding for Texas Instruments clockdomain. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1] in consumer role. +Every clock on TI SoC belongs to one clockdomain, but software +only needs this information for specific clocks which require +their parent clockdomain to be controlled when the clock is +enabled/disabled. This binding doesn't define a new clock +binding type, it is used to group existing clock nodes under +hardware hierarchy. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,clockdomain" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of clocks within this domain + +Examples: + dss_clkdm: dss_clkdm { + compatible = "ti,clockdomain"; + clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/composite.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/composite.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f43c4706b0944d5b025485f41ca4bb16343c592 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/composite.txt @@ -0,0 +1,54 @@ +Binding for TI composite clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped composite clock with multiple different sub-types; + +a multiplexer clock with multiple input clock signals or parents, one +of which can be selected as output, this behaves exactly as [2] + +an adjustable clock rate divider, this behaves exactly as [3] + +a gating function which can be used to enable and disable the output +clock, this behaves exactly as [4] + +The binding must provide a list of the component clocks that shall be +merged to this clock. The component clocks shall be of one of the +"ti,*composite*-clock" types. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/mux.txt +[3] Documentation/devicetree/bindings/clock/ti/divider.txt +[4] Documentation/devicetree/bindings/clock/ti/gate.txt + +Required properties: +- compatible : shall be: "ti,composite-clock" +- clocks : link phandles of component clocks +- #clock-cells : from common clock binding; shall be set to 0. + +Examples: + +usb_l4_gate_ick: usb_l4_gate_ick { + #clock-cells = <0>; + compatible = "ti,composite-interface-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <5>; + reg = <0x0a10>; +}; + +usb_l4_div_ick: usb_l4_div_ick { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&l4_ick>; + ti,bit-shift = <4>; + ti,max-div = <1>; + reg = <0x0a40>; + ti,index-starts-at-one; +}; + +usb_l4_ick: usb_l4_ick { + #clock-cells = <0>; + compatible = "ti,composite-clock"; + clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/da8xx-cfgchip.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/da8xx-cfgchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e03dce99a8f3f6ea977493e9fb6093f7719bdaa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/da8xx-cfgchip.txt @@ -0,0 +1,93 @@ +Binding for TI DA8XX/OMAP-L13X/AM17XX/AM18XX CFGCHIP clocks + +TI DA8XX/OMAP-L13X/AM17XX/AM18XX SoCs contain a general purpose set of +registers call CFGCHIPn. Some of these registers function as clock +gates. This document describes the bindings for those clocks. + +All of the clock nodes described below must be child nodes of a CFGCHIP node +(compatible = "ti,da830-cfgchip"). + +USB PHY clocks +-------------- +Required properties: +- compatible: shall be "ti,da830-usb-phy-clocks". +- #clock-cells: from common clock binding; shall be set to 1. +- clocks: phandles to the parent clocks corresponding to clock-names +- clock-names: shall be "fck", "usb_refclkin", "auxclk" + +This node provides two clocks. The clock at index 0 is the USB 2.0 PHY 48MHz +clock and the clock at index 1 is the USB 1.1 PHY 48MHz clock. + +eHRPWM Time Base Clock (TBCLK) +------------------------------ +Required properties: +- compatible: shall be "ti,da830-tbclksync". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandle to the parent clock +- clock-names: shall be "fck" + +PLL DIV4.5 divider +------------------ +Required properties: +- compatible: shall be "ti,da830-div4p5ena". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandle to the parent clock +- clock-names: shall be "pll0_pllout" + +EMIFA clock source (ASYNC1) +--------------------------- +Required properties: +- compatible: shall be "ti,da850-async1-clksrc". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandles to the parent clocks corresponding to clock-names +- clock-names: shall be "pll0_sysclk3", "div4.5" + +ASYNC3 clock source +------------------- +Required properties: +- compatible: shall be "ti,da850-async3-clksrc". +- #clock-cells: from common clock binding; shall be set to 0. +- clocks: phandles to the parent clocks corresponding to clock-names +- clock-names: shall be "pll0_sysclk2", "pll1_sysclk2" + +Examples: + + cfgchip: syscon@1417c { + compatible = "ti,da830-cfgchip", "syscon", "simple-mfd"; + reg = <0x1417c 0x14>; + + usb_phy_clk: usb-phy-clocks { + compatible = "ti,da830-usb-phy-clocks"; + #clock-cells = <1>; + clocks = <&psc1 1>, <&usb_refclkin>, <&pll0_auxclk>; + clock-names = "fck", "usb_refclkin", "auxclk"; + }; + ehrpwm_tbclk: ehrpwm_tbclk { + compatible = "ti,da830-tbclksync"; + #clock-cells = <0>; + clocks = <&psc1 17>; + clock-names = "fck"; + }; + div4p5_clk: div4.5 { + compatible = "ti,da830-div4p5ena"; + #clock-cells = <0>; + clocks = <&pll0_pllout>; + clock-names = "pll0_pllout"; + }; + async1_clk: async1 { + compatible = "ti,da850-async1-clksrc"; + #clock-cells = <0>; + clocks = <&pll0_sysclk 3>, <&div4p5_clk>; + clock-names = "pll0_sysclk3", "div4.5"; + }; + async3_clk: async3 { + compatible = "ti,da850-async3-clksrc"; + #clock-cells = <0>; + clocks = <&pll0_sysclk 2>, <&pll1_sysclk 2>; + clock-names = "pll0_sysclk2", "pll1_sysclk2"; + }; + }; + +Also see: +- Documentation/devicetree/bindings/clock/clock-bindings.txt + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/pll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..36998e184821aef65cf32efdf0670fece08a8923 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/pll.txt @@ -0,0 +1,96 @@ +Binding for TI DaVinci PLL Controllers + +The PLL provides clocks to most of the components on the SoC. In addition +to the PLL itself, this controller also contains bypasses, gates, dividers, +an multiplexers for various clock signals. + +Required properties: +- compatible: shall be one of: + - "ti,da850-pll0" for PLL0 on DA850/OMAP-L138/AM18XX + - "ti,da850-pll1" for PLL1 on DA850/OMAP-L138/AM18XX +- reg: physical base address and size of the controller's register area. +- clocks: phandles corresponding to the clock names +- clock-names: names of the clock sources - depends on compatible string + - for "ti,da850-pll0", shall be "clksrc", "extclksrc" + - for "ti,da850-pll1", shall be "clksrc" + +Optional properties: +- ti,clkmode-square-wave: Indicates that the the board is supplying a square + wave input on the OSCIN pin instead of using a crystal oscillator. + This property is only valid when compatible = "ti,da850-pll0". + + +Optional child nodes: + +pllout + Describes the main PLL clock output (before POSTDIV). The node name must + be "pllout". + + Required properties: + - #clock-cells: shall be 0 + +sysclk + Describes the PLLDIVn divider clocks that provide the SYSCLKn clock + domains. The node name must be "sysclk". Consumers of this node should + use "n" in "SYSCLKn" as the index parameter for the clock cell. + + Required properties: + - #clock-cells: shall be 1 + +auxclk + Describes the AUXCLK output of the PLL. The node name must be "auxclk". + This child node is only valid when compatible = "ti,da850-pll0". + + Required properties: + - #clock-cells: shall be 0 + +obsclk + Describes the OBSCLK output of the PLL. The node name must be "obsclk". + + Required properties: + - #clock-cells: shall be 0 + + +Examples: + + pll0: clock-controller@11000 { + compatible = "ti,da850-pll0"; + reg = <0x11000 0x1000>; + clocks = <&ref_clk>, <&pll1_sysclk 3>; + clock-names = "clksrc", "extclksrc"; + ti,clkmode-square-wave; + + pll0_pllout: pllout { + #clock-cells = <0>; + }; + + pll0_sysclk: sysclk { + #clock-cells = <1>; + }; + + pll0_auxclk: auxclk { + #clock-cells = <0>; + }; + + pll0_obsclk: obsclk { + #clock-cells = <0>; + }; + }; + + pll1: clock-controller@21a000 { + compatible = "ti,da850-pll1"; + reg = <0x21a000 0x1000>; + clocks = <&ref_clk>; + clock-names = "clksrc"; + + pll0_sysclk: sysclk { + #clock-cells = <1>; + }; + + pll0_obsclk: obsclk { + #clock-cells = <0>; + }; + }; + +Also see: +- Documentation/devicetree/bindings/clock/clock-bindings.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/psc.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/psc.txt new file mode 100644 index 0000000000000000000000000000000000000000..dae4ad8e198cbfbc61a0b45433710b87d5832594 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/davinci/psc.txt @@ -0,0 +1,71 @@ +Binding for TI DaVinci Power Sleep Controller (PSC) + +The PSC provides power management, clock gating and reset functionality. It is +primarily used for clocking. + +Required properties: +- compatible: shall be one of: + - "ti,da850-psc0" for PSC0 on DA850/OMAP-L138/AM18XX + - "ti,da850-psc1" for PSC1 on DA850/OMAP-L138/AM18XX +- reg: physical base address and size of the controller's register area +- #clock-cells: from common clock binding; shall be set to 1 +- #power-domain-cells: from generic power domain binding; shall be set to 1. +- clocks: phandles to clocks corresponding to the clock-names property +- clock-names: list of parent clock names - depends on compatible value + - for "ti,da850-psc0", shall be "pll0_sysclk1", "pll0_sysclk2", + "pll0_sysclk4", "pll0_sysclk6", "async1" + - for "ti,da850-psc1", shall be "pll0_sysclk2", "pll0_sysclk4", "async3" + +Optional properties: +- #reset-cells: from reset binding; shall be set to 1 - only applicable when + at least one local domain provides a local reset. + +Consumers: + + Clock, power domain and reset consumers shall use the local power domain + module ID (LPSC) as the index corresponding to the clock cell. Refer to + the device-specific datasheet to find these numbers. NB: Most local + domains only provide a clock/power domain and not a reset. + +Examples: + + psc0: clock-controller@10000 { + compatible = "ti,da850-psc0"; + reg = <0x10000 0x1000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + #reset-cells = <1>; + clocks = <&pll0_sysclk 1>, <&pll0_sysclk 2>, + <&pll0_sysclk 4>, <&pll0_sysclk 6>, <&async1_clk>; + clock_names = "pll0_sysclk1", "pll0_sysclk2", + "pll0_sysclk4", "pll0_sysclk6", "async1"; + }; + psc1: clock-controller@227000 { + compatible = "ti,da850-psc1"; + reg = <0x227000 0x1000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + clocks = <&pll0_sysclk 2>, <&pll0_sysclk 4>, <&async3_clk>; + clock_names = "pll0_sysclk2", "pll0_sysclk4", "async3"; + }; + + /* consumer */ + dsp: dsp@11800000 { + compatible = "ti,da850-dsp"; + reg = <0x11800000 0x40000>, + <0x11e00000 0x8000>, + <0x11f00000 0x8000>, + <0x01c14044 0x4>, + <0x01c14174 0x8>; + reg-names = "l2sram", "l1pram", "l1dram", "host1cfg", "chipsig"; + interrupt-parent = <&intc>; + interrupts = <28>; + clocks = <&psc0 15>; + power-domains = <&psc0 15>; + resets = <&psc0 15>; + }; + +Also see: +- Documentation/devicetree/bindings/clock/clock-bindings.txt +- Documentation/devicetree/bindings/power/power_domain.txt +- Documentation/devicetree/bindings/reset/reset.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/divider.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/divider.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b13b32974f9926874d1a893fa00be961c5aef4d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/divider.txt @@ -0,0 +1,117 @@ +Binding for TI divider clock + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped adjustable clock rate divider that does not gate and has +only one input clock or parent. By default the value programmed into +the register is one less than the actual divisor value. E.g: + +register value actual divisor value +0 1 +1 2 +2 3 + +This assumption may be modified by the following optional properties: + +ti,index-starts-at-one - valid divisor values start at 1, not the default +of 0. E.g: +register value actual divisor value +1 1 +2 2 +3 3 + +ti,index-power-of-two - valid divisor values are powers of two. E.g: +register value actual divisor value +0 1 +1 2 +2 4 + +Additionally an array of valid dividers may be supplied like so: + + ti,dividers = <4>, <8>, <0>, <16>; + +Which will map the resulting values to a divisor table by their index: +register value actual divisor value +0 4 +1 8 +2 +3 16 + +Any zero value in this array means the corresponding bit-value is invalid +and must not be used. + +The binding must also provide the register to control the divider and +unless the divider array is provided, min and max dividers. Optionally +the number of bits to shift that mask, if necessary. If the shift value +is missing it is the same as supplying a zero shift. + +This binding can also optionally provide support to the hardware autoidle +feature, see [2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +Required properties: +- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link to phandle of parent clock +- reg : offset for register controlling adjustable divider + +Optional properties: +- clock-output-names : from common clock binding. +- ti,dividers : array of integers defining divisors +- ti,bit-shift : number of bits to shift the divider value, defaults to 0 +- ti,min-div : min divisor for dividing the input clock rate, only + needed if the first divisor is offset from the default value (1) +- ti,max-div : max divisor for dividing the input clock rate, only needed + if ti,dividers is not defined. +- ti,index-starts-at-one : valid divisor programming starts at 1, not zero, + only valid if ti,dividers is not defined. +- ti,index-power-of-two : valid divisor programming must be a power of two, + only valid if ti,dividers is not defined. +- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock, + see [2] +- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0, + see [2] +- ti,set-rate-parent : clk_set_rate is propagated to parent +- ti,latch-bit : latch the divider value to HW, only needed if the register + access requires this. As an example dra76x DPLL_GMAC H14 divider implements + such behavior. + +Examples: +dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&dpll_usb_ck>; + ti,max-div = <127>; + reg = <0x190>; + ti,index-starts-at-one; +}; + +aess_fclk: aess_fclk@4a004528 { + #clock-cells = <0>; + compatible = "ti,divider-clock"; + clocks = <&abe_clk>; + ti,bit-shift = <24>; + reg = <0x528>; + ti,max-div = <2>; +}; + +dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&dpll_core_x2_ck>; + ti,max-div = <31>; + reg = <0x0134>; + ti,index-starts-at-one; +}; + +ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 { + #clock-cells = <0>; + compatible = "ti,composite-divider-clock"; + clocks = <&corex2_fck>; + ti,bit-shift = <8>; + reg = <0x0a40>; + ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/dpll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/dpll.txt new file mode 100644 index 0000000000000000000000000000000000000000..df57009ff8e74ff48693220908f3a8f1581e15f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/dpll.txt @@ -0,0 +1,85 @@ +Binding for Texas Instruments DPLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped DPLL with usually two selectable input clocks +(reference clock and bypass clock), with digital phase locked +loop logic for multiplying the input clock to a desired output +clock. This clock also typically supports different operation +modes (locked, low power stop etc.) This binding has several +sub-types, which effectively result in slightly different setup +for the actual DPLL clock. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of: + "ti,omap3-dpll-clock", + "ti,omap3-dpll-core-clock", + "ti,omap3-dpll-per-clock", + "ti,omap3-dpll-per-j-type-clock", + "ti,omap4-dpll-clock", + "ti,omap4-dpll-x2-clock", + "ti,omap4-dpll-core-clock", + "ti,omap4-dpll-m4xen-clock", + "ti,omap4-dpll-j-type-clock", + "ti,omap5-mpu-dpll-clock", + "ti,am3-dpll-no-gate-clock", + "ti,am3-dpll-j-type-clock", + "ti,am3-dpll-no-gate-j-type-clock", + "ti,am3-dpll-clock", + "ti,am3-dpll-core-clock", + "ti,am3-dpll-x2-clock", + "ti,omap2-dpll-core-clock", + +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks, first entry lists reference clock + and second entry bypass clock +- reg : offsets for the register set for controlling the DPLL. + Registers are listed in following order: + "control" - contains the control register base address + "idlest" - contains the idle status register base address + "mult-div1" - contains the multiplier / divider register base address + "autoidle" - contains the autoidle register base address (optional) + ti,am3-* dpll types do not have autoidle register + ti,omap2-* dpll type does not support idlest / autoidle registers + +Optional properties: +- DPLL mode setting - defining any one or more of the following overrides + default setting. + - ti,low-power-stop : DPLL supports low power stop mode, gating output + - ti,low-power-bypass : DPLL output matches rate of parent bypass clock + - ti,lock : DPLL locks in programmed rate + +Examples: + dpll_core_ck: dpll_core_ck@44e00490 { + #clock-cells = <0>; + compatible = "ti,omap4-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x490>, <0x45c>, <0x488>, <0x468>; + }; + + dpll2_ck: dpll2_ck@48004004 { + #clock-cells = <0>; + compatible = "ti,omap3-dpll-clock"; + clocks = <&sys_ck>, <&dpll2_fck>; + ti,low-power-stop; + ti,low-power-bypass; + ti,lock; + reg = <0x4>, <0x24>, <0x34>, <0x40>; + }; + + dpll_core_ck: dpll_core_ck@44e00490 { + #clock-cells = <0>; + compatible = "ti,am3-dpll-core-clock"; + clocks = <&sys_clkin_ck>, <&sys_clkin_ck>; + reg = <0x90>, <0x5c>, <0x68>; + }; + + dpll_ck: dpll_ck { + #clock-cells = <0>; + compatible = "ti,omap2-dpll-core-clock"; + clocks = <&sys_ck>, <&sys_ck>; + reg = <0x0500>, <0x0540>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/dra7-atl.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/dra7-atl.txt new file mode 100644 index 0000000000000000000000000000000000000000..10f7047755f39817d7d5bf3d4b369ebd46227fa0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/dra7-atl.txt @@ -0,0 +1,94 @@ +Device Tree Clock bindings for ATL (Audio Tracking Logic) of DRA7 SoC. + +The ATL IP is used to generate clock to be used to synchronize baseband and +audio codec. A single ATL IP provides four ATL clock instances sharing the same +functional clock but can be configured to provide different clocks. +ATL can maintain a clock averages to some desired frequency based on the bws/aws +signals - can compensate the drift between the two ws signal. + +In order to provide the support for ATL and it's output clocks (which can be used +internally within the SoC or external components) two sets of bindings is needed: + +Clock tree binding: +This binding uses the common clock binding[1]. +To be able to integrate the ATL clocks with DT clock tree. +Provides ccf level representation of the ATL clocks to be used by drivers. +Since the clock instances are part of a single IP this binding is used as a node +for the DT clock tree, the IP driver is needed to handle the actual configuration +of the IP. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,dra7-atl-clock" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles to functional clock of ATL + +Binding for the IP driver: +This binding is used to configure the IP driver which is going to handle the +configuration of the IP for the ATL clock instances. + +Required properties: +- compatible : shall be "ti,dra7-atl" +- reg : base address for the ATL IP +- ti,provided-clocks : List of phandles to the clocks associated with the ATL +- clocks : link phandles to functional clock of ATL +- clock-names : Shall be set to "fck" +- ti,hwmods : Shall be set to "atl" + +Optional properties: +Configuration of ATL instances: +- atl{0/1/2/3} { + - bws : Baseband word select signal selection + - aws : Audio word select signal selection +}; + +For valid word select signals, see the dt-bindings/clk/ti-dra7-atl.h include +file. + +Examples: +/* clock bindings for atl provided clocks */ +atl_clkin0_ck: atl_clkin0_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +atl_clkin1_ck: atl_clkin1_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +atl_clkin2_ck: atl_clkin2_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +atl_clkin3_ck: atl_clkin3_ck { + #clock-cells = <0>; + compatible = "ti,dra7-atl-clock"; + clocks = <&atl_gfclk_mux>; +}; + +/* binding for the IP */ +atl: atl@4843c000 { + compatible = "ti,dra7-atl"; + reg = <0x4843c000 0x3ff>; + ti,hwmods = "atl"; + ti,provided-clocks = <&atl_clkin0_ck>, <&atl_clkin1_ck>, + <&atl_clkin2_ck>, <&atl_clkin3_ck>; + clocks = <&atl_gfclk_mux>; + clock-names = "fck"; +}; + +#include + +&atl { + + atl2 { + bws = ; + aws = ; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/fapll.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/fapll.txt new file mode 100644 index 0000000000000000000000000000000000000000..c19b3f253b8cf7fa31ed962ef076ce6e56681f4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/fapll.txt @@ -0,0 +1,33 @@ +Binding for Texas Instruments FAPLL clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped FAPLL with usually two selectable input clocks +(reference clock and bypass clock), and one or more child +syntesizers. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,dm816-fapll-clock" +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks (clk-ref and clk-bypass) +- reg : address and length of the register set for controlling the FAPLL. + +Examples: + main_fapll: main_fapll { + #clock-cells = <1>; + compatible = "ti,dm816-fapll-clock"; + reg = <0x400 0x40>; + clocks = <&sys_clkin_ck &sys_clkin_ck>; + clock-indices = <1>, <2>, <3>, <4>, <5>, + <6>, <7>; + clock-output-names = "main_pll_clk1", + "main_pll_clk2", + "main_pll_clk3", + "main_pll_clk4", + "main_pll_clk5", + "main_pll_clk6", + "main_pll_clk7"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/fixed-factor-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/fixed-factor-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..662b36d53bf0b616bdbd365d62807e80b57cfbda --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/fixed-factor-clock.txt @@ -0,0 +1,43 @@ +Binding for TI fixed factor rate clock sources. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1], and also uses the autoidle +support from TI autoidle clock [2]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt + +Required properties: +- compatible : shall be "ti,fixed-factor-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- ti,clock-div: fixed divider. +- ti,clock-mult: fixed multiplier. +- clocks: parent clock. + +Optional properties: +- ti,autoidle-shift: bit shift of the autoidle enable bit for the clock, + see [2] +- reg: offset for the autoidle register of this clock, see [2] +- ti,invert-autoidle-bit: autoidle is enabled by setting the bit to 0, see [2] +- ti,set-rate-parent: clk_set_rate is propagated to parent + +Example: + clock { + compatible = "ti,fixed-factor-clock"; + clocks = <&parentclk>; + #clock-cells = <0>; + ti,clock-div = <2>; + ti,clock-mult = <1>; + }; + + dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck { + #clock-cells = <0>; + compatible = "ti,fixed-factor-clock"; + clocks = <&dpll_usb_ck>; + ti,clock-div = <1>; + ti,autoidle-shift = <8>; + reg = <0x01b4>; + ti,clock-mult = <1>; + ti,invert-autoidle-bit; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/gate.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/gate.txt new file mode 100644 index 0000000000000000000000000000000000000000..56d603c1f71685678a6cf9d8a52da537cff721bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/gate.txt @@ -0,0 +1,106 @@ +Binding for Texas Instruments gate clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. This clock is +quite much similar to the basic gate-clock [2], however, +it supports a number of additional features. If no register +is provided for this clock, the code assumes that a clockdomain +will be controlled instead and the corresponding hw-ops for +that is used. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.txt +[3] Documentation/devicetree/bindings/clock/ti/clockdomain.txt + +Required properties: +- compatible : shall be one of: + "ti,gate-clock" - basic gate clock + "ti,wait-gate-clock" - gate clock which waits until clock is active before + returning from clk_enable() + "ti,dss-gate-clock" - gate clock with DSS specific hardware handling + "ti,am35xx-gate-clock" - gate clock with AM35xx specific hardware handling + "ti,clkdm-gate-clock" - clockdomain gate clock, which derives its functional + clock directly from a clockdomain, see [3] how + to map clockdomains properly + "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling, + required for a hardware errata + "ti,composite-gate-clock" - composite gate clock, to be part of composite + clock + "ti,composite-no-wait-gate-clock" - composite gate clock that does not wait + for clock to be active before returning + from clk_enable() +- #clock-cells : from common clock binding; shall be set to 0 +- clocks : link to phandle of parent clock +- reg : offset for register controlling adjustable gate, not needed for + ti,clkdm-gate-clock type + +Optional properties: +- ti,bit-shift : bit shift for programming the clock gate, invalid for + ti,clkdm-gate-clock type +- ti,set-bit-to-disable : inverts default gate programming. Setting the bit + gates the clock and clearing the bit ungates the clock. + +Examples: + mmchs2_fck: mmchs2_fck@48004a00 { + #clock-cells = <0>; + compatible = "ti,gate-clock"; + clocks = <&core_96m_fck>; + reg = <0x0a00>; + ti,bit-shift = <25>; + }; + + uart4_fck_am35xx: uart4_fck_am35xx { + #clock-cells = <0>; + compatible = "ti,wait-gate-clock"; + clocks = <&core_48m_fck>; + reg = <0x0a00>; + ti,bit-shift = <23>; + }; + + dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2@48004e00 { + #clock-cells = <0>; + compatible = "ti,dss-gate-clock"; + clocks = <&dpll4_m4x2_ck>; + reg = <0x0e00>; + ti,bit-shift = <0>; + }; + + emac_ick: emac_ick@4800259c { + #clock-cells = <0>; + compatible = "ti,am35xx-gate-clock"; + clocks = <&ipss_ick>; + reg = <0x059c>; + ti,bit-shift = <1>; + }; + + emu_src_ck: emu_src_ck { + #clock-cells = <0>; + compatible = "ti,clkdm-gate-clock"; + clocks = <&emu_src_mux_ck>; + }; + + dpll4_m2x2_ck: dpll4_m2x2_ck@48004d00 { + #clock-cells = <0>; + compatible = "ti,hsdiv-gate-clock"; + clocks = <&dpll4_m2x2_mul_ck>; + ti,bit-shift = <0x1b>; + reg = <0x0d00>; + ti,set-bit-to-disable; + }; + + vlynq_gate_fck: vlynq_gate_fck { + #clock-cells = <0>; + compatible = "ti,composite-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <3>; + reg = <0x0200>; + }; + + sys_clkout2_src_gate: sys_clkout2_src_gate { + #clock-cells = <0>; + compatible = "ti,composite-no-wait-gate-clock"; + clocks = <&core_ck>; + ti,bit-shift = <15>; + reg = <0x0070>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/interface.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/interface.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f4704040140d1dd350148da2dff43cff63f9120 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/interface.txt @@ -0,0 +1,56 @@ +Binding for Texas Instruments interface clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. This clock is +quite much similar to the basic gate-clock [2], however, +it supports a number of additional features, including +companion clock finding (match corresponding functional gate +clock) and hardware autoidle enable / disable. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.txt + +Required properties: +- compatible : shall be one of: + "ti,omap3-interface-clock" - basic OMAP3 interface clock + "ti,omap3-no-wait-interface-clock" - interface clock which has no hardware + capability for waiting clock to be ready + "ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW + handling + "ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling + "ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling + "ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling + "ti,omap2430-interface-clock" - interface clock with OMAP2430 specific HW + handling +- #clock-cells : from common clock binding; shall be set to 0 +- clocks : link to phandle of parent clock +- reg : base address for the control register + +Optional properties: +- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0) + +Examples: + aes1_ick: aes1_ick@48004a14 { + #clock-cells = <0>; + compatible = "ti,omap3-interface-clock"; + clocks = <&security_l4_ick2>; + reg = <0x48004a14 0x4>; + ti,bit-shift = <3>; + }; + + cam_ick: cam_ick@48004f10 { + #clock-cells = <0>; + compatible = "ti,omap3-no-wait-interface-clock"; + clocks = <&l4_ick>; + reg = <0x48004f10 0x4>; + ti,bit-shift = <0>; + }; + + ssi_ick_3430es2: ssi_ick_3430es2@48004a10 { + #clock-cells = <0>; + compatible = "ti,omap3-ssi-interface-clock"; + clocks = <&ssi_l4_ick>; + reg = <0x48004a10 0x4>; + ti,bit-shift = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ti/mux.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ti/mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..eec8994b9be876752795bc4a37dc526329b9e453 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ti/mux.txt @@ -0,0 +1,79 @@ +Binding for TI mux clock. + +Binding status: Unstable - ABI compatibility may be broken in the future + +This binding uses the common clock binding[1]. It assumes a +register-mapped multiplexer with multiple input clock signals or +parents, one of which can be selected as output. This clock does not +gate or adjust the parent rate via a divider or multiplier. + +By default the "clocks" property lists the parents in the same order +as they are programmed into the regster. E.g: + + clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>; + +results in programming the register as follows: + +register value selected parent clock +0 foo_clock +1 bar_clock +2 baz_clock + +Some clock controller IPs do not allow a value of zero to be programmed +into the register, instead indexing begins at 1. The optional property +"index-starts-at-one" modified the scheme as follows: + +register value selected clock parent +1 foo_clock +2 bar_clock +3 baz_clock + +The binding must provide the register to control the mux. Optionally +the number of bits to shift the control field in the register can be +supplied. If the shift value is missing it is the same as supplying +a zero shift. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock". +- #clock-cells : from common clock binding; shall be set to 0. +- clocks : link phandles of parent clocks +- reg : register offset for register controlling adjustable mux + +Optional properties: +- ti,bit-shift : number of bits to shift the bit-mask, defaults to + 0 if not present +- ti,index-starts-at-one : valid input select programming starts at 1, not + zero +- ti,set-rate-parent : clk_set_rate is propagated to parent clock, + not supported by the composite-mux-clock subtype +- ti,latch-bit : latch the mux value to HW, only needed if the register + access requires this. As an example, dra7x DPLL_GMAC H14 muxing + implements such behavior. + +Examples: + +sys_clkin_ck: sys_clkin_ck@4a306110 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>; + reg = <0x0110>; + ti,index-starts-at-one; +}; + +abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 { + #clock-cells = <0>; + compatible = "ti,mux-clock"; + clocks = <&sys_clkin_ck>, <&sys_32k_ck>; + ti,bit-shift = <24>; + reg = <0x0108>; +}; + +mcbsp5_mux_fck: mcbsp5_mux_fck { + #clock-cells = <0>; + compatible = "ti,composite-mux-clock"; + clocks = <&core_96m_fck>, <&mcbsp_clks>; + ti,bit-shift = <4>; + reg = <0x02d8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/uniphier-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/uniphier-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b5f602765fe2fc318fef07c8c4ffc5168ddd5d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/uniphier-clock.txt @@ -0,0 +1,132 @@ +UniPhier clock controller + + +System clock +------------ + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-clock" - for LD4 SoC. + "socionext,uniphier-pro4-clock" - for Pro4 SoC. + "socionext,uniphier-sld8-clock" - for sLD8 SoC. + "socionext,uniphier-pro5-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-clock" - for LD11 SoC. + "socionext,uniphier-ld20-clock" - for LD20 SoC. + "socionext,uniphier-pxs3-clock" - for PXs3 SoC +- #clock-cells: should be 1. + +Example: + + sysctrl@61840000 { + compatible = "socionext,uniphier-sysctrl", + "simple-mfd", "syscon"; + reg = <0x61840000 0x4000>; + + clock { + compatible = "socionext,uniphier-ld11-clock"; + #clock-cells = <1>; + }; + + other nodes ... + }; + +Provided clocks: + + 8: ST DMAC +12: GIO (Giga bit stream I/O) +14: USB3 ch0 host +15: USB3 ch1 host +16: USB3 ch0 PHY0 +17: USB3 ch0 PHY1 +20: USB3 ch1 PHY0 +21: USB3 ch1 PHY1 + + +Media I/O (MIO) clock, SD clock +------------------------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-mio-clock" - for LD4 SoC. + "socionext,uniphier-pro4-mio-clock" - for Pro4 SoC. + "socionext,uniphier-sld8-mio-clock" - for sLD8 SoC. + "socionext,uniphier-pro5-sd-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-sd-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-mio-clock" - for LD11 SoC. + "socionext,uniphier-ld20-sd-clock" - for LD20 SoC. + "socionext,uniphier-pxs3-sd-clock" - for PXs3 SoC +- #clock-cells: should be 1. + +Example: + + mioctrl@59810000 { + compatible = "socionext,uniphier-mioctrl", + "simple-mfd", "syscon"; + reg = <0x59810000 0x800>; + + clock { + compatible = "socionext,uniphier-ld11-mio-clock"; + #clock-cells = <1>; + }; + + other nodes ... + }; + +Provided clocks: + + 0: SD ch0 host + 1: eMMC host + 2: SD ch1 host + 7: MIO DMAC + 8: USB2 ch0 host + 9: USB2 ch1 host +10: USB2 ch2 host +12: USB2 ch0 PHY +13: USB2 ch1 PHY +14: USB2 ch2 PHY + + +Peripheral clock +---------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-peri-clock" - for LD4 SoC. + "socionext,uniphier-pro4-peri-clock" - for Pro4 SoC. + "socionext,uniphier-sld8-peri-clock" - for sLD8 SoC. + "socionext,uniphier-pro5-peri-clock" - for Pro5 SoC. + "socionext,uniphier-pxs2-peri-clock" - for PXs2/LD6b SoC. + "socionext,uniphier-ld11-peri-clock" - for LD11 SoC. + "socionext,uniphier-ld20-peri-clock" - for LD20 SoC. + "socionext,uniphier-pxs3-peri-clock" - for PXs3 SoC +- #clock-cells: should be 1. + +Example: + + perictrl@59820000 { + compatible = "socionext,uniphier-perictrl", + "simple-mfd", "syscon"; + reg = <0x59820000 0x200>; + + clock { + compatible = "socionext,uniphier-ld11-peri-clock"; + #clock-cells = <1>; + }; + + other nodes ... + }; + +Provided clocks: + + 0: UART ch0 + 1: UART ch1 + 2: UART ch2 + 3: UART ch3 + 4: I2C ch0 + 5: I2C ch1 + 6: I2C ch2 + 7: I2C ch3 + 8: I2C ch4 + 9: I2C ch5 +10: I2C ch6 diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/ux500.txt b/arch/arm64/boot/dts/vendor/bindings/clock/ux500.txt new file mode 100644 index 0000000000000000000000000000000000000000..e52bd4b72348e35930aa9483f7c5d251a406e898 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/ux500.txt @@ -0,0 +1,64 @@ +Clock bindings for ST-Ericsson Ux500 clocks + +Required properties : +- compatible : shall contain only one of the following: + "stericsson,u8500-clks" + "stericsson,u8540-clks" + "stericsson,u9540-clks" +- reg : shall contain base register location and length for + CLKRST1, 2, 3, 5, and 6 in an array. Note the absence of + CLKRST4, which does not exist. + +Required subnodes: +- prcmu-clock: a subnode with one clock cell for PRCMU (power, + reset, control unit) clocks. The cell indicates which PRCMU + clock in the prcmu-clock node the consumer wants to use. +- prcc-periph-clock: a subnode with two clock cells for + PRCC (programmable reset- and clock controller) peripheral clocks. + The first cell indicates which PRCC block the consumer + wants to use, possible values are 1, 2, 3, 5, 6. The second + cell indicates which clock inside the PRCC block it wants, + possible values are 0 thru 31. +- prcc-kernel-clock: a subnode with two clock cells for + PRCC (programmable reset- and clock controller) kernel clocks + The first cell indicates which PRCC block the consumer + wants to use, possible values are 1, 2, 3, 5, 6. The second + cell indicates which clock inside the PRCC block it wants, + possible values are 0 thru 31. +- rtc32k-clock: a subnode with zero clock cells for the 32kHz + RTC clock. +- smp-twd-clock: a subnode for the ARM SMP Timer Watchdog cluster + with zero clock cells. + +Example: + +clocks { + compatible = "stericsson,u8500-clks"; + /* + * Registers for the CLKRST block on peripheral + * groups 1, 2, 3, 5, 6, + */ + reg = <0x8012f000 0x1000>, <0x8011f000 0x1000>, + <0x8000f000 0x1000>, <0xa03ff000 0x1000>, + <0xa03cf000 0x1000>; + + prcmu_clk: prcmu-clock { + #clock-cells = <1>; + }; + + prcc_pclk: prcc-periph-clock { + #clock-cells = <2>; + }; + + prcc_kclk: prcc-kernel-clock { + #clock-cells = <2>; + }; + + rtc_clk: rtc32k-clock { + #clock-cells = <0>; + }; + + smp_twd_clk: smp-twd-clock { + #clock-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/vf610-clock.txt b/arch/arm64/boot/dts/vendor/bindings/clock/vf610-clock.txt new file mode 100644 index 0000000000000000000000000000000000000000..63f9f1ac34390762b9950254ef478c9b6b6053a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/vf610-clock.txt @@ -0,0 +1,41 @@ +* Clock bindings for Freescale Vybrid VF610 SOC + +Required properties: +- compatible: Should be "fsl,vf610-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> + +Optional properties: +- clocks: list of clock identifiers which are external input clocks to the + given clock controller. Please refer the next section to find + the input clocks for a given controller. +- clock-names: list of names of clocks which are exteral input clocks to the + given clock controller. + +Input clocks for top clock controller: + - sxosc (external crystal oscillator 32KHz, recommended) + - fxosc (external crystal oscillator 24MHz, recommended) + - audio_ext + - enet_ext + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/vf610-clock.h +for the full list of VF610 clock IDs. + +Examples: + +clks: ccm@4006b000 { + compatible = "fsl,vf610-ccm"; + reg = <0x4006b000 0x1000>; + #clock-cells = <1>; + clocks = <&sxosc>, <&fxosc>; + clock-names = "sxosc", "fxosc"; +}; + +uart1: serial@40028000 { + compatible = "fsl,vf610-uart"; + reg = <0x40028000 0x1000>; + interrupts = <0 62 0x04>; + clocks = <&clks VF610_CLK_UART1>; + clock-names = "ipg"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/vt8500.txt b/arch/arm64/boot/dts/vendor/bindings/clock/vt8500.txt new file mode 100644 index 0000000000000000000000000000000000000000..91d71cc0314ad7b5cfb468c311e38aaab2bd40e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/vt8500.txt @@ -0,0 +1,74 @@ +Device Tree Clock bindings for arch-vt8500 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "via,vt8500-pll-clock" - for a VT8500/WM8505 PLL clock + "wm,wm8650-pll-clock" - for a WM8650 PLL clock + "wm,wm8750-pll-clock" - for a WM8750 PLL clock + "wm,wm8850-pll-clock" - for a WM8850 PLL clock + "via,vt8500-device-clock" - for a VT/WM device clock + +Required properties for PLL clocks: +- reg : shall be the control register offset from PMC base for the pll clock. +- clocks : shall be the input parent clock phandle for the clock. This should + be the reference clock. +- #clock-cells : from common clock binding; shall be set to 0. + +Required properties for device clocks: +- clocks : shall be the input parent clock phandle for the clock. This should + be a pll output. +- #clock-cells : from common clock binding; shall be set to 0. + + +Device Clocks + +Device clocks are required to have one or both of the following sets of +properties: + + +Gated device clocks: + +Required properties: +- enable-reg : shall be the register offset from PMC base for the enable + register. +- enable-bit : shall be the bit within enable-reg to enable/disable the clock. + + +Divisor device clocks: + +Required property: +- divisor-reg : shall be the register offset from PMC base for the divisor + register. +Optional property: +- divisor-mask : shall be the mask for the divisor register. Defaults to 0x1f + if not specified. + + +For example: + +ref25: ref25M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <25000000>; +}; + +plla: plla { + #clock-cells = <0>; + compatible = "wm,wm8650-pll-clock"; + clocks = <&ref25>; + reg = <0x200>; +}; + +sdhc: sdhc { + #clock-cells = <0>; + compatible = "via,vt8500-device-clock"; + clocks = <&pllb>; + divisor-reg = <0x328>; + divisor-mask = <0x3f>; + enable-reg = <0x254>; + enable-bit = <18>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/xgene.txt b/arch/arm64/boot/dts/vendor/bindings/clock/xgene.txt new file mode 100644 index 0000000000000000000000000000000000000000..8233e771711b11c853569209bd4e7c6682c45832 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/xgene.txt @@ -0,0 +1,131 @@ +Device Tree Clock bindings for APM X-Gene + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "apm,xgene-socpll-clock" - for a X-Gene SoC PLL clock + "apm,xgene-pcppll-clock" - for a X-Gene PCP PLL clock + "apm,xgene-pmd-clock" - for a X-Gene PMD clock + "apm,xgene-device-clock" - for a X-Gene device clock + "apm,xgene-socpll-v2-clock" - for a X-Gene SoC PLL v2 clock + "apm,xgene-pcppll-v2-clock" - for a X-Gene PCP PLL v2 clock + +Required properties for SoC or PCP PLL clocks: +- reg : shall be the physical PLL register address for the pll clock. +- clocks : shall be the input parent clock phandle for the clock. This should + be the reference clock. +- #clock-cells : shall be set to 1. +- clock-output-names : shall be the name of the PLL referenced by derive + clock. +Optional properties for PLL clocks: +- clock-names : shall be the name of the PLL. If missing, use the device name. + +Required properties for PMD clocks: +- reg : shall be the physical register address for the pmd clock. +- clocks : shall be the input parent clock phandle for the clock. +- #clock-cells : shall be set to 1. +- clock-output-names : shall be the name of the clock referenced by derive + clock. +Optional properties for PLL clocks: +- clock-names : shall be the name of the clock. If missing, use the device name. + +Required properties for device clocks: +- reg : shall be a list of address and length pairs describing the CSR + reset and/or the divider. Either may be omitted, but at least + one must be present. + - reg-names : shall be a string list describing the reg resource. This + may include "csr-reg" and/or "div-reg". If this property + is not present, the reg property is assumed to describe + only "csr-reg". +- clocks : shall be the input parent clock phandle for the clock. +- #clock-cells : shall be set to 1. +- clock-output-names : shall be the name of the device referenced. +Optional properties for device clocks: +- clock-names : shall be the name of the device clock. If missing, use the + device name. +- csr-offset : Offset to the CSR reset register from the reset address base. + Default is 0. +- csr-mask : CSR reset mask bit. Default is 0xF. +- enable-offset : Offset to the enable register from the reset address base. + Default is 0x8. +- enable-mask : CSR enable mask bit. Default is 0xF. +- divider-offset : Offset to the divider CSR register from the divider base. + Default is 0x0. +- divider-width : Width of the divider register. Default is 0. +- divider-shift : Bit shift of the divider register. Default is 0. + +For example: + + pcppll: pcppll@17000100 { + compatible = "apm,xgene-pcppll-clock"; + #clock-cells = <1>; + clocks = <&refclk 0>; + clock-names = "pcppll"; + reg = <0x0 0x17000100 0x0 0x1000>; + clock-output-names = "pcppll"; + type = <0>; + }; + + pmd0clk: pmd0clk@7e200200 { + compatible = "apm,xgene-pmd-clock"; + #clock-cells = <1>; + clocks = <&pmdpll 0>; + reg = <0x0 0x7e200200 0x0 0x10>; + clock-output-names = "pmd0clk"; + }; + + socpll: socpll@17000120 { + compatible = "apm,xgene-socpll-clock"; + #clock-cells = <1>; + clocks = <&refclk 0>; + clock-names = "socpll"; + reg = <0x0 0x17000120 0x0 0x1000>; + clock-output-names = "socpll"; + type = <1>; + }; + + qmlclk: qmlclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "qmlclk"; + reg = <0x0 0x1703C000 0x0 0x1000>; + reg-name = "csr-reg"; + clock-output-names = "qmlclk"; + }; + + ethclk: ethclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + clock-names = "ethclk"; + reg = <0x0 0x17000000 0x0 0x1000>; + reg-names = "div-reg"; + divider-offset = <0x238>; + divider-width = <0x9>; + divider-shift = <0x0>; + clock-output-names = "ethclk"; + }; + + apbclk: apbclk { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&ahbclk 0>; + clock-names = "apbclk"; + reg = <0x0 0x1F2AC000 0x0 0x1000 + 0x0 0x1F2AC000 0x0 0x1000>; + reg-names = "csr-reg", "div-reg"; + csr-offset = <0x0>; + csr-mask = <0x200>; + enable-offset = <0x8>; + enable-mask = <0x200>; + divider-offset = <0x10>; + divider-width = <0x2>; + divider-shift = <0x0>; + flags = <0x8>; + clock-output-names = "apbclk"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/zx296702-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/zx296702-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c91c9e4f1beb47f35feb64361f3de23bcc35389 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/zx296702-clk.txt @@ -0,0 +1,34 @@ +Device Tree Clock bindings for ZTE zx296702 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "zte,zx296702-topcrm-clk": + zx296702 top clock selection, divider and gating + + "zte,zx296702-lsp0crpm-clk" and + "zte,zx296702-lsp1crpm-clk": + zx296702 device level clock selection and gating + +- reg: Address and length of the register set + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296702-clock.h +for the full list of zx296702 clock IDs. + + +topclk: topcrm@09800000 { + compatible = "zte,zx296702-topcrm-clk"; + reg = <0x09800000 0x1000>; + #clock-cells = <1>; +}; + +uart0: serial@09405000 { + compatible = "zte,zx296702-uart"; + reg = <0x09405000 0x1000>; + interrupts = ; + clocks = <&lsp1clk ZX296702_UART0_PCLK>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/zx296718-clk.txt b/arch/arm64/boot/dts/vendor/bindings/clock/zx296718-clk.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a46bf0b2540cf7a6c6b565cc0cd47f2e9a0bdfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/zx296718-clk.txt @@ -0,0 +1,37 @@ +Device Tree Clock bindings for ZTE zx296718 + +This binding uses the common clock binding[1]. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Required properties: +- compatible : shall be one of the following: + "zte,zx296718-topcrm": + zx296718 top clock selection, divider and gating + + "zte,zx296718-lsp0crm" and + "zte,zx296718-lsp1crm": + zx296718 device level clock selection and gating + + "zte,zx296718-audiocrm": + zx296718 audio clock selection, divider and gating + +- reg: Address and length of the register set + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/zx296718-clock.h +for the full list of zx296718 clock IDs. + + +topclk: topcrm@1461000 { + compatible = "zte,zx296718-topcrm-clk"; + reg = <0x01461000 0x1000>; + #clock-cells = <1>; +}; + +usbphy0:usb-phy0 { + compatible = "zte,zx296718-usb-phy"; + #phy-cells = <0>; + clocks = <&topclk USB20_PHY_CLK>; + clock-names = "phyclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/clock/zynq-7000.txt b/arch/arm64/boot/dts/vendor/bindings/clock/zynq-7000.txt new file mode 100644 index 0000000000000000000000000000000000000000..d93746cf29751e9ada09eb02ff9a5797cd186e9f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/clock/zynq-7000.txt @@ -0,0 +1,110 @@ +Device Tree Clock bindings for the Zynq 7000 EPP + +The Zynq EPP has several different clk providers, each with there own bindings. +The purpose of this document is to document their usage. + +See clock_bindings.txt for more information on the generic clock bindings. +See Chapter 25 of Zynq TRM for more information about Zynq clocks. + +== Clock Controller == +The clock controller is a logical abstraction of Zynq's clock tree. It reads +required input clock frequencies from the devicetree and acts as clock provider +for all clock consumers of PS clocks. + +Required properties: + - #clock-cells : Must be 1 + - compatible : "xlnx,ps7-clkc" + - reg : SLCR offset and size taken via syscon < 0x100 0x100 > + - ps-clk-frequency : Frequency of the oscillator providing ps_clk in HZ + (usually 33 MHz oscillators are used for Zynq platforms) + - clock-output-names : List of strings used to name the clock outputs. Shall be + a list of the outputs given below. + +Optional properties: + - clocks : as described in the clock bindings + - clock-names : as described in the clock bindings + - fclk-enable : Bit mask to enable FCLKs statically at boot time. + Bit [0..3] correspond to FCLK0..FCLK3. The corresponding + FCLK will only be enabled if it is actually running at + boot time. + +Clock inputs: +The following strings are optional parameters to the 'clock-names' property in +order to provide an optional (E)MIO clock source. + - swdt_ext_clk + - gem0_emio_clk + - gem1_emio_clk + - mio_clk_XX # with XX = 00..53 +... + +Clock outputs: + 0: armpll + 1: ddrpll + 2: iopll + 3: cpu_6or4x + 4: cpu_3or2x + 5: cpu_2x + 6: cpu_1x + 7: ddr2x + 8: ddr3x + 9: dci + 10: lqspi + 11: smc + 12: pcap + 13: gem0 + 14: gem1 + 15: fclk0 + 16: fclk1 + 17: fclk2 + 18: fclk3 + 19: can0 + 20: can1 + 21: sdio0 + 22: sdio1 + 23: uart0 + 24: uart1 + 25: spi0 + 26: spi1 + 27: dma + 28: usb0_aper + 29: usb1_aper + 30: gem0_aper + 31: gem1_aper + 32: sdio0_aper + 33: sdio1_aper + 34: spi0_aper + 35: spi1_aper + 36: can0_aper + 37: can1_aper + 38: i2c0_aper + 39: i2c1_aper + 40: uart0_aper + 41: uart1_aper + 42: gpio_aper + 43: lqspi_aper + 44: smc_aper + 45: swdt + 46: dbg_trc + 47: dbg_apb + +Example: + clkc: clkc@100 { + #clock-cells = <1>; + compatible = "xlnx,ps7-clkc"; + ps-clk-frequency = <33333333>; + reg = <0x100 0x100>; + clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x", + "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x", + "dci", "lqspi", "smc", "pcap", "gem0", "gem1", + "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1", + "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1", + "dma", "usb0_aper", "usb1_aper", "gem0_aper", + "gem1_aper", "sdio0_aper", "sdio1_aper", + "spi0_aper", "spi1_aper", "can0_aper", "can1_aper", + "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper", + "gpio_aper", "lqspi_aper", "smc_aper", "swdt", + "dbg_trc", "dbg_apb"; + # optional props + clocks = <&clkc 16>, <&clk_foo>; + clock-names = "gem1_emio_clk", "can_mio_clk_23"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cnss/cnss-wlan.txt b/arch/arm64/boot/dts/vendor/bindings/cnss/cnss-wlan.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8526d3cd24b7a9ace0710be93e044702d87c25d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cnss/cnss-wlan.txt @@ -0,0 +1,98 @@ +* Qualcomm Technologies, Inc. ConNectivity SubSystem Platform Driver + +This platform driver adds support for the CNSS subsystem used for PCIe +based Wi-Fi devices. It also adds support to integrate PCIe WLAN module +to subsystem restart framework. Apart from that, it also manages the +3.3V voltage regulator, WLAN Enable GPIO signal and PCIe link dynamically +with support for suspend and resume by retaining the PCI config space +states when PCIe link is shutdown. The main purpose of this device tree +entry below is to invoke the CNSS platform driver and provide handle to +the WLAN enable GPIO, 3.3V fixed voltage regulator resources. It also +provides the reserved RAM dump memory location and size. + +Required properties: + - compatible: "qcom,cnss" for QCA6174 device + "qcom,cnss-qca6290" for QCA6290 device + "qcom,cnss-qca6390" for QCA6390 device + "qcom,cnss-qca6490" for QCA6490 device + - wlan-en-gpio: WLAN_EN GPIO signal specified by the chip specifications + - vdd-wlan-supply: phandle to the regulator device tree node + - pinctrl-names: Names corresponding to the numbered pinctrl states + - pinctrl-: Pinctrl states as described in + bindings/pinctrl/pinctrl-bindings.txt + - qcom,wlan-rc-num: PCIe root complex number which WLAN chip is attached to + +Optional properties: + - qcom,notify-modem-status: Boolean property to decide whether modem + notification should be enabled or not in this + platform + - wlan-soc-swreg-supply: phandle to the external 1.15V regulator for QCA6174 + - wlan-ant-switch-supply: phandle to the 2.7V regulator for the antenna + switch of QCA6174 + - qcom,wlan-uart-access: Boolean property to decide whether QCA6174 + has exclusive access to UART. + - vdd-wlan-io-supply: phandle to the 1.8V IO regulator for QCA6174 + - vdd-wlan-xtal-supply: phandle to the 1.8V XTAL regulator for QCA6174 + - vdd-wlan-xtal-aon-supply: phandle to the LDO-4 regulator. This is needed + on platforms where XTAL regulator depends on + always on regulator in VDDmin. + - vdd-wlan-ctrl1-supply: phandle to the DBU1 - 1.8V for QCA6595 or 3.3V for + QCA6174 on auto platform. + - vdd-wlan-ctrl2-supply: phandle to the DBU4 - 2.2V for QCA6595 or 3.85V for + QCA6696 on auto platform. + - vdd-wlan-core-supply: phandle to the 1.3V CORE regulator for QCA6174 + - vdd-wlan-sp2t-supply: phandle to the 2.7V SP2T regulator for QCA6174 + - -supply: phandle to the regulator device tree node. + optional "supply-name" is "vdd-wlan-rfa" + - qcom,-config: Specifies voltage levels for supply. Should specified + in pairs (min, max), units uV. There can be optional + load in uA and Regulator settle delay in us + - qcom,smmu-s1-enable: Boolean property to decide whether to enable SMMU + S1 stage or not + - qcom,wlan-smmu-iova-address: I/O virtual address range as + format to be used for allocations associated + between WLAN/PCIe and SMMU + - qcom,wlan-ramdump-dynamic: To enable CNSS RAMDUMP collection + by providing the size of CNSS DUMP + - qcom,cmd_db_name: CommandDB name indicating the PMIC rail used for open + loop CPR + - reg: Memory regions defined as starting address and size + - reg-names: Names of the memory regions defined in reg entry + - wlan-bootstrap-gpio: WLAN_BOOTSTRAP GPIO signal specified by QCA6174 + which should be drived depending on platforms + - qcom,is-dual-wifi-enabled: Boolean property to control wlan enable(wlan-en) + gpio on dual-wifi platforms. + - vdd-wlan-en-supply: WLAN_EN fixed regulator specified by QCA6174 + specifications. + - qcom,wlan-en-vreg-support: Boolean property to decide the whether the + WLAN_EN pin is a gpio or fixed regulator. + - qcom,mhi: phandle to indicate the device which needs MHI support. + - qcom,cap-tsf-gpio: WLAN_TSF_CAPTURED GPIO signal specified by the chip + specifications, should be drived depending on products + - cnss-daemon-support: Boolean property to decide whether cnss_daemon + userspace QMI client is supported. + - use-nv-mac: Boolean property to indicate whether NV MAC is used or not. + - qcom,set-wlaon-pwr-ctrl: Boolean property to indicate if set + WLAON_QFPROM_PWR_CTRL_REG register during power on + and off sequences. + - qcom,converged-dt: Boolean property to decide whether it supports multiple + WLAN devices. + +Example: + + qcom,cnss@0d400000 { + compatible = "qcom,cnss"; + reg = <0x0d400000 0x200000>; + reg-names = "ramdump"; + qcom,wlan-ramdump-dynamic = <0x200000>; + wlan-en-gpio = <&msmgpio 82 0>; + vdd-wlan-supply = <&wlan_vreg>; + qcom,notify-modem-status; + wlan-soc-swreg-supply = <&pma8084_l27>; + pinctrl-names = "default"; + pinctrl-0 = <&cnss_default>; + qcom,wlan-rc-num = <0>; + qcom,wlan-smmu-iova-address = <0 0x10000000>; + qcom,mhi = <&mhi_wlan>; + qcom,cap-tsf-gpio = <&tlmm 126 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cnss/icnss.txt b/arch/arm64/boot/dts/vendor/bindings/cnss/icnss.txt new file mode 100644 index 0000000000000000000000000000000000000000..982505db6003a873619541087f56454ef5355138 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cnss/icnss.txt @@ -0,0 +1,78 @@ +* Qualcomm Technologies Inc Q6 Integrated connectivity Platform Driver + +This platform driver adds support for the Integrated WLAN that runs +on Q6 based platforms. WLAN FW on these architecture runs on Q6. This +platform driver communicates with WLAN FW over QMI, WLAN on/off messages +to FW are communicated thru this interface. This driver also listens to +WLAN PD restart notifications. + +Required properties: + - compatible: "qcom,icnss" for ADRASTEA architecture + "qcom,wcn6750" for iWCN architecture + - reg: Memory regions defined as starting address and size + - reg-names: Names of the memory regions defined in reg entry + - interrupts: Copy engine interrupt table + - qcom,wlan-msa-memory: MSA memory size + - clocks: List of clock phandles + - clock-names: List of clock names corresponding to the "clocks" property + - iommus: SMMUs and corresponding Stream IDs needed by WLAN + - qcom,wlan-smmu-iova-address: I/O virtual address range as + format to be used for allocations associated between WLAN and SMMU + +Optional properties: + - -supply: phandle to the regulator device tree node + optional "supply-name" is "vdd-0.8-cx-mx". + - qcom,-config: Specifies voltage levels for supply. Should be + specified in pairs (min, max), units uV. There can + be optional load in uA and Regulator settle delay in + uS. + - qcom,icnss-vadc: VADC handle for vph_pwr read APIs. + - qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs. + - io-channels: IIO channel to monitor for vph_pwr power. + - io-channel-names: IIO channel name as per the client name. + - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass + - qcom,wlan-msa-fixed-region: phandle, specifier pairs to children of /reserved-memory + - qcom,hyp_disabled: Boolean context flag to disable hyperviser + +WLAN SMP2P sub nodes + + - qcom,smp2p_map_wlan_1_in - represents the in smp2p to + wlan driver from modem. + +Example: + + qcom,icnss@0a000000 { + compatible = "qcom,icnss"; + reg = <0x0a000000 0x1000000>; + reg-names = "membase"; + clocks = <&clock_gcc clk_aggre2_noc_clk>; + clock-names = "smmu_aggre2_noc_clk"; + iommus = <&anoc2_smmu 0x1900>, + <&anoc2_smmu 0x1901>; + qcom,wlan-smmu-iova-address = <0 0x10000000>; + interrupts = + <0 130 0 /* CE0 */ >, + <0 131 0 /* CE1 */ >, + <0 132 0 /* CE2 */ >, + <0 133 0 /* CE3 */ >, + <0 134 0 /* CE4 */ >, + <0 135 0 /* CE5 */ >, + <0 136 0 /* CE6 */ >, + <0 137 0 /* CE7 */ >, + <0 138 0 /* CE8 */ >, + <0 139 0 /* CE9 */ >, + <0 140 0 /* CE10 */ >, + <0 141 0 /* CE11 */ >; + qcom,wlan-msa-memory = <0x200000>; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; + qcom,smmu-s1-bypass; + vdd-0.8-cx-mx-supply = <&pm8998_l5>; + qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>; + qcom,hyp_disabled; + qcom,smp2p_map_wlan_1_in { + interrupts-extended = <&smp2p_wlan_1_in 0 0>, + <&smp2p_wlan_1_in 1 0>; + interrupt-names = "qcom,smp2p-force-fatal-error", + "qcom,smp2p-early-crash-ind"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/common-properties.txt b/arch/arm64/boot/dts/vendor/bindings/common-properties.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3448bfa1c827971f6d0e9c33e31c7636a0ce1b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/common-properties.txt @@ -0,0 +1,86 @@ +Common properties +================= + +Endianness +---------- + +The Devicetree Specification does not define any properties related to hardware +byteswapping, but endianness issues show up frequently in porting Linux to +different machine types. This document attempts to provide a consistent +way of handling byteswapping across drivers. + +Optional properties: + - big-endian: Boolean; force big endian register accesses + unconditionally (e.g. ioread32be/iowrite32be). Use this if you + know the peripheral always needs to be accessed in BE mode. + - little-endian: Boolean; force little endian register accesses + unconditionally (e.g. readl/writel). Use this if you know the + peripheral always needs to be accessed in LE mode. + - native-endian: Boolean; always use register accesses matched to the + endianness of the kernel binary (e.g. LE vmlinux -> readl/writel, + BE vmlinux -> ioread32be/iowrite32be). In this case no byteswaps + will ever be performed. Use this if the hardware "self-adjusts" + register endianness based on the CPU's configured endianness. + +If a binding supports these properties, then the binding should also +specify the default behavior if none of these properties are present. +In such cases, little-endian is the preferred default, but it is not +a requirement. The of_device_is_big_endian() and of_fdt_is_big_endian() +helper functions do assume that little-endian is the default, because +most existing (PCI-based) drivers implicitly default to LE by using +readl/writel for MMIO accesses. + +Examples: +Scenario 1 : CPU in LE mode & device in LE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... + native-endian; +}; + +Scenario 2 : CPU in LE mode & device in BE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... + big-endian; +}; + +Scenario 3 : CPU in BE mode & device in BE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... + native-endian; +}; + +Scenario 4 : CPU in BE mode & device in LE mode. +dev: dev@40031000 { + compatible = "name"; + reg = <0x40031000 0x1000>; + ... + little-endian; +}; + +Daisy-chained devices +--------------------- + +Many serially-attached GPIO and IIO devices are daisy-chainable. To the +host controller, a daisy-chain appears as a single device, but the number +of inputs and outputs it provides is the sum of inputs and outputs provided +by all of its devices. The driver needs to know how many devices the +daisy-chain comprises to determine the amount of data exchanged, how many +inputs and outputs to register and so on. + +Optional properties: + - #daisy-chained-devices: Number of devices in the daisy-chain (default is 1). + +Example: +gpio@0 { + compatible = "name"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + #daisy-chained-devices = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/connector/samsung,usb-connector-11pin.txt b/arch/arm64/boot/dts/vendor/bindings/connector/samsung,usb-connector-11pin.txt new file mode 100644 index 0000000000000000000000000000000000000000..22256e295a7a1f36ff4c2d348f52fb24b57864f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/connector/samsung,usb-connector-11pin.txt @@ -0,0 +1,49 @@ +Samsung micro-USB 11-pin connector +================================== + +Samsung micro-USB 11-pin connector is an extension of micro-USB connector. +It is present in multiple Samsung mobile devices. +It has additional pins to route MHL traffic simultanously with USB. + +The bindings are superset of usb-connector bindings for micro-USB connector[1]. + +Required properties: +- compatible: must be: "samsung,usb-connector-11pin", "usb-b-connector", +- type: must be "micro". + +Required nodes: +- any data bus to the connector should be modeled using the OF graph bindings + specified in bindings/graph.txt, unless the bus is between parent node and + the connector. Since single connector can have multpile data buses every bus + has assigned OF graph port number as follows: + 0: High Speed (HS), + 3: Mobile High-Definition Link (MHL), specific to 11-pin Samsung micro-USB. + +[1]: bindings/connector/usb-connector.txt + +Example +------- + +Micro-USB connector with HS lines routed via controller (MUIC) and MHL lines +connected to HDMI-MHL bridge (sii8620): + +muic-max77843@66 { + ... + usb_con: connector { + compatible = "samsung,usb-connector-11pin", "usb-b-connector"; + label = "micro-USB"; + type = "micro"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@3 { + reg = <3>; + usb_con_mhl: endpoint { + remote-endpoint = <&sii8620_mhl>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/connector/usb-connector.txt b/arch/arm64/boot/dts/vendor/bindings/connector/usb-connector.txt new file mode 100644 index 0000000000000000000000000000000000000000..8855bfcfd778564b0666a92cc1cb51fe8900322f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/connector/usb-connector.txt @@ -0,0 +1,119 @@ +USB Connector +============= + +USB connector node represents physical USB connector. It should be +a child of USB interface controller. + +Required properties: +- compatible: describes type of the connector, must be one of: + "usb-a-connector", + "usb-b-connector", + "usb-c-connector". + +Optional properties: +- label: symbolic name for the connector, +- type: size of the connector, should be specified in case of USB-A, USB-B + non-fullsize connectors: "mini", "micro". + +Optional properties for usb-c-connector: +- power-role: should be one of "source", "sink" or "dual"(DRP) if typec + connector has power support. +- try-power-role: preferred power role if "dual"(DRP) can support Try.SNK + or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC. +- data-role: should be one of "host", "device", "dual"(DRD) if typec + connector supports USB data. + +Required properties for usb-c-connector with power delivery support: +- source-pdos: An array of u32 with each entry providing supported power + source data object(PDO), the detailed bit definitions of PDO can be found + in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 + Source_Capabilities Message, the order of each entry(PDO) should follow + the PD spec chapter 6.4.1. Required for power source and power dual role. + User can specify the source PDO array via PDO_FIXED/BATT/VAR() defined in + dt-bindings/usb/pd.h. +- sink-pdos: An array of u32 with each entry providing supported power + sink data object(PDO), the detailed bit definitions of PDO can be found + in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 + Sink Capabilities Message, the order of each entry(PDO) should follow + the PD spec chapter 6.4.1. Required for power sink and power dual role. + User can specify the sink PDO array via PDO_FIXED/BATT/VAR() defined in + dt-bindings/usb/pd.h. +- op-sink-microwatt: Sink required operating power in microwatt, if source + can't offer the power, Capability Mismatch is set. Required for power + sink and power dual role. + +Required nodes: +- any data bus to the connector should be modeled using the OF graph bindings + specified in bindings/graph.txt, unless the bus is between parent node and + the connector. Since single connector can have multpile data buses every bus + has assigned OF graph port number as follows: + 0: High Speed (HS), present in all connectors, + 1: Super Speed (SS), present in SS capable connectors, + 2: Sideband use (SBU), present in USB-C. + +Examples +-------- + +1. Micro-USB connector with HS lines routed via controller (MUIC): + +muic-max77843@66 { + ... + usb_con: connector { + compatible = "usb-b-connector"; + label = "micro-USB"; + type = "micro"; + }; +}; + +2. USB-C connector attached to CC controller (s2mm005), HS lines routed +to companion PMIC (max77865), SS lines to USB3 PHY and SBU to DisplayPort. +DisplayPort video lines are routed to the connector via SS mux in USB3 PHY. + +ccic: s2mm005@33 { + ... + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + usb_con_hs: endpoint { + remote-endpoint = <&max77865_usbc_hs>; + }; + }; + port@1 { + reg = <1>; + usb_con_ss: endpoint { + remote-endpoint = <&usbdrd_phy_ss>; + }; + }; + port@2 { + reg = <2>; + usb_con_sbu: endpoint { + remote-endpoint = <&dp_aux>; + }; + }; + }; + }; +}; + +3. USB-C connector attached to a typec port controller(ptn5110), which has +power delivery support and enables drp. + +typec: ptn5110@50 { + ... + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/coresight/coresight.txt b/arch/arm64/boot/dts/vendor/bindings/coresight/coresight.txt new file mode 100644 index 0000000000000000000000000000000000000000..242560041a2618fca6de4d6a3b2919a2358f3610 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/coresight/coresight.txt @@ -0,0 +1,435 @@ +* CoreSight Components + +CoreSight components are compliant with the ARM CoreSight architecture +specification and can be connected in various topologies to suite a particular +SoCs tracing needs. These trace components can generally be classified as sinks, +links and sources. Trace data produced by one or more sources flows through the +intermediate links connecting the source to the currently selected sink. Each +CoreSight component device should use these properties to describe its hardware +characteristcs. + +Required properties: + +- compatible : name of the component used for driver matching, should be one of + the following: + "arm,coresight-tmc" for coresight tmc-etr or tmc-etf device, + "arm,coresight-tpiu" for coresight tpiu device, + "qcom,coresight-replicator" for coresight replicator device, + "arm,coresight-funnel" for coresight funnel devices, + "qcom,coresight-tpda" for coresight tpda device, + "qcom,coresight-tpdm" for coresight tpdm device, + "qcom,coresight-dbgui" for coresight dbgui device + "arm,coresight-stm" for coresight stm trace device, + "arm,coresight-etm" for coresight etm trace devices, + "arm,coresight-etmv4" for coresight etmv4 trace devices, + "qcom,coresight-csr" for coresight csr device, + "arm,coresight-cti" for coresight cti devices, + "qcom,coresight-hwevent" for coresight hardware event devices + "arm,coresight-fuse" for coresight fuse v1 device, + "arm,coresight-fuse-v2" for coresight fuse v2 device, + "arm,coresight-fuse-v3" for coresight fuse v3 device, + "qcom,coresight-remote-etm" for coresight remote processor etm trace device, + "qcom,coresight-qpdi" for coresight qpdi device +- reg : physical base address and length of the register set(s) of the component. + Not required for the following compatible string: + - "qcom,coresight-remote-etm" +- reg-names : names corresponding to each reg property value. + Not required for the following compatible string: + - "qcom,coresight-remote-etm" + The reg-names that need to be used with corresponding compatible string + for a coresight device are: + - for coresight tmc-etr or tmc-etf device: + compatible : should be "arm,coresight-tmc" + reg-names : should be: + "tmc-base" - physical base address of tmc configuration + registers + "bam-base" - physical base address of tmc-etr bam registers + - for coresight tpiu device: + compatible : should be "arm,coresight-tpiu" + reg-names : should be: + "tpiu-base" - physical base address of tpiu registers + - for coresight replicator device + compatible : should be "qcom,coresight-replicator" + reg-names : should be: + "replicator-base" - physical base address of replicator + registers + - for coresight funnel devices + compatible : should be "arm,coresight-funnel" + reg-names : should be: + "funnel-base" - physical base address of funnel registers + - for coresight tpda trace device + compatible : should be "qcom,coresight-tpda" + reg-names : should be: + "tpda-base" - physical base address of tpda registers + - for coresight tpdm trace device + compatible : should be "qcom,coresight-tpdm" + reg-names : should be: + "tpdm-base" - physical base address of tpdm registers + - for coresight dbgui device: + compatible : should be "qcom,coresight-dbgui" + reg-names : should be: + "dbgui-base" - physical base address of dbgui registers + - for coresight stm trace device + compatible : should be "arm,coresight-stm" + reg-names : should be: + "stm-base" - physical base address of stm configuration + registers + "stm-data-base" - physical base address of stm data registers + - for coresight etm trace devices + compatible : should be "arm,coresight-etm" + reg-names : should be: + "etm-base" - physical base address of etm registers + - for coresight etmv4 trace devices + compatible : should be "arm,coresight-etmv4" + reg-names : should be: + "etm-base" - physical base address of etmv4 registers + - for coresight csr device: + compatible : should be "qcom,coresight-csr" + reg-names : should be: + "csr-base" - physical base address of csr registers + - for coresight cti devices: + compatible : should be "arm,coresight-cti" + reg-names : should be: + "cti-base" - physical base address of cti registers + - for coresight hardware event devices: + compatible : should be "qcom,coresight-hwevent" + reg-names : should be: + "" - physical base address of hardware event mux + control registers where is subsystem mux it + represents + - for coresight fuse device: + compatible : should be "arm,coresight-fuse" + reg-names : should be: + "fuse-base" - physical base address of fuse registers + "nidnt-fuse-base" - physical base address of nidnt fuse registers + "qpdi-fuse-base" - physical base address of qpdi fuse registers + - for coresight qpdi device: + compatible : should be "qcom,coresight-qpdi" + reg-names : should be: + "qpdi-base" - physical base address of qpdi registers +- coresight-id : unique integer identifier for the component +- coresight-name : unique descriptive name of the component +- coresight-nr-inports : number of input ports on the component + +Optional properties: + +- coresight-outports : list of output port numbers of this component +- coresight-child-list : list of phandles pointing to the children of this + component +- coresight-child-ports : list of input port numbers of the children +- coresight-default-sink : represents the default compile time CoreSight sink +- coresight-ctis : list of ctis that this component interacts with +- qcom,cti-save : boolean, indicating cti context needs to be saved and restored +- qcom,cti-hwclk : boolean, indicating support of hardware clock to access cti + registers to be saved and restored +- qcom,cti-gpio-trigin : cti trigger input driven by gpio +- qcom,cti-gpio-trigout : cti trigger output sent to gpio +- qcom,pc-save : program counter save implemented +- qcom,blk-size : block size for tmc-etr to usb transfers +- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer +- qcom,round-robin : indicates if per core etms are allowed round-robin access + by the funnel +- qcom,write-64bit : only 64bit data writes supported by stm +- qcom,data-barrier : barrier required for every stm data write to channel space +- -supply: phandle to the regulator device tree node. The required + is "vdd" for SD card and "vdd-io" for SD + I/O supply. Used for tpiu component +- qcom,-voltage-level : specifies voltage level for vdd supply. Should + be specified in pairs (min, max) with units + being uV. Here can be "vdd" for SD card + vdd supply or "vdd-io" for SD I/O vdd supply. +- qcom,-current-level : specifies current load levels for vdd supply. + Should be specified in pairs (lpm, hpm) with + units being uA. Here can be "vdd" for + SD card vdd supply or "vdd-io" for SD I/O vdd + supply. +- qcom,hwevent-clks : list of clocks required by hardware event driver +- qcom,hwevent-regs : list of regulators required by hardware event driver +- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on + the device. Only relevant in case of tmc-etr device. +- interrupts : where a is 0 or 1 depending on if the interrupt is + spi/ppi, b is the interrupt number and c is the mask, +- interrupt-names : a list of strings that map in order to the list of + interrupts specified in the 'interrupts' property. +- qcom,sg-enable : indicates whether scatter gather feature is supported for TMC + ETR configuration. +- qcom,force-reg-dump : boolean, indicate whether TMC register need to be dumped. + Used for TMC component +- qcom,nidntsw : boolean, indicating NIDnT software debug or trace support + present. Used for tpiu component +- qcom,nidnthw : boolean, indicating NIDnT hardware sensing support present. + Used for tpiu component + qcom,nidntsw and qcom,nidnthw are mutually exclusive properties, either of + these may specified for tpiu component +- qcom,nidnt-swduart : boolean, indicating NIDnT swd uart support present. Used + for tpiu component +- qcom,nidnt-swdtrc : boolean, indicating NIDnT swd trace support present. Used + for tpiu component +- qcom,nidnt-jtag : boolean, indicating NIDnT jtag debug support present. Used + for tpiu component +- qcom,nidnt-spmi : boolean, indicating NIDnT spmi debug support present. Used + for tpiu component +- nidnt-gpio : specifies gpio for NIDnT hardware detection +- nidnt-gpio-polarity : specifies gpio polarity for NIDnT hardware detection +- pinctrl-names : names corresponding to the numbered pinctrl. The allowed + names are subset of the following: cti-trigin-pctrl, + cti-trigout-pctrl. Used for cti component +- pinctrl-: list of pinctrl phandles for the different pinctrl states. Refer + to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt". +- qcom,funnel-save-restore : boolean, indicating funnel port needs to be disabled + for the ETM whose CPU is being powered down. The port + state is restored when CPU is powered up. Used for + funnel component. +- qcom,tmc-flush-powerdown : boolean, indicating trace data needs to be flushed before + powering down CPU. Used for TMC component. +- qcom,bc-elem-size : specifies the BC element size supported by each monitor + connected to the aggregator on each port. Should be specified + in pairs (port, bc element size). +- qcom,tc-elem-size : specifies the TC element size supported by each monitor + connected to the aggregator on each port. Should be specified + in pairs (port, tc element size). +- qcom,dsb-elem-size : specifies the DSB element size supported by each monitor + connected to the aggregator on each port. Should be specified + in pairs (port, dsb element size). +- qcom,cmb-elem-size : specifies the CMB element size supported by each monitor + connected to the aggregator on each port. Should be specified + in pairs (port, cmb element size). +- qcom,clk-enable: specifies whether additional clock bit needs to be set for + M4M TPDM. +- qcom,tpda-atid : specifies the ATID for TPDA. +- qcom,inst-id : QMI instance id for remote ETMs. +- qcom,noovrflw-enable : boolean, indicating whether no overflow bit needs to be + set in ETM stall control register. +- coresight-cti-cpu : cpu phandle for cpu cti, required when qcom,cti-save is true +- coresight-etm-cpu : specifies phandle for the cpu associated with the ETM device +- qcom,dbgui-addr-offset : indicates the offset of dbgui address registers +- qcom,dbgui-data-offset : indicates the offset of dbgui data registers +- qcom,dbgui-size : indicates the size of dbgui address and data registers +- qcom,pmic-carddetect-gpio : indicates the hotplug capabilities of the qpdi driver +- qcom,cpuss-debug-cgc: debug clock gating phandle for etm + reg : the clock gating register for each cluster + cluster : indicate the cluster number + +coresight-outports, coresight-child-list and coresight-child-ports lists will +be of the same length and will have a one to one correspondence among the +elements at the same list index. + +coresight-default-sink must be specified for one of the sink devices that is +intended to be made the default sink. Other sink devices must not have this +specified. Not specifying this property on any of the sinks is invalid. + +Examples: + +1. Sinks + tmc_etr: tmc@fc322000 { + compatible = "arm,coresight-tmc"; + reg = <0xfc322000 0x1000>, + <0xfc37c000 0x3000>; + reg-names = "tmc-base", "bam-base"; + + interrupts = <0 166 0>; + interrupt-names = "byte-cntr-irq"; + + qcom,byte-cntr-absent; + qcom,memory-size = <0x100000>; + + coresight-id = <0>; + coresight-name = "coresight-tmc-etr"; + coresight-nr-inports = <1>; + coresight-default-sink; + }; + + tpiu: tpiu@fc318000 { + compatible = "arm,coresight-tpiu"; + reg = <0xfc318000 0x1000>; + reg-names = "tpiu-base"; + + coresight-id = <1>; + coresight-name = "coresight-tpiu"; + coresight-nr-inports = <1>; + + qcom,nidnt; + qcom,nidnthw; + nidnt-gpio = <38>; + nidnt-gpio-polarity = <1>; + + vdd-supply = <&pm8941_l21>; + + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <9000 800000>; + }; + +2. Links + funnel_merg: funnel@fc31b000 { + compatible = "arm,coresight-funnel"; + reg = <0xfc31b000 0x1000>; + reg-names = "funnel-base"; + + coresight-id = <4>; + coresight-name = "coresight-funnel-merg"; + coresight-nr-inports = <2>; + coresight-outports = <0>; + coresight-child-list = <&tmc_etf>; + coresight-child-ports = <0>; + }; + + funnel_in0: funnel@fc319000 { + compatible = "arm,coresight-funnel"; + reg = <0xfc319000 0x1000>; + reg-names = "funnel-base"; + + coresight-id = <5>; + coresight-name = "coresight-funnel-in0"; + coresight-nr-inports = <8>; + coresight-outports = <0>; + coresight-child-list = <&funnel_merg>; + coresight-child-ports = <0>; + }; + + tpda_lmh: tpda@fbb91000 { + compatible = "qcom,coresight-tpda"; + reg = <0xfbb91000x1000>; + reg-names = "tpda-base"; + + coresight-id = <7>; + coresight-name = "coresight-tpda-lmh"; + coresight-nr-inports = <32>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in0>; + coresight-child-ports = <4>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_rpm clk_qdss_clk>, + <&clock_rpm clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + +3. Sources + tpdm_lmh: tpdm@fbb90000 { + compatible = "qcom,coresight-tpdm"; + reg = <0xfbb90000x1000>; + reg-names = "tpdm-base"; + + coresight-id = <8>; + coresight-name = "coresight-tpdm-lmh"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&tpda_lmh>; + coresight-child-ports = <0>; + + clocks = <&clock_rpm clk_qdss_clk>, + <&clock_rpm clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + + dbgui: dbgui@86d000 { + compatible = "qcom,coresight-dbgui"; + reg = <0x86d000 0x1000>; + reg-names = "dbgui-base"; + + coresight-id = <11>; + coresight-name = "coresight-dbgui"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in3>; + coresight-child-ports = <2>; + + qcom,dbgui-addr-offset = <0x30>; + qcom,dbgui-data-offset = <0xB0>; + qcom,dbgui-size = <32>; + + clocks = <&clock_rpm clk_qdss_clk>, + <&clock_rpm clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + + stm: stm@fc321000 { + compatible = "arm,coresight-stm"; + reg = <0xfc321000 0x1000>, + <0xfa280000 0x180000>; + reg-names = "stm-base", "stm-data-base"; + + coresight-id = <9>; + coresight-name = "coresight-stm"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in1>; + coresight-child-ports = <7>; + }; + + etm0: etm@fc33c000 { + compatible = "arm,coresight-etm"; + reg = <0xfc33c000 0x1000>; + reg-names = "etm-base"; + + coresight-id = <10>; + coresight-name = "coresight-etm0"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_kpss>; + coresight-child-ports = <0>; + coresight-etm-cpu = <&CPU0>; + qcom,cpuss-debug-cgc = <&CGC_0>; + + qcom,pc-save; + qcom,round-robin; + + #address-cells = <1>; + #size-cells = <1>; + CGC_0: cluster-cgc { + reg = <0xb011088 0x4>; + cluster = <1>; + }; + }; + +4. Miscellaneous + cti0: cti@fc308000 { + compatible = "arm,coresight-cti"; + reg = <0xfc308000 0x1000>; + reg-names = "cti-base"; + + coresight-id = <15>; + coresight-name = "coresight-cti0"; + coresight-nr-inports = <0>; + + qcom,cti-gpio-trigout = <1>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; + }; + + cti1: cti@fc309000 { + compatible = "arm,coresight-cti"; + reg = <0xfc309000 0x1000>; + reg-names = "cti-base"; + + coresight-id = <16>; + coresight-name = "coresight-cti1"; + coresight-nr-inports = <0>; + }; + + hwevent: hwevent@fdf30018 { + compatible = "qcom,coresight-hwevent"; + reg = <0xfdf30018 0x80>, + <0xf9011080 0x80>, + <0xfd4ab160 0x80>, + <0xfc401600 0x80>; + reg-names = "mmss-mux", "apcs-mux", "ppss-mux", "gcc-mux"; + + coresight-id = <29>; + coresight-name = "coresight-hwevent"; + coresight-nr-inports = <0>; + + qcom,hwevent-clks = "core_mmss_clk"; + qcom,hwevent-regs = "gdsc_ufs"; + }; + + fuse: fuse@fc4be024 { + compatible = "arm,coresight-fuse"; + reg = <0xfc4be024 0x8> + <0x58040 0x4>; + reg-names = "fuse-base", "nidnt-fuse-base"; + + coresight-id = <30>; + coresight-name = "coresight-fuse"; + coresight-nr-inports = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/arm_big_little_dt.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/arm_big_little_dt.txt new file mode 100644 index 0000000000000000000000000000000000000000..2aa06ac0fac594ae48b85041fd1c3aed21f674ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/arm_big_little_dt.txt @@ -0,0 +1,65 @@ +Generic ARM big LITTLE cpufreq driver's DT glue +----------------------------------------------- + +This is DT specific glue layer for generic cpufreq driver for big LITTLE +systems. + +Both required and optional properties listed below must be defined +under node /cpus/cpu@x. Where x is the first cpu inside a cluster. + +FIXME: Cpus should boot in the order specified in DT and all cpus for a cluster +must be present contiguously. Generic DT driver will check only node 'x' for +cpu:x. + +Required properties: +- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt + for details + +Optional properties: +- clock-latency: Specify the possible maximum transition latency for clock, + in unit of nanoseconds. + +Examples: + +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a15"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 1100000 + 396000 950000 + 198000 850000 + >; + clock-latency = <61036>; /* two CLK32 periods */ + }; + + cpu@1 { + compatible = "arm,cortex-a15"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@100 { + compatible = "arm,cortex-a7"; + reg = <100>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 950000 + 396000 750000 + 198000 450000 + >; + clock-latency = <61036>; /* two CLK32 periods */ + }; + + cpu@101 { + compatible = "arm,cortex-a7"; + reg = <101>; + next-level-cache = <&L2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt new file mode 100644 index 0000000000000000000000000000000000000000..73470ecd1f12f282755101bd0460359a815c2904 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/brcm,stb-avs-cpu-freq.txt @@ -0,0 +1,76 @@ +Broadcom AVS mail box and interrupt register bindings +===================================================== + +A total of three DT nodes are required. One node (brcm,avs-cpu-data-mem) +references the mailbox register used to communicate with the AVS CPU[1]. The +second node (brcm,avs-cpu-l2-intr) is required to trigger an interrupt on +the AVS CPU. The interrupt tells the AVS CPU that it needs to process a +command sent to it by a driver. Interrupting the AVS CPU is mandatory for +commands to be processed. + +The interface also requires a reference to the AVS host interrupt controller, +so a driver can react to interrupts generated by the AVS CPU whenever a command +has been processed. See [2] for more information on the brcm,l2-intc node. + +[1] The AVS CPU is an independent co-processor that runs proprietary +firmware. On some SoCs, this firmware supports DFS and DVFS in addition to +Adaptive Voltage Scaling. + +[2] Documentation/devicetree/bindings/interrupt-controller/brcm,l2-intc.txt + + +Node brcm,avs-cpu-data-mem +-------------------------- + +Required properties: +- compatible: must include: brcm,avs-cpu-data-mem and + should include: one of brcm,bcm7271-avs-cpu-data-mem or + brcm,bcm7268-avs-cpu-data-mem +- reg: Specifies base physical address and size of the registers. +- interrupts: The interrupt that the AVS CPU will use to interrupt the host + when a command completed. +- interrupt-names: The name of the interrupt used to interrupt the host. + +Optional properties: +- None + +Node brcm,avs-cpu-l2-intr +------------------------- + +Required properties: +- compatible: must include: brcm,avs-cpu-l2-intr and + should include: one of brcm,bcm7271-avs-cpu-l2-intr or + brcm,bcm7268-avs-cpu-l2-intr +- reg: Specifies base physical address and size of the registers. + +Optional properties: +- None + + +Example +======= + + avs_host_l2_intc: interrupt-controller@f04d1200 { + #interrupt-cells = <1>; + compatible = "brcm,l2-intc"; + interrupt-parent = <&intc>; + reg = <0xf04d1200 0x48>; + interrupt-controller; + interrupts = <0x0 0x19 0x0>; + interrupt-names = "avs"; + }; + + avs-cpu-data-mem@f04c4000 { + compatible = "brcm,bcm7271-avs-cpu-data-mem", + "brcm,avs-cpu-data-mem"; + reg = <0xf04c4000 0x60>; + interrupts = <0x1a>; + interrupt-parent = <&avs_host_l2_intc>; + interrupt-names = "sw_intr"; + }; + + avs-cpu-l2-intr@f04d1100 { + compatible = "brcm,bcm7271-avs-cpu-l2-intr", + "brcm,avs-cpu-l2-intr"; + reg = <0xf04d1100 0x10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-dt.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-dt.txt new file mode 100644 index 0000000000000000000000000000000000000000..332aed8f4597a86240e498f03933497028a66029 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-dt.txt @@ -0,0 +1,60 @@ +Generic cpufreq driver + +It is a generic DT based cpufreq driver for frequency management. It supports +both uniprocessor (UP) and symmetric multiprocessor (SMP) systems which share +clock and voltage across all CPUs. + +Both required and optional properties listed below must be defined +under node /cpus/cpu@0. + +Required properties: +- None + +Optional properties: +- operating-points: Refer to Documentation/devicetree/bindings/opp/opp.txt for + details. OPPs *must* be supplied either via DT, i.e. this property, or + populated at runtime. +- clock-latency: Specify the possible maximum transition latency for clock, + in unit of nanoseconds. +- voltage-tolerance: Specify the CPU voltage tolerance in percentage. +- #cooling-cells: + Please refer to Documentation/devicetree/bindings/thermal/thermal.txt. + +Examples: + +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 1100000 + 396000 950000 + 198000 850000 + >; + clock-latency = <61036>; /* two CLK32 periods */ + #cooling-cells = <2>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + }; + + cpu@2 { + compatible = "arm,cortex-a9"; + reg = <2>; + next-level-cache = <&L2>; + }; + + cpu@3 { + compatible = "arm,cortex-a9"; + reg = <3>; + next-level-cache = <&L2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-mediatek.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-mediatek.txt new file mode 100644 index 0000000000000000000000000000000000000000..0551c78619de807b99908d76eaf76cd6831ee3a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-mediatek.txt @@ -0,0 +1,243 @@ +Binding for MediaTek's CPUFreq driver +===================================== + +Required properties: +- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock names. +- clock-names: Should contain the following: + "cpu" - The multiplexer for clock input of CPU cluster. + "intermediate" - A parent of "cpu" clock which is used as "intermediate" clock + source (usually MAINPLL) when the original CPU PLL is under + transition and not stable yet. + Please refer to Documentation/devicetree/bindings/clock/clock-bindings.txt for + generic clock consumer properties. +- operating-points-v2: Please refer to Documentation/devicetree/bindings/opp/opp.txt + for detail. +- proc-supply: Regulator for Vproc of CPU cluster. + +Optional properties: +- sram-supply: Regulator for Vsram of CPU cluster. When present, the cpufreq driver + needs to do "voltage tracking" to step by step scale up/down Vproc and + Vsram to fit SoC specific needs. When absent, the voltage scaling + flow is handled by hardware, hence no software "voltage tracking" is + needed. +- #cooling-cells: + Please refer to Documentation/devicetree/bindings/thermal/thermal.txt + for detail. + +Example 1 (MT7623 SoC): + + cpu_opp_table: opp_table { + compatible = "operating-points-v2"; + opp-shared; + + opp-598000000 { + opp-hz = /bits/ 64 <598000000>; + opp-microvolt = <1050000>; + }; + + opp-747500000 { + opp-hz = /bits/ 64 <747500000>; + opp-microvolt = <1050000>; + }; + + opp-1040000000 { + opp-hz = /bits/ 64 <1040000000>; + opp-microvolt = <1150000>; + }; + + opp-1196000000 { + opp-hz = /bits/ 64 <1196000000>; + opp-microvolt = <1200000>; + }; + + opp-1300000000 { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1300000>; + }; + }; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x0>; + clocks = <&infracfg CLK_INFRA_CPUSEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table>; + #cooling-cells = <2>; + }; + cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x1>; + operating-points-v2 = <&cpu_opp_table>; + }; + cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x2>; + operating-points-v2 = <&cpu_opp_table>; + }; + cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a7"; + reg = <0x3>; + operating-points-v2 = <&cpu_opp_table>; + }; + +Example 2 (MT8173 SoC): + cpu_opp_table_a: opp_table_a { + compatible = "operating-points-v2"; + opp-shared; + + opp-507000000 { + opp-hz = /bits/ 64 <507000000>; + opp-microvolt = <859000>; + }; + + opp-702000000 { + opp-hz = /bits/ 64 <702000000>; + opp-microvolt = <908000>; + }; + + opp-1001000000 { + opp-hz = /bits/ 64 <1001000000>; + opp-microvolt = <983000>; + }; + + opp-1105000000 { + opp-hz = /bits/ 64 <1105000000>; + opp-microvolt = <1009000>; + }; + + opp-1183000000 { + opp-hz = /bits/ 64 <1183000000>; + opp-microvolt = <1028000>; + }; + + opp-1404000000 { + opp-hz = /bits/ 64 <1404000000>; + opp-microvolt = <1083000>; + }; + + opp-1508000000 { + opp-hz = /bits/ 64 <1508000000>; + opp-microvolt = <1109000>; + }; + + opp-1573000000 { + opp-hz = /bits/ 64 <1573000000>; + opp-microvolt = <1125000>; + }; + }; + + cpu_opp_table_b: opp_table_b { + compatible = "operating-points-v2"; + opp-shared; + + opp-507000000 { + opp-hz = /bits/ 64 <507000000>; + opp-microvolt = <828000>; + }; + + opp-702000000 { + opp-hz = /bits/ 64 <702000000>; + opp-microvolt = <867000>; + }; + + opp-1001000000 { + opp-hz = /bits/ 64 <1001000000>; + opp-microvolt = <927000>; + }; + + opp-1209000000 { + opp-hz = /bits/ 64 <1209000000>; + opp-microvolt = <968000>; + }; + + opp-1404000000 { + opp-hz = /bits/ 64 <1007000000>; + opp-microvolt = <1028000>; + }; + + opp-1612000000 { + opp-hz = /bits/ 64 <1612000000>; + opp-microvolt = <1049000>; + }; + + opp-1807000000 { + opp-hz = /bits/ 64 <1807000000>; + opp-microvolt = <1089000>; + }; + + opp-1989000000 { + opp-hz = /bits/ 64 <1989000000>; + opp-microvolt = <1125000>; + }; + }; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x000>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA53SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table_a>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x001>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA53SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table_a>; + }; + + cpu2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA57SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table_b>; + }; + + cpu3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA57SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cpu_opp_table_b>; + }; + + &cpu0 { + proc-supply = <&mt6397_vpca15_reg>; + }; + + &cpu1 { + proc-supply = <&mt6397_vpca15_reg>; + }; + + &cpu2 { + proc-supply = <&da9211_vcpu_reg>; + sram-supply = <&mt6397_vsramca7_reg>; + }; + + &cpu3 { + proc-supply = <&da9211_vcpu_reg>; + sram-supply = <&mt6397_vsramca7_reg>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw-debug.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw-debug.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f7243cce8a0596ba55385f72bffbccdae4933c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw-debug.txt @@ -0,0 +1,66 @@ +Qualcomm Technologies, Inc. CPUFREQ Hardware Debug Trace Bindings +-------------------------------------------------------------------- + +CPUFREQ Trace provide the support to capture CPUFREQ_HW debug and trace. + +CPUFREQ HW debug and trace is used by Qualcomm Technologies, Inc. (QTI) to +capture trace packets from various clock domains. If applicable trace mode +could be set to periodic or xor. Also, it enables the print for CPUFREQ_HW debug +registers. + +Required Properties: +- compatible: shall contain the following: + "qcom,cpufreq-hw-debug-trace" or "qcom,cpufreq-hw-debug" + or "qcom,cpufreq-hw-epss-debug". +- reg: shall contain base register location and length. +- reg-names: shall contain the frequency domain name. + +Optional Properties: +- qcom,freq-hw-domain: phandle to the frequency domain device node. + +Usage : +The following debug node would get created under qcom-cpufreq-hw directory. + +== Trace Enable/Debug == + +- clock_domain_packet_sel +Function: Set and clear clock domain and trace packet +Input: echo 1 2 1 > clock_domain_packet_sel (domain 1, packet 2, set) + echo 1 2 1 > clock_domain_packet_sel (domain 1, packet 2, clear) + +- clock_timer +Function: Enable/Disable Clock Timer +Input: echo 0 > clk_timer; + echo 1 > clk_timer; + cat clk_timer; + +- trace_enable +Function: Enable and disable global trace +Input: echo 1 > trace_enable + echo 0 > trace_enable + cat trace_enable + +- trace_type +Function: Set trace type to XOR or PERIODIC +Input: echo xor > trace_type; + echo periodic > trace_type; + cat trace_type; + +- print_cpufreq_trace_regs +Function: Print cpufreq hw trace registers +Input: cat print_cpufreq_trace_regs + +== CPUFREQ-HW Register == + +- print_cpufreq_debug_regs +Function: Print cpufreq hardware debug registers +Input: cat print_cpufreq_debug_regs + +Example: + cpufreq_hw_trace: qcom,cpufreq-hw-trace { + compatible = "qcom,cpufreq-hw-trace"; + reg = <0x18320000 0x800>; + reg-names = "domain-top"; + qcom,freq-hw-domain = <&cpufreq_hw 0>, <&cpufreq_hw 1>, + <&cpufreq_hw 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw.txt new file mode 100644 index 0000000000000000000000000000000000000000..1208f624a6e71605cf32efb5208a0d43ca127118 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw.txt @@ -0,0 +1,194 @@ +Qualcomm Technologies, Inc. CPUFREQ Bindings + +CPUFREQ HW is a hardware engine used by some Qualcomm Technologies, Inc. (QTI) +SoCs to manage frequency in hardware. It is capable of controlling frequency +for multiple clusters. + +Properties: +- compatible + Usage: required + Value type: + Definition: must be "qcom,cpufreq-hw" or "qcom,cpufreq-hw-epss". + +- clocks + Usage: required + Value type: From common clock binding. + Definition: clock handle for XO clock and GPLL0 clock. + +- clock-names + Usage: required + Value type: From common clock binding. + Definition: must be "xo", "alternate". + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the HW bases in + each frequency domain. +- reg-names + Usage: Optional + Value type: + Definition: Frequency domain name i.e. + "freq-domain0", "freq-domain1". + +- qcom,lut-row-size + Usage: Optional + Value type: + Definition: Size of the LUT row size. + +- qcom,lut-max-entries + Usage: Optional + Value type: + Definition: Size of the LUT entries. + +- qcom,skip-enable-check + Usage: Optional + Value type: bool + Definition: Indicate to check for Enable of FW before registering + with cpufreq. + +- qcom,no-accumulative-counter + Usage: Optional + Value type: bool + Definition: Indicate to disable reading of accumulative cycle + counter of the frequency domain. This is needed by the + cpufreq-hw which uses the "qcom,cpufreq-hw" + compatible. + +* Property qcom,freq-domain +Devices supporting freq-domain must set their "qcom,freq-domain" property with +phandle to a cpufreq_hw followed by the Domain ID(0/1) and core count in the +CPU DT node. + + +Example: + +Example 1: Dual-cluster, Quad-core per cluster. CPUs within a cluster switch +DCVS state together. + +/ { + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + L2_0: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + L3_0: l3-cache { + compatible = "cache"; + }; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_100>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + L2_100: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&L2_200>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + L2_200: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_300>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + L2_300: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x400>; + enable-method = "psci"; + next-level-cache = <&L2_400>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + L2_400: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x500>; + enable-method = "psci"; + next-level-cache = <&L2_500>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + L2_500: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x600>; + enable-method = "psci"; + next-level-cache = <&L2_600>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + L2_600: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "qcom,kryo385"; + reg = <0x0 0x700>; + enable-method = "psci"; + next-level-cache = <&L2_700>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + L2_700: l2-cache { + compatible = "cache"; + next-level-cache = <&L3_0>; + }; + }; + }; + + soc { + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw"; + reg = <0x17d43000 0x1400>, <0x17d45800 0x1400>; + reg-names = "freq-domain0", "freq-domain1"; + + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>; + clock-names = "xo", "cpu_clk"; + + #freq-domains-cells = <2> + + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-spear.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-spear.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3d44984d91ce63f1d35f1824eef52cdefb42b7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-spear.txt @@ -0,0 +1,42 @@ +SPEAr cpufreq driver +------------------- + +SPEAr SoC cpufreq driver for CPU frequency scaling. +It supports both uniprocessor (UP) and symmetric multiprocessor (SMP) systems +which share clock across all CPUs. + +Required properties: +- cpufreq_tbl: Table of frequencies CPU could be transitioned into, in the + increasing order. + +Optional properties: +- clock-latency: Specify the possible maximum transition latency for clock, in + unit of nanoseconds. + +Both required and optional properties listed above must be defined under node +/cpus/cpu@0. + +Examples: +-------- +cpus { + + <...> + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + + <...> + + cpufreq_tbl = < 166000 + 200000 + 250000 + 300000 + 400000 + 500000 + 600000 >; + }; + + <...> + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-st.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..d91a02a3b6b0721a3e3ccb59367cc47f2f062c1f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-st.txt @@ -0,0 +1,91 @@ +Binding for ST's CPUFreq driver +=============================== + +ST's CPUFreq driver attempts to read 'process' and 'version' attributes +from the SoC, then supplies the OPP framework with 'prop' and 'supported +hardware' information respectively. The framework is then able to read +the DT and operate in the usual way. + +For more information about the expected DT format [See: ../opp/opp.txt]. + +Frequency Scaling only +---------------------- + +No vendor specific driver required for this. + +Located in CPU's node: + +- operating-points : [See: ../power/opp.txt] + +Example [safe] +-------------- + +cpus { + cpu@0 { + /* kHz uV */ + operating-points = <1500000 0 + 1200000 0 + 800000 0 + 500000 0>; + }; +}; + +Dynamic Voltage and Frequency Scaling (DVFS) +-------------------------------------------- + +This requires the ST CPUFreq driver to supply 'process' and 'version' info. + +Located in CPU's node: + +- operating-points-v2 : [See ../power/opp.txt] + +Example [unsafe] +---------------- + +cpus { + cpu@0 { + operating-points-v2 = <&cpu0_opp_table>; + }; +}; + +cpu0_opp_table: opp_table { + compatible = "operating-points-v2"; + + /* ############################################################### */ + /* # WARNING: Do not attempt to copy/replicate these nodes, # */ + /* # they are only to be supplied by the bootloader !!! # */ + /* ############################################################### */ + opp0 { + /* Major Minor Substrate */ + /* 2 all all */ + opp-supported-hw = <0x00000004 0xffffffff 0xffffffff>; + opp-hz = /bits/ 64 <1500000000>; + clock-latency-ns = <10000000>; + + opp-microvolt-pcode0 = <1200000>; + opp-microvolt-pcode1 = <1200000>; + opp-microvolt-pcode2 = <1200000>; + opp-microvolt-pcode3 = <1200000>; + opp-microvolt-pcode4 = <1170000>; + opp-microvolt-pcode5 = <1140000>; + opp-microvolt-pcode6 = <1100000>; + opp-microvolt-pcode7 = <1070000>; + }; + + opp1 { + /* Major Minor Substrate */ + /* all all all */ + opp-supported-hw = <0xffffffff 0xffffffff 0xffffffff>; + opp-hz = /bits/ 64 <1200000000>; + clock-latency-ns = <10000000>; + + opp-microvolt-pcode0 = <1110000>; + opp-microvolt-pcode1 = <1150000>; + opp-microvolt-pcode2 = <1100000>; + opp-microvolt-pcode3 = <1080000>; + opp-microvolt-pcode4 = <1040000>; + opp-microvolt-pcode5 = <1020000>; + opp-microvolt-pcode6 = <980000>; + opp-microvolt-pcode7 = <930000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/msm-cpufreq.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/msm-cpufreq.txt new file mode 100644 index 0000000000000000000000000000000000000000..a74eb4580e99fa9d5b1ff258c5c7fbe95c61fdc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/msm-cpufreq.txt @@ -0,0 +1,47 @@ +Qualcomm Technologies, Inc. CPUfreq device + +msm-cpufreq is a device that represents the list of usable CPU frequencies +and provides a device handle for the CPUfreq driver to get the CPU and cache +clocks. + +Required properties: +- compatible: Must be "qcom,msm-cpufreq" +- qcom,cpufreq-table, or qcom,cpufreq-table-: + A list of usable CPU frequencies (KHz). + Use "qcom,cpufreq-table" if all CPUs in the system + should share same list of frequencies. + Use "qcom,cpufreq-table-" to describe + different CPU freq tables for different CPUs. + The table should be listed only for the first CPU + if multiple CPUs are synchronous. + +Optional properties: +- clock-names: When DT based binding of clock is available, this + provides a list of CPU subsystem clocks. + "cpuX_clk" for every CPU that's present. + "l2_clk" when an async cache/CCI is present. + +Optional properties: +- qcom,governor-per-policy: This property denotes that governor tunables + should be associated with each cpufreq policy + group instead of being global. + +Example: + qcom,msm-cpufreq { + compatible = "qcom,msm-cpufreq"; + qcom,cpufreq-table = + < 300000 >, + < 422400 >, + < 652800 >, + < 729600 >, + < 883200 >, + < 960000 >, + < 1036800 >, + < 1190400 >, + < 1267200 >, + < 1497600 >, + < 1574400 >, + < 1728000 >, + < 1958400 >, + < 2265600 >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/nvidia,tegra124-cpufreq.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/nvidia,tegra124-cpufreq.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1669fbfb74040dea99faee3b6df90bea443ed05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/nvidia,tegra124-cpufreq.txt @@ -0,0 +1,44 @@ +Tegra124 CPU frequency scaling driver bindings +---------------------------------------------- + +Both required and optional properties listed below must be defined +under node /cpus/cpu@0. + +Required properties: +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - cpu_g: Clock mux for the fast CPU cluster. + - cpu_lp: Clock mux for the low-power CPU cluster. + - pll_x: Fast PLL clocksource. + - pll_p: Auxiliary PLL used during fast PLL rate changes. + - dfll: Fast DFLL clocksource that also automatically scales CPU voltage. +- vdd-cpu-supply: Regulator for CPU voltage + +Optional properties: +- clock-latency: Specify the possible maximum transition latency for clock, + in unit of nanoseconds. + +Example: +-------- +cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a15"; + reg = <0>; + + clocks = <&tegra_car TEGRA124_CLK_CCLK_G>, + <&tegra_car TEGRA124_CLK_CCLK_LP>, + <&tegra_car TEGRA124_CLK_PLL_X>, + <&tegra_car TEGRA124_CLK_PLL_P>, + <&dfll>; + clock-names = "cpu_g", "cpu_lp", "pll_x", "pll_p", "dfll"; + clock-latency = <300000>; + vdd-cpu-supply: <&vdd_cpu>; + }; + + <...> +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpufreq/ti-cpufreq.txt b/arch/arm64/boot/dts/vendor/bindings/cpufreq/ti-cpufreq.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c38e4b8fc518e2d6f65adb1910cafb680b0914a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpufreq/ti-cpufreq.txt @@ -0,0 +1,128 @@ +TI CPUFreq and OPP bindings +================================ + +Certain TI SoCs, like those in the am335x, am437x, am57xx, and dra7xx +families support different OPPs depending on the silicon variant in use. +The ti-cpufreq driver can use revision and an efuse value from the SoC to +provide the OPP framework with supported hardware information. This is +used to determine which OPPs from the operating-points-v2 table get enabled +when it is parsed by the OPP framework. + +Required properties: +-------------------- +In 'cpus' nodes: +- operating-points-v2: Phandle to the operating-points-v2 table to use. + +In 'operating-points-v2' table: +- compatible: Should be + - 'operating-points-v2-ti-cpu' for am335x, am43xx, and dra7xx/am57xx SoCs +- syscon: A phandle pointing to a syscon node representing the control module + register space of the SoC. + +Optional properties: +-------------------- +For each opp entry in 'operating-points-v2' table: +- opp-supported-hw: Two bitfields indicating: + 1. Which revision of the SoC the OPP is supported by + 2. Which eFuse bits indicate this OPP is available + + A bitwise AND is performed against these values and if any bit + matches, the OPP gets enabled. + +Example: +-------- + +/* From arch/arm/boot/dts/am33xx.dtsi */ +cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + compatible = "arm,cortex-a8"; + device_type = "cpu"; + reg = <0>; + + operating-points-v2 = <&cpu0_opp_table>; + + clocks = <&dpll_mpu_ck>; + clock-names = "cpu"; + + clock-latency = <300000>; /* From omap-cpufreq driver */ + }; +}; + +/* + * cpu0 has different OPPs depending on SoC revision and some on revisions + * 0x2 and 0x4 have eFuse bits that indicate if they are available or not + */ +cpu0_opp_table: opp-table { + compatible = "operating-points-v2-ti-cpu"; + syscon = <&scm_conf>; + + /* + * The three following nodes are marked with opp-suspend + * because they can not be enabled simultaneously on a + * single SoC. + */ + opp50-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <950000 931000 969000>; + opp-supported-hw = <0x06 0x0010>; + opp-suspend; + }; + + opp100-275000000 { + opp-hz = /bits/ 64 <275000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x01 0x00FF>; + opp-suspend; + }; + + opp100-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x06 0x0020>; + opp-suspend; + }; + + opp100-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x01 0xFFFF>; + }; + + opp100-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <1100000 1078000 1122000>; + opp-supported-hw = <0x06 0x0040>; + }; + + opp120-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <1200000 1176000 1224000>; + opp-supported-hw = <0x01 0xFFFF>; + }; + + opp120-720000000 { + opp-hz = /bits/ 64 <720000000>; + opp-microvolt = <1200000 1176000 1224000>; + opp-supported-hw = <0x06 0x0080>; + }; + + oppturbo-720000000 { + opp-hz = /bits/ 64 <720000000>; + opp-microvolt = <1260000 1234800 1285200>; + opp-supported-hw = <0x01 0xFFFF>; + }; + + oppturbo-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1260000 1234800 1285200>; + opp-supported-hw = <0x06 0x0100>; + }; + + oppnitro-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <1325000 1298500 1351500>; + opp-supported-hw = <0x04 0x0200>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/cpuss_dump/cpuss_dump.txt b/arch/arm64/boot/dts/vendor/bindings/cpuss_dump/cpuss_dump.txt new file mode 100644 index 0000000000000000000000000000000000000000..e19632a0168b8a96b921d8d89cf5b590be2b874f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/cpuss_dump/cpuss_dump.txt @@ -0,0 +1,27 @@ +CPU Subsystem Dump Driver + +The CPU Subsystem dump driver is used to dump various hardware entities +like the instruction and data tlbs or the unified tlbs etc. to an +allocated buffer. This allows the data to be analysed in case of corruption. + +Required Properties for the cpuss_dump node: +-compatible = "qcom,cpuss-dump"; + +All child nodes of cpuss_dump node are interpreted as the various hardware +entities which need to be dumped. + +Required properties of the dump nodes + +- qcom,dump-node: phandle to the acutal cpuss hardware entity present + in the cpu map +- qcom,dump-id: The ID within the data dump table where this entry needs to + be added. + +Example: + msm_cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,itlb_dump100 { + qcom,dump-node = <&L1_itlb_100>; + qcom,dump-id = <34>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/amd-ccp.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/amd-ccp.txt new file mode 100644 index 0000000000000000000000000000000000000000..d87579d63da641f887e56baaa060d98d72c3db5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/amd-ccp.txt @@ -0,0 +1,17 @@ +* AMD Cryptographic Coprocessor driver (ccp) + +Required properties: +- compatible: Should be "amd,ccp-seattle-v1a" +- reg: Address and length of the register set for the device +- interrupts: Should contain the CCP interrupt + +Optional properties: +- dma-coherent: Present if dma operations are coherent + +Example: + ccp@e0100000 { + compatible = "amd,ccp-seattle-v1a"; + reg = <0 0xe0100000 0 0x10000>; + interrupt-parent = <&gic>; + interrupts = <0 3 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/arm-cryptocell.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/arm-cryptocell.txt new file mode 100644 index 0000000000000000000000000000000000000000..999fb2a810f67717bac503006f10cde1ce878262 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/arm-cryptocell.txt @@ -0,0 +1,21 @@ +Arm TrustZone CryptoCell cryptographic engine + +Required properties: +- compatible: Should be one of: "arm,cryptocell-712-ree", + "arm,cryptocell-710-ree" or "arm,cryptocell-630p-ree". +- reg: Base physical address of the engine and length of memory mapped region. +- interrupts: Interrupt number for the device. + +Optional properties: +- clocks: Reference to the crypto engine clock. +- dma-coherent: Present if dma operations are coherent. + +Examples: + + arm_cc712: crypto@80000000 { + compatible = "arm,cryptocell-712-ree"; + interrupt-parent = <&intc>; + interrupts = < 0 30 4 >; + reg = < 0x80000000 0x10000 >; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/artpec6-crypto.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/artpec6-crypto.txt new file mode 100644 index 0000000000000000000000000000000000000000..d9cca4875bd64659079b114712974f82a1950b17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/artpec6-crypto.txt @@ -0,0 +1,16 @@ +Axis crypto engine with PDMA interface. + +Required properties: +- compatible : Should be one of the following strings: + "axis,artpec6-crypto" for the version in the Axis ARTPEC-6 SoC + "axis,artpec7-crypto" for the version in the Axis ARTPEC-7 SoC. +- reg: Base address and size for the PDMA register area. +- interrupts: Interrupt handle for the PDMA interrupt line. + +Example: + +crypto@f4264000 { + compatible = "axis,artpec6-crypto"; + reg = <0xf4264000 0x1000>; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/atmel-crypto.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/atmel-crypto.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b458bb2440d6b846d2a21337c5316d54d672777 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/atmel-crypto.txt @@ -0,0 +1,81 @@ +* Atmel HW cryptographic accelerators + +These are the HW cryptographic accelerators found on some Atmel products. + +* Advanced Encryption Standard (AES) + +Required properties: +- compatible : Should be "atmel,at91sam9g46-aes". +- reg: Should contain AES registers location and length. +- interrupts: Should contain the IRQ line for the AES. +- dmas: List of two DMA specifiers as described in + atmel-dma.txt and dma.txt files. +- dma-names: Contains one identifier string for each DMA specifier + in the dmas property. + +Example: +aes@f8038000 { + compatible = "atmel,at91sam9g46-aes"; + reg = <0xf8038000 0x100>; + interrupts = <43 4 0>; + dmas = <&dma1 2 18>, + <&dma1 2 19>; + dma-names = "tx", "rx"; + +* Triple Data Encryption Standard (Triple DES) + +Required properties: +- compatible : Should be "atmel,at91sam9g46-tdes". +- reg: Should contain TDES registers location and length. +- interrupts: Should contain the IRQ line for the TDES. + +Optional properties: +- dmas: List of two DMA specifiers as described in + atmel-dma.txt and dma.txt files. +- dma-names: Contains one identifier string for each DMA specifier + in the dmas property. + +Example: +tdes@f803c000 { + compatible = "atmel,at91sam9g46-tdes"; + reg = <0xf803c000 0x100>; + interrupts = <44 4 0>; + dmas = <&dma1 2 20>, + <&dma1 2 21>; + dma-names = "tx", "rx"; +}; + +* Secure Hash Algorithm (SHA) + +Required properties: +- compatible : Should be "atmel,at91sam9g46-sha". +- reg: Should contain SHA registers location and length. +- interrupts: Should contain the IRQ line for the SHA. + +Optional properties: +- dmas: One DMA specifiers as described in + atmel-dma.txt and dma.txt files. +- dma-names: Contains one identifier string for each DMA specifier + in the dmas property. Only one "tx" string needed. + +Example: +sha@f8034000 { + compatible = "atmel,at91sam9g46-sha"; + reg = <0xf8034000 0x100>; + interrupts = <42 4 0>; + dmas = <&dma1 2 17>; + dma-names = "tx"; +}; + +* Eliptic Curve Cryptography (I2C) + +Required properties: +- compatible : must be "atmel,atecc508a". +- reg: I2C bus address of the device. +- clock-frequency: must be present in the i2c controller node. + +Example: +atecc508a@c0 { + compatible = "atmel,atecc508a"; + reg = <0xC0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/brcm,spu-crypto.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/brcm,spu-crypto.txt new file mode 100644 index 0000000000000000000000000000000000000000..29b6007568eb39695aa4de9cb23b45affeec6b42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/brcm,spu-crypto.txt @@ -0,0 +1,22 @@ +The Broadcom Secure Processing Unit (SPU) hardware supports symmetric +cryptographic offload for Broadcom SoCs. A SoC may have multiple SPU hardware +blocks. + +Required properties: +- compatible: Should be one of the following: + brcm,spum-crypto - for devices with SPU-M hardware + brcm,spu2-crypto - for devices with SPU2 hardware + brcm,spu2-v2-crypto - for devices with enhanced SPU2 hardware features like SHA3 + and Rabin Fingerprint support + brcm,spum-nsp-crypto - for the Northstar Plus variant of the SPU-M hardware + +- reg: Should contain SPU registers location and length. +- mboxes: The mailbox channel to be used to communicate with the SPU. + Mailbox channels correspond to DMA rings on the device. + +Example: + crypto@612d0000 { + compatible = "brcm,spum-crypto"; + reg = <0 0x612d0000 0 0x900>; + mboxes = <&pdc0 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-dcp.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-dcp.txt new file mode 100644 index 0000000000000000000000000000000000000000..76a0b4e80e83edd46510783274d834748eaff7a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-dcp.txt @@ -0,0 +1,16 @@ +Freescale DCP (Data Co-Processor) found on i.MX23/i.MX28 . + +Required properties: +- compatible : Should be "fsl,-dcp" +- reg : Should contain MXS DCP registers location and length +- interrupts : Should contain MXS DCP interrupt numbers, VMI IRQ and DCP IRQ + must be supplied, optionally Secure IRQ can be present, but + is currently not implemented and not used. + +Example: + +dcp@80028000 { + compatible = "fsl,imx28-dcp", "fsl,imx23-dcp"; + reg = <0x80028000 0x2000>; + interrupts = <52 53>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-imx-sahara.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-imx-sahara.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8a35c71e9478c76db058ac1c6cf6c921bc919ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-imx-sahara.txt @@ -0,0 +1,15 @@ +Freescale SAHARA Cryptographic Accelerator included in some i.MX chips. +Currently only i.MX27 and i.MX53 are supported. + +Required properties: +- compatible : Should be "fsl,-sahara" +- reg : Should contain SAHARA registers location and length +- interrupts : Should contain SAHARA interrupt number + +Example: + +sah@10025000 { + compatible = "fsl,imx27-sahara"; + reg = < 0x10025000 0x800>; + interrupts = <75>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-imx-scc.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-imx-scc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7aad448e8a366812bf54652b5f552fd489bf3cf6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-imx-scc.txt @@ -0,0 +1,21 @@ +Freescale Security Controller (SCC) + +Required properties: +- compatible : Should be "fsl,imx25-scc". +- reg : Should contain register location and length. +- interrupts : Should contain interrupt numbers for SCM IRQ and SMN IRQ. +- interrupt-names : Should specify the names "scm" and "smn" for the + SCM IRQ and SMN IRQ. +- clocks: Should contain the clock driving the SCC core. +- clock-names: Should be set to "ipg". + +Example: + + scc: crypto@53fac000 { + compatible = "fsl,imx25-scc"; + reg = <0x53fac000 0x4000>; + clocks = <&clks 111>; + clock-names = "ipg"; + interrupts = <49>, <50>; + interrupt-names = "scm", "smn"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-sec2.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-sec2.txt new file mode 100644 index 0000000000000000000000000000000000000000..125f155d00d052eec7d5093b5c5076cbe720417f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-sec2.txt @@ -0,0 +1,65 @@ +Freescale SoC SEC Security Engines versions 1.x-2.x-3.x + +Required properties: + +- compatible : Should contain entries for this and backward compatible + SEC versions, high to low, e.g., "fsl,sec2.1", "fsl,sec2.0" (SEC2/3) + e.g., "fsl,sec1.2", "fsl,sec1.0" (SEC1) + warning: SEC1 and SEC2 are mutually exclusive +- reg : Offset and length of the register set for the device +- interrupts : the SEC's interrupt number +- fsl,num-channels : An integer representing the number of channels + available. +- fsl,channel-fifo-len : An integer representing the number of + descriptor pointers each channel fetch fifo can hold. +- fsl,exec-units-mask : The bitmask representing what execution units + (EUs) are available. It's a single 32-bit cell. EU information + should be encoded following the SEC's Descriptor Header Dword + EU_SEL0 field documentation, i.e. as follows: + + bit 0 = reserved - should be 0 + bit 1 = set if SEC has the ARC4 EU (AFEU) + bit 2 = set if SEC has the DES/3DES EU (DEU) + bit 3 = set if SEC has the message digest EU (MDEU/MDEU-A) + bit 4 = set if SEC has the random number generator EU (RNG) + bit 5 = set if SEC has the public key EU (PKEU) + bit 6 = set if SEC has the AES EU (AESU) + bit 7 = set if SEC has the Kasumi EU (KEU) + bit 8 = set if SEC has the CRC EU (CRCU) + bit 11 = set if SEC has the message digest EU extended alg set (MDEU-B) + +remaining bits are reserved for future SEC EUs. + +- fsl,descriptor-types-mask : The bitmask representing what descriptors + are available. It's a single 32-bit cell. Descriptor type information + should be encoded following the SEC's Descriptor Header Dword DESC_TYPE + field documentation, i.e. as follows: + + bit 0 = set if SEC supports the aesu_ctr_nonsnoop desc. type + bit 1 = set if SEC supports the ipsec_esp descriptor type + bit 2 = set if SEC supports the common_nonsnoop desc. type + bit 3 = set if SEC supports the 802.11i AES ccmp desc. type + bit 4 = set if SEC supports the hmac_snoop_no_afeu desc. type + bit 5 = set if SEC supports the srtp descriptor type + bit 6 = set if SEC supports the non_hmac_snoop_no_afeu desc.type + bit 7 = set if SEC supports the pkeu_assemble descriptor type + bit 8 = set if SEC supports the aesu_key_expand_output desc.type + bit 9 = set if SEC supports the pkeu_ptmul descriptor type + bit 10 = set if SEC supports the common_nonsnoop_afeu desc. type + bit 11 = set if SEC supports the pkeu_ptadd_dbl descriptor type + + ..and so on and so forth. + +Example: + + /* MPC8548E */ + crypto@30000 { + compatible = "fsl,sec2.1", "fsl,sec2.0"; + reg = <0x30000 0x10000>; + interrupts = <29 2>; + interrupt-parent = <&mpic>; + fsl,num-channels = <4>; + fsl,channel-fifo-len = <24>; + fsl,exec-units-mask = <0xfe>; + fsl,descriptor-types-mask = <0x12b0ebf>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-sec6.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-sec6.txt new file mode 100644 index 0000000000000000000000000000000000000000..73b0eb950bb39014a50c4fbe0ad01225e08e0a5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/fsl-sec6.txt @@ -0,0 +1,157 @@ +SEC 6 is as Freescale's Cryptographic Accelerator and Assurance Module (CAAM). +Currently Freescale powerpc chip C29X is embedded with SEC 6. +SEC 6 device tree binding include: + -SEC 6 Node + -Job Ring Node + -Full Example + +===================================================================== +SEC 6 Node + +Description + + Node defines the base address of the SEC 6 block. + This block specifies the address range of all global + configuration registers for the SEC 6 block. + For example, In C293, we could see three SEC 6 node. + +PROPERTIES + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v6.0". + + - fsl,sec-era + Usage: optional + Value type: + Definition: A standard property. Define the 'ERA' of the SEC + device. + + - #address-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing physical addresses in child nodes. + + - #size-cells + Usage: required + Value type: + Definition: A standard property. Defines the number of cells + for representing the size of physical addresses in + child nodes. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical + address and length of the SEC 6 configuration registers. + + - ranges + Usage: required + Value type: + Definition: A standard property. Specifies the physical address + range of the SEC 6.0 register space (-SNVS not included). A + triplet that includes the child address, parent address, & + length. + + Note: All other standard properties (see the Devicetree Specification) + are allowed but are optional. + +EXAMPLE + crypto@a0000 { + compatible = "fsl,sec-v6.0"; + fsl,sec-era = <6>; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xa0000 0x20000>; + ranges = <0 0xa0000 0x20000>; + }; + +===================================================================== +Job Ring (JR) Node + + Child of the crypto node defines data processing interface to SEC 6 + across the peripheral bus for purposes of processing + cryptographic descriptors. The specified address + range can be made visible to one (or more) cores. + The interrupt defined for this node is controlled within + the address range of this node. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,sec-v6.0-job-ring". + + - reg + Usage: required + Value type: + Definition: Specifies a two JR parameters: an offset from + the parent physical address and the length the JR registers. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this + device. The value of the interrupts property + consists of one interrupt specifier. The format + of the specifier is defined by the binding document + describing the node's interrupt parent. + +EXAMPLE + jr@1000 { + compatible = "fsl,sec-v6.0-job-ring"; + reg = <0x1000 0x1000>; + interrupts = <49 2 0 0>; + }; + +=================================================================== +Full Example + +Since some chips may contain more than one SEC, the dtsi contains +only the node contents, not the node itself. A chip using the SEC +should include the dtsi inside each SEC node. Example: + +In qoriq-sec6.0.dtsi: + + compatible = "fsl,sec-v6.0"; + fsl,sec-era = <6>; + #address-cells = <1>; + #size-cells = <1>; + + jr@1000 { + compatible = "fsl,sec-v6.0-job-ring", + "fsl,sec-v5.2-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.4-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x1000 0x1000>; + }; + + jr@2000 { + compatible = "fsl,sec-v6.0-job-ring", + "fsl,sec-v5.2-job-ring", + "fsl,sec-v5.0-job-ring", + "fsl,sec-v4.4-job-ring", + "fsl,sec-v4.0-job-ring"; + reg = <0x2000 0x1000>; + }; + +In the C293 device tree, we add the include of public property: + + crypto@a0000 { + /include/ "qoriq-sec6.0.dtsi" + } + + crypto@a0000 { + reg = <0xa0000 0x20000>; + ranges = <0 0xa0000 0x20000>; + + jr@1000 { + interrupts = <49 2 0 0>; + }; + + jr@2000 { + interrupts = <50 2 0 0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/hisilicon,hip07-sec.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/hisilicon,hip07-sec.txt new file mode 100644 index 0000000000000000000000000000000000000000..78d2db9d4de58f012eb9f3096962698b2430a315 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/hisilicon,hip07-sec.txt @@ -0,0 +1,67 @@ +* Hisilicon hip07 Security Accelerator (SEC) + +Required properties: +- compatible: Must contain one of + - "hisilicon,hip06-sec" + - "hisilicon,hip07-sec" +- reg: Memory addresses and lengths of the memory regions through which + this device is controlled. + Region 0 has registers to control the backend processing engines. + Region 1 has registers for functionality common to all queues. + Regions 2-18 have registers for the 16 individual queues which are isolated + both in hardware and within the driver. +- interrupts: Interrupt specifiers. + Refer to interrupt-controller/interrupts.txt for generic interrupt client node + bindings. + Interrupt 0 is for the SEC unit error queue. + Interrupt 2N + 1 is the completion interrupt for queue N. + Interrupt 2N + 2 is the error interrupt for queue N. +- dma-coherent: The driver assumes coherent dma is possible. + +Optional properties: +- iommus: The SEC units are behind smmu-v3 iommus. + Refer to iommu/arm,smmu-v3.txt for more information. + +Example: + +p1_sec_a: crypto@400,d2000000 { + compatible = "hisilicon,hip07-sec"; + reg = <0x400 0xd0000000 0x0 0x10000 + 0x400 0xd2000000 0x0 0x10000 + 0x400 0xd2010000 0x0 0x10000 + 0x400 0xd2020000 0x0 0x10000 + 0x400 0xd2030000 0x0 0x10000 + 0x400 0xd2040000 0x0 0x10000 + 0x400 0xd2050000 0x0 0x10000 + 0x400 0xd2060000 0x0 0x10000 + 0x400 0xd2070000 0x0 0x10000 + 0x400 0xd2080000 0x0 0x10000 + 0x400 0xd2090000 0x0 0x10000 + 0x400 0xd20a0000 0x0 0x10000 + 0x400 0xd20b0000 0x0 0x10000 + 0x400 0xd20c0000 0x0 0x10000 + 0x400 0xd20d0000 0x0 0x10000 + 0x400 0xd20e0000 0x0 0x10000 + 0x400 0xd20f0000 0x0 0x10000 + 0x400 0xd2100000 0x0 0x10000>; + interrupt-parent = <&p1_mbigen_sec_a>; + iommus = <&p1_smmu_alg_a 0x600>; + dma-coherent; + interrupts = <576 4>, + <577 1>, <578 4>, + <579 1>, <580 4>, + <581 1>, <582 4>, + <583 1>, <584 4>, + <585 1>, <586 4>, + <587 1>, <588 4>, + <589 1>, <590 4>, + <591 1>, <592 4>, + <593 1>, <594 4>, + <595 1>, <596 4>, + <597 1>, <598 4>, + <599 1>, <600 4>, + <601 1>, <602 4>, + <603 1>, <604 4>, + <605 1>, <606 4>, + <607 1>, <608 4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/img-hash.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/img-hash.txt new file mode 100644 index 0000000000000000000000000000000000000000..91a3d757d641bb68b0f4556b40673a0431ab6033 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/img-hash.txt @@ -0,0 +1,27 @@ +Imagination Technologies hardware hash accelerator + +The hash accelerator provides hardware hashing acceleration for +SHA1, SHA224, SHA256 and MD5 hashes + +Required properties: + +- compatible : "img,hash-accelerator" +- reg : Offset and length of the register set for the module, and the DMA port +- interrupts : The designated IRQ line for the hashing module. +- dmas : DMA specifier as per Documentation/devicetree/bindings/dma/dma.txt +- dma-names : Should be "tx" +- clocks : Clock specifiers +- clock-names : "sys" Used to clock the hash block registers + "hash" Used to clock data through the accelerator + +Example: + + hash: hash@18149600 { + compatible = "img,hash-accelerator"; + reg = <0x18149600 0x100>, <0x18101100 0x4>; + interrupts = ; + dmas = <&dma 8 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_HASH>, <&clk_periph PERIPH_CLK_ROM>; + clock-names = "sys", "hash"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/inside-secure-safexcel.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/inside-secure-safexcel.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bbf144c9988e6c9f12880eeaa8c74d0c02b3751 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/inside-secure-safexcel.txt @@ -0,0 +1,40 @@ +Inside Secure SafeXcel cryptographic engine + +Required properties: +- compatible: Should be "inside-secure,safexcel-eip197b", + "inside-secure,safexcel-eip197d" or + "inside-secure,safexcel-eip97ies". +- reg: Base physical address of the engine and length of memory mapped region. +- interrupts: Interrupt numbers for the rings and engine. +- interrupt-names: Should be "ring0", "ring1", "ring2", "ring3", "eip", "mem". + +Optional properties: +- clocks: Reference to the crypto engine clocks, the second clock is + needed for the Armada 7K/8K SoCs. +- clock-names: mandatory if there is a second clock, in this case the + name must be "core" for the first clock and "reg" for + the second one. + +Backward compatibility: +Two compatibles are kept for backward compatibility, but shouldn't be used for +new submissions: +- "inside-secure,safexcel-eip197" is equivalent to + "inside-secure,safexcel-eip197b". +- "inside-secure,safexcel-eip97" is equivalent to + "inside-secure,safexcel-eip97ies". + +Example: + + crypto: crypto@800000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0x800000 0x200000>; + interrupts = , + , + , + , + , + ; + interrupt-names = "mem", "ring0", "ring1", "ring2", "ring3", + "eip"; + clocks = <&cpm_syscon0 1 26>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/marvell-cesa.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/marvell-cesa.txt new file mode 100644 index 0000000000000000000000000000000000000000..28d3f2496b8925393669967c389433ca2af7f8e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/marvell-cesa.txt @@ -0,0 +1,44 @@ +Marvell Cryptographic Engines And Security Accelerator + +Required properties: +- compatible: should be one of the following string + "marvell,orion-crypto" + "marvell,kirkwood-crypto" + "marvell,dove-crypto" + "marvell,armada-370-crypto" + "marvell,armada-xp-crypto" + "marvell,armada-375-crypto" + "marvell,armada-38x-crypto" +- reg: base physical address of the engine and length of memory mapped + region. Can also contain an entry for the SRAM attached to the CESA, + but this representation is deprecated and marvell,crypto-srams should + be used instead +- reg-names: "regs". Can contain an "sram" entry, but this representation + is deprecated and marvell,crypto-srams should be used instead +- interrupts: interrupt number +- clocks: reference to the crypto engines clocks. This property is not + required for orion and kirkwood platforms +- clock-names: "cesaX" and "cesazX", X should be replaced by the crypto engine + id. + This property is not required for the orion and kirkwoord + platforms. + "cesazX" clocks are not required on armada-370 platforms +- marvell,crypto-srams: phandle to crypto SRAM definitions + +Optional properties: +- marvell,crypto-sram-size: SRAM size reserved for crypto operations, if not + specified the whole SRAM is used (2KB) + + +Examples: + + crypto@90000 { + compatible = "marvell,armada-xp-crypto"; + reg = <0x90000 0x10000>; + reg-names = "regs"; + interrupts = <48>, <49>; + clocks = <&gateclk 23>, <&gateclk 23>; + clock-names = "cesa0", "cesa1"; + marvell,crypto-srams = <&crypto_sram0>, <&crypto_sram1>; + marvell,crypto-sram-size = <0x600>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/mediatek-crypto.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/mediatek-crypto.txt new file mode 100644 index 0000000000000000000000000000000000000000..450da3661cad96082c4f8e7f5743fb1f6f0f3b81 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/mediatek-crypto.txt @@ -0,0 +1,25 @@ +MediaTek cryptographic accelerators + +Required properties: +- compatible: Should be "mediatek,eip97-crypto" +- reg: Address and length of the register set for the device +- interrupts: Should contain the five crypto engines interrupts in numeric + order. These are global system and four descriptor rings. +- clocks: the clock used by the core +- clock-names: Must contain "cryp". +- power-domains: Must contain a reference to the PM domain. + + +Example: + crypto: crypto@1b240000 { + compatible = "mediatek,eip97-crypto"; + reg = <0 0x1b240000 0 0x20000>; + interrupts = , + , + , + , + ; + clocks = <ðsys CLK_ETHSYS_CRYPTO>; + clock-names = "cryp"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/msm/ice.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/ice.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b0684debd6df64d2e5ec03c033d3acc9d567e30 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/ice.txt @@ -0,0 +1,61 @@ +* Inline Crypto Engine (ICE) + +Required properties: + - compatible : should be "qcom,ice" + - reg : + +Optional properties: + - interrupt-names : name describing the interrupts for ICE IRQ + - interrupts : + - qcom,enable-ice-clk : should enable clocks for ICE HW + - clocks : List of phandle and clock specifier pairs + - clock-names : List of clock input name strings sorted in the same + order as the clocks property. + - qocm,op-freq-hz : max clock speed sorted in the same order as the clocks + property. + - qcom,instance-type : describe the storage type for which ICE node is defined + currently, only "ufs" and "sdcc" are supported storage type + - vdd-hba-supply : regulated supply to be used by ICE HW + - qcom,msm-bus,name : bus for ICE transactions + - qcom,msm-bus,num-cases : bus case mapping for ICE HW + - qcom,msm-bus,num-paths : bus path mapping for iCE HW + - qcom,msm-bus,vectors-KBps : bus bandwidth to be voted + - qcom,bus-vector-names : bus vectors mapping + +Example: + ufs_ice: ufsice@630000 { + compatible = "qcom,ice"; + reg = <0x630000 0x8000>; + interrupt-names = "ufs_ice_nonsec_level_irq", "ufs_ice_sec_level_irq"; + interrupts = <0 258 0>, <0 257 0>; + qcom,enable-ice-clk; + clock-names = "ice_core_clk_src", "ice_core_clk"; + clocks = <&clock_gcc clk_ufs_ice_core_clk_src>, + <&clock_gcc clk_gcc_ufs_ice_core_clk>; + qcom,op-freq-hz = <300000000>, <0>; + qcom,instance-type = "ufs"; + status = "disabled"; + }; + + ufs_card_ice: ufscardice@1db0000 { + compatible = "qcom,ice_card"; + reg = <0x1db0000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_CARD_AXI_CLK>, + <&clock_gcc GCC_UFS_CARD_CLKREF_CLK>, + <&clock_gcc GCC_UFS_CARD_AHB_CLK>, + <&clock_gcc GCC_UFS_CARD_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_card_gdsc>; + qcom,msm-bus,name = "ufs_card_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs_card"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcedev.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcedev.txt new file mode 100644 index 0000000000000000000000000000000000000000..7849afcaa2713323cfbff154c07bbbb9848d99a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcedev.txt @@ -0,0 +1,73 @@ +* QCEDEV (QTI Crypto Engine Device) + +[Root level node] +Crypto Engine +============ +Required properties: + - compatible : should be "qcom,qcedev" + - reg : should contain crypto, BAM register map. + - reg-names : should contain the crypto and bam base register names. + - interrupts : should contain crypto BAM interrupt. + - qcom,bam-pipe-pair : should contain crypto BAM pipe pair index. + - qcom,ce-hw-instance : should contain crypto HW instance. + - qcom,msm_bus,name: Should be "qcedev-noc" + - qcom,msm_bus,num_cases: Depends on the use cases for bus scaling + - qcom,msm_bus,active-only: Boolean flag for context of request (actve/dual) + - qcom,msm_bus,num_paths: The paths for source and destination ports + - qcom,msm_bus,vectors: Vectors for bus topology. + - qcom,ce-device: Device number. + - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target. + +Optional properties: + - qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE. + - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY. + - qcom,support-core-clk-only : optional, indicates if the HW supports single crypto core clk. + - qcom,bsm-ee : optional, indicate the BAM EE value, changes from target to target. Default value is 1 if not specified. + - qcom,smmu-s1-enable : Boolean flag to enable SMMU stage 1 translation. + - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + - qcom,no-clock-support : indicates clocks are not handled by hlos crypto driver. + + +[Second level nodes] +Context banks +============= +Required properties: + - compatible : should be "qcom,qcedev,context-bank" + - iommus : A phandle parsed by smmu driver. Number of entries will vary across targets. + +Optional properties: + - label - string describing iommu domain usage. + - virtual-addr : start of virtual address pool. + - virtual-size : size of virtual address pool. + +Example: + + qcom,qcedev@fd440000 { + compatible = "qcom,qcedev"; + reg = <0xfd440000 0x20000>, + <0xfd444000 0x8000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 235 0>; + qcom,bam-pipe-pair = <0>; + qcom,ce-hw-instance = <1>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <56 512 0 0>, + <56 512 3936000 393600>, + qcom,ce-opp-freq = <100000000>; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&anoc2_smmu 0x1878>, + <&anoc2_smmu 0x1879>, + <&anoc2_smmu 0x187c>, + <&anoc2_smmu 0x187f>; + virtual-addr = <0x60000000>; + virtual-size = <0x00200000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcota.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcota.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ce63af7d4e626a8c7cd72b74753a438ad9e4414 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcota.txt @@ -0,0 +1,42 @@ +* QCOTA (Over The Air Crypto Device) + +Required properties: + - compatible : should be "qcom,qcota" + - reg : should contain crypto, BAM register map. + - reg-names : should contain the crypto and bam base register names. + - interrupts : should contain crypto BAM interrupt. + - qcom,bam-pipe-pair : should contain crypto BAM pipe pair index. + - qcom,ce-hw-instance : should contain crypto HW instance. + - qcom,ce-device: Unique QCOTA device identifier. 0 for first + instance, 1 for second instance, n-1 for n-th instance. + - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target. + +Optional properties: + - qcom,support-core-clk-only : optional, indicates if the HW supports single crypto core clk. + - qcom,bsm-ee : optional, indicate the BAM EE value, changes from target to target.Default value is 1 if not specified. + +Example: + + qcom,qcota@fe140000 { + compatible = "qcom,qcota"; + reg = <0xfe140000 0x20000>, + <0xfe144000 0x8000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 111 0>; + qcom,bam-pipe-pair = <1>; + qcom,ce-hw-instance = <2>; + qcom,ce-device = <0>; + qcom,ce-opp-freq = <100000000>; + }; + + qcom,qcota@fe0c0000 { + compatible = "qcom,qcota"; + reg = <0xfe0c0000 0x20000>, + <0xfe0c4000 0x8000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 113 0>; + qcom,bam-pipe-pair = <1>; + qcom,ce-hw-instance = <4>; + qcom,ce-device = <1>; + qcom,ce-opp-freq = <100000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcrypto.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcrypto.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcb1ae9a412c4cc685531b0ae28793da36777730 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/msm/qcrypto.txt @@ -0,0 +1,66 @@ +* QCRYPTO (QTI Crypto) + +Required properties: + - compatible : should be "qcom,qcrypto" + - reg : should contain crypto, BAM register map. + - reg-names : should contain the crypto and bam base register names. + - interrupts : should contain crypto BAM interrupt. + - qcom,bam-pipe-pair : should contain crypto BAM pipe pair index. + - qcom,ce-hw-instance : should contain crypto HW instance. + - qcom,msm_bus,name: Should be "qcrypto-noc" + - qcom,msm_bus,num_cases: Depends on the use cases for bus scaling + - qcom,msm_bus,active-only: Boolean flag for context of request (actve/dual) + - qcom,msm_bus,num_paths: The paths for source and destination ports + - qcom,ce-device: Device number. Device number is encoded with the following: + bit 3-0 device type: 0 for full disk encryption(fde) + 1 for per file encrption(pfe) + bit 7-4 unit number within the device type. + + +Optional properties: + - qcom,ce-hw-shared : optional, indicates if the hardware is shared between EE. + - qcom,ce-hw-key : optional, indicates if the hardware supports use of HW KEY. + - qcom,use-sw-aes-cbc-ecb-ctr-algo : optional, indicates if use SW aes-cbc/ecb/ctr algorithm. + - qcom,use-sw-aes-xts-algo : optional, indicates if use SW aes-xts algorithm. + - qcom,use-sw-aead-algo : optional, indicates if use SW aead algorithm. + - qcom,use-sw-ahash-algo : optional, indicates if use SW hash algorithm. + - qcom,use-sw-hmac-algo : optional, indicates if use SW hmac algorithm. + - qcom,use-sw-aes-ccm-algo : optional, indicates if use SW aes-ccm algorithm. + - qcom,clk-mgmt-sus-res : optional, indicate if the ce clocks need to be disabled/enabled in suspend/resume function. + - qcom,support-core-clk-only : optional, indicates if the HW supports single crypto core clk. + - qcom,request-bw-before-clk : optional, indicates if the HW supports bandwidth requests prior to clock controls. + - qcom,bsm-ee : optional, indicate the BAM EE value, changes from target to target.Default value is 1 if not specified. + + - qcom,ce-opp-freq: optional, indicates the CE operating frequency in Hz, + changes from target to target. If not specified, by default the + frequency is set as 100MHZ. + + - qcom,msm_bus,vectors: optional, indicates vectors for bus topology. + This attribute is required for msm targets where bus scaling is + required. For other targets such as fsm, they do not perform + bus scaling. It is not required for those targets. + + - qcom,smmu-s1-enable : Boolean flag to bypass SMMU stage 1 translation. + - iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + - qcom,no-clock-support : indicates clocks are not handled by hlos crypto driver. + +Example: + + qcom,qcrypto@fd444000 { + compatible = "qcom,qcrypto"; + reg = <0xfd440000 0x20000>, + <0xfd444000 0x8000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 235 0>; + qcom,bam-pipe-pair = <1>; + qcom,ce-hw-instance = <1>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <56 512 0 0>, + <56 512 3936000 393600>, + qcom,ce-opp-freq = <100000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/mv_cesa.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/mv_cesa.txt new file mode 100644 index 0000000000000000000000000000000000000000..d9b92e2f3138106c2fc11a4660a8bf2b5b8f39af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/mv_cesa.txt @@ -0,0 +1,32 @@ +Marvell Cryptographic Engines And Security Accelerator + +Required properties: +- compatible: should be one of the following string + "marvell,orion-crypto" + "marvell,kirkwood-crypto" + "marvell,dove-crypto" +- reg: base physical address of the engine and length of memory mapped + region. Can also contain an entry for the SRAM attached to the CESA, + but this representation is deprecated and marvell,crypto-srams should + be used instead +- reg-names: "regs". Can contain an "sram" entry, but this representation + is deprecated and marvell,crypto-srams should be used instead +- interrupts: interrupt number +- clocks: reference to the crypto engines clocks. This property is only + required for Dove platforms +- marvell,crypto-srams: phandle to crypto SRAM definitions + +Optional properties: +- marvell,crypto-sram-size: SRAM size reserved for crypto operations, if not + specified the whole SRAM is used (2KB) + +Examples: + + crypto@30000 { + compatible = "marvell,orion-crypto"; + reg = <0x30000 0x10000>; + reg-names = "regs"; + interrupts = <22>; + marvell,crypto-srams = <&crypto_sram>; + marvell,crypto-sram-size = <0x600>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/omap-aes.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/omap-aes.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd9717653cbb9616f7ab194832eb315efef1a6bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/omap-aes.txt @@ -0,0 +1,31 @@ +OMAP SoC AES crypto Module + +Required properties: + +- compatible : Should contain entries for this and backward compatible + AES versions: + - "ti,omap2-aes" for OMAP2. + - "ti,omap3-aes" for OMAP3. + - "ti,omap4-aes" for OMAP4 and AM33XX. + Note that the OMAP2 and 3 versions are compatible (OMAP3 supports + more algorithms) but they are incompatible with OMAP4. +- ti,hwmods: Name of the hwmod associated with the AES module +- reg : Offset and length of the register set for the module +- interrupts : the interrupt-specifier for the AES module. + +Optional properties: +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request names should include "tx" and "rx" if present. + +Example: + /* AM335x */ + aes: aes@53500000 { + compatible = "ti,omap4-aes"; + ti,hwmods = "aes"; + reg = <0x53500000 0xa0>; + interrupts = <102>; + dmas = <&edma 6>, + <&edma 5>; + dma-names = "tx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/omap-des.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/omap-des.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8c63bf2e16dbd92fe4197d3d82d0020e871544e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/omap-des.txt @@ -0,0 +1,30 @@ +OMAP SoC DES crypto Module + +Required properties: + +- compatible : Should contain "ti,omap4-des" +- ti,hwmods: Name of the hwmod associated with the DES module +- reg : Offset and length of the register set for the module +- interrupts : the interrupt-specifier for the DES module +- clocks : A phandle to the functional clock node of the DES module + corresponding to each entry in clock-names +- clock-names : Name of the functional clock, should be "fck" + +Optional properties: +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt + Each entry corresponds to an entry in dma-names +- dma-names: DMA request names should include "tx" and "rx" if present + +Example: + /* DRA7xx SoC */ + des: des@480a5000 { + compatible = "ti,omap4-des"; + ti,hwmods = "des"; + reg = <0x480a5000 0xa0>; + interrupts = ; + dmas = <&sdma 117>, <&sdma 116>; + dma-names = "tx", "rx"; + clocks = <&l3_iclk_div>; + clock-names = "fck"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/omap-sham.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/omap-sham.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad911556961144cb76958411c4a95a7d5dfde279 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/omap-sham.txt @@ -0,0 +1,28 @@ +OMAP SoC SHA crypto Module + +Required properties: + +- compatible : Should contain entries for this and backward compatible + SHAM versions: + - "ti,omap2-sham" for OMAP2 & OMAP3. + - "ti,omap4-sham" for OMAP4 and AM33XX. + - "ti,omap5-sham" for OMAP5, DRA7 and AM43XX. +- ti,hwmods: Name of the hwmod associated with the SHAM module +- reg : Offset and length of the register set for the module +- interrupts : the interrupt-specifier for the SHAM module. + +Optional properties: +- dmas: DMA specifiers for the rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request name. Should be "rx" if a dma is present. + +Example: + /* AM335x */ + sham: sham@53100000 { + compatible = "ti,omap4-sham"; + ti,hwmods = "sham"; + reg = <0x53100000 0x200>; + interrupts = <109>; + dmas = <&edma 36>; + dma-names = "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/picochip-spacc.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/picochip-spacc.txt new file mode 100644 index 0000000000000000000000000000000000000000..df1151f87745e45356f9bdacb6d5413237256504 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/picochip-spacc.txt @@ -0,0 +1,21 @@ +Picochip picoXcell SPAcc (Security Protocol Accelerator) bindings + +Picochip picoXcell devices contain crypto offload engines that may be used for +IPSEC and femtocell layer 2 ciphering. + +Required properties: + - compatible : "picochip,spacc-ipsec" for the IPSEC offload engine + "picochip,spacc-l2" for the femtocell layer 2 ciphering engine. + - reg : Offset and length of the register set for this device + - interrupts : The interrupt line from the SPAcc. + - ref-clock : The input clock that drives the SPAcc. + +Example SPAcc node: + +spacc@10000 { + compatible = "picochip,spacc-ipsec"; + reg = <0x100000 0x10000>; + interrupt-parent = <&vic0>; + interrupts = <24>; + ref-clock = <&ipsec_clk>, "ref"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/qcom,prng.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/qcom,prng.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ee0e9eac9739beacefbc773bd0fc6a2c95e79de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/qcom,prng.txt @@ -0,0 +1,19 @@ +Qualcomm MSM pseudo random number generator. + +Required properties: + +- compatible : should be "qcom,prng" for 8916 etc + : should be "qcom,prng-ee" for 8996 and later using EE + (Execution Environment) slice of prng +- reg : specifies base physical address and size of the registers map +- clocks : phandle to clock-controller plus clock-specifier pair +- clock-names : "core" clocks all registers, FIFO and circuits in PRNG IP block + +Example: + + rng@f9bff000 { + compatible = "qcom,prng"; + reg = <0xf9bff000 0x200>; + clocks = <&clock GCC_PRNG_AHB_CLK>; + clock-names = "core"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/qcom-qce.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/qcom-qce.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdd53b184ba8bf743a16c4345facd8e08a02e7eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/qcom-qce.txt @@ -0,0 +1,25 @@ +Qualcomm crypto engine driver + +Required properties: + +- compatible : should be "qcom,crypto-v5.1" +- reg : specifies base physical address and size of the registers map +- clocks : phandle to clock-controller plus clock-specifier pair +- clock-names : "iface" clocks register interface + "bus" clocks data transfer interface + "core" clocks rest of the crypto block +- dmas : DMA specifiers for tx and rx dma channels. For more see + Documentation/devicetree/bindings/dma/dma.txt +- dma-names : DMA request names should be "rx" and "tx" + +Example: + crypto@fd45a000 { + compatible = "qcom,crypto-v5.1"; + reg = <0xfd45a000 0x6000>; + clocks = <&gcc GCC_CE2_AHB_CLK>, + <&gcc GCC_CE2_AXI_CLK>, + <&gcc GCC_CE2_CLK>; + clock-names = "iface", "bus", "core"; + dmas = <&cryptobam 2>, <&cryptobam 3>; + dma-names = "rx", "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/rockchip-crypto.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/rockchip-crypto.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e2ba385b8c9b9a6118af61c36c2a4e0b8463287 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/rockchip-crypto.txt @@ -0,0 +1,28 @@ +Rockchip Electronics And Security Accelerator + +Required properties: +- compatible: Should be "rockchip,rk3288-crypto" +- reg: Base physical address of the engine and length of memory mapped + region +- interrupts: Interrupt number +- clocks: Reference to the clocks about crypto +- clock-names: "aclk" used to clock data + "hclk" used to clock data + "sclk" used to clock crypto accelerator + "apb_pclk" used to clock dma +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the name "crypto-rst". + +Examples: + + crypto: cypto-controller@ff8a0000 { + compatible = "rockchip,rk3288-crypto"; + reg = <0xff8a0000 0x4000>; + interrupts = ; + clocks = <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>, + <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC1>; + clock-names = "aclk", "hclk", "sclk", "apb_pclk"; + resets = <&cru SRST_CRYPTO>; + reset-names = "crypto-rst"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/samsung-sss.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/samsung-sss.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a5ca56683cc99cd68ca910277081168a24fb791 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/samsung-sss.txt @@ -0,0 +1,32 @@ +Samsung SoC SSS (Security SubSystem) module + +The SSS module in S5PV210 SoC supports the following: +-- Feeder (FeedCtrl) +-- Advanced Encryption Standard (AES) +-- Data Encryption Standard (DES)/3DES +-- Public Key Accelerator (PKA) +-- SHA-1/SHA-256/MD5/HMAC (SHA-1/SHA-256/MD5)/PRNG +-- PRNG: Pseudo Random Number Generator + +The SSS module in Exynos4 (Exynos4210) and +Exynos5 (Exynos5420 and Exynos5250) SoCs +supports the following also: +-- ARCFOUR (ARC4) +-- True Random Number Generator (TRNG) +-- Secure Key Manager + +Required properties: + +- compatible : Should contain entries for this and backward compatible + SSS versions: + - "samsung,s5pv210-secss" for S5PV210 SoC. + - "samsung,exynos4210-secss" for Exynos4210, Exynos4212, Exynos4412, Exynos5250, + Exynos5260 and Exynos5420 SoCs. +- reg : Offset and length of the register set for the module +- interrupts : interrupt specifiers of SSS module interrupts (one feed + control interrupt). + +- clocks : list of clock phandle and specifier pairs for all clocks listed in + clock-names property. +- clock-names : list of device clock input names; should contain one entry + "secss". diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-crc.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-crc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ba92a5e9b3617e0ceb86af03f6cf288d278ae73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-crc.txt @@ -0,0 +1,16 @@ +* STMicroelectronics STM32 CRC + +Required properties: +- compatible: Should be "st,stm32f7-crc". +- reg: The address and length of the peripheral registers space +- clocks: The input clock of the CRC instance + +Optional properties: none + +Example: + +crc: crc@40023000 { + compatible = "st,stm32f7-crc"; + reg = <0x40023000 0x400>; + clocks = <&rcc 0 12>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-cryp.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-cryp.txt new file mode 100644 index 0000000000000000000000000000000000000000..970487fa40b815f83d4fb9ccc730f11185ea041a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-cryp.txt @@ -0,0 +1,19 @@ +* STMicroelectronics STM32 CRYP + +Required properties: +- compatible: Should be "st,stm32f756-cryp". +- reg: The address and length of the peripheral registers space +- clocks: The input clock of the CRYP instance +- interrupts: The CRYP interrupt + +Optional properties: +- resets: The input reset of the CRYP instance + +Example: +crypto@50060000 { + compatible = "st,stm32f756-cryp"; + reg = <0x50060000 0x400>; + interrupts = <79>; + clocks = <&rcc 0 STM32F7_AHB2_CLOCK(CRYP)>; + resets = <&rcc STM32F7_AHB2_RESET(CRYP)>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-hash.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-hash.txt new file mode 100644 index 0000000000000000000000000000000000000000..04fc246f02f79326999ea09ebfae58872100d089 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/st,stm32-hash.txt @@ -0,0 +1,30 @@ +* STMicroelectronics STM32 HASH + +Required properties: +- compatible: Should contain entries for this and backward compatible + HASH versions: + - "st,stm32f456-hash" for stm32 F456. + - "st,stm32f756-hash" for stm32 F756. +- reg: The address and length of the peripheral registers space +- interrupts: the interrupt specifier for the HASH +- clocks: The input clock of the HASH instance + +Optional properties: +- resets: The input reset of the HASH instance +- dmas: DMA specifiers for the HASH. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request name. Should be "in" if a dma is present. +- dma-maxburst: Set number of maximum dma burst supported + +Example: + +hash1: hash@50060400 { + compatible = "st,stm32f756-hash"; + reg = <0x50060400 0x400>; + interrupts = <80>; + clocks = <&rcc 0 STM32F7_AHB2_CLOCK(HASH)>; + resets = <&rcc STM32F7_AHB2_RESET(HASH)>; + dmas = <&dma2 7 2 0x400 0x0>; + dma-names = "in"; + dma-maxburst = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/crypto/sun4i-ss.txt b/arch/arm64/boot/dts/vendor/bindings/crypto/sun4i-ss.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2dc3d9bca9204edd46777100064f8ce034ebafc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/crypto/sun4i-ss.txt @@ -0,0 +1,23 @@ +* Allwinner Security System found on A20 SoC + +Required properties: +- compatible : Should be "allwinner,sun4i-a10-crypto". +- reg: Should contain the Security System register location and length. +- interrupts: Should contain the IRQ line for the Security System. +- clocks : List of clock specifiers, corresponding to ahb and ss. +- clock-names : Name of the functional clock, should be + * "ahb" : AHB gating clock + * "mod" : SS controller clock + +Optional properties: + - resets : phandle + reset specifier pair + - reset-names : must contain "ahb" + +Example: + crypto: crypto-engine@1c15000 { + compatible = "allwinner,sun4i-a10-crypto"; + reg = <0x01c15000 0x1000>; + interrupts = ; + clocks = <&ahb_gates 5>, <&ss_clk>; + clock-names = "ahb", "mod"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/arm-memlat-mon.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/arm-memlat-mon.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad70b89bc13cd8d2cc611ab999d5710bc51ff8fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/arm-memlat-mon.txt @@ -0,0 +1,73 @@ +ARM CPU memory latency monitor device + +arm-memlat-mon is a device that represents the use of the PMU in ARM cores +to measure the parameters for latency driven memory access patterns. + +Required structure: +An instance of arm-memlat-mon must be described in two levels of device nodes. +The first level describes the controller while the second level describes the +monitors that the controller manages. At least one monitor is required per +controller. + +[First Level Nodes] +Required properties: +- compatible: Must be "qcom,arm-memlat-cpugrp" +- qcom,cpulist: List of CPU phandles to be monitored in a + cluster. Must be a superset of cpulists + described in second level nodes. + +[Second Level Nodes] +Required properties: +- compatible: Must be "qcom,arm-memlat-mon" or + "qcom,arm-compute-mon" +- qcom,target-dev: The DT device that corresponds to this master + port +- qcom,core-dev-table: A mapping table of core frequency to a required + bandwidth vote at the given core frequency. +- qcom,cachemiss-ev: The cache miss event that this monitor is + supposed to measure. Optional for compute only. +Optional properties: +- qcom,cpulist: List of CPU phandles to be monitored in a + cluster. Must be a subset of the cpulist + described in first level node. Defaults to + cpulist in first level node if not specified. +- qcom,inst-ev: The instruction count event that this monitor is + supposed to measure. Defaults to 0x08 if not + specified. +- qcom,stall-cycle-ev: The stall cycle count that this monitor is + supposed to measure. Assumes 100% stall if not + specified. +- qcom,ddr-type: Optional property indicates ddr type which can support + different frequencies for a given target. + +Example: + +#define DDR_TYPE_LPDDR3 5 +#define DDR_TYPE_LPDDR4X 7 + + qcom,arm-memlat-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1>; + + qcom,arm-memlat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,target-dev = <&memlat0>; + qcom,cachemiss-ev = <0x2A>; + qcom,inst-ev = <0x08>; + qcom,stall-cycle-ev = <0xE7>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 1525 >, + < 499200 3143 >, + < 1881600 5859 >; + }; + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 1525 >, + < 499200 3143 >, + < 1881600 5859 >; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/bimc-bwmon.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/bimc-bwmon.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6925d7fc38859ff7658045602282d3bc99fee97 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/bimc-bwmon.txt @@ -0,0 +1,39 @@ +MSM BIMC bandwidth monitor device + +bimc-bwmon is a device that represents the MSM BIMC bandwidth monitors that +can be used to measure the bandwidth of read/write traffic from the BIMC +master ports. For example, the CPU subsystem sits on one BIMC master port. + +Required properties: +- compatible: Must be "qcom,bimc-bwmon", "qcom,bimc-bwmon2" + "qcom,bimc-bwmon3" or "qcom,bimc-bwmon4" or + "qcom,bimc-bwmon5" +- reg: Pairs of physical base addresses and region sizes of + memory mapped registers. +- reg-names: Names of the bases for the above registers. Expected + bases are: "base", "global_base" +- interrupts: Lists the threshold IRQ. +- qcom,mport: The hardware master port that this device can monitor +- qcom,target-dev: The DT device that corresponds to this master port +- qcom,hw-timer-hz: Hardware sampling rate in Hz. This field must be + specified for "qcom,bimc-bwmon4" +Optional properties: +- qcom,byte-mid-match: Byte count MID match value +- qcom,byte-mid-mask: Byte count MID mask value +- qcom,count-unit: Number of bytes monitor counts in +- qcom,msm_bus: A list of tuples where each tuple consists of a bus + master port number and a bus slave port number. +- qcom,msm_bus_name: Name of the DT device voting for the bus. +Example: + qcom,cpu-bwmon { + compatible = "qcom,bimc-bwmon"; + reg = <0xfc388000 0x300>, <0xfc381000 0x200>; + reg-names = "base", "global_base"; + interrupts = <0 183 1>; + qcom,mport = <0>; + qcom,target-dev = <&cpubw>; + qcom,hw-timer-hz = <19200000>; + qcom,byte-mid-match = <0x1e00>; + qcom,byte-mid-mask = <0x1e00>; + qcom,count-unit = <0x100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/devbw.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/devbw.txt new file mode 100644 index 0000000000000000000000000000000000000000..052ea9270b89cb098915c32a5ce5c3c4712b2e5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/devbw.txt @@ -0,0 +1,75 @@ +MSM device bandwidth device + +devbw is a device that represents a MSM device's BW requirements from its +master port(s) to a different device's slave port(s) in a MSM SoC. This +device is typically used to vote for BW requirements from a device's (Eg: +CPU, GPU) master port(s) to the slave (Eg: DDR) port(s). + +Required properties: +- compatible: Must be "qcom,devbw" or "qcom,devbw-ddr" or "qcom,devbw-llcc" +- qcom,src-dst-ports: A list of tuples where each tuple consists of a bus + master port number and a bus slave port number. +- operating-points-v2: A phandle to the OPP v2 table that holds meaningful + instantaneous bandwidth values (in MB/s) that can be + requested from the device master port to the slave port. + The list of values depend on the supported bus/slave + frequencies and the bus width. +Optional properties: +- qcom,active-only: Indicates that the bandwidth votes need to be + enforced only when the CPU subsystem is active. +- governor: Initial governor to use for the device. + Default: "performance" + +- opp-supported-hw: For the devices that are compatible with "qcom, devbw-ddr", + the OPP node can have opp-supported-hw property. This is a + single 32 bit bitmap value, representing compatible DDR-Type in HW. +Example: + Value: + 0x80: Frequency Compatible for LPDDR4X only + 0x100: Frequency Compatible for LPDDR5 only + 0x180: Frequency Compatible for both LPDDR4X and LPDDR5 + + +Example: + + bw_opp_table: bw-opp-table { + compatible = "operating-points-v2"; + opp-75 { + opp-hz = /bits/ 64 < 572 >; /* 75 MHz */ + opp-supported-hw = <0x80>; + }; + opp-150 { + opp-hz = /bits/ 64 < 1144 >; /* 150 MHz */ + opp-supported-hw = <0x80>; + }; + opp-200 { + opp-hz = /bits/ 64 < 1525 >; /* 200 MHz */ + opp-supported-hw = <0x180>; + }; + opp-307 { + opp-hz = /bits/ 64 < 2342 >; /* 307 MHz */ + opp-supported-hw = <0x80>; + }; + opp-460 { + opp-hz = /bits/ 64 < 3509 >; /* 460 MHz */ + opp-supported-hw = <0x80>; + }; + opp-614 { + opp-hz = /bits/ 64 < 4684 >; /* 614 MHz */ + opp-supported-hw = <0x80>; + }; + opp-800 { + opp-hz = /bits/ 64 < 6103 >; /* 800 MHz */ + opp-supported-hw = <0x80>; + }; + opp-931 { + opp-hz = /bits/ 64 < 7102 >; /* 931 MHz */ + opp-supported-hw = <0x80>; + }; + }; + qcom,cpubw { + compatible = "qcom,devbw-ddr"; + qcom,src-dst-ports = <1 512>, <2 512>; + qcom,active-only; + operating-points-v2 = <&bw_opp_table>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-qcom-fw.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-qcom-fw.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d4494f37f8307b26fdaec6533fbff71a14edecb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-qcom-fw.txt @@ -0,0 +1,48 @@ +QCOM Devfreq firmware device + +Some Qualcomm Technologies, Inc. (QTI) chipsets have a firmware that +offloads the steps for frequency switching. It provides a table of +supported frequencies and a register to request one of the supported +freqencies. + +The qcom,devfreq-fw represents this firmware as a device. Sometimes, +multiple entities want to vote on the frequency request that is sent to the +firmware. The qcom,devfreq-fw-voter represents these voters as child +devices of the corresponding qcom,devfreq-fw device. + +Required properties: +- compatible: Must be "qcom,devfreq-fw" or "qcom,devfreq-fw-voter" +Only for qcom,devfreq-fw: +- reg: Pairs of physical base addresses and region sizes of + memory mapped registers. +- reg-names: Names of the bases for the above registers. + Required register regions are: + - "en-base": address of register to check if the + firmware is enabled. + - "ftbl-base": address region for the frequency + table. + - "perf-base": address of register to request a + frequency. + Optional register region: + - "pstate-base": address of register to request + for current performance state (Mandatory if + qcom,support-panic-notifier property is added). +Optional properties: +- qcom,ftbl-row-size: Size of the LUT row size. +- qcom,support-panic-notifier: Support for panic notifier for l3-domain. + +Example: + + qcom,devfreq-l3 { + compatible = "qcom,devfreq-fw"; + reg-names = "en-base", "ftbl-base", "perf-base"; + reg = <0x18321000 0x4>, <0x18321110 0x600>, <0x18321920 0x4>; + + qcom,cpu0-l3 { + compatible = "qcom,devfreq-fw-voter"; + }; + + qcom,cpu4-l3 { + compatible = "qcom,devfreq-fw-voter"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-qcom-qoslat.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-qcom-qoslat.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b25bf38e7be06d0ea7c083b02f69c2276f632f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-qcom-qoslat.txt @@ -0,0 +1,37 @@ +QCOM Devfreq memory latency QoS voting device + +Some Qualcomm Technologies, Inc. (QTI) chipsets have an interface to vote for +a memory latency QoS level. The qcom,devfreq-qoslat represents a device that +votes on this interface to request a particular memory latency QoS level. + +Required properties: +- compatible: Must be "qcom,devfreq-qoslat" +- operating-points-v2: A phandle to the OPP v2 table that holds the supported + QoS levels for the particular chipset. Currently, only + OPP values of 0 and 1 are supported. +- mboxes: A phandle to the mailbox used by this device to send + requests to adjust the memory latency QoS level. +Optional properties: +- governor: Initial governor to use for the device. + Default: "powersave" + +Example: + + qoslat_opp_table: qoslat-opp-table { + compatible = "operating-points-v2"; + opp-0 { + opp-hz = /bits/ 64 < 0 >; + }; + + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; + }; + + qcom,devfreq-qoslat { + compatible = "qcom,devfreq-qoslat"; + governor = "powersave"; + operating-points-v2 = <&qoslat_opp_table>; + mboxes = <&qmp_aop 0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-simple-dev.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-simple-dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f66bbffc06eb963b20448ce5ef058130c2d33f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/devfreq-simple-dev.txt @@ -0,0 +1,48 @@ +Devfreq simple device + +devfreq-simple-dev is a device that represents a simple device that cannot do +any status reporting and uses a clock that can be scaled by one of more +devfreq governors. It provides a list of usable frequencies for the device +and some additional optional parameters. + +Required properties: +- compatible: Must be "devfreq-simple-dev" +- clock-names: Must be "devfreq_clk" +- clocks: Must refer to the clock that's fed to the device. +Optional properties: +- polling-ms: Polling interval for the device in milliseconds. Default: 50 +- governor: Initial governor to user for the device. Default: "performance" +- qcom,prepare-clk: Prepare the device clock during initialization. +- freq-tbl-khz: A list of usable frequencies (in kHz) for the device + clock. + +Example: + + qcom,cache { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_krait clk_l2_clk>; + polling-ms = 50; + governor = "cpufreq"; + freq-tbl-khz = + < 300000 >, + < 345600 >, + < 422400 >, + < 499200 >, + < 576000 >, + < 652800 >, + < 729600 >, + < 806400 >, + < 883200 >, + < 960000 >, + < 1036800 >, + < 1113600 >, + < 1190400 >, + < 1267200 >, + < 1344000 >, + < 1420800 >, + < 1497600 >, + < 1574400 >, + < 1651200 >, + < 1728000 >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/event/exynos-nocp.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/event/exynos-nocp.txt new file mode 100644 index 0000000000000000000000000000000000000000..aeaebd425d1fc583b94685268a0d6c30c8e255f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/event/exynos-nocp.txt @@ -0,0 +1,26 @@ + +* Samsung Exynos NoC (Network on Chip) Probe device + +The Samsung Exynos542x SoC has NoC (Network on Chip) Probe for NoC bus. +NoC provides the primitive values to get the performance data. The packets +that the Network on Chip (NoC) probes detects are transported over +the network infrastructure to observer units. You can configure probes to +capture packets with header or data on the data request response network, +or as traffic debug or statistic collectors. Exynos542x bus has multiple +NoC probes to provide bandwidth information about behavior of the SoC +that you can use while analyzing system performance. + +Required properties: +- compatible: Should be "samsung,exynos5420-nocp" +- reg: physical base address of each NoC Probe and length of memory mapped region. + +Optional properties: +- clock-names : the name of clock used by the NoC Probe, "nocp" +- clocks : phandles for clock specified in "clock-names" property + +Example : NoC Probe nodes in Device Tree are listed below. + + nocp_mem0_0: nocp@10ca1000 { + compatible = "samsung,exynos5420-nocp"; + reg = <0x10CA1000 0x200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/event/exynos-ppmu.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/event/exynos-ppmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e36c1d113866267d659362b1841c25c190e8e36 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/event/exynos-ppmu.txt @@ -0,0 +1,147 @@ + +* Samsung Exynos PPMU (Platform Performance Monitoring Unit) device + +The Samsung Exynos SoC has PPMU (Platform Performance Monitoring Unit) for +each IP. PPMU provides the primitive values to get performance data. These +PPMU events provide information of the SoC's behaviors so that you may +use to analyze system performance, to make behaviors visible and to count +usages of each IP (DMC, CPU, RIGHTBUS, LEFTBUS, CAM interface, LCD, G3D, MFC). +The Exynos PPMU driver uses the devfreq-event class to provide event data +to various devfreq devices. The devfreq devices would use the event data when +derterming the current state of each IP. + +Required properties: +- compatible: Should be "samsung,exynos-ppmu" or "samsung,exynos-ppmu-v2. +- reg: physical base address of each PPMU and length of memory mapped region. + +Optional properties: +- clock-names : the name of clock used by the PPMU, "ppmu" +- clocks : phandles for clock specified in "clock-names" property + +Example1 : PPMUv1 nodes in exynos3250.dtsi are listed below. + + ppmu_dmc0: ppmu_dmc0@106a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106a0000 0x2000>; + status = "disabled"; + }; + + ppmu_dmc1: ppmu_dmc1@106b0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106b0000 0x2000>; + status = "disabled"; + }; + + ppmu_cpu: ppmu_cpu@106c0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x106c0000 0x2000>; + status = "disabled"; + }; + + ppmu_rightbus: ppmu_rightbus@112a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x112a0000 0x2000>; + clocks = <&cmu CLK_PPMURIGHT>; + clock-names = "ppmu"; + status = "disabled"; + }; + + ppmu_leftbus: ppmu_leftbus0@116a0000 { + compatible = "samsung,exynos-ppmu"; + reg = <0x116a0000 0x2000>; + clocks = <&cmu CLK_PPMULEFT>; + clock-names = "ppmu"; + status = "disabled"; + }; + +Example2 : Events of each PPMU node in exynos3250-rinato.dts are listed below. + + &ppmu_dmc0 { + status = "okay"; + + events { + ppmu_dmc0_3: ppmu-event3-dmc0 { + event-name = "ppmu-event3-dmc0"; + }; + + ppmu_dmc0_2: ppmu-event2-dmc0 { + event-name = "ppmu-event2-dmc0"; + }; + + ppmu_dmc0_1: ppmu-event1-dmc0 { + event-name = "ppmu-event1-dmc0"; + }; + + ppmu_dmc0_0: ppmu-event0-dmc0 { + event-name = "ppmu-event0-dmc0"; + }; + }; + }; + + &ppmu_dmc1 { + status = "okay"; + + events { + ppmu_dmc1_3: ppmu-event3-dmc1 { + event-name = "ppmu-event3-dmc1"; + }; + }; + }; + + &ppmu_leftbus { + status = "okay"; + + events { + ppmu_leftbus_3: ppmu-event3-leftbus { + event-name = "ppmu-event3-leftbus"; + }; + }; + }; + + &ppmu_rightbus { + status = "okay"; + + events { + ppmu_rightbus_3: ppmu-event3-rightbus { + event-name = "ppmu-event3-rightbus"; + }; + }; + }; + +Example3 : PPMUv2 nodes in exynos5433.dtsi are listed below. + + ppmu_d0_cpu: ppmu_d0_cpu@10480000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x10480000 0x2000>; + status = "disabled"; + }; + + ppmu_d0_general: ppmu_d0_general@10490000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x10490000 0x2000>; + status = "disabled"; + }; + + ppmu_d0_rt: ppmu_d0_rt@104a0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104a0000 0x2000>; + status = "disabled"; + }; + + ppmu_d1_cpu: ppmu_d1_cpu@104b0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104b0000 0x2000>; + status = "disabled"; + }; + + ppmu_d1_general: ppmu_d1_general@104c0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104c0000 0x2000>; + status = "disabled"; + }; + + ppmu_d1_rt: ppmu_d1_rt@104d0000 { + compatible = "samsung,exynos-ppmu-v2"; + reg = <0x104d0000 0x2000>; + status = "disabled"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/event/rockchip-dfi.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/event/rockchip-dfi.txt new file mode 100644 index 0000000000000000000000000000000000000000..148191b0fc15864725da6907a0571b64337024d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/event/rockchip-dfi.txt @@ -0,0 +1,18 @@ + +* Rockchip rk3399 DFI device + +Required properties: +- compatible: Must be "rockchip,rk3399-dfi". +- reg: physical base address of each DFI and length of memory mapped region +- rockchip,pmu: phandle to the syscon managing the "pmu general register files" +- clocks: phandles for clock specified in "clock-names" property +- clock-names : the name of clock used by the DFI, must be "pclk_ddr_mon"; + +Example: + dfi: dfi@ff630000 { + compatible = "rockchip,rk3399-dfi"; + reg = <0x00 0xff630000 0x00 0x4000>; + rockchip,pmu = <&pmugrf>; + clocks = <&cru PCLK_DDR_MON>; + clock-names = "pclk_ddr_mon"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/exynos-bus.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/exynos-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8e946471a58d7bb6ac07d22cf6a876d8c509410 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/exynos-bus.txt @@ -0,0 +1,423 @@ +* Generic Exynos Bus frequency device + +The Samsung Exynos SoC has many buses for data transfer between DRAM +and sub-blocks in SoC. Most Exynos SoCs share the common architecture +for buses. Generally, each bus of Exynos SoC includes a source clock +and a power line, which are able to change the clock frequency +of the bus in runtime. To monitor the usage of each bus in runtime, +the driver uses the PPMU (Platform Performance Monitoring Unit), which +is able to measure the current load of sub-blocks. + +The Exynos SoC includes the various sub-blocks which have the each AXI bus. +The each AXI bus has the owned source clock but, has not the only owned +power line. The power line might be shared among one more sub-blocks. +So, we can divide into two type of device as the role of each sub-block. +There are two type of bus devices as following: +- parent bus device +- passive bus device + +Basically, parent and passive bus device share the same power line. +The parent bus device can only change the voltage of shared power line +and the rest bus devices (passive bus device) depend on the decision of +the parent bus device. If there are three blocks which share the VDD_xxx +power line, Only one block should be parent device and then the rest blocks +should depend on the parent device as passive device. + + VDD_xxx |--- A block (parent) + |--- B block (passive) + |--- C block (passive) + +There are a little different composition among Exynos SoC because each Exynos +SoC has different sub-blocks. Therefore, such difference should be specified +in devicetree file instead of each device driver. In result, this driver +is able to support the bus frequency for all Exynos SoCs. + +Required properties for all bus devices: +- compatible: Should be "samsung,exynos-bus". +- clock-names : the name of clock used by the bus, "bus". +- clocks : phandles for clock specified in "clock-names" property. +- operating-points-v2: the OPP table including frequency/voltage information + to support DVFS (Dynamic Voltage/Frequency Scaling) feature. + +Required properties only for parent bus device: +- vdd-supply: the regulator to provide the buses with the voltage. +- devfreq-events: the devfreq-event device to monitor the current utilization + of buses. + +Required properties only for passive bus device: +- devfreq: the parent bus device. + +Optional properties only for parent bus device: +- exynos,saturation-ratio: the percentage value which is used to calibrate + the performance count against total cycle count. +- exynos,voltage-tolerance: the percentage value for bus voltage tolerance + which is used to calculate the max voltage. + +Detailed correlation between sub-blocks and power line according to Exynos SoC: +- In case of Exynos3250, there are two power line as following: + VDD_MIF |--- DMC + + VDD_INT |--- LEFTBUS (parent device) + |--- PERIL + |--- MFC + |--- G3D + |--- RIGHTBUS + |--- PERIR + |--- FSYS + |--- LCD0 + |--- PERIR + |--- ISP + |--- CAM + +- In case of Exynos4210, there is one power line as following: + VDD_INT |--- DMC (parent device) + |--- LEFTBUS + |--- PERIL + |--- MFC(L) + |--- G3D + |--- TV + |--- LCD0 + |--- RIGHTBUS + |--- PERIR + |--- MFC(R) + |--- CAM + |--- FSYS + |--- GPS + |--- LCD0 + |--- LCD1 + +- In case of Exynos4x12, there are two power line as following: + VDD_MIF |--- DMC + + VDD_INT |--- LEFTBUS (parent device) + |--- PERIL + |--- MFC(L) + |--- G3D + |--- TV + |--- IMAGE + |--- RIGHTBUS + |--- PERIR + |--- MFC(R) + |--- CAM + |--- FSYS + |--- GPS + |--- LCD0 + |--- ISP + +- In case of Exynos5422, there are two power line as following: + VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller) + |--- DREX 1 + + VDD_INT |--- NoC_Core (parent device) + |--- G2D + |--- G3D + |--- DISP1 + |--- NoC_WCORE + |--- GSCL + |--- MSCL + |--- ISP + |--- MFC + |--- GEN + |--- PERIS + |--- PERIC + |--- FSYS + |--- FSYS2 + +- In case of Exynos5433, there is VDD_INT power line as following: + VDD_INT |--- G2D (parent device) + |--- MSCL + |--- GSCL + |--- JPEG + |--- MFC + |--- HEVC + |--- BUS0 + |--- BUS1 + |--- BUS2 + |--- PERIS (Fixed clock rate) + |--- PERIC (Fixed clock rate) + |--- FSYS (Fixed clock rate) + +Example1: + Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to + power line (regulator). The MIF (Memory Interface) AXI bus is used to + transfer data between DRAM and CPU and uses the VDD_MIF regulator. + + - MIF (Memory Interface) block + : VDD_MIF |--- DMC (Dynamic Memory Controller) + + - INT (Internal) block + : VDD_INT |--- LEFTBUS (parent device) + |--- PERIL + |--- MFC + |--- G3D + |--- RIGHTBUS + |--- FSYS + |--- LCD0 + |--- PERIR + |--- ISP + |--- CAM + + - MIF bus's frequency/voltage table + ----------------------- + |Lv| Freq | Voltage | + ----------------------- + |L1| 50000 |800000 | + |L2| 100000 |800000 | + |L3| 134000 |800000 | + |L4| 200000 |825000 | + |L5| 400000 |875000 | + ----------------------- + + - INT bus's frequency/voltage table + ---------------------------------------------------------- + |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP |PERIL ||VDD_INT | + | name| |LCD0 | | | || | + | | |FSYS | | | || | + | | |MFC | | | || | + ---------------------------------------------------------- + |Mode |*parent|passive |passive|passive|passive|| | + ---------------------------------------------------------- + |Lv |Frequency ||Voltage | + ---------------------------------------------------------- + |L1 |50000 |50000 |50000 |50000 |50000 ||900000 | + |L2 |80000 |80000 |80000 |80000 |80000 ||900000 | + |L3 |100000 |100000 |100000 |100000 |100000 ||1000000 | + |L4 |134000 |134000 |200000 |200000 | ||1000000 | + |L5 |200000 |200000 |400000 |300000 | ||1000000 | + ---------------------------------------------------------- + +Example2 : + The bus of DMC (Dynamic Memory Controller) block in exynos3250.dtsi + is listed below: + + bus_dmc: bus_dmc { + compatible = "samsung,exynos-bus"; + clocks = <&cmu_dmc CLK_DIV_DMC>; + clock-names = "bus"; + operating-points-v2 = <&bus_dmc_opp_table>; + status = "disabled"; + }; + + bus_dmc_opp_table: opp_table1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + opp-microvolt = <800000>; + }; + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <800000>; + }; + opp-134000000 { + opp-hz = /bits/ 64 <134000000>; + opp-microvolt = <800000>; + }; + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <825000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <875000>; + }; + }; + + bus_leftbus: bus_leftbus { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_GDL>; + clock-names = "bus"; + operating-points-v2 = <&bus_leftbus_opp_table>; + status = "disabled"; + }; + + bus_rightbus: bus_rightbus { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_GDR>; + clock-names = "bus"; + operating-points-v2 = <&bus_leftbus_opp_table>; + status = "disabled"; + }; + + bus_lcd0: bus_lcd0 { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_ACLK_160>; + clock-names = "bus"; + operating-points-v2 = <&bus_leftbus_opp_table>; + status = "disabled"; + }; + + bus_fsys: bus_fsys { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_ACLK_200>; + clock-names = "bus"; + operating-points-v2 = <&bus_leftbus_opp_table>; + status = "disabled"; + }; + + bus_mcuisp: bus_mcuisp { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_ACLK_400_MCUISP>; + clock-names = "bus"; + operating-points-v2 = <&bus_mcuisp_opp_table>; + status = "disabled"; + }; + + bus_isp: bus_isp { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_ACLK_266>; + clock-names = "bus"; + operating-points-v2 = <&bus_isp_opp_table>; + status = "disabled"; + }; + + bus_peril: bus_peril { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_DIV_ACLK_100>; + clock-names = "bus"; + operating-points-v2 = <&bus_peril_opp_table>; + status = "disabled"; + }; + + bus_mfc: bus_mfc { + compatible = "samsung,exynos-bus"; + clocks = <&cmu CLK_SCLK_MFC>; + clock-names = "bus"; + operating-points-v2 = <&bus_leftbus_opp_table>; + status = "disabled"; + }; + + bus_leftbus_opp_table: opp_table1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + opp-microvolt = <900000>; + }; + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + opp-microvolt = <900000>; + }; + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <1000000>; + }; + opp-134000000 { + opp-hz = /bits/ 64 <134000000>; + opp-microvolt = <1000000>; + }; + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <1000000>; + }; + }; + + bus_mcuisp_opp_table: opp_table2 { + compatible = "operating-points-v2"; + opp-shared; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + }; + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + }; + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + }; + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + }; + }; + + bus_isp_opp_table: opp_table3 { + compatible = "operating-points-v2"; + opp-shared; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + }; + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + }; + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + }; + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + }; + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + }; + }; + + bus_peril_opp_table: opp_table4 { + compatible = "operating-points-v2"; + opp-shared; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + }; + opp-80000000 { + opp-hz = /bits/ 64 <80000000>; + }; + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + }; + }; + + + Usage case to handle the frequency and voltage of bus on runtime + in exynos3250-rinato.dts is listed below: + + &bus_dmc { + devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>; + vdd-supply = <&buck1_reg>; /* VDD_MIF */ + status = "okay"; + }; + + &bus_leftbus { + devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>; + vdd-supply = <&buck3_reg>; + status = "okay"; + }; + + &bus_rightbus { + devfreq = <&bus_leftbus>; + status = "okay"; + }; + + &bus_lcd0 { + devfreq = <&bus_leftbus>; + status = "okay"; + }; + + &bus_fsys { + devfreq = <&bus_leftbus>; + status = "okay"; + }; + + &bus_mcuisp { + devfreq = <&bus_leftbus>; + status = "okay"; + }; + + &bus_isp { + devfreq = <&bus_leftbus>; + status = "okay"; + }; + + &bus_peril { + devfreq = <&bus_leftbus>; + status = "okay"; + }; + + &bus_mfc { + devfreq = <&bus_leftbus>; + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/rk3399_dmc.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/rk3399_dmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ec68141f85a7c05aa04b10c277b3ad02af43942 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/rk3399_dmc.txt @@ -0,0 +1,213 @@ +* Rockchip rk3399 DMC (Dynamic Memory Controller) device + +Required properties: +- compatible: Must be "rockchip,rk3399-dmc". +- devfreq-events: Node to get DDR loading, Refer to + Documentation/devicetree/bindings/devfreq/event/ + rockchip-dfi.txt +- clocks: Phandles for clock specified in "clock-names" property +- clock-names : The name of clock used by the DFI, must be + "pclk_ddr_mon"; +- operating-points-v2: Refer to Documentation/devicetree/bindings/opp/opp.txt + for details. +- center-supply: DMC supply node. +- status: Marks the node enabled/disabled. + +Optional properties: +- interrupts: The CPU interrupt number. The interrupt specifier + format depends on the interrupt controller. + It should be a DCF interrupt. When DDR DVFS finishes + a DCF interrupt is triggered. + +Following properties relate to DDR timing: + +- rockchip,dram_speed_bin : Value reference include/dt-bindings/clock/rk3399-ddr.h, + it selects the DDR3 cl-trp-trcd type. It must be + set according to "Speed Bin" in DDR3 datasheet, + DO NOT use a smaller "Speed Bin" than specified + for the DDR3 being used. + +- rockchip,pd_idle : Configure the PD_IDLE value. Defines the + power-down idle period in which memories are + placed into power-down mode if bus is idle + for PD_IDLE DFI clock cycles. + +- rockchip,sr_idle : Configure the SR_IDLE value. Defines the + self-refresh idle period in which memories are + placed into self-refresh mode if bus is idle + for SR_IDLE * 1024 DFI clock cycles (DFI + clocks freq is half of DRAM clock), default + value is "0". + +- rockchip,sr_mc_gate_idle : Defines the memory self-refresh and controller + clock gating idle period. Memories are placed + into self-refresh mode and memory controller + clock arg gating started if bus is idle for + sr_mc_gate_idle*1024 DFI clock cycles. + +- rockchip,srpd_lite_idle : Defines the self-refresh power down idle + period in which memories are placed into + self-refresh power down mode if bus is idle + for srpd_lite_idle * 1024 DFI clock cycles. + This parameter is for LPDDR4 only. + +- rockchip,standby_idle : Defines the standby idle period in which + memories are placed into self-refresh mode. + The controller, pi, PHY and DRAM clock will + be gated if bus is idle for standby_idle * DFI + clock cycles. + +- rockchip,dram_dll_dis_freq : Defines the DDR3 DLL bypass frequency in MHz. + When DDR frequency is less than DRAM_DLL_DISB_FREQ, + DDR3 DLL will be bypassed. Note: if DLL was bypassed, + the odt will also stop working. + +- rockchip,phy_dll_dis_freq : Defines the PHY dll bypass frequency in + MHz (Mega Hz). When DDR frequency is less than + DRAM_DLL_DISB_FREQ, PHY DLL will be bypassed. + Note: PHY DLL and PHY ODT are independent. + +- rockchip,ddr3_odt_dis_freq : When the DRAM type is DDR3, this parameter defines + the ODT disable frequency in MHz (Mega Hz). + when the DDR frequency is less then ddr3_odt_dis_freq, + the ODT on the DRAM side and controller side are + both disabled. + +- rockchip,ddr3_drv : When the DRAM type is DDR3, this parameter defines + the DRAM side driver strength in ohms. Default + value is DDR3_DS_40ohm. + +- rockchip,ddr3_odt : When the DRAM type is DDR3, this parameter defines + the DRAM side ODT strength in ohms. Default value + is DDR3_ODT_120ohm. + +- rockchip,phy_ddr3_ca_drv : When the DRAM type is DDR3, this parameter defines + the phy side CA line (incluing command line, + address line and clock line) driver strength. + Default value is PHY_DRV_ODT_40. + +- rockchip,phy_ddr3_dq_drv : When the DRAM type is DDR3, this parameter defines + the PHY side DQ line (including DQS/DQ/DM line) + driver strength. Default value is PHY_DRV_ODT_40. + +- rockchip,phy_ddr3_odt : When the DRAM type is DDR3, this parameter defines + the PHY side ODT strength. Default value is + PHY_DRV_ODT_240. + +- rockchip,lpddr3_odt_dis_freq : When the DRAM type is LPDDR3, this parameter defines + then ODT disable frequency in MHz (Mega Hz). + When DDR frequency is less then ddr3_odt_dis_freq, + the ODT on the DRAM side and controller side are + both disabled. + +- rockchip,lpddr3_drv : When the DRAM type is LPDDR3, this parameter defines + the DRAM side driver strength in ohms. Default + value is LP3_DS_34ohm. + +- rockchip,lpddr3_odt : When the DRAM type is LPDDR3, this parameter defines + the DRAM side ODT strength in ohms. Default value + is LP3_ODT_240ohm. + +- rockchip,phy_lpddr3_ca_drv : When the DRAM type is LPDDR3, this parameter defines + the PHY side CA line (including command line, + address line and clock line) driver strength. + Default value is PHY_DRV_ODT_40. + +- rockchip,phy_lpddr3_dq_drv : When the DRAM type is LPDDR3, this parameter defines + the PHY side DQ line (including DQS/DQ/DM line) + driver strength. Default value is + PHY_DRV_ODT_40. + +- rockchip,phy_lpddr3_odt : When dram type is LPDDR3, this parameter define + the phy side odt strength, default value is + PHY_DRV_ODT_240. + +- rockchip,lpddr4_odt_dis_freq : When the DRAM type is LPDDR4, this parameter + defines the ODT disable frequency in + MHz (Mega Hz). When the DDR frequency is less then + ddr3_odt_dis_freq, the ODT on the DRAM side and + controller side are both disabled. + +- rockchip,lpddr4_drv : When the DRAM type is LPDDR4, this parameter defines + the DRAM side driver strength in ohms. Default + value is LP4_PDDS_60ohm. + +- rockchip,lpddr4_dq_odt : When the DRAM type is LPDDR4, this parameter defines + the DRAM side ODT on DQS/DQ line strength in ohms. + Default value is LP4_DQ_ODT_40ohm. + +- rockchip,lpddr4_ca_odt : When the DRAM type is LPDDR4, this parameter defines + the DRAM side ODT on CA line strength in ohms. + Default value is LP4_CA_ODT_40ohm. + +- rockchip,phy_lpddr4_ca_drv : When the DRAM type is LPDDR4, this parameter defines + the PHY side CA line (including command address + line) driver strength. Default value is + PHY_DRV_ODT_40. + +- rockchip,phy_lpddr4_ck_cs_drv : When the DRAM type is LPDDR4, this parameter defines + the PHY side clock line and CS line driver + strength. Default value is PHY_DRV_ODT_80. + +- rockchip,phy_lpddr4_dq_drv : When the DRAM type is LPDDR4, this parameter defines + the PHY side DQ line (including DQS/DQ/DM line) + driver strength. Default value is PHY_DRV_ODT_80. + +- rockchip,phy_lpddr4_odt : When the DRAM type is LPDDR4, this parameter defines + the PHY side ODT strength. Default value is + PHY_DRV_ODT_60. + +Example: + dmc_opp_table: dmc_opp_table { + compatible = "operating-points-v2"; + + opp00 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <900000>; + }; + opp01 { + opp-hz = /bits/ 64 <666000000>; + opp-microvolt = <900000>; + }; + }; + + dmc: dmc { + compatible = "rockchip,rk3399-dmc"; + devfreq-events = <&dfi>; + interrupts = ; + clocks = <&cru SCLK_DDRCLK>; + clock-names = "dmc_clk"; + operating-points-v2 = <&dmc_opp_table>; + center-supply = <&ppvar_centerlogic>; + upthreshold = <15>; + downdifferential = <10>; + rockchip,ddr3_speed_bin = <21>; + rockchip,pd_idle = <0x40>; + rockchip,sr_idle = <0x2>; + rockchip,sr_mc_gate_idle = <0x3>; + rockchip,srpd_lite_idle = <0x4>; + rockchip,standby_idle = <0x2000>; + rockchip,dram_dll_dis_freq = <300>; + rockchip,phy_dll_dis_freq = <125>; + rockchip,auto_pd_dis_freq = <666>; + rockchip,ddr3_odt_dis_freq = <333>; + rockchip,ddr3_drv = ; + rockchip,ddr3_odt = ; + rockchip,phy_ddr3_ca_drv = ; + rockchip,phy_ddr3_dq_drv = ; + rockchip,phy_ddr3_odt = ; + rockchip,lpddr3_odt_dis_freq = <333>; + rockchip,lpddr3_drv = ; + rockchip,lpddr3_odt = ; + rockchip,phy_lpddr3_ca_drv = ; + rockchip,phy_lpddr3_dq_drv = ; + rockchip,phy_lpddr3_odt = ; + rockchip,lpddr4_odt_dis_freq = <333>; + rockchip,lpddr4_drv = ; + rockchip,lpddr4_dq_odt = ; + rockchip,lpddr4_ca_odt = ; + rockchip,phy_lpddr4_ca_drv = ; + rockchip,phy_lpddr4_ck_cs_drv = ; + rockchip,phy_lpddr4_dq_drv = ; + rockchip,phy_lpddr4_odt = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/devfreq/staticmap_gov.txt b/arch/arm64/boot/dts/vendor/bindings/devfreq/staticmap_gov.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef43ef91e7c767feca35bdf2c8882d5c38b1fc07 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/devfreq/staticmap_gov.txt @@ -0,0 +1,30 @@ +MSM Static Map governor + +static map governor is a device that registers with a clock notifier +of the master port and votes for the slave port using the core-dev freq +mapping table. The idea behind the governor is to match the voltage corners +of the master and slave ports when voting for the bandwidth. + +Required properties: +- compatible: Must be "qcom,static-map" +- clocks: The phandles for clock specified in "clock-names" property +- clock-names: Names of the clocks for registering a notifier +- qcom,dev-clk: Names of the clocks for registering a notifier +- qcom,target-dev: The DT device that corresponds to this master port +- qcom,core-dev-table: A mapping table of core frequency to a required + bandwidth vote at the given core frequency. +Example: + npu_staticmap_mon: qcom,npu-staticmap-mon { + compatible = "qcom,static-map"; + qcom,target-dev = <&npu_ddr_static>; + clocks = <&clock_npucc NPU_CC_CAL_HM0_CLK>; + clock-names = "cal_hm0_clk"; + qcom,dev_clk = "cal_hm0_clk"; + qcom,core-dev-table = + < 0 MHZ_TO_MBPS( 0, 4) >, + < 200000 MHZ_TO_MBPS( 451, 4) >, + < 466000 MHZ_TO_MBPS( 768, 4) >, + < 533000 MHZ_TO_MBPS( 1017, 4) >, + < 850000 MHZ_TO_MBPS( 1555, 4) >, + < 1000000 MHZ_TO_MBPS( 2736, 4) >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/amlogic,meson-dw-hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/amlogic,meson-dw-hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf4a18047309a5f806bff4f8d5bf72459cf347c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/amlogic,meson-dw-hdmi.txt @@ -0,0 +1,115 @@ +Amlogic specific extensions to the Synopsys Designware HDMI Controller +====================================================================== + +The Amlogic Meson Synopsys Designware Integration is composed of : +- A Synopsys DesignWare HDMI Controller IP +- A TOP control block controlling the Clocks and PHY +- A custom HDMI PHY in order to convert video to TMDS signal + ___________________________________ +| HDMI TOP |<= HPD +|___________________________________| +| | | +| Synopsys HDMI | HDMI PHY |=> TMDS +| Controller |________________| +|___________________________________|<=> DDC + +The HDMI TOP block only supports HPD sensing. +The Synopsys HDMI Controller interrupt is routed through the +TOP Block interrupt. +Communication to the TOP Block and the Synopsys HDMI Controller is done +via a pair of dedicated addr+read/write registers. +The HDMI PHY is configured by registers in the HHI register block. + +Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux +selects either the ENCI encoder for the 576i or 480i formats or the ENCP +encoder for all the other formats including interlaced HD formats. + +The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate +DVI timings for the HDMI controller. + +Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare +HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF +audio source interfaces. + +Required properties: +- compatible: value should be different for each SoC family as : + - GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi" + - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" + - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" + followed by the common "amlogic,meson-gx-dw-hdmi" +- reg: Physical base address and length of the controller's registers. +- interrupts: The HDMI interrupt number +- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, + and the Amlogic Meson venci clocks as described in + Documentation/devicetree/bindings/clock/clock-bindings.txt, + the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci" +- resets, resets-names: must have the phandles to the HDMI apb, glue and phy + resets as described in : + Documentation/devicetree/bindings/reset/reset.txt, + the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy" + +Optional properties: +- hdmi-supply: Optional phandle to an external 5V regulator to power the HDMI + logic, as described in the file ../regulator/regulator.txt + +Required nodes: + +The connections to the HDMI ports are modeled using the OF graph +bindings specified in Documentation/devicetree/bindings/graph.txt. + +The following table lists for each supported model the port number +corresponding to each HDMI output and input. + + Port 0 Port 1 +----------------------------------------- + S905 (GXBB) VENC Input TMDS Output + S905X (GXL) VENC Input TMDS Output + S905D (GXL) VENC Input TMDS Output + S912 (GXM) VENC Input TMDS Output + +Example: + +hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; +}; + +hdmi_tx: hdmi-tx@c883a000 { + compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi"; + reg = <0x0 0xc883a000 0x0 0x1c>; + interrupts = ; + resets = <&reset RESET_HDMITX_CAPB3>, + <&reset RESET_HDMI_SYSTEM_RESET>, + <&reset RESET_HDMI_TX>; + reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; + clocks = <&clkc CLKID_HDMI_PCLK>, + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + hdmi_tx_venc_port: port@0 { + reg = <0>; + + hdmi_tx_in: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + + /* TMDS Output */ + hdmi_tx_tmds_port: port@1 { + reg = <1>; + + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/amlogic,meson-vpu.txt b/arch/arm64/boot/dts/vendor/bindings/display/amlogic,meson-vpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..057b81335775e7526805710324eb497fe7c04bcb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/amlogic,meson-vpu.txt @@ -0,0 +1,116 @@ +Amlogic Meson Display Controller +================================ + +The Amlogic Meson Display controller is composed of several components +that are going to be documented below: + +DMC|---------------VPU (Video Processing Unit)----------------|------HHI------| + | vd1 _______ _____________ _________________ | | +D |-------| |----| | | | | HDMI PLL | +D | vd2 | VIU | | Video Post | | Video Encoders |<---|-----VCLK | +R |-------| |----| Processing | | | | | + | osd2 | | | |---| Enci ----------|----|-----VDAC------| +R |-------| CSC |----| Scalers | | Encp ----------|----|----HDMI-TX----| +A | osd1 | | | Blenders | | Encl ----------|----|---------------| +M |-------|______|----|____________| |________________| | | +___|__________________________________________________________|_______________| + + +VIU: Video Input Unit +--------------------- + +The Video Input Unit is in charge of the pixel scanout from the DDR memory. +It fetches the frames addresses, stride and parameters from the "Canvas" memory. +This part is also in charge of the CSC (Colorspace Conversion). +It can handle 2 OSD Planes and 2 Video Planes. + +VPP: Video Post Processing +-------------------------- + +The Video Post Processing is in charge of the scaling and blending of the +various planes into a single pixel stream. +There is a special "pre-blending" used by the video planes with a dedicated +scaler and a "post-blending" to merge with the OSD Planes. +The OSD planes also have a dedicated scaler for one of the OSD. + +VENC: Video Encoders +-------------------- + +The VENC is composed of the multiple pixel encoders : + - ENCI : Interlace Video encoder for CVBS and Interlace HDMI + - ENCP : Progressive Video Encoder for HDMI + - ENCL : LCD LVDS Encoder +The VENC Unit gets a Pixel Clocks (VCLK) from a dedicated HDMI PLL and clock +tree and provides the scanout clock to the VPP and VIU. +The ENCI is connected to a single VDAC for Composite Output. +The ENCI and ENCP are connected to an on-chip HDMI Transceiver. + +Device Tree Bindings: +--------------------- + +VPU: Video Processing Unit +-------------------------- + +Required properties: +- compatible: value should be different for each SoC family as : + - GXBB (S905) : "amlogic,meson-gxbb-vpu" + - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" + - GXM (S912) : "amlogic,meson-gxm-vpu" + followed by the common "amlogic,meson-gx-vpu" +- reg: base address and size of he following memory-mapped regions : + - vpu + - hhi + - dmc +- reg-names: should contain the names of the previous memory regions +- interrupts: should contain the VENC Vsync interrupt number + +Optional properties: +- power-domains: Optional phandle to associated power domain as described in + the file ../power/power_domain.txt + +Required nodes: + +The connections to the VPU output video ports are modeled using the OF graph +bindings specified in Documentation/devicetree/bindings/graph.txt. + +The following table lists for each supported model the port number +corresponding to each VPU output. + + Port 0 Port 1 +----------------------------------------- + S905 (GXBB) CVBS VDAC HDMI-TX + S905X (GXL) CVBS VDAC HDMI-TX + S905D (GXL) CVBS VDAC HDMI-TX + S912 (GXM) CVBS VDAC HDMI-TX + +Example: + +tv-connector { + compatible = "composite-video-connector"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&cvbs_vdac_out>; + }; + }; +}; + +vpu: vpu@d0100000 { + compatible = "amlogic,meson-gxbb-vpu"; + reg = <0x0 0xd0100000 0x0 0x100000>, + <0x0 0xc883c000 0x0 0x1000>, + <0x0 0xc8838000 0x0 0x1000>; + reg-names = "vpu", "hhi", "dmc"; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + + /* CVBS VDAC output port */ + port@0 { + reg = <0>; + + cvbs_vdac_out: endpoint { + remote-endpoint = <&tv_connector_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/arm,hdlcd.txt b/arch/arm64/boot/dts/vendor/bindings/display/arm,hdlcd.txt new file mode 100644 index 0000000000000000000000000000000000000000..78bc24296f3e477770decb7e9af40cf5d59c88d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/arm,hdlcd.txt @@ -0,0 +1,79 @@ +ARM HDLCD + +This is a display controller found on several development platforms produced +by ARM Ltd and in more modern of its' Fast Models. The HDLCD is an RGB +streamer that reads the data from a framebuffer and sends it to a single +digital encoder (DVI or HDMI). + +Required properties: + - compatible: "arm,hdlcd" + - reg: Physical base address and length of the controller's registers. + - interrupts: One interrupt used by the display controller to notify the + interrupt controller when any of the interrupt sources programmed in + the interrupt mask register have activated. + - clocks: A list of phandle + clock-specifier pairs, one for each + entry in 'clock-names'. + - clock-names: A list of clock names. For HDLCD it should contain: + - "pxlclk" for the clock feeding the output PLL of the controller. + +Required sub-nodes: + - port: The HDLCD connection to an encoder chip. The connection is modeled + using the OF graph bindings specified in + Documentation/devicetree/bindings/graph.txt. + +Optional properties: + - memory-region: phandle to a node describing memory (see + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) to be + used for the framebuffer; if not present, the framebuffer may be located + anywhere in memory. + + +Example: + +/ { + ... + + hdlcd@2b000000 { + compatible = "arm,hdlcd"; + reg = <0 0x2b000000 0 0x1000>; + interrupts = ; + clocks = <&oscclk5>; + clock-names = "pxlclk"; + port { + hdlcd_output: endpoint@0 { + remote-endpoint = <&hdmi_enc_input>; + }; + }; + }; + + /* HDMI encoder on I2C bus */ + i2c@7ffa0000 { + .... + hdmi-transmitter@70 { + compatible = "....."; + reg = <0x70>; + port@0 { + hdmi_enc_input: endpoint { + remote-endpoint = <&hdlcd_output>; + }; + + hdmi_enc_output: endpoint { + remote-endpoint = <&hdmi_1_port>; + }; + }; + }; + + }; + + hdmi1: connector@1 { + compatible = "hdmi-connector"; + type = "a"; + port { + hdmi_1_port: endpoint { + remote-endpoint = <&hdmi_enc_output>; + }; + }; + }; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/arm,malidp.txt b/arch/arm64/boot/dts/vendor/bindings/display/arm,malidp.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f7870983ef1842c6e4658b612be2fa64c0f3844 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/arm,malidp.txt @@ -0,0 +1,65 @@ +ARM Mali-DP + +The following bindings apply to a family of Display Processors sold as +licensable IP by ARM Ltd. The bindings describe the Mali DP500, DP550 and +DP650 processors that offer multiple composition layers, support for +rotation and scaling output. + +Required properties: + - compatible: should be one of + "arm,mali-dp500" + "arm,mali-dp550" + "arm,mali-dp650" + depending on the particular implementation present in the hardware + - reg: Physical base address and size of the block of registers used by + the processor. + - interrupts: Interrupt list, as defined in ../interrupt-controller/interrupts.txt, + interrupt client nodes. + - interrupt-names: name of the engine inside the processor that will + use the corresponding interrupt. Should be one of "DE" or "SE". + - clocks: A list of phandle + clock-specifier pairs, one for each entry + in 'clock-names' + - clock-names: A list of clock names. It should contain: + - "pclk": for the APB interface clock + - "aclk": for the AXI interface clock + - "mclk": for the main processor clock + - "pxlclk": for the pixel clock feeding the output PLL of the processor. + - arm,malidp-output-port-lines: Array of u8 values describing the number + of output lines per channel (R, G and B). + +Required sub-nodes: + - port: The Mali DP connection to an encoder input port. The connection + is modelled using the OF graph bindings specified in + Documentation/devicetree/bindings/graph.txt + +Optional properties: + - memory-region: phandle to a node describing memory (see + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) + to be used for the framebuffer; if not present, the framebuffer may + be located anywhere in memory. + + +Example: + +/ { + ... + + dp0: malidp@6f200000 { + compatible = "arm,mali-dp650"; + reg = <0 0x6f200000 0 0x20000>; + memory-region = <&display_reserved>; + interrupts = <0 168 IRQ_TYPE_LEVEL_HIGH>, + <0 168 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "DE", "SE"; + clocks = <&oscclk2>, <&fpgaosc0>, <&fpgaosc1>, <&fpgaosc1>; + clock-names = "pxlclk", "mclk", "aclk", "pclk"; + arm,malidp-output-port-lines = /bits/ 8 <8 8 8>; + port { + dp0_output: endpoint { + remote-endpoint = <&tda998x_2_input>; + }; + }; + }; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/arm,pl11x.txt b/arch/arm64/boot/dts/vendor/bindings/display/arm,pl11x.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef89ab46b2c933945b86197aa1031ecbbfc3b6c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/arm,pl11x.txt @@ -0,0 +1,109 @@ +* ARM PrimeCell Color LCD Controller PL110/PL111 + +See also Documentation/devicetree/bindings/arm/primecell.txt + +Required properties: + +- compatible: must be one of: + "arm,pl110", "arm,primecell" + "arm,pl111", "arm,primecell" + +- reg: base address and size of the control registers block + +- interrupt-names: either the single entry "combined" representing a + combined interrupt output (CLCDINTR), or the four entries + "mbe", "vcomp", "lnbu", "fuf" representing the individual + CLCDMBEINTR, CLCDVCOMPINTR, CLCDLNBUINTR, CLCDFUFINTR interrupts + +- interrupts: contains an interrupt specifier for each entry in + interrupt-names + +- clock-names: should contain "clcdclk" and "apb_pclk" + +- clocks: contains phandle and clock specifier pairs for the entries + in the clock-names property. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Optional properties: + +- memory-region: phandle to a node describing memory (see + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) + to be used for the framebuffer; if not present, the framebuffer + may be located anywhere in the memory + +- max-memory-bandwidth: maximum bandwidth in bytes per second that the + cell's memory interface can handle; if not present, the memory + interface is fast enough to handle all possible video modes + +Required sub-nodes: + +- port: describes LCD panel signals, following the common binding + for video transmitter interfaces; see + Documentation/devicetree/bindings/media/video-interfaces.txt; + when it is a TFT panel, the port's endpoint must define the + following property: + + - arm,pl11x,tft-r0g0b0-pads: an array of three 32-bit values, + defining the way CLD pads are wired up; first value + contains index of the "CLD" external pin (pad) used + as R0 (first bit of the red component), second value + index of the pad used as G0, third value index of the + pad used as B0, see also "LCD panel signal multiplexing + details" paragraphs in the PL110/PL111 Technical + Reference Manuals; this implicitly defines available + color modes, for example: + - PL111 TFT 4:4:4 panel: + arm,pl11x,tft-r0g0b0-pads = <4 15 20>; + - PL110 TFT (1:)5:5:5 panel: + arm,pl11x,tft-r0g0b0-pads = <1 7 13>; + - PL111 TFT (1:)5:5:5 panel: + arm,pl11x,tft-r0g0b0-pads = <3 11 19>; + - PL111 TFT 5:6:5 panel: + arm,pl11x,tft-r0g0b0-pads = <3 10 19>; + - PL110 and PL111 TFT 8:8:8 panel: + arm,pl11x,tft-r0g0b0-pads = <0 8 16>; + - PL110 and PL111 TFT 8:8:8 panel, R & B components swapped: + arm,pl11x,tft-r0g0b0-pads = <16 8 0>; + + +Example: + + clcd@10020000 { + compatible = "arm,pl111", "arm,primecell"; + reg = <0x10020000 0x1000>; + interrupt-names = "combined"; + interrupts = <0 44 4>; + clocks = <&oscclk1>, <&oscclk2>; + clock-names = "clcdclk", "apb_pclk"; + max-memory-bandwidth = <94371840>; /* Bps, 1024x768@60 16bpp */ + + port { + clcd_pads: endpoint { + remote-endpoint = <&clcd_panel>; + arm,pl11x,tft-r0g0b0-pads = <0 8 16>; + }; + }; + + }; + + panel { + compatible = "panel-dpi"; + + port { + clcd_panel: endpoint { + remote-endpoint = <&clcd_pads>; + }; + }; + + panel-timing { + clock-frequency = <25175000>; + hactive = <640>; + hback-porch = <40>; + hfront-porch = <24>; + hsync-len = <96>; + vactive = <480>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/armada/marvell,dove-lcd.txt b/arch/arm64/boot/dts/vendor/bindings/display/armada/marvell,dove-lcd.txt new file mode 100644 index 0000000000000000000000000000000000000000..46525ea3e646e9b1dc1d0005283f0464817699d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/armada/marvell,dove-lcd.txt @@ -0,0 +1,30 @@ +Device Tree bindings for Armada DRM CRTC driver + +Required properties: + - compatible: value should be "marvell,dove-lcd". + - reg: base address and size of the LCD controller + - interrupts: single interrupt number for the LCD controller + - port: video output port with endpoints, as described by graph.txt + +Optional properties: + + - clocks: as described by clock-bindings.txt + - clock-names: as described by clock-bindings.txt + "axiclk" - axi bus clock for pixel clock + "plldivider" - pll divider clock for pixel clock + "ext_ref_clk0" - external clock 0 for pixel clock + "ext_ref_clk1" - external clock 1 for pixel clock + +Note: all clocks are optional but at least one must be specified. +Further clocks may be added in the future according to requirements of +different SoCs. + +Example: + + lcd0: lcd-controller@820000 { + compatible = "marvell,dove-lcd"; + reg = <0x820000 0x1000>; + interrupts = <47>; + clocks = <&si5351 0>; + clock-names = "ext_ref_clk_1"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/atmel,lcdc.txt b/arch/arm64/boot/dts/vendor/bindings/display/atmel,lcdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..acb5a01321279e13d0c0c2780be8018b330152d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/atmel,lcdc.txt @@ -0,0 +1,88 @@ +Atmel LCDC Framebuffer +----------------------------------------------------- + +Required properties: +- compatible : + "atmel,at91sam9261-lcdc" , + "atmel,at91sam9263-lcdc" , + "atmel,at91sam9g10-lcdc" , + "atmel,at91sam9g45-lcdc" , + "atmel,at91sam9g45es-lcdc" , + "atmel,at91sam9rl-lcdc" , + "atmel,at32ap-lcdc" +- reg : Should contain 1 register ranges(address and length). + Can contain an additional register range(address and length) + for fixed framebuffer memory. Useful for dedicated memories. +- interrupts : framebuffer controller interrupt +- display: a phandle pointing to the display node + +Required nodes: +- display: a display node is required to initialize the lcd panel + This should be in the board dts. +- default-mode: a videomode within the display with timing parameters + as specified below. + +Optional properties: +- lcd-supply: Regulator for LCD supply voltage. + +Example: + + fb0: fb@00500000 { + compatible = "atmel,at91sam9g45-lcdc"; + reg = <0x00500000 0x1000>; + interrupts = <23 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fb>; + display = <&display0>; + #address-cells = <1>; + #size-cells = <1>; + + }; + +Example for fixed framebuffer memory: + + fb0: fb@00500000 { + compatible = "atmel,at91sam9263-lcdc"; + reg = <0x00700000 0x1000 0x70000000 0x200000>; + [...] + }; + +Atmel LCDC Display +----------------------------------------------------- +Required properties (as per of_videomode_helper): + + - atmel,dmacon: dma controller configuration + - atmel,lcdcon2: lcd controller configuration + - atmel,guard-time: lcd guard time (Delay in frame periods) + - bits-per-pixel: lcd panel bit-depth. + +Optional properties (as per of_videomode_helper): + - atmel,lcdcon-backlight: enable backlight + - atmel,lcdcon-backlight-inverted: invert backlight PWM polarity + - atmel,lcd-wiring-mode: lcd wiring mode "RGB" or "BRG" + - atmel,power-control-gpio: gpio to power on or off the LCD (as many as needed) + +Example: + display0: display { + bits-per-pixel = <32>; + atmel,lcdcon-backlight; + atmel,dmacon = <0x1>; + atmel,lcdcon2 = <0x80008002>; + atmel,guard-time = <9>; + atmel,lcd-wiring-mode = <1>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <9000000>; + hactive = <480>; + vactive = <272>; + hback-porch = <1>; + hfront-porch = <1>; + vback-porch = <40>; + vfront-porch = <1>; + hsync-len = <45>; + vsync-len = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/atmel/hlcdc-dc.txt b/arch/arm64/boot/dts/vendor/bindings/display/atmel/hlcdc-dc.txt new file mode 100644 index 0000000000000000000000000000000000000000..82f2acb3d37406d0916b2a202d3d28cc64c5fc06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/atmel/hlcdc-dc.txt @@ -0,0 +1,52 @@ +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver + +The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device. +See ../../mfd/atmel-hlcdc.txt for more details. + +Required properties: + - compatible: value should be "atmel,hlcdc-display-controller" + - pinctrl-names: the pin control state names. Should contain "default". + - pinctrl-0: should contain the default pinctrl states. + - #address-cells: should be set to 1. + - #size-cells: should be set to 0. + +Required children nodes: + Children nodes are encoding available output ports and their connections + to external devices using the OF graph reprensentation (see ../graph.txt). + At least one port node is required. + +Example: + + hlcdc: hlcdc@f0030000 { + compatible = "atmel,sama5d3-hlcdc"; + reg = <0xf0030000 0x2000>; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + + hlcdc-display-controller { + compatible = "atmel,hlcdc-display-controller"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/brcm,bcm-vc4.txt b/arch/arm64/boot/dts/vendor/bindings/display/brcm,bcm-vc4.txt new file mode 100644 index 0000000000000000000000000000000000000000..26649b4c4dd8de41ab16a6f76f8e73dcac2525a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/brcm,bcm-vc4.txt @@ -0,0 +1,174 @@ +Broadcom VC4 (VideoCore4) GPU + +The VC4 device present on the Raspberry Pi includes a display system +with HDMI output and the HVS (Hardware Video Scaler) for compositing +display planes. + +Required properties for VC4: +- compatible: Should be "brcm,bcm2835-vc4" or "brcm,cygnus-vc4" + +Required properties for Pixel Valve: +- compatible: Should be one of "brcm,bcm2835-pixelvalve0", + "brcm,bcm2835-pixelvalve1", or "brcm,bcm2835-pixelvalve2" +- reg: Physical base address and length of the PV's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +Required properties for HVS: +- compatible: Should be "brcm,bcm2835-hvs" +- reg: Physical base address and length of the HVS's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +Required properties for HDMI +- compatible: Should be "brcm,bcm2835-hdmi" +- reg: Physical base address and length of the two register ranges + ("HDMI" and "HD", in that order) +- interrupts: The interrupt numbers + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- ddc: phandle of the I2C controller used for DDC EDID probing +- clocks: a) hdmi: The HDMI state machine clock + b) pixel: The pixel clock. + +Optional properties for HDMI: +- hpd-gpios: The GPIO pin for HDMI hotplug detect (if it doesn't appear + as an interrupt/status bit in the HDMI controller + itself). See bindings/pinctrl/brcm,bcm2835-gpio.txt +- dmas: Should contain one entry pointing to the DMA channel used to + transfer audio data +- dma-names: Should contain "audio-rx" + +Required properties for DPI: +- compatible: Should be "brcm,bcm2835-dpi" +- reg: Physical base address and length of the registers +- clocks: a) core: The core clock the unit runs on + b) pixel: The pixel clock that feeds the pixelvalve +- port: Port node with a single endpoint connecting to the panel + device, as defined in [1] + +Required properties for VEC: +- compatible: Should be "brcm,bcm2835-vec" +- reg: Physical base address and length of the registers +- clocks: The core clock the unit runs on +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +Required properties for V3D: +- compatible: Should be "brcm,bcm2835-v3d" or "brcm,cygnus-v3d" +- reg: Physical base address and length of the V3D's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +Optional properties for V3D: +- clocks: The clock the unit runs on + +Required properties for DSI: +- compatible: Should be "brcm,bcm2835-dsi0" or "brcm,bcm2835-dsi1" +- reg: Physical base address and length of the DSI block's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- clocks: a) phy: The DSI PLL clock feeding the DSI analog PHY + b) escape: The DSI ESC clock from CPRMAN + c) pixel: The DSI pixel clock from CPRMAN +- clock-output-names: + The 3 clocks output from the DSI analog PHY: dsi[01]_byte, + dsi[01]_ddr2, and dsi[01]_ddr + +Required properties for the TXP (writeback) block: +- compatible: Should be "brcm,bcm2835-txp" +- reg: Physical base address and length of the TXP block's registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +[1] Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: +pixelvalve@7e807000 { + compatible = "brcm,bcm2835-pixelvalve2"; + reg = <0x7e807000 0x100>; + interrupts = <2 10>; /* pixelvalve */ +}; + +hvs@7e400000 { + compatible = "brcm,bcm2835-hvs"; + reg = <0x7e400000 0x6000>; + interrupts = <2 1>; +}; + +hdmi: hdmi@7e902000 { + compatible = "brcm,bcm2835-hdmi"; + reg = <0x7e902000 0x600>, + <0x7e808000 0x100>; + interrupts = <2 8>, <2 9>; + ddc = <&i2c2>; + hpd-gpios = <&gpio 46 GPIO_ACTIVE_HIGH>; + clocks = <&clocks BCM2835_PLLH_PIX>, + <&clocks BCM2835_CLOCK_HSM>; + clock-names = "pixel", "hdmi"; +}; + +dpi: dpi@7e208000 { + compatible = "brcm,bcm2835-dpi"; + reg = <0x7e208000 0x8c>; + clocks = <&clocks BCM2835_CLOCK_VPU>, + <&clocks BCM2835_CLOCK_DPI>; + clock-names = "core", "pixel"; + #address-cells = <1>; + #size-cells = <0>; + + port { + dpi_out: endpoint@0 { + remote-endpoint = <&panel_in>; + }; + }; +}; + +dsi1: dsi@7e700000 { + compatible = "brcm,bcm2835-dsi1"; + reg = <0x7e700000 0x8c>; + interrupts = <2 12>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + clocks = <&clocks BCM2835_PLLD_DSI1>, + <&clocks BCM2835_CLOCK_DSI1E>, + <&clocks BCM2835_CLOCK_DSI1P>; + clock-names = "phy", "escape", "pixel"; + + clock-output-names = "dsi1_byte", "dsi1_ddr2", "dsi1_ddr"; + + pitouchscreen: panel@0 { + compatible = "raspberrypi,touchscreen"; + reg = <0>; + + <...> + }; +}; + +vec: vec@7e806000 { + compatible = "brcm,bcm2835-vec"; + reg = <0x7e806000 0x1000>; + clocks = <&clocks BCM2835_CLOCK_VEC>; + interrupts = <2 27>; +}; + +v3d: v3d@7ec00000 { + compatible = "brcm,bcm2835-v3d"; + reg = <0x7ec00000 0x1000>; + interrupts = <1 10>; +}; + +vc4: gpu { + compatible = "brcm,bcm2835-vc4"; +}; + +panel: panel { + compatible = "ontat,yx700wv03", "simple-panel"; + + port { + panel_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/adi,adv7123.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/adi,adv7123.txt new file mode 100644 index 0000000000000000000000000000000000000000..a6b2b2b8f3d9e3a6b770f349d7e2f6dff91c68d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/adi,adv7123.txt @@ -0,0 +1,50 @@ +Analog Device ADV7123 Video DAC +------------------------------- + +The ADV7123 is a digital-to-analog converter that outputs VGA signals from a +parallel video input. + +Required properties: + +- compatible: Should be "adi,adv7123" + +Optional properties: + +- psave-gpios: Power save control GPIO + +Required nodes: + +The ADV7123 has two video ports. Their connections are modeled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for DPI input +- Video port 1 for VGA output + + +Example +------- + + adv7123: encoder@0 { + compatible = "adi,adv7123"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adv7123_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + adv7123_out: endpoint@0 { + remote-endpoint = <&vga_connector_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/adi,adv7511.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/adi,adv7511.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c887536258cfef57309664baf57d620074bcb42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/adi,adv7511.txt @@ -0,0 +1,142 @@ +Analog Device ADV7511(W)/13/33 HDMI Encoders +----------------------------------------- + +The ADV7511, ADV7511W, ADV7513 and ADV7533 are HDMI audio and video transmitters +compatible with HDMI 1.4 and DVI 1.0. They support color space conversion, +S/PDIF, CEC and HDCP. ADV7533 supports the DSI interface for input pixels, while +the others support RGB interface. + +Required properties: + +- compatible: Should be one of: + "adi,adv7511" + "adi,adv7511w" + "adi,adv7513" + "adi,adv7533" + +- reg: I2C slave addresses + The ADV7511 internal registers are split into four pages exposed through + different I2C addresses, creating four register maps. Each map has it own + I2C address and acts as a standard slave device on the I2C bus. The main + address is mandatory, others are optional and revert to defaults if not + specified. + + +The ADV7511 supports a large number of input data formats that differ by their +color depth, color format, clock mode, bit justification and random +arrangement of components on the data bus. The combination of the following +properties describe the input and map directly to the video input tables of the +ADV7511 datasheet that document all the supported combinations. + +- adi,input-depth: Number of bits per color component at the input (8, 10 or + 12). +- adi,input-colorspace: The input color space, one of "rgb", "yuv422" or + "yuv444". +- adi,input-clock: The input clock type, one of "1x" (one clock cycle per + pixel), "2x" (two clock cycles per pixel), "ddr" (one clock cycle per pixel, + data driven on both edges). + +The following input format properties are required except in "rgb 1x" and +"yuv444 1x" modes, in which case they must not be specified. + +- adi,input-style: The input components arrangement variant (1, 2 or 3), as + listed in the input format tables in the datasheet. +- adi,input-justification: The input bit justification ("left", "evenly", + "right"). + +- avdd-supply: A 1.8V supply that powers up the AVDD pin on the chip. +- dvdd-supply: A 1.8V supply that powers up the DVDD pin on the chip. +- pvdd-supply: A 1.8V supply that powers up the PVDD pin on the chip. +- dvdd-3v-supply: A 3.3V supply that powers up the pin called DVDD_3V + on the chip. +- bgvdd-supply: A 1.8V supply that powers up the BGVDD pin. This is + needed only for ADV7511. + +The following properties are required for ADV7533: + +- adi,dsi-lanes: Number of DSI data lanes connected to the DSI host. It should + be one of 1, 2, 3 or 4. +- a2vdd-supply: 1.8V supply that powers up the A2VDD pin on the chip. +- v3p3-supply: A 3.3V supply that powers up the V3P3 pin on the chip. +- v1p2-supply: A supply that powers up the V1P2 pin on the chip. It can be + either 1.2V or 1.8V. + +Optional properties: + +- interrupts: Specifier for the ADV7511 interrupt +- pd-gpios: Specifier for the GPIO connected to the power down signal + +- adi,clock-delay: Video data clock delay relative to the pixel clock, in ps + (-1200 ps .. 1600 ps). Defaults to no delay. +- adi,embedded-sync: The input uses synchronization signals embedded in the + data stream (similar to BT.656). Defaults to separate H/V synchronization + signals. +- adi,disable-timing-generator: Only for ADV7533. Disables the internal timing + generator. The chip will rely on the sync signals in the DSI data lanes, + rather than generate its own timings for HDMI output. +- clocks: from common clock binding: reference to the CEC clock. +- clock-names: from common clock binding: must be "cec". +- reg-names : Names of maps with programmable addresses. + It can contain any map needing a non-default address. + Possible maps names are : "main", "edid", "cec", "packet" + +Required nodes: + +The ADV7511 has two video ports. Their connections are modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for the RGB, YUV or DSI input. In the case of ADV7533, the + remote endpoint phandle should be a reference to a valid mipi_dsi_host device + node. +- Video port 1 for the HDMI output +- Audio port 2 for the HDMI audio input + + +Example +------- + + adv7511w: hdmi@39 { + compatible = "adi,adv7511w"; + /* + * The EDID page will be accessible on address 0x66 on the I2C + * bus. All other maps continue to use their default addresses. + */ + reg = <0x39>, <0x66>; + reg-names = "main", "edid"; + interrupt-parent = <&gpio3>; + interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + clocks = <&cec_clock>; + clock-names = "cec"; + + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + adi,input-style = <1>; + adi,input-justification = "evenly"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7511w_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + adv7511_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + + port@2 { + reg = <2>; + codec_endpoint: endpoint { + remote-endpoint = <&i2s0_cpu_endpoint>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/analogix_dp.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/analogix_dp.txt new file mode 100644 index 0000000000000000000000000000000000000000..027d76c27a41d33a1ec21b5cfe58b95ad97d9b65 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/analogix_dp.txt @@ -0,0 +1,51 @@ +Analogix Display Port bridge bindings + +Required properties for dp-controller: + -compatible: + platform specific such as: + * "samsung,exynos5-dp" + * "rockchip,rk3288-dp" + * "rockchip,rk3399-edp" + -reg: + physical base address of the controller and length + of memory mapped region. + -interrupts: + interrupt combiner values. + -clocks: + from common clock binding: handle to dp clock. + -clock-names: + from common clock binding: Shall be "dp". + -phys: + from general PHY binding: the phandle for the PHY device. + -phy-names: + from general PHY binding: Should be "dp". + +Optional properties for dp-controller: + -force-hpd: + Indicate driver need force hpd when hpd detect failed, this + is used for some eDP screen which don't have hpd signal. + -hpd-gpios: + Hotplug detect GPIO. + Indicates which GPIO should be used for hotplug detection + -port@[X]: SoC specific port nodes with endpoint definitions as defined + in Documentation/devicetree/bindings/media/video-interfaces.txt, + please refer to the SoC specific binding document: + * Documentation/devicetree/bindings/display/exynos/exynos_dp.txt + * Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt +------------------------------------------------------------------------------- + +Example: + + dp-controller { + compatible = "samsung,exynos5-dp"; + reg = <0x145b0000 0x10000>; + interrupts = <10 3>; + interrupt-parent = <&combiner>; + clocks = <&clock 342>; + clock-names = "dp"; + + phys = <&dp_phy>; + phy-names = "dp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/anx7814.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/anx7814.txt new file mode 100644 index 0000000000000000000000000000000000000000..dbd7c84ee58495f4adc88246115671ed905a11d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/anx7814.txt @@ -0,0 +1,38 @@ +Analogix ANX7814 SlimPort (Full-HD Transmitter) +----------------------------------------------- + +The ANX7814 is an ultra-low power Full-HD (1080p60) SlimPort transmitter +designed for portable devices. + +Required properties: + + - compatible : "analogix,anx7814" + - reg : I2C address of the device + - interrupts : Should contain the INTP interrupt + - hpd-gpios : Which GPIO to use for hpd + - pd-gpios : Which GPIO to use for power down + - reset-gpios : Which GPIO to use for reset + +Optional properties: + + - dvdd10-supply : Regulator for 1.0V digital core power. + - Video port for HDMI input, using the DT bindings defined in [1]. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + anx7814: anx7814@38 { + compatible = "analogix,anx7814"; + reg = <0x38>; + interrupt-parent = <&gpio0>; + interrupts = <99 IRQ_TYPE_LEVEL_LOW>; /* INTP */ + hpd-gpios = <&pio 36 GPIO_ACTIVE_HIGH>; + pd-gpios = <&pio 33 GPIO_ACTIVE_HIGH>; + reset-gpios = <&pio 98 GPIO_ACTIVE_HIGH>; + port { + anx7814_in: endpoint { + remote-endpoint = <&hdmi0_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/cdns,dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/cdns,dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5725bb6c61ca9bd6aa5cb645c4aa006e468a5e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/cdns,dsi.txt @@ -0,0 +1,133 @@ +Cadence DSI bridge +================== + +The Cadence DSI bridge is a DPI to DSI bridge supporting up to 4 DSI lanes. + +Required properties: +- compatible: should be set to "cdns,dsi". +- reg: physical base address and length of the controller's registers. +- interrupts: interrupt line connected to the DSI bridge. +- clocks: DSI bridge clocks. +- clock-names: must contain "dsi_p_clk" and "dsi_sys_clk". +- phys: phandle link to the MIPI D-PHY controller. +- phy-names: must contain "dphy". +- #address-cells: must be set to 1. +- #size-cells: must be set to 0. + +Optional properties: +- resets: DSI reset lines. +- reset-names: can contain "dsi_p_rst". + +Required subnodes: +- ports: Ports as described in Documentation/devicetree/bindings/graph.txt. + 2 ports are available: + * port 0: this port is only needed if some of your DSI devices are + controlled through an external bus like I2C or SPI. Can have at + most 4 endpoints. The endpoint number is directly encoding the + DSI virtual channel used by this device. + * port 1: represents the DPI input. + Other ports will be added later to support the new kind of inputs. + +- one subnode per DSI device connected on the DSI bus. Each DSI device should + contain a reg property encoding its virtual channel. + +Cadence DPHY +============ + +Cadence DPHY block. + +Required properties: +- compatible: should be set to "cdns,dphy". +- reg: physical base address and length of the DPHY registers. +- clocks: DPHY reference clocks. +- clock-names: must contain "psm" and "pll_ref". +- #phy-cells: must be set to 0. + + +Example: + dphy0: dphy@fd0e0000{ + compatible = "cdns,dphy"; + reg = <0x0 0xfd0e0000 0x0 0x1000>; + clocks = <&psm_clk>, <&pll_ref_clk>; + clock-names = "psm", "pll_ref"; + #phy-cells = <0>; + }; + + dsi0: dsi@fd0c0000 { + compatible = "cdns,dsi"; + reg = <0x0 0xfd0c0000 0x0 0x1000>; + clocks = <&pclk>, <&sysclk>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + interrupts = <1>; + phys = <&dphy0>; + phy-names = "dphy"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + dsi0_dpi_input: endpoint { + remote-endpoint = <&xxx_dpi_output>; + }; + }; + }; + + panel: dsi-dev@0 { + compatible = ""; + reg = <0>; + }; + }; + +or + + dsi0: dsi@fd0c0000 { + compatible = "cdns,dsi"; + reg = <0x0 0xfd0c0000 0x0 0x1000>; + clocks = <&pclk>, <&sysclk>; + clock-names = "dsi_p_clk", "dsi_sys_clk"; + interrupts = <1>; + phys = <&dphy1>; + phy-names = "dphy"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + dsi0_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&dsi_panel_input>; + }; + }; + + port@1 { + reg = <1>; + dsi0_dpi_input: endpoint { + remote-endpoint = <&xxx_dpi_output>; + }; + }; + }; + }; + + i2c@xxx { + panel: panel@59 { + compatible = ""; + reg = <0x59>; + + port { + dsi_panel_input: endpoint { + remote-endpoint = <&dsi0_output>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/dumb-vga-dac.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/dumb-vga-dac.txt new file mode 100644 index 0000000000000000000000000000000000000000..164cbb15f04cccb3b35647b87b41d6e886bdf3c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/dumb-vga-dac.txt @@ -0,0 +1,50 @@ +Dumb RGB to VGA DAC bridge +--------------------------- + +This binding is aimed for dumb RGB to VGA DAC based bridges that do not require +any configuration. + +Required properties: + +- compatible: Must be "dumb-vga-dac" + +Required nodes: + +This device has two video ports. Their connections are modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for RGB input +- Video port 1 for VGA output + +Optional properties: +- vdd-supply: Power supply for DAC + +Example +------- + +bridge { + compatible = "dumb-vga-dac"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + vga_bridge_in: endpoint { + remote-endpoint = <&tcon0_out_vga>; + }; + }; + + port@1 { + reg = <1>; + + vga_bridge_out: endpoint { + remote-endpoint = <&vga_con_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/dw_hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/dw_hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..33bf981fbe3348877d52da4301f96696f1c7927b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/dw_hdmi.txt @@ -0,0 +1,33 @@ +Synopsys DesignWare HDMI TX Encoder +=================================== + +This document defines device tree properties for the Synopsys DesignWare HDMI +TX Encoder (DWC HDMI TX). It doesn't constitue a device tree binding +specification by itself but is meant to be referenced by platform-specific +device tree bindings. + +When referenced from platform device tree bindings the properties defined in +this document are defined as follows. The platform device tree bindings are +responsible for defining whether each property is required or optional. + +- reg: Memory mapped base address and length of the DWC HDMI TX registers. + +- reg-io-width: Width of the registers specified by the reg property. The + value is expressed in bytes and must be equal to 1 or 4 if specified. The + register width defaults to 1 if the property is not present. + +- interrupts: Reference to the DWC HDMI TX interrupt. + +- clocks: References to all the clocks specified in the clock-names property + as specified in Documentation/devicetree/bindings/clock/clock-bindings.txt. + +- clock-names: The DWC HDMI TX uses the following clocks. + + - "iahb" is the bus clock for either AHB and APB (mandatory). + - "isfr" is the internal register configuration clock (mandatory). + - "cec" is the HDMI CEC controller main clock (optional). + +- ports: The connectivity of the DWC HDMI TX with the rest of the system is + expressed in using ports as specified in the device graph bindings defined + in Documentation/devicetree/bindings/graph.txt. The numbering of the ports + is platform-specific. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/dw_mipi_dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/dw_mipi_dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b13adf30b8d3b4d21322a91baa8912bafc0083a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/dw_mipi_dsi.txt @@ -0,0 +1,32 @@ +Synopsys DesignWare MIPI DSI host controller +============================================ + +This document defines device tree properties for the Synopsys DesignWare MIPI +DSI host controller. It doesn't constitue a device tree binding specification +by itself but is meant to be referenced by platform-specific device tree +bindings. + +When referenced from platform device tree bindings the properties defined in +this document are defined as follows. The platform device tree bindings are +responsible for defining whether each optional property is used or not. + +- reg: Memory mapped base address and length of the DesignWare MIPI DSI + host controller registers. (mandatory) + +- clocks: References to all the clocks specified in the clock-names property + as specified in [1]. (mandatory) + +- clock-names: + - "pclk" is the peripheral clock for either AHB and APB. (mandatory) + - "px_clk" is the pixel clock for the DPI/RGB input. (optional) + +- resets: References to all the resets specified in the reset-names property + as specified in [2]. (optional) + +- reset-names: string reset name, must be "apb" if used. (optional) + +- panel or bridge node: see [3]. (mandatory) + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/reset/reset.txt +[3] Documentation/devicetree/bindings/display/mipi-dsi-bus.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/lt9611uxc.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/lt9611uxc.txt new file mode 100644 index 0000000000000000000000000000000000000000..19cf21b55c9bcccc7060968ee376a41e137ac8ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/lt9611uxc.txt @@ -0,0 +1,124 @@ +LT9611uxc DSI to HDMI bridge + +Required properties: + - compatible: Must be "lt,lt9611uxc" + - reg: Main I2C slave ID (for I2C host driver) + - lt,irq-gpio: Main IRQ gpio mapping + - lt,reset-gpio Main reset gpio mapping + + + Optional properties: + - lt,hdmi-ps-gpio: gpio mapping for HDMI PS + - lt,hdmi-en-gpio: gpio mapping for HDMI EN + + - lt,supply-entries: A node that lists the elements of the supply used to + power the bridge. There can be more than one instance + of this binding, in which case the entry would be + appended with the supply entry index. + e.g. lt,supply-entry@0 + -- lt,supply-name: name of the supply (vdd/vcc) + -- lt,supply-min-voltage: minimum voltage level (uV) + -- lt,supply-max-voltage: maximum voltage level (uV) + -- lt,supply-enable-load: load drawn (uA) from enabled supply + -- lt,supply-disable-load: load drawn (uA) from disabled supply + -- lt,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode + -- lt,supply-pre-on-sleep: time to sleep (ms) before turning on + -- lt,supply-post-on-sleep: time to sleep (ms) after turning on + -- lt,supply-pre-off-sleep: time to sleep (ms) before turning off + -- lt,supply-post-off-sleep: time to sleep (ms) after turning off + + - lt,non-pluggable: Boolean to indicate if display is non pluggable. + - lt,customize-modes: Customized modes when it's non-pluggable display. + e.g. lt,customize-mode-id@0 + -- lt,mode-h-active: Horizontal active pixels for this mode. + -- lt,mode-h-front-porch: Horizontal front porch in pixels for this mode. + -- lt,mode-h-pulse-width: Horizontal sync width in pixels for this mode. + -- lt,mode-h-back-porch: Horizontal back porch in pixels for this mode. + -- lt,mode-h-active-high: Boolean to indicate if mode horizontal polarity is active high. + -- lt,mode-v-active: Vertical active lines for this mode. + -- lt,mode-v-front-porch: Vertical front porch in lines for this mode. + -- lt,mode-v-pulse-width: Vertical sync width in lines for this mode. + -- lt,mode-v-back-porch: Vertical back porch in lines for this mode. + -- lt,mode-v-active-high: Boolean to indicate if mode vertical polarity is active high. + -- lt,mode-refersh-rate: Mode refresh rate in hertz. + -- lt,mode-clock-in-khz: Mode pclk in KHz. + +Required nodes: + +The LT9611 has one video port. Its connection is modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. +Video port 0 is for the DSI input. The remote endpoint phandle should +be a reference to a valid mipi_dsi_host device node. + + +Example: + +&qupv3_se9_i2c { + status = "okay"; + lt9611@3b { + compatible = "lt,lt9611uxc"; + reg = <0x3b>; + interrupt-parent = <&tlmm>; + interrupts = <125 0>; + interrupt-names = "lt_irq"; + lt,irq-gpio = <&tlmm 125 0x0>; + lt,reset-gpio = <&tlmm 134 0x0>; + lt,hdmi-ps-gpio = <&tlmm 136 0x0>; + lt,hdmi-en-gpio = <&tlmm 137 0x0>; + + vcc-supply = <&pm660l_l6>; + vdd-supply = <&pm660_l11>; + lt,supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + lt,supply-entry@0 { + reg = <0>; + lt,supply-name = "vcc"; + lt,supply-min-voltage = <3300000>; + lt,supply-max-voltage = <3300000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + + lt,supply-entry@1 { + reg = <1>; + lt,supply-name = "vdd"; + lt,supply-min-voltage = <1800000>; + lt,supply-max-voltage = <1800000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + }; + + lt,customize-modes { + lt,customize-mode-id@0 { + lt,mode-h-active = <1920>; + lt,mode-h-front-porch = <88>; + lt,mode-h-pulse-width = <44>; + lt,mode-h-back-porch = <148>; + lt,mode-h-active-high; + lt,mode-v-active = <1080>; + lt,mode-v-front-porch = <4>; + lt,mode-v-pulse-width = <5>; + lt,mode-v-back-porch = <36>; + lt,mode-v-active-high; + lt,mode-refresh-rate = <60>; + lt,mode-clock-in-khz = <148500>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt9611_in: endpoint { + remote-endpoint = <&ext_dsi_out>; + }; + }; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/lvds-transmitter.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/lvds-transmitter.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd39ad34c38304cfea44e0529feb0c9070388719 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/lvds-transmitter.txt @@ -0,0 +1,64 @@ +Parallel to LVDS Encoder +------------------------ + +This binding supports the parallel to LVDS encoders that don't require any +configuration. + +LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple +incompatible data link layers have been used over time to transmit image data +to LVDS panels. This binding targets devices compatible with the following +specifications only. + +[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February +1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) +[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National +Semiconductor +[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video +Electronics Standards Association (VESA) + +Those devices have been marketed under the FPD-Link and FlatLink brand names +among others. + + +Required properties: + +- compatible: Must be "lvds-encoder" + +Required nodes: + +This device has two video ports. Their connections are modeled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for parallel input +- Video port 1 for LVDS output + + +Example +------- + +lvds-encoder { + compatible = "lvds-encoder"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_enc_in: endpoint { + remote-endpoint = <&display_out_rgb>; + }; + }; + + port@1 { + reg = <1>; + + lvds_enc_out: endpoint { + remote-endpoint = <&lvds_panel_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt new file mode 100644 index 0000000000000000000000000000000000000000..09e0a21f705ef6ad51c9e38b99a30260960d045d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt @@ -0,0 +1,91 @@ +Drivers for the second video output of the GE B850v3: + STDP4028-ge-b850v3-fw bridges (LVDS-DP) + STDP2690-ge-b850v3-fw bridges (DP-DP++) + +The video processing pipeline on the second output on the GE B850v3: + + Host -> LVDS|--(STDP4028)--|DP -> DP|--(STDP2690)--|DP++ -> Video output + +Each bridge has a dedicated flash containing firmware for supporting the custom +design. The result is that, in this design, neither the STDP4028 nor the +STDP2690 behave as the stock bridges would. The compatible strings include the +suffix "-ge-b850v3-fw" to make it clear that the driver is for the bridges with +the firmware specific for the GE B850v3. + +The hardware do not provide control over the video processing pipeline, as the +two bridges behaves as a single one. The only interfaces exposed by the +hardware are EDID, HPD, and interrupts. + +stdp4028-ge-b850v3-fw required properties: + - compatible : "megachips,stdp4028-ge-b850v3-fw" + - reg : I2C bus address + - interrupts : one interrupt should be described here, as in + <0 IRQ_TYPE_LEVEL_HIGH> + - ports : One input port(reg = <0>) and one output port(reg = <1>) + +stdp2690-ge-b850v3-fw required properties: + compatible : "megachips,stdp2690-ge-b850v3-fw" + - reg : I2C bus address + - ports : One input port(reg = <0>) and one output port(reg = <1>) + +Example: + +&mux2_i2c2 { + clock-frequency = <100000>; + + stdp4028@73 { + compatible = "megachips,stdp4028-ge-b850v3-fw"; + #address-cells = <1>; + #size-cells = <0>; + + reg = <0x73>; + + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + stdp4028_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + port@1 { + reg = <1>; + stdp4028_out: endpoint { + remote-endpoint = <&stdp2690_in>; + }; + }; + }; + }; + + stdp2690@72 { + compatible = "megachips,stdp2690-ge-b850v3-fw"; + #address-cells = <1>; + #size-cells = <0>; + + reg = <0x72>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + stdp2690_in: endpoint { + remote-endpoint = <&stdp4028_out>; + }; + }; + + port@1 { + reg = <1>; + stdp2690_out: endpoint { + /* Connector for external display */ + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/ps8622.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ps8622.txt new file mode 100644 index 0000000000000000000000000000000000000000..c989c3807f2b1fa17f5324d5dce8494d6d7c5d99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ps8622.txt @@ -0,0 +1,31 @@ +ps8622-bridge bindings + +Required properties: + - compatible: "parade,ps8622" or "parade,ps8625" + - reg: first i2c address of the bridge + - sleep-gpios: OF device-tree gpio specification for PD_ pin. + - reset-gpios: OF device-tree gpio specification for RST_ pin. + +Optional properties: + - lane-count: number of DP lanes to use + - use-external-pwm: backlight will be controlled by an external PWM + - video interfaces: Device node can contain video interface port + nodes for panel according to [1]. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + lvds-bridge@48 { + compatible = "parade,ps8622"; + reg = <0x48>; + sleep-gpios = <&gpc3 6 1 0 0>; + reset-gpios = <&gpc3 1 1 0 0>; + lane-count = <1>; + ports { + port@0 { + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/ptn3460.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ptn3460.txt new file mode 100644 index 0000000000000000000000000000000000000000..361971ba104dd34969879209073b651511ee3731 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ptn3460.txt @@ -0,0 +1,39 @@ +ptn3460 bridge bindings + +Required properties: + - compatible: "nxp,ptn3460" + - reg: i2c address of the bridge + - powerdown-gpio: OF device-tree gpio specification for PD_N pin. + - reset-gpio: OF device-tree gpio specification for RST_N pin. + - edid-emulation: The EDID emulation entry to use + +-------+------------+------------------+ + | Value | Resolution | Description | + | 0 | 1024x768 | NXP Generic | + | 1 | 1920x1080 | NXP Generic | + | 2 | 1920x1080 | NXP Generic | + | 3 | 1600x900 | Samsung LTM200KT | + | 4 | 1920x1080 | Samsung LTM230HT | + | 5 | 1366x768 | NXP Generic | + | 6 | 1600x900 | ChiMei M215HGE | + +-------+------------+------------------+ + + - video interfaces: Device node can contain video interface port + nodes for panel according to [1]. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + lvds-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + powerdown-gpio = <&gpy2 5 1 0 0>; + reset-gpio = <&gpx1 5 1 0 0>; + edid-emulation = <5>; + ports { + port@0 { + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/renesas,dw-hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/renesas,dw-hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..a41d280c3f9f74a5dc2b600a868ec0f8d6e73426 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/renesas,dw-hdmi.txt @@ -0,0 +1,83 @@ +Renesas Gen3 DWC HDMI TX Encoder +================================ + +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with a companion PHY IP. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. + + +Required properties: + +- compatible : Shall contain one or more of + - "renesas,r8a7795-hdmi" for R8A7795 (R-Car H3) compatible HDMI TX + - "renesas,r8a7796-hdmi" for R8A7796 (R-Car M3-W) compatible HDMI TX + - "renesas,r8a77965-hdmi" for R8A77965 (R-Car M3-N) compatible HDMI TX + - "renesas,rcar-gen3-hdmi" for the generic R-Car Gen3 compatible HDMI TX + + When compatible with generic versions, nodes must list the SoC-specific + version corresponding to the platform first, followed by the + family-specific version. + +- reg: See dw_hdmi.txt. +- interrupts: HDMI interrupt number +- clocks: See dw_hdmi.txt. +- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt. +- ports: See dw_hdmi.txt. The DWC HDMI shall have one port numbered 0 + corresponding to the video input of the controller and one port numbered 1 + corresponding to its HDMI output, and one port numbered 2 corresponding to + sound input of the controller. Each port shall have a single endpoint. + +Optional properties: + +- power-domains: Shall reference the power domain that contains the DWC HDMI, + if any. + + +Example: + + hdmi0: hdmi@fead0000 { + compatible = "renesas,r8a7795-dw-hdmi"; + reg = <0 0xfead0000 0 0x10000>; + interrupts = <0 389 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_CORE R8A7795_CLK_S0D4>, <&cpg CPG_MOD 729>; + clock-names = "iahb", "isfr"; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + dw_hdmi0_in: endpoint { + remote-endpoint = <&du_out_hdmi0>; + }; + }; + port@1 { + reg = <1>; + rcar_dw_hdmi0_out: endpoint { + remote-endpoint = <&hdmi0_con>; + }; + }; + port@2 { + reg = <2>; + rcar_dw_hdmi0_sound_in: endpoint { + remote-endpoint = <&hdmi_sound_out>; + }; + }; + }; + }; + + hdmi0-out { + compatible = "hdmi-connector"; + label = "HDMI0 OUT"; + type = "a"; + + port { + hdmi0_con: endpoint { + remote-endpoint = <&rcar_dw_hdmi0_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/renesas,lvds.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/renesas,lvds.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f0ab3ed3b6f28f75eafb61140e6a7f9bbd95aea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/renesas,lvds.txt @@ -0,0 +1,58 @@ +Renesas R-Car LVDS Encoder +========================== + +These DT bindings describe the LVDS encoder embedded in the Renesas R-Car +Gen2, R-Car Gen3 and RZ/G SoCs. + +Required properties: + +- compatible : Shall contain one of + - "renesas,r8a7743-lvds" for R8A7743 (RZ/G1M) compatible LVDS encoders + - "renesas,r8a7790-lvds" for R8A7790 (R-Car H2) compatible LVDS encoders + - "renesas,r8a7791-lvds" for R8A7791 (R-Car M2-W) compatible LVDS encoders + - "renesas,r8a7793-lvds" for R8A7793 (R-Car M2-N) compatible LVDS encoders + - "renesas,r8a7795-lvds" for R8A7795 (R-Car H3) compatible LVDS encoders + - "renesas,r8a7796-lvds" for R8A7796 (R-Car M3-W) compatible LVDS encoders + - "renesas,r8a77970-lvds" for R8A77970 (R-Car V3M) compatible LVDS encoders + - "renesas,r8a77995-lvds" for R8A77995 (R-Car D3) compatible LVDS encoders + +- reg: Base address and length for the memory-mapped registers +- clocks: A phandle + clock-specifier pair for the functional clock +- resets: A phandle + reset specifier for the module reset + +Required nodes: + +The LVDS encoder has two video ports. Their connections are modelled using the +OF graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 corresponds to the parallel RGB input +- Video port 1 corresponds to the LVDS output + +Each port shall have a single endpoint. + + +Example: + + lvds0: lvds@feb90000 { + compatible = "renesas,r8a7790-lvds"; + reg = <0 0xfeb90000 0 0x1c>; + clocks = <&cpg CPG_MOD 726>; + resets = <&cpg 726>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds0_in: endpoint { + remote-endpoint = <&du_out_lvds0>; + }; + }; + port@1 { + reg = <1>; + lvds0_out: endpoint { + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/sii902x.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/sii902x.txt new file mode 100644 index 0000000000000000000000000000000000000000..72d2dc6c3e6b58b5d2ca80b94c701966f6725024 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/sii902x.txt @@ -0,0 +1,35 @@ +sii902x HDMI bridge bindings + +Required properties: + - compatible: "sil,sii9022" + - reg: i2c address of the bridge + +Optional properties: + - interrupts: describe the interrupt line used to inform the host + about hotplug events. + - reset-gpios: OF device-tree gpio specification for RST_N pin. + +Optional subnodes: + - video input: this subnode can contain a video input port node + to connect the bridge to a display controller output (See this + documentation [1]). + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + hdmi-bridge@39 { + compatible = "sil,sii9022"; + reg = <0x39>; + reset-gpios = <&pioA 1 0>; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + bridge_in: endpoint { + remote-endpoint = <&dc_out>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/sii9234.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/sii9234.txt new file mode 100644 index 0000000000000000000000000000000000000000..a55bf77bd9600e615f185cc189f5e55d148dfc04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/sii9234.txt @@ -0,0 +1,49 @@ +Silicon Image SiI9234 HDMI/MHL bridge bindings + +Required properties: + - compatible : "sil,sii9234". + - reg : I2C address for TPI interface, use 0x39 + - avcc33-supply : MHL/USB Switch Supply Voltage (3.3V) + - iovcc18-supply : I/O Supply Voltage (1.8V) + - avcc12-supply : TMDS Analog Supply Voltage (1.2V) + - cvcc12-supply : Digital Core Supply Voltage (1.2V) + - interrupts: interrupt specifier of INT pin + - reset-gpios: gpio specifier of RESET pin (active low) + - video interfaces: Device node can contain two video interface port + nodes for HDMI encoder and connector according to [1]. + - port@0 - MHL to HDMI + - port@1 - MHL to connector + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + + +Example: + sii9234@39 { + compatible = "sil,sii9234"; + reg = <0x39>; + avcc33-supply = <&vcc33mhl>; + iovcc18-supply = <&vcc18mhl>; + avcc12-supply = <&vsil12>; + cvcc12-supply = <&vsil12>; + reset-gpios = <&gpf3 4 GPIO_ACTIVE_LOW>; + interrupt-parent = <&gpf3>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mhl_to_hdmi: endpoint { + remote-endpoint = <&hdmi_to_mhl>; + }; + }; + port@1 { + reg = <1>; + mhl_to_connector: endpoint { + remote-endpoint = <&connector_to_mhl>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/sil-sii8620.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/sil-sii8620.txt new file mode 100644 index 0000000000000000000000000000000000000000..b05052f7d62fccca0533a8fc386b25155d2a7495 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/sil-sii8620.txt @@ -0,0 +1,33 @@ +Silicon Image SiI8620 HDMI/MHL bridge bindings + +Required properties: + - compatible: "sil,sii8620" + - reg: i2c address of the bridge + - cvcc10-supply: Digital Core Supply Voltage (1.0V) + - iovcc18-supply: I/O Supply Voltage (1.8V) + - interrupts: interrupt specifier of INT pin + - reset-gpios: gpio specifier of RESET pin + - clocks, clock-names: specification and name of "xtal" clock + - video interfaces: Device node can contain video interface port + node for HDMI encoder according to [1]. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + sii8620@39 { + reg = <0x39>; + compatible = "sil,sii8620"; + cvcc10-supply = <&ldo36_reg>; + iovcc18-supply = <&ldo34_reg>; + interrupt-parent = <&gpf0>; + interrupts = <2 0>; + reset-gpio = <&gpv7 0 0>; + clocks = <&pmu_system_controller 0>; + clock-names = "xtal"; + + port { + mhl_to_hdmi: endpoint { + remote-endpoint = <&hdmi_to_mhl>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/tda998x.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/tda998x.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5a02f61dd36f1c68acc89f15507a144188db8c0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/tda998x.txt @@ -0,0 +1,54 @@ +Device-Tree bindings for the NXP TDA998x HDMI transmitter + +Required properties; + - compatible: must be "nxp,tda998x" + + - reg: I2C address + +Required node: + - port: Input port node with endpoint definition, as described + in Documentation/devicetree/bindings/graph.txt + +Optional properties: + - interrupts: interrupt number and trigger type + default: polling + + - pinctrl-0: pin control group to be used for + screen plug/unplug interrupt. + + - pinctrl-names: must contain a "default" entry. + + - video-ports: 24 bits value which defines how the video controller + output is wired to the TDA998x input - default: <0x230145> + + - audio-ports: array of 8-bit values, 2 values per one DAI[1]. + The first value defines the DAI type: TDA998x_SPDIF or TDA998x_I2S[2]. + The second value defines the tda998x AP_ENA reg content when the DAI + in question is used. The implementation allows one or two DAIs. If two + DAIs are defined, they must be of different type. + + - nxp,calib-gpios: calibration GPIO, which must correspond with the + gpio used for the TDA998x interrupt pin. + +[1] Documentation/sound/soc/dai.rst +[2] include/dt-bindings/display/tda998x.h + +Example: + +#include + + tda998x: hdmi-encoder { + compatible = "nxp,tda998x"; + reg = <0x70>; + interrupt-parent = <&gpio0>; + interrupts = <27 2>; /* falling edge */ + pinctrl-0 = <&pmx_camera>; + pinctrl-names = "default"; + video-ports = <0x230145>; + + #sound-dai-cells = <2>; + /* DAI-format AP_ENA reg value */ + audio-ports = < TDA998x_SPDIF 0x04 + TDA998x_I2S 0x03>; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/thine,thc63lvd1024.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/thine,thc63lvd1024.txt new file mode 100644 index 0000000000000000000000000000000000000000..37f0c04d5a28b60d7a121b566974bad37f69e2f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/thine,thc63lvd1024.txt @@ -0,0 +1,60 @@ +Thine Electronics THC63LVD1024 LVDS decoder +------------------------------------------- + +The THC63LVD1024 is a dual link LVDS receiver designed to convert LVDS streams +to parallel data outputs. The chip supports single/dual input/output modes, +handling up to two LVDS input streams and up to two digital CMOS/TTL outputs. + +Single or dual operation mode, output data mapping and DDR output modes are +configured through input signals and the chip does not expose any control bus. + +Required properties: +- compatible: Shall be "thine,thc63lvd1024" +- vcc-supply: Power supply for TTL output, TTL CLOCKOUT signal, LVDS input, + PPL and digital circuitry + +Optional properties: +- powerdown-gpios: Power down GPIO signal, pin name "/PDWN". Active low +- oe-gpios: Output enable GPIO signal, pin name "OE". Active high + +The THC63LVD1024 video port connections are modeled according +to OF graph bindings specified by Documentation/devicetree/bindings/graph.txt + +Required video port nodes: +- port@0: First LVDS input port +- port@2: First digital CMOS/TTL parallel output + +Optional video port nodes: +- port@1: Second LVDS input port +- port@3: Second digital CMOS/TTL parallel output + +Example: +-------- + + thc63lvd1024: lvds-decoder { + compatible = "thine,thc63lvd1024"; + + vcc-supply = <®_lvds_vcc>; + powerdown-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_dec_in_0: endpoint { + remote-endpoint = <&lvds_out>; + }; + }; + + port@2{ + reg = <2>; + + lvds_dec_out_2: endpoint { + remote-endpoint = <&adv7511_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/thine,thc63lvdm83d.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/thine,thc63lvdm83d.txt new file mode 100644 index 0000000000000000000000000000000000000000..527e236e9a2a126dcdd814e3b50c972a7145fe44 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/thine,thc63lvdm83d.txt @@ -0,0 +1,50 @@ +THine Electronics THC63LVDM83D LVDS serializer +---------------------------------------------- + +The THC63LVDM83D is an LVDS serializer designed to support pixel data +transmission between a host and a flat panel. + +Required properties: + +- compatible: Should be "thine,thc63lvdm83d" + +Optional properties: + +- pwdn-gpios: Power down control GPIO + +Required nodes: + +The THC63LVDM83D has two video ports. Their connections are modeled using the +OFgraph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for CMOS/TTL input +- Video port 1 for LVDS output + + +Example +------- + + lvds_enc: encoder@0 { + compatible = "thine,thc63lvdm83d"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lvds_enc_in: endpoint@0 { + remote-endpoint = <&rgb_out>; + }; + }; + + port@1 { + reg = <1>; + + lvds_enc_out: endpoint@0 { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/ti,tfp410.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ti,tfp410.txt new file mode 100644 index 0000000000000000000000000000000000000000..54d7e31525ecfe944615d39ff8d5a55cf020850e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ti,tfp410.txt @@ -0,0 +1,46 @@ +TFP410 DPI to DVI encoder +========================= + +Required properties: +- compatible: "ti,tfp410" + +Optional properties: +- powerdown-gpios: power-down gpio +- reg: I2C address. If and only if present the device node + should be placed into the i2c controller node where the + tfp410 i2c is connected to. + +Required nodes: +- Video port 0 for DPI input [1]. +- Video port 1 for DVI output [1]. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example +------- + +tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/ti,ths813x.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ti,ths813x.txt new file mode 100644 index 0000000000000000000000000000000000000000..df3d7c1ac09e5aff5ecff3e47c84d686ae9e98ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/ti,ths813x.txt @@ -0,0 +1,51 @@ +THS8134 and THS8135 Video DAC +----------------------------- + +This is the binding for Texas Instruments THS8134, THS8134A, THS8134B and +THS8135 Video DAC bridges. + +Required properties: + +- compatible: Must be one of + "ti,ths8134" + "ti,ths8134a," "ti,ths8134" + "ti,ths8134b", "ti,ths8134" + "ti,ths8135" + +Required nodes: + +This device has two video ports. Their connections are modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for RGB input +- Video port 1 for VGA output + +Example +------- + +vga-bridge { + compatible = "ti,ths8135"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + vga_bridge_in: endpoint { + remote-endpoint = <&lcdc_out_vga>; + }; + }; + + port@1 { + reg = <1>; + + vga_bridge_out: endpoint { + remote-endpoint = <&vga_con_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/bridge/toshiba,tc358767.txt b/arch/arm64/boot/dts/vendor/bindings/display/bridge/toshiba,tc358767.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3f6aa6a214de08a46c08f2cca23405f281c99a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/bridge/toshiba,tc358767.txt @@ -0,0 +1,53 @@ +Toshiba TC358767 eDP bridge bindings + +Required properties: + - compatible: "toshiba,tc358767" + - reg: i2c address of the bridge, 0x68 or 0x0f, depending on bootstrap pins + - clock-names: should be "ref" + - clocks: OF device-tree clock specification for refclk input. The reference + clock rate must be 13 MHz, 19.2 MHz, 26 MHz, or 38.4 MHz. + +Optional properties: + - shutdown-gpios: OF device-tree gpio specification for SD pin + (active high shutdown input) + - reset-gpios: OF device-tree gpio specification for RSTX pin + (active low system reset) + - ports: the ports node can contain video interface port nodes to connect + to a DPI/DSI source and to an eDP/DP sink according to [1][2]: + - port@0: DSI input port + - port@1: DPI input port + - port@2: eDP/DP output port + +[1]: Documentation/devicetree/bindings/graph.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + edp-bridge@68 { + compatible = "toshiba,tc358767"; + reg = <0x68>; + shutdown-gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio3 24 GPIO_ACTIVE_LOW>; + clock-names = "ref"; + clocks = <&edp_refclk>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + bridge_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + port@2 { + reg = <2>; + + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/cirrus,clps711x-fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/cirrus,clps711x-fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..b0e506610400c4bc020f743963c2e65794d79460 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/cirrus,clps711x-fb.txt @@ -0,0 +1,47 @@ +* Currus Logic CLPS711X Framebuffer + +Required properties: +- compatible: Shall contain "cirrus,ep7209-fb". +- reg : Physical base address and length of the controller's registers + + location and size of the framebuffer memory. +- clocks : phandle + clock specifier pair of the FB reference clock. +- display : phandle to a display node as described in + Documentation/devicetree/bindings/display/panel/display-timing.txt. + Additionally, the display node has to define properties: + - bits-per-pixel: Bits per pixel. + - ac-prescale : LCD AC bias frequency. This frequency is the required + AC bias frequency for a given manufacturer's LCD plate. + - cmap-invert : Invert the color levels (Optional). + +Optional properties: +- lcd-supply: Regulator for LCD supply voltage. + +Example: + fb: fb@800002c0 { + compatible = "cirrus,ep7312-fb", "cirrus,ep7209-fb"; + reg = <0x800002c0 0xd44>, <0x60000000 0xc000>; + clocks = <&clks 2>; + lcd-supply = <®5v0>; + display = <&display>; + }; + + display: display { + model = "320x240x4"; + native-mode = <&timing0>; + bits-per-pixel = <4>; + ac-prescale = <17>; + + display-timings { + timing0: 320x240 { + hactive = <320>; + hback-porch = <0>; + hfront-porch = <0>; + hsync-len = <0>; + vactive = <240>; + vback-porch = <0>; + vfront-porch = <0>; + vsync-len = <0>; + clock-frequency = <6500000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/connector/analog-tv-connector.txt b/arch/arm64/boot/dts/vendor/bindings/display/connector/analog-tv-connector.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c0970c210ab7be0c2a52ba4a977a0de8ddd0d5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/connector/analog-tv-connector.txt @@ -0,0 +1,25 @@ +Analog TV Connector +=================== + +Required properties: +- compatible: "composite-video-connector" or "svideo-connector" + +Optional properties: +- label: a symbolic name for the connector + +Required nodes: +- Video port for TV input + +Example +------- + +tv: connector { + compatible = "composite-video-connector"; + label = "tv"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&venc_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/connector/dvi-connector.txt b/arch/arm64/boot/dts/vendor/bindings/display/connector/dvi-connector.txt new file mode 100644 index 0000000000000000000000000000000000000000..207e42e9eba0e1b17a0d0fcc6a7cf32b8209b4c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/connector/dvi-connector.txt @@ -0,0 +1,36 @@ +DVI Connector +============== + +Required properties: +- compatible: "dvi-connector" + +Optional properties: +- label: a symbolic name for the connector +- ddc-i2c-bus: phandle to the i2c bus that is connected to DVI DDC +- analog: the connector has DVI analog pins +- digital: the connector has DVI digital pins +- dual-link: the connector has pins for DVI dual-link +- hpd-gpios: HPD GPIO number + +Required nodes: +- Video port for DVI input + +Note: One (or both) of 'analog' or 'digital' must be set. + +Example +------- + +dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/connector/hdmi-connector.txt b/arch/arm64/boot/dts/vendor/bindings/display/connector/hdmi-connector.txt new file mode 100644 index 0000000000000000000000000000000000000000..508aee461e0dd5723e9b11fe8f765ba5ee0d9de3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/connector/hdmi-connector.txt @@ -0,0 +1,30 @@ +HDMI Connector +============== + +Required properties: +- compatible: "hdmi-connector" +- type: the HDMI connector type: "a", "b", "c", "d" or "e" + +Optional properties: +- label: a symbolic name for the connector +- hpd-gpios: HPD GPIO number +- ddc-i2c-bus: phandle link to the I2C controller used for DDC EDID probing + +Required nodes: +- Video port for HDMI input + +Example +------- + +hdmi0: connector@1 { + compatible = "hdmi-connector"; + label = "hdmi"; + + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/connector/vga-connector.txt b/arch/arm64/boot/dts/vendor/bindings/display/connector/vga-connector.txt new file mode 100644 index 0000000000000000000000000000000000000000..c727f298e7ad087de6108f32a72a9ae06f519e8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/connector/vga-connector.txt @@ -0,0 +1,36 @@ +VGA Connector +============= + +Required properties: + +- compatible: "vga-connector" + +Optional properties: + +- label: a symbolic name for the connector corresponding to a hardware label +- ddc-i2c-bus: phandle to the I2C bus that is connected to VGA DDC + +Required nodes: + +The VGA connector internal connections are modeled using the OF graph bindings +specified in Documentation/devicetree/bindings/graph.txt. + +The VGA connector has a single port that must be connected to a video source +port. + + +Example +------- + +vga0: connector@0 { + compatible = "vga-connector"; + label = "vga"; + + ddc-i2c-bus = <&i2c3>; + + port { + vga_connector_in: endpoint { + remote-endpoint = <&adv7123_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/etnaviv/etnaviv-drm.txt b/arch/arm64/boot/dts/vendor/bindings/display/etnaviv/etnaviv-drm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8def11b16a24a0c44106a3367ec956f82a7e95cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/etnaviv/etnaviv-drm.txt @@ -0,0 +1,36 @@ +Vivante GPU core devices +======================== + +Required properties: +- compatible: Should be "vivante,gc" + A more specific compatible is not needed, as the cores contain chip + identification registers at fixed locations, which provide all the + necessary information to the driver. +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain the cores interrupt line +- clocks: should contain one clock for entry in clock-names + see Documentation/devicetree/bindings/clock/clock-bindings.txt +- clock-names: + - "bus": AXI/master interface clock + - "reg": AHB/slave interface clock + (only required if GPU can gate slave interface independently) + - "core": GPU core clock + - "shader": Shader clock (only required if GPU has feature PIPE_3D) + +Optional properties: +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt + +example: + +gpu_3d: gpu@130000 { + compatible = "vivante,gc"; + reg = <0x00130000 0x4000>; + interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_GPU3D_AXI>, + <&clks IMX6QDL_CLK_GPU3D_CORE>, + <&clks IMX6QDL_CLK_GPU3D_SHADER>; + clock-names = "bus", "core", "shader"; + power-domains = <&gpc 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos-mic.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos-mic.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fba2ee6440ae2b1dcaa6087e828c201e5776d0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos-mic.txt @@ -0,0 +1,51 @@ +Device-Tree bindings for Samsung Exynos SoC mobile image compressor (MIC) + +MIC (mobile image compressor) resides between decon and mipi dsi. Mipi dsi is +not capable to transfer high resoltuion frame data as decon can send. MIC +solves this problem by compressing the frame data by 1/2 before it is +transferred through mipi dsi. The compressed frame data must be uncompressed in +the panel PCB. + +Required properties: +- compatible: value should be "samsung,exynos5433-mic". +- reg: physical base address and length of the MIC registers set and system + register of mic. +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. +- clock-names: list of clock names sorted in the same order as the clocks + property. Must contain "pclk_mic0", "sclk_rgb_vclk_to_mic0". +- samsung,disp-syscon: the reference node for syscon for DISP block. +- ports: contains a port which is connected to decon node and dsi node. + address-cells and size-cells must 1 and 0, respectively. +- port: contains an endpoint node which is connected to the endpoint in the + decon node or dsi node. The reg value must be 0 and 1 respectively. + +Example: +SoC specific DT entry: +mic: mic@13930000 { + compatible = "samsung,exynos5433-mic"; + reg = <0x13930000 0x48>; + clocks = <&cmu_disp CLK_PCLK_MIC0>, + <&cmu_disp CLK_SCLK_RGB_VCLK_TO_MIC0>; + clock-names = "pclk_mic0", "sclk_rgb_vclk_to_mic0"; + samsung,disp-syscon = <&syscon_disp>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mic_to_decon: endpoint { + remote-endpoint = <&decon_to_mic>; + }; + }; + + port@1 { + reg = <1>; + mic_to_dsi: endpoint { + remote-endpoint = <&dsi_to_mic>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos5433-decon.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos5433-decon.txt new file mode 100644 index 0000000000000000000000000000000000000000..775193e1c64147212afd32c2e4407621cb56b159 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos5433-decon.txt @@ -0,0 +1,60 @@ +Device-Tree bindings for Samsung Exynos SoC display controller (DECON) + +DECON (Display and Enhancement Controller) is the Display Controller for the +Exynos series of SoCs which transfers the image data from a video memory +buffer to an external LCD interface. + +Required properties: +- compatible: value should be one of: + "samsung,exynos5433-decon", "samsung,exynos5433-decon-tv"; +- reg: physical base address and length of the DECON registers set. +- interrupt-names: should contain the interrupt names depending on mode of work: + video mode: "vsync", + command mode: "lcd_sys", + command mode with software trigger: "lcd_sys", "te". +- interrupts or interrupts-extended: list of interrupt specifiers corresponding + to names privided in interrupt-names, as described in + interrupt-controller/interrupts.txt +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. +- clock-names: list of clock names sorted in the same order as the clocks + property. Must contain "pclk", "aclk_decon", "aclk_smmu_decon0x", + "aclk_xiu_decon0x", "pclk_smmu_decon0x", "aclk_smmu_decon1x", + "aclk_xiu_decon1x", "pclk_smmu_decon1x", clk_decon_vclk", + "sclk_decon_eclk" +- ports: contains a port which is connected to mic node. address-cells and + size-cells must 1 and 0, respectively. +- port: contains an endpoint node which is connected to the endpoint in the mic + node. The reg value muset be 0. + +Example: +SoC specific DT entry: +decon: decon@13800000 { + compatible = "samsung,exynos5433-decon"; + reg = <0x13800000 0x2104>; + clocks = <&cmu_disp CLK_ACLK_DECON>, <&cmu_disp CLK_ACLK_SMMU_DECON0X>, + <&cmu_disp CLK_ACLK_XIU_DECON0X>, + <&cmu_disp CLK_PCLK_SMMU_DECON0X>, + <&cmu_disp CLK_ACLK_SMMU_DECON1X>, + <&cmu_disp CLK_ACLK_XIU_DECON1X>, + <&cmu_disp CLK_PCLK_SMMU_DECON1X>, + <&cmu_disp CLK_SCLK_DECON_VCLK>, + <&cmu_disp CLK_SCLK_DECON_ECLK>; + clock-names = "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x", + "pclk_smmu_decon0x", "aclk_smmu_decon1x", "aclk_xiu_decon1x", + "pclk_smmu_decon1x", "sclk_decon_vclk", "sclk_decon_eclk"; + interrupt-names = "vsync", "lcd_sys"; + interrupts = <0 202 0>, <0 203 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + decon_to_mic: endpoint { + remote-endpoint = <&mic_to_decon>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos7-decon.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos7-decon.txt new file mode 100644 index 0000000000000000000000000000000000000000..53912c99ec38930093322033fb485bbbda3eefe0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos7-decon.txt @@ -0,0 +1,65 @@ +Device-Tree bindings for Samsung Exynos7 SoC display controller (DECON) + +DECON (Display and Enhancement Controller) is the Display Controller for the +Exynos7 series of SoCs which transfers the image data from a video memory +buffer to an external LCD interface. + +Required properties: +- compatible: value should be "samsung,exynos7-decon"; + +- reg: physical base address and length of the DECON registers set. + +- interrupts: should contain a list of all DECON IP block interrupts in the + order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier + format depends on the interrupt controller used. + +- interrupt-names: should contain the interrupt names: "fifo", "vsync", + "lcd_sys", in the same order as they were listed in the interrupts + property. + +- pinctrl-0: pin control group to be used for this controller. + +- pinctrl-names: must contain a "default" entry. + +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. + +- clock-names: list of clock names sorted in the same order as the clocks + property. Must contain "pclk_decon0", "aclk_decon0", + "decon0_eclk", "decon0_vclk". +- i80-if-timings: timing configuration for lcd i80 interface support. + +Optional Properties: +- power-domains: a phandle to DECON power domain node. +- display-timings: timing settings for DECON, as described in document [1]. + Can be used in case timings cannot be provided otherwise + or to override timings provided by the panel. + +[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt + +Example: + +SoC specific DT entry: + + decon@13930000 { + compatible = "samsung,exynos7-decon"; + interrupt-parent = <&combiner>; + reg = <0x13930000 0x1000>; + interrupt-names = "lcd_sys", "vsync", "fifo"; + interrupts = <0 188 0>, <0 189 0>, <0 190 0>; + clocks = <&clock_disp PCLK_DECON_INT>, + <&clock_disp ACLK_DECON_INT>, + <&clock_disp SCLK_DECON_INT_ECLK>, + <&clock_disp SCLK_DECON_INT_EXTCLKPLL>; + clock-names = "pclk_decon0", "aclk_decon0", "decon0_eclk", + "decon0_vclk"; + status = "disabled"; + }; + +Board specific DT entry: + + decon@13930000 { + pinctrl-0 = <&lcd_clk &pwm1_out>; + pinctrl-names = "default"; + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_dp.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_dp.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b6cba3f82af7a8e24e73e1266bbfb17e7ea8d0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_dp.txt @@ -0,0 +1,112 @@ +The Exynos display port interface should be configured based on +the type of panel connected to it. + +We use two nodes: + -dp-controller node + -dptx-phy node(defined inside dp-controller node) + +For the DP-PHY initialization, we use the dptx-phy node. +Required properties for dptx-phy: deprecated, use phys and phy-names + -reg: deprecated + Base address of DP PHY register. + -samsung,enable-mask: deprecated + The bit-mask used to enable/disable DP PHY. + +For the Panel initialization, we read data from dp-controller node. +Required properties for dp-controller: + -compatible: + should be "samsung,exynos5-dp". + -reg: + physical base address of the controller and length + of memory mapped region. + -interrupts: + interrupt combiner values. + -clocks: + from common clock binding: handle to dp clock. + -clock-names: + from common clock binding: Shall be "dp". + -phys: + from general PHY binding: the phandle for the PHY device. + -phy-names: + from general PHY binding: Should be "dp". + +Optional properties for dp-controller: + -interlaced: + interlace scan mode. + Progressive if defined, Interlaced if not defined + -vsync-active-high: + VSYNC polarity configuration. + High if defined, Low if not defined + -hsync-active-high: + HSYNC polarity configuration. + High if defined, Low if not defined + -samsung,hpd-gpio: + Hotplug detect GPIO. + Indicates which GPIO should be used for hotplug + detection + -video interfaces: Device node can contain video interface port + nodes according to [1]. + - display-timings: timings for the connected panel as described by + Documentation/devicetree/bindings/display/panel/display-timing.txt + +For the below properties, please refer to Analogix DP binding document: + * Documentation/devicetree/bindings/display/bridge/analogix_dp.txt + -phys (required) + -phy-names (required) + -hpd-gpios (optional) + force-hpd (optional) + +Deprecated properties for DisplayPort: +-interlaced: deprecated prop that can parsed from drm_display_mode. +-vsync-active-high: deprecated prop that can parsed from drm_display_mode. +-hsync-active-high: deprecated prop that can parsed from drm_display_mode. +-samsung,ycbcr-coeff: deprecated prop that can parsed from drm_display_mode. +-samsung,dynamic-range: deprecated prop that can parsed from drm_display_mode. +-samsung,color-space: deprecated prop that can parsed from drm_display_info. +-samsung,color-depth: deprecated prop that can parsed from drm_display_info. +-samsung,link-rate: deprecated prop that can reading from monitor by dpcd method. +-samsung,lane-count: deprecated prop that can reading from monitor by dpcd method. +-samsung,hpd-gpio: deprecated name for hpd-gpios. + +------------------------------------------------------------------------------- + +Example: + +SOC specific portion: + dp-controller { + compatible = "samsung,exynos5-dp"; + reg = <0x145b0000 0x10000>; + interrupts = <10 3>; + interrupt-parent = <&combiner>; + clocks = <&clock 342>; + clock-names = "dp"; + + phys = <&dp_phy>; + phy-names = "dp"; + }; + +Board Specific portion: + dp-controller { + display-timings { + native-mode = <&lcd_timing>; + lcd_timing: 1366x768 { + clock-frequency = <70589280>; + hactive = <1366>; + vactive = <768>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <32>; + vback-porch = <10>; + vfront-porch = <12>; + vsync-len = <6>; + }; + }; + + ports { + port@0 { + dp_out: endpoint { + remote-endpoint = <&bridge_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_dsim.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_dsim.txt new file mode 100644 index 0000000000000000000000000000000000000000..2fff8b406f4cbe3ef8eec8e4bc72dd4d07d88c00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_dsim.txt @@ -0,0 +1,103 @@ +Exynos MIPI DSI Master + +Required properties: + - compatible: value should be one of the following + "samsung,exynos3250-mipi-dsi" /* for Exynos3250/3472 SoCs */ + "samsung,exynos4210-mipi-dsi" /* for Exynos4 SoCs */ + "samsung,exynos5410-mipi-dsi" /* for Exynos5410/5420/5440 SoCs */ + "samsung,exynos5422-mipi-dsi" /* for Exynos5422/5800 SoCs */ + "samsung,exynos5433-mipi-dsi" /* for Exynos5433 SoCs */ + - reg: physical base address and length of the registers set for the device + - interrupts: should contain DSI interrupt + - clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names + - clock-names: should include "bus_clk"and "sclk_mipi" entries + the use of "pll_clk" is deprecated + - phys: list of phy specifiers, must contain an entry for each required + entry in phy-names + - phy-names: should include "dsim" entry + - vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V) + - vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V) + - samsung,pll-clock-frequency: specifies frequency of the oscillator clock + - #address-cells, #size-cells: should be set respectively to <1> and <0> + according to DSI host bindings (see MIPI DSI bindings [1]) + +Optional properties: + - power-domains: a phandle to DSIM power domain node + +Child nodes: + Should contain DSI peripheral nodes (see MIPI DSI bindings [1]). + +Video interfaces: + Device node can contain video interface port nodes according to [2]. + The following are properties specific to those nodes: + + port node inbound: + - reg: (required) must be 0. + port node outbound: + - reg: (required) must be 1. + + endpoint node connected from mic node (reg = 0): + - remote-endpoint: specifies the endpoint in mic node. This node is required + for Exynos5433 mipi dsi. So mic can access to panel node + throughout this dsi node. + endpoint node connected to panel node (reg = 1): + - remote-endpoint: specifies the endpoint in panel node. This node is + required in all kinds of exynos mipi dsi to represent + the connection between mipi dsi and panel. + - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst + mode + - samsung,esc-clock-frequency: specifies DSI frequency in escape mode + +[1]: Documentation/devicetree/bindings/display/mipi-dsi-bus.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + dsi@11c80000 { + compatible = "samsung,exynos4210-mipi-dsi"; + reg = <0x11C80000 0x10000>; + interrupts = <0 79 0>; + clocks = <&clock 286>, <&clock 143>; + clock-names = "bus_clk", "sclk_mipi"; + phys = <&mipi_phy 1>; + phy-names = "dsim"; + vddcore-supply = <&vusb_reg>; + vddio-supply = <&vmipi_reg>; + power-domains = <&pd_lcd0>; + #address-cells = <1>; + #size-cells = <0>; + samsung,pll-clock-frequency = <24000000>; + + panel@1 { + reg = <0>; + ... + port { + panel_ep: endpoint { + remote-endpoint = <&dsi_ep>; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + decon_to_mic: endpoint { + remote-endpoint = <&mic_to_decon>; + }; + }; + + port@1 { + reg = <1>; + dsi_ep: endpoint { + reg = <0>; + samsung,burst-clock-frequency = <500000000>; + samsung,esc-clock-frequency = <20000000>; + remote-endpoint = <&panel_ep>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..58b12e25bbb16d5ce85b7d11be530ec80dab71d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmi.txt @@ -0,0 +1,64 @@ +Device-Tree bindings for drm hdmi driver + +Required properties: +- compatible: value should be one among the following: + 1) "samsung,exynos4210-hdmi" + 2) "samsung,exynos4212-hdmi" + 3) "samsung,exynos5420-hdmi" + 4) "samsung,exynos5433-hdmi" +- reg: physical base address of the hdmi and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- hpd-gpios: following information about the hotplug gpio pin. + a) phandle of the gpio controller node. + b) pin number within the gpio controller. + c) optional flags and pull up/down. +- ddc: phandle to the hdmi ddc node +- phy: phandle to the hdmi phy node +- samsung,syscon-phandle: phandle for system controller node for PMU. +- #sound-dai-cells: should be 0. + +Required properties for Exynos 4210, 4212, 5420 and 5433: +- clocks: list of clock IDs from SoC clock driver. + a) hdmi: Gate of HDMI IP bus clock. + b) sclk_hdmi: Gate of HDMI special clock. + c) sclk_pixel: Pixel special clock, one of the two possible inputs of + HDMI clock mux. + d) sclk_hdmiphy: HDMI PHY clock output, one of two possible inputs of + HDMI clock mux. + e) mout_hdmi: It is required by the driver to switch between the 2 + parents i.e. sclk_pixel and sclk_hdmiphy. If hdmiphy is stable + after configuration, parent is set to sclk_hdmiphy else + sclk_pixel. +- clock-names: aliases as per driver requirements for above clock IDs: + "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi". + +Required properties for Exynos 5433: +- clocks: list of clock specifiers according to common clock bindings. + a) hdmi_pclk: Gate of HDMI IP APB bus. + b) hdmi_i_pclk: Gate of HDMI-PHY IP APB bus. + d) i_tmds_clk: Gate of HDMI TMDS clock. + e) i_pixel_clk: Gate of HDMI pixel clock. + f) i_spdif_clk: Gate of HDMI SPDIF clock. + g) oscclk: Oscillator clock, used as parent of following *_user clocks + in case HDMI-PHY is not operational. + h) tmds_clko: TMDS clock generated by HDMI-PHY. + i) tmds_clko_user: MUX used to switch between oscclk and tmds_clko, + respectively if HDMI-PHY is off and operational. + j) pixel_clko: Pixel clock generated by HDMI-PHY. + k) pixel_clko_user: MUX used to switch between oscclk and pixel_clko, + respectively if HDMI-PHY is off and operational. +- clock-names: aliases for above clock specfiers. +- samsung,sysreg: handle to syscon used to control the system registers. + +Example: + + hdmi { + compatible = "samsung,exynos4212-hdmi"; + reg = <0x14530000 0x100000>; + interrupts = <0 95 0>; + hpd-gpios = <&gpx3 7 1>; + ddc = <&hdmi_ddc_node>; + phy = <&hdmi_phy_node>; + samsung,syscon-phandle = <&pmu_system_controller>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmiddc.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmiddc.txt new file mode 100644 index 0000000000000000000000000000000000000000..41eee971562b384813f6bdb93e0a917c10786c04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmiddc.txt @@ -0,0 +1,15 @@ +Device-Tree bindings for hdmiddc driver + +Required properties: +- compatible: value should be one of the following + 1) "samsung,exynos5-hdmiddc" + 2) "samsung,exynos4210-hdmiddc" + +- reg: I2C address of the hdmiddc device. + +Example: + + hdmiddc { + compatible = "samsung,exynos4210-hdmiddc"; + reg = <0x50>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmiphy.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmiphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..162f641f7639c02a27c47cbf8e137c01b0dfc1d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_hdmiphy.txt @@ -0,0 +1,15 @@ +Device-Tree bindings for hdmiphy driver + +Required properties: +- compatible: value should be one of the following: + 1) "samsung,exynos5-hdmiphy" + 2) "samsung,exynos4210-hdmiphy". + 3) "samsung,exynos4212-hdmiphy". +- reg: I2C address of the hdmiphy device. + +Example: + + hdmiphy { + compatible = "samsung,exynos4210-hdmiphy"; + reg = <0x38>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_mixer.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_mixer.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e38128f866b1f8a74856b7c8b6927844d4f8763 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/exynos_mixer.txt @@ -0,0 +1,26 @@ +Device-Tree bindings for mixer driver + +Required properties: +- compatible: value should be one of the following: + 1) "samsung,exynos5-mixer" + 2) "samsung,exynos4210-mixer" + 3) "samsung,exynos4212-mixer" + 4) "samsung,exynos5250-mixer" + 5) "samsung,exynos5420-mixer" + +- reg: physical base address of the mixer and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- clocks: list of clock IDs from SoC clock driver. + a) mixer: Gate of Mixer IP bus clock. + b) sclk_hdmi: HDMI Special clock, one of the two possible inputs of + mixer mux. + c) hdmi: Gate of HDMI IP bus clock, needed together with sclk_hdmi. + +Example: + + mixer { + compatible = "samsung,exynos5250-mixer"; + reg = <0x14450000 0x10000>; + interrupts = <0 94 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/exynos/samsung-fimd.txt b/arch/arm64/boot/dts/vendor/bindings/display/exynos/samsung-fimd.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3096421d42b1dfa3a993fdd919abfaf66536148 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/exynos/samsung-fimd.txt @@ -0,0 +1,107 @@ +Device-Tree bindings for Samsung SoC display controller (FIMD) + +FIMD (Fully Interactive Mobile Display) is the Display Controller for the +Samsung series of SoCs which transfers the image data from a video memory +buffer to an external LCD interface. + +Required properties: +- compatible: value should be one of the following + "samsung,s3c2443-fimd"; /* for S3C24XX SoCs */ + "samsung,s3c6400-fimd"; /* for S3C64XX SoCs */ + "samsung,s5pv210-fimd"; /* for S5PV210 SoC */ + "samsung,exynos3250-fimd"; /* for Exynos3250/3472 SoCs */ + "samsung,exynos4210-fimd"; /* for Exynos4 SoCs */ + "samsung,exynos5250-fimd"; /* for Exynos5250 SoCs */ + "samsung,exynos5420-fimd"; /* for Exynos5420/5422/5800 SoCs */ + +- reg: physical base address and length of the FIMD registers set. + +- interrupts: should contain a list of all FIMD IP block interrupts in the + order: FIFO Level, VSYNC, LCD_SYSTEM. The interrupt specifier + format depends on the interrupt controller used. + +- interrupt-names: should contain the interrupt names: "fifo", "vsync", + "lcd_sys", in the same order as they were listed in the interrupts + property. + +- pinctrl-0: pin control group to be used for this controller. + +- pinctrl-names: must contain a "default" entry. + +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. + +- clock-names: list of clock names sorted in the same order as the clocks + property. Must contain "sclk_fimd" and "fimd". + +Optional Properties: +- power-domains: a phandle to FIMD power domain node. +- samsung,invert-vden: video enable signal is inverted +- samsung,invert-vclk: video clock signal is inverted +- display-timings: timing settings for FIMD, as described in document [1]. + Can be used in case timings cannot be provided otherwise + or to override timings provided by the panel. +- samsung,sysreg: handle to syscon used to control the system registers +- i80-if-timings: timing configuration for lcd i80 interface support. + - cs-setup: clock cycles for the active period of address signal is enabled + until chip select is enabled. + If not specified, the default value(0) will be used. + - wr-setup: clock cycles for the active period of CS signal is enabled until + write signal is enabled. + If not specified, the default value(0) will be used. + - wr-active: clock cycles for the active period of CS is enabled. + If not specified, the default value(1) will be used. + - wr-hold: clock cycles for the active period of CS is disabled until write + signal is disabled. + If not specified, the default value(0) will be used. + + The parameters are defined as: + + VCLK(internal) __|??????|_____|??????|_____|??????|_____|??????|_____|?? + : : : : : + Address Output --:| : : : + Chip Select ???????????????|____________:____________:____________|?? + | wr-setup+1 | | wr-hold+1 | + |<---------->| |<---------->| + Write Enable ????????????????????????????|____________|??????????????? + | wr-active+1| + |<---------->| + Video Data ------------------------------ + +The device node can contain 'port' child nodes according to the bindings defined +in [2]. The following are properties specific to those nodes: +- reg: (required) port index, can be: + 0 - for CAMIF0 input, + 1 - for CAMIF1 input, + 2 - for CAMIF2 input, + 3 - for parallel output, + 4 - for write-back interface + +[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + +SoC specific DT entry: + + fimd@11c00000 { + compatible = "samsung,exynos4210-fimd"; + interrupt-parent = <&combiner>; + reg = <0x11c00000 0x20000>; + interrupt-names = "fifo", "vsync", "lcd_sys"; + interrupts = <11 0>, <11 1>, <11 2>; + clocks = <&clock 140>, <&clock 283>; + clock-names = "sclk_fimd", "fimd"; + power-domains = <&pd_lcd0>; + status = "disabled"; + }; + +Board specific DT entry: + + fimd@11c00000 { + pinctrl-0 = <&lcd_clk &lcd_data24 &pwm1_out>; + pinctrl-names = "default"; + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/faraday,tve200.txt b/arch/arm64/boot/dts/vendor/bindings/display/faraday,tve200.txt new file mode 100644 index 0000000000000000000000000000000000000000..82e3bc0b7485a098def2f449f7fecdede66658a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/faraday,tve200.txt @@ -0,0 +1,54 @@ +* Faraday TV Encoder TVE200 + +Required properties: + +- compatible: must be one of: + "faraday,tve200" + "cortina,gemini-tvc", "faraday,tve200" + +- reg: base address and size of the control registers block + +- interrupts: contains an interrupt specifier for the interrupt + line from the TVE200 + +- clock-names: should contain "PCLK" for the clock line clocking the + silicon and "TVE" for the 27MHz clock to the video driver + +- clocks: contains phandle and clock specifier pairs for the entries + in the clock-names property. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Optional properties: + +- resets: contains the reset line phandle for the block + +Required sub-nodes: + +- port: describes LCD panel signals, following the common binding + for video transmitter interfaces; see + Documentation/devicetree/bindings/media/video-interfaces.txt + This port should have the properties: + reg = <0>; + It should have one endpoint connected to a remote endpoint where + the display is connected. + +Example: + +display-controller@6a000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "faraday,tve200"; + reg = <0x6a000000 0x1000>; + interrupts = <13 IRQ_TYPE_EDGE_RISING>; + resets = <&syscon GEMINI_RESET_TVC>; + clocks = <&syscon GEMINI_CLK_GATE_TVC>, + <&syscon GEMINI_CLK_TVC>; + clock-names = "PCLK", "TVE"; + + port@0 { + reg = <0>; + display_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/fsl,dcu.txt b/arch/arm64/boot/dts/vendor/bindings/display/fsl,dcu.txt new file mode 100644 index 0000000000000000000000000000000000000000..63ec2a624aa9455a3d4c41ff8eca165e4587c96d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/fsl,dcu.txt @@ -0,0 +1,34 @@ +Device Tree bindings for Freescale DCU DRM Driver + +Required properties: +- compatible: Should be one of + * "fsl,ls1021a-dcu". + * "fsl,vf610-dcu". + +- reg: Address and length of the register set for dcu. +- clocks: Handle to "dcu" and "pix" clock (in the order below) + This can be the same clock (e.g. LS1021a) + See ../clocks/clock-bindings.txt for details. +- clock-names: Should be "dcu" and "pix" + See ../clocks/clock-bindings.txt for details. +- big-endian Boolean property, LS1021A DCU registers are big-endian. +- port Video port for the panel output + +Optional properties: +- fsl,tcon: The phandle to the timing controller node. + +Examples: +dcu: dcu@2ce0000 { + compatible = "fsl,ls1021a-dcu"; + reg = <0x0 0x2ce0000 0x0 0x10000>; + clocks = <&platform_clk 0>, <&platform_clk 0>; + clock-names = "dcu", "pix"; + big-endian; + fsl,tcon = <&tcon>; + + port { + dcu_out: endpoint { + remote-endpoint = <&panel_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/fsl,tcon.txt b/arch/arm64/boot/dts/vendor/bindings/display/fsl,tcon.txt new file mode 100644 index 0000000000000000000000000000000000000000..475008747801e64ed3577d74d22d1a57dee2cb4f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/fsl,tcon.txt @@ -0,0 +1,17 @@ +Device Tree bindings for Freescale TCON Driver + +Required properties: +- compatible: Should be one of + * "fsl,vf610-tcon". + +- reg: Address and length of the register set for tcon. +- clocks: From common clock binding: handle to tcon ipg clock. +- clock-names: From common clock binding: Shall be "ipg". + +Examples: +timing-controller@4003d000 { + compatible = "fsl,vf610-tcon"; + reg = <0x4003d000 0x1000>; + clocks = <&clks VF610_CLK_TCON0>; + clock-names = "ipg"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/google,goldfish-fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/google,goldfish-fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..751fa9f51e5d4fab3235af5ab14f0d80af0a59de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/google,goldfish-fb.txt @@ -0,0 +1,17 @@ +Android Goldfish framebuffer + +Android Goldfish framebuffer device used by Android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-fb" +- reg : +- interrupts : + +Example: + + display-controller@1f008000 { + compatible = "google,goldfish-fb"; + interrupts = <0x10>; + reg = <0x1f008000 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/hisilicon/dw-dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/hisilicon/dw-dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..d270bfe4e4e072d49459660fee4381648186a6e3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/hisilicon/dw-dsi.txt @@ -0,0 +1,72 @@ +Device-Tree bindings for DesignWare DSI Host Controller v1.20a driver + +A DSI Host Controller resides in the middle of display controller and external +HDMI converter or panel. + +Required properties: +- compatible: value should be "hisilicon,hi6220-dsi". +- reg: physical base address and length of dsi controller's registers. +- clocks: contains APB clock phandle + clock-specifier pair. +- clock-names: should be "pclk". +- ports: contains DSI controller input and output sub port. + The input port connects to ADE output port with the reg value "0". + The output port with the reg value "1", it could connect to panel or + any other bridge endpoints. + See Documentation/devicetree/bindings/graph.txt for more device graph info. + +A example of HiKey board hi6220 SoC and board specific DT entry: +Example: + +SoC specific: + dsi: dsi@f4107800 { + compatible = "hisilicon,hi6220-dsi"; + reg = <0x0 0xf4107800 0x0 0x100>; + clocks = <&media_ctrl HI6220_DSI_PCLK>; + clock-names = "pclk"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* 0 for input port */ + port@0 { + reg = <0>; + dsi_in: endpoint { + remote-endpoint = <&ade_out>; + }; + }; + }; + }; + + +Board specific: + &dsi { + status = "ok"; + + ports { + /* 1 for output port */ + port@1 { + reg = <1>; + + dsi_out0: endpoint@0 { + remote-endpoint = <&adv7533_in>; + }; + }; + }; + }; + + &i2c2 { + ... + + adv7533: adv7533@39 { + ... + + port { + adv7533_in: endpoint { + remote-endpoint = <&dsi_out0>; + }; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/hisilicon/hisi-ade.txt b/arch/arm64/boot/dts/vendor/bindings/display/hisilicon/hisi-ade.txt new file mode 100644 index 0000000000000000000000000000000000000000..305a0e72a900390326225ccebbabdd65e01e1aa9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/hisilicon/hisi-ade.txt @@ -0,0 +1,64 @@ +Device-Tree bindings for hisilicon ADE display controller driver + +ADE (Advanced Display Engine) is the display controller which grab image +data from memory, do composition, do post image processing, generate RGB +timing stream and transfer to DSI. + +Required properties: +- compatible: value should be "hisilicon,hi6220-ade". +- reg: physical base address and length of the ADE controller's registers. +- hisilicon,noc-syscon: ADE NOC QoS syscon. +- resets: The ADE reset controller node. +- interrupt: the ldi vblank interrupt number used. +- clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. +- clock-names: should contain: + "clk_ade_core" for the ADE core clock. + "clk_codec_jpeg" for the media NOC QoS clock, which use the same clock with + jpeg codec. + "clk_ade_pix" for the ADE pixel clock. +- assigned-clocks: Should contain "clk_ade_core" and "clk_codec_jpeg" clocks' + phandle + clock-specifier pairs. +- assigned-clock-rates: clock rates, one for each entry in assigned-clocks. + The rate of "clk_ade_core" could be "360000000" or "180000000"; + The rate of "clk_codec_jpeg" could be or less than "1440000000". + These rate values could be configured according to performance and power + consumption. +- port: the output port. This contains one endpoint subnode, with its + remote-endpoint set to the phandle of the connected DSI input endpoint. + See Documentation/devicetree/bindings/graph.txt for more device graph info. + +Optional properties: +- dma-coherent: Present if dma operations are coherent. + + +A example of HiKey board hi6220 SoC specific DT entry: +Example: + + ade: ade@f4100000 { + compatible = "hisilicon,hi6220-ade"; + reg = <0x0 0xf4100000 0x0 0x7800>; + reg-names = "ade_base"; + hisilicon,noc-syscon = <&medianoc_ade>; + resets = <&media_ctrl MEDIA_ADE>; + interrupts = <0 115 4>; /* ldi interrupt */ + + clocks = <&media_ctrl HI6220_ADE_CORE>, + <&media_ctrl HI6220_CODEC_JPEG>, + <&media_ctrl HI6220_ADE_PIX_SRC>; + /*clock name*/ + clock-names = "clk_ade_core", + "clk_codec_jpeg", + "clk_ade_pix"; + + assigned-clocks = <&media_ctrl HI6220_ADE_CORE>, + <&media_ctrl HI6220_CODEC_JPEG>; + assigned-clock-rates = <360000000>, <288000000>; + dma-coherent; + + port { + ade_out: endpoint { + remote-endpoint = <&dsi_in>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ht16k33.txt b/arch/arm64/boot/dts/vendor/bindings/display/ht16k33.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5a8b070b46779a410062a624ba9af0b498aaf18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ht16k33.txt @@ -0,0 +1,40 @@ +Holtek ht16k33 RAM mapping 16*8 LED controller driver with keyscan +------------------------------------------------------------------------------- + +Required properties: +- compatible: "holtek,ht16k33" +- reg: I2C slave address of the chip. +- interrupts: Interrupt specification for the key pressed interrupt. +- refresh-rate-hz: Display update interval in HZ. +- debounce-delay-ms: Debouncing interval time in milliseconds. +- linux,keymap: The keymap for keys as described in the binding + document (devicetree/bindings/input/matrix-keymap.txt). + +Optional properties: +- linux,no-autorepeat: Disable keyrepeat. +- default-brightness-level: Initial brightness level [0-15] (default: 15). + +Example: + +&i2c1 { + ht16k33: ht16k33@70 { + compatible = "holtek,ht16k33"; + reg = <0x70>; + refresh-rate-hz = <20>; + debounce-delay-ms = <50>; + interrupt-parent = <&gpio4>; + interrupts = <5 (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)>; + linux,keymap = < + MATRIX_KEY(2, 0, KEY_F6) + MATRIX_KEY(3, 0, KEY_F8) + MATRIX_KEY(4, 0, KEY_F10) + MATRIX_KEY(5, 0, KEY_F4) + MATRIX_KEY(6, 0, KEY_F2) + MATRIX_KEY(2, 1, KEY_F5) + MATRIX_KEY(3, 1, KEY_F7) + MATRIX_KEY(4, 1, KEY_F9) + MATRIX_KEY(5, 1, KEY_F3) + MATRIX_KEY(6, 1, KEY_F1) + >; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ilitek,ili9225.txt b/arch/arm64/boot/dts/vendor/bindings/display/ilitek,ili9225.txt new file mode 100644 index 0000000000000000000000000000000000000000..a59feb52015be1329140529bc9befc5685abee8d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ilitek,ili9225.txt @@ -0,0 +1,25 @@ +Ilitek ILI9225 display panels + +This binding is for display panels using an Ilitek ILI9225 controller in SPI +mode. + +Required properties: +- compatible: "vot,v220hf01a-t", "ilitek,ili9225" +- rs-gpios: Register select signal +- reset-gpios: Reset pin + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional properties: +- rotation: panel rotation in degrees counter clockwise (0,90,180,270) + +Example: + display@0{ + compatible = "vot,v220hf01a-t", "ilitek,ili9225"; + reg = <0>; + spi-max-frequency = <12000000>; + rs-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; + rotation = <270>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ilitek,ili9341.txt b/arch/arm64/boot/dts/vendor/bindings/display/ilitek,ili9341.txt new file mode 100644 index 0000000000000000000000000000000000000000..169b32e4ee4ed63c6028602558b3c27ff753543a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ilitek,ili9341.txt @@ -0,0 +1,27 @@ +Ilitek ILI9341 display panels + +This binding is for display panels using an Ilitek ILI9341 controller in SPI +mode. + +Required properties: +- compatible: "adafruit,yx240qv29", "ilitek,ili9341" +- dc-gpios: D/C pin +- reset-gpios: Reset pin + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional properties: +- rotation: panel rotation in degrees counter clockwise (0,90,180,270) +- backlight: phandle of the backlight device attached to the panel + +Example: + display@0{ + compatible = "adafruit,yx240qv29", "ilitek,ili9341"; + reg = <0>; + spi-max-frequency = <32000000>; + dc-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; + rotation = <270>; + backlight = <&backlight>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/imx/fsl,imx-fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/imx/fsl,imx-fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..e5a8b363d82972dc64133b69be7cc190f4470f56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/imx/fsl,imx-fb.txt @@ -0,0 +1,57 @@ +Freescale imx21 Framebuffer + +This framebuffer driver supports devices imx1, imx21, imx25, and imx27. + +Required properties: +- compatible : "fsl,-fb", chip should be imx1 or imx21 +- reg : Should contain 1 register ranges(address and length) +- interrupts : One interrupt of the fb dev + +Required nodes: +- display: Phandle to a display node as described in + Documentation/devicetree/bindings/display/panel/display-timing.txt + Additional, the display node has to define properties: + - bits-per-pixel: Bits per pixel + - fsl,pcr: LCDC PCR value + A display node may optionally define + - fsl,aus-mode: boolean to enable AUS mode (only for imx21) + +Optional properties: +- lcd-supply: Regulator for LCD supply voltage. +- fsl,dmacr: DMA Control Register value. This is optional. By default, the + register is not modified as recommended by the datasheet. +- fsl,lpccr: Contrast Control Register value. This property provides the + default value for the contrast control register. + If that property is omitted, the register is zeroed. +- fsl,lscr1: LCDC Sharp Configuration Register value. + +Example: + + imxfb: fb@10021000 { + compatible = "fsl,imx21-fb"; + interrupts = <61>; + reg = <0x10021000 0x1000>; + display = <&display0>; + }; + + ... + + display0: display0 { + model = "Primeview-PD050VL1"; + native-mode = <&timing_disp0>; + bits-per-pixel = <16>; + fsl,pcr = <0xf0c88080>; /* non-standard but required */ + display-timings { + timing_disp0: 640x480 { + hactive = <640>; + vactive = <480>; + hback-porch = <112>; + hfront-porch = <36>; + hsync-len = <32>; + vback-porch = <33>; + vfront-porch = <33>; + vsync-len = <2>; + clock-frequency = <25000000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/imx/fsl-imx-drm.txt b/arch/arm64/boot/dts/vendor/bindings/display/imx/fsl-imx-drm.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bf77f6dd19db0ea3eab3cb3f837f54089c2a547 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/imx/fsl-imx-drm.txt @@ -0,0 +1,162 @@ +Freescale i.MX DRM master device +================================ + +The freescale i.MX DRM master device is a virtual device needed to list all +IPU or other display interface nodes that comprise the graphics subsystem. + +Required properties: +- compatible: Should be "fsl,imx-display-subsystem" +- ports: Should contain a list of phandles pointing to display interface ports + of IPU devices + +example: + +display-subsystem { + compatible = "fsl,display-subsystem"; + ports = <&ipu_di0>; +}; + + +Freescale i.MX IPUv3 +==================== + +Required properties: +- compatible: Should be "fsl,-ipu" where is one of + - imx51 + - imx53 + - imx6q + - imx6qp +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain sync interrupt and error interrupt, + in this order. +- resets: phandle pointing to the system reset controller and + reset line index, see reset/fsl,imx-src.txt for details +Additional required properties for fsl,imx6qp-ipu: +- fsl,prg: phandle to prg node associated with this IPU instance +Optional properties: +- port@[0-3]: Port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + Ports 0 and 1 should correspond to CSI0 and CSI1, + ports 2 and 3 should correspond to DI0 and DI1, respectively. + +example: + +ipu: ipu@18000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-ipu"; + reg = <0x18000000 0x080000000>; + interrupts = <11 10>; + resets = <&src 2>; + + ipu_di0: port@2 { + reg = <2>; + + ipu_di0_disp0: endpoint { + remote-endpoint = <&display_in>; + }; + }; +}; + +Freescale i.MX PRE (Prefetch Resolve Engine) +============================================ + +Required properties: +- compatible: should be "fsl,imx6qp-pre" +- reg: should be register base and length as documented in the + datasheet +- clocks : phandle to the PRE axi clock input, as described + in Documentation/devicetree/bindings/clock/clock-bindings.txt and + Documentation/devicetree/bindings/clock/imx6q-clock.txt. +- clock-names: should be "axi" +- interrupts: should contain the PRE interrupt +- fsl,iram: phandle pointing to the mmio-sram device node, that should be + used for the PRE SRAM double buffer. + +example: + +pre@21c8000 { + compatible = "fsl,imx6qp-pre"; + reg = <0x021c8000 0x1000>; + interrupts = ; + clocks = <&clks IMX6QDL_CLK_PRE0>; + clock-names = "axi"; + fsl,iram = <&ocram2>; +}; + +Freescale i.MX PRG (Prefetch Resolve Gasket) +============================================ + +Required properties: +- compatible: should be "fsl,imx6qp-prg" +- reg: should be register base and length as documented in the + datasheet +- clocks : phandles to the PRG ipg and axi clock inputs, as described + in Documentation/devicetree/bindings/clock/clock-bindings.txt and + Documentation/devicetree/bindings/clock/imx6q-clock.txt. +- clock-names: should be "ipg" and "axi" +- fsl,pres: phandles to the PRE units attached to this PRG, with the fixed + PRE as the first entry and the muxable PREs following. + +example: + +prg@21cc000 { + compatible = "fsl,imx6qp-prg"; + reg = <0x021cc000 0x1000>; + clocks = <&clks IMX6QDL_CLK_PRG0_APB>, + <&clks IMX6QDL_CLK_PRG0_AXI>; + clock-names = "ipg", "axi"; + fsl,pres = <&pre1>, <&pre2>, <&pre3>; +}; + +Parallel display support +======================== + +Required properties: +- compatible: Should be "fsl,imx-parallel-display" +Optional properties: +- interface-pix-fmt: How this display is connected to the + display interface. Currently supported types: "rgb24", "rgb565", "bgr666" + and "lvds666". +- edid: verbatim EDID data block describing attached display. +- ddc: phandle describing the i2c bus handling the display data + channel +- port@[0-1]: Port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + Port 0 is the input port connected to the IPU display interface, + port 1 is the output port connected to a panel. + +example: + +disp0 { + compatible = "fsl,imx-parallel-display"; + edid = [edid-data]; + interface-pix-fmt = "rgb24"; + + port@0 { + reg = <0>; + + display_in: endpoint { + remote-endpoint = <&ipu_di0_disp0>; + }; + }; + + port@1 { + reg = <1>; + + display_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; +}; + +panel { + ... + + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/imx/hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/imx/hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d021e71c9cf1d745a04e068a4f90b8b117d3921 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/imx/hdmi.txt @@ -0,0 +1,65 @@ +Freescale i.MX6 DWC HDMI TX Encoder +=================================== + +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with a companion PHY IP. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. + + +Required properties: + +- compatible : Shall be one of "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi". +- reg: See dw_hdmi.txt. +- interrupts: HDMI interrupt number +- clocks: See dw_hdmi.txt. +- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt. +- ports: See dw_hdmi.txt. The DWC HDMI shall have between one and four ports, + numbered 0 to 3, corresponding to the four inputs of the HDMI multiplexer. + Each port shall have a single endpoint. +- gpr : Shall contain a phandle to the iomuxc-gpr region containing the HDMI + multiplexer control register. + +Optional properties + +- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master + or the functionally-reduced I2C master contained in the DWC HDMI. When + connected to a system I2C master this property contains a phandle to that + I2C master controller. + + +Example: + + gpr: iomuxc-gpr@20e0000 { + /* ... */ + }; + + hdmi: hdmi@120000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx6q-hdmi"; + reg = <0x00120000 0x9000>; + interrupts = <0 115 0x04>; + gpr = <&gpr>; + clocks = <&clks 123>, <&clks 124>; + clock-names = "iahb", "isfr"; + ddc-i2c-bus = <&i2c2>; + + port@0 { + reg = <0>; + + hdmi_mux_0: endpoint { + remote-endpoint = <&ipu1_di0_hdmi>; + }; + }; + + port@1 { + reg = <1>; + + hdmi_mux_1: endpoint { + remote-endpoint = <&ipu1_di1_hdmi>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/imx/ldb.txt b/arch/arm64/boot/dts/vendor/bindings/display/imx/ldb.txt new file mode 100644 index 0000000000000000000000000000000000000000..38c637fa39ddf4efaef296a3878859dfb598e82c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/imx/ldb.txt @@ -0,0 +1,147 @@ +Device-Tree bindings for LVDS Display Bridge (ldb) + +LVDS Display Bridge +=================== + +The LVDS Display Bridge device tree node contains up to two lvds-channel +nodes describing each of the two LVDS encoder channels of the bridge. + +Required properties: + - #address-cells : should be <1> + - #size-cells : should be <0> + - compatible : should be "fsl,imx53-ldb" or "fsl,imx6q-ldb". + Both LDB versions are similar, but i.MX6 has an additional + multiplexer in the front to select any of the four IPU display + interfaces as input for each LVDS channel. + - gpr : should be <&gpr> on i.MX53 and i.MX6q. + The phandle points to the iomuxc-gpr region containing the LVDS + control register. +- clocks, clock-names : phandles to the LDB divider and selector clocks and to + the display interface selector clocks, as described in + Documentation/devicetree/bindings/clock/clock-bindings.txt + The following clocks are expected on i.MX53: + "di0_pll" - LDB LVDS channel 0 mux + "di1_pll" - LDB LVDS channel 1 mux + "di0" - LDB LVDS channel 0 gate + "di1" - LDB LVDS channel 1 gate + "di0_sel" - IPU1 DI0 mux + "di1_sel" - IPU1 DI1 mux + On i.MX6q the following additional clocks are needed: + "di2_sel" - IPU2 DI0 mux + "di3_sel" - IPU2 DI1 mux + The needed clock numbers for each are documented in + Documentation/devicetree/bindings/clock/imx5-clock.txt, and in + Documentation/devicetree/bindings/clock/imx6q-clock.txt. + +Optional properties: + - pinctrl-names : should be "default" on i.MX53, not used on i.MX6q + - pinctrl-0 : a phandle pointing to LVDS pin settings on i.MX53, + not used on i.MX6q + - fsl,dual-channel : boolean. if it exists, only LVDS channel 0 should + be configured - one input will be distributed on both outputs in dual + channel mode + +LVDS Channel +============ + +Each LVDS Channel has to contain either an of graph link to a panel device node +or a display-timings node that describes the video timings for the connected +LVDS display as well as the fsl,data-mapping and fsl,data-width properties. + +Required properties: + - reg : should be <0> or <1> + - port: Input and output port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/graph.txt. + On i.MX5, the internal two-input-multiplexer is used. Due to hardware + limitations, only one input port (port@[0,1]) can be used for each channel + (lvds-channel@[0,1], respectively). + On i.MX6, there should be four input ports (port@[0-3]) that correspond + to the four LVDS multiplexer inputs. + A single output port (port@2 on i.MX5, port@4 on i.MX6) must be connected + to a panel input port. Optionally, the output port can be left out if + display-timings are used instead. + +Optional properties (required if display-timings are used): + - ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - display-timings : A node that describes the display timings as defined in + Documentation/devicetree/bindings/display/panel/display-timing.txt. + - fsl,data-mapping : should be "spwg" or "jeida" + This describes how the color bits are laid out in the + serialized LVDS signal. + - fsl,data-width : should be <18> or <24> + +example: + +gpr: iomuxc-gpr@53fa8000 { + /* ... */ +}; + +ldb: ldb@53fa8008 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx53-ldb"; + gpr = <&gpr>; + clocks = <&clks IMX5_CLK_LDB_DI0_SEL>, + <&clks IMX5_CLK_LDB_DI1_SEL>, + <&clks IMX5_CLK_IPU_DI0_SEL>, + <&clks IMX5_CLK_IPU_DI1_SEL>, + <&clks IMX5_CLK_LDB_DI0_GATE>, + <&clks IMX5_CLK_LDB_DI1_GATE>; + clock-names = "di0_pll", "di1_pll", + "di0_sel", "di1_sel", + "di0", "di1"; + + /* Using an of-graph endpoint link to connect the panel */ + lvds-channel@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + port@0 { + reg = <0>; + + lvds0_in: endpoint { + remote-endpoint = <&ipu_di0_lvds0>; + }; + }; + + port@2 { + reg = <2>; + + lvds0_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; + + /* Using display-timings and fsl,data-mapping/width instead */ + lvds-channel@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + fsl,data-mapping = "spwg"; + fsl,data-width = <24>; + + display-timings { + /* ... */ + }; + + port@1 { + reg = <1>; + + lvds1_in: endpoint { + remote-endpoint = <&ipu_di1_lvds1>; + }; + }; + }; +}; + +panel: lvds-panel { + /* ... */ + + port { + panel_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/marvell,pxa2xx-lcdc.txt b/arch/arm64/boot/dts/vendor/bindings/display/marvell,pxa2xx-lcdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..45ffd6c417487692df9ff8507e2fd62ced32846b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/marvell,pxa2xx-lcdc.txt @@ -0,0 +1,36 @@ +PXA LCD Controller +------------------ + +Required properties: + - compatible : one of these + "marvell,pxa2xx-lcdc", + "marvell,pxa270-lcdc", + "marvell,pxa300-lcdc" + - reg : should contain 1 register range (address and length). + - interrupts : framebuffer controller interrupt. + - clocks: phandle to input clocks + +Optional properties: + - lcd-supply: A phandle to a power regulator that controls the LCD voltage. + +Required nodes: + - port: connection to the LCD panel (see video-interfaces.txt) + This node must have its properties bus-width and remote-endpoint set. + If the panel is not a TFT color panel, then a "lcd-type" property in + the panel should specify the panel type. + This panel node should be in the board dts. + +Example: + lcd-controller@40500000 { + compatible = "marvell,pxa2xx-lcdc"; + reg = <0x44000000 0x10000>; + interrupts = <17>; + clocks = <&clks CLK_LCD>; + + port { + lcdc_out: endpoint { + remote-endpoint = <&panel_in>; + bus-width = <16>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/marvell,pxa300-gcu.txt b/arch/arm64/boot/dts/vendor/bindings/display/marvell,pxa300-gcu.txt new file mode 100644 index 0000000000000000000000000000000000000000..9cfae5c4e8ecb839846bd9683647405cc005f746 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/marvell,pxa300-gcu.txt @@ -0,0 +1,17 @@ +PXA3xx GCU Controller +--------------------- + +Required properties: + - compatible : "marvell,pxa300-gcu" + - reg : should contain the register range (address and length). + - interrupts : Controller interrupt. + - clocks: phandle to the PXA specific input clock. + +Example for PXA300: + + display-controller@54000000 { + compatible = "marvell,pxa300-gcu"; + reg = <0x54000000 0x1000>; + interrupts = <39>; + clocks = <&clks CLK_PXA300_GCU>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,disp.txt b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,disp.txt new file mode 100644 index 0000000000000000000000000000000000000000..8469de510001b25cc173b4ab2f44d1e27e9acc21 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,disp.txt @@ -0,0 +1,205 @@ +Mediatek display subsystem +========================== + +The Mediatek display subsystem consists of various DISP function blocks in the +MMSYS register space. The connections between them can be configured by output +and input selectors in the MMSYS_CONFIG register space. Pixel clock and start +of frame signal are distributed to the other function blocks by a DISP_MUTEX +function block. + +All DISP device tree nodes must be siblings to the central MMSYS_CONFIG node. +For a description of the MMSYS_CONFIG binding, see +Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt. + +DISP function blocks +==================== + +A display stream starts at a source function block that reads pixel data from +memory and ends with a sink function block that drives pixels on a display +interface, or writes pixels back to memory. All DISP function blocks have +their own register space, interrupt, and clock gate. The blocks that can +access memory additionally have to list the IOMMU and local arbiter they are +connected to. + +For a description of the display interface sink function blocks, see +Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.txt and +Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt. + +Required properties (all function blocks): +- compatible: "mediatek,-disp-", one of + "mediatek,-disp-ovl" - overlay (4 layers, blending, csc) + "mediatek,-disp-rdma" - read DMA / line buffer + "mediatek,-disp-wdma" - write DMA + "mediatek,-disp-color" - color processor + "mediatek,-disp-aal" - adaptive ambient light controller + "mediatek,-disp-gamma" - gamma correction + "mediatek,-disp-merge" - merge streams from two RDMA sources + "mediatek,-disp-split" - split stream to two encoders + "mediatek,-disp-ufoe" - data compression engine + "mediatek,-dsi" - DSI controller, see mediatek,dsi.txt + "mediatek,-dpi" - DPI controller, see mediatek,dpi.txt + "mediatek,-disp-mutex" - display mutex + "mediatek,-disp-od" - overdrive + the supported chips are mt2701, mt2712 and mt8173. +- reg: Physical base address and length of the function block register space +- interrupts: The interrupt signal from the function block (required, except for + merge and split function blocks). +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. + For most function blocks this is just a single clock input. Only the DSI and + DPI controller nodes have multiple clock inputs. These are documented in + mediatek,dsi.txt and mediatek,dpi.txt, respectively. + +Required properties (DMA function blocks): +- compatible: Should be one of + "mediatek,-disp-ovl" + "mediatek,-disp-rdma" + "mediatek,-disp-wdma" + the supported chips are mt2701 and mt8173. +- larb: Should contain a phandle pointing to the local arbiter device as defined + in Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt +- iommus: Should point to the respective IOMMU block with master port as + argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt + for details. + +Examples: + +mmsys: clock-controller@14000000 { + compatible = "mediatek,mt8173-mmsys", "syscon"; + reg = <0 0x14000000 0 0x1000>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + #clock-cells = <1>; +}; + +ovl0: ovl@1400c000 { + compatible = "mediatek,mt8173-disp-ovl"; + reg = <0 0x1400c000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_OVL0>; + iommus = <&iommu M4U_PORT_DISP_OVL0>; + mediatek,larb = <&larb0>; +}; + +ovl1: ovl@1400d000 { + compatible = "mediatek,mt8173-disp-ovl"; + reg = <0 0x1400d000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_OVL1>; + iommus = <&iommu M4U_PORT_DISP_OVL1>; + mediatek,larb = <&larb4>; +}; + +rdma0: rdma@1400e000 { + compatible = "mediatek,mt8173-disp-rdma"; + reg = <0 0x1400e000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_RDMA0>; + iommus = <&iommu M4U_PORT_DISP_RDMA0>; + mediatek,larb = <&larb0>; +}; + +rdma1: rdma@1400f000 { + compatible = "mediatek,mt8173-disp-rdma"; + reg = <0 0x1400f000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_RDMA1>; + iommus = <&iommu M4U_PORT_DISP_RDMA1>; + mediatek,larb = <&larb4>; +}; + +rdma2: rdma@14010000 { + compatible = "mediatek,mt8173-disp-rdma"; + reg = <0 0x14010000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_RDMA2>; + iommus = <&iommu M4U_PORT_DISP_RDMA2>; + mediatek,larb = <&larb4>; +}; + +wdma0: wdma@14011000 { + compatible = "mediatek,mt8173-disp-wdma"; + reg = <0 0x14011000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_WDMA0>; + iommus = <&iommu M4U_PORT_DISP_WDMA0>; + mediatek,larb = <&larb0>; +}; + +wdma1: wdma@14012000 { + compatible = "mediatek,mt8173-disp-wdma"; + reg = <0 0x14012000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_WDMA1>; + iommus = <&iommu M4U_PORT_DISP_WDMA1>; + mediatek,larb = <&larb4>; +}; + +color0: color@14013000 { + compatible = "mediatek,mt8173-disp-color"; + reg = <0 0x14013000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_COLOR0>; +}; + +color1: color@14014000 { + compatible = "mediatek,mt8173-disp-color"; + reg = <0 0x14014000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_COLOR1>; +}; + +aal@14015000 { + compatible = "mediatek,mt8173-disp-aal"; + reg = <0 0x14015000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_AAL>; +}; + +gamma@14016000 { + compatible = "mediatek,mt8173-disp-gamma"; + reg = <0 0x14016000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_GAMMA>; +}; + +ufoe@1401a000 { + compatible = "mediatek,mt8173-disp-ufoe"; + reg = <0 0x1401a000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_UFOE>; +}; + +dsi0: dsi@1401b000 { + /* See mediatek,dsi.txt for details */ +}; + +dpi0: dpi@1401d000 { + /* See mediatek,dpi.txt for details */ +}; + +mutex: mutex@14020000 { + compatible = "mediatek,mt8173-disp-mutex"; + reg = <0 0x14020000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_MUTEX_32K>; +}; + +od@14023000 { + compatible = "mediatek,mt8173-disp-od"; + reg = <0 0x14023000 0 0x1000>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_DISP_OD>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,dpi.txt b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,dpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6a7e7397b8b47ef4d250fd6f8dba971ee23dc00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,dpi.txt @@ -0,0 +1,35 @@ +Mediatek DPI Device +=================== + +The Mediatek DPI function block is a sink of the display subsystem and +provides 8-bit RGB/YUV444 or 8/10/10-bit YUV422 pixel data on a parallel +output bus. + +Required properties: +- compatible: "mediatek,-dpi" +- reg: Physical base address and length of the controller's registers +- interrupts: The interrupt signal from the function block. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: must contain "pixel", "engine", and "pll" +- port: Output port node with endpoint definitions as described in + Documentation/devicetree/bindings/graph.txt. This port should be connected + to the input port of an attached HDMI or LVDS encoder chip. + +Example: + +dpi0: dpi@1401d000 { + compatible = "mediatek,mt8173-dpi"; + reg = <0 0x1401d000 0 0x1000>; + interrupts = ; + clocks = <&mmsys CLK_MM_DPI_PIXEL>, + <&mmsys CLK_MM_DPI_ENGINE>, + <&apmixedsys CLK_APMIXED_TVDPLL>; + clock-names = "pixel", "engine", "pll"; + + port { + dpi0_out: endpoint { + remote-endpoint = <&hdmi0_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..fadf327c7cdf716f3290bc4b8861bd6396bf8be3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,dsi.txt @@ -0,0 +1,62 @@ +Mediatek DSI Device +=================== + +The Mediatek DSI function block is a sink of the display subsystem and can +drive up to 4-lane MIPI DSI output. Two DSIs can be synchronized for dual- +channel output. + +Required properties: +- compatible: "mediatek,-dsi" + the supported chips are mt2701 and mt8173. +- reg: Physical base address and length of the controller's registers +- interrupts: The interrupt signal from the function block. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: must contain "engine", "digital", and "hs" +- phys: phandle link to the MIPI D-PHY controller. +- phy-names: must contain "dphy" +- port: Output port node with endpoint definitions as described in + Documentation/devicetree/bindings/graph.txt. This port should be connected + to the input port of an attached DSI panel or DSI-to-eDP encoder chip. + +MIPI TX Configuration Module +============================ + +The MIPI TX configuration module controls the MIPI D-PHY. + +Required properties: +- compatible: "mediatek,-mipi-tx" + the supported chips are mt2701 and mt8173. +- reg: Physical base address and length of the controller's registers +- clocks: PLL reference clock +- clock-output-names: name of the output clock line to the DSI encoder +- #clock-cells: must be <0>; +- #phy-cells: must be <0>. + +Example: + +mipi_tx0: mipi-dphy@10215000 { + compatible = "mediatek,mt8173-mipi-tx"; + reg = <0 0x10215000 0 0x1000>; + clocks = <&clk26m>; + clock-output-names = "mipi_tx0_pll"; + #clock-cells = <0>; + #phy-cells = <0>; +}; + +dsi0: dsi@1401b000 { + compatible = "mediatek,mt8173-dsi"; + reg = <0 0x1401b000 0 0x1000>; + interrupts = ; + clocks = <&mmsys MM_DSI0_ENGINE>, <&mmsys MM_DSI0_DIGITAL>, + <&mipi_tx0>; + clock-names = "engine", "digital", "hs"; + phys = <&mipi_tx0>; + phy-names = "dphy"; + + port { + dsi0_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b124242b0c553b7c09e7412a789c831430e6b3c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/mediatek/mediatek,hdmi.txt @@ -0,0 +1,148 @@ +Mediatek HDMI Encoder +===================== + +The Mediatek HDMI encoder can generate HDMI 1.4a or MHL 2.0 signals from +its parallel input. + +Required properties: +- compatible: Should be "mediatek,-hdmi". +- reg: Physical base address and length of the controller's registers +- interrupts: The interrupt signal from the function block. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: must contain "pixel", "pll", "bclk", and "spdif". +- phys: phandle link to the HDMI PHY node. + See Documentation/devicetree/bindings/phy/phy-bindings.txt for details. +- phy-names: must contain "hdmi" +- mediatek,syscon-hdmi: phandle link and register offset to the system + configuration registers. For mt8173 this must be offset 0x900 into the + MMSYS_CONFIG region: <&mmsys 0x900>. +- ports: A node containing input and output port nodes with endpoint + definitions as documented in Documentation/devicetree/bindings/graph.txt. +- port@0: The input port in the ports node should be connected to a DPI output + port. +- port@1: The output port in the ports node should be connected to the input + port of a connector node that contains a ddc-i2c-bus property, or to the + input port of an attached bridge chip, such as a SlimPort transmitter. + +HDMI CEC +======== + +The HDMI CEC controller handles hotplug detection and CEC communication. + +Required properties: +- compatible: Should be "mediatek,-cec" +- reg: Physical base address and length of the controller's registers +- interrupts: The interrupt signal from the function block. +- clocks: device clock + +HDMI DDC +======== + +The HDMI DDC i2c controller is used to interface with the HDMI DDC pins. +The Mediatek's I2C controller is used to interface with I2C devices. + +Required properties: +- compatible: Should be "mediatek,-hdmi-ddc" +- reg: Physical base address and length of the controller's registers +- clocks: device clock +- clock-names: Should be "ddc-i2c". + +HDMI PHY +======== + +The HDMI PHY serializes the HDMI encoder's three channel 10-bit parallel +output and drives the HDMI pads. + +Required properties: +- compatible: "mediatek,-hdmi-phy" +- reg: Physical base address and length of the module's registers +- clocks: PLL reference clock +- clock-names: must contain "pll_ref" +- clock-output-names: must be "hdmitx_dig_cts" on mt8173 +- #phy-cells: must be <0> +- #clock-cells: must be <0> + +Optional properties: +- mediatek,ibias: TX DRV bias current for <1.65Gbps, defaults to 0xa +- mediatek,ibias_up: TX DRV bias current for >1.65Gbps, defaults to 0x1c + +Example: + +cec: cec@10013000 { + compatible = "mediatek,mt8173-cec"; + reg = <0 0x10013000 0 0xbc>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_CEC>; +}; + +hdmi_phy: hdmi-phy@10209100 { + compatible = "mediatek,mt8173-hdmi-phy"; + reg = <0 0x10209100 0 0x24>; + clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>; + clock-names = "pll_ref"; + clock-output-names = "hdmitx_dig_cts"; + mediatek,ibias = <0xa>; + mediatek,ibias_up = <0x1c>; + #clock-cells = <0>; + #phy-cells = <0>; +}; + +hdmi_ddc0: i2c@11012000 { + compatible = "mediatek,mt8173-hdmi-ddc"; + reg = <0 0x11012000 0 0x1c>; + interrupts = ; + clocks = <&pericfg CLK_PERI_I2C5>; + clock-names = "ddc-i2c"; +}; + +hdmi0: hdmi@14025000 { + compatible = "mediatek,mt8173-hdmi"; + reg = <0 0x14025000 0 0x400>; + interrupts = ; + clocks = <&mmsys CLK_MM_HDMI_PIXEL>, + <&mmsys CLK_MM_HDMI_PLLCK>, + <&mmsys CLK_MM_HDMI_AUDIO>, + <&mmsys CLK_MM_HDMI_SPDIF>; + clock-names = "pixel", "pll", "bclk", "spdif"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_pin>; + phys = <&hdmi_phy>; + phy-names = "hdmi"; + mediatek,syscon-hdmi = <&mmsys 0x900>; + assigned-clocks = <&topckgen CLK_TOP_HDMI_SEL>; + assigned-clock-parents = <&hdmi_phy>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + hdmi0_in: endpoint { + remote-endpoint = <&dpi0_out>; + }; + }; + + port@1 { + reg = <1>; + + hdmi0_out: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; + }; + }; +}; + +connector { + compatible = "hdmi-connector"; + type = "a"; + ddc-i2c-bus = <&hdmiddc0>; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi0_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/mipi-dsi-bus.txt b/arch/arm64/boot/dts/vendor/bindings/display/mipi-dsi-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..973c27273772b56f673756954bd43008159afc48 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/mipi-dsi-bus.txt @@ -0,0 +1,98 @@ +MIPI DSI (Display Serial Interface) busses +========================================== + +The MIPI Display Serial Interface specifies a serial bus and a protocol for +communication between a host and up to four peripherals. This document will +define the syntax used to represent a DSI bus in a device tree. + +This document describes DSI bus-specific properties only or defines existing +standard properties in the context of the DSI bus. + +Each DSI host provides a DSI bus. The DSI host controller's node contains a +set of properties that characterize the bus. Child nodes describe individual +peripherals on that bus. + +The following assumes that only a single peripheral is connected to a DSI +host. Experience shows that this is true for the large majority of setups. + +DSI host +-------- + +In addition to the standard properties and those defined by the parent bus of +a DSI host, the following properties apply to a node representing a DSI host. + +Required properties: +- #address-cells: The number of cells required to represent an address on the + bus. DSI peripherals are addressed using a 2-bit virtual channel number, so + a maximum of 4 devices can be addressed on a single bus. Hence the value of + this property should be 1. +- #size-cells: Should be 0. There are cases where it makes sense to use a + different value here. See below. + +DSI peripheral +-------------- + +Peripherals are represented as child nodes of the DSI host's node. Properties +described here apply to all DSI peripherals, but individual bindings may want +to define additional, device-specific properties. + +Required properties: +- reg: The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3. + +Some DSI peripherals respond to more than a single virtual channel. In that +case two alternative representations can be chosen: +- The reg property can take multiple entries, one for each virtual channel + that the peripheral responds to. +- If the virtual channels that a peripheral responds to are consecutive, the + #size-cells can be set to 1. The first cell of each entry in the reg + property is the number of the first virtual channel and the second cell is + the number of consecutive virtual channels. + +Example +------- + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channel 0 */ + peripheral@0 { + compatible = "..."; + reg = <0>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channels 0 and 2 */ + peripheral@0 { + compatible = "..."; + reg = <0, 2>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <1>; + + /* peripheral responds to virtual channels 1, 2 and 3 */ + peripheral@1 { + compatible = "..."; + reg = <1 3>; + }; + + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/dpu.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/dpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad2e8830324e28cc7038446388a9c41762b2ae3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/dpu.txt @@ -0,0 +1,131 @@ +Qualcomm Technologies, Inc. DPU KMS + +Description: + +Device tree bindings for MSM Mobile Display Subsytem(MDSS) that encapsulates +sub-blocks like DPU display controller, DSI and DP interfaces etc. +The DPU display controller is found in SDM845 SoC. + +MDSS: +Required properties: +- compatible: "qcom,sdm845-mdss" +- reg: physical base address and length of contoller's registers. +- reg-names: register region names. The following region is required: + * "mdss" +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt +- clocks: list of clock specifiers for clocks needed by the device. +- clock-names: device clock names, must be in same order as clocks property. + The following clocks are required: + * "iface" + * "bus" + * "core" +- interrupts: interrupt signal from MDSS. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- iommus: phandle of iommu device node. +- #address-cells: number of address cells for the MDSS children. Should be 1. +- #size-cells: Should be 1. +- ranges: parent bus address space is the same as the child bus address space. + +Optional properties: +- assigned-clocks: list of clock specifiers for clocks needing rate assignment +- assigned-clock-rates: list of clock frequencies sorted in the same order as + the assigned-clocks property. + +MDP: +Required properties: +- compatible: "qcom,sdm845-dpu" +- reg: physical base address and length of controller's registers. +- reg-names : register region names. The following region is required: + * "mdp" + * "vbif" +- clocks: list of clock specifiers for clocks needed by the device. +- clock-names: device clock names, must be in same order as clocks property. + The following clocks are required. + * "bus" + * "iface" + * "core" + * "vsync" +- interrupts: interrupt line from DPU to MDSS. +- ports: contains the list of output ports from DPU device. These ports connect + to interfaces that are external to the DPU hardware, such as DSI, DP etc. + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + Port 0 -> DPU_INTF1 (DSI1) + Port 1 -> DPU_INTF2 (DSI2) + +Optional properties: +- assigned-clocks: list of clock specifiers for clocks needing rate assignment +- assigned-clock-rates: list of clock frequencies sorted in the same order as + the assigned-clocks property. + +Example: + + mdss: mdss@ae00000 { + compatible = "qcom,sdm845-mdss"; + reg = <0xae00000 0x1000>; + reg-names = "mdss"; + + power-domains = <&clock_dispcc 0>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, <&gcc GCC_DISP_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; + assigned-clock-rates = <300000000>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_iommu 0>; + + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0xae00000 0xb2008>; + + mdss_mdp: mdp@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0 0x1000 0x8f000>, <0 0xb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <0 0 300000000 19200000>; + + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6b793ca2639d14d28f8456bcca9de1f4c379056 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/dsi.txt @@ -0,0 +1,256 @@ +Qualcomm Technologies Inc. adreno/snapdragon DSI output + +DSI Controller: +Required properties: +- compatible: + * "qcom,mdss-dsi-ctrl" +- reg: Physical base address and length of the registers of controller +- reg-names: The names of register regions. The following regions are required: + * "dsi_ctrl" +- interrupts: The interrupt signal from the DSI block. +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: Phandles to device clocks. +- clock-names: the following clocks are required: + * "mdp_core" + * "iface" + * "bus" + * "core_mmss" + * "byte" + * "pixel" + * "core" + For DSIv2, we need an additional clock: + * "src" + For DSI6G v2.0 onwards, we need also need the clock: + * "byte_intf" +- assigned-clocks: Parents of "byte" and "pixel" for the given platform. +- assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided + by a DSI PHY block. See [1] for details on clock bindings. +- vdd-supply: phandle to vdd regulator device node +- vddio-supply: phandle to vdd-io regulator device node +- vdda-supply: phandle to vdda regulator device node +- phys: phandle to DSI PHY device node +- phy-names: the name of the corresponding PHY device +- syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2) +- ports: Contains 2 DSI controller ports as child nodes. Each port contains + an endpoint subnode as defined in [2] and [3]. + +Optional properties: +- panel@0: Node of panel connected to this DSI controller. + See files in [4] for each supported panel. +- qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is + driving a panel which needs 2 DSI links. +- qcom,master-dsi: Boolean value indicating if the DSI controller is driving + the master link of the 2-DSI panel. +- qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is + driving a 2-DSI panel whose 2 links need receive command simultaneously. +- pinctrl-names: the pin control state names; should contain "default" +- pinctrl-0: the default pinctrl state (active) +- pinctrl-n: the "sleep" pinctrl state +- ports: contains DSI controller input and output ports as children, each + containing one endpoint subnode. + + DSI Endpoint properties: + - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's + input endpoint. For port@1, set to the MDP interface output. See [2] for + device graph info. + + - data-lanes: this describes how the physical DSI data lanes are mapped + to the logical lanes on the given platform. The value contained in + index n describes what physical lane is mapped to the logical lane n + (DATAn, where n lies between 0 and 3). The clock lane position is fixed + and can't be changed. Hence, they aren't a part of the DT bindings. See + [3] for more info on the data-lanes property. + + For example: + + data-lanes = <3 0 1 2>; + + The above mapping describes that the logical data lane DATA0 is mapped to + the physical data lane DATA3, logical DATA1 to physical DATA0, logic DATA2 + to phys DATA1 and logic DATA3 to phys DATA2. + + There are only a limited number of physical to logical mappings possible: + <0 1 2 3> + <1 2 3 0> + <2 3 0 1> + <3 0 1 2> + <0 3 2 1> + <1 0 3 2> + <2 1 0 3> + <3 2 1 0> + +DSI PHY: +Required properties: +- compatible: Could be the following + * "qcom,dsi-phy-28nm-hpm" + * "qcom,dsi-phy-28nm-lp" + * "qcom,dsi-phy-20nm" + * "qcom,dsi-phy-28nm-8960" + * "qcom,dsi-phy-14nm" + * "qcom,dsi-phy-10nm" +- reg: Physical base address and length of the registers of PLL, PHY. Some + revisions require the PHY regulator base address, whereas others require the + PHY lane base address. See below for each PHY revision. +- reg-names: The names of register regions. The following regions are required: + For DSI 28nm HPM/LP/8960 PHYs and 20nm PHY: + * "dsi_pll" + * "dsi_phy" + * "dsi_phy_regulator" + For DSI 14nm and 10nm PHYs: + * "dsi_pll" + * "dsi_phy" + * "dsi_phy_lane" +- clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating + 2 clocks: A byte clock (index 0), and a pixel clock (index 1). +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: Phandles to device clocks. See [1] for details on clock bindings. +- clock-names: the following clocks are required: + * "iface" + For 28nm HPM/LP, 28nm 8960 PHYs: +- vddio-supply: phandle to vdd-io regulator device node + For 20nm PHY: +- vddio-supply: phandle to vdd-io regulator device node +- vcca-supply: phandle to vcca regulator device node + For 14nm PHY: +- vcca-supply: phandle to vcca regulator device node + For 10nm PHY: +- vdds-supply: phandle to vdds regulator device node + +Optional properties: +- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY + regulator is wanted. +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split is enabled, this time should not be higher + than two times the dsi link rate time. + If the property is not specified, then the default value is 14000 us. + +- frame-threshold-time-us: For command mode panels, this specifies the idle + time for dsi controller where no active data is + send to the panel, as controller is done sending + active pixels. If there is no desired DSI clocks + specified, then clocks will be derived from this + threshold time, which has a default value in chipset + based on the CPU processing power. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/graph.txt +[3] Documentation/devicetree/bindings/media/video-interfaces.txt +[4] Documentation/devicetree/bindings/display/panel/ + +Example: + dsi0: dsi@fd922800 { + compatible = "qcom,mdss-dsi-ctrl"; + qcom,dsi-host-index = <0>; + interrupt-parent = <&mdp>; + interrupts = <4 0>; + reg-names = "dsi_ctrl"; + reg = <0xfd922800 0x200>; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = + "bus", + "byte", + "core", + "core_mmss", + "iface", + "mdp_core", + "pixel"; + clocks = + <&mmcc MDSS_AXI_CLK>, + <&mmcc MDSS_BYTE0_CLK>, + <&mmcc MDSS_ESC0_CLK>, + <&mmcc MMSS_MISC_AHB_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_PCLK0_CLK>; + + assigned-clocks = + <&mmcc BYTE0_CLK_SRC>, + <&mmcc PCLK0_CLK_SRC>; + assigned-clock-parents = + <&dsi_phy0 0>, + <&dsi_phy0 1>; + + vdda-supply = <&pma8084_l2>; + vdd-supply = <&pma8084_l22>; + vddio-supply = <&pma8084_l12>; + + phys = <&dsi_phy0>; + phy-names ="dsi-phy"; + + qcom,dual-dsi-mode; + qcom,master-dsi; + qcom,sync-dual-dsi; + + qcom,mdss-mdp-transfer-time-us = <12000>; + frame-threshold-time-us = <800>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&dsi_active>; + pinctrl-1 = <&dsi_suspend>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + remote-endpoint = <&panel_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; + + panel: panel@0 { + compatible = "sharp,lq101r1sx01"; + reg = <0>; + link2 = <&secondary>; + + power-supply = <...>; + backlight = <...>; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; + + dsi_phy0: dsi-phy@fd922a00 { + compatible = "qcom,dsi-phy-28nm-hpm"; + qcom,dsi-phy-index = <0>; + reg-names = + "dsi_pll", + "dsi_phy", + "dsi_phy_regulator"; + reg = <0xfd922a00 0xd4>, + <0xfd922b00 0x2b0>, + <0xfd922d80 0x7b>; + clock-names = "iface"; + clocks = <&mmcc MDSS_AHB_CLK>; + #clock-cells = <1>; + vddio-supply = <&pma8084_l12>; + + qcom,dsi-phy-regulator-ldo-mode; + qcom,panel-allow-phy-poweroff; + qcom,dsi-phy-regulator-min-datarate-bps = <1200000000>; + qcom,panel-force-clock-lane-hs; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/edp.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/edp.txt new file mode 100644 index 0000000000000000000000000000000000000000..eff9daff418cf391ed00423abe4f27626206a314 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/edp.txt @@ -0,0 +1,56 @@ +Qualcomm Technologies Inc. adreno/snapdragon eDP output + +Required properties: +- compatible: + * "qcom,mdss-edp" +- reg: Physical base address and length of the registers of controller and PLL +- reg-names: The names of register regions. The following regions are required: + * "edp" + * "pll_base" +- interrupts: The interrupt signal from the eDP block. +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: the following clocks are required: + * "core" + * "iface" + * "mdp_core" + * "pixel" + * "link" +- #clock-cells: The value should be 1. +- vdda-supply: phandle to vdda regulator device node +- lvl-vdd-supply: phandle to regulator device node which is used to supply power + to HPD receiving chip +- panel-en-gpios: GPIO pin to supply power to panel. +- panel-hpd-gpios: GPIO pin used for eDP hpd. + + +Example: + mdss_edp: qcom,mdss_edp@fd923400 { + compatible = "qcom,mdss-edp"; + reg-names = + "edp", + "pll_base"; + reg = <0xfd923400 0x700>, + <0xfd923a00 0xd4>; + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = + "core", + "pixel", + "iface", + "link", + "mdp_core"; + clocks = + <&mmcc MDSS_EDPAUX_CLK>, + <&mmcc MDSS_EDPPIXEL_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_EDPLINK_CLK>, + <&mmcc MDSS_MDP_CLK>; + #clock-cells = <1>; + vdda-supply = <&pma8084_l12>; + lvl-vdd-supply = <&lvl_vreg>; + panel-en-gpios = <&tlmm 137 0>; + panel-hpd-gpios = <&tlmm 103 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/gpu.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/gpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..43fac0fe09bbaf69bfbc1539ffbf095a3078bba8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/gpu.txt @@ -0,0 +1,38 @@ +Qualcomm adreno/snapdragon GPU + +Required properties: +- compatible: "qcom,adreno-XYZ.W", "qcom,adreno" + for example: "qcom,adreno-306.0", "qcom,adreno" + Note that you need to list the less specific "qcom,adreno" (since this + is what the device is matched on), in addition to the more specific + with the chip-id. +- reg: Physical base address and length of the controller's registers. +- interrupts: The interrupt signal from the gpu. +- clocks: device clocks + See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required: + * "core" + * "iface" + * "mem_iface" + +Example: + +/ { + ... + + gpu: qcom,kgsl-3d0@4300000 { + compatible = "qcom,adreno-320.2", "qcom,adreno"; + reg = <0x04300000 0x20000>; + reg-names = "kgsl_3d0_reg_memory"; + interrupts = ; + interrupt-names = "kgsl_3d0_irq"; + clock-names = + "core", + "iface", + "mem_iface"; + clocks = + <&mmcc GFX3D_CLK>, + <&mmcc GFX3D_AHB_CLK>, + <&mmcc MMSS_IMEM_AHB_CLK>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f90a40da51b2f0c96273c5afeec3e2bce6d485a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/hdmi.txt @@ -0,0 +1,99 @@ +Qualcomm adreno/snapdragon hdmi output + +Required properties: +- compatible: one of the following + * "qcom,hdmi-tx-8996" + * "qcom,hdmi-tx-8994" + * "qcom,hdmi-tx-8084" + * "qcom,hdmi-tx-8974" + * "qcom,hdmi-tx-8660" + * "qcom,hdmi-tx-8960" +- reg: Physical base address and length of the controller's registers +- reg-names: "core_physical" +- interrupts: The interrupt signal from the hdmi block. +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: device clocks + See ../clocks/clock-bindings.txt for details. +- core-vdda-supply: phandle to supply regulator +- hdmi-mux-supply: phandle to mux regulator +- phys: the phandle for the HDMI PHY device +- phy-names: the name of the corresponding PHY device + +Optional properties: +- hpd-gpios: hpd pin +- qcom,hdmi-tx-mux-en-gpios: hdmi mux enable pin +- qcom,hdmi-tx-mux-sel-gpios: hdmi mux select pin +- qcom,hdmi-tx-mux-lpm-gpios: hdmi mux lpm pin +- power-domains: reference to the power domain(s), if available. +- pinctrl-names: the pin control state names; should contain "default" +- pinctrl-0: the default pinctrl state (active) +- pinctrl-1: the "sleep" pinctrl state + +HDMI PHY: +Required properties: +- compatible: Could be the following + * "qcom,hdmi-phy-8660" + * "qcom,hdmi-phy-8960" + * "qcom,hdmi-phy-8974" + * "qcom,hdmi-phy-8084" + * "qcom,hdmi-phy-8996" +- #phy-cells: Number of cells in a PHY specifier; Should be 0. +- reg: Physical base address and length of the registers of the PHY sub blocks. +- reg-names: The names of register regions. The following regions are required: + * "hdmi_phy" + * "hdmi_pll" + For HDMI PHY on msm8996, these additional register regions are required: + * "hdmi_tx_l0" + * "hdmi_tx_l1" + * "hdmi_tx_l3" + * "hdmi_tx_l4" +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- core-vdda-supply: phandle to vdda regulator device node + +Example: + +/ { + ... + + hdmi: hdmi@4a00000 { + compatible = "qcom,hdmi-tx-8960"; + reg-names = "core_physical"; + reg = <0x04a00000 0x2f0>; + interrupts = ; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = + "core", + "master_iface", + "slave_iface"; + clocks = + <&mmcc HDMI_APP_CLK>, + <&mmcc HDMI_M_AHB_CLK>, + <&mmcc HDMI_S_AHB_CLK>; + qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>; + qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>; + qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>; + core-vdda-supply = <&pm8921_hdmi_mvs>; + hdmi-mux-supply = <&ext_3p3v>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hpd_active &ddc_active &cec_active>; + pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>; + + phys = <&hdmi_phy>; + phy-names = "hdmi_phy"; + }; + + hdmi_phy: phy@4a00400 { + compatible = "qcom,hdmi-phy-8960"; + reg-names = "hdmi_phy", + "hdmi_pll"; + reg = <0x4a00400 0x60>, + <0x4a00500 0x100>; + #phy-cells = <0>; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = "slave_iface"; + clocks = <&mmcc HDMI_S_AHB_CLK>; + core-vdda-supply = <&pm8921_hdmi_mvs>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/mdp4.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdp4.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c341a15ccdc6a51ad3bf313d2b0ec9566a0d5f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdp4.txt @@ -0,0 +1,112 @@ +Qualcomm adreno/snapdragon MDP4 display controller + +Description: + +This is the bindings documentation for the MDP4 display controller found in +SoCs like MSM8960, APQ8064 and MSM8660. + +Required properties: +- compatible: + * "qcom,mdp4" - mdp4 +- reg: Physical base address and length of the controller's registers. +- interrupts: The interrupt signal from the display controller. +- clocks: device clocks + See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. + * "core_clk" + * "iface_clk" + * "bus_clk" + * "lut_clk" + * "hdmi_clk" + * "tv_clk" +- ports: contains the list of output ports from MDP. These connect to interfaces + that are external to the MDP hardware, such as HDMI, DSI, EDP etc (LVDS is a + special case since it is a part of the MDP block itself). + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + The output port mappings are: + Port 0 -> LCDC/LVDS + Port 1 -> DSI1 Cmd/Video + Port 2 -> DSI2 Cmd/Video + Port 3 -> DTV + +Optional properties: +- clock-names: the following clocks are optional: + * "lut_clk" + +Example: + +/ { + ... + + hdmi: hdmi@4a00000 { + ... + ports { + ... + port@0 { + reg = <0>; + hdmi_in: endpoint { + remote-endpoint = <&mdp_dtv_out>; + }; + }; + ... + }; + ... + }; + + ... + + mdp: mdp@5100000 { + compatible = "qcom,mdp4"; + reg = <0x05100000 0xf0000>; + interrupts = ; + clock-names = + "core_clk", + "iface_clk", + "lut_clk", + "hdmi_clk", + "tv_clk"; + clocks = + <&mmcc MDP_CLK>, + <&mmcc MDP_AHB_CLK>, + <&mmcc MDP_AXI_CLK>, + <&mmcc MDP_LUT_CLK>, + <&mmcc HDMI_TV_CLK>, + <&mmcc MDP_TV_CLK>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp_lvds_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + mdp_dsi1_out: endpoint { + }; + }; + + port@2 { + reg = <2>; + mdp_dsi2_out: endpoint { + }; + }; + + port@3 { + reg = <3>; + mdp_dtv_out: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/mdp5.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdp5.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e11338548aa7a8474dbd5a7ceaf2a759394edfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdp5.txt @@ -0,0 +1,158 @@ +Qualcomm adreno/snapdragon MDP5 display controller + +Description: + +This is the bindings documentation for the Mobile Display Subsytem(MDSS) that +encapsulates sub-blocks like MDP5, DSI, HDMI, eDP etc, and the MDP5 display +controller found in SoCs like MSM8974, APQ8084, MSM8916, MSM8994 and MSM8996. + +MDSS: +Required properties: +- compatible: + * "qcom,mdss" - MDSS +- reg: Physical base address and length of the controller's registers. +- reg-names: The names of register regions. The following regions are required: + * "mdss_phys" + * "vbif_phys" +- interrupts: The interrupt signal from MDSS. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt +- clocks: device clocks. See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. + * "iface" + * "bus" + * "vsync" +- #address-cells: number of address cells for the MDSS children. Should be 1. +- #size-cells: Should be 1. +- ranges: parent bus address space is the same as the child bus address space. + +Optional properties: +- clock-names: the following clocks are optional: + * "lut" + +MDP5: +Required properties: +- compatible: + * "qcom,mdp5" - MDP5 +- reg: Physical base address and length of the controller's registers. +- reg-names: The names of register regions. The following regions are required: + * "mdp_phys" +- interrupts: Interrupt line from MDP5 to MDSS interrupt controller. +- clocks: device clocks. See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. +- * "bus" +- * "iface" +- * "core" +- * "vsync" +- ports: contains the list of output ports from MDP. These connect to interfaces + that are external to the MDP hardware, such as HDMI, DSI, EDP etc (LVDS is a + special case since it is a part of the MDP block itself). + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + The availability of output ports can vary across SoC revisions: + + For MSM8974 and APQ8084: + Port 0 -> MDP_INTF0 (eDP) + Port 1 -> MDP_INTF1 (DSI1) + Port 2 -> MDP_INTF2 (DSI2) + Port 3 -> MDP_INTF3 (HDMI) + + For MSM8916: + Port 0 -> MDP_INTF1 (DSI1) + + For MSM8994 and MSM8996: + Port 0 -> MDP_INTF1 (DSI1) + Port 1 -> MDP_INTF2 (DSI2) + Port 2 -> MDP_INTF3 (HDMI) + +Optional properties: +- clock-names: the following clocks are optional: + * "lut" + +Example: + +/ { + ... + + mdss: mdss@1a00000 { + compatible = "qcom,mdss"; + reg = <0x1a00000 0x1000>, + <0x1ac8000 0x3000>; + reg-names = "mdss_phys", "vbif_phys"; + + power-domains = <&gcc MDSS_GDSC>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "vsync" + + interrupts = <0 72 0>; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mdp: mdp@1a01000 { + compatible = "qcom,mdp5"; + reg = <0x1a01000 0x90000>; + reg-names = "mdp_phys"; + + interrupt-parent = <&mdss>; + interrupts = <0 0>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_MDP_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "core", + "vsync"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp5_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; + + dsi0: dsi@1a98000 { + ... + ports { + ... + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp5_intf1_out>; + }; + }; + ... + }; + ... + }; + + dsi_phy0: dsi-phy@1a98300 { + ... + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/mdss-dsi-panel.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdss-dsi-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1f83f6f43fd216bfa36167cfe7f9e486d4ac9dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdss-dsi-panel.txt @@ -0,0 +1,843 @@ +QTI mdss-dsi-panel + +mdss-dsi-panel is a dsi panel device which supports panels that +are compatible with MIPI display serial interface specification. + +Required properties: +- compatible: This property applies to DSI V2 panels only. + This property should not be added for panels + that work based on version "V6.0" + DSI panels that are of different versions + are initialized by the drivers for dsi controller. + This property specifies the version + for DSI HW that this panel will work with + "qcom,dsi-panel-v2" = DSI V2.0 +- status: This property applies to DSI V2 panels only. + This property should not be added for panels + that work based on version "V6.0" + DSI panels that are of different versions + are initialized by the drivers for dsi controller. + A string that has to be set to "okay/ok" + to enable the panel driver. By default this property + will be set to "disable". Will be set to "ok/okay" + status for specific platforms. +- qcom,mdss-dsi-panel-controller: Specifies the phandle for the DSI controller that + this panel will be mapped to. +- qcom,mdss-dsi-panel-width: Specifies panel width in pixels. +- qcom,mdss-dsi-panel-height: Specifies panel height in pixels. +- qcom,mdss-dsi-bpp: Specifies the panel bits per pixel. + 3 = for rgb111 + 8 = for rgb332 + 12 = for rgb444 + 16 = for rgb565 + 18 = for rgb666 + 24 = for rgb888 +- qcom,mdss-dsi-panel-destination: A string that specifies the destination display for the panel. + "display_1" = DISPLAY_1 + "display_2" = DISPLAY_2 +- qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY + timing settings for the panel. +- qcom,mdss-dsi-panel-timings-8996: An array of length 40 char that specifies the 8996 PHY lane + timing settings for the panel. +- qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-off-command: A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are + sent after displaying an image. + +Note, if a short DCS packet(i.e packet with Byte 0:dcs data type as 05) mentioned in +qcom,mdss-dsi-on-command/qcom,mdss-dsi-off-command stream fails to transmit, +then 3 options can be tried. + 1. Send the packet as a long packet instead + Byte 0: dcs data type = 05 (DCS short Packet) + Byte 0: dcs data type = 29 (DCS long Packet) + 2. Send the packet in one burst by prepending with the next packet in packet stream + Byte 1 = 01 (indicates this is an individual packet) + Byte 1 = 00 (indicates this will be appended to the next + individual packet in the packet stream) + 3. Prepend a NULL packet to the short packet and send both in one burst instead of + combining multiple short packets and sending them in one burst. + +Optional properties: +- qcom,mdss-dsi-panel-name: A string used as a descriptive name of the panel +- qcom,mdss-dsi-physical-type: A string used as a decriptive type of the panel. + "oled" : That indicate it's an OLED panel. + "lcd" : That indicate it's an LCD panel. + If it is not set, consider it is a LCD panel as default. +- qcom,mdss-dsi-panel-phy-timings: An array of length 'n' char that specifies the DSI PHY lane + timing settings for the panel. This is specific to SDE DRM driver. + The value of 'n' depends on the DSI PHY h/w revision and parsing this + property properly will be taken care in the DSI PHY DRM driver. +- qcom,cmd-sync-wait-broadcast: Boolean used to broadcast dcs command to panels. +- qcom,mdss-dsi-fbc-enable: Boolean used to enable frame buffer compression mode. +- qcom,mdss-dsi-panel-mode-switch: Boolean used to enable panel operating mode switch. +- qcom,mdss-dsi-fbc-slice-height: Slice height(in lines) of compressed block. + Expressed as power of 2. To set as 128 lines, + this should be set to 7. +- qcom,mdss-dsi-fbc-2d-pred-mode: Boolean to enable 2D map prediction. +- qcom,mdss-dsi-fbc-ver2-mode: Boolean to enable FBC 2.0 that supports 1/3 + compression. +- qcom,mdss-dsi-fbc-bpp: Compressed bpp supported by the panel. + Specified color order is used as default value. +- qcom,mdss-dsi-fbc-packing: Component packing. + 0 = default value. +- qcom,mdss-dsi-fbc-quant-error: Boolean used to enable quantization error calculation. +- qcom,mdss-dsi-fbc-bias: Bias for CD. + 0 = default value. +- qcom,mdss-dsi-fbc-pat-mode: Boolean used to enable PAT mode. +- qcom,mdss-dsi-fbc-vlc-mode: Boolean used to enable VLC mode. +- qcom,mdss-dsi-fbc-bflc-mode: Boolean used to enable BFLC mode. +- qcom,mdss-dsi-fbc-h-line-budget: Per line extra budget. + 0 = default value. +- qcom,mdss-dsi-fbc-budget-ctrl: Extra budget level. + 0 = default value. +- qcom,mdss-dsi-fbc-block-budget: Per block budget. + 0 = default value. +- qcom,mdss-dsi-fbc-lossless-threshold: Lossless mode threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-lossy-threshold: Lossy mode threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-rgb-threshold: Lossy RGB threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-lossy-mode-idx: Lossy mode index value. + 0 = default value. +- qcom,mdss-dsi-fbc-max-pred-err: Max quantization prediction error. + 0 = default value +- qcom,mdss-dsi-h-back-porch: Horizontal back porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-h-front-porch: Horizontal front porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-h-pulse-width: Horizontal pulse width. + 2 = default value. +- qcom,mdss-dsi-h-sync-skew: Horizontal sync skew value. + 0 = default value. +- qcom,mdss-dsi-v-back-porch: Vertical back porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-v-front-porch: Vertical front porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-v-pulse-width: Vertical pulse width. + 2 = default value. +- qcom,mdss-dsi-h-left-border: Horizontal left border in pixel. + 0 = default value +- qcom,mdss-dsi-h-right-border: Horizontal right border in pixel. + 0 = default value +- qcom,mdss-dsi-v-top-border: Vertical top border in pixel. + 0 = default value +- qcom,mdss-dsi-v-bottom-border: Vertical bottom border in pixel. + 0 = default value +- qcom,mdss-dsi-underflow-color: Specifies the controller settings for the + panel under flow color. + 0xff = default value. +- qcom,mdss-dsi-border-color: Defines the border color value if border is present. + 0 = default value. +- qcom,mdss-dsi-panel-jitter: Panel jitter value is expressed in terms of numerator + and denominator. It contains two u32 values - numerator + followed by denominator. The jitter configurition causes + the early wakeup if panel needs to adjust before vsync. + Default jitter value is 2.0%. Max allowed value is 10%. +- qcom,mdss-dsi-panel-prefill-lines: An integer value defines the panel prefill lines required to + calculate the backoff time of rsc. + Default value is 16 lines. Max allowed value is vtotal. +- qcom,mdss-dsi-pan-enable-dynamic-fps: Boolean used to enable change in frame rate dynamically. +- qcom,mdss-dsi-pan-fps-update: A string that specifies when to change the frame rate. + "dfps_suspend_resume_mode"= FPS change request is + implemented during suspend/resume. + "dfps_immediate_clk_mode" = FPS change request is + implemented immediately using DSI clocks. + "dfps_immediate_porch_mode_hfp" = FPS change request is + implemented immediately by changing panel horizontal + front porch values. + "dfps_immediate_porch_mode_vfp" = FPS change request is + implemented immediately by changing panel vertical + front porch values. +- qcom,min-refresh-rate: Minimum refresh rate supported by the panel. +- qcom,max-refresh-rate: Maximum refresh rate supported by the panel. If max refresh + rate is not specified, then the frame rate of the panel in + qcom,mdss-dsi-panel-framerate is used. +- qcom,dsi-dyn-clk-enable: Boolean to indicate dsi dynamic clock switch feature + is supported. +- qcom,dsi-dyn-clk-list: An u32 array which lists all the supported dsi bit clock + frequencies in Hz for the given panel. +- qcom,dsi-dyn-clk-type: A string that specifies the sub-type for the dynamic + clk feature. If dyn clk type is not specified, default + value "legacy" is used. + "legacy" = FPS is not maintained after dynamic clock switch. + "constant-fps-adjust-hfp" = FPS is maintained even after + dynamic clock switch by changing panel horizontal front + porch values. + "constant-fps-adjust-vfp" = FPS is maintained even after + dynamic clock switch by changing panel vertical front + porch values. + This dyn-clk-type entry is an optional binding which is + contingent on the enabling of dynamic clock switch. +- qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight + control for this panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + "bl_ctrl_dcs" = Backlight controlled by DCS commands. + "bl_ctrl_external" = Backlight controlled by externally + other: Unknown backlight control. (default) +- qcom,mdss-dsi-sec-bl-pmic-control-type: A string that specifies the implementation of backlight + control for secondary panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + "bl_ctrl_dcs" = Backlight controlled by DCS commands. + "bl_ctrl_external" = Backlight controlled by externally + other: Unknown backlight control. (default) +- qcom,mdss-dsi-bl-pwm-pmi: Boolean to indicate that PWM control is through second pmic chip. +- qcom,mdss-dsi-bl-pmic-bank-select: LPG channel for backlight. + Required if backlight pmic control type is PWM +- qcom,mdss-dsi-bl-pmic-pwm-frequency: PWM period in microseconds. + Required if backlight pmic control type is PWM +- qcom,mdss-dsi-pwm-gpio: PMIC gpio binding to backlight. + Required if backlight pmic control type is PWM +- qcom,mdss-dsi-bl-min-level: Specifies the min backlight level supported by the panel. + 0 = default value. +- qcom,mdss-dsi-bl-max-level: Specifies the max backlight level supported by the panel. + 255 = default value. +- qcom,mdss-dsi-bl-inverted-dbv: A boolean to specify whether to invert the display brightness value. + When this boolean is set, will inverted display brightness value. +- qcom,mdss-brightness-max-level: Specifies the max brightness level supported. + 255 = default value. +- qcom,bl-update-flag: A string that specifies controls for backlight update of the panel. + "delay_until_first_frame" = Delay backlight update of the panel + until the first frame is received from the HW. +- qcom,mdss-dsi-interleave-mode: Specifies interleave mode. + 0 = default value. +- qcom,mdss-dsi-panel-type: Specifies the panel operating mode. + "dsi_video_mode" = enable video mode (default). + "dsi_cmd_mode" = enable command mode. +- qcom,5v-boost-gpio: Specifies the panel gpio for display 5v boost. +- qcom,mdss-dsi-te-check-enable: Boolean to enable Tear Check configuration. +- qcom,mdss-dsi-te-using-wd: Boolean entry enables the watchdog timer support to generate the vsync signal + for command mode panel. By default, panel TE will be used to generate the vsync. +- qcom,mdss-dsi-te-using-te-pin: Boolean to specify whether using hardware vsync. +- qcom,mdss-dsi-qsync-min-refresh-rate: A u32 entry to specify minimum refresh rate supported by the panel to enable qsync feature. +- qcom,mdss-dsi-qsync-on-commands: String that specifies the commands to enable qsync feature. +- qcom,mdss-dsi-qsync-on-commands-state: String that specifies the ctrl state for sending qsync on commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-qsync-off-commands: String that specifies the commands to disable qsync feature. +- qcom,mdss-dsi-qsync-off-commands-state: String that specifies the ctrl state for sending qsync off commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-te-pin-select: Specifies TE operating mode. + 0 = TE through embedded dcs command + 1 = TE through TE gpio pin. (default) +- qcom,mdss-dsi-te-dcs-command: Inserts the dcs command. + 1 = default value. +- qcom,mdss-dsi-wr-mem-start: DCS command for write_memory_start. + 0x2c = default value. +- qcom,mdss-dsi-wr-mem-continue: DCS command for write_memory_continue. + 0x3c = default value. +- qcom,mdss-dsi-h-sync-pulse: Specifies the pulse mode option for the panel. + 0 = Don't send hsa/he following vs/ve packet(default) + 1 = Send hsa/he following vs/ve packet +- qcom,mdss-dsi-hfp-power-mode: Boolean to determine DSI lane state during + horizontal front porch (HFP) blanking period. +- qcom,mdss-dsi-hbp-power-mode: Boolean to determine DSI lane state during + horizontal back porch (HBP) blanking period. +- qcom,mdss-dsi-hsa-power-mode: Boolean to determine DSI lane state during + horizontal sync active (HSA) mode. +- qcom,mdss-dsi-last-line-interleave Boolean to determine if last line + interleave flag needs to be enabled. +- qcom,mdss-dsi-bllp-eof-power-mode: Boolean to determine DSI lane state during + blanking low power period (BLLP) EOF mode. +- qcom,mdss-dsi-bllp-power-mode: Boolean to determine DSI lane state during + blanking low power period (BLLP) mode. +- qcom,mdss-dsi-traffic-mode: Specifies the panel traffic mode. + "non_burst_sync_pulse" = non burst with sync pulses (default). + "non_burst_sync_event" = non burst with sync start event. + "burst_mode" = burst mode. +- qcom,mdss-dsi-pixel-packing: Specifies if pixel packing is used (in case of RGB666). + "tight" = Tight packing (default value). + "loose" = Loose packing. +- qcom,mdss-dsi-virtual-channel-id: Specifies the virtual channel identefier. + 0 = default value. +- qcom,mdss-dsi-color-order: Specifies the R, G and B channel ordering. + "rgb_swap_rgb" = DSI_RGB_SWAP_RGB (default value) + "rgb_swap_rbg" = DSI_RGB_SWAP_RBG + "rgb_swap_brg" = DSI_RGB_SWAP_BRG + "rgb_swap_grb" = DSI_RGB_SWAP_GRB + "rgb_swap_gbr" = DSI_RGB_SWAP_GBR +- qcom,mdss-dsi-lane-0-state: Boolean that specifies whether data lane 0 is enabled. +- qcom,mdss-dsi-lane-1-state: Boolean that specifies whether data lane 1 is enabled. +- qcom,mdss-dsi-lane-2-state: Boolean that specifies whether data lane 2 is enabled. +- qcom,mdss-dsi-lane-3-state: Boolean that specifies whether data lane 3 is enabled. +- qcom,mdss-dsi-t-clk-post: Specifies the byte clock cycles after mode switch. + 0x00 = default value. +- qcom,mdss-dsi-t-clk-pre: Specifies the byte clock cycles before mode switch. + 0x00 = default value. +- qcom,mdss-dsi-t-clk-pre-extend: Boolean that specifies whether to enable t_clk_pre counter + increment by 2 byteclk. +- qcom,mdss-dsi-stream: Specifies the packet stream to be used. + 0 = stream 0 (default) + 1 = stream 1 +- qcom,mdss-dsi-mdp-trigger: Specifies the trigger mechanism to be used for MDP path. + "none" = no trigger + "trigger_te" = Tear check signal line used for trigger + "trigger_sw" = Triggered by software (default) + "trigger_sw_te" = Software trigger and TE +- qcom,mdss-dsi-dma-trigger: Specifies the trigger mechanism to be used for DMA path. + "none" = no trigger + "trigger_te" = Tear check signal line used for trigger + "trigger_sw" = Triggered by software (default) + "trigger_sw_seof" = Software trigger and start/end of frame trigger. + "trigger_sw_te" = Software trigger and TE +- qcom,mdss-dsi-panel-framerate: Specifies the frame rate for the panel. + 60 = 60 frames per second (default) +- qcom,mdss-dsi-panel-clockrate: A 64 bit value specifies the panel clock speed in Hz. + 0 = default value. +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split enabled, this time should not be higher + than two times the dsi link rate time. + 14000 = default value. +- qcom,mdss-dsi-on-command-state: String that specifies the ctrl state for sending ON commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-off-command-state: String that specifies the ctrl state for sending OFF commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-post-mode-switch-on-command-state: String that specifies the ctrl state for sending ON commands post mode switch. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-pan-physical-width-dimension: Specifies panel physical width in mm which corresponds + to the physical width in the framebuffer information. +- qcom,mdss-pan-physical-height-dimension: Specifies panel physical height in mm which corresponds + to the physical height in the framebuffer information. +- qcom,mdss-dsi-panel-test-pin: Specifies the panel test gpio. +- qcom,mdss-dsi-mode-sel-gpio-state: String that specifies the lcd mode for panel + (such as single-port/dual-port), if qcom,panel-mode-gpio + binding is defined in dsi controller. + "dual_port" = Set GPIO to LOW + "single_port" = Set GPIO to HIGH + "high" = Set GPIO to HIGH + "low" = Set GPIO to LOW + The default value is "dual_port". +- qcom,mdss-tear-check-disable: Boolean to disable mdp tear check. Tear check is enabled by default to avoid + tearing. Other tear-check properties are ignored if this property is present. + The below tear check configuration properties can be individually tuned if + tear check is enabled. +- qcom,mdss-tear-check-sync-cfg-height: Specifies the vertical total number of lines. + The default value is 0xfff0. +- qcom,mdss-tear-check-sync-init-val: Specifies the init value at which the read pointer gets loaded + at vsync edge. The reader pointer refers to the line number of + panel buffer that is currently being updated. + The default value is panel height. +- qcom,mdss-tear-check-sync-threshold-start: + Allows the first ROI line write to an panel when read pointer is + between the range of ROI start line and ROI start line plus this + setting. + The default value is 4. +- qcom,mdss-tear-check-sync-threshold-continue: + The minimum number of lines the write pointer needs to be + above the read pointer so that it is safe to write to the panel. + (This check is not done for the first ROI line write of an update) + The default value is 4. +- qcom,mdss-tear-check-start-pos: Specify the y position from which the start_threshold value is + added and write is kicked off if the read pointer falls within that + region. + The default value is panel height. +- qcom,mdss-tear-check-rd-ptr-trigger-intr: + Specify the read pointer value at which an interrupt has to be + generated. + The default value is panel height + 1. +- qcom,mdss-tear-check-frame-rate: Specify the value to be a real frame rate(fps) x 100 factor to tune the + timing of TE simulation with more precision. + The default value is 6000 with 60 fps. +- qcom,mdss-dsi-reset-sequence: An array that lists the + sequence of reset gpio values and sleeps + Each command will have the format defined + as below: + --> Reset GPIO value + --> Sleep value (in ms) +- qcom,partial-update-enabled: String used to enable partial + panel update for command mode panels. + "none": partial update is disabled + "single_roi": default enable mode, only single roi is sent to panel + "dual_roi": two rois are merged into one big roi. Panel ddic should be able + to process two roi's along with the DCS command to send two rois. + disabled if property is not specified. This property is specified + per timing node to support resolution restrictions. +- qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating + additional idle time in dsi clock cycles that is needed + to compensate for smaller line width. +- qcom,partial-update-roi-merge: Boolean indicates roi combination is need + and function has been provided for dcs + 2A/2B command. This property is specified per timing node to support + resolution restrictions. +- qcom,dcs-cmd-by-left: Boolean to indicate that dcs command are sent + through the left DSI controller only in a dual-dsi configuration +- qcom,mdss-dsi-panel-hdr-enabled: Boolean to indicate HDR support in panel. +- qcom,mdss-dsi-panel-hdr-color-primaries: + Array of 8 unsigned integers denoting chromaticity of panel.These + values are specified in nits units. The value range is 0 through 50000. + To obtain real chromacity, these values should be divided by factor of + 50000. The structure of array is defined in below order + value 1: x value of white chromaticity of display panel + value 2: y value of white chromaticity of display panel + value 3: x value of red chromaticity of display panel + value 4: y value of red chromaticity of display panel + value 5: x value of green chromaticity of display panel + value 6: y value of green chromaticity of display panel + value 7: x value of blue chromaticity of display panel + value 8: y value of blue chromaticity of display panel +- qcom,mdss-dsi-panel-peak-brightness: Maximum brightness supported by panel.In absence of maximum value + typical value becomes peak brightness. Value is specified in nits units. + To obtain real peak brightness, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-panel-blackness-level: Blackness level supported by panel. Blackness level is defined as + ratio of peak brightness to contrast. Value is specified in nits units. + To obtain real blackness level, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-lp11-init: Boolean used to enable the DSI clocks and data lanes (low power 11) + before issuing hardware reset line. +- qcom,mdss-dsi-init-delay-us: Delay in microseconds(us) before performing any DSI activity in lp11 + mode. This master delay (t_init_delay as per DSI spec) should be sum + of DSI internal delay to reach fuctional after power up and minimum + delay required by panel to reach functional. +- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets. +- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets. +- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode. +- qcom,suspend-ulps-enabled: Boolean to enable support for ULPS mode for panels during suspend state. +- qcom,platform-reset-gpio-always-on: Boolean to keep display reset gpio on during suspend. +- qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its + left, top, width, height alignments and minimum width and + height values. This property is specified per timing node to support + resolution's alignment restrictions. +- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. +- qcom,mdss-dsi-panel-status-command: A byte stream formed by multiple dcs packets based on + qcom dsi controller protocol, to read the panel status. + This value is used to kick in the ESD recovery. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-panel-status-command-mode: + String that specifies the ctrl state for reading the panel status. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-lp1-command: An optional byte stream to request low + power mode on a panel +- qcom,mdss-dsi-lp1-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-lp2-command: An optional byte stream to request ultra + low power mode on a panel +- qcom,mdss-dsi-lp2-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-nolp-command: An optional byte stream to disable low + power and ultra low power panel modes +- qcom,mdss-dsi-nolp-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. + "bta_check" = Uses BTA to check the panel status + "reg_read" = Reads panel status register to check the panel status + "reg_read_nt35596" = Reads panel status register to check the panel + status for NT35596 panel. + "te_signal_check" = Uses TE signal behaviour to check the panel status +- qcom,mdss-dsi-panel-status-read-length: Integer array that specify the expected read-back length of values + for each of panel registers. Each length is corresponding to number of + returned parameters of register introduced in specification. +- qcom,mdss-dsi-panel-status-valid-params: Integer array that specify the valid returned values which need to check + for each of register. + Some panel need only check the first few values returned from panel. + So: if this property is the same to qcom,mdss-dsi-panel-status-read-length, + then just ignore this one. +- qcom,mdss-dsi-panel-status-value: Multiple integer arrays, each specifies the values of the panel status register + which is used to check the panel status. The size of each array is the sum of + length specified in qcom,mdss-dsi-panel-status-read-length, and must be equal. + This can cover that Some panel may return several alternative values. +- qcom,mdss-dsi-panel-max-error-count: Integer value that specifies the maximum number of errors from register + read that can be ignored before treating that the panel has gone bad. +- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports + dynamic switching from video mode to command mode + and vice versa. +- qcom,dynamic-mode-switch-type: A string specifies how to perform dynamic mode switch. + If qcom,dynamic-mode-switch-enabled is set and no string specified, default value is + dynamic-switch-suspend-resume. + "dynamic-switch-suspend-resume"= Switch using suspend/resume. Panel will + go blank during transition. + "dynamic-switch-immediate"= Switch on next frame update. Panel will + not go blank for this transition. + "dynamic-resolution-switch-immediate"= Switch the panel resolution. Panel will + not go blank for this transition. +- qcom,mdss-dsi-post-mode-switch-on-command: Multiple dcs packets used for turning on DSI panel + after panel has switch modes. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,video-to-cmd-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from video mode to command mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from command mode to video mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,send-pps-before-switch: Boolean propety to indicate when PPS commands should be sent, + either before or after switch commands during dynamic resolution + switch in DSC panels. If the property is not present, the default + behavior is to send PPS commands after the switch commands. +- qcom,mdss-dsi-panel-orientation: String used to indicate orientation of panel + "180" = panel is flipped in both horizontal and vertical directions + "hflip" = panel is flipped in horizontal direction + "vflip" = panel is flipped in vertical direction +- qcom,panel-ack-disabled: A boolean property to indicate, whether we need to wait for any ACK from the panel + for any commands that we send. +- qcom,mdss-dsi-force-clock-lane-hs: Boolean to force dsi clock lanes to HS mode always. +- qcom,panel-cphy-mode: Boolean to specify whether panel is using cphy. +- qcom,compression-mode: Select compression mode for panel. + "fbc" - frame buffer compression + "dsc" - display stream compression. + If "dsc" compression is used then config subnodes needs to be defined. +- qcom,panel-supply-entries: A node that lists the elements of the supply used to + power the DSI panel. There can be more than one instance + of this binding, in which case the entry would be appended + with the supply entry index. For a detailed description of + fields in the supply entry, refer to the qcom,ctrl-supply-entries + binding above. +- qcom,mdss-dsc-version: An 8 bit value indicates the DSC version supported by panel. Bits[0.3] + provides information about minor version while Bits[4.7] provides + major version information. It supports only DSC rev 1(Major).1(Minor) + right now. +- qcom,mdss-dsc-scr-version: Each DSC version can have multiple SCR. This 8 bit value indicates + current SCR revision information supported by panel. +- qcom,mdss-dsc-encoders: An integer value indicating how many DSC encoders should be used + to drive data stream to DSI. + Default value is 1 and max value is 2. + 2 encoder should be used only if qcom,mdss-lm-split or + qcom,split-mode with pingpong-split is used. +- qcom,mdss-dsc-slice-height: An integer value indicates the dsc slice height. +- qcom,mdss-dsc-slice-width: An integer value indicates the dsc slice width. + Multiple of slice width should be equal to panel-width. + Maximum 2 slices per DSC encoder can be used so if 2 DSC encoders + are used then minimum slice width is equal to panel-width/4. +- qcom,mdss-dsc-slice-per-pkt: An integer value indicates the slice per dsi packet. +- qcom,mdss-dsc-bit-per-component: An integer value indicates the bits per component before compression. +- qcom,mdss-dsc-bit-per-pixel: An integer value indicates the bits per pixel after compression. +- qcom,mdss-dsc-block-prediction-enable: A boolean value to enable/disable the block prediction at decoder. +- qcom,mdss-dsc-config-by-manufacture-cmd: A boolean to indicates panel use manufacture command to setup pps + instead of standard dcs type 0x0A. +- qcom,mdss-pps-delay-ms: An u32 value that indicates post PPS command + delay in milliseconds. If no value is specified, it chooses zero by default. +- qcom,display-topology: Array of u32 values which specifies the list of topologies available + for the display. A display topology is defined by a + set of 3 values in the order: + - number of mixers + - number of compression encoders + - number of interfaces + Therefore, the array should always contain a tuple of 3 elements. +- qcom,default-topology-index: An u32 value which indexes the topology set + specified by the node "qcom,display-topology" + to identify the default topology for the + display. The first set is indexed by the + value 0. +- qcom,mdss-dsi-ext-bridge-mode: External bridge chip is connected instead of panel. +- qcom,mdss-dsi-dma-schedule-line: An integer value indicates the line number after vertical active + region, at which command DMA needs to be triggered. + +Required properties for sub-nodes: None +Optional properties: +- qcom,dba-panel: Indicates whether the current panel is used as a display bridge + to a non-DSI interface. +- qcom,bridge-name: A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name + is required if qcom,dba-panel is defined for the panel. +- qcom,adjust-timer-wakeup-ms: An integer value to indicate the timer delay(in ms) to accommodate + s/w delay while configuring the event timer wakeup logic. + +- qcom,mdss-dsi-display-timings: Parent node that lists the different resolutions that the panel supports. + Each child represents timings settings for a specific resolution. +- qcom,mdss-dsi-post-init-delay: Specifies required number of frames to wait so that panel can be functional + to show proper display. +- qcom,mdss-dsi-video-mode: A boolean to indicates current timing can only work in video mode. +- qcom,mdss-dsi-cmd-mode: A boolean to indicates current timing can only work in command mode. + +Additional properties added to the second level nodes that represent timings properties: +- qcom,mdss-dsi-timing-default: Property that specifies the current child as the default + timing configuration that will be used. +- qcom,mdss-dsi-timing-switch-command: List of commands that need to be sent + to panel when the resolution/timing switch happens dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,mdss-dsi-timing-switch-command-state: String that specifies the ctrl state for sending resolution switch + commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode + +Note, if a given optional qcom,* binding is not present, then the driver will configure +the default values specified. + +Example: +&mdss_mdp { + dsi_sim_vid: qcom,mdss_dsi_sim_video { + qcom,mdss-dsi-panel-name = "simulator video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-pixel-packing = <0>; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-fbc-enable; + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-fbc-slice-height = <5>; + qcom,mdss-dsi-fbc-2d-pred-mode; + qcom,mdss-dsi-fbc-ver2-mode; + qcom,mdss-dsi-fbc-bpp = <0>; + qcom,mdss-dsi-fbc-packing = <0>; + qcom,mdss-dsi-fbc-quant-error; + qcom,mdss-dsi-fbc-bias = <0>; + qcom,mdss-dsi-fbc-pat-mode; + qcom,mdss-dsi-fbc-vlc-mode; + qcom,mdss-dsi-fbc-bflc-mode; + qcom,mdss-dsi-fbc-h-line-budget = <0>; + qcom,mdss-dsi-fbc-budget-ctrl = <0>; + qcom,mdss-dsi-fbc-block-budget = <0>; + qcom,mdss-dsi-fbc-lossless-threshold = <0>; + qcom,mdss-dsi-fbc-lossy-threshold = <0>; + qcom,mdss-dsi-fbc-rgb-threshold = <0>; + qcom,mdss-dsi-fbc-lossy-mode-idx = <0>; + qcom,mdss-dsi-fbc-max-pred-err = <2>; + qcom,mdss-dsi-h-front-porch = <140>; + qcom,mdss-dsi-h-back-porch = <164>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <1>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = < 15>; + qcom,mdss-brightness-max-level = <255>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-interleave-mode = <0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-qsync-min-refresh-rate = <30>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-hfp-power-mode; + qcom,mdss-dsi-hbp-power-mode; + qcom,mdss-dsi-hsa-power-mode; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-last-line-interleave; + qcom,mdss-dsi-traffic-mode = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-color-order = <0>; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x20>; + qcom,mdss-dsi-t-clk-pre = <0x2c>; + qcom,mdss-dsi-t-clk-pre-extend; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-mdp-trigger = <0>; + qcom,mdss-dsi-dma-trigger = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 + 22 27 1e 03 04 00]; + qcom,mdss-dsi-panel-timings-8996 = [23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 2e 06 08 05 03 04 a0]; + qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; + qcom,min-refresh-rate = <30>; + qcom,max-refresh-rate = <60>; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <534712320 532484352 530256384>; + qcom,dsi-dyn-clk-type = "constant-fps-adjust-vfp"; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>; + qcom,5v-boost-gpio = <&pm8994_gpios 14 0>; + qcom,mdss-pan-physical-width-dimension = <60>; + qcom,mdss-pan-physical-height-dimension = <140>; + qcom,mdss-dsi-mode-sel-gpio-state = "dsc_mode"; + qcom,mdss-tear-check-sync-cfg-height = <0xfff0>; + qcom,mdss-tear-check-sync-init-val = <1280>; + qcom,mdss-tear-check-sync-threshold-start = <4>; + qcom,mdss-tear-check-sync-threshold-continue = <4>; + qcom,mdss-tear-check-start-pos = <1280>; + qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; + qcom,mdss-tear-check-frame-rate = <6000>; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <100>; + mdss-dsi-rx-eot-ignore; + mdss-dsi-tx-eot-append; + qcom,ulps-enabled; + qcom,suspend-ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-read-length = <8>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-panel-status-value = <0x1c 0x00 0x05 0x02 0x40 0x84 0x06 0x01>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + qcom,mdss-dsi-post-mode-switch-on-command = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 B0 03]; + qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B + 15 01 00 00 00 00 02 C2 08]; + qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03]; + qcom,send-pps-before-switch; + qcom,panel-ack-disabled; + qcom,mdss-dsi-horizontal-line-idle = <0 40 256>, + <40 120 128>, + <128 240 64>; + qcom,mdss-dsi-panel-orientation = "180" + qcom,mdss-dsi-panel-jitter = <0x8 0x10>; + qcom,mdss-dsi-panel-prefill-lines = <0x10>; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,compression-mode = "dsc"; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + wqhd { + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <728>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <424000000>; + qcom,mdss-mdp-transfer-time-us = <12500>; + qcom,mdss-dsi-panel-timings = [E6 38 26 00 68 6E 2A 3C 2C 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; + qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00 + 05 01 00 00 02 00 02 29 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 00 00 00 00 00 02 B0 04 + 29 00 00 00 00 00 02 F1 00]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-qsync-on-commands = [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = "dsi_hs_mode"; + + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <4 4 2 2 20 20>; + }; + }; + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2800000>; + qcom,supply-max-voltage = <2800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,dba-panel; + qcom,bridge-name = "adv7533"; + qcom,mdss-dsc-version = <0x11>; + qcom,mdss-dsc-scr-version = <0x1>; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <0>; + qcom,mdss-dsi-dma-schedule-line = <5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/mdss-pll.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdss-pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..a93529717d1c3cebaf167a91ce40c8279d8bfb50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/mdss-pll.txt @@ -0,0 +1,108 @@ +Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI + +mdss-pll is a pll controller device which supports pll devices that +are compatible with MIPI display serial interface specification, +HDMI and edp. + +Required properties: +- compatible: Compatible name used in the driver. Should be one of: + "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", + "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", + "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", + "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", + "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", + "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", + "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", + "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", + "qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8", + "qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998", + "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm", + "qcom,mdss_dsi_pll_7nm", "qcom,mdss_dp_pll_7nm", + "qcom,mdss_dsi_pll_28lpm", "qcom,mdss_dsi_pll_14nm", + "qcom,mdss_dp_pll_14nm", "qcom,mdss_dsi_pll_7nm_v2", + "qcom,mdss_hdmi_pll_28lpm","qcom,mdss_dsi_pll_7nm_v4_1", + "qcom,mdss_dp_pll_7nm_v2" +- cell-index: Specifies the controller used +- reg: offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- gdsc-supply: Phandle for gdsc regulator device node. +- vddio-supply: Phandle for vddio regulator device node. +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- clock-rate: List of clock rates in Hz. + +Optional properties: +- label: A string used to describe the driver used. +- vcca-supply: Phandle for vcca regulator device node. + + +- qcom,dsi-pll-ssc-en: Boolean property to indicate that ssc is enabled. +- qcom,dsi-pll-ssc-mode: Spread-spectrum clocking. It can be either "down-spread" + or "center-spread". Default is "down-spread" if it is not specified. +- qcom,ssc-frequency-hz: Integer property to specify the spread frequency + to be programmed for the SSC. +- qcom,ssc-ppm: Integer property to specify the Parts per Million + value of SSC. + +- qcom,platform-supply-entries: A node that lists the elements of the supply. There + can be more than one instance of this binding, + in which case the entry would be appended with + the supply entry index. + e.g. qcom,platform-supply-entry@0 + - reg: offset and length of the register set for the device. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +Example: + mdss_dsi0_pll: qcom,mdss_dsi_pll@fd922A00 { + compatible = "qcom,mdss_dsi_pll_8974"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + + reg = <0xfd922A00 0xD4>, + <0xfd922900 0x64>, + <0xfd8c2300 0x8>; + reg-names = "pll_base", "dynamic_pll_base", "gdsc_base"; + gdsc-supply = <&gdsc_mdss>; + vddio-supply = <&pm8941_l12>; + vcca-supply = <&pm8941_l28>; + + clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>, + <&clock_gcc clk_gcc_mdss_ahb_clk>, + <&clock_gcc clk_gcc_mdss_axi_clk>; + clock-names = "mdp_core_clk", "iface_clk", "bus_clk"; + clock-rate = <0>, <0>, <0>; + + qcom,dsi-pll-slave; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,ssc-frequency-hz = <30000>; + qcom,ssc-ppm = <5000>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/msm-notifier.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/msm-notifier.txt new file mode 100644 index 0000000000000000000000000000000000000000..c55f55cda9e6035e2fd8a3a07c403fd6dff386ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/msm-notifier.txt @@ -0,0 +1,15 @@ +Qualcomm Technologies, Inc. MSM NOTIFIER + +Snapdragon Display Engine implements msm notifier to alert +listeners to changes in display mode. + +Required properties +- compatible: "qcom,msm-notifier" +- panel: list of panels that support multiple refresh + rate + +Example: + msm_notifier: qcom,msm_notifier@0{ + compatible = "qcom,msm-notifier"; + panel = <&dsi_sw43404_amoled_cmd &dsi_sharp_qsync_wqhd_cmd>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-dp.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-dp.txt new file mode 100644 index 0000000000000000000000000000000000000000..78812304b88797319076eac673962bb197950623 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-dp.txt @@ -0,0 +1,237 @@ +Qualcomm Technologies, Inc. +sde-dp is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification. +DP Controller: Required properties: +- compatible: Should be "qcom,dp-display". +- reg: Base address and length of DP hardware's memory mapped regions. +- reg-names: A list of strings that name the list of regs. "dp_ctrl" - DP controller memory region. + "dp_phy" - DP PHY memory region. + "dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region. + "dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region. + "dp_mmss_cc" - Display Clock Control memory region. + "qfprom_physical" - QFPROM Phys memory region. + "dp_pll" - USB3 DP combo PLL memory region. + "usb3_dp_com" - USB3 DP PHY combo memory region. + "hdcp_physical" - DP HDCP memory region. +- cell-index: Specifies the controller instance. +- clocks: Clocks required for Display Port operation. +- clock-names: Names of the clocks corresponding to handles. Following clocks are required: + "core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent". +- gdsc-supply: phandle to gdsc regulator node. +- vdda-1p2-supply: phandle to vdda 1.2V regulator node. +- vdda-0p9-supply: phandle to vdda 0.9V regulator node. +- interrupt-parent phandle to the interrupt parent device node. +- interrupts: The interrupt signal from the DSI block. +- qcom,aux-en-gpio: Specifies the aux-channel enable gpio. +- qcom,aux-sel-gpio: Specifies the aux-channel select gpio. +- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio. +- qcom,aux-cfg0-settings: Specifies the DP AUX configuration 0 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg1-settings: Specifies the DP AUX configuration 1 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg2-settings: Specifies the DP AUX configuration 2 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg3-settings: Specifies the DP AUX configuration 3 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg4-settings: Specifies the DP AUX configuration 4 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg5-settings: Specifies the DP AUX configuration 5 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg6-settings: Specifies the DP AUX configuration 6 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg7-settings: Specifies the DP AUX configuration 7 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg8-settings: Specifies the DP AUX configuration 8 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg9-settings: Specifies the DP AUX configuration 9 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port. +- qcom,mst-enable: MST feature enable control node. +- qcom,dsc-feature-enable: DSC feature enable control node. +- qcom,fec-feature-enable: FEC feature enable control node. +- qcom,max-dp-dsc-blks: An integer specifying the max. DSC blocks available for Display port. +- qcom,max-dp-dsc-input-width-pixs: An integer specifying the max. input width of pixels for each DSC block. +- qcom,dp-usbpd-detection: Phandle for the PMI regulator node for USB PHY PD detection. +- qcom,dp-aux-switch: Phandle for the driver used to program the AUX switch for Display Port orientation. +- qcom,dp-hpd-gpio: HPD gpio for direct DP connector without USB PHY or AUX switch. +- qcom,dp-gpio-aux-switch: Gpio DP AUX switch chipset support. +- qcom,-supply-entries: A node that lists the elements of the supply used by the a particular "type" of DSI module. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +msm_ext_disp is a device which manages the interaction between external +display interfaces, e.g. Display Port, and the audio subsystem. + +Optional properties: +- qcom,ext-disp: phandle for msm-ext-display module +- compatible: Must be "qcom,msm-ext-disp" +- qcom,dp-low-power-hw-hpd: Low power hardware HPD feature enable control node +- qcom,phy-version: Phy version +- qcom,pn-swap-lane-map: P/N swap configuration of each lane +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt +- qcom,max-lclk-frequency-khz: An integer specifying the max. link clock in KHz supported by Display Port. +- qcom,mst-fixed-topology-ports: u32 values of which MST output port to reserve, start from one + +[Optional child nodes]: These nodes are for devices which are +dependent on msm_ext_disp. If msm_ext_disp is disabled then +these devices will be disabled as well. Ex. Audio Codec device. + +- ext_disp_audio_codec: Node for Audio Codec. +- compatible : "qcom,msm-ext-disp-audio-codec-rx"; + +Example: + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + gdsc-supply = <&mdss_core_gdsc>; + vdda-1p2-supply = <&pm8998_l26>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xae90000 0xa84>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea030 0x10>, + <0x88e8000 0x621c>, + <0x0aee1000 0x034>; + reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,dp-usbpd-detection = <&pm8150b_pdphy>; + qcom,ext-disp = <&ext_disp>; + qcom,phy-version = <0x420>; + qcom,dp-aux-switch = <&fsa4480>; + + qcom,aux-cfg0-settings = [1c 00]; + qcom,aux-cfg1-settings = [20 13 23 1d]; + qcom,aux-cfg2-settings = [24 00]; + qcom,aux-cfg3-settings = [28 00]; + qcom,aux-cfg4-settings = [2c 0a]; + qcom,aux-cfg5-settings = [30 26]; + qcom,aux-cfg6-settings = [34 0a]; + qcom,aux-cfg7-settings = [38 03]; + qcom,aux-cfg8-settings = [3c bb]; + qcom,aux-cfg9-settings = [40 03]; + qcom,max-pclk-frequency-khz = <593470>; + qcom,mst-enable; + qcom,dsc-feature-enable; + qcom,fec-feature-enable; + qcom,max-dp-dsc-blks = <2>; + qcom,max-dp-dsc-input-width-pixs = <2048>; + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 43 0>; + qcom,aux-sel-gpio = <&tlmm 51 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e09261d55b31af1a2352474d027c53db314e5f3a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-dsi.txt @@ -0,0 +1,118 @@ +Qualcomm Technologies, Inc. + +mdss-dsi is the master DSI device which supports multiple DSI host controllers +that are compatible with MIPI display serial interface specification. + +DSI Controller: +Required properties: +- compatible: Should be "qcom,dsi-ctrl-hw-v". Supported + versions include 1.4, 2.0 and 2.2. + eg: qcom,dsi-ctrl-hw-v1.4, qcom,dsi-ctrl-hw-v2.0, + qcom,dsi-ctrl-hw-v2.2, qcom,dsi-ctrl-hw-v2.3, + qcom,dsi-ctrl-hw-v2.4 + And for dsi phy driver: + qcom,dsi-phy-v0.0-hpm, qcom,dsi-phy-v0.0-lpm, + qcom,dsi-phy-v1.0, qcom,dsi-phy-v2.0, + qcom,dsi-phy-v3.0, qcom,dsi-phy-v4.0, qcom,dsi-phy-v4.1 +- reg: Base address and length of DSI controller's memory + mapped regions. +- reg-names: A list of strings that name the list of regs. + "dsi_ctrl" - DSI controller memory region. + "mmss_misc" - MMSS misc memory region. +- cell-index: Specifies the controller instance. +- clocks: Clocks required for DSI controller operation. +- clock-names: Names of the clocks corresponding to handles. Following + clocks are required: + "mdp_core_clk" + "iface_clk" + "core_mmss_clk" + "bus_clk" + "byte_clk" + "pixel_clk" + "core_clk" + "byte_clk_rcg" + "pixel_clk_rcg" +- gdsc-supply: phandle to gdsc regulator node. +- vdda-supply: phandle to vdda regulator node. +- vcca-supply: phandle to vcca regulator node. +- interrupt-parent phandle to the interrupt parent device node. +- interrupts: The interrupt signal from the DSI block. +- qcom,dsi-default-panel: Specifies the default panel. +- qcom,mdp: Specifies the mdp node which can find panel node from this. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the number of bus scaling use cases + defined in the vectors property. This must be + set to <2> for MDSS DSI driver where use-case 0 + is used to remove BW votes from the system. Use + case 1 is used to generate bandwidth requestes + when sending command packets. +- qcom,msm-bus,num-paths: This represents number of paths in each bus + scaling usecase. This value depends on number of + AXI master ports dedicated to MDSS for + particular chipset. +- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt. + DSI driver should always set average bandwidth + (ab) to 0 and always use instantaneous + bandwidth(ib) values. + +Optional properties: +- label: String to describe controller. +- qcom,platform-te-gpio: Specifies the gpio used for TE. +- qcom,panel-te-source: Specifies the source pin for Vsync from panel or WD Timer. +- qcom,dsi-ctrl: handle to dsi controller device +- qcom,dsi-phy: handle to dsi phy device +- qcom,dsi-ctrl-num: Specifies the DSI controllers to use for primary panel +- qcom,dsi-sec-ctrl-num: Specifies the DSI controllers to use for secondary panel +- qcom,dsi-phy-num: Specifies the DSI PHYs to use for primary panel +- qcom,dsi-sec-phy-num: Specifies the DSI PHYs to use for secondary panel +- qcom,dsi-select-clocks: Specifies the required clocks to use for primary panel +- qcom,dsi-select-sec-clocks: Specifies the required clocks to use for secondary panel +- qcom,dsi-display-list: Specifies the list of supported displays. +- qcom,dsi-manager: Specifies dsi manager is present +- qcom,dsi-display: Specifies dsi display is present +- qcom,hdmi-display: Specifies hdmi is present +- qcom,dp-display: Specified dp is present +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI module. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split enabled, this time should not be higher + than two times the dsi link rate time. + If the property is not specified, then the default value is 14000 us. +- qcom,dsi-phy-isolation-enabled: A boolean property enables the phy isolation from dsi + controller. This must be enabled for debugging purpose + only with simulator panel. It should not be enabled for + normal DSI panels. +- - qcom,null-insertion-enabled: A boolean to enable NULL packet insertion feature for DSI controller. +- ports: This video port is used when external bridge is present. + The connection is modeled using the OF graph bindings + specified in Documentation/devicetree/bindings/graph.txt. + Video port 0 reg 0 is for the bridge output. The remote + endpoint phandle should be mipi_dsi_device device node. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-rsc.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-rsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3af5629ca4670a1a821389ef0e4f56f7fb071622 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-rsc.txt @@ -0,0 +1,97 @@ +Qualcomm Technologies, Inc. SDE RSC + +Snapdragon Display Engine implements display rsc to driver +display core to different modes for power saving + +Required properties +- compatible: "qcom,sde-rsc" + "qcom,sde-rsc-rpmh" +- reg: Offset and length of the register set for + the device. +- reg-names: Names to refer to register sets related + to this device + +Optional properties: +- clocks: List of phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- vdd-supply: phandle for vdd regulator device node. +- qcom,sde-rsc-version: U32 property represents the rsc version. It helps to + select correct sequence for sde rsc based on version. +- qcom,sde-dram-channels: U32 property represents the number of channels in the + Bus memory controller. +- qcom,sde-num-nrt-paths: U32 property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports that are dedicated to non-realtime VBIF + for particular chipset. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. + +Bus Scaling Subnodes: +- qcom,sde-data-bus: Property to provide Bus scaling for data bus access for + sde blocks. +- qcom,sde-llcc-bus: Property to provide Bus scaling for data bus access for + mnoc to llcc. +- qcom,sde-ebi-bus: Property to provide Bus scaling for data bus access for + llcc to ebi. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing client name. +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex +- qcom,msm-bus,num-cases: This is the number of Bus Scaling use cases + defined in the vectors property. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h +Example: + sde_rscc { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + clocks = <&clock_mmss clk_mdss_ahb_clk>, + <&clock_mmss clk_mdss_axi_clk>; + clock-names = "iface_clk", "bus_clk"; + vdd-supply = <&gdsc_mdss>; + + qcom,sde-rsc-version = <1>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <1>; + + qcom,sde-data-bus { + qcom,msm-bus,name = "sde_rsc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; + qcom,sde-llcc-bus { + qcom,msm-bus,name = "sde_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + qcom,sde-ebi-bus { + qcom,msm-bus,name = "sde_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-wb.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-wb.txt new file mode 100644 index 0000000000000000000000000000000000000000..863b334e438a704f8ff9396e6bf2ac3f02b0224b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde-wb.txt @@ -0,0 +1,23 @@ +QTI Snapdragon Display Engine (SDE) writeback display + +Required properties: +- compatible: "qcom,wb-display" + +Optional properties: +- cell-index: Index of writeback device instance. + Default to 0 if not specified. +- label: String to describe this writeback display. + Default to "unknown" if not specified. + +Example: + +/ { + ... + + sde_wb: qcom,wb-display { + compatible = "qcom,wb-display"; + cell-index = <2>; + label = "wb_display"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/msm/sde.txt b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde.txt new file mode 100644 index 0000000000000000000000000000000000000000..00108a47d68deffe1819fc4f049fa4965bebed88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/msm/sde.txt @@ -0,0 +1,921 @@ +Qualcomm Technologies, Inc. SDE KMS + +Snapdragon Display Engine implements Linux DRM/KMS APIs to drive user +interface to different panel interfaces. SDE driver is the core of +display subsystem which manage all data paths to different panel interfaces. + +Required properties +- compatible: Must be "qcom,sde-kms" +- compatible: "msm-hdmi-audio-codec-rx"; +- reg: Offset and length of the register set for the device. +- reg-names : Names to refer to register sets related to this device +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- mmagic-supply: Phandle for mmagic mdss supply regulator device node. +- vdd-supply: Phandle for vdd regulator device node. +- interrupt-parent: Must be core interrupt controller. +- interrupts: Interrupt associated with MDSS. +- interrupt-controller: Mark the device node as an interrupt controller. +- #interrupt-cells: Should be one. The first cell is interrupt number. +- iommus: Specifies the SID's used by this context bank. +- qcom,sde-sspp-type: Array of strings for SDE source surface pipes type information. + A source pipe can be "vig", "rgb", "dma" or "cursor" type. + Number of xin ids defined should match the number of offsets + defined in property: qcom,sde-sspp-off. +- qcom,sde-sspp-off: Array of offset for SDE source surface pipes. The offsets + are calculated from register "mdp_phys" defined in + reg property + "sde-off". The number of offsets defined here should + reflect the amount of pipes that can be active in SDE for + this configuration. +- qcom,sde-sspp-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective source pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,sde-sspp-off. +- qcom,sde-ctl-off: Array of offset addresses for the available ctl + hw blocks within SDE, these offsets are + calculated from register "mdp_phys" defined in + reg property. The number of ctl offsets defined + here should reflect the number of control paths + that can be configured concurrently on SDE for + this configuration. +- qcom,sde-wb-off: Array of offset addresses for the programmable + writeback blocks within SDE. +- qcom,sde-wb-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective writeback. Number of xin ids + defined should match the number of offsets + defined in property: qcom,sde-wb-off. +- qcom,sde-mixer-off: Array of offset addresses for the available + mixer blocks that can drive data to panel + interfaces. These offsets are be calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined should reflect the + amount of mixers that can drive data to a panel + interface. +- qcom,sde-dspp-top-off: Offset address for the dspp top block. + The offset is calculated from register "mdp_phys" + defined in reg property. +- qcom,sde-dspp-off: Array of offset addresses for the available dspp + blocks. These offsets are calculated from + register "mdp_phys" defined in reg property. +- qcom,sde-pp-off: Array of offset addresses for the available + pingpong blocks. These offsets are calculated + from register "mdp_phys" defined in reg property. +- qcom,sde-pp-slave: Array of flags indicating whether each ping pong + block may be configured as a pp slave. +- qcom,sde-pp-merge-3d-id: Array of index ID values for the merge 3d block + connected to each pingpong, starting at 0. +- qcom,sde-merge-3d-off: Array of offset addresses for the available + merge 3d blocks. These offsets are calculated + from register "mdp_phys" defined in reg property. +- qcom,sde-intf-off: Array of offset addresses for the available SDE + interface blocks that can drive data to a + panel controller. The offsets are calculated + from "mdp_phys" defined in reg property. The number + of offsets defined should reflect the number of + programmable interface blocks available in hardware. +- qcom,sde-mixer-blend-op-off Array of offset addresses for the available + blending stages. The offsets are relative to + qcom,sde-mixer-off. +- qcom,sde-mixer-pair-mask Array of mixer numbers that can be paired with + mixer number corresponding to the array index. + +Optional properties: +- clock-rate: List of clock rates in Hz. +- clock-max-rate: List of maximum clock rate in Hz that this device supports. +- qcom,platform-supply-entries: A node that lists the elements of the supply. There + can be more than one instance of this binding, + in which case the entry would be appended with + the supply entry index. + e.g. qcom,platform-supply-entry@0 + -- reg: offset and length of the register set for the device. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- qcom,sde-sspp-src-size: A u32 value indicates the address range for each sspp. +- qcom,sde-mixer-size: A u32 value indicates the address range for each mixer. +- qcom,sde-ctl-size: A u32 value indicates the address range for each ctl. +- qcom,sde-dspp-size: A u32 value indicates the address range for each dspp. +- qcom,sde-intf-size: A u32 value indicates the address range for each intf. +- qcom,sde-dsc-size: A u32 value indicates the address range for each dsc. +- qcom,sde-cdm-size: A u32 value indicates the address range for each cdm. +- qcom,sde-pp-size: A u32 value indicates the address range for each pingpong. +- qcom,sde-merge-3d-size: A u32 value indicates the address range for each merge 3d. +- qcom,sde-wb-size: A u32 value indicates the address range for each writeback. +- qcom,sde-len: A u32 entry for SDE address range. +- qcom,sde-intf-max-prefetch-lines: Array of u32 values for max prefetch lines on + each interface. +- qcom,sde-sspp-linewidth: A u32 value indicates the max sspp line width. +- qcom,sde-vig-sspp-linewidth: A u32 value indicates the max vig sspp line width. +- qcom,sde-mixer-linewidth: A u32 value indicates the max mixer line width. +- qcom,sde-wb-linewidth: A u32 value indicates the max writeback line width. +- qcom,sde-sspp-scale-size: A u32 value indicates the scaling block size on sspp. +- qcom,sde-mixer-blendstages: A u32 value indicates the max mixer blend stages for + alpha blending. +- qcom,sde-qseed-type: A string entry indiates qseed support on sspp and wb. + It supports "qssedv3" and "qseedv2" entries for qseed + type. By default "qseedv2" is used if this optional property + is not defined. +- qcom,sde-csc-type: A string entry indicates csc support on sspp and wb. + It supports "csc" and "csc-10bit" entries for csc + type. +- qcom,sde-highest-bank-bit: A u32 property to indicate GPU/Camera/Video highest memory + bank bit used for tile format buffers. +- qcom,sde-ubwc-version: Property to specify the UBWC feature version. +- qcom,sde-ubwc-static: Property to specify the default UBWC static + configuration value. +- qcom,sde-ubwc-bw-calc-version: A u32 property to specify version of UBWC bandwidth + calculation algorithm +- qcom,sde-ubwc-swizzle: Property to specify the default UBWC swizzle + configuration value. +- qcom,sde-smart-panel-align-mode: A u32 property to specify the align mode for + split display on smart panel. Possible values: + 0x0 - no alignment + 0xc - align at start of frame + 0xd - align at start of line +- qcom,sde-panic-per-pipe: Boolean property to indicate if panic signal + control feature is available on each source pipe. +- qcom,sde-has-src-split: Boolean property to indicate if source split + feature is available or not. +- qcom,sde-has-dim-layer: Boolean property to indicate if mixer has dim layer + feature is available or not. +- qcom,sde-has-idle-pc: Boolean property to indicate if target has idle + power collapse feature available or not. +- qcom,sde-has-mixer-gc: Boolean property to indicate if mixer has gamma correction + feature available or not. +- qcom,sde-has-dest-scaler: Boolean property to indicate if destination scaler + feature is available or not. +- qcom,sde-max-dest-scaler-input-linewidth: A u32 value indicates the + maximum input line width to destination scaler. +- qcom,sde-max-dest-scaler-output-linewidth: A u32 value indicates the + maximum output line width of destination scaler. +- qcom,sde-dest-scaler-top-off: A u32 value provides the + offset from mdp base to destination scaler block. +- qcom,sde-dest-scaler-top-size: A u32 value indicates the address range for ds top +- qcom,sde-dest-scaler-off: Array of u32 offsets indicate the qseed3 scaler blocks + offset from destination scaler top offset. +- qcom,sde-dest-scaler-size: A u32 value indicates the address range for each scaler block +- qcom,sde-sspp-clk-ctrl: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of offsets defined in + property: qcom,sde-sspp-off +- qcom,sde-sspp-clk-status: Array of offsets describing clk status + offsets for dynamic clock gating. 1st value + in the array represents offset of the status + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of offsets defined in + property: qcom,sde-sspp-off. +- qcom,sde-sspp-excl-rect: Array of u32 values indicating exclusion rectangle + support on each sspp. +- qcom,sde-sspp-smart-dma-priority: Array of u32 values indicating hw pipe + priority of secondary rectangles when smart dma + is supported. Number of priority values should + match the number of offsets defined in + qcom,sde-sspp-off node. Zero indicates no support + for smart dma for the sspp. +- qcom,sde-smart-dma-rev: A string entry indicating the smart dma version + supported on the device. Supported entries are + "smart_dma_v1" and "smart_dma_v2". +- qcom,sde-intf-type: Array of string provides the interface type information. + Possible string values + "dsi" - dsi display interface + "dp" - Display Port interface + "hdmi" - HDMI display interface + An interface is considered as "none" if interface type + is not defined. +- qcom,sde-off: SDE offset from "mdp_phys" defined in reg property. +- qcom,sde-cdm-off: Array of offset addresses for the available + cdm blocks. These offsets will be calculated from + register "mdp_phys" defined in reg property. +- qcom,sde-vbif-off: Array of offset addresses for the available + vbif blocks. These offsets will be calculated from + register "vbif_phys" defined in reg property. +- qcom,sde-vbif-size: A u32 value indicates the vbif block address range. +- qcom,sde-uidle-off: A u32 value with the offset for the uidle + block, from the "mdp_phys". +- qcom,sde-uidle-size: A u32 value indicates the uidle block address range. +- qcom,sde-te-off: A u32 offset indicates the te block offset on pingpong. + This offset is 0x0 by default. +- qcom,sde-te2-off: A u32 offset indicates the te2 block offset on pingpong. +- qcom,sde-te-size: A u32 value indicates the te block address range. +- qcom,sde-te2-size: A u32 value indicates the te2 block address range. +- qcom,sde-dsc-off: A u32 offset indicates the dsc block offset on pingpong. +- qcom,sde-qdss-off: A u32 offset indicates the qdss block offset. +- qcom,sde-dither-off: A u32 offset indicates the dither block offset on pingpong. +- qcom,sde-dither-version: A u32 value indicates the dither block version. +- qcom,sde-dither-size: A u32 value indicates the dither block address range. +- qcom,sde-sspp-vig-blocks: A node that lists the blocks inside the VIG hardware. The + block entries will contain the offset and version (if needed) + of each feature block. The presence of a block entry + indicates that the SSPP VIG contains that feature hardware. + e.g. qcom,sde-sspp-vig-blocks + -- qcom,sde-vig-csc-off: offset of CSC hardware + -- qcom,sde-vig-qseed-off: offset of QSEED hardware + -- qcom,sde-vig-qseed-size: A u32 address range for qseed scaler. + -- qcom,sde-vig-pcc: offset and version of PCC hardware + -- qcom,sde-vig-hsic: offset and version of global PA adjustment + -- qcom,sde-vig-memcolor: offset and version of PA memcolor hardware + -- qcom,sde-vig-gamut: offset and version of 3D LUT Gamut hardware + -- qcom,sde-vig-igc: offset and version of 1D LUT IGC hardware + -- qcom,sde-vig-inverse-pma: Boolean property to indicate if + inverse PMA feature is available on VIG pipe +- qcom,sde-sspp-dma-blocks: A node that lists the blocks inside the DMA hardware. There + can be more than one instance of this binding, in which case the + entry would be appended with dgm entry index. Each entry will + contain the offset and version (if needed) of each feature block. + The presence of a block entry indicates that the SSPP DMA contains + that feature hardware. + e.g. qcom,sde-sspp-dma-blocks + -- dgm@0 + -- qcom,sde-dma-igc: offset and version of DMA IGC + -- qcom,sde-dma-gc: offset and version of DMA GC + -- qcom,sde-dma-inverse-pma: Boolean property to indicate if + inverse PMA feature is available on DMA pipe + -- qcom,sde-dma-csc-off: offset of CSC hardware +- qcom,sde-sspp-rgb-blocks: A node that lists the blocks inside the RGB hardware. The + block entries will contain the offset and version (if needed) + of each feature block. The presence of a block entry + indicates that the SSPP RGB contains that feature hardware. + e.g. qcom,sde-sspp-rgb-blocks + -- qcom,sde-rgb-scaler-off: offset of RGB scaler hardware + -- qcom,sde-rgb-scaler-size: A u32 address range for scaler. + -- qcom,sde-rgb-pcc: offset and version of PCC hardware +- qcom,sde-dspp-blocks: A node that lists the blocks inside the DSPP hardware. The + block entries will contain the offset and version of each + feature block. The presence of a block entry indicates that + the DSPP contains that feature hardware. + e.g. qcom,sde-dspp-blocks + -- qcom,sde-dspp-pcc: offset and version of PCC hardware + -- qcom,sde-dspp-gc: offset and version of GC hardware + -- qcom,sde-dspp-igc: offset and version of IGC hardware + -- qcom,sde-dspp-hsic: offset and version of global PA adjustment + -- qcom,sde-dspp-memcolor: offset and version of PA memcolor hardware + -- qcom,sde-dspp-sixzone: offset and version of PA sixzone hardware + -- qcom,sde-dspp-gamut: offset and version of Gamut mapping hardware + -- qcom,sde-dspp-dither: offset and version of dither hardware + -- qcom,sde-dspp-hist: offset and version of histogram hardware + -- qcom,sde-dspp-vlut: offset and version of PA vLUT hardware +- qcom,sde-mixer-blocks: A node that lists the blocks inside the layer mixer hardware. The + block entries will contain the offset and version (if needed) + of each feature block. The presence of a block entry + indicates that the layer mixer contains that feature hardware. + e.g. qcom,sde-mixer-blocks + -- qcom,sde-mixer-gc: offset and version of mixer GC hardware +- qcom,sde-dspp-ad-off: Array of u32 offsets indicate the ad block offset from the + DSPP offset. Since AD hardware is represented as part of + DSPP block, the AD offsets must be offset from the + corresponding DSPP base. +- qcom,sde-dspp-ad-version A u32 value indicating the version of the AD hardware +- qcom,sde-dspp-ltm-version A u32 value indicating the major(upper 16 bits) and minor(lower 16 bits) + version of the LTM hardware +- qcom,sde-dspp-ltm-off: Array of u32 offsets indicate the LTM block offsets from the + DSPP offsets. Since LTM hardware is represented as part of + DSPP block, the LTM offsets are calculated based on the + corresponding DSPP base. +- qcom,sde-vbif-id: Array of vbif ids corresponding to the + offsets defined in property: qcom,sde-vbif-off. +- qcom,sde-vbif-default-ot-rd-limit: A u32 value indicates the default read OT limit +- qcom,sde-vbif-default-ot-wr-limit: A u32 value indicates the default write OT limit +- qcom,sde-vbif-dynamic-ot-rd-limit: A series of 2 cell property, with a format + of (pps, OT limit), where pps is pixel per second and + OT limit is the read limit to apply if the given + pps is not exceeded. +- qcom,sde-vbif-dynamic-ot-wr-limit: A series of 2 cell property, with a format + of (pps, OT limit), where pps is pixel per second and + OT limit is the write limit to apply if the given + pps is not exceeded. +- qcom,sde-vbif-memtype-0: Array of u32 vbif memory type settings, group 0 +- qcom,sde-vbif-memtype-1: Array of u32 vbif memory type settings, group 1 +- qcom,sde-wb-id: Array of writeback ids corresponding to the + offsets defined in property: qcom,sde-wb-off. +- qcom,sde-wb-clk-ctrl: Array of 2 cell property describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of offsets defined in + property: qcom,sde-wb-off +- qcom,sde-reg-dma-off: Offset of the register dma hardware block from + "regdma_phys" defined in reg property. +- qcom,sde-reg-dma-version: Version of the reg dma hardware block. +- qcom,sde-reg-dma-trigger-off: Offset of the lut dma trigger reg from "mdp_phys" + defined in reg property. +- qcom,sde-reg-dma-broadcast-disabled: Boolean property to indicate if broadcast + functionality in the register dma hardware block should be used. +- qcom,sde-reg-dma-xin-id: VBIF clients id (xin) corresponding + to the LUTDMA block. +- qcom,sde-reg-dma-clk-ctrl: Array of 2 cell property describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. +- qcom,sde-dram-channels: This represents the number of channels in the + Bus memory controller. +- qcom,sde-num-nrt-paths: Integer property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports that are dedicated to non-realtime VBIF + for particular chipset. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. +- qcom,sde-max-bw-low-kbps: This value indicates the max bandwidth in Kbps + that can be supported without underflow. + This is a low bandwidth threshold which should + be applied in most scenarios to be safe from + underflows when unable to satisfy bandwidth + requirements. +- qcom,sde-max-bw-high-kbps: This value indicates the max bandwidth in Kbps + that can be supported without underflow in the + event where there is no VFE. + This is a high bandwidth threshold which can be + applied in scenarios where panel interface can + be more tolerant to memory latency such as + command mode panels. +- qcom,sde-core-ib-ff: A string entry indicating the fudge factor for + core ib calculation. +- qcom,sde-core-clk-ff: A string entry indicating the fudge factor for + core clock calculation. +- qcom,sde-min-core-ib-kbps: This u32 value indicates the minimum mnoc ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-min-llcc-ib-kbps: This u32 value indicates the minimum llcc ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-min-dram-ib-kbps: This u32 value indicates the minimum dram ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-comp-ratio-rt: A string entry indicating the compression ratio + for each supported compressed format on realtime interface. + The string is composed of one or more of + /// + separated with spaces. +- qcom,sde-comp-ratio-nrt: A string entry indicating the compression ratio + for each supported compressed format on non-realtime interface. + The string is composed of one or more of + /// + separated with spaces. +- qcom,sde-undersized-prefill-lines: A u32 value indicates the size of undersized prefill in lines. +- qcom,sde-xtra-prefill-lines: A u32 value indicates the extra prefill in lines. +- qcom,sde-dest-scale-prefill-lines: A u32 value indicates the latency of destination scaler in lines. +- qcom,sde-macrotile-prefill-lines: A u32 value indicates the latency of macrotile in lines. +- qcom,sde-yuv-nv12-prefill-lines: A u32 value indicates the latency of yuv/nv12 in lines. +- qcom,sde-linear-prefill-lines: A u32 value indicates the latency of linear in lines. +- qcom,sde-downscaling-prefill-lines: A u32 value indicates the latency of downscaling in lines. +- qcom,sde-max-per-pipe-bw-kbps: Array of u32 value indicates the max per pipe bandwidth in Kbps. +- qcom,sde-amortizable-threshold: This value indicates the min for traffic shaping in lines. +- qcom,sde-vbif-qos-rt-remap: This array is used to program vbif qos remapper register + priority for realtime clients. +- qcom,sde-vbif-qos-nrt-remap: This array is used to program vbif qos remapper register + priority for non-realtime clients. +- qcom,sde-vbif-qos-cwb-remap: This array is used to program vbif qos remapper register + priority for concurrent writeback clients. +- qcom,sde-vbif-qos-lutdma-remap: This array is used to program vbif qos remapper register + priority for lutdma client. +- qcom,sde-qos-refresh-rates: A u32 array, indicating the different refresh rates for + danger, safe and creq luts on sspp and wb. All luts will be + multidimensional values when multiple refresh rate qos is present. +- qcom,sde-danger-lut: A u32 array of 5 cell property, with a format of + , + indicating the danger luts on sspp and wb. +- qcom,sde-safe-lut-linear: A u32 array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for linear format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-macrotile: A u32 array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for macrotile format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-macrotile-qseed: A u32 array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for macrotile format + with qseed3 on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-nrt: A u32 array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for nrt (e.g wfd) on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-cwb: A u32 array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for cwb on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-linear: A u64 array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for linear format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-macrotile: A u64 array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for macrotile format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-macrotile-qseed: A u64 array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for macrotile format + with qseed3 enabled on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-nrt: A u64 array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for nrt (e.g wfd) on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-cwb: A u64 array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for cwb on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-cdp-setting: Array of 2 cell property, with a format of + for cdp use cases in + order of , and . +- qcom,sde-qos-cpu-mask: A u32 value indicating desired PM QoS CPU affine mask. +- qcom,sde-qos-cpu-dma-latency: A u32 value indicating desired PM QoS CPU DMA latency in usec. +- qcom,sde-qos-cpu-irq-latency: A u32 value indicating desired PM QoS CPU irq latency in usec + for 120 fps based targets. +- qcom,sde-inline-rot-xin: An integer array of xin-ids related to inline + rotation. +- qcom,sde-inline-rot-xin-type: A string array indicating the type of xin, + namely sspp or wb. Number of entries should match + the number of xin-ids defined in + property: qcom,sde-inline-rot-xin +- qcom,sde-inline-rot-clk-ctrl: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of xin-ids defined in + property: qcom,sde-inline-rot-xin +- qcom,sde-secure-sid-mask: Array of secure SID masks used during + secure-camera/secure-display usecases. +- #power-domain-cells: Number of cells in a power-domain specifier and should contain 0. +- #list-cells: Number of mdp cells, must be 1. +- qcom,sde-mixer-display-pref: A string array indicating the preferred display type + for the mixer block. Possible values: + "primary" - preferred for primary display + "none" - no preference on display +- qcom,sde-mixer-cwb-pref: A string array indicating the preferred mixer block. + for CWB. Possible values: + "cwb" - preferred for cwb + "none" - no preference on display +- qcom,sde-ctl-display-pref: A string array indicating the preferred display type + for the ctl block. Possible values: + "primary" - preferred for primary display + "none" - no preference on display +- qcom,sde-pipe-order-version: A u32 property to indicate version of pipe + ordering block + 0: lower priority pipe has to be on the left for a given pair of pipes. + 1: priority have to be explicitly configured for a given pair of pipes. +- qcom,sde-limits: A node that lists the limits for different properties. This node + can have multiple child nodes. Each child node represents a + specific usecase limit. The usecase can be defined for properties like + sspp linewidth, bw limit etc. + e.g. qcom,sde-limits + -- qcom,sde-limit-name: name of the usecase + -- qcom,sde-limit-cases: different usecases to be considered + -- qcom,sde-limit-ids: respective ids for the above usecases + -- qcom,sde-limit-values: usecase and value for different combinations +- qcom,sde-mixer-stage-base-layer: A boolean property to indicate if a layer can be staged on base + stage instead of border fill + +Bus Scaling Subnodes: +- qcom,sde-reg-bus: Property to provide Bus scaling for register access for + mdss blocks. +- qcom,sde-data-bus: Property to provide Bus scaling for data bus access for + mdss blocks. +- qcom,sde-llcc-bus: Property to provide Bus scaling for data bus access for + mnoc to llcc. +- qcom,sde-ebi-bus: Property to provide Bus scaling for data bus access for + llcc to ebi. + +- qcom,sde-inline-rotator: A 2 cell property, with format of (rotator phandle, + instance id), of inline rotator device. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing client name. +- qcom,msm-bus,num-cases: This is the number of Bus Scaling use cases + defined in the vectors property. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + +SMMU Subnodes: +- smmu_sde_****: Child nodes representing sde smmu virtual + devices + +Subnode properties: +- compatible: Compatible names used for smmu devices. + names should be: + "qcom,smmu_sde_unsec": smmu context bank device + for unsecure sde real time domain. + "qcom,smmu_sde_sec": smmu context bank device + for secure sde real time domain. + "qcom,smmu_sde_nrt_unsec": smmu context bank device + for unsecure sde non-real time domain. + "qcom,smmu_sde_nrt_sec": smmu context bank device + for secure sde non-real time domain. + + +Please refer to ../../interrupt-controller/interrupts.txt for a general +description of interrupt bindings. + +Example: + mdss_mdp: qcom,mdss_mdp@900000 { + compatible = "qcom,sde-kms"; + reg = <0x00900000 0x90000>, + <0x009b0000 0x1040>, + <0x009b8000 0x1040>, + <0x0aeac000 0x00f0>; + reg-names = "mdp_phys", + "vbif_phys", + "vbif_nrt_phys", + "regdma_phys"; + clocks = <&clock_mmss clk_mdss_ahb_clk>, + <&clock_mmss clk_mdss_axi_clk>, + <&clock_mmss clk_mdp_clk_src>, + <&clock_mmss clk_mdss_mdp_vote_clk>, + <&clock_mmss clk_smmu_mdp_axi_clk>, + <&clock_mmss clk_mmagic_mdss_axi_clk>, + <&clock_mmss clk_mdss_vsync_clk>; + clock-names = "iface_clk", + "bus_clk", + "core_clk_src", + "core_clk", + "iommu_clk", + "mmagic_clk", + "vsync_clk"; + clock-rate = <0>, <0>, <0>; + clock-max-rate= <0 320000000 0>; + mmagic-supply = <&gdsc_mmagic_mdss>; + vdd-supply = <&gdsc_mdss>; + interrupt-parent = <&intc>; + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&mdp_smmu 0>; + #power-domain-cells = <0>; + + qcom,sde-off = <0x1000>; + qcom,sde-ctl-off = <0x00002000 0x00002200 0x00002400 + 0x00002600 0x00002800>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + qcom,sde-mixer-off = <0x00045000 0x00046000 + 0x00047000 0x0004a000>; + qcom,sde-mixer-display-pref = "primary", "none", + "none", "none"; + qcom,sde-mixer-cwb-pref = "none", "none", + "cwb", "none"; + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-off = <0x00055000 0x00057000>; + qcom,sde-dspp-ad-off = <0x24000 0x22800>; + qcom,sde-dspp-ad-version = <0x00030000>; + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-wb-off = <0x00066000>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-intf-off = <0x0006b000 0x0006b800 + 0x0006c000 0x0006c800>; + qcom,sde-intf-type = "none", "dsi", "dsi", "hdmi"; + qcom,sde-pp-off = <0x00071000 0x00071800 + 0x00072000 0x00072800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0>; + qcom,sde-cdm-off = <0x0007a200>; + qcom,sde-dsc-off = <0x00081000 0x00081400>; + qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>; + + qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>; + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-qdss-off = <0x81a00>; + + qcom,sde-sspp-type = "vig", "vig", "vig", + "vig", "rgb", "rgb", + "rgb", "rgb", "dma", + "dma", "cursor", "cursor"; + + qcom,sde-sspp-off = <0x00005000 0x00007000 0x00009000 + 0x0000b000 0x00015000 0x00017000 + 0x00019000 0x0001b000 0x00025000 + 0x00027000 0x00035000 0x00037000>; + + qcom,sde-sspp-xin-id = <0 4 8 + 12 1 5 + 9 13 2 + 10 7 7>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, + <0x2c4 0>, <0x2ac 4>, <0x2b4 4>, <0x2bc 4>, + <0x2c4 4>, <0x2ac 8>, <0x2b4 8>, <0x3a8 16>, + <0x3b0 16>; + qcom,sde-sspp-clk-status = <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, + <0x2c4 0>, <0x2ac 4>, <0x2b4 4>, <0x2bc 4>, + <0x2c4 4>, <0x2ac 8>, <0x2b4 8>, <0x3a8 16>, + <0x3b0 16>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2560>; + qcom,sde-mixer-blendstages = <0x7>; + qcom,sde-highest-bank-bit = <0x2>; + qcom,sde-ubwc-version = <0x100>; + qcom,sde-ubwc-static = <0x100>; + qcom,sde-ubwc-swizzle = <0>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-smart-panel-align-mode = <0xd>; + qcom,sde-panic-per-pipe; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-sspp-src-size = <0x100>; + qcom,sde-mixer-size = <0x100>; + qcom,sde-ctl-size = <0x100>; + qcom,sde-dspp-top-size = <0xc>; + qcom,sde-dspp-size = <0x100>; + qcom,sde-intf-size = <0x100>; + qcom,sde-dsc-size = <0x100>; + qcom,sde-cdm-size = <0x100>; + qcom,sde-pp-size = <0x100>; + qcom,sde-wb-size = <0x100>; + qcom,sde-dest-scaler-top-size = <0xc>; + qcom,sde-dest-scaler-size = <0x800>; + qcom,sde-len = <0x100>; + qcom,sde-wb-linewidth = <2560>; + qcom,sde-sspp-scale-size = <0x100>; + qcom,sde-mixer-blendstages = <0x8>; + qcom,sde-qseed-type = "qseedv2"; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-highest-bank-bit = <15>; + qcom,sde-has-mixer-gc; + qcom,sde-has-idle-pc; + qcom,fullsize-va-map; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-sspp-max-rects = <1 1 1 1 + 1 1 1 1 + 1 1 + 1 1>; + qcom,sde-sspp-excl-rect = <1 1 1 1 + 1 1 1 1 + 1 1 + 1 1>; + qcom,sde-sspp-smart-dma-priority = <0 0 0 0 + 0 0 0 0 + 0 0 + 1 2>; + qcom,sde-smart-dma-rev = "smart_dma_v2"; + qcom,sde-te-off = <0x100>; + qcom,sde-te2-off = <0x100>; + qcom,sde-te-size = <0xffff>; + qcom,sde-te2-size = <0xffff>; + + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x2bc 16>; + + qcom,sde-danger-lut = <0x0000ffff 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>, <0x0003ffff + 0x0003ffff 0x00000000 0x00000000 0x0003ffff>; + + + qcom,sde-safe-lut-linear = <0 0xff00>, <0 0xfe00>; + qcom,sde-safe-lut-macrotile = <0 0xff00>, <0 0xfe00>; + qcom,sde-safe-lut-macrotile-qseed = <0 0xff00>, <0 0xfe00>; + qcom,sde-safe-lut-nrt = <0 0xffff>, <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0x3ff>, <0x3ff>; + + + qcom,sde-qos-lut-linear = <0 0x00112233 0x44556677>, + <0 0x00112234 0x45566777>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>, + <0 0x00112234 0x45566777>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>, + <0 0x00112236 0x67777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>, + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x66666541 0x00000000>, + <0 0x66666541 0x00000000>; + qcom,sde-qos-refresh-rates = <60 120>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + qcom,sde-vbif-off = <0 0>; + qcom,sde-vbif-id = <0 1>; + qcom,sde-vbif-default-ot-rd-limit = <32>; + qcom,sde-vbif-default-ot-wr-limit = <16>; + qcom,sde-vbif-dynamic-ot-rd-limit = <62208000 2>, + <124416000 4>, <248832000 16>; + qcom,sde-vbif-dynamic-ot-wr-limit = <62208000 2>, + <124416000 4>, <248832000 16>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-uidle-off = <0x80000>; + qcom,sde-uidle-size = <0x70>; + + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <1>; + + qcom,sde-max-bw-high-kbps = <9000000>; + qcom,sde-max-bw-low-kbps = <9000000>; + + qcom,sde-core-ib-ff = "1.1"; + qcom,sde-core-clk-ff = "1.0"; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-comp-ratio-rt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3"; + qcom,sde-comp-ratio-nrt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3"; + qcom,sde-undersized-prefill-lines = <4>; + qcom,sde-xtra-prefill-lines = <5>; + qcom,sde-dest-scale-prefill-lines = <6>; + qcom,sde-macrotile-prefill-lines = <7>; + qcom,sde-yuv-nv12-prefill-lines = <8>; + qcom,sde-linear-prefill-lines = <9>; + qcom,sde-downscaling-prefill-lines = <10>; + qcom,sde-max-per-pipe-bw-kbps = <2400000 2400000 2400000 2400000 + 2400000 2400000 2400000 2400000>; + qcom,sde-amortizable-threshold = <11>; + qcom,sde-secure-sid-mask = <0x200801 0x200c01>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-qos-cwb-remap = <3 3 4 4 5 5 6 3>; + qcom,sde-vbif-qos-lutdma-remap = <3 3 3 3 4 4 4 4>; + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010002>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + qcom,sde-reg-dma-broadcast-disabled = <0>; + qcom,sde-reg-dma-xin-id = <7>; + qcom,sde-reg-dma-clk-ctrl = <0x2bc 20>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x320>; + qcom,sde-vig-qseed-off = <0x200>; + qcom,sde-vig-qseed-size = <0x74>; + /* Offset from vig top, version of HSIC */ + qcom,sde-vig-hsic = <0x200 0x00010000>; + qcom,sde-vig-memcolor = <0x200 0x00010000>; + qcom,sde-vig-pcc = <0x1780 0x00010000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + } + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + } + }; + + qcom,sde-sspp-rgb-blocks { + qcom,sde-rgb-scaler-off = <0x200>; + qcom,sde-rgb-scaler-size = <0x74>; + qcom,sde-rgb-pcc = <0x380 0x00010000>; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00010000>; + qcom,sde-dspp-pcc = <0x1700 0x00010000>; + qcom,sde-dspp-gc = <0x17c0 0x00010000>; + qcom,sde-dspp-hsic = <0x0 0x00010000>; + qcom,sde-dspp-memcolor = <0x0 0x00010000>; + qcom,sde-dspp-sixzone = <0x0 0x00010000>; + qcom,sde-dspp-gamut = <0x1600 0x00010000>; + qcom,sde-dspp-dither = <0x0 0x00010000>; + qcom,sde-dspp-hist = <0x0 0x00010000>; + qcom,sde-dspp-vlut = <0x0 0x00010000>; + }; + + qcom,sde-limits { + qcom,sde-linewidth-limits{ + qcom,sde-limit-cases = "vig", "dma", "scaling", "inline_rot"; + qcom,sde-limit-ids= <0x1 0x2 0x4 0x8>; + /* the qcom,sde-limit-values property consist of two values: + one for the usecase and the other for the value. The usecase can be + any combination of the values mentioned in qcom,sde-limit-ids. + For eg: <0x5 2560> means usecase is 0x5 and value is 2560. + 0x5 = (0x1 | 0x4) = vig + scaling. Thus the linewidth for usecase + vig + scaling = 2560 */ + qcom,sde-limit-values = <0x1 4096>, + <0x5 2560>, + <0xd 1088>, + <0x2 4096>; + }; + qcom,sde-bw-limits{ + qcom,sde-limit-cases = "per_pipe", "total_bw", "vfe_on", "cwb_on"; + qcom,sde-limit-ids = <0x1 0x2 0x4 0x8>; + qcom,sde-limit-values = <0x1 2600000>, + <0x9 2600000>, + <0x5 2600000>, + <0xd 2600000>, + <0x2 5800000>, + <0xa 5500000>, + <0x6 4400000>, + <0xe 3900000>; + }; + }; + + qcom,sde-mixer-blocks { + qcom,sde-mixer-gc = <0x3c0 0x00010000>; + }; + + qcom,msm-hdmi-audio-rx { + compatible = "qcom,msm-hdmi-audio-codec-rx"; + }; + + qcom,sde-inline-rotator = <&mdss_rotator 0>; + qcom,sde-inline-rot-xin = <10 11>; + qcom,sde-inline-rot-xin-type = "sspp", "wb"; + qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, <25 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <25 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>, + <25 512 0 6400000>; + }; + qcom,sde-llcc-bus { + qcom,msm-bus,name = "mdss_sde_llcc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <132 770 0 0>, + <132 770 0 6400000>, + <132 770 0 6400000>; + }; + qcom,sde-ebi-bus { + qcom,msm-bus,name = "mdss_sde_ebi"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 6400000>, + <129 512 0 6400000>; + }; + + qcom,sde-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + + smmu_kms_unsec: qcom,smmu_kms_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&mmss_smmu 0>; + }; + + smmu_kms_sec: qcom,smmu_kms_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&mmss_smmu 1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/multi-inno,mi0283qt.txt b/arch/arm64/boot/dts/vendor/bindings/display/multi-inno,mi0283qt.txt new file mode 100644 index 0000000000000000000000000000000000000000..eed48c3d4875f0a166aa03e69bded4b78e9682e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/multi-inno,mi0283qt.txt @@ -0,0 +1,27 @@ +Multi-Inno MI0283QT display panel + +Required properties: +- compatible: "multi-inno,mi0283qt". + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional properties: +- dc-gpios: D/C pin. The presence/absence of this GPIO determines + the panel interface mode (IM[3:0] pins): + - present: IM=x110 4-wire 8-bit data serial interface + - absent: IM=x101 3-wire 9-bit data serial interface +- reset-gpios: Reset pin +- power-supply: A regulator node for the supply voltage. +- backlight: phandle of the backlight device attached to the panel +- rotation: panel rotation in degrees counter clockwise (0,90,180,270) + +Example: + mi0283qt@0{ + compatible = "multi-inno,mi0283qt"; + reg = <0>; + spi-max-frequency = <32000000>; + rotation = <90>; + dc-gpios = <&gpio 25 0>; + backlight = <&backlight>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/mxsfb.txt b/arch/arm64/boot/dts/vendor/bindings/display/mxsfb.txt new file mode 100644 index 0000000000000000000000000000000000000000..472e1ea6c591e8cfa174a31f078b891c3de3e929 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/mxsfb.txt @@ -0,0 +1,86 @@ +* Freescale MXS LCD Interface (LCDIF) + +New bindings: +============= +Required properties: +- compatible: Should be "fsl,imx23-lcdif" for i.MX23. + Should be "fsl,imx28-lcdif" for i.MX28. + Should be "fsl,imx6sx-lcdif" for i.MX6SX. +- reg: Address and length of the register set for LCDIF +- interrupts: Should contain LCDIF interrupt +- clocks: A list of phandle + clock-specifier pairs, one for each + entry in 'clock-names'. +- clock-names: A list of clock names. For MXSFB it should contain: + - "pix" for the LCDIF block clock + - (MX6SX-only) "axi", "disp_axi" for the bus interface clock + +Required sub-nodes: + - port: The connection to an encoder chip. + +Example: + + lcdif1: display-controller@2220000 { + compatible = "fsl,imx6sx-lcdif", "fsl,imx28-lcdif"; + reg = <0x02220000 0x4000>; + interrupts = ; + clocks = <&clks IMX6SX_CLK_LCDIF1_PIX>, + <&clks IMX6SX_CLK_LCDIF_APB>, + <&clks IMX6SX_CLK_DISPLAY_AXI>; + clock-names = "pix", "axi", "disp_axi"; + + port { + parallel_out: endpoint { + remote-endpoint = <&panel_in_parallel>; + }; + }; + }; + +Deprecated bindings: +==================== +Required properties: +- compatible: Should be "fsl,imx23-lcdif" for i.MX23. + Should be "fsl,imx28-lcdif" for i.MX28. +- reg: Address and length of the register set for LCDIF +- interrupts: Should contain LCDIF interrupts +- display: phandle to display node (see below for details) + +* display node + +Required properties: +- bits-per-pixel: <16> for RGB565, <32> for RGB888/666. +- bus-width: number of data lines. Could be <8>, <16>, <18> or <24>. + +Required sub-node: +- display-timings: Refer to binding doc display-timing.txt for details. + +Examples: + +lcdif@80030000 { + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 2000>; + interrupts = <38 86>; + + display: display { + bits-per-pixel = <32>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <164>; + hback-porch = <89>; + hsync-len = <10>; + vback-porch = <23>; + vfront-porch = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt new file mode 100644 index 0000000000000000000000000000000000000000..6812280cb109fed629d669547407ae58b47fff02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/ampire,am-480272h3tmqw-t01h.txt @@ -0,0 +1,26 @@ +Ampire AM-480272H3TMQW-T01H 4.3" WQVGA TFT LCD panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "ampire,am-480272h3tmqw-t01h" + +Optional properties: +- power-supply: regulator to provide the supply voltage +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Optional nodes: +- Video port for RGB input. + +Example: + panel_rgb: panel-rgb { + compatible = "ampire,am-480272h3tmqw-t01h"; + enable-gpios = <&gpioa 8 1>; + port { + panel_in_rgb: endpoint { + remote-endpoint = <&controller_out_rgb>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/ampire,am800480r3tmqwa1h.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/ampire,am800480r3tmqwa1h.txt new file mode 100644 index 0000000000000000000000000000000000000000..83e2cae1cc1b48eb7830e923322fa38f043537d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/ampire,am800480r3tmqwa1h.txt @@ -0,0 +1,7 @@ +Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel + +Required properties: +- compatible: should be "ampire,am800480r3tmqwa1h" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/arm,versatile-tft-panel.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/arm,versatile-tft-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..248141c3c7e3ddc1fc74143bce4b9b8ae6377750 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/arm,versatile-tft-panel.txt @@ -0,0 +1,31 @@ +ARM Versatile TFT Panels + +These panels are connected to the daughterboards found on the +ARM Versatile reference designs. + +This device node must appear as a child to a "syscon"-compatible +node. + +Required properties: +- compatible: should be "arm,versatile-tft-panel" + +Required subnodes: +- port: see display/panel/panel-common.txt, graph.txt + + +Example: + +sysreg@0 { + compatible = "arm,versatile-sysreg", "syscon", "simple-mfd"; + reg = <0x00000 0x1000>; + + panel: display@0 { + compatible = "arm,versatile-tft-panel"; + + port { + panel_in: endpoint { + remote-endpoint = <&foo>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b080uan01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b080uan01.txt new file mode 100644 index 0000000000000000000000000000000000000000..bae0e2b5146799eb96dcdc3f2a0157f082d8e353 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b080uan01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 8.0" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101ean01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101aw03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101aw03.txt new file mode 100644 index 0000000000000000000000000000000000000000..72e088a4fb3a954db5afb08a479ab57a69f6a0f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101aw03.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101aw03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101ean01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101ean01.txt new file mode 100644 index 0000000000000000000000000000000000000000..3590b0741619cec0ff7d31b2a6d4b1ff2210cd00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101ean01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101ean01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101xtn01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101xtn01.txt new file mode 100644 index 0000000000000000000000000000000000000000..889d511d66c91901e1ee0839fa4eaa93947fcca6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b101xtn01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101xtn01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b116xw03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b116xw03.txt new file mode 100644 index 0000000000000000000000000000000000000000..690d0a568ef392e162505d7e78aebcb96f061f0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b116xw03.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel + +Required properties: +- compatible: should be "auo,b116xw03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b133htn01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b133htn01.txt new file mode 100644 index 0000000000000000000000000000000000000000..302226b5bb557014bb978e4951996a6aee2bc949 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b133htn01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 13.3" FHD (1920x1080) color TFT-LCD panel + +Required properties: +- compatible: should be "auo,b133htn01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b133xtn01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b133xtn01.txt new file mode 100644 index 0000000000000000000000000000000000000000..7443b7c767698131e763806c01d537458769dc73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,b133xtn01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 13.3" WXGA (1366x768) TFT LCD panel + +Required properties: +- compatible: should be "auo,b133xtn01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g070vvn01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g070vvn01.txt new file mode 100644 index 0000000000000000000000000000000000000000..49e4105378f65e16c14f9616d2457d7a9e958c5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g070vvn01.txt @@ -0,0 +1,29 @@ +AU Optronics Corporation 7.0" FHD (800 x 480) TFT LCD panel + +Required properties: +- compatible: should be "auo,g070vvn01" +- backlight: phandle of the backlight device attached to the panel +- power-supply: single regulator to provide the supply voltage + +Required nodes: +- port: Parallel port mapping to connect this display + +This panel needs single power supply voltage. Its backlight is conntrolled +via PWM signal. + +Example: +-------- + +Example device-tree definition when connected to iMX6Q based board + + lcd_panel: lcd-panel { + compatible = "auo,g070vvn01"; + backlight = <&backlight_lcd>; + power-supply = <®_display>; + + port { + lcd_panel_in: endpoint { + remote-endpoint = <&lcd_display_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g104sn02.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g104sn02.txt new file mode 100644 index 0000000000000000000000000000000000000000..85626edf63e516548068d45ce0c38a7a3cc8babe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g104sn02.txt @@ -0,0 +1,12 @@ +AU Optronics Corporation 10.4" (800x600) color TFT LCD panel + +Required properties: +- compatible: should be "auo,g104sn02" +- power-supply: as specified in the base binding + +Optional properties: +- backlight: as specified in the base binding +- enable-gpios: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g133han01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g133han01.txt new file mode 100644 index 0000000000000000000000000000000000000000..3afc7674782416ff60a8005fd0a73d6ed4295b31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g133han01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel + +Required properties: +- compatible: should be "auo,g133han01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g185han01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g185han01.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed657c2141d4de98db506f3054e005216aeb0d2d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,g185han01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel + +Required properties: +- compatible: should be "auo,g185han01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,p320hvn03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,p320hvn03.txt new file mode 100644 index 0000000000000000000000000000000000000000..59bb6cd8aa75b5398f0b622ea395be8412a20ed5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,p320hvn03.txt @@ -0,0 +1,8 @@ +AU Optronics Corporation 31.5" FHD (1920x1080) TFT LCD panel + +Required properties: +- compatible: should be "auo,p320hvn03" +- power-supply: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,t215hvn01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,t215hvn01.txt new file mode 100644 index 0000000000000000000000000000000000000000..cbd9da3f03b13964af5f7806f65e9bb1be0a2256 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/auo,t215hvn01.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 21.5" FHD (1920x1080) color TFT LCD panel + +Required properties: +- compatible: should be "auo,t215hvn01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/avic,tm070ddh03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/avic,tm070ddh03.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6f2f3e8f44e89aac4c50ff89d606a005c8a5285 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/avic,tm070ddh03.txt @@ -0,0 +1,7 @@ +Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel + +Required properties: +- compatible: should be "avic,tm070ddh03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,hv070wsa-100.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,hv070wsa-100.txt new file mode 100644 index 0000000000000000000000000000000000000000..55183d360032ceffdc88972db0b82506fd86a495 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,hv070wsa-100.txt @@ -0,0 +1,28 @@ +BOE HV070WSA-100 7.01" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "boe,hv070wsa-100" +- power-supply: regulator to provide the VCC supply voltage (3.3 volts) +- enable-gpios: GPIO pin to enable and disable panel (active high) + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [1]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + panel: panel { + compatible = "boe,hv070wsa-100"; + power-supply = <&vcc_3v3_reg>; + enable-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>; + port { + panel_ep: endpoint { + remote-endpoint = <&bridge_out_ep>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,nv101wxmn51.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,nv101wxmn51.txt new file mode 100644 index 0000000000000000000000000000000000000000..b258d6a91ec6daa66bccea9b97031f52b3cc4588 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,nv101wxmn51.txt @@ -0,0 +1,7 @@ +BOE OPTOELECTRONICS TECHNOLOGY 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "boe,nv101wxmn51" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,tv080wum-nl0.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,tv080wum-nl0.txt new file mode 100644 index 0000000000000000000000000000000000000000..50be5e2438b27bfc9f23ff6014441dcebd66c076 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/boe,tv080wum-nl0.txt @@ -0,0 +1,7 @@ +Boe Corporation 8.0" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "boe,tv080wum-nl0" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa070wp03xg.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa070wp03xg.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd22685d2adc32a05a1924b1b568e87499fd12c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa070wp03xg.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 7" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa070wp03xg" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa101wa01a.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa101wa01a.txt new file mode 100644 index 0000000000000000000000000000000000000000..f24614e4d5ecb838f0786e34151a89587999ac58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa101wa01a.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wa01a" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa101wb03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa101wb03.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ab2c05a4c22a62d44289d35f1f2b621efb5052a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/chunghwa,claa101wb03.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wb03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/dataimage,scf0700c48ggu18.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/dataimage,scf0700c48ggu18.txt new file mode 100644 index 0000000000000000000000000000000000000000..897085ee3cd4bf6f6fbe4cb78b7b9b67e8226a44 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/dataimage,scf0700c48ggu18.txt @@ -0,0 +1,8 @@ +DataImage, Inc. 7" WVGA (800x480) TFT LCD panel with 24-bit parallel interface. + +Required properties: +- compatible: should be "dataimage,scf0700c48ggu18" +- power-supply: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/display-timing.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/display-timing.txt new file mode 100644 index 0000000000000000000000000000000000000000..78222ced187436503382c0241f39a438af842c16 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/display-timing.txt @@ -0,0 +1,123 @@ +display-timing bindings +======================= + +display-timings node +-------------------- + +required properties: + - none + +optional properties: + - native-mode: The native mode for the display, in case multiple modes are + provided. When omitted, assume the first node is the native. + +timing subnode +-------------- + +required properties: + - hactive, vactive: display resolution + - hfront-porch, hback-porch, hsync-len: horizontal display timing parameters + in pixels + vfront-porch, vback-porch, vsync-len: vertical display timing parameters in + lines + - clock-frequency: display clock in Hz + +optional properties: + - hsync-active: hsync pulse is active low/high/ignored + - vsync-active: vsync pulse is active low/high/ignored + - de-active: data-enable pulse is active low/high/ignored + - pixelclk-active: with + - active high = drive pixel data on rising edge/ + sample data on falling edge + - active low = drive pixel data on falling edge/ + sample data on rising edge + - ignored = ignored + - syncclk-active: with + - active high = drive sync on rising edge/ + sample sync on falling edge of pixel + clock + - active low = drive sync on falling edge/ + sample sync on rising edge of pixel + clock + - omitted = same configuration as pixelclk-active + - interlaced (bool): boolean to enable interlaced mode + - doublescan (bool): boolean to enable doublescan mode + - doubleclk (bool): boolean to enable doubleclock mode + +All the optional properties that are not bool follow the following logic: + <1>: high active + <0>: low active + omitted: not used on hardware + +There are different ways of describing the capabilities of a display. The +devicetree representation corresponds to the one commonly found in datasheets +for displays. If a display supports multiple signal timings, the native-mode +can be specified. + +The parameters are defined as: + + +----------+-------------------------------------+----------+-------+ + | | ^ | | | + | | |vback_porch | | | + | | v | | | + +----------#######################################----------+-------+ + | # ^ # | | + | # | # | | + | hback # | # hfront | hsync | + | porch # | hactive # porch | len | + |<-------->#<-------+--------------------------->#<-------->|<----->| + | # | # | | + | # |vactive # | | + | # | # | | + | # v # | | + +----------#######################################----------+-------+ + | | ^ | | | + | | |vfront_porch | | | + | | v | | | + +----------+-------------------------------------+----------+-------+ + | | ^ | | | + | | |vsync_len | | | + | | v | | | + +----------+-------------------------------------+----------+-------+ + +Note: In addition to being used as subnode(s) of display-timings, the timing + subnode may also be used on its own. This is appropriate if only one mode + need be conveyed. In this case, the node should be named 'panel-timing'. + + +Example: + + display-timings { + native-mode = <&timing0>; + timing0: 1080p24 { + /* 1920x1080p24 */ + clock-frequency = <52000000>; + hactive = <1920>; + vactive = <1080>; + hfront-porch = <25>; + hback-porch = <25>; + hsync-len = <25>; + vback-porch = <2>; + vfront-porch = <2>; + vsync-len = <2>; + hsync-active = <1>; + }; + }; + +Every required property also supports the use of ranges, so the commonly used +datasheet description with minimum, typical and maximum values can be used. + +Example: + + timing1: timing { + /* 1920x1080p24 */ + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hsync-len = <0 44 60>; + hfront-porch = <80 88 95>; + hback-porch = <100 148 160>; + vfront-porch = <0 4 6>; + vback-porch = <0 36 50>; + vsync-len = <0 5 6>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/dlc,dlc0700yzg-1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/dlc,dlc0700yzg-1.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf06bb025b086306502c026a7950c1be504c6311 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/dlc,dlc0700yzg-1.txt @@ -0,0 +1,13 @@ +DLC Display Co. DLC0700YZG-1 7.0" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "dlc,dlc0700yzg-1" +- power-supply: See simple-panel.txt + +Optional properties: +- reset-gpios: See panel-common.txt +- enable-gpios: See simple-panel.txt +- backlight: See simple-panel.txt + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/edt,et-series.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/edt,et-series.txt new file mode 100644 index 0000000000000000000000000000000000000000..f56b99ebd9be142bef91df47b237a5a92ac0dd8d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/edt,et-series.txt @@ -0,0 +1,39 @@ +Emerging Display Technology Corp. Displays +========================================== + + +Display bindings for EDT Display Technology Corp. Displays which are +compatible with the simple-panel binding, which is specified in +simple-panel.txt + + +5,7" WVGA TFT Panels +-------------------- + ++-----------------+---------------------+-------------------------------------+ +| Identifier | compatbile | description | ++=================+=====================+=====================================+ +| ET057090DHU | edt,et057090dhu | 5.7" VGA TFT LCD panel | ++-----------------+---------------------+-------------------------------------+ + + +7,0" WVGA TFT Panels +-------------------- + ++-----------------+---------------------+-------------------------------------+ +| Identifier | compatbile | description | ++=================+=====================+=====================================+ +| ETM0700G0DH6 | edt,etm070080dh6 | WVGA TFT Display with capacitive | +| | | Touchscreen | ++-----------------+---------------------+-------------------------------------+ +| ETM0700G0BDH6 | edt,etm070080bdh6 | Same as ETM0700G0DH6 but with | +| | | inverted pixel clock. | ++-----------------+---------------------+-------------------------------------+ +| ETM0700G0EDH6 | edt,etm070080edh6 | Same display as the ETM0700G0BDH6, | +| | | but with changed Hardware for the | +| | | backlight and the touch interface | ++-----------------+---------------------+-------------------------------------+ +| ET070080DH6 | edt,etm070080dh6 | Same timings as the ETM0700G0DH6, | +| | | but with resistive touch. | ++-----------------+---------------------+-------------------------------------+ + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/foxlink,fl500wvr00-a0t.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/foxlink,fl500wvr00-a0t.txt new file mode 100644 index 0000000000000000000000000000000000000000..b47f9d87bc1956f63c7e8c2afea9213549f68727 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/foxlink,fl500wvr00-a0t.txt @@ -0,0 +1,7 @@ +Foxlink Group 5" WVGA TFT LCD panel + +Required properties: +- compatible: should be "foxlink,fl500wvr00-a0t" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/giantplus,gpg482739qs5.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/giantplus,gpg482739qs5.txt new file mode 100644 index 0000000000000000000000000000000000000000..24b0b624434bf84c6664140ac7274a2581260af4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/giantplus,gpg482739qs5.txt @@ -0,0 +1,7 @@ +GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel + +Required properties: +- compatible: should be "giantplus,gpg48273qs5" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/hannstar,hsd070pww1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/hannstar,hsd070pww1.txt new file mode 100644 index 0000000000000000000000000000000000000000..7da1d5c038ffb46de435d93081b860d601f55b76 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/hannstar,hsd070pww1.txt @@ -0,0 +1,7 @@ +HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel + +Required properties: +- compatible: should be "hannstar,hsd070pww1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/hannstar,hsd100pxn1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/hannstar,hsd100pxn1.txt new file mode 100644 index 0000000000000000000000000000000000000000..8270319a99de5551bdfd6bcb619e27c9500c9782 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/hannstar,hsd100pxn1.txt @@ -0,0 +1,7 @@ +HannStar Display Corp. HSD100PXN1 10.1" XGA LVDS panel + +Required properties: +- compatible: should be "hannstar,hsd100pxn1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/hit,tx23d38vm0caa.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/hit,tx23d38vm0caa.txt new file mode 100644 index 0000000000000000000000000000000000000000..04caaae19af6f943bd6c5cf9689ce02793caade2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/hit,tx23d38vm0caa.txt @@ -0,0 +1,7 @@ +Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel + +Required properties: +- compatible: should be "hit,tx23d38vm0caa" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/ilitek,ili9322.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/ilitek,ili9322.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d5ce6ad6ec71f48d8e67a36014101da708d3f7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/ilitek,ili9322.txt @@ -0,0 +1,49 @@ +Ilitek ILI9322 TFT panel driver with SPI control bus + +This is a driver for 320x240 TFT panels, accepting a variety of input +streams that get adapted and scaled to the panel. The panel output has +960 TFT source driver pins and 240 TFT gate driver pins, VCOM, VCOML and +VCOMH outputs. + +Required properties: + - compatible: "dlink,dir-685-panel", "ilitek,ili9322" + (full system-specific compatible is always required to look up configuration) + - reg: address of the panel on the SPI bus + +Optional properties: + - vcc-supply: core voltage supply, see regulator/regulator.txt + - iovcc-supply: voltage supply for the interface input/output signals, + see regulator/regulator.txt + - vci-supply: voltage supply for analog parts, see regulator/regulator.txt + - reset-gpios: a GPIO spec for the reset pin, see gpio/gpio.txt + + The following optional properties only apply to RGB and YUV input modes and + can be omitted for BT.656 input modes: + + - pixelclk-active: see display/panel/display-timing.txt + - de-active: see display/panel/display-timing.txt + - hsync-active: see display/panel/display-timing.txt + - vsync-active: see display/panel/display-timing.txt + +The panel must obey the rules for a SPI slave device as specified in +spi/spi-bus.txt + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in +media/video-interfaces.txt. This node should describe panel's video bus. + +Example: + +panel: display@0 { + compatible = "dlink,dir-685-panel", "ilitek,ili9322"; + reg = <0>; + vcc-supply = <&vdisp>; + iovcc-supply = <&vdisp>; + vci-supply = <&vdisp>; + + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/ilitek,ili9881c.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/ilitek,ili9881c.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a041acb4e185367f1990fdcd11da23d958ff61c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/ilitek,ili9881c.txt @@ -0,0 +1,20 @@ +Ilitek ILI9881c based MIPI-DSI panels + +Required properties: + - compatible: must be "ilitek,ili9881c" and one of: + * "bananapi,lhr050h41" + - reg: DSI virtual channel used by that screen + - power-supply: phandle to the power regulator + - reset-gpios: a GPIO phandle for the reset pin + +Optional properties: + - backlight: phandle to the backlight used + +Example: +panel@0 { + compatible = "bananapi,lhr050h41", "ilitek,ili9881c"; + reg = <0>; + power-supply = <®_display>; + reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */ + backlight = <&pwm_bl>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,at043tn24.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,at043tn24.txt new file mode 100644 index 0000000000000000000000000000000000000000..4104226b61bc7a4a08401d34aa27044ff02dd9ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,at043tn24.txt @@ -0,0 +1,7 @@ +Innolux AT043TN24 4.3" WQVGA TFT LCD panel + +Required properties: +- compatible: should be "innolux,at043tn24" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,at070tn92.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,at070tn92.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e10cd7824919b7c026ce8a5d9c6e1f7c951e7f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,at070tn92.txt @@ -0,0 +1,7 @@ +Innolux AT070TN92 7.0" WQVGA TFT LCD panel + +Required properties: +- compatible: should be "innolux,at070tn92" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g070y2-l01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g070y2-l01.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c234cf68e1163989537d56bfe63c6a07d3cd175 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g070y2-l01.txt @@ -0,0 +1,12 @@ +Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel + +Required properties: +- compatible: should be "innolux,g070y2-l01" +- power-supply: as specified in the base binding + +Optional properties: +- backlight: as specified in the base binding +- enable-gpios: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g101ice-l01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g101ice-l01.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e7590465227b500381fa77292a68664e334c5a2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g101ice-l01.txt @@ -0,0 +1,7 @@ +Innolux Corporation 10.1" G101ICE-L01 WXGA (1280x800) LVDS panel + +Required properties: +- compatible: should be "innolux,g101ice-l01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g121i1-l01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g121i1-l01.txt new file mode 100644 index 0000000000000000000000000000000000000000..2743b07cd2f22e2073720ecc4c0c2cdb79a868b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g121i1-l01.txt @@ -0,0 +1,7 @@ +Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel + +Required properties: +- compatible: should be "innolux,g121i1-l01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g121x1-l03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g121x1-l03.txt new file mode 100644 index 0000000000000000000000000000000000000000..649744620ae1cdd0e46c3ff9427e45a14a610319 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,g121x1-l03.txt @@ -0,0 +1,7 @@ +Innolux Corporation 12.1" G121X1-L03 XGA (1024x768) TFT LCD panel + +Required properties: +- compatible: should be "innolux,g121x1-l03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,n116bge.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,n116bge.txt new file mode 100644 index 0000000000000000000000000000000000000000..081bb939ed319be1b8c793b96decc485c3740a99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,n116bge.txt @@ -0,0 +1,7 @@ +Innolux Corporation 11.6" WXGA (1366x768) TFT LCD panel + +Required properties: +- compatible: should be "innolux,n116bge" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,n156bge-l21.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,n156bge-l21.txt new file mode 100644 index 0000000000000000000000000000000000000000..7825844aafdff781f764da037681687e73f68d5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,n156bge-l21.txt @@ -0,0 +1,7 @@ +InnoLux 15.6" WXGA TFT LCD panel + +Required properties: +- compatible: should be "innolux,n156bge-l21" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,p079zca.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,p079zca.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0f55161579a55f6c83146929fb46b7ad40f7d96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,p079zca.txt @@ -0,0 +1,22 @@ +Innolux P079ZCA 7.85" 768x1024 TFT LCD panel + +Required properties: +- compatible: should be "innolux,p079zca" +- reg: DSI virtual channel of the peripheral +- power-supply: phandle of the regulator that provides the supply voltage +- enable-gpios: panel enable gpio + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + &mipi_dsi { + panel { + compatible = "innolux,p079zca"; + reg = <0>; + power-supply = <...>; + backlight = <&backlight>; + enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,p097pfg.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,p097pfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..595d9dfeffd3ff97d3e03658cab1351701bccbd0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,p097pfg.txt @@ -0,0 +1,24 @@ +Innolux P097PFG 9.7" 1536x2048 TFT LCD panel + +Required properties: +- compatible: should be "innolux,p097pfg" +- reg: DSI virtual channel of the peripheral +- avdd-supply: phandle of the regulator that provides positive voltage +- avee-supply: phandle of the regulator that provides negative voltage +- enable-gpios: panel enable gpio + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + &mipi_dsi { + panel { + compatible = "innolux,p079zca"; + reg = <0>; + avdd-supply = <...>; + avee-supply = <...>; + backlight = <&backlight>; + enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,tv123wam.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,tv123wam.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9b35265fa13a48e938348abc2054990713971ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,tv123wam.txt @@ -0,0 +1,20 @@ +Innolux TV123WAM 12.3 inch eDP 2K display panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "innolux,tv123wam" +- power-supply: regulator to provide the supply voltage + +Optional properties: +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + panel_edp: panel-edp { + compatible = "innolux,tv123wam"; + enable-gpios = <&msmgpio 31 GPIO_ACTIVE_LOW>; + power-supply = <&pm8916_l2>; + backlight = <&backlight>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,zj070na-01p.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,zj070na-01p.txt new file mode 100644 index 0000000000000000000000000000000000000000..824f87f1526ded4a68ed5bb779d5dd7c15e16f72 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/innolux,zj070na-01p.txt @@ -0,0 +1,7 @@ +Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel + +Required properties: +- compatible: should be "innolux,zj070na-01p" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/jdi,lt070me05000.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/jdi,lt070me05000.txt new file mode 100644 index 0000000000000000000000000000000000000000..4989c91d505f6f11301a8530c4ffaca029c5095c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/jdi,lt070me05000.txt @@ -0,0 +1,31 @@ +JDI model LT070ME05000 1200x1920 7" DSI Panel + +Required properties: +- compatible: should be "jdi,lt070me05000" +- vddp-supply: phandle of the regulator that provides the supply voltage + Power IC supply (3-5V) +- iovcc-supply: phandle of the regulator that provides the supply voltage + IOVCC , power supply for LCM (1.8V) +- enable-gpios: phandle of gpio for enable line + LED_EN, LED backlight enable, High active +- reset-gpios: phandle of gpio for reset line + This should be 8mA, gpio can be configured using mux, pinctrl, pinctrl-names + XRES, Reset, Low active +- dcdc-en-gpios: phandle of the gpio for power ic line + Power IC supply enable, High active + +Example: + + dsi0: qcom,mdss_dsi@4700000 { + panel@0 { + compatible = "jdi,lt070me05000"; + reg = <0>; + + vddp-supply = <&pm8921_l17>; + iovcc-supply = <&pm8921_lvs7>; + + enable-gpios = <&pm8921_gpio 36 GPIO_ACTIVE_HIGH>; + reset-gpios = <&tlmm_pinmux 54 GPIO_ACTIVE_LOW>; + dcdc-en-gpios = <&pm8921_gpio 23 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/kingdisplay,kd097d04.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/kingdisplay,kd097d04.txt new file mode 100644 index 0000000000000000000000000000000000000000..164a5fa236daf7ad23bdeba391a8a241e83f8d0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/kingdisplay,kd097d04.txt @@ -0,0 +1,22 @@ +Kingdisplay KD097D04 9.7" 1536x2048 TFT LCD panel + +Required properties: +- compatible: should be "kingdisplay,kd097d04" +- reg: DSI virtual channel of the peripheral +- power-supply: phandle of the regulator that provides the supply voltage +- enable-gpios: panel enable gpio + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + &mipi_dsi { + panel { + compatible = "kingdisplay,kd097d04"; + reg = <0>; + power-supply = <...>; + backlight = <&backlight>; + enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/koe,tx31d200vm0baa.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/koe,tx31d200vm0baa.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a036ede3e2824d66bd27858333e01e39ca30ca7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/koe,tx31d200vm0baa.txt @@ -0,0 +1,25 @@ +Kaohsiung Opto-Electronics. TX31D200VM0BAA 12.3" HSXGA LVDS panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "koe,tx31d200vm0baa" + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Optional nodes: +- Video port for LVDS panel input. + +Example: + panel { + compatible = "koe,tx31d200vm0baa"; + backlight = <&backlight_lvds>; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/kyo,tcg121xglp.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/kyo,tcg121xglp.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8e940fe731eed77626ed2a2d4721112e88a263e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/kyo,tcg121xglp.txt @@ -0,0 +1,7 @@ +Kyocera Corporation 12.1" XGA (1024x768) TFT LCD panel + +Required properties: +- compatible: should be "kyo,tcg121xglp" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lb070wv8.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lb070wv8.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7588e5259cfdd2d4f1309c7f822866c0652116a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lb070wv8.txt @@ -0,0 +1,7 @@ +LG 7" (800x480 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lb070wv8" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,ld070wx3-sl01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,ld070wx3-sl01.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e649cb9aa1a37b94d82b393d704a3d2cd446e56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,ld070wx3-sl01.txt @@ -0,0 +1,7 @@ +LG Corporation 7" WXGA TFT LCD panel + +Required properties: +- compatible: should be "lg,ld070wx3-sl01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lg4573.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lg4573.txt new file mode 100644 index 0000000000000000000000000000000000000000..824441f4e95a2cb8323f06d3971baba4c099d3e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lg4573.txt @@ -0,0 +1,19 @@ +LG LG4573 TFT Liquid Crystal Display with SPI control bus + +Required properties: + - compatible: "lg,lg4573" + - reg: address of the panel on the SPI bus + +The panel must obey rules for SPI slave device specified in document [1]. + +[1]: Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + + lcd_panel: display@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "lg,lg4573"; + spi-max-frequency = <10000000>; + reg = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lh500wx1-sd03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lh500wx1-sd03.txt new file mode 100644 index 0000000000000000000000000000000000000000..a04fd2b2e73db04f2ce71bf7651b4a2fb2d5f7e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lh500wx1-sd03.txt @@ -0,0 +1,7 @@ +LG Corporation 5" HD TFT LCD panel + +Required properties: +- compatible: should be "lg,lh500wx1-sd03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp079qx1-sp0v.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp079qx1-sp0v.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9877acad012ee9a6ec45d2826475beb4870a522 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp079qx1-sp0v.txt @@ -0,0 +1,7 @@ +LG LP079QX1-SP0V 7.9" (1536x2048 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp079qx1-sp0v" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp097qx1-spa1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp097qx1-spa1.txt new file mode 100644 index 0000000000000000000000000000000000000000..42141516f078271c661c0a090350d369e4f13ef1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp097qx1-spa1.txt @@ -0,0 +1,7 @@ +LG 9.7" (2048x1536 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp097qx1-spa1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp120up1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp120up1.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c5de692c55ce6036219b9c812832ddb75ea14cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp120up1.txt @@ -0,0 +1,7 @@ +LG 12.0" (1920x1280 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp120up1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp129qe.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp129qe.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f262e0c5a2e15a3098e363ba8b62cd3290b3052 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lg,lp129qe.txt @@ -0,0 +1,7 @@ +LG 12.9" (2560x1700 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp129qe" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/lgphilips,lb035q02.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/lgphilips,lb035q02.txt new file mode 100644 index 0000000000000000000000000000000000000000..1a1e653e54072404c0df38935494ef4b6c1672bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/lgphilips,lb035q02.txt @@ -0,0 +1,33 @@ +LG.Philips LB035Q02 Panel +========================= + +Required properties: +- compatible: "lgphilips,lb035q02" +- enable-gpios: panel enable gpio + +Optional properties: +- label: a symbolic name for the panel + +Required nodes: +- Video port for DPI input + +Example +------- + +lcd-panel: panel@0 { + compatible = "lgphilips,lb035q02"; + reg = <0>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + label = "lcd"; + + enable-gpios = <&gpio7 7 0>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa070mc01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa070mc01.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d8f6eeef6d978133af9b0822bade8c8cb206bb6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa070mc01.txt @@ -0,0 +1,7 @@ +Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel + +Required properties: +- compatible: should be "mitsubishi,aa070mc01-ca1" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa104xd12.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa104xd12.txt new file mode 100644 index 0000000000000000000000000000000000000000..ced0121aed7db8db138df8d67d7cad5b06329510 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa104xd12.txt @@ -0,0 +1,47 @@ +Mitsubishi AA204XD12 LVDS Display Panel +======================================= + +The AA104XD12 is a 10.4" XGA TFT-LCD display panel. + +These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt +with the following device-specific properties. + + +Required properties: + +- compatible: Shall contain "mitsubishi,aa121td01" and "panel-lvds", in that + order. +- vcc-supply: Reference to the regulator powering the panel VCC pins. + + +Example +------- + +panel { + compatible = "mitsubishi,aa104xd12", "panel-lvds"; + vcc-supply = <&vcc_3v3>; + + width-mm = <210>; + height-mm = <158>; + + data-mapping = "jeida-24"; + + panel-timing { + /* 1024x768 @65Hz */ + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hsync-len = <136>; + hfront-porch = <20>; + hback-porch = <160>; + vfront-porch = <3>; + vback-porch = <29>; + vsync-len = <6>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_encoder>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa121td01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa121td01.txt new file mode 100644 index 0000000000000000000000000000000000000000..d6e1097504fe4c7fd26a3cf9f7b95d4ef142f308 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/mitsubishi,aa121td01.txt @@ -0,0 +1,47 @@ +Mitsubishi AA121TD01 LVDS Display Panel +======================================= + +The AA121TD01 is a 12.1" WXGA TFT-LCD display panel. + +These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt +with the following device-specific properties. + + +Required properties: + +- compatible: Shall contain "mitsubishi,aa121td01" and "panel-lvds", in that + order. +- vcc-supply: Reference to the regulator powering the panel VCC pins. + + +Example +------- + +panel { + compatible = "mitsubishi,aa121td01", "panel-lvds"; + vcc-supply = <&vcc_3v3>; + + width-mm = <261>; + height-mm = <163>; + + data-mapping = "jeida-24"; + + panel-timing { + /* 1280x800 @60Hz */ + clock-frequency = <71000000>; + hactive = <1280>; + vactive = <800>; + hsync-len = <70>; + hfront-porch = <20>; + hback-porch = <70>; + vsync-len = <5>; + vfront-porch = <3>; + vback-porch = <15>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_encoder>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/nec,nl12880b20-05.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/nec,nl12880b20-05.txt new file mode 100644 index 0000000000000000000000000000000000000000..71cbc49ecfab5732a126cba293691c449e2fb3af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/nec,nl12880b20-05.txt @@ -0,0 +1,8 @@ +NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel + +Required properties: +- compatible: should be "nec,nl12880bc20-05" +- power-supply: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/nec,nl4827hc19-05b.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/nec,nl4827hc19-05b.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e1914d1edb8268f0ebcf8691da5265b01f9cb1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/nec,nl4827hc19-05b.txt @@ -0,0 +1,7 @@ +NEC LCD Technologies,Ltd. WQVGA TFT LCD panel + +Required properties: +- compatible: should be "nec,nl4827hc19-05b" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/netron-dy,e231732.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/netron-dy,e231732.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6d06b5eab511f5a5af5b2e5bcbe6443a4333187 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/netron-dy,e231732.txt @@ -0,0 +1,7 @@ +Netron-DY E231732 7.0" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "netron-dy,e231732" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt new file mode 100644 index 0000000000000000000000000000000000000000..e78292b1a131e3d96aa85a7ffd77134e7a8a73ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/newhaven,nhd-4.3-480272ef-atxl.txt @@ -0,0 +1,7 @@ +Newhaven Display International 480 x 272 TFT LCD panel + +Required properties: +- compatible: should be "newhaven,nhd-4.3-480272ef-atxl" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/nlt,nl192108ac18-02d.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/nlt,nl192108ac18-02d.txt new file mode 100644 index 0000000000000000000000000000000000000000..1a639fd8778dac2ddcca3cb4ea337aa537812958 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/nlt,nl192108ac18-02d.txt @@ -0,0 +1,8 @@ +NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel + +Required properties: +- compatible: should be "nlt,nl192108ac18-02d" +- power-supply: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/nvd,9128.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/nvd,9128.txt new file mode 100644 index 0000000000000000000000000000000000000000..17bcd017c678651107c0b47bcb4b271b17f78f32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/nvd,9128.txt @@ -0,0 +1,7 @@ +New Vision Display 7.0" 800 RGB x 480 TFT LCD panel + +Required properties: +- compatible: should be "nvd,9128" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/okaya,rs800480t-7x0gp.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/okaya,rs800480t-7x0gp.txt new file mode 100644 index 0000000000000000000000000000000000000000..ddf8e211d382dc7a41a8b7fb01d1b2be86905993 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/okaya,rs800480t-7x0gp.txt @@ -0,0 +1,7 @@ +OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel + +Required properties: +- compatible: should be "okaya,rs800480t-7x0gp" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..74540a090669c4b24beac9d95bc625b43c46a022 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt @@ -0,0 +1,7 @@ +Olimex 4.3" TFT LCD panel + +Required properties: +- compatible: should be "olimex,lcd-olinuxino-43-ts" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/ontat,yx700wv03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/ontat,yx700wv03.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d8a5e029242a38d9b442559ad0edbc062fd52d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/ontat,yx700wv03.txt @@ -0,0 +1,7 @@ +On Tat Industrial Company 7" DPI TFT panel. + +Required properties: +- compatible: should be "ontat,yx700wv03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/orisetech,otm8009a.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/orisetech,otm8009a.txt new file mode 100644 index 0000000000000000000000000000000000000000..203b03eefb688aa0c1ba6e44578e98acc435a2d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/orisetech,otm8009a.txt @@ -0,0 +1,23 @@ +Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode) + +The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using +a MIPI-DSI video interface. Its backlight is managed through the DSI link. + +Required properties: + - compatible: "orisetech,otm8009a" + - reg: the virtual channel number of a DSI peripheral + +Optional properties: + - reset-gpios: a GPIO spec for the reset pin (active low). + - power-supply: phandle of the regulator that provides the supply voltage. + +Example: +&dsi { + ... + panel@0 { + compatible = "orisetech,otm8009a"; + reg = <0>; + reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; + power-supply = <&v1v8>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/ortustech,com43h4m85ulc.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/ortustech,com43h4m85ulc.txt new file mode 100644 index 0000000000000000000000000000000000000000..de19e9398618b70c5f27adf1debb54927675ffcd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/ortustech,com43h4m85ulc.txt @@ -0,0 +1,7 @@ +OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel + +Required properties: +- compatible: should be "ortustech,com43h4m85ulc" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panasonic,vvx10f004b00.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panasonic,vvx10f004b00.txt new file mode 100644 index 0000000000000000000000000000000000000000..d328b0341bf4411563b3bb57836249e32349ce3d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panasonic,vvx10f004b00.txt @@ -0,0 +1,7 @@ +Panasonic Corporation 10.1" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "panasonic,vvx10f004b00" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panasonic,vvx10f034n00.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panasonic,vvx10f034n00.txt new file mode 100644 index 0000000000000000000000000000000000000000..37dedf6a6702db3628edb5bd9755c2c1fa3b0ae5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panasonic,vvx10f034n00.txt @@ -0,0 +1,20 @@ +Panasonic 10" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "panasonic,vvx10f034n00" +- reg: DSI virtual channel of the peripheral +- power-supply: phandle of the regulator that provides the supply voltage + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Example: + + mdss_dsi@fd922800 { + panel@0 { + compatible = "panasonic,vvx10f034n00"; + reg = <0>; + power-supply = <&vreg_vsp>; + backlight = <&lp8566_wled>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-common.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-common.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d2519af4bb5ca5e33f59b3b5a42e8c9242345a2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-common.txt @@ -0,0 +1,101 @@ +Common Properties for Display Panel +=================================== + +This document defines device tree properties common to several classes of +display panels. It doesn't constitue a device tree binding specification by +itself but is meant to be referenced by device tree bindings. + +When referenced from panel device tree bindings the properties defined in this +document are defined as follows. The panel device tree bindings are +responsible for defining whether each property is required or optional. + + +Descriptive Properties +---------------------- + +- width-mm, +- height-mm: The width-mm and height-mm specify the width and height of the + physical area where images are displayed. These properties are expressed in + millimeters and rounded to the closest unit. + +- label: The label property specifies a symbolic name for the panel as a + string suitable for use by humans. It typically contains a name inscribed on + the system (e.g. as an affixed label) or specified in the system's + documentation (e.g. in the user's manual). + + If no such name exists, and unless the property is mandatory according to + device tree bindings, it shall rather be omitted than constructed of + non-descriptive information. For instance an LCD panel in a system that + contains a single panel shall not be labelled "LCD" if that name is not + inscribed on the system or used in a descriptive fashion in system + documentation. + + +Display Timings +--------------- + +- panel-timing: Most display panels are restricted to a single resolution and + require specific display timings. The panel-timing subnode expresses those + timings as specified in the timing subnode section of the display timing + bindings defined in + Documentation/devicetree/bindings/display/panel/display-timing.txt. + + +Connectivity +------------ + +- ports: Panels receive video data through one or multiple connections. While + the nature of those connections is specific to the panel type, the + connectivity is expressed in a standard fashion using ports as specified in + the device graph bindings defined in + Documentation/devicetree/bindings/graph.txt. + +- ddc-i2c-bus: Some panels expose EDID information through an I2C-compatible + bus such as DDC2 or E-DDC. For such panels the ddc-i2c-bus contains a + phandle to the system I2C controller connected to that bus. + + +Control I/Os +------------ + +Many display panels can be controlled through pins driven by GPIOs. The nature +and timing of those control signals are device-specific and left for panel +device tree bindings to specify. The following GPIO specifiers can however be +used for panels that implement compatible control signals. + +- enable-gpios: Specifier for a GPIO connected to the panel enable control + signal. The enable signal is active high and enables operation of the panel. + This property can also be used for panels implementing an active low power + down signal, which is a negated version of the enable signal. Active low + enable signals (or active high power down signals) can be supported by + inverting the GPIO specifier polarity flag. + + Note that the enable signal control panel operation only and must not be + confused with a backlight enable signal. + +- reset-gpios: Specifier for a GPIO coonnected to the panel reset control + signal. The reset signal is active low and resets the panel internal logic + while active. Active high reset signals can be supported by inverting the + GPIO specifier polarity flag. + +Power +----- + +- power-supply: display panels require power to be supplied. While several + panels need more than one power supply with panel-specific constraints + governing the order and timings of the power supplies, in many cases a single + power supply is sufficient, either because the panel has a single power rail, + or because all its power rails can be driven by the same supply. In that case + the power-supply property specifies the supply powering the panel as a phandle + to a regulator. + +Backlight +--------- + +Most display panels include a backlight. Some of them also include a backlight +controller exposed through a control bus such as I2C or DSI. Others expose +backlight control through GPIO, PWM or other signals connected to an external +backlight controller. + +- backlight: For panels whose backlight is controlled by an external backlight + controller, this property contains a phandle that references the controller. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-dpi.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-dpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b203bc4d932f19416d400bc077ecde66dcd729d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-dpi.txt @@ -0,0 +1,50 @@ +Generic MIPI DPI Panel +====================== + +Required properties: +- compatible: "panel-dpi" + +Optional properties: +- label: a symbolic name for the panel +- enable-gpios: panel enable gpio +- reset-gpios: GPIO to control the RESET pin +- vcc-supply: phandle of regulator that will be used to enable power to the display +- backlight: phandle of the backlight device + +Required nodes: +- "panel-timing" containing video timings + (Documentation/devicetree/bindings/display/panel/display-timing.txt) +- Video port for DPI input + +Example +------- + +lcd0: display@0 { + compatible = "samsung,lte430wq-f0c", "panel-dpi"; + label = "lcd"; + + backlight = <&backlight>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + panel-timing { + clock-frequency = <9200000>; + hactive = <480>; + vactive = <272>; + hfront-porch = <8>; + hback-porch = <4>; + hsync-len = <41>; + vback-porch = <2>; + vfront-porch = <4>; + vsync-len = <10>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-dsi-cm.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-dsi-cm.txt new file mode 100644 index 0000000000000000000000000000000000000000..dce48eb9db57ead8f5dfcab067e744c824690e24 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-dsi-cm.txt @@ -0,0 +1,29 @@ +Generic MIPI DSI Command Mode Panel +=================================== + +Required properties: +- compatible: "panel-dsi-cm" + +Optional properties: +- label: a symbolic name for the panel +- reset-gpios: panel reset gpio +- te-gpios: panel TE gpio + +Required nodes: +- Video port for DSI input + +Example +------- + +lcd0: display { + compatible = "tpo,taal", "panel-dsi-cm"; + label = "lcd0"; + + reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>; + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi1_out_ep>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-lvds.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-lvds.txt new file mode 100644 index 0000000000000000000000000000000000000000..250850a2150b8c9805997de6cfa153a8ea403aae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel-lvds.txt @@ -0,0 +1,121 @@ +LVDS Display Panel +================== + +LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple +incompatible data link layers have been used over time to transmit image data +to LVDS panels. This bindings supports display panels compatible with the +following specifications. + +[JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February +1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) +[LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National +Semiconductor +[VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video +Electronics Standards Association (VESA) + +Device compatible with those specifications have been marketed under the +FPD-Link and FlatLink brands. + + +Required properties: + +- compatible: Shall contain "panel-lvds" in addition to a mandatory + panel-specific compatible string defined in individual panel bindings. The + "panel-lvds" value shall never be used on its own. +- width-mm: See panel-common.txt. +- height-mm: See panel-common.txt. +- data-mapping: The color signals mapping order, "jeida-18", "jeida-24" + or "vesa-24". + +Optional properties: + +- label: See panel-common.txt. +- gpios: See panel-common.txt. +- backlight: See panel-common.txt. +- power-supply: See panel-common.txt. +- data-mirror: If set, reverse the bit order described in the data mappings + below on all data lanes, transmitting bits for slots 6 to 0 instead of + 0 to 6. + +Required nodes: + +- panel-timing: See panel-common.txt. +- ports: See panel-common.txt. These bindings require a single port subnode + corresponding to the panel LVDS input. + + +LVDS data mappings are defined as follows. + +- "jeida-18" - 18-bit data mapping compatible with the [JEIDA], [LDI] and + [VESA] specifications. Data are transferred as follows on 3 LVDS lanes. + +Slot 0 1 2 3 4 5 6 + ________________ _________________ +Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ +DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< +DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< +DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< + +- "jeida-24" - 24-bit data mapping compatible with the [DSIM] and [LDI] + specifications. Data are transferred as follows on 4 LVDS lanes. + +Slot 0 1 2 3 4 5 6 + ________________ _________________ +Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ +DATA0 ><__G2__><__R7__><__R6__><__R5__><__R4__><__R3__><__R2__>< +DATA1 ><__B3__><__B2__><__G7__><__G6__><__G5__><__G4__><__G3__>< +DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__>< +DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< + +- "vesa-24" - 24-bit data mapping compatible with the [VESA] specification. + Data are transferred as follows on 4 LVDS lanes. + +Slot 0 1 2 3 4 5 6 + ________________ _________________ +Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ +DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< +DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< +DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< +DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< + +Control signals are mapped as follows. + +CTL0: HSync +CTL1: VSync +CTL2: Data Enable +CTL3: 0 + + +Example +------- + +panel { + compatible = "mitsubishi,aa121td01", "panel-lvds"; + + width-mm = <261>; + height-mm = <163>; + + data-mapping = "jeida-24"; + + panel-timing { + /* 1280x800 @60Hz */ + clock-frequency = <71000000>; + hactive = <1280>; + vactive = <800>; + hsync-len = <70>; + hfront-porch = <20>; + hback-porch = <70>; + vsync-len = <5>; + vfront-porch = <3>; + vback-porch = <15>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_encoder>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/panel.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..e2e6867852b899b4a3a3793d7bdb47b7faee3338 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/panel.txt @@ -0,0 +1,4 @@ +Common display properties +------------------------- + +- rotation: Display rotation in degrees counter clockwise (0,90,180,270) diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/qiaodian,qd43003c0-40.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/qiaodian,qd43003c0-40.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fbdab89ac3d43153391f9292da1c79aca86216f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/qiaodian,qd43003c0-40.txt @@ -0,0 +1,7 @@ +QiaoDian XianShi Corporation 4"3 TFT LCD panel + +Required properties: +- compatible: should be "qiaodian,qd43003c0-40" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/raspberrypi,7inch-touchscreen.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/raspberrypi,7inch-touchscreen.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9e19c059260d6d8f33acf4113197eab209011ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/raspberrypi,7inch-touchscreen.txt @@ -0,0 +1,49 @@ +This binding covers the official 7" (800x480) Raspberry Pi touchscreen +panel. + +This DSI panel contains: + +- TC358762 DSI->DPI bridge +- Atmel microcontroller on I2C for power sequencing the DSI bridge and + controlling backlight +- Touchscreen controller on I2C for touch input + +and this binding covers the DSI display parts but not its touch input. + +Required properties: +- compatible: Must be "raspberrypi,7inch-touchscreen-panel" +- reg: Must be "45" +- port: See panel-common.txt + +Example: + +dsi1: dsi@7e700000 { + #address-cells = <1>; + #size-cells = <0>; + <...> + + port { + dsi_out_port: endpoint { + remote-endpoint = <&panel_dsi_port>; + }; + }; +}; + +i2c_dsi: i2c { + compatible = "i2c-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&gpio 28 0 + &gpio 29 0>; + + lcd@45 { + compatible = "raspberrypi,7inch-touchscreen-panel"; + reg = <0x45>; + + port { + panel_dsi_port: endpoint { + remote-endpoint = <&dsi_out_port>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/raydium,rm68200.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/raydium,rm68200.txt new file mode 100644 index 0000000000000000000000000000000000000000..cbb79ef3bfc9862fff863fe1d8cc5a76d839d2b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/raydium,rm68200.txt @@ -0,0 +1,25 @@ +Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel + +The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD +panel connected using a MIPI-DSI video interface. + +Required properties: + - compatible: "raydium,rm68200" + - reg: the virtual channel number of a DSI peripheral + +Optional properties: + - reset-gpios: a GPIO spec for the reset pin (active low). + - power-supply: phandle of the regulator that provides the supply voltage. + - backlight: phandle of the backlight device attached to the panel. + +Example: +&dsi { + ... + panel@0 { + compatible = "raydium,rm68200"; + reg = <0>; + reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; + power-supply = <&v1v8>; + backlight = <&pwm_backlight>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/rocktech,rk070er9427.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/rocktech,rk070er9427.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb1fb9f8d1f4687d5477c594313ae442606fb65d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/rocktech,rk070er9427.txt @@ -0,0 +1,25 @@ +Rocktech Display Ltd. RK070ER9427 800(RGB)x480 TFT LCD panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Required properties: +- compatible: should be "rocktech,rk070er9427" + +Optional properties: +- backlight: phandle of the backlight device attached to the panel + +Optional nodes: +- Video port for LCD panel input. + +Example: + panel { + compatible = "rocktech,rk070er9427"; + backlight = <&backlight_lcd>; + + port { + lcd_panel_in: endpoint { + remote-endpoint = <&lcd_display_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ld9040.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ld9040.txt new file mode 100644 index 0000000000000000000000000000000000000000..354d4d1df4ff40449436238189fab54717f0dfe6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ld9040.txt @@ -0,0 +1,66 @@ +Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus + +Required properties: + - compatible: "samsung,ld9040" + - reg: address of the panel on SPI bus + - vdd3-supply: core voltage supply + - vci-supply: voltage supply for analog circuits + - reset-gpios: a GPIO spec for the reset pin + - display-timings: timings for the connected panel according to [1] + +The panel must obey rules for SPI slave device specified in document [2]. + +Optional properties: + - power-on-delay: delay after turning regulators on [ms] + - reset-delay: delay after reset sequence [ms] + - panel-width-mm: physical panel width [mm] + - panel-height-mm: physical panel height [mm] + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [3]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt +[2]: Documentation/devicetree/bindings/spi/spi-bus.txt +[3]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + lcd@0 { + compatible = "samsung,ld9040"; + reg = <0>; + vdd3-supply = <&ldo7_reg>; + vci-supply = <&ldo17_reg>; + reset-gpios = <&gpy4 5 0>; + spi-max-frequency = <1200000>; + spi-cpol; + spi-cpha; + power-on-delay = <10>; + reset-delay = <10>; + panel-width-mm = <90>; + panel-height-mm = <154>; + + display-timings { + timing { + clock-frequency = <23492370>; + hactive = <480>; + vactive = <800>; + hback-porch = <16>; + hfront-porch = <16>; + vback-porch = <2>; + vfront-porch = <28>; + hsync-len = <2>; + vsync-len = <1>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + port { + lcd_ep: endpoint { + remote-endpoint = <&fimd_dpi_ep>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,lsn122dl01-c01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,lsn122dl01-c01.txt new file mode 100644 index 0000000000000000000000000000000000000000..dba298b43b2498fa45e7a21787ed13c0f80137cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,lsn122dl01-c01.txt @@ -0,0 +1,7 @@ +Samsung 12.2" (2560x1600 pixels) TFT LCD panel + +Required properties: +- compatible: should be "samsung,lsn122dl01-c01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ltn101nt05.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ltn101nt05.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef522c6bb85f8b58ee56ec1f74ae102139d58cf1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ltn101nt05.txt @@ -0,0 +1,7 @@ +Samsung Electronics 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "samsung,ltn101nt05" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ltn140at29-301.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ltn140at29-301.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7f969d891cc7c85e97bbe0d5a4b2b4a65687857 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,ltn140at29-301.txt @@ -0,0 +1,7 @@ +Samsung Electronics 14" WXGA (1366x768) TFT LCD panel + +Required properties: +- compatible: should be "samsung,ltn140at29-301" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e3ha2.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e3ha2.txt new file mode 100644 index 0000000000000000000000000000000000000000..4acea25c244bc7fd60d840370d4e5f7b95f683c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e3ha2.txt @@ -0,0 +1,31 @@ +Samsung S6E3HA2 5.7" 1440x2560 AMOLED panel +Samsung S6E3HF2 5.65" 1600x2560 AMOLED panel + +Required properties: + - compatible: should be one of: + "samsung,s6e3ha2", + "samsung,s6e3hf2". + - reg: the virtual channel number of a DSI peripheral + - vdd3-supply: I/O voltage supply + - vci-supply: voltage supply for analog circuits + - reset-gpios: a GPIO spec for the reset pin (active low) + - enable-gpios: a GPIO spec for the panel enable pin (active high) + +Optional properties: + - te-gpios: a GPIO spec for the tearing effect synchronization signal + gpio pin (active high) + +Example: +&dsi { + ... + + panel@0 { + compatible = "samsung,s6e3ha2"; + reg = <0>; + vdd3-supply = <&ldo27_reg>; + vci-supply = <&ldo28_reg>; + reset-gpios = <&gpg0 0 GPIO_ACTIVE_LOW>; + enable-gpios = <&gpf1 5 GPIO_ACTIVE_HIGH>; + te-gpios = <&gpf1 3 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e63j0x03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e63j0x03.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f1a8392af7ff1797fff844233ab363233fc3a06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e63j0x03.txt @@ -0,0 +1,24 @@ +Samsung S6E63J0X03 1.63" 320x320 AMOLED panel (interface: MIPI-DSI command mode) + +Required properties: + - compatible: "samsung,s6e63j0x03" + - reg: the virtual channel number of a DSI peripheral + - vdd3-supply: I/O voltage supply + - vci-supply: voltage supply for analog circuits + - reset-gpios: a GPIO spec for the reset pin (active low) + - te-gpios: a GPIO spec for the tearing effect synchronization signal + gpio pin (active high) + +Example: +&dsi { + ... + + panel@0 { + compatible = "samsung,s6e63j0x03"; + reg = <0>; + vdd3-supply = <&ldo16_reg>; + vci-supply = <&ldo20_reg>; + reset-gpios = <&gpe0 1 GPIO_ACTIVE_LOW>; + te-gpios = <&gpx0 6 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e8aa0.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e8aa0.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e766c5f86daf970cf7715a2d655b9fcebb1d35d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/samsung,s6e8aa0.txt @@ -0,0 +1,56 @@ +Samsung S6E8AA0 AMOLED LCD 5.3 inch panel + +Required properties: + - compatible: "samsung,s6e8aa0" + - reg: the virtual channel number of a DSI peripheral + - vdd3-supply: core voltage supply + - vci-supply: voltage supply for analog circuits + - reset-gpios: a GPIO spec for the reset pin + - display-timings: timings for the connected panel as described by [1] + +Optional properties: + - power-on-delay: delay after turning regulators on [ms] + - reset-delay: delay after reset sequence [ms] + - init-delay: delay after initialization sequence [ms] + - panel-width-mm: physical panel width [mm] + - panel-height-mm: physical panel height [mm] + - flip-horizontal: boolean to flip image horizontally + - flip-vertical: boolean to flip image vertically + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [2]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/display/panel/display-timing.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + panel { + compatible = "samsung,s6e8aa0"; + reg = <0>; + vdd3-supply = <&vcclcd_reg>; + vci-supply = <&vlcd_reg>; + reset-gpios = <&gpy4 5 0>; + power-on-delay= <50>; + reset-delay = <100>; + init-delay = <100>; + panel-width-mm = <58>; + panel-height-mm = <103>; + flip-horizontal; + flip-vertical; + + display-timings { + timing0: timing-0 { + clock-frequency = <57153600>; + hactive = <720>; + vactive = <1280>; + hfront-porch = <5>; + hback-porch = <5>; + hsync-len = <5>; + vfront-porch = <13>; + vback-porch = <1>; + vsync-len = <2>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/seiko,43wvf1g.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/seiko,43wvf1g.txt new file mode 100644 index 0000000000000000000000000000000000000000..aae57ef36cdd237a4463a9c0877ffe04ba062445 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/seiko,43wvf1g.txt @@ -0,0 +1,23 @@ +Seiko Instruments Inc. 4.3" WVGA (800 x RGB x 480) TFT with Touch-Panel + +Required properties: +- compatible: should be "sii,43wvf1g". +- "dvdd-supply": 3v3 digital regulator. +- "avdd-supply": 5v analog regulator. + +Optional properties: +- backlight: phandle for the backlight control. + +Example: + + panel { + compatible = "sii,43wvf1g"; + backlight = <&backlight_display>; + dvdd-supply = <®_lcd_3v3>; + avdd-supply = <®_lcd_5v>; + port { + panel_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sgd,gktw70sdae4se.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sgd,gktw70sdae4se.txt new file mode 100644 index 0000000000000000000000000000000000000000..d06644b555bd883a5d881078a382c77582fc9a66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sgd,gktw70sdae4se.txt @@ -0,0 +1,41 @@ +Solomon Goldentek Display GKTW70SDAE4SE LVDS Display Panel +========================================================== + +The GKTW70SDAE4SE is a 7" WVGA TFT-LCD display panel. + +These DT bindings follow the LVDS panel bindings defined in panel-lvds.txt +with the following device-specific properties. + +Required properties: + +- compatible: Shall contain "sgd,gktw70sdae4se" and "panel-lvds", in that order. + +Example +------- + +panel { + compatible = "sgd,gktw70sdae4se", "panel-lvds"; + + width-mm = <153>; + height-mm = <86>; + + data-mapping = "jeida-18"; + + panel-timing { + clock-frequency = <32000000>; + hactive = <800>; + vactive = <480>; + hback-porch = <39>; + hfront-porch = <39>; + vback-porch = <29>; + vfront-porch = <13>; + hsync-len = <47>; + vsync-len = <2>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_encoder>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq035q7db03.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq035q7db03.txt new file mode 100644 index 0000000000000000000000000000000000000000..0753f6967279b7da2a9a6145028b0101a0e7046b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq035q7db03.txt @@ -0,0 +1,12 @@ +Sharp LQ035Q7DB03 3.5" QVGA TFT LCD panel + +Required properties: +- compatible: should be "sharp,lq035q7db03" +- power-supply: phandle of the regulator that provides the supply voltage + +Optional properties: +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq101k1ly04.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq101k1ly04.txt new file mode 100644 index 0000000000000000000000000000000000000000..4aff25b8dfe68c2f697207c56ff98aee7a7d8d2f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq101k1ly04.txt @@ -0,0 +1,7 @@ +Sharp Display Corp. LQ101K1LY04 10.07" WXGA TFT LCD panel + +Required properties: +- compatible: should be "sharp,lq101k1ly04" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq101r1sx01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq101r1sx01.txt new file mode 100644 index 0000000000000000000000000000000000000000..f522bb8e47e1c7dc39dd7e8e21d6387bbc492df2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq101r1sx01.txt @@ -0,0 +1,49 @@ +Sharp Microelectronics 10.1" WQXGA TFT LCD panel + +This panel requires a dual-channel DSI host to operate. It supports two modes: +- left-right: each channel drives the left or right half of the screen +- even-odd: each channel drives the even or odd lines of the screen + +Each of the DSI channels controls a separate DSI peripheral. The peripheral +driven by the first link (DSI-LINK1), left or even, is considered the primary +peripheral and controls the device. The 'link2' property contains a phandle +to the peripheral driven by the second link (DSI-LINK2, right or odd). + +Note that in video mode the DSI-LINK1 interface always provides the left/even +pixels and DSI-LINK2 always provides the right/odd pixels. In command mode it +is possible to program either link to drive the left/even or right/odd pixels +but for the sake of consistency this binding assumes that the same assignment +is chosen as for video mode. + +Required properties: +- compatible: should be "sharp,lq101r1sx01" +- reg: DSI virtual channel of the peripheral + +Required properties (for DSI-LINK1 only): +- link2: phandle to the DSI peripheral on the secondary link. Note that the + presence of this property marks the containing node as DSI-LINK1. +- power-supply: phandle of the regulator that provides the supply voltage + +Optional properties (for DSI-LINK1 only): +- backlight: phandle of the backlight device attached to the panel + +Example: + + dsi@54300000 { + panel: panel@0 { + compatible = "sharp,lq101r1sx01"; + reg = <0>; + + link2 = <&secondary>; + + power-supply = <...>; + backlight = <...>; + }; + }; + + dsi@54400000 { + secondary: panel@0 { + compatible = "sharp,lq101r1sx01"; + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq123p1jx31.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq123p1jx31.txt new file mode 100644 index 0000000000000000000000000000000000000000..bcb0e8a29f713fcbc63af17310944ff757fc9b87 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq123p1jx31.txt @@ -0,0 +1,7 @@ +Sharp 12.3" (2400x1600 pixels) TFT LCD panel + +Required properties: +- compatible: should be "sharp,lq123p1jx31" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq150x1lg11.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq150x1lg11.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f57c3143506b195aed1eae42b1e4ccd5cfb44f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,lq150x1lg11.txt @@ -0,0 +1,36 @@ +Sharp 15" LQ150X1LG11 XGA TFT LCD panel + +Required properties: +- compatible: should be "sharp,lq150x1lg11" +- power-supply: regulator to provide the VCC supply voltage (3.3 volts) + +Optional properties: +- backlight: phandle of the backlight device +- rlud-gpios: a single GPIO for the RL/UD (rotate 180 degrees) pin. +- sellvds-gpios: a single GPIO for the SELLVDS pin. + +If rlud-gpios and/or sellvds-gpios are not specified, the RL/UD and/or SELLVDS +pins are assumed to be handled appropriately by the hardware. + +Example: + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 100000>; /* VBR */ + + brightness-levels = <0 20 40 60 80 100>; + default-brightness-level = <2>; + + power-supply = <&vdd_12v_reg>; /* VDD */ + enable-gpios = <&gpio 42 GPIO_ACTIVE_HIGH>; /* XSTABY */ + }; + + panel { + compatible = "sharp,lq150x1lg11"; + + power-supply = <&vcc_3v3_reg>; /* VCC */ + + backlight = <&backlight>; + rlud-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; /* RL/UD */ + sellvds-gpios = <&gpio 18 GPIO_ACTIVE_HIGH>; /* SELLVDS */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,ls037v7dw01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,ls037v7dw01.txt new file mode 100644 index 0000000000000000000000000000000000000000..0cc8981e9d497908b9368b6fd5e84e7a816576a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,ls037v7dw01.txt @@ -0,0 +1,43 @@ +SHARP LS037V7DW01 TFT-LCD panel +=================================== + +Required properties: +- compatible: "sharp,ls037v7dw01" + +Optional properties: +- label: a symbolic name for the panel +- enable-gpios: a GPIO spec for the optional enable pin. + This pin is the INI pin as specified in the LS037V7DW01.pdf file. +- reset-gpios: a GPIO spec for the optional reset pin. + This pin is the RESB pin as specified in the LS037V7DW01.pdf file. +- mode-gpios: a GPIO + ordered MO, LR, and UD as specified in the LS037V7DW01.pdf file. + +Required nodes: +- Video port for DPI input + +This panel can have zero to five GPIOs to configure to change configuration +between QVGA and VGA mode and the scan direction. As these pins can be also +configured with external pulls, all the GPIOs are considered optional with holes +in the array. + +Example +------- + +Example when connected to a omap2+ based device: + +lcd0: display { + compatible = "sharp,ls037v7dw01"; + power-supply = <&lcd_3v3>; + enable-gpios = <&gpio5 24 GPIO_ACTIVE_HIGH>; /* gpio152, lcd INI */ + reset-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; /* gpio155, lcd RESB */ + mode-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH /* gpio154, lcd MO */ + &gpio1 2 GPIO_ACTIVE_HIGH /* gpio2, lcd LR */ + &gpio1 3 GPIO_ACTIVE_HIGH>; /* gpio3, lcd UD */ + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,ls043t1le01.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,ls043t1le01.txt new file mode 100644 index 0000000000000000000000000000000000000000..3770a111968b613e648e51c4f7403f4973fc979b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sharp,ls043t1le01.txt @@ -0,0 +1,22 @@ +Sharp Microelectronics 4.3" qHD TFT LCD panel + +Required properties: +- compatible: should be "sharp,ls043t1le01-qhd" +- reg: DSI virtual channel of the peripheral +- power-supply: phandle of the regulator that provides the supply voltage + +Optional properties: +- backlight: phandle of the backlight device attached to the panel +- reset-gpios: a GPIO spec for the reset pin + +Example: + + mdss_dsi@fd922800 { + panel@0 { + compatible = "sharp,ls043t1le01-qhd"; + reg = <0>; + avdd-supply = <&pm8941_l22>; + backlight = <&pm8941_wled>; + reset-gpios = <&pm8941_gpios 19 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/shelly,sca07010-bfn-lnn.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/shelly,sca07010-bfn-lnn.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc1ea9e26c940a82e4139ad137e2d6729f546b33 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/shelly,sca07010-bfn-lnn.txt @@ -0,0 +1,7 @@ +Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel + +Required properties: +- compatible: should be "shelly,sca07010-bfn-lnn" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/simple-panel.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/simple-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..45a457ad38f0f078eed709424e1e237ebcfe420f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/simple-panel.txt @@ -0,0 +1,25 @@ +Simple display panel +==================== + +panel node +---------- + +Required properties: +- power-supply: See panel-common.txt + +Optional properties: +- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + + panel: panel { + compatible = "cptt,claa101wb01"; + ddc-i2c-bus = <&panelddc>; + + power-supply = <&vdd_pnl_reg>; + enable-gpios = <&gpio 90 0>; + + backlight = <&backlight>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sitronix,st7789v.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sitronix,st7789v.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6995dde641b46156629a82e0e99da598a0d0830 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sitronix,st7789v.txt @@ -0,0 +1,37 @@ +Sitronix ST7789V RGB panel with SPI control bus + +Required properties: + - compatible: "sitronix,st7789v" + - reg: Chip select of the panel on the SPI bus + - reset-gpios: a GPIO phandle for the reset pin + - power-supply: phandle of the regulator that provides the supply voltage + +Optional properties: + - backlight: phandle to the backlight used + +The generic bindings for the SPI slaves documented in [1] also applies + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [2]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/spi/spi-bus.txt +[2]: Documentation/devicetree/bindings/graph.txt + +Example: + +panel@0 { + compatible = "sitronix,st7789v"; + reg = <0>; + reset-gpios = <&pio 6 11 GPIO_ACTIVE_LOW>; + backlight = <&pwm_bl>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + port { + panel_input: endpoint { + remote-endpoint = <&tcon0_out_panel>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/sony,acx565akm.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/sony,acx565akm.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1233328074965e8ff5a3da5c233cab02e50c42a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/sony,acx565akm.txt @@ -0,0 +1,30 @@ +Sony ACX565AKM SDI Panel +======================== + +Required properties: +- compatible: "sony,acx565akm" + +Optional properties: +- label: a symbolic name for the panel +- reset-gpios: panel reset gpio + +Required nodes: +- Video port for SDI input + +Example +------- + +acx565akm@2 { + compatible = "sony,acx565akm"; + spi-max-frequency = <6000000>; + reg = <2>; + + label = "lcd"; + reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */ + + port { + lcd_in: endpoint { + remote-endpoint = <&sdi_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/starry,kr122ea0sra.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/starry,kr122ea0sra.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e87fe6078af32e6160c6d944431949fc15aa9b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/starry,kr122ea0sra.txt @@ -0,0 +1,7 @@ +Starry 12.2" (1920x1200 pixels) TFT LCD panel + +Required properties: +- compatible: should be "starry,kr122ea0sra" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/startek,startek-kd050c.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/startek,startek-kd050c.txt new file mode 100644 index 0000000000000000000000000000000000000000..70cd8d18d8414fc596bad39f3b86d0cc9c0cbe8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/startek,startek-kd050c.txt @@ -0,0 +1,4 @@ +Startek Electronic Technology Co. KD050C 5.0" WVGA TFT LCD panel + +Required properties: +- compatible: should be "startek,startek-kd050c" diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tianma,tm070jdhg30.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tianma,tm070jdhg30.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb9501a82e259f8c5b26d5b5dffac7270e4fa878 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tianma,tm070jdhg30.txt @@ -0,0 +1,7 @@ +Tianma Micro-electronics TM070JDHG30 7.0" WXGA TFT LCD panel + +Required properties: +- compatible: should be "tianma,tm070jdhg30" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tianma,tm070rvhg71.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tianma,tm070rvhg71.txt new file mode 100644 index 0000000000000000000000000000000000000000..b25261e63a6d1aebc50a1089145a5b0cafa90a5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tianma,tm070rvhg71.txt @@ -0,0 +1,29 @@ +Tianma Micro-electronics TM070RVHG71 7.0" WXGA TFT LCD panel + +Required properties: +- compatible: should be "tianma,tm070rvhg71" +- power-supply: single regulator to provide the supply voltage +- backlight: phandle of the backlight device attached to the panel + +Required nodes: +- port: LVDS port mapping to connect this display + +This panel needs single power supply voltage. Its backlight is conntrolled +via PWM signal. + +Example: +-------- + +Example device-tree definition when connected to iMX6Q based board + + panel: panel-lvds0 { + compatible = "tianma,tm070rvhg71"; + backlight = <&backlight_lvds>; + power-supply = <®_lvds>; + + port { + panel_in_lvds0: endpoint { + remote-endpoint = <&lvds0_out>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/toshiba,lt089ac29000.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/toshiba,lt089ac29000.txt new file mode 100644 index 0000000000000000000000000000000000000000..89826116628c729044c90e8183881727e5f5785b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/toshiba,lt089ac29000.txt @@ -0,0 +1,8 @@ +Toshiba 8.9" WXGA (1280x768) TFT LCD panel + +Required properties: +- compatible: should be "toshiba,lt089ac29000" +- power-supply: as specified in the base binding + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tpk,f07a-0102.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpk,f07a-0102.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2613b9675df71f94fad9b84b3d4221b1edac5af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpk,f07a-0102.txt @@ -0,0 +1,8 @@ +TPK U.S.A. LLC Fusion 7" integrated projected capacitive touch display with, +800 x 480 (WVGA) LCD panel. + +Required properties: +- compatible: should be "tpk,f07a-0102" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tpk,f10a-0102.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpk,f10a-0102.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9d051196ba9b4d8f68983e6e7c14165b3a454ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpk,f10a-0102.txt @@ -0,0 +1,8 @@ +TPK U.S.A. LLC Fusion 10.1" integrated projected capacitive touch display with, +1024 x 600 (WSVGA) LCD panel. + +Required properties: +- compatible: should be "tpk,f10a-0102" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,td028ttec1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,td028ttec1.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed34253d9fb129916f25db38440faf13645721c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,td028ttec1.txt @@ -0,0 +1,30 @@ +Toppoly TD028TTEC1 Panel +======================== + +Required properties: +- compatible: "tpo,td028ttec1" + +Optional properties: +- label: a symbolic name for the panel + +Required nodes: +- Video port for DPI input + +Example +------- + +lcd-panel: td028ttec1@0 { + compatible = "tpo,td028ttec1"; + reg = <0>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + label = "lcd"; + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,td043mtea1.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,td043mtea1.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec6d62975162315931b075d6d7950b9690a46a37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,td043mtea1.txt @@ -0,0 +1,33 @@ +TPO TD043MTEA1 Panel +==================== + +Required properties: +- compatible: "tpo,td043mtea1" +- reset-gpios: panel reset gpio + +Optional properties: +- label: a symbolic name for the panel + +Required nodes: +- Video port for DPI input + +Example +------- + +lcd-panel: panel@0 { + compatible = "tpo,td043mtea1"; + reg = <0>; + spi-max-frequency = <100000>; + spi-cpol; + spi-cpha; + + label = "lcd"; + + reset-gpios = <&gpio7 7 0>; + + port { + lcd_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,tpg110.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,tpg110.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5e3c6f2095a502d420fec40af372c009e80e418 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/tpo,tpg110.txt @@ -0,0 +1,47 @@ +TPO TPG110 Panel +================ + +This binding builds on the DPI bindings, adding a few properties +as a superset of a DPI. See panel-dpi.txt for the required DPI +bindings. + +Required properties: +- compatible : "tpo,tpg110" +- grestb-gpios : panel reset GPIO +- scen-gpios : serial control enable GPIO +- scl-gpios : serial control clock line GPIO +- sda-gpios : serial control data line GPIO + +Required nodes: +- Video port for DPI input, see panel-dpi.txt +- Panel timing for DPI setup, see panel-dpi.txt + +Example +------- + +panel { + compatible = "tpo,tpg110", "panel-dpi"; + grestb-gpios = <&stmpe_gpio44 5 GPIO_ACTIVE_LOW>; + scen-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + scl-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + backlight = <&bl>; + + port { + nomadik_clcd_panel: endpoint { + remote-endpoint = <&nomadik_clcd_pads>; + }; + }; + + panel-timing { + clock-frequency = <33200000>; + hactive = <800>; + hback-porch = <216>; + hfront-porch = <40>; + hsync-len = <1>; + vactive = <480>; + vback-porch = <35>; + vfront-porch = <10>; + vsync-len = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/urt,umsh-8596md.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/urt,umsh-8596md.txt new file mode 100644 index 0000000000000000000000000000000000000000..088a6cea5015fa5590c5b3c31d0d90b549f0ca0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/urt,umsh-8596md.txt @@ -0,0 +1,16 @@ +United Radiant Technology UMSH-8596MD-xT 7.0" WVGA TFT LCD panel + +Supported are LVDS versions (-11T, -19T) and parallel ones +(-T, -1T, -7T, -20T). + +Required properties: +- compatible: should be one of: + "urt,umsh-8596md-t", + "urt,umsh-8596md-1t", + "urt,umsh-8596md-7t", + "urt,umsh-8596md-11t", + "urt,umsh-8596md-19t", + "urt,umsh-8596md-20t". + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/panel/winstar,wf35ltiacd.txt b/arch/arm64/boot/dts/vendor/bindings/display/panel/winstar,wf35ltiacd.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a7e6e3ba64c3e68db0201bd2968f7fae94246ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/panel/winstar,wf35ltiacd.txt @@ -0,0 +1,48 @@ +Winstar Display Corporation 3.5" QVGA (320x240) TFT LCD panel + +Required properties: +- compatible: should be "winstar,wf35ltiacd" +- power-supply: regulator to provide the VCC supply voltage (3.3 volts) + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. + +Example: + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 PWM_POLARITY_INVERTED>; + brightness-levels = <0 31 63 95 127 159 191 223 255>; + default-brightness-level = <191>; + power-supply = <&bl_reg>; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + panel: panel { + compatible = "winstar,wf35ltiacd", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint { + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/dpu.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/dpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad2e8830324e28cc7038446388a9c41762b2ae3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/dpu.txt @@ -0,0 +1,131 @@ +Qualcomm Technologies, Inc. DPU KMS + +Description: + +Device tree bindings for MSM Mobile Display Subsytem(MDSS) that encapsulates +sub-blocks like DPU display controller, DSI and DP interfaces etc. +The DPU display controller is found in SDM845 SoC. + +MDSS: +Required properties: +- compatible: "qcom,sdm845-mdss" +- reg: physical base address and length of contoller's registers. +- reg-names: register region names. The following region is required: + * "mdss" +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt +- clocks: list of clock specifiers for clocks needed by the device. +- clock-names: device clock names, must be in same order as clocks property. + The following clocks are required: + * "iface" + * "bus" + * "core" +- interrupts: interrupt signal from MDSS. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- iommus: phandle of iommu device node. +- #address-cells: number of address cells for the MDSS children. Should be 1. +- #size-cells: Should be 1. +- ranges: parent bus address space is the same as the child bus address space. + +Optional properties: +- assigned-clocks: list of clock specifiers for clocks needing rate assignment +- assigned-clock-rates: list of clock frequencies sorted in the same order as + the assigned-clocks property. + +MDP: +Required properties: +- compatible: "qcom,sdm845-dpu" +- reg: physical base address and length of controller's registers. +- reg-names : register region names. The following region is required: + * "mdp" + * "vbif" +- clocks: list of clock specifiers for clocks needed by the device. +- clock-names: device clock names, must be in same order as clocks property. + The following clocks are required. + * "bus" + * "iface" + * "core" + * "vsync" +- interrupts: interrupt line from DPU to MDSS. +- ports: contains the list of output ports from DPU device. These ports connect + to interfaces that are external to the DPU hardware, such as DSI, DP etc. + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + Port 0 -> DPU_INTF1 (DSI1) + Port 1 -> DPU_INTF2 (DSI2) + +Optional properties: +- assigned-clocks: list of clock specifiers for clocks needing rate assignment +- assigned-clock-rates: list of clock frequencies sorted in the same order as + the assigned-clocks property. + +Example: + + mdss: mdss@ae00000 { + compatible = "qcom,sdm845-mdss"; + reg = <0xae00000 0x1000>; + reg-names = "mdss"; + + power-domains = <&clock_dispcc 0>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, <&gcc GCC_DISP_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "bus", "core"; + + assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>; + assigned-clock-rates = <300000000>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_iommu 0>; + + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0xae00000 0xb2008>; + + mdss_mdp: mdp@ae01000 { + compatible = "qcom,sdm845-dpu"; + reg = <0 0x1000 0x8f000>, <0 0xb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "iface", "bus", "core", "vsync"; + + assigned-clocks = <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <0 0 300000000 19200000>; + + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..577b3cede370e0332489111741eb0ec6cc1654e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/dsi.txt @@ -0,0 +1,247 @@ +Qualcomm Technologies Inc. adreno/snapdragon DSI output + +DSI Controller: +Required properties: +- compatible: + * "qcom,mdss-dsi-ctrl" +- reg: Physical base address and length of the registers of controller +- reg-names: The names of register regions. The following regions are required: + * "dsi_ctrl" +- interrupts: The interrupt signal from the DSI block. +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: Phandles to device clocks. +- clock-names: the following clocks are required: + * "mdp_core" + * "iface" + * "bus" + * "core_mmss" + * "byte" + * "pixel" + * "core" + For DSIv2, we need an additional clock: + * "src" + For DSI6G v2.0 onwards, we need also need the clock: + * "byte_intf" +- assigned-clocks: Parents of "byte" and "pixel" for the given platform. +- assigned-clock-parents: The Byte clock and Pixel clock PLL outputs provided + by a DSI PHY block. See [1] for details on clock bindings. +- vdd-supply: phandle to vdd regulator device node +- vddio-supply: phandle to vdd-io regulator device node +- vdda-supply: phandle to vdda regulator device node +- phys: phandle to DSI PHY device node +- phy-names: the name of the corresponding PHY device +- syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2) +- ports: Contains 2 DSI controller ports as child nodes. Each port contains + an endpoint subnode as defined in [2] and [3]. + +Optional properties: +- panel@0: Node of panel connected to this DSI controller. + See files in [4] for each supported panel. +- qcom,dual-dsi-mode: Boolean value indicating if the DSI controller is + driving a panel which needs 2 DSI links. +- qcom,master-dsi: Boolean value indicating if the DSI controller is driving + the master link of the 2-DSI panel. +- qcom,sync-dual-dsi: Boolean value indicating if the DSI controller is + driving a 2-DSI panel whose 2 links need receive command simultaneously. +- pinctrl-names: the pin control state names; should contain "default" +- pinctrl-0: the default pinctrl state (active) +- pinctrl-n: the "sleep" pinctrl state +- ports: contains DSI controller input and output ports as children, each + containing one endpoint subnode. + + DSI Endpoint properties: + - remote-endpoint: For port@0, set to phandle of the connected panel/bridge's + input endpoint. For port@1, set to the MDP interface output. See [2] for + device graph info. + + - data-lanes: this describes how the physical DSI data lanes are mapped + to the logical lanes on the given platform. The value contained in + index n describes what physical lane is mapped to the logical lane n + (DATAn, where n lies between 0 and 3). The clock lane position is fixed + and can't be changed. Hence, they aren't a part of the DT bindings. See + [3] for more info on the data-lanes property. + + For example: + + data-lanes = <3 0 1 2>; + + The above mapping describes that the logical data lane DATA0 is mapped to + the physical data lane DATA3, logical DATA1 to physical DATA0, logic DATA2 + to phys DATA1 and logic DATA3 to phys DATA2. + + There are only a limited number of physical to logical mappings possible: + <0 1 2 3> + <1 2 3 0> + <2 3 0 1> + <3 0 1 2> + <0 3 2 1> + <1 0 3 2> + <2 1 0 3> + <3 2 1 0> + +DSI PHY: +Required properties: +- compatible: Could be the following + * "qcom,dsi-phy-28nm-hpm" + * "qcom,dsi-phy-28nm-lp" + * "qcom,dsi-phy-20nm" + * "qcom,dsi-phy-28nm-8960" + * "qcom,dsi-phy-14nm" + * "qcom,dsi-phy-10nm" +- reg: Physical base address and length of the registers of PLL, PHY. Some + revisions require the PHY regulator base address, whereas others require the + PHY lane base address. See below for each PHY revision. +- reg-names: The names of register regions. The following regions are required: + For DSI 28nm HPM/LP/8960 PHYs and 20nm PHY: + * "dsi_pll" + * "dsi_phy" + * "dsi_phy_regulator" + For DSI 14nm and 10nm PHYs: + * "dsi_pll" + * "dsi_phy" + * "dsi_phy_lane" +- clock-cells: Must be 1. The DSI PHY block acts as a clock provider, creating + 2 clocks: A byte clock (index 0), and a pixel clock (index 1). +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: Phandles to device clocks. See [1] for details on clock bindings. +- clock-names: the following clocks are required: + * "iface" + For 28nm HPM/LP, 28nm 8960 PHYs: +- vddio-supply: phandle to vdd-io regulator device node + For 20nm PHY: +- vddio-supply: phandle to vdd-io regulator device node +- vcca-supply: phandle to vcca regulator device node + For 14nm PHY: +- vcca-supply: phandle to vcca regulator device node + For 10nm PHY: +- vdds-supply: phandle to vdds regulator device node + +Optional properties: +- qcom,dsi-phy-regulator-ldo-mode: Boolean value indicating if the LDO mode PHY + regulator is wanted. +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split is enabled, this time should not be higher + than two times the dsi link rate time. + If the property is not specified, then the default value is 14000 us. + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/graph.txt +[3] Documentation/devicetree/bindings/media/video-interfaces.txt +[4] Documentation/devicetree/bindings/display/panel/ + +Example: + dsi0: dsi@fd922800 { + compatible = "qcom,mdss-dsi-ctrl"; + qcom,dsi-host-index = <0>; + interrupt-parent = <&mdp>; + interrupts = <4 0>; + reg-names = "dsi_ctrl"; + reg = <0xfd922800 0x200>; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = + "bus", + "byte", + "core", + "core_mmss", + "iface", + "mdp_core", + "pixel"; + clocks = + <&mmcc MDSS_AXI_CLK>, + <&mmcc MDSS_BYTE0_CLK>, + <&mmcc MDSS_ESC0_CLK>, + <&mmcc MMSS_MISC_AHB_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_PCLK0_CLK>; + + assigned-clocks = + <&mmcc BYTE0_CLK_SRC>, + <&mmcc PCLK0_CLK_SRC>; + assigned-clock-parents = + <&dsi_phy0 0>, + <&dsi_phy0 1>; + + vdda-supply = <&pma8084_l2>; + vdd-supply = <&pma8084_l22>; + vddio-supply = <&pma8084_l12>; + + phys = <&dsi_phy0>; + phy-names ="dsi-phy"; + + qcom,dual-dsi-mode; + qcom,master-dsi; + qcom,sync-dual-dsi; + + qcom,mdss-mdp-transfer-time-us = <12000>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&dsi_active>; + pinctrl-1 = <&dsi_suspend>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + remote-endpoint = <&panel_in>; + data-lanes = <0 1 2 3>; + }; + }; + }; + + panel: panel@0 { + compatible = "sharp,lq101r1sx01"; + reg = <0>; + link2 = <&secondary>; + + power-supply = <...>; + backlight = <...>; + + port { + panel_in: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; + + dsi_phy0: dsi-phy@fd922a00 { + compatible = "qcom,dsi-phy-28nm-hpm"; + qcom,dsi-phy-index = <0>; + reg-names = + "dsi_pll", + "dsi_phy", + "dsi_phy_regulator"; + reg = <0xfd922a00 0xd4>, + <0xfd922b00 0x2b0>, + <0xfd922d80 0x7b>; + clock-names = "iface"; + clocks = <&mmcc MDSS_AHB_CLK>; + #clock-cells = <1>; + vddio-supply = <&pma8084_l12>; + + qcom,dsi-phy-regulator-ldo-mode; + qcom,panel-allow-phy-poweroff; + qcom,dsi-phy-regulator-min-datarate-bps = <1200000000>; + qcom,panel-force-clock-lane-hs; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/edp.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/edp.txt new file mode 100644 index 0000000000000000000000000000000000000000..186ee231a1a1bd3a6759883fd2d8468d01cdab1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/edp.txt @@ -0,0 +1,56 @@ +Qualcomm Technologies Inc. snapdragon eDP output + +Required properties: +- compatible: + * "qcom,mdss-edp" +- reg: Physical base address and length of the registers of controller and PLL +- reg-names: The names of register regions. The following regions are required: + * "edp" + * "pll_base" +- interrupts: The interrupt signal from the eDP block. +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: the following clocks are required: + * "core" + * "iface" + * "mdp_core" + * "pixel" + * "link" +- #clock-cells: The value should be 1. +- vdda-supply: phandle to vdda regulator device node +- lvl-vdd-supply: phandle to regulator device node which is used to supply power + to HPD receiving chip +- panel-en-gpios: GPIO pin to supply power to panel. +- panel-hpd-gpios: GPIO pin used for eDP hpd. + + +Example: + mdss_edp: qcom,mdss_edp@fd923400 { + compatible = "qcom,mdss-edp"; + reg-names = + "edp", + "pll_base"; + reg = <0xfd923400 0x700>, + <0xfd923a00 0xd4>; + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = + "core", + "pixel", + "iface", + "link", + "mdp_core"; + clocks = + <&mmcc MDSS_EDPAUX_CLK>, + <&mmcc MDSS_EDPPIXEL_CLK>, + <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_EDPLINK_CLK>, + <&mmcc MDSS_MDP_CLK>; + #clock-cells = <1>; + vdda-supply = <&pma8084_l12>; + lvl-vdd-supply = <&lvl_vreg>; + panel-en-gpios = <&tlmm 137 0>; + panel-hpd-gpios = <&tlmm 103 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..66a123b221b82a22f6ae593024dec1d89409baf0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/hdmi.txt @@ -0,0 +1,99 @@ +Qualcomm Technologies, Inc. adreno/snapdragon hdmi output + +Required properties: +- compatible: one of the following + * "qcom,hdmi-tx-8996" + * "qcom,hdmi-tx-8994" + * "qcom,hdmi-tx-8084" + * "qcom,hdmi-tx-8974" + * "qcom,hdmi-tx-8660" + * "qcom,hdmi-tx-8960" +- reg: Physical base address and length of the controller's registers +- reg-names: "core_physical" +- interrupts: The interrupt signal from the hdmi block. +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: device clocks + See ../clocks/clock-bindings.txt for details. +- core-vdda-supply: phandle to supply regulator +- hdmi-mux-supply: phandle to mux regulator +- phys: the phandle for the HDMI PHY device +- phy-names: the name of the corresponding PHY device + +Optional properties: +- hpd-gpios: hpd pin +- qcom,hdmi-tx-mux-en-gpios: hdmi mux enable pin +- qcom,hdmi-tx-mux-sel-gpios: hdmi mux select pin +- qcom,hdmi-tx-mux-lpm-gpios: hdmi mux lpm pin +- power-domains: reference to the power domain(s), if available. +- pinctrl-names: the pin control state names; should contain "default" +- pinctrl-0: the default pinctrl state (active) +- pinctrl-1: the "sleep" pinctrl state + +HDMI PHY: +Required properties: +- compatible: Could be the following + * "qcom,hdmi-phy-8660" + * "qcom,hdmi-phy-8960" + * "qcom,hdmi-phy-8974" + * "qcom,hdmi-phy-8084" + * "qcom,hdmi-phy-8996" +- #phy-cells: Number of cells in a PHY specifier; Should be 0. +- reg: Physical base address and length of the registers of the PHY sub blocks. +- reg-names: The names of register regions. The following regions are required: + * "hdmi_phy" + * "hdmi_pll" + For HDMI PHY on msm8996, these additional register regions are required: + * "hdmi_tx_l0" + * "hdmi_tx_l1" + * "hdmi_tx_l3" + * "hdmi_tx_l4" +- power-domains: Should be <&mmcc MDSS_GDSC>. +- clocks: device clocks + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- core-vdda-supply: phandle to vdda regulator device node + +Example: + +/ { + ... + + hdmi: hdmi@4a00000 { + compatible = "qcom,hdmi-tx-8960"; + reg-names = "core_physical"; + reg = <0x04a00000 0x2f0>; + interrupts = ; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = + "core", + "master_iface", + "slave_iface"; + clocks = + <&mmcc HDMI_APP_CLK>, + <&mmcc HDMI_M_AHB_CLK>, + <&mmcc HDMI_S_AHB_CLK>; + qcom,hdmi-tx-ddc-clk = <&msmgpio 70 GPIO_ACTIVE_HIGH>; + qcom,hdmi-tx-ddc-data = <&msmgpio 71 GPIO_ACTIVE_HIGH>; + qcom,hdmi-tx-hpd = <&msmgpio 72 GPIO_ACTIVE_HIGH>; + core-vdda-supply = <&pm8921_hdmi_mvs>; + hdmi-mux-supply = <&ext_3p3v>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&hpd_active &ddc_active &cec_active>; + pinctrl-1 = <&hpd_suspend &ddc_suspend &cec_suspend>; + + phys = <&hdmi_phy>; + phy-names = "hdmi_phy"; + }; + + hdmi_phy: phy@4a00400 { + compatible = "qcom,hdmi-phy-8960"; + reg-names = "hdmi_phy", + "hdmi_pll"; + reg = <0x4a00400 0x60>, + <0x4a00500 0x100>; + #phy-cells = <0>; + power-domains = <&mmcc MDSS_GDSC>; + clock-names = "slave_iface"; + clocks = <&mmcc HDMI_S_AHB_CLK>; + core-vdda-supply = <&pm8921_hdmi_mvs>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdp4.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdp4.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d9cf3579dc61a81586a8174bc65dfea7e0206ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdp4.txt @@ -0,0 +1,112 @@ +Qualcomm Technologies, Inc. adreno/snapdragon MDP4 display controller + +Description: + +This is the bindings documentation for the MDP4 display controller found in +SoCs like MSM8960, APQ8064 and MSM8660. + +Required properties: +- compatible: + * "qcom,mdp4" - mdp4 +- reg: Physical base address and length of the controller's registers. +- interrupts: The interrupt signal from the display controller. +- clocks: device clocks + See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. + * "core_clk" + * "iface_clk" + * "bus_clk" + * "lut_clk" + * "hdmi_clk" + * "tv_clk" +- ports: contains the list of output ports from MDP. These connect to interfaces + that are external to the MDP hardware, such as HDMI, DSI, EDP etc (LVDS is a + special case since it is a part of the MDP block itself). + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + The output port mappings are: + Port 0 -> LCDC/LVDS + Port 1 -> DSI1 Cmd/Video + Port 2 -> DSI2 Cmd/Video + Port 3 -> DTV + +Optional properties: +- clock-names: the following clocks are optional: + * "lut_clk" + +Example: + +/ { + ... + + hdmi: hdmi@4a00000 { + ... + ports { + ... + port@0 { + reg = <0>; + hdmi_in: endpoint { + remote-endpoint = <&mdp_dtv_out>; + }; + }; + ... + }; + ... + }; + + ... + + mdp: mdp@5100000 { + compatible = "qcom,mdp4"; + reg = <0x05100000 0xf0000>; + interrupts = ; + clock-names = + "core_clk", + "iface_clk", + "lut_clk", + "hdmi_clk", + "tv_clk"; + clocks = + <&mmcc MDP_CLK>, + <&mmcc MDP_AHB_CLK>, + <&mmcc MDP_AXI_CLK>, + <&mmcc MDP_LUT_CLK>, + <&mmcc HDMI_TV_CLK>, + <&mmcc MDP_TV_CLK>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp_lvds_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + mdp_dsi1_out: endpoint { + }; + }; + + port@2 { + reg = <2>; + mdp_dsi2_out: endpoint { + }; + }; + + port@3 { + reg = <3>; + mdp_dtv_out: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdp5.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdp5.txt new file mode 100644 index 0000000000000000000000000000000000000000..fcad35c3a26e5eb893b10e12906003d63c2ee92c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdp5.txt @@ -0,0 +1,158 @@ +Qualcomm Technologies, Inc. adreno/snapdragon MDP5 display controller + +Description: + +This is the bindings documentation for the Mobile Display Subsytem(MDSS) that +encapsulates sub-blocks like MDP5, DSI, HDMI, eDP etc, and the MDP5 display +controller found in SoCs like MSM8974, APQ8084, MSM8916, MSM8994 and MSM8996. + +MDSS: +Required properties: +- compatible: + * "qcom,mdss" - MDSS +- reg: Physical base address and length of the controller's registers. +- reg-names: The names of register regions. The following regions are required: + * "mdss_phys" + * "vbif_phys" +- interrupts: The interrupt signal from MDSS. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- power-domains: a power domain consumer specifier according to + Documentation/devicetree/bindings/power/power_domain.txt +- clocks: device clocks. See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. + * "iface" + * "bus" + * "vsync" +- #address-cells: number of address cells for the MDSS children. Should be 1. +- #size-cells: Should be 1. +- ranges: parent bus address space is the same as the child bus address space. + +Optional properties: +- clock-names: the following clocks are optional: + * "lut" + +MDP5: +Required properties: +- compatible: + * "qcom,mdp5" - MDP5 +- reg: Physical base address and length of the controller's registers. +- reg-names: The names of register regions. The following regions are required: + * "mdp_phys" +- interrupts: Interrupt line from MDP5 to MDSS interrupt controller. +- clocks: device clocks. See ../clocks/clock-bindings.txt for details. +- clock-names: the following clocks are required. +- * "bus" +- * "iface" +- * "core" +- * "vsync" +- ports: contains the list of output ports from MDP. These connect to interfaces + that are external to the MDP hardware, such as HDMI, DSI, EDP etc (LVDS is a + special case since it is a part of the MDP block itself). + + Each output port contains an endpoint that describes how it is connected to an + external interface. These are described by the standard properties documented + here: + Documentation/devicetree/bindings/graph.txt + Documentation/devicetree/bindings/media/video-interfaces.txt + + The availability of output ports can vary across SoC revisions: + + For MSM8974 and APQ8084: + Port 0 -> MDP_INTF0 (eDP) + Port 1 -> MDP_INTF1 (DSI1) + Port 2 -> MDP_INTF2 (DSI2) + Port 3 -> MDP_INTF3 (HDMI) + + For MSM8916: + Port 0 -> MDP_INTF1 (DSI1) + + For MSM8994 and MSM8996: + Port 0 -> MDP_INTF1 (DSI1) + Port 1 -> MDP_INTF2 (DSI2) + Port 2 -> MDP_INTF3 (HDMI) + +Optional properties: +- clock-names: the following clocks are optional: + * "lut" + +Example: + +/ { + ... + + mdss: mdss@1a00000 { + compatible = "qcom,mdss"; + reg = <0x1a00000 0x1000>, + <0x1ac8000 0x3000>; + reg-names = "mdss_phys", "vbif_phys"; + + power-domains = <&gcc MDSS_GDSC>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "vsync" + + interrupts = <0 72 0>; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mdp: mdp@1a01000 { + compatible = "qcom,mdp5"; + reg = <0x1a01000 0x90000>; + reg-names = "mdp_phys"; + + interrupt-parent = <&mdss>; + interrupts = <0 0>; + + clocks = <&gcc GCC_MDSS_AHB_CLK>, + <&gcc GCC_MDSS_AXI_CLK>, + <&gcc GCC_MDSS_MDP_CLK>, + <&gcc GCC_MDSS_VSYNC_CLK>; + clock-names = "iface", + "bus", + "core", + "vsync"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdp5_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + }; + }; + + dsi0: dsi@1a98000 { + ... + ports { + ... + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&mdp5_intf1_out>; + }; + }; + ... + }; + ... + }; + + dsi_phy0: dsi-phy@1a98300 { + ... + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdss-dsi-panel.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdss-dsi-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..338ea8d8dc9e742dfb1db92ac97cd6942ef9b84a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdss-dsi-panel.txt @@ -0,0 +1,810 @@ +QTI mdss-dsi-panel + +mdss-dsi-panel is a dsi panel device which supports panels that +are compatible with MIPI display serial interface specification. + +Required properties: +- compatible: This property applies to DSI V2 panels only. + This property should not be added for panels + that work based on version "V6.0" + DSI panels that are of different versions + are initialized by the drivers for dsi controller. + This property specifies the version + for DSI HW that this panel will work with + "qcom,dsi-panel-v2" = DSI V2.0 +- status: This property applies to DSI V2 panels only. + This property should not be added for panels + that work based on version "V6.0" + DSI panels that are of different versions + are initialized by the drivers for dsi controller. + A string that has to be set to "okay/ok" + to enable the panel driver. By default this property + will be set to "disable". Will be set to "ok/okay" + status for specific platforms. +- qcom,mdss-dsi-panel-controller: Specifies the phandle for the DSI controller that + this panel will be mapped to. +- qcom,mdss-dsi-panel-width: Specifies panel width in pixels. +- qcom,mdss-dsi-panel-height: Specifies panel height in pixels. +- qcom,mdss-dsi-bpp: Specifies the panel bits per pixel. + 3 = for rgb111 + 8 = for rgb332 + 12 = for rgb444 + 16 = for rgb565 + 18 = for rgb666 + 24 = for rgb888 +- qcom,mdss-dsi-panel-destination: A string that specifies the destination display for the panel. + "display_1" = DISPLAY_1 + "display_2" = DISPLAY_2 +- qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY + timing settings for the panel. +- qcom,mdss-dsi-panel-timings-8996: An array of length 40 char that specifies the 8996 PHY lane + timing settings for the panel. +- qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-off-command: A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are + sent after displaying an image. + +Note, if a short DCS packet(i.e packet with Byte 0:dcs data type as 05) mentioned in +qcom,mdss-dsi-on-command/qcom,mdss-dsi-off-command stream fails to transmit, +then 3 options can be tried. + 1. Send the packet as a long packet instead + Byte 0: dcs data type = 05 (DCS short Packet) + Byte 0: dcs data type = 29 (DCS long Packet) + 2. Send the packet in one burst by prepending with the next packet in packet stream + Byte 1 = 01 (indicates this is an individual packet) + Byte 1 = 00 (indicates this will be appended to the next + individual packet in the packet stream) + 3. Prepend a NULL packet to the short packet and send both in one burst instead of + combining multiple short packets and sending them in one burst. + +Optional properties: +- qcom,mdss-dsi-panel-name: A string used as a descriptive name of the panel +- qcom,mdss-dsi-panel-phy-timings: An array of length 'n' char that specifies the DSI PHY lane + timing settings for the panel. This is specific to SDE DRM driver. + The value of 'n' depends on the DSI PHY h/w revision and parsing this + property properly will be taken care in the DSI PHY DRM driver. +- qcom,cmd-sync-wait-broadcast: Boolean used to broadcast dcs command to panels. +- qcom,mdss-dsi-fbc-enable: Boolean used to enable frame buffer compression mode. +- qcom,mdss-dsi-panel-mode-switch: Boolean used to enable panel operating mode switch. +- qcom,mdss-dsi-fbc-slice-height: Slice height(in lines) of compressed block. + Expressed as power of 2. To set as 128 lines, + this should be set to 7. +- qcom,mdss-dsi-fbc-2d-pred-mode: Boolean to enable 2D map prediction. +- qcom,mdss-dsi-fbc-ver2-mode: Boolean to enable FBC 2.0 that supports 1/3 + compression. +- qcom,mdss-dsi-fbc-bpp: Compressed bpp supported by the panel. + Specified color order is used as default value. +- qcom,mdss-dsi-fbc-packing: Component packing. + 0 = default value. +- qcom,mdss-dsi-fbc-quant-error: Boolean used to enable quantization error calculation. +- qcom,mdss-dsi-fbc-bias: Bias for CD. + 0 = default value. +- qcom,mdss-dsi-fbc-pat-mode: Boolean used to enable PAT mode. +- qcom,mdss-dsi-fbc-vlc-mode: Boolean used to enable VLC mode. +- qcom,mdss-dsi-fbc-bflc-mode: Boolean used to enable BFLC mode. +- qcom,mdss-dsi-fbc-h-line-budget: Per line extra budget. + 0 = default value. +- qcom,mdss-dsi-fbc-budget-ctrl: Extra budget level. + 0 = default value. +- qcom,mdss-dsi-fbc-block-budget: Per block budget. + 0 = default value. +- qcom,mdss-dsi-fbc-lossless-threshold: Lossless mode threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-lossy-threshold: Lossy mode threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-rgb-threshold: Lossy RGB threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-lossy-mode-idx: Lossy mode index value. + 0 = default value. +- qcom,mdss-dsi-fbc-max-pred-err: Max quantization prediction error. + 0 = default value +- qcom,mdss-dsi-h-back-porch: Horizontal back porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-h-front-porch: Horizontal front porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-h-pulse-width: Horizontal pulse width. + 2 = default value. +- qcom,mdss-dsi-h-sync-skew: Horizontal sync skew value. + 0 = default value. +- qcom,mdss-dsi-v-back-porch: Vertical back porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-v-front-porch: Vertical front porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-v-pulse-width: Vertical pulse width. + 2 = default value. +- qcom,mdss-dsi-h-left-border: Horizontal left border in pixel. + 0 = default value +- qcom,mdss-dsi-h-right-border: Horizontal right border in pixel. + 0 = default value +- qcom,mdss-dsi-v-top-border: Vertical top border in pixel. + 0 = default value +- qcom,mdss-dsi-v-bottom-border: Vertical bottom border in pixel. + 0 = default value +- qcom,mdss-dsi-underflow-color: Specifies the controller settings for the + panel under flow color. + 0xff = default value. +- qcom,mdss-dsi-border-color: Defines the border color value if border is present. + 0 = default value. +- qcom,mdss-dsi-panel-jitter: Panel jitter value is expressed in terms of numerator + and denominator. It contains two u32 values - numerator + followed by denominator. The jitter configurition causes + the early wakeup if panel needs to adjust before vsync. + Default jitter value is 2.0%. Max allowed value is 10%. +- qcom,mdss-dsi-panel-prefill-lines: An integer value defines the panel prefill lines required to + calculate the backoff time of rsc. + Default value is 16 lines. Max allowed value is vtotal. +- qcom,mdss-dsi-pan-enable-dynamic-fps: Boolean used to enable change in frame rate dynamically. +- qcom,mdss-dsi-pan-fps-update: A string that specifies when to change the frame rate. + "dfps_suspend_resume_mode"= FPS change request is + implemented during suspend/resume. + "dfps_immediate_clk_mode" = FPS change request is + implemented immediately using DSI clocks. + "dfps_immediate_porch_mode_hfp" = FPS change request is + implemented immediately by changing panel horizontal + front porch values. + "dfps_immediate_porch_mode_vfp" = FPS change request is + implemented immediately by changing panel vertical + front porch values. +- qcom,min-refresh-rate: Minimum refresh rate supported by the panel. +- qcom,max-refresh-rate: Maximum refresh rate supported by the panel. If max refresh + rate is not specified, then the frame rate of the panel in + qcom,mdss-dsi-panel-framerate is used. +- qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight + control for this panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + "bl_ctrl_dcs" = Backlight controlled by DCS commands. + "bl_ctrl_external" = Backlight controlled by externally + other: Unknown backlight control. (default) +- qcom,mdss-dsi-sec-bl-pmic-control-type: A string that specifies the implementation of backlight + control for secondary panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + "bl_ctrl_dcs" = Backlight controlled by DCS commands. + "bl_ctrl_external" = Backlight controlled by externally + other: Unknown backlight control. (default) +- qcom,mdss-dsi-bl-pwm-pmi: Boolean to indicate that PWM control is through second pmic chip. +- qcom,mdss-dsi-bl-pmic-bank-select: LPG channel for backlight. + Required if backlight pmic control type is PWM +- qcom,mdss-dsi-bl-pmic-pwm-frequency: PWM period in microseconds. + Required if backlight pmic control type is PWM +- qcom,mdss-dsi-pwm-gpio: PMIC gpio binding to backlight. + Required if backlight pmic control type is PWM +- qcom,mdss-dsi-bl-min-level: Specifies the min backlight level supported by the panel. + 0 = default value. +- qcom,mdss-dsi-bl-max-level: Specifies the max backlight level supported by the panel. + 255 = default value. +- qcom,mdss-brightness-max-level: Specifies the max brightness level supported. + 255 = default value. +- qcom,bl-update-flag: A string that specifies controls for backlight update of the panel. + "delay_until_first_frame" = Delay backlight update of the panel + until the first frame is received from the HW. +- qcom,mdss-dsi-interleave-mode: Specifies interleave mode. + 0 = default value. +- qcom,mdss-dsi-panel-type: Specifies the panel operating mode. + "dsi_video_mode" = enable video mode (default). + "dsi_cmd_mode" = enable command mode. +- qcom,5v-boost-gpio: Specifies the panel gpio for display 5v boost. +- qcom,mdss-dsi-te-check-enable: Boolean to enable Tear Check configuration. +- qcom,mdss-dsi-te-using-wd: Boolean entry enables the watchdog timer support to generate the vsync signal + for command mode panel. By default, panel TE will be used to generate the vsync. +- qcom,mdss-dsi-te-using-te-pin: Boolean to specify whether using hardware vsync. +- qcom,mdss-dsi-qsync-min-refresh-rate: A u32 entry to specify minimum refresh rate supported by the panel to enable qsync feature. +- qcom,mdss-dsi-qsync-on-commands: String that specifies the commands to enable qsync feature. +- qcom,mdss-dsi-qsync-on-commands-state: String that specifies the ctrl state for sending qsync on commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-qsync-off-commands: String that specifies the commands to disable qsync feature. +- qcom,mdss-dsi-qsync-off-commands-state: String that specifies the ctrl state for sending qsync off commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-te-pin-select: Specifies TE operating mode. + 0 = TE through embedded dcs command + 1 = TE through TE gpio pin. (default) +- qcom,mdss-dsi-te-dcs-command: Inserts the dcs command. + 1 = default value. +- qcom,mdss-dsi-wr-mem-start: DCS command for write_memory_start. + 0x2c = default value. +- qcom,mdss-dsi-wr-mem-continue: DCS command for write_memory_continue. + 0x3c = default value. +- qcom,mdss-dsi-h-sync-pulse: Specifies the pulse mode option for the panel. + 0 = Don't send hsa/he following vs/ve packet(default) + 1 = Send hsa/he following vs/ve packet +- qcom,mdss-dsi-hfp-power-mode: Boolean to determine DSI lane state during + horizontal front porch (HFP) blanking period. +- qcom,mdss-dsi-hbp-power-mode: Boolean to determine DSI lane state during + horizontal back porch (HBP) blanking period. +- qcom,mdss-dsi-hsa-power-mode: Boolean to determine DSI lane state during + horizontal sync active (HSA) mode. +- qcom,mdss-dsi-last-line-interleave Boolean to determine if last line + interleave flag needs to be enabled. +- qcom,mdss-dsi-bllp-eof-power-mode: Boolean to determine DSI lane state during + blanking low power period (BLLP) EOF mode. +- qcom,mdss-dsi-bllp-power-mode: Boolean to determine DSI lane state during + blanking low power period (BLLP) mode. +- qcom,mdss-dsi-traffic-mode: Specifies the panel traffic mode. + "non_burst_sync_pulse" = non burst with sync pulses (default). + "non_burst_sync_event" = non burst with sync start event. + "burst_mode" = burst mode. +- qcom,mdss-dsi-pixel-packing: Specifies if pixel packing is used (in case of RGB666). + "tight" = Tight packing (default value). + "loose" = Loose packing. +- qcom,mdss-dsi-virtual-channel-id: Specifies the virtual channel identefier. + 0 = default value. +- qcom,mdss-dsi-color-order: Specifies the R, G and B channel ordering. + "rgb_swap_rgb" = DSI_RGB_SWAP_RGB (default value) + "rgb_swap_rbg" = DSI_RGB_SWAP_RBG + "rgb_swap_brg" = DSI_RGB_SWAP_BRG + "rgb_swap_grb" = DSI_RGB_SWAP_GRB + "rgb_swap_gbr" = DSI_RGB_SWAP_GBR +- qcom,mdss-dsi-lane-0-state: Boolean that specifies whether data lane 0 is enabled. +- qcom,mdss-dsi-lane-1-state: Boolean that specifies whether data lane 1 is enabled. +- qcom,mdss-dsi-lane-2-state: Boolean that specifies whether data lane 2 is enabled. +- qcom,mdss-dsi-lane-3-state: Boolean that specifies whether data lane 3 is enabled. +- qcom,mdss-dsi-t-clk-post: Specifies the byte clock cycles after mode switch. + 0x00 = default value. +- qcom,mdss-dsi-t-clk-pre: Specifies the byte clock cycles before mode switch. + 0x00 = default value. +- qcom,mdss-dsi-stream: Specifies the packet stream to be used. + 0 = stream 0 (default) + 1 = stream 1 +- qcom,mdss-dsi-mdp-trigger: Specifies the trigger mechanism to be used for MDP path. + "none" = no trigger + "trigger_te" = Tear check signal line used for trigger + "trigger_sw" = Triggered by software (default) + "trigger_sw_te" = Software trigger and TE +- qcom,mdss-dsi-dma-trigger: Specifies the trigger mechanism to be used for DMA path. + "none" = no trigger + "trigger_te" = Tear check signal line used for trigger + "trigger_sw" = Triggered by software (default) + "trigger_sw_seof" = Software trigger and start/end of frame trigger. + "trigger_sw_te" = Software trigger and TE +- qcom,mdss-dsi-panel-framerate: Specifies the frame rate for the panel. + 60 = 60 frames per second (default) +- qcom,mdss-dsi-panel-clockrate: A 64 bit value specifies the panel clock speed in Hz. + 0 = default value. +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split enabled, this time should not be higher + than two times the dsi link rate time. + 14000 = default value. +- qcom,mdss-dsi-on-command-state: String that specifies the ctrl state for sending ON commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-off-command-state: String that specifies the ctrl state for sending OFF commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-post-mode-switch-on-command-state: String that specifies the ctrl state for sending ON commands post mode switch. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-pan-physical-width-dimension: Specifies panel physical width in mm which corresponds + to the physical width in the framebuffer information. +- qcom,mdss-pan-physical-height-dimension: Specifies panel physical height in mm which corresponds + to the physical height in the framebuffer information. +- qcom,mdss-dsi-mode-sel-gpio-state: String that specifies the lcd mode for panel + (such as single-port/dual-port), if qcom,panel-mode-gpio + binding is defined in dsi controller. + "dual_port" = Set GPIO to LOW + "single_port" = Set GPIO to HIGH + "high" = Set GPIO to HIGH + "low" = Set GPIO to LOW + The default value is "dual_port". +- qcom,mdss-tear-check-disable: Boolean to disable mdp tear check. Tear check is enabled by default to avoid + tearing. Other tear-check properties are ignored if this property is present. + The below tear check configuration properties can be individually tuned if + tear check is enabled. +- qcom,mdss-tear-check-sync-cfg-height: Specifies the vertical total number of lines. + The default value is 0xfff0. +- qcom,mdss-tear-check-sync-init-val: Specifies the init value at which the read pointer gets loaded + at vsync edge. The reader pointer refers to the line number of + panel buffer that is currently being updated. + The default value is panel height. +- qcom,mdss-tear-check-sync-threshold-start: + Allows the first ROI line write to an panel when read pointer is + between the range of ROI start line and ROI start line plus this + setting. + The default value is 4. +- qcom,mdss-tear-check-sync-threshold-continue: + The minimum number of lines the write pointer needs to be + above the read pointer so that it is safe to write to the panel. + (This check is not done for the first ROI line write of an update) + The default value is 4. +- qcom,mdss-tear-check-start-pos: Specify the y position from which the start_threshold value is + added and write is kicked off if the read pointer falls within that + region. + The default value is panel height. +- qcom,mdss-tear-check-rd-ptr-trigger-intr: + Specify the read pointer value at which an interrupt has to be + generated. + The default value is panel height + 1. +- qcom,mdss-tear-check-frame-rate: Specify the value to be a real frame rate(fps) x 100 factor to tune the + timing of TE simulation with more precision. + The default value is 6000 with 60 fps. +- qcom,mdss-dsi-reset-sequence: An array that lists the + sequence of reset gpio values and sleeps + Each command will have the format defined + as below: + --> Reset GPIO value + --> Sleep value (in ms) +- qcom,partial-update-enabled: String used to enable partial + panel update for command mode panels. + "none": partial update is disabled + "single_roi": default enable mode, only single roi is sent to panel + "dual_roi": two rois are merged into one big roi. Panel ddic should be able + to process two roi's along with the DCS command to send two rois. + disabled if property is not specified. This property is specified + per timing node to support resolution restrictions. +- qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating + additional idle time in dsi clock cycles that is needed + to compensate for smaller line width. +- qcom,partial-update-roi-merge: Boolean indicates roi combination is need + and function has been provided for dcs + 2A/2B command. This property is specified per timing node to support + resolution restrictions. +- qcom,dcs-cmd-by-left: Boolean to indicate that dcs command are sent + through the left DSI controller only in a dual-dsi configuration +- qcom,mdss-dsi-panel-hdr-enabled: Boolean to indicate HDR support in panel. +- qcom,mdss-dsi-panel-hdr-color-primaries: + Array of 8 unsigned integers denoting chromaticity of panel.These + values are specified in nits units. The value range is 0 through 50000. + To obtain real chromacity, these values should be divided by factor of + 50000. The structure of array is defined in below order + value 1: x value of white chromaticity of display panel + value 2: y value of white chromaticity of display panel + value 3: x value of red chromaticity of display panel + value 4: y value of red chromaticity of display panel + value 5: x value of green chromaticity of display panel + value 6: y value of green chromaticity of display panel + value 7: x value of blue chromaticity of display panel + value 8: y value of blue chromaticity of display panel +- qcom,mdss-dsi-panel-peak-brightness: Maximum brightness supported by panel.In absence of maximum value + typical value becomes peak brightness. Value is specified in nits units. + To obtain real peak brightness, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-panel-blackness-level: Blackness level supported by panel. Blackness level is defined as + ratio of peak brightness to contrast. Value is specified in nits units. + To obtain real blackness level, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-lp11-init: Boolean used to enable the DSI clocks and data lanes (low power 11) + before issuing hardware reset line. +- qcom,mdss-dsi-init-delay-us: Delay in microseconds(us) before performing any DSI activity in lp11 + mode. This master delay (t_init_delay as per DSI spec) should be sum + of DSI internal delay to reach fuctional after power up and minimum + delay required by panel to reach functional. +- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets. +- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets. +- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode. +- qcom,suspend-ulps-enabled: Boolean to enable support for ULPS mode for panels during suspend state. +- qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its + left, top, width, height alignments and minimum width and + height values. This property is specified per timing node to support + resolution's alignment restrictions. +- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. +- qcom,mdss-dsi-panel-status-command: A byte stream formed by multiple dcs packets based on + qcom dsi controller protocol, to read the panel status. + This value is used to kick in the ESD recovery. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-panel-status-command-mode: + String that specifies the ctrl state for reading the panel status. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-lp1-command: An optional byte stream to request low + power mode on a panel +- qcom,mdss-dsi-lp1-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-lp2-command: An optional byte stream to request ultra + low power mode on a panel +- qcom,mdss-dsi-lp2-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-nolp-command: An optional byte stream to disable low + power and ultra low power panel modes +- qcom,mdss-dsi-nolp-command-mode: String that specifies the ctrl state for + setting the panel power mode. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. + "bta_check" = Uses BTA to check the panel status + "reg_read" = Reads panel status register to check the panel status + "reg_read_nt35596" = Reads panel status register to check the panel + status for NT35596 panel. + "te_signal_check" = Uses TE signal behaviour to check the panel status +- qcom,mdss-dsi-panel-status-read-length: Integer array that specify the expected read-back length of values + for each of panel registers. Each length is corresponding to number of + returned parameters of register introduced in specification. +- qcom,mdss-dsi-panel-status-valid-params: Integer array that specify the valid returned values which need to check + for each of register. + Some panel need only check the first few values returned from panel. + So: if this property is the same to qcom,mdss-dsi-panel-status-read-length, + then just ignore this one. +- qcom,mdss-dsi-panel-status-value: Multiple integer arrays, each specifies the values of the panel status register + which is used to check the panel status. The size of each array is the sum of + length specified in qcom,mdss-dsi-panel-status-read-length, and must be equal. + This can cover that Some panel may return several alternative values. +- qcom,mdss-dsi-panel-max-error-count: Integer value that specifies the maximum number of errors from register + read that can be ignored before treating that the panel has gone bad. +- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports + dynamic switching from video mode to command mode + and vice versa. +- qcom,dynamic-mode-switch-type: A string specifies how to perform dynamic mode switch. + If qcom,dynamic-mode-switch-enabled is set and no string specified, default value is + dynamic-switch-suspend-resume. + "dynamic-switch-suspend-resume"= Switch using suspend/resume. Panel will + go blank during transition. + "dynamic-switch-immediate"= Switch on next frame update. Panel will + not go blank for this transition. + "dynamic-resolution-switch-immediate"= Switch the panel resolution. Panel will + not go blank for this transition. +- qcom,mdss-dsi-post-mode-switch-on-command: Multiple dcs packets used for turning on DSI panel + after panel has switch modes. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,video-to-cmd-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from video mode to command mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from command mode to video mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,send-pps-before-switch: Boolean propety to indicate when PPS commands should be sent, + either before or after switch commands during dynamic resolution + switch in DSC panels. If the property is not present, the default + behavior is to send PPS commands after the switch commands. +- qcom,mdss-dsi-panel-orientation: String used to indicate orientation of panel + "180" = panel is flipped in both horizontal and vertical directions + "hflip" = panel is flipped in horizontal direction + "vflip" = panel is flipped in vertical direction +- qcom,panel-ack-disabled: A boolean property to indicate, whether we need to wait for any ACK from the panel + for any commands that we send. +- qcom,mdss-dsi-force-clock-lane-hs: Boolean to force dsi clock lanes to HS mode always. + +- qcom,compression-mode: Select compression mode for panel. + "fbc" - frame buffer compression + "dsc" - display stream compression. + If "dsc" compression is used then config subnodes needs to be defined. +- qcom,panel-supply-entries: A node that lists the elements of the supply used to + power the DSI panel. There can be more than one instance + of this binding, in which case the entry would be appended + with the supply entry index. For a detailed description of + fields in the supply entry, refer to the qcom,ctrl-supply-entries + binding above. +- qcom,mdss-dsc-version: An 8 bit value indicates the DSC version supported by panel. Bits[0.3] + provides information about minor version while Bits[4.7] provides + major version information. It supports only DSC rev 1(Major).1(Minor) + right now. +- qcom,mdss-dsc-scr-version: Each DSC version can have multiple SCR. This 8 bit value indicates + current SCR revision information supported by panel. +- qcom,mdss-dsc-encoders: An integer value indicating how many DSC encoders should be used + to drive data stream to DSI. + Default value is 1 and max value is 2. + 2 encoder should be used only if qcom,mdss-lm-split or + qcom,split-mode with pingpong-split is used. +- qcom,mdss-dsc-slice-height: An integer value indicates the dsc slice height. +- qcom,mdss-dsc-slice-width: An integer value indicates the dsc slice width. + Multiple of slice width should be equal to panel-width. + Maximum 2 slices per DSC encoder can be used so if 2 DSC encoders + are used then minimum slice width is equal to panel-width/4. +- qcom,mdss-dsc-slice-per-pkt: An integer value indicates the slice per dsi packet. +- qcom,mdss-dsc-bit-per-component: An integer value indicates the bits per component before compression. +- qcom,mdss-dsc-bit-per-pixel: An integer value indicates the bits per pixel after compression. +- qcom,mdss-dsc-block-prediction-enable: A boolean value to enable/disable the block prediction at decoder. +- qcom,mdss-dsc-config-by-manufacture-cmd: A boolean to indicates panel use manufacture command to setup pps + instead of standard dcs type 0x0A. +- qcom,display-topology: Array of u32 values which specifies the list of topologies available + for the display. A display topology is defined by a + set of 3 values in the order: + - number of mixers + - number of compression encoders + - number of interfaces + Therefore, the array should always contain a tuple of 3 elements. +- qcom,default-topology-index: An u32 value which indexes the topology set + specified by the node "qcom,display-topology" + to identify the default topology for the + display. The first set is indexed by the + value 0. +- qcom,mdss-dsi-ext-bridge-mode: External bridge chip is connected instead of panel. +- qcom,mdss-dsi-dma-schedule-line: An integer value indicates the line number after vertical active + region, at which command DMA needs to be triggered. + +Required properties for sub-nodes: None +Optional properties: +- qcom,dba-panel: Indicates whether the current panel is used as a display bridge + to a non-DSI interface. +- qcom,bridge-name: A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name + is required if qcom,dba-panel is defined for the panel. +- qcom,adjust-timer-wakeup-ms: An integer value to indicate the timer delay(in ms) to accommodate + s/w delay while configuring the event timer wakeup logic. + +- qcom,mdss-dsi-display-timings: Parent node that lists the different resolutions that the panel supports. + Each child represents timings settings for a specific resolution. +- qcom,mdss-dsi-post-init-delay: Specifies required number of frames to wait so that panel can be functional + to show proper display. +- qcom,mdss-dsi-video-mode: A boolean to indicates current timing can only work in video mode. +- qcom,mdss-dsi-cmd-mode: A boolean to indicates current timing can only work in command mode. + +Additional properties added to the second level nodes that represent timings properties: +- qcom,mdss-dsi-timing-default: Property that specifies the current child as the default + timing configuration that will be used. +- qcom,mdss-dsi-timing-switch-command: List of commands that need to be sent + to panel when the resolution/timing switch happens dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,mdss-dsi-timing-switch-command-state: String that specifies the ctrl state for sending resolution switch + commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode + +Note, if a given optional qcom,* binding is not present, then the driver will configure +the default values specified. + +Example: +&mdss_mdp { + dsi_sim_vid: qcom,mdss_dsi_sim_video { + qcom,mdss-dsi-panel-name = "simulator video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-pixel-packing = <0>; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-fbc-enable; + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-fbc-slice-height = <5>; + qcom,mdss-dsi-fbc-2d-pred-mode; + qcom,mdss-dsi-fbc-ver2-mode; + qcom,mdss-dsi-fbc-bpp = <0>; + qcom,mdss-dsi-fbc-packing = <0>; + qcom,mdss-dsi-fbc-quant-error; + qcom,mdss-dsi-fbc-bias = <0>; + qcom,mdss-dsi-fbc-pat-mode; + qcom,mdss-dsi-fbc-vlc-mode; + qcom,mdss-dsi-fbc-bflc-mode; + qcom,mdss-dsi-fbc-h-line-budget = <0>; + qcom,mdss-dsi-fbc-budget-ctrl = <0>; + qcom,mdss-dsi-fbc-block-budget = <0>; + qcom,mdss-dsi-fbc-lossless-threshold = <0>; + qcom,mdss-dsi-fbc-lossy-threshold = <0>; + qcom,mdss-dsi-fbc-rgb-threshold = <0>; + qcom,mdss-dsi-fbc-lossy-mode-idx = <0>; + qcom,mdss-dsi-fbc-max-pred-err = <2>; + qcom,mdss-dsi-h-front-porch = <140>; + qcom,mdss-dsi-h-back-porch = <164>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <1>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = < 15>; + qcom,mdss-brightness-max-level = <255>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-interleave-mode = <0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-qsync-min-refresh-rate = <30>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-hfp-power-mode; + qcom,mdss-dsi-hbp-power-mode; + qcom,mdss-dsi-hsa-power-mode; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-last-line-interleave; + qcom,mdss-dsi-traffic-mode = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-color-order = <0>; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x20>; + qcom,mdss-dsi-t-clk-pre = <0x2c>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-mdp-trigger = <0>; + qcom,mdss-dsi-dma-trigger = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 + 22 27 1e 03 04 00]; + qcom,mdss-dsi-panel-timings-8996 = [23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 2e 06 08 05 03 04 a0]; + qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; + qcom,min-refresh-rate = <30>; + qcom,max-refresh-rate = <60>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>; + qcom,5v-boost-gpio = <&pm8994_gpios 14 0>; + qcom,mdss-pan-physical-width-dimension = <60>; + qcom,mdss-pan-physical-height-dimension = <140>; + qcom,mdss-dsi-mode-sel-gpio-state = "dsc_mode"; + qcom,mdss-tear-check-sync-cfg-height = <0xfff0>; + qcom,mdss-tear-check-sync-init-val = <1280>; + qcom,mdss-tear-check-sync-threshold-start = <4>; + qcom,mdss-tear-check-sync-threshold-continue = <4>; + qcom,mdss-tear-check-start-pos = <1280>; + qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; + qcom,mdss-tear-check-frame-rate = <6000>; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <100>; + mdss-dsi-rx-eot-ignore; + mdss-dsi-tx-eot-append; + qcom,ulps-enabled; + qcom,suspend-ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-read-length = <8>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-panel-status-value = <0x1c 0x00 0x05 0x02 0x40 0x84 0x06 0x01>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + qcom,mdss-dsi-post-mode-switch-on-command = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 B0 03]; + qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B + 15 01 00 00 00 00 02 C2 08]; + qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03]; + qcom,send-pps-before-switch; + qcom,panel-ack-disabled; + qcom,mdss-dsi-horizontal-line-idle = <0 40 256>, + <40 120 128>, + <128 240 64>; + qcom,mdss-dsi-panel-orientation = "180" + qcom,mdss-dsi-panel-jitter = <0x8 0x10>; + qcom,mdss-dsi-panel-prefill-lines = <0x10>; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,compression-mode = "dsc"; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + wqhd { + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <728>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <424000000>; + qcom,mdss-mdp-transfer-time-us = <12500>; + qcom,mdss-dsi-panel-timings = [E6 38 26 00 68 6E 2A 3C 2C 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; + qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00 + 05 01 00 00 02 00 02 29 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 00 00 00 00 00 02 B0 04 + 29 00 00 00 00 00 02 F1 00]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-qsync-on-commands = [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = "dsi_hs_mode"; + + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <4 4 2 2 20 20>; + }; + }; + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2800000>; + qcom,supply-max-voltage = <2800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,dba-panel; + qcom,bridge-name = "adv7533"; + qcom,mdss-dsc-version = <0x11>; + qcom,mdss-dsc-scr-version = <0x1>; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <0>; + qcom,mdss-dsi-dma-schedule-line = <5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdss-pll.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdss-pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..a93529717d1c3cebaf167a91ce40c8279d8bfb50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/mdss-pll.txt @@ -0,0 +1,108 @@ +Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI + +mdss-pll is a pll controller device which supports pll devices that +are compatible with MIPI display serial interface specification, +HDMI and edp. + +Required properties: +- compatible: Compatible name used in the driver. Should be one of: + "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", + "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", + "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", + "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", + "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", + "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", + "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", + "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", + "qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8", + "qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998", + "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm", + "qcom,mdss_dsi_pll_7nm", "qcom,mdss_dp_pll_7nm", + "qcom,mdss_dsi_pll_28lpm", "qcom,mdss_dsi_pll_14nm", + "qcom,mdss_dp_pll_14nm", "qcom,mdss_dsi_pll_7nm_v2", + "qcom,mdss_hdmi_pll_28lpm","qcom,mdss_dsi_pll_7nm_v4_1", + "qcom,mdss_dp_pll_7nm_v2" +- cell-index: Specifies the controller used +- reg: offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- gdsc-supply: Phandle for gdsc regulator device node. +- vddio-supply: Phandle for vddio regulator device node. +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- clock-rate: List of clock rates in Hz. + +Optional properties: +- label: A string used to describe the driver used. +- vcca-supply: Phandle for vcca regulator device node. + + +- qcom,dsi-pll-ssc-en: Boolean property to indicate that ssc is enabled. +- qcom,dsi-pll-ssc-mode: Spread-spectrum clocking. It can be either "down-spread" + or "center-spread". Default is "down-spread" if it is not specified. +- qcom,ssc-frequency-hz: Integer property to specify the spread frequency + to be programmed for the SSC. +- qcom,ssc-ppm: Integer property to specify the Parts per Million + value of SSC. + +- qcom,platform-supply-entries: A node that lists the elements of the supply. There + can be more than one instance of this binding, + in which case the entry would be appended with + the supply entry index. + e.g. qcom,platform-supply-entry@0 + - reg: offset and length of the register set for the device. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +Example: + mdss_dsi0_pll: qcom,mdss_dsi_pll@fd922A00 { + compatible = "qcom,mdss_dsi_pll_8974"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + + reg = <0xfd922A00 0xD4>, + <0xfd922900 0x64>, + <0xfd8c2300 0x8>; + reg-names = "pll_base", "dynamic_pll_base", "gdsc_base"; + gdsc-supply = <&gdsc_mdss>; + vddio-supply = <&pm8941_l12>; + vcca-supply = <&pm8941_l28>; + + clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>, + <&clock_gcc clk_gcc_mdss_ahb_clk>, + <&clock_gcc clk_gcc_mdss_axi_clk>; + clock-names = "mdp_core_clk", "iface_clk", "bus_clk"; + clock-rate = <0>, <0>, <0>; + + qcom,dsi-pll-slave; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,ssc-frequency-hz = <30000>; + qcom,ssc-ppm = <5000>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-dp.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-dp.txt new file mode 100644 index 0000000000000000000000000000000000000000..78812304b88797319076eac673962bb197950623 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-dp.txt @@ -0,0 +1,237 @@ +Qualcomm Technologies, Inc. +sde-dp is the master Display Port device which supports DP host controllers that are compatible with VESA Display Port interface specification. +DP Controller: Required properties: +- compatible: Should be "qcom,dp-display". +- reg: Base address and length of DP hardware's memory mapped regions. +- reg-names: A list of strings that name the list of regs. "dp_ctrl" - DP controller memory region. + "dp_phy" - DP PHY memory region. + "dp_ln_tx0" - USB3 DP PHY combo TX-0 lane memory region. + "dp_ln_tx1" - USB3 DP PHY combo TX-1 lane memory region. + "dp_mmss_cc" - Display Clock Control memory region. + "qfprom_physical" - QFPROM Phys memory region. + "dp_pll" - USB3 DP combo PLL memory region. + "usb3_dp_com" - USB3 DP PHY combo memory region. + "hdcp_physical" - DP HDCP memory region. +- cell-index: Specifies the controller instance. +- clocks: Clocks required for Display Port operation. +- clock-names: Names of the clocks corresponding to handles. Following clocks are required: + "core_aux_clk", "core_usb_ref_clk_src","core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent". +- gdsc-supply: phandle to gdsc regulator node. +- vdda-1p2-supply: phandle to vdda 1.2V regulator node. +- vdda-0p9-supply: phandle to vdda 0.9V regulator node. +- interrupt-parent phandle to the interrupt parent device node. +- interrupts: The interrupt signal from the DSI block. +- qcom,aux-en-gpio: Specifies the aux-channel enable gpio. +- qcom,aux-sel-gpio: Specifies the aux-channel select gpio. +- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio. +- qcom,aux-cfg0-settings: Specifies the DP AUX configuration 0 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg1-settings: Specifies the DP AUX configuration 1 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg2-settings: Specifies the DP AUX configuration 2 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg3-settings: Specifies the DP AUX configuration 3 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg4-settings: Specifies the DP AUX configuration 4 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg5-settings: Specifies the DP AUX configuration 5 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg6-settings: Specifies the DP AUX configuration 6 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg7-settings: Specifies the DP AUX configuration 7 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg8-settings: Specifies the DP AUX configuration 8 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg9-settings: Specifies the DP AUX configuration 9 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port. +- qcom,mst-enable: MST feature enable control node. +- qcom,dsc-feature-enable: DSC feature enable control node. +- qcom,fec-feature-enable: FEC feature enable control node. +- qcom,max-dp-dsc-blks: An integer specifying the max. DSC blocks available for Display port. +- qcom,max-dp-dsc-input-width-pixs: An integer specifying the max. input width of pixels for each DSC block. +- qcom,dp-usbpd-detection: Phandle for the PMI regulator node for USB PHY PD detection. +- qcom,dp-aux-switch: Phandle for the driver used to program the AUX switch for Display Port orientation. +- qcom,dp-hpd-gpio: HPD gpio for direct DP connector without USB PHY or AUX switch. +- qcom,dp-gpio-aux-switch: Gpio DP AUX switch chipset support. +- qcom,-supply-entries: A node that lists the elements of the supply used by the a particular "type" of DSI module. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +msm_ext_disp is a device which manages the interaction between external +display interfaces, e.g. Display Port, and the audio subsystem. + +Optional properties: +- qcom,ext-disp: phandle for msm-ext-display module +- compatible: Must be "qcom,msm-ext-disp" +- qcom,dp-low-power-hw-hpd: Low power hardware HPD feature enable control node +- qcom,phy-version: Phy version +- qcom,pn-swap-lane-map: P/N swap configuration of each lane +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt +- qcom,max-lclk-frequency-khz: An integer specifying the max. link clock in KHz supported by Display Port. +- qcom,mst-fixed-topology-ports: u32 values of which MST output port to reserve, start from one + +[Optional child nodes]: These nodes are for devices which are +dependent on msm_ext_disp. If msm_ext_disp is disabled then +these devices will be disabled as well. Ex. Audio Codec device. + +- ext_disp_audio_codec: Node for Audio Codec. +- compatible : "qcom,msm-ext-disp-audio-codec-rx"; + +Example: + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + gdsc-supply = <&mdss_core_gdsc>; + vdda-1p2-supply = <&pm8998_l26>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xae90000 0xa84>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea030 0x10>, + <0x88e8000 0x621c>, + <0x0aee1000 0x034>; + reg-names = "dp_ctrl", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,dp-usbpd-detection = <&pm8150b_pdphy>; + qcom,ext-disp = <&ext_disp>; + qcom,phy-version = <0x420>; + qcom,dp-aux-switch = <&fsa4480>; + + qcom,aux-cfg0-settings = [1c 00]; + qcom,aux-cfg1-settings = [20 13 23 1d]; + qcom,aux-cfg2-settings = [24 00]; + qcom,aux-cfg3-settings = [28 00]; + qcom,aux-cfg4-settings = [2c 0a]; + qcom,aux-cfg5-settings = [30 26]; + qcom,aux-cfg6-settings = [34 0a]; + qcom,aux-cfg7-settings = [38 03]; + qcom,aux-cfg8-settings = [3c bb]; + qcom,aux-cfg9-settings = [40 03]; + qcom,max-pclk-frequency-khz = <593470>; + qcom,mst-enable; + qcom,dsc-feature-enable; + qcom,fec-feature-enable; + qcom,max-dp-dsc-blks = <2>; + qcom,max-dp-dsc-input-width-pixs = <2048>; + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 43 0>; + qcom,aux-sel-gpio = <&tlmm 51 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e09261d55b31af1a2352474d027c53db314e5f3a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-dsi.txt @@ -0,0 +1,118 @@ +Qualcomm Technologies, Inc. + +mdss-dsi is the master DSI device which supports multiple DSI host controllers +that are compatible with MIPI display serial interface specification. + +DSI Controller: +Required properties: +- compatible: Should be "qcom,dsi-ctrl-hw-v". Supported + versions include 1.4, 2.0 and 2.2. + eg: qcom,dsi-ctrl-hw-v1.4, qcom,dsi-ctrl-hw-v2.0, + qcom,dsi-ctrl-hw-v2.2, qcom,dsi-ctrl-hw-v2.3, + qcom,dsi-ctrl-hw-v2.4 + And for dsi phy driver: + qcom,dsi-phy-v0.0-hpm, qcom,dsi-phy-v0.0-lpm, + qcom,dsi-phy-v1.0, qcom,dsi-phy-v2.0, + qcom,dsi-phy-v3.0, qcom,dsi-phy-v4.0, qcom,dsi-phy-v4.1 +- reg: Base address and length of DSI controller's memory + mapped regions. +- reg-names: A list of strings that name the list of regs. + "dsi_ctrl" - DSI controller memory region. + "mmss_misc" - MMSS misc memory region. +- cell-index: Specifies the controller instance. +- clocks: Clocks required for DSI controller operation. +- clock-names: Names of the clocks corresponding to handles. Following + clocks are required: + "mdp_core_clk" + "iface_clk" + "core_mmss_clk" + "bus_clk" + "byte_clk" + "pixel_clk" + "core_clk" + "byte_clk_rcg" + "pixel_clk_rcg" +- gdsc-supply: phandle to gdsc regulator node. +- vdda-supply: phandle to vdda regulator node. +- vcca-supply: phandle to vcca regulator node. +- interrupt-parent phandle to the interrupt parent device node. +- interrupts: The interrupt signal from the DSI block. +- qcom,dsi-default-panel: Specifies the default panel. +- qcom,mdp: Specifies the mdp node which can find panel node from this. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the number of bus scaling use cases + defined in the vectors property. This must be + set to <2> for MDSS DSI driver where use-case 0 + is used to remove BW votes from the system. Use + case 1 is used to generate bandwidth requestes + when sending command packets. +- qcom,msm-bus,num-paths: This represents number of paths in each bus + scaling usecase. This value depends on number of + AXI master ports dedicated to MDSS for + particular chipset. +- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt. + DSI driver should always set average bandwidth + (ab) to 0 and always use instantaneous + bandwidth(ib) values. + +Optional properties: +- label: String to describe controller. +- qcom,platform-te-gpio: Specifies the gpio used for TE. +- qcom,panel-te-source: Specifies the source pin for Vsync from panel or WD Timer. +- qcom,dsi-ctrl: handle to dsi controller device +- qcom,dsi-phy: handle to dsi phy device +- qcom,dsi-ctrl-num: Specifies the DSI controllers to use for primary panel +- qcom,dsi-sec-ctrl-num: Specifies the DSI controllers to use for secondary panel +- qcom,dsi-phy-num: Specifies the DSI PHYs to use for primary panel +- qcom,dsi-sec-phy-num: Specifies the DSI PHYs to use for secondary panel +- qcom,dsi-select-clocks: Specifies the required clocks to use for primary panel +- qcom,dsi-select-sec-clocks: Specifies the required clocks to use for secondary panel +- qcom,dsi-display-list: Specifies the list of supported displays. +- qcom,dsi-manager: Specifies dsi manager is present +- qcom,dsi-display: Specifies dsi display is present +- qcom,hdmi-display: Specifies hdmi is present +- qcom,dp-display: Specified dp is present +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI module. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split enabled, this time should not be higher + than two times the dsi link rate time. + If the property is not specified, then the default value is 14000 us. +- qcom,dsi-phy-isolation-enabled: A boolean property enables the phy isolation from dsi + controller. This must be enabled for debugging purpose + only with simulator panel. It should not be enabled for + normal DSI panels. +- - qcom,null-insertion-enabled: A boolean to enable NULL packet insertion feature for DSI controller. +- ports: This video port is used when external bridge is present. + The connection is modeled using the OF graph bindings + specified in Documentation/devicetree/bindings/graph.txt. + Video port 0 reg 0 is for the bridge output. The remote + endpoint phandle should be mipi_dsi_device device node. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-rsc.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-rsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3af5629ca4670a1a821389ef0e4f56f7fb071622 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-rsc.txt @@ -0,0 +1,97 @@ +Qualcomm Technologies, Inc. SDE RSC + +Snapdragon Display Engine implements display rsc to driver +display core to different modes for power saving + +Required properties +- compatible: "qcom,sde-rsc" + "qcom,sde-rsc-rpmh" +- reg: Offset and length of the register set for + the device. +- reg-names: Names to refer to register sets related + to this device + +Optional properties: +- clocks: List of phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- vdd-supply: phandle for vdd regulator device node. +- qcom,sde-rsc-version: U32 property represents the rsc version. It helps to + select correct sequence for sde rsc based on version. +- qcom,sde-dram-channels: U32 property represents the number of channels in the + Bus memory controller. +- qcom,sde-num-nrt-paths: U32 property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports that are dedicated to non-realtime VBIF + for particular chipset. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. + +Bus Scaling Subnodes: +- qcom,sde-data-bus: Property to provide Bus scaling for data bus access for + sde blocks. +- qcom,sde-llcc-bus: Property to provide Bus scaling for data bus access for + mnoc to llcc. +- qcom,sde-ebi-bus: Property to provide Bus scaling for data bus access for + llcc to ebi. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing client name. +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex +- qcom,msm-bus,num-cases: This is the number of Bus Scaling use cases + defined in the vectors property. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h +Example: + sde_rscc { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + clocks = <&clock_mmss clk_mdss_ahb_clk>, + <&clock_mmss clk_mdss_axi_clk>; + clock-names = "iface_clk", "bus_clk"; + vdd-supply = <&gdsc_mdss>; + + qcom,sde-rsc-version = <1>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <1>; + + qcom,sde-data-bus { + qcom,msm-bus,name = "sde_rsc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; + qcom,sde-llcc-bus { + qcom,msm-bus,name = "sde_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + qcom,sde-ebi-bus { + qcom,msm-bus,name = "sde_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-wb.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-wb.txt new file mode 100644 index 0000000000000000000000000000000000000000..90093e41a917628ca681d7051cecdf775af3c090 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde-wb.txt @@ -0,0 +1,23 @@ +Qualcomm Technologies, Inc. Snapdragon Display Engine (SDE) writeback display + +Required properties: +- compatible: "qcom,wb-display" + +Optional properties: +- cell-index: Index of writeback device instance. + Default to 0 if not specified. +- label: String to describe this writeback display. + Default to "unknown" if not specified. + +Example: + +/ { + ... + + sde_wb: qcom,wb-display { + compatible = "qcom,wb-display"; + cell-index = <2>; + label = "wb_display"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde.txt b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4c6698514e8ac9d0cbbf4c5ca3f9082e9fd1d84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/qcom/sde.txt @@ -0,0 +1,888 @@ +Qualcomm Technologies, Inc. SDE KMS + +Snapdragon Display Engine implements Linux DRM/KMS APIs to drive user +interface to different panel interfaces. SDE driver is the core of +display subsystem which manage all data paths to different panel interfaces. + +Required properties +- compatible: Must be "qcom,sde-kms" +- compatible: "msm-hdmi-audio-codec-rx"; +- reg: Offset and length of the register set for the device. +- reg-names : Names to refer to register sets related to this device +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- mmagic-supply: Phandle for mmagic mdss supply regulator device node. +- vdd-supply: Phandle for vdd regulator device node. +- interrupt-parent: Must be core interrupt controller. +- interrupts: Interrupt associated with MDSS. +- interrupt-controller: Mark the device node as an interrupt controller. +- #interrupt-cells: Should be one. The first cell is interrupt number. +- iommus: Specifies the SID's used by this context bank. +- qcom,sde-sspp-type: Array of strings for SDE source surface pipes type information. + A source pipe can be "vig", "rgb", "dma" or "cursor" type. + Number of xin ids defined should match the number of offsets + defined in property: qcom,sde-sspp-off. +- qcom,sde-sspp-off: Array of offset for SDE source surface pipes. The offsets + are calculated from register "mdp_phys" defined in + reg property + "sde-off". The number of offsets defined here should + reflect the amount of pipes that can be active in SDE for + this configuration. +- qcom,sde-sspp-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective source pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,sde-sspp-off. +- qcom,sde-ctl-off: Array of offset addresses for the available ctl + hw blocks within SDE, these offsets are + calculated from register "mdp_phys" defined in + reg property. The number of ctl offsets defined + here should reflect the number of control paths + that can be configured concurrently on SDE for + this configuration. +- qcom,sde-wb-off: Array of offset addresses for the programmable + writeback blocks within SDE. +- qcom,sde-wb-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective writeback. Number of xin ids + defined should match the number of offsets + defined in property: qcom,sde-wb-off. +- qcom,sde-mixer-off: Array of offset addresses for the available + mixer blocks that can drive data to panel + interfaces. These offsets are be calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined should reflect the + amount of mixers that can drive data to a panel + interface. +- qcom,sde-dspp-top-off: Offset address for the dspp top block. + The offset is calculated from register "mdp_phys" + defined in reg property. +- qcom,sde-dspp-off: Array of offset addresses for the available dspp + blocks. These offsets are calculated from + register "mdp_phys" defined in reg property. +- qcom,sde-pp-off: Array of offset addresses for the available + pingpong blocks. These offsets are calculated + from register "mdp_phys" defined in reg property. +- qcom,sde-pp-slave: Array of flags indicating whether each ping pong + block may be configured as a pp slave. +- qcom,sde-pp-merge-3d-id: Array of index ID values for the merge 3d block + connected to each pingpong, starting at 0. +- qcom,sde-merge-3d-off: Array of offset addresses for the available + merge 3d blocks. These offsets are calculated + from register "mdp_phys" defined in reg property. +- qcom,sde-intf-off: Array of offset addresses for the available SDE + interface blocks that can drive data to a + panel controller. The offsets are calculated + from "mdp_phys" defined in reg property. The number + of offsets defined should reflect the number of + programmable interface blocks available in hardware. +- qcom,sde-mixer-blend-op-off Array of offset addresses for the available + blending stages. The offsets are relative to + qcom,sde-mixer-off. +- qcom,sde-mixer-pair-mask Array of mixer numbers that can be paired with + mixer number corresponding to the array index. + +Optional properties: +- clock-rate: List of clock rates in Hz. +- clock-max-rate: List of maximum clock rate in Hz that this device supports. +- qcom,platform-supply-entries: A node that lists the elements of the supply. There + can be more than one instance of this binding, + in which case the entry would be appended with + the supply entry index. + e.g. qcom,platform-supply-entry@0 + -- reg: offset and length of the register set for the device. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- qcom,sde-sspp-src-size: A u32 value indicates the address range for each sspp. +- qcom,sde-mixer-size: A u32 value indicates the address range for each mixer. +- qcom,sde-ctl-size: A u32 value indicates the address range for each ctl. +- qcom,sde-dspp-size: A u32 value indicates the address range for each dspp. +- qcom,sde-intf-size: A u32 value indicates the address range for each intf. +- qcom,sde-dsc-size: A u32 value indicates the address range for each dsc. +- qcom,sde-cdm-size: A u32 value indicates the address range for each cdm. +- qcom,sde-pp-size: A u32 value indicates the address range for each pingpong. +- qcom,sde-merge-3d-size: A u32 value indicates the address range for each merge 3d. +- qcom,sde-wb-size: A u32 value indicates the address range for each writeback. +- qcom,sde-len: A u32 entry for SDE address range. +- qcom,sde-intf-max-prefetch-lines: Array of u32 values for max prefetch lines on + each interface. +- qcom,sde-sspp-linewidth: A u32 value indicates the max sspp line width. +- qcom,sde-mixer-linewidth: A u32 value indicates the max mixer line width. +- qcom,sde-wb-linewidth: A u32 value indicates the max writeback line width. +- qcom,sde-sspp-scale-size: A u32 value indicates the scaling block size on sspp. +- qcom,sde-mixer-blendstages: A u32 value indicates the max mixer blend stages for + alpha blending. +- qcom,sde-qseed-type: A string entry indiates qseed support on sspp and wb. + It supports "qssedv3" and "qseedv2" entries for qseed + type. By default "qseedv2" is used if this optional property + is not defined. +- qcom,sde-csc-type: A string entry indicates csc support on sspp and wb. + It supports "csc" and "csc-10bit" entries for csc + type. +- qcom,sde-highest-bank-bit: A u32 property to indicate GPU/Camera/Video highest memory + bank bit used for tile format buffers. +- qcom,sde-ubwc-version: Property to specify the UBWC feature version. +- qcom,sde-ubwc-static: Property to specify the default UBWC static + configuration value. +- qcom,sde-ubwc-bw-calc-version: A u32 property to specify version of UBWC bandwidth + calculation algorithm +- qcom,sde-ubwc-swizzle: Property to specify the default UBWC swizzle + configuration value. +- qcom,sde-smart-panel-align-mode: A u32 property to specify the align mode for + split display on smart panel. Possible values: + 0x0 - no alignment + 0xc - align at start of frame + 0xd - align at start of line +- qcom,sde-panic-per-pipe: Boolean property to indicate if panic signal + control feature is available on each source pipe. +- qcom,sde-has-src-split: Boolean property to indicate if source split + feature is available or not. +- qcom,sde-has-dim-layer: Boolean property to indicate if mixer has dim layer + feature is available or not. +- qcom,sde-has-idle-pc: Boolean property to indicate if target has idle + power collapse feature available or not. +- qcom,fullsize-va-map: Boolean property to indicate smmu mapping range + for mdp should be full range (4GB). +- qcom,sde-has-mixer-gc: Boolean property to indicate if mixer has gamma correction + feature available or not. +- qcom,sde-has-dest-scaler: Boolean property to indicate if destination scaler + feature is available or not. +- qcom,sde-max-dest-scaler-input-linewidth: A u32 value indicates the + maximum input line width to destination scaler. +- qcom,sde-max-dest-scaler-output-linewidth: A u32 value indicates the + maximum output line width of destination scaler. +- qcom,sde-dest-scaler-top-off: A u32 value provides the + offset from mdp base to destination scaler block. +- qcom,sde-dest-scaler-top-size: A u32 value indicates the address range for ds top +- qcom,sde-dest-scaler-off: Array of u32 offsets indicate the qseed3 scaler blocks + offset from destination scaler top offset. +- qcom,sde-dest-scaler-size: A u32 value indicates the address range for each scaler block +- qcom,sde-sspp-clk-ctrl: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of offsets defined in + property: qcom,sde-sspp-off +- qcom,sde-sspp-clk-status: Array of offsets describing clk status + offsets for dynamic clock gating. 1st value + in the array represents offset of the status + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of offsets defined in + property: qcom,sde-sspp-off. +- qcom,sde-sspp-excl-rect: Array of u32 values indicating exclusion rectangle + support on each sspp. +- qcom,sde-sspp-smart-dma-priority: Array of u32 values indicating hw pipe + priority of secondary rectangles when smart dma + is supported. Number of priority values should + match the number of offsets defined in + qcom,sde-sspp-off node. Zero indicates no support + for smart dma for the sspp. +- qcom,sde-smart-dma-rev: A string entry indicating the smart dma version + supported on the device. Supported entries are + "smart_dma_v1" and "smart_dma_v2". +- qcom,sde-intf-type: Array of string provides the interface type information. + Possible string values + "dsi" - dsi display interface + "dp" - Display Port interface + "hdmi" - HDMI display interface + An interface is considered as "none" if interface type + is not defined. +- qcom,sde-off: SDE offset from "mdp_phys" defined in reg property. +- qcom,sde-cdm-off: Array of offset addresses for the available + cdm blocks. These offsets will be calculated from + register "mdp_phys" defined in reg property. +- qcom,sde-vbif-off: Array of offset addresses for the available + vbif blocks. These offsets will be calculated from + register "vbif_phys" defined in reg property. +- qcom,sde-vbif-size: A u32 value indicates the vbif block address range. +- qcom,sde-uidle-off: A u32 value with the offset for the uidle + block, from the "mdp_phys". +- qcom,sde-uidle-size: A u32 value indicates the uidle block address range. +- qcom,sde-te-off: A u32 offset indicates the te block offset on pingpong. + This offset is 0x0 by default. +- qcom,sde-te2-off: A u32 offset indicates the te2 block offset on pingpong. +- qcom,sde-te-size: A u32 value indicates the te block address range. +- qcom,sde-te2-size: A u32 value indicates the te2 block address range. +- qcom,sde-dsc-off: A u32 offset indicates the dsc block offset on pingpong. +- qcom,sde-qdss-off: A u32 offset indicates the qdss block offset. +- qcom,sde-dither-off: A u32 offset indicates the dither block offset on pingpong. +- qcom,sde-dither-version: A u32 value indicates the dither block version. +- qcom,sde-dither-size: A u32 value indicates the dither block address range. +- qcom,sde-sspp-vig-blocks: A node that lists the blocks inside the VIG hardware. The + block entries will contain the offset and version (if needed) + of each feature block. The presence of a block entry + indicates that the SSPP VIG contains that feature hardware. + e.g. qcom,sde-sspp-vig-blocks + -- qcom,sde-vig-csc-off: offset of CSC hardware + -- qcom,sde-vig-qseed-off: offset of QSEED hardware + -- qcom,sde-vig-qseed-size: A u32 address range for qseed scaler. + -- qcom,sde-vig-pcc: offset and version of PCC hardware + -- qcom,sde-vig-hsic: offset and version of global PA adjustment + -- qcom,sde-vig-memcolor: offset and version of PA memcolor hardware + -- qcom,sde-vig-gamut: offset and version of 3D LUT Gamut hardware + -- qcom,sde-vig-igc: offset and version of 1D LUT IGC hardware + -- qcom,sde-vig-inverse-pma: Boolean property to indicate if + inverse PMA feature is available on VIG pipe +- qcom,sde-sspp-dma-blocks: A node that lists the blocks inside the DMA hardware. There + can be more than one instance of this binding, in which case the + entry would be appended with dgm entry index. Each entry will + contain the offset and version (if needed) of each feature block. + The presence of a block entry indicates that the SSPP DMA contains + that feature hardware. + e.g. qcom,sde-sspp-dma-blocks + -- dgm@0 + -- qcom,sde-dma-igc: offset and version of DMA IGC + -- qcom,sde-dma-gc: offset and version of DMA GC + -- qcom,sde-dma-inverse-pma: Boolean property to indicate if + inverse PMA feature is available on DMA pipe + -- qcom,sde-dma-csc-off: offset of CSC hardware +- qcom,sde-sspp-rgb-blocks: A node that lists the blocks inside the RGB hardware. The + block entries will contain the offset and version (if needed) + of each feature block. The presence of a block entry + indicates that the SSPP RGB contains that feature hardware. + e.g. qcom,sde-sspp-rgb-blocks + -- qcom,sde-rgb-scaler-off: offset of RGB scaler hardware + -- qcom,sde-rgb-scaler-size: A u32 address range for scaler. + -- qcom,sde-rgb-pcc: offset and version of PCC hardware +- qcom,sde-dspp-blocks: A node that lists the blocks inside the DSPP hardware. The + block entries will contain the offset and version of each + feature block. The presence of a block entry indicates that + the DSPP contains that feature hardware. + e.g. qcom,sde-dspp-blocks + -- qcom,sde-dspp-pcc: offset and version of PCC hardware + -- qcom,sde-dspp-gc: offset and version of GC hardware + -- qcom,sde-dspp-igc: offset and version of IGC hardware + -- qcom,sde-dspp-hsic: offset and version of global PA adjustment + -- qcom,sde-dspp-memcolor: offset and version of PA memcolor hardware + -- qcom,sde-dspp-sixzone: offset and version of PA sixzone hardware + -- qcom,sde-dspp-gamut: offset and version of Gamut mapping hardware + -- qcom,sde-dspp-dither: offset and version of dither hardware + -- qcom,sde-dspp-hist: offset and version of histogram hardware + -- qcom,sde-dspp-vlut: offset and version of PA vLUT hardware +- qcom,sde-mixer-blocks: A node that lists the blocks inside the layer mixer hardware. The + block entries will contain the offset and version (if needed) + of each feature block. The presence of a block entry + indicates that the layer mixer contains that feature hardware. + e.g. qcom,sde-mixer-blocks + -- qcom,sde-mixer-gc: offset and version of mixer GC hardware +- qcom,sde-dspp-ad-off: Array of u32 offsets indicate the ad block offset from the + DSPP offset. Since AD hardware is represented as part of + DSPP block, the AD offsets must be offset from the + corresponding DSPP base. +- qcom,sde-dspp-ad-version A u32 value indicating the version of the AD hardware +- qcom,sde-dspp-ltm-version A u32 value indicating the major(upper 16 bits) and minor(lower 16 bits) + version of the LTM hardware +- qcom,sde-dspp-ltm-off: Array of u32 offsets indicate the LTM block offsets from the + DSPP offsets. Since LTM hardware is represented as part of + DSPP block, the LTM offsets are calculated based on the + corresponding DSPP base. +- qcom,sde-vbif-id: Array of vbif ids corresponding to the + offsets defined in property: qcom,sde-vbif-off. +- qcom,sde-vbif-default-ot-rd-limit: A u32 value indicates the default read OT limit +- qcom,sde-vbif-default-ot-wr-limit: A u32 value indicates the default write OT limit +- qcom,sde-vbif-dynamic-ot-rd-limit: A series of 2 cell property, with a format + of (pps, OT limit), where pps is pixel per second and + OT limit is the read limit to apply if the given + pps is not exceeded. +- qcom,sde-vbif-dynamic-ot-wr-limit: A series of 2 cell property, with a format + of (pps, OT limit), where pps is pixel per second and + OT limit is the write limit to apply if the given + pps is not exceeded. +- qcom,sde-vbif-memtype-0: Array of u32 vbif memory type settings, group 0 +- qcom,sde-vbif-memtype-1: Array of u32 vbif memory type settings, group 1 +- qcom,sde-wb-id: Array of writeback ids corresponding to the + offsets defined in property: qcom,sde-wb-off. +- qcom,sde-wb-clk-ctrl: Array of 2 cell property describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of offsets defined in + property: qcom,sde-wb-off +- qcom,sde-reg-dma-off: Offset of the register dma hardware block from + "regdma_phys" defined in reg property. +- qcom,sde-reg-dma-version: Version of the reg dma hardware block. +- qcom,sde-reg-dma-trigger-off: Offset of the lut dma trigger reg from "mdp_phys" + defined in reg property. +- qcom,sde-reg-dma-broadcast-disabled: Boolean property to indicate if broadcast + functionality in the register dma hardware block should be used. +- qcom,sde-reg-dma-xin-id: VBIF clients id (xin) corresponding + to the LUTDMA block. +- qcom,sde-reg-dma-clk-ctrl: Array of 2 cell property describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. +- qcom,sde-dram-channels: This represents the number of channels in the + Bus memory controller. +- qcom,sde-num-nrt-paths: Integer property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports that are dedicated to non-realtime VBIF + for particular chipset. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. +- qcom,sde-max-bw-low-kbps: This value indicates the max bandwidth in Kbps + that can be supported without underflow. + This is a low bandwidth threshold which should + be applied in most scenarios to be safe from + underflows when unable to satisfy bandwidth + requirements. +- qcom,sde-max-bw-high-kbps: This value indicates the max bandwidth in Kbps + that can be supported without underflow in the + event where there is no VFE. + This is a high bandwidth threshold which can be + applied in scenarios where panel interface can + be more tolerant to memory latency such as + command mode panels. +- qcom,sde-core-ib-ff: A string entry indicating the fudge factor for + core ib calculation. +- qcom,sde-core-clk-ff: A string entry indicating the fudge factor for + core clock calculation. +- qcom,sde-min-core-ib-kbps: This u32 value indicates the minimum mnoc ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-min-llcc-ib-kbps: This u32 value indicates the minimum llcc ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-min-dram-ib-kbps: This u32 value indicates the minimum dram ib + vote in Kbps that can be reduced without hitting underflow. + BW calculation logic will choose the IB bandwidth requirement + based on usecase if this floor value is not defined. +- qcom,sde-comp-ratio-rt: A string entry indicating the compression ratio + for each supported compressed format on realtime interface. + The string is composed of one or more of + /// + separated with spaces. +- qcom,sde-comp-ratio-nrt: A string entry indicating the compression ratio + for each supported compressed format on non-realtime interface. + The string is composed of one or more of + /// + separated with spaces. +- qcom,sde-undersized-prefill-lines: A u32 value indicates the size of undersized prefill in lines. +- qcom,sde-xtra-prefill-lines: A u32 value indicates the extra prefill in lines. +- qcom,sde-dest-scale-prefill-lines: A u32 value indicates the latency of destination scaler in lines. +- qcom,sde-macrotile-prefill-lines: A u32 value indicates the latency of macrotile in lines. +- qcom,sde-yuv-nv12-prefill-lines: A u32 value indicates the latency of yuv/nv12 in lines. +- qcom,sde-linear-prefill-lines: A u32 value indicates the latency of linear in lines. +- qcom,sde-downscaling-prefill-lines: A u32 value indicates the latency of downscaling in lines. +- qcom,sde-max-per-pipe-bw-kbps: Array of u32 value indicates the max per pipe bandwidth in Kbps. +- qcom,sde-amortizable-threshold: This value indicates the min for traffic shaping in lines. +- qcom,sde-vbif-qos-rt-remap: This array is used to program vbif qos remapper register + priority for realtime clients. +- qcom,sde-vbif-qos-nrt-remap: This array is used to program vbif qos remapper register + priority for non-realtime clients. +- qcom,sde-vbif-qos-cwb-remap: This array is used to program vbif qos remapper register + priority for concurrent writeback clients. +- qcom,sde-vbif-qos-lutdma-remap: This array is used to program vbif qos remapper register + priority for lutdma client. +- qcom,sde-danger-lut: Array of 5 cell property, with a format of + , + indicating the danger luts on sspp. +- qcom,sde-safe-lut-linear: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for linear format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-macrotile: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for macrotile format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-macrotile-qseed: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for macrotile format + with qseed3 on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-nrt: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for nrt (e.g wfd) on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-safe-lut-cwb: Array of 2 cell property, with a format of + in ascending fill level + indicating the safe luts for cwb on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-linear: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for linear format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-macrotile: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for macrotile format on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-macrotile-qseed: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for macrotile format + with qseed3 enabled on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-nrt: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for nrt (e.g wfd) on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-qos-lut-cwb: Array of 3 cell property, with a format of + in ascending fill level + indicating the qos luts for cwb on sspp. + Zero fill level on the last entry identifies the default lut. +- qcom,sde-cdp-setting: Array of 2 cell property, with a format of + for cdp use cases in + order of , and . +- qcom,sde-qos-cpu-mask: A u32 value indicating desired PM QoS CPU affine mask. +- qcom,sde-qos-cpu-dma-latency: A u32 value indicating desired PM QoS CPU DMA latency in usec. +- qcom,sde-inline-rot-xin: An integer array of xin-ids related to inline + rotation. +- qcom,sde-inline-rot-xin-type: A string array indicating the type of xin, + namely sspp or wb. Number of entries should match + the number of xin-ids defined in + property: qcom,sde-inline-rot-xin +- qcom,sde-inline-rot-clk-ctrl: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register. Number of offsets defined should + match the number of xin-ids defined in + property: qcom,sde-inline-rot-xin +- qcom,sde-secure-sid-mask: Array of secure SID masks used during + secure-camera/secure-display usecases. +- #power-domain-cells: Number of cells in a power-domain specifier and should contain 0. +- #list-cells: Number of mdp cells, must be 1. +- qcom,sde-mixer-display-pref: A string array indicating the preferred display type + for the mixer block. Possible values: + "primary" - preferred for primary display + "none" - no preference on display +- qcom,sde-mixer-cwb-pref: A string array indicating the preferred mixer block. + for CWB. Possible values: + "cwb" - preferred for cwb + "none" - no preference on display +- qcom,sde-ctl-display-pref: A string array indicating the preferred display type + for the ctl block. Possible values: + "primary" - preferred for primary display + "none" - no preference on display +- qcom,sde-pipe-order-version: A u32 property to indicate version of pipe + ordering block + 0: lower priority pipe has to be on the left for a given pair of pipes. + 1: priority have to be explicitly configured for a given pair of pipes. + +Bus Scaling Subnodes: +- qcom,sde-reg-bus: Property to provide Bus scaling for register access for + mdss blocks. +- qcom,sde-data-bus: Property to provide Bus scaling for data bus access for + mdss blocks. +- qcom,sde-llcc-bus: Property to provide Bus scaling for data bus access for + mnoc to llcc. +- qcom,sde-ebi-bus: Property to provide Bus scaling for data bus access for + llcc to ebi. + +- qcom,sde-inline-rotator: A 2 cell property, with format of (rotator phandle, + instance id), of inline rotator device. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing client name. +- qcom,msm-bus,num-cases: This is the number of Bus Scaling use cases + defined in the vectors property. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + +SMMU Subnodes: +- smmu_sde_****: Child nodes representing sde smmu virtual + devices + +Subnode properties: +- compatible: Compatible names used for smmu devices. + names should be: + "qcom,smmu_sde_unsec": smmu context bank device + for unsecure sde real time domain. + "qcom,smmu_sde_sec": smmu context bank device + for secure sde real time domain. + "qcom,smmu_sde_nrt_unsec": smmu context bank device + for unsecure sde non-real time domain. + "qcom,smmu_sde_nrt_sec": smmu context bank device + for secure sde non-real time domain. + + +Please refer to ../../interrupt-controller/interrupts.txt for a general +description of interrupt bindings. + +Example: + mdss_mdp: qcom,mdss_mdp@900000 { + compatible = "qcom,sde-kms"; + reg = <0x00900000 0x90000>, + <0x009b0000 0x1040>, + <0x009b8000 0x1040>, + <0x0aeac000 0x00f0>; + reg-names = "mdp_phys", + "vbif_phys", + "vbif_nrt_phys", + "regdma_phys"; + clocks = <&clock_mmss clk_mdss_ahb_clk>, + <&clock_mmss clk_mdss_axi_clk>, + <&clock_mmss clk_mdp_clk_src>, + <&clock_mmss clk_mdss_mdp_vote_clk>, + <&clock_mmss clk_smmu_mdp_axi_clk>, + <&clock_mmss clk_mmagic_mdss_axi_clk>, + <&clock_mmss clk_mdss_vsync_clk>; + clock-names = "iface_clk", + "bus_clk", + "core_clk_src", + "core_clk", + "iommu_clk", + "mmagic_clk", + "vsync_clk"; + clock-rate = <0>, <0>, <0>; + clock-max-rate= <0 320000000 0>; + mmagic-supply = <&gdsc_mmagic_mdss>; + vdd-supply = <&gdsc_mdss>; + interrupt-parent = <&intc>; + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&mdp_smmu 0>; + #power-domain-cells = <0>; + + qcom,sde-off = <0x1000>; + qcom,sde-ctl-off = <0x00002000 0x00002200 0x00002400 + 0x00002600 0x00002800>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + qcom,sde-mixer-off = <0x00045000 0x00046000 + 0x00047000 0x0004a000>; + qcom,sde-mixer-display-pref = "primary", "none", + "none", "none"; + qcom,sde-mixer-cwb-pref = "none", "none", + "cwb", "none"; + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-off = <0x00055000 0x00057000>; + qcom,sde-dspp-ad-off = <0x24000 0x22800>; + qcom,sde-dspp-ad-version = <0x00030000>; + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-wb-off = <0x00066000>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-intf-off = <0x0006b000 0x0006b800 + 0x0006c000 0x0006c800>; + qcom,sde-intf-type = "none", "dsi", "dsi", "hdmi"; + qcom,sde-pp-off = <0x00071000 0x00071800 + 0x00072000 0x00072800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0>; + qcom,sde-cdm-off = <0x0007a200>; + qcom,sde-dsc-off = <0x00081000 0x00081400>; + qcom,sde-intf-max-prefetch-lines = <0x15 0x15 0x15 0x15>; + + qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>; + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-qdss-off = <0x81a00>; + + qcom,sde-sspp-type = "vig", "vig", "vig", + "vig", "rgb", "rgb", + "rgb", "rgb", "dma", + "dma", "cursor", "cursor"; + + qcom,sde-sspp-off = <0x00005000 0x00007000 0x00009000 + 0x0000b000 0x00015000 0x00017000 + 0x00019000 0x0001b000 0x00025000 + 0x00027000 0x00035000 0x00037000>; + + qcom,sde-sspp-xin-id = <0 4 8 + 12 1 5 + 9 13 2 + 10 7 7>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, + <0x2c4 0>, <0x2ac 4>, <0x2b4 4>, <0x2bc 4>, + <0x2c4 4>, <0x2ac 8>, <0x2b4 8>, <0x3a8 16>, + <0x3b0 16>; + qcom,sde-sspp-clk-status = <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, + <0x2c4 0>, <0x2ac 4>, <0x2b4 4>, <0x2bc 4>, + <0x2c4 4>, <0x2ac 8>, <0x2b4 8>, <0x3a8 16>, + <0x3b0 16>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2560>; + qcom,sde-mixer-blendstages = <0x7>; + qcom,sde-highest-bank-bit = <0x2>; + qcom,sde-ubwc-version = <0x100>; + qcom,sde-ubwc-static = <0x100>; + qcom,sde-ubwc-swizzle = <0>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-smart-panel-align-mode = <0xd>; + qcom,sde-panic-per-pipe; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-sspp-src-size = <0x100>; + qcom,sde-mixer-size = <0x100>; + qcom,sde-ctl-size = <0x100>; + qcom,sde-dspp-top-size = <0xc>; + qcom,sde-dspp-size = <0x100>; + qcom,sde-intf-size = <0x100>; + qcom,sde-dsc-size = <0x100>; + qcom,sde-cdm-size = <0x100>; + qcom,sde-pp-size = <0x100>; + qcom,sde-wb-size = <0x100>; + qcom,sde-dest-scaler-top-size = <0xc>; + qcom,sde-dest-scaler-size = <0x800>; + qcom,sde-len = <0x100>; + qcom,sde-wb-linewidth = <2560>; + qcom,sde-sspp-scale-size = <0x100>; + qcom,sde-mixer-blendstages = <0x8>; + qcom,sde-qseed-type = "qseedv2"; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-highest-bank-bit = <15>; + qcom,sde-has-mixer-gc; + qcom,sde-has-idle-pc; + qcom,fullsize-va-map; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-sspp-max-rects = <1 1 1 1 + 1 1 1 1 + 1 1 + 1 1>; + qcom,sde-sspp-excl-rect = <1 1 1 1 + 1 1 1 1 + 1 1 + 1 1>; + qcom,sde-sspp-smart-dma-priority = <0 0 0 0 + 0 0 0 0 + 0 0 + 1 2>; + qcom,sde-smart-dma-rev = "smart_dma_v2"; + qcom,sde-te-off = <0x100>; + qcom,sde-te2-off = <0x100>; + qcom,sde-te-size = <0xffff>; + qcom,sde-te2-size = <0xffff>; + + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x2bc 16>; + + qcom,sde-danger-lut = <0x0000000f 0x0000ffff 0x00000000 + 0x00000000 0x0000ffff>; + qcom,sde-safe-lut-linear = <0 0xfff8>; + qcom,sde-safe-lut-macrotile = <0 0xf000>; + qcom,sde-safe-lut-macrotile-qseed = <0 0xf000>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0xffff>; + + qcom,sde-qos-lut-linear = + <4 0x00000000 0x00000357>, + <5 0x00000000 0x00003357>, + <6 0x00000000 0x00023357>, + <7 0x00000000 0x00223357>, + <8 0x00000000 0x02223357>, + <9 0x00000000 0x22223357>, + <10 0x00000002 0x22223357>, + <11 0x00000022 0x22223357>, + <12 0x00000222 0x22223357>, + <13 0x00002222 0x22223357>, + <14 0x00012222 0x22223357>, + <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = + <10 0x00000003 0x44556677>, + <11 0x00000033 0x44556677>, + <12 0x00000233 0x44556677>, + <13 0x00002233 0x44556677>, + <14 0x00012233 0x44556677>, + <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = + <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = + <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + qcom,sde-vbif-off = <0 0>; + qcom,sde-vbif-id = <0 1>; + qcom,sde-vbif-default-ot-rd-limit = <32>; + qcom,sde-vbif-default-ot-wr-limit = <16>; + qcom,sde-vbif-dynamic-ot-rd-limit = <62208000 2>, + <124416000 4>, <248832000 16>; + qcom,sde-vbif-dynamic-ot-wr-limit = <62208000 2>, + <124416000 4>, <248832000 16>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-uidle-off = <0x80000>; + qcom,sde-uidle-size = <0x70>; + + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <1>; + + qcom,sde-max-bw-high-kbps = <9000000>; + qcom,sde-max-bw-low-kbps = <9000000>; + + qcom,sde-core-ib-ff = "1.1"; + qcom,sde-core-clk-ff = "1.0"; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-comp-ratio-rt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3"; + qcom,sde-comp-ratio-nrt = "NV12/5/1/1.1 AB24/5/1/1.2 XB24/5/1/1.3"; + qcom,sde-undersized-prefill-lines = <4>; + qcom,sde-xtra-prefill-lines = <5>; + qcom,sde-dest-scale-prefill-lines = <6>; + qcom,sde-macrotile-prefill-lines = <7>; + qcom,sde-yuv-nv12-prefill-lines = <8>; + qcom,sde-linear-prefill-lines = <9>; + qcom,sde-downscaling-prefill-lines = <10>; + qcom,sde-max-per-pipe-bw-kbps = <2400000 2400000 2400000 2400000 + 2400000 2400000 2400000 2400000>; + qcom,sde-amortizable-threshold = <11>; + qcom,sde-secure-sid-mask = <0x200801 0x200c01>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-qos-cwb-remap = <3 3 4 4 5 5 6 3>; + qcom,sde-vbif-qos-lutdma-remap = <3 3 3 3 4 4 4 4>; + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010002>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + qcom,sde-reg-dma-broadcast-disabled = <0>; + qcom,sde-reg-dma-xin-id = <7>; + qcom,sde-reg-dma-clk-ctrl = <0x2bc 20>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x320>; + qcom,sde-vig-qseed-off = <0x200>; + qcom,sde-vig-qseed-size = <0x74>; + /* Offset from vig top, version of HSIC */ + qcom,sde-vig-hsic = <0x200 0x00010000>; + qcom,sde-vig-memcolor = <0x200 0x00010000>; + qcom,sde-vig-pcc = <0x1780 0x00010000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + } + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + } + }; + + qcom,sde-sspp-rgb-blocks { + qcom,sde-rgb-scaler-off = <0x200>; + qcom,sde-rgb-scaler-size = <0x74>; + qcom,sde-rgb-pcc = <0x380 0x00010000>; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00010000>; + qcom,sde-dspp-pcc = <0x1700 0x00010000>; + qcom,sde-dspp-gc = <0x17c0 0x00010000>; + qcom,sde-dspp-hsic = <0x0 0x00010000>; + qcom,sde-dspp-memcolor = <0x0 0x00010000>; + qcom,sde-dspp-sixzone = <0x0 0x00010000>; + qcom,sde-dspp-gamut = <0x1600 0x00010000>; + qcom,sde-dspp-dither = <0x0 0x00010000>; + qcom,sde-dspp-hist = <0x0 0x00010000>; + qcom,sde-dspp-vlut = <0x0 0x00010000>; + }; + + qcom,sde-mixer-blocks { + qcom,sde-mixer-gc = <0x3c0 0x00010000>; + }; + + qcom,msm-hdmi-audio-rx { + compatible = "qcom,msm-hdmi-audio-codec-rx"; + }; + + qcom,sde-inline-rotator = <&mdss_rotator 0>; + qcom,sde-inline-rot-xin = <10 11>; + qcom,sde-inline-rot-xin-type = "sspp", "wb"; + qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, <25 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <25 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>, + <25 512 0 6400000>; + }; + qcom,sde-llcc-bus { + qcom,msm-bus,name = "mdss_sde_llcc"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <132 770 0 0>, + <132 770 0 6400000>, + <132 770 0 6400000>; + }; + qcom,sde-ebi-bus { + qcom,msm-bus,name = "mdss_sde_ebi"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 6400000>, + <129 512 0 6400000>; + }; + + qcom,sde-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + + smmu_kms_unsec: qcom,smmu_kms_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&mmss_smmu 0>; + }; + + smmu_kms_sec: qcom,smmu_kms_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&mmss_smmu 1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/renesas,du.txt b/arch/arm64/boot/dts/vendor/bindings/display/renesas,du.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec9d34be2ff76974cf0a69825868d17722a76f51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/renesas,du.txt @@ -0,0 +1,110 @@ +* Renesas R-Car Display Unit (DU) + +Required Properties: + + - compatible: must be one of the following. + - "renesas,du-r8a7743" for R8A7743 (RZ/G1M) compatible DU + - "renesas,du-r8a7745" for R8A7745 (RZ/G1E) compatible DU + - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU + - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU + - "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU + - "renesas,du-r8a7792" for R8A7792 (R-Car V2H) compatible DU + - "renesas,du-r8a7793" for R8A7793 (R-Car M2-N) compatible DU + - "renesas,du-r8a7794" for R8A7794 (R-Car E2) compatible DU + - "renesas,du-r8a7795" for R8A7795 (R-Car H3) compatible DU + - "renesas,du-r8a7796" for R8A7796 (R-Car M3-W) compatible DU + - "renesas,du-r8a77965" for R8A77965 (R-Car M3-N) compatible DU + - "renesas,du-r8a77970" for R8A77970 (R-Car V3M) compatible DU + - "renesas,du-r8a77995" for R8A77995 (R-Car D3) compatible DU + + - reg: the memory-mapped I/O registers base address and length + + - interrupts: Interrupt specifiers for the DU interrupts. + + - clocks: A list of phandles + clock-specifier pairs, one for each entry in + the clock-names property. + - clock-names: Name of the clocks. This property is model-dependent. + - R8A7779 uses a single functional clock. The clock doesn't need to be + named. + - All other DU instances use one functional clock per channel The + functional clocks must be named "du.x" with "x" being the channel + numerical index. + - In addition to the functional clocks, all DU versions also support + externally supplied pixel clocks. Those clocks are optional. When + supplied they must be named "dclkin.x" with "x" being the input clock + numerical index. + + - vsps: A list of phandle and channel index tuples to the VSPs that handle + the memory interfaces for the DU channels. The phandle identifies the VSP + instance that serves the DU channel, and the channel index identifies the + LIF instance in that VSP. + +Required nodes: + +The connections to the DU output video ports are modeled using the OF graph +bindings specified in Documentation/devicetree/bindings/graph.txt. + +The following table lists for each supported model the port number +corresponding to each DU output. + + Port0 Port1 Port2 Port3 +----------------------------------------------------------------------------- + R8A7743 (RZ/G1M) DPAD 0 LVDS 0 - - + R8A7745 (RZ/G1E) DPAD 0 DPAD 1 - - + R8A7779 (R-Car H1) DPAD 0 DPAD 1 - - + R8A7790 (R-Car H2) DPAD 0 LVDS 0 LVDS 1 - + R8A7791 (R-Car M2-W) DPAD 0 LVDS 0 - - + R8A7792 (R-Car V2H) DPAD 0 DPAD 1 - - + R8A7793 (R-Car M2-N) DPAD 0 LVDS 0 - - + R8A7794 (R-Car E2) DPAD 0 DPAD 1 - - + R8A7795 (R-Car H3) DPAD 0 HDMI 0 HDMI 1 LVDS 0 + R8A7796 (R-Car M3-W) DPAD 0 HDMI 0 LVDS 0 - + R8A77965 (R-Car M3-N) DPAD 0 HDMI 0 LVDS 0 - + R8A77970 (R-Car V3M) DPAD 0 LVDS 0 - - + R8A77995 (R-Car D3) DPAD 0 LVDS 0 LVDS 1 - + + +Example: R8A7795 (R-Car H3) ES2.0 DU + + du: display@feb00000 { + compatible = "renesas,du-r8a7795"; + reg = <0 0xfeb00000 0 0x80000>; + interrupts = , + , + , + ; + clocks = <&cpg CPG_MOD 724>, + <&cpg CPG_MOD 723>, + <&cpg CPG_MOD 722>, + <&cpg CPG_MOD 721>; + clock-names = "du.0", "du.1", "du.2", "du.3"; + vsps = <&vspd0 0>, <&vspd1 0>, <&vspd2 0>, <&vspd0 1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_hdmi0: endpoint { + remote-endpoint = <&dw_hdmi0_in>; + }; + }; + port@2 { + reg = <2>; + du_out_hdmi1: endpoint { + remote-endpoint = <&dw_hdmi1_in>; + }; + }; + port@3 { + reg = <3>; + du_out_lvds0: endpoint { + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/repaper.txt b/arch/arm64/boot/dts/vendor/bindings/display/repaper.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5f9f9cf6a25bf5ad4ed3022a4c6d71e45b66225 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/repaper.txt @@ -0,0 +1,52 @@ +Pervasive Displays RePaper branded e-ink displays + +Required properties: +- compatible: "pervasive,e1144cs021" for 1.44" display + "pervasive,e1190cs021" for 1.9" display + "pervasive,e2200cs021" for 2.0" display + "pervasive,e2271cs021" for 2.7" display + +- panel-on-gpios: Timing controller power control +- discharge-gpios: Discharge control +- reset-gpios: RESET pin +- busy-gpios: BUSY pin + +Required property for e2271cs021: +- border-gpios: Border control + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional property: +- pervasive,thermal-zone: name of thermometer's thermal zone + +Example: + + display_temp: lm75@48 { + compatible = "lm75b"; + reg = <0x48>; + #thermal-sensor-cells = <0>; + }; + + thermal-zones { + display { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&display_temp>; + }; + }; + + papirus27@0{ + compatible = "pervasive,e2271cs021"; + reg = <0>; + + spi-max-frequency = <8000000>; + + panel-on-gpios = <&gpio 23 0>; + border-gpios = <&gpio 14 0>; + discharge-gpios = <&gpio 15 0>; + reset-gpios = <&gpio 24 0>; + busy-gpios = <&gpio 25 0>; + + pervasive,thermal-zone = "display"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/analogix_dp-rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/analogix_dp-rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..43561584c13af152655a7afb9dd2ddc65574ad76 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/analogix_dp-rockchip.txt @@ -0,0 +1,98 @@ +Rockchip RK3288 specific extensions to the Analogix Display Port +================================ + +Required properties: +- compatible: "rockchip,rk3288-dp", + "rockchip,rk3399-edp"; + +- reg: physical base address of the controller and length + +- clocks: from common clock binding: handle to dp clock. + of memory mapped region. + +- clock-names: from common clock binding: + Required elements: "dp" "pclk" + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + +- pinctrl-names: Names corresponding to the chip hotplug pinctrl states. +- pinctrl-0: pin-control mode. should be <&edp_hpd> + +- reset-names: Must include the name "dp" + +- rockchip,grf: this soc should set GRF regs, so need get grf here. + +- ports: there are 2 port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + Port 0: contained 2 endpoints, connecting to the output of vop. + Port 1: contained 1 endpoint, connecting to the input of panel. + +Optional property for different chips: +- clocks: from common clock binding: handle to grf_vio clock. + +- clock-names: from common clock binding: + Required elements: "grf" + +For the below properties, please refer to Analogix DP binding document: + * Documentation/devicetree/bindings/display/bridge/analogix_dp.txt +- phys (required) +- phy-names (required) +- hpd-gpios (optional) +- force-hpd (optional) +------------------------------------------------------------------------------- + +Example: + dp-controller: dp@ff970000 { + compatible = "rockchip,rk3288-dp"; + reg = <0xff970000 0x4000>; + interrupts = ; + clocks = <&cru SCLK_EDP>, <&cru PCLK_EDP_CTRL>; + clock-names = "dp", "pclk"; + phys = <&dp_phy>; + phy-names = "dp"; + + rockchip,grf = <&grf>; + resets = <&cru 111>; + reset-names = "dp"; + + pinctrl-names = "default"; + pinctrl-0 = <&edp_hpd>; + + + ports { + #address-cells = <1>; + #size-cells = <0>; + edp_in: port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + edp_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_edp>; + }; + edp_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_edp>; + }; + }; + + edp_out: port@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + edp_out_panel: endpoint { + reg = <0>; + remote-endpoint = <&panel_in_edp> + }; + }; + }; + }; + + pinctrl { + edp { + edp_hpd: edp-hpd { + rockchip,pins = <7 11 RK_FUNC_2 &pcfg_pull_none>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/cdn-dp-rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/cdn-dp-rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..8df7d2e393d62e723db0feade13370a52e309ae5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/cdn-dp-rockchip.txt @@ -0,0 +1,74 @@ +Rockchip RK3399 specific extensions to the cdn Display Port +================================ + +Required properties: +- compatible: must be "rockchip,rk3399-cdn-dp" + +- reg: physical base address of the controller and length + +- clocks: from common clock binding: handle to dp clock. + +- clock-names: from common clock binding: + Required elements: "core-clk" "pclk" "spdif" "grf" + +- resets : a list of phandle + reset specifier pairs +- reset-names : string of reset names + Required elements: "apb", "core", "dptx", "spdif" +- power-domains : power-domain property defined with a phandle + to respective power domain. +- assigned-clocks: main clock, should be <&cru SCLK_DP_CORE> +- assigned-clock-rates : the DP core clk frequency, shall be: 100000000 + +- rockchip,grf: this soc should set GRF regs, so need get grf here. + +- ports: contain a port nodes with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + contained 2 endpoints, connecting to the output of vop. + +- phys: from general PHY binding: the phandle for the PHY device. + +- extcon: extcon specifier for the Power Delivery + +- #sound-dai-cells = it must be 1 if your system is using 2 DAIs: I2S, SPDIF + +------------------------------------------------------------------------------- + +Example: + cdn_dp: dp@fec00000 { + compatible = "rockchip,rk3399-cdn-dp"; + reg = <0x0 0xfec00000 0x0 0x100000>; + interrupts = ; + clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>, + <&cru SCLK_SPDIF_REC_DPTX>, <&cru PCLK_VIO_GRF>; + clock-names = "core-clk", "pclk", "spdif", "grf"; + assigned-clocks = <&cru SCLK_DP_CORE>; + assigned-clock-rates = <100000000>; + power-domains = <&power RK3399_PD_HDCP>; + phys = <&tcphy0_dp>, <&tcphy1_dp>; + resets = <&cru SRST_DPTX_SPDIF_REC>; + reset-names = "spdif"; + extcon = <&fusb0>, <&fusb1>; + rockchip,grf = <&grf>; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + dp_in: port { + #address-cells = <1>; + #size-cells = <0>; + dp_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_dp>; + }; + + dp_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_dp>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/dw_hdmi-rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/dw_hdmi-rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..adc94fc3c9f88543862821bbc0ac6f506f6cfc1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/dw_hdmi-rockchip.txt @@ -0,0 +1,63 @@ +Rockchip DWC HDMI TX Encoder +============================ + +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with a companion PHY IP. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. + + +Required properties: + +- compatible: should be one of the following: + "rockchip,rk3288-dw-hdmi" + "rockchip,rk3399-dw-hdmi" +- reg: See dw_hdmi.txt. +- reg-io-width: See dw_hdmi.txt. Shall be 4. +- interrupts: HDMI interrupt number +- clocks: See dw_hdmi.txt. +- clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt. +- ports: See dw_hdmi.txt. The DWC HDMI shall have a single port numbered 0 + corresponding to the video input of the controller. The port shall have two + endpoints, numbered 0 and 1, connected respectively to the vopb and vopl. +- rockchip,grf: Shall reference the GRF to mux vopl/vopb. + +Optional properties + +- ddc-i2c-bus: The HDMI DDC bus can be connected to either a system I2C master + or the functionally-reduced I2C master contained in the DWC HDMI. When + connected to a system I2C master this property contains a phandle to that + I2C master controller. +- clock-names: See dw_hdmi.txt. The "cec" clock is optional. +- clock-names: May contain "cec" as defined in dw_hdmi.txt. +- clock-names: May contain "grf", power for grf io. +- clock-names: May contain "vpll", external clock for some hdmi phy. + +Example: + +hdmi: hdmi@ff980000 { + compatible = "rockchip,rk3288-dw-hdmi"; + reg = <0xff980000 0x20000>; + reg-io-width = <4>; + ddc-i2c-bus = <&i2c5>; + rockchip,grf = <&grf>; + interrupts = ; + clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>; + clock-names = "iahb", "isfr"; + ports { + hdmi_in: port { + #address-cells = <1>; + #size-cells = <0>; + hdmi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_hdmi>; + }; + hdmi_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_hdmi>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..6bb59ab39f2f1ac1ebd587b49408608e1f32f92c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt @@ -0,0 +1,68 @@ +Rockchip specific extensions to the Synopsys Designware MIPI DSI +================================ + +Required properties: +- #address-cells: Should be <1>. +- #size-cells: Should be <0>. +- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi". + "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi". +- reg: Represent the physical address range of the controller. +- interrupts: Represent the controller's interrupt to the CPU(s). +- clocks, clock-names: Phandles to the controller's pll reference + clock(ref) and APB clock(pclk). For RK3399, a phy config clock + (phy_cfg) and a grf clock(grf) are required. As described in [1]. +- rockchip,grf: this soc should set GRF regs to mux vopl/vopb. +- ports: contain a port node with endpoint definitions as defined in [2]. + For vopb,set the reg = <0> and set the reg = <1> for vopl. + +Optional properties: +- power-domains: a phandle to mipi dsi power domain node. +- resets: list of phandle + reset specifier pairs, as described in [3]. +- reset-names: string reset name, must be "apb". + +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/media/video-interfaces.txt +[3] Documentation/devicetree/bindings/reset/reset.txt + +Example: + mipi_dsi: mipi@ff960000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi"; + reg = <0xff960000 0x4000>; + interrupts = ; + clocks = <&cru SCLK_MIPI_24M>, <&cru PCLK_MIPI_DSI0>; + clock-names = "ref", "pclk"; + resets = <&cru SRST_MIPIDSI0>; + reset-names = "apb"; + rockchip,grf = <&grf>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + mipi_in: port { + #address-cells = <1>; + #size-cells = <0>; + mipi_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_mipi>; + }; + mipi_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_mipi>; + }; + }; + }; + + panel { + compatible ="boe,tv080wum-nl0"; + reg = <0>; + + enable-gpios = <&gpio7 3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_en>; + backlight = <&backlight>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/inno_hdmi-rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/inno_hdmi-rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..cec21714f0e0a32ca8fc2e6079887e255f91175c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/inno_hdmi-rockchip.txt @@ -0,0 +1,49 @@ +Rockchip specific extensions to the Innosilicon HDMI +================================ + +Required properties: +- compatible: + "rockchip,rk3036-inno-hdmi"; +- reg: + Physical base address and length of the controller's registers. +- clocks, clock-names: + Phandle to hdmi controller clock, name should be "pclk" +- interrupts: + HDMI interrupt number +- ports: + Contain one port node with endpoint definitions as defined in + Documentation/devicetree/bindings/graph.txt. +- pinctrl-0, pinctrl-name: + Switch the iomux of HPD/CEC pins to HDMI function. + +Example: +hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; + clocks = <&cru PCLK_HDMI>; + clock-names = "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + + hdmi_in: port { + #address-cells = <1>; + #size-cells = <0>; + hdmi_in_lcdc: endpoint@0 { + reg = <0>; + remote-endpoint = <&lcdc_out_hdmi>; + }; + }; +}; + +&pinctrl { + hdmi { + hdmi_ctl: hdmi-ctl { + rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>, + <1 9 RK_FUNC_1 &pcfg_pull_none>, + <1 10 RK_FUNC_1 &pcfg_pull_none>, + <1 11 RK_FUNC_1 &pcfg_pull_none>; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-drm.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-drm.txt new file mode 100644 index 0000000000000000000000000000000000000000..5707af89319da70588c6b2b575cdb390420dd9f6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-drm.txt @@ -0,0 +1,19 @@ +Rockchip DRM master device +================================ + +The Rockchip DRM master device is a virtual device needed to list all +vop devices or other display interface nodes that comprise the +graphics subsystem. + +Required properties: +- compatible: Should be "rockchip,display-subsystem" +- ports: Should contain a list of phandles pointing to display interface port + of vop devices. vop definitions as defined in + Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt + +example: + +display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vopl_out>, <&vopb_out>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-lvds.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-lvds.txt new file mode 100644 index 0000000000000000000000000000000000000000..da6939efdb43a47039e63be0634894228b17fc94 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-lvds.txt @@ -0,0 +1,99 @@ +Rockchip RK3288 LVDS interface +================================ + +Required properties: +- compatible: matching the soc type, one of + - "rockchip,rk3288-lvds"; + +- reg: physical base address of the controller and length + of memory mapped region. +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. +- clock-names: must contain "pclk_lvds" + +- avdd1v0-supply: regulator phandle for 1.0V analog power +- avdd1v8-supply: regulator phandle for 1.8V analog power +- avdd3v3-supply: regulator phandle for 3.3V analog power + +- rockchip,grf: phandle to the general register files syscon +- rockchip,output: "rgb", "lvds" or "duallvds", This describes the output interface + +Optional properties: +- pinctrl-names: must contain a "lcdc" entry. +- pinctrl-0: pin control group to be used for this controller. + +Required nodes: + +The lvds has two video ports as described by + Documentation/devicetree/bindings/media/video-interfaces.txt +Their connections are modeled using the OF graph bindings specified in + Documentation/devicetree/bindings/graph.txt. + +- video port 0 for the VOP input, the remote endpoint maybe vopb or vopl +- video port 1 for either a panel or subsequent encoder + +the lvds panel described by + Documentation/devicetree/bindings/display/panel/simple-panel.txt + +Panel required properties: +- ports for remote LVDS output + +Panel optional properties: +- data-mapping: should be "vesa-24","jeida-24" or "jeida-18". +This describes decribed by: + Documentation/devicetree/bindings/display/panel/panel-lvds.txt + +Example: + +lvds_panel: lvds-panel { + compatible = "auo,b101ean01"; + enable-gpios = <&gpio7 21 GPIO_ACTIVE_HIGH>; + data-mapping = "jeida-24"; + + ports { + panel_in_lvds: endpoint { + remote-endpoint = <&lvds_out_panel>; + }; + }; +}; + +For Rockchip RK3288: + + lvds: lvds@ff96c000 { + compatible = "rockchip,rk3288-lvds"; + rockchip,grf = <&grf>; + reg = <0xff96c000 0x4000>; + clocks = <&cru PCLK_LVDS_PHY>; + clock-names = "pclk_lvds"; + pinctrl-names = "lcdc"; + pinctrl-0 = <&lcdc_ctl>; + avdd1v0-supply = <&vdd10_lcd>; + avdd1v8-supply = <&vcc18_lcd>; + avdd3v3-supply = <&vcca_33>; + rockchip,output = "rgb"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + lvds_in: port@0 { + reg = <0>; + + lvds_in_vopb: endpoint@0 { + reg = <0>; + remote-endpoint = <&vopb_out_lvds>; + }; + lvds_in_vopl: endpoint@1 { + reg = <1>; + remote-endpoint = <&vopl_out_lvds>; + }; + }; + + lvds_out: port@1 { + reg = <1>; + + lvds_out_panel: endpoint { + remote-endpoint = <&panel_in_lvds>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-vop.txt b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-vop.txt new file mode 100644 index 0000000000000000000000000000000000000000..eeda3597011e89698f63fc759c102bb0885af8cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/rockchip/rockchip-vop.txt @@ -0,0 +1,66 @@ +device-tree bindings for rockchip soc display controller (vop) + +VOP (Visual Output Processor) is the Display Controller for the Rockchip +series of SoCs which transfers the image data from a video memory +buffer to an external LCD interface. + +Required properties: +- compatible: value should be one of the following + "rockchip,rk3036-vop"; + "rockchip,rk3126-vop"; + "rockchip,rk3288-vop"; + "rockchip,rk3368-vop"; + "rockchip,rk3366-vop"; + "rockchip,rk3399-vop-big"; + "rockchip,rk3399-vop-lit"; + "rockchip,rk3228-vop"; + "rockchip,rk3328-vop"; + +- interrupts: should contain a list of all VOP IP block interrupts in the + order: VSYNC, LCD_SYSTEM. The interrupt specifier + format depends on the interrupt controller used. + +- clocks: must include clock specifiers corresponding to entries in the + clock-names property. + +- clock-names: Must contain + aclk_vop: for ddr buffer transfer. + hclk_vop: for ahb bus to R/W the phy regs. + dclk_vop: pixel clock. + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - axi + - ahb + - dclk + +- iommus: required a iommu node + +- port: A port node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: +SoC specific DT entry: + vopb: vopb@ff930000 { + compatible = "rockchip,rk3288-vop"; + reg = <0xff930000 0x19c>; + interrupts = ; + clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>; + clock-names = "aclk_vop", "dclk_vop", "hclk_vop"; + resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>; + reset-names = "axi", "ahb", "dclk"; + iommus = <&vopb_mmu>; + vopb_out: port { + #address-cells = <1>; + #size-cells = <0>; + vopb_out_edp: endpoint@0 { + reg = <0>; + remote-endpoint=<&edp_in_vopb>; + }; + vopb_out_hdmi: endpoint@1 { + reg = <1>; + remote-endpoint=<&hdmi_in_vopb>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/simple-framebuffer-sunxi.txt b/arch/arm64/boot/dts/vendor/bindings/display/simple-framebuffer-sunxi.txt new file mode 100644 index 0000000000000000000000000000000000000000..d693b8dc9a628e72b9f40bffe01c3c1cc0f0d402 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/simple-framebuffer-sunxi.txt @@ -0,0 +1,36 @@ +Sunxi specific Simple Framebuffer bindings + +This binding documents sunxi specific extensions to the simple-framebuffer +bindings. The sunxi simplefb u-boot code relies on the devicetree containing +pre-populated simplefb nodes. + +These extensions are intended so that u-boot can select the right node based +on which pipeline is being used. As such they are solely intended for +firmware / bootloader use, and the OS should ignore them. + +Required properties: +- compatible: "allwinner,simple-framebuffer" +- allwinner,pipeline, one of: + "de_be0-lcd0" + "de_be1-lcd1" + "de_be0-lcd0-hdmi" + "de_be1-lcd1-hdmi" + "mixer0-lcd0" + "mixer0-lcd0-hdmi" + "mixer1-lcd1-hdmi" + "mixer1-lcd1-tve" + +Example: + +chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + framebuffer@0 { + compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; + allwinner,pipeline = "de_be0-lcd0-hdmi"; + clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, + <&ahb_gates 44>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/simple-framebuffer.txt b/arch/arm64/boot/dts/vendor/bindings/display/simple-framebuffer.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a9ce511be88c69f27aad155a6e6ffebc26e033e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/simple-framebuffer.txt @@ -0,0 +1,91 @@ +Simple Framebuffer + +A simple frame-buffer describes a frame-buffer setup by firmware or +the bootloader, with the assumption that the display hardware has already +been set up to scan out from the memory pointed to by the reg property. + +Since simplefb nodes represent runtime information they must be sub-nodes of +the chosen node (*). Simplefb nodes must be named "framebuffer@
". + +If the devicetree contains nodes for the display hardware used by a simplefb, +then the simplefb node must contain a property called "display", which +contains a phandle pointing to the primary display hw node, so that the OS +knows which simplefb to disable when handing over control to a driver for the +real hardware. The bindings for the hw nodes must specify which node is +considered the primary node. + +It is advised to add display# aliases to help the OS determine how to number +things. If display# aliases are used, then if the simplefb node contains a +"display" property then the /aliases/display# path must point to the display +hw node the "display" property points to, otherwise it must point directly +to the simplefb node. + +If a simplefb node represents the preferred console for user interaction, +then the chosen node's stdout-path property should point to it, or to the +primary display hw node, as with display# aliases. If display aliases are +used then it should be set to the alias instead. + +It is advised that devicetree files contain pre-filled, disabled framebuffer +nodes, so that the firmware only needs to update the mode information and +enable them. This way if e.g. later on support for more display clocks get +added, the simplefb nodes will already contain this info and the firmware +does not need to be updated. + +If pre-filled framebuffer nodes are used, the firmware may need extra +information to find the right node. In that case an extra platform specific +compatible and platform specific properties should be used and documented, +see e.g. simple-framebuffer-sunxi.txt . + +Required properties: +- compatible: "simple-framebuffer" +- reg: Should contain the location and size of the framebuffer memory. +- width: The width of the framebuffer in pixels. +- height: The height of the framebuffer in pixels. +- stride: The number of bytes in each line of the framebuffer. +- format: The format of the framebuffer surface. Valid values are: + - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b). + - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r). + +Optional properties: +- clocks : List of clocks used by the framebuffer. +- *-supply : Any number of regulators used by the framebuffer. These should + be named according to the names in the device's design. + + The above resources are expected to already be configured correctly. + The OS must ensure they are not modified or disabled while the simple + framebuffer remains active. + +- display : phandle pointing to the primary display hardware node + +Example: + +aliases { + display0 = &lcdc0; +} + +chosen { + framebuffer0: framebuffer@1d385000 { + compatible = "simple-framebuffer"; + reg = <0x1d385000 (1600 * 1200 * 2)>; + width = <1600>; + height = <1200>; + stride = <(1600 * 2)>; + format = "r5g6b5"; + clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>; + lcd-supply = <®_dc1sw>; + display = <&lcdc0>; + }; + stdout-path = "display0"; +}; + +soc@1c00000 { + lcdc0: lcdc@1c0c000 { + compatible = "allwinner,sun4i-a10-lcdc"; + ... + }; +}; + + +*) Older devicetree files may have a compatible = "simple-framebuffer" node +in a different place, operating systems must first enumerate any compatible +nodes found under chosen and then check for other compatible nodes. diff --git a/arch/arm64/boot/dts/vendor/bindings/display/sitronix,st7586.txt b/arch/arm64/boot/dts/vendor/bindings/display/sitronix,st7586.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d0dad1210d380849370738dbfb6a7b0e07773e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/sitronix,st7586.txt @@ -0,0 +1,22 @@ +Sitronix ST7586 display panel + +Required properties: +- compatible: "lego,ev3-lcd". +- a0-gpios: The A0 signal (since this binding is for serial mode, this is + the pin labeled D1 on the controller, not the pin labeled A0) +- reset-gpios: Reset pin + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional properties: +- rotation: panel rotation in degrees counter clockwise (0,90,180,270) + +Example: + display@0{ + compatible = "lego,ev3-lcd"; + reg = <0>; + spi-max-frequency = <10000000>; + a0-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/sitronix,st7735r.txt b/arch/arm64/boot/dts/vendor/bindings/display/sitronix,st7735r.txt new file mode 100644 index 0000000000000000000000000000000000000000..f0a5090a3326b86c1df8a42eb65e8884a77cd521 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/sitronix,st7735r.txt @@ -0,0 +1,35 @@ +Sitronix ST7735R display panels + +This binding is for display panels using a Sitronix ST7735R controller in SPI +mode. + +Required properties: +- compatible: "jianda,jd-t18003-t01", "sitronix,st7735r" +- dc-gpios: Display data/command selection (D/CX) +- reset-gpios: Reset signal (RSTX) + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in ../spi/spi-bus.txt must be specified. + +Optional properties: +- rotation: panel rotation in degrees counter clockwise (0,90,180,270) +- backlight: phandle of the backlight device attached to the panel + +Example: + + backlight: backlight { + compatible = "gpio-backlight"; + gpios = <&gpio 44 GPIO_ACTIVE_HIGH>; + } + + ... + + display@0{ + compatible = "jianda,jd-t18003-t01", "sitronix,st7735r"; + reg = <0>; + spi-max-frequency = <32000000>; + dc-gpios = <&gpio 43 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 80 GPIO_ACTIVE_HIGH>; + rotation = <270>; + backlight = &backlight; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/sm501fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/sm501fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c79c267a57f729cb99da64f5c3f08d2aa65b082 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/sm501fb.txt @@ -0,0 +1,32 @@ +* SM SM501 + +The SM SM501 is a LCD controller, with proper hardware, it can also +drive DVI monitors. + +Required properties: +- compatible : should be "smi,sm501". +- reg : contain two entries: + - First entry: System Configuration register + - Second entry: IO space (Display Controller register) +- interrupts : SMI interrupt to the cpu should be described here. + +Optional properties: +- mode : select a video mode: + x[-][@] +- edid : verbatim EDID data block describing attached display. + Data from the detailed timing descriptor will be used to + program the display controller. +- little-endian: available on big endian systems, to + set different foreign endian. +- big-endian: available on little endian systems, to + set different foreign endian. + +Example for MPC5200: + display@1,0 { + compatible = "smi,sm501"; + reg = <1 0x00000000 0x00800000 + 1 0x03e00000 0x00200000>; + interrupts = <1 1 3>; + mode = "640x480-32@60"; + edid = [edid-data]; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/snps,arcpgu.txt b/arch/arm64/boot/dts/vendor/bindings/display/snps,arcpgu.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5c7dfd37df2f52e3bc5b93607988ac004d45b9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/snps,arcpgu.txt @@ -0,0 +1,35 @@ +ARC PGU + +This is a display controller found on several development boards produced +by Synopsys. The ARC PGU is an RGB streamer that reads the data from a +framebuffer and sends it to a single digital encoder (usually HDMI). + +Required properties: + - compatible: "snps,arcpgu" + - reg: Physical base address and length of the controller's registers. + - clocks: A list of phandle + clock-specifier pairs, one for each + entry in 'clock-names'. + - clock-names: A list of clock names. For ARC PGU it should contain: + - "pxlclk" for the clock feeding the output PLL of the controller. + +Required sub-nodes: + - port: The PGU connection to an encoder chip. + +Example: + +/ { + ... + + pgu@XXXXXXXX { + compatible = "snps,arcpgu"; + reg = <0xXXXXXXXX 0x400>; + clocks = <&clock_node>; + clock-names = "pxlclk"; + + port { + pgu_output: endpoint { + remote-endpoint = <&hdmi_enc_input>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ssd1289fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/ssd1289fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..4fcd5e68cb6e005927f87c0c36d843de640de525 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ssd1289fb.txt @@ -0,0 +1,13 @@ +* Solomon SSD1289 Framebuffer Driver + +Required properties: + - compatible: Should be "solomon,ssd1289fb". The only supported bus for + now is lbc. + - reg: Should contain address of the controller on the LBC bus. The detail + was described in Documentation/devicetree/bindings/powerpc/fsl/lbc.txt + +Examples: +display@2,0 { + compatible = "solomon,ssd1289fb"; + reg = <0x2 0x0000 0x0004>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ssd1307fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/ssd1307fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..209d931ef16c4e53e46e8378b09f5cf04b121586 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ssd1307fb.txt @@ -0,0 +1,51 @@ +* Solomon SSD1307 Framebuffer Driver + +Required properties: + - compatible: Should be "solomon,fb-". The only supported bus for + now is i2c, and the supported chips are ssd1305, ssd1306, ssd1307 and + ssd1309. + - reg: Should contain address of the controller on the I2C bus. Most likely + 0x3c or 0x3d + - pwm: Should contain the pwm to use according to the OF device tree PWM + specification [0]. Only required for the ssd1307. + - solomon,height: Height in pixel of the screen driven by the controller + - solomon,width: Width in pixel of the screen driven by the controller + - solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is + mapped to. + +Optional properties: + - reset-gpios: The GPIO used to reset the OLED display, if available. See + Documentation/devicetree/bindings/gpio/gpio.txt for details. + - vbat-supply: The supply for VBAT + - solomon,segment-no-remap: Display needs normal (non-inverted) data column + to segment mapping + - solomon,com-seq: Display uses sequential COM pin configuration + - solomon,com-lrremap: Display uses left-right COM pin remap + - solomon,com-invdir: Display uses inverted COM pin scan direction + - solomon,com-offset: Number of the COM pin wired to the first display line + - solomon,prechargep1: Length of deselect period (phase 1) in clock cycles. + - solomon,prechargep2: Length of precharge period (phase 2) in clock cycles. + This needs to be the higher, the higher the capacitance + of the OLED's pixels is + +[0]: Documentation/devicetree/bindings/pwm/pwm.txt + +Examples: +ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7>; + reset-active-low; +}; + +ssd1306: oled@3c { + compatible = "solomon,ssd1306fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7>; + reset-active-low; + solomon,com-lrremap; + solomon,com-invdir; + solomon,com-offset = <32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/st,stih4xx.txt b/arch/arm64/boot/dts/vendor/bindings/display/st,stih4xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..6778b3e7ad5b4db12a8ed02b723f8c5ae584f2e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/st,stih4xx.txt @@ -0,0 +1,241 @@ +STMicroelectronics stih4xx platforms + +- sti-vtg: video timing generator + Required properties: + - compatible: "st,vtg" + - reg: Physical base address of the IP registers and length of memory mapped region. + Optional properties: + - interrupts : VTG interrupt number to the CPU. + - st,slave: phandle on a slave vtg + +- sti-vtac: video timing advanced inter dye communication Rx and TX + Required properties: + - compatible: "st,vtac-main" or "st,vtac-aux" + - reg: Physical base address of the IP registers and length of memory mapped region. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + +- sti-display-subsystem: Master device for DRM sub-components + This device must be the parent of all the sub-components and is responsible + of bind them. + Required properties: + - compatible: "st,sti-display-subsystem" + - ranges: to allow probing of subdevices + +- sti-compositor: frame compositor engine + must be a child of sti-display-subsystem + Required properties: + - compatible: "st,stih-compositor" + - reg: Physical base address of the IP registers and length of memory mapped region. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + - resets: resets to be used by the device + See ../reset/reset.txt for details. + - reset-names: names of the resets listed in resets property in the same + order. + - st,vtg: phandle(s) on vtg device (main and aux) nodes. + +- sti-tvout: video out hardware block + must be a child of sti-display-subsystem + Required properties: + - compatible: "st,stih-tvout" + - reg: Physical base address of the IP registers and length of memory mapped region. + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + - resets: resets to be used by the device + See ../reset/reset.txt for details. + - reset-names: names of the resets listed in resets property in the same + order. + +- sti-hdmi: hdmi output block + must be a child of sti-display-subsystem + Required properties: + - compatible: "st,stih-hdmi"; + - reg: Physical base address of the IP registers and length of memory mapped region. + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + - interrupts : HDMI interrupt number to the CPU. + - interrupt-names: names of the interrupts listed in interrupts property in + the same order + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + - clock-names: names of the clocks listed in clocks property in the same + order. + - ddc: phandle of an I2C controller used for DDC EDID probing + +sti-hda: + Required properties: + must be a child of sti-display-subsystem + - compatible: "st,stih-hda" + - reg: Physical base address of the IP registers and length of memory mapped region. + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + +sti-dvo: + Required properties: + must be a child of sti-display-subsystem + - compatible: "st,stih-dvo" + - reg: Physical base address of the IP registers and length of memory mapped region. + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + - pinctrl-0: pin control handle + - pinctrl-names: names of the pin control states to use + - sti,panel: phandle of the panel connected to the DVO output + +sti-hqvdp: + must be a child of sti-display-subsystem + Required properties: + - compatible: "st,stih-hqvdp" + - reg: Physical base address of the IP registers and length of memory mapped region. + - clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend of the SoC type. + See ../clocks/clock-bindings.txt for details. + - clock-names: names of the clocks listed in clocks property in the same + order. + - resets: resets to be used by the device + See ../reset/reset.txt for details. + - reset-names: names of the resets listed in resets property in the same + order. + - st,vtg: phandle on vtg main device node. + +Example: + +/ { + ... + + vtg_main_slave: sti-vtg-main-slave@fe85a800 { + compatible = "st,vtg"; + reg = <0xfe85A800 0x300>; + interrupts = ; + }; + + vtg_main: sti-vtg-main-master@fd348000 { + compatible = "st,vtg"; + reg = <0xfd348000 0x400>; + st,slave = <&vtg_main_slave>; + }; + + vtg_aux_slave: sti-vtg-aux-slave@fd348400 { + compatible = "st,vtg"; + reg = <0xfe858200 0x300>; + interrupts = ; + }; + + vtg_aux: sti-vtg-aux-master@fd348400 { + compatible = "st,vtg"; + reg = <0xfd348400 0x400>; + st,slave = <&vtg_aux_slave>; + }; + + + sti-vtac-rx-main@fee82800 { + compatible = "st,vtac-main"; + reg = <0xfee82800 0x200>; + clock-names = "vtac"; + clocks = <&clk_m_a2_div0 CLK_M_VTAC_MAIN_PHY>; + }; + + sti-vtac-rx-aux@fee82a00 { + compatible = "st,vtac-aux"; + reg = <0xfee82a00 0x200>; + clock-names = "vtac"; + clocks = <&clk_m_a2_div0 CLK_M_VTAC_AUX_PHY>; + }; + + sti-vtac-tx-main@fd349000 { + compatible = "st,vtac-main"; + reg = <0xfd349000 0x200>, <0xfd320000 0x10000>; + clock-names = "vtac"; + clocks = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>; + }; + + sti-vtac-tx-aux@fd349200 { + compatible = "st,vtac-aux"; + reg = <0xfd349200 0x200>, <0xfd320000 0x10000>; + clock-names = "vtac"; + clocks = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>; + }; + + sti-display-subsystem { + compatible = "st,sti-display-subsystem"; + ranges; + + sti-compositor@fd340000 { + compatible = "st,stih416-compositor"; + reg = <0xfd340000 0x1000>; + clock-names = "compo_main", "compo_aux", + "pix_main", "pix_aux"; + clocks = <&clk_m_a2_div1 CLK_M_COMPO_MAIN>, <&clk_m_a2_div1 CLK_M_COMPO_AUX>, + <&clockgen_c_vcc CLK_S_PIX_MAIN>, <&clockgen_c_vcc CLK_S_PIX_AUX>; + reset-names = "compo-main", "compo-aux"; + resets = <&softreset STIH416_COMPO_M_SOFTRESET>, <&softreset STIH416_COMPO_A_SOFTRESET>; + st,vtg = <&vtg_main>, <&vtg_aux>; + }; + + sti-tvout@fe000000 { + compatible = "st,stih416-tvout"; + reg = <0xfe000000 0x1000>, <0xfe85a000 0x400>, <0xfe830000 0x10000>; + reg-names = "tvout-reg", "hda-reg", "syscfg"; + reset-names = "tvout"; + resets = <&softreset STIH416_HDTVOUT_SOFTRESET>; + }; + + sti-hdmi@fe85c000 { + compatible = "st,stih416-hdmi"; + reg = <0xfe85c000 0x1000>, <0xfe830000 0x10000>; + reg-names = "hdmi-reg", "syscfg"; + interrupts = ; + interrupt-names = "irq"; + clock-names = "pix", "tmds", "phy", "audio"; + clocks = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>; + }; + + sti-hda@fe85a000 { + compatible = "st,stih416-hda"; + reg = <0xfe85a000 0x400>, <0xfe83085c 0x4>; + reg-names = "hda-reg", "video-dacs-ctrl"; + clock-names = "pix", "hddac"; + clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>; + }; + + sti-dvo@8d00400 { + compatible = "st,stih407-dvo"; + reg = <0x8d00400 0x200>; + reg-names = "dvo-reg"; + clock-names = "dvo_pix", "dvo", + "main_parent", "aux_parent"; + clocks = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>, + <&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvo>; + sti,panel = <&panel_dvo>; + }; + + sti-hqvdp@9c000000 { + compatible = "st,stih407-hqvdp"; + reg = <0x9C00000 0x100000>; + clock-names = "hqvdp", "pix_main"; + clocks = <&clk_s_c0_flexgen CLK_MAIN_DISP>, <&clk_s_d2_flexgen CLK_PIX_MAIN_DISP>; + reset-names = "hqvdp"; + resets = <&softreset STIH407_HDQVDP_SOFTRESET>; + st,vtg = <&vtg_main>; + }; + }; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/st,stm32-ltdc.txt b/arch/arm64/boot/dts/vendor/bindings/display/st,stm32-ltdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3eb1b48b47ddc92348e4d2516743152f5753a598 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/st,stm32-ltdc.txt @@ -0,0 +1,141 @@ +* STMicroelectronics STM32 lcd-tft display controller + +- ltdc: lcd-tft display controller host + Required properties: + - compatible: "st,stm32-ltdc" + - reg: Physical base address of the IP registers and length of memory mapped region. + - clocks: A list of phandle + clock-specifier pairs, one for each + entry in 'clock-names'. + - clock-names: A list of clock names. For ltdc it should contain: + - "lcd" for the clock feeding the output pixel clock & IP clock. + - resets: reset to be used by the device (defined by use of RCC macro). + Required nodes: + - Video port for DPI RGB output: ltdc has one video port with up to 2 + endpoints: + - for external dpi rgb panel or bridge, using gpios. + - for internal dpi input of the MIPI DSI host controller. + Note: These 2 endpoints cannot be activated simultaneously. + +* STMicroelectronics STM32 DSI controller specific extensions to Synopsys + DesignWare MIPI DSI host controller + +The STMicroelectronics STM32 DSI controller uses the Synopsys DesignWare MIPI +DSI host controller. For all mandatory properties & nodes, please refer +to the related documentation in [5]. + +Mandatory properties specific to STM32 DSI: +- #address-cells: Should be <1>. +- #size-cells: Should be <0>. +- compatible: "st,stm32-dsi". +- clock-names: + - phy pll reference clock string name, must be "ref". +- resets: see [5]. +- reset-names: see [5]. + +Mandatory nodes specific to STM32 DSI: +- ports: A node containing DSI input & output port nodes with endpoint + definitions as documented in [3] & [4]. + - port@0: DSI input port node, connected to the ltdc rgb output port. + - port@1: DSI output port node, connected to a panel or a bridge input port. +- panel or bridge node: A node containing the panel or bridge description as + documented in [6]. + - port: panel or bridge port node, connected to the DSI output port (port@1). + +Note: You can find more documentation in the following references +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt +[2] Documentation/devicetree/bindings/reset/reset.txt +[3] Documentation/devicetree/bindings/media/video-interfaces.txt +[4] Documentation/devicetree/bindings/graph.txt +[5] Documentation/devicetree/bindings/display/bridge/dw_mipi_dsi.txt +[6] Documentation/devicetree/bindings/display/mipi-dsi-bus.txt + +Example 1: RGB panel +/ { + ... + soc { + ... + ltdc: display-controller@40016800 { + compatible = "st,stm32-ltdc"; + reg = <0x40016800 0x200>; + interrupts = <88>, <89>; + resets = <&rcc STM32F4_APB2_RESET(LTDC)>; + clocks = <&rcc 1 CLK_LCD>; + clock-names = "lcd"; + + port { + ltdc_out_rgb: endpoint { + }; + }; + }; + }; +}; + +Example 2: DSI panel + +/ { + ... + soc { + ... + ltdc: display-controller@40016800 { + compatible = "st,stm32-ltdc"; + reg = <0x40016800 0x200>; + interrupts = <88>, <89>; + resets = <&rcc STM32F4_APB2_RESET(LTDC)>; + clocks = <&rcc 1 CLK_LCD>; + clock-names = "lcd"; + + port { + ltdc_out_dsi: endpoint { + remote-endpoint = <&dsi_in>; + }; + }; + }; + + + dsi: dsi@40016c00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32-dsi"; + reg = <0x40016c00 0x800>; + clocks = <&rcc 1 CLK_F469_DSI>, <&clk_hse>; + clock-names = "pclk", "ref"; + resets = <&rcc STM32F4_APB2_RESET(DSI)>; + reset-names = "apb"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi_in: endpoint { + remote-endpoint = <<dc_out_dsi>; + }; + }; + + port@1 { + reg = <1>; + dsi_out: endpoint { + remote-endpoint = <&dsi_in_panel>; + }; + }; + + }; + + panel-dsi@0 { + reg = <0>; /* dsi virtual channel (0..3) */ + compatible = ...; + enable-gpios = ...; + + port { + dsi_in_panel: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + }; + + }; + + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/sunxi/sun4i-drm.txt b/arch/arm64/boot/dts/vendor/bindings/display/sunxi/sun4i-drm.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8773ecb75252f91ea1e80cc47574b9781888de2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/sunxi/sun4i-drm.txt @@ -0,0 +1,608 @@ +Allwinner A10 Display Pipeline +============================== + +The Allwinner A10 Display pipeline is composed of several components +that are going to be documented below: + +For all connections between components up to the TCONs in the display +pipeline, when there are multiple components of the same type at the +same depth, the local endpoint ID must be the same as the remote +component's index. For example, if the remote endpoint is Frontend 1, +then the local endpoint ID must be 1. + + Frontend 0 [0] ------- [0] Backend 0 [0] ------- [0] TCON 0 + [1] -- -- [1] [1] -- -- [1] + \ / \ / + X X + / \ / \ + [0] -- -- [0] [0] -- -- [0] + Frontend 1 [1] ------- [1] Backend 1 [1] ------- [1] TCON 1 + +For a two pipeline system such as the one depicted above, the lines +represent the connections between the components, while the numbers +within the square brackets corresponds to the ID of the local endpoint. + +The same rule also applies to DE 2.0 mixer-TCON connections: + + Mixer 0 [0] ----------- [0] TCON 0 + [1] ---- ---- [1] + \ / + X + / \ + [0] ---- ---- [0] + Mixer 1 [1] ----------- [1] TCON 1 + +HDMI Encoder +------------ + +The HDMI Encoder supports the HDMI video and audio outputs, and does +CEC. It is one end of the pipeline. + +Required properties: + - compatible: value must be one of: + * allwinner,sun4i-a10-hdmi + * allwinner,sun5i-a10s-hdmi + * allwinner,sun6i-a31-hdmi + - reg: base address and size of memory-mapped region + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the HDMI encoder + * ahb: the HDMI interface clock + * mod: the HDMI module clock + * ddc: the HDMI ddc clock (A31 only) + * pll-0: the first video PLL + * pll-1: the second video PLL + - clock-names: the clock names mentioned above + - resets: phandle to the reset control for the HDMI encoder (A31 only) + - dmas: phandles to the DMA channels used by the HDMI encoder + * ddc-tx: The channel for DDC transmission + * ddc-rx: The channel for DDC reception + * audio-tx: The channel used for audio transmission + - dma-names: the channel names mentioned above + + - ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoint. The second should be the + output, usually to an HDMI connector. + +DWC HDMI TX Encoder +------------------- + +The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP +with Allwinner's own PHY IP. It supports audio and video outputs and CEC. + +These DT bindings follow the Synopsys DWC HDMI TX bindings defined in +Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the +following device-specific properties. + +Required properties: + + - compatible: value must be one of: + * "allwinner,sun8i-a83t-dw-hdmi" + - reg: base address and size of memory-mapped region + - reg-io-width: See dw_hdmi.txt. Shall be 1. + - interrupts: HDMI interrupt number + - clocks: phandles to the clocks feeding the HDMI encoder + * iahb: the HDMI bus clock + * isfr: the HDMI register clock + * tmds: TMDS clock + - clock-names: the clock names mentioned above + - resets: phandle to the reset controller + - reset-names: must be "ctrl" + - phys: phandle to the DWC HDMI PHY + - phy-names: must be "phy" + + - ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoint. The second should be the + output, usually to an HDMI connector. + +DWC HDMI PHY +------------ + +Required properties: + - compatible: value must be one of: + * allwinner,sun8i-a83t-hdmi-phy + * allwinner,sun8i-h3-hdmi-phy + * allwinner,sun50i-a64-hdmi-phy + - reg: base address and size of memory-mapped region + - clocks: phandles to the clocks feeding the HDMI PHY + * bus: the HDMI PHY interface clock + * mod: the HDMI PHY module clock + - clock-names: the clock names mentioned above + - resets: phandle to the reset controller driving the PHY + - reset-names: must be "phy" + +H3 and A64 HDMI PHY require additional clocks: + - pll-0: parent of phy clock + - pll-1: second possible phy clock parent (A64 only) + +TV Encoder +---------- + +The TV Encoder supports the composite and VGA output. It is one end of +the pipeline. + +Required properties: + - compatible: value should be "allwinner,sun4i-a10-tv-encoder". + - reg: base address and size of memory-mapped region + - clocks: the clocks driving the TV encoder + - resets: phandle to the reset controller driving the encoder + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoint. + +TCON +---- + +The TCON acts as a timing controller for RGB, LVDS and TV interfaces. + +Required properties: + - compatible: value must be either: + * allwinner,sun4i-a10-tcon + * allwinner,sun5i-a13-tcon + * allwinner,sun6i-a31-tcon + * allwinner,sun6i-a31s-tcon + * allwinner,sun7i-a20-tcon + * allwinner,sun8i-a33-tcon + * allwinner,sun8i-a83t-tcon-lcd + * allwinner,sun8i-a83t-tcon-tv + * allwinner,sun8i-r40-tcon-tv + * allwinner,sun8i-v3s-tcon + * allwinner,sun9i-a80-tcon-lcd + * allwinner,sun9i-a80-tcon-tv + - reg: base address and size of memory-mapped region + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the TCON. + - 'ahb': the interface clocks + - 'tcon-ch0': The clock driving the TCON channel 0, if supported + - resets: phandles to the reset controllers driving the encoder + - "lcd": the reset line for the TCON + - "edp": the reset line for the eDP block (A80 only) + + - clock-names: the clock names mentioned above + - reset-names: the reset names mentioned above + - clock-output-names: Name of the pixel clock created, if TCON supports + channel 0. + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoint, the second one the output + + The output may have multiple endpoints. TCON can have 1 or 2 channels, + usually with the first channel being used for the panels interfaces + (RGB, LVDS, etc.), and the second being used for the outputs that + require another controller (TV Encoder, HDMI, etc.). The endpoints + will take an extra property, allwinner,tcon-channel, to specify the + channel the endpoint is associated to. If that property is not + present, the endpoint number will be used as the channel number. + +For TCONs with channel 0, there is one more clock required: + - 'tcon-ch0': The clock driving the TCON channel 0 +For TCONs with channel 1, there is one more clock required: + - 'tcon-ch1': The clock driving the TCON channel 1 + +When TCON support LVDS (all TCONs except TV TCONs on A83T, R40 and those found +in A13, H3, H5 and V3s SoCs), you need one more reset line: + - 'lvds': The reset line driving the LVDS logic + +And on the A23, A31, A31s and A33, you need one more clock line: + - 'lvds-alt': An alternative clock source, separate from the TCON channel 0 + clock, that can be used to drive the LVDS clock + +TCON TOP +-------- + +TCON TOPs main purpose is to configure whole display pipeline. It determines +relationships between mixers and TCONs, selects source TCON for HDMI, muxes +LCD and TV encoder GPIO output, selects TV encoder clock source and contains +additional TV TCON and DSI gates. + +It allows display pipeline to be configured in very different ways: + + / LCD0/LVDS0 + / [0] TCON-LCD0 + | \ MIPI DSI + mixer0 | + \ / [1] TCON-LCD1 - LCD1/LVDS1 + TCON-TOP + / \ [2] TCON-TV0 [0] - TVE0/RGB + mixer1 | \ + | TCON-TOP - HDMI + | / + \ [3] TCON-TV1 [1] - TVE1/RGB + +Note that both TCON TOP references same physical unit. Both mixers can be +connected to any TCON. + +Required properties: + - compatible: value must be one of: + * allwinner,sun8i-r40-tcon-top + - reg: base address and size of the memory-mapped region. + - clocks: phandle to the clocks feeding the TCON TOP + * bus: TCON TOP interface clock + * tcon-tv0: TCON TV0 clock + * tve0: TVE0 clock + * tcon-tv1: TCON TV1 clock + * tve1: TVE0 clock + * dsi: MIPI DSI clock + - clock-names: clock name mentioned above + - resets: phandle to the reset line driving the TCON TOP + - #clock-cells : must contain 1 + - clock-output-names: Names of clocks created for TCON TV0 channel clock, + TCON TV1 channel clock and DSI channel clock, in that order. + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. 6 ports should + be defined: + * port 0 is input for mixer0 mux + * port 1 is output for mixer0 mux + * port 2 is input for mixer1 mux + * port 3 is output for mixer1 mux + * port 4 is input for HDMI mux + * port 5 is output for HDMI mux + All output endpoints for mixer muxes and input endpoints for HDMI mux should + have reg property with the id of the target TCON, as shown in above graph + (0-3 for mixer muxes and 0-1 for HDMI mux). All ports should have only one + endpoint connected to remote endpoint. + +DRC +--- + +The DRC (Dynamic Range Controller), found in the latest Allwinner SoCs +(A31, A23, A33, A80), allows to dynamically adjust pixel +brightness/contrast based on histogram measurements for LCD content +adaptive backlight control. + + +Required properties: + - compatible: value must be one of: + * allwinner,sun6i-a31-drc + * allwinner,sun6i-a31s-drc + * allwinner,sun8i-a33-drc + * allwinner,sun9i-a80-drc + - reg: base address and size of the memory-mapped region. + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the DRC + * ahb: the DRC interface clock + * mod: the DRC module clock + * ram: the DRC DRAM clock + - clock-names: the clock names mentioned above + - resets: phandles to the reset line driving the DRC + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoints, the second one the outputs + +Display Engine Backend +---------------------- + +The display engine backend exposes layers and sprites to the +system. + +Required properties: + - compatible: value must be one of: + * allwinner,sun4i-a10-display-backend + * allwinner,sun5i-a13-display-backend + * allwinner,sun6i-a31-display-backend + * allwinner,sun7i-a20-display-backend + * allwinner,sun8i-a33-display-backend + * allwinner,sun9i-a80-display-backend + - reg: base address and size of the memory-mapped region. + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the frontend and backend + * ahb: the backend interface clock + * mod: the backend module clock + * ram: the backend DRAM clock + - clock-names: the clock names mentioned above + - resets: phandles to the reset controllers driving the backend + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoints, the second one the output + +On the A33, some additional properties are required: + - reg needs to have an additional region corresponding to the SAT + - reg-names need to be set, with "be" and "sat" + - clocks and clock-names need to have a phandle to the SAT bus + clocks, whose name will be "sat" + - resets and reset-names need to have a phandle to the SAT bus + resets, whose name will be "sat" + +DEU +--- + +The DEU (Detail Enhancement Unit), found in the Allwinner A80 SoC, +can sharpen the display content in both luma and chroma channels. + +Required properties: + - compatible: value must be one of: + * allwinner,sun9i-a80-deu + - reg: base address and size of the memory-mapped region. + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the DEU + * ahb: the DEU interface clock + * mod: the DEU module clock + * ram: the DEU DRAM clock + - clock-names: the clock names mentioned above + - resets: phandles to the reset line driving the DEU + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoints, the second one the outputs + +Display Engine Frontend +----------------------- + +The display engine frontend does formats conversion, scaling, +deinterlacing and color space conversion. + +Required properties: + - compatible: value must be one of: + * allwinner,sun4i-a10-display-frontend + * allwinner,sun5i-a13-display-frontend + * allwinner,sun6i-a31-display-frontend + * allwinner,sun7i-a20-display-frontend + * allwinner,sun8i-a33-display-frontend + * allwinner,sun9i-a80-display-frontend + - reg: base address and size of the memory-mapped region. + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the frontend and backend + * ahb: the backend interface clock + * mod: the backend module clock + * ram: the backend DRAM clock + - clock-names: the clock names mentioned above + - resets: phandles to the reset controllers driving the backend + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoints, the second one the outputs + +Display Engine 2.0 Mixer +------------------------ + +The DE2 mixer have many functionalities, currently only layer blending is +supported. + +Required properties: + - compatible: value must be one of: + * allwinner,sun8i-a83t-de2-mixer-0 + * allwinner,sun8i-a83t-de2-mixer-1 + * allwinner,sun8i-h3-de2-mixer-0 + * allwinner,sun8i-v3s-de2-mixer + - reg: base address and size of the memory-mapped region. + - clocks: phandles to the clocks feeding the mixer + * bus: the mixer interface clock + * mod: the mixer module clock + - clock-names: the clock names mentioned above + - resets: phandles to the reset controllers driving the mixer + +- ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoints, the second one the output + + +Display Engine Pipeline +----------------------- + +The display engine pipeline (and its entry point, since it can be +either directly the backend or the frontend) is represented as an +extra node. + +Required properties: + - compatible: value must be one of: + * allwinner,sun4i-a10-display-engine + * allwinner,sun5i-a10s-display-engine + * allwinner,sun5i-a13-display-engine + * allwinner,sun6i-a31-display-engine + * allwinner,sun6i-a31s-display-engine + * allwinner,sun7i-a20-display-engine + * allwinner,sun8i-a33-display-engine + * allwinner,sun8i-a83t-display-engine + * allwinner,sun8i-h3-display-engine + * allwinner,sun8i-r40-display-engine + * allwinner,sun8i-v3s-display-engine + * allwinner,sun9i-a80-display-engine + + - allwinner,pipelines: list of phandle to the display engine + frontends (DE 1.0) or mixers (DE 2.0) available. + +Example: + +panel: panel { + compatible = "olimex,lcd-olinuxino-43-ts"; + #address-cells = <1>; + #size-cells = <0>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint { + remote-endpoint = <&tcon0_out_panel>; + }; + }; +}; + +connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; +}; + +hdmi: hdmi@1c16000 { + compatible = "allwinner,sun5i-a10s-hdmi"; + reg = <0x01c16000 0x1000>; + interrupts = <58>; + clocks = <&ccu CLK_AHB_HDMI>, <&ccu CLK_HDMI>, + <&ccu CLK_PLL_VIDEO0_2X>, + <&ccu CLK_PLL_VIDEO1_2X>; + clock-names = "ahb", "mod", "pll-0", "pll-1"; + dmas = <&dma SUN4I_DMA_NORMAL 16>, + <&dma SUN4I_DMA_NORMAL 16>, + <&dma SUN4I_DMA_DEDICATED 24>; + dma-names = "ddc-tx", "ddc-rx", "audio-tx"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + hdmi_in_tcon0: endpoint { + remote-endpoint = <&tcon0_out_hdmi>; + }; + }; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; + }; + }; +}; + +tve0: tv-encoder@1c0a000 { + compatible = "allwinner,sun4i-a10-tv-encoder"; + reg = <0x01c0a000 0x1000>; + clocks = <&ahb_gates 34>; + resets = <&tcon_ch0_clk 0>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + tve0_in_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_out_tve0>; + }; + }; +}; + +tcon0: lcd-controller@1c0c000 { + compatible = "allwinner,sun5i-a13-tcon"; + reg = <0x01c0c000 0x1000>; + interrupts = <44>; + resets = <&tcon_ch0_clk 1>; + reset-names = "lcd"; + clocks = <&ahb_gates 36>, + <&tcon_ch0_clk>, + <&tcon_ch1_clk>; + clock-names = "ahb", + "tcon-ch0", + "tcon-ch1"; + clock-output-names = "tcon-pixel-clock"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + tcon0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + tcon0_in_be0: endpoint@0 { + reg = <0>; + remote-endpoint = <&be0_out_tcon0>; + }; + }; + + tcon0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + tcon0_out_panel: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + + tcon0_out_tve0: endpoint@1 { + reg = <1>; + remote-endpoint = <&tve0_in_tcon0>; + }; + }; + }; +}; + +fe0: display-frontend@1e00000 { + compatible = "allwinner,sun5i-a13-display-frontend"; + reg = <0x01e00000 0x20000>; + interrupts = <47>; + clocks = <&ahb_gates 46>, <&de_fe_clk>, + <&dram_gates 25>; + clock-names = "ahb", "mod", + "ram"; + resets = <&de_fe_clk>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + fe0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + fe0_out_be0: endpoint { + remote-endpoint = <&be0_in_fe0>; + }; + }; + }; +}; + +be0: display-backend@1e60000 { + compatible = "allwinner,sun5i-a13-display-backend"; + reg = <0x01e60000 0x10000>; + interrupts = <47>; + clocks = <&ahb_gates 44>, <&de_be_clk>, + <&dram_gates 26>; + clock-names = "ahb", "mod", + "ram"; + resets = <&de_be_clk>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + be0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + be0_in_fe0: endpoint@0 { + reg = <0>; + remote-endpoint = <&fe0_out_be0>; + }; + }; + + be0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + be0_out_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_in_be0>; + }; + }; + }; +}; + +display-engine { + compatible = "allwinner,sun5i-a13-display-engine"; + allwinner,pipelines = <&fe0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/sunxi/sun6i-dsi.txt b/arch/arm64/boot/dts/vendor/bindings/display/sunxi/sun6i-dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a6cf5de08b0c445718ab71a8071a30e8d13a300 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/sunxi/sun6i-dsi.txt @@ -0,0 +1,93 @@ +Allwinner A31 DSI Encoder +========================= + +The DSI pipeline consists of two separate blocks: the DSI controller +itself, and its associated D-PHY. + +DSI Encoder +----------- + +The DSI Encoder generates the DSI signal from the TCON's. + +Required properties: + - compatible: value must be one of: + * allwinner,sun6i-a31-mipi-dsi + - reg: base address and size of memory-mapped region + - interrupts: interrupt associated to this IP + - clocks: phandles to the clocks feeding the DSI encoder + * bus: the DSI interface clock + * mod: the DSI module clock + - clock-names: the clock names mentioned above + - phys: phandle to the D-PHY + - phy-names: must be "dphy" + - resets: phandle to the reset controller driving the encoder + + - ports: A ports node with endpoint definitions as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + first port should be the input endpoint, usually coming from the + associated TCON. + +Any MIPI-DSI device attached to this should be described according to +the bindings defined in ../mipi-dsi-bus.txt + +D-PHY +----- + +Required properties: + - compatible: value must be one of: + * allwinner,sun6i-a31-mipi-dphy + - reg: base address and size of memory-mapped region + - clocks: phandles to the clocks feeding the DSI encoder + * bus: the DSI interface clock + * mod: the DSI module clock + - clock-names: the clock names mentioned above + - resets: phandle to the reset controller driving the encoder + +Example: + +dsi0: dsi@1ca0000 { + compatible = "allwinner,sun6i-a31-mipi-dsi"; + reg = <0x01ca0000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_MIPI_DSI>, + <&ccu CLK_DSI_SCLK>; + clock-names = "bus", "mod"; + resets = <&ccu RST_BUS_MIPI_DSI>; + phys = <&dphy0>; + phy-names = "dphy"; + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "bananapi,lhr050h41", "ilitek,ili9881c"; + reg = <0>; + power-gpios = <&pio 1 7 GPIO_ACTIVE_HIGH>; /* PB07 */ + reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */ + backlight = <&pwm_bl>; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + dsi0_in_tcon0: endpoint { + remote-endpoint = <&tcon0_out_dsi0>; + }; + }; + }; +}; + +dphy0: d-phy@1ca1000 { + compatible = "allwinner,sun6i-a31-mipi-dphy"; + reg = <0x01ca1000 0x1000>; + clocks = <&ccu CLK_BUS_MIPI_DSI>, + <&ccu CLK_DSI_DPHY>; + clock-names = "bus", "mod"; + resets = <&ccu RST_BUS_MIPI_DSI>; + #phy-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/tegra/nvidia,tegra114-mipi.txt b/arch/arm64/boot/dts/vendor/bindings/display/tegra/nvidia,tegra114-mipi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4a25cedc5cf4a523a53cdffe6c88ebe0f8b3093 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/tegra/nvidia,tegra114-mipi.txt @@ -0,0 +1,41 @@ +NVIDIA Tegra MIPI pad calibration controller + +Required properties: +- compatible: "nvidia,tegra-mipi" +- reg: Physical base address and length of the controller's registers. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - mipi-cal +- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads + that need to be calibrated for a given device. + +User nodes need to contain an nvidia,mipi-calibrate property that has a +phandle to refer to the calibration controller node and a bitmask of the pads +that need to be calibrated. + +Example: + + mipi: mipi@700e3000 { + compatible = "nvidia,tegra114-mipi"; + reg = <0x700e3000 0x100>; + clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>; + clock-names = "mipi-cal"; + #nvidia,mipi-calibrate-cells = <1>; + }; + + ... + + host1x@50000000 { + ... + + dsi@54300000 { + ... + + nvidia,mipi-calibrate = <&mipi 0x060>; + + ... + }; + + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/tegra/nvidia,tegra20-host1x.txt b/arch/arm64/boot/dts/vendor/bindings/display/tegra/nvidia,tegra20-host1x.txt new file mode 100644 index 0000000000000000000000000000000000000000..593be44a53c9527774c35ca9331f9b25e23d97cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -0,0 +1,416 @@ +NVIDIA Tegra host1x + +Required properties: +- compatible: "nvidia,tegra-host1x" +- reg: Physical base address and length of the controller's registers. + For pre-Tegra186, one entry describing the whole register area. + For Tegra186, one entry for each entry in reg-names: + "vm" - VM region assigned to Linux + "hypervisor" - Hypervisor region (only if Linux acts as hypervisor) +- interrupts: The interrupt outputs from the controller. +- #address-cells: The number of cells used to represent physical base addresses + in the host1x address space. Should be 1. +- #size-cells: The number of cells used to represent the size of an address + range in the host1x address space. Should be 1. +- ranges: The mapping of the host1x address space to the CPU address space. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - host1x + +The host1x top-level node defines a number of children, each representing one +of the following host1x client modules: + +- mpe: video encoder + + Required properties: + - compatible: "nvidia,tegra-mpe" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - mpe + +- vi: video input + + Required properties: + - compatible: "nvidia,tegra-vi" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - vi + +- epp: encoder pre-processor + + Required properties: + - compatible: "nvidia,tegra-epp" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - epp + +- isp: image signal processor + + Required properties: + - compatible: "nvidia,tegra-isp" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - isp + +- gr2d: 2D graphics engine + + Required properties: + - compatible: "nvidia,tegra-gr2d" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - 2d + +- gr3d: 3D graphics engine + + Required properties: + - compatible: "nvidia,tegra-gr3d" + - reg: Physical base address and length of the controller's registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + (This property may be omitted if the only clock in the list is "3d") + - 3d + This MUST be the first entry. + - 3d2 (Only required on SoCs with two 3D clocks) + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - 3d + - 3d2 (Only required on SoCs with two 3D clocks) + +- dc: display controller + + Required properties: + - compatible: "nvidia,tegra-dc" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - dc + This MUST be the first entry. + - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dc + - nvidia,head: The number of the display controller head. This is used to + setup the various types of output to receive video data from the given + head. + + Each display controller node has a child node, named "rgb", that represents + the RGB output associated with the controller. It can take the following + optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel + +- hdmi: High Definition Multimedia Interface + + Required properties: + - compatible: "nvidia,tegra-hdmi" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - hdmi-supply: supply for the +5V HDMI connector pin + - vdd-supply: regulator for supply voltage + - pll-supply: regulator for PLL + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - hdmi + This MUST be the first entry. + - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - hdmi + + Optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel + +- tvo: TV encoder output + + Required properties: + - compatible: "nvidia,tegra-tvo" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +- dsi: display serial interface + + Required properties: + - compatible: "nvidia,tegra-dsi" + - reg: Physical base address and length of the controller's registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - dsi + This MUST be the first entry. + - lp + - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dsi + - avdd-dsi-supply: phandle of a supply that powers the DSI controller + - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying + which pads are used by this DSI output and need to be calibrated. See also + ../display/tegra/nvidia,tegra114-mipi.txt. + + Optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel + - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang + up with in order to support up to 8 data lanes + +- sor: serial output resource + + Required properties: + - compatible: Should be: + - "nvidia,tegra124-sor": for Tegra124 and Tegra132 + - "nvidia,tegra132-sor": for Tegra132 + - "nvidia,tegra210-sor": for Tegra210 + - "nvidia,tegra210-sor1": for Tegra210 + - "nvidia,tegra186-sor": for Tegra186 + - "nvidia,tegra186-sor1": for Tegra186 + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - sor: clock input for the SOR hardware + - out: SOR output clock + - parent: input for the pixel clock + - dp: reference clock for the SOR clock + - safe: safe reference for the SOR clock during power up + + For Tegra186 and later: + - pad: SOR pad output clock (on Tegra186 and later) + + Obsolete: + - source: source clock for the SOR clock (obsolete, use "out" instead) + + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - sor + + Required properties on Tegra186 and later: + - nvidia,interface: index of the SOR interface + + Optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel + + Optional properties when driving an eDP output: + - nvidia,dpaux: phandle to a DispayPort AUX interface + +- dpaux: DisplayPort AUX interface + - compatible : Should contain one of the following: + - "nvidia,tegra124-dpaux": for Tegra124 and Tegra132 + - "nvidia,tegra210-dpaux": for Tegra210 + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - dpaux: clock input for the DPAUX hardware + - parent: reference clock + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dpaux + - vdd-supply: phandle of a supply that powers the DisplayPort link + - i2c-bus: Subnode where I2C slave devices are listed. This subnode + must be always present. If there are no I2C slave devices, an empty + node should be added. See ../../i2c/i2c.txt for more information. + + See ../pinctrl/nvidia,tegra124-dpaux-padctl.txt for information + regarding the DPAUX pad controller bindings. + +- vic: Video Image Compositor + - compatible : "nvidia,tegra-vic" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - vic: clock input for the VIC hardware + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - vic + +Example: + +/ { + ... + + host1x { + compatible = "nvidia,tegra20-host1x", "simple-bus"; + reg = <0x50000000 0x00024000>; + interrupts = <0 65 0x04 /* mpcore syncpt */ + 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car TEGRA20_CLK_HOST1X>; + resets = <&tegra_car 28>; + reset-names = "host1x"; + + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x54000000 0x54000000 0x04000000>; + + mpe { + compatible = "nvidia,tegra20-mpe"; + reg = <0x54040000 0x00040000>; + interrupts = <0 68 0x04>; + clocks = <&tegra_car TEGRA20_CLK_MPE>; + resets = <&tegra_car 60>; + reset-names = "mpe"; + }; + + vi { + compatible = "nvidia,tegra20-vi"; + reg = <0x54080000 0x00040000>; + interrupts = <0 69 0x04>; + clocks = <&tegra_car TEGRA20_CLK_VI>; + resets = <&tegra_car 100>; + reset-names = "vi"; + }; + + epp { + compatible = "nvidia,tegra20-epp"; + reg = <0x540c0000 0x00040000>; + interrupts = <0 70 0x04>; + clocks = <&tegra_car TEGRA20_CLK_EPP>; + resets = <&tegra_car 19>; + reset-names = "epp"; + }; + + isp { + compatible = "nvidia,tegra20-isp"; + reg = <0x54100000 0x00040000>; + interrupts = <0 71 0x04>; + clocks = <&tegra_car TEGRA20_CLK_ISP>; + resets = <&tegra_car 23>; + reset-names = "isp"; + }; + + gr2d { + compatible = "nvidia,tegra20-gr2d"; + reg = <0x54140000 0x00040000>; + interrupts = <0 72 0x04>; + clocks = <&tegra_car TEGRA20_CLK_GR2D>; + resets = <&tegra_car 21>; + reset-names = "2d"; + }; + + gr3d { + compatible = "nvidia,tegra20-gr3d"; + reg = <0x54180000 0x00040000>; + clocks = <&tegra_car TEGRA20_CLK_GR3D>; + resets = <&tegra_car 24>; + reset-names = "3d"; + }; + + dc@54200000 { + compatible = "nvidia,tegra20-dc"; + reg = <0x54200000 0x00040000>; + interrupts = <0 73 0x04>; + clocks = <&tegra_car TEGRA20_CLK_DISP1>, + <&tegra_car TEGRA20_CLK_PLL_P>; + clock-names = "dc", "parent"; + resets = <&tegra_car 27>; + reset-names = "dc"; + + rgb { + status = "disabled"; + }; + }; + + dc@54240000 { + compatible = "nvidia,tegra20-dc"; + reg = <0x54240000 0x00040000>; + interrupts = <0 74 0x04>; + clocks = <&tegra_car TEGRA20_CLK_DISP2>, + <&tegra_car TEGRA20_CLK_PLL_P>; + clock-names = "dc", "parent"; + resets = <&tegra_car 26>; + reset-names = "dc"; + + rgb { + status = "disabled"; + }; + }; + + hdmi { + compatible = "nvidia,tegra20-hdmi"; + reg = <0x54280000 0x00040000>; + interrupts = <0 75 0x04>; + clocks = <&tegra_car TEGRA20_CLK_HDMI>, + <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; + clock-names = "hdmi", "parent"; + resets = <&tegra_car 51>; + reset-names = "hdmi"; + status = "disabled"; + }; + + tvo { + compatible = "nvidia,tegra20-tvo"; + reg = <0x542c0000 0x00040000>; + interrupts = <0 76 0x04>; + clocks = <&tegra_car TEGRA20_CLK_TVO>; + status = "disabled"; + }; + + dsi { + compatible = "nvidia,tegra20-dsi"; + reg = <0x54300000 0x00040000>; + clocks = <&tegra_car TEGRA20_CLK_DSI>, + <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; + clock-names = "dsi", "parent"; + resets = <&tegra_car 48>; + reset-names = "dsi"; + status = "disabled"; + }; + }; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,dra7-dss.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,dra7-dss.txt new file mode 100644 index 0000000000000000000000000000000000000000..91279f1060fe1a4f58ae0b4908dee632e98e6b11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,dra7-dss.txt @@ -0,0 +1,74 @@ +Texas Instruments DRA7x Display Subsystem +========================================= + +See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,dra7-dss" +- reg: address and length of the register spaces for 'dss' +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" +- syscon: phandle to control module core syscon node + +Optional properties: + +Some DRA7xx SoCs have one dedicated video PLL, some have two. These properties +can be used to describe the video PLLs: + +- reg: address and length of the register spaces for 'pll1_clkctrl', + 'pll1', 'pll2_clkctrl', 'pll2' +- clocks: handle to video1 pll clock and video2 pll clock +- clock-names: "video1_clk" and "video2_clk" + +Required nodes: +- DISPC + +Optional nodes: +- DSS Submodules: HDMI +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,dra7-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + +Optional properties: +- max-memory-bandwidth: Input memory (from main memory to dispc) bandwidth limit + in bytes per second + + +HDMI +---- + +Required properties: +- compatible: "ti,dra7-hdmi" +- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy', + 'core' +- reg-names: "wp", "pll", "phy", "core" +- interrupts: the HDMI interrupt line +- ti,hwmods: "dss_hdmi" +- vdda-supply: vdda power supply +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for HDMI output + +HDMI Endpoint optional properties: +- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-, + D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7) diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap-dss.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap-dss.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1ef29569338f32d0934f7d560eb881709e67a2e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap-dss.txt @@ -0,0 +1,211 @@ +Texas Instruments OMAP Display Subsystem +======================================== + +Generic Description +------------------- + +This document is a generic description of the OMAP Display Subsystem bindings. +Binding details for each OMAP SoC version are described in respective binding +documentation. + +The OMAP Display Subsystem (DSS) hardware consists of DSS Core, DISPC module and +a number of encoder modules. All DSS versions contain DSS Core and DISPC, but +the encoder modules vary. + +The DSS Core is the parent of the other DSS modules, and manages clock routing, +integration to the SoC, etc. + +DISPC is the display controller, which reads pixels from the memory and outputs +a RGB pixel stream to encoders. + +The encoder modules encode the received RGB pixel stream to a video output like +HDMI, MIPI DPI, etc. + +Video Ports +----------- + +The DSS Core and the encoders have video port outputs. The structure of the +video ports is described in Documentation/devicetree/bindings/graph.txt, +and the properties for the ports and endpoints for each encoder are +described in the SoC's DSS binding documentation. + +The video ports are used to describe the connections to external hardware, like +panels or external encoders. + +Aliases +------- + +The board dts file may define aliases for displays to assign "displayX" style +name for each display. If no aliases are defined, a semi-random number is used +for the display. + +Example +------- + +A shortened example of the DSS description for OMAP4, with non-relevant parts +removed, defined in omap4.dtsi: + +dss: dss@58000000 { + compatible = "ti,omap4-dss"; + reg = <0x58000000 0x80>; + status = "disabled"; + ti,hwmods = "dss_core"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@58001000 { + compatible = "ti,omap4-dispc"; + reg = <0x58001000 0x1000>; + interrupts = ; + ti,hwmods = "dss_dispc"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + }; + + hdmi: encoder@58006000 { + compatible = "ti,omap4-hdmi"; + reg = <0x58006000 0x200>, + <0x58006200 0x100>, + <0x58006300 0x100>, + <0x58006400 0x1000>; + reg-names = "wp", "pll", "phy", "core"; + interrupts = ; + status = "disabled"; + ti,hwmods = "dss_hdmi"; + clocks = <&dss_48mhz_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; +}; + +A shortened example of the board description for OMAP4 Panda board, defined in +omap4-panda.dts. + +The Panda board has a DVI and a HDMI connector, and the board contains a TFP410 +chip (MIPI DPI to DVI encoder) and a TPD12S015 chip (HDMI ESD protection & level +shifter). The video pipelines for the connectors are formed as follows: + +DSS Core --(MIPI DPI)--> TFP410 --(DVI)--> DVI Connector +OMAP HDMI --(HDMI)--> TPD12S015 --(HDMI)--> HDMI Connector + +/ { + aliases { + display0 = &dvi0; + display1 = &hdmi0; + }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; /* 0, power-down */ + + pinctrl-names = "default"; + pinctrl-0 = <&tfp410_pins>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tpd12s015: encoder@1 { + compatible = "ti,tpd12s015"; + + pinctrl-names = "default"; + pinctrl-0 = <&tpd12s015_pins>; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + + hdmi0: connector@1 { + compatible = "hdmi-connector"; + label = "hdmi"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; + }; +}; + +&dss { + status = "ok"; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_dpi_pins>; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; + +&hdmi { + status = "ok"; + vdda-supply = <&vdac>; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_hdmi_pins>; + + port { + hdmi_out: endpoint { + remote-endpoint = <&tpd12s015_in>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap2-dss.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap2-dss.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee867c4d1152e4a62b41f266b6944b943203e34c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap2-dss.txt @@ -0,0 +1,58 @@ +Texas Instruments OMAP2 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap2-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" + +Optional nodes: +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap2-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt + +Optional properties: +- max-memory-bandwidth: Input memory (from main memory to dispc) bandwidth limit + in bytes per second + + +RFBI +---- + +Required properties: +- compatible: "ti,omap2-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" + + +VENC +---- + +Required properties: +- compatible: "ti,omap2-venc" +- reg: address and length of the register space +- ti,hwmods: "dss_venc" +- vdda-supply: power supply for DAC + +VENC Endpoint required properties: + +Required properties: +- ti,invert-polarity: invert the polarity of the video signal +- ti,channels: 1 for composite, 2 for s-video diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap3-dss.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap3-dss.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd02516a40b6f0a2974a08d307ba66ec265dfc70 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap3-dss.txt @@ -0,0 +1,87 @@ +Texas Instruments OMAP3 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap3-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" + +Optional nodes: +- Video ports: + - Port 0: DPI output + - Port 1: SDI output + +DPI Endpoint required properties: +- data-lines: number of lines used + +SDI Endpoint required properties: +- datapairs: number of datapairs used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap3-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + +Optional properties: +- max-memory-bandwidth: Input memory (from main memory to dispc) bandwidth limit + in bytes per second + + +RFBI +---- + +Required properties: +- compatible: "ti,omap3-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" +- clocks: handles to fclk and iclk +- clock-names: "fck", "ick" + + +VENC +---- + +Required properties: +- compatible: "ti,omap3-venc" +- reg: address and length of the register space +- ti,hwmods: "dss_venc" +- vdda-supply: power supply for DAC +- clocks: handle to fclk +- clock-names: "fck" + +VENC Endpoint required properties: +- ti,invert-polarity: invert the polarity of the video signal +- ti,channels: 1 for composite, 2 for s-video + + +DSI +--- + +Required properties: +- compatible: "ti,omap3-dsi" +- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll' +- reg-names: "proto", "phy", "pll" +- interrupts: the DSI interrupt line +- ti,hwmods: "dss_dsi1" +- vdd-supply: power supply for DSI +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +DSI Endpoint required properties: +- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-, + DATA1+, DATA1-, ... diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap4-dss.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap4-dss.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f85f6b3a5a8b4609c7c1fe6a056d210dfc25b7c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap4-dss.txt @@ -0,0 +1,119 @@ +Texas Instruments OMAP4 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap4-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" + +Required nodes: +- DISPC + +Optional nodes: +- DSS Submodules: RFBI, VENC, DSI, HDMI +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap4-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + +Optional properties: +- max-memory-bandwidth: Input memory (from main memory to dispc) bandwidth limit + in bytes per second + + +RFBI +---- + +Required properties: +- compatible: "ti,omap4-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" +- clocks: handles to fclk and iclk +- clock-names: "fck", "ick" + +Optional nodes: +- Video port for RFBI output +- RFBI controlled peripherals + + +VENC +---- + +Required properties: +- compatible: "ti,omap4-venc" +- reg: address and length of the register space +- ti,hwmods: "dss_venc" +- vdda-supply: power supply for DAC +- clocks: handle to fclk +- clock-names: "fck" + +Optional nodes: +- Video port for VENC output + +VENC Endpoint required properties: +- ti,invert-polarity: invert the polarity of the video signal +- ti,channels: 1 for composite, 2 for s-video + + +DSI +--- + +Required properties: +- compatible: "ti,omap4-dsi" +- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll' +- reg-names: "proto", "phy", "pll" +- interrupts: the DSI interrupt line +- ti,hwmods: "dss_dsi1" or "dss_dsi2" +- vdd-supply: power supply for DSI +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for DSI output +- DSI controlled peripherals + +DSI Endpoint required properties: +- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-, + DATA1+, DATA1-, ... + + +HDMI +---- + +Required properties: +- compatible: "ti,omap4-hdmi" +- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy', + 'core' +- reg-names: "wp", "pll", "phy", "core" +- interrupts: the HDMI interrupt line +- ti,hwmods: "dss_hdmi" +- vdda-supply: vdda power supply +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for HDMI output + +HDMI Endpoint optional properties: +- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-, + D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7) diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap5-dss.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap5-dss.txt new file mode 100644 index 0000000000000000000000000000000000000000..20861218649f14412c3b280e533e6426d7e93053 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,omap5-dss.txt @@ -0,0 +1,100 @@ +Texas Instruments OMAP5 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/display/ti/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap5-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" + +Required nodes: +- DISPC + +Optional nodes: +- DSS Submodules: RFBI, DSI, HDMI +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap5-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + +Optional properties: +- max-memory-bandwidth: Input memory (from main memory to dispc) bandwidth limit + in bytes per second + + +RFBI +---- + +Required properties: +- compatible: "ti,omap5-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" +- clocks: handles to fclk and iclk +- clock-names: "fck", "ick" + +Optional nodes: +- Video port for RFBI output +- RFBI controlled peripherals + + +DSI +--- + +Required properties: +- compatible: "ti,omap5-dsi" +- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll' +- reg-names: "proto", "phy", "pll" +- interrupts: the DSI interrupt line +- ti,hwmods: "dss_dsi1" or "dss_dsi2" +- vdd-supply: power supply for DSI +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for DSI output +- DSI controlled peripherals + +DSI Endpoint required properties: +- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-, + DATA1+, DATA1-, ... + + +HDMI +---- + +Required properties: +- compatible: "ti,omap5-hdmi" +- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy', + 'core' +- reg-names: "wp", "pll", "phy", "core" +- interrupts: the HDMI interrupt line +- ti,hwmods: "dss_hdmi" +- vdda-supply: vdda power supply +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for HDMI output + +HDMI Endpoint optional properties: +- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-, + D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7) diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,opa362.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,opa362.txt new file mode 100644 index 0000000000000000000000000000000000000000..f96083c0bd177413f35d004ff93165b2a9a4d875 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,opa362.txt @@ -0,0 +1,38 @@ +OPA362 analog video amplifier + +Required properties: +- compatible: "ti,opa362" +- enable-gpios: enable/disable output gpio + +Required node: +- Video port 0 for opa362 input +- Video port 1 for opa362 output + +Example: + +tv_amp: opa362 { + compatible = "ti,opa362"; + enable-gpios = <&gpio1 23 0>; /* GPIO to enable video out amplifier */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + opa_in: endpoint@0 { + remote-endpoint = <&venc_out>; + }; + }; + + port@1 { + reg = <1>; + opa_out: endpoint@0 { + remote-endpoint = <&tv_connector_in>; + }; + }; + }; +}; + + + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,tpd12s015.txt b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,tpd12s015.txt new file mode 100644 index 0000000000000000000000000000000000000000..26e6d32e3f20522ce0abfefb5f1961d437f87559 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/ti/ti,tpd12s015.txt @@ -0,0 +1,44 @@ +TPD12S015 HDMI level shifter and ESD protection chip +==================================================== + +Required properties: +- compatible: "ti,tpd12s015" + +Optional properties: +- gpios: CT CP HPD, LS OE and HPD gpios + +Required nodes: +- Video port 0 for HDMI input +- Video port 1 for HDMI output + +Example +------- + +tpd12s015: encoder@1 { + compatible = "ti,tpd12s015"; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/panel.txt b/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..808216310ea2712a88c4ecb78bd19150af70f5ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/panel.txt @@ -0,0 +1,66 @@ +Device-Tree bindings for tilcdc DRM generic panel output driver + +Required properties: + - compatible: value should be "ti,tilcdc,panel". + - panel-info: configuration info to configure LCDC correctly for the panel + - ac-bias: AC Bias Pin Frequency + - ac-bias-intrpt: AC Bias Pin Transitions per Interrupt + - dma-burst-sz: DMA burst size + - bpp: Bits per pixel + - fdd: FIFO DMA Request Delay + - sync-edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling + - sync-ctrl: Horizontal and Vertical Sync: Control: 0=ignore + - raster-order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most + - fifo-th: DMA FIFO threshold + - display-timings: typical videomode of lcd panel. Multiple video modes + can be listed if the panel supports multiple timings, but the 'native-mode' + should be the preferred/default resolution. Refer to + Documentation/devicetree/bindings/display/panel/display-timing.txt for display + timing binding details. + +Optional properties: +- backlight: phandle of the backlight device attached to the panel +- enable-gpios: GPIO pin to enable or disable the panel + +Recommended properties: + - pinctrl-names, pinctrl-0: the pincontrol settings to configure + muxing properly for pins that connect to TFP410 device + +Example: + + /* Settings for CDTech_S035Q01 / LCD3 cape: */ + lcd3 { + compatible = "ti,tilcdc,panel"; + pinctrl-names = "default"; + pinctrl-0 = <&bone_lcd3_cape_lcd_pins>; + backlight = <&backlight>; + enable-gpios = <&gpio3 19 0>; + + panel-info { + ac-bias = <255>; + ac-bias-intrpt = <0>; + dma-burst-sz = <16>; + bpp = <16>; + fdd = <0x80>; + sync-edge = <0>; + sync-ctrl = <1>; + raster-order = <0>; + fifo-th = <0>; + }; + display-timings { + native-mode = <&timing0>; + timing0: 320x240 { + hactive = <320>; + vactive = <240>; + hback-porch = <21>; + hfront-porch = <58>; + hsync-len = <47>; + vback-porch = <11>; + vfront-porch = <23>; + vsync-len = <2>; + clock-frequency = <8000000>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/tfp410.txt b/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/tfp410.txt new file mode 100644 index 0000000000000000000000000000000000000000..a58ae7756fc6989902fcb48a8c23e33398378070 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/tfp410.txt @@ -0,0 +1,21 @@ +Device-Tree bindings for tilcdc DRM TFP410 output driver + +Required properties: + - compatible: value should be "ti,tilcdc,tfp410". + - i2c: the phandle for the i2c device to use for DDC + +Recommended properties: + - pinctrl-names, pinctrl-0: the pincontrol settings to configure + muxing properly for pins that connect to TFP410 device + - powerdn-gpio: the powerdown GPIO, pulled low to power down the + TFP410 device (for DPMS_OFF) + +Example: + + dvicape { + compatible = "ti,tilcdc,tfp410"; + i2c = <&i2c2>; + pinctrl-names = "default"; + pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>; + powerdn-gpio = <&gpio2 31 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/tilcdc.txt b/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/tilcdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bf1bb444812adc0a417e7d57e8be0ddbddc28d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/tilcdc/tilcdc.txt @@ -0,0 +1,82 @@ +Device-Tree bindings for tilcdc DRM driver + +Required properties: + - compatible: value should be one of the following: + - "ti,am33xx-tilcdc" for AM335x based boards + - "ti,da850-tilcdc" for DA850/AM18x/OMAP-L138 based boards + - interrupts: the interrupt number + - reg: base address and size of the LCDC device + +Recommended properties: + - ti,hwmods: Name of the hwmod associated to the LCDC + +Optional properties: + - max-bandwidth: The maximum pixels per second that the memory + interface / lcd controller combination can sustain + - max-width: The maximum horizontal pixel width supported by + the lcd controller. + - max-pixelclock: The maximum pixel clock that can be supported + by the lcd controller in KHz. + - blue-and-red-wiring: Recognized values "straight" or "crossed". + This property deals with the LCDC revision 2 (found on AM335x) + color errata [1]. + - "straight" indicates normal wiring that supports RGB565, + BGR888, and XBGR8888 color formats. + - "crossed" indicates wiring that has blue and red wires + crossed. This setup supports BGR565, RGB888 and XRGB8888 + formats. + - If the property is not present or its value is not recognized + the legacy mode is assumed. This configuration supports RGB565, + RGB888 and XRGB8888 formats. However, depending on wiring, the red + and blue colors are swapped in either 16 or 24-bit color modes. + +Optional nodes: + + - port/ports: to describe a connection to an external encoder. The + binding follows Documentation/devicetree/bindings/graph.txt and + supports a single port with a single endpoint. + + - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and + Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting + tfp410 DVI encoder or lcd panel to lcdc + +[1] There is an errata about AM335x color wiring. For 16-bit color mode + the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]), + but for 24 bit color modes the wiring of blue and red components is + crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is + for Blue[3-7]. For more details see section 3.1.1 in AM335x + Silicon Errata: + http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360 + +Example: + + fb: fb@4830e000 { + compatible = "ti,am33xx-tilcdc", "ti,da850-tilcdc"; + reg = <0x4830e000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <36>; + ti,hwmods = "lcdc"; + + blue-and-red-wiring = "crossed"; + + port { + lcdc_0: endpoint@0 { + remote-endpoint = <&hdmi_0>; + }; + }; + }; + + tda19988: tda19988 { + compatible = "nxp,tda998x"; + reg = <0x70>; + + pinctrl-names = "default", "off"; + pinctrl-0 = <&nxp_hdmi_bonelt_pins>; + pinctrl-1 = <&nxp_hdmi_bonelt_off_pins>; + + port { + hdmi_0: endpoint@0 { + remote-endpoint = <&lcdc_0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/via,vt8500-fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/via,vt8500-fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..2871e218a0fb7662299997b848c859b00d150435 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/via,vt8500-fb.txt @@ -0,0 +1,36 @@ +VIA VT8500 Framebuffer +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-fb" +- reg : Should contain 1 register ranges(address and length) +- interrupts : framebuffer controller interrupt +- bits-per-pixel : bit depth of framebuffer (16 or 32) + +Required subnodes: +- display-timings: see display-timing.txt for information + +Example: + + fb@d8050800 { + compatible = "via,vt8500-fb"; + reg = <0xd800e400 0x400>; + interrupts = <12>; + bits-per-pixel = <16>; + + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/display/wm,prizm-ge-rops.txt b/arch/arm64/boot/dts/vendor/bindings/display/wm,prizm-ge-rops.txt new file mode 100644 index 0000000000000000000000000000000000000000..a850fa011f029f1e6bd056bb6dca6dc684209788 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/wm,prizm-ge-rops.txt @@ -0,0 +1,13 @@ +VIA/Wondermedia Graphics Engine Controller +----------------------------------------------------- + +Required properties: +- compatible : "wm,prizm-ge-rops" +- reg : Should contain 1 register ranges(address and length) + +Example: + + ge_rops@d8050400 { + compatible = "wm,prizm-ge-rops"; + reg = <0xd8050400 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/wm,wm8505-fb.txt b/arch/arm64/boot/dts/vendor/bindings/display/wm,wm8505-fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..0bcadb2840a5c9d17d3f81dd2ef3056ed4b25381 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/wm,wm8505-fb.txt @@ -0,0 +1,33 @@ +Wondermedia WM8505 Framebuffer +----------------------------------------------------- + +Required properties: +- compatible : "wm,wm8505-fb" +- reg : Should contain 1 register ranges(address and length) +- bits-per-pixel : bit depth of framebuffer (16 or 32) + +Required subnodes: +- display-timings: see display-timing.txt for information + +Example: + + fb@d8051700 { + compatible = "wm,wm8505-fb"; + reg = <0xd8051700 0x200>; + bits-per-pixel = <16>; + + display-timings { + native-mode = <&timing0>; + timing0: 800x480 { + clock-frequency = <0>; /* unused but required */ + hactive = <800>; + vactive = <480>; + hfront-porch = <40>; + hback-porch = <88>; + hsync-len = <0>; + vback-porch = <32>; + vfront-porch = <11>; + vsync-len = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/display/zte,vou.txt b/arch/arm64/boot/dts/vendor/bindings/display/zte,vou.txt new file mode 100644 index 0000000000000000000000000000000000000000..38476475fd6031e803e0dec2b6094be1416702ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/display/zte,vou.txt @@ -0,0 +1,120 @@ +ZTE VOU Display Controller + +This is a display controller found on ZTE ZX296718 SoC. It includes multiple +Graphic Layer (GL) and Video Layer (VL), two Mixers/Channels, and a few blocks +handling scaling, color space conversion etc. VOU also integrates the support +for typical output devices, like HDMI, TV Encoder, VGA, and RGB LCD. + +* Master VOU node + +It must be the parent node of all the sub-device nodes. + +Required properties: + - compatible: should be "zte,zx296718-vou" + - #address-cells: should be <1> + - #size-cells: should be <1> + - ranges: list of address translations between VOU and sub-devices + +* VOU DPC device + +Required properties: + - compatible: should be "zte,zx296718-dpc" + - reg: Physical base address and length of DPC register regions, one for each + entry in 'reg-names' + - reg-names: The names of register regions. The following regions are required: + "osd" + "timing_ctrl" + "dtrc" + "vou_ctrl" + "otfppu" + - interrupts: VOU DPC interrupt number to CPU + - clocks: A list of phandle + clock-specifier pairs, one for each entry + in 'clock-names' + - clock-names: A list of clock names. The following clocks are required: + "aclk" + "ppu_wclk" + "main_wclk" + "aux_wclk" + +* HDMI output device + +Required properties: + - compatible: should be "zte,zx296718-hdmi" + - reg: Physical base address and length of the HDMI device IO region + - interrupts : HDMI interrupt number to CPU + - clocks: A list of phandle + clock-specifier pairs, one for each entry + in 'clock-names' + - clock-names: A list of clock names. The following clocks are required: + "osc_cec" + "osc_clk" + "xclk" + +* TV Encoder output device + +Required properties: + - compatible: should be "zte,zx296718-tvenc" + - reg: Physical base address and length of the TVENC device IO region + - zte,tvenc-power-control: the phandle to SYSCTRL block followed by two + integer cells. The first cell is the offset of SYSCTRL register used + to control TV Encoder DAC power, and the second cell is the bit mask. + +* VGA output device + +Required properties: + - compatible: should be "zte,zx296718-vga" + - reg: Physical base address and length of the VGA device IO region + - interrupts : VGA interrupt number to CPU + - clocks: Phandle with clock-specifier pointing to VGA I2C clock. + - clock-names: Must be "i2c_wclk". + - zte,vga-power-control: the phandle to SYSCTRL block followed by two + integer cells. The first cell is the offset of SYSCTRL register used + to control VGA DAC power, and the second cell is the bit mask. + +Example: + +vou: vou@1440000 { + compatible = "zte,zx296718-vou"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1440000 0x10000>; + + dpc: dpc@0 { + compatible = "zte,zx296718-dpc"; + reg = <0x0000 0x1000>, <0x1000 0x1000>, + <0x5000 0x1000>, <0x6000 0x1000>, + <0xa000 0x1000>; + reg-names = "osd", "timing_ctrl", + "dtrc", "vou_ctrl", + "otfppu"; + interrupts = ; + clocks = <&topcrm VOU_ACLK>, <&topcrm VOU_PPU_WCLK>, + <&topcrm VOU_MAIN_WCLK>, <&topcrm VOU_AUX_WCLK>; + clock-names = "aclk", "ppu_wclk", + "main_wclk", "aux_wclk"; + }; + + vga: vga@8000 { + compatible = "zte,zx296718-vga"; + reg = <0x8000 0x1000>; + interrupts = ; + clocks = <&topcrm VGA_I2C_WCLK>; + clock-names = "i2c_wclk"; + zte,vga-power-control = <&sysctrl 0x170 0xe0>; + }; + + hdmi: hdmi@c000 { + compatible = "zte,zx296718-hdmi"; + reg = <0xc000 0x4000>; + interrupts = ; + clocks = <&topcrm HDMI_OSC_CEC>, + <&topcrm HDMI_OSC_CLK>, + <&topcrm HDMI_XCLK>; + clock-names = "osc_cec", "osc_clk", "xclk"; + }; + + tvenc: tvenc@2000 { + compatible = "zte,zx296718-tvenc"; + reg = <0x2000 0x1000>; + zte,tvenc-power-control = <&sysctrl 0x170 0x10>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/adi,axi-dmac.txt b/arch/arm64/boot/dts/vendor/bindings/dma/adi,axi-dmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..47cb1d14b690f0f0c7051733f6fc6648984bd560 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/adi,axi-dmac.txt @@ -0,0 +1,61 @@ +Analog Device AXI-DMAC DMA controller + +Required properties: + - compatible: Must be "adi,axi-dmac-1.00.a". + - reg: Specification for the controllers memory mapped register map. + - interrupts: Specification for the controllers interrupt. + - clocks: Phandle and specifier to the controllers AXI interface clock + - #dma-cells: Must be 1. + +Required sub-nodes: + - adi,channels: This sub-node must contain a sub-node for each DMA channel. For + the channel sub-nodes the following bindings apply. They must match the + configuration options of the peripheral as it was instantiated. + +Required properties for adi,channels sub-node: + - #size-cells: Must be 0 + - #address-cells: Must be 1 + +Required channel sub-node properties: + - reg: Which channel this node refers to. + - adi,length-width: Width of the DMA transfer length register. + - adi,source-bus-width, + adi,destination-bus-width: Width of the source or destination bus in bits. + - adi,source-bus-type, + adi,destination-bus-type: Type of the source or destination bus. Must be one + of the following: + 0 (AXI_DMAC_TYPE_AXI_MM): Memory mapped AXI interface + 1 (AXI_DMAC_TYPE_AXI_STREAM): Streaming AXI interface + 2 (AXI_DMAC_TYPE_AXI_FIFO): FIFO interface + +Optional channel properties: + - adi,cyclic: Must be set if the channel supports hardware cyclic DMA + transfers. + - adi,2d: Must be set if the channel supports hardware 2D DMA transfers. + +DMA clients connected to the AXI-DMAC DMA controller must use the format +described in the dma.txt file using a one-cell specifier. The value of the +specifier refers to the DMA channel index. + +Example: + +dma: dma@7c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c420000 0x10000>; + interrupts = <0 57 0>; + clocks = <&clkc 16>; + #dma-cells = <1>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <32>; + adi,source-bus-type = ; + adi,destination-bus-width = <64>; + adi,destination-bus-type = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/apm-xgene-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/apm-xgene-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..c53e0b08032fe73a42f130cd790b2b1dfa753939 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/apm-xgene-dma.txt @@ -0,0 +1,47 @@ +Applied Micro X-Gene SoC DMA nodes + +DMA nodes are defined to describe on-chip DMA interfaces in +APM X-Gene SoC. + +Required properties for DMA interfaces: +- compatible: Should be "apm,xgene-dma". +- device_type: set to "dma". +- reg: Address and length of the register set for the device. + It contains the information of registers in the following order: + 1st - DMA control and status register address space. + 2nd - Descriptor ring control and status register address space. + 3rd - Descriptor ring command register address space. + 4th - Soc efuse register address space. +- interrupts: DMA has 5 interrupts sources. 1st interrupt is + DMA error reporting interrupt. 2nd, 3rd, 4th and 5th interrupts + are completion interrupts for each DMA channels. +- clocks: Reference to the clock entry. + +Optional properties: +- dma-coherent : Present if dma operations are coherent + +Example: + dmaclk: dmaclk@1f27c000 { + compatible = "apm,xgene-device-clock"; + #clock-cells = <1>; + clocks = <&socplldiv2 0>; + reg = <0x0 0x1f27c000 0x0 0x1000>; + reg-names = "csr-reg"; + clock-output-names = "dmaclk"; + }; + + dma: dma@1f270000 { + compatible = "apm,xgene-storm-dma"; + device_type = "dma"; + reg = <0x0 0x1f270000 0x0 0x10000>, + <0x0 0x1f200000 0x0 0x10000>, + <0x0 0x1b000000 0x0 0x400000>, + <0x0 0x1054a000 0x0 0x100>; + interrupts = <0x0 0x82 0x4>, + <0x0 0xb8 0x4>, + <0x0 0xb9 0x4>, + <0x0 0xba 0x4>, + <0x0 0xbb 0x4>; + dma-coherent; + clocks = <&dmaclk 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/arm-pl08x.txt b/arch/arm64/boot/dts/vendor/bindings/dma/arm-pl08x.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ba81f79266f3c8ed47a91ac79b81b2f6a0d5eb4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/arm-pl08x.txt @@ -0,0 +1,59 @@ +* ARM PrimeCells PL080 and PL081 and derivatives DMA controller + +Required properties: +- compatible: "arm,pl080", "arm,primecell"; + "arm,pl081", "arm,primecell"; + "faraday,ftdmac020", "arm,primecell" +- arm,primecell-periphid: on the FTDMAC020 the primecell ID is not hard-coded + in the hardware and must be specified here as <0x0003b080>. This number + follows the PrimeCell standard numbering using the JEP106 vendor code 0x38 + for Faraday Technology. +- reg: Address range of the PL08x registers +- interrupt: The PL08x interrupt number +- clocks: The clock running the IP core clock +- clock-names: Must contain "apb_pclk" +- lli-bus-interface-ahb1: if AHB master 1 is eligible for fetching LLIs +- lli-bus-interface-ahb2: if AHB master 2 is eligible for fetching LLIs +- mem-bus-interface-ahb1: if AHB master 1 is eligible for fetching memory contents +- mem-bus-interface-ahb2: if AHB master 2 is eligible for fetching memory contents +- #dma-cells: must be <2>. First cell should contain the DMA request, + second cell should contain either 1 or 2 depending on + which AHB master that is used. + +Optional properties: +- dma-channels: contains the total number of DMA channels supported by the DMAC +- dma-requests: contains the total number of DMA requests supported by the DMAC +- memcpy-burst-size: the size of the bursts for memcpy: 1, 4, 8, 16, 32 + 64, 128 or 256 bytes are legal values +- memcpy-bus-width: the bus width used for memcpy in bits: 8, 16 or 32 are legal + values, the Faraday FTDMAC020 can also accept 64 bits + +Clients +Required properties: +- dmas: List of DMA controller phandle, request channel and AHB master id +- dma-names: Names of the aforementioned requested channels + +Example: + +dmac0: dma-controller@10130000 { + compatible = "arm,pl080", "arm,primecell"; + reg = <0x10130000 0x1000>; + interrupt-parent = <&vica>; + interrupts = <15>; + clocks = <&hclkdma0>; + clock-names = "apb_pclk"; + lli-bus-interface-ahb1; + lli-bus-interface-ahb2; + mem-bus-interface-ahb2; + memcpy-burst-size = <256>; + memcpy-bus-width = <32>; + #dma-cells = <2>; +}; + +device@40008000 { + ... + dmas = <&dmac0 0 2 + &dmac0 1 2>; + dma-names = "tx", "rx"; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/arm-pl330.txt b/arch/arm64/boot/dts/vendor/bindings/dma/arm-pl330.txt new file mode 100644 index 0000000000000000000000000000000000000000..db7e2260f9c5749e510a19e6d275e7bbfdaff467 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/arm-pl330.txt @@ -0,0 +1,45 @@ +* ARM PrimeCell PL330 DMA Controller + +The ARM PrimeCell PL330 DMA controller can move blocks of memory contents +between memory and peripherals or memory to memory. + +Required properties: + - compatible: should include both "arm,pl330" and "arm,primecell". + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + +Optional properties: + - dma-coherent : Present if dma operations are coherent + - #dma-cells: must be <1>. used to represent the number of integer + cells in the dmas property of client device. + - dma-channels: contains the total number of DMA channels supported by the DMAC + - dma-requests: contains the total number of DMA requests supported by the DMAC + - arm,pl330-broken-no-flushp: quirk for avoiding to execute DMAFLUSHP + +Example: + + pdma0: pdma@12680000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x12680000 0x1000>; + interrupts = <99>; + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <32>; + }; + +Client drivers (device nodes requiring dma transfers from dev-to-mem or +mem-to-dev) should specify the DMA channel numbers and dma channel names +as shown below. + + [property name] = <[phandle of the dma controller] [dma request id]>; + [property name] = <[dma channel name]> + + where 'dma request id' is the dma request number which is connected + to the client controller. The 'property name' 'dmas' and 'dma-names' + as required by the generic dma device tree binding helpers. The dma + names correspond 1:1 with the dma request ids in the dmas property. + + Example: dmas = <&pdma0 12 + &pdma1 11>; + dma-names = "tx", "rx"; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/atmel-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/atmel-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..f69bcf5a6343bf314b5eef199999c5a676131e74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/atmel-dma.txt @@ -0,0 +1,42 @@ +* Atmel Direct Memory Access Controller (DMA) + +Required properties: +- compatible: Should be "atmel,-dma". +- reg: Should contain DMA registers location and length. +- interrupts: Should contain DMA interrupt. +- #dma-cells: Must be <2>, used to represent the number of integer cells in +the dmas property of client devices. + +Example: + +dma0: dma@ffffec00 { + compatible = "atmel,at91sam9g45-dma"; + reg = <0xffffec00 0x200>; + interrupts = <21>; + #dma-cells = <2>; +}; + +DMA clients connected to the Atmel DMA controller must use the format +described in the dma.txt file, using a three-cell specifier for each channel: +a phandle plus two integer cells. +The three cells in order are: + +1. A phandle pointing to the DMA controller. +2. The memory interface (16 most significant bits), the peripheral interface +(16 less significant bits). +3. Parameters for the at91 DMA configuration register which are device +dependent: + - bit 7-0: peripheral identifier for the hardware handshaking interface. The + identifier can be different for tx and rx. + - bit 11-8: FIFO configuration. 0 for half FIFO, 1 for ALAP, 2 for ASAP. + +Example: + +i2c0@i2c@f8010000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8010000 0x100>; + interrupts = <9 4 6>; + dmas = <&dma0 1 7>, + <&dma0 1 8>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/atmel-xdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/atmel-xdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..0eb2b3207e08826214ede46b964e334cb57db619 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/atmel-xdma.txt @@ -0,0 +1,54 @@ +* Atmel Extensible Direct Memory Access Controller (XDMAC) + +* XDMA Controller +Required properties: +- compatible: Should be "atmel,-dma". + compatible description: + - sama5d4: first SoC adding the XDMAC +- reg: Should contain DMA registers location and length. +- interrupts: Should contain DMA interrupt. +- #dma-cells: Must be <1>, used to represent the number of integer cells in +the dmas property of client devices. + - The 1st cell specifies the channel configuration register: + - bit 13: SIF, source interface identifier, used to get the memory + interface identifier, + - bit 14: DIF, destination interface identifier, used to get the peripheral + interface identifier, + - bit 30-24: PERID, peripheral identifier. + +Example: + +dma1: dma-controller@f0004000 { + compatible = "atmel,sama5d4-dma"; + reg = <0xf0004000 0x200>; + interrupts = <50 4 0>; + #dma-cells = <1>; +}; + + +* DMA clients +DMA clients connected to the Atmel XDMA controller must use the format +described in the dma.txt file, using a one-cell specifier for each channel. +The two cells in order are: +1. A phandle pointing to the DMA controller. +2. Channel configuration register. Configurable fields are: + - bit 13: SIF, source interface identifier, used to get the memory + interface identifier, + - bit 14: DIF, destination interface identifier, used to get the peripheral + interface identifier, + - bit 30-24: PERID, peripheral identifier. + +Example: + +i2c2: i2c@f8024000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8024000 0x4000>; + interrupts = <34 4 6>; + dmas = <&dma1 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(6))>, + <&dma1 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(7))>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/brcm,bcm2835-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/brcm,bcm2835-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6a8cc0978cd5ff91965b7b3cf93813b80972a3e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/brcm,bcm2835-dma.txt @@ -0,0 +1,83 @@ +* BCM2835 DMA controller + +The BCM2835 DMA controller has 16 channels in total. +Only the lower 13 channels have an associated IRQ. +Some arbitrary channels are used by the firmware +(1,3,6,7 in the current firmware version). +The channels 0,2 and 3 have special functionality +and should not be used by the driver. + +Required properties: +- compatible: Should be "brcm,bcm2835-dma". +- reg: Should contain DMA registers location and length. +- interrupts: Should contain the DMA interrupts associated + to the DMA channels in ascending order. +- interrupt-names: Should contain the names of the interrupt + in the form "dmaXX". + Use "dma-shared-all" for the common interrupt line + that is shared by all dma channels. +- #dma-cells: Must be <1>, the cell in the dmas property of the + client device represents the DREQ number. +- brcm,dma-channel-mask: Bit mask representing the channels + not used by the firmware in ascending order, + i.e. first channel corresponds to LSB. + +Example: + +dma: dma@7e007000 { + compatible = "brcm,bcm2835-dma"; + reg = <0x7e007000 0xf00>; + interrupts = <1 16>, + <1 17>, + <1 18>, + <1 19>, + <1 20>, + <1 21>, + <1 22>, + <1 23>, + <1 24>, + <1 25>, + <1 26>, + /* dma channel 11-14 share one irq */ + <1 27>, + <1 27>, + <1 27>, + <1 27>, + /* unused shared irq for all channels */ + <1 28>; + interrupt-names = "dma0", + "dma1", + "dma2", + "dma3", + "dma4", + "dma5", + "dma6", + "dma7", + "dma8", + "dma9", + "dma10", + "dma11", + "dma12", + "dma13", + "dma14", + "dma-shared-all"; + + #dma-cells = <1>; + brcm,dma-channel-mask = <0x7f35>; +}; + + +DMA clients connected to the BCM2835 DMA controller must use the format +described in the dma.txt file, using a two-cell specifier for each channel. + +Example: + +bcm2835_i2s: i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; + reg = < 0x7e203000 0x24>; + clocks = <&clocks BCM2835_CLOCK_PCM>; + + dmas = <&dma 2>, + <&dma 3>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/brcm,iproc-sba.txt b/arch/arm64/boot/dts/vendor/bindings/dma/brcm,iproc-sba.txt new file mode 100644 index 0000000000000000000000000000000000000000..092913a284577c50547af6b1e67467edca91606a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/brcm,iproc-sba.txt @@ -0,0 +1,29 @@ +* Broadcom SBA RAID engine + +Required properties: +- compatible: Should be one of the following + "brcm,iproc-sba" + "brcm,iproc-sba-v2" + The "brcm,iproc-sba" has support for only 6 PQ coefficients + The "brcm,iproc-sba-v2" has support for only 30 PQ coefficients +- mboxes: List of phandle and mailbox channel specifiers + +Example: + +raid_mbox: mbox@67400000 { + ... + #mbox-cells = <3>; + ... +}; + +raid0 { + compatible = "brcm,iproc-sba-v2"; + mboxes = <&raid_mbox 0 0x1 0xffff>, + <&raid_mbox 1 0x1 0xffff>, + <&raid_mbox 2 0x1 0xffff>, + <&raid_mbox 3 0x1 0xffff>, + <&raid_mbox 4 0x1 0xffff>, + <&raid_mbox 5 0x1 0xffff>, + <&raid_mbox 6 0x1 0xffff>, + <&raid_mbox 7 0x1 0xffff>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..6312fb00ce8d31d0c8c455af0e82e3a3d86ff008 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/dma.txt @@ -0,0 +1,109 @@ +* Generic DMA Controller and DMA request bindings + +Generic binding to provide a way for a driver using DMA Engine to retrieve the +DMA request or channel information that goes from a hardware device to a DMA +controller. + + +* DMA controller + +Required property: +- #dma-cells: Must be at least 1. Used to provide DMA controller + specific information. See DMA client binding below for + more details. + +Optional properties: +- dma-channels: Number of DMA channels supported by the controller. +- dma-requests: Number of DMA request signals supported by the + controller. + +Example: + + dma: dma@48000000 { + compatible = "ti,omap-sdma"; + reg = <0x48000000 0x1000>; + interrupts = <0 12 0x4 + 0 13 0x4 + 0 14 0x4 + 0 15 0x4>; + #dma-cells = <1>; + dma-channels = <32>; + dma-requests = <127>; + }; + +* DMA router + +DMA routers are transparent IP blocks used to route DMA request lines from +devices to the DMA controller. Some SoCs (like TI DRA7x) have more peripherals +integrated with DMA requests than what the DMA controller can handle directly. + +Required property: +- dma-masters: phandle of the DMA controller or list of phandles for + the DMA controllers the router can direct the signal to. +- #dma-cells: Must be at least 1. Used to provide DMA router specific + information. See DMA client binding below for more + details. + +Optional properties: +- dma-requests: Number of incoming request lines the router can handle. +- In the node pointed by the dma-masters: + - dma-requests: The router driver might need to look for this in order + to configure the routing. + +Example: + sdma_xbar: dma-router@4a002b78 { + compatible = "ti,dra7-dma-crossbar"; + reg = <0x4a002b78 0xfc>; + #dma-cells = <1>; + dma-requests = <205>; + ti,dma-safe-map = <0>; + dma-masters = <&sdma>; + }; + +* DMA client + +Client drivers should specify the DMA property using a phandle to the controller +followed by DMA controller specific data. + +Required property: +- dmas: List of one or more DMA specifiers, each consisting of + - A phandle pointing to DMA controller node + - A number of integer cells, as determined by the + #dma-cells property in the node referenced by phandle + containing DMA controller specific information. This + typically contains a DMA request line number or a + channel number, but can contain any data that is + required for configuring a channel. +- dma-names: Contains one identifier string for each DMA specifier in + the dmas property. The specific strings that can be used + are defined in the binding of the DMA client device. + Multiple DMA specifiers can be used to represent + alternatives and in this case the dma-names for those + DMA specifiers must be identical (see examples). + +Examples: + +1. A device with one DMA read channel, one DMA write channel: + + i2c1: i2c@1 { + ... + dmas = <&dma 2 /* read channel */ + &dma 3>; /* write channel */ + dma-names = "rx", "tx"; + ... + }; + +2. A single read-write channel with three alternative DMA controllers: + + dmas = <&dma1 5 + &dma2 7 + &dma3 2>; + dma-names = "rx-tx", "rx-tx", "rx-tx"; + +3. A device with three channels, one of which has two alternatives: + + dmas = <&dma1 2 /* read channel */ + &dma1 3 /* write channel */ + &dma2 0 /* error read */ + &dma3 0>; /* alternative error read */ + dma-names = "rx", "tx", "error", "error"; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/fsl-edma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-edma.txt new file mode 100644 index 0000000000000000000000000000000000000000..97e213e07660816a2f81d19f400b104e09b1fe90 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-edma.txt @@ -0,0 +1,75 @@ +* Freescale enhanced Direct Memory Access(eDMA) Controller + + The eDMA channels have multiplex capability by programmble memory-mapped +registers. channels are split into two groups, called DMAMUX0 and DMAMUX1, +specific DMA request source can only be multiplexed by any channel of certain +group, DMAMUX0 or DMAMUX1, but not both. + +* eDMA Controller +Required properties: +- compatible : + - "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC +- reg : Specifies base physical address(s) and size of the eDMA registers. + The 1st region is eDMA control register's address and size. + The 2nd and the 3rd regions are programmable channel multiplexing + control register's address and size. +- interrupts : A list of interrupt-specifiers, one for each entry in + interrupt-names. +- interrupt-names : Should contain: + "edma-tx" - the transmission interrupt + "edma-err" - the error interrupt +- #dma-cells : Must be <2>. + The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1). + Specific request source can only be multiplexed by specific channels + group called DMAMUX. + The 2nd cell specifies the request source(slot) ID. + See the SoC's reference manual for all the supported request sources. +- dma-channels : Number of channels supported by the controller +- clock-names : A list of channel group clock names. Should contain: + "dmamux0" - clock name of mux0 group + "dmamux1" - clock name of mux1 group +- clocks : A list of phandle and clock-specifier pairs, one for each entry in + clock-names. + +Optional properties: +- big-endian: If present registers and hardware scatter/gather descriptors + of the eDMA are implemented in big endian mode, otherwise in little + mode. + + +Examples: + +edma0: dma-controller@40018000 { + #dma-cells = <2>; + compatible = "fsl,vf610-edma"; + reg = <0x40018000 0x2000>, + <0x40024000 0x1000>, + <0x40025000 0x1000>; + interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>, + <0 9 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "edma-tx", "edma-err"; + dma-channels = <32>; + clock-names = "dmamux0", "dmamux1"; + clocks = <&clks VF610_CLK_DMAMUX0>, + <&clks VF610_CLK_DMAMUX1>; +}; + + +* DMA clients +DMA client drivers that uses the DMA function must use the format described +in the dma.txt file, using a two-cell specifier for each channel: the 1st +specifies the channel group(DMAMUX) in which this request can be multiplexed, +and the 2nd specifies the request source. + +Examples: + +sai2: sai@40031000 { + compatible = "fsl,vf610-sai"; + reg = <0x40031000 0x1000>; + interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "sai"; + clocks = <&clks VF610_CLK_SAI2>; + dma-names = "tx", "rx"; + dmas = <&edma0 0 21>, + <&edma0 0 20>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/fsl-imx-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-imx-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bd8847d6394e6bbfb7df8b43eea2af4375cc883 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-imx-dma.txt @@ -0,0 +1,48 @@ +* Freescale Direct Memory Access (DMA) Controller for i.MX + +This document will only describe differences to the generic DMA Controller and +DMA request bindings as described in dma/dma.txt . + +* DMA controller + +Required properties: +- compatible : Should be "fsl,-dma". chip can be imx1, imx21 or imx27 +- reg : Should contain DMA registers location and length +- interrupts : First item should be DMA interrupt, second one is optional and + should contain DMA Error interrupt +- #dma-cells : Has to be 1. imx-dma does not support anything else. + +Optional properties: +- #dma-channels : Number of DMA channels supported. Should be 16. +- #dma-requests : Number of DMA requests supported. + +Example: + + dma: dma@10001000 { + compatible = "fsl,imx27-dma"; + reg = <0x10001000 0x1000>; + interrupts = <32 33>; + #dma-cells = <1>; + #dma-channels = <16>; + }; + + +* DMA client + +Clients have to specify the DMA requests with phandles in a list. + +Required properties: +- dmas: List of one or more DMA request specifiers. One DMA request specifier + consists of a phandle to the DMA controller followed by the integer + specifying the request line. +- dma-names: List of string identifiers for the DMA requests. For the correct + names, have a look at the specific client driver. + +Example: + + sdhci1: sdhci@10013000 { + ... + dmas = <&dma 7>; + dma-names = "rx-tx"; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/fsl-imx-sdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-imx-sdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c9a57a8443b25903474293dd3e3181a29958d7c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-imx-sdma.txt @@ -0,0 +1,113 @@ +* Freescale Smart Direct Memory Access (SDMA) Controller for i.MX + +Required properties: +- compatible : Should be one of + "fsl,imx25-sdma" + "fsl,imx31-sdma", "fsl,imx31-to1-sdma", "fsl,imx31-to2-sdma" + "fsl,imx35-sdma", "fsl,imx35-to1-sdma", "fsl,imx35-to2-sdma" + "fsl,imx51-sdma" + "fsl,imx53-sdma" + "fsl,imx6q-sdma" + "fsl,imx7d-sdma" + The -to variants should be preferred since they allow to determine the + correct ROM script addresses needed for the driver to work without additional + firmware. +- reg : Should contain SDMA registers location and length +- interrupts : Should contain SDMA interrupt +- #dma-cells : Must be <3>. + The first cell specifies the DMA request/event ID. See details below + about the second and third cell. +- fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM + scripts firmware + +The second cell of dma phandle specifies the peripheral type of DMA transfer. +The full ID of peripheral types can be found below. + + ID transfer type + --------------------- + 0 MCU domain SSI + 1 Shared SSI + 2 MMC + 3 SDHC + 4 MCU domain UART + 5 Shared UART + 6 FIRI + 7 MCU domain CSPI + 8 Shared CSPI + 9 SIM + 10 ATA + 11 CCM + 12 External peripheral + 13 Memory Stick Host Controller + 14 Shared Memory Stick Host Controller + 15 DSP + 16 Memory + 17 FIFO type Memory + 18 SPDIF + 19 IPU Memory + 20 ASRC + 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2) + 23 Shared ASRC + 24 SAI + +The third cell specifies the transfer priority as below. + + ID transfer priority + ------------------------- + 0 High + 1 Medium + 2 Low + +Optional properties: + +- gpr : The phandle to the General Purpose Register (GPR) node. +- fsl,sdma-event-remap : Register bits of sdma event remap, the format is + . + reg is the GPR register offset. + shift is the bit position inside the GPR register. + val is the value of the bit (0 or 1). + +Examples: + +sdma@83fb0000 { + compatible = "fsl,imx51-sdma", "fsl,imx35-sdma"; + reg = <0x83fb0000 0x4000>; + interrupts = <6>; + #dma-cells = <3>; + fsl,sdma-ram-script-name = "sdma-imx51.bin"; +}; + +DMA clients connected to the i.MX SDMA controller must use the format +described in the dma.txt file. + +Examples: + +ssi2: ssi@70014000 { + compatible = "fsl,imx51-ssi", "fsl,imx21-ssi"; + reg = <0x70014000 0x4000>; + interrupts = <30>; + clocks = <&clks 49>; + dmas = <&sdma 24 1 0>, + <&sdma 25 1 0>; + dma-names = "rx", "tx"; + fsl,fifo-depth = <15>; +}; + +Using the fsl,sdma-event-remap property: + +If we want to use SDMA on the SAI1 port on a MX6SX: + +&sdma { + gpr = <&gpr>; + /* SDMA events remap for SAI1_RX and SAI1_TX */ + fsl,sdma-event-remap = <0 15 1>, <0 16 1>; +}; + +The fsl,sdma-event-remap property in this case has two values: +- <0 15 1> means that the offset is 0, so GPR0 is the register of the +SDMA remap. Bit 15 of GPR0 selects between UART4_RX and SAI1_RX. +Setting bit 15 to 1 selects SAI1_RX. +- <0 16 1> means that the offset is 0, so GPR0 is the register of the +SDMA remap. Bit 16 of GPR0 selects between UART4_TX and SAI1_TX. +Setting bit 16 to 1 selects SAI1_TX. diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/fsl-mxs-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-mxs-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..e30e184f50c727aa84d2284914581ce9927dba1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/fsl-mxs-dma.txt @@ -0,0 +1,60 @@ +* Freescale MXS DMA + +Required properties: +- compatible : Should be "fsl,-dma-apbh" or "fsl,-dma-apbx" +- reg : Should contain registers location and length +- interrupts : Should contain the interrupt numbers of DMA channels. + If a channel is empty/reserved, 0 should be filled in place. +- #dma-cells : Must be <1>. The number cell specifies the channel ID. +- dma-channels : Number of channels supported by the DMA controller + +Optional properties: +- interrupt-names : Name of DMA channel interrupts + +Supported chips: +imx23, imx28. + +Examples: + +dma_apbh: dma-apbh@80004000 { + compatible = "fsl,imx28-dma-apbh"; + reg = <0x80004000 0x2000>; + interrupts = <82 83 84 85 + 88 88 88 88 + 88 88 88 88 + 87 86 0 0>; + interrupt-names = "ssp0", "ssp1", "ssp2", "ssp3", + "gpmi0", "gmpi1", "gpmi2", "gmpi3", + "gpmi4", "gmpi5", "gpmi6", "gmpi7", + "hsadc", "lcdif", "empty", "empty"; + #dma-cells = <1>; + dma-channels = <16>; +}; + +dma_apbx: dma-apbx@80024000 { + compatible = "fsl,imx28-dma-apbx"; + reg = <0x80024000 0x2000>; + interrupts = <78 79 66 0 + 80 81 68 69 + 70 71 72 73 + 74 75 76 77>; + interrupt-names = "auart4-rx", "auart4-tx", "spdif-tx", "empty", + "saif0", "saif1", "i2c0", "i2c1", + "auart0-rx", "auart0-tx", "auart1-rx", "auart1-tx", + "auart2-rx", "auart2-tx", "auart3-rx", "auart3-tx"; + #dma-cells = <1>; + dma-channels = <16>; +}; + +DMA clients connected to the MXS DMA controller must use the format +described in the dma.txt file. + +Examples: + +auart0: serial@8006a000 { + compatible = "fsl,imx28-auart", "fsl,imx23-auart"; + reg = <0x8006a000 0x2000>; + interrupts = <112>; + dmas = <&dma_apbx 8>, <&dma_apbx 9>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/img-mdc-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/img-mdc-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..28c1341db3461c3d2ca196d5f0dde20c7ae341e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/img-mdc-dma.txt @@ -0,0 +1,57 @@ +* IMG Multi-threaded DMA Controller (MDC) + +Required properties: +- compatible: Must be "img,pistachio-mdc-dma". +- reg: Must contain the base address and length of the MDC registers. +- interrupts: Must contain all the per-channel DMA interrupts. +- clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - sys: MDC system interface clock. +- img,cr-periph: Must contain a phandle to the peripheral control syscon + node which contains the DMA request to channel mapping registers. +- img,max-burst-multiplier: Must be the maximum supported burst size multiplier. + The maximum burst size is this value multiplied by the hardware-reported bus + width. +- #dma-cells: Must be 3: + - The first cell is the peripheral's DMA request line. + - The second cell is a bitmap specifying to which channels the DMA request + line may be mapped (i.e. bit N set indicates channel N is usable). + - The third cell is the thread ID to be used by the channel. + +Optional properties: +- dma-channels: Number of supported DMA channels, up to 32. If not specified + the number reported by the hardware is used. + +Example: + +mdc: dma-controller@18143000 { + compatible = "img,pistachio-mdc-dma"; + reg = <0x18143000 0x1000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&system_clk>; + clock-names = "sys"; + + img,max-burst-multiplier = <16>; + img,cr-periph = <&cr_periph>; + + #dma-cells = <3>; +}; + +spi@18100f00 { + ... + dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>; + dma-names = "tx", "rx"; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/jz4780-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/jz4780-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..03e9cf7b42e01da28cb77f5317a05ed2efd49d5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/jz4780-dma.txt @@ -0,0 +1,55 @@ +* Ingenic JZ4780 DMA Controller + +Required properties: + +- compatible: Should be "ingenic,jz4780-dma" +- reg: Should contain the DMA controller registers location and length. +- interrupts: Should contain the interrupt specifier of the DMA controller. +- clocks: Should contain a clock specifier for the JZ4780 PDMA clock. +- #dma-cells: Must be <2>. Number of integer cells in the dmas property of + DMA clients (see below). + +Optional properties: + +- ingenic,reserved-channels: Bitmask of channels to reserve for devices that + need a specific channel. These channels will only be assigned when explicitly + requested by a client. The primary use for this is channels 0 and 1, which + can be configured to have special behaviour for NAND/BCH when using + programmable firmware. + +Example: + +dma: dma@13420000 { + compatible = "ingenic,jz4780-dma"; + reg = <0x13420000 0x10000>; + + interrupt-parent = <&intc>; + interrupts = <10>; + + clocks = <&cgu JZ4780_CLK_PDMA>; + + #dma-cells = <2>; + + ingenic,reserved-channels = <0x3>; +}; + +DMA clients must use the format described in dma.txt, giving a phandle to the +DMA controller plus the following 2 integer cells: + +1. Request type: The DMA request type for transfers to/from the device on + the allocated channel, as defined in the SoC documentation. + +2. Channel: If set to 0xffffffff, any available channel will be allocated for + the client. Otherwise, the exact channel specified will be used. The channel + should be reserved on the DMA controller using the ingenic,reserved-channels + property. + +Example: + +uart0: serial@10030000 { + ... + dmas = <&dma 0x14 0xffffffff + &dma 0x15 0xffffffff>; + dma-names = "tx", "rx"; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/k3dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/k3dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..4945aeac4dc4f0b12499a6b947227fcf785325f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/k3dma.txt @@ -0,0 +1,45 @@ +* Hisilicon K3 DMA controller + +See dma.txt first + +Required properties: +- compatible: Should be "hisilicon,k3-dma-1.0" +- reg: Should contain DMA registers location and length. +- interrupts: Should contain one interrupt shared by all channel +- #dma-cells: see dma.txt, should be 1, para number +- dma-channels: physical channels supported +- dma-requests: virtual channels supported, each virtual channel + have specific request line +- clocks: clock required + +Example: + +Controller: + dma0: dma@fcd02000 { + compatible = "hisilicon,k3-dma-1.0"; + reg = <0xfcd02000 0x1000>; + #dma-cells = <1>; + dma-channels = <16>; + dma-requests = <27>; + interrupts = <0 12 4>; + clocks = <&pclk>; + }; + +Client: +Use specific request line passing from dmax +For example, i2c0 read channel request line is 18, while write channel use 19 + + i2c0: i2c@fcb08000 { + compatible = "snps,designware-i2c"; + dmas = <&dma0 18 /* read channel */ + &dma0 19>; /* write channel */ + dma-names = "rx", "tx"; + }; + + i2c1: i2c@fcb09000 { + compatible = "snps,designware-i2c"; + dmas = <&dma0 20 /* read channel */ + &dma0 21>; /* write channel */ + dma-names = "rx", "tx"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/lpc1850-dmamux.txt b/arch/arm64/boot/dts/vendor/bindings/dma/lpc1850-dmamux.txt new file mode 100644 index 0000000000000000000000000000000000000000..87740adb299560e44aec9966c9c88b33db3657ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/lpc1850-dmamux.txt @@ -0,0 +1,54 @@ +NXP LPC18xx/43xx DMA MUX (DMA request router) + +Required properties: +- compatible: "nxp,lpc1850-dmamux" +- reg: Memory map for accessing module +- #dma-cells: Should be set to <3>. + * 1st cell contain the master dma request signal + * 2nd cell contain the mux value (0-3) for the peripheral + * 3rd cell contain either 1 or 2 depending on the AHB + master used. +- dma-requests: Number of DMA requests for the mux +- dma-masters: phandle pointing to the DMA controller + +The DMA controller node need to have the following poroperties: +- dma-requests: Number of DMA requests the controller can handle + +Example: + +dmac: dma@40002000 { + compatible = "nxp,lpc1850-gpdma", "arm,pl080", "arm,primecell"; + arm,primecell-periphid = <0x00041080>; + reg = <0x40002000 0x1000>; + interrupts = <2>; + clocks = <&ccu1 CLK_CPU_DMA>; + clock-names = "apb_pclk"; + #dma-cells = <2>; + dma-channels = <8>; + dma-requests = <16>; + lli-bus-interface-ahb1; + lli-bus-interface-ahb2; + mem-bus-interface-ahb1; + mem-bus-interface-ahb2; + memcpy-burst-size = <256>; + memcpy-bus-width = <32>; +}; + +dmamux: dma-mux { + compatible = "nxp,lpc1850-dmamux"; + #dma-cells = <3>; + dma-requests = <64>; + dma-masters = <&dmac>; +}; + +uart0: serial@40081000 { + compatible = "nxp,lpc1850-uart", "ns16550a"; + reg = <0x40081000 0x1000>; + reg-shift = <2>; + interrupts = <24>; + clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>; + clock-names = "uartclk", "reg"; + dmas = <&dmamux 1 1 2 + &dmamux 2 1 2>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/mmp-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/mmp-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f7364a7b349edc76bdad6737234dd97907c75d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/mmp-dma.txt @@ -0,0 +1,79 @@ +* MARVELL MMP DMA controller + +Marvell Peripheral DMA Controller +Used platforms: pxa688, pxa910, pxa3xx, etc + +Required properties: +- compatible: Should be "marvell,pdma-1.0" +- reg: Should contain DMA registers location and length. +- interrupts: Either contain all of the per-channel DMA interrupts + or one irq for pdma device + +Optional properties: +- #dma-channels: Number of DMA channels supported by the controller (defaults + to 32 when not specified) +- #dma-requests: Number of DMA requestor lines supported by the controller + (defaults to 32 when not specified) + +"marvell,pdma-1.0" +Used platforms: pxa25x, pxa27x, pxa3xx, pxa93x, pxa168, pxa910, pxa688. + +Examples: + +/* + * Each channel has specific irq + * ICU parse out irq channel from ICU register, + * while DMA controller may not able to distinguish the irq channel + * Using this method, interrupt-parent is required as demuxer + * For example, pxa688 icu register 0x128, bit 0~15 is PDMA channel irq, + * 18~21 is ADMA irq + */ +pdma: dma-controller@d4000000 { + compatible = "marvell,pdma-1.0"; + reg = <0xd4000000 0x10000>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>; + interrupt-parent = <&intcmux32>; + #dma-channels = <16>; + }; + +/* + * One irq for all channels + * Dmaengine driver (DMA controller) distinguish irq channel via + * parsing internal register + */ +pdma: dma-controller@d4000000 { + compatible = "marvell,pdma-1.0"; + reg = <0xd4000000 0x10000>; + interrupts = <47>; + #dma-channels = <16>; + }; + + +Marvell Two Channel DMA Controller used specifically for audio +Used platforms: pxa688, pxa910 + +Required properties: +- compatible: Should be "marvell,adma-1.0" or "marvell,pxa910-squ" +- reg: Should contain DMA registers location and length. +- interrupts: Either contain all of the per-channel DMA interrupts + or one irq for dma device + +"marvell,adma-1.0" used on pxa688 +"marvell,pxa910-squ" used on pxa910 + +Examples: + +/* each channel has specific irq */ +adma0: dma-controller@d42a0800 { + compatible = "marvell,adma-1.0"; + reg = <0xd42a0800 0x100>; + interrupts = <18 19>; + interrupt-parent = <&intcmux32>; + }; + +/* One irq for all channels */ +squ: dma-controller@d42a0800 { + compatible = "marvell,pxa910-squ"; + reg = <0xd42a0800 0x100>; + interrupts = <46>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/moxa,moxart-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/moxa,moxart-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a9f3559335b50f0c663bcfe49ca6cc336745e6f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/moxa,moxart-dma.txt @@ -0,0 +1,45 @@ +MOXA ART DMA Controller + +See dma.txt first + +Required properties: + +- compatible : Must be "moxa,moxart-dma" +- reg : Should contain registers location and length +- interrupts : Should contain an interrupt-specifier for the sole + interrupt generated by the device +- #dma-cells : Should be 1, a single cell holding a line request number + +Example: + + dma: dma@90500000 { + compatible = "moxa,moxart-dma"; + reg = <0x90500080 0x40>; + interrupts = <24 0>; + #dma-cells = <1>; + }; + + +Clients: + +DMA clients connected to the MOXA ART DMA controller must use the format +described in the dma.txt file, using a two-cell specifier for each channel: +a phandle plus one integer cells. +The two cells in order are: + +1. A phandle pointing to the DMA controller. +2. Peripheral identifier for the hardware handshaking interface. + +Example: +Use specific request line passing from dma +For example, MMC request line is 5 + + sdhci: sdhci@98e00000 { + compatible = "moxa,moxart-sdhci"; + reg = <0x98e00000 0x5C>; + interrupts = <5 0>; + clocks = <&clk_apb>; + dmas = <&dma 5>, + <&dma 5>; + dma-names = "tx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/mpc512x-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/mpc512x-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..a6511df165c53cf9c4ae522d3a66d078e36bc660 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/mpc512x-dma.txt @@ -0,0 +1,29 @@ +* Freescale MPC512x and MPC8308 DMA Controller + +The DMA controller in Freescale MPC512x and MPC8308 SoCs can move +blocks of memory contents between memory and peripherals or +from memory to memory. + +Refer to "Generic DMA Controller and DMA request bindings" in +the dma/dma.txt file for a more detailed description of binding. + +Required properties: +- compatible: should be "fsl,mpc5121-dma" or "fsl,mpc8308-dma"; +- reg: should contain the DMA controller registers location and length; +- interrupt for the DMA controller: syntax of interrupt client node + is described in interrupt-controller/interrupts.txt file. +- #dma-cells: the length of the DMA specifier, must be <1>. + Each channel of this DMA controller has a peripheral request line, + the assignment is fixed in hardware. This one cell + in dmas property of a client device represents the channel number. + +Example: + + dma0: dma@14000 { + compatible = "fsl,mpc5121-dma"; + reg = <0x14000 0x1800>; + interrupts = <65 0x8>; + #dma-cells = <1>; + }; + +DMA clients must use the format described in dma/dma.txt file. diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/mtk-hsdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/mtk-hsdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..4bb317359dc696ec0c41f55d8c7ca4bfca87e0d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/mtk-hsdma.txt @@ -0,0 +1,33 @@ +MediaTek High-Speed DMA Controller +================================== + +This device follows the generic DMA bindings defined in dma/dma.txt. + +Required properties: + +- compatible: Must be one of + "mediatek,mt7622-hsdma": for MT7622 SoC + "mediatek,mt7623-hsdma": for MT7623 SoC +- reg: Should contain the register's base address and length. +- interrupts: Should contain a reference to the interrupt used by this + device. +- clocks: Should be the clock specifiers corresponding to the entry in + clock-names property. +- clock-names: Should contain "hsdma" entries. +- power-domains: Phandle to the power domain that the device is part of +- #dma-cells: The length of the DMA specifier, must be <1>. This one cell + in dmas property of a client device represents the channel + number. +Example: + + hsdma: dma-controller@1b007000 { + compatible = "mediatek,mt7623-hsdma"; + reg = <0 0x1b007000 0 0x1000>; + interrupts = ; + clocks = <ðsys CLK_ETHSYS_HSDMA>; + clock-names = "hsdma"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + #dma-cells = <1>; + }; + +DMA clients must use the format described in dma/dma.txt file. diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/mv-xor-v2.txt b/arch/arm64/boot/dts/vendor/bindings/dma/mv-xor-v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c38bbe7e6d7d86993be1f24ad011ee27a8e1d59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/mv-xor-v2.txt @@ -0,0 +1,28 @@ +* Marvell XOR v2 engines + +Required properties: +- compatible: one of the following values: + "marvell,armada-7k-xor" + "marvell,xor-v2" +- reg: Should contain registers location and length (two sets) + the first set is the DMA registers + the second set is the global registers +- msi-parent: Phandle to the MSI-capable interrupt controller used for + interrupts. + +Optional properties: +- clocks: Optional reference to the clocks used by the XOR engine. +- clock-names: mandatory if there is a second clock, in this case the + name must be "core" for the first clock and "reg" for the second + one + + +Example: + + xor0@400000 { + compatible = "marvell,xor-v2"; + reg = <0x400000 0x1000>, + <0x410000 0x1000>; + msi-parent = <&gic_v2m0>; + dma-coherent; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/mv-xor.txt b/arch/arm64/boot/dts/vendor/bindings/dma/mv-xor.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ffb4d8766a844a0bf82cf6fb08c2645ae6187e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/mv-xor.txt @@ -0,0 +1,40 @@ +* Marvell XOR engines + +Required properties: +- compatible: Should be one of the following: + - "marvell,orion-xor" + - "marvell,armada-380-xor" + - "marvell,armada-3700-xor". +- reg: Should contain registers location and length (two sets) + the first set is the low registers, the second set the high + registers for the XOR engine. +- clocks: pointer to the reference clock + +The DT node must also contains sub-nodes for each XOR channel that the +XOR engine has. Those sub-nodes have the following required +properties: +- interrupts: interrupt of the XOR channel + +The sub-nodes used to contain one or several of the following +properties, but they are now deprecated: +- dmacap,memcpy to indicate that the XOR channel is capable of memcpy operations +- dmacap,memset to indicate that the XOR channel is capable of memset operations +- dmacap,xor to indicate that the XOR channel is capable of xor operations +- dmacap,interrupt to indicate that the XOR channel is capable of + generating interrupts + +Example: + +xor@d0060900 { + compatible = "marvell,orion-xor"; + reg = <0xd0060900 0x100 + 0xd0060b00 0x100>; + clocks = <&coreclk 0>; + + xor00 { + interrupts = <51>; + }; + xor01 { + interrupts = <52>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/nbpfaxi.txt b/arch/arm64/boot/dts/vendor/bindings/dma/nbpfaxi.txt new file mode 100644 index 0000000000000000000000000000000000000000..d2e1e62e346ac08ac18e9169f9cac59504102bfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/nbpfaxi.txt @@ -0,0 +1,69 @@ +* Renesas "Type-AXI" NBPFAXI* DMA controllers + +* DMA controller + +Required properties + +- compatible: must be one of + "renesas,nbpfaxi64dmac1b4" + "renesas,nbpfaxi64dmac1b8" + "renesas,nbpfaxi64dmac1b16" + "renesas,nbpfaxi64dmac4b4" + "renesas,nbpfaxi64dmac4b8" + "renesas,nbpfaxi64dmac4b16" + "renesas,nbpfaxi64dmac8b4" + "renesas,nbpfaxi64dmac8b8" + "renesas,nbpfaxi64dmac8b16" +- #dma-cells: must be 2: the first integer is a terminal number, to which this + slave is connected, the second one is flags. Flags is a bitmask + with the following bits defined: + +#define NBPF_SLAVE_RQ_HIGH 1 +#define NBPF_SLAVE_RQ_LOW 2 +#define NBPF_SLAVE_RQ_LEVEL 4 + +Optional properties: +- max-burst-mem-read: limit burst size for memory reads + (DMA_MEM_TO_MEM/DMA_MEM_TO_DEV) to this value, specified in bytes, rather + than using the maximum burst size allowed by the hardware's buffer size. +- max-burst-mem-write: limit burst size for memory writes + (DMA_DEV_TO_MEM/DMA_MEM_TO_MEM) to this value, specified in bytes, rather + than using the maximum burst size allowed by the hardware's buffer size. + If both max-burst-mem-read and max-burst-mem-write are set, DMA_MEM_TO_MEM + will use the lower value. + +You can use dma-channels and dma-requests as described in dma.txt, although they +won't be used, this information is derived from the compatibility string. + +Example: + + dma: dma-controller@48000000 { + compatible = "renesas,nbpfaxi64dmac8b4"; + reg = <0x48000000 0x400>; + interrupts = <0 12 0x4 + 0 13 0x4 + 0 14 0x4 + 0 15 0x4 + 0 16 0x4 + 0 17 0x4 + 0 18 0x4 + 0 19 0x4>; + #dma-cells = <2>; + dma-channels = <8>; + dma-requests = <8>; + }; + +* DMA client + +Required properties: + +dmas and dma-names are required, as described in dma.txt. + +Example: + +#include + +... + dmas = <&dma 0 (NBPF_SLAVE_RQ_HIGH | NBPF_SLAVE_RQ_LEVEL) + &dma 1 (NBPF_SLAVE_RQ_HIGH | NBPF_SLAVE_RQ_LEVEL)>; + dma-names = "rx", "tx"; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/nvidia,tegra20-apbdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/nvidia,tegra20-apbdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6908e7c42cca6936ec9798f5614af25298fb981 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/nvidia,tegra20-apbdma.txt @@ -0,0 +1,44 @@ +* NVIDIA Tegra APB DMA controller + +Required properties: +- compatible: Should be "nvidia,-apbdma" +- reg: Should contain DMA registers location and length. This shuld include + all of the per-channel registers. +- interrupts: Should contain all of the per-channel DMA interrupts. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - dma +- #dma-cells : Must be <1>. This dictates the length of DMA specifiers in + client nodes' dmas properties. The specifier represents the DMA request + select value for the peripheral. For more details, consult the Tegra TRM's + documentation of the APB DMA channel control register REQ_SEL field. + +Examples: + +apbdma: dma@6000a000 { + compatible = "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1200>; + interrupts = < 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04 + 0 144 0x04 + 0 145 0x04 + 0 146 0x04 + 0 147 0x04 + 0 148 0x04 + 0 149 0x04 + 0 150 0x04 + 0 151 0x04 >; + clocks = <&tegra_car 34>; + resets = <&tegra_car 34>; + reset-names = "dma"; + #dma-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/nvidia,tegra210-adma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/nvidia,tegra210-adma.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f35b047f7721e128399ba94baab192a2b823c8a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/nvidia,tegra210-adma.txt @@ -0,0 +1,54 @@ +* NVIDIA Tegra Audio DMA (ADMA) controller + +The Tegra Audio DMA controller that is used for transferring data +between system memory and the Audio Processing Engine (APE). + +Required properties: +- compatible: Must be "nvidia,tegra210-adma". +- reg: Should contain DMA registers location and length. This should be + a single entry that includes all of the per-channel registers in one + contiguous bank. +- interrupts: Should contain all of the per-channel DMA interrupts in + ascending order with respect to the DMA channel index. +- clocks: Must contain one entry for the ADMA module clock + (TEGRA210_CLK_D_AUDIO). +- clock-names: Must contain the name "d_audio" for the corresponding + 'clocks' entry. +- #dma-cells : Must be 1. The first cell denotes the receive/transmit + request number and should be between 1 and the maximum number of + requests supported. This value corresponds to the RX/TX_REQUEST_SELECT + fields in the ADMA_CHn_CTRL register. + + +Example: + +adma: dma@702e2000 { + compatible = "nvidia,tegra210-adma"; + reg = <0x0 0x702e2000 0x0 0x2000>; + interrupt-parent = <&tegra_agic>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&tegra_car TEGRA210_CLK_D_AUDIO>; + clock-names = "d_audio"; + #dma-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/owl-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/owl-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..03e9bb12b75f71c84389efb4ca873af2af6786ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/owl-dma.txt @@ -0,0 +1,47 @@ +* Actions Semi Owl SoCs DMA controller + +This binding follows the generic DMA bindings defined in dma.txt. + +Required properties: +- compatible: Should be "actions,s900-dma". +- reg: Should contain DMA registers location and length. +- interrupts: Should contain 4 interrupts shared by all channel. +- #dma-cells: Must be <1>. Used to represent the number of integer + cells in the dmas property of client device. +- dma-channels: Physical channels supported. +- dma-requests: Number of DMA request signals supported by the controller. + Refer to Documentation/devicetree/bindings/dma/dma.txt +- clocks: Phandle and Specifier of the clock feeding the DMA controller. + +Example: + +Controller: + dma: dma-controller@e0260000 { + compatible = "actions,s900-dma"; + reg = <0x0 0xe0260000 0x0 0x1000>; + interrupts = , + , + , + ; + #dma-cells = <1>; + dma-channels = <12>; + dma-requests = <46>; + clocks = <&clock CLK_DMAC>; + }; + +Client: + +DMA clients connected to the Actions Semi Owl SoCs DMA controller must +use the format described in the dma.txt file, using a two-cell specifier +for each channel. + +The two cells in order are: +1. A phandle pointing to the DMA controller. +2. The channel id. + +uart5: serial@e012a000 { + ... + dma-names = "tx", "rx"; + dmas = <&dma 26>, <&dma 27>; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/qcom-sps-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/qcom-sps-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6c8726dac263f294127c73c11d2754afc27171e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/qcom-sps-dma.txt @@ -0,0 +1,42 @@ +* Qualcomm technologies inc, DMA engine driver for BAM (Bus Access Manager). + +Required properties: +- compatible: Should be "qcom,sps-dma". +- reg: Should contain DMA registers location and length. This should include + all of the per-channel registers. +- interrupts: Should contain the BAM interrupt number. +- qcom,summing-threshold: Should contain the BAM event threshold of + the sum of descriptors' sizes in bytes. + +Optional properties: +- qcom,managed-locally : Use when BAM global device control is managed locally + by the application processor. + +Example: + + dma_blsp1: qcom,sps-dma@f9904000 { /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0xf9904000 0x19000>; + interrupts = <0 238 0>; + qcom,summing-threshold = <10>; + }; + +DMA clients connected to the qcom-sps-dma DMA controller must use the format +described in the dma.txt file, using a five-cell specifier for each channel, +a phandle plus four integer cells, as shown below: + +dmas = <[phandle of the dma controller] [pipe index] [number of descriptors] + [sps_connect flags] [sps_register_event flags]>; + +Example: + +i2c_2: i2c@f9924000 { /* BLSP1 QUP2 */ + . + . + . + /* <&phandle pipe-idx n-descs connect-flags event-flags> */ + dmas = <&dma_blsp1 14 32 0x20000020 0x20>, + <&dma_blsp1 15 64 0x20000020 0x20>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/qcom_adm.txt b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_adm.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d3b2f917b7b31ea0c9ac6ff7e545b5324b77005 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_adm.txt @@ -0,0 +1,61 @@ +QCOM ADM DMA Controller + +Required properties: +- compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960 +- reg: Address range for DMA registers +- interrupts: Should contain one interrupt shared by all channels +- #dma-cells: must be <2>. First cell denotes the channel number. Second cell + denotes CRCI (client rate control interface) flow control assignment. +- clocks: Should contain the core clock and interface clock. +- clock-names: Must contain "core" for the core clock and "iface" for the + interface clock. +- resets: Must contain an entry for each entry in reset names. +- reset-names: Must include the following entries: + - clk + - c0 + - c1 + - c2 +- qcom,ee: indicates the security domain identifier used in the secure world. + +Example: + adm_dma: dma@18300000 { + compatible = "qcom,adm"; + reg = <0x18300000 0x100000>; + interrupts = <0 170 0>; + #dma-cells = <2>; + + clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>; + clock-names = "core", "iface"; + + resets = <&gcc ADM0_RESET>, + <&gcc ADM0_C0_RESET>, + <&gcc ADM0_C1_RESET>, + <&gcc ADM0_C2_RESET>; + reset-names = "clk", "c0", "c1", "c2"; + qcom,ee = <0>; + }; + +DMA clients must use the format descripted in the dma.txt file, using a three +cell specifier for each channel. + +Each dmas request consists of 3 cells: + 1. phandle pointing to the DMA controller + 2. channel number + 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0. + The CRCI is used for flow control. It identifies the peripheral device that + is the source/destination for the transferred data. + +Example: + + spi4: spi@1a280000 { + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 0>; + + dmas = <&adm_dma 6 9>, + <&adm_dma 5 10>; + dma-names = "rx", "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/qcom_bam_dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_bam_dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf5b9e44432c62b3d2b451e142dcc67db2ac11ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_bam_dma.txt @@ -0,0 +1,50 @@ +QCOM BAM DMA controller + +Required properties: +- compatible: must be one of the following: + * "qcom,bam-v1.4.0" for MSM8974, APQ8074 and APQ8084 + * "qcom,bam-v1.3.0" for APQ8064, IPQ8064 and MSM8960 + * "qcom,bam-v1.7.0" for MSM8916 +- reg: Address range for DMA registers +- interrupts: Should contain the one interrupt shared by all channels +- #dma-cells: must be <1>, the cell in the dmas property of the client device + represents the channel number +- clocks: required clock +- clock-names: must contain "bam_clk" entry +- qcom,ee : indicates the active Execution Environment identifier (0-7) used in + the secure world. +- qcom,controlled-remotely : optional, indicates that the bam is controlled by + remote proccessor i.e. execution environment. +- num-channels : optional, indicates supported number of DMA channels in a + remotely controlled bam. +- qcom,num-ees : optional, indicates supported number of Execution Environments + in a remotely controlled bam. + +Example: + + uart-bam: dma@f9984000 = { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9984000 0x15000>; + interrupts = <0 94 0>; + clocks = <&gcc GCC_BAM_DMA_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; + +DMA clients must use the format described in the dma.txt file, using a two cell +specifier for each channel. + +Example: + serial@f991e000 { + compatible = "qcom,msm-uart"; + reg = <0xf991e000 0x1000> + <0xf9944000 0x19000>; + interrupts = <0 108 0>; + clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + + dmas = <&uart-bam 0>, <&uart-bam 1>; + dma-names = "rx", "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/qcom_gpi.txt b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_gpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb4a7ca3ae3106788e09975a8f809ec9f6c67312 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_gpi.txt @@ -0,0 +1,107 @@ +Qualcomm Technologies Inc GPI DMA controller + +QCOM GPI DMA controller provides DMA capabilities for +peripheral buses such as I2C, UART, and SPI. + +============== +Node Structure +============== + +Main node properties: + +- #dma-cells + Usage: required + Value type: + Definition: Number of parameters client will provide. Must be set to 5. + 1st parameter: channel index, 0 for TX, 1 for RX + 2nd parameter: serial engine index + 3rd parameter: bus protocol, 1 for SPI, 2 for UART, 3 for I2C + 4th parameter: channel ring length in transfer ring elements + 5th parameter: event processing priority, set to 0 for lowest latency + +- compatible + Usage: required + Value type: + Definition: "qcom,gpi-dma" + +- reg + Usage: required + Value type: Array of + Definition: register address space location and size + +- reg-name + Usage: required + Value type: + Definition: register space name, must be "gpi-top" + +- interrupts + Usage: required + Value type: Array of + Definition: Array of tuples which describe interrupt line for each GPII + instance. + +- qcom,max-num-gpii + Usage: required + Value type: + Definition: Total number of GPII instances available for this controller. + +- qcom,gpii-mask + Usage: required + Value type: + Definition: Bitmap of supported GPII instances in hlos. + +- qcom,ev-factor + Usage: required + Value type: + Definition: Event ring transfer size compare to channel transfer ring. Event + ring length = ev-factor * transfer ring size + +- iommus + Usage: required + Value type: + Definition: phandle for apps smmu controller and SID, and mask + for the controller. For more detail please check binding + documentation arm,smmu.txt + +- qcom,smmu-cfg + Usage: required + Value type: + Definition: Determine whether GPI driver require to configure SMMU that + sits behind GPI controller. + Bit mask: + BIT(0) : Attach address mapping to endpoint device + BIT(1) : Set SMMU attribute S1_BYPASS + BIT(2) : Set SMMU attribute FAST + BIT(3) : Set SMMU attribute ATOMIC + +- qcom,iova-range + Usage: required if SMMU S1 translation is enabled + Value type: Array of + Definition: Pair of values describing iova base and size to allocate. + +Optional property: +- qcom,gpi-ee-offset + Usage: optional + Value type: u64 + Definition: Specifies the gsi ee register offset for the QUP. + +======== +Example: +======== +gpi_dma0: qcom,gpi-dma@0x800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, + <0 252 0>, <0 253 0>, <0 254 0>, <0 255 0>, + <0 256 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x0016 0x0>; + qcom,smmu-cfg = <0x1> + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/qcom_hidma_mgmt.txt b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_hidma_mgmt.txt new file mode 100644 index 0000000000000000000000000000000000000000..1ae4748730a854f2914f29c6cd9a8461e232bd63 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/qcom_hidma_mgmt.txt @@ -0,0 +1,95 @@ +Qualcomm Technologies HIDMA Management interface + +Qualcomm Technologies HIDMA is a high speed DMA device. It only supports +memcpy and memset capabilities. It has been designed for virtualized +environments. + +Each HIDMA HW instance consists of multiple DMA channels. These channels +share the same bandwidth. The bandwidth utilization can be partitioned +among channels based on the priority and weight assignments. + +There are only two priority levels and 15 weigh assignments possible. + +Other parameters here determine how much of the system bus this HIDMA +instance can use like maximum read/write request and number of bytes to +read/write in a single burst. + +Main node required properties: +- compatible: "qcom,hidma-mgmt-1.0"; +- reg: Address range for DMA device +- dma-channels: Number of channels supported by this DMA controller. +- max-write-burst-bytes: Maximum write burst in bytes that HIDMA can + occupy the bus for in a single transaction. A memcpy requested is + fragmented to multiples of this amount. This parameter is used while + writing into destination memory. Setting this value incorrectly can + starve other peripherals in the system. +- max-read-burst-bytes: Maximum read burst in bytes that HIDMA can + occupy the bus for in a single transaction. A memcpy request is + fragmented to multiples of this amount. This parameter is used while + reading the source memory. Setting this value incorrectly can starve + other peripherals in the system. +- max-write-transactions: This value is how many times a write burst is + applied back to back while writing to the destination before yielding + the bus. +- max-read-transactions: This value is how many times a read burst is + applied back to back while reading the source before yielding the bus. +- channel-reset-timeout-cycles: Channel reset timeout in cycles for this SOC. + Once a reset is applied to the HW, HW starts a timer for reset operation + to confirm. If reset is not completed within this time, HW reports reset + failure. + +Sub-nodes: + +HIDMA has one or more DMA channels that are used to move data from one +memory location to another. + +When the OS is not in control of the management interface (i.e. it's a guest), +the channel nodes appear on their own, not under a management node. + +Required properties: +- compatible: must contain "qcom,hidma-1.0" for initial HW or + "qcom,hidma-1.1"/"qcom,hidma-1.2" for MSI capable HW. +- reg: Addresses for the transfer and event channel +- interrupts: Should contain the event interrupt +- desc-count: Number of asynchronous requests this channel can handle +- iommus: required a iommu node + +Optional properties for MSI: +- msi-parent : See the generic MSI binding described in + devicetree/bindings/interrupt-controller/msi.txt for a description of the + msi-parent property. + +Example: + +Hypervisor OS configuration: + + hidma-mgmt@f9984000 = { + compatible = "qcom,hidma-mgmt-1.0"; + reg = <0xf9984000 0x15000>; + dma-channels = <6>; + max-write-burst-bytes = <1024>; + max-read-burst-bytes = <1024>; + max-write-transactions = <31>; + max-read-transactions = <31>; + channel-reset-timeout-cycles = <0x500>; + + hidma_24: dma-controller@5c050000 { + compatible = "qcom,hidma-1.0"; + reg = <0 0x5c050000 0x0 0x1000>, + <0 0x5c0b0000 0x0 0x1000>; + interrupts = <0 389 0>; + desc-count = <10>; + iommus = <&system_mmu>; + }; + }; + +Guest OS configuration: + + hidma_24: dma-controller@5c050000 { + compatible = "qcom,hidma-1.0"; + reg = <0 0x5c050000 0x0 0x1000>, + <0 0x5c0b0000 0x0 0x1000>; + interrupts = <0 389 0>; + desc-count = <10>; + iommus = <&system_mmu>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/renesas,rcar-dmac.txt b/arch/arm64/boot/dts/vendor/bindings/dma/renesas,rcar-dmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..946229c48657cfa255b6ea913b5b41c18929e5ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/renesas,rcar-dmac.txt @@ -0,0 +1,112 @@ +* Renesas R-Car (RZ/G) DMA Controller Device Tree bindings + +Renesas R-Car Generation 2 SoCs have multiple multi-channel DMA +controller instances named DMAC capable of serving multiple clients. Channels +can be dedicated to specific clients or shared between a large number of +clients. + +Each DMA client is connected to one dedicated port of the DMAC, identified by +an 8-bit port number called the MID/RID. A DMA controller can thus serve up to +256 clients in total. When the number of hardware channels is lower than the +number of clients to be served, channels must be shared between multiple DMA +clients. The association of DMA clients to DMAC channels is fully dynamic and +not described in these device tree bindings. + +Required Properties: + +- compatible: "renesas,dmac-", "renesas,rcar-dmac" as fallback. + Examples with soctypes are: + - "renesas,dmac-r8a7743" (RZ/G1M) + - "renesas,dmac-r8a7745" (RZ/G1E) + - "renesas,dmac-r8a77470" (RZ/G1C) + - "renesas,dmac-r8a7790" (R-Car H2) + - "renesas,dmac-r8a7791" (R-Car M2-W) + - "renesas,dmac-r8a7792" (R-Car V2H) + - "renesas,dmac-r8a7793" (R-Car M2-N) + - "renesas,dmac-r8a7794" (R-Car E2) + - "renesas,dmac-r8a7795" (R-Car H3) + - "renesas,dmac-r8a7796" (R-Car M3-W) + - "renesas,dmac-r8a77965" (R-Car M3-N) + - "renesas,dmac-r8a77970" (R-Car V3M) + - "renesas,dmac-r8a77980" (R-Car V3H) + - "renesas,dmac-r8a77990" (R-Car E3) + - "renesas,dmac-r8a77995" (R-Car D3) + +- reg: base address and length of the registers block for the DMAC + +- interrupts: interrupt specifiers for the DMAC, one for each entry in + interrupt-names. +- interrupt-names: one entry for the error interrupt, named "error", plus one + entry per channel, named "ch%u", where %u is the channel number ranging from + zero to the number of channels minus one. + +- clock-names: "fck" for the functional clock +- clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. +- clock-names: must contain "fck" for the functional clock. + +- #dma-cells: must be <1>, the cell specifies the MID/RID of the DMAC port + connected to the DMA client +- dma-channels: number of DMA channels + +Example: R8A7790 (R-Car H2) SYS-DMACs + + dmac0: dma-controller@e6700000 { + compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac"; + reg = <0 0xe6700000 0 0x20000>; + interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH + 0 200 IRQ_TYPE_LEVEL_HIGH + 0 201 IRQ_TYPE_LEVEL_HIGH + 0 202 IRQ_TYPE_LEVEL_HIGH + 0 203 IRQ_TYPE_LEVEL_HIGH + 0 204 IRQ_TYPE_LEVEL_HIGH + 0 205 IRQ_TYPE_LEVEL_HIGH + 0 206 IRQ_TYPE_LEVEL_HIGH + 0 207 IRQ_TYPE_LEVEL_HIGH + 0 208 IRQ_TYPE_LEVEL_HIGH + 0 209 IRQ_TYPE_LEVEL_HIGH + 0 210 IRQ_TYPE_LEVEL_HIGH + 0 211 IRQ_TYPE_LEVEL_HIGH + 0 212 IRQ_TYPE_LEVEL_HIGH + 0 213 IRQ_TYPE_LEVEL_HIGH + 0 214 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14"; + clocks = <&mstp2_clks R8A7790_CLK_SYS_DMAC0>; + clock-names = "fck"; + #dma-cells = <1>; + dma-channels = <15>; + }; + + dmac1: dma-controller@e6720000 { + compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac"; + reg = <0 0xe6720000 0 0x20000>; + interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH + 0 216 IRQ_TYPE_LEVEL_HIGH + 0 217 IRQ_TYPE_LEVEL_HIGH + 0 218 IRQ_TYPE_LEVEL_HIGH + 0 219 IRQ_TYPE_LEVEL_HIGH + 0 308 IRQ_TYPE_LEVEL_HIGH + 0 309 IRQ_TYPE_LEVEL_HIGH + 0 310 IRQ_TYPE_LEVEL_HIGH + 0 311 IRQ_TYPE_LEVEL_HIGH + 0 312 IRQ_TYPE_LEVEL_HIGH + 0 313 IRQ_TYPE_LEVEL_HIGH + 0 314 IRQ_TYPE_LEVEL_HIGH + 0 315 IRQ_TYPE_LEVEL_HIGH + 0 316 IRQ_TYPE_LEVEL_HIGH + 0 317 IRQ_TYPE_LEVEL_HIGH + 0 318 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14"; + clocks = <&mstp2_clks R8A7790_CLK_SYS_DMAC1>; + clock-names = "fck"; + #dma-cells = <1>; + dma-channels = <15>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/renesas,usb-dmac.txt b/arch/arm64/boot/dts/vendor/bindings/dma/renesas,usb-dmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..482e54362d3e0ba60bd1b5f731f14854d0168c30 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/renesas,usb-dmac.txt @@ -0,0 +1,49 @@ +* Renesas USB DMA Controller Device Tree bindings + +Required Properties: +-compatible: "renesas,-usb-dmac", "renesas,usb-dmac" as fallback. + Examples with soctypes are: + - "renesas,r8a7743-usb-dmac" (RZ/G1M) + - "renesas,r8a7745-usb-dmac" (RZ/G1E) + - "renesas,r8a7790-usb-dmac" (R-Car H2) + - "renesas,r8a7791-usb-dmac" (R-Car M2-W) + - "renesas,r8a7793-usb-dmac" (R-Car M2-N) + - "renesas,r8a7794-usb-dmac" (R-Car E2) + - "renesas,r8a7795-usb-dmac" (R-Car H3) + - "renesas,r8a7796-usb-dmac" (R-Car M3-W) + - "renesas,r8a77965-usb-dmac" (R-Car M3-N) + - "renesas,r8a77990-usb-dmac" (R-Car E3) + - "renesas,r8a77995-usb-dmac" (R-Car D3) +- reg: base address and length of the registers block for the DMAC +- interrupts: interrupt specifiers for the DMAC, one for each entry in + interrupt-names. +- interrupt-names: one entry per channel, named "ch%u", where %u is the + channel number ranging from zero to the number of channels minus one. +- clocks: a list of phandle + clock-specifier pairs. +- #dma-cells: must be <1>, the cell specifies the channel number of the DMAC + port connected to the DMA client. +- dma-channels: number of DMA channels + +Example: R8A7790 (R-Car H2) USB-DMACs + + usb_dmac0: dma-controller@e65a0000 { + compatible = "renesas,r8a7790-usb-dmac", "renesas,usb-dmac"; + reg = <0 0xe65a0000 0 0x100>; + interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH + 0 109 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ch0", "ch1"; + clocks = <&mstp3_clks R8A7790_CLK_USBDMAC0>; + #dma-cells = <1>; + dma-channels = <2>; + }; + + usb_dmac1: dma-controller@e65b0000 { + compatible = "renesas,usb-dmac"; + reg = <0 0xe65b0000 0 0x100>; + interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH + 0 110 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ch0", "ch1"; + clocks = <&mstp3_clks R8A7790_CLK_USBDMAC1>; + #dma-cells = <1>; + dma-channels = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/shdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/shdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..a91920a49433c2b813e6b62498387d9f9748e204 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/shdma.txt @@ -0,0 +1,84 @@ +* SHDMA Device Tree bindings + +Sh-/r-mobile and R-Car systems often have multiple identical DMA controller +instances, capable of serving any of a common set of DMA slave devices, using +the same configuration. To describe this topology we require all compatible +SHDMA DT nodes to be placed under a DMA multiplexer node. All such compatible +DMAC instances have the same number of channels and use the same DMA +descriptors. Therefore respective DMA DT bindings can also all be placed in the +multiplexer node. Even if there is only one such DMAC instance on a system, it +still has to be placed under such a multiplexer node. + +* DMA multiplexer + +Required properties: +- compatible: should be "renesas,shdma-mux" +- #dma-cells: should be <1>, see "dmas" property below + +Optional properties (currently unused): +- dma-channels: number of DMA channels +- dma-requests: number of DMA request signals + +* DMA controller + +Required properties: +- compatible: should be of the form "renesas,shdma-", where should + be replaced with the desired SoC model, e.g. + "renesas,shdma-r8a73a4" for the system DMAC on r8a73a4 SoC + +Example: + dmac: dma-multiplexer@0 { + compatible = "renesas,shdma-mux"; + #dma-cells = <1>; + dma-channels = <20>; + dma-requests = <256>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dma0: dma-controller@e6700020 { + compatible = "renesas,shdma-r8a73a4"; + reg = <0 0xe6700020 0 0x89e0>; + interrupt-parent = <&gic>; + interrupts = <0 220 4 + 0 200 4 + 0 201 4 + 0 202 4 + 0 203 4 + 0 204 4 + 0 205 4 + 0 206 4 + 0 207 4 + 0 208 4 + 0 209 4 + 0 210 4 + 0 211 4 + 0 212 4 + 0 213 4 + 0 214 4 + 0 215 4 + 0 216 4 + 0 217 4 + 0 218 4 + 0 219 4>; + interrupt-names = "error", + "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "ch16", "ch17", "ch18", "ch19"; + }; + }; + +* DMA client + +Required properties: +- dmas: a list of <[DMA multiplexer phandle] [MID/RID value]> pairs, + where MID/RID values are fixed handles, specified in the SoC + manual +- dma-names: a list of DMA channel names, one per "dmas" entry + +Example: + dmas = <&dmac 0xd1 + &dmac 0xd2>; + dma-names = "tx", "rx"; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/sirfsoc-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/sirfsoc-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccd52d6a231a2b41a010d375a7c395b6c6da0f42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/sirfsoc-dma.txt @@ -0,0 +1,44 @@ +* CSR SiRFSoC DMA controller + +See dma.txt first + +Required properties: +- compatible: Should be "sirf,prima2-dmac", "sirf,atlas7-dmac" or + "sirf,atlas7-dmac-v2" +- reg: Should contain DMA registers location and length. +- interrupts: Should contain one interrupt shared by all channel +- #dma-cells: must be <1>. used to represent the number of integer + cells in the dmas property of client device. +- clocks: clock required + +Example: + +Controller: +dmac0: dma-controller@b00b0000 { + compatible = "sirf,prima2-dmac"; + reg = <0xb00b0000 0x10000>; + interrupts = <12>; + clocks = <&clks 24>; + #dma-cells = <1>; +}; + + +Client: +Fill the specific dma request line in dmas. In the below example, spi0 read +channel request line is 9 of the 2nd dma controller, while write channel uses +4 of the 2nd dma controller; spi1 read channel request line is 12 of the 1st +dma controller, while write channel uses 13 of the 1st dma controller: + +spi0: spi@b00d0000 { + compatible = "sirf,prima2-spi"; + dmas = <&dmac1 9>, + <&dmac1 4>; + dma-names = "rx", "tx"; +}; + +spi1: spi@b0170000 { + compatible = "sirf,prima2-spi"; + dmas = <&dmac0 12>, + <&dmac0 13>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/snps,dw-axi-dmac.txt b/arch/arm64/boot/dts/vendor/bindings/dma/snps,dw-axi-dmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..dbe160400adcdafffdb6618e5f18e89616d732b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/snps,dw-axi-dmac.txt @@ -0,0 +1,39 @@ +Synopsys DesignWare AXI DMA Controller + +Required properties: +- compatible: "snps,axi-dma-1.01a" +- reg: Address range of the DMAC registers. This should include + all of the per-channel registers. +- interrupt: Should contain the DMAC interrupt number. +- dma-channels: Number of channels supported by hardware. +- snps,dma-masters: Number of AXI masters supported by the hardware. +- snps,data-width: Maximum AXI data width supported by hardware. + (0 - 8bits, 1 - 16bits, 2 - 32bits, ..., 6 - 512bits) +- snps,priority: Priority of channel. Array size is equal to the number of + dma-channels. Priority value must be programmed within [0:dma-channels-1] + range. (0 - minimum priority) +- snps,block-size: Maximum block size supported by the controller channel. + Array size is equal to the number of dma-channels. + +Optional properties: +- snps,axi-max-burst-len: Restrict master AXI burst length by value specified + in this property. If this property is missing the maximum AXI burst length + supported by DMAC is used. [1:256] + +Example: + +dmac: dma-controller@80000 { + compatible = "snps,axi-dma-1.01a"; + reg = <0x80000 0x400>; + clocks = <&core_clk>, <&cfgr_clk>; + clock-names = "core-clk", "cfgr-clk"; + interrupt-parent = <&intc>; + interrupts = <27>; + + dma-channels = <4>; + snps,dma-masters = <2>; + snps,data-width = <3>; + snps,block-size = <4096 4096 4096 4096>; + snps,priority = <0 1 2 3>; + snps,axi-max-burst-len = <16>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/snps-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/snps-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..39e2b26be344bf5b4935a19fc7df88169450dd77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/snps-dma.txt @@ -0,0 +1,67 @@ +* Synopsys Designware DMA Controller + +Required properties: +- compatible: "snps,dma-spear1340" +- reg: Address range of the DMAC registers +- interrupt: Should contain the DMAC interrupt number +- dma-channels: Number of channels supported by hardware +- dma-requests: Number of DMA request lines supported, up to 16 +- dma-masters: Number of AHB masters supported by the controller +- #dma-cells: must be <3> +- chan_allocation_order: order of allocation of channel, 0 (default): ascending, + 1: descending +- chan_priority: priority of channels. 0 (default): increase from chan 0->n, 1: + increase from chan n->0 +- block_size: Maximum block size supported by the controller +- data-width: Maximum data width supported by hardware per AHB master + (in bytes, power of 2) + + +Deprecated properties: +- data_width: Maximum data width supported by hardware per AHB master + (0 - 8bits, 1 - 16bits, ..., 5 - 256bits) + + +Optional properties: +- is_private: The device channels should be marked as private and not for by the + general purpose DMA channel allocator. False if not passed. +- multi-block: Multi block transfers supported by hardware. Array property with + one cell per channel. 0: not supported, 1 (default): supported. + +Example: + + dmahost: dma@fc000000 { + compatible = "snps,dma-spear1340"; + reg = <0xfc000000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + + dma-channels = <8>; + dma-requests = <16>; + dma-masters = <2>; + #dma-cells = <3>; + chan_allocation_order = <1>; + chan_priority = <1>; + block_size = <0xfff>; + data-width = <8 8>; + }; + +DMA clients connected to the Designware DMA controller must use the format +described in the dma.txt file, using a four-cell specifier for each channel. +The four cells in order are: + +1. A phandle pointing to the DMA controller +2. The DMA request line number +3. Memory master for transfers on allocated channel +4. Peripheral master for transfers on allocated channel + +Example: + + serial@e0000000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xe0000000 0x1000>; + interrupts = <0 35 0x4>; + dmas = <&dmahost 12 0 1>, + <&dmahost 13 1 0>; + dma-names = "rx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/sprd-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/sprd-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a10fea2e51bdfd1f2d7578781a07d701d3496c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/sprd-dma.txt @@ -0,0 +1,41 @@ +* Spreadtrum DMA controller + +This binding follows the generic DMA bindings defined in dma.txt. + +Required properties: +- compatible: Should be "sprd,sc9860-dma". +- reg: Should contain DMA registers location and length. +- interrupts: Should contain one interrupt shared by all channel. +- #dma-cells: must be <1>. Used to represent the number of integer + cells in the dmas property of client device. +- #dma-channels : Number of DMA channels supported. Should be 32. +- clock-names: Should contain the clock of the DMA controller. +- clocks: Should contain a clock specifier for each entry in clock-names. + +Example: + +Controller: +apdma: dma-controller@20100000 { + compatible = "sprd,sc9860-dma"; + reg = <0x20100000 0x4000>; + interrupts = ; + #dma-cells = <1>; + #dma-channels = <32>; + clock-names = "enable"; + clocks = <&clk_ap_ahb_gates 5>; +}; + + +Client: +DMA clients connected to the Spreadtrum DMA controller must use the format +described in the dma.txt file, using a two-cell specifier for each channel. +The two cells in order are: +1. A phandle pointing to the DMA controller. +2. The channel id. + +spi0: spi@70a00000{ + ... + dma-names = "rx_chn", "tx_chn"; + dmas = <&apdma 11>, <&apdma 12>; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/sps/sps.txt b/arch/arm64/boot/dts/vendor/bindings/dma/sps/sps.txt new file mode 100644 index 0000000000000000000000000000000000000000..f455b1cf9beaf9ad644768edd0fe83bb854d922d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/sps/sps.txt @@ -0,0 +1,47 @@ +SPS (Smart Peripheral Switch) may be used as a DMA engine to move data +in either the Peripheral-to-Peripheral (a.k.a. BAM-to-BAM) mode or the +Peripheral-to-Memory (a.k.a. BAM-System) mode. SPS includes BAM (Bus +Access Module) hardware block, BAM DMA peripheral, and pipe memory. + +Required property: + - compatible: should be "qcom,msm-sps" or "qcom,msm-sps-4k" + +Optional properties: + - reg: offset and size for the memory mapping, including maps for + BAM DMA BAM, BAM DMA peripheral, pipe memory and reserved memory. + - reg-names: indicates various resources passed to driver (via reg + property) by name. "reg-names" examples are "bam_mem", "core_mem" + , "pipe_mem" and "res_mem". + - interrupts: IRQ line + - qcom,device-type: specify the device configuration of BAM DMA and + pipe memory. Can be one of + 1 - With BAM DMA and without pipe memory + 2 - With BAM DMA and with pipe memory + 3 - Without BAM DMA and without pipe memory + - qcom,pipe-attr-ee: BAM pipes are attributed to a specific EE, with + which we can know the pipes belong to apps side and can have the + error interrupts at the pipe level. + - clocks: This property shall provide a list of entries each of which + contains a phandle to clock controller device and a macro that is + the clock's name in hardware.These should be "clock_rpm" as clock + controller phandle and "clk_pnoc_sps_clk" as macro for "dfab_clk" + and "clock_gcc" as clock controller phandle and "clk_gcc_bam_dma_ahb_clk" + as macro for "dma_bam_pclk". + - clock-names: This property shall contain the clock input names used + by driver in same order as the clocks property.These should be "dfab_clk" + and "dma_bam_pclk". + +Example: + + qcom,sps@f9980000 { + compatible = "qcom,msm-sps"; + reg = <0xf9984000 0x15000>, + <0xf9999000 0xb000>, + <0xfe803000 0x4800>; + interrupts = <0 94 0>; + qcom,device-type = <2>; + qcom,pipe-attr-ee; + clocks = <&clock_rpm clk_pnoc_sps_clk>, + <&clock_gcc clk_gcc_bam_dma_ahb_clk>; + clock-names = "dfab_clk", "dma_bam_pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/st_fdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/st_fdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..52cfec9e77ad528287f7ff18670802162d2a72cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/st_fdma.txt @@ -0,0 +1,86 @@ +* STMicroelectronics Flexible Direct Memory Access Device Tree bindings + +The FDMA is a general-purpose direct memory access controller capable of +supporting 16 independent DMA channels. It accepts up to 32 DMA requests. +The FDMA is based on a Slim processor which requires a firmware. + +* FDMA Controller + +Required properties: +- compatible : Should be one of + - st,stih407-fdma-mpe31-11, "st,slim-rproc"; + - st,stih407-fdma-mpe31-12, "st,slim-rproc"; + - st,stih407-fdma-mpe31-13, "st,slim-rproc"; +- reg : Should contain an entry for each name in reg-names +- reg-names : Must contain "slimcore", "dmem", "peripherals", "imem" entries +- interrupts : Should contain one interrupt shared by all channels +- dma-channels : Number of channels supported by the controller +- #dma-cells : Must be <3>. See DMA client section below +- clocks : Must contain an entry for each clock +See: Documentation/devicetree/bindings/clock/clock-bindings.txt + + +Example: + + fdma0: dma-controller@8e20000 { + compatible = "st,stih407-fdma-mpe31-11", "st,slim-rproc"; + reg = <0x8e20000 0x8000>, + <0x8e30000 0x3000>, + <0x8e37000 0x1000>, + <0x8e38000 0x8000>; + reg-names = "slimcore", "dmem", "peripherals", "imem"; + clocks = <&clk_s_c0_flexgen CLK_FDMA>, + <&clk_s_c0_flexgen CLK_EXT2F_A9>, + <&clk_s_c0_flexgen CLK_EXT2F_A9>, + <&clk_s_c0_flexgen CLK_EXT2F_A9>; + interrupts = ; + dma-channels = <16>; + #dma-cells = <3>; + }; + +* DMA client + +Required properties: +- dmas: Comma separated list of dma channel requests +- dma-names: Names of the aforementioned requested channels + +Each dmas request consists of 4 cells: +1. A phandle pointing to the FDMA controller +2. The request line number +3. A 32bit mask specifying (see include/linux/platform_data/dma-st-fdma.h) + -bit 2-0: Holdoff value, dreq will be masked for + 0x0: 0-0.5us + 0x1: 0.5-1us + 0x2: 1-1.5us + -bit 17: data swap + 0x0: disabled + 0x1: enabled + -bit 21: Increment Address + 0x0: no address increment between transfers + 0x1: increment address between transfers + -bit 22: 2 STBus Initiator Coprocessor interface + 0x0: high priority port + 0x1: low priority port +4. transfers type + 0 free running + 1 paced + +Example: + + sti_uni_player2: sti-uni-player@2 { + compatible = "st,sti-uni-player"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_PCM_2>; + assigned-clocks = <&clk_s_d0_flexgen CLK_PCM_2>; + assigned-clock-parents = <&clk_s_d0_quadfs 2>; + assigned-clock-rates = <50000000>; + reg = <0x8D82000 0x158>; + interrupts = ; + dmas = <&fdma0 4 0 1>; + dai-name = "Uni Player #1 (DAC)"; + dma-names = "tx"; + st,uniperiph-id = <2>; + st,version = <5>; + st,mode = "PCM"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/ste-coh901318.txt b/arch/arm64/boot/dts/vendor/bindings/dma/ste-coh901318.txt new file mode 100644 index 0000000000000000000000000000000000000000..091ad057e9cfd7fc28e164eb0d077d30b53268fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/ste-coh901318.txt @@ -0,0 +1,32 @@ +ST-Ericsson COH 901 318 DMA Controller + +This is a DMA controller which has begun as a fork of the +ARM PL08x PrimeCell VHDL code. + +Required properties: +- compatible: should be "stericsson,coh901318" +- reg: register locations and length +- interrupts: the single DMA IRQ +- #dma-cells: must be set to <1>, as the channels on the + COH 901 318 are simple and identified by a single number +- dma-channels: the number of DMA channels handled + +Example: + +dmac: dma-controller@c00020000 { + compatible = "stericsson,coh901318"; + reg = <0xc0020000 0x1000>; + interrupt-parent = <&vica>; + interrupts = <2>; + #dma-cells = <1>; + dma-channels = <40>; +}; + +Consumers example: + +uart0: serial@c0013000 { + compatible = "..."; + (...) + dmas = <&dmac 17 &dmac 18>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/ste-dma40.txt b/arch/arm64/boot/dts/vendor/bindings/dma/ste-dma40.txt new file mode 100644 index 0000000000000000000000000000000000000000..99ab5c4d331e71bba4db1928d2e0e8573968a58c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/ste-dma40.txt @@ -0,0 +1,138 @@ +* DMA40 DMA Controller + +Required properties: +- compatible: "stericsson,dma40" +- reg: Address range of the DMAC registers +- reg-names: Names of the above areas to use during resource look-up +- interrupt: Should contain the DMAC interrupt number +- #dma-cells: must be <3> +- memcpy-channels: Channels to be used for memcpy + +Optional properties: +- dma-channels: Number of channels supported by hardware - if not present + the driver will attempt to obtain the information from H/W +- disabled-channels: Channels which can not be used + +Example: + + dma: dma-controller@801c0000 { + compatible = "stericsson,db8500-dma40", "stericsson,dma40"; + reg = <0x801C0000 0x1000 0x40010000 0x800>; + reg-names = "base", "lcpa"; + interrupt-parent = <&intc>; + interrupts = <0 25 0x4>; + + #dma-cells = <2>; + memcpy-channels = <56 57 58 59 60>; + disabled-channels = <12>; + dma-channels = <8>; + }; + +Clients +Required properties: +- dmas: Comma separated list of dma channel requests +- dma-names: Names of the aforementioned requested channels + +Each dmas request consists of 4 cells: + 1. A phandle pointing to the DMA controller + 2. Device signal number, the signal line for single and burst requests + connected from the device to the DMA40 engine + 3. The DMA request line number (only when 'use fixed channel' is set) + 4. A 32bit mask specifying; mode, direction and endianness + [NB: This list will grow] + 0x00000001: Mode: + Logical channel when unset + Physical channel when set + 0x00000002: Direction: + Memory to Device when unset + Device to Memory when set + 0x00000004: Endianness: + Little endian when unset + Big endian when set + 0x00000008: Use fixed channel: + Use automatic channel selection when unset + Use DMA request line number when set + 0x00000010: Set channel as high priority: + Normal priority when unset + High priority when set + +Existing signal numbers for the DB8500 ASIC. Unless specified, the signals are +bidirectional, i.e. the same for RX and TX operations: + +0: SPI controller 0 +1: SD/MMC controller 0 (unused) +2: SD/MMC controller 1 (unused) +3: SD/MMC controller 2 (unused) +4: I2C port 1 +5: I2C port 3 +6: I2C port 2 +7: I2C port 4 +8: Synchronous Serial Port SSP0 +9: Synchronous Serial Port SSP1 +10: Multi-Channel Display Engine MCDE RX +11: UART port 2 +12: UART port 1 +13: UART port 0 +14: Multirate Serial Port MSP2 +15: I2C port 0 +16: USB OTG in/out endpoints 7 & 15 +17: USB OTG in/out endpoints 6 & 14 +18: USB OTG in/out endpoints 5 & 13 +19: USB OTG in/out endpoints 4 & 12 +20: SLIMbus or HSI channel 0 +21: SLIMbus or HSI channel 1 +22: SLIMbus or HSI channel 2 +23: SLIMbus or HSI channel 3 +24: Multimedia DSP SXA0 +25: Multimedia DSP SXA1 +26: Multimedia DSP SXA2 +27: Multimedia DSP SXA3 +28: SD/MM controller 2 +29: SD/MM controller 0 +30: MSP port 1 on DB8500 v1, MSP port 3 on DB8500 v2 +31: MSP port 0 or SLIMbus channel 0 +32: SD/MM controller 1 +33: SPI controller 2 +34: i2c3 RX2 TX2 +35: SPI controller 1 +36: USB OTG in/out endpoints 3 & 11 +37: USB OTG in/out endpoints 2 & 10 +38: USB OTG in/out endpoints 1 & 9 +39: USB OTG in/out endpoints 8 +40: SPI controller 3 +41: SD/MM controller 3 +42: SD/MM controller 4 +43: SD/MM controller 5 +44: Multimedia DSP SXA4 +45: Multimedia DSP SXA5 +46: SLIMbus channel 8 or Multimedia DSP SXA6 +47: SLIMbus channel 9 or Multimedia DSP SXA7 +48: Crypto Accelerator 1 +49: Crypto Accelerator 1 TX or Hash Accelerator 1 TX +50: Hash Accelerator 1 TX +51: memcpy TX (to be used by the DMA driver for memcpy operations) +52: SLIMbus or HSI channel 4 +53: SLIMbus or HSI channel 5 +54: SLIMbus or HSI channel 6 +55: SLIMbus or HSI channel 7 +56: memcpy (to be used by the DMA driver for memcpy operations) +57: memcpy (to be used by the DMA driver for memcpy operations) +58: memcpy (to be used by the DMA driver for memcpy operations) +59: memcpy (to be used by the DMA driver for memcpy operations) +60: memcpy (to be used by the DMA driver for memcpy operations) +61: Crypto Accelerator 0 +62: Crypto Accelerator 0 TX or Hash Accelerator 0 TX +63: Hash Accelerator 0 TX + +Example: + + uart@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 0x4>; + + dmas = <&dma 13 0 0x2>, /* Logical - DevToMem */ + <&dma 13 0 0x0>; /* Logical - MemToDev */ + dma-names = "rx", "rx"; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/stm32-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/stm32-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5f519097204f847fee551879c67a9260f71103e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/stm32-dma.txt @@ -0,0 +1,83 @@ +* STMicroelectronics STM32 DMA controller + +The STM32 DMA is a general-purpose direct memory access controller capable of +supporting 8 independent DMA channels. Each channel can have up to 8 requests. + +Required properties: +- compatible: Should be "st,stm32-dma" +- reg: Should contain DMA registers location and length. This should include + all of the per-channel registers. +- interrupts: Should contain all of the per-channel DMA interrupts in + ascending order with respect to the DMA channel index. +- clocks: Should contain the input clock of the DMA instance. +- #dma-cells : Must be <4>. See DMA client paragraph for more details. + +Optional properties: +- dma-requests : Number of DMA requests supported. +- resets: Reference to a reset controller asserting the DMA controller +- st,mem2mem: boolean; if defined, it indicates that the controller supports + memory-to-memory transfer + +Example: + + dma2: dma-controller@40026400 { + compatible = "st,stm32-dma"; + reg = <0x40026400 0x400>; + interrupts = <56>, + <57>, + <58>, + <59>, + <60>, + <68>, + <69>, + <70>; + clocks = <&clk_hclk>; + #dma-cells = <4>; + st,mem2mem; + resets = <&rcc 150>; + dma-requests = <8>; + }; + +* DMA client + +DMA clients connected to the STM32 DMA controller must use the format +described in the dma.txt file, using a four-cell specifier for each +channel: a phandle to the DMA controller plus the following four integer cells: + +1. The channel id +2. The request line number +3. A 32bit mask specifying the DMA channel configuration which are device + dependent: + -bit 9: Peripheral Increment Address + 0x0: no address increment between transfers + 0x1: increment address between transfers + -bit 10: Memory Increment Address + 0x0: no address increment between transfers + 0x1: increment address between transfers + -bit 15: Peripheral Increment Offset Size + 0x0: offset size is linked to the peripheral bus width + 0x1: offset size is fixed to 4 (32-bit alignment) + -bit 16-17: Priority level + 0x0: low + 0x1: medium + 0x2: high + 0x3: very high +4. A 32bit bitfield value specifying DMA features which are device dependent: + -bit 0-1: DMA FIFO threshold selection + 0x0: 1/4 full FIFO + 0x1: 1/2 full FIFO + 0x2: 3/4 full FIFO + 0x3: full FIFO + + +Example: + + usart1: serial@40011000 { + compatible = "st,stm32-uart"; + reg = <0x40011000 0x400>; + interrupts = <37>; + clocks = <&clk_pclk2>; + dmas = <&dma2 2 4 0x10400 0x3>, + <&dma2 7 5 0x10200 0x3>; + dma-names = "rx", "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/stm32-dmamux.txt b/arch/arm64/boot/dts/vendor/bindings/dma/stm32-dmamux.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b893b23550720de68836883bf6025a4bf1245d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/stm32-dmamux.txt @@ -0,0 +1,84 @@ +STM32 DMA MUX (DMA request router) + +Required properties: +- compatible: "st,stm32h7-dmamux" +- reg: Memory map for accessing module +- #dma-cells: Should be set to <3>. + First parameter is request line number. + Second is DMA channel configuration + Third is Fifo threshold + For more details about the three cells, please see + stm32-dma.txt documentation binding file +- dma-masters: Phandle pointing to the DMA controllers. + Several controllers are allowed. Only "st,stm32-dma" DMA + compatible are supported. + +Optional properties: +- dma-channels : Number of DMA requests supported. +- dma-requests : Number of DMAMUX requests supported. +- resets: Reference to a reset controller asserting the DMA controller +- clocks: Input clock of the DMAMUX instance. + +Example: + +/* DMA controller 1 */ +dma1: dma-controller@40020000 { + compatible = "st,stm32-dma"; + reg = <0x40020000 0x400>; + interrupts = <11>, + <12>, + <13>, + <14>, + <15>, + <16>, + <17>, + <47>; + clocks = <&timer_clk>; + #dma-cells = <4>; + st,mem2mem; + resets = <&rcc 150>; + dma-channels = <8>; + dma-requests = <8>; +}; + +/* DMA controller 1 */ +dma2: dma@40020400 { + compatible = "st,stm32-dma"; + reg = <0x40020400 0x400>; + interrupts = <56>, + <57>, + <58>, + <59>, + <60>, + <68>, + <69>, + <70>; + clocks = <&timer_clk>; + #dma-cells = <4>; + st,mem2mem; + resets = <&rcc 150>; + dma-channels = <8>; + dma-requests = <8>; +}; + +/* DMA mux */ +dmamux1: dma-router@40020800 { + compatible = "st,stm32h7-dmamux"; + reg = <0x40020800 0x3c>; + #dma-cells = <3>; + dma-requests = <128>; + dma-channels = <16>; + dma-masters = <&dma1 &dma2>; + clocks = <&timer_clk>; +}; + +/* DMA client */ +usart1: serial@40011000 { + compatible = "st,stm32-usart", "st,stm32-uart"; + reg = <0x40011000 0x400>; + interrupts = <37>; + clocks = <&timer_clk>; + dmas = <&dmamux1 41 0x414 0>, + <&dmamux1 42 0x414 0>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/stm32-mdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/stm32-mdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..d18772d6bc6560f460f06c5072735874b9890861 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/stm32-mdma.txt @@ -0,0 +1,94 @@ +* STMicroelectronics STM32 MDMA controller + +The STM32 MDMA is a general-purpose direct memory access controller capable of +supporting 64 independent DMA channels with 256 HW requests. + +Required properties: +- compatible: Should be "st,stm32h7-mdma" +- reg: Should contain MDMA registers location and length. This should include + all of the per-channel registers. +- interrupts: Should contain the MDMA interrupt. +- clocks: Should contain the input clock of the DMA instance. +- resets: Reference to a reset controller asserting the DMA controller. +- #dma-cells : Must be <5>. See DMA client paragraph for more details. + +Optional properties: +- dma-channels: Number of DMA channels supported by the controller. +- dma-requests: Number of DMA request signals supported by the controller. +- st,ahb-addr-masks: Array of u32 mask to list memory devices addressed via + AHB bus. + +Example: + + mdma1: dma@52000000 { + compatible = "st,stm32h7-mdma"; + reg = <0x52000000 0x1000>; + interrupts = <122>; + clocks = <&timer_clk>; + resets = <&rcc 992>; + #dma-cells = <5>; + dma-channels = <16>; + dma-requests = <32>; + st,ahb-addr-masks = <0x20000000>, <0x00000000>; + }; + +* DMA client + +DMA clients connected to the STM32 MDMA controller must use the format +described in the dma.txt file, using a five-cell specifier for each channel: +a phandle to the MDMA controller plus the following five integer cells: + +1. The request line number +2. The priority level + 0x00: Low + 0x01: Medium + 0x10: High + 0x11: Very high +3. A 32bit mask specifying the DMA channel configuration + -bit 0-1: Source increment mode + 0x00: Source address pointer is fixed + 0x10: Source address pointer is incremented after each data transfer + 0x11: Source address pointer is decremented after each data transfer + -bit 2-3: Destination increment mode + 0x00: Destination address pointer is fixed + 0x10: Destination address pointer is incremented after each data + transfer + 0x11: Destination address pointer is decremented after each data + transfer + -bit 8-9: Source increment offset size + 0x00: byte (8bit) + 0x01: half-word (16bit) + 0x10: word (32bit) + 0x11: double-word (64bit) + -bit 10-11: Destination increment offset size + 0x00: byte (8bit) + 0x01: half-word (16bit) + 0x10: word (32bit) + 0x11: double-word (64bit) +-bit 25-18: The number of bytes to be transferred in a single transfer + (min = 1 byte, max = 128 bytes) +-bit 29:28: Trigger Mode + 0x00: Each MDMA request triggers a buffer transfer (max 128 bytes) + 0x01: Each MDMA request triggers a block transfer (max 64K bytes) + 0x10: Each MDMA request triggers a repeated block transfer + 0x11: Each MDMA request triggers a linked list transfer +4. A 32bit value specifying the register to be used to acknowledge the request + if no HW ack signal is used by the MDMA client +5. A 32bit mask specifying the value to be written to acknowledge the request + if no HW ack signal is used by the MDMA client + +Example: + + i2c4: i2c@5c002000 { + compatible = "st,stm32f7-i2c"; + reg = <0x5c002000 0x400>; + interrupts = <95>, + <96>; + clocks = <&timer_clk>; + #address-cells = <1>; + #size-cells = <0>; + dmas = <&mdma1 36 0x0 0x40008 0x0 0x0>, + <&mdma1 37 0x0 0x40002 0x0 0x0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/sun4i-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/sun4i-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ad556aca70b56dad0177dba779fa8b8cee2c888 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/sun4i-dma.txt @@ -0,0 +1,45 @@ +Allwinner A10 DMA Controller + +This driver follows the generic DMA bindings defined in dma.txt. + +Required properties: + +- compatible: Must be "allwinner,sun4i-a10-dma" +- reg: Should contain the registers base address and length +- interrupts: Should contain a reference to the interrupt used by this device +- clocks: Should contain a reference to the parent AHB clock +- #dma-cells : Should be 2, first cell denoting normal or dedicated dma, + second cell holding the request line number. + +Example: + dma: dma-controller@1c02000 { + compatible = "allwinner,sun4i-a10-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <27>; + clocks = <&ahb_gates 6>; + #dma-cells = <2>; + }; + +Clients: + +DMA clients connected to the Allwinner A10 DMA controller must use the +format described in the dma.txt file, using a three-cell specifier for +each channel: a phandle plus two integer cells. +The three cells in order are: + +1. A phandle pointing to the DMA controller. +2. Whether it is using normal (0) or dedicated (1) channels +3. The port ID as specified in the datasheet + +Example: + spi2: spi@1c17000 { + compatible = "allwinner,sun4i-a10-spi"; + reg = <0x01c17000 0x1000>; + interrupts = <0 12 4>; + clocks = <&ahb_gates 22>, <&spi2_clk>; + clock-names = "ahb", "mod"; + dmas = <&dma 1 29>, <&dma 1 28>; + dma-names = "rx", "tx"; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/sun6i-dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/sun6i-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fccc20d83311c22713370968638190720c90e1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/sun6i-dma.txt @@ -0,0 +1,76 @@ +Allwinner A31 DMA Controller + +This driver follows the generic DMA bindings defined in dma.txt. + +Required properties: + +- compatible: Must be one of + "allwinner,sun6i-a31-dma" + "allwinner,sun8i-a23-dma" + "allwinner,sun8i-a83t-dma" + "allwinner,sun8i-h3-dma" + "allwinner,sun8i-v3s-dma" +- reg: Should contain the registers base address and length +- interrupts: Should contain a reference to the interrupt used by this device +- clocks: Should contain a reference to the parent AHB clock +- resets: Should contain a reference to the reset controller asserting + this device in reset +- #dma-cells : Should be 1, a single cell holding a line request number + +Example: + dma: dma-controller@1c02000 { + compatible = "allwinner,sun6i-a31-dma"; + reg = <0x01c02000 0x1000>; + interrupts = <0 50 4>; + clocks = <&ahb1_gates 6>; + resets = <&ahb1_rst 6>; + #dma-cells = <1>; + }; + +------------------------------------------------------------------------------ +For A64 DMA controller: + +Required properties: +- compatible: "allwinner,sun50i-a64-dma" +- dma-channels: Number of DMA channels supported by the controller. + Refer to Documentation/devicetree/bindings/dma/dma.txt +- all properties above, i.e. reg, interrupts, clocks, resets and #dma-cells + +Optional properties: +- dma-requests: Number of DMA request signals supported by the controller. + Refer to Documentation/devicetree/bindings/dma/dma.txt + +Example: + dma: dma-controller@1c02000 { + compatible = "allwinner,sun50i-a64-dma"; + reg = <0x01c02000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_DMA>; + dma-channels = <8>; + dma-requests = <27>; + resets = <&ccu RST_BUS_DMA>; + #dma-cells = <1>; + }; +------------------------------------------------------------------------------ + +Clients: + +DMA clients connected to the A31 DMA controller must use the format +described in the dma.txt file, using a two-cell specifier for each +channel: a phandle plus one integer cells. +The two cells in order are: + +1. A phandle pointing to the DMA controller. +2. The port ID as specified in the datasheet + +Example: +spi2: spi@1c6a000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c6a000 0x1000>; + interrupts = <0 67 4>; + clocks = <&ahb1_gates 22>, <&spi2_clk>; + clock-names = "ahb", "mod"; + dmas = <&dma 25>, <&dma 25>; + dma-names = "rx", "tx"; + resets = <&ahb1_rst 22>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/ti-dma-crossbar.txt b/arch/arm64/boot/dts/vendor/bindings/dma/ti-dma-crossbar.txt new file mode 100644 index 0000000000000000000000000000000000000000..b849a1ed389d55df9662ca5708f8b93424b9ce88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/ti-dma-crossbar.txt @@ -0,0 +1,68 @@ +Texas Instruments DMA Crossbar (DMA request router) + +Required properties: +- compatible: "ti,dra7-dma-crossbar" for DRA7xx DMA crossbar + "ti,am335x-edma-crossbar" for AM335x and AM437x +- reg: Memory map for accessing module +- #dma-cells: Should be set to to match with the DMA controller's dma-cells + for ti,dra7-dma-crossbar and <3> for ti,am335x-edma-crossbar. +- dma-requests: Number of DMA requests the crossbar can receive +- dma-masters: phandle pointing to the DMA controller + +The DMA controller node need to have the following poroperties: +- dma-requests: Number of DMA requests the controller can handle + +Optional properties: +- ti,dma-safe-map: Safe routing value for unused request lines +- ti,reserved-dma-request-ranges: DMA request ranges which should not be used + when mapping xbar input to DMA request, they are either + allocated to be used by for example the DSP or they are used as + memcpy channels in eDMA. + +Notes: +When requesting channel via ti,dra7-dma-crossbar, the DMA clinet must request +the DMA event number as crossbar ID (input to the DMA crossbar). + +For ti,am335x-edma-crossbar: the meaning of parameters of dmas for clients: +dmas = <&edma_xbar 12 0 1>; where <12> is the DMA request number, <0> is the TC +the event should be assigned and <1> is the mux selection for in the crossbar. +When mux 0 is used the DMA channel can be requested directly from edma node. + +Example: + +/* DMA controller */ +sdma: dma-controller@4a056000 { + compatible = "ti,omap4430-sdma"; + reg = <0x4a056000 0x1000>; + interrupts = , + , + , + ; + #dma-cells = <1>; + dma-channels = <32>; + dma-requests = <127>; +}; + +/* DMA crossbar */ +sdma_xbar: dma-router@4a002b78 { + compatible = "ti,dra7-dma-crossbar"; + reg = <0x4a002b78 0xfc>; + #dma-cells = <1>; + dma-requests = <205>; + ti,dma-safe-map = <0>; + /* Protect the sDMA request ranges: 10-14 and 100-126 */ + ti,reserved-dma-request-ranges = <10 5>, <100 27>; + dma-masters = <&sdma>; +}; + +/* DMA client */ +uart1: serial@4806a000 { + compatible = "ti,omap4-uart"; + reg = <0x4806a000 0x100>; + interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; + ti,hwmods = "uart1"; + clock-frequency = <48000000>; + /* Requesting crossbar input 49 and 50 */ + dmas = <&sdma_xbar 49>, <&sdma_xbar 50>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/ti-edma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/ti-edma.txt new file mode 100644 index 0000000000000000000000000000000000000000..4bbc94d829c8aa8c54f13de98e7a526dc72c0eb6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/ti-edma.txt @@ -0,0 +1,230 @@ +Texas Instruments eDMA + +The eDMA3 consists of two components: Channel controller (CC) and Transfer +Controller(s) (TC). The CC is the main entry for DMA users since it is +responsible for the DMA channel handling, while the TCs are responsible to +execute the actual DMA tansfer. + +------------------------------------------------------------------------------ +eDMA3 Channel Controller + +Required properties: +-------------------- +- compatible: Should be: + - "ti,edma3-tpcc" for the channel controller(s) on OMAP, + AM33xx and AM43xx SoCs. + - "ti,k2g-edma3-tpcc", "ti,edma3-tpcc" for the + channel controller(s) on 66AK2G. +- #dma-cells: Should be set to <2>. The first number is the DMA request + number and the second is the TC the channel is serviced on. +- reg: Memory map of eDMA CC +- reg-names: "edma3_cc" +- interrupts: Interrupt lines for CCINT, MPERR and CCERRINT. +- interrupt-names: "edma3_ccint", "edma3_mperr" and "edma3_ccerrint" +- ti,tptcs: List of TPTCs associated with the eDMA in the following form: + <&tptc_phandle TC_priority_number>. The highest priority is 0. + +SoC-specific Required properties: +-------------------------------- +The following are mandatory properties for OMAP, AM33xx and AM43xx SoCs only: +- ti,hwmods: Name of the hwmods associated to the eDMA CC. + +The following are mandatory properties for 66AK2G SoCs only: +- power-domains:Should contain a phandle to a PM domain provider node + and an args specifier containing the device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt + +Optional properties: +------------------- +- ti,edma-memcpy-channels: List of channels allocated to be used for memcpy, iow + these channels will be SW triggered channels. See example. +- ti,edma-reserved-slot-ranges: PaRAM slot ranges which should not be used by + the driver, they are allocated to be used by for example the + DSP. See example. + +------------------------------------------------------------------------------ +eDMA3 Transfer Controller + +Required properties: +-------------------- +- compatible: Should be: + - "ti,edma3-tptc" for the transfer controller(s) on OMAP, + AM33xx and AM43xx SoCs. + - "ti,k2g-edma3-tptc", "ti,edma3-tptc" for the + transfer controller(s) on 66AK2G. +- reg: Memory map of eDMA TC +- interrupts: Interrupt number for TCerrint. + +SoC-specific Required properties: +-------------------------------- +The following are mandatory properties for OMAP, AM33xx and AM43xx SoCs only: +- ti,hwmods: Name of the hwmods associated to the eDMA TC. + +The following are mandatory properties for 66AK2G SoCs only: +- power-domains:Should contain a phandle to a PM domain provider node + and an args specifier containing the device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt + +Optional properties: +------------------- +- interrupt-names: "edma3_tcerrint" + +------------------------------------------------------------------------------ +Examples: + +1. +edma: edma@49000000 { + compatible = "ti,edma3-tpcc"; + ti,hwmods = "tpcc"; + reg = <0x49000000 0x10000>; + reg-names = "edma3_cc"; + interrupts = <12 13 14>; + interrupt-names = "edma3_ccint", "edma3_mperr", "edma3_ccerrint"; + dma-requests = <64>; + #dma-cells = <2>; + + ti,tptcs = <&edma_tptc0 7>, <&edma_tptc1 7>, <&edma_tptc2 0>; + + /* Channel 20 and 21 is allocated for memcpy */ + ti,edma-memcpy-channels = <20 21>; + /* The following PaRAM slots are reserved: 35-44 and 100-109 */ + ti,edma-reserved-slot-ranges = <35 10>, <100 10>; +}; + +edma_tptc0: tptc@49800000 { + compatible = "ti,edma3-tptc"; + ti,hwmods = "tptc0"; + reg = <0x49800000 0x100000>; + interrupts = <112>; + interrupt-names = "edm3_tcerrint"; +}; + +edma_tptc1: tptc@49900000 { + compatible = "ti,edma3-tptc"; + ti,hwmods = "tptc1"; + reg = <0x49900000 0x100000>; + interrupts = <113>; + interrupt-names = "edm3_tcerrint"; +}; + +edma_tptc2: tptc@49a00000 { + compatible = "ti,edma3-tptc"; + ti,hwmods = "tptc2"; + reg = <0x49a00000 0x100000>; + interrupts = <114>; + interrupt-names = "edm3_tcerrint"; +}; + +sham: sham@53100000 { + compatible = "ti,omap4-sham"; + ti,hwmods = "sham"; + reg = <0x53100000 0x200>; + interrupts = <109>; + /* DMA channel 36 executed on eDMA TC0 - low priority queue */ + dmas = <&edma 36 0>; + dma-names = "rx"; +}; + +mcasp0: mcasp@48038000 { + compatible = "ti,am33xx-mcasp-audio"; + ti,hwmods = "mcasp0"; + reg = <0x48038000 0x2000>, + <0x46000000 0x400000>; + reg-names = "mpu", "dat"; + interrupts = <80>, <81>; + interrupt-names = "tx", "rx"; + /* DMA channels 8 and 9 executed on eDMA TC2 - high priority queue */ + dmas = <&edma 8 2>, + <&edma 9 2>; + dma-names = "tx", "rx"; +}; + +2. +edma1: edma@2728000 { + compatible = "ti,k2g-edma3-tpcc", "ti,edma3-tpcc"; + reg = <0x02728000 0x8000>; + reg-names = "edma3_cc"; + interrupts = , + , + ; + interrupt-names = "edma3_ccint", "emda3_mperr", + "edma3_ccerrint"; + dma-requests = <64>; + #dma-cells = <2>; + + ti,tptcs = <&edma1_tptc0 7>, <&edma1_tptc1 0>; + + /* + * memcpy is disabled, can be enabled with: + * ti,edma-memcpy-channels = <12 13 14 15>; + * for example. + */ + + power-domains = <&k2g_pds 0x4f>; +}; + +edma1_tptc0: tptc@27b0000 { + compatible = "ti,k2g-edma3-tptc", "ti,edma3-tptc"; + reg = <0x027b0000 0x400>; + power-domains = <&k2g_pds 0x4f>; +}; + +edma1_tptc1: tptc@27b8000 { + compatible = "ti, k2g-edma3-tptc", "ti,edma3-tptc"; + reg = <0x027b8000 0x400>; + power-domains = <&k2g_pds 0x4f>; +}; + +mmc0: mmc@23000000 { + compatible = "ti,k2g-hsmmc", "ti,omap4-hsmmc"; + reg = <0x23000000 0x400>; + interrupts = ; + dmas = <&edma1 24 0>, <&edma1 25 0>; + dma-names = "tx", "rx"; + bus-width = <4>; + ti,needs-special-reset; + no-1-8-v; + max-frequency = <96000000>; + power-domains = <&k2g_pds 0xb>; + clocks = <&k2g_clks 0xb 1>, <&k2g_clks 0xb 2>; + clock-names = "fck", "mmchsdb_fck"; +}; + +------------------------------------------------------------------------------ +DEPRECATED binding, new DTS files must use the ti,edma3-tpcc/ti,edma3-tptc +binding. + +Required properties: +- compatible : "ti,edma3" +- #dma-cells: Should be set to <1> + Clients should use a single channel number per DMA request. +- reg: Memory map for accessing module +- interrupts: Exactly 3 interrupts need to be specified in the order: + 1. Transfer completion interrupt. + 2. Memory protection interrupt. + 3. Error interrupt. +Optional properties: +- ti,hwmods: Name of the hwmods associated to the EDMA +- ti,edma-xbar-event-map: Crossbar event to channel map + +Deprecated properties: +Listed here in case one wants to boot an old kernel with new DTB. These +properties might need to be added to the new DTS files. +- ti,edma-regions: Number of regions +- ti,edma-slots: Number of slots +- dma-channels: Specify total DMA channels per CC + +Example: + +edma: edma@49000000 { + reg = <0x49000000 0x10000>; + interrupt-parent = <&intc>; + interrupts = <12 13 14>; + compatible = "ti,edma3"; + ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; + #dma-cells = <1>; + ti,edma-xbar-event-map = /bits/ 16 <1 12 + 2 13>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/xilinx/xilinx_dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/xilinx/xilinx_dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..174af2c45e7774ca5c15de325d4db580cca694e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/xilinx/xilinx_dma.txt @@ -0,0 +1,117 @@ +Xilinx AXI VDMA engine, it does transfers between memory and video devices. +It can be configured to have one channel or two channels. If configured +as two channels, one is to transmit to the video device and another is +to receive from the video device. + +Xilinx AXI DMA engine, it does transfers between memory and AXI4 stream +target devices. It can be configured to have one channel or two channels. +If configured as two channels, one is to transmit to the device and another +is to receive from the device. + +Xilinx AXI CDMA engine, it does transfers between memory-mapped source +address and a memory-mapped destination address. + +Required properties: +- compatible: Should be "xlnx,axi-vdma-1.00.a" or "xlnx,axi-dma-1.00.a" or + "xlnx,axi-cdma-1.00.a"" +- #dma-cells: Should be <1>, see "dmas" property below +- reg: Should contain VDMA registers location and length. +- xlnx,addrwidth: Should be the vdma addressing size in bits(ex: 32 bits). +- dma-ranges: Should be as the following . +- dma-channel child node: Should have at least one channel and can have up to + two channels per device. This node specifies the properties of each + DMA channel (see child node properties below). +- clocks: Input clock specifier. Refer to common clock bindings. +- clock-names: List of input clocks + For VDMA: + Required elements: "s_axi_lite_aclk" + Optional elements: "m_axi_mm2s_aclk" "m_axi_s2mm_aclk", + "m_axis_mm2s_aclk", "s_axis_s2mm_aclk" + For CDMA: + Required elements: "s_axi_lite_aclk", "m_axi_aclk" + FOR AXIDMA: + Required elements: "s_axi_lite_aclk" + Optional elements: "m_axi_mm2s_aclk", "m_axi_s2mm_aclk", + "m_axi_sg_aclk" + +Required properties for VDMA: +- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w. + +Optional properties: +- xlnx,include-sg: Tells configured for Scatter-mode in + the hardware. +Optional properties for AXI DMA: +- xlnx,mcdma: Tells whether configured for multi-channel mode in the hardware. +Optional properties for VDMA: +- xlnx,flush-fsync: Tells which channel to Flush on Frame sync. + It takes following values: + {1}, flush both channels + {2}, flush mm2s channel + {3}, flush s2mm channel + +Required child node properties: +- compatible: + For VDMA: It should be either "xlnx,axi-vdma-mm2s-channel" or + "xlnx,axi-vdma-s2mm-channel". + For CDMA: It should be "xlnx,axi-cdma-channel". + For AXIDMA: It should be either "xlnx,axi-dma-mm2s-channel" or + "xlnx,axi-dma-s2mm-channel". +- interrupts: Should contain per channel VDMA interrupts. +- xlnx,datawidth: Should contain the stream data width, take values + {32,64...1024}. + +Optional child node properties: +- xlnx,include-dre: Tells hardware is configured for Data + Realignment Engine. +Optional child node properties for VDMA: +- xlnx,genlock-mode: Tells Genlock synchronization is + enabled/disabled in hardware. +- xlnx,enable-vert-flip: Tells vertical flip is + enabled/disabled in hardware(S2MM path). +Optional child node properties for AXI DMA: +-dma-channels: Number of dma channels in child node. + +Example: +++++++++ + +axi_vdma_0: axivdma@40030000 { + compatible = "xlnx,axi-vdma-1.00.a"; + #dma_cells = <1>; + reg = < 0x40030000 0x10000 >; + dma-ranges = <0x00000000 0x00000000 0x40000000>; + xlnx,num-fstores = <0x8>; + xlnx,flush-fsync = <0x1>; + xlnx,addrwidth = <0x20>; + clocks = <&clk 0>, <&clk 1>, <&clk 2>, <&clk 3>, <&clk 4>; + clock-names = "s_axi_lite_aclk", "m_axi_mm2s_aclk", "m_axi_s2mm_aclk", + "m_axis_mm2s_aclk", "s_axis_s2mm_aclk"; + dma-channel@40030000 { + compatible = "xlnx,axi-vdma-mm2s-channel"; + interrupts = < 0 54 4 >; + xlnx,datawidth = <0x40>; + } ; + dma-channel@40030030 { + compatible = "xlnx,axi-vdma-s2mm-channel"; + interrupts = < 0 53 4 >; + xlnx,datawidth = <0x40>; + } ; +} ; + + +* DMA client + +Required properties: +- dmas: a list of <[Video DMA device phandle] [Channel ID]> pairs, + where Channel ID is '0' for write/tx and '1' for read/rx + channel. +- dma-names: a list of DMA channel names, one per "dmas" entry + +Example: +++++++++ + +vdmatest_0: vdmatest@0 { + compatible ="xlnx,axi-vdma-test-1.00.a"; + dmas = <&axi_vdma_0 0 + &axi_vdma_0 1>; + dma-names = "vdma0", "vdma1"; +} ; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/xilinx/zynqmp_dma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/xilinx/zynqmp_dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..07a5a7aa9ea05964d74bcccbe75f882d86fa6501 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/xilinx/zynqmp_dma.txt @@ -0,0 +1,26 @@ +Xilinx ZynqMP DMA engine, it does support memory to memory transfers, +memory to device and device to memory transfers. It also has flow +control and rate control support for slave/peripheral dma access. + +Required properties: +- compatible : Should be "xlnx,zynqmp-dma-1.0" +- reg : Memory map for gdma/adma module access. +- interrupts : Should contain DMA channel interrupt. +- xlnx,bus-width : Axi buswidth in bits. Should contain 128 or 64 +- clock-names : List of input clocks "clk_main", "clk_apb" + (see clock bindings for details) + +Optional properties: +- dma-coherent : Present if dma operations are coherent. + +Example: +++++++++ +fpd_dma_chan1: dma@fd500000 { + compatible = "xlnx,zynqmp-dma-1.0"; + reg = <0x0 0xFD500000 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 117 4>; + clock-names = "clk_main", "clk_apb"; + xlnx,bus-width = <128>; + dma-coherent; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/dma/zxdma.txt b/arch/arm64/boot/dts/vendor/bindings/dma/zxdma.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ab80f69e566ef7c66001486a7cd5acea5685df8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/dma/zxdma.txt @@ -0,0 +1,38 @@ +* ZTE ZX296702 DMA controller + +Required properties: +- compatible: Should be "zte,zx296702-dma" +- reg: Should contain DMA registers location and length. +- interrupts: Should contain one interrupt shared by all channel +- #dma-cells: see dma.txt, should be 1, para number +- dma-channels: physical channels supported +- dma-requests: virtual channels supported, each virtual channel + have specific request line +- clocks: clock required + +Example: + +Controller: + dma: dma-controller@09c00000{ + compatible = "zte,zx296702-dma"; + reg = <0x09c00000 0x1000>; + clocks = <&topclk ZX296702_DMA_ACLK>; + interrupts = ; + #dma-cells = <1>; + dma-channels = <24>; + dma-requests = <24>; + }; + +Client: +Use specific request line passing from dmax +For example, spdif0 tx channel request line is 4 + spdif0: spdif0@b004000 { + #sound-dai-cells = <0>; + compatible = "zte,zx296702-spdif"; + reg = <0x0b004000 0x1000>; + clocks = <&lsp0clk ZX296702_SPDIF0_DIV>; + clock-names = "tx"; + interrupts = ; + dmas = <&dma 4>; + dma-names = "tx"; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/edac/apm-xgene-edac.txt b/arch/arm64/boot/dts/vendor/bindings/edac/apm-xgene-edac.txt new file mode 100644 index 0000000000000000000000000000000000000000..1006b04894642685a984081121c4b9229181a55c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/edac/apm-xgene-edac.txt @@ -0,0 +1,112 @@ +* APM X-Gene SoC EDAC node + +EDAC node is defined to describe on-chip error detection and correction. +The follow error types are supported: + + memory controller - Memory controller + PMD (L1/L2) - Processor module unit (PMD) L1/L2 cache + L3 - L3 cache controller + SoC - SoC IP's such as Ethernet, SATA, and etc + +The following section describes the EDAC DT node binding. + +Required properties: +- compatible : Shall be "apm,xgene-edac". +- regmap-csw : Regmap of the CPU switch fabric (CSW) resource. +- regmap-mcba : Regmap of the MCB-A (memory bridge) resource. +- regmap-mcbb : Regmap of the MCB-B (memory bridge) resource. +- regmap-efuse : Regmap of the PMD efuse resource. +- regmap-rb : Regmap of the register bus resource. This property + is optional only for compatibility. If the RB + error conditions are not cleared, it will + continuously generate interrupt. +- reg : First resource shall be the CPU bus (PCP) resource. +- interrupts : Interrupt-specifier for MCU, PMD, L3, or SoC error + IRQ(s). + +Required properties for memory controller subnode: +- compatible : Shall be "apm,xgene-edac-mc". +- reg : First resource shall be the memory controller unit + (MCU) resource. +- memory-controller : Instance number of the memory controller. + +Required properties for PMD subnode: +- compatible : Shall be "apm,xgene-edac-pmd" or + "apm,xgene-edac-pmd-v2". +- reg : First resource shall be the PMD resource. +- pmd-controller : Instance number of the PMD controller. + +Required properties for L3 subnode: +- compatible : Shall be "apm,xgene-edac-l3" or + "apm,xgene-edac-l3-v2". +- reg : First resource shall be the L3 EDAC resource. + +Required properties for SoC subnode: +- compatible : Shall be "apm,xgene-edac-soc-v1" for revision 1 or + "apm,xgene-edac-l3-soc" for general value reporting + only. +- reg : First resource shall be the SoC EDAC resource. + +Example: + csw: csw@7e200000 { + compatible = "apm,xgene-csw", "syscon"; + reg = <0x0 0x7e200000 0x0 0x1000>; + }; + + mcba: mcba@7e700000 { + compatible = "apm,xgene-mcb", "syscon"; + reg = <0x0 0x7e700000 0x0 0x1000>; + }; + + mcbb: mcbb@7e720000 { + compatible = "apm,xgene-mcb", "syscon"; + reg = <0x0 0x7e720000 0x0 0x1000>; + }; + + efuse: efuse@1054a000 { + compatible = "apm,xgene-efuse", "syscon"; + reg = <0x0 0x1054a000 0x0 0x20>; + }; + + rb: rb@7e000000 { + compatible = "apm,xgene-rb", "syscon"; + reg = <0x0 0x7e000000 0x0 0x10>; + }; + + edac@78800000 { + compatible = "apm,xgene-edac"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + regmap-csw = <&csw>; + regmap-mcba = <&mcba>; + regmap-mcbb = <&mcbb>; + regmap-efuse = <&efuse>; + regmap-rb = <&rb>; + reg = <0x0 0x78800000 0x0 0x100>; + interrupts = <0x0 0x20 0x4>, + <0x0 0x21 0x4>, + <0x0 0x27 0x4>; + + edacmc@7e800000 { + compatible = "apm,xgene-edac-mc"; + reg = <0x0 0x7e800000 0x0 0x1000>; + memory-controller = <0>; + }; + + edacpmd@7c000000 { + compatible = "apm,xgene-edac-pmd"; + reg = <0x0 0x7c000000 0x0 0x200000>; + pmd-controller = <0>; + }; + + edacl3@7e600000 { + compatible = "apm,xgene-edac-l3"; + reg = <0x0 0x7e600000 0x0 0x1000>; + }; + + edacsoc@7e930000 { + compatible = "apm,xgene-edac-soc-v1"; + reg = <0x0 0x7e930000 0x0 0x1000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/edac/arm64_cache_erp.txt b/arch/arm64/boot/dts/vendor/bindings/edac/arm64_cache_erp.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b600be55787693ab60d68d8dd35064c3bad215f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/edac/arm64_cache_erp.txt @@ -0,0 +1,34 @@ +* ARM Cortex A53 / A57 cache error reporting driver + +Required properties: +- compatible: Should be "arm,arm64-cpu-erp" +- interrupts: List of hardware interrupts that may indicate an error condition + in the CPU subsystem, or in the L1 / L2 caches. At least one interrupt entry + is required. +- interrupt-names: Must contain one or more of the following IRQ types: + "pri-dbe-irq" - double-bit error interrupt for primary cluster + "sec-dbe-irq" - double-bit error interrupt for secondary cluster + "pri-ext-irq" - external bus error interrupt for primary cluster + "sec-ext-irq" - external bus error interrupt for secondary cluster + "cci-irq" - CCI error interrupt. If this property is present, having + the 'cci' reg-base defined using the 'reg' property is + recommended. + At least one irq entry is required. + +Optional properties: +- reg: Should contain physical address of the CCI register space +- reg-names: Should contain 'cci'. Must be present if 'reg' property is present +- poll-delay-msec: Indicates how often the edac check callback should be called. Time in msec. + +Example: + cpu_cache_erp { + compatible = "arm,arm64-cpu-erp"; + interrupt-names = "pri-dbe-irq", + "sec-dbe-irq", + "pri-ext-irq", + "sec-ext-irq"; + interrupts = <0 92 0>, + <0 91 0>, + <0 96 0>, + <0 95 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/edac/kryo-edac.txt b/arch/arm64/boot/dts/vendor/bindings/edac/kryo-edac.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7362911ac646cba0fd95b16ab7260f19c62fe05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/edac/kryo-edac.txt @@ -0,0 +1,32 @@ +* Kryo EDAC node + +Kryo EDAC node is defined to describe on-chip error detection and correction +for the Kryo core. + +Kryo will report all SBE and DBE found in L1/L2/L3/SCU caches in two registers: + ERRXSTATUS - Error Record Primary Status Register + ERRXMISC0 - Error Record Miscellaneous Register + +Current implementation of Kryo ECC mechanism is based on interrupts. + +The following section describes the DT node binding for kryo_cpu_erp. + +Required properties: +- compatible : Shall be "arm,arm64-kryo-cpu-erp". +- interrupts : Interrupt-specifier for L1/L2, L3/SCU error IRQ(s) +- interrupt-names : Descriptive names of the interrupts + +Example: + + kryo-erp { + compatible = "arm,arm64-kryo-cpu-erp"; + interrupts = <1 6 4>, + <1 7 4>, + <0 34 4>, + <0 35 4>; + + interrupt-names = "l1-l2-faultirq", + "l1-l2-errirq", + "l3-scu-errirq", + "l3-scu-faultirq"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/edac/socfpga-eccmgr.txt b/arch/arm64/boot/dts/vendor/bindings/edac/socfpga-eccmgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..5626560a6cfdff805ebd1460a14ec2127747de4a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/edac/socfpga-eccmgr.txt @@ -0,0 +1,268 @@ +Altera SoCFPGA ECC Manager +This driver uses the EDAC framework to implement the SOCFPGA ECC Manager. +The ECC Manager counts and corrects single bit errors and counts/handles +double bit errors which are uncorrectable. + +Cyclone5 and Arria5 ECC Manager +Required Properties: +- compatible : Should be "altr,socfpga-ecc-manager" +- #address-cells: must be 1 +- #size-cells: must be 1 +- ranges : standard definition, should translate from local addresses + +Subcomponents: + +L2 Cache ECC +Required Properties: +- compatible : Should be "altr,socfpga-l2-ecc" +- reg : Address and size for ECC error interrupt clear registers. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt. Note the rising edge type. + +On Chip RAM ECC +Required Properties: +- compatible : Should be "altr,socfpga-ocram-ecc" +- reg : Address and size for ECC error interrupt clear registers. +- iram : phandle to On-Chip RAM definition. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt. Note the rising edge type. + +Example: + + eccmgr: eccmgr@ffd08140 { + compatible = "altr,socfpga-ecc-manager"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + l2-ecc@ffd08140 { + compatible = "altr,socfpga-l2-ecc"; + reg = <0xffd08140 0x4>; + interrupts = <0 36 1>, <0 37 1>; + }; + + ocram-ecc@ffd08144 { + compatible = "altr,socfpga-ocram-ecc"; + reg = <0xffd08144 0x4>; + iram = <&ocram>; + interrupts = <0 178 1>, <0 179 1>; + }; + }; + +Arria10 SoCFPGA ECC Manager +The Arria10 SoC ECC Manager handles the IRQs for each peripheral +in a shared register instead of individual IRQs like the Cyclone5 +and Arria5. Therefore the device tree is different as well. + +Required Properties: +- compatible : Should be "altr,socfpga-a10-ecc-manager" +- altr,sysgr-syscon : phandle to Arria10 System Manager Block + containing the ECC manager registers. +- #address-cells: must be 1 +- #size-cells: must be 1 +- interrupts : Should be single bit error interrupt, then double bit error + interrupt. +- interrupt-controller : boolean indicator that ECC Manager is an interrupt controller +- #interrupt-cells : must be set to 2. +- ranges : standard definition, should translate from local addresses + +Subcomponents: + +L2 Cache ECC +Required Properties: +- compatible : Should be "altr,socfpga-a10-l2-ecc" +- reg : Address and size for ECC error interrupt clear registers. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +On-Chip RAM ECC +Required Properties: +- compatible : Should be "altr,socfpga-a10-ocram-ecc" +- reg : Address and size for ECC block registers. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +Ethernet FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-eth-mac-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent Ethernet node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +NAND FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-nand-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent NAND node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +DMA FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-dma-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent DMA node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +USB FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-usb-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent USB node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +QSPI FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-qspi-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent QSPI node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +SDMMC FIFO ECC +Required Properties: +- compatible : Should be "altr,socfpga-sdmmc-ecc" +- reg : Address and size for ECC block registers. +- altr,ecc-parent : phandle to parent SD/MMC node. +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order for port A, and then single bit error interrupt, + then double bit error interrupt in this order for port B. + +Example: + + eccmgr: eccmgr@ffd06000 { + compatible = "altr,socfpga-a10-ecc-manager"; + altr,sysmgr-syscon = <&sysmgr>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = <0 2 IRQ_TYPE_LEVEL_HIGH>, + <0 0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <2>; + ranges; + + l2-ecc@ffd06010 { + compatible = "altr,socfpga-a10-l2-ecc"; + reg = <0xffd06010 0x4>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>, + <32 IRQ_TYPE_LEVEL_HIGH>; + }; + + ocram-ecc@ff8c3000 { + compatible = "altr,socfpga-a10-ocram-ecc"; + reg = <0xff8c3000 0x90>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>, + <33 IRQ_TYPE_LEVEL_HIGH> ; + }; + + emac0-rx-ecc@ff8c0800 { + compatible = "altr,socfpga-eth-mac-ecc"; + reg = <0xff8c0800 0x400>; + altr,ecc-parent = <&gmac0>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>, + <36 IRQ_TYPE_LEVEL_HIGH>; + }; + + emac0-tx-ecc@ff8c0c00 { + compatible = "altr,socfpga-eth-mac-ecc"; + reg = <0xff8c0c00 0x400>; + altr,ecc-parent = <&gmac0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, + <37 IRQ_TYPE_LEVEL_HIGH>; + }; + + nand-buf-ecc@ff8c2000 { + compatible = "altr,socfpga-nand-ecc"; + reg = <0xff8c2000 0x400>; + altr,ecc-parent = <&nand>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>, + <43 IRQ_TYPE_LEVEL_HIGH>; + }; + + nand-rd-ecc@ff8c2400 { + compatible = "altr,socfpga-nand-ecc"; + reg = <0xff8c2400 0x400>; + altr,ecc-parent = <&nand>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH>, + <45 IRQ_TYPE_LEVEL_HIGH>; + }; + + nand-wr-ecc@ff8c2800 { + compatible = "altr,socfpga-nand-ecc"; + reg = <0xff8c2800 0x400>; + altr,ecc-parent = <&nand>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, + <44 IRQ_TYPE_LEVEL_HIGH>; + }; + + dma-ecc@ff8c8000 { + compatible = "altr,socfpga-dma-ecc"; + reg = <0xff8c8000 0x400>; + altr,ecc-parent = <&pdma>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>, + <42 IRQ_TYPE_LEVEL_HIGH>; + + usb0-ecc@ff8c8800 { + compatible = "altr,socfpga-usb-ecc"; + reg = <0xff8c8800 0x400>; + altr,ecc-parent = <&usb0>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, + <34 IRQ_TYPE_LEVEL_HIGH>; + }; + + qspi-ecc@ff8c8400 { + compatible = "altr,socfpga-qspi-ecc"; + reg = <0xff8c8400 0x400>; + altr,ecc-parent = <&qspi>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, + <46 IRQ_TYPE_LEVEL_HIGH>; + }; + + sdmmc-ecc@ff8c2c00 { + compatible = "altr,socfpga-sdmmc-ecc"; + reg = <0xff8c2c00 0x400>; + altr,ecc-parent = <&mmc>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH>, + <47 IRQ_TYPE_LEVEL_HIGH>, + <16 IRQ_TYPE_LEVEL_HIGH>, + <48 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + +Stratix10 SoCFPGA ECC Manager +The Stratix10 SoC ECC Manager handles the IRQs for each peripheral +in a shared register similar to the Arria10. However, ECC requires +access to registers that can only be read from Secure Monitor with +SMC calls. Therefore the device tree is slightly different. + +Required Properties: +- compatible : Should be "altr,socfpga-s10-ecc-manager" +- interrupts : Should be single bit error interrupt, then double bit error + interrupt. +- interrupt-controller : boolean indicator that ECC Manager is an interrupt controller +- #interrupt-cells : must be set to 2. + +Subcomponents: + +SDRAM ECC +Required Properties: +- compatible : Should be "altr,sdram-edac-s10" +- interrupts : Should be single bit error interrupt, then double bit error + interrupt, in this order. + +Example: + + eccmgr { + compatible = "altr,socfpga-s10-ecc-manager"; + interrupts = <0 15 4>, <0 95 4>; + interrupt-controller; + #interrupt-cells = <2>; + + sdramedac { + compatible = "altr,sdram-edac-s10"; + interrupts = <16 4>, <48 4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/eeprom/at24.txt b/arch/arm64/boot/dts/vendor/bindings/eeprom/at24.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9a7c984274ce739c392a3af08c0775199d6e32e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/eeprom/at24.txt @@ -0,0 +1,85 @@ +EEPROMs (I2C) + +Required properties: + + - compatible: Must be a "," pair. The following + values are supported (assuming "atmel" as manufacturer): + + "atmel,24c00", + "atmel,24c01", + "atmel,24cs01", + "atmel,24c02", + "atmel,24cs02", + "atmel,24mac402", + "atmel,24mac602", + "atmel,spd", + "atmel,24c04", + "atmel,24cs04", + "atmel,24c08", + "atmel,24cs08", + "atmel,24c16", + "atmel,24cs16", + "atmel,24c32", + "atmel,24cs32", + "atmel,24c64", + "atmel,24cs64", + "atmel,24c128", + "atmel,24c256", + "atmel,24c512", + "atmel,24c1024", + "atmel,24c2048", + + If is not "atmel", then a fallback must be used + with the same and "atmel" as manufacturer. + + Example: + compatible = "microchip,24c128", "atmel,24c128"; + + Supported manufacturers are: + + "catalyst", + "microchip", + "nxp", + "ramtron", + "renesas", + "rohm", + "st", + + Some vendors use different model names for chips which are just + variants of the above. Known such exceptions are listed below: + + "nxp,se97b" - the fallback is "atmel,24c02", + "renesas,r1ex24002" - the fallback is "atmel,24c02" + "renesas,r1ex24128" - the fallback is "atmel,24c128" + "rohm,br24t01" - the fallback is "atmel,24c01" + + - reg: The I2C address of the EEPROM. + +Optional properties: + + - pagesize: The length of the pagesize for writing. Please consult the + manual of your device, that value varies a lot. A wrong value + may result in data loss! If not specified, a safety value of + '1' is used which will be very slow. + + - read-only: This parameterless property disables writes to the eeprom. + + - size: Total eeprom size in bytes. + + - no-read-rollover: This parameterless property indicates that the + multi-address eeprom does not automatically roll over + reads to the next slave address. Please consult the + manual of your device. + + - wp-gpios: GPIO to which the write-protect pin of the chip is connected. + + - address-width: number of address bits (one of 8, 16). + +Example: + +eeprom@52 { + compatible = "atmel,24c32"; + reg = <0x52>; + pagesize = <32>; + wp-gpios = <&gpio1 3 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/eeprom/at25.txt b/arch/arm64/boot/dts/vendor/bindings/eeprom/at25.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3bde97dc19913ea7e552a0206aa0f6e6fe4c093 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/eeprom/at25.txt @@ -0,0 +1,42 @@ +EEPROMs (SPI) compatible with Atmel at25. + +Required properties: +- compatible : Should be ",", and generic value "atmel,at25". + Example "," values: + "microchip,25lc040" + "st,m95m02" + "st,m95256" + +- reg : chip select number +- spi-max-frequency : max spi frequency to use +- pagesize : size of the eeprom page +- size : total eeprom size in bytes +- address-width : number of address bits (one of 8, 9, 16, or 24). + For 9 bits, the MSB of the address is sent as bit 3 of the instruction + byte, before the address byte. + +Optional properties: +- spi-cpha : SPI shifted clock phase, as per spi-bus bindings. +- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings. +- read-only : this parameter-less property disables writes to the eeprom + +Obsolete legacy properties can be used in place of "size", "pagesize", +"address-width", and "read-only": +- at25,byte-len : total eeprom size in bytes +- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h +- at25,page-size : size of the eeprom page + +Additional compatible properties are also allowed. + +Example: + eeprom@0 { + compatible = "st,m95256", "atmel,at25"; + reg = <0> + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-arizona.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-arizona.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f3d94ae81ffb64f5b9de085d9f1015eca5b7b8a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-arizona.txt @@ -0,0 +1,76 @@ +Cirrus Logic Arizona class audio SoCs + +These devices are audio SoCs with extensive digital capabilities and a range +of analogue I/O. + +This document lists Extcon specific bindings, see the primary binding document: + ../mfd/arizona.txt + +Optional properties: + + - wlf,hpdet-channel : Headphone detection channel. + ARIZONA_ACCDET_MODE_HPL or 1 - Headphone detect mode is set to HPDETL + ARIZONA_ACCDET_MODE_HPR or 2 - Headphone detect mode is set to HPDETR + If this node is not mentioned or if the value is unknown, then + headphone detection mode is set to HPDETL. + + - wlf,use-jd2 : Use the additional JD input along with JD1 for dual pin jack + detection. + - wlf,use-jd2-nopull : Internal pull on JD2 is disabled when used for + jack detection. + - wlf,jd-invert : Invert the polarity of the jack detection switch + + - wlf,micd-software-compare : Use a software comparison to determine mic + presence + - wlf,micd-detect-debounce : Additional software microphone detection + debounce specified in milliseconds. + - wlf,micd-pol-gpio : GPIO specifier for the GPIO controlling the headset + polarity if one exists. + - wlf,micd-bias-start-time : Time allowed for MICBIAS to startup prior to + performing microphone detection, specified as per the ARIZONA_MICD_TIME_XXX + defines. + - wlf,micd-rate : Delay between successive microphone detection measurements, + specified as per the ARIZONA_MICD_TIME_XXX defines. + - wlf,micd-dbtime : Microphone detection hardware debounces specified as the + number of measurements to take, valid values being 2 and 4. + - wlf,micd-timeout-ms : Timeout for microphone detection, specified in + milliseconds. + - wlf,micd-force-micbias : Force MICBIAS continuously on during microphone + detection. + - wlf,micd-configs : Headset polarity configurations (generally used for + detection of CTIA / OMTP headsets), the field can be of variable length + but should always be a multiple of 3 cells long, each three cell group + represents one polarity configuration. + The first cell defines the accessory detection pin, zero will use MICDET1 + and all other values will use MICDET2. + The second cell represents the MICBIAS to be used. + The third cell represents the value of the micd-pol-gpio pin. + + - wlf,gpsw : Settings for the general purpose switch, set as one of the + ARIZONA_GPSW_XXX defines. + +Example: + +codec: wm8280@0 { + compatible = "wlf,wm8280"; + reg = <0>; + ... + + wlf,use-jd2; + wlf,use-jd2-nopull; + wlf,jd-invert; + + wlf,micd-software-compare; + wlf,micd-detect-debounce = <0>; + wlf,micd-pol-gpio = <&codec 2 0>; + wlf,micd-rate = ; + wlf,micd-dbtime = <4>; + wlf,micd-timeout-ms = <100>; + wlf,micd-force-micbias; + wlf,micd-configs = < + 0 1 0 /* MICDET1 MICBIAS1 GPIO=low */ + 1 2 1 /* MICDET2 MICBIAS2 GPIO=high */ + >; + + wlf,gpsw = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..f453fb5c86f2a8e09a20b6a0ed28b02944b1e85c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-gpio.txt @@ -0,0 +1,32 @@ +GPIO Extcon device + +This is a virtual device used to generate GPIO states from the GPIO ID pin +connected to a GPIO pin. + +Required properties: +- compatible: Should be "extcon-gpio" +- extcon-id: The unique id of specific external connector. + Valid range is 0 (EXTCON_NONE) to 63 (EXTCON_NUM). + Refer include/linux/extcon.h for details. +- gpio: Specify GPIO (see gpio binding) +- debounce-ms: Debounce time for GPIO IRQ in ms +- irq-flags: interrupt flags (edge/level). Refer to "include/dt-bindings/interrupt-controller/irq.h" +- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + for these optional properties + +Example: + extcon_storage_cd { + compatible = "extcon-gpio"; + extcon-id = <62>; /* EXTCON_MECHANICAL */ + gpio = <&tlmm 126 GPIO_ACTIVE_LOW>; + debounce-ms = <200>; + irq-flags = ; + } + + &ufshc_card { + extcon = <&extcon_storage_cd>; + }; + + &sd_card { + extcon = <&extcon_storage_cd>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-max3355.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-max3355.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2288ea9eb8288a52abe5d7147defedab3474234 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-max3355.txt @@ -0,0 +1,21 @@ +Maxim Integrated MAX3355 USB OTG chip +------------------------------------- + +MAX3355 integrates a charge pump and comparators to enable a system with an +integrated USB OTG dual-role transceiver to function as a USB OTG dual-role +device. + +Required properties: +- compatible: should be "maxim,max3355"; +- maxim,shdn-gpios: should contain a phandle and GPIO specifier for the GPIO pin + connected to the MAX3355's SHDN# pin; +- id-gpios: should contain a phandle and GPIO specifier for the GPIO pin + connected to the MAX3355's ID_OUT pin. + +Example: + + usb-otg { + compatible = "maxim,max3355"; + maxim,shdn-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; + id-gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-palmas.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-palmas.txt new file mode 100644 index 0000000000000000000000000000000000000000..f61d5af44a27f20d21479c9920081906440674a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-palmas.txt @@ -0,0 +1,22 @@ +EXTCON FOR PALMAS/TWL CHIPS + +PALMAS USB COMPARATOR +Required Properties: + - compatible: should contain one of: + * "ti,palmas-usb-vid". + * "ti,twl6035-usb-vid". + * "ti,palmas-usb" (DEPRECATED - use "ti,palmas-usb-vid"). + * "ti,twl6035-usb" (DEPRECATED - use "ti,twl6035-usb-vid"). + +Optional Properties: + - ti,wakeup : To enable the wakeup comparator in probe + - ti,enable-id-detection: Perform ID detection. If id-gpio is specified + it performs id-detection using GPIO else using OTG core. + - ti,enable-vbus-detection: Perform VBUS detection. + - id-gpio: gpio for GPIO ID detection. See gpio binding. + - debounce-delay-ms: debounce delay for GPIO ID pin in milliseconds. + +palmas-usb { + compatible = "ti,twl6035-usb", "ti,palmas-usb"; + ti,wakeup; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-rt8973a.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-rt8973a.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfcf455ad4deffc1e4819934e6dc6fb3f95a54a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-rt8973a.txt @@ -0,0 +1,23 @@ + +* Richtek RT8973A - Micro USB Switch device + +The Richtek RT8973A is Micro USB Switch with OVP and I2C interface. The RT8973A +is a USB port accessory detector and switch that is optimized to protect low +voltage system from abnormal high input voltage (up to 28V) and supports high +speed USB operation. Also, RT8973A support 'auto-configuration' mode. +If auto-configuration mode is enabled, RT8973A would control internal h/w patch +for USB D-/D+ switching. + +Required properties: +- compatible: Should be "richtek,rt8973a-muic" +- reg: Specifies the I2C slave address of the MUIC block. It should be 0x14 +- interrupts: Interrupt specifiers for detection interrupt sources. + +Example: + + rt8973a@14 { + compatible = "richtek,rt8973a-muic"; + interrupt-parent = <&gpx1>; + interrupts = <5 0>; + reg = <0x14>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-sm5502.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-sm5502.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc3888e09549eb44cc8eb4e385d0ba637bc37904 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-sm5502.txt @@ -0,0 +1,21 @@ + +* SM5502 MUIC (Micro-USB Interface Controller) device + +The Silicon Mitus SM5502 is a MUIC (Micro-USB Interface Controller) device +which can detect the state of external accessory when external accessory is +attached or detached and button is pressed or released. It is interfaced to +the host controller using an I2C interface. + +Required properties: +- compatible: Should be "siliconmitus,sm5502-muic" +- reg: Specifies the I2C slave address of the MUIC block. It should be 0x25 +- interrupts: Interrupt specifiers for detection interrupt sources. + +Example: + + sm5502@25 { + compatible = "siliconmitus,sm5502-muic"; + interrupt-parent = <&gpx1>; + interrupts = <5 0>; + reg = <0x25>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-usb-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-usb-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e904ca94538d2f7e103866da62f9b3db04b4920 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-usb-gpio.txt @@ -0,0 +1,24 @@ +USB GPIO Extcon device + +This is a virtual device used to generate USB cable states from the USB ID pin +connected to a GPIO pin. + +Required properties: +- compatible: Should be "linux,extcon-usb-gpio" + +Either one of id-gpio or vbus-gpio must be present. Both can be present as well. +- id-gpio: gpio for USB ID pin. See gpio binding. +- vbus-gpio: gpio for USB VBUS pin. + +Optional properties: +- vbus-out-gpio: gpio for enabling VBUS output (e.g. when entering host mode) + +Example: Examples of extcon-usb-gpio node in dra7-evm.dts as listed below: + extcon_usb1 { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&gpio6 1 GPIO_ACTIVE_HIGH>; + } + + &omap_dwc3_1 { + extcon = <&extcon_usb1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-usbc-cros-ec.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-usbc-cros-ec.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e8625c00dfac9926743f0d3f8441519021797e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/extcon-usbc-cros-ec.txt @@ -0,0 +1,24 @@ +ChromeOS EC USB Type-C cable and accessories detection + +On ChromeOS systems with USB Type C ports, the ChromeOS Embedded Controller is +able to detect the state of external accessories such as display adapters +or USB devices when said accessories are attached or detached. + +The node for this device must be under a cros-ec node like google,cros-ec-spi +or google,cros-ec-i2c. + +Required properties: +- compatible: Should be "google,extcon-usbc-cros-ec". +- google,usb-port-id: Specifies the USB port ID to use. + +Example: + cros-ec@0 { + compatible = "google,cros-ec-i2c"; + + ... + + extcon { + compatible = "google,extcon-usbc-cros-ec"; + google,usb-port-id = <0>; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/extcon/qcom,pm8941-misc.txt b/arch/arm64/boot/dts/vendor/bindings/extcon/qcom,pm8941-misc.txt new file mode 100644 index 0000000000000000000000000000000000000000..35383adb10f16abd054c2e599fea2fd40b69764f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/extcon/qcom,pm8941-misc.txt @@ -0,0 +1,41 @@ +Qualcomm's PM8941 USB ID Extcon device + +Some Qualcomm PMICs have a "misc" module that can be used to detect when +the USB ID pin has been pulled low or high. + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,pm8941-misc"; + +- reg: + Usage: required + Value type: + Definition: Should contain the offset to the misc address space + +- interrupts: + Usage: required + Value type: + Definition: Should contain the usb id interrupt + +- interrupt-names: + Usage: required + Value type: + Definition: Should contain the string "usb_id" for the usb id interrupt + +Example: + + pmic { + usb_id: misc@900 { + compatible = "qcom,pm8941-misc"; + reg = <0x900>; + interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "usb_id"; + }; + } + + usb-controller { + extcon = <&usb_id>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/adv7533.txt b/arch/arm64/boot/dts/vendor/bindings/fb/adv7533.txt new file mode 100644 index 0000000000000000000000000000000000000000..b198f37f8fc610ad8bb77c7110fed95008e85cdc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/adv7533.txt @@ -0,0 +1,54 @@ +ADV7533 DSI to HDMI bridge + + +Required properties: +- compatible: Must be "adv7533" +- reg: Main I2C slave ID (for I2C host driver) +- adi,video-mode: Excepted a number and possible inputs are 0 to 3, while: + 3 = 1080p + 2 = 720p + 1 = 480p + 0 = 1080p pattern +- adi,main-addr: Main I2C slave ID +- adi,cec-dsi-addr: CEC DSI I2C slave ID + +Optional properties: +- adi,enable-audio: +- adi,disable-gpios: +- adi,irq-gpio: Main IRQ gpio mapping +- adi,hpd-irq-gpio: HPD IRQ gpio mapping +- adi,switch-gpio: DSI switch gpio mapping +- qcom,supply-names: Regulator names that supply 5v to bridge chip +- qcom,min-voltage-level Minimum voltage level to be supplied to bridge chip +- qcom,max-voltage-level Maximum voltage level to be supplied to bridge chip +- qcom,enable-load Load current to bridge chip when enabled +- qcom,disable-load Load current to bridge chip when disabled +- qcom,post-on-sleep Sleep time (ms) to indicate the sleep + time after the vreg is enabled + +Example: +&soc { + i2c@78b8000 { + adv7533@39 { + compatible = "adv7533"; + reg = <0x39>; + adi,video-mode = <3>; /* 3 = 1080p */ + adi,main-addr = <0x39>; + adi,cec-dsi-addr = <0x3C>; + adi,enable-audio; + pinctrl-names = "pmx_adv7533_active","pmx_adv7533_suspend"; + pinctrl-0 = <&adv7533_int_active &adv7533_hpd_int_active &adv7533_switch_active>; + pinctrl-1 = <&adv7533_int_suspend &adv7533_hpd_int_suspend &adv7533_switch_suspend>; + adi,irq-gpio = <&msm_gpio 31 0x2002>; + adi,hpd-irq-gpio = <&msm_gpio 20 0x2003>; + adi,switch-gpio = <&msm_gpio 32 0x0>; + hpd-5v-en-supply = <&adv_vreg>; + qcom,supply-names = "hpd-5v-en"; + qcom,min-voltage-level = <0>; + qcom,max-voltage-level = <0>; + qcom,enable-load = <0>; + qcom,disable-load = <0>; + qcom,post-on-sleep = <10>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/lt8912.txt b/arch/arm64/boot/dts/vendor/bindings/fb/lt8912.txt new file mode 100644 index 0000000000000000000000000000000000000000..daeb15fe3ab555c2de51d733487b84ce98957391 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/lt8912.txt @@ -0,0 +1,20 @@ +LT8912 DSI to HDMI bridge + + +Required properties: +- compatible: Must be "lontium,lt8912" +- reg: Main I2C slave ID (for I2C host driver) + +Optional properties: +- qcom,hdmi-reset: Main reset gpio mapping + +Example: +&soc { + i2c@78b8000 { + lt8912@48 { + compatible = "lontium,lt8912"; + reg = <0x48>; + qcom,hdmi-reset = <&tlmm 64 0x0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dp.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dp.txt new file mode 100644 index 0000000000000000000000000000000000000000..707e6edb26eaa9e4466232d74e231dc56905de03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dp.txt @@ -0,0 +1,195 @@ +QTI MDSS DP + +MDSS DP is a display-port driver which supports panels that are compatible with +VESA DP and EDP display interface specification. + +When configuring the optional properties for external backlight, one should also +configure the gpio that drives the pwm to it. + +Required properties +- compatible : Must be "qcom,mdss-edp". +- reg : Offset and length of the register set for the + device. +- reg-names : Names to refer to register sets related to this + device +- gdsc-supply : Phandle for gdsc regulator device node. +- vdda-1p2-supply : Phandle for 1.2V vdda regulator device node. +- vdda-0p9-supply : Phandle for 0.9V vdda regulator device node. +- status : A string that has to be set to "okay/ok" to enable + the driver. By default this property will be set to + "disable". Will be set to "ok/okay" status for + specific platforms. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- qcom,aux-en-gpio: Specifies the aux-channel enable gpio. +- qcom,aux-sel-gpio: Specifies the aux-channel select gpio. +- qcom,usbplug-cc-gpio: Specifies the usbplug orientation gpio. +- qcom,aux-cfg0-settings: Specifies the DP AUX configuration 0 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg1-settings: Specifies the DP AUX configuration 1 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg2-settings: Specifies the DP AUX configuration 2 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg3-settings: Specifies the DP AUX configuration 3 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg4-settings: Specifies the DP AUX configuration 4 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg5-settings: Specifies the DP AUX configuration 5 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg6-settings: Specifies the DP AUX configuration 6 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg7-settings: Specifies the DP AUX configuration 7 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg8-settings: Specifies the DP AUX configuration 8 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. +- qcom,aux-cfg9-settings: Specifies the DP AUX configuration 9 settings. The first + entry in this array corresponds to the register offset + within DP AUX, while the remaining entries indicate the + programmable values. + +Optional properties: +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI modulee. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- qcom,hpd-gpio: Specifies the HPD gpio. +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt +- qcom,logical2physical-lane-map: An array that specifies the DP logical to physical lane map setting. +- qcom,phy-register-offset: An integer specifying the offset value of DP PHY register space. +- qcom,max-pclk-frequency-khz: An integer specifying the max. pixel clock in KHz supported by Display Port. + +Example: + mdss_dp_ctrl: qcom,dp_ctrl@c990000 { + cell-index = <0>; + compatible = "qcom,mdss-dp"; + qcom,mdss-fb-map = <&mdss_fb3>; + + gdsc-supply = <&gdsc_mdss>; + vdda-1p2-supply = <&pm8998_l2>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xc990000 0xa84>, + <0xc011000 0x910>, + <0x1fcb200 0x050>; + reg-names = "dp_ctrl", "dp_phy", "tcsr_regs"; + + clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_mdss_ahb_clk>, + <&clock_mmss clk_mmss_mdss_axi_clk>, + <&clock_mmss clk_mmss_mdss_mdp_clk>, + <&clock_mmss clk_mmss_mdss_hdmi_dp_ahb_clk>, + <&clock_mmss clk_mmss_mdss_dp_aux_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, + <&clock_mmss clk_mmss_mdss_dp_link_clk>, + <&clock_mmss clk_mmss_mdss_dp_link_intf_clk>, + <&clock_mmss clk_mmss_mdss_dp_crypto_clk>, + <&clock_mmss clk_mmss_mdss_dp_pixel_clk>; + clock-names = "core_mnoc_clk", "core_iface_clk", "core_bus_clk", + "core_mdp_core_clk", "core_alt_iface_clk", + "core_aux_clk", "core_cfg_ahb_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", "ctrl_pixel_clk"; + + qcom,aux-cfg0-settings = [1c 00]; + qcom,aux-cfg1-settings = [20 13 23 1d]; + qcom,aux-cfg2-settings = [24 00]; + qcom,aux-cfg3-settings = [28 00]; + qcom,aux-cfg4-settings = [2c 0a]; + qcom,aux-cfg5-settings = [30 26]; + qcom,aux-cfg6-settings = [34 0a]; + qcom,aux-cfg7-settings = [38 03]; + qcom,aux-cfg8-settings = [3c bb]; + qcom,aux-cfg9-settings = [40 03]; + qcom,logical2physical-lane-map = [02 03 01 00]; + qcom,phy-register-offset = <0x4>; + qcom,max-pclk-frequency-khz = <593470>; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <12560>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <73400>; + qcom,supply-disable-load = <32>; + }; + }; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active + &mdss_dp_hpd_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend + &mdss_dp_hpd_suspend>; + qcom,aux-en-gpio = <&tlmm 77 0>; + qcom,aux-sel-gpio = <&tlmm 78 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; + qcom,hpd-gpio = <&tlmm 34 0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dsi-panel.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dsi-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..2182ade92b46fbea8f3d4f8d1cb2e885dbb5a48f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dsi-panel.txt @@ -0,0 +1,839 @@ +Qualcomm Technologies, Inc. mdss-dsi-panel + +mdss-dsi-panel is a dsi panel device which supports panels that +are compatible with MIPI display serial interface specification. + +Required properties: +- compatible: This property applies to DSI V2 panels only. + This property should not be added for panels + that work based on version "V6.0" + DSI panels that are of different versions + are initialized by the drivers for dsi controller. + This property specifies the version + for DSI HW that this panel will work with + "qcom,dsi-panel-v2" = DSI V2.0 + "qcom,msm-dsi-v2" = DSI V2.0 +- status: This property applies to DSI V2 panels only. + This property should not be added for panels + that work based on version "V6.0" + DSI panels that are of different versions + are initialized by the drivers for dsi controller. + A string that has to be set to "okay/ok" + to enable the panel driver. By default this property + will be set to "disable". Will be set to "ok/okay" + status for specific platforms. +- qcom,mdss-dsi-panel-controller: Specifies the phandle for the DSI controller that + this panel will be mapped to. +- qcom,mdss-dsi-panel-width: Specifies panel width in pixels. +- qcom,mdss-dsi-panel-height: Specifies panel height in pixels. +- qcom,mdss-dsi-bpp: Specifies the panel bits per pixel. + 3 = for rgb111 + 8 = for rgb332 + 12 = for rgb444 + 16 = for rgb565 + 18 = for rgb666 + 24 = for rgb888 +- qcom,mdss-dsi-panel-destination: A string that specifies the destination display for the panel. + "display_1" = DISPLAY_1 + "display_2" = DISPLAY_2 +- qcom,mdss-dsi-panel-timings: An array of length 12 that specifies the PHY + timing settings for the panel. +- qcom,mdss-dsi-panel-timings-phy-v2: An array of length 40 char that specifies the PHY version 2 + lane timing settings for the panel. +- qcom,mdss-dsi-panel-timings-phy-12nm: An array of length 8 char that specifies the 12nm DSI PHY + lane timing settings for the panel. +- qcom,mdss-dsi-on-command: A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-off-command: A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-on: This is used to enable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-lp-mode-off: This is used to disable display low persistence mode. + A byte stream formed by multiple dcs packets base on + qcom dsi controller protocol. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are + sent after displaying an image. + +- qcom,mdss-dsi-idle-on-command: same as "qcom,mdss-dsi-on-command". Set of DCS command + used for idle mode entry. + +- qcom,mdss-dsi-idle-off-command: same as "qcom,mdss-dsi-on-command". Set of DCS command + used for idle mode exit. + +Note, if a short DCS packet(i.e packet with Byte 0:dcs data type as 05) mentioned in +qcom,mdss-dsi-on-command/qcom,mdss-dsi-off-command stream fails to transmit, +then 3 options can be tried. + 1. Send the packet as a long packet instead + Byte 0: dcs data type = 05 (DCS short Packet) + Byte 0: dcs data type = 29 (DCS long Packet) + 2. Send the packet in one burst by prepending with the next packet in packet stream + Byte 1 = 01 (indicates this is an individual packet) + Byte 1 = 00 (indicates this will be appended to the next + individual packet in the packet stream) + 3. Prepend a NULL packet to the short packet and send both in one burst instead of + combining multiple short packets and sending them in one burst. + +Optional properties: +- qcom,mdss-dsi-panel-name: A string used as a descriptive name of the panel +- qcom,cmd-sync-wait-broadcast: Boolean used to broadcast dcs command to panels. +- qcom,mdss-dsi-fbc-enable: Boolean used to enable frame buffer compression mode. +- qcom,mdss-dsi-fbc-slice-height: Slice height(in lines) of compressed block. + Expressed as power of 2. To set as 128 lines, + this should be set to 7. +- qcom,mdss-dsi-fbc-2d-pred-mode: Boolean to enable 2D map prediction. +- qcom,mdss-dsi-fbc-ver2-mode: Boolean to enable FBC 2.0 that supports 1/3 + compression. +- qcom,mdss-dsi-fbc-bpp: Compressed bpp supported by the panel. + Specified color order is used as default value. +- qcom,mdss-dsi-fbc-packing: Component packing. + 0 = default value. +- qcom,mdss-dsi-fbc-quant-error: Boolean used to enable quantization error calculation. +- qcom,mdss-dsi-fbc-bias: Bias for CD. + 0 = default value. +- qcom,mdss-dsi-fbc-pat-mode: Boolean used to enable PAT mode. +- qcom,mdss-dsi-fbc-vlc-mode: Boolean used to enable VLC mode. +- qcom,mdss-dsi-fbc-bflc-mode: Boolean used to enable BFLC mode. +- qcom,mdss-dsi-fbc-h-line-budget: Per line extra budget. + 0 = default value. +- qcom,mdss-dsi-fbc-budget-ctrl: Extra budget level. + 0 = default value. +- qcom,mdss-dsi-fbc-block-budget: Per block budget. + 0 = default value. +- qcom,mdss-dsi-fbc-lossless-threshold: Lossless mode threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-lossy-threshold: Lossy mode threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-rgb-threshold: Lossy RGB threshold. + 0 = default value. +- qcom,mdss-dsi-fbc-lossy-mode-idx: Lossy mode index value. + 0 = default value. +- qcom,mdss-dsi-fbc-max-pred-err: Max quantization prediction error. + 0 = default value +- qcom,mdss-dsi-h-back-porch: Horizontal back porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-h-front-porch: Horizontal front porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-h-pulse-width: Horizontal pulse width. + 2 = default value. +- qcom,mdss-dsi-h-sync-skew: Horizontal sync skew value. + 0 = default value. +- qcom,mdss-dsi-v-back-porch: Vertical back porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-v-front-porch: Vertical front porch value in pixel. + 6 = default value. +- qcom,mdss-dsi-v-pulse-width: Vertical pulse width. + 2 = default value. +- qcom,mdss-dsi-h-left-border: Horizontal left border in pixel. + 0 = default value +- qcom,mdss-dsi-h-right-border: Horizontal right border in pixel. + 0 = default value +- qcom,mdss-dsi-v-top-border: Vertical top border in pixel. + 0 = default value +- qcom,mdss-dsi-v-bottom-border: Vertical bottom border in pixel. + 0 = default value +- qcom,mdss-dsi-underflow-color: Specifies the controller settings for the + panel under flow color. + 0xff = default value. +- qcom,mdss-dsi-border-color: Defines the border color value if border is present. + 0 = default value. +- qcom,mdss-dsi-pan-enable-dynamic-fps: Boolean used to enable change in frame rate dynamically. +- qcom,mdss-dsi-pan-fps-update: A string that specifies when to change the frame rate. + "dfps_suspend_resume_mode"= FPS change request is + implemented during suspend/resume. + "dfps_immediate_clk_mode" = FPS change request is + implemented immediately using DSI clocks. + "dfps_immediate_porch_mode_hfp" = FPS change request is + implemented immediately by changing panel horizontal + front porch values. + "dfps_immediate_porch_mode_vfp" = FPS change request is + implemented immediately by changing panel vertical + front porch values. +- qcom,min-refresh-rate: Minimum refresh rate supported by the panel. +- qcom,max-refresh-rate: Maximum refresh rate supported by the panel. If max refresh + rate is not specified, then the frame rate of the panel in + qcom,mdss-dsi-panel-framerate is used. +- qcom,mdss-dsi-bl-pmic-control-type: A string that specifies the implementation of backlight + control for this panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + "bl_ctrl_dcs" = Backlight controlled by DCS commands. + "bl_ctrl_tlmm_gpio" = Backlight controlled by TLMM GPIO. + other: Unknown backlight control. (default) +- qcom,mdss-dsi-bl-pwm-pmi: Boolean to indicate that PWM control is through second pmic chip. +- qcom,mdss-dsi-bl-pmic-bank-select: LPG channel for backlight. + Required if blpmiccontroltype is PWM +- qcom,mdss-dsi-bl-pmic-pwm-frequency: PWM period in microseconds. + Required if blpmiccontroltype is PWM +- qcom,mdss-dsi-pwm-gpio: PMIC gpio binding to backlight. + Required if blpmiccontroltype is PWM +- qcom,mdss-dsi-bl-min-level: Specifies the min backlight level supported by the panel. + 0 = default value. +- qcom,mdss-dsi-bl-max-level: Specifies the max backlight level supported by the panel. + 255 = default value. +- qcom,mdss-brightness-max-level: Specifies the max brightness level supported. + 255 = default value. +- qcom,mdss-dsi-interleave-mode: Specifies interleave mode. + 0 = default value. +- qcom,mdss-dsi-panel-type: Specifies the panel operating mode. + "dsi_video_mode" = enable video mode (default). + "dsi_cmd_mode" = enable command mode. +- qcom,5v-boost-gpio: Specifies the panel gpio for display 5v boost. +- qcom,mdss-dsi-te-check-enable: Boolean to enable Tear Check configuration. +- qcom,mdss-dsi-te-using-te-pin: Boolean to specify whether using hardware vsync. +- qcom,mdss-dsi-te-pin-select: Specifies TE operating mode. + 0 = TE through embedded dcs command + 1 = TE through TE gpio pin. (default) +- qcom,mdss-dsi-te-dcs-command: Inserts the dcs command. + 1 = default value. +- qcom,mdss-dsi-wr-mem-start: DCS command for write_memory_start. + 0x2c = default value. +- qcom,mdss-dsi-wr-mem-continue: DCS command for write_memory_continue. + 0x3c = default value. +- qcom,mdss-dsi-h-sync-pulse: Specifies the pulse mode option for the panel. + 0 = Don't send hsa/he following vs/ve packet(default) + 1 = Send hsa/he following vs/ve packet +- qcom,mdss-dsi-hfp-power-mode: Boolean to determine DSI lane state during + horizontal front porch (HFP) blanking period. +- qcom,mdss-dsi-hbp-power-mode: Boolean to determine DSI lane state during + horizontal back porch (HBP) blanking period. +- qcom,mdss-dsi-hsa-power-mode: Boolean to determine DSI lane state during + horizontal sync active (HSA) mode. +- qcom,mdss-dsi-last-line-interleave Boolean to determine if last line + interleave flag needs to be enabled. +- qcom,mdss-dsi-bllp-eof-power-mode: Boolean to determine DSI lane state during + blanking low power period (BLLP) EOF mode. +- qcom,mdss-dsi-bllp-power-mode: Boolean to determine DSI lane state during + blanking low power period (BLLP) mode. +- qcom,mdss-dsi-traffic-mode: Specifies the panel traffic mode. + "non_burst_sync_pulse" = non burst with sync pulses (default). + "non_burst_sync_event" = non burst with sync start event. + "burst_mode" = burst mode. +- qcom,mdss-dsi-pixel-packing: Specifies if pixel packing is used (in case of RGB666). + "tight" = Tight packing (default value). + "loose" = Loose packing. +- qcom,mdss-dsi-virtual-channel-id: Specifies the virtual channel identefier. + 0 = default value. +- qcom,mdss-dsi-color-order: Specifies the R, G and B channel ordering. + "rgb_swap_rgb" = DSI_RGB_SWAP_RGB (default value) + "rgb_swap_rbg" = DSI_RGB_SWAP_RBG + "rgb_swap_brg" = DSI_RGB_SWAP_BRG + "rgb_swap_grb" = DSI_RGB_SWAP_GRB + "rgb_swap_gbr" = DSI_RGB_SWAP_GBR +- qcom,mdss-dsi-lane-0-state: Boolean that specifies whether data lane 0 is enabled. +- qcom,mdss-dsi-lane-1-state: Boolean that specifies whether data lane 1 is enabled. +- qcom,mdss-dsi-lane-2-state: Boolean that specifies whether data lane 2 is enabled. +- qcom,mdss-dsi-lane-3-state: Boolean that specifies whether data lane 3 is enabled. +- qcom,mdss-dsi-t-clk-post: Specifies the byte clock cycles after mode switch. + 0x03 = default value. +- qcom,mdss-dsi-t-clk-pre: Specifies the byte clock cycles before mode switch. + 0x24 = default value. +- qcom,mdss-dsi-stream: Specifies the packet stream to be used. + 0 = stream 0 (default) + 1 = stream 1 +- qcom,mdss-dsi-mdp-trigger: Specifies the trigger mechanism to be used for MDP path. + "none" = no trigger + "trigger_te" = Tear check signal line used for trigger + "trigger_sw" = Triggered by software (default) + "trigger_sw_te" = Software trigger and TE +- qcom,mdss-dsi-dma-trigger: Specifies the trigger mechanism to be used for DMA path. + "none" = no trigger + "trigger_te" = Tear check signal line used for trigger + "trigger_sw" = Triggered by software (default) + "trigger_sw_seof" = Software trigger and start/end of frame trigger. + "trigger_sw_te" = Software trigger and TE +- qcom,mdss-dsi-panel-framerate: Specifies the frame rate for the panel. + 60 = 60 frames per second (default) +- qcom,mdss-dsi-panel-clockrate: A 64 bit value specifies the panel clock speed in Hz. + 0 = default value. +- qcom,mdss-mdp-kickoff-threshold: This property can be used to define a region + (in terms of scanlines) where the +hardware is allowed + to trigger a data transfer from MDP to DSI. + If this property is used, the region must be defined setting + two values, the low and the high thresholds: + + Where following condition must be met: + low_threshold < high_threshold + These values will be used by the driver in such way that if + the Driver receives a request to kickoff a transfer (MDP to DSI), + the transfer will be triggered only if the following condition + is satisfied: + low_threshold < scanline < high_threshold + If the condition is not met, then the driver will delay the + transfer by the time defined in the following property: + "qcom,mdss-mdp-kickoff-delay". + So in order to use this property, the delay property must + be defined as well and greater than 0. +- qcom,mdss-mdp-kickoff-delay: This property defines the delay in microseconds that + the driver will delay before triggering an MDP transfer if the + thresholds defined by the following property are not met: + "qcom,mdss-mdp-kickoff-threshold". + So in order to use this property, the threshold property must + be defined as well. Note that this delay cannot be zero + and also should not be greater than +the fps window. + i.e. For 60fps value should not exceed +16666 uS. +- qcom,mdss-mdp-transfer-time-us: Specifies the dsi transfer time for command mode + panels in microseconds. Driver uses this number to adjust + the clock rate according to the expected transfer time. + Increasing this value would slow down the mdp processing + and can result in slower performance. + Decreasing this value can speed up the mdp processing, + but this can also impact power consumption. + As a rule this time should not be higher than the time + that would be expected with the processing at the + dsi link rate since anyways this would be the maximum + transfer time that could be achieved. + If ping pong split enabled, this time should not be higher + than two times the dsi link rate time. + 14000 = default value. +- qcom,mdss-dsi-on-command-state: String that specifies the ctrl state for sending ON commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-off-command-state: String that specifies the ctrl state for sending OFF commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-post-mode-switch-on-command-state: String that specifies the ctrl state for sending ON commands post mode switch. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-pan-physical-width-dimension: Specifies panel physical width in mm which corresponds + to the physical width in the framebuffer information. +- qcom,mdss-pan-physical-height-dimension: Specifies panel physical height in mm which corresponds + to the physical height in the framebuffer information. +- qcom,mdss-dsi-panel-mode-gpio-state: String that specifies the mode state for panel if it is defined + in dsi controller. + "high" = Set GPIO to HIGH + "low" = Set GPIO to LOW +- qcom,mdss-tear-check-disable: Boolean to disable mdp tear check. Tear check is enabled by default to avoid + tearing. Other tear-check properties are ignored if this property is present. + The below tear check configuration properties can be individually tuned if + tear check is enabled. +- qcom,mdss-tear-check-sync-cfg-height: Specifies the vertical total number of lines. + The default value is 0xfff0. +- qcom,mdss-tear-check-sync-init-val: Specifies the init value at which the read pointer gets loaded + at vsync edge. The reader pointer refers to the line number of + panel buffer that is currently being updated. + The default value is panel height. +- qcom,mdss-tear-check-sync-threshold-start: + Allows the first ROI line write to an panel when read pointer is + between the range of ROI start line and ROI start line plus this + setting. + The default value is 4. +- qcom,mdss-tear-check-sync-threshold-continue: + The minimum number of lines the write pointer needs to be + above the read pointer so that it is safe to write to the panel. + (This check is not done for the first ROI line write of an update) + The default value is 4. +- qcom,mdss-tear-check-start-pos: Specify the y position from which the start_threshold value is + added and write is kicked off if the read pointer falls within that + region. + The default value is panel height. +- qcom,mdss-tear-check-rd-ptr-trigger-intr: + Specify the read pointer value at which an interrupt has to be + generated. + The default value is panel height + 1. +- qcom,mdss-tear-check-frame-rate: Specify the value to be a real frame rate(fps) x 100 factor to tune the + timing of TE simulation with more precision. + The default value is 6000 with 60 fps. +- qcom,mdss-dsi-reset-sequence: An array that lists the + sequence of reset gpio values and sleeps + Each command will have the format defined + as below: + --> Reset GPIO value + --> Sleep value (in ms) +- qcom,partial-update-enabled: Boolean used to enable partial + panel update for command mode panels. +- qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating + additional idle time in dsi clock cycles that is needed + to compensate for smaller line width. +- qcom,partial-update-roi-merge: Boolean indicates roi combination is need + and function has been provided for dcs + 2A/2B command. +- qcom,dcs-cmd-by-left: Boolean to indicate that dcs command are sent + through the left DSI controller only in a dual-dsi configuration +- qcom,mdss-dsi-panel-hdr-enabled: Boolean to indicate HDR support in panel. +- qcom,mdss-dsi-panel-hdr-color-primaries: + Array of 8 unsigned integers denoting chromaticity of panel.These + values are specified in nits units. The value range is 0 through 50000. + To obtain real chromacity, these values should be divided by factor of + 50000. The structure of array is defined in below order + value 1: x value of white chromaticity of display panel + value 2: y value of white chromaticity of display panel + value 3: x value of red chromaticity of display panel + value 4: y value of red chromaticity of display panel + value 5: x value of green chromaticity of display panel + value 6: y value of green chromaticity of display panel + value 7: x value of blue chromaticity of display panel + value 8: y value of blue chromaticity of display panel +- qcom,mdss-dsi-panel-peak-brightness: Maximum brightness supported by panel.In absence of maximum value + typical value becomes peak brightness. Value is specified in nits units. + To obtail real peak brightness, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-panel-blackness-level: Blackness level supported by panel. Blackness level is defined as + ratio of peak brightness to contrast. Value is specified in nits units. + To obtail real blackness level, this value should be divided by factor of + 10000. +- qcom,mdss-dsi-lp11-init: Boolean used to enable the DSI clocks and data lanes (low power 11) + before issuing hardware reset line. +- qcom,mdss-dsi-init-delay-us: Delay in microseconds(us) before performing any DSI activity in lp11 + mode. This master delay (t_init_delay as per DSI spec) should be sum + of DSI internal delay to reach fuctional after power up and minimum + delay required by panel to reach functional. +- qcom,mdss-dsi-rx-eot-ignore: Boolean used to enable ignoring end of transmission packets. +- qcom,mdss-dsi-tx-eot-append: Boolean used to enable appending end of transmission packets. +- qcom,ulps-enabled: Boolean to enable support for Ultra Low Power State (ULPS) mode. +- qcom,suspend-ulps-enabled: Boolean to enable support for ULPS mode for panels during suspend state. +- qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its + left, top, width, height alignments and minimum width and + height values +- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. +- qcom,mdss-dsi-panel-status-command: A byte stream formed by multiple dcs packets based on + qcom dsi controller protocol, to read the panel status. + This value is used to kick in the ESD recovery. + byte 0: dcs data type + byte 1: set to indicate this is an individual packet + (no chain) + byte 2: virtual channel number + byte 3: expect ack from client (dcs read command) + byte 4: wait number of specified ms after dcs command + transmitted + byte 5, 6: 16 bits length in network byte order + byte 7 and beyond: number byte of payload +- qcom,mdss-dsi-panel-status-command-mode: + String that specifies the ctrl state for reading the panel status. + "dsi_lp_mode" = DSI low power mode + "dsi_hs_mode" = DSI high speed mode +- qcom,mdss-dsi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. + "bta_check" = Uses BTA to check the panel status + "reg_read" = Reads panel status register to check the panel status + "reg_read_nt35596" = Reads panel status register to check the panel + status for NT35596 panel. + "te_signal_check" = Uses TE signal behaviour to check the panel status +- qcom,mdss-dsi-panel-status-read-length: Integer array that specify the expected read-back length of values + for each of panel registers. Each length is corresponding to number of + returned parameters of register introduced in specification. +- qcom,mdss-dsi-panel-status-valid-params: Integer array that specify the valid returned values which need to check + for each of register. + Some panel need only check the first few values returned from panel. + So: if this property is the same to qcom,mdss-dsi-panel-status-read-length, + then just ignore this one. +- qcom,mdss-dsi-panel-status-value: Multiple integer arrays, each specifies the values of the panel status register + which is used to check the panel status. The size of each array is the sum of + length specified in qcom,mdss-dsi-panel-status-read-length, and must be equal. + This can cover that Some panel may return several alternative values. +- qcom,mdss-dsi-panel-max-error-count: Integer value that specifies the maximum number of errors from register + read that can be ignored before treating that the panel has gone bad. +- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports + dynamic switching from video mode to command mode + and vice versa. +- qcom,dynamic-mode-switch-type: A string specifies how to perform dynamic mode switch. + If qcom,dynamic-mode-switch-enabled is set and no string specified, default value is + dynamic-switch-suspend-resume. + "dynamic-switch-suspend-resume"= Switch using suspend/resume. Panel will + go blank during transition. + "dynamic-switch-immediate"= Switch on next frame update. Panel will + not go blank for this transition. + "dynamic-resolution-switch-immediate"= Switch the panel resolution. Panel will + not go blank for this transition. +- qcom,mdss-dsi-post-mode-switch-on-command: Multiple dcs packets used for turning on DSI panel + after panel has switch modes. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,video-to-cmd-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from video mode to command mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from command mode to video mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,send-pps-before-switch: Boolean propety to indicate when PPS commands should be sent, + either before or after switch commands during dynamic resolution + switch in DSC panels. If the property is not present, the default + behavior is to send PPS commands after the switch commands. +- qcom,mdss-dsi-panel-orientation: String used to indicate orientation of panel + "180" = panel is flipped in both horizontal and vertical directions + "hflip" = panel is flipped in horizontal direction + "vflip" = panel is flipped in vertical direction +- qcom,panel-ack-disabled: A boolean property to indicate, whether we need to wait for any ACK from the panel + for any commands that we send. +- qcom,mdss-dsi-force-clock-lane-hs: Boolean to force dsi clock lanes to HS mode always. + +- qcom,compression-mode: Select compression mode for panel. + "fbc" - frame buffer compression + "dsc" - display stream compression. + If "dsc" compression is used then config subnodes needs to be defined. +- qcom,panel-supply-entries: A node that lists the elements of the supply used to + power the DSI panel. There can be more than one instance + of this binding, in which case the entry would be appended + with the supply entry index. For a detailed description of + fields in the supply entry, refer to the qcom,ctrl-supply-entries + binding above. +- qcom,config-select: Optional property to select default configuration. +- qcom,panel-allow-phy-poweroff: A boolean property indicates that panel allows to turn off the phy power + supply during idle screen. A panel should able to handle the dsi lanes + in floating state(not LP00 or LP11) to turn on this property. Software + turns off PHY pmic power supply, phy ldo and DSI Lane ldo during + idle screen (footswitch control off) when this property is enabled. +[[Optional config sub-nodes]] These subnodes provide different configurations for a given same panel. + Default configuration can be chosen by specifying phandle of the + selected subnode in the qcom,config-select. +Required properties for sub-nodes: None +Optional properites: +- qcom,lm-split: An array of two values indicating MDP should use two layer + mixers to reduce power. + Ex: Normally 1080x1920 display uses single DSI and thus one layer + mixer. But if we use two layer mixers then mux the output of + those two mixers into single stream and route it to single DSI + then we can lower the clock requirements of MDP. To use this + configuration we need two fill this array with <540 540>. + Both values doesn't have to be same, but recommended, however sum of + both values has to be equal to the panel-width. + By default two mixer streams are merged using 2D mux, however if + 2 DSC encoders are used then merge is performed within compression + engine. +- qcom,split-mode: String property indicating which split mode MDP should use. Valid + entries are "pingpong-split" and "dualctl-split". + This property is mutually exclusive with qcom,lm-split. +- qcom,mdss-dsc-version: An 8 bit value indicates the DSC version supported by panel. Bits[0.3] + provides information about minor version while Bits[4.7] provides + major version information. It supports only DSC rev 1(Major).1(Minor) + right now. +- qcom,mdss-dsc-scr-version: Each DSC version can have multiple SCR. This 8 bit value indicates + current SCR revision information supported by panel. +- qcom,mdss-dsc-encoders: An integer value indicating how many DSC encoders should be used + to drive data stream to DSI. + Default value is 1 and max value is 2. + 2 encoder should be used only if qcom,mdss-lm-split or + qcom,split-mode with pingpong-split is used. +- qcom,mdss-dsc-slice-height: An integer value indicates the dsc slice height. +- qcom,mdss-dsc-slice-width: An integer value indicates the dsc slice width. + Multiple of slice width should be equal to panel-width. + Maximum 2 slices per DSC encoder can be used so if 2 DSC encoders + are used then minimum slice width is equal to panel-width/4. +- qcom,mdss-dsc-slice-per-pkt: An integer value indicates the slice per dsi packet. +- qcom,mdss-dsc-bit-per-component: An integer value indicates the bits per component before compression. +- qcom,mdss-dsc-bit-per-pixel: An integer value indicates the bits per pixel after compression. +- qcom,mdss-dsc-block-prediction-enable: A boolean value to enable/disable the block prediction at decoder. +- qcom,mdss-dsc-config-by-manufacture-cmd: A boolean to indicates panel use manufacture command to setup pps + instead of standard dcs type 0x0A. +- qcom,dba-panel: Indicates whether the current panel is used as a display bridge + to a non-DSI interface. +- qcom,bridge-name: A string to indicate the name of the bridge chip connected to DSI. qcom,bridge-name + is required if qcom,dba-panel is defined for the panel. +- qcom,hdmi-mode: Indicates where current panel is HDMI mode, otherwise, it will be DVI mode. +- qcom,adjust-timer-wakeup-ms: An integer value to indicate the timer delay(in ms) to accommodate + s/w delay while configuring the event timer wakeup logic. + +- qcom,mdss-dsi-display-timings: Parent node that lists the different resolutions that the panel supports. + Each child represents timings settings for a specific resolution. +- qcom,mdss-dsi-post-init-delay: Specifies required number of frames to wait so that panel can be functional + to show proper display. + +Additional properties added to the second level nodes that represent timings properties: +- qcom,mdss-dsi-timing-default: Property that specifies the current child as the default + timing configuration that will be used. +- qcom,mdss-dsi-timing-switch-command: List of commands that need to be sent + to panel when the resolution/timing switch happens dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,mdss-dsi-timing-switch-command-state: String that specifies the ctrl state for sending resolution switch + commands. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode + +Note, if a given optional qcom,* binding is not present, then the driver will configure +the default values specified. + +Note, all the "qcom,supply-*" properties have their definitions in mdss-dsi-txt. + +Example: +&mdss_mdp { + dsi_sim_vid: qcom,mdss_dsi_sim_video { + qcom,mdss-dsi-panel-name = "simulator video mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-pixel-packing = <0>; + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-fbc-enable; + qcom,mdss-dsi-fbc-slice-height = <5>; + qcom,mdss-dsi-fbc-2d-pred-mode; + qcom,mdss-dsi-fbc-ver2-mode; + qcom,mdss-dsi-fbc-bpp = <0>; + qcom,mdss-dsi-fbc-packing = <0>; + qcom,mdss-dsi-fbc-quant-error; + qcom,mdss-dsi-fbc-bias = <0>; + qcom,mdss-dsi-fbc-pat-mode; + qcom,mdss-dsi-fbc-vlc-mode; + qcom,mdss-dsi-fbc-bflc-mode; + qcom,mdss-dsi-fbc-h-line-budget = <0>; + qcom,mdss-dsi-fbc-budget-ctrl = <0>; + qcom,mdss-dsi-fbc-block-budget = <0>; + qcom,mdss-dsi-fbc-lossless-threshold = <0>; + qcom,mdss-dsi-fbc-lossy-threshold = <0>; + qcom,mdss-dsi-fbc-rgb-threshold = <0>; + qcom,mdss-dsi-fbc-lossy-mode-idx = <0>; + qcom,mdss-dsi-fbc-max-pred-err = <2>; + qcom,mdss-dsi-h-front-porch = <140>; + qcom,mdss-dsi-h-back-porch = <164>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <1>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = < 15>; + qcom,mdss-dsi-interleave-mode = <0>; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-hfp-power-mode; + qcom,mdss-dsi-hbp-power-mode; + qcom,mdss-dsi-hsa-power-mode; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-last-line-interleave; + qcom,mdss-dsi-traffic-mode = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-color-order = <0>; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x20>; + qcom,mdss-dsi-t-clk-pre = <0x2c>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-mdp-trigger = <0>; + qcom,mdss-dsi-dma-trigger = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <424000000>; + qcom,mdss-mdp-kickoff-threshold = <11 2430>; + qcom,mdss-mdp-kickoff-delay = <1000>; + qcom,mdss-mdp-transfer-time-us = <12500>; + qcom,mdss-dsi-panel-timings = [7d 25 1d 00 37 33 + 22 27 1e 03 04 00]; + qcom,mdss-dsi-panel-timings-phy-v2 = [23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 2e 06 08 05 03 04 a0]; + qcom,mdss-dsi-panel-timings-phy-12nm = + [a9 4e 56 0b 8a 4d 0b d6]; + qcom,mdss-dsi-on-command = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp-mode-on = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 FF 99]; + qcom,mdss-dsi-lp-mode-off = [22 01 00 00 00 00 00]; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; + qcom,min-refresh-rate = <30>; + qcom,max-refresh-rate = <60>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8941_mpps 5 0>; + qcom,5v-boost-gpio = <&pm8994_gpios 14 0>; + qcom,mdss-pan-physical-width-dimension = <60>; + qcom,mdss-pan-physical-height-dimension = <140>; + qcom,mdss-dsi-panel-mode-gpio-state = "low"; + qcom,mdss-tear-check-sync-cfg-height = <0xfff0>; + qcom,mdss-tear-check-sync-init-val = <1280>; + qcom,mdss-tear-check-sync-threshold-start = <4>; + qcom,mdss-tear-check-sync-threshold-continue = <4>; + qcom,mdss-tear-check-start-pos = <1280>; + qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; + qcom,mdss-tear-check-frame-rate = <6000>; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; + qcom,partial-update-enabled; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-init-delay-us = <100>; + mdss-dsi-rx-eot-ignore; + mdss-dsi-tx-eot-append; + qcom,ulps-enabled; + qcom,suspend-ulps-enabled; + qcom,panel-roi-alignment = <4 4 2 2 20 20>; + qcom,esd-check-enabled; + qcom,panel-allow-phy-poweroff; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-read-length = <8>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-panel-status-value = <0x1c 0x00 0x05 0x02 0x40 0x84 0x06 0x01>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + qcom,mdss-dsi-post-mode-switch-on-command = [32 01 00 00 00 00 02 00 00 + 29 01 00 00 10 00 02 B0 03]; + qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B + 15 01 00 00 00 00 02 C2 08]; + qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03]; + qcom,send-pps-before-switch; + qcom,panel-ack-disabled; + qcom,mdss-dsi-horizontal-line-idle = <0 40 256>, + <40 120 128>, + <128 240 64>; + qcom,mdss-dsi-panel-orientation = "180" + qcom,mdss-dsi-force-clock-lane-hs; + qcom,compression-mode = "dsc"; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + wqhd { + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <728>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = [E6 38 26 00 68 6E 2A 3C 2C 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; + qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00 + 05 01 00 00 02 00 02 29 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-timing-switch-command = [ + 29 00 00 00 00 00 02 B0 04 + 29 00 00 00 00 00 02 F1 00]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode"; + + qcom,config-select = <&dsi_sim_vid_config0>; + dsi_sim_vid_config0: config0 { + qcom,lm-split = <360 360>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + }; + }; + }; + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2800000>; + qcom,supply-max-voltage = <2800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,config-select = <&dsi_sim_vid_config0>; + qcom,dba-panel; + qcom,bridge-name = "adv7533"; + qcom,mdss-dsc-version = <0x11>; + qcom,mdss-dsc-scr-version = <0x1>; + + dsi_sim_vid_config0: config0 { + qcom,lm-split = <360 360>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + }; + + dsi_sim_vid_config1: config1 { + qcom,mdss-dsc-encoders = <1>; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + }; + + dsi_sim_vid_config2: config2 { + qcom,split-mode = "dualctl-split"; + }; + + dsi_sim_vid_config3: config3 { + qcom,split-mode = "pingpong-split"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dsi.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b593a97ef0d80dc4fb9785bd96c89cc2f1dd8ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-dsi.txt @@ -0,0 +1,261 @@ +Qualcomm Technologies, Inc. mdss-dsi + +mdss-dsi is the master DSI device which supports multiple DSI host controllers that +are compatible with MIPI display serial interface specification. + +Required properties: +- compatible: Must be "qcom,mdss-dsi" +- hw-config: Specifies the DSI host setup configuration + "hw-config" = "single_dsi" + "hw-config" = "dual_dsi" + "hw-config" = "split_dsi" +- ranges: The standard property which specifies the child address + space, parent address space and the length. +- vdda-supply: Phandle for vreg regulator device node. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom, msm-bus,num-cases: This is the number of bus scaling use cases + defined in the vectors property. This must be + set to <2> for MDSS DSI driver where use-case 0 + is used to remove BW votes from the system. Use + case 1 is used to generate bandwidth requestes + when sending command packets. +- qcom,msm-bus,num-paths: This represents number of paths in each bus + scaling usecase. This value depends on number of + AXI master ports dedicated to MDSS for + particular chipset. +- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt. + DSI driver should always set average bandwidth + (ab) to 0 and always use instantaneous + bandwidth(ib) values. + +Optional properties: +- vcca-supply: Phandle for vcca regulator device node. +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI modulee. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- pll-src-config Specified the source PLL for the DSI + link clocks: + "PLL0" - Clocks sourced out of DSI PLL0 + "PLL1" - Clocks sourced out of DSI PLL1 + This property is only valid for + certain DSI hardware configurations + mentioned in the "hw-config" binding above. + For example, in split_dsi config, the clocks can + only be sourced out of PLL0. For + dual_dsi, both PLL would be active. + For single DSI, it is possible to + select either PLL. If no value is specified, + the default value for single DSI is set as PLL0. +- qcom,mmss-ulp-clamp-ctrl-offset: Specifies the offset for dsi ulps clamp control register. +- qcom,mmss-phyreset-ctrl-offset: Specifies the offset for dsi phy reset control register. +- qcom,dsi-clk-ln-recovery: Boolean which enables the clk lane recovery + +mdss-dsi-ctrl is a dsi controller device which is treated as a subnode of the mdss-dsi device. + +Required properties: +- compatible: Must be "qcom,mdss-dsi-ctrl" +- cell-index: Specifies the controller used among the two controllers. +- reg: Base address and length of the different register + regions(s) required for DSI device functionality. +- reg-names: A list of strings that map in order to the list of regs. + "dsi_ctrl" - MDSS DSI controller register region + "dsi_phy" - MDSS DSI PHY register region + "dsi_phy_regulator" - MDSS DSI PHY REGULATOR region + "mmss_misc_phys" - Register region for MMSS DSI clamps +- vdd-supply: Phandle for vdd regulator device node. +- vddio-supply: Phandle for vdd-io regulator device node. +- qcom,mdss-fb-map-prim: pHandle that specifies the framebuffer to which the + primary interface is mapped. +- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. +- qcom,platform-regulator-settings: An array of length 7 or 5 that specifies the PHY + regulator settings. It use 5 bytes for 8996 pll. +- qcom,platform-strength-ctrl: An array of length 2 or 10 that specifies the PHY + strengthCtrl settings. It use 10 bytes for 8996 pll. +- qcom,platform-lane-config: An array of length 45 or 20 that specifies the PHY + lane configuration settings. It use 20 bytes for 8996 pll. +- qcom,platform-bist-ctrl: An array of length 6 that specifies the PHY + BIST ctrl settings. +- qcom,dsi-pref-prim-pan: phandle that specifies the primary panel to be used + with the controller. + +Optional properties: +- label: A string used to describe the controller used. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- qcom,mdss-fb-map-sec: pHandle that specifies the framebuffer to which the + secondary interface is mapped. +- qcom,platform-enable-gpio: Specifies the panel lcd/display enable gpio. +- qcom,platform-reset-gpio: Specifies the panel reset gpio. +- qcom,platform-te-gpio: Specifies the gpio used for TE. +- qcom,platform-bklight-en-gpio: Specifies the gpio used to enable display back-light +- qcom,platform-mode-gpio: Select video/command mode of panel through gpio when it supports + both modes. +- qcom,platform-intf-mux-gpio: Select dsi/external(hdmi) interface through gpio when it supports + either dsi or external interface. +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt +- qcom,regulator-ldo-mode: Boolean to enable ldo mode for the dsi phy regulator +- qcom,null-insertion-enabled: Boolean to enable NULL packet insertion + feature for DSI controller. +- qcom,dsi-irq-line: Boolean specifies if DSI has a different irq line than mdp. +- qcom,lane-map: Specifies the data lane swap configuration. + "lane_map_0123" = <0 1 2 3> (default value) + "lane_map_3012" = <3 0 1 2> + "lane_map_2301" = <2 3 0 1> + "lane_map_1230" = <1 2 3 0> + "lane_map_0321" = <0 3 2 1> + "lane_map_1032" = <1 0 3 2> + "lane_map_2103" = <2 1 0 3> + "lane_map_3210" = <3 2 1 0> +- qcom,pluggable Boolean to enable hotplug feature. +- qcom,timing-db-mode: Boolean specifies dsi timing mode registers are supported or not. +- qcom,display-id A string indicates the display ID for the controller. + The possible values are: + - "primary" + - "secondary" + - "tertiary" +- qcom,bridge-index: Instance id of the bridge chip connected to DSI. qcom,bridge-index is + required if a bridge chip panel is used. + +Example: + mdss_dsi: qcom,mdss_dsi@0 { + compatible = "qcom,mdss-dsi"; + hw-config = "single_dsi"; + pll-src-config = "PLL0"; + #address-cells = <1>; + #size-cells = <1>; + vdda-supply = <&pm8226_l4>; + vcca-supply = <&pm8226_l28>; + reg = <0x1a98000 0x1a98000 0x25c + 0x1a98500 0x1a98500 0x280 + 0x1a98780 0x1a98780 0x30 + 0x193e000 0x193e000 0x30>; + + qcom,dsi-clk-ln-recovery; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + qcom,supply-ulp-load = <0>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-ulp-load = <1000>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + mdss_dsi0: mdss_dsi_ctrl0@fd922800 { + compatible = "qcom,mdss-dsi-ctrl"; + label = "MDSS DSI CTRL->0"; + cell-index = <0>; + reg = <0xfd922800 0x1f8>, + <0xfd922b00 0x2b0>, + <0xfd998780 0x30>, + <0xfd828000 0x108>; + reg-names = "dsi_ctrl", "dsi_phy", + "dsi_phy_regulator", "mmss_misc_phys"; + + vdd-supply = <&pm8226_l15>; + vddio-supply = <&pm8226_l8>; + qcom,mdss-fb-map-prim = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + + qcom,dsi-pref-prim-pan = <&dsi_tosh_720_vid>; + + qcom,platform-strength-ctrl = [ff 06]; + qcom,platform-bist-ctrl = [00 00 b1 ff 00 00]; + qcom,platform-regulator-settings = [07 09 03 00 20 00 01]; + qcom,platform-lane-config = [00 00 00 00 00 00 00 01 97 + 00 00 00 00 05 00 00 01 97 + 00 00 00 00 0a 00 00 01 97 + 00 00 00 00 0f 00 00 01 97 + 00 c0 00 00 00 00 00 01 bb]; + + qcom,mmss-ulp-clamp-ctrl-offset = <0x20>; + qcom,mmss-phyreset-ctrl-offset = <0x24>; + qcom,regulator-ldo-mode; + qcom,null-insertion-enabled; + qcom,timing-db-mode; + + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active>; + pinctrl-1 = <&mdss_dsi_suspend>; + qcom,platform-reset-gpio = <&msmgpio 25 1>; + qcom,platform-te-gpio = <&msmgpio 24 0>; + qcom,platform-enable-gpio = <&msmgpio 58 1>; + qcom,platform-bklight-en-gpio = <&msmgpio 86 0>; + qcom,platform-mode-gpio = <&msmgpio 7 0>; + qcom,platform-intf-mux-gpio = <&tlmm 115 0>; + qcom,dsi-irq-line; + qcom,lane-map = "lane_map_3012"; + qcom,display-id = "primary"; + qcom,bridge-index = <00>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-edp.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-edp.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ca688edc35feb0b3aac51a641bf1e4c47eab943 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-edp.txt @@ -0,0 +1,149 @@ +Qualcomm Technologies, Inc. MDSS EDP + +MDSS EDP is a edp driver which supports panels that are compatible with +VESA EDP display interface specification. + +When configuring the optional properties for external backlight, one should also +configure the gpio that drives the pwm to it. + +Required properties +- compatible : Must be "qcom,mdss-edp". +- reg : Offset and length of the register set for the + device. +- reg-names : Names to refer to register sets related to this + device +- vdda-supply : Phandle for vdd regulator device node. +- gpio-panel-en : GPIO for supplying power to panel and backlight + driver. +- gpio-lvl-en : GPIO to enable HPD be received by host. +- status : A string that has to be set to "okay/ok" to enable + the driver. By default this property will be set to + "disable". Will be set to "ok/okay" status for + specific platforms. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. +- gpio-panel-hpd : gpio pin use for edp hpd + +Optional properties +- qcom,panel-lpg-channel : LPG channel for backlight. +- qcom,panel-pwm-period : PWM period in microseconds. + + +Optional properties: +- qcom,mdss-brightness-max-level: Specifies the max brightness level supported. + 255 = default value. + +Example: + mdss_edp: qcom,mdss_edp@fd923400 { + compatible = "qcom,mdss-edp"; + reg = <0xfd923400 0x700>, + <0xfd8c2000 0x1000>; + reg-names = "edp_base", "mmss_cc_base"; + vdda-supply = <&pm8941_l12>; + gpio-panel-en = <&msmgpio 58 0>; + gpio-lvl-en = <&msmgpio 91 0>; + qcom,panel-lpg-channel = <7>; /* LPG Channel 8 */ + qcom,panel-pwm-period = <53>; + status = "disable"; + qcom,mdss-fb-map = <&mdss_fb0>; + gpio-panel-hpd = <&msmgpio 102 0>; + }; + + +Example: + mdss_dp_ctrl: qcom,dp_ctrl@c990000 { + cell-index = <0>; + compatible = "qcom,mdss-dp"; + qcom,mdss-fb-map = <&mdss_fb3>; + + gdsc-supply = <&gdsc_mdss>; + vdda-1p2-supply = <&pm8998_l2>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xc990000 0xa84>, + <0xc011000 0x910>, + <0x1fcb200 0x050>; + reg-names = "dp_ctrl", "dp_phy", "tcsr_regs"; + + clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, + <&clock_mmss clk_mmss_mdss_ahb_clk>, + <&clock_mmss clk_mmss_mdss_axi_clk>, + <&clock_mmss clk_mmss_mdss_mdp_clk>, + <&clock_mmss clk_mmss_mdss_hdmi_dp_ahb_clk>, + <&clock_mmss clk_mmss_mdss_dp_aux_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, + <&clock_mmss clk_mmss_mdss_dp_link_clk>, + <&clock_mmss clk_mmss_mdss_dp_link_intf_clk>, + <&clock_mmss clk_mmss_mdss_dp_crypto_clk>, + <&clock_mmss clk_mmss_mdss_dp_pixel_clk>; + clock-names = "core_mnoc_clk", "core_iface_clk", "core_bus_clk", + "core_mdp_core_clk", "core_alt_iface_clk", + "core_aux_clk", "core_cfg_ahb_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", "ctrl_pixel_clk"; + + qcom,aux-cfg0-settings = [1c 00]; + qcom,aux-cfg1-settings = [20 13 23 1d]; + qcom,aux-cfg2-settings = [24 00]; + qcom,aux-cfg3-settings = [28 00]; + qcom,aux-cfg4-settings = [2c 0a]; + qcom,aux-cfg5-settings = [30 26]; + qcom,aux-cfg6-settings = [34 0a]; + qcom,aux-cfg7-settings = [38 03]; + qcom,aux-cfg8-settings = [3c bb]; + qcom,aux-cfg9-settings = [40 03]; + qcom,logical2physical-lane-map = [02 03 01 00]; + qcom,phy-register-offset = <0x4>; + qcom,max-pclk-frequency-khz = <593470>; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <12560>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <73400>; + qcom,supply-disable-load = <32>; + }; + }; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active + &mdss_dp_hpd_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend + &mdss_dp_hpd_suspend>; + qcom,aux-en-gpio = <&tlmm 77 0>; + qcom,aux-sel-gpio = <&tlmm 78 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; + qcom,hpd-gpio = <&tlmm 34 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-mdp.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-mdp.txt new file mode 100644 index 0000000000000000000000000000000000000000..5624321b47d68d19866f0c50f240ac59ebbfc7b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-mdp.txt @@ -0,0 +1,898 @@ +Qualcomm Technologies, Inc. MDSS MDP + +MDSS is Mobile Display SubSystem which implements Linux framebuffer APIs to +drive user interface to different panel interfaces. MDP driver is the core of +MDSS which manage all data paths to different panel interfaces. + +Required properties +- compatible : Must be "qcom,mdss_mdp" + - "qcom,mdss_mdp3" for mdp3 +- reg : offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- interrupts : Interrupt associated with MDSS. +- interrupt-controller: Mark the device node as an interrupt controller. + This is an empty, boolean property. +- #interrupt-cells: Should be one. The first cell is interrupt number. +- vdd-supply : Phandle for vdd regulator device node. +- qcom,max-clk-rate: Specify maximum MDP core clock rate in hz that this + device supports. +- qcom,mdss-pipe-vig-off: Array of offset for MDP source surface pipes of + type VIG, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of VIG pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-vig-fetch-id: Array of shared memory pool fetch ids + corresponding to the VIG pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective VIG pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-vig-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-off: Array of offsets for MDP source surface pipes of + type RGB, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of RGB pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-rgb-fetch-id: Array of shared memory pool fetch ids + corresponding to the RGB pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective RGB pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-rgb-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-off: Array of offsets for MDP source surface pipes of + type DMA, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of DMA pipes that can be + active in MDP for this configuration. +- qcom,mdss-pipe-dma-fetch-id: Array of shared memory pool fetch ids + corresponding to the DMA pipe offsets defined in + previous property, the amount of fetch ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective DMA pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-dma-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-pipe-cursor-off: Array of offsets for MDP source surface pipes of + type cursor, the offsets are calculated from + register "mdp_phys" defined in reg property. + The number of offsets defined here should + reflect the amount of cursor pipes that can be + active in MDP for this configuration. Meant for + hardware that has hw cursors support as a + source pipe. +- qcom,mdss-pipe-cursor-xin-id: Array of VBIF clients ids (xins) corresponding + to the respective cursor pipes. Number of xin ids + defined should match the number of offsets + defined in property: qcom,mdss-pipe-cursor-off +- qcom,mdss-pipe-cursor-clk-ctrl-off: Array of offsets describing clk control + offsets for dynamic clock gating. 1st value + in the array represents offset of the control + register. 2nd value represents bit offset within + control register and 3rd value represents bit + offset within status register. Number of tuples + defined should match the number of offsets + defined in property: qcom,mdss-pipe-cursor-off +- qcom,mdss-ctl-off: Array of offset addresses for the available ctl + hw blocks within MDP, these offsets are + calculated from register "mdp_phys" defined in + reg property. The number of ctl offsets defined + here should reflect the number of control paths + that can be configured concurrently on MDP for + this configuration. +- qcom,mdss-wb-off: Array of offset addresses for the progammable + writeback blocks within MDP. The number of + offsets defined should match the number of ctl + blocks defined in property: qcom,mdss-ctl-off +- qcom,mdss-mixer-intf-off: Array of offset addresses for the available + mixer blocks that can drive data to panel + interfaces. + These offsets are be calculated from register + "mdp_phys" defined in reg property. + The number of offsets defined should reflect the + amount of mixers that can drive data to a panel + interface. +- qcom,mdss-dspp-off: Array of offset addresses for the available dspp + blocks. These offsets are calculated from + register "mdp_phys" defined in reg property. + The number of dspp blocks should match the + number of mixers driving data to interface + defined in property: qcom,mdss-mixer-intf-off +- qcom,mdss-pingpong-off: Array of offset addresses for the available + pingpong blocks. These offsets are calculated + from register "mdp_phys" defined in reg property. + The number of pingpong blocks should match the + number of mixers driving data to interface + defined in property: qcom,mdss-mixer-intf-off +- qcom,mdss-mixer-wb-off: Array of offset addresses for the available + mixer blocks that can be drive data to writeback + block. These offsets will be calculated from + register "mdp_phys" defined in reg property. + The number of writeback mixer offsets defined + should reflect the number of mixers that can + drive data to a writeback block. +- qcom,mdss-intf-off: Array of offset addresses for the available MDP + video interface blocks that can drive data to a + panel controller through timing engine. + The offsets are calculated from "mdp_phys" + defined in reg property. The number of offsets + defiend should reflect the number of progammable + interface blocks available in hardware. +- qcom,mdss-pref-prim-intf: A string which indicates the configured hardware + interface between MDP and the primary panel. + Individual panel controller drivers initialize + hardware based on this property. + Based on the interfaces supported at present, + possible values are: + - "dsi" + - "edp" + - "hdmi" + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for MDSS driver where use-case 0 is + used to take off MDSS BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,active-only: A boolean flag indicating if it is active only. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to MDSS for particular chipset. This + value represents the RT + NRT AXI master ports. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for MDSS are: + 22 = MSM_BUS_MASTER_MDP_PORT0 + 23 = MSM_BUS_MASTER_MDP_PORT1 + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for MDSS are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +- qcom,mdss-prefill-outstanding-buffer-bytes: The size of mdp outstanding buffer + in bytes. The buffer is filled during prefill + time and the buffer size shall be included in + prefill bandwidth calculation. +- qcom,mdss-prefill-y-buffer-bytes: The size of mdp y plane buffer in bytes. The + buffer is filled during prefill time when format + is YUV and the buffer size shall be included in + prefill bandwidth calculation. +- qcom,mdss-prefill-scaler-buffer-lines-bilinear: The value indicates how many lines + of scaler line buffer need to be filled during + prefill time. If bilinear scalar is enabled, then this + number of lines is used to determine how many bytes + of scaler buffer to be included in prefill bandwidth + calculation. +- qcom,mdss-prefill-scaler-buffer-lines-caf: The value indicates how many lines of + of scaler line buffer need to be filled during + prefill time. If CAF mode filter is enabled, then + this number of lines is used to determine how many + bytes of scaler buffer to be included in prefill + bandwidth calculation. +- qcom,mdss-prefill-post-scaler-buffer: The size of post scaler buffer in bytes. + The buffer is used to smooth the output of the + scaler. If the buffer is present in h/w, it is + filled during prefill time and the number of bytes + shall be included in prefill bandwidth calculation. +- qcom,mdss-prefill-pingpong-buffer-pixels: The size of pingpong buffer in pixels. + The buffer is used to keep pixels flowing to the + panel interface. If the vertical start position of a + layer is in the beginning of the active area, pingpong + buffer must be filled during prefill time to generate + starting lines. The number of bytes to be filled is + determined by the line width, starting position, + byte per pixel and scaling ratio, this number shall be + included in prefill bandwidth calculation. +- qcom,mdss-prefill-fbc-lines: The value indicates how many lines are required to fill + fbc buffer during prefill time if FBC (Frame Buffer + Compressor) is enabled. The number of bytes to be filled + is determined by the line width, bytes per pixel and + scaling ratio, this number shall be included in prefill bandwidth + calculation. +- qcom,max-mixer-width: Specify maximum MDP mixer width that the device supports. + This is a mandatory property, if not specified then + mdp probe will fail. + +Optional properties: +- batfet-supply : Phandle for battery FET regulator device node. +- vdd-cx-supply : Phandle for vdd CX regulator device node. +- qcom,vbif-settings : Array with key-value pairs of constant VBIF register + settings used to setup MDSS QoS for optimum performance. + The key used should be offset from "vbif_phys" register + defined in reg property. +- qcom,vbif-nrt-settings : The key used should be offset from "vbif_nrt_phys" + register defined in reg property. Refer qcom,vbif-settings + for a detailed description of this binding. +- qcom,mdp-settings : Array with key-value pairs of constant MDP register + settings used to setup MDSS QoS for best performance. + The key used should be offset from "mdp_phys" register + defined in reg property. +- qcom,mdss-smp-data: Array of shared memory pool data for dynamic SMP. There + should be only two values in this property. The first + value corresponds to the number of smp blocks and the + second is the size of each block present in the mdss + hardware. This property is optional for MDP hardware + with fix pixel latency ram. +- qcom,mdss-rot-block-size: The size of a memory block (in pixels) to be used + by the rotator. If this property is not specified, + then a default value of 128 pixels would be used. +- qcom,mdss-has-bwc: Boolean property to indicate the presence of bandwidth + compression feature in the rotator. +- qcom,mdss-has-non-scalar-rgb: Boolean property to indicate the presence of RGB + pipes which have no scaling support. +- qcom,mdss-has-decimation: Boolean property to indicate the presence of + decimation feature in fetch. +- qcom,mdss-has-fixed-qos-arbiter-enabled: Boolean property to indicate the + presence of rt/nrt feature. This feature enables + increased performance by prioritizing the real time + (rt) traffic over non real time (nrt) traffic to + access the memory. +- qcom,mdss-num-nrt-paths: Integer property represents the number of non-realtime + paths in each Bus Scaling Usecase. This value depends on + number of AXI ports are dedicated to non-realtime VBIF for + particular chipset. This property is mandatory when + "qcom,mdss-has-fixed-qos-arbiter-enabled" is enabled. + These paths must be defined after rt-paths in + "qcom,msm-bus,vectors-KBps" vector request. +- qcom,mdss-has-source-split: Boolean property to indicate if source split + feature is available or not. +- qcom,mdss-has-rotator-downscale: Boolean property to indicate if rotator + downscale feature is available or not. +- qcom,mdss-rot-downscale-min: This integer value indicates the Minimum + downscale factor supported by rotator. +- qcom,mdss-rot-downscale-max: This integer value indicates the Maximum + downscale factor supported by rotator. +- qcom,mdss-ad-off: Array of offset addresses for the available + Assertive Display (AD) blocks. These offsets + are calculated from the register "mdp_phys" + defined in reg property. The number of AD + offsets should be less than or equal to the + number of mixers driving interfaces defined in + property: qcom,mdss-mixer-intf-off. Assumes + that AD blocks are aligned with the mixer + offsets as well (i.e. the first mixer offset + corresponds to the same pathway as the first + AD offset). +- qcom,mdss-has-wb-ad: Boolean property to indicate assertive display feature + support on write back framebuffer. +- qcom,mdss-no-lut-read: Boolean property to indicate reading of LUT is + not supported. +- qcom,mdss-no-hist-vote Boolean property to indicate histogram reads + and histogram LUT writes do not need additional + bandwidth voting. +- qcom,mdss-mdp-wfd-mode: A string that specifies what is the mode of + writeback wfd block. + "intf" = Writeback wfd block is + connected to the interface mixer. + "shared" = Writeback block shared + between wfd and rotator. + "dedicated" = Dedicated writeback + block for wfd using writeback mixer. +- qcom,mdss-smp-mb-per-pipe: Maximum number of shared memory pool blocks + restricted for a source surface pipe. If this + property is not specified, no such restriction + would be applied. +- qcom,mdss-highest-bank-bit: Property to indicate tile format as opposed to usual + linear format. The value tells the GPU highest memory + bank bit used. +- qcom,mdss-pipe-rgb-fixed-mmb: Array of indexes describing fixed Memory Macro + Blocks (MMBs) for rgb pipes. First value denotes + total numbers of MMBs per pipe while values, if + any, following first one denotes indexes of MMBs + to that RGB pipe. +- qcom,mdss-pipe-vig-fixed-mmb: Array of indexes describing fixed Memory Macro + Blocks (MMBs) for vig pipes. First value denotes + total numbers of MMBs per pipe while values, if + any, following first one denotes indexes of MMBs + to that VIG pipe. +- qcom,mdss-pipe-sw-reset-off: Property to indicate offset to the register which + holds sw_reset bitmap for different MDSS + components. +- qcom,mdss-pipe-vig-sw-reset-map: Array of bit offsets for vig pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-sw-reset-map: Array of bit offsets for rgb pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-sw-reset-map: Array of bit offsets for dma pipes within + sw_reset register bitmap. Number of offsets + defined should match the number of offsets + defined in property: qcom,mdss-pipe-dma-off +- qcom,mdss-default-ot-wr-limit: This integer value indicates maximum number of pending + writes that can be allowed on each WR xin. + This value can be used to reduce the pending writes + limit and can be tuned to match performance + requirements depending upon system state. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot write limit + will enable this dynamic limiting for the write + operations in the platforms that require these + limits. +- qcom,mdss-default-ot-rd-limit: This integer value indicates the default number of pending + reads that can be allowed on each RD xin. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot read limit + will enable this dynamic limiting for the read + operations in the platforms that require these + limits. +- qcom,mdss-clk-levels: This array indicates the mdp core clock level selection + array. Core clock is calculated for each frame and + hence depending upon calculated value, clock rate + will be rounded up to the next level according to + this table. Order of entries need to be ordered in + ascending order. +- qcom,mdss-vbif-qos-rt-setting: This array is used to program vbif qos remapper register + priority for real time clients. +- qcom,mdss-vbif-qos-nrt-setting: This array is used to program vbif qos remapper register + priority for non real time clients. +- qcom,mdss-traffic-shaper-enabled: This boolean property enables traffic shaper functionality + for MDSS rotator which spread out rotator bandwidth request + so that rotator don't compete with other real time read + clients. +- qcom,mdss-dram-channels: This represents the number of channels in the + Bus memory controller. +- qcom,regs-dump-mdp: This array represents the registers offsets that + will be dumped from the mdp when the debug logging + is enabled; each entry in the table is an start and + end offset from the MDP address "mdp_phys", the + format of each entry is as follows: + + Ex: + <0x01000 0x01404> + Will dump the MDP registers + from the address: "mdp_phys + 0x01000" + to the address: "mdp_phys + 0x01404" +- qcom,regs-dump-names-mdp: This array represents the tag that will be used + for each of the entries defined within regs-dump. + Note that each tag matches with one of the + regs-dump entries in the same order as they + are defined. +- qcom,regs-dump-xin-id-mdp: Array of VBIF clients ids (xins) corresponding + to mdp block. Xin id property is not valid for mdp + internal blocks like ctl, lm, dspp. It should set + to 0xff for such blocks. + +Fudge Factors: Fudge factors are used to boost demand for + resources like bus bandswidth, clk rate etc. to + overcome system inefficiencies and avoid any + glitches. These fudge factors are expressed in + terms of numerator and denominator. First value + is numerator followed by denominator. They all + are optional but highly recommended. + Ex: + x = value to be fudged + a = numerator, default value is 1 + b = denominator, default value is 1 + FUDGE(x, a, b) = ((x * a) / b) +- qcom,mdss-ib-factor: This fudge factor is applied to calculated ib + values in default conditions. +- qcom,mdss-ib-factor-overlap: This fudge factor is applied to calculated ib + values when the overlap bandwidth is the + predominant value compared to prefill bandwidth + value. +- qcom,mdss-clk-factor: This fudge factor is applied to calculated mdp + clk rate in default conditions. + +- qcom,max-bandwidth-low-kbps: This value indicates the max bandwidth in KB + that can be supported without underflow. + This is a low bandwidth threshold which should + be applied in most scenarios to be safe from + underflows when unable to satisfy bandwidth + requirements. +- qcom,max-bandwidth-high-kbps: This value indicates the max bandwidth in KB + that can be supported without underflow. + This is a high bandwidth threshold which can be + applied in scenarios where panel interface can + be more tolerant to memory latency such as + command mode panels. +- qcom,max-bandwidth-per-pipe-kbps: A two dimensional array indicating the max + bandwidth in KB that a single pipe can support + without underflow for various usecases. The + first parameter indicates the usecase and the + second parameter gives the max bw allowed for + the usecase. Following are the enum values for + modes in different cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. +- qcom,max-bw-settings: This two dimension array indicates the max bandwidth + in KB that has to be supported when particular + scenarios are involved such as camera, flip. + The first parameter indicate the + scenario/usecase and second parameter indicate + the maximum bandwidth for that usecase. + Following are the enum values for modes in different + cases: + For default case, mode = 1 + camera usecase, mode = 2 + hflip usecase, mode = 4 + vflip usecase, mode = 8 + First parameter/mode value need to match enum, + mdss_mdp_max_bw_mode, present in + include/uapi/linux/msm_mdp.h. + +- qcom,mdss-has-panic-ctrl: Boolean property to indicate if panic/robust signal + control feature is available or not. +- qcom,mdss-en-svs-high: Boolean property to indicate if this target needs to + enable the svs high voltage level for CX rail. +- qcom,mdss-pipe-vig-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective VIG pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-vig-off +- qcom,mdss-pipe-rgb-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective RGB pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-rgb-off +- qcom,mdss-pipe-dma-panic-ctrl-offsets: Array of panic/robust signal offsets + corresponding to the respective DMA pipes. + Number of signal offsets should match the + number of offsets defined in property: + qcom,mdss-pipe-dma-off +- qcom,mdss-per-pipe-panic-luts: Array to configure the panic/robust luts for + each rt and nrt clients. This property is + for the MDPv1.7 and above, which configures + the panic independently on each client. + Each element of the array corresponds to: + First element - panic for linear formats + Second element - panic for tile formats + Third element - robust for linear formats + Fourth element - robust for tile formats +- qcom,mdss-has-pingpong-split: Boolean property to indicate if destination + split feature is available or not in the target. +- qcom,mdss-slave-pingpong-off: Offset address for the extra TE block which needs + to be programmed when pingpong split feature is enabled. + Offset is calculated from the "mdp_phys" + register value. Mandatory when qcom,mdss-has-pingpong-split + is enabled. +- qcom,mdss-ppb-ctl-off: Array of offset addresses of ping pong buffer control registers. + The offsets are calculated from the "mdp_phys" base address + specified. The number of offsets should match the + number of ping pong buffers available in the hardware. + Mandatory when qcom,mdss-has-pingpong-split is enabled. +- qcom,mdss-ppb-cfg-off: Array of offset addresses of ping pong buffer config registers. + The offsets are calculated from the "mdp_phys" base address + specified. The number of offsets should match the + number of ping pong buffers available in the hardware. + Mandatory when qcom,mdss-has-pingpong-split is enabled. +- qcom,mdss-cdm-off: Array of offset addresses for the available + chroma down modules that can convert RGB data + to YUV before sending it to the interface + block. These offsets will be calculated from + register "mdp_phys" define in reg property. The + number of cdm offsets should reflect the number + of cdm blocks present in hardware. +- qcom,mdss-dsc-off: Array of offset addresses for the available + display stream compression module block. + These offsets will be calculated from + register "mdp_phys" define in reg property. The + number of dsc offsets should reflect the number + of dsc blocks present in hardware. +- qcom,max-pipe-width: This value specifies the maximum MDP SSPP width + the device supports. If not specified, a default value + of 2048 will be applied. +- qcom,mdss-reg-bus: Property to provide Bus scaling for register access for + MDP and DSI Blocks. + +- qcom,mdss-rot-reg-bus: Property to provide Bus scaling for register access for + Rotator Block. + +- qcom,mdss-hw-rt: Optional Property to request min vote on the bus. + Few Low tier targets expect min vote on the bus during SMMU + and TZ operations. use this handle to request the vote needed. + +Optional subnodes: +- mdss_fb: Child nodes representing the frame buffer virtual devices. + +Subnode properties: +- compatible : Must be "qcom,mdss-fb" +- cell-index : Index representing frame buffer +- qcom,mdss-mixer-swap: A boolean property that indicates if the mixer muxes + need to be swapped based on the target panel. + By default the property is not defined. +- qcom,memblock-reserve: Specifies the memory location and the size reserved + for the framebuffer used to display the splash screen. + This property is required whenever the continuous splash + screen feature is enabled for the corresponding + framebuffer device. It should be used for only 32bit + kernel. +- qcom,cont-splash-memory: Specifies the memory block region reserved for + continuous splash screen feature. This property should be + defined for corresponding framebuffer device if + "qcom,memblock-reserve" is not defined when continuous + splash screen feature is enabled. +- linux,contiguous-region: Phandle to the continuous memory region reserved for + frame-buffer or continuous splash screen. Size of this + region is dependent on the display panel resolution and + buffering scheme for frame-buffer node. Currently driver + uses double buffering. + + Example: Width = 1920, Height = 1080, BytesPerPixel = 4, + Number of frame-buffers reserved = 2. + Size = 1920*1080*4*2 = ROUND_1MB(15.8MB) = 16MB. +- qcom,mdss-fb-splash-logo-enabled: The boolean entry enables the framebuffer + driver to display the splash logo image. + It is independent of continuous splash + screen feature and has no relation with + qcom,cont-splash-enabled entry present in + panel configuration. +- qcom,mdss-idle-power-collapse-enabled: Boolean property that enables support + for mdss power collapse in idle + screen use cases with smart panels. +- qcom,boot-indication-enabled: Boolean property that enables turning on the blue + LED for notifying that the device is in boot + process. + +- qcom,mdss-pp-offets: A node that lists the offsets of post processing blocks + from base module. + -- qcom,mdss-mdss-sspp-igc-lut-off: This 32 bit value provides the + offset to the IGC lut rams from mdp_phys base. + -- qcom,mdss-sspp-vig-pcc-off: This 32 bit value provides the offset + to PCC block from the VIG pipe base address. + -- qcom,mdss-sspp-rgb-pcc-off: This 32 bit value provides the offset + to PCC block from the RGB pipe base address. + -- qcom,mdss-sspp-dma-pcc-off: This 32 bit value provides the offset + to PCC block from the DMA pipe base address. + -- qcom,mdss-dspp-pcc-off: This 32 bit value provides the offset + to PCC block from the DSPP pipe base address. + -- qcom,mdss-lm-pgc-off: This 32 bit value provides the offset + to PGC block from the layer mixer base address. + -- qcom,mdss-dspp-gamut-off: This 32 bit value provides the offset + to gamut block from DSPP base address. + -- qcom,mdss-dspp-pgc-off: This 32 bit value provides the offset to + PGC block from the DSPP base address. + +- qcom,mdss-scaler-offsets: A node that lists the offsets of scaler blocks + from base module. + -- qcom,mdss-vig-scaler-off: This 32 bit value provides the + offset to vig scaler from vig pipe base. + -- qcom,mdss-vig-scaler-lut-off: This 32 bit value provides the + offset to vig scaler lut from vig pipe base. + -- qcom,mdss-has-dest-scaler: Boolean property to indicate the + presence of destination scaler block. + -- qcom,mdss-dest-block-off: This 32 bit value provides the + offset from mdp base to destination scaler block. + -- qcom,mdss-dest-scaler-off: Array containing offsets of + destination scalar modules from the scaler block. + -- qcom,mdss-dest-scaler-lut-off: Array containing offsets of destination + scaler lut tables from scalar block. + +- qcom,mdss-has-separate-rotator: Boolean property to indicate support of + indpendent rotator. Indpendent rotator has + separate DMA pipe working in block mode only. + +- smmu_mdp_***: Child nodes representing the mdss smmu virtual devices. + Mandatory smmu v2 and not required for smmu v1. + +Subnode properties: +- compatible : Compatible name used in smmu v2. + smmu_v2 names should be: + "qcom,smmu_mdp_unsec" - smmu context bank device for + unsecure mdp domain. + "qcom,smmu_rot_unsec" - smmu context bank device for + unsecure rotation domain. + "qcom,smmu_mdp_sec" - smmu context bank device for + secure mdp domain. + "qcom,smmu_rot_sec" - smmu context bank device for + secure rotation domain. + "qcom,smmu_kms_unsec" - smmu context bank device for + unsecure mdp domain for KMS driver. + "qcom,smmu_nrt_unsec" - smmu context bank device for + unsecure rotation domain for KMS driver. + "qcom,smmu_kms_sec" - smmu context bank device for + secure mdp domain for KMS driver. + "qcom,smmu_nrt_sec" - smmu context bank device for + secure rotation domain for KMS driver. + "qcom,smmu_arm_mdp_unsec" - arm smmu context bank device for + unsecure mdp domain. + "qcom,smmu_arm_mdp_sec" - arm smmu context bank device for + secure mdp domain. +- gdsc-mmagic-mdss-supply: Phandle for mmagic mdss supply regulator device node. +- reg : offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. + +Subnode properties: +Required properties: +- compatible: Must be "qcom,mdss_wb" +- qcom,mdss_pan_res: Array containing two elements, width and height which + specifies size of writeback buffer. +- qcom,mdss_pan_bpp: Specifies bits per pixel for writeback buffer. +- qcom,mdss-fb-map: Specifies the handle for frame buffer. + +Example: + mdss_mdp: qcom,mdss_mdp@fd900000 { + compatible = "qcom,mdss_mdp"; + reg = <0xfd900000 0x22100>, + <0xfd924000 0x1000>, + <0xfd925000 0x1000>; + reg-names = "mdp_phys", "vbif_phys", "vbif_nrt_phys"; + interrupts = <0 72 0>; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + vdd-supply = <&gdsc_mdss>; + batfet-supply = <&pm8941_chg_batif>; + vdd-cx-supply = <&pm8841_s2_corner>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_mdp"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,mdss-dram-channels = <2>; + qcom,mdss-num-nrt-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + + /* Fudge factors */ + qcom,mdss-ab-factor = <2 1>; /* 2 times */ + qcom,mdss-ib-factor = <3 2>; /* 1.5 times */ + qcom,mdss-high-ib-factor = <2 1>; /* 2 times */ + qcom,mdss-clk-factor = <5 4>; /* 1.25 times */ + + /* Clock levels */ + qcom,mdss-clk-levels = <92310000, 177780000, 200000000>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-vbif-qos-rt-setting = <2 2 2 2>; + qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>; + + qcom,max-bandwidth-low-kbps = <2300000>; + qcom,max-bandwidth-high-kbps = <3000000>; + qcom,max-bandwidth-per-pipe-kbps = <4 2100000>, + <8 1800000>; + qcom,max-bw-settings = <1 2300000>, + <2 1700000>, + <4 2300000>, + <8 2000000>; + + qcom,max-mixer-width = <2048>; + qcom,max-pipe-width = <2048>; + qcom,max-clk-rate = <320000000>; + qcom,vbif-settings = <0x0004 0x00000001>, + <0x00D8 0x00000707>; + qcom,vbif-nrt-settings = <0x0004 0x00000001>, + <0x00D8 0x00000707>; + qcom,mdp-settings = <0x02E0 0x000000AA>, + <0x02E4 0x00000055>; + qcom,mdss-pipe-vig-off = <0x00001200 0x00001600 + 0x00001A00>; + qcom,mdss-pipe-rgb-off = <0x00001E00 0x00002200 + 0x00002600>; + qcom,mdss-pipe-dma-off = <0x00002A00 0x00002E00>; + qcom,mdss-pipe-cursor-off = <0x00035000 0x00037000>; + qcom,mdss-dsc-off = <0x00081000 0x00081400>; + qcom,mdss-pipe-vig-fetch-id = <1 4 7>; + qcom,mdss-pipe-rgb-fetch-id = <16 17 18>; + qcom,mdss-pipe-dma-fetch-id = <10 13>; + qcom,mdss-pipe-rgb-fixed-mmb = <2 0 1>, + <2 2 3>, + <2 4 5>, + <2 6 7>; + qcom,mdss-pipe-vig-fixed-mmb = <1 8>, + <1 9>, + <1 10>, + <1 11>; + qcom,mdss-smp-data = <22 4096>; + qcom,mdss-rot-block-size = <64>; + qcom,mdss-rotator-ot-limit = <2>; + qcom,mdss-smp-mb-per-pipe = <2>; + qcom,mdss-pref-prim-intf = "dsi"; + qcom,mdss-has-non-scalar-rgb; + qcom,mdss-has-bwc; + qcom,mdss-has-decimation; + qcom,mdss-has-fixed-qos-arbiter-enabled; + qcom,mdss-has-source-split; + qcom,mdss-wfd-mode = "intf"; + qcom,mdss-no-lut-read; + qcom,mdss-no-hist-vote; + qcom,mdss-traffic-shaper-enabled; + qcom,mdss-has-rotator-downscale; + qcom,mdss-rot-downscale-min = <2>; + qcom,mdss-rot-downscale-max = <16>; + + qcom,mdss-has-pingpong-split; + qcom,mdss-pipe-vig-xin-id = <0 4 8>; + qcom,mdss-pipe-rgb-xin-id = <1 5 9>; + qcom,mdss-pipe-dma-xin-id = <2 10>; + qcom,mdss-pipe-cursor-xin-id = <7 7>; + + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x3AC 0 0>, + <0x3B4 0 0>, + <0x3BC 0 0>, + <0x3C4 0 0>; + + qcom,mdss-pipe-rgb-clk-ctrl-offsets = <0x3AC 4 8>, + <0x3B4 4 8>, + <0x3BC 4 8>, + <0x3C4 4 8>; + + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x3AC 8 12>, + <0x3B4 8 12>; + + qcom,mdss-per-pipe-panic-luts = <0x000f>, + <0xffff>, + <0xfffc>, + <0xff00>; + + qcom,mdss-has-panic-ctrl; + qcom,mdss-pipe-vig-panic-ctrl-offsets = <0 1 2 3>; + qcom,mdss-pipe-rgb-panic-ctrl-offsets = <4 5 6 7>; + qcom,mdss-pipe-dma-panic-ctrl-offsets = <8 9>; + + qcom,mdss-pipe-sw-reset-off = <0x0128>; + qcom,mdss-pipe-vig-sw-reset-map = <5 6 7 8>; + qcom,mdss-pipe-rgb-sw-reset-map = <9 10 11 12>; + qcom,mdss-pipe-dma-sw-reset-map = <13 14>; + + qcom,mdss-ctl-off = <0x00000600 0x00000700 0x00000800 + 0x00000900 0x0000A00>; + qcom,mdss-mixer-intf-off = <0x00003200 0x00003600 + 0x00003A00>; + qcom,mdss-mixer-wb-off = <0x00003E00 0x00004200>; + qcom,mdss-dspp-off = <0x00004600 0x00004A00 0x00004E00>; + qcom,mdss-pingpong-off = <0x00012D00 0x00012E00 0x00012F00>; + qcom,mdss-wb-off = <0x00011100 0x00013100 0x00015100 + 0x00017100 0x00019100>; + qcom,mdss-intf-off = <0x00021100 0x00021300 + 0x00021500 0x00021700>; + qcom,mdss-cdm-off = <0x0007A200>; + qcom,mdss-ppb-ctl-off = <0x0000420>; + qcom,mdss-ppb-cfg-off = <0x0000424>; + qcom,mdss-slave-pingpong-off = <0x00073000> + + /* buffer parameters to calculate prefill bandwidth */ + qcom,mdss-prefill-outstanding-buffer-bytes = <1024>; + qcom,mdss-prefill-y-buffer-bytes = <4096>; + qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>; + qcom,mdss-prefill-scaler-buffer-lines-caf = <4>; + qcom,mdss-prefill-post-scaler-buffer-pixels = <2048>; + qcom,mdss-prefill-pingpong-buffer-pixels = <5120>; + qcom,mdss-prefill-fbc-lines = <2>; + qcom,mdss-idle-power-collapse-enabled; + + qcom,regs-dump-xin-id-mdp = <0xff 0xff 0xff 0xff 0x0 0x0>; + mdss_fb0: qcom,mdss_fb_primary { + cell-index = <0>; + compatible = "qcom,mdss-fb"; + qcom,mdss-mixer-swap; + linux,contiguous-region = <&fb_mem>; + qcom,mdss-fb-splash-logo-enabled: + qcom,cont-splash-memory { + linux,contiguous-region = <&cont_splash_mem>; + }; + }; + + qcom,mdss-pp-offsets { + qcom,mdss-sspp-mdss-igc-lut-off = <0x3000>; + qcom,mdss-sspp-vig-pcc-off = <0x1580>; + qcom,mdss-sspp-rgb-pcc-off = <0x180>; + qcom,mdss-sspp-dma-pcc-off = <0x180>; + qcom,mdss-lm-pgc-off = <0x3C0>; + qcom,mdss-dspp-gamut-off = <0x1600>; + qcom,mdss-dspp-pcc-off = <0x1700>; + qcom,mdss-dspp-pgc-off = <0x17C0>; + }; + + qcom,mdss-scaler-offsets { + qcom,mdss-vig-scaler-off = <0xA00>; + qcom,mdss-vig-scaler-lut-off = <0xB00>; + qcom,mdss-has-dest-scaler; + qcom,mdss-dest-block-off = <0x00061000>; + qcom,mdss-dest-scaler-off = <0x800 0x1000>; + qcom,mdss-dest-scaler-lut-off = <0x900 0x1100>; + }; + + qcom,mdss-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + + qcom,mdss-hw-rt-bus { + /* hw-rt Bus Scale Settings */ + qcom,msm-bus,name = "mdss_hw_rt"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 1000>; + }; + + smmu_mdp_sec: qcom,smmu_mdp_sec_cb { + compatible = "qcom,smmu_mdp_sec"; + iommus = <&mdp_smmu 1>; + reg = <0xd09000 0x000d00>, + reg-names = "mmu_cb"; + gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; + clocks = <&clock_mmss clk_smmu_mdp_ahb_clk>, + <&clock_mmss clk_smmu_mdp_axi_clk>; + clock-names = "dummy_clk", "dummy_clk"; + }; + + qcom,mdss_wb_panel { + compatible = "qcom,mdss_wb"; + qcom,mdss_pan_res = <1280 720>; + qcom,mdss_pan_bpp = <24>; + qcom,mdss-fb-map = <&mdss_fb1>; + }; + + qcom,mdss-rot-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-pll.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-pll.txt new file mode 100644 index 0000000000000000000000000000000000000000..6000f7f4dd6500a6dae9a020ff644c506a84d342 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-pll.txt @@ -0,0 +1,109 @@ +Qualcomm Technologies, Inc. MDSS pll for DSI/EDP/HDMI + +mdss-pll is a pll controller device which supports pll devices that +are compatible with MIPI display serial interface specification, +HDMI and edp. + +Required properties: +- compatible: Compatible name used in the driver. Should be one of: + "qcom,mdss_dsi_pll_8916", "qcom,mdss_dsi_pll_8939", + "qcom,mdss_dsi_pll_8974", "qcom,mdss_dsi_pll_8994", + "qcom,mdss_dsi_pll_8994", "qcom,mdss_dsi_pll_8909", + "qcom,mdss_hdmi_pll", "qcom,mdss_hdmi_pll_8994", + "qcom,mdss_dsi_pll_8992", "qcom,mdss_hdmi_pll_8992", + "qcom,mdss_dsi_pll_8996", "qcom,mdss_hdmi_pll_8996", + "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", + "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_hdmi_pll_8996_v3_1p8", + "qcom,mdss_edp_pll_8996_v3", "qcom,mdss_edp_pll_8996_v3_1p8", + "qcom,mdss_dsi_pll_10nm", "qcom,mdss_dp_pll_8998", + "qcom,mdss_hdmi_pll_8998", "qcom,mdss_dp_pll_10nm", + "qcom,mdss_dsi_pll_7nm", "qcom,mdss_dp_pll_7nm", + "qcom,mdss_dsi_pll_28lpm", "qcom,mdss_dsi_pll_14nm", + "qcom,mdss_dp_pll_14nm", "qcom,mdss_hdmi_pll_28lpm", + "qcom,mdss_dsi_pll_7nm_v2" + "qcom,mdss_dp_pll_sdm660", + "qcom,mdss_dsi_pll_sdm660" +- cell-index: Specifies the controller used +- reg: offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- gdsc-supply: Phandle for gdsc regulator device node. +- vddio-supply: Phandle for vddio regulator device node. +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- clock-rate: List of clock rates in Hz. + +Optional properties: +- label: A string used to describe the driver used. +- vcca-supply: Phandle for vcca regulator device node. + + +- qcom,dsi-pll-ssc-en: Boolean property to indicate that ssc is enabled. +- qcom,dsi-pll-ssc-mode: Spread-spectrum clocking. It can be either "down-spread" + or "center-spread". Default is "down-spread" if it is not specified. +- qcom,ssc-frequency-hz: Integer property to specify the spread frequency + to be programmed for the SSC. +- qcom,ssc-ppm: Integer property to specify the Parts per Million + value of SSC. + +- qcom,platform-supply-entries: A node that lists the elements of the supply. There + can be more than one instance of this binding, + in which case the entry would be appended with + the supply entry index. + e.g. qcom,platform-supply-entry@0 + - reg: offset and length of the register set for the device. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + +Example: + mdss_dsi0_pll: qcom,mdss_dsi_pll@fd922A00 { + compatible = "qcom,mdss_dsi_pll_8974"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + + reg = <0xfd922A00 0xD4>, + <0xfd922900 0x64>, + <0xfd8c2300 0x8>; + reg-names = "pll_base", "dynamic_pll_base", "gdsc_base"; + gdsc-supply = <&gdsc_mdss>; + vddio-supply = <&pm8941_l12>; + vcca-supply = <&pm8941_l28>; + + clocks = <&clock_gcc clk_gcc_mdss_mdp_clk>, + <&clock_gcc clk_gcc_mdss_ahb_clk>, + <&clock_gcc clk_gcc_mdss_axi_clk>; + clock-names = "mdp_core_clk", "iface_clk", "bus_clk"; + clock-rate = <0>, <0>, <0>; + + qcom,dsi-pll-slave; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,ssc-frequency-hz = <30000>; + qcom,ssc-ppm = <5000>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-qpic-panel.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-qpic-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c11a438f5d8f569ec77f77484f0388dc436b8e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-qpic-panel.txt @@ -0,0 +1,25 @@ +Qualcomm Technologies, Inc. mdss-qpic-panel + +mdss-qpic-panel is a panel device which can be driven by qpic. + +Required properties: +- compatible: Must be "qcom,mdss-qpic-panel" +- qcom,mdss-pan-res: A two dimensional array that specifies the panel + resolution. +- qcom,mdss-pan-bpp: Specifies the panel bits per pixel. +- qcom,refresh_rate: Panel refresh rate + +Optional properties: +- label: A string used as a descriptive name of the panel + + +Example: +/ { + qcom,mdss_lcdc_ili9341_qvga { + compatible = "qcom,mdss-qpic-panel"; + label = "ili qvga lcdc panel"; + qcom,mdss-pan-res = <240 320>; + qcom,mdss-pan-bpp = <18>; + qcom,refresh_rate = <60>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-qpic.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-qpic.txt new file mode 100644 index 0000000000000000000000000000000000000000..272eb5e1b7a0d9814d9ff30d9205f317c318d1dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-qpic.txt @@ -0,0 +1,49 @@ +Qualcomm Technologies, Inc. mdss-qpic + +mdss-qpic is a qpic controller device which supports dma transmission to MIPI +and LCDC panel. + +Required properties: +- compatible: must be "qcom,mdss_qpic" +- reg: offset and length of the register set for the device. +- reg-names : names to refer to register sets related to this device +- interrupts: IRQ line +- vdd-supply: Phandle for vdd regulator device node. +- avdd-supply: Phandle for avdd regulator device node. +- qcom,cs-gpio: Phandle for cs gpio device node. +- qcom,te-gpio: Phandle for te gpio device node. +- qcom,rst-gpio: Phandle for rst gpio device node. +- qcom,ad8-gpio: Phandle for ad8 gpio device node. +- qcom,bl-gpio: Phandle for backlight gpio device node. + +Optional properties: +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for +below Bus Scaling properties: + - qcom,msm-bus,name + - qcom,msm-bus,num-cases + - qcom,msm-bus,num-paths + - qcom,msm-bus,vectors-KBps + +Example: + qcom,msm_qpic@f9ac0000 { + compatible = "qcom,mdss_qpic"; + reg = <0xf9ac0000 0x24000>; + reg-names = "qpic_base"; + interrupts = <0 251 0>; + + qcom,msm-bus,name = "mdss_qpic"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + + qcom,msm-bus,vectors-KBps = + <91 512 0 0>, + <91 512 400000 800000>; + + vdd-supply = <&pm8019_l11>; + avdd-supply = <&pm8019_l14>; + qcom,cs-gpio = <&msmgpio 21 0>; + qcom,te-gpio = <&msmgpio 22 0>; + qcom,rst-gpio = <&msmgpio 23 0>; + qcom,ad8-gpio = <&msmgpio 20 0>; + qcom,bl-gpio = <&msmgpio 84 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-rgb.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-rgb.txt new file mode 100644 index 0000000000000000000000000000000000000000..2384cc6fbe1f8b9b1772c9591dfaabdf4582b133 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-rgb.txt @@ -0,0 +1,153 @@ +Qualcomm Technologies, Inc. mdss-rgb + +mdss-rgb is the master RGB device which supports software RGB interface. + +Required properties: +- compatible: Must be "qcom,mdss-rgb" +- ranges: The standard property which specifies the child address +- reg: Base address and length of the different register + regions(s) required for RGB functionality. +- reg-names: A list of strings that map in order to the list of regs. + "dsi_phy" - MDSS DSI PHY register region + "dsi_phy_regulator" - MDSS DSI PHY REGULATOR region + "mmss_misc_phys" - Register region for MMSS DSI clamps +- vdda-supply: Phandle for vdda regulator device node. +- vddio-supply: Phandle for vddio regulator device node. +- qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + +- qcom,platform-reset-gpio: Specifies the panel reset gpio. +- pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node + Refer to pinctrl-bindings.txt +- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl + device node. Refer to pinctrl-bindings.txt + +- qcom,-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of RGB modulee. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-ulp-load: load drawn (uA) from supply in ultra-low power mode + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off + + +Example: + mdss_rgb: qcom,mdss_rgb { + compatible = "qcom,mdss-rgb"; + #address-cells = <1>; + #size-cells = <1>; + + ranges = <0x1a94400 0x1a94400 0x280 + 0x1a94b80 0x1a94b80 0x30 + 0x193e000 0x193e000 0x30>; + + reg = <0x1a94400 0x280>, + <0x1a94b80 0x30>, + <0x193e000 0x30>; + reg-names = "dsi_phy", + "dsi_phy_regulator", "mmss_misc_phys"; + + gdsc-supply = <&gdsc_mdss>; + vdda-1p2-supply = <&pms405_l4>; + vdda-1p8-supply = <&pms405_l5>; + vddio-supply = <&pms405_l6>; + + qcom,mdss-fb-map = <&mdss_fb0>; + qcom,mdss-mdp = <&mdss_mdp>; + + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_rgb_active &mdss_rgb_data0_active + &mdss_rgb_data1_active &mdss_rgb_data2_active + &mdss_rgb_data3_active &mdss_rgb_data4_active + &mdss_rgb_data5_active &mdss_rgb_data_b0_active + &mdss_rgb_data_b1_active &mdss_rgb_data_b2_active + &mdss_rgb_data_b3_active &mdss_rgb_data_b4_active + &mdss_rgb_data_b5_active &mdss_rgb_hsync_active + &mdss_rgb_vsync_active &mdss_rgb_de_active + &mdss_rgb_clk_active>; + pinctrl-1 = <&mdss_rgb_suspend &mdss_rgb_data0_suspend + &mdss_rgb_data1_suspend &mdss_rgb_data2_suspend + &mdss_rgb_data3_suspend &mdss_rgb_data4_suspend + &mdss_rgb_data5_suspend &mdss_rgb_data_b0_suspend + &mdss_rgb_data_b1_suspend &mdss_rgb_data_b2_suspend + &mdss_rgb_data_b3_suspend &mdss_rgb_data_b4_suspend + &mdss_rgb_data_b5_suspend &mdss_rgb_hsync_suspend + &mdss_rgb_vsync_suspend &mdss_rgb_de_suspend + &mdss_rgb_clk_suspend>; + qcom,platform-reset-gpio = <&tlmm 58 0>; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p8"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + }; + +mdss-rgb-spi is the SPI controller for RGB device which supports control +commands communication with RGB panel. + +Required properties: +- compatible: Must be "qcom,mdss-rgb-spi" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz + +Optional properties: +- label: A string used to describe the controller used. +- spi-cpol : Empty property indicating device requires inverse + clock polarity (CPOL) mode +- spi-cpha : Empty property indicating device requires shifted + clock phase (CPHA) mode + +Example: + mdss_rgb_spi: qcom,mdss_rgb_spi { + compatible = "qcom,mdss-rgb-spi"; + label = "MDSS SPI QUP1 CLIENT"; + spi-max-frequency = <5000000>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-rotator.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-rotator.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e077ac23819adc6804913465beb5b17ee4ec53f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-rotator.txt @@ -0,0 +1,78 @@ +QTI MDSS Rotator + +MDSS rotator is a rotator driver, which manages the rotator hw +block inside the Mobile Display Subsystem. + +Required properties +- compatible : Must be "qcom,mdss-rotator". +- qcom,mdss-wb-count: The number of writeback block + in the hardware +- -supply: Phandle for regulator device node. + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing MDSS client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for MDSS driver where use-case 0 is + used to take off MDSS BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to MDSS for particular chipset. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for MDSS are: + 22 = MSM_BUS_MASTER_MDP_PORT0 + 23 = MSM_BUS_MASTER_MDP_PORT1 + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for MDSS are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +Optional properties +- qcom,mdss-has-reg-bus: Boolean property to indicate + if rotator needs to vote for register bus. This + property is needed starting 8996 +- qcom,mdss-has-ubwc: Boolean property to indicate + if the hw supports universal + bandwidth compression (ubwc) +- qcom,mdss-has-downscale Boolean property to indicate + if the hw supports downscale + +Example: + mdss_rotator: qcom,mdss_rotator { + compatible = "qcom,mdss_rotator"; + qcom,mdss-has-downscale; + qcom,mdss-has-ubwc; + qcom,mdss-wb-count = <2>; + + qcom,mdss-has-reg-bus; + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,mdss-num-nrt-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + vdd-supply = <&gdsc_mdss>; + gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>; + qcom,supply-names = "vdd", "gdsc-mmagic-mdss"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-client.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-client.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8945383bad79a0735cafc8c2e1be6aa5260a876 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-client.txt @@ -0,0 +1,26 @@ +Qualcomm Technologies, Inc. mdss-spi-client + +mdss-spi-client is for spi display send the FB data to spi master. + +Required properties: +- compatible : should be "qcom,mdss-spi-client" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz + +Optional properties: +- label: A string used to describe the controller used. +- spi-cpol : Empty property indicating device requires inverse + clock polarity (CPOL) mode +- spi-cpha : Empty property indicating device requires shifted + clock phase (CPHA) mode +- spi-cs-high : Empty property indicating device requires + chip select active high + +Example: +spi@78b9000 { /* BLSP1 QUP5 */ + qcom,mdss_spi_client{ + reg = <0>; + compatible = "qcom,mdss-spi-client"; + label = "MDSS SPI QUP5 CLIENT"; + spi-max-frequency = <50000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-display.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-display.txt new file mode 100644 index 0000000000000000000000000000000000000000..a48ba3f2f45b04017e8b9588b60b1c08a59123d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-display.txt @@ -0,0 +1,24 @@ +Qualcomm Technologies, Inc. mdss-spi-display + +mdss-spi-display is a spi interface display which support send frame +data and command to panel, compatible with SPI interface specification. + +Required properties: +- compatible: Must be "qcom,mdss-spi-display" +- qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the + interface is mapped. + +Optional properties: +- label: A string used to describe the controller used. + +Example: +mdss_spi_display: qcom,mdss_spi_display { + compatible = "qcom,mdss-spi-display"; + label = "mdss spi display"; + + mdss_fb0: qcom,mdss_fb_primary { + cell-index = <0>; + compatible = "qcom,mdss-fb"; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-panel.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-panel.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b303d1d5043005e637224270f9266e050d169e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mdss-spi-panel.txt @@ -0,0 +1,204 @@ +Qualcomm Technologies, Inc. mdss-spi-panel + +mdss-spi-panel is a spi panel device which supports panels that +are compatible with display serial interface specification. + +Required properties: +- qcom,mdss-spi-panel-controller: Specifies the phandle for the SPI controller that + this panel will be mapped to. +- qcom,mdss-spi-panel-width: Specifies panel width in pixels. +- qcom,mdss-spi-panel-height: Specifies panel height in pixels. +- qcom,mdss-spi-bpp: Specifies the panel bits per pixels. + 3 = for rgb111 + 8 = for rgb332 + 12 = for rgb444 + 16 = for rgb565 + 18 = for rgb666 + 24 = for rgb888 +- qcom,mdss-spi-panel-destination: A string that specifies the destination display for the panel. + "display_1" = DISPLAY_1 + "display_2" = DISPLAY_2 +- qcom,mdss-spi-on-command: A byte stream formed by multiple packets + byte 0: wait number of specified ms after command + transmitted + byte 1: 8 bits length in network byte order + byte 3 and beyond: number byte of payload +- qcom,mdss-spi-off-command: A byte stream formed by multiple packets + byte 0: wait number of specified ms after command + transmitted + byte 1: 8 bits length in network byte order + byte 3 and beyond: number byte of payload +Optional properties: +- qcom,mdss-spi-panel-name: A string used as a descriptive name of the panel +- qcom,cont-splash-enabled: Boolean used to enable continuous splash mode. + If this property is specified, it is required to + to specify the memory reserved for the splash + screen using the qcom,memblock-reserve binding + for the framebuffer device attached to the panel. +- qcom,mdss-spi-h-back-porch: Horizontal back porch value in pixels. + 6 = default value. +- qcom,mdss-spi-h-front-porch: Horizontal front porch value in pixels. + 6 = default value. +- qcom,mdss-spi-h-pulse-width: Horizontal pulse width. + 2 = default value. +- qcom,mdss-spi-h-sync-skew: Horizontal sync skew value. + 0 = default value. +- qcom,mdss-spi-v-back-porch: Vertical back porch value in pixels. + 6 = default value. +- qcom,mdss-spi-v-front-porch: Vertical front porch value in pixels. + 6 = default value. +- qcom,mdss-spi-v-pulse-width: Vertical pulse width. + 2 = default value. +- qcom,mdss-spi-bl-pmic-control-type: A string that specifies the implementation of backlight + control for this panel. + "bl_ctrl_pwm" = Backlight controlled by PWM gpio. + "bl_ctrl_wled" = Backlight controlled by WLED. + other: Unknown backlight control. (default) +- qcom,mdss-spi-bl-min-level: Specifies the min backlight level supported by the panel. + 0 = default value. +- qcom,mdss-spi-bl-max-level: Specifies the max backlight level supported by the panel. + 255 = default value. +- qcom,mdss-spi-panel-framerate: Specifies the frame rate for the panel. +- qcom,mdss-spi-panel-vsync-per-te: Specifies the number of how many TE will trigger a VSYNC. +- qcom,esd-check-enabled: Boolean used to enable ESD recovery feature. +- qcom,mdss-spi-panel-status-check-mode:Specifies the panel status check method for ESD recovery. + "send_init_command" = Regardless of panel status, direct send the panel + initial code to recover panel status + "reg_read" = Reads panel status register to check the panel status +- qcom,mdss-spi-panel-status-reg: Unsigned 8bits integer value that specifies the value of panel status register address. +- qcom,mdss-spi-panel-status-read-length: + Unsigned 8bits integer value that specifies the expected read-back length of the + panel register. +- qcom,mdss-spi-panel-status-value: An unsigned 8bits integer araray that specifies the values of the panel status register + which is used to check the panel status. The size of this array + is specified by qcom,mdss-dsi-panel-status-read-length. +Example: +&mdss_spi_display { + spi_gc9305_qvga_cmd: qcom,mdss_spi_gc9305_qvga_cmd { + qcom,mdss-spi-panel-name = "gc9305 qvga command mode spi panel"; + qcom,mdss-spi-panel-destination = "display_1"; + qcom,mdss-spi-panel-controller = <&mdss_spi>; + qcom,mdss-spi-panel-framerate = <30>; + qcom,mdss-spi-panel-width = <240>; + qcom,mdss-spi-panel-height = <320>; + qcom,mdss-spi-h-front-porch = <79>; + qcom,mdss-spi-h-back-porch = <59>; + qcom,mdss-spi-h-pulse-width = <60>; + qcom,mdss-spi-v-back-porch = <10>; + qcom,mdss-spi-v-front-porch = <7>; + qcom,mdss-spi-v-pulse-width = <2>; + qcom,mdss-spi-h-left-border = <0>; + qcom,mdss-spi-h-right-border = <0>; + qcom,mdss-spi-v-top-border = <0>; + qcom,mdss-spi-v-bottom-border = <0>; + qcom,mdss-spi-bpp = <16>; + qcom,mdss-spi-on-command = [00 01 FE + 00 01 EF + 00 02 36 48 + 00 02 3A 05 + 00 02 35 00 + 00 03 A4 44 44 + 00 03 A5 42 42 + 00 03 AA 88 88 + 00 03 E8 12 40 + 00 03 E3 01 10 + 00 02 FF 61 + 00 02 AC 00 + 00 03 A6 2A 2A + 00 03 A7 2B 2B + 00 03 A8 18 18 + 00 03 A9 2A 2A + 00 02 AD 33 + 00 02 AF 55 + 00 02 AE 2B + 00 05 2A 00 00 00 EF + 00 05 2B 00 00 01 3F + 00 01 2C + 00 07 F0 02 02 00 08 0C 10 + 00 07 F1 01 00 00 14 1D 0E + 00 07 F2 10 09 37 04 04 48 + 00 07 F3 10 0B 3F 05 05 4E + 00 07 F4 0D 19 17 1D 1E 0F + 00 07 F5 06 12 13 1A 1B 0F + 78 01 11 + 00 01 29 + 00 01 2C]; + qcom,mdss-spi-off-command = [20 01 28 + 20 01 10]; + qcom,mdss-spi-bl-min-level = <1>; + qcom,mdss-spi-bl-max-level = <4095>; + qcom,esd-check-enabled; + qcom,mdss-spi-panel-status-check-mode = "reg_read"; + qcom,mdss-spi-panel-status-reg = /bits/ 8 <0x09>; + qcom,mdss-spi-panel-status-read-length = <4>; + qcom,mdss-spi-panel-status-value = /bits/ 8 <0x52 0x29 0x83 0x00>; + }; +}; + +mdss-spi-panel is a SPI interface panel which uses SPI protocol for data +receive and send. + +Required properties: +- compatible: Must be "qcom,mdss-spi-panel" +- vdd-supply: Phandle for vdd regulator device node. +- vddio-supply: Phandle for vdd-io regulator device node. +- qcom,panel-supply-entries: A node that lists the elements of the supply used to + power the DSI panel. There can be more than one instance + of this binding, in which case the entry would be appended + with the supply entry index. For a detailed description of + fields in the supply entry, refer to the qcom,ctrl-supply-entries + binding above. + +Optional properties: +- pwms: + Value type: + Definition: The PWM device (phandle) used for controlling backlight. +- qcom,platform-spi-dc-gpio: Pull down this gpio indicate current package is command, + Pull up this gpio indicate current package is parameter or pixels. +- qcom,platform-reset-gpio: Specifies the panel reset gpio. +- qcom,platform-te-gpio: Specifies the gpio used for TE. +- label: A string used to describe the controller used. + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +Example: + mdss_spi_panel: qcom,mdss_spi_panel { + compatible = "qcom,mdss-spi-panel"; + label = "mdss spi panel"; + + vdd-supply = <&pms405_l1>; + vddio-supply = <&pms405_l6>; + qcom,platform-te-gpio = <&tlmm 57 0>; + qcom,platform-reset-gpio = <&tlmm 42 0>; + qcom,platform-spi-dc-gpio = <&tlmm 39 0>; + pwms = <&pms405_l1 0 1000000>; + + qcom,panel-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2850000>; + qcom,supply-max-voltage = <2850000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/msm-hdmi-tx.txt b/arch/arm64/boot/dts/vendor/bindings/fb/msm-hdmi-tx.txt new file mode 100644 index 0000000000000000000000000000000000000000..28eb6c14e34e173fb2abf1c3379854e9c36cf16f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/msm-hdmi-tx.txt @@ -0,0 +1,117 @@ +* Qualcomm Technologies, Inc. HDMI Tx + +Required properties: +- cell-index: hdmi tx controller index +- compatible: must be "qcom,hdmi-tx" +- reg: offset and length of the register regions(s) for the device. +- reg-names: a list of strings that map in order to the list of regs. + +- hpd-gdsc-supply: phandle to the mdss gdsc regulator device tree node. +- hpd-5v-supply: phandle to the 5V regulator device tree node. +- core-vdda-supply: phandle to the HDMI vdda regulator device tree node. +- core-vcc-supply: phandle to the HDMI vcc regulator device tree node. +- qcom,supply-names: a list of strings that map in order + to the list of supplies. +- qcom,min-voltage-level: specifies minimum voltage (uV) level + of supply(ies) mentioned above. +- qcom,max-voltage-level: specifies maximum voltage (uV) level + of supply(ies) mentioned above. +- qcom,enable-load: specifies the current (uA) that will be + drawn from the enabled supply(ies) mentioned above. +- qcom,disable-load: specifies the current (uA) that will be + drawn from the disabled supply(ies) mentioned above. + +- qcom,hdmi-tx-cec: gpio for Consumer Electronics Control (cec) line. +- qcom,hdmi-tx-ddc-clk: gpio for Display Data Channel (ddc) clock line. +- qcom,hdmi-tx-ddc-data: gpio for ddc data line. + +Optional properties: +- hpd-5v-en-supply: phandle to the 5V boost enable regulator device tree node. +- qcom,hdmi-tx-mux-sel: gpio required to toggle HDMI output between + docking station, type A, and liquid device, type D, ports. Required + property for liquid devices. +- qcom,hdmi-tx-ddc-mux-sel: gpio for ddc mux select. +- qcom,hdmi-tx-mux-en: gpio required to enable mux for HDMI output + on liquid devices. Required property for liquid devices. +- qcom,hdmi-tx-mux-lpm: gpio required for hdmi mux configuration + selection on liquid devices. Required property for liquid devices. +- qcom,conditional-power-on: Enables HPD conditionally on MTP targets. + Required property for MTP devices which are reworked to expose HDMI port. +- qcom,hdmi-tx-hpd: gpio required for HDMI hot-plug detect. Required on + platforms where companion chip is not used. +- pinctrl-names: a list of strings that map to the pinctrl states. +- pinctrl-0: list of phandles, each pointing at a pin configuration node. +... +- pinctrl-n: list of phandles, each pointing at a pin configuration node. +- qcom,conti-splash-enabled: Enables the hdmi continuous splash screen feature. + HDMI interface will remain powered on from LK to kernel with continuous + display of bootup logo. +- qcom,pluggable: boolean to enable hotplug feature. +- qcom,max-pclk-frequency-khz: maximum supported pclk frequency in KHz. +- qcom,display-id: A string indicates the display ID for the controller. + The possible values are: + - "primary" + - "secondary" + - "tertiary" + +[Optional child nodes]: These nodes are for devices which are +dependent on HDMI Tx controller. If HDMI Tx controller is disabled then +these devices will be disabled as well. Ex. HDMI Audio Codec device. + +- qcom,msm-hdmi-audio-rx: Node for HDMI audio codec. +Required properties: +- compatible : "msm-hdmi-audio-codec-rx"; + +Example: + mdss_hdmi_tx: qcom,hdmi_tx@fd922100 { + cell-index = <0>; + compatible = "qcom,hdmi-tx"; + reg = <0xfd922100 0x35C>, + <0xfd922500 0x7C>, + <0xfc4b8000 0x60F0>, + <0xfe2a0000 0xFFF>; + reg-names = "core_physical", "phy_physical", "qfprom_physical", + "hdcp_physical"; + + hpd-gdsc-supply = <&gdsc_mdss>; + hpd-5v-supply = <&pm8941_mvs2>; + hpd-5v-en-supply = <&hdmi_vreg>; + core-vdda-supply = <&pm8941_l12>; + core-vcc-supply = <&pm8941_s3>; + qcom,supply-names = "hpd-gdsc", "hpd-5v", "hpd-5v-en", "core-vdda", "core-vcc"; + qcom,min-voltage-level = <0 0 0 1800000 1800000>; + qcom,max-voltage-level = <0 0 0 1800000 1800000>; + qcom,enable-load = <0 0 0 1800000 0>; + qcom,disable-load = <0 0 0 0 0>; + + qcom,hdmi-tx-ddc-mux-sel = <&pma8084_gpios 6 0>; + qcom,hdmi-tx-cec = <&msmgpio 31 0>; + qcom,hdmi-tx-ddc-clk = <&msmgpio 32 0>; + qcom,hdmi-tx-ddc-data = <&msmgpio 33 0>; + qcom,hdmi-tx-hpd = <&msmgpio 34 0>; + + qcom,hdmi-tx-mux-lpm = <&msmgpio 27 0>; + qcom,hdmi-tx-mux-en = <&msmgpio 83 0>; + qcom,hdmi-tx-mux-sel = <&msmgpio 85 0>; + + qcom,conditional-power-on; + qcom,pluggable; + qcom,display-id = "secondary"; + + qcom,msm-hdmi-audio-rx { + compatible = "qcom,msm-hdmi-audio-codec-rx"; + }; + pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", + "hdmi_cec_active", "hdmi_active", + "hdmi_sleep"; + pinctrl-0 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_suspend + &mdss_hdmi_cec_suspend>; + pinctrl-1 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_active + &mdss_hdmi_cec_suspend>; + pinctrl-2 = <&mdss_hdmi_hpd_active &mdss_hdmi_cec_active + &mdss_hdmi_ddc_suspend>; + pinctrl-3 = <&mdss_hdmi_hpd_active &mdss_hdmi_ddc_active + &mdss_hdmi_cec_active>; + pinctrl-4 = <&mdss_hdmi_hpd_suspend &mdss_hdmi_ddc_suspend + &mdss_hdmi_cec_suspend>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/mxsfb.txt b/arch/arm64/boot/dts/vendor/bindings/fb/mxsfb.txt new file mode 100644 index 0000000000000000000000000000000000000000..96ec5179c8a00199e2056ee574c3c55aef37bae3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/mxsfb.txt @@ -0,0 +1,49 @@ +* Freescale MXS LCD Interface (LCDIF) + +Required properties: +- compatible: Should be "fsl,-lcdif". Supported chips include + imx23 and imx28. +- reg: Address and length of the register set for lcdif +- interrupts: Should contain lcdif interrupts +- display : phandle to display node (see below for details) + +* display node + +Required properties: +- bits-per-pixel : <16> for RGB565, <32> for RGB888/666. +- bus-width : number of data lines. Could be <8>, <16>, <18> or <24>. + +Required sub-node: +- display-timings : Refer to binding doc display-timing.txt for details. + +Examples: + +lcdif@80030000 { + compatible = "fsl,imx28-lcdif"; + reg = <0x80030000 2000>; + interrupts = <38 86>; + + display: display { + bits-per-pixel = <32>; + bus-width = <24>; + + display-timings { + native-mode = <&timing0>; + timing0: timing0 { + clock-frequency = <33500000>; + hactive = <800>; + vactive = <480>; + hfront-porch = <164>; + hback-porch = <89>; + hsync-len = <10>; + vback-porch = <23>; + vfront-porch = <10>; + vsync-len = <10>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/fb/sm501fb.txt b/arch/arm64/boot/dts/vendor/bindings/fb/sm501fb.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d9f0098092b927b48dabbf198ee252e91d08a58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fb/sm501fb.txt @@ -0,0 +1,34 @@ +* SM SM501 + +The SM SM501 is a LCD controller, with proper hardware, it can also +drive DVI monitors. + +Required properties: +- compatible : should be "smi,sm501". +- reg : contain two entries: + - First entry: System Configuration register + - Second entry: IO space (Display Controller register) +- interrupts : SMI interrupt to the cpu should be described here. +- interrupt-parent : the phandle for the interrupt controller that + services interrupts for this device. + +Optional properties: +- mode : select a video mode: + x[-][@] +- edid : verbatim EDID data block describing attached display. + Data from the detailed timing descriptor will be used to + program the display controller. +- little-endian: available on big endian systems, to + set different foreign endian. +- big-endian: available on little endian systems, to + set different foreign endian. + +Example for MPC5200: + display@1,0 { + compatible = "smi,sm501"; + reg = <1 0x00000000 0x00800000 + 1 0x03e00000 0x00200000>; + interrupts = <1 1 3>; + mode = "640x480-32@60"; + edid = [edid-data]; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/firmware/coreboot.txt b/arch/arm64/boot/dts/vendor/bindings/firmware/coreboot.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c955703cea87f733494d7ac84d87d1198cf0fb7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/firmware/coreboot.txt @@ -0,0 +1,33 @@ +COREBOOT firmware information + +The device tree node to communicate the location of coreboot's memory-resident +bookkeeping structures to the kernel. Since coreboot itself cannot boot a +device-tree-based kernel (yet), this node needs to be inserted by a +second-stage bootloader (a coreboot "payload"). + +Required properties: + - compatible: Should be "coreboot" + - reg: Address and length of the following two memory regions, in order: + 1.) The coreboot table. This is a list of variable-sized descriptors + that contain various compile- and run-time generated firmware + parameters. It is identified by the magic string "LBIO" in its first + four bytes. + See coreboot's src/commonlib/include/commonlib/coreboot_tables.h for + details. + 2.) The CBMEM area. This is a downward-growing memory region used by + coreboot to dynamically allocate data structures that remain resident. + It may or may not include the coreboot table as one of its members. It + is identified by a root node descriptor with the magic number + 0xc0389481 that resides in the topmost 8 bytes of the area. + See coreboot's src/include/imd.h for details. + +Example: + firmware { + ranges; + + coreboot { + compatible = "coreboot"; + reg = <0xfdfea000 0x264>, + <0xfdfea000 0x16000>; + } + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/firmware/meson/meson_sm.txt b/arch/arm64/boot/dts/vendor/bindings/firmware/meson/meson_sm.txt new file mode 100644 index 0000000000000000000000000000000000000000..c248cd44f7270e877502d397ed01fe5fefc83c89 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/firmware/meson/meson_sm.txt @@ -0,0 +1,15 @@ +* Amlogic Secure Monitor + +In the Amlogic SoCs the Secure Monitor code is used to provide access to the +NVMEM, enable JTAG, set USB boot, etc... + +Required properties for the secure monitor node: +- compatible: Should be "amlogic,meson-gxbb-sm" + +Example: + + firmware { + sm: secure-monitor { + compatible = "amlogic,meson-gxbb-sm"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/firmware/nvidia,tegra186-bpmp.txt b/arch/arm64/boot/dts/vendor/bindings/firmware/nvidia,tegra186-bpmp.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c10802c8327274a56c3d313db952fd63b0d241e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/firmware/nvidia,tegra186-bpmp.txt @@ -0,0 +1,108 @@ +NVIDIA Tegra Boot and Power Management Processor (BPMP) + +The BPMP is a specific processor in Tegra chip, which is designed for +booting process handling and offloading the power management, clock +management, and reset control tasks from the CPU. The binding document +defines the resources that would be used by the BPMP firmware driver, +which can create the interprocessor communication (IPC) between the CPU +and BPMP. + +Required properties: +- name : Should be bpmp +- compatible + Array of strings + One of: + - "nvidia,tegra186-bpmp" +- mboxes : The phandle of mailbox controller and the mailbox specifier. +- shmem : List of the phandle of the TX and RX shared memory area that + the IPC between CPU and BPMP is based on. +- #clock-cells : Should be 1. +- #power-domain-cells : Should be 1. +- #reset-cells : Should be 1. + +This node is a mailbox consumer. See the following files for details of +the mailbox subsystem, and the specifiers implemented by the relevant +provider(s): + +- .../mailbox/mailbox.txt +- .../mailbox/nvidia,tegra186-hsp.txt + +This node is a clock, power domain, and reset provider. See the following +files for general documentation of those features, and the specifiers +implemented by this node: + +- .../clock/clock-bindings.txt +- +- ../power/power_domain.txt +- +- .../reset/reset.txt +- + +The BPMP implements some services which must be represented by separate nodes. +For example, it can provide access to certain I2C controllers, and the I2C +bindings represent each I2C controller as a device tree node. Such nodes should +be nested directly inside the main BPMP node. + +Software can determine whether a child node of the BPMP node represents a device +by checking for a compatible property. Any node with a compatible property +represents a device that can be instantiated. Nodes without a compatible +property may be used to provide configuration information regarding the BPMP +itself, although no such configuration nodes are currently defined by this +binding. + +The BPMP firmware defines no single global name-/numbering-space for such +services. Put another way, the numbering scheme for I2C buses is distinct from +the numbering scheme for any other service the BPMP may provide (e.g. a future +hypothetical SPI bus service). As such, child device nodes will have no reg +property, and the BPMP node will have no #address-cells or #size-cells property. + +The shared memory bindings for BPMP +----------------------------------- + +The shared memory area for the IPC TX and RX between CPU and BPMP are +predefined and work on top of sysram, which is an SRAM inside the chip. + +See ".../sram/sram.txt" for the bindings. + +Example: + +hsp_top0: hsp@3c00000 { + ... + #mbox-cells = <2>; +}; + +sysram@30000000 { + compatible = "nvidia,tegra186-sysram", "mmio-sram"; + reg = <0x0 0x30000000 0x0 0x50000>; + #address-cells = <2>; + #size-cells = <2>; + ranges = <0 0x0 0x0 0x30000000 0x0 0x50000>; + + cpu_bpmp_tx: shmem@4e000 { + compatible = "nvidia,tegra186-bpmp-shmem"; + reg = <0x0 0x4e000 0x0 0x1000>; + label = "cpu-bpmp-tx"; + pool; + }; + + cpu_bpmp_rx: shmem@4f000 { + compatible = "nvidia,tegra186-bpmp-shmem"; + reg = <0x0 0x4f000 0x0 0x1000>; + label = "cpu-bpmp-rx"; + pool; + }; +}; + +bpmp { + compatible = "nvidia,tegra186-bpmp"; + mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB TEGRA_HSP_DB_MASTER_BPMP>; + shmem = <&cpu_bpmp_tx &cpu_bpmp_rx>; + #clock-cells = <1>; + #power-domain-cells = <1>; + #reset-cells = <1>; + + i2c { + compatible = "..."; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/firmware/qcom,scm.txt b/arch/arm64/boot/dts/vendor/bindings/firmware/qcom,scm.txt new file mode 100644 index 0000000000000000000000000000000000000000..242cbc1a6190c1271295e3eb5f3e3468ae3414c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/firmware/qcom,scm.txt @@ -0,0 +1,58 @@ +QCOM Secure Channel Manager (SCM) + +Qualcomm processors include an interface to communicate to the secure firmware. +This interface allows for clients to request different types of actions. These +can include CPU power up/down, HDCP requests, loading of firmware, and other +assorted actions. + +Required properties: +- compatible: must contain one of the following: + * "qcom,scm-apq8064" for APQ8064 platforms + * "qcom,scm-msm8660" for MSM8660 platforms + * "qcom,scm-msm8690" for MSM8690 platforms + * "qcom,scm-msm8996" for MSM8996 platforms + * "qcom,scm-ipq4019" for IPQ4019 platforms + * "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc) + * "android,firmware" for firmware image + * "android,vbmeta" for setting system properties for verified boot. +- clocks: One to three clocks may be required based on compatible. + * No clock required for "qcom,scm-msm8996", "qcom,scm-ipq4019" + * Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960" + * Core, iface, and bus clocks required for "qcom,scm" +- clock-names: Must contain "core" for the core clock, "iface" for the interface + clock and "bus" for the bus clock per the requirements of the compatible. +- qcom,dload-mode: phandle to the TCSR hardware block and offset of the + download mode control register (optional) + +Example for MSM8916: + + firmware { + scm { + compatible = "qcom,scm"; + clocks = <&gcc GCC_CRYPTO_CLK> , <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_AHB_CLK>; + clock-names = "core", "bus", "iface"; + }; + }; + +Example for SM6150: + +firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-fpga2sdram-bridge.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-fpga2sdram-bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..817a8d4bf9037ef136fb980c90fb30621047201a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-fpga2sdram-bridge.txt @@ -0,0 +1,16 @@ +Altera FPGA To SDRAM Bridge Driver + +Required properties: +- compatible : Should contain "altr,socfpga-fpga2sdram-bridge" + +Optional properties: +- bridge-enable : 0 if driver should disable bridge at startup + 1 if driver should enable bridge at startup + Default is to leave bridge in current state. + +Example: + fpga_bridge3: fpga-bridge@ffc25080 { + compatible = "altr,socfpga-fpga2sdram-bridge"; + reg = <0xffc25080 0x4>; + bridge-enable = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-freeze-bridge.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-freeze-bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8e288c71b2decf719dc7c6f7c8504170c56ca50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-freeze-bridge.txt @@ -0,0 +1,23 @@ +Altera Freeze Bridge Controller Driver + +The Altera Freeze Bridge Controller manages one or more freeze bridges. +The controller can freeze/disable the bridges which prevents signal +changes from passing through the bridge. The controller can also +unfreeze/enable the bridges which allows traffic to pass through the +bridge normally. + +Required properties: +- compatible : Should contain "altr,freeze-bridge-controller" +- regs : base address and size for freeze bridge module + +Optional properties: +- bridge-enable : 0 if driver should disable bridge at startup + 1 if driver should enable bridge at startup + Default is to leave bridge in current state. + +Example: + freeze-controller@100000450 { + compatible = "altr,freeze-bridge-controller"; + regs = <0x1000 0x10>; + bridge-enable = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-hps2fpga-bridge.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-hps2fpga-bridge.txt new file mode 100644 index 0000000000000000000000000000000000000000..6406f9337eeba24ddc45a67f349b0ec54bb91b2b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-hps2fpga-bridge.txt @@ -0,0 +1,39 @@ +Altera FPGA/HPS Bridge Driver + +Required properties: +- regs : base address and size for AXI bridge module +- compatible : Should contain one of: + "altr,socfpga-lwhps2fpga-bridge", + "altr,socfpga-hps2fpga-bridge", or + "altr,socfpga-fpga2hps-bridge" +- resets : Phandle and reset specifier for this bridge's reset +- clocks : Clocks used by this module. + +Optional properties: +- bridge-enable : 0 if driver should disable bridge at startup. + 1 if driver should enable bridge at startup. + Default is to leave bridge in its current state. + +Example: + fpga_bridge0: fpga-bridge@ff400000 { + compatible = "altr,socfpga-lwhps2fpga-bridge"; + reg = <0xff400000 0x100000>; + resets = <&rst LWHPS2FPGA_RESET>; + clocks = <&l4_main_clk>; + bridge-enable = <0>; + }; + + fpga_bridge1: fpga-bridge@ff500000 { + compatible = "altr,socfpga-hps2fpga-bridge"; + reg = <0xff500000 0x10000>; + resets = <&rst HPS2FPGA_RESET>; + clocks = <&l4_main_clk>; + bridge-enable = <1>; + }; + + fpga_bridge2: fpga-bridge@ff600000 { + compatible = "altr,socfpga-fpga2hps-bridge"; + reg = <0xff600000 0x100000>; + resets = <&rst FPGA2HPS_RESET>; + clocks = <&l4_main_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-passive-serial.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-passive-serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..48478bc07e29c597e6e2c542c6caf3ee07197b6c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-passive-serial.txt @@ -0,0 +1,29 @@ +Altera Passive Serial SPI FPGA Manager + +Altera FPGAs support a method of loading the bitstream over what is +referred to as "passive serial". +The passive serial link is not technically SPI, and might require extra +circuits in order to play nicely with other SPI slaves on the same bus. + +See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf + +Required properties: +- compatible: Must be one of the following: + "altr,fpga-passive-serial", + "altr,fpga-arria10-passive-serial" +- reg: SPI chip select of the FPGA +- nconfig-gpios: config pin (referred to as nCONFIG in the manual) +- nstat-gpios: status pin (referred to as nSTATUS in the manual) + +Optional properties: +- confd-gpios: confd pin (referred to as CONF_DONE in the manual) + +Example: + fpga: fpga@0 { + compatible = "altr,fpga-passive-serial"; + spi-max-frequency = <20000000>; + reg = <0>; + nconfig-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; + nstat-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; + confd-gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-pr-ip.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-pr-ip.txt new file mode 100644 index 0000000000000000000000000000000000000000..52a294cf2730537c0b925cb16b0845b85c0195b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-pr-ip.txt @@ -0,0 +1,12 @@ +Altera Arria10 Partial Reconfiguration IP + +Required properties: +- compatible : should contain "altr,a10-pr-ip" +- reg : base address and size for memory mapped io. + +Example: + + fpga_mgr: fpga-mgr@ff20c000 { + compatible = "altr,a10-pr-ip"; + reg = <0xff20c000 0x10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..2fd8e7a8473448264ff03cf996cecb3574787b23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt @@ -0,0 +1,19 @@ +Altera SOCFPGA Arria10 FPGA Manager + +Required properties: +- compatible : should contain "altr,socfpga-a10-fpga-mgr" +- reg : base address and size for memory mapped io. + - The first index is for FPGA manager register access. + - The second index is for writing FPGA configuration data. +- resets : Phandle and reset specifier for the device's reset. +- clocks : Clocks used by the device. + +Example: + + fpga_mgr: fpga-mgr@ffd03000 { + compatible = "altr,socfpga-a10-fpga-mgr"; + reg = <0xffd03000 0x100 + 0xffcfe400 0x20>; + clocks = <&l4_mp_clk>; + resets = <&rst FPGAMGR_RESET>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/altera-socfpga-fpga-mgr.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-socfpga-fpga-mgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..d52f3340414d056ea2e813249ec0eb908eca8c8d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/altera-socfpga-fpga-mgr.txt @@ -0,0 +1,17 @@ +Altera SOCFPGA FPGA Manager + +Required properties: +- compatible : should contain "altr,socfpga-fpga-mgr" +- reg : base address and size for memory mapped io. + - The first index is for FPGA manager register access. + - The second index is for writing FPGA configuration data. +- interrupts : interrupt for the FPGA Manager device. + +Example: + + hps_0_fpgamgr: fpgamgr@ff706000 { + compatible = "altr,socfpga-fpga-mgr"; + reg = <0xFF706000 0x1000 + 0xFFB90000 0x1000>; + interrupts = <0 175 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/fpga-region.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/fpga-region.txt new file mode 100644 index 0000000000000000000000000000000000000000..6db8aeda461aebc0155326ae68a136fce19e2898 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/fpga-region.txt @@ -0,0 +1,497 @@ +FPGA Region Device Tree Binding + +Alan Tull 2016 + + CONTENTS + - Introduction + - Terminology + - Sequence + - FPGA Region + - Supported Use Models + - Device Tree Examples + - Constraints + + +Introduction +============ + +FPGA Regions represent FPGA's and partial reconfiguration regions of FPGA's in +the Device Tree. FPGA Regions provide a way to program FPGAs under device tree +control. + +This device tree binding document hits some of the high points of FPGA usage and +attempts to include terminology used by both major FPGA manufacturers. This +document isn't a replacement for any manufacturers specifications for FPGA +usage. + + +Terminology +=========== + +Full Reconfiguration + * The entire FPGA is programmed. + +Partial Reconfiguration (PR) + * A section of an FPGA is reprogrammed while the rest of the FPGA is not + affected. + * Not all FPGA's support PR. + +Partial Reconfiguration Region (PRR) + * Also called a "reconfigurable partition" + * A PRR is a specific section of a FPGA reserved for reconfiguration. + * A base (or static) FPGA image may create a set of PRR's that later may + be independently reprogrammed many times. + * The size and specific location of each PRR is fixed. + * The connections at the edge of each PRR are fixed. The image that is loaded + into a PRR must fit and must use a subset of the region's connections. + * The busses within the FPGA are split such that each region gets its own + branch that may be gated independently. + +Persona + * Also called a "partial bit stream" + * An FPGA image that is designed to be loaded into a PRR. There may be + any number of personas designed to fit into a PRR, but only one at at time + may be loaded. + * A persona may create more regions. + +FPGA Bridge + * FPGA Bridges gate bus signals between a host and FPGA. + * FPGA Bridges should be disabled while the FPGA is being programmed to + prevent spurious signals on the cpu bus and to the soft logic. + * FPGA bridges may be actual hardware or soft logic on an FPGA. + * During Full Reconfiguration, hardware bridges between the host and FPGA + will be disabled. + * During Partial Reconfiguration of a specific region, that region's bridge + will be used to gate the busses. Traffic to other regions is not affected. + * In some implementations, the FPGA Manager transparantly handles gating the + buses, eliminating the need to show the hardware FPGA bridges in the + device tree. + * An FPGA image may create a set of reprogrammable regions, each having its + own bridge and its own split of the busses in the FPGA. + +FPGA Manager + * An FPGA Manager is a hardware block that programs an FPGA under the control + of a host processor. + +Base Image + * Also called the "static image" + * An FPGA image that is designed to do full reconfiguration of the FPGA. + * A base image may set up a set of partial reconfiguration regions that may + later be reprogrammed. + + ---------------- ---------------------------------- + | Host CPU | | FPGA | + | | | | + | ----| | ----------- -------- | + | | H | | |==>| Bridge0 |<==>| PRR0 | | + | | W | | | ----------- -------- | + | | | | | | + | | B |<=====>|<==| ----------- -------- | + | | R | | |==>| Bridge1 |<==>| PRR1 | | + | | I | | | ----------- -------- | + | | D | | | | + | | G | | | ----------- -------- | + | | E | | |==>| Bridge2 |<==>| PRR2 | | + | ----| | ----------- -------- | + | | | | + ---------------- ---------------------------------- + +Figure 1: An FPGA set up with a base image that created three regions. Each +region (PRR0-2) gets its own split of the busses that is independently gated by +a soft logic bridge (Bridge0-2) in the FPGA. The contents of each PRR can be +reprogrammed independently while the rest of the system continues to function. + + +Sequence +======== + +When a DT overlay that targets a FPGA Region is applied, the FPGA Region will +do the following: + + 1. Disable appropriate FPGA bridges. + 2. Program the FPGA using the FPGA manager. + 3. Enable the FPGA bridges. + 4. The Device Tree overlay is accepted into the live tree. + 5. Child devices are populated. + +When the overlay is removed, the child nodes will be removed and the FPGA Region +will disable the bridges. + + +FPGA Region +=========== + +FPGA Regions represent FPGA's and FPGA PR regions in the device tree. An FPGA +Region brings together the elements needed to program on a running system and +add the child devices: + + * FPGA Manager + * FPGA Bridges + * image-specific information needed to to the programming. + * child nodes + +The intended use is that a Device Tree overlay (DTO) can be used to reprogram an +FPGA while an operating system is running. + +An FPGA Region that exists in the live Device Tree reflects the current state. +If the live tree shows a "firmware-name" property or child nodes under a FPGA +Region, the FPGA already has been programmed. A DTO that targets a FPGA Region +and adds the "firmware-name" property is taken as a request to reprogram the +FPGA. After reprogramming is successful, the overlay is accepted into the live +tree. + +The base FPGA Region in the device tree represents the FPGA and supports full +reconfiguration. It must include a phandle to an FPGA Manager. The base +FPGA region will be the child of one of the hardware bridges (the bridge that +allows register access) between the cpu and the FPGA. If there are more than +one bridge to control during FPGA programming, the region will also contain a +list of phandles to the additional hardware FPGA Bridges. + +For partial reconfiguration (PR), each PR region will have an FPGA Region. +These FPGA regions are children of FPGA bridges which are then children of the +base FPGA region. The "Full Reconfiguration to add PRR's" example below shows +this. + +If an FPGA Region does not specify a FPGA Manager, it will inherit the FPGA +Manager specified by its ancestor FPGA Region. This supports both the case +where the same FPGA Manager is used for all of a FPGA as well the case where +a different FPGA Manager is used for each region. + +FPGA Regions do not inherit their ancestor FPGA regions' bridges. This prevents +shutting down bridges that are upstream from the other active regions while one +region is getting reconfigured (see Figure 1 above). During PR, the FPGA's +hardware bridges remain enabled. The PR regions' bridges will be FPGA bridges +within the static image of the FPGA. + +Required properties: +- compatible : should contain "fpga-region" +- fpga-mgr : should contain a phandle to an FPGA Manager. Child FPGA Regions + inherit this property from their ancestor regions. A fpga-mgr property + in a region will override any inherited FPGA manager. +- #address-cells, #size-cells, ranges : must be present to handle address space + mapping for child nodes. + +Optional properties: +- firmware-name : should contain the name of an FPGA image file located on the + firmware search path. If this property shows up in a live device tree + it indicates that the FPGA has already been programmed with this image. + If this property is in an overlay targeting a FPGA region, it is a + request to program the FPGA with that image. +- fpga-bridges : should contain a list of phandles to FPGA Bridges that must be + controlled during FPGA programming along with the parent FPGA bridge. + This property is optional if the FPGA Manager handles the bridges. + If the fpga-region is the child of a fpga-bridge, the list should not + contain the parent bridge. +- partial-fpga-config : boolean, set if partial reconfiguration is to be done, + otherwise full reconfiguration is done. +- external-fpga-config : boolean, set if the FPGA has already been configured + prior to OS boot up. +- encrypted-fpga-config : boolean, set if the bitstream is encrypted +- region-unfreeze-timeout-us : The maximum time in microseconds to wait for + bridges to successfully become enabled after the region has been + programmed. +- region-freeze-timeout-us : The maximum time in microseconds to wait for + bridges to successfully become disabled before the region has been + programmed. +- config-complete-timeout-us : The maximum time in microseconds time for the + FPGA to go to operating mode after the region has been programmed. +- child nodes : devices in the FPGA after programming. + +In the example below, when an overlay is applied targeting fpga-region0, +fpga_mgr is used to program the FPGA. Two bridges are controlled during +programming: the parent fpga_bridge0 and fpga_bridge1. Because the region is +the child of fpga_bridge0, only fpga_bridge1 needs to be specified in the +fpga-bridges property. During programming, these bridges are disabled, the +firmware specified in the overlay is loaded to the FPGA using the FPGA manager +specified in the region. If FPGA programming succeeds, the bridges are +reenabled and the overlay makes it into the live device tree. The child devices +are then populated. If FPGA programming fails, the bridges are left disabled +and the overlay is rejected. The overlay's ranges property maps the lwhps +bridge's region (0xff200000) and the hps bridge's region (0xc0000000) for use by +the two child devices. + +Example: +Base tree contains: + + fpga_mgr: fpga-mgr@ff706000 { + compatible = "altr,socfpga-fpga-mgr"; + reg = <0xff706000 0x1000 + 0xffb90000 0x20>; + interrupts = <0 175 4>; + }; + + fpga_bridge0: fpga-bridge@ff400000 { + compatible = "altr,socfpga-lwhps2fpga-bridge"; + reg = <0xff400000 0x100000>; + resets = <&rst LWHPS2FPGA_RESET>; + clocks = <&l4_main_clk>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + fpga_region0: fpga-region0 { + compatible = "fpga-region"; + fpga-mgr = <&fpga_mgr>; + }; + }; + + fpga_bridge1: fpga-bridge@ff500000 { + compatible = "altr,socfpga-hps2fpga-bridge"; + reg = <0xff500000 0x10000>; + resets = <&rst HPS2FPGA_RESET>; + clocks = <&l4_main_clk>; + }; + +Overlay contains: + +/dts-v1/ /plugin/; +/ { + fragment@0 { + target = <&fpga_region0>; + #address-cells = <1>; + #size-cells = <1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "soc_system.rbf"; + fpga-bridges = <&fpga_bridge1>; + ranges = <0x20000 0xff200000 0x100000>, + <0x0 0xc0000000 0x20000000>; + + gpio@10040 { + compatible = "altr,pio-1.0"; + reg = <0x10040 0x20>; + altr,gpio-bank-width = <4>; + #gpio-cells = <2>; + clocks = <2>; + gpio-controller; + }; + + onchip-memory { + device_type = "memory"; + compatible = "altr,onchipmem-15.1"; + reg = <0x0 0x10000>; + }; + }; + }; +}; + + +Supported Use Models +==================== + +In all cases the live DT must have the FPGA Manager, FPGA Bridges (if any), and +a FPGA Region. The target of the Device Tree Overlay is the FPGA Region. Some +uses are specific to a FPGA device. + + * No FPGA Bridges + In this case, the FPGA Manager which programs the FPGA also handles the + bridges behind the scenes. No FPGA Bridge devices are needed for full + reconfiguration. + + * Full reconfiguration with hardware bridges + In this case, there are hardware bridges between the processor and FPGA that + need to be controlled during full reconfiguration. Before the overlay is + applied, the live DT must include the FPGA Manager, FPGA Bridges, and a + FPGA Region. The FPGA Region is the child of the bridge that allows + register access to the FPGA. Additional bridges may be listed in a + fpga-bridges property in the FPGA region or in the device tree overlay. + + * Partial reconfiguration with bridges in the FPGA + In this case, the FPGA will have one or more PRR's that may be programmed + separately while the rest of the FPGA can remain active. To manage this, + bridges need to exist in the FPGA that can gate the buses going to each FPGA + region while the buses are enabled for other sections. Before any partial + reconfiguration can be done, a base FPGA image must be loaded which includes + PRR's with FPGA bridges. The device tree should have a FPGA region for each + PRR. + +Device Tree Examples +==================== + +The intention of this section is to give some simple examples, focusing on +the placement of the elements detailed above, especially: + * FPGA Manager + * FPGA Bridges + * FPGA Region + * ranges + * target-path or target + +For the purposes of this section, I'm dividing the Device Tree into two parts, +each with its own requirements. The two parts are: + * The live DT prior to the overlay being added + * The DT overlay + +The live Device Tree must contain an FPGA Region, an FPGA Manager, and any FPGA +Bridges. The FPGA Region's "fpga-mgr" property specifies the manager by phandle +to handle programming the FPGA. If the FPGA Region is the child of another FPGA +Region, the parent's FPGA Manager is used. If FPGA Bridges need to be involved, +they are specified in the FPGA Region by the "fpga-bridges" property. During +FPGA programming, the FPGA Region will disable the bridges that are in its +"fpga-bridges" list and will re-enable them after FPGA programming has +succeeded. + +The Device Tree Overlay will contain: + * "target-path" or "target" + The insertion point where the the contents of the overlay will go into the + live tree. target-path is a full path, while target is a phandle. + * "ranges" + The address space mapping from processor to FPGA bus(ses). + * "firmware-name" + Specifies the name of the FPGA image file on the firmware search + path. The search path is described in the firmware class documentation. + * "partial-fpga-config" + This binding is a boolean and should be present if partial reconfiguration + is to be done. + * child nodes corresponding to hardware that will be loaded in this region of + the FPGA. + +Device Tree Example: Full Reconfiguration without Bridges +========================================================= + +Live Device Tree contains: + fpga_mgr0: fpga-mgr@f8007000 { + compatible = "xlnx,zynq-devcfg-1.0"; + reg = <0xf8007000 0x100>; + interrupt-parent = <&intc>; + interrupts = <0 8 4>; + clocks = <&clkc 12>; + clock-names = "ref_clk"; + syscon = <&slcr>; + }; + + fpga_region0: fpga-region0 { + compatible = "fpga-region"; + fpga-mgr = <&fpga_mgr0>; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + }; + +DT Overlay contains: +/dts-v1/ /plugin/; +/ { +fragment@0 { + target = <&fpga_region0>; + #address-cells = <1>; + #size-cells = <1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "zynq-gpio.bin"; + + gpio1: gpio@40000000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0x40000000 0x10000>; + gpio-controller; + #gpio-cells = <0x2>; + xlnx,gpio-width= <0x6>; + }; + }; +}; + +Device Tree Example: Full Reconfiguration to add PRR's +====================================================== + +The base FPGA Region is specified similar to the first example above. + +This example programs the FPGA to have two regions that can later be partially +configured. Each region has its own bridge in the FPGA fabric. + +DT Overlay contains: +/dts-v1/ /plugin/; +/ { + fragment@0 { + target = <&fpga_region0>; + #address-cells = <1>; + #size-cells = <1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "base.rbf"; + + fpga-bridge@4400 { + compatible = "altr,freeze-bridge"; + reg = <0x4400 0x10>; + + fpga_region1: fpga-region1 { + compatible = "fpga-region"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + }; + }; + + fpga-bridge@4420 { + compatible = "altr,freeze-bridge"; + reg = <0x4420 0x10>; + + fpga_region2: fpga-region2 { + compatible = "fpga-region"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + }; + }; + }; + }; +}; + +Device Tree Example: Partial Reconfiguration +============================================ + +This example reprograms one of the PRR's set up in the previous example. + +The sequence that occurs when this overlay is similar to the above, the only +differences are that the FPGA is partially reconfigured due to the +"partial-fpga-config" boolean and the only bridge that is controlled during +programming is the FPGA based bridge of fpga_region1. + +/dts-v1/ /plugin/; +/ { + fragment@0 { + target = <&fpga_region1>; + #address-cells = <1>; + #size-cells = <1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + firmware-name = "soc_image2.rbf"; + partial-fpga-config; + + gpio@10040 { + compatible = "altr,pio-1.0"; + reg = <0x10040 0x20>; + clocks = <0x2>; + altr,gpio-bank-width = <0x4>; + resetvalue = <0x0>; + #gpio-cells = <0x2>; + gpio-controller; + }; + }; + }; +}; + +Constraints +=========== + +It is beyond the scope of this document to fully describe all the FPGA design +constraints required to make partial reconfiguration work[1] [2] [3], but a few +deserve quick mention. + +A persona must have boundary connections that line up with those of the partion +or region it is designed to go into. + +During programming, transactions through those connections must be stopped and +the connections must be held at a fixed logic level. This can be achieved by +FPGA Bridges that exist on the FPGA fabric prior to the partial reconfiguration. + +-- +[1] www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_partrecon.pdf +[2] tspace.library.utoronto.ca/bitstream/1807/67932/1/Byma_Stuart_A_201411_MAS_thesis.pdf +[3] http://www.xilinx.com/support/documentation/sw_manuals/xilinx14_1/ug702.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/lattice-ice40-fpga-mgr.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/lattice-ice40-fpga-mgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dc412437b086d6470038f60480b7af03ddf7e3d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/lattice-ice40-fpga-mgr.txt @@ -0,0 +1,21 @@ +Lattice iCE40 FPGA Manager + +Required properties: +- compatible: Should contain "lattice,ice40-fpga-mgr" +- reg: SPI chip select +- spi-max-frequency: Maximum SPI frequency (>=1000000, <=25000000) +- cdone-gpios: GPIO input connected to CDONE pin +- reset-gpios: Active-low GPIO output connected to CRESET_B pin. Note + that unless the GPIO is held low during startup, the + FPGA will enter Master SPI mode and drive SCK with a + clock signal potentially jamming other devices on the + bus until the firmware is loaded. + +Example: + fpga: fpga@0 { + compatible = "lattice,ice40-fpga-mgr"; + reg = <0>; + spi-max-frequency = <1000000>; + cdone-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 22 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/lattice-machxo2-spi.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/lattice-machxo2-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8c362eb160cc7f0a686c850ccc9703edc2a8dca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/lattice-machxo2-spi.txt @@ -0,0 +1,29 @@ +Lattice MachXO2 Slave SPI FPGA Manager + +Lattice MachXO2 FPGAs support a method of loading the bitstream over +'slave SPI' interface. + +See 'MachXO2ProgrammingandConfigurationUsageGuide.pdf' on www.latticesemi.com + +Required properties: +- compatible: should contain "lattice,machxo2-slave-spi" +- reg: spi chip select of the FPGA + +Example for full FPGA configuration: + + fpga-region0 { + compatible = "fpga-region"; + fpga-mgr = <&fpga_mgr_spi>; + #address-cells = <0x1>; + #size-cells = <0x1>; + }; + + spi1: spi@2000 { + ... + + fpga_mgr_spi: fpga-mgr@0 { + compatible = "lattice,machxo2-slave-spi"; + spi-max-frequency = <8000000>; + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-pr-decoupler.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-pr-decoupler.txt new file mode 100644 index 0000000000000000000000000000000000000000..8dcfba926bc78c7d577ef0491a062b0c6e741ad9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-pr-decoupler.txt @@ -0,0 +1,36 @@ +Xilinx LogiCORE Partial Reconfig Decoupler Softcore + +The Xilinx LogiCORE Partial Reconfig Decoupler manages one or more +decouplers / fpga bridges. +The controller can decouple/disable the bridges which prevents signal +changes from passing through the bridge. The controller can also +couple / enable the bridges which allows traffic to pass through the +bridge normally. + +The Driver supports only MMIO handling. A PR region can have multiple +PR Decouplers which can be handled independently or chained via decouple/ +decouple_status signals. + +Required properties: +- compatible : Should contain "xlnx,pr-decoupler-1.00" followed by + "xlnx,pr-decoupler" +- regs : base address and size for decoupler module +- clocks : input clock to IP +- clock-names : should contain "aclk" + +Optional properties: +- bridge-enable : 0 if driver should disable bridge at startup + 1 if driver should enable bridge at startup + Default is to leave bridge in current state. + +See Documentation/devicetree/bindings/fpga/fpga-region.txt for generic bindings. + +Example: + fpga-bridge@100000450 { + compatible = "xlnx,pr-decoupler-1.00", + "xlnx-pr-decoupler"; + regs = <0x10000045 0x10>; + clocks = <&clkc 15>; + clock-names = "aclk"; + bridge-enable = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-slave-serial.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-slave-serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfa4ed42b62f9bad7d4a5dd56f69b2eca94f4639 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-slave-serial.txt @@ -0,0 +1,43 @@ +Xilinx Slave Serial SPI FPGA Manager + +Xilinx Spartan-6 FPGAs support a method of loading the bitstream over +what is referred to as "slave serial" interface. +The slave serial link is not technically SPI, and might require extra +circuits in order to play nicely with other SPI slaves on the same bus. + +See https://www.xilinx.com/support/documentation/user_guides/ug380.pdf + +Required properties: +- compatible: should contain "xlnx,fpga-slave-serial" +- reg: spi chip select of the FPGA +- prog_b-gpios: config pin (referred to as PROGRAM_B in the manual) +- done-gpios: config status pin (referred to as DONE in the manual) + +Example for full FPGA configuration: + + fpga-region0 { + compatible = "fpga-region"; + fpga-mgr = <&fpga_mgr_spi>; + #address-cells = <0x1>; + #size-cells = <0x1>; + }; + + spi1: spi@10680 { + compatible = "marvell,armada-xp-spi", "marvell,orion-spi"; + pinctrl-0 = <&spi0_pins>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <1>; + interrupts = <92>; + clocks = <&coreclk 0>; + + fpga_mgr_spi: fpga-mgr@0 { + compatible = "xlnx,fpga-slave-serial"; + spi-max-frequency = <60000000>; + spi-cpha; + reg = <0>; + done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>; + prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-zynq-fpga-mgr.txt b/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-zynq-fpga-mgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..7018aa896835915aab194e5ee1ee39bd0c6b919c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fpga/xilinx-zynq-fpga-mgr.txt @@ -0,0 +1,19 @@ +Xilinx Zynq FPGA Manager + +Required properties: +- compatible: should contain "xlnx,zynq-devcfg-1.0" +- reg: base address and size for memory mapped io +- interrupts: interrupt for the FPGA manager device +- clocks: phandle for clocks required operation +- clock-names: name for the clock, should be "ref_clk" +- syscon: phandle for access to SLCR registers + +Example: + devcfg: devcfg@f8007000 { + compatible = "xlnx,zynq-devcfg-1.0"; + reg = <0xf8007000 0x100>; + interrupts = <0 8 4>; + clocks = <&clkc 12>; + clock-names = "ref_clk"; + syscon = <&slcr>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fsi/fsi-master-ast-cf.txt b/arch/arm64/boot/dts/vendor/bindings/fsi/fsi-master-ast-cf.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dc752db748b8fc3935fd45b9548c553b1ff93e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fsi/fsi-master-ast-cf.txt @@ -0,0 +1,36 @@ +Device-tree bindings for ColdFire offloaded gpio-based FSI master driver +------------------------------------------------------------------------ + +Required properties: + - compatible = + "aspeed,ast2400-cf-fsi-master" for an AST2400 based system + or + "aspeed,ast2500-cf-fsi-master" for an AST2500 based system + + - clock-gpios = ; : GPIO for FSI clock + - data-gpios = ; : GPIO for FSI data signal + - enable-gpios = ; : GPIO for enable signal + - trans-gpios = ; : GPIO for voltage translator enable + - mux-gpios = ; : GPIO for pin multiplexing with other + functions (eg, external FSI masters) + - memory-region = ; : Reference to the reserved memory for + the ColdFire. Must be 2M aligned on + AST2400 and 1M aligned on AST2500 + - aspeed,sram = ; : Reference to the SRAM node. + - aspeed,cvic = ; : Reference to the CVIC node. + +Examples: + + fsi-master { + compatible = "aspeed,ast2500-cf-fsi-master", "fsi-master"; + + clock-gpios = <&gpio 0>; + data-gpios = <&gpio 1>; + enable-gpios = <&gpio 2>; + trans-gpios = <&gpio 3>; + mux-gpios = <&gpio 4>; + + memory-region = <&coldfire_memory>; + aspeed,sram = <&sram>; + aspeed,cvic = <&cvic>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/fsi/fsi-master-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/fsi/fsi-master-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e442450747f9c9c9c68a2a71893255359acabdf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fsi/fsi-master-gpio.txt @@ -0,0 +1,28 @@ +Device-tree bindings for gpio-based FSI master driver +----------------------------------------------------- + +Required properties: + - compatible = "fsi-master-gpio"; + - clock-gpios = ; : GPIO for FSI clock + - data-gpios = ; : GPIO for FSI data signal + +Optional properties: + - enable-gpios = ; : GPIO for enable signal + - trans-gpios = ; : GPIO for voltage translator enable + - mux-gpios = ; : GPIO for pin multiplexing with other + functions (eg, external FSI masters) + - no-gpio-delays; : Don't add extra delays between GPIO + accesses. This is useful when the HW + GPIO block is running at a low enough + frequency. + +Examples: + + fsi-master { + compatible = "fsi-master-gpio", "fsi-master"; + clock-gpios = <&gpio 0>; + data-gpios = <&gpio 1>; + enable-gpios = <&gpio 2>; + trans-gpios = <&gpio 3>; + mux-gpios = <&gpio 4>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/fsi/fsi.txt b/arch/arm64/boot/dts/vendor/bindings/fsi/fsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..afb4eccab13190d7959618e3bd3366eec79e57ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fsi/fsi.txt @@ -0,0 +1,156 @@ +FSI bus & engine generic device tree bindings +============================================= + +The FSI bus is probe-able, so the OS is able to enumerate FSI slaves, and +engines within those slaves. However, we have a facility to match devicetree +nodes to probed engines. This allows for fsi engines to expose non-probeable +busses, which are then exposed by the device tree. For example, an FSI engine +that is an I2C master - the I2C bus can be described by the device tree under +the engine's device tree node. + +FSI masters may require their own DT nodes (to describe the master HW itself); +that requirement is defined by the master's implementation, and is described by +the fsi-master-* binding specifications. + +Under the masters' nodes, we can describe the bus topology using nodes to +represent the FSI slaves and their slave engines. As a basic outline: + + fsi-master { + /* top-level of FSI bus topology, bound to an FSI master driver and + * exposes an FSI bus */ + + fsi-slave@ { + /* this node defines the FSI slave device, and is handled + * entirely with FSI core code */ + + fsi-slave-engine@ { + /* this node defines the engine endpoint & address range, which + * is bound to the relevant fsi device driver */ + ... + }; + + fsi-slave-engine@ { + ... + }; + + }; + }; + +Note that since the bus is probe-able, some (or all) of the topology may +not be described; this binding only provides an optional facility for +adding subordinate device tree nodes as children of FSI engines. + +FSI masters +----------- + +FSI master nodes declare themselves as such with the "fsi-master" compatible +value. It's likely that an implementation-specific compatible value will +be needed as well, for example: + + compatible = "fsi-master-gpio", "fsi-master"; + +Since the master nodes describe the top-level of the FSI topology, they also +need to declare the FSI-standard addressing scheme. This requires two cells for +addresses (link index and slave ID), and no size: + + #address-cells = <2>; + #size-cells = <0>; + +An optional boolean property can be added to indicate that a particular master +should not scan for connected devices at initialization time. This is +necessary in cases where a scan could cause arbitration issues with other +masters that may be present on the bus. + + no-scan-on-init; + +FSI slaves +---------- + +Slaves are identified by a (link-index, slave-id) pair, so require two cells +for an address identifier. Since these are not a range, no size cells are +required. For an example, a slave on link 1, with ID 2, could be represented +as: + + cfam@1,2 { + reg = <1 2>; + [...]; + } + +Each slave provides an address-space, under which the engines are accessible. +That address space has a maximum of 23 bits, so we use one cell to represent +addresses and sizes in the slave address space: + + #address-cells = <1>; + #size-cells = <1>; + +Optionally, a slave can provide a global unique chip ID which is used to +identify the physical location of the chip in a system specific way + + chip-id = <0>; + +FSI engines (devices) +--------------------- + +Engines are identified by their address under the slaves' address spaces. We +use a single cell for address and size. Engine nodes represent the endpoint +FSI device, and are passed to those FSI device drivers' ->probe() functions. + +For example, for a slave using a single 0x400-byte page starting at address +0xc00: + + engine@c00 { + reg = <0xc00 0x400>; + }; + + +Full example +------------ + +Here's an example that illustrates: + - an FSI master + - connected to an FSI slave + - that contains an engine that is an I2C master + - connected to an I2C EEPROM + +The FSI master may be connected to additional slaves, and slaves may have +additional engines, but they don't necessarily need to be describe in the +device tree if no extra platform information is required. + + /* The GPIO-based FSI master node, describing the top level of the + * FSI bus + */ + gpio-fsi { + compatible = "fsi-master-gpio", "fsi-master"; + #address-cells = <2>; + #size-cells = <0>; + + /* A FSI slave (aka. CFAM) at link 0, ID 0. */ + cfam@0,0 { + reg = <0 0>; + #address-cells = <1>; + #size-cells = <1>; + chip-id = <0>; + + /* FSI engine at 0xc00, using a single page. In this example, + * it's an I2C master controller, so subnodes describe the + * I2C bus. + */ + i2c-controller@c00 { + reg = <0xc00 0x400>; + + /* Engine-specific data. In this case, we're describing an + * I2C bus, so we're conforming to the generic I2C binding + */ + compatible = "some-vendor,fsi-i2c-controller"; + #address-cells = <1>; + #size-cells = <1>; + + /* I2C endpoint device: an Atmel EEPROM */ + eeprom@50 { + compatible = "atmel,24c256"; + reg = <0x50>; + pagesize = <64>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/fuse/nvidia,tegra20-fuse.txt b/arch/arm64/boot/dts/vendor/bindings/fuse/nvidia,tegra20-fuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..41372d441131aa66071a13357413d752d1025138 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/fuse/nvidia,tegra20-fuse.txt @@ -0,0 +1,40 @@ +NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 fuse block. + +Required properties: +- compatible : For Tegra20, must contain "nvidia,tegra20-efuse". For Tegra30, + must contain "nvidia,tegra30-efuse". For Tegra114, must contain + "nvidia,tegra114-efuse". For Tegra124, must contain "nvidia,tegra124-efuse". + Otherwise, must contain "nvidia,-efuse", plus one of the above, where + is tegra132. + Details: + nvidia,tegra20-efuse: Tegra20 requires using APB DMA to read the fuse data + due to a hardware bug. Tegra20 also lacks certain information which is + available in later generations such as fab code, lot code, wafer id,.. + nvidia,tegra30-efuse, nvidia,tegra114-efuse and nvidia,tegra124-efuse: + The differences between these SoCs are the size of the efuse array, + the location of the spare (OEM programmable) bits and the location of + the speedo data. +- reg: Should contain 1 entry: the entry gives the physical address and length + of the fuse registers. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - fuse +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - fuse + +Example: + + fuse@7000f800 { + compatible = "nvidia,tegra20-efuse"; + reg = <0x7000f800 0x400>, + <0x70000000 0x400>; + clocks = <&tegra_car TEGRA20_CLK_FUSE>; + clock-names = "fuse"; + resets = <&tegra_car 39>; + reset-names = "fuse"; + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/gnss/gnss.txt b/arch/arm64/boot/dts/vendor/bindings/gnss/gnss.txt new file mode 100644 index 0000000000000000000000000000000000000000..f1e4a2ff47c5c0a1fbad287d516c0c3f17960fda --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gnss/gnss.txt @@ -0,0 +1,36 @@ +GNSS Receiver DT binding + +This documents the binding structure and common properties for GNSS receiver +devices. + +A GNSS receiver node is a node named "gnss" and typically resides on a serial +bus (e.g. UART, I2C or SPI). + +Please refer to the following documents for generic properties: + + Documentation/devicetree/bindings/serial/slave-device.txt + Documentation/devicetree/bindings/spi/spi-bus.txt + +Required properties: + +- compatible : A string reflecting the vendor and specific device the node + represents + +Optional properties: +- enable-gpios : GPIO used to enable the device +- timepulse-gpios : Time pulse GPIO + +Example: + +serial@1234 { + compatible = "ns16550a"; + + gnss { + compatible = "u-blox,neo-8"; + + vcc-supply = <&gnss_reg>; + timepulse-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + + current-speed = <4800>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gnss/sirfstar.txt b/arch/arm64/boot/dts/vendor/bindings/gnss/sirfstar.txt new file mode 100644 index 0000000000000000000000000000000000000000..648d183cdb77dd690727572e2d587d81f924093b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gnss/sirfstar.txt @@ -0,0 +1,45 @@ +SiRFstar-based GNSS Receiver DT binding + +SiRFstar chipsets are used in GNSS-receiver modules produced by several +vendors and can use UART, SPI or I2C interfaces. + +Please see Documentation/devicetree/bindings/gnss/gnss.txt for generic +properties. + +Required properties: + +- compatible : Must be one of + + "fastrax,uc430" + "linx,r4" + "wi2wi,w2sg0008i" + "wi2wi,w2sg0084i" + +- vcc-supply : Main voltage regulator (pin name: 3V3_IN, VCC, VDD) + +Required properties (I2C): +- reg : I2C slave address + +Required properties (SPI): +- reg : SPI chip select address + +Optional properties: + +- sirf,onoff-gpios : GPIO used to power on and off device (pin name: ON_OFF) +- sirf,wakeup-gpios : GPIO used to determine device power state + (pin name: RFPWRUP, WAKEUP) +- timepulse-gpios : Time pulse GPIO (pin name: 1PPS, TM) + +Example: + +serial@1234 { + compatible = "ns16550a"; + + gnss { + compatible = "wi2wi,w2sg0084i"; + + vcc-supply = <&gnss_reg>; + sirf,onoff-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + sirf,wakeup-gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gnss/u-blox.txt b/arch/arm64/boot/dts/vendor/bindings/gnss/u-blox.txt new file mode 100644 index 0000000000000000000000000000000000000000..e475659cb85f9848cafb5bec40f86451543aa78e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gnss/u-blox.txt @@ -0,0 +1,44 @@ +u-blox GNSS Receiver DT binding + +The u-blox GNSS receivers can use UART, DDC (I2C), SPI and USB interfaces. + +Please see Documentation/devicetree/bindings/gnss/gnss.txt for generic +properties. + +Required properties: + +- compatible : Must be one of + + "u-blox,neo-8" + "u-blox,neo-m8" + +- vcc-supply : Main voltage regulator + +Required properties (DDC): +- reg : DDC (I2C) slave address + +Required properties (SPI): +- reg : SPI chip select address + +Required properties (USB): +- reg : Number of the USB hub port or the USB host-controller port + to which this device is attached + +Optional properties: + +- timepulse-gpios : Time pulse GPIO +- u-blox,extint-gpios : GPIO connected to the "external interrupt" input pin +- v-bckp-supply : Backup voltage regulator + +Example: + +serial@1234 { + compatible = "ns16550a"; + + gnss { + compatible = "u-blox,neo-8"; + + v-bckp-supply = <&gnss_v_bckp_reg>; + vcc-supply = <&gnss_vcc_reg>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/goldfish/audio.txt b/arch/arm64/boot/dts/vendor/bindings/goldfish/audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..d043fda433bac51e42b99bb464ee7ba9c3a689db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/goldfish/audio.txt @@ -0,0 +1,17 @@ +Android Goldfish Audio + +Android goldfish audio device generated by android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-audio" to match emulator +- reg : +- interrupts : + +Example: + + goldfish_audio@9030000 { + compatible = "google,goldfish-audio"; + reg = <0x9030000 0x100>; + interrupts = <0x4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/goldfish/battery.txt b/arch/arm64/boot/dts/vendor/bindings/goldfish/battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..4fb613933214adb299a4a57ce719d4de2981083f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/goldfish/battery.txt @@ -0,0 +1,17 @@ +Android Goldfish Battery + +Android goldfish battery device generated by android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-battery" to match emulator +- reg : +- interrupts : + +Example: + + goldfish_battery@9020000 { + compatible = "google,goldfish-battery"; + reg = <0x9020000 0x1000>; + interrupts = <0x3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/goldfish/events.txt b/arch/arm64/boot/dts/vendor/bindings/goldfish/events.txt new file mode 100644 index 0000000000000000000000000000000000000000..5babf46317a4e46e55d00f57c35e21caba4a6c78 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/goldfish/events.txt @@ -0,0 +1,17 @@ +Android Goldfish Events Keypad + +Android goldfish events keypad device generated by android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-events-keypad" to match emulator +- reg : +- interrupts : + +Example: + + goldfish-events@9040000 { + compatible = "google,goldfish-events-keypad"; + reg = <0x9040000 0x1000>; + interrupts = <0x5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/goldfish/pipe.txt b/arch/arm64/boot/dts/vendor/bindings/goldfish/pipe.txt new file mode 100644 index 0000000000000000000000000000000000000000..e417a31a1ee3f7ea85a8d6f8edff7c181128af77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/goldfish/pipe.txt @@ -0,0 +1,17 @@ +Android Goldfish QEMU Pipe + +Andorid pipe virtual device generated by android emulator. + +Required properties: + +- compatible : should contain "google,android-pipe" to match emulator +- reg : +- interrupts : + +Example: + + android_pipe@a010000 { + compatible = "google,android-pipe"; + reg = ; + interrupts = <0x12>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/goldfish/tty.txt b/arch/arm64/boot/dts/vendor/bindings/goldfish/tty.txt new file mode 100644 index 0000000000000000000000000000000000000000..82648278da774ebba0a78723665cceaeabcb60a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/goldfish/tty.txt @@ -0,0 +1,17 @@ +Android Goldfish TTY + +Android goldfish tty device generated by android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-tty" to match emulator +- reg : +- interrupts : + +Example: + + goldfish_tty@1f004000 { + compatible = "google,goldfish-tty"; + reg = <0x1f004000 0x1000>; + interrupts = <0xc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/8xxx_gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/8xxx_gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..973362eb3f1e7313d89f793455b489d9e023d235 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/8xxx_gpio.txt @@ -0,0 +1,72 @@ +GPIO controllers on MPC8xxx SoCs + +This is for the non-QE/CPM/GUTs GPIO controllers as found on +8349, 8572, 8610 and compatible. + +Every GPIO controller node must have #gpio-cells property defined, +this information will be used to translate gpio-specifiers. +See bindings/gpio/gpio.txt for details of how to specify GPIO +information for devices. + +The GPIO module usually is connected to the SoC's internal interrupt +controller, see bindings/interrupt-controller/interrupts.txt (the +interrupt client nodes section) for details how to specify this GPIO +module's interrupt. + +The GPIO module may serve as another interrupt controller (cascaded to +the SoC's internal interrupt controller). See the interrupt controller +nodes section in bindings/interrupt-controller/interrupts.txt for +details. + +Required properties: +- compatible: "fsl,-gpio" followed by "fsl,mpc8349-gpio" + for 83xx, "fsl,mpc8572-gpio" for 85xx, or + "fsl,mpc8610-gpio" for 86xx. +- #gpio-cells: Should be two. The first cell is the pin number + and the second cell is used to specify optional + parameters (currently unused). +- interrupts: Interrupt mapping for GPIO IRQ. +- gpio-controller: Marks the port as GPIO controller. + +Optional properties: +- interrupt-controller: Empty boolean property which marks the GPIO + module as an IRQ controller. +- #interrupt-cells: Should be two. Defines the number of integer + cells required to specify an interrupt within + this interrupt controller. The first cell + defines the pin number, the second cell + defines additional flags (trigger type, + trigger polarity). Note that the available + set of trigger conditions supported by the + GPIO module depends on the actual SoC. + +Example of gpio-controller nodes for a MPC8347 SoC: + + gpio1: gpio-controller@c00 { + #gpio-cells = <2>; + compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio"; + reg = <0xc00 0x100>; + interrupt-parent = <&ipic>; + interrupts = <74 0x8>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio-controller@d00 { + #gpio-cells = <2>; + compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio"; + reg = <0xd00 0x100>; + interrupt-parent = <&ipic>; + interrupts = <75 0x8>; + gpio-controller; + }; + +Example of a peripheral using the GPIO module as an IRQ controller: + + funkyfpga@0 { + compatible = "funky-fpga"; + ... + interrupt-parent = <&gpio1>; + interrupts = <4 3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/abilis,tb10x-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/abilis,tb10x-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce19c5660aca422cb175143a2a612d849401eefa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/abilis,tb10x-gpio.txt @@ -0,0 +1,35 @@ +* Abilis TB10x GPIO controller + +Required Properties: +- compatible: Should be "abilis,tb10x-gpio" +- reg: Address and length of the register set for the device +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be <2>. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted). +- abilis,ngpio: the number of GPIO pins this driver controls. + +Optional Properties: +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be <1>. Interrupts are triggered on both edges. +- interrupts: Defines the interrupt line connecting this GPIO controller to + its parent interrupt controller. + +GPIO ranges are specified as described in +Documentation/devicetree/bindings/gpio/gpio.txt + +Example: + + gpioa: gpio@ff140000 { + compatible = "abilis,tb10x-gpio"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tb10x_ictl>; + interrupts = <27 2>; + reg = <0xFF140000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + abilis,ngpio = <3>; + gpio-ranges = <&iomux 0 0 0>; + gpio-ranges-group-names = "gpioa_pins"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,bcm6345-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,bcm6345-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7853143fa42787a8b39c1c98ab3381b81cf0b4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,bcm6345-gpio.txt @@ -0,0 +1,46 @@ +Bindings for the Broadcom's brcm,bcm6345-gpio memory-mapped GPIO controllers. + +These bindings can be used on any BCM63xx SoC. However, BCM6338 and BCM6345 +are the only ones which don't need a pinctrl driver. +BCM6338 have 8-bit data and dirout registers, where GPIO state can be read +and/or written, and the direction changed from input to output. +BCM6345 have 16-bit data and dirout registers, where GPIO state can be read +and/or written, and the direction changed from input to output. + +Required properties: + - compatible: should be "brcm,bcm6345-gpio" + - reg-names: must contain + "dat" - data register + "dirout" - direction (output) register + - reg: address + size pairs describing the GPIO register sets; + order must correspond with the order of entries in reg-names + - #gpio-cells: must be set to 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + - gpio-controller: Marks the device node as a gpio controller. + +Optional properties: + - native-endian: use native endian memory. + +Examples: + - BCM6338: + gpio: gpio-controller@fffe0407 { + compatible = "brcm,bcm6345-gpio"; + reg-names = "dirout", "dat"; + reg = <0xfffe0407 1>, <0xfffe040f 1>; + + #gpio-cells = <2>; + gpio-controller; + }; + + - BCM6345: + gpio: gpio-controller@fffe0406 { + compatible = "brcm,bcm6345-gpio"; + reg-names = "dirout", "dat"; + reg = <0xfffe0406 2>, <0xfffe040a 2>; + native-endian; + + #gpio-cells = <2>; + gpio-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,brcmstb-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,brcmstb-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d468ecd180938fdba9d45196ee0de21406133b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,brcmstb-gpio.txt @@ -0,0 +1,83 @@ +Broadcom STB "UPG GIO" GPIO controller + +The controller's registers are organized as sets of eight 32-bit +registers with each set controlling a bank of up to 32 pins. A single +interrupt is shared for all of the banks handled by the controller. + +Required properties: + +- compatible: + Must be "brcm,brcmstb-gpio" + +- reg: + Define the base and range of the I/O address space containing + the brcmstb GPIO controller registers + +- #gpio-cells: + Should be <2>. The first cell is the pin number (within the controller's + pin space), and the second is used for the following: + bit[0]: polarity (0 for active-high, 1 for active-low) + +- gpio-controller: + Specifies that the node is a GPIO controller. + +- brcm,gpio-bank-widths: + Number of GPIO lines for each bank. Number of elements must + correspond to number of banks suggested by the 'reg' property. + +Optional properties: + +- interrupts: + The interrupt shared by all GPIO lines for this controller. + +- interrupts-extended: + Alternate form of specifying interrupts and parents that allows for + multiple parents. This takes precedence over 'interrupts' and + 'interrupt-parent'. Wakeup-capable GPIO controllers often route their + wakeup interrupt lines through a different interrupt controller than the + primary interrupt line, making this property necessary. + +- #interrupt-cells: + Should be <2>. The first cell is the GPIO number, the second should specify + flags. The following subset of flags is supported: + - bits[3:0] trigger type and level flags + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + Valid combinations are 1, 2, 3, 4, 8. + See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +- interrupt-controller: + Marks the device node as an interrupt controller + +- wakeup-source: + GPIOs for this controller can be used as a wakeup source + +Example: + upg_gio: gpio@f040a700 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio"; + gpio-controller; + interrupt-controller; + reg = <0xf040a700 0x80>; + interrupt-parent = <&irq0_intc>; + interrupts = <0x6>; + brcm,gpio-bank-widths = <32 32 32 24>; + }; + + upg_gio_aon: gpio@f04172c0 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio"; + gpio-controller; + interrupt-controller; + reg = <0xf04172c0 0x40>; + interrupt-parent = <&irq0_aon_intc>; + interrupts = <0x6>; + interrupts-extended = <&irq0_aon_intc 0x6>, + <&aon_pm_l2_intc 0x5>; + wakeup-source; + brcm,gpio-bank-widths = <18 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,kona-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,kona-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a63bc96b6871bf72366f354c55c94bea89ba048 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/brcm,kona-gpio.txt @@ -0,0 +1,52 @@ +Broadcom Kona Family GPIO +========================= + +This GPIO driver is used in the following Broadcom SoCs: + BCM11130, BCM11140, BCM11351, BCM28145, BCM28155 + +The Broadcom GPIO Controller IP can be configured prior to synthesis to +support up to 8 banks of 32 GPIOs where each bank has its own IRQ. The +GPIO controller only supports edge, not level, triggering of interrupts. + +Required properties +------------------- + +- compatible: "brcm,bcm11351-gpio", "brcm,kona-gpio" +- reg: Physical base address and length of the controller's registers. +- interrupts: The interrupt outputs from the controller. There is one GPIO + interrupt per GPIO bank. The number of interrupts listed depends on the + number of GPIO banks on the SoC. The interrupts must be ordered by bank, + starting with bank 0. There is always a 1:1 mapping between banks and + IRQs. +- #gpio-cells: Should be <2>. The first cell is the pin number, the second + cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) + See also "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt. +- #interrupt-cells: Should be <2>. The first cell is the GPIO number. The + second cell is used to specify flags. The following subset of flags is + supported: + - trigger type (bits[1:0]): + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 3 = low-to-high or high-to-low edge triggered + Valid values are 1, 2, 3 + See also .../devicetree/bindings/interrupt-controller/interrupts.txt. +- gpio-controller: Marks the device node as a GPIO controller. +- interrupt-controller: Marks the device node as an interrupt controller. + +Example: + gpio: gpio@35003000 { + compatible = "brcm,bcm11351-gpio", "brcm,kona-gpio"; + reg = <0x35003000 0x800>; + interrupts = + ; + #gpio-cells = <2>; + #interrupt-cells = <2>; + gpio-controller; + interrupt-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/cavium-octeon-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/cavium-octeon-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d6dcd3fe7f996c7d9ca2260ba994345eea19d03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/cavium-octeon-gpio.txt @@ -0,0 +1,49 @@ +* General Purpose Input Output (GPIO) bus. + +Properties: +- compatible: "cavium,octeon-3860-gpio" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the GPIO unit's register bank. + +- gpio-controller: This is a GPIO controller. + +- #gpio-cells: Must be <2>. The first cell is the GPIO pin. + +- interrupt-controller: The GPIO controller is also an interrupt + controller, many of its pins may be configured as an interrupt + source. + +- #interrupt-cells: Must be <2>. The first cell is the GPIO pin + connected to the interrupt source. The second cell is the interrupt + triggering protocol and may have one of four values: + 1 - edge triggered on the rising edge. + 2 - edge triggered on the falling edge + 4 - level triggered active high. + 8 - level triggered active low. + +- interrupts: Interrupt routing for each pin. + +Example: + + gpio-controller@1070000000800 { + #gpio-cells = <2>; + compatible = "cavium,octeon-3860-gpio"; + reg = <0x10700 0x00000800 0x0 0x100>; + gpio-controller; + /* Interrupts are specified by two parts: + * 1) GPIO pin number (0..15) + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + interrupt-controller; + #interrupt-cells = <2>; + /* The GPIO pin connect to 16 consecutive CUI bits */ + interrupts = <0 16>, <0 17>, <0 18>, <0 19>, + <0 20>, <0 21>, <0 22>, <0 23>, + <0 24>, <0 25>, <0 26>, <0 27>, + <0 28>, <0 29>, <0 30>, <0 31>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd42e7280f72111d6c0757fe9b3d4bffd8e6b15b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/cirrus,clps711x-mctrl-gpio.txt @@ -0,0 +1,17 @@ +* ARM Cirrus Logic CLPS711X SYSFLG1 MCTRL GPIOs + +Required properties: +- compatible: Should contain "cirrus,ep7209-mctrl-gpio". +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = Active high, + 1 = Active low. + +Example: + sysgpio: sysgpio { + compatible = "cirrus,ep7312-mctrl-gpio", + "cirrus,ep7209-mctrl-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/faraday,ftgpio010.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/faraday,ftgpio010.txt new file mode 100644 index 0000000000000000000000000000000000000000..d04236558619d84b0b1b99351ac72803ac4b2ca9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/faraday,ftgpio010.txt @@ -0,0 +1,27 @@ +Faraday Technology FTGPIO010 GPIO Controller + +Required properties: + +- compatible : Should be one of + "cortina,gemini-gpio", "faraday,ftgpio010" + "moxa,moxart-gpio", "faraday,ftgpio010" + "faraday,ftgpio010" +- reg : Should contain registers location and length +- interrupts : Should contain the interrupt line for the GPIO block +- gpio-controller : marks this as a GPIO controller +- #gpio-cells : Should be 2, see gpio/gpio.txt +- interrupt-controller : marks this as an interrupt controller +- #interrupt-cells : a standard two-cell interrupt flag, see + interrupt-controller/interrupts.txt + +Example: + +gpio@4d000000 { + compatible = "cortina,gemini-gpio", "faraday,ftgpio010"; + reg = <0x4d000000 0x100>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/fsl-imx-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/fsl-imx-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..b4cd9f906c24d7d3485d524a12521f457aad921a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/fsl-imx-gpio.txt @@ -0,0 +1,35 @@ +* Freescale i.MX/MXC GPIO controller + +Required properties: +- compatible : Should be "fsl,-gpio" +- reg : Address and length of the register set for the device +- interrupts : Should be the port interrupt shared by all 32 pins, if + one number. If two numbers, the first one is the interrupt shared + by low 16 pins and the second one is for high 16 pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells : Should be 2. The first cell is the GPIO number. + The second cell bits[3:0] is used to specify trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + +Optional properties: +- clocks: the clock for clocking the GPIO silicon + +Example: + +gpio0: gpio@73f84000 { + compatible = "fsl,imx51-gpio", "fsl,imx35-gpio"; + reg = <0x73f84000 0x4000>; + interrupts = <50 51>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/fujitsu,mb86s70-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/fujitsu,mb86s70-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..bef353f370d8e5482f4ffcffb7cfdefc3a2fd831 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/fujitsu,mb86s70-gpio.txt @@ -0,0 +1,20 @@ +Fujitsu MB86S7x GPIO Controller +------------------------------- + +Required properties: +- compatible: Should be "fujitsu,mb86s70-gpio" +- reg: Base address and length of register space +- clocks: Specify the clock +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be <2>. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted). + +Examples: + gpio0: gpio@31000000 { + compatible = "fujitsu,mb86s70-gpio"; + reg = <0 0x31000000 0x10000>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&clk 0 2 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-74x164.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-74x164.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a97553d8d76d9f5d42452eda2f979f94752ead4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-74x164.txt @@ -0,0 +1,27 @@ +* Generic 8-bits shift register GPIO driver + +Required properties: +- compatible: Should contain one of the following: + "fairchild,74hc595" + "nxp,74lvc594" +- reg : chip select number +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- registers-number: Number of daisy-chained shift registers + +Optional properties: +- enable-gpios: GPIO connected to the OE (Output Enable) pin. + +Example: + +gpio5: gpio5@0 { + compatible = "fairchild,74hc595"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + registers-number = <4>; + spi-max-frequency = <100000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-74xx-mmio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-74xx-mmio.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bb1a9d60133109ede743502925d3d24f0cf90ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-74xx-mmio.txt @@ -0,0 +1,30 @@ +* 74XX MMIO GPIO driver + +Required properties: +- compatible: Should contain one of the following: + "ti,741g125": for 741G125 (1-bit Input), + "ti,741g174": for 741G74 (1-bit Output), + "ti,742g125": for 742G125 (2-bit Input), + "ti,7474" : for 7474 (2-bit Output), + "ti,74125" : for 74125 (4-bit Input), + "ti,74175" : for 74175 (4-bit Output), + "ti,74365" : for 74365 (6-bit Input), + "ti,74174" : for 74174 (6-bit Output), + "ti,74244" : for 74244 (8-bit Input), + "ti,74273" : for 74273 (8-bit Output), + "ti,741624" : for 741624 (16-bit Input), + "ti,7416374": for 7416374 (16-bit Output). +- reg: Physical base address and length where IC resides. +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify the GPIO polarity: + 0 = Active High, + 1 = Active Low. + +Example: + ctrl: gpio@30008004 { + compatible = "ti,74174"; + reg = <0x30008004 0x1>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-adnp.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-adnp.txt new file mode 100644 index 0000000000000000000000000000000000000000..a28902a65a622dd79569765b7667434a8e778a5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-adnp.txt @@ -0,0 +1,33 @@ +Avionic Design N-bit GPIO expander bindings + +Required properties: +- compatible: should be "ad,gpio-adnp" +- reg: The I2C slave address for this device. +- interrupts: Interrupt specifier for the controllers interrupt. +- #gpio-cells: Should be 2. The first cell is the GPIO number and the + second cell is used to specify optional parameters: + - bit 0: polarity (0: normal, 1: inverted) +- gpio-controller: Marks the device as a GPIO controller +- nr-gpios: The number of pins supported by the controller. + +The GPIO expander can optionally be used as an interrupt controller, in +which case it uses the default two cell specifier as described in +Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + +Example: + + gpioext: gpio-controller@41 { + compatible = "ad,gpio-adnp"; + reg = <0x41>; + + interrupt-parent = <&gpio>; + interrupts = <160 1>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + nr-gpios = <64>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-altera.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-altera.txt new file mode 100644 index 0000000000000000000000000000000000000000..146e554b3c6769cfe10238acc1e9b48d9a5e3d28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-altera.txt @@ -0,0 +1,43 @@ +Altera GPIO controller bindings + +Required properties: +- compatible: + - "altr,pio-1.0" +- reg: Physical base address and length of the controller's registers. +- #gpio-cells : Should be 2 + - The first cell is the gpio offset number. + - The second cell is reserved and is currently unused. +- gpio-controller : Marks the device node as a GPIO controller. +- interrupt-controller: Mark the device node as an interrupt controller +- #interrupt-cells : Should be 1. The interrupt type is fixed in the hardware. + - The first cell is the GPIO offset number within the GPIO controller. +- interrupts: Specify the interrupt. +- altr,interrupt-type: Specifies the interrupt trigger type the GPIO + hardware is synthesized. This field is required if the Altera GPIO controller + used has IRQ enabled as the interrupt type is not software controlled, + but hardware synthesized. Required if GPIO is used as an interrupt + controller. The value is defined in + Only the following flags are supported: + IRQ_TYPE_EDGE_RISING + IRQ_TYPE_EDGE_FALLING + IRQ_TYPE_EDGE_BOTH + IRQ_TYPE_LEVEL_HIGH + +Optional properties: +- altr,ngpio: Width of the GPIO bank. This defines how many pins the + GPIO device has. Ranges between 1-32. Optional and defaults to 32 if not + specified. + +Example: + +gpio_altr: gpio@ff200000 { + compatible = "altr,pio-1.0"; + reg = <0xff200000 0x10>; + interrupts = <0 45 4>; + altr,ngpio = <32>; + altr,interrupt-type = ; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <1>; + interrupt-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-aspeed.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-aspeed.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e9b586770b0599e7c4e88b45d03e692b46e9a78 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-aspeed.txt @@ -0,0 +1,36 @@ +Aspeed GPIO controller Device Tree Bindings +------------------------------------------- + +Required properties: +- compatible : Either "aspeed,ast2400-gpio" or "aspeed,ast2500-gpio" + +- #gpio-cells : Should be two + - First cell is the GPIO line number + - Second cell is used to specify optional + parameters (unused) + +- reg : Address and length of the register set for the device +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt specifier (see interrupt bindings for + details) +- interrupt-controller : Mark the GPIO controller as an interrupt-controller + +Optional properties: + +- clocks : A phandle to the clock to use for debounce timings + +The gpio and interrupt properties are further described in their respective +bindings documentation: + +- Documentation/devicetree/bindings/gpio/gpio.txt +- Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + + Example: + gpio@1e780000 { + #gpio-cells = <2>; + compatible = "aspeed,ast2400-gpio"; + gpio-controller; + interrupts = <20>; + reg = <0x1e780000 0x1000>; + interrupt-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ath79.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ath79.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf71f3ec969d5750258eb2925d29f1252fda5b02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ath79.txt @@ -0,0 +1,37 @@ +Binding for Qualcomm Atheros AR7xxx/AR9xxx GPIO controller + +Required properties: +- compatible: has to be "qca,-gpio" and one of the following + fallbacks: + - "qca,ar7100-gpio" + - "qca,ar9340-gpio" +- reg: Base address and size of the controllers memory area +- gpio-controller : Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters. +- ngpios: Should be set to the number of GPIOs available on the SoC. + +Optional properties: +- interrupts: Interrupt specifier for the controllers interrupt. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode interrupt + source, should be 2 + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +Example: + + gpio@18040000 { + compatible = "qca,ar9132-gpio", "qca,ar7100-gpio"; + reg = <0x18040000 0x30>; + interrupts = <2>; + + ngpios = <22>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-atlas7.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-atlas7.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7e123fc90b574bfc3d46c292394a50dde2853e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-atlas7.txt @@ -0,0 +1,50 @@ +CSR SiRFatlas7 GPIO controller bindings + +Required properties: +- compatible : "sirf,atlas7-gpio" +- reg : Address range of the pinctrl registers +- interrupts : Interrupts used by every GPIO group +- gpio-banks : How many gpio banks on this controller +- gpio-controller : Indicates this device is a GPIO controller +- interrupt-controller : Marks the device node as an interrupt controller + +The GPIO controller also acts as an interrupt controller. It uses the default +two cells specifier as described in Documentation/devicetree/bindings/ +interrupt-controller/interrupts.txt. + +Example: + + gpio_0: gpio_mediam@17040000 { + compatible = "sirf,atlas7-gpio"; + reg = <0x17040000 0x1000>; + interrupts = <0 13 0>, <0 14 0>; + + #gpio-cells = <2>; + #interrupt-cells = <2>; + + gpio-controller; + interrupt-controller; + + gpio-banks = <2>; + gpio-ranges = <&pinctrl 0 0 0>, + <&pinctrl 32 0 0>; + gpio-ranges-group-names = "lvds_gpio_grp", + "uart_nand_gpio_grp"; + }; + + leds { + compatible = "gpio-leds"; + + led1 { + gpios = <&gpio_1 15 0>; + ... + }; + + led2 { + gpios = <&gpio_2 34 0>; + ... + }; + }; + +Please refer to gpio.txt in this directory for details of the common +gpio properties used by devices. diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-axp209.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-axp209.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc42b2caa06d7c88da09eb5d8553f338e62db8de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-axp209.txt @@ -0,0 +1,75 @@ +AXP209 GPIO & pinctrl controller + +This driver follows the usual GPIO bindings found in +Documentation/devicetree/bindings/gpio/gpio.txt + +This driver follows the usual pinctrl bindings found in +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +This driver employs the per-pin muxing pattern. + +Required properties: +- compatible: Should be one of: + - "x-powers,axp209-gpio" + - "x-powers,axp813-gpio" +- #gpio-cells: Should be two. The first cell is the pin number and the + second is the GPIO flags. +- gpio-controller: Marks the device node as a GPIO controller. + +This node must be a subnode of the axp20x PMIC, documented in +Documentation/devicetree/bindings/mfd/axp20x.txt + +Example: + +axp209: pmic@34 { + compatible = "x-powers,axp209"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + axp_gpio: gpio { + compatible = "x-powers,axp209-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; +}; + +The GPIOs can be muxed to other functions and therefore, must be a subnode of +axp_gpio. + +Example: + +&axp_gpio { + gpio0_adc: gpio0-adc { + pins = "GPIO0"; + function = "adc"; + }; +}; + +&example_node { + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_adc>; +}; + +GPIOs and their functions +------------------------- + +Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does +not force GPIO1 and GPIO2 to be in gpio_in function as well). + +axp209 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo, adc +GPIO2 | gpio_in, gpio_out + +axp813 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-clps711x.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-clps711x.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a304ad29d817e87bab4af0aa024315b8b197fe5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-clps711x.txt @@ -0,0 +1,28 @@ +Cirrus Logic CLPS711X GPIO controller + +Required properties: +- compatible: Should be "cirrus,ep7209-gpio" +- reg: Physical base GPIO controller registers location and length. + There should be two registers, first is DATA register, the second + is DIRECTION. +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + +Note: Each GPIO port should have an alias correctly numbered in "aliases" +node. + +Example: + +aliases { + gpio0 = &porta; +}; + +porta: gpio@80000000 { + compatible = "cirrus,ep7312-gpio","cirrus,ep7209-gpio"; + reg = <0x80000000 0x1>, <0x80000040 0x1>; + gpio-controller; + #gpio-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-davinci.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-davinci.txt new file mode 100644 index 0000000000000000000000000000000000000000..553b92a7e87bf5891dcd6c6fa762ae7f37f5a950 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-davinci.txt @@ -0,0 +1,147 @@ +Davinci/Keystone GPIO controller bindings + +Required Properties: +- compatible: should be "ti,dm6441-gpio": for Davinci da850 SoCs + "ti,keystone-gpio": for Keystone 2 66AK2H/K, 66AK2L, + 66AK2E SoCs + "ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G + +- reg: Physical base address of the controller and the size of memory mapped + registers. + +- gpio-controller : Marks the device node as a gpio controller. + +- #gpio-cells : Should be two. + - first cell is the pin number + - second cell is used to specify optional parameters (unused) + +- interrupts: Array of GPIO interrupt number. Only banked or unbanked IRQs are + supported at a time. + +- ti,ngpio: The number of GPIO pins supported. + +- ti,davinci-gpio-unbanked: The number of GPIOs that have an individual interrupt + line to processor. + +- clocks: Should contain the device's input clock, and should be defined as per + the appropriate clock bindings consumer usage in, + + Documentation/devicetree/bindings/clock/keystone-gate.txt + for 66AK2HK/66AK2L/66AK2E SoCs or, + + Documentation/devicetree/bindings/clock/ti,sci-clk.txt + for 66AK2G SoCs + +- clock-names: Name should be "gpio"; + +Currently clock-names and clocks are needed for all keystone 2 platforms +Davinci platforms do not have DT clocks as of now. + +The GPIO controller also acts as an interrupt controller. It uses the default +two cells specifier as described in Documentation/devicetree/bindings/ +interrupt-controller/interrupts.txt. + +Example: + +gpio: gpio@1e26000 { + compatible = "ti,dm6441-gpio"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x226000 0x1000>; + interrupt-parent = <&intc>; + interrupts = <42 IRQ_TYPE_EDGE_BOTH 43 IRQ_TYPE_EDGE_BOTH + 44 IRQ_TYPE_EDGE_BOTH 45 IRQ_TYPE_EDGE_BOTH + 46 IRQ_TYPE_EDGE_BOTH 47 IRQ_TYPE_EDGE_BOTH + 48 IRQ_TYPE_EDGE_BOTH 49 IRQ_TYPE_EDGE_BOTH + 50 IRQ_TYPE_EDGE_BOTH>; + ti,ngpio = <144>; + ti,davinci-gpio-unbanked = <0>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +leds { + compatible = "gpio-leds"; + + led1 { + label = "davinci:green:usr1"; + gpios = <&gpio 10 GPIO_ACTIVE_HIGH>; + ... + }; + + led2 { + label = "davinci:red:debug1"; + gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; + ... + }; +}; + +Example for 66AK2G: + +gpio0: gpio@2603000 { + compatible = "ti,k2g-gpio", "ti,keystone-gpio"; + reg = <0x02603000 0x100>; + gpio-controller; + #gpio-cells = <2>; + interrupts = , + , + , + , + , + , + , + , + ; + interrupt-controller; + #interrupt-cells = <2>; + ti,ngpio = <144>; + ti,davinci-gpio-unbanked = <0>; + clocks = <&k2g_clks 0x001b 0x0>; + clock-names = "gpio"; +}; + +Example for 66AK2HK/66AK2L/66AK2E: + +gpio0: gpio@260bf00 { + compatible = "ti,keystone-gpio"; + reg = <0x0260bf00 0x100>; + gpio-controller; + #gpio-cells = <2>; + /* HW Interrupts mapped to GPIO pins */ + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&clkgpio>; + clock-names = "gpio"; + ti,ngpio = <32>; + ti,davinci-gpio-unbanked = <32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-dsp-keystone.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-dsp-keystone.txt new file mode 100644 index 0000000000000000000000000000000000000000..0423699d74c77468bbf1c9590c5fc5437ae15846 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-dsp-keystone.txt @@ -0,0 +1,39 @@ +Keystone 2 DSP GPIO controller bindings + +HOST OS userland running on ARM can send interrupts to DSP cores using +the DSP GPIO controller IP. It provides 28 IRQ signals per each DSP core. +This is one of the component used by the IPC mechanism used on Keystone SOCs. + +For example TCI6638K2K SoC has 8 DSP GPIO controllers: + - 8 for C66x CorePacx CPUs 0-7 + +Keystone 2 DSP GPIO controller has specific features: +- each GPIO can be configured only as output pin; +- setting GPIO value to 1 causes IRQ generation on target DSP core; +- reading pin value returns 0 - if IRQ was handled or 1 - IRQ is still + pending. + +Required Properties: +- compatible: should be "ti,keystone-dsp-gpio" +- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to + access device state control registers and the offset of device's specific + registers within device state control registers range. +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be 2. + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example: + dspgpio0: keystone_dsp_gpio@2620240 { + compatible = "ti,keystone-dsp-gpio"; + ti,syscon-dev = <&devctrl 0x240>; + gpio-controller; + #gpio-cells = <2>; + }; + + dsp0: dsp0 { + compatible = "linux,rproc-user"; + ... + kick-gpio = <&dspgpio0 27>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-eic-sprd.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-eic-sprd.txt new file mode 100644 index 0000000000000000000000000000000000000000..93d98d09d92b18ebbbdb89804419e052e60c89c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-eic-sprd.txt @@ -0,0 +1,97 @@ +Spreadtrum EIC controller bindings + +The EIC is the abbreviation of external interrupt controller, which can +be used only in input mode. The Spreadtrum platform has 2 EIC controllers, +one is in digital chip, and another one is in PMIC. The digital chip EIC +controller contains 4 sub-modules: EIC-debounce, EIC-latch, EIC-async and +EIC-sync. But the PMIC EIC controller contains only one EIC-debounce sub- +module. + +The EIC-debounce sub-module provides up to 8 source input signal +connections. A debounce mechanism is used to capture the input signals' +stable status (millisecond resolution) and a single-trigger mechanism +is introduced into this sub-module to enhance the input event detection +reliability. In addition, this sub-module's clock can be shut off +automatically to reduce power dissipation. Moreover the debounce range +is from 1ms to 4s with a step size of 1ms. The input signal will be +ignored if it is asserted for less than 1 ms. + +The EIC-latch sub-module is used to latch some special power down signals +and generate interrupts, since the EIC-latch does not depend on the APB +clock to capture signals. + +The EIC-async sub-module uses a 32kHz clock to capture the short signals +(microsecond resolution) to generate interrupts by level or edge trigger. + +The EIC-sync is similar with GPIO's input function, which is a synchronized +signal input register. It can generate interrupts by level or edge trigger +when detecting input signals. + +Required properties: +- compatible: Should be one of the following: + "sprd,sc9860-eic-debounce", + "sprd,sc9860-eic-latch", + "sprd,sc9860-eic-async", + "sprd,sc9860-eic-sync", + "sprd,sc27xx-eic". +- reg: Define the base and range of the I/O address space containing + the GPIO controller registers. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be <2>. The first cell is the gpio number and + the second cell is used to specify optional parameters. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be <2>. Specifies the number of cells needed + to encode interrupt source. +- interrupts: Should be the port interrupt shared by all the gpios. + +Example: + eic_debounce: gpio@40210000 { + compatible = "sprd,sc9860-eic-debounce"; + reg = <0 0x40210000 0 0x80>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + eic_latch: gpio@40210080 { + compatible = "sprd,sc9860-eic-latch"; + reg = <0 0x40210080 0 0x20>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + eic_async: gpio@402100a0 { + compatible = "sprd,sc9860-eic-async"; + reg = <0 0x402100a0 0 0x20>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + eic_sync: gpio@402100c0 { + compatible = "sprd,sc9860-eic-sync"; + reg = <0 0x402100c0 0 0x20>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + pmic_eic: gpio@300 { + compatible = "sprd,sc27xx-eic"; + reg = <0x300>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-exar.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-exar.txt new file mode 100644 index 0000000000000000000000000000000000000000..4540d61824af8a3d9cccb33398876570d66fd6ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-exar.txt @@ -0,0 +1,5 @@ +Exportable MPIO interface of Exar UART chips + +Required properties of the device: + - exar,first-pin: first exportable pins (0..15) + - ngpios: number of exportable pins (1..16) diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-grgpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-grgpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..e466598105fc6a2ed1a3ada4c166bf9a4cee4d39 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-grgpio.txt @@ -0,0 +1,26 @@ +Aeroflex Gaisler GRGPIO General Purpose I/O cores. + +The GRGPIO GPIO core is available in the GRLIB VHDL IP core library. + +Note: In the ordinary environment for the GRGPIO core, a Leon SPARC system, +these properties are built from information in the AMBA plug&play. + +Required properties: + +- name : Should be "GAISLER_GPIO" or "01_01a" + +- reg : Address and length of the register set for the device + +- interrupts : Interrupt numbers for this device + +Optional properties: + +- nbits : The number of gpio lines. If not present driver assumes 32 lines. + +- irqmap : An array with an index for each gpio line. An index is either a valid + index into the interrupts property array, or 0xffffffff that indicates + no irq for that line. Driver provides no interrupt support if not + present. + +For further information look in the documentation for the GLIB IP core library: +http://www.gaisler.com/products/grlib/grip.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-lp3943.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-lp3943.txt new file mode 100644 index 0000000000000000000000000000000000000000..80fcb7d70e13d1d35c3157ac99e72db3d6f9fb70 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-lp3943.txt @@ -0,0 +1,37 @@ +TI/National Semiconductor LP3943 GPIO controller + +Required properties: + - compatible: "ti,lp3943-gpio" + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be 2. See gpio.txt in this directory for a + description of the cells format. + +Example: +Simple LED controls with LP3943 GPIO controller + +&i2c4 { + lp3943@60 { + compatible = "ti,lp3943"; + reg = <0x60>; + + gpioex: gpio { + compatible = "ti,lp3943-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + }; +}; + +leds { + compatible = "gpio-leds"; + indicator1 { + label = "indi1"; + gpios = <&gpioex 9 GPIO_ACTIVE_LOW>; + }; + + indicator2 { + label = "indi2"; + gpios = <&gpioex 10 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max3191x.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max3191x.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3a6444b8f455c831531f73124a0e68c26eb954e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max3191x.txt @@ -0,0 +1,59 @@ +GPIO driver for Maxim MAX3191x industrial serializer + +Required properties: + - compatible: Must be one of: + "maxim,max31910" + "maxim,max31911" + "maxim,max31912" + "maxim,max31913" + "maxim,max31953" + "maxim,max31963" + - reg: Chip select number. + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be two. For consumer use see gpio.txt. + +Optional properties: + - #daisy-chained-devices: + Number of chips in the daisy-chain (default is 1). + - maxim,modesel-gpios: GPIO pins to configure modesel of each chip. + The number of GPIOs must equal "#daisy-chained-devices" + (if each chip is driven by a separate pin) or 1 + (if all chips are wired to the same pin). + - maxim,fault-gpios: GPIO pins to read fault of each chip. + The number of GPIOs must equal "#daisy-chained-devices" + or 1. + - maxim,db0-gpios: GPIO pins to configure debounce of each chip. + The number of GPIOs must equal "#daisy-chained-devices" + or 1. + - maxim,db1-gpios: GPIO pins to configure debounce of each chip. + The number of GPIOs must equal "maxim,db0-gpios". + - maxim,modesel-8bit: Boolean whether the modesel pin of the chips is + pulled high (8-bit mode). Use this if the modesel pin + is hardwired and consequently "maxim,modesel-gpios" + cannot be specified. By default if neither this nor + "maxim,modesel-gpios" is given, the driver assumes + that modesel is pulled low (16-bit mode). + - maxim,ignore-undervoltage: + Boolean whether to ignore undervoltage alarms signaled + by the "maxim,fault-gpios" or by the status byte + (in 16-bit mode). Use this if the chips are powered + through 5VOUT instead of VCC24V, in which case they + will constantly signal undervoltage. + +For other required and optional properties of SPI slave nodes please refer to +../spi/spi-bus.txt. + +Example: + gpio@0 { + compatible = "maxim,max31913"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + + maxim,modesel-gpios = <&gpio2 23>; + maxim,fault-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>; + maxim,db0-gpios = <&gpio2 25>; + maxim,db1-gpios = <&gpio2 26>; + + spi-max-frequency = <25000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max732x.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max732x.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3a9c0c32823190fbc2a211a782e6bb5bf0b2fe4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max732x.txt @@ -0,0 +1,58 @@ +* MAX732x-compatible I/O expanders + +Required properties: + - compatible: Should be one of the following: + - "maxim,max7319": For the Maxim MAX7319 + - "maxim,max7320": For the Maxim MAX7320 + - "maxim,max7321": For the Maxim MAX7321 + - "maxim,max7322": For the Maxim MAX7322 + - "maxim,max7323": For the Maxim MAX7323 + - "maxim,max7324": For the Maxim MAX7324 + - "maxim,max7325": For the Maxim MAX7325 + - "maxim,max7326": For the Maxim MAX7326 + - "maxim,max7327": For the Maxim MAX7327 + - reg: I2C slave address for this device. + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be 2. + - first cell is the GPIO number + - second cell specifies GPIO flags, as defined in . + Only the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + +Optional properties: + + The I/O expander can detect input state changes, and thus optionally act as + an interrupt controller. When the expander interrupt line is connected all the + following properties must be set. For more information please see the + interrupt controller device tree bindings documentation available at + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: Number of cells to encode an interrupt source, shall be 2. + - first cell is the pin number + - second cell is used to specify flags + - interrupts: Interrupt specifier for the controllers interrupt. + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example 1. MAX7325 with interrupt support enabled (CONFIG_GPIO_MAX732X_IRQ=y): + + expander: max7325@6d { + compatible = "maxim,max7325"; + reg = <0x6d>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio4>; + interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + }; + +Example 2. MAX7325 with interrupt support disabled (CONFIG_GPIO_MAX732X_IRQ=n): + + expander: max7325@6d { + compatible = "maxim,max7325"; + reg = <0x6d>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max77620.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max77620.txt new file mode 100644 index 0000000000000000000000000000000000000000..410e716fd3d22c8b1df3ad222d08ff3d2551a80e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-max77620.txt @@ -0,0 +1,25 @@ +GPIO driver for MAX77620 Power management IC from Maxim Semiconductor. + +Device has 8 GPIO pins which can be configured as GPIO as well as the +special IO functions. + +Required properties: +------------------- +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +For more details, please refer generic GPIO DT binding document +. + +Example: +-------- +#include +... +max77620@3c { + compatible = "maxim,max77620"; + + gpio-controller; + #gpio-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mm-lantiq.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mm-lantiq.txt new file mode 100644 index 0000000000000000000000000000000000000000..f93d51478d5ab976adeb453bf131f12031ba0fd7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mm-lantiq.txt @@ -0,0 +1,38 @@ +Lantiq SoC External Bus memory mapped GPIO controller + +By attaching hardware latches to the EBU it is possible to create output +only gpios. This driver configures a special memory address, which when +written to outputs 16 bit to the latches. + +The node describing the memory mapped GPIOs needs to be a child of the node +describing the "lantiq,localbus". + +Required properties: +- compatible : Should be "lantiq,gpio-mm-lantiq" +- reg : Address and length of the register set for the device +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify optional parameters (currently + unused). +- gpio-controller : Marks the device node as a gpio controller. + +Optional properties: +- lantiq,shadow : The default value that we shall assume as already set on the + shift register cascade. + +Example: + +localbus@0 { + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x0 0x3ffffff /* addrsel0 */ + 1 0 0x4000000 0x4000010>; /* addsel1 */ + compatible = "lantiq,localbus", "simple-bus"; + + gpio_mm0: gpio@4000000 { + compatible = "lantiq,gpio-mm"; + reg = <1 0x0 0x10>; + gpio-controller; + #gpio-cells = <2>; + lantiq,shadow = <0x77f> + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mpc8xxx.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mpc8xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..69d46162d0f5ba385da868a0ce9240e2b34b06ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mpc8xxx.txt @@ -0,0 +1,39 @@ +* Freescale MPC512x/MPC8xxx/QorIQ/Layerscape GPIO controller + +Required properties: +- compatible : Should be "fsl,-gpio" + The following s are known to be supported: + mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq, + ls1021a, ls1043a, ls2080a. +- reg : Address and length of the register set for the device +- interrupts : Should be the port interrupt shared by all 32 pins. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + +Optional properties: +- little-endian : GPIO registers are used as little endian. If not + present registers are used as big endian by default. + +Example of gpio-controller node for a mpc5125 SoC: + +gpio0: gpio@1100 { + compatible = "fsl,mpc5125-gpio"; + #gpio-cells = <2>; + reg = <0x1100 0x080>; + interrupts = <78 0x8>; +}; + +Example of gpio-controller node for a ls2080a SoC: + +gpio0: gpio@2300000 { + compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; + reg = <0x0 0x2300000 0x0 0x10000>; + interrupts = <0 36 0x4>; /* Level high type */ + gpio-controller; + little-endian; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mvebu.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mvebu.txt new file mode 100644 index 0000000000000000000000000000000000000000..38ca2201e8ae1f99f83eb6c8e10fca42955c1eed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mvebu.txt @@ -0,0 +1,95 @@ +* Marvell EBU GPIO controller + +Required properties: + +- compatible : Should be "marvell,orion-gpio", "marvell,mv78200-gpio", + "marvell,armadaxp-gpio" or "marvell,armada-8k-gpio". + + "marvell,orion-gpio" should be used for Orion, Kirkwood, Dove, + Discovery (except MV78200) and Armada 370. "marvell,mv78200-gpio" + should be used for the Discovery MV78200. + + "marvel,armadaxp-gpio" should be used for all Armada XP SoCs + (MV78230, MV78260, MV78460). + + "marvell,armada-8k-gpio" should be used for the Armada 7K and 8K + SoCs (either from AP or CP), see + Documentation/devicetree/bindings/arm/marvell/cp110-system-controller0.txt + and + Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt + for specific details about the offset property. + +- reg: Address and length of the register set for the device. Only one + entry is expected, except for the "marvell,armadaxp-gpio" variant + for which two entries are expected: one for the general registers, + one for the per-cpu registers. Not used for marvell,armada-8k-gpio. + +- interrupts: The list of interrupts that are used for all the pins + managed by this GPIO bank. There can be more than one interrupt + (example: 1 interrupt per 8 pins on Armada XP, which means 4 + interrupts per bank of 32 GPIOs). + +- interrupt-controller: identifies the node as an interrupt controller + +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. Should be two. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + +- gpio-controller: marks the device node as a gpio controller + +- ngpios: number of GPIOs this controller has + +- #gpio-cells: Should be two. The first cell is the pin number. The + second cell is reserved for flags, unused at the moment. + +Optional properties: + +In order to use the GPIO lines in PWM mode, some additional optional +properties are required. + +- compatible: Must contain "marvell,armada-370-gpio" + +- reg: an additional register set is needed, for the GPIO Blink + Counter on/off registers. + +- reg-names: Must contain an entry "pwm" corresponding to the + additional register range needed for PWM operation. + +- #pwm-cells: Should be two. The first cell is the GPIO line number. The + second cell is the period in nanoseconds. + +- clocks: Must be a phandle to the clock for the GPIO controller. + +Example: + + gpio0: gpio@d0018100 { + compatible = "marvell,armadaxp-gpio"; + reg = <0xd0018100 0x40>, + <0xd0018800 0x30>; + ngpios = <32>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <16>, <17>, <18>, <19>; + }; + + gpio1: gpio@18140 { + compatible = "marvell,armada-370-gpio"; + reg = <0x18140 0x40>, <0x181c8 0x08>; + reg-names = "gpio", "pwm"; + ngpios = <17>; + gpio-controller; + #gpio-cells = <2>; + #pwm-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <87>, <88>, <89>; + clocks = <&coreclk 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mxs.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mxs.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e677a47b83605ade43d6072711fa19b88e8a33f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-mxs.txt @@ -0,0 +1,88 @@ +* Freescale MXS GPIO controller + +The Freescale MXS GPIO controller is part of MXS PIN controller. The +GPIOs are organized in port/bank. Each port consists of 32 GPIOs. + +As the GPIO controller is embedded in the PIN controller and all the +GPIO ports share the same IO space with PIN controller, the GPIO node +will be represented as sub-nodes of MXS pinctrl node. + +Required properties for GPIO node: +- compatible : Should be "fsl,-gpio". The supported SoCs include + imx23 and imx28. +- interrupts : Should be the port interrupt shared by all 32 pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells : Should be 2. The first cell is the GPIO number. + The second cell bits[3:0] is used to specify trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + +Note: Each GPIO port should have an alias correctly numbered in "aliases" +node. + +Examples: + +aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; +}; + +pinctrl@80018000 { + compatible = "fsl,imx28-pinctrl", "simple-bus"; + reg = <0x80018000 2000>; + + gpio0: gpio@0 { + compatible = "fsl,imx28-gpio"; + interrupts = <127>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio@1 { + compatible = "fsl,imx28-gpio"; + interrupts = <126>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio2: gpio@2 { + compatible = "fsl,imx28-gpio"; + interrupts = <125>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio3: gpio@3 { + compatible = "fsl,imx28-gpio"; + interrupts = <124>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio4: gpio@4 { + compatible = "fsl,imx28-gpio"; + interrupts = <123>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-nmk.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-nmk.txt new file mode 100644 index 0000000000000000000000000000000000000000..8315ac7780ef96429dd4b4dc421aa8ba98558081 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-nmk.txt @@ -0,0 +1,31 @@ +Nomadik GPIO controller + +Required properties: +- compatible : Should be "st,nomadik-gpio". +- reg : Physical base address and length of the controller's registers. +- interrupts : The interrupt outputs from the controller. +- #gpio-cells : Should be two: + The first cell is the pin number. + The second cell is used to specify optional parameters: + - bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. +- gpio-controller : Marks the device node as a GPIO controller. +- interrupt-controller : Marks the device node as an interrupt controller. +- gpio-bank : Specifies which bank a controller owns. +- st,supports-sleepmode : Specifies whether controller can sleep or not + +Example: + + gpio1: gpio@8012e080 { + compatible = "st,nomadik-gpio"; + reg = <0x8012e080 0x80>; + interrupts = <0 120 0x4>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + st,supports-sleepmode; + gpio-bank = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-omap.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d950522e7fa4220f0d018636650cfb104a2c272 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-omap.txt @@ -0,0 +1,39 @@ +OMAP GPIO controller bindings + +Required properties: +- compatible: + - "ti,omap2-gpio" for OMAP2 controllers + - "ti,omap3-gpio" for OMAP3 controllers + - "ti,omap4-gpio" for OMAP4 controllers +- gpio-controller : Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + - first cell is the pin number + - second cell is used to specify optional parameters (unused) +- interrupt-controller: Mark the device node as an interrupt controller. +- #interrupt-cells : Should be 2. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + +OMAP specific properties: +- ti,hwmods: Name of the hwmod associated to the GPIO: + "gpio", being the 1-based instance number + from the HW spec. +- ti,gpio-always-on: Indicates if a GPIO bank is always powered and + so will never lose its logic state. + + +Example: + +gpio4: gpio4 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio4"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-palmas.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-palmas.txt new file mode 100644 index 0000000000000000000000000000000000000000..08b5b52a3ae05f32c717a52910d141324c69478c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-palmas.txt @@ -0,0 +1,27 @@ +Palmas GPIO controller bindings + +Required properties: +- compatible: + - "ti,palams-gpio" for palma series of the GPIO controller + - "ti,tps80036-gpio" for Palma series device TPS80036. + - "ti,tps65913-gpio" for palma series device TPS65913. + - "ti,tps65914-gpio" for palma series device TPS65914. +- #gpio-cells : Should be two. + - first cell is the gpio pin number + - second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- gpio-controller : Marks the device node as a GPIO controller. + +Note: This gpio node will be sub node of palmas node. + +Example: + palmas: tps65913@58 { + ::::::::::: + palmas_gpio: palmas_gpio { + compatible = "ti,palmas-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + ::::::::::: + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pca953x.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pca953x.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e3c550e319ad2e09b95941123f8b535ae6ac58f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pca953x.txt @@ -0,0 +1,86 @@ +* NXP PCA953x I2C GPIO multiplexer + +Required properties: + - compatible: Has to contain one of the following: + nxp,pca9505 + nxp,pca9534 + nxp,pca9535 + nxp,pca9536 + nxp,pca9537 + nxp,pca9538 + nxp,pca9539 + nxp,pca9554 + nxp,pca9555 + nxp,pca9556 + nxp,pca9557 + nxp,pca9574 + nxp,pca9575 + nxp,pca9698 + nxp,pcal6524 + nxp,pcal9555a + maxim,max7310 + maxim,max7312 + maxim,max7313 + maxim,max7315 + ti,pca6107 + ti,pca9536 + ti,tca6408 + ti,tca6416 + ti,tca6424 + ti,tca9539 + ti,tca9554 + onnn,pca9654 + exar,xra1202 + - gpio-controller: if used as gpio expander. + - #gpio-cells: if used as gpio expander. + - interrupt-controller: if to be used as interrupt expander. + - #interrupt-cells: if to be used as interrupt expander. + +Optional properties: + - interrupts: interrupt specifier for the device's interrupt output. + - reset-gpios: GPIO specification for the RESET input. This is an + active low signal to the PCA953x. + - vcc-supply: power supply regulator. + +Example: + + + gpio@20 { + compatible = "nxp,pca9505"; + reg = <0x20>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pca9505>; + gpio-controller; + #gpio-cells = <2>; + interrupt-parent = <&gpio3>; + interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + }; + + +Example with Interrupts: + + + gpio99: gpio@22 { + compatible = "nxp,pcal6524"; + reg = <0x22>; + interrupt-parent = <&gpio6>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; /* gpio6_161 */ + interrupt-controller; + #interrupt-cells = <2>; + vcc-supply = <&vdds_1v8_main>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = + "hdmi-ct-hpd", "hdmi.ls-oe", "p02", "p03", "vibra", "fault2", "p06", "p07", + "en-usb", "en-host1", "en-host2", "chg-int", "p14", "p15", "mic-int", "en-modem", + "shdn-hs-amp", "chg-status+red", "green", "blue", "en-esata", "fault1", "p26", "p27"; + }; + + ts3a227@3b { + compatible = "ti,ts3a227e"; + reg = <0x3b>; + interrupt-parent = <&gpio99>; + interrupts = <14 IRQ_TYPE_EDGE_RISING>; + ti,micbias = <0>; /* 2.1V */ + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pcf857x.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pcf857x.txt new file mode 100644 index 0000000000000000000000000000000000000000..a482455a205b0855d1cca8e5c0d3ff7d7999bfb4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pcf857x.txt @@ -0,0 +1,69 @@ +* PCF857x-compatible I/O expanders + +The PCF857x-compatible chips have "quasi-bidirectional" I/O lines that can be +driven high by a pull-up current source or driven low to ground. This combines +the direction and output level into a single bit per line, which can't be read +back. We can't actually know at initialization time whether a line is configured +(a) as output and driving the signal low/high, or (b) as input and reporting a +low/high value, without knowing the last value written since the chip came out +of reset (if any). The only reliable solution for setting up line direction is +thus to do it explicitly. + +Required Properties: + + - compatible: should be one of the following. + - "maxim,max7328": For the Maxim MAX7378 + - "maxim,max7329": For the Maxim MAX7329 + - "nxp,pca8574": For the NXP PCA8574 + - "nxp,pca8575": For the NXP PCA8575 + - "nxp,pca9670": For the NXP PCA9670 + - "nxp,pca9671": For the NXP PCA9671 + - "nxp,pca9672": For the NXP PCA9672 + - "nxp,pca9673": For the NXP PCA9673 + - "nxp,pca9674": For the NXP PCA9674 + - "nxp,pca9675": For the NXP PCA9675 + - "nxp,pcf8574": For the NXP PCF8574 + - "nxp,pcf8574a": For the NXP PCF8574A + - "nxp,pcf8575": For the NXP PCF8575 + + - reg: I2C slave address. + + - gpio-controller: Marks the device node as a gpio controller. + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second + cell specifies GPIO flags, as defined in . Only the + GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + +Optional Properties: + + - lines-initial-states: Bitmask that specifies the initial state of each + line. When a bit is set to zero, the corresponding line will be initialized to + the input (pulled-up) state. When the bit is set to one, the line will be + initialized the low-level output state. If the property is not specified + all lines will be initialized to the input state. + + The I/O expander can detect input state changes, and thus optionally act as + an interrupt controller. When the expander interrupt line is connected all the + following properties must be set. For more information please see the + interrupt controller device tree bindings documentation available at + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. + + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: Number of cells to encode an interrupt source, shall be 2. + - interrupts: Interrupt specifier for the controllers interrupt. + + +Please refer to gpio.txt in this directory for details of the common GPIO +bindings used by client devices. + +Example: PCF8575 I/O expander node + + pcf8575: gpio@20 { + compatible = "nxp,pcf8575"; + reg = <0x20>; + interrupt-parent = <&irqpin2>; + interrupts = <3 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pisosr.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pisosr.txt new file mode 100644 index 0000000000000000000000000000000000000000..414a01cdf715ba490243c45843ed23c7c319072f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-pisosr.txt @@ -0,0 +1,34 @@ +Generic Parallel-in/Serial-out Shift Register GPIO Driver + +This binding describes generic parallel-in/serial-out shift register +devices that can be used for GPI (General Purpose Input). This includes +SN74165 serial-out shift registers and the SN65HVS88x series of +industrial serializers. + +Required properties: + - compatible : Should be "pisosr-gpio". + - gpio-controller : Marks the device node as a GPIO controller. + - #gpio-cells : Should be two. For consumer use see gpio.txt. + +Optional properties: + - ngpios : Number of used GPIO lines (0..n-1), default is 8. + - load-gpios : GPIO pin specifier attached to load enable, this + pin is pulsed before reading from the device to + load input pin values into the the device. + +For other required and optional properties of SPI slave +nodes please refer to ../spi/spi-bus.txt. + +Example: + + gpio@0 { + compatible = "ti,sn65hvs882", "pisosr-gpio"; + gpio-controller; + #gpio-cells = <2>; + + load-gpios = <&gpio2 23 GPIO_ACTIVE_LOW>; + + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpol; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-samsung.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-samsung.txt new file mode 100644 index 0000000000000000000000000000000000000000..5375625e8cd2bdfb07e7a935286bd1d50eb873b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-samsung.txt @@ -0,0 +1,41 @@ +Samsung Exynos4 GPIO Controller + +Required properties: +- compatible: Compatible property value should be "samsung,exynos4-gpio>". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- #gpio-cells: Should be 4. The syntax of the gpio specifier used by client nodes + should be the following with values derived from the SoC user manual. + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [mux function] + [flags and pull up/down] + [drive strength]> + + Values for gpio specifier: + - Pin number: is a value between 0 to 7. + - Flags and Pull Up/Down: 0 - Pull Up/Down Disabled. + 1 - Pull Down Enabled. + 3 - Pull Up Enabled. + Bit 16 (0x00010000) - Input is active low. + - Drive Strength: 0 - 1x, + 1 - 3x, + 2 - 2x, + 3 - 4x + +- gpio-controller: Specifies that the node is a gpio controller. +- #address-cells: should be 1. +- #size-cells: should be 1. + +Example: + + gpa0: gpio-controller@11400000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "samsung,exynos4-gpio"; + reg = <0x11400000 0x20>; + #gpio-cells = <4>; + gpio-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-sprd.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-sprd.txt new file mode 100644 index 0000000000000000000000000000000000000000..eca97d45388f574048a3c24be719822754e9755c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-sprd.txt @@ -0,0 +1,28 @@ +Spreadtrum GPIO controller bindings + +The controller's registers are organized as sets of sixteen 16-bit +registers with each set controlling a bank of up to 16 pins. A single +interrupt is shared for all of the banks handled by the controller. + +Required properties: +- compatible: Should be "sprd,sc9860-gpio". +- reg: Define the base and range of the I/O address space containing +the GPIO controller registers. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be <2>. The first cell is the gpio number and +the second cell is used to specify optional parameters. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be <2>. Specifies the number of cells needed +to encode interrupt source. +- interrupts: Should be the port interrupt shared by all the gpios. + +Example: + ap_gpio: gpio@40280000 { + compatible = "sprd,sc9860-gpio"; + reg = <0 0x40280000 0 0x1000>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stericsson-coh901.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stericsson-coh901.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd665b44d76741a763559be360e8d7b236aab4cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stericsson-coh901.txt @@ -0,0 +1,7 @@ +ST-Ericsson COH 901 571/3 GPIO controller + +Required properties: +- compatible: Compatible property value should be "stericsson,gpio-coh901" +- reg: Physical base address of the controller and length of memory mapped + region. +- interrupts: the 0...n interrupts assigned to the different GPIO ports/banks. diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stmpe.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stmpe.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0e4cf8852139eea53f193c9e6f961544d1f026c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stmpe.txt @@ -0,0 +1,18 @@ +STMPE gpio +---------- + +Required properties: + - compatible: "st,stmpe-gpio" + +Optional properties: + - st,norequest-mask: bitmask specifying which GPIOs should _not_ be requestable + due to different usage (e.g. touch, keypad) + +Node name must be stmpe_gpio and should be child node of stmpe node to which it +belongs. + +Example: + stmpe_gpio { + compatible = "st,stmpe-gpio"; + st,norequest-mask = <0x20>; //gpio 5 can't be used + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stp-xway.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stp-xway.txt new file mode 100644 index 0000000000000000000000000000000000000000..78458adbf4b700675a2982ea37170e6d4d160a39 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-stp-xway.txt @@ -0,0 +1,42 @@ +Lantiq SoC Serial To Parallel (STP) GPIO controller + +The Serial To Parallel (STP) is found on MIPS based Lantiq socs. It is a +peripheral controller used to drive external shift register cascades. At most +3 groups of 8 bits can be driven. The hardware is able to allow the DSL modem +to drive the 2 LSBs of the cascade automatically. + + +Required properties: +- compatible : Should be "lantiq,gpio-stp-xway" +- reg : Address and length of the register set for the device +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify optional parameters (currently + unused). +- gpio-controller : Marks the device node as a gpio controller. + +Optional properties: +- lantiq,shadow : The default value that we shall assume as already set on the + shift register cascade. +- lantiq,groups : Set the 3 bit mask to select which of the 3 groups are enabled + in the shift register cascade. +- lantiq,dsl : The dsl core can control the 2 LSBs of the gpio cascade. This 2 bit + property can enable this feature. +- lantiq,phy1 : The gphy1 core can control 3 bits of the gpio cascade. +- lantiq,phy2 : The gphy2 core can control 3 bits of the gpio cascade. +- lantiq,rising : use rising instead of falling edge for the shift register + +Example: + +gpio1: stp@e100bb0 { + compatible = "lantiq,gpio-stp-xway"; + reg = <0xE100BB0 0x40>; + #gpio-cells = <2>; + gpio-controller; + + lantiq,shadow = <0xffff>; + lantiq,groups = <0x7>; + lantiq,dsl = <0x3>; + lantiq,phy1 = <0x7>; + lantiq,phy2 = <0x7>; + /* lantiq,rising; */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-thunderx.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-thunderx.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f883ae29d116887e702ead20b26a25f9d2349d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-thunderx.txt @@ -0,0 +1,27 @@ +Cavium ThunderX/OCTEON-TX GPIO controller bindings + +Required Properties: +- reg: The controller bus address. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Must be 2. + - First cell is the GPIO pin number relative to the controller. + - Second cell is a standard generic flag bitfield as described in gpio.txt. + +Optional Properties: +- compatible: "cavium,thunder-8890-gpio", unused as PCI driver binding is used. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Must be present and have value of 2 if + "interrupt-controller" is present. + - First cell is the GPIO pin number relative to the controller. + - Second cell is triggering flags as defined in interrupts.txt. + +Example: + +gpio_6_0: gpio@6,0 { + compatible = "cavium,thunder-8890-gpio"; + reg = <0x3000 0 0 0 0>; /* DEVFN = 0x30 (6:0) */ + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-tpic2810.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-tpic2810.txt new file mode 100644 index 0000000000000000000000000000000000000000..1afc2de7a537d5a5d4b304b09c8441cc29dec220 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-tpic2810.txt @@ -0,0 +1,16 @@ +TPIC2810 GPIO controller bindings + +Required properties: + - compatible : Should be "ti,tpic2810". + - reg : The I2C address of the device + - gpio-controller : Marks the device node as a GPIO controller. + - #gpio-cells : Should be two. For consumer use see gpio.txt. + +Example: + + gpio@60 { + compatible = "ti,tpic2810"; + reg = <0x60>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ts4800.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ts4800.txt new file mode 100644 index 0000000000000000000000000000000000000000..92ea9c8f6399e2c67bd7927a37e7672dc18e5602 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ts4800.txt @@ -0,0 +1,20 @@ +* TS-4800 FPGA's GPIO controller bindings + +Required properties: +- compatible: Must be "technologic,ts4800-gpio". +- #gpio-cells: Should be two. The first cell is the pin number. +- reg: Physical base address of the controller and length + of memory mapped region. + +Optional property: +- ngpios: See "gpio.txt" + +Example: + +gpio1: gpio { + compatible = "technologic,ts4800-gpio"; + reg = <0x10020 0x6>; + ngpios = <8>; + gpio-controller; + #gpio-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ts4900.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ts4900.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f8e71b1ab2a09277190636f593b92cc4980beff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-ts4900.txt @@ -0,0 +1,30 @@ +* Technologic Systems I2C-FPGA's GPIO controller bindings + +This bindings describes the GPIO controller for Technologic's FPGA core. +TS-4900's FPGA encodes the GPIO state on 3 bits, whereas the TS-7970's FPGA +uses 2 bits: it doesn't use a dedicated input bit. + +Required properties: +- compatible: Should be one of the following + "technologic,ts4900-gpio" + "technologic,ts7970-gpio" +- reg: Physical base address of the controller and length + of memory mapped region. +- #gpio-cells: Should be two. The first cell is the pin number. +- gpio-controller: Marks the device node as a gpio controller. + +Optional property: +- ngpios: Number of GPIOs this controller is instantiated with, + the default is 32. See gpio.txt for more details. + +Example: + +&i2c2 { + gpio8: gpio@28 { + compatible = "technologic,ts4900-gpio"; + reg = <0x28>; + #gpio-cells = <2>; + gpio-controller; + ngpios = <32>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-twl4030.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-twl4030.txt new file mode 100644 index 0000000000000000000000000000000000000000..66788fda1db383491411364f197a39f7233f4e13 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-twl4030.txt @@ -0,0 +1,29 @@ +twl4030 GPIO controller bindings + +Required properties: +- compatible: + - "ti,twl4030-gpio" for twl4030 GPIO controller +- #gpio-cells : Should be two. + - first cell is the pin number + - second cell is used to specify optional parameters (unused) +- gpio-controller : Marks the device node as a GPIO controller. +- #interrupt-cells : Should be 2. +- interrupt-controller: Mark the device node as an interrupt controller + The first cell is the GPIO number. + The second cell is not used. +- ti,use-leds : Enables LEDA and LEDB outputs if set +- ti,debounce : if n-th bit is set, debounces GPIO-n +- ti,mmc-cd : if n-th bit is set, GPIO-n controls VMMC(n+1) +- ti,pullups : if n-th bit is set, set a pullup on GPIO-n +- ti,pulldowns : if n-th bit is set, set a pulldown on GPIO-n + +Example: + +twl_gpio: gpio { + compatible = "ti,twl4030-gpio"; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; + ti,use-leds; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-uniphier.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-uniphier.txt new file mode 100644 index 0000000000000000000000000000000000000000..f281f12dac18d3cfe2b337b025a17372816b8e2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-uniphier.txt @@ -0,0 +1,51 @@ +UniPhier GPIO controller + +Required properties: +- compatible: Should be "socionext,uniphier-gpio". +- reg: Specifies offset and length of the register set for the device. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be 2. The first cell is the pin number and the second + cell is used to specify optional parameters. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be 2. The first cell defines the interrupt number. + The second cell bits[3:0] is used to specify trigger type as follows: + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + Valid combinations are 1, 2, 3, 4, 8. +- ngpios: Specifies the number of GPIO lines. +- gpio-ranges: Mapping to pin controller pins (as described in gpio.txt) +- socionext,interrupt-ranges: Specifies an interrupt number mapping between + this GPIO controller and its interrupt parent, in the form of arbitrary + number of triplets. + +Optional properties: +- gpio-ranges-group-names: Used for named gpio ranges (as described in gpio.txt) + +Example: + gpio: gpio@55000000 { + compatible = "socionext,uniphier-gpio"; + reg = <0x55000000 0x200>; + interrupt-parent = <&aidet>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 0 0>; + gpio-ranges-group-names = "gpio_range"; + ngpios = <248>; + socionext,interrupt-ranges = <0 48 16>, <16 154 5>, <21 217 3>; + }; + +Consumer Example: + + sdhci0_pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio UNIPHIER_GPIO_PORT(29, 4) GPIO_ACTIVE_LOW>; + }; + +Please note UNIPHIER_GPIO_PORT(29, 4) represents PORT294 in the SoC document. +Unfortunately, only the one's place is octal in the port numbering. (That is, +PORT 8, 9, 18, 19, 28, 29, ... are missing.) UNIPHIER_GPIO_PORT() is a helper +macro to calculate 29 * 8 + 4. diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-vf610.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-vf610.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ccbae44019cca07ce6627ebd5ed5f496d4b879d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-vf610.txt @@ -0,0 +1,57 @@ +* Freescale VF610 PORT/GPIO module + +The Freescale PORT/GPIO modules are two adjacent modules providing GPIO +functionality. Each pair serves 32 GPIOs. The VF610 has 5 instances of +each, and each PORT module has its own interrupt. + +Required properties for GPIO node: +- compatible : Should be "fsl,-gpio", below is supported list: + "fsl,vf610-gpio" + "fsl,imx7ulp-gpio" +- reg : The first reg tuple represents the PORT module, the second tuple + the GPIO module. +- interrupts : Should be the port interrupt shared by all 32 pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells : Should be 2. The first cell is the GPIO number. + The second cell bits[3:0] is used to specify trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + +Note: Each GPIO port should have an alias correctly numbered in "aliases" +node. + +Examples: + +aliases { + gpio0 = &gpio1; + gpio1 = &gpio2; +}; + +gpio1: gpio@40049000 { + compatible = "fsl,vf610-gpio"; + reg = <0x40049000 0x1000 0x400ff000 0x40>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 0 32>; +}; + +gpio2: gpio@4004a000 { + compatible = "fsl,vf610-gpio"; + reg = <0x4004a000 0x1000 0x400ff040 0x40>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&iomuxc 0 32 32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xgene-sb.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xgene-sb.txt new file mode 100644 index 0000000000000000000000000000000000000000..e90fb987e25faf81b7d4545664dc4bdbf242246c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xgene-sb.txt @@ -0,0 +1,64 @@ +APM X-Gene Standby GPIO controller bindings + +This is a gpio controller in the standby domain. It also supports interrupt in +some particular pins which are sourced to its parent interrupt controller +as diagram below: + +-----------------+ + | X-Gene standby | + | GPIO controller +------ GPIO_0 ++------------+ | | ... +| Parent IRQ | EXT_INT_0 | +------ GPIO_8/EXT_INT_0 +| controller | (SPI40) | | ... +| (GICv2) +--------------+ +------ GPIO_[N+8]/EXT_INT_N +| | ... | | +| | EXT_INT_N | +------ GPIO_[N+9] +| | (SPI[40 + N])| | ... +| +--------------+ +------ GPIO_MAX ++------------+ +-----------------+ + +Required properties: +- compatible: "apm,xgene-gpio-sb" for the X-Gene Standby GPIO controller +- reg: Physical base address and size of the controller's registers +- #gpio-cells: Should be two. + - first cell is the pin number + - second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- gpio-controller: Marks the device node as a GPIO controller. +- interrupts: The EXT_INT_0 parent interrupt resource must be listed first. +- interrupt-cells: Should be two. + - first cell is 0-N coresponding for EXT_INT_0 to EXT_INT_N. + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as an interrupt controller. +- apm,nr-gpios: Optional, specify number of gpios pin. +- apm,nr-irqs: Optional, specify number of interrupt pins. +- apm,irq-start: Optional, specify lowest gpio pin support interrupt. + +Example: + sbgpio: gpio@17001000{ + compatible = "apm,xgene-gpio-sb"; + reg = <0x0 0x17001000 0x0 0x400>; + #gpio-cells = <2>; + gpio-controller; + interrupts = <0x0 0x28 0x1>, + <0x0 0x29 0x1>, + <0x0 0x2a 0x1>, + <0x0 0x2b 0x1>, + <0x0 0x2c 0x1>, + <0x0 0x2d 0x1>; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + interrupt-controller; + apm,nr-gpios = <22>; + apm,nr-irqs = <6>; + apm,irq-start = <8>; + }; + + testuser { + compatible = "example,testuser"; + /* Use the GPIO_13/EXT_INT_5 line as an active high triggered + * level interrupt + */ + interrupts = <5 4>; + interrupt-parent = <&sbgpio>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xgene.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xgene.txt new file mode 100644 index 0000000000000000000000000000000000000000..86dbb05e77584d1e63061bd874a557343afe478b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xgene.txt @@ -0,0 +1,22 @@ +APM X-Gene SoC GPIO controller bindings + +This is a gpio controller that is part of the flash controller. +This gpio controller controls a total of 48 gpios. + +Required properties: +- compatible: "apm,xgene-gpio" for X-Gene GPIO controller +- reg: Physical base address and size of the controller's registers +- #gpio-cells: Should be two. + - first cell is the pin number + - second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- gpio-controller: Marks the device node as a GPIO controller. + +Example: + gpio0: gpio0@1701c000 { + compatible = "apm,xgene-gpio"; + reg = <0x0 0x1701c000 0x0 0x40>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xilinx.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xilinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..08eed2335db022ef4bdec88680bd114a60d2454c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xilinx.txt @@ -0,0 +1,46 @@ +Xilinx plb/axi GPIO controller + +Dual channel GPIO controller with configurable number of pins +(from 1 to 32 per channel). Every pin can be configured as +input/output/tristate. Both channels share the same global IRQ but +local interrupts can be enabled on channel basis. + +Required properties: +- compatible : Should be "xlnx,xps-gpio-1.00.a" +- reg : Address and length of the register set for the device +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). +- gpio-controller : Marks the device node as a GPIO controller. + +Optional properties: +- interrupts : Interrupt mapping for GPIO IRQ. +- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input +- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1 +- xlnx,gpio-width : gpio width +- xlnx,tri-default : if n-th bit is 1, GPIO-n is in tristate mode +- xlnx,is-dual : if 1, controller also uses the second channel +- xlnx,all-inputs-2 : as above but for the second channel +- xlnx,dout-default-2 : as above but the second channel +- xlnx,gpio2-width : as above but for the second channel +- xlnx,tri-default-2 : as above but for the second channel + + +Example: +gpio: gpio@40000000 { + #gpio-cells = <2>; + compatible = "xlnx,xps-gpio-1.00.a"; + gpio-controller ; + interrupt-parent = <µblaze_0_intc>; + interrupts = < 6 2 >; + reg = < 0x40000000 0x10000 >; + xlnx,all-inputs = <0x0>; + xlnx,all-inputs-2 = <0x0>; + xlnx,dout-default = <0x0>; + xlnx,dout-default-2 = <0x0>; + xlnx,gpio-width = <0x2>; + xlnx,gpio2-width = <0x2>; + xlnx,interrupt-present = <0x1>; + xlnx,is-dual = <0x1>; + xlnx,tri-default = <0xffffffff>; + xlnx,tri-default-2 = <0xffffffff>; +} ; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xlp.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xlp.txt new file mode 100644 index 0000000000000000000000000000000000000000..47fc64922fe07b0dd4c6fba11fd55a22e721e0b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xlp.txt @@ -0,0 +1,49 @@ +Netlogic XLP Family GPIO +======================== + +This GPIO driver is used for following Netlogic XLP SoCs: + XLP832, XLP316, XLP208, XLP980, XLP532 +This GPIO driver is also compatible with GPIO controller found on +Broadcom Vulcan ARM64. + +Required properties: +------------------- + +- compatible: Should be one of the following: + - "netlogic,xlp832-gpio": For Netlogic XLP832 + - "netlogic,xlp316-gpio": For Netlogic XLP316 + - "netlogic,xlp208-gpio": For Netlogic XLP208 + - "netlogic,xlp980-gpio": For Netlogic XLP980 + - "netlogic,xlp532-gpio": For Netlogic XLP532 + - "brcm,vulcan-gpio": For Broadcom Vulcan ARM64 +- reg: Physical base address and length of the controller's registers. +- #gpio-cells: Should be two. The first cell is the pin number and the second + cell is used to specify optional parameters (currently unused). +- gpio-controller: Marks the device node as a GPIO controller. +- nr-gpios: Number of GPIO pins supported by the controller. +- interrupt-cells: Should be two. The first cell is the GPIO Number. The + second cell is used to specify flags. The following subset of flags is + supported: + - trigger type: + 1 = low to high edge triggered. + 2 = high to low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. +- interrupts: Interrupt number for this device. +- interrupt-controller: Identifies the node as an interrupt controller. + +Example: + + gpio: xlp_gpio@34000 { + compatible = "netlogic,xlp316-gpio"; + reg = <0 0x34100 0x1000 + 0 0x35100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + nr-gpios = <57>; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xra1403.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xra1403.txt new file mode 100644 index 0000000000000000000000000000000000000000..e13cc399b363f24aae0083fc34b09bd434aa78cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-xra1403.txt @@ -0,0 +1,46 @@ +GPIO Driver for XRA1403 16-BIT GPIO Expander With Reset Input from EXAR + +The XRA1403 is an 16-bit GPIO expander with an SPI interface. Features available: + - Individually programmable inputs: + - Internal pull-up resistors + - Polarity inversion + - Individual interrupt enable + - Rising edge and/or Falling edge interrupt + - Input filter + - Individually programmable outputs + - Output Level Control + - Output Three-State Control + +Properties +---------- +Check documentation for SPI and GPIO controllers regarding properties needed to configure the node. + + - compatible = "exar,xra1403". + - reg - SPI id of the device. + - gpio-controller - marks the node as gpio. + - #gpio-cells - should be two where the first cell is the pin number + and the second one is used for optional parameters. + +Optional properties: +------------------- + - reset-gpios: in case available used to control the device reset line. + - interrupt-controller - marks the node as interrupt controller. + - #interrupt-cells - should be two and represents the number of cells + needed to encode interrupt source. + +Example +-------- + + gpioxra0: gpio@2 { + compatible = "exar,xra1403"; + reg = <2>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; + spi-max-frequency = <1000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-zevio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-zevio.txt new file mode 100644 index 0000000000000000000000000000000000000000..a37bd9ae27307b36f374179918edcc8bfab44d6b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-zevio.txt @@ -0,0 +1,16 @@ +Zevio GPIO controller + +Required properties: +- compatible: Should be "lsi,zevio-gpio" +- reg: Address and length of the register set for the device +- #gpio-cells: Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). +- gpio-controller: Marks the device node as a GPIO controller. + +Example: + gpio: gpio@90000000 { + compatible = "lsi,zevio-gpio"; + reg = <0x90000000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-zynq.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-zynq.txt new file mode 100644 index 0000000000000000000000000000000000000000..4fa4eb5507cdf8469f08183b8e934816e71570bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio-zynq.txt @@ -0,0 +1,34 @@ +Xilinx Zynq GPIO controller Device Tree Bindings +------------------------------------------- + +Required properties: +- #gpio-cells : Should be two + - First cell is the GPIO line number + - Second cell is used to specify optional + parameters (unused) +- compatible : Should be "xlnx,zynq-gpio-1.0" or "xlnx,zynqmp-gpio-1.0" +- clocks : Clock specifier (see clock bindings for details) +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt specifier (see interrupt bindings for + details) +- interrupt-controller : Marks the device node as an interrupt controller. +- #interrupt-cells : Should be 2. The first cell is the GPIO number. + The second cell bits[3:0] is used to specify trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. +- reg : Address and length of the register set for the device + +Example: + gpio@e000a000 { + #gpio-cells = <2>; + compatible = "xlnx,zynq-gpio-1.0"; + clocks = <&clkc 42>; + gpio-controller; + interrupt-parent = <&intc>; + interrupts = <0 20 4>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0xe000a000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7c31de2936202aa2fa9370934e6982ce5222deb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio.txt @@ -0,0 +1,311 @@ +Specifying GPIO information for devices +============================================ + +1) gpios property +----------------- + +Nodes that makes use of GPIOs should specify them using one or more +properties, each containing a 'gpio-list': + + gpio-list ::= [gpio-list] + single-gpio ::= + gpio-phandle : phandle to gpio controller node + gpio-specifier : Array of #gpio-cells specifying specific gpio + (controller specific) + +GPIO properties should be named "[-]gpios", with being the purpose +of this GPIO for the device. While a non-existent is considered valid +for compatibility reasons (resolving to the "gpios" property), it is not allowed +for new bindings. Also, GPIO properties named "[-]gpio" are valid and old +bindings use it, but are only supported for compatibility reasons and should not +be used for newer bindings since it has been deprecated. + +GPIO properties can contain one or more GPIO phandles, but only in exceptional +cases should they contain more than one. If your device uses several GPIOs with +distinct functions, reference each of them under its own property, giving it a +meaningful name. The only case where an array of GPIOs is accepted is when +several GPIOs serve the same function (e.g. a parallel data line). + +The exact purpose of each gpios property must be documented in the device tree +binding of the device. + +The following example could be used to describe GPIO pins used as device enable +and bit-banged data signals: + + gpio1: gpio1 { + gpio-controller + #gpio-cells = <2>; + }; + gpio2: gpio2 { + gpio-controller + #gpio-cells = <1>; + }; + [...] + + enable-gpios = <&gpio2 2>; + data-gpios = <&gpio1 12 0>, + <&gpio1 13 0>, + <&gpio1 14 0>, + <&gpio1 15 0>; + +Note that gpio-specifier length is controller dependent. In the +above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2 +only uses one. + +gpio-specifier may encode: bank, pin position inside the bank, +whether pin is open-drain and whether pin is logically inverted. + +Exact meaning of each specifier cell is controller specific, and must +be documented in the device tree binding for the device. + +Most controllers are however specifying a generic flag bitfield +in the last cell, so for these, use the macros defined in +include/dt-bindings/gpio/gpio.h whenever possible: + +Example of a node using GPIOs: + + node { + enable-gpios = <&qe_pio_e 18 GPIO_ACTIVE_HIGH>; + }; + +GPIO_ACTIVE_HIGH is 0, so in this example gpio-specifier is "18 0" and encodes +GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller. + +Optional standard bitfield specifiers for the last cell: + +- Bit 0: 0 means active high, 1 means active low +- Bit 1: 0 mean push-pull wiring, see: + https://en.wikipedia.org/wiki/Push-pull_output + 1 means single-ended wiring, see: + https://en.wikipedia.org/wiki/Single-ended_triode +- Bit 2: 0 means open-source, 1 means open drain, see: + https://en.wikipedia.org/wiki/Open_collector +- Bit 3: 0 means the output should be maintained during sleep/low-power mode + 1 means the output state can be lost during sleep/low-power mode + +1.1) GPIO specifier best practices +---------------------------------- + +A gpio-specifier should contain a flag indicating the GPIO polarity; active- +high or active-low. If it does, the following best practices should be +followed: + +The gpio-specifier's polarity flag should represent the physical level at the +GPIO controller that achieves (or represents, for inputs) a logically asserted +value at the device. The exact definition of logically asserted should be +defined by the binding for the device. If the board inverts the signal between +the GPIO controller and the device, then the gpio-specifier will represent the +opposite physical level than the signal at the device's pin. + +When the device's signal polarity is configurable, the binding for the +device must either: + +a) Define a single static polarity for the signal, with the expectation that +any software using that binding would statically program the device to use +that signal polarity. + +The static choice of polarity may be either: + +a1) (Preferred) Dictated by a binding-specific DT property. + +or: + +a2) Defined statically by the DT binding itself. + +In particular, the polarity cannot be derived from the gpio-specifier, since +that would prevent the DT from separately representing the two orthogonal +concepts of configurable signal polarity in the device, and possible board- +level signal inversion. + +or: + +b) Pick a single option for device signal polarity, and document this choice +in the binding. The gpio-specifier should represent the polarity of the signal +(at the GPIO controller) assuming that the device is configured for this +particular signal polarity choice. If software chooses to program the device +to generate or receive a signal of the opposite polarity, software will be +responsible for correctly interpreting (inverting) the GPIO signal at the GPIO +controller. + +2) gpio-controller nodes +------------------------ + +Every GPIO controller node must contain both an empty "gpio-controller" +property, and a #gpio-cells integer property, which indicates the number of +cells in a gpio-specifier. + +Some system-on-chips (SoCs) use the concept of GPIO banks. A GPIO bank is an +instance of a hardware IP core on a silicon die, usually exposed to the +programmer as a coherent range of I/O addresses. Usually each such bank is +exposed in the device tree as an individual gpio-controller node, reflecting +the fact that the hardware was synthesized by reusing the same IP block a +few times over. + +Optionally, a GPIO controller may have a "ngpios" property. This property +indicates the number of in-use slots of available slots for GPIOs. The +typical example is something like this: the hardware register is 32 bits +wide, but only 18 of the bits have a physical counterpart. The driver is +generally written so that all 32 bits can be used, but the IP block is reused +in a lot of designs, some using all 32 bits, some using 18 and some using +12. In this case, setting "ngpios = <18>;" informs the driver that only the +first 18 GPIOs, at local offset 0 .. 17, are in use. + +If these GPIOs do not happen to be the first N GPIOs at offset 0...N-1, an +additional set of tuples is needed to specify which GPIOs are unusable, with +the gpio-reserved-ranges binding. This property indicates the start and size +of the GPIOs that can't be used. + +Optionally, a GPIO controller may have a "gpio-line-names" property. This is +an array of strings defining the names of the GPIO lines going out of the +GPIO controller. This name should be the most meaningful producer name +for the system, such as a rail name indicating the usage. Package names +such as pin name are discouraged: such lines have opaque names (since they +are by definition generic purpose) and such names are usually not very +helpful. For example "MMC-CD", "Red LED Vdd" and "ethernet reset" are +reasonable line names as they describe what the line is used for. "GPIO0" +is not a good name to give to a GPIO line. Placeholders are discouraged: +rather use the "" (blank string) if the use of the GPIO line is undefined +in your design. The names are assigned starting from line offset 0 from +left to right from the passed array. An incomplete array (where the number +of passed named are less than ngpios) will still be used up until the last +provided valid line index. + +Example: + +gpio-controller@00000000 { + compatible = "foo"; + reg = <0x00000000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <18>; + gpio-reserved-ranges = <0 4>, <12 2>; + gpio-line-names = "MMC-CD", "MMC-WP", "VDD eth", "RST eth", "LED R", + "LED G", "LED B", "Col A", "Col B", "Col C", "Col D", + "Row A", "Row B", "Row C", "Row D", "NMI button", + "poweroff", "reset"; +} + +The GPIO chip may contain GPIO hog definitions. GPIO hogging is a mechanism +providing automatic GPIO request and configuration as part of the +gpio-controller's driver probe function. + +Each GPIO hog definition is represented as a child node of the GPIO controller. +Required properties: +- gpio-hog: A property specifying that this child node represents a GPIO hog. +- gpios: Store the GPIO information (id, flags, ...) for each GPIO to + affect. Shall contain an integer multiple of the number of cells + specified in its parent node (GPIO controller node). +Only one of the following properties scanned in the order shown below. +This means that when multiple properties are present they will be searched +in the order presented below and the first match is taken as the intended +configuration. +- input: A property specifying to set the GPIO direction as input. +- output-low A property specifying to set the GPIO direction as output with + the value low. +- output-high A property specifying to set the GPIO direction as output with + the value high. + +Optional properties: +- line-name: The GPIO label name. If not present the node name is used. + +Example of two SOC GPIO banks defined as gpio-controller nodes: + + qe_pio_a: gpio-controller@1400 { + compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + #gpio-cells = <2>; + + line_b { + gpio-hog; + gpios = <6 0>; + output-low; + line-name = "foo-bar-gpio"; + }; + }; + + qe_pio_e: gpio-controller@1460 { + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + #gpio-cells = <2>; + }; + +2.1) gpio- and pin-controller interaction +----------------------------------------- + +Some or all of the GPIOs provided by a GPIO controller may be routed to pins +on the package via a pin controller. This allows muxing those pins between +GPIO and other functions. + +It is useful to represent which GPIOs correspond to which pins on which pin +controllers. The gpio-ranges property described below represents this, and +contains information structures as follows: + + gpio-range-list ::= [gpio-range-list] + single-gpio-range ::= | + numeric-gpio-range ::= + + named-gpio-range ::= '<0 0>' + pinctrl-phandle : phandle to pin controller node + gpio-base : Base GPIO ID in the GPIO controller + pinctrl-base : Base pinctrl pin ID in the pin controller + count : The number of GPIOs/pins in this range + +The "pin controller node" mentioned above must conform to the bindings +described in ../pinctrl/pinctrl-bindings.txt. + +In case named gpio ranges are used (ranges with both and + set to 0), the property gpio-ranges-group-names contains one string +for every single-gpio-range in gpio-ranges: + gpiorange-names-list ::= [gpiorange-names-list] + gpiorange-name : Name of the pingroup associated to the GPIO range in + the respective pin controller. + +Elements of gpiorange-names-list corresponding to numeric ranges contain +the empty string. Elements of gpiorange-names-list corresponding to named +ranges contain the name of a pin group defined in the respective pin +controller. The number of pins/GPIOs in the range is the number of pins in +that pin group. + +Previous versions of this binding required all pin controller nodes that +were referenced by any gpio-ranges property to contain a property named +#gpio-range-cells with value <3>. This requirement is now deprecated. +However, that property may still exist in older device trees for +compatibility reasons, and would still be required even in new device +trees that need to be compatible with older software. + +Example 1: + + qe_pio_e: gpio-controller@1460 { + #gpio-cells = <2>; + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>; + }; + +Here, a single GPIO controller has GPIOs 0..9 routed to pin controller +pinctrl1's pins 20..29, and GPIOs 10..29 routed to pin controller pinctrl2's +pins 50..69. + +Example 2: + + gpio_pio_i: gpio-controller@14b0 { + #gpio-cells = <2>; + compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank"; + reg = <0x1480 0x18>; + gpio-controller; + gpio-ranges = <&pinctrl1 0 20 10>, + <&pinctrl2 10 0 0>, + <&pinctrl1 15 0 10>, + <&pinctrl2 25 0 0>; + gpio-ranges-group-names = "", + "foo", + "", + "bar"; + }; + +Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO +ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2 +are named "foo" and "bar". diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_atmel.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_atmel.txt new file mode 100644 index 0000000000000000000000000000000000000000..29416f9c3220f575a2191f849c6407aba3be2805 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_atmel.txt @@ -0,0 +1,31 @@ +* Atmel GPIO controller (PIO) + +Required properties: +- compatible: "atmel,-gpio", where is at91rm9200 or at91sam9x5. +- reg: Should contain GPIO controller registers location and length +- interrupts: Should be the port interrupt shared by all the pins. +- #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify optional parameters to declare if the GPIO + is active high or low. See gpio.txt. +- gpio-controller: Marks the device node as a GPIO controller. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. The first cell is the pin number and the + second cell is used to specify irq type flags, see the two cell description + in interrupt-controller/interrupts.txt for details. + +optional properties: +- #gpio-lines: Number of gpio if absent 32. + + +Example: + pioA: gpio@fffff200 { + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff200 0x100>; + interrupts = <2 4>; + #gpio-cells = <2>; + gpio-controller; + #gpio-lines = <19>; + interrupt-controller; + #interrupt-cells = <2>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_lpc32xx.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_lpc32xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..49819367a011f479dbce58ffdaa4017d672869d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_lpc32xx.txt @@ -0,0 +1,43 @@ +NXP LPC32xx SoC GPIO controller + +Required properties: +- compatible: must be "nxp,lpc3220-gpio" +- reg: Physical base address and length of the controller's registers. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be 3: + 1) bank: + 0: GPIO P0 + 1: GPIO P1 + 2: GPIO P2 + 3: GPIO P3 + 4: GPI P3 + 5: GPO P3 + 2) pin number + 3) optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- reg: Index of the GPIO group + +Example: + + gpio: gpio@40028000 { + compatible = "nxp,lpc3220-gpio"; + reg = <0x40028000 0x1000>; + gpio-controller; + #gpio-cells = <3>; /* bank, pin, flags */ + }; + + leds { + compatible = "gpio-leds"; + + led0 { + gpios = <&gpio 5 1 1>; /* GPO_P3 1, active low */ + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led1 { + gpios = <&gpio 5 14 1>; /* GPO_P3 14, active low */ + linux,default-trigger = "timer"; + default-state = "off"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_oxnas.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_oxnas.txt new file mode 100644 index 0000000000000000000000000000000000000000..966514744df484d5be1af84619199bbc8d199108 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/gpio_oxnas.txt @@ -0,0 +1,47 @@ +* Oxford Semiconductor OXNAS SoC GPIO Controller + +Please refer to gpio.txt for generic information regarding GPIO bindings. + +Required properties: + - compatible: "oxsemi,ox810se-gpio" or "oxsemi,ox820-gpio" + - reg: Base address and length for the device. + - interrupts: The port interrupt shared by all pins. + - gpio-controller: Marks the port as GPIO controller. + - #gpio-cells: Two. The first cell is the pin number and + the second cell is used to specify the gpio polarity as defined in + defined in : + 0 = GPIO_ACTIVE_HIGH + 1 = GPIO_ACTIVE_LOW + - interrupt-controller: Marks the device node as an interrupt controller. + - #interrupt-cells: Two. The first cell is the GPIO number and second cell + is used to specify the trigger type as defined in + : + IRQ_TYPE_EDGE_RISING + IRQ_TYPE_EDGE_FALLING + IRQ_TYPE_EDGE_BOTH + - gpio-ranges: Interaction with the PINCTRL subsystem, it also specifies the + gpio base and count, should be in the format of numeric-gpio-range as + specified in the gpio.txt file. + +Example: + +gpio0: gpio@0 { + compatible = "oxsemi,ox810se-gpio"; + reg = <0x000000 0x100000>; + interrupts = <21>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&pinctrl 0 0 32>; +}; + +keys { + ... + + button-esc { + label = "ESC"; + linux,code = <1>; + gpios = <&gpio0 12 0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/ibm,ppc4xx-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/ibm,ppc4xx-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..d58b3958f3eaf3c599b5a4bfc6753bfba8f5714a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/ibm,ppc4xx-gpio.txt @@ -0,0 +1,24 @@ +* IBM/AMCC/APM GPIO Controller for PowerPC 4XX series and compatible SoCs + +All GPIOs are pin-shared with other functions. DCRs control whether a +particular pin that has GPIO capabilities acts as a GPIO or is used for +another purpose. GPIO outputs are separately programmable to emulate +an open-drain driver. + +Required properties: + - compatible: must be "ibm,ppc4xx-gpio" + - reg: address and length of the register set for the device + - #gpio-cells: must be set to 2. The first cell is the pin number + and the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + - gpio-controller: marks the device node as a gpio controller. + +Example: + +GPIO0: gpio@ef600b00 { + compatible = "ibm,ppc4xx-gpio"; + reg = <0xef600b00 0x00000048>; + #gpio-cells = <2>; + gpio-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/ingenic,gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/ingenic,gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..7988aeb725f42118d9beb355e673fc759ac58c2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/ingenic,gpio.txt @@ -0,0 +1,46 @@ +Ingenic jz47xx GPIO controller + +That the Ingenic GPIO driver node must be a sub-node of the Ingenic pinctrl +driver node. + +Required properties: +-------------------- + + - compatible: Must contain one of: + - "ingenic,jz4740-gpio" + - "ingenic,jz4770-gpio" + - "ingenic,jz4780-gpio" + - reg: The GPIO bank number. + - interrupt-controller: Marks the device node as an interrupt controller. + - interrupts: Interrupt specifier for the controllers interrupt. + - #interrupt-cells: Should be 2. Refer to + ../interrupt-controller/interrupts.txt for more details. + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second + cell specifies GPIO flags, as defined in . Only the + GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + - gpio-ranges: Range of pins managed by the GPIO controller. Refer to + 'gpio.txt' in this directory for more details. + +Example: +-------- + +&pinctrl { + #address-cells = <1>; + #size-cells = <0>; + + gpa: gpio@0 { + compatible = "ingenic,jz4740-gpio"; + reg = <0>; + + gpio-controller; + gpio-ranges = <&pinctrl 0 0 32>; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&intc>; + interrupts = <28>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/mediatek,mt7621-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/mediatek,mt7621-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba455589f869355dc534c5421ff25a7aa96bf4a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/mediatek,mt7621-gpio.txt @@ -0,0 +1,35 @@ +Mediatek MT7621 SoC GPIO controller bindings + +The IP core used inside these SoCs has 3 banks of 32 GPIOs each. +The registers of all the banks are interwoven inside one single IO range. +We load one GPIO controller instance per bank. Also the GPIO controller can receive +interrupts on any of the GPIOs, either edge or level. It then interrupts the CPU +using GIC INT12. + +Required properties for the top level node: +- #gpio-cells : Should be two. The first cell is the GPIO pin number and the + second cell specifies GPIO flags, as defined in . + Only the GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt. Should be 2. The first cell defines the interrupt number, + the second encodes the triger flags encoded as described in + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +- compatible: + - "mediatek,mt7621-gpio" for Mediatek controllers +- reg : Physical base address and length of the controller's registers +- interrupt-parent : phandle of the parent interrupt controller. +- interrupts : Interrupt specifier for the controllers interrupt. +- interrupt-controller : Mark the device node as an interrupt controller. +- gpio-controller : Marks the device node as a GPIO controller. + +Example: + gpio@600 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "mediatek,mt7621-gpio"; + gpio-controller; + interrupt-controller; + reg = <0x600 0x100>; + interrupt-parent = <&gic>; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/microchip,pic32-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/microchip,pic32-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd031fc93b55c1e959df3f0709bdda2dd0f50cbf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/microchip,pic32-gpio.txt @@ -0,0 +1,49 @@ +* Microchip PIC32 GPIO devices (PIO). + +Required properties: + - compatible: "microchip,pic32mzda-gpio" + - reg: Base address and length for the device. + - interrupts: The port interrupt shared by all pins. + - gpio-controller: Marks the port as GPIO controller. + - #gpio-cells: Two. The first cell is the pin number and + the second cell is used to specify the gpio polarity as defined in + defined in : + 0 = GPIO_ACTIVE_HIGH + 1 = GPIO_ACTIVE_LOW + 2 = GPIO_OPEN_DRAIN + - interrupt-controller: Marks the device node as an interrupt controller. + - #interrupt-cells: Two. The first cell is the GPIO number and second cell + is used to specify the trigger type as defined in + : + IRQ_TYPE_EDGE_RISING + IRQ_TYPE_EDGE_FALLING + IRQ_TYPE_EDGE_BOTH + - clocks: Clock specifier (see clock bindings for details). + - microchip,gpio-bank: Specifies which bank a controller owns. + - gpio-ranges: Interaction with the PINCTRL subsystem. + +Example: + +/* PORTA */ +gpio0: gpio0@1f860000 { + compatible = "microchip,pic32mzda-gpio"; + reg = <0x1f860000 0x100>; + interrupts = <118 IRQ_TYPE_LEVEL_HIGH>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&rootclk PB4CLK>; + microchip,gpio-bank = <0>; + gpio-ranges = <&pic32_pinctrl 0 0 16>; +}; + +keys { + ... + + button@sw1 { + label = "ESC"; + linux,code = <1>; + gpios = <&gpio0 12 0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/mrvl-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/mrvl-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..30fd2201b3d4cfc8fbc3fe7b1f7a39854c1d3d7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/mrvl-gpio.txt @@ -0,0 +1,48 @@ +* Marvell PXA GPIO controller + +Required properties: +- compatible : Should be "intel,pxa25x-gpio", "intel,pxa26x-gpio", + "intel,pxa27x-gpio", "intel,pxa3xx-gpio", + "marvell,pxa93x-gpio", "marvell,mmp-gpio", + "marvell,mmp2-gpio" or marvell,pxa1928-gpio. +- reg : Address and length of the register set for the device +- interrupts : Should be the port interrupt shared by all gpio pins. + There're three gpio interrupts in arch-pxa, and they're gpio0, + gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp, + gpio_mux. +- interrupt-names : Should be the names of irq resources. Each interrupt + uses its own interrupt name, so there should be as many interrupt names + as referenced interrupts. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. See gpio.txt for possible + values. + +Example for a MMP platform: + + gpio: gpio@d4019000 { + compatible = "marvell,mmp-gpio"; + reg = <0xd4019000 0x1000>; + interrupts = <49>; + interrupt-names = "gpio_mux"; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <1>; + }; + +Example for a PXA3xx platform: + + gpio: gpio@40e00000 { + compatible = "intel,pxa3xx-gpio"; + reg = <0x40e00000 0x10000>; + interrupt-names = "gpio0", "gpio1", "gpio_mux"; + interrupts = <8 9 10>; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/netxbig-gpio-ext.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/netxbig-gpio-ext.txt new file mode 100644 index 0000000000000000000000000000000000000000..50ec2e690701a74deb0391e6c78719a3d2c2d464 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/netxbig-gpio-ext.txt @@ -0,0 +1,22 @@ +Binding for the GPIO extension bus found on some LaCie/Seagate boards +(Example: 2Big/5Big Network v2, 2Big NAS). + +Required properties: +- compatible: "lacie,netxbig-gpio-ext". +- addr-gpios: GPIOs representing the address register (LSB -> MSB). +- data-gpios: GPIOs representing the data register (LSB -> MSB). +- enable-gpio: latches the new configuration (address, data) on raising edge. + +Example: + +netxbig_gpio_ext: netxbig-gpio-ext { + compatible = "lacie,netxbig-gpio-ext"; + + addr-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH + &gpio1 16 GPIO_ACTIVE_HIGH + &gpio1 17 GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH + &gpio1 13 GPIO_ACTIVE_HIGH + &gpio1 14 GPIO_ACTIVE_HIGH>; + enable-gpio = <&gpio0 29 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/ni,169445-nand-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/ni,169445-nand-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca2f8c745a279cfea1375dc68dceff29a63f8de5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/ni,169445-nand-gpio.txt @@ -0,0 +1,38 @@ +Bindings for the National Instruments 169445 GPIO NAND controller + +The 169445 GPIO NAND controller has two memory mapped GPIO registers, one +for input (the ready signal) and one for output (control signals). It is +intended to be used with the GPIO NAND driver. + +Required properties: + - compatible: should be "ni,169445-nand-gpio" + - reg-names: must contain + "dat" - data register + - reg: address + size pairs describing the GPIO register sets; + order must correspond with the order of entries in reg-names + - #gpio-cells: must be set to 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + - gpio-controller: Marks the device node as a gpio controller. + +Optional properties: + - no-output: disables driving output on the pins + +Examples: + gpio1: nand-gpio-out@1f300010 { + compatible = "ni,169445-nand-gpio"; + reg = <0x1f300010 0x4>; + reg-names = "dat"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio2: nand-gpio-in@1f300014 { + compatible = "ni,169445-nand-gpio"; + reg = <0x1f300014 0x4>; + reg-names = "dat"; + gpio-controller; + #gpio-cells = <2>; + no-output; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/nintendo,hollywood-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/nintendo,hollywood-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..df63da46309cbd454ec5663d2a54a4db254d86c6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/nintendo,hollywood-gpio.txt @@ -0,0 +1,26 @@ +Nintendo Wii (Hollywood) GPIO controller + +Required properties: +- compatible: "nintendo,hollywood-gpio" +- reg: Physical base address and length of the controller's registers. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be <2>. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted). + +Optional properties: +- ngpios: see Documentation/devicetree/bindings/gpio/gpio.txt +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- interrupts: Interrupt specifier for the controller's Broadway (PowerPC) + interrupt. + +Example: + + GPIO: gpio@d8000c0 { + #gpio-cells = <2>; + compatible = "nintendo,hollywood-gpio"; + reg = <0x0d8000c0 0x40>; + gpio-controller; + ngpios = <24>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/nvidia,tegra186-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/nvidia,tegra186-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..adff16c71d21acb0695e872992e05819eb9971e1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/nvidia,tegra186-gpio.txt @@ -0,0 +1,165 @@ +NVIDIA Tegra186 GPIO controllers + +Tegra186 contains two GPIO controllers; a main controller and an "AON" +controller. This binding document applies to both controllers. The register +layouts for the controllers share many similarities, but also some significant +differences. Hence, this document describes closely related but different +bindings and compatible values. + +The Tegra186 GPIO controller allows software to set the IO direction of, and +read/write the value of, numerous GPIO signals. Routing of GPIO signals to +package balls is under the control of a separate pin controller HW block. Two +major sets of registers exist: + +a) Security registers, which allow configuration of allowed access to the GPIO +register set. These registers exist in a single contiguous block of physical +address space. The size of this block, and the security features available, +varies between the different GPIO controllers. + +Access to this set of registers is not necessary in all circumstances. Code +that wishes to configure access to the GPIO registers needs access to these +registers to do so. Code which simply wishes to read or write GPIO data does not +need access to these registers. + +b) GPIO registers, which allow manipulation of the GPIO signals. In some GPIO +controllers, these registers are exposed via multiple "physical aliases" in +address space, each of which access the same underlying state. See the hardware +documentation for rationale. Any particular GPIO client is expected to access +just one of these physical aliases. + +Tegra HW documentation describes a unified naming convention for all GPIOs +implemented by the SoC. Each GPIO is assigned to a port, and a port may control +a number of GPIOs. Thus, each GPIO is named according to an alphabetical port +name and an integer GPIO name within the port. For example, GPIO_PA0, GPIO_PN6, +or GPIO_PCC3. + +The number of ports implemented by each GPIO controller varies. The number of +implemented GPIOs within each port varies. GPIO registers within a controller +are grouped and laid out according to the port they affect. + +The mapping from port name to the GPIO controller that implements that port, and +the mapping from port name to register offset within a controller, are both +extremely non-linear. The header file +describes the port-level mapping. In that file, the naming convention for ports +matches the HW documentation. The values chosen for the names are alphabetically +sorted within a particular controller. Drivers need to map between the DT GPIO +IDs and HW register offsets using a lookup table. + +Each GPIO controller can generate a number of interrupt signals. Each signal +represents the aggregate status for all GPIOs within a set of ports. Thus, the +number of interrupt signals generated by a controller varies as a rough function +of the number of ports it implements. Note that the HW documentation refers to +both the overall controller HW module and the sets-of-ports as "controllers". + +Each GPIO controller in fact generates multiple interrupts signals for each set +of ports. Each GPIO may be configured to feed into a specific one of the +interrupt signals generated by a set-of-ports. The intent is for each generated +signal to be routed to a different CPU, thus allowing different CPUs to each +handle subsets of the interrupts within a port. The status of each of these +per-port-set signals is reported via a separate register. Thus, a driver needs +to know which status register to observe. This binding currently defines no +configuration mechanism for this. By default, drivers should use register +GPIO_${port}_INTERRUPT_STATUS_G1_0. Future revisions to the binding could +define a property to configure this. + +Required properties: +- compatible + Array of strings. + One of: + - "nvidia,tegra186-gpio". + - "nvidia,tegra186-gpio-aon". + - "nvidia,tegra194-gpio". + - "nvidia,tegra194-gpio-aon". +- reg-names + Array of strings. + Contains a list of names for the register spaces described by the reg + property. May contain the following entries, in any order: + - "gpio": Mandatory. GPIO control registers. This may cover either: + a) The single physical alias that this OS should use. + b) All physical aliases that exist in the controller. This is + appropriate when the OS is responsible for managing assignment of + the physical aliases. + - "security": Optional. Security configuration registers. + Users of this binding MUST look up entries in the reg property by name, + using this reg-names property to do so. +- reg + Array of (physical base address, length) tuples. + Must contain one entry per entry in the reg-names property, in a matching + order. +- interrupts + Array of interrupt specifiers. + The interrupt outputs from the HW block, one per set of ports, in the + order the HW manual describes them. The number of entries required varies + depending on compatible value: + - "nvidia,tegra186-gpio": 6 entries. + - "nvidia,tegra186-gpio-aon": 1 entry. + - "nvidia,tegra194-gpio": 6 entries. + - "nvidia,tegra194-gpio-aon": 1 entry. +- gpio-controller + Boolean. + Marks the device node as a GPIO controller/provider. +- #gpio-cells + Single-cell integer. + Must be <2>. + Indicates how many cells are used in a consumer's GPIO specifier. + In the specifier: + - The first cell is the pin number. + See . + - The second cell contains flags: + - Bit 0 specifies polarity + - 0: Active-high (normal). + - 1: Active-low (inverted). +- interrupt-controller + Boolean. + Marks the device node as an interrupt controller/provider. +- #interrupt-cells + Single-cell integer. + Must be <2>. + Indicates how many cells are used in a consumer's interrupt specifier. + In the specifier: + - The first cell is the GPIO number. + See . + - The second cell is contains flags: + - Bits [3:0] indicate trigger type and level: + - 1: Low-to-high edge triggered. + - 2: High-to-low edge triggered. + - 4: Active high level-sensitive. + - 8: Active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. + +Example: + +#include + +gpio@2200000 { + compatible = "nvidia,tegra186-gpio"; + reg-names = "security", "gpio"; + reg = + <0x0 0x2200000 0x0 0x10000>, + <0x0 0x2210000 0x0 0x10000>; + interrupts = + <0 47 IRQ_TYPE_LEVEL_HIGH>, + <0 50 IRQ_TYPE_LEVEL_HIGH>, + <0 53 IRQ_TYPE_LEVEL_HIGH>, + <0 56 IRQ_TYPE_LEVEL_HIGH>, + <0 59 IRQ_TYPE_LEVEL_HIGH>, + <0 180 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +gpio@c2f0000 { + compatible = "nvidia,tegra186-gpio-aon"; + reg-names = "security", "gpio"; + reg = + <0x0 0xc2f0000 0x0 0x1000>, + <0x0 0xc2f1000 0x0 0x1000>; + interrupts = + <0 60 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/nvidia,tegra20-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/nvidia,tegra20-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..023c9526e5f838c277eefdd10292943c11b4fd5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/nvidia,tegra20-gpio.txt @@ -0,0 +1,40 @@ +NVIDIA Tegra GPIO controller + +Required properties: +- compatible : "nvidia,tegra-gpio" +- reg : Physical base address and length of the controller's registers. +- interrupts : The interrupt outputs from the controller. For Tegra20, + there should be 7 interrupts specified, and for Tegra30, there should + be 8 interrupts specified. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- gpio-controller : Marks the device node as a GPIO controller. +- #interrupt-cells : Should be 2. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. +- interrupt-controller : Marks the device node as an interrupt controller. + +Example: + +gpio: gpio@6000d000 { + compatible = "nvidia,tegra20-gpio"; + reg = < 0x6000d000 0x1000 >; + interrupts = < 0 32 0x04 + 0 33 0x04 + 0 34 0x04 + 0 35 0x04 + 0 55 0x04 + 0 87 0x04 + 0 89 0x04 >; + #gpio-cells = <2>; + gpio-controller; + #interrupt-cells = <2>; + interrupt-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/nxp,lpc1850-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/nxp,lpc1850-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb7cdd69e10bf07b486a9a734174698dbf889bf5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/nxp,lpc1850-gpio.txt @@ -0,0 +1,39 @@ +NXP LPC18xx/43xx GPIO controller Device Tree Bindings +----------------------------------------------------- + +Required properties: +- compatible : Should be "nxp,lpc1850-gpio" +- reg : Address and length of the register set for the device +- clocks : Clock specifier (see clock bindings for details) +- gpio-controller : Marks the device node as a GPIO controller. +- #gpio-cells : Should be two + - First cell is the GPIO line number + - Second cell is used to specify polarity + +Optional properties: +- gpio-ranges : Mapping between GPIO and pinctrl + +Example: +#define LPC_GPIO(port, pin) (port * 32 + pin) +#define LPC_PIN(port, pin) (0x##port * 32 + pin) + +gpio: gpio@400f4000 { + compatible = "nxp,lpc1850-gpio"; + reg = <0x400f4000 0x4000>; + clocks = <&ccu1 CLK_CPU_GPIO>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl LPC_GPIO(0,0) LPC_PIN(0,0) 2>, + ... + <&pinctrl LPC_GPIO(7,19) LPC_PIN(f,5) 7>; +}; + +gpio_joystick { + compatible = "gpio-keys-polled"; + ... + + button@0 { + ... + gpios = <&gpio LPC_GPIO(4,8) GPIO_ACTIVE_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/pl061-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/pl061-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..89058d375b7c1eab85d68027920fa871bfe40df6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/pl061-gpio.txt @@ -0,0 +1,10 @@ +ARM PL061 GPIO controller + +Required properties: +- compatible : "arm,pl061", "arm,primecell" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt mapping for GPIO IRQ. +- gpio-ranges : Interaction with the PINCTRL subsystem. diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/raspberrypi,firmware-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/raspberrypi,firmware-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce97265e23ba6764adedde12b2fc1256fbd91d88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/raspberrypi,firmware-gpio.txt @@ -0,0 +1,30 @@ +Raspberry Pi GPIO expander + +The Raspberry Pi 3 GPIO expander is controlled by the VC4 firmware. The +firmware exposes a mailbox interface that allows the ARM core to control the +GPIO lines on the expander. + +The Raspberry Pi GPIO expander node must be a child node of the Raspberry Pi +firmware node. + +Required properties: + +- compatible : Should be "raspberrypi,firmware-gpio" +- gpio-controller : Marks the device node as a gpio controller +- #gpio-cells : Should be two. The first cell is the pin number, and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + +Example: + +firmware: firmware-rpi { + compatible = "raspberrypi,bcm2835-firmware"; + mboxes = <&mailbox>; + + expgpio: gpio { + compatible = "raspberrypi,firmware-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/renesas,gpio-rcar.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/renesas,gpio-rcar.txt new file mode 100644 index 0000000000000000000000000000000000000000..4018ee57a6af5a662a37640262a6dd972daf02de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/renesas,gpio-rcar.txt @@ -0,0 +1,80 @@ +* Renesas R-Car GPIO Controller + +Required Properties: + + - compatible: should contain one or more of the following: + - "renesas,gpio-r8a7743": for R8A7743 (RZ/G1M) compatible GPIO controller. + - "renesas,gpio-r8a7745": for R8A7745 (RZ/G1E) compatible GPIO controller. + - "renesas,gpio-r8a77470": for R8A77470 (RZ/G1C) compatible GPIO controller. + - "renesas,gpio-r8a7778": for R8A7778 (R-Car M1) compatible GPIO controller. + - "renesas,gpio-r8a7779": for R8A7779 (R-Car H1) compatible GPIO controller. + - "renesas,gpio-r8a7790": for R8A7790 (R-Car H2) compatible GPIO controller. + - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. + - "renesas,gpio-r8a7792": for R8A7792 (R-Car V2H) compatible GPIO controller. + - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. + - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. + - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller. + - "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller. + - "renesas,gpio-r8a77965": for R8A77965 (R-Car M3-N) compatible GPIO controller. + - "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller. + - "renesas,gpio-r8a77980": for R8A77980 (R-Car V3H) compatible GPIO controller. + - "renesas,gpio-r8a77990": for R8A77990 (R-Car E3) compatible GPIO controller. + - "renesas,gpio-r8a77995": for R8A77995 (R-Car D3) compatible GPIO controller. + - "renesas,rcar-gen1-gpio": for a generic R-Car Gen1 GPIO controller. + - "renesas,rcar-gen2-gpio": for a generic R-Car Gen2 or RZ/G1 GPIO controller. + - "renesas,rcar-gen3-gpio": for a generic R-Car Gen3 GPIO controller. + - "renesas,gpio-rcar": deprecated. + + When compatible with the generic version nodes must list the + SoC-specific version corresponding to the platform first followed by + the generic version. + + - reg: Base address and length of each memory resource used by the GPIO + controller hardware module. + + - interrupts: Interrupt specifier for the controllers interrupt. + + - gpio-controller: Marks the device node as a gpio controller. + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second + cell specifies GPIO flags, as defined in . Only the + GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + - gpio-ranges: Range of pins managed by the GPIO controller. + +Optional properties: + + - clocks: Must contain a reference to the functional clock. The property is + mandatory if the hardware implements a controllable functional clock for + the GPIO instance. + +Please refer to gpio.txt in this directory for details of gpio-ranges property +and the common GPIO bindings used by client devices. + +The GPIO controller also acts as an interrupt controller. It uses the default +two cells specifier as described in Documentation/devicetree/bindings/ +interrupt-controller/interrupts.txt. + +Example: R8A7779 (R-Car H1) GPIO controller nodes + + gpio0: gpio@ffc40000 { + compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio"; + reg = <0xffc40000 0x2c>; + interrupt-parent = <&gic>; + interrupts = <0 141 0x4>; + #gpio-cells = <2>; + gpio-controller; + gpio-ranges = <&pfc 0 0 32>; + interrupt-controller; + #interrupt-cells = <2>; + }; + ... + gpio6: gpio@ffc46000 { + compatible = "renesas,gpio-r8a7779", "renesas,rcar-gen1-gpio"; + reg = <0xffc46000 0x2c>; + interrupt-parent = <&gic>; + interrupts = <0 147 0x4>; + #gpio-cells = <2>; + gpio-controller; + gpio-ranges = <&pfc 0 192 9>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/rockchip,rk3328-grf-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/rockchip,rk3328-grf-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9231df17c2b8250a0dd21a12d355ec324e65c7a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/rockchip,rk3328-grf-gpio.txt @@ -0,0 +1,32 @@ +Rockchip RK3328 GRF (General Register Files) GPIO controller. + +In Rockchip RK3328, the output only GPIO_MUTE pin, originally for codec mute +control, can also be used for general purpose. It is manipulated by the +GRF_SOC_CON10 register in GRF. Aside from the GPIO_MUTE pin, the HDMI pins can +also be set in the same way. + +Currently this GPIO controller only supports the mute pin. If needed in the +future, the HDMI pins support can also be added. + +Required properties: +- compatible: Should contain "rockchip,rk3328-grf-gpio". +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = Active high, + 1 = Active low. + +Example: + + grf: syscon@ff100000 { + compatible = "rockchip,rk3328-grf", "syscon", "simple-mfd"; + + grf_gpio: grf-gpio { + compatible = "rockchip,rk3328-grf-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + +Note: The grf_gpio node should be declared as the child of the GRF (General +Register File) node. The GPIO_MUTE pin is referred to as <&grf_gpio 0>. diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/snps-dwapb-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/snps-dwapb-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..7276b50c35065b0b896cd09715426c03357ba81b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/snps-dwapb-gpio.txt @@ -0,0 +1,65 @@ +* Synopsys DesignWare APB GPIO controller + +Required properties: +- compatible : Should contain "snps,dw-apb-gpio" +- reg : Address and length of the register set for the device. +- #address-cells : should be 1 (for addressing port subnodes). +- #size-cells : should be 0 (port subnodes). + +The GPIO controller has a configurable number of ports, each of which are +represented as child nodes with the following properties: + +Required properties: +- compatible : "snps,dw-apb-gpio-port" +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low +- reg : The integer port index of the port, a single cell. + +Optional properties: +- interrupt-controller : The first port may be configured to be an interrupt +controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt. Shall be set to 2. The first cell defines the interrupt number, + the second encodes the triger flags encoded as described in + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +- interrupts : The interrupts to the parent controller raised when GPIOs + generate the interrupts. If the controller provides one combined interrupt + for all GPIOs, specify a single interrupt. If the controller provides one + interrupt for each GPIO, provide a list of interrupts that correspond to each + of the GPIO pins. When specifying multiple interrupts, if any are unconnected, + use the interrupts-extended property to specify the interrupts and set the + interrupt controller handle for unused interrupts to 0. +- snps,nr-gpios : The number of pins in the port, a single cell. +- resets : Reset line for the controller. + +Example: + +gpio: gpio@20000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x20000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&vic1>; + interrupts = <0>; + }; + + portb: gpio-controller@1 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + reg = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/sodaville.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/sodaville.txt new file mode 100644 index 0000000000000000000000000000000000000000..563eff22b975624fbeeb2714b64a7fd39e406f03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/sodaville.txt @@ -0,0 +1,48 @@ +GPIO controller on CE4100 / Sodaville SoCs +========================================== + +The bindings for CE4100's GPIO controller match the generic description +which is covered by the gpio.txt file in this folder. + +The only additional property is the intel,muxctl property which holds the +value which is written into the MUXCNTL register. + +There is no compatible property for now because the driver is probed via +PCI id (vendor 0x8086 device 0x2e67). + +The interrupt specifier consists of two cells encoded as follows: + - <1st cell>: The interrupt-number that identifies the interrupt source. + - <2nd cell>: The level-sense information, encoded as follows: + 4 - active high level-sensitive + 8 - active low level-sensitive + +Example of the GPIO device and one user: + + pcigpio: gpio@b,1 { + /* two cells for GPIO and interrupt */ + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "pci8086,2e67.2", + "pci8086,2e67", + "pciclassff0000", + "pciclassff00"; + + reg = <0x15900 0x0 0x0 0x0 0x0>; + /* Interrupt line of the gpio device */ + interrupts = <15 1>; + /* It is an interrupt and GPIO controller itself */ + interrupt-controller; + gpio-controller; + intel,muxctl = <0>; + }; + + testuser@20 { + compatible = "example,testuser"; + /* User the 11th GPIO line as an active high triggered + * level interrupt + */ + interrupts = <11 8>; + interrupt-parent = <&pcigpio>; + /* Use this GPIO also with the gpio functions */ + gpios = <&pcigpio 11 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/spear_spics.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/spear_spics.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd04d96e6ff1596d7c69ab0c94f9d389ab72137a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/spear_spics.txt @@ -0,0 +1,49 @@ +=== ST Microelectronics SPEAr SPI CS Driver === + +SPEAr platform provides a provision to control chipselects of ARM PL022 Prime +Cell spi controller through its system registers, which otherwise remains under +PL022 control. If chipselect remain under PL022 control then they would be +released as soon as transfer is over and TxFIFO becomes empty. This is not +desired by some of the device protocols above spi which expect (multiple) +transfers without releasing their chipselects. + +Chipselects can be controlled by software by turning them as GPIOs. SPEAr +provides another interface through system registers through which software can +directly control each PL022 chipselect. Hence, it is natural for SPEAr to export +the control of this interface as gpio. + +Required properties: + + * compatible: should be defined as "st,spear-spics-gpio" + * reg: mentioning address range of spics controller + * st-spics,peripcfg-reg: peripheral configuration register offset + * st-spics,sw-enable-bit: bit offset to enable sw control + * st-spics,cs-value-bit: bit offset to drive chipselect low or high + * st-spics,cs-enable-mask: chip select number bit mask + * st-spics,cs-enable-shift: chip select number program offset + * gpio-controller: Marks the device node as gpio controller + * #gpio-cells: should be 1 and will mention chip select number + +All the above bit offsets are within peripcfg register. + +Example: +------- +spics: spics@e0700000{ + compatible = "st,spear-spics-gpio"; + reg = <0xe0700000 0x1000>; + st-spics,peripcfg-reg = <0x3b0>; + st-spics,sw-enable-bit = <12>; + st-spics,cs-value-bit = <11>; + st-spics,cs-enable-mask = <3>; + st-spics,cs-enable-shift = <8>; + gpio-controller; + #gpio-cells = <2>; +}; + + +spi0: spi@e0100000 { + num-cs = <3>; + cs-gpios = <&gpio1 7 0>, <&spics 0>, + <&spics 1>; + ... +} diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/wd,mbl-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/wd,mbl-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..038c3a6a1f4d180408ed1f0ad89f97ffea7f2eb2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/wd,mbl-gpio.txt @@ -0,0 +1,38 @@ +Bindings for the Western Digital's MyBook Live memory-mapped GPIO controllers. + +The Western Digital MyBook Live has two memory-mapped GPIO controllers. +Both GPIO controller only have a single 8-bit data register, where GPIO +state can be read and/or written. + +Required properties: + - compatible: should be "wd,mbl-gpio" + - reg-names: must contain + "dat" - data register + - reg: address + size pairs describing the GPIO register sets; + order must correspond with the order of entries in reg-names + - #gpio-cells: must be set to 2. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + - gpio-controller: Marks the device node as a gpio controller. + +Optional properties: + - no-output: GPIOs are read-only. + +Examples: + gpio0: gpio0@e0000000 { + compatible = "wd,mbl-gpio"; + reg-names = "dat"; + reg = <0xe0000000 0x1>; + #gpio-cells = <2>; + gpio-controller; + }; + + gpio1: gpio1@e0100000 { + compatible = "wd,mbl-gpio"; + reg-names = "dat"; + reg = <0xe0100000 0x1>; + #gpio-cells = <2>; + gpio-controller; + no-output; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpio/zx296702-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/gpio/zx296702-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dab156fcf41775fad139313d64c70fa2f65a052 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpio/zx296702-gpio.txt @@ -0,0 +1,24 @@ +ZTE ZX296702 GPIO controller + +Required properties: +- compatible : "zte,zx296702-gpio" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt mapping for GPIO IRQ. +- gpio-ranges : Interaction with the PINCTRL subsystem. + +gpio1: gpio@b008040 { + compatible = "zte,zx296702-gpio"; + reg = <0xb008040 0x40>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = < &pmx0 0 54 2 &pmx0 2 59 14>; + interrupts = ; + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <2>; + clock-names = "gpio_pclk"; + clocks = <&lsp0clk ZX296702_GPIO_CLK>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-busmon.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-busmon.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9a99bbd004f469776fc1c5c3629aac44c6bd861 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-busmon.txt @@ -0,0 +1,16 @@ +Adreno bus monitor device + +kgsl-busmon is a psedo device that represents a devfreq bus bandwidth +governor. If this device is present then two different governors are used +for GPU DCVS and bus DCVS. + +Required properties: +- compatible: Must be "qcom,kgsl-busmon" +- label: Device name used for sysfs entry. + +Example: + +qcom,kgsl-busmon { + compatible = "qcom,kgsl-busmon"; + label = "kgsl-busmon"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-gmu.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-gmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..df028c77773cb290744042e17a051b0999f90a38 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-gmu.txt @@ -0,0 +1,101 @@ +Qualcomm Technologies, Inc. GPU Graphics Management Unit (GMU) + +Required properties: +- compatible : + - "qcom,gpu-gmu" + - "qcom,gpu-rgmu" +- reg: Specifies the GMU register base address and size. +- reg-names: Resource names used for the physical address + and length of GMU registers. +- interrupts: Interrupt mapping for GMU and HFI IRQs. +- interrupt-names: String property to describe the name of each interrupt. + +Bus Scaling Data: +qcom,msm-bus,name: String property to describe the name of bus client. +qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases defined in the vectors property. +qcom,msm-bus,num-paths: This represents the number of paths in each Bus Scaling Usecase. +qcom,msm-bus,vectors-KBps: A series of 4 cell properties, format of which is: + , , // For Bus Scaling Usecase 1 + , , // For Bus Scaling Usecase 2 + <.. .. .. ..>, <.. .. .. ..>; // For Bus Scaling Usecase n + This property is a series of all vectors for all Bus Scaling Usecases. + Each set of vectors for each usecase describes bandwidth votes for a combination + of src/dst ports. The driver will set the desired use case based on the selected + power level and the desired bandwidth vote will be registered for the port pairs. + +GMU GDSC/regulators: +- regulator-names: List of regulator name strings +- vddcx-supply: Phandle for vddcx regulator device node. +- vdd-supply: Phandle for vdd regulator device node. + +- clock: List of clocks to be used for GMU register access and DCVS. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for information about the format. For each clock specified + here, there must be a corresponding entry in clock-names + (see below). + +- clock-names: List of clock names corresponding to the clocks specified in + the "clocks" property (above). See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for more info. Currently GMU required these clock names: + "gmu_clk", "ahb_clk", "cxo_clk", "axi_clk", "memnoc_clk", + "rbcpr_clk" + +- List of sub nodes, one for each of the translation context banks needed + for GMU to access system memory in different operating mode. Currently + supported names are: + - gmu_user: used for GMU 'user' mode address space. + - gmu_kernel: used for GMU 'kernel' mode address space. + Each sub node has the following required properties: + + - compatible : "qcom,smmu-gmu-user-cb" or "qcom,smmu-gmu-kernel-cb" + - iommus : Specifies the SID's used by this context bank, this + needs to be pair, kgsl_smmu is the string + parsed by iommu driver to match this context bank with the + kgsl_smmu device defined in iommu device tree. On targets + where the msm iommu driver is used rather than the arm smmu + driver, this property may be absent. + +Example: + +gmu: qcom,gmu@2c6a000 { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = <0x2c6a000 0x30000>; + reg-names = "kgsl_gmu_reg"; + + interrupts = <0 304 0>, <0 305 0>; + interrupt-names = "kgsl_gmu_irq", "kgsl_hfi_irq"; + + qcom,msm-bus,name = "cnoc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 10036 0 0>, // CNOC off + <26 10036 0 100>; // CNOC on + + regulator-name = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + clocks = <&clock_gpugcc clk_gcc_gmu_clk>, + <&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_RBCPR_CLK>; + + clock-names = "gmu_clk", "ahb_clk", "cxo_clk", + "axi_clk", "memnoc_clk", "rbcpr_clk"; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 4>; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-iommu.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..fef7515c2b49a01f3e8917f048e32a7127ba1ae5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-iommu.txt @@ -0,0 +1,81 @@ +Qualcomm Technologies, Inc. GPU IOMMU + +Required properties: + +Required properties: +- compatible : one of: + - "qcom,kgsl-smmu-v1" + - "qcom,kgsl-smmu-v2" + +- reg : Base address and size of the SMMU. + +- clocks : List of clocks to be used during SMMU register access. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for information about the format. For each clock specified + here, there must be a corresponding entry in clock-names + (see below). + +- clock-names : List of clock names corresponding to the clocks specified in + the "clocks" property (above). See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for more info. +- qcom,protect : The GPU register region which must be protected by a CP + protected mode. On some targets this region must cover + the entire SMMU register space, on others there + is a separate aperture for CP to program context banks. + +Optional properties: +- qcom,retention : A boolean specifying if retention is supported on this target +- qcom,global_pt : A boolean specifying if global pagetable should be used. + When not set we use per process pagetables +- qcom,hyp_secure_alloc : A bool specifying if the hypervisor is used on this target + for secure buffer allocation + +- List of sub nodes, one for each of the translation context banks supported. + The driver uses the names of these nodes to determine how they are used, + currently supported names are: + - gfx3d_user : Used for the 'normal' GPU address space. + - gfx3d_secure : Used for the content protection address space. + - gfx3d_secure_alt : Used for the content protection address space for alternative SID. + + Each sub node has the following required properties: + + - compatible : "qcom,smmu-kgsl-cb" + - iommus : Specifies the SID's used by this context bank, this needs to be + pair, kgsl_smmu is the string parsed by iommu + driver to match this context bank with the kgsl_smmu device + defined in iommu device tree. On targets where the msm iommu + driver is used rather than the arm smmu driver, this property + may be absent. + +Example: + +msm_iommu: qcom,kgsl-iommu@2ca0000 { + compatible = "qcom,kgsl-smmu-v2"; + reg = <0x2ca0000 0x10000>; + qcom,protect = <0xa0000 0xc000>; + clocks = <&clock_mmss clk_gpu_ahb_clk>, + <&clock_gcc clk_gcc_mmss_bimc_gfx_clk>, + <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_mmss clk_mmss_mmagic_cfg_ahb_clk>; + clock-names = "gpu_ahb_clk", "bimc_gfx_clk", "mmagic_ahb_clk", "mmagic_cfg_ahb_clk"; + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,global_pt; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 0>, + <&kgsl_smmu 1>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 2>; + }; + + gfx3d_secure_alt: gfx3d_secure_alt { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-pwrlevels.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-pwrlevels.txt new file mode 100644 index 0000000000000000000000000000000000000000..2db61a8e68b761ca3f001e6f8fd1a5f94e0c42e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno-pwrlevels.txt @@ -0,0 +1,80 @@ +Qualcomm Technologies, Inc. GPU powerlevels + +Powerlevels are defined in sets by qcom,gpu-pwrlevels. Multiple sets (bins) +can be defined within qcom,gpu-pwrelvel-bins. Each powerlevel defines a +voltage, bus, bandwidth level, and a DVM value. + +- qcom,gpu-pwrlevel-bins: Contains one or more qcom,gpu-pwrlevels sets + +Properties: +- compatible: Must be qcom,gpu-pwrlevel-bins +- qcom,gpu-pwrlevels: Defines a set of powerlevels + +Properties: +- qcom,speed-bin: Speed bin identifier for the set - must match + the value read from the hardware +- qcom,initial-pwrlevel: GPU wakeup powerlevel + +- qcom,gpu-pwrlevel: A single powerlevel + +- qcom,ca-target-pwrlevel: + This value indicates which qcom,gpu-pwrlevel + to jump on in case of context aware power level + jump. +Required Properties: +- reg: Index of the powerlevel (0 = highest perf) +- qcom,gpu-freq GPU frequency for the powerlevel (in Hz) +- qcom,bus-freq Index to a bus level (defined by the bus + settings). + +- qcom,bus-freq-ddrX If specified, define the DDR specific bus + frequency for the power level. X will be the + return value from of_fdt_get_ddrtype(). + +Optional Properties: +- qcom,bus-min Minimum bus level to set for the power level + +- qcom,bus-min-ddrX If specified, define the DDR specific minimum + bus level for the power level. X will be the + return value from of_fdt_get_ddrtype(). + +- qcom,bus-max maximum bus level to set for the power level + +- qcom,bus-max-ddrX If specified, define the DDR specific maximum + bus level for the power level. X will be the + return value from of_fdt_get_ddrtype(). + +- qcom,acd-level: Value that is used as a register setting for + the ACD power feature. It helps to determine + the threshold for when ACD activates. Zero is + the default value, and the setting where ACD + will never activate. +Example: + +qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + qcom,acd-level = <0xffffffff>; +}; + +Example for DDR4/DDR5 specific part: + +qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <480000000>; + + /* DDR5 */ + qcom,bus-freq-ddr8 = <10>; + qcom,bus-min-ddr8 = <9>; + qcom,bus-max-ddr8 = <11>; + + /* DDR 4 */ + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <7>; + qcom,bus-max-ddr7 = <9>; + + qcom,acd-level = <0xffffffff>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/adreno.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno.txt new file mode 100644 index 0000000000000000000000000000000000000000..ced4f62d97391566d8df481cbaf519395d5c154e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/adreno.txt @@ -0,0 +1,525 @@ +Qualcomm Technologies, Inc. GPU + +Qualcomm Technologies, Inc. Adreno GPU + +Required properties: +- label: A string used as a descriptive name for the device. +- compatible: Must be "qcom,kgsl-3d0" and "qcom,kgsl-3d" +- reg: Specifies the register base address and size, the shader memory + base address and size (if it exists), and the base address and size + of the CX_DBGC block (if it exists). +- reg-names: Resource names used for the physical address of device registers + and shader memory. "kgsl_3d0_reg_memory" gives the physical address + and length of device registers while "kgsl_3d0_shader_memory" gives + physical address and length of device shader memory. If + specified, "qfprom_memory" gives the range for the efuse + registers used for various configuration options. If specified, + "kgsl_3d0_cx_dbgc_memory" gives the physical address and length + of the CX DBGC block. +- interrupts: Interrupt mapping for GPU IRQ. +- interrupt-names: String property to describe the name of the interrupt. +- qcom,id: An integer used as an identification number for the device. +- qcom,gpu-bimc-interface-clk-freq: + GPU-BIMC interface clock needs to be set to this value for + targets where B/W requirements does not meet GPU Turbo use cases. +- clocks: List of phandle and clock specifier pairs, one pair + for each clock input to the device. +- clock-names: List of clock input name strings sorted in the same + order as the clocks property. + Current values of clock-names are: + "src_clk", "core_clk", "iface_clk", "mem_clk", "mem_iface_clk", + "alt_mem_iface_clk", "rbbmtimer_clk", "alwayson_clk", + "iref_clk", "l3_vote" + "core_clk" and "iface_clk" are required and others are optional + +- qcom,base-leakage-coefficient: Dynamic leakage coefficient. +- qcom,lm-limit: Current limit for GPU limit management. +- qcom,isense-clk-on-level: below or equal this power level isense clock is at XO rate, + above this powerlevel isense clock is at working frequency. + +Bus Scaling Data: +- qcom,gpu-bus-table: Defines a bus voting table with the below properties. Multiple sets of bus + voting tables can be defined for given platform based on the type of ddr system. + +Properties: +- compatible: Must be "qcom,gpu-bus-table". Additionally, "qcom,gpu-bus-table-ddr" must also + be provided, with the ddr type value(integer) appended to the string. +- qcom,msm-bus,name: String property to describe the name of the 3D graphics processor. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases defined in the vectors property. +- qcom,msm-bus,active-only: A boolean flag indicating if it is active only. +- qcom,msm-bus,num-paths: This represents the number of paths in each Bus Scaling Usecase. +- qcom,msm-bus,vectors-KBps: A series of 4 cell properties, format of which is: + , , // For Bus Scaling Usecase 1 + , , // For Bus Scaling Usecase 2 + <.. .. .. ..>, <.. .. .. ..>; // For Bus Scaling Usecase n + This property is a series of all vectors for all Bus Scaling Usecases. + Each set of vectors for each usecase describes bandwidth votes for a combination + of src/dst ports. The driver will set the desired use case based on the selected + power level and the desired bandwidth vote will be registered for the port pairs. + Current values of src are: + 0 = MSM_BUS_MASTER_GRAPHICS_3D + 1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1 + 2 = MSM_BUS_MASTER_V_OCMEM_GFX3D + Current values of dst are: + 0 = MSM_BUS_SLAVE_EBI_CH0 + 1 = MSM_BUS_SLAVE_OCMEM + ab: Represents aggregated bandwidth. This value is 0 for Graphics. + ib: Represents instantaneous bandwidth. This value has a range <0 8000 MB/s> + +- qcom,ocmem-bus-client: Container for another set of bus scaling properties + qcom,msm-bus,name + qcom,msm-bus,num-cases + qcom,msm-bus,num-paths + qcom,msm-bus,vectors-KBps + to be used by ocmem msm bus scaling client. + +- qcom,cpu-to-gpu-cfg-path: Container for another set of bus scaling properties + qcom,msm-bus,name + qcom,msm-bus,num-cases + qcom,msm-bus,num-paths + qcom,msm-bus,vectors-KBps + to be used for keeping all clocks ON in CPU to GPU AHB config path. + +GDSC Oxili Regulators: +- regulator-names: List of regulator name strings sorted in power-on order +- vddcx-supply: Phandle for vddcx regulator device node. +- vdd-supply: Phandle for vdd regulator device node. + +IOMMU Data: +- iommu: Phandle for the KGSL IOMMU device node + +GPU Power levels: +- qcom,gpu-pwrlevel-bins: Container for sets of GPU power levels (see + adreno-pwrlevels.txt) +DCVS Core info +- qcom,dcvs-core-info Container for the DCVS core info (see + dcvs-core-info.txt) + +Optional Properties: +- qcom,initial-powerlevel: This value indicates which qcom,gpu-pwrlevel should be used at start time + and when coming back out of resume +- qcom,throttle-pwrlevel: This value indicates which qcom,gpu-pwrlevel LM throttling + may start to occur +- qcom,bus-control: Boolean. Enables an independent bus vote from the gpu frequency +- qcom,bus-accesses: Parameter for tuning bus dcvs. +- qcom,bus-accesses-ddrX: Parameter for tuning bus dcvs for each DDR configuration where + X will be the return value from of_fdt_get_ddrtype(). +- qcom,gpubw-dev: a phandle to a device representing bus bandwidth requirements + (see devdw.txt) +- qcom,idle-timeout: This property represents the time in milliseconds for idle timeout. +- qcom,no-nap: If it exists software clockgating will be disabled at boot time. +- qcom,chipid: If it exists this property is used to replace + the chip identification read from the GPU hardware. + This is used to override faulty hardware readings. +- qcom,disable-wake-on-touch: Boolean. Disables the GPU power up on a touch input event. +- qcom,disable-busy-time-burst: + Boolean. Disables the busy time burst to avoid switching + of power level for large frames based on the busy time limit. + +- qcom,pm-qos-active-latency: + Right after GPU wakes up from sleep, driver votes for + acceptable maximum latency to the pm-qos driver. This + voting demands that the system can not go into any + power save state *if* the latency to bring system back + into active state is more than this value. + Value is in microseconds. +- qcom,pm-qos-wakeup-latency: + Similar to the above. Driver votes against deep low + power modes right before GPU wakes up from sleep. +- qcom,l2pc-cpu-mask-latency: + The CPU mask latency in microseconds to avoid L2PC + on masked CPUs. + +- qcom,force-32bit: + Force the GPU to use 32 bit data sizes even if + it is capable of doing 64 bit. + +- qcom,gpu-speed-bin: GPU speed bin information in the format + + offset - offset of the efuse register from the base. + mask - mask for the relevant bits in the efuse register. + shift - number of bits to right shift to get the speed bin + value. +- qcom,gpu-disable-fuse: GPU disable fuse + + offset - offset of the efuse register from the base. + mask - mask for the relevant bits in the efuse register. + shift - number of bits to right shift to get the disable_gpu + fuse bit value. + +- qcom,soc-hw-rev-efuse: SOC hardware revision fuse information in the format + + offset - offset of the efuse register from the base. + bit_position - hardware revision starting bit in the efuse register. + mask - mask for the relevant bits in the efuse register. + +- qcom,highest-bank-bit: + Specify the bit of the highest DDR bank. This + is programmed into protected registers and also + passed to the user as a property. +- qcom,min-access-length: + Specify the minimum access length for the chip. + Either 32 or 64 bytes. + Based on the above options, program the appropriate bit into + certain protected registers and also pass to the user as + a property. +- qcom,ubwc-mode: + Specify the ubwc mode for this chip. + 1: UBWC 1.0 + 2: UBWC 2.0 + 3: UBWC 3.0 + Based on the ubwc mode, program the appropriate bit into + certain protected registers and also pass to the user as + a property. +- qcom,l2pc-cpu-mask: + Disables L2PC on masked CPUto the string.rendering thread is running on masked CPUs. + Bit 0 is for CPU-0, bit 1 is for CPU-1... + +- qcom,l2pc-update-queue: + Disables L2PC on masked CPUs at queue time when it's true. + +- qcom,snapshot-size: + Specify the size of snapshot in bytes. This will override + snapshot size defined in the driver code. + +- qcom,enable-ca-jump: + Boolean. Enables use of context aware DCVS +- qcom,ca-busy-penalty: + This property represents the time in microseconds required to + initiate context aware power level jump. +- qcom,ca-target-pwrlevel: + This value indicates which qcom,gpu-pwrlevel to jump on in case + of context aware power level jump. + +- qcom,gpu-qdss-stm: + + baseAddr - base address of the gpu channels in the qdss stm memory region + size - size of the gpu stm region + +- qcom,gpu-qtimer: + + baseAddr - base address of the qtimer memory region + size - size of the qtimer region + +- qcom,tsens-name: + Specify the name of GPU temperature sensor. This name will be used + to get the temperature from the thermal driver API. + +- qcom,enable-midframe-timer: + Boolean. Enables the use of midframe sampling timer. This timer + samples the GPU powerstats if the cmdbatch expiry takes longer than + the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if + target has NAP state enabled. + nvmem-cells: + A phandle to the configuration data such as gpu speed bin, gpu gaming mode + provided by a nvmem device. If unspecified default values shall be used. + nvmem-cell-names: + Should be "speed_bin", "gaming_bin" + +GPU Quirks: +- qcom,gpu-quirk-two-pass-use-wfi: + Signal the GPU to set Set TWOPASSUSEWFI bit in + PC_DBG_ECO_CNTL (5XX and 6XX only) +- qcom,gpu-quirk-critical-packets: + Submit a set of critical PM4 packets when the GPU wakes up +- qcom,gpu-quirk-fault-detect-mask: + Mask out RB1-3 activity signals from HW hang + detection logic +- qcom,gpu-quirk-dp2clockgating-disable: + Disable RB sampler data path clock gating optimization +- qcom,gpu-quirk-lmloadkill-disable: + Use register setting to disable local memory(LM) feature + to avoid corner case error +- qcom,gpu-quirk-hfi-use-reg: + Use registers to replace DCVS HFI message to avoid GMU failure + to access system memory during IFPC +- qcom,gpu-quirk-limit-uche-gbif-rw: + Limit number of read and write transactions from UCHE block to + GBIF to avoid possible deadlock between GBIF, SMMU and MEMNOC. +- qcom,gpu-quirk-mmu-secure-cb-alt: + Select alternate secure context bank to generate SID1 for + secure playback. + +KGSL Memory Pools: +- qcom,gpu-mempools: Container for sets of GPU mempools.Multiple sets + (pools) can be defined within qcom,gpu-mempools. + Each mempool defines a pool order, reserved pages, + allocation allowed. +Properties: +- compatible: Should be qcom,gpu-mempools or qcom,gpu-mempools-lowmem. +- qcom,mempool-max-pages: Max pages for all mempools, If not defined there is no limit. +- qcom,gpu-mempool: Defines a set of mempools. + +Properties: +- reg: Index of the pool (0 = lowest pool order). +- qcom,mempool-page-size: Size of page. +- qcom,mempool-reserved: Number of pages reserved at init time for a pool. +- qcom,mempool-allocate: Allocate memory from the system memory when the + reserved pool exhausted. +- qcom,mempool-max-pages: Limit on max pages this pool can hold, If not defined + there is no limit. +GPU CX Ipeak: +- qcom,gpu-cx-ipeak: Container for GPU CX ipeak clients. Multiple clients + can be defined within qcom,gpu-cx-ipeak. Each client + specifies the data required by CX Ipeak driver for + registration and frequency value for which this client + will be used. +Properties: +- compatible: Must be qcom,gpu-cx-ipeak. +- qcom,gpu-cx-ipeak: Defines a CX Ipeak client. + +Properties: +- qcom,gpu-cx-ipeak: + CX Ipeak is a mitigation scheme which throttles cDSP frequency + if all the clients are running at their respective threshold + frequencies to limit CX peak current. + + phandle - phandle of CX Ipeak device node + bit - Every bit corresponds to a client of CX Ipeak + driver in the relevant register. +- qcom,gpu-cx-ipeak-freq: + GPU frequency threshold for CX Ipeak voting. GPU votes + to CX Ipeak driver when GPU clock crosses this threshold. + CX Ipeak can limit peak current based on voting from other client. + +SOC Hardware revisions: +- qcom,soc-hw-revisions: + Container of sets of SOC hardware revisions specified by + qcom,soc-hw-revision. +Properties: +- compatible: + Must be qcom,soc-hw-revisions. + +- qcom,soc-hw-revision: + Defines a SOC hardware revision. + +Properties: +- qcom,soc-hw-revision: + Identifier for the hardware revision - must match the value read + from the hardware. +- qcom,chipid: + GPU Chip ID to be used for this hardware revision. +- qcom,gpu-quirk-*: + GPU quirks applicable for this hardware revision. + +GPU LLC slice info: +- cache-slice-names: List of LLC cache slices for GPU transactions + and pagetable walk. +- cache-slices: phandle to the system LLC driver, cache slice index. + +L3 Power levels: +- qcom,l3-pwrlevels: Container for sets of L3 power levels, the + L3 frequency is adjusted according to the + performance hint received from userspace. + +Properties: +- compatible: Must be qcom,l3-pwrlevels +- qcom,l3-pwrlevel: A single L3 powerlevel + +Properties: +- reg: Index of the L3 powerlevel + 0 = powerlevel for no L3 vote + 1 = powerlevel for medium L3 vote + 2 = powerlevel for maximum L3 vote +- qcom,l3-freq: The L3 frequency for the powerlevel (in Hz) + +GPU coresight info: +The following properties are optional as collecting data via coresight might +not be supported for every chipset. The documentation for coresight +properties can be found in: +Documentation/devicetree/bindings/coresight/coresight.txt + +- qcom,gpu-coresights: Container for sets of GPU coresight sources. +- coresight-id: Unique integer identifier for the bus. +- coresight-name: Unique descriptive name of the bus. +- coresight-nr-inports: Number of input ports on the bus. +- coresight-outports: List of output port numbers on the bus. +- coresight-child-list: List of phandles pointing to the children of this + component. +- coresight-child-ports: List of input port numbers of the children. +- coresight-atid: The unique ATID value of the coresight device + +Example of A330 GPU in MSM8916: + +&soc { + msm_gpu: qcom,kgsl-3d0@1c00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + reg = <0x1c00000 0x10000 + 0x1c20000 0x20000>; + reg-names = "kgsl_3d0_reg_memory" , "kgsl_3d0_shader_memory"; + interrupts = <0 33 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x03000600>; + + qcom,initial-pwrlevel = <1>; + + /* Idle Timeout = HZ/12 */ + qcom,idle-timeout = <8>; + qcom,strtstp-sleepwake; + + clocks = <&clock_gcc clk_gcc_oxili_gfx3d_clk>, + <&clock_gcc clk_gcc_oxili_ahb_clk>, + <&clock_gcc clk_gcc_oxili_gmem_clk>, + <&clock_gcc clk_gcc_bimc_gfx_clk>, + <&clock_gcc clk_gcc_bimc_gpu_clk>; + clock-names = "core_clk", "iface_clk", "mem_clk", + "mem_iface_clk", "alt_mem_iface_clk"; + + /* Bus Scale Settings */ + qcom, gpu-bus-table { + compatible="qcom,gpu-bus-table","qcom,gpu-bus-table-ddr7"; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 1600000>, + <26 512 0 3200000>, + <26 512 0 4264000>; + }; + + /* GDSC oxili regulators */ + vdd-supply = <&gdsc_oxili_gx>; + + nvmem-cells = <&gpu_speed_bin>, <&gpu_gaming_bin>; + nvmem-cell-names = "speed_bin", "gaming_bin"; + + /* IOMMU Data */ + iommu = <&gfx_iommu>; + + /* Trace bus */ + coresight-id = <67>; + coresight-name = "coresight-gfx"; + coresight-nr-inports = <0>; + coresight-outports = <0>; + coresight-child-list = <&funnel_in0>; + coresight-child-ports = <5>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <1>; + + qcom,gpu-cx-ipeak { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-cx-ipeak"; + + qcom,gpu-cx-ipeak@0 { + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 10>; + qcom,gpu-cx-ipeak-freq = <980000000>; + }; + + qcom,gpu-cx-ipeak@1 { + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 1>; + qcom,gpu-cx-ipeak-freq = <900000000>; + }; + }; + + qcom,soc-hw-revisions { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,soc-hw-revisions"; + + qcom,soc-hw-revision@0 { + reg = <0>; + + qcom,chipid = <0x06010500>; + qcom,gpu-quirk-hfi-use-reg; + qcom,gpu-quirk-limit-uche-gbif-rw; + }; + + qcom,soc-hw-revision@1 { + reg = <1>; + + qcom,chipid = <0x06010501>; + qcom,gpu-quirk-hfi-use-reg; + }; + }; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells= <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-reserved = <2048>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-reserved = <1024>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* Power levels */ + qcom,gpu-pwrlevels-bins { + #address-cells = <1>; + #size-cells = <0>; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + qcom,ca-target-pwrlevel = <1>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <3>; + qcom,io-fraction = <33>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <310000000>; + qcom,bus-freq = <2>; + qcom,io-fraction = <66>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <200000000>; + qcom,bus-freq = <1>; + qcom,io-fraction = <100>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <27000000>; + qcom,bus-freq = <0>; + qcom,io-fraction = <0>; + }; + }; + }; + + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/arm,mali-midgard.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/arm,mali-midgard.txt new file mode 100644 index 0000000000000000000000000000000000000000..18a2cde2e5f3a96c89067ea5cafd60fe4c71a0bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/arm,mali-midgard.txt @@ -0,0 +1,87 @@ +ARM Mali Midgard GPU +==================== + +Required properties: + +- compatible : + * Must contain one of the following: + + "arm,mali-t604" + + "arm,mali-t624" + + "arm,mali-t628" + + "arm,mali-t720" + + "arm,mali-t760" + + "arm,mali-t820" + + "arm,mali-t830" + + "arm,mali-t860" + + "arm,mali-t880" + * which must be preceded by one of the following vendor specifics: + + "amlogic,meson-gxm-mali" + + "rockchip,rk3288-mali" + + "rockchip,rk3399-mali" + +- reg : Physical base address of the device and length of the register area. + +- interrupts : Contains the three IRQ lines required by Mali Midgard devices. + +- interrupt-names : Contains the names of IRQ resources in the order they were + provided in the interrupts property. Must contain: "job", "mmu", "gpu". + + +Optional properties: + +- clocks : Phandle to clock for the Mali Midgard device. + +- mali-supply : Phandle to regulator for the Mali device. Refer to + Documentation/devicetree/bindings/regulator/regulator.txt for details. + +- operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt + for details. + + +Example for a Mali-T760: + +gpu@ffa30000 { + compatible = "rockchip,rk3288-mali", "arm,mali-t760"; + reg = <0xffa30000 0x10000>; + interrupts = , + , + ; + interrupt-names = "job", "mmu", "gpu"; + clocks = <&cru ACLK_GPU>; + mali-supply = <&vdd_gpu>; + operating-points-v2 = <&gpu_opp_table>; + power-domains = <&power RK3288_PD_GPU>; +}; + +gpu_opp_table: opp_table0 { + compatible = "operating-points-v2"; + + opp@533000000 { + opp-hz = /bits/ 64 <533000000>; + opp-microvolt = <1250000>; + }; + opp@450000000 { + opp-hz = /bits/ 64 <450000000>; + opp-microvolt = <1150000>; + }; + opp@400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <1125000>; + }; + opp@350000000 { + opp-hz = /bits/ 64 <350000000>; + opp-microvolt = <1075000>; + }; + opp@266000000 { + opp-hz = /bits/ 64 <266000000>; + opp-microvolt = <1025000>; + }; + opp@160000000 { + opp-hz = /bits/ 64 <160000000>; + opp-microvolt = <925000>; + }; + opp@100000000 { + opp-hz = /bits/ 64 <100000000>; + opp-microvolt = <912500>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/arm,mali-utgard.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/arm,mali-utgard.txt new file mode 100644 index 0000000000000000000000000000000000000000..63cd91176a688b5faf24b37dfd959dbeb1c7376d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/arm,mali-utgard.txt @@ -0,0 +1,112 @@ +ARM Mali Utgard GPU +=================== + +Required properties: + - compatible + * Must be one of the following: + + "arm,mali-300" + + "arm,mali-400" + + "arm,mali-450" + * And, optionally, one of the vendor specific compatible: + + allwinner,sun4i-a10-mali + + allwinner,sun7i-a20-mali + + allwinner,sun8i-h3-mali + + allwinner,sun50i-h5-mali + + amlogic,meson-gxbb-mali + + amlogic,meson-gxl-mali + + rockchip,rk3036-mali + + rockchip,rk3066-mali + + rockchip,rk3188-mali + + rockchip,rk3228-mali + + rockchip,rk3328-mali + + stericsson,db8500-mali + + - reg: Physical base address and length of the GPU registers + + - interrupts: an entry for each entry in interrupt-names. + See ../interrupt-controller/interrupts.txt for details. + + - interrupt-names: + * ppX: Pixel Processor X interrupt (X from 0 to 7) + * ppmmuX: Pixel Processor X MMU interrupt (X from 0 to 7) + * pp: Pixel Processor broadcast interrupt (mali-450 only) + * gp: Geometry Processor interrupt + * gpmmu: Geometry Processor MMU interrupt + + - clocks: an entry for each entry in clock-names + - clock-names: + * bus: bus clock for the GPU + * core: clock driving the GPU itself + +Optional properties: + - interrupt-names and interrupts: + * pmu: Power Management Unit interrupt, if implemented in hardware + + - memory-region: + Memory region to allocate from, as defined in + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt + + - mali-supply: + Phandle to regulator for the Mali device, as defined in + Documentation/devicetree/bindings/regulator/regulator.txt for details. + + - operating-points-v2: + Operating Points for the GPU, as defined in + Documentation/devicetree/bindings/opp/opp.txt + + - power-domains: + A power domain consumer specifier as defined in + Documentation/devicetree/bindings/power/power_domain.txt + +Vendor-specific bindings +------------------------ + +The Mali GPU is integrated very differently from one SoC to +another. In order to accomodate those differences, you have the option +to specify one more vendor-specific compatible, among: + + - allwinner,sun4i-a10-mali + Required properties: + * resets: phandle to the reset line for the GPU + + - allwinner,sun7i-a20-mali + Required properties: + * resets: phandle to the reset line for the GPU + + - allwinner,sun50i-h5-mali + Required properties: + * resets: phandle to the reset line for the GPU + + - Rockchip variants: + Required properties: + * resets: phandle to the reset line for the GPU + + - stericsson,db8500-mali + Required properties: + * interrupt-names and interrupts: + + combined: combined interrupt of all of the above lines + +Example: + +mali: gpu@1c40000 { + compatible = "allwinner,sun7i-a20-mali", "arm,mali-400"; + reg = <0x01c40000 0x10000>; + interrupts = , + , + , + , + , + , + ; + interrupt-names = "gp", + "gpmmu", + "pp0", + "ppmmu0", + "pp1", + "ppmmu1", + "pmu"; + clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>; + clock-names = "bus", "core"; + resets = <&ccu RST_BUS_GPU>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/brcm,bcm-v3d.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/brcm,bcm-v3d.txt new file mode 100644 index 0000000000000000000000000000000000000000..c907aa8dd755eb8083d14cdc8716b875c9820e99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/brcm,bcm-v3d.txt @@ -0,0 +1,28 @@ +Broadcom V3D GPU + +Only the Broadcom V3D 3.x and newer GPUs are covered by this binding. +For V3D 2.x, see brcm,bcm-vc4.txt. + +Required properties: +- compatible: Should be "brcm,7268-v3d" or "brcm,7278-v3d" +- reg: Physical base addresses and lengths of the register areas +- reg-names: Names for the register areas. The "hub", "bridge", and "core0" + register areas are always required. The "gca" register area + is required if the GCA cache controller is present. +- interrupts: The interrupt numbers. The first interrupt is for the hub, + while the following interrupts are for the cores. + See bindings/interrupt-controller/interrupts.txt + +Optional properties: +- clocks: The core clock the unit runs on + +v3d { + compatible = "brcm,7268-v3d"; + reg = <0xf1204000 0x100>, + <0xf1200000 0x4000>, + <0xf1208000 0x4000>, + <0xf1204100 0x100>; + reg-names = "bridge", "hub", "core0", "gca"; + interrupts = <0 78 4>, + <0 77 4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/nvidia,gk20a.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/nvidia,gk20a.txt new file mode 100644 index 0000000000000000000000000000000000000000..f32bbba4d3bca902242049fabd1a2d92eca36cc5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/nvidia,gk20a.txt @@ -0,0 +1,90 @@ +NVIDIA Tegra Graphics Processing Units + +Required properties: +- compatible: "nvidia," + Currently recognized values: + - nvidia,gk20a + - nvidia,gm20b + - nvidia,gp10b +- reg: Physical base address and length of the controller's registers. + Must contain two entries: + - first entry for bar0 + - second entry for bar1 +- interrupts: Must contain an entry for each entry in interrupt-names. + See ../interrupt-controller/interrupts.txt for details. +- interrupt-names: Must include the following entries: + - stall + - nonstall +- vdd-supply: regulator for supply voltage. Only required for GPUs not using + power domains. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - gpu + - pwr +If the compatible string is "nvidia,gm20b", then the following clock +is also required: + - ref +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - gpu +- power-domains: GPUs that make use of power domains can define this property + instead of vdd-supply. Currently "nvidia,gp10b" makes use of this. + +Optional properties: +- iommus: A reference to the IOMMU. See ../iommu/iommu.txt for details. + +Example for GK20A: + + gpu@57000000 { + compatible = "nvidia,gk20a"; + reg = <0x0 0x57000000 0x0 0x01000000>, + <0x0 0x58000000 0x0 0x01000000>; + interrupts = , + ; + interrupt-names = "stall", "nonstall"; + vdd-supply = <&vdd_gpu>; + clocks = <&tegra_car TEGRA124_CLK_GPU>, + <&tegra_car TEGRA124_CLK_PLL_P_OUT5>; + clock-names = "gpu", "pwr"; + resets = <&tegra_car 184>; + reset-names = "gpu"; + iommus = <&mc TEGRA_SWGROUP_GPU>; + }; + +Example for GM20B: + + gpu@57000000 { + compatible = "nvidia,gm20b"; + reg = <0x0 0x57000000 0x0 0x01000000>, + <0x0 0x58000000 0x0 0x01000000>; + interrupts = , + ; + interrupt-names = "stall", "nonstall"; + clocks = <&tegra_car TEGRA210_CLK_GPU>, + <&tegra_car TEGRA210_CLK_PLL_P_OUT5>, + <&tegra_car TEGRA210_CLK_PLL_G_REF>; + clock-names = "gpu", "pwr", "ref"; + resets = <&tegra_car 184>; + reset-names = "gpu"; + iommus = <&mc TEGRA_SWGROUP_GPU>; + }; + +Example for GP10B: + + gpu@17000000 { + compatible = "nvidia,gp10b"; + reg = <0x0 0x17000000 0x0 0x1000000>, + <0x0 0x18000000 0x0 0x1000000>; + interrupts = ; + interrupt-names = "stall", "nonstall"; + clocks = <&bpmp TEGRA186_CLK_GPCCLK>, + <&bpmp TEGRA186_CLK_GPU>; + clock-names = "gpu", "pwr"; + resets = <&bpmp TEGRA186_RESET_GPU>; + reset-names = "gpu"; + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_GPU>; + iommus = <&smmu TEGRA186_SID_GPU>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-g2d.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-g2d.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e7959332dbcb2bff6954e35b401d307b202e4af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-g2d.txt @@ -0,0 +1,27 @@ +* Samsung 2D Graphics Accelerator + +Required properties: + - compatible : value should be one among the following: + (a) "samsung,s5pv210-g2d" for G2D IP present in S5PV210 & Exynos4210 SoC + (b) "samsung,exynos4212-g2d" for G2D IP present in Exynos4x12 SoCs + (c) "samsung,exynos5250-g2d" for G2D IP present in Exynos5250 SoC + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : G2D interrupt number to the CPU. + - clocks : from common clock binding: handle to G2D clocks. + - clock-names : names of clocks listed in clocks property, in the same + order, depending on SoC type: + - for S5PV210 and Exynos4 based SoCs: "fimg2d" and + "sclk_fimg2d" + - for Exynos5250 SoC: "fimg2d". + +Example: + g2d@12800000 { + compatible = "samsung,s5pv210-g2d"; + reg = <0x12800000 0x1000>; + interrupts = <0 89 0>; + clocks = <&clock 177>, <&clock 277>; + clock-names = "sclk_fimg2d", "fimg2d"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-rotator.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-rotator.txt new file mode 100644 index 0000000000000000000000000000000000000000..82cd1ed0be9317cef6b7ca457f5f904d9d0e16d7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-rotator.txt @@ -0,0 +1,27 @@ +* Samsung Image Rotator + +Required properties: + - compatible : value should be one of the following: + (a) "samsung,exynos4210-rotator" for Rotator IP in Exynos4210 + (b) "samsung,exynos4212-rotator" for Rotator IP in Exynos4212/4412 + (c) "samsung,exynos5250-rotator" for Rotator IP in Exynos5250 + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : Interrupt specifier for rotator interrupt, according to format + specific to interrupt parent. + + - clocks : Clock specifier for rotator clock, according to generic clock + bindings. (See Documentation/devicetree/bindings/clock/exynos*.txt) + + - clock-names : Names of clocks. For exynos rotator, it should be "rotator". + +Example: + rotator@12810000 { + compatible = "samsung,exynos4210-rotator"; + reg = <0x12810000 0x1000>; + interrupts = <0 83 0>; + clocks = <&clock 278>; + clock-names = "rotator"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-scaler.txt b/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-scaler.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c3d98105dfd802aba4a396fde9fe7184e140f7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/gpu/samsung-scaler.txt @@ -0,0 +1,27 @@ +* Samsung Exynos Image Scaler + +Required properties: + - compatible : value should be one of the following: + (a) "samsung,exynos5420-scaler" for Scaler IP in Exynos5420 + (b) "samsung,exynos5433-scaler" for Scaler IP in Exynos5433 + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : Interrupt specifier for scaler interrupt, according to format + specific to interrupt parent. + + - clocks : Clock specifier for scaler clock, according to generic clock + bindings. (See Documentation/devicetree/bindings/clock/exynos*.txt) + + - clock-names : Names of clocks. For exynos scaler, it should be "mscl" + on 5420 and "pclk", "aclk" and "aclk_xiu" on 5433. + +Example: + scaler@12800000 { + compatible = "samsung,exynos5420-scaler"; + reg = <0x12800000 0x1294>; + interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clock CLK_MSCL0>; + clock-names = "mscl"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/graph.txt b/arch/arm64/boot/dts/vendor/bindings/graph.txt new file mode 100644 index 0000000000000000000000000000000000000000..0415e2c53ba072e8db49427d476714ee15f5221a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/graph.txt @@ -0,0 +1,128 @@ +Common bindings for device graphs + +General concept +--------------- + +The hierarchical organisation of the device tree is well suited to describe +control flow to devices, but there can be more complex connections between +devices that work together to form a logical compound device, following an +arbitrarily complex graph. +There already is a simple directed graph between devices tree nodes using +phandle properties pointing to other nodes to describe connections that +can not be inferred from device tree parent-child relationships. The device +tree graph bindings described herein abstract more complex devices that can +have multiple specifiable ports, each of which can be linked to one or more +ports of other devices. + +These common bindings do not contain any information about the direction or +type of the connections, they just map their existence. Specific properties +may be described by specialized bindings depending on the type of connection. + +To see how this binding applies to video pipelines, for example, see +Documentation/devicetree/bindings/media/video-interfaces.txt. +Here the ports describe data interfaces, and the links between them are +the connecting data buses. A single port with multiple connections can +correspond to multiple devices being connected to the same physical bus. + +Organisation of ports and endpoints +----------------------------------- + +Ports are described by child 'port' nodes contained in the device node. +Each port node contains an 'endpoint' subnode for each remote device port +connected to this port. If a single port is connected to more than one +remote device, an 'endpoint' child node must be provided for each link. +If more than one port is present in a device node or there is more than one +endpoint at a port, or a port node needs to be associated with a selected +hardware interface, a common scheme using '#address-cells', '#size-cells' +and 'reg' properties is used to number the nodes. + +device { + ... + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + endpoint@0 { + reg = <0>; + ... + }; + endpoint@1 { + reg = <1>; + ... + }; + }; + + port@1 { + reg = <1>; + + endpoint { ... }; + }; +}; + +All 'port' nodes can be grouped under an optional 'ports' node, which +allows to specify #address-cells, #size-cells properties for the 'port' +nodes independently from any other child device nodes a device might +have. + +device { + ... + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + ... + endpoint@0 { ... }; + endpoint@1 { ... }; + }; + + port@1 { ... }; + }; +}; + +Links between endpoints +----------------------- + +Each endpoint should contain a 'remote-endpoint' phandle property that points +to the corresponding endpoint in the port of the remote device. In turn, the +remote endpoint should contain a 'remote-endpoint' property. If it has one, it +must not point to anything other than the local endpoint. Two endpoints with +their 'remote-endpoint' phandles pointing at each other form a link between the +containing ports. + +device-1 { + port { + device_1_output: endpoint { + remote-endpoint = <&device_2_input>; + }; + }; +}; + +device-2 { + port { + device_2_input: endpoint { + remote-endpoint = <&device_1_output>; + }; + }; +}; + +Required properties +------------------- + +If there is more than one 'port' or more than one 'endpoint' node or 'reg' +property present in the port and/or endpoint nodes then the following +properties are required in a relevant parent node: + + - #address-cells : number of cells required to define port/endpoint + identifier, should be 1. + - #size-cells : should be zero. + +Optional endpoint properties +---------------------------- + +- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node. + diff --git a/arch/arm64/boot/dts/vendor/bindings/h8300/cpu.txt b/arch/arm64/boot/dts/vendor/bindings/h8300/cpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..70cd58608f4ba41d5f90066f6efe09862220d6a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/h8300/cpu.txt @@ -0,0 +1,13 @@ +* H8/300 CPU bindings + +Required properties: + +- compatible: Compatible property value should be "renesas,h8300". +- clock-frequency: Contains the clock frequency for CPU, in Hz. + +Example: + + cpu@0 { + compatible = "renesas,h8300"; + clock-frequency = <20000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hsi/client-devices.txt b/arch/arm64/boot/dts/vendor/bindings/hsi/client-devices.txt new file mode 100644 index 0000000000000000000000000000000000000000..104c9a3e57a497f11cd8e76877cef0c7fe72c5c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hsi/client-devices.txt @@ -0,0 +1,44 @@ +Each HSI port is supposed to have one child node, which +symbols the remote device connected to the HSI port. The +following properties are standardized for HSI clients: + +Required HSI configuration properties: + +- hsi-channel-ids: A list of channel ids + +- hsi-rx-mode: Receiver Bit transmission mode ("stream" or "frame") +- hsi-tx-mode: Transmitter Bit transmission mode ("stream" or "frame") +- hsi-mode: May be used instead hsi-rx-mode and hsi-tx-mode if + the transmission mode is the same for receiver and + transmitter +- hsi-speed-kbps: Max bit transmission speed in kbit/s +- hsi-flow: RX flow type ("synchronized" or "pipeline") +- hsi-arb-mode: Arbitration mode for TX frame ("round-robin", "priority") + +Optional HSI configuration properties: + +- hsi-channel-names: A list with one name per channel specified in the + hsi-channel-ids property + + +Device Tree node example for an HSI client: + +hsi-controller { + hsi-port { + modem: hsi-client { + compatible = "nokia,n900-modem"; + + hsi-channel-ids = <0>, <1>, <2>, <3>; + hsi-channel-names = "mcsaab-control", + "speech-control", + "speech-data", + "mcsaab-data"; + hsi-speed-kbps = <55000>; + hsi-mode = "frame"; + hsi-flow = "synchronized"; + hsi-arb-mode = "round-robin"; + + /* more client specific properties */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hsi/nokia-modem.txt b/arch/arm64/boot/dts/vendor/bindings/hsi/nokia-modem.txt new file mode 100644 index 0000000000000000000000000000000000000000..53de1d9d0b958c57dc79129569dab03d843a61a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hsi/nokia-modem.txt @@ -0,0 +1,59 @@ +Nokia modem client bindings + +The Nokia modem HSI client follows the common HSI client binding +and inherits all required properties. The following additional +properties are needed by the Nokia modem HSI client: + +Required properties: +- compatible: Should be one of + "nokia,n900-modem" + "nokia,n950-modem" + "nokia,n9-modem" +- hsi-channel-names: Should contain the following strings + "mcsaab-control" + "speech-control" + "speech-data" + "mcsaab-data" +- gpios: Should provide a GPIO handler for each GPIO listed in + gpio-names +- gpio-names: Should contain the following strings + "cmt_apeslpx" (for n900, n950, n9) + "cmt_rst_rq" (for n900, n950, n9) + "cmt_en" (for n900, n950, n9) + "cmt_rst" (for n900) + "cmt_bsi" (for n900) +- interrupts: Should be IRQ handle for modem's reset indication + +Example: + +&ssi_port { + modem: hsi-client { + compatible = "nokia,n900-modem"; + + pinctrl-names = "default"; + pinctrl-0 = <&modem_pins>; + + hsi-channel-ids = <0>, <1>, <2>, <3>; + hsi-channel-names = "mcsaab-control", + "speech-control", + "speech-data", + "mcsaab-data"; + hsi-speed-kbps = <55000>; + hsi-mode = "frame"; + hsi-flow = "synchronized"; + hsi-arb-mode = "round-robin"; + + interrupts-extended = <&gpio3 8 IRQ_TYPE_EDGE_FALLING>; /* 72 */ + + gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>, /* 70 */ + <&gpio3 9 GPIO_ACTIVE_HIGH>, /* 73 */ + <&gpio3 10 GPIO_ACTIVE_HIGH>, /* 74 */ + <&gpio3 11 GPIO_ACTIVE_HIGH>, /* 75 */ + <&gpio5 29 GPIO_ACTIVE_HIGH>; /* 157 */ + gpio-names = "cmt_apeslpx", + "cmt_rst_rq", + "cmt_en", + "cmt_rst", + "cmt_bsi"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hsi/omap-ssi.txt b/arch/arm64/boot/dts/vendor/bindings/hsi/omap-ssi.txt new file mode 100644 index 0000000000000000000000000000000000000000..77a0c3c3036ec6b5d9fa09dfbf0dd470aac29ba7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hsi/omap-ssi.txt @@ -0,0 +1,102 @@ +OMAP SSI controller bindings + +OMAP3's Synchronous Serial Interface (SSI) controller implements a +legacy variant of MIPI's High Speed Synchronous Serial Interface (HSI), +while the controller found inside OMAP4 is supposed to be fully compliant +with the HSI standard. + +Required properties: +- compatible: Should include "ti,omap3-ssi" or "ti,omap4-hsi" +- reg-names: Contains the values "sys" and "gdd" (in this order). +- reg: Contains a matching register specifier for each entry + in reg-names. +- interrupt-names: Contains the value "gdd_mpu". +- interrupts: Contains matching interrupt information for each entry + in interrupt-names. +- ranges: Represents the bus address mapping between the main + controller node and the child nodes below. +- clock-names: Must include the following entries: + "ssi_ssr_fck": The OMAP clock of that name + "ssi_sst_fck": The OMAP clock of that name + "ssi_ick": The OMAP clock of that name +- clocks: Contains a matching clock specifier for each entry in + clock-names. +- #address-cells: Should be set to <1> +- #size-cells: Should be set to <1> + +Each port is represented as a sub-node of the ti,omap3-ssi device. + +Required Port sub-node properties: +- compatible: Should be set to the following value + ti,omap3-ssi-port (applicable to OMAP34xx devices) + ti,omap4-hsi-port (applicable to OMAP44xx devices) +- reg-names: Contains the values "tx" and "rx" (in this order). +- reg: Contains a matching register specifier for each entry + in reg-names. +- interrupts: Should contain interrupt specifiers for mpu interrupts + 0 and 1 (in this order). +- ti,ssi-cawake-gpio: Defines which GPIO pin is used to signify CAWAKE + events for the port. This is an optional board-specific + property. If it's missing the port will not be + enabled. + +Optional properties: +- ti,hwmods: Shall contain TI interconnect module name if needed + by the SoC + +Example for Nokia N900: + +ssi-controller@48058000 { + compatible = "ti,omap3-ssi"; + + /* needed until hwmod is updated to use the compatible string */ + ti,hwmods = "ssi"; + + reg = <0x48058000 0x1000>, + <0x48059000 0x1000>; + reg-names = "sys", + "gdd"; + + interrupts = <55>; + interrupt-names = "gdd_mpu"; + + clocks = <&ssi_ssr_fck>, + <&ssi_sst_fck>, + <&ssi_ick>; + clock-names = "ssi_ssr_fck", + "ssi_sst_fck", + "ssi_ick"; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ssi-port@4805a000 { + compatible = "ti,omap3-ssi-port"; + + reg = <0x4805a000 0x800>, + <0x4805a800 0x800>; + reg-names = "tx", + "rx"; + + interrupt-parent = <&intc>; + interrupts = <67>, + <68>; + + ti,ssi-cawake-gpio = <&gpio5 23 GPIO_ACTIVE_HIGH>; /* 151 */ + } + + ssi-port@4805a000 { + compatible = "ti,omap3-ssi-port"; + + reg = <0x4805b000 0x800>, + <0x4805b800 0x800>; + reg-names = "tx", + "rx"; + + interrupt-parent = <&intc>; + interrupts = <69>, + <70>; + + } +} diff --git a/arch/arm64/boot/dts/vendor/bindings/hwlock/hwlock.txt b/arch/arm64/boot/dts/vendor/bindings/hwlock/hwlock.txt new file mode 100644 index 0000000000000000000000000000000000000000..085d1f5c916a42d53d06f70eddfb002634172b39 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwlock/hwlock.txt @@ -0,0 +1,59 @@ +Generic hwlock bindings +======================= + +Generic bindings that are common to all the hwlock platform specific driver +implementations. + +Please also look through the individual platform specific hwlock binding +documentations for identifying any additional properties specific to that +platform. + +hwlock providers: +================= + +Required properties: +- #hwlock-cells: Specifies the number of cells needed to represent a + specific lock. + +hwlock users: +============= + +Consumers that require specific hwlock(s) should specify them using the +property "hwlocks", and an optional "hwlock-names" property. + +Required properties: +- hwlocks: List of phandle to a hwlock provider node and an + associated hwlock args specifier as indicated by + #hwlock-cells. The list can have just a single hwlock + or multiple hwlocks, with each hwlock represented by + a phandle and a corresponding args specifier. + +Optional properties: +- hwlock-names: List of hwlock name strings defined in the same order + as the hwlocks, with one name per hwlock. Consumers can + use the hwlock-names to match and get a specific hwlock. + + +1. Example of a node using a single specific hwlock: + +The following example has a node requesting a hwlock in the bank defined by +the node hwlock1. hwlock1 is a hwlock provider with an argument specifier +of length 1. + + node { + ... + hwlocks = <&hwlock1 2>; + ... + }; + +2. Example of a node using multiple specific hwlocks: + +The following example has a node requesting two hwlocks, a hwlock within +the hwlock device node 'hwlock1' with #hwlock-cells value of 1, and another +hwlock within the hwlock device node 'hwlock2' with #hwlock-cells value of 2. + + node { + ... + hwlocks = <&hwlock1 2>, <&hwlock2 0 3>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwlock/omap-hwspinlock.txt b/arch/arm64/boot/dts/vendor/bindings/hwlock/omap-hwspinlock.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c9804f4f4ac1cd206f6eff8fe5bae8c8d0d02ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwlock/omap-hwspinlock.txt @@ -0,0 +1,26 @@ +OMAP4+ HwSpinlock Driver +======================== + +Required properties: +- compatible: Should be "ti,omap4-hwspinlock" for + OMAP44xx, OMAP54xx, AM33xx, AM43xx, DRA7xx SoCs +- reg: Contains the hwspinlock module register address space + (base address and length) +- ti,hwmods: Name of the hwmod associated with the hwspinlock device +- #hwlock-cells: Should be 1. The OMAP hwspinlock users will use a + 0-indexed relative hwlock number as the argument + specifier value for requesting a specific hwspinlock + within a hwspinlock bank. + +Please look at the generic hwlock binding for usage information for consumers, +"Documentation/devicetree/bindings/hwlock/hwlock.txt" + +Example: + +/* OMAP4 */ +hwspinlock: spinlock@4a0f6000 { + compatible = "ti,omap4-hwspinlock"; + reg = <0x4a0f6000 0x1000>; + ti,hwmods = "spinlock"; + #hwlock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwlock/qcom-hwspinlock.txt b/arch/arm64/boot/dts/vendor/bindings/hwlock/qcom-hwspinlock.txt new file mode 100644 index 0000000000000000000000000000000000000000..4563f524556b351717e05ea4c09cd3fe6e89778e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwlock/qcom-hwspinlock.txt @@ -0,0 +1,39 @@ +Qualcomm Hardware Mutex Block: + +The hardware block provides mutexes utilized between different processors on +the SoC as part of the communication protocol used by these processors. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,sfpb-mutex", + "qcom,tcsr-mutex" + +- syscon: + Usage: required + Value type: + Definition: one cell containing: + syscon phandle + offset of the hwmutex block within the syscon + stride of the hwmutex registers + +- #hwlock-cells: + Usage: required + Value type: + Definition: must be 1, the specified cell represent the lock id + (hwlock standard property, see hwlock.txt) + +Example: + + tcsr_mutex_block: syscon@fd484000 { + compatible = "syscon"; + reg = <0xfd484000 0x2000>; + }; + + hwlock@fd484000 { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x80>; + + #hwlock-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwlock/sirf,hwspinlock.txt b/arch/arm64/boot/dts/vendor/bindings/hwlock/sirf,hwspinlock.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bb1240a68e0cd7a53f9e1c1f5118690a6a76ca6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwlock/sirf,hwspinlock.txt @@ -0,0 +1,28 @@ +SIRF Hardware spinlock device Binding +----------------------------------------------- + +Required properties : +- compatible : shall contain only one of the following: + "sirf,hwspinlock" + +- reg : the register address of hwspinlock + +- #hwlock-cells : hwlock users only use the hwlock id to represent a specific + hwlock, so the number of cells should be <1> here. + +Please look at the generic hwlock binding for usage information for consumers, +"Documentation/devicetree/bindings/hwlock/hwlock.txt" + +Example of hwlock provider: + hwlock { + compatible = "sirf,hwspinlock"; + reg = <0x13240000 0x00010000>; + #hwlock-cells = <1>; + }; + +Example of hwlock users: + node { + ... + hwlocks = <&hwlock 2>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwlock/sprd-hwspinlock.txt b/arch/arm64/boot/dts/vendor/bindings/hwlock/sprd-hwspinlock.txt new file mode 100644 index 0000000000000000000000000000000000000000..581db9d941bad570334103f457971f0bb1cfe397 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwlock/sprd-hwspinlock.txt @@ -0,0 +1,23 @@ +SPRD Hardware Spinlock Device Binding +------------------------------------- + +Required properties : +- compatible : should be "sprd,hwspinlock-r3p0". +- reg : the register address of hwspinlock. +- #hwlock-cells : hwlock users only use the hwlock id to represent a specific + hwlock, so the number of cells should be <1> here. +- clock-names : Must contain "enable". +- clocks : Must contain a phandle entry for the clock in clock-names, see the + common clock bindings. + +Please look at the generic hwlock binding for usage information for consumers, +"Documentation/devicetree/bindings/hwlock/hwlock.txt" + +Example of hwlock provider: + hwspinlock@40500000 { + compatible = "sprd,hwspinlock-r3p0"; + reg = <0 0x40500000 0 0x1000>; + #hwlock-cells = <1>; + clock-names = "enable"; + clocks = <&clk_aon_apb_gates0 22>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/adc128d818.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/adc128d818.txt new file mode 100644 index 0000000000000000000000000000000000000000..08bab0e94d25a21b8ed4d87738641e5ffe74bfa2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/adc128d818.txt @@ -0,0 +1,38 @@ +TI ADC128D818 ADC System Monitor With Temperature Sensor +-------------------------------------------------------- + +Operation modes: + + - Mode 0: 7 single-ended voltage readings (IN0-IN6), + 1 temperature reading (internal) + - Mode 1: 8 single-ended voltage readings (IN0-IN7), + no temperature + - Mode 2: 4 pseudo-differential voltage readings + (IN0-IN1, IN3-IN2, IN4-IN5, IN7-IN6), + 1 temperature reading (internal) + - Mode 3: 4 single-ended voltage readings (IN0-IN3), + 2 pseudo-differential voltage readings + (IN4-IN5, IN7-IN6), + 1 temperature reading (internal) + +If no operation mode is configured via device tree, the driver keeps the +currently active chip operation mode (default is mode 0). + + +Required node properties: + + - compatible: must be set to "ti,adc128d818" + - reg: I2C address of the device + +Optional node properties: + + - ti,mode: Operation mode (see above). + + +Example (operation mode 2): + + adc128d818@1d { + compatible = "ti,adc128d818"; + reg = <0x1d>; + ti,mode = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ads1015.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ads1015.txt new file mode 100644 index 0000000000000000000000000000000000000000..918a507d1159f9aaaef2211f5ee9994b9f330f0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ads1015.txt @@ -0,0 +1,73 @@ +ADS1015 (I2C) + +This device is a 12-bit A-D converter with 4 inputs. + +The inputs can be used single ended or in certain differential combinations. + +For configuration all possible combinations are mapped to 8 channels: + 0: Voltage over AIN0 and AIN1. + 1: Voltage over AIN0 and AIN3. + 2: Voltage over AIN1 and AIN3. + 3: Voltage over AIN2 and AIN3. + 4: Voltage over AIN0 and GND. + 5: Voltage over AIN1 and GND. + 6: Voltage over AIN2 and GND. + 7: Voltage over AIN3 and GND. + +Each channel can be configured individually: + - pga is the programmable gain amplifier (values are full scale) + 0: +/- 6.144 V + 1: +/- 4.096 V + 2: +/- 2.048 V (default) + 3: +/- 1.024 V + 4: +/- 0.512 V + 5: +/- 0.256 V + - data_rate in samples per second + 0: 128 + 1: 250 + 2: 490 + 3: 920 + 4: 1600 (default) + 5: 2400 + 6: 3300 + +1) The /ads1015 node + + Required properties: + + - compatible : must be "ti,ads1015" + - reg : I2C bus address of the device + - #address-cells : must be <1> + - #size-cells : must be <0> + + The node contains child nodes for each channel that the platform uses. + + Example ADS1015 node: + + ads1015@49 { + compatible = "ti,ads1015"; + reg = <0x49>; + #address-cells = <1>; + #size-cells = <0>; + + [ child node definitions... ] + } + +2) channel nodes + + Required properties: + + - reg : the channel number + + Optional properties: + + - ti,gain : the programmable gain amplifier setting + - ti,datarate : the converter data rate + + Example ADS1015 channel node: + + channel@4 { + reg = <4>; + ti,gain = <3>; + ti,datarate = <5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ads7828.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ads7828.txt new file mode 100644 index 0000000000000000000000000000000000000000..fe0cc4ad7ea9f289d650e71895145fbaeb2c7b02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ads7828.txt @@ -0,0 +1,25 @@ +ads7828 properties + +Required properties: +- compatible: Should be one of + ti,ads7828 + ti,ads7830 +- reg: I2C address + +Optional properties: + +- ti,differential-input + Set to use the device in differential mode. +- vref-supply + The external reference on the device is set to this regulators output. If it + does not exists the internal reference will be used and output by the ads78xx + on the "external vref" pin. + + Example ADS7828 node: + + ads7828: ads@48 { + comatible = "ti,ads7828"; + reg = <0x48>; + vref-supply = <&vref>; + ti,differential-input; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/apm-xgene-hwmon.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/apm-xgene-hwmon.txt new file mode 100644 index 0000000000000000000000000000000000000000..59b38557f1bb6d5b57e107bd4ed1b5ccf70c261e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/apm-xgene-hwmon.txt @@ -0,0 +1,14 @@ +APM X-Gene hwmon driver + +APM X-Gene SOC sensors are accessed over the "SLIMpro" mailbox. + +Required properties : + - compatible : should be "apm,xgene-slimpro-hwmon" + - mboxes : use the label reference for the mailbox as the first parameter. + The second parameter is the channel number. + +Example : + hwmonslimpro { + compatible = "apm,xgene-slimpro-hwmon"; + mboxes = <&mailbox 7>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/aspeed-pwm-tacho.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/aspeed-pwm-tacho.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ac02988a1a58013e16ba78945fb7a587544edbb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/aspeed-pwm-tacho.txt @@ -0,0 +1,73 @@ +ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver + +The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho +controller can support upto 16 Fan tachometer inputs. + +There can be upto 8 fans supported. Each fan can have one PWM output and +one/two Fan tach inputs. + +Required properties for pwm-tacho node: +- #address-cells : should be 1. + +- #size-cells : should be 1. + +- #cooling-cells: should be 2. + +- reg : address and length of the register set for the device. + +- pinctrl-names : a pinctrl state named "default" must be defined. + +- pinctrl-0 : phandle referencing pin configuration of the PWM ports. + +- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and + "aspeed,ast2500-pwm-tacho" for AST2500. + +- clocks : phandle to clock provider with the clock number in the second cell + +- resets : phandle to reset controller with the reset number in the second cell + +fan subnode format: +=================== +Under fan subnode there can upto 8 child nodes, with each child node +representing a fan. If there are 8 fans each fan can have one PWM port and +one/two Fan tach inputs. +For PWM port can be configured cooling-levels to create cooling device. +Cooling device could be bound to a thermal zone for the thermal control. + +Required properties for each child node: +- reg : should specify PWM source port. + integer value in the range 0 to 7 with 0 indicating PWM port A and + 7 indicating PWM port H. + +- cooling-levels: PWM duty cycle values in a range from 0 to 255 + which correspond to thermal cooling states. + +- aspeed,fan-tach-ch : should specify the Fan tach input channel. + integer value in the range 0 through 15, with 0 indicating + Fan tach channel 0 and 15 indicating Fan tach channel 15. + Atleast one Fan tach input channel is required. + +Examples: + +pwm_tacho: pwmtachocontroller@1e786000 { + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + reg = <0x1E786000 0x1000>; + compatible = "aspeed,ast2500-pwm-tacho"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_PWM>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>; + + fan@0 { + reg = <0x00>; + cooling-levels = /bits/ 8 <125 151 177 203 229 255>; + aspeed,fan-tach-ch = /bits/ 8 <0x00>; + }; + + fan@1 { + reg = <0x01>; + aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/g762.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/g762.txt new file mode 100644 index 0000000000000000000000000000000000000000..25cc6d8ee575e5dd17d2d4c085a3473804c774aa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/g762.txt @@ -0,0 +1,47 @@ +GMT G762/G763 PWM Fan controller + +Required node properties: + + - "compatible": must be either "gmt,g762" or "gmt,g763" + - "reg": I2C bus address of the device + - "clocks": a fixed clock providing input clock frequency + on CLK pin of the chip. + +Optional properties: + + - "fan_startv": fan startup voltage. Accepted values are 0, 1, 2 and 3. + The higher the more. + + - "pwm_polarity": pwm polarity. Accepted values are 0 (positive duty) + and 1 (negative duty). + + - "fan_gear_mode": fan gear mode. Supported values are 0, 1 and 2. + +If an optional property is not set in .dts file, then current value is kept +unmodified (e.g. u-boot installed value). + +Additional information on operational parameters for the device is available +in Documentation/hwmon/g762. A detailed datasheet for the device is available +at http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf. + +Example g762 node: + + clocks { + #address-cells = <1>; + #size-cells = <0>; + + g762_clk: fixedclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <8192>; + } + } + + g762: g762@3e { + compatible = "gmt,g762"; + reg = <0x3e>; + clocks = <&g762_clk> + fan_gear_mode = <0>; /* chip default */ + fan_startv = <1>; /* chip default */ + pwm_polarity = <0>; /* chip default */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/gpio-fan.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/gpio-fan.txt new file mode 100644 index 0000000000000000000000000000000000000000..2becdcfdc840c60e6d02ffe0f3893c00eb80321d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/gpio-fan.txt @@ -0,0 +1,40 @@ +Bindings for fan connected to GPIO lines + +Required properties: +- compatible : "gpio-fan" + +Optional properties: +- gpios: Specifies the pins that map to bits in the control value, + ordered MSB-->LSB. +- gpio-fan,speed-map: A mapping of possible fan RPM speeds and the + control value that should be set to achieve them. This array + must have the RPM values in ascending order. +- alarm-gpios: This pin going active indicates something is wrong with + the fan, and a udev event will be fired. +- #cooling-cells: If used as a cooling device, must be <2> + Also see: Documentation/devicetree/bindings/thermal/thermal.txt + min and max states are derived from the speed-map of the fan. + +Note: At least one the "gpios" or "alarm-gpios" properties must be set. + +Examples: + + gpio_fan { + compatible = "gpio-fan"; + gpios = <&gpio1 14 1 + &gpio1 13 1>; + gpio-fan,speed-map = <0 0 + 3000 1 + 6000 2>; + alarm-gpios = <&gpio1 15 1>; + }; + gpio_fan_cool: gpio_fan { + compatible = "gpio-fan"; + gpios = <&gpio2 14 1 + &gpio2 13 1>; + gpio-fan,speed-map = <0 0>, + <3000 1>, + <6000 2>; + alarm-gpios = <&gpio2 15 1>; + #cooling-cells = <2>; /* min followed by max */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ibm,cffps1.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ibm,cffps1.txt new file mode 100644 index 0000000000000000000000000000000000000000..f68a0a68fc524cdc1ee547313892a34e78248800 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ibm,cffps1.txt @@ -0,0 +1,21 @@ +Device-tree bindings for IBM Common Form Factor Power Supply Version 1 +---------------------------------------------------------------------- + +Required properties: + - compatible = "ibm,cffps1"; + - reg = < I2C bus address >; : Address of the power supply on the + I2C bus. + +Example: + + i2c-bus@100 { + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + < more properties > + + power-supply@68 { + compatible = "ibm,cffps1"; + reg = <0x68>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ibmpowernv.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ibmpowernv.txt new file mode 100644 index 0000000000000000000000000000000000000000..f93242be60a145b1d823999f3c52e81a2ec63d1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ibmpowernv.txt @@ -0,0 +1,23 @@ +IBM POWERNV platform sensors +---------------------------- + +Required node properties: +- compatible: must be one of + "ibm,opal-sensor-cooling-fan" + "ibm,opal-sensor-amb-temp" + "ibm,opal-sensor-power-supply" + "ibm,opal-sensor-power" +- sensor-id: an opaque id provided by the firmware to the kernel, identifies a + given sensor and its attribute data + +Example sensors node: + +cooling-fan#8-data { + sensor-id = <0x7052107>; + compatible = "ibm,opal-sensor-cooling-fan"; +}; + +amb-temp#1-thrs { + sensor-id = <0x5096000>; + compatible = "ibm,opal-sensor-amb-temp"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ina2xx.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ina2xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..02af0d94e9217d19e8bbec945ec10e338b6eeafd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ina2xx.txt @@ -0,0 +1,24 @@ +ina2xx properties + +Required properties: +- compatible: Must be one of the following: + - "ti,ina209" for ina209 + - "ti,ina219" for ina219 + - "ti,ina220" for ina220 + - "ti,ina226" for ina226 + - "ti,ina230" for ina230 + - "ti,ina231" for ina231 +- reg: I2C address + +Optional properties: + +- shunt-resistor + Shunt resistor value in micro-Ohm + +Example: + +ina220@44 { + compatible = "ti,ina220"; + reg = <0x44>; + shunt-resistor = <1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/jc42.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/jc42.txt new file mode 100644 index 0000000000000000000000000000000000000000..f569db58f64a100b6c72e1053ce443b77ae102c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/jc42.txt @@ -0,0 +1,46 @@ +Properties for Jedec JC-42.4 compatible temperature sensors + +Required properties: +- compatible: May include a device-specific string consisting of the + manufacturer and the name of the chip. A list of supported + chip names follows. + Must include "jedec,jc-42.4-temp" for any Jedec JC-42.4 + compatible temperature sensor. + + Supported chip names: + adi,adt7408 + atmel,at30ts00 + atmel,at30tse004 + onnn,cat6095 + onnn,cat34ts02 + maxim,max6604 + microchip,mcp9804 + microchip,mcp9805 + microchip,mcp9808 + microchip,mcp98243 + microchip,mcp98244 + microchip,mcp9843 + nxp,se97 + nxp,se98 + st,stts2002 + st,stts2004 + st,stts3000 + st,stts424 + st,stts424e + idt,tse2002 + idt,tse2004 + idt,ts3000 + idt,ts3001 + +- reg: I2C address + +Optional properties: +- smbus-timeout-disable: When set, the smbus timeout function will be disabled. + This is not supported on all chips. + +Example: + +temp-sensor@1a { + compatible = "jedec,jc-42.4-temp"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/lm70.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/lm70.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea417a0d32af52adf5bd2ee63b3ee3060ae10c96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/lm70.txt @@ -0,0 +1,22 @@ +* LM70/TMP121/LM71/LM74 thermometer. + +Required properties: +- compatible: one of + "ti,lm70" + "ti,tmp121" + "ti,tmp122" + "ti,lm71" + "ti,lm74" + +See Documentation/devicetree/bindings/spi/spi-bus.txt for more required and +optional properties. + +Example: + +spi_master { + temperature-sensor@0 { + compatible = "ti,lm70"; + reg = <0>; + spi-max-frequency = <1000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/lm87.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/lm87.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1b79903f2043d6e3c16876b6651bb263afbb9fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/lm87.txt @@ -0,0 +1,30 @@ +*LM87 hwmon sensor. + +Required properties: +- compatible: Should be + "ti,lm87" + +- reg: I2C address + +optional properties: +- has-temp3: This configures pins 18 and 19 to be used as a second + remote temperature sensing channel. By default the pins + are configured as voltage input pins in0 and in5. + +- has-in6: When set, pin 5 is configured to be used as voltage input + in6. Otherwise the pin is set as FAN1 input. + +- has-in7: When set, pin 6 is configured to be used as voltage input + in7. Otherwise the pin is set as FAN2 input. + +- vcc-supply: a Phandle for the regulator supplying power, can be + cofigured to measure 5.0V power supply. Default is 3.3V. + +Example: + +lm87@2e { + compatible = "ti,lm87"; + reg = <0x2e>; + has-temp3; + vcc-supply = <®_5v0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/lm90.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/lm90.txt new file mode 100644 index 0000000000000000000000000000000000000000..97581266e329730fa7260be8d1e14473f1c9dbc0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/lm90.txt @@ -0,0 +1,50 @@ +* LM90 series thermometer. + +Required node properties: +- compatible: manufacturer and chip name, one of + "adi,adm1032" + "adi,adt7461" + "adi,adt7461a" + "gmt,g781" + "national,lm90" + "national,lm86" + "national,lm89" + "national,lm99" + "dallas,max6646" + "dallas,max6647" + "dallas,max6649" + "dallas,max6657" + "dallas,max6658" + "dallas,max6659" + "dallas,max6680" + "dallas,max6681" + "dallas,max6695" + "dallas,max6696" + "onnn,nct1008" + "winbond,w83l771" + "nxp,sa56004" + +- reg: I2C bus address of the device + +- vcc-supply: vcc regulator for the supply voltage. + +Optional properties: +- interrupts: Contains a single interrupt specifier which describes the + LM90 "-ALERT" pin output. + See interrupt-controller/interrupts.txt for the format. + +- #thermal-sensor-cells: should be set to 1. See thermal/thermal.txt for + details. See for the + definition of the local, remote and 2nd remote sensor index + constants. + +Example LM90 node: + +temp-sensor { + compatible = "onnn,nct1008"; + reg = <0x4c>; + vcc-supply = <&palmas_ldo6_reg>; + interrupt-parent = <&gpio>; + interrupts = ; + #thermal-sensor-cells = <1>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc2978.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc2978.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf2a47bbdc585547995d2084482899436de533d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc2978.txt @@ -0,0 +1,46 @@ +ltc2978 + +Required properties: +- compatible: should contain one of: + * "lltc,ltc2974" + * "lltc,ltc2975" + * "lltc,ltc2977" + * "lltc,ltc2978" + * "lltc,ltc2980" + * "lltc,ltc3880" + * "lltc,ltc3882" + * "lltc,ltc3883" + * "lltc,ltc3886" + * "lltc,ltc3887" + * "lltc,ltm2987" + * "lltc,ltm4675" + * "lltc,ltm4676" +- reg: I2C slave address + +Optional properties: +- regulators: A node that houses a sub-node for each regulator controlled by + the device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + +Valid names of regulators depend on number of supplies supported per device: + * ltc2974, ltc2975 : vout0 - vout3 + * ltc2977, ltc2980, ltm2987 : vout0 - vout7 + * ltc2978 : vout0 - vout7 + * ltc3880, ltc3882, ltc3886 : vout0 - vout1 + * ltc3883 : vout0 + * ltm4676 : vout0 - vout1 + +Example: +ltc2978@5e { + compatible = "lltc,ltc2978"; + reg = <0x5e>; + regulators { + vout0 { + regulator-name = "FPGA-2.5V"; + }; + vout2 { + regulator-name = "FPGA-1.5V"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc2990.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc2990.txt new file mode 100644 index 0000000000000000000000000000000000000000..f92f54029e84c68f7a571a4b222d43e954e856dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc2990.txt @@ -0,0 +1,36 @@ +ltc2990: Linear Technology LTC2990 power monitor + +Required properties: +- compatible: Must be "lltc,ltc2990" +- reg: I2C slave address +- lltc,meas-mode: + An array of two integers for configuring the chip measurement mode. + + The first integer defines the bits 2..0 in the control register. In all + cases the internal temperature and supply voltage are measured. In + addition the following input measurements are enabled per mode: + + 0: V1, V2, TR2 + 1: V1-V2, TR2 + 2: V1-V2, V3, V4 + 3: TR1, V3, V4 + 4: TR1, V3-V4 + 5: TR1, TR2 + 6: V1-V2, V3-V4 + 7: V1, V2, V3, V4 + + The second integer defines the bits 4..3 in the control register. This + allows a subset of the measurements to be enabled: + + 0: Internal temperature and supply voltage only + 1: TR1, V1 or V1-V2 only per mode + 2: TR2, V3 or V3-V4 only per mode + 3: All measurements per mode + +Example: + +ltc2990@4c { + compatible = "lltc,ltc2990"; + reg = <0x4c>; + lltc,meas-mode = <7 3>; /* V1, V2, V3, V4 */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc4151.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc4151.txt new file mode 100644 index 0000000000000000000000000000000000000000..d008a5ef525a7d2db246a3e4b8d3be0a7735da0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltc4151.txt @@ -0,0 +1,18 @@ +LTC4151 High Voltage I2C Current and Voltage Monitor + +Required properties: +- compatible: Must be "lltc,ltc4151" +- reg: I2C address + +Optional properties: +- shunt-resistor-micro-ohms + Shunt resistor value in micro-Ohms + Defaults to <1000> if unset. + +Example: + +ltc4151@6e { + compatible = "lltc,ltc4151"; + reg = <0x6e>; + shunt-resistor-micro-ohms = <1500>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ltq-cputemp.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltq-cputemp.txt new file mode 100644 index 0000000000000000000000000000000000000000..33fd00a987c7d924cd7b1b67970c2c6ee9100b79 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ltq-cputemp.txt @@ -0,0 +1,10 @@ +Lantiq cpu temperatur sensor + +Requires node properties: +- compatible value : + "lantiq,cputemp" + +Example: + cputemp@0 { + compatible = "lantiq,cputemp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/max1619.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/max1619.txt new file mode 100644 index 0000000000000000000000000000000000000000..c70dbbe1e56f2b8cbccc5544c8f75a75fa31a483 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/max1619.txt @@ -0,0 +1,12 @@ +Bindings for MAX1619 Temperature Sensor + +Required properties: +- compatible : "maxim,max1619" +- reg : I2C address, one of 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, or + 0x4d, 0x4e + +Example: + temp@4c { + compatible = "maxim,max1619"; + reg = <0x4c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/max31785.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/max31785.txt new file mode 100644 index 0000000000000000000000000000000000000000..106e08c56aaa9cfee0d13b5ef555495e34df4edb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/max31785.txt @@ -0,0 +1,22 @@ +Bindings for the Maxim MAX31785 Intelligent Fan Controller +========================================================== + +Reference: + +https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf + +The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan +management with temperature and remote voltage sensing. Various fan control +features are provided, including PWM frequency control, temperature hysteresis, +dual tachometer measurements, and fan health monitoring. + +Required properties: +- compatible : One of "maxim,max31785" or "maxim,max31785a" +- reg : I2C address, one of 0x52, 0x53, 0x54, 0x55. + +Example: + + fans@52 { + compatible = "maxim,max31785"; + reg = <0x52>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/max6650.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/max6650.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6bd87d8e284560bb5a3d141d6f7c4eda751edd9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/max6650.txt @@ -0,0 +1,28 @@ +Bindings for MAX6651 and MAX6650 I2C fan controllers + +Reference: +[1] https://datasheets.maximintegrated.com/en/ds/MAX6650-MAX6651.pdf + +Required properties: +- compatible : One of "maxim,max6650" or "maxim,max6651" +- reg : I2C address, one of 0x1b, 0x1f, 0x4b, 0x48. + +Optional properties, default is to retain the chip's current setting: +- maxim,fan-microvolt : The supply voltage of the fan, either 5000000 uV or + 12000000 uV. +- maxim,fan-prescale : Pre-scaling value, as per datasheet [1]. Lower values + allow more fine-grained control of slower fans. + Valid: 1, 2, 4, 8, 16. +- maxim,fan-target-rpm: Initial requested fan rotation speed. If specified, the + driver selects closed-loop mode and the requested speed. + This ensures the fan is already running before userspace + takes over. + +Example: + fan-max6650: max6650@1b { + reg = <0x1b>; + compatible = "maxim,max6650"; + maxim,fan-microvolt = <12000000>; + maxim,fan-prescale = <4>; + maxim,fan-target-rpm = <1200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/max6697.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/max6697.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f793998e4a480977780946a03356df0a691e1a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/max6697.txt @@ -0,0 +1,64 @@ +max6697 properties + +Required properties: +- compatible: + Should be one of + maxim,max6581 + maxim,max6602 + maxim,max6622 + maxim,max6636 + maxim,max6689 + maxim,max6693 + maxim,max6694 + maxim,max6697 + maxim,max6698 + maxim,max6699 +- reg: I2C address + +Optional properties: + +- smbus-timeout-disable + Set to disable SMBus timeout. If not specified, SMBus timeout will be + enabled. +- extended-range-enable + Only valid for MAX6581. Set to enable extended temperature range. + Extended temperature will be disabled if not specified. +- beta-compensation-enable + Only valid for MAX6693 and MX6694. Set to enable beta compensation on + remote temperature channel 1. + Beta compensation will be disabled if not specified. +- alert-mask + Alert bit mask. Alert disabled for bits set. + Select bit 0 for local temperature, bit 1..7 for remote temperatures. + If not specified, alert will be enabled for all channels. +- over-temperature-mask + Over-temperature bit mask. Over-temperature reporting disabled for + bits set. + Select bit 0 for local temperature, bit 1..7 for remote temperatures. + If not specified, over-temperature reporting will be enabled for all + channels. +- resistance-cancellation + Boolean for all chips other than MAX6581. Set to enable resistance + cancellation on remote temperature channel 1. + For MAX6581, resistance cancellation enabled for all channels if + specified as boolean, otherwise as per bit mask specified. + Only supported for remote temperatures (bit 1..7). + If not specified, resistance cancellation will be disabled for all + channels. +- transistor-ideality + For MAX6581 only. Two values; first is bit mask, second is ideality + select value as per MAX6581 data sheet. Select bit 1..7 for remote + channels. + Transistor ideality will be initialized to default (1.008) if not + specified. + +Example: + +temp-sensor@1a { + compatible = "maxim,max6697"; + reg = <0x1a>; + smbus-timeout-disable; + resistance-cancellation; + alert-mask = <0x72>; + over-temperature-mask = <0x7f>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/mcp3021.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/mcp3021.txt new file mode 100644 index 0000000000000000000000000000000000000000..294318ba69145405e7f9ecb363f61ff865845787 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/mcp3021.txt @@ -0,0 +1,21 @@ +mcp3021 properties + +Required properties: +- compatible: Must be one of the following: + - "microchip,mcp3021" for mcp3021 + - "microchip,mcp3221" for mcp3221 +- reg: I2C address + +Optional properties: + +- reference-voltage-microvolt + Reference voltage in microvolt (uV) + +Example: + +mcp3021@4d { + compatible = "microchip,mcp3021"; + reg = <0x4d>; + + reference-voltage-microvolt = <4500000>; /* 4.5 V */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/npcm750-pwm-fan.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/npcm750-pwm-fan.txt new file mode 100644 index 0000000000000000000000000000000000000000..28f43e929f6ddeea281c1726fc6906a3b9b2ec3c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/npcm750-pwm-fan.txt @@ -0,0 +1,84 @@ +Nuvoton NPCM7xx PWM and Fan Tacho controller device + +The Nuvoton BMC NPCM7XX supports 8 Pulse-width modulation (PWM) +controller outputs and 16 Fan tachometer controller inputs. + +Required properties for pwm-fan node +- #address-cells : should be 1. +- #size-cells : should be 0. +- compatible : "nuvoton,npcm750-pwm-fan" for Poleg NPCM7XX. +- reg : specifies physical base address and size of the registers. +- reg-names : must contain: + * "pwm" for the PWM registers. + * "fan" for the Fan registers. +- clocks : phandle of reference clocks. +- clock-names : must contain + * "pwm" for PWM controller operating clock. + * "fan" for Fan controller operating clock. +- interrupts : contain the Fan interrupts with flags for falling edge. +- pinctrl-names : a pinctrl state named "default" must be defined. +- pinctrl-0 : phandle referencing pin configuration of the PWM and Fan + controller ports. + +fan subnode format: +=================== +Under fan subnode can be upto 8 child nodes, each child node representing a fan. +Each fan subnode must have one PWM channel and atleast one Fan tach channel. + +For PWM channel can be configured cooling-levels to create cooling device. +Cooling device could be bound to a thermal zone for the thermal control. + +Required properties for each child node: +- reg : specify the PWM output channel. + integer value in the range 0 through 7, that represent + the PWM channel number that used. + +- fan-tach-ch : specify the Fan tach input channel. + integer value in the range 0 through 15, that represent + the fan tach channel number that used. + + At least one Fan tach input channel is required + +Optional property for each child node: +- cooling-levels: PWM duty cycle values in a range from 0 to 255 + which correspond to thermal cooling states. + +Examples: + +pwm_fan:pwm-fan-controller@103000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nuvoton,npcm750-pwm-fan"; + reg = <0x103000 0x2000>, + <0x180000 0x8000>; + reg-names = "pwm", "fan"; + clocks = <&clk NPCM7XX_CLK_APB3>, + <&clk NPCM7XX_CLK_APB4>; + clock-names = "pwm","fan"; + interrupts = , + , + , + , + , + , + , + ; + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pins &pwm1_pins &pwm2_pins + &fanin0_pins &fanin1_pins &fanin2_pins + &fanin3_pins &fanin4_pins>; + fan@0 { + reg = <0x00>; + fan-tach-ch = /bits/ 8 <0x00 0x01>; + cooling-levels = <127 255>; + }; + fan@1 { + reg = <0x01>; + fan-tach-ch = /bits/ 8 <0x02 0x03>; + }; + fan@2 { + reg = <0x02>; + fan-tach-ch = /bits/ 8 <0x04>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/nsa320-mcu.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/nsa320-mcu.txt new file mode 100644 index 0000000000000000000000000000000000000000..0863e067c85b02820d79fdcd68cd6eb1e789a3ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/nsa320-mcu.txt @@ -0,0 +1,20 @@ +Bindings for the fan / temperature monitor microcontroller used on +the Zyxel NSA 320 and several subsequent models. + +Required properties: +- compatible : "zyxel,nsa320-mcu" +- data-gpios : The GPIO pin connected to the data line on the MCU +- clk-gpios : The GPIO pin connected to the clock line on the MCU +- act-gpios : The GPIO pin connected to the active line on the MCU + +Example: + + hwmon { + compatible = "zyxel,nsa320-mcu"; + pinctrl-0 = <&pmx_mcu_data &pmx_mcu_clk &pmx_mcu_act>; + pinctrl-names = "default"; + + data-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; + clk-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + act-gpios = <&gpio0 17 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/ntc_thermistor.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/ntc_thermistor.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3b9c4cfe8dfe32962642e36cbe4ec625190f8d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/ntc_thermistor.txt @@ -0,0 +1,43 @@ +NTC Thermistor hwmon sensors +------------------------------- + +Requires node properties: +- "compatible" value : one of + "epcos,b57330v2103" + "murata,ncp15wb473" + "murata,ncp18wb473" + "murata,ncp21wb473" + "murata,ncp03wb473" + "murata,ncp15wl333" + "murata,ncp03wf104" + "murata,ncp15xh103" + +/* Usage of vendor name "ntc" is deprecated */ + "ntc,ncp15wb473" + "ntc,ncp18wb473" + "ntc,ncp21wb473" + "ntc,ncp03wb473" + "ntc,ncp15wl333" + +- "pullup-uv" Pull up voltage in micro volts +- "pullup-ohm" Pull up resistor value in ohms +- "pulldown-ohm" Pull down resistor value in ohms +- "connected-positive" Always ON, If not specified. + Status change is possible. +- "io-channels" Channel node of ADC to be used for + conversion. + +Optional node properties: +- "#thermal-sensor-cells" Used to expose itself to thermal fw. + +Read more about iio bindings at + Documentation/devicetree/bindings/iio/iio-bindings.txt + +Example: + ncp15wb473@0 { + compatible = "murata,ncp15wb473"; + pullup-uv = <1800000>; + pullup-ohm = <47000>; + pulldown-ohm = <0>; + io-channels = <&adc 3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/pwm-fan.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/pwm-fan.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6d533202d3e3a1a12eee650fe17125d48e5963f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/pwm-fan.txt @@ -0,0 +1,37 @@ +Bindings for a fan connected to the PWM lines + +Required properties: +- compatible : "pwm-fan" +- pwms : the PWM that is used to control the PWM fan +- cooling-levels : PWM duty cycle values in a range from 0 to 255 + which correspond to thermal cooling states + +Example: + fan0: pwm-fan { + compatible = "pwm-fan"; + cooling-min-state = <0>; + cooling-max-state = <3>; + #cooling-cells = <2>; + pwms = <&pwm 0 10000 0>; + cooling-levels = <0 102 170 230>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + thermal-sensors = <&tmu 0>; + polling-delay-passive = <0>; + polling-delay = <0>; + trips { + cpu_alert1: cpu-alert1 { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + }; + cooling-maps { + map0 { + trip = <&cpu_alert1>; + cooling-device = <&fan0 0 1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/sht15.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/sht15.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a80277cc426911f9232647dd2e6b46fe6ed8610 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/sht15.txt @@ -0,0 +1,19 @@ +Sensirion SHT15 Humidity and Temperature Sensor + +Required properties: + + - "compatible": must be "sensirion,sht15". + - "data-gpios": GPIO connected to the data line. + - "clk-gpios": GPIO connected to the clock line. + - "vcc-supply": regulator that drives the VCC pin. + +Example: + + sensor { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor>; + compatible = "sensirion,sht15"; + clk-gpios = <&gpio4 12 0>; + data-gpios = <&gpio4 13 0>; + vcc-supply = <®_sht15>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/stts751.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/stts751.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ee1dc30e72f86b55e0804f869c8d893be0e9e53 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/stts751.txt @@ -0,0 +1,15 @@ +* STTS751 thermometer. + +Required node properties: +- compatible: "stts751" +- reg: I2C bus address of the device + +Optional properties: +- smbus-timeout-disable: when set, the smbus timeout function will be disabled + +Example stts751 node: + +temp-sensor { + compatible = "stts751"; + reg = <0x48>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/tmp108.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/tmp108.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c4b10df86d9fe18918338e7f310a97602c73bea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/tmp108.txt @@ -0,0 +1,14 @@ +TMP108 temperature sensor +------------------------- + +This device supports I2C only. + +Requires node properties: +- compatible : "ti,tmp108" +- reg : the I2C address of the device. This is 0x48, 0x49, 0x4a, or 0x4b. + +Example: + tmp108@48 { + compatible = "ti,tmp108"; + reg = <0x48>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/hwmon/vexpress.txt b/arch/arm64/boot/dts/vendor/bindings/hwmon/vexpress.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c27ed694bbbf29f8e96e286855799879e0f26b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/hwmon/vexpress.txt @@ -0,0 +1,23 @@ +Versatile Express hwmon sensors +------------------------------- + +Requires node properties: +- "compatible" value : one of + "arm,vexpress-volt" + "arm,vexpress-amp" + "arm,vexpress-temp" + "arm,vexpress-power" + "arm,vexpress-energy" +- "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg + (see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt + for more details) + +Optional node properties: +- label : string describing the monitored value + +Example: + energy@0 { + compatible = "arm,vexpress-energy"; + arm,vexpress-sysreg,func = <13 0>; + label = "A15 Jcore"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,bcm2835-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,bcm2835-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9de3756752b5a95fee7c9debc76524b075172db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,bcm2835-i2c.txt @@ -0,0 +1,20 @@ +Broadcom BCM2835 I2C controller + +Required properties: +- compatible : Should be "brcm,bcm2835-i2c". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks : The clock feeding the I2C controller. + +Recommended properties: +- clock-frequency : desired I2C bus clock frequency in Hz. + +Example: + +i2c@20205000 { + compatible = "brcm,bcm2835-i2c"; + reg = <0x7e205000 0x1000>; + interrupts = <2 21>; + clocks = <&clk_i2c>; + clock-frequency = <100000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,iproc-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,iproc-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..81f982ccca315537e7b0db1c81ac4b6a0abec873 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,iproc-i2c.txt @@ -0,0 +1,37 @@ +Broadcom iProc I2C controller + +Required properties: + +- compatible: + Must be "brcm,iproc-i2c" + +- reg: + Define the base and range of the I/O address space that contain the iProc + I2C controller registers + +- interrupts: + Should contain the I2C interrupt + +- clock-frequency: + This is the I2C bus clock. Need to be either 100000 or 400000 + +- #address-cells: + Always 1 (for I2C addresses) + +- #size-cells: + Always 0 + +Example: + i2c0: i2c@18008000 { + compatible = "brcm,iproc-i2c"; + reg = <0x18008000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-frequency = <100000>; + + codec: wm8750@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,kona-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,kona-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b87b741fa8e49319330992906a46806c35a792a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/brcm,kona-i2c.txt @@ -0,0 +1,35 @@ +Broadcom Kona Family I2C +========================= + +This I2C controller is used in the following Broadcom SoCs: + + BCM11130 + BCM11140 + BCM11351 + BCM28145 + BCM28155 + +Required Properties +------------------- +- compatible: "brcm,bcm11351-i2c", "brcm,kona-i2c" +- reg: Physical base address and length of controller registers +- interrupts: The interrupt number used by the controller +- clocks: clock specifier for the kona i2c external clock +- clock-frequency: The I2C bus frequency in Hz +- #address-cells: Should be <1> +- #size-cells: Should be <0> + +Refer to clocks/clock-bindings.txt for generic clock consumer +properties. + +Example: + +i2c@3e016000 { + compatible = "brcm,bcm11351-i2c","brcm,kona-i2c"; + reg = <0x3e016000 0x80>; + interrupts = ; + clocks = <&bsc1_clk>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-altera.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-altera.txt new file mode 100644 index 0000000000000000000000000000000000000000..767664f448ece3315dc376f33ad0fdaef5ecb23d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-altera.txt @@ -0,0 +1,39 @@ +* Altera I2C Controller +* This is Altera's synthesizable logic block I2C Controller for use +* in Altera's FPGAs. + +Required properties : + - compatible : should be "altr,softip-i2c-v1.0" + - reg : Offset and length of the register set for the device + - interrupts : where IRQ is the interrupt number. + - clocks : phandle to input clock. + - #address-cells = <1>; + - #size-cells = <0>; + +Recommended properties : + - clock-frequency : desired I2C bus clock frequency in Hz. + +Optional properties : + - fifo-size : Size of the RX and TX FIFOs in bytes. + - Child nodes conforming to i2c bus binding + +Example : + + i2c@100080000 { + compatible = "altr,softip-i2c-v1.0"; + reg = <0x00000001 0x00080000 0x00000040>; + interrupt-parent = <&intc>; + interrupts = <0 43 4>; + clocks = <&clk_0>; + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + fifo-size = <4>; + + eeprom@51 { + compatible = "atmel,24c32"; + reg = <0x51>; + pagesize = <32>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-arb-gpio-challenge.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-arb-gpio-challenge.txt new file mode 100644 index 0000000000000000000000000000000000000000..548a73cde796f9acc5ac4ee71ce3e0d93bbf9d74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-arb-gpio-challenge.txt @@ -0,0 +1,82 @@ +GPIO-based I2C Arbitration Using a Challenge & Response Mechanism +================================================================= +This uses GPIO lines and a challenge & response mechanism to arbitrate who is +the master of an I2C bus in a multimaster situation. + +In many cases using GPIOs to arbitrate is not needed and a design can use +the standard I2C multi-master rules. Using GPIOs is generally useful in +the case where there is a device on the bus that has errata and/or bugs +that makes standard multimaster mode not feasible. + +Note that this scheme works well enough but has some downsides: +* It is nonstandard (not using standard I2C multimaster) +* Having two masters on a bus in general makes it relatively hard to debug + problems (hard to tell if i2c issues were caused by one master, another, or + some device on the bus). + + +Algorithm: + +All masters on the bus have a 'bus claim' line which is an output that the +others can see. These are all active low with pull-ups enabled. We'll +describe these lines as: + +- OUR_CLAIM: output from us signaling to other hosts that we want the bus +- THEIR_CLAIMS: output from others signaling that they want the bus + +The basic algorithm is to assert your line when you want the bus, then make +sure that the other side doesn't want it also. A detailed explanation is best +done with an example. + +Let's say we want to claim the bus. We: +1. Assert OUR_CLAIM. +2. Waits a little bit for the other sides to notice (slew time, say 10 + microseconds). +3. Check THEIR_CLAIMS. If none are asserted then the we have the bus and we are + done. +4. Otherwise, wait for a few milliseconds and see if THEIR_CLAIMS are released. +5. If not, back off, release the claim and wait for a few more milliseconds. +6. Go back to 1 (until retry time has expired). + + +Required properties: +- compatible: i2c-arb-gpio-challenge +- our-claim-gpio: The GPIO that we use to claim the bus. +- their-claim-gpios: The GPIOs that the other sides use to claim the bus. + Note that some implementations may only support a single other master. +- I2C arbitration bus node. See i2c-arb.txt in this directory. + +Optional properties: +- slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us. +- wait-retry-us: we'll attempt another claim after this many microseconds. + Default is 3000 us. +- wait-free-us: we'll give up after this many microseconds. Default is 50000 us. + + +Example: + i2c@12ca0000 { + compatible = "acme,some-i2c-device"; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c-arbitrator { + compatible = "i2c-arb-gpio-challenge"; + + i2c-parent = <&{/i2c@12CA0000}>; + + our-claim-gpio = <&gpf0 3 1>; + their-claim-gpios = <&gpe0 4 1>; + slew-delay-us = <10>; + wait-retry-us = <3000>; + wait-free-us = <50000>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + i2c@52 { + // Normal I2C device + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-arb.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-arb.txt new file mode 100644 index 0000000000000000000000000000000000000000..59abf9277bdc12cc773ad319c686bed03a41ac34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-arb.txt @@ -0,0 +1,35 @@ +Common i2c arbitration bus properties. + +- i2c-arb child node + +Required properties for the i2c-arb child node: +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties for i2c-arb child node: +- Child nodes conforming to i2c bus binding + + +Example : + + /* + An NXP pca9541 I2C bus master selector at address 0x74 + with a NXP pca8574 GPIO expander attached. + */ + + arb@74 { + compatible = "nxp,pca9541"; + reg = <0x74>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + gpio@38 { + compatible = "nxp,pca8574"; + reg = <0x38>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-aspeed.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-aspeed.txt new file mode 100644 index 0000000000000000000000000000000000000000..8fbd8633a387dd880a1a3b3353066b07ea6dd446 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-aspeed.txt @@ -0,0 +1,48 @@ +Device tree configuration for the I2C busses on the AST24XX and AST25XX SoCs. + +Required Properties: +- #address-cells : should be 1 +- #size-cells : should be 0 +- reg : address offset and range of bus +- compatible : should be "aspeed,ast2400-i2c-bus" + or "aspeed,ast2500-i2c-bus" +- clocks : root clock of bus, should reference the APB + clock in the second cell +- resets : phandle to reset controller with the reset number in + the second cell +- interrupts : interrupt number + +Optional Properties: +- bus-frequency : frequency of the bus clock in Hz defaults to 100 kHz when not + specified +- multi-master : states that there is another master active on this bus. + +Example: + +i2c { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x1e78a000 0x1000>; + + i2c_ic: interrupt-controller@0 { + #interrupt-cells = <1>; + compatible = "aspeed,ast2400-i2c-ic"; + reg = <0x0 0x40>; + interrupts = <12>; + interrupt-controller; + }; + + i2c0: i2c-bus@40 { + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + reg = <0x40 0x40>; + compatible = "aspeed,ast2400-i2c-bus"; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_I2C>; + bus-frequency = <100000>; + interrupts = <0>; + interrupt-parent = <&i2c_ic>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-at91.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-at91.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef973a0343c7b48a95cd18c3cc44b48b0ae08e62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-at91.txt @@ -0,0 +1,63 @@ +I2C for Atmel platforms + +Required properties : +- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c", + "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c", + "atmel,at91sam9x5-i2c", "atmel,sama5d4-i2c" or "atmel,sama5d2-i2c" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- #address-cells = <1>; +- #size-cells = <0>; +- clocks: phandles to input clocks. + +Optional properties: +- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000 +- dmas: A list of two dma specifiers, one for each entry in dma-names. +- dma-names: should contain "tx" and "rx". +- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO + capable I2C controllers. +- i2c-sda-hold-time-ns: TWD hold time, only available for "atmel,sama5d4-i2c" + and "atmel,sama5d2-i2c". +- Child nodes conforming to i2c bus binding + +Examples : + +i2c0: i2c@fff84000 { + compatible = "atmel,at91sam9g20-i2c"; + reg = <0xfff84000 0x100>; + interrupts = <12 4 6>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&twi0_clk>; + clock-frequency = <400000>; + + 24c512@50 { + compatible = "24c512"; + reg = <0x50>; + pagesize = <128>; + } +} + +i2c0: i2c@f8034600 { + compatible = "atmel,sama5d2-i2c"; + reg = <0xf8034600 0x100>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) + AT91_XDMAC_DT_PERID(11)>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) + AT91_XDMAC_DT_PERID(12)>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx0>; + atmel,fifo-size = <16>; + i2c-sda-hold-time-ns = <336>; + + wm8731: wm8731@1a { + compatible = "wm8731"; + reg = <0x1a>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-axxia.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-axxia.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d53a2b795530522c00cf5a7cc38e6f0f178e7a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-axxia.txt @@ -0,0 +1,30 @@ +LSI Axxia I2C + +Required properties : +- compatible : Must be "lsi,api2c" +- reg : Offset and length of the register set for the device +- interrupts : the interrupt specifier +- #address-cells : Must be <1>; +- #size-cells : Must be <0>; +- clock-names : Must contain "i2c". +- clocks: Must contain an entry for each name in clock-names. See the common + clock bindings. + +Optional properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, + the default 100 kHz frequency will be used. As only Normal and Fast modes + are supported, possible values are 100000 and 400000. + +Example : + +i2c@2010084000 { + compatible = "lsi,api2c"; + device_type = "i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x20 0x10084000 0x00 0x1000>; + interrupts = <0 19 4>; + clocks = <&clk_per>; + clock-names = "i2c"; + clock-frequency = <400000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-brcmstb.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-brcmstb.txt new file mode 100644 index 0000000000000000000000000000000000000000..0380609b177a458730cfd02779eb80de7bbd45d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-brcmstb.txt @@ -0,0 +1,26 @@ +Broadcom stb bsc iic master controller + +Required properties: + +- compatible: should be "brcm,brcmstb-i2c" or "brcm,brcmper-i2c" +- clock-frequency: 32-bit decimal value of iic master clock freqency in Hz + valid values are 375000, 390000, 187500, 200000 + 93750, 97500, 46875 and 50000 +- reg: specifies the base physical address and size of the registers + +Optional properties : + +- interrupts: specifies the interrupt number, the irq line to be used +- interrupt-names: Interrupt name string + +Example: + +bsca: i2c@f0406200 { + clock-frequency = <390000>; + compatible = "brcm,brcmstb-i2c"; + interrupt-parent = <&irq0_intc>; + reg = <0xf0406200 0x58>; + interrupts = <0x18>; + interrupt-names = "upg_bsca"; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cadence.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cadence.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebaa90c58c8e727bd7c9fbfcb56cbd8b5e20d345 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cadence.txt @@ -0,0 +1,28 @@ +Binding for the Cadence I2C controller + +Required properties: + - reg: Physical base address and size of the controller's register area. + - compatible: Should contain one of: + * "cdns,i2c-r1p10" + Note: Use this when cadence i2c controller version 1.0 is used. + * "cdns,i2c-r1p14" + Note: Use this when cadence i2c controller version 1.4 is used. + - clocks: Input clock specifier. Refer to common clock bindings. + - interrupts: Interrupt specifier. Refer to interrupt bindings. + - #address-cells: Should be 1. + - #size-cells: Should be 0. + +Optional properties: + - clock-frequency: Desired operating frequency, in Hz, of the bus. + - clock-names: Input clock name, should be 'pclk'. + +Example: + i2c@e0004000 { + compatible = "cdns,i2c-r1p10"; + clocks = <&clkc 38>; + interrupts = ; + reg = <0xe0004000 0x1000>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cbus-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cbus-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..c143948b2a37fc31b9aa7cc200bb82ff0a839787 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cbus-gpio.txt @@ -0,0 +1,27 @@ +Device tree bindings for i2c-cbus-gpio driver + +Required properties: + - compatible = "i2c-cbus-gpio"; + - gpios: clk, dat, sel + - #address-cells = <1>; + - #size-cells = <0>; + +Optional properties: + - child nodes conforming to i2c bus binding + +Example: + +i2c@0 { + compatible = "i2c-cbus-gpio"; + gpios = <&gpio 66 0 /* clk */ + &gpio 65 0 /* dat */ + &gpio 64 0 /* sel */ + >; + #address-cells = <1>; + #size-cells = <0>; + + retu: retu@1 { + compatible = "nokia,retu"; + reg = <0x1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cros-ec-tunnel.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cros-ec-tunnel.txt new file mode 100644 index 0000000000000000000000000000000000000000..898f030eba6229ec45da1073a410f32b16ba4011 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-cros-ec-tunnel.txt @@ -0,0 +1,39 @@ +I2C bus that tunnels through the ChromeOS EC (cros-ec) +====================================================== +On some ChromeOS board designs we've got a connection to the EC (embedded +controller) but no direct connection to some devices on the other side of +the EC (like a battery and PMIC). To get access to those devices we need +to tunnel our i2c commands through the EC. + +The node for this device should be under a cros-ec node like google,cros-ec-spi +or google,cros-ec-i2c. + + +Required properties: +- compatible: google,cros-ec-i2c-tunnel +- google,remote-bus: The EC bus we'd like to talk to. + +Optional child nodes: +- One node per I2C device connected to the tunnelled I2C bus. + + +Example: + cros-ec@0 { + compatible = "google,cros-ec-spi"; + + ... + + i2c-tunnel { + compatible = "google,cros-ec-i2c-tunnel"; + #address-cells = <1>; + #size-cells = <0>; + + google,remote-bus = <0>; + + battery: sbs-battery@b { + compatible = "sbs,sbs-battery"; + reg = <0xb>; + sbs,poll-retry-count = <1>; + }; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-davinci.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-davinci.txt new file mode 100644 index 0000000000000000000000000000000000000000..b745f3706120f0605f43642af2750832832c75db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-davinci.txt @@ -0,0 +1,43 @@ +* Texas Instruments Davinci/Keystone I2C + +This file provides information, what the device node for the +davinci/keystone i2c interface contains. + +Required properties: +- compatible: "ti,davinci-i2c" or "ti,keystone-i2c"; +- reg : Offset and length of the register set for the device +- clocks: I2C functional clock phandle. + For 66AK2G this property should be set per binding, + Documentation/devicetree/bindings/clock/ti,sci-clk.txt + +SoC-specific Required Properties: + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the I2C device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt + +Recommended properties : +- interrupts : standard interrupt property. +- clock-frequency : desired I2C bus clock frequency in Hz. +- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC + registers. PFUNC registers allow to switch I2C pins to function as + GPIOs, so they can be toggled manually. + +Example (enbw_cmc board): + i2c@1c22000 { + compatible = "ti,davinci-i2c"; + reg = <0x22000 0x1000>; + clock-frequency = <100000>; + interrupts = <15>; + interrupt-parent = <&intc>; + #address-cells = <1>; + #size-cells = <0>; + + dtt@48 { + compatible = "national,lm75"; + reg = <0x48>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-demux-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-demux-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..81b5d55086fa60a0118047ee9bec880c9cc8250a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-demux-pinctrl.txt @@ -0,0 +1,135 @@ +Pinctrl-based I2C Bus DeMux + +This binding describes an I2C bus demultiplexer that uses pin multiplexing to +route the I2C signals, and represents the pin multiplexing configuration using +the pinctrl device tree bindings. This may be used to select one I2C IP core at +runtime which may have a better feature set for a given task than another I2C +IP core on the SoC. The most simple example is to fall back to GPIO bitbanging +if your current runtime configuration hits an errata of the internal IP core. + + +-------------------------------+ + | SoC | + | | +-----+ +-----+ + | +------------+ | | dev | | dev | + | |I2C IP Core1|--\ | +-----+ +-----+ + | +------------+ \-------+ | | | + | |Pinctrl|--|------+--------+ + | +------------+ +-------+ | + | |I2C IP Core2|--/ | + | +------------+ | + | | + +-------------------------------+ + +Required properties: +- compatible: "i2c-demux-pinctrl" +- i2c-parent: List of phandles of I2C masters available for selection. The first + one will be used as default. +- i2c-bus-name: The name of this bus. Also needed as pinctrl-name for the I2C + parents. + +Furthermore, I2C mux properties and child nodes. See i2c-mux.txt in this +directory. + +Example: + +Here is a snipplet for a bus to be demuxed. It contains various i2c clients for +HDMI, so the bus is named "i2c-hdmi": + + i2chdmi: i2c@8 { + + compatible = "i2c-demux-pinctrl"; + i2c-parent = <&gpioi2c>, <&iic2>, <&i2c2>; + i2c-bus-name = "i2c-hdmi"; + #address-cells = <1>; + #size-cells = <0>; + + ak4643: sound-codec@12 { + compatible = "asahi-kasei,ak4643"; + + #sound-dai-cells = <0>; + reg = <0x12>; + }; + + composite-in@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + remote = <&vin1>; + + port { + adv7180: endpoint { + bus-width = <8>; + remote-endpoint = <&vin1ep0>; + }; + }; + }; + + hdmi@39 { + compatible = "adi,adv7511w"; + reg = <0x39>; + interrupt-parent = <&gpio1>; + interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + adi,input-style = <1>; + adi,input-justification = "evenly"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7511_in: endpoint { + remote-endpoint = <&du_out_lvds0>; + }; + }; + + port@1 { + reg = <1>; + adv7511_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + }; + +And for clarification, here are the snipplets for the i2c-parents: + + gpioi2c: i2c@9 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "i2c-gpio"; + gpios = <&gpio5 6 GPIO_ACTIVE_HIGH /* sda */ + &gpio5 5 GPIO_ACTIVE_HIGH /* scl */ + >; + i2c-gpio,delay-us = <5>; + }; + +... + +&i2c2 { + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "i2c-hdmi"; + + clock-frequency = <100000>; +}; + +... + +&iic2 { + pinctrl-0 = <&iic2_pins>; + pinctrl-names = "i2c-hdmi"; + + clock-frequency = <100000>; +}; + +Please note: + +- pinctrl properties for the parent I2C controllers need a pinctrl state + with the same name as i2c-bus-name, not "default"! + +- the i2c masters must have their status "disabled". This driver will + enable them at runtime when needed. diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-designware.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-designware.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbb0a6d8b9643540e4f5c2e084216b5e66560b2e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-designware.txt @@ -0,0 +1,59 @@ +* Synopsys DesignWare I2C + +Required properties : + + - compatible : should be "snps,designware-i2c" + - reg : Offset and length of the register set for the device + - interrupts : where IRQ is the interrupt number. + +Recommended properties : + + - clock-frequency : desired I2C bus clock frequency in Hz. + +Optional properties : + - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. + This option is only supported in hardware blocks version 1.11a or newer. + + - i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds. + This value which is by default 300ns is used to compute the tLOW period. + + - i2c-sda-falling-time-ns : should contain the SDA falling time in nanoseconds. + This value which is by default 300ns is used to compute the tHIGH period. + +Examples : + + i2c@f0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0xf0000 0x1000>; + interrupts = <11>; + clock-frequency = <400000>; + }; + + i2c@1120000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x1120000 0x1000>; + interrupt-parent = <&ictl>; + interrupts = <12 1>; + clock-frequency = <400000>; + i2c-sda-hold-time-ns = <300>; + i2c-sda-falling-time-ns = <300>; + i2c-scl-falling-time-ns = <300>; + }; + + i2c@1120000 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2000 0x100>; + clock-frequency = <400000>; + clocks = <&i2cclk>; + interrupts = <0>; + + eeprom@64 { + compatible = "linux,slave-24c02"; + reg = <0x40000064>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-digicolor.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-digicolor.txt new file mode 100644 index 0000000000000000000000000000000000000000..457a098d4f7e63b2ad0308ae6de56cf4856b8e2b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-digicolor.txt @@ -0,0 +1,25 @@ +Conexant Digicolor I2C controller + +Required properties: + - compatible: must be "cnxt,cx92755-i2c" + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + +Optional properties: +- clock-frequency: the desired I2C bus clock frequency in Hz; in + absence of this property the default value is used (100 kHz). + +Example: + + i2c: i2c@f0000120 { + compatible = "cnxt,cx92755-i2c"; + reg = <0xf0000120 0x10>; + interrupts = <28>; + clocks = <&main_clk>; + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-efm32.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-efm32.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b30e54ae3c7a2aefb1afd760e623c132a4a5ce8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-efm32.txt @@ -0,0 +1,33 @@ +* Energymicro efm32 i2c controller + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : should be "energymicro,efm32-i2c" + - interrupts : the interrupt number + - clocks : reference to the module clock + +Recommended properties : + + - clock-frequency : maximal I2C bus clock frequency in Hz. + - energymicro,location : Decides the location of the USART I/O pins. + Allowed range : [0 .. 6] + +Example: + i2c0: i2c@4000a000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "energymicro,efm32-i2c"; + reg = <0x4000a000 0x400>; + interrupts = <9>; + clocks = <&cmu clk_HFPERCLKI2C0>; + clock-frequency = <100000>; + energymicro,location = <3>; + + eeprom@50 { + compatible = "microchip,24c02"; + reg = <0x50>; + pagesize = <16>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-emev2.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-emev2.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ed1ea1c7e14a9cd0795303d2b9355fe6f262bf3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-emev2.txt @@ -0,0 +1,22 @@ +Device tree configuration for Renesas EMEV2 IIC controller + +Required properties: +- compatible : "renesas,iic-emev2" +- reg : address start and address range size of device +- interrupts : specifier for the IIC controller interrupt +- clocks : phandle to the IP core SCLK +- clock-names : must be "sclk" +- #address-cells : should be <1> +- #size-cells : should be <0> + +Example: + + iic0: i2c@e0070000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,iic-emev2"; + reg = <0xe0070000 0x28>; + interrupts = <0 32 IRQ_TYPE_EDGE_RISING>; + clocks = <&iic0_sclk>; + clock-names = "sclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-exynos5.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-exynos5.txt new file mode 100644 index 0000000000000000000000000000000000000000..2dbc0b62daa69a80c3d04cff149717aba3ed6663 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-exynos5.txt @@ -0,0 +1,53 @@ +* Samsung's High Speed I2C controller + +The Samsung's High Speed I2C controller is used to interface with I2C devices +at various speeds ranging from 100khz to 3.4Mhz. + +Required properties: + - compatible: value should be. + -> "samsung,exynos5-hsi2c", (DEPRECATED) + for i2c compatible with HSI2C available + on Exynos5250 and Exynos5420 SoCs. + -> "samsung,exynos5250-hsi2c", for i2c compatible with HSI2C available + on Exynos5250 and Exynos5420 SoCs. + -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available + on Exynos5260 SoCs. + -> "samsung,exynos7-hsi2c", for i2c compatible with HSI2C available + on Exynos7 SoCs. + + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + - #address-cells: always 1 (for i2c addresses) + - #size-cells: always 0 + + - Pinctrl: + - pinctrl-0: Pin control group to be used for this controller. + - pinctrl-names: Should contain only one value - "default". + +Optional properties: + - clock-frequency: Desired operating frequency in Hz of the bus. + -> If not specified, the bus operates in fast-speed mode at + at 100khz. + -> If specified, the bus operates in high-speed mode only if the + clock-frequency is >= 1Mhz. + +Example: + +hsi2c@12ca0000 { + compatible = "samsung,exynos5250-hsi2c"; + reg = <0x12ca0000 0x100>; + interrupts = <56>; + clock-frequency = <100000>; + + pinctrl-0 = <&i2c4_bus>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-fsi.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-fsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1be2ceb7e6966c3780b1de8fb43df990b242a6f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-fsi.txt @@ -0,0 +1,40 @@ +Device-tree bindings for FSI-attached I2C master and busses +----------------------------------------------------------- + +Required properties: + - compatible = "ibm,i2c-fsi"; + - reg = < address size >; : The FSI CFAM address and address + space size. + - #address-cells = <1>; : Number of address cells in child + nodes. + - #size-cells = <0>; : Number of size cells in child nodes. + - child nodes : Nodes to describe busses off the I2C + master. + +Child node required properties: + - reg = < port number > : The port number on the I2C master. + +Child node optional properties: + - child nodes : Nodes to describe devices on the I2C + bus. + +Examples: + + i2c@1800 { + compatible = "ibm,i2c-fsi"; + reg = < 0x1800 0x400 >; + #address-cells = <1>; + #size-cells = <0>; + + i2c-bus@0 { + reg = <0>; + }; + + i2c-bus@1 { + reg = <1>; + + eeprom@50 { + compatible = "vendor,dev-name"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-gate.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-gate.txt new file mode 100644 index 0000000000000000000000000000000000000000..1846d236e656d140110834cc1bf9adb6df6bff9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-gate.txt @@ -0,0 +1,41 @@ +An i2c gate is useful to e.g. reduce the digital noise for RF tuners connected +to the i2c bus. Gates are similar to arbitrators in that you need to perform +some kind of operation to access the i2c bus past the arbitrator/gate, but +there are no competing masters to consider for gates and therefore there is +no arbitration happening for gates. + +Common i2c gate properties. + +- i2c-gate child node + +Required properties for the i2c-gate child node: +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties for i2c-gate child node: +- Child nodes conforming to i2c bus binding + + +Example : + + /* + An Invensense mpu9150 at address 0x68 featuring an on-chip Asahi + Kasei ak8975 compass behind a gate. + */ + + mpu9150@68 { + compatible = "invensense,mpu9150"; + reg = <0x68>; + interrupt-parent = <&gpio1>; + interrupts = <18 1>; + + i2c-gate { + #address-cells = <1>; + #size-cells = <0>; + + ax8975@c { + compatible = "ak,ak8975"; + reg = <0x0c>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..38a05562d1d2958d41520a9920a83ddfdf444418 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-gpio.txt @@ -0,0 +1,46 @@ +Device-Tree bindings for i2c gpio driver + +Required properties: + - compatible = "i2c-gpio"; + - sda-gpios: gpio used for the sda signal, this should be flagged as + active high using open drain with (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) + from since the signal is by definition + open drain. + - scl-gpios: gpio used for the scl signal, this should be flagged as + active high using open drain with (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN) + from since the signal is by definition + open drain. + +Optional properties: + - i2c-gpio,scl-output-only: scl as output only + - i2c-gpio,delay-us: delay between GPIO operations (may depend on each platform) + - i2c-gpio,timeout-ms: timeout to get data + +Deprecated properties, do not use in new device tree sources: + - gpios: sda and scl gpio, alternative for {sda,scl}-gpios + - i2c-gpio,sda-open-drain: this means that something outside of our + control has put the GPIO line used for SDA into open drain mode, and + that something is not the GPIO chip. It is essentially an + inconsistency flag. + - i2c-gpio,scl-open-drain: this means that something outside of our + control has put the GPIO line used for SCL into open drain mode, and + that something is not the GPIO chip. It is essentially an + inconsistency flag. + +Example nodes: + +#include + +i2c@0 { + compatible = "i2c-gpio"; + sda-gpios = <&pioA 23 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&pioA 24 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + + rv3029c2@56 { + compatible = "rv3029c2"; + reg = <0x56>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-hix5hd2.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-hix5hd2.txt new file mode 100644 index 0000000000000000000000000000000000000000..f98b37401e6eb3946468013e1bef55a629f642e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-hix5hd2.txt @@ -0,0 +1,24 @@ +I2C for Hisilicon hix5hd2 chipset platform + +Required properties: +- compatible: Must be "hisilicon,hix5hd2-i2c" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- #address-cells = <1>; +- #size-cells = <0>; +- clocks: phandles to input clocks. + +Optional properties: +- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000 +- Child nodes conforming to i2c bus binding + +Examples: +I2C0@f8b10000 { + compatible = "hisilicon,hix5hd2-i2c"; + reg = <0xf8b10000 0x1000>; + interrupts = <0 38 4>; + clocks = <&clock HIX5HD2_I2C0_RST>; + #address-cells = <1>; + #size-cells = <0>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-img-scb.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-img-scb.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6461602dca54d97d1f82ad32a615a0757a86ffe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-img-scb.txt @@ -0,0 +1,26 @@ +IMG Serial Control Bus (SCB) I2C Controller + +Required Properties: +- compatible: "img,scb-i2c" +- reg: Physical base address and length of controller registers +- interrupts: Interrupt number used by the controller +- clocks : Should contain a clock specifier for each entry in clock-names +- clock-names : Should contain the following entries: + "scb", for the SCB core clock. + "sys", for the system clock. +- clock-frequency: The I2C bus frequency in Hz +- #address-cells: Should be <1> +- #size-cells: Should be <0> + +Example: + +i2c@18100000 { + compatible = "img,scb-i2c"; + reg = <0x18100000 0x200>; + interrupts = ; + clocks = <&i2c0_clk>, <&system_clk>; + clock-names = "scb", "sys"; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-imx-lpi2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-imx-lpi2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..091c8dfd322910e14712d4a818e9879538abf3d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-imx-lpi2c.txt @@ -0,0 +1,18 @@ +* Freescale Low Power Inter IC (LPI2C) for i.MX + +Required properties: +- compatible : + - "fsl,imx7ulp-lpi2c" for LPI2C compatible with the one integrated on i.MX7ULP soc +- reg : address and length of the lpi2c master registers +- interrupts : lpi2c interrupt +- clocks : lpi2c clock specifier + +Examples: + +lpi2c7: lpi2c7@40a50000 { + compatible = "fsl,imx7ulp-lpi2c"; + reg = <0x40A50000 0x10000>; + interrupt-parent = <&intc>; + interrupts = ; + clocks = <&clks IMX7ULP_CLK_LPI2C7>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-imx.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-imx.txt new file mode 100644 index 0000000000000000000000000000000000000000..b967544590e804c413063cfbd4c1d56bee6f486b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-imx.txt @@ -0,0 +1,49 @@ +* Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MX + +Required properties: +- compatible : + - "fsl,imx1-i2c" for I2C compatible with the one integrated on i.MX1 SoC + - "fsl,imx21-i2c" for I2C compatible with the one integrated on i.MX21 SoC + - "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC +- reg : Should contain I2C/HS-I2C registers location and length +- interrupts : Should contain I2C/HS-I2C interrupt +- clocks : Should contain the I2C/HS-I2C clock specifier + +Optional properties: +- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. + The absence of the property indicates the default frequency 100 kHz. +- dmas: A list of two dma specifiers, one for each entry in dma-names. +- dma-names: should contain "tx" and "rx". +- scl-gpios: specify the gpio related to SCL pin +- sda-gpios: specify the gpio related to SDA pin +- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c + bus recovery, call it "gpio" state + +Examples: + +i2c@83fc4000 { /* I2C2 on i.MX51 */ + compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; + reg = <0x83fc4000 0x4000>; + interrupts = <63>; +}; + +i2c@70038000 { /* HS-I2C on i.MX51 */ + compatible = "fsl,imx51-i2c", "fsl,imx21-i2c"; + reg = <0x70038000 0x4000>; + interrupts = <64>; + clock-frequency = <400000>; +}; + +i2c0: i2c@40066000 { /* i2c0 on vf610 */ + compatible = "fsl,vf610-i2c"; + reg = <0x40066000 0x1000>; + interrupts =<0 71 0x04>; + dmas = <&edma0 0 50>, + <&edma0 0 51>; + dma-names = "rx","tx"; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>; + sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-jz4780.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-jz4780.txt new file mode 100644 index 0000000000000000000000000000000000000000..3738cfbf863fd3810236099c420b6b1050dcf626 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-jz4780.txt @@ -0,0 +1,31 @@ +* Ingenic JZ4780 I2C Bus controller + +Required properties: +- compatible: should be "ingenic,jz4780-i2c" +- reg: Should contain the address & size of the I2C controller registers. +- interrupts: Should specify the interrupt provided by parent. +- clocks: Should contain a single clock specifier for the JZ4780 I2C clock. +- clock-frequency: desired I2C bus clock frequency in Hz. + +Recommended properties: +- pinctrl-names: should be "default"; +- pinctrl-0: phandle to pinctrl function + +Example + +/ { + i2c4: i2c4@10054000 { + compatible = "ingenic,jz4780-i2c"; + reg = <0x10054000 0x1000>; + + interrupt-parent = <&intc>; + interrupts = <56>; + + clocks = <&cgu JZ4780_CLK_SMB4>; + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pins_i2c4_data>; + + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-lpc2k.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-lpc2k.txt new file mode 100644 index 0000000000000000000000000000000000000000..4101aa621ad42ecafe4edb938199417216d675d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-lpc2k.txt @@ -0,0 +1,33 @@ +NXP I2C controller for LPC2xxx/178x/18xx/43xx + +Required properties: + - compatible: must be "nxp,lpc1788-i2c" + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + +Optional properties: +- clock-frequency: the desired I2C bus clock frequency in Hz; in + absence of this property the default value is used (100 kHz). + +Example: +i2c0: i2c@400a1000 { + compatible = "nxp,lpc1788-i2c"; + reg = <0x400a1000 0x1000>; + interrupts = <18>; + clocks = <&ccu1 CLK_APB1_I2C0>; + #address-cells = <1>; + #size-cells = <0>; +}; + +&i2c0 { + clock-frequency = <400000>; + + lm75@48 { + compatible = "nxp,lm75"; + reg = <0x48>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-meson.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-meson.txt new file mode 100644 index 0000000000000000000000000000000000000000..13d410de077cce268e6a35e3578e71269c103cea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-meson.txt @@ -0,0 +1,30 @@ +Amlogic Meson I2C controller + +Required properties: + - compatible: must be: + "amlogic,meson6-i2c" for Meson8 and compatible SoCs + "amlogic,meson-gxbb-i2c" for GXBB and compatible SoCs + "amlogic,meson-axg-i2c"for AXG and compatible SoCs + + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + +For details regarding the following core I2C bindings see also i2c.txt. + +Optional properties: +- clock-frequency: the desired I2C bus clock frequency in Hz; in + absence of this property the default value is used (100 kHz). + +Examples: + + i2c@c8100500 { + compatible = "amlogic,meson6-i2c"; + reg = <0xc8100500 0x20>; + interrupts = <0 92 1>; + clocks = <&clk81>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mpc.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mpc.txt new file mode 100644 index 0000000000000000000000000000000000000000..42a390526957f3dc659774fa7ae40c2d61fbe046 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mpc.txt @@ -0,0 +1,62 @@ +* I2C + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : should be "fsl,CHIP-i2c" where CHIP is the name of a + compatible processor, e.g. mpc8313, mpc8543, mpc8544, mpc5121, + mpc5200 or mpc5200b. For the mpc5121, an additional node + "fsl,mpc5121-i2c-ctrl" is required as shown in the example below. + +Recommended properties : + + - interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. + - fsl,preserve-clocking : boolean; if defined, the clock settings + from the bootloader are preserved (not touched). + - clock-frequency : desired I2C bus clock frequency in Hz. + - fsl,timeout : I2C bus timeout in microseconds. + +Examples : + + /* MPC5121 based board */ + i2c@1740 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc5121-i2c", "fsl-i2c"; + reg = <0x1740 0x20>; + interrupts = <11 0x8>; + interrupt-parent = <&ipic>; + clock-frequency = <100000>; + }; + + i2ccontrol@1760 { + compatible = "fsl,mpc5121-i2c-ctrl"; + reg = <0x1760 0x8>; + }; + + /* MPC5200B based board */ + i2c@3d00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc5200b-i2c","fsl,mpc5200-i2c","fsl-i2c"; + reg = <0x3d00 0x40>; + interrupts = <2 15 0>; + interrupt-parent = <&mpc5200_pic>; + fsl,preserve-clocking; + }; + + /* MPC8544 base board */ + i2c@3100 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc8544-i2c", "fsl-i2c"; + reg = <0x3100 0x100>; + interrupts = <43 2>; + interrupt-parent = <&mpic>; + clock-frequency = <400000>; + fsl,timeout = <10000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-msm-v2.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-msm-v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c0ec7dba1508e73b5a0b6ece30b8737f9e0d9ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-msm-v2.txt @@ -0,0 +1,59 @@ +Qualcomm Technologies, Inc. I2C controller + +Required properties: + - reg : Offset and length of the register region for the device named in + reg-names and has the same index. + - reg-names : Register region name(s) referenced in reg above + "qup_phys_addr" : Physical address of QUP register space. + - compatible : should be "qcom,i2c-msm-v2" + - interrupts : Interrupt number which correspond to the entry with the same + index in interrupt-names. + - interrupt-names: QUP core interrupt name(s) referenced in interrupts above + "qup_irq" : QUP interrupt used by the controller. + - dmas : DMA engine API's parameters for blsp. + <[phandle of the dma controller] [pipe index] [number of descriptors] + [sps_connect flags] [sps_register_event flags]>; + - dma-names : dma channel names. + - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz + - qcom,clk-freq-in : Supplied core clock frequency in Hz. + - qcom,i2c-dat : specifies GPIO which corresponds to the I2C data line. + - qcom,i2c-clk : specifies GPIO which corresponds to the I2C clock line. + +Required alias: + - The desired bus-number is specified by an alias with the following format: + 'i2c{n}' where n is the bus number. + +Optional property: + - qcom,noise-rjct-scl : number of low samples on clock line to consider it low. + When missing default to 0. + - qcom,noise-rjct-sda : number of low samples on data line to consider it low. + When missing default to 0. + - qcom,disable-dma : disables DMA transfer mode. + - qcom,master-id : Master-port value used on voting for the clock path. + - qcom,high-time-clk-div : high time divider value to configure clk-ctl + register. When missing, default to the value given in driver. + - qcom,fs-clk-div: fs divider value to configure clk-ctl register. When + missing, default to the value given in driver. + +Example: + aliases { + i2c10 = &i2c_10; + }; + + i2c_10: i2c@f9966000 { + compatible = "qcom,i2c-msm-v2"; + reg-names = "qup_phys_addr", "dma_phys_addr"; + reg = <0xf9966000 0x1000>; + interrupt-names = "qup_irq"; + interrupts = <0 104 0>; + dmas = <&dma_blsp1 14 32 0x20000020 0x20>, + <&dma_blsp1 15 64 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,clk-freq-out = <100000>; + qcom,clk-freq-in = <24000000>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + qcom,i2c-dat = <&tlmm 67 0x00>; + qcom,i2c-clk = <&tlmm 68 0x00>; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mtk.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mtk.txt new file mode 100644 index 0000000000000000000000000000000000000000..e199695b1c961374922ccbbd7ada40eb017b3ba1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mtk.txt @@ -0,0 +1,43 @@ +* MediaTek's I2C controller + +The MediaTek's I2C controller is used to interface with I2C devices. + +Required properties: + - compatible: value should be either of the following. + "mediatek,mt2701-i2c", "mediatek,mt6577-i2c": for MediaTek MT2701 + "mediatek,mt2712-i2c": for MediaTek MT2712 + "mediatek,mt6577-i2c": for MediaTek MT6577 + "mediatek,mt6589-i2c": for MediaTek MT6589 + "mediatek,mt7622-i2c": for MediaTek MT7622 + "mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623 + "mediatek,mt8173-i2c": for MediaTek MT8173 + - reg: physical base address of the controller and dma base, length of memory + mapped region. + - interrupts: interrupt number to the cpu. + - clock-div: the fixed value for frequency divider of clock source in i2c + module. Each IC may be different. + - clocks: clock name from clock manager + - clock-names: Must include "main" and "dma", if enable have-pmic need include + "pmic" extra. + +Optional properties: + - clock-frequency: Frequency in Hz of the bus when transfer, the default value + is 100000. + - mediatek,have-pmic: platform can control i2c form special pmic side. + Only mt6589 and mt8135 support this feature. + - mediatek,use-push-pull: IO config use push-pull mode. + +Example: + + i2c0: i2c@1100d000 { + compatible = "mediatek,mt6577-i2c"; + reg = <0x1100d000 0x70>, + <0x11000300 0x80>; + interrupts = ; + clock-frequency = <400000>; + mediatek,have-pmic; + clock-div = <16>; + clocks = <&i2c0_ck>, <&ap_dma_ck>; + clock-names = "main", "dma"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..21da3ecbb3700c06bc80cb3685ee31e56bc1471b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-gpio.txt @@ -0,0 +1,81 @@ +GPIO-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses GPIOs to +route the I2C signals. + + +-----+ +-----+ + | dev | | dev | + +------------+ +-----+ +-----+ + | SoC | | | + | | /--------+--------+ + | +------+ | +------+ child bus A, on GPIO value set to 0 + | | I2C |-|--| Mux | + | +------+ | +--+---+ child bus B, on GPIO value set to 1 + | | | \----------+--------+--------+ + | +------+ | | | | | + | | GPIO |-|-----+ +-----+ +-----+ +-----+ + | +------+ | | dev | | dev | | dev | + +------------+ +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-gpio +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-gpios: list of gpios used to control the muxer +* Standard I2C mux properties. See i2c-mux.txt in this directory. +* I2C child bus nodes. See i2c-mux.txt in this directory. + +Optional properties: +- idle-state: value to set the muxer to when idle. When no value is + given, it defaults to the last value used. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on their order in the device tree. + +Whenever an access is made to a device on a child bus, the value set +in the relevant node's reg property will be output using the list of +GPIOs, the first in the list holding the least-significant value. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +GPIOs will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into hardware whenever no access is being made to a +device on a child bus. + +Example: + i2cmux { + compatible = "i2c-mux-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mux-gpios = <&gpio1 22 0 &gpio1 23 0>; + i2c-parent = <&i2c1>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-gpmux.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-gpmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..2907dab562987ee210790242ac283a5f6028a879 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-gpmux.txt @@ -0,0 +1,99 @@ +General Purpose I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses a mux controller +from the mux subsystem to route the I2C signals. + + .-----. .-----. + | dev | | dev | + .------------. '-----' '-----' + | SoC | | | + | | .--------+--------' + | .------. | .------+ child bus A, on MUX value set to 0 + | | I2C |-|--| Mux | + | '------' | '--+---+ child bus B, on MUX value set to 1 + | .------. | | '----------+--------+--------. + | | MUX- | | | | | | + | | Ctrl |-|-----+ .-----. .-----. .-----. + | '------' | | dev | | dev | | dev | + '------------' '-----' '-----' '-----' + +Required properties: +- compatible: i2c-mux +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +- mux-controls: The phandle of the mux controller to use for operating the + mux. +* Standard I2C mux properties. See i2c-mux.txt in this directory. +* I2C child bus nodes. See i2c-mux.txt in this directory. The sub-bus number + is also the mux-controller state described in ../mux/mux-controller.txt + +Optional properties: +- mux-locked: If present, explicitly allow unrelated I2C transactions on the + parent I2C adapter at these times: + + during setup of the multiplexer + + between setup of the multiplexer and the child bus I2C transaction + + between the child bus I2C transaction and releasing of the multiplexer + + during releasing of the multiplexer + However, I2C transactions to devices behind all I2C multiplexers connected + to the same parent adapter that this multiplexer is connected to are blocked + for the full duration of the complete multiplexed I2C transaction (i.e. + including the times covered by the above list). + If mux-locked is not present, the multiplexer is assumed to be parent-locked. + This means that no unrelated I2C transactions are allowed on the parent I2C + adapter for the complete multiplexed I2C transaction. + The properties of mux-locked and parent-locked multiplexers are discussed + in more detail in Documentation/i2c/i2c-topology. + +For each i2c child node, an I2C child bus will be created. They will +be numbered based on their order in the device tree. + +Whenever an access is made to a device on a child bus, the value set +in the relevant node's reg property will be set as the state in the +mux controller. + +Example: + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>, + <&pioA 1 GPIO_ACTIVE_HIGH>; + }; + + i2c-mux { + compatible = "i2c-mux"; + mux-locked; + i2c-parent = <&i2c1>; + + mux-controls = <&mux>; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + compatible = "solomon,ssd1307fb-i2c"; + reg = <0x3c>; + pwms = <&pwm 4 3000>; + reset-gpios = <&gpio2 7 1>; + reset-active-low; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + compatible = "nxp,pca9555"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-ltc4306.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-ltc4306.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e98c6b3a721bfe6b92386678027a38641865ab8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-ltc4306.txt @@ -0,0 +1,61 @@ +* Linear Technology / Analog Devices I2C bus switch + +Required Properties: + + - compatible: Must contain one of the following. + "lltc,ltc4305", "lltc,ltc4306" + - reg: The I2C address of the device. + + The following required properties are defined externally: + + - Standard I2C mux properties. See i2c-mux.txt in this directory. + - I2C child bus nodes. See i2c-mux.txt in this directory. + +Optional Properties: + + - enable-gpios: Reference to the GPIO connected to the enable input. + - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all + children in idle state. This is necessary for example, if there are several + multiplexers on the bus and the devices behind them use same I2C addresses. + - gpio-controller: Marks the device node as a GPIO Controller. + - #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - ltc,downstream-accelerators-enable: Enables the rise time accelerators + on the downstream port. + - ltc,upstream-accelerators-enable: Enables the rise time accelerators + on the upstream port. + +Example: + + ltc4306: i2c-mux@4a { + compatible = "lltc,ltc4306"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a>; + + gpio-controller; + #gpio-cells = <2>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + eeprom@50 { + compatible = "at,24c02"; + reg = <0x50>; + }; + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + eeprom@50 { + compatible = "at,24c02"; + reg = <0x50>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-pca954x.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-pca954x.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccf6c86ed076dd843e7cac6f7459b2e520f73054 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-pca954x.txt @@ -0,0 +1,72 @@ +* NXP PCA954x I2C bus switch + +The driver supports NXP PCA954x and PCA984x I2C mux/switch devices. + +Required Properties: + + - compatible: Must contain one of the following. + "nxp,pca9540", + "nxp,pca9542", + "nxp,pca9543", + "nxp,pca9544", + "nxp,pca9545", + "nxp,pca9546", "nxp,pca9846", + "nxp,pca9547", "nxp,pca9847", + "nxp,pca9548", "nxp,pca9848", + "nxp,pca9849" + + - reg: The I2C address of the device. + + The following required properties are defined externally: + + - Standard I2C mux properties. See i2c-mux.txt in this directory. + - I2C child bus nodes. See i2c-mux.txt in this directory. + +Optional Properties: + + - reset-gpios: Reference to the GPIO connected to the reset input. + - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all + children in idle state. This is necessary for example, if there are several + multiplexers on the bus and the devices behind them use same I2C addresses. + - interrupts: Interrupt mapping for IRQ. + - interrupt-controller: Marks the device node as an interrupt controller. + - #interrupt-cells : Should be two. + - first cell is the pin number + - second cell is used to specify flags. + See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example: + + i2c-switch@74 { + compatible = "nxp,pca9548"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x74>; + + interrupt-parent = <&ipic>; + interrupts = <17 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..33119a98e1447681f5dbb04eb55df352ede95d6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-pinctrl.txt @@ -0,0 +1,93 @@ +Pinctrl-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses pin multiplexing to +route the I2C signals, and represents the pin multiplexing configuration +using the pinctrl device tree bindings. + + +-----+ +-----+ + | dev | | dev | + +------------------------+ +-----+ +-----+ + | SoC | | | + | /----|------+--------+ + | +---+ +------+ | child bus A, on first set of pins + | |I2C|---|Pinmux| | + | +---+ +------+ | child bus B, on second set of pins + | \----|------+--------+--------+ + | | | | | + +------------------------+ +-----+ +-----+ +-----+ + | dev | | dev | | dev | + +-----+ +-----+ +-----+ + +Required properties: +- compatible: i2c-mux-pinctrl +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. + +Also required are: + +* Standard pinctrl properties that specify the pin mux state for each child + bus. See ../pinctrl/pinctrl-bindings.txt. + +* Standard I2C mux properties. See i2c-mux.txt in this directory. + +* I2C child bus nodes. See i2c-mux.txt in this directory. + +For each named state defined in the pinctrl-names property, an I2C child bus +will be created. I2C child bus numbers are assigned based on the index into +the pinctrl-names property. + +The only exception is that no bus will be created for a state named "idle". If +such a state is defined, it must be the last entry in pinctrl-names. For +example: + + pinctrl-names = "ddc", "pta", "idle" -> ddc = bus 0, pta = bus 1 + pinctrl-names = "ddc", "idle", "pta" -> Invalid ("idle" not last) + pinctrl-names = "idle", "ddc", "pta" -> Invalid ("idle" not last) + +Whenever an access is made to a device on a child bus, the relevant pinctrl +state will be programmed into hardware. + +If an idle state is defined, whenever an access is not being made to a device +on a child bus, the idle pinctrl state will be programmed into hardware. + +If an idle state is not defined, the most recently used pinctrl state will be +left programmed into hardware whenever no access is being made of a device on +a child bus. + +Example: + + i2cmux { + compatible = "i2c-mux-pinctrl"; + #address-cells = <1>; + #size-cells = <0>; + + i2c-parent = <&i2c1>; + + pinctrl-names = "ddc", "pta", "idle"; + pinctrl-0 = <&state_i2cmux_ddc>; + pinctrl-1 = <&state_i2cmux_pta>; + pinctrl-2 = <&state_i2cmux_idle>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom { + compatible = "eeprom"; + reg = <0x50>; + }; + }; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom { + compatible = "eeprom"; + reg = <0x50>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-reg.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-reg.txt new file mode 100644 index 0000000000000000000000000000000000000000..de00d7fc450b005333e874b4b831a5585594d50b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux-reg.txt @@ -0,0 +1,74 @@ +Register-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses a single register +to route the I2C signals. + +Required properties: +- compatible: i2c-mux-reg +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +* Standard I2C mux properties. See i2c-mux.txt in this directory. +* I2C child bus nodes. See i2c-mux.txt in this directory. + +Optional properties: +- reg: this pair of specifies the register to control the mux. + The depends on its parent node. It can be any memory-mapped + address. The size must be either 1, 2, or 4 bytes. If reg is omitted, the + resource of this device will be used. +- little-endian: The existence indicates the register is in little endian. +- big-endian: The existence indicates the register is in big endian. + If both little-endian and big-endian are omitted, the endianness of the + CPU will be used. +- write-only: The existence indicates the register is write-only. +- idle-state: value to set the muxer to when idle. When no value is + given, it defaults to the last value used. + +Whenever an access is made to a device on a child bus, the value set +in the relevant node's reg property will be output to the register. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +register will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into the register. + +Example of a mux on PCIe card, the host is a powerpc SoC (big endian): + + i2c-mux { + /* the depends on the address translation + * of the parent device. If omitted, device resource + * will be used instead. The size is to determine + * whether iowrite32, iowrite16, or iowrite8 will be used. + */ + reg = <0x6028 0x4>; + little-endian; /* little endian register on PCIe */ + compatible = "i2c-mux-reg"; + #address-cells = <1>; + #size-cells = <0>; + i2c-parent = <&i2c1>; + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + si5338: clock-generator@70 { + compatible = "silabs,si5338"; + reg = <0x70>; + /* other stuff */ + }; + }; + + i2c@1 { + /* data is written using iowrite32 */ + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + si5338: clock-generator@70 { + compatible = "silabs,si5338"; + reg = <0x70>; + /* other stuff */ + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..b38f58a1c8784184bf57bc0f9dd20d985d8cba45 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mux.txt @@ -0,0 +1,73 @@ +Common i2c bus multiplexer/switch properties. + +An i2c bus multiplexer/switch will have several child busses that are +numbered uniquely in a device dependent manner. The nodes for an i2c bus +multiplexer/switch will have one child node for each child bus. + +Optional properties: +- #address-cells = <1>; + This property is required if the i2c-mux child node does not exist. + +- #size-cells = <0>; + This property is required if the i2c-mux child node does not exist. + +- i2c-mux + For i2c multiplexers/switches that have child nodes that are a mixture + of both i2c child busses and other child nodes, the 'i2c-mux' subnode + can be used for populating the i2c child busses. If an 'i2c-mux' + subnode is present, only subnodes of this will be considered as i2c + child busses. + +Required properties for the i2c-mux child node: +- #address-cells = <1>; +- #size-cells = <0>; + +Required properties for i2c child bus nodes: +- #address-cells = <1>; +- #size-cells = <0>; +- reg : The sub-bus number. + +Optional properties for i2c child bus nodes: +- Other properties specific to the multiplexer/switch hardware. +- Child nodes conforming to i2c bus binding + + +Example : + + /* + An NXP pca9548 8 channel I2C multiplexer at address 0x70 + with two NXP pca8574 GPIO expanders attached, one each to + ports 3 and 4. + */ + + mux@70 { + compatible = "nxp,pca9548"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + gpio1: gpio@38 { + compatible = "nxp,pca8574"; + reg = <0x38>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + i2c@4 { + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; + + gpio2: gpio@38 { + compatible = "nxp,pca8574"; + reg = <0x38>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mv64xxx.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mv64xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ffe65a316aeec89ab9d28352a759096a2a77f12 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mv64xxx.txt @@ -0,0 +1,64 @@ + +* Marvell MV64XXX I2C controller + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : Should be either: + - "allwinner,sun4i-a10-i2c" + - "allwinner,sun6i-a31-i2c" + - "marvell,mv64xxx-i2c" + - "marvell,mv78230-i2c" + - "marvell,mv78230-a0-i2c" + * Note: Only use "marvell,mv78230-a0-i2c" for a + very rare, initial version of the SoC which + had broken offload support. Linux + auto-detects this and sets it appropriately. + - interrupts : The interrupt number + +Optional properties : + + - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the +default frequency is 100kHz + + - resets : phandle to the parent reset controller. Mandatory + whenever you're using the "allwinner,sun6i-a31-i2c" + compatible. + + - clocks: : pointers to the reference clocks for this device, the + first one is the one used for the clock on the i2c bus, + the second one is the clock used to acces the registers + of the controller + + - clock-names : names of used clocks, mandatory if the second clock is + used, the name must be "core", and "reg" (the latter is + only for Armada 7K/8K). + +Examples: + + i2c@11000 { + compatible = "marvell,mv64xxx-i2c"; + reg = <0x11000 0x20>; + interrupts = <29>; + clock-frequency = <100000>; + }; + +For the Armada XP: + + i2c@11000 { + compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c"; + reg = <0x11000 0x100>; + interrupts = <29>; + clock-frequency = <100000>; + }; + +For the Armada 7040: + + i2c@701000 { + compatible = "marvell,mv78230-i2c"; + reg = <0x701000 0x20>; + interrupts = <29>; + clock-frequency = <100000>; + clock-names = "core", "reg"; + clocks = <&core_clock>, <®_clock>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mxs.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mxs.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e1c8ac01eba54da7685cbbaf69109e1ff69634a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-mxs.txt @@ -0,0 +1,25 @@ +* Freescale MXS Inter IC (I2C) Controller + +Required properties: +- compatible: Should be "fsl,-i2c" +- reg: Should contain registers location and length +- interrupts: Should contain ERROR interrupt number +- clock-frequency: Desired I2C bus clock frequency in Hz. + Only 100000Hz and 400000Hz modes are supported. +- dmas: DMA specifier, consisting of a phandle to DMA controller node + and I2C DMA channel ID. + Refer to dma.txt and fsl-mxs-dma.txt for details. +- dma-names: Must be "rx-tx". + +Examples: + +i2c0: i2c@80058000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-i2c"; + reg = <0x80058000 2000>; + interrupts = <111>; + clock-frequency = <100000>; + dmas = <&dma_apbx 6>; + dma-names = "rx-tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-nomadik.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-nomadik.txt new file mode 100644 index 0000000000000000000000000000000000000000..72065b0ff680b151a4efa4b708b1e532ed852a4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-nomadik.txt @@ -0,0 +1,23 @@ +I2C for Nomadik based systems + +Required (non-standard) properties: + - Nil + +Recommended (non-standard) properties: + - clock-frequency : Maximum bus clock frequency for the device + +Optional (non-standard) properties: + - Nil + +Example : + +i2c@80004000 { + compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; + reg = <0x80004000 0x1000>; + interrupts = <0 21 0x4>; + #address-cells = <1>; + #size-cells = <0>; + v-i2c-supply = <&db8500_vape_reg>; + + clock-frequency = <400000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-ocores.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-ocores.txt new file mode 100644 index 0000000000000000000000000000000000000000..17bef9a34e507541ea3f201039b04e199e551fa3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-ocores.txt @@ -0,0 +1,69 @@ +Device tree configuration for i2c-ocores + +Required properties: +- compatible : "opencores,i2c-ocores" or "aeroflexgaisler,i2cmst" +- reg : bus address start and address range size of device +- interrupts : interrupt number +- clocks : handle to the controller clock; see the note below. + Mutually exclusive with opencores,ip-clock-frequency +- opencores,ip-clock-frequency: frequency of the controller clock in Hz; + see the note below. Mutually exclusive with clocks +- #address-cells : should be <1> +- #size-cells : should be <0> + +Optional properties: +- clock-frequency : frequency of bus clock in Hz; see the note below. + Defaults to 100 KHz when the property is not specified +- reg-shift : device register offsets are shifted by this value +- reg-io-width : io register width in bytes (1, 2 or 4) +- regstep : deprecated, use reg-shift above + +Note +clock-frequency property is meant to control the bus frequency for i2c bus +drivers, but it was incorrectly used to specify i2c controller input clock +frequency. So the following rules are set to fix this situation: +- if clock-frequency is present and neither opencores,ip-clock-frequency nor + clocks are, then clock-frequency specifies i2c controller clock frequency. + This is to keep backwards compatibility with setups using old DTB. i2c bus + frequency is fixed at 100 KHz. +- if clocks is present it specifies i2c controller clock. clock-frequency + property specifies i2c bus frequency. +- if opencores,ip-clock-frequency is present it specifies i2c controller + clock frequency. clock-frequency property specifies i2c bus frequency. + +Examples: + + i2c0: ocores@a0000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "opencores,i2c-ocores"; + reg = <0xa0000000 0x8>; + interrupts = <10>; + opencores,ip-clock-frequency = <20000000>; + + reg-shift = <0>; /* 8 bit registers */ + reg-io-width = <1>; /* 8 bit read/write */ + + dummy@60 { + compatible = "dummy"; + reg = <0x60>; + }; + }; +or + i2c0: ocores@a0000000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "opencores,i2c-ocores"; + reg = <0xa0000000 0x8>; + interrupts = <10>; + clocks = <&osc>; + clock-frequency = <400000>; /* i2c bus frequency 400 KHz */ + + reg-shift = <0>; /* 8 bit registers */ + reg-io-width = <1>; /* 8 bit read/write */ + + dummy@60 { + compatible = "dummy"; + reg = <0x60>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-octeon.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-octeon.txt new file mode 100644 index 0000000000000000000000000000000000000000..872d485dffab19c3cce1ed27215272e5f41809cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-octeon.txt @@ -0,0 +1,40 @@ +* Two Wire Serial Interface (TWSI) / I2C + +- compatible: "cavium,octeon-3860-twsi" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + + or + + compatible: "cavium,octeon-7890-twsi" + + Compatibility with cn78XX SOCs. + +- reg: The base address of the TWSI/I2C bus controller register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. I2C addresses have no size component. + +- interrupts: A single interrupt specifier. + +- clock-frequency: The I2C bus clock rate in Hz. + +Example: + twsi0: i2c@1180000001000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cavium,octeon-3860-twsi"; + reg = <0x11800 0x00001000 0x0 0x200>; + interrupts = <0 45>; + clock-frequency = <100000>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + }; + tmp@4c { + compatible = "ti,tmp421"; + reg = <0x4c>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-omap.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e49839d41249ca5168b0de1ea02781a2798486d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-omap.txt @@ -0,0 +1,31 @@ +I2C for OMAP platforms + +Required properties : +- compatible : Must be "ti,omap2420-i2c", "ti,omap2430-i2c", "ti,omap3-i2c" + or "ti,omap4-i2c" +- ti,hwmods : Must be "i2c", n being the instance number (1-based) +- #address-cells = <1>; +- #size-cells = <0>; + +Recommended properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. Otherwise + the default 100 kHz frequency will be used. + +Optional properties: +- Child nodes conforming to i2c bus binding + +Note: Current implementation will fetch base address, irq and dma +from omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples : + +i2c1: i2c@0 { + compatible = "ti,omap3-i2c"; + #address-cells = <1>; + #size-cells = <0>; + ti,hwmods = "i2c1"; + clock-frequency = <400000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-opal.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-opal.txt new file mode 100644 index 0000000000000000000000000000000000000000..12bc61465ee586670b5e62124ce644b7352581da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-opal.txt @@ -0,0 +1,37 @@ +Device-tree bindings for I2C OPAL driver +---------------------------------------- + +Most of the device node and properties layout is specific to the firmware and +used by the firmware itself for configuring the port. From the linux +perspective, the properties of use are "ibm,port-name" and "ibm,opal-id". + +Required properties: + +- reg: Port-id within a given master +- compatible: must be "ibm,opal-i2c" +- ibm,opal-id: Refers to a specific bus and used to identify it when calling + the relevant OPAL functions. +- bus-frequency: Operating frequency of the i2c bus (in HZ). Informational for + linux, used by the FW though. + +Optional properties: +- ibm,port-name: Firmware provides this name that uniquely identifies the i2c + port. + +The node contains a number of other properties that are used by the FW itself +and depend on the specific hardware implementation. The example below depicts +a P8 on-chip bus. + +Example: + +i2c-bus@0 { + reg = <0x0>; + bus-frequency = <0x61a80>; + compatible = "ibm,power8-i2c-port", "ibm,opal-i2c"; + ibm,opal-id = <0x1>; + ibm,port-name = "p8_00000000_e1p0"; + #address-cells = <0x1>; + phandle = <0x10000006>; + #size-cells = <0x0>; + linux,phandle = <0x10000006>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-owl.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-owl.txt new file mode 100644 index 0000000000000000000000000000000000000000..b743fe444e9f6096e2f16ca74bdb5386c8e0e1ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-owl.txt @@ -0,0 +1,27 @@ +Actions Semiconductor Owl I2C controller + +Required properties: + +- compatible : Should be "actions,s900-i2c". +- reg : Offset and length of the register set for the device. +- #address-cells : Should be 1. +- #size-cells : Should be 0. +- interrupts : A single interrupt specifier. +- clocks : Phandle of the clock feeding the I2C controller. + +Optional properties: + +- clock-frequency : Desired I2C bus clock frequency in Hz. As only Normal and + Fast modes are supported, possible values are 100000 and + 400000. +Examples: + + i2c0: i2c@e0170000 { + compatible = "actions,s900-i2c"; + reg = <0 0xe0170000 0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&clock CLK_I2C0>; + clock-frequency = <100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pca-platform.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pca-platform.txt new file mode 100644 index 0000000000000000000000000000000000000000..73a693d66ef7776b32190dfcfdc5cf556d8e1e02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pca-platform.txt @@ -0,0 +1,27 @@ +* NXP PCA PCA9564/PCA9665 I2C controller + +The PCA9564/PCA9665 serves as an interface between most standard +parallel-bus microcontrollers/microprocessors and the serial I2C-bus +and allows the parallel bus system to communicate bi-directionally +with the I2C-bus. + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : one of "nxp,pca9564" or "nxp,pca9665" + +Optional properties + - interrupts : the interrupt number + - reset-gpios : gpio specifier for gpio connected to RESET_N pin. As the line + is active low, it should be marked GPIO_ACTIVE_LOW. + - clock-frequency : I2C bus frequency. + +Example: + i2c0: i2c@80000 { + compatible = "nxp,pca9564"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x80000 0x4>; + reset-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; + clock-frequency = <100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pnx.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pnx.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a59006cf79e53748e0ca7ba17f3ca4c9caf68cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pnx.txt @@ -0,0 +1,34 @@ +* NXP PNX I2C Controller + +Required properties: + + - reg: Offset and length of the register set for the device + - compatible: should be "nxp,pnx-i2c" + - interrupts: configure one interrupt line + - #address-cells: always 1 (for i2c addresses) + - #size-cells: always 0 + +Optional properties: + + - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz + +Examples: + + i2c1: i2c@400a0000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a0000 0x100>; + interrupt-parent = <&mic>; + interrupts = <51 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c2: i2c@400a8000 { + compatible = "nxp,pnx-i2c"; + reg = <0x400a8000 0x100>; + interrupt-parent = <&mic>; + interrupts = <50 0>; + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pxa-pci-ce4100.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pxa-pci-ce4100.txt new file mode 100644 index 0000000000000000000000000000000000000000..569b16248514ff86095a1736200a1d3f5d2d77bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pxa-pci-ce4100.txt @@ -0,0 +1,93 @@ +CE4100 I2C +---------- + +CE4100 has one PCI device which is described as the I2C-Controller. This +PCI device has three PCI-bars, each bar contains a complete I2C +controller. So we have a total of three independent I2C-Controllers +which share only an interrupt line. +The driver is probed via the PCI-ID and is gathering the information of +attached devices from the devices tree. +Grant Likely recommended to use the ranges property to map the PCI-Bar +number to its physical address and to use this to find the child nodes +of the specific I2C controller. This were his exact words: + + Here's where the magic happens. Each entry in + ranges describes how the parent pci address space + (middle group of 3) is translated to the local + address space (first group of 2) and the size of + each range (last cell). In this particular case, + the first cell of the local address is chosen to be + 1:1 mapped to the BARs, and the second is the + offset from be base of the BAR (which would be + non-zero if you had 2 or more devices mapped off + the same BAR) + + ranges allows the address mapping to be described + in a way that the OS can interpret without + requiring custom device driver code. + +This is an example which is used on FalconFalls: +------------------------------------------------ + i2c-controller@b,2 { + #address-cells = <2>; + #size-cells = <1>; + compatible = "pci8086,2e68.2", + "pci8086,2e68", + "pciclass,ff0000", + "pciclass,ff00"; + + reg = <0x15a00 0x0 0x0 0x0 0x0>; + interrupts = <16 1>; + + /* as described by Grant, the first number in the group of + * three is the bar number followed by the 64bit bar address + * followed by size of the mapping. The bar address + * requires also a valid translation in parents ranges + * property. + */ + ranges = <0 0 0x02000000 0 0xdffe0500 0x100 + 1 0 0x02000000 0 0xdffe0600 0x100 + 2 0 0x02000000 0 0xdffe0700 0x100>; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "intel,ce4100-i2c-controller"; + + /* The first number in the reg property is the + * number of the bar + */ + reg = <0 0 0x100>; + + /* This I2C controller has no devices */ + }; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "intel,ce4100-i2c-controller"; + reg = <1 0 0x100>; + + /* This I2C controller has one gpio controller */ + gpio@26 { + #gpio-cells = <2>; + compatible = "ti,pcf8575"; + reg = <0x26>; + gpio-controller; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "intel,ce4100-i2c-controller"; + reg = <2 0 0x100>; + + gpio@26 { + #gpio-cells = <2>; + compatible = "ti,pcf8575"; + reg = <0x26>; + gpio-controller; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pxa.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pxa.txt new file mode 100644 index 0000000000000000000000000000000000000000..c30783c0eca03a42c61b93e0d106a20de0ed92fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-pxa.txt @@ -0,0 +1,31 @@ +* Marvell MMP I2C controller + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible : should be "mrvl,mmp-twsi" where mmp is the name of a + compatible processor, e.g. pxa168, pxa910, mmp2, mmp3. + For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required + as shown in the example below. + For the Armada 3700, the compatible should be "marvell,armada-3700-i2c". + +Recommended properties : + + - interrupts : the interrupt number + - mrvl,i2c-polling : Disable interrupt of i2c controller. Polling + status register of i2c controller instead. + - mrvl,i2c-fast-mode : Enable fast mode of i2c controller. + +Examples: + twsi1: i2c@d4011000 { + compatible = "mrvl,mmp-twsi"; + reg = <0xd4011000 0x1000>; + interrupts = <7>; + mrvl,i2c-fast-mode; + }; + + twsi2: i2c@d4025000 { + compatible = "mrvl,mmp-twsi"; + reg = <0xd4025000 0x1000>; + interrupts = <58>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-rcar.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-rcar.txt new file mode 100644 index 0000000000000000000000000000000000000000..39cd21d95810628b259f22247aebc654cb0e7fa6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-rcar.txt @@ -0,0 +1,59 @@ +I2C for R-Car platforms + +Required properties: +- compatible: + "renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC. + "renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC. + "renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC. + "renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC. + "renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC. + "renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC. + "renesas,i2c-r8a7791" if the device is a part of a R8A7791 SoC. + "renesas,i2c-r8a7792" if the device is a part of a R8A7792 SoC. + "renesas,i2c-r8a7793" if the device is a part of a R8A7793 SoC. + "renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC. + "renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC. + "renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC. + "renesas,i2c-r8a77965" if the device is a part of a R8A77965 SoC. + "renesas,i2c-r8a77970" if the device is a part of a R8A77970 SoC. + "renesas,i2c-r8a77980" if the device is a part of a R8A77980 SoC. + "renesas,i2c-r8a77990" if the device is a part of a R8A77990 SoC. + "renesas,i2c-r8a77995" if the device is a part of a R8A77995 SoC. + "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device. + "renesas,rcar-gen2-i2c" for a generic R-Car Gen2 or RZ/G1 compatible + device. + "renesas,rcar-gen3-i2c" for a generic R-Car Gen3 or RZ/G2 compatible + device. + "renesas,i2c-rcar" (deprecated) + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first followed + by the generic version. + +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt specifier. + +Optional properties: +- clock-frequency: desired I2C bus clock frequency in Hz. The absence of this + property indicates the default frequency 100 kHz. +- clocks: clock specifier. +- dmas: Must contain a list of two references to DMA specifiers, one for + transmission, and one for reception. +- dma-names: Must contain a list of two DMA names, "tx" and "rx". + +- i2c-scl-falling-time-ns: see i2c.txt +- i2c-scl-internal-delay-ns: see i2c.txt +- i2c-scl-rising-time-ns: see i2c.txt + +Examples : + +i2c0: i2c@e6508000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c"; + reg = <0 0xe6508000 0 0x40>; + interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7791_CLK_I2C0>; + clock-frequency = <400000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-riic.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-riic.txt new file mode 100644 index 0000000000000000000000000000000000000000..0bcc4716c319885fab95d1645cd054a87745e56d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-riic.txt @@ -0,0 +1,29 @@ +Device tree configuration for Renesas RIIC driver + +Required properties: +- compatible : "renesas,riic-". "renesas,riic-rz" as fallback +- reg : address start and address range size of device +- interrupts : 8 interrupts (TEI, RI, TI, SPI, STI, NAKI, ALI, TMOI) +- clock-frequency : frequency of bus clock in Hz +- #address-cells : should be <1> +- #size-cells : should be <0> + +Pinctrl properties might be needed, too. See there. + +Example: + + i2c0: i2c@fcfee000 { + compatible = "renesas,riic-r7s72100", "renesas,riic-rz"; + reg = <0xfcfee000 0x44>; + interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>, + <0 158 IRQ_TYPE_EDGE_RISING>, + <0 159 IRQ_TYPE_EDGE_RISING>, + <0 160 IRQ_TYPE_LEVEL_HIGH>, + <0 161 IRQ_TYPE_LEVEL_HIGH>, + <0 162 IRQ_TYPE_LEVEL_HIGH>, + <0 163 IRQ_TYPE_LEVEL_HIGH>, + <0 164 IRQ_TYPE_LEVEL_HIGH>; + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-rk3x.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-rk3x.txt new file mode 100644 index 0000000000000000000000000000000000000000..22f2eeb2c4c93a69e82d1742a902c8820b04e8fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-rk3x.txt @@ -0,0 +1,68 @@ +* Rockchip RK3xxx I2C controller + +This driver interfaces with the native I2C controller present in Rockchip +RK3xxx SoCs. + +Required properties : + + - reg : Offset and length of the register set for the device + - compatible: should be one of the following: + - "rockchip,rv1108-i2c": for rv1108 + - "rockchip,rk3066-i2c": for rk3066 + - "rockchip,rk3188-i2c": for rk3188 + - "rockchip,rk3228-i2c": for rk3228 + - "rockchip,rk3288-i2c": for rk3288 + - "rockchip,rk3328-i2c", "rockchip,rk3399-i2c": for rk3328 + - "rockchip,rk3399-i2c": for rk3399 + - interrupts : interrupt number + - clocks: See ../clock/clock-bindings.txt + - For older hardware (rk3066, rk3188, rk3228, rk3288): + - There is one clock that's used both to derive the functional clock + for the device and as the bus clock. + - For newer hardware (rk3399): specified by name + - "i2c": This is used to derive the functional clock. + - "pclk": This is the bus clock. + +Required on RK3066, RK3188 : + + - rockchip,grf : the phandle of the syscon node for the general register + file (GRF) + - on those SoCs an alias with the correct I2C bus ID (bit offset in the GRF) + is also required. + +Optional properties : + + - clock-frequency : SCL frequency to use (in Hz). If omitted, 100kHz is used. + - i2c-scl-rising-time-ns : Number of nanoseconds the SCL signal takes to rise + (t(r) in I2C specification). If not specified this is assumed to be + the maximum the specification allows(1000 ns for Standard-mode, + 300 ns for Fast-mode) which might cause slightly slower communication. + - i2c-scl-falling-time-ns : Number of nanoseconds the SCL signal takes to fall + (t(f) in the I2C specification). If not specified this is assumed to + be the maximum the specification allows (300 ns) which might cause + slightly slower communication. + - i2c-sda-falling-time-ns : Number of nanoseconds the SDA signal takes to fall + (t(f) in the I2C specification). If not specified we'll use the SCL + value since they are the same in nearly all cases. + +Example: + +aliases { + i2c0 = &i2c0; +} + +i2c0: i2c@2002d000 { + compatible = "rockchip,rk3188-i2c"; + reg = <0x2002d000 0x1000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + + rockchip,grf = <&grf>; + + clock-names = "i2c"; + clocks = <&cru PCLK_I2C0>; + + i2c-scl-rising-time-ns = <800>; + i2c-scl-falling-time-ns = <100>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-s3c2410.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-s3c2410.txt new file mode 100644 index 0000000000000000000000000000000000000000..66ae46d3bc2ff410b5be06a8f1fd288c306c6c4e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-s3c2410.txt @@ -0,0 +1,58 @@ +* Samsung's I2C controller + +The Samsung's I2C controller is used to interface with I2C devices. + +Required properties: + - compatible: value should be either of the following. + (a) "samsung, s3c2410-i2c", for i2c compatible with s3c2410 i2c. + (b) "samsung, s3c2440-i2c", for i2c compatible with s3c2440 i2c. + (c) "samsung, s3c2440-hdmiphy-i2c", for s3c2440-like i2c used + inside HDMIPHY block found on several samsung SoCs + (d) "samsung, exynos5-sata-phy-i2c", for s3c2440-like i2c used as + a host to SATA PHY controller on an internal bus. + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + - samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges. + +Required for all cases except "samsung,s3c2440-hdmiphy-i2c": + - Samsung GPIO variant (deprecated): + - gpios: The order of the gpios should be the following: . + The gpio specifier depends on the gpio controller. Required in all + cases except for "samsung,s3c2440-hdmiphy-i2c" whose input/output + lines are permanently wired to the respective clienta + - Pinctrl variant (preferred, if available): + - pinctrl-0: Pin control group to be used for this controller. + - pinctrl-names: Should contain only one value - "default". + +Optional properties: + - samsung,i2c-slave-addr: Slave address in multi-master environment. If not + specified, default value is 0. + - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not + specified, the default value in Hz is 100000. + - samsung,sysreg-phandle - handle to syscon used to control the system registers + +Example: + + i2c@13870000 { + compatible = "samsung,s3c2440-i2c"; + reg = <0x13870000 0x100>; + interrupts = <345>; + samsung,i2c-sda-delay = <100>; + samsung,i2c-max-bus-freq = <100000>; + /* Samsung GPIO variant begins here */ + gpios = <&gpd1 2 0 /* SDA */ + &gpd1 3 0 /* SCL */>; + /* Samsung GPIO variant ends here */ + /* Pinctrl variant begins here */ + pinctrl-0 = <&i2c3_bus>; + pinctrl-names = "default"; + /* Pinctrl variant ends here */ + #address-cells = <1>; + #size-cells = <0>; + + wm8994@1a { + compatible = "wlf,wm8994"; + reg = <0x1a>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sh_mobile.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sh_mobile.txt new file mode 100644 index 0000000000000000000000000000000000000000..872673adff5aae3db366d1e202b8f4a5118ce825 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sh_mobile.txt @@ -0,0 +1,59 @@ +Device tree configuration for Renesas IIC (sh_mobile) driver + +Required properties: +- compatible : + - "renesas,iic-r8a73a4" (R-Mobile APE6) + - "renesas,iic-r8a7740" (R-Mobile A1) + - "renesas,iic-r8a7743" (RZ/G1M) + - "renesas,iic-r8a7745" (RZ/G1E) + - "renesas,iic-r8a774a1" (RZ/G2M) + - "renesas,iic-r8a7790" (R-Car H2) + - "renesas,iic-r8a7791" (R-Car M2-W) + - "renesas,iic-r8a7792" (R-Car V2H) + - "renesas,iic-r8a7793" (R-Car M2-N) + - "renesas,iic-r8a7794" (R-Car E2) + - "renesas,iic-r8a7795" (R-Car H3) + - "renesas,iic-r8a7796" (R-Car M3-W) + - "renesas,iic-r8a77965" (R-Car M3-N) + - "renesas,iic-sh73a0" (SH-Mobile AG5) + - "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1 + compatible device) + - "renesas,rcar-gen3-iic" (generic R-Car Gen3 or RZ/G2 + compatible device) + - "renesas,rmobile-iic" (generic device) + + When compatible with a generic R-Car version, nodes + must list the SoC-specific version corresponding to + the platform first followed by the generic R-Car + version. + + renesas,rmobile-iic must always follow. + +- reg : address start and address range size of device +- interrupts : interrupt of device +- clocks : clock for device +- #address-cells : should be <1> +- #size-cells : should be <0> + +Optional properties: +- clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset. +- dmas : Must contain a list of two references to DMA + specifiers, one for transmission, and one for + reception. +- dma-names : Must contain a list of two DMA names, "tx" and "rx". + + +Pinctrl properties might be needed, too. See there. + +Example: + + iic0: i2c@e6500000 { + compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic", + "renesas,rmobile-iic"; + reg = <0 0xe6500000 0 0x425>; + interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_IIC0>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sirf.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..2701eefb00f77c9f64d79c63efed43c4b2cec239 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sirf.txt @@ -0,0 +1,19 @@ +I2C for SiRFprimaII platforms + +Required properties : +- compatible : Must be "sirf,prima2-i2c" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt number to the cpu. + +Optional properties: +- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. + The absence of the property indicates the default frequency 100 kHz. + +Examples : + +i2c0: i2c@b00e0000 { + compatible = "sirf,prima2-i2c"; + reg = <0xb00e0000 0x10000>; + interrupts = <24>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sprd.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sprd.txt new file mode 100644 index 0000000000000000000000000000000000000000..60b7cda15dd2b2badabcdae29a60cefa92cdc24a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sprd.txt @@ -0,0 +1,31 @@ +I2C for Spreadtrum platforms + +Required properties: +- compatible: Should be "sprd,sc9860-i2c". +- reg: Specify the physical base address of the controller and length + of memory mapped region. +- interrupts: Should contain I2C interrupt. +- clock-names: Should contain following entries: + "i2c" for I2C clock, + "source" for I2C source (parent) clock, + "enable" for I2C module enable clock. +- clocks: Should contain a clock specifier for each entry in clock-names. +- clock-frequency: Constains desired I2C bus clock frequency in Hz. +- #address-cells: Should be 1 to describe address cells for I2C device address. +- #size-cells: Should be 0 means no size cell for I2C device address. + +Optional properties: +- Child nodes conforming to I2C bus binding + +Examples: +i2c0: i2c@70500000 { + compatible = "sprd,sc9860-i2c"; + reg = <0 0x70500000 0 0x1000>; + interrupts = ; + clock-names = "i2c", "source", "enable"; + clocks = <&clk_i2c3>, <&ext_26m>, <&clk_ap_apb_gates 11>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-st-ddci2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-st-ddci2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd81a482634f3416241196270ee8ad4b4308fc0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-st-ddci2c.txt @@ -0,0 +1,15 @@ +ST Microelectronics DDC I2C + +Required properties : +- compatible : Must be "st,ddci2c" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: interrupt number to the cpu. +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding + +Examples : + diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-st.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c26fda3844a7f06c05cdef710d7e08fef2b76b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-st.txt @@ -0,0 +1,41 @@ +ST SSC binding, for I2C mode operation + +Required properties : +- compatible : Must be "st,comms-ssc-i2c" or "st,comms-ssc4-i2c" +- reg : Offset and length of the register set for the device +- interrupts : the interrupt specifier +- clock-names: Must contain "ssc". +- clocks: Must contain an entry for each name in clock-names. See the common + clock bindings. +- A pinctrl state named "default" must be defined to set pins in mode of + operation for I2C transfer. + +Optional properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, + the default 100 kHz frequency will be used. As only Normal and Fast modes + are supported, possible values are 100000 and 400000. +- st,i2c-min-scl-pulse-width-us : The minimum valid SCL pulse width that is + allowed through the deglitch circuit. In units of us. +- st,i2c-min-sda-pulse-width-us : The minimum valid SDA pulse width that is + allowed through the deglitch circuit. In units of us. +- A pinctrl state named "idle" could be defined to set pins in idle state + when I2C instance is not performing a transfer. +- A pinctrl state named "sleep" could be defined to set pins in sleep state + when driver enters in suspend. + + + +Example : + +i2c0: i2c@fed40000 { + compatible = "st,comms-ssc4-i2c"; + reg = <0xfed40000 0x110>; + interrupts = ; + clocks = <&clk_s_a0_ls CLK_ICN_REG>; + clock-names = "ssc"; + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0_default>; + st,i2c-min-scl-pulse-width-us = <0>; + st,i2c-min-sda-pulse-width-us = <5>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-stm32.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-stm32.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b54899666342b8e5a114bc0842e193871139d5e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-stm32.txt @@ -0,0 +1,56 @@ +* I2C controller embedded in STMicroelectronics STM32 I2C platform + +Required properties : +- compatible : Must be one of the following + - "st,stm32f4-i2c" + - "st,stm32f7-i2c" +- reg : Offset and length of the register set for the device +- interrupts : Must contain the interrupt id for I2C event and then the + interrupt id for I2C error. +- resets: Must contain the phandle to the reset controller. +- clocks: Must contain the input clock of the I2C instance. +- A pinctrl state named "default" must be defined to set pins in mode of + operation for I2C transfer +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties : +- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified, + the default 100 kHz frequency will be used. + For STM32F4 SoC Standard-mode and Fast-mode are supported, possible values are + 100000 and 400000. + For STM32F7 SoC, Standard-mode, Fast-mode and Fast-mode Plus are supported, + possible values are 100000, 400000 and 1000000. +- i2c-scl-rising-time-ns : Only for STM32F7, I2C SCL Rising time for the board + (default: 25) +- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board + (default: 10) + I2C Timings are derived from these 2 values + +Example : + + i2c@40005400 { + compatible = "st,stm32f4-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40005400 0x400>; + interrupts = <31>, + <32>; + resets = <&rcc 277>; + clocks = <&rcc 0 149>; + pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; + pinctrl-names = "default"; + }; + + i2c@40005400 { + compatible = "st,stm32f7-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40005400 0x400>; + interrupts = <31>, + <32>; + resets = <&rcc STM32F7_APB1_RESET(I2C1)>; + clocks = <&rcc 1 CLK_I2C1>; + pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; + pinctrl-names = "default"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sunxi-p2wi.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sunxi-p2wi.txt new file mode 100644 index 0000000000000000000000000000000000000000..49df0053347ada4e808403bb5630e2427dc1b98b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-sunxi-p2wi.txt @@ -0,0 +1,41 @@ + +* Allwinner P2WI (Push/Pull 2 Wire Interface) controller + +Required properties : + + - reg : Offset and length of the register set for the device. + - compatible : Should one of the following: + - "allwinner,sun6i-a31-p2wi" + - interrupts : The interrupt line connected to the P2WI peripheral. + - clocks : The gate clk connected to the P2WI peripheral. + - resets : The reset line connected to the P2WI peripheral. + +Optional properties : + + - clock-frequency : Desired P2WI bus clock frequency in Hz. If not set the +default frequency is 100kHz + +A P2WI may contain one child node encoding a P2WI slave device. + +Slave device properties: + Required properties: + - reg : the I2C slave address used during the initialization + process to switch from I2C to P2WI mode + +Example: + + p2wi@1f03400 { + compatible = "allwinner,sun6i-a31-p2wi"; + reg = <0x01f03400 0x400>; + interrupts = <0 39 4>; + clocks = <&apb0_gates 3>; + clock-frequency = <6000000>; + resets = <&apb0_rst 3>; + + axp221: pmic@68 { + compatible = "x-powers,axp221"; + reg = <0x68>; + + /* ... */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-synquacer.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-synquacer.txt new file mode 100644 index 0000000000000000000000000000000000000000..72f4a2f0fedcfe13a83bccdf3f4b4b8a61dbc521 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-synquacer.txt @@ -0,0 +1,29 @@ +Socionext SynQuacer I2C + +Required properties: +- compatible : Must be "socionext,synquacer-i2c" +- reg : Offset and length of the register set for the device +- interrupts : A single interrupt specifier +- #address-cells : Must be <1>; +- #size-cells : Must be <0>; +- clock-names : Must contain "pclk". +- clocks : Must contain an entry for each name in clock-names. + (See the common clock bindings.) + +Optional properties: +- clock-frequency : Desired I2C bus clock frequency in Hz. As only Normal and + Fast modes are supported, possible values are 100000 and + 400000. + +Example : + + i2c@51210000 { + compatible = "socionext,synquacer-i2c"; + reg = <0x51210000 0x1000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "pclk"; + clocks = <&clk_i2c>; + clock-frequency = <400000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-uniphier-f.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-uniphier-f.txt new file mode 100644 index 0000000000000000000000000000000000000000..27fc6f8c798b45af29fef8b613ef6c50bae13dc1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-uniphier-f.txt @@ -0,0 +1,25 @@ +UniPhier I2C controller (FIFO-builtin) + +Required properties: +- compatible: should be "socionext,uniphier-fi2c". +- #address-cells: should be 1. +- #size-cells: should be 0. +- reg: offset and length of the register set for the device. +- interrupts: a single interrupt specifier. +- clocks: phandle to the input clock. + +Optional properties: +- clock-frequency: desired I2C bus frequency in Hz. The maximum supported + value is 400000. Defaults to 100000 if not specified. + +Examples: + + i2c0: i2c@58780000 { + compatible = "socionext,uniphier-fi2c"; + reg = <0x58780000 0x80>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0 41 4>; + clocks = <&i2c_clk>; + clock-frequency = <100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-uniphier.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-uniphier.txt new file mode 100644 index 0000000000000000000000000000000000000000..26f9d95b3436f76f4688639691a897838aaf9867 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-uniphier.txt @@ -0,0 +1,25 @@ +UniPhier I2C controller (FIFO-less) + +Required properties: +- compatible: should be "socionext,uniphier-i2c". +- #address-cells: should be 1. +- #size-cells: should be 0. +- reg: offset and length of the register set for the device. +- interrupts: a single interrupt specifier. +- clocks: phandle to the input clock. + +Optional properties: +- clock-frequency: desired I2C bus frequency in Hz. The maximum supported + value is 400000. Defaults to 100000 if not specified. + +Examples: + + i2c0: i2c@58400000 { + compatible = "socionext,uniphier-i2c"; + reg = <0x58400000 0x40>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0 41 1>; + clocks = <&i2c_clk>; + clock-frequency = <100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-versatile.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-versatile.txt new file mode 100644 index 0000000000000000000000000000000000000000..361d31c51b6f59b881df097e8c3fe83166608425 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-versatile.txt @@ -0,0 +1,10 @@ +i2c Controller on ARM Versatile platform: + +Required properties: +- compatible : Must be "arm,versatile-i2c"; +- reg +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-vt8500.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-vt8500.txt new file mode 100644 index 0000000000000000000000000000000000000000..94a425eaa6c78bc9e3136ae7055b51635baf16ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-vt8500.txt @@ -0,0 +1,24 @@ +* Wondermedia I2C Controller + +Required properties : + + - compatible : should be "wm,wm8505-i2c" + - reg : Offset and length of the register set for the device + - interrupts : where IRQ is the interrupt number + - clocks : phandle to the I2C clock source + +Optional properties : + + - clock-frequency : desired I2C bus clock frequency in Hz. + Valid values are 100000 and 400000. + Default to 100000 if not specified, or invalid value. + +Example : + + i2c_0: i2c@d8280000 { + compatible = "wm,wm8505-i2c"; + reg = <0xd8280000 0x1000>; + interrupts = <19>; + clocks = <&clki2c0>; + clock-frequency = <400000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xgene-slimpro.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xgene-slimpro.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6b2c20cfbf6ac86eacae0900795ccbb754c6484 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xgene-slimpro.txt @@ -0,0 +1,15 @@ +APM X-Gene SLIMpro Mailbox I2C Driver + +An I2C controller accessed over the "SLIMpro" mailbox. + +Required properties : + + - compatible : should be "apm,xgene-slimpro-i2c" + - mboxes : use the label reference for the mailbox as the first parameter. + The second parameter is the channel number. + +Example : + i2cslimpro { + compatible = "apm,xgene-slimpro-i2c"; + mboxes = <&mailbox 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xiic.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xiic.txt new file mode 100644 index 0000000000000000000000000000000000000000..caf42e98946255098ddbff95c19efa360655fc09 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xiic.txt @@ -0,0 +1,25 @@ +Xilinx IIC controller: + +Required properties: +- compatible : Must be "xlnx,xps-iic-2.00.a" +- reg : IIC register location and length +- interrupts : IIC controller unterrupt +- #address-cells = <1> +- #size-cells = <0> +- clocks: Input clock specifier. Refer to common clock bindings. + +Optional properties: +- Child nodes conforming to i2c bus binding +- clock-names: Input clock name, should be 'pclk'. + +Example: + + axi_iic_0: i2c@40800000 { + compatible = "xlnx,xps-iic-2.00.a"; + clocks = <&clkc 15>; + interrupts = < 1 2 >; + reg = < 0x40800000 0x10000 >; + + #size-cells = <0>; + #address-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xlp9xx.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xlp9xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..f818ef507ab7cdf416be4065b664182dc52a64c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-xlp9xx.txt @@ -0,0 +1,22 @@ +Device tree configuration for the I2C controller on the XLP9xx/5xx SoC + +Required properties: +- compatible : should be "netlogic,xlp980-i2c" +- reg : bus address start and address range size of device +- interrupts : interrupt number + +Optional properties: +- clock-frequency : frequency of bus clock in Hz + Defaults to 100 KHz when the property is not specified + +Example: + +i2c0: i2c@113100 { + compatible = "netlogic,xlp980-i2c"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x113100 0x100>; + clock-frequency = <400000>; + interrupts = <30>; + interrupt-parent = <&pic>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-zx2967.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-zx2967.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb806d1ae4c9d525ba76f713c1a797d7eb7ce1e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c-zx2967.txt @@ -0,0 +1,22 @@ +ZTE zx2967 I2C controller + +Required properties: + - compatible: must be "zte,zx296718-i2c" + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + - clock-frequency: the desired I2C bus clock frequency. + +Examples: + + i2c@112000 { + compatible = "zte,zx296718-i2c"; + reg = <0x00112000 0x1000>; + interrupts = ; + clocks = <&osc24m>; + #address-cells = <1> + #size-cells = <0>; + clock-frequency = <1600000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/i2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..11263982470e548316e0038e202d8dfc05ab9b07 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/i2c.txt @@ -0,0 +1,94 @@ +Generic device tree bindings for I2C busses +=========================================== + +This document describes generic bindings which can be used to describe I2C +busses in a device tree. + +Required properties +------------------- + +- #address-cells - should be <1>. Read more about addresses below. +- #size-cells - should be <0>. +- compatible - name of I2C bus controller following generic names + recommended practice. + +For other required properties e.g. to describe register sets, +clocks, etc. check the binding documentation of the specific driver. + +The cells properties above define that an address of children of an I2C bus +are described by a single value. This is usually a 7 bit address. However, +flags can be attached to the address. I2C_TEN_BIT_ADDRESS is used to mark a 10 +bit address. It is needed to avoid the ambiguity between e.g. a 7 bit address +of 0x50 and a 10 bit address of 0x050 which, in theory, can be on the same bus. +Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we listen to +be devices ourselves. + +Optional properties +------------------- + +These properties may not be supported by all drivers. However, if a driver +wants to support one of the below features, it should adapt the bindings below. + +- clock-frequency + frequency of bus clock in Hz. + +- i2c-bus + For I2C adapters that have child nodes that are a mixture of both I2C + devices and non-I2C devices, the 'i2c-bus' subnode can be used for + populating I2C devices. If the 'i2c-bus' subnode is present, only + subnodes of this will be considered as I2C slaves. The properties, + '#address-cells' and '#size-cells' must be defined under this subnode + if present. + +- i2c-scl-falling-time-ns + Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C + specification. + +- i2c-scl-internal-delay-ns + Number of nanoseconds the IP core additionally needs to setup SCL. + +- i2c-scl-rising-time-ns + Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C + specification. + +- i2c-sda-falling-time-ns + Number of nanoseconds the SDA signal takes to fall; t(f) in the I2C + specification. + +- interrupts + interrupts used by the device. + +- interrupt-names + "irq", "wakeup" and "smbus_alert" names are recognized by I2C core, + other names are left to individual drivers. + +- host-notify + device uses SMBus host notify protocol instead of interrupt line. + +- multi-master + states that there is another master active on this bus. The OS can use + this information to adapt power management to keep the arbitration awake + all the time, for example. + +- wakeup-source + device can be used as a wakeup source. + +- reg + I2C slave addresses + +- reg-names + Names of map programmable addresses. + It can contain any map needing another address than default one. + +Binding may contain optional "interrupts" property, describing interrupts +used by the device. I2C core will assign "irq" interrupt (or the very first +interrupt if not using interrupt names) as primary interrupt for the slave. + +Alternatively, devices supporting SMbus Host Notify, and connected to +adapters that support this feature, may use "host-notify" property. I2C +core will create a virtual interrupt for Host Notify and assign it as +primary interrupt for the slave. + +Also, if device is marked as a wakeup source, I2C core will set up "wakeup" +interrupt for the device. If "wakeup" interrupt name is not present in the +binding, then primary interrupt will be used as wakeup interrupt. diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab240e10debc34dd21f431c53327358872842885 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt @@ -0,0 +1,42 @@ +NVIDIA Tegra186 BPMP I2C controller + +In Tegra186, the BPMP (Boot and Power Management Processor) owns certain HW +devices, such as the I2C controller for the power management I2C bus. Software +running on other CPUs must perform IPC to the BPMP in order to execute +transactions on that I2C bus. This binding describes an I2C bus that is +accessed in such a fashion. + +The BPMP I2C node must be located directly inside the main BPMP node. See +../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding. + +This node represents an I2C controller. See ../i2c/i2c.txt for details of the +core I2C binding. + +Required properties: +- compatible: + Array of strings. + One of: + - "nvidia,tegra186-bpmp-i2c". +- #address-cells: Address cells for I2C device address. + Single-cell integer. + Must be <1>. +- #size-cells: + Single-cell integer. + Must be <0>. +- nvidia,bpmp-bus-id: + Single-cell integer. + Indicates the I2C bus number this DT node represent, as defined by the + BPMP firmware. + +Example: + +bpmp { + ... + + i2c { + compatible = "nvidia,tegra186-bpmp-i2c"; + #address-cells = <1>; + #size-cells = <0>; + nvidia,bpmp-bus-id = <5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/nvidia,tegra20-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/nvidia,tegra20-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..f64064f8bdc25e5f0ee52c024fa1e2b8e36b8a5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/nvidia,tegra20-i2c.txt @@ -0,0 +1,74 @@ +NVIDIA Tegra20/Tegra30/Tegra114 I2C controller driver. + +Required properties: +- compatible : For Tegra20, must be one of "nvidia,tegra20-i2c-dvc" or + "nvidia,tegra20-i2c". For Tegra30, must be "nvidia,tegra30-i2c". + For Tegra114, must be "nvidia,tegra114-i2c". Otherwise, must be + "nvidia,-i2c", plus at least one of the above, where is + tegra124, tegra132, or tegra210. + Details of compatible are as follows: + nvidia,tegra20-i2c-dvc: Tegra20 has specific I2C controller called as DVC I2C + controller. This only support master mode of I2C communication. Register + interface/offset and interrupts handling are different than generic I2C + controller. Driver of DVC I2C controller is only compatible with + "nvidia,tegra20-i2c-dvc". + nvidia,tegra20-i2c: Tegra20 has 4 generic I2C controller. This can support + master and slave mode of I2C communication. The i2c-tegra driver only + support master mode of I2C communication. Driver of I2C controller is + only compatible with "nvidia,tegra20-i2c". + nvidia,tegra30-i2c: Tegra30 has 5 generic I2C controller. This controller is + very much similar to Tegra20 I2C controller with additional feature: + Continue Transfer Support. This feature helps to implement M_NO_START + as per I2C core API transfer flags. Driver of I2C controller is + compatible with "nvidia,tegra30-i2c" to enable the continue transfer + support. This is also compatible with "nvidia,tegra20-i2c" without + continue transfer support. + nvidia,tegra114-i2c: Tegra114 has 5 generic I2C controller. This controller is + very much similar to Tegra30 I2C controller with some hardware + modification: + - Tegra30/Tegra20 I2C controller has 2 clock source called div-clk and + fast-clk. Tegra114 has only one clock source called as div-clk and + hence clock mechanism is changed in I2C controller. + - Tegra30/Tegra20 I2C controller has enabled per packet transfer by + default and there is no way to disable it. Tegra114 has this + interrupt disable by default and SW need to enable explicitly. + Due to above changes, Tegra114 I2C driver makes incompatible with + previous hardware driver. Hence, tegra114 I2C controller is compatible + with "nvidia,tegra114-i2c". +- reg: Should contain I2C controller registers physical address and length. +- interrupts: Should contain I2C controller interrupts. +- address-cells: Address cells for I2C device address. +- size-cells: Size of the I2C device address. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + Tegra20/Tegra30: + - div-clk + - fast-clk + Tegra114: + - div-clk +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - i2c +- dmas: Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names: Must include the following entries: + - rx + - tx + +Example: + + i2c@7000c000 { + compatible = "nvidia,tegra20-i2c"; + reg = <0x7000c000 0x100>; + interrupts = <0 38 0x04>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&tegra_car 12>, <&tegra_car 124>; + clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 12>; + reset-names = "i2c"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/nxp,pca9541.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/nxp,pca9541.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fbbc6970ec524fcacd68ab29b77473e7183ec54 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/nxp,pca9541.txt @@ -0,0 +1,29 @@ +* NXP PCA9541 I2C bus master selector + +Required Properties: + + - compatible: Must be "nxp,pca9541" + + - reg: The I2C address of the device. + + The following required properties are defined externally: + + - I2C arbitration bus node. See i2c-arb.txt in this directory. + + +Example: + + i2c-arbitrator@74 { + compatible = "nxp,pca9541"; + reg = <0x74>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/qcom,i2c-qcom-geni.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/qcom,i2c-qcom-geni.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf5617f24400974f9172d749a751d6d11502f99d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/qcom,i2c-qcom-geni.txt @@ -0,0 +1,42 @@ +GENI based Qualcomm Technologies Inc Universal Peripheral version 3 (QUPv3) + I2C controller + +Required properties: + - compatible: Should be: + * "qcom,i2c-geni. + - reg: Should contain QUP register address and length. + - interrupts: Should contain I2C interrupt. + - clocks: Serial engine core clock, and AHB clocks needed by the device. + - pinctrl-names/pinctrl-0/1: The GPIOs assigned to this core. The names + should be "active" and "sleep" for the pin confuguration when core is active + or when entering sleep state. + - #address-cells: Should be <1> Address cells for i2c device address + - #size-cells: Should be <0> as i2c addresses have no size component + - qcom,wrapper-core: Wrapper QUPv3 core containing this I2C controller. + +Optional property: + - qcom,clk-freq-out : Desired I2C bus clock frequency in Hz. + When missing default to 400000Hz. + - qcom,shared : Boolean flag to support multi-ee usecase, used in GSI mode. + Needs to be added by client driver node in case of multi-ee usecase. + +Child nodes should conform to i2c bus binding. + +Example: + +i2c@a94000 { + compatible = "qcom,i2c-geni"; + reg = <0xa94000 0x4000>; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qup_1_i2c_5_active>; + pinctrl-1 = <&qup_1_i2c_5_sleep>; + #address-cells = <1>; + #size-cells = <0>; + qcom,wrapper-core = <&qupv3_0>; + qcom,clk-freq-out = <400000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/i2c/qcom,i2c-qup.txt b/arch/arm64/boot/dts/vendor/bindings/i2c/qcom,i2c-qup.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc71754a56afe52715b086dbd5d416391918ede2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i2c/qcom,i2c-qup.txt @@ -0,0 +1,40 @@ +Qualcomm Universal Peripheral (QUP) I2C controller + +Required properties: + - compatible: Should be: + * "qcom,i2c-qup-v1.1.1" for 8660, 8960 and 8064. + * "qcom,i2c-qup-v2.1.1" for 8974 v1. + * "qcom,i2c-qup-v2.2.1" for 8974 v2 and later. + - reg: Should contain QUP register address and length. + - interrupts: Should contain I2C interrupt. + + - clocks: A list of phandles + clock-specifiers, one for each entry in + clock-names. + - clock-names: Should contain: + * "core" for the core clock + * "iface" for the AHB clock + + - #address-cells: Should be <1> Address cells for i2c device address + - #size-cells: Should be <0> as i2c addresses have no size component + +Optional properties: + - clock-frequency: Should specify the desired i2c bus clock frequency in Hz, + defaults to 100kHz if omitted. + +Child nodes should conform to i2c bus binding. + +Example: + + i2c@f9924000 { + compatible = "qcom,i2c-qup-v2.2.1"; + reg = <0xf9924000 0x1000>; + interrupts = <0 96 0>; + + clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + + clock-frequency = <355000>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i3c/i3c.txt b/arch/arm64/boot/dts/vendor/bindings/i3c/i3c.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab729a0a86ae7f5aee85cc8034ad882da4727469 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i3c/i3c.txt @@ -0,0 +1,138 @@ +Generic device tree bindings for I3C busses +=========================================== + +This document describes generic bindings that should be used to describe I3C +busses in a device tree. + +Required properties +------------------- + +- #address-cells - should be <3>. Read more about addresses below. +- #size-cells - should be <0>. +- compatible - name of the I3C master controller driving the I3C bus + +For other required properties e.g. to describe register sets, +clocks, etc. check the binding documentation of the specific driver. +The node describing an I3C bus should be named i3c-master. + +Optional properties +------------------- + +These properties may not be supported by all I3C master drivers. Each I3C +master bindings should specify which of them are supported. + +- i3c-scl-hz: frequency of the SCL signal used for I3C transfers. + When undefined the core sets it to 12.5MHz. + +- i2c-scl-hz: frequency of the SCL signal used for I2C transfers. + When undefined, the core looks at LVR (Legacy Virtual Register) + values of I2C devices described in the device tree to determine + the maximum I2C frequency. + +I2C devices +=========== + +Each I2C device connected to the bus should be described in a subnode. All +properties described in Documentation/devicetree/bindings/i2c/i2c.txt are +valid here, but several new properties have been added. + +New constraint on existing properties: +-------------------------------------- +- reg: contains 3 cells + + first cell : still encoding the I2C address + + + second cell: shall be 0 + + + third cell: shall encode the I3C LVR (Legacy Virtual Register) + bit[31:8]: unused/ignored + bit[7:5]: I2C device index. Possible values + * 0: I2C device has a 50 ns spike filter + * 1: I2C device does not have a 50 ns spike filter but supports high + frequency on SCL + * 2: I2C device does not have a 50 ns spike filter and is not tolerant + to high frequencies + * 3-7: reserved + + bit[4]: tell whether the device operates in FM (Fast Mode) or FM+ mode + * 0: FM+ mode + * 1: FM mode + + bit[3:0]: device type + * 0-15: reserved + +The I2C node unit-address should always match the first cell of the reg +property: @. + +I3C devices +=========== + +All I3C devices are supposed to support DAA (Dynamic Address Assignment), and +are thus discoverable. So, by default, I3C devices do not have to be described +in the device tree. +This being said, one might want to attach extra resources to these devices, +and those resources may have to be described in the device tree, which in turn +means we have to describe I3C devices. + +Another use case for describing an I3C device in the device tree is when this +I3C device has a static I2C address and we want to assign it a specific I3C +dynamic address before the DAA takes place (so that other devices on the bus +can't take this dynamic address). + +The I3C device should be names @,, +where device-type is describing the type of device connected on the bus +(gpio-controller, sensor, ...). + +Required properties +------------------- +- reg: contains 3 cells + + first cell : encodes the static I2C address. Should be 0 if the device does + not have one (0 is not a valid I2C address). + + + second and third cells: should encode the ProvisionalID. The second cell + contains the manufacturer ID left-shifted by 1. + The third cell contains ORing of the part ID + left-shifted by 16, the instance ID left-shifted + by 12 and the extra information. This encoding is + following the PID definition provided by the I3C + specification. + +Optional properties +------------------- +- assigned-address: dynamic address to be assigned to this device. This + property is only valid if the I3C device has a static + address (first cell of the reg property != 0). + + +Example: + + i3c-master@d040000 { + compatible = "cdns,i3c-master"; + clocks = <&coreclock>, <&i3csysclock>; + clock-names = "pclk", "sysclk"; + interrupts = <3 0>; + reg = <0x0d040000 0x1000>; + #address-cells = <3>; + #size-cells = <0>; + i2c-scl-hz = <100000>; + + /* I2C device. */ + nunchuk: nunchuk@52 { + compatible = "nintendo,nunchuk"; + reg = <0x52 0x0 0x10>; + }; + + /* I3C device with a static I2C address. */ + thermal_sensor: sensor@68,39200144004 { + reg = <0x68 0x392 0x144004>; + assigned-address = <0xa>; + }; + + /* + * I3C device without a static I2C address but requiring + * resources described in the DT. + */ + sensor@0,39200154004 { + reg = <0x0 0x392 0x154004>; + clocks = <&clock_provider 0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/i3c/qcom,geni-i3c.txt b/arch/arm64/boot/dts/vendor/bindings/i3c/qcom,geni-i3c.txt new file mode 100644 index 0000000000000000000000000000000000000000..cef74fa7f14c8217856055d13940bd8cf1d51471 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/i3c/qcom,geni-i3c.txt @@ -0,0 +1,50 @@ +Qualcomm Technologies, Inc. GENI I3C master block + +Generic bindings document for GENI I3C master controller driver. + +Required properties: +- compatible: shall be "qcom,geni-i3c". +- clocks: shall reference the se clock. +- clock-names: shall contain clock name corresponding to the serial engine. +- interrupts: the interrupt line connected to this I3C master. +- reg: I3C master registers. +- qcom,wrapper-core: Wrapper QUPv3 core containing this I3C controller. +- qcom,ibi-ctrl-id: IBI controller instance number. + +Optional properties: +- se-clock-frequency: Source serial clock frequency to use. +- dfs-index: Dynamic frequency scaling table index to use. + +Mandatory properties defined by the generic binding (see +Documentation/devicetree/bindings/i3c/i3c.txt for more details): + +- #address-cells: shall be set to 3. +- #size-cells: shall be set to 0. + +Optional properties defined by the generic binding (see +Documentation/devicetree/bindings/i3c/i3c.txt for more details): + +- i2c-scl-hz: frequency for i2c transfers. +- i3c-scl-hz: frequency for i3c transfers. + +I3C device connected on the bus follow the generic description (see +Documentation/devicetree/bindings/i3c/i3c.txt for more details). + +Example: + i3c0: i3c-master@980000 { + compatible = "qcom,geni-i3c"; + reg = <0x980000 0x4000>, + <0xec30000 0x10000>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i3c_active>; + pinctrl-1 = <&qupv3_se0_i3c_sleep>; + interrupts = ; + #address-cells = <3>; + #size-cells = <0>; + qcom,wrapper-core = <&qupv3_0>; + qcom,ibi-ctrl-id = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/accel/adxl345.txt b/arch/arm64/boot/dts/vendor/bindings/iio/accel/adxl345.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9525f6e3d43337599af0ee8000a29663332641a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/accel/adxl345.txt @@ -0,0 +1,39 @@ +Analog Devices ADXL345/ADXL375 3-Axis Digital Accelerometers + +http://www.analog.com/en/products/mems/accelerometers/adxl345.html +http://www.analog.com/en/products/sensors-mems/accelerometers/adxl375.html + +Required properties: + - compatible : should be one of + "adi,adxl345" + "adi,adxl375" + - reg : the I2C address or SPI chip select number of the sensor + +Required properties for SPI bus usage: + - spi-max-frequency : set maximum clock frequency, must be 5000000 + - spi-cpol and spi-cpha : must be defined for adxl345 to enable SPI mode 3 + +Optional properties: + - interrupts: interrupt mapping for IRQ as documented in + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example for a I2C device node: + + accelerometer@2a { + compatible = "adi,adxl345"; + reg = <0x53>; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + +Example for a SPI device node: + + accelerometer@0 { + compatible = "adi,adxl345"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpol; + spi-cpha; + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/accel/bma180.txt b/arch/arm64/boot/dts/vendor/bindings/iio/accel/bma180.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b25b4c4d446b9f48ac5de7c47d64679d3be2277 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/accel/bma180.txt @@ -0,0 +1,26 @@ +* Bosch BMA180 / BMA250 triaxial acceleration sensor + +http://omapworld.com/BMA180_111_1002839.pdf +http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/bst-bma250-ds002-05.pdf + +Required properties: + + - compatible : should be "bosch,bma180" or "bosch,bma250" + - reg : the I2C address of the sensor + +Optional properties: + + - interrupts : interrupt mapping for GPIO IRQ, it should by configured with + flags IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING + For the bma250 the first interrupt listed must be the one + connected to the INT1 pin, the second (optional) interrupt + listed must be the one connected to the INT2 pin. + +Example: + +bma180@40 { + compatible = "bosch,bma180"; + reg = <0x40>; + interrupt-parent = <&gpio6>; + interrupts = <18 (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/accel/dmard06.txt b/arch/arm64/boot/dts/vendor/bindings/iio/accel/dmard06.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce105a12c645747dba77989a647fd104bc472dfc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/accel/dmard06.txt @@ -0,0 +1,19 @@ +Device tree bindings for Domintech DMARD05, DMARD06, DMARD07 accelerometers + +Required properties: + - compatible : Should be "domintech,dmard05" + or "domintech,dmard06" + or "domintech,dmard07" + - reg : I2C address of the chip. Should be 0x1c + +Example: + &i2c1 { + /* ... */ + + accelerometer@1c { + compatible = "domintech,dmard06"; + reg = <0x1c>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/accel/kionix,kxsd9.txt b/arch/arm64/boot/dts/vendor/bindings/iio/accel/kionix,kxsd9.txt new file mode 100644 index 0000000000000000000000000000000000000000..b25bf3a77e0fd3b08b5a810d504d2fe762df0b8c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/accel/kionix,kxsd9.txt @@ -0,0 +1,22 @@ +Kionix KXSD9 Accelerometer device tree bindings + +Required properties: + - compatible: should be set to "kionix,kxsd9" + - reg: i2c slave address + +Optional properties: + - vdd-supply: The input supply for VDD + - iovdd-supply: The input supply for IOVDD + - interrupts: The movement detection interrupt + - mount-matrix: See mount-matrix.txt + +Example: + +kxsd9@18 { + compatible = "kionix,kxsd9"; + reg = <0x18>; + interrupt-parent = <&foo>; + interrupts = <57 IRQ_TYPE_EDGE_FALLING>; + iovdd-supply = <&bar>; + vdd-supply = <&baz>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/accel/lis302.txt b/arch/arm64/boot/dts/vendor/bindings/iio/accel/lis302.txt new file mode 100644 index 0000000000000000000000000000000000000000..dfdce67826bae50cf67d073c947a079628714368 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/accel/lis302.txt @@ -0,0 +1,119 @@ +LIS302 accelerometer devicetree bindings + +This device is matched via its bus drivers, and has a number of properties +that apply in on the generic device (independent from the bus). + + +Required properties for the SPI bindings: + - compatible: should be set to "st,lis3lv02d-spi" + - reg: the chipselect index + - spi-max-frequency: maximal bus speed, should be set to 1000000 unless + constrained by external circuitry + - interrupts: the interrupt generated by the device + +Required properties for the I2C bindings: + - compatible: should be set to "st,lis3lv02d" + - reg: i2c slave address + - Vdd-supply: The input supply for Vdd + - Vdd_IO-supply: The input supply for Vdd_IO + + +Optional properties for all bus drivers: + + - st,click-single-{x,y,z}: if present, tells the device to issue an + interrupt on single click events on the + x/y/z axis. + - st,click-double-{x,y,z}: if present, tells the device to issue an + interrupt on double click events on the + x/y/z axis. + - st,click-thresh-{x,y,z}: set the x/y/z axis threshold + - st,click-click-time-limit: click time limit, from 0 to 127.5msec + with step of 0.5 msec + - st,click-latency: click latency, from 0 to 255 msec with + step of 1 msec. + - st,click-window: click window, from 0 to 255 msec with + step of 1 msec. + - st,irq{1,2}-disable: disable IRQ 1/2 + - st,irq{1,2}-ff-wu-1: raise IRQ 1/2 on FF_WU_1 condition + - st,irq{1,2}-ff-wu-2: raise IRQ 1/2 on FF_WU_2 condition + - st,irq{1,2}-data-ready: raise IRQ 1/2 on data ready contition + - st,irq{1,2}-click: raise IRQ 1/2 on click condition + - st,irq-open-drain: consider IRQ lines open-drain + - st,irq-active-low: make IRQ lines active low + - st,wu-duration-1: duration register for Free-Fall/Wake-Up + interrupt 1 + - st,wu-duration-2: duration register for Free-Fall/Wake-Up + interrupt 2 + - st,wakeup-{x,y,z}-{lo,hi}: set wakeup condition on x/y/z axis for + upper/lower limit + - st,wakeup-threshold: set wakeup threshold + - st,wakeup2-{x,y,z}-{lo,hi}: set wakeup condition on x/y/z axis for + upper/lower limit for second wakeup + engine. + - st,wakeup2-threshold: set wakeup threshold for second wakeup + engine. + - st,highpass-cutoff-hz=: 1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of + highpass cut-off frequency + - st,hipass{1,2}-disable: disable highpass 1/2. + - st,default-rate=: set the default rate + - st,axis-{x,y,z}=: set the axis to map to the three coordinates. + Negative values can be used for inverted axis. + - st,{min,max}-limit-{x,y,z} set the min/max limits for x/y/z axis + (used by self-test) + + +Example for a SPI device node: + + lis302@0 { + compatible = "st,lis302dl-spi"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupt-parent = <&gpio>; + interrupts = <104 0>; + + st,click-single-x; + st,click-single-y; + st,click-single-z; + st,click-thresh-x = <10>; + st,click-thresh-y = <10>; + st,click-thresh-z = <10>; + st,irq1-click; + st,irq2-click; + st,wakeup-x-lo; + st,wakeup-x-hi; + st,wakeup-y-lo; + st,wakeup-y-hi; + st,wakeup-z-lo; + st,wakeup-z-hi; + }; + +Example for a I2C device node: + + lis331dlh: lis331dlh@18 { + compatible = "st,lis331dlh", "st,lis3lv02d"; + reg = <0x18>; + Vdd-supply = <&lis3_reg>; + Vdd_IO-supply = <&lis3_reg>; + + st,click-single-x; + st,click-single-y; + st,click-single-z; + st,click-thresh-x = <10>; + st,click-thresh-y = <10>; + st,click-thresh-z = <10>; + st,irq1-click; + st,irq2-click; + st,wakeup-x-lo; + st,wakeup-x-hi; + st,wakeup-y-lo; + st,wakeup-y-hi; + st,wakeup-z-lo; + st,wakeup-z-hi; + st,min-limit-x = <120>; + st,min-limit-y = <120>; + st,min-limit-z = <140>; + st,max-limit-x = <550>; + st,max-limit-y = <550>; + st,max-limit-z = <750>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/accel/mma8452.txt b/arch/arm64/boot/dts/vendor/bindings/iio/accel/mma8452.txt new file mode 100644 index 0000000000000000000000000000000000000000..2100e9af379c6942c9b3e09bd481e591356d3078 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/accel/mma8452.txt @@ -0,0 +1,31 @@ +Freescale MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC or FXLS8471Q +triaxial accelerometer + +Required properties: + + - compatible: should contain one of + * "fsl,mma8451" + * "fsl,mma8452" + * "fsl,mma8453" + * "fsl,mma8652" + * "fsl,mma8653" + * "fsl,fxls8471" + + - reg: the I2C address of the chip + +Optional properties: + + - interrupts: interrupt mapping for GPIO IRQ + + - interrupt-names: should contain "INT1" and/or "INT2", the accelerometer's + interrupt line in use. + +Example: + + mma8453fc@1d { + compatible = "fsl,mma8453"; + reg = <0x1d>; + interrupt-parent = <&gpio1>; + interrupts = <5 0>; + interrupt-names = "INT2"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/amlogic,meson-saradc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/amlogic,meson-saradc.txt new file mode 100644 index 0000000000000000000000000000000000000000..54b823f3a45301d63ff594783f07b015e7f6c5d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/amlogic,meson-saradc.txt @@ -0,0 +1,37 @@ +* Amlogic Meson SAR (Successive Approximation Register) A/D converter + +Required properties: +- compatible: depending on the SoC this should be one of: + - "amlogic,meson8-saradc" for Meson8 + - "amlogic,meson8b-saradc" for Meson8b + - "amlogic,meson8m2-saradc" for Meson8m2 + - "amlogic,meson-gxbb-saradc" for GXBB + - "amlogic,meson-gxl-saradc" for GXL + - "amlogic,meson-gxm-saradc" for GXM + - "amlogic,meson-axg-saradc" for AXG + along with the generic "amlogic,meson-saradc" +- reg: the physical base address and length of the registers +- interrupts: the interrupt indicating end of sampling +- clocks: phandle and clock identifier (see clock-names) +- clock-names: mandatory clocks: + - "clkin" for the reference clock (typically XTAL) + - "core" for the SAR ADC core clock + optional clocks: + - "adc_clk" for the ADC (sampling) clock + - "adc_sel" for the ADC (sampling) clock mux +- vref-supply: the regulator supply for the ADC reference voltage +- #io-channel-cells: must be 1, see ../iio-bindings.txt + +Example: + saradc: adc@8680 { + compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc"; + #io-channel-cells = <1>; + reg = <0x0 0x8680 0x0 0x34>; + interrupts = ; + clocks = <&xtal>, + <&clkc CLKID_SAR_ADC>, + <&clkc CLKID_SANA>, + <&clkc CLKID_SAR_ADC_CLK>, + <&clkc CLKID_SAR_ADC_SEL>; + clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/aspeed_adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/aspeed_adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..034fc2ba100e7924dfafcc93ffbb0ed66a5c1609 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/aspeed_adc.txt @@ -0,0 +1,22 @@ +Aspeed ADC + +This device is a 10-bit converter for 16 voltage channels. All inputs are +single ended. + +Required properties: +- compatible: Should be "aspeed,ast2400-adc" or "aspeed,ast2500-adc" +- reg: memory window mapping address and length +- clocks: Input clock used to derive the sample clock. Expected to be the + SoC's APB clock. +- resets: Reset controller phandle +- #io-channel-cells: Must be set to <1> to indicate channels are selected + by index. + +Example: + adc@1e6e9000 { + compatible = "aspeed,ast2400-adc"; + reg = <0x1e6e9000 0xb0>; + clocks = <&syscon ASPEED_CLK_APB>; + resets = <&syscon ASPEED_RESET_ADC>; + #io-channel-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/at91-sama5d2_adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/at91-sama5d2_adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a3c1d496e1a0bee7f2b9ae25168a7d66ff0ca72 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/at91-sama5d2_adc.txt @@ -0,0 +1,50 @@ +* AT91 SAMA5D2 Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "atmel,sama5d2-adc". + - reg: Should contain ADC registers location and length. + - interrupts: Should contain the IRQ line for the ADC. + - clocks: phandle to device clock. + - clock-names: Must be "adc_clk". + - vref-supply: Supply used as reference for conversions. + - vddana-supply: Supply for the adc device. + - atmel,min-sample-rate-hz: Minimum sampling rate, it depends on SoC. + - atmel,max-sample-rate-hz: Maximum sampling rate, it depends on SoC. + - atmel,startup-time-ms: Startup time expressed in ms, it depends on SoC. + - atmel,trigger-edge-type: One of possible edge types for the ADTRG hardware + trigger pin. When the specific edge type is detected, the conversion will + start. Possible values are rising, falling, or both. + This property uses the IRQ edge types values: IRQ_TYPE_EDGE_RISING , + IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH + +Optional properties: + - dmas: Phandle to dma channel for the ADC. + - dma-names: Must be "rx" when dmas property is being used. + See ../../dma/dma.txt for details. + - #io-channel-cells: in case consumer drivers are attached, this must be 1. + See for details. + +Properties for consumer drivers: + - Consumer drivers can be connected to this producer device, as specified + in + - Channels exposed are specified in: + + +Example: + +adc: adc@fc030000 { + compatible = "atmel,sama5d2-adc"; + reg = <0xfc030000 0x100>; + interrupts = <40 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&adc_clk>; + clock-names = "adc_clk"; + atmel,min-sample-rate-hz = <200000>; + atmel,max-sample-rate-hz = <20000000>; + atmel,startup-time-ms = <4>; + vddana-supply = <&vdd_3v3_lp_reg>; + vref-supply = <&vdd_3v3_lp_reg>; + atmel,trigger-edge-type = ; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>; + dma-names = "rx"; + #io-channel-cells = <1>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/at91_adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/at91_adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f65b04fb79623b1885340bfd2a5e5f1fcb2ed8e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/at91_adc.txt @@ -0,0 +1,83 @@ +* AT91's Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "atmel,-adc" + can be "at91sam9260", "at91sam9g45" or "at91sam9x5" + - reg: Should contain ADC registers location and length + - interrupts: Should contain the IRQ line for the ADC + - clock-names: tuple listing input clock names. + Required elements: "adc_clk", "adc_op_clk". + - clocks: phandles to input clocks. + - atmel,adc-channels-used: Bitmask of the channels muxed and enabled for this + device + - atmel,adc-startup-time: Startup Time of the ADC in microseconds as + defined in the datasheet + - atmel,adc-vref: Reference voltage in millivolts for the conversions + - atmel,adc-res: List of resolutions in bits supported by the ADC. List size + must be two at least. + - atmel,adc-res-names: Contains one identifier string for each resolution + in atmel,adc-res property. "lowres" and "highres" + identifiers are required. + +Optional properties: + - atmel,adc-use-external-triggers: Boolean to enable the external triggers + - atmel,adc-use-res: String corresponding to an identifier from + atmel,adc-res-names property. If not specified, the highest + resolution will be used. + - atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion + - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds + - atmel,adc-ts-wires: Number of touchscreen wires. Should be 4 or 5. If this + value is set, then the adc driver will enable touchscreen + support. + NOTE: when adc touchscreen is enabled, the adc hardware trigger will be + disabled. Since touchscreen will occupy the trigger register. + - atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It + makes touch detection more precise. + +Optional trigger Nodes: + - Required properties: + * trigger-name: Name of the trigger exposed to the user + * trigger-value: Value to put in the Trigger register + to activate this trigger + - Optional properties: + * trigger-external: Is the trigger an external trigger? + +Examples: +adc0: adc@fffb0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91sam9260-adc"; + reg = <0xfffb0000 0x100>; + interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&adc_clk>, <&adc_op_clk>; + clock-names = "adc_clk", "adc_op_clk"; + atmel,adc-channels-used = <0xff>; + atmel,adc-startup-time = <40>; + atmel,adc-use-external-triggers; + atmel,adc-vref = <3300>; + atmel,adc-res = <8 10>; + atmel,adc-res-names = "lowres", "highres"; + atmel,adc-use-res = "lowres"; + + trigger0 { + trigger-name = "external-rising"; + trigger-value = <0x1>; + trigger-external; + }; + trigger1 { + trigger-name = "external-falling"; + trigger-value = <0x2>; + trigger-external; + }; + + trigger2 { + trigger-name = "external-any"; + trigger-value = <0x3>; + trigger-external; + }; + + trigger3 { + trigger-name = "continuous"; + trigger-value = <0x6>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/avia-hx711.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/avia-hx711.txt new file mode 100644 index 0000000000000000000000000000000000000000..7222328a3d0dd6c2eb2cc23a6f35ce7d7f47cded --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/avia-hx711.txt @@ -0,0 +1,24 @@ +* AVIA HX711 ADC chip for weight cells + Bit-banging driver + +Required properties: + - compatible: Should be "avia,hx711" + - sck-gpios: Definition of the GPIO for the clock + - dout-gpios: Definition of the GPIO for data-out + See Documentation/devicetree/bindings/gpio/gpio.txt + - avdd-supply: Definition of the regulator used as analog supply + +Optional properties: + - clock-frequency: Frequency of PD_SCK in Hz + Minimum value allowed is 10 kHz because of maximum + high time of 50 microseconds. + +Example: +weight { + compatible = "avia,hx711"; + sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>; + dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + avdd-suppy = <&avdd>; + clock-frequency = <100000>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/axp20x_adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/axp20x_adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a6313913923a7dadcaa5c495e425ac1d1f85f06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/axp20x_adc.txt @@ -0,0 +1,48 @@ +* X-Powers AXP ADC bindings + +Required properties: + - compatible: should be one of: + - "x-powers,axp209-adc", + - "x-powers,axp221-adc", + - "x-powers,axp813-adc", + - #io-channel-cells: should be 1, + +Example: + +&axp22x { + adc { + compatible = "x-powers,axp221-adc"; + #io-channel-cells = <1>; + }; +}; + +ADC channels and their indexes per variant: + +AXP209 +------ + 0 | acin_v + 1 | acin_i + 2 | vbus_v + 3 | vbus_i + 4 | pmic_temp + 5 | gpio0_v + 6 | gpio1_v + 7 | ipsout_v + 8 | batt_v + 9 | batt_chrg_i +10 | batt_dischrg_i + +AXP22x +------ + 0 | pmic_temp + 1 | batt_v + 2 | batt_chrg_i + 3 | batt_dischrg_i + +AXP813 +------ + 0 | pmic_temp + 1 | gpio0_v + 2 | batt_v + 3 | batt_chrg_i + 4 | batt_dischrg_i diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/berlin2_adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/berlin2_adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..908334c6b07f53169c9ffe91f11cb5cfdc3f1b27 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/berlin2_adc.txt @@ -0,0 +1,19 @@ +* Berlin Analog to Digital Converter (ADC) + +The Berlin ADC has 8 channels, with one connected to a temperature sensor. +It is part of the system controller register set. The ADC node should be a +sub-node of the system controller node. + +Required properties: +- compatible: must be "marvell,berlin2-adc" +- interrupts: the interrupts for the ADC and the temperature sensor +- interrupt-names: should be "adc" and "tsen" + +Example: + +adc: adc { + compatible = "marvell,berlin2-adc"; + interrupt-parent = <&sic>; + interrupts = <12>, <14>; + interrupt-names = "adc", "tsen"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/brcm,iproc-static-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/brcm,iproc-static-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b1b1e4086d4f1eb11a12bfba7a256e1aba86727 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/brcm,iproc-static-adc.txt @@ -0,0 +1,40 @@ +* Broadcom's IPROC Static ADC controller + +Broadcom iProc ADC controller has 8 channels 10bit ADC. +Allows user to convert analog input voltage values to digital. + +Required properties: + +- compatible: Must be "brcm,iproc-static-adc" + +- adc-syscon: Handler of syscon node defining physical base address of the + controller and length of memory mapped region. + +- #io-channel-cells = <1>; As ADC has multiple outputs + refer to Documentation/devicetree/bindings/iio/iio-bindings.txt for details. + +- io-channel-ranges: + refer to Documentation/devicetree/bindings/iio/iio-bindings.txt for details. + +- clocks: Clock used for this block. + +- clock-names: Clock name should be given as tsc_clk. + +- interrupts: interrupt line number. + +For example: + + ts_adc_syscon: ts_adc_syscon@180a6000 { + compatible = "brcm,iproc-ts-adc-syscon","syscon"; + reg = <0x180a6000 0xc30>; + }; + + adc: adc@180a6000 { + compatible = "brcm,iproc-static-adc"; + adc-syscon = <&ts_adc_syscon>; + #io-channel-cells = <1>; + io-channel-ranges; + clocks = <&asiu_clks BCM_CYGNUS_ASIU_ADC_CLK>; + clock-names = "tsc_clk"; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/cc10001_adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/cc10001_adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..904f76de90552ffca6cc2f5922ea547a015f9690 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/cc10001_adc.txt @@ -0,0 +1,22 @@ +* Cosmic Circuits - Analog to Digital Converter (CC-10001-ADC) + +Required properties: + - compatible: Should be "cosmic,10001-adc" + - reg: Should contain adc registers location and length. + - clock-names: Should contain "adc". + - clocks: Should contain a clock specifier for each entry in clock-names + - vref-supply: The regulator supply ADC reference voltage. + +Optional properties: + - adc-reserved-channels: Bitmask of reserved channels, + i.e. channels that cannot be used by the OS. + +Example: +adc: adc@18101600 { + compatible = "cosmic,10001-adc"; + reg = <0x18101600 0x24>; + adc-reserved-channels = <0x2>; + clocks = <&adc_clk>; + clock-names = "adc"; + vref-supply = <®_1v8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/cpcap-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/cpcap-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec04008e8f4fdd6f7cee35ad889c6a399ed8ce66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/cpcap-adc.txt @@ -0,0 +1,17 @@ +Motorola CPCAP PMIC ADC binding + +Required properties: +- compatible: Should be "motorola,cpcap-adc" or "motorola,mapphone-cpcap-adc" +- interrupts: The interrupt number for the ADC device +- interrupt-names: Should be "adcdone" +- #io-channel-cells: Number of cells in an IIO specifier + +Example: + +cpcap_adc: adc { + compatible = "motorola,mapphone-cpcap-adc"; + interrupt-parent = <&cpcap>; + interrupts = <8 IRQ_TYPE_NONE>; + interrupt-names = "adcdone"; + #io-channel-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/da9150-gpadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/da9150-gpadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c07228da92acf08818e3a31fb604652336a01a5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/da9150-gpadc.txt @@ -0,0 +1,16 @@ +Dialog Semiconductor DA9150 IIO GPADC bindings + +Required properties: +- compatible: "dlg,da9150-gpadc" for DA9150 IIO GPADC +- #io-channel-cells: Should be set to <1> + (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info) + +For further information on GPADC channels, see device datasheet. + + +Example: + + gpadc: da9150-gpadc { + compatible = "dlg,da9150-gpadc"; + #io-channel-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/envelope-detector.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/envelope-detector.txt new file mode 100644 index 0000000000000000000000000000000000000000..27544bdd4478f9a7b976900e4be6ff8585bc4e49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/envelope-detector.txt @@ -0,0 +1,54 @@ +Bindings for ADC envelope detector using a DAC and a comparator + +The DAC is used to find the peak level of an alternating voltage input +signal by a binary search using the output of a comparator wired to +an interrupt pin. Like so: + _ + | \ + input +------>-------|+ \ + | \ + .-------. | }---. + | | | / | + | dac|-->--|- / | + | | |_/ | + | | | + | | | + | irq|------<-------' + | | + '-------' + +Required properties: +- compatible: Should be "axentia,tse850-envelope-detector" +- io-channels: Channel node of the dac to be used for comparator input. +- io-channel-names: Should be "dac". +- interrupt specification for one client interrupt, + see ../../interrupt-controller/interrupts.txt for details. +- interrupt-names: Should be "comp". + +Example: + + &i2c { + dpot: mcp4651-104@28 { + compatible = "microchip,mcp4651-104"; + reg = <0x28>; + #io-channel-cells = <1>; + }; + }; + + dac: dac { + compatible = "dpot-dac"; + vref-supply = <®_3v3>; + io-channels = <&dpot 0>; + io-channel-names = "dpot"; + #io-channel-cells = <1>; + }; + + envelope-detector { + compatible = "axentia,tse850-envelope-detector"; + io-channels = <&dac 0>; + io-channel-names = "dac"; + + interrupt-parent = <&gpio>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "comp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/fsl,imx25-gcq.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/fsl,imx25-gcq.txt new file mode 100644 index 0000000000000000000000000000000000000000..eebdcec3dab5c86a8d54e4db75e440a137f9de5e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/fsl,imx25-gcq.txt @@ -0,0 +1,57 @@ +Freescale i.MX25 ADC GCQ device + +This is a generic conversion queue device that can convert any of the +analog inputs using the ADC unit of the i.MX25. + +Required properties: + - compatible: Should be "fsl,imx25-gcq". + - reg: Should be the register range of the module. + - interrupts: Should be the interrupt number of the module. + Typically this is <1>. + - #address-cells: Should be <1> (setting for the subnodes) + - #size-cells: Should be <0> (setting for the subnodes) + +Optional properties: + - vref-ext-supply: The regulator supplying the ADC reference voltage. + Required when at least one subnode uses the this reference. + - vref-xp-supply: The regulator supplying the ADC reference voltage on pin XP. + Required when at least one subnode uses this reference. + - vref-yp-supply: The regulator supplying the ADC reference voltage on pin YP. + Required when at least one subnode uses this reference. + +Sub-nodes: +Optionally you can define subnodes which define the reference voltage +for the analog inputs. + +Required properties for subnodes: + - reg: Should be the number of the analog input. + 0: xp + 1: yp + 2: xn + 3: yn + 4: wiper + 5: inaux0 + 6: inaux1 + 7: inaux2 +Optional properties for subnodes: + - fsl,adc-refp: specifies the positive reference input as defined in + + - fsl,adc-refn: specifies the negative reference input as defined in + + +Example: + + adc: adc@50030800 { + compatible = "fsl,imx25-gcq"; + reg = <0x50030800 0x60>; + interrupt-parent = <&tscadc>; + interrupts = <1>; + #address-cells = <1>; + #size-cells = <0>; + + inaux@5 { + reg = <5>; + fsl,adc-refp = ; + fsl,adc-refn = ; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/hi8435.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/hi8435.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b0348c5e516645904df0a834aee26f6a9c050b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/hi8435.txt @@ -0,0 +1,21 @@ +Holt Integrated Circuits HI-8435 threshold detector bindings + +Required properties: + - compatible: should be "holt,hi8435" + - reg: spi chip select number for the device + +Recommended properties: + - spi-max-frequency: definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: + - gpios: GPIO used for controlling the reset pin + +Example: +sensor@0 { + compatible = "holt,hi8435"; + reg = <0>; + gpios = <&gpio6 1 0>; + + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/imx7d-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/imx7d-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c184b9406693f68b28ecb3e4fcfda32470c92ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/imx7d-adc.txt @@ -0,0 +1,22 @@ +Freescale imx7d ADC bindings + +The devicetree bindings are for the ADC driver written for +imx7d SoC. + +Required properties: +- compatible: Should be "fsl,imx7d-adc" +- reg: Offset and length of the register set for the ADC device +- interrupts: The interrupt number for the ADC device +- clocks: The root clock of the ADC controller +- clock-names: Must contain "adc", matching entry in the clocks property +- vref-supply: The regulator supply ADC reference voltage + +Example: +adc1: adc@30610000 { + compatible = "fsl,imx7d-adc"; + reg = <0x30610000 0x10000>; + interrupts = ; + clocks = <&clks IMX7D_ADC_ROOT_CLK>; + clock-names = "adc"; + vref-supply = <®_vcc_3v3_mcu>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/lpc1850-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/lpc1850-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ada5abd45fa05401cb9611d456a095583c07e53 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/lpc1850-adc.txt @@ -0,0 +1,20 @@ +NXP LPC1850 ADC bindings + +Required properties: +- compatible: Should be "nxp,lpc1850-adc" +- reg: Offset and length of the register set for the ADC device +- interrupts: The interrupt number for the ADC device +- clocks: The root clock of the ADC controller +- vref-supply: The regulator supply ADC reference voltage +- resets: phandle to reset controller and line specifier + +Example: + +adc0: adc@400e3000 { + compatible = "nxp,lpc1850-adc"; + reg = <0x400e3000 0x1000>; + interrupts = <17>; + clocks = <&ccu1 CLK_APB3_ADC0>; + vref-supply = <®_vdda>; + resets = <&rgu 40>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ltc2497.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ltc2497.txt new file mode 100644 index 0000000000000000000000000000000000000000..a237ed99c0d8d5041a4105b80a8d2523e37bc4b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ltc2497.txt @@ -0,0 +1,13 @@ +* Linear Technology / Analog Devices LTC2497 ADC + +Required properties: + - compatible: Must be "lltc,ltc2497" + - reg: Must contain the ADC I2C address + - vref-supply: The regulator supply for ADC reference voltage + +Example: + ltc2497: adc@76 { + compatible = "lltc,ltc2497"; + reg = <0x76>; + vref-supply = <<c2497_reg>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1027-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1027-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e680c61dfb84ac58018ed3ed8b9254e2b119e132 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1027-adc.txt @@ -0,0 +1,20 @@ +* Maxim 1027/1029/1031 Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "maxim,max1027" or "maxim,max1029" or "maxim,max1031" + - reg: SPI chip select number for the device + - interrupts: IRQ line for the ADC + see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Recommended properties: +- spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "maxim,max1027"; + reg = <0>; + interrupt-parent = <&gpio5>; + interrupts = <15 IRQ_TYPE_EDGE_RISING>; + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/max11100.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max11100.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7f7177b8aca01d69cada63c57e72dbf972904aa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max11100.txt @@ -0,0 +1,18 @@ +* Maxim max11100 Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "maxim,max11100" + - reg: the adc unit address + - vref-supply: phandle to the regulator that provides reference voltage + +Optional properties: + - spi-max-frequency: SPI maximum frequency + +Example: + +max11100: adc@0 { + compatible = "maxim,max11100"; + reg = <0>; + vref-supply = <&adc0_vref>; + spi-max-frequency = <240000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1118.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1118.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf33d0b15a6d714024512b6d2f9e881f1ea9f6b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1118.txt @@ -0,0 +1,21 @@ +* MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs + +Required properties: + - compatible: Should be one of + * "maxim,max1117" + * "maxim,max1118" + * "maxim,max1119" + - reg: spi chip select number for the device + - (max1118 only) vref-supply: The regulator supply for ADC reference voltage + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "maxim,max1118"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1363.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1363.txt new file mode 100644 index 0000000000000000000000000000000000000000..94a9011dd8608ff91344b2e19c18eb4c390ad58d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max1363.txt @@ -0,0 +1,63 @@ +* Maxim 1x3x/136x/116xx Analog to Digital Converter (ADC) + +The node for this driver must be a child node of a I2C controller, hence +all mandatory properties for your controller must be specified. See directory: + + Documentation/devicetree/bindings/i2c + +for more details. + +Required properties: + - compatible: Should be one of + "maxim,max1361" + "maxim,max1362" + "maxim,max1363" + "maxim,max1364" + "maxim,max1036" + "maxim,max1037" + "maxim,max1038" + "maxim,max1039" + "maxim,max1136" + "maxim,max1137" + "maxim,max1138" + "maxim,max1139" + "maxim,max1236" + "maxim,max1237" + "maxim,max1238" + "maxim,max1239" + "maxim,max11600" + "maxim,max11601" + "maxim,max11602" + "maxim,max11603" + "maxim,max11604" + "maxim,max11605" + "maxim,max11606" + "maxim,max11607" + "maxim,max11608" + "maxim,max11609" + "maxim,max11610" + "maxim,max11611" + "maxim,max11612" + "maxim,max11613" + "maxim,max11614" + "maxim,max11615" + "maxim,max11616" + "maxim,max11617" + "maxim,max11644" + "maxim,max11645" + "maxim,max11646" + "maxim,max11647" + - reg: Should contain the ADC I2C address + +Optional properties: + - vcc-supply: phandle to the regulator that provides power to the ADC. + - vref-supply: phandle to the regulator for ADC reference voltage. + - interrupts: IRQ line for the ADC. If not used the driver will use + polling. + +Example: +adc: max11644@36 { + compatible = "maxim,max11644"; + reg = <0x36>; + vref-supply = <&adc_vref>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/max9611.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max9611.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab4f43145ae578f37f030bbdeb4080a138762a0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/max9611.txt @@ -0,0 +1,27 @@ +* Maxim max9611/max9612 current sense amplifier with 12-bits ADC interface + +Maxim max9611/max9612 is an high-side current sense amplifier with integrated +12-bits ADC communicating over I2c bus. +The device node for this driver shall be a child of a I2c controller. + +Required properties + - compatible: Should be "maxim,max9611" or "maxim,max9612" + - reg: The 7-bits long I2c address of the device + - shunt-resistor-micro-ohms: Value, in micro Ohms, of the current sense shunt + resistor + +Example: + +&i2c4 { + csa: adc@7c { + compatible = "maxim,max9611"; + reg = <0x7c>; + + shunt-resistor-micro-ohms = <5000>; + }; +}; + +This device node describes a current sense amplifier sitting on I2c4 bus +with address 0x7c (read address is 0xf9, write address is 0xf8). +A sense resistor of 0,005 Ohm is installed between RS+ and RS- current-sensing +inputs. diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/mcp320x.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/mcp320x.txt new file mode 100644 index 0000000000000000000000000000000000000000..56373d643f768abfac1380db28e8daa72a6bb071 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/mcp320x.txt @@ -0,0 +1,57 @@ +* Microchip Analog to Digital Converter (ADC) + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "mcp3001" (DEPRECATED) + "mcp3002" (DEPRECATED) + "mcp3004" (DEPRECATED) + "mcp3008" (DEPRECATED) + "mcp3201" (DEPRECATED) + "mcp3202" (DEPRECATED) + "mcp3204" (DEPRECATED) + "mcp3208" (DEPRECATED) + "mcp3301" (DEPRECATED) + + "microchip,mcp3001" + "microchip,mcp3002" + "microchip,mcp3004" + "microchip,mcp3008" + "microchip,mcp3201" + "microchip,mcp3202" + "microchip,mcp3204" + "microchip,mcp3208" + "microchip,mcp3301" + "microchip,mcp3550-50" + "microchip,mcp3550-60" + "microchip,mcp3551" + "microchip,mcp3553" + + NOTE: The use of the compatibles with no vendor prefix + is deprecated and only listed because old DT use them. + + - spi-cpha, spi-cpol (boolean): + Either SPI mode (0,0) or (1,1) must be used, so specify + none or both of spi-cpha, spi-cpol. The MCP3550/1/3 + is more efficient in mode (1,1) as only 3 instead of + 4 bytes need to be read from the ADC, but not all SPI + masters support it. + + - vref-supply: Phandle to the external reference voltage supply. + +Examples: +spi_controller { + mcp3x0x@0 { + compatible = "microchip,mcp3002"; + reg = <0>; + spi-max-frequency = <1000000>; + vref-supply = <&vref_reg>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/mcp3422.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/mcp3422.txt new file mode 100644 index 0000000000000000000000000000000000000000..82bcce07255d4792baee3038b0a2dfadbff7b3c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/mcp3422.txt @@ -0,0 +1,19 @@ +* Microchip mcp3421/2/3/4/6/7/8 chip family (ADC) + +Required properties: + - compatible: Should be + "microchip,mcp3421" or + "microchip,mcp3422" or + "microchip,mcp3423" or + "microchip,mcp3424" or + "microchip,mcp3425" or + "microchip,mcp3426" or + "microchip,mcp3427" or + "microchip,mcp3428" + - reg: I2C address for the device + +Example: +adc@0 { + compatible = "microchip,mcp3424"; + reg = <0x68>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/mt6577_auxadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/mt6577_auxadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0df9befdaecca610aafeac98cdae4daf6bb9453a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/mt6577_auxadc.txt @@ -0,0 +1,31 @@ +* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx) +=============== + +The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found +in some Mediatek SoCs which among other things measures the temperatures +in the SoC. It can be used directly with register accesses, but it is also +used by thermal controller which reads the temperatures from the AUXADC +directly via its own bus interface. See +Documentation/devicetree/bindings/thermal/mediatek-thermal.txt +for the Thermal Controller which holds a phandle to the AUXADC. + +Required properties: + - compatible: Should be one of: + - "mediatek,mt2701-auxadc": For MT2701 family of SoCs + - "mediatek,mt2712-auxadc": For MT2712 family of SoCs + - "mediatek,mt7622-auxadc": For MT7622 family of SoCs + - "mediatek,mt8173-auxadc": For MT8173 family of SoCs + - reg: Address range of the AUXADC unit. + - clocks: Should contain a clock specifier for each entry in clock-names + - clock-names: Should contain "main". + - #io-channel-cells: Should be 1, see ../iio-bindings.txt + +Example: + +auxadc: adc@11001000 { + compatible = "mediatek,mt2701-auxadc"; + reg = <0 0x11001000 0 0x1000>; + clocks = <&pericfg CLK_PERI_AUXADC>; + clock-names = "main"; + #io-channel-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/nuvoton-nau7802.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/nuvoton-nau7802.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9582e6fe350035226c5d8366fdccf85cf49a0b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/nuvoton-nau7802.txt @@ -0,0 +1,18 @@ +* Nuvoton NAU7802 Analog to Digital Converter (ADC) + +Required properties: + - compatible: Should be "nuvoton,nau7802" + - reg: Should contain the ADC I2C address + +Optional properties: + - nuvoton,vldo: Internal reference voltage in millivolts to be + configured valid values are between 2400 mV and 4500 mV. + - interrupts: IRQ line for the ADC. If not used the driver will use + polling. + +Example: +adc2: nau7802@2a { + compatible = "nuvoton,nau7802"; + reg = <0x2a>; + nuvoton,vldo = <3000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/palmas-gpadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/palmas-gpadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4bb9a86065d13a26484b3be287e2afd25aaa5a61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/palmas-gpadc.txt @@ -0,0 +1,48 @@ +* Palmas general purpose ADC IP block devicetree bindings + +Channels list: + 0 battery type + 1 battery temp NTC (optional current source) + 2 GP + 3 temp (with ext. diode, optional current source) + 4 GP + 5 GP + 6 VBAT_SENSE + 7 VCC_SENSE + 8 Backup Battery voltage + 9 external charger (VCHG) + 10 VBUS + 11 DC-DC current probe (how does this work?) + 12 internal die temp + 13 internal die temp + 14 USB ID pin voltage + 15 test network + +Required properties: +- compatible : Must be "ti,palmas-gpadc". +- #io-channel-cells: Should be set to <1>. + +Optional sub-nodes: +ti,channel0-current-microamp: Channel 0 current in uA. + Values are rounded to derive 0uA, 5uA, 15uA, 20uA. +ti,channel3-current-microamp: Channel 3 current in uA. + Values are rounded to derive 0uA, 10uA, 400uA, 800uA. +ti,enable-extended-delay: Enable extended delay. + +Example: + +pmic { + compatible = "ti,twl6035-pmic", "ti,palmas-pmic"; + ... + gpadc { + compatible = "ti,palmas-gpadc"; + interrupts = <18 0 + 16 0 + 17 0>; + #io-channel-cells = <1>; + ti,channel0-current-microamp = <5>; + ti,channel3-current-microamp = <10>; + }; + }; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,pm8xxx-xoadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,pm8xxx-xoadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ae06127789e30654792851c79b51fe3f53863e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,pm8xxx-xoadc.txt @@ -0,0 +1,157 @@ +Qualcomm's PM8xxx voltage XOADC + +The Qualcomm PM8xxx PMICs contain a HK/XO ADC (Housekeeping/Crystal +oscillator ADC) encompassing PM8018, PM8038, PM8058 and PM8921. + +Required properties: + +- compatible: should be one of: + "qcom,pm8018-adc" + "qcom,pm8038-adc" + "qcom,pm8058-adc" + "qcom,pm8921-adc" + +- reg: should contain the ADC base address in the PMIC, typically + 0x197. + +- xoadc-ref-supply: should reference a regulator that can supply + a reference voltage on demand. The reference voltage may vary + with PMIC variant but is typically something like 2.2 or 1.8V. + +The following required properties are standard for IO channels, see +iio-bindings.txt for more details, but notice that this particular +ADC has a special addressing scheme that require two cells for +identifying each ADC channel: + +- #address-cells: should be set to <2>, the first cell is the + prescaler (on PM8058) or premux (on PM8921) with two valid bits + so legal values are 0x00, 0x01 or 0x02. The second cell + is the main analog mux setting (0x00..0x0f). The combination + of prescaler/premux and analog mux uniquely addresses a hardware + channel on all systems. + +- #size-cells: should be set to <0> + +- #io-channel-cells: should be set to <2>, again the cells are + precaler or premux followed by the analog muxing line. + +- interrupts: should refer to the parent PMIC interrupt controller + and reference the proper ADC interrupt. + +Required subnodes: + +The ADC channels are configured as subnodes of the ADC. + +Since some of them are used for calibrating the ADC, these nodes are +compulsory: + +adc-channel@c { + reg = <0x00 0x0c>; +}; + +adc-channel@d { + reg = <0x00 0x0d>; +}; + +adc-channel@f { + reg = <0x00 0x0f>; +}; + +These three nodes are used for absolute and ratiometric calibration +and only need to have these reg values: they are by hardware definition +1:1 ratio converters that sample 625, 1250 and 0 milliV and create +an interpolation calibration for all other ADCs. + +Optional subnodes: any channels other than channels [0x00 0x0c], +[0x00 0x0d] and [0x00 0x0f] are optional. + +Required channel node properties: + +- reg: should contain the hardware channel number in the range + 0 .. 0xff (8 bits). + +Optional channel node properties: + +- qcom,decimation: + Value type: + Definition: This parameter is used to decrease the ADC sampling rate. + Quicker measurements can be made by reducing the decimation ratio. + Valid values are 512, 1024, 2048, 4096. + If the property is not found, a default value of 512 will be used. + +- qcom,ratiometric: + Value type: + Definition: Channel calibration type. If this property is specified + VADC will use a special voltage references for channel + calibration. The available references are specified in the + as a u32 value setting (see below) and it is compulsory + to also specify this reference if ratiometric calibration + is selected. + + If the property is not found, the channel will be + calibrated with the 0.625V and 1.25V reference channels, also + known as an absolute calibration. + The reference voltage pairs when using ratiometric calibration: + 0 = XO_IN/XOADC_GND + 1 = PMIC_IN/XOADC_GND + 2 = PMIC_IN/BMS_CSP + 3 (invalid) + 4 = XOADC_GND/XOADC_GND + 5 = XOADC_VREF/XOADC_GND + +Example: + +xoadc: xoadc@197 { + compatible = "qcom,pm8058-adc"; + reg = <0x197>; + interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; + #address-cells = <2>; + #size-cells = <0>; + #io-channel-cells = <2>; + + vcoin: adc-channel@0 { + reg = <0x00 0x00>; + }; + vbat: adc-channel@1 { + reg = <0x00 0x01>; + }; + dcin: adc-channel@2 { + reg = <0x00 0x02>; + }; + ichg: adc-channel@3 { + reg = <0x00 0x03>; + }; + vph_pwr: adc-channel@4 { + reg = <0x00 0x04>; + }; + usb_vbus: adc-channel@a { + reg = <0x00 0x0a>; + }; + die_temp: adc-channel@b { + reg = <0x00 0x0b>; + }; + ref_625mv: adc-channel@c { + reg = <0x00 0x0c>; + }; + ref_1250mv: adc-channel@d { + reg = <0x00 0x0d>; + }; + ref_325mv: adc-channel@e { + reg = <0x00 0x0e>; + }; + ref_muxoff: adc-channel@f { + reg = <0x00 0x0f>; + }; +}; + +/* IIO client node */ +iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&xoadc 0x00 0x01>, /* Battery */ + <&xoadc 0x00 0x02>, /* DC in (charger) */ + <&xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&xoadc 0x00 0x0b>, /* Die temperature */ + <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-adc5.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-adc5.txt new file mode 100644 index 0000000000000000000000000000000000000000..045c9a079bf97302df9da646589dc350a7446acf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-adc5.txt @@ -0,0 +1,183 @@ +Qualcomm Technologies Inc. SPMI PMIC5 voltage and current ADC + +SPMI PMIC5 voltage ADC (ADC) provides interface to clients to read +voltage. The ADC is a 15-bit sigma-delta ADC. + +ADC node: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,spmi-adc5" for PMIC5 ADC devices. + Should contain "qcom,spmi-adc7" for PMIC7 ADC devices. + Should contain "qcom,spmi-adc-rev2" for PMIC refresh ADC devices. + Should contain "qcom,spmi-adc5-lite" for PMIC5 ADC-lite devices. + +- reg: + Usage: required for VADC base address + Value type: + Definition: VADC base address and length in the SPMI PMIC register map. + ADC_CAL base address and length in SPMI PMIC register map. + ADC_CAL base is optional and is dependent on USB_IN_V channel + read sequence for the PMIC. + +- reg-names + Usage: required + Value type: + Definition: Names associated with base addresses. should be + "adc5-usr-base", "adc5-cal-base". + +- #address-cells: + Usage: required + Value type: + Definition: Must be one. Child node 'reg' property should define ADC + channel number. + +- #size-cells: + Usage: required + Value type: + Definition: Must be zero. + +- #io-channel-cells: + Usage: required + Value type: + Definition: Must be one. For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- interrupts: + Usage: optional + Value type: + Definition: End of conversion interrupt. + +- qcom,pmic-revid: + Usage: optional + Value type: + Definition: phandle pointing to the revision peripheral node. Use it to query the + PMIC type and revision. + +Channel node properties: + +- reg: + Usage: required + Value type: + Definition: ADC channel number. + See include/dt-bindings/iio/qcom,spmi-vadc.h + +- label: + Usage: required + Value type: + Definition: ADC datasheet channel name. + For thermistor inputs connected to generic AMUX or GPIO inputs + these can vary across platform for the same pins. Hence select + the datasheet name for this channel. + +- qcom,pre-scaling: + Usage: required + Value type: + Definition: Used for scaling the channel input signal before the signal is + fed to VADC. The configuration for this node is to know the + pre-determined ratio and use it for post scaling. Select one from + the following options. + <1 1>, <1 3>, <1 4>, <1 6>, <1 20>, <1 8>, <10 81>, <1 10> + If property is not found default value depending on chip will be used. + +- qcom,decimation: + Usage: optional + Value type: + Definition: This parameter is used to decrease ADC sampling rate. + Quicker measurements can be made by reducing decimation ratio. + For PMIC5 ADC, combined two step decimation values are 250, 420 and 840. + If property is not found, default value of 840 will be used. + For PMIC7 ADC, combined two step decimation values are 85, 340 and 1360. + If property is not found, default value of 1360 will be used. + For PMIC refresh ADC, supported decimation values are 256, 512, 1024. + If property is not found, default value of 1024 will be used. + +- qcom,ratiometric: + Usage: optional + Value type: + Definition: Channel calibration type. If this property is specified + VADC will use the VDD reference (1.875V) and GND for channel + calibration. If property is not found, channel will be + calibrated with 0V and 1.25V reference channels, also + known as absolute calibration. + +- qcom,hw-settle-time: + Usage: optional + Value type: + Definition: Time in microseconds between AMUX getting configured and the ADC starting + conversion. + For PMIC5, delay = 15us for value 0, + 100us * (value) for values 0 < value < 11, and + 2ms * (value - 10) otherwise. + Valid values are: 15, 100, 200, 300, 400, 500, 600, 700, 800, + 900 us and 1, 2, 4, 6, 8, 10 ms + If property is not found, channel will use 15us. + For PMIC7, delay = 15us for value 0, + 100us * (value) for values < 8, 1ms for value 8 and + 2ms * (value - 8) otherwise. + Valid values are: 15, 100, 200, 300, 400, 500, 600, 700, 1000, + 2000, 4000, 8000, 16000, 32000, 64000, 128000 us. + If property is not found, channel will use 15us. + For PMIC rev2, delay = 100us * (value) for values 0 < value < 11, and + 2ms * (value - 10) otherwise. + Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800, + 900 us and 1, 2, 4, 6, 8, 10 ms + If property is not found, channel will use 0 us. + +- qcom,avg-samples: + Usage: optional + Value type: + Definition: Number of samples to be used for measurement. + Averaging provides the option to obtain a single measurement + from the ADC that is an average of multiple samples. The value + selected is 2^(value). + Valid values are: 1, 2, 4, 8, 16 + If property is not found, 1 sample will be used. + +- qcom,lut-index: + Usage: optional + Value type: + Definition: Lookup table index (only for bat_therm channels). + A bat_therm channel (for 30k, 100k or 400k pull-up resistance) + requires a voltage-temperature look-up table which depends on the target. + The LUT to be used for a channel is selected from a table of LUTs + for that particular channel. + If property is not found, a default LUT is used for that channel, + corresponding to index 0. + +- qcom,scale-fn-type: + Usage: optional + Value type: + Definition: The index of the VADC scale function used to convert raw ADC + code to physical scaled units for the channel. + See include/dt-bindings/iio/qcom,spmi-vadc.h + +Example: + + /* VADC node */ + pmic_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,decimation = <840>; + qcom,hw-settle-time = <0>; + qcom,avg-samples = <1>; + qcom,pre-scaling = <1 3>; + }; + }; + + /* IIO client node */ + usb { + io-channels = <&pmic_vadc ADC_VPH_PWR>; + io-channel-names = "vadc"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-iadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-iadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e36d6e2f7b6b613c0805dc8c7038f798930ac6f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-iadc.txt @@ -0,0 +1,46 @@ +Qualcomm's SPMI PMIC current ADC + +QPNP PMIC current ADC (IADC) provides interface to clients to read current. +A 16 bit ADC is used for current measurements. IADC can measure the current +through an external resistor (channel 1) or internal (built-in) resistor +(channel 0). When using an external resistor it is to be described by +qcom,external-resistor-micro-ohms property. + +IADC node: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,spmi-iadc". + +- reg: + Usage: required + Value type: + Definition: IADC base address and length in the SPMI PMIC register map + +- interrupts: + Usage: optional + Value type: + Definition: End of ADC conversion. + +- qcom,external-resistor-micro-ohms: + Usage: optional + Value type: + Definition: Sense resister value in micro Ohm. + If not defined value of 10000 micro Ohms will be used. + +Example: + /* IADC node */ + pmic_iadc: iadc@3600 { + compatible = "qcom,spmi-iadc"; + reg = <0x3600 0x100>; + interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; + qcom,external-resistor-micro-ohms = <10000>; + #io-channel-cells = <1>; + }; + + /* IIO client node */ + bat { + io-channels = <&pmic_iadc 0>; + io-channel-names = "iadc"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-vadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-vadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0fb46137f9369c5c5e94080356e326e450551c06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom,spmi-vadc.txt @@ -0,0 +1,129 @@ +Qualcomm's SPMI PMIC voltage ADC + +SPMI PMIC voltage ADC (VADC) provides interface to clients to read +voltage. The VADC is a 15-bit sigma-delta ADC. + +VADC node: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,spmi-vadc". + +- reg: + Usage: required + Value type: + Definition: VADC base address and length in the SPMI PMIC register map. + +- #address-cells: + Usage: required + Value type: + Definition: Must be one. Child node 'reg' property should define ADC + channel number. + +- #size-cells: + Usage: required + Value type: + Definition: Must be zero. + +- #io-channel-cells: + Usage: required + Value type: + Definition: Must be one. For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- interrupts: + Usage: optional + Value type: + Definition: End of conversion interrupt. + +Channel node properties: + +- reg: + Usage: required + Value type: + Definition: ADC channel number. + See include/dt-bindings/iio/qcom,spmi-vadc.h + +- qcom,decimation: + Usage: optional + Value type: + Definition: This parameter is used to decrease ADC sampling rate. + Quicker measurements can be made by reducing decimation ratio. + Valid values are 512, 1024, 2048, 4096. + If property is not found, default value of 512 will be used. + +- qcom,pre-scaling: + Usage: optional + Value type: + Definition: Used for scaling the channel input signal before the signal is + fed to VADC. The configuration for this node is to know the + pre-determined ratio and use it for post scaling. Select one from + the following options. + <1 1>, <1 3>, <1 4>, <1 6>, <1 20>, <1 8>, <10 81>, <1 10> + If property is not found default value depending on chip will be used. + +- qcom,ratiometric: + Usage: optional + Value type: + Definition: Channel calibration type. If this property is specified + VADC will use the VDD reference (1.8V) and GND for channel + calibration. If property is not found, channel will be + calibrated with 0.625V and 1.25V reference channels, also + known as absolute calibration. + +- qcom,hw-settle-time: + Usage: optional + Value type: + Definition: Time between AMUX getting configured and the ADC starting + conversion. Delay = 100us * (value) for value < 11, and + 2ms * (value - 10) otherwise. + Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800, + 900 us and 1, 2, 4, 6, 8, 10 ms + If property is not found, channel will use 0us. + +- qcom,avg-samples: + Usage: optional + Value type: + Definition: Number of samples to be used for measurement. + Averaging provides the option to obtain a single measurement + from the ADC that is an average of multiple samples. The value + selected is 2^(value). + Valid values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 + If property is not found, 1 sample will be used. + +NOTE: + +Following channels, also known as reference point channels, are used for +result calibration and their channel configuration nodes should be defined: +VADC_REF_625MV and/or VADC_SPARE1(based on PMIC version) VADC_REF_1250MV, +VADC_GND_REF and VADC_VDD_VADC. + +Example: + + /* VADC node */ + pmic_vadc: vadc@3100 { + compatible = "qcom,spmi-vadc"; + reg = <0x3100 0x100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + usb_id_nopull { + reg = ; + qcom,decimation = <512>; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,avg-samples = <1>; + qcom,pre-scaling = <1 3>; + }; + }; + + /* IIO client node */ + usb { + io-channels = <&pmic_vadc VADC_LR_MUX10_USB_ID>; + io-channel-names = "vadc"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom-rradc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom-rradc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1ab49edfe30ce59f92652fd04e7b45079b224135 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom-rradc.txt @@ -0,0 +1,63 @@ +Qualcomm Technologies Inc., PMIC Round Robin ADC (RRADC) + +PMIC RRADC provides an interface to the clients to read +the voltage, current and temperature for supported channels +such as battery ID, battery thermistor, die temperature, +charger temperature, USB_IN and DC_IN voltage and current. + +Main node properties: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,rradc". + +- reg: + Usage: required + Value type: + Definition: RRADC base address and length in the PMIC register map. + +- #address-cells: + Usage: required + Value type: + Definition: Must be one. Child node 'channel' property should define ADC + channel number. For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- #size-cells: + Usage: required + Value type: + Definition: Must be zero. For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- #io-channel-cells: + Usage: required + Value type: + Definition: Must be one. For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +IIO client nodes need to specify the RRADC channel number while requesting ADC reads. +The channel list supported by the RRADC driver is available in the enum rradc_channel_id +located at at drivers/iio/adc/qcom-rradc.c. Clients can use this index from the enum +as the channel number while requesting ADC reads. + +Optional property: +- qcom,pmic-revid : Phandle pointing to the revision peripheral node. Use it to query the + PMIC fabrication ID for applying the appropriate temperature + compensation parameters. +Example: + + /* RRADC node */ + pmic_rradc: rradc@4500 { + compatible = "qcom,rradc"; + reg = <0x4500 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + }; + + /* IIO client node */ + charger { + io-channels = <&pmic_rradc 0>; + io-channel-names = "rradc_batt_id"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom-tadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom-tadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6880d304367d2884c92916f7e119ad7bbe7700c0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/qcom-tadc.txt @@ -0,0 +1,141 @@ +Qualcomm Technologies, Inc. TADC Specific Bindings + +TADC (Telemetry ADC) is a 10 bit resolution ADC which has 8 channels: battery +temperature, skin temperature, die temperature, battery current, battery +voltage, input current, input voltage, and OTG current. + +======================= +Required Node Structure +======================= + +A TADC must be described in two levels of devices nodes. + +======================= +First Level Node - TADC +======================= + +- reg + Usage: required + Value type: + Definition: Address and size of the TADC register block. + +TADC specific properties: +- compatible + Usage: required + Value type: + Definition: Must be "qcom,tadc". + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +============================================= +Second Level Nodes - TADC Thermistor Channels +============================================= + +- reg + Usage: required + Value type: + Definition: The 0 based channel number. + +TADC thermistor channel specific properties: +- qcom,rbias + Usage: required + Value type: + Definition: The bias resistor value. + +- qcom,therm-at-25degc + Usage: required + Value type: + Definition: The thermistor resistance at 25 DegC. + +- qcom,beta-coefficient + Usage: required + Value type: + Definition: The beta coefficeent or B-parameter of the thermistor. + +=============================================== +Second Level Nodes - TADC Scale/Offset Channels +=============================================== + +- reg + Usage: required + Value type: + Definition: The 0 based channel number. + +TADC scale/offset channel specific properties: +- qcom,scale + Usage: required + Value type: + Definition: The RAW scaling factor. + +- qcom,offset + Usage: optional + Value type: + Definition: The offset after scaling. + +======= +Example +======= + +smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_temp@0 { + reg = <0>; + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp@1 { + reg = <1>; + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp@2 { + reg = <2>; + qcom,scale = <(-1032)>; + qcom,offset = <344125>; + }; + + batt_i@3 { + reg = <3>; + qcom,channel = <3>; + qcom,scale = <20000000>; + }; + + batt_v@4 { + reg = <4>; + qcom,scale = <5000000>; + }; + + input_i@5 { + reg = <5>; + qcom,scale = <14285714>; + }; + + input_v@6 { + reg = <6>; + qcom,scale = <25000000>; + }; + + otg_i@7 { + reg = <7>; + qcom,scale = <5714286>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/renesas,gyroadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/renesas,gyroadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..df5b9f2ad8d8182057e94dfc627e66014f390651 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/renesas,gyroadc.txt @@ -0,0 +1,98 @@ +* Renesas R-Car GyroADC device driver + +The GyroADC block is a reduced SPI block with up to 8 chipselect lines, +which supports the SPI protocol of a selected few SPI ADCs. The SPI ADCs +are sampled by the GyroADC block in a round-robin fashion and the result +presented in the GyroADC registers. + +Required properties: +- compatible: Should be "", "renesas,rcar-gyroadc". + The should be one of: + renesas,r8a7791-gyroadc - for the GyroADC block present + in r8a7791 SoC + renesas,r8a7792-gyroadc - for the GyroADC with interrupt + block present in r8a7792 SoC +- reg: Address and length of the register set for the device +- clocks: References to all the clocks specified in the clock-names + property as specified in + Documentation/devicetree/bindings/clock/clock-bindings.txt. +- clock-names: Shall contain "fck". The "fck" is the GyroADC block clock. +- power-domains: Must contain a reference to the PM domain, if available. +- #address-cells: Should be <1> (setting for the subnodes) for all ADCs + except for "fujitsu,mb88101a". Should be <0> (setting for + only subnode) for "fujitsu,mb88101a". +- #size-cells: Should be <0> (setting for the subnodes) + +Sub-nodes: +You must define subnode(s) which select the connected ADC type and reference +voltage for the GyroADC channels. + +Required properties for subnodes: +- compatible: Should be either of: + "fujitsu,mb88101a" + - Fujitsu MB88101A compatible mode, + 12bit sampling, up to 4 channels can be sampled in + round-robin fashion. One Fujitsu chip supplies four + GyroADC channels with data as it contains four ADCs + on the chip and thus for 4-channel operation, single + MB88101A is required. The Cx chipselect lines of the + MB88101A connect directly to two CHS lines of the + GyroADC, no demuxer is required. The data out line + of each MB88101A connects to a shared input pin of + the GyroADC. + "ti,adcs7476" or "ti,adc121" or "adi,ad7476" + - TI ADCS7476 / TI ADC121 / ADI AD7476 compatible mode, + 15bit sampling, up to 8 channels can be sampled in + round-robin fashion. One TI/ADI chip supplies single + ADC channel with data, thus for 8-channel operation, + 8 chips are required. A 3:8 chipselect demuxer is + required to connect the nCS line of the TI/ADI chips + to the GyroADC, while MISO line of each TI/ADI ADC + connects to a shared input pin of the GyroADC. + "maxim,max1162" or "maxim,max11100" + - Maxim MAX1162 / Maxim MAX11100 compatible mode, + 16bit sampling, up to 8 channels can be sampled in + round-robin fashion. One Maxim chip supplies single + ADC channel with data, thus for 8-channel operation, + 8 chips are required. A 3:8 chipselect demuxer is + required to connect the nCS line of the MAX chips + to the GyroADC, while MISO line of each Maxim ADC + connects to a shared input pin of the GyroADC. +- reg: Should be the number of the analog input. Should be present + for all ADCs except "fujitsu,mb88101a". +- vref-supply: Reference to the channel reference voltage regulator. + +Example: + vref_max1162: regulator-vref-max1162 { + compatible = "regulator-fixed"; + + regulator-name = "MAX1162 Vref"; + regulator-min-microvolt = <4096000>; + regulator-max-microvolt = <4096000>; + }; + + adc@e6e54000 { + compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc"; + reg = <0 0xe6e54000 0 64>; + clocks = <&mstp9_clks R8A7791_CLK_GYROADC>; + clock-names = "fck"; + power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; + + pinctrl-0 = <&adc_pins>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + reg = <0>; + compatible = "maxim,max1162"; + vref-supply = <&vref_max1162>; + }; + + adc@1 { + reg = <1>; + compatible = "maxim,max1162"; + vref-supply = <&vref_max1162>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/rockchip-saradc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/rockchip-saradc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2c50b59873d8b2ec69a4d7084ce8e8addb87a31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/rockchip-saradc.txt @@ -0,0 +1,37 @@ +Rockchip Successive Approximation Register (SAR) A/D Converter bindings + +Required properties: +- compatible: should be "rockchip,-saradc" or "rockchip,rk3066-tsadc" + - "rockchip,saradc": for rk3188, rk3288 + - "rockchip,rk3066-tsadc": for rk3036 + - "rockchip,rk3328-saradc", "rockchip,rk3399-saradc": for rk3328 + - "rockchip,rk3399-saradc": for rk3399 + - "rockchip,rv1108-saradc", "rockchip,rk3399-saradc": for rv1108 + +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Shall be "saradc" for the converter-clock, and "apb_pclk" for + the peripheral clock. +- vref-supply: The regulator supply ADC reference voltage. +- #io-channel-cells: Should be 1, see ../iio-bindings.txt + +Optional properties: +- resets: Must contain an entry for each entry in reset-names if need support + this option. See ../reset/reset.txt for details. +- reset-names: Must include the name "saradc-apb". + +Example: + saradc: saradc@2006c000 { + compatible = "rockchip,saradc"; + reg = <0x2006c000 0x100>; + interrupts = ; + clocks = <&cru SCLK_SARADC>, <&cru PCLK_SARADC>; + clock-names = "saradc", "apb_pclk"; + resets = <&cru SRST_SARADC>; + reset-names = "saradc-apb"; + #io-channel-cells = <1>; + vref-supply = <&vcc18>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/samsung,exynos-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/samsung,exynos-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c49db7f8ad2597128b644316fe60936e994198c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/samsung,exynos-adc.txt @@ -0,0 +1,103 @@ +Samsung Exynos Analog to Digital Converter bindings + +The devicetree bindings are for the new ADC driver written for +Exynos4 and upward SoCs from Samsung. + +New driver handles the following +1. Supports ADC IF found on EXYNOS4412/EXYNOS5250 + and future SoCs from Samsung +2. Add ADC driver under iio/adc framework +3. Also adds the Documentation for device tree bindings + +Required properties: +- compatible: Must be "samsung,exynos-adc-v1" + for exynos4412/5250 and s5pv210 controllers. + Must be "samsung,exynos-adc-v2" for + future controllers. + Must be "samsung,exynos3250-adc" for + controllers compatible with ADC of Exynos3250. + Must be "samsung,exynos7-adc" for + the ADC in Exynos7 and compatibles + Must be "samsung,s3c2410-adc" for + the ADC in s3c2410 and compatibles + Must be "samsung,s3c2416-adc" for + the ADC in s3c2416 and compatibles + Must be "samsung,s3c2440-adc" for + the ADC in s3c2440 and compatibles + Must be "samsung,s3c2443-adc" for + the ADC in s3c2443 and compatibles + Must be "samsung,s3c6410-adc" for + the ADC in s3c6410 and compatibles +- reg: List of ADC register address range + - The base address and range of ADC register + - The base address and range of ADC_PHY register (every + SoC except for s3c24xx/s3c64xx ADC) +- interrupts: Contains the interrupt information for the timer. The + format is being dependent on which interrupt controller + the Samsung device uses. +- #io-channel-cells = <1>; As ADC has multiple outputs +- clocks From common clock bindings: handles to clocks specified + in "clock-names" property, in the same order. +- clock-names From common clock bindings: list of clock input names + used by ADC block: + - "adc" : ADC bus clock + - "sclk" : ADC special clock (only for Exynos3250 and + compatible ADC block) +- vdd-supply VDD input supply. + +- samsung,syscon-phandle Contains the PMU system controller node + (To access the ADC_PHY register on Exynos5250/5420/5800/3250) +Optional properties: +- has-touchscreen: If present, indicates that a touchscreen is + connected an usable. + +Note: child nodes can be added for auto probing from device tree. + +Example: adding device info in dtsi file + +adc: adc@12d10000 { + compatible = "samsung,exynos-adc-v1"; + reg = <0x12D10000 0x100>; + interrupts = <0 106 0>; + #io-channel-cells = <1>; + io-channel-ranges; + + clocks = <&clock 303>; + clock-names = "adc"; + + vdd-supply = <&buck5_reg>; + samsung,syscon-phandle = <&pmu_system_controller>; +}; + +Example: adding device info in dtsi file for Exynos3250 with additional sclk + +adc: adc@126c0000 { + compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2; + reg = <0x126C0000 0x100>; + interrupts = <0 137 0>; + #io-channel-cells = <1>; + io-channel-ranges; + + clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>; + clock-names = "adc", "sclk"; + + vdd-supply = <&buck5_reg>; + samsung,syscon-phandle = <&pmu_system_controller>; +}; + +Example: Adding child nodes in dts file + +adc@12d10000 { + + /* NTC thermistor is a hwmon device */ + ncp15wb473@0 { + compatible = "murata,ncp15wb473"; + pullup-uv = <1800000>; + pullup-ohm = <47000>; + pulldown-ohm = <0>; + io-channels = <&adc 4>; + }; +}; + +Note: Does not apply to ADC driver under arch/arm/plat-samsung/ +Note: The child node can be added under the adc node or separately. diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/sigma-delta-modulator.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/sigma-delta-modulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..59b92cd325527c66eca92e69ff3c27d2fb4f0dcc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/sigma-delta-modulator.txt @@ -0,0 +1,13 @@ +Device-Tree bindings for sigma delta modulator + +Required properties: +- compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use + as a generic SD modulator if modulator not specified in compatible list. +- #io-channel-cells = <0>: See the IIO bindings section "IIO consumers". + +Example node: + + ads1202: adc { + compatible = "sd-modulator"; + #io-channel-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/sprd,sc27xx-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/sprd,sc27xx-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8aad960de50bebdecd95ebbc899a4f9844804184 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/sprd,sc27xx-adc.txt @@ -0,0 +1,36 @@ +Spreadtrum SC27XX series PMICs ADC binding + +Required properties: +- compatible: Should be one of the following. + "sprd,sc2720-adc" + "sprd,sc2721-adc" + "sprd,sc2723-adc" + "sprd,sc2730-adc" + "sprd,sc2731-adc" +- reg: The address offset of ADC controller. +- interrupt-parent: The interrupt controller. +- interrupts: The interrupt number for the ADC device. +- #io-channel-cells: Number of cells in an IIO specifier. +- hwlocks: Reference to a phandle of a hwlock provider node. + +Example: + + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + pmic_adc: adc@480 { + compatible = "sprd,sc2731-adc"; + reg = <0x480>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + #io-channel-cells = <1>; + hwlocks = <&hwlock 4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/st,stm32-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/st,stm32-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8346bcb04ad79efb85230021f1cd66fc3803010a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/st,stm32-adc.txt @@ -0,0 +1,140 @@ +STMicroelectronics STM32 ADC device driver + +STM32 ADC is a successive approximation analog-to-digital converter. +It has several multiplexed input channels. Conversions can be performed +in single, continuous, scan or discontinuous mode. Result of the ADC is +stored in a left-aligned or right-aligned 32-bit data register. +Conversions can be launched in software or using hardware triggers. + +The analog watchdog feature allows the application to detect if the input +voltage goes beyond the user-defined, higher or lower thresholds. + +Each STM32 ADC block can have up to 3 ADC instances. + +Each instance supports two contexts to manage conversions, each one has its +own configurable sequence and trigger: +- regular conversion can be done in sequence, running in background +- injected conversions have higher priority, and so have the ability to + interrupt regular conversion sequence (either triggered in SW or HW). + Regular sequence is resumed, in case it has been interrupted. + +Contents of a stm32 adc root node: +----------------------------------- +Required properties: +- compatible: Should be one of: + "st,stm32f4-adc-core" + "st,stm32h7-adc-core" + "st,stm32mp1-adc-core" +- reg: Offset and length of the ADC block register set. +- interrupts: One or more interrupts for ADC block. Some parts like stm32f4 + and stm32h7 share a common ADC interrupt line. stm32mp1 has two separate + interrupt lines, one for each ADC within ADC block. +- clocks: Core can use up to two clocks, depending on part used: + - "adc" clock: for the analog circuitry, common to all ADCs. + It's required on stm32f4. + It's optional on stm32h7. + - "bus" clock: for registers access, common to all ADCs. + It's not present on stm32f4. + It's required on stm32h7. +- clock-names: Must be "adc" and/or "bus" depending on part used. +- interrupt-controller: Identifies the controller node as interrupt-parent +- vref-supply: Phandle to the vref input analog reference voltage. +- #interrupt-cells = <1>; +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- A pinctrl state named "default" for each ADC channel may be defined to set + inX ADC pins in mode of operation for analog input on external pin. + +Contents of a stm32 adc child node: +----------------------------------- +An ADC block node should contain at least one subnode, representing an +ADC instance available on the machine. + +Required properties: +- compatible: Should be one of: + "st,stm32f4-adc" + "st,stm32h7-adc" + "st,stm32mp1-adc" +- reg: Offset of ADC instance in ADC block (e.g. may be 0x0, 0x100, 0x200). +- clocks: Input clock private to this ADC instance. It's required only on + stm32f4, that has per instance clock input for registers access. +- interrupts: IRQ Line for the ADC (e.g. may be 0 for adc@0, 1 for adc@100 or + 2 for adc@200). +- st,adc-channels: List of single-ended channels muxed for this ADC. + It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered + from 0 to 15 or 19 (resp. for in0..in15 or in0..in19). +- st,adc-diff-channels: List of differential channels muxed for this ADC. + Depending on part used, some channels can be configured as differential + instead of single-ended (e.g. stm32h7). List here positive and negative + inputs pairs as , ,... vinp and vinn are numbered + from 0 to 19 on stm32h7) + Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is required. + Both properties can be used together. Some channels can be used as + single-ended and some other ones as differential (mixed). But channels + can't be configured both as single-ended and differential (invalid). +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in + Documentation/devicetree/bindings/iio/iio-bindings.txt + +Optional properties: +- dmas: Phandle to dma channel for this ADC instance. + See ../../dma/dma.txt for details. +- dma-names: Must be "rx" when dmas property is being used. +- assigned-resolution-bits: Resolution (bits) to use for conversions. Must + match device available resolutions: + * can be 6, 8, 10 or 12 on stm32f4 + * can be 8, 10, 12, 14 or 16 on stm32h7 + Default is maximum resolution if unset. +- st,min-sample-time-nsecs: Minimum sampling time in nanoseconds. + Depending on hardware (board) e.g. high/low analog input source impedance, + fine tune of ADC sampling time may be recommended. + This can be either one value or an array that matches 'st,adc-channels' list, + to set sample time resp. for all channels, or independently for each channel. + +Example: + adc: adc@40012000 { + compatible = "st,stm32f4-adc-core"; + reg = <0x40012000 0x400>; + interrupts = <18>; + clocks = <&rcc 0 168>; + clock-names = "adc"; + vref-supply = <®_vref>; + interrupt-controller; + pinctrl-names = "default"; + pinctrl-0 = <&adc3_in8_pin>; + + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "st,stm32f4-adc"; + #io-channel-cells = <1>; + reg = <0x0>; + clocks = <&rcc 0 168>; + interrupt-parent = <&adc>; + interrupts = <0>; + st,adc-channels = <8>; + dmas = <&dma2 0 0 0x400 0x0>; + dma-names = "rx"; + assigned-resolution-bits = <8>; + }; + ... + other adc child nodes follow... + }; + +Example to setup: +- channel 1 as single-ended +- channels 2 & 3 as differential (with resp. 6 & 7 negative inputs) + + adc: adc@40022000 { + compatible = "st,stm32h7-adc-core"; + ... + adc1: adc@0 { + compatible = "st,stm32h7-adc"; + ... + st,adc-channels = <1>; + st,adc-diff-channels = <2 6>, <3 7>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/st,stm32-dfsdm-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/st,stm32-dfsdm-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..75ba25d062e1833fd28a777a8ad2991c9b1d9efa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/st,stm32-dfsdm-adc.txt @@ -0,0 +1,135 @@ +STMicroelectronics STM32 DFSDM ADC device driver + + +STM32 DFSDM ADC is a sigma delta analog-to-digital converter dedicated to +interface external sigma delta modulators to STM32 micro controllers. +It is mainly targeted for: +- Sigma delta modulators (motor control, metering...) +- PDM microphones (audio digital microphone) + +It features up to 8 serial digital interfaces (SPI or Manchester) and +up to 4 filters on stm32h7 or 6 filters on stm32mp1. + +Each child node match with a filter instance. + +Contents of a STM32 DFSDM root node: +------------------------------------ +Required properties: +- compatible: Should be one of: + "st,stm32h7-dfsdm" + "st,stm32mp1-dfsdm" +- reg: Offset and length of the DFSDM block register set. +- clocks: IP and serial interfaces clocking. Should be set according + to rcc clock ID and "clock-names". +- clock-names: Input clock name "dfsdm" must be defined, + "audio" is optional. If defined CLKOUT is based on the audio + clock, else "dfsdm" is used. +- #interrupt-cells = <1>; +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- spi-max-frequency: Requested only for SPI master mode. + SPI clock OUT frequency (Hz). This clock must be set according + to "clock" property. Frequency must be a multiple of the rcc + clock frequency. If not, SPI CLKOUT frequency will not be + accurate. +- pinctrl-names: Set to "default". +- pinctrl-0: List of phandles pointing to pin configuration + nodes to set pins in mode of operation for dfsdm + on external pin. + +Contents of a STM32 DFSDM child nodes: +-------------------------------------- + +Required properties: +- compatible: Must be: + "st,stm32-dfsdm-adc" for sigma delta ADCs + "st,stm32-dfsdm-dmic" for audio digital microphone. +- reg: Specifies the DFSDM filter instance used. + Valid values are from 0 to 3 on stm32h7, 0 to 5 on stm32mp1. +- interrupts: IRQ lines connected to each DFSDM filter instance. +- st,adc-channels: List of single-ended channels muxed for this ADC. + valid values: + "st,stm32h7-dfsdm" compatibility: 0 to 7. +- st,adc-channel-names: List of single-ended channel names. +- st,filter-order: SinC filter order from 0 to 5. + 0: FastSinC + [1-5]: order 1 to 5. + For audio purpose it is recommended to use order 3 to 5. +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers". + +Required properties for "st,stm32-dfsdm-adc" compatibility: +- io-channels: From common IIO binding. Used to pipe external sigma delta + modulator or internal ADC output to DFSDM channel. + This is not required for "st,stm32-dfsdm-pdm" compatibility as + PDM microphone is binded in Audio DT node. + +Required properties for "st,stm32-dfsdm-pdm" compatibility: +- #sound-dai-cells: Must be set to 0. +- dma: DMA controller phandle and DMA request line associated to the + filter instance (specified by the field "reg") +- dma-names: Must be "rx" + +Optional properties: +- st,adc-channel-types: Single-ended channel input type. + - "SPI_R": SPI with data on rising edge (default) + - "SPI_F": SPI with data on falling edge + - "MANCH_R": manchester codec, rising edge = logic 0, falling edge = logic 1 + - "MANCH_F": manchester codec, rising edge = logic 1, falling edge = logic 0 +- st,adc-channel-clk-src: Conversion clock source. + - "CLKIN": external SPI clock (CLKIN x) + - "CLKOUT": internal SPI clock (CLKOUT) (default) + - "CLKOUT_F": internal SPI clock divided by 2 (falling edge). + - "CLKOUT_R": internal SPI clock divided by 2 (rising edge). + +- st,adc-alt-channel: Must be defined if two sigma delta modulator are + connected on same SPI input. + If not set, channel n is connected to SPI input n. + If set, channel n is connected to SPI input n + 1. + +- st,filter0-sync: Set to 1 to synchronize with DFSDM filter instance 0. + Used for multi microphones synchronization. + +Example of a sigma delta adc connected on DFSDM SPI port 0 +and a pdm microphone connected on DFSDM SPI port 1: + + ads1202: simple_sd_adc@0 { + compatible = "ads1202"; + #io-channel-cells = <1>; + }; + + dfsdm: dfsdm@40017000 { + compatible = "st,stm32h7-dfsdm"; + reg = <0x40017000 0x400>; + clocks = <&rcc DFSDM1_CK>; + clock-names = "dfsdm"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dfsdm_adc0: filter@0 { + compatible = "st,stm32-dfsdm-adc"; + #io-channel-cells = <1>; + reg = <0>; + interrupts = <110>; + st,adc-channels = <0>; + st,adc-channel-names = "sd_adc0"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; + io-channels = <&ads1202 0>; + st,filter-order = <3>; + }; + dfsdm_pdm1: filter@1 { + compatible = "st,stm32-dfsdm-dmic"; + reg = <1>; + interrupts = <111>; + dmas = <&dmamux1 102 0x400 0x00>; + dma-names = "rx"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic1"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <5>; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc0832.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc0832.txt new file mode 100644 index 0000000000000000000000000000000000000000..d91130587d016ab8e88cb193e8e787188a251435 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc0832.txt @@ -0,0 +1,19 @@ +* Texas Instruments' ADC0831/ADC0832/ADC0832/ADC0838 + +Required properties: + - compatible: Should be one of + * "ti,adc0831" + * "ti,adc0832" + * "ti,adc0834" + * "ti,adc0838" + - reg: spi chip select number for the device + - vref-supply: The regulator supply for ADC reference voltage + - spi-max-frequency: Max SPI frequency to use (< 400000) + +Example: +adc@0 { + compatible = "ti,adc0832"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <200000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc084s021.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc084s021.txt new file mode 100644 index 0000000000000000000000000000000000000000..4259e50620bcd5dc5d97fcea7218250886c74d04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc084s021.txt @@ -0,0 +1,19 @@ +* Texas Instruments' ADC084S021 + +Required properties: + - compatible : Must be "ti,adc084s021" + - reg : SPI chip select number for the device + - vref-supply : The regulator supply for ADC reference voltage + - spi-cpol : Per spi-bus bindings + - spi-cpha : Per spi-bus bindings + - spi-max-frequency : Per spi-bus bindings + +Example: +adc@0 { + compatible = "ti,adc084s021"; + reg = <0>; + vref-supply = <&adc_vref>; + spi-cpol; + spi-cpha; + spi-max-frequency = <16000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc108s102.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc108s102.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbbbb4a9f58f33b8ce8587c22f6d41be3903bdc2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc108s102.txt @@ -0,0 +1,18 @@ +* Texas Instruments' ADC108S102 and ADC128S102 ADC chip + +Required properties: + - compatible: Should be "ti,adc108s102" + - reg: spi chip select number for the device + - vref-supply: The regulator supply for ADC reference voltage + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "ti,adc108s102"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc12138.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc12138.txt new file mode 100644 index 0000000000000000000000000000000000000000..049a1d36f013028eeb8a7b1ba0e6ffc8cc0ae406 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc12138.txt @@ -0,0 +1,37 @@ +* Texas Instruments' ADC12130/ADC12132/ADC12138 + +Required properties: + - compatible: Should be one of + * "ti,adc12130" + * "ti,adc12132" + * "ti,adc12138" + - reg: SPI chip select number for the device + - interrupts: Should contain interrupt for EOC (end of conversion) + - clocks: phandle to conversion clock input + - spi-max-frequency: Definision as per + Documentation/devicetree/bindings/spi/spi-bus.txt + - vref-p-supply: The regulator supply for positive analog voltage reference + +Optional properties: + - vref-n-supply: The regulator supply for negative analog voltage reference + (Note that this must not go below GND or exceed vref-p) + If not specified, this is assumed to be analog ground. + - ti,acquisition-time: The number of conversion clock periods for the S/H's + acquisition time. Should be one of 6, 10, 18, 34. If not specified, + default value of 10 is used. + For high source impedances, this value can be increased to 18 or 34. + For less ADC accuracy and/or slower CCLK frequencies this value may be + decreased to 6. See section 6.0 INPUT SOURCE RESISTANCE in the + datasheet for details. + +Example: +adc@0 { + compatible = "ti,adc12138"; + reg = <0>; + interrupts = <28 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio1>; + clocks = <&cclk>; + vref-p-supply = <&ldo4_reg>; + spi-max-frequency = <5000000>; + ti,acquisition-time = <6>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc128s052.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc128s052.txt new file mode 100644 index 0000000000000000000000000000000000000000..daa2b2c294285f4e717d25d473690582a3bc0329 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc128s052.txt @@ -0,0 +1,18 @@ +* Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip + +Required properties: + - compatible: Should be "ti,adc128s052", "ti,adc122s021" or "ti,adc124s021" + - reg: spi chip select number for the device + - vref-supply: The regulator supply for ADC reference voltage + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "ti,adc128s052"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc161s626.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc161s626.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d25011f0c99beb664506d0a97583cf635f45cef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-adc161s626.txt @@ -0,0 +1,18 @@ +* Texas Instruments ADC141S626 and ADC161S626 chips + +Required properties: + - compatible: Should be "ti,adc141s626" or "ti,adc161s626" + - reg: spi chip select number for the device + - vdda-supply: supply voltage to VDDA pin + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "ti,adc161s626"; + vdda-supply = <&vdda_fixed>; + reg = <0>; + spi-max-frequency = <4300000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-ads7950.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-ads7950.txt new file mode 100644 index 0000000000000000000000000000000000000000..e77a6f7e100163d2981d4711277bbd3edbc11638 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-ads7950.txt @@ -0,0 +1,23 @@ +* Texas Instruments ADS7950 family of A/DC chips + +Required properties: + - compatible: Must be one of "ti,ads7950", "ti,ads7951", "ti,ads7952", + "ti,ads7953", "ti,ads7954", "ti,ads7955", "ti,ads7956", "ti,ads7957", + "ti,ads7958", "ti,ads7959", "ti,ads7960", or "ti,ads7961" + - reg: SPI chip select number for the device + - #io-channel-cells: Must be 1 as per ../iio-bindings.txt + - vref-supply: phandle to a regulator node that supplies the 2.5V or 5V + reference voltage + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: +adc@0 { + compatible = "ti,ads7957"; + reg = <0>; + #io-channel-cells = <1>; + vref-supply = <&refin_supply>; + spi-max-frequency = <10000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-ads8688.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-ads8688.txt new file mode 100644 index 0000000000000000000000000000000000000000..a02337d7efa447f46265dbd4a460e8c760ea45f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/ti-ads8688.txt @@ -0,0 +1,20 @@ +* Texas Instruments' ADS8684 and ADS8688 ADC chip + +Required properties: + - compatible: Should be "ti,ads8684" or "ti,ads8688" + - reg: spi chip select number for the device + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: + - vref-supply: The regulator supply for ADC reference voltage + +Example: +adc@0 { + compatible = "ti,ads8688"; + reg = <0>; + vref-supply = <&vdd_supply>; + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/twl4030-madc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/twl4030-madc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6bdd21404b57c2952ce133b2604379f0655fea67 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/twl4030-madc.txt @@ -0,0 +1,24 @@ +* TWL4030 Monitoring Analog to Digital Converter (MADC) + +The MADC subsystem in the TWL4030 consists of a 10-bit ADC +combined with a 16-input analog multiplexer. + +Required properties: + - compatible: Should contain "ti,twl4030-madc". + - interrupts: IRQ line for the MADC submodule. + - #io-channel-cells: Should be set to <1>. + +Optional properties: + - ti,system-uses-second-madc-irq: boolean, set if the second madc irq register + should be used, which is intended to be used + by Co-Processors (e.g. a modem). + +Example: + +&twl { + madc { + compatible = "ti,twl4030-madc"; + interrupts = <3>; + #io-channel-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/vf610-adc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/vf610-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1aad0514e6474be4171e854ae5265d872cc7c89c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/vf610-adc.txt @@ -0,0 +1,36 @@ +Freescale vf610 Analog to Digital Converter bindings + +The devicetree bindings are for the new ADC driver written for +vf610/i.MX6slx and upward SoCs from Freescale. + +Required properties: +- compatible: Should contain "fsl,vf610-adc" +- reg: Offset and length of the register set for the device +- interrupts: Should contain the interrupt for the device +- clocks: The clock is needed by the ADC controller, ADC clock source is ipg clock. +- clock-names: Must contain "adc", matching entry in the clocks property. +- vref-supply: The regulator supply ADC reference voltage. + +Recommended properties: +- fsl,adck-max-frequency: Maximum frequencies according to datasheets operating + requirements. Three values are required, depending on conversion mode: + - Frequency in normal mode (ADLPC=0, ADHSC=0) + - Frequency in high-speed mode (ADLPC=0, ADHSC=1) + - Frequency in low-power mode (ADLPC=1, ADHSC=0) +- min-sample-time: Minimum sampling time in nanoseconds. This value has + to be chosen according to the conversion mode and the connected analog + source resistance (R_as) and capacitance (C_as). Refer the datasheet's + operating requirements. A safe default across a wide range of R_as and + C_as as well as conversion modes is 1000ns. + +Example: +adc0: adc@4003b000 { + compatible = "fsl,vf610-adc"; + reg = <0x4003b000 0x1000>; + interrupts = <0 53 0x04>; + clocks = <&clks VF610_CLK_ADC0>; + clock-names = "adc"; + fsl,adck-max-frequency = <30000000>, <40000000>, + <20000000>; + vref-supply = <®_vcc_3v3_mcu>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/adc/xilinx-xadc.txt b/arch/arm64/boot/dts/vendor/bindings/iio/adc/xilinx-xadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0e0755cabd8af9a80b68cb5f1df379e8971841b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/adc/xilinx-xadc.txt @@ -0,0 +1,112 @@ +Xilinx XADC device driver + +This binding document describes the bindings for both of them since the +bindings are very similar. The Xilinx XADC is a ADC that can be found in the +series 7 FPGAs from Xilinx. The XADC has a DRP interface for communication. +Currently two different frontends for the DRP interface exist. One that is only +available on the ZYNQ family as a hardmacro in the SoC portion of the ZYNQ. The +other one is available on all series 7 platforms and is a softmacro with a AXI +interface. This binding document describes the bindings for both of them since +the bindings are very similar. + +Required properties: + - compatible: Should be one of + * "xlnx,zynq-xadc-1.00.a": When using the ZYNQ device + configuration interface to interface to the XADC hardmacro. + * "xlnx,axi-xadc-1.00.a": When using the axi-xadc pcore to + interface to the XADC hardmacro. + - reg: Address and length of the register set for the device + - interrupts: Interrupt for the XADC control interface. + - clocks: When using the ZYNQ this must be the ZYNQ PCAP clock, + when using the AXI-XADC pcore this must be the clock that provides the + clock to the AXI bus interface of the core. + +Optional properties: + - xlnx,external-mux: + * "none": No external multiplexer is used, this is the default + if the property is omitted. + * "single": External multiplexer mode is used with one + multiplexer. + * "dual": External multiplexer mode is used with two + multiplexers for simultaneous sampling. + - xlnx,external-mux-channel: Configures which pair of pins is used to + sample data in external mux mode. + Valid values for single external multiplexer mode are: + 0: VP/VN + 1: VAUXP[0]/VAUXN[0] + 2: VAUXP[1]/VAUXN[1] + ... + 16: VAUXP[15]/VAUXN[15] + Valid values for dual external multiplexer mode are: + 1: VAUXP[0]/VAUXN[0] - VAUXP[8]/VAUXN[8] + 2: VAUXP[1]/VAUXN[1] - VAUXP[9]/VAUXN[9] + ... + 8: VAUXP[7]/VAUXN[7] - VAUXP[15]/VAUXN[15] + + This property needs to be present if the device is configured for + external multiplexer mode (either single or dual). If the device is + not using external multiplexer mode the property is ignored. + - xnlx,channels: List of external channels that are connected to the ADC + Required properties: + * #address-cells: Should be 1. + * #size-cells: Should be 0. + + The child nodes of this node represent the external channels which are + connected to the ADC. If the property is no present no external + channels will be assumed to be connected. + + Each child node represents one channel and has the following + properties: + Required properties: + * reg: Pair of pins the channel is connected to. + 0: VP/VN + 1: VAUXP[0]/VAUXN[0] + 2: VAUXP[1]/VAUXN[1] + ... + 16: VAUXP[15]/VAUXN[15] + Note each channel number should only be used at most + once. + Optional properties: + * xlnx,bipolar: If set the channel is used in bipolar + mode. + + +Examples: + xadc@f8007100 { + compatible = "xlnx,zynq-xadc-1.00.a"; + reg = <0xf8007100 0x20>; + interrupts = <0 7 4>; + interrupt-parent = <&gic>; + clocks = <&pcap_clk>; + + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + }; + channel@1 { + reg = <1>; + }; + channel@8 { + reg = <8>; + }; + }; + }; + + xadc@43200000 { + compatible = "xlnx,axi-xadc-1.00.a"; + reg = <0x43200000 0x1000>; + interrupts = <0 53 4>; + interrupt-parent = <&gic>; + clocks = <&fpga1_clk>; + + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + xlnx,bipolar; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/afe/current-sense-amplifier.txt b/arch/arm64/boot/dts/vendor/bindings/iio/afe/current-sense-amplifier.txt new file mode 100644 index 0000000000000000000000000000000000000000..821b61b8c542ff925e192b175efc5be0516de962 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/afe/current-sense-amplifier.txt @@ -0,0 +1,26 @@ +Current Sense Amplifier +======================= + +When an io-channel measures the output voltage from a current sense +amplifier, the interesting measurement is almost always the current +through the sense resistor, not the voltage output. This binding +describes such a current sense circuit. + +Required properties: +- compatible : "current-sense-amplifier" +- io-channels : Channel node of a voltage io-channel. +- sense-resistor-micro-ohms : The sense resistance in microohms. + +Optional properties: +- sense-gain-mult: Amplifier gain multiplier. The default is <1>. +- sense-gain-div: Amplifier gain divider. The default is <1>. + +Example: + +sysi { + compatible = "current-sense-amplifier"; + io-channels = <&tiadc 0>; + + sense-resistor-micro-ohms = <20000>; + sense-gain-mul = <50>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/afe/current-sense-shunt.txt b/arch/arm64/boot/dts/vendor/bindings/iio/afe/current-sense-shunt.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f67108a07b6327bfa0f1de99b8781715a0c2734 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/afe/current-sense-shunt.txt @@ -0,0 +1,41 @@ +Current Sense Shunt +=================== + +When an io-channel measures the voltage over a current sense shunt, +the interesting measurement is almost always the current through the +shunt, not the voltage over it. This binding describes such a current +sense circuit. + +Required properties: +- compatible : "current-sense-shunt" +- io-channels : Channel node of a voltage io-channel. +- shunt-resistor-micro-ohms : The shunt resistance in microohms. + +Example: +The system current is measured by measuring the voltage over a +3.3 ohms shunt resistor. + +sysi { + compatible = "current-sense-shunt"; + io-channels = <&tiadc 0>; + + /* Divide the voltage by 3300000/1000000 (or 3.3) for the current. */ + shunt-resistor-micro-ohms = <3300000>; +}; + +&i2c { + tiadc: adc@48 { + compatible = "ti,ads1015"; + reg = <0x48>; + #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { /* IN0,IN1 differential */ + reg = <0>; + ti,gain = <1>; + ti,datarate = <4>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/afe/voltage-divider.txt b/arch/arm64/boot/dts/vendor/bindings/iio/afe/voltage-divider.txt new file mode 100644 index 0000000000000000000000000000000000000000..b452a8406107625e9cc8bf6be1eb56ba80bd7240 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/afe/voltage-divider.txt @@ -0,0 +1,53 @@ +Voltage divider +=============== + +When an io-channel measures the midpoint of a voltage divider, the +interesting voltage is often the voltage over the full resistance +of the divider. This binding describes the voltage divider in such +a curcuit. + + Vin ----. + | + .-----. + | R | + '-----' + | + +---- Vout + | + .-----. + | Rout| + '-----' + | + GND + +Required properties: +- compatible : "voltage-divider" +- io-channels : Channel node of a voltage io-channel measuring Vout. +- output-ohms : Resistance Rout over which the output voltage is measured. + See full-ohms. +- full-ohms : Resistance R + Rout for the full divider. The io-channel + is scaled by the Rout / (R + Rout) quotient. + +Example: +The system voltage is circa 12V, but divided down with a 22/222 +voltage divider (R = 200 Ohms, Rout = 22 Ohms) and fed to an ADC. + +sysv { + compatible = "voltage-divider"; + io-channels = <&maxadc 1>; + + /* Scale the system voltage by 22/222 to fit the ADC range. */ + output-ohms = <22>; + full-ohms = <222>; /* 200 + 22 */ +}; + +&spi { + maxadc: adc@0 { + compatible = "maxim,max1027"; + reg = <0>; + #io-channel-cells = <1>; + interrupt-parent = <&gpio5>; + interrupts = <15 IRQ_TYPE_EDGE_RISING>; + spi-max-frequency = <1000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,ec-sm.txt b/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,ec-sm.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4320595b851755977a8c8b2f4b6637aa20efb18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,ec-sm.txt @@ -0,0 +1,21 @@ +* Atlas Scientific EC-SM OEM sensor + +http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf + +Required properties: + + - compatible: must be "atlas,ec-sm" + - reg: the I2C address of the sensor + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + +Example: + +atlas@64 { + compatible = "atlas,ec-sm"; + reg = <0x64>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,orp-sm.txt b/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,orp-sm.txt new file mode 100644 index 0000000000000000000000000000000000000000..af1f5a9aa4daa70bb3200680bf372a9f796c7d96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,orp-sm.txt @@ -0,0 +1,21 @@ +* Atlas Scientific ORP-SM OEM sensor + +https://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf + +Required properties: + + - compatible: must be "atlas,orp-sm" + - reg: the I2C address of the sensor + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + +Example: + +atlas@66 { + compatible = "atlas,orp-sm"; + reg = <0x66>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,ph-sm.txt b/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,ph-sm.txt new file mode 100644 index 0000000000000000000000000000000000000000..79d90f0603271bb2be167c59002f7d3218f6b68a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/chemical/atlas,ph-sm.txt @@ -0,0 +1,21 @@ +* Atlas Scientific pH-SM OEM sensor + +http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf + +Required properties: + + - compatible: must be "atlas,ph-sm" + - reg: the I2C address of the sensor + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + +Example: + +atlas@65 { + compatible = "atlas,ph-sm"; + reg = <0x65>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/counter/stm32-lptimer-cnt.txt b/arch/arm64/boot/dts/vendor/bindings/iio/counter/stm32-lptimer-cnt.txt new file mode 100644 index 0000000000000000000000000000000000000000..a04aa5c041034369b340d0a7ebbf28bf28da883c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/counter/stm32-lptimer-cnt.txt @@ -0,0 +1,27 @@ +STMicroelectronics STM32 Low-Power Timer quadrature encoder and counter + +STM32 Low-Power Timer provides several counter modes. It can be used as: +- quadrature encoder to detect angular position and direction of rotary + elements, from IN1 and IN2 input signals. +- simple counter from IN1 input signal. + +Must be a sub-node of an STM32 Low-Power Timer device tree node. +See ../mfd/stm32-lptimer.txt for details about the parent node. + +Required properties: +- compatible: Must be "st,stm32-lptimer-counter". +- pinctrl-names: Set to "default". +- pinctrl-0: List of phandles pointing to pin configuration nodes, + to set IN1/IN2 pins in mode of operation for Low-Power + Timer input on external pin. + +Example: + timer@40002400 { + compatible = "st,stm32-lptimer"; + ... + counter { + compatible = "st,stm32-lptimer-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&lptim1_in_pins>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5592r.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5592r.txt new file mode 100644 index 0000000000000000000000000000000000000000..989f96f31c66f45285a5147d80f53e6f91048be2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5592r.txt @@ -0,0 +1,155 @@ +Analog Devices AD5592R/AD5593R DAC/ADC device driver + +Required properties for the AD5592R: + - compatible: Must be "adi,ad5592r" + - reg: SPI chip select number for the device + - spi-max-frequency: Max SPI frequency to use (< 30000000) + - spi-cpol: The AD5592R requires inverse clock polarity (CPOL) mode + +Required properties for the AD5593R: + - compatible: Must be "adi,ad5593r" + - reg: I2C address of the device + +Required properties for all supported chips: + - #address-cells: Should be 1. + - #size-cells: Should be 0. + - channel nodes: + Each child node represents one channel and has the following + Required properties: + * reg: Pin on which this channel is connected to. + * adi,mode: Mode or function of this channel. + Macros specifying the valid values + can be found in . + + The following values are currently supported: + * CH_MODE_UNUSED (the pin is unused) + * CH_MODE_ADC (the pin is ADC input) + * CH_MODE_DAC (the pin is DAC output) + * CH_MODE_DAC_AND_ADC (the pin is DAC output + but can be monitored by an ADC, since + there is no disadvantage this + this should be considered as the + preferred DAC mode) + * CH_MODE_GPIO (the pin is registered + with GPIOLIB) + Optional properties: + * adi,off-state: State of this channel when unused or the + device gets removed. Macros specifying the + valid values can be found in + . + + * CH_OFFSTATE_PULLDOWN (the pin is pulled down) + * CH_OFFSTATE_OUT_LOW (the pin is output low) + * CH_OFFSTATE_OUT_HIGH (the pin is output high) + * CH_OFFSTATE_OUT_TRISTATE (the pin is + tristated output) + + +Optional properties: + - vref-supply: Phandle to the external reference voltage supply. This should + only be set if there is an external reference voltage connected to the VREF + pin. If the property is not set the internal 2.5V reference is used. + - reset-gpios : GPIO spec for the RESET pin. If specified, it will be + asserted during driver probe. + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second + cell specifies GPIO flags, as defined in . + +AD5592R Example: + + #include + + vref: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "vref-ad559x"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + ad5592r@0 { + #size-cells = <0>; + #address-cells = <1>; + #gpio-cells = <2>; + compatible = "adi,ad5592r"; + reg = <0>; + + spi-max-frequency = <1000000>; + spi-cpol; + + vref-supply = <&vref>; /* optional */ + reset-gpios = <&gpio0 86 0>; /* optional */ + gpio-controller; + + channel@0 { + reg = <0>; + adi,mode = ; + }; + channel@1 { + reg = <1>; + adi,mode = ; + }; + channel@2 { + reg = <2>; + adi,mode = ; + }; + channel@3 { + reg = <3>; + adi,mode = ; + adi,off-state = ; + }; + channel@4 { + reg = <4>; + adi,mode = ; + adi,off-state = ; + }; + channel@5 { + reg = <5>; + adi,mode = ; + adi,off-state = ; + }; + channel@6 { + reg = <6>; + adi,mode = ; + adi,off-state = ; + }; + channel@7 { + reg = <7>; + adi,mode = ; + adi,off-state = ; + }; + }; + +AD5593R Example: + + #include + + ad5593r@10 { + #size-cells = <0>; + #address-cells = <1>; + #gpio-cells = <2>; + compatible = "adi,ad5593r"; + reg = <0x10>; + gpio-controller; + + channel@0 { + reg = <0>; + adi,mode = ; + adi,off-state = ; + }; + channel@1 { + reg = <1>; + adi,mode = ; + adi,off-state = ; + }; + channel@2 { + reg = <2>; + adi,mode = ; + adi,off-state = ; + }; + channel@6 { + reg = <6>; + adi,mode = ; + adi,off-state = ; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5755.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5755.txt new file mode 100644 index 0000000000000000000000000000000000000000..f0bbd7e1029bd44d7c2c989217cbfc0b144635f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5755.txt @@ -0,0 +1,124 @@ +* Analog Device AD5755 IIO Multi-Channel DAC Linux Driver + +Required properties: + - compatible: Has to contain one of the following: + adi,ad5755 + adi,ad5755-1 + adi,ad5757 + adi,ad5735 + adi,ad5737 + + - reg: spi chip select number for the device + - spi-cpha or spi-cpol: is the only modes that is supported + +Recommended properties: + - spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: +See include/dt-bindings/iio/ad5755.h + - adi,ext-dc-dc-compenstation-resistor: boolean set if the hardware have an + external resistor and thereby bypasses + the internal compensation resistor. + - adi,dc-dc-phase: + Valid values for DC DC Phase control is: + 0: All dc-to-dc converters clock on the same edge. + 1: Channel A and Channel B clock on the same edge, + Channel C and Channel D clock on opposite edges. + 2: Channel A and Channel C clock on the same edge, + Channel B and Channel D clock on opposite edges. + 3: Channel A, Channel B, Channel C, and Channel D + clock 90 degrees out of phase from each other. + - adi,dc-dc-freq-hz: + Valid values for DC DC frequency is [Hz]: + 250000 + 410000 + 650000 + - adi,dc-dc-max-microvolt: + Valid values for the maximum allowed Vboost voltage supplied by + the dc-to-dc converter is: + 23000000 + 24500000 + 27000000 + 29500000 + +Optional for every channel: + - adi,mode: + Valid values for DAC modes is: + 0: 0 V to 5 V voltage range. + 1: 0 V to 10 V voltage range. + 2: Plus minus 5 V voltage range. + 3: Plus minus 10 V voltage range. + 4: 4 mA to 20 mA current range. + 5: 0 mA to 20 mA current range. + 6: 0 mA to 24 mA current range. + - adi,ext-current-sense-resistor: boolean set if the hardware a external + current sense resistor. + - adi,enable-voltage-overrange: boolean enable voltage overrange + - adi,slew: Array of slewrate settings should contain 3 fields: + 1: Should be either 0 or 1 in order to enable or disable slewrate. + 2: Slew rate settings: + Valid values for the slew rate update frequency: + 64000 + 32000 + 16000 + 8000 + 4000 + 2000 + 1000 + 500 + 250 + 125 + 64 + 32 + 16 + 8 + 4 + 0 + 3: Slew step size: + Valid values for the step size LSBs: + 1 + 2 + 4 + 16 + 32 + 64 + 128 + 256 + +Example: +dac@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "adi,ad5755"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpha; + adi,dc-dc-phase = <0>; + adi,dc-dc-freq-hz = <410000>; + adi,dc-dc-max-microvolt = <23000000>; + channel@0 { + reg = <0>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; + channel@1 { + reg = <1>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; + channel@2 { + reg = <2>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; + channel@3 { + reg = <3>; + adi,mode = <4>; + adi,ext-current-sense-resistor; + adi,slew = <0 64000 1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5758.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5758.txt new file mode 100644 index 0000000000000000000000000000000000000000..bba01a5cab1bad1a4ce5ca43f8fbe9ddd8fe3bf6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad5758.txt @@ -0,0 +1,78 @@ +Analog Devices AD5758 DAC device driver + +Required properties for the AD5758: + - compatible: Must be "adi,ad5758" + - reg: SPI chip select number for the device + - spi-max-frequency: Max SPI frequency to use (< 50000000) + - spi-cpha: is the only mode that is supported + +Required properties: + + - adi,dc-dc-mode: Mode of operation of the dc-to-dc converter + Dynamic Power Control (DPC) + In this mode, the AD5758 circuitry senses the output + voltage and dynamically regulates the supply voltage, + VDPC+, to meet compliance requirements plus an optimized + headroom voltage for the output buffer. + + Programmable Power Control (PPC) + In this mode, the VDPC+ voltage is user-programmable to + a fixed level that needs to accommodate the maximum output + load required. + + The output of the DAC core is either converted to a + current or voltage output at the VIOUT pin. Only one mode + can be enabled at any one time. + + The following values are currently supported: + * 1: DPC current mode + * 2: DPC voltage mode + * 3: PPC current mode + + Depending on the selected output mode (voltage or current) one of the + two properties must + be present: + + - adi,range-microvolt: Voltage output range + The array of voltage output ranges must contain two fields: + * <0 5000000>: 0 V to 5 V voltage range + * <0 10000000>: 0 V to 10 V voltage range + * <(-5000000) 5000000>: ±5 V voltage range + * <(-10000000) 10000000>: ±10 V voltage range + - adi,range-microamp: Current output range + The array of current output ranges must contain two fields: + * <0 20000>: 0 mA to 20 mA current range + * <0 24000>: 0 mA to 24 mA current range + * <4 24000>: 4 mA to 20 mA current range + * <(-20000) 20000>: ±20 mA current range + * <(-24000) 24000>: ±24 mA current range + * <(-1000) 22000>: −1 mA to +22 mA current range + +Optional properties: + + - adi,dc-dc-ilim-microamp: The dc-to-dc converter current limit + The following values are currently supported [uA]: + * 150000 + * 200000 + * 250000 + * 300000 + * 350000 + * 400000 + + - adi,slew-time-us: The time it takes for the output to reach the + full scale [uS] + The supported range is between 133us up to 1023984375us + +AD5758 Example: + + dac@0 { + compatible = "adi,ad5758"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cpha; + + adi,dc-dc-mode = <2>; + adi,range-microvolt = <0 10000000>; + adi,dc-dc-ilim-microamp = <200000>; + adi,slew-time-us = <125000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad7303.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad7303.txt new file mode 100644 index 0000000000000000000000000000000000000000..914610f0556ef93215984f0a04f9ad8e49d9268c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ad7303.txt @@ -0,0 +1,23 @@ +Analog Devices AD7303 DAC device driver + +Required properties: + - compatible: Must be "adi,ad7303" + - reg: SPI chip select number for the device + - spi-max-frequency: Max SPI frequency to use (< 30000000) + - Vdd-supply: Phandle to the Vdd power supply + +Optional properties: + - REF-supply: Phandle to the external reference voltage supply. This should + only be set if there is an external reference voltage connected to the REF + pin. If the property is not set Vdd/2 is used as the reference voltage. + +Example: + + ad7303@4 { + compatible = "adi,ad7303"; + reg = <4>; + spi-max-frequency = <10000000>; + Vdd-supply = <&vdd_supply>; + adi,use-external-reference; + REF-supply = <&vref_supply>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/dpot-dac.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/dpot-dac.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdf47a01bfef6400dcc67a8bb5342fffefbd0be0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/dpot-dac.txt @@ -0,0 +1,41 @@ +Bindings for DAC emulation using a digital potentiometer + +It is assumed that the dpot is used as a voltage divider between the +current dpot wiper setting and the maximum resistance of the dpot. The +divided voltage is provided by a vref regulator. + + .------. + .-----------. | | + | vref |--' .---. + | regulator |--. | | + '-----------' | | d | + | | p | + | | o | wiper + | | t |<---------+ + | | | + | '---' dac output voltage + | | + '------+------------+ + +Required properties: +- compatible: Should be "dpot-dac" +- vref-supply: The regulator supplying the voltage divider. +- io-channels: Channel node of the dpot to be used for the voltage division. +- io-channel-names: Should be "dpot". + +Example: + + &i2c { + dpot: mcp4651-503@28 { + compatible = "microchip,mcp4651-503"; + reg = <0x28>; + #io-channel-cells = <1>; + }; + }; + + dac { + compatible = "dpot-dac"; + vref-supply = <®_3v3>; + io-channels = <&dpot 0>; + io-channel-names = "dpot"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ds4424.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ds4424.txt new file mode 100644 index 0000000000000000000000000000000000000000..eaebbf8dab40a1b031043ab60a84584c82777907 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ds4424.txt @@ -0,0 +1,20 @@ +Maxim Integrated DS4422/DS4424 7-bit Sink/Source Current DAC Device Driver + +Datasheet publicly available at: +https://datasheets.maximintegrated.com/en/ds/DS4422-DS4424.pdf + +Required properties: + - compatible: Should be one of + maxim,ds4422 + maxim,ds4424 + - reg: Should contain the DAC I2C address + +Optional properties: + - vcc-supply: Power supply is optional. If not defined, driver will ignore it. + +Example: + ds4224@10 { + compatible = "maxim,ds4424"; + reg = <0x10>; /* When A0, A1 pins are ground */ + vcc-supply = <&vcc_3v3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/lpc1850-dac.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/lpc1850-dac.txt new file mode 100644 index 0000000000000000000000000000000000000000..42db783c4e7552b4e3eab7cc34fce4ec340413aa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/lpc1850-dac.txt @@ -0,0 +1,19 @@ +NXP LPC1850 DAC bindings + +Required properties: +- compatible: Should be "nxp,lpc1850-dac" +- reg: Offset and length of the register set for the ADC device +- interrupts: The interrupt number for the ADC device +- clocks: The root clock of the ADC controller +- vref-supply: The regulator supply ADC reference voltage +- resets: phandle to reset controller and line specifier + +Example: +dac: dac@400e1000 { + compatible = "nxp,lpc1850-dac"; + reg = <0x400e1000 0x1000>; + interrupts = <0>; + clocks = <&ccu1 CLK_APB3_DAC>; + vref-supply = <®_vdda>; + resets = <&rgu 42>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ltc2632.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ltc2632.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0d5fea33031d3614676b45be596a9dc6c3e79bf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ltc2632.txt @@ -0,0 +1,37 @@ +Linear Technology LTC2632 DAC device driver + +Required properties: + - compatible: Has to contain one of the following: + lltc,ltc2632-l12 + lltc,ltc2632-l10 + lltc,ltc2632-l8 + lltc,ltc2632-h12 + lltc,ltc2632-h10 + lltc,ltc2632-h8 + +Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt +apply. In particular, "reg" and "spi-max-frequency" properties must be given. + +Optional properties: + - vref-supply: Phandle to the external reference voltage supply. This should + only be set if there is an external reference voltage connected to the VREF + pin. If the property is not set the internal reference is used. + +Example: + + vref: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "vref-ltc2632"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; + regulator-always-on; + }; + + spi_master { + dac: ltc2632@0 { + compatible = "lltc,ltc2632-l12"; + reg = <0>; /* CS0 */ + spi-max-frequency = <1000000>; + vref-supply = <&vref>; /* optional */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/max5821.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/max5821.txt new file mode 100644 index 0000000000000000000000000000000000000000..54276ce8c971a5d64e00f1459e297d71ab89a372 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/max5821.txt @@ -0,0 +1,14 @@ +Maxim max5821 DAC device driver + +Required properties: + - compatible: Must be "maxim,max5821" + - reg: Should contain the DAC I2C address + - vref-supply: Phandle to the vref power supply + +Example: + + max5821@38 { + compatible = "maxim,max5821"; + reg = <0x38>; + vref-supply = <®_max5821>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/mcp4725.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/mcp4725.txt new file mode 100644 index 0000000000000000000000000000000000000000..1bc6c093fbfed25ae593cf8162ff34617654bdba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/mcp4725.txt @@ -0,0 +1,35 @@ +Microchip mcp4725 and mcp4726 DAC device driver + +Required properties: + - compatible: Must be "microchip,mcp4725" or "microchip,mcp4726" + - reg: Should contain the DAC I2C address + - vdd-supply: Phandle to the Vdd power supply. This supply is used as a + voltage reference on mcp4725. It is used as a voltage reference on + mcp4726 if there is no vref-supply specified. + +Optional properties (valid only for mcp4726): + - vref-supply: Optional phandle to the Vref power supply. Vref pin is + used as a voltage reference when this supply is specified. + - microchip,vref-buffered: Boolean to enable buffering of the external + Vref pin. This boolean is not valid without the vref-supply. Quoting + the datasheet: This is offered in cases where the reference voltage + does not have the current capability not to drop its voltage when + connected to the internal resistor ladder circuit. + +Examples: + + /* simple mcp4725 */ + mcp4725@60 { + compatible = "microchip,mcp4725"; + reg = <0x60>; + vdd-supply = <&vdac_vdd>; + }; + + /* mcp4726 with the buffered external reference voltage */ + mcp4726@60 { + compatible = "microchip,mcp4726"; + reg = <0x60>; + vdd-supply = <&vdac_vdd>; + vref-supply = <&vdac_vref>; + microchip,vref-buffered; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/st,stm32-dac.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/st,stm32-dac.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf2925c671c68f7a357e4a0f125af6713c4956aa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/st,stm32-dac.txt @@ -0,0 +1,63 @@ +STMicroelectronics STM32 DAC + +The STM32 DAC is a 12-bit voltage output digital-to-analog converter. The DAC +may be configured in 8 or 12-bit mode. It has two output channels, each with +its own converter. +It has built-in noise and triangle waveform generator and supports external +triggers for conversions. The DAC's output buffer allows a high drive output +current. + +Contents of a stm32 dac root node: +----------------------------------- +Required properties: +- compatible: Should be one of: + "st,stm32f4-dac-core" + "st,stm32h7-dac-core" +- reg: Offset and length of the device's register set. +- clocks: Must contain an entry for pclk (which feeds the peripheral bus + interface) +- clock-names: Must be "pclk". +- vref-supply: Phandle to the vref+ input analog reference supply. +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- resets: Must contain the phandle to the reset controller. +- A pinctrl state named "default" for each DAC channel may be defined to set + DAC_OUTx pin in mode of operation for analog output on external pin. + +Contents of a stm32 dac child node: +----------------------------------- +DAC core node should contain at least one subnode, representing a +DAC instance/channel available on the machine. + +Required properties: +- compatible: Must be "st,stm32-dac". +- reg: Must be either 1 or 2, to define (single) channel in use +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in + Documentation/devicetree/bindings/iio/iio-bindings.txt + +Example: + dac: dac@40007400 { + compatible = "st,stm32h7-dac-core"; + reg = <0x40007400 0x400>; + clocks = <&clk>; + clock-names = "pclk"; + vref-supply = <®_vref>; + pinctrl-names = "default"; + pinctrl-0 = <&dac_out1 &dac_out2>; + #address-cells = <1>; + #size-cells = <0>; + + dac1: dac@1 { + compatible = "st,stm32-dac"; + #io-channels-cells = <1>; + reg = <1>; + }; + + dac2: dac@2 { + compatible = "st,stm32-dac"; + #io-channels-cells = <1>; + reg = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti,dac5571.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti,dac5571.txt new file mode 100644 index 0000000000000000000000000000000000000000..03af6b9a4d07c1434eb45e34eb1b5de19df8231c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti,dac5571.txt @@ -0,0 +1,24 @@ +* Texas Instruments DAC5571 Family + +Required properties: + - compatible: Should contain + "ti,dac5571" + "ti,dac6571" + "ti,dac7571" + "ti,dac5574" + "ti,dac6574" + "ti,dac7574" + "ti,dac5573" + "ti,dac6573" + "ti,dac7573" + - reg: Should contain the DAC I2C address + +Optional properties: + - vref-supply: The regulator supply for DAC reference voltage + +Example: +dac@0 { + compatible = "ti,dac5571"; + reg = <0x4C>; + vref-supply = <&vdd_supply>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti,dac7512.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti,dac7512.txt new file mode 100644 index 0000000000000000000000000000000000000000..1db45939dac989ab918e02a312af4dcde0a5f6a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti,dac7512.txt @@ -0,0 +1,20 @@ +TI DAC7512 DEVICETREE BINDINGS + +Required properties: + + - "compatible" Must be set to "ti,dac7512" + +Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt +apply. In particular, "reg" and "spi-max-frequency" properties must be given. + + +Example: + + spi_master { + dac7512: dac7512@0 { + compatible = "ti,dac7512"; + reg = <0>; /* CS0 */ + spi-max-frequency = <1000000>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti-dac082s085.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti-dac082s085.txt new file mode 100644 index 0000000000000000000000000000000000000000..9cb0e10df704aa58a4d62b419c1d14b6b7f1ec51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/ti-dac082s085.txt @@ -0,0 +1,34 @@ +Texas Instruments 8/10/12-bit 2/4-channel DAC driver + +Required properties: + - compatible: Must be one of: + "ti,dac082s085" + "ti,dac102s085" + "ti,dac122s085" + "ti,dac084s085" + "ti,dac104s085" + "ti,dac124s085" + - reg: Chip select number. + - spi-cpha, spi-cpol: SPI mode (0,1) or (1,0) must be used, so specify + either spi-cpha or spi-cpol (but not both). + - vref-supply: Phandle to the external reference voltage supply. + +For other required and optional properties of SPI slave nodes please refer to +../../spi/spi-bus.txt. + +Example: + vref_2v5_reg: regulator-vref { + compatible = "regulator-fixed"; + regulator-name = "2v5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + dac@0 { + compatible = "ti,dac082s085"; + reg = <0>; + spi-max-frequency = <40000000>; + spi-cpol; + vref-supply = <&vref_2v5_reg>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/dac/vf610-dac.txt b/arch/arm64/boot/dts/vendor/bindings/iio/dac/vf610-dac.txt new file mode 100644 index 0000000000000000000000000000000000000000..20c6c7ae9687b06c1a478326bfebb083186b88a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/dac/vf610-dac.txt @@ -0,0 +1,20 @@ +Freescale vf610 Digital to Analog Converter bindings + +The devicetree bindings are for the new DAC driver written for +vf610 SoCs from Freescale. + +Required properties: +- compatible: Should contain "fsl,vf610-dac" +- reg: Offset and length of the register set for the device +- interrupts: Should contain the interrupt for the device +- clocks: The clock is needed by the DAC controller +- clock-names: Must contain "dac" matching entry in the clocks property. + +Example: +dac0: dac@400cc000 { + compatible = "fsl,vf610-dac"; + reg = <0x400cc000 0x1000>; + interrupts = <55 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "dac"; + clocks = <&clks VF610_CLK_DAC0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/frequency/adf4350.txt b/arch/arm64/boot/dts/vendor/bindings/iio/frequency/adf4350.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8c181d81d2d21230902def1ae88bcb01ba4daa3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/frequency/adf4350.txt @@ -0,0 +1,86 @@ +Analog Devices ADF4350/ADF4351 device driver + +Required properties: + - compatible: Should be one of + * "adi,adf4350": When using the ADF4350 device + * "adi,adf4351": When using the ADF4351 device + - reg: SPI chip select numbert for the device + - spi-max-frequency: Max SPI frequency to use (< 20000000) + - clocks: From common clock binding. Clock is phandle to clock for + ADF435x Reference Clock (CLKIN). + +Optional properties: + - gpios: GPIO Lock detect - If set with a valid phandle and GPIO number, + pll lock state is tested upon read. + - adi,channel-spacing: Channel spacing in Hz (influences MODULUS). + - adi,power-up-frequency: If set in Hz the PLL tunes to + the desired frequency on probe. + - adi,reference-div-factor: If set the driver skips dynamic calculation + and uses this default value instead. + - adi,reference-doubler-enable: Enables reference doubler. + - adi,reference-div2-enable: Enables reference divider. + - adi,phase-detector-polarity-positive-enable: Enables positive phase + detector polarity. Default = negative. + - adi,lock-detect-precision-6ns-enable: Enables 6ns lock detect precision. + Default = 10ns. + - adi,lock-detect-function-integer-n-enable: Enables lock detect + for integer-N mode. Default = factional-N mode. + - adi,charge-pump-current: Charge pump current in mA. + Default = 2500mA. + - adi,muxout-select: On chip multiplexer output selection. + Valid values for the multiplexer output are: + 0: Three-State Output (default) + 1: DVDD + 2: DGND + 3: R-Counter output + 4: N-Divider output + 5: Analog lock detect + 6: Digital lock detect + - adi,low-spur-mode-enable: Enables low spur mode. + Default = Low noise mode. + - adi,cycle-slip-reduction-enable: Enables cycle slip reduction. + - adi,charge-cancellation-enable: Enabled charge pump + charge cancellation for integer-N modes. + - adi,anti-backlash-3ns-enable: Enables 3ns antibacklash pulse width + for integer-N modes. + - adi,band-select-clock-mode-high-enable: Enables faster band + selection logic. + - adi,12bit-clk-divider: Clock divider value used when + adi,12bit-clkdiv-mode != 0 + - adi,clk-divider-mode: + Valid values for the clkdiv mode are: + 0: Clock divider off (default) + 1: Fast lock enable + 2: Phase resync enable + - adi,aux-output-enable: Enables auxiliary RF output. + - adi,aux-output-fundamental-enable: Selects fundamental VCO output on + the auxiliary RF output. Default = Output of RF dividers. + - adi,mute-till-lock-enable: Enables Mute-Till-Lock-Detect function. + - adi,output-power: Output power selection. + Valid values for the power mode are: + 0: -4dBm (default) + 1: -1dBm + 2: +2dBm + 3: +5dBm + - adi,aux-output-power: Auxiliary output power selection. + Valid values for the power mode are: + 0: -4dBm (default) + 1: -1dBm + 2: +2dBm + 3: +5dBm + + +Example: + lo_pll0_rx_adf4351: adf4351-rx-lpc@4 { + compatible = "adi,adf4351"; + reg = <4>; + spi-max-frequency = <10000000>; + clocks = <&clk0_ad9523 9>; + clock-names = "clkin"; + adi,channel-spacing = <10000>; + adi,power-up-frequency = <2400000000>; + adi,phase-detector-polarity-positive-enable; + adi,charge-pump-current = <2500>; + adi,output-power = <3>; + adi,mute-till-lock-enable; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/gyroscope/invensense,mpu3050.txt b/arch/arm64/boot/dts/vendor/bindings/iio/gyroscope/invensense,mpu3050.txt new file mode 100644 index 0000000000000000000000000000000000000000..233fe207aded2f1df267722b59b5ce5ca05f27cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/gyroscope/invensense,mpu3050.txt @@ -0,0 +1,45 @@ +Invensense MPU-3050 Gyroscope device tree bindings + +Required properties: + - compatible : should be "invensense,mpu3050" + - reg : the I2C address of the sensor + +Optional properties: + - interrupts : interrupt mapping for the trigger interrupt from the + internal oscillator. The following IRQ modes are supported: + IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, IRQ_TYPE_LEVEL_HIGH and + IRQ_TYPE_LEVEL_LOW. The driver should detect and configure the hardware + for the desired interrupt type. + - vdd-supply : supply regulator for the main power voltage. + - vlogic-supply : supply regulator for the signal voltage. + - mount-matrix : see iio/mount-matrix.txt + +Optional subnodes: + - The MPU-3050 will pass through and forward the I2C signals from the + incoming I2C bus, alternatively drive traffic to a slave device (usually + an accelerometer) on its own initiative. Therefore is supports a subnode + i2c gate node. For details see: i2c/i2c-gate.txt + +Example: + +mpu3050@68 { + compatible = "invensense,mpu3050"; + reg = <0x68>; + interrupt-parent = <&foo>; + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&bar>; + vlogic-supply = <&baz>; + + /* External I2C interface */ + i2c-gate { + #address-cells = <1>; + #size-cells = <0>; + + fnord@18 { + compatible = "fnord"; + reg = <0x18>; + interrupt-parent = <&foo>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/health/afe4403.txt b/arch/arm64/boot/dts/vendor/bindings/iio/health/afe4403.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e412054d6d5f01905357551799f5d0309849cbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/health/afe4403.txt @@ -0,0 +1,33 @@ +Texas Instruments AFE4403 Heart rate and Pulse Oximeter + +Required properties: + - compatible : Should be "ti,afe4403". + - reg : SPI chip select address of device. + - tx-supply : Regulator supply to transmitting LEDs. + - interrupts : The interrupt line the device ADC_RDY pin is + connected to. For details refer to, + ../../interrupt-controller/interrupts.txt. + +Optional properties: + - reset-gpios : GPIO used to reset the device. + For details refer to, ../../gpio/gpio.txt. + +For other required and optional properties of SPI slave nodes +please refer to ../../spi/spi-bus.txt. + +Example: + +&spi0 { + heart_mon@0 { + compatible = "ti,afe4403"; + reg = <0>; + spi-max-frequency = <10000000>; + + tx-supply = <&vbat>; + + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_EDGE_RISING>; + + reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/health/afe4404.txt b/arch/arm64/boot/dts/vendor/bindings/iio/health/afe4404.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b52830a0d9c001391db2a0f8dc6dd4efa192ecd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/health/afe4404.txt @@ -0,0 +1,29 @@ +Texas Instruments AFE4404 Heart rate and Pulse Oximeter + +Required properties: + - compatible : Should be "ti,afe4404". + - reg : I2C address of the device. + - tx-supply : Regulator supply to transmitting LEDs. + - interrupts : The interrupt line the device ADC_RDY pin is + connected to. For details refer to, + ../interrupt-controller/interrupts.txt. + +Optional properties: + - reset-gpios : GPIO used to reset the device. + For details refer to, ../gpio/gpio.txt. + +Example: + +&i2c2 { + heart_mon@58 { + compatible = "ti,afe4404"; + reg = <0x58>; + + tx-supply = <&vbat>; + + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_EDGE_RISING>; + + reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/health/max30100.txt b/arch/arm64/boot/dts/vendor/bindings/iio/health/max30100.txt new file mode 100644 index 0000000000000000000000000000000000000000..0054908a6e7495ed39b04a6b9a821e173e852682 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/health/max30100.txt @@ -0,0 +1,28 @@ +Maxim MAX30100 heart rate and pulse oximeter sensor + +* https://datasheets.maximintegrated.com/en/ds/MAX30100.pdf + +Required properties: + - compatible: must be "maxim,max30100" + - reg: the I2C address of the sensor + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - maxim,led-current-microamp: configuration for LED current in microamperes + while the engine is running. First indexed value is the configuration for + the RED LED, and second value is for the IR LED. + + Refer to the datasheet for the allowed current values. + +Example: + +max30100@57 { + compatible = "maxim,max30100"; + reg = <0x57>; + maxim,led-current-microamp = <24000 50000>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/health/max30102.txt b/arch/arm64/boot/dts/vendor/bindings/iio/health/max30102.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ef7ae40ae4f9adde28365842b18521b7844c1d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/health/max30102.txt @@ -0,0 +1,33 @@ +Maxim MAX30102 heart rate and pulse oximeter sensor +Maxim MAX30105 optical particle-sensing module + +* https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf +* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf + +Required properties: + - compatible: must be "maxim,max30102" or "maxim,max30105" + - reg: the I2C address of the sensor + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - maxim,red-led-current-microamp: configuration for red LED current + - maxim,ir-led-current-microamp: configuration for IR LED current + - maxim,green-led-current-microamp: configuration for green LED current + (max30105 only) + + Note that each step is approximately 200 microamps, ranging from 0 uA to + 50800 uA. + +Example: + +max30102@57 { + compatible = "maxim,max30102"; + reg = <0x57>; + maxim,red-led-current-microamp = <7000>; + maxim,ir-led-current-microamp = <7000>; + interrupt-parent = <&gpio1>; + interrupts = <16 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/humidity/dht11.txt b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/dht11.txt new file mode 100644 index 0000000000000000000000000000000000000000..ecc24c199fd609f86e11e7098ea1e0483cf49ebf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/dht11.txt @@ -0,0 +1,14 @@ +* DHT11 humidity/temperature sensor (and compatibles like DHT22) + +Required properties: + - compatible: Should be "dht11" + - gpios: Should specify the GPIO connected to the sensor's data + line, see "gpios property" in + Documentation/devicetree/bindings/gpio/gpio.txt. + +Example: + +humidity_sensor { + compatible = "dht11"; + gpios = <&gpio0 6 0>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/humidity/hdc100x.txt b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/hdc100x.txt new file mode 100644 index 0000000000000000000000000000000000000000..c52333bdfd1997384f0fde55b5b7512af0b531fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/hdc100x.txt @@ -0,0 +1,17 @@ +* HDC100x temperature + humidity sensors + +Required properties: + - compatible: Should contain one of the following: + ti,hdc1000 + ti,hdc1008 + ti,hdc1010 + ti,hdc1050 + ti,hdc1080 + - reg: i2c address of the sensor + +Example: + +hdc100x@40 { + compatible = "ti,hdc1000"; + reg = <0x40>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/humidity/hts221.txt b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/hts221.txt new file mode 100644 index 0000000000000000000000000000000000000000..84d029372260dcb0bf690eb21d34943e82efcf63 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/hts221.txt @@ -0,0 +1,30 @@ +* HTS221 STM humidity + temperature sensor + +Required properties: +- compatible: should be "st,hts221" +- reg: i2c address of the sensor / spi cs line + +Optional properties: +- drive-open-drain: the interrupt/data ready line will be configured + as open drain, which is useful if several sensors share the same + interrupt line. This is a boolean property. + If the requested interrupt is configured as IRQ_TYPE_LEVEL_HIGH or + IRQ_TYPE_EDGE_RISING a pull-down resistor is needed to drive the line + when it is not active, whereas a pull-up one is needed when interrupt + line is configured as IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_EDGE_FALLING. + Refer to pinctrl/pinctrl-bindings.txt for the property description. +- interrupts: interrupt mapping for IRQ. It should be configured with + flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or + IRQ_TYPE_EDGE_FALLING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt + client node bindings. + +Example: + +hts221@5f { + compatible = "st,hts221"; + reg = <0x5f>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/humidity/htu21.txt b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/htu21.txt new file mode 100644 index 0000000000000000000000000000000000000000..97d79636f7ae151e2867cd0d01e1ee87a1dea399 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/humidity/htu21.txt @@ -0,0 +1,13 @@ +*HTU21 - Measurement-Specialties htu21 temperature & humidity sensor and humidity part of MS8607 sensor + +Required properties: + + - compatible: should be "meas,htu21" or "meas,ms8607-humidity" + - reg: I2C address of the sensor + +Example: + +htu21@40 { + compatible = "meas,htu21"; + reg = <0x40>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/iio-bindings.txt b/arch/arm64/boot/dts/vendor/bindings/iio/iio-bindings.txt new file mode 100644 index 0000000000000000000000000000000000000000..68d6f8ce063b87ca41496d387f58916916e004ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/iio-bindings.txt @@ -0,0 +1,97 @@ +This binding is derived from clock bindings, and based on suggestions +from Lars-Peter Clausen [1]. + +Sources of IIO channels can be represented by any node in the device +tree. Those nodes are designated as IIO providers. IIO consumer +nodes use a phandle and IIO specifier pair to connect IIO provider +outputs to IIO inputs. Similar to the gpio specifiers, an IIO +specifier is an array of one or more cells identifying the IIO +output on a device. The length of an IIO specifier is defined by the +value of a #io-channel-cells property in the IIO provider node. + +[1] http://marc.info/?l=linux-iio&m=135902119507483&w=2 + +==IIO providers== + +Required properties: +#io-channel-cells: Number of cells in an IIO specifier; Typically 0 for nodes + with a single IIO output and 1 for nodes with multiple + IIO outputs. + +Example for a simple configuration with no trigger: + + adc: voltage-sensor@35 { + compatible = "maxim,max1139"; + reg = <0x35>; + #io-channel-cells = <1>; + }; + +Example for a configuration with trigger: + + adc@35 { + compatible = "some-vendor,some-adc"; + reg = <0x35>; + + adc1: iio-device@0 { + #io-channel-cells = <1>; + /* other properties */ + }; + adc2: iio-device@1 { + #io-channel-cells = <1>; + /* other properties */ + }; + }; + +==IIO consumers== + +Required properties: +io-channels: List of phandle and IIO specifier pairs, one pair + for each IIO input to the device. Note: if the + IIO provider specifies '0' for #io-channel-cells, + then only the phandle portion of the pair will appear. + +Optional properties: +io-channel-names: + List of IIO input name strings sorted in the same + order as the io-channels property. Consumers drivers + will use io-channel-names to match IIO input names + with IIO specifiers. +io-channel-ranges: + Empty property indicating that child nodes can inherit named + IIO channels from this node. Useful for bus nodes to provide + and IIO channel to their children. + +For example: + + device { + io-channels = <&adc 1>, <&ref 0>; + io-channel-names = "vcc", "vdd"; + }; + +This represents a device with two IIO inputs, named "vcc" and "vdd". +The vcc channel is connected to output 1 of the &adc device, and the +vdd channel is connected to output 0 of the &ref device. + +==Example== + + adc: max1139@35 { + compatible = "maxim,max1139"; + reg = <0x35>; + #io-channel-cells = <1>; + }; + + ... + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 0>, <&adc 1>, <&adc 2>, + <&adc 3>, <&adc 4>, <&adc 5>, + <&adc 6>, <&adc 7>, <&adc 8>, + <&adc 9>; + }; + + some_consumer { + compatible = "some-consumer"; + io-channels = <&adc 10>, <&adc 11>; + io-channel-names = "adc1", "adc2"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/imu/bmi160.txt b/arch/arm64/boot/dts/vendor/bindings/iio/imu/bmi160.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c1c105fb50369c9c4f5eb5aedb700b7bfe33773 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/imu/bmi160.txt @@ -0,0 +1,35 @@ +Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope +and externally connectable Magnetometer + +https://www.bosch-sensortec.com/bst/products/all_products/bmi160 + +Required properties: + - compatible : should be "bosch,bmi160" + - reg : the I2C address or SPI chip select number of the sensor + - spi-max-frequency : set maximum clock frequency (only for SPI) + +Optional properties: + - interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW + - interrupt-names : set to "INT1" if INT1 pin should be used as interrupt + input, set to "INT2" if INT2 pin should be used instead + +Examples: + +bmi160@68 { + compatible = "bosch,bmi160"; + reg = <0x68>; + + interrupt-parent = <&gpio4>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "INT1"; +}; + +bmi160@0 { + compatible = "bosch,bmi160"; + reg = <0>; + spi-max-frequency = <10000000>; + + interrupt-parent = <&gpio2>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "INT2"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/imu/inv_mpu6050.txt b/arch/arm64/boot/dts/vendor/bindings/iio/imu/inv_mpu6050.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2f27da847b88a23fd6c6642a9ee5f3f0a6789ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/imu/inv_mpu6050.txt @@ -0,0 +1,59 @@ +InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device + +http://www.invensense.com/mems/gyro/mpu6050.html + +Required properties: + - compatible : should be one of + "invensense,mpu6050" + "invensense,mpu6500" + "invensense,mpu6515" + "invensense,mpu9150" + "invensense,mpu9250" + "invensense,mpu9255" + "invensense,icm20608" + - reg : the I2C address of the sensor + - interrupts: interrupt mapping for IRQ. It should be configured with flags + IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or + IRQ_TYPE_EDGE_FALLING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt client node + bindings. + +Optional properties: + - mount-matrix: an optional 3x3 mounting rotation matrix + - i2c-gate node. These devices also support an auxiliary i2c bus. This is + simple enough to be described using the i2c-gate binding. See + i2c/i2c-gate.txt for more details. + +Example: + mpu6050@68 { + compatible = "invensense,mpu6050"; + reg = <0x68>; + interrupt-parent = <&gpio1>; + interrupts = <18 IRQ_TYPE_EDGE_RISING>; + mount-matrix = "-0.984807753012208", /* x0 */ + "0", /* y0 */ + "-0.173648177666930", /* z0 */ + "0", /* x1 */ + "-1", /* y1 */ + "0", /* z1 */ + "-0.173648177666930", /* x2 */ + "0", /* y2 */ + "0.984807753012208"; /* z2 */ + }; + + + mpu9250@68 { + compatible = "invensense,mpu9250"; + reg = <0x68>; + interrupt-parent = <&gpio3>; + interrupts = <21 IRQ_TYPE_LEVEL_HIGH>; + i2c-gate { + #address-cells = <1>; + #size-cells = <0>; + ax8975@c { + compatible = "ak,ak8975"; + reg = <0x0c>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/imu/st_lsm6dsx.txt b/arch/arm64/boot/dts/vendor/bindings/iio/imu/st_lsm6dsx.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea2d6e0ae4c593be794ee2a948943dc6cc91fb04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/imu/st_lsm6dsx.txt @@ -0,0 +1,37 @@ +* ST_LSM6DSx driver for STM 6-axis (acc + gyro) imu Mems sensors + +Required properties: +- compatible: must be one of: + "st,lsm6ds3" + "st,lsm6ds3h" + "st,lsm6dsl" + "st,lsm6dsm" + "st,ism330dlc" +- reg: i2c address of the sensor / spi cs line + +Optional properties: +- st,drdy-int-pin: the pin on the package that will be used to signal + "data ready" (valid values: 1 or 2). +- drive-open-drain: the interrupt/data ready line will be configured + as open drain, which is useful if several sensors share the same + interrupt line. This is a boolean property. + (This binding is taken from pinctrl/pinctrl-bindings.txt) + If the requested interrupt is configured as IRQ_TYPE_LEVEL_HIGH or + IRQ_TYPE_EDGE_RISING a pull-down resistor is needed to drive the line + when it is not active, whereas a pull-up one is needed when interrupt + line is configured as IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_EDGE_FALLING. +- interrupts: interrupt mapping for IRQ. It should be configured with + flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or + IRQ_TYPE_EDGE_FALLING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt + client node bindings. + +Example: + +lsm6dsm@6b { + compatible = "st,lsm6dsm"; + reg = <0x6b>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/apds9300.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/apds9300.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa199e09a493f179ecee2cf55a45054203c5a9a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/apds9300.txt @@ -0,0 +1,21 @@ +* Avago APDS9300 ambient light sensor + +http://www.avagotech.com/docs/AV02-1077EN + +Required properties: + + - compatible : should be "avago,apds9300" + - reg : the I2C address of the sensor + +Optional properties: + + - interrupts : interrupt mapping for GPIO IRQ + +Example: + +apds9300@39 { + compatible = "avago,apds9300"; + reg = <0x39>; + interrupt-parent = <&gpio2>; + interrupts = <29 8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/apds9960.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/apds9960.txt new file mode 100644 index 0000000000000000000000000000000000000000..3af325ad194b9137da740ace14d9fc9188ddc4fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/apds9960.txt @@ -0,0 +1,21 @@ +* Avago APDS9960 gesture/RGB/ALS/proximity sensor + +http://www.avagotech.com/docs/AV02-4191EN + +Required properties: + + - compatible: must be "avago,apds9960" + - reg: the I2c address of the sensor + - interrupts : the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + +Example: + +apds9960@39 { + compatible = "avago,apds9960"; + reg = <0x39>; + interrupt-parent = <&gpio1>; + interrupts = <16 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/cm3605.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/cm3605.txt new file mode 100644 index 0000000000000000000000000000000000000000..56331a79f9ab21cf54bebd7926f4697e935fda48 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/cm3605.txt @@ -0,0 +1,41 @@ +Capella Microsystems CM3605 +Ambient Light and Short Distance Proximity Sensor + +The CM3605 is an entirely analog part which however require quite a bit of +software logic to interface a host operating system. + +This ALS and proximity sensor was one of the very first deployed in mobile +handsets, notably it is used in the very first Nexus One Android phone from +2010. + +Required properties: +- compatible: must be: "capella,cm3605" +- aset-gpios: GPIO line controlling the ASET line (drive low + to activate the ALS, should be flagged GPIO_ACTIVE_LOW) +- interrupts: the IRQ line (such as a GPIO) that is connected to + the POUT (proximity sensor out) line. The edge detection must + be set to IRQ_TYPE_EDGE_BOTH so as to detect movements toward + and away from the proximity sensor. +- io-channels: the ADC channel used for converting the voltage from + AOUT to a digital representation. +- io-channel-names: must be "aout" + +Optional properties: +- vdd-supply: regulator supplying VDD power to the component. +- capella,aset-resistance-ohms: the sensitivity calibration resistance, + in Ohms. Valid values are: 50000, 100000, 300000 and 600000, + as these are the resistance values that we are supplied with + calibration curves for. If not supplied, 100 kOhm will be assumed + but it is strongly recommended to supply this. + +Example: + +cm3605 { + compatible = "capella,cm3605"; + vdd-supply = <&foo_reg>; + aset-gpios = <&foo_gpio 1 GPIO_ACTIVE_LOW>; + capella,aset-resistance-ohms = <100000>; + interrupts = <1 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&adc 0x01>; + io-channel-names = "aout"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/cm36651.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/cm36651.txt new file mode 100644 index 0000000000000000000000000000000000000000..c03e19db4550898f52ad98f3851fc9ab4c3dd538 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/cm36651.txt @@ -0,0 +1,26 @@ +* Capella CM36651 I2C Proximity and Color Light sensor + +Required properties: +- compatible: must be "capella,cm36651" +- reg: the I2C address of the device +- interrupts: interrupt-specifier for the sole interrupt + generated by the device +- vled-supply: regulator for the IR LED. IR_LED is a part + of the cm36651 for proximity detection. + As covered in ../../regulator/regulator.txt + +Example: + + i2c_cm36651: i2c-gpio { + /* ... */ + + cm36651@18 { + compatible = "capella,cm36651"; + reg = <0x18>; + interrupt-parent = <&gpx0>; + interrupts = <2 0>; + vled-supply = <&ps_als_reg>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/gp2ap020a00f.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/gp2ap020a00f.txt new file mode 100644 index 0000000000000000000000000000000000000000..9231c82317ad52cee6109bf026808e67a0c3bc5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/gp2ap020a00f.txt @@ -0,0 +1,21 @@ +* Sharp GP2AP020A00F I2C Proximity/ALS sensor + +The proximity detector sensor requires power supply +for its built-in led. It is also defined by this binding. + +Required properties: + + - compatible : should be "sharp,gp2ap020a00f" + - reg : the I2C slave address of the light sensor + - interrupts : interrupt specifier for the sole interrupt generated + by the device + - vled-supply : VLED power supply, as covered in ../regulator/regulator.txt + +Example: + +gp2ap020a00f@39 { + compatible = "sharp,gp2ap020a00f"; + reg = <0x39>; + interrupts = <2 0>; + vled-supply = <...>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/isl29018.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/isl29018.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9bbde3e13edcc1ffa5fba12b2217e60a4e4cca2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/isl29018.txt @@ -0,0 +1,27 @@ +* ISL 29018/29023/29035 I2C ALS, Proximity, and Infrared sensor + +Required properties: + + - compatible: Should be one of + "isil,isl29018" + "isil,isl29023" + "isil,isl29035" + - reg: the I2C address of the device + +Optional properties: + + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + + - vcc-supply: phandle to the regulator that provides power to the sensor. + +Example: + +isl29018@44 { + compatible = "isil,isl29018"; + reg = <0x44>; + interrupt-parent = <&gpio>; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/isl29501.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/isl29501.txt new file mode 100644 index 0000000000000000000000000000000000000000..46957997fee3a1d6646526e7b121b260e0838b10 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/isl29501.txt @@ -0,0 +1,13 @@ +* ISL29501 Time-of-flight sensor. + +Required properties: + + - compatible : should be "renesas,isl29501" + - reg : the I2C address of the sensor + +Example: + +isl29501@57 { + compatible = "renesas,isl29501"; + reg = <0x57>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/opt3001.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/opt3001.txt new file mode 100644 index 0000000000000000000000000000000000000000..47b13eb8f4ecb02835295522860ed0643f707a51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/opt3001.txt @@ -0,0 +1,25 @@ +* Texas Instruments OPT3001 Ambient Light Sensor + +The driver supports interrupt-driven and interrupt-less operation, depending +on whether an interrupt property has been populated into the DT. Note that +the optional generation of IIO events on rising/falling light threshold changes +requires the use of interrupts. Without interrupts, only the simple reading +of the current light value is supported through the IIO API. + +http://www.ti.com/product/opt3001 + +Required properties: + - compatible: should be "ti,opt3001" + - reg: the I2C address of the sensor + +Optional properties: + - interrupts: interrupt mapping for GPIO IRQ (configure for falling edge) + +Example: + +opt3001@44 { + compatible = "ti,opt3001"; + reg = <0x44>; + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/tsl2563.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/tsl2563.txt new file mode 100644 index 0000000000000000000000000000000000000000..f91e809e736eaed329e09d66ffaa7854d8440b63 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/tsl2563.txt @@ -0,0 +1,19 @@ +* AMS TAOS TSL2563 ambient light sensor + +Required properties: + + - compatible : should be "amstaos,tsl2563" + - reg : the I2C address of the sensor + +Optional properties: + + - amstaos,cover-comp-gain : integer used as multiplier for gain + compensation (default = 1) + +Example: + +tsl2563@29 { + compatible = "amstaos,tsl2563"; + reg = <0x29>; + amstaos,cover-comp-gain = <16>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/tsl2583.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/tsl2583.txt new file mode 100644 index 0000000000000000000000000000000000000000..059dffa1829a26523bb0f3e2cd49e1cf38dfe69f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/tsl2583.txt @@ -0,0 +1,25 @@ +* TAOS TSL 2580/2581/2583 ALS sensor + +Required properties: + + - compatible: Should be one of + "amstaos,tsl2580" + "amstaos,tsl2581" + "amstaos,tsl2583" + - reg: the I2C address of the device + +Optional properties: + + - interrupts: the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic interrupt client + node bindings. + + - vcc-supply: phandle to the regulator that provides power to the sensor. + +Example: + +tsl2581@29 { + compatible = "amstaos,tsl2581"; + reg = <0x29>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/us5182d.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/us5182d.txt new file mode 100644 index 0000000000000000000000000000000000000000..a61979997f373c6e784865dbf5fe145fd388906e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/us5182d.txt @@ -0,0 +1,45 @@ +* UPISEMI us5182d I2C ALS and Proximity sensor + +Required properties: +- compatible: must be "upisemi,usd5182" +- reg: the I2C address of the device + +Optional properties: +- upisemi,glass-coef: glass attenuation factor - compensation factor of + resolution 1000 for material transmittance. + +- upisemi,dark-ths: array of 8 elements containing 16-bit thresholds (adc + counts) corresponding to every scale. + +- upisemi,upper-dark-gain: 8-bit dark gain compensation factor(4 int and 4 + fractional bits - Q4.4) applied when light > threshold + +- upisemi,lower-dark-gain: 8-bit dark gain compensation factor(4 int and 4 + fractional bits - Q4.4) applied when light < threshold + +- upisemi,continuous: This chip has two power modes: one-shot (chip takes one + measurement and then shuts itself down) and continuous ( + chip takes continuous measurements). The one-shot mode is + more power-friendly but the continuous mode may be more + reliable. If this property is specified the continuous + mode will be used instead of the default one-shot one for + raw reads. + +If the optional properties are not specified these factors will default to the +values in the below example. +The glass-coef defaults to no compensation for the covering material. +The threshold array defaults to experimental values that work with US5182D +sensor on evaluation board - roughly between 12-32 lux. +There will be no dark-gain compensation by default when ALS > thresh +(0 * dark-gain), and a 1.35 compensation factor when ALS < thresh. + +Example: + + usd5182@39 { + compatible = "upisemi,usd5182"; + reg = <0x39>; + upisemi,glass-coef = < 1000 >; + upisemi,dark-ths = /bits/ 16 <170 200 512 512 800 2000 4000 8000>; + upisemi,upper-dark-gain = /bits/ 8 <0x00>; + upisemi,lower-dark-gain = /bits/ 8 <0x16>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/uvis25.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/uvis25.txt new file mode 100644 index 0000000000000000000000000000000000000000..043c139d91e6c69f4739cf071e12493867b6a3f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/uvis25.txt @@ -0,0 +1,22 @@ +* ST UVIS25 uv sensor + +Required properties: +- compatible: should be "st,uvis25" +- reg: i2c address of the sensor / spi cs line + +Optional properties: +- interrupts: interrupt mapping for IRQ. It should be configured with + flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or + IRQ_TYPE_EDGE_FALLING. + + Refer to interrupt-controller/interrupts.txt for generic interrupt + client node bindings. + +Example: + +uvis25@47 { + compatible = "st,uvis25"; + reg = <0x47>; + interrupt-parent = <&gpio0>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/light/vl6180.txt b/arch/arm64/boot/dts/vendor/bindings/iio/light/vl6180.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c52952715a0e279596067b14554c0462e3a2e9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/light/vl6180.txt @@ -0,0 +1,15 @@ +STMicro VL6180 - ALS, range and proximity sensor + +Link to datasheet: http://www.st.com/resource/en/datasheet/vl6180x.pdf + +Required properties: + + -compatible: should be "st,vl6180" + -reg: the I2C address of the sensor + +Example: + +vl6180@29 { + compatible = "st,vl6180"; + reg = <0x29>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/ak8974.txt b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/ak8974.txt new file mode 100644 index 0000000000000000000000000000000000000000..baecc4a85197573925430b86a76a446c65c6c1cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/ak8974.txt @@ -0,0 +1,29 @@ +* Asahi Kasei AK8974 magnetometer sensor + +Required properties: + +- compatible : should be "asahi-kasei,ak8974" +- reg : the I2C address of the magnetometer + +Optional properties: + +- avdd-supply: regulator supply for the analog voltage + (see regulator/regulator.txt) +- dvdd-supply: regulator supply for the digital voltage + (see regulator/regulator.txt) +- interrupts: data ready (DRDY) and interrupt (INT1) lines + from the chip, the DRDY interrupt must be placed first. + The interrupts can be triggered on rising or falling + edges alike. +- mount-matrix: an optional 3x3 mounting rotation matrix + +Example: + +ak8974@f { + compatible = "asahi-kasei,ak8974"; + reg = <0x0f>; + avdd-supply = <&foo_reg>; + dvdd-supply = <&bar_reg>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>, + <1 IRQ_TYPE_EDGE_RISING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/ak8975.txt b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/ak8975.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa67ceb0d4e046cc0f228baa10f12de33f2f6484 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/ak8975.txt @@ -0,0 +1,30 @@ +* AsahiKASEI AK8975 magnetometer sensor + +Required properties: + + - compatible : should be "asahi-kasei,ak8975" + - reg : the I2C address of the magnetometer + +Optional properties: + + - gpios : should be device tree identifier of the magnetometer DRDY pin + - vdd-supply: an optional regulator that needs to be on to provide VDD + - mount-matrix: an optional 3x3 mounting rotation matrix + +Example: + +ak8975@c { + compatible = "asahi-kasei,ak8975"; + reg = <0x0c>; + gpios = <&gpj0 7 0>; + vdd-supply = <&ldo_3v3_gnss>; + mount-matrix = "-0.984807753012208", /* x0 */ + "0", /* y0 */ + "-0.173648177666930", /* z0 */ + "0", /* x1 */ + "-1", /* y1 */ + "0", /* z1 */ + "-0.173648177666930", /* x2 */ + "0", /* y2 */ + "0.984807753012208"; /* z2 */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/bmc150_magn.txt b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/bmc150_magn.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd5fca90fb39614c97861e61f99429b8935cda31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/bmc150_magn.txt @@ -0,0 +1,21 @@ +* Bosch BMC150 magnetometer sensor + +http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf + +Required properties: + + - compatible : should be "bosch,bmc150_magn" + - reg : the I2C address of the magnetometer + +Optional properties: + + - interrupts : interrupt mapping for GPIO IRQ + +Example: + +bmc150_magn@12 { + compatible = "bosch,bmc150_magn"; + reg = <0x12>; + interrupt-parent = <&gpio1>; + interrupts = <0 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/hmc5843.txt b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/hmc5843.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e191eef014e6112696b3c82678fb20dbe3dc553 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/hmc5843.txt @@ -0,0 +1,21 @@ +* Honeywell HMC5843 magnetometer sensor + +Required properties: + + - compatible : should be "honeywell,hmc5843" + Other models which are supported with driver are: + "honeywell,hmc5883" + "honeywell,hmc5883l" + "honeywell,hmc5983" + - reg : the I2C address of the magnetometer - typically 0x1e + +Optional properties: + + - gpios : should be device tree identifier of the magnetometer DRDY pin + +Example: + +hmc5843@1e { + compatible = "honeywell,hmc5843" + reg = <0x1e>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/mmc35240.txt b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/mmc35240.txt new file mode 100644 index 0000000000000000000000000000000000000000..a01235c7fa151b31a98821f634eba98bd7dc9232 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/magnetometer/mmc35240.txt @@ -0,0 +1,13 @@ +* MEMSIC MMC35240 magnetometer sensor + +Required properties: + + - compatible : should be "memsic,mmc35240" + - reg : the I2C address of the magnetometer + +Example: + +mmc35240@30 { + compatible = "memsic,mmc35240"; + reg = <0x30>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/multiplexer/io-channel-mux.txt b/arch/arm64/boot/dts/vendor/bindings/iio/multiplexer/io-channel-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..c82794002595f56f92286b9fc30f8c41f3311bf0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/multiplexer/io-channel-mux.txt @@ -0,0 +1,39 @@ +I/O channel multiplexer bindings + +If a multiplexer is used to select which hardware signal is fed to +e.g. an ADC channel, these bindings describe that situation. + +Required properties: +- compatible : "io-channel-mux" +- io-channels : Channel node of the parent channel that has multiplexed + input. +- io-channel-names : Should be "parent". +- #address-cells = <1>; +- #size-cells = <0>; +- mux-controls : Mux controller node to use for operating the mux +- channels : List of strings, labeling the mux controller states. + +For each non-empty string in the channels property, an io-channel will +be created. The number of this io-channel is the same as the index into +the list of strings in the channels property, and also matches the mux +controller state. The mux controller state is described in +../mux/mux-controller.txt + +Example: + mux: mux-controller { + compatible = "mux-gpio"; + #mux-control-cells = <0>; + + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>, + <&pioA 1 GPIO_ACTIVE_HIGH>; + }; + + adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 0>; + io-channel-names = "parent"; + + mux-controls = <&mux>; + + channels = "sync", "in", "system-regulator"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/ad5272.txt b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/ad5272.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9b2eef946aa3fc0ee0c37d1834051c36a90130d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/ad5272.txt @@ -0,0 +1,27 @@ +* Analog Devices AD5272 digital potentiometer + +The node for this device must be a child node of a I2C controller, hence +all mandatory properties for your controller must be specified. See directory: + + Documentation/devicetree/bindings/i2c + +for more details. + +Required properties: + - compatible: Must be one of the following, depending on the model: + adi,ad5272-020 + adi,ad5272-050 + adi,ad5272-100 + adi,ad5274-020 + adi,ad5274-100 + +Optional properties: + - reset-gpios: GPIO specification for the RESET input. This is an + active low signal to the AD5272. + +Example: +ad5272: potentiometer@2f { + reg = <0x2F>; + compatible = "adi,ad5272-020"; + reset-gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/ds1803.txt b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/ds1803.txt new file mode 100644 index 0000000000000000000000000000000000000000..df77bf552656686b9611bafeaa7d4f4958d54dd9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/ds1803.txt @@ -0,0 +1,21 @@ +* Maxim Integrated DS1803 digital potentiometer driver + +The node for this driver must be a child node of a I2C controller, hence +all mandatory properties for your controller must be specified. See directory: + + Documentation/devicetree/bindings/i2c + +for more details. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "maxim,ds1803-010", + "maxim,ds1803-050", + "maxim,ds1803-100" + +Example: +ds1803: ds1803@1 { + reg = <0x28>; + compatible = "maxim,ds1803-010"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/max5481.txt b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/max5481.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a91b106e0764c19c03b0896c5f93e7bc8d98fd9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/max5481.txt @@ -0,0 +1,23 @@ +* Maxim Linear-Taper Digital Potentiometer MAX5481-MAX5484 + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "maxim,max5481" + "maxim,max5482" + "maxim,max5483" + "maxim,max5484" + +Example: +max548x: max548x@0 { + compatible = "maxim,max5482"; + spi-max-frequency = <7000000>; + reg = <0>; /* chip-select */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/mcp4131.txt b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/mcp4131.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ccba16f7035326c694381b5473afa0dd0fc947b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/potentiometer/mcp4131.txt @@ -0,0 +1,84 @@ +* Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer + driver + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "microchip,mcp4131-502" + "microchip,mcp4131-103" + "microchip,mcp4131-503" + "microchip,mcp4131-104" + "microchip,mcp4132-502" + "microchip,mcp4132-103" + "microchip,mcp4132-503" + "microchip,mcp4132-104" + "microchip,mcp4141-502" + "microchip,mcp4141-103" + "microchip,mcp4141-503" + "microchip,mcp4141-104" + "microchip,mcp4142-502" + "microchip,mcp4142-103" + "microchip,mcp4142-503" + "microchip,mcp4142-104" + "microchip,mcp4151-502" + "microchip,mcp4151-103" + "microchip,mcp4151-503" + "microchip,mcp4151-104" + "microchip,mcp4152-502" + "microchip,mcp4152-103" + "microchip,mcp4152-503" + "microchip,mcp4152-104" + "microchip,mcp4161-502" + "microchip,mcp4161-103" + "microchip,mcp4161-503" + "microchip,mcp4161-104" + "microchip,mcp4162-502" + "microchip,mcp4162-103" + "microchip,mcp4162-503" + "microchip,mcp4162-104" + "microchip,mcp4231-502" + "microchip,mcp4231-103" + "microchip,mcp4231-503" + "microchip,mcp4231-104" + "microchip,mcp4232-502" + "microchip,mcp4232-103" + "microchip,mcp4232-503" + "microchip,mcp4232-104" + "microchip,mcp4241-502" + "microchip,mcp4241-103" + "microchip,mcp4241-503" + "microchip,mcp4241-104" + "microchip,mcp4242-502" + "microchip,mcp4242-103" + "microchip,mcp4242-503" + "microchip,mcp4242-104" + "microchip,mcp4251-502" + "microchip,mcp4251-103" + "microchip,mcp4251-503" + "microchip,mcp4251-104" + "microchip,mcp4252-502" + "microchip,mcp4252-103" + "microchip,mcp4252-503" + "microchip,mcp4252-104" + "microchip,mcp4261-502" + "microchip,mcp4261-103" + "microchip,mcp4261-503" + "microchip,mcp4261-104" + "microchip,mcp4262-502" + "microchip,mcp4262-103" + "microchip,mcp4262-503" + "microchip,mcp4262-104" + +Example: +mcp4131: mcp4131@0 { + compatible = "mcp4131-502"; + reg = <0>; + spi-max-frequency = <500000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/potentiostat/lmp91000.txt b/arch/arm64/boot/dts/vendor/bindings/iio/potentiostat/lmp91000.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6d0c2eb345c4cbf4fca7022549325ffa0a727d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/potentiostat/lmp91000.txt @@ -0,0 +1,33 @@ +* Texas Instruments LMP91000 series of potentiostats + +LMP91000: http://www.ti.com/lit/ds/symlink/lmp91000.pdf +LMP91002: http://www.ti.com/lit/ds/symlink/lmp91002.pdf + +Required properties: + + - compatible: should be one of the following: + "ti,lmp91000" + "ti,lmp91002" + - reg: the I2C address of the device + - io-channels: the phandle of the iio provider + + - ti,external-tia-resistor: if the property ti,tia-gain-ohm is not defined this + needs to be set to signal that an external resistor value is being used. + +Optional properties: + + - ti,tia-gain-ohm: ohm value of the internal resistor for the transimpedance + amplifier. Must be 2750, 3500, 7000, 14000, 35000, 120000, or 350000 ohms. + + - ti,rload-ohm: ohm value of the internal resistor load applied to the gas + sensor. Must be 10, 33, 50, or 100 (default) ohms. + +Example: + +lmp91000@48 { + compatible = "ti,lmp91000"; + reg = <0x48>; + ti,tia-gain-ohm = <7500>; + ti,rload = <100>; + io-channels = <&adc>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/pressure/bmp085.txt b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/bmp085.txt new file mode 100644 index 0000000000000000000000000000000000000000..61c72e63c58454a53a9478e7e7b5f3ef41f06214 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/bmp085.txt @@ -0,0 +1,27 @@ +BMP085/BMP18x/BMP28x digital pressure sensors + +Required properties: +- compatible: must be one of: + "bosch,bmp085" + "bosch,bmp180" + "bosch,bmp280" + "bosch,bme280" + +Optional properties: +- interrupts: interrupt mapping for IRQ +- reset-gpios: a GPIO line handling reset of the sensor: as the line is + active low, it should be marked GPIO_ACTIVE_LOW (see gpio/gpio.txt) +- vddd-supply: digital voltage regulator (see regulator/regulator.txt) +- vdda-supply: analog voltage regulator (see regulator/regulator.txt) + +Example: + +pressure@77 { + compatible = "bosch,bmp085"; + reg = <0x77>; + interrupt-parent = <&gpio0>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + reset-gpios = <&gpio0 26 GPIO_ACTIVE_LOW>; + vddd-supply = <&foo>; + vdda-supply = <&bar>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/pressure/hp03.txt b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/hp03.txt new file mode 100644 index 0000000000000000000000000000000000000000..831dbee7a5c35abee4e2d64e5c2c30de653fbe7a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/hp03.txt @@ -0,0 +1,17 @@ +HopeRF HP03 digital pressure/temperature sensors + +Required properties: +- compatible: must be "hoperf,hp03" +- xclr-gpio: must be device tree identifier of the XCLR pin. + The XCLR pin is a reset of the ADC in the chip, + it must be pulled HI before the conversion and + readout of the value from the ADC registers and + pulled LO afterward. + +Example: + +hp03@77 { + compatible = "hoperf,hp03"; + reg = <0x77>; + xclr-gpio = <&portc 0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/pressure/ms5611.txt b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/ms5611.txt new file mode 100644 index 0000000000000000000000000000000000000000..17bca866c08417dcafc08b44d9df916c06daa06a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/ms5611.txt @@ -0,0 +1,19 @@ +MEAS ms5611 family pressure sensors + +Pressure sensors from MEAS Switzerland with SPI and I2C bus interfaces. + +Required properties: +- compatible: "meas,ms5611" or "meas,ms5607" +- reg: the I2C address or SPI chip select the device will respond to + +Optional properties: +- vdd-supply: an optional regulator that needs to be on to provide VDD + power to the sensor. + +Example: + +ms5607@77 { + compatible = "meas,ms5607"; + reg = <0x77>; + vdd-supply = <&ldo_3v3_gnss>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/pressure/ms5637.txt b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/ms5637.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f43ffa068ac60f5323e52a069b8e21643b9a3d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/ms5637.txt @@ -0,0 +1,17 @@ +* MS5637 - Measurement-Specialties MS5637, MS5805, MS5837 and MS8607 pressure & temperature sensor + +Required properties: + + -compatible: should be one of the following + meas,ms5637 + meas,ms5805 + meas,ms5837 + meas,ms8607-temppressure + -reg: I2C address of the sensor + +Example: + +ms5637@76 { + compatible = "meas,ms5637"; + reg = <0x76>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/pressure/zpa2326.txt b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/zpa2326.txt new file mode 100644 index 0000000000000000000000000000000000000000..a36ab3e0c3f767e2fe5efe7560580e0fde795f72 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/pressure/zpa2326.txt @@ -0,0 +1,29 @@ +Murata ZPA2326 pressure sensor + +Pressure sensor from Murata with SPI and I2C bus interfaces. + +Required properties: +- compatible: "murata,zpa2326" +- reg: the I2C address or SPI chip select the device will respond to + +Recommended properties for SPI bus usage: +- spi-max-frequency: maximum SPI bus frequency as documented in + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: +- vref-supply: an optional regulator that needs to be on to provide VREF + power to the sensor +- vdd-supply: an optional regulator that needs to be on to provide VDD + power to the sensor +- interrupts: interrupt mapping for IRQ as documented in + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example: + +zpa2326@5c { + compatible = "murata,zpa2326"; + reg = <0x5c>; + interrupt-parent = <&gpio>; + interrupts = <12>; + vdd-supply = <&ldo_1v8_gnss>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/proximity/as3935.txt b/arch/arm64/boot/dts/vendor/bindings/iio/proximity/as3935.txt new file mode 100644 index 0000000000000000000000000000000000000000..849115585d55000328091a6e517b060c8899a390 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/proximity/as3935.txt @@ -0,0 +1,34 @@ +Austrian Microsystems AS3935 Franklin lightning sensor device driver + +Required properties: + - compatible: must be "ams,as3935" + - reg: SPI chip select number for the device + - spi-max-frequency: specifies maximum SPI clock frequency + - spi-cpha: SPI Mode 1. Refer to spi/spi-bus.txt for generic SPI + slave node bindings. + - interrupts : the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - ams,tuning-capacitor-pf: Calibration tuning capacitor stepping + value 0 - 120pF. This will require using the calibration data from + the manufacturer. + - ams,nflwdth: Set the noise and watchdog threshold register on + startup. This will need to set according to the noise from the + MCU board, and possibly the local environment. Refer to the + datasheet for the threshold settings. + +Example: + +as3935@0 { + compatible = "ams,as3935"; + reg = <0>; + spi-max-frequency = <400000>; + spi-cpha; + interrupt-parent = <&gpio1>; + interrupts = <16 1>; + ams,tuning-capacitor-pf = <80>; + ams,nflwdth = <0x44>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/proximity/devantech-srf04.txt b/arch/arm64/boot/dts/vendor/bindings/iio/proximity/devantech-srf04.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4dc7a227e2ed8840cf2ca861661dd9bedd1cdee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/proximity/devantech-srf04.txt @@ -0,0 +1,28 @@ +* Devantech SRF04 ultrasonic range finder + Bit-banging driver using two GPIOs + +Required properties: + - compatible: Should be "devantech,srf04" + + - trig-gpios: Definition of the GPIO for the triggering (output) + This GPIO is set for about 10 us by the driver to tell the + device it should initiate the measurement cycle. + + - echo-gpios: Definition of the GPIO for the echo (input) + This GPIO is set by the device as soon as an ultrasonic + burst is sent out and reset when the first echo is + received. + Thus this GPIO is set while the ultrasonic waves are doing + one round trip. + It needs to be an GPIO which is able to deliver an + interrupt because the time between two interrupts is + measured in the driver. + See Documentation/devicetree/bindings/gpio/gpio.txt for + information on how to specify a consumer gpio. + +Example: +srf04@0 { + compatible = "devantech,srf04"; + trig-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + echo-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/proximity/sx9500.txt b/arch/arm64/boot/dts/vendor/bindings/iio/proximity/sx9500.txt new file mode 100644 index 0000000000000000000000000000000000000000..c54455db3becf20f5a69e5ad713a979b24be24f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/proximity/sx9500.txt @@ -0,0 +1,23 @@ +Semtech's SX9500 capacitive proximity button device driver + +Required properties: + - compatible: must be "semtech,sx9500" + - reg: i2c address where to find the device + - interrupts : the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - reset-gpios: Reference to the GPIO connected to the device's active + low reset pin. + +Example: + +sx9500@28 { + compatible = "semtech,sx9500"; + reg = <0x28>; + interrupt-parent = <&gpio2>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/sensorhub.txt b/arch/arm64/boot/dts/vendor/bindings/iio/sensorhub.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6ac0457d4eab34862b46c8da0168fb55de2dafb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/sensorhub.txt @@ -0,0 +1,24 @@ +Samsung Sensorhub driver + +Sensorhub is a MCU which manages several sensors and also plays the role +of a virtual sensor device. + +Required properties: +- compatible: "samsung,sensorhub-rinato" or "samsung,sensorhub-thermostat" +- spi-max-frequency: max SPI clock frequency +- interrupts: communication interrupt +- ap-mcu-gpios: [out] ap to sensorhub line - used during communication +- mcu-ap-gpios: [in] sensorhub to ap - used during communication +- mcu-reset-gpios: [out] sensorhub reset + +Example: + + shub_spi: shub { + compatible = "samsung,sensorhub-rinato"; + spi-max-frequency = <5000000>; + interrupt-parent = <&gpx0>; + interrupts = <2 0>; + ap-mcu-gpios = <&gpx0 0 0>; + mcu-ap-gpios = <&gpx0 4 0>; + mcu-reset-gpios = <&gpx0 5 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/st-sensors.txt b/arch/arm64/boot/dts/vendor/bindings/iio/st-sensors.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f626f73417ee6aeccc78eabeb45a86994c93186 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/st-sensors.txt @@ -0,0 +1,77 @@ +STMicroelectronics MEMS sensors + +The STMicroelectronics sensor devices are pretty straight-forward I2C or +SPI devices, all sharing the same device tree descriptions no matter what +type of sensor it is. + +Required properties: +- compatible: see the list of valid compatible strings below +- reg: the I2C or SPI address the device will respond to + +Optional properties: +- vdd-supply: an optional regulator that needs to be on to provide VDD + power to the sensor. +- vddio-supply: an optional regulator that needs to be on to provide the + VDD IO power to the sensor. +- st,drdy-int-pin: the pin on the package that will be used to signal + "data ready" (valid values: 1 or 2). This property is not configurable + on all sensors. +- drive-open-drain: the interrupt/data ready line will be configured + as open drain, which is useful if several sensors share the same + interrupt line. (This binding is taken from pinctrl/pinctrl-bindings.txt) + This is a boolean property. + +Sensors may also have applicable pin control settings, those use the +standard bindings from pinctrl/pinctrl-bindings.txt. + +Valid compatible strings: + +Accelerometers: +- st,lis3lv02d (deprecated, use st,lis3lv02dl-accel) +- st,lis302dl-spi (deprecated, use st,lis3lv02dl-accel) +- st,lis3lv02dl-accel +- st,lsm303dlh-accel +- st,lsm303dlhc-accel +- st,lis3dh-accel +- st,lsm330d-accel +- st,lsm330dl-accel +- st,lsm330dlc-accel +- st,lis331dl-accel +- st,lis331dlh-accel +- st,lsm303dl-accel +- st,lsm303dlm-accel +- st,lsm330-accel +- st,lsm303agr-accel +- st,lis2dh12-accel +- st,h3lis331dl-accel +- st,lng2dm-accel +- st,lis3l02dq +- st,lis2dw12 +- st,lis3dhh + +Gyroscopes: +- st,l3g4200d-gyro +- st,lsm330d-gyro +- st,lsm330dl-gyro +- st,lsm330dlc-gyro +- st,l3gd20-gyro +- st,l3gd20h-gyro +- st,l3g4is-gyro +- st,lsm330-gyro +- st,lsm9ds0-gyro + +Magnetometers: +- st,lsm303agr-magn +- st,lsm303dlh-magn +- st,lsm303dlhc-magn +- st,lsm303dlm-magn +- st,lis3mdl-magn +- st,lis2mdl + +Pressure sensors: +- st,lps001wp-press +- st,lps25h-press +- st,lps331ap-press +- st,lps22hb-press +- st,lps33hw +- st,lps35hw diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/temperature/maxim_thermocouple.txt b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/maxim_thermocouple.txt new file mode 100644 index 0000000000000000000000000000000000000000..28bc5c4d965b83c683f24cc487396227ede8d836 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/maxim_thermocouple.txt @@ -0,0 +1,21 @@ +Maxim thermocouple support + +* https://datasheets.maximintegrated.com/en/ds/MAX6675.pdf +* https://datasheets.maximintegrated.com/en/ds/MAX31855.pdf + +Required properties: + + - compatible: must be "maxim,max31855" or "maxim,max6675" + - reg: SPI chip select number for the device + - spi-max-frequency: must be 4300000 + - spi-cpha: must be defined for max6675 to enable SPI mode 1 + + Refer to spi/spi-bus.txt for generic SPI slave bindings. + +Example: + + max31855@0 { + compatible = "maxim,max31855"; + reg = <0>; + spi-max-frequency = <4300000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/temperature/mlx90614.txt b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/mlx90614.txt new file mode 100644 index 0000000000000000000000000000000000000000..9be57b036092cb7b3f54974395e298614661f2c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/mlx90614.txt @@ -0,0 +1,24 @@ +* Melexis MLX90614 contactless IR temperature sensor + +http://melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/MLX90614-615.aspx + +Required properties: + + - compatible: should be "melexis,mlx90614" + - reg: the I2C address of the sensor + +Optional properties: + + - wakeup-gpios: device tree identifier of the GPIO connected to the SDA line + to hold low in order to wake up the device. In normal operation, the + GPIO is set as input and will not interfere in I2C communication. There + is no need for a GPIO driving the SCL line. If no GPIO is given, power + management is disabled. + +Example: + +mlx90614@5a { + compatible = "melexis,mlx90614"; + reg = <0x5a>; + wakeup-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/temperature/mlx90632.txt b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/mlx90632.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b05812001f882df26555e9b3f7ce94fdc448002 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/mlx90632.txt @@ -0,0 +1,28 @@ +* Melexis MLX90632 contactless Infra Red temperature sensor + +Link to datasheet: https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90632 + +There are various applications for the Infra Red contactless temperature sensor +and MLX90632 is most suitable for consumer applications where measured object +temperature is in range between -20 to 200 degrees Celsius with relative error +of measurement below 1 degree Celsius in object temperature range for +industrial applications. Since it can operate and measure ambient temperature +in range of -20 to 85 degrees Celsius it is suitable also for outdoor use. + +Be aware that electronics surrounding the sensor can increase ambient +temperature. MLX90632 can be calibrated to reduce the housing effect via +already existing EEPROM parameters. + +Since measured object emissivity effects Infra Red energy emitted, emissivity +should be set before requesting the object temperature. + +Required properties: + - compatible: should be "melexis,mlx90632" + - reg: the I2C address of the sensor (default 0x3a) + +Example: + +mlx90632@3a { + compatible = "melexis,mlx90632"; + reg = <0x3a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/temperature/tmp007.txt b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/tmp007.txt new file mode 100644 index 0000000000000000000000000000000000000000..da0af234a3576dde1c7f3ce4efeafdd23a7d2bcf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/tmp007.txt @@ -0,0 +1,33 @@ +* TI TMP007 - IR thermopile sensor with integrated math engine + +Link to datasheet: http://www.ti.com/lit/ds/symlink/tmp007.pdf + +Required properties: + + - compatible: should be "ti,tmp007" + - reg: the I2C address of the sensor (changeable via ADR pins) + ------------------------------ + |ADR1 | ADR0 | Device Address| + ------------------------------ + 0 0 0x40 + 0 1 0x41 + 0 SDA 0x42 + 0 SCL 0x43 + 1 0 0x44 + 1 1 0x45 + 1 SDA 0x46 + 1 SCL 0x47 + +Optional properties: + + - interrupts: interrupt mapping for GPIO IRQ (level active low) + +Example: + +tmp007@40 { + compatible = "ti,tmp007"; + reg = <0x40>; + interrupt-parent = <&gpio0>; + interrupts = <5 0x08>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/temperature/tsys01.txt b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/tsys01.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d5cc5595d0cd589ac32992a9df4ab4b66c747d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/temperature/tsys01.txt @@ -0,0 +1,19 @@ +* TSYS01 - Measurement Specialties temperature sensor + +Required properties: + + - compatible: should be "meas,tsys01" + - reg: I2C address of the sensor (changeable via CSB pin) + + ------------------------ + | CSB | Device Address | + ------------------------ + 1 0x76 + 0 0x77 + +Example: + +tsys01@76 { + compatible = "meas,tsys01"; + reg = <0x76>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/timer/stm32-lptimer-trigger.txt b/arch/arm64/boot/dts/vendor/bindings/iio/timer/stm32-lptimer-trigger.txt new file mode 100644 index 0000000000000000000000000000000000000000..85e6806b17d73440273f48bb86f9e5a55c0fa1b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/timer/stm32-lptimer-trigger.txt @@ -0,0 +1,23 @@ +STMicroelectronics STM32 Low-Power Timer Trigger + +STM32 Low-Power Timer provides trigger source (LPTIM output) that can be used +by STM32 internal ADC and/or DAC. + +Must be a sub-node of an STM32 Low-Power Timer device tree node. +See ../mfd/stm32-lptimer.txt for details about the parent node. + +Required properties: +- compatible: Must be "st,stm32-lptimer-trigger". +- reg: Identify trigger hardware block. Must be 0, 1 or 2 + respectively for lptimer1, lptimer2 or lptimer3 + trigger output. + +Example: + timer@40002400 { + compatible = "st,stm32-lptimer"; + ... + trigger@0 { + compatible = "st,stm32-lptimer-trigger"; + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iio/timer/stm32-timer-trigger.txt b/arch/arm64/boot/dts/vendor/bindings/iio/timer/stm32-timer-trigger.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8e8c769d434371e29f05d966e4060c5b3827575 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iio/timer/stm32-timer-trigger.txt @@ -0,0 +1,25 @@ +STMicroelectronics STM32 Timers IIO timer bindings + +Must be a sub-node of an STM32 Timers device tree node. +See ../mfd/stm32-timers.txt for details about the parent node. + +Required parameters: +- compatible: Must be one of: + "st,stm32-timer-trigger" + "st,stm32h7-timer-trigger" +- reg: Identify trigger hardware block. + +Example: + timers@40010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32-timers"; + reg = <0x40010000 0x400>; + clocks = <&rcc 0 160>; + clock-names = "int"; + + timer@0 { + compatible = "st,stm32-timer-trigger"; + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/infiniband/hisilicon-hns-roce.txt b/arch/arm64/boot/dts/vendor/bindings/infiniband/hisilicon-hns-roce.txt new file mode 100644 index 0000000000000000000000000000000000000000..84f1a1b505d25cede54d8689f4b51f4af497ca94 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/infiniband/hisilicon-hns-roce.txt @@ -0,0 +1,108 @@ +Hisilicon RoCE DT description + +Hisilicon RoCE engine is a part of network subsystem. +It works depending on other part of network wubsytem, such as, gmac and +dsa fabric. + +Additional properties are described here: + +Required properties: +- compatible: Should contain "hisilicon,hns-roce-v1". +- reg: Physical base address of the RoCE driver and +length of memory mapped region. +- eth-handle: phandle, specifies a reference to a node +representing a ethernet device. +- dsaf-handle: phandle, specifies a reference to a node +representing a dsaf device. +- node_guid: a number that uniquely identifies a device or component +- #address-cells: must be 2 +- #size-cells: must be 2 +Optional properties: +- dma-coherent: Present if DMA operations are coherent. +- interrupts: should contain 32 completion event irq,1 async event irq +and 1 event overflow irq. +- interrupt-names:should be one of 34 irqs for roce device + - hns-roce-comp-0 ~ hns-roce-comp-31: 32 complete event irq + - hns-roce-async: 1 async event irq + - hns-roce-common: named common exception warning irq +Example: + infiniband@c4000000 { + compatible = "hisilicon,hns-roce-v1"; + reg = <0x0 0xc4000000 0x0 0x100000>; + dma-coherent; + eth-handle = <ð2 ð3 ð4 ð5 ð6 ð7>; + dsaf-handle = <&soc0_dsa>; + node-guid = [00 9A CD 00 00 01 02 03]; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&mbigen_dsa>; + interrupts = <722 1>, + <723 1>, + <724 1>, + <725 1>, + <726 1>, + <727 1>, + <728 1>, + <729 1>, + <730 1>, + <731 1>, + <732 1>, + <733 1>, + <734 1>, + <735 1>, + <736 1>, + <737 1>, + <738 1>, + <739 1>, + <740 1>, + <741 1>, + <742 1>, + <743 1>, + <744 1>, + <745 1>, + <746 1>, + <747 1>, + <748 1>, + <749 1>, + <750 1>, + <751 1>, + <752 1>, + <753 1>, + <785 1>, + <754 4>; + + interrupt-names = "hns-roce-comp-0", + "hns-roce-comp-1", + "hns-roce-comp-2", + "hns-roce-comp-3", + "hns-roce-comp-4", + "hns-roce-comp-5", + "hns-roce-comp-6", + "hns-roce-comp-7", + "hns-roce-comp-8", + "hns-roce-comp-9", + "hns-roce-comp-10", + "hns-roce-comp-11", + "hns-roce-comp-12", + "hns-roce-comp-13", + "hns-roce-comp-14", + "hns-roce-comp-15", + "hns-roce-comp-16", + "hns-roce-comp-17", + "hns-roce-comp-18", + "hns-roce-comp-19", + "hns-roce-comp-20", + "hns-roce-comp-21", + "hns-roce-comp-22", + "hns-roce-comp-23", + "hns-roce-comp-24", + "hns-roce-comp-25", + "hns-roce-comp-26", + "hns-roce-comp-27", + "hns-roce-comp-28", + "hns-roce-comp-29", + "hns-roce-comp-30", + "hns-roce-comp-31", + "hns-roce-async", + "hns-roce-common"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/adc-keys.txt b/arch/arm64/boot/dts/vendor/bindings/input/adc-keys.txt new file mode 100644 index 0000000000000000000000000000000000000000..e551814629b48e3a0ece53bf226864a701d1ed61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/adc-keys.txt @@ -0,0 +1,49 @@ +ADC attached resistor ladder buttons +------------------------------------ + +Required properties: + - compatible: "adc-keys" + - io-channels: Phandle to an ADC channel + - io-channel-names = "buttons"; + - keyup-threshold-microvolt: Voltage at which all the keys are considered up. + +Optional properties: + - poll-interval: Poll interval time in milliseconds + - autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem. + +Each button (key) is represented as a sub-node of "adc-keys": + +Required subnode-properties: + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + - press-threshold-microvolt: Voltage ADC input when this key is pressed. + +Example: + +#include + + adc-keys { + compatible = "adc-keys"; + io-channels = <&lradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <2000000>; + + button-up { + label = "Volume Up"; + linux,code = ; + press-threshold-microvolt = <1500000>; + }; + + button-down { + label = "Volume Down"; + linux,code = ; + press-threshold-microvolt = <1000000>; + }; + + button-enter { + label = "Enter"; + linux,code = ; + press-threshold-microvolt = <500000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/atmel,captouch.txt b/arch/arm64/boot/dts/vendor/bindings/input/atmel,captouch.txt new file mode 100644 index 0000000000000000000000000000000000000000..fe9ee5c53bcceaf1b4a4a5794685ee474821be09 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/atmel,captouch.txt @@ -0,0 +1,36 @@ +Device tree bindings for Atmel capacitive touch device, typically +an Atmel touch sensor connected to AtmegaXX MCU running firmware +based on Qtouch library. + +The node for this device must be a child of a I2C controller node, as the +device communicates via I2C. + +Required properties: + + compatible: Must be "atmel,captouch". + reg: The I2C slave address of the device. + interrupts: Property describing the interrupt line the device + is connected to. The device only has one interrupt + source. + linux,keycodes: Specifies an array of numeric keycode values to + be used for reporting button presses. The array can + contain up to 8 entries. + +Optional properties: + + autorepeat: Enables the Linux input system's autorepeat + feature on the input device. + +Example: + + atmel-captouch@51 { + compatible = "atmel,captouch"; + reg = <0x51>; + interrupt-parent = <&tlmm>; + interrupts = <67 IRQ_TYPE_EDGE_FALLING>; + linux,keycodes = , , + , , + , , + , ; + autorepeat; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/atmel,maxtouch.txt b/arch/arm64/boot/dts/vendor/bindings/input/atmel,maxtouch.txt new file mode 100644 index 0000000000000000000000000000000000000000..c88919480d373ea373be6cdff30e9206224603db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/atmel,maxtouch.txt @@ -0,0 +1,41 @@ +Atmel maXTouch touchscreen/touchpad + +Required properties: +- compatible: + atmel,maxtouch + + The following compatibles have been used in various products but are + deprecated: + atmel,qt602240_ts + atmel,atmel_mxt_ts + atmel,atmel_mxt_tp + atmel,mXT224 + +- reg: The I2C address of the device + +- interrupts: The sink for the touchpad's IRQ output + See ../interrupt-controller/interrupts.txt + +Optional properties for main touchpad device: + +- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages + on GPIO bit changes. An array of up to 8 entries can be provided + indicating the Linux keycode mapped to each bit of the status byte, + starting at the LSB. Linux keycodes are defined in + . + + Note: the numbering of the GPIOs and the bit they start at varies between + maXTouch devices. You must either refer to the documentation, or + experiment to determine which bit corresponds to which input. Use + KEY_RESERVED for unused padding values. + +- reset-gpios: GPIO specifier for the touchscreen's reset pin (active low) + +Example: + + touch@4b { + compatible = "atmel,maxtouch"; + reg = <0x4b>; + interrupt-parent = <&gpio>; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/brcm,bcm-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/brcm,bcm-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..262deab7358898ea8ae1a626bec492c64b148faf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/brcm,bcm-keypad.txt @@ -0,0 +1,107 @@ +* Broadcom Keypad Controller device tree bindings + +Broadcom Keypad controller is used to interface a SoC with a matrix-type +keypad device. The keypad controller supports multiple row and column lines. +A key can be placed at each intersection of a unique row and a unique column. +The keypad controller can sense a key-press and key-release and report the +event using a interrupt to the cpu. + +This binding is based on the matrix-keymap binding with the following +changes: + +keypad,num-rows and keypad,num-columns are required. + +Required SoC Specific Properties: +- compatible: should be "brcm,bcm-keypad" + +- reg: physical base address of the controller and length of memory mapped + region. + +- interrupts: The interrupt number to the cpu. + +Board Specific Properties: +- keypad,num-rows: Number of row lines connected to the keypad + controller. + +- keypad,num-columns: Number of column lines connected to the + keypad controller. + +- col-debounce-filter-period: The debounce period for the Column filter. + + KEYPAD_DEBOUNCE_1_ms = 0 + KEYPAD_DEBOUNCE_2_ms = 1 + KEYPAD_DEBOUNCE_4_ms = 2 + KEYPAD_DEBOUNCE_8_ms = 3 + KEYPAD_DEBOUNCE_16_ms = 4 + KEYPAD_DEBOUNCE_32_ms = 5 + KEYPAD_DEBOUNCE_64_ms = 6 + KEYPAD_DEBOUNCE_128_ms = 7 + +- status-debounce-filter-period: The debounce period for the Status filter. + + KEYPAD_DEBOUNCE_1_ms = 0 + KEYPAD_DEBOUNCE_2_ms = 1 + KEYPAD_DEBOUNCE_4_ms = 2 + KEYPAD_DEBOUNCE_8_ms = 3 + KEYPAD_DEBOUNCE_16_ms = 4 + KEYPAD_DEBOUNCE_32_ms = 5 + KEYPAD_DEBOUNCE_64_ms = 6 + KEYPAD_DEBOUNCE_128_ms = 7 + +- row-output-enabled: An optional property indicating whether the row or + column is being used as output. If specified the row is being used + as the output. Else defaults to column. + +- pull-up-enabled: An optional property indicating the Keypad scan mode. + If specified implies the keypad scan pull-up has been enabled. + +- autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem (optional). + +- linux,keymap: The keymap for keys as described in the binding document + devicetree/bindings/input/matrix-keymap.txt. + +Example: +#include "dt-bindings/input/input.h" + +/ { + keypad: keypad@180ac000 { + /* Required SoC specific properties */ + compatible = "brcm,bcm-keypad"; + + /* Required Board specific properties */ + keypad,num-rows = <5>; + keypad,num-columns = <5>; + + linux,keymap = ; + + /* Optional board specific properties */ + col-debounce-filter-period = <5>; + row-output-enabled; + pull-up-enabled; + + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/cap11xx.txt b/arch/arm64/boot/dts/vendor/bindings/input/cap11xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c67a0b5058d82ab875b817eda7d5859fce88c9f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/cap11xx.txt @@ -0,0 +1,78 @@ +Device tree bindings for Microchip CAP11xx based capacitive touch sensors + +The node for this device must be a child of a I2C controller node, as the +device communication via I2C only. + +Required properties: + + compatible: Must contain one of: + "microchip,cap1106" + "microchip,cap1126" + "microchip,cap1188" + + reg: The I2C slave address of the device. + + interrupts: Property describing the interrupt line the + device's ALERT#/CM_IRQ# pin is connected to. + The device only has one interrupt source. + +Optional properties: + + autorepeat: Enables the Linux input system's autorepeat + feature on the input device. + + microchip,sensor-gain: Defines the gain of the sensor circuitry. This + effectively controls the sensitivity, as a + smaller delta capacitance is required to + generate the same delta count values. + Valid values are 1, 2, 4, and 8. + By default, a gain of 1 is set. + + microchip,irq-active-high: By default the interrupt pin is active low + open drain. This property allows using the active + high push-pull output. + + linux,keycodes: Specifies an array of numeric keycode values to + be used for the channels. If this property is + omitted, KEY_A, KEY_B, etc are used as + defaults. The array must have exactly six + entries. + +Example: + +i2c_controller { + cap1106@28 { + compatible = "microchip,cap1106"; + interrupt-parent = <&gpio1>; + interrupts = <0 0>; + reg = <0x28>; + autorepeat; + microchip,sensor-gain = <2>; + + linux,keycodes = <103>, /* KEY_UP */ + <106>, /* KEY_RIGHT */ + <108>, /* KEY_DOWN */ + <105>, /* KEY_LEFT */ + <109>, /* KEY_PAGEDOWN */ + <104>; /* KEY_PAGEUP */ + + #address-cells = <1>; + #size-cells = <0>; + + usr@0 { + label = "cap11xx:green:usr0"; + reg = <0>; + }; + + usr@1 { + label = "cap11xx:green:usr1"; + reg = <1>; + }; + + alive@2 { + label = "cap11xx:green:alive"; + reg = <2>; + linux,default_trigger = "heartbeat"; + }; + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/input/clps711x-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/clps711x-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..3eed8819d05d6345c2fc8e5a36e365131b2c4663 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/clps711x-keypad.txt @@ -0,0 +1,27 @@ +* Cirrus Logic CLPS711X matrix keypad device tree bindings + +Required Properties: +- compatible: Shall contain "cirrus,ep7209-keypad". +- row-gpios: List of GPIOs used as row lines. +- poll-interval: Poll interval time in milliseconds. +- linux,keymap: The definition can be found at + bindings/input/matrix-keymap.txt. + +Optional Properties: +- autorepeat: Enable autorepeat feature. + +Example: + keypad { + compatible = "cirrus,ep7312-keypad", "cirrus,ep7209-keypad"; + autorepeat; + poll-interval = <120>; + row-gpios = <&porta 0 0>, + <&porta 1 0>; + + linux,keymap = < + MATRIX_KEY(0, 0, KEY_UP) + MATRIX_KEY(0, 1, KEY_DOWN) + MATRIX_KEY(1, 0, KEY_LEFT) + MATRIX_KEY(1, 1, KEY_RIGHT) + >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/cpcap-pwrbutton.txt b/arch/arm64/boot/dts/vendor/bindings/input/cpcap-pwrbutton.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dd0076daf71f17463e0d06e856677e1d2d1bc44 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/cpcap-pwrbutton.txt @@ -0,0 +1,20 @@ +Motorola CPCAP on key + +This module is part of the CPCAP. For more details about the whole +chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt. + +This module provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be one of the following + - "motorola,cpcap-pwrbutton" +- interrupts: irq specifier for CPCAP's ON IRQ + +Example: + +&cpcap { + cpcap_pwrbutton: pwrbutton { + compatible = "motorola,cpcap-pwrbutton"; + interrupts = <23 IRQ_TYPE_NONE>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/cros-ec-keyb.txt b/arch/arm64/boot/dts/vendor/bindings/input/cros-ec-keyb.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f6355ce39b511e15bfa62b8897548793e5becb1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/cros-ec-keyb.txt @@ -0,0 +1,72 @@ +ChromeOS EC Keyboard + +Google's ChromeOS EC Keyboard is a simple matrix keyboard implemented on +a separate EC (Embedded Controller) device. It provides a message for reading +key scans from the EC. These are then converted into keycodes for processing +by the kernel. + +This binding is based on matrix-keymap.txt and extends/modifies it as follows: + +Required properties: +- compatible: "google,cros-ec-keyb" + +Optional properties: +- google,needs-ghost-filter: True to enable a ghost filter for the matrix +keyboard. This is recommended if the EC does not have its own logic or +hardware for this. + + +Example: + +cros-ec-keyb { + compatible = "google,cros-ec-keyb"; + keypad,num-rows = <8>; + keypad,num-columns = <13>; + google,needs-ghost-filter; + /* + * Keymap entries take the form of 0xRRCCKKKK where + * RR=Row CC=Column KKKK=Key Code + * The values below are for a US keyboard layout and + * are taken from the Linux driver. Note that the + * 102ND key is not used for US keyboards. + */ + linux,keymap = < + /* CAPSLCK F1 B F10 */ + 0x0001003a 0x0002003b 0x00030030 0x00040044 + /* N = R_ALT ESC */ + 0x00060031 0x0008000d 0x000a0064 0x01010001 + /* F4 G F7 H */ + 0x0102003e 0x01030022 0x01040041 0x01060023 + /* ' F9 BKSPACE L_CTRL */ + 0x01080028 0x01090043 0x010b000e 0x0200001d + /* TAB F3 T F6 */ + 0x0201000f 0x0202003d 0x02030014 0x02040040 + /* ] Y 102ND [ */ + 0x0205001b 0x02060015 0x02070056 0x0208001a + /* F8 GRAVE F2 5 */ + 0x02090042 0x03010029 0x0302003c 0x03030006 + /* F5 6 - \ */ + 0x0304003f 0x03060007 0x0308000c 0x030b002b + /* R_CTRL A D F */ + 0x04000061 0x0401001e 0x04020020 0x04030021 + /* S K J ; */ + 0x0404001f 0x04050025 0x04060024 0x04080027 + /* L ENTER Z C */ + 0x04090026 0x040b001c 0x0501002c 0x0502002e + /* V X , M */ + 0x0503002f 0x0504002d 0x05050033 0x05060032 + /* L_SHIFT / . SPACE */ + 0x0507002a 0x05080035 0x05090034 0x050B0039 + /* 1 3 4 2 */ + 0x06010002 0x06020004 0x06030005 0x06040003 + /* 8 7 0 9 */ + 0x06050009 0x06060008 0x0608000b 0x0609000a + /* L_ALT DOWN RIGHT Q */ + 0x060a0038 0x060b006c 0x060c006a 0x07010010 + /* E R W I */ + 0x07020012 0x07030013 0x07040011 0x07050017 + /* U R_SHIFT P O */ + 0x07060016 0x07070036 0x07080019 0x07090018 + /* UP LEFT */ + 0x070b0067 0x070c0069>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/cypress,cyapa.txt b/arch/arm64/boot/dts/vendor/bindings/input/cypress,cyapa.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3db65916a36393d561749a2ec076d03348083ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/cypress,cyapa.txt @@ -0,0 +1,42 @@ +Cypress I2C Touchpad + +Required properties: +- compatible: must be "cypress,cyapa". +- reg: I2C address of the chip. +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). + +Optional properties: +- wakeup-source: touchpad can be used as a wakeup source. +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the device (see + pinctrl binding [1]). +- vcc-supply: a phandle for the regulator supplying 3.3V power. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + &i2c0 { + /* ... */ + + /* Cypress Gen3 touchpad */ + touchpad@67 { + compatible = "cypress,cyapa"; + reg = <0x67>; + interrupt-parent = <&gpio>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO 2 */ + wakeup-source; + }; + + /* Cypress Gen5 and later touchpad */ + touchpad@24 { + compatible = "cypress,cyapa"; + reg = <0x24>; + interrupt-parent = <&gpio>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; /* GPIO 2 */ + wakeup-source; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/cypress,tm2-touchkey.txt b/arch/arm64/boot/dts/vendor/bindings/input/cypress,tm2-touchkey.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c252d9306dab31dfbe748e3c855215602c66de2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/cypress,tm2-touchkey.txt @@ -0,0 +1,25 @@ +Samsung tm2-touchkey + +Required properties: +- compatible: must be "cypress,tm2-touchkey" +- reg: I2C address of the chip. +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). +- vcc-supply : internal regulator output. 1.8V +- vdd-supply : power supply for IC 3.3V + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example: + &i2c0 { + /* ... */ + + touchkey@20 { + compatible = "cypress,tm2-touchkey"; + reg = <0x20>; + interrupt-parent = <&gpa3>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vcc-supply=<&ldo32_reg>; + vdd-supply=<&ldo33_reg>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/da9062-onkey.txt b/arch/arm64/boot/dts/vendor/bindings/input/da9062-onkey.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f9fbc68e58a45bd95af3ea2a5998d581a328b52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/da9062-onkey.txt @@ -0,0 +1,47 @@ +* Dialog DA9061/62/63 OnKey Module + +This module is part of the DA9061/DA9062/DA9063. For more details about entire +DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt +For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt + +This module provides the KEY_POWER event. + +Required properties: + +- compatible: should be one of the following valid compatible string lines: + "dlg,da9061-onkey", "dlg,da9062-onkey" + "dlg,da9062-onkey" + "dlg,da9063-onkey" + +Optional properties: + +- dlg,disable-key-power : Disable power-down using a long key-press. If this + entry exists the OnKey driver will remove support for the KEY_POWER key + press when triggered using a long press of the OnKey. + +Example: DA9063 + + pmic0: da9063@58 { + onkey { + compatible = "dlg,da9063-onkey"; + dlg,disable-key-power; + }; + }; + +Example: DA9062 + + pmic0: da9062@58 { + onkey { + compatible = "dlg,da9062-onkey"; + dlg,disable-key-power; + }; + }; + +Example: DA9061 using a fall-back compatible for the DA9062 onkey driver + + pmic0: da9061@58 { + onkey { + compatible = "dlg,da9061-onkey", "dlg,da9062-onkey"; + dlg,disable-key-power; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/dlink,dir685-touchkeys.txt b/arch/arm64/boot/dts/vendor/bindings/input/dlink,dir685-touchkeys.txt new file mode 100644 index 0000000000000000000000000000000000000000..10dec1c57abf5fa25323e6b4802fdba1f6961c67 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/dlink,dir685-touchkeys.txt @@ -0,0 +1,21 @@ +* D-Link DIR-685 Touchkeys + +This is a I2C one-off touchkey controller based on the Cypress Semiconductor +CY8C214 MCU with some firmware in its internal 8KB flash. The circuit +board inside the router is named E119921. + +The touchkey device node should be placed inside an I2C bus node. + +Required properties: +- compatible: must be "dlink,dir685-touchkeys" +- reg: the I2C address of the touchkeys +- interrupts: reference to the interrupt number + +Example: + +touchkeys@26 { + compatible = "dlink,dir685-touchkeys"; + reg = <0x26>; + interrupt-parent = <&gpio0>; + interrupts = <17 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/e3x0-button.txt b/arch/arm64/boot/dts/vendor/bindings/input/e3x0-button.txt new file mode 100644 index 0000000000000000000000000000000000000000..907b195f2eaabca7a7500caac8478c0e8fdef846 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/e3x0-button.txt @@ -0,0 +1,23 @@ +National Instruments Ettus Research USRP E3x0 button driver + +This module is part of the NI Ettus Research USRP E3x0 SDR. + +This module provides a simple power button event via two interrupts. + +Required properties: +- compatible: should be one of the following + - "ettus,e3x0-button": For devices such as the NI Ettus Research USRP E3x0 +- interrupts: should be one of the following + - <0 30 1>, <0 31 1>: For devices such as the NI Ettus Research USRP E3x0 +- interrupt-names: should be one of the following + - "press", "release": For devices such as the NI Ettus Research USRP E3x0 + +Note: Interrupt numbers might vary depending on the FPGA configuration. + +Example: + button { + compatible = "ettus,e3x0-button"; + interrupt-parent = <&intc>; + interrupts = <0 30 1>, <0 31 1>; + interrupt-names = "press", "release"; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/input/elan_i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/elan_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..797607460735a295994527aa536822e69ca35e3f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/elan_i2c.txt @@ -0,0 +1,33 @@ +Elantech I2C Touchpad + +Required properties: +- compatible: must be "elan,ekth3000". +- reg: I2C address of the chip. +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). + +Optional properties: +- wakeup-source: touchpad can be used as a wakeup source. +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the device (see + pinctrl binding [1]). +- vcc-supply: a phandle for the regulator supplying 3.3V power. +- elan,trackpoint: touchpad can support a trackpoint (boolean) + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + &i2c1 { + /* ... */ + + touchpad@15 { + compatible = "elan,ekth3000"; + reg = <0x15>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>; + wakeup-source; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/elants_i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/elants_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..5edac8be08028046c3f7ebb93eae8d6fea5b6927 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/elants_i2c.txt @@ -0,0 +1,34 @@ +Elantech I2C Touchscreen + +Required properties: +- compatible: must be "elan,ekth3500". +- reg: I2C address of the chip. +- interrupts: interrupt to which the chip is connected (see interrupt + binding[0]). + +Optional properties: +- wakeup-source: touchscreen can be used as a wakeup source. +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the device (see + pinctrl binding [1]). +- reset-gpios: reset gpio the chip is connected to. +- vcc33-supply: a phandle for the regulator supplying 3.3V power. +- vccio-supply: a phandle for the regulator supplying IO power. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + &i2c1 { + /* ... */ + + touchscreen@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>; + wakeup-source; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/fsl-mma8450.txt b/arch/arm64/boot/dts/vendor/bindings/input/fsl-mma8450.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b96e5737d3a569ca4acfec137cc6870d1b56880 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/fsl-mma8450.txt @@ -0,0 +1,12 @@ +* Freescale MMA8450 3-Axis Accelerometer + +Required properties: +- compatible : "fsl,mma8450". +- reg: the I2C address of MMA8450 + +Example: + +accelerometer: mma8450@1c { + compatible = "fsl,mma8450"; + reg = <0x1c>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/gpio-beeper.txt b/arch/arm64/boot/dts/vendor/bindings/input/gpio-beeper.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5086e37fce6522db73b50567904d64f9307573a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/gpio-beeper.txt @@ -0,0 +1,13 @@ +* GPIO beeper device tree bindings + +Register a beeper connected to GPIO pin. + +Required properties: +- compatible: Should be "gpio-beeper". +- gpios: From common gpio binding; gpio connection to beeper enable pin. + +Example: + beeper: beeper { + compatible = "gpio-beeper"; + gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/gpio-decoder.txt b/arch/arm64/boot/dts/vendor/bindings/input/gpio-decoder.txt new file mode 100644 index 0000000000000000000000000000000000000000..14a77fb96cf07a4360d01af9944b07462fed8894 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/gpio-decoder.txt @@ -0,0 +1,23 @@ +* GPIO Decoder DT bindings + +Required Properties: +- compatible: should be "gpio-decoder" +- gpios: a spec of gpios (at least two) to be decoded to a number with + first entry representing the MSB. + +Optional Properties: +- decoder-max-value: Maximum possible value that can be reported by + the gpios. +- linux,axis: the input subsystem axis to map to (ABS_X/ABS_Y). + Defaults to 0 (ABS_X). + +Example: + gpio-decoder0 { + compatible = "gpio-decoder"; + gpios = <&pca9536 3 GPIO_ACTIVE_HIGH>, + <&pca9536 2 GPIO_ACTIVE_HIGH>, + <&pca9536 1 GPIO_ACTIVE_HIGH>, + <&pca9536 0 GPIO_ACTIVE_HIGH>; + linux,axis = <0>; /* ABS_X */ + decoder-max-value = <9>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/gpio-keys-polled.txt b/arch/arm64/boot/dts/vendor/bindings/input/gpio-keys-polled.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d9a3717eaaf6f76105b0257da9bcccb1e496cbf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/gpio-keys-polled.txt @@ -0,0 +1,45 @@ +Device-Tree bindings for input/gpio_keys_polled.c keyboard driver + +Required properties: + - compatible = "gpio-keys-polled"; + - poll-interval: Poll interval time in milliseconds + +Optional properties: + - autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem. + +Each button (key) is represented as a sub-node of "gpio-keys-polled": +Subnode properties: + + - gpios: OF device-tree gpio specification. + - label: Descriptive name of the key. + - linux,code: Key / Axis code to emit. + +Optional subnode-properties: + - linux,input-type: Specify event type this button/key generates. + If not specified defaults to <1> == EV_KEY. + - linux,input-value: If linux,input-type is EV_ABS or EV_REL then this + value is sent for events this button generates when pressed. + EV_ABS/EV_REL axis will generate an event with a value of 0 when + all buttons with linux,input-type == type and linux,code == axis + are released. This value is interpreted as a signed 32 bit value, + e.g. to make a button generate a value of -1 use: + linux,input-value = <0xffffffff>; /* -1 */ + - debounce-interval: Debouncing interval time in milliseconds. + If not specified defaults to 5. + - wakeup-source: Boolean, button can wake-up the system. + (Legacy property supported: "gpio-key,wakeup") + +Example nodes: + + gpio_keys_polled { + compatible = "gpio-keys-polled"; + poll-interval = <100>; + autorepeat; + + button21 { + label = "GPIO Key UP"; + linux,code = <103>; + gpios = <&gpio1 0 1>; + }; + ... diff --git a/arch/arm64/boot/dts/vendor/bindings/input/gpio-keys.txt b/arch/arm64/boot/dts/vendor/bindings/input/gpio-keys.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cccc49b6beade0d60adaafc228b3ed8ecfa34e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/gpio-keys.txt @@ -0,0 +1,58 @@ +Device-Tree bindings for input/keyboard/gpio_keys.c keyboard driver + +Required properties: + - compatible = "gpio-keys"; + +Optional properties: + - autorepeat: Boolean, Enable auto repeat feature of Linux input + subsystem. + - label: String, name of the input device. + +Each button (key) is represented as a sub-node of "gpio-keys": +Subnode properties: + + - gpios: OF device-tree gpio specification. + - interrupts: the interrupt line for that input. + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + +Note that either "interrupts" or "gpios" properties can be omitted, but not +both at the same time. Specifying both properties is allowed. + +Optional subnode-properties: + - linux,input-type: Specify event type this button/key generates. + If not specified defaults to <1> == EV_KEY. + - debounce-interval: Debouncing interval time in milliseconds. + If not specified defaults to 5. + - wakeup-source: Boolean, button can wake-up the system. + (Legacy property supported: "gpio-key,wakeup") + - wakeup-event-action: Specifies whether the key should wake the + system when asserted, when deasserted, or both. This property is + only valid for keys that wake up the system (e.g., when the + "wakeup-source" property is also provided). + Supported values are defined in linux-event-codes.h: + EV_ACT_ASSERTED - asserted + EV_ACT_DEASSERTED - deasserted + EV_ACT_ANY - both asserted and deasserted + - linux,can-disable: Boolean, indicates that button is connected + to dedicated (not shared) interrupt which can be disabled to + suppress events from the button. + +Example nodes: + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + + up { + label = "GPIO Key UP"; + linux,code = <103>; + gpios = <&gpio1 0 1>; + }; + + down { + label = "GPIO Key DOWN"; + linux,code = <108>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + }; + ... diff --git a/arch/arm64/boot/dts/vendor/bindings/input/gpio-matrix-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/gpio-matrix-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..570dc10f0cd74b7da9c1ced0c2dfb73e55e452a2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/gpio-matrix-keypad.txt @@ -0,0 +1,49 @@ +* GPIO driven matrix keypad device tree bindings + +GPIO driven matrix keypad is used to interface a SoC with a matrix keypad. +The matrix keypad supports multiple row and column lines, a key can be +placed at each intersection of a unique row and a unique column. The matrix +keypad can sense a key-press and key-release by means of GPIO lines and +report the event using GPIO interrupts to the cpu. + +Required Properties: +- compatible: Should be "gpio-matrix-keypad" +- row-gpios: List of gpios used as row lines. The gpio specifier + for this property depends on the gpio controller to + which these row lines are connected. +- col-gpios: List of gpios used as column lines. The gpio specifier + for this property depends on the gpio controller to + which these column lines are connected. +- linux,keymap: The definition can be found at + bindings/input/matrix-keymap.txt + +Optional Properties: +- linux,no-autorepeat: do no enable autorepeat feature. +- wakeup-source: use any event on keypad as wakeup event. + (Legacy property supported: "linux,wakeup") +- debounce-delay-ms: debounce interval in milliseconds +- col-scan-delay-us: delay, measured in microseconds, that is needed + before we can scan keypad after activating column gpio +- drive-inactive-cols: drive inactive columns during scan, + default is to turn inactive columns into inputs. + +Example: + matrix-keypad { + compatible = "gpio-matrix-keypad"; + debounce-delay-ms = <5>; + col-scan-delay-us = <2>; + + row-gpios = <&gpio2 25 0 + &gpio2 26 0 + &gpio2 27 0>; + + col-gpios = <&gpio2 21 0 + &gpio2 22 0>; + + linux,keymap = <0x0000008B + 0x0100009E + 0x02000069 + 0x0001006A + 0x0101001C + 0x0201006C>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/gpio-mouse.txt b/arch/arm64/boot/dts/vendor/bindings/input/gpio-mouse.txt new file mode 100644 index 0000000000000000000000000000000000000000..519510a11af9814b2d95c008c83f42cfc1c361d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/gpio-mouse.txt @@ -0,0 +1,32 @@ +Device-Tree bindings for GPIO attached mice + +This simply uses standard GPIO handles to define a simple mouse connected +to 5-7 GPIO lines. + +Required properties: + - compatible: must be "gpio-mouse" + - scan-interval-ms: The scanning interval in milliseconds + - up-gpios: GPIO line phandle to the line indicating "up" + - down-gpios: GPIO line phandle to the line indicating "down" + - left-gpios: GPIO line phandle to the line indicating "left" + - right-gpios: GPIO line phandle to the line indicating "right" + +Optional properties: + - button-left-gpios: GPIO line handle to the left mouse button + - button-middle-gpios: GPIO line handle to the middle mouse button + - button-right-gpios: GPIO line handle to the right mouse button +Example: + +#include + +gpio-mouse { + compatible = "gpio-mouse"; + scan-interval-ms = <50>; + up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; + button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/hbtp-input.txt b/arch/arm64/boot/dts/vendor/bindings/input/hbtp-input.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad28952c5e7e9a2b2a909e4564e49de9bfc4b374 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/hbtp-input.txt @@ -0,0 +1,89 @@ +Platform device for Host Based Touch Processing (HBTP) + +hbtp_input is a kernel driver that provides functionality needed by +Host Based Touch Processing (HBTP) from the kernel. One of the +functionality is to manage the power source for touch Analog Front +End (AFE). + +Required properties: + + - compatible : should be "qcom,hbtp-input" + +Optional properties: + + - vcc_ana-supply : Analog power supply needed to power device + - qcom,afe-load : AFE/Analog supply load in uA + - qcom,afe-vtg-min : AFE/Analog minimum voltage in uV + - qcom,afe-vtg-max : AFE/Analog maximum voltage in uV + - qcom,dig-load : Digital supply load in uA + - qcom,dig-vtg-min : Digital supply minimum voltage in uV + - qcom,dig-vtg-max : Digital supply maximum voltage in uV + - qcom,display-resolution : Display resolution - maxX, maxY + - qcom,use-scale : boolean, enables the scaling for touch coordinates + - pinctrl-names : defines pinctrl names + "pmx_ts_active" : Required pinctrl name. + This should specify active config of TS RST gpio + "pmx_ts_suspend" : Required pinctrl name + This should specify suspend config of TS RST gpio + "ddic_rst_active" : Required pinctrl name + This should specify active config of DDIC RST gpio + "ddic_rst_suspend" : Required pinctrl name + This should specify suspend config of DDIC RST gpio + - pinctrl-0 : pin control to be used for TS active config + - pinctrl-1 : pin control to be used for TS suspend config + - pinctrl-2 : pin control to be used for DDIC active config + - pinctrl-3 : pin control to be used for DDIC suspend config + +Optional properties if qcom,use-scale DT property is defined: + - qcom,def-maxx : default X-resolution of the touch panel. + - qcom,def-maxy : default Y-resolution of the touch panel. + (Above two properties should be defined in pairs only) + - qcom,des-maxx : desired X-resolution of the touch panel. + - qcom,des-maxy : desired Y-resolution of the touch panel. + (Above two properties should be defined in pairs only) + +Optional Properties if pinctrl names are defined: + - qcom,pmx-ts-on-seq-delay-us : unsigned integer type for + delay after active TS RST gpio is changed + - qcom,fb-resume-delay-us : unsigned integer type for + delay in early resume framebuffer callback + - qcom,ddic-rst-on-seq-delay-us : array of unsigned integer type for + delay of each step in series of DDIC RST gpio control + +Optional Properties if qcom,afe-vtg and qcom,dig-vtg are defined + - qcom,afe-power-on-delay-us : unsigned integer type for + delay between turning on analog and digital power supply + - qcom,afe-power-off-delay-us : unsigned integer type for + delay between turning off digital and analog power supply + +Example: + &soc { + hbtp { + compatible = "qcom,hbtp-input"; + vcc_ana-supply = <&pm8941_l17>; + vcc_dig-supply = <&pm8950_l16>; + qcom,afe-load = <50000>; + qcom,afe-vtg-min = <2850000>; + qcom,afe-vtg-max = <2850000>; + qcom,dig-load = <15000>; + qcom,dig-vtg-min = <1800000>; + qcom,dig-vtg-max = <1800000>; + qcom,display-resolution = <719 1279>; + qcom,use-scale; + qcom,default-max-x = <1080>; + qcom,default-max-y = <1920>; + qcom,desired-max-x = <720>; + qcom,desired-max-y = <1280>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "ddic_rst_active", "ddic_rst_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + pinctrl-2 = <&ddic_rst_active>; + pinctrl-3 = <&ddic_rst_suspend>; + qcom,pmx-ts-on-seq-delay-us = <1000>; + qcom,ddic-rst-on-seq-delay-us = <10000 10000 10000 10000>; + qcom,fb-resume-delay-us = <90000>; + qcom,afe-power-on-delay-us = <1000>; + qcom,afe-power-off-delay-us = <6>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/hid-over-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/hid-over-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..c76bafaf98d2fc8c84aaea3d774dee37040a6e06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/hid-over-i2c.txt @@ -0,0 +1,44 @@ +* HID over I2C Device-Tree bindings + +HID over I2C provides support for various Human Interface Devices over the +I2C bus. These devices can be for example touchpads, keyboards, touch screens +or sensors. + +The specification has been written by Microsoft and is currently available here: +http://msdn.microsoft.com/en-us/library/windows/hardware/hh852380.aspx + +If this binding is used, the kernel module i2c-hid will handle the communication +with the device and the generic hid core layer will handle the protocol. + +Required properties: +- compatible: must be "hid-over-i2c" +- reg: i2c slave address +- hid-descr-addr: HID descriptor address +- interrupts: interrupt line + +Additional optional properties: + +Some devices may support additional optional properties to help with, e.g., +power sequencing. The following properties can be supported by one or more +device-specific compatible properties, which should be used in addition to the +"hid-over-i2c" string. + +- compatible: + * "wacom,w9013" (Wacom W9013 digitizer). Supports: + - vdd-supply (3.3V) + - vddl-supply (1.8V) + - post-power-on-delay-ms + +- vdd-supply: phandle of the regulator that provides the supply voltage. +- post-power-on-delay-ms: time required by the device after enabling its regulators + or powering it on, before it is ready for communication. + +Example: + + i2c-hid-dev@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x0020>; + interrupt-parent = <&gpx3>; + interrupts = <3 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/imx-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/imx-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ebaf7d26843c7038421d650b321eeb14b0a7d23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/imx-keypad.txt @@ -0,0 +1,53 @@ +* Freescale i.MX Keypad Port(KPP) device tree bindings + +The KPP is designed to interface with a keypad matrix with 2-point contact +or 3-point contact keys. The KPP is designed to simplify the software task +of scanning a keypad matrix. The KPP is capable of detecting, debouncing, +and decoding one or multiple keys pressed simultaneously on a keypad. + +Required SoC Specific Properties: +- compatible: Should be "fsl,-kpp". + +- reg: Physical base address of the KPP and length of memory mapped + region. + +- interrupts: The KPP interrupt number to the CPU(s). + +- clocks: The clock provided by the SoC to the KPP. Some SoCs use dummy +clock(The clock for the KPP is provided by the SoCs automatically). + +Required Board Specific Properties: +- pinctrl-names: The definition can be found at +pinctrl/pinctrl-bindings.txt. + +- pinctrl-0: The definition can be found at +pinctrl/pinctrl-bindings.txt. + +- linux,keymap: The definition can be found at +bindings/input/matrix-keymap.txt. + +Example: +kpp: kpp@73f94000 { + compatible = "fsl,imx51-kpp", "fsl,imx21-kpp"; + reg = <0x73f94000 0x4000>; + interrupts = <60>; + clocks = <&clks 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_kpp_1>; + linux,keymap = <0x00000067 /* KEY_UP */ + 0x0001006c /* KEY_DOWN */ + 0x00020072 /* KEY_VOLUMEDOWN */ + 0x00030066 /* KEY_HOME */ + 0x0100006a /* KEY_RIGHT */ + 0x01010069 /* KEY_LEFT */ + 0x0102001c /* KEY_ENTER */ + 0x01030073 /* KEY_VOLUMEUP */ + 0x02000040 /* KEY_F6 */ + 0x02010042 /* KEY_F8 */ + 0x02020043 /* KEY_F9 */ + 0x02030044 /* KEY_F10 */ + 0x0300003b /* KEY_F1 */ + 0x0301003c /* KEY_F2 */ + 0x0302003d /* KEY_F3 */ + 0x03030074>; /* KEY_POWER */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/input-reset.txt b/arch/arm64/boot/dts/vendor/bindings/input/input-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..2bb2626fdb78b4521fc06a08fec7107ec85a71a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/input-reset.txt @@ -0,0 +1,33 @@ +Input: sysrq reset sequence + +A simple binding to represent a set of keys as described in +include/uapi/linux/input.h. This is to communicate a sequence of keys to the +sysrq driver. Upon holding the keys for a specified amount of time (if +specified) the system is sync'ed and reset. + +Key sequences are global to the system but all the keys in a set must be coming +from the same input device. + +The /chosen node should contain a 'linux,sysrq-reset-seq' child node to define +a set of keys. + +Required property: +sysrq-reset-seq: array of Linux keycodes, one keycode per cell. + +Optional property: +timeout-ms: duration keys must be pressed together in milliseconds before +generating a sysrq. If omitted the system is rebooted immediately when a valid +sequence has been recognized. + +Example: + + chosen { + linux,sysrq-reset-seq { + keyset = <0x03 + 0x04 + 0x0a>; + timeout-ms = <3000>; + }; + }; + +Would represent KEY_2, KEY_3 and KEY_9. diff --git a/arch/arm64/boot/dts/vendor/bindings/input/keys.txt b/arch/arm64/boot/dts/vendor/bindings/input/keys.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5a5ddde53f1978aa1d54871b29a1044db2c2a77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/keys.txt @@ -0,0 +1,8 @@ +General Keys Properties: + +Optional properties for Keys: +- power-off-time-sec: Duration in seconds which the key should be kept + pressed for device to power off automatically. Device with key pressed + shutdown feature can specify this property. +- linux,keycodes: Specifies the numeric keycode values to be used for + reporting key presses. diff --git a/arch/arm64/boot/dts/vendor/bindings/input/lpc32xx-key.txt b/arch/arm64/boot/dts/vendor/bindings/input/lpc32xx-key.txt new file mode 100644 index 0000000000000000000000000000000000000000..bcf62f856358d095916ffe50de4f9d6e65abae50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/lpc32xx-key.txt @@ -0,0 +1,31 @@ +NXP LPC32xx Key Scan Interface + +This binding is based on the matrix-keymap binding with the following +changes: + +Required Properties: +- compatible: Should be "nxp,lpc3220-key" +- reg: Physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number to the cpu. +- nxp,debounce-delay-ms: Debounce delay in ms +- nxp,scan-delay-ms: Repeated scan period in ms +- linux,keymap: the key-code to be reported when the key is pressed + and released, see also + Documentation/devicetree/bindings/input/matrix-keymap.txt + +Note: keypad,num-rows and keypad,num-columns are required, and must be equal +since LPC32xx only supports square matrices + +Example: + + key@40050000 { + compatible = "nxp,lpc3220-key"; + reg = <0x40050000 0x1000>; + interrupts = <54 0>; + keypad,num-rows = <1>; + keypad,num-columns = <1>; + nxp,debounce-delay-ms = <3>; + nxp,scan-delay-ms = <34>; + linux,keymap = <0x00000002>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/matrix-keymap.txt b/arch/arm64/boot/dts/vendor/bindings/input/matrix-keymap.txt new file mode 100644 index 0000000000000000000000000000000000000000..c54919fad17e6fc6f8ef771f7132b6de175bd9a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/matrix-keymap.txt @@ -0,0 +1,27 @@ +A simple common binding for matrix-connected key boards. Currently targeted at +defining the keys in the scope of linux key codes since that is a stable and +standardized interface at this time. + +Required properties: +- linux,keymap: an array of packed 1-cell entries containing the equivalent + of row, column and linux key-code. The 32-bit big endian cell is packed + as: + row << 24 | column << 16 | key-code + +Optional properties: +Properties for the number of rows and columns are optional because some +drivers will use fixed values for these. +- keypad,num-rows: Number of row lines connected to the keypad controller. +- keypad,num-columns: Number of column lines connected to the keypad + controller. + +Some users of this binding might choose to specify secondary keymaps for +cases where there is a modifier key such as a Fn key. Proposed names +for said properties are "linux,fn-keymap" or with another descriptive +word for the modifier other from "Fn". + +Example: + linux,keymap = < 0x00030012 + 0x0102003a >; + keypad,num-rows = <2>; + keypad,num-columns = <8>; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/mpr121-touchkey.txt b/arch/arm64/boot/dts/vendor/bindings/input/mpr121-touchkey.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7c61ee5841bcf9cd5aa0fd44087f9212e3145d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/mpr121-touchkey.txt @@ -0,0 +1,30 @@ +* Freescale MPR121 Controllor + +Required Properties: +- compatible: Should be "fsl,mpr121-touchkey" +- reg: The I2C slave address of the device. +- interrupts: The interrupt number to the cpu. +- vdd-supply: Phandle to the Vdd power supply. +- linux,keycodes: Specifies an array of numeric keycode values to + be used for reporting button presses. The array can + contain up to 12 entries. + +Optional Properties: +- wakeup-source: Use any event on keypad as wakeup event. +- autorepeat: Enable autorepeat feature. + +Example: + +#include "dt-bindings/input/input.h" + + touchkey: mpr121@5a { + compatible = "fsl,mpr121-touchkey"; + reg = <0x5a>; + interrupt-parent = <&gpio1>; + interrupts = <28 2>; + autorepeat; + vdd-supply = <&ldo4_reg>; + linux,keycodes = , , , , + , , , + , , , ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/mtk-pmic-keys.txt b/arch/arm64/boot/dts/vendor/bindings/input/mtk-pmic-keys.txt new file mode 100644 index 0000000000000000000000000000000000000000..2888d07c2ef0629e9a092619b7f1f9dc04d2d890 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/mtk-pmic-keys.txt @@ -0,0 +1,43 @@ +MediaTek MT6397/MT6323 PMIC Keys Device Driver + +There are two key functions provided by MT6397/MT6323 PMIC, pwrkey +and homekey. The key functions are defined as the subnode of the function +node provided by MT6397/MT6323 PMIC that is being defined as one kind +of Muti-Function Device (MFD) + +For MT6397/MT6323 MFD bindings see: +Documentation/devicetree/bindings/mfd/mt6397.txt + +Required properties: +- compatible: "mediatek,mt6397-keys" or "mediatek,mt6323-keys" +- linux,keycodes: See Documentation/devicetree/bindings/input/keys.txt + +Optional Properties: +- wakeup-source: See Documentation/devicetree/bindings/power/wakeup-source.txt +- mediatek,long-press-mode: Long press key shutdown setting, 1 for + pwrkey only, 2 for pwrkey/homekey together, others for disabled. +- power-off-time-sec: See Documentation/devicetree/bindings/input/keys.txt + +Example: + + pmic: mt6397 { + compatible = "mediatek,mt6397"; + + ... + + mt6397keys: mt6397keys { + compatible = "mediatek,mt6397-keys"; + mediatek,long-press-mode = <1>; + power-off-time-sec = <0>; + + power { + linux,keycodes = <116>; + wakeup-source; + }; + + home { + linux,keycodes = <114>; + }; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/nvidia,tegra20-kbc.txt b/arch/arm64/boot/dts/vendor/bindings/input/nvidia,tegra20-kbc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1faa7292e21f5de0d2d439d2c554f24082457341 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/nvidia,tegra20-kbc.txt @@ -0,0 +1,55 @@ +* Tegra keyboard controller +The key controller has maximum 24 pins to make matrix keypad. Any pin +can be configured as row or column. The maximum column pin can be 8 +and maximum row pins can be 16 for Tegra20/Tegra30. + +Required properties: +- compatible: "nvidia,tegra20-kbc" +- reg: Register base address of KBC. +- interrupts: Interrupt number for the KBC. +- nvidia,kbc-row-pins: The KBC pins which are configured as row. This is an + array of pin numbers which is used as rows. +- nvidia,kbc-col-pins: The KBC pins which are configured as column. This is an + array of pin numbers which is used as column. +- linux,keymap: The keymap for keys as described in the binding document + devicetree/bindings/input/matrix-keymap.txt. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - kbc + +Optional properties, in addition to those specified by the shared +matrix-keyboard bindings: + +- linux,fn-keymap: a second keymap, same specification as the + matrix-keyboard-controller spec but to be used when the KEY_FN modifier + key is pressed. +- nvidia,debounce-delay-ms: delay in milliseconds per row scan for debouncing +- nvidia,repeat-delay-ms: delay in milliseconds before repeat starts +- nvidia,ghost-filter: enable ghost filtering for this device +- wakeup-source: configure keyboard as a wakeup source for suspend/resume + (Legacy property supported: "nvidia,wakeup-source") + +Example: + +keyboard: keyboard { + compatible = "nvidia,tegra20-kbc"; + reg = <0x7000e200 0x100>; + interrupts = <0 85 0x04>; + clocks = <&tegra_car 36>; + resets = <&tegra_car 36>; + reset-names = "kbc"; + nvidia,ghost-filter; + nvidia,debounce-delay-ms = <640>; + nvidia,kbc-row-pins = <0 1 2>; /* pin 0, 1, 2 as rows */ + nvidia,kbc-col-pins = <11 12 13>; /* pin 11, 12, 13 as columns */ + linux,keymap = <0x00000074 + 0x00010067 + 0x00020066 + 0x01010068 + 0x02000069 + 0x02010070 + 0x02020071>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/omap-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/omap-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..34ed1c60ff95ce80b6c763a14d1ee577f4cfcba7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/omap-keypad.txt @@ -0,0 +1,28 @@ +* TI's Keypad Controller device tree bindings + +TI's Keypad controller is used to interface a SoC with a matrix-type +keypad device. The keypad controller supports multiple row and column lines. +A key can be placed at each intersection of a unique row and a unique column. +The keypad controller can sense a key-press and key-release and report the +event using a interrupt to the cpu. + +This binding is based on the matrix-keymap binding with the following +changes: + +keypad,num-rows and keypad,num-columns are required. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "ti,omap4-keypad": For controllers compatible with omap4 keypad + controller. + +Optional Properties specific to linux: +- linux,keypad-no-autorepeat: do no enable autorepeat feature. + +Example: + keypad@4ae1c000{ + compatible = "ti,omap4-keypad"; + keypad,num-rows = <2>; + keypad,num-columns = <8>; + linux,keypad-no-autorepeat; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/ps2keyb-mouse-apbps2.txt b/arch/arm64/boot/dts/vendor/bindings/input/ps2keyb-mouse-apbps2.txt new file mode 100644 index 0000000000000000000000000000000000000000..3029c5694cf6bc15ad8f325cb6d33b3e775f5f15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/ps2keyb-mouse-apbps2.txt @@ -0,0 +1,16 @@ +Aeroflex Gaisler APBPS2 PS/2 Core, supporting Keyboard or Mouse. + +The APBPS2 PS/2 core is available in the GRLIB VHDL IP core library. + +Note: In the ordinary environment for the APBPS2 core, a LEON SPARC system, +these properties are built from information in the AMBA plug&play and from +bootloader settings. + +Required properties: + +- name : Should be "GAISLER_APBPS2" or "01_060" +- reg : Address and length of the register set for the device +- interrupts : Interrupt numbers for this device + +For further information look in the documentation for the GLIB IP core library: +http://www.gaisler.com/products/grlib/grip.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/input/pwm-beeper.txt b/arch/arm64/boot/dts/vendor/bindings/input/pwm-beeper.txt new file mode 100644 index 0000000000000000000000000000000000000000..8fc0e48c20db2b2b31795e8f75c4b24257f9272f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/pwm-beeper.txt @@ -0,0 +1,24 @@ +* PWM beeper device tree bindings + +Registers a PWM device as beeper. + +Required properties: +- compatible: should be "pwm-beeper" +- pwms: phandle to the physical PWM device + +Optional properties: +- amp-supply: phandle to a regulator that acts as an amplifier for the beeper +- beeper-hz: bell frequency in Hz + +Example: + +beeper_amp: amplifier { + compatible = "fixed-regulator"; + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; +}; + +beeper { + compatible = "pwm-beeper"; + pwms = <&pwm0>; + amp-supply = <&beeper_amp>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/pwm-vibrator.txt b/arch/arm64/boot/dts/vendor/bindings/input/pwm-vibrator.txt new file mode 100644 index 0000000000000000000000000000000000000000..09145d18491d866f2642fed6e1ce981961a41ac9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/pwm-vibrator.txt @@ -0,0 +1,66 @@ +* PWM vibrator device tree bindings + +Registers a PWM device as vibrator. It is expected, that the vibrator's +strength increases based on the duty cycle of the enable PWM channel +(100% duty cycle meaning strongest vibration, 0% meaning no vibration). + +The binding supports an optional direction PWM channel, that can be +driven at fixed duty cycle. If available this is can be used to increase +the vibration effect of some devices. + +Required properties: +- compatible: should contain "pwm-vibrator" +- pwm-names: Should contain "enable" and optionally "direction" +- pwms: Should contain a PWM handle for each entry in pwm-names + +Optional properties: +- vcc-supply: Phandle for the regulator supplying power +- direction-duty-cycle-ns: Duty cycle of the direction PWM channel in + nanoseconds, defaults to 50% of the channel's + period. + +Example from Motorola Droid 4: + +&omap4_pmx_core { + vibrator_direction_pin: pinmux_vibrator_direction_pin { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1) /* dmtimer8_pwm_evt (gpio_27) */ + >; + }; + + vibrator_enable_pin: pinmux_vibrator_enable_pin { + pinctrl-single,pins = < + OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1) /* dmtimer9_pwm_evt (gpio_28) */ + >; + }; +}; + +/ { + pwm8: dmtimer-pwm { + pinctrl-names = "default"; + pinctrl-0 = <&vibrator_direction_pin>; + + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&timer8>; + ti,clock-source = <0x01>; + }; + + pwm9: dmtimer-pwm { + pinctrl-names = "default"; + pinctrl-0 = <&vibrator_enable_pin>; + + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&timer9>; + ti,clock-source = <0x01>; + }; + + vibrator { + compatible = "pwm-vibrator"; + pwms = <&pwm8 0 1000000000 0>, + <&pwm9 0 1000000000 0>; + pwm-names = "enable", "direction"; + direction-duty-cycle-ns = <1000000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/pxa27x-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/pxa27x-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8674f7e5ea52d2e0f63d4b52155fefab6555905 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/pxa27x-keypad.txt @@ -0,0 +1,60 @@ +* Marvell PXA Keypad controller + +Required Properties +- compatible : should be "marvell,pxa27x-keypad" +- reg : Address and length of the register set for the device +- interrupts : The interrupt for the keypad controller +- marvell,debounce-interval : How long time the key will be + recognized when it is pressed. It is a u32 value, and bit[31:16] + is debounce interval for direct key and bit[15:0] is debounce + interval for matrix key. The value is in binary number of 2ms + +Optional Properties For Matrix Keyes +Please refer to matrix-keymap.txt + +Optional Properties for Direct Keyes +- marvell,direct-key-count : How many direct keyes are used. +- marvell,direct-key-mask : The mask indicates which keyes + are used. If bit[X] of the mask is set, the direct key X + is used. +- marvell,direct-key-low-active : Direct key status register + tells the level of pins that connects to the direct keyes. + When this property is set, it means that when the pin level + is low, the key is pressed(active). +- marvell,direct-key-map : It is a u16 array. Each item indicates + the linux key-code for the direct key. + +Optional Properties For Rotary +- marvell,rotary0 : It is a u32 value. Bit[31:16] is the + linux key-code for rotary up. Bit[15:0] is the linux key-code + for rotary down. It is for rotary 0. +- marvell,rotary1 : Same as marvell,rotary0. It is for rotary 1. +- marvell,rotary-rel-key : When rotary is used for relative axes + in the device, the value indicates the key-code for relative + axes measurement in the device. It is a u32 value. Bit[31:16] + is for rotary 1, and Bit[15:0] is for rotary 0. + +Examples: + keypad: keypad@d4012000 { + keypad,num-rows = <3>; + keypad,num-columns = <5>; + linux,keymap = <0x0000000e /* KEY_BACKSPACE */ + 0x0001006b /* KEY_END */ + 0x00020061 /* KEY_RIGHTCTRL */ + 0x0003000b /* KEY_0 */ + 0x00040002 /* KEY_1 */ + 0x0100008b /* KEY_MENU */ + 0x01010066 /* KEY_HOME */ + 0x010200e7 /* KEY_SEND */ + 0x01030009 /* KEY_8 */ + 0x0104000a /* KEY_9 */ + 0x02000160 /* KEY_OK */ + 0x02010003 /* KEY_2 */ + 0x02020004 /* KEY_3 */ + 0x02030005 /* KEY_4 */ + 0x02040006>; /* KEY_5 */ + marvell,rotary0 = <0x006c0067>; /* KEY_UP & KEY_DOWN */ + marvell,direct-key-count = <1>; + marvell,direct-key-map = <0x001c>; + marvell,debounce-interval = <0x001e001e>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8941-pwrkey.txt b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8941-pwrkey.txt new file mode 100644 index 0000000000000000000000000000000000000000..34ab5763f49453926c38fc361e91e988d4cf591c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8941-pwrkey.txt @@ -0,0 +1,53 @@ +Qualcomm PM8941 PMIC Power Key + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8941-pwrkey" + "qcom,pm8941-resin" + +- reg: + Usage: required + Value type: + Definition: base address of registers for block + +- interrupts: + Usage: required + Value type: + Definition: key change interrupt; The format of the specifier is + defined by the binding document describing the node's + interrupt parent. + +- debounce: + Usage: optional + Value type: + Definition: time in microseconds that key must be pressed or released + for state change interrupt to trigger. + +- bias-pull-up: + Usage: optional + Value type: + Definition: presence of this property indicates that the KPDPWR_N pin + should be configured for pull up. + +- linux,code: + Usage: optional + Value type: + Definition: The input key-code associated with the power key. + Use the linux event codes defined in + include/dt-bindings/input/linux-event-codes.h + When property is omitted KEY_POWER is assumed. + +EXAMPLE + + pwrkey@800 { + compatible = "qcom,pm8941-pwrkey"; + reg = <0x800>; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a9dc6ba96b144b8667fc670524cec594f264b3d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-keypad.txt @@ -0,0 +1,90 @@ +Qualcomm PM8xxx PMIC Keypad + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8058-keypad" + "qcom,pm8921-keypad" + +- reg: + Usage: required + Value type: + Definition: address of keypad control register + +- interrupts: + Usage: required + Value type: + Definition: the first interrupt specifies the key sense interrupt + and the second interrupt specifies the key stuck interrupt. + The format of the specifier is defined by the binding + document describing the node's interrupt parent. + +- linux,keymap: + Usage: required + Value type: + Definition: the linux keymap. More information can be found in + input/matrix-keymap.txt. + +- linux,keypad-no-autorepeat: + Usage: optional + Value type: + Definition: don't enable autorepeat feature. + +- wakeup-source: + Usage: optional + Value type: + Definition: use any event on keypad as wakeup event. + (Legacy property supported: "linux,keypad-wakeup") + +- keypad,num-rows: + Usage: required + Value type: + Definition: number of rows in the keymap. More information can be found + in input/matrix-keymap.txt. + +- keypad,num-columns: + Usage: required + Value type: + Definition: number of columns in the keymap. More information can be + found in input/matrix-keymap.txt. + +- debounce: + Usage: optional + Value type: + Definition: time in microseconds that key must be pressed or release + for key sense interrupt to trigger. + +- scan-delay: + Usage: optional + Value type: + Definition: time in microseconds to pause between successive scans + of the matrix array. + +- row-hold: + Usage: optional + Value type: + Definition: time in nanoseconds to pause between scans of each row in + the matrix array. + +EXAMPLE + + keypad@148 { + compatible = "qcom,pm8921-keypad"; + reg = <0x148>; + interrupt-parent = <&pmicintc>; + interrupts = <74 1>, <75 1>; + linux,keymap = < + MATRIX_KEY(0, 0, KEY_VOLUMEUP) + MATRIX_KEY(0, 1, KEY_VOLUMEDOWN) + MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS) + MATRIX_KEY(0, 3, KEY_CAMERA) + >; + keypad,num-rows = <1>; + keypad,num-columns = <5>; + debounce = <15>; + scan-delay = <32>; + row-hold = <91500>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-pwrkey.txt b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-pwrkey.txt new file mode 100644 index 0000000000000000000000000000000000000000..588536cc96ed95d8012fd39f55f7e69e6092477d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-pwrkey.txt @@ -0,0 +1,46 @@ +Qualcomm PM8xxx PMIC Power Key + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8058-pwrkey" + "qcom,pm8921-pwrkey" + +- reg: + Usage: required + Value type: + Definition: address of power key control register + +- interrupts: + Usage: required + Value type: + Definition: the first interrupt specifies the key release interrupt + and the second interrupt specifies the key press interrupt. + The format of the specifier is defined by the binding + document describing the node's interrupt parent. + +- debounce: + Usage: optional + Value type: + Definition: time in microseconds that key must be pressed or release + for state change interrupt to trigger. + +- pull-up: + Usage: optional + Value type: + Definition: presence of this property indicates that the KPDPWR_N pin + should be configured for pull up. + +EXAMPLE + + pwrkey@1c { + compatible = "qcom,pm8921-pwrkey"; + reg = <0x1c>; + interrupt-parent = <&pmicintc>; + interrupts = <50 1>, <51 1>; + debounce = <15625>; + pull-up; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-vib.txt b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-vib.txt new file mode 100644 index 0000000000000000000000000000000000000000..64bb990075c31c3c51a1b1b1aabd4b8a3083fc30 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/qcom,pm8xxx-vib.txt @@ -0,0 +1,23 @@ +Qualcomm PM8xxx PMIC Vibrator + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8058-vib" + "qcom,pm8916-vib" + "qcom,pm8921-vib" + +- reg: + Usage: required + Value type: + Definition: address of vibration control register + +EXAMPLE + + vibrator@4a { + compatible = "qcom,pm8058-vib"; + reg = <0x4a>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/qpnp-power-on.txt b/arch/arm64/boot/dts/vendor/bindings/input/qpnp-power-on.txt new file mode 100644 index 0000000000000000000000000000000000000000..7367934138e8f58b069d300d02d971b67222e8a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/qpnp-power-on.txt @@ -0,0 +1,247 @@ +Qualcomm Technologies, Inc. QPNP Power-on PMIC Peripheral Device Tree Bindings + +qpnp-power-on devices support the power-on (PON) peripheral of Qualcomm +Technologies, Inc. PMICs. The supported functionality includes power on/off +reason, key press/release detection, PMIC reset configurations and other PON +specific features. The PON module supports multiple physical power-on (KPDPWR_N, +CBLPWR) and reset (KPDPWR_N, RESIN, KPDPWR+RESIN) sources. This peripheral is +connected to the host processor via the SPMI interface. + +Required properties: +- compatible: Must be "qcom,qpnp-power-on" +- reg: Specifies the SPMI address and size for this PON + (power-on) peripheral. + +Optional properties: +- interrupts: Specifies the interrupts associated with PON. +- interrupt-names: Specifies the interrupt names associated with + the interrupts property. Must be a subset of + "kpdpwr", "kpdpwr-bark", "resin", "resin-bark", + "cblpwr", "kpdpwr-resin-bark", and + "pmic-wd-bark". Bark interrupts are associated + with system reset configuration to allow default + reset configuration to be activated. If system + reset configuration is not supported then bark + interrupts are nops. Additionally, the + "pmic-wd-bark" interrupt can be added if the + system needs to handle PMIC watchdog barks. +- qcom,pon-dbc-delay: The debounce delay for the power-key interrupt + specified in us. + Possible values for GEN1 PON are: + 15625, 31250, 62500, 125000, 250000, 500000, + 1000000 and 2000000. + Possible values for GEN2 PON are: + 62, 123, 245, 489, 977, 1954, 3907, 7813, + 15625, 31250, 62500, 125000 and 250000. + Intermediate value is rounded down to the + nearest valid value. +- qcom,system-reset: Boolean which specifies that this PON peripheral + can be used to reset the system. This property + can only be used by one device on the system. It + is an error to include it more than once. +- qcom,modem-reset: Boolean which specifies that this PON peripheral + can be used to reset the attached modem chip. + This property can only be used by one PON device + on the system. qcom,modem-reset and + qcom,system-reset cannot be specified for the + same PON device. +- qcom,s3-debounce: The debounce delay for stage 3 reset trigger in + secs. The values range from 0 to 128. +- qcom,s3-src: The source for stage 3 reset. It can be one of + "kpdpwr", "resin", "kpdpwr-or-resin" or + "kpdpwr-and-resin". +- qcom,uvlo-panic: Boolean indicating that the device should + trigger a controlled panic shutdown if a restart + was caused by under voltage lock-out (UVLO). +- qcom,clear-warm-reset: Boolean which specifies that the WARM_RESET + reason registers need to be cleared for this + target. The property is used for the targets + which have a hardware feature to catch resets + which aren't triggered by the application + processor. In such cases clearing WARM_REASON + registers across processor resets keeps the + registers in a useful state. +- qcom,secondary-pon-reset: Boolean property which indicates that the PON + peripheral is a secondary PON device which + needs to be configured during reset in addition + to the primary PON device that is configured + for system reset through qcom,system-reset + property. + This should not be defined along with the + qcom,system-reset or qcom,modem-reset property. +- qcom,store-hard-reset-reason: Boolean property which if set will store the + hardware reset reason to SOFT_RB_SPARE register + of the core PMIC PON peripheral. +- qcom,warm-reset-poweroff-type: Poweroff type required to be configured + on PS_HOLD reset control register when the + system goes for warm reset. If this property is + not specified, then the default type, warm reset + will be configured to PS_HOLD reset control + register. + Supported values: PON_POWER_OFF_TYPE_* found in + include/dt-bindings/input/qcom,qpnp-power-on.h +- qcom,hard-reset-poweroff-type: Same description as + qcom,warm-reset-poweroff-type but this applies + for the system hard reset case. +- qcom,shutdown-poweroff-type: Same description as qcom,warm-reset-poweroff- + type but this applies for the system shutdown + case. +- qcom,kpdpwr-sw-debounce: Boolean property to enable the debounce logic + on the KPDPWR_N rising edge. +- qcom,resin-pon-reset: Boolean property which indicates that resin + needs to be configured during reset in addition + to the primary PON device that is configured + for system reset through qcom,system-reset + property. +- qcom,resin-warm-reset-type: Poweroff type required to be configured on + RESIN reset control register when the system + initiates warm reset. If this property is not + specified, then the default type, warm reset + will be configured to RESIN reset control + register. This property is effective only if + qcom,resin-pon-reset is defined. + Supported values: PON_POWER_OFF_TYPE_* found in + include/dt-bindings/input/qcom,qpnp-power-on.h +- qcom,resin-hard-reset-type: Same description as qcom,resin-warm-reset-type + but this applies for the system hard reset case. +- qcom,resin-shutdown-type: Same description as qcom,resin-warm-reset-type + but this applies for the system shutdown case. +- qcom,resin-shutdown-disable: Boolean property to disable RESIN power off + trigger during system shutdown case. + This property is effective only if + qcom,resin-pon-reset is defined. +- qcom,resin-hard-reset-disable: Boolean property to disable RESIN power + off trigger during system hard reset case. + This property is effective only if + qcom,resin-pon-reset is defined. +- qcom,ps-hold-shutdown-disable: Boolean property to disable PS_HOLD + power off trigger during system shutdown case. +- qcom,ps-hold-hard-reset-disable: Boolean property to disable PS_HOLD + power off trigger during system hard reset case. + +Optional Sub-nodes: +- qcom,pon_1 ... qcom,pon_n: These PON child nodes correspond to features + supported by the PON peripheral including reset + configurations, pushbutton keys, and regulators. + +Sub-node properties: + +Sub-nodes (if defined) should belong to either a PON configuration or a +regulator configuration. + +Regulator sub-node required properties: +- regulator-name: Regulator name for the PON regulator that is + being configured. +- qcom,pon-spare-reg-addr: Register offset from the base address of the + PON peripheral that needs to be configured for + the regulator being controlled. +- qcom,pon-spare-reg-bit: Bit position in the specified register that + needs to be configured for the regulator being + controlled. + +PON sub-node required properties: +- qcom,pon-type: The type of PON/RESET source. Supported values: + 0 = KPDPWR + 1 = RESIN + 2 = CBLPWR + 3 = KPDPWR_RESIN + These values are PON_POWER_ON_TYPE_* found in + include/dt-bindings/input/qcom,qpnp-power-on.h + +PON sub-node optional properties: +- qcom,pull-up: Boolean flag indicating if a pull-up resistor + should be enabled for the input. +- qcom,support-reset: Indicates if this PON source supports + reset functionality. + 0 = Not supported + 1 = Supported + If this property is not defined, then default S2 + reset configurations should not be modified. +- qcom,use-bark: Specify if this PON type needs to handle a bark + interrupt. +- linux,code: The input key-code associated with the reset + source. The reset source in its default + configuration can be used to support standard + keys. + +The below mentioned properties are required only when qcom,support-reset DT +property is defined and is set to 1. + +- qcom,s1-timer: The debounce timer for the BARK interrupt for + the reset source. Value is specified in ms. + Supported values are: + 0, 32, 56, 80, 128, 184, 272, 408, 608, 904, + 1352, 2048, 3072, 4480, 6720, 10256 +- qcom,s2-timer: The debounce timer for the S2 reset specified + in ms. On the expiry of this timer, the PMIC + executes the reset sequence. + Supported values are: + 0, 10, 50, 100, 250, 500, 1000, 2000 +- qcom,s2-type: The type of reset associated with this source. + Supported values: + 0 = SOFT_RESET (legacy) + 1 = WARM_RESET + 4 = SHUTDOWN + 5 = DVDD_SHUTDOWN + 7 = HARD_RESET + 8 = DVDD_HARD_RESET + These values are PON_POWER_OFF_TYPE_* found in + include/dt-bindings/input/qcom,qpnp-power-on.h + +Examples: + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x8 0x5 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "kpdpwr", "resin", "resin-bark", + "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,system-reset; + qcom,s3-debounce = <32>; + qcom,s3-src = "resin"; + qcom,clear-warm-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + qcom,pull-up; + linux,code = ; + }; + + qcom,pon_2 { + qcom,pon-type = ; + qcom,support-reset = <1>; + qcom,pull-up; + qcom,s1-timer = <0>; + qcom,s2-timer = <2000>; + qcom,s2-type = ; + linux,code = ; + qcom,use-bark; + }; + + qcom,pon_3 { + qcom,pon-type = ; + qcom,support-reset = <1>; + qcom,s1-timer = <6720>; + qcom,s2-timer = <2000>; + qcom,s2-type = ; + qcom,pull-up; + qcom,use-bark; + }; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = ; + + pon_perph_reg: qcom,pon_perph_reg { + regulator-name = "pon_spare_reg"; + qcom,pon-spare-reg-addr = <0x8c>; + qcom,pon-spare-reg-bit = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/qti-haptics.txt b/arch/arm64/boot/dts/vendor/bindings/input/qti-haptics.txt new file mode 100644 index 0000000000000000000000000000000000000000..b86bae9a3726bf8297b0136d9f28ec5324baffec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/qti-haptics.txt @@ -0,0 +1,209 @@ +Qualcomm Technologies, Inc. Haptics driver + +Haptics peripheral in QTI PMICs can support different type of actuators or +vibrators: + 1) Eccentric Rotation Mass (ERM); + 2) Linear Resonant Actuator (LRA). +This binding document describes the properties for this module. + +Properties: + +- compatible + Usage: required + Value type: + Definition: It can be one of the following: + "qcom,haptics", + "qcom,pm660-haptics", + "qcom,pm8150b-haptics". + +- reg + Usage: required + Value type: + Definition: Base address of haptics peripheral. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. Following + interrupts are required: "hap_play_irq", "hap_sc_irq". + +- qcom,actuator-type + Usage: optional + Value type: + Definition: Specifies the type of the actuator connected on the output of + haptics module. Allowed values: "erm", "lra". If this is + not specified, then LRA type will be used by default. + +- qcom,vmax-mv + Usage: optional + Value type: + Definition: Specifies the maximum allowed output voltage in millivolts + for the actuator. Value specified here will be rounded + off to the closest multiple of 116 mV. Allowed values: + 0 to 3596. If this is not specified, then 1800 mV will be + used by default. + +- qcom,play-rate-us + Usage: optional + Value type: + Definition: Specifies the period at which each sample of the 8-byte waveform + registers is played. For ERM, this period is flexible and it + can be chosen based on the desired shape of the pattern. + For LRA, it should be set equal to the resonance period + specified in the LRA actuator datasheet. Allowed values are: + 0 to 20475. If this is not specified, 5715us play rate is used. + +- vdd-supply + Usage: optional + Value type: + Definition: Specifies the phandle of the regulator device which supplies + haptics module through VDD_HAP pin. This is only needed if VDD_HAP + is supplied from an external boost regulator instead of VPH_PWR. + +Following properties are specific only when LRA actuator is used: + +- qcom,lra-resonance-sig-shape + Usage: optional + Value type: + Definition: Specifies the shape of the LRA resonance drive signal. Allowed + values: "sine", "square". If this is not specified, sinusoid + resonance driver signal is used. + +- qcom,lra-allow-variable-play-rate + Usage: optional + Value type: + Definition: If specified, "qcom,wf-play-rate-us" for LRA defined in each + effect could be different with the resonance period of the + LRA actuator. + +- qcom,lra-auto-resonance-mode + Usage: optional + Value type: + Definition: Specifies the auto resonance technique for LRA. Allowed values are: + "zxd": zero crossing based discontinuous method; + "qwd": quarter wave drive method; + +Following properties could be specified in child nodes for defining vibrating +waveforms/effects: + +- qcom,effect-id + Usage: required + Value type: + Definition: Specifies the effect ID that the client can request to play the + corresponding waveform defined in this child node. The ID is + normaly defined and sent from userspace for certain user + notification event. + +- qcom,wf-pattern + Usage: optional + Value type: + Definition: Specifies the waveform pattern in a byte array that will be + played for the effect-id. The bit fields of each byte are: + [7]: drive direction, 0 - forward; 1 - reverse + [6]: overdrive, 0 -- 1x drive; 1 -- 2x drive + [5:1]: waveform amplitude + [0]: reserved. + +- qcom,wf-vmax-mv + Usage: optional + Value type: + Definition: Specifies the maximum allowed output voltage in millivolts + for this effect. Value specified here will be rounded + off to the closest multiple of 116 mV. Allowed values: + 0 to 3596. If this is not specified, the value defined in + "qcom,vmax-mv" will be applied. + +- qcom,wf-play-rate-us + Usage: optional + Value type: + Definition: Specifies the play period in microseconds for each byte pattern. + Allowed values are: 0 to 20475. For LRA actuator, if + "qcom,lra-allow-variable-play-rate" is defined, it could be + set to other values not equal to the resonance period of the + LRA actuator. + +- qcom,wf-repeat-count + Usage: optional + Value type: + Definition: Specifies the repeat times for the waveform pattern. Allowed + values are: 1, 2, 4, 8, 16, 32, 64, 128. + +- qcom,wf-s-repeat-count + Usage: optional + Value type: + Definition: Specifies the repeat times for each sample defined in + qcom,wf-pattern. Allowed values are: 1, 2, 4, 8. + +- qcom,wf-brake-pattern + Usage: optional + Value type: + Definition: Specifies the brake pattern with 4 elements used to enable the + internal reverse braking. Allowed values for each element are: + 0: no brake + 1: brake with (Vmax / 2) strength + 2: brake with Vmax strength + 3: brake with (2 * Vmax) strength + If this property is specified with an array of non-zero values, + then the brake pattern is applied at the end of the playing + waveform. + +- qcom,lra-auto-resonance-disable + Usage: optional + Value type: + Definition: If specified, the hardware feature of LRA auto resonance detection + is disabled. + +- qcom,wf-line-in-audio + Usage: optional + Value type: + Definition: Boolean flag to indicate if the effect is playing the audio signal + comes into LINE-IN pin. If this is specified, the pattern + specified in "qcom,wf-pattern" will be ignored. + +- qcom,wf-line-in-pwm + Usage: optional + Value type: + Definition: Boolean flag to indicate if the effect is playing the PWM signal + comes into LINE-IN pin. If this is specified, the pattern + specified in "qcom,wf-pattern" will be ignored. +Example: + qcom,haptics@c000 { + compatible = "qcom,haptics"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hap-sc-irq", "hap-play-irq"; + qcom,actuator-type = "lra"; + qcom,vmax-mv = <1800>; + qcom,play-rate-us = <8000>; + qcom,lra-resonance-sig-shape = "sine"; + qcom,lra-auto-resonance-mode = "qwd"; + qcom,lra-allow-variable-play-rate; + + wf_0 { + /* CLICK effect */ + qcom,effect-id = <0>; + qcom,wf-play-rate-us = <6250>; + qcom,wf-pattern = [3e 3e 3e]; + qcom,lra-auto-resonance-disable; + }; + + wf_5 { + /* HEAVY_CLICK effect */ + qcom,effect-id = <5>; + qcom,wf-play-rate-us = <6250>; + qcom,wf-pattern = [7e 7e 7e]; + }; + + wf_6 { + /* RINGTONE_x effect */ + qcom,effect-id = <6>; + qcom,wf-line-in-audio; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/raydium_i2c_ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/raydium_i2c_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..99a4f2ab55576f945fd4a2af98318f84cb7dad52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/raydium_i2c_ts.txt @@ -0,0 +1,19 @@ +Raydium I2C touchscreen + +Required properties: +- compatible: must be "raydium,rm32380" +- reg: The I2C address of the device +- interrupts: interrupt to which the chip is connected + See ../interrupt-controller/interrupts.txt +Optional properties: +- avdd-supply: analog power supply needed to power device +- vccio-supply: IO Power source +- reset-gpios: reset gpio the chip is connected to. + +Example: + touchscreen@39 { + compatible = "raydium,rm32380"; + reg = <0x39>; + interrupt-parent = <&gpio>; + interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/regulator-haptic.txt b/arch/arm64/boot/dts/vendor/bindings/input/regulator-haptic.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ed1c7eb2f973ad645a42f28b613af5bddad0fc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/regulator-haptic.txt @@ -0,0 +1,21 @@ +* Regulator Haptic Device Tree Bindings + +Required Properties: + - compatible : Should be "regulator-haptic" + - haptic-supply : Power supply to the haptic motor. + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt + + - max-microvolt : The maximum voltage value supplied to the haptic motor. + [The unit of the voltage is a micro] + + - min-microvolt : The minimum voltage value supplied to the haptic motor. + [The unit of the voltage is a micro] + +Example: + + haptics { + compatible = "regulator-haptic"; + haptic-supply = <&motor_regulator>; + max-microvolt = <2700000>; + min-microvolt = <1100000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_2d_sensor.txt b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_2d_sensor.txt new file mode 100644 index 0000000000000000000000000000000000000000..9afffbdf6e285bc3c57673e86b4aac3e805aa855 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_2d_sensor.txt @@ -0,0 +1,56 @@ +Synaptics RMI4 2D Sensor Device Binding + +The Synaptics RMI4 core is able to support RMI4 devices using different +transports and different functions. This file describes the device tree +bindings for devices which contain 2D sensors using Function 11 or +Function 12. Complete documentation for transports and other functions +can be found in: +Documentation/devicetree/bindings/input/rmi4. + +RMI4 Function 11 and Function 12 are for 2D touch position sensing. +Additional documentation for F11 can be found at: +http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf + +Optional Touch Properties: +Description in Documentation/devicetree/bindings/input/touchscreen +- touchscreen-inverted-x +- touchscreen-inverted-y +- touchscreen-swapped-x-y +- touchscreen-x-mm +- touchscreen-y-mm + +Optional Properties: +- syna,clip-x-low: Sets a minimum value for X. +- syna,clip-y-low: Sets a minimum value for Y. +- syna,clip-x-high: Sets a maximum value for X. +- syna,clip-y-high: Sets a maximum value for Y. +- syna,offset-x: Add an offset to X. +- syna,offset-y: Add an offset to Y. +- syna,delta-x-threshold: Set the minimum distance on the X axis required + to generate an interrupt in reduced reporting + mode. +- syna,delta-y-threshold: Set the minimum distance on the Y axis required + to generate an interrupt in reduced reporting + mode. +- syna,sensor-type: Set the sensor type. 1 for touchscreen 2 for touchpad. +- syna,disable-report-mask: Mask for disabling posiiton reporting. Used to + disable reporing absolute position data. +- syna,rezero-wait-ms: Time in miliseconds to wait after issuing a rezero + command. + + +Example of a RMI4 I2C device with F11: +Example: + &i2c1 { + rmi4-i2c-dev@2c { + compatible = "syna,rmi4-i2c"; + + ... + + rmi4-f11@11 { + reg = <0x11>; + touchscreen-inverted-y; + syna,sensor-type = <2>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_f01.txt b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_f01.txt new file mode 100644 index 0000000000000000000000000000000000000000..079cad2b6843b62290c735e1bf260348e223e847 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_f01.txt @@ -0,0 +1,39 @@ +Synaptics RMI4 F01 Device Binding + +The Synaptics RMI4 core is able to support RMI4 devices using different +transports and different functions. This file describes the device tree +bindings for devices which contain Function 1. Complete documentation +for transports and other functions can be found in: +Documentation/devicetree/bindings/input/rmi4. + +Additional documentation for F01 can be found at: +http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf + +Optional Properties: +- syna,nosleep-mode: If set the device will run at full power without sleeping. + nosleep has 3 modes, 0 will not change the default + setting, 1 will disable nosleep (allow sleeping), + and 2 will enable nosleep (disabling sleep). +- syna,wakeup-threshold: Defines the amplitude of the disturbance to the + background capacitance that will cause the + device to wake from dozing. +- syna,doze-holdoff-ms: The delay to wait after the last finger lift and the + first doze cycle. +- syna,doze-interval-ms: The time period that the device sleeps between finger + activity. + + +Example of a RMI4 I2C device with F01: + Example: + &i2c1 { + rmi4-i2c-dev@2c { + compatible = "syna,rmi4-i2c"; + + ... + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcb012f5b3eeef748abba15c0db3041e1dc51e81 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_i2c.txt @@ -0,0 +1,61 @@ +Synaptics RMI4 I2C Device Binding + +The Synaptics RMI4 core is able to support RMI4 devices using different +transports and different functions. This file describes the device tree +bindings for devices using the I2C transport driver. Complete documentation +for other transports and functions can be found in +Documentation/devicetree/bindings/input/rmi4. + +Required Properties: +- compatible: syna,rmi4-i2c +- reg: I2C address +- #address-cells: Set to 1 to indicate that the function child nodes + consist of only on uint32 value. +- #size-cells: Set to 0 to indicate that the function child nodes do not + have a size property. + +Optional Properties: +- interrupts: interrupt which the rmi device is connected to. +See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +- syna,reset-delay-ms: The number of milliseconds to wait after resetting the + device. + +- syna,startup-delay-ms: The number of milliseconds to wait after powering on + the device. + +- vdd-supply: VDD power supply. +See ../regulator/regulator.txt + +- vio-supply: VIO power supply +See ../regulator/regulator.txt + +Function Parameters: +Parameters specific to RMI functions are contained in child nodes of the rmi device + node. Documentation for the parameters of each function can be found in: +Documentation/devicetree/bindings/input/rmi4/rmi_f*.txt. + + + +Example: + &i2c1 { + rmi4-i2c-dev@2c { + compatible = "syna,rmi4-i2c"; + reg = <0x2c>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&gpio>; + interrupts = <4 2>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + touchscreen-inverted-y; + syna,sensor-type = <2>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_spi.txt b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..632f473db65b383f6842ff6c08478ee6e6a0056e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/rmi4/rmi_spi.txt @@ -0,0 +1,56 @@ +Synaptics RMI4 SPI Device Binding + +The Synaptics RMI4 core is able to support RMI4 devices using different +transports and different functions. This file describes the device tree +bindings for devices using the SPI transport driver. Complete documentation +for other transports and functions can be found in +Documentation/devicetree/bindings/input/rmi4. + +Required Properties: +- compatible: syna,rmi4-spi +- reg: Chip select address for the device +- #address-cells: Set to 1 to indicate that the function child nodes + consist of only on uint32 value. +- #size-cells: Set to 0 to indicate that the function child nodes do not + have a size property. + +Optional Properties: +- interrupts: interrupt which the rmi device is connected to. +See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +- spi-rx-delay-us: microsecond delay after a read transfer. +- spi-tx-delay-us: microsecond delay after a write transfer. + +Function Parameters: +Parameters specific to RMI functions are contained in child nodes of the rmi device + node. Documentation for the parameters of each function can be found in: +Documentation/devicetree/bindings/input/rmi4/rmi_f*.txt. + + + +Example: + spi@7000d800 { + rmi4-spi-dev@0 { + compatible = "syna,rmi4-spi"; + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <4000000>; + spi-cpha; + spi-cpol; + interrupt-parent = <&gpio>; + interrupts = ; + spi-rx-delay-us = <30>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + touchscreen-inverted-y; + syna,sensor-type = <2>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/rotary-encoder.txt b/arch/arm64/boot/dts/vendor/bindings/input/rotary-encoder.txt new file mode 100644 index 0000000000000000000000000000000000000000..a644408b33b8f17d1d00be1177a259e8780a9c97 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/rotary-encoder.txt @@ -0,0 +1,50 @@ +Rotary encoder DT bindings + +Required properties: +- gpios: a spec for at least two GPIOs to be used, most significant first + +Optional properties: +- linux,axis: the input subsystem axis to map to this rotary encoder. + Defaults to 0 (ABS_X / REL_X) +- rotary-encoder,steps: Number of steps in a full turnaround of the + encoder. Only relevant for absolute axis. Defaults to 24 which is a + typical value for such devices. +- rotary-encoder,relative-axis: register a relative axis rather than an + absolute one. Relative axis will only generate +1/-1 events on the input + device, hence no steps need to be passed. +- rotary-encoder,rollover: Automatic rollover when the rotary value becomes + greater than the specified steps or smaller than 0. For absolute axis only. +- rotary-encoder,steps-per-period: Number of steps (stable states) per period. + The values have the following meaning: + 1: Full-period mode (default) + 2: Half-period mode + 4: Quarter-period mode +- wakeup-source: Boolean, rotary encoder can wake up the system. +- rotary-encoder,encoding: String, the method used to encode steps. + Supported are "gray" (the default and more common) and "binary". + +Deprecated properties: +- rotary-encoder,half-period: Makes the driver work on half-period mode. + This property is deprecated. Instead, a 'steps-per-period ' value should + be used, such as "rotary-encoder,steps-per-period = <2>". + +See Documentation/input/devices/rotary-encoder.rst for more information. + +Example: + + rotary@0 { + compatible = "rotary-encoder"; + gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */ + linux,axis = <0>; /* REL_X */ + rotary-encoder,encoding = "gray"; + rotary-encoder,relative-axis; + }; + + rotary@1 { + compatible = "rotary-encoder"; + gpios = <&gpio 21 0>, <&gpio 22 0>; + linux,axis = <1>; /* ABS_Y */ + rotary-encoder,steps = <24>; + rotary-encoder,encoding = "binary"; + rotary-encoder,rollover; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/samsung-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/samsung-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c5c0a82586d406174d1bda200b2101b32caca61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/samsung-keypad.txt @@ -0,0 +1,77 @@ +* Samsung's Keypad Controller device tree bindings + +Samsung's Keypad controller is used to interface a SoC with a matrix-type +keypad device. The keypad controller supports multiple row and column lines. +A key can be placed at each intersection of a unique row and a unique column. +The keypad controller can sense a key-press and key-release and report the +event using a interrupt to the cpu. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad + controller. + - "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad + controller. + +- reg: physical base address of the controller and length of memory mapped + region. + +- interrupts: The interrupt number to the cpu. + +Required Board Specific Properties: +- samsung,keypad-num-rows: Number of row lines connected to the keypad + controller. + +- samsung,keypad-num-columns: Number of column lines connected to the + keypad controller. + +- Keys represented as child nodes: Each key connected to the keypad + controller is represented as a child node to the keypad controller + device node and should include the following properties. + - keypad,row: the row number to which the key is connected. + - keypad,column: the column number to which the key is connected. + - linux,code: the key-code to be reported when the key is pressed + and released. + +- pinctrl-0: Should specify pin control groups used for this controller. +- pinctrl-names: Should contain only one value - "default". + +Optional Properties: +- wakeup-source: use any event on keypad as wakeup event. + (Legacy property supported: "linux,input-wakeup") + +Optional Properties specific to linux: +- linux,keypad-no-autorepeat: do no enable autorepeat feature. + + +Example: + keypad@100a0000 { + compatible = "samsung,s5pv210-keypad"; + reg = <0x100A0000 0x100>; + interrupts = <173>; + samsung,keypad-num-rows = <2>; + samsung,keypad-num-columns = <8>; + linux,input-no-autorepeat; + wakeup-source; + + pinctrl-names = "default"; + pinctrl-0 = <&keypad_rows &keypad_columns>; + + key_1 { + keypad,row = <0>; + keypad,column = <3>; + linux,code = <2>; + }; + + key_2 { + keypad,row = <0>; + keypad,column = <4>; + linux,code = <3>; + }; + + key_3 { + keypad,row = <0>; + keypad,column = <5>; + linux,code = <4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/snvs-pwrkey.txt b/arch/arm64/boot/dts/vendor/bindings/input/snvs-pwrkey.txt new file mode 100644 index 0000000000000000000000000000000000000000..70c14250323b0a85590b8fec237e748ae2b8db27 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/snvs-pwrkey.txt @@ -0,0 +1 @@ +See Documentation/devicetree/bindings/crypto/fsl-sec4.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/input/spear-keyboard.txt b/arch/arm64/boot/dts/vendor/bindings/input/spear-keyboard.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a846d26da235dbd11ddba5af0e102deb0f6486d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/spear-keyboard.txt @@ -0,0 +1,20 @@ +* SPEAr keyboard controller + +Required properties: +- compatible: "st,spear300-kbd" + +Optional properties, in addition to those specified by the shared +matrix-keyboard bindings: +- autorepeat: bool: enables key autorepeat +- st,mode: keyboard mode: 0 - 9x9, 1 - 6x6, 2 - 2x2 + +Example: + +kbd@fc400000 { + compatible = "st,spear300-kbd"; + reg = <0xfc400000 0x100>; + linux,keymap = < 0x00030012 + 0x0102003a >; + autorepeat; + st,mode = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/sprd,sc27xx-vibra.txt b/arch/arm64/boot/dts/vendor/bindings/input/sprd,sc27xx-vibra.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2ec0d4f2dff47692bd840f4b6a551345af8455a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/sprd,sc27xx-vibra.txt @@ -0,0 +1,23 @@ +Spreadtrum SC27xx PMIC Vibrator + +Required properties: +- compatible: should be "sprd,sc2731-vibrator". +- reg: address of vibrator control register. + +Example : + + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + vibrator@eb4 { + compatible = "sprd,sc2731-vibrator"; + reg = <0xeb4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/st-keyscan.txt b/arch/arm64/boot/dts/vendor/bindings/input/st-keyscan.txt new file mode 100644 index 0000000000000000000000000000000000000000..51eb428e5c85aae526bf17c66afc22f5e2d138b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/st-keyscan.txt @@ -0,0 +1,60 @@ +* ST Keyscan controller Device Tree bindings + +The ST keyscan controller Device Tree binding is based on the +matrix-keymap. + +Required properties: +- compatible: "st,sti-keyscan" + +- reg: Register base address and size of st-keyscan controller. + +- interrupts: Interrupt number for the st-keyscan controller. + +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +- pinctrl: Should specify pin control groups used for this controller. + See ../pinctrl/pinctrl-bindings.txt for details. + +- linux,keymap: The keymap for keys as described in the binding document + devicetree/bindings/input/matrix-keymap.txt. + +- keypad,num-rows: Number of row lines connected to the keypad controller. + +- keypad,num-columns: Number of column lines connected to the keypad + controller. + +Optional property: +- st,debounce_us: Debouncing interval time in microseconds + +Example: + +keyscan: keyscan@fe4b0000 { + compatible = "st,sti-keyscan"; + reg = <0xfe4b0000 0x2000>; + interrupts = ; + clocks = <&CLK_SYSIN>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_keyscan>; + + keypad,num-rows = <4>; + keypad,num-columns = <4>; + st,debounce_us = <5000>; + + linux,keymap = < MATRIX_KEY(0x00, 0x00, KEY_F13) + MATRIX_KEY(0x00, 0x01, KEY_F9) + MATRIX_KEY(0x00, 0x02, KEY_F5) + MATRIX_KEY(0x00, 0x03, KEY_F1) + MATRIX_KEY(0x01, 0x00, KEY_F14) + MATRIX_KEY(0x01, 0x01, KEY_F10) + MATRIX_KEY(0x01, 0x02, KEY_F6) + MATRIX_KEY(0x01, 0x03, KEY_F2) + MATRIX_KEY(0x02, 0x00, KEY_F15) + MATRIX_KEY(0x02, 0x01, KEY_F11) + MATRIX_KEY(0x02, 0x02, KEY_F7) + MATRIX_KEY(0x02, 0x03, KEY_F3) + MATRIX_KEY(0x03, 0x00, KEY_F16) + MATRIX_KEY(0x03, 0x01, KEY_F12) + MATRIX_KEY(0x03, 0x02, KEY_F8) + MATRIX_KEY(0x03, 0x03, KEY_F4) >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/stmpe-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/stmpe-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..12bb771d66d446647722ba3e423aabc3734f77bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/stmpe-keypad.txt @@ -0,0 +1,41 @@ +* STMPE Keypad + +Required properties: + - compatible : "st,stmpe-keypad" + - linux,keymap : See ./matrix-keymap.txt + +Optional properties: + - debounce-interval : Debouncing interval time in milliseconds + - st,scan-count : Scanning cycles elapsed before key data is updated + - st,no-autorepeat : If specified device will not autorepeat + - keypad,num-rows : See ./matrix-keymap.txt + - keypad,num-columns : See ./matrix-keymap.txt + +Example: + + stmpe_keypad { + compatible = "st,stmpe-keypad"; + + debounce-interval = <64>; + st,scan-count = <8>; + st,no-autorepeat; + + linux,keymap = <0x205006b + 0x4010074 + 0x3050072 + 0x1030004 + 0x502006a + 0x500000a + 0x5008b + 0x706001c + 0x405000b + 0x6070003 + 0x3040067 + 0x303006c + 0x60400e7 + 0x602009e + 0x4020073 + 0x5050002 + 0x4030069 + 0x3020008>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/sun4i-lradc-keys.txt b/arch/arm64/boot/dts/vendor/bindings/input/sun4i-lradc-keys.txt new file mode 100644 index 0000000000000000000000000000000000000000..1458c3179a63a2e7ea223814169247b97f77ddc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/sun4i-lradc-keys.txt @@ -0,0 +1,62 @@ +Allwinner sun4i low res adc attached tablet keys +------------------------------------------------ + +Required properties: + - compatible: "allwinner,sun4i-a10-lradc-keys" + - reg: mmio address range of the chip + - interrupts: interrupt to which the chip is connected + - vref-supply: powersupply for the lradc reference voltage + +Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys": + +Required subnode-properties: + - label: Descriptive name of the key. + - linux,code: Keycode to emit. + - channel: Channel this key is attached to, must be 0 or 1. + - voltage: Voltage in µV at lradc input when this key is pressed. + +Example: + +#include + + lradc: lradc@1c22800 { + compatible = "allwinner,sun4i-a10-lradc-keys"; + reg = <0x01c22800 0x100>; + interrupts = <31>; + vref-supply = <®_vcc3v0>; + + button@191 { + label = "Volume Up"; + linux,code = ; + channel = <0>; + voltage = <191274>; + }; + + button@392 { + label = "Volume Down"; + linux,code = ; + channel = <0>; + voltage = <392644>; + }; + + button@601 { + label = "Menu"; + linux,code = ; + channel = <0>; + voltage = <601151>; + }; + + button@795 { + label = "Enter"; + linux,code = ; + channel = <0>; + voltage = <795090>; + }; + + button@987 { + label = "Home"; + linux,code = ; + channel = <0>; + voltage = <987387>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/tca8418_keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/tca8418_keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..255185009167819a1a11429dd0b5079f9d189cb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/tca8418_keypad.txt @@ -0,0 +1,10 @@ +This binding is based on the matrix-keymap binding with the following +changes: + +keypad,num-rows and keypad,num-columns are required. + +Required properties: +- compatible: "ti,tca8418" +- reg: the I2C address +- interrupts: IRQ line number, should trigger on falling edge +- linux,keymap: Keys definitions, see keypad-matrix. diff --git a/arch/arm64/boot/dts/vendor/bindings/input/ti,drv260x.txt b/arch/arm64/boot/dts/vendor/bindings/input/ti,drv260x.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c5312eaaa85a7894b04208cc34478c5e28abe00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/ti,drv260x.txt @@ -0,0 +1,50 @@ +* Texas Instruments - drv260x Haptics driver family + +Required properties: + - compatible - One of: + "ti,drv2604" - DRV2604 + "ti,drv2605" - DRV2605 + "ti,drv2605l" - DRV2605L + - reg - I2C slave address + - vbat-supply - Required supply regulator + - mode - Power up mode of the chip (defined in include/dt-bindings/input/ti-drv260x.h) + DRV260X_LRA_MODE - Linear Resonance Actuator mode (Piezoelectric) + DRV260X_LRA_NO_CAL_MODE - This is a LRA Mode but there is no calibration + sequence during init. And the device is configured for real + time playback mode (RTP mode). + DRV260X_ERM_MODE - Eccentric Rotating Mass mode (Rotary vibrator) + - library-sel - These are ROM based waveforms pre-programmed into the IC. + This should be set to set the library to use at power up. + (defined in include/dt-bindings/input/ti-drv260x.h) + DRV260X_LIB_EMPTY - Do not use a pre-programmed library + DRV260X_ERM_LIB_A - Pre-programmed Library + DRV260X_ERM_LIB_B - Pre-programmed Library + DRV260X_ERM_LIB_C - Pre-programmed Library + DRV260X_ERM_LIB_D - Pre-programmed Library + DRV260X_ERM_LIB_E - Pre-programmed Library + DRV260X_ERM_LIB_F - Pre-programmed Library + DRV260X_LIB_LRA - Pre-programmed LRA Library + +Optional properties: + - enable-gpio - gpio pin to enable/disable the device. + - vib-rated-mv - The rated voltage of the actuator in millivolts. + If this is not set then the value will be defaulted to + 3.2 v. + - vib-overdrive-mv - The overdrive voltage of the actuator in millivolts. + If this is not set then the value will be defaulted to + 3.2 v. +Example: + +haptics: haptics@5a { + compatible = "ti,drv2605l"; + reg = <0x5a>; + vbat-supply = <&vbat>; + enable-gpio = <&gpio1 28 GPIO_ACTIVE_HIGH>; + mode = ; + library-sel = ; + vib-rated-mv = <3200>; + vib-overdrive-mv = <3200>; +} + +For more product information please see the link below: +http://www.ti.com/product/drv2605 diff --git a/arch/arm64/boot/dts/vendor/bindings/input/ti,drv2665.txt b/arch/arm64/boot/dts/vendor/bindings/input/ti,drv2665.txt new file mode 100644 index 0000000000000000000000000000000000000000..1ba97ac04305873fab152755d02e48a7c4bd9542 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/ti,drv2665.txt @@ -0,0 +1,17 @@ +* Texas Instruments - drv2665 Haptics driver + +Required properties: + - compatible - "ti,drv2665" - DRV2665 + - reg - I2C slave address + - vbat-supply - Required supply regulator + +Example: + +haptics: haptics@59 { + compatible = "ti,drv2665"; + reg = <0x59>; + vbat-supply = <&vbat>; +}; + +For more product information please see the link below: +http://www.ti.com/product/drv2665 diff --git a/arch/arm64/boot/dts/vendor/bindings/input/ti,drv2667.txt b/arch/arm64/boot/dts/vendor/bindings/input/ti,drv2667.txt new file mode 100644 index 0000000000000000000000000000000000000000..996382cf994a1203073bd70fe9b104977642ea77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/ti,drv2667.txt @@ -0,0 +1,17 @@ +* Texas Instruments - drv2667 Haptics driver + +Required properties: + - compatible - "ti,drv2667" - DRV2667 + - reg - I2C slave address + - vbat-supply - Required supply regulator + +Example: + +haptics: haptics@59 { + compatible = "ti,drv2667"; + reg = <0x59>; + vbat-supply = <&vbat>; +}; + +For more product information please see the link below: +http://www.ti.com/product/drv2667 diff --git a/arch/arm64/boot/dts/vendor/bindings/input/ti,nspire-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/ti,nspire-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..513d94d6e899e03162de22906bcfb8e9216150ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/ti,nspire-keypad.txt @@ -0,0 +1,60 @@ +TI-NSPIRE Keypad + +Required properties: +- compatible: Compatible property value should be "ti,nspire-keypad". + +- reg: Physical base address of the peripheral and length of memory mapped + region. + +- interrupts: The interrupt number for the peripheral. + +- scan-interval: How often to scan in us. Based on a APB speed of 33MHz, the + maximum and minimum delay time is ~2000us and ~500us respectively + +- row-delay: How long to wait before scanning each row. + +- clocks: The clock this peripheral is attached to. + +- linux,keymap: The keymap to use + (see Documentation/devicetree/bindings/input/matrix-keymap.txt) + +Optional properties: +- active-low: Specify that the keypad is active low (i.e. logical low signifies + a key press). + +Example: + +input { + compatible = "ti,nspire-keypad"; + reg = <0x900E0000 0x1000>; + interrupts = <16>; + + scan-interval = <1000>; + row-delay = <200>; + + clocks = <&apb_pclk>; + + linux,keymap = < + 0x0000001c 0x0001001c 0x00040039 + 0x0005002c 0x00060015 0x0007000b + 0x0008000f 0x0100002d 0x01010011 + 0x0102002f 0x01030004 0x01040016 + 0x01050014 0x0106001f 0x01070002 + 0x010a006a 0x02000013 0x02010010 + 0x02020019 0x02030007 0x02040018 + 0x02050031 0x02060032 0x02070005 + 0x02080028 0x0209006c 0x03000026 + 0x03010025 0x03020024 0x0303000a + 0x03040017 0x03050023 0x03060022 + 0x03070008 0x03080035 0x03090069 + 0x04000021 0x04010012 0x04020020 + 0x0404002e 0x04050030 0x0406001e + 0x0407000d 0x04080037 0x04090067 + 0x05010038 0x0502000c 0x0503001b + 0x05040034 0x0505001a 0x05060006 + 0x05080027 0x0509000e 0x050a006f + 0x0600002b 0x0602004e 0x06030068 + 0x06040003 0x0605006d 0x06060009 + 0x06070001 0x0609000f 0x0708002a + 0x0709001d 0x070a0033 >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/ti,palmas-pwrbutton.txt b/arch/arm64/boot/dts/vendor/bindings/input/ti,palmas-pwrbutton.txt new file mode 100644 index 0000000000000000000000000000000000000000..c829e18e1a05cb4372b0b0cec6b3b16d665999cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/ti,palmas-pwrbutton.txt @@ -0,0 +1,35 @@ +Texas Instruments Palmas family power button module + +This module is part of the Palmas family of PMICs. For more details +about the whole chip see: +Documentation/devicetree/bindings/mfd/palmas.txt. + +This module provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be one of the following + - "ti,palmas-pwrbutton": For Palmas compatible power on button +- interrupts: Interrupt number of power button submodule on device. + +Optional Properties: + +- ti,palmas-long-press-seconds: Duration in seconds which the power + button should be kept pressed for Palmas to power off automatically. + NOTE: This depends on OTP support and POWERHOLD signal configuration + on platform. Valid values are 6, 8, 10 and 12. +- ti,palmas-pwron-debounce-milli-seconds: Duration in milliseconds + which the power button should be kept pressed for Palmas to register + a press for debouncing purposes. NOTE: This depends on specific + Palmas variation capability. Valid values are 15, 100, 500 and 1000. + +Example: + +&palmas { + palmas_pwr_button: pwrbutton { + compatible = "ti,palmas-pwrbutton"; + interrupt-parent = <&tps659038>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + ti,palmas-long-press-seconds = <12>; + ti,palmas-pwron-debounce-milli-seconds = <15>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/STMicroelectronics.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/STMicroelectronics.txt new file mode 100644 index 0000000000000000000000000000000000000000..7799392700a773ece4785e910efe5286dfaf5e50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/STMicroelectronics.txt @@ -0,0 +1,54 @@ +STMicroelectronics touch controller + +The STMicroelectronics controller is connected to host processor +via i2c. The controller generates interrupts when the +user touches the panel. The host controller is expected +to read the touch coordinates over i2c and pass the coordinates +to the rest of the system. + +Required properties: + + - compatible : should be "st,fts". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - vdd-supply : Power supply needed to power up the device. + - vcc-supply : Power source required to power up i2c bus. + - st,irq-gpio : irq gpio which is to provide interrupts to host, + same as "interrupts" node. It will also + contain active low or active high information. + - st,reset-gpio : reset gpio to control the reset of chip. + - pinctrl-names : This should be defined if a target uses pinctrl framework. + See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt. + Specify the names of the configs that pinctrl can install in driver. + Following are the pinctrl configs that can be installed: + "pmx_ts_active" : Active configuration of pins, this should specify active + config defined in pin groups of interrupt and reset gpio. + "pmx_ts_suspend" : Disabled configuration of pins, this should specify sleep + config defined in pin groups of interrupt and reset gpio. + "pmx_ts_release" : Release configuration of pins, this should specify + release config defined in pin groups of interrupt and reset gpio. + - st,regulator_avdd : name of Power supply needed to power up the device. + - st,regulator_dvdd : name of Power source required to power up i2c bus. +Optional properties: + + +Example: + i2c@78b9000 { /* BLSP1 QUP5 */ + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2008>; + vdd-supply = <&pm8916_l17>; + vcc-supply = <&pm8916_l6>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&msm_gpio 13 0x00000001>; + st,reset-gpio = <&msm_gpio 12 0x0>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ad7879.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ad7879.txt new file mode 100644 index 0000000000000000000000000000000000000000..cdd743a1f2d5989497fd7ab2e2542d3cbc229fce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ad7879.txt @@ -0,0 +1,71 @@ +* Analog Devices AD7879(-1)/AD7889(-1) touchscreen interface (SPI/I2C) + +Required properties: +- compatible : for SPI slave, use "adi,ad7879" + for I2C slave, use "adi,ad7879-1" +- reg : SPI chipselect/I2C slave address + See spi-bus.txt for more SPI slave properties +- interrupts : touch controller interrupt +- touchscreen-max-pressure : maximum reported pressure +- adi,resistance-plate-x : total resistance of X-plate (for pressure + calculation) +Optional properties: +- touchscreen-swapped-x-y : X and Y axis are swapped (boolean) +- adi,first-conversion-delay : 0-12: In 128us steps (starting with 128us) + 13 : 2.560ms + 14 : 3.584ms + 15 : 4.096ms + This property has to be a '/bits/ 8' value +- adi,acquisition-time : 0: 2us + 1: 4us + 2: 8us + 3: 16us + This property has to be a '/bits/ 8' value +- adi,median-filter-size : 0: disabled + 1: 4 measurements + 2: 8 measurements + 3: 16 measurements + This property has to be a '/bits/ 8' value +- adi,averaging : 0: 2 middle values (1 if median disabled) + 1: 4 middle values + 2: 8 middle values + 3: 16 values + This property has to be a '/bits/ 8' value +- adi,conversion-interval: : 0 : convert one time only + 1-255: 515us + val * 35us (up to 9.440ms) + This property has to be a '/bits/ 8' value +- gpio-controller : Switch AUX/VBAT/GPIO pin to GPIO mode + +Example: + + ad7879@2c { + compatible = "adi,ad7879-1"; + reg = <0x2c>; + interrupt-parent = <&gpio1>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + touchscreen-max-pressure = <4096>; + adi,resistance-plate-x = <120>; + adi,first-conversion-delay = /bits/ 8 <3>; + adi,acquisition-time = /bits/ 8 <1>; + adi,median-filter-size = /bits/ 8 <2>; + adi,averaging = /bits/ 8 <1>; + adi,conversion-interval = /bits/ 8 <255>; + }; + + ad7879@1 { + compatible = "adi,ad7879"; + spi-max-frequency = <5000000>; + reg = <1>; + spi-cpol; + spi-cpha; + gpio-controller; + interrupt-parent = <&gpio1>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + touchscreen-max-pressure = <4096>; + adi,resistance-plate-x = <120>; + adi,first-conversion-delay = /bits/ 8 <3>; + adi,acquisition-time = /bits/ 8 <1>; + adi,median-filter-size = /bits/ 8 <2>; + adi,averaging = /bits/ 8 <1>; + adi,conversion-interval = /bits/ 8 <255>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ads7846.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ads7846.txt new file mode 100644 index 0000000000000000000000000000000000000000..04413da51391f2007f7118ca0d984992eb89b3ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ads7846.txt @@ -0,0 +1,93 @@ +Device tree bindings for TI's ADS7843, ADS7845, ADS7846, ADS7873, TSC2046 +SPI driven touch screen controllers. + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Additional required properties: + + compatible Must be one of the following, depending on the + model: + "ti,tsc2046" + "ti,ads7843" + "ti,ads7845" + "ti,ads7846" + "ti,ads7873" + + interrupts An interrupt node describing the IRQ line the chip's + !PENIRQ pin is connected to. + vcc-supply A regulator node for the supply voltage. + + +Optional properties: + + ti,vref-delay-usecs vref supply delay in usecs, 0 for + external vref (u16). + ti,vref-mv The VREF voltage, in millivolts (u16). + Set to 0 to use internal references + (ADS7846). + ti,keep-vref-on set to keep vref on for differential + measurements as well + ti,swap-xy swap x and y axis + ti,settle-delay-usec Settling time of the analog signals; + a function of Vcc and the capacitance + on the X/Y drivers. If set to non-zero, + two samples are taken with settle_delay + us apart, and the second one is used. + ~150 uSec with 0.01uF caps (u16). + ti,penirq-recheck-delay-usecs If set to non-zero, after samples are + taken this delay is applied and penirq + is rechecked, to help avoid false + events. This value is affected by the + material used to build the touch layer + (u16). + ti,x-plate-ohms Resistance of the X-plate, + in Ohms (u16). + ti,y-plate-ohms Resistance of the Y-plate, + in Ohms (u16). + ti,x-min Minimum value on the X axis (u16). + ti,y-min Minimum value on the Y axis (u16). + ti,x-max Maximum value on the X axis (u16). + ti,y-max Minimum value on the Y axis (u16). + ti,pressure-min Minimum reported pressure value + (threshold) - u16. + ti,pressure-max Maximum reported pressure value (u16). + ti,debounce-max Max number of additional readings per + sample (u16). + ti,debounce-tol Tolerance used for filtering (u16). + ti,debounce-rep Additional consecutive good readings + required after the first two (u16). + ti,pendown-gpio-debounce Platform specific debounce time for the + pendown-gpio (u32). + pendown-gpio GPIO handle describing the pin the !PENIRQ + line is connected to. + wakeup-source use any event on touchscreen as wakeup event. + (Legacy property support: "linux,wakeup") + + +Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC:: + + spi_controller { + tsc2046@0 { + reg = <0>; /* CS0 */ + compatible = "ti,tsc2046"; + interrupt-parent = <&gpio1>; + interrupts = <8 0>; /* BOOT6 / GPIO 8 */ + spi-max-frequency = <1000000>; + pendown-gpio = <&gpio1 8 0>; + vcc-supply = <®_vcc3>; + + ti,x-min = /bits/ 16 <0>; + ti,x-max = /bits/ 16 <8000>; + ti,y-min = /bits/ 16 <0>; + ti,y-max = /bits/ 16 <4800>; + ti,x-plate-ohms = /bits/ 16 <40>; + ti,pressure-max = /bits/ 16 <255>; + + wakeup-source; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ar1021.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ar1021.txt new file mode 100644 index 0000000000000000000000000000000000000000..82019bd6094ee30b0f86726162e7ab950f37f9a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ar1021.txt @@ -0,0 +1,15 @@ +* Microchip AR1020 and AR1021 touchscreen interface (I2C) + +Required properties: +- compatible : "microchip,ar1021-i2c" +- reg : I2C slave address +- interrupts : touch controller interrupt + +Example: + + touchscreen@4d { + compatible = "microchip,ar1021-i2c"; + reg = <0x4d>; + interrupt-parent = <&gpio3>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/auo_pixcir_ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/auo_pixcir_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..f40f21c642b96f90d9447d5984a0119d6e58cba4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/auo_pixcir_ts.txt @@ -0,0 +1,30 @@ +* AUO in-cell touchscreen controller using Pixcir sensors + +Required properties: +- compatible: must be "auo,auo_pixcir_ts" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- gpios: gpios the chip is connected to + first one is the interrupt gpio and second one the reset gpio +- x-size: horizontal resolution of touchscreen +- y-size: vertical resolution of touchscreen + +Example: + + i2c@00000000 { + /* ... */ + + auo_pixcir_ts@5c { + compatible = "auo,auo_pixcir_ts"; + reg = <0x5c>; + interrupts = <2 0>; + + gpios = <&gpf 2 0 2>, /* INT */ + <&gpf 5 1 0>; /* RST */ + + x-size = <800>; + y-size = <600>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/brcm,iproc-touchscreen.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/brcm,iproc-touchscreen.txt new file mode 100644 index 0000000000000000000000000000000000000000..f127a2117072f91c6c91c97f42f39264684c04f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/brcm,iproc-touchscreen.txt @@ -0,0 +1,87 @@ +* Broadcom's IPROC Touchscreen Controller + +Required properties: +- compatible: must be "brcm,iproc-touchscreen" +- ts_syscon: handler of syscon node defining physical base + address of the controller and length of memory mapped region. + If this property is selected please make sure MFD_SYSCON config + is enabled in the defconfig file. +- clocks: The clock provided by the SOC to driver the tsc +- clock-names: name for the clock +- interrupts: The touchscreen controller's interrupt +- address-cells: Specify the number of u32 entries needed in child nodes. + Should set to 1. +- size-cells: Specify number of u32 entries needed to specify child nodes size + in reg property. Should set to 1. + +Optional properties: +- scanning_period: Time between scans. Each step is 1024 us. Valid 1-256. +- debounce_timeout: Each step is 512 us. Valid 0-255 +- settling_timeout: The settling duration (in ms) is the amount of time + the tsc waits to allow the voltage to settle after + turning on the drivers in detection mode. + Valid values: 0-11 + 0 = 0.008 ms + 1 = 0.01 ms + 2 = 0.02 ms + 3 = 0.04 ms + 4 = 0.08 ms + 5 = 0.16 ms + 6 = 0.32 ms + 7 = 0.64 ms + 8 = 1.28 ms + 9 = 2.56 ms + 10 = 5.12 ms + 11 = 10.24 ms +- touch_timeout: The continuous number of scan periods in which touch is + not detected before the controller returns to idle state. + Valid values 0-255. +- average_data: Number of data samples which are averaged before a final + data point is placed into the FIFO + Valid values 0-7 + 0 = 1 sample + 1 = 2 samples + 2 = 4 samples + 3 = 8 samples + 4 = 16 samples + 5 = 32 samples + 6 = 64 samples + 7 = 128 samples +- fifo_threshold: Interrupt is generated whenever the number of fifo + entries exceeds this value + Valid values 0-31 +- touchscreen-size-x: horizontal resolution of touchscreen (in pixels) +- touchscreen-size-y: vertical resolution of touchscreen (in pixels) +- touchscreen-fuzz-x: horizontal noise value of the absolute input + device (in pixels) +- touchscreen-fuzz-y: vertical noise value of the absolute input + device (in pixels) +- touchscreen-inverted-x: X axis is inverted (boolean) +- touchscreen-inverted-y: Y axis is inverted (boolean) + +Example: An example of touchscreen node + + ts_adc_syscon: ts_adc_syscon@180a6000 { + compatible = "brcm,iproc-ts-adc-syscon","syscon"; + reg = <0x180a6000 0xc30>; + }; + + touchscreen: touchscreen@180a6000 { + compatible = "brcm,iproc-touchscreen"; + #address-cells = <1>; + #size-cells = <1>; + ts_syscon = <&ts_adc_syscon>; + clocks = <&adc_clk>; + clock-names = "tsc_clk"; + interrupts = ; + + scanning_period = <5>; + debounce_timeout = <40>; + settling_timeout = <7>; + touch_timeout = <10>; + average_data = <5>; + fifo_threshold = <1>; + /* Touchscreen is rotated 180 degrees. */ + touchscreen-inverted-x; + touchscreen-inverted-y; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/bu21013.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/bu21013.txt new file mode 100644 index 0000000000000000000000000000000000000000..56d835242af2d834f440e3d149011b38e5a7a65f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/bu21013.txt @@ -0,0 +1,28 @@ +* Rohm BU21013 Touch Screen + +Required properties: + - compatible : "rohm,bu21013_tp" + - reg : I2C device address + +Optional properties: + - touch-gpio : GPIO pin registering a touch event + - -supply : Phandle to a regulator supply + - rohm,touch-max-x : Maximum outward permitted limit in the X axis + - rohm,touch-max-y : Maximum outward permitted limit in the Y axis + - rohm,flip-x : Flip touch coordinates on the X axis + - rohm,flip-y : Flip touch coordinates on the Y axis + +Example: + + i2c@80110000 { + bu21013_tp@5c { + compatible = "rohm,bu21013_tp"; + reg = <0x5c>; + touch-gpio = <&gpio2 20 0x4>; + avdd-supply = <&ab8500_ldo_aux1_reg>; + + rohm,touch-max-x = <384>; + rohm,touch-max-y = <704>; + rohm,flip-y; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/bu21029.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/bu21029.txt new file mode 100644 index 0000000000000000000000000000000000000000..8daa0e868a8fa1e59ca99b00882cb3cf852ace34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/bu21029.txt @@ -0,0 +1,35 @@ +* Rohm BU21029 Touch Screen Controller + +Required properties: + - compatible : must be "rohm,bu21029" + - reg : i2c device address of the chip (0x40 or 0x41) + - interrupt-parent : the phandle for the gpio controller + - interrupts : (gpio) interrupt to which the chip is connected + - rohm,x-plate-ohms : x-plate resistance in Ohm + +Optional properties: + - reset-gpios : gpio pin to reset the chip (active low) + - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) + - touchscreen-size-y : vertical resolution of touchscreen (in pixels) + - touchscreen-max-pressure: maximum pressure value + - vdd-supply : power supply for the controller + +Example: + + &i2c1 { + /* ... */ + + bu21029: bu21029@40 { + compatible = "rohm,bu21029"; + reg = <0x40>; + interrupt-parent = <&gpio1>; + interrupts = <4 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; + rohm,x-plate-ohms = <600>; + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-max-pressure = <4095>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/chipone_icn8318.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/chipone_icn8318.txt new file mode 100644 index 0000000000000000000000000000000000000000..38b0603f65f36b4df7ccc4cdca42ed56b00d7b17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/chipone_icn8318.txt @@ -0,0 +1,44 @@ +* ChipOne icn8318 I2C touchscreen controller + +Required properties: + - compatible : "chipone,icn8318" + - reg : I2C slave address of the chip (0x40) + - interrupts : interrupt specification for the icn8318 interrupt + - wake-gpios : GPIO specification for the WAKE input + - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) + - touchscreen-size-y : vertical resolution of touchscreen (in pixels) + +Optional properties: + - pinctrl-names : should be "default" + - pinctrl-0: : a phandle pointing to the pin settings for the + control gpios + - touchscreen-fuzz-x : horizontal noise value of the absolute input + device (in pixels) + - touchscreen-fuzz-y : vertical noise value of the absolute input + device (in pixels) + - touchscreen-inverted-x : X axis is inverted (boolean) + - touchscreen-inverted-y : Y axis is inverted (boolean) + - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) + Swapping is done after inverting the axis + +Example: + +i2c@00000000 { + /* ... */ + + chipone_icn8318@40 { + compatible = "chipone,icn8318"; + reg = <0x40>; + interrupt-parent = <&pio>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* EINT9 (PG9) */ + pinctrl-names = "default"; + pinctrl-0 = <&ts_wake_pin_p66>; + wake-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */ + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; + + /* ... */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/colibri-vf50-ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/colibri-vf50-ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..2e1490a8fe74ed8ca36f3b655d62f4e4ca3458d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/colibri-vf50-ts.txt @@ -0,0 +1,34 @@ +* Toradex Colibri VF50 Touchscreen driver + +Required Properties: +- compatible must be toradex,vf50-touchscreen +- io-channels: adc channels being used by the Colibri VF50 module +- xp-gpios: FET gate driver for input of X+ +- xm-gpios: FET gate driver for input of X- +- yp-gpios: FET gate driver for input of Y+ +- ym-gpios: FET gate driver for input of Y- +- interrupts: pen irq interrupt for touch detection +- pinctrl-names: "idle", "default", "gpios" +- pinctrl-0: pinctrl node for pen/touch detection state pinmux +- pinctrl-1: pinctrl node for X/Y and pressure measurement (ADC) state pinmux +- pinctrl-2: pinctrl node for gpios functioning as FET gate drivers +- vf50-ts-min-pressure: pressure level at which to stop measuring X/Y values + +Example: + + touchctrl: vf50_touchctrl { + compatible = "toradex,vf50-touchscreen"; + io-channels = <&adc1 0>,<&adc0 0>, + <&adc0 1>,<&adc1 2>; + xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>; + yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&gpio0>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "idle","default","gpios"; + pinctrl-0 = <&pinctrl_touchctrl_idle>; + pinctrl-1 = <&pinctrl_touchctrl_default>; + pinctrl-2 = <&pinctrl_touchctrl_gpios>; + vf50-ts-min-pressure = <200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/cyttsp.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/cyttsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ee274aa8b03cf4146a4bb18d8145da69b30a935 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/cyttsp.txt @@ -0,0 +1,93 @@ +* Cypress cyttsp touchscreen controller + +Required properties: + - compatible : must be "cypress,cyttsp-i2c" or "cypress,cyttsp-spi" + - reg : Device I2C address or SPI chip select number + - spi-max-frequency : Maximum SPI clocking speed of the device (for cyttsp-spi) + - interrupts : (gpio) interrupt to which the chip is connected + (see interrupt binding[0]). + - bootloader-key : the 8-byte bootloader key that is required to switch + the chip from bootloader mode (default mode) to + application mode. + This property has to be specified as an array of 8 + '/bits/ 8' values. + +Optional properties: + - reset-gpios : the reset gpio the chip is connected to + (see GPIO binding[1] for more details). + - touchscreen-size-x : horizontal resolution of touchscreen (in pixels) + - touchscreen-size-y : vertical resolution of touchscreen (in pixels) + - touchscreen-fuzz-x : horizontal noise value of the absolute input device + (in pixels) + - touchscreen-fuzz-y : vertical noise value of the absolute input device + (in pixels) + - active-distance : the distance in pixels beyond which a touch must move + before movement is detected and reported by the device. + Valid values: 0-15. + - active-interval-ms : the minimum period in ms between consecutive + scanning/processing cycles when the chip is in active mode. + Valid values: 0-255. + - lowpower-interval-ms : the minimum period in ms between consecutive + scanning/processing cycles when the chip is in low-power mode. + Valid values: 0-2550 + - touch-timeout-ms : minimum time in ms spent in the active power state while no + touches are detected before entering low-power mode. + Valid values: 0-2550 + - use-handshake : enable register-based handshake (boolean). This should + only be used if the chip is configured to use 'blocking + communication with timeout' (in this case the device + generates an interrupt at the end of every + scanning/processing cycle). + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/gpio/gpio.txt + +Example: + &i2c1 { + /* ... */ + cyttsp@a { + compatible = "cypress,cyttsp-i2c"; + reg = <0xa>; + interrupt-parent = <&gpio0>; + interrupts = <28 0>; + reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; + + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-fuzz-x = <4>; + touchscreen-fuzz-y = <7>; + + bootloader-key = /bits/ 8 <0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08>; + active-distance = <8>; + active-interval-ms = <0>; + lowpower-interval-ms = <200>; + touch-timeout-ms = <100>; + }; + + /* ... */ + }; + + &mcspi1 { + /* ... */ + cyttsp@0 { + compatible = "cypress,cyttsp-spi"; + spi-max-frequency = <6000000>; + reg = <0>; + interrupt-parent = <&gpio0>; + interrupts = <28 0>; + reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; + + touchscreen-size-x = <800>; + touchscreen-size-y = <480>; + touchscreen-fuzz-x = <4>; + touchscreen-fuzz-y = <7>; + + bootloader-key = /bits/ 8 <0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08>; + active-distance = <8>; + active-interval-ms = <0>; + lowpower-interval-ms = <200>; + touch-timeout-ms = <100>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/edt-ft5x06.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/edt-ft5x06.txt new file mode 100644 index 0000000000000000000000000000000000000000..da2dc5d6c98b9e952541fd0b531e9e413d5e7b67 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/edt-ft5x06.txt @@ -0,0 +1,63 @@ +FocalTech EDT-FT5x06 Polytouch driver +===================================== + +There are 3 variants of the chip for various touch panel sizes +FT5206GE1 2.8" .. 3.8" +FT5306DE4 4.3" .. 7" +FT5406EE8 7" .. 8.9" +FT5506EEG 7" .. 8.9" + +The software interface is identical for all those chips, so that +currently there is no need for the driver to distinguish between the +different chips. Nevertheless distinct compatible strings are used so +that a distinction can be added if necessary without changing the DT +bindings. + + +Required properties: + - compatible: "edt,edt-ft5206" + or: "edt,edt-ft5306" + or: "edt,edt-ft5406" + or: "edt,edt-ft5506" + or: "focaltech,ft6236" + + - reg: I2C slave address of the chip (0x38) + - interrupts: interrupt specification for the touchdetect + interrupt + +Optional properties: + - reset-gpios: GPIO specification for the RESET input + - wake-gpios: GPIO specification for the WAKE input + + - pinctrl-names: should be "default" + - pinctrl-0: a phandle pointing to the pin settings for the + control gpios + + - threshold: allows setting the "click"-threshold in the range + from 0 to 80. + + - gain: allows setting the sensitivity in the range from 0 to + 31. Note that lower values indicate higher + sensitivity. + + - offset: allows setting the edge compensation in the range from + 0 to 31. + - touchscreen-size-x : See touchscreen.txt + - touchscreen-size-y : See touchscreen.txt + - touchscreen-fuzz-x : See touchscreen.txt + - touchscreen-fuzz-y : See touchscreen.txt + - touchscreen-inverted-x : See touchscreen.txt + - touchscreen-inverted-y : See touchscreen.txt + - touchscreen-swapped-x-y : See touchscreen.txt + +Example: + polytouch: edt-ft5x06@38 { + compatible = "edt,edt-ft5406", "edt,edt-ft5x06"; + reg = <0x38>; + pinctrl-names = "default"; + pinctrl-0 = <&edt_ft5x06_pins>; + interrupt-parent = <&gpio2>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; + wake-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/eeti.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/eeti.txt new file mode 100644 index 0000000000000000000000000000000000000000..32b3712c916ebd7d4c1a3558d7bdc5184ca99d15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/eeti.txt @@ -0,0 +1,30 @@ +Bindings for EETI touchscreen controller + +Required properties: +- compatible: should be "eeti,exc3000-i2c" +- reg: I2C address of the chip. Should be set to <0xa> +- interrupts: interrupt to which the chip is connected + +Optional properties: +- attn-gpios: A handle to a GPIO to check whether interrupt is still + latched. This is necessary for platforms that lack + support for level-triggered IRQs. + +The following optional properties described in touchscreen.txt are +also supported: + +- touchscreen-inverted-x +- touchscreen-inverted-y +- touchscreen-swapped-x-y + +Example: + +i2c-master { + touchscreen@a { + compatible = "eeti,exc3000-i2c"; + reg = <0xa>; + interrupt-parent = <&gpio>; + interrupts = <123 IRQ_TYPE_EDGE_RISING>; + attn-gpios = <&gpio 123 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/egalax-ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/egalax-ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..92fb2620f5e24d13c7b7e44842c80f0eef3e5cff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/egalax-ts.txt @@ -0,0 +1,18 @@ +* EETI eGalax Multiple Touch Controller + +Required properties: +- compatible: must be "eeti,egalax_ts" +- reg: i2c slave address +- interrupts: touch controller interrupt +- wakeup-gpios: the gpio pin to be used for waking up the controller + and also used as irq pin + +Example: + + touchscreen@4 { + compatible = "eeti,egalax_ts"; + reg = <0x04>; + interrupt-parent = <&gpio1>; + interrupts = <9 2>; + wakeup-gpios = <&gpio1 9 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ektf2127.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ektf2127.txt new file mode 100644 index 0000000000000000000000000000000000000000..94c4fc64494072b7160c836b7feb2fdfe49d5160 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ektf2127.txt @@ -0,0 +1,25 @@ +* Elan eKTF2127 I2C touchscreen controller + +Required properties: + - compatible : "elan,ektf2127" + - reg : I2C slave address of the chip (0x40) + - interrupts : interrupt specification for the ektf2127 interrupt + - power-gpios : GPIO specification for the pin connected to the + ektf2127's wake input. This needs to be driven high + to take ektf2127 out of it's low power state + +For additional optional properties see: touchscreen.txt + +Example: + +i2c@00000000 { + ektf2127: touchscreen@15 { + compatible = "elan,ektf2127"; + reg = <0x15>; + interrupt-parent = <&pio>; + interrupts = <6 11 IRQ_TYPE_EDGE_FALLING> + power-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/exc3000.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/exc3000.txt new file mode 100644 index 0000000000000000000000000000000000000000..68291b94fec2d69393c121236bc45137e74c4449 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/exc3000.txt @@ -0,0 +1,26 @@ +* EETI EXC3000 Multiple Touch Controller + +Required properties: +- compatible: must be "eeti,exc3000" +- reg: i2c slave address +- interrupts: touch controller interrupt +- touchscreen-size-x: See touchscreen.txt +- touchscreen-size-y: See touchscreen.txt + +Optional properties: +- touchscreen-inverted-x: See touchscreen.txt +- touchscreen-inverted-y: See touchscreen.txt +- touchscreen-swapped-x-y: See touchscreen.txt + +Example: + + touchscreen@2a { + compatible = "eeti,exc3000"; + reg = <0x2a>; + interrupt-parent = <&gpio1>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/focaltech-ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/focaltech-ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f8537e547902beebf230d052d9b76b82672d46c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/focaltech-ts.txt @@ -0,0 +1,68 @@ +FocalTech touch controller + +The focaltech controller is connected to host processor via i2c. The controller generates interrupts when the user touches the panel. The host controller is expected to read the touch coordinates over i2c and pass the coordinates to the rest of the system. + +Required properties: + - compatible : should be "focaltech,fts_ts" + - reg : i2c slave address of the device, should be <0x38>; For spi interface, means cs number, always be 0 + - interrupt-parent : parent of interrupt + - interrupts : irq gpio, "0x02" stands for that the irq triggered by falling edge. + - focaltech,irq-gpio : irq gpio, same as "interrupts" node. + - focaltech,reset-gpio : reset gpio + - focaltech,num-max-touches : maximum number of touches support + - focaltech,display-coords : display resolution in pixels. A four tuple consisting of minX, minY, maxX and maxY. + +Optional properties: + - focaltech,have-key : specify if virtual keys are supported + - focaltech,key-number : number of keys + - focaltech,keys : virtual key codes mapping to the coords + - focaltech,key-x-coords : constant x coordinates of keys, depends on the x resolution + - focaltech,key-y-coords : constant y coordinates of keys, depends on the y resolution + +Example: +I2C Interface: + i2c@f9927000 { + focaltech@38{ + compatible = "focaltech,fts_ts"; + reg = <0x38>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x02>; + focaltech,reset-gpio = <&msm_gpio 12 0x01>; + focaltech,irq-gpio = <&msm_gpio 13 0x02>; + focaltech,max-touch-number = <10>; + focaltech,display-coords = <0 0 1080 1920>; + + pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + /* + focaltech,have-key; + focaltech,key-number = <3>; + focaltech,keys = <139 102 158>; + focaltech,key-x-coords = <200 600 800>; + focaltech,key-y-coords = <2000 2000 2000>; + */ + }; + }; + +SPI Interface: + spi@78b9000 { + focaltech@0 { + compatible = "focaltech,fts_ts"; + reg = <0x0>; + spi-max-frequency = <6000000>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0x2>; + focaltech,reset-gpio = <&msm_gpio 12 0x01>; + focaltech,irq-gpio = <&msm_gpio 13 0x02>; + focaltech,max-touch-number = <10>; + focaltech,display-coords = <0 0 1080 1920>; + + pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + }; + }; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/fsl-mx25-tcq.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/fsl-mx25-tcq.txt new file mode 100644 index 0000000000000000000000000000000000000000..99d6f9d2533579672eb4e277bcb40d274696831b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/fsl-mx25-tcq.txt @@ -0,0 +1,34 @@ +Freescale mx25 TS conversion queue module + +mx25 touchscreen conversion queue module which controls the ADC unit of the +mx25 for attached touchscreens. + +Required properties: + - compatible: Should be "fsl,imx25-tcq". + - reg: Memory range of the device. + - interrupts: Should be the interrupt number associated with this module within + the tscadc unit (<0>). + - fsl,wires: Should be '<4>' or '<5>' + +Optional properties: + - fsl,pen-debounce-ns: Pen debounce time in nanoseconds. + - fsl,pen-threshold: Pen-down threshold for the touchscreen. This is a value + between 1 and 4096. It is the ratio between the internal reference voltage + and the measured voltage after the plate was precharged. Resistance between + plates and therefore the voltage decreases with pressure so that a smaller + value is equivalent to a higher pressure. + - fsl,settling-time-ns: Settling time in nanoseconds. The settling time is before + the actual touch detection to wait for an even charge distribution in the + plate. + +This device includes two conversion queues which can be added as subnodes. +The first queue is for the touchscreen, the second for general purpose ADC. + +Example: + tsc: tcq@50030400 { + compatible = "fsl,imx25-tcq"; + reg = <0x50030400 0x60>; + interrupt-parent = <&tscadc>; + interrupts = <0>; + fsl,wires = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/goodix.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/goodix.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7e95c52f3c7d33b3e9223bb1abb5c1db3e32502 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/goodix.txt @@ -0,0 +1,43 @@ +Device tree bindings for Goodix GT9xx series touchscreen controller + +Required properties: + + - compatible : Should be "goodix,gt1151" + or "goodix,gt911" + or "goodix,gt9110" + or "goodix,gt912" + or "goodix,gt927" + or "goodix,gt9271" + or "goodix,gt928" + or "goodix,gt967" + - reg : I2C address of the chip. Should be 0x5d or 0x14 + - interrupts : Interrupt to which the chip is connected + +Optional properties: + + - irq-gpios : GPIO pin used for IRQ. The driver uses the + interrupt gpio pin as output to reset the device. + - reset-gpios : GPIO pin used for reset + + - touchscreen-inverted-x : X axis is inverted (boolean) + - touchscreen-inverted-y : Y axis is inverted (boolean) + - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) + (swapping is done after inverting the axis) + +Example: + + i2c@00000000 { + /* ... */ + + gt928@5d { + compatible = "goodix,gt928"; + reg = <0x5d>; + interrupt-parent = <&gpio>; + interrupts = <0 0>; + + irq-gpios = <&gpio1 0 0>; + reset-gpios = <&gpio1 1 0>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/hideep.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/hideep.txt new file mode 100644 index 0000000000000000000000000000000000000000..a47c36190b01120c74c8e30077d5c2e9d25e0485 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/hideep.txt @@ -0,0 +1,41 @@ +* HiDeep Finger and Stylus touchscreen controller + +Required properties: +- compatible : must be "hideep,hideep-ts" +- reg : I2C slave address, (e.g. 0x6C). +- interrupts : Interrupt to which the chip is connected. + +Optional properties: +- vdd-supply : It is the controller supply for controlling + main voltage(3.3V) through the regulator. +- vid-supply : It is the controller supply for controlling + IO voltage(1.8V) through the regulator. +- reset-gpios : Define for reset gpio pin. + It is to use for reset IC. +- touchscreen-size-x : X axis size of touchscreen +- touchscreen-size-y : Y axis size of touchscreen +- linux,keycodes : Specifies an array of numeric keycode values to + be used for reporting button presses. The array can + contain up to 3 entries. + +Example: + +#include "dt-bindings/input/input.h" + +i2c@00000000 { + + /* ... */ + + touchscreen@6c { + compatible = "hideep,hideep-ts"; + reg = <0x6c>; + interrupt-parent = <&gpx1>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + vdd-supply = <&ldo15_reg>; + vid-supply = <&ldo18_reg>; + reset-gpios = <&gpx1 5 0>; + touchscreen-size-x = <1080>; + touchscreen-size-y = <1920>; + linux,keycodes = , , ; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/imx6ul_tsc.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/imx6ul_tsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..16491500442447e4ce61d85a7b4f7dac44c930b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/imx6ul_tsc.txt @@ -0,0 +1,38 @@ +* Freescale i.MX6UL Touch Controller + +Required properties: +- compatible: must be "fsl,imx6ul-tsc". +- reg: this touch controller address and the ADC2 address. +- interrupts: the interrupt of this touch controller and ADC2. +- clocks: the root clock of touch controller and ADC2. +- clock-names; must be "tsc" and "adc". +- xnur-gpio: the X- gpio this controller connect to. + This xnur-gpio returns to low once the finger leave the touch screen (The + last touch event the touch controller capture). + +Optional properties: +- measure-delay-time: the value of measure delay time. + Before X-axis or Y-axis measurement, the screen need some time before + even potential distribution ready. + This value depends on the touch screen. +- pre-charge-time: the touch screen need some time to precharge. + This value depends on the touch screen. +- touchscreen-average-samples: Number of data samples which are averaged for + each read. Valid values are 1, 4, 8, 16 and 32. + +Example: + tsc: tsc@2040000 { + compatible = "fsl,imx6ul-tsc"; + reg = <0x02040000 0x4000>, <0x0219c000 0x4000>; + interrupts = , + ; + clocks = <&clks IMX6UL_CLK_IPG>, + <&clks IMX6UL_CLK_ADC2>; + clock-names = "tsc", "adc"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc>; + xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; + measure-delay-time = <0xfff>; + pre-charge-time = <0xffff>; + touchscreen-average-samples = <32>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/lpc32xx-tsc.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/lpc32xx-tsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..41cbf4b7a670df3dd8ae3bfc5438a5be51683941 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/lpc32xx-tsc.txt @@ -0,0 +1,16 @@ +* NXP LPC32xx SoC Touchscreen Controller (TSC) + +Required properties: +- compatible: must be "nxp,lpc3220-tsc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The TSC/ADC interrupt + +Example: + + tsc@40048000 { + compatible = "nxp,lpc3220-tsc"; + reg = <0x40048000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <39 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/max11801-ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/max11801-ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..05e982c3454eb6aed5ca9fe10ca78e725d47cf9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/max11801-ts.txt @@ -0,0 +1,17 @@ +* MAXI MAX11801 Resistive touch screen controller with i2c interface + +Required properties: +- compatible: must be "maxim,max11801" +- reg: i2c slave address +- interrupts: touch controller interrupt + +Example: + +&i2c1 { + max11801: touchscreen@48 { + compatible = "maxim,max11801"; + reg = <0x48>; + interrupt-parent = <&gpio3>; + interrupts = <31 IRQ_TYPE_EDGE_FALLING>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/melfas_mip4.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/melfas_mip4.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2ab5498e51900e887fab4d9b5239cccccec2ea9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/melfas_mip4.txt @@ -0,0 +1,20 @@ +* MELFAS MIP4 Touchscreen + +Required properties: +- compatible: must be "melfas,mip4_ts" +- reg: I2C slave address of the chip (0x48 or 0x34) +- interrupts: interrupt to which the chip is connected + +Optional properties: +- ce-gpios: GPIO connected to the CE (chip enable) pin of the chip + +Example: + i2c@00000000 { + touchscreen: melfas_mip4@48 { + compatible = "melfas,mip4_ts"; + reg = <0x48>; + interrupt-parent = <&gpio>; + interrupts = <0 IRQ_TYPE_EDGE_FALLING>; + ce-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/mms114.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/mms114.txt new file mode 100644 index 0000000000000000000000000000000000000000..2cd954051d299f1f4adc3e130184d9e04eac4a41 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/mms114.txt @@ -0,0 +1,41 @@ +* MELFAS MMS114/MMS152 touchscreen controller + +Required properties: +- compatible: should be one of: + - "melfas,mms114" + - "melfas,mms152" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- touchscreen-size-x: See [1] +- touchscreen-size-y: See [1] + +Optional properties: +- touchscreen-fuzz-x: See [1] +- touchscreen-fuzz-y: See [1] +- touchscreen-fuzz-pressure: See [1] +- touchscreen-inverted-x: See [1] +- touchscreen-inverted-y: See [1] +- touchscreen-swapped-x-y: See [1] + +[1]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt + +Example: + + i2c@00000000 { + /* ... */ + + touchscreen@48 { + compatible = "melfas,mms114"; + reg = <0x48>; + interrupts = <39 0>; + touchscreen-size-x = <720>; + touchscreen-size-y = <1280>; + touchscreen-fuzz-x = <10>; + touchscreen-fuzz-y = <10>; + touchscreen-fuzz-pressure = <10>; + touchscreen-inverted-x; + touchscreen-inverted-y; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/novatek_nt36xxx.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/novatek_nt36xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..44b963f1a264bd93875d9055207b9f8b2d9fe68f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/novatek_nt36xxx.txt @@ -0,0 +1,32 @@ +* Novatek nt36xxx touch controller + +Please add this description here: The Novatek Touch controller is connected to the +host processor via I2C. The controller generates interrupts when the user touches +the panel. The host controller is expected to read the touch coordinates over I2C and +pass the coordinates to the rest of the system. + +Required properties: + - compatible : should be "novatek,NVT-ts" + - reg : i2c slave address of the device. + - vdd-supply : digital voltage power supply needed to power device. + - avdd-supply : analog voltage power supply needed to power device. + - novatek,reset-gpio : reset gpio. + - novatek,irq-gpio : irq gpio. + +Example: + &i2c_1 { + status = "ok"; + + /* Novatek device tree node */ + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + vdd-supply = <&pm8994_lvs2>; + avdd-supply = <&pm8994_l22>; + + novatek,reset-gpio = <&msm_gpio 102 0x00>; + novatek,irq-gpio = <&msm_gpio 65 0x2001>; + }; + }; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/pixcir_i2c_ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/pixcir_i2c_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..697a3e7831e734e00173ffee012d3bc0f40381da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/pixcir_i2c_ts.txt @@ -0,0 +1,31 @@ +* Pixcir I2C touchscreen controllers + +Required properties: +- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- attb-gpio: GPIO connected to the ATTB line of the chip +- touchscreen-size-x: horizontal resolution of touchscreen (in pixels) +- touchscreen-size-y: vertical resolution of touchscreen (in pixels) + +Optional properties: +- reset-gpios: GPIO connected to the RESET line of the chip +- enable-gpios: GPIO connected to the ENABLE line of the chip +- wake-gpios: GPIO connected to the WAKE line of the chip + +Example: + + i2c@00000000 { + /* ... */ + + pixcir_ts@5c { + compatible = "pixcir,pixcir_ts"; + reg = <0x5c>; + interrupts = <2 0>; + attb-gpio = <&gpf 2 0 2>; + touchscreen-size-x = <800>; + touchscreen-size-y = <600>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/resistive-adc-touch.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/resistive-adc-touch.txt new file mode 100644 index 0000000000000000000000000000000000000000..51456c0e9a27870e7efd4e6938492ccad66cc7ed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/resistive-adc-touch.txt @@ -0,0 +1,30 @@ +Generic resistive touchscreen ADC + +Required properties: + + - compatible: must be "resistive-adc-touch" +The device must be connected to an ADC device that provides channels for +position measurement and optional pressure. +Refer to ../iio/iio-bindings.txt for details + - iio-channels: must have at least two channels connected to an ADC device. +These should correspond to the channels exposed by the ADC device and should +have the right index as the ADC device registers them. These channels +represent the relative position on the "x" and "y" axes. + - iio-channel-names: must have all the channels' names. Mandatory channels +are "x" and "y". + +Optional properties: + - iio-channels: The third channel named "pressure" is optional and can be +used if the ADC device also measures pressure besides position. +If this channel is missing, pressure will be ignored and the touchscreen +will only report position. + - iio-channel-names: optional channel named "pressure". + +Example: + + resistive_touch: resistive_touch { + compatible = "resistive-adc-touch"; + touchscreen-min-pressure = <50000>; + io-channels = <&adc 24>, <&adc 25>, <&adc 26>; + io-channel-names = "x", "y", "pressure"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/samsung,s6sy761.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/samsung,s6sy761.txt new file mode 100644 index 0000000000000000000000000000000000000000..6805d10d226d394a2a1ac35994c2def38acc50b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/samsung,s6sy761.txt @@ -0,0 +1,32 @@ +* Samsung S6SY761 touchscreen controller + +Required properties: +- compatible : must be "samsung,s6sy761" +- reg : I2C slave address, (e.g. 0x48) +- interrupts : interrupt specification +- avdd-supply : analogic power supply +- vdd-supply : power supply + +Optional properties: +- touchscreen-size-x : see touchscreen.txt. This property is embedded in the + device. If defined it forces a different x resolution. +- touchscreen-size-y : see touchscreen.txt. This property is embedded in the + device. If defined it forces a different y resolution. + +Example: + +i2c@00000000 { + + /* ... */ + + touchscreen@48 { + compatible = "samsung,s6sy761"; + reg = <0x48>; + interrupt-parent = <&gpa1>; + interrupts = <1 IRQ_TYPE_NONE>; + avdd-supply = <&ldo30_reg>; + vdd-supply = <&ldo31_reg>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/silead_gsl1680.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/silead_gsl1680.txt new file mode 100644 index 0000000000000000000000000000000000000000..d67e558e5ab5652322b1f2f13123c06ca1b600a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/silead_gsl1680.txt @@ -0,0 +1,44 @@ +* GSL 1680 touchscreen controller + +Required properties: +- compatible : Must be one of the following, depending on the model: + "silead,gsl1680" + "silead,gsl1688" + "silead,gsl3670" + "silead,gsl3675" + "silead,gsl3692" +- reg : I2C slave address of the chip (0x40) +- interrupts : interrupt specification for the gsl1680 interrupt +- power-gpios : Specification for the pin connected to the gsl1680's + shutdown input. This needs to be driven high to take the + gsl1680 out of its low power state +- touchscreen-size-x : See touchscreen.txt +- touchscreen-size-y : See touchscreen.txt + +Optional properties: +- firmware-name : File basename (string) for board specific firmware +- touchscreen-inverted-x : See touchscreen.txt +- touchscreen-inverted-y : See touchscreen.txt +- touchscreen-swapped-x-y : See touchscreen.txt +- silead,max-fingers : maximum number of fingers the touchscreen can detect +- silead,home-button : Boolean, set to true on devices which have a + capacitive home-button build into the touchscreen +- vddio-supply : regulator phandle for controller VDDIO +- avdd-supply : regulator phandle for controller AVDD + +Example: + +i2c@00000000 { + gsl1680: touchscreen@40 { + compatible = "silead,gsl1680"; + reg = <0x40>; + interrupt-parent = <&pio>; + interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>; + power-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; + touchscreen-inverted-x; + touchscreen-swapped-x-y; + silead,max-fingers = <5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sis_i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sis_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f5322e01024040d76ea0c6eb4df8a04ec1cf730 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sis_i2c.txt @@ -0,0 +1,31 @@ +* SiS I2C Multiple Touch Controller + +Required properties: +- compatible: must be "sis,9200-ts" +- reg: i2c slave address +- interrupts: touch controller interrupt (see interrupt + binding [0]) + +Optional properties: +- pinctrl-names: should be "default" (see pinctrl binding [1]). +- pinctrl-0: a phandle pointing to the pin settings for the + device (see pinctrl binding [1]). +- attn-gpios: the gpio pin used as attention line +- reset-gpios: the gpio pin used to reset the controller +- wakeup-source: touchscreen can be used as a wakeup source + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + + sis9255@5c { + compatible = "sis,9200-ts"; + reg = <0x5c>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sis>; + interrupt-parent = <&gpio3>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; + irq-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio2 30 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sitronix-st1232.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sitronix-st1232.txt new file mode 100644 index 0000000000000000000000000000000000000000..64ad48b824a23afcdee391da1c44bd73157f3f58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sitronix-st1232.txt @@ -0,0 +1,24 @@ +* Sitronix st1232 touchscreen controller + +Required properties: +- compatible: must be "sitronix,st1232" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected + +Optional properties: +- gpios: a phandle to the reset GPIO + +Example: + + i2c@00000000 { + /* ... */ + + touchscreen@55 { + compatible = "sitronix,st1232"; + reg = <0x55>; + interrupts = <2 0>; + gpios = <&gpio1 166 0>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/st,stmfts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/st,stmfts.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a5d0cb4a280d83aad04cfcecb15e37f2d2f78fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/st,stmfts.txt @@ -0,0 +1,41 @@ +* ST-Microelectronics FingerTip touchscreen controller + +The ST-Microelectronics FingerTip device provides a basic touchscreen +functionality. Along with it the user can enable the touchkey which can work as +a basic HOME and BACK key for phones. + +The driver supports also hovering as an absolute single touch event with x, y, z +coordinates. + +Required properties: +- compatible : must be "st,stmfts" +- reg : I2C slave address, (e.g. 0x49) +- interrupts : interrupt specification +- avdd-supply : analogic power supply +- vdd-supply : power supply +- touchscreen-size-x : see touchscreen.txt +- touchscreen-size-y : see touchscreen.txt + +Optional properties: +- touch-key-connected : specifies whether the touchkey feature is connected +- ledvdd-supply : power supply to the touch key leds + +Example: + +i2c@00000000 { + + /* ... */ + + touchscreen@49 { + compatible = "st,stmfts"; + reg = <0x49>; + interrupt-parent = <&gpa1>; + interrupts = <1 IRQ_TYPE_NONE>; + touchscreen-size-x = <1599>; + touchscreen-size-y = <2559>; + touch-key-connected; + avdd-supply = <&ldo30_reg>; + vdd-supply = <&ldo31_reg>; + ledvdd-supply = <&ldo33_reg>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/stmpe.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/stmpe.txt new file mode 100644 index 0000000000000000000000000000000000000000..127baa31a77a6201e35d637b17bc59edfe8d0625 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/stmpe.txt @@ -0,0 +1,43 @@ +STMPE Touchscreen +---------------- + +Required properties: + - compatible: "st,stmpe-ts" + +Optional properties: +- st,sample-time: ADC converstion time in number of clock. (0 -> 36 clocks, 1 -> + 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, 4 -> 80 clocks, 5 -> 96 clocks, 6 + -> 144 clocks), recommended is 4. +- st,mod-12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC) +- st,ref-sel: ADC reference source (0 -> internal reference, 1 -> external + reference) +- st,adc-freq: ADC Clock speed (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz) +- st,ave-ctrl: Sample average control (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 + samples, 3 -> 8 samples) +- st,touch-det-delay: Touch detect interrupt delay (0 -> 10 us, 1 -> 50 us, 2 -> + 100 us, 3 -> 500 us, 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms) recommended + is 3 +- st,settling: Panel driver settling time (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 + -> 1 ms, 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms) recommended is 2 +- st,fraction-z: Length of the fractional part in z (fraction-z ([0..7]) = Count of + the fractional part) recommended is 7 +- st,i-drive: current limit value of the touchscreen drivers (0 -> 20 mA typical 35 + mA max, 1 -> 50 mA typical 80 mA max) + +Node name must be stmpe_touchscreen and should be child node of stmpe node to +which it belongs. + +Example: + + stmpe_touchscreen { + compatible = "st,stmpe-ts"; + st,sample-time = <4>; + st,mod-12b = <1>; + st,ref-sel = <0>; + st,adc-freq = <1>; + st,ave-ctrl = <1>; + st,touch-det-delay = <2>; + st,settling = <2>; + st,fraction-z = <7>; + st,i-drive = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sx8654.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sx8654.txt new file mode 100644 index 0000000000000000000000000000000000000000..4886c4aa2906f31e1fd39aad9f89481b6bebd33d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/sx8654.txt @@ -0,0 +1,15 @@ +* Semtech SX8654 I2C Touchscreen Controller + +Required properties: +- compatible: must be "semtech,sx8654" +- reg: i2c slave address +- interrupts: touch controller interrupt + +Example: + + sx8654@48 { + compatible = "semtech,sx8654"; + reg = <0x48>; + interrupt-parent = <&gpio6>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_dsx_i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_dsx_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..131942dd0ae9b4a092ece9bd1a4f558c10bf0945 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_dsx_i2c.txt @@ -0,0 +1,62 @@ +Synaptics DSXV27 touch controller + +Please add this description here: The Synaptics Touch controller is connected to the +host processor via I2C. The controller generates interrupts when the user touches +the panel. The host controller is expected to read the touch coordinates over I2C and +pass the coordinates to the rest of the system. + +Required properties: + + - compatible : should be "synaptics,dsx-i2c". + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - synaptics,irq-gpio : irq gpio. + - synaptics,reset-gpio : reset gpio. + - vdd_supply : digital voltage power supply needed to power device. + - avdd_supply : analog voltage power supply needed to power device. + - synaptics,pwr-reg-name : power reg name of digital voltage. + - synaptics,bus-reg-name : bus reg name of analog voltage. + +Optional property: + - synaptics,ub-i2c-addr : addr of ub-i2c. + - synaptics,irq-on-state : status of irq gpio. + - synaptics,cap-button-codes : virtual key code mappings to be used. + - synaptics,vir-button-codes : virtual key code and the response region on panel. + - synaptics,x-flip : modify orientation of the x axis. + - synaptics,y-flip : modify orientation of the y axis. + - synaptics,reset-delay-ms : reset delay for controller (ms), default 100. + - synaptics,power-delay-ms : power delay for controller (ms), default 100. + - synaptics,reset-active-ms : reset active time for controller (ms), default 20. + - synaptics,max-y-for-2d : maximal y value of the panel. + - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk" + - clocks : Defined if 'clock-names' DT property is defined. These clocks + are associated with the underlying I2C bus. + +Example: + i2c@78b7000 { + status = "ok"; + synaptics@4b { + compatible = "synaptics,dsx-i2c"; + reg = <0x4b>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + vdd_supply = <&pmtitanium_l17>; + avdd_supply = <&pmtitanium_l6>; + synaptics,pwr-reg-name = "vdd"; + synaptics,bus-reg-name = "avdd"; + synaptics,ub-i2c-addr = <0x2c>; + synaptics,irq-gpio = <&tlmm 65 0x2008>; + synaptics,reset-gpio = <&tlmm 99 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-active-ms = <20>; + synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */ + synaptics,cap-button-codes = <139 172 158>; + synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>; + /* Underlying clocks used by secure touch */ + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_i2c.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..11ec15a5603bc221768c9aef83ffe7847edf0391 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_i2c.txt @@ -0,0 +1,71 @@ +Synaptics TCM I2C touchscreen controller + +Required properties: + - compatible: + should be "synaptics,tcm-i2c" + - reg: + i2c slave address of device + - interrupt-parent: + hardware controller of interrupt signal + - interrupts: + gpio number and flags of interrupt signal + - vdd-supply: + digital power source + - avdd-supply: + analog power source + - pinctrl-names: + - pinctrl-0: + - pinctrl-1: + should be defined if using pinctrl framework + "pmx_ts_active": active configuration of pins + "pmx_ts_suspend": disabled configuration of pins + - synaptics,bus-reg-name: + name of digital power source regulator + - synaptics,pwr-reg-name: + name of analog power source regulator + - synaptics,irq-gpio: + interrupt hardware controller, gpio number, and flags + - synaptics,irq-on-state: + active state of interrupt signal + +Optional properties: + - synaptics,power-gpio: + hardware controller and gpio number of power control signal + - synaptics,power-delay-ms: + delay time in ms after powering on device + - synaptics,reset-gpio: + hardware controller and gpio number of reset signal + - synaptics,reset-delay-ms: + delay time in ms after issuing reset to device + - synaptics,reset-on-state: + active state of reset signal + - synaptics,reset-active-ms: + active duration in ms of reset signal + - synaptics,x-flip: + flip x axis + - synaptics,y-flip: + flip y axis + - synaptics,swap-axes: + swap x and y axes + - synaptics,ubl-i2c-addr: + i2c slave address of device in microbootloader mode + +Example: + synaptics_tcm@2c { + compatible = "synaptics,tcm-i2c"; + reg = <0x2c>; + interrupt-parent = <&msm_gpio>; + interrupts = <65 0x2008>; + vdd-supply = <&pm8994_lvs2>; + avdd-supply = <&pm8994_l22>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_suspend>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,irq-gpio = <&msm_gpio 65 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x2c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_spi.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9d5c20d425a2c80bee9e0222d916cbaba73a72b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/synaptics_tcm_spi.txt @@ -0,0 +1,86 @@ +Synaptics TCM SPI touchscreen controller + +Required properties: + - compatible: + should be "synaptics,tcm-spi" + - reg: + should be 0 + - spi-max-frequency: + maximum spi clock frequency + - interrupt-parent: + hardware controller of interrupt signal + - interrupts: + gpio number and flags of interrupt signal + - vdd-supply: + digital power source + - avdd-supply: + analog power source + - pinctrl-names: + - pinctrl-0: + - pinctrl-1: + should be defined if using pinctrl framework + "pmx_ts_active": active configuration of pins + "pmx_ts_suspend": disabled configuration of pins + - synaptics,bus-reg-name: + name of digital power source regulator + - synaptics,pwr-reg-name: + name of analog power source regulator + - synaptics,irq-gpio: + interrupt hardware controller, gpio number, and flags + - synaptics,irq-on-state: + active state of interrupt signal + +Optional properties: + - synaptics,spi-mode: + spi mode + - synaptics,byte-delay-us: + inter-byte delay time in us + - synaptics,block-delay-us: + inter-block delay time in us + - synaptics,power-gpio: + hardware controller and gpio number of power control signal + - synaptics,power-delay-ms: + delay time in ms after powering on device + - synaptics,reset-gpio: + hardware controller and gpio number of reset signal + - synaptics,reset-delay-ms: + delay time in ms after issuing reset to device + - synaptics,reset-on-state: + active state of reset signal + - synaptics,reset-active-ms: + active duration in ms of reset signal + - synaptics,x-flip: + flip x axis + - synaptics,y-flip: + flip y axis + - synaptics,swap-axes: + swap x and y axes + - synaptics,ubl-max-freq: + maximum spi clock frequency for microbootloader mode + - synaptics,ubl-byte-delay-us: + inter-byte delay time in us for microbootloader mode + +Example: + synaptics_tcm@0 { + compatible = "synaptics,tcm-spi"; + reg = <0>; + spi-max-frequency = <10000000>; + interrupt-parent = <&msm_gpio>; + interrupts = <65 0x2008>; + vdd-supply = <&pm8994_lvs2>; + avdd-supply = <&pm8994_l22>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_suspend>; + synaptics,bus-reg-name = "vdd"; + synaptics,pwr-reg-name = "avdd"; + synaptics,irq-gpio = <&msm_gpio 65 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,spi-mode = <3>; + synaptics,byte-delay-us = <0>; + synaptics,block-delay-us = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,ubl-max-freq = <5000000>; + synaptics,ubl-byte-delay-us = <20>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ti-tsc-adc.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ti-tsc-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1163bf9714683bb2122135edcd036cafa526afa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ti-tsc-adc.txt @@ -0,0 +1,83 @@ +* TI - TSC ADC (Touschscreen and analog digital converter) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Required properties: +- child "tsc" + ti,wires: Wires refer to application modes i.e. 4/5/8 wire touchscreen + support on the platform. + ti,x-plate-resistance: X plate resistance + ti,coordinate-readouts: The sequencer supports a total of 16 + programmable steps each step is used to + read a single coordinate. A single + readout is enough but multiple reads can + increase the quality. + A value of 5 means, 5 reads for X, 5 for + Y and 2 for Z (always). This utilises 12 + of the 16 software steps available. The + remaining 4 can be used by the ADC. + ti,wire-config: Different boards could have a different order for + connecting wires on touchscreen. We need to provide an + 8 bit number where in the 1st four bits represent the + analog lines and the next 4 bits represent positive/ + negative terminal on that input line. Notations to + represent the input lines and terminals resoectively + is as follows: + AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. + XP = 0, XN = 1, YP = 2, YN = 3. +- child "adc" + ti,adc-channels: List of analog inputs available for ADC. + AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. + +Optional properties: +- child "tsc" + ti,charge-delay: Length of touch screen charge delay step in terms of + ADC clock cycles. Charge delay value should be large + in order to avoid false pen-up events. This value + effects the overall sampling speed, hence need to be + kept as low as possible, while avoiding false pen-up + event. Start from a lower value, say 0x400, and + increase value until false pen-up events are avoided. + The pen-up detection happens immediately after the + charge step, so this does in fact function as a + hardware knob for adjusting the amount of "settling + time". + +- child "adc" + ti,chan-step-opendelay: List of open delays for each channel of + ADC in the order of ti,adc-channels. The + value corresponds to the number of ADC + clock cycles to wait after applying the + step configuration registers and before + sending the start of ADC conversion. + Maximum value is 0x3FFFF. + ti,chan-step-sampledelay: List of sample delays for each channel + of ADC in the order of ti,adc-channels. + The value corresponds to the number of + ADC clock cycles to sample (to hold + start of conversion high). + Maximum value is 0xFF. + ti,chan-step-avg: Number of averages to be performed for each + channel of ADC. If average is 16 then input + is sampled 16 times and averaged to get more + accurate value. This increases the time taken + by ADC to generate a sample. Valid range is 0 + average to 16 averages. Maximum value is 16. + +Example: + tscadc: tscadc@44e0d000 { + compatible = "ti,am3359-tscadc"; + tsc { + ti,wires = <4>; + ti,x-plate-resistance = <200>; + ti,coordiante-readouts = <5>; + ti,wire-config = <0x00 0x11 0x22 0x33>; + ti,charge-delay = <0x400>; + }; + + adc { + ti,adc-channels = <4 5 6 7>; + ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>; + ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>; + ti,chan-step-avg = <16 2 4 8>; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/touchscreen.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/touchscreen.txt new file mode 100644 index 0000000000000000000000000000000000000000..d092d5d033a0dfdb45f2f4486da1527aa6e03b44 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/touchscreen.txt @@ -0,0 +1,37 @@ +General Touchscreen Properties: + +Optional properties for Touchscreens: + - touchscreen-size-x : horizontal resolution of touchscreen + (in pixels) + - touchscreen-size-y : vertical resolution of touchscreen + (in pixels) + - touchscreen-max-pressure : maximum reported pressure (arbitrary range + dependent on the controller) + - touchscreen-min-pressure : minimum pressure on the touchscreen to be + achieved in order for the touchscreen + driver to report a touch event. + - touchscreen-fuzz-x : horizontal noise value of the absolute input + device (in pixels) + - touchscreen-fuzz-y : vertical noise value of the absolute input + device (in pixels) + - touchscreen-fuzz-pressure : pressure noise value of the absolute input + device (arbitrary range dependent on the + controller) + - touchscreen-average-samples : Number of data samples which are averaged + for each read (valid values dependent on the + controller) + - touchscreen-inverted-x : X axis is inverted (boolean) + - touchscreen-inverted-y : Y axis is inverted (boolean) + - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) + Swapping is done after inverting the axis + - touchscreen-x-mm : horizontal length in mm of the touchscreen + - touchscreen-y-mm : vertical length in mm of the touchscreen + +Deprecated properties for Touchscreens: + - x-size : deprecated name for touchscreen-size-x + - y-size : deprecated name for touchscreen-size-y + - moving-threshold : deprecated name for a combination of + touchscreen-fuzz-x and touchscreen-fuzz-y + - contact-threshold : deprecated name for touchscreen-fuzz-pressure + - x-invert : deprecated name for touchscreen-inverted-x + - y-invert : deprecated name for touchscreen-inverted-y diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ts4800-ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ts4800-ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c1c092c276bc5c602223aa88fa810aa6cbef11b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/ts4800-ts.txt @@ -0,0 +1,11 @@ +* TS-4800 Touchscreen bindings + +Required properties: +- compatible: must be "technologic,ts4800-ts" +- reg: physical base address of the controller and length of memory mapped + region. +- syscon: phandle / integers array that points to the syscon node which + describes the FPGA's syscon registers. + - phandle to FPGA's syscon + - offset to the touchscreen register + - offset to the touchscreen enable bit diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/tsc2005.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/tsc2005.txt new file mode 100644 index 0000000000000000000000000000000000000000..b80c04b0e5c028a45ae85f3ba77230b509318037 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/tsc2005.txt @@ -0,0 +1,64 @@ +* Texas Instruments tsc2004 and tsc2005 touchscreen controllers + +Required properties: + - compatible : "ti,tsc2004" or "ti,tsc2005" + - reg : Device address + - interrupts : IRQ specifier + - spi-max-frequency : Maximum SPI clocking speed of the device + (for tsc2005) + +Optional properties: + - vio-supply : Regulator specifier + - reset-gpios : GPIO specifier for the controller reset line + - ti,x-plate-ohms : integer, resistance of the touchscreen's X plates + in ohm (defaults to 280) + - ti,esd-recovery-timeout-ms : integer, if the touchscreen does not respond after + the configured time (in milli seconds), the driver + will reset it. This is disabled by default. + - properties defined in touchscreen.txt + +Example: + +&i2c3 { + tsc2004@48 { + compatible = "ti,tsc2004"; + reg = <0x48>; + vio-supply = <&vio>; + + reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&gpio1 27 IRQ_TYPE_EDGE_RISING>; + + touchscreen-fuzz-x = <4>; + touchscreen-fuzz-y = <7>; + touchscreen-fuzz-pressure = <2>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; + touchscreen-max-pressure = <2048>; + + ti,x-plate-ohms = <280>; + ti,esd-recovery-timeout-ms = <8000>; + }; +} + +&mcspi1 { + tsc2005@0 { + compatible = "ti,tsc2005"; + spi-max-frequency = <6000000>; + reg = <0>; + + vio-supply = <&vio>; + + reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */ + interrupts-extended = <&gpio4 4 IRQ_TYPE_EDGE_RISING>; /* 100 */ + + touchscreen-fuzz-x = <4>; + touchscreen-fuzz-y = <7>; + touchscreen-fuzz-pressure = <2>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; + touchscreen-max-pressure = <2048>; + + ti,x-plate-ohms = <280>; + ti,esd-recovery-timeout-ms = <8000>; + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/tsc2007.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/tsc2007.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed00f61b8c08b078bc0ee386c9f0bb379eec6ccf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/tsc2007.txt @@ -0,0 +1,39 @@ +* Texas Instruments tsc2007 touchscreen controller + +Required properties: +- compatible: must be "ti,tsc2007". +- reg: I2C address of the chip. +- ti,x-plate-ohms: X-plate resistance in ohms. + +Optional properties: +- gpios: the interrupt gpio the chip is connected to (trough the penirq pin). + The penirq pin goes to low when the panel is touched. + (see GPIO binding[1] for more details). +- interrupts: (gpio) interrupt to which the chip is connected + (see interrupt binding[0]). +- ti,max-rt: maximum pressure. +- ti,fuzzx: specifies the absolute input fuzz x value. + If set, it will permit noise in the data up to +- the value given to the fuzz + parameter, that is used to filter noise from the event stream. +- ti,fuzzy: specifies the absolute input fuzz y value. +- ti,fuzzz: specifies the absolute input fuzz z value. +- ti,poll-period: how much time to wait (in milliseconds) before reading again the + values from the tsc2007. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/gpio/gpio.txt + +Example: + &i2c1 { + /* ... */ + tsc2007@49 { + compatible = "ti,tsc2007"; + reg = <0x49>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 0x8>; + gpios = <&gpio4 0 0>; + ti,x-plate-ohms = <180>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/zet6223.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/zet6223.txt new file mode 100644 index 0000000000000000000000000000000000000000..27d55a506f183df5e2ad6f26c0c4a3c196e02599 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/zet6223.txt @@ -0,0 +1,30 @@ +Zeitec ZET6223 I2C touchscreen controller + +Required properties: +- compatible : "zeitec,zet6223" +- reg : I2C slave address of the chip (0x76) +- interrupts : interrupt specification for the zet6223 interrupt + +Optional properties: + +- vio-supply : Specification for VIO supply (1.8V or 3.3V, + depending on system interface needs). +- vcc-supply : Specification for 3.3V VCC supply. +- touchscreen-size-x : See touchscreen.txt +- touchscreen-size-y : See touchscreen.txt +- touchscreen-inverted-x : See touchscreen.txt +- touchscreen-inverted-y : See touchscreen.txt +- touchscreen-swapped-x-y : See touchscreen.txt + +Example: + +i2c@00000000 { + + zet6223: touchscreen@76 { + compatible = "zeitec,zet6223"; + reg = <0x76>; + interrupt-parent = <&pio>; + interrupts = <6 11 IRQ_TYPE_EDGE_FALLING> + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/zforce_ts.txt b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/zforce_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3c27c4fd9c851fbbb51791084b280a9e343827d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/touchscreen/zforce_ts.txt @@ -0,0 +1,34 @@ +* Neonode infrared touchscreen controller + +Required properties: +- compatible: must be "neonode,zforce" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- reset-gpios: reset gpio the chip is connected to +- x-size: horizontal resolution of touchscreen +- y-size: vertical resolution of touchscreen + +Optional properties: +- irq-gpios : interrupt gpio the chip is connected to +- vdd-supply: Regulator controlling the controller supply + +Example: + + i2c@00000000 { + /* ... */ + + zforce_ts@50 { + compatible = "neonode,zforce"; + reg = <0x50>; + interrupts = <2 0>; + vdd-supply = <®_zforce_vdd>; + + reset-gpios = <&gpio5 9 0>; /* RST */ + irq-gpios = <&gpio5 6 0>; /* IRQ, optional */ + + x-size = <800>; + y-size = <600>; + }; + + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/tps65218-pwrbutton.txt b/arch/arm64/boot/dts/vendor/bindings/input/tps65218-pwrbutton.txt new file mode 100644 index 0000000000000000000000000000000000000000..8682ab6d4a50f86d0d352f6b5b4e8a337c5511c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/tps65218-pwrbutton.txt @@ -0,0 +1,30 @@ +Texas Instruments TPS65217 and TPS65218 power button + +This module is part of the TPS65217/TPS65218. For more details about the whole +TPS65217 chip see Documentation/devicetree/bindings/regulator/tps65217.txt. + +This driver provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be "ti,tps65217-pwrbutton" or "ti,tps65218-pwrbutton" + +Required properties: +- interrupts: should be one of the following + - <2>: For controllers compatible with tps65217 + - <3 IRQ_TYPE_EDGE_BOTH>: For controllers compatible with tps65218 + +Examples: + +&tps { + tps65217-pwrbutton { + compatible = "ti,tps65217-pwrbutton"; + interrupts = <2>; + }; +}; + +&tps { + power-button { + compatible = "ti,tps65218-pwrbutton"; + interrupts = <3 IRQ_TYPE_EDGE_BOTH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/twl4030-keypad.txt b/arch/arm64/boot/dts/vendor/bindings/input/twl4030-keypad.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4be2f76a717bc30e78ca9a821802fc38182e4ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/twl4030-keypad.txt @@ -0,0 +1,27 @@ +* TWL4030's Keypad Controller device tree bindings + +TWL4030's Keypad controller is used to interface a SoC with a matrix-type +keypad device. The keypad controller supports multiple row and column lines. +A key can be placed at each intersection of a unique row and a unique column. +The keypad controller can sense a key-press and key-release and report the +event using a interrupt to the cpu. + +This binding is based on the matrix-keymap binding with the following +changes: + + * keypad,num-rows and keypad,num-columns are required. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "ti,twl4030-keypad": For controllers compatible with twl4030 keypad + controller. +- interrupt: should be one of the following + - <1>: For controllers compatible with twl4030 keypad controller. + +Example: + twl_keypad: keypad { + compatible = "ti,twl4030-keypad"; + interrupts = <1>; + keypad,num-rows = <8>; + keypad,num-columns = <8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/twl4030-pwrbutton.txt b/arch/arm64/boot/dts/vendor/bindings/input/twl4030-pwrbutton.txt new file mode 100644 index 0000000000000000000000000000000000000000..c864a46cddcf65ea573a0e7575ff30c7405b9476 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/twl4030-pwrbutton.txt @@ -0,0 +1,21 @@ +Texas Instruments TWL family (twl4030) pwrbutton module + +This module is part of the TWL4030. For more details about the whole +chip see Documentation/devicetree/bindings/mfd/twl-familly.txt. + +This module provides a simple power button event via an Interrupt. + +Required properties: +- compatible: should be one of the following + - "ti,twl4030-pwrbutton": For controllers compatible with twl4030 +- interrupts: should be one of the following + - <8>: For controllers compatible with twl4030 + +Example: + +&twl { + twl_pwrbutton: pwrbutton { + compatible = "ti,twl4030-pwrbutton"; + interrupts = <8>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/input/zii,rave-sp-pwrbutton.txt b/arch/arm64/boot/dts/vendor/bindings/input/zii,rave-sp-pwrbutton.txt new file mode 100644 index 0000000000000000000000000000000000000000..43ef770dfeb919f451e5d956a29a287a630e5e2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/input/zii,rave-sp-pwrbutton.txt @@ -0,0 +1,22 @@ +Zodiac Inflight Innovations RAVE Supervisory Processor Power Button Bindings + +RAVE SP input device is a "MFD cell" device corresponding to power +button functionality of RAVE Supervisory Processor. It is expected +that its Device Tree node is specified as a child of the node +corresponding to the parent RAVE SP device (as documented in +Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) + +Required properties: + +- compatible: Should be "zii,rave-sp-pwrbutton" + +Example: + + rave-sp { + compatible = "zii,rave-sp-rdu1"; + current-speed = <38400>; + + pwrbutton { + compatible = "zii,rave-sp-pwrbutton"; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/abilis,tb10x-ictl.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/abilis,tb10x-ictl.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a4dd263fc127e40c49448325d45166762f7bbd4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/abilis,tb10x-ictl.txt @@ -0,0 +1,37 @@ +TB10x Top Level Interrupt Controller +==================================== + +The Abilis TB10x SOC contains a custom interrupt controller. It performs +one-to-one mapping of external interrupt sources to CPU interrupts and +provides support for reconfigurable trigger modes. + +Required properties +------------------- + +- compatible: Should be "abilis,tb10x-ictl" +- reg: specifies physical base address and size of register range. +- interrupt-congroller: Identifies the node as an interrupt controller. +- #interrupt cells: Specifies the number of cells used to encode an interrupt + source connected to this controller. The value shall be 2. +- interrupts: Specifies the list of interrupt lines which are handled by + the interrupt controller in the parent controller's notation. Interrupts + are mapped one-to-one to parent interrupts. + +Example +------- + +intc: interrupt-controller { /* Parent interrupt controller */ + interrupt-controller; + #interrupt-cells = <1>; /* For example below */ + /* ... */ +}; + +tb10x_ictl: pic@2000 { /* TB10x interrupt controller */ + compatible = "abilis,tb10x-ictl"; + reg = <0x2000 0x20>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupts = <5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/al,alpine-msix.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/al,alpine-msix.txt new file mode 100644 index 0000000000000000000000000000000000000000..5669764f9cc96d69e7368ce414b55fd351b2374d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/al,alpine-msix.txt @@ -0,0 +1,25 @@ +Alpine MSIX controller + +See arm,gic-v3.txt for SPI and MSI definitions. + +Required properties: + +- compatible: should be "al,alpine-msix" +- reg: physical base address and size of the registers +- interrupt-controller: identifies the node as an interrupt controller +- msi-controller: identifies the node as an PCI Message Signaled Interrupt + controller +- al,msi-base-spi: SPI base of the MSI frame +- al,msi-num-spis: number of SPIs assigned to the MSI frame, relative to SPI0 + +Example: + +msix: msix { + compatible = "al,alpine-msix"; + reg = <0x0 0xfbe00000 0x0 0x100000>; + interrupt-parent = <&gic>; + interrupt-controller; + msi-controller; + al,msi-base-spi = <160>; + al,msi-num-spis = <160>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/allwinner,sun4i-ic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/allwinner,sun4i-ic.txt new file mode 100644 index 0000000000000000000000000000000000000000..b290ca150d30eabb5bd25ac64ff8efb682caab47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/allwinner,sun4i-ic.txt @@ -0,0 +1,18 @@ +Allwinner Sunxi Interrupt Controller + +Required properties: + +- compatible : should be "allwinner,sun4i-a10-ic" +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + +Example: + +intc: interrupt-controller { + compatible = "allwinner,sun4i-a10-ic"; + reg = <0x01c20400 0x400>; + interrupt-controller; + #interrupt-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/allwinner,sunxi-nmi.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/allwinner,sunxi-nmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..24beadf7ba83bea893097352d0f721f91c33f670 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/allwinner,sunxi-nmi.txt @@ -0,0 +1,29 @@ +Allwinner Sunxi NMI Controller +============================== + +Required properties: + +- compatible : should be one of the following: + - "allwinner,sun7i-a20-sc-nmi" + - "allwinner,sun6i-a31-sc-nmi" (deprecated) + - "allwinner,sun6i-a31-r-intc" + - "allwinner,sun9i-a80-nmi" +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 2. The first cell is the IRQ number, the + second cell the trigger type as defined in interrupt.txt in this directory. +- interrupts: Specifies the interrupt line (NMI) which is handled by + the interrupt controller in the parent controller's notation. This value + shall be the NMI. + +Example: + +sc-nmi-intc@1c00030 { + compatible = "allwinner,sun7i-a20-sc-nmi"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x01c00030 0x0c>; + interrupt-parent = <&gic>; + interrupts = <0 0 4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1502a51548bb45b2d7343eedb0822913eb01483c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/amlogic,meson-gpio-intc.txt @@ -0,0 +1,34 @@ +Amlogic meson GPIO interrupt controller + +Meson SoCs contains an interrupt controller which is able to watch the SoC +pads and generate an interrupt on edge or level. The controller is essentially +a 256 pads to 8 GIC interrupt multiplexer, with a filter block to select edge +or level and polarity. It does not expose all 256 mux inputs because the +documentation shows that the upper part is not mapped to any pad. The actual +number of interrupt exposed depends on the SoC. + +Required properties: + +- compatible : must have "amlogic,meson8-gpio-intc" and either + "amlogic,meson8-gpio-intc" for meson8 SoCs (S802) or + "amlogic,meson8b-gpio-intc" for meson8b SoCs (S805) or + "amlogic,meson-gxbb-gpio-intc" for GXBB SoCs (S905) or + "amlogic,meson-gxl-gpio-intc" for GXL SoCs (S905X, S912) + "amlogic,meson-axg-gpio-intc" for AXG SoCs (A113D, A113X) +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 2. +- meson,channel-interrupts: Array with the 8 upstream hwirq numbers. These + are the hwirqs used on the parent interrupt controller. + +Example: + +gpio_interrupt: interrupt-controller@9880 { + compatible = "amlogic,meson-gxbb-gpio-intc", + "amlogic,meson-gpio-intc"; + reg = <0x0 0x9880 0x0 0x10>; + interrupt-controller; + #interrupt-cells = <2>; + meson,channel-interrupts = <64 65 66 67 68 69 70 71>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/andestech,ativic32.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/andestech,ativic32.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4b4193d830ed8123784ee73551d8568cda50c59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/andestech,ativic32.txt @@ -0,0 +1,19 @@ +* Andestech Internal Vector Interrupt Controller + +The Internal Vector Interrupt Controller (IVIC) is a basic interrupt controller +suitable for a simpler SoC platform not requiring a more sophisticated and +bigger External Vector Interrupt Controller. + + +Main node required properties: + +- compatible : should at least contain "andestech,ativic32". +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells: 1 cells and refer to interrupt-controller/interrupts + +Examples: + intc: interrupt-controller { + compatible = "andestech,ativic32"; + #interrupt-cells = <1>; + interrupt-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,gic-v3.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,gic-v3.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ea78c4ef887c9be43a48a287b9cabc77c1a2db4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,gic-v3.txt @@ -0,0 +1,173 @@ +* ARM Generic Interrupt Controller, version 3 + +AArch64 SMP cores are often associated with a GICv3, providing Private +Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI), +Software Generated Interrupts (SGI), and Locality-specific Peripheral +Interrupts (LPI). + +Main node required properties: + +- compatible : should at least contain "arm,gic-v3". +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. Must be a single cell with a value of at least 3. + If the system requires describing PPI affinity, then the value must + be at least 4. + + The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI + interrupts. Other values are reserved for future use. + + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. + 1 = edge triggered + 4 = level triggered + + The 4th cell is a phandle to a node describing a set of CPUs this + interrupt is affine to. The interrupt must be a PPI, and the node + pointed must be a subnode of the "ppi-partitions" subnode. For + interrupt types other than PPI or PPIs that are not partitionned, + this cell must be zero. See the "ppi-partitions" node description + below. + + Cells 5 and beyond are reserved for future use and must have a value + of 0 if present. + +- reg : Specifies base physical address(s) and size of the GIC + registers, in the following order: + - GIC Distributor interface (GICD) + - GIC Redistributors (GICR), one range per redistributor region + - GIC CPU interface (GICC) + - GIC Hypervisor interface (GICH) + - GIC Virtual CPU interface (GICV) + + GICC, GICH and GICV are optional. + +- interrupts : Interrupt source of the VGIC maintenance interrupt. + +Optional + +- redistributor-stride : If using padding pages, specifies the stride + of consecutive redistributors. Must be a multiple of 64kB. + +- #redistributor-regions: The number of independent contiguous regions + occupied by the redistributors. Required if more than one such + region is present. + +- msi-controller: Boolean property. Identifies the node as an MSI + controller. Only present if the Message Based Interrupt + functionnality is being exposed by the HW, and the mbi-ranges + property present. + +- mbi-ranges: A list of pairs , where "intid" is the first + SPI of a range that can be used an MBI, and "span" the size of that + range. Multiple ranges can be provided. Requires "msi-controller" to + be set. + +- mbi-alias: Address property. Base address of an alias of the GICD + region containing only the {SET,CLR}SPI registers to be used if + isolation is required, and if supported by the HW. + +Sub-nodes: + +PPI affinity can be expressed as a single "ppi-partitions" node, +containing a set of sub-nodes, each with the following property: +- affinity: Should be a list of phandles to CPU nodes (as described in +Documentation/devicetree/bindings/arm/cpus.txt). + +GICv3 has one or more Interrupt Translation Services (ITS) that are +used to route Message Signalled Interrupts (MSI) to the CPUs. + +These nodes must have the following properties: +- compatible : Should at least contain "arm,gic-v3-its". +- msi-controller : Boolean property. Identifies the node as an MSI controller +- #msi-cells: Must be <1>. The single msi-cell is the DeviceID of the device + which will generate the MSI. +- reg: Specifies the base physical address and size of the ITS + registers. + +Optional: +- socionext,synquacer-pre-its: (u32, u32) tuple describing the untranslated + address and size of the pre-ITS window. + +The main GIC node must contain the appropriate #address-cells, +#size-cells and ranges properties for the reg property of all ITS +nodes. + +Examples: + + gic: interrupt-controller@2cf00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + interrupt-controller; + reg = <0x0 0x2f000000 0 0x10000>, // GICD + <0x0 0x2f100000 0 0x200000>, // GICR + <0x0 0x2c000000 0 0x2000>, // GICC + <0x0 0x2c010000 0 0x2000>, // GICH + <0x0 0x2c020000 0 0x2000>; // GICV + interrupts = <1 9 4>; + + msi-controller; + mbi-ranges = <256 128>; + + gic-its@2c200000 { + compatible = "arm,gic-v3-its"; + msi-controller; + #msi-cells = <1>; + reg = <0x0 0x2c200000 0 0x20000>; + }; + }; + + gic: interrupt-controller@2c010000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <4>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + interrupt-controller; + redistributor-stride = <0x0 0x40000>; // 256kB stride + #redistributor-regions = <2>; + reg = <0x0 0x2c010000 0 0x10000>, // GICD + <0x0 0x2d000000 0 0x800000>, // GICR 1: CPUs 0-31 + <0x0 0x2e000000 0 0x800000>; // GICR 2: CPUs 32-63 + <0x0 0x2c040000 0 0x2000>, // GICC + <0x0 0x2c060000 0 0x2000>, // GICH + <0x0 0x2c080000 0 0x2000>; // GICV + interrupts = <1 9 4>; + + gic-its@2c200000 { + compatible = "arm,gic-v3-its"; + msi-controller; + #msi-cells = <1>; + reg = <0x0 0x2c200000 0 0x20000>; + }; + + gic-its@2c400000 { + compatible = "arm,gic-v3-its"; + msi-controller; + #msi-cells = <1>; + reg = <0x0 0x2c400000 0 0x20000>; + }; + + ppi-partitions { + part0: interrupt-partition-0 { + affinity = <&cpu0 &cpu2>; + }; + + part1: interrupt-partition-1 { + affinity = <&cpu1 &cpu3>; + }; + }; + }; + + + device@0 { + reg = <0 0 0 4>; + interrupts = <1 1 4 &part0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,gic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,gic.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f324464864658a80a13b1cdab0395282f280b8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,gic.txt @@ -0,0 +1,171 @@ +* ARM Generic Interrupt Controller + +ARM SMP cores are often associated with a GIC, providing per processor +interrupts (PPI), shared processor interrupts (SPI) and software +generated interrupts (SGI). + +Primary GIC is attached directly to the CPU and typically has PPIs and SGIs. +Secondary GICs are cascaded into the upward interrupt controller and do not +have PPIs or SGIs. + +Main node required properties: + +- compatible : should be one of: + "arm,arm1176jzf-devchip-gic" + "arm,arm11mp-gic" + "arm,cortex-a15-gic" + "arm,cortex-a7-gic" + "arm,cortex-a9-gic" + "arm,eb11mp-gic" + "arm,gic-400" + "arm,pl390" + "arm,tc11mp-gic" + "brcm,brahma-b15-gic" + "nvidia,tegra210-agic" + "qcom,msm-8660-qgic" + "qcom,msm-qgic2" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 3. + + The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI + interrupts. + + The 2nd cell contains the interrupt number for the interrupt type. + SPI interrupts are in the range [0-987]. PPI interrupts are in the + range [0-15]. + + The 3rd cell is the flags, encoded as follows: + bits[3:0] trigger type and level flags. + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered (invalid for SPIs) + 4 = active high level-sensitive + 8 = active low level-sensitive (invalid for SPIs). + bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of + the 8 possible cpus attached to the GIC. A bit set to '1' indicated + the interrupt is wired to that CPU. Only valid for PPI interrupts. + Also note that the configurability of PPI interrupts is IMPLEMENTATION + DEFINED and as such not guaranteed to be present (most SoC available + in 2014 seem to ignore the setting of this flag and use the hardware + default value). + +- reg : Specifies base physical address(s) and size of the GIC registers. The + first region is the GIC distributor register base and size. The 2nd region is + the GIC cpu interface register base and size. + +Optional +- interrupts : Interrupt source of the parent interrupt controller on + secondary GICs, or VGIC maintenance interrupt on primary GIC (see + below). + +- cpu-offset : per-cpu offset within the distributor and cpu interface + regions, used when the GIC doesn't have banked registers. The offset is + cpu-offset * cpu-nr. + +- clocks : List of phandle and clock-specific pairs, one for each entry + in clock-names. +- clock-names : List of names for the GIC clock input(s). Valid clock names + depend on the GIC variant: + "ic_clk" (for "arm,arm11mp-gic") + "PERIPHCLKEN" (for "arm,cortex-a15-gic") + "PERIPHCLK", "PERIPHCLKEN" (for "arm,cortex-a9-gic") + "clk" (for "arm,gic-400" and "nvidia,tegra210") + "gclk" (for "arm,pl390") + +- power-domains : A phandle and PM domain specifier as defined by bindings of + the power controller specified by phandle, used when the GIC + is part of a Power or Clock Domain. + + +Example: + + intc: interrupt-controller@fff11000 { + compatible = "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <1>; + interrupt-controller; + reg = <0xfff11000 0x1000>, + <0xfff10100 0x100>; + }; + + +* GIC virtualization extensions (VGIC) + +For ARM cores that support the virtualization extensions, additional +properties must be described (they only exist if the GIC is the +primary interrupt controller). + +Required properties: + +- reg : Additional regions specifying the base physical address and + size of the VGIC registers. The first additional region is the GIC + virtual interface control register base and size. The 2nd additional + region is the GIC virtual cpu interface register base and size. + +- interrupts : VGIC maintenance interrupt. + +Example: + + interrupt-controller@2c001000 { + compatible = "arm,cortex-a15-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x2c001000 0x1000>, + <0x2c002000 0x2000>, + <0x2c004000 0x2000>, + <0x2c006000 0x2000>; + interrupts = <1 9 0xf04>; + }; + + +* GICv2m extension for MSI/MSI-x support (Optional) + +Certain revisions of GIC-400 supports MSI/MSI-x via V2M register frame(s). +This is enabled by specifying v2m sub-node(s). + +Required properties: + +- compatible : The value here should contain "arm,gic-v2m-frame". + +- msi-controller : Identifies the node as an MSI controller. + +- reg : GICv2m MSI interface register base and size + +Optional properties: + +- arm,msi-base-spi : When the MSI_TYPER register contains an incorrect + value, this property should contain the SPI base of + the MSI frame, overriding the HW value. + +- arm,msi-num-spis : When the MSI_TYPER register contains an incorrect + value, this property should contain the number of + SPIs assigned to the frame, overriding the HW value. + +Example: + + interrupt-controller@e1101000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + interrupt-controller; + interrupts = <1 8 0xf04>; + ranges = <0 0 0 0xe1100000 0 0x100000>; + reg = <0x0 0xe1110000 0 0x01000>, + <0x0 0xe112f000 0 0x02000>, + <0x0 0xe1140000 0 0x10000>, + <0x0 0xe1160000 0 0x10000>; + v2m0: v2m@8000 { + compatible = "arm,gic-v2m-frame"; + msi-controller; + reg = <0x0 0x80000 0 0x1000>; + }; + + .... + + v2mN: v2m@9000 { + compatible = "arm,gic-v2m-frame"; + msi-controller; + reg = <0x0 0x90000 0 0x1000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,nvic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,nvic.txt new file mode 100644 index 0000000000000000000000000000000000000000..386ab37a383fa229de70a31b4398f408fb791edc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,nvic.txt @@ -0,0 +1,36 @@ +* ARM Nested Vector Interrupt Controller (NVIC) + +The NVIC provides an interrupt controller that is tightly coupled to +Cortex-M based processor cores. The NVIC implemented on different SoCs +vary in the number of interrupts and priority bits per interrupt. + +Main node required properties: + +- compatible : should be one of: + "arm,v6m-nvic" + "arm,v7m-nvic" + "arm,v8m-nvic" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 2. + + The 1st cell contains the interrupt number for the interrupt type. + + The 2nd cell is the priority of the interrupt. + +- reg : Specifies base physical address(s) and size of the NVIC registers. + This is at a fixed address (0xe000e100) and size (0xc00). + +- arm,num-irq-priority-bits: The number of priority bits implemented by the + given SoC + +Example: + + intc: interrupt-controller@e000e100 { + compatible = "arm,v7m-nvic"; + #interrupt-cells = <2>; + #address-cells = <1>; + interrupt-controller; + reg = <0xe000e100 0xc00>; + arm,num-irq-priority-bits = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,versatile-fpga-irq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,versatile-fpga-irq.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a1d16bdf834dd9aa01b5843c48add374e155668 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,versatile-fpga-irq.txt @@ -0,0 +1,36 @@ +* ARM Versatile FPGA interrupt controller + +One or more FPGA IRQ controllers can be synthesized in an ARM reference board +such as the Integrator or Versatile family. The output of these different +controllers are OR:ed together and fed to the CPU tile's IRQ input. Each +instance can handle up to 32 interrupts. + +Required properties: +- compatible: "arm,versatile-fpga-irq" or "oxsemi,ox810se-rps-irq" +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: The number of cells to define the interrupts. Must be 1 + as the FPGA IRQ controller has no configuration options for interrupt + sources. The cell is a u32 and defines the interrupt number. +- reg: The register bank for the FPGA interrupt controller. +- clear-mask: a u32 number representing the mask written to clear all IRQs + on the controller at boot for example. +- valid-mask: a u32 number representing a bit mask determining which of + the interrupts are valid. Unconnected/unused lines are set to 0, and + the system till not make it possible for devices to request these + interrupts. + +Example: + +pic: pic@14000000 { + compatible = "arm,versatile-fpga-irq"; + #interrupt-cells = <1>; + interrupt-controller; + reg = <0x14000000 0x100>; + clear-mask = <0xffffffff>; + valid-mask = <0x003fffff>; +}; + +Optional properties: +- interrupts: if the FPGA IRQ controller is cascaded, i.e. if its IRQ + output is simply connected to the input of another IRQ controller, + then the parent IRQ shall be specified in this property. diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,vic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,vic.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd527216c5fbddfce790fe9bf4a2342f56e025f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/arm,vic.txt @@ -0,0 +1,41 @@ +* ARM Vectored Interrupt Controller + +One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM +system for interrupt routing. For multiple controllers they can either be +nested or have the outputs wire-OR'd together. + +Required properties: + +- compatible : should be one of + "arm,pl190-vic" + "arm,pl192-vic" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : The number of cells to define the interrupts. Must be 1 as + the VIC has no configuration options for interrupt sources. The cell is a u32 + and defines the interrupt number. +- reg : The register bank for the VIC. + +Optional properties: + +- interrupts : Interrupt source for parent controllers if the VIC is nested. +- valid-mask : A one cell big bit mask of valid interrupt sources. Each bit + represents single interrupt source, starting from source 0 at LSb and ending + at source 31 at MSb. A bit that is set means that the source is wired and + clear means otherwise. If unspecified, defaults to all valid. +- valid-wakeup-mask : A one cell big bit mask of interrupt sources that can be + configured as wake up source for the system. Order of bits is the same as for + valid-mask property. A set bit means that this interrupt source can be + configured as a wake up source for the system. If unspecied, defaults to all + interrupt sources configurable as wake up sources. + +Example: + + vic0: interrupt-controller@60000 { + compatible = "arm,pl192-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x60000 0x1000>; + + valid-mask = <0xffffff7f>; + valid-wakeup-mask = <0x0000ff7f>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt new file mode 100644 index 0000000000000000000000000000000000000000..033cc82e5684024889a5aba38be693eca9248a5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/aspeed,ast2400-i2c-ic.txt @@ -0,0 +1,25 @@ +Device tree configuration for the I2C Interrupt Controller on the AST24XX and +AST25XX SoCs. + +Required Properties: +- #address-cells : should be 1 +- #size-cells : should be 1 +- #interrupt-cells : should be 1 +- compatible : should be "aspeed,ast2400-i2c-ic" + or "aspeed,ast2500-i2c-ic" +- reg : address start and range of controller +- interrupts : interrupt number +- interrupt-controller : denotes that the controller receives and fires + new interrupts for child busses + +Example: + +i2c_ic: interrupt-controller@0 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <1>; + compatible = "aspeed,ast2400-i2c-ic"; + reg = <0x0 0x40>; + interrupts = <12>; + interrupt-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/aspeed,ast2400-vic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/aspeed,ast2400-vic.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3fea0758d2535cb0598337941a7a995a275651f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/aspeed,ast2400-vic.txt @@ -0,0 +1,23 @@ +Aspeed Vectored Interrupt Controller + +These bindings are for the Aspeed interrupt controller. The AST2400 and +AST2500 SoC families include a legacy register layout before a re-designed +layout, but the bindings do not prescribe the use of one or the other. + +Required properties: + +- compatible : "aspeed,ast2400-vic" + "aspeed,ast2500-vic" + +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + +Example: + + vic: interrupt-controller@1e6c0080 { + compatible = "aspeed,ast2400-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1e6c0080 0x80>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/atmel,aic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/atmel,aic.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4c5d34c41115878c335503185774c4c1b580aaf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/atmel,aic.txt @@ -0,0 +1,40 @@ +* Advanced Interrupt Controller (AIC) + +Required properties: +- compatible: Should be "atmel,-aic" + can be "at91rm9200", "sama5d2", "sama5d3" or "sama5d4" +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: The number of cells to define the interrupts. It should be 3. + The first cell is the IRQ number (aka "Peripheral IDentifier" on datasheet). + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. + Default flag for internal sources should be set to 4 (active high). + The third cell is used to specify the irq priority from 0 (lowest) to 7 + (highest). +- reg: Should contain AIC registers location and length +- atmel,external-irqs: u32 array of external irqs. + +Examples: + /* + * AIC + */ + aic: interrupt-controller@fffff000 { + compatible = "atmel,at91rm9200-aic"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0xfffff000 0x200>; + }; + + /* + * An interrupt generating device that is wired to an AIC. + */ + dma: dma-controller@ffffec00 { + compatible = "atmel,at91sam9g45-dma"; + reg = <0xffffec00 0x200>; + interrupts = <21 4 5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f1af5a1c12e77e677a11c1262ec53907ef81f35 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt @@ -0,0 +1,131 @@ +BCM2835 Top-Level ("ARMCTRL") Interrupt Controller + +The BCM2835 contains a custom top-level interrupt controller, which supports +72 interrupt sources using a 2-level register scheme. The interrupt +controller, or the HW block containing it, is referred to occasionally +as "armctrl" in the SoC documentation, hence naming of this binding. + +The BCM2836 contains the same interrupt controller with the same +interrupts, but the per-CPU interrupt controller is the root, and an +interrupt there indicates that the ARMCTRL has an interrupt to handle. + +Required properties: + +- compatible : should be "brcm,bcm2835-armctrl-ic" or + "brcm,bcm2836-armctrl-ic" +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 2. + + The 1st cell is the interrupt bank; 0 for interrupts in the "IRQ basic + pending" register, or 1/2 respectively for interrupts in the "IRQ pending + 1/2" register. + + The 2nd cell contains the interrupt number within the bank. Valid values + are 0..7 for bank 0, and 0..31 for bank 1. + +Additional required properties for brcm,bcm2836-armctrl-ic: +- interrupts : Specifies the interrupt on the parent for this interrupt + controller to handle. + +The interrupt sources are as follows: + +Bank 0: +0: ARM_TIMER +1: ARM_MAILBOX +2: ARM_DOORBELL_0 +3: ARM_DOORBELL_1 +4: VPU0_HALTED +5: VPU1_HALTED +6: ILLEGAL_TYPE0 +7: ILLEGAL_TYPE1 + +Bank 1: +0: TIMER0 +1: TIMER1 +2: TIMER2 +3: TIMER3 +4: CODEC0 +5: CODEC1 +6: CODEC2 +7: VC_JPEG +8: ISP +9: VC_USB +10: VC_3D +11: TRANSPOSER +12: MULTICORESYNC0 +13: MULTICORESYNC1 +14: MULTICORESYNC2 +15: MULTICORESYNC3 +16: DMA0 +17: DMA1 +18: VC_DMA2 +19: VC_DMA3 +20: DMA4 +21: DMA5 +22: DMA6 +23: DMA7 +24: DMA8 +25: DMA9 +26: DMA10 +27: DMA11-14 - shared interrupt for DMA 11 to 14 +28: DMAALL - triggers on all dma interrupts (including chanel 15) +29: AUX +30: ARM +31: VPUDMA + +Bank 2: +0: HOSTPORT +1: VIDEOSCALER +2: CCP2TX +3: SDC +4: DSI0 +5: AVE +6: CAM0 +7: CAM1 +8: HDMI0 +9: HDMI1 +10: PIXELVALVE1 +11: I2CSPISLV +12: DSI1 +13: PWA0 +14: PWA1 +15: CPR +16: SMI +17: GPIO0 +18: GPIO1 +19: GPIO2 +20: GPIO3 +21: VC_I2C +22: VC_SPI +23: VC_I2SPCM +24: VC_SDIO +25: VC_UART +26: SLIMBUS +27: VEC +28: CPG +29: RNG +30: VC_ARASANSDIO +31: AVSPMON + +Example: + +/* BCM2835, first level */ +intc: interrupt-controller { + compatible = "brcm,bcm2835-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +/* BCM2836, second level */ +intc: interrupt-controller { + compatible = "brcm,bcm2836-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&local_intc>; + interrupts = <8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ced1696c325bbc07525869845f41be37d043698 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt @@ -0,0 +1,37 @@ +BCM2836 per-CPU interrupt controller + +The BCM2836 has a per-cpu interrupt controller for the timer, PMU +events, and SMP IPIs. One of the CPUs may receive interrupts for the +peripheral (GPU) events, which chain to the BCM2835-style interrupt +controller. + +Required properties: + +- compatible: Should be "brcm,bcm2836-l1-intc" +- reg: Specifies base physical address and size of the + registers +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 2 + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +The interrupt sources are as follows: + +0: CNTPSIRQ +1: CNTPNSIRQ +2: CNTHPIRQ +3: CNTVIRQ +8: GPU_FAST +9: PMU_FAST + +Example: + +local_intc: local_intc { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&local_intc>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..37aea40d5430e87a74383343e91bed72c0304399 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm3380-l2-intc.txt @@ -0,0 +1,39 @@ +Broadcom BCM3380-style Level 1 / Level 2 interrupt controller + +This interrupt controller shows up in various forms on many BCM338x/BCM63xx +chipsets. It has the following properties: + +- outputs a single interrupt signal to its interrupt controller parent + +- contains one or more enable/status word pairs, which often appear at + different offsets in different blocks + +- no atomic set/clear operations + +Required properties: + +- compatible: should be "brcm,bcm3380-l2-intc" +- reg: specifies one or more enable/status pairs, in the following format: + ... +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupts: specifies the interrupt line in the interrupt-parent controller + node, valid values depend on the type of parent interrupt controller + +Optional properties: + +- brcm,irq-can-wake: if present, this means the L2 controller can be used as a + wakeup source for system suspend/resume. + +Example: + +irq0_intc: interrupt-controller@10000020 { + compatible = "brcm,bcm3380-l2-intc"; + reg = <0x10000024 0x4 0x1000002c 0x4>, + <0x10000020 0x4 0x10000028 0x4>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&cpu_intc>; + interrupts = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..2bc19b1ac877ba1c15d08aa4d5d12076985d88ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm6345-l1-intc.txt @@ -0,0 +1,55 @@ +Broadcom BCM6345-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. + +Key elements of the hardware design include: + +- 32, 64 or 128 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Contains one or more enable/status word pairs per CPU + +- No atomic set/clear operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-4 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm-l1-intc", "brcm,bcm6345-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +The driver operates in native CPU endian by default, there is no support for +specifying an alternative endianness. + +Example: + +periph_intc: interrupt-controller@10000000 { + compatible = "brcm,bcm63168-l1-intc", "brcm,bcm6345-l1-intc"; + reg = <0x10000020 0x20>, + <0x10000040 0x20>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..2117d4ac1ae5cbe0a2005c72513c2ec7f80cc305 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm7038-l1-intc.txt @@ -0,0 +1,50 @@ +Broadcom BCM7038-style Level 1 interrupt controller + +This block is a first level interrupt controller that is typically connected +directly to one of the HW INT lines on each CPU. Every BCM7xxx set-top chip +since BCM7038 has contained this hardware. + +Key elements of the hardware design include: + +- 64, 96, 128, or 160 incoming level IRQ lines + +- Most onchip peripherals are wired directly to an L1 input + +- A separate instance of the register set for each CPU, allowing individual + peripheral IRQs to be routed to any CPU + +- Atomic mask/unmask operations + +- No polarity/level/edge settings + +- No FIFO or priority encoder logic; software is expected to read all + 2-5 status words to determine which IRQs are pending + +Required properties: + +- compatible: should be "brcm,bcm7038-l1-intc" +- reg: specifies the base physical address and size of the registers; + the number of supported IRQs is inferred from the size argument +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node; valid values depend on the type of parent interrupt controller + +If multiple reg ranges and interrupt-parent entries are present on an SMP +system, the driver will allow IRQ SMP affinity to be set up through the +/proc/irq/ interface. In the simplest possible configuration, only one +reg range and one interrupt-parent is needed. + +Example: + +periph_intc: periph_intc@1041a400 { + compatible = "brcm,bcm7038-l1-intc"; + reg = <0x1041a400 0x30 0x1041a600 0x30>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu_intc>; + interrupts = <2>, <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..addd86b6ca2f2af1bb5e1d1d4df246955d9d0fae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt @@ -0,0 +1,88 @@ +Broadcom BCM7120-style Level 2 interrupt controller + +This interrupt controller hardware is a second level interrupt controller that +is hooked to a parent interrupt controller: e.g: ARM GIC for ARM-based +platforms. It can be found on BCM7xxx products starting with BCM7120. + +Such an interrupt controller has the following hardware design: + +- outputs multiple interrupts signals towards its interrupt controller parent + +- controls how some of the interrupts will be flowing, whether they will + directly output an interrupt signal towards the interrupt controller parent, + or if they will output an interrupt signal at this 2nd level interrupt + controller, in particular for UARTs + +- has one 32-bit enable word and one 32-bit status word + +- no atomic set/clear operations + +- not all bits within the interrupt controller actually map to an interrupt + +The typical hardware layout for this controller is represented below: + +2nd level interrupt line Outputs for the parent controller (e.g: ARM GIC) + +0 -----[ MUX ] ------------|==========> GIC interrupt 75 + \-----------\ + | +1 -----[ MUX ] --------)---|==========> GIC interrupt 76 + \------------| + | +2 -----[ MUX ] --------)---|==========> GIC interrupt 77 + \------------| + | +3 ---------------------| +4 ---------------------| +5 ---------------------| +7 ---------------------|---|===========> GIC interrupt 66 +9 ---------------------| +10 --------------------| +11 --------------------/ + +6 ------------------------\ + |===========> GIC interrupt 64 +8 ------------------------/ + +12 ........................ X +13 ........................ X (not connected) +.. +31 ........................ X + +Required properties: + +- compatible: should be "brcm,bcm7120-l2-intc" +- reg: specifies the base physical address and size of the registers +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupts: specifies the interrupt line(s) in the interrupt-parent controller + node, valid values depend on the type of parent interrupt controller +- brcm,int-map-mask: 32-bits bit mask describing how many and which interrupts + are wired to this 2nd level interrupt controller, and how they match their + respective interrupt parents. Should match exactly the number of interrupts + specified in the 'interrupts' property. + +Optional properties: + +- brcm,irq-can-wake: if present, this means the L2 controller can be used as a + wakeup source for system suspend/resume. + +- brcm,int-fwd-mask: if present, a bit mask to configure the interrupts which + have a mux gate, typically UARTs. Setting these bits will make their + respective interrupt outputs bypass this 2nd level interrupt controller + completely; it is completely transparent for the interrupt controller + parent. This should have one 32-bit word per enable/status pair. + +Example: + +irq0_intc: interrupt-controller@f0406800 { + compatible = "brcm,bcm7120-l2-intc"; + interrupt-parent = <&intc>; + #interrupt-cells = <1>; + reg = <0xf0406800 0x8>; + interrupt-controller; + interrupts = <0x0 0x42 0x0>, <0x0 0x40 0x0>; + brcm,int-map-mask = <0xeb8>, <0x140>; + brcm,int-fwd-mask = <0x7>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,l2-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,l2-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d514ec060a4a7199569d5b9141bd5324aab2e2f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/brcm,l2-intc.txt @@ -0,0 +1,28 @@ +Broadcom Generic Level 2 Interrupt Controller + +Required properties: + +- compatible: should be "brcm,l2-intc" for latched interrupt controllers + should be "brcm,bcm7271-l2-intc" for level interrupt controllers +- reg: specifies the base physical address and size of the registers +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. Should be 1. +- interrupts: specifies the interrupt line in the interrupt-parent irq space + to be used for cascading + +Optional properties: + +- brcm,irq-can-wake: If present, this means the L2 controller can be used as a + wakeup source for system suspend/resume. + +Example: + +hif_intr2_intc: interrupt-controller@f0441000 { + compatible = "brcm,l2-intc"; + reg = <0xf0441000 0x30>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&intc>; + interrupts = <0x0 0x20 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cdns,xtensa-mx.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cdns,xtensa-mx.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4de980e55fa61392fa8293f52a966ca362aaa92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cdns,xtensa-mx.txt @@ -0,0 +1,18 @@ +* Xtensa Interrupt Distributor and Programmable Interrupt Controller (MX) + +Required properties: +- compatible: Should be "cdns,xtensa-mx". + +Remaining properties have exact same meaning as in Xtensa PIC +(see cdns,xtensa-pic.txt). + +Examples: + pic: pic { + compatible = "cdns,xtensa-mx"; + /* one cell: internal irq number, + * two cells: second cell == 0: internal irq number + * second cell == 1: external irq number + */ + #interrupt-cells = <2>; + interrupt-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cdns,xtensa-pic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cdns,xtensa-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..026ef4cfc1d52f895a2d8d0736b8f110b56a314b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cdns,xtensa-pic.txt @@ -0,0 +1,25 @@ +* Xtensa built-in Programmable Interrupt Controller (PIC) + +Required properties: +- compatible: Should be "cdns,xtensa-pic". +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: The number of cells to define the interrupts. + It may be either 1 or 2. + When it's 1, the first cell is the internal IRQ number. + When it's 2, the first cell is the IRQ number, and the second cell + specifies whether it's internal (0) or external (1). + Periferals are usually connected to a fixed external IRQ, but for different + core variants it may be mapped to different internal IRQ. + IRQ sensitivity and priority are fixed for each core variant and may not be + changed at runtime. + +Examples: + pic: pic { + compatible = "cdns,xtensa-pic"; + /* one cell: internal irq number, + * two cells: second cell == 0: internal irq number + * second cell == 1: external irq number + */ + #interrupt-cells = <2>; + interrupt-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cirrus,clps711x-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cirrus,clps711x-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..969b4582ec6048383571836992ef6c02979bab68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/cirrus,clps711x-intc.txt @@ -0,0 +1,41 @@ +Cirrus Logic CLPS711X Interrupt Controller + +Required properties: + +- compatible: Should be "cirrus,ep7209-intc". +- reg: Specifies base physical address of the registers set. +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + +The interrupt sources are as follows: +ID Name Description +--------------------------- +1: BLINT Battery low (FIQ) +3: MCINT Media changed (FIQ) +4: CSINT CODEC sound +5: EINT1 External 1 +6: EINT2 External 2 +7: EINT3 External 3 +8: TC1OI TC1 under flow +9: TC2OI TC2 under flow +10: RTCMI RTC compare match +11: TINT 64Hz tick +12: UTXINT1 UART1 transmit FIFO half empty +13: URXINT1 UART1 receive FIFO half full +14: UMSINT UART1 modem status changed +15: SSEOTI SSI1 end of transfer +16: KBDINT Keyboard +17: SS2RX SSI2 receive FIFO half or greater full +18: SS2TX SSI2 transmit FIFO less than half empty +28: UTXINT2 UART2 transmit FIFO half empty +29: URXINT2 UART2 receive FIFO half full +32: DAIINT DAI interface (FIQ) + +Example: + intc: interrupt-controller { + compatible = "cirrus,ep7312-intc", "cirrus,ep7209-intc"; + reg = <0x80000000 0x4000>; + interrupt-controller; + #interrupt-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/digicolor-ic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/digicolor-ic.txt new file mode 100644 index 0000000000000000000000000000000000000000..42d41ec84c7bdae3898b2ee0cc00922e1fde9b36 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/digicolor-ic.txt @@ -0,0 +1,21 @@ +Conexant Digicolor Interrupt Controller + +Required properties: + +- compatible : should be "cnxt,cx92755-ic" +- reg : Specifies base physical address and size of the interrupt controller + registers (IC) area +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. +- syscon: A phandle to the syscon node describing UC registers + +Example: + + intc: interrupt-controller@f0000040 { + compatible = "cnxt,cx92755-ic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xf0000040 0x40>; + syscon = <&uc_regs>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ezchip,nps400-ic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ezchip,nps400-ic.txt new file mode 100644 index 0000000000000000000000000000000000000000..888b2b9f706483af864ef3ab6d556419ade3026b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ezchip,nps400-ic.txt @@ -0,0 +1,17 @@ +EZchip NPS Interrupt Controller + +Required properties: + +- compatible : should be "ezchip,nps400-ic" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + + +Example: + +intc: interrupt-controller { + compatible = "ezchip,nps400-ic"; + interrupt-controller; + #interrupt-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/faraday,ftintc010.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/faraday,ftintc010.txt new file mode 100644 index 0000000000000000000000000000000000000000..24428d47f4872c2e8114336d3559c92636b4af56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/faraday,ftintc010.txt @@ -0,0 +1,25 @@ +* Faraday Technologt FTINTC010 interrupt controller + +This interrupt controller is a stock IP block from Faraday Technology found +in the Gemini SoCs and other designs. + +Required properties: +- compatible: must be one of + "faraday,ftintc010" + "cortina,gemini-interrupt-controller" (deprecated) +- reg: The register bank for the interrupt controller. +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: The number of cells to define the interrupts. + Must be 2 as the controller can specify level or rising edge + IRQs. The bindings follows the standard binding for controllers + with two cells specified in + interrupt-controller/interrupts.txt + +Example: + +interrupt-controller@48000000 { + compatible = "faraday,ftintc010" + reg = <0x48000000 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/fsl,ls-scfg-msi.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/fsl,ls-scfg-msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..454ce04d678743fd76e1239df5d01fb651aa44ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/fsl,ls-scfg-msi.txt @@ -0,0 +1,30 @@ +* Freescale Layerscape SCFG PCIe MSI controller + +Required properties: + +- compatible: should be "fsl,-msi" to identify + Layerscape PCIe MSI controller block such as: + "fsl,ls1021a-msi" + "fsl,ls1043a-msi" + "fsl,ls1046a-msi" + "fsl,ls1043a-v1.1-msi" + "fsl,ls1012a-msi" +- msi-controller: indicates that this is a PCIe MSI controller node +- reg: physical base address of the controller and length of memory mapped. +- interrupts: an interrupt to the parent interrupt controller. + +This interrupt controller hardware is a second level interrupt controller that +is hooked to a parent interrupt controller: e.g: ARM GIC for ARM-based +platforms. If interrupt-parent is not provided, the default parent interrupt +controller will be used. +Each PCIe node needs to have property msi-parent that points to +MSI controller node + +Examples: + + msi1: msi-controller@1571000 { + compatible = "fsl,ls1043a-msi"; + reg = <0x0 0x1571000 0x0 0x8>, + msi-controller; + interrupts = <0 116 0x4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/google,goldfish-pic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/google,goldfish-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..35f752706e7d6ba9e70158effce6d3ba87414dbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/google,goldfish-pic.txt @@ -0,0 +1,30 @@ +Android Goldfish PIC + +Android Goldfish programmable interrupt device used by Android +emulator. + +Required properties: + +- compatible : should contain "google,goldfish-pic" +- reg : +- interrupts : + +Example for mips when used in cascade mode: + + cpuintc { + #interrupt-cells = <0x1>; + #address-cells = <0>; + interrupt-controller; + compatible = "mti,cpu-interrupt-controller"; + }; + + interrupt-controller@1f000000 { + compatible = "google,goldfish-pic"; + reg = <0x1f000000 0x1000>; + + interrupt-controller; + #interrupt-cells = <0x1>; + + interrupt-parent = <&cpuintc>; + interrupts = <0x2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/hisilicon,mbigen-v2.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/hisilicon,mbigen-v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..a6813a071f15c38bc11d7a528fa801687c0f0fef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/hisilicon,mbigen-v2.txt @@ -0,0 +1,84 @@ +Hisilicon mbigen device tree bindings. +======================================= + +Mbigen means: message based interrupt generator. + +MBI is kind of msi interrupt only used on Non-PCI devices. + +To reduce the wired interrupt number connected to GIC, +Hisilicon designed mbigen to collect and generate interrupt. + + +Non-pci devices can connect to mbigen and generate the +interrupt by writing ITS register. + +The mbigen chip and devices connect to mbigen have the following properties: + +Mbigen main node required properties: +------------------------------------------- +- compatible: Should be "hisilicon,mbigen-v2" + +- reg: Specifies the base physical address and size of the Mbigen + registers. + +Mbigen sub node required properties: +------------------------------------------ +- interrupt controller: Identifies the node as an interrupt controller + +- msi-parent: Specifies the MSI controller this mbigen use. + For more detail information,please refer to the generic msi-parent binding in + Documentation/devicetree/bindings/interrupt-controller/msi.txt. + +- num-pins: the total number of pins implemented in this Mbigen + instance. + +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 2. + + The 1st cell is hardware pin number of the interrupt.This number is local to + each mbigen chip and in the range from 0 to the maximum interrupts number + of the mbigen. + + The 2nd cell is the interrupt trigger type. + The value of this cell should be: + 1: rising edge triggered + or + 4: high level triggered + +Examples: + + mbigen_chip_dsa { + compatible = "hisilicon,mbigen-v2"; + reg = <0x0 0xc0080000 0x0 0x10000>; + + mbigen_gmac:intc_gmac { + interrupt-controller; + msi-parent = <&its_dsa 0x40b1c>; + num-pins = <9>; + #interrupt-cells = <2>; + }; + + mbigen_i2c:intc_i2c { + interrupt-controller; + msi-parent = <&its_dsa 0x40b0e>; + num-pins = <2>; + #interrupt-cells = <2>; + }; + }; + +Devices connect to mbigen required properties: +---------------------------------------------------- +-interrupts:Specifies the interrupt source. + For the specific information of each cell in this property,please refer to + the "interrupt-cells" description mentioned above. + +Examples: + gmac0: ethernet@c2080000 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0xc2080000 0 0x20000>, + <0 0xc0000000 0 0x1000>; + interrupt-parent = <&mbigen_device_gmac>; + interrupts = <656 1>, + <657 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/img,meta-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/img,meta-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..42431f44697fb22cee723d176ef4ce9d1cdc4ebd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/img,meta-intc.txt @@ -0,0 +1,82 @@ +* Meta External Trigger Controller Binding + +This binding specifies what properties must be available in the device tree +representation of a Meta external trigger controller. + +Required properties: + + - compatible: Specifies the compatibility list for the interrupt controller. + The type shall be and the value shall include "img,meta-intc". + + - num-banks: Specifies the number of interrupt banks (each of which can + handle 32 interrupt sources). + + - interrupt-controller: The presence of this property identifies the node + as an interrupt controller. No property value shall be defined. + + - #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 2. + + - #address-cells: Specifies the number of cells needed to encode an + address. The type shall be and the value shall be 0. As such, + 'interrupt-map' nodes do not have to specify a parent unit address. + +Optional properties: + + - no-mask: The controller doesn't have any mask registers. + +* Interrupt Specifier Definition + + Interrupt specifiers consists of 2 cells encoded as follows: + + - <1st-cell>: The interrupt-number that identifies the interrupt source. + + - <2nd-cell>: The Linux interrupt flags containing level-sense information, + encoded as follows: + 1 = edge triggered + 4 = level-sensitive + +* Examples + +Example 1: + + /* + * Meta external trigger block + */ + intc: intc { + // This is an interrupt controller node. + interrupt-controller; + + // No address cells so that 'interrupt-map' nodes which + // reference this interrupt controller node do not need a parent + // address specifier. + #address-cells = <0>; + + // Two cells to encode interrupt sources. + #interrupt-cells = <2>; + + // Number of interrupt banks + num-banks = <2>; + + // No HWMASKEXT is available (specify on Chorus2 and Comet ES1) + no-mask; + + // Compatible with Meta hardware trigger block. + compatible = "img,meta-intc"; + }; + +Example 2: + + /* + * An interrupt generating device that is wired to a Meta external + * trigger block. + */ + uart1: uart@02004c00 { + // Interrupt source '5' that is level-sensitive. + // Note that there are only two cells as specified in the + // interrupt parent's '#interrupt-cells' property. + interrupts = <5 4 /* level */>; + + // The interrupt controller that this device is wired to. + interrupt-parent = <&intc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/img,pdc-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/img,pdc-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5dc2a55ad81143d86d8e781f147342ad6a21848e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/img,pdc-intc.txt @@ -0,0 +1,105 @@ +* ImgTec Powerdown Controller (PDC) Interrupt Controller Binding + +This binding specifies what properties must be available in the device tree +representation of a PDC IRQ controller. This has a number of input interrupt +lines which can wake the system, and are passed on through output interrupt +lines. + +Required properties: + + - compatible: Specifies the compatibility list for the interrupt controller. + The type shall be and the value shall include "img,pdc-intc". + + - reg: Specifies the base PDC physical address(s) and size(s) of the + addressable register space. The type shall be . + + - interrupt-controller: The presence of this property identifies the node + as an interrupt controller. No property value shall be defined. + + - #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 2. + + - num-perips: Number of waking peripherals. + + - num-syswakes: Number of SysWake inputs. + + - interrupts: List of interrupt specifiers. The first specifier shall be the + shared SysWake interrupt, and remaining specifies shall be PDC peripheral + interrupts in order. + +* Interrupt Specifier Definition + + Interrupt specifiers consists of 2 cells encoded as follows: + + - <1st-cell>: The interrupt-number that identifies the interrupt source. + 0-7: Peripheral interrupts + 8-15: SysWake interrupts + + - <2nd-cell>: The level-sense information, encoded using the Linux interrupt + flags as follows (only 4 valid for peripheral interrupts): + 0 = none (decided by software) + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 3 = both edge triggered + 4 = active-high level-sensitive (required for perip irqs) + 8 = active-low level-sensitive + +* Examples + +Example 1: + + /* + * TZ1090 PDC block + */ + pdc: pdc@02006000 { + // This is an interrupt controller node. + interrupt-controller; + + // Three cells to encode interrupt sources. + #interrupt-cells = <2>; + + // Offset address of 0x02006000 and size of 0x1000. + reg = <0x02006000 0x1000>; + + // Compatible with Meta hardware trigger block. + compatible = "img,pdc-intc"; + + // Three peripherals are connected. + num-perips = <3>; + + // Four SysWakes are connected. + num-syswakes = <4>; + + interrupts = <18 4 /* level */>, /* Syswakes */ + <30 4 /* level */>, /* Peripheral 0 (RTC) */ + <29 4 /* level */>, /* Peripheral 1 (IR) */ + <31 4 /* level */>; /* Peripheral 2 (WDT) */ + }; + +Example 2: + + /* + * An SoC peripheral that is wired through the PDC. + */ + rtc0 { + // The interrupt controller that this device is wired to. + interrupt-parent = <&pdc>; + + // Interrupt source Peripheral 0 + interrupts = <0 /* Peripheral 0 (RTC) */ + 4> /* IRQ_TYPE_LEVEL_HIGH */ + }; + +Example 3: + + /* + * An interrupt generating device that is wired to a SysWake pin. + */ + touchscreen0 { + // The interrupt controller that this device is wired to. + interrupt-parent = <&pdc>; + + // Interrupt source SysWake 0 that is active-low level-sensitive + interrupts = <8 /* SysWake0 */ + 8 /* IRQ_TYPE_LEVEL_LOW */>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ingenic,intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ingenic,intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4373d0f7121d586277d6e441bae1d684d019ef9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ingenic,intc.txt @@ -0,0 +1,28 @@ +Ingenic SoC Interrupt Controller + +Required properties: + +- compatible : should be "ingenic,-intc". Valid strings are: + ingenic,jz4740-intc + ingenic,jz4725b-intc + ingenic,jz4770-intc + ingenic,jz4775-intc + ingenic,jz4780-intc +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. +- interrupts : Specifies the CPU interrupt the controller is connected to. + +Example: + +intc: interrupt-controller@10001000 { + compatible = "ingenic,jz4740-intc"; + reg = <0x10001000 0x14>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/intel,ce4100-ioapic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/intel,ce4100-ioapic.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d19f494f19a3e82cf79370c54c0756134b2347f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/intel,ce4100-ioapic.txt @@ -0,0 +1,26 @@ +Interrupt chips +--------------- + +* Intel I/O Advanced Programmable Interrupt Controller (IO APIC) + + Required properties: + -------------------- + compatible = "intel,ce4100-ioapic"; + #interrupt-cells = <2>; + + Device's interrupt property: + + interrupts =

; + + The first number (P) represents the interrupt pin which is wired to the + IO APIC. The second number (S) represents the sense of interrupt which + should be configured and can be one of: + 0 - Edge Rising + 1 - Level Low + 2 - Level High + 3 - Edge Falling + +* Local APIC + Required property: + + compatible = "intel,ce4100-lapic"; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/interrupts.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/interrupts.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a3c4082989906248fd4f07ee7a1493b20580794 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/interrupts.txt @@ -0,0 +1,110 @@ +Specifying interrupt information for devices +============================================ + +1) Interrupt client nodes +------------------------- + +Nodes that describe devices which generate interrupts must contain an +"interrupts" property, an "interrupts-extended" property, or both. If both are +present, the latter should take precedence; the former may be provided simply +for compatibility with software that does not recognize the latter. These +properties contain a list of interrupt specifiers, one per output interrupt. The +format of the interrupt specifier is determined by the interrupt controller to +which the interrupts are routed; see section 2 below for details. + + Example: + interrupt-parent = <&intc1>; + interrupts = <5 0>, <6 0>; + +The "interrupt-parent" property is used to specify the controller to which +interrupts are routed and contains a single phandle referring to the interrupt +controller node. This property is inherited, so it may be specified in an +interrupt client node or in any of its parent nodes. Interrupts listed in the +"interrupts" property are always in reference to the node's interrupt parent. + +The "interrupts-extended" property is a special form for use when a node needs +to reference multiple interrupt parents. Each entry in this property contains +both the parent phandle and the interrupt specifier. "interrupts-extended" +should only be used when a device has multiple interrupt parents. + + Example: + interrupts-extended = <&intc1 5 1>, <&intc2 1 0>; + +2) Interrupt controller nodes +----------------------------- + +A device is marked as an interrupt controller with the "interrupt-controller" +property. This is a empty, boolean property. An additional "#interrupt-cells" +property defines the number of cells needed to specify a single interrupt. + +It is the responsibility of the interrupt controller's binding to define the +length and format of the interrupt specifier. The following two variants are +commonly used: + + a) one cell + ----------- + The #interrupt-cells property is set to 1 and the single cell defines the + index of the interrupt within the controller. + + Example: + + vic: intc@10140000 { + compatible = "arm,versatile-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10140000 0x1000>; + }; + + sic: intc@10003000 { + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10003000 0x1000>; + interrupt-parent = <&vic>; + interrupts = <31>; /* Cascaded to vic */ + }; + + b) two cells + ------------ + The #interrupt-cells property is set to 2 and the first cell defines the + index of the interrupt within the controller, while the second cell is used + to specify any of the following flags: + - bits[3:0] trigger type and level flags + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + + Example: + + i2c@7000c000 { + gpioext: gpio-adnp@41 { + compatible = "ad,gpio-adnp"; + reg = <0x41>; + + interrupt-parent = <&gpio>; + interrupts = <160 1>; + + gpio-controller; + #gpio-cells = <1>; + + interrupt-controller; + #interrupt-cells = <2>; + + nr-gpios = <64>; + }; + + sx8634@2b { + compatible = "smtc,sx8634"; + reg = <0x2b>; + + interrupt-parent = <&gpioext>; + interrupts = <3 0x8>; + + #address-cells = <1>; + #size-cells = <0>; + + threshold = <0x40>; + sensitivity = <7>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/jcore,aic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/jcore,aic.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee2ad36f8df8c82b5f6023d32ed36e4fcb01b9d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/jcore,aic.txt @@ -0,0 +1,26 @@ +J-Core Advanced Interrupt Controller + +Required properties: + +- compatible: Should be "jcore,aic1" for the (obsolete) first-generation aic + with 8 interrupt lines with programmable priorities, or "jcore,aic2" for + the "aic2" core with 64 interrupts. + +- reg: Memory region(s) for configuration. For SMP, there should be one + region per cpu, indexed by the sequential, zero-based hardware cpu + number. + +- interrupt-controller: Identifies the node as an interrupt controller + +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + + +Example: + +aic: interrupt-controller@200 { + compatible = "jcore,aic2"; + reg = < 0x200 0x30 0x500 0x30 >; + interrupt-controller; + #interrupt-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/lsi,zevio-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/lsi,zevio-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..aee38e7c13e7d15174822e6d70d2416c3242858b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/lsi,zevio-intc.txt @@ -0,0 +1,18 @@ +TI-NSPIRE interrupt controller + +Required properties: +- compatible: Compatible property value should be "lsi,zevio-intc". + +- reg: Physical base address of the controller and length of memory mapped + region. + +- interrupt-controller : Identifies the node as an interrupt controller + +Example: + +interrupt-controller { + compatible = "lsi,zevio-intc"; + interrupt-controller; + reg = <0xDC000000 0x1000>; + #interrupt-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt new file mode 100644 index 0000000000000000000000000000000000000000..5fc03134a9996473e4fe3ce1cd895b49da5b96f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,armada-370-xp-mpic.txt @@ -0,0 +1,38 @@ +Marvell Armada 370, 375, 38x, XP Interrupt Controller +----------------------------------------------------- + +Required properties: +- compatible: Should be "marvell,mpic" +- interrupt-controller: Identifies the node as an interrupt controller. +- msi-controller: Identifies the node as an PCI Message Signaled + Interrupt controller. +- #interrupt-cells: The number of cells to define the interrupts. Should be 1. + The cell is the IRQ number + +- reg: Should contain PMIC registers location and length. First pair + for the main interrupt registers, second pair for the per-CPU + interrupt registers. For this last pair, to be compliant with SMP + support, the "virtual" must be use (For the record, these registers + automatically map to the interrupt controller registers of the + current CPU) + +Optional properties: + +- interrupts: If defined, then it indicates that this MPIC is + connected as a slave to another interrupt controller. This is + typically the case on Armada 375 and Armada 38x, where the MPIC is + connected as a slave to the Cortex-A9 GIC. The provided interrupt + indicate to which GIC interrupt the MPIC output is connected. + +Example: + + mpic: interrupt-controller@d0020000 { + compatible = "marvell,mpic"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + msi-controller; + reg = <0xd0020a00 0x1d0>, + <0xd0021070 0x58>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,armada-8k-pic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,armada-8k-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..86a7b4cd03f5dfee84fcbe74f69278aed25e3b92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,armada-8k-pic.txt @@ -0,0 +1,25 @@ +Marvell Armada 7K/8K PIC Interrupt controller +--------------------------------------------- + +This is the Device Tree binding for the PIC, a secondary interrupt +controller available on the Marvell Armada 7K/8K ARM64 SoCs, and +typically connected to the GIC as the primary interrupt controller. + +Required properties: +- compatible: should be "marvell,armada-8k-pic" +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: the number of cells to define interrupts on this + controller. Should be 1 +- reg: the register area for the PIC interrupt controller +- interrupts: the interrupt to the primary interrupt controller, + typically the GIC + +Example: + + pic: interrupt-controller@3f0100 { + compatible = "marvell,armada-8k-pic"; + reg = <0x3f0100 0x10>; + #interrupt-cells = <1>; + interrupt-controller; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,gicp.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,gicp.txt new file mode 100644 index 0000000000000000000000000000000000000000..64a00ceb7da42eba5d0fa40c57413c6401cf8102 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,gicp.txt @@ -0,0 +1,27 @@ +Marvell GICP Controller +----------------------- + +GICP is a Marvell extension of the GIC that allows to trigger GIC SPI +interrupts by doing a memory transaction. It is used by the ICU +located in the Marvell CP110 to turn wired interrupts inside the CP +into GIC SPI interrupts. + +Required properties: + +- compatible: Must be "marvell,ap806-gicp" + +- reg: Must be the address and size of the GICP SPI registers + +- marvell,spi-ranges: tuples of GIC SPI interrupts ranges available + for this GICP + +- msi-controller: indicates that this is an MSI controller + +Example: + +gicp_spi: gicp-spi@3f0040 { + compatible = "marvell,ap806-gicp"; + reg = <0x3f0040 0x10>; + marvell,spi-ranges = <64 64>, <288 64>; + msi-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,icu.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,icu.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa8bf2ec89054962b92212a21d8a1fbe8475a0d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,icu.txt @@ -0,0 +1,51 @@ +Marvell ICU Interrupt Controller +-------------------------------- + +The Marvell ICU (Interrupt Consolidation Unit) controller is +responsible for collecting all wired-interrupt sources in the CP and +communicating them to the GIC in the AP, the unit translates interrupt +requests on input wires to MSG memory mapped transactions to the GIC. + +Required properties: + +- compatible: Should be "marvell,cp110-icu" + +- reg: Should contain ICU registers location and length. + +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 3. + + The 1st cell is the group type of the ICU interrupt. Possible group + types are: + + ICU_GRP_NSR (0x0) : Shared peripheral interrupt, non-secure + ICU_GRP_SR (0x1) : Shared peripheral interrupt, secure + ICU_GRP_SEI (0x4) : System error interrupt + ICU_GRP_REI (0x5) : RAM error interrupt + + The 2nd cell is the index of the interrupt in the ICU unit. + + The 3rd cell is the type of the interrupt. See arm,gic.txt for + details. + +- interrupt-controller: Identifies the node as an interrupt + controller. + +- msi-parent: Should point to the GICP controller, the GIC extension + that allows to trigger interrupts using MSG memory mapped + transactions. + +Example: + +icu: interrupt-controller@1e0000 { + compatible = "marvell,cp110-icu"; + reg = <0x1e0000 0x10>; + #interrupt-cells = <3>; + interrupt-controller; + msi-parent = <&gicp>; +}; + +usb3h0: usb3@500000 { + interrupt-parent = <&icu>; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,odmi-controller.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,odmi-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..930fb462fd9fe4df2f6f74933163cf9133e020e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,odmi-controller.txt @@ -0,0 +1,42 @@ + +* Marvell ODMI for MSI support + +Some Marvell SoCs have an On-Die Message Interrupt (ODMI) controller +which can be used by on-board peripheral for MSI interrupts. + +Required properties: + +- compatible : The value here should contain: + + "marvell,ap806-odmi-controller", "marvell,odmi-controller". + +- interrupt,controller : Identifies the node as an interrupt controller. + +- msi-controller : Identifies the node as an MSI controller. + +- marvell,odmi-frames : Number of ODMI frames available. Each frame + provides a number of events. + +- reg : List of register definitions, one for each + ODMI frame. + +- marvell,spi-base : List of GIC base SPI interrupts, one for each + ODMI frame. Those SPI interrupts are 0-based, + i.e marvell,spi-base = <128> will use SPI #96. + See Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt + for details about the GIC Device Tree binding. + +Example: + + odmi: odmi@300000 { + compatible = "marvell,ap806-odmi-controller", + "marvell,odmi-controller"; + interrupt-controller; + msi-controller; + marvell,odmi-frames = <4>; + reg = <0x300000 0x4000>, + <0x304000 0x4000>, + <0x308000 0x4000>, + <0x30C000 0x4000>; + marvell,spi-base = <128>, <136>, <144>, <152>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,orion-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,orion-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c11ac76fac992156b24ba957ae3bbd94093e390 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/marvell,orion-intc.txt @@ -0,0 +1,48 @@ +Marvell Orion SoC interrupt controllers + +* Main interrupt controller + +Required properties: +- compatible: shall be "marvell,orion-intc" +- reg: base address(es) of interrupt registers starting with CAUSE register +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt source, shall be 1 + +The interrupt sources map to the corresponding bits in the interrupt +registers, i.e. +- 0 maps to bit 0 of first base address, +- 1 maps to bit 1 of first base address, +- 32 maps to bit 0 of second base address, and so on. + +Example: + intc: interrupt-controller { + compatible = "marvell,orion-intc"; + interrupt-controller; + #interrupt-cells = <1>; + /* Dove has 64 first level interrupts */ + reg = <0x20200 0x10>, <0x20210 0x10>; + }; + +* Bridge interrupt controller + +Required properties: +- compatible: shall be "marvell,orion-bridge-intc" +- reg: base address of bridge interrupt registers starting with CAUSE register +- interrupts: bridge interrupt of the main interrupt controller +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt source, shall be 1 + +Optional properties: +- marvell,#interrupts: number of interrupts provided by bridge interrupt + controller, defaults to 32 if not set + +Example: + bridge_intc: interrupt-controller { + compatible = "marvell,orion-bridge-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x20110 0x8>; + interrupts = <0>; + /* Dove bridge provides 5 interrupts */ + marvell,#interrupts = <5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mediatek,cirq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mediatek,cirq.txt new file mode 100644 index 0000000000000000000000000000000000000000..5865f4f2c69dcfa583d05452053e04b91e33dcfc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mediatek,cirq.txt @@ -0,0 +1,33 @@ +* Mediatek 27xx cirq + +In Mediatek SOCs, the CIRQ is a low power interrupt controller designed to +work outside MCUSYS which comprises with Cortex-Ax cores,CCI and GIC. +The external interrupts (outside MCUSYS) will feed through CIRQ and connect +to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive +interrupts and generate a pulse signal to parent interrupt controller when +flush command is executed. With CIRQ, MCUSYS can be completely turned off +to improve the system power consumption without losing interrupts. + +Required properties: +- compatible: should be one of + - "mediatek,mt2701-cirq" for mt2701 CIRQ + - "mediatek,mt8135-cirq" for mt8135 CIRQ + - "mediatek,mt8173-cirq" for mt8173 CIRQ + and "mediatek,cirq" as a fallback. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt. +- reg: Physical base address of the cirq registers and length of memory + mapped region. +- mediatek,ext-irq-range: Identifies external irq number range in different + SOCs. + +Example: + cirq: interrupt-controller@10204000 { + compatible = "mediatek,mt2701-cirq", + "mediatek,mtk-cirq"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&sysirq>; + reg = <0 0x10204000 0 0x400>; + mediatek,ext-irq-start = <32 200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mediatek,sysirq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mediatek,sysirq.txt new file mode 100644 index 0000000000000000000000000000000000000000..33a98eb44949f1c43c972a7955e4d4d5427f7865 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mediatek,sysirq.txt @@ -0,0 +1,38 @@ ++Mediatek MT65xx/MT67xx/MT81xx sysirq + +Mediatek SOCs sysirq support controllable irq inverter for each GIC SPI +interrupt. + +Required properties: +- compatible: should be + "mediatek,mt8173-sysirq", "mediatek,mt6577-sysirq": for MT8173 + "mediatek,mt8135-sysirq", "mediatek,mt6577-sysirq": for MT8135 + "mediatek,mt8127-sysirq", "mediatek,mt6577-sysirq": for MT8127 + "mediatek,mt7622-sysirq", "mediatek,mt6577-sysirq": for MT7622 + "mediatek,mt6795-sysirq", "mediatek,mt6577-sysirq": for MT6795 + "mediatek,mt6797-sysirq", "mediatek,mt6577-sysirq": for MT6797 + "mediatek,mt6765-sysirq", "mediatek,mt6577-sysirq": for MT6765 + "mediatek,mt6755-sysirq", "mediatek,mt6577-sysirq": for MT6755 + "mediatek,mt6592-sysirq", "mediatek,mt6577-sysirq": for MT6592 + "mediatek,mt6589-sysirq", "mediatek,mt6577-sysirq": for MT6589 + "mediatek,mt6582-sysirq", "mediatek,mt6577-sysirq": for MT6582 + "mediatek,mt6580-sysirq", "mediatek,mt6577-sysirq": for MT6580 + "mediatek,mt6577-sysirq": for MT6577 + "mediatek,mt2712-sysirq", "mediatek,mt6577-sysirq": for MT2712 + "mediatek,mt2701-sysirq", "mediatek,mt6577-sysirq": for MT2701 +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Use the same format as specified by GIC in arm,gic.txt. +- reg: Physical base address of the intpol registers and length of memory + mapped region. Could be multiple bases here. Ex: mt6797 needs 2 reg, others + need 1. + +Example: + sysirq: intpol-controller@10200620 { + compatible = "mediatek,mt6797-sysirq", + "mediatek,mt6577-sysirq"; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10220620 0 0x20>, + <0 0x10220690 0 0x10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/microchip,pic32-evic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/microchip,pic32-evic.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3a1b37c4c35840c2d33e9d59b5e3c2af0423689 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/microchip,pic32-evic.txt @@ -0,0 +1,67 @@ +Microchip PIC32 Interrupt Controller +==================================== + +The Microchip PIC32 contains an Enhanced Vectored Interrupt Controller (EVIC). +It handles all internal and external interrupts. This controller exists outside +of the CPU and is the arbitrator of all interrupts (including interrupts from +the CPU itself) before they are presented to the CPU. + +External interrupts have a software configurable edge polarity. Non external +interrupts have a type and polarity that is determined by the source of the +interrupt. + +Required properties +------------------- + +- compatible: Should be "microchip,pic32mzda-evic" +- reg: Specifies physical base address and size of register range. +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt cells: Specifies the number of cells used to encode an interrupt + source connected to this controller. The value shall be 2 and interrupt + descriptor shall have the following format: + + + + hw_irq - represents the hardware interrupt number as in the data sheet. + irq_type - is used to describe the type and polarity of an interrupt. For + internal interrupts use IRQ_TYPE_EDGE_RISING for non persistent interrupts and + IRQ_TYPE_LEVEL_HIGH for persistent interrupts. For external interrupts use + IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING to select the desired polarity. + +Optional properties +------------------- +- microchip,external-irqs: u32 array of external interrupts with software + polarity configuration. This array corresponds to the bits in the INTCON + SFR. + +Example +------- + +evic: interrupt-controller@1f810000 { + compatible = "microchip,pic32mzda-evic"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x1f810000 0x1000>; + microchip,external-irqs = <3 8 13 18 23>; +}; + +Each device/peripheral must request its interrupt line with the associated type +and polarity. + +Internal interrupt DTS snippet +------------------------------ + +device@1f800000 { + ... + interrupts = <113 IRQ_TYPE_LEVEL_HIGH>; + ... +}; + +External interrupt DTS snippet +------------------------------ + +device@1f800000 { + ... + interrupts = <3 IRQ_TYPE_EDGE_RISING>; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mips-gic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mips-gic.txt new file mode 100644 index 0000000000000000000000000000000000000000..173595305e2667e4098b8e977b2a603782f406a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mips-gic.txt @@ -0,0 +1,67 @@ +MIPS Global Interrupt Controller (GIC) + +The MIPS GIC routes external interrupts to individual VPEs and IRQ pins. +It also supports local (per-processor) interrupts and software-generated +interrupts which can be used as IPIs. The GIC also includes a free-running +global timer, per-CPU count/compare timers, and a watchdog. + +Required properties: +- compatible : Should be "mti,gic". +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt specifier. Should be 3. + - The first cell is the type of interrupt, local or shared. + See . + - The second cell is the GIC interrupt number. + - The third cell encodes the interrupt flags. + See for a list of valid + flags. + +Optional properties: +- reg : Base address and length of the GIC registers. If not present, + the base address reported by the hardware GCR_GIC_BASE will be used. +- mti,reserved-cpu-vectors : Specifies the list of CPU interrupt vectors + to which the GIC may not route interrupts. Valid values are 2 - 7. + This property is ignored if the CPU is started in EIC mode. +- mti,reserved-ipi-vectors : Specifies the range of GIC interrupts that are + reserved for IPIs. + It accepts 2 values, the 1st is the starting interrupt and the 2nd is the size + of the reserved range. + If not specified, the driver will allocate the last 2 * number of VPEs in the + system. + +Required properties for timer sub-node: +- compatible : Should be "mti,gic-timer". +- interrupts : Interrupt for the GIC local timer. + +Optional properties for timer sub-node: +- clocks : GIC timer operating clock. +- clock-frequency : Clock frequency at which the GIC timers operate. + +Note that one of clocks or clock-frequency must be specified. + +Example: + + gic: interrupt-controller@1bdc0000 { + compatible = "mti,gic"; + reg = <0x1bdc0000 0x20000>; + + interrupt-controller; + #interrupt-cells = <3>; + + mti,reserved-cpu-vectors = <7>; + mti,reserved-ipi-vectors = <40 8>; + + timer { + compatible = "mti,gic-timer"; + interrupts = ; + clock-frequency = <50000000>; + }; + }; + + uart@18101400 { + ... + interrupt-parent = <&gic>; + interrupts = ; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mrvl,intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mrvl,intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b53273cb22f367ae77146bb7da0c6079e7a1bff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mrvl,intc.txt @@ -0,0 +1,60 @@ +* Marvell MMP Interrupt controller + +Required properties: +- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or + "mrvl,mmp2-mux-intc" +- reg : Address and length of the register set of the interrupt controller. + If the interrupt controller is intc, address and length means the range + of the whold interrupt controller. If the interrupt controller is mux-intc, + address and length means one register. Since address of mux-intc is in the + range of intc. mux-intc is secondary interrupt controller. +- reg-names : Name of the register set of the interrupt controller. It's + only required in mux-intc interrupt controller. +- interrupts : Should be the port interrupt shared by mux interrupts. It's + only required in mux-intc interrupt controller. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. +- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt + controller. +- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge + detection first. + +Example: + intc: interrupt-controller@d4282000 { + compatible = "mrvl,mmp2-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xd4282000 0x1000>; + mrvl,intc-nr-irqs = <64>; + }; + + intcmux4@d4282150 { + compatible = "mrvl,mmp2-mux-intc"; + interrupts = <4>; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x150 0x4>, <0x168 0x4>; + reg-names = "mux status", "mux mask"; + mrvl,intc-nr-irqs = <2>; + }; + +* Marvell Orion Interrupt controller + +Required properties +- compatible : Should be "marvell,orion-intc". +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. Supported value is <1>. +- interrupt-controller : Declare this node to be an interrupt controller. +- reg : Interrupt mask address. A list of 4 byte ranges, one per controller. + One entry in the list represents 32 interrupts. + +Example: + + intc: interrupt-controller { + compatible = "marvell,orion-intc", "marvell,intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0xfed20204 0x04>, + <0xfed20214 0x04>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5baeccb689f2671ec440b07c56860583dacd415 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/mscc,ocelot-icpu-intr.txt @@ -0,0 +1,21 @@ +Microsemi Ocelot SoC ICPU Interrupt Controller + +Required properties: + +- compatible : should be "mscc,ocelot-icpu-intr" +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. +- interrupts : Specifies the CPU interrupt the controller is connected to. + +Example: + + intc: interrupt-controller@70000070 { + compatible = "mscc,ocelot-icpu-intr"; + reg = <0x70000070 0x70>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&cpuintc>; + interrupts = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/msi.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..c60c034dcf1950005bce969e78b28a69b0dbfa62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/msi.txt @@ -0,0 +1,135 @@ +This document describes the generic device tree binding for MSI controllers and +their master(s). + +Message Signaled Interrupts (MSIs) are a class of interrupts generated by a +write to an MMIO address. + +MSIs were originally specified by PCI (and are used with PCIe), but may also be +used with other busses, and hence a mechanism is required to relate devices on +those busses to the MSI controllers which they are capable of using, +potentially including additional information. + +MSIs are distinguished by some combination of: + +- The doorbell (the MMIO address written to). + + Devices may be configured by software to write to arbitrary doorbells which + they can address. An MSI controller may feature a number of doorbells. + +- The payload (the value written to the doorbell). + + Devices may be configured to write an arbitrary payload chosen by software. + MSI controllers may have restrictions on permitted payloads. + +- Sideband information accompanying the write. + + Typically this is neither configurable nor probeable, and depends on the path + taken through the memory system (i.e. it is a property of the combination of + MSI controller and device rather than a property of either in isolation). + + +MSI controllers: +================ + +An MSI controller signals interrupts to a CPU when a write is made to an MMIO +address by some master. An MSI controller may feature a number of doorbells. + +Required properties: +-------------------- + +- msi-controller: Identifies the node as an MSI controller. + +Optional properties: +-------------------- + +- #msi-cells: The number of cells in an msi-specifier, required if not zero. + + Typically this will encode information related to sideband data, and will + not encode doorbells or payloads as these can be configured dynamically. + + The meaning of the msi-specifier is defined by the device tree binding of + the specific MSI controller. + + +MSI clients +=========== + +MSI clients are devices which generate MSIs. For each MSI they wish to +generate, the doorbell and payload may be configured, though sideband +information may not be configurable. + +Required properties: +-------------------- + +- msi-parent: A list of phandle + msi-specifier pairs, one for each MSI + controller which the device is capable of using. + + This property is unordered, and MSIs may be allocated from any combination of + MSI controllers listed in the msi-parent property. + + If a device has restrictions on the allocation of MSIs, these restrictions + must be described with additional properties. + + When #msi-cells is non-zero, busses with an msi-parent will require + additional properties to describe the relationship between devices on the bus + and the set of MSIs they can potentially generate. + + +Example +======= + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi_a: msi-controller@a { + reg = <0xa 0xf00>; + compatible = "vendor-a,some-controller"; + msi-controller; + /* No sideband data, so #msi-cells omitted */ + }; + + msi_b: msi-controller@b { + reg = <0xb 0xf00>; + compatible = "vendor-b,another-controller"; + msi-controller; + /* Each device has some unique ID */ + #msi-cells = <1>; + }; + + msi_c: msi-controller@c { + reg = <0xb 0xf00>; + compatible = "vendor-b,another-controller"; + msi-controller; + /* Each device has some unique ID */ + #msi-cells = <1>; + }; + + dev@0 { + reg = <0x0 0xf00>; + compatible = "vendor-c,some-device"; + + /* Can only generate MSIs to msi_a */ + msi-parent = <&msi_a>; + }; + + dev@1 { + reg = <0x1 0xf00>; + compatible = "vendor-c,some-device"; + + /* + * Can generate MSIs to either A or B. + */ + msi-parent = <&msi_a>, <&msi_b 0x17>; + }; + + dev@2 { + reg = <0x2 0xf00>; + compatible = "vendor-c,some-device"; + /* + * Has different IDs at each MSI controller. + * Can generate MSIs to all of the MSI controllers. + */ + msi-parent = <&msi_a>, <&msi_b 0x17>, <&msi_c 0x53>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/nvidia,tegra20-ictlr.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/nvidia,tegra20-ictlr.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ff3566401003a57407a0cf41658aef5e00c2019 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/nvidia,tegra20-ictlr.txt @@ -0,0 +1,41 @@ +NVIDIA Legacy Interrupt Controller + +All Tegra SoCs contain a legacy interrupt controller that routes +interrupts to the GIC, and also serves as a wakeup source. It is also +referred to as "ictlr", hence the name of the binding. + +The HW block exposes a number of interrupt controllers, each +implementing a set of 32 interrupts. + +Required properties: + +- compatible : should be: "nvidia,tegra-ictlr". The LIC on + subsequent SoCs remained backwards-compatible with Tegra30, so on + Tegra generations later than Tegra30 the compatible value should + include "nvidia,tegra30-ictlr". +- reg : Specifies base physical address and size of the registers. + Each controller must be described separately (Tegra20 has 4 of them, + whereas Tegra30 and later have 5). +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 3. + +Notes: + +- Because this HW ultimately routes interrupts to the GIC, the + interrupt specifier must be that of the GIC. +- Only SPIs can use the ictlr as an interrupt parent. SGIs and PPIs + are explicitly forbidden. + +Example: + + ictlr: interrupt-controller@60004000 { + compatible = "nvidia,tegra20-ictlr", "nvidia,tegra-ictlr"; + reg = <0x60004000 64>, + <0x60004100 64>, + <0x60004200 64>, + <0x60004300 64>; + interrupt-controller; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/nxp,lpc3220-mic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/nxp,lpc3220-mic.txt new file mode 100644 index 0000000000000000000000000000000000000000..0bfb3ba55f4cef20188f4bfe23ffba9ae4b30231 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/nxp,lpc3220-mic.txt @@ -0,0 +1,58 @@ +* NXP LPC32xx MIC, SIC1 and SIC2 Interrupt Controllers + +Required properties: +- compatible: "nxp,lpc3220-mic" or "nxp,lpc3220-sic". +- reg: should contain IC registers location and length. +- interrupt-controller: identifies the node as an interrupt controller. +- #interrupt-cells: the number of cells to define an interrupt, should be 2. + The first cell is the IRQ number, the second cell is used to specify + one of the supported IRQ types: + IRQ_TYPE_EDGE_RISING = low-to-high edge triggered, + IRQ_TYPE_EDGE_FALLING = high-to-low edge triggered, + IRQ_TYPE_LEVEL_HIGH = active high level-sensitive, + IRQ_TYPE_LEVEL_LOW = active low level-sensitive. + Reset value is IRQ_TYPE_LEVEL_LOW. + +Optional properties: +- interrupts: empty for MIC interrupt controller, cascaded MIC + hardware interrupts for SIC1 and SIC2 + +Examples: + + /* LPC32xx MIC, SIC1 and SIC2 interrupt controllers */ + mic: interrupt-controller@40008000 { + compatible = "nxp,lpc3220-mic"; + reg = <0x40008000 0x4000>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sic1: interrupt-controller@4000c000 { + compatible = "nxp,lpc3220-sic"; + reg = <0x4000c000 0x4000>; + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&mic>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>, + <30 IRQ_TYPE_LEVEL_LOW>; + }; + + sic2: interrupt-controller@40010000 { + compatible = "nxp,lpc3220-sic"; + reg = <0x40010000 0x4000>; + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&mic>; + interrupts = <1 IRQ_TYPE_LEVEL_LOW>, + <31 IRQ_TYPE_LEVEL_LOW>; + }; + + /* ADC */ + adc@40048000 { + compatible = "nxp,lpc3220-adc"; + reg = <0x40048000 0x1000>; + interrupt-parent = <&sic1>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/open-pic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/open-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccbbfdc53c72780c97cb121c59faea2727689291 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/open-pic.txt @@ -0,0 +1,97 @@ +* Open PIC Binding + +This binding specifies what properties must be available in the device tree +representation of an Open PIC compliant interrupt controller. This binding is +based on the binding defined for Open PIC in [1] and is a superset of that +binding. + +Required properties: + + NOTE: Many of these descriptions were paraphrased here from [1] to aid + readability. + + - compatible: Specifies the compatibility list for the PIC. The type + shall be and the value shall include "open-pic". + + - reg: Specifies the base physical address(s) and size(s) of this + PIC's addressable register space. The type shall be . + + - interrupt-controller: The presence of this property identifies the node + as an Open PIC. No property value shall be defined. + + - #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 2. + + - #address-cells: Specifies the number of cells needed to encode an + address. The type shall be and the value shall be 0. As such, + 'interrupt-map' nodes do not have to specify a parent unit address. + +Optional properties: + + - pic-no-reset: The presence of this property indicates that the PIC + shall not be reset during runtime initialization. No property value shall + be defined. The presence of this property also mandates that any + initialization related to interrupt sources shall be limited to sources + explicitly referenced in the device tree. + +* Interrupt Specifier Definition + + Interrupt specifiers consists of 2 cells encoded as + follows: + + - <1st-cell>: The interrupt-number that identifies the interrupt source. + + - <2nd-cell>: The level-sense information, encoded as follows: + 0 = low-to-high edge triggered + 1 = active low level-sensitive + 2 = active high level-sensitive + 3 = high-to-low edge triggered + +* Examples + +Example 1: + + /* + * An Open PIC interrupt controller + */ + mpic: pic@40000 { + // This is an interrupt controller node. + interrupt-controller; + + // No address cells so that 'interrupt-map' nodes which reference + // this Open PIC node do not need a parent address specifier. + #address-cells = <0>; + + // Two cells to encode interrupt sources. + #interrupt-cells = <2>; + + // Offset address of 0x40000 and size of 0x40000. + reg = <0x40000 0x40000>; + + // Compatible with Open PIC. + compatible = "open-pic"; + + // The PIC shall not be reset. + pic-no-reset; + }; + +Example 2: + + /* + * An interrupt generating device that is wired to an Open PIC. + */ + serial0: serial@4500 { + // Interrupt source '42' that is active high level-sensitive. + // Note that there are only two cells as specified in the interrupt + // parent's '#interrupt-cells' property. + interrupts = <42 2>; + + // The interrupt controller that this device is wired to. + interrupt-parent = <&mpic>; + }; + +* References + +[1] Devicetree Specification + (https://www.devicetree.org/specifications/) + diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/opencores,or1k-pic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/opencores,or1k-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..55c04faa3f3febbfe447e7c6de29104f75acaa1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/opencores,or1k-pic.txt @@ -0,0 +1,23 @@ +OpenRISC 1000 Programmable Interrupt Controller + +Required properties: + +- compatible : should be "opencores,or1k-pic-level" for variants with + level triggered interrupt lines, "opencores,or1k-pic-edge" for variants with + edge triggered interrupt lines or "opencores,or1200-pic" for machines + with the non-spec compliant or1200 type implementation. + + "opencores,or1k-pic" is also provided as an alias to "opencores,or1200-pic", + but this is only for backwards compatibility. + +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 1. + +Example: + +intc: interrupt-controller { + compatible = "opencores,or1k-pic-level"; + interrupt-controller; + #interrupt-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/openrisc,ompic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/openrisc,ompic.txt new file mode 100644 index 0000000000000000000000000000000000000000..caec07cc71496d1b0acc8fa268039e0cecef2920 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/openrisc,ompic.txt @@ -0,0 +1,22 @@ +Open Multi-Processor Interrupt Controller + +Required properties: + +- compatible : This should be "openrisc,ompic" +- reg : Specifies base physical address and size of the register space. The + size is based on the number of cores the controller has been configured + to handle, this should be set to 8 bytes per cpu core. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : This should be set to 0 as this will not be an irq + parent. +- interrupts : Specifies the interrupt line to which the ompic is wired. + +Example: + +ompic: interrupt-controller@98000000 { + compatible = "openrisc,ompic"; + reg = <0x98000000 16>; + interrupt-controller; + #interrupt-cells = <0>; + interrupts = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qca,ath79-cpu-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qca,ath79-cpu-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..aabce7810d29ccdffc2ddca3fece515d022e4dfe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qca,ath79-cpu-intc.txt @@ -0,0 +1,44 @@ +Binding for Qualcomm Atheros AR7xxx/AR9XXX CPU interrupt controller + +On most SoC the IRQ controller need to flush the DDR FIFO before running +the interrupt handler of some devices. This is configured using the +qca,ddr-wb-channels and qca,ddr-wb-channel-interrupts properties. + +Required Properties: + +- compatible: has to be "qca,-cpu-intc", "qca,ar7100-cpu-intc" + as fallback +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode interrupt + source, should be 1 for intc + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +Optional Properties: + +- qca,ddr-wb-channel-interrupts: List of the interrupts needing a write + buffer flush +- qca,ddr-wb-channels: List of phandles to the write buffer channels for + each interrupt. If qca,ddr-wb-channel-interrupts is not present the interrupt + default to the entry's index. + +Example: + + interrupt-controller { + compatible = "qca,ar9132-cpu-intc", "qca,ar7100-cpu-intc"; + + interrupt-controller; + #interrupt-cells = <1>; + + qca,ddr-wb-channel-interrupts = <2>, <3>, <4>, <5>; + qca,ddr-wb-channels = <&ddr_ctrl 3>, <&ddr_ctrl 2>, + <&ddr_ctrl 0>, <&ddr_ctrl 1>; + }; + + ... + + ddr_ctrl: memory-controller@18000000 { + ... + #qca,ddr-wb-channel-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qca,ath79-misc-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qca,ath79-misc-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad70006c1848f4e5ab89829d5c438c12e288e66e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qca,ath79-misc-intc.txt @@ -0,0 +1,45 @@ +Binding for Qualcomm Atheros AR7xxx/AR9XXX MISC interrupt controller + +The MISC interrupt controller is a secondary controller for lower priority +interrupt. + +Required Properties: +- compatible: has to be "qca,-cpu-intc", "qca,ar7100-misc-intc" or + "qca,-cpu-intc", "qca,ar7240-misc-intc" +- reg: Base address and size of the controllers memory area +- interrupts: Interrupt specifier for the controllers interrupt. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode interrupt + source, should be 1 + +Compatible fallback depends on the SoC. Use ar7100 for ar71xx and ar913x, +use ar7240 for all other SoCs. + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +Example: + + interrupt-controller@18060010 { + compatible = "qca,ar9132-misc-intc", "qca,ar7100-misc-intc"; + reg = <0x18060010 0x4>; + + interrupt-parent = <&cpuintc>; + interrupts = <6>; + + interrupt-controller; + #interrupt-cells = <1>; + }; + +Another example: + + interrupt-controller@18060010 { + compatible = "qca,ar9331-misc-intc", qca,ar7240-misc-intc"; + reg = <0x18060010 0x4>; + + interrupt-parent = <&cpuintc>; + interrupts = <6>; + + interrupt-controller; + #interrupt-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qcom,mpm.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qcom,mpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..f67d2c3f6ac1f2aa46c61407ef5d7895b9fa5f5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qcom,mpm.txt @@ -0,0 +1,110 @@ +QTI MPM interrupt controller +MPM (MSM sleep Power Manager) is QTI's platform parent +interrupt controller. It manages subsystem wakeups and +resources during sleep. This driver marks the wakeup +interrupts in APSS such that it monitors the interrupts +when the system is asleep, wakes up the APSS when one +of these interrupts occur and replays it to the subsystem +interrupt controller after it becomes operational. + +Platform interrupt controller MPM is next in hierarchy, +followed by others. + +This defines 2 interrupt controllers to monitor the +interrupts when system is asleep: + +One to monitor the wakeup capable gic interrupts called +wakegic. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,mpm-gic" and the respective + target compatible flag from below ones. + "qcom,mpm-gic-msm8953", + "qcom,mpm-gic-msm8937", + "qcom,mpm-gic-qcs405" + "qcom,mpm-gic-trinket" + "qcom,mpm-gic-bengal" + "qcom,mpm-gic-scuba" + "qcom,mpm-gic-sdm660" + +- interrupts: + Usage: required + Value type: + Definition: should specify the IRQ used by remote processor to + wakeup APSS. + +- interrupt-parent: + Usage: required + Value type: + Definition: Specifies the interrupt parent necessary for + hierarchical domain to operate. + +- interrupt-controller: + Usage: required + Value type: + Definition: Identifies the node as an interrupt controller. + +- reg: + Usage: required + Value type: + Definition: Specifies the base physical address to trigger an + interrupt into remote processor. + +-reg-names: + Usage: required + Value type: , + Definition: Specifies the address field names. + +- qcom,num-mpm-irqs: + Usage: optional + Value type: + Defination: Specifies the number of interrupts supported. + +Example: + +wakegic: wake-gic@7781b8 { + compatible = "qcom,mpm-gic", "qcom,mpm-gic-bengal"; + interrupts = ; + reg = <0x601d4 0x1000>, + <0xb011008 0x4>; /* MSM_APCS_GCC_BASE 4K */ + reg-names = "vmpm", "ipc"; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <3>; +}; + + +One to monitor the wakeup capable gpio interrupts called wakegpio. + +properties: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,mpm-gpio" and the respective + target compatible flag from below ones. + "qcom,mpm-gpio", + +- interrupt-parent: + Usage: required + Value type: + Definition: Specifies the interrupt parent necessary for + hierarchical domain to operate. + +- interrupt-controller: + Usage: required + Value type: + Definition: Identifies the node as an interrupt controller. + +Example: + +wakegpio: wake-gpio { + compatible = "qcom,mpm-gpio"; + interrupt-controller; + interrupt-parent = <&tlmm>; + #interrupt-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qcom,pdc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qcom,pdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..031d78ce7e8ae8458b211562f434b7e08ec34d81 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/qcom,pdc.txt @@ -0,0 +1,74 @@ +PDC interrupt controller + +Qualcomm Technologies Inc. SoCs based on the RPM Hardened architecture have a +Power Domain Controller (PDC) that is on always-on domain. In addition to +providing power control for the power domains, the hardware also has an +interrupt controller that can be used to help detect edge low interrupts as +well detect interrupts when the GIC is non-operational. + +GIC is parent interrupt controller at the highest level. Platform interrupt +controller PDC is next in hierarchy, followed by others. Drivers requiring +wakeup capabilities of their device interrupts routed through the PDC, must +specify PDC as their interrupt controller and request the PDC port associated +with the GIC interrupt. See example below. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,-pdc" + - "qcom,sdm845-pdc": For SDM845 + - "qcom,lagoon-pdc": For Lagoon + +- reg: + Usage: required + Value type: + Definition: Specifies the base physical address for PDC hardware and + the interrupt type configuration register. + +- interrupt-cells: + Usage: required + Value type: + Definition: Specifies the number of cells needed to encode an interrupt + source. + Must be 2. + The first element of the tuple is the PDC pin for the + interrupt. + The second element is the trigger type. + +- interrupt-controller: + Usage: required + Value type: + Definition: Identifies the node as an interrupt controller. + +- qcom,pdc-ranges: + Usage: required + Value type: + Definition: Specifies the PDC pin offset and the number of PDC ports. + The tuples indicates the valid mapping of valid PDC ports + and their hwirq mapping. + The first element of the tuple is the starting PDC port. + The second element is the GIC hwirq number for the PDC port. + The third element is the number of interrupts in sequence. + +Example: + + pdc: interrupt-controller@b220000 { + compatible = "qcom,sdm845-pdc"; + reg = <0xb220000 0x30000>, <0x179900f0 0x60>; + qcom,pdc-ranges = <0 480 94>, <94 609 15>, <115 630 7>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + +DT binding of a device that wants to use the GIC SPI 482 as a wakeup +interrupt, must do - + + wake-device { + interrupts-extended = <&pdc 2 IRQ_TYPE_LEVEL_HIGH>; + }; + +In this case interrupt 514 would be mapped to port 2 on the PDC as defined by +the qcom,pdc-ranges property. diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,h8300h-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,h8300h-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..56e8d82aff342845a19e992762ac67d4fff992db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,h8300h-intc.txt @@ -0,0 +1,22 @@ +* H8/300H Interrupt controller + +Required properties: + +- compatible: has to be "renesas,h8300h-intc", "renesas,h8300-intc" as fallback. +- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in + interrupts.txt in this directory +- regs: Base address of interrupt controller registers. + +Optional properties: + +- any properties, listed in interrupts.txt, and any standard resource allocation + properties + +Example: + + h8intc: interrupt-controller@fee012 { + compatible = "renesas,h8300h-intc", "renesas,h8300-intc"; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0xfee012 7>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,h8s-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,h8s-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..faded2b1559b8bdda5800229edf5f622bf41339e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,h8s-intc.txt @@ -0,0 +1,22 @@ +* H8S Interrupt controller + +Required properties: + +- compatible: has to be "renesas,h8s-intc", "renesas,h8300-intc" as fallback. +- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in + interrupts.txt in this directory +- regs: Base address of interrupt controller registers. + +Optional properties: + +- any properties, listed in interrupts.txt, and any standard resource allocation + properties + +Example: + + h8intc: interrupt-controller@fffe00 { + compatible = "renesas,h8s-intc", "renesas,h8300-intc"; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0xfffe00 24>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,intc-irqpin.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,intc-irqpin.txt new file mode 100644 index 0000000000000000000000000000000000000000..772c550d3b4bcfe23d05f48496f871ed5db5186e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,intc-irqpin.txt @@ -0,0 +1,62 @@ +DT bindings for the R-/SH-Mobile irqpin controller + +Required properties: + +- compatible: has to be "renesas,intc-irqpin-", "renesas,intc-irqpin" + as fallback. + Examples with soctypes are: + - "renesas,intc-irqpin-r8a7740" (R-Mobile A1) + - "renesas,intc-irqpin-r8a7778" (R-Car M1A) + - "renesas,intc-irqpin-r8a7779" (R-Car H1) + - "renesas,intc-irqpin-sh73a0" (SH-Mobile AG5) + +- reg: Base address and length of each register bank used by the external + IRQ pins driven by the interrupt controller hardware module. The base + addresses, length and number of required register banks varies with soctype. +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in + interrupts.txt in this directory. +- interrupts: Must contain a list of interrupt specifiers. For each interrupt + provided by this irqpin controller instance, there must be one entry, + referring to the corresponding parent interrupt. + +Optional properties: + +- any properties, listed in interrupts.txt, and any standard resource allocation + properties +- sense-bitfield-width: width of a single sense bitfield in the SENSE register, + if different from the default 4 bits +- control-parent: disable and enable interrupts on the parent interrupt + controller, needed for some broken implementations +- clocks: Must contain a reference to the functional clock. This property is + mandatory if the hardware implements a controllable functional clock for + the irqpin controller instance. +- power-domains: Must contain a reference to the power domain. This property is + mandatory if the irqpin controller instance is part of a controllable power + domain. + + +Example +------- + + irqpin1: interrupt-controller@e6900004 { + compatible = "renesas,intc-irqpin-r8a7740", + "renesas,intc-irqpin"; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0xe6900004 4>, + <0xe6900014 4>, + <0xe6900024 1>, + <0xe6900044 1>, + <0xe6900064 1>; + interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7740_CLK_INTCA>; + power-domains = <&pd_a4s>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,irqc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,irqc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a046ed374d808d668195082afc950c5b14beff62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/renesas,irqc.txt @@ -0,0 +1,44 @@ +DT bindings for the R-Mobile/R-Car/RZ/G interrupt controller + +Required properties: + +- compatible: has to be "renesas,irqc-", "renesas,irqc" as fallback. + Examples with soctypes are: + - "renesas,irqc-r8a73a4" (R-Mobile APE6) + - "renesas,irqc-r8a7743" (RZ/G1M) + - "renesas,irqc-r8a7745" (RZ/G1E) + - "renesas,irqc-r8a77470" (RZ/G1C) + - "renesas,irqc-r8a7790" (R-Car H2) + - "renesas,irqc-r8a7791" (R-Car M2-W) + - "renesas,irqc-r8a7792" (R-Car V2H) + - "renesas,irqc-r8a7793" (R-Car M2-N) + - "renesas,irqc-r8a7794" (R-Car E2) + - "renesas,intc-ex-r8a774a1" (RZ/G2M) + - "renesas,intc-ex-r8a7795" (R-Car H3) + - "renesas,intc-ex-r8a7796" (R-Car M3-W) + - "renesas,intc-ex-r8a77965" (R-Car M3-N) + - "renesas,intc-ex-r8a77970" (R-Car V3M) + - "renesas,intc-ex-r8a77980" (R-Car V3H) + - "renesas,intc-ex-r8a77995" (R-Car D3) +- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in + interrupts.txt in this directory +- clocks: Must contain a reference to the functional clock. + +Optional properties: + +- any properties, listed in interrupts.txt, and any standard resource allocation + properties + +Example: + + irqc0: interrupt-controller@e61c0000 { + compatible = "renesas,irqc-r8a7790", "renesas,irqc"; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0 0xe61c0000 0 0x200>; + interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>, + <0 1 IRQ_TYPE_LEVEL_HIGH>, + <0 2 IRQ_TYPE_LEVEL_HIGH>, + <0 3 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp4_clks R8A7790_CLK_IRQC>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/riscv,cpu-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/riscv,cpu-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..265b223cd9780158a8415e96ce7dfb16c192237a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/riscv,cpu-intc.txt @@ -0,0 +1,52 @@ +RISC-V Hart-Level Interrupt Controller (HLIC) +--------------------------------------------- + +RISC-V cores include Control Status Registers (CSRs) which are local to each +CPU core (HART in RISC-V terminology) and can be read or written by software. +Some of these CSRs are used to control local interrupts connected to the core. +Every interrupt is ultimately routed through a hart's HLIC before it +interrupts that hart. + +The RISC-V supervisor ISA manual specifies three interrupt sources that are +attached to every HLIC: software interrupts, the timer interrupt, and external +interrupts. Software interrupts are used to send IPIs between cores. The +timer interrupt comes from an architecturally mandated real-time timer that is +controlled via Supervisor Binary Interface (SBI) calls and CSR reads. External +interrupts connect all other device interrupts to the HLIC, which are routed +via the platform-level interrupt controller (PLIC). + +All RISC-V systems that conform to the supervisor ISA specification are +required to have a HLIC with these three interrupt sources present. Since the +interrupt map is defined by the ISA it's not listed in the HLIC's device tree +entry, though external interrupt controllers (like the PLIC, for example) will +need to define how their interrupts map to the relevant HLICs. This means +a PLIC interrupt property will typically list the HLICs for all present HARTs +in the system. + +Required properties: +- compatible : "riscv,cpu-intc" +- #interrupt-cells : should be <1>. The interrupt sources are defined by the + RISC-V supervisor ISA manual, with only the following three interrupts being + defined for supervisor mode: + - Source 1 is the supervisor software interrupt, which can be sent by an SBI + call and is reserved for use by software. + - Source 5 is the supervisor timer interrupt, which can be configured by + SBI calls and implements a one-shot timer. + - Source 9 is the supervisor external interrupt, which chains to all other + device interrupts. +- interrupt-controller : Identifies the node as an interrupt controller + +Furthermore, this interrupt-controller MUST be embedded inside the cpu +definition of the hart whose CSRs control these local interrupts. + +An example device tree entry for a HLIC is show below. + + cpu1: cpu@1 { + compatible = "riscv"; + ... + cpu1-intc: interrupt-controller { + #interrupt-cells = <1>; + compatible = "sifive,fu540-c000-cpu-intc", "riscv,cpu-intc"; + interrupt-controller; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/samsung,exynos4210-combiner.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/samsung,exynos4210-combiner.txt new file mode 100644 index 0000000000000000000000000000000000000000..19af687858a1dde70bd5604934a6f665ff1f3f4b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/samsung,exynos4210-combiner.txt @@ -0,0 +1,50 @@ +* Samsung Exynos Interrupt Combiner Controller + +Samsung's Exynos4 architecture includes a interrupt combiner controller which +can combine interrupt sources as a group and provide a single interrupt request +for the group. The interrupt request from each group are connected to a parent +interrupt controller, such as GIC in case of Exynos4210. + +The interrupt combiner controller consists of multiple combiners. Up to eight +interrupt sources can be connected to a combiner. The combiner outputs one +combined interrupt for its eight interrupt sources. The combined interrupt +is usually connected to a parent interrupt controller. + +A single node in the device tree is used to describe the interrupt combiner +controller module (which includes multiple combiners). A combiner in the +interrupt controller module shares config/control registers with other +combiners. For example, a 32-bit interrupt enable/disable config register +can accommodate up to 4 interrupt combiners (with each combiner supporting +up to 8 interrupt sources). + +Required properties: +- compatible: should be "samsung,exynos4210-combiner". +- interrupt-controller: Identifies the node as an interrupt controller. +- #interrupt-cells: should be <2>. The meaning of the cells are + * First Cell: Combiner Group Number. + * Second Cell: Interrupt number within the group. +- reg: Base address and size of interrupt combiner registers. +- interrupts: The list of interrupts generated by the combiners which are then + connected to a parent interrupt controller. The format of the interrupt + specifier depends in the interrupt parent controller. + +Optional properties: +- samsung,combiner-nr: The number of interrupt combiners supported. If this + property is not specified, the default number of combiners is assumed + to be 16. + + +Example: + + The following is a an example from the Exynos4210 SoC dtsi file. + + combiner:interrupt-controller@10440000 { + compatible = "samsung,exynos4210-combiner"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x10440000 0x1000>; + interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>, + <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>, + <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>, + <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/samsung,s3c24xx-irq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/samsung,s3c24xx-irq.txt new file mode 100644 index 0000000000000000000000000000000000000000..c54c5a9a2a9085935096b502f606d40acebaa9c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/samsung,s3c24xx-irq.txt @@ -0,0 +1,53 @@ +Samsung S3C24XX Interrupt Controllers + +The S3C24XX SoCs contain a custom set of interrupt controllers providing a +varying number of interrupt sources. The set consists of a main- and sub- +controller and on newer SoCs even a second main controller. + +Required properties: +- compatible: Compatible property value should be "samsung,s3c2410-irq" + for machines before s3c2416 and "samsung,s3c2416-irq" for s3c2416 and later. + +- reg: Physical base address of the controller and length of memory mapped + region. + +- interrupt-controller : Identifies the node as an interrupt controller + +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value shall be 4 and interrupt descriptor shall + have the following format: + + + ctrl_num contains the controller to use: + - 0 ... main controller + - 1 ... sub controller + - 2 ... second main controller on s3c2416 and s3c2450 + parent_irq contains the parent bit in the main controller and will be + ignored in main controllers + ctrl_irq contains the interrupt bit of the controller + type contains the trigger type to use + +Example: + + interrupt-controller@4a000000 { + compatible = "samsung,s3c2410-irq"; + reg = <0x4a000000 0x100>; + interrupt-controller; + #interrupt-cells=<4>; + }; + + [...] + + serial@50000000 { + compatible = "samsung,s3c2410-uart"; + reg = <0x50000000 0x4000>; + interrupt-parent = <&subintc>; + interrupts = <1 28 0 4>, <1 28 1 4>; + }; + + rtc@57000000 { + compatible = "samsung,s3c2410-rtc"; + reg = <0x57000000 0x100>; + interrupt-parent = <&intc>; + interrupts = <0 30 0 3>, <0 8 0 3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/sifive,plic-1.0.0.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/sifive,plic-1.0.0.txt new file mode 100644 index 0000000000000000000000000000000000000000..6adf7a6e8825e6a817a2c8456a810dafab7e025d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/sifive,plic-1.0.0.txt @@ -0,0 +1,58 @@ +SiFive Platform-Level Interrupt Controller (PLIC) +------------------------------------------------- + +SiFive SOCs include an implementation of the Platform-Level Interrupt Controller +(PLIC) high-level specification in the RISC-V Privileged Architecture +specification. The PLIC connects all external interrupts in the system to all +hart contexts in the system, via the external interrupt source in each hart. + +A hart context is a privilege mode in a hardware execution thread. For example, +in an 4 core system with 2-way SMT, you have 8 harts and probably at least two +privilege modes per hart; machine mode and supervisor mode. + +Each interrupt can be enabled on per-context basis. Any context can claim +a pending enabled interrupt and then release it once it has been handled. + +Each interrupt has a configurable priority. Higher priority interrupts are +serviced first. Each context can specify a priority threshold. Interrupts +with priority below this threshold will not cause the PLIC to raise its +interrupt line leading to the context. + +While the PLIC supports both edge-triggered and level-triggered interrupts, +interrupt handlers are oblivious to this distinction and therefore it is not +specified in the PLIC device-tree binding. + +While the RISC-V ISA doesn't specify a memory layout for the PLIC, the +"sifive,plic-1.0.0" device is a concrete implementation of the PLIC that +contains a specific memory layout, which is documented in chapter 8 of the +SiFive U5 Coreplex Series Manual . + +Required properties: +- compatible : "sifive,plic-1.0.0" and a string identifying the actual + detailed implementation in case that specific bugs need to be worked around. +- #address-cells : should be <0> or more. +- #interrupt-cells : should be <1> or more. +- interrupt-controller : Identifies the node as an interrupt controller. +- reg : Should contain 1 register range (address and length). +- interrupts-extended : Specifies which contexts are connected to the PLIC, + with "-1" specifying that a context is not present. Each node pointed + to should be a riscv,cpu-intc node, which has a riscv node as parent. +- riscv,ndev: Specifies how many external interrupts are supported by + this controller. + +Example: + + plic: interrupt-controller@c000000 { + #address-cells = <0>; + #interrupt-cells = <1>; + compatible = "sifive,plic-1.0.0", "sifive,fu540-c000-plic"; + interrupt-controller; + interrupts-extended = < + &cpu0-intc 11 + &cpu1-intc 11 &cpu1-intc 9 + &cpu2-intc 11 &cpu2-intc 9 + &cpu3-intc 11 &cpu3-intc 9 + &cpu4-intc 11 &cpu4-intc 9>; + reg = <0xc000000 0x4000000>; + riscv,ndev = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/sigma,smp8642-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/sigma,smp8642-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..355c18a3a4d30ddb3bdeedfd39e204c67cf7c896 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/sigma,smp8642-intc.txt @@ -0,0 +1,48 @@ +Sigma Designs SMP86xx/SMP87xx secondary interrupt controller + +Required properties: +- compatible: should be "sigma,smp8642-intc" +- reg: physical address of MMIO region +- ranges: address space mapping of child nodes +- interrupt-controller: boolean +- #address-cells: should be <1> +- #size-cells: should be <1> + +One child node per control block with properties: +- reg: address of registers for this control block +- interrupt-controller: boolean +- #interrupt-cells: should be <2>, interrupt index and flags per interrupts.txt +- interrupts: interrupt spec of primary interrupt controller + +Example: + +interrupt-controller@6e000 { + compatible = "sigma,smp8642-intc"; + reg = <0x6e000 0x400>; + ranges = <0x0 0x6e000 0x400>; + interrupt-parent = <&gic>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <1>; + + irq0: interrupt-controller@0 { + reg = <0x000 0x100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + irq1: interrupt-controller@100 { + reg = <0x100 0x100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + + irq2: interrupt-controller@300 { + reg = <0x300 0x100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,arc700-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,arc700-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a5d562435ea770b668bac8603ce38398cd60523 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,arc700-intc.txt @@ -0,0 +1,24 @@ +* ARC700 incore Interrupt Controller + + The core interrupt controller provides 32 prioritised interrupts (2 levels) + to ARC700 core. + +Properties: + +- compatible: "snps,arc700-intc" +- interrupt-controller: This is an interrupt controller. +- #interrupt-cells: Must be <1>. + + Single Cell "interrupts" property of a device specifies the IRQ number + between 0 to 31 + + intc accessed via the special ARC AUX register interface, hence "reg" property + is not specified. + +Example: + + intc: interrupt-controller { + compatible = "snps,arc700-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,archs-idu-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,archs-idu-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..09fc02b9984577860563661d881d88f3308a489a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,archs-idu-intc.txt @@ -0,0 +1,36 @@ +* ARC-HS Interrupt Distribution Unit + + This optional 2nd level interrupt controller can be used in SMP configurations for + dynamic IRQ routing, load balancing of common/external IRQs towards core intc. + +Properties: + +- compatible: "snps,archs-idu-intc" +- interrupt-controller: This is an interrupt controller. +- #interrupt-cells: Must be <1>. + + Value of the cell specifies the "common" IRQ from peripheral to IDU. Number N + of the particular interrupt line of IDU corresponds to the line N+24 of the + core interrupt controller. + + intc accessed via the special ARC AUX register interface, hence "reg" property + is not specified. + +Example: + core_intc: core-interrupt-controller { + compatible = "snps,archs-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + + idu_intc: idu-interrupt-controller { + compatible = "snps,archs-idu-intc"; + interrupt-controller; + interrupt-parent = <&core_intc>; + #interrupt-cells = <1>; + }; + + some_device: serial@c0fc1000 { + interrupt-parent = <&idu_intc>; + interrupts = <0>; /* upstream idu IRQ #24 */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,archs-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,archs-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..69f326d6a5ad2be038c127101d8e39d82882ef66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,archs-intc.txt @@ -0,0 +1,22 @@ +* ARC-HS incore Interrupt Controller (Provided by cores implementing ARCv2 ISA) + +Properties: + +- compatible: "snps,archs-intc" +- interrupt-controller: This is an interrupt controller. +- #interrupt-cells: Must be <1>. + + Single Cell "interrupts" property of a device specifies the IRQ number + between 16 to 256 + + intc accessed via the special ARC AUX register interface, hence "reg" property + is not specified. + +Example: + + intc: interrupt-controller { + compatible = "snps,archs-intc"; + interrupt-controller; + #interrupt-cells = <1>; + interrupts = <16 17 18 19 20 21 22 23 24 25>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,dw-apb-ictl.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,dw-apb-ictl.txt new file mode 100644 index 0000000000000000000000000000000000000000..086ff08322db94fca1053899f705d594f4805c51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/snps,dw-apb-ictl.txt @@ -0,0 +1,31 @@ +Synopsys DesignWare APB interrupt controller (dw_apb_ictl) + +Synopsys DesignWare provides interrupt controller IP for APB known as +dw_apb_ictl. The IP is used as secondary interrupt controller in some SoCs with +APB bus, e.g. Marvell Armada 1500. + +Required properties: +- compatible: shall be "snps,dw-apb-ictl" +- reg: physical base address of the controller and length of memory mapped + region starting with ENABLE_LOW register +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: number of cells to encode an interrupt-specifier, shall be 1 +- interrupts: interrupt reference to primary interrupt controller + +The interrupt sources map to the corresponding bits in the interrupt +registers, i.e. +- 0 maps to bit 0 of low interrupts, +- 1 maps to bit 1 of low interrupts, +- 32 maps to bit 0 of high interrupts, +- 33 maps to bit 1 of high interrupts, +- (optional) fast interrupts start at 64. + +Example: + aic: interrupt-controller@3000 { + compatible = "snps,dw-apb-ictl"; + reg = <0x3000 0xc00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/socionext,synquacer-exiu.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/socionext,synquacer-exiu.txt new file mode 100644 index 0000000000000000000000000000000000000000..dac0846fe78974c53ccea5937aac46a3ba7daf1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/socionext,synquacer-exiu.txt @@ -0,0 +1,31 @@ +Socionext SynQuacer External Interrupt Unit (EXIU) + +The Socionext Synquacer SoC has an external interrupt unit (EXIU) +that forwards a block of 32 configurable input lines to 32 adjacent +level-high type GICv3 SPIs. + +Required properties: + +- compatible : Should be "socionext,synquacer-exiu". +- reg : Specifies base physical address and size of the + control registers. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 3. +- socionext,spi-base : The SPI number of the first SPI of the 32 adjacent + ones the EXIU forwards its interrups to. + +Notes: + +- Only SPIs can use the EXIU as an interrupt parent. + +Example: + + exiu: interrupt-controller@510c0000 { + compatible = "socionext,synquacer-exiu"; + reg = <0x0 0x510c0000 0x0 0x20>; + interrupt-controller; + interrupt-parent = <&gic>; + #interrupt-cells = <3>; + socionext,spi-base = <112>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/socionext,uniphier-aidet.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/socionext,uniphier-aidet.txt new file mode 100644 index 0000000000000000000000000000000000000000..48e71d3ac2adfaff8f7cd5da2c42f54eb3219deb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/socionext,uniphier-aidet.txt @@ -0,0 +1,32 @@ +UniPhier AIDET + +UniPhier AIDET (ARM Interrupt Detector) is an add-on block for ARM GIC (Generic +Interrupt Controller). GIC itself can handle only high level and rising edge +interrupts. The AIDET provides logic inverter to support low level and falling +edge interrupts. + +Required properties: +- compatible: Should be one of the following: + "socionext,uniphier-ld4-aidet" - for LD4 SoC + "socionext,uniphier-pro4-aidet" - for Pro4 SoC + "socionext,uniphier-sld8-aidet" - for sLD8 SoC + "socionext,uniphier-pro5-aidet" - for Pro5 SoC + "socionext,uniphier-pxs2-aidet" - for PXs2/LD6b SoC + "socionext,uniphier-ld11-aidet" - for LD11 SoC + "socionext,uniphier-ld20-aidet" - for LD20 SoC + "socionext,uniphier-pxs3-aidet" - for PXs3 SoC +- reg: Specifies offset and length of the register set for the device. +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an interrupt + source. The value should be 2. The first cell defines the interrupt number + (corresponds to the SPI interrupt number of GIC). The second cell specifies + the trigger type as defined in interrupts.txt in this directory. + +Example: + + aidet: aidet@5fc20000 { + compatible = "socionext,uniphier-pro4-aidet"; + reg = <0x5fc20000 0x200>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,spear3xx-shirq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,spear3xx-shirq.txt new file mode 100644 index 0000000000000000000000000000000000000000..a407c499b3cc7fa11976808a3f7577badb25e4ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,spear3xx-shirq.txt @@ -0,0 +1,44 @@ +* SPEAr Shared IRQ layer (shirq) + +SPEAr3xx architecture includes shared/multiplexed irqs for certain set +of devices. The multiplexor provides a single interrupt to parent +interrupt controller (VIC) on behalf of a group of devices. + +There can be multiple groups available on SPEAr3xx variants but not +exceeding 4. The number of devices in a group can differ, further they +may share same set of status/mask registers spanning across different +bit masks. Also in some cases the group may not have enable or other +registers. This makes software little complex. + +A single node in the device tree is used to describe the shared +interrupt multiplexor (one node for all groups). A group in the +interrupt controller shares config/control registers with other groups. +For example, a 32-bit interrupt enable/disable config register can +accommodate up to 4 interrupt groups. + +Required properties: + - compatible: should be, either of + - "st,spear300-shirq" + - "st,spear310-shirq" + - "st,spear320-shirq" + - interrupt-controller: Identifies the node as an interrupt controller. + - #interrupt-cells: should be <1> which basically contains the offset + (starting from 0) of interrupts for all the groups. + - reg: Base address and size of shirq registers. + - interrupts: The list of interrupts generated by the groups which are + then connected to a parent interrupt controller. Each group is + associated with one of the interrupts, hence number of interrupts (to + parent) is equal to number of groups. The format of the interrupt + specifier depends in the interrupt parent controller. + +Example: + +The following is an example from the SPEAr320 SoC dtsi file. + +shirq: interrupt-controller@b3000000 { + compatible = "st,spear320-shirq"; + reg = <0xb3000000 0x1000>; + interrupts = <28 29 30 1>; + #interrupt-cells = <1>; + interrupt-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,sti-irq-syscfg.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,sti-irq-syscfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..ced6014061a3dcee71a430f70c440d662f9d109c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,sti-irq-syscfg.txt @@ -0,0 +1,35 @@ +STMicroelectronics STi System Configuration Controlled IRQs +----------------------------------------------------------- + +On STi based systems; External, CTI (Core Sight), PMU (Performance Management), +and PL310 L2 Cache IRQs are controlled using System Configuration registers. +This driver is used to unmask them prior to use. + +Required properties: +- compatible : Should be set to one of: + "st,stih415-irq-syscfg" + "st,stih416-irq-syscfg" + "st,stih407-irq-syscfg" + "st,stid127-irq-syscfg" +- st,syscfg : Phandle to Cortex-A9 IRQ system config registers +- st,irq-device : Array of IRQs to enable - should be 2 in length +- st,fiq-device : Array of FIQs to enable - should be 2 in length + +Optional properties: +- st,invert-ext : External IRQs can be inverted at will. This property inverts + these IRQs using bitwise logic. A number of defines have been + provided for convenience: + ST_IRQ_SYSCFG_EXT_1_INV + ST_IRQ_SYSCFG_EXT_2_INV + ST_IRQ_SYSCFG_EXT_3_INV +Example: + +irq-syscfg { + compatible = "st,stih416-irq-syscfg"; + st,syscfg = <&syscfg_cpu>; + st,irq-device = , + ; + st,fiq-device = , + ; + st,invert-ext = <(ST_IRQ_SYSCFG_EXT_1_INV | ST_IRQ_SYSCFG_EXT_3_INV)>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,stm32-exti.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,stm32-exti.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a36bf66d932d42320cfc6b3c998b16488609d61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/st,stm32-exti.txt @@ -0,0 +1,25 @@ +STM32 External Interrupt Controller + +Required properties: + +- compatible: Should be: + "st,stm32-exti" + "st,stm32h7-exti" + "st,stm32mp1-exti" +- reg: Specifies base physical address and size of the registers +- interrupt-controller: Indentifies the node as an interrupt controller +- #interrupt-cells: Specifies the number of cells to encode an interrupt + specifier, shall be 2 +- interrupts: interrupts references to primary interrupt controller + (only needed for exti controller with multiple exti under + same parent interrupt: st,stm32-exti and st,stm32h7-exti) + +Example: + +exti: interrupt-controller@40013c00 { + compatible = "st,stm32-exti"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x40013C00 0x400>; + interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <42>, <62>, <76>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/technologic,ts4800.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/technologic,ts4800.txt new file mode 100644 index 0000000000000000000000000000000000000000..341ae5909333feeb198803eab797298309951ee8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/technologic,ts4800.txt @@ -0,0 +1,14 @@ +TS-4800 FPGA interrupt controller + +TS-4800 FPGA has an internal interrupt controller. When one of the +interrupts is triggered, the SoC is notified, usually using a GPIO as +parent interrupt source. + +Required properties: +- compatible: should be "technologic,ts4800-irqc" +- interrupt-controller: identifies the node as an interrupt controller +- reg: physical base address of the controller and length of memory mapped + region +- #interrupt-cells: specifies the number of cells needed to encode an interrupt + source, should be 1. +- interrupts: specifies the interrupt line in the interrupt-parent controller diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,c64x+megamod-pic.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,c64x+megamod-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee3f9c35150115f548814c68f500662cbaf40bc6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,c64x+megamod-pic.txt @@ -0,0 +1,103 @@ +C6X Interrupt Chips +------------------- + +* C64X+ Core Interrupt Controller + + The core interrupt controller provides 16 prioritized interrupts to the + C64X+ core. Priority 0 and 1 are used for reset and NMI respectively. + Priority 2 and 3 are reserved. Priority 4-15 are used for interrupt + sources coming from outside the core. + + Required properties: + -------------------- + - compatible: Should be "ti,c64x+core-pic"; + - #interrupt-cells: <1> + + Interrupt Specifier Definition + ------------------------------ + Single cell specifying the core interrupt priority level (4-15) where + 4 is highest priority and 15 is lowest priority. + + Example + ------- + core_pic: interrupt-controller@0 { + interrupt-controller; + #interrupt-cells = <1>; + compatible = "ti,c64x+core-pic"; + }; + + + +* C64x+ Megamodule Interrupt Controller + + The megamodule PIC consists of four interrupt mupliplexers each of which + combine up to 32 interrupt inputs into a single interrupt output which + may be cascaded into the core interrupt controller. The megamodule PIC + has a total of 12 outputs cascading into the core interrupt controller. + One for each core interrupt priority level. In addition to the combined + interrupt sources, individual megamodule interrupts may be cascaded to + the core interrupt controller. When an individual interrupt is cascaded, + it is no longer handled through a megamodule interrupt combiner and is + considered to have the core interrupt controller as the parent. + + Required properties: + -------------------- + - compatible: "ti,c64x+megamod-pic" + - interrupt-controller + - #interrupt-cells: <1> + - reg: base address and size of register area + - interrupts: This should have four cells; one for each interrupt combiner. + The cells contain the core priority interrupt to which the + corresponding combiner output is wired. + + Optional properties: + -------------------- + - ti,c64x+megamod-pic-mux: Array of 12 cells correspnding to the 12 core + priority interrupts. The first cell corresponds to + core priority 4 and the last cell corresponds to + core priority 15. The value of each cell is the + megamodule interrupt source which is MUXed to + the core interrupt corresponding to the cell + position. Allowed values are 4 - 127. Mapping for + interrupts 0 - 3 (combined interrupt sources) are + ignored. + + Interrupt Specifier Definition + ------------------------------ + Single cell specifying the megamodule interrupt source (4-127). Note that + interrupts mapped directly to the core with "ti,c64x+megamod-pic-mux" will + use the core interrupt controller as their parent and the specifier will + be the core priority level, not the megamodule interrupt number. + + Examples + -------- + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + interrupts = < 12 13 14 15 >; + }; + + This is a minimal example where all individual interrupts go through a + combiner. Combiner-0 is mapped to core interrupt 12, combiner-1 is mapped + to interrupt 13, etc. + + + megamod_pic: interrupt-controller@1800000 { + compatible = "ti,c64x+megamod-pic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x1800000 0x1000>; + interrupt-parent = <&core_pic>; + interrupts = < 12 13 14 15 >; + ti,c64x+megamod-pic-mux = < 0 0 0 0 + 32 0 0 0 + 0 0 0 0 >; + }; + + This the same as the first example except that megamodule interrupt 32 is + mapped directly to core priority interrupt 8. The node using this interrupt + must set the core controller as its interrupt parent and use 8 in the + interrupt specifier value. diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,cp-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,cp-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..597e8a089fe4348016af913148dd08dd6f5869ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,cp-intc.txt @@ -0,0 +1,27 @@ +* TI Common Platform Interrupt Controller + +Common Platform Interrupt Controller (cp_intc) is used on +OMAP-L1x SoCs and can support several configurable number +of interrupts. + +Main node required properties: + +- compatible : should be: + "ti,cp-intc" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 1. + + The cell contains the interrupt number in the range [0-128]. +- ti,intc-size: Number of interrupts handled by the interrupt controller. +- reg: physical base address and size of the intc registers map. + +Example: + + intc: interrupt-controller@1 { + compatible = "ti,cp-intc"; + interrupt-controller; + #interrupt-cells = <1>; + ti,intc-size = <101>; + reg = <0xfffee000 0x2000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,keystone-irq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,keystone-irq.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f94d7739d8d27916c7331083f4f817e1860c732 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,keystone-irq.txt @@ -0,0 +1,36 @@ +Keystone 2 IRQ controller IP + +On Keystone SOCs, DSP cores can send interrupts to ARM +host using the IRQ controller IP. It provides 28 IRQ signals to ARM. +The IRQ handler running on HOST OS can identify DSP signal source by +analyzing SRCCx bits in IPCARx registers. This is one of the component +used by the IPC mechanism used on Keystone SOCs. + +Required Properties: +- compatible: should be "ti,keystone-irq" +- ti,syscon-dev : phandle and offset pair. The phandle to syscon used to + access device control registers and the offset inside + device control registers range. +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode interrupt + source should be 1. +- interrupts: interrupt reference to primary interrupt controller + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +Example: + kirq0: keystone_irq0@26202a0 { + compatible = "ti,keystone-irq"; + ti,syscon-dev = <&devctrl 0x2a0>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + }; + + dsp0: dsp0 { + compatible = "linux,rproc-user"; + ... + interrupt-parent = <&kirq0>; + interrupts = <10 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap-intc-irq.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap-intc-irq.txt new file mode 100644 index 0000000000000000000000000000000000000000..38ce5d037722989cb2938a30914e155b3ff7d84e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap-intc-irq.txt @@ -0,0 +1,28 @@ +Omap2/3 intc controller + +On TI omap2 and 3 the intc interrupt controller can provide +96 or 128 IRQ signals to the ARM host depending on the SoC. + +Required Properties: +- compatible: should be one of + "ti,omap2-intc" + "ti,omap3-intc" + "ti,dm814-intc" + "ti,dm816-intc" + "ti,am33xx-intc" + +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode interrupt + source, should be 1 for intc +- interrupts: interrupt reference to primary interrupt controller + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +Example: + intc: interrupt-controller@48200000 { + compatible = "ti,omap3-intc"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x48200000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap2-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap2-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2583e6ec0609d92a518ddb20a0290314ca18063 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap2-intc.txt @@ -0,0 +1,27 @@ +* OMAP Interrupt Controller + +OMAP2/3 are using a TI interrupt controller that can support several +configurable number of interrupts. + +Main node required properties: + +- compatible : should be: + "ti,omap2-intc" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The type shall be a and the value shall be 1. + + The cell contains the interrupt number in the range [0-128]. +- ti,intc-size: Number of interrupts handled by the interrupt controller. +- reg: physical base address and size of the intc registers map. + +Example: + + intc: interrupt-controller@1 { + compatible = "ti,omap2-intc"; + interrupt-controller; + #interrupt-cells = <1>; + ti,intc-size = <96>; + reg = <0x48200000 0x1000>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap4-wugen-mpu b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap4-wugen-mpu new file mode 100644 index 0000000000000000000000000000000000000000..422d6908f8b2afd4483768377c902b141aabdef9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/ti,omap4-wugen-mpu @@ -0,0 +1,31 @@ +TI OMAP4 Wake-up Generator + +All TI OMAP4/5 (and their derivatives) an interrupt controller that +routes interrupts to the GIC, and also serves as a wakeup source. It +is also referred to as "WUGEN-MPU", hence the name of the binding. + +Required properties: + +- compatible : should contain at least "ti,omap4-wugen-mpu" or + "ti,omap5-wugen-mpu" +- reg : Specifies base physical address and size of the registers. +- interrupt-controller : Identifies the node as an interrupt controller. +- #interrupt-cells : Specifies the number of cells needed to encode an + interrupt source. The value must be 3. + +Notes: + +- Because this HW ultimately routes interrupts to the GIC, the + interrupt specifier must be that of the GIC. +- Only SPIs can use the WUGEN as an interrupt parent. SGIs and PPIs + are explicitly forbidden. + +Example: + + wakeupgen: interrupt-controller@48281000 { + compatible = "ti,omap5-wugen-mpu", "ti,omap4-wugen-mpu"; + interrupt-controller; + #interrupt-cells = <3>; + reg = <0x48281000 0x1000>; + interrupt-parent = <&gic>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/via,vt8500-intc.txt b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/via,vt8500-intc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a4ce1051b0252bbbdeef3288b90e9913d3f16f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/interrupt-controller/via,vt8500-intc.txt @@ -0,0 +1,16 @@ +VIA/Wondermedia VT8500 Interrupt Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-intc" +- reg : Should contain 1 register ranges(address and length) +- #interrupt-cells : should be <1> + +Example: + + intc: interrupt-controller@d8140000 { + compatible = "via,vt8500-intc"; + interrupt-controller; + reg = <0xd8140000 0x10000>; + #interrupt-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/arm,smmu-v3.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/arm,smmu-v3.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9abbf3e4f68238faaa287dc9fb2222af0e4c236 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/arm,smmu-v3.txt @@ -0,0 +1,77 @@ +* ARM SMMUv3 Architecture Implementation + +The SMMUv3 architecture is a significant departure from previous +revisions, replacing the MMIO register interface with in-memory command +and event queues and adding support for the ATS and PRI components of +the PCIe specification. + +** SMMUv3 required properties: + +- compatible : Should include: + + * "arm,smmu-v3" for any SMMUv3 compliant + implementation. This entry should be last in the + compatible list. + +- reg : Base address and size of the SMMU. + +- interrupts : Non-secure interrupt list describing the wired + interrupt sources corresponding to entries in + interrupt-names. If no wired interrupts are + present then this property may be omitted. + +- interrupt-names : When the interrupts property is present, should + include the following: + * "eventq" - Event Queue not empty + * "priq" - PRI Queue not empty + * "cmdq-sync" - CMD_SYNC complete + * "gerror" - Global Error activated + * "combined" - The combined interrupt is optional, + and should only be provided if the + hardware supports just a single, + combined interrupt line. + If provided, then the combined interrupt + will be used in preference to any others. + +- #iommu-cells : See the generic IOMMU binding described in + devicetree/bindings/pci/pci-iommu.txt + for details. For SMMUv3, must be 1, with each cell + describing a single stream ID. All possible stream + IDs which a device may emit must be described. + +** SMMUv3 optional properties: + +- dma-coherent : Present if DMA operations made by the SMMU (page + table walks, stream table accesses etc) are cache + coherent with the CPU. + + NOTE: this only applies to the SMMU itself, not + masters connected upstream of the SMMU. + +- msi-parent : See the generic MSI binding described in + devicetree/bindings/interrupt-controller/msi.txt + for a description of the msi-parent property. + +- hisilicon,broken-prefetch-cmd + : Avoid sending CMD_PREFETCH_* commands to the SMMU. + +- cavium,cn9900-broken-page1-regspace + : Replaces all page 1 offsets used for EVTQ_PROD/CONS, + PRIQ_PROD/CONS register access with page 0 offsets. + Set for Cavium ThunderX2 silicon that doesn't support + SMMU page1 register space. + +** Example + + smmu@2b400000 { + compatible = "arm,smmu-v3"; + reg = <0x0 0x2b400000 0x0 0x20000>; + interrupts = , + , + , + ; + interrupt-names = "eventq", "priq", "cmdq-sync", "gerror"; + dma-coherent; + #iommu-cells = <1>; + msi-parent = <&its 0xff0000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/arm,smmu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/arm,smmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f22b57d4639c4e71df34aded95a6996b0bf9771 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/arm,smmu.txt @@ -0,0 +1,336 @@ +* ARM System MMU Architecture Implementation + +ARM SoCs may contain an implementation of the ARM System Memory +Management Unit Architecture, which can be used to provide 1 or 2 stages +of address translation to bus masters external to the CPU. + +The SMMU may also raise interrupts in response to various fault +conditions. + +** System MMU required properties: + +- compatible : Should be one of: + + "arm,smmu-v1" + "arm,smmu-v2" + "arm,mmu-400" + "arm,mmu-401" + "arm,mmu-500" + "cavium,smmu-v2" + "qcom,qsmmu-v500" + "qcom,smmu-v2" + + depending on the particular implementation and/or the + version of the architecture implemented. + +- reg : Base address and size of the SMMU. + +- reg-names : For the "qcom,qsmmu-v500" device "tcu-base" is expected. + +- #global-interrupts : The number of global interrupts exposed by the + device. + +- interrupts : Interrupt list, with the first #global-irqs entries + corresponding to the global interrupts and any + following entries corresponding to context interrupts, + specified in order of their indexing by the SMMU. + + For SMMUv2 implementations, there must be exactly one + interrupt per context bank. In the case of a single, + combined interrupt, it must be listed multiple times. + +- #iommu-cells : See Documentation/devicetree/bindings/iommu/iommu.txt + for details. With a value of 1, each IOMMU specifier + represents a distinct stream ID emitted by that device + into the relevant SMMU. + + SMMUs with stream matching support and complex masters + may use a value of 2, where the second cell of the + IOMMU specifier represents an SMR mask to combine with + the ID in the first cell. Care must be taken to ensure + the set of matched IDs does not result in conflicts. + +** System MMU optional properties: + +- dma-coherent : Present if page table walks made by the SMMU are + cache coherent with the CPU. + + NOTE: this only applies to the SMMU itself, not + masters connected upstream of the SMMU. + +- calxeda,smmu-secure-config-access : Enable proper handling of buggy + implementations that always use secure access to + SMMU configuration registers. In this case non-secure + aliases of secure registers have to be used during + SMMU configuration. + +- stream-match-mask : For SMMUs supporting stream matching and using + #iommu-cells = <1>, specifies a mask of bits to ignore + when matching stream IDs (e.g. this may be programmed + into the SMRn.MASK field of every stream match register + used). For cases where it is desirable to ignore some + portion of every Stream ID (e.g. for certain MMU-500 + configurations given globally unique input IDs). This + property is not valid for SMMUs using stream indexing, + or using stream matching with #iommu-cells = <2>, and + may be ignored if present in such cases. +- attach-impl-defs : global registers to program at device attach + time. This should be a list of 2-tuples of the format: + . + +- qcom,fatal-asf : Enable BUG_ON for address size faults. Some hardware + requires special fixups to recover from address size + faults. Rather than applying the fixups just BUG since + address size faults are due to a fundamental programming + error from which we don't care about recovering anyways. + +- qcom,tz-device-id : A string indicating the device ID for this SMMU known + to TZ. See msm_tz_smmu.c for a full list of mappings. + +- qcom,skip-init : Disable resetting configuration for all context banks + during device reset. This is useful for targets where + some context banks are dedicated to other execution + environments outside of Linux and those other EEs are + programming their own stream match tables, SCTLR, etc. + Without setting this option we will trample on their + configuration. + +- qcom,dynamic : Allow dynamic domains to be attached. This is only + useful if the upstream hardware is capable of switching + between multiple domains within a single context bank. + +- qcom,use-3-lvl-tables: + Some hardware configurations may not be optimized for using + a four level page table configuration. Set to use a three + level page table instead. + +- qcom,no-asid-retention: + Some hardware may lose internal state for asid after + retention. No cache invalidation operations involving asid + may be used. + +- qcom,actlr: + An array of . + Any sid X for which X&~mask==sid will be programmed with the + given actlr-setting. + +- qcom,enable-static-cb : Enables option to use pre-defined static context bank + allocation programmed by TZ. Global register including SMR and + S2CR registers are configured by TZ before kernel comes up and + this programming is not altered throughout the life of system. + We would be reading through these registers at run time to + identify CB allocated for a particular sid. SID masking isn't + supported as we are directly comparing client SID with ID bits + of SMR registers. + +-qcom,disable-atos: + Some hardware may not have full support for atos debugging + in tandem with other features like power collapse. + +-qcom,opt-out-tbu-halting: + Allow certain TBUs to opt-out from being halted for the + ATOS operation to proceed. Halting certain TBUs would cause + considerable impact to the system such as deadlocks on demand. + Such TBUs can be opted out to be halted from software. + +- qcom,deferred-regulator-disable-delay : The time delay for deferred regulator + disable in ms. In case of unmap call, regulator is + enabled/disabled. This may introduce additional delay. For + clients who do not detach, it's not possible to keep regulator + vote while smmu is attached. Type is . + +- qcom,no-dynamic-asid: + Clients that uses the dynamic domains will have an unique asid + per each domain and all domains can share the same context bank. + When ASID based invalidation is used, on some hardware revisions, + as a result of multiple ASID's associated with the same context + bank, TLB entries are not invalidated properly. On such systems, + we can choose to have a single ASID associated with all domains + for a context bank. + +- qcom,testbus-version: + Testbus implementation is different in some hardware for eg some doesn't + have a separate register for programming tbu testbuses so, they share the + same register to program both tcu and tbu testbuses. on such hardware this + option can be used to specify the testbus version to support testbus interface. + Type is . + +- qcom,iommu-geometry: + Allow clients to extend the available IOVA space by setting the + DOMAIN_ATTR_GEOMETRY domain attribute. The new IOVA space created + will be a superset of the IOVA range which was created through the + create mapping call. The DOMAIN_ATTR_GEOMETRY domain attribute can + only be set before attaching. + +- clocks : List of clocks to be used during SMMU register access. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for information about the format. For each clock specified + here, there must be a corresponding entry in clock-names + (see below). + +- clock-names : List of clock names corresponding to the clocks specified in + the "clocks" property (above). See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for more info. + +- (%s)-supply : Phandle of the regulator that should be powered on during + SMMU register access. (%s) is a string from the + qcom,regulator-names property. + +- qcom,regulator-names : + List of strings to use with the (%s)-supply property. + +- qcom,msm-bus,name +- qcom,msm-bus,num-cases +- qcom,msm-bus,num-paths +- qcom,msm-bus,vectors-KBps + : Refer to devicetree/bindings/arm/msm/msm_bus.txt + +** Deprecated properties: + +- mmu-masters (deprecated in favour of the generic "iommus" binding) : + A list of phandles to device nodes representing bus + masters for which the SMMU can provide a translation + and their corresponding Stream IDs. Each device node + linked from this list must have a "#stream-id-cells" + property, indicating the number of Stream ID + arguments associated with its phandle. + +** Additional properties for Iommu Clients: +- qcom,iommu-dma: + Optional, String. + Can be one of "bypass", "fastmap", "atomic", "disabled". +--- "default": + Standard iommu translation behavior. + The iommu framework will automatically create a domain for the client. + iommu and DMA apis may not be called in atomic context. +--- "bypass": + DMA APIs will use 1-to-1 translation between dma_addr and phys_addr. + Allows using iommu and DMA apis in atomic context. +--- "fastmap": + DMA APIs will run faster, but use several orders of magnitude more memory. + Also allows using iommu and DMA apis in atomic context. +--- "atomic": + Allows using iommu and DMA apis in atomic context. +--- "disabled": + The iommu client is responsible for allocating an iommu domain, as + well as calling iommu_map to create the desired mappings. + +- qcom,iommu-faults: + Optional, List of Strings. + The SCTLR register setting which affect iommu faults handling. + Any combination of the below strings may be used. Mutliple + values are accepted. +--- "default": + Any faults are treated as fatal errors. +--- "no-CFRE": + Iommu faults do not return an abort to the client hardware. +--- "non-fatal": + Iommu faults do not trigger a kernel panic. +--- "stall-disable": + Iommu faults do not stall the client while the fault + interrupt is being handled. +--- "HUPCF": + Iommu may process other transactions while a fault is + in the process of being handled. +- qcom,iommu-vmid: + Optional, Int. + An identifier indicating the security state of the client. + +- qcom,iommu-pagetable: + Optional, String. + Enables coherency for the IOMMU device, but not for the Client. +--- "default": + Pagetables are not coherent nor cached in the system cache.. +--- "coherent" + Pagetables are io-coherent. +--- "LLC" + Pagetables may be saved in the system cache. +--- "LLC_NWA" + Pagetables may be saved in the system cache is used, and + write-allocate hint is disabled. + +- qcom,iommu-earlymap: + Optional, Bool. + Support creating mappings in the page-table before Stage 1 translation is + enabled. + +- qcom,iommu-dma-addr-pool: + Optional, tuple of

. + Defaults to <0, SZ_4G> if not present. + Indicates the range of addresses that the dma layer will use. + +** Examples: + + /* SMMU with stream matching or stream indexing */ + smmu1: iommu { + compatible = "arm,smmu-v1"; + reg = <0xba5e0000 0x10000>; + #global-interrupts = <2>; + interrupts = <0 32 4>, + <0 33 4>, + <0 34 4>, /* This is the first context interrupt */ + <0 35 4>, + <0 36 4>, + <0 37 4>; + #iommu-cells = <1>; + }; + + /* device with two stream IDs, 0 and 7 */ + master1 { + iommus = <&smmu1 0>, + <&smmu1 7>; + }; + + + /* SMMU with stream matching */ + smmu2: iommu { + ... + #iommu-cells = <2>; + }; + + /* device with stream IDs 0 and 7 */ + master2 { + iommus = <&smmu2 0 0>, + <&smmu2 7 0>; + }; + + /* device with stream IDs 1, 17, 33 and 49 */ + master3 { + iommus = <&smmu2 1 0x30>; + }; + + +* Qualcomm MMU-500 TBU Device + +The qcom,qsmmu-v500 device implements a number of register regions containing +debug functionality. Each register region maps to a separate tbu from the +arm mmu-500 implementation. + +** TBU required properties: + +- compatible : Should be one of: + "qcom,qsmmuv500-tbu" + +- reg : Base address and size. + +- reg-names : "base" and "status-reg" are expected + "base" is the main TBU register region. + "status-reg" indicates whether hw can process a new request. + +-qcom,stream-id-range: + Pair of values describing the smallest supported stream-id + and the size of the entire set. + +Example: +smmu { + compatible = "qcom,qsmmu-v500"; + tbu@0x1000 { + compatible = "qcom,qsmmuv500-tbu"; + regs = <0x1000 0x1000>, + <0x2000 0x8>; + reg-names = "base", + "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/iommu-debug.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/iommu-debug.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d79f1865aa53cec64e8249145dd3edf44f676c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/iommu-debug.txt @@ -0,0 +1,27 @@ +This document describes the device tree binding for IOMMU test devices. + +The iommu-debug framework can optionally make use of some platform devices +for improved standalone testing and other features. + +- compatible: iommu-debug-test + + +Required properties +=================== + +- iommus: The IOMMU for the test device (see iommu.txt) + + +Example +======= + + iommu_test_device { + compatible = "iommu-debug-test"; + /* + * 42 shouldn't be used by anyone on the cpp_fd_smmu. We just + * need _something_ here to get this node recognized by the + * SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&cpp_fd_smmu 42>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/iommu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a8b4624defcb981fc630b2b88ba88957efe6868 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/iommu.txt @@ -0,0 +1,182 @@ +This document describes the generic device tree binding for IOMMUs and their +master(s). + + +IOMMU device node: +================== + +An IOMMU can provide the following services: + +* Remap address space to allow devices to access physical memory ranges that + they otherwise wouldn't be capable of accessing. + + Example: 32-bit DMA to 64-bit physical addresses + +* Implement scatter-gather at page level granularity so that the device does + not have to. + +* Provide system protection against "rogue" DMA by forcing all accesses to go + through the IOMMU and faulting when encountering accesses to unmapped + address regions. + +* Provide address space isolation between multiple contexts. + + Example: Virtualization + +Device nodes compatible with this binding represent hardware with some of the +above capabilities. + +IOMMUs can be single-master or multiple-master. Single-master IOMMU devices +typically have a fixed association to the master device, whereas multiple- +master IOMMU devices can translate accesses from more than one master. + +The device tree node of the IOMMU device's parent bus must contain a valid +"dma-ranges" property that describes how the physical address space of the +IOMMU maps to memory. An empty "dma-ranges" property means that there is a +1:1 mapping from IOMMU to memory. + +Required properties: +-------------------- +- #iommu-cells: The number of cells in an IOMMU specifier needed to encode an + address. + +The meaning of the IOMMU specifier is defined by the device tree binding of +the specific IOMMU. Below are a few examples of typical use-cases: + +- #iommu-cells = <0>: Single master IOMMU devices are not configurable and + therefore no additional information needs to be encoded in the specifier. + This may also apply to multiple master IOMMU devices that do not allow the + association of masters to be configured. Note that an IOMMU can by design + be multi-master yet only expose a single master in a given configuration. + In such cases the number of cells will usually be 1 as in the next case. +- #iommu-cells = <1>: Multiple master IOMMU devices may need to be configured + in order to enable translation for a given master. In such cases the single + address cell corresponds to the master device's ID. In some cases more than + one cell can be required to represent a single master ID. +- #iommu-cells = <4>: Some IOMMU devices allow the DMA window for masters to + be configured. The first cell of the address in this may contain the master + device's ID for example, while the second cell could contain the start of + the DMA window for the given device. The length of the DMA window is given + by the third and fourth cells. + +Note that these are merely examples and real-world use-cases may use different +definitions to represent their individual needs. Always refer to the specific +IOMMU binding for the exact meaning of the cells that make up the specifier. + + +IOMMU master node: +================== + +Devices that access memory through an IOMMU are called masters. A device can +have multiple master interfaces (to one or more IOMMU devices). + +Required properties: +-------------------- +- iommus: A list of phandle and IOMMU specifier pairs that describe the IOMMU + master interfaces of the device. One entry in the list describes one master + interface of the device. + +When an "iommus" property is specified in a device tree node, the IOMMU will +be used for address translation. If a "dma-ranges" property exists in the +device's parent node it will be ignored. An exception to this rule is if the +referenced IOMMU is disabled, in which case the "dma-ranges" property of the +parent shall take effect. Note that merely disabling a device tree node does +not guarantee that the IOMMU is really disabled since the hardware may not +have a means to turn off translation. But it is invalid in such cases to +disable the IOMMU's device tree node in the first place because it would +prevent any driver from properly setting up the translations. + + +Notes: +====== + +One possible extension to the above is to use an "iommus" property along with +a "dma-ranges" property in a bus device node (such as PCI host bridges). This +can be useful to describe how children on the bus relate to the IOMMU if they +are not explicitly listed in the device tree (e.g. PCI devices). However, the +requirements of that use-case haven't been fully determined yet. Implementing +this is therefore not recommended without further discussion and extension of +this binding. + + +Examples: +========= + +Single-master IOMMU: +-------------------- + + iommu { + #iommu-cells = <0>; + }; + + master { + iommus = <&{/iommu}>; + }; + +Multiple-master IOMMU with fixed associations: +---------------------------------------------- + + /* multiple-master IOMMU */ + iommu { + /* + * Masters are statically associated with this IOMMU and share + * the same address translations because the IOMMU does not + * have sufficient information to distinguish between masters. + * + * Consequently address translation is always on or off for + * all masters at any given point in time. + */ + #iommu-cells = <0>; + }; + + /* static association with IOMMU */ + master@1 { + reg = <1>; + iommus = <&{/iommu}>; + }; + + /* static association with IOMMU */ + master@2 { + reg = <2>; + iommus = <&{/iommu}>; + }; + +Multiple-master IOMMU: +---------------------- + + iommu { + /* the specifier represents the ID of the master */ + #iommu-cells = <1>; + }; + + master@1 { + /* device has master ID 42 in the IOMMU */ + iommus = <&{/iommu} 42>; + }; + + master@2 { + /* device has master IDs 23 and 24 in the IOMMU */ + iommus = <&{/iommu} 23>, <&{/iommu} 24>; + }; + +Multiple-master IOMMU with configurable DMA window: +--------------------------------------------------- + + / { + iommu { + /* + * One cell for the master ID and one cell for the + * address of the DMA window. The length of the DMA + * window is encoded in two cells. + * + * The DMA window is the range addressable by the + * master (i.e. the I/O virtual address space). + */ + #iommu-cells = <4>; + }; + + master { + /* master ID 42, 4 GiB DMA window starting at 0 */ + iommus = <&{/iommu} 42 0 0x1 0x0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/mediatek,iommu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/mediatek,iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..df5db732138d10658b5d659f25ca1ea3df28e025 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/mediatek,iommu.txt @@ -0,0 +1,75 @@ +* Mediatek IOMMU Architecture Implementation + + Some Mediatek SOCs contain a Multimedia Memory Management Unit (M4U), and +this M4U have two generations of HW architecture. Generation one uses flat +pagetable, and only supports 4K size page mapping. Generation two uses the +ARM Short-Descriptor translation table format for address translation. + + About the M4U Hardware Block Diagram, please check below: + + EMI (External Memory Interface) + | + m4u (Multimedia Memory Management Unit) + | + SMI Common(Smart Multimedia Interface Common) + | + +----------------+------- + | | + | | + SMI larb0 SMI larb1 ... SoCs have several SMI local arbiter(larb). + (display) (vdec) + | | + | | + +-----+-----+ +----+----+ + | | | | | | + | | |... | | | ... There are different ports in each larb. + | | | | | | +OVL0 RDMA0 WDMA0 MC PP VLD + + As above, The Multimedia HW will go through SMI and M4U while it +access EMI. SMI is a bridge between m4u and the Multimedia HW. It contain +smi local arbiter and smi common. It will control whether the Multimedia +HW should go though the m4u for translation or bypass it and talk +directly with EMI. And also SMI help control the power domain and clocks for +each local arbiter. + Normally we specify a local arbiter(larb) for each multimedia HW +like display, video decode, and camera. And there are different ports +in each larb. Take a example, There are many ports like MC, PP, VLD in the +video decode local arbiter, all these ports are according to the video HW. + +Required properties: +- compatible : must be one of the following string: + "mediatek,mt2701-m4u" for mt2701 which uses generation one m4u HW. + "mediatek,mt2712-m4u" for mt2712 which uses generation two m4u HW. + "mediatek,mt8173-m4u" for mt8173 which uses generation two m4u HW. +- reg : m4u register base and size. +- interrupts : the interrupt of m4u. +- clocks : must contain one entry for each clock-names. +- clock-names : must be "bclk", It is the block clock of m4u. +- mediatek,larbs : List of phandle to the local arbiters in the current Socs. + Refer to bindings/memory-controllers/mediatek,smi-larb.txt. It must sort + according to the local arbiter index, like larb0, larb1, larb2... +- iommu-cells : must be 1. This is the mtk_m4u_id according to the HW. + Specifies the mtk_m4u_id as defined in + dt-binding/memory/mt2701-larb-port.h for mt2701, + dt-binding/memory/mt2712-larb-port.h for mt2712, and + dt-binding/memory/mt8173-larb-port.h for mt8173. + +Example: + iommu: iommu@10205000 { + compatible = "mediatek,mt8173-m4u"; + reg = <0 0x10205000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_M4U>; + clock-names = "bclk"; + mediatek,larbs = <&larb0 &larb1 &larb2 &larb3 &larb4 &larb5>; + #iommu-cells = <1>; + }; + +Example for a client device: + display { + compatible = "mediatek,mt8173-disp"; + iommus = <&iommu M4U_PORT_DISP_OVL0>, + <&iommu M4U_PORT_DISP_RDMA0>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/msm,iommu-v0.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/msm,iommu-v0.txt new file mode 100644 index 0000000000000000000000000000000000000000..20236385f26e52b84732cc76a04b7d1f8349d335 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/msm,iommu-v0.txt @@ -0,0 +1,64 @@ +* QCOM IOMMU + +The MSM IOMMU is an implementation compatible with the ARM VMSA short +descriptor page tables. It provides address translation for bus masters outside +of the CPU, each connected to the IOMMU through a port called micro-TLB. + +Required Properties: + + - compatible: Must contain "qcom,apq8064-iommu". + - reg: Base address and size of the IOMMU registers. + - interrupts: Specifiers for the MMU fault interrupts. For instances that + support secure mode two interrupts must be specified, for non-secure and + secure mode, in that order. For instances that don't support secure mode a + single interrupt must be specified. + - #iommu-cells: The number of cells needed to specify the stream id. This + is always 1. + - qcom,ncb: The total number of context banks in the IOMMU. + - clocks : List of clocks to be used during SMMU register access. See + Documentation/devicetree/bindings/clock/clock-bindings.txt + for information about the format. For each clock specified + here, there must be a corresponding entry in clock-names + (see below). + + - clock-names : List of clock names corresponding to the clocks specified in + the "clocks" property (above). + Should be "smmu_pclk" for specifying the interface clock + required for iommu's register accesses. + Should be "smmu_clk" for specifying the functional clock + required by iommu for bus accesses. + +Each bus master connected to an IOMMU must reference the IOMMU in its device +node with the following property: + + - iommus: A reference to the IOMMU in multiple cells. The first cell is a + phandle to the IOMMU and the second cell is the stream id. + A single master device can be connected to more than one iommu + and multiple contexts in each of the iommu. So multiple entries + are required to list all the iommus and the stream ids that the + master is connected to. + +Example: mdp iommu and its bus master + + mdp_port0: iommu@7500000 { + compatible = "qcom,apq8064-iommu"; + #iommu-cells = <1>; + clock-names = + "smmu_pclk", + "smmu_clk"; + clocks = + <&mmcc SMMU_AHB_CLK>, + <&mmcc MDP_AXI_CLK>; + reg = <0x07500000 0x100000>; + interrupts = + , + ; + qcom,ncb = <2>; + }; + + mdp: qcom,mdp@5100000 { + compatible = "qcom,mdp"; + ... + iommus = <&mdp_port0 0 + &mdp_port0 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/nvidia,tegra20-gart.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/nvidia,tegra20-gart.txt new file mode 100644 index 0000000000000000000000000000000000000000..099d9362ebc106442a47be8f59f2f1d3f88fa161 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/nvidia,tegra20-gart.txt @@ -0,0 +1,14 @@ +NVIDIA Tegra 20 GART + +Required properties: +- compatible: "nvidia,tegra20-gart" +- reg: Two pairs of cells specifying the physical address and size of + the memory controller registers and the GART aperture respectively. + +Example: + + gart { + compatible = "nvidia,tegra20-gart"; + reg = <0x7000f024 0x00000018 /* controller registers */ + 0x58000000 0x02000000>; /* GART aperture */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/nvidia,tegra30-smmu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/nvidia,tegra30-smmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..89fb5434b73016958f0c9ac829929cacc0f8045e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/nvidia,tegra30-smmu.txt @@ -0,0 +1,21 @@ +NVIDIA Tegra 30 IOMMU H/W, SMMU (System Memory Management Unit) + +Required properties: +- compatible : "nvidia,tegra30-smmu" +- reg : Should contain 3 register banks(address and length) for each + of the SMMU register blocks. +- interrupts : Should contain MC General interrupt. +- nvidia,#asids : # of ASIDs +- dma-window : IOVA start address and length. +- nvidia,ahb : phandle to the ahb bus connected to SMMU. + +Example: + smmu { + compatible = "nvidia,tegra30-smmu"; + reg = <0x7000f010 0x02c + 0x7000f1f0 0x010 + 0x7000f228 0x05c>; + nvidia,#asids = <4>; /* # of ASIDs */ + dma-window = <0 0x40000000>; /* IOVA start & length */ + nvidia,ahb = <&ahb>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/qcom,iommu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/qcom,iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..059139abce3547bda5700695b521c713b0c3a07f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/qcom,iommu.txt @@ -0,0 +1,121 @@ +* QCOM IOMMU v1 Implementation + +Qualcomm "B" family devices which are not compatible with arm-smmu have +a similar looking IOMMU but without access to the global register space, +and optionally requiring additional configuration to route context irqs +to non-secure vs secure interrupt line. + +** Required properties: + +- compatible : Should be one of: + + "qcom,msm8916-iommu" + + Followed by "qcom,msm-iommu-v1". + +- clock-names : Should be a pair of "iface" (required for IOMMUs + register group access) and "bus" (required for + the IOMMUs underlying bus access). + +- clocks : Phandles for respective clocks described by + clock-names. + +- #address-cells : must be 1. + +- #size-cells : must be 1. + +- #iommu-cells : Must be 1. Index identifies the context-bank #. + +- ranges : Base address and size of the iommu context banks. + +- qcom,iommu-secure-id : secure-id. + +- List of sub-nodes, one per translation context bank. Each sub-node + has the following required properties: + + - compatible : Should be one of: + - "qcom,msm-iommu-v1-ns" : non-secure context bank + - "qcom,msm-iommu-v1-sec" : secure context bank + - reg : Base address and size of context bank within the iommu + - interrupts : The context fault irq. + +** Optional properties: + +- reg : Base address and size of the SMMU local base, should + be only specified if the iommu requires configuration + for routing of context bank irq's to secure vs non- + secure lines. (Ie. if the iommu contains secure + context banks) + + +** Examples: + + apps_iommu: iommu@1e20000 { + #address-cells = <1>; + #size-cells = <1>; + #iommu-cells = <1>; + compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1"; + ranges = <0 0x1e20000 0x40000>; + reg = <0x1ef0000 0x3000>; + clocks = <&gcc GCC_SMMU_CFG_CLK>, + <&gcc GCC_APSS_TCU_CLK>; + clock-names = "iface", "bus"; + qcom,iommu-secure-id = <17>; + + // mdp_0: + iommu-ctx@4000 { + compatible = "qcom,msm-iommu-v1-ns"; + reg = <0x4000 0x1000>; + interrupts = ; + }; + + // venus_ns: + iommu-ctx@5000 { + compatible = "qcom,msm-iommu-v1-sec"; + reg = <0x5000 0x1000>; + interrupts = ; + }; + }; + + gpu_iommu: iommu@1f08000 { + #address-cells = <1>; + #size-cells = <1>; + #iommu-cells = <1>; + compatible = "qcom,msm8916-iommu", "qcom,msm-iommu-v1"; + ranges = <0 0x1f08000 0x10000>; + clocks = <&gcc GCC_SMMU_CFG_CLK>, + <&gcc GCC_GFX_TCU_CLK>; + clock-names = "iface", "bus"; + qcom,iommu-secure-id = <18>; + + // gfx3d_user: + iommu-ctx@1000 { + compatible = "qcom,msm-iommu-v1-ns"; + reg = <0x1000 0x1000>; + interrupts = ; + }; + + // gfx3d_priv: + iommu-ctx@2000 { + compatible = "qcom,msm-iommu-v1-ns"; + reg = <0x2000 0x1000>; + interrupts = ; + }; + }; + + ... + + venus: video-codec@1d00000 { + ... + iommus = <&apps_iommu 5>; + }; + + mdp: mdp@1a01000 { + ... + iommus = <&apps_iommu 4>; + }; + + gpu@1c00000 { + ... + iommus = <&gpu_iommu 1>, <&gpu_iommu 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/renesas,ipmmu-vmsa.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/renesas,ipmmu-vmsa.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6e2d855fe131fc17454ff08ed5bc799848c3d10 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/renesas,ipmmu-vmsa.txt @@ -0,0 +1,69 @@ +* Renesas VMSA-Compatible IOMMU + +The IPMMU is an IOMMU implementation compatible with the ARM VMSA page tables. +It provides address translation for bus masters outside of the CPU, each +connected to the IPMMU through a port called micro-TLB. + + +Required Properties: + + - compatible: Must contain SoC-specific and generic entry below in case + the device is compatible with the R-Car Gen2 VMSA-compatible IPMMU. + + - "renesas,ipmmu-r8a73a4" for the R8A73A4 (R-Mobile APE6) IPMMU. + - "renesas,ipmmu-r8a7743" for the R8A7743 (RZ/G1M) IPMMU. + - "renesas,ipmmu-r8a7745" for the R8A7745 (RZ/G1E) IPMMU. + - "renesas,ipmmu-r8a7790" for the R8A7790 (R-Car H2) IPMMU. + - "renesas,ipmmu-r8a7791" for the R8A7791 (R-Car M2-W) IPMMU. + - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU. + - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU. + - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU. + - "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU. + - "renesas,ipmmu-r8a77965" for the R8A77965 (R-Car M3-N) IPMMU. + - "renesas,ipmmu-r8a77970" for the R8A77970 (R-Car V3M) IPMMU. + - "renesas,ipmmu-r8a77980" for the R8A77980 (R-Car V3H) IPMMU. + - "renesas,ipmmu-r8a77990" for the R8A77990 (R-Car E3) IPMMU. + - "renesas,ipmmu-r8a77995" for the R8A77995 (R-Car D3) IPMMU. + - "renesas,ipmmu-vmsa" for generic R-Car Gen2 or RZ/G1 VMSA-compatible + IPMMU. + + - reg: Base address and size of the IPMMU registers. + - interrupts: Specifiers for the MMU fault interrupts. For instances that + support secure mode two interrupts must be specified, for non-secure and + secure mode, in that order. For instances that don't support secure mode a + single interrupt must be specified. Not required for cache IPMMUs. + + - #iommu-cells: Must be 1. + +Optional properties: + + - renesas,ipmmu-main: reference to the main IPMMU instance in two cells. + The first cell is a phandle to the main IPMMU and the second cell is + the interrupt bit number associated with the particular cache IPMMU device. + The interrupt bit number needs to match the main IPMMU IMSSTR register. + Only used by cache IPMMU instances. + + +Each bus master connected to an IPMMU must reference the IPMMU in its device +node with the following property: + + - iommus: A reference to the IPMMU in two cells. The first cell is a phandle + to the IPMMU and the second cell the number of the micro-TLB that the + device is connected to. + + +Example: R8A7791 IPMMU-MX and VSP1-D0 bus master + + ipmmu_mx: mmu@fe951000 { + compatible = "renasas,ipmmu-r8a7791", "renasas,ipmmu-vmsa"; + reg = <0 0xfe951000 0 0x1000>; + interrupts = <0 222 IRQ_TYPE_LEVEL_HIGH>, + <0 221 IRQ_TYPE_LEVEL_HIGH>; + #iommu-cells = <1>; + }; + + vsp@fe928000 { + ... + iommus = <&ipmmu_mx 13>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/rockchip,iommu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/rockchip,iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ecefea1c6f9b4647140e57fceb9134608b43acb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/rockchip,iommu.txt @@ -0,0 +1,38 @@ +Rockchip IOMMU +============== + +A Rockchip DRM iommu translates io virtual addresses to physical addresses for +its master device. Each slave device is bound to a single master device, and +shares its clocks, power domain and irq. + +Required properties: +- compatible : Should be "rockchip,iommu" +- reg : Address space for the configuration registers +- interrupts : Interrupt specifier for the IOMMU instance +- interrupt-names : Interrupt name for the IOMMU instance +- #iommu-cells : Should be <0>. This indicates the iommu is a + "single-master" device, and needs no additional information + to associate with its master device. See: + Documentation/devicetree/bindings/iommu/iommu.txt +- clocks : A list of clocks required for the IOMMU to be accessible by + the host CPU. +- clock-names : Should contain the following: + "iface" - Main peripheral bus clock (PCLK/HCL) (required) + "aclk" - AXI bus clock (required) + +Optional properties: +- rockchip,disable-mmu-reset : Don't use the mmu reset operation. + Some mmu instances may produce unexpected results + when the reset operation is used. + +Example: + + vopl_mmu: iommu@ff940300 { + compatible = "rockchip,iommu"; + reg = <0xff940300 0x100>; + interrupts = ; + interrupt-names = "vopl_mmu"; + clocks = <&cru ACLK_VOP1>, <&cru HCLK_VOP1>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/samsung,sysmmu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/samsung,sysmmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..525ec82615a668d37d87bb28c53d9a364b1599ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/samsung,sysmmu.txt @@ -0,0 +1,67 @@ +Samsung Exynos IOMMU H/W, System MMU (System Memory Management Unit) + +Samsung's Exynos architecture contains System MMUs that enables scattered +physical memory chunks visible as a contiguous region to DMA-capable peripheral +devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth. + +System MMU is an IOMMU and supports identical translation table format to +ARMv7 translation tables with minimum set of page properties including access +permissions, shareability and security protection. In addition, System MMU has +another capabilities like L2 TLB or block-fetch buffers to minimize translation +latency. + +System MMUs are in many to one relation with peripheral devices, i.e. single +peripheral device might have multiple System MMUs (usually one for each bus +master), but one System MMU can handle transactions from only one peripheral +device. The relation between a System MMU and the peripheral device needs to be +defined in device node of the peripheral device. + +MFC in all Exynos SoCs and FIMD, M2M Scalers and G2D in Exynos5420 has 2 System +MMUs. +* MFC has one System MMU on its left and right bus. +* FIMD in Exynos5420 has one System MMU for window 0 and 4, the other system MMU + for window 1, 2 and 3. +* M2M Scalers and G2D in Exynos5420 has one System MMU on the read channel and + the other System MMU on the write channel. + +For information on assigning System MMU controller to its peripheral devices, +see generic IOMMU bindings. + +Required properties: +- compatible: Should be "samsung,exynos-sysmmu" +- reg: A tuple of base address and size of System MMU registers. +- #iommu-cells: Should be <0>. +- interrupts: An interrupt specifier for interrupt signal of System MMU, + according to the format defined by a particular interrupt + controller. +- clock-names: Should be "sysmmu" or a pair of "aclk" and "pclk" to gate + SYSMMU core clocks. + Optional "master" if the clock to the System MMU is gated by + another gate clock other core (usually main gate clock + of peripheral device this SYSMMU belongs to). +- clocks: Phandles for respective clocks described by clock-names. +- power-domains: Required if the System MMU is needed to gate its power. + Please refer to the following document: + Documentation/devicetree/bindings/power/pd-samsung.txt + +Examples: + gsc_0: gsc@13e00000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; + power-domains = <&pd_gsc>; + clocks = <&clock CLK_GSCL0>; + clock-names = "gscl"; + iommus = <&sysmmu_gsc0>; + }; + + sysmmu_gsc0: sysmmu@13e80000 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13E80000 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 0>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>; + power-domains = <&pd_gsc>; + #iommu-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/iommu/ti,omap-iommu.txt b/arch/arm64/boot/dts/vendor/bindings/iommu/ti,omap-iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..4bd10dd881b8324d86dbbed31005be81a4f52fa9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/iommu/ti,omap-iommu.txt @@ -0,0 +1,59 @@ +OMAP2+ IOMMU + +Required properties: +- compatible : Should be one of, + "ti,omap2-iommu" for OMAP2/OMAP3 IOMMU instances + "ti,omap4-iommu" for OMAP4/OMAP5 IOMMU instances + "ti,dra7-dsp-iommu" for DRA7xx DSP IOMMU instances + "ti,dra7-iommu" for DRA7xx IOMMU instances +- ti,hwmods : Name of the hwmod associated with the IOMMU instance +- reg : Address space for the configuration registers +- interrupts : Interrupt specifier for the IOMMU instance +- #iommu-cells : Should be 0. OMAP IOMMUs are all "single-master" devices, + and needs no additional data in the pargs specifier. Please + also refer to the generic bindings document for more info + on this property, + Documentation/devicetree/bindings/iommu/iommu.txt + +Optional properties: +- ti,#tlb-entries : Number of entries in the translation look-aside buffer. + Should be either 8 or 32 (default: 32) +- ti,iommu-bus-err-back : Indicates the IOMMU instance supports throwing + back a bus error response on MMU faults. +- ti,syscon-mmuconfig : Should be a pair of the phandle to the DSP_SYSTEM + syscon node that contains the additional control + register for enabling the MMU, and the MMU instance + number (0-indexed) within the sub-system. This property + is required for DSP IOMMU instances on DRA7xx SoCs. The + instance number should be 0 for DSP MDMA MMUs and 1 for + DSP EDMA MMUs. + +Example: + /* OMAP3 ISP MMU */ + mmu_isp: mmu@480bd400 { + #iommu-cells = <0>; + compatible = "ti,omap2-iommu"; + reg = <0x480bd400 0x80>; + interrupts = <24>; + ti,hwmods = "mmu_isp"; + ti,#tlb-entries = <8>; + }; + + /* DRA74x DSP2 MMUs */ + mmu0_dsp2: mmu@41501000 { + compatible = "ti,dra7-dsp-iommu"; + reg = <0x41501000 0x100>; + interrupts = ; + ti,hwmods = "mmu0_dsp2"; + #iommu-cells = <0>; + ti,syscon-mmuconfig = <&dsp2_system 0x0>; + }; + + mmu1_dsp2: mmu@41502000 { + compatible = "ti,dra7-dsp-iommu"; + reg = <0x41502000 0x100>; + interrupts = ; + ti,hwmods = "mmu1_dsp2"; + #iommu-cells = <0>; + ti,syscon-mmuconfig = <&dsp2_system 0x1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt b/arch/arm64/boot/dts/vendor/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..028268fd99eeba926424ae90ac73eab6b818f4be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ipmi/aspeed,ast2400-ibt-bmc.txt @@ -0,0 +1,25 @@ +* Aspeed BT (Block Transfer) IPMI interface + +The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs +(BaseBoard Management Controllers) and the BT interface can be used to +perform in-band IPMI communication with their host. + +Required properties: + +- compatible : should be one of + "aspeed,ast2400-ibt-bmc" + "aspeed,ast2500-ibt-bmc" +- reg: physical address and size of the registers + +Optional properties: + +- interrupts: interrupt generated by the BT interface. without an + interrupt, the driver will operate in poll mode. + +Example: + + ibt@1e789140 { + compatible = "aspeed,ast2400-ibt-bmc"; + reg = <0x1e789140 0x18>; + interrupts = <8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ipmi/aspeed-kcs-bmc.txt b/arch/arm64/boot/dts/vendor/bindings/ipmi/aspeed-kcs-bmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d98a9bf45d6cba6fbabb9eee79ee75970908baf8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ipmi/aspeed-kcs-bmc.txt @@ -0,0 +1,25 @@ +* Aspeed KCS (Keyboard Controller Style) IPMI interface + +The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs +(Baseboard Management Controllers) and the KCS interface can be +used to perform in-band IPMI communication with their host. + +Required properties: +- compatible : should be one of + "aspeed,ast2400-kcs-bmc" + "aspeed,ast2500-kcs-bmc" +- interrupts : interrupt generated by the controller +- kcs_chan : The LPC channel number in the controller +- kcs_addr : The host CPU IO map address + + +Example: + + kcs3: kcs3@0 { + compatible = "aspeed,ast2500-kcs-bmc"; + reg = <0x0 0x80>; + interrupts = <8>; + kcs_chan = <3>; + kcs_addr = <0xCA2>; + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ipmi/ipmi-smic.txt b/arch/arm64/boot/dts/vendor/bindings/ipmi/ipmi-smic.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5f1a877ed3ec6581d884b0b4a3adadc4cef4fdb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ipmi/ipmi-smic.txt @@ -0,0 +1,25 @@ +IPMI device + +Required properties: +- compatible: should be one of ipmi-kcs, ipmi-smic, or ipmi-bt +- device_type: should be ipmi +- reg: Address and length of the register set for the device + +Optional properties: +- interrupts: The interrupt for the device. Without this the interface + is polled. +- reg-size - The size of the register. Defaults to 1 +- reg-spacing - The number of bytes between register starts. Defaults to 1 +- reg-shift - The amount to shift the registers to the right to get the data + into bit zero. + +Example: + +smic@fff3a000 { + compatible = "ipmi-smic"; + device_type = "ipmi"; + reg = <0xfff3a000 0x1000>; + interrupts = <0 24 4>; + reg-size = <4>; + reg-spacing = <4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ipmi/npcm7xx-kcs-bmc.txt b/arch/arm64/boot/dts/vendor/bindings/ipmi/npcm7xx-kcs-bmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3538a214fff156d461322f7e10b92821f9331484 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ipmi/npcm7xx-kcs-bmc.txt @@ -0,0 +1,39 @@ +* Nuvoton NPCM7xx KCS (Keyboard Controller Style) IPMI interface + +The Nuvoton SOCs (NPCM7xx) are commonly used as BMCs +(Baseboard Management Controllers) and the KCS interface can be +used to perform in-band IPMI communication with their host. + +Required properties: +- compatible : should be one of + "nuvoton,npcm750-kcs-bmc" +- interrupts : interrupt generated by the controller +- kcs_chan : The KCS channel number in the controller + +Example: + + lpc_kcs: lpc_kcs@f0007000 { + compatible = "nuvoton,npcm750-lpc-kcs", "simple-mfd", "syscon"; + reg = <0xf0007000 0x40>; + reg-io-width = <1>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xf0007000 0x40>; + + kcs1: kcs1@0 { + compatible = "nuvoton,npcm750-kcs-bmc"; + reg = <0x0 0x40>; + interrupts = <0 9 4>; + kcs_chan = <1>; + status = "disabled"; + }; + + kcs2: kcs2@0 { + compatible = "nuvoton,npcm750-kcs-bmc"; + reg = <0x0 0x40>; + interrupts = <0 9 4>; + kcs_chan = <2>; + status = "disabled"; + }; + }; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/jailhouse.txt b/arch/arm64/boot/dts/vendor/bindings/jailhouse.txt new file mode 100644 index 0000000000000000000000000000000000000000..2901c25ff340e89f46e422254096b3cbe33b29d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/jailhouse.txt @@ -0,0 +1,8 @@ +Jailhouse non-root cell device tree bindings +-------------------------------------------- + +When running in a non-root Jailhouse cell (partition), the device tree of this +platform shall have a top-level "hypervisor" node with the following +properties: + +- compatible = "jailhouse,cell" diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/ams,as3645a.txt b/arch/arm64/boot/dts/vendor/bindings/leds/ams,as3645a.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdc40e354a64dd582d86841afac520a73d6fa5f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/ams,as3645a.txt @@ -0,0 +1,79 @@ +Analog devices AS3645A device tree bindings + +The AS3645A flash LED controller can drive two LEDs, one high current +flash LED and one indicator LED. The high current flash LED can be +used in torch mode as well. + +Ranges below noted as [a, b] are closed ranges between a and b, i.e. a +and b are included in the range. + +Please also see common.txt in the same directory. + + +Required properties +=================== + +compatible : Must be "ams,as3645a". +reg : The I2C address of the device. Typically 0x30. +#address-cells : 1 +#size-cells : 0 + + +Required properties of the flash child node (0) +=============================================== + +reg: 0 +flash-timeout-us: Flash timeout in microseconds. The value must be in + the range [100000, 850000] and divisible by 50000. +flash-max-microamp: Maximum flash current in microamperes. Has to be + in the range between [200000, 500000] and + divisible by 20000. +led-max-microamp: Maximum torch (assist) current in microamperes. The + value must be in the range between [20000, 160000] and + divisible by 20000. +ams,input-max-microamp: Maximum flash controller input current. The + value must be in the range [1250000, 2000000] + and divisible by 50000. + + +Optional properties of the flash child node +=========================================== + +label : The label of the flash LED. + + +Required properties of the indicator child node (1) +=================================================== + +reg: 1 +led-max-microamp: Maximum indicator current. The allowed values are + 2500, 5000, 7500 and 10000. + +Optional properties of the indicator child node +=============================================== + +label : The label of the indicator LED. + + +Example +======= + + as3645a@30 { + #address-cells: 1 + #size-cells: 0 + reg = <0x30>; + compatible = "ams,as3645a"; + flash@0 { + reg = <0x0>; + flash-timeout-us = <150000>; + flash-max-microamp = <320000>; + led-max-microamp = <60000>; + ams,input-max-microamp = <1750000>; + label = "as3645a:flash"; + }; + indicator@1 { + reg = <0x1>; + led-max-microamp = <10000>; + label = "as3645a:indicator"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/88pm860x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/88pm860x.txt new file mode 100644 index 0000000000000000000000000000000000000000..261df2799315b2b645f54454a1ef6f5e1bb42766 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/88pm860x.txt @@ -0,0 +1,15 @@ +88pm860x-backlight bindings + +Optional properties: + - marvell,88pm860x-iset: Current supplies on backlight device. + - marvell,88pm860x-pwm: PWM frequency on backlight device. + +Example: + + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/arcxcnn_bl.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/arcxcnn_bl.txt new file mode 100644 index 0000000000000000000000000000000000000000..230abdefd6e7be20b470c3790e74c4d26d084ee8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/arcxcnn_bl.txt @@ -0,0 +1,33 @@ +Binding for ArcticSand arc2c0608 LED driver + +Required properties: +- compatible: should be "arc,arc2c0608" +- reg: slave address + +Optional properties: +- default-brightness: brightness value on boot, value from: 0-4095 +- label: The name of the backlight device + See Documentation/devicetree/bindings/leds/common.txt +- led-sources: List of enabled channels from 0 to 5. + See Documentation/devicetree/bindings/leds/common.txt + +- arc,led-config-0: setting for register ILED_CONFIG_0 +- arc,led-config-1: setting for register ILED_CONFIG_1 +- arc,dim-freq: PWM mode frequence setting (bits [3:0] used) +- arc,comp-config: setting for register CONFIG_COMP +- arc,filter-config: setting for register FILTER_CONFIG +- arc,trim-config: setting for register IMAXTUNE + +Note: Optional properties not specified will default to values in IC EPROM + +Example: + +arc2c0608@30 { + compatible = "arc,arc2c0608"; + reg = <0x30>; + default-brightness = <500>; + label = "lcd-backlight"; + linux,default-trigger = "backlight"; + led-sources = <0 1 2 5>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/gpio-backlight.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/gpio-backlight.txt new file mode 100644 index 0000000000000000000000000000000000000000..321be6640533e9ee2d0ff024788f2800343f50d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/gpio-backlight.txt @@ -0,0 +1,16 @@ +gpio-backlight bindings + +Required properties: + - compatible: "gpio-backlight" + - gpios: describes the gpio that is used for enabling/disabling the backlight. + refer to bindings/gpio/gpio.txt for more details. + +Optional properties: + - default-on: enable the backlight at boot. + +Example: + backlight { + compatible = "gpio-backlight"; + gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>; + default-on; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/lp855x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/lp855x.txt new file mode 100644 index 0000000000000000000000000000000000000000..88f56641fc2858addfba1c7ebba2e6b6ef141789 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/lp855x.txt @@ -0,0 +1,72 @@ +lp855x bindings + +Required properties: + - compatible: "ti,lp8550", "ti,lp8551", "ti,lp8552", "ti,lp8553", + "ti,lp8555", "ti,lp8556", "ti,lp8557" + - reg: I2C slave address (u8) + - dev-ctrl: Value of DEVICE CONTROL register (u8). It depends on the device. + +Optional properties: + - bl-name: Backlight device name (string) + - init-brt: Initial value of backlight brightness (u8) + - pwm-period: PWM period value. Set only PWM input mode used (u32) + - rom-addr: Register address of ROM area to be updated (u8) + - rom-val: Register value to be updated (u8) + - power-supply: Regulator which controls the 3V rail + - enable-supply: Regulator which controls the EN/VDDIO input + +Example: + + /* LP8555 */ + backlight@2c { + compatible = "ti,lp8555"; + reg = <0x2c>; + + dev-ctrl = /bits/ 8 <0x00>; + pwm-period = <10000>; + + /* 4V OV, 4 output LED0 string enabled */ + rom_14h { + rom-addr = /bits/ 8 <0x14>; + rom-val = /bits/ 8 <0xcf>; + }; + + /* Heavy smoothing, 24ms ramp time step */ + rom_15h { + rom-addr = /bits/ 8 <0x15>; + rom-val = /bits/ 8 <0xc7>; + }; + + /* 4 output LED1 string enabled */ + rom_19h { + rom-addr = /bits/ 8 <0x19>; + rom-val = /bits/ 8 <0x0f>; + }; + }; + + /* LP8556 */ + backlight@2c { + compatible = "ti,lp8556"; + reg = <0x2c>; + + bl-name = "lcd-bl"; + dev-ctrl = /bits/ 8 <0x85>; + init-brt = /bits/ 8 <0x10>; + }; + + /* LP8557 */ + backlight@2c { + compatible = "ti,lp8557"; + reg = <0x2c>; + enable-supply = <&backlight_vddio>; + power-supply = <&backlight_vdd>; + + dev-ctrl = /bits/ 8 <0x41>; + init-brt = /bits/ 8 <0x0a>; + + /* 4V OV, 4 output LED string enabled */ + rom_14h { + rom-addr = /bits/ 8 <0x14>; + rom-val = /bits/ 8 <0xcf>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/max8925-backlight.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/max8925-backlight.txt new file mode 100644 index 0000000000000000000000000000000000000000..b4cffdaa41377a8aa7d011b4becd1541ded49ff1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/max8925-backlight.txt @@ -0,0 +1,10 @@ +88pm860x-backlight bindings + +Optional properties: + - maxim,max8925-dual-string: whether support dual string + +Example: + + backlights { + maxim,max8925-dual-string = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/pm8941-wled.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/pm8941-wled.txt new file mode 100644 index 0000000000000000000000000000000000000000..e5b294dafc5837f9d580531ad1471bdd9ad3f55d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/pm8941-wled.txt @@ -0,0 +1,42 @@ +Binding for Qualcomm PM8941 WLED driver + +Required properties: +- compatible: should be "qcom,pm8941-wled" +- reg: slave address + +Optional properties: +- default-brightness: brightness value on boot, value from: 0-4095 + default: 2048 +- label: The name of the backlight device +- qcom,cs-out: bool; enable current sink output +- qcom,cabc: bool; enable content adaptive backlight control +- qcom,ext-gen: bool; use externally generated modulator signal to dim +- qcom,current-limit: mA; per-string current limit; value from 0 to 25 + default: 20mA +- qcom,current-boost-limit: mA; boost current limit; one of: + 105, 385, 525, 805, 980, 1260, 1400, 1680 + default: 805mA +- qcom,switching-freq: kHz; switching frequency; one of: + 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, + 1600, 1920, 2400, 3200, 4800, 9600, + default: 1600kHz +- qcom,ovp: V; Over-voltage protection limit; one of: + 27, 29, 32, 35 + default: 29V +- qcom,num-strings: #; number of led strings attached; value from 1 to 3 + default: 2 + +Example: + +pm8941-wled@d800 { + compatible = "qcom,pm8941-wled"; + reg = <0xd800>; + label = "backlight"; + + qcom,cs-out; + qcom,current-limit = <20>; + qcom,current-boost-limit = <805>; + qcom,switching-freq = <1600>; + qcom,ovp = <29>; + qcom,num-strings = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/pwm-backlight.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/pwm-backlight.txt new file mode 100644 index 0000000000000000000000000000000000000000..64fa2fbd98c9e6a48fc9031423acffbe96e766a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/pwm-backlight.txt @@ -0,0 +1,61 @@ +pwm-backlight bindings + +Required properties: + - compatible: "pwm-backlight" + - pwms: OF device-tree PWM specification (see PWM binding[0]) + - power-supply: regulator for supply voltage + +Optional properties: + - pwm-names: a list of names for the PWM devices specified in the + "pwms" property (see PWM binding[0]) + - enable-gpios: contains a single GPIO specifier for the GPIO which enables + and disables the backlight (see GPIO binding[1]) + - post-pwm-on-delay-ms: Delay in ms between setting an initial (non-zero) PWM + and enabling the backlight using GPIO. + - pwm-off-delay-ms: Delay in ms between disabling the backlight using GPIO + and setting PWM value to 0. + - brightness-levels: Array of distinct brightness levels. Typically these + are in the range from 0 to 255, but any range starting at + 0 will do. The actual brightness level (PWM duty cycle) + will be interpolated from these values. 0 means a 0% duty + cycle (darkest/off), while the last value in the array + represents a 100% duty cycle (brightest). + - default-brightness-level: The default brightness level (index into the + array defined by the "brightness-levels" property). + - num-interpolated-steps: Number of interpolated steps between each value + of brightness-levels table. This way a high + resolution pwm duty cycle can be used without + having to list out every possible value in the + brightness-level array. + +[0]: Documentation/devicetree/bindings/pwm/pwm.txt +[1]: Documentation/devicetree/bindings/gpio/gpio.txt + +Example: + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 5000000>; + + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + + power-supply = <&vdd_bl_reg>; + enable-gpios = <&gpio 58 0>; + post-pwm-on-delay-ms = <10>; + pwm-off-delay-ms = <10>; + }; + +Example using num-interpolation-steps: + + backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 5000000>; + + brightness-levels = <0 2048 4096 8192 16384 65535>; + num-interpolated-steps = <2048>; + default-brightness-level = <4096>; + + power-supply = <&vdd_bl_reg>; + enable-gpios = <&gpio 58 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/qcom-spmi-wled.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/qcom-spmi-wled.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0447c6d6469f5dc4efb658b2ae699310b9352a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/qcom-spmi-wled.txt @@ -0,0 +1,303 @@ +Bindings for Qualcomm Technologies, Inc. WLED driver + +WLED (White Light Emitting Diode) driver is used for controlling display +backlight that is part of PMIC on Qualcomm Technologies, Inc. reference +platforms. The PMIC is connected to the host processor via SPMI bus. + +- compatible + Usage: required + Value type: + Definition: should be one of the below. + "qcom,pmi8998-spmi-wled", + "qcom,pm8150l-spmi-wled", + "qcom,pm6150l-spmi-wled" + "qcom,pm660l-spmi-wled" + +- reg + Usage: required + Value type: + Definition: Base address and size of the WLED modules. + +- reg-names + Usage: required + Value type: + Definition: Names associated with base addresses. should be + "wled-ctrl-base", "wled-sink-base". + +- interrupts + Usage: optional + Value type: + Definition: Interrupts associated with WLED. Interrupts can be + specified as per the encoding listed under + Documentation/devicetree/bindings/spmi/ + qcom,spmi-pmic-arb.txt. + +- interrupt-names + Usage: optional + Value type: + Definition: Interrupt names associated with the interrupts. + Currently supported interrupts are "sc-irq", "ovp-irq", + "pre-flash-irq" and "flash-irq". Pre_flash and flash + interrupts can be specified only for PMICs that has WLED5. + +- label + Usage: required + Value type: + Definition: The name of the backlight device. + +- default-brightness + Usage: optional + Value type: + Definition: Brightness value on boot. Default is 2048. + Range of values are: + For pmi8998, it is 0-4095. + For pm8150l, this can vary from 0-4095 or 0-32767 depending + on the brightness control mode. If CABC is enabled, 0-4095 + range is used. + +- max-brightness + Usage: optional + Value type: + Definition: Maximum brightness level. Allowed values are: + For pmi8998, it is 4095. + For pm8150l, this can be either 4095 or 32767. + If CABC is enabled, this is capped to 4095. + +- qcom,fs-current-limit + Usage: optional + Value type: + Definition: per-string full scale current limit in uA. value from + 0 to 30000 with 5000 uA resolution. Default: 25000 uA + +- qcom,boost-current-limit + Usage: optional + Value type: + Definition: ILIM threshold in mA. values are 105, 280, 450, 620, 970, + 1150, 1300, 1500. Default: 970 mA + +- qcom,switching-freq + Usage: optional + Value type: + Definition: Switching frequency in KHz. values are + 600, 640, 685, 738, 800, 872, 960, 1066, 1200, 1371, + 1600, 1920, 2400, 3200, 4800, 9600. + Default: 800 KHz + +- qcom,ovp + Usage: optional + Value type: + Definition: Over-voltage protection limit in mV. values are 31100, + 29600, 19600, 18100. + Default: 29600 mV + +- qcom,string-cfg + Usage: optional + Value type: + Definition: Bit mask of the WLED strings. Bit 0 to 3 indicates strings + 0 to 3 respectively. WLED module has four strings of leds + numbered from 0 to 3. Each string of leds are operated + individually. Specify the strings using the bit mask. Any + combination of led strings can be used. + Default value is 15 (b1111). + +- qcom,en-cabc + Usage: optional + Value type: + Definition: Specify if cabc (content adaptive backlight control) is + needed. + +- qcom,ext-pfet-sc-pro-en + Usage: optional + Value type: + Definition: Specify if external PFET control for short circuit + protection is needed. This is not applicable for PM8150L. + +- qcom,auto-calibration + Usage: optional + Value type: + Definition: Enables auto-calibration of the WLED sink configuration. + +- qcom,modulator-sel + Usage: optional + Value type: + Definition: Selects the modulator used for brightness modulation. + Allowed values are: + 0 - Modulator A + 1 - Modulator B + If not specified, then modulator A will be used by default. + This property is applicable only to WLED5 peripheral. + +- qcom,cabc-sel + Usage: optional + Value type: + Definition: Selects the CABC pin signal used for brightness modulation. + Allowed values are: + 0 - CABC disabled + 1 - CABC 1 + 2 - CABC 2 + 3 - External signal (e.g. LPG) is used for dimming + This property is applicable only to WLED5 peripheral. + +- qcom,pmic-revid + Usage: optional + Value type: + Definition: If specified, can be used to get PMIC revision information. + +- qcom,leds-per-string + Usage: optional + Value type: + Definition: If specified, can be used to calculate available current + during selfie flash operation. If not specified, available + current calculated is simply the configured threshold. + +Following properties are for child subnodes that are needed for WLED preflash +(or torch), flash and switch. These child subnodes can be specified only for +PMICs that has WLED5 (e.g. PM8150L). + +For wled_torch child subnode, + +- label + Usage: required + Value type: + Definition: Should be "torch". + +- qcom,default-led-trigger + Usage: optional + Value type: + Definition: Name for LED trigger. If unspecified, "wled_torch" is used. + +- qcom,wled-torch-fsc + Usage: optional + Value type: + Definition: WLED torch full scale current in mA. This configures the + maximum current allowed for torch device. Allowed values + are from 5 to 60 mA with a step of 5 mA. If not specified, + default value is set to 30 mA. + +- qcom,wled-torch-step + Usage: optional + Value type: + Definition: WLED torch step delay in us. This configures the step delay + when the output is ramped up to the desired target current. + Allowed values are from 50 to 400 us with a step of 50 us. + If not specified, default value is set to 200 us. + +- qcom,wled-torch-timer + Usage: optional + Value type: + Definition: WLED torch safety timer in ms. This configures the safety + timer to turn off torch automatically after timer expiry. + Allowed values are: 50, 100, 200, 400, 600, 800, 1000 and + 1200. If not specified, default value is set to 1200 ms. + +For wled_flash child subnode, + +- label + Usage: required + Value type: + Definition: Should be "flash". + +- qcom,default-led-trigger + Usage: optional + Value type: + Definition: Name for LED trigger. If unspecified, "wled_flash" is used. + +- qcom,wled-flash-fsc + Usage: optional + Value type: + Definition: WLED flash full scale current in mA. This configures the + maximum current allowed for flash device. Allowed values + are from 5 to 60 mA with a step of 5 mA. If not specified, + default value is set to 40 mA. + +- qcom,wled-flash-step + Usage: optional + Value type: + Definition: WLED flash step delay in us. This configures the step delay + when the output is ramped up to the desired target current. + Allowed values are from 50 to 400 us with a step of 50 us. + If not specified, default value is set to 200 us. + +- qcom,wled-flash-timer + Usage: optional + Value type: + Definition: WLED flash safety timer in ms. This configures the safety + timer to turn off flash automatically after timer expiry. + Allowed values are: 50, 100, 200, 400, 600, 800, 1000 and + 1200. If not specified, default value is set to 100 ms. + +For wled_switch child subnode, + +- label + Usage: required + Value type: + Definition: Should be "switch". + +- qcom,default-led-trigger + Usage: optional + Value type: + Definition: Name for LED trigger. If unspecified, "wled_switch" is + used. + +Example: + +qcom-wled@d800 { + compatible = "qcom,pmi8998-spmi-wled"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xd800 0xd900>; + reg-names = "wled-ctrl-base", "wled-sink-base"; + label = "backlight"; + + interrupts = <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq", "ovp-irq"; + qcom,fs-current-limit = <25000>; + qcom,boost-current-limit = <970>; + qcom,switching-freq = <800>; + qcom,ovp = <29600>; + qcom,string-cfg = <15>; +}; + +qcom-wled@d800 { + compatible = "qcom,pm8150l-spmi-wled"; + #address-cells = <2>; + #size-cells = <0>; + reg = <0xd800 0x100>, <0xd900 0x100>; + reg-names = "wled-ctrl-base", "wled-sink-base"; + label = "backlight"; + + interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq"; + qcom,string-cfg = <7>; + + wled_torch: qcom,wled-torch { + label = "torch"; + qcom,wled-torch-fsc = <40>; + qcom,wled-torch-step = <300>; + qcom,wled-torch-timer = <600>; + }; + + wled_flash: qcom,wled-flash { + label = "flash"; + qcom,wled-flash-fsc = <60>; + qcom,wled-flash-step = <100>; + qcom,wled-flash-timer = <200>; + }; + + wled_switch: qcom,wled-switch { + label = "switch"; + }; +}; + +qcom,leds@d800 { + compatible = "qcom,pm660l-spmi-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base"; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq"; + linux,name = "wled"; + linux,default-led-trigger = "bkl-trigger"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/sky81452-backlight.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/sky81452-backlight.txt new file mode 100644 index 0000000000000000000000000000000000000000..8bf2940f54bcfc86eaa716485640c92ea3f80021 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/sky81452-backlight.txt @@ -0,0 +1,29 @@ +SKY81452-backlight bindings + +Required properties: +- compatible : Must be "skyworks,sky81452-backlight" + +Optional properties: +- name : Name of backlight device. Default is 'lcd-backlight'. +- gpios : GPIO to use to EN pin. + See Documentation/devicetree/bindings/gpio/gpio.txt +- led-sources : List of enabled channels from 0 to 5. + See Documentation/devicetree/bindings/leds/common.txt +- skyworks,ignore-pwm : Ignore both PWM input +- skyworks,dpwm-mode : Enable DPWM dimming mode, otherwise Analog dimming. +- skyworks,phase-shift : Enable phase shift mode +- skyworks,short-detection-threshold-volt + : It should be one of 4, 5, 6 and 7V. +- skyworks,current-limit-mA + : It should be 2300mA or 2750mA. + +Example: + + backlight { + compatible = "skyworks,sky81452-backlight"; + name = "pwm-backlight"; + led-sources = <0 1 2 5>; + skyworks,ignore-pwm; + skyworks,phase-shift; + skyworks,current-limit-mA = <2300>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/tps65217-backlight.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/tps65217-backlight.txt new file mode 100644 index 0000000000000000000000000000000000000000..5fb9279ac2874885456187c5e9504da095c2a82c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/tps65217-backlight.txt @@ -0,0 +1,27 @@ +TPS65217 family of regulators + +The TPS65217 chip contains a boost converter and current sinks which can be +used to drive LEDs for use as backlights. + +Required properties: +- compatible: "ti,tps65217" +- reg: I2C slave address +- backlight: node for specifying WLED1 and WLED2 lines in TPS65217 +- isel: selection bit, valid values: 1 for ISEL1 (low-level) and 2 for ISEL2 (high-level) +- fdim: PWM dimming frequency, valid values: 100, 200, 500, 1000 +- default-brightness: valid values: 0-100 + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps: tps@24 { + reg = <0x24>; + compatible = "ti,tps65217"; + backlight { + isel = <1>; /* 1 - ISET1, 2 ISET2 */ + fdim = <100>; /* TPS65217_BL_FDIM_100HZ */ + default-brightness = <50>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/backlight/zii,rave-sp-backlight.txt b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/zii,rave-sp-backlight.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff5c921386502f296a88be04abf66a1e30ac5d92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/backlight/zii,rave-sp-backlight.txt @@ -0,0 +1,23 @@ +Zodiac Inflight Innovations RAVE Supervisory Processor Backlight Bindings + +RAVE SP backlight device is a "MFD cell" device corresponding to +backlight functionality of RAVE Supervisory Processor. It is expected +that its Device Tree node is specified as a child of the node +corresponding to the parent RAVE SP device (as documented in +Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) + +Required properties: + +- compatible: Should be "zii,rave-sp-backlight" + +Example: + + rave-sp { + compatible = "zii,rave-sp-rdu1"; + current-speed = <38400>; + + backlight { + compatible = "zii,rave-sp-backlight"; + }; + } + diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/common.txt b/arch/arm64/boot/dts/vendor/bindings/leds/common.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa1399814a2ae55c79eed6f1ae8695d64625472e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/common.txt @@ -0,0 +1,115 @@ +* Common leds properties. + +LED and flash LED devices provide the same basic functionality as current +regulators, but extended with LED and flash LED specific features like +blinking patterns, flash timeout, flash faults and external flash strobe mode. + +Many LED devices expose more than one current output that can be connected +to one or more discrete LED component. Since the arrangement of connections +can influence the way of the LED device initialization, the LED components +have to be tightly coupled with the LED device binding. They are represented +by child nodes of the parent LED device binding. + +Optional properties for child nodes: +- led-sources : List of device current outputs the LED is connected to. The + outputs are identified by the numbers that must be defined + in the LED device binding documentation. +- label : The label for this LED. If omitted, the label is taken from the node + name (excluding the unit address). It has to uniquely identify + a device, i.e. no other LED class device can be assigned the same + label. + +- default-state : The initial state of the LED. Valid values are "on", "off", + and "keep". If the LED is already on or off and the default-state property is + set the to same value, then no glitch should be produced where the LED + momentarily turns off (or on). The "keep" setting will keep the LED at + whatever its current state is, without producing a glitch. The default is + off if this property is not present. + +- linux,default-trigger : This parameter, if present, is a + string defining the trigger assigned to the LED. Current triggers are: + "backlight" - LED will act as a back-light, controlled by the framebuffer + system + "default-on" - LED will turn on (but for leds-gpio see "default-state" + property in Documentation/devicetree/bindings/leds/leds-gpio.txt) + "heartbeat" - LED "double" flashes at a load average based rate + "disk-activity" - LED indicates disk activity + "ide-disk" - LED indicates IDE disk activity (deprecated), + in new implementations use "disk-activity" + "timer" - LED flashes at a fixed, configurable rate + +- led-max-microamp : Maximum LED supply current in microamperes. This property + can be made mandatory for the board configurations + introducing a risk of hardware damage in case an excessive + current is set. + For flash LED controllers with configurable current this + property is mandatory for the LEDs in the non-flash modes + (e.g. torch or indicator). + +- panic-indicator : This property specifies that the LED should be used, + if at all possible, as a panic indicator. + +- trigger-sources : List of devices which should be used as a source triggering + this LED activity. Some LEDs can be related to a specific + device and should somehow indicate its state. E.g. USB 2.0 + LED may react to device(s) in a USB 2.0 port(s). + Another common example is switch or router with multiple + Ethernet ports each of them having its own LED assigned + (assuming they are not hardwired). In such cases this + property should contain phandle(s) of related source + device(s). + In many cases LED can be related to more than one device + (e.g. one USB LED vs. multiple USB ports). Each source + should be represented by a node in the device tree and be + referenced by a phandle and a set of phandle arguments. A + length of arguments should be specified by the + #trigger-source-cells property in the source node. + +Required properties for flash LED child nodes: +- flash-max-microamp : Maximum flash LED supply current in microamperes. +- flash-max-timeout-us : Maximum timeout in microseconds after which the flash + LED is turned off. + +For controllers that have no configurable current the flash-max-microamp +property can be omitted. +For controllers that have no configurable timeout the flash-max-timeout-us +property can be omitted. + +* Trigger source providers + +Each trigger source should be represented by a device tree node. It may be e.g. +a USB port or an Ethernet device. + +Required properties for trigger source: +- #trigger-source-cells : Number of cells in a source trigger. Typically 0 for + nodes of simple trigger sources (e.g. a specific USB + port). + +* Examples + +gpio-leds { + compatible = "gpio-leds"; + + system-status { + label = "Status"; + linux,default-trigger = "heartbeat"; + gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>; + }; + + usb { + gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + trigger-sources = <&ohci_port1>, <&ehci_port1>; + }; +}; + +max77693-led { + compatible = "maxim,max77693-led"; + + camera-flash { + label = "Flash"; + led-sources = <0>, <1>; + led-max-microamp = <50000>; + flash-max-microamp = <320000>; + flash-max-timeout-us = <500000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/irled/gpio-ir-tx.txt b/arch/arm64/boot/dts/vendor/bindings/leds/irled/gpio-ir-tx.txt new file mode 100644 index 0000000000000000000000000000000000000000..cbe8dfd29715b1f7660906d3cd87ce46e422abae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/irled/gpio-ir-tx.txt @@ -0,0 +1,14 @@ +Device tree bindings for IR LED connected through gpio pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "gpio-ir-tx". + - gpios : Should specify the IR LED GPIO, see "gpios property" in + Documentation/devicetree/bindings/gpio/gpio.txt. Active low LEDs + should be indicated using flags in the GPIO specifier. + +Example: + irled@0 { + compatible = "gpio-ir-tx"; + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/irled/pwm-ir-tx.txt b/arch/arm64/boot/dts/vendor/bindings/leds/irled/pwm-ir-tx.txt new file mode 100644 index 0000000000000000000000000000000000000000..66e5672c2e3d852262a7d027fff3ec2c8daf8204 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/irled/pwm-ir-tx.txt @@ -0,0 +1,13 @@ +Device tree bindings for IR LED connected through pwm pin which is used as +remote controller transmitter. + +Required properties: + - compatible: should be "pwm-ir-tx". + - pwms : PWM property to point to the PWM device (phandle)/port (id) + and to specify the period time to be used: <&phandle id period_ns>; + +Example: + irled { + compatible = "pwm-ir-tx"; + pwms = <&pwm0 0 10000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/irled/spi-ir-led.txt b/arch/arm64/boot/dts/vendor/bindings/leds/irled/spi-ir-led.txt new file mode 100644 index 0000000000000000000000000000000000000000..896b6997cf30d8cf3fe9a6dbcd457aa0fa11ec28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/irled/spi-ir-led.txt @@ -0,0 +1,29 @@ +Device tree bindings for IR LED connected through SPI bus which is used as +remote controller. + +The IR LED switch is connected to the MOSI line of the SPI device and the data +are delivered thourgh that. + +Required properties: + - compatible: should be "ir-spi-led". + +Optional properties: + - duty-cycle: 8 bit balue that represents the percentage of one period + in which the signal is active. It can be 50, 60, 70, 75, 80 or 90. + - led-active-low: boolean value that specifies whether the output is + negated with a NOT gate. + - power-supply: specifies the power source. It can either be a regulator + or a gpio which enables a regulator, i.e. a regulator-fixed as + described in + Documentation/devicetree/bindings/regulator/fixed-regulator.txt + +Example: + + irled@0 { + compatible = "ir-spi-led"; + reg = <0x0>; + spi-max-frequency = <5000000>; + power-supply = <&vdd_led>; + led-active-low; + duty-cycle = /bits/ 8 <60>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-aat1290.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-aat1290.txt new file mode 100644 index 0000000000000000000000000000000000000000..85c0c58617f6da50d3ac0f7f4177df3d9aeb68ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-aat1290.txt @@ -0,0 +1,73 @@ +* Skyworks Solutions, Inc. AAT1290 Current Regulator for Flash LEDs + +The device is controlled through two pins: FL_EN and EN_SET. The pins when, +asserted high, enable flash strobe and movie mode (max 1/2 of flash current) +respectively. In order to add a capability of selecting the strobe signal source +(e.g. CPU or camera sensor) there is an additional switch required, independent +of the flash chip. The switch is controlled with pin control. + +Required properties: + +- compatible : Must be "skyworks,aat1290". +- flen-gpios : Must be device tree identifier of the flash device FL_EN pin. +- enset-gpios : Must be device tree identifier of the flash device EN_SET pin. + +Optional properties: +- pinctrl-names : Must contain entries: "default", "host", "isp". Entries + "default" and "host" must refer to the same pin configuration + node, which sets the host as a strobe signal provider. Entry + "isp" must refer to the pin configuration node, which sets the + ISP as a strobe signal provider. + +A discrete LED element connected to the device must be represented by a child +node - see Documentation/devicetree/bindings/leds/common.txt. + +Required properties of the LED child node: +- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt +- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt + Maximum flash LED supply current can be calculated using + following formula: I = 1A * 162kohm / Rset. +- flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt + Maximum flash timeout can be calculated using following + formula: T = 8.82 * 10^9 * Ct. + +Optional properties of the LED child node: +- label : see Documentation/devicetree/bindings/leds/common.txt + +Example (by Ct = 220nF, Rset = 160kohm and exynos4412-trats2 board with +a switch that allows for routing strobe signal either from the host or from +the camera sensor): + +#include "exynos4412.dtsi" + +aat1290 { + compatible = "skyworks,aat1290"; + flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>; + enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default", "host", "isp"; + pinctrl-0 = <&camera_flash_host>; + pinctrl-1 = <&camera_flash_host>; + pinctrl-2 = <&camera_flash_isp>; + + camera_flash: flash-led { + label = "aat1290-flash"; + led-max-microamp = <520833>; + flash-max-microamp = <1012500>; + flash-max-timeout-us = <1940000>; + }; +}; + +&pinctrl_0 { + camera_flash_host: camera-flash-host { + samsung,pins = "gpj1-0"; + samsung,pin-function = <1>; + samsung,pin-val = <0>; + }; + + camera_flash_isp: camera-flash-isp { + samsung,pins = "gpj1-0"; + samsung,pin-function = <1>; + samsung,pin-val = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-bcm6328.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-bcm6328.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccebce597f372b656adf76ab0f1eccb6e85c6a30 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-bcm6328.txt @@ -0,0 +1,319 @@ +LEDs connected to Broadcom BCM6328 controller + +This controller is present on BCM6318, BCM6328, BCM6362 and BCM63268. +In these SoCs it's possible to control LEDs both as GPIOs or by hardware. +However, on some devices there are Serial LEDs (LEDs connected to a 74x164 +controller), which can either be controlled by software (exporting the 74x164 +as spi-gpio. See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or +by hardware using this driver. +Some of these Serial LEDs are hardware controlled (e.g. ethernet LEDs) and +exporting the 74x164 as spi-gpio prevents those LEDs to be hardware +controlled, so the only chance to keep them working is by using this driver. + +BCM6328 LED controller has a HWDIS register, which controls whether a LED +should be controlled by a hardware signal instead of the MODE register value, +with 0 meaning hardware control enabled and 1 hardware control disabled. This +is usually 1:1 for hardware to LED signals, but through the activity/link +registers you have some limited control over rerouting the LEDs (as +explained later in brcm,link-signal-sources). Even if a LED is hardware +controlled you are still able to make it blink or light it up if it isn't, +but you can't turn it off if the hardware decides to light it up. For this +reason, hardware controlled LEDs aren't registered as LED class devices. + +Required properties: + - compatible : should be "brcm,bcm6328-leds". + - #address-cells : must be 1. + - #size-cells : must be 0. + - reg : BCM6328 LED controller address and size. + +Optional properties: + - brcm,serial-leds : Boolean, enables Serial LEDs. + Default : false + - brcm,serial-mux : Boolean, enables Serial LEDs multiplexing. + Default : false + - brcm,serial-clk-low : Boolean, makes clock signal active low. + Default : false + - brcm,serial-dat-low : Boolean, makes data signal active low. + Default : false + - brcm,serial-shift-inv : Boolean, inverts Serial LEDs shift direction. + Default : false + +Each LED is represented as a sub-node of the brcm,bcm6328-leds device. + +LED sub-node required properties: + - reg : LED pin number (only LEDs 0 to 23 are valid). + +LED sub-node optional properties: + a) Optional properties for sub-nodes related to software controlled LEDs: + - label : see Documentation/devicetree/bindings/leds/common.txt + - active-low : Boolean, makes LED active low. + Default : false + - default-state : see + Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : see + Documentation/devicetree/bindings/leds/common.txt + + b) Optional properties for sub-nodes related to hardware controlled LEDs: + - brcm,hardware-controlled : Boolean, makes this LED hardware controlled. + Default : false + - brcm,link-signal-sources : An array of hardware link + signal sources. Up to four link hardware signals can get muxed into + these LEDs. Only valid for LEDs 0 to 7, where LED signals 0 to 3 may + be muxed to LEDs 0 to 3, and signals 4 to 7 may be muxed to LEDs + 4 to 7. A signal can be muxed to more than one LED, and one LED can + have more than one source signal. + - brcm,activity-signal-sources : An array of hardware activity + signal sources. Up to four activity hardware signals can get muxed into + these LEDs. Only valid for LEDs 0 to 7, where LED signals 0 to 3 may + be muxed to LEDs 0 to 3, and signals 4 to 7 may be muxed to LEDs + 4 to 7. A signal can be muxed to more than one LED, and one LED can + have more than one source signal. + +Examples: +Scenario 1 : BCM6328 with 4 EPHY LEDs + leds0: led-controller@10000800 { + compatible = "brcm,bcm6328-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10000800 0x24>; + + alarm_red@2 { + reg = <2>; + active-low; + label = "red:alarm"; + }; + inet_green@3 { + reg = <3>; + active-low; + label = "green:inet"; + }; + power_green@4 { + reg = <4>; + active-low; + label = "green:power"; + default-state = "on"; + }; + ephy0_spd@17 { + reg = <17>; + brcm,hardware-controlled; + }; + ephy1_spd@18 { + reg = <18>; + brcm,hardware-controlled; + }; + ephy2_spd@19 { + reg = <19>; + brcm,hardware-controlled; + }; + ephy3_spd@20 { + reg = <20>; + brcm,hardware-controlled; + }; + }; + +Scenario 2 : BCM63268 with Serial/GPHY0 LEDs + leds0: led-controller@10001900 { + compatible = "brcm,bcm6328-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10001900 0x24>; + brcm,serial-leds; + brcm,serial-dat-low; + brcm,serial-shift-inv; + + gphy0_spd0@0 { + reg = <0>; + brcm,hardware-controlled; + brcm,link-signal-sources = <0>; + }; + gphy0_spd1@1 { + reg = <1>; + brcm,hardware-controlled; + brcm,link-signal-sources = <1>; + }; + inet_red@2 { + reg = <2>; + active-low; + label = "red:inet"; + }; + dsl_green@3 { + reg = <3>; + active-low; + label = "green:dsl"; + }; + usb_green@4 { + reg = <4>; + active-low; + label = "green:usb"; + }; + wps_green@7 { + reg = <7>; + active-low; + label = "green:wps"; + }; + inet_green@8 { + reg = <8>; + active-low; + label = "green:inet"; + }; + ephy0_act@9 { + reg = <9>; + brcm,hardware-controlled; + }; + ephy1_act@10 { + reg = <10>; + brcm,hardware-controlled; + }; + ephy2_act@11 { + reg = <11>; + brcm,hardware-controlled; + }; + gphy0_act@12 { + reg = <12>; + brcm,hardware-controlled; + }; + ephy0_spd@13 { + reg = <13>; + brcm,hardware-controlled; + }; + ephy1_spd@14 { + reg = <14>; + brcm,hardware-controlled; + }; + ephy2_spd@15 { + reg = <15>; + brcm,hardware-controlled; + }; + power_green@20 { + reg = <20>; + active-low; + label = "green:power"; + default-state = "on"; + }; + }; + +Scenario 3 : BCM6362 with 1 LED for each EPHY + leds0: led-controller@10001900 { + compatible = "brcm,bcm6328-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10001900 0x24>; + + usb@0 { + reg = <0>; + brcm,hardware-controlled; + brcm,link-signal-sources = <0>; + brcm,activity-signal-sources = <0>; + /* USB link/activity routed to USB LED */ + }; + inet@1 { + reg = <1>; + brcm,hardware-controlled; + brcm,activity-signal-sources = <1>; + /* INET activity routed to INET LED */ + }; + ephy0@4 { + reg = <4>; + brcm,hardware-controlled; + brcm,link-signal-sources = <4>; + /* EPHY0 link routed to EPHY0 LED */ + }; + ephy1@5 { + reg = <5>; + brcm,hardware-controlled; + brcm,link-signal-sources = <5>; + /* EPHY1 link routed to EPHY1 LED */ + }; + ephy2@6 { + reg = <6>; + brcm,hardware-controlled; + brcm,link-signal-sources = <6>; + /* EPHY2 link routed to EPHY2 LED */ + }; + ephy3@7 { + reg = <7>; + brcm,hardware-controlled; + brcm,link-signal-sources = <7>; + /* EPHY3 link routed to EPHY3 LED */ + }; + power_green@20 { + reg = <20>; + active-low; + label = "green:power"; + default-state = "on"; + }; + }; + +Scenario 4 : BCM6362 with 1 LED for all EPHYs + leds0: led-controller@10001900 { + compatible = "brcm,bcm6328-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10001900 0x24>; + + usb@0 { + reg = <0>; + brcm,hardware-controlled; + brcm,link-signal-sources = <0 1>; + brcm,activity-signal-sources = <0 1>; + /* USB/INET link/activity routed to USB LED */ + }; + ephy@4 { + reg = <4>; + brcm,hardware-controlled; + brcm,link-signal-sources = <4 5 6 7>; + /* EPHY0/1/2/3 link routed to EPHY0 LED */ + }; + power_green@20 { + reg = <20>; + active-low; + label = "green:power"; + default-state = "on"; + }; + }; + +Scenario 5 : BCM6362 with EPHY LEDs swapped + leds0: led-controller@10001900 { + compatible = "brcm,bcm6328-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10001900 0x24>; + + usb@0 { + reg = <0>; + brcm,hardware-controlled; + brcm,link-signal-sources = <0>; + brcm,activity-signal-sources = <0 1>; + /* USB link/act and INET act routed to USB LED */ + }; + ephy0@4 { + reg = <4>; + brcm,hardware-controlled; + brcm,link-signal-sources = <7>; + /* EPHY3 link routed to EPHY0 LED */ + }; + ephy1@5 { + reg = <5>; + brcm,hardware-controlled; + brcm,link-signal-sources = <6>; + /* EPHY2 link routed to EPHY1 LED */ + }; + ephy2@6 { + reg = <6>; + brcm,hardware-controlled; + brcm,link-signal-sources = <5>; + /* EPHY1 link routed to EPHY2 LED */ + }; + ephy3@7 { + reg = <7>; + brcm,hardware-controlled; + brcm,link-signal-sources = <4>; + /* EPHY0 link routed to EPHY3 LED */ + }; + power_green@20 { + reg = <20>; + active-low; + label = "green:power"; + default-state = "on"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-bcm6358.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-bcm6358.txt new file mode 100644 index 0000000000000000000000000000000000000000..da5708e7b43b93ba83a0f759d39452c44be8223d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-bcm6358.txt @@ -0,0 +1,145 @@ +LEDs connected to Broadcom BCM6358 controller + +This controller is present on BCM6358 and BCM6368. +In these SoCs there are Serial LEDs (LEDs connected to a 74x164 controller), +which can either be controlled by software (exporting the 74x164 as spi-gpio. +See Documentation/devicetree/bindings/gpio/gpio-74x164.txt), or +by hardware using this driver. + +Required properties: + - compatible : should be "brcm,bcm6358-leds". + - #address-cells : must be 1. + - #size-cells : must be 0. + - reg : BCM6358 LED controller address and size. + +Optional properties: + - brcm,clk-div : SCK signal divider. Possible values are 1, 2, 4 and 8. + Default : 1 + - brcm,clk-dat-low : Boolean, makes clock and data signals active low. + Default : false + +Each LED is represented as a sub-node of the brcm,bcm6358-leds device. + +LED sub-node required properties: + - reg : LED pin number (only LEDs 0 to 31 are valid). + +LED sub-node optional properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + - active-low : Boolean, makes LED active low. + Default : false + - default-state : see + Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : see + Documentation/devicetree/bindings/leds/common.txt + +Examples: +Scenario 1 : BCM6358 + leds0: led-controller@fffe00d0 { + compatible = "brcm,bcm6358-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfffe00d0 0x8>; + + alarm_white { + reg = <0>; + active-low; + label = "white:alarm"; + }; + tv_white { + reg = <2>; + active-low; + label = "white:tv"; + }; + tel_white { + reg = <3>; + active-low; + label = "white:tel"; + }; + adsl_white { + reg = <4>; + active-low; + label = "white:adsl"; + }; + }; + +Scenario 2 : BCM6368 + leds0: led-controller@100000d0 { + compatible = "brcm,bcm6358-leds"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x100000d0 0x8>; + brcm,pol-low; + brcm,clk-div = <4>; + + power_red { + reg = <0>; + active-low; + label = "red:power"; + }; + power_green { + reg = <1>; + active-low; + label = "green:power"; + default-state = "on"; + }; + power_blue { + reg = <2>; + label = "blue:power"; + }; + broadband_red { + reg = <3>; + active-low; + label = "red:broadband"; + }; + broadband_green { + reg = <4>; + label = "green:broadband"; + }; + broadband_blue { + reg = <5>; + active-low; + label = "blue:broadband"; + }; + wireless_red { + reg = <6>; + active-low; + label = "red:wireless"; + }; + wireless_green { + reg = <7>; + active-low; + label = "green:wireless"; + }; + wireless_blue { + reg = <8>; + label = "blue:wireless"; + }; + phone_red { + reg = <9>; + active-low; + label = "red:phone"; + }; + phone_green { + reg = <10>; + active-low; + label = "green:phone"; + }; + phone_blue { + reg = <11>; + label = "blue:phone"; + }; + upgrading_red { + reg = <12>; + active-low; + label = "red:upgrading"; + }; + upgrading_green { + reg = <13>; + active-low; + label = "green:upgrading"; + }; + upgrading_blue { + reg = <14>; + label = "blue:upgrading"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-cpcap.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-cpcap.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebf7cdc7f70c2d545db6669d5547c5128878251a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-cpcap.txt @@ -0,0 +1,29 @@ +Motorola CPCAP PMIC LEDs +------------------------ + +This module is part of the CPCAP. For more details about the whole +chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt. + +Requires node properties: +- compatible: should be one of + * "motorola,cpcap-led-mdl" (Main Display Lighting) + * "motorola,cpcap-led-kl" (Keyboard Lighting) + * "motorola,cpcap-led-adl" (Aux Display Lighting) + * "motorola,cpcap-led-red" (Red Triode) + * "motorola,cpcap-led-green" (Green Triode) + * "motorola,cpcap-led-blue" (Blue Triode) + * "motorola,cpcap-led-cf" (Camera Flash) + * "motorola,cpcap-led-bt" (Bluetooth) + * "motorola,cpcap-led-cp" (Camera Privacy LED) +- label: see Documentation/devicetree/bindings/leds/common.txt +- vdd-supply: A phandle to the regulator powering the LED + +Example: + +&cpcap { + cpcap_led_red: red-led { + compatible = "motorola,cpcap-led-red"; + label = "cpcap:red"; + vdd-supply = <&sw5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-cr0014114.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-cr0014114.txt new file mode 100644 index 0000000000000000000000000000000000000000..4255b19ad25cf597efdd99bf3591810d4432d707 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-cr0014114.txt @@ -0,0 +1,54 @@ +Crane Merchandising System - cr0014114 LED driver +------------------------------------------------- + +This LED Board is widely used in vending machines produced +by Crane Merchandising Systems. + +Required properties: +- compatible: "crane,cr0014114" + +Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt +apply. In particular, "reg" and "spi-max-frequency" properties must be given. + +LED sub-node properties: +- label : + see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt + +Example +------- + +led-controller@0 { + compatible = "crane,cr0014114"; + reg = <0>; + spi-max-frequency = <50000>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + label = "red:coin"; + }; + led@1 { + reg = <1>; + label = "green:coin"; + }; + led@2 { + reg = <2>; + label = "blue:coin"; + }; + led@3 { + reg = <3>; + label = "red:bill"; + }; + led@4 { + reg = <4>; + label = "green:bill"; + }; + led@5 { + reg = <5>; + label = "blue:bill"; + }; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..a48dda268f81b4f3fcb3cceeb8dea6ff536bceb9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-gpio.txt @@ -0,0 +1,66 @@ +LEDs connected to GPIO lines + +Required properties: +- compatible : should be "gpio-leds". + +Each LED is represented as a sub-node of the gpio-leds device. Each +node's name represents the name of the corresponding LED. + +LED sub-node properties: +- gpios : Should specify the LED's GPIO, see "gpios property" in + Documentation/devicetree/bindings/gpio/gpio.txt. Active low LEDs should be + indicated using flags in the GPIO specifier. +- label : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- default-state: (optional) The initial state of the LED. + see Documentation/devicetree/bindings/leds/common.txt +- retain-state-suspended: (optional) The suspend state can be retained.Such + as charge-led gpio. +- retain-state-shutdown: (optional) Retain the state of the LED on shutdown. + Useful in BMC systems, for example when the BMC is rebooted while the host + remains up. +- panic-indicator : (optional) + see Documentation/devicetree/bindings/leds/common.txt + +Examples: + +#include + +leds { + compatible = "gpio-leds"; + hdd { + label = "Disk Activity"; + gpios = <&mcu_pio 0 GPIO_ACTIVE_LOW>; + linux,default-trigger = "disk-activity"; + }; + + fault { + gpios = <&mcu_pio 1 GPIO_ACTIVE_HIGH>; + /* Keep LED on if BIOS detected hardware fault */ + default-state = "keep"; + }; +}; + +run-control { + compatible = "gpio-leds"; + red { + gpios = <&mpc8572 6 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + green { + gpios = <&mpc8572 7 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; +}; + +leds { + compatible = "gpio-leds"; + + charger-led { + gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "max8903-charger-charging"; + retain-state-suspended; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-is31fl319x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-is31fl319x.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc2603484544d41178fcf89dd967ed75f4621740 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-is31fl319x.txt @@ -0,0 +1,59 @@ +LEDs connected to is31fl319x LED controller chip + +Required properties: +- compatible : Should be any of + "issi,is31fl3190" + "issi,is31fl3191" + "issi,is31fl3193" + "issi,is31fl3196" + "issi,is31fl3199" + "si-en,sn3199". +- #address-cells: Must be 1. +- #size-cells: Must be 0. +- reg: 0x64, 0x65, 0x66, or 0x67. + +Optional properties: +- audio-gain-db : audio gain selection for external analog modulation input. + Valid values: 0 - 21, step by 3 (rounded down) + Default: 0 + +Each led is represented as a sub-node of the issi,is31fl319x device. +There can be less leds subnodes than the chip can support but not more. + +Required led sub-node properties: +- reg : number of LED line + Valid values: 1 - number of leds supported by the chip variant. + +Optional led sub-node properties: +- label : see Documentation/devicetree/bindings/leds/common.txt. +- linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt. +- led-max-microamp : (optional) + Valid values: 5000 - 40000, step by 5000 (rounded down) + Default: 20000 (20 mA) + Note: a driver will take the lowest of all led limits since the + chip has a single global setting. The lowest value will be chosen + due to the PWM specificity, where lower brightness is achieved + by reducing the dury-cycle of pulses and not the current, which + will always have its peak value equal to led-max-microamp. + +Examples: + +fancy_leds: leds@65 { + compatible = "issi,is31fl3196"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x65>; + + red_aux: led@1 { + label = "red:aux"; + reg = <1>; + led-max-microamp = <10000>; + }; + + green_power: led@5 { + label = "green:power"; + reg = <5>; + linux,default-trigger = "default-on"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-is31fl32xx.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-is31fl32xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..926c2117942c4dc200fcd68156864f544b11a326 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-is31fl32xx.txt @@ -0,0 +1,52 @@ +Binding for ISSI IS31FL32xx and Si-En SN32xx LED Drivers + +The IS31FL32xx/SN32xx family of LED drivers are I2C devices with multiple +constant-current channels, each with independent 256-level PWM control. +Each LED is represented as a sub-node of the device. + +Required properties: +- compatible: one of + issi,is31fl3236 + issi,is31fl3235 + issi,is31fl3218 + issi,is31fl3216 + si-en,sn3218 + si-en,sn3216 +- reg: I2C slave address +- address-cells : must be 1 +- size-cells : must be 0 + +LED sub-node properties: +- reg : LED channel number (1..N) +- label : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt + + +Example: + +is31fl3236: led-controller@3c { + compatible = "issi,is31fl3236"; + reg = <0x3c>; + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + label = "EB:blue:usr0"; + }; + led@2 { + reg = <2>; + label = "EB:blue:usr1"; + }; + ... + led@36 { + reg = <36>; + label = "EB:blue:usr35"; + }; +}; + +For more product information please see the links below: +http://www.issi.com/US/product-analog-fxled-driver.shtml +http://www.si-en.com/product.asp?parentid=890 diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-ktd2692.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-ktd2692.txt new file mode 100644 index 0000000000000000000000000000000000000000..85373745258036d8b9340654f0eaff0d638084ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-ktd2692.txt @@ -0,0 +1,50 @@ +* Kinetic Technologies - KTD2692 Flash LED Driver + +KTD2692 is the ideal power solution for high-power flash LEDs. +It uses ExpressWire single-wire programming for maximum flexibility. + +The ExpressWire interface through CTRL pin can control LED on/off and +enable/disable the IC, Movie(max 1/3 of Flash current) / Flash mode current, +Flash timeout, LVP(low voltage protection). + +Also, When the AUX pin is pulled high while CTRL pin is high, +LED current will be ramped up to the flash-mode current level. + +Required properties: +- compatible : Should be "kinetic,ktd2692". +- ctrl-gpios : Specifier of the GPIO connected to CTRL pin. +- aux-gpios : Specifier of the GPIO connected to AUX pin. + +Optional properties: +- vin-supply : "vin" LED supply (2.7V to 5.5V). + See Documentation/devicetree/bindings/regulator/regulator.txt + +A discrete LED element connected to the device must be represented by a child +node - See Documentation/devicetree/bindings/leds/common.txt + +Required properties for flash LED child nodes: + See Documentation/devicetree/bindings/leds/common.txt +- led-max-microamp : Minimum Threshold for Timer protection + is defined internally (Maximum 300mA). +- flash-max-microamp : Flash LED maximum current + Formula : I(mA) = 15000 / Rset. +- flash-max-timeout-us : Flash LED maximum timeout. + +Optional properties for flash LED child nodes: +- label : See Documentation/devicetree/bindings/leds/common.txt + +Example: + +ktd2692 { + compatible = "kinetic,ktd2692"; + ctrl-gpios = <&gpc0 1 0>; + aux-gpios = <&gpc0 2 0>; + vin-supply = <&vbat>; + + flash-led { + label = "ktd2692-flash"; + led-max-microamp = <300000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1835000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-lm3601x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lm3601x.txt new file mode 100644 index 0000000000000000000000000000000000000000..a88b2c41e75b7f81d5a7a8e95261d0a5f907b03b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lm3601x.txt @@ -0,0 +1,45 @@ +* Texas Instruments - lm3601x Single-LED Flash Driver + +The LM3601X are ultra-small LED flash drivers that +provide a high level of adjustability. + +Required properties: + - compatible : Can be one of the following + "ti,lm36010" + "ti,lm36011" + - reg : I2C slave address + - #address-cells : 1 + - #size-cells : 0 + +Required child properties: + - reg : 0 - Indicates a IR mode + 1 - Indicates a Torch (white LED) mode + +Required properties for flash LED child nodes: + See Documentation/devicetree/bindings/leds/common.txt + - flash-max-microamp : Range from 11mA - 1.5A + - flash-max-timeout-us : Range from 40ms - 1600ms + - led-max-microamp : Range from 2.4mA - 376mA + +Optional child properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + +Example: +led-controller@64 { + compatible = "ti,lm36010"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x64>; + + led@0 { + reg = <1>; + label = "white:torch"; + led-max-microamp = <376000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1600000>; + }; +} + +For more product information please see the links below: +http://www.ti.com/product/LM36010 +http://www.ti.com/product/LM36011 diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-lm3692x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lm3692x.txt new file mode 100644 index 0000000000000000000000000000000000000000..08b352840bd7f8f05099015dc3637b85b64bbb5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lm3692x.txt @@ -0,0 +1,52 @@ +* Texas Instruments - LM3692x Highly Efficient White LED Driver + +The LM3692x is an ultra-compact, highly efficient, +white-LED driver designed for LCD display backlighting. + +The main difference between the LM36922 and LM36923 is the number of +LED strings it supports. The LM36922 supports two strings while the LM36923 +supports three strings. + +Required properties: + - compatible: + "ti,lm36922" + "ti,lm36923" + - reg : I2C slave address + - #address-cells : 1 + - #size-cells : 0 + +Optional properties: + - enable-gpios : gpio pin to enable/disable the device. + - vled-supply : LED supply + +Required child properties: + - reg : 0 - Will enable all LED sync paths + 1 - Will enable the LED1 sync + 2 - Will enable the LED2 sync + 3 - Will enable the LED3 sync (LM36923 only) + +Optional child properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +led-controller@36 { + compatible = "ti,lm3692x"; + reg = <0x36>; + #address-cells = <1>; + #size-cells = <0>; + + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + vled-supply = <&vbatt>; + + led@0 { + reg = <0>; + label = "white:backlight_cluster"; + linux,default-trigger = "backlight"; + }; +} + +For more product information please see the link below: +http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-lp55xx.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lp55xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b66a413fb9dfed9c6bb2c94d5cc02b1e7e26532 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lp55xx.txt @@ -0,0 +1,228 @@ +Binding for TI/National Semiconductor LP55xx Led Drivers + +Required properties: +- compatible: one of + national,lp5521 + national,lp5523 + ti,lp55231 + ti,lp5562 + ti,lp8501 + +- reg: I2C slave address +- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external) + +Each child has own specific current settings +- led-cur: Current setting at each led channel (mA x10, 0 if led is not connected) +- max-cur: Maximun current at each led channel. + +Optional properties: +- enable-gpio: GPIO attached to the chip's enable pin +- label: Used for naming LEDs +- pwr-sel: LP8501 specific property. Power selection for output channels. + 0: D1~9 are connected to VDD + 1: D1~6 with VDD, D7~9 with VOUT + 2: D1~6 with VOUT, D7~9 with VDD + 3: D1~9 are connected to VOUT + +Alternatively, each child can have a specific channel name and trigger: +- chan-name (optional): name of channel +- linux,default-trigger (optional): see + Documentation/devicetree/bindings/leds/common.txt + +example 1) LP5521 +3 LED channels, external clock used. Channel names are 'lp5521_pri:channel0', +'lp5521_pri:channel1' and 'lp5521_pri:channel2', with a heartbeat trigger +on channel 0. + +lp5521@32 { + compatible = "national,lp5521"; + reg = <0x32>; + label = "lp5521_pri"; + clock-mode = /bits/ 8 <2>; + + chan0 { + led-cur = /bits/ 8 <0x2f>; + max-cur = /bits/ 8 <0x5f>; + linux,default-trigger = "heartbeat"; + }; + + chan1 { + led-cur = /bits/ 8 <0x2f>; + max-cur = /bits/ 8 <0x5f>; + }; + + chan2 { + led-cur = /bits/ 8 <0x2f>; + max-cur = /bits/ 8 <0x5f>; + }; +}; + +example 2) LP5523 +9 LED channels with specific name. Internal clock used. +The I2C slave address is configurable with ASEL1 and ASEL0 pins. +Available addresses are 32/33/34/35h. + +ASEL1 ASEL0 Address +------------------------- + GND GND 32h + GND VEN 33h + VEN GND 34h + VEN VEN 35h + +lp5523@32 { + compatible = "national,lp5523"; + reg = <0x32>; + clock-mode = /bits/ 8 <1>; + + chan0 { + chan-name = "d1"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan1 { + chan-name = "d2"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan2 { + chan-name = "d3"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan3 { + chan-name = "d4"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan4 { + chan-name = "d5"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan5 { + chan-name = "d6"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan6 { + chan-name = "d7"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan7 { + chan-name = "d8"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan8 { + chan-name = "d9"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; +}; + +example 3) LP5562 +4 channels are defined. + +lp5562@30 { + compatible = "ti,lp5562"; + reg = <0x30>; + clock-mode = /bits/8 <2>; + + chan0 { + chan-name = "R"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan1 { + chan-name = "G"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan2 { + chan-name = "B"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; + + chan3 { + chan-name = "W"; + led-cur = /bits/ 8 <0x20>; + max-cur = /bits/ 8 <0x60>; + }; +}; + +example 4) LP8501 +9 channels are defined. The 'pwr-sel' is LP8501 specific property. +Others are same as LP5523. + +lp8501@32 { + compatible = "ti,lp8501"; + reg = <0x32>; + clock-mode = /bits/ 8 <2>; + pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */ + + chan0 { + chan-name = "d1"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan1 { + chan-name = "d2"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan2 { + chan-name = "d3"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan3 { + chan-name = "d4"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan4 { + chan-name = "d5"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan5 { + chan-name = "d6"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan6 { + chan-name = "d7"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan7 { + chan-name = "d8"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; + + chan8 { + chan-name = "d9"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-lp8860.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lp8860.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f0e892ad7592480ef220c26fb31fe7b88b01f77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lp8860.txt @@ -0,0 +1,45 @@ +* Texas Instruments - lp8860 4-Channel LED Driver + +The LP8860-Q1 is an high-efficiency LED +driver with boost controller. It has 4 high-precision +current sinks that can be controlled by a PWM input +signal, a SPI/I2C master, or both. + +Required properties: + - compatible : + "ti,lp8860" + - reg : I2C slave address + - #address-cells : 1 + - #size-cells : 0 + +Optional properties: + - enable-gpios : gpio pin to enable (active high)/disable the device. + - vled-supply : LED supply + +Required child properties: + - reg : 0 + +Optional child properties: + - label : see Documentation/devicetree/bindings/leds/common.txt + - linux,default-trigger : + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +led-controller@2d { + compatible = "ti,lp8860"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2d>; + enable-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + vled-supply = <&vbatt>; + + led@0 { + reg = <0>; + label = "white:backlight"; + linux,default-trigger = "backlight"; + }; +} + +For more product information please see the link below: +http://www.ti.com/product/lp8860-q1 diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-lt3593.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lt3593.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b2cabc36c0cd6ed2956e223dd903d3fad4a7535 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-lt3593.txt @@ -0,0 +1,32 @@ +Bindings for Linear Technologies LT3593 LED controller + +Required properties: +- compatible: Should be "lltc,lt3593". +- lltc,ctrl-gpios: A handle to the GPIO that is connected to the 'CTRL' + pin of the chip. + +The hardware supports only one LED. The properties of this LED are +configured in a sub-node in the device node. + +Optional sub-node properties: +- label: A label for the LED. If none is given, the LED will be + named "lt3595::". +- linux,default-trigger: The default trigger for the LED. + See Documentation/devicetree/bindings/leds/common.txt +- default-state: The initial state of the LED. + See Documentation/devicetree/bindings/leds/common.txt + +If multiple chips of this type are found in a design, each one needs to +be handled by its own device node. + +Example: + +led-controller { + compatible = "lltc,lt3593"; + lltc,ctrl-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + + led { + label = "white:backlight"; + default-state = "on"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-mt6323.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-mt6323.txt new file mode 100644 index 0000000000000000000000000000000000000000..45bf9f7d85f37685932f558aa9807bf5cf7ac8c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-mt6323.txt @@ -0,0 +1,60 @@ +Device Tree Bindings for LED support on MT6323 PMIC + +MT6323 LED controller is subfunction provided by MT6323 PMIC, so the LED +controllers are defined as the subnode of the function node provided by MT6323 +PMIC controller that is being defined as one kind of Muti-Function Device (MFD) +using shared bus called PMIC wrapper for each subfunction to access remote +MT6323 PMIC hardware. + +For MT6323 MFD bindings see: +Documentation/devicetree/bindings/mfd/mt6397.txt +For MediaTek PMIC wrapper bindings see: +Documentation/devicetree/bindings/soc/mediatek/pwrap.txt + +Required properties: +- compatible : Must be "mediatek,mt6323-led" +- address-cells : Must be 1 +- size-cells : Must be 0 + +Each led is represented as a child node of the mediatek,mt6323-led that +describes the initial behavior for each LED physically and currently only four +LED child nodes can be supported. + +Required properties for the LED child node: +- reg : LED channel number (0..3) + +Optional properties for the LED child node: +- label : See Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : See Documentation/devicetree/bindings/leds/common.txt +- default-state: See Documentation/devicetree/bindings/leds/common.txt + +Example: + + mt6323: pmic { + compatible = "mediatek,mt6323"; + + ... + + mt6323led: leds { + compatible = "mediatek,mt6323-led"; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + label = "LED0"; + linux,default-trigger = "timer"; + default-state = "on"; + }; + led@1 { + reg = <1>; + label = "LED1"; + default-state = "off"; + }; + led@2 { + reg = <2>; + label = "LED2"; + default-state = "on"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-netxbig.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-netxbig.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ef92a26d7685511fc406074ddc38a468c448c3a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-netxbig.txt @@ -0,0 +1,92 @@ +Binding for the CPLD LEDs (GPIO extension bus) found on some LaCie/Seagate +boards (Example: 2Big/5Big Network v2, 2Big NAS). + +Required properties: +- compatible: "lacie,netxbig-leds". +- gpio-ext: Phandle for the gpio-ext bus. + +Optional properties: +- timers: Timer array. Each timer entry is represented by three integers: + Mode (gpio-ext bus), delay_on and delay_off. + +Each LED is represented as a sub-node of the netxbig-leds device. + +Required sub-node properties: +- mode-addr: Mode register address on gpio-ext bus. +- mode-val: Mode to value mapping. Each entry is represented by two integers: + A mode and the corresponding value on the gpio-ext bus. +- bright-addr: Brightness register address on gpio-ext bus. +- max-brightness: Maximum brightness value. + +Optional sub-node properties: +- label: Name for this LED. If omitted, the label is taken from the node name. +- linux,default-trigger: Trigger assigned to the LED. + +Example: + +netxbig-leds { + compatible = "lacie,netxbig-leds"; + + gpio-ext = &gpio_ext; + + timers = ; + + blue-power { + label = "netxbig:blue:power"; + mode-addr = <0>; + mode-val = ; + bright-addr = <1>; + max-brightness = <7>; + }; + red-power { + label = "netxbig:red:power"; + mode-addr = <0>; + mode-val = ; + bright-addr = <1>; + max-brightness = <7>; + }; + blue-sata0 { + label = "netxbig:blue:sata0"; + mode-addr = <3>; + mode-val = ; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata0 { + label = "netxbig:red:sata0"; + mode-addr = <3>; + mode-val = ; + bright-addr = <2>; + max-brightness = <7>; + }; + blue-sata1 { + label = "netxbig:blue:sata1"; + mode-addr = <4>; + mode-val = ; + bright-addr = <2>; + max-brightness = <7>; + }; + red-sata1 { + label = "netxbig:red:sata1"; + mode-addr = <4>; + mode-val = ; + bright-addr = <2>; + max-brightness = <7>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-ns2.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-ns2.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f81258a5b6e9035835c0cb230559a5a6e7a68f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-ns2.txt @@ -0,0 +1,35 @@ +Binding for dual-GPIO LED found on Network Space v2 (and parents). + +Required properties: +- compatible: "lacie,ns2-leds". + +Each LED is represented as a sub-node of the ns2-leds device. + +Required sub-node properties: +- cmd-gpio: Command LED GPIO. See OF device-tree GPIO specification. +- slow-gpio: Slow LED GPIO. See OF device-tree GPIO specification. +- modes-map: A mapping between LED modes (off, on or SATA activity blinking) and + the corresponding cmd-gpio/slow-gpio values. All the GPIO values combinations + should be given in order to avoid having an unknown mode at driver probe time. + +Optional sub-node properties: +- label: Name for this LED. If omitted, the label is taken from the node name. +- linux,default-trigger: Trigger assigned to the LED. + +Example: + +#include + +ns2-leds { + compatible = "lacie,ns2-leds"; + + blue-sata { + label = "ns2:blue:sata"; + slow-gpio = <&gpio0 29 0>; + cmd-gpio = <&gpio0 30 0>; + modes-map = ; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-pca9532.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pca9532.txt new file mode 100644 index 0000000000000000000000000000000000000000..f769c52e36439205572e33d74c4c9e0f9a09b808 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pca9532.txt @@ -0,0 +1,49 @@ +*NXP - pca9532 PWM LED Driver + +The PCA9532 family is SMBus I/O expander optimized for dimming LEDs. +The PWM support 256 steps. + +Required properties: + - compatible: + "nxp,pca9530" + "nxp,pca9531" + "nxp,pca9532" + "nxp,pca9533" + - reg - I2C slave address + +Each led is represented as a sub-node of the nxp,pca9530. + +Optional sub-node properties: + - label: see Documentation/devicetree/bindings/leds/common.txt + - type: Output configuration, see dt-bindings/leds/leds-pca9532.h (default NONE) + - linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt + - default-state: see Documentation/devicetree/bindings/leds/common.txt + This property is only valid for sub-nodes of type . + +Example: + #include + + leds: pca9530@60 { + compatible = "nxp,pca9530"; + reg = <0x60>; + + red-power { + label = "pca:red:power"; + type = ; + }; + green-power { + label = "pca:green:power"; + type = ; + }; + kernel-booting { + type = ; + default-state = "on"; + }; + sys-stat { + type = ; + default-state = "keep"; // don't touch, was set by U-Boot + }; + }; + +For more product information please see the link below: +http://nxp.com/documents/data_sheet/PCA9532.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-pca955x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pca955x.txt new file mode 100644 index 0000000000000000000000000000000000000000..7984efb767b411ac6814bd139513e53d48fa7ff3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pca955x.txt @@ -0,0 +1,88 @@ +* NXP - pca955x LED driver + +The PCA955x family of chips are I2C LED blinkers whose pins not used +to control LEDs can be used as general purpose I/Os. The GPIO pins can +be input or output, and output pins can also be pulse-width controlled. + +Required properties: +- compatible : should be one of : + "nxp,pca9550" + "nxp,pca9551" + "nxp,pca9552" + "nxp,pca9553" +- #address-cells: must be 1 +- #size-cells: must be 0 +- reg: I2C slave address. depends on the model. + +Optional properties: +- gpio-controller: allows pins to be used as GPIOs. +- #gpio-cells: must be 2. +- gpio-line-names: define the names of the GPIO lines + +LED sub-node properties: +- reg : number of LED line. + from 0 to 1 for the pca9550 + from 0 to 7 for the pca9551 + from 0 to 15 for the pca9552 + from 0 to 3 for the pca9553 +- type: (optional) either + PCA9532_TYPE_NONE + PCA9532_TYPE_LED + PCA9532_TYPE_GPIO + see dt-bindings/leds/leds-pca955x.h (default to LED) +- label : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt + +Examples: + +pca9552: pca9552@60 { + compatible = "nxp,pca9552"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x60>; + + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "GPIO12", "GPIO13", "GPIO14", "GPIO15"; + + gpio@12 { + reg = <12>; + type = ; + }; + gpio@13 { + reg = <13>; + type = ; + }; + gpio@14 { + reg = <14>; + type = ; + }; + gpio@15 { + reg = <15>; + type = ; + }; + + led@0 { + label = "red:power"; + linux,default-trigger = "default-on"; + reg = <0>; + type = ; + }; + led@1 { + label = "green:power"; + reg = <1>; + type = ; + }; + led@2 { + label = "pca9552:yellow"; + reg = <2>; + type = ; + }; + led@3 { + label = "pca9552:white"; + reg = <3>; + type = ; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-pm8058.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pm8058.txt new file mode 100644 index 0000000000000000000000000000000000000000..89584c49aab2b37227bca98c8765d77c247d0630 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pm8058.txt @@ -0,0 +1,67 @@ +Qualcomm PM8058 LED driver + +The Qualcomm PM8058 is a multi-functional device which contains +an LED driver block for up to six LEDs: three normal LEDs, two +"flash" LEDs and one "keypad backlight" LED. The names are +quoted because sometimes these LED drivers are used for wildly +different things than flash or keypad backlight: their names +are more of a suggestion than a hard-wired usecase. + +Hardware-wise the different LEDs support slightly different +output currents. The "flash" LEDs do not need to charge nor +do they support external triggers. They are just powerful LED +drivers. + +The LEDs appear as children to the PM8058 device, with the +proper compatible string. For the PM8058 bindings see: +mfd/qcom-pm8xxx.txt. + +Each LED is represented as a sub-node of the syscon device. Each +node's name represents the name of the corresponding LED. + +LED sub-node properties: + +Required properties: +- compatible: one of + "qcom,pm8058-led" (for the normal LEDs at 0x131, 0x132 and 0x133) + "qcom,pm8058-keypad-led" (for the "keypad" LED at 0x48) + "qcom,pm8058-flash-led" (for the "flash" LEDs at 0x49 and 0xFB) + +Optional properties: +- label: see Documentation/devicetree/bindings/leds/common.txt +- default-state: see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger: see Documentation/devicetree/bindings/leds/common.txt + +Example: + +qcom,ssbi@500000 { + pmicintc: pmic@0 { + compatible = "qcom,pm8058"; + led@48 { + compatible = "qcom,pm8058-keypad-led"; + reg = <0x48>; + label = "pm8050:white:keypad"; + default-state = "off"; + }; + led@131 { + compatible = "qcom,pm8058-led"; + reg = <0x131>; + label = "pm8058:red"; + default-state = "off"; + }; + led@132 { + compatible = "qcom,pm8058-led"; + reg = <0x132>; + label = "pm8058:yellow"; + default-state = "off"; + linux,default-trigger = "mmc0"; + }; + led@133 { + compatible = "qcom,pm8058-led"; + reg = <0x133>; + label = "pm8058:green"; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-powernv.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-powernv.txt new file mode 100644 index 0000000000000000000000000000000000000000..66655690f749ace1fd67b3bfd3c83b76330be4e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-powernv.txt @@ -0,0 +1,26 @@ +Device Tree binding for LEDs on IBM Power Systems +------------------------------------------------- + +Required properties: +- compatible : Should be "ibm,opal-v3-led". +- led-mode : Should be "lightpath" or "guidinglight". + +Each location code of FRU/Enclosure must be expressed in the +form of a sub-node. + +Required properties for the sub nodes: +- led-types : Supported LED types (attention/identify/fault) provided + in the form of string array. + +Example: + +leds { + compatible = "ibm,opal-v3-led"; + led-mode = "lightpath"; + + U78C9.001.RST0027-P1-C1 { + led-types = "identify", "fault"; + }; + ... + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c6583c35f2ff6bfe41ca3e9747dc720d6d72d84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-pwm.txt @@ -0,0 +1,50 @@ +LED connected to PWM + +Required properties: +- compatible : should be "pwm-leds". + +Each LED is represented as a sub-node of the pwm-leds device. Each +node's name represents the name of the corresponding LED. + +LED sub-node properties: +- pwms : PWM property to point to the PWM device (phandle)/port (id) and to + specify the period time to be used: <&phandle id period_ns>; +- pwm-names : (optional) Name to be used by the PWM subsystem for the PWM device + For the pwms and pwm-names property please refer to: + Documentation/devicetree/bindings/pwm/pwm.txt +- max-brightness : Maximum brightness possible for the LED +- active-low : (optional) For PWMs where the LED is wired to supply + rather than ground. +- label : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +twl_pwm: pwm { + /* provides two PWMs (id 0, 1 for PWM1 and PWM2) */ + compatible = "ti,twl6030-pwm"; + #pwm-cells = <2>; +}; + +twl_pwmled: pwmled { + /* provides one PWM (id 0 for Charing indicator LED) */ + compatible = "ti,twl6030-pwmled"; + #pwm-cells = <2>; +}; + +pwmleds { + compatible = "pwm-leds"; + kpad { + label = "omap4::keypad"; + pwms = <&twl_pwm 0 7812500>; + max-brightness = <127>; + }; + + charging { + label = "omap4:green:chrg"; + pwms = <&twl_pwmled 0 7812500>; + max-brightness = <255>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-qpnp-flash-v2.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qpnp-flash-v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..a282b4c8d9a40d7442e2e0b583f72a1f137a4361 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qpnp-flash-v2.txt @@ -0,0 +1,325 @@ +Qualcomm Technologies Inc. PNP v2 Flash LED + +QPNP (Qualcomm Technologies Inc. Plug N Play) Flash LED (Light +Emitting Diode) driver v2 is used to provide illumination to +camera sensor when background light is dim to capture good +picture. It can also be used for flashlight/torch application. +It is part of PMIC on Qualcomm Technologies Inc. reference platforms. + +Main node: + +Required properties: +- compatible : Should be "qcom,qpnp-flash-led-v2" +- reg : Base address and size for flash LED modules +- qcom,pmic-revid : phandle of PMIC revid module. This is used to + identify the PMIC subtype. + +Optional properties: +- interrupts : Specifies the interrupts associated with flash-led. +- interrupt-names : Specify the interrupt names associated with interrupts. +- qcom,hdrm-auto-mode : Boolean type to select headroom auto mode enabled or not +- qcom,isc-delay-us : Integer type to specify short circuit delay. Valid values are 32, 64, + 128, 192. Unit is uS. +- qcom,warmup-delay-us : Integer type to specify warm up delay. Valid values are 32, 64, + 128, 192. Unit is uS. +- qcom,short-circuit-det : Boolean property which enables short circuit fault detection. +- qcom,open-circuit-det : Boolean property which enables open circuit fault detection. +- qcom,vph-droop-det : Boolean property which enables VPH droop detection. +- qcom,vph-droop-hysteresis-mv : Integer property to specify VPH droop hysteresis. It is only used if + qcom,vph-droop-det is specified. Valid values are 0, 25, 50 and 75. + Unit is mV. +- qcom,vph-droop-threshold-mv : Integer property to specify VPH droop threshold. It is only used if + qcom,vph-droop-det is specified. Valid values are + 2500 to 3200 with step size of 100. Unit is mV. +- qcom,vph-droop-debounce-us : Integer property to specify VPH droop debounce time. It is only used + if qcom,vph-droop-det is specified. Valid values are 0, 8, 16 and 26. + Unit is uS. +- qcom,led1n2-iclamp-low-ma : Integer property to specify current clamp low + level for mitigation. Unit is mA. Allowed + values are same as under qcom,max-current. +- qcom,led1n2-iclamp-mid-ma : Integer property to specify current clamp mid + level for mitigation. Unit is mA. Allowed + values are same as under qcom,max-current. +- qcom,led3-iclamp-low-ma : Integer property to specify current clamp low + level for mitigation. Unit is mA. Allowed + values are same as under qcom,max-current. +- qcom,led3-iclamp-mid-ma : Integer property to specify current clamp mid + level for mitigation. Unit is mA. Allowed + values are same as under qcom,max-current. +- qcom,vled-max-uv : Integer property for flash current predictive mitigation. + Default value is 3500000 uV. +- qcom,ibatt-ocp-threshold-ua : Integer property for flash current predictive mitigation. + Default value is 4500000 uA. +- qcom,rparasitic-uohm : Integer property for flash current predictive mitigation indicating + parasitic component of battery resistance. Default value is 0 uOhm. +- qcom,lmh-ocv-threshold-uv : Required property for flash current preemptive LMH mitigation. + Default value is 3700000 uV. +- qcom,lmh-rbatt-threshold-uohm : Required property for flash current preemptive LMH mitigation. + Default value is 400000 uOhm. +- qcom,lmh-mitigation-sel : Optional property to configure flash current preemptive LMH mitigation. + Accepted values are: + 0: MITIGATION_DISABLED + 1: MITIGATION_BY_ILED_THRESHOLD + 2: MITIGATION_BY_SW + Default value is 2. +- qcom,chgr-mitigation-sel : Optional property to configure flash current preemptive charger mitigation. + Accepted values are: + 0: MITIGATION_DISABLED + 1: MITIGATION_BY_ILED_THRESHOLD + 2: MITIGATION_BY_SW + Default value is 2. +- qcom,lmh-level : Optional property to configure flash current preemptive LMH mitigation. + Accepted values are 0, 1, and 3. Default value is 0. +- qcom,iled-thrsh-ma : Optional property to configure the led current threshold at which HW + preemptive mitigation is triggered. Unit is mA. Default value is 1000. + Accepted values are in the range 0 - 3100, with steps of 100. + 0 disables autonomous HW mitigation. +- qcom,thermal-derate-en : Boolean property to enable flash current thermal mitigation. +- qcom,thermal-derate-current : Array of currrent limits for thermal mitigation. Required if + qcom,thermal-derate-en is specified. Unit is mA. Format is + qcom,thermal-derate-current = . +- qcom,otst-ramp-back-up-dis : Boolean property to disable current ramp + backup after thermal derate trigger is + deasserted. +- qcom,thermal-derate-slow : Integer property to specify slow ramping + down thermal rate. Unit is in uS. Allowed + values are: 128, 256, 512, 1024, 2048, 4096, + 8192 and 314592. +- qcom,thermal-derate-fast : Integer property to specify fast ramping + down thermal rate. Unit is in uS. Allowed + values are: 32, 64, 96, 128, 256, 384 and + 512. +- qcom,thermal-debounce : Integer property to specify thermal debounce + time. It is only used if qcom,thermal-derate-en + is specified. Unit is in uS. Allowed values + are: 0, 16, 32, 64. +- qcom,thermal-hysteresis : Integer property to specify thermal derating + hysteresis. Unit is in deciDegC. It is only + used if qcom,thermal-derate-en is specified. + Allowed values are: + 0, 15, 30, 45 for pmi8998. + 0, 20, 40, 60 for pm660l. +- qcom,thermal-thrsh1 : Integer property to specify OTST1 threshold + for thermal mitigation. Unit is in Celsius. + Accepted values are: + 85, 79, 73, 67, 109, 103, 97, 91. +- qcom,thermal-thrsh2 : Integer property to specify OTST2 threshold + for thermal mitigation. Unit is in Celsius. + Accepted values are: + 110, 104, 98, 92, 134, 128, 122, 116. +- qcom,thermal-thrsh3 : Integer property to specify OTST3 threshold + for thermal mitigation. Unit is in Celsius. + Accepted values are: + 125, 119, 113, 107, 149, 143, 137, 131. +- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified + value, additional GPIO configuration may be required to provide strobing + support. Supported values are: + 0: Flash strobe is used for LED1, LED2, LED3 + 1: Flash strobe is used for LED1, LED2 and GPIO10 is used for LED3 + 2: Flash strobe is used for LED1; GPIO9 is used for LED2; GPIO10 is used for LED3 + For PM8150L/A and its derivatives, supported values are: + 0: Flash strobe is used for LED1, LED2, LED3 + 1: Flash strobe is used for LED1, LED2 and GPIO12 is used for LED3 +- switchX-supply : phandle of the regulator that needs to be used + as a supply for flash switch_X device. +- qcom,bst-pwm-ovrhd-uv : Charger flash VPH overhead. Applicable for PMI632 only. + Supported values (in mV) are: 300, 400, 500, 600. Default is 300. + +Child node: Contains settings for each individual LED. Each LED channel needs a flash node and +torch node for itself, and an individual switch node to serve as an overall switch. + +Required Properties: +- label : Type of led that will be used, either "flash", "torch", or "switch. +- qcom,led-name : Name of the LED. +- qcom,default-led-trigger : Trigger for the camera flash and torch. Accepted values are + "flash0_trigger", "flash1_trigger", "flash2_trigger, "torch0_trigger", + "torch1_trigger", "torch2_trigger", and "switch_trigger". +- qcom,id : ID for each physical LED equipped. In order to handle situation when + only 1 or 2 LEDs are installed, flash and torch nodes on LED channel 0 + should be specified with ID 0; nodes on channel 1 be ID 1, etc. This is + not required for switch node. +- qcom,max-current : Maximum current allowed on this LED. Valid values should be + integer from 0 to 1500 inclusive. Flash 2 should have maximum current of + 750 per hardware requirement. Unit is mA. For torch, the maximum current + is clamped at 500 mA. This is not required for the switch node. +- qcom,duration-ms : Required property for flash nodes but not needed for torch. Integer + type specifying flash duration. Values are from 10ms to 1280ms with + 10ms resolution. This is not required for switch node. +- qcom,led-mask : Required property for switch nodes. Bitmask to indicate which leds are + controlled by this switch node. Accepted values are in the range 1 to 7, + inclusive. Example: + qcom,led-mask = <4>; /* This switch node controls the flash2/torch2 led. */ + +Optional properties: +- qcom,current-ma : operational current intensity for LED in mA. Accepted values are a + positive integer in the range of 0 to qcom,max-current inclusive. +- qcom,ires-ua : Integer type to specify current resolution. Accepted values should be + 12500, 10000, 7500, and 5000. Unit is uA. +- qcom,hdrm-voltage-mv : Integer type specifying headroom voltage. Values are from 125mV to 500mV + with 25mV resolution. Default setting is 325mV +- qcom,hdrm-vol-hi-lo-win-mv : Integer type to specify headroom voltage swing range. Values are + from 0mV to 375mV with 25mV resolution. Default setting is 100mV. +- pinctrl-names : Name of the pinctrl configuration that will be used when external GPIOs + are used for enabling/disabling, HW strobing of flash LEDs. For more + information on using pinctrl, please refer + Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt + Following are the pinctrl configs that can be specified: + "led_enable" : pinctrl config to enable led. This should specify the active + configuration defined for each pin or pin group. + "led_disable" : pinctrl config to disable led. This should specify the sleep + configuration defined for each pin or pin group. + "strobe_enable" : pinctrl config to enable hw-strobe. This should specify the + active configuration defined for each pin or pin group. + "strobe_disable" : pinctrl config to disable hw-strobe. This should specify the + sleep configuration defined for each pin or pin group. +- qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no + pinctrl support or PMIC GPIOs are used. +- qcom,strobe-sel : Property to select strobe type. If not defined, + software strobe will be used. Allowed options are: + 0 - SW strobe + 1 - HW strobe + 2 - LPG strobe + LPG strobe is supported only for LED3. + If LPG strobe is specified, then strobe control is + configured for active high and level triggered. Also + qcom,hw-strobe-option should be set to 1 or 2. +- qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to + be edge triggered. Otherwise, it is level triggered. +- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe + signal polarity is set to active-low, else it is active-high. +- qcom,symmetry-en : Boolean property to specify if the flash LEDs under a + switch node are controlled symmetrically. This needs + to be specified if a group of flash LED channels are + connected to a single LED. +Example: + qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xd3 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "led-fault-irq", + "mitigation-irq", + "flash-timer-exp-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq", + "led3-ramp-up-done-irq", + "led2-ramp-up-done-irq", + "led1-ramp-up-done-irq"; + + qcom,hdrm-auto-mode; + qcom,isc-delay = <192>; + switch0-supply = <&pmi8998_bob>; + + pmi8998_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = + "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = + "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = + "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; + }; + + pmi8998_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = + "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = + "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = + "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; + }; + + pmi8998_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = + "switch0_trigger"; + qcom,symmetry-en; + }; + + pmi8998_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <4>; + qcom,default-led-trigger = + "switch1_trigger"; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-qpnp-vibrator-ldo.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qpnp-vibrator-ldo.txt new file mode 100644 index 0000000000000000000000000000000000000000..2865019b3fccf2187f44b30174fdc1bd3086101d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qpnp-vibrator-ldo.txt @@ -0,0 +1,50 @@ +Qualcomm Technologies, Inc. Vibrator-LDO + +QPNP (Qualcomm Technologies, Inc. Plug N Play) Vibrator-LDO is a peripheral +on some QTI PMICs. It can be interfaced with the host processor via SPMI. + +Vibrator-LDO peripheral supports Eccentric Rotation Mass (ERM) vibrator. + +Properties: + +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-vibrator-ldo". + +- reg + Usage: required + Value type: + Definition: Base address of vibrator-ldo peripheral. + +- qcom,vib-ldo-volt-uv + Usage: required + Value type: + Definition: The optimal voltage requirement of the vibrator motor for + a normal vibration. Value is specified in microvolts. + +- qcom,disable-overdrive + Usage: optional + Value type: + Definition: Do not apply overdrive voltage. + +- qcom,vib-overdrive-volt-uv + Usage: optional and not required if qcom,disable-overdrive present + Value type: + Definition: The voltage in microvolts used as overdrive factor for + improving motor reactivity at the start of vibration. + If this property not specified, a default value of + 2 times the value specified in qcom,vib-ldo-volt-uv + property is used. + +======= +Example +======= + +pmi632_vib: qcom,vibrator@5700 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5700 0x100>; + qcom,vib-ldo-volt-uv = <1504000>; + qcom,disable-overdrive; + qcom,vib-overdrive-volt-uv = <3544000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-qti-flash.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qti-flash.txt new file mode 100644 index 0000000000000000000000000000000000000000..9cc002b57ee553b44882dc879d59c11849471811 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qti-flash.txt @@ -0,0 +1,247 @@ +Qualcomm Technologies Inc. Flash LED bindings. + +Qualcomm Technologies, Inc. Flash LED supports camera flash with +multiple LED channels (HW dependent) that can be used for multiplh +camera devices which can be configured for pre-flash(torch) and +flash modes. + +Flash LED device has two level of nodes. The main node represents +flash LED peripheral and sub node represents the type of device +that uses flash LED channel. It can be a torch, flash or switch. + +Main node: + +Required properties: +- compatible : Should be one of "qcom,pm8350c-flash-led" + "qcom,pm2250-flash-led" + +- reg : Base address of flash LED modules + +Optional properties: +- interrupts : Specifies the interrupts associated with flash-led. + +- interrupt-names : Specify the interrupt names associated with interrupts. + +- qcom,thermal-derate-current : Array of currrent limits for thermal mitigation. + Unit is mA. Format is + qcom,thermal-derate-current = + . + +- qcom,hw-strobe-gpios : Array of one or more phandles to specify GPIOs to use + for strobing flash/torch devices with HW strobe option. + qcom,strobe-sel for flash/torch should be 1 if phandle + is specified. + +Child node: Contains settings for each individual LED. Each LED channel needs a + flash node and torch node for itself, and an individual switch node + to serve as an overall switch. + +Required Properties: +- label : Type of led that will be used, either "flash", "torch", or "switch. + +- qcom,led-name : Name of the LED. + +- qcom,id : ID for each LED channel. In order to handle situation when only + 1 or 2 LEDs are installed, flash and torch nodes on LED channel + 0 should be specified with ID 0; nodes on channel 1 be ID 1, etc. + This is not required for switch node. + +- qcom,default-led-trigger : Trigger for the camera flash and torch. Accepted + values are "flash0_trigger", "flash1_trigger", + "flash2_trigger, "flash3_trigger, + "torch0_trigger", "torch1_trigger", + "torch2_trigger", "torch3_trigger", + and "switch_trigger". + +- qcom,led-mask : Required property for switch nodes. Bit mask to indicate which + leds are controlled by this switch node. Accepted values are in + the range 1 to 15, inclusive. + Example: qcom,led-mask = <9>; + /* This switch node controls the flash0/torch0 and + flash3/torch3 led. */ + +Optional properties: +- qcom,max-current-ma : Maximum current allowed on this LED. + Valid values are: + For PM8350C flash from 0 to 1500 inclusive. Unit is mA. + For PM8350C torch, the maximum current is clamped to + 500 mA. + For PM2250 flash from 0 to 1000 inclusive. Unit is mA. + For PM2250 torch, the maximum current is clamped to + 200 mA. + This is not required for the switch node. + +- qcom,duration-ms : Required property for flash nodes but not needed for torch + or switch node. Integer type specifying flash duration. + Values are from 10ms to 1280ms with 10ms resolution. + +- qcom,ires-ua : Integer type to specify current resolution. Accepted values + should be 12500 and 5000. Unit is uA. + +- qcom,strobe-sel : Property to select strobe type. If not defined software + strobe will be used. Allowed options are: + 0 - SW strobe + 1 - HW strobe + +- qcom,strobe-config: Strobe input selection for flash LED device. Each + flash LED device has independently connected HW strobe + inputs (GPIO1, GPIO2, GPIO3, GPIO4). + PM8350C has 4 LED channles and PM2250 has one LED channel. + This is applicable only when HW strobe is selected. + +- qcom,symmetry-en : Boolean property to specify if the flash LEDs under + a switch node are controlled symmetrically. This needs to + be specified if a group of flash LED channels are connected + to a single LED. + +- qcom,ibatt-ocp-threshold-ua : Integer property for flash current predictive mitigation. + Default value is 2500000 uA. + +Example: + +qcom,leds@ee00 { + compatible = "qcom,pm8350c-flash-led"; + reg = <0xee00>; + interrupts = <0x2 0xee 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0xee 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0xee 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,thermal-derate-current = <200 500>; + qcom,hw-strobe-gpios = <&pm8350c_gpios 1 0>; + + pm8350c_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current-ma = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,strobe-sel = <1>; + qcom,strobe-config = <0>; + }; + + pm8350c_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current-ma = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + }; + + pm8350c_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current-ma = <1500>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + }; + + pm8350c_flash3: qcom,flash_3 { + label = "flash"; + qcom,led-name = "led:flash_3"; + qcom,max-current-ma = <1500>; + qcom,default-led-trigger = "flash3_trigger"; + qcom,id = <3>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + }; + + pm8350_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current-ma = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,ires-ua = <12500>; + qcom,strobe-sel = <1>; + qcom,strobe-config = <0>; + }; + + pm8350_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current-ma = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,ires-ua = <12500>; + }; + + pm8350_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current-ma = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,ires-ua = <12500>; + }; + + pm8350_torch3: qcom,torch_3 { + label = "torch"; + qcom,led-name = "led:torch_3"; + qcom,max-current-ma = <500>; + qcom,default-led-trigger = "torch3_trigger"; + qcom,id = <3>; + qcom,ires-ua = <12500>; + }; + + pm8350_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <9>; /* Channels 1 & 4 */ + qcom,default-led-trigger = "switch0_trigger"; + qcom,symmetry-en; + }; + + pm8350_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <6>; /* Channels 2 & 3 */ + qcom,default-led-trigger = "switch1_trigger"; + qcom,symmetry-en; + }; +}; + + +qcom,flash_led@d300 { + compatible = "qcom,pm2250-flash-led"; + reg = <0xd300>; + interrupts = <0x2 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq" + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + + pm2250_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current-ma = <1000>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + }; + + pm2250_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current-ma = <200>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,ires-ua = <12500>; + }; + + pm2250_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <1>; /* Channel 0 */ + qcom,default-led-trigger = "switch0_trigger"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-qti-tri-led.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qti-tri-led.txt new file mode 100644 index 0000000000000000000000000000000000000000..e179f4222739aeea4b745ecc91bcf82839d224bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-qti-tri-led.txt @@ -0,0 +1,72 @@ +Qualcomm Technologies, Inc. TRI_LED driver specific bindings + +This binding document describes the properties of TRI_LED module in +Qualcomm Technologies, Inc. PMIC chips. + +- compatible: + Usage: required + Value type: + Definition: Must be "qcom,tri-led". + +- reg: + Usage: required + Value type: + Definition: Register base of the TRI_LED module and length. + +- nvmem-names: + Usage: optional + Value type: + Definition: Nvmem device name for SDAM to do PBS trigger. It must be + defined as "pbs_sdam". This is required only for HR_LEDs. + +- nvmem: + Usage: optional + Value type: + Definition: Phandle of the nvmem device name to access SDAM to do PBS + trigger. This is required only for HR_LEDs. + +Properties for child nodes: +- pwms: + Usage: required + Value type: + Definition: The PWM device (phandle) used for controlling LED. + +- led-sources: + Usage: required + Value type: + Definition: see Documentation/devicetree/bindings/leds/common.txt; + Device current output identifiers are: 0 - LED1_EN, + 1 - LED2_EN, 2 - LED3_EN. + +- label: + Usage: optional + Value type: + Definition: see Documentation/devicetree/bindings/leds/common.txt; + +- linux,default-trigger: + Usage: optional + Value_type: + Definition: see Documentation/devicetree/bindings/leds/common.txt; + +Example: + + pmi8998_rgb: tri-led@d000{ + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + + red { + label = "red"; + pwms = <&pmi8998_lpg 4 1000000>; + led-sources = <0>; + }; + green { + label = "green"; + pwms = <&pmi8998_lpg 3 1000000>; + led-sources = <1>; + }; + blue { + label = "blue"; + pwms = <&pmi8998_lpg 2 1000000>; + led-sources = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-sc27xx-bltc.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-sc27xx-bltc.txt new file mode 100644 index 0000000000000000000000000000000000000000..dddf84f9c7ea5d1cad32715731e5ddf5640b6ad0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-sc27xx-bltc.txt @@ -0,0 +1,41 @@ +LEDs connected to Spreadtrum SC27XX PMIC breathing light controller + +The SC27xx breathing light controller supports to 3 outputs: +red LED, green LED and blue LED. Each LED can work at normal +PWM mode or breath light mode. + +Required properties: +- compatible: Should be "sprd,sc2731-bltc". +- #address-cells: Must be 1. +- #size-cells: Must be 0. +- reg: Specify the controller address. + +Required child properties: +- reg: Port this LED is connected to. + +Optional child properties: +- label: See Documentation/devicetree/bindings/leds/common.txt. + +Examples: + +led-controller@200 { + compatible = "sprd,sc2731-bltc"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x200>; + + led@0 { + label = "red"; + reg = <0x0>; + }; + + led@1 { + label = "green"; + reg = <0x1>; + }; + + led@2 { + label = "blue"; + reg = <0x2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/leds-tlc591xx.txt b/arch/arm64/boot/dts/vendor/bindings/leds/leds-tlc591xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bbbf70244119e300b0662faf6791f91a1a4185e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/leds-tlc591xx.txt @@ -0,0 +1,40 @@ +LEDs connected to tlc59116 or tlc59108 + +Required properties +- compatible: should be "ti,tlc59116" or "ti,tlc59108" +- #address-cells: must be 1 +- #size-cells: must be 0 +- reg: typically 0x68 + +Each led is represented as a sub-node of the ti,tlc59116. +See Documentation/devicetree/bindings/leds/common.txt + +LED sub-node properties: +- reg: number of LED line, 0 to 15 or 0 to 7 +- label: (optional) name of LED +- linux,default-trigger : (optional) + +Examples: + +tlc59116@68 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tlc59116"; + reg = <0x68>; + + wan@0 { + label = "wrt1900ac:amber:wan"; + reg = <0x0>; + }; + + 2g@2 { + label = "wrt1900ac:white:2g"; + reg = <0x2>; + }; + + alive@9 { + label = "wrt1900ac:green:alive"; + reg = <0x9>; + linux,default_trigger = "heartbeat"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/pca963x.txt b/arch/arm64/boot/dts/vendor/bindings/leds/pca963x.txt new file mode 100644 index 0000000000000000000000000000000000000000..4eee41482041f50f6267a05e3c8090f645cf00c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/pca963x.txt @@ -0,0 +1,52 @@ +LEDs connected to pca9632, pca9633 or pca9634 + +Required properties: +- compatible : should be : "nxp,pca9632", "nxp,pca9633", "nxp,pca9634" or "nxp,pca9635" + +Optional properties: +- nxp,totem-pole : use totem pole (push-pull) instead of open-drain (pca9632 defaults + to open-drain, newer chips to totem pole) +- nxp,hw-blink : use hardware blinking instead of software blinking +- nxp,period-scale : In some configurations, the chip blinks faster than expected. + This parameter provides a scaling ratio (fixed point, decimal divided + by 1000) to compensate, e.g. 1300=1.3x and 750=0.75x. +- nxp,inverted-out: invert the polarity of the generated PWM + +Each led is represented as a sub-node of the nxp,pca963x device. + +LED sub-node properties: +- label : (optional) see Documentation/devicetree/bindings/leds/common.txt +- reg : number of LED line (could be from 0 to 3 in pca9632 or pca9633, + 0 to 7 in pca9634, or 0 to 15 in pca9635) +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt + +Examples: + +pca9632: pca9632 { + compatible = "nxp,pca9632"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x62>; + + red@0 { + label = "red"; + reg = <0>; + linux,default-trigger = "none"; + }; + green@1 { + label = "green"; + reg = <1>; + linux,default-trigger = "none"; + }; + blue@2 { + label = "blue"; + reg = <2>; + linux,default-trigger = "none"; + }; + unused@3 { + label = "unused"; + reg = <3>; + linux,default-trigger = "none"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/register-bit-led.txt b/arch/arm64/boot/dts/vendor/bindings/leds/register-bit-led.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf1ea403ba7aa22f14542c8ceb295475b9f2a574 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/register-bit-led.txt @@ -0,0 +1,94 @@ +Device Tree Bindings for Register Bit LEDs + +Register bit leds are used with syscon multifunctional devices +where single bits in a certain register can turn on/off a +single LED. The register bit LEDs appear as children to the +syscon device, with the proper compatible string. For the +syscon bindings see: +Documentation/devicetree/bindings/mfd/syscon.txt + +Each LED is represented as a sub-node of the syscon device. Each +node's name represents the name of the corresponding LED. + +LED sub-node properties: + +Required properties: +- compatible : must be "register-bit-led" +- offset : register offset to the register controlling this LED +- mask : bit mask for the bit controlling this LED in the register + typically 0x01, 0x02, 0x04 ... + +Optional properties: +- label : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- default-state: (optional) The initial state of the LED + see Documentation/devicetree/bindings/leds/common.txt + +Example: + +syscon: syscon@10000000 { + compatible = "arm,realview-pb1176-syscon", "syscon"; + reg = <0x10000000 0x1000>; + + led@8.0 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x01>; + label = "versatile:0"; + linux,default-trigger = "heartbeat"; + default-state = "on"; + }; + led@8.1 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x02>; + label = "versatile:1"; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + led@8.2 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x04>; + label = "versatile:2"; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + led@8.3 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x08>; + label = "versatile:3"; + default-state = "off"; + }; + led@8.4 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x10>; + label = "versatile:4"; + default-state = "off"; + }; + led@8.5 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x20>; + label = "versatile:5"; + default-state = "off"; + }; + led@8.6 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x40>; + label = "versatile:6"; + default-state = "off"; + }; + led@8.7 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x80>; + label = "versatile:7"; + default-state = "off"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/leds/tca6507.txt b/arch/arm64/boot/dts/vendor/bindings/leds/tca6507.txt new file mode 100644 index 0000000000000000000000000000000000000000..bad9102796f3299fb0e96100bca982cc76b79831 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/leds/tca6507.txt @@ -0,0 +1,49 @@ +LEDs connected to tca6507 + +Required properties: +- compatible : should be : "ti,tca6507". +- #address-cells: must be 1 +- #size-cells: must be 0 +- reg: typically 0x45. + +Optional properties: +- gpio-controller: allows lines to be used as output-only GPIOs. +- #gpio-cells: if present, must not be 0. + +Each led is represented as a sub-node of the ti,tca6507 device. + +LED sub-node properties: +- label : (optional) see Documentation/devicetree/bindings/leds/common.txt +- reg : number of LED line (could be from 0 to 6) +- linux,default-trigger : (optional) + see Documentation/devicetree/bindings/leds/common.txt +- compatible: either "led" (the default) or "gpio". + +Examples: + +tca6507@45 { + compatible = "ti,tca6507"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x45>; + + gpio-controller; + #gpio-cells = <2>; + + led0: red-aux@0 { + label = "red:aux"; + reg = <0x0>; + }; + + led1: green-aux@1 { + label = "green:aux"; + reg = <0x5>; + linux,default-trigger = "default-on"; + }; + + wifi-reset@6 { + reg = <0x6>; + compatible = "gpio"; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/lpddr2/lpddr2-timings.txt b/arch/arm64/boot/dts/vendor/bindings/lpddr2/lpddr2-timings.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ceb19e0c7fde6be95d3470ce7a525ba289952ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/lpddr2/lpddr2-timings.txt @@ -0,0 +1,52 @@ +* AC timing parameters of LPDDR2(JESD209-2) memories for a given speed-bin + +Required properties: +- compatible : Should be "jedec,lpddr2-timings" +- min-freq : minimum DDR clock frequency for the speed-bin. Type is +- max-freq : maximum DDR clock frequency for the speed-bin. Type is + +Optional properties: + +The following properties represent AC timing parameters from the memory +data-sheet of the device for a given speed-bin. All these properties are +of type and the default unit is ps (pico seconds). Parameters with +a different unit have a suffix indicating the unit such as 'tRAS-max-ns' +- tRCD +- tWR +- tRAS-min +- tRRD +- tWTR +- tXP +- tRTP +- tDQSCK-max +- tFAW +- tZQCS +- tZQinit +- tRPab +- tZQCL +- tCKESR +- tRAS-max-ns +- tDQSCK-max-derated + +Example: + +timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/lpddr2/lpddr2.txt b/arch/arm64/boot/dts/vendor/bindings/lpddr2/lpddr2.txt new file mode 100644 index 0000000000000000000000000000000000000000..58354a075e13928f54ded8cdd80323c44c23bbbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/lpddr2/lpddr2.txt @@ -0,0 +1,102 @@ +* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2 + +Required properties: +- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2", + "jedec,lpddr2-s4" + + "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type + + "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type + + "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type + +- density : representing density in Mb (Mega bits) + +- io-width : representing bus width. Possible values are 8, 16, and 32 + +Optional properties: + +The following optional properties represent the minimum value of some AC +timing parameters of the DDR device in terms of number of clock cycles. +These values shall be obtained from the device data-sheet. +- tRRD-min-tck +- tWTR-min-tck +- tXP-min-tck +- tRTP-min-tck +- tCKE-min-tck +- tRPab-min-tck +- tRCD-min-tck +- tWR-min-tck +- tRASmin-min-tck +- tCKESR-min-tck +- tFAW-min-tck + +Child nodes: +- The lpddr2 node may have one or more child nodes of type "lpddr2-timings". + "lpddr2-timings" provides AC timing parameters of the device for + a given speed-bin. The user may provide the timings for as many + speed-bins as is required. Please see Documentation/devicetree/ + bindings/lpddr2/lpddr2-timings.txt for more information on "lpddr2-timings" + +Example: + +elpida_ECB240ABACN : lpddr2 { + compatible = "Elpida,ECB240ABACN","jedec,lpddr2-s4"; + density = <2048>; + io-width = <32>; + + tRPab-min-tck = <3>; + tRCD-min-tck = <3>; + tWR-min-tck = <3>; + tRASmin-min-tck = <3>; + tRRD-min-tck = <2>; + tWTR-min-tck = <2>; + tXP-min-tck = <2>; + tRTP-min-tck = <2>; + tCKE-min-tck = <3>; + tCKESR-min-tck = <3>; + tFAW-min-tck = <8>; + + timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + + timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <200000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <10000>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + +} diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/altera-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/altera-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4dd93f1fed2432608fb9c79f7dfac033a087311 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/altera-mailbox.txt @@ -0,0 +1,48 @@ +Altera Mailbox Driver +===================== + +Required properties: +- compatible : "altr,mailbox-1.0". +- reg : physical base address of the mailbox and length of + memory mapped region. +- #mbox-cells: Common mailbox binding property to identify the number + of cells required for the mailbox specifier. Should be 1. + +Optional properties: +- interrupts : interrupt number. The interrupt specifier format + depends on the interrupt controller parent. + +Example: + mbox_tx: mailbox@100 { + compatible = "altr,mailbox-1.0"; + reg = <0x100 0x8>; + interrupt-parent = < &gic_0 >; + interrupts = <5>; + #mbox-cells = <1>; + }; + + mbox_rx: mailbox@200 { + compatible = "altr,mailbox-1.0"; + reg = <0x200 0x8>; + interrupt-parent = < &gic_0 >; + interrupts = <6>; + #mbox-cells = <1>; + }; + +Mailbox client +=============== +"mboxes" and the optional "mbox-names" (please see +Documentation/devicetree/bindings/mailbox/mailbox.txt for details). Each value +of the mboxes property should contain a phandle to the mailbox controller +device node and second argument is the channel index. It must be 0 (hardware +support only one channel).The equivalent "mbox-names" property value can be +used to give a name to the communication channel to be used by the client user. + +Example: + mclient0: mclient0@400 { + compatible = "client-1.0"; + reg = <0x400 0x10>; + mbox-names = "mbox-tx", "mbox-rx"; + mboxes = <&mbox_tx 0>, + <&mbox_rx 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/arm-mhu.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/arm-mhu.txt new file mode 100644 index 0000000000000000000000000000000000000000..4971f03f0b3307d2a39f81276cf4037ba070c942 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/arm-mhu.txt @@ -0,0 +1,43 @@ +ARM MHU Mailbox Driver +====================== + +The ARM's Message-Handling-Unit (MHU) is a mailbox controller that has +3 independent channels/links to communicate with remote processor(s). + MHU links are hardwired on a platform. A link raises interrupt for any +received data. However, there is no specified way of knowing if the sent +data has been read by the remote. This driver assumes the sender polls +STAT register and the remote clears it after having read the data. +The last channel is specified to be a 'Secure' resource, hence can't be +used by Linux running NS. + +Mailbox Device Node: +==================== + +Required properties: +-------------------- +- compatible: Shall be "arm,mhu" & "arm,primecell" +- reg: Contains the mailbox register address range (base + address and length) +- #mbox-cells Shall be 1 - the index of the channel needed. +- interrupts: Contains the interrupt information corresponding to + each of the 3 links of MHU. + +Example: +-------- + + mhu: mailbox@2b1f0000 { + #mbox-cells = <1>; + compatible = "arm,mhu", "arm,primecell"; + reg = <0 0x2b1f0000 0x1000>; + interrupts = <0 36 4>, /* LP-NonSecure */ + <0 35 4>, /* HP-NonSecure */ + <0 37 4>; /* Secure */ + clocks = <&clock 0 2 1>; + clock-names = "apb_pclk"; + }; + + mhu_client: scb@2e000000 { + compatible = "fujitsu,mb86s70-scb-1.0"; + reg = <0 0x2e000000 0x4000>; + mboxes = <&mhu 1>; /* HP-NonSecure */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,bcm2835-mbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,bcm2835-mbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..b48d7d30012cbc000aea6536065fd3e24dc846d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,bcm2835-mbox.txt @@ -0,0 +1,26 @@ +Broadcom BCM2835 VideoCore mailbox IPC + +Required properties: + +- compatible: Should be "brcm,bcm2835-mbox" +- reg: Specifies base physical address and size of the registers +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +- #mbox-cells: Specifies the number of cells needed to encode a mailbox + channel. The value shall be 0, since there is only one + mailbox channel implemented by the device. + +Example: + +mailbox: mailbox@7e00b880 { + compatible = "brcm,bcm2835-mbox"; + reg = <0x7e00b880 0x40>; + interrupts = <0 1>; + #mbox-cells = <0>; +}; + +firmware: firmware { + compatible = "raspberrypi,firmware"; + mboxes = <&mailbox>; + #power-domain-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,iproc-flexrm-mbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,iproc-flexrm-mbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..752ae6b00d26a7c39f914637d37149f93efb5b36 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,iproc-flexrm-mbox.txt @@ -0,0 +1,59 @@ +Broadcom FlexRM Ring Manager +============================ +The Broadcom FlexRM ring manager provides a set of rings which can be +used to submit work to offload engines. An SoC may have multiple FlexRM +hardware blocks. There is one device tree entry per FlexRM block. The +FlexRM driver will create a mailbox-controller instance for given FlexRM +hardware block where each mailbox channel is a separate FlexRM ring. + +Required properties: +-------------------- +- compatible: Should be "brcm,iproc-flexrm-mbox" +- reg: Specifies base physical address and size of the FlexRM + ring registers +- msi-parent: Phandles (and potential Device IDs) to MSI controllers + The FlexRM engine will send MSIs (instead of wired + interrupts) to CPU. There is one MSI for each FlexRM ring. + Refer devicetree/bindings/interrupt-controller/msi.txt +- #mbox-cells: Specifies the number of cells needed to encode a mailbox + channel. This should be 3. + + The 1st cell is the mailbox channel number. + + The 2nd cell contains MSI completion threshold. This is the + number of completion messages for which FlexRM will inject + one MSI interrupt to CPU. + + The 3nd cell contains MSI timer value representing time for + which FlexRM will wait to accumulate N completion messages + where N is the value specified by 2nd cell above. If FlexRM + does not get required number of completion messages in time + specified by this cell then it will inject one MSI interrupt + to CPU provided atleast one completion message is available. + +Optional properties: +-------------------- +- dma-coherent: Present if DMA operations made by the FlexRM engine (such + as DMA descriptor access, access to buffers pointed by DMA + descriptors and read/write pointer updates to DDR) are + cache coherent with the CPU. + +Example: +-------- +crypto_mbox: mbox@67000000 { + compatible = "brcm,iproc-flexrm-mbox"; + reg = <0x67000000 0x200000>; + msi-parent = <&gic_its 0x7f00>; + #mbox-cells = <3>; +}; + +crypto@672c0000 { + compatible = "brcm,spu2-v2-crypto"; + reg = <0x672c0000 0x1000>; + mboxes = <&crypto_mbox 0 0x1 0xffff>, + <&crypto_mbox 1 0x1 0xffff>, + <&crypto_mbox 16 0x1 0xffff>, + <&crypto_mbox 17 0x1 0xffff>, + <&crypto_mbox 30 0x1 0xffff>, + <&crypto_mbox 31 0x1 0xffff>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,iproc-pdc-mbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,iproc-pdc-mbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bcdf2087625c108a8180060f3dd9ebb4c111a46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/brcm,iproc-pdc-mbox.txt @@ -0,0 +1,25 @@ +The PDC driver manages data transfer to and from various offload engines +on some Broadcom SoCs. An SoC may have multiple PDC hardware blocks. There is +one device tree entry per block. On some chips, the PDC functionality is +handled by the FA2 (Northstar Plus). + +Required properties: +- compatible : Should be "brcm,iproc-pdc-mbox" or "brcm,iproc-fa2-mbox" for + FA2/Northstar Plus. +- reg: Should contain PDC registers location and length. +- interrupts: Should contain the IRQ line for the PDC. +- #mbox-cells: 1 +- brcm,rx-status-len: Length of metadata preceding received frames, in bytes. + +Optional properties: +- brcm,use-bcm-hdr: present if a BCM header precedes each frame. + +Example: + pdc0: iproc-pdc0@612c0000 { + compatible = "brcm,iproc-pdc-mbox"; + reg = <0 0x612c0000 0 0x445>; /* PDC FS0 regs */ + interrupts = ; + #mbox-cells = <1>; /* one cell per mailbox channel */ + brcm,rx-status-len = <32>; + brcm,use-bcm-hdr; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/fsl,mu.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/fsl,mu.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3cf77eb5ab41c3ae67b633af2abe1ac68645c35 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/fsl,mu.txt @@ -0,0 +1,54 @@ +NXP i.MX Messaging Unit (MU) +-------------------------------------------------------------------- + +The Messaging Unit module enables two processors within the SoC to +communicate and coordinate by passing messages (e.g. data, status +and control) through the MU interface. The MU also provides the ability +for one processor to signal the other processor using interrupts. + +Because the MU manages the messaging between processors, the MU uses +different clocks (from each side of the different peripheral buses). +Therefore, the MU must synchronize the accesses from one side to the +other. The MU accomplishes synchronization using two sets of matching +registers (Processor A-facing, Processor B-facing). + +Messaging Unit Device Node: +============================= + +Required properties: +------------------- +- compatible : should be "fsl,-mu", the supported chips include + imx6sx, imx7s, imx8qxp, imx8qm. + The "fsl,imx6sx-mu" compatible is seen as generic and should + be included together with SoC specific compatible. +- reg : Should contain the registers location and length +- interrupts : Interrupt number. The interrupt specifier format depends + on the interrupt controller parent. +- #mbox-cells: Must be 2. + <&phandle type channel> + phandle : Label name of controller + type : Channel type + channel : Channel number + + This MU support 4 type of unidirectional channels, each type + has 4 channels. A total of 16 channels. Following types are + supported: + 0 - TX channel with 32bit transmit register and IRQ transmit + acknowledgment support. + 1 - RX channel with 32bit receive register and IRQ support + 2 - TX doorbell channel. Without own register and no ACK support. + 3 - RX doorbell channel. + +Optional properties: +------------------- +- clocks : phandle to the input clock. +- fsl,mu-side-b : Should be set for side B MU. + +Examples: +-------- +lsio_mu0: mailbox@5d1b0000 { + compatible = "fsl,imx8qxp-mu"; + reg = <0x0 0x5d1b0000 0x0 0x10000>; + interrupts = ; + #mbox-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/hisilicon,hi3660-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/hisilicon,hi3660-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e5b4537407d173c7fc7e95453ba7714f24d897c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/hisilicon,hi3660-mailbox.txt @@ -0,0 +1,51 @@ +Hisilicon Hi3660 Mailbox Controller + +Hisilicon Hi3660 mailbox controller supports up to 32 channels. Messages +are passed between processors, including application & communication +processors, MCU, HIFI, etc. Each channel is unidirectional and accessed +by using MMIO registers; it supports maximum to 8 words message. + +Controller +---------- + +Required properties: +- compatible: : Shall be "hisilicon,hi3660-mbox" +- reg: : Offset and length of the device's register set +- #mbox-cells: : Must be 3 + <&phandle channel dst_irq ack_irq> + phandle : Label name of controller + channel : Channel number + dst_irq : Remote interrupt vector + ack_irq : Local interrupt vector + +- interrupts: : Contains the two IRQ lines for mailbox. + +Example: + +mailbox: mailbox@e896b000 { + compatible = "hisilicon,hi3660-mbox"; + reg = <0x0 0xe896b000 0x0 0x1000>; + interrupts = <0x0 0xc0 0x4>, + <0x0 0xc1 0x4>; + #mbox-cells = <3>; +}; + +Client +------ + +Required properties: +- compatible : See the client docs +- mboxes : Standard property to specify a Mailbox (See ./mailbox.txt) + Cells must match 'mbox-cells' (See Controller docs above) + +Optional properties +- mbox-names : Name given to channels seen in the 'mboxes' property. + +Example: + +stub_clock: stub_clock@e896b500 { + compatible = "hisilicon,hi3660-stub-clk"; + reg = <0x0 0xe896b500 0x0 0x0100>; + #clock-cells = <1>; + mboxes = <&mailbox 13 3 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/hisilicon,hi6220-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/hisilicon,hi6220-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..044b17f3a77a6bd1958d0d2e0e9d73b48c073adb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/hisilicon,hi6220-mailbox.txt @@ -0,0 +1,74 @@ +Hisilicon Hi6220 Mailbox Driver +=============================== + +Hisilicon Hi6220 mailbox supports up to 32 channels. Each channel +is unidirectional with a maximum message size of 8 words. I/O is +performed using register access (there is no DMA) and the cell +raises an interrupt when messages are received. + +Mailbox Device Node: +==================== + +Required properties: +-------------------- +- compatible: Shall be "hisilicon,hi6220-mbox" +- reg: Contains the mailbox register address range (base + address and length); the first item is for IPC + registers, the second item is shared buffer for + slots. +- #mbox-cells: Common mailbox binding property to identify the number + of cells required for the mailbox specifier. Must be 3. + <&phandle slot_id dst_irq ack_irq> + phandle: Label name of mailbox controller + slot_id: Slot id used either for TX or RX + dst_irq: IRQ identifier index number which used by MCU + ack_irq: IRQ identifier index number with generating a + TX/RX interrupt to application processor, + mailbox driver uses it to acknowledge interrupt +- interrupts: Contains the interrupt information for the mailbox + device. The format is dependent on which interrupt + controller the SoCs use. + +Optional Properties: +-------------------- +- hi6220,mbox-tx-noirq: Property of MCU firmware's feature, so mailbox driver + use this flag to ask MCU to enable "automatic idle + flag" mode or IRQ generated mode to acknowledge a TX + completion. + +Example: +-------- + + mailbox: mailbox@f7510000 { + compatible = "hisilicon,hi6220-mbox"; + reg = <0x0 0xf7510000 0x0 0x1000>, /* IPC_S */ + <0x0 0x06dff800 0x0 0x0800>; /* Mailbox */ + interrupt-parent = <&gic>; + interrupts = ; + #mbox-cells = <3>; + }; + + +Mailbox client +=============== + +Required properties: +-------------------- +- compatible: Many (See the client docs). +- mboxes: Standard property to specify a Mailbox (See ./mailbox.txt) + Cells must match 'mbox-cells' (See Mailbox Device Node above). + +Optional Properties: +-------------------- +- mbox-names: Name given to channels seen in the 'mboxes' property. + +Example: +-------- + + stub_clock: stub_clock { + compatible = "hisilicon,hi6220-stub-clk"; + hisilicon,hi6220-clk-sram = <&sram>; + #clock-cells = <1>; + mbox-names = "mbox-tx", "mbox-rx"; + mboxes = <&mailbox 1 0 11>, <&mailbox 0 1 10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..af8ecee2ac687f105d1c5e2c99a34b2e56f51e10 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/mailbox.txt @@ -0,0 +1,60 @@ +* Generic Mailbox Controller and client driver bindings + +Generic binding to provide a way for Mailbox controller drivers to +assign appropriate mailbox channel to client drivers. + +* Mailbox Controller + +Required property: +- #mbox-cells: Must be at least 1. Number of cells in a mailbox + specifier. + +Example: + mailbox: mailbox { + ... + #mbox-cells = <1>; + }; + + +* Mailbox Client + +Required property: +- mboxes: List of phandle and mailbox channel specifiers. + +Optional property: +- mbox-names: List of identifier strings for each mailbox channel. +- shmem : List of phandle pointing to the shared memory(SHM) area between the + users of these mailboxes for IPC, one for each mailbox. This shared + memory can be part of any memory reserved for the purpose of this + communication between the mailbox client and the remote. + + +Example: + pwr_cntrl: power { + ... + mbox-names = "pwr-ctrl", "rpc"; + mboxes = <&mailbox 0 &mailbox 1>; + }; + +Example with shared memory(shmem): + + sram: sram@50000000 { + compatible = "mmio-sram"; + reg = <0x50000000 0x10000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x50000000 0x10000>; + + cl_shmem: shmem@0 { + compatible = "client-shmem"; + reg = <0x0 0x200>; + }; + }; + + client@2e000000 { + ... + mboxes = <&mailbox 0>; + shmem = <&cl_shmem>; + .. + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/meson-mhu.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/meson-mhu.txt new file mode 100644 index 0000000000000000000000000000000000000000..a530310772b9f4b35134f0f3d77c8034a97af199 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/meson-mhu.txt @@ -0,0 +1,34 @@ +Amlogic Meson MHU Mailbox Driver +================================ + +The Amlogic's Meson SoCs Message-Handling-Unit (MHU) is a mailbox controller +that has 3 independent channels/links to communicate with remote processor(s). +MHU links are hardwired on a platform. A link raises interrupt for any +received data. However, there is no specified way of knowing if the sent +data has been read by the remote. This driver assumes the sender polls +STAT register and the remote clears it after having read the data. + +Mailbox Device Node: +==================== + +Required properties: +-------------------- +- compatible: Shall be "amlogic,meson-gxbb-mhu" +- reg: Contains the mailbox register address range (base + address and length) +- #mbox-cells Shall be 1 - the index of the channel needed. +- interrupts: Contains the interrupt information corresponding to + each of the 2 links of MHU. + +Example: +-------- + + mailbox: mailbox@c883c404 { + #mbox-cells = <1>; + compatible = "amlogic,meson-gxbb-mhu"; + reg = <0 0xc883c404 0 0x4c>; + interrupts = <0 208 IRQ_TYPE_EDGE_RISING>, + <0 209 IRQ_TYPE_EDGE_RISING>, + <0 210 IRQ_TYPE_EDGE_RISING>; + #mbox-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/mtk-gce.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/mtk-gce.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d72b21c9e94d4af4222bed54fb2d7d50efb2961 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/mtk-gce.txt @@ -0,0 +1,57 @@ +MediaTek GCE +=============== + +The Global Command Engine (GCE) is used to help read/write registers with +critical time limitation, such as updating display configuration during the +vblank. The GCE can be used to implement the Command Queue (CMDQ) driver. + +CMDQ driver uses mailbox framework for communication. Please refer to +mailbox.txt for generic information about mailbox device-tree bindings. + +Required properties: +- compatible: Must be "mediatek,mt8173-gce" +- reg: Address range of the GCE unit +- interrupts: The interrupt signal from the GCE block +- clock: Clocks according to the common clock binding +- clock-names: Must be "gce" to stand for GCE clock +- #mbox-cells: Should be 3. + <&phandle channel priority atomic_exec> + phandle: Label name of a gce node. + channel: Channel of mailbox. Be equal to the thread id of GCE. + priority: Priority of GCE thread. + atomic_exec: GCE processing continuous packets of commands in atomic + way. + +Required properties for a client device: +- mboxes: Client use mailbox to communicate with GCE, it should have this + property and list of phandle, mailbox specifiers. +- mediatek,gce-subsys: u32, specify the sub-system id which is corresponding + to the register address. + +Some vaules of properties are defined in 'dt-bindings/gce/mt8173-gce.h'. Such as +sub-system ids, thread priority, event ids. + +Example: + + gce: gce@10212000 { + compatible = "mediatek,mt8173-gce"; + reg = <0 0x10212000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_GCE>; + clock-names = "gce"; + thread-num = CMDQ_THR_MAX_COUNT; + #mbox-cells = <3>; + }; + +Example for a client device: + + mmsys: clock-controller@14000000 { + compatible = "mediatek,mt8173-mmsys"; + mboxes = <&gce 0 CMDQ_THR_PRIO_LOWEST 1>, + <&gce 1 CMDQ_THR_PRIO_LOWEST 1>; + mediatek,gce-subsys = ; + mutex-event-eof = ; + + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/nvidia,tegra186-hsp.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/nvidia,tegra186-hsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..b99d25fc2f26e7a2bd6a4548f0b7a8f9baae8723 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/nvidia,tegra186-hsp.txt @@ -0,0 +1,52 @@ +NVIDIA Tegra Hardware Synchronization Primitives (HSP) + +The HSP modules are used for the processors to share resources and communicate +together. It provides a set of hardware synchronization primitives for +interprocessor communication. So the interprocessor communication (IPC) +protocols can use hardware synchronization primitives, when operating between +two processors not in an SMP relationship. + +The features that HSP supported are shared mailboxes, shared semaphores, +arbitrated semaphores and doorbells. + +Required properties: +- name : Should be hsp +- compatible + Array of strings. + one of: + - "nvidia,tegra186-hsp" +- reg : Offset and length of the register set for the device. +- interrupt-names + Array of strings. + Contains a list of names for the interrupts described by the interrupt + property. May contain the following entries, in any order: + - "doorbell" + Users of this binding MUST look up entries in the interrupt property + by name, using this interrupt-names property to do so. +- interrupts + Array of interrupt specifiers. + Must contain one entry per entry in the interrupt-names property, + in a matching order. +- #mbox-cells : Should be 2. + +The mbox specifier of the "mboxes" property in the client node should +contain two data. The first one should be the HSP type and the second +one should be the ID that the client is going to use. Those information +can be found in the following file. + +- . + +Example: + +hsp_top0: hsp@3c00000 { + compatible = "nvidia,tegra186-hsp"; + reg = <0x0 0x03c00000 0x0 0xa0000>; + interrupts = ; + interrupt-names = "doorbell"; + #mbox-cells = <2>; +}; + +client { + ... + mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB TEGRA_HSP_DB_MASTER_XXX>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/omap-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/omap-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ef372656a3eac86e8b1be97fc7dc8231936b8e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/omap-mailbox.txt @@ -0,0 +1,139 @@ +OMAP2+ Mailbox Driver +===================== + +The OMAP mailbox hardware facilitates communication between different processors +using a queued mailbox interrupt mechanism. The IP block is external to the +various processor subsystems and is connected on an interconnect bus. The +communication is achieved through a set of registers for message storage and +interrupt configuration registers. + +Each mailbox IP block has a certain number of h/w fifo queues and output +interrupt lines. An output interrupt line is routed to an interrupt controller +within a processor subsystem, and there can be more than one line going to a +specific processor's interrupt controller. The interrupt line connections are +fixed for an instance and are dictated by the IP integration into the SoC +(excluding the SoCs that have a Interrupt Crossbar IP). Each interrupt line is +programmable through a set of interrupt configuration registers, and have a rx +and tx interrupt source per h/w fifo. Communication between different processors +is achieved through the appropriate programming of the rx and tx interrupt +sources on the appropriate interrupt lines. + +The number of h/w fifo queues and interrupt lines dictate the usable registers. +All the current OMAP SoCs except for the newest DRA7xx SoC has a single IP +instance. DRA7xx has multiple instances with different number of h/w fifo queues +and interrupt lines between different instances. The interrupt lines can also be +routed to different processor sub-systems on DRA7xx as they are routed through +the Crossbar, a kind of interrupt router/multiplexer. + +Mailbox Device Node: +==================== +A Mailbox device node is used to represent a Mailbox IP instance within a SoC. +The sub-mailboxes are represented as child nodes of this parent node. + +Required properties: +-------------------- +- compatible: Should be one of the following, + "ti,omap2-mailbox" for OMAP2420, OMAP2430 SoCs + "ti,omap3-mailbox" for OMAP3430, OMAP3630 SoCs + "ti,omap4-mailbox" for OMAP44xx, OMAP54xx, AM33xx, + AM43xx and DRA7xx SoCs +- reg: Contains the mailbox register address range (base + address and length) +- interrupts: Contains the interrupt information for the mailbox + device. The format is dependent on which interrupt + controller the OMAP device uses +- ti,hwmods: Name of the hwmod associated with the mailbox +- #mbox-cells: Common mailbox binding property to identify the number + of cells required for the mailbox specifier. Should be + 1 +- ti,mbox-num-users: Number of targets (processor devices) that the mailbox + device can interrupt +- ti,mbox-num-fifos: Number of h/w fifo queues within the mailbox IP block + +Child Nodes: +============ +A child node is used for representing the actual sub-mailbox device that is +used for the communication between the host processor and a remote processor. +Each child node should have a unique node name across all the different +mailbox device nodes. + +Required properties: +-------------------- +- ti,mbox-tx: sub-mailbox descriptor property defining a Tx fifo +- ti,mbox-rx: sub-mailbox descriptor property defining a Rx fifo + +Sub-mailbox Descriptor Data +--------------------------- +Each of the above ti,mbox-tx and ti,mbox-rx properties should have 3 cells of +data that represent the following: + Cell #1 (fifo_id) - mailbox fifo id used either for transmitting + (ti,mbox-tx) or for receiving (ti,mbox-rx) + Cell #2 (irq_id) - irq identifier index number to use from the parent's + interrupts data. Should be 0 for most of the cases, a + positive index value is seen only on mailboxes that have + multiple interrupt lines connected to the MPU processor. + Cell #3 (usr_id) - mailbox user id for identifying the interrupt line + associated with generating a tx/rx fifo interrupt. + +Optional Properties: +-------------------- +- ti,mbox-send-noirq: Quirk flag to allow the client user of this sub-mailbox + to send messages without triggering a Tx ready interrupt, + and to control the Tx ticker. Should be used only on + sub-mailboxes used to communicate with WkupM3 remote + processor on AM33xx/AM43xx SoCs. + +Mailbox Users: +============== +A device needing to communicate with a target processor device should specify +them using the common mailbox binding properties, "mboxes" and the optional +"mbox-names" (please see Documentation/devicetree/bindings/mailbox/mailbox.txt +for details). Each value of the mboxes property should contain a phandle to the +mailbox controller device node and an args specifier that will be the phandle to +the intended sub-mailbox child node to be used for communication. The equivalent +"mbox-names" property value can be used to give a name to the communication channel +to be used by the client user. + + +Example: +-------- + +/* OMAP4 */ +mailbox: mailbox@4a0f4000 { + compatible = "ti,omap4-mailbox"; + reg = <0x4a0f4000 0x200>; + interrupts = ; + ti,hwmods = "mailbox"; + #mbox-cells = <1>; + ti,mbox-num-users = <3>; + ti,mbox-num-fifos = <8>; + mbox_ipu: mbox_ipu { + ti,mbox-tx = <0 0 0>; + ti,mbox-rx = <1 0 0>; + }; + mbox_dsp: mbox_dsp { + ti,mbox-tx = <3 0 0>; + ti,mbox-rx = <2 0 0>; + }; +}; + +dsp { + ... + mboxes = <&mailbox &mbox_dsp>; + ... +}; + +/* AM33xx */ +mailbox: mailbox@480c8000 { + compatible = "ti,omap4-mailbox"; + reg = <0x480C8000 0x200>; + interrupts = <77>; + ti,hwmods = "mailbox"; + #mbox-cells = <1>; + ti,mbox-num-users = <4>; + ti,mbox-num-fifos = <8>; + mbox_wkupm3: wkup_m3 { + ti,mbox-tx = <0 0 0>; + ti,mbox-rx = <0 0 3>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/qcom,apcs-kpss-global.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/qcom,apcs-kpss-global.txt new file mode 100644 index 0000000000000000000000000000000000000000..b77d58bb5b490b03864634a5abf35dc4080363f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/qcom,apcs-kpss-global.txt @@ -0,0 +1,71 @@ +Binding for the Qualcomm APCS global block +========================================== + +This binding describes the APCS "global" block found in various Qualcomm +platforms. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,msm8916-apcs-kpss-global", + "qcom,msm8996-apcs-hmss-global" + "qcom,msm8998-apcs-hmss-global" + "qcom,sdm845-apss-shared" + "qcom,sm8150-apcs-hmss-global" + "qcom,sm8150-spcs-global" + "qcom,kona-spcs-global" + "qcom,bengal-apcs-hmss-global" + "qcom,scuba-apcs-hmss-global" + "qcom,sdm660-apcs-hmss-global" +- reg: + Usage: required + Value type: + Definition: must specify the base address and size of the global block +- clocks: + Usage: required if #clocks-cells property is present + Value type: + Definition: phandle to the input PLL, which feeds the APCS mux/divider + +- #mbox-cells: + Usage: required + Value type: + Definition: as described in mailbox.txt, must be 1 + +- #clock-cells: + Usage: optional + Value type: + Definition: as described in clock.txt, must be 0 + + += EXAMPLE +The following example describes the APCS HMSS found in MSM8996 and part of the +GLINK RPM referencing the "rpm_hlos" doorbell therein. + + apcs_glb: mailbox@9820000 { + compatible = "qcom,msm8996-apcs-hmss-global"; + reg = <0x9820000 0x1000>; + + #mbox-cells = <1>; + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + + interrupts = ; + + qcom,rpm-msg-ram = <&rpm_msg_ram>; + + mboxes = <&apcs_glb 0>; + mbox-names = "rpm_hlos"; + }; + +Below is another example of the APCS binding on MSM8916 platforms: + + apcs: mailbox@b011000 { + compatible = "qcom,msm8916-apcs-kpss-global"; + reg = <0xb011000 0x1000>; + #mbox-cells = <1>; + clocks = <&a53pll>; + #clock-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/rockchip-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/rockchip-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6bb84acf5be65d96a47af56ccd051ed57cead32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/rockchip-mailbox.txt @@ -0,0 +1,32 @@ +Rockchip mailbox + +The Rockchip mailbox is used by the Rockchip CPU cores to communicate +requests to MCU processor. + +Refer to ./mailbox.txt for generic information about mailbox device-tree +bindings. + +Required properties: + + - compatible: should be one of the following. + - "rockchip,rk3368-mbox" for rk3368 + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. + - #mbox-cells: Common mailbox binding property to identify the number + of cells required for the mailbox specifier. Should be 1 + +Example: +-------- + +/* RK3368 */ +mbox: mbox@ff6b0000 { + compatible = "rockchip,rk3368-mailbox"; + reg = <0x0 0xff6b0000 0x0 0x1000>, + interrupts = , + , + , + ; + #mbox-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/sti-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/sti-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..351f612673fc5368ba3d4f8116114fbdd2fb5659 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/sti-mailbox.txt @@ -0,0 +1,51 @@ +ST Microelectronics Mailbox Driver + +Each ST Mailbox IP currently consists of 4 instances of 32 channels. Messages +are passed between Application and Remote processors using shared memory. + +Controller +---------- + +Required properties: +- compatible : Should be "st,stih407-mailbox" +- reg : Offset and length of the device's register set +- mbox-name : Name of the mailbox +- #mbox-cells: : Must be 2 + <&phandle instance channel direction> + phandle : Label name of controller + instance : Instance number + channel : Channel number + +Optional properties +- interrupts : Contains the IRQ line for a Rx mailbox + +Example: + +mailbox0: mailbox@0 { + compatible = "st,stih407-mailbox"; + reg = <0x08f00000 0x1000>; + interrupts = ; + #mbox-cells = <2>; + mbox-name = "a9"; +}; + +Client +------ + +Required properties: +- compatible : Many (See the client docs) +- reg : Shared (between Application and Remote) memory address +- mboxes : Standard property to specify a Mailbox (See ./mailbox.txt) + Cells must match 'mbox-cells' (See Controller docs above) + +Optional properties +- mbox-names : Name given to channels seen in the 'mboxes' property. + +Example: + +mailbox_test { + compatible = "mailbox-test"; + reg = <0x[shared_memory_address], [shared_memory_size]>; + mboxes = <&mailbox2 0 1>, <&mailbox0 2 1>; + mbox-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/stm32-ipcc.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/stm32-ipcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d2b7fee7b853e52bf5b6d2e2c718e96e3f85456 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/stm32-ipcc.txt @@ -0,0 +1,47 @@ +* STMicroelectronics STM32 IPCC (Inter-Processor Communication Controller) + +The IPCC block provides a non blocking signaling mechanism to post and +retrieve messages in an atomic way between two processors. +It provides the signaling for N bidirectionnal channels. The number of channels +(N) can be read from a dedicated register. + +Required properties: +- compatible: Must be "st,stm32mp1-ipcc" +- reg: Register address range (base address and length) +- st,proc-id: Processor id using the mailbox (0 or 1) +- clocks: Input clock +- interrupt-names: List of names for the interrupts described by the interrupt + property. Must contain the following entries: + - "rx" + - "tx" + - "wakeup" +- interrupts: Interrupt specifiers for "rx channel occupied", "tx channel + free" and "system wakeup". +- #mbox-cells: Number of cells required for the mailbox specifier. Must be 1. + The data contained in the mbox specifier of the "mboxes" + property in the client node is the mailbox channel index. + +Optional properties: +- wakeup-source: Flag to indicate whether this device can wake up the system + + + +Example: + ipcc: mailbox@4c001000 { + compatible = "st,stm32mp1-ipcc"; + #mbox-cells = <1>; + reg = <0x4c001000 0x400>; + st,proc-id = <0>; + interrupts-extended = <&intc GIC_SPI 100 IRQ_TYPE_NONE>, + <&intc GIC_SPI 101 IRQ_TYPE_NONE>, + <&aiec 62 1>; + interrupt-names = "rx", "tx", "wakeup"; + clocks = <&rcc_clk IPCC>; + wakeup-source; + } + +Client: + mbox_test { + ... + mboxes = <&ipcc 0>, <&ipcc 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/ti,message-manager.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/ti,message-manager.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebf0e3710ceecebf8682c649dcd19f1969c990bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/ti,message-manager.txt @@ -0,0 +1,50 @@ +Texas Instruments' Message Manager Driver +======================================== + +The Texas Instruments' Message Manager is a mailbox controller that has +configurable queues selectable at SoC(System on Chip) integration. The Message +manager is broken up into queues in different address regions that are called +"proxies" - each instance is unidirectional and is instantiated at SoC +integration level to indicate receive or transmit path. + +Message Manager Device Node: +=========================== +Required properties: +-------------------- +- compatible: Shall be: "ti,k2g-message-manager" +- reg-names queue_proxy_region - Map the queue proxy region. + queue_state_debug_region - Map the queue state debug + region. +- reg: Contains the register map per reg-names. +- #mbox-cells Shall be 2. Contains the queue ID and proxy ID in that + order referring to the transfer path. +- interrupt-names: Contains interrupt names matching the rx transfer path + for a given SoC. Receive interrupts shall be of the + format: "rx_". + For ti,k2g-message-manager, this shall contain: + "rx_005", "rx_057" +- interrupts: Contains the interrupt information corresponding to + interrupt-names property. + +Example(K2G): +------------ + + msgmgr: msgmgr@2a00000 { + compatible = "ti,k2g-message-manager"; + #mbox-cells = <2>; + reg-names = "queue_proxy_region", "queue_state_debug_region"; + reg = <0x02a00000 0x400000>, <0x028c3400 0x400>; + interrupt-names = "rx_005", "rx_057"; + interrupts = , + ; + }; + + pmmc: pmmc { + [...] + mbox-names = "rx", "tx"; + # RX queue ID is 5, proxy ID is 2 + # TX queue ID is 0, proxy ID is 0 + mboxes= <&msgmgr 5 2>, + <&msgmgr 0 0>; + [...] + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/ti,secure-proxy.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/ti,secure-proxy.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c9c7daf0f5c3239c7c3acc4081d705d189bd24d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/ti,secure-proxy.txt @@ -0,0 +1,50 @@ +Texas Instruments' Secure Proxy +======================================== + +The Texas Instruments' secure proxy is a mailbox controller that has +configurable queues selectable at SoC(System on Chip) integration. The +Message manager is broken up into different address regions that are +called "threads" or "proxies" - each instance is unidirectional and is +instantiated at SoC integration level by system controller to indicate +receive or transmit path. + +Message Manager Device Node: +=========================== +Required properties: +-------------------- +- compatible: Shall be "ti,am654-secure-proxy" +- reg-names target_data - Map the proxy data region + rt - Map the realtime status region + scfg - Map the configuration region +- reg: Contains the register map per reg-names. +- #mbox-cells Shall be 1 and shall refer to the transfer path + called thread. +- interrupt-names: Contains interrupt names matching the rx transfer path + for a given SoC. Receive interrupts shall be of the + format: "rx_". +- interrupts: Contains the interrupt information corresponding to + interrupt-names property. + +Example(AM654): +------------ + + secure_proxy: mailbox@32c00000 { + compatible = "ti,am654-secure-proxy"; + #mbox-cells = <1>; + reg-names = "target_data", "rt", "scfg"; + reg = <0x0 0x32c00000 0x0 0x100000>, + <0x0 0x32400000 0x0 0x100000>, + <0x0 0x32800000 0x0 0x100000>; + interrupt-names = "rx_011"; + interrupts = ; + }; + + dmsc: dmsc { + [...] + mbox-names = "rx", "tx"; + # RX Thread ID is 11 + # TX Thread ID is 13 + mboxes= <&secure_proxy 11>, + <&secure_proxy 13>; + [...] + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mailbox/xgene-slimpro-mailbox.txt b/arch/arm64/boot/dts/vendor/bindings/mailbox/xgene-slimpro-mailbox.txt new file mode 100644 index 0000000000000000000000000000000000000000..e46451bb242f3d577b4ed8240b202ba2e29b1c95 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mailbox/xgene-slimpro-mailbox.txt @@ -0,0 +1,35 @@ +The APM X-Gene SLIMpro mailbox is used to communicate messages between +the ARM64 processors and the Cortex M3 (dubbed SLIMpro). It uses a simple +interrupt based door bell mechanism and can exchange simple messages using the +internal registers. + +There are total of 8 interrupts in this mailbox. Each used for an individual +door bell (or mailbox channel). + +Required properties: +- compatible: Should be as "apm,xgene-slimpro-mbox". + +- reg: Contains the mailbox register address range. + +- interrupts: 8 interrupts must be from 0 to 7, interrupt 0 define the + the interrupt for mailbox channel 0 and interrupt 1 for + mailbox channel 1 and so likewise for the reminder. + +- #mbox-cells: only one to specify the mailbox channel number. + +Example: + +Mailbox Node: + mailbox: mailbox@10540000 { + compatible = "apm,xgene-slimpro-mbox"; + reg = <0x0 0x10540000 0x0 0xa000>; + #mbox-cells = <1>; + interrupts = <0x0 0x0 0x4>, + <0x0 0x1 0x4>, + <0x0 0x2 0x4>, + <0x0 0x3 0x4>, + <0x0 0x4 0x4>, + <0x0 0x5 0x4>, + <0x0 0x6 0x4>, + <0x0 0x7 0x4>, + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/atmel-isc.txt b/arch/arm64/boot/dts/vendor/bindings/media/atmel-isc.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbe0e87c6188dc76f6f4a24ce75142e6b8c6296f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/atmel-isc.txt @@ -0,0 +1,65 @@ +Atmel Image Sensor Controller (ISC) +---------------------------------------------- + +Required properties for ISC: +- compatible + Must be "atmel,sama5d2-isc". +- reg + Physical base address and length of the registers set for the device. +- interrupts + Should contain IRQ line for the ISC. +- clocks + List of clock specifiers, corresponding to entries in + the clock-names property; + Please refer to clock-bindings.txt. +- clock-names + Required elements: "hclock", "iscck", "gck". +- #clock-cells + Should be 0. +- clock-output-names + Should be "isc-mck". +- pinctrl-names, pinctrl-0 + Please refer to pinctrl-bindings.txt. + +ISC supports a single port node with parallel bus. It should contain one +'port' child node with child 'endpoint' node. Please refer to the bindings +defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: +isc: isc@f0008000 { + compatible = "atmel,sama5d2-isc"; + reg = <0xf0008000 0x4000>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&isc_clk>, <&iscck>, <&isc_gclk>; + clock-names = "hclock", "iscck", "gck"; + #clock-cells = <0>; + clock-output-names = "isc-mck"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>; + + port { + isc_0: endpoint { + remote-endpoint = <&ov7740_0>; + hsync-active = <1>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; +}; + +i2c1: i2c@fc028000 { + ov7740: camera@21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + clocks = <&isc>; + clock-names = "xvclk"; + assigned-clocks = <&isc>; + assigned-clock-rates = <24000000>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isc_0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/atmel-isi.txt b/arch/arm64/boot/dts/vendor/bindings/media/atmel-isi.txt new file mode 100644 index 0000000000000000000000000000000000000000..332513a151cc9d45ba299e4722cb19eb8a20a827 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/atmel-isi.txt @@ -0,0 +1,66 @@ +Atmel Image Sensor Interface (ISI) +---------------------------------- + +Required properties for ISI: +- compatible: must be "atmel,at91sam9g45-isi". +- reg: physical base address and length of the registers set for the device. +- interrupts: should contain IRQ line for the ISI. +- clocks: list of clock specifiers, corresponding to entries in the clock-names + property; please refer to clock-bindings.txt. +- clock-names: required elements: "isi_clk". +- pinctrl-names, pinctrl-0: please refer to pinctrl-bindings.txt. + +ISI supports a single port node with parallel bus. It shall contain one +'port' child node with child 'endpoint' node. Please refer to the bindings +defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + +Endpoint node properties +------------------------ + +- bus-width: <8> or <10> (mandatory) +- hsync-active (default: active high) +- vsync-active (default: active high) +- pclk-sample (default: sample on falling edge) +- remote-endpoint: A phandle to the bus receiver's endpoint node (mandatory). + +Example: + +isi: isi@f0034000 { + compatible = "atmel,at91sam9g45-isi"; + reg = <0xf0034000 0x4000>; + interrupts = <37 IRQ_TYPE_LEVEL_HIGH 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_isi_data_0_7>; + clocks = <&isi_clk>; + clock-names = "isi_clk"; + port { + isi_0: endpoint { + remote-endpoint = <&ov2640_0>; + bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; + }; + }; +}; + +i2c1: i2c@f0018000 { + ov2640: camera@30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioE 11 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioE 13 GPIO_ACTIVE_HIGH>; + clocks = <&pck0>; + clock-names = "xvclk"; + assigned-clocks = <&pck0>; + assigned-clock-rates = <25000000>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isi_0>; + bus-width = <8>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/camera b/arch/arm64/boot/dts/vendor/bindings/media/camera new file mode 120000 index 0000000000000000000000000000000000000000..11325bdb95b935c1dd742e3961a5f8056f62b380 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/camera @@ -0,0 +1 @@ +../../qcom/camera/bindings/ \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/media/cdns,csi2rx.txt b/arch/arm64/boot/dts/vendor/bindings/media/cdns,csi2rx.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b02a0657ad9794265e65539da57cc65c7e86242 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/cdns,csi2rx.txt @@ -0,0 +1,100 @@ +Cadence MIPI-CSI2 RX controller +=============================== + +The Cadence MIPI-CSI2 RX controller is a CSI-2 bridge supporting up to 4 CSI +lanes in input, and 4 different pixel streams in output. + +Required properties: + - compatible: must be set to "cdns,csi2rx" and an SoC-specific compatible + - reg: base address and size of the memory mapped region + - clocks: phandles to the clocks driving the controller + - clock-names: must contain: + * sys_clk: main clock + * p_clk: register bank clock + * pixel_if[0-3]_clk: pixel stream output clock, one for each stream + implemented in hardware, between 0 and 3 + +Optional properties: + - phys: phandle to the external D-PHY, phy-names must be provided + - phy-names: must contain "dphy", if the implementation uses an + external D-PHY + +Required subnodes: + - ports: A ports node with one port child node per device input and output + port, in accordance with the video interface bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + port nodes are numbered as follows: + + Port Description + ----------------------------- + 0 CSI-2 input + 1 Stream 0 output + 2 Stream 1 output + 3 Stream 2 output + 4 Stream 3 output + + The stream output port nodes are optional if they are not + connected to anything at the hardware level or implemented + in the design.Since there is only one endpoint per port, + the endpoints are not numbered. + + +Example: + +csi2rx: csi-bridge@0d060000 { + compatible = "cdns,csi2rx"; + reg = <0x0d060000 0x1000>; + clocks = <&byteclock>, <&byteclock> + <&coreclock>, <&coreclock>, + <&coreclock>, <&coreclock>; + clock-names = "sys_clk", "p_clk", + "pixel_if0_clk", "pixel_if1_clk", + "pixel_if2_clk", "pixel_if3_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + csi2rx_in_sensor: endpoint { + remote-endpoint = <&sensor_out_csi2rx>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + + port@1 { + reg = <1>; + + csi2rx_out_grabber0: endpoint { + remote-endpoint = <&grabber0_in_csi2rx>; + }; + }; + + port@2 { + reg = <2>; + + csi2rx_out_grabber1: endpoint { + remote-endpoint = <&grabber1_in_csi2rx>; + }; + }; + + port@3 { + reg = <3>; + + csi2rx_out_grabber2: endpoint { + remote-endpoint = <&grabber2_in_csi2rx>; + }; + }; + + port@4 { + reg = <4>; + + csi2rx_out_grabber3: endpoint { + remote-endpoint = <&grabber3_in_csi2rx>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/cdns,csi2tx.txt b/arch/arm64/boot/dts/vendor/bindings/media/cdns,csi2tx.txt new file mode 100644 index 0000000000000000000000000000000000000000..459c6e332f5290a9a746306041ab2a848286a0f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/cdns,csi2tx.txt @@ -0,0 +1,98 @@ +Cadence MIPI-CSI2 TX controller +=============================== + +The Cadence MIPI-CSI2 TX controller is a CSI-2 bridge supporting up to +4 CSI lanes in output, and up to 4 different pixel streams in input. + +Required properties: + - compatible: must be set to "cdns,csi2tx" + - reg: base address and size of the memory mapped region + - clocks: phandles to the clocks driving the controller + - clock-names: must contain: + * esc_clk: escape mode clock + * p_clk: register bank clock + * pixel_if[0-3]_clk: pixel stream output clock, one for each stream + implemented in hardware, between 0 and 3 + +Optional properties + - phys: phandle to the D-PHY. If it is set, phy-names need to be set + - phy-names: must contain "dphy" + +Required subnodes: + - ports: A ports node with one port child node per device input and output + port, in accordance with the video interface bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + port nodes are numbered as follows. + + Port Description + ----------------------------- + 0 CSI-2 output + 1 Stream 0 input + 2 Stream 1 input + 3 Stream 2 input + 4 Stream 3 input + + The stream input port nodes are optional if they are not + connected to anything at the hardware level or implemented + in the design. Since there is only one endpoint per port, + the endpoints are not numbered. + +Example: + +csi2tx: csi-bridge@0d0e1000 { + compatible = "cdns,csi2tx"; + reg = <0x0d0e1000 0x1000>; + clocks = <&byteclock>, <&byteclock>, + <&coreclock>, <&coreclock>, + <&coreclock>, <&coreclock>; + clock-names = "p_clk", "esc_clk", + "pixel_if0_clk", "pixel_if1_clk", + "pixel_if2_clk", "pixel_if3_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + csi2tx_out: endpoint { + remote-endpoint = <&remote_in>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + + port@1 { + reg = <1>; + + csi2tx_in_stream0: endpoint { + remote-endpoint = <&stream0_out>; + }; + }; + + port@2 { + reg = <2>; + + csi2tx_in_stream1: endpoint { + remote-endpoint = <&stream1_out>; + }; + }; + + port@3 { + reg = <3>; + + csi2tx_in_stream2: endpoint { + remote-endpoint = <&stream2_out>; + }; + }; + + port@4 { + reg = <4>; + + csi2tx_in_stream3: endpoint { + remote-endpoint = <&stream3_out>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/cec-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/media/cec-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..47e8d73d32a3450ddd281ad164e3b926c7b0c78a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/cec-gpio.txt @@ -0,0 +1,42 @@ +* HDMI CEC GPIO driver + +The HDMI CEC GPIO module supports CEC implementations where the CEC line +is hooked up to a pull-up GPIO line and - optionally - the HPD line is +hooked up to another GPIO line. + +Please note: the maximum voltage for the CEC line is 3.63V, for the HPD and +5V lines it is 5.3V. So you may need some sort of level conversion circuitry +when connecting them to a GPIO line. + +Required properties: + - compatible: value must be "cec-gpio". + - cec-gpios: gpio that the CEC line is connected to. The line should be + tagged as open drain. + +If the CEC line is associated with an HDMI receiver/transmitter, then the +following property is also required: + + - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. + +If the CEC line is not associated with an HDMI receiver/transmitter, then +the following property is optional and can be used for debugging HPD changes: + + - hpd-gpios: gpio that the HPD line is connected to. + +This property is optional and can be used for debugging changes on the 5V line: + + - v5-gpios: gpio that the 5V line is connected to. + +Example for the Raspberry Pi 3 where the CEC line is connected to +pin 26 aka BCM7 aka CE1 on the GPIO pin header, the HPD line is +connected to pin 11 aka BCM17 and the 5V line is connected to pin +15 aka BCM22 (some level shifter is needed for the HPD and 5V lines!): + +#include + +cec-gpio { + compatible = "cec-gpio"; + cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + v5-gpios = <&gpio 22 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/cec.txt b/arch/arm64/boot/dts/vendor/bindings/media/cec.txt new file mode 100644 index 0000000000000000000000000000000000000000..22d7aae3d3d74c8f5c2c51388dd4f6092f568d6e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/cec.txt @@ -0,0 +1,8 @@ +Common bindings for HDMI CEC adapters + +- hdmi-phandle: phandle to the HDMI controller. + +- needs-hpd: if present the CEC support is only available when the HPD + is high. Some boards only let the CEC pin through if the HPD is high, + for example if there is a level converter that uses the HPD to power + up or down. diff --git a/arch/arm64/boot/dts/vendor/bindings/media/coda.txt b/arch/arm64/boot/dts/vendor/bindings/media/coda.txt new file mode 100644 index 0000000000000000000000000000000000000000..90eb74cc1993f794e5e991475eb69468bd8e1ec5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/coda.txt @@ -0,0 +1,31 @@ +Chips&Media Coda multi-standard codec IP +======================================== + +Coda codec IPs are present in i.MX SoCs in various versions, +called VPU (Video Processing Unit). + +Required properties: +- compatible : should be "fsl,-src" for i.MX SoCs: + (a) "fsl,imx27-vpu" for CodaDx6 present in i.MX27 + (b) "fsl,imx51-vpu" for CodaHx4 present in i.MX51 + (c) "fsl,imx53-vpu" for CODA7541 present in i.MX53 + (d) "fsl,imx6q-vpu" for CODA960 present in i.MX6q +- reg: should be register base and length as documented in the + SoC reference manual +- interrupts : Should contain the VPU interrupt. For CODA960, + a second interrupt is needed for the MJPEG unit. +- clocks : Should contain the ahb and per clocks, in the order + determined by the clock-names property. +- clock-names : Should be "ahb", "per" +- iram : phandle pointing to the SRAM device node + +Example: + +vpu: vpu@63ff4000 { + compatible = "fsl,imx53-vpu"; + reg = <0x63ff4000 0x1000>; + interrupts = <9>; + clocks = <&clks 63>, <&clks 63>; + clock-names = "ahb", "per"; + iram = <&ocram>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/exynos-fimc-lite.txt b/arch/arm64/boot/dts/vendor/bindings/media/exynos-fimc-lite.txt new file mode 100644 index 0000000000000000000000000000000000000000..0bf6fb7fbeabcbd4c4d14933c2b331f7fa9daa2d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/exynos-fimc-lite.txt @@ -0,0 +1,16 @@ +Exynos4x12/Exynos5 SoC series camera host interface (FIMC-LITE) + +Required properties: + +- compatible : should be one of: + "samsung,exynos4212-fimc-lite" for Exynos4212/4412 SoCs, + "samsung,exynos5250-fimc-lite" for Exynos5250 compatible + devices; +- reg : physical base address and size of the device memory mapped + registers; +- interrupts : should contain FIMC-LITE interrupt; +- clocks : FIMC LITE gate clock should be specified in this property. +- clock-names : should contain "flite" entry. + +Each FIMC device should have an alias in the aliases node, in the form of +fimc-lite, where is an integer specifying the IP block instance. diff --git a/arch/arm64/boot/dts/vendor/bindings/media/exynos-jpeg-codec.txt b/arch/arm64/boot/dts/vendor/bindings/media/exynos-jpeg-codec.txt new file mode 100644 index 0000000000000000000000000000000000000000..38941db23dd2435e97f085633cfeb298cf6a030f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/exynos-jpeg-codec.txt @@ -0,0 +1,16 @@ +Samsung S5P/EXYNOS SoC series JPEG codec + +Required properties: + +- compatible : should be one of: + "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg", + "samsung,exynos3250-jpeg", "samsung,exynos5420-jpeg", + "samsung,exynos5433-jpeg"; +- reg : address and length of the JPEG codec IP register set; +- interrupts : specifies the JPEG codec IP interrupt; +- clock-names : should contain: + - "jpeg" for the core gate clock, + - "sclk" for the special clock (optional). +- clocks : should contain the clock specifier and clock ID list + matching entries in the clock-names property; from + the common clock bindings. diff --git a/arch/arm64/boot/dts/vendor/bindings/media/exynos4-fimc-is.txt b/arch/arm64/boot/dts/vendor/bindings/media/exynos4-fimc-is.txt new file mode 100644 index 0000000000000000000000000000000000000000..32ced99d4244d6f8cc3d324fca50a790ed504500 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/exynos4-fimc-is.txt @@ -0,0 +1,50 @@ +Exynos4x12 SoC series Imaging Subsystem (FIMC-IS) + +The FIMC-IS is a subsystem for processing image signal from an image sensor. +The Exynos4x12 SoC series FIMC-IS V1.5 comprises of a dedicated ARM Cortex-A5 +processor, ISP, DRC and FD IP blocks and peripheral devices such as UART, I2C +and SPI bus controllers, PWM and ADC. + +fimc-is node +------------ + +Required properties: +- compatible : should be "samsung,exynos4212-fimc-is" for Exynos4212 and + Exynos4412 SoCs; +- reg : physical base address and length of the registers set; +- interrupts : must contain two FIMC-IS interrupts, in order: ISP0, ISP1; +- clocks : list of clock specifiers, corresponding to entries in + clock-names property; +- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1" + "mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "gicisp", + "pwm_isp", "mcuctl_isp", "uart", "ispdiv0", "ispdiv1", + "mcuispdiv0", "mcuispdiv1", "aclk200", "div_aclk200", + "aclk400mcuisp", "div_aclk400mcuisp" entries, + matching entries in the clocks property. +pmu subnode +----------- + +Required properties: + - reg : must contain PMU physical base address and size of the register set. + +The following are the FIMC-IS peripheral device nodes and can be specified +either standalone or as the fimc-is node child nodes. + +i2c-isp (ISP I2C bus controller) nodes +------------------------------------------ + +Required properties: + +- compatible : should be "samsung,exynos4212-i2c-isp" for Exynos4212 and + Exynos4412 SoCs; +- reg : physical base address and length of the registers set; +- clocks : must contain gate clock specifier for this controller; +- clock-names : must contain "i2c_isp" entry. + +For the above nodes it is required to specify a pinctrl state named "default", +according to the pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt. + +Device tree nodes of the image sensors' controlled directly by the FIMC-IS +firmware must be child nodes of their corresponding ISP I2C bus controller node. +The data link of these image sensors must be specified using the common video +interfaces bindings, defined in video-interfaces.txt. diff --git a/arch/arm64/boot/dts/vendor/bindings/media/exynos5-gsc.txt b/arch/arm64/boot/dts/vendor/bindings/media/exynos5-gsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc963a6d305a8bbc0e0ca2a231eea89d3247087c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/exynos5-gsc.txt @@ -0,0 +1,38 @@ +* Samsung Exynos5 G-Scaler device + +G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs. + +Required properties: +- compatible: should be one of + "samsung,exynos5250-gsc" + "samsung,exynos5420-gsc" + "samsung,exynos5433-gsc" + "samsung,exynos5-gsc" (deprecated) +- reg: should contain G-Scaler physical address location and length. +- interrupts: should contain G-Scaler interrupt number + +Optional properties: +- samsung,sysreg: handle to syscon used to control the system registers to + set writeback input and destination + +Example: + +gsc_0: gsc@13e00000 { + compatible = "samsung,exynos5250-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; +}; + +Aliases: +Each G-Scaler node should have a numbered alias in the aliases node, +in the form of gscN, N = 0...3. G-Scaler driver uses these aliases +to retrieve the device IDs using "of_alias_get_id()" call. + +Example: + +aliases { + gsc0 =&gsc_0; + gsc1 =&gsc_1; + gsc2 =&gsc_2; + gsc3 =&gsc_3; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/fsl-vdoa.txt b/arch/arm64/boot/dts/vendor/bindings/media/fsl-vdoa.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c5628530bb7bef687b1268ff78fd8dfd2a904ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/fsl-vdoa.txt @@ -0,0 +1,21 @@ +Freescale Video Data Order Adapter +================================== + +The Video Data Order Adapter (VDOA) is present on the i.MX6q. Its sole purpose +is to reorder video data from the macroblock tiled order produced by the CODA +960 VPU to the conventional raster-scan order for scanout. + +Required properties: +- compatible: must be "fsl,imx6q-vdoa" +- reg: the register base and size for the device registers +- interrupts: the VDOA interrupt +- clocks: the vdoa clock + +Example: + +vdoa@21e4000 { + compatible = "fsl,imx6q-vdoa"; + reg = <0x021e4000 0x4000>; + interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_VDOA>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/gpio-ir-receiver.txt b/arch/arm64/boot/dts/vendor/bindings/media/gpio-ir-receiver.txt new file mode 100644 index 0000000000000000000000000000000000000000..58261fb7b408981d709832eadf9c28282a67a822 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/gpio-ir-receiver.txt @@ -0,0 +1,17 @@ +Device-Tree bindings for GPIO IR receiver + +Required properties: + - compatible: should be "gpio-ir-receiver". + - gpios: specifies GPIO used for IR signal reception. + +Optional properties: + - linux,rc-map-name: see rc.txt file in the same + directory. + +Example node: + + ir: ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio0 19 1>; + linux,rc-map-name = "rc-rc6-mce"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/hix5hd2-ir.txt b/arch/arm64/boot/dts/vendor/bindings/media/hix5hd2-ir.txt new file mode 100644 index 0000000000000000000000000000000000000000..13ebc0fac9ea2faaae8b19b75e494ffa0950ede4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/hix5hd2-ir.txt @@ -0,0 +1,25 @@ +Device-Tree bindings for hix5hd2 ir IP + +Required properties: + - compatible: Should contain "hisilicon,hix5hd2-ir". + - reg: Base physical address of the controller and length of memory + mapped region. + - interrupts: interrupt-specifier for the sole interrupt generated by + the device. The interrupt specifier format depends on the interrupt + controller parent. + - clocks: clock phandle and specifier pair. + +Optional properties: + - linux,rc-map-name: see rc.txt file in the same directory. + - hisilicon,power-syscon: DEPRECATED. Don't use this in new dts files. + Provide correct clocks instead. + +Example node: + + ir: ir@f8001000 { + compatible = "hisilicon,hix5hd2-ir"; + reg = <0xf8001000 0x1000>; + interrupts = <0 47 4>; + clocks = <&clock HIX5HD2_IR_CLOCK>; + linux,rc-map-name = "rc-tivo"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ad5820.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ad5820.txt new file mode 100644 index 0000000000000000000000000000000000000000..5940ca11c021e6c86bd30387037673f0550989a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ad5820.txt @@ -0,0 +1,19 @@ +* Analog Devices AD5820 autofocus coil + +Required Properties: + + - compatible: Must contain "adi,ad5820" + + - reg: I2C slave address + + - VANA-supply: supply of voltage for VANA pin + +Example: + + ad5820: coil@c { + compatible = "adi,ad5820"; + reg = <0x0c>; + + VANA-supply = <&vaux4>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/adp1653.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adp1653.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cce0de40ee9208566a917b71400b7a7d7482725 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adp1653.txt @@ -0,0 +1,38 @@ +* Analog Devices ADP1653 flash LED driver + +Required Properties: + + - compatible: Must contain "adi,adp1653" + + - reg: I2C slave address + + - enable-gpios: Specifier of the GPIO connected to EN pin + +There are two LED outputs available - flash and indicator. One LED is +represented by one child node, nodes need to be named "flash" and "indicator". + +Required properties of the LED child node: +- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt + +Required properties of the flash LED child node: + +- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt +- flash-timeout-us : see Documentation/devicetree/bindings/leds/common.txt +- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt + +Example: + + adp1653: led-controller@30 { + compatible = "adi,adp1653"; + reg = <0x30>; + enable-gpios = <&gpio3 24 GPIO_ACTIVE_HIGH>; /* 88 */ + + flash { + flash-timeout-us = <500000>; + flash-max-microamp = <320000>; + led-max-microamp = <50000>; + }; + indicator { + led-max-microamp = <17500>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7180.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7180.txt new file mode 100644 index 0000000000000000000000000000000000000000..552b6a82cb1f0ed42090ba4ede1498303e36d3ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7180.txt @@ -0,0 +1,49 @@ +* Analog Devices ADV7180 analog video decoder family + +The adv7180 family devices are used to capture analog video to different +digital interfaces like MIPI CSI-2 or parallel video. + +Required Properties : +- compatible : value must be one of + "adi,adv7180" + "adi,adv7180cp" + "adi,adv7180st" + "adi,adv7182" + "adi,adv7280" + "adi,adv7280-m" + "adi,adv7281" + "adi,adv7281-m" + "adi,adv7281-ma" + "adi,adv7282" + "adi,adv7282-m" + +Device nodes of "adi,adv7180cp" and "adi,adv7180st" must contain one +'port' child node per device input and output port, in accordance with the +video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. The port +nodes are numbered as follows. + + Port adv7180cp adv7180st +------------------------------------------------------------------- + Input 0-2 0-5 + Output 3 6 + +The digital output port node must contain at least one endpoint. + +Optional Properties : +- powerdown-gpios: reference to the GPIO connected to the powerdown pin, + if any. + + +Example: + + i2c0@1c22000 { + ... + ... + adv7180@21 { + compatible = "adi,adv7180"; + reg = <0x21>; + }; + ... + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7343.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7343.txt new file mode 100644 index 0000000000000000000000000000000000000000..5653bc2428b897ebcfa84fca31df15146a096966 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7343.txt @@ -0,0 +1,48 @@ +* Analog Devices adv7343 video encoder + +The ADV7343 are high speed, digital-to-analog video encoders in a 64-lead LQFP +package. Six high speed, 3.3 V, 11-bit video DACs provide support for composite +(CVBS), S-Video (Y-C), and component (YPrPb/RGB) analog outputs in standard +definition (SD), enhanced definition (ED), or high definition (HD) video +formats. + +Required Properties : +- compatible: Must be "adi,adv7343" + +Optional Properties : +- adi,power-mode-sleep-mode: on enable the current consumption is reduced to + micro ampere level. All DACs and the internal PLL + circuit are disabled. +- adi,power-mode-pll-ctrl: PLL and oversampling control. This control allows + internal PLL 1 circuit to be powered down and the + oversampling to be switched off. +- ad,adv7343-power-mode-dac: array configuring the power on/off DAC's 1..6, + 0 = OFF and 1 = ON, Default value when this + property is not specified is <0 0 0 0 0 0>. +- ad,adv7343-sd-config-dac-out: array configure SD DAC Output's 1 and 2, 0 = OFF + and 1 = ON, Default value when this property is + not specified is <0 0>. + +Example: + +i2c0@1c22000 { + ... + ... + + adv7343@2a { + compatible = "adi,adv7343"; + reg = <0x2a>; + + port { + adv7343_1: endpoint { + adi,power-mode-sleep-mode; + adi,power-mode-pll-ctrl; + /* Use DAC1..3, DAC6 */ + adi,dac-enable = <1 1 1 0 0 1>; + /* Use SD DAC output 1 */ + adi,sd-dac-enable = <1 0>; + }; + }; + }; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv748x.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv748x.txt new file mode 100644 index 0000000000000000000000000000000000000000..21ffb5ed818302ff4fb709a213aebfc1d4980b1f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv748x.txt @@ -0,0 +1,95 @@ +* Analog Devices ADV748X video decoder with HDMI receiver + +The ADV7481 and ADV7482 are multi format video decoders with an integrated +HDMI receiver. They can output CSI-2 on two independent outputs TXA and TXB +from three input sources HDMI, analog and TTL. + +Required Properties: + + - compatible: Must contain one of the following + - "adi,adv7481" for the ADV7481 + - "adi,adv7482" for the ADV7482 + + - reg: I2C slave address + +Optional Properties: + + - interrupt-names: Should specify the interrupts as "intrq1", "intrq2" and/or + "intrq3". All interrupts are optional. The "intrq3" interrupt + is only available on the adv7481 + - interrupts: Specify the interrupt lines for the ADV748x + +The device node must contain one 'port' child node per device input and output +port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes +are numbered as follows. + + Name Type Port + --------------------------------------- + AIN0 sink 0 + AIN1 sink 1 + AIN2 sink 2 + AIN3 sink 3 + AIN4 sink 4 + AIN5 sink 5 + AIN6 sink 6 + AIN7 sink 7 + HDMI sink 8 + TTL sink 9 + TXA source 10 + TXB source 11 + +The digital output port nodes must contain at least one endpoint. + +Ports are optional if they are not connected to anything at the hardware level. + +Example: + + video-receiver@70 { + compatible = "adi,adv7482"; + reg = <0x70>; + + #address-cells = <1>; + #size-cells = <0>; + + interrupt-parent = <&gpio6>; + interrupt-names = "intrq1", "intrq2"; + interrupts = <30 IRQ_TYPE_LEVEL_LOW>, + <31 IRQ_TYPE_LEVEL_LOW>; + + port@7 { + reg = <7>; + + adv7482_ain7: endpoint { + remote-endpoint = <&cvbs_in>; + }; + }; + + port@8 { + reg = <8>; + + adv7482_hdmi: endpoint { + remote-endpoint = <&hdmi_in>; + }; + }; + + port@10 { + reg = <10>; + + adv7482_txa: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + remote-endpoint = <&csi40_in>; + }; + }; + + port@11 { + reg = <11>; + + adv7482_txb: endpoint { + clock-lanes = <0>; + data-lanes = <1>; + remote-endpoint = <&csi20_in>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7604.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7604.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcf57e7c60eba95b701dd929d1698e198953fbf6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/adv7604.txt @@ -0,0 +1,88 @@ +* Analog Devices ADV7604/11/12 video decoder with HDMI receiver + +The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated +HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog +input, and the ADV7611 has one HDMI input and no analog input. The 7612 is +similar to the 7611 but has 2 HDMI inputs. + +These device tree bindings support the ADV7611/12 only at the moment. + +Required Properties: + + - compatible: Must contain one of the following + - "adi,adv7611" for the ADV7611 + - "adi,adv7612" for the ADV7612 + + - reg: I2C slave addresses + The ADV76xx has up to thirteen 256-byte maps that can be accessed via the + main I2C ports. Each map has it own I2C address and acts as a standard + slave device on the I2C bus. The main address is mandatory, others are + optional and revert to defaults if not specified. + + - hpd-gpios: References to the GPIOs that control the HDMI hot-plug + detection pins, one per HDMI input. The active flag indicates the GPIO + level that enables hot-plug detection. + +The device node must contain one 'port' child node per device input and output +port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes +are numbered as follows. + + Port ADV7611 ADV7612 +------------------------------------------------------------ + HDMI 0 0, 1 + Digital output 1 2 + +The digital output port node must contain at least one endpoint. + +Optional Properties: + + - reset-gpios: Reference to the GPIO connected to the device's reset pin. + - default-input: Select which input is selected after reset. + - reg-names : Names of maps with programmable addresses. + It can contain any map needing a non-default address. + Possible maps names are : + "main", "avlink", "cec", "infoframe", "esdp", "dpp", "afe", + "rep", "edid", "hdmi", "test", "cp", "vdp" + +Optional Endpoint Properties: + + The following three properties are defined in video-interfaces.txt and are + valid for source endpoints only. + + - hsync-active: Horizontal synchronization polarity. Defaults to active low. + - vsync-active: Vertical synchronization polarity. Defaults to active low. + - pclk-sample: Pixel clock polarity. Defaults to output on the falling edge. + + If none of hsync-active, vsync-active and pclk-sample is specified the + endpoint will use embedded BT.656 synchronization. + +Example: + + hdmi_receiver@4c { + compatible = "adi,adv7611"; + /* + * The edid page will be accessible @ 0x66 on the I2C bus. All + * other maps will retain their default addresses. + */ + reg = <0x4c>, <0x66>; + reg-names "main", "edid"; + + reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; + hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; + + #address-cells = <1>; + #size-cells = <0>; + + default-input = <0>; + + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + hdmi_in: endpoint { + remote-endpoint = <&ccdc_in>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ak7375.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ak7375.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa3e24b412410488a06705ef13dadeeef844717e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ak7375.txt @@ -0,0 +1,8 @@ +Asahi Kasei Microdevices AK7375 voice coil lens driver + +AK7375 is a camera voice coil lens. + +Mandatory properties: + +- compatible: "asahi-kasei,ak7375" +- reg: I2C slave address diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/aptina,mt9v111.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/aptina,mt9v111.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd896e9f67d1785aee250fc8d98e6aef3379a506 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/aptina,mt9v111.txt @@ -0,0 +1,46 @@ +* Aptina MT9V111 CMOS sensor +---------------------------- + +The Aptina MT9V111 is a 1/4-Inch VGA-format digital image sensor with a core +based on Aptina MT9V011 sensor and an integrated Image Flow Processor (IFP). + +The sensor has an active pixel array of 640x480 pixels and can output a number +of image resolution and formats controllable through a simple two-wires +interface. + +Required properties: +-------------------- + +- compatible: shall be "aptina,mt9v111". +- clocks: reference to the system clock input provider. + +Optional properties: +-------------------- + +- enable-gpios: output enable signal, pin name "OE#". Active low. +- standby-gpios: low power state control signal, pin name "STANDBY". + Active high. +- reset-gpios: chip reset signal, pin name "RESET#". Active low. + +The device node must contain one 'port' child node with one 'endpoint' child +sub-node for its digital output video port, in accordance with the video +interface bindings defined in: +Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: +-------- + + &i2c1 { + camera@48 { + compatible = "aptina,mt9v111"; + reg = <0x48>; + + clocks = <&camera_clk>; + + port { + mt9v111_out: endpoint { + remote-endpoint = <&ceu_in>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/dongwoon,dw9714.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/dongwoon,dw9714.txt new file mode 100644 index 0000000000000000000000000000000000000000..b88dcdd41def013f1710371eb5a6c41ed357caa8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/dongwoon,dw9714.txt @@ -0,0 +1,9 @@ +Dongwoon Anatech DW9714 camera voice coil lens driver + +DW9174 is a 10-bit DAC with current sink capability. It is intended +for driving voice coil lenses in camera modules. + +Mandatory properties: + +- compatible: "dongwoon,dw9714" +- reg: I²C slave address diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/dongwoon,dw9807.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/dongwoon,dw9807.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4701f1eaaf6313db2375599b188327cacf6ddc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/dongwoon,dw9807.txt @@ -0,0 +1,9 @@ +Dongwoon Anatech DW9807 voice coil lens driver + +DW9807 is a 10-bit DAC with current sink capability. It is intended for +controlling voice coil lenses. + +Mandatory properties: + +- compatible: "dongwoon,dw9807-vcm" +- reg: I2C slave address diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/imx274.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/imx274.txt new file mode 100644 index 0000000000000000000000000000000000000000..80f2e89568e10153a03ae8cc595eb449a4dc4fd9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/imx274.txt @@ -0,0 +1,33 @@ +* Sony 1/2.5-Inch 8.51Mp CMOS Digital Image Sensor + +The Sony imx274 is a 1/2.5-inch CMOS active pixel digital image sensor with +an active array size of 3864H x 2202V. 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 4 lanes +at 1440 Mbps. + + +Required Properties: +- compatible: value should be "sony,imx274" for imx274 sensor +- reg: I2C bus address of the device + +Optional Properties: +- reset-gpios: Sensor reset GPIO + +The imx274 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. + +Example: + sensor@1a { + compatible = "sony,imx274"; + reg = <0x1a>; + #address-cells = <1>; + #size-cells = <0>; + reset-gpios = <&gpio_sensor 0 0>; + port { + sensor_out: endpoint { + remote-endpoint = <&csiss_in>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/max2175.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/max2175.txt new file mode 100644 index 0000000000000000000000000000000000000000..02b4e9cd7b1bcc6e05f6f81dcdd74fa787cf5cae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/max2175.txt @@ -0,0 +1,59 @@ +Maxim Integrated MAX2175 RF to Bits tuner +----------------------------------------- + +The MAX2175 IC is an advanced analog/digital hybrid-radio receiver with +RF to Bits® front-end designed for software-defined radio solutions. + +Required properties: +-------------------- +- compatible: "maxim,max2175" for MAX2175 RF-to-bits tuner. +- clocks: clock specifier. +- port: child port node corresponding to the I2S output, in accordance with + the video interface bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The port + node must contain at least one endpoint. + +Optional properties: +-------------------- +- maxim,master : phandle to the master tuner if it is a slave. This + is used to define two tuners in diversity mode + (1 master, 1 slave). By default each tuner is an + individual master. +- maxim,refout-load : load capacitance value (in picofarads) on reference + output drive level. The possible load values are: + 0 (default - refout disabled) + 10 + 20 + 30 + 40 + 60 + 70 +- maxim,am-hiz-filter : empty property indicates the AM Hi-Z filter is used + in this hardware for AM antenna input. + +Example: +-------- + +Board specific DTS file + +/* Fixed XTAL clock node */ +maxim_xtal: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <36864000>; +}; + +/* A tuner device instance under i2c bus */ +max2175_0: tuner@60 { + compatible = "maxim,max2175"; + reg = <0x60>; + clocks = <&maxim_xtal>; + maxim,refout-load = <10>; + + port { + max2175_0_ep: endpoint { + remote-endpoint = <&slave_rx_device>; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9m111.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9m111.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b910036b57e9303df805e23f7389d1a86c44f19 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9m111.txt @@ -0,0 +1,32 @@ +Micron 1.3Mp CMOS Digital Image Sensor + +The Micron MT9M111 is a CMOS active pixel digital image sensor with an active +array size of 1280H x 1024V. It is programmable through a simple two-wire serial +interface. + +Required Properties: +- compatible: value should be "micron,mt9m111" +- clocks: reference to the master clock. +- clock-names: shall be "mclk". + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c_master { + mt9m111@5d { + compatible = "micron,mt9m111"; + reg = <0x5d>; + clocks = <&mclk>; + clock-names = "mclk"; + + remote = <&pxa_camera>; + port { + mt9m111_1: endpoint { + bus-width = <8>; + remote-endpoint = <&pxa_camera>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9p031.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9p031.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb60443ff78fa7d50e4d6a4abb4fec4b4265f4bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9p031.txt @@ -0,0 +1,40 @@ +* Aptina 1/2.5-Inch 5Mp CMOS Digital Image Sensor + +The Aptina MT9P031 is a 1/2.5-inch CMOS active pixel digital image sensor with +an active array size of 2592H x 1944V. It is programmable through a simple +two-wire serial interface. + +Required Properties: +- compatible: value should be either one among the following + (a) "aptina,mt9p031" for mt9p031 sensor + (b) "aptina,mt9p031m" for mt9p031m sensor + +- input-clock-frequency: Input clock frequency. + +- pixel-clock-frequency: Pixel clock frequency. + +Optional Properties: +- reset-gpios: Chip reset GPIO + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c0@1c22000 { + ... + ... + mt9p031@5d { + compatible = "aptina,mt9p031"; + reg = <0x5d>; + reset-gpios = <&gpio3 30 0>; + + port { + mt9p031_1: endpoint { + input-clock-frequency = <6000000>; + pixel-clock-frequency = <96000000>; + }; + }; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9v032.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9v032.txt new file mode 100644 index 0000000000000000000000000000000000000000..100f0ae432691c36ff54609c86a8cc984b9a5b7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/mt9v032.txt @@ -0,0 +1,41 @@ +* Aptina 1/3-Inch WVGA CMOS Digital Image Sensor + +The Aptina MT9V032 is a 1/3-inch CMOS active pixel digital image sensor with +an active array size of 752H x 480V. It is programmable through a simple +two-wire serial interface. + +Required Properties: + +- compatible: value should be either one among the following + (a) "aptina,mt9v022" for MT9V022 color sensor + (b) "aptina,mt9v022m" for MT9V022 monochrome sensor + (c) "aptina,mt9v024" for MT9V024 color sensor + (d) "aptina,mt9v024m" for MT9V024 monochrome sensor + (e) "aptina,mt9v032" for MT9V032 color sensor + (f) "aptina,mt9v032m" for MT9V032 monochrome sensor + (g) "aptina,mt9v034" for MT9V034 color sensor + (h) "aptina,mt9v034m" for MT9V034 monochrome sensor + +Optional Properties: + +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is + expressed as a 64-bit big-endian integer. +- reset-gpios: GPIO handle which is connected to the reset pin of the chip. +- standby-gpios: GPIO handle which is connected to the standby pin of the chip. + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + mt9v032@5c { + compatible = "aptina,mt9v032"; + reg = <0x5c>; + + port { + mt9v032_out: endpoint { + link-frequencies = /bits/ 64 + <13000000 26600000 27000000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/nokia,smia.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/nokia,smia.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ee7c7972ac79754152cb927854d0c9ce72f0738 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/nokia,smia.txt @@ -0,0 +1,68 @@ +SMIA/SMIA++ sensor + +SMIA (Standard Mobile Imaging Architecture) is an image sensor standard +defined jointly by Nokia and ST. SMIA++, defined by Nokia, is an extension +of that. These definitions are valid for both types of sensors. + +More detailed documentation can be found in +Documentation/devicetree/bindings/media/video-interfaces.txt . + + +Mandatory properties +-------------------- + +- compatible: "nokia,smia" +- reg: I2C address (0x10, or an alternative address) +- vana-supply: Analogue voltage supply (VANA), typically 2,8 volts (sensor + dependent). +- clocks: External clock to the sensor +- clock-frequency: Frequency of the external clock to the sensor +- link-frequencies: List of allowed data link frequencies. An array of + 64-bit elements. + + +Optional properties +------------------- + +- nokia,nvm-size: The size of the NVM, in bytes. If the size is not given, + the NVM contents will not be read. +- reset-gpios: XSHUTDOWN GPIO +- flash-leds: See ../video-interfaces.txt +- lens-focus: See ../video-interfaces.txt +- rotation: Integer property; valid values are 0 (sensor mounted upright) + and 180 (sensor mounted upside down). See + ../video-interfaces.txt . + + +Endpoint node mandatory properties +---------------------------------- + +- clock-lanes: <0> +- data-lanes: <1..n> +- remote-endpoint: A phandle to the bus receiver's endpoint node. + + +Example +------- + +&i2c2 { + clock-frequency = <400000>; + + smiapp_1: camera@10 { + compatible = "nokia,smia"; + reg = <0x10>; + reset-gpios = <&gpio3 20 0>; + vana-supply = <&vaux3>; + clocks = <&omap3_isp 0>; + clock-frequency = <9600000>; + nokia,nvm-size = <512>; /* 8 * 64 */ + link-frequencies = /bits/ 64 <199200000 210000000 499200000>; + port { + smiapp_1_1: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&csi2a_ep>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2640.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2640.txt new file mode 100644 index 0000000000000000000000000000000000000000..989ce6cb6ac30489df01c8008ef0181e5e7bc637 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2640.txt @@ -0,0 +1,41 @@ +* Omnivision OV2640 CMOS sensor + +The Omnivision OV2640 sensor supports multiple resolutions output, such as +CIF, SVGA, UXGA. It also can support the YUV422/420, RGB565/555 or raw RGB +output formats. + +Required Properties: +- compatible: should be "ovti,ov2640" +- clocks: reference to the xvclk input clock. +- clock-names: should be "xvclk". + +Optional Properties: +- resetb-gpios: reference to the GPIO connected to the resetb pin, if any. +- pwdn-gpios: reference to the GPIO connected to the pwdn pin, if any. + +The device node must contain one 'port' child node for its digital output +video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c1: i2c@f0018000 { + ov2640: camera@30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioE 11 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioE 13 GPIO_ACTIVE_HIGH>; + clocks = <&pck0>; + clock-names = "xvclk"; + assigned-clocks = <&pck0>; + assigned-clock-rates = <25000000>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isi_0>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2659.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2659.txt new file mode 100644 index 0000000000000000000000000000000000000000..cabc7d827dfbc3a08f5c03e55c2228b584995f43 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2659.txt @@ -0,0 +1,38 @@ +* OV2659 1/5-Inch 2Mp SOC Camera + +The Omnivision OV2659 is a 1/5-inch SOC camera, with an active array size of +1632H x 1212V. It is programmable through a SCCB. The OV2659 sensor supports +multiple resolutions output, such as UXGA, SVGA, 720p. It also can support +YUV422, RGB565/555 or raw RGB output formats. + +Required Properties: +- compatible: Must be "ovti,ov2659" +- reg: I2C slave address +- clocks: reference to the xvclk input clock. +- clock-names: should be "xvclk". +- link-frequencies: target pixel clock frequency. + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c0@1c22000 { + ... + ... + ov2659@30 { + compatible = "ovti,ov2659"; + reg = <0x30>; + + clocks = <&clk_ov2659 0>; + clock-names = "xvclk"; + + port { + ov2659_0: endpoint { + remote-endpoint = <&vpfe_ep>; + link-frequencies = /bits/ 64 <70000000>; + }; + }; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2680.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2680.txt new file mode 100644 index 0000000000000000000000000000000000000000..11e925ed9dad82f3227645e08bc88d90089ce11e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2680.txt @@ -0,0 +1,46 @@ +* Omnivision OV2680 MIPI CSI-2 sensor + +Required Properties: +- compatible: should be "ovti,ov2680". +- clocks: reference to the xvclk input clock. +- clock-names: should be "xvclk". +- DOVDD-supply: Digital I/O voltage supply. +- DVDD-supply: Digital core voltage supply. +- AVDD-supply: Analog voltage supply. + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the powerdown/reset pin, + if any. This is an active low signal to the OV2680. + +The device node must contain one 'port' child node for its digital output +video port, and this port must have a single endpoint in accordance with + the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Endpoint node required properties for CSI-2 connection are: +- remote-endpoint: a phandle to the bus receiver's endpoint node. +- clock-lanes: should be set to <0> (clock lane on hardware lane 0). +- data-lanes: should be set to <1> (one CSI-2 lane supported). + +Example: + +&i2c2 { + ov2680: camera-sensor@36 { + compatible = "ovti,ov2680"; + reg = <0x36>; + clocks = <&osc>; + clock-names = "xvclk"; + reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>; + DOVDD-supply = <&sw2_reg>; + DVDD-supply = <&sw2_reg>; + AVDD-supply = <®_peri_3p15v>; + + port { + ov2680_to_mipi: endpoint { + remote-endpoint = <&mipi_from_sensor>; + clock-lanes = <0>; + data-lanes = <1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2685.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2685.txt new file mode 100644 index 0000000000000000000000000000000000000000..625c4a8c0d53de24679e58ba1bd5365e4785b933 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov2685.txt @@ -0,0 +1,41 @@ +* Omnivision OV2685 MIPI CSI-2 sensor + +Required Properties: +- compatible: shall be "ovti,ov2685" +- clocks: reference to the xvclk input clock +- clock-names: shall be "xvclk" +- avdd-supply: Analog voltage supply, 2.8 volts +- dovdd-supply: Digital I/O voltage supply, 1.8 volts +- dvdd-supply: Digital core voltage supply, 1.8 volts +- reset-gpios: Low active reset gpio + +The device node shall contain one 'port' child node with an +'endpoint' subnode for its digital output video port, +in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. +The endpoint optional property 'data-lanes' shall be "<1>". + +Example: +&i2c7 { + ov2685: camera-sensor@3c { + compatible = "ovti,ov2685"; + reg = <0x3c>; + pinctrl-names = "default"; + pinctrl-0 = <&clk_24m_cam>; + + clocks = <&cru SCLK_TESTCLKOUT1>; + clock-names = "xvclk"; + + avdd-supply = <&pp2800_cam>; + dovdd-supply = <&pp1800>; + dvdd-supply = <&pp1800>; + reset-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; + + port { + ucam_out: endpoint { + remote-endpoint = <&mipi_in_ucam>; + data-lanes = <1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5640.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5640.txt new file mode 100644 index 0000000000000000000000000000000000000000..c97c2f2da12d779857db8c1bfdf82a2a7bd17b8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5640.txt @@ -0,0 +1,92 @@ +* Omnivision OV5640 MIPI CSI-2 / parallel sensor + +Required Properties: +- compatible: should be "ovti,ov5640" +- 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.5 volts + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the reset pin, if any. + This is an active low signal to the OV5640. +- powerdown-gpios: reference to the GPIO connected to the powerdown pin, + if any. This is an active high signal to the OV5640. +- rotation: as defined in + Documentation/devicetree/bindings/media/video-interfaces.txt, + valid values are 0 (sensor mounted upright) and 180 (sensor + mounted upside down). + +The device node must contain one 'port' child node for its digital output +video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +OV5640 can be connected to a MIPI CSI-2 bus or a parallel bus endpoint. + +Endpoint node required properties for CSI-2 connection are: +- remote-endpoint: a phandle to the bus receiver's endpoint node. +- clock-lanes: should be set to <0> (clock lane on hardware lane 0) +- data-lanes: should be set to <1> or <1 2> (one or two CSI-2 lanes supported) + +Endpoint node required properties for parallel connection are: +- remote-endpoint: a phandle to the bus receiver's endpoint node. +- bus-width: shall be set to <8> for 8 bits parallel bus + or <10> for 10 bits parallel bus +- data-shift: shall be set to <2> for 8 bits parallel bus + (lines 9:2 are used) or <0> for 10 bits parallel bus +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. +- pclk-sample: sample data on rising (1) or falling (0) edge of the pixel clock + signal. + +Examples: + +&i2c1 { + ov5640: camera@3c { + compatible = "ovti,ov5640"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ov5640>; + reg = <0x3c>; + clocks = <&clks IMX6QDL_CLK_CKO>; + clock-names = "xclk"; + DOVDD-supply = <&vgen4_reg>; /* 1.8v */ + AVDD-supply = <&vgen3_reg>; /* 2.8v */ + DVDD-supply = <&vgen2_reg>; /* 1.5v */ + powerdown-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; + rotation = <180>; + + port { + /* MIPI CSI-2 bus endpoint */ + ov5640_to_mipi_csi2: endpoint { + remote-endpoint = <&mipi_csi2_from_ov5640>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&i2c1 { + ov5640: camera@3c { + compatible = "ovti,ov5640"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ov5640>; + reg = <0x3c>; + clocks = <&clk_ext_camera>; + clock-names = "xclk"; + + port { + /* Parallel bus endpoint */ + ov5640_to_parallel: endpoint { + remote-endpoint = <¶llel_from_ov5640>; + bus-width = <8>; + data-shift = <2>; /* lines 9:2 are used */ + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5645.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5645.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd7aec9f8e247a1a507991aba3544713cd6b06f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5645.txt @@ -0,0 +1,54 @@ +* Omnivision 1/4-Inch 5Mp CMOS Digital Image Sensor + +The Omnivision OV5645 is a 1/4-Inch CMOS active pixel digital image sensor with +an active array size of 2592H x 1944V. It is programmable through a serial I2C +interface. + +Required Properties: +- compatible: Value should be "ovti,ov5645". +- clocks: Reference to the xclk clock. +- clock-names: Should be "xclk". +- clock-frequency: Frequency of the xclk clock. +- enable-gpios: Chip enable GPIO. Polarity is GPIO_ACTIVE_HIGH. This corresponds + to the hardware pin PWDNB which is physically active low. +- reset-gpios: Chip reset GPIO. Polarity is GPIO_ACTIVE_LOW. This corresponds to + the hardware pin RESETB. +- vdddo-supply: Chip digital IO regulator. +- vdda-supply: Chip analog regulator. +- vddd-supply: Chip digital core regulator. + +The device node must contain one 'port' child node for its digital output +video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + &i2c1 { + ... + + ov5645: ov5645@78 { + compatible = "ovti,ov5645"; + reg = <0x78>; + + enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio5 20 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_default>; + + clocks = <&clks 200>; + clock-names = "xclk"; + clock-frequency = <23880000>; + + vdddo-supply = <&camera_dovdd_1v8>; + vdda-supply = <&camera_avdd_2v8>; + vddd-supply = <&camera_dvdd_1v2>; + + port { + ov5645_ep: endpoint { + clock-lanes = <1>; + data-lanes = <0 2>; + remote-endpoint = <&csi0_ep>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5647.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5647.txt new file mode 100644 index 0000000000000000000000000000000000000000..22e44945b66108d20eb283cb00f25b6af1a47a34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5647.txt @@ -0,0 +1,35 @@ +Omnivision OV5647 raw image sensor +--------------------------------- + +OV5647 is a raw image sensor with MIPI CSI-2 and CCP2 image data interfaces +and CCI (I2C compatible) control bus. + +Required properties: + +- compatible : "ovti,ov5647". +- reg : I2C slave address of the sensor. +- clocks : Reference to the xclk clock. + +The common video interfaces bindings (see video-interfaces.txt) should be +used to specify link to the image data receiver. The OV5647 device +node should contain one 'port' child node with an 'endpoint' subnode. + +Endpoint node mandatory properties: + +- remote-endpoint: A phandle to the bus receiver's endpoint node. + +Example: + + i2c@2000 { + ... + ov: camera@36 { + compatible = "ovti,ov5647"; + reg = <0x36>; + clocks = <&camera_clk>; + port { + camera_1: endpoint { + remote-endpoint = <&csi1_ep1>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5695.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5695.txt new file mode 100644 index 0000000000000000000000000000000000000000..640a63717d96cc5856d4ab567f9a138e112c412b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov5695.txt @@ -0,0 +1,41 @@ +* Omnivision OV5695 MIPI CSI-2 sensor + +Required Properties: +- compatible: shall be "ovti,ov5695" +- clocks: reference to the xvclk input clock +- clock-names: shall be "xvclk" +- avdd-supply: Analog voltage supply, 2.8 volts +- dovdd-supply: Digital I/O voltage supply, 1.8 volts +- dvdd-supply: Digital core voltage supply, 1.2 volts +- reset-gpios: Low active reset gpio + +The device node shall contain one 'port' child node with an +'endpoint' subnode for its digital output video port, +in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. +The endpoint optional property 'data-lanes' shall be "<1 2>". + +Example: +&i2c7 { + ov5695: camera-sensor@36 { + compatible = "ovti,ov5695"; + reg = <0x36>; + pinctrl-names = "default"; + pinctrl-0 = <&clk_24m_cam>; + + clocks = <&cru SCLK_TESTCLKOUT1>; + clock-names = "xvclk"; + + avdd-supply = <&pp2800_cam>; + dovdd-supply = <&pp1800>; + dvdd-supply = <&pp1250_cam>; + reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + + port { + wcam_out: endpoint { + remote-endpoint = <&mipi_in_wcam>; + data-lanes = <1 2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7251.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7251.txt new file mode 100644 index 0000000000000000000000000000000000000000..8281151f7493e3f5c28006002c80de97dd0b3646 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7251.txt @@ -0,0 +1,52 @@ +* Omnivision 1/7.5-Inch B&W VGA CMOS Digital Image Sensor + +The Omnivision OV7251 is a 1/7.5-Inch CMOS active pixel digital image sensor +with an active array size of 640H x 480V. It is programmable through a serial +I2C interface. + +Required Properties: +- compatible: Value should be "ovti,ov7251". +- clocks: Reference to the xclk clock. +- clock-names: Should be "xclk". +- clock-frequency: Frequency of the xclk clock. +- enable-gpios: Chip enable GPIO. Polarity is GPIO_ACTIVE_HIGH. This corresponds + to the hardware pin XSHUTDOWN which is physically active low. +- vdddo-supply: Chip digital IO regulator. +- vdda-supply: Chip analog regulator. +- vddd-supply: Chip digital core regulator. + +The device node shall contain one 'port' child node with a single 'endpoint' +subnode for its digital output video port, in accordance with the video +interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + &i2c1 { + ... + + ov7251: camera-sensor@60 { + compatible = "ovti,ov7251"; + reg = <0x60>; + + enable-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_bw_default>; + + clocks = <&clks 200>; + clock-names = "xclk"; + clock-frequency = <24000000>; + + vdddo-supply = <&camera_dovdd_1v8>; + vdda-supply = <&camera_avdd_2v8>; + vddd-supply = <&camera_dvdd_1v2>; + + port { + ov7251_ep: endpoint { + clock-lanes = <1>; + data-lanes = <0>; + remote-endpoint = <&csi0_ep>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7670.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7670.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c972a56f3cb5ea354f22c74bc8a41ee5792b6a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7670.txt @@ -0,0 +1,55 @@ +* Omnivision OV7670 CMOS sensor + +The Omnivision OV7670 sensor supports multiple resolutions output, such as +CIF, SVGA, UXGA. It also can support the YUV422/420, RGB565/555 or raw RGB +output formats. + +Required Properties: +- compatible: should be "ovti,ov7670" +- clocks: reference to the xclk input clock. +- clock-names: should be "xclk". + +Required Endpoint Properties: +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the resetb pin, if any. + Active is low. +- powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any. + Active is high. +- ov7670,pclk-hb-disable: a boolean property to suppress pixel clock output + signal during horizontal blankings. + +The device node must contain one 'port' child node with one 'endpoint' child +sub-node for its digital output video port, in accordance with the video +interface bindings defined in: +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c1: i2c@f0018000 { + ov7670: camera@21 { + compatible = "ovti,ov7670"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + reset-gpios = <&pioE 11 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&pioE 13 GPIO_ACTIVE_HIGH>; + clocks = <&pck0>; + clock-names = "xclk"; + assigned-clocks = <&pck0>; + assigned-clock-rates = <25000000>; + + ov7670,pclk-hb-disable; + + port { + ov7670_0: endpoint { + hsync-active = <0>; + vsync-active = <0>; + + remote-endpoint = <&isi_0>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov772x.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov772x.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b3ede5b8e6aea41ccca0e638a5ed66c69c008d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov772x.txt @@ -0,0 +1,40 @@ +* Omnivision OV7720/OV7725 CMOS sensor + +The Omnivision OV7720/OV7725 sensor supports multiple resolutions output, +such as VGA, QVGA, and any size scaling down from CIF to 40x30. It also can +support the YUV422, RGB565/555/444, GRB422 or raw RGB output formats. + +Required Properties: +- compatible: shall be one of + "ovti,ov7720" + "ovti,ov7725" +- clocks: reference to the xclk input clock. + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the RSTB pin which is + active low, if any. +- powerdown-gpios: reference to the GPIO connected to the PWDN pin which is + active high, if any. + +The device node shall contain one 'port' child node with one child 'endpoint' +subnode for its digital output video port, in accordance with the video +interface bindings defined in Documentation/devicetree/bindings/media/ +video-interfaces.txt. + +Example: + +&i2c0 { + ov772x: camera@21 { + compatible = "ovti,ov7725"; + reg = <0x21>; + reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_LOW>; + clocks = <&xclk>; + + port { + ov772x_0: endpoint { + remote-endpoint = <&vcap1_in0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7740.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7740.txt new file mode 100644 index 0000000000000000000000000000000000000000..af781c3a5f0ee2124851b7a912dbb7e89e3162b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov7740.txt @@ -0,0 +1,47 @@ +* Omnivision OV7740 CMOS image sensor + +The Omnivision OV7740 image sensor supports multiple output image +size, such as VGA, and QVGA, CIF and any size smaller. It also +supports the RAW RGB and YUV output formats. + +The common video interfaces bindings (see video-interfaces.txt) should +be used to specify link to the image data receiver. The OV7740 device +node should contain one 'port' child node with an 'endpoint' subnode. + +Required Properties: +- compatible: "ovti,ov7740". +- reg: I2C slave address of the sensor. +- clocks: Reference to the xvclk input clock. +- clock-names: "xvclk". + +Optional Properties: +- reset-gpios: Rreference to the GPIO connected to the reset_b pin, + if any. Active low with pull-ip resistor. +- powerdown-gpios: Reference to the GPIO connected to the pwdn pin, + if any. Active high with pull-down resistor. + +Endpoint node mandatory properties: +- remote-endpoint: A phandle to the bus receiver's endpoint node. + +Example: + + i2c1: i2c@fc028000 { + ov7740: camera@21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + clocks = <&isc>; + clock-names = "xvclk"; + assigned-clocks = <&isc>; + assigned-clock-rates = <24000000>; + reset-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isc_0>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov9650.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov9650.txt new file mode 100644 index 0000000000000000000000000000000000000000..506dfc52872ac08e3d2c9c4d7ef95455b6174a3c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ov9650.txt @@ -0,0 +1,36 @@ +* Omnivision OV9650/OV9652 CMOS sensor + +Required Properties: +- compatible: shall be one of + "ovti,ov9650" + "ovti,ov9652" +- clocks: reference to the xvclk input clock. + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the resetb pin, if any. + Active is high. +- powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any. + Active is high. + +The device node shall contain one 'port' child node with one child 'endpoint' +subnode for its digital output video port, in accordance with the video +interface bindings defined in Documentation/devicetree/bindings/media/ +video-interfaces.txt. + +Example: + +&i2c0 { + ov9650: camera@30 { + compatible = "ovti,ov9650"; + reg = <0x30>; + reset-gpios = <&axi_gpio_0 0 GPIO_ACTIVE_HIGH>; + powerdown-gpios = <&axi_gpio_0 1 GPIO_ACTIVE_HIGH>; + clocks = <&xclk>; + + port { + ov9650_0: endpoint { + remote-endpoint = <&vcap1_in0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/panasonic,amg88xx.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/panasonic,amg88xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a3181a3dd7e2f606a9517ff747f0ceb38f2cf49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/panasonic,amg88xx.txt @@ -0,0 +1,19 @@ +* Panasonic AMG88xx + +The Panasonic family of AMG88xx Grid-Eye sensors allow recording +8x8 10Hz video which consists of thermal datapoints + +Required Properties: + - compatible : Must be "panasonic,amg88xx" + - reg : i2c address of the device + +Example: + + i2c0@1c22000 { + ... + amg88xx@69 { + compatible = "panasonic,amg88xx"; + reg = <0x69>; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/tc358743.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tc358743.txt new file mode 100644 index 0000000000000000000000000000000000000000..59102edcf01ea574c1b2e94231d0fa349c767e9d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tc358743.txt @@ -0,0 +1,48 @@ +* Toshiba TC358743 HDMI-RX to MIPI CSI2-TX Bridge + +The Toshiba TC358743 HDMI-RX to MIPI CSI2-TX (H2C) is a bridge that converts +a HDMI stream to MIPI CSI-2 TX. It is programmable through I2C. + +Required Properties: + +- compatible: value should be "toshiba,tc358743" +- clocks, clock-names: should contain a phandle link to the reference clock + source, the clock input is named "refclk". + +Optional Properties: + +- reset-gpios: gpio phandle GPIO connected to the reset pin +- interrupts: GPIO connected to the interrupt pin +- data-lanes: should be <1 2 3 4> for four-lane operation, + or <1 2> for two-lane operation +- clock-lanes: should be <0> +- clock-noncontinuous: Presence of this boolean property decides whether the + MIPI CSI-2 clock is continuous or non-continuous. +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is + expressed as a 64-bit big-endian integer. The frequency + is half of the bps per lane due to DDR transmission. + +For further information on the MIPI CSI-2 endpoint node properties, see +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + tc358743@f { + compatible = "toshiba,tc358743"; + reg = <0x0f>; + clocks = <&hdmi_osc>; + clock-names = "refclk"; + reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; + interrupt-parent = <&gpio2>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + + port { + tc358743_out: endpoint { + remote-endpoint = <&mipi_csi2_in>; + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + clock-noncontinuous; + link-frequencies = /bits/ 64 <297000000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/tda1997x.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tda1997x.txt new file mode 100644 index 0000000000000000000000000000000000000000..e76167999d76c905a013a9c13c58f6c6f988ea5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tda1997x.txt @@ -0,0 +1,178 @@ +Device-Tree bindings for the NXP TDA1997x HDMI receiver + +The TDA19971/73 are HDMI video receivers. + +The TDA19971 Video port output pins can be used as follows: + - RGB 8bit per color (24 bits total): R[11:4] B[11:4] G[11:4] + - YUV444 8bit per color (24 bits total): Y[11:4] Cr[11:4] Cb[11:4] + - YUV422 semi-planar 8bit per component (16 bits total): Y[11:4] CbCr[11:4] + - YUV422 semi-planar 10bit per component (20 bits total): Y[11:2] CbCr[11:2] + - YUV422 semi-planar 12bit per component (24 bits total): - Y[11:0] CbCr[11:0] + - YUV422 BT656 8bit per component (8 bits total): YCbCr[11:4] (2-cycles) + - YUV422 BT656 10bit per component (10 bits total): YCbCr[11:2] (2-cycles) + - YUV422 BT656 12bit per component (12 bits total): YCbCr[11:0] (2-cycles) + +The TDA19973 Video port output pins can be used as follows: + - RGB 12bit per color (36 bits total): R[11:0] B[11:0] G[11:0] + - YUV444 12bit per color (36 bits total): Y[11:0] Cb[11:0] Cr[11:0] + - YUV422 semi-planar 12bit per component (24 bits total): Y[11:0] CbCr[11:0] + - YUV422 BT656 12bit per component (12 bits total): YCbCr[11:0] (2-cycles) + +The Video port output pins are mapped via 4-bit 'pin groups' allowing +for a variety of connection possibilities including swapping pin order within +pin groups. The video_portcfg device-tree property consists of register mapping +pairs which map a chip-specific VP output register to a 4-bit pin group. If +the pin group needs to be bit-swapped you can use the *_S pin-group defines. + +Required Properties: + - compatible : + - "nxp,tda19971" for the TDA19971 + - "nxp,tda19973" for the TDA19973 + - reg : I2C slave address + - interrupts : The interrupt number + - DOVDD-supply : Digital I/O supply + - DVDD-supply : Digital Core supply + - AVDD-supply : Analog supply + - nxp,vidout-portcfg : array of pairs mapping VP output pins to pin groups. + +Optional Properties: + - nxp,audout-format : DAI bus format: "i2s" or "spdif". + - nxp,audout-width : width of audio output data bus (1-4). + - nxp,audout-layout : data layout (0=AP0 used, 1=AP0/AP1/AP2/AP3 used). + - nxp,audout-mclk-fs : Multiplication factor between stream rate and codec + mclk. + +The port node shall contain one endpoint child node for its digital +output video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Optional Endpoint Properties: + The following three properties are defined in video-interfaces.txt and + are valid for the output parallel bus endpoint: + - hsync-active: Horizontal synchronization polarity. Defaults to active high. + - vsync-active: Vertical synchronization polarity. Defaults to active high. + - data-active: Data polarity. Defaults to active high. + +Examples: + - VP[15:0] connected to IMX6 CSI_DATA[19:4] for 16bit YUV422 + 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins) + hdmi-receiver@48 { + compatible = "nxp,tda19971"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tda1997x>; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + DOVDD-supply = <®_3p3v>; + AVDD-supply = <®_1p8v>; + DVDD-supply = <®_1p8v>; + /* audio */ + #sound-dai-cells = <0>; + nxp,audout-format = "i2s"; + nxp,audout-layout = <0>; + nxp,audout-width = <16>; + nxp,audout-mclk-fs = <128>; + /* + * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4] + * and Y[11:4] across 16bits in the same pixclk cycle. + */ + nxp,vidout-portcfg = + /* Y[11:8]<->VP[15:12]<->CSI_DATA[19:16] */ + < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >, + /* Y[7:4]<->VP[11:08]<->CSI_DATA[15:12] */ + < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >, + /* CbCc[11:8]<->VP[07:04]<->CSI_DATA[11:8] */ + < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >, + /* CbCr[7:4]<->VP[03:00]<->CSI_DATA[7:4] */ + < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >; + + port { + tda1997x_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + bus-width = <16>; + hsync-active = <1>; + vsync-active = <1>; + data-active = <1>; + }; + }; + }; + - VP[15:8] connected to IMX6 CSI_DATA[19:12] for 8bit BT656 + 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins) + hdmi-receiver@48 { + compatible = "nxp,tda19971"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tda1997x>; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + DOVDD-supply = <®_3p3v>; + AVDD-supply = <®_1p8v>; + DVDD-supply = <®_1p8v>; + /* audio */ + #sound-dai-cells = <0>; + nxp,audout-format = "i2s"; + nxp,audout-layout = <0>; + nxp,audout-width = <16>; + nxp,audout-mclk-fs = <128>; + /* + * The 8bpp YUV422 semi-planar mode outputs CbCr[11:4] + * and Y[11:4] across 16bits in the same pixclk cycle. + */ + nxp,vidout-portcfg = + /* Y[11:8]<->VP[15:12]<->CSI_DATA[19:16] */ + < TDA1997X_VP24_V15_12 TDA1997X_G_Y_11_8 >, + /* Y[7:4]<->VP[11:08]<->CSI_DATA[15:12] */ + < TDA1997X_VP24_V11_08 TDA1997X_G_Y_7_4 >, + /* CbCc[11:8]<->VP[07:04]<->CSI_DATA[11:8] */ + < TDA1997X_VP24_V07_04 TDA1997X_R_CR_CBCR_11_8 >, + /* CbCr[7:4]<->VP[03:00]<->CSI_DATA[7:4] */ + < TDA1997X_VP24_V03_00 TDA1997X_R_CR_CBCR_7_4 >; + + port { + tda1997x_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + bus-width = <16>; + hsync-active = <1>; + vsync-active = <1>; + data-active = <1>; + }; + }; + }; + - VP[15:8] connected to IMX6 CSI_DATA[19:12] for 8bit BT656 + 16bit I2S layout0 with a 128*fs clock (A_WS, AP0, A_CLK pins) + hdmi-receiver@48 { + compatible = "nxp,tda19971"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tda1997x>; + reg = <0x48>; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + DOVDD-supply = <®_3p3v>; + AVDD-supply = <®_1p8v>; + DVDD-supply = <®_1p8v>; + /* audio */ + #sound-dai-cells = <0>; + nxp,audout-format = "i2s"; + nxp,audout-layout = <0>; + nxp,audout-width = <16>; + nxp,audout-mclk-fs = <128>; + /* + * The 8bpp BT656 mode outputs YCbCr[11:4] across 8bits over + * 2 pixclk cycles. + */ + nxp,vidout-portcfg = + /* YCbCr[11:8]<->VP[15:12]<->CSI_DATA[19:16] */ + < TDA1997X_VP24_V15_12 TDA1997X_R_CR_CBCR_11_8 >, + /* YCbCr[7:4]<->VP[11:08]<->CSI_DATA[15:12] */ + < TDA1997X_VP24_V11_08 TDA1997X_R_CR_CBCR_7_4 >, + + port { + tda1997x_to_ipu1_csi0_mux: endpoint { + remote-endpoint = <&ipu1_csi0_mux_from_parallel_sensor>; + bus-width = <16>; + hsync-active = <1>; + vsync-active = <1>; + data-active = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/ths8200.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ths8200.txt new file mode 100644 index 0000000000000000000000000000000000000000..285f6ae7dfa93b79748cdfcd87fa1525d3ea0ea6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/ths8200.txt @@ -0,0 +1,19 @@ +* Texas Instruments THS8200 video encoder + +The ths8200 device is a digital to analog converter used in DVD players, video +recorders, set-top boxes. + +Required Properties : +- compatible : value must be "ti,ths8200" + +Example: + + i2c0@1c22000 { + ... + ... + ths8200@5c { + compatible = "ti,ths8200"; + reg = <0x5c>; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/toshiba,et8ek8.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/toshiba,et8ek8.txt new file mode 100644 index 0000000000000000000000000000000000000000..e80d5891b7eddf53e499c64446e0df41b03cfad5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/toshiba,et8ek8.txt @@ -0,0 +1,55 @@ +Toshiba et8ek8 5MP sensor + +Toshiba et8ek8 5MP sensor is an image sensor found in Nokia N900 device + +More detailed documentation can be found in +Documentation/devicetree/bindings/media/video-interfaces.txt . + + +Mandatory properties +-------------------- + +- compatible: "toshiba,et8ek8" +- reg: I2C address (0x3e, or an alternative address) +- vana-supply: Analogue voltage supply (VANA), 2.8 volts +- clocks: External clock to the sensor +- clock-frequency: Frequency of the external clock to the sensor. Camera + driver will set this frequency on the external clock. The clock frequency is + a pre-determined frequency known to be suitable to the board. +- reset-gpios: XSHUTDOWN GPIO. The XSHUTDOWN signal is active low. The sensor + is in hardware standby mode when the signal is in the low state. + + +Optional properties +------------------- + +- flash-leds: See ../video-interfaces.txt +- lens-focus: See ../video-interfaces.txt + + +Endpoint node mandatory properties +---------------------------------- + +- remote-endpoint: A phandle to the bus receiver's endpoint node. + + +Example +------- + +&i2c3 { + clock-frequency = <400000>; + + cam1: camera@3e { + compatible = "toshiba,et8ek8"; + reg = <0x3e>; + vana-supply = <&vaux4>; + clocks = <&isp 0>; + clock-frequency = <9600000>; + reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* 102 */ + port { + csi_cam1: endpoint { + remote-endpoint = <&csi_out1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp514x.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp514x.txt new file mode 100644 index 0000000000000000000000000000000000000000..46752cc71f2eb2b58b8279ee87555347a06f758e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp514x.txt @@ -0,0 +1,44 @@ +* Texas Instruments TVP514x video decoder + +The TVP5146/TVP5146m2/TVP5147/TVP5147m1 device is high quality, single-chip +digital video decoder that digitizes and decodes all popular baseband analog +video formats into digital video component. The tvp514x decoder supports analog- +to-digital (A/D) conversion of component RGB and YPbPr signals as well as A/D +conversion and decoding of NTSC, PAL and SECAM composite and S-video into +component YCbCr. + +Required Properties : +- compatible : value should be either one among the following + (a) "ti,tvp5146" for tvp5146 decoder. + (b) "ti,tvp5146m2" for tvp5146m2 decoder. + (c) "ti,tvp5147" for tvp5147 decoder. + (d) "ti,tvp5147m1" for tvp5147m1 decoder. + +- hsync-active: HSYNC Polarity configuration for endpoint. + +- vsync-active: VSYNC Polarity configuration for endpoint. + +- pclk-sample: Clock polarity of the endpoint. + +For further reading on port node refer to Documentation/devicetree/bindings/ +media/video-interfaces.txt. + +Example: + + i2c0@1c22000 { + ... + ... + tvp514x@5c { + compatible = "ti,tvp5146"; + reg = <0x5c>; + + port { + tvp514x_1: endpoint { + hsync-active = <1>; + vsync-active = <1>; + pclk-sample = <0>; + }; + }; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp5150.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp5150.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c0fc1a26bf0a60c3746c66223c5d2bdb5a5018c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp5150.txt @@ -0,0 +1,45 @@ +* Texas Instruments TVP5150 and TVP5151 video decoders + +The TVP5150 and TVP5151 are video decoders that convert baseband NTSC and PAL +(and also SECAM in the TVP5151 case) video signals to either 8-bit 4:2:2 YUV +with discrete syncs or 8-bit ITU-R BT.656 with embedded syncs output formats. + +Required Properties: +- compatible: value must be "ti,tvp5150" +- reg: I2C slave address + +Optional Properties: +- pdn-gpios: phandle for the GPIO connected to the PDN pin, if any. +- reset-gpios: phandle for the GPIO connected to the RESETB pin, if any. + +The device node must contain one 'port' child node for its digital output +video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Required Endpoint Properties for parallel synchronization: + +- hsync-active: active state of the HSYNC signal. Must be <1> (HIGH). +- vsync-active: active state of the VSYNC signal. Must be <1> (HIGH). +- field-even-active: field signal level during the even field data + transmission. Must be <0>. + +If none of hsync-active, vsync-active and field-even-active is specified, +the endpoint is assumed to use embedded BT.656 synchronization. + +Example: + +&i2c2 { + ... + tvp5150@5c { + compatible = "ti,tvp5150"; + reg = <0x5c>; + pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>; + + port { + tvp5150_1: endpoint { + remote-endpoint = <&ccdc_ep>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp7002.txt b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp7002.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f28b5d9abcce5d52c24f1f4398802934e18e292 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/i2c/tvp7002.txt @@ -0,0 +1,53 @@ +* Texas Instruments TV7002 video decoder + +The TVP7002 device supports digitizing of video and graphics signal in RGB and +YPbPr color space. + +Required Properties : +- compatible : Must be "ti,tvp7002" + +Optional Properties: +- hsync-active: HSYNC Polarity configuration for the bus. Default value when + this property is not specified is <0>. + +- vsync-active: VSYNC Polarity configuration for the bus. Default value when + this property is not specified is <0>. + +- pclk-sample: Clock polarity of the bus. Default value when this property is + not specified is <0>. + +- sync-on-green-active: Active state of Sync-on-green signal property of the + endpoint. + 0 = Normal Operation (Active Low, Default) + 1 = Inverted operation + +- field-even-active: Active-high Field ID output polarity control of the bus. + Under normal operation, the field ID output is set to logic 1 for an odd field + (field 1) and set to logic 0 for an even field (field 0). + 0 = Normal Operation (Active Low, Default) + 1 = FID output polarity inverted + +For further reading of port node refer Documentation/devicetree/bindings/media/ +video-interfaces.txt. + +Example: + + i2c0@1c22000 { + ... + ... + tvp7002@5c { + compatible = "ti,tvp7002"; + reg = <0x5c>; + + port { + tvp7002_1: endpoint { + hsync-active = <1>; + vsync-active = <1>; + pclk-sample = <0>; + sync-on-green-active = <1>; + field-even-active = <0>; + }; + }; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/img-ir-rev1.txt b/arch/arm64/boot/dts/vendor/bindings/media/img-ir-rev1.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed9ec52b77e0633f1e367cd160c112b71c667f73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/img-ir-rev1.txt @@ -0,0 +1,34 @@ +* ImgTec Infrared (IR) decoder version 1 + +This binding is for Imagination Technologies' Infrared decoder block, +specifically major revision 1. + +Required properties: +- compatible: Should be "img,ir-rev1" +- reg: Physical base address of the controller and length of + memory mapped region. +- interrupts: The interrupt specifier to the cpu. + +Optional properties: +- clocks: List of clock specifiers as described in standard + clock bindings. + Up to 3 clocks may be specified in the following order: + 1st: Core clock (defaults to 32.768KHz if omitted). + 2nd: System side (fast) clock. + 3rd: Power modulation clock. +- clock-names: List of clock names corresponding to the clocks + specified in the clocks property. + Accepted clock names are: + "core": Core clock. + "sys": System clock. + "mod": Power modulation clock. + +Example: + + ir@2006200 { + compatible = "img,ir-rev1"; + reg = <0x02006200 0x100>; + interrupts = <29 4>; + clocks = <&clk_32khz>; + clock-names = "core"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/imx.txt b/arch/arm64/boot/dts/vendor/bindings/media/imx.txt new file mode 100644 index 0000000000000000000000000000000000000000..77f4b0a7fd2b0058d1e6858278acd16e815b783b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/imx.txt @@ -0,0 +1,53 @@ +Freescale i.MX Media Video Device +================================= + +Video Media Controller node +--------------------------- + +This is the media controller node for video capture support. It is a +virtual device that lists the camera serial interface nodes that the +media device will control. + +Required properties: +- compatible : "fsl,imx-capture-subsystem"; +- ports : Should contain a list of phandles pointing to camera + sensor interface ports of IPU devices + +example: + +capture-subsystem { + compatible = "fsl,imx-capture-subsystem"; + ports = <&ipu1_csi0>, <&ipu1_csi1>; +}; + + +mipi_csi2 node +-------------- + +This is the device node for the MIPI CSI-2 Receiver core in the i.MX +SoC. This is a Synopsys Designware MIPI CSI-2 host controller core +combined with a D-PHY core mixed into the same register block. In +addition this device consists of an i.MX-specific "CSI2IPU gasket" +glue logic, also controlled from the same register block. The CSI2IPU +gasket demultiplexes the four virtual channel streams from the host +controller's 32-bit output image bus onto four 16-bit parallel busses +to the i.MX IPU CSIs. + +Required properties: +- compatible : "fsl,imx6-mipi-csi2"; +- reg : physical base address and length of the register set; +- clocks : the MIPI CSI-2 receiver requires three clocks: hsi_tx + (the D-PHY clock), video_27m (D-PHY PLL reference + clock), and eim_podf; +- clock-names : must contain "dphy", "ref", "pix"; +- port@* : five port nodes must exist, containing endpoints + connecting to the source and sink devices according to + of_graph bindings. The first port is an input port, + connecting with a MIPI CSI-2 source, and ports 1 + through 4 are output ports connecting with parallel + bus sink endpoint nodes and correspond to the four + MIPI CSI-2 virtual channel outputs. + +Optional properties: +- interrupts : must contain two level-triggered interrupts, + in order: 100 and 101; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/mediatek-jpeg-decoder.txt b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-jpeg-decoder.txt new file mode 100644 index 0000000000000000000000000000000000000000..3813947b4d4f02bfd27ccaf126f64e0ecb933ce2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-jpeg-decoder.txt @@ -0,0 +1,37 @@ +* Mediatek JPEG Decoder + +Mediatek JPEG Decoder is the JPEG decode hardware present in Mediatek SoCs + +Required properties: +- compatible : must be one of the following string: + "mediatek,mt8173-jpgdec" + "mediatek,mt2701-jpgdec" +- reg : physical base address of the jpeg decoder registers and length of + memory mapped region. +- interrupts : interrupt number to the interrupt controller. +- clocks: device clocks, see + Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: must contain "jpgdec-smi" and "jpgdec". +- power-domains: a phandle to the power domain, see + Documentation/devicetree/bindings/power/power_domain.txt for details. +- mediatek,larb: must contain the local arbiters in the current Socs, see + Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt + for details. +- iommus: should point to the respective IOMMU block with master port as + argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt + for details. + +Example: + jpegdec: jpegdec@15004000 { + compatible = "mediatek,mt2701-jpgdec"; + reg = <0 0x15004000 0 0x1000>; + interrupts = ; + clocks = <&imgsys CLK_IMG_JPGDEC_SMI>, + <&imgsys CLK_IMG_JPGDEC>; + clock-names = "jpgdec-smi", + "jpgdec"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>; + mediatek,larb = <&larb2>; + iommus = <&iommu MT2701_M4U_PORT_JPGDEC_WDMA>, + <&iommu MT2701_M4U_PORT_JPGDEC_BSDMA>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/mediatek-mdp.txt b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-mdp.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d03e3ae2be2f23a294a27fbc63425d3f540eb05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-mdp.txt @@ -0,0 +1,103 @@ +* Mediatek Media Data Path + +Media Data Path is used for scaling and color space conversion. + +Required properties (controller node): +- compatible: "mediatek,mt8173-mdp" +- mediatek,vpu: the node of video processor unit, see + Documentation/devicetree/bindings/media/mediatek-vpu.txt for details. + +Required properties (all function blocks, child node): +- compatible: Should be one of + "mediatek,mt8173-mdp-rdma" - read DMA + "mediatek,mt8173-mdp-rsz" - resizer + "mediatek,mt8173-mdp-wdma" - write DMA + "mediatek,mt8173-mdp-wrot" - write DMA with rotation +- reg: Physical base address and length of the function block register space +- clocks: device clocks, see + Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- power-domains: a phandle to the power domain, see + Documentation/devicetree/bindings/power/power_domain.txt for details. + +Required properties (DMA function blocks, child node): +- compatible: Should be one of + "mediatek,mt8173-mdp-rdma" + "mediatek,mt8173-mdp-wdma" + "mediatek,mt8173-mdp-wrot" +- iommus: should point to the respective IOMMU block with master port as + argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt + for details. +- mediatek,larb: must contain the local arbiters in the current Socs, see + Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt + for details. + +Example: + mdp_rdma0: rdma@14001000 { + compatible = "mediatek,mt8173-mdp-rdma"; + "mediatek,mt8173-mdp"; + reg = <0 0x14001000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_RDMA0>, + <&mmsys CLK_MM_MUTEX_32K>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + iommus = <&iommu M4U_PORT_MDP_RDMA0>; + mediatek,larb = <&larb0>; + mediatek,vpu = <&vpu>; + }; + + mdp_rdma1: rdma@14002000 { + compatible = "mediatek,mt8173-mdp-rdma"; + reg = <0 0x14002000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_RDMA1>, + <&mmsys CLK_MM_MUTEX_32K>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + iommus = <&iommu M4U_PORT_MDP_RDMA1>; + mediatek,larb = <&larb4>; + }; + + mdp_rsz0: rsz@14003000 { + compatible = "mediatek,mt8173-mdp-rsz"; + reg = <0 0x14003000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_RSZ0>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + }; + + mdp_rsz1: rsz@14004000 { + compatible = "mediatek,mt8173-mdp-rsz"; + reg = <0 0x14004000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_RSZ1>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + }; + + mdp_rsz2: rsz@14005000 { + compatible = "mediatek,mt8173-mdp-rsz"; + reg = <0 0x14005000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_RSZ2>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + }; + + mdp_wdma0: wdma@14006000 { + compatible = "mediatek,mt8173-mdp-wdma"; + reg = <0 0x14006000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_WDMA>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + iommus = <&iommu M4U_PORT_MDP_WDMA>; + mediatek,larb = <&larb0>; + }; + + mdp_wrot0: wrot@14007000 { + compatible = "mediatek,mt8173-mdp-wrot"; + reg = <0 0x14007000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_WROT0>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + iommus = <&iommu M4U_PORT_MDP_WROT0>; + mediatek,larb = <&larb0>; + }; + + mdp_wrot1: wrot@14008000 { + compatible = "mediatek,mt8173-mdp-wrot"; + reg = <0 0x14008000 0 0x1000>; + clocks = <&mmsys CLK_MM_MDP_WROT1>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + iommus = <&iommu M4U_PORT_MDP_WROT1>; + mediatek,larb = <&larb4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/mediatek-vcodec.txt b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-vcodec.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a615d84a682563d28499b9a1f26a5ca2abcd984 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-vcodec.txt @@ -0,0 +1,108 @@ +Mediatek Video Codec + +Mediatek Video Codec is the video codec hw present in Mediatek SoCs which +supports high resolution encoding and decoding functionalities. + +Required properties: +- compatible : "mediatek,mt8173-vcodec-enc" for encoder + "mediatek,mt8173-vcodec-dec" for decoder. +- reg : Physical base address of the video codec registers and length of + memory mapped region. +- interrupts : interrupt number to the cpu. +- mediatek,larb : must contain the local arbiters in the current Socs. +- clocks : list of clock specifiers, corresponding to entries in + the clock-names property. +- clock-names: encoder must contain "venc_sel_src", "venc_sel",, + "venc_lt_sel_src", "venc_lt_sel", decoder must contain "vcodecpll", + "univpll_d2", "clk_cci400_sel", "vdec_sel", "vdecpll", "vencpll", + "venc_lt_sel", "vdec_bus_clk_src". +- iommus : should point to the respective IOMMU block with master port as + argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt + for details. +- mediatek,vpu : the node of video processor unit + + +Example: + +vcodec_dec: vcodec@16000000 { + compatible = "mediatek,mt8173-vcodec-dec"; + reg = <0 0x16000000 0 0x100>, /*VDEC_SYS*/ + <0 0x16020000 0 0x1000>, /*VDEC_MISC*/ + <0 0x16021000 0 0x800>, /*VDEC_LD*/ + <0 0x16021800 0 0x800>, /*VDEC_TOP*/ + <0 0x16022000 0 0x1000>, /*VDEC_CM*/ + <0 0x16023000 0 0x1000>, /*VDEC_AD*/ + <0 0x16024000 0 0x1000>, /*VDEC_AV*/ + <0 0x16025000 0 0x1000>, /*VDEC_PP*/ + <0 0x16026800 0 0x800>, /*VP8_VD*/ + <0 0x16027000 0 0x800>, /*VP6_VD*/ + <0 0x16027800 0 0x800>, /*VP8_VL*/ + <0 0x16028400 0 0x400>; /*VP9_VD*/ + interrupts = ; + mediatek,larb = <&larb1>; + iommus = <&iommu M4U_PORT_HW_VDEC_MC_EXT>, + <&iommu M4U_PORT_HW_VDEC_PP_EXT>, + <&iommu M4U_PORT_HW_VDEC_AVC_MV_EXT>, + <&iommu M4U_PORT_HW_VDEC_PRED_RD_EXT>, + <&iommu M4U_PORT_HW_VDEC_PRED_WR_EXT>, + <&iommu M4U_PORT_HW_VDEC_UFO_EXT>, + <&iommu M4U_PORT_HW_VDEC_VLD_EXT>, + <&iommu M4U_PORT_HW_VDEC_VLD2_EXT>; + mediatek,vpu = <&vpu>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>; + clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>, + <&topckgen CLK_TOP_UNIVPLL_D2>, + <&topckgen CLK_TOP_CCI400_SEL>, + <&topckgen CLK_TOP_VDEC_SEL>, + <&topckgen CLK_TOP_VCODECPLL>, + <&apmixedsys CLK_APMIXED_VENCPLL>, + <&topckgen CLK_TOP_VENC_LT_SEL>, + <&topckgen CLK_TOP_VCODECPLL_370P5>; + clock-names = "vcodecpll", + "univpll_d2", + "clk_cci400_sel", + "vdec_sel", + "vdecpll", + "vencpll", + "venc_lt_sel", + "vdec_bus_clk_src"; + }; + + vcodec_enc: vcodec@18002000 { + compatible = "mediatek,mt8173-vcodec-enc"; + reg = <0 0x18002000 0 0x1000>, /*VENC_SYS*/ + <0 0x19002000 0 0x1000>; /*VENC_LT_SYS*/ + interrupts = , + ; + mediatek,larb = <&larb3>, + <&larb5>; + iommus = <&iommu M4U_PORT_VENC_RCPU>, + <&iommu M4U_PORT_VENC_REC>, + <&iommu M4U_PORT_VENC_BSDMA>, + <&iommu M4U_PORT_VENC_SV_COMV>, + <&iommu M4U_PORT_VENC_RD_COMV>, + <&iommu M4U_PORT_VENC_CUR_LUMA>, + <&iommu M4U_PORT_VENC_CUR_CHROMA>, + <&iommu M4U_PORT_VENC_REF_LUMA>, + <&iommu M4U_PORT_VENC_REF_CHROMA>, + <&iommu M4U_PORT_VENC_NBM_RDMA>, + <&iommu M4U_PORT_VENC_NBM_WDMA>, + <&iommu M4U_PORT_VENC_RCPU_SET2>, + <&iommu M4U_PORT_VENC_REC_FRM_SET2>, + <&iommu M4U_PORT_VENC_BSDMA_SET2>, + <&iommu M4U_PORT_VENC_SV_COMA_SET2>, + <&iommu M4U_PORT_VENC_RD_COMA_SET2>, + <&iommu M4U_PORT_VENC_CUR_LUMA_SET2>, + <&iommu M4U_PORT_VENC_CUR_CHROMA_SET2>, + <&iommu M4U_PORT_VENC_REF_LUMA_SET2>, + <&iommu M4U_PORT_VENC_REC_CHROMA_SET2>; + mediatek,vpu = <&vpu>; + clocks = <&topckgen CLK_TOP_VENCPLL_D2>, + <&topckgen CLK_TOP_VENC_SEL>, + <&topckgen CLK_TOP_UNIVPLL1_D2>, + <&topckgen CLK_TOP_VENC_LT_SEL>; + clock-names = "venc_sel_src", + "venc_sel", + "venc_lt_sel_src", + "venc_lt_sel"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/mediatek-vpu.txt b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-vpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a5bac37f9a2268209a59a607352d0e5d9dd9bfe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/mediatek-vpu.txt @@ -0,0 +1,31 @@ +* Mediatek Video Processor Unit + +Video Processor Unit is a HW video controller. It controls HW Codec including +H.264/VP8/VP9 Decode, H.264/VP8 Encode and Image Processor (scale/rotate/color convert). + +Required properties: + - compatible: "mediatek,mt8173-vpu" + - reg: Must contain an entry for each entry in reg-names. + - reg-names: Must include the following entries: + "tcm": tcm base + "cfg_reg": Main configuration registers base + - interrupts: interrupt number to the cpu. + - clocks : clock name from clock manager + - clock-names: must be main. It is the main clock of VPU + +Optional properties: + - memory-region: phandle to a node describing memory (see + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) + to be used for VPU extended memory; if not present, VPU may be located + anywhere in the memory + +Example: + vpu: vpu@10020000 { + compatible = "mediatek,mt8173-vpu"; + reg = <0 0x10020000 0 0x30000>, + <0 0x10050000 0 0x100>; + reg-names = "tcm", "cfg_reg"; + interrupts = ; + clocks = <&topckgen TOP_SCP_SEL>; + clock-names = "main"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/meson-ao-cec.txt b/arch/arm64/boot/dts/vendor/bindings/media/meson-ao-cec.txt new file mode 100644 index 0000000000000000000000000000000000000000..8671bdb08080e37303227d5b6e55d78c24402ccc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/meson-ao-cec.txt @@ -0,0 +1,28 @@ +* Amlogic Meson AO-CEC driver + +The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is +to handle communication between HDMI connected devices over the CEC bus. + +Required properties: + - compatible : value should be following + "amlogic,meson-gx-ao-cec" + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : AO-CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to AO-CEC clock. + - clock-names : from common clock binding: must contain "core", + corresponding to entry in the clocks property. + - hdmi-phandle: phandle to the HDMI controller + +Example: + +cec_AO: cec@100 { + compatible = "amlogic,meson-gx-ao-cec"; + reg = <0x0 0x00100 0x0 0x14>; + interrupts = ; + clocks = <&clkc_AO CLKID_AO_CEC_32K>; + clock-names = "core"; + hdmi-phandle = <&hdmi_tx>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/meson-ir.txt b/arch/arm64/boot/dts/vendor/bindings/media/meson-ir.txt new file mode 100644 index 0000000000000000000000000000000000000000..efd9d29a8f103f3003dffd82c84df1eb1d614973 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/meson-ir.txt @@ -0,0 +1,20 @@ +* Amlogic Meson IR remote control receiver + +Required properties: + - compatible : depending on the platform this should be one of: + - "amlogic,meson6-ir" + - "amlogic,meson8b-ir" + - "amlogic,meson-gxbb-ir" + - reg : physical base address and length of the device registers + - interrupts : a single specifier for the interrupt from the device + +Optional properties: + - linux,rc-map-name: see rc.txt file in the same directory. + +Example: + + ir-receiver@c8100480 { + compatible= "amlogic,meson6-ir"; + reg = <0xc8100480 0x20>; + interrupts = <0 15 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/msm-npu-pwrlevels.txt b/arch/arm64/boot/dts/vendor/bindings/media/msm-npu-pwrlevels.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a8a014c95d822b4c6f2128ebda7078411b03ce9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/msm-npu-pwrlevels.txt @@ -0,0 +1,164 @@ +Qualcomm Technologies, Inc. NPU powerlevels + +Powerlevels are defined in sets by qcom,npu-pwrlevels. Each powerlevel defines +a series of clock frequencies. These frequencies are for the corresponding +clocks in the clocks property of the msm_npu device. + +qcom,npu-pwrlevels bindings: + +Required Properties: +- #address-cells: Should be set to 1 +- #size-cells: Should be set to 0 +- compatible: Must be qcom,npu-pwrlevels +- initial-pwrlevel: NPU initial wakeup power level, this is the index of the + child node. + +qcom,npu-pwrlevel: This is a child node defining power levels. +qcom,npu-pwrlevels must contain at least one power level node. Each child node +has the following properties: + +Required Properties: +- reg: Index of the powerlevel (0 = lowest performance) +- clk-freq: List of clock frequencies (in Hz) of each clock for the current + powerlevel. List of clocks and order described in: + Documentation/devicetree/bindings/media/msm-npu.txt + +Example: + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + clk-freq = <9600000 + 9600000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 60000000 + 19200000 + 19200000 + 30000000 + 19200000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@1 { + reg = <1>; + clk-freq = <300000000 + 300000000 + 19200000 + 100000000 + 19200000 + 19200000 + 300000000 + 150000000 + 19200000 + 19200000 + 60000000 + 100000000 + 100000000 + 37500000 + 100000000 + 19200000 + 300000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@2 { + reg = <2>; + clk-freq = <350000000 + 350000000 + 19200000 + 150000000 + 19200000 + 19200000 + 350000000 + 200000000 + 37500000 + 19200000 + 120000000 + 150000000 + 150000000 + 75000000 + 150000000 + 19200000 + 350000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@3 { + reg = <3>; + clk-freq = <400000000 + 400000000 + 19200000 + 200000000 + 19200000 + 19200000 + 400000000 + 300000000 + 37500000 + 19200000 + 120000000 + 200000000 + 200000000 + 75000000 + 200000000 + 19200000 + 400000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@4 { + reg = <4>; + clk-freq = <600000000 + 600000000 + 19200000 + 300000000 + 19200000 + 19200000 + 600000000 + 403000000 + 75000000 + 19200000 + 240000000 + 300000000 + 300000000 + 150000000 + 300000000 + 19200000 + 600000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; + clk-freq = <715000000 + 715000000 + 19200000 + 350000000 + 19200000 + 19200000 + 715000000 + 533000000 + 75000000 + 19200000 + 240000000 + 350000000 + 350000000 + 150000000 + 350000000 + 19200000 + 715000000 + 19200000 + 0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/msm-npu.txt b/arch/arm64/boot/dts/vendor/bindings/media/msm-npu.txt new file mode 100644 index 0000000000000000000000000000000000000000..f009650f728a03737c841ddabb9e744a923e10f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/msm-npu.txt @@ -0,0 +1,228 @@ +* Qualcomm Technologies, Inc. MSM NPU + +NPU (Neural Network Processing Unit) applies neural network processing + +Required properties: +- compatible: Must be "qcom,msm-npu" +- reg: Specify offset and length of the device register sets. +- reg-names: Names corresponding to the defined register sets. + - "npu_base": npu base registers +- interrupts: Specify the npu interrupts. +- interrupt-names: should specify relevant names to each interrupts + property defined. +- cache-slice-names: A set of names that identify the usecase names of a + client that uses cache slice. These strings are used to look up the + cache slice entries by name +- cache-slices: The tuple has phandle to llcc device as the first argument + and the second argument is the usecase id of the client +- clocks: clocks required for the device. +- clock-names: names of clocks required for the device. +- vdd-supply: Phandle for vdd regulator device node +- vdd_'reg'-supply: Reference to the regulator that supplies the corresponding + 'reg' domain, e.g. vdd_cx-supply. +- qcom,proxy-reg-names: Names of the regulators that need to be turned on/off + during proxy voting/unvoting. +- qcom,vdd_'reg'-uV-uA: Voltage and current values for the 'reg' regulator, + e.g. qcom,vdd_cx-uV-uA. +- mboxes: Phandle array for mailbox controllers to be used for IPC +- mbox-names: names of each mailboxes +- #cooling-cells: Should be set to 2 +- qcom,npubw-dev: a phandle to a device representing bus bandwidth requirements + (see devbw.txt) +- qcom,npu-pwrlevels: Container for NPU power levels + (see msm-npu-pwrlevels.txt) +Example: + msm_npu: qcom,msm_npu@9800000 { + compatible = "qcom,msm-npu"; + status = "ok"; + reg = <0x9800000 0x800000>; + reg-names = "npu_base"; + interrupts = ; + iommus = <&apps_smmu 0x1461 0x0>, <&apps_smmu 0x2061 0x0>; + cache-slice-names = "npu"; + cache-slices = <&llcc 23>; + clocks = <&clock_npucc NPU_CC_CAL_DP_CLK>, + <&clock_npucc NPU_CC_CAL_DP_CLK_SRC>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_ARMWIC_CORE_CLK>, + <&clock_npucc NPU_CC_BTO_CORE_CLK>, + <&clock_npucc NPU_CC_BWMON_CLK>, + <&clock_npucc NPU_CC_CAL_DP_CDC_CLK>, + <&clock_npucc NPU_CC_COMP_NOC_AXI_CLK>, + <&clock_npucc NPU_CC_CONF_NOC_AHB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_APB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_ATB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_NPU_CORE_CTI_CLK>, + <&clock_npucc NPU_CC_NPU_CPC_CLK>, + <&clock_npucc NPU_CC_NPU_CPC_TIMER_CLK>, + <&clock_npucc NPU_CC_PERF_CNT_CLK>, + <&clock_npucc NPU_CC_QTIMER_CORE_CLK>, + <&clock_npucc NPU_CC_SLEEP_CLK>; + clock-names = "cal_dp_clk", + "cal_dp_clk_src", + "xo_clk", + "armwic_core_clk", + "bto_core_clk", + "bwmon_clk", + "cal_dp_cdc_clk", + "comp_noc_axi_clk", + "conf_noc_ahb_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk", + "npu_cpc_clk", + "npu_cpc_timer_clk", + "perf_cnt_clk", + "qtimer_core_clk", + "sleep_clk"; + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&pm8150l_s6_level>; + qcom,proxy-reg-names ="vdd", "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + mboxes = <&qmp_npu0 0>, <&qmp_npu1 0>; + mbox-names = "npu_low", "npu_high"; + #cooling-cells = <2>; + qcom,npubw-dev = <&npu_npu_ddr_bw>; + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + clk-freq = <9600000 + 9600000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 60000000 + 19200000 + 19200000 + 30000000 + 19200000 + 19200000 + 19200000 + 19200000 + 19200000 + 9600000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@1 { + reg = <1>; + clk-freq = <300000000 + 300000000 + 19200000 + 100000000 + 19200000 + 19200000 + 300000000 + 150000000 + 19200000 + 19200000 + 60000000 + 100000000 + 100000000 + 37500000 + 100000000 + 19200000 + 300000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@2 { + reg = <2>; + clk-freq = <350000000 + 350000000 + 19200000 + 150000000 + 19200000 + 19200000 + 350000000 + 200000000 + 37500000 + 19200000 + 120000000 + 150000000 + 150000000 + 75000000 + 150000000 + 19200000 + 350000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@3 { + reg = <3>; + clk-freq = <400000000 + 400000000 + 19200000 + 200000000 + 19200000 + 19200000 + 400000000 + 300000000 + 37500000 + 19200000 + 120000000 + 200000000 + 200000000 + 75000000 + 200000000 + 19200000 + 400000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@4 { + reg = <4>; + clk-freq = <600000000 + 600000000 + 19200000 + 300000000 + 19200000 + 19200000 + 600000000 + 403000000 + 75000000 + 19200000 + 240000000 + 300000000 + 300000000 + 150000000 + 300000000 + 19200000 + 600000000 + 19200000 + 0>; + }; + qcom,npu-pwrlevel@5 { + reg = <5>; + clk-freq = <715000000 + 715000000 + 19200000 + 350000000 + 19200000 + 19200000 + 715000000 + 533000000 + 75000000 + 19200000 + 240000000 + 350000000 + 350000000 + 150000000 + 350000000 + 19200000 + 715000000 + 19200000 + 0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/mtk-cir.txt b/arch/arm64/boot/dts/vendor/bindings/media/mtk-cir.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e18087ce11f25410fdff901d398f8d60d6f7133 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/mtk-cir.txt @@ -0,0 +1,28 @@ +Device-Tree bindings for Mediatek consumer IR controller +found in Mediatek SoC family + +Required properties: +- compatible : Should be + "mediatek,mt7623-cir": for MT7623 SoC + "mediatek,mt7622-cir": for MT7622 SoC +- clocks : list of clock specifiers, corresponding to + entries in clock-names property; +- clock-names : should contain + - "clk" entries: for MT7623 SoC + - "clk", "bus" entries: for MT7622 SoC +- interrupts : should contain IR IRQ number; +- reg : should contain IO map address for IR. + +Optional properties: +- linux,rc-map-name : see rc.txt file in the same directory. + +Example: + +cir: cir@10013000 { + compatible = "mediatek,mt7623-cir"; + reg = <0 0x10013000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_IRRX>; + clock-names = "clk"; + linux,rc-map-name = "rc-rc6-mce"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/nokia,n900-ir b/arch/arm64/boot/dts/vendor/bindings/media/nokia,n900-ir new file mode 100644 index 0000000000000000000000000000000000000000..13a18ce37dd14371aeee9e1943e4f539500c18ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/nokia,n900-ir @@ -0,0 +1,20 @@ +Device-Tree bindings for LIRC TX driver for Nokia N900(RX51) + +Required properties: + - compatible: should be "nokia,n900-ir". + - pwms: specifies PWM used for IR signal transmission. + +Example node: + + pwm9: dmtimer-pwm@9 { + compatible = "ti,omap-dmtimer-pwm"; + ti,timers = <&timer9>; + ti,clock-source = <0x00>; /* timer_sys_ck */ + #pwm-cells = <3>; + }; + + ir: n900-ir { + compatible = "nokia,n900-ir"; + + pwms = <&pwm9 0 26316 0>; /* 38000 Hz */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/nvidia,tegra-vde.txt b/arch/arm64/boot/dts/vendor/bindings/media/nvidia,tegra-vde.txt new file mode 100644 index 0000000000000000000000000000000000000000..7302e949e662cb8070fb0a32b9f77d75bd249c62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/nvidia,tegra-vde.txt @@ -0,0 +1,62 @@ +NVIDIA Tegra Video Decoder Engine + +Required properties: +- compatible : Must contain one of the following values: + - "nvidia,tegra20-vde" + - "nvidia,tegra30-vde" + - "nvidia,tegra114-vde" + - "nvidia,tegra124-vde" + - "nvidia,tegra132-vde" +- reg : Must contain an entry for each entry in reg-names. +- reg-names : Must include the following entries: + - sxe + - bsev + - mbe + - ppe + - mce + - tfe + - ppb + - vdma + - frameid +- iram : Must contain phandle to the mmio-sram device node that represents + IRAM region used by VDE. +- interrupts : Must contain an entry for each entry in interrupt-names. +- interrupt-names : Must include the following entries: + - sync-token + - bsev + - sxe +- clocks : Must include the following entries: + - vde +- resets : Must contain an entry for each entry in reset-names. +- reset-names : Should include the following entries: + - vde + +Optional properties: +- resets : Must contain an entry for each entry in reset-names. +- reset-names : Must include the following entries: + - mc + +Example: + +video-codec@6001a000 { + compatible = "nvidia,tegra20-vde"; + reg = <0x6001a000 0x1000 /* Syntax Engine */ + 0x6001b000 0x1000 /* Video Bitstream Engine */ + 0x6001c000 0x100 /* Macroblock Engine */ + 0x6001c200 0x100 /* Post-processing Engine */ + 0x6001c400 0x100 /* Motion Compensation Engine */ + 0x6001c600 0x100 /* Transform Engine */ + 0x6001c800 0x100 /* Pixel prediction block */ + 0x6001ca00 0x100 /* Video DMA */ + 0x6001d800 0x300 /* Video frame controls */>; + reg-names = "sxe", "bsev", "mbe", "ppe", "mce", + "tfe", "ppb", "vdma", "frameid"; + iram = <&vde_pool>; /* IRAM region */ + interrupts = , /* Sync token interrupt */ + , /* BSE-V interrupt */ + ; /* SXE interrupt */ + interrupt-names = "sync-token", "bsev", "sxe"; + clocks = <&tegra_car TEGRA20_CLK_VDE>; + reset-names = "vde", "mc"; + resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/pxa-camera.txt b/arch/arm64/boot/dts/vendor/bindings/media/pxa-camera.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc03ec096269dc60fb429bc4ef0409c472a39d4a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/pxa-camera.txt @@ -0,0 +1,42 @@ +Marvell PXA camera host interface + +Required properties: + - compatible: Should be "marvell,pxa270-qci" + - reg: register base and size + - interrupts: the interrupt number + - any required generic properties defined in video-interfaces.txt + +Optional properties: + - clocks: input clock (see clock-bindings.txt) + - clock-output-names: should contain the name of the clock driving the + sensor master clock MCLK + - clock-frequency: host interface is driving MCLK, and MCLK rate is this rate + +Example: + + pxa_camera: pxa_camera@50000000 { + compatible = "marvell,pxa270-qci"; + reg = <0x50000000 0x1000>; + interrupts = <33>; + + clocks = <&pxa2xx_clks 24>; + clock-names = "ciclk"; + clock-frequency = <50000000>; + clock-output-names = "qci_mclk"; + + + port { + #address-cells = <1>; + #size-cells = <0>; + + /* Parallel bus endpoint */ + qci: endpoint@0 { + reg = <0>; /* Local endpoint # */ + remote-endpoint = <&mt9m111_1>; + bus-width = <8>; /* Used data lines */ + hsync-active = <0>; /* Active low */ + vsync-active = <0>; /* Active low */ + pclk-sample = <1>; /* Rising */ + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/qcom,camss.txt b/arch/arm64/boot/dts/vendor/bindings/media/qcom,camss.txt new file mode 100644 index 0000000000000000000000000000000000000000..09eb6ed99114abb77b9ad5bbf198f72cf5b602d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/qcom,camss.txt @@ -0,0 +1,229 @@ +Qualcomm Camera Subsystem + +* Properties + +- compatible: + Usage: required + Value type: + Definition: Should contain one of: + - "qcom,msm8916-camss" + - "qcom,msm8996-camss" +- reg: + Usage: required + Value type: + Definition: Register ranges as listed in the reg-names property. +- reg-names: + Usage: required + Value type: + Definition: Should contain the following entries: + - "csiphy0" + - "csiphy0_clk_mux" + - "csiphy1" + - "csiphy1_clk_mux" + - "csiphy2" (8996 only) + - "csiphy2_clk_mux" (8996 only) + - "csid0" + - "csid1" + - "csid2" (8996 only) + - "csid3" (8996 only) + - "ispif" + - "csi_clk_mux" + - "vfe0" + - "vfe1" (8996 only) +- interrupts: + Usage: required + Value type: + Definition: Interrupts as listed in the interrupt-names property. +- interrupt-names: + Usage: required + Value type: + Definition: Should contain the following entries: + - "csiphy0" + - "csiphy1" + - "csiphy2" (8996 only) + - "csid0" + - "csid1" + - "csid2" (8996 only) + - "csid3" (8996 only) + - "ispif" + - "vfe0" + - "vfe1" (8996 only) +- power-domains: + Usage: required + Value type: + Definition: A phandle and power domain specifier pairs to the + power domain which is responsible for collapsing + and restoring power to the peripheral. +- clocks: + Usage: required + Value type: + Definition: A list of phandle and clock specifier pairs as listed + in clock-names property. +- clock-names: + Usage: required + Value type: + Definition: Should contain the following entries: + - "top_ahb" + - "ispif_ahb" + - "csiphy0_timer" + - "csiphy1_timer" + - "csiphy2_timer" (8996 only) + - "csi0_ahb" + - "csi0" + - "csi0_phy" + - "csi0_pix" + - "csi0_rdi" + - "csi1_ahb" + - "csi1" + - "csi1_phy" + - "csi1_pix" + - "csi1_rdi" + - "csi2_ahb" (8996 only) + - "csi2" (8996 only) + - "csi2_phy" (8996 only) + - "csi2_pix" (8996 only) + - "csi2_rdi" (8996 only) + - "csi3_ahb" (8996 only) + - "csi3" (8996 only) + - "csi3_phy" (8996 only) + - "csi3_pix" (8996 only) + - "csi3_rdi" (8996 only) + - "ahb" + - "vfe0" + - "csi_vfe0" + - "vfe0_ahb", (8996 only) + - "vfe0_stream", (8996 only) + - "vfe1", (8996 only) + - "csi_vfe1", (8996 only) + - "vfe1_ahb", (8996 only) + - "vfe1_stream", (8996 only) + - "vfe_ahb" + - "vfe_axi" +- vdda-supply: + Usage: required + Value type: + Definition: A phandle to voltage supply for CSI2. +- iommus: + Usage: required + Value type: + Definition: A list of phandle and IOMMU specifier pairs. + +* Nodes + +- ports: + Usage: required + Definition: As described in video-interfaces.txt in same directory. + Properties: + - reg: + Usage: required + Value type: + Definition: Selects CSI2 PHY interface - PHY0, PHY1 + or PHY2 (8996 only) + Endpoint node properties: + - clock-lanes: + Usage: required + Value type: + Definition: The physical clock lane index. On 8916 + the value must always be <1> as the physical + clock lane is lane 1. On 8996 the value must + always be <7> as the hardware supports D-PHY + and C-PHY, indexes are in a common set and + D-PHY physical clock lane is labeled as 7. + - data-lanes: + Usage: required + Value type: + Definition: An array of physical data lanes indexes. + Position of an entry determines the logical + lane number, while the value of an entry + indicates physical lane index. Lane swapping + is supported. Physical lane indexes for + 8916: 0, 2, 3, 4; for 8996: 0, 1, 2, 3. + +* An Example + + camss: camss@1b00000 { + compatible = "qcom,msm8916-camss"; + reg = <0x1b0ac00 0x200>, + <0x1b00030 0x4>, + <0x1b0b000 0x200>, + <0x1b00038 0x4>, + <0x1b08000 0x100>, + <0x1b08400 0x100>, + <0x1b0a000 0x500>, + <0x1b00020 0x10>, + <0x1b10000 0x1000>; + reg-names = "csiphy0", + "csiphy0_clk_mux", + "csiphy1", + "csiphy1_clk_mux", + "csid0", + "csid1", + "ispif", + "csi_clk_mux", + "vfe0"; + interrupts = , + , + , + , + , + ; + interrupt-names = "csiphy0", + "csiphy1", + "csid0", + "csid1", + "ispif", + "vfe0"; + power-domains = <&gcc VFE_GDSC>; + clocks = <&gcc GCC_CAMSS_TOP_AHB_CLK>, + <&gcc GCC_CAMSS_ISPIF_AHB_CLK>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK>, + <&gcc GCC_CAMSS_CSI0_AHB_CLK>, + <&gcc GCC_CAMSS_CSI0_CLK>, + <&gcc GCC_CAMSS_CSI0PHY_CLK>, + <&gcc GCC_CAMSS_CSI0PIX_CLK>, + <&gcc GCC_CAMSS_CSI0RDI_CLK>, + <&gcc GCC_CAMSS_CSI1_AHB_CLK>, + <&gcc GCC_CAMSS_CSI1_CLK>, + <&gcc GCC_CAMSS_CSI1PHY_CLK>, + <&gcc GCC_CAMSS_CSI1PIX_CLK>, + <&gcc GCC_CAMSS_CSI1RDI_CLK>, + <&gcc GCC_CAMSS_AHB_CLK>, + <&gcc GCC_CAMSS_VFE0_CLK>, + <&gcc GCC_CAMSS_CSI_VFE0_CLK>, + <&gcc GCC_CAMSS_VFE_AHB_CLK>, + <&gcc GCC_CAMSS_VFE_AXI_CLK>; + clock-names = "top_ahb", + "ispif_ahb", + "csiphy0_timer", + "csiphy1_timer", + "csi0_ahb", + "csi0", + "csi0_phy", + "csi0_pix", + "csi0_rdi", + "csi1_ahb", + "csi1", + "csi1_phy", + "csi1_pix", + "csi1_rdi", + "ahb", + "vfe0", + "csi_vfe0", + "vfe_ahb", + "vfe_axi"; + vdda-supply = <&pm8916_l2>; + iommus = <&apps_iommu 3>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + csiphy0_ep: endpoint { + clock-lanes = <1>; + data-lanes = <0 2>; + remote-endpoint = <&ov5645_ep>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/qcom,venus.txt b/arch/arm64/boot/dts/vendor/bindings/media/qcom,venus.txt new file mode 100644 index 0000000000000000000000000000000000000000..00d0d1bf764748381a0d1f02be0b9a97314dde01 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/qcom,venus.txt @@ -0,0 +1,108 @@ +* Qualcomm Venus video encoder/decoder accelerators + +- compatible: + Usage: required + Value type: + Definition: Value should contain one of: + - "qcom,msm8916-venus" + - "qcom,msm8996-venus" + - "qcom,sdm845-venus" +- reg: + Usage: required + Value type: + Definition: Register base address and length of the register map. +- interrupts: + Usage: required + Value type: + Definition: Should contain interrupt line number. +- clocks: + Usage: required + Value type: + Definition: A List of phandle and clock specifier pairs as listed + in clock-names property. +- clock-names: + Usage: required for msm8916 + Value type: + Definition: Should contain the following entries: + - "core" Core video accelerator clock + - "iface" Video accelerator AHB clock + - "bus" Video accelerator AXI clock +- clock-names: + Usage: required for msm8996 + Value type: + Definition: Should contain the following entries: + - "core" Core video accelerator clock + - "iface" Video accelerator AHB clock + - "bus" Video accelerator AXI clock + - "mbus" Video MAXI clock +- power-domains: + Usage: required + Value type: + Definition: A phandle and power domain specifier pairs to the + power domain which is responsible for collapsing + and restoring power to the peripheral. +- iommus: + Usage: required + Value type: + Definition: A list of phandle and IOMMU specifier pairs. +- memory-region: + Usage: required + Value type: + Definition: reference to the reserved-memory for the firmware + memory region. + +* Subnodes +The Venus video-codec node must contain two subnodes representing +video-decoder and video-encoder. + +Every of video-encoder or video-decoder subnode should have: + +- compatible: + Usage: required + Value type: + Definition: Value should contain "venus-decoder" or "venus-encoder" +- clocks: + Usage: required for msm8996 + Value type: + Definition: A List of phandle and clock specifier pairs as listed + in clock-names property. +- clock-names: + Usage: required for msm8996 + Value type: + Definition: Should contain the following entries: + - "core" Subcore video accelerator clock + +- power-domains: + Usage: required for msm8996 + Value type: + Definition: A phandle and power domain specifier pairs to the + power domain which is responsible for collapsing + and restoring power to the subcore. + +* An Example + video-codec@1d00000 { + compatible = "qcom,msm8916-venus"; + reg = <0x01d00000 0xff000>; + interrupts = ; + clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, + <&gcc GCC_VENUS0_AHB_CLK>, + <&gcc GCC_VENUS0_AXI_CLK>; + clock-names = "core", "iface", "bus"; + power-domains = <&gcc VENUS_GDSC>; + iommus = <&apps_iommu 5>; + memory-region = <&venus_mem>; + + video-decoder { + compatible = "venus-decoder"; + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; + clock-names = "core"; + power-domains = <&mmcc VENUS_CORE0_GDSC>; + }; + + video-encoder { + compatible = "venus-encoder"; + clocks = <&mmcc VIDEO_SUBCORE1_CLK>; + clock-names = "core"; + power-domains = <&mmcc VENUS_CORE1_GDSC>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/rc.txt b/arch/arm64/boot/dts/vendor/bindings/media/rc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3e7a012bfda15ef2121e4ee3af7930cb5a3f3a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/rc.txt @@ -0,0 +1,117 @@ +The following properties are common to the infrared remote controllers: + +- linux,rc-map-name: string, specifies the scancode/key mapping table + defined in-kernel for the remote controller. Support values are: + * "rc-adstech-dvb-t-pci" + * "rc-alink-dtu-m" + * "rc-anysee" + * "rc-apac-viewcomp" + * "rc-asus-pc39" + * "rc-asus-ps3-100" + * "rc-ati-tv-wonder-hd-600" + * "rc-ati-x10" + * "rc-avermedia-a16d" + * "rc-avermedia-cardbus" + * "rc-avermedia-dvbt" + * "rc-avermedia-m135a" + * "rc-avermedia-m733a-rm-k6" + * "rc-avermedia-rm-ks" + * "rc-avermedia" + * "rc-avertv-303" + * "rc-azurewave-ad-tu700" + * "rc-behold-columbus" + * "rc-behold" + * "rc-budget-ci-old" + * "rc-cec" + * "rc-cinergy-1400" + * "rc-cinergy" + * "rc-delock-61959" + * "rc-dib0700-nec" + * "rc-dib0700-rc5" + * "rc-digitalnow-tinytwin" + * "rc-digittrade" + * "rc-dm1105-nec" + * "rc-dntv-live-dvbt-pro" + * "rc-dntv-live-dvb-t" + * "rc-dtt200u" + * "rc-dvbsky" + * "rc-empty" + * "rc-em-terratec" + * "rc-encore-enltv2" + * "rc-encore-enltv-fm53" + * "rc-encore-enltv" + * "rc-evga-indtube" + * "rc-eztv" + * "rc-flydvb" + * "rc-flyvideo" + * "rc-fusionhdtv-mce" + * "rc-gadmei-rm008z" + * "rc-geekbox" + * "rc-genius-tvgo-a11mce" + * "rc-gotview7135" + * "rc-hauppauge" + * "rc-imon-mce" + * "rc-imon-pad" + * "rc-iodata-bctv7e" + * "rc-it913x-v1" + * "rc-it913x-v2" + * "rc-kaiomy" + * "rc-kworld-315u" + * "rc-kworld-pc150u" + * "rc-kworld-plus-tv-analog" + * "rc-leadtek-y04g0051" + * "rc-lirc" + * "rc-lme2510" + * "rc-manli" + * "rc-medion-x10" + * "rc-medion-x10-digitainer" + * "rc-medion-x10-or2x" + * "rc-msi-digivox-ii" + * "rc-msi-digivox-iii" + * "rc-msi-tvanywhere-plus" + * "rc-msi-tvanywhere" + * "rc-nebula" + * "rc-nec-terratec-cinergy-xs" + * "rc-norwood" + * "rc-npgtech" + * "rc-pctv-sedna" + * "rc-pinnacle-color" + * "rc-pinnacle-grey" + * "rc-pinnacle-pctv-hd" + * "rc-pixelview-new" + * "rc-pixelview" + * "rc-pixelview-002t" + * "rc-pixelview-mk12" + * "rc-powercolor-real-angel" + * "rc-proteus-2309" + * "rc-purpletv" + * "rc-pv951" + * "rc-hauppauge" + * "rc-rc5-tv" + * "rc-rc6-mce" + * "rc-real-audio-220-32-keys" + * "rc-reddo" + * "rc-snapstream-firefly" + * "rc-streamzap" + * "rc-tbs-nec" + * "rc-technisat-ts35" + * "rc-technisat-usb2" + * "rc-terratec-cinergy-c-pci" + * "rc-terratec-cinergy-s2-hd" + * "rc-terratec-cinergy-xs" + * "rc-terratec-slim" + * "rc-terratec-slim-2" + * "rc-tevii-nec" + * "rc-tivo" + * "rc-total-media-in-hand" + * "rc-total-media-in-hand-02" + * "rc-trekstor" + * "rc-tt-1500" + * "rc-twinhan-dtv-cab-ci" + * "rc-twinhan1027" + * "rc-videomate-k100" + * "rc-videomate-s350" + * "rc-videomate-tv-pvr" + * "rc-winfast" + * "rc-winfast-usbii-deluxe" + * "rc-su3000" diff --git a/arch/arm64/boot/dts/vendor/bindings/media/rcar_vin.txt b/arch/arm64/boot/dts/vendor/bindings/media/rcar_vin.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f420050d57f75883dd964d08b818e4a37cc856b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/rcar_vin.txt @@ -0,0 +1,213 @@ +Renesas R-Car Video Input driver (rcar_vin) +------------------------------------------- + +The rcar_vin device provides video input capabilities for the Renesas R-Car +family of devices. + +Each VIN instance has a single parallel input that supports RGB and YUV video, +with both external synchronization and BT.656 synchronization for the latter. +Depending on the instance the VIN input is connected to external SoC pins, or +on Gen3 platforms to a CSI-2 receiver. + + - compatible: Must be one or more of the following + - "renesas,vin-r8a7743" for the R8A7743 device + - "renesas,vin-r8a7745" for the R8A7745 device + - "renesas,vin-r8a7778" for the R8A7778 device + - "renesas,vin-r8a7779" for the R8A7779 device + - "renesas,vin-r8a7790" for the R8A7790 device + - "renesas,vin-r8a7791" for the R8A7791 device + - "renesas,vin-r8a7792" for the R8A7792 device + - "renesas,vin-r8a7793" for the R8A7793 device + - "renesas,vin-r8a7794" for the R8A7794 device + - "renesas,vin-r8a7795" for the R8A7795 device + - "renesas,vin-r8a7796" for the R8A7796 device + - "renesas,vin-r8a77965" for the R8A77965 device + - "renesas,vin-r8a77970" for the R8A77970 device + - "renesas,vin-r8a77995" for the R8A77995 device + - "renesas,rcar-gen2-vin" for a generic R-Car Gen2 or RZ/G1 compatible + device. + + When compatible with the generic version nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + + - reg: the register base and size for the device registers + - interrupts: the interrupt for the device + - clocks: Reference to the parent clock + +Additionally, an alias named vinX will need to be created to specify +which video input device this is. + +The per-board settings Gen2 platforms: + +- port - sub-node describing a single endpoint connected to the VIN + from external SoC pins as described in video-interfaces.txt[1]. + Only the first one will be considered as each vin interface has one + input port. + + - Optional properties for endpoint nodes: + - hsync-active: see [1] for description. Default is active high. + - vsync-active: see [1] for description. Default is active high. + If both HSYNC and VSYNC polarities are not specified, embedded + synchronization is selected. + - field-active-even: see [1] for description. Default is active high. + - bus-width: see [1] for description. The selected bus width depends on + the SoC type and selected input image format. + Valid values are: 8, 10, 12, 16, 24 and 32. + - data-shift: see [1] for description. Valid values are 0 and 8. + - data-enable-active: polarity of CLKENB signal, see [1] for + description. Default is active high. + +The per-board settings Gen3 platforms: + +Gen3 platforms can support both a single connected parallel input source +from external SoC pins (port@0) and/or multiple parallel input sources +from local SoC CSI-2 receivers (port@1) depending on SoC. + +- renesas,id - ID number of the VIN, VINx in the documentation. +- ports + - port@0 - sub-node describing a single endpoint connected to the VIN + from external SoC pins as described in video-interfaces.txt[1]. + Describing more than one endpoint in port@0 is invalid. Only VIN + instances that are connected to external pins should have port@0. + + Endpoint nodes of port@0 support the optional properties listed in + the Gen2 per-board settings description. + + - port@1 - sub-nodes describing one or more endpoints connected to + the VIN from local SoC CSI-2 receivers. The endpoint numbers must + use the following schema. + + - endpoint@0 - sub-node describing the endpoint connected to CSI20 + - endpoint@1 - sub-node describing the endpoint connected to CSI21 + - endpoint@2 - sub-node describing the endpoint connected to CSI40 + - endpoint@3 - sub-node describing the endpoint connected to CSI41 + + Endpoint nodes of port@1 do not support any optional endpoint property. + +Device node example for Gen2 platforms +-------------------------------------- + + aliases { + vin0 = &vin0; + }; + + vin0: vin@e6ef0000 { + compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin"; + clocks = <&mstp8_clks R8A7790_CLK_VIN0>; + reg = <0 0xe6ef0000 0 0x1000>; + interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + +Board setup example for Gen2 platforms (vin1 composite video input) +------------------------------------------------------------------- + +&i2c2 { + status = "okay"; + pinctrl-0 = <&i2c2_pins>; + pinctrl-names = "default"; + + adv7180@20 { + compatible = "adi,adv7180"; + reg = <0x20>; + remote = <&vin1>; + + port { + adv7180: endpoint { + bus-width = <8>; + remote-endpoint = <&vin1ep0>; + }; + }; + }; +}; + +/* composite video input */ +&vin1 { + pinctrl-0 = <&vin1_pins>; + pinctrl-names = "default"; + + status = "okay"; + + port { + vin1ep0: endpoint { + remote-endpoint = <&adv7180>; + bus-width = <8>; + }; + }; +}; + +Device node example for Gen3 platforms +-------------------------------------- + + vin0: video@e6ef0000 { + compatible = "renesas,vin-r8a7795"; + reg = <0 0xe6ef0000 0 0x1000>; + interrupts = ; + clocks = <&cpg CPG_MOD 811>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 811>; + renesas,id = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + vin0csi20: endpoint@0 { + reg = <0>; + remote-endpoint= <&csi20vin0>; + }; + vin0csi21: endpoint@1 { + reg = <1>; + remote-endpoint= <&csi21vin0>; + }; + vin0csi40: endpoint@2 { + reg = <2>; + remote-endpoint= <&csi40vin0>; + }; + }; + }; + }; + + csi20: csi2@fea80000 { + compatible = "renesas,r8a7795-csi2"; + reg = <0 0xfea80000 0 0x10000>; + interrupts = ; + clocks = <&cpg CPG_MOD 714>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + resets = <&cpg 714>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + csi20_in: endpoint { + clock-lanes = <0>; + data-lanes = <1>; + remote-endpoint = <&adv7482_txb>; + }; + }; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + csi20vin0: endpoint@0 { + reg = <0>; + remote-endpoint = <&vin0csi20>; + }; + }; + }; + }; + +[1] video-interfaces.txt common video media interface diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,ceu.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,ceu.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a7a616e9019b12f2e498b0bfa16ec12958622ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,ceu.txt @@ -0,0 +1,82 @@ +Renesas Capture Engine Unit (CEU) +---------------------------------------------- + +The Capture Engine Unit is the image capture interface found in the Renesas +SH Mobile, R-Mobile and RZ SoCs. + +The interface supports a single parallel input with data bus width of 8 or 16 +bits. + +Required properties: +- compatible: Shall be one of the following values: + "renesas,r7s72100-ceu" for CEU units found in RZ/A1H and RZ/A1M SoCs + "renesas,r8a7740-ceu" for CEU units found in R-Mobile A1 R8A7740 SoCs +- reg: Registers address base and size. +- interrupts: The interrupt specifier. + +The CEU supports a single parallel input and should contain a single 'port' +subnode with a single 'endpoint'. Connection to input devices are modeled +according to the video interfaces OF bindings specified in: +Documentation/devicetree/bindings/media/video-interfaces.txt + +Optional endpoint properties applicable to parallel input bus described in +the above mentioned "video-interfaces.txt" file are supported. + +- hsync-active: Active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. + If property is not present, default is active high. +- vsync-active: Active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. + If property is not present, default is active high. + +Example: + +The example describes the connection between the Capture Engine Unit and an +OV7670 image sensor connected to i2c1 interface. + +ceu: ceu@e8210000 { + reg = <0xe8210000 0x209c>; + compatible = "renesas,r7s72100-ceu"; + interrupts = ; + + pinctrl-names = "default"; + pinctrl-0 = <&vio_pins>; + + status = "okay"; + + port { + ceu_in: endpoint { + remote-endpoint = <&ov7670_out>; + + hsync-active = <1>; + vsync-active = <0>; + }; + }; +}; + +i2c1: i2c@fcfee400 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + + status = "okay"; + + clock-frequency = <100000>; + + ov7670: camera@21 { + compatible = "ovti,ov7670"; + reg = <0x21>; + + pinctrl-names = "default"; + pinctrl-0 = <&vio_pins>; + + reset-gpios = <&port3 11 GPIO_ACTIVE_LOW>; + powerdown-gpios = <&port3 12 GPIO_ACTIVE_HIGH>; + + port { + ov7670_out: endpoint { + remote-endpoint = <&ceu_in>; + + hsync-active = <1>; + vsync-active = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,drif.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,drif.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d8974aa8b38f362bf2331da1094f6000f2ddbb4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,drif.txt @@ -0,0 +1,177 @@ +Renesas R-Car Gen3 Digital Radio Interface controller (DRIF) +------------------------------------------------------------ + +R-Car Gen3 DRIF is a SPI like receive only slave device. A general +representation of DRIF interfacing with a master device is shown below. + ++---------------------+ +---------------------+ +| |-----SCK------->|CLK | +| Master |-----SS-------->|SYNC DRIFn (slave) | +| |-----SD0------->|D0 | +| |-----SD1------->|D1 | ++---------------------+ +---------------------+ + +As per datasheet, each DRIF channel (drifn) is made up of two internal +channels (drifn0 & drifn1). These two internal channels share the common +CLK & SYNC. Each internal channel has its own dedicated resources like +irq, dma channels, address space & clock. This internal split is not +visible to the external master device. + +The device tree model represents each internal channel as a separate node. +The internal channels sharing the CLK & SYNC are tied together by their +phandles using a property called "renesas,bonding". For the rest of +the documentation, unless explicitly stated, the word channel implies an +internal channel. + +When both internal channels are enabled they need to be managed together +as one (i.e.) they cannot operate alone as independent devices. Out of the +two, one of them needs to act as a primary device that accepts common +properties of both the internal channels. This channel is identified by a +property called "renesas,primary-bond". + +To summarize, + - When both the internal channels that are bonded together are enabled, + the zeroth channel is selected as primary-bond. This channels accepts + properties common to all the members of the bond. + - When only one of the bonded channels need to be enabled, the property + "renesas,bonding" or "renesas,primary-bond" will have no effect. That + enabled channel can act alone as any other independent device. + +Required properties of an internal channel: +------------------------------------------- +- compatible: "renesas,r8a7795-drif" if DRIF controller is a part of R8A7795 SoC. + "renesas,r8a7796-drif" if DRIF controller is a part of R8A7796 SoC. + "renesas,rcar-gen3-drif" for a generic R-Car Gen3 compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: offset and length of that channel. +- interrupts: associated with that channel. +- clocks: phandle and clock specifier of that channel. +- clock-names: clock input name string: "fck". +- dmas: phandles to the DMA channels. +- dma-names: names of the DMA channel: "rx". +- renesas,bonding: phandle to the other channel. + +Optional properties of an internal channel: +------------------------------------------- +- power-domains: phandle to the respective power domain. + +Required properties of an internal channel when: + - It is the only enabled channel of the bond (or) + - If it acts as primary among enabled bonds +-------------------------------------------------------- +- pinctrl-0: pin control group to be used for this channel. +- pinctrl-names: must be "default". +- renesas,primary-bond: empty property indicating the channel acts as primary + among the bonded channels. +- port: child port node corresponding to the data input, in accordance with + the video interface bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The port + node must contain at least one endpoint. + +Optional endpoint property: +--------------------------- +- sync-active: Indicates sync signal polarity, 0/1 for low/high respectively. + This property maps to SYNCAC bit in the hardware manual. The + default is 1 (active high). + +Example: +-------- + +(1) Both internal channels enabled: +----------------------------------- + +When interfacing with a third party tuner device with two data pins as shown +below. + ++---------------------+ +---------------------+ +| |-----SCK------->|CLK | +| Master |-----SS-------->|SYNC DRIFn (slave) | +| |-----SD0------->|D0 | +| |-----SD1------->|D1 | ++---------------------+ +---------------------+ + + drif00: rif@e6f40000 { + compatible = "renesas,r8a7795-drif", + "renesas,rcar-gen3-drif"; + reg = <0 0xe6f40000 0 0x64>; + interrupts = ; + clocks = <&cpg CPG_MOD 515>; + clock-names = "fck"; + dmas = <&dmac1 0x20>, <&dmac2 0x20>; + dma-names = "rx", "rx"; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + renesas,bonding = <&drif01>; + renesas,primary-bond; + pinctrl-0 = <&drif0_pins>; + pinctrl-names = "default"; + port { + drif0_ep: endpoint { + remote-endpoint = <&tuner_ep>; + }; + }; + }; + + drif01: rif@e6f50000 { + compatible = "renesas,r8a7795-drif", + "renesas,rcar-gen3-drif"; + reg = <0 0xe6f50000 0 0x64>; + interrupts = ; + clocks = <&cpg CPG_MOD 514>; + clock-names = "fck"; + dmas = <&dmac1 0x22>, <&dmac2 0x22>; + dma-names = "rx", "rx"; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + renesas,bonding = <&drif00>; + }; + + +(2) Internal channel 1 alone is enabled: +---------------------------------------- + +When interfacing with a third party tuner device with one data pin as shown +below. + ++---------------------+ +---------------------+ +| |-----SCK------->|CLK | +| Master |-----SS-------->|SYNC DRIFn (slave) | +| | |D0 (unused) | +| |-----SD-------->|D1 | ++---------------------+ +---------------------+ + + drif00: rif@e6f40000 { + compatible = "renesas,r8a7795-drif", + "renesas,rcar-gen3-drif"; + reg = <0 0xe6f40000 0 0x64>; + interrupts = ; + clocks = <&cpg CPG_MOD 515>; + clock-names = "fck"; + dmas = <&dmac1 0x20>, <&dmac2 0x20>; + dma-names = "rx", "rx"; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + renesas,bonding = <&drif01>; + }; + + drif01: rif@e6f50000 { + compatible = "renesas,r8a7795-drif", + "renesas,rcar-gen3-drif"; + reg = <0 0xe6f50000 0 0x64>; + interrupts = ; + clocks = <&cpg CPG_MOD 514>; + clock-names = "fck"; + dmas = <&dmac1 0x22>, <&dmac2 0x22>; + dma-names = "rx", "rx"; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + renesas,bonding = <&drif00>; + pinctrl-0 = <&drif0_pins>; + pinctrl-names = "default"; + port { + drif0_ep: endpoint { + remote-endpoint = <&tuner_ep>; + sync-active = <0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,fcp.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,fcp.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ec91803ba58c2640415918d6b3af9594c094d42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,fcp.txt @@ -0,0 +1,33 @@ +Renesas R-Car Frame Compression Processor (FCP) +----------------------------------------------- + +The FCP is a companion module of video processing modules in the Renesas R-Car +Gen3 SoCs. It provides data compression and decompression, data caching, and +conversion of AXI transactions in order to reduce the memory bandwidth. + +There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP +for FDP (FCPF). Their configuration and behaviour depend on the module they +are paired with. These DT bindings currently support the FCPV and FCPF. + + - compatible: Must be one or more of the following + + - "renesas,fcpv" for generic compatible 'FCP for VSP' + - "renesas,fcpf" for generic compatible 'FCP for FDP' + + - reg: the register base and size for the device registers + - clocks: Reference to the functional clock + +Optional properties: + - power-domains : power-domain property defined with a power domain specifier + to respective power domain. + + +Device node example +------------------- + + fcpvd1: fcp@fea2f000 { + compatible = "renesas,fcpv"; + reg = <0 0xfea2f000 0 0x200>; + clocks = <&cpg CPG_MOD 602>; + power-domains = <&sysc R8A7795_PD_A3VP>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,fdp1.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,fdp1.txt new file mode 100644 index 0000000000000000000000000000000000000000..8dd1007bb573a28e59fc709a184236ac80a34d27 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,fdp1.txt @@ -0,0 +1,37 @@ +Renesas R-Car Fine Display Processor (FDP1) +------------------------------------------- + +The FDP1 is a de-interlacing module which converts interlaced video to +progressive video. It is capable of performing pixel format conversion between +YCbCr/YUV formats and RGB formats. Only YCbCr/YUV formats are supported as +an input to the module. + +Required properties: + + - compatible: must be "renesas,fdp1" + - reg: the register base and size for the device registers + - interrupts : interrupt specifier for the FDP1 instance + - clocks: reference to the functional clock + +Optional properties: + + - power-domains: reference to the power domain that the FDP1 belongs to, if + any. + - renesas,fcp: a phandle referencing the FCP that handles memory accesses + for the FDP1. Not needed on Gen2, mandatory on Gen3. + +Please refer to the binding documentation for the clock and/or power domain +providers for more details. + + +Device node example +------------------- + + fdp1@fe940000 { + compatible = "renesas,fdp1"; + reg = <0 0xfe940000 0 0x2400>; + interrupts = ; + clocks = <&cpg CPG_MOD 119>; + power-domains = <&sysc R8A7795_PD_A3VP>; + renesas,fcp = <&fcpf0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,jpu.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,jpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3436e5190f9196a64f42fd0872a218a893cc229 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,jpu.txt @@ -0,0 +1,25 @@ +* Renesas JPEG Processing Unit + +The JPEG processing unit (JPU) incorporates the JPEG codec with an encoding +and decoding function conforming to the JPEG baseline process, so that the JPU +can encode image data and decode JPEG data quickly. + +Required properties: +- compatible: "renesas,jpu-", "renesas,rcar-gen2-jpu" as fallback. + Examples with soctypes are: + - "renesas,jpu-r8a7790" for R-Car H2 + - "renesas,jpu-r8a7791" for R-Car M2-W + - "renesas,jpu-r8a7792" for R-Car V2H + - "renesas,jpu-r8a7793" for R-Car M2-N + + - reg: Base address and length of the registers block for the JPU. + - interrupts: JPU interrupt specifier. + - clocks: A phandle + clock-specifier pair for the JPU functional clock. + +Example: R8A7790 (R-Car H2) JPU node + jpeg-codec@fe980000 { + compatible = "renesas,jpu-r8a7790", "renesas,rcar-gen2-jpu"; + reg = <0 0xfe980000 0 0x10300>; + interrupts = <0 272 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_JPU>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,rcar-csi2.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,rcar-csi2.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d385b65b275bc584a0b7022c8f4ea8e2b8c6b99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,rcar-csi2.txt @@ -0,0 +1,101 @@ +Renesas R-Car MIPI CSI-2 +------------------------ + +The R-Car CSI-2 receiver device provides MIPI CSI-2 capabilities for the +Renesas R-Car family of devices. It is used in conjunction with the +R-Car VIN module, which provides the video capture capabilities. + +Mandatory properties +-------------------- + - compatible: Must be one or more of the following + - "renesas,r8a7795-csi2" for the R8A7795 device. + - "renesas,r8a7796-csi2" for the R8A7796 device. + - "renesas,r8a77965-csi2" for the R8A77965 device. + - "renesas,r8a77970-csi2" for the R8A77970 device. + + - reg: the register base and size for the device registers + - interrupts: the interrupt for the device + - clocks: reference to the parent clock + +The device node shall contain two 'port' child nodes according to the +bindings defined in Documentation/devicetree/bindings/media/ +video-interfaces.txt. port@0 shall connect to the CSI-2 source. port@1 +shall connect to all the R-Car VIN modules that have a hardware +connection to the CSI-2 receiver. + +- port@0- Video source (mandatory) + - endpoint@0 - sub-node describing the endpoint that is the video source + +- port@1 - VIN instances (optional) + - One endpoint sub-node for every R-Car VIN instance which is connected + to the R-Car CSI-2 receiver. + +Example: + + csi20: csi2@fea80000 { + compatible = "renesas,r8a7796-csi2"; + reg = <0 0xfea80000 0 0x10000>; + interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 714>; + power-domains = <&sysc R8A7796_PD_ALWAYS_ON>; + resets = <&cpg 714>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <0>; + + csi20_in: endpoint@0 { + reg = <0>; + clock-lanes = <0>; + data-lanes = <1>; + remote-endpoint = <&adv7482_txb>; + }; + }; + + port@1 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <1>; + + csi20vin0: endpoint@0 { + reg = <0>; + remote-endpoint = <&vin0csi20>; + }; + csi20vin1: endpoint@1 { + reg = <1>; + remote-endpoint = <&vin1csi20>; + }; + csi20vin2: endpoint@2 { + reg = <2>; + remote-endpoint = <&vin2csi20>; + }; + csi20vin3: endpoint@3 { + reg = <3>; + remote-endpoint = <&vin3csi20>; + }; + csi20vin4: endpoint@4 { + reg = <4>; + remote-endpoint = <&vin4csi20>; + }; + csi20vin5: endpoint@5 { + reg = <5>; + remote-endpoint = <&vin5csi20>; + }; + csi20vin6: endpoint@6 { + reg = <6>; + remote-endpoint = <&vin6csi20>; + }; + csi20vin7: endpoint@7 { + reg = <7>; + remote-endpoint = <&vin7csi20>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/renesas,vsp1.txt b/arch/arm64/boot/dts/vendor/bindings/media/renesas,vsp1.txt new file mode 100644 index 0000000000000000000000000000000000000000..16427017cb45561e97051d36abe7bcca108c4aa1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/renesas,vsp1.txt @@ -0,0 +1,30 @@ +* Renesas VSP Video Processing Engine + +The VSP is a video processing engine that supports up-/down-scaling, alpha +blending, color space conversion and various other image processing features. +It can be found in the Renesas R-Car second generation SoCs. + +Required properties: + + - compatible: Must contain one of the following values + - "renesas,vsp1" for the R-Car Gen2 VSP1 + - "renesas,vsp2" for the R-Car Gen3 VSP2 + + - reg: Base address and length of the registers block for the VSP. + - interrupts: VSP interrupt specifier. + - clocks: A phandle + clock-specifier pair for the VSP functional clock. + +Optional properties: + + - renesas,fcp: A phandle referencing the FCP that handles memory accesses + for the VSP. Not needed on Gen2, mandatory on Gen3. + + +Example: R8A7790 (R-Car H2) VSP1-S node + + vsp@fe928000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe928000 0 0x8000>; + interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/rockchip-rga.txt b/arch/arm64/boot/dts/vendor/bindings/media/rockchip-rga.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd5276abfad6822e01632302c8dc7b883479cab1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/rockchip-rga.txt @@ -0,0 +1,33 @@ +device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA) + +RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D +graphics operations, such as point/line drawing, image scaling, rotation, +BitBLT, alpha blending and image blur/sharpness. + +Required properties: +- compatible: value should be one of the following + "rockchip,rk3288-rga"; + "rockchip,rk3399-rga"; + +- interrupts: RGA interrupt specifier. + +- clocks: phandle to RGA sclk/hclk/aclk clocks + +- clock-names: should be "aclk", "hclk" and "sclk" + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: should be "core", "axi" and "ahb" + +Example: +SoC-specific DT entry: + rga: rga@ff680000 { + compatible = "rockchip,rk3399-rga"; + reg = <0xff680000 0x10000>; + interrupts = ; + clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>; + clock-names = "aclk", "hclk", "sclk"; + + resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>; + reset-names = "core, "axi", "ahb"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/s5p-cec.txt b/arch/arm64/boot/dts/vendor/bindings/media/s5p-cec.txt new file mode 100644 index 0000000000000000000000000000000000000000..e847291d4aff9014e4907de295075f0be08883dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/s5p-cec.txt @@ -0,0 +1,36 @@ +* Samsung HDMI CEC driver + +The HDMI CEC module is present is Samsung SoCs and its purpose is to +handle communication between HDMI connected devices over the CEC bus. + +Required properties: + - compatible : value should be following + "samsung,s5p-cec" + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : HDMI CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to HDMI CEC clock. + - clock-names : from common clock binding: must contain "hdmicec", + corresponding to entry in the clocks property. + - samsung,syscon-phandle - phandle to the PMU system controller + - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. + +Optional: + - needs-hpd : if present the CEC support is only available when the HPD + is high. See cec.txt for more details. + +Example: + +hdmicec: cec@100b0000 { + compatible = "samsung,s5p-cec"; + reg = <0x100B0000 0x200>; + interrupts = <0 114 0>; + clocks = <&clock CLK_HDMI_CEC>; + clock-names = "hdmicec"; + samsung,syscon-phandle = <&pmu_system_controller>; + hdmi-phandle = <&hdmi>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_cec>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/s5p-mfc.txt b/arch/arm64/boot/dts/vendor/bindings/media/s5p-mfc.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa54c8159d9f0d1c738749b246296f1106da2c47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/s5p-mfc.txt @@ -0,0 +1,76 @@ +* Samsung Multi Format Codec (MFC) + +Multi Format Codec (MFC) is the IP present in Samsung SoCs which +supports high resolution decoding and encoding functionalities. +The MFC device driver is a v4l2 driver which can encode/decode +video raw/elementary streams and has support for all popular +video codecs. + +Required properties: + - compatible : value should be either one among the following + (a) "samsung,mfc-v5" for MFC v5 present in Exynos4 SoCs + (b) "samsung,mfc-v6" for MFC v6 present in Exynos5 SoCs + (c) "samsung,mfc-v7" for MFC v7 present in Exynos5420 SoC + (d) "samsung,mfc-v8" for MFC v8 present in Exynos5800 SoC + (e) "samsung,exynos5433-mfc" for MFC v8 present in Exynos5433 SoC + (f) "samsung,mfc-v10" for MFC v10 present in Exynos7880 SoC + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : MFC interrupt number to the CPU. + - clocks : from common clock binding: handle to mfc clock. + - clock-names : from common clock binding: must contain "mfc", + corresponding to entry in the clocks property. + +Optional properties: + - power-domains : power-domain property defined with a phandle + to respective power domain. + - memory-region : from reserved memory binding: phandles to two reserved + memory regions, first is for "left" mfc memory bus interfaces, + second if for the "right" mfc memory bus, used when no SYSMMU + support is available; used only by MFC v5 present in Exynos4 SoCs + +Obsolete properties: + - samsung,mfc-r, samsung,mfc-l : support removed, please use memory-region + property instead + + +Example: +SoC specific DT entry: + +mfc: codec@13400000 { + compatible = "samsung,mfc-v5"; + reg = <0x13400000 0x10000>; + interrupts = <0 94 0>; + power-domains = <&pd_mfc>; + clocks = <&clock 273>; + clock-names = "mfc"; +}; + +Reserved memory specific DT entry for given board (see reserved memory binding +for more information): + +reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + mfc_left: region@51000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x51000000 0x800000>; + }; + + mfc_right: region@43000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0x43000000 0x800000>; + }; +}; + +Board specific DT entry: + +codec@13400000 { + memory-region = <&mfc_left>, <&mfc_right>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/samsung-fimc.txt b/arch/arm64/boot/dts/vendor/bindings/media/samsung-fimc.txt new file mode 100644 index 0000000000000000000000000000000000000000..48c599dacbdf7baafbc2cc3a64c170a44ba95313 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/samsung-fimc.txt @@ -0,0 +1,209 @@ +Samsung S5P/EXYNOS SoC Camera Subsystem (FIMC) +---------------------------------------------- + +The S5P/Exynos SoC Camera subsystem comprises of multiple sub-devices +represented by separate device tree nodes. Currently this includes: FIMC (in +the S5P SoCs series known as CAMIF), MIPI CSIS, FIMC-LITE and FIMC-IS (ISP). + +The sub-subdevices are defined as child nodes of the common 'camera' node which +also includes common properties of the whole subsystem not really specific to +any single sub-device, like common camera port pins or the CAMCLK clock outputs +for external image sensors attached to an SoC. + +Common 'camera' node +-------------------- + +Required properties: + +- compatible: must be "samsung,fimc", "simple-bus" +- clocks: list of clock specifiers, corresponding to entries in + the clock-names property; +- clock-names : must contain "sclk_cam0", "sclk_cam1", "pxl_async0", + "pxl_async1" entries, matching entries in the clocks property. + +- #clock-cells: from the common clock bindings (../clock/clock-bindings.txt), + must be 1. A clock provider is associated with the 'camera' node and it should + be referenced by external sensors that use clocks provided by the SoC on + CAM_*_CLKOUT pins. The clock specifier cell stores an index of a clock. + The indices are 0, 1 for CAM_A_CLKOUT, CAM_B_CLKOUT clocks respectively. + +- clock-output-names: from the common clock bindings, should contain names of + clocks registered by the camera subsystem corresponding to CAM_A_CLKOUT, + CAM_B_CLKOUT output clocks respectively. + +The pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt must be used +to define a required pinctrl state named "default" and optional pinctrl states: +"idle", "active-a", active-b". These optional states can be used to switch the +camera port pinmux at runtime. The "idle" state should configure both the camera +ports A and B into high impedance state, especially the CAMCLK clock output +should be inactive. For the "active-a" state the camera port A must be activated +and the port B deactivated and for the state "active-b" it should be the other +way around. + +The 'camera' node must include at least one 'fimc' child node. + + +'fimc' device nodes +------------------- + +Required properties: + +- compatible: "samsung,s5pv210-fimc" for S5PV210, "samsung,exynos4210-fimc" + for Exynos4210 and "samsung,exynos4212-fimc" for Exynos4x12 SoCs; +- reg: physical base address and length of the registers set for the device; +- interrupts: should contain FIMC interrupt; +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names; +- clock-names: must contain "fimc", "sclk_fimc" entries. +- samsung,pix-limits: an array of maximum supported image sizes in pixels, for + details refer to Table 2-1 in the S5PV210 SoC User Manual; The meaning of + each cell is as follows: + 0 - scaler input horizontal size, + 1 - input horizontal size for the scaler bypassed, + 2 - REAL_WIDTH without input rotation, + 3 - REAL_HEIGHT with input rotation, +- samsung,sysreg: a phandle to the SYSREG node. + +Each FIMC device should have an alias in the aliases node, in the form of +fimc, where is an integer specifying the IP block instance. + +Optional properties: + +- clock-frequency: maximum FIMC local clock (LCLK) frequency; +- samsung,min-pix-sizes: an array specyfing minimum image size in pixels at + the FIMC input and output DMA, in the first and second cell respectively. + Default value when this property is not present is <16 16>; +- samsung,min-pix-alignment: minimum supported image height alignment (first + cell) and the horizontal image offset (second cell). The values are in pixels + and default to <2 1> when this property is not present; +- samsung,mainscaler-ext: a boolean property indicating whether the FIMC IP + supports extended image size and has CIEXTEN register; +- samsung,rotators: a bitmask specifying whether this IP has the input and + the output rotator. Bits 4 and 0 correspond to input and output rotator + respectively. If a rotator is present its corresponding bit should be set. + Default value when this property is not specified is 0x11. +- samsung,cam-if: a bolean property indicating whether the IP block includes + the camera input interface. +- samsung,isp-wb: this property must be present if the IP block has the ISP + writeback input. +- samsung,lcd-wb: this property must be present if the IP block has the LCD + writeback input. + + +'parallel-ports' node +--------------------- + +This node should contain child 'port' nodes specifying active parallel video +input ports. It includes camera A and camera B inputs. 'reg' property in the +port nodes specifies data input - 0, 1 indicates input A, B respectively. + +Optional properties + +- samsung,camclk-out (deprecated) : specifies clock output for remote sensor, + 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT; + +Image sensor nodes +------------------ + +The sensor device nodes should be added to their control bus controller (e.g. +I2C0) nodes and linked to a port node in the csis or the parallel-ports node, +using the common video interfaces bindings, defined in video-interfaces.txt. + +Example: + + aliases { + fimc0 = &fimc_0; + }; + + /* Parallel bus IF sensor */ + i2c_0: i2c@13860000 { + s5k6aa: sensor@3c { + compatible = "samsung,s5k6aafx"; + reg = <0x3c>; + vddio-supply = <...>; + + clock-frequency = <24000000>; + clocks = <&camera 1>; + clock-names = "mclk"; + + port { + s5k6aa_ep: endpoint { + remote-endpoint = <&fimc0_ep>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <1>; + pclk-sample = <1>; + }; + }; + }; + + /* MIPI CSI-2 bus IF sensor */ + s5c73m3: sensor@1a { + compatible = "samsung,s5c73m3"; + reg = <0x1a>; + vddio-supply = <...>; + + clock-frequency = <24000000>; + clocks = <&camera 0>; + clock-names = "mclk"; + + port { + s5c73m3_1: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&csis0_ep>; + }; + }; + }; + }; + + camera { + compatible = "samsung,fimc", "simple-bus"; + clocks = <&clock 132>, <&clock 133>, <&clock 351>, + <&clock 352>; + clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", + "pxl_async1"; + #clock-cells = <1>; + clock-output-names = "cam_a_clkout", "cam_b_clkout"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_port_a_clk_active>; + #address-cells = <1>; + #size-cells = <1>; + + /* parallel camera ports */ + parallel-ports { + /* camera A input */ + port@0 { + reg = <0>; + fimc0_ep: endpoint { + remote-endpoint = <&s5k6aa_ep>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <1>; + pclk-sample = <1>; + }; + }; + }; + + fimc_0: fimc@11800000 { + compatible = "samsung,exynos4210-fimc"; + reg = <0x11800000 0x1000>; + interrupts = <0 85 0>; + }; + + csis_0: csis@11880000 { + compatible = "samsung,exynos4210-csis"; + reg = <0x11880000 0x1000>; + interrupts = <0 78 0>; + /* camera C input */ + port@3 { + reg = <3>; + csis0_ep: endpoint { + remote-endpoint = <&s5c73m3_ep>; + data-lanes = <1 2 3 4>; + samsung,csis-hs-settle = <12>; + }; + }; + }; + }; + +The MIPI-CSIS device binding is defined in samsung-mipi-csis.txt. diff --git a/arch/arm64/boot/dts/vendor/bindings/media/samsung-mipi-csis.txt b/arch/arm64/boot/dts/vendor/bindings/media/samsung-mipi-csis.txt new file mode 100644 index 0000000000000000000000000000000000000000..be45f0b1a4497bdb8c249baff41a273b0a98d80d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/samsung-mipi-csis.txt @@ -0,0 +1,81 @@ +Samsung S5P/EXYNOS SoC series MIPI CSI-2 receiver (MIPI CSIS) +------------------------------------------------------------- + +Required properties: + +- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110), + "samsung,exynos4210-csis" for Exynos4210 (S5PC210), + "samsung,exynos4212-csis" for Exynos4212/Exynos4412, + "samsung,exynos5250-csis" for Exynos5250; +- reg : offset and length of the register set for the device; +- interrupts : should contain MIPI CSIS interrupt; the format of the + interrupt specifier depends on the interrupt controller; +- bus-width : maximum number of data lanes supported (SoC specific); +- vddio-supply : MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V); +- vddcore-supply : MIPI CSIS Core voltage supply (e.g. 1.1V); +- clocks : list of clock specifiers, corresponding to entries in + clock-names property; +- clock-names : must contain "csis", "sclk_csis" entries, matching entries + in the clocks property. + +Optional properties: + +- clock-frequency : The IP's main (system bus) clock frequency in Hz, default + value when this property is not specified is 166 MHz; +- samsung,csis-wclk : CSI-2 wrapper clock selection. If this property is present + external clock from CMU will be used, or the bus clock if + if it's not specified. + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +media/video-interfaces.txt. The following are properties specific to those nodes. + +port node +--------- + +- reg : (required) must be 3 for camera C input (CSIS0) or 4 for + camera D input (CSIS1); + +endpoint node +------------- + +- data-lanes : (required) an array specifying active physical MIPI-CSI2 + data input lanes and their mapping to logical lanes; the + array's content is unused, only its length is meaningful; + +- samsung,csis-hs-settle : (optional) differential receiver (HS-RX) settle time; + + +Example: + + reg0: regulator@0 { + }; + + reg1: regulator@1 { + }; + +/* SoC properties */ + + csis_0: csis@11880000 { + compatible = "samsung,exynos4210-csis"; + reg = <0x11880000 0x1000>; + interrupts = <0 78 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + +/* Board properties */ + + csis_0: csis@11880000 { + clock-frequency = <166000000>; + vddio-supply = <®0>; + vddcore-supply = <®1>; + port { + reg = <3>; /* 3 - CSIS0, 4 - CSIS1 */ + csis0_ep: endpoint { + remote-endpoint = <...>; + data-lanes = <1>, <2>; + samsung,csis-hs-settle = <12>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5c73m3.txt b/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5c73m3.txt new file mode 100644 index 0000000000000000000000000000000000000000..21f31fdf5543108309590bb27cf21a97e72a69de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5c73m3.txt @@ -0,0 +1,97 @@ +Samsung S5C73M3 8Mp camera ISP +------------------------------ + +The S5C73M3 camera ISP supports MIPI CSI-2 and parallel (ITU-R BT.656) video +data busses. The I2C bus is the main control bus and additionally the SPI bus +is used, mostly for transferring the firmware to and from the device. Two +slave device nodes corresponding to these control bus interfaces are required +and should be placed under respective bus controller nodes. + +I2C slave device node +--------------------- + +Required properties: + +- compatible : "samsung,s5c73m3"; +- reg : I2C slave address of the sensor; +- vdd-int-supply : digital power supply (1.2V); +- vdda-supply : analog power supply (1.2V); +- vdd-reg-supply : regulator input power supply (2.8V); +- vddio-host-supply : host I/O power supply (1.8V to 2.8V); +- vddio-cis-supply : CIS I/O power supply (1.2V to 1.8V); +- vdd-af-supply : lens power supply (2.8V); +- xshutdown-gpios : specifier of GPIO connected to the XSHUTDOWN pin; +- standby-gpios : specifier of GPIO connected to the STANDBY pin; +- clocks : should contain list of phandle and clock specifier pairs + according to common clock bindings for the clocks described + in the clock-names property; +- clock-names : should contain "cis_extclk" entry for the CIS_EXTCLK clock; + +Optional properties: + +- clock-frequency : the frequency at which the "cis_extclk" clock should be + configured to operate, in Hz; if this property is not + specified default 24 MHz value will be used. + +The common video interfaces bindings (see video-interfaces.txt) should be used +to specify link from the S5C73M3 to an external image data receiver. The S5C73M3 +device node should contain one 'port' child node with an 'endpoint' subnode for +this purpose. The data link from a raw image sensor to the S5C73M3 can be +similarly specified, but it is optional since the S5C73M3 ISP and a raw image +sensor are usually inseparable and form a hybrid module. + +Following properties are valid for the endpoint node(s): + +endpoint subnode +---------------- + +- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in + video-interfaces.txt. This sensor doesn't support data lane remapping + and physical lane indexes in subsequent elements of the array should + be only consecutive ascending values. + +SPI device node +--------------- + +Required properties: + +- compatible : "samsung,s5c73m3"; + +For more details see description of the SPI busses bindings +(../spi/spi-bus.txt) and bindings of a specific bus controller. + +Example: + +i2c@138a000000 { + ... + s5c73m3@3c { + compatible = "samsung,s5c73m3"; + reg = <0x3c>; + vdd-int-supply = <&buck9_reg>; + vdda-supply = <&ldo17_reg>; + vdd-reg-supply = <&cam_io_reg>; + vddio-host-supply = <&ldo18_reg>; + vddio-cis-supply = <&ldo9_reg>; + vdd-af-supply = <&cam_af_reg>; + clock-frequency = <24000000>; + clocks = <&clk 0>; + clock-names = "cis_extclk"; + reset-gpios = <&gpf1 3 1>; + standby-gpios = <&gpm0 1 1>; + port { + s5c73m3_ep: endpoint { + remote-endpoint = <&csis0_ep>; + data-lanes = <1 2 3 4>; + }; + }; + }; +}; + +spi@1392000 { + ... + s5c73m3_spi: s5c73m3@0 { + compatible = "samsung,s5c73m3"; + reg = <0>; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5k5baf.txt b/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5k5baf.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f51e0439c962db4b796770189d52da7d14f7914 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5k5baf.txt @@ -0,0 +1,58 @@ +Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor with embedded SoC ISP +-------------------------------------------------------------------- + +Required properties: + +- compatible : "samsung,s5k5baf"; +- reg : I2C slave address of the sensor; +- vdda-supply : analog power supply 2.8V (2.6V to 3.0V); +- vddreg-supply : regulator input power supply 1.8V (1.7V to 1.9V) + or 2.8V (2.6V to 3.0); +- vddio-supply : I/O power supply 1.8V (1.65V to 1.95V) + or 2.8V (2.5V to 3.1V); +- stbyn-gpios : GPIO connected to STDBYN pin; +- rstn-gpios : GPIO connected to RSTN pin; +- clocks : list of phandle and clock specifier pairs + according to common clock bindings for the + clocks described in clock-names; +- clock-names : should include "mclk" for the sensor's master clock; + +Optional properties: + +- clock-frequency : the frequency at which the "mclk" clock should be + configured to operate, in Hz; if this property is not + specified default 24 MHz value will be used. + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +media/video-interfaces.txt. The following are properties specific to those +nodes. + +endpoint node +------------- + +- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in + video-interfaces.txt. If present it should be <1> - the device + supports only one data lane without re-mapping. + +Example: + +s5k5bafx@2d { + compatible = "samsung,s5k5baf"; + reg = <0x2d>; + vdda-supply = <&cam_io_en_reg>; + vddreg-supply = <&vt_core_15v_reg>; + vddio-supply = <&vtcam_reg>; + stbyn-gpios = <&gpl2 0 1>; + rstn-gpios = <&gpl2 1 1>; + clock-names = "mclk"; + clocks = <&clock_cam 0>; + clock-frequency = <24000000>; + + port { + s5k5bafx_ep: endpoint { + remote-endpoint = <&csis1_ep>; + data-lanes = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5k6a3.txt b/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5k6a3.txt new file mode 100644 index 0000000000000000000000000000000000000000..cce01e82f3e3ad9db12d078f0da7da18b882f31d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/samsung-s5k6a3.txt @@ -0,0 +1,33 @@ +Samsung S5K6A3(YX) raw image sensor +--------------------------------- + +S5K6A3(YX) is a raw image sensor with MIPI CSI-2 and CCP2 image data interfaces +and CCI (I2C compatible) control bus. + +Required properties: + +- compatible : "samsung,s5k6a3"; +- reg : I2C slave address of the sensor; +- svdda-supply : core voltage supply; +- svddio-supply : I/O voltage supply; +- afvdd-supply : AF (actuator) voltage supply; +- gpios : specifier of a GPIO connected to the RESET pin; +- clocks : should contain list of phandle and clock specifier pairs + according to common clock bindings for the clocks described + in the clock-names property; +- clock-names : should contain "extclk" entry for the sensor's EXTCLK clock; + +Optional properties: + +- clock-frequency : the frequency at which the "extclk" clock should be + configured to operate, in Hz; if this property is not + specified default 24 MHz value will be used. + +The common video interfaces bindings (see video-interfaces.txt) should be +used to specify link to the image data receiver. The S5K6A3(YX) device +node should contain one 'port' child node with an 'endpoint' subnode. + +Following properties are valid for the endpoint node: + +- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in + video-interfaces.txt. The sensor supports only one data lane. diff --git a/arch/arm64/boot/dts/vendor/bindings/media/sh_mobile_ceu.txt b/arch/arm64/boot/dts/vendor/bindings/media/sh_mobile_ceu.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfa4ffada8ae55bbac035ee1cabf85fea8f5bab6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/sh_mobile_ceu.txt @@ -0,0 +1,17 @@ +Bindings, specific for the sh_mobile_ceu_camera.c driver: + - compatible: Should be "renesas,sh-mobile-ceu" + - reg: register base and size + - interrupts: the interrupt number + - renesas,max-width: maximum image width, supported on this SoC + - renesas,max-height: maximum image height, supported on this SoC + +Example: + +ceu0: ceu@fe910000 { + compatible = "renesas,sh-mobile-ceu"; + reg = <0xfe910000 0xa0>; + interrupt-parent = <&intcs>; + interrupts = <0x880>; + renesas,max-width = <8188>; + renesas,max-height = <8188>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/si4713.txt b/arch/arm64/boot/dts/vendor/bindings/media/si4713.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ee5552d346535a2dc578cec8fb858ccc3275c81 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/si4713.txt @@ -0,0 +1,30 @@ +* Silicon Labs FM Radio transmitter + +The Silicon Labs Si4713 is an FM radio transmitter with receive power scan +supporting 76-108 MHz. It includes an RDS encoder and has both, a stereo-analog +and a digital interface, which supports I2S, left-justified and a custom +DSP-mode format. It is programmable through an I2C interface. + +Required Properties: +- compatible: Should contain "silabs,si4713" +- reg: the I2C address of the device + +Optional Properties: +- interrupts-extended: Interrupt specifier for the chips interrupt +- reset-gpios: GPIO specifier for the chips reset line +- vdd-supply: phandle for Vdd regulator +- vio-supply: phandle for Vio regulator + +Example: + +&i2c2 { + fmtx: si4713@63 { + compatible = "silabs,si4713"; + reg = <0x63>; + + interrupts-extended = <&gpio2 21 IRQ_TYPE_EDGE_FALLING>; /* 53 */ + reset-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 */ + vio-supply = <&vio>; + vdd-supply = <&vaux1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/spi/sony-cxd2880.txt b/arch/arm64/boot/dts/vendor/bindings/media/spi/sony-cxd2880.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc5aa263abe53dfe6caffaa40dcb6d501523951a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/spi/sony-cxd2880.txt @@ -0,0 +1,14 @@ +Sony CXD2880 DVB-T2/T tuner + demodulator driver SPI adapter + +Required properties: +- compatible: Should be "sony,cxd2880". +- reg: SPI chip select number for the device. +- spi-max-frequency: Maximum bus speed, should be set to <55000000> (55MHz). + +Example: + +cxd2880@0 { + compatible = "sony,cxd2880"; + reg = <0>; /* CE0 */ + spi-max-frequency = <55000000>; /* 55MHz */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/st,st-delta.txt b/arch/arm64/boot/dts/vendor/bindings/media/st,st-delta.txt new file mode 100644 index 0000000000000000000000000000000000000000..a538ab30a617a25e2211321197a94185f9843bbf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/st,st-delta.txt @@ -0,0 +1,17 @@ +* STMicroelectronics DELTA multi-format video decoder + +Required properties: +- compatible: should be "st,st-delta". +- clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend on the SoC type. + See ../clock/clock-bindings.txt for details. +- clock-names: names of the clocks listed in clocks property in the same order. + +Example: + delta0 { + compatible = "st,st-delta"; + clock-names = "delta", "delta-st231", "delta-flash-promip"; + clocks = <&clk_s_c0_flexgen CLK_VID_DMU>, + <&clk_s_c0_flexgen CLK_ST231_DMU>, + <&clk_s_c0_flexgen CLK_FLASH_PROMIP>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/st,st-hva.txt b/arch/arm64/boot/dts/vendor/bindings/media/st,st-hva.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d76174a1f7e9eb4de66f08a6cfbeeee6571e7b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/st,st-hva.txt @@ -0,0 +1,24 @@ +st-hva: multi-format video encoder for STMicroelectronics SoC. + +Required properties: +- compatible: should be "st,st-hva". +- reg: HVA physical address location and length, esram address location and + length. +- reg-names: names of the registers listed in registers property in the same + order. +- interrupts: HVA interrupt number. +- clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend on the SoC type. + See ../clock/clock-bindings.txt for details. +- clock-names: names of the clocks listed in clocks property in the same order. + +Example: + hva@8c85000{ + compatible = "st,st-hva"; + reg = <0x8c85000 0x400>, <0x6000000 0x40000>; + reg-names = "hva_registers", "hva_esram"; + interrupts = , + ; + clock-names = "clk_hva"; + clocks = <&clk_s_c0_flexgen CLK_HVA>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/st,stih4xx.txt b/arch/arm64/boot/dts/vendor/bindings/media/st,stih4xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..df655cd3a4f8beaf81627671dd5d4362680ba7e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/st,stih4xx.txt @@ -0,0 +1,32 @@ +STMicroelectronics stih4xx platforms + +bdisp: 2D blitter for STMicroelectronics SoC. + +Required properties: +- compatible: should be "st,stih407-bdisp". +- reg: BDISP physical address location and length. +- interrupts: BDISP interrupt number. +- clocks: from common clock binding: handle hardware IP needed clocks, the + number of clocks may depend on the SoC type. + See ../clocks/clock-bindings.txt for details. +- clock-names: names of the clocks listed in clocks property in the same order. + +Example: + + bdisp0:bdisp@9f10000 { + compatible = "st,stih407-bdisp"; + reg = <0x9f10000 0x1000>; + interrupts = ; + clock-names = "bdisp"; + clocks = <&clk_s_c0_flexgen CLK_IC_BDISP_0>; + }; + +Aliases: +Each BDISP should have a numbered alias in the aliases node, in the form of +bdispN, N = 0 or 1. + +Example: + + aliases { + bdisp0 = &bdisp0; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/st,stm32-cec.txt b/arch/arm64/boot/dts/vendor/bindings/media/st,stm32-cec.txt new file mode 100644 index 0000000000000000000000000000000000000000..6be2381c180d0e3c667813491b1429e5ae53ba6e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/st,stm32-cec.txt @@ -0,0 +1,19 @@ +STMicroelectronics STM32 CEC driver + +Required properties: + - compatible : value should be "st,stm32-cec" + - reg : Physical base address of the IP registers and length of memory + mapped region. + - clocks : from common clock binding: handle to CEC clocks + - clock-names : from common clock binding: must be "cec" and "hdmi-cec". + - interrupts : CEC interrupt number to the CPU. + +Example for stm32f746: + +cec: cec@40006c00 { + compatible = "st,stm32-cec"; + reg = <0x40006C00 0x400>; + interrupts = <94>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>; + clock-names = "cec", "hdmi-cec"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/st,stm32-dcmi.txt b/arch/arm64/boot/dts/vendor/bindings/media/st,stm32-dcmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..249790a93017571da5cf3f9366737f8a5a5f7a49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/st,stm32-dcmi.txt @@ -0,0 +1,45 @@ +STMicroelectronics STM32 Digital Camera Memory Interface (DCMI) + +Required properties: +- compatible: "st,stm32-dcmi" +- reg: physical base address and length of the registers set for the device +- interrupts: should contain IRQ line for the DCMI +- resets: reference to a reset controller, + see Documentation/devicetree/bindings/reset/st,stm32-rcc.txt +- clocks: list of clock specifiers, corresponding to entries in + the clock-names property +- clock-names: must contain "mclk", which is the DCMI peripherial clock +- pinctrl: the pincontrol settings to configure muxing properly + for pins that connect to DCMI device. + See Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt. +- dmas: phandle to DMA controller node, + see Documentation/devicetree/bindings/dma/stm32-dma.txt +- dma-names: must contain "tx", which is the transmit channel from DCMI to DMA + +DCMI supports a single port node with parallel bus. It should contain one +'port' child node with child 'endpoint' node. Please refer to the bindings +defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + dcmi: dcmi@50050000 { + compatible = "st,stm32-dcmi"; + reg = <0x50050000 0x400>; + interrupts = <78>; + resets = <&rcc STM32F4_AHB2_RESET(DCMI)>; + clocks = <&rcc 0 STM32F4_AHB2_CLOCK(DCMI)>; + clock-names = "mclk"; + pinctrl-names = "default"; + pinctrl-0 = <&dcmi_pins>; + dmas = <&dma2 1 1 0x414 0x3>; + dma-names = "tx"; + port { + dcmi_0: endpoint { + remote-endpoint = <...>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/st-rc.txt b/arch/arm64/boot/dts/vendor/bindings/media/st-rc.txt new file mode 100644 index 0000000000000000000000000000000000000000..05c432d08bcade2ee46c69c57e5d0f2f4f678b00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/st-rc.txt @@ -0,0 +1,29 @@ +Device-Tree bindings for ST IRB IP + +Required properties: + - compatible: Should contain "st,comms-irb". + - reg: Base physical address of the controller and length of memory + mapped region. + - interrupts: interrupt-specifier for the sole interrupt generated by + the device. The interrupt specifier format depends on the interrupt + controller parent. + - rx-mode: can be "infrared" or "uhf". This property specifies the L1 + protocol used for receiving remote control signals. rx-mode should + be present iff the rx pins are wired up. + - tx-mode: should be "infrared". This property specifies the L1 + protocol used for transmitting remote control signals. tx-mode should + be present iff the tx pins are wired up. + +Optional properties: + - pinctrl-names, pinctrl-0: the pincontrol settings to configure muxing + properly for IRB pins. + - clocks : phandle with clock-specifier pair for IRB. + +Example node: + + rc: rc@fe518000 { + compatible = "st,comms-irb"; + reg = <0xfe518000 0x234>; + interrupts = <0 203 0>; + rx-mode = "infrared"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/stih-cec.txt b/arch/arm64/boot/dts/vendor/bindings/media/stih-cec.txt new file mode 100644 index 0000000000000000000000000000000000000000..ece0832fdeaff7e33903fa759fc6edd90c88bd90 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/stih-cec.txt @@ -0,0 +1,27 @@ +STMicroelectronics STIH4xx HDMI CEC driver + +Required properties: + - compatible : value should be "st,stih-cec" + - reg : Physical base address of the IP registers and length of memory + mapped region. + - clocks : from common clock binding: handle to HDMI CEC clock + - interrupts : HDMI CEC interrupt number to the CPU. + - pinctrl-names: Contains only one value - "default" + - pinctrl-0: Specifies the pin control groups used for CEC hardware. + - resets: Reference to a reset controller + - hdmi-phandle: Phandle to the HDMI controller, see also cec.txt. + +Example for STIH407: + +sti-cec@94a087c { + compatible = "st,stih-cec"; + reg = <0x94a087c 0x64>; + clocks = <&clk_sysin>; + clock-names = "cec-clk"; + interrupts = ; + interrupt-names = "cec-irq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_cec0_default>; + resets = <&softreset STIH407_LPM_SOFTRESET>; + hdmi-phandle = <&hdmi>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/stih407-c8sectpfe.txt b/arch/arm64/boot/dts/vendor/bindings/media/stih407-c8sectpfe.txt new file mode 100644 index 0000000000000000000000000000000000000000..880d4d70c9fd741ac13101721ced18f04336c373 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/stih407-c8sectpfe.txt @@ -0,0 +1,88 @@ +STMicroelectronics STi c8sectpfe binding +============================================ + +This document describes the c8sectpfe device bindings that is used to get transport +stream data into the SoC on the TS pins, and into DDR for further processing. + +It is typically used in conjunction with one or more demodulator and tuner devices +which converts from the RF to digital domain. Demodulators and tuners are usually +located on an external DVB frontend card connected to SoC TS input pins. + +Currently 7 TS input (tsin) channels are supported on the stih407 family SoC. + +Required properties (controller (parent) node): +- compatible : Should be "stih407-c8sectpfe" + +- reg : Address and length of register sets for each device in + "reg-names" + +- reg-names : The names of the register addresses corresponding to the + registers filled in "reg": + - c8sectpfe: c8sectpfe registers + - c8sectpfe-ram: c8sectpfe internal sram + +- clocks : phandle list of c8sectpfe clocks +- clock-names : should be "c8sectpfe" +See: Documentation/devicetree/bindings/clock/clock-bindings.txt + +- pinctrl-names : a pinctrl state named tsin%d-serial or tsin%d-parallel (where %d is tsin-num) + must be defined for each tsin child node. +- pinctrl-0 : phandle referencing pin configuration for this tsin configuration +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + + +Required properties (tsin (child) node): + +- tsin-num : tsin id of the InputBlock (must be between 0 to 6) +- i2c-bus : phandle to the I2C bus DT node which the demodulators & tuners on this tsin channel are connected. +- reset-gpios : reset gpio for this tsin channel. + +Optional properties (tsin (child) node): + +- invert-ts-clk : Bool property to control sense of ts input clock (data stored on falling edge of clk). +- serial-not-parallel : Bool property to configure input bus width (serial on ts_data<7>). +- async-not-sync : Bool property to control if data is received in asynchronous mode + (all bits/bytes with ts_valid or ts_packet asserted are valid). + +- dvb-card : Describes the NIM card connected to this tsin channel. + +Example: + +/* stih410 SoC b2120 + b2004a + stv0367-pll(NIMB) + stv0367-tda18212 (NIMA) DT example) */ + + c8sectpfe@8a20000 { + compatible = "st,stih407-c8sectpfe"; + reg = <0x08a20000 0x10000>, <0x08a00000 0x4000>; + reg-names = "stfe", "stfe-ram"; + interrupts = , ; + interrupt-names = "stfe-error-irq", "stfe-idle-irq"; + pinctrl-0 = <&pinctrl_tsin0_serial>; + pinctrl-1 = <&pinctrl_tsin0_parallel>; + pinctrl-2 = <&pinctrl_tsin3_serial>; + pinctrl-3 = <&pinctrl_tsin4_serial_alt3>; + pinctrl-4 = <&pinctrl_tsin5_serial_alt1>; + pinctrl-names = "tsin0-serial", + "tsin0-parallel", + "tsin3-serial", + "tsin4-serial", + "tsin5-serial"; + clocks = <&clk_s_c0_flexgen CLK_PROC_STFE>; + clock-names = "c8sectpfe"; + + /* tsin0 is TSA on NIMA */ + tsin0: port@0 { + tsin-num = <0>; + serial-not-parallel; + i2c-bus = <&ssc2>; + reset-gpios = <&pio15 4 GPIO_ACTIVE_HIGH>; + dvb-card = ; + }; + + tsin3: port@3 { + tsin-num = <3>; + serial-not-parallel; + i2c-bus = <&ssc3>; + reset-gpios = <&pio15 7 GPIO_ACTIVE_HIGH>; + dvb-card = ; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/sunxi-ir.txt b/arch/arm64/boot/dts/vendor/bindings/media/sunxi-ir.txt new file mode 100644 index 0000000000000000000000000000000000000000..278098987edbd5990850d50e6992f7091dd0d392 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/sunxi-ir.txt @@ -0,0 +1,28 @@ +Device-Tree bindings for SUNXI IR controller found in sunXi SoC family + +Required properties: +- compatible : "allwinner,sun4i-a10-ir" or "allwinner,sun5i-a13-ir" +- clocks : list of clock specifiers, corresponding to + entries in clock-names property; +- clock-names : should contain "apb" and "ir" entries; +- interrupts : should contain IR IRQ number; +- reg : should contain IO map address for IR. + +Optional properties: +- linux,rc-map-name: see rc.txt file in the same directory. +- resets : phandle + reset specifier pair +- clock-frequency : IR Receiver clock frequency, in Hertz. Defaults to 8 MHz + if missing. + +Example: + +ir0: ir@1c21800 { + compatible = "allwinner,sun4i-a10-ir"; + clocks = <&apb0_gates 6>, <&ir0_clk>; + clock-names = "apb", "ir"; + clock-frequency = <3000000>; + resets = <&apb0_rst 1>; + interrupts = <0 5 1>; + reg = <0x01C21800 0x40>; + linux,rc-map-name = "rc-rc6-mce"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/tango-ir.txt b/arch/arm64/boot/dts/vendor/bindings/media/tango-ir.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9f00c2bf8970efa628267c1b5a03dc0aa5566af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/tango-ir.txt @@ -0,0 +1,21 @@ +Sigma Designs Tango IR NEC/RC-5/RC-6 decoder (SMP86xx and SMP87xx) + +Required properties: + +- compatible: "sigma,smp8642-ir" +- reg: address/size of NEC+RC5 area, address/size of RC6 area +- interrupts: spec for IR IRQ +- clocks: spec for IR clock (typically the crystal oscillator) + +Optional properties: + +- linux,rc-map-name: see Documentation/devicetree/bindings/media/rc.txt + +Example: + + ir@10518 { + compatible = "sigma,smp8642-ir"; + reg = <0x10518 0x18>, <0x105e0 0x1c>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/tegra-cec.txt b/arch/arm64/boot/dts/vendor/bindings/media/tegra-cec.txt new file mode 100644 index 0000000000000000000000000000000000000000..c503f06f3b844bba5b8bcab0a5c319fea2a7cc15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/tegra-cec.txt @@ -0,0 +1,27 @@ +* Tegra HDMI CEC hardware + +The HDMI CEC module is present in Tegra SoCs and its purpose is to +handle communication between HDMI connected devices over the CEC bus. + +Required properties: + - compatible : value should be one of the following: + "nvidia,tegra114-cec" + "nvidia,tegra124-cec" + "nvidia,tegra210-cec" + - reg : Physical base address of the IP registers and length of memory + mapped region. + - interrupts : HDMI CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to HDMI CEC clock. + - clock-names : from common clock binding: must contain "cec", + corresponding to the entry in the clocks property. + - hdmi-phandle : phandle to the HDMI controller, see also cec.txt. + +Example: + +cec@70015000 { + compatible = "nvidia,tegra124-cec"; + reg = <0x0 0x70015000 0x0 0x00001000>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_CEC>; + clock-names = "cec"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/ti,da850-vpif.txt b/arch/arm64/boot/dts/vendor/bindings/media/ti,da850-vpif.txt new file mode 100644 index 0000000000000000000000000000000000000000..e47c7ccc57f11ec53fe9aa5eb28b4c48e6397a27 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/ti,da850-vpif.txt @@ -0,0 +1,106 @@ +Texas Instruments VPIF +---------------------- + +The TI Video Port InterFace (VPIF) is the primary component for video +capture and display on the DA850/AM18x family of TI DaVinci/Sitara +SoCs. + +TI Document reference: SPRUH82C, Chapter 35 +http://www.ti.com/lit/pdf/spruh82 + +Required properties: +- compatible: must be "ti,da850-vpif" +- reg: physical base address and length of the registers set for the device; +- interrupts: should contain IRQ line for the VPIF + +Video Capture: + +VPIF has a 16-bit parallel bus input, supporting 2 8-bit channels or a +single 16-bit channel. It should contain one or two port child nodes +with child 'endpoint' node. If there are two ports then port@0 must +describe the input and port@1 output channels. Please refer to the +bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example using 2 8-bit input channels, one of which is connected to an +I2C-connected TVP5147 decoder: + + vpif: vpif@217000 { + compatible = "ti,da850-vpif"; + reg = <0x217000 0x1000>; + interrupts = <92>; + + port@0 { + vpif_input_ch0: endpoint@0 { + reg = <0>; + bus-width = <8>; + remote-endpoint = <&composite_in>; + }; + + vpif_input_ch1: endpoint@1 { + reg = <1>; + bus-width = <8>; + data-shift = <8>; + }; + }; + + port@1 { + vpif_output_ch0: endpoint { + bus-width = <8>; + remote-endpoint = <&composite_out>; + }; + }; + }; + +[ ... ] + +&i2c0 { + + tvp5147@5d { + compatible = "ti,tvp5147"; + reg = <0x5d>; + + port { + composite_in: endpoint { + hsync-active = <1>; + vsync-active = <1>; + pclk-sample = <0>; + + /* VPIF channel 0 (lower 8-bits) */ + remote-endpoint = <&vpif_input_ch0>; + bus-width = <8>; + }; + }; + }; + + adv7343@2a { + compatible = "adi,adv7343"; + reg = <0x2a>; + + port { + composite_out: endpoint { + adi,dac-enable = <1 1 1>; + adi,sd-dac-enable = <1>; + + remote-endpoint = <&vpif_output_ch0>; + bus-width = <8>; + }; + }; + }; +}; + + +Alternatively, an example when the bus is configured as a single +16-bit input (e.g. for raw-capture mode): + + vpif: vpif@217000 { + compatible = "ti,da850-vpif"; + reg = <0x217000 0x1000>; + interrupts = <92>; + + port { + vpif_ch0: endpoint { + bus-width = <16>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/ti,omap3isp.txt b/arch/arm64/boot/dts/vendor/bindings/media/ti,omap3isp.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac23de8556412c52710f46c3ea015d2976c96dad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/ti,omap3isp.txt @@ -0,0 +1,71 @@ +OMAP 3 ISP Device Tree bindings +=============================== + +The DT definitions can be found in include/dt-bindings/media/omap3-isp.h. + +Required properties +=================== + +compatible : must contain "ti,omap3-isp" + +reg : the two registers sets (physical address and length) for the + ISP. The first set contains the core ISP registers up to + the end of the SBL block. The second set contains the + CSI PHYs and receivers registers. +interrupts : the ISP interrupt specifier +iommus : phandle and IOMMU specifier for the IOMMU that serves the ISP +syscon : the phandle and register offset to the Complex I/O or CSI-PHY + register +ti,phy-type : 0 -- OMAP3ISP_PHY_TYPE_COMPLEX_IO (e.g. 3430) + 1 -- OMAP3ISP_PHY_TYPE_CSIPHY (e.g. 3630) +#clock-cells : Must be 1 --- the ISP provides two external clocks, + cam_xclka and cam_xclkb, at indices 0 and 1, + respectively. Please find more information on common + clock bindings in ../clock/clock-bindings.txt. + +Port nodes (optional) +--------------------- + +More documentation on these bindings is available in +video-interfaces.txt in the same directory. + +reg : The interface: + 0 - parallel (CCDC) + 1 - CSIPHY1 -- CSI2C / CCP2B on 3630; + CSI1 -- CSIb on 3430 + 2 - CSIPHY2 -- CSI2A / CCP2B on 3630; + CSI2 -- CSIa on 3430 + +Optional properties +=================== + +vdd-csiphy1-supply : voltage supply of the CSI-2 PHY 1 +vdd-csiphy2-supply : voltage supply of the CSI-2 PHY 2 + +Endpoint nodes +-------------- + +lane-polarities : lane polarity (required on CSI-2) + 0 -- not inverted; 1 -- inverted +data-lanes : an array of data lanes from 1 to 3. The length can + be either 1 or 2. (required on CSI-2) +clock-lanes : the clock lane (from 1 to 3). (required on CSI-2) + + +Example +======= + + isp@480bc000 { + compatible = "ti,omap3-isp"; + reg = <0x480bc000 0x12fc + 0x480bd800 0x0600>; + interrupts = <24>; + iommus = <&mmu_isp>; + syscon = <&scm_conf 0x2f0>; + ti,phy-type = ; + #clock-cells = <1>; + ports { + #address-cells = <1>; + #size-cells = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/ti-am437x-vpfe.txt b/arch/arm64/boot/dts/vendor/bindings/media/ti-am437x-vpfe.txt new file mode 100644 index 0000000000000000000000000000000000000000..3932e766553adc7405aef8875476777cf64f01e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/ti-am437x-vpfe.txt @@ -0,0 +1,61 @@ +Texas Instruments AM437x CAMERA (VPFE) +-------------------------------------- + +The Video Processing Front End (VPFE) is a key component for image capture +applications. The capture module provides the system interface and the +processing capability to connect RAW image-sensor modules and video decoders +to the AM437x device. + +Required properties: +- compatible: must be "ti,am437x-vpfe" +- reg: physical base address and length of the registers set for the device; +- interrupts: should contain IRQ line for the VPFE; +- ti,am437x-vpfe-interface: can be one of the following, + 0 - Raw Bayer Interface. + 1 - 8 Bit BT656 Interface. + 2 - 10 Bit BT656 Interface. + 3 - YCbCr 8 Bit Interface. + 4 - YCbCr 16 Bit Interface. + +VPFE supports a single port node with parallel bus. It should contain one +'port' child node with child 'endpoint' node. Please refer to the bindings +defined in Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + vpfe: vpfe@f0034000 { + compatible = "ti,am437x-vpfe"; + reg = <0x48328000 0x2000>; + interrupts = ; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&vpfe_pins_default>; + pinctrl-1 = <&vpfe_pins_sleep>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + vpfe0_ep: endpoint { + remote-endpoint = <&ov2659_1>; + ti,am437x-vpfe-interface = <0>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; + + i2c1: i2c@4802a000 { + + ov2659@30 { + compatible = "ti,ov2659"; + reg = <0x30>; + + port { + ov2659_1: endpoint { + remote-endpoint = <&vpfe0_ep>; + bus-width = <8>; + mclk-frequency = <12000000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/ti-cal.txt b/arch/arm64/boot/dts/vendor/bindings/media/ti-cal.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae9b52f375769407d99d2bbc8b90726119f1b2cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/ti-cal.txt @@ -0,0 +1,72 @@ +Texas Instruments DRA72x CAMERA ADAPTATION LAYER (CAL) +------------------------------------------------------ + +The Camera Adaptation Layer (CAL) is a key component for image capture +applications. The capture module provides the system interface and the +processing capability to connect CSI2 image-sensor modules to the +DRA72x device. + +Required properties: +- compatible: must be "ti,dra72-cal" +- reg: CAL Top level, Receiver Core #0, Receiver Core #1 and Camera RX + control address space +- reg-names: cal_top, cal_rx_core0, cal_rx_core1, and camerrx_control + registers +- interrupts: should contain IRQ line for the CAL; + +CAL supports 2 camera port nodes on MIPI bus. Each CSI2 camera port nodes +should contain a 'port' child node with child 'endpoint' node. Please +refer to the bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + cal: cal@4845b000 { + compatible = "ti,dra72-cal"; + ti,hwmods = "cal"; + reg = <0x4845B000 0x400>, + <0x4845B800 0x40>, + <0x4845B900 0x40>, + <0x4A002e94 0x4>; + reg-names = "cal_top", + "cal_rx_core0", + "cal_rx_core1", + "camerrx_control"; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi2_0: port@0 { + reg = <0>; + endpoint { + slave-mode; + remote-endpoint = <&ar0330_1>; + }; + }; + csi2_1: port@1 { + reg = <1>; + }; + }; + }; + + i2c5: i2c@4807c000 { + ar0330@10 { + compatible = "ti,ar0330"; + reg = <0x10>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + ar0330_1: endpoint { + reg = <0>; + clock-lanes = <1>; + data-lanes = <0 2 3 4>; + remote-endpoint = <&csi2_0>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video-interfaces.txt b/arch/arm64/boot/dts/vendor/bindings/media/video-interfaces.txt new file mode 100644 index 0000000000000000000000000000000000000000..baf9d9756b3cf27b8fe4533ece6e3c7c1ef4ed64 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video-interfaces.txt @@ -0,0 +1,273 @@ +Common bindings for video receiver and transmitter interfaces + +General concept +--------------- + +Video data pipelines usually consist of external devices, e.g. camera sensors, +controlled over an I2C, SPI or UART bus, and SoC internal IP blocks, including +video DMA engines and video data processors. + +SoC internal blocks are described by DT nodes, placed similarly to other SoC +blocks. External devices are represented as child nodes of their respective +bus controller nodes, e.g. I2C. + +Data interfaces on all video devices are described by their child 'port' nodes. +Configuration of a port depends on other devices participating in the data +transfer and is described by 'endpoint' subnodes. + +device { + ... + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + ... + endpoint@0 { ... }; + endpoint@1 { ... }; + }; + port@1 { ... }; + }; +}; + +If a port can be configured to work with more than one remote device on the same +bus, an 'endpoint' child node must be provided for each of them. If more than +one port is present in a device node or there is more than one endpoint at a +port, or port node needs to be associated with a selected hardware interface, +a common scheme using '#address-cells', '#size-cells' and 'reg' properties is +used. + +All 'port' nodes can be grouped under optional 'ports' node, which allows to +specify #address-cells, #size-cells properties independently for the 'port' +and 'endpoint' nodes and any child device nodes a device might have. + +Two 'endpoint' nodes are linked with each other through their 'remote-endpoint' +phandles. An endpoint subnode of a device contains all properties needed for +configuration of this device for data exchange with other device. In most +cases properties at the peer 'endpoint' nodes will be identical, however they +might need to be different when there is any signal modifications on the bus +between two devices, e.g. there are logic signal inverters on the lines. + +It is allowed for multiple endpoints at a port to be active simultaneously, +where supported by a device. For example, in case where a data interface of +a device is partitioned into multiple data busses, e.g. 16-bit input port +divided into two separate ITU-R BT.656 8-bit busses. In such case bus-width +and data-shift properties can be used to assign physical data lines to each +endpoint node (logical bus). + +Documenting bindings for devices +-------------------------------- + +All required and optional bindings the device supports shall be explicitly +documented in device DT binding documentation. This also includes port and +endpoint nodes for the device, including unit-addresses and reg properties where +relevant. + +Please also see Documentation/devicetree/bindings/graph.txt . + +Required properties +------------------- + +If there is more than one 'port' or more than one 'endpoint' node or 'reg' +property is present in port and/or endpoint nodes the following properties +are required in a relevant parent node: + + - #address-cells : number of cells required to define port/endpoint + identifier, should be 1. + - #size-cells : should be zero. + + +Optional properties +------------------- + +- flash-leds: An array of phandles, each referring to a flash LED, a sub-node + of the LED driver device node. + +- lens-focus: A phandle to the node of the focus lens controller. + +- rotation: The device, typically an image sensor, is not mounted upright, + but a number of degrees counter clockwise. Typical values are 0 and 180 + (upside down). + + +Optional endpoint properties +---------------------------- + +- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node. +- slave-mode: a boolean property indicating that the link is run in slave mode. + The default when this property is not specified is master mode. In the slave + mode horizontal and vertical synchronization signals are provided to the + slave device (data source) by the master device (data sink). In the master + mode the data source device is also the source of the synchronization signals. +- bus-type: data bus type. Possible values are: + 0 - autodetect based on other properties (MIPI CSI-2 D-PHY, parallel or Bt656) + 1 - MIPI CSI-2 C-PHY + 2 - MIPI CSI1 + 3 - CCP2 +- bus-width: number of data lines actively used, valid for the parallel busses. +- data-shift: on the parallel data busses, if bus-width is used to specify the + number of data lines, data-shift can be used to specify which data lines are + used, e.g. "bus-width=<8>; data-shift=<2>;" means, that lines 9:2 are used. +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. + Note, that if HSYNC and VSYNC polarities are not specified, embedded + synchronization may be required, where supported. +- data-active: similar to HSYNC and VSYNC, specifies data line polarity. +- data-enable-active: similar to HSYNC and VSYNC, specifies the data enable + signal polarity. +- field-even-active: field signal level during the even field data transmission. +- pclk-sample: sample data on rising (1) or falling (0) edge of the pixel clock + signal. +- sync-on-green-active: active state of Sync-on-green (SoG) signal, 0/1 for + LOW/HIGH respectively. +- data-lanes: an array of physical data lane indexes. Position of an entry + determines the logical lane number, while the value of an entry indicates + physical lane, e.g. for 2-lane MIPI CSI-2 bus we could have + "data-lanes = <1 2>;", assuming the clock lane is on hardware lane 0. + If the hardware does not support lane reordering, monotonically + incremented values shall be used from 0 or 1 onwards, depending on + whether or not there is also a clock lane. This property is valid for + serial busses only (e.g. MIPI CSI-2). +- clock-lanes: an array of physical clock lane indexes. Position of an entry + determines the logical lane number, while the value of an entry indicates + physical lane, e.g. for a MIPI CSI-2 bus we could have "clock-lanes = <0>;", + which places the clock lane on hardware lane 0. This property is valid for + serial busses only (e.g. MIPI CSI-2). Note that for the MIPI CSI-2 bus this + array contains only one entry. +- clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous + clock mode. +- link-frequencies: Allowed data bus frequencies. For MIPI CSI-2, for + instance, this is the actual frequency of the bus, not bits per clock per + lane value. An array of 64-bit unsigned integers. +- lane-polarities: an array of polarities of the lanes starting from the clock + lane and followed by the data lanes in the same order as in data-lanes. + Valid values are 0 (normal) and 1 (inverted). The length of the array + should be the combined length of data-lanes and clock-lanes properties. + If the lane-polarities property is omitted, the value must be interpreted + as 0 (normal). This property is valid for serial busses only. +- strobe: Whether the clock signal is used as clock (0) or strobe (1). Used + with CCP2, for instance. + +Example +------- + +The example snippet below describes two data pipelines. ov772x and imx074 are +camera sensors with a parallel and serial (MIPI CSI-2) video bus respectively. +Both sensors are on the I2C control bus corresponding to the i2c0 controller +node. ov772x sensor is linked directly to the ceu0 video host interface. +imx074 is linked to ceu0 through the MIPI CSI-2 receiver (csi2). ceu0 has a +(single) DMA engine writing captured data to memory. ceu0 node has a single +'port' node which may indicate that at any time only one of the following data +pipelines can be active: ov772x -> ceu0 or imx074 -> csi2 -> ceu0. + + ceu0: ceu@fe910000 { + compatible = "renesas,sh-mobile-ceu"; + reg = <0xfe910000 0xa0>; + interrupts = <0x880>; + + mclk: master_clock { + compatible = "renesas,ceu-clock"; + #clock-cells = <1>; + clock-frequency = <50000000>; /* Max clock frequency */ + clock-output-names = "mclk"; + }; + + port { + #address-cells = <1>; + #size-cells = <0>; + + /* Parallel bus endpoint */ + ceu0_1: endpoint@1 { + reg = <1>; /* Local endpoint # */ + remote = <&ov772x_1_1>; /* Remote phandle */ + bus-width = <8>; /* Used data lines */ + data-shift = <2>; /* Lines 9:2 are used */ + + /* If hsync-active/vsync-active are missing, + embedded BT.656 sync is used */ + hsync-active = <0>; /* Active low */ + vsync-active = <0>; /* Active low */ + data-active = <1>; /* Active high */ + pclk-sample = <1>; /* Rising */ + }; + + /* MIPI CSI-2 bus endpoint */ + ceu0_0: endpoint@0 { + reg = <0>; + remote = <&csi2_2>; + }; + }; + }; + + i2c0: i2c@fff20000 { + ... + ov772x_1: camera@21 { + compatible = "ovti,ov772x"; + reg = <0x21>; + vddio-supply = <®ulator1>; + vddcore-supply = <®ulator2>; + + clock-frequency = <20000000>; + clocks = <&mclk 0>; + clock-names = "xclk"; + + port { + /* With 1 endpoint per port no need for addresses. */ + ov772x_1_1: endpoint { + bus-width = <8>; + remote-endpoint = <&ceu0_1>; + hsync-active = <1>; + vsync-active = <0>; /* Who came up with an + inverter here ?... */ + data-active = <1>; + pclk-sample = <1>; + }; + }; + }; + + imx074: camera@1a { + compatible = "sony,imx074"; + reg = <0x1a>; + vddio-supply = <®ulator1>; + vddcore-supply = <®ulator2>; + + clock-frequency = <30000000>; /* Shared clock with ov772x_1 */ + clocks = <&mclk 0>; + clock-names = "sysclk"; /* Assuming this is the + name in the datasheet */ + port { + imx074_1: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&csi2_1>; + }; + }; + }; + }; + + csi2: csi2@ffc90000 { + compatible = "renesas,sh-mobile-csi2"; + reg = <0xffc90000 0x1000>; + interrupts = <0x17a0>; + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + compatible = "renesas,csi2c"; /* One of CSI2I and CSI2C. */ + reg = <1>; /* CSI-2 PHY #1 of 2: PHY_S, + PHY_M has port address 0, + is unused. */ + csi2_1: endpoint { + clock-lanes = <0>; + data-lanes = <2 1>; + remote-endpoint = <&imx074_1>; + }; + }; + port@2 { + reg = <2>; /* port 2: link to the CEU */ + + csi2_2: endpoint { + remote-endpoint = <&ceu0_0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video-mux.txt b/arch/arm64/boot/dts/vendor/bindings/media/video-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..63b9dc913e4568aa08eaa77a8cead42cec69153b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video-mux.txt @@ -0,0 +1,60 @@ +Video Multiplexer +================= + +Video multiplexers allow to select between multiple input ports. Video received +on the active input port is passed through to the output port. Muxes described +by this binding are controlled by a multiplexer controller that is described by +the bindings in Documentation/devicetree/bindings/mux/mux-controller.txt + +Required properties: +- compatible : should be "video-mux" +- mux-controls : mux controller node to use for operating the mux +- #address-cells: should be <1> +- #size-cells: should be <0> +- port@*: at least three port nodes containing endpoints connecting to the + source and sink devices according to of_graph bindings. The last port is + the output port, all others are inputs. + +Optionally, #address-cells, #size-cells, and port nodes can be grouped under a +ports node as described in Documentation/devicetree/bindings/graph.txt. + +Example: + + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>; + }; + + video-mux { + compatible = "video-mux"; + mux-controls = <&mux>; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mux_in0: endpoint { + remote-endpoint = <&video_source0_out>; + }; + }; + + port@1 { + reg = <1>; + + mux_in1: endpoint { + remote-endpoint = <&video_source1_out>; + }; + }; + + port@2 { + reg = <2>; + + mux_out: endpoint { + remote-endpoint = <&capture_interface_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-cci.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-cci.txt new file mode 100644 index 0000000000000000000000000000000000000000..de157c2eb3125ed5ce18ab4269c1e43c498e9dd0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-cci.txt @@ -0,0 +1,898 @@ +* Qualcomm Technologies, Inc. MSM CCI + +CCI (Camera Control Interface) is module that is use for camera sensor module +I2C communication. + +======================= +Required Node Structure +======================= +The camera CCI node must be described in two levels of device nodes. The +first level describe the overall CCI node structure. Second level nodes +describe camera sensor submodule nodes which is using CCI for +i2c communication. + +====================================== +First Level Node - CCI device +====================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cci". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- reg-names + Usage: required + Value type: + Definition: Should specify relevant names to each + reg property defined. + +- interrupts + Usage: required + Value type: + Definition: Interrupt associated with CCI HW. + +- interrupt-names + Usage: required + Value type: + Definition: Name of the interrupt. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the CCI. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels in + gpio-req-tbl-num property (in the same order) + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CCI HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clock rates in Hz for CCI HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- src-clock-name + Usage: required + Value type: + Definition: name for the source clock. + +- regulator-names + Usage: required + Value type: + Definition: name of the voltage regulators required for the device. + +- gdscr-supply + Usage: required + Value type: + Definition: should contain gdsr regulator used for cci clocks. + +- mmagic-supply + Usage: optional + Value type: + Definition: should contain mmagic regulator used for mmagic clocks. + +========================= +CCI clock settings +========================= +- I2c speed settings (*) + Usage: required + Definition: List of i2c rates for CCI HW. + - i2c_freq_100Khz + Definition: qcom,i2c_standard_mode - node should contain clock settings for + 100Khz + - i2c_freq_400Khz + Definition: qcom,i2c_fast_mode - node should contain clock settings for + 400Khz + - i2c_freq_custom + Definition: qcom,i2c_custom_mode - node can contain clock settings for + frequencies other than 100Khz and 400Khz which is specific to usecase. + Currently it has settings for 375Khz. + - i2c_freq_1Mhz + Definition: qcom,i2c_fast_plus_mode - node should contain clock + settings for 1Mhz +* if speed settings is not defined the low level driver can use "i2c_freq_custom" +like default + + - hw-thigh + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tlow + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tsu-sto + Definition: should contain setup time for STOP condition + - hw-tsu-sta + Definition: should contain setup time for Repeated START condition + - hw-thd-dat + Definition: should contain hold time for the data + - hw-thd-sta + Definition: should contain hold time for START condition + - hw-tbuf + Definition: should contain free time between a STOP and a START condition + - hw-scl-stretch-en + Definition: should contain enable or disable clock stretching + - hw-trdhld + Definition: should contain internal hold time for SDA + - hw-tsp + Definition: should contain filtering of glitches + +Example: + + qcom,cci@0xfda0c000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xfda0c000 0x300>; + reg-names = "cci"; + interrupts = <0 50 0>; + interrupt-names = "cci"; + clock-names = "camnoc_axi_clk", "soc_ahb_clk", + "slow_ahb_src_clk", "cpas_ahb_clk", + "cci_clk", "cci_clk_src"; + clock-rates = <0 0 80000000 0 0 37500000>; + clock-cntl-level = "turbo"; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-tbl-num = <0 1 2 3>; + gpio-tbl-flags = <1 1 1 1>; + gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <78>; + hw-tlow = <114>; + hw-tsu-sto = <28>; + hw-tsu-sta = <28>; + hw-thd-dat = <10>; + hw-thd-sta = <77>; + hw-tbuf = <118>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <1>; + status = "ok"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <20>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <15>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <19>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + +======================================= +Second Level Node - CAM SENSOR MODULES +======================================= + +======================================= +CAM SENSOR RESOURCE MANAGER +======================================= +Camera Sensor Resource manager node contains properties of shared camera +sensor resource. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-res-mgr". + +- shared-gpios + Usage: optional + Value type: + Definition: should contain the gpios which are used by two or more + cameras, and these cameras may be opened together. + +- pinctrl-names + Usage: optional + Value type: + Definition: List of names to assign the shared pin state defined in pinctrl device node + +- pinctrl-<0..n> + Usage: optional + Value type: + Definition: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl device node. + + +============================= +CAMERA IMAGE SENSOR MODULE +============================= +Image sensor node contains properties of camera image sensor + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-sensor". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- csiphy-sd-index + Usage: required + Value type: + Definition: should contain csiphy instance that will used to + receive sensor data (0, 1, 2, 3). + +- cam_vdig-supply + Usage: required + Value type: + Definition: should contain regulator from which digital voltage is + supplied + +- cam_vana-supply + Usage: required + Value type: + Definition: should contain regulator from which analog voltage is + supplied + +- cam_vio-supply + Usage: required + Value type: + Definition: should contain regulator from which IO voltage is supplied + +- cam_bob-supply + Usage: optional + Value type: + Definition: should contain regulator from which BoB voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + sensor + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property is required if the sw control regulator parameters + e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain optimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- sensor-position-roll + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-pitch + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-yaw + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- qcom,secure + Usage: optional + Value type: + Definition: should be enabled to operate the camera in secure mode + +- gpio-no-mux + Usage: optional + Value type: + Definition: should contain field to indicate whether gpio mux table is + available. i.e. 1 if gpio mux is not available, 0 otherwise + +- cam_vaf-supply + Usage: optional + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- pwm-switch + Usage: optional + Value type: + Definition: This property is required for regulator to switch into PWM mode. + +- gpios + Usage: required + Value type: + Definition: should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) + +- gpio-reset + Usage: required + Value type: + Definition: should contain index to gpio used by sensors reset_n + +- gpio-standby + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors standby_n + +- gpio-vio + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors io vreg enable + +- gpio-vana + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors analog vreg enable + +- gpio-vdig + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors digital vreg enable + +- gpio-vaf + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af vreg enable + +- gpio-af-pwdm + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af pwdm_n + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should contain index to gpios specific to this sensor + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should contain direction of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should contain name of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-set-tbl-num + Usage: optional + Value type: + Definition: should contain index of gpios that need to be + configured by msm + +- gpio-set-tbl-flags + Usage: optional + Value type: + Definition: should contain value to be configured for the gpios + present in gpio-set-tbl-num property (in the same order) + +- gpio-set-tbl-delay + Usage: optional + Value type: + Definition: should contain amount of delay after configuring + gpios as specified in gpio_set_tbl_flags property (in the same order) + +- actuator-src + Usage: optional + Value type: + Definition: if auto focus is supported by this sensor, this + property should contain phandle of respective actuator node + +- led-flash-src + Usage: optional + Value type: + Definition: if LED flash is supported by this sensor, this + property should contain phandle of respective LED flash node + +- qcom,vdd-cx-supply + Usage: optional + Value type: + Definition: should contain regulator from which cx voltage is supplied + +- qcom,vdd-cx-name + Usage: optional + Value type: + Definition: should contain names of cx regulator + +- eeprom-src + Usage: optional + Value type: + Definition: if eeprom memory is supported by this sensor, this + property should contain phandle of respective eeprom nodes + +- ois-src + Usage: optional + Value type: + Definition: if optical image stabilization is supported by this sensor, + this property should contain phandle of respective ois node + +- ir-led-src + Usage: optional + Value type: + Definition: if ir led is supported by this sensor, this property + should contain phandle of respective ir-led node + +- qcom,ir-cut-src + Usage: optional + Value type: + Definition: if ir cut is supported by this sensor, this property + should contain phandle of respective ir-cut node + +- qcom,special-support-sensors + Usage: required + Value type: + Definition: if only some special sensors are supported + on this board, add sensor name in this property. + +- use-shared-clk + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the clk is shared clk between different sensor and ois, if this + device need to be opened together. + +- clock-rates + Usage: required + Value type: + Definition: clock rate in Hz. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clock-cntl-support + Usage: optional + Value type: + Definition: Says whether clock control support is present or not + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- clock-control + Usage: optional + Value type: + Definition: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property clock-rates. + +============================= +ACTUATOR MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,actuator". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +============================= +OIS MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,ois". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +- use-shared-clk + Usage: optional + Value type: + Definition: This property is required if the clk is shared clk between different + sensor and ois, if this device need to be opened together. + +============================= +IRLED MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,camera-ir-led". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- pwms + Usage: optional + Value type: + Definition: should contain phandle to pwm node used for IRLED + +- pinctrl-names + Usage: required + Value type: + Definition: List of names to assign the shared pin state defined in pinctrl device node + +- pinctrl-<0..n> + Usage: required + Value type: + Definition: Lists phandles each pointing to the pin configuration node within a pin + +- gpios + Usage: required + Value type: + Definition: should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels in + gpio-req-tbl-num property (in the same order) + +Example: +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8994_flash0 &pmi8994_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch>; + status = "ok"; + }; + + ir_led: camera-ir-led@0 { + cell-index = <0>; + reg = <0x00>; + compatible = "qcom,camera-ir-led"; + pwms = <&pm6150l_pwm_1 0 0>; + + enable-active-high; + pinctrl-names = "default", "cam_default", "cam_suspend"; + pinctrl-0 = <&irled_pwm>; + pinctrl-1 = <&cam_sensor_ir_cut_on>; + pinctrl-2 = <&cam_sensor_ir_cut_off>; + gpios = <&tlmm 73 0>, + <&tlmm 74 0>; + qcom,gpio-ir-p = <0>; + qcom,gpio-ir-m = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <0 0>; + qcom,gpio-req-tbl-label = "IR_CUT_FILTER_P", + "IR_CUT_FILTER_M"; + gpio-no-mux = <0>; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&pmi8998_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&pmi8998_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <18 19>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_shared_clk_active &cam_res_mgr_active>; + pinctrl-1 = <&cam_shared_clk_suspend &cam_res_mgr_suspend>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + secure = <1>; + led-flash-src = <&led_flash0>; + actuator-src = <&actuator0>; + ois-src = <&ois0>; + eeprom-src = <&eeprom0>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009l_l1>; + cam_vana-supply = <&pm8009l_l5>; + cam_bob-supply = <&pm8150l_bob>; + cam_clk-supply = <&tital_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <0 2800000 1200000 0 3008000>; + rgltr-max-voltage = <0 2800000 1200000 0 4000000>; + rgltr-load-current = <0 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 80 0>, + <&tlmm 79 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + use-shared-clk; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + clock-cntl-leveli = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-eeprom.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-eeprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..d77f337a9e3c0659db6966ee77025a9b7a8bb857 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-eeprom.txt @@ -0,0 +1,503 @@ +* Qualcomm Technologies, Inc. MSM EEPROM + +EEPROM is a one time programmed(OTP) device that stores the calibration data +use for camera sensor. It may either be integrated in the sensor module or in +the sensor itself. As a result, the power, clock and GPIOs may be the same as +the camera sensor. The following describes the page block map, power supply, +clock, GPIO and power on sequence properties of the EEPROM device. + +======================================================= +Required Node Structure if probe happens from userspace +======================================================= +The EEPROM device is described in one level of the device node. + +====================================== +First Level Node - CAM EEPROM device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,eeprom". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for EEPROM HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property specifies if the regulator control is supported + e.g. rgltr-min-voltage. + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain the maximum current in microamps required for + the regulators mentioned in regulator-names property. + +- gpio-no-mux + Usage: required + Value type: + Definition: should specify the gpio mux type. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the eeprom. + +- gpio-reset + Usage: required + Value type: + Definition: should specify the reset gpio index. + +- gpio-standby + Usage: required + Value type: + Definition: should specify the standby gpio index. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels. + +- sensor-position + Usage: required + Value type: + Definition: should contain the mount angle of the camera sensor. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor. + +- sensor-mode + Usage: required + Value type: + Definition: should contain sensor mode supported. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for EEPROM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for EEPROM HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: says what all different clock levels eeprom node has. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Example: + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8998_l5>; + cam_vio-supply = <&pm8998_lvs1>; + regulator-names = "cam_vdig", "cam_vio"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 0>; + rgltr-max-voltage = <1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + +======================================================= +Required Node Structure if probe happens from kernel +======================================================= +The EEPROM device is described in one level of the device node. + +====================================== +First Level Node - CAM EEPROM device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,eeprom". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- qcom,eeprom-name + Usage: required + Value type: + Definition: Name of the EEPROM HW. + +- qcom,slave-addr + Usage: required + Value type: + Definition: Slave address of the EEPROM HW. + +- qcom,num-blocks + Usage: required + Value type: + Definition: Total block number that eeprom contains. + +- qcom,pageX + Usage: required + Value type: + Definition: List of values specifying page size, start address, + address type, data, data type, delay in ms. + size 0 stand for non-paged. + +- qcom,pollX + Usage: required + Value type: + Definition: List of values specifying poll size, poll reg address, + address type, data, data type, delay in ms. + size 0 stand for not used. + +- qcom,memX + Usage: required + Value type: + Definition: List of values specifying memory size, start address, + address type, data, data type, delay in ms. + size 0 stand for not used. + +- qcom,saddrX + Usage: required + Value type: + Definition: property should specify the slave address for block (%d). + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for EEPROM HW. + +- qcom,cmm-data-support + Usage: required + Value type: + Definition: Camera MultiModule data capability flag.. + +- qcom,cmm-data-compressed + Usage: required + Value type: + Definition: Camera MultiModule data compression flag. + +- qcom,cmm-data-offset + Usage: required + Value type: + Definition: Camera MultiModule data start offset. + +- qcom,cmm-data-size + Usage: required + Value type: + Definition: Camera MultiModule data size. + +- qcom,cam-power-seq-type + Usage: required + Value type: + Definition: should specify the power on sequence types. + +- qcom,cam-power-seq-val + Usage: required + Value type: + Definition: should specify the power on sequence values. + +- qcom,cam-power-seq-cfg-val + Usage: required + Value type: + Definition: should specify the power on sequence config values. + +- qcom,cam-power-seq-delay + Usage: required + Value type: + Definition: should specify the power on sequence delay time in ms. + +- spiop-read + Usage: required + Value type: + Definition: this array provides SPI read operation related data. + +- spiop-readseq + Usage: required + Value type: + Definition: this array provides SPI read sequence operation realted data. + +- spiop-queryid + Usage: required + Value type: + Definition: this array provides SPI query eeprom id operation related data. + +- spiop-pprog: + Usage: required + Value type: + Definition: this array provides SPI page program operation related data. + +- spiop-wenable + Usage: required + Value type: + Definition: this array provides SPI write enable operation related data. + +- spiop-readst + Usage: required + Value type: + Definition: this array provides SPI read destination operation related data. + +- spiop-erase + Usage: required + Value type: + Definition: this array provides SPI erase operation related data. + +- eeprom-idx + Usage: required + Value type: + Definition: this array provides eeprom id realted data. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property specifies if the regulator control is supported + e.g. rgltr-min-voltage. + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain the maximum current in microamps required for + the regulators mentioned in regulator-names property. + +- gpio-no-mux + Usage: required + Value type: + Definition: should specify the gpio mux type. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the eeprom. + +- gpio-reset + Usage: required + Value type: + Definition: should specify the reset gpio index. + +- gpio-standby + Usage: required + Value type: + Definition: should specify the standby gpio index. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels. + +- sensor-position + Usage: required + Value type: + Definition: should contain the mount angle of the camera sensor. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor. + +- sensor-mode + Usage: required + Value type: + Definition: should contain sensor mode supported. + +- clock-cntl-level + Usage: required + Value type: + Definition: says what all different clock levels eeprom node has. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for EEPROM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for EEPROM HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Example: + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0x0>; + qcom,eeprom-name = "msm_eeprom"; + eeprom-id0 = <0xF8 0x15>; + eeprom-id1 = <0xEF 0x15>; + eeprom-id2 = <0xC2 0x36>; + eeprom-id3 = <0xC8 0x15>; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x60>; + qcom,num-blocks = <2>; + qcom,page0 = <1 0x100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0 1 1>; + qcom,mem0 = <0 0x0 2 0 1 0>; + qcom,page1 = <1 0x0200 2 0x8 1 1>; + qcom,pageen1 = <1 0x0202 2 0x01 1 10>; + qcom,poll1 = <0 0x0 2 0 1 1>; + qcom,mem1 = <32 0x3000 2 0 1 0>; + qcom,saddr1 = <0x62>; + qcom,cmm-data-support; + qcom,cmm-data-compressed; + qcom,cmm-data-offset = <0>; + qcom,cmm-data-size = <0>; + spiop-read = <0x03 3 0 0 0>; + spiop-readseq = <0x03 3 0 0 0>; + spiop-queryid = <0x90 3 0 0 0>; + spiop-pprog = <0x02 3 0 3 100>; + spiop-wenable = <0x06 0 0 0 0>; + spiop-readst = <0x05 0 0 0 0>; + spiop-erase = <0x20 3 0 10 100>; + qcom,cam-power-seq-type = "sensor_vreg", + "sensor_vreg", "sensor_clk", + "sensor_gpio", "sensor_gpio"; + qcom,cam-power-seq-val = "cam_vdig", + "cam_vio", "sensor_cam_mclk", + "sensor_gpio_reset", + "sensor_gpio_standby"; + qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>; + qcom,cam-power-seq-delay = <1 1 5 5 10>; + cam_vdig-supply = <&pm8998_l5>; + cam_vio-supply = <&pm8998_lvs1>; + regulator-names = "cam_vdig", "cam_vio"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 0>; + rgltr-max-voltage = <1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-cntl-level = "turbo"; + clock-names = "cam_clk"; + clock-rates = <24000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-jpeg.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-jpeg.txt new file mode 100644 index 0000000000000000000000000000000000000000..73e99b25cd8f370e62059b5dd8e49396f8ef2ac7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-jpeg.txt @@ -0,0 +1,186 @@ +* Qualcomm Technologies, Inc. MSM Camera JPEG + +The MSM camera JPEG devices are implemented multiple device nodes. +The root JPEG device node has properties defined to hint the driver +about the number of Encoder and DMA nodes available during the +probe sequence. Each node has multiple properties defined +for interrupts, clocks and regulators. + +======================= +Required Node Structure +======================= +JPEG root interface node takes care of the handling account for number +of Encoder and DMA devices present on the hardware. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-jpeg". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,jpegenc" or "qcom,jpegdma". + +- num-jpeg-enc + Usage: required + Value type: + Definition: Number of supported Encoder HW blocks. + +- num-jpeg-dma + Usage: required + Value type: + Definition: Number of supported DMA HW blocks. + +Example: + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + +======================= +Required Node Structure +======================= +Encoder/DMA Nodes provide interface for JPEG driver about +the device register map, interrupt map, clocks and regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam_jpeg_enc". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with JPEG HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for JPEG HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for JPEG HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for JPEG HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Examples: + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-smmu.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-smmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b1f086128657961f600ad9a53ee6a29a1484f8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cam-smmu.txt @@ -0,0 +1,148 @@ +* Qualcomm Technologies, Inc. MSM Camera SMMU + +The MSM camera SMMU device provides SMMU context bank definitions +for all HW blocks that need to map IOVA to physical memory. These +definitions consist of various properties that define how the +IOVA address space is laid out for each HW block in the camera +subsystem. + +======================= +Required Node Structure +======================= +The camera SMMU device must be described in three levels of device nodes. The +first level describes the overall SMMU device. Within it, second level nodes +describe individual context banks that map different stream ids. There can +also be second level nodes describing firmware device nodes. Each HW block +such as IFE, ICP maps into these second level device nodes. All context bank +specific properties that define how the IOVA is laid out is contained within +third level device nodes within the second level device nodes. + +During the kernel initialization all the devices are probed recursively and +a device pointer is created for each context bank keeping track of the IOVA +mapping information. + +Duplicate regions of the same type are not allowed within the same +context bank. All context banks must contain an IO region at the very least. + +================================== +First Level Node - CAM SMMU device +================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,msm-cam-smmu". + +- qcom,camera-secure-sid + Usage: optional + Value type: boolean + Definition: Specifies if the sensor stream is a secure stream. + +=================================================================== +Second Level Node - CAM SMMU context bank device or firmware device +=================================================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,msm-cam-smmu-cb" or "qcom,msm-cam-smmu-fw-dev". + +- memory-region + Usage: optional + Value type: + Definition: Should specify the phandle of the memory region for firmware. + allocation + +- iommus + Usage: required + Value type: + Definition: first cell is phandle of the iommu, second cell is stream id + and third cell is SMR mask. + +- label + Usage: required + Value type: + Definition: Should specify a string label to identify the context bank. + +- qcom,secure-cb + Usage: optional + Value type: boolean + Definition: Specifies if the context bank is a secure context bank. + +============================================= +Third Level Node - CAM SMMU memory map device +============================================= +- iova-region-name + Usage: required + Value type: + Definition: Should specify a string label to identify the IOVA region. + +- iova-region-start + Usage: required + Value type: + Definition: Should specify start IOVA for region. + +- iova-region-len + Usage: required + Value type: + Definition: Should specify length for IOVA region. + +- iova-region-id + Usage: required + Value type: + Definition: Should specify the numerical identifier for IOVA region. + Allowed values are: 0x00 to 0x03 + - Firmware region: 0x00 + - Shared region: 0x01 + - Scratch region: 0x02 + - IO region: 0x03 + +- iova-granularity + Usage: optional + Value type: + Definition: Should specify IOVA granularity for shared memory region. + +Example: + qcom,cam_smmu@0 { + compatible = "qcom,msm-cam-smmu"; + qcom,camera-secure-sid; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1078>, + <&apps_smmu 0x1020>, + <&apps_smmu 0x1028>, + <&apps_smmu 0x1040>, + <&apps_smmu 0x1048>, + <&apps_smmu 0x1030>, + <&apps_smmu 0x1050>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.5 GB */ + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-camera-flash.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-camera-flash.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab81329df08ed7601fa9bdb42db67bc28dcccd4a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-camera-flash.txt @@ -0,0 +1,132 @@ +* Qualcomm Technologies, Inc. MSM FLASH + +The MSM camera Flash driver provides the definitions for +enabling and disabling LED Torch/Flash by requesting it to +PMIC/I2C/GPIO based hardware. It provides the functions for +the Client to control the Flash hardware. + +======================================================= +Required Node Structure +======================================================= +The Flash device is described in one level of the device node. + +====================================== +First Level Node - CAM FLASH device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,camera-flash". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- flash-source + Usage: required + Value type: + Definition: Should contain array of phandles to Flash source nodes. + +- torch-source + Usage: required + Value type: + Definition: Should contain array of phandles to torch source nodes. + +- switch-source + Usage: Optional + Value type: + Definition: Should contain phandle to switch source nodes. + +- slave-id + Usage: optional + Value type: + Definition: should contain i2c slave address, device id address + and expected id read value. + +- cci-master + Usage: optional + Value type: + Definition: should contain i2c master id to be used for this camera + flash. + +- max-current + Usage: optional + Value type: + Definition: Max current in mA supported by flash + +- max-duration + Usage: optional + Value type: + Definition: Max duration in ms flash can glow. + +- wled-flash-support + Usage: optional + Value type: + Definition: To identity wled flash hardware support. + +- gpios + Usage: optional + Value type: + Definition: should specify the gpios to be used for the flash. + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should specify the gpio labels. + +- gpio-flash-reset + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash reset" pin. + +- gpio-flash-en + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash enable" pin. + +- gpio-flash-now + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash now" pin. + +Example: + +led_flash_rear: qcom,camera-flash@0 { + reg = <0x00 0x00>; + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + wled-flash-support; + qcom,slave-id = <0x00 0x00 0x0011>; + qcom,cci-master = <0>; + gpios = <&msmgpio 23 0>, + <&msmgpio 24 0>; + <&msmgpio 25 0>; + qcom,gpio-flash-reset = <0>; + qcom,gpio-flash-en = <0>; + qcom,gpio-flash-now = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <0 0>; + qcom,gpio-req-tbl-label = "FLASH_EN", + "FLASH_NOW"; + qcom,max-current = <1500>; + qcom,max-duration = <1200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cci.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cci.txt new file mode 100644 index 0000000000000000000000000000000000000000..b43b2954e50254056b57e32f2098965dde1a9fc4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cci.txt @@ -0,0 +1,398 @@ +* Qualcomm Technologies, Inc. MSM CCI + +[First level nodes] +Required properties: +- cell-index: cci hardware core index +- compatible : + - "qcom,cci" +- reg : offset and length of the register set for the device + for the cci operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should contain the cci interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- gpios : should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) +- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor +- qcom,gpio-req-tbl-flags : should contain direction of gpios present in + qcom,gpio-req-tbl-num property (in the same order) +- qcom,gpio-req-tbl-label : should contain name of gpios present in + qcom,gpio-req-tbl-num property (in the same order) +- clock-names: name of the clocks required for the device +- clock-rates: clock rate in Hz + +Optional properties: +- qcom,cam-vreg-name : name of the voltage regulators required for the device. +- gdscr-supply : should contain gdsr regulator used for cci clocks. +- mmagic-supply : should contain mmagic regulator used for mmagic clocks. + +- I2c speed settings (*) + - i2c_freq_100Khz: qcom,i2c_standard_mode - node should contain clock settings for + 100Khz + - i2c_freq_400Khz: qcom,i2c_fast_mode - node should contain clock settings for + 400Khz + - i2c_freq_custom: qcom,i2c_custom_mode - node can contain clock settings for + frequencies other than 100Khz and 400Khz which is specific to usecase. + Currently it has settings for 375Khz. + - i2c_freq_1Mhz: qcom,i2c_fast_plus_mode - node should contain clock + settings for 1Mhz + * if speed settings is not defined the low level driver can use "i2c_freq_custom" + like default + +[Second level nodes] +* Qualcomm Technologies, Inc. CCI clock settings + +Optional properties: +- qcom,hw-thigh : should contain high period of the SCL clock in terms of CCI + clock cycle +- qcom,hw-tlow : should contain high period of the SCL clock in terms of CCI + clock cycle +- qcom,hw-tsu-sto : should contain setup time for STOP condition +- qcom,hw-tsu-sta : should contain setup time for Repeated START condition +- qcom,hw-thd-dat : should contain hold time for the data +- qcom,hw-thd-sta : should contain hold time for START condition +- qcom,hw-tbuf : should contain free time between a STOP and a START condition +- qcom,hw-scl-stretch-en : should contain enable or disable clock stretching +- qcom,hw-trdhld : should contain internal hold time for SDA +- qcom,hw-tsp : should contain filtering of glitches + +* Qualcomm Technologies, Inc. MSM Sensor + +MSM sensor node contains properties of camera sensor + +Required properties: +- compatible : should be manufacturer name followed by sensor name + - "qcom,camera" + - "shinetech,gc0310" +- reg : should contain i2c slave address of the device +- qcom,csiphy-sd-index : should contain csiphy instance that will used to + receive sensor data + - 0, 1, 2 +- qcom,csid-sd-index : should contain csid core instance that will used to + receive sensor data + - 0, 1, 2, 3 +- cam_vdig-supply : should contain regulator from which digital voltage is + supplied +- cam_vana-supply : should contain regulator from which analog voltage is + supplied +- cam_vio-supply : should contain regulator from which IO voltage is supplied +- qcom,cam-vreg-name : should contain names of all regulators needed by this + sensor + - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf" +- qcom,cam-vreg-min-voltage : should contain minimum voltage level for + regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-max-voltage : should contain maximum voltage level for + regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-op-mode : should contain optimum voltage level for regulators + mentioned in qcom,cam-vreg-name property (in the same order) + +Optional properties: +- qcom,slave-id : should contain i2c slave address, device id address + ,expected id read value and device id mask +- qcom,sensor-name : should contain unique sensor name to differentiate from + other sensor + - "s5k3l1yx" +- qcom,sensor-mode : should contain sensor mode supported + - 0 -> back camera 2D + - 1 -> front camera 2D + - 2 -> back camera 3D + - 3 -> back camera int 3D +- qcom,sensor-type : should contain format of data that sensor streams + - 0 -> bayer format + - 1 -> yuv format +- qcom,is-vpe : should be enabled if VPE module is required for post processing + of this sensor + - 1 if required, 0 otherwise +- qcom,mount-angle : should contain the physical mount angle of the sensor on + the target + - 0, 90, 180, 360 +- qcom,secure : should be enabled to operate the camera in secure mode + - 0, 1 +- qcom,mclk-23880000 : should be enabled if the supported mclk is 23.88Mhz and + not 24 Mhz. +- qcom,gpio-no-mux : should contain field to indicate whether gpio mux table is + available + - 1 if gpio mux is not available, 0 otherwise +- cam_vaf-supply : should contain regulator from which AF voltage is supplied +- gpios : should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) +- qcom,gpio-reset : should contain index to gpio used by sensors reset_n +- qcom,gpio-standby : should contain index to gpio used by sensors standby_n +- qcom,gpio-vio : should contain index to gpio used by sensors io vreg enable +- qcom,gpio-vana : should contain index to gpio used by sensors analog vreg enable +- qcom,gpio-vdig : should contain index to gpio used by sensors digital vreg enable +- qcom,gpio-vaf : should contain index to gpio used by sensors af vreg enable +- qcom,gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n +- qcom,gpio-req-tbl-num : should contain index to gpios specific to this sensor +- qcom,gpio-req-tbl-flags : should contain direction of gpios present in + qcom,gpio-req-tbl-num property (in the same order) +- qcom,gpio-req-tbl-label : should contain name of gpios present in + qcom,gpio-req-tbl-num property (in the same order) +- qcom,gpio-set-tbl-num : should contain index of gpios that need to be + configured by msm +- qcom,gpio-set-tbl-flags : should contain value to be configured for the gpios + present in qcom,gpio-set-tbl-num property (in the same order) +- qcom,gpio-set-tbl-delay : should contain amount of delay after configuring + gpios as specified in gpio_set_tbl_flags property (in the same order) +- qcom,csi-lane-assign : should contain lane assignment value to map CSIPHY + lanes to CSID lanes + - 0x4320 +- qcom,csi-lane-mask : should contain lane mask that specifies CSIPHY lanes to + be enabled +- qcom,csi-phy-sel : should contain CSIPHY core instance from which CSID should + receive data +- qcom,actuator-cam-name : should contain actuator cam name associated with + this sensor + - If actuator does not exist, this property should not be initialized + - If actuator exist, this field should indicate the index of actuator to + be used +- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled + for actuator +- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm + gpio +- qcom,sensor-position : should contain the mount angle of the camera sensor + - 0 -> back camera + - 1 -> front camera +- qcom,cci-master : should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 +- qcom,actuator-src : if auto focus is supported by this sensor, this + property should contain phandle of respective actuator node +- qcom,led-flash-src : if LED flash is supported by this sensor, this + property should contain phandle of respective LED flash node +- qcom,vdd-cx-supply : should contain regulator from which cx voltage is + supplied +- qcom,vdd-cx-name : should contain names of cx regulator +- qcom,eeprom-src : if eeprom memory is supported by this sensor, this + property should contain phandle of respective eeprom nodes +- qcom,ois-src : if optical image stabilization is supported by this sensor, + this property should contain phandle of respective ois node +- qcom,ir-led-src : if ir led is supported by this sensor, this property + should contain phandle of respective ir-led node +- qcom,ir-cut-src : if ir cut is supported by this sensor, this property + should contain phandle of respective ir-cut node +- qcom,special-support-sensors: if only some special sensors are supported + on this board, add sensor name in this property. + +* Qualcomm Technologies, Inc. MSM ACTUATOR + +Required properties: +- cell-index : should contain unique identifier to differentiate + between multiple actuators +- reg : should contain i2c slave address of the actuator and length of + data field which is 0x0 +- compatible : + - "qcom,actuator" +- qcom,cci-master : should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +Optional properties: +- qcom,cam-vreg-name : should contain names of all regulators needed by this + actuator + - "cam_vaf" +- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-op-mode : should contain the maximum current in microamps + required from the regulators mentioned in the qcom,cam-vreg-name property + (in the same order). +- cam_vaf-supply : should contain regulator from which AF voltage is supplied + +* Qualcomm Technologies, Inc. MSM LASER LED + +Required properties: +- cell-index : should contain unique identifier to differentiate + between multiple laser led modules +- reg : should contain i2c slave address of the laser led and length of + data field which is 0x0 +- compatible : + - "qcom,laser-led" +- qcom,cci-master : should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +Optional properties: +- qcom,cam-vreg-name : should contain names of all regulators needed by this + laser led +- qcom,cam-vreg-min-voltage : should contain minimum voltage level in microvolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-max-voltage : should contain maximum voltage level in microvolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-op-mode : should contain the maximum current in microamps + required from the regulators mentioned in the qcom,cam-vreg-name property + (in the same order). + +* Qualcomm Technologies, Inc. MSM OIS + +Required properties: +- cell-index : should contain unique identifier to differentiate + between multiple ois drivers +- reg : should contain i2c slave address of the ois and length of + data field which is 0x0 +- compatible : + - "qcom,ois" +- qcom,cci-master : should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +Optional properties: +- qcom,cam-vreg-name : should contain names of all regulators needed by this + ois + - "cam_vaf" +- qcom,cam-vreg-min-voltage : should contain minimum voltage level in mcrovolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-max-voltage : should contain maximum voltage level in mcrovolts + for regulators mentioned in qcom,cam-vreg-name property (in the same order) +- qcom,cam-vreg-op-mode : should contain the maximum current in microamps + required from the regulators mentioned in the qcom,cam-vreg-name property + (in the same order). +- cam_vaf-supply : should contain regulator from which ois voltage is supplied + +Example: + + qcom,cci@0xfda0c000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xfda0c000 0x300>; + reg-names = "cci"; + interrupts = <0 50 0>; + interrupt-names = "cci"; + clock-names = "camss_top_ahb_clk", "vfe_clk_src", + "camss_vfe_vfe_clk", "iface_clk", "cpp_core_clk", + "cpp_iface_clk", "cpp_bus_clk", "micro_iface_clk"; + qcom,clock-rates = <0 266670000 0 0 266670000 0 0 0>; + gpios = <&msmgpio 19 0>, + <&msmgpio 20 0>, + <&msmgpio 21 0>, + <&msmgpio 22 0>; + qcom,gpio-tbl-num = <0 1 2 3>; + qcom,gpio-tbl-flags = <1 1 1 1>; + qcom,gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + status = "disabled"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + status = "disabled"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + status = "disabled"; + }; + + actuator0: qcom,actuator@18 { + cell-index = <0>; + reg = <0x18>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8941_l23>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3000000>; + qcom,cam-vreg-max-voltage = <3000000>; + qcom,cam-vreg-op-mode = <100000>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,secure = <1>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator0>; + qcom,eeprom-src = <&eeprom0>; + cam_vdig-supply = <&pm8994_s3>; + cam_vio-supply = <&pm8994_lvs1>; + cam_vana-supply = <&pm8994_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana"; + qcom,cam-vreg-min-voltage = <1300000 0 2500000>; + qcom,cam-vreg-max-voltage = <1300000 0 2500000>; + qcom,cam-vreg-op-mode = <105000 0 80000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>, + <&tlmm 29 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + }; + +&i2c_freq_100Khz { + qcom,hw-thigh = <78>; + qcom,hw-tlow = <114>; + qcom,hw-tsu-sto = <28>; + qcom,hw-tsu-sta = <28>; + qcom,hw-thd-dat = <10>; + qcom,hw-thd-sta = <77>; + qcom,hw-tbuf = <118>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <1>; + status = "ok"; +}; + +&i2c_freq_400Khz { + qcom,hw-thigh = <20>; + qcom,hw-tlow = <28>; + qcom,hw-tsu-sto = <21>; + qcom,hw-tsu-sta = <21>; + qcom,hw-thd-dat = <13>; + qcom,hw-thd-sta = <18>; + qcom,hw-tbuf = <25>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + status = "ok"; +}; + +&i2c_freq_custom { + qcom,hw-thigh = <15>; + qcom,hw-tlow = <28>; + qcom,hw-tsu-sto = <21>; + qcom,hw-tsu-sta = <21>; + qcom,hw-thd-dat = <13>; + qcom,hw-thd-sta = <18>; + qcom,hw-tbuf = <25>; + qcom,hw-scl-stretch-en = <1>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + status = "ok"; +}; + +&i2c_freq_1Mhz { + qcom,hw-thigh = <16>; + qcom,hw-tlow = <22>; + qcom,hw-tsu-sto = <17>; + qcom,hw-tsu-sta = <18>; + qcom,hw-thd-dat = <16>; + qcom,hw-thd-sta = <15>; + qcom,hw-tbuf = <19>; + qcom,hw-scl-stretch-en = <1>; + qcom,hw-trdhld = <3>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cpp.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cpp.txt new file mode 100644 index 0000000000000000000000000000000000000000..450e4d6ee8f0490b028cc725088b7418f5a2723d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cpp.txt @@ -0,0 +1,145 @@ +* Qualcomm Technologies, Inc. MSM CPP + +Required properties: +- cell-index: cpp hardware core index +- compatible : + - "qcom,cpp" +- reg : offset and length of the register set for the device + for the cpp operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. + - cpp - has CPP MICRO register set. + - cpp_vbif - has VBIF core register set used by CPP. + - cpp_hw - has CPP hardware register set. +- interrupts : should contain the cpp interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- vdd-supply: phandle to GDSC regulator controlling VFE & CPP core. +- clocks: list of phandles to the clock controller device and coresponding + clock names. +- clock-names: name of the clocks required for the device used by the consumer. +- qcom,clock-rates: clock rate in Hz. +- qcom,min-clock-rate: minimum clock rate in Hz, to be set to CPP hardware in + case dynamic clock scaling based on prevalent streams need lower clock rate. +- qcom,cpp-fw-payload-info: Child node for cpp node having infomration on + cpp firmware payload offsets. This is mandatory node. +- resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. +- reset-names: reset signal name strings sorted in the same order as the resets + property. +- qcom,src-clock-rates = This is an array which holds clock rates for cpp src + clocks. The maximum size for the array is 10. + +Required properties of the child node: +- qcom,stripe-base = Base offset of stripes in cpp payload. +- qcom,plane-base = Base offset of planes in cpp payload. +- qcom,stripe-size = size of each stripe in payload. +- qcom,plane-size = size of each plane in payload. +- qcom,fe-ptr-off = offset from stripe base to fetch engine address + location in payload. +- qcom,we-ptr-off = offset from stripe base to write engine address + location in payload. + +Optional properties of the child node: +- qcom,ref-fe-ptr-off = offset from stripe base to reference fetch engine + address location in payload. +- qcom,ref-we-ptr-off = offset from stripe base to reference write engine + address location in payload. +- qcom,we-meta-ptr-off = offset from stripe base to metadata address + location in payload. +- qcom,fe-mmu-pf-ptr-off = offset from plane base to fetch engine mmu prefetch + address min location in payload. +- qcom,ref-fe-mmu-pf-ptr-off = offset from plane base to reference fetch engine + mmu prefetch address min location in payload. +- qcom,we-mmu-pf-ptr-off = offset from plane base to write engine mmu prefetch + address min location in payload. +- qcom,dup-we-mmu-pf-ptr-off = offset from plane base to duplicate write engine + mmu prefetch address min location in payload. +- qcom,ref-we-mmu-pf-ptr-off = offset from plane base to reference write engine + mmu prefetch address min location in payload. +- qcom,set-group-buffer-len = length/size of set group buffer command used for + hfr. +- qcom,dup-frame-indicator-off = offset for duplicate frame indicator in a + batch for frames + +Optional properties: +- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic. +- camss-vdd-supply: phandle to GDSC regulator controlling camss. +- qcom,bus-master: Flag for presence of CPP bus master. It has to be set only for + platforms that support such feature. +- qcom,vbif-setting: The offset and value for vbif core qos registers. + The first entry is register offset and second entry is register value. +- qcom,micro-reset: Boolean flag indicating if micro reset need to be enabled. + This needs to present on platforms that support this feature. +- qcom,cpp-cx-ipeak: To handle Cx peak current limit. + + phandle - phandle of cx ipeak device node + bit - bit number of client in relevant register + This is used to access Cx ipeak HW module to limit the current drawn by + various subsystem blocks on Cx power rail. CPP set their bit in tcsr register + if it is going to cross its own threshold. + +Example: + + qcom,cpp@fda04000 { + cell-index = <0>; + compatible = "qcom,cpp"; + reg = <0xfda04000 0x100>, + <0xfda80000 0x200>, + <0xfda18000 0x008>, + <0xfd8c36D4 0x4>; + reg-names = "cpp", "cpp_vbif", "cpp_hw", "camss_cpp"; + interrupts = <0 49 0>; + interrupt-names = "cpp"; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + camss-vdd-supply = <&gdsc_camss_top>; + vdd-supply = <&gdsc_cpp>; + clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_gcc clk_mmssnoc_axi_clk>, + <&clock_mmss clk_mmagic_camss_axi_clk>, + <&clock_mmss clk_camss_top_ahb_clk>, + <&clock_mmss clk_cpp_clk_src>, + <&clock_mmss clk_camss_cpp_ahb_clk>, + <&clock_mmss clk_camss_cpp_axi_clk>, + <&clock_mmss clk_camss_cpp_clk>, + <&clock_mmss clk_camss_micro_ahb_clk>, + <&clock_mmss clk_camss_ahb_clk>; + <&clock_mmss clk_smmu_cpp_axi_clk>, + <&clock_mmss clk_camss_cpp_vbif_ahb_clk>, + clock-names = "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk", + "mmagic_camss_axi_clk", "camss_top_ahb_clk", + "cpp_core_clk", "camss_cpp_ahb_clk", + "camss_cpp_axi_clk", "camss_cpp_clk", + "micro_iface_clk", "camss_ahb_clk"; + "smmu_cpp_axi_clk", "cpp_vbif_ahb_clk"; + qcom,clock-rates = <0 0 0 0 465000000 0 0 465000000 0 0 0 0>; + qcom,cpp-cx-ipeak = <&cx_ipeak_lm 2>; + qcom,min-clock-rate = <320000000>; + qcom,bus-master = <1>; + qcom,vbif-qos-setting = <0x20 0x10000000>, + <0x24 0x10000000>, + <0x28 0x10000000>, + <0x2C 0x10000000>; + qcom,src-clock-rates = <100000000 200000000 384000000 404000000 + 480000000 576000000 600000000>; + qcom,micro-reset; + qcom,cpp-fw-payload-info { + qcom,stripe-base = <553>; + qcom,plane-base = <481>; + qcom,stripe-size = <61>; + qcom,plane-size = <24>; + qcom,fe-ptr-off = <11>; + qcom,we-ptr-off = <23>; + qcom,ref-fe-ptr-off = <17>; + qcom,ref-we-ptr-off = <36>; + qcom,we-meta-ptr-off = <42>; + qcom,fe-mmu-pf-ptr-off = <6>; + qcom,ref-fe-mmu-pf-ptr-off = <9>; + qcom,we-mmu-pf-ptr-off = <12>; + qcom,dup-we-mmu-pf-ptr-off = <17>; + qcom,ref-we-mmu-pf-ptr-off = <22>; + qcom,set-group-buffer-len = <135>; + qcom,dup-frame-indicator-off = <70>; + resets = <&clock_mmss MMSS_CAMSS_MICRO_BCR>; + reset-names = "micro_iface_reset"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-csi-phy.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-csi-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..24a3443113e5e8511145abfd59ec42464b9df901 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-csi-phy.txt @@ -0,0 +1,41 @@ +* Qualcomm Technologies, Inc. MSM CSI Phy + +Required properties: +- cell-index: csi phy hardware core index +- compatible : + - "qcom,csiphy" + - "qcom,csiphy-v2.0" + - "qcom,csiphy-v2.2" + - "qcom,csiphy-v3.0" + - "qcom,csiphy-v3.1" + - "qcom,csiphy-v3.1.1" + - "qcom,csiphy-v3.2" + - "qcom,csiphy-v3.4.2" + - "qcom,csiphy-v3.5" + - "qcom,csiphy-v5.0" + - "qcom,csiphy-v5.01" + - "qcom,csiphy-v10.00" +- reg : offset and length of the register set for the device + for the csiphy operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should contain the csiphy interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- clock-names: name of the clocks required for the device +- qcom,clock-rates: clock rate in Hz + - 0 if appropriate clock is required but doesn't have to apply the rate + +Example: + + qcom,csiphy@fda0ac00 { + cell-index = <0>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0xfda0ac00 0x200>; + reg-names = "csiphy"; + interrupts = <0 78 0>; + interrupt-names = "csiphy"; + clock-names = "camss_top_ahb_clk", + "ispif_ahb_clk", "csiphy_timer_src_clk", + "csiphy_timer_clk"; + qcom,clock-rates = <0 0 200000000 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-csid.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-csid.txt new file mode 100644 index 0000000000000000000000000000000000000000..340d98688b76cc3d3eab1059efbaf2ae8554c92e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-csid.txt @@ -0,0 +1,52 @@ +* Qualcomm Technologies, Inc. MSM CSID + +Required properties: +- cell-index: csid hardware core index +- compatible : + - "qcom,csid" + - "qcom,csid-v2.0" + - "qcom,csid-v2.2" + - "qcom,csid-v3.0" + - "qcom,csid-v3.1" + - "qcom,csid-v3.2" + - "qcom,csid-v3.5" + - "qcom,csid-v4.0" + - "qcom,csid-v3.4.2" + - "qcom,csid-v3.5.1" + - "qcom,csid-v3.4.3" + - "qcom,csid-v5.0" +- reg : offset and length of the register set for the device + for the csid operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should contain the csid interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- qcom,csi-vdd-voltage : should specify voltage level + for mipi csi in uV. +- qcom,mipi-csi-vdd-supply : should contain regulator to be used for + this csid core +- clock-names: name of the clocks required for the device +- qcom,clock-rates: clock rate in Hz + - 0 if appropriate clock is required but doesn't have to apply the rate + +Optional properties: +- qcom,cam-vreg-name : name of the voltage regulators required for the device. +- gdscr-supply : should contain regulator used for csid clocks. +- mmagic-supply : should contain mmagic regulator used for mmagic clocks. + +Example: + + qcom,csid@fda08000 { + cell-index = <0>; + compatible = "qcom,csid-v2.0", "qcom,csid"; + reg = <0xfda08000 0x200>; + reg-names = "csid"; + interrupts = <0 51 0>; + interrupt-names = "csiphy"; + qcom,csi-vdd-voltage = <1800000>; + qcom,mipi-csi-vdd-supply = <&pm8941_l12>; + clock-names = "camss_top_ahb_clk", "ispif_ahb_clk", + "csi_ahb_clk", "csi_src_clk", "csi_clk", + "csi_phy_clk", "csi_pix_clk", "csi_rdi_clk"; + qcom,clock-rates = <0 0 0 200000000 0 0 0 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cvp.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cvp.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cf63676cd6915f92301048fb057b6983a30ff73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-cvp.txt @@ -0,0 +1,152 @@ +* Qualcomm Technologies, Inc. MSM CVP + +[Root level node] +cvp +===== +Required properties: +- compatible : one of: + - "qcom,msm-cvp" + - "qcom,kona-cvp" : Invokes driver specific data for Kona. + +Optional properties: +- reg : offset and length of the CSR register set for the device. +- interrupts : should contain the cvp interrupt. +- qcom,reg-presets : list of offset-value pairs for registers to be written. + The offsets are from the base offset specified in 'reg'. This is mainly + used for QoS, VBIF, etc. presets for video. +- qcom,qdss-presets : list of physical address and memory allocation size pairs. + when fw_debug_mode is set as HFI_DEBUG_MODE_QDSS, all firmware messages will be + written to QDSS memory. +- *-supply: A phandle pointing to the appropriate regulator. Number of + regulators vary across targets. +- clock-names: an array of clocks that the driver is supposed to be + manipulating. The clocks names here correspond to the clock names used in + clk_get(). +- qcom,clock-configs = an array of bitmaps of clocks' configurations. The index + of the bitmap corresponds to the clock at the same index in qcom,clock-names. + The bitmaps describes the actions that the device needs to take regarding the + clock (i.e. scale it based on load). + + The bitmap is defined as: + scalable = 0x1 (if the driver should vary the clock's frequency based on load) +- qcom,allowed-clock-rates = an array of supported clock rates by the chipset. +- qcom,use-non-secure-pil = A bool indicating which type of pil to use to load + the fw. +- qcom,fw-bias = The address at which cvp fw is loaded (manually). + +[Second level nodes] +Context Banks +============= +Required properties: +- compatible : one of: + - "qcom,msm-cvp,context-bank" +- iommus : A phandle parsed by smmu driver. Number of entries will vary + across targets. + +Optional properties: +- label - string describing iommu domain usage. +- buffer-types : bitmap of buffer types that can be mapped into the current + IOMMU domain. + - Buffer types are defined as the following: + input = 0x1 + output = 0x2 + output2 = 0x4 + extradata input = 0x8 + extradata output = 0x10 + extradata output2 = 0x20 + internal scratch = 0x40 + internal scratch1 = 0x80 + internal scratch2 = 0x100 + internal persist = 0x200 + internal persist1 = 0x400 + internal cmd queue = 0x800 +- virtual-addr-pool : offset and length of virtual address pool. +- qcom,fw-context-bank : bool indicating firmware context bank. +- qcom,secure-context-bank : bool indicating secure context bank. + +Buses +===== +Required properties: +- compatible : one of: + - "qcom,msm-cvp,bus" +- label : an arbitrary name +- qcom,bus-master : an integer descriptor of the bus master. Refer to arch/arm/\ + boot/dts/include/dt-bindings/msm/msm-bus-ids.h for list of acceptable masters +- qcom,bus-slave : an integer descriptor of the bus slave. Refer to arch/arm/\ + boot/dts/include/dt-bindings/msm/msm-bus-ids.h for list of acceptable slaves + +Optional properties: +- qcom,bus-governor : governor to use when scaling bus, generally any commonly + found devfreq governor might be used. In addition to those governors, the + custom Venus governors, "msm-vidc-ddr" or "msm-vidc-llcc" are also + acceptable values. + In the absence of this property the "performance" governor is used. +- qcom,bus-rage-kbps : an array of two items () that indicate the + minimum and maximum acceptable votes for the bus. + In the absence of this property <0 INT_MAX> is used. +- qcom,ubwc-10bit : UBWC 10 bit content has different bus requirements, + this tag will be used to pick the appropriate bus as per the session profile + as shown below in example. + +Memory Heaps +============ +Required properties: +- compatible : one of: + - "qcom,msm-vidc,mem-cdsp" +- memory-region : phandle to the memory heap/region. + +Example: + msm_cvp: qcom,cvp@ab00000 { + compatible = "qcom,msm-cvp", "qcom,kona-cvp"; + status = "ok"; + reg = <0xab00000 0x100000>; + interrupts = ; + + /* FIXME: LLCC Info */ + /* cache-slice-names = "vidsc0", "vidsc1"; */ + /* cache-slices = <&llcc 2>, <&llcc 3>; */ + + /* Supply */ + cvp-supply = <&mvs1_gdsc>; + + /* Clocks */ + clock-names = "gcc_video_axi0", + "gcc_video_axi1", "cvp_clk"; + clocks = <&clock_gcc GCC_VIDEO_AXI0_CLK>, + <&clock_gcc GCC_VIDEO_AXI1_CLK>, + <&clock_videocc VIDEO_CC_MVS1_CLK>; + qcom,proxy-clock-names = "gcc_video_axi0", "gcc_video_axi1", + "cvp_clk"; + + qcom,clock-configs = <0x0 0x0 0x1>; + qcom,allowed-clock-rates = <403000000 520000000 + 549000000 666000000 800000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-cvp,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-cvp,context-bank"; + label = "cvp_hlos"; + iommus = + <&apps_smmu 0x2120 0x400>; + qcom,iommu-dma = "disabled"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x4b000000 0xe0000000>; + }; + + /* Memory Heaps */ + qcom,msm-cvp,mem_cdsp { + compatible = "qcom,msm-cvp,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-eeprom.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-eeprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5bfba5672fa21cc8bbe7f710a0f056475654b68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-eeprom.txt @@ -0,0 +1,199 @@ +* Qualcomm Technologies, Inc. MSM EEPROM + +EEPROM is a one time programmed(OTP) device that stores the calibration data +use for camera sensor. It may either be integrated in the sensor module or in +the sensor itself. As a result, the power, clock and GPIOs may be the same as +the camera sensor. The following describes the page block map, power supply, +clock, GPIO and power on sequence properties of the EEPROM device. + +Required properties if probe happens from camera daemon: +- cell-index: eeprom hardware core index +- compatible : + - "qcom,eeprom" +- reg : offset of eeprom device registers. +- qcom,cci-master : should specify the cci core index that eeprom use. +- cam_vio-supply : should contain regulator to be used for the IO vdd. +- qcom,cam-vreg-name : should specify the regulator name to be used for + this eeprom. +- qcom,cam-vreg-type : should specify the regulator type to be used for + this eeprom. +- qcom,cam-vreg-min-voltage : should specify minimum voltage level + for eeprom in uV. +- qcom,cam-vreg-max-voltage : should specify maximum voltage level + for eeprom in uV. +- qcom,cam-vreg-op-mode : should specify current level for eeprom in uA. +- qcom,gpio-no-mux : should specify the gpio mux type. +- gpios : should specify the gpios to be used for the eeprom. +- qcom,gpio-reset : should specify the reset gpio index. +- qcom,gpio-standby : should specify the standby gpio index. +- qcom,gpio-req-tbl-num : should specify the gpio table index. +- qcom,gpio-req-tbl-flags : should specify the gpio functions. +- qcom,gpio-req-tbl-label : should specify the gpio labels. +- qcom,cam-power-seq-type : should specify the power on sequence types. +- qcom,cam-power-seq-val : should specify the power on sequence values. +- qcom,cam-power-seq-cfg-val : should specify the power on sequence config + values. +- qcom,cam-power-seq-delay : should specify the power on sequence delay + time in ms. + +Optional properties: +- cam_vdig-supply : should contain regulator to be used for the digital vdd. + + + +Example: + + eeprom0: qcom,eeprom@60 { + cell-index = <0>; + reg = <0x60 0x0>; + compatible = "qcom,eeprom"; + qcom,cci-master = <0>; + cam_vdig-supply = <&pm8226_l5>; + cam_vio-supply = <&pm8226_lvs1>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio"; + qcom,cam-vreg-type = <0 1>; + qcom,cam-vreg-min-voltage = <1200000 0>; + qcom,cam-vreg-max-voltage = <1200000 0>; + qcom,cam-vreg-op-mode = <200000 0>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + qcom,cam-power-seq-type = "sensor_vreg", + "sensor_vreg", "sensor_clk", + "sensor_gpio", "sensor_gpio"; + qcom,cam-power-seq-val = "cam_vdig", + "cam_vio", "sensor_cam_mclk", + "sensor_gpio_reset", + "sensor_gpio_standby"; + qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>; + qcom,cam-power-seq-delay = <1 1 5 5 10>; + }; + + + +Required properties if eeprom probe is kernel probe: +- cell-index: eeprom hardware core index +- compatible : + - "qcom,eeprom" +- reg : offset of eeprom device registers. +- qcom,eeprom-name : should specify relevant names of the eeprom module + library. +- qcom,slave-addr : should specify the slave address of the eeprom. +- qcom,cci-master : should specify the cci core index that eeprom use. +- qcom,num-blocks : should specify the total block number that eeprom contains, + every block should contains page poll and mem. +- qcom,page%d : number %d page size, start address, address type, data, + data type, delay in ms. size 0 stand for non-paged. + - address type : 1 byte, 2 word. + - data type : 1 byte, 2 word. +- qcom,poll%d : number %d poll size, poll reg address, address type, data, + data type, delay in ms. size 0 stand for not used. + - address type : 1 byte, 2 word. + - data type : 1 byte, 2 word. +- qcom,mem%d : number %d memory size, start address, address type, data, + data type, delay in ms. size 0 stand for not used. + - address type : 1 byte, 2 word. + - data type : 1 byte, 2 word. +- cam_vio-supply : should contain regulator to be used for the IO vdd. +- qcom,cam-vreg-name : should specify the regulator name to be used for + this eeprom. +- qcom,cam-vreg-type : should specify the regulator type to be used for + this eeprom. +- qcom,cam-vreg-min-voltage : should specify minimum voltage level + for eeprom in uV. +- qcom,cam-vreg-max-voltage : should specify maximum voltage level + for eeprom in uV. +- qcom,cam-vreg-op-mode : should specify current level for eeprom in uA. +- pinctrl-names : should specify the pin control groups followed by + the definition of each group +- qcom,gpio-no-mux : should specify the gpio mux type. +- gpios : should specify the gpios to be used for the eeprom. +- qcom,gpio-reset : should specify the reset gpio index. +- qcom,gpio-standby : should specify the standby gpio index. +- qcom,gpio-req-tbl-num : should specify the gpio table index. +- qcom,gpio-req-tbl-flags : should specify the gpio functions. +- qcom,gpio-req-tbl-label : should specify the gpio labels. +- qcom,cam-power-seq-type : should specify the power on sequence types. +- qcom,cam-power-seq-val : should specify the power on sequence values. +- qcom,cam-power-seq-cfg-val : should specify the power on sequence config + values. +- qcom,cam-power-seq-delay : should specify the power on sequence delay + time in ms. + +Optional properties: +- qcom,pageen%d : number %d page enable reg size, start address, address type, + data, data type, delay in ms. size 0 stand for not used. +- cam_vdig-supply : should contain regulator to be used for the digital vdd. +- qcom,saddr%d : property should specify the slave address for block (%d). +- qcom,i2c-freq-mode : property should specify the I2C speed mode. + +Optional properties -EEPROM Camera Multimodule +- qcom,cmm-data-support - Camera MultiModule data capability flag. +- qcom,cmm-data-compressed - Camera MultiModule data compression flag. +- qcom,cmm-data-offset - Camera MultiModule data start offset. +- qcom,cmm-data-size - Camera MultiModule data size. + + + +Example: + + eeprom0: qcom,eeprom@60 { + cell-index = <0>; + reg = <0x60 0x0>; + qcom,eeprom-name = "msm_eeprom"; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x60>; + qcom,cci-master = <0>; + qcom,num-blocks = <2>; + qcom,page0 = <1 0x0100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0 1 1>; + qcom,mem0 = <0 0x0 2 0 1 0>; + qcom,page1 = <1 0x0200 2 0x8 1 1>; + qcom,pageen1 = <1 0x0202 2 0x01 1 10>; + qcom,poll1 = <0 0x0 2 0 1 1>; + qcom,mem1 = <32 0x3000 2 0 1 0>; + qcom,saddr1 = <0x62>; + + qcom,cmm-data-support; + qcom,cmm-data-compressed; + qcom,cmm-data-offset = <0>; + qcom,cmm-data-size = <0>; + + cam_vdig-supply = <&pm8226_l5>; + cam_vio-supply = <&pm8226_lvs1>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio"; + qcom,cam-vreg-type = <0 1>; + qcom,cam-vreg-min-voltage = <1200000 0>; + qcom,cam-vreg-max-voltage = <1200000 0>; + qcom,cam-vreg-op-mode = <200000 0>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + qcom,cam-power-seq-type = "sensor_vreg", + "sensor_vreg", "sensor_clk", + "sensor_gpio", "sensor_gpio"; + qcom,cam-power-seq-val = "cam_vdig", + "cam_vio", "sensor_cam_mclk", + "sensor_gpio_reset", + "sensor_gpio_standby"; + qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>; + qcom,cam-power-seq-delay = <1 1 5 5 10>; + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-fd.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-fd.txt new file mode 100644 index 0000000000000000000000000000000000000000..05635999a86a27ce24a2f7b6be960cd065b3b38e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-fd.txt @@ -0,0 +1,99 @@ +* Qualcomm Technologies, Inc. MSM FD + +Face detection hardware block. +The Face Detection Hardware Block will offload processing +on the host and also reduce power consumption. +Supports: +Front and back camera face detection concurrently. +Sizes: QVGA, VGA, WQVGA, WVGA at 20 pix minimum face size. + +Required properties: + +- compatible: + - "qcom,face-detection" +- reg: offset and length of the register set for the device. +- reg-names: should specify relevant names to each reg property defined. + - "fd_core" - FD CORE hardware register set. + - "fd_misc" - FD MISC hardware register set. + - "fd_vbif" - FD VBIF hardware register set. +- interrupts: should contain the fd interrupts. From fd cores with + revisions 0x10010000 and higher, power collapse sequence is required. + Face detection misc irq is needed to perform power collapse. +- interrupt-names: should specify relevant names to each interrupts + property defined. +- vdd-supply: phandle to GDSC regulator controlling face detection hw. +- clocks: list of entries each of which contains: + - phandle to the clock controller. + - macro containing clock's name in hardware. +- clock-names: should specify relevant names to each clocks + property defined. + +Optional properties: + +- clock-rates: should specify clock rates in Hz to each clocks + property defined. + If we want to have different operating clock frequencies we can define + rate levels. They should be defined in incremental order. +- qcom,bus-bandwidth-vectors: Specifies instant and average bus bandwidth + vectors per clock rate. + Each of entries contains: + - ab. Average bus bandwidth (Bps). + - ib. Instantaneous bus bandwidth (Bps). +- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic. +- camss-vdd-supply: phandle to GDSC regulator controlling camss. +- qcom,fd-core-reg-settings: relative address offsets and value pairs for + FD CORE registers and bit mask. + Format: +- qcom,fd-misc-reg-settings: relative address offsets and value pairs for + FD MISC registers and bit mask. + Format: +- qcom,fd-vbif-reg-settings: relative address offsets and value pairs for + FD VBIF registers and bit mask. + Format: + +Example: + + qcom,fd@fd878000 { + compatible = "qcom,face-detection"; + reg = <0xfd878000 0x800>, + <0xfd87c000 0x800>, + <0xfd860000 0x1000>; + reg-names = "fd_core", "fd_misc", "fd_vbif"; + interrupts = <0 316 0>; + interrupt-names = "fd"; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + camss-vdd-supply = <&gdsc_camss_top>; + vdd-supply = <&gdsc_fd>; + qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd"; + clocks = <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_gcc clk_mmssnoc_axi_clk>, + <&clock_mmss clk_mmagic_camss_axi_clk>, + <&clock_mmss clk_camss_top_ahb_clk>, + <&clock_mmss clk_fd_core_clk_src>, + <&clock_mmss clk_fd_core_clk>, + <&clock_mmss clk_fd_core_uar_clk>, + <&clock_mmss clk_fd_ahb_clk>, + <&clock_mmss clk_smmu_cpp_axi_clk>, + <&clock_mmss clk_camss_ahb_clk>, + <&clock_mmss clk_camss_cpp_axi_clk>, + <&clock_mmss clk_camss_cpp_vbif_ahb_clk>, + <&clock_mmss clk_smmu_cpp_ahb_clk>; + clock-names = "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk" , + "mmagic_camss_axi_clk", "camss_top_ahb_clk", + "fd_core_clk_src", "fd_core_clk", + "fd_core_uar_clk", "fd_ahb_clk", + "smmu_cpp_axi_clk", "camss_ahb_clk", + "camss_cpp_axi_clk", "cpp_vbif_ahb_clk", + "smmu_cpp_ahb_clk"; + clock-rates = <0 0 0 0 400000000 400000000 400000000 80000000 0 0 0 0 0>; + qcom,bus-bandwidth-vectors = <13000000 13000000>, + <45000000 45000000>, + <90000000 90000000>; + qcom,fd-vbif-reg-settings = <0x20 0x10000000 0x30000000>, + <0x24 0x10000000 0x30000000>, + <0x28 0x10000000 0x30000000>, + <0x2c 0x10000000 0x30000000>; + qcom,fd-misc-reg-settings = <0x20 0x2 0x3>, + <0x24 0x2 0x3>; + qcom,fd-core-reg-settings = <0x8 0x20 0xffffffff>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-ispif.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-ispif.txt new file mode 100644 index 0000000000000000000000000000000000000000..3df158035cd8397e0eb908a3ebca7744047f7b01 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-ispif.txt @@ -0,0 +1,158 @@ +* Qualcomm Technologies, Inc. MSM ISPIF + +Required properties: +- cell-index: ispif hardware core index +- compatible : + - "qcom,ispif" + - "qcom,ispif-v3.0" +- reg : offset and length of the register set for the device + for the ispif operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should contain the ispif interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- camss-vdd-supply: phandle to GDSC regulator. +- mmagic-vdd-supply: phandle to mmagic regulator. +- vfe0-vdd-supply: phandle to vfe0 regulator. +- vfe1-vdd-supply: phandle to vfe1 regulator. +- clocks: list of phandles to the clock controller device and coresponding + clock names. +- clock-names: name of the clocks required for the device used by the consumer. +- qcom,clock-rates: clock rate in Hz. +- qcom,clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property qcom,clock-rates. + +Optional properties: +- qcom,num-isps: The number of ISPs the ISPIF module is connected to. If not set + the default value used is 1 + +Example: + + qcom,ispif@fda0a000 { + cell-index = <0>; + compatible = "qcom,ispif"; + reg = <0xfda0a000 0x300>; + reg-names = "ispif"; + interrupts = <0 55 0>; + interrupt-names = "ispif"; + camss-vdd-supply = <&gdsc_camss_top>; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + vfe0-vdd-supply = <&gdsc_vfe0>; + vfe1-vdd-supply = <&gdsc_vfe1>; + clocks = <&clock_mmss clk_camss_ispif_ahb_clk>, + <&clock_mmss clk_csi0_clk_src>, + <&clock_mmss clk_camss_csi0_clk>, + <&clock_mmss clk_camss_csi0rdi_clk>, + <&clock_mmss clk_camss_csi0pix_clk>, + <&clock_mmss clk_csi1_clk_src>, + <&clock_mmss clk_camss_csi1_clk>, + <&clock_mmss clk_camss_csi1rdi_clk>, + <&clock_mmss clk_camss_csi1pix_clk>, + <&clock_mmss clk_csi2_clk_src>, + <&clock_mmss clk_camss_csi2_clk>, + <&clock_mmss clk_camss_csi2rdi_clk>, + <&clock_mmss clk_camss_csi2pix_clk>, + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_camss_csi3_clk>, + <&clock_mmss clk_camss_csi3rdi_clk>, + <&clock_mmss clk_camss_csi3pix_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_camss_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe1_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>; + clock-names = "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_pix_clk", "csi0_rdi_clk", + "csi1_src_clk", "csi1_clk", + "csi1_pix_clk", "csi1_rdi_clk", + "csi2_src_clk", "csi2_clk", + "csi2_pix_clk", "csi2_rdi_clk", + "csi3_src_clk", "csi3_clk", + "csi3_pix_clk", "csi3_rdi_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk"; + qcom,clock-rates = <0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE"; + + }; + +or + + qcom,ispif@fda0a000 { + cell-index = <0>; + compatible = "qcom,ispif-v3.0", "qcom,ispif"; + reg = <0xfda0a000 0x300>; + reg-names = "ispif"; + interrupts = <0 55 0>; + interrupt-names = "ispif"; + qcom,num-isps = <2> + vdd-supply = <&gdsc_camss_top>; + clocks = <&clock_mmss clk_camss_ispif_ahb_clk>, + <&clock_mmss clk_csi0_clk_src>, + <&clock_mmss clk_camss_csi0_clk>, + <&clock_mmss clk_camss_csi0rdi_clk>, + <&clock_mmss clk_camss_csi0pix_clk>, + <&clock_mmss clk_csi1_clk_src>, + <&clock_mmss clk_camss_csi1_clk>, + <&clock_mmss clk_camss_csi1rdi_clk>, + <&clock_mmss clk_camss_csi1pix_clk>, + <&clock_mmss clk_csi2_clk_src>, + <&clock_mmss clk_camss_csi2_clk>, + <&clock_mmss clk_camss_csi2rdi_clk>, + <&clock_mmss clk_camss_csi2pix_clk>, + <&clock_mmss clk_csi3_clk_src>, + <&clock_mmss clk_camss_csi3_clk>, + <&clock_mmss clk_camss_csi3rdi_clk>, + <&clock_mmss clk_camss_csi3pix_clk>, + <&clock_mmss clk_vfe0_clk_src>, + <&clock_mmss clk_camss_vfe0_clk>, + <&clock_mmss clk_camss_csi_vfe0_clk>, + <&clock_mmss clk_vfe1_clk_src>, + <&clock_mmss clk_camss_vfe1_clk>, + <&clock_mmss clk_camss_csi_vfe1_clk>; + clock-names = "ispif_ahb_clk", + "csi0_src_clk", "csi0_clk", + "csi0_pix_clk", "csi0_rdi_clk", + "csi1_src_clk", "csi1_clk", + "csi1_pix_clk", "csi1_rdi_clk", + "csi2_src_clk", "csi2_clk", + "csi2_pix_clk", "csi2_rdi_clk", + "csi3_src_clk", "csi3_clk", + "csi3_pix_clk", "csi3_rdi_clk", + "vfe0_clk_src", "camss_vfe_vfe0_clk", "camss_csi_vfe0_clk", + "vfe1_clk_src", "camss_vfe_vfe1_clk", "camss_csi_vfe1_clk"; + qcom,clock-rates = <0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 200000000 0 0 0 + 0 0 0 + 0 0 0>; + qcom,clock-control = "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "SET_RATE", "NO_SET_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", "NO_SET_RATE", "NO_SET_RATE"; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-jpeg.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-jpeg.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f9f24bfa1cee50f9b099b40bd9f8029ba1cb8f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-jpeg.txt @@ -0,0 +1,139 @@ +* Qualcomm Technologies, Inc. MSM JPEG + +Required properties: +- cell-index: jpeg hardware core index +- compatible : + - "qcom,jpeg" + - "qcom,jpeg_dma" +- reg : offset and length of the register set of jpeg device and vbif device + for the jpeg operating in compatible mode. +- reg-names : should specify relevant names to each reg property defined. +- interrupts : should contain the jpeg interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. +- clock-names : names of clocks required for the device. +- clocks : clocks required for the device. +- qcom, clock-rates: rates of the required clocks. +- vdd-supply: phandle to GDSC regulator controlling JPEG core. +- mmagic-vdd-supply: phandle to GDSC regulator controlling mmagic. +- camss-vdd-supply: phandle to GDSC regulator controlling camss. + +Optional properties: +- qcom,vbif-reg-settings: relative address offsets and value pairs for VBIF registers. +- qcom,qos-reg-settings: relative address offsets and value pairs for QoS registers. +- qcom,prefetch-reg-settings: relative address offsets and value pairs for + MMU prefetch registers. + +Example: + + qcom,jpeg@a1c000 { + cell-index = <0>; + compatible = "qcom,jpeg"; + reg = <0xa1c000 0x4000>, + <0xa60000 0x3000>; + reg-names = "jpeg"; + interrupts = <0 316 0>; + interrupt-names = "jpeg"; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + camss-vdd-supply = <&gdsc_camss_top>; + vdd-supply = <&gdsc_jpeg>; + qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd"; + clock-names = "core_clk", "iface_clk", "bus_clk0", + "camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk", + "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk", + "mmagic_camss_axi_clk"; + clocks = <&clock_mmss clk_camss_jpeg0_clk>, + <&clock_mmss clk_camss_jpeg_ahb_clk>, + <&clock_mmss clk_camss_jpeg_axi_clk>, + <&clock_mmss clk_camss_top_ahb_clk>, + <&clock_mmss clk_camss_ahb_clk>, + <&clock_mmss clk_smmu_jpeg_axi_clk>, + <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_gcc clk_mmssnoc_axi_clk>, + <&clock_mmss clk_mmagic_camss_axi_clk>; + qcom,clock-rates = <320000000 0 0 0 0 0 0 0 0>; + qcom,vbif-reg-settings = <0x4 0x1>, + <0xb0 0x00100010>, + <0xc0 0x10001000>; + qcom,qos-reg-settings = <0x28 0x00000008>; + qcom,prefetch-reg-settings = <0x30c 0x1111>, + <0x318 0x31>, + <0x324 0x31>, + <0x330 0x31>, + <0x33c 0x0>; + status = "ok"; + }; + + qcom,jpeg@a24000 { + cell-index = <2>; + compatible = "qcom,jpeg"; + reg = <0xa24000 0x4000>, + <0xa60000 0x3000>; + reg-names = "jpeg"; + interrupts = <0 318 0>; + interrupt-names = "jpeg"; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + camss-vdd-supply = <&gdsc_camss_top>; + vdd-supply = <&gdsc_jpeg>; + qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd"; + clock-names = "core_clk", "iface_clk", "bus_clk0", + "camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk", + "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk", + "mmagic_camss_axi_clk"; + clocks = <&clock_mmss clk_camss_jpeg2_clk>, + <&clock_mmss clk_camss_jpeg_ahb_clk>, + <&clock_mmss clk_camss_jpeg_axi_clk>, + <&clock_mmss clk_camss_top_ahb_clk>, + <&clock_mmss clk_camss_ahb_clk>, + <&clock_mmss clk_smmu_jpeg_axi_clk>, + <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_gcc clk_mmssnoc_axi_clk>, + <&clock_mmss clk_mmagic_camss_axi_clk>; + qcom,clock-rates = <266670000 0 0 0 0 0 0 0 0>; + qcom,vbif-reg-settings = <0x4 0x1>, + <0xb0 0x00100010>, + <0xc0 0x10001000>; + qcom,qos-reg-settings = <0x28 0x00000008>; + qcom,prefetch-reg-settings = <0x30c 0x1111>, + <0x318 0x0>, + <0x324 0x31>, + <0x330 0x31>, + <0x33c 0x31>; + status = "ok"; + }; + + qcom,jpeg@aa0000 { + cell-index = <3>; + compatible = "qcom,jpeg_dma"; + reg = <0xaa0000 0x4000>, + <0xa60000 0x3000>; + reg-names = "jpeg"; + interrupts = <0 304 0>; + interrupt-names = "jpeg"; + mmagic-vdd-supply = <&gdsc_mmagic_camss>; + camss-vdd-supply = <&gdsc_camss_top>; + vdd-supply = <&gdsc_jpeg>; + qcom,vdd-names = "mmagic-vdd", "camss-vdd", "vdd"; + clock-names = "core_clk", "iface_clk", "bus_clk0", + "camss_top_ahb_clk", "camss_ahb_clk", "smmu_jpeg_axi_clk", + "mmss_mmagic_ahb_clk", "mmssnoc_axi_clk", + "mmagic_camss_axi_clk"; + clocks = <&clock_mmss clk_camss_jpeg_dma_clk>, + <&clock_mmss clk_camss_jpeg_ahb_clk>, + <&clock_mmss clk_camss_jpeg_axi_clk>, + <&clock_mmss clk_camss_top_ahb_clk>, + <&clock_mmss clk_camss_ahb_clk>, + <&clock_mmss clk_smmu_jpeg_axi_clk>, + <&clock_mmss clk_mmss_mmagic_ahb_clk>, + <&clock_gcc clk_mmssnoc_axi_clk>, + <&clock_mmss clk_mmagic_camss_axi_clk>; + qcom,clock-rates = <266670000 0 0 0 0 0 0 0 0>; + qcom,vbif-reg-settings = <0x4 0x1>, + <0xb0 0x00100010>, + <0xc0 0x10001000>; + qcom,qos-reg-settings = <0x28 0x00000008>; + qcom,prefetch-reg-settings = <0x18c 0x11>, + <0x1a0 0x31>, + <0x1b0 0x31>; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-sde-rotator.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-sde-rotator.txt new file mode 100644 index 0000000000000000000000000000000000000000..534c59545156c4479110c4f08b36e4200d84422a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-sde-rotator.txt @@ -0,0 +1,237 @@ +SDE Rotator + +SDE rotator is a v4l2 rotator driver, which manages the rotator hw +block inside the Snapdragon Display Engine (or Mobile Display Subsystem) + +Required properties +- compatible: Must be "qcom,sde-rotator". +- reg: offset and length of the register set for the device. +- reg-names: names to refer to register sets related to this device +- interrupt-parent: phandle for the interrupt controller that + services interrupts for this device. +- interrupts: Interrupt associated with rotator. +- -supply: Phandle for regulator device node. +- qcom,supply-names: names to refer to regulator device node. +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. +- #list-cells: Number of rotator cells, must be 1 + +Bus Scaling Data: +- qcom,msm-bus,name: String property describing rotator client. +- qcom,msm-bus,num-cases: This is the the number of Bus Scaling use cases + defined in the vectors property. This must be + set to <3> for rotator driver where use-case 0 is + used to take off rotator BW votes from the system. + And use-case 1 & 2 are used in ping-pong fashion + to generate run-time BW requests. +- qcom,msm-bus,num-paths: This represents the number of paths in each + Bus Scaling Usecase. This value depends on + how many number of AXI master ports are + dedicated to rotator for particular chipset. +- qcom,msm-bus,vectors-KBps: * A series of 4 cell properties, with a format + of (src, dst, ab, ib) which is defined at + Documentation/devicetree/bindings/arm/msm/msm_bus.txt + * Current values of src & dst are defined at + include/linux/msm-bus-board.h + src values allowed for rotator are: + 25 = MSM_BUS_MASTER_ROTATOR + dst values allowed for rotator are: + 512 = MSM_BUS_SLAVE_EBI_CH0 + ab: Represents aggregated bandwidth. + ib: Represents instantaneous bandwidth. + * Total number of 4 cell properties will be + (number of use-cases * number of paths). + * These values will be overridden by the driver + based on the run-time requirements. So initial + ab and ib values defined here are random and + bare no logic except for the use-case 0 where ab + and ib values needs to be 0. + * Define realtime vector properties followed by + non-realtime vector properties. + +Optional properties +- qcom,rot-vbif-settings: Array with key-value pairs of constant VBIF register + settings used to setup MDSS QoS for optimum performance. + The key used should be offset from "rot_vbif_phys" register + defined in reg property. +- qcom,mdss-rot-block-size: This integer value indicates the size of a memory block + (in pixels) to be used by the rotator. If this property + is not specified, then a default value of 128 pixels + would be used. +- qcom,mdss-highest-bank-bit: This integer value indicate tile format as opposed to usual + linear format. The value tells the GPU highest memory + bank bit used. +- qcom,mdss-default-ot-wr-limit: This integer value indicates maximum number of pending + writes that can be allowed on each WR xin. + This value can be used to reduce the pending writes + limit and can be tuned to match performance + requirements depending upon system state. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot write limit + will enable this dynamic limiting for the write + operations in the platforms that require these + limits. +- qcom,mdss-default-ot-rd-limit: This integer value indicates the default number of pending + reads that can be allowed on each RD xin. + Some platforms require a dynamic ot limiting in + some cases. Setting this default ot read limit + will enable this dynamic limiting for the read + operations in the platforms that require these + limits. +- qcom,mdss-rot-vbif-qos-setting: This array is used to program vbif qos remapper register + priority for rotator clients. +- qcom,mdss-rot-vbif-memtype: Array of u32 vbif memory type settings for each xin port. +- qcom,mdss-rot-cdp-setting: Integer array of size two, to indicate client driven + prefetch is available or not. Index 0 represents + if CDP is enabled for read and index 1, if CDP + is enabled for write operation. +- qcom,mdss-rot-qos-lut A 4 cell property with the format of indicating the qos + lut settings for the rotator sspp and writeback + client. +- qcom,mdss-rot-danger-lut A two cell property with the format of indicating the danger lut settings for + the rotator sspp and writeback client. +- qcom,mdss-rot-safe-lut A two cell property with the format of indicating the safe lut settings for the + rotator sspp and writeback client. +- qcom,mdss-inline-rot-qos-lut: A 4 cell property with the format of indicating the qos + lut settings for the inline rotator sspp and + writeback client. +- qcom,mdss-inline-rot-danger-lut: A two cell property with the format of + indicating the danger lut + settings for the inline rotator sspp and + writeback client. +- qcom,mdss-inline-rot-safe-lut: A two cell property with the format of + indicating the safe lut + settings for the inline rotator sspp and + writeback client. +- qcom,mdss-rot-qos-cpu-mask: A u32 value indicating desired PM QoS CPU + affine mask. +- qcom,mdss-rot-qos-cpu-dma-latency: A u32 value indicating desired PM QoS CPU DMA + latency in usec. +- qcom,mdss-rot-mode: This is integer value indicates operation mode + of the rotator device +- qcom,mdss-sbuf-headroom: This integer value indicates stream buffer headroom in lines. +- qcom,mdss-rot-linewidth: This integer value indicates rotator line width supported in pixels. +- cache-slice-names: A set of names that identify the usecase names of a client that uses + cache slice. These strings are used to look up the cache slice + entries by name. +- cache-slices: The tuple has phandle to llcc device as the first argument and the + second argument is the usecase id of the client. +- qcom,sde-ubwc-malsize: A u32 property to specify the default UBWC + minimum allowable length configuration value. +- qcom,sde-ubwc-swizzle: A u32 property to specify the default UBWC + swizzle configuration value. +- qcom,rot-reg-bus: Property to provide Bus scaling for register + access for rotator blocks. +- power-domains: A phandle to respective power domain node. +- qcom,mdss-rot-parent: A 2 cell property, with format of (mdp phandle, + instance id), of mdp device. +- qcom,mdss-rot-xin-id: An integer array of xin-ids when nrt path for rotation + is not available. + +Subnode properties: +- compatible: Compatible name used in smmu v2. + smmu_v2 names should be: + "qcom,smmu_sde_rot_unsec"- smmu context bank device for + unsecure rotation domain. + "qcom,smmu_sde_rot_sec" - smmu context bank device for + secure rotation domain. +- iommus: specifies the SID's used by this context bank +- gdsc-mdss-supply: Phandle for mdss supply regulator device node. +- clocks: List of Phandles for clock device nodes + needed by the device. +- clock-names: List of clock names needed by the device. + + +Example: + mdss_rotator: qcom,mdss_rotator { + compatible = "qcom,sde_rotator"; + reg = <0xfd900000 0x22100>, + <0xfd925000 0x1000>; + reg-names = "mdp_phys", "rot_vbif_phys"; + + #list-cells = <1>; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + qcom,mdss-mdp-reg-offset = <0x00001000>; + + rot-vdd-supply = <&gdsc_mdss>; + qcom,supply-names = "rot-vdd"; + + clocks = <&clock_mmss clk_mmss_mdss_ahb_clk>, + <&clock_mmss clk_mmss_mdss_rot_clk>; + clock-names = "iface_clk", "rot_core_clk"; + + qcom,mdss-highest-bank-bit = <0x2>; + qcom,sde-ubwc-malsize = <0>; + qcom,sde-ubwc-swizzle = <1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>; + qcom,mdss-rot-vbif-memtype = <3 3>; + + com,mdss-rot-cdp-setting = <1 1>; + + qcom,mdss-default-ot-rd-limit = <8>; + qcom,mdss-default-ot-wr-limit = <16>; + + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0>; + + qcom,mdss-rot-qos-cpu-mask = <0xf>; + qcom,mdss-rot-qos-cpu-dma-latency = <75>; + + qcom,mdss-inline-rot-qos-lut = <0x0 0x0 0x00112233 0x44556677>; + qcom,mdss-inline-rot-danger-lut = <0x0 0x0000ffff>; + qcom,mdss-inline-rot-safe-lut = <0x0 0x0000ff00>; + + qcom,mdss-sbuf-headroom = <20>; + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&mdp_smmu 0xe00>; + gdsc-mdss-supply = <&gdsc_bimc_smmu>; + clocks = <&clock_mmss clk_bimc_smmu_ahb_clk>, + <&clock_mmss clk_bimc_smmu_axi_clk>; + clock-names = "rot_ahb_clk", "rot_axi_clk"; + }; + + smmu_sde_rot_sec: qcom,smmu_sde_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&mmss_smmu 0xe01>; + gdsc-mdss-supply = <&gdsc_bimc_smmu>; + clocks = <&clock_mmss clk_bimc_smmu_ahb_clk>, + <&clock_mmss clk_bimc_smmu_axi_clk>; + clock-names = "rot_ahb_clk", "rot_axi_clk"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vfe.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vfe.txt new file mode 100644 index 0000000000000000000000000000000000000000..aaf13442fcf10b332c9000acd7bea6354d7af271 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vfe.txt @@ -0,0 +1,208 @@ +* Qualcomm Technologies, Inc. MSM VFE + +Required properties for parent node: +- compatible : + - "qcom,vfe" +- #address-cells : Number of address related values in the reg field +- #size-cells : Number of size related values in the reg field +- ranges: How the register offsets for child translate to parent. + +Required properties for child node: +- cell-index: vfe hardware core index +- compatible : + - "qcom,vfe32" + - "qcom,vfe40" + - "qcom,vfe44" + - "qcom,vfe46" + - "qcom,vfe47" + - "qcom,vfe48" +- reg : offset and length of the register set for the device + for the vfe operating in compatible mode. For parent node, add union of + all registers for both vfe. +- reg-names : should specify relevant names to each reg property defined. + Only needed for child node. + - "vfe" - Required. + - "vfe_vbif" - Optional for "vfe32". Required for "vfe40". + - "vfe_fuse" - Optional. +- interrupts : should contain the vfe interrupt. +- interrupt-names : should specify relevant names to each interrupts + property defined. + - "vfe" - Required. +- vdd-supply: phandle to GDSC regulator controlling VFE core. +- qos-entries: number of QoS registers to program +- qos-regs: relative address offsets of QoS registers +- qos-settings: QoS values to be written to QoS registers +- vbif-entries - number of VBIF registers to program (optional) +- vbif-regs: relative address offsets of VBIF registers (optional) +- vbif-settings: VBIF values to be written to VBIF registers (optional) +- ds-entries: number danger/safe registers to program (optional) +- ds-regs: relative address offsets of danger/safe registers (optional) +- ds-settings: danger/safe values to be written to registers (optional) + NOTE: For all qos*, vbif*, ds* parameters, same SoC can have different + hardware versions with different entries/registers/settings. They can be + specified by adding version to the string e.g. qos-v2-settings. Also + different SoC can have same hardware version and still different QOS, VBIF, + and DS parameters. In this case they are exported if separate SoC version + specific dts files. +- max-svs-clk: svs rate of the VFE clock in Hertz. +- max-nominal-clk: nominal rate of the VFE clock in Hertz. +- max-turbo-clk: turbo/high rate of the VFE clock in Hertz. + +Example: + +vfe0: qcom,vfe0@fda10000 { + cell-index = <0>; + compatible = "qcom,vfe44"; + reg = <0xfda10000 0x1000>, + <0xfda40000 0x200>, + <0x7801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; + interrupts = <0 57 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + qos-entries = <8>; + qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8 + 0x2dc 0x2e0>; + qos-settings = <0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0x0002aaaa>; + qos-v2-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + qos-v3-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + vbif-entries = <17>; + vbif-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xdc 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-settings = <0x1 0x01010101 0x01010101 0x10010110 + 0x10101010 0x10101010 0x10101010 0x00001010 + 0x00001010 0x00000707 0x00000707 0x00000030 + 0x00000fff 0x0fff0fff 0x00000001 0x22222222 + 0x00002222>; + vbif-v2-entries = <16>; + vbif-v2-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-v2-settings = <0x1 0x10101010 0x10101010 0x10101010 + 0x10101010 0x10101010 0x10101010 0x00000010 + 0x00000010 0x00000707 0x00000010 0x00000fff + 0x0fff0fff 0x00000003 0x22222222 0x00002222>; + ds-entries = <17>; + ds-regs = <0x988 0x98c 0x990 0x994 0x998 + 0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0 + 0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>; + ds-settings = <0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x00000103>; + max-clk-svs = <300000000>; + max-clk-nominal = <465000000>; + max-clk-turbo = <600000000>; +}; + +vfe1: qcom,vfe1@fda14000 { + cell-index = <1>; + compatible = "qcom,vfe44"; + reg = <0xfda14000 0x1000>, + <0xfda40000 0x200>, + <0x7801a4 0x8>; + reg-names = "vfe", "vfe_vbif", "vfe_fuse"; + interrupts = <0 58 0>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe>; + qos-entries = <8>; + qos-regs = <0x2c4 0x2c8 0x2cc 0x2d0 0x2d4 0x2d8 + 0x2dc 0x2e0>; + qos-settings = <0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa + 0xaaaaaaaa 0x0002aaaa>; + qos-v2-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + qos-v3-settings = <0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0xaaa9aaa9 0xaaa9aaa9 + 0xaaa9aaa9 0x0001aaa9>; + vbif-entries = <17>; + vbif-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xdc 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-settings = <0x1 0x01010101 0x01010101 0x10010110 + 0x10101010 0x10101010 0x10101010 0x00001010 + 0x00001010 0x00000707 0x00000707 0x00000030 + 0x00000fff 0x0fff0fff 0x00000001 0x22222222 + 0x00002222>; + vbif-v2-entries = <16>; + vbif-v2-regs = <0x4 0xb0 0xb4 0xb8 0xc0 0xc4 0xc8 0xd0 + 0xd4 0xd8 0xf0 0x178 0x17c 0x124 0x160 + 0x164>; + vbif-v2-settings = <0x1 0x10101010 0x10101010 0x10101010 + 0x10101010 0x10101010 0x10101010 0x00000010 + 0x00000010 0x00000707 0x00000010 0x00000fff + 0x0fff0fff 0x00000003 0x22222222 0x00002222>; + ds-entries = <17>; + ds-regs = <0x988 0x98c 0x990 0x994 0x998 + 0x99c 0x9a0 0x9a4 0x9a8 0x9ac 0x9b0 + 0x9b4 0x9b8 0x9bc 0x9c0 0x9c4 0x9c8>; + ds-settings = <0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x44441111 0x44441111 + 0x44441111 0x00000103>; + max-clk-svs = <300000000>; + max-clk-nominal = <465000000>; + max-clk-turbo = <600000000>; +}; + +qcom,vfe { + compatible = "qcom,vfe"; + num_child = <2>; +}; + +In version specific file one needs to move only entries that differ between +SoC versions with same VFE HW version: + + &vfe0 { + qos-entries = <8>; + qos-regs = <0x378 0x37C 0x380 0x384 0x388 0x38C + 0x390 0x394>; + qos-settings = <0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0xAAA9AAA9 + 0x0001AAA9>; + vbif-entries = <1>; + vbif-regs = <0x124>; + vbif-settings = <0x3>; + ds-entries = <17>; + ds-regs = <0xBD8 0xBDC 0xBE0 0xBE4 0xBE8 + 0xBEC 0xBF0 0xBF4 0xBF8 0xBFC 0xC00 + 0xC04 0xC08 0xC0C 0xC10 0xC14 0xC18>; + ds-settings = <0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x44441111 + 0x00000103>; + max-clk-svs = <300000000>; + max-clk-nominal = <465000000>; + max-clk-turbo = <600000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc-bus.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d4056fa91c1b5edc1011a470a30800f6c0907c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc-bus.txt @@ -0,0 +1,49 @@ +* Qualcomm Technologies Inc MSM VIDC BUS + +Required properties: +- compatible : "qcom,msm-vidc,governor,table" +- name : name of the governor. +- qcom,bus-table : node containing individual domain nodes, each with: + - qcom,codec-mask: a bitmap of supported codec types, every two bits + represents a codec type. + - qcom,load-busfreq-tbl: load (in macroblocks/sec) and the corresponding + bus frequency (in KBps) table. + +Optional properties: +- qcom,low-power-mode: a boolean which indicates whether bus profile need + to be used when client enables low-power mode. +- qcom,ubwc-mode: a boolean which indicates whether the bus profile need + to be used when client enables UBWC mode. + +Example: + +venus-bus-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "qcom,venus-gov"; + qcom,bus-freq-table { + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,ubwc-mode; + qcom,load-busfreq-tbl = + <489600 1205248>, /* 1080p60D */ + <244800 618496>, /* 1080p30D */ + <216000 618496>, /* 720p60D */ + <108000 314368>, /* 720p30D */ + <72000 233472>, /* VGA60D */ + <36000 118784>, /* VGA30D */ + <0 0>; + }; + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,low-power-mode; + qcom,load-busfreq-tbl = + <244800 787456>, /* 1080p30E */ + <216000 350208>, /* 720p60E */ + <108000 350208>, /* 720p30E */ + <72000 350208>, /* VGA60E */ + <36000 136806>, /* VGA30E */ + <0 0>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc-vmem.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc-vmem.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b5323ee786a8cf5fa0c345ee8c30a9e4217d556 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc-vmem.txt @@ -0,0 +1,42 @@ +* Qualcomm Technologies Inc MSM VIDC VMEM + +Required properties: +- compatible : "qcom,msm-vmem" +- interrupts : Contains the interrupt that maps to the VMEM module +- reg : A set of 2 start address and size pairs that describe the hardware +register address space and mappable memory address space. +- reg-names : Strings that describe the pairs in "reg". The register address +space should be called "reg-base" and the memory space should be called "mem-base". +- clocks : A set of clocks that correspond to the AHB and MAXI clocks that the +hardware uses. +- clock-names : A string that describes the "clocks" property. The AHB clock +should be named "ahb" and the MAXI clock should be named "maxi". +- qcom,bank-size : The size of each memory bank, in bytes. +- vdd-supply: phandle to a regulator that is considered to be the footswitch for vmem. +- qcom,msm-bus,(name|num-cases,num-paths,vectors-KBps) - Bus to be voted for prior to + issuing any IO transactions to vmem. Refer to Documentation/devicetree/bindings/arm/\ + msm/msm_bus_adhoc.txt for further details. + +Example: + +qcom,vmem@880000 { + compatible = "qcom,msm-vmem"; + interrupts = <0 429 0>; + reg = <0x880000 0x800>, + <0x6800000 0x100000>; + reg-names = "reg-base", "mem-base"; + + vdd-supply = <&gdsc_mmagic_video>; + clocks = <&clock_mmss clk_vmem_ahb_clk>, + <&clock_mmss clk_vmem_maxi_clk>; + clock-names = "ahb", "maxi"; + + qcom,bank-size = <131072>; + + qcom,msm-bus,name = "vmem"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc.txt b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc.txt new file mode 100644 index 0000000000000000000000000000000000000000..264725fb1f2e6d28a30e84f8dc0dcb17e79af004 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/video/msm-vidc.txt @@ -0,0 +1,190 @@ +* Qualcomm Technologies, Inc. MSM VIDC + +[Root level node] +Venus +===== +Required properties: +- compatible : one of: + - "qcom,msm-vidc" + - "qcom,kona-vidc" : Invokes driver specific data for KONA. + - "qcom,lito-vidc" : Invokes driver specific data for LITO. + - "qcom,bengal-vidc" : Invokes driver specific data for BENGAL. + - "qcom,lagoon-vidc" : Invokes driver specific data for LAGOON. + - "qcom,scuba-vidc" : Invokes driver specific data for SCUBA. +Optional properties: +- reg : offset and length of the register set for the device. +- sku-index : sku version of the hardware. +- interrupts : should contain the vidc interrupt. +- qcom,reg-presets : list of offset-value pairs for registers to be written. + The offsets are from the base offset specified in 'reg'. This is mainly + used for QoS, VBIF, etc. presets for video. +- qcom,qdss-presets : list of physical address and memory allocation size pairs. + when fw_debug_mode is set as HFI_DEBUG_MODE_QDSS, all firmware messages will be + written to QDSS memory. +- *-supply: A phandle pointing to the appropriate regulator. Number of + regulators vary across targets. +- clock-names: an array of clocks that the driver is supposed to be + manipulating. The clocks names here correspond to the clock names used in + clk_get(). +- qcom,clock-configs = an array of bitmaps of clocks' configurations. The index + of the bitmap corresponds to the clock at the same index in qcom,clock-names. + The bitmaps describes the actions that the device needs to take regarding the + clock (i.e. scale it based on load). + + The bitmap is defined as: + scalable = 0x1 (if the driver should vary the clock's frequency based on load) +- qcom,allowed-clock-rates = an array of supported clock rates by the chipset. +- qcom,clock-freq-tbl = node containing individual domain nodes, each with: + - qcom,codec-mask: a bitmap of supported codec types, every two bits + represents a codec type. + supports mvc encoder = 0x00000001 + supports mvc decoder = 0x00000003 + supports h264 encoder = 0x00000004 + supports h264 decoder = 0x0000000c + supports mpeg1 encoder = 0x00000040 + supports mpeg1 decoder = 0x000000c0 + supports mpeg2 encoder = 0x00000100 + supports mpeg2 decoder = 0x00000300 + supports vp6 encoder = 0x00100000 + supports vp6 decoder = 0x00300000 + supports vp7 encoder = 0x00400000 + supports vp7 decoder = 0x00c00000 + supports vp8 encoder = 0x01000000 + supports vp8 decoder = 0x03000000 + supports hevc encoder = 0x04000000 + supports hevc decoder = 0x0c000000 + - qcom,cycles-per-mb: number of cycles required to process each macro + block. + - qcom,low-power-cycles-per-mb: number of cycles required to process each + macro block in low power mode. + the required frequency to get the final frequency, the factor is + represented in Q16 format. +- qcom,vidc-iommu-domains = node containing individual domain nodes, each with: + - a unique domain name for the domain node (e.g vidc,domain-ns) + - qcom,vidc-domain-phandle: phandle for the domain as defined in + -iommu-domains.dtsi (e.g msm8974-v1-iommu-domains.dtsi) + - qcom,vidc-buffer-types: bitmap of buffer types that can be mapped into each + IOMMU domain. + - Buffer types are defined as the following: + input = 0x1 + output = 0x2 + output2 = 0x4 + extradata input = 0x8 + extradata output = 0x10 + extradata output2 = 0x20 + internal scratch = 0x40 + internal scratch1 = 0x80 + internal scratch2 = 0x100 + internal persist = 0x200 + internal persist1 = 0x400 + internal cmd queue = 0x800 +- cache-slice-names = An array of supported cache slice names by llcc +- cache-slices = An array of supported cache slice ids corresponding + to cache-slice-names by llcc + +[Second level nodes] +Context Banks +============= +Required properties: +- compatible : one of: + - "qcom,msm-vidc,context-bank" +- iommus : A phandle parsed by smmu driver. Number of entries will vary + across targets. + +Optional properties: +- label - string describing iommu domain usage. +- buffer-types : bitmap of buffer types that can be mapped into the current + IOMMU domain. + - Buffer types are defined as the following: + input = 0x1 + output = 0x2 + output2 = 0x4 + extradata input = 0x8 + extradata output = 0x10 + extradata output2 = 0x20 + internal scratch = 0x40 + internal scratch1 = 0x80 + internal scratch2 = 0x100 + internal persist = 0x200 + internal persist1 = 0x400 + internal cmd queue = 0x800 +- virtual-addr-pool : offset and length of virtual address pool. +- qcom,secure-context-bank : bool indicating secure context bank. + +Buses +===== +Required properties: +- compatible : one of: + - "qcom,msm-vidc,bus" +- label : an arbitrary name +- qcom,bus-master : an integer descriptor of the bus master. Refer to arch/arm/\ + boot/dts/include/dt-bindings/msm/msm-bus-ids.h for list of acceptable masters +- qcom,bus-slave : an integer descriptor of the bus slave. Refer to arch/arm/\ + boot/dts/include/dt-bindings/msm/msm-bus-ids.h for list of acceptable slaves + +Optional properties: +- qcom,bus-range-kbps : an array of two items () that indicate the + minimum and maximum acceptable votes for the bus. + In the absence of this property <0 INT_MAX> is used. +- qcom,ubwc-10bit : UBWC 10 bit content has different bus requirements, + this tag will be used to pick the appropriate bus as per the session profile + as shown below in example. +- qcom,mode : Type of BW calculations to use. + "performance" - Use highest valid BW vote. + "venus-ddr", "venus-llcc" - Calculate for DDR, LLCC path. + +Memory Heaps +============ +Required properties: +- compatible : one of: + - "qcom,msm-vidc,mem-adsp" + - "qcom,msm-vidc,mem-cdsp" +- memory-region : phandle to the memory heap/region. + +Example: + + qcom,vidc@fdc00000 { + compatible = "qcom,msm-vidc"; + reg = <0xfdc00000 0xff000>; + interrupts = <0 44 0>; + venus-supply = <&gdsc>; + venus-core0-supply = <&gdsc1>; + venus-core1-supply = <&gdsc2>; + qcom,reg-presets = <0x80004 0x1>, + <0x80178 0x00001FFF>; + qcom,qdss-presets = <0xFC307000 0x1000>, + <0xFC322000 0x1000>; + clock-names = "foo_clk", "bar_clk", "baz_clk"; + qcom,clock-configs = <0x3 0x1 0x0>; + qcom,buffer-type-tz-usage-table = <0x1 0x1>, + <0x1fe 0x2>; + qcom,allowed-clock-rates = <200000000 300000000 400000000>; + + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "venus-cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-ddr"; + qcom,bus-range-kbps = <1000 3388000>; + }; + + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&apps_smmu 0x1300 0x60>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/xilinx/video.txt b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/video.txt new file mode 100644 index 0000000000000000000000000000000000000000..68ac210e688ed0e48918309b037e5c7474eb89f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/video.txt @@ -0,0 +1,35 @@ +DT bindings for Xilinx video IP cores +------------------------------------- + +Xilinx video IP cores process video streams by acting as video sinks and/or +sources. They are connected by links through their input and output ports, +creating a video pipeline. + +Each video IP core is represented by an AMBA bus child node in the device +tree using bindings documented in this directory. Connections between the IP +cores are represented as defined in ../video-interfaces.txt. + +The whole pipeline is represented by an AMBA bus child node in the device +tree using bindings documented in ./xlnx,video.txt. + +Common properties +----------------- + +The following properties are common to all Xilinx video IP cores. + +- xlnx,video-format: This property represents a video format transmitted on an + AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream + Video IP and System Design Guide" [UG934]. How the format relates to the IP + core is described in the IP core bindings documentation. + +- xlnx,video-width: This property qualifies the video format with the sample + width expressed as a number of bits per pixel component. All components must + use the same width. + +- xlnx,cfa-pattern: When the video format is set to Mono/Sensor, this property + describes the sensor's color filter array pattern. Supported values are + "bggr", "gbrg", "grbg", "rggb" and "mono". If not specified, the pattern + defaults to "mono". + + +[UG934] http://www.xilinx.com/support/documentation/ip_documentation/axi_videoip/v1_0/ug934_axi_videoIP.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,v-tc.txt b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,v-tc.txt new file mode 100644 index 0000000000000000000000000000000000000000..2aed3b4a6cf1ac8a73cc81e861b8ec5c1d7fe74d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,v-tc.txt @@ -0,0 +1,33 @@ +Xilinx Video Timing Controller (VTC) +------------------------------------ + +The Video Timing Controller is a general purpose video timing generator and +detector. + +Required properties: + + - compatible: Must be "xlnx,v-tc-6.1". + + - reg: Physical base address and length of the registers set for the device. + + - clocks: Must contain a clock specifier for the VTC core and timing + interfaces clock. + +Optional properties: + + - xlnx,detector: The VTC has a timing detector + - xlnx,generator: The VTC has a timing generator + + At least one of the xlnx,detector and xlnx,generator properties must be + specified. + + +Example: + + vtc: vtc@43c40000 { + compatible = "xlnx,v-tc-6.1"; + reg = <0x43c40000 0x10000>; + + clocks = <&clkc 15>; + xlnx,generator; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,v-tpg.txt b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,v-tpg.txt new file mode 100644 index 0000000000000000000000000000000000000000..439351ab2a7959360473320559f35e2b860c1d59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,v-tpg.txt @@ -0,0 +1,71 @@ +Xilinx Video Test Pattern Generator (TPG) +----------------------------------------- + +Required properties: + +- compatible: Must contain at least one of + + "xlnx,v-tpg-5.0" (TPG version 5.0) + "xlnx,v-tpg-6.0" (TPG version 6.0) + + TPG versions backward-compatible with previous versions should list all + compatible versions in the newer to older order. + +- reg: Physical base address and length of the registers set for the device. + +- clocks: Reference to the video core clock. + +- xlnx,video-format, xlnx,video-width: Video format and width, as defined in + video.txt. + +- port: Video port, using the DT bindings defined in ../video-interfaces.txt. + The TPG has a single output port numbered 0. + +Optional properties: + +- xlnx,vtc: A phandle referencing the Video Timing Controller that generates + video timings for the TPG test patterns. + +- timing-gpios: Specifier for a GPIO that controls the timing mux at the TPG + input. The GPIO active level corresponds to the selection of VTC-generated + video timings. + +The xlnx,vtc and timing-gpios properties are mandatory when the TPG is +synthesized with two ports and forbidden when synthesized with one port. + +Example: + + tpg_0: tpg@40050000 { + compatible = "xlnx,v-tpg-6.0", "xlnx,v-tpg-5.0"; + reg = <0x40050000 0x10000>; + clocks = <&clkc 15>; + + xlnx,vtc = <&vtc_3>; + timing-gpios = <&ps7_gpio_0 55 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + xlnx,video-format = ; + xlnx,video-width = <8>; + + tpg_in: endpoint { + remote-endpoint = <&adv7611_out>; + }; + }; + port@1 { + reg = <1>; + + xlnx,video-format = ; + xlnx,video-width = <8>; + + tpg1_out: endpoint { + remote-endpoint = <&switch_in0>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,video.txt b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,video.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a022702360857d371240d59d0decbfc80861eda --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/xilinx/xlnx,video.txt @@ -0,0 +1,55 @@ +Xilinx Video IP Pipeline (VIPP) +------------------------------- + +General concept +--------------- + +Xilinx video IP pipeline processes video streams through one or more Xilinx +video IP cores. Each video IP core is represented as documented in video.txt +and IP core specific documentation, xlnx,v-*.txt, in this directory. The DT +node of the VIPP represents as a top level node of the pipeline and defines +mappings between DMAs and the video IP cores. + +Required properties: + +- compatible: Must be "xlnx,video". + +- dmas, dma-names: List of one DMA specifier and identifier string (as defined + in Documentation/devicetree/bindings/dma/dma.txt) per port. Each port + requires a DMA channel with the identifier string set to "port" followed by + the port index. + +- ports: Video port, using the DT bindings defined in ../video-interfaces.txt. + +Required port properties: + +- direction: should be either "input" or "output" depending on the direction + of stream. + +Example: + + video_cap { + compatible = "xlnx,video"; + dmas = <&vdma_1 1>, <&vdma_3 1>; + dma-names = "port0", "port1"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + direction = "input"; + vcap0_in0: endpoint { + remote-endpoint = <&scaler0_out>; + }; + }; + port@1 { + reg = <1>; + direction = "input"; + vcap0_in1: endpoint { + remote-endpoint = <&switch_out1>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/media/zx-irdec.txt b/arch/arm64/boot/dts/vendor/bindings/media/zx-irdec.txt new file mode 100644 index 0000000000000000000000000000000000000000..295b9fab593ef36375d4ac37ff1b67eb143ce939 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/media/zx-irdec.txt @@ -0,0 +1,14 @@ +IR Decoder (IRDEC) on ZTE ZX family SoCs + +Required properties: + - compatible: Should be "zte,zx296718-irdec". + - reg: Physical base address and length of IRDEC registers. + - interrupts: Interrupt number of IRDEC. + +Exmaples: + + irdec: ir-decoder@111000 { + compatible = "zte,zx296718-irdec"; + reg = <0x111000 0x1000>; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/arm,pl172.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/arm,pl172.txt new file mode 100644 index 0000000000000000000000000000000000000000..22b77ee02f58340eca67c7566553a391e11d8461 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/arm,pl172.txt @@ -0,0 +1,127 @@ +* Device tree bindings for ARM PL172/PL175/PL176 MultiPort Memory Controller + +Required properties: + +- compatible: Must be "arm,primecell" and exactly one from + "arm,pl172", "arm,pl175" or "arm,pl176". + +- reg: Must contains offset/length value for controller. + +- #address-cells: Must be 2. The partition number has to be encoded in the + first address cell and it may accept values 0..N-1 + (N - total number of partitions). The second cell is the + offset into the partition. + +- #size-cells: Must be set to 1. + +- ranges: Must contain one or more chip select memory regions. + +- clocks: Must contain references to controller clocks. + +- clock-names: Must contain "mpmcclk" and "apb_pclk". + +- clock-ranges: Empty property indicating that child nodes can inherit + named clocks. Required only if clock tree data present + in device tree. + See clock-bindings.txt + +Child chip-select (cs) nodes contain the memory devices nodes connected to +such as NOR (e.g. cfi-flash) and NAND. + +Required child cs node properties: + +- #address-cells: Must be 2. + +- #size-cells: Must be 1. + +- ranges: Empty property indicating that child nodes can inherit + memory layout. + +- clock-ranges: Empty property indicating that child nodes can inherit + named clocks. Required only if clock tree data present + in device tree. + +- mpmc,cs: Chip select number. Indicates to the pl0172 driver + which chipselect is used for accessing the memory. + +- mpmc,memory-width: Width of the chip select memory. Must be equal to + either 8, 16 or 32. + +Optional child cs node config properties: + +- mpmc,async-page-mode: Enable asynchronous page mode. + +- mpmc,cs-active-high: Set chip select polarity to active high. + +- mpmc,byte-lane-low: Set byte lane state to low. + +- mpmc,extended-wait: Enable extended wait. + +- mpmc,buffer-enable: Enable write buffer, option is not supported by + PL175 and PL176 controllers. + +- mpmc,write-protect: Enable write protect. + +Optional child cs node timing properties: + +- mpmc,write-enable-delay: Delay from chip select assertion to write + enable (WE signal) in nano seconds. + +- mpmc,output-enable-delay: Delay from chip select assertion to output + enable (OE signal) in nano seconds. + +- mpmc,write-access-delay: Delay from chip select assertion to write + access in nano seconds. + +- mpmc,read-access-delay: Delay from chip select assertion to read + access in nano seconds. + +- mpmc,page-mode-read-delay: Delay for asynchronous page mode sequential + accesses in nano seconds. + +- mpmc,turn-round-delay: Delay between access to memory banks in nano + seconds. + +If any of the above timing parameters are absent, current parameter value will +be taken from the corresponding HW reg. + +Example for pl172 with nor flash on chip select 0 shown below. + +emc: memory-controller@40005000 { + compatible = "arm,pl172", "arm,primecell"; + reg = <0x40005000 0x1000>; + clocks = <&ccu1 CLK_CPU_EMCDIV>, <&ccu1 CLK_CPU_EMC>; + clock-names = "mpmcclk", "apb_pclk"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x1c000000 0x1000000 + 1 0 0x1d000000 0x1000000 + 2 0 0x1e000000 0x1000000 + 3 0 0x1f000000 0x1000000>; + + cs0 { + #address-cells = <2>; + #size-cells = <1>; + ranges; + + mpmc,cs = <0>; + mpmc,memory-width = <16>; + mpmc,byte-lane-low; + mpmc,write-enable-delay = <0>; + mpmc,output-enable-delay = <0>; + mpmc,read-enable-delay = <70>; + mpmc,page-mode-read-delay = <70>; + + flash@0,0 { + compatible = "sst,sst39vf320", "cfi-flash"; + reg = <0 0 0x400000>; + bank-width = <2>; + #address-cells = <1>; + #size-cells = <1>; + partition@0 { + label = "data"; + reg = <0 0x400000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ath79-ddr-controller.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ath79-ddr-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..c81af75bcd88697a227f1824d74cd555a84d6bc4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ath79-ddr-controller.txt @@ -0,0 +1,35 @@ +Binding for Qualcomm Atheros AR7xxx/AR9xxx DDR controller + +The DDR controller of the AR7xxx and AR9xxx families provides an interface +to flush the FIFO between various devices and the DDR. This is mainly used +by the IRQ controller to flush the FIFO before running the interrupt handler +of such devices. + +Required properties: + +- compatible: has to be "qca,-ddr-controller", + "qca,[ar7100|ar7240]-ddr-controller" as fallback. + On SoC with PCI support "qca,ar7100-ddr-controller" should be used as + fallback, otherwise "qca,ar7240-ddr-controller" should be used. +- reg: Base address and size of the controller's memory area +- #qca,ddr-wb-channel-cells: Specifies the number of cells needed to encode + the write buffer channel index, should be 1. + +Example: + + ddr_ctrl: memory-controller@18000000 { + compatible = "qca,ar9132-ddr-controller", + "qca,ar7240-ddr-controller"; + reg = <0x18000000 0x100>; + + #qca,ddr-wb-channel-cells = <1>; + }; + + ... + + interrupt-controller { + ... + qca,ddr-wb-channel-interrupts = <2>, <3>, <4>, <5>; + qca,ddr-wb-channels = <&ddr_ctrl 3>, <&ddr_ctrl 2>, + <&ddr_ctrl 0>, <&ddr_ctrl 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/atmel,ebi.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/atmel,ebi.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bb5f57e206627408e3ee73d803f22855066be12 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/atmel,ebi.txt @@ -0,0 +1,136 @@ +* Device tree bindings for Atmel EBI + +The External Bus Interface (EBI) controller is a bus where you can connect +asynchronous (NAND, NOR, SRAM, ....) and synchronous memories (SDR/DDR SDRAMs). +The EBI provides a glue-less interface to asynchronous memories through the SMC +(Static Memory Controller). + +Required properties: + +- compatible: "atmel,at91sam9260-ebi" + "atmel,at91sam9261-ebi" + "atmel,at91sam9263-ebi0" + "atmel,at91sam9263-ebi1" + "atmel,at91sam9rl-ebi" + "atmel,at91sam9g45-ebi" + "atmel,at91sam9x5-ebi" + "atmel,sama5d3-ebi" + +- reg: Contains offset/length value for EBI memory mapping. + This property might contain several entries if the EBI + memory range is not contiguous + +- #address-cells: Must be 2. + The first cell encodes the CS. + The second cell encode the offset into the CS memory + range. + +- #size-cells: Must be set to 1. + +- ranges: Encodes CS to memory region association. + +- clocks: Clock feeding the EBI controller. + See clock-bindings.txt + +Children device nodes are representing device connected to the EBI bus. + +Required device node properties: + +- reg: Contains the chip-select id, the offset and the length + of the memory region requested by the device. + +EBI bus configuration will be defined directly in the device subnode. + +Optional EBI/SMC properties: + +- atmel,smc-bus-width: width of the asynchronous device's data bus + 8, 16 or 32. + Default to 8 when undefined. + +- atmel,smc-byte-access-type "write" or "select" (see Atmel datasheet). + Default to "select" when undefined. + +- atmel,smc-read-mode "nrd" or "ncs". + Default to "ncs" when undefined. + +- atmel,smc-write-mode "nwe" or "ncs". + Default to "ncs" when undefined. + +- atmel,smc-exnw-mode "disabled", "frozen" or "ready". + Default to "disabled" when undefined. + +- atmel,smc-page-mode enable page mode if present. The provided value + defines the page size (supported values: 4, 8, + 16 and 32). + +- atmel,smc-tdf-mode: "normal" or "optimized". When set to + "optimized" the data float time is optimized + depending on the next device being accessed + (next device setup time is subtracted to the + current device data float time). + Default to "normal" when undefined. + +If at least one atmel,smc- property is defined the following SMC timing +properties become mandatory. In the other hand, if none of the atmel,smc- +properties are specified, we assume that the EBI bus configuration will be +handled by the sub-device driver, and none of those properties should be +defined. + +All the timings are expressed in nanoseconds (see Atmel datasheet for a full +description). + +- atmel,smc-ncs-rd-setup-ns +- atmel,smc-nrd-setup-ns +- atmel,smc-ncs-wr-setup-ns +- atmel,smc-nwe-setup-ns +- atmel,smc-ncs-rd-pulse-ns +- atmel,smc-nrd-pulse-ns +- atmel,smc-ncs-wr-pulse-ns +- atmel,smc-nwe-pulse-ns +- atmel,smc-nwe-cycle-ns +- atmel,smc-nrd-cycle-ns +- atmel,smc-tdf-ns + +Example: + + ebi: ebi@10000000 { + compatible = "atmel,sama5d3-ebi"; + #address-cells = <2>; + #size-cells = <1>; + atmel,smc = <&hsmc>; + atmel,matrix = <&matrix>; + reg = <0x10000000 0x10000000 + 0x40000000 0x30000000>; + ranges = <0x0 0x0 0x10000000 0x10000000 + 0x1 0x0 0x40000000 0x10000000 + 0x2 0x0 0x50000000 0x10000000 + 0x3 0x0 0x60000000 0x10000000>; + clocks = <&mck>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ebi_addr>; + + nor: flash@0,0 { + compatible = "cfi-flash"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x0 0x0 0x1000000>; + bank-width = <2>; + + atmel,smc-read-mode = "nrd"; + atmel,smc-write-mode = "nwe"; + atmel,smc-bus-width = <16>; + atmel,smc-ncs-rd-setup-ns = <0>; + atmel,smc-ncs-wr-setup-ns = <0>; + atmel,smc-nwe-setup-ns = <8>; + atmel,smc-nrd-setup-ns = <16>; + atmel,smc-ncs-rd-pulse-ns = <84>; + atmel,smc-ncs-wr-pulse-ns = <84>; + atmel,smc-nrd-pulse-ns = <76>; + atmel,smc-nwe-pulse-ns = <76>; + atmel,smc-nrd-cycle-ns = <107>; + atmel,smc-nwe-cycle-ns = <84>; + atmel,smc-tdf-ns = <16>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/brcm,dpfe-cpu.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/brcm,dpfe-cpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..82d923ef413f92a6bc8c0887c91cfeb85b12dc02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/brcm,dpfe-cpu.txt @@ -0,0 +1,27 @@ +DDR PHY Front End (DPFE) for Broadcom STB +========================================= + +DPFE and the DPFE firmware provide an interface for the host CPU to +communicate with the DCPU, which resides inside the DDR PHY. + +There are three memory regions for interacting with the DCPU. These are +specified in a single reg property. + +Required properties: + - compatible: must be "brcm,bcm7271-dpfe-cpu", "brcm,bcm7268-dpfe-cpu" + or "brcm,dpfe-cpu" + - reg: must reference three register ranges + - start address and length of the DCPU register space + - start address and length of the DCPU data memory space + - start address and length of the DCPU instruction memory space + - reg-names: must contain "dpfe-cpu", "dpfe-dmem", and "dpfe-imem"; + they must be in the same order as the register declarations + +Example: + dpfe_cpu0: dpfe-cpu@f1132000 { + compatible = "brcm,bcm7271-dpfe-cpu", "brcm,dpfe-cpu"; + reg = <0xf1132000 0x180 + 0xf1134000 0x1000 + 0xf1138000 0x4000>; + reg-names = "dpfe-cpu", "dpfe-dmem", "dpfe-imem"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/calxeda-ddr-ctrlr.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/calxeda-ddr-ctrlr.txt new file mode 100644 index 0000000000000000000000000000000000000000..049675944b78035b5829ed94d53f5c0d2d45fc5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/calxeda-ddr-ctrlr.txt @@ -0,0 +1,16 @@ +Calxeda DDR memory controller + +Properties: +- compatible : Should be: + - "calxeda,hb-ddr-ctrl" for ECX-1000 + - "calxeda,ecx-2000-ddr-ctrl" for ECX-2000 +- reg : Address and size for DDR controller registers. +- interrupts : Interrupt for DDR controller. + +Example: + + memory-controller@fff00000 { + compatible = "calxeda,hb-ddr-ctrl"; + reg = <0xfff00000 0x1000>; + interrupts = <0 91 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/exynos-srom.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/exynos-srom.txt new file mode 100644 index 0000000000000000000000000000000000000000..f633b5d0f8ca489808a85da3823bbdc6198fbdeb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/exynos-srom.txt @@ -0,0 +1,79 @@ +SAMSUNG Exynos SoCs SROM Controller driver. + +Required properties: +- compatible : Should contain "samsung,exynos4210-srom". + +- reg: offset and length of the register set + +Optional properties: +The SROM controller can be used to attach external peripherals. In this case +extra properties, describing the bus behind it, should be specified as below: + +- #address-cells: Must be set to 2 to allow device address translation. + Address is specified as (bank#, offset). + +- #size-cells: Must be set to 1 to allow device size passing + +- ranges: Must be set up to reflect the memory layout with four integer values + per bank: + 0 + +Sub-nodes: +The actual device nodes should be added as subnodes to the SROMc node. These +subnodes, in addition to regular device specification, should contain the following +properties, describing configuration of the relevant SROM bank: + +Required properties: +- reg: bank number, base address (relative to start of the bank) and size of + the memory mapped for the device. Note that base address will be + typically 0 as this is the start of the bank. + +- samsung,srom-timing : array of 6 integers, specifying bank timings in the + following order: Tacp, Tcah, Tcoh, Tacc, Tcos, Tacs. + Each value is specified in cycles and has the following + meaning and valid range: + Tacp : Page mode access cycle at Page mode (0 - 15) + Tcah : Address holding time after CSn (0 - 15) + Tcoh : Chip selection hold on OEn (0 - 15) + Tacc : Access cycle (0 - 31, the actual time is N + 1) + Tcos : Chip selection set-up before OEn (0 - 15) + Tacs : Address set-up before CSn (0 - 15) + +Optional properties: +- reg-io-width : data width in bytes (1 or 2). If omitted, default of 1 is used. + +- samsung,srom-page-mode : if page mode is set, 4 data page mode will be configured, + else normal (1 data) page mode will be set. + +Example: basic definition, no banks are configured + memory-controller@12570000 { + compatible = "samsung,exynos4210-srom"; + reg = <0x12570000 0x14>; + }; + +Example: SROMc with SMSC911x ethernet chip on bank 3 + memory-controller@12570000 { + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x04000000 0x20000 // Bank0 + 1 0 0x05000000 0x20000 // Bank1 + 2 0 0x06000000 0x20000 // Bank2 + 3 0 0x07000000 0x20000>; // Bank3 + + compatible = "samsung,exynos4210-srom"; + reg = <0x12570000 0x14>; + + ethernet@3,0 { + compatible = "smsc,lan9115"; + reg = <3 0 0x10000>; // Bank 3, offset = 0 + phy-mode = "mii"; + interrupt-parent = <&gpx0>; + interrupts = <5 8>; + reg-io-width = <2>; + smsc,irq-push-pull; + smsc,force-internal-phy; + + samsung,srom-page-mode; + samsung,srom-timing = <9 12 1 9 1 1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/fsl/ddr.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/fsl/ddr.txt new file mode 100644 index 0000000000000000000000000000000000000000..dde6d837083af19c286ea295eee00b8661078893 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/fsl/ddr.txt @@ -0,0 +1,29 @@ +Freescale DDR memory controller + +Properties: + +- compatible : Should include "fsl,chip-memory-controller" where + chip is the processor (bsc9132, mpc8572 etc.), or + "fsl,qoriq-memory-controller". +- reg : Address and size of DDR controller registers +- interrupts : Error interrupt of DDR controller +- little-endian : Specifies little-endian access to registers + If omitted, big-endian will be used. + +Example 1: + + memory-controller@2000 { + compatible = "fsl,bsc9132-memory-controller"; + reg = <0x2000 0x1000>; + interrupts = <16 2 1 8>; + }; + + +Example 2: + + ddr1: memory-controller@8000 { + compatible = "fsl,qoriq-memory-controller-v4.7", + "fsl,qoriq-memory-controller"; + reg = <0x8000 0x1000>; + interrupts = <16 2 1 23>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/fsl/ifc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/fsl/ifc.txt new file mode 100644 index 0000000000000000000000000000000000000000..89427b018ba75053938f75e13f74a0591a8c3044 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/fsl/ifc.txt @@ -0,0 +1,82 @@ +Integrated Flash Controller + +Properties: +- name : Should be ifc +- compatible : should contain "fsl,ifc". The version of the integrated + flash controller can be found in the IFC_REV register at + offset zero. + +- #address-cells : Should be either two or three. The first cell is the + chipselect number, and the remaining cells are the + offset into the chipselect. +- #size-cells : Either one or two, depending on how large each chipselect + can be. +- reg : Offset and length of the register set for the device +- interrupts: IFC may have one or two interrupts. If two interrupt + specifiers are present, the first is the "common" + interrupt (CM_EVTER_STAT), and the second is the NAND + interrupt (NAND_EVTER_STAT). If there is only one, + that interrupt reports both types of event. + +- little-endian : If this property is absent, the big-endian mode will + be in use as default for registers. + +- ranges : Each range corresponds to a single chipselect, and covers + the entire access window as configured. + +Child device nodes describe the devices connected to IFC such as NOR (e.g. +cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices +like FPGAs, CPLDs, etc. + +Example: + + ifc@ffe1e000 { + compatible = "fsl,ifc", "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0x0 0xffe1e000 0 0x2000>; + interrupts = <16 2 19 2>; + little-endian; + + /* NOR, NAND Flashes and CPLD on board */ + ranges = <0x0 0x0 0x0 0xee000000 0x02000000 + 0x1 0x0 0x0 0xffa00000 0x00010000 + 0x3 0x0 0x0 0xffb00000 0x00020000>; + + flash@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x2000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + /* 32MB for user data */ + reg = <0x0 0x02000000>; + label = "NOR Data"; + }; + }; + + flash@1,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,ifc-nand"; + reg = <0x1 0x0 0x10000>; + + partition@0 { + /* This location must not be altered */ + /* 1MB for u-boot Bootloader Image */ + reg = <0x0 0x00100000>; + label = "NAND U-Boot Image"; + read-only; + }; + }; + + cpld@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p1010rdb-cpld"; + reg = <0x3 0x0 0x000001f>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ingenic,jz4780-nemc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ingenic,jz4780-nemc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f936b5589b1953030adc2563c88555398a49e839 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ingenic,jz4780-nemc.txt @@ -0,0 +1,75 @@ +* Ingenic JZ4780 NAND/external memory controller (NEMC) + +This file documents the device tree bindings for the NEMC external memory +controller in Ingenic JZ4780 + +Required properties: +- compatible: Should be set to one of: + "ingenic,jz4780-nemc" (JZ4780) +- reg: Should specify the NEMC controller registers location and length. +- clocks: Clock for the NEMC controller. +- #address-cells: Must be set to 2. +- #size-cells: Must be set to 1. +- ranges: A set of ranges for each bank describing the physical memory layout. + Each should specify the following 4 integer values: + + 0 + +Each child of the NEMC node describes a device connected to the NEMC. + +Required child node properties: +- reg: Should contain at least one register specifier, given in the following + format: + + + + Multiple registers can be specified across multiple banks. This is needed, + for example, for packaged NAND devices with multiple dies. Such devices + should be grouped into a single node. + +Optional child node properties: +- ingenic,nemc-bus-width: Specifies the bus width in bits. Defaults to 8 bits. +- ingenic,nemc-tAS: Address setup time in nanoseconds. +- ingenic,nemc-tAH: Address hold time in nanoseconds. +- ingenic,nemc-tBP: Burst pitch time in nanoseconds. +- ingenic,nemc-tAW: Access wait time in nanoseconds. +- ingenic,nemc-tSTRV: Static memory recovery time in nanoseconds. + +If a child node references multiple banks in its "reg" property, the same value +for all optional parameters will be configured for all banks. If any optional +parameters are omitted, they will be left unchanged from whatever they are +configured to when the NEMC device is probed (which may be the reset value as +given in the hardware reference manual, or a value configured by the boot +loader). + +Example (NEMC node with a NAND child device attached at CS1): + +nemc: nemc@13410000 { + compatible = "ingenic,jz4780-nemc"; + reg = <0x13410000 0x10000>; + + #address-cells = <2>; + #size-cells = <1>; + + ranges = <1 0 0x1b000000 0x1000000 + 2 0 0x1a000000 0x1000000 + 3 0 0x19000000 0x1000000 + 4 0 0x18000000 0x1000000 + 5 0 0x17000000 0x1000000 + 6 0 0x16000000 0x1000000>; + + clocks = <&cgu JZ4780_CLK_NEMC>; + + nand: nand@1 { + compatible = "ingenic,jz4780-nand"; + reg = <1 0 0x1000000>; + + ingenic,nemc-tAS = <10>; + ingenic,nemc-tAH = <5>; + ingenic,nemc-tBP = <10>; + ingenic,nemc-tAW = <15>; + ingenic,nemc-tSTRV = <100>; + + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mediatek,smi-common.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mediatek,smi-common.txt new file mode 100644 index 0000000000000000000000000000000000000000..615abdd0eb0de6db2a35ee61b727f71d31c5cee2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mediatek,smi-common.txt @@ -0,0 +1,41 @@ +SMI (Smart Multimedia Interface) Common + +The hardware block diagram please check bindings/iommu/mediatek,iommu.txt + +Mediatek SMI have two generations of HW architecture, mt2712 and mt8173 use +the second generation of SMI HW while mt2701 uses the first generation HW of +SMI. + +There's slight differences between the two SMI, for generation 2, the +register which control the iommu port is at each larb's register base. But +for generation 1, the register is at smi ao base(smi always on register +base). Besides that, the smi async clock should be prepared and enabled for +SMI generation 1 to transform the smi clock into emi clock domain, but that is +not needed for SMI generation 2. + +Required properties: +- compatible : must be one of : + "mediatek,mt2701-smi-common" + "mediatek,mt2712-smi-common" + "mediatek,mt8173-smi-common" +- reg : the register and size of the SMI block. +- power-domains : a phandle to the power domain of this local arbiter. +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : must contain 3 entries for generation 1 smi HW and 2 entries + for generation 2 smi HW as follows: + - "apb" : Advanced Peripheral Bus clock, It's the clock for setting + the register. + - "smi" : It's the clock for transfer data and command. + They may be the same if both source clocks are the same. + - "async" : asynchronous clock, it help transform the smi clock into the emi + clock domain, this clock is only needed by generation 1 smi HW. + +Example: + smi_common: smi@14022000 { + compatible = "mediatek,mt8173-smi-common"; + reg = <0 0x14022000 0 0x1000>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_MM>; + clocks = <&mmsys CLK_MM_SMI_COMMON>, + <&mmsys CLK_MM_SMI_COMMON>; + clock-names = "apb", "smi"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mediatek,smi-larb.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mediatek,smi-larb.txt new file mode 100644 index 0000000000000000000000000000000000000000..083155cdc2a0e787df4510b919bf8d97ec1cce15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mediatek,smi-larb.txt @@ -0,0 +1,43 @@ +SMI (Smart Multimedia Interface) Local Arbiter + +The hardware block diagram please check bindings/iommu/mediatek,iommu.txt + +Required properties: +- compatible : must be one of : + "mediatek,mt2701-smi-larb" + "mediatek,mt2712-smi-larb" + "mediatek,mt8173-smi-larb" +- reg : the register and size of this local arbiter. +- mediatek,smi : a phandle to the smi_common node. +- power-domains : a phandle to the power domain of this local arbiter. +- clocks : Must contain an entry for each entry in clock-names. +- clock-names: must contain 2 entries, as follows: + - "apb" : Advanced Peripheral Bus clock, It's the clock for setting + the register. + - "smi" : It's the clock for transfer data and command. + +Required property for mt2701 and mt2712: +- mediatek,larb-id :the hardware id of this larb. + +Example: + larb1: larb@16010000 { + compatible = "mediatek,mt8173-smi-larb"; + reg = <0 0x16010000 0 0x1000>; + mediatek,smi = <&smi_common>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_VDEC>; + clocks = <&vdecsys CLK_VDEC_CKEN>, + <&vdecsys CLK_VDEC_LARB_CKEN>; + clock-names = "apb", "smi"; + }; + +Example for mt2701: + larb0: larb@14010000 { + compatible = "mediatek,mt2701-smi-larb"; + reg = <0 0x14010000 0 0x1000>; + mediatek,smi = <&smi_common>; + mediatek,larb-id = <0>; + clocks = <&mmsys CLK_MM_SMI_LARB0>, + <&mmsys CLK_MM_SMI_LARB0>; + clock-names = "apb", "smi"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mvebu-devbus.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mvebu-devbus.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b9388cc1ccc6d8884feaa115233ea099ff6907c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mvebu-devbus.txt @@ -0,0 +1,177 @@ +Device tree bindings for MVEBU Device Bus controllers + +The Device Bus controller available in some Marvell's SoC allows to control +different types of standard memory and I/O devices such as NOR, NAND, and FPGA. +The actual devices are instantiated from the child nodes of a Device Bus node. + +Required properties: + + - compatible: Armada 370/XP SoC are supported using the + "marvell,mvebu-devbus" compatible string. + + Orion5x SoC are supported using the + "marvell,orion-devbus" compatible string. + + - reg: A resource specifier for the register space. + This is the base address of a chip select within + the controller's register space. + (see the example below) + + - #address-cells: Must be set to 1 + - #size-cells: Must be set to 1 + - ranges: Must be set up to reflect the memory layout with four + integer values for each chip-select line in use: + 0 + +Optional properties: + + - devbus,keep-config This property can optionally be used to keep + using the timing parameters set by the + bootloader. It makes all the timing properties + described below unused. + +Timing properties for child nodes: + +Read parameters: + + - devbus,turn-off-ps: Defines the time during which the controller does not + drive the AD bus after the completion of a device read. + This prevents contentions on the Device Bus after a read + cycle from a slow device. + Mandatory, except if devbus,keep-config is used. + + - devbus,bus-width: Defines the bus width, in bits (e.g. <16>). + Mandatory, except if devbus,keep-config is used. + + - devbus,badr-skew-ps: Defines the time delay from from A[2:0] toggle, + to read data sample. This parameter is useful for + synchronous pipelined devices, where the address + precedes the read data by one or two cycles. + Mandatory, except if devbus,keep-config is used. + + - devbus,acc-first-ps: Defines the time delay from the negation of + ALE[0] to the cycle that the first read data is sampled + by the controller. + Mandatory, except if devbus,keep-config is used. + + - devbus,acc-next-ps: Defines the time delay between the cycle that + samples data N and the cycle that samples data N+1 + (in burst accesses). + Mandatory, except if devbus,keep-config is used. + + - devbus,rd-setup-ps: Defines the time delay between DEV_CSn assertion to + DEV_OEn assertion. If set to 0 (default), + DEV_OEn and DEV_CSn are asserted at the same cycle. + This parameter has no affect on parameter + (no affect on first data sample). Set + to a value smaller than . + Mandatory for "marvell,mvebu-devbus" compatible string, + except if devbus,keep-config is used. + + - devbus,rd-hold-ps: Defines the time between the last data sample to the + de-assertion of DEV_CSn. If set to 0 (default), + DEV_OEn and DEV_CSn are de-asserted at the same cycle + (the cycle of the last data sample). + This parameter has no affect on DEV_OEn de-assertion. + DEV_OEn is always de-asserted the next cycle after + last data sampled. Also this parameter has no + affect on parameter. + Set to a value smaller than . + Mandatory for "marvell,mvebu-devbus" compatible string, + except if devbus,keep-config is used. + +Write parameters: + + - devbus,ale-wr-ps: Defines the time delay from the ALE[0] negation cycle + to the DEV_WEn assertion. + Mandatory. + + - devbus,wr-low-ps: Defines the time during which DEV_WEn is active. + A[2:0] and Data are kept valid as long as DEV_WEn + is active. This parameter defines the setup time of + address and data to DEV_WEn rise. + Mandatory. + + - devbus,wr-high-ps: Defines the time during which DEV_WEn is kept + inactive (high) between data beats of a burst write. + DEV_A[2:0] and Data are kept valid (do not toggle) for + - ps. + This parameter defines the hold time of address and + data after DEV_WEn rise. + Mandatory. + + - devbus,sync-enable: Synchronous device enable. + 1: True + 0: False + Mandatory for "marvell,mvebu-devbus" compatible string, + except if devbus,keep-config is used. + +An example for an Armada XP GP board, with a 16 MiB NOR device as child +is showed below. Note that the Device Bus driver is in charge of allocating +the mbus address decoding window for each of its child devices. +The window is created using the chip select specified in the child +device node together with the base address and size specified in the ranges +property. For instance, in the example below the allocated decoding window +will start at base address 0xf0000000, with a size 0x1000000 (16 MiB) +for chip select 0 (a.k.a DEV_BOOTCS). + +This address window handling is done in this mvebu-devbus only as a temporary +solution. It will be removed when the support for mbus device tree binding is +added. + +The reg property implicitly specifies the chip select as this: + + 0x10400: DEV_BOOTCS + 0x10408: DEV_CS0 + 0x10410: DEV_CS1 + 0x10418: DEV_CS2 + 0x10420: DEV_CS3 + +Example: + + devbus-bootcs@d0010400 { + ranges = <0 0xf0000000 0x1000000>; /* @addr 0xf0000000, size 0x1000000 */ + #address-cells = <1>; + #size-cells = <1>; + + /* Device Bus parameters are required */ + + /* Read parameters */ + devbus,bus-width = <8>; + devbus,turn-off-ps = <60000>; + devbus,badr-skew-ps = <0>; + devbus,acc-first-ps = <124000>; + devbus,acc-next-ps = <248000>; + devbus,rd-setup-ps = <0>; + devbus,rd-hold-ps = <0>; + + /* Write parameters */ + devbus,sync-enable = <0>; + devbus,wr-high-ps = <60000>; + devbus,wr-low-ps = <60000>; + devbus,ale-wr-ps = <60000>; + + flash@0 { + compatible = "cfi-flash"; + + /* 16 MiB */ + reg = <0 0x1000000>; + bank-width = <2>; + #address-cells = <1>; + #size-cells = <1>; + + /* + * We split the 16 MiB in two partitions, + * just as an example. + */ + partition@0 { + label = "First"; + reg = <0 0x800000>; + }; + + partition@800000 { + label = "Second"; + reg = <0x800000 0x800000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mvebu-sdram-controller.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mvebu-sdram-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..89657d1d4cd495164607761b0fd6c78f6b1e665d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/mvebu-sdram-controller.txt @@ -0,0 +1,21 @@ +Device Tree bindings for MVEBU SDRAM controllers + +The Marvell EBU SoCs all have a SDRAM controller. The SDRAM controller +differs from one SoC variant to another, but they also share a number +of commonalities. + +For now, this Device Tree binding documentation only documents the +Armada XP SDRAM controller. + +Required properties: + + - compatible: for Armada XP, "marvell,armada-xp-sdram-controller" + - reg: a resource specifier for the register space, which should + include all SDRAM controller registers as per the datasheet. + +Example: + +sdramc@1400 { + compatible = "marvell,armada-xp-sdram-controller"; + reg = <0x1400 0x500>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra124-emc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra124-emc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba0bc3f124197eb07f196f140c68dda063d4a8d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra124-emc.txt @@ -0,0 +1,374 @@ +NVIDIA Tegra124 SoC EMC (external memory controller) +==================================================== + +Required properties : +- compatible : Should be "nvidia,tegra124-emc". +- reg : physical base address and length of the controller's registers. +- nvidia,memory-controller : phandle of the MC driver. + +The node should contain a "emc-timings" subnode for each supported RAM type +(see field RAM_CODE in register PMC_STRAPPING_OPT_A), with its unit address +being its RAM_CODE. + +Required properties for "emc-timings" nodes : +- nvidia,ram-code : Should contain the value of RAM_CODE this timing set is +used for. + +Each "emc-timings" node should contain a "timing" subnode for every supported +EMC clock rate. The "timing" subnodes should have the clock rate in Hz as +their unit address. + +Required properties for "timing" nodes : +- clock-frequency : Should contain the memory clock rate in Hz. +- The following properties contain EMC timing characterization values +(specified in the board documentation) : + - nvidia,emc-auto-cal-config : EMC_AUTO_CAL_CONFIG + - nvidia,emc-auto-cal-config2 : EMC_AUTO_CAL_CONFIG2 + - nvidia,emc-auto-cal-config3 : EMC_AUTO_CAL_CONFIG3 + - nvidia,emc-auto-cal-interval : EMC_AUTO_CAL_INTERVAL + - nvidia,emc-bgbias-ctl0 : EMC_BGBIAS_CTL0 + - nvidia,emc-cfg : EMC_CFG + - nvidia,emc-cfg-2 : EMC_CFG_2 + - nvidia,emc-ctt-term-ctrl : EMC_CTT_TERM_CTRL + - nvidia,emc-mode-1 : Mode Register 1 + - nvidia,emc-mode-2 : Mode Register 2 + - nvidia,emc-mode-4 : Mode Register 4 + - nvidia,emc-mode-reset : Mode Register 0 + - nvidia,emc-mrs-wait-cnt : EMC_MRS_WAIT_CNT + - nvidia,emc-sel-dpd-ctrl : EMC_SEL_DPD_CTRL + - nvidia,emc-xm2dqspadctrl2 : EMC_XM2DQSPADCTRL2 + - nvidia,emc-zcal-cnt-long : EMC_ZCAL_WAIT_CNT after clock change + - nvidia,emc-zcal-interval : EMC_ZCAL_INTERVAL +- nvidia,emc-configuration : EMC timing characterization data. These are the +registers (see section "15.6.2 EMC Registers" in the TRM) whose values need to +be specified, according to the board documentation: + + EMC_RC + EMC_RFC + EMC_RFC_SLR + EMC_RAS + EMC_RP + EMC_R2W + EMC_W2R + EMC_R2P + EMC_W2P + EMC_RD_RCD + EMC_WR_RCD + EMC_RRD + EMC_REXT + EMC_WEXT + EMC_WDV + EMC_WDV_MASK + EMC_QUSE + EMC_QUSE_WIDTH + EMC_IBDLY + EMC_EINPUT + EMC_EINPUT_DURATION + EMC_PUTERM_EXTRA + EMC_PUTERM_WIDTH + EMC_PUTERM_ADJ + EMC_CDB_CNTL_1 + EMC_CDB_CNTL_2 + EMC_CDB_CNTL_3 + EMC_QRST + EMC_QSAFE + EMC_RDV + EMC_RDV_MASK + EMC_REFRESH + EMC_BURST_REFRESH_NUM + EMC_PRE_REFRESH_REQ_CNT + EMC_PDEX2WR + EMC_PDEX2RD + EMC_PCHG2PDEN + EMC_ACT2PDEN + EMC_AR2PDEN + EMC_RW2PDEN + EMC_TXSR + EMC_TXSRDLL + EMC_TCKE + EMC_TCKESR + EMC_TPD + EMC_TFAW + EMC_TRPAB + EMC_TCLKSTABLE + EMC_TCLKSTOP + EMC_TREFBW + EMC_FBIO_CFG6 + EMC_ODT_WRITE + EMC_ODT_READ + EMC_FBIO_CFG5 + EMC_CFG_DIG_DLL + EMC_CFG_DIG_DLL_PERIOD + EMC_DLL_XFORM_DQS0 + EMC_DLL_XFORM_DQS1 + EMC_DLL_XFORM_DQS2 + EMC_DLL_XFORM_DQS3 + EMC_DLL_XFORM_DQS4 + EMC_DLL_XFORM_DQS5 + EMC_DLL_XFORM_DQS6 + EMC_DLL_XFORM_DQS7 + EMC_DLL_XFORM_DQS8 + EMC_DLL_XFORM_DQS9 + EMC_DLL_XFORM_DQS10 + EMC_DLL_XFORM_DQS11 + EMC_DLL_XFORM_DQS12 + EMC_DLL_XFORM_DQS13 + EMC_DLL_XFORM_DQS14 + EMC_DLL_XFORM_DQS15 + EMC_DLL_XFORM_QUSE0 + EMC_DLL_XFORM_QUSE1 + EMC_DLL_XFORM_QUSE2 + EMC_DLL_XFORM_QUSE3 + EMC_DLL_XFORM_QUSE4 + EMC_DLL_XFORM_QUSE5 + EMC_DLL_XFORM_QUSE6 + EMC_DLL_XFORM_QUSE7 + EMC_DLL_XFORM_ADDR0 + EMC_DLL_XFORM_ADDR1 + EMC_DLL_XFORM_ADDR2 + EMC_DLL_XFORM_ADDR3 + EMC_DLL_XFORM_ADDR4 + EMC_DLL_XFORM_ADDR5 + EMC_DLL_XFORM_QUSE8 + EMC_DLL_XFORM_QUSE9 + EMC_DLL_XFORM_QUSE10 + EMC_DLL_XFORM_QUSE11 + EMC_DLL_XFORM_QUSE12 + EMC_DLL_XFORM_QUSE13 + EMC_DLL_XFORM_QUSE14 + EMC_DLL_XFORM_QUSE15 + EMC_DLI_TRIM_TXDQS0 + EMC_DLI_TRIM_TXDQS1 + EMC_DLI_TRIM_TXDQS2 + EMC_DLI_TRIM_TXDQS3 + EMC_DLI_TRIM_TXDQS4 + EMC_DLI_TRIM_TXDQS5 + EMC_DLI_TRIM_TXDQS6 + EMC_DLI_TRIM_TXDQS7 + EMC_DLI_TRIM_TXDQS8 + EMC_DLI_TRIM_TXDQS9 + EMC_DLI_TRIM_TXDQS10 + EMC_DLI_TRIM_TXDQS11 + EMC_DLI_TRIM_TXDQS12 + EMC_DLI_TRIM_TXDQS13 + EMC_DLI_TRIM_TXDQS14 + EMC_DLI_TRIM_TXDQS15 + EMC_DLL_XFORM_DQ0 + EMC_DLL_XFORM_DQ1 + EMC_DLL_XFORM_DQ2 + EMC_DLL_XFORM_DQ3 + EMC_DLL_XFORM_DQ4 + EMC_DLL_XFORM_DQ5 + EMC_DLL_XFORM_DQ6 + EMC_DLL_XFORM_DQ7 + EMC_XM2CMDPADCTRL + EMC_XM2CMDPADCTRL4 + EMC_XM2CMDPADCTRL5 + EMC_XM2DQPADCTRL2 + EMC_XM2DQPADCTRL3 + EMC_XM2CLKPADCTRL + EMC_XM2CLKPADCTRL2 + EMC_XM2COMPPADCTRL + EMC_XM2VTTGENPADCTRL + EMC_XM2VTTGENPADCTRL2 + EMC_XM2VTTGENPADCTRL3 + EMC_XM2DQSPADCTRL3 + EMC_XM2DQSPADCTRL4 + EMC_XM2DQSPADCTRL5 + EMC_XM2DQSPADCTRL6 + EMC_DSR_VTTGEN_DRV + EMC_TXDSRVTTGEN + EMC_FBIO_SPARE + EMC_ZCAL_WAIT_CNT + EMC_MRS_WAIT_CNT2 + EMC_CTT + EMC_CTT_DURATION + EMC_CFG_PIPE + EMC_DYN_SELF_REF_CONTROL + EMC_QPOP + +Example SoC include file: + +/ { + emc@7001b000 { + compatible = "nvidia,tegra124-emc"; + reg = <0x0 0x7001b000 0x0 0x1000>; + + nvidia,memory-controller = <&mc>; + }; +}; + +Example board file: + +/ { + emc@7001b000 { + emc-timings-3 { + nvidia,ram-code = <3>; + + timing-12750000 { + clock-frequency = <12750000>; + + nvidia,emc-zcal-cnt-long = <0x00000042>; + nvidia,emc-auto-cal-interval = <0x001fffff>; + nvidia,emc-ctt-term-ctrl = <0x00000802>; + nvidia,emc-cfg = <0x73240000>; + nvidia,emc-cfg-2 = <0x000008c5>; + nvidia,emc-sel-dpd-ctrl = <0x00040128>; + nvidia,emc-bgbias-ctl0 = <0x00000008>; + nvidia,emc-auto-cal-config = <0xa1430000>; + nvidia,emc-auto-cal-config2 = <0x00000000>; + nvidia,emc-auto-cal-config3 = <0x00000000>; + nvidia,emc-mode-reset = <0x80001221>; + nvidia,emc-mode-1 = <0x80100003>; + nvidia,emc-mode-2 = <0x80200008>; + nvidia,emc-mode-4 = <0x00000000>; + + nvidia,emc-configuration = < + 0x00000000 /* EMC_RC */ + 0x00000003 /* EMC_RFC */ + 0x00000000 /* EMC_RFC_SLR */ + 0x00000000 /* EMC_RAS */ + 0x00000000 /* EMC_RP */ + 0x00000004 /* EMC_R2W */ + 0x0000000a /* EMC_W2R */ + 0x00000003 /* EMC_R2P */ + 0x0000000b /* EMC_W2P */ + 0x00000000 /* EMC_RD_RCD */ + 0x00000000 /* EMC_WR_RCD */ + 0x00000003 /* EMC_RRD */ + 0x00000003 /* EMC_REXT */ + 0x00000000 /* EMC_WEXT */ + 0x00000006 /* EMC_WDV */ + 0x00000006 /* EMC_WDV_MASK */ + 0x00000006 /* EMC_QUSE */ + 0x00000002 /* EMC_QUSE_WIDTH */ + 0x00000000 /* EMC_IBDLY */ + 0x00000005 /* EMC_EINPUT */ + 0x00000005 /* EMC_EINPUT_DURATION */ + 0x00010000 /* EMC_PUTERM_EXTRA */ + 0x00000003 /* EMC_PUTERM_WIDTH */ + 0x00000000 /* EMC_PUTERM_ADJ */ + 0x00000000 /* EMC_CDB_CNTL_1 */ + 0x00000000 /* EMC_CDB_CNTL_2 */ + 0x00000000 /* EMC_CDB_CNTL_3 */ + 0x00000004 /* EMC_QRST */ + 0x0000000c /* EMC_QSAFE */ + 0x0000000d /* EMC_RDV */ + 0x0000000f /* EMC_RDV_MASK */ + 0x00000060 /* EMC_REFRESH */ + 0x00000000 /* EMC_BURST_REFRESH_NUM */ + 0x00000018 /* EMC_PRE_REFRESH_REQ_CNT */ + 0x00000002 /* EMC_PDEX2WR */ + 0x00000002 /* EMC_PDEX2RD */ + 0x00000001 /* EMC_PCHG2PDEN */ + 0x00000000 /* EMC_ACT2PDEN */ + 0x00000007 /* EMC_AR2PDEN */ + 0x0000000f /* EMC_RW2PDEN */ + 0x00000005 /* EMC_TXSR */ + 0x00000005 /* EMC_TXSRDLL */ + 0x00000004 /* EMC_TCKE */ + 0x00000005 /* EMC_TCKESR */ + 0x00000004 /* EMC_TPD */ + 0x00000000 /* EMC_TFAW */ + 0x00000000 /* EMC_TRPAB */ + 0x00000005 /* EMC_TCLKSTABLE */ + 0x00000005 /* EMC_TCLKSTOP */ + 0x00000064 /* EMC_TREFBW */ + 0x00000000 /* EMC_FBIO_CFG6 */ + 0x00000000 /* EMC_ODT_WRITE */ + 0x00000000 /* EMC_ODT_READ */ + 0x106aa298 /* EMC_FBIO_CFG5 */ + 0x002c00a0 /* EMC_CFG_DIG_DLL */ + 0x00008000 /* EMC_CFG_DIG_DLL_PERIOD */ + 0x00064000 /* EMC_DLL_XFORM_DQS0 */ + 0x00064000 /* EMC_DLL_XFORM_DQS1 */ + 0x00064000 /* EMC_DLL_XFORM_DQS2 */ + 0x00064000 /* EMC_DLL_XFORM_DQS3 */ + 0x00064000 /* EMC_DLL_XFORM_DQS4 */ + 0x00064000 /* EMC_DLL_XFORM_DQS5 */ + 0x00064000 /* EMC_DLL_XFORM_DQS6 */ + 0x00064000 /* EMC_DLL_XFORM_DQS7 */ + 0x00064000 /* EMC_DLL_XFORM_DQS8 */ + 0x00064000 /* EMC_DLL_XFORM_DQS9 */ + 0x00064000 /* EMC_DLL_XFORM_DQS10 */ + 0x00064000 /* EMC_DLL_XFORM_DQS11 */ + 0x00064000 /* EMC_DLL_XFORM_DQS12 */ + 0x00064000 /* EMC_DLL_XFORM_DQS13 */ + 0x00064000 /* EMC_DLL_XFORM_DQS14 */ + 0x00064000 /* EMC_DLL_XFORM_DQS15 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE0 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE1 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE2 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE3 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE4 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE5 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE6 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE7 */ + 0x00000000 /* EMC_DLL_XFORM_ADDR0 */ + 0x00000000 /* EMC_DLL_XFORM_ADDR1 */ + 0x00000000 /* EMC_DLL_XFORM_ADDR2 */ + 0x00000000 /* EMC_DLL_XFORM_ADDR3 */ + 0x00000000 /* EMC_DLL_XFORM_ADDR4 */ + 0x00000000 /* EMC_DLL_XFORM_ADDR5 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE8 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE9 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE10 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE11 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE12 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE13 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE14 */ + 0x00000000 /* EMC_DLL_XFORM_QUSE15 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS0 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS1 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS2 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS3 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS4 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS5 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS6 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS7 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS8 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS9 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS10 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS11 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS12 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS13 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS14 */ + 0x00000000 /* EMC_DLI_TRIM_TXDQS15 */ + 0x000fc000 /* EMC_DLL_XFORM_DQ0 */ + 0x000fc000 /* EMC_DLL_XFORM_DQ1 */ + 0x000fc000 /* EMC_DLL_XFORM_DQ2 */ + 0x000fc000 /* EMC_DLL_XFORM_DQ3 */ + 0x0000fc00 /* EMC_DLL_XFORM_DQ4 */ + 0x0000fc00 /* EMC_DLL_XFORM_DQ5 */ + 0x0000fc00 /* EMC_DLL_XFORM_DQ6 */ + 0x0000fc00 /* EMC_DLL_XFORM_DQ7 */ + 0x10000280 /* EMC_XM2CMDPADCTRL */ + 0x00000000 /* EMC_XM2CMDPADCTRL4 */ + 0x00111111 /* EMC_XM2CMDPADCTRL5 */ + 0x00000000 /* EMC_XM2DQPADCTRL2 */ + 0x00000000 /* EMC_XM2DQPADCTRL3 */ + 0x77ffc081 /* EMC_XM2CLKPADCTRL */ + 0x00000e0e /* EMC_XM2CLKPADCTRL2 */ + 0x81f1f108 /* EMC_XM2COMPPADCTRL */ + 0x07070004 /* EMC_XM2VTTGENPADCTRL */ + 0x0000003f /* EMC_XM2VTTGENPADCTRL2 */ + 0x016eeeee /* EMC_XM2VTTGENPADCTRL3 */ + 0x51451400 /* EMC_XM2DQSPADCTRL3 */ + 0x00514514 /* EMC_XM2DQSPADCTRL4 */ + 0x00514514 /* EMC_XM2DQSPADCTRL5 */ + 0x51451400 /* EMC_XM2DQSPADCTRL6 */ + 0x0000003f /* EMC_DSR_VTTGEN_DRV */ + 0x00000007 /* EMC_TXDSRVTTGEN */ + 0x00000000 /* EMC_FBIO_SPARE */ + 0x00000042 /* EMC_ZCAL_WAIT_CNT */ + 0x000e000e /* EMC_MRS_WAIT_CNT2 */ + 0x00000000 /* EMC_CTT */ + 0x00000003 /* EMC_CTT_DURATION */ + 0x0000f2f3 /* EMC_CFG_PIPE */ + 0x800001c5 /* EMC_DYN_SELF_REF_CONTROL */ + 0x0000000a /* EMC_QPOP */ + >; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra20-mc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra20-mc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d60a50a4fa1c72ec7c6347705b3ffea3898c6b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra20-mc.txt @@ -0,0 +1,26 @@ +NVIDIA Tegra20 MC(Memory Controller) + +Required properties: +- compatible : "nvidia,tegra20-mc" +- reg : Should contain 2 register ranges(address and length); see the + example below. Note that the MC registers are interleaved with the + GART registers, and hence must be represented as multiple ranges. +- interrupts : Should contain MC General interrupt. +- #reset-cells : Should be 1. This cell represents memory client module ID. + The assignments may be found in header file + or in the TRM documentation. + +Example: + mc: memory-controller@7000f000 { + compatible = "nvidia,tegra20-mc"; + reg = <0x7000f000 0x024 + 0x7000f03c 0x3c4>; + interrupts = <0 77 0x04>; + #reset-cells = <1>; + }; + + video-codec@6001a000 { + compatible = "nvidia,tegra20-vde"; + ... + resets = <&mc TEGRA20_MC_RESET_VDE>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra30-mc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra30-mc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a878b5908a4d0652cce014bbe465137d48056ded --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/nvidia,tegra30-mc.txt @@ -0,0 +1,123 @@ +NVIDIA Tegra Memory Controller device tree bindings +=================================================== + +memory-controller node +---------------------- + +Required properties: +- compatible: Should be "nvidia,tegra-mc" +- reg: Physical base address and length of the controller's registers. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - mc: the module's clock input +- interrupts: The interrupt outputs from the controller. +- #reset-cells : Should be 1. This cell represents memory client module ID. + The assignments may be found in header file + or in the TRM documentation. + +Required properties for Tegra30, Tegra114, Tegra124, Tegra132 and Tegra210: +- #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines + the SWGROUP of the master. + +This device implements an IOMMU that complies with the generic IOMMU binding. +See ../iommu/iommu.txt for details. + +emc-timings subnode +------------------- + +The node should contain a "emc-timings" subnode for each supported RAM type (see field RAM_CODE in +register PMC_STRAPPING_OPT_A). + +Required properties for "emc-timings" nodes : +- nvidia,ram-code : Should contain the value of RAM_CODE this timing set is used for. + +timing subnode +-------------- + +Each "emc-timings" node should contain a subnode for every supported EMC clock rate. + +Required properties for timing nodes : +- clock-frequency : Should contain the memory clock rate in Hz. +- nvidia,emem-configuration : Values to be written to the EMEM register block. For the Tegra124 SoC +(see section "15.6.1 MC Registers" in the TRM), these are the registers whose values need to be +specified, according to the board documentation: + + MC_EMEM_ARB_CFG + MC_EMEM_ARB_OUTSTANDING_REQ + MC_EMEM_ARB_TIMING_RCD + MC_EMEM_ARB_TIMING_RP + MC_EMEM_ARB_TIMING_RC + MC_EMEM_ARB_TIMING_RAS + MC_EMEM_ARB_TIMING_FAW + MC_EMEM_ARB_TIMING_RRD + MC_EMEM_ARB_TIMING_RAP2PRE + MC_EMEM_ARB_TIMING_WAP2PRE + MC_EMEM_ARB_TIMING_R2R + MC_EMEM_ARB_TIMING_W2W + MC_EMEM_ARB_TIMING_R2W + MC_EMEM_ARB_TIMING_W2R + MC_EMEM_ARB_DA_TURNS + MC_EMEM_ARB_DA_COVERS + MC_EMEM_ARB_MISC0 + MC_EMEM_ARB_MISC1 + MC_EMEM_ARB_RING1_THROTTLE + +Example SoC include file: + +/ { + mc: memory-controller@70019000 { + compatible = "nvidia,tegra124-mc"; + reg = <0x0 0x70019000 0x0 0x1000>; + clocks = <&tegra_car TEGRA124_CLK_MC>; + clock-names = "mc"; + + interrupts = ; + + #iommu-cells = <1>; + #reset-cells = <1>; + }; + + sdhci@700b0000 { + compatible = "nvidia,tegra124-sdhci"; + ... + iommus = <&mc TEGRA_SWGROUP_SDMMC1A>; + resets = <&mc TEGRA124_MC_RESET_SDMMC1>; + }; +}; + +Example board file: + +/ { + memory-controller@70019000 { + emc-timings-3 { + nvidia,ram-code = <3>; + + timing-12750000 { + clock-frequency = <12750000>; + + nvidia,emem-configuration = < + 0x40040001 /* MC_EMEM_ARB_CFG */ + 0x8000000a /* MC_EMEM_ARB_OUTSTANDING_REQ */ + 0x00000001 /* MC_EMEM_ARB_TIMING_RCD */ + 0x00000001 /* MC_EMEM_ARB_TIMING_RP */ + 0x00000002 /* MC_EMEM_ARB_TIMING_RC */ + 0x00000000 /* MC_EMEM_ARB_TIMING_RAS */ + 0x00000002 /* MC_EMEM_ARB_TIMING_FAW */ + 0x00000001 /* MC_EMEM_ARB_TIMING_RRD */ + 0x00000002 /* MC_EMEM_ARB_TIMING_RAP2PRE */ + 0x00000008 /* MC_EMEM_ARB_TIMING_WAP2PRE */ + 0x00000003 /* MC_EMEM_ARB_TIMING_R2R */ + 0x00000002 /* MC_EMEM_ARB_TIMING_W2W */ + 0x00000003 /* MC_EMEM_ARB_TIMING_R2W */ + 0x00000006 /* MC_EMEM_ARB_TIMING_W2R */ + 0x06030203 /* MC_EMEM_ARB_DA_TURNS */ + 0x000a0402 /* MC_EMEM_ARB_DA_COVERS */ + 0x77e30303 /* MC_EMEM_ARB_MISC0 */ + 0x70000f03 /* MC_EMEM_ARB_MISC1 */ + 0x001f0000 /* MC_EMEM_ARB_RING1_THROTTLE */ + >; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/omap-gpmc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/omap-gpmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1359f4d48d709efe12d7c081ee45878d0f2676e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/omap-gpmc.txt @@ -0,0 +1,157 @@ +Device tree bindings for OMAP general purpose memory controllers (GPMC) + +The actual devices are instantiated from the child nodes of a GPMC node. + +Required properties: + + - compatible: Should be set to one of the following: + + ti,omap2420-gpmc (omap2420) + ti,omap2430-gpmc (omap2430) + ti,omap3430-gpmc (omap3430 & omap3630) + ti,omap4430-gpmc (omap4430 & omap4460 & omap543x) + ti,am3352-gpmc (am335x devices) + + - reg: A resource specifier for the register space + (see the example below) + - ti,hwmods: Should be set to "ti,gpmc" until the DT transition is + completed. + - #address-cells: Must be set to 2 to allow memory address translation + - #size-cells: Must be set to 1 to allow CS address passing + - gpmc,num-cs: The maximum number of chip-select lines that controller + can support. + - gpmc,num-waitpins: The maximum number of wait pins that controller can + support. + - ranges: Must be set up to reflect the memory layout with four + integer values for each chip-select line in use: + + 0 + + Currently, calculated values derived from the contents + of the per-CS register GPMC_CONFIG7 (as set up by the + bootloader) are used for the physical address decoding. + As this will change in the future, filling correct + values here is a requirement. + - interrupt-controller: The GPMC driver implements and interrupt controller for + the NAND events "fifoevent" and "termcount" plus the + rising/falling edges on the GPMC_WAIT pins. + The interrupt number mapping is as follows + 0 - NAND_fifoevent + 1 - NAND_termcount + 2 - GPMC_WAIT0 pin edge + 3 - GPMC_WAIT1 pin edge, and so on. + - interrupt-cells: Must be set to 2 + - gpio-controller: The GPMC driver implements a GPIO controller for the + GPMC WAIT pins that can be used as general purpose inputs. + 0 maps to GPMC_WAIT0 pin. + - gpio-cells: Must be set to 2 + +Required properties when using NAND prefetch dma: + - dmas GPMC NAND prefetch dma channel + - dma-names Must be set to "rxtx" + +Timing properties for child nodes. All are optional and default to 0. + + - gpmc,sync-clk-ps: Minimum clock period for synchronous mode, in picoseconds + + Chip-select signal timings (in nanoseconds) corresponding to GPMC_CONFIG2: + - gpmc,cs-on-ns: Assertion time + - gpmc,cs-rd-off-ns: Read deassertion time + - gpmc,cs-wr-off-ns: Write deassertion time + + ADV signal timings (in nanoseconds) corresponding to GPMC_CONFIG3: + - gpmc,adv-on-ns: Assertion time + - gpmc,adv-rd-off-ns: Read deassertion time + - gpmc,adv-wr-off-ns: Write deassertion time + - gpmc,adv-aad-mux-on-ns: Assertion time for AAD + - gpmc,adv-aad-mux-rd-off-ns: Read deassertion time for AAD + - gpmc,adv-aad-mux-wr-off-ns: Write deassertion time for AAD + + WE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4: + - gpmc,we-on-ns Assertion time + - gpmc,we-off-ns: Deassertion time + + OE signals timings (in nanoseconds) corresponding to GPMC_CONFIG4: + - gpmc,oe-on-ns: Assertion time + - gpmc,oe-off-ns: Deassertion time + - gpmc,oe-aad-mux-on-ns: Assertion time for AAD + - gpmc,oe-aad-mux-off-ns: Deassertion time for AAD + + Access time and cycle time timings (in nanoseconds) corresponding to + GPMC_CONFIG5: + - gpmc,page-burst-access-ns: Multiple access word delay + - gpmc,access-ns: Start-cycle to first data valid delay + - gpmc,rd-cycle-ns: Total read cycle time + - gpmc,wr-cycle-ns: Total write cycle time + - gpmc,bus-turnaround-ns: Turn-around time between successive accesses + - gpmc,cycle2cycle-delay-ns: Delay between chip-select pulses + - gpmc,clk-activation-ns: GPMC clock activation time + - gpmc,wait-monitoring-ns: Start of wait monitoring with regard to valid + data + +Boolean timing parameters. If property is present parameter enabled and +disabled if omitted: + - gpmc,adv-extra-delay: ADV signal is delayed by half GPMC clock + - gpmc,cs-extra-delay: CS signal is delayed by half GPMC clock + - gpmc,cycle2cycle-diffcsen: Add "cycle2cycle-delay" between successive + accesses to a different CS + - gpmc,cycle2cycle-samecsen: Add "cycle2cycle-delay" between successive + accesses to the same CS + - gpmc,oe-extra-delay: OE signal is delayed by half GPMC clock + - gpmc,we-extra-delay: WE signal is delayed by half GPMC clock + - gpmc,time-para-granularity: Multiply all access times by 2 + +The following are only applicable to OMAP3+ and AM335x: + - gpmc,wr-access-ns: In synchronous write mode, for single or + burst accesses, defines the number of + GPMC_FCLK cycles from start access time + to the GPMC_CLK rising edge used by the + memory device for the first data capture. + - gpmc,wr-data-mux-bus-ns: In address-data multiplex mode, specifies + the time when the first data is driven on + the address-data bus. + +GPMC chip-select settings properties for child nodes. All are optional. + +- gpmc,burst-length Page/burst length. Must be 4, 8 or 16. +- gpmc,burst-wrap Enables wrap bursting +- gpmc,burst-read Enables read page/burst mode +- gpmc,burst-write Enables write page/burst mode +- gpmc,device-width Total width of device(s) connected to a GPMC + chip-select in bytes. The GPMC supports 8-bit + and 16-bit devices and so this property must be + 1 or 2. +- gpmc,mux-add-data Address and data multiplexing configuration. + Valid values are 1 for address-address-data + multiplexing mode and 2 for address-data + multiplexing mode. +- gpmc,sync-read Enables synchronous read. Defaults to asynchronous + is this is not set. +- gpmc,sync-write Enables synchronous writes. Defaults to asynchronous + is this is not set. +- gpmc,wait-pin Wait-pin used by client. Must be less than + "gpmc,num-waitpins". +- gpmc,wait-on-read Enables wait monitoring on reads. +- gpmc,wait-on-write Enables wait monitoring on writes. + +Example for an AM33xx board: + + gpmc: gpmc@50000000 { + compatible = "ti,am3352-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x50000000 0x2000>; + interrupts = <100>; + dmas = <&edma 52 0>; + dma-names = "rxtx"; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <2>; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x08000000 0x10000000>; /* CS0 @addr 0x8000000, size 0x10000000 */ + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + + /* child nodes go here */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/renesas,h8300-bsc.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/renesas,h8300-bsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..cdf406c902e2b177b35407443841a57a76b87390 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/renesas,h8300-bsc.txt @@ -0,0 +1,12 @@ +* H8/300 bus controller + +Required properties: + - compatible: Must be "renesas,h8300-bsc". + - reg: Base address and length of BSC registers. + +Example. + bsc: memory-controller@fee01e { + compatible = "renesas,h8300h-bsc", "renesas,h8300-bsc"; + reg = <0xfee01e 8>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/renesas-memory-controllers.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/renesas-memory-controllers.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f78e6c82740cc89ed9556e111a91ad104fe5138 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/renesas-memory-controllers.txt @@ -0,0 +1,44 @@ +DT bindings for Renesas R-Mobile and SH-Mobile memory controllers +================================================================= + +Renesas R-Mobile and SH-Mobile SoCs contain one or more memory controllers. +These memory controllers differ from one SoC variant to another, and are called +by different names ("DDR Bus Controller (DBSC)", "DDR3 Bus State Controller +(DBSC3)", "SDRAM Bus State Controller (SBSC)"). + +Currently memory controller device nodes are used only to reference PM +domains, and prevent these PM domains from being powered down, which would +crash the system. + +As there exist no actual drivers for these controllers yet, these bindings +should be considered EXPERIMENTAL for now. + +Required properties: + - compatible: Must be one of the following SoC-specific values: + - "renesas,dbsc-r8a73a4" (R-Mobile APE6) + - "renesas,dbsc3-r8a7740" (R-Mobile A1) + - "renesas,sbsc-sh73a0" (SH-Mobile AG5) + - reg: Must contain the base address and length of the memory controller's + registers. + +Optional properties: + - interrupts: Must contain a list of interrupt specifiers for memory + controller interrupts, if available. + - interrupt-names: Must contain a list of interrupt names corresponding to + the interrupts in the interrupts property, if available. + Valid interrupt names are: + - "sec" (secure interrupt) + - "temp" (normal (temperature) interrupt) + - power-domains: Must contain a reference to the PM domain that the memory + controller belongs to, if available. + +Example: + + sbsc1: memory-controller@fe400000 { + compatible = "renesas,sbsc-sh73a0"; + reg = <0xfe400000 0x400>; + interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>, + <0 36 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "sec", "temp"; + power-domains = <&pd_a4bc0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/synopsys.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/synopsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..a43d26d41e04b7f87586b6b825c4307e6ff9f3ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/synopsys.txt @@ -0,0 +1,15 @@ +Binding for Synopsys IntelliDDR Multi Protocol Memory Controller + +This controller has an optional ECC support in half-bus width (16-bit) +configuration. The ECC controller corrects one bit error and detects +two bit errors. + +Required properties: + - compatible: Should be 'xlnx,zynq-ddrc-a05' + - reg: Base address and size of the controllers memory area + +Example: + memory-controller@f8006000 { + compatible = "xlnx,zynq-ddrc-a05"; + reg = <0xf8006000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti-aemif.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti-aemif.txt new file mode 100644 index 0000000000000000000000000000000000000000..190437a0c146fe4e9678118f2b8996edcd04af7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti-aemif.txt @@ -0,0 +1,210 @@ +* Device tree bindings for Texas instruments AEMIF controller + +The Async External Memory Interface (EMIF16/AEMIF) controller is intended to +provide a glue-less interface to a variety of asynchronous memory devices like +ASRA M, NOR and NAND memory. A total of 256M bytes of any of these memories +can be accessed at any given time via four chip selects with 64M byte access +per chip select. Synchronous memories such as DDR1 SD RAM, SDR SDRAM +and Mobile SDR are not supported. + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf +Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf + +Required properties: + +- compatible: "ti,davinci-aemif" + "ti,keystone-aemif" + "ti,da850-aemif" + +- reg: contains offset/length value for AEMIF control registers + space. + +- #address-cells: Must be 2. The partition number has to be encoded in the + first address cell and it may accept values 0..N-1 + (N - total number of partitions). It's recommended to + assign N-1 number for the control partition. The second + cell is the offset into the partition. + +- #size-cells: Must be set to 1. + +- ranges: Contains memory regions. There are two types of + ranges/partitions: + - CS-specific partition/range. If continuous, must be + set up to reflect the memory layout for 4 chipselects, + if not then additional range/partition can be added and + child device can select the proper one. + - control partition which is common for all CS + interfaces. + +- clocks: the clock feeding the controller clock. Required only + if clock tree data present in device tree. + See clock-bindings.txt + +- clock-names: clock name. It has to be "aemif". Required only if clock + tree data present in device tree, in another case don't + use it. + See clock-bindings.txt + +- clock-ranges: Empty property indicating that child nodes can inherit + named clocks. Required only if clock tree data present + in device tree. + See clock-bindings.txt + + +Child chip-select (cs) nodes contain the memory devices nodes connected to +such as NOR (e.g. cfi-flash) and NAND (ti,davinci-nand, see davinci-nand.txt). +There might be board specific devices like FPGAs. + +Required child cs node properties: + +- #address-cells: Must be 2. + +- #size-cells: Must be 1. + +- ranges: Empty property indicating that child nodes can inherit + memory layout. + +- clock-ranges: Empty property indicating that child nodes can inherit + named clocks. Required only if clock tree data present + in device tree. + +- ti,cs-chipselect: number of chipselect. Indicates on the aemif driver + which chipselect is used for accessing the memory. For + compatibles "ti,davinci-aemif" and "ti,keystone-aemif" + it can be in range [0-3]. For compatible + "ti,da850-aemif" range is [2-5]. + +Optional child cs node properties: + +- ti,cs-bus-width: width of the asynchronous device's data bus + 8 or 16 if not preset 8 + +- ti,cs-select-strobe-mode: enable/disable select strobe mode + In select strobe mode chip select behaves as + the strobe and is active only during the strobe + period. If present then enable. + +- ti,cs-extended-wait-mode: enable/disable extended wait mode + if set, the controller monitors the EMIFWAIT pin + mapped to that chip select to determine if the + device wants to extend the strobe period. If + present then enable. + +- ti,cs-min-turnaround-ns: minimum turn around time, ns + Time between the end of one asynchronous memory + access and the start of another asynchronous + memory access. This delay is not incurred + between a read followed by read or a write + followed by a write to same chip select. + +- ti,cs-read-setup-ns: read setup width, ns + Time between the beginning of a memory cycle + and the activation of read strobe. + Minimum value is 1 (0 treated as 1). + +- ti,cs-read-strobe-ns: read strobe width, ns + Time between the activation and deactivation of + the read strobe. + Minimum value is 1 (0 treated as 1). + +- ti,cs-read-hold-ns: read hold width, ns + Time between the deactivation of the read + strobe and the end of the cycle (which may be + either an address change or the deactivation of + the chip select signal. + Minimum value is 1 (0 treated as 1). + +- ti,cs-write-setup-ns: write setup width, ns + Time between the beginning of a memory cycle + and the activation of write strobe. + Minimum value is 1 (0 treated as 1). + +- ti,cs-write-strobe-ns: write strobe width, ns + Time between the activation and deactivation of + the write strobe. + Minimum value is 1 (0 treated as 1). + +- ti,cs-write-hold-ns: write hold width, ns + Time between the deactivation of the write + strobe and the end of the cycle (which may be + either an address change or the deactivation of + the chip select signal. + Minimum value is 1 (0 treated as 1). + +If any of the above parameters are absent, current parameter value will be taken +from the corresponding HW reg. + +Example for aemif, davinci nand and nor flash chip select shown below. + +memory-controller@21000a00 { + compatible = "ti,davinci-aemif"; + #address-cells = <2>; + #size-cells = <1>; + clocks = <&clkaemif 0>; + clock-names = "aemif"; + clock-ranges; + reg = <0x21000A00 0x00000100>; + ranges = <0 0 0x70000000 0x10000000 + 1 0 0x21000A00 0x00000100>; + /* + * Partition0: CS-specific memory range which is + * implemented as continuous physical memory region + * Partition1: control memory range + */ + + nand:cs2 { + #address-cells = <2>; + #size-cells = <1>; + clock-ranges; + ranges; + + ti,cs-chipselect = <2>; + /* all timings in nanoseconds */ + ti,cs-min-turnaround-ns = <0>; + ti,cs-read-hold-ns = <7>; + ti,cs-read-strobe-ns = <42>; + ti,cs-read-setup-ns = <14>; + ti,cs-write-hold-ns = <7>; + ti,cs-write-strobe-ns = <42>; + ti,cs-write-setup-ns = <14>; + + nand@0,0x8000000 { + compatible = "ti,davinci-nand"; + reg = <0 0x8000000 0x4000000 + 1 0x0000000 0x0000100>; + /* + * Partition0, offset 0x8000000, size 0x4000000 + * Partition1, offset 0x0000000, size 0x0000100 + */ + + .. see davinci-nand.txt + }; + }; + + nor:cs0 { + #address-cells = <2>; + #size-cells = <1>; + clock-ranges; + ranges; + + ti,cs-chipselect = <0>; + /* all timings in nanoseconds */ + ti,cs-min-turnaround-ns = <0>; + ti,cs-read-hold-ns = <8>; + ti,cs-read-strobe-ns = <40>; + ti,cs-read-setup-ns = <14>; + ti,cs-write-hold-ns = <7>; + ti,cs-write-strobe-ns = <40>; + ti,cs-write-setup-ns = <14>; + ti,cs-bus-width = <16>; + + flash@0,0x0000000 { + compatible = "cfi-flash"; + reg = <0 0x0000000 0x4000000>; + + ... + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti-da8xx-ddrctl.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti-da8xx-ddrctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec1dd408d573793961cd725037f321cff47c85b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti-da8xx-ddrctl.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Texas Instruments da8xx DDR2/mDDR memory controller + +The DDR2/mDDR memory controller present on Texas Instruments da8xx SoCs features +a set of registers which allow to tweak the controller's behavior. + +Documentation: +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf + +Required properties: + +- compatible: "ti,da850-ddr-controller" - for da850 SoC based boards +- reg: a tuple containing the base address of the memory + controller and the size of the memory area to map + +Example for da850 shown below. + +ddrctl { + compatible = "ti,da850-ddr-controller"; + reg = <0xb0000000 0xe8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti/emif.txt b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti/emif.txt new file mode 100644 index 0000000000000000000000000000000000000000..44d71469c9148001df7ed926d54096f09c109e9f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/memory-controllers/ti/emif.txt @@ -0,0 +1,84 @@ +* EMIF family of TI SDRAM controllers + +EMIF - External Memory Interface - is an SDRAM controller used in +TI SoCs. EMIF supports, based on the IP revision, one or more of +DDR2/DDR3/LPDDR2 protocols. This binding describes a given instance +of the EMIF IP and memory parts attached to it. Certain revisions +of the EMIF controller also contain optional ECC support, which +corrects one bit errors and detects two bit errors. + +Required properties: +- compatible : Should be of the form "ti,emif-" where + is the IP revision of the specific EMIF instance. For newer controllers, + compatible should be one of the following: + "ti,emif-am3352" + "ti,emif-am4372" + "ti,emif-dra7xx" + "ti,emif-keystone" + +- phy-type : indicating the DDR phy type. Following are the + allowed values + <1> : Attila PHY + <2> : Intelli PHY + +- device-handle : phandle to a "lpddr2" node representing the memory part + +- ti,hwmods : For TI hwmods processing and omap device creation + the value shall be "emif" where is the number of the EMIF + instance with base 1. +- interrupts : interrupt used by the controller + +Required only for "ti,emif-am3352" and "ti,emif-am4372": +- sram : Phandles for generic sram driver nodes, + first should be type 'protect-exec' for the driver to use to copy + and run PM functions, second should be regular pool to be used for + data region for code. See Documentation/devicetree/bindings/sram/sram.txt + for more details. + +Optional properties: +- cs1-used : Have this property if CS1 of this EMIF + instance has a memory part attached to it. If there is a memory + part attached to CS1, it should be the same type as the one on CS0, + so there is no need to give the details of this memory part. + +- cal-resistor-per-cs : Have this property if the board has one + calibration resistor per chip-select. + +- hw-caps-read-idle-ctrl: Have this property if the controller + supports read idle window programming + +- hw-caps-dll-calib-ctrl: Have this property if the controller + supports dll calibration control + +- hw-caps-ll-interface : Have this property if the controller + has a low latency interface and corresponding interrupt events + +- hw-caps-temp-alert : Have this property if the controller + has capability for generating SDRAM temperature alerts + +-Examples: + +emif1: emif@4c000000 { + compatible = "ti,emif-4d"; + ti,hwmods = "emif2"; + phy-type = <1>; + device-handle = <&elpida_ECB240ABACN>; + cs1-used; + hw-caps-read-idle-ctrl; + hw-caps-ll-interface; + hw-caps-temp-alert; +}; + +/* From am33xx.dtsi */ +emif: emif@4c000000 { + compatible = "ti,emif-am3352"; + reg = <0x4C000000 0x1000>; + sram = <&pm_sram_code + &pm_sram_data>; +}; + +emif1: emif@4c000000 { + compatible = "ti,emif-dra7xx"; + reg = <0x4c000000 0x200>; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/88pm860x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/88pm860x.txt new file mode 100644 index 0000000000000000000000000000000000000000..63f3ee33759cf0ed57e2ff1622966b0a5a847583 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/88pm860x.txt @@ -0,0 +1,85 @@ +* Marvell 88PM860x Power Management IC + +Required parent device properties: +- compatible : "marvell,88pm860x" +- reg : the I2C slave address for the 88pm860x chip +- interrupts : IRQ line for the 88pm860x chip +- interrupt-controller: describes the 88pm860x as an interrupt controller (has its own domain) +- #interrupt-cells : should be 1. + - The cell is the 88pm860x local IRQ number + +Optional parent device properties: +- marvell,88pm860x-irq-read-clr: inicates whether interrupt status is cleared by read +- marvell,88pm860x-slave-addr: 88pm860x are two chips solution. stores the I2C address + of one chip, and this property stores the I2C address of + another chip. + +88pm860x consists of a large and varied group of sub-devices: + +Device Supply Names Description +------ ------------ ----------- +88pm860x-onkey : : On key +88pm860x-rtc : : RTC +88pm8607 : : Regulators +88pm860x-backlight : : Backlight +88pm860x-led : : Led +88pm860x-touch : : Touchscreen + +Example: + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + interrupts = <4>; + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <1>; + + marvell,88pm860x-irq-read-clr; + marvell,88pm860x-slave-addr = <0x11>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + LDO1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + rtc { + marvell,88pm860x-vrtc = <1>; + }; + touch { + marvell,88pm860x-gpadc-prebias = <1>; + marvell,88pm860x-gpadc-slot-cycle = <1>; + marvell,88pm860x-tsi-prebias = <6>; + marvell,88pm860x-pen-prebias = <16>; + marvell,88pm860x-pen-prechg = <2>; + marvell,88pm860x-resistor-X = <300>; + }; + backlights { + backlight-0 { + marvell,88pm860x-iset = <4>; + marvell,88pm860x-pwm = <3>; + }; + backlight-2 { + }; + }; + leds { + led0-red { + marvell,88pm860x-iset = <12>; + }; + led0-green { + marvell,88pm860x-iset = <12>; + }; + led0-blue { + marvell,88pm860x-iset = <12>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/ab8500.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/ab8500.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd9e90c5d1715b495d03448d35235dddb0b6d051 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/ab8500.txt @@ -0,0 +1,159 @@ +* AB8500 Multi-Functional Device (MFD) + +Required parent device properties: +- compatible : contains "stericsson,ab8500"; +- interrupts : contains the IRQ line for the AB8500 +- interrupt-controller : describes the AB8500 as an Interrupt Controller (has its own domain) +- #interrupt-cells : should be 2, for 2-cell format + - The first cell is the AB8500 local IRQ number + - The second cell is used to specify optional parameters + - bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + +The AB8500 consists of a large and varied group of sub-devices: + +Device IRQ Names Supply Names Description +------ --------- ------------ ----------- +ab8500-bm : : : Battery Manager +ab8500-btemp : : : Battery Temperature +ab8500-charger : : : Battery Charger +ab8500-codec : : : Audio Codec +ab8500-fg : : vddadc : Fuel Gauge + : NCONV_ACCU : : Accumulate N Sample Conversion + : BATT_OVV : : Battery Over Voltage + : LOW_BAT_F : : LOW threshold battery voltage + : CC_INT_CALIB : : Coulomb Counter Internal Calibration + : CCEOC : : Coulomb Counter End of Conversion +ab8500-btemp : : vtvout : Battery Temperature + : BAT_CTRL_INDB : : Battery Removal Indicator + : BTEMP_LOW : : Btemp < BtempLow, if battery temperature is lower than -10°C + : BTEMP_LOW_MEDIUM : : BtempLow < Btemp < BtempMedium,if battery temperature is between -10 and 0°C + : BTEMP_MEDIUM_HIGH : : BtempMedium < Btemp < BtempHigh,if battery temperature is between 0°C and“MaxTemp + : BTEMP_HIGH : : Btemp > BtempHigh, if battery temperature is higher than “MaxTemp +ab8500-charger : : vddadc : Charger interface + : MAIN_CH_UNPLUG_DET : : main charger unplug detection management (not in 8505) + : MAIN_CHARGE_PLUG_DET : : main charger plug detection management (not in 8505) + : MAIN_EXT_CH_NOT_OK : : main charger not OK + : MAIN_CH_TH_PROT_R : : Die temp is above main charger + : MAIN_CH_TH_PROT_F : : Die temp is below main charger + : VBUS_DET_F : : VBUS falling detected + : VBUS_DET_R : : VBUS rising detected + : USB_LINK_STATUS : : USB link status has changed + : USB_CH_TH_PROT_R : : Die temp is above usb charger + : USB_CH_TH_PROT_F : : Die temp is below usb charger + : USB_CHARGER_NOT_OKR : : allowed USB charger not ok detection + : VBUS_OVV : : Overvoltage on Vbus ball detected (USB charge is stopped) + : CH_WD_EXP : : Charger watchdog detected +ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter + SW_CONV_END : : +ab8500-gpio : : : GPIO Controller +ab8500-ponkey : ONKEY_DBF : : Power-on Key + ONKEY_DBR : : +ab8500-pwm : : : Pulse Width Modulator +ab8500-regulator : : : Regulators +ab8500-rtc : 60S : : Real Time Clock + : ALARM : : +ab8500-sysctrl : : : System Control +ab8500-usb : ID_WAKEUP_R : vddulpivio18 : Universal Serial Bus + : ID_WAKEUP_F : v-ape : + : VBUS_DET_F : musb_1v8 : + : VBUS_DET_R : : + : USB_LINK_STATUS : : + : USB_ADP_PROBE_PLUG : : + : USB_ADP_PROBE_UNPLUG : : + +Required child device properties: +- compatible : "stericsson,ab8500-[bm|btemp|charger|fg|gpadc|gpio|ponkey| + pwm|regulator|rtc|sysctrl|usb]"; + +Optional child device properties: +- interrupts : contains the device IRQ(s) using the 2-cell format (see above) +- interrupt-names : contains names of IRQ resource in the order in which they were + supplied in the interrupts property +- -supply : contains a phandle to the regulator supply node in Device Tree + +Non-standard child device properties: + - Audio CODEC: + - stericsson,amic[1|2]-type-single-ended : Single-ended Analoge Mic (default: differential) + - stericsson,amic1a-bias-vamic2 : Analoge Mic wishes to use a non-standard Vamic + - stericsson,amic1b-bias-vamic2 : Analoge Mic wishes to use a non-standard Vamic + - stericsson,amic2-bias-vamic1 : Analoge Mic wishes to use a non-standard Vamic + - stericsson,earpeice-cmv : Earpeice voltage (only: 950 | 1100 | 1270 | 1580) + +ab8500 { + compatible = "stericsson,ab8500"; + interrupts = <0 40 0x4>; + interrupt-controller; + #interrupt-cells = <2>; + + ab8500-rtc { + compatible = "stericsson,ab8500-rtc"; + interrupts = <17 0x4 + 18 0x4>; + interrupt-names = "60S", "ALARM"; + }; + + ab8500-gpadc { + compatible = "stericsson,ab8500-gpadc"; + interrupts = <32 0x4 + 39 0x4>; + interrupt-names = "HW_CONV_END", "SW_CONV_END"; + vddadc-supply = <&ab8500_ldo_tvout_reg>; + }; + + ab8500-usb { + compatible = "stericsson,ab8500-usb"; + interrupts = < 90 0x4 + 96 0x4 + 14 0x4 + 15 0x4 + 79 0x4 + 74 0x4 + 75 0x4>; + interrupt-names = "ID_WAKEUP_R", + "ID_WAKEUP_F", + "VBUS_DET_F", + "VBUS_DET_R", + "USB_LINK_STATUS", + "USB_ADP_PROBE_PLUG", + "USB_ADP_PROBE_UNPLUG"; + vddulpivio18-supply = <&ab8500_ldo_intcore_reg>; + v-ape-supply = <&db8500_vape_reg>; + musb_1v8-supply = <&db8500_vsmps2_reg>; + }; + + ab8500-ponkey { + compatible = "stericsson,ab8500-ponkey"; + interrupts = <6 0x4 + 7 0x4>; + interrupt-names = "ONKEY_DBF", "ONKEY_DBR"; + }; + + ab8500-sysctrl { + compatible = "stericsson,ab8500-sysctrl"; + }; + + ab8500-pwm { + compatible = "stericsson,ab8500-pwm"; + }; + + codec: ab8500-codec { + compatible = "stericsson,ab8500-codec"; + + stericsson,earpeice-cmv = <950>; /* Units in mV. */ + }; + + ab8500-regulators { + compatible = "stericsson,ab8500-regulator"; + + ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { + /* + * See: Documentation/devicetree/bindings/regulator/regulator.txt + * for more information on regulators + */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/ac100.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/ac100.txt new file mode 100644 index 0000000000000000000000000000000000000000..dff219f074931bdcce6bbac66853680b72fddbde --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/ac100.txt @@ -0,0 +1,50 @@ +X-Powers AC100 Codec/RTC IC Device Tree bindings + +AC100 is a audio codec and RTC subsystem combo IC. The 2 parts are +separated, including power supplies and interrupt lines, but share +a common register address space and host interface. + +Required properties: +- compatible: "x-powers,ac100" +- reg: The I2C slave address or RSB hardware address for the chip +- sub-nodes: + - codec + - compatible: "x-powers,ac100-codec" + - interrupts: SoC NMI / GPIO interrupt connected to the + IRQ_AUDIO pin + - #clock-cells: Shall be 0 + - clock-output-names: "4M_adda" + + - see clock/clock-bindings.txt for common clock bindings + + - rtc + - compatible: "x-powers,ac100-rtc" + - clocks: A phandle to the codec's "4M_adda" clock + - #clock-cells: Shall be 1 + - clock-output-names: "cko1_rtc", "cko2_rtc", "cko3_rtc" + + - see clock/clock-bindings.txt for common clock bindings + +Example: + +ac100: codec@e89 { + compatible = "x-powers,ac100"; + reg = <0xe89>; + + ac100_codec: codec { + compatible = "x-powers,ac100-codec"; + interrupt-parent = <&r_pio>; + interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */ + #clock-cells = <0>; + clock-output-names = "4M_adda"; + }; + + ac100_rtc: rtc { + compatible = "x-powers,ac100-rtc"; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + clocks = <&ac100_codec>; + #clock-cells = <1>; + clock-output-names = "cko1_rtc", "cko2_rtc", "cko3_rtc"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/act8945a.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/act8945a.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6f168db6c723e018dc50389c5405dac614d1f0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/act8945a.txt @@ -0,0 +1,82 @@ +Device-Tree bindings for Active-semi ACT8945A MFD driver + +Required properties: + - compatible: "active-semi,act8945a". + - reg: the I2C slave address for the ACT8945A chip + +The chip exposes two subdevices: + - a regulators: see ../regulator/act8945a-regulator.txt + - a charger: see ../power/act8945a-charger.txt + +Example: + pmic@5b { + compatible = "active-semi,act8945a"; + reg = <0x5b>; + + active-semi,vsel-high; + + regulators { + vdd_1v35_reg: REG_DCDC1 { + regulator-name = "VDD_1V35"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + vdd_1v2_reg: REG_DCDC2 { + regulator-name = "VDD_1V2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + + vdd_3v3_reg: REG_DCDC3 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_fuse_reg: REG_LDO1 { + regulator-name = "VDD_FUSE"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vdd_3v3_lp_reg: REG_LDO2 { + regulator-name = "VDD_3V3_LP"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_led_reg: REG_LDO3 { + regulator-name = "VDD_LED"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_sdhc_1v8_reg: REG_LDO4 { + regulator-name = "VDD_SDHC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + }; + + charger { + compatible = "active-semi,act8945a-charger"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>; + interrupt-parent = <&pioA>; + interrupts = <45 GPIO_ACTIVE_LOW>; + + active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>; + active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>; + active-semi,input-voltage-threshold-microvolt = <6600>; + active-semi,precondition-timeout = <40>; + active-semi,total-timeout = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/altera-a10sr.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/altera-a10sr.txt new file mode 100644 index 0000000000000000000000000000000000000000..a688520dd87d28de3fd0c31eddf53ce185531d11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/altera-a10sr.txt @@ -0,0 +1,56 @@ +* Altera Arria10 Development Kit System Resource Chip + +Required parent device properties: +- compatible : "altr,a10sr" +- spi-max-frequency : Maximum SPI frequency. +- reg : The SPI Chip Select address for the Arria10 + System Resource chip +- interrupts : The interrupt line the device is connected to. +- interrupt-controller : Marks the device node as an interrupt controller. +- #interrupt-cells : The number of cells to describe an IRQ, should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as trigger + masks from ../interrupt-controller/interrupts.txt. + +The A10SR consists of these sub-devices: + +Device Description +------ ---------- +a10sr_gpio GPIO Controller +a10sr_rst Reset Controller + +Arria10 GPIO +Required Properties: +- compatible : Should be "altr,a10sr-gpio" +- gpio-controller : Marks the device node as a GPIO Controller. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + +Arria10 Peripheral PHY Reset +Required Properties: +- compatible : Should be "altr,a10sr-reset" +- #reset-cells : Should be one. + +Example: + + resource-manager@0 { + compatible = "altr,a10sr"; + reg = <0>; + spi-max-frequency = <100000>; + interrupt-parent = <&portb>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + a10sr_gpio: gpio-controller { + compatible = "altr,a10sr-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + a10sr_rst: reset-controller { + compatible = "altr,a10sr-reset"; + #reset-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/arizona.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/arizona.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b62831fdf3eb8f2de11d5a14878241382f21194 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/arizona.txt @@ -0,0 +1,101 @@ +Cirrus Logic/Wolfson Microelectronics Arizona class audio SoCs + +These devices are audio SoCs with extensive digital capabilities and a range +of analogue I/O. + +Required properties: + + - compatible : One of the following chip-specific strings: + "cirrus,cs47l24" + "wlf,wm5102" + "wlf,wm5110" + "wlf,wm8280" + "wlf,wm8997" + "wlf,wm8998" + "wlf,wm1814" + "wlf,wm1831" + + - reg : I2C slave address when connected using I2C, chip select number when + using SPI. + + - interrupts : The interrupt line the /IRQ signal for the device is + connected to. + - interrupt-controller : Arizona class devices contain interrupt controllers + and may provide interrupt services to other devices. + - #interrupt-cells: the number of cells to describe an IRQ, this should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as the trigger masks from + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + + - gpio-controller : Indicates this device is a GPIO controller. + - #gpio-cells : Must be 2. The first cell is the pin number and the + second cell is used to specify optional parameters, see ../gpio/gpio.txt + for details. + + - AVDD-supply, DBVDD1-supply, CPVDD-supply : Power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt + + - DBVDD2-supply, DBVDD3-supply : Additional databus power supplies (wm5102, + wm5110, wm8280, wm8998, wm1814) + + - SPKVDDL-supply, SPKVDDR-supply : Speaker driver power supplies (wm5102, + wm5110, wm8280, wm8998, wm1814) + + - SPKVDD-supply : Speaker driver power supply (wm8997) + + - DCVDD-supply : Main power supply (cs47l24, wm1831) + + - MICVDD-supply : Microphone power supply (cs47l24, wm1831) + +Optional properties: + + - reset-gpios : GPIO specifier for the GPIO controlling /RESET + + - clocks: Should reference the clocks supplied on MCLK1 and MCLK2 + - clock-names: Should contains two strings: + "mclk1" for the clock supplied on MCLK1, recommended to be a high + quality audio reference clock + "mclk2" for the clock supplied on MCLK2, recommended to be an always on + 32k clock + + - wlf,gpio-defaults : A list of GPIO configuration register values. Defines + for the appropriate values can found in . If + absent, no configuration of these registers is performed. If any entry has + a value that is out of range for a 16 bit register then the chip default + will be used. If present exactly five values must be specified. + + - DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if + they are being externally supplied. As covered in + Documentation/devicetree/bindings/regulator/regulator.txt + (wm5102, wm5110, wm8280, wm8997, wm8998, wm1814) + +Deprecated properties: + + - wlf,reset : GPIO specifier for the GPIO controlling /RESET + +Also see child specific device properties: + Regulator - ../regulator/arizona-regulator.txt + Extcon - ../extcon/extcon-arizona.txt + Sound - ../sound/arizona.txt + +Example: + +codec: wm5102@1a { + compatible = "wlf,wm5102"; + reg = <0x1a>; + interrupts = <347>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + + gpio-controller; + #gpio-cells = <2>; + + wlf,gpio-defaults = < + ARIZONA_GP_FN_TXLRCLK + ARIZONA_GP_DEFAULT + ARIZONA_GP_DEFAULT + ARIZONA_GP_DEFAULT + ARIZONA_GP_DEFAULT + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/as3711.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/as3711.txt new file mode 100644 index 0000000000000000000000000000000000000000..d98cf18c721ceb18ce35016626ee817805d0158f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/as3711.txt @@ -0,0 +1,73 @@ +AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power +supplies, a battery charger and an RTC. So far only bindings for the two stepup +DCDC converters are defined. Other DCDC and LDO supplies are configured, using +standard regulator properties, they must belong to a sub-node, called +"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter +configuration should be placed in a subnode, called "backlight." + +Compulsory properties: +- compatible : must be "ams,as3711" +- reg : specifies the I2C address + +To use the SU1 converter as a backlight source the following two properties must +be provided: +- su1-dev : framebuffer phandle +- su1-max-uA : maximum current + +To use the SU2 converter as a backlight source the following two properties must +be provided: +- su2-dev : framebuffer phandle +- su1-max-uA : maximum current + +Additionally one of these properties must be provided to select the type of +feedback used: +- su2-feedback-voltage : voltage feedback is used +- su2-feedback-curr1 : CURR1 input used for current feedback +- su2-feedback-curr2 : CURR2 input used for current feedback +- su2-feedback-curr3 : CURR3 input used for current feedback +- su2-feedback-curr-auto: automatic current feedback selection + +and one of these to select the over-voltage protection pin +- su2-fbprot-lx-sd4 : LX_SD4 is used for over-voltage protection +- su2-fbprot-gpio2 : GPIO2 is used for over-voltage protection +- su2-fbprot-gpio3 : GPIO3 is used for over-voltage protection +- su2-fbprot-gpio4 : GPIO4 is used for over-voltage protection + +If "su2-feedback-curr-auto" is selected, one or more of the following properties +have to be specified: +- su2-auto-curr1 : use CURR1 input for current feedback +- su2-auto-curr2 : use CURR2 input for current feedback +- su2-auto-curr3 : use CURR3 input for current feedback + +Example: + +as3711@40 { + compatible = "ams,as3711"; + reg = <0x40>; + + regulators { + sd4 { + regulator-name = "1.215V"; + regulator-min-microvolt = <1215000>; + regulator-max-microvolt = <1235000>; + }; + ldo2 { + regulator-name = "2.8V CPU"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + }; + + backlight { + compatible = "ams,as3711-bl"; + su2-dev = <&lcdc>; + su2-max-uA = <36000>; + su2-feedback-curr-auto; + su2-fbprot-gpio4; + su2-auto-curr1; + su2-auto-curr2; + su2-auto-curr3; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/as3722.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/as3722.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a665741d7fe20e8089feb38767066d9bda7b0fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/as3722.txt @@ -0,0 +1,214 @@ +* ams AS3722 Power management IC. + +Required properties: +------------------- +- compatible: Must be "ams,as3722". +- reg: I2C device address. +- interrupt-controller: AS3722 has internal interrupt controller which takes the + interrupt request from internal sub-blocks like RTC, regulators, GPIOs as well + as external input. +- #interrupt-cells: Should be set to 2 for IRQ number and flags. + The first cell is the IRQ number. IRQ numbers for different interrupt source + of AS3722 are defined at dt-bindings/mfd/as3722.h + The second cell is the flags, encoded as the trigger masks from binding document + interrupts.txt, using dt-bindings/irq. + +Optional properties: +-------------------- +- ams,enable-internal-int-pullup: Boolean property, to enable internal pullup on + interrupt pin. Missing this will disable internal pullup on INT pin. +- ams,enable-internal-i2c-pullup: Boolean property, to enable internal pullup on + i2c scl/sda pins. Missing this will disable internal pullup on i2c + scl/sda lines. +- ams,enable-ac-ok-power-on: Boolean property, to enable exit out of power off + mode with AC_OK pin (pin enabled in power off mode). + +Optional submodule and their properties: +======================================= + +Pinmux and GPIO: +=============== +Device has 8 GPIO pins which can be configured as GPIO as well as the special IO +functions. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Following are properties which is needed if GPIO and pinmux functionality +is required: + Required properties: + ------------------- + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Number of GPIO cells. Refer to binding document + gpio/gpio.txt + + Optional properties: + -------------------- + Following properties are require if pin control setting is required + at boot. + - pinctrl-names: A pinctrl state named "default" be defined, using the + bindings in pinctrl/pinctrl-bindings.txt. + - pinctrl[0...n]: Properties to contain the phandle that refer to + different nodes of pin control settings. These nodes represents + the pin control setting of state 0 to state n. Each of these + nodes contains different subnodes to represents some desired + configuration for a list of pins. This configuration can + include the mux function to select on those pin(s), and + various pin configuration parameters, such as pull-up, + open drain. + + Each subnode have following properties: + Required properties: + - pins: List of pins. Valid values of pins properties are: + gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, + gpio6, gpio7 + + Optional properties: + function, bias-disable, bias-pull-up, bias-pull-down, + bias-high-impedance, drive-open-drain. + + Valid values for function properties are: + gpio, interrupt-out, gpio-in-interrupt, + vsup-vbat-low-undebounce-out, + vsup-vbat-low-debounce-out, + voltage-in-standby, oc-pg-sd0, oc-pg-sd6, + powergood-out, pwm-in, pwm-out, clk32k-out, + watchdog-in, soft-reset-in + +Regulators: +=========== +Device has multiple DCDC and LDOs. The node "regulators" is require if regulator +functionality is needed. + +Following are properties of regulator subnode. + + Optional properties: + ------------------- + The input supply of regulators are the optional properties on the + regulator node. The input supply of these regulators are provided + through following properties: + vsup-sd2-supply: Input supply for SD2. + vsup-sd3-supply: Input supply for SD3. + vsup-sd4-supply: Input supply for SD4. + vsup-sd5-supply: Input supply for SD5. + vin-ldo0-supply: Input supply for LDO0. + vin-ldo1-6-supply: Input supply for LDO1 and LDO6. + vin-ldo2-5-7-supply: Input supply for LDO2, LDO5 and LDO7. + vin-ldo3-4-supply: Input supply for LDO3 and LDO4. + vin-ldo9-10-supply: Input supply for LDO9 and LDO10. + vin-ldo11-supply: Input supply for LDO11. + + Optional sub nodes for regulators: + --------------------------------- + The subnodes name is the name of regulator and it must be one of: + sd[0-6], ldo[0-7], ldo[9-11] + + Each sub-node should contain the constraints and initialization + information for that regulator. See regulator.txt for a description + of standard properties for these sub-nodes. + Additional optional custom properties are listed below. + ams,ext-control: External control of the rail. The option of + this properties will tell which external input is + controlling this rail. Valid values are 0, 1, 2 ad 3. + 0: There is no external control of this rail. + 1: Rail is controlled by ENABLE1 input pin. + 2: Rail is controlled by ENABLE2 input pin. + 3: Rail is controlled by ENABLE3 input pin. + Missing this property on DT will be assume as no + external control. The external control pin macros + are defined @dt-bindings/mfd/as3722.h + + ams,enable-tracking: Enable tracking with SD1, only supported + by LDO3. + +Power-off: +========= +AS3722 supports the system power off by turning off all its rails. +The device node should have the following properties to enable this +functionality +ams,system-power-controller: Boolean, to enable the power off functionality + through this device. + +Example: +-------- +#include +... +ams3722 { + compatible = "ams,as3722"; + reg = <0x48>; + + ams,system-power-controller; + + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <2>; + + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&as3722_default>; + + as3722_default: pinmux { + gpio0 { + pins = "gpio0"; + function = "gpio"; + bias-pull-down; + }; + + gpio1_2_4_7 { + pins = "gpio1", "gpio2", "gpio4", "gpio7"; + function = "gpio"; + bias-pull-up; + }; + + gpio5 { + pins = "gpio5"; + function = "clk32k_out"; + }; + } + + regulators { + vsup-sd2-supply = <...>; + ... + + sd0 { + regulator-name = "vdd_cpu"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + ams,ext-control = <2>; + }; + + sd1 { + regulator-name = "vdd_core"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + ams,ext-control = <1>; + }; + + sd2 { + regulator-name = "vddio_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + sd4 { + regulator-name = "avdd-hdmi-pex"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + }; + + sd5 { + regulator-name = "vdd-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + .... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-gfx.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-gfx.txt new file mode 100644 index 0000000000000000000000000000000000000000..aea5370efd970a7420aa3097729c7bd6a49bc5a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-gfx.txt @@ -0,0 +1,17 @@ +* Device tree bindings for Aspeed SoC Display Controller (GFX) + +The Aspeed SoC Display Controller primarily does as its name suggests, but also +participates in pinmux requests on the g5 SoCs. It is therefore considered a +syscon device. + +Required properties: +- compatible: "aspeed,ast2500-gfx", "syscon" +- reg: contains offset/length value of the GFX memory + region. + +Example: + +gfx: display@1e6e6000 { + compatible = "aspeed,ast2500-gfx", "syscon"; + reg = <0x1e6e6000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-lpc.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-lpc.txt new file mode 100644 index 0000000000000000000000000000000000000000..34dd89087cff09d0fdd26ebe1cc4fbf9c7c43928 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-lpc.txt @@ -0,0 +1,199 @@ +====================================================================== +Device tree bindings for the Aspeed Low Pin Count (LPC) Bus Controller +====================================================================== + +The LPC bus is a means to bridge a host CPU to a number of low-bandwidth +peripheral devices, replacing the use of the ISA bus in the age of PCI[0]. The +primary use case of the Aspeed LPC controller is as a slave on the bus +(typically in a Baseboard Management Controller SoC), but under certain +conditions it can also take the role of bus master. + +The LPC controller is represented as a multi-function device to account for the +mix of functionality it provides. The principle split is between the register +layout at the start of the I/O space which is, to quote the Aspeed datasheet, +"basically compatible with the [LPC registers from the] popular BMC controller +H8S/2168[1]", and everything else, where everything else is an eclectic +collection of functions with a esoteric register layout. "Everything else", +here labeled the "host" portion of the controller, includes, but is not limited +to: + +* An IPMI Block Transfer[2] Controller + +* An LPC Host Controller: Manages LPC functions such as host vs slave mode, the + physical properties of some LPC pins, configuration of serial IRQs, and + APB-to-LPC bridging amonst other functions. + +* An LPC Host Interface Controller: Manages functions exposed to the host such + as LPC firmware hub cycles, configuration of the LPC-to-AHB mapping, UART + management and bus snoop configuration. + +* A set of SuperIO[3] scratch registers: Enables implementation of e.g. custom + hardware management protocols for handover between the host and baseboard + management controller. + +Additionally the state of the LPC controller influences the pinmux +configuration, therefore the host portion of the controller is exposed as a +syscon as a means to arbitrate access. + +[0] http://www.intel.com/design/chipsets/industry/25128901.pdf +[1] https://www.renesas.com/en-sg/doc/products/mpumcu/001/rej09b0078_h8s2168.pdf?key=7c88837454702128622bee53acbda8f4 +[2] http://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmi-second-gen-interface-spec-v2-rev1-1.pdf +[3] https://en.wikipedia.org/wiki/Super_I/O + +Required properties +=================== + +- compatible: One of: + "aspeed,ast2400-lpc", "simple-mfd" + "aspeed,ast2500-lpc", "simple-mfd" + +- reg: contains the physical address and length values of the Aspeed + LPC memory region. + +- #address-cells: <1> +- #size-cells: <1> +- ranges: Maps 0 to the physical address and length of the LPC memory + region + +Required LPC Child nodes +======================== + +BMC Node +-------- + +- compatible: One of: + "aspeed,ast2400-lpc-bmc" + "aspeed,ast2500-lpc-bmc" + +- reg: contains the physical address and length values of the + H8S/2168-compatible LPC controller memory region + +Host Node +--------- + +- compatible: One of: + "aspeed,ast2400-lpc-host", "simple-mfd", "syscon" + "aspeed,ast2500-lpc-host", "simple-mfd", "syscon" + +- reg: contains the address and length values of the host-related + register space for the Aspeed LPC controller + +- #address-cells: <1> +- #size-cells: <1> +- ranges: Maps 0 to the address and length of the host-related LPC memory + region + +Example: + +lpc: lpc@1e789000 { + compatible = "aspeed,ast2500-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1e789000 0x1000>; + + lpc_bmc: lpc-bmc@0 { + compatible = "aspeed,ast2500-lpc-bmc"; + reg = <0x0 0x80>; + }; + + lpc_host: lpc-host@80 { + compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon"; + reg = <0x80 0x1e0>; + reg-io-width = <4>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x80 0x1e0>; + }; +}; + +BMC Node Children +================== + + +Host Node Children +================== + +LPC Host Interface Controller +------------------- + +The LPC Host Interface Controller manages functions exposed to the host such as +LPC firmware hub cycles, configuration of the LPC-to-AHB mapping, UART +management and bus snoop configuration. + +Required properties: + +- compatible: One of: + "aspeed,ast2400-lpc-ctrl"; + "aspeed,ast2500-lpc-ctrl"; + +- reg: contains offset/length values of the host interface controller + memory regions + +- clocks: contains a phandle to the syscon node describing the clocks. + There should then be one cell representing the clock to use + +- memory-region: A phandle to a reserved_memory region to be used for the LPC + to AHB mapping + +- flash: A phandle to the SPI flash controller containing the flash to + be exposed over the LPC to AHB mapping + +Example: + +lpc-host@80 { + lpc_ctrl: lpc-ctrl@0 { + compatible = "aspeed,ast2500-lpc-ctrl"; + reg = <0x0 0x80>; + clocks = <&syscon ASPEED_CLK_GATE_LCLK>; + memory-region = <&flash_memory>; + flash = <&spi>; + }; +}; + +LPC Host Controller +------------------- + +The Aspeed LPC Host Controller configures the Low Pin Count (LPC) bus behaviour +between the host and the baseboard management controller. The registers exist +in the "host" portion of the Aspeed LPC controller, which must be the parent of +the LPC host controller node. + +Required properties: + +- compatible: One of: + "aspeed,ast2400-lhc"; + "aspeed,ast2500-lhc"; + +- reg: contains offset/length values of the LHC memory regions. In the + AST2400 and AST2500 there are two regions. + +Example: + +lhc: lhc@20 { + compatible = "aspeed,ast2500-lhc"; + reg = <0x20 0x24 0x48 0x8>; +}; + +LPC reset control +----------------- + +The UARTs present in the ASPEED SoC can have their resets tied to the reset +state of the LPC bus. Some systems may chose to modify this configuration. + +Required properties: + + - compatible: "aspeed,ast2500-lpc-reset" or + "aspeed,ast2400-lpc-reset" + - reg: offset and length of the IP in the LHC memory region + - #reset-controller indicates the number of reset cells expected + +Example: + +lpc_reset: reset-controller@18 { + compatible = "aspeed,ast2500-lpc-reset"; + reg = <0x18 0x4>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-scu.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-scu.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce8cf0ec6279a5ccc8aece96e4c85cc2aab46776 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/aspeed-scu.txt @@ -0,0 +1,24 @@ +The Aspeed System Control Unit manages the global behaviour of the SoC, +configuring elements such as clocks, pinmux, and reset. + +Required properties: +- compatible: One of: + "aspeed,ast2400-scu", "syscon", "simple-mfd" + "aspeed,g4-scu", "syscon", "simple-mfd" + "aspeed,ast2500-scu", "syscon", "simple-mfd" + "aspeed,g5-scu", "syscon", "simple-mfd" + +- reg: contains the offset and length of the SCU memory region +- #clock-cells: should be set to <1> - the system controller is also a + clock provider +- #reset-cells: should be set to <1> - the system controller is also a + reset line provider + +Example: + +syscon: syscon@1e6e2000 { + compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd"; + reg = <0x1e6e2000 0x1a8>; + #clock-cells = <1>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-flexcom.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-flexcom.txt new file mode 100644 index 0000000000000000000000000000000000000000..692300117c647c2a78abd3da8140e62d1d08c897 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-flexcom.txt @@ -0,0 +1,63 @@ +* Device tree bindings for Atmel Flexcom (Flexible Serial Communication Unit) + +The Atmel Flexcom is just a wrapper which embeds a SPI controller, an I2C +controller and an USART. Only one function can be used at a time and is chosen +at boot time according to the device tree. + +Required properties: +- compatible: Should be "atmel,sama5d2-flexcom" +- reg: Should be the offset/length value for Flexcom dedicated + I/O registers (without USART, TWI or SPI registers). +- clocks: Should be the Flexcom peripheral clock from PMC. +- #address-cells: Should be <1> +- #size-cells: Should be <1> +- ranges: Should be one range for the full I/O register region + (including USART, TWI and SPI registers). +- atmel,flexcom-mode: Should be one of the following values: + - <1> for USART + - <2> for SPI + - <3> for I2C + +Required child: +A single available child device of type matching the "atmel,flexcom-mode" +property. + +The phandle provided by the clocks property of the child is the same as one for +the Flexcom parent. + +For other properties, please refer to the documentations of the respective +device: +- ../serial/atmel-usart.txt +- ../spi/spi_atmel.txt +- ../i2c/i2c-at91.txt + +Example: + +flexcom@f8034000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xf8034000 0x200>; + clocks = <&flx0_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xf8034000 0x800>; + atmel,flexcom-mode = <2>; + + spi@400 { + compatible = "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx0_default>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx0_clk>; + clock-names = "spi_clk"; + atmel,fifo-size = <32>; + + mtd_dataflash@0 { + compatible = "atmel,at25f512b"; + reg = <0>; + spi-max-frequency = <20000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-gpbr.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-gpbr.txt new file mode 100644 index 0000000000000000000000000000000000000000..a28569540683e13958d68a1c36c6f1d2ec28994e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-gpbr.txt @@ -0,0 +1,15 @@ +* Device tree bindings for Atmel GPBR (General Purpose Backup Registers) + +The GPBR are a set of battery-backed registers. + +Required properties: +- compatible: "atmel,at91sam9260-gpbr", "syscon" +- reg: contains offset/length value of the GPBR memory + region. + +Example: + +gpbr: gpbr@fffffd50 { + compatible = "atmel,at91sam9260-gpbr", "syscon"; + reg = <0xfffffd50 0x10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-hlcdc.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-hlcdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f643ef121ff51ade6dd0205d5d3ec770cebf6f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-hlcdc.txt @@ -0,0 +1,54 @@ +Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver + +Required properties: + - compatible: value should be one of the following: + "atmel,at91sam9n12-hlcdc" + "atmel,at91sam9x5-hlcdc" + "atmel,sama5d2-hlcdc" + "atmel,sama5d3-hlcdc" + "atmel,sama5d4-hlcdc" + - reg: base address and size of the HLCDC device registers. + - clock-names: the name of the 3 clocks requested by the HLCDC device. + Should contain "periph_clk", "sys_clk" and "slow_clk". + - clocks: should contain the 3 clocks requested by the HLCDC device. + - interrupts: should contain the description of the HLCDC interrupt line + +The HLCDC IP exposes two subdevices: + - a PWM chip: see ../pwm/atmel-hlcdc-pwm.txt + - a Display Controller: see ../display/atmel/hlcdc-dc.txt + +Example: + + hlcdc: hlcdc@f0030000 { + compatible = "atmel,sama5d3-hlcdc"; + reg = <0xf0030000 0x2000>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; + + hlcdc-display-controller { + compatible = "atmel,hlcdc-display-controller"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-matrix.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-matrix.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3ef50ca02a5e4f1f81ff57c1e46ea78118e9528 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-matrix.txt @@ -0,0 +1,24 @@ +* Device tree bindings for Atmel Bus Matrix + +The Bus Matrix registers are used to configure Atmel SoCs internal bus +behavior (master/slave priorities, undefined burst length type, ...) + +Required properties: +- compatible: Should be one of the following + "atmel,at91sam9260-matrix", "syscon" + "atmel,at91sam9261-matrix", "syscon" + "atmel,at91sam9263-matrix", "syscon" + "atmel,at91sam9rl-matrix", "syscon" + "atmel,at91sam9g45-matrix", "syscon" + "atmel,at91sam9n12-matrix", "syscon" + "atmel,at91sam9x5-matrix", "syscon" + "atmel,sama5d3-matrix", "syscon" +- reg: Contains offset/length value of the Bus Matrix + memory region. + +Example: + +matrix: matrix@ffffec00 { + compatible = "atmel,sama5d3-matrix", "syscon"; + reg = <0xffffec00 0x200>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-smc.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-smc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1103ce2030fbbcda2a303340cc1344326201e76a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-smc.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Atmel SMC (Static Memory Controller) + +The SMC registers are used to configure Atmel EBI (External Bus Interface) +to interface with standard memory devices (NAND, NOR, SRAM or specialized +devices like FPGAs). + +Required properties: +- compatible: Should be one of the following + "atmel,at91sam9260-smc", "syscon" + "atmel,sama5d3-smc", "syscon" + "atmel,sama5d2-smc", "syscon" +- reg: Contains offset/length value of the SMC memory + region. + +Example: + +smc: smc@ffffc000 { + compatible = "atmel,sama5d3-smc", "syscon"; + reg = <0xffffc000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-tcb.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-tcb.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4a83e364cb66ce32c285f9067d216d2d8011ec9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/atmel-tcb.txt @@ -0,0 +1,56 @@ +* Device tree bindings for Atmel Timer Counter Blocks +- compatible: Should be "atmel,-tcb", "simple-mfd", "syscon". + can be "at91rm9200" or "at91sam9x5" +- reg: Should contain registers location and length +- #address-cells: has to be 1 +- #size-cells: has to be 0 +- interrupts: Should contain all interrupts for the TC block + Note that you can specify several interrupt cells if the TC + block has one interrupt per channel. +- clock-names: tuple listing input clock names. + Required elements: "t0_clk", "slow_clk" + Optional elements: "t1_clk", "t2_clk" +- clocks: phandles to input clocks. + +The TCB can expose multiple subdevices: + * a timer + - compatible: Should be "atmel,tcb-timer" + - reg: Should contain the TCB channels to be used. If the + counter width is 16 bits (at91rm9200-tcb), two consecutive + channels are needed. Else, only one channel will be used. + +Examples: + +One interrupt per TC block: + tcb0: timer@fff7c000 { + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfff7c000 0x100>; + interrupts = <18 4>; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; + + timer@0 { + compatible = "atmel,tcb-timer"; + reg = <0>, <1>; + }; + + timer@2 { + compatible = "atmel,tcb-timer"; + reg = <2>; + }; + }; + +One interrupt per TC channel in a TC block: + tcb1: timer@fffdc000 { + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xfffdc000 0x100>; + interrupts = <26 4>, <27 4>, <28 4>; + clocks = <&tcb1_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/axp20x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/axp20x.txt new file mode 100644 index 0000000000000000000000000000000000000000..188f0373d441bcad97a78943d6d551601b89c4cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/axp20x.txt @@ -0,0 +1,262 @@ +AXP family PMIC device tree bindings + +The axp20x family current members : +axp152 (X-Powers) +axp202 (X-Powers) +axp209 (X-Powers) +axp221 (X-Powers) +axp223 (X-Powers) +axp803 (X-Powers) +axp806 (X-Powers) +axp809 (X-Powers) +axp813 (X-Powers) + +The AXP813 is 2 chips packaged into 1. The 2 chips do not share anything +other than the packaging. Pins are routed separately. As such they should +be treated as separate entities. The other half is an AC100 RTC/codec +combo chip. Please see ./ac100.txt for its bindings. + +Required properties: +- compatible: should be one of: + * "x-powers,axp152" + * "x-powers,axp202" + * "x-powers,axp209" + * "x-powers,axp221" + * "x-powers,axp223" + * "x-powers,axp803" + * "x-powers,axp806" + * "x-powers,axp809" + * "x-powers,axp813" +- reg: The I2C slave address or RSB hardware address for the AXP chip +- interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin +- interrupt-controller: The PMIC has its own internal IRQs +- #interrupt-cells: Should be set to 1 + +Optional properties: +- x-powers,dcdc-freq: defines the work frequency of DC-DC in KHz + AXP152/20X: range: 750-1875, Default: 1.5 MHz + AXP22X/8XX: range: 1800-4050, Default: 3 MHz + +- x-powers,drive-vbus-en: boolean, set this when the N_VBUSEN pin is + used as an output pin to control an external + regulator to drive the OTG VBus, rather then + as an input pin which signals whether the + board is driving OTG VBus or not. + (axp221 / axp223 / axp803/ axp813 only) + +- x-powers,self-working-mode and + x-powers,master-mode: Boolean (axp806 only). Set either of these when the + PMIC is wired for self-working mode or master mode. + If neither is set then slave mode is assumed. + This corresponds to how the MODESET pin is wired. + +- -supply: a phandle to the regulator supply node. May be omitted if + inputs are unregulated, such as using the IPSOUT output + from the PMIC. + +- regulators: A node that houses a sub-node for each regulator. Regulators + not used but preferred to be managed by the OS should be + listed as well. + See Documentation/devicetree/bindings/regulator/regulator.txt + for more information on standard regulator bindings. + +Optional properties for DCDC regulators: +- x-powers,dcdc-workmode: 1 for PWM mode, 0 for AUTO (PWM/PFM) mode + Default: Current hardware setting + The DCDC regulators work in a mixed PWM/PFM mode, + using PFM under light loads and switching to PWM + for heavier loads. Forcing PWM mode trades efficiency + under light loads for lower output noise. This + probably makes sense for HiFi audio related + applications that aren't battery constrained. + +AXP202/AXP209 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC2 : DC-DC buck : vin2-supply +DCDC3 : DC-DC buck : vin3-supply +LDO1 : LDO : acin-supply : always on +LDO2 : LDO : ldo24in-supply : shared supply +LDO3 : LDO : ldo3in-supply +LDO4 : LDO : ldo24in-supply : shared supply +LDO5 : LDO : ldo5in-supply + +AXP221/AXP223 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC1 : DC-DC buck : vin1-supply +DCDC2 : DC-DC buck : vin2-supply +DCDC3 : DC-DC buck : vin3-supply +DCDC4 : DC-DC buck : vin4-supply +DCDC5 : DC-DC buck : vin5-supply +DC1SW : On/Off Switch : : DCDC1 secondary output +DC5LDO : LDO : : input from DCDC5 +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +DLDO1 : LDO : dldoin-supply : shared supply +DLDO2 : LDO : dldoin-supply : shared supply +DLDO3 : LDO : dldoin-supply : shared supply +DLDO4 : LDO : dldoin-supply : shared supply +ELDO1 : LDO : eldoin-supply : shared supply +ELDO2 : LDO : eldoin-supply : shared supply +ELDO3 : LDO : eldoin-supply : shared supply +LDO_IO0 : LDO : ips-supply : GPIO 0 +LDO_IO1 : LDO : ips-supply : GPIO 1 +RTC_LDO : LDO : ips-supply : always on +DRIVEVBUS : Enable output : drivevbus-supply : external regulator + +AXP803 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC1 : DC-DC buck : vin1-supply +DCDC2 : DC-DC buck : vin2-supply : poly-phase capable +DCDC3 : DC-DC buck : vin3-supply : poly-phase capable +DCDC4 : DC-DC buck : vin4-supply +DCDC5 : DC-DC buck : vin5-supply : poly-phase capable +DCDC6 : DC-DC buck : vin6-supply : poly-phase capable +DC1SW : On/Off Switch : : DCDC1 secondary output +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +DLDO1 : LDO : dldoin-supply : shared supply +DLDO2 : LDO : dldoin-supply : shared supply +DLDO3 : LDO : dldoin-supply : shared supply +DLDO4 : LDO : dldoin-supply : shared supply +ELDO1 : LDO : eldoin-supply : shared supply +ELDO2 : LDO : eldoin-supply : shared supply +ELDO3 : LDO : eldoin-supply : shared supply +FLDO1 : LDO : fldoin-supply : shared supply +FLDO2 : LDO : fldoin-supply : shared supply +LDO_IO0 : LDO : ips-supply : GPIO 0 +LDO_IO1 : LDO : ips-supply : GPIO 1 +RTC_LDO : LDO : ips-supply : always on +DRIVEVBUS : Enable output : drivevbus-supply : external regulator + +AXP806 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDCA : DC-DC buck : vina-supply : poly-phase capable +DCDCB : DC-DC buck : vinb-supply : poly-phase capable +DCDCC : DC-DC buck : vinc-supply : poly-phase capable +DCDCD : DC-DC buck : vind-supply : poly-phase capable +DCDCE : DC-DC buck : vine-supply : poly-phase capable +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +BLDO1 : LDO : bldoin-supply : shared supply +BLDO2 : LDO : bldoin-supply : shared supply +BLDO3 : LDO : bldoin-supply : shared supply +BLDO4 : LDO : bldoin-supply : shared supply +CLDO1 : LDO : cldoin-supply : shared supply +CLDO2 : LDO : cldoin-supply : shared supply +CLDO3 : LDO : cldoin-supply : shared supply +SW : On/Off Switch : swin-supply + +Additionally, the AXP806 DC-DC regulators support poly-phase arrangements +for higher output current. The possible groupings are: A+B, A+B+C, D+E. + +AXP809 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC1 : DC-DC buck : vin1-supply +DCDC2 : DC-DC buck : vin2-supply +DCDC3 : DC-DC buck : vin3-supply +DCDC4 : DC-DC buck : vin4-supply +DCDC5 : DC-DC buck : vin5-supply +DC1SW : On/Off Switch : : DCDC1 secondary output +DC5LDO : LDO : : input from DCDC5 +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +DLDO1 : LDO : dldoin-supply : shared supply +DLDO2 : LDO : dldoin-supply : shared supply +ELDO1 : LDO : eldoin-supply : shared supply +ELDO2 : LDO : eldoin-supply : shared supply +ELDO3 : LDO : eldoin-supply : shared supply +LDO_IO0 : LDO : ips-supply : GPIO 0 +LDO_IO1 : LDO : ips-supply : GPIO 1 +RTC_LDO : LDO : ips-supply : always on +SW : On/Off Switch : swin-supply + +AXP813 regulators, type, and corresponding input supply names: + +Regulator Type Supply Name Notes +--------- ---- ----------- ----- +DCDC1 : DC-DC buck : vin1-supply +DCDC2 : DC-DC buck : vin2-supply : poly-phase capable +DCDC3 : DC-DC buck : vin3-supply : poly-phase capable +DCDC4 : DC-DC buck : vin4-supply +DCDC5 : DC-DC buck : vin5-supply : poly-phase capable +DCDC6 : DC-DC buck : vin6-supply : poly-phase capable +DCDC7 : DC-DC buck : vin7-supply +ALDO1 : LDO : aldoin-supply : shared supply +ALDO2 : LDO : aldoin-supply : shared supply +ALDO3 : LDO : aldoin-supply : shared supply +DLDO1 : LDO : dldoin-supply : shared supply +DLDO2 : LDO : dldoin-supply : shared supply +DLDO3 : LDO : dldoin-supply : shared supply +DLDO4 : LDO : dldoin-supply : shared supply +ELDO1 : LDO : eldoin-supply : shared supply +ELDO2 : LDO : eldoin-supply : shared supply +ELDO3 : LDO : eldoin-supply : shared supply +FLDO1 : LDO : fldoin-supply : shared supply +FLDO2 : LDO : fldoin-supply : shared supply +FLDO3 : LDO : fldoin-supply : shared supply +LDO_IO0 : LDO : ips-supply : GPIO 0 +LDO_IO1 : LDO : ips-supply : GPIO 1 +RTC_LDO : LDO : ips-supply : always on +SW : On/Off Switch : swin-supply +DRIVEVBUS : Enable output : drivevbus-supply : external regulator + +Example: + +axp209: pmic@34 { + compatible = "x-powers,axp209"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + regulators { + x-powers,dcdc-freq = <1500>; + + vdd_cpu: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1450000>; + regulator-name = "vdd-cpu"; + }; + + vdd_int_dll: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-int-dll"; + }; + + vdd_rtc: ldo1 { + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + regulator-name = "vdd-rtc"; + }; + + avcc: ldo2 { + regulator-always-on; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + regulator-name = "avcc"; + }; + + ldo3 { + /* unused but preferred to be managed by OS */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/bd9571mwv.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/bd9571mwv.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c4678650d1a3087423811b7e60e115d0d60e208 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/bd9571mwv.txt @@ -0,0 +1,69 @@ +* ROHM BD9571MWV Power Management Integrated Circuit (PMIC) bindings + +Required properties: + - compatible : Should be "rohm,bd9571mwv". + - reg : I2C slave address. + - interrupts : The interrupt line the device is connected to. + - interrupt-controller : Marks the device node as an interrupt controller. + - #interrupt-cells : The number of cells to describe an IRQ, should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as trigger + masks from ../interrupt-controller/interrupts.txt. + - gpio-controller : Marks the device node as a GPIO Controller. + - #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - regulators: : List of child nodes that specify the regulator + initialization data. Child nodes must be named + after their hardware counterparts: + - vd09 + - vd18 + - vd25 + - vd33 + - dvfs + Each child node is defined using the standard + binding for regulators. + +Optional properties: + - rohm,ddr-backup-power : Value to use for DDR-Backup Power (default 0). + This is a bitmask that specifies which DDR power + rails need to be kept powered when backup mode is + entered, for system suspend: + - bit 0: DDR0 + - bit 1: DDR1 + - bit 2: DDR0C + - bit 3: DDR1C + These bits match the KEEPON_DDR* bits in the + documentation for the "BKUP Mode Cnt" register. + - rohm,rstbmode-level: The RSTB signal is configured for level mode, to + accommodate a toggle power switch (the RSTBMODE pin is + strapped low). + - rohm,rstbmode-pulse: The RSTB signal is configured for pulse mode, to + accommodate a momentary power switch (the RSTBMODE pin + is strapped high). + The two properties above are mutually exclusive. + +Example: + + pmic: pmic@30 { + compatible = "rohm,bd9571mwv"; + reg = <0x30>; + interrupt-parent = <&gpio2>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + rohm,ddr-backup-power = <0xf>; + rohm,rstbmode-pulse; + + regulators { + dvfs: dvfs { + regulator-name = "dvfs"; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1030000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/bfticu.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/bfticu.txt new file mode 100644 index 0000000000000000000000000000000000000000..538192fda9ae953b1a23f09f108f9570ac311e1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/bfticu.txt @@ -0,0 +1,24 @@ +KEYMILE bfticu Chassis Management FPGA + +The bfticu is a multifunction device that manages the whole chassis. +Its main functionality is to collect IRQs from the whole chassis and signals +them to a single controller. + +Required properties: +- compatible: "keymile,bfticu" +- interrupt-controller: the bfticu FPGA is an interrupt controller +- interrupts: the main IRQ line to signal the collected IRQs +- #interrupt-cells : is 2 and their usage is compliant to the 2 cells variant + of Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +- reg: access on the parent local bus (chip select, offset in chip select, size) + +Example: + + chassis-mgmt@3,0 { + compatible = "keymile,bfticu"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <3 0 0x100>; + interrupt-parent = <&mpic>; + interrupts = <6 1 0 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,bcm59056.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,bcm59056.txt new file mode 100644 index 0000000000000000000000000000000000000000..be51a15e05f926913b3a473648d977b25f1a2fbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,bcm59056.txt @@ -0,0 +1,39 @@ +------------------------------- +BCM590xx Power Management Units +------------------------------- + +Required properties: +- compatible: "brcm,bcm59056" +- reg: I2C slave address +- interrupts: interrupt for the PMU. Generic interrupt client node bindings + are described in interrupt-controller/interrupts.txt + +------------------ +Voltage Regulators +------------------ + +Optional child nodes: +- regulators: container node for regulators following the generic + regulator binding in regulator/regulator.txt + + The valid regulator node names for BCM59056 are: + rfldo, camldo1, camldo2, simldo1, simldo2, sdldo, sdxldo, + mmcldo1, mmcldo2, audldo, micldo, usbldo, vibldo, + csr, iosr1, iosr2, msr, sdsr1, sdsr2, vsr, + gpldo1, gpldo2, gpldo3, gpldo4, gpldo5, gpldo6, + vbus + +Example: + pmu: bcm59056@8 { + compatible = "brcm,bcm59056"; + reg = <0x08>; + interrupts = ; + regulators { + rfldo_reg: rfldo { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,iproc-cdru.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,iproc-cdru.txt new file mode 100644 index 0000000000000000000000000000000000000000..82f82e069563cf9a559ea6c647b8aa9268a0dc15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,iproc-cdru.txt @@ -0,0 +1,16 @@ +Broadcom iProc Chip Device Resource Unit (CDRU) + +Various Broadcom iProc SoCs have a set of registers that provide various +chip specific device and resource configurations. This node allows access to +these CDRU registers via syscon. + +Required properties: +- compatible: should contain: + "brcm,sr-cdru", "syscon" for Stingray +- reg: base address and range of the CDRU registers + +Example: + cdru: syscon@6641d000 { + compatible = "brcm,sr-cdru", "syscon"; + reg = <0 0x6641d000 0 0x400>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,iproc-mhb.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,iproc-mhb.txt new file mode 100644 index 0000000000000000000000000000000000000000..4421e9771b8a2a7ca82b1208a7e7a5e8e334fc09 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/brcm,iproc-mhb.txt @@ -0,0 +1,18 @@ +Broadcom iProc Multi Host Bridge (MHB) + +Certain Broadcom iProc SoCs have a multi host bridge (MHB) block that controls +the connection and configuration of 1) internal PCIe serdes; 2) PCIe endpoint +interface; 3) access to the Nitro (network processing) engine + +This node allows access to these MHB registers via syscon. + +Required properties: +- compatible: should contain: + "brcm,sr-mhb", "syscon" for Stingray +- reg: base address and range of the MHB registers + +Example: + mhb: syscon@60401000 { + compatible = "brcm,sr-mhb", "syscon"; + reg = <0 0x60401000 0 0x38c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/cros-ec.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/cros-ec.txt new file mode 100644 index 0000000000000000000000000000000000000000..6245c9b1a68bbc451ded3b33678362afcbf058d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/cros-ec.txt @@ -0,0 +1,73 @@ +ChromeOS Embedded Controller + +Google's ChromeOS EC is a Cortex-M device which talks to the AP and +implements various function such as keyboard and battery charging. + +The EC can be connect through various means (I2C, SPI, LPC) and the +compatible string used depends on the interface. Each connection method has +its own driver which connects to the top level interface-agnostic EC driver. +Other Linux driver (such as cros-ec-keyb for the matrix keyboard) connect to +the top-level driver. + +Required properties (I2C): +- compatible: "google,cros-ec-i2c" +- reg: I2C slave address + +Required properties (SPI): +- compatible: "google,cros-ec-spi" +- reg: SPI chip select + +Optional properties (SPI): +- google,cros-ec-spi-pre-delay: Some implementations of the EC need a little + time to wake up from sleep before they can receive SPI transfers at a high + clock rate. This property specifies the delay, in usecs, between the + assertion of the CS to the start of the first clock pulse. +- google,cros-ec-spi-msg-delay: Some implementations of the EC require some + additional processing time in order to accept new transactions. If the delay + between transactions is not long enough the EC may not be able to respond + properly to subsequent transactions and cause them to hang. This property + specifies the delay, in usecs, introduced between transactions to account + for the time required by the EC to get back into a state in which new data + can be accepted. + +Required properties (LPC): +- compatible: "google,cros-ec-lpc" +- reg: List of (IO address, size) pairs defining the interface uses + +Optional properties (all): +- google,has-vbc-nvram: Some implementations of the EC include a small + nvram space used to store verified boot context data. This boolean flag + is used to specify whether this nvram is present or not. + +Example for I2C: + +i2c@12ca0000 { + cros-ec@1e { + reg = <0x1e>; + compatible = "google,cros-ec-i2c"; + interrupts = <14 0>; + interrupt-parent = <&wakeup_eint>; + wakeup-source; + }; + + +Example for SPI: + +spi@131b0000 { + ec@0 { + compatible = "google,cros-ec-spi"; + reg = <0x0>; + interrupts = <14 0>; + interrupt-parent = <&wakeup_eint>; + wakeup-source; + spi-max-frequency = <5000000>; + controller-data { + cs-gpio = <&gpf0 3 4 3 0>; + samsung,spi-cs; + samsung,spi-feedback-delay = <2>; + }; + }; +}; + + +Example for LPC is not supplied as it is not yet implemented. diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/da9052-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/da9052-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..07c69c0c6624ce2e2d0adab034c4d10ce8b373e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/da9052-i2c.txt @@ -0,0 +1,67 @@ +* Dialog DA9052/53 Power Management Integrated Circuit (PMIC) + +Required properties: +- compatible : Should be "dlg,da9052", "dlg,da9053-aa", + "dlg,da9053-ab", or "dlg,da9053-bb" + +Optional properties: +- dlg,tsi-as-adc : Boolean, if set the X+, X-, Y+, Y- touchscreen + input lines are used as general purpose analogue + input. +- tsiref-supply: Phandle to the regulator, which provides the reference + voltage for the TSIREF pin. Must be provided when the + touchscreen pins are used for ADC purposes. + +Sub-nodes: +- regulators : Contain the regulator nodes. The DA9052/53 regulators are + bound using their names as listed below: + + buck1 : regulator BUCK CORE + buck2 : regulator BUCK PRO + buck3 : regulator BUCK MEM + buck4 : regulator BUCK PERI + ldo1 : regulator LDO1 + ldo2 : regulator LDO2 + ldo3 : regulator LDO3 + ldo4 : regulator LDO4 + ldo5 : regulator LDO5 + ldo6 : regulator LDO6 + ldo7 : regulator LDO7 + ldo8 : regulator LDO8 + ldo9 : regulator LDO9 + ldo10 : regulator LDO10 + + The bindings details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +Examples: + +i2c@63fc8000 { /* I2C1 */ + + pmic: dialog@48 { + compatible = "dlg,da9053-aa"; + reg = <0x48>; + + regulators { + buck1 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2075000>; + }; + + buck2 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <2075000>; + }; + + buck3 { + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <2500000>; + }; + + buck4 { + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <2500000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/da9055.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/da9055.txt new file mode 100644 index 0000000000000000000000000000000000000000..131a53283e1786c6488a91587617e558f7109963 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/da9055.txt @@ -0,0 +1,70 @@ +* Dialog DA9055 Power Management Integrated Circuit (PMIC) + +DA9055 consists of a large and varied group of sub-devices (I2C Only): + +Device Supply Names Description +------ ------------ ----------- +da9055-gpio : : GPIOs +da9055-regulator : : Regulators +da9055-onkey : : On key +da9055-rtc : : RTC +da9055-hwmon : : ADC +da9055-watchdog : : Watchdog + +The CODEC device in DA9055 has a separate, configurable I2C address and so +is instantiated separately from the PMIC. + +For details on accompanying CODEC I2C device, see the following: +Documentation/devicetree/bindings/sound/da9055.txt + +====== + +Required properties: +- compatible : Should be "dlg,da9055-pmic" +- reg: Specifies the I2C slave address (defaults to 0x5a but can be modified) +- interrupts: IRQ line info for da9055 chip. +- interrupt-controller: da9055 has internal IRQs (has own IRQ domain). +- #interrupt-cells: Should be 1, is the local IRQ number for da9055. + +Sub-nodes: +- regulators : Contain the regulator nodes. The DA9055 regulators are + bound using their names as listed below: + + buck1 : regulator BUCK1 + buck2 : regulator BUCK2 + ldo1 : regulator LDO1 + ldo2 : regulator LDO2 + ldo3 : regulator LDO3 + ldo4 : regulator LDO4 + ldo5 : regulator LDO5 + ldo6 : regulator LDO6 + + The bindings details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + + +Example: + + pmic: da9055-pmic@5a { + compatible = "dlg,da9055-pmic"; + reg = <0x5a>; + interrupt-parent = <&intc>; + interrupts = <5 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + regulators { + buck1: BUCK1 { + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <2075000>; + }; + buck2: BUCK2 { + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <2500000>; + }; + ldo1: LDO1 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/da9062.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/da9062.txt new file mode 100644 index 0000000000000000000000000000000000000000..edca653a57777d5a5867eb30315c87b616c58606 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/da9062.txt @@ -0,0 +1,109 @@ +* Dialog DA9062 Power Management Integrated Circuit (PMIC) + +Product information for the DA9062 and DA9061 devices can be found here: +- http://www.dialog-semiconductor.com/products/da9062 +- http://www.dialog-semiconductor.com/products/da9061 + +The DA9062 PMIC consists of: + +Device Supply Names Description +------ ------------ ----------- +da9062-regulator : : LDOs & BUCKs +da9062-rtc : : Real-Time Clock +da9062-onkey : : On Key +da9062-watchdog : : Watchdog Timer +da9062-thermal : : Thermal + +The DA9061 PMIC consists of: + +Device Supply Names Description +------ ------------ ----------- +da9062-regulator : : LDOs & BUCKs +da9062-onkey : : On Key +da9062-watchdog : : Watchdog Timer +da9062-thermal : : Thermal + +====== + +Required properties: + +- compatible : Should be + "dlg,da9062" for DA9062 + "dlg,da9061" for DA9061 +- reg : Specifies the I2C slave address (this defaults to 0x58 but it can be + modified to match the chip's OTP settings). +- interrupts : IRQ line information. +- interrupt-controller + +See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for +further information on IRQ bindings. + +Sub-nodes: + +- regulators : This node defines the settings for the LDOs and BUCKs. + The DA9062 regulators are bound using their names listed below: + + buck1 : BUCK_1 + buck2 : BUCK_2 + buck3 : BUCK_3 + buck4 : BUCK_4 + ldo1 : LDO_1 + ldo2 : LDO_2 + ldo3 : LDO_3 + ldo4 : LDO_4 + + The DA9061 regulators are bound using their names listed below: + + buck1 : BUCK_1 + buck2 : BUCK_2 + buck3 : BUCK_3 + ldo1 : LDO_1 + ldo2 : LDO_2 + ldo3 : LDO_3 + ldo4 : LDO_4 + + The component follows the standard regulator framework and the bindings + details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +- rtc : This node defines settings required for the Real-Time Clock associated + with the DA9062. There are currently no entries in this binding, however + compatible = "dlg,da9062-rtc" should be added if a node is created. + +- onkey : See ../input/da9062-onkey.txt + +- watchdog: See ../watchdog/da9062-watchdog.txt + +- thermal : See ../thermal/da9062-thermal.txt + +Example: + + pmic0: da9062@58 { + compatible = "dlg,da9062"; + reg = <0x58>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + + rtc { + compatible = "dlg,da9062-rtc"; + }; + + regulators { + DA9062_BUCK1: buck1 { + regulator-name = "BUCK1"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <500000>; + regulator-max-microamp = <2000000>; + regulator-boot-on; + }; + DA9062_LDO1: ldo1 { + regulator-name = "LDO_1"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3600000>; + regulator-boot-on; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/da9063.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/da9063.txt new file mode 100644 index 0000000000000000000000000000000000000000..8da879935c597038ed3615f93192f7d546e79dbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/da9063.txt @@ -0,0 +1,111 @@ +* Dialog DA9063/DA9063L Power Management Integrated Circuit (PMIC) + +DA9093 consists of a large and varied group of sub-devices (I2C Only): + +Device Supply Names Description +------ ------------ ----------- +da9063-regulator : : LDOs & BUCKs +da9063-onkey : : On Key +da9063-rtc : : Real-Time Clock (DA9063 only) +da9063-watchdog : : Watchdog + +====== + +Required properties: + +- compatible : Should be "dlg,da9063" or "dlg,da9063l" +- reg : Specifies the I2C slave address (this defaults to 0x58 but it can be + modified to match the chip's OTP settings). +- interrupts : IRQ line information. +- interrupt-controller + +Sub-nodes: + +- regulators : This node defines the settings for the LDOs and BUCKs. + The DA9063(L) regulators are bound using their names listed below: + + bcore1 : BUCK CORE1 + bcore2 : BUCK CORE2 + bpro : BUCK PRO + bmem : BUCK MEM + bio : BUCK IO + bperi : BUCK PERI + ldo1 : LDO_1 (DA9063 only) + ldo2 : LDO_2 (DA9063 only) + ldo3 : LDO_3 + ldo4 : LDO_4 (DA9063 only) + ldo5 : LDO_5 (DA9063 only) + ldo6 : LDO_6 (DA9063 only) + ldo7 : LDO_7 + ldo8 : LDO_8 + ldo9 : LDO_9 + ldo10 : LDO_10 (DA9063 only) + ldo11 : LDO_11 + + The component follows the standard regulator framework and the bindings + details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +- rtc : This node defines settings for the Real-Time Clock associated with + the DA9063 only. The RTC is not present in DA9063L. There are currently + no entries in this binding, however compatible = "dlg,da9063-rtc" should + be added if a node is created. + +- onkey : This node defines the OnKey settings for controlling the key + functionality of the device. The node should contain the compatible property + with the value "dlg,da9063-onkey". + + Optional onkey properties: + + - dlg,disable-key-power : Disable power-down using a long key-press. If this + entry exists the OnKey driver will remove support for the KEY_POWER key + press. If this entry does not exist then by default the key-press + triggered power down is enabled and the OnKey will support both KEY_POWER + and KEY_SLEEP. + +- watchdog : This node defines settings for the Watchdog timer associated + with the DA9063 and DA9063L. There are currently no entries in this + binding, however compatible = "dlg,da9063-watchdog" should be added + if a node is created. + + +Example: + + pmic0: da9063@58 { + compatible = "dlg,da9063" + reg = <0x58>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + + rtc { + compatible = "dlg,da9063-rtc"; + }; + + wdt { + compatible = "dlg,da9063-watchdog"; + }; + + onkey { + compatible = "dlg,da9063-onkey"; + dlg,disable-key-power; + }; + + regulators { + DA9063_BCORE1: bcore1 { + regulator-name = "BCORE1"; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <500000>; + regulator-max-microamp = <2000000>; + regulator-boot-on; + }; + DA9063_LDO11: ldo11 { + regulator-name = "LDO_11"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3600000>; + regulator-boot-on; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/da9150.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/da9150.txt new file mode 100644 index 0000000000000000000000000000000000000000..f09b41fbdf474ce474f088dfcf065d7dda86ffac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/da9150.txt @@ -0,0 +1,60 @@ +Dialog Semiconductor DA9150 Combined Charger/Fuel-Gauge MFD bindings + +DA9150 consists of a group of sub-devices: + +Device Description +------ ----------- +da9150-gpadc : General Purpose ADC +da9150-charger : Battery Charger +da9150-fg : Battery Fuel-Gauge + +====== + +Required properties: +- compatible : Should be "dlg,da9150" +- reg: Specifies the I2C slave address +- interrupts: IRQ line info for da9150 chip. +- interrupt-controller: da9150 has internal IRQs (own IRQ domain). + (See ../interrupt-controller/interrupts.txt for + further information relating to interrupt properties) + +Sub-devices: +- da9150-gpadc: See ../iio/adc/da9150-gpadc.txt +- da9150-charger: See ../power/da9150-charger.txt +- da9150-fg: See ../power/da9150-fg.txt + +Example: + + charger_fg: da9150@58 { + compatible = "dlg,da9150"; + reg = <0x58>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + + gpadc: da9150-gpadc { + compatible = "dlg,da9150-gpadc"; + #io-channel-cells = <1>; + }; + + charger { + compatible = "dlg,da9150-charger"; + + io-channels = <&gpadc 0>, + <&gpadc 2>, + <&gpadc 8>, + <&gpadc 5>; + io-channel-names = "CHAN_IBUS", + "CHAN_VBUS", + "CHAN_TJUNC", + "CHAN_VBAT"; + }; + + fuel-gauge { + compatible = "dlg,da9150-fuel-gauge"; + + dlg,update-interval = <10000>; + dlg,warn-soc-level = /bits/ 8 <15>; + dlg,crit-soc-level = /bits/ 8 <5> + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/fsl-imx25-tsadc.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/fsl-imx25-tsadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b0350528699764c49e388362aaceb2311e9ec57e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/fsl-imx25-tsadc.txt @@ -0,0 +1,47 @@ +Freescale MX25 ADC/TSC MultiFunction Device (MFD) + +This device combines two general purpose conversion queues one used for general +ADC and the other used for touchscreens. + +Required properties: + - compatible: Should be "fsl,imx25-tsadc". + - reg: Start address and size of the memory area of + the device + - interrupts: Interrupt for this device + (See: ../interrupt-controller/interrupts.txt) + - clocks: An 'ipg' clock (See: ../clock/clock-bindings.txt) + - interrupt-controller: This device is an interrupt controller. It + controls the interrupts of both + conversion queues. + - #interrupt-cells: Should be '<1>'. + - #address-cells: Should be '<1>'. + - #size-cells: Should be '<1>'. + +This device includes two conversion queues which can be added as subnodes. +The first queue is for the touchscreen, the second for general purpose ADC. + +Example: + tscadc: tscadc@50030000 { + compatible = "fsl,imx25-tsadc"; + reg = <0x50030000 0xc>; + interrupts = <46>; + clocks = <&clks 119>; + clock-names = "ipg"; + interrupt-controller; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + tsc: tcq@50030400 { + compatible = "fsl,imx25-tcq"; + reg = <0x50030400 0x60>; + ... + }; + + adc: gcq@50030800 { + compatible = "fsl,imx25-gcq"; + reg = <0x50030800 0x60>; + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/hi6421.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/hi6421.txt new file mode 100644 index 0000000000000000000000000000000000000000..22da96d344a7bc9b082942cd8e423616392bf4a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/hi6421.txt @@ -0,0 +1,40 @@ +* HI6421 Multi-Functional Device (MFD), by HiSilicon Ltd. + +Required parent device properties: +- compatible : One of the following chip-specific strings: + "hisilicon,hi6421-pmic"; + "hisilicon,hi6421v530-pmic"; +- reg : register range space of hi6421; + +Supported Hi6421 sub-devices include: + +Device IRQ Names Supply Names Description +------ --------- ------------ ----------- +regulators : None : None : Regulators + +Required child device properties: +None. + +Example: + hi6421 { + compatible = "hisilicon,hi6421-pmic"; + reg = <0xfcc00000 0x0180>; /* 0x60 << 2 */ + + regulators { + // supply for MLC NAND/ eMMC + hi6421_vout0_reg: hi6421_vout0 { + regulator-name = "VOUT0"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + // supply for 26M Oscillator + hi6421_vout1_reg: hi6421_vout1 { + regulator-name = "VOUT1"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2000000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/hisilicon,hi655x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/hisilicon,hi655x.txt new file mode 100644 index 0000000000000000000000000000000000000000..9630ac0e4b56ef372f08a0850175be06d13cd9a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/hisilicon,hi655x.txt @@ -0,0 +1,33 @@ +Hisilicon Hi655x Power Management Integrated Circuit (PMIC) + +The hardware layout for access PMIC Hi655x from AP SoC Hi6220. +Between PMIC Hi655x and Hi6220, the physical signal channel is SSI. +We can use memory-mapped I/O to communicate. + ++----------------+ +-------------+ +| | | | +| Hi6220 | SSI bus | Hi655x | +| |-------------| | +| |(REGMAP_MMIO)| | ++----------------+ +-------------+ + +Required properties: +- compatible: Should be "hisilicon,hi655x-pmic". +- reg: Base address of PMIC on Hi6220 SoC. +- interrupt-controller: Hi655x has internal IRQs (has own IRQ domain). +- pmic-gpios: The GPIO used by PMIC IRQ. +- #clock-cells: From common clock binding; shall be set to 0 + +Optional properties: +- clock-output-names: From common clock binding to override the + default output clock name + +Example: + pmic: pmic@f8000000 { + compatible = "hisilicon,hi655x-pmic"; + reg = <0x0 0xf8000000 0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + pmic-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + #clock-cells = <0>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/lp3943.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/lp3943.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8591d6b11b49ddbfc6ab428be0e9601153ece59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/lp3943.txt @@ -0,0 +1,33 @@ +TI/National Semiconductor LP3943 MFD driver + +Required properties: + - compatible: "ti,lp3943" + - reg: I2C slave address. From 0x60 to 0x67. + +LP3943 consists of two sub-devices, lp3943-gpio and lp3943-pwm. + +For the LP3943 GPIO properties please refer to: +Documentation/devicetree/bindings/gpio/gpio-lp3943.txt + +For the LP3943 PWM properties please refer to: +Documentation/devicetree/bindings/pwm/pwm-lp3943.txt + +Example: + +lp3943@60 { + compatible = "ti,lp3943"; + reg = <0x60>; + + gpioex: gpio { + compatible = "ti,lp3943-gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + pwm3943: pwm { + compatible = "ti,lp3943-pwm"; + #pwm-cells = <2>; + ti,pwm0 = <8 9 10>; + ti,pwm1 = <15>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/lp873x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/lp873x.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae9cf39bd101f5a704e59e2cdcb0af0584558c3a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/lp873x.txt @@ -0,0 +1,67 @@ +TI LP873X PMIC MFD driver + +Required properties: + - compatible: "ti,lp8732", "ti,lp8733" + - reg: I2C slave address. + - gpio-controller: Marks the device node as a GPIO Controller. + - #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - xxx-in-supply: Phandle to parent supply node of each regulator + populated under regulators node. xxx can be + buck0, buck1, ldo0 or ldo1. + - regulators: List of child nodes that specify the regulator + initialization data. +Example: + +pmic: lp8733@60 { + compatible = "ti,lp8733"; + reg = <0x60>; + gpio-controller; + #gpio-cells = <2>; + + buck0-in-supply = <&vsys_3v3>; + buck1-in-supply = <&vsys_3v3>; + ldo0-in-supply = <&vsys_3v3>; + ldo1-in-supply = <&vsys_3v3>; + + regulators { + lp8733_buck0: buck0 { + regulator-name = "lp8733-buck0"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + regulator-min-microamp = <1500000>; + regulator-max-microamp = <4000000>; + regulator-ramp-delay = <10000>; + regulator-always-on; + regulator-boot-on; + }; + + lp8733_buck1: buck1 { + regulator-name = "lp8733-buck1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + regulator-min-microamp = <1500000>; + regulator-max-microamp = <4000000>; + regulator-ramp-delay = <10000>; + regulator-boot-on; + regulator-always-on; + }; + + lp8733_ldo0: ldo0 { + regulator-name = "lp8733-ldo0"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + lp8733_ldo1: ldo1 { + regulator-name = "lp8733-ldo1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/lp87565.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/lp87565.txt new file mode 100644 index 0000000000000000000000000000000000000000..a48df7c08ab087d7873306e319b7e2384a439fbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/lp87565.txt @@ -0,0 +1,43 @@ +TI LP87565 PMIC MFD driver + +Required properties: + - compatible: "ti,lp87565", "ti,lp87565-q1" + - reg: I2C slave address. + - gpio-controller: Marks the device node as a GPIO Controller. + - #gpio-cells: Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - xxx-in-supply: Phandle to parent supply node of each regulator + populated under regulators node. xxx should match + the supply_name populated in driver. +Example: + +lp87565_pmic: pmic@60 { + compatible = "ti,lp87565-q1"; + reg = <0x60>; + gpio-controller; + #gpio-cells = <2>; + + buck10-in-supply = <&vsys_3v3>; + buck23-in-supply = <&vsys_3v3>; + + regulators: regulators { + buck10_reg: buck10 { + /* VDD_MPU */ + regulator-name = "buck10"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1250000>; + regulator-always-on; + regulator-boot-on; + }; + + buck23_reg: buck23 { + /* VDD_GPU */ + regulator-name = "buck23"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1250000>; + regulator-boot-on; + regulator-always-on; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/madera.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/madera.txt new file mode 100644 index 0000000000000000000000000000000000000000..db3266088386a984b6dc6c44666cc0ac53aa03fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/madera.txt @@ -0,0 +1,102 @@ +Cirrus Logic Madera class audio codecs Multi-Functional Device + +These devices are audio SoCs with extensive digital capabilities and a range +of analogue I/O. + +See also the child driver bindings in: +bindings/pinctrl/cirrus,madera-pinctrl.txt +bindings/regulator/arizona-regulator.txt +bindings/sound/madera.txt + +Required properties: + + - compatible : One of the following chip-specific strings: + "cirrus,cs47l35" + "cirrus,cs47l85" + "cirrus,cs47l90" + "cirrus,cs47l91" + "cirrus,wm1840" + + - reg : I2C slave address when connected using I2C, chip select number when + using SPI. + + - DCVDD-supply : Power supply for the device as defined in + bindings/regulator/regulator.txt + Mandatory on CS47L35, CS47L90, CS47L91 + Optional on CS47L85, WM1840 + + - AVDD-supply, DBVDD1-supply, DBVDD2-supply, CPVDD1-supply, CPVDD2-supply : + Power supplies for the device + + - DBVDD3-supply, DBVDD4-supply : Power supplies for the device + (CS47L85, CS47L90, CS47L91, WM1840) + + - SPKVDDL-supply, SPKVDDR-supply : Power supplies for the device + (CS47L85, WM1840) + + - SPKVDD-supply : Power supply for the device + (CS47L35) + + - interrupt-controller : Indicates that this device is an interrupt controller + + - #interrupt-cells: the number of cells to describe an IRQ, must be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as the trigger masks from + bindings/interrupt-controller/interrupts.txt + + - gpio-controller : Indicates this device is a GPIO controller. + + - #gpio-cells : Must be 2. The first cell is the pin number. The second cell + is reserved for future use and must be zero + + - interrupt-parent : The parent interrupt controller. + + - interrupts : The interrupt line the /IRQ signal for the device is + connected to. + +Optional properties: + + - MICVDD-supply : Power supply, only need to be specified if + powered externally + + - reset-gpios : One entry specifying the GPIO controlling /RESET. + As defined in bindings/gpio.txt. + Although optional, it is strongly recommended to use a hardware reset + + - MICBIASx : Initial data for the MICBIAS regulators, as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + One for each MICBIAS generator (MICBIAS1, MICBIAS2, ...) + (all codecs) + + One for each output pin (MICBIAS1A, MIBCIAS1B, MICBIAS2A, ...) + (all except CS47L85, WM1840) + + The following following additional property is supported for the generator + nodes: + - cirrus,ext-cap : Set to 1 if the MICBIAS has external decoupling + capacitors attached. + +Optional child nodes: + micvdd : Node containing initialization data for the micvdd regulator + See bindings/regulator/arizona-regulator.txt + + ldo1 : Node containing initialization data for the LDO1 regulator + See bindings/regulator/arizona-regulator.txt + (cs47l85, wm1840) + +Example: + +cs47l85@0 { + compatible = "cirrus,cs47l85"; + reg = <0>; + + reset-gpios = <&gpio 0>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <&host_irq1>; + interrupt-parent = <&gic>; + + gpio-controller; + #gpio-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max14577.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max14577.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc6f0f4e8beb75879060ac1657f991a0369c5df6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max14577.txt @@ -0,0 +1,145 @@ +Maxim MAX14577/77836 Multi-Function Device + +MAX14577 is a Multi-Function Device with Micro-USB Interface Circuit, Li+ +Battery Charger and SFOUT LDO output for powering USB devices. It is +interfaced to host controller using I2C. + +MAX77836 additionally contains PMIC (with two LDO regulators) and Fuel Gauge. + + +Required properties: +- compatible : Must be "maxim,max14577" or "maxim,max77836". +- reg : I2C slave address for the max14577 chip (0x25 for max14577/max77836) +- interrupts : IRQ line for the chip. + + +Required nodes: + - charger : + Node for configuring the charger driver. + Required properties: + - compatible : "maxim,max14577-charger" + or "maxim,max77836-charger" + - maxim,fast-charge-uamp : Current in uA for Fast Charge; + Valid values: + - for max14577: 90000 - 950000; + - for max77836: 45000 - 475000; + - maxim,eoc-uamp : Current in uA for End-Of-Charge mode; + Valid values: + - for max14577: 50000 - 200000; + - for max77836: 5000 - 100000; + - maxim,ovp-uvolt : OverVoltage Protection Threshold in uV; + In an overvoltage condition, INT asserts and charging + stops. Valid values: + - 6000000, 6500000, 7000000, 7500000; + - maxim,constant-uvolt : Battery Constant Voltage in uV; + Valid values: + - 4000000 - 4280000 (step by 20000); + - 4350000; + + +Optional nodes: +- max14577-muic/max77836-muic : + Node used only by extcon consumers. + Required properties: + - compatible : "maxim,max14577-muic" or "maxim,max77836-muic" + +- regulators : + Required properties: + - compatible : "maxim,max14577-regulator" + or "maxim,max77836-regulator" + + May contain a sub-node per regulator from the list below. Each + sub-node should contain the constraints and initialization information + for that regulator. See regulator.txt for a description of standard + properties for these sub-nodes. + + List of valid regulator names: + - for max14577: CHARGER, SAFEOUT. + - for max77836: CHARGER, SAFEOUT, LDO1, LDO2. + + The SAFEOUT is a fixed voltage regulator so there is no need to specify + voltages for it. + + +Example: + +#include + +max14577@25 { + compatible = "maxim,max14577"; + reg = <0x25>; + interrupt-parent = <&gpx1>; + interrupts = <5 IRQ_TYPE_NONE>; + + muic: max14577-muic { + compatible = "maxim,max14577-muic"; + }; + + regulators { + compatible = "maxim,max14577-regulator"; + + SAFEOUT { + regulator-name = "SAFEOUT"; + }; + CHARGER { + regulator-name = "CHARGER"; + regulator-min-microamp = <90000>; + regulator-max-microamp = <950000>; + regulator-boot-on; + }; + }; + + charger { + compatible = "maxim,max14577-charger"; + + maxim,constant-uvolt = <4350000>; + maxim,fast-charge-uamp = <450000>; + maxim,eoc-uamp = <50000>; + maxim,ovp-uvolt = <6500000>; + }; +}; + + +max77836@25 { + compatible = "maxim,max77836"; + reg = <0x25>; + interrupt-parent = <&gpx1>; + interrupts = <5 IRQ_TYPE_NONE>; + + muic: max77836-muic { + compatible = "maxim,max77836-muic"; + }; + + regulators { + compatible = "maxim,max77836-regulator"; + + SAFEOUT { + regulator-name = "SAFEOUT"; + }; + CHARGER { + regulator-name = "CHARGER"; + regulator-min-microamp = <90000>; + regulator-max-microamp = <950000>; + regulator-boot-on; + }; + LDO1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2700000>; + }; + LDO2 { + regulator-name = "LDO2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3950000>; + }; + }; + + charger { + compatible = "maxim,max77836-charger"; + + maxim,constant-uvolt = <4350000>; + maxim,fast-charge-uamp = <225000>; + maxim,eoc-uamp = <7500>; + maxim,ovp-uvolt = <6500000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max77620.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max77620.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c16d51cc15b913ce900c622741eb51904224686 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max77620.txt @@ -0,0 +1,155 @@ +MAX77620 Power management IC from Maxim Semiconductor. + +Required properties: +------------------- +- compatible: Must be one of + "maxim,max77620" + "maxim,max20024". +- reg: I2C device address. + +Optional properties: +------------------- +- interrupts: The interrupt on the parent the controller is + connected to. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: is <2> and their usage is compliant to the 2 cells + variant of <../interrupt-controller/interrupts.txt> + IRQ numbers for different interrupt source of MAX77620 + are defined at dt-bindings/mfd/max77620.h. + +Optional subnodes and their properties: +======================================= + +Flexible power sequence configurations: +-------------------------------------- +The Flexible Power Sequencer (FPS) allows each regulator to power up under +hardware or software control. Additionally, each regulator can power on +independently or among a group of other regulators with an adjustable power-up +and power-down delays (sequencing). GPIO1, GPIO2, and GPIO3 can be programmed +to be part of a sequence allowing external regulators to be sequenced along +with internal regulators. 32KHz clock can be programmed to be part of a +sequence. + +The flexible sequencing structure consists of two hardware enable inputs +(EN0, EN1), and 3 master sequencing timers called FPS0, FPS1 and FPS2. +Each master sequencing timer is programmable through its configuration +register to have a hardware enable source (EN1 or EN2) or a software enable +source (SW). When enabled/disabled, the master sequencing timer generates +eight sequencing events on different time periods called slots. The time +period between each event is programmable within the configuration register. +Each regulator, GPIO1, GPIO2, GPIO3, and 32KHz clock has a flexible power +sequence slave register which allows its enable source to be specified as +a flexible power sequencer timer or a software bit. When a FPS source of +regulators, GPIOs and clocks specifies the enable source to be a flexible +power sequencer, the power up and power down delays can be specified in +the regulators, GPIOs and clocks flexible power sequencer configuration +registers. + +When FPS event cleared (set to LOW), regulators, GPIOs and 32KHz +clock are set into following state at the sequencing event that +corresponds to its flexible sequencer configuration register. + Sleep state: In this state, regulators, GPIOs + and 32KHz clock get disabled at + the sequencing event. + Global Low Power Mode (GLPM): In this state, regulators are set in + low power mode at the sequencing event. + +The configuration parameters of FPS is provided through sub-node "fps" +and their child for FPS specific. The child node name for FPS are "fps0", +"fps1", and "fps2" for FPS0, FPS1 and FPS2 respectively. + +The FPS configurations like FPS source, power up and power down slots for +regulators, GPIOs and 32kHz clocks are provided in their respective +configuration nodes which is explained in respective sub-system DT +binding document. + +There is need for different FPS configuration parameters based on system +state like when system state changed from active to suspend or active to +power off (shutdown). + +Optional properties: +------------------- +-maxim,fps-event-source: u32, FPS event source like external + hardware input to PMIC i.e. EN0, EN1 or + software (SW). + The macros are defined on + dt-bindings/mfd/max77620.h + for different control source. + - MAX77620_FPS_EVENT_SRC_EN0 + for hardware input pin EN0. + - MAX77620_FPS_EVENT_SRC_EN1 + for hardware input pin EN1. + - MAX77620_FPS_EVENT_SRC_SW + for software control. + +-maxim,shutdown-fps-time-period-us: u32, FPS time period in microseconds + when system enters in to shutdown + state. + +-maxim,suspend-fps-time-period-us: u32, FPS time period in microseconds + when system enters in to suspend state. + +-maxim,device-state-on-disabled-event: u32, describe the PMIC state when FPS + event cleared (set to LOW) whether it + should go to sleep state or low-power + state. Following are valid values: + - MAX77620_FPS_INACTIVE_STATE_SLEEP + to set the PMIC state to sleep. + - MAX77620_FPS_INACTIVE_STATE_LOW_POWER + to set the PMIC state to low + power. + Absence of this property or other value + will not change device state when FPS + event get cleared. + +Here supported time periods by device in microseconds are as follows: +MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds. +MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds. + +-maxim,power-ok-control: configure map power ok bit + 1: Enables POK(Power OK) to control nRST_IO and GPIO1 + POK function. + 0: Disables POK control. + if property missing, do not configure MPOK bit. + If POK mapping is enabled for GPIO1/nRST_IO then, + GPIO1/nRST_IO pins are HIGH only if all rails + that have POK control enabled are HIGH. + If any of the rails goes down(which are enabled for POK + control) then, GPIO1/nRST_IO goes LOW. + this property is valid for max20024 only. + +For DT binding details of different sub modules like GPIO, pincontrol, +regulator, power, please refer respective device-tree binding document +under their respective sub-system directories. + +Example: +-------- +#include + +max77620@3c { + compatible = "maxim,max77620"; + reg = <0x3c>; + + interrupt-parent = <&intc>; + interrupts = <0 86 IRQ_TYPE_NONE>; + + interrupt-controller; + #interrupt-cells = <2>; + + fps { + fps0 { + maxim,shutdown-fps-time-period-us = <1280>; + maxim,fps-event-source = ; + }; + + fps1 { + maxim,shutdown-fps-time-period-us = <1280>; + maxim,fps-event-source = ; + }; + + fps2 { + maxim,shutdown-fps-time-period-us = <1280>; + maxim,fps-event-source = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max77686.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max77686.txt new file mode 100644 index 0000000000000000000000000000000000000000..42968b7144e009fe618e523e7720d91618945c26 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max77686.txt @@ -0,0 +1,26 @@ +Maxim MAX77686 multi-function device + +MAX77686 is a Multifunction device with PMIC, RTC and Charger on chip. It is +interfaced to host controller using i2c interface. PMIC and Charger submodules +are addressed using same i2c slave address whereas RTC submodule uses +different i2c slave address,presently for which we are statically creating i2c +client while probing.This document describes the binding for mfd device and +PMIC submodule. + +Bindings for the built-in 32k clock generator block and +regulators are defined in ../clk/maxim,max77686.txt and +../regulator/max77686.txt respectively. + +Required properties: +- compatible : Must be "maxim,max77686"; +- reg : Specifies the i2c slave address of PMIC block. +- interrupts : This i2c device has an IRQ line connected to the main SoC. + +Example: + + max77686: pmic@9 { + compatible = "maxim,max77686"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max77693.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max77693.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3c60a7a3be1e23f51f166045f8d96e00243b195 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max77693.txt @@ -0,0 +1,193 @@ +Maxim MAX77693 multi-function device + +MAX77693 is a Multifunction device with the following submodules: +- PMIC, +- CHARGER, +- LED, +- MUIC, +- HAPTIC + +It is interfaced to host controller using i2c. +This document describes the bindings for the mfd device. + +Required properties: +- compatible : Must be "maxim,max77693". +- reg : Specifies the i2c slave address of PMIC block. +- interrupts : This i2c device has an IRQ line connected to the main SoC. + +Optional properties: +- regulators : The regulators of max77693 have to be instantiated under subnode + named "regulators" using the following format. + + regulators { + regulator-compatible = ESAFEOUT1/ESAFEOUT2/CHARGER + standard regulator constraints[*]. + }; + + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt + +- haptic : The MAX77693 haptic device utilises a PWM controlled motor to provide + users with tactile feedback. PWM period and duty-cycle are varied in + order to provide the appropriate level of feedback. + + Required properties: + - compatible : Must be "maxim,max77693-haptic" + - haptic-supply : power supply for the haptic motor + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt + - pwms : phandle to the physical PWM(Pulse Width Modulation) device. + PWM properties should be named "pwms". And number of cell is different + for each pwm device. + To get more information, please refer to documentation. + [*] refer Documentation/devicetree/bindings/pwm/pwm.txt + +- charger : Node configuring the charger driver. + If present, required properties: + - compatible : Must be "maxim,max77693-charger". + + Optional properties (if not set, defaults will be used): + - maxim,constant-microvolt : Battery constant voltage in uV. The charger + will operate in fast charge constant current mode till battery voltage + reaches this level. Then the charger will switch to fast charge constant + voltage mode. Also vsys (system voltage) will be set to this value when + DC power is supplied but charger is not enabled. + Valid values: 3650000 - 4400000, step by 25000 (rounded down) + Default: 4200000 + + - maxim,min-system-microvolt : Minimal system voltage in uV. + Valid values: 3000000 - 3700000, step by 100000 (rounded down) + Default: 3600000 + + - maxim,thermal-regulation-celsius : Temperature in Celsius for entering + high temperature charging mode. If die temperature exceeds this value + the charging current will be reduced by 105 mA/Celsius. + Valid values: 70, 85, 100, 115 + Default: 100 + + - maxim,battery-overcurrent-microamp : Overcurrent protection threshold + in uA (current from battery to system). + Valid values: 2000000 - 3500000, step by 250000 (rounded down) + Default: 3500000 + + - maxim,charge-input-threshold-microvolt : Threshold voltage in uV for + triggering input voltage regulation loop. If input voltage decreases + below this value, the input current will be reduced to reach the + threshold voltage. + Valid values: 4300000, 4700000, 4800000, 4900000 + Default: 4300000 + +- led : the LED submodule device node + +There are two LED outputs available - FLED1 and FLED2. Each of them can +control a separate LED or they can be connected together to double +the maximum current for a single connected LED. One LED is represented +by one child node. + +Required properties: +- compatible : Must be "maxim,max77693-led". + +Optional properties: +- maxim,boost-mode : + In boost mode the device can produce up to 1.2A of total current + on both outputs. The maximum current on each output is reduced + to 625mA then. If not enabled explicitly, boost setting defaults to + LEDS_BOOST_FIXED in case both current sources are used. + Possible values: + LEDS_BOOST_OFF (0) - no boost, + LEDS_BOOST_ADAPTIVE (1) - adaptive mode, + LEDS_BOOST_FIXED (2) - fixed mode. +- maxim,boost-mvout : Output voltage of the boost module in millivolts. + Valid values: 3300 - 5500, step by 25 (rounded down) + Default: 3300 +- maxim,mvsys-min : Low input voltage level in millivolts. Flash is not fired + if chip estimates that system voltage could drop below this level due + to flash power consumption. + Valid values: 2400 - 3400, step by 33 (rounded down) + Default: 2400 + +Required properties for the LED child node: +- led-sources : see Documentation/devicetree/bindings/leds/common.txt; + device current output identifiers: 0 - FLED1, 1 - FLED2 +- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt + Valid values for a LED connected to one FLED output: + 15625 - 250000, step by 15625 (rounded down) + Valid values for a LED connected to both FLED outputs: + 15625 - 500000, step by 15625 (rounded down) +- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt + Valid values for a single LED connected to one FLED output + (boost mode must be turned off): + 15625 - 1000000, step by 15625 (rounded down) + Valid values for a single LED connected to both FLED outputs: + 15625 - 1250000, step by 15625 (rounded down) + Valid values for two LEDs case: + 15625 - 625000, step by 15625 (rounded down) +- flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt + Valid values: 62500 - 1000000, step by 62500 (rounded down) + +Optional properties for the LED child node: +- label : see Documentation/devicetree/bindings/leds/common.txt + +Optional nodes: +- max77693-muic : + Node used only by extcon consumers. + Required properties: + - compatible : "maxim,max77693-muic" + +Example: +#include + + max77693@66 { + compatible = "maxim,max77693"; + reg = <0x66>; + interrupt-parent = <&gpx1>; + interrupts = <5 2>; + + regulators { + esafeout@1 { + regulator-compatible = "ESAFEOUT1"; + regulator-name = "ESAFEOUT1"; + regulator-boot-on; + }; + esafeout@2 { + regulator-compatible = "ESAFEOUT2"; + regulator-name = "ESAFEOUT2"; + }; + charger@0 { + regulator-compatible = "CHARGER"; + regulator-name = "CHARGER"; + regulator-min-microamp = <60000>; + regulator-max-microamp = <2580000>; + regulator-boot-on; + }; + }; + + haptic { + compatible = "maxim,max77693-haptic"; + haptic-supply = <&haptic_supply>; + pwms = <&pwm 0 40000 0>; + pwm-names = "haptic"; + }; + + charger { + compatible = "maxim,max77693-charger"; + + maxim,constant-microvolt = <4200000>; + maxim,min-system-microvolt = <3600000>; + maxim,thermal-regulation-celsius = <75>; + maxim,battery-overcurrent-microamp = <3000000>; + maxim,charge-input-threshold-microvolt = <4300000>; + + led { + compatible = "maxim,max77693-led"; + maxim,boost-mode = ; + maxim,boost-mvout = <5000>; + maxim,mvsys-min = <2400>; + + camera_flash: flash-led { + label = "max77693-flash"; + led-sources = <0>, <1>; + led-max-microamp = <500000>; + flash-max-microamp = <1250000>; + flash-max-timeout-us = <1000000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max77802.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max77802.txt new file mode 100644 index 0000000000000000000000000000000000000000..09decac20d919f597fc753583b3669ec3841bcb2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max77802.txt @@ -0,0 +1,25 @@ +Maxim MAX77802 multi-function device + +The Maxim MAX77802 is a Power Management IC (PMIC) that contains 10 high +efficiency Buck regulators, 32 Low-DropOut (LDO) regulators used to power +up application processors and peripherals, a 2-channel 32kHz clock outputs, +a Real-Time-Clock (RTC) and a I2C interface to program the individual +regulators, clocks outputs and the RTC. + +Bindings for the built-in 32k clock generator block and +regulators are defined in ../clk/maxim,max77802.txt and +../regulator/max77802.txt respectively. + +Required properties: +- compatible : Must be "maxim,max77802" +- reg : Specifies the I2C slave address of PMIC block. +- interrupts : I2C device IRQ line connected to the main SoC. + +Example: + + max77802: pmic@9 { + compatible = "maxim,max77802"; + interrupt-parent = <&intc>; + interrupts = <26 IRQ_TYPE_NONE>; + reg = <0x09>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max8925.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max8925.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f0dc6638e5e19abf2be5594dfb6361849a9f6b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max8925.txt @@ -0,0 +1,64 @@ +* Maxim max8925 Power Management IC + +Required parent device properties: +- compatible : "maxim,max8925" +- reg : the I2C slave address for the max8925 chip +- interrupts : IRQ line for the max8925 chip +- interrupt-controller: describes the max8925 as an interrupt + controller (has its own domain) +- #interrupt-cells : should be 1. + - The cell is the max8925 local IRQ number + +Optional parent device properties: +- maxim,tsc-irq: there are 2 IRQ lines for max8925, one is indicated in + interrupts property, the other is indicated here. + +max8925 consists of a large and varied group of sub-devices: + +Device Supply Names Description +------ ------------ ----------- +max8925-onkey : : On key +max8925-rtc : : RTC +max8925-regulator : : Regulators +max8925-backlight : : Backlight +max8925-touch : : Touchscreen +max8925-power : : Charger + +Example: + + pmic: max8925@3c { + compatible = "maxim,max8925"; + reg = <0x3c>; + interrupts = <1>; + interrupt-parent = <&intcmux4>; + interrupt-controller; + #interrupt-cells = <1>; + maxim,tsc-irq = <0>; + + regulators { + SDV1 { + regulator-min-microvolt = <637500>; + regulator-max-microvolt = <1425000>; + regulator-boot-on; + regulator-always-on; + }; + + LDO1 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <3900000>; + regulator-boot-on; + regulator-always-on; + }; + + }; + backlight { + maxim,max8925-dual-string = <0>; + }; + charger { + batt-detect = <0>; + topoff-threshold = <1>; + fast-charge = <7>; + no-temp-support = <0>; + no-insert-detect = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/max8998.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/max8998.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f2f07c09c9018c9fb65e80239e0e2a95bdbf418 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/max8998.txt @@ -0,0 +1,117 @@ +* Maxim MAX8998, National/TI LP3974 multi-function device + +The Maxim MAX8998 is a multi-function device which includes voltage/current +regulators, real time clock, battery charging controller and several +other sub-blocks. It is interfaced using an I2C interface. Each sub-block +is addressed by the host system using different i2c slave address. + +PMIC sub-block +-------------- + +The PMIC sub-block contains a number of voltage and current regulators, +with controllable parameters and dynamic voltage scaling capability. +In addition, it includes a real time clock and battery charging controller +as well. It is accessible at I2C address 0x66. + +Required properties: +- compatible: Should be one of the following: + - "maxim,max8998" for Maxim MAX8998 + - "national,lp3974" or "ti,lp3974" for National/TI LP3974. +- reg: Specifies the i2c slave address of the pmic block. It should be 0x66. + +Optional properties: +- interrupts: Interrupt specifiers for two interrupt sources. + - First interrupt specifier is for main interrupt. + - Second interrupt specifier is for power-on/-off interrupt. +- max8998,pmic-buck1-dvs-gpios: GPIO specifiers for two host gpios used + for buck 1 dvs. The format of the gpio specifier depends on the gpio + controller. +- max8998,pmic-buck2-dvs-gpio: GPIO specifier for host gpio used + for buck 2 dvs. The format of the gpio specifier depends on the gpio + controller. +- max8998,pmic-buck1-default-dvs-idx: Default voltage setting selected from + the possible 4 options selectable by the dvs gpios. The value of this + property should be 0, 1, 2 or 3. If not specified or out of range, + a default value of 0 is taken. +- max8998,pmic-buck2-default-dvs-idx: Default voltage setting selected from + the possible 2 options selectable by the dvs gpios. The value of this + property should be 0 or 1. If not specified or out of range, a default + value of 0 is taken. +- max8998,pmic-buck-voltage-lock: If present, disallows changing of + preprogrammed buck dvfs voltages. + +Additional properties required if max8998,pmic-buck1-dvs-gpios is defined: +- max8998,pmic-buck1-dvs-voltage: An array of 4 voltage values in microvolts + for buck1 regulator that can be selected using dvs gpio. + +Additional properties required if max8998,pmic-buck2-dvs-gpio is defined: +- max8998,pmic-buck2-dvs-voltage: An array of 2 voltage values in microvolts + for buck2 regulator that can be selected using dvs gpio. + +Regulators: All the regulators of MAX8998 to be instantiated shall be +listed in a child node named 'regulators'. Each regulator is represented +by a child node of the 'regulators' node. + + regulator-name { + /* standard regulator bindings here */ + }; + +Following regulators of the MAX8998 PMIC block are supported. Note that +the 'n' in regulator name, as in LDOn or BUCKn, represents the LDO or BUCK +number as described in MAX8998 datasheet. + + - LDOn + - valid values for n are 2 to 17 + - Example: LDO2, LDO10, LDO17 + - BUCKn + - valid values for n are 1 to 4. + - Example: BUCK1, BUCK2, BUCK3, BUCK4 + + - ENVICHG: Battery Charging Current Monitor Output. This is a fixed + voltage type regulator + + - ESAFEOUT1: (ldo19) + - ESAFEOUT2: (ld020) + +Standard regulator bindings are used inside regulator subnodes. Check + Documentation/devicetree/bindings/regulator/regulator.txt +for more details. + +Example: + + pmic@66 { + compatible = "maxim,max8998-pmic"; + reg = <0x66>; + interrupt-parent = <&wakeup_eint>; + interrupts = <4 0>, <3 0>; + + /* Buck 1 DVS settings */ + max8998,pmic-buck1-default-dvs-idx = <0>; + max8998,pmic-buck1-dvs-gpios = <&gpx0 0 1 0 0>, /* SET1 */ + <&gpx0 1 1 0 0>; /* SET2 */ + max8998,pmic-buck1-dvs-voltage = <1350000>, <1300000>, + <1000000>, <950000>; + + /* Buck 2 DVS settings */ + max8998,pmic-buck2-default-dvs-idx = <0>; + max8998,pmic-buck2-dvs-gpio = <&gpx0 0 3 0 0>; /* SET3 */ + max8998,pmic-buck2-dvs-voltage = <1350000>, <1300000>; + + /* Regulators to instantiate */ + regulators { + ldo2_reg: LDO2 { + regulator-name = "VDD_ALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "VDD_ARM_1.2V"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/mc13xxx.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/mc13xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..8261ea73278a6bbed3eb2f5604490d3493259994 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/mc13xxx.txt @@ -0,0 +1,156 @@ +* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC) + +Required properties: +- compatible : Should be "fsl,mc13783" or "fsl,mc13892" + +Optional properties: +- fsl,mc13xxx-uses-adc : Indicate the ADC is being used +- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used +- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used +- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used + +Sub-nodes: +- codec: Contain the Audio Codec node. + - adc-port: Contain PMIC SSI port number used for ADC. + - dac-port: Contain PMIC SSI port number used for DAC. +- leds : Contain the led nodes and initial register values in property + "led-control". Number of register depends of used IC, for MC13783 is 6, + for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of + these registers. + - #address-cells: Must be 1. + - #size-cells: Must be 0. + Each led node should contain "reg", which used as LED ID (described below). + Optional properties "label" and "linux,default-trigger" is described in + Documentation/devicetree/bindings/leds/common.txt. +- regulators : Contain the regulator nodes. The regulators are bound using + their names as listed below with their registers and bits for enabling. + +MC13783 LED IDs: + 0 : Main display + 1 : AUX display + 2 : Keypad + 3 : Red 1 + 4 : Green 1 + 5 : Blue 1 + 6 : Red 2 + 7 : Green 2 + 8 : Blue 2 + 9 : Red 3 + 10 : Green 3 + 11 : Blue 3 + +MC13892 LED IDs: + 0 : Main display + 1 : AUX display + 2 : Keypad + 3 : Red + 4 : Green + 5 : Blue + +MC34708 LED IDs: + 0 : Charger Red + 1 : Charger Green + +MC13783 regulators: + sw1a : regulator SW1A (register 24, bit 0) + sw1b : regulator SW1B (register 25, bit 0) + sw2a : regulator SW2A (register 26, bit 0) + sw2b : regulator SW2B (register 27, bit 0) + sw3 : regulator SW3 (register 29, bit 20) + vaudio : regulator VAUDIO (register 32, bit 0) + viohi : regulator VIOHI (register 32, bit 3) + violo : regulator VIOLO (register 32, bit 6) + vdig : regulator VDIG (register 32, bit 9) + vgen : regulator VGEN (register 32, bit 12) + vrfdig : regulator VRFDIG (register 32, bit 15) + vrfref : regulator VRFREF (register 32, bit 18) + vrfcp : regulator VRFCP (register 32, bit 21) + vsim : regulator VSIM (register 33, bit 0) + vesim : regulator VESIM (register 33, bit 3) + vcam : regulator VCAM (register 33, bit 6) + vrfbg : regulator VRFBG (register 33, bit 9) + vvib : regulator VVIB (register 33, bit 11) + vrf1 : regulator VRF1 (register 33, bit 12) + vrf2 : regulator VRF2 (register 33, bit 15) + vmmc1 : regulator VMMC1 (register 33, bit 18) + vmmc2 : regulator VMMC2 (register 33, bit 21) + gpo1 : regulator GPO1 (register 34, bit 6) + gpo2 : regulator GPO2 (register 34, bit 8) + gpo3 : regulator GPO3 (register 34, bit 10) + gpo4 : regulator GPO4 (register 34, bit 12) + pwgt1spi : regulator PWGT1SPI (register 34, bit 15) + pwgt2spi : regulator PWGT2SPI (register 34, bit 16) + +MC13892 regulators: + vcoincell : regulator VCOINCELL (register 13, bit 23) + sw1 : regulator SW1 (register 24, bit 0) + sw2 : regulator SW2 (register 25, bit 0) + sw3 : regulator SW3 (register 26, bit 0) + sw4 : regulator SW4 (register 27, bit 0) + swbst : regulator SWBST (register 29, bit 20) + vgen1 : regulator VGEN1 (register 32, bit 0) + viohi : regulator VIOHI (register 32, bit 3) + vdig : regulator VDIG (register 32, bit 9) + vgen2 : regulator VGEN2 (register 32, bit 12) + vpll : regulator VPLL (register 32, bit 15) + vusb2 : regulator VUSB2 (register 32, bit 18) + vgen3 : regulator VGEN3 (register 33, bit 0) + vcam : regulator VCAM (register 33, bit 6) + vvideo : regulator VVIDEO (register 33, bit 12) + vaudio : regulator VAUDIO (register 33, bit 15) + vsd : regulator VSD (register 33, bit 18) + gpo1 : regulator GPO1 (register 34, bit 6) + gpo2 : regulator GPO2 (register 34, bit 8) + gpo3 : regulator GPO3 (register 34, bit 10) + gpo4 : regulator GPO4 (register 34, bit 12) + pwgt1spi : regulator PWGT1SPI (register 34, bit 15) + pwgt2spi : regulator PWGT2SPI (register 34, bit 16) + vusb : regulator VUSB (register 50, bit 3) + + The bindings details of individual regulator device can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +Examples: + +ecspi@70010000 { /* ECSPI1 */ + cs-gpios = <&gpio4 24 0>, /* GPIO4_24 */ + <&gpio4 25 0>; /* GPIO4_25 */ + + pmic: mc13892@0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mc13892"; + spi-max-frequency = <6000000>; + reg = <0>; + interrupt-parent = <&gpio0>; + interrupts = <8>; + + leds { + #address-cells = <1>; + #size-cells = <0>; + led-control = <0x000 0x000 0x0e0 0x000>; + + sysled@3 { + reg = <3>; + label = "system:red:live"; + linux,default-trigger = "heartbeat"; + }; + }; + + regulators { + sw1_reg: mc13892__sw1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1375000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: mc13892__sw2 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1850000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/mfd.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/mfd.txt new file mode 100644 index 0000000000000000000000000000000000000000..336c0495c8a3a21bb33758b4cff3d1d600a9a133 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/mfd.txt @@ -0,0 +1,51 @@ +Multi-Function Devices (MFD) + +These devices comprise a nexus for heterogeneous hardware blocks containing +more than one non-unique yet varying hardware functionality. + +A typical MFD can be: + +- A mixed signal ASIC on an external bus, sometimes a PMIC (Power Management + Integrated Circuit) that is manufactured in a lower technology node (rough + silicon) that handles analog drivers for things like audio amplifiers, LED + drivers, level shifters, PHY (physical interfaces to things like USB or + ethernet), regulators etc. + +- A range of memory registers containing "miscellaneous system registers" also + known as a system controller "syscon" or any other memory range containing a + mix of unrelated hardware devices. + +Optional properties: + +- compatible : "simple-mfd" - this signifies that the operating system should + consider all subnodes of the MFD device as separate devices akin to how + "simple-bus" indicates when to see subnodes as children for a simple + memory-mapped bus. For more complex devices, when the nexus driver has to + probe registers to figure out what child devices exist etc, this should not + be used. In the latter case the child devices will be determined by the + operating system. + +- ranges: Describes the address mapping relationship to the parent. Should set + the child's base address to 0, the physical address within parent's address + space, and the length of the address map. + +- #address-cells: Specifies the number of cells used to represent physical base + addresses. Must be present if ranges is used. + +- #size-cells: Specifies the number of cells used to represent the size of an + address. Must be present if ranges is used. + +Example: + +foo@1000 { + compatible = "syscon", "simple-mfd"; + reg = <0x01000 0x1000>; + + led@8.0 { + compatible = "register-bit-led"; + offset = <0x08>; + mask = <0x01>; + label = "myled"; + default-state = "on"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/motorola-cpcap.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/motorola-cpcap.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ddcc8f4febc08b631a23d9bd15d35921267ffaa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/motorola-cpcap.txt @@ -0,0 +1,72 @@ +Motorola CPCAP PMIC device tree binding + +Required properties: +- compatible : One or both of "motorola,cpcap" or "ste,6556002" +- reg : SPI chip select +- interrupts : The interrupt line the device is connected to +- interrupt-controller : Marks the device node as an interrupt controller +- #interrupt-cells : The number of cells to describe an IRQ, should be 2 +- #address-cells : Child device offset number of cells, should be 1 +- #size-cells : Child device size number of cells, should be 0 +- spi-max-frequency : Typically set to 3000000 +- spi-cs-high : SPI chip select direction + +Optional subnodes: + +The sub-functions of CPCAP get their own node with their own compatible values, +which are described in the following files: + +- ../power/supply/cpcap-battery.txt +- ../power/supply/cpcap-charger.txt +- ../regulator/cpcap-regulator.txt +- ../phy/phy-cpcap-usb.txt +- ../input/cpcap-pwrbutton.txt +- ../rtc/cpcap-rtc.txt +- ../leds/leds-cpcap.txt +- ../iio/adc/cpcap-adc.txt + +The only exception is the audio codec. Instead of a compatible value its +node must be named "audio-codec". + +Required properties for the audio-codec subnode: + +- #sound-dai-cells = <1>; + +The audio-codec provides two DAIs. The first one is connected to the +Stereo HiFi DAC and the second one is connected to the Voice DAC. + +Example: + +&mcspi1 { + cpcap: pmic@0 { + compatible = "motorola,cpcap", "ste,6556002"; + reg = <0>; /* cs0 */ + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_EDGE_RISING>; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <3000000>; + spi-cs-high; + + audio-codec { + #sound-dai-cells = <1>; + + /* HiFi */ + port@0 { + endpoint { + remote-endpoint = <&cpu_dai1>; + }; + }; + + /* Voice */ + port@1 { + endpoint { + remote-endpoint = <&cpu_dai2>; + }; + }; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/mt6397.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/mt6397.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ebd08af777d4d461c13e1d414627ea209d4af81 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/mt6397.txt @@ -0,0 +1,83 @@ +MediaTek MT6397/MT6323 Multifunction Device Driver + +MT6397/MT6323 is a multifunction device with the following sub modules: +- Regulator +- RTC +- Audio codec +- GPIO +- Clock +- LED +- Keys + +It is interfaced to host controller using SPI interface by a proprietary hardware +called PMIC wrapper or pwrap. MT6397/MT6323 MFD is a child device of pwrap. +See the following for pwarp node definitions: +Documentation/devicetree/bindings/soc/mediatek/pwrap.txt + +This document describes the binding for MFD device and its sub module. + +Required properties: +compatible: "mediatek,mt6397" or "mediatek,mt6323" + +Optional subnodes: + +- rtc + Required properties: + - compatible: "mediatek,mt6397-rtc" +- regulators + Required properties: + - compatible: "mediatek,mt6397-regulator" + see Documentation/devicetree/bindings/regulator/mt6397-regulator.txt + - compatible: "mediatek,mt6323-regulator" + see Documentation/devicetree/bindings/regulator/mt6323-regulator.txt +- codec + Required properties: + - compatible: "mediatek,mt6397-codec" +- clk + Required properties: + - compatible: "mediatek,mt6397-clk" +- led + Required properties: + - compatible: "mediatek,mt6323-led" + see Documentation/devicetree/bindings/leds/leds-mt6323.txt + +- keys + Required properties: + - compatible: "mediatek,mt6397-keys" or "mediatek,mt6323-keys" + see Documentation/devicetree/bindings/input/mtk-pmic-keys.txt + +Example: + pwrap: pwrap@1000f000 { + compatible = "mediatek,mt8135-pwrap"; + + ... + + pmic { + compatible = "mediatek,mt6397"; + + codec: mt6397codec { + compatible = "mediatek,mt6397-codec"; + }; + + regulators { + compatible = "mediatek,mt6397-regulator"; + + mt6397_vpca15_reg: buck_vpca15 { + regulator-compatible = "buck_vpca15"; + regulator-name = "vpca15"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <12500>; + regulator-always-on; + }; + + mt6397_vgp4_reg: ldo_vgp4 { + regulator-compatible = "ldo_vgp4"; + regulator-name = "vgp4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/mxs-lradc.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/mxs-lradc.txt new file mode 100644 index 0000000000000000000000000000000000000000..755cbef0647df9d07ac7921526f103b4736360c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/mxs-lradc.txt @@ -0,0 +1,45 @@ +* Freescale MXS LRADC device driver + +Required properties: +- compatible: Should be "fsl,imx23-lradc" for i.MX23 SoC and "fsl,imx28-lradc" + for i.MX28 SoC +- reg: Address and length of the register set for the device +- interrupts: Should contain the LRADC interrupts + +Optional properties: +- fsl,lradc-touchscreen-wires: Number of wires used to connect the touchscreen + to LRADC. Valid value is either 4 or 5. If this + property is not present, then the touchscreen is + disabled. 5 wires is valid for i.MX28 SoC only. +- fsl,ave-ctrl: number of samples per direction to calculate an average value. + Allowed value is 1 ... 32, default is 4 +- fsl,ave-delay: delay between consecutive samples. Allowed value is + 2 ... 2048. It is used if 'fsl,ave-ctrl' > 1, counts at + 2 kHz and its default is 2 (= 1 ms) +- fsl,settling: delay between plate switch to next sample. Allowed value is + 1 ... 2047. It counts at 2 kHz and its default is + 10 (= 5 ms) + +Example for i.MX23 SoC: + + lradc@80050000 { + compatible = "fsl,imx23-lradc"; + reg = <0x80050000 0x2000>; + interrupts = <36 37 38 39 40 41 42 43 44>; + fsl,lradc-touchscreen-wires = <4>; + fsl,ave-ctrl = <4>; + fsl,ave-delay = <2>; + fsl,settling = <10>; + }; + +Example for i.MX28 SoC: + + lradc@80050000 { + compatible = "fsl,imx28-lradc"; + reg = <0x80050000 0x2000>; + interrupts = <10 14 15 16 17 18 19 20 21 22 23 24 25>; + fsl,lradc-touchscreen-wires = <5>; + fsl,ave-ctrl = <4>; + fsl,ave-delay = <2>; + fsl,settling = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/omap-usb-host.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/omap-usb-host.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa1eaa59581be9ab66be663fa55b502c99a5bcce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/omap-usb-host.txt @@ -0,0 +1,103 @@ +OMAP HS USB Host + +Required properties: + +- compatible: should be "ti,usbhs-host" +- reg: should contain one register range i.e. start and length +- ti,hwmods: must contain "usb_host_hs" + +Optional properties: + +- num-ports: number of USB ports. Usually this is automatically detected + from the IP's revision register but can be overridden by specifying + this property. A maximum of 3 ports are supported at the moment. + +- portN-mode: String specifying the port mode for port N, where N can be + from 1 to 3. If the port mode is not specified, that port is treated + as unused. When specified, it must be one of the following. + "ehci-phy", + "ehci-tll", + "ehci-hsic", + "ohci-phy-6pin-datse0", + "ohci-phy-6pin-dpdm", + "ohci-phy-3pin-datse0", + "ohci-phy-4pin-dpdm", + "ohci-tll-6pin-datse0", + "ohci-tll-6pin-dpdm", + "ohci-tll-3pin-datse0", + "ohci-tll-4pin-dpdm", + "ohci-tll-2pin-datse0", + "ohci-tll-2pin-dpdm", + +- single-ulpi-bypass: Must be present if the controller contains a single + ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1 + +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + +- clock-names: should include: + For OMAP3 + * "usbhost_120m_fck" - 120MHz Functional clock. + + For OMAP4+ + * "refclk_60m_int" - 60MHz internal reference clock for UTMI clock mux + * "refclk_60m_ext_p1" - 60MHz external ref. clock for Port 1's UTMI clock mux. + * "refclk_60m_ext_p2" - 60MHz external ref. clock for Port 2's UTMI clock mux + * "utmi_p1_gfclk" - Port 1 UTMI clock mux. + * "utmi_p2_gfclk" - Port 2 UTMI clock mux. + * "usb_host_hs_utmi_p1_clk" - Port 1 UTMI clock gate. + * "usb_host_hs_utmi_p2_clk" - Port 2 UTMI clock gate. + * "usb_host_hs_utmi_p3_clk" - Port 3 UTMI clock gate. + * "usb_host_hs_hsic480m_p1_clk" - Port 1 480MHz HSIC clock gate. + * "usb_host_hs_hsic480m_p2_clk" - Port 2 480MHz HSIC clock gate. + * "usb_host_hs_hsic480m_p3_clk" - Port 3 480MHz HSIC clock gate. + * "usb_host_hs_hsic60m_p1_clk" - Port 1 60MHz HSIC clock gate. + * "usb_host_hs_hsic60m_p2_clk" - Port 2 60MHz HSIC clock gate. + * "usb_host_hs_hsic60m_p3_clk" - Port 3 60MHz HSIC clock gate. + +Required properties if child node exists: + +- #address-cells: Must be 1 +- #size-cells: Must be 1 +- ranges: must be present + +Properties for children: + +The OMAP HS USB Host subsystem contains EHCI and OHCI controllers. +See Documentation/devicetree/bindings/usb/ehci-omap.txt and +Documentation/devicetree/bindings/usb/ohci-omap3.txt. + +Example for OMAP4: + +usbhshost: usbhshost@4a064000 { + compatible = "ti,usbhs-host"; + reg = <0x4a064000 0x800>; + ti,hwmods = "usb_host_hs"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + usbhsohci: ohci@4a064800 { + compatible = "ti,ohci-omap3", "usb-ohci"; + reg = <0x4a064800 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 76 0x4>; + }; + + usbhsehci: ehci@4a064c00 { + compatible = "ti,ehci-omap", "usb-ehci"; + reg = <0x4a064c00 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 77 0x4>; + }; +}; + +&usbhshost { + port1-mode = "ehci-phy"; + port2-mode = "ehci-tll"; + port3-mode = "ehci-phy"; +}; + +&usbhsehci { + phys = <&hsusb1_phy 0 &hsusb3_phy>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/omap-usb-tll.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/omap-usb-tll.txt new file mode 100644 index 0000000000000000000000000000000000000000..c58d70437fce8b0dd11636a5a5f98946d8674d42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/omap-usb-tll.txt @@ -0,0 +1,27 @@ +OMAP HS USB Host TLL (Transceiver-Less Interface) + +Required properties: + +- compatible : should be "ti,usbhs-tll" +- reg : should contain one register range i.e. start and length +- interrupts : should contain the TLL module's interrupt +- ti,hwmod : must contain "usb_tll_hs" + +Optional properties: + +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + +- clock-names: should include: + * "usb_tll_hs_usb_ch0_clk" - USB TLL channel 0 clock + * "usb_tll_hs_usb_ch1_clk" - USB TLL channel 1 clock + * "usb_tll_hs_usb_ch2_clk" - USB TLL channel 2 clock + +Example: + + usbhstll: usbhstll@4a062000 { + compatible = "ti,usbhs-tll"; + reg = <0x4a062000 0x1000>; + interrupts = <78>; + ti,hwmods = "usb_tll_hs"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/palmas.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/palmas.txt new file mode 100644 index 0000000000000000000000000000000000000000..e736ab3012a63e6b1df863e62d176577547b78ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/palmas.txt @@ -0,0 +1,52 @@ +* palmas device tree bindings + +The TI palmas family current members :- +twl6035 (palmas) +twl6037 (palmas) +tps65913 (palmas) +tps65914 (palmas) +tps659038 +tps65917 + +Required properties: +- compatible : Should be from the list + ti,twl6035 + ti,twl6036 + ti,twl6037 + ti,tps65913 + ti,tps65914 + ti,tps80036 + ti,tps659038 + ti,tps65917 +and also the generic series names + ti,palmas +- interrupt-controller : palmas has its own internal IRQs +- #interrupt-cells : should be set to 2 for IRQ number and flags + The first cell is the IRQ number. + The second cell is the flags, encoded as the trigger masks from + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Optional properties: + ti,mux-padX : set the pad register X (1-2) to the correct muxing for the + hardware, if not set will use muxing in OTP. + +Example: + +palmas { + compatible = "ti,twl6035", "ti,palmas"; + reg = <0x48> + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <2>; + + ti,mux-pad1 = <0>; + ti,mux-pad2 = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + pmic { + compatible = "ti,twl6035-pmic", "ti,palmas-pmic"; + .... + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/qcom,spmi-pmic.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom,spmi-pmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..272e9c02c895911fdfeae61b063dc4ac6b84091f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom,spmi-pmic.txt @@ -0,0 +1,80 @@ + Qualcomm SPMI PMICs multi-function device bindings + +The Qualcomm SPMI series presently includes PM8941, PM8841 and PMA8084 +PMICs. These PMICs use a QPNP scheme through SPMI interface. +QPNP is effectively a partitioning scheme for dividing the SPMI extended +register space up into logical pieces, and set of fixed register +locations/definitions within these regions, with some of these regions +specifically used for interrupt handling. + +The QPNP PMICs are used with the Qualcomm Snapdragon series SoCs, and are +interfaced to the chip via the SPMI (System Power Management Interface) bus. +Support for multiple independent functions are implemented by splitting the +16-bit SPMI slave address space into 256 smaller fixed-size regions, 256 bytes +each. A function can consume one or more of these fixed-size register regions. + +Required properties: +- compatible: Should contain one of: + "qcom,pm8941", + "qcom,pm8841", + "qcom,pma8084", + "qcom,pm8019", + "qcom,pm8226", + "qcom,pm8110", + "qcom,pma8084", + "qcom,pmi8962", + "qcom,pmd9635", + "qcom,pm8994", + "qcom,pmi8994", + "qcom,pm8916", + "qcom,pm8004", + "qcom,pm8909", + "qcom,pm8998", + "qcom,pmi8998", + "qcom,pm8005", + or generalized "qcom,spmi-pmic". +- reg: Specifies the SPMI USID slave address for this device. + For more information see: + Documentation/devicetree/bindings/spmi/spmi.txt + +Required properties for peripheral child nodes: +- compatible: Should contain "qcom,xxx", where "xxx" is a peripheral name. + +Optional properties for peripheral child nodes: +- interrupts: Interrupts are specified as a 4-tuple. For more information + see: + Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt +- interrupt-names: Corresponding interrupt name to the interrupts property +- qcom,can-sleep: Boolean flag indicating that processes waiting on SPMI + transactions may sleep + +Each child node of SPMI slave id represents a function of the PMIC. In the +example below the rtc device node represents a peripheral of pm8941 +SID = 0. The regulator device node represents a peripheral of pm8941 SID = 1. + +Example: + + spmi { + compatible = "qcom,spmi-pmic-arb"; + + pm8941@0 { + compatible = "qcom,pm8941", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + + rtc { + compatible = "qcom,rtc"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "alarm"; + }; + }; + + pm8941@1 { + compatible = "qcom,pm8941", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + + regulator { + compatible = "qcom,regulator"; + regulator-name = "8941_boost"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/qcom,tcsr.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom,tcsr.txt new file mode 100644 index 0000000000000000000000000000000000000000..e90519d566a30a1a3ca2c003f15660d84b32a792 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom,tcsr.txt @@ -0,0 +1,22 @@ +QCOM Top Control and Status Register + +Qualcomm devices have a set of registers that provide various control and status +functions for their peripherals. This node is intended to allow access to these +registers via syscon. + +Required properties: +- compatible: Should contain: + "qcom,tcsr-ipq8064", "syscon" for IPQ8064 + "qcom,tcsr-apq8064", "syscon" for APQ8064 + "qcom,tcsr-msm8660", "syscon" for MSM8660 + "qcom,tcsr-msm8960", "syscon" for MSM8960 + "qcom,tcsr-msm8974", "syscon" for MSM8974 + "qcom,tcsr-apq8084", "syscon" for APQ8084 + "qcom,tcsr-msm8916", "syscon" for MSM8916 +- reg: Address range for TCSR registers + +Example: + tcsr: syscon@1a400000 { + compatible = "qcom,tcsr-msm8960", "syscon"; + reg = <0x1a400000 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-i2c-pmic.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-i2c-pmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..a63b7e26ae7c73950e792d88cf046dce88bb945a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-i2c-pmic.txt @@ -0,0 +1,103 @@ +Qualcomm Technologies, Inc. I2C PMIC Interrupt Controller +Platform Independent Bindings + +The I2C PMIC Controller is used by multi-function PMIC devices which communicate +over the I2C bus. An I2C PMIC controller node typically contains one or more +child nodes representing the device's peripherals. Each of the peripherals +typically has its own driver on the platform bus and will be enumerated by this +controller. The controller exposes a regmap to the peripherals to communicate +over the I2C bus. + +The controller also controls interrupts for all of the peripherals on the bus. +The controller takes a summary interrupt, deciphers which peripheral triggered +the interrupt, and which of the peripheral's interrupts were triggered. Finally, +it calls the handlers for each of the virtual interrupts that were registered. + +This document describes the common platform independent bindings that apply +to all I2C PMIC interrupt controllers. + +======================================== +First Level Nodes - I2C PMIC Controllers +======================================== + +Platform independent properties: +- compatible + Usage: required + Value type: + Definition: Must be "qcom,i2c-pmic". + +- reg + Usage: required + Value type: + Definition: 7-bit I2C address of the device. + +- interrupt-parent + Usage: optional + Value type: + Definition: phandle of the interrupt controller which services the + summary interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Summary interrupt specifier. + +- interrupt-controller + Usage: optional + Value type: + Definition: Boolean flag which indicates this device node is an + interrupt controller. + +- #interrupt-cells + Usage: optional + Value type: + Definition: Number of cells to encode an interrupt source. + +- qcom,periph-map + Usage: optional + Value type: + Definition: A list of u32 arrays. This provides a mapping between the + summary status register bits and peripheral addresses. + + The number of arrays should match the number of summary + registers with up to 8 elements each. One element per bit + of the summary status register in order from the least + sigificant bit to the most significant bit. + +- pinctrl-names + Usage: optional + Value type: + Definition: Should be "default". + Please refer to pinctrl-bindings.txt + +- pinctrl-0 + Usage: optional + Value type: + Definition: phandle of the pin configuration. + Please refer to pinctrl-bindings.txt + +- qcom,enable-toggle-stat + Usage: optional + Value type: bool + Definition: Enables stat interrupt toggle at init. + +======= +Example +======= + +&i2c_3 { + status = "ok"; + qcom,smb138x@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <83 0>; + interrupt-controller; + #interrupt-cells = <3>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_active>; + #address-cells = <1>; + #size-cells = <0>; + qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-pm8xxx.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-pm8xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..07f49254f3661acf1bbbff0b5c2882e01c482159 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-pm8xxx.txt @@ -0,0 +1,100 @@ +Qualcomm PM8xxx PMIC multi-function devices + +The PM8xxx family of Power Management ICs are used to provide regulated +voltages and other various functionality to Qualcomm SoCs. + += PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8058" + "qcom,pm8821" + "qcom,pm8921" + +- #address-cells: + Usage: required + Value type: + Definition: must be 1 + +- #size-cells: + Usage: required + Value type: + Definition: must be 0 + +- interrupts: + Usage: required + Value type: + Definition: specifies the interrupt that indicates a subdevice + has generated an interrupt (summary interrupt). The + format of the specifier is defined by the binding document + describing the node's interrupt parent. + +- #interrupt-cells: + Usage: required + Value type : + Definition: must be 2. Specifies the number of cells needed to encode + an interrupt source. The 1st cell contains the interrupt + number. The 2nd cell is the trigger type and level flags + encoded as follows: + + 1 = low-to-high edge triggered + 2 = high-to-low edge triggered + 4 = active high level-sensitive + 8 = active low level-sensitive + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + += SUBCOMPONENTS + +The PMIC contains multiple independent functions, each described in a subnode. +The below bindings specify the set of valid subnodes. + +== Real-Time Clock + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8058-rtc" + "qcom,pm8921-rtc" + "qcom,pm8941-rtc" + "qcom,pm8018-rtc" + "qcom,pmk8350-rtc" + +- reg: + Usage: required + Value type: + Definition: single entry specifying the base address of the RTC registers + +- interrupts: + Usage: required + Value type: + Definition: single entry specifying the RTC's alarm interrupt + +- allow-set-time: + Usage: optional + Value type: + Definition: indicates that the setting of RTC time is allowed by + the host CPU + += EXAMPLE + + pmicintc: pmic@0 { + compatible = "qcom,pm8921"; + interrupts = <104 8>; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + rtc@11d { + compatible = "qcom,pm8921-rtc"; + reg = <0x11d>; + interrupts = <0x27 0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-rpm.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-rpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c91ad430eea3fcc0b725a3e5fc591027d5cfe46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/qcom-rpm.txt @@ -0,0 +1,279 @@ +Qualcomm Resource Power Manager (RPM) + +This driver is used to interface with the Resource Power Manager (RPM) found in +various Qualcomm platforms. The RPM allows each component in the system to vote +for state of the system resources, such as clocks, regulators and bus +frequencies. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-apq8064" + "qcom,rpm-msm8660" + "qcom,rpm-msm8960" + "qcom,rpm-ipq8064" + "qcom,rpm-mdm9615" + +- reg: + Usage: required + Value type: + Definition: base address and size of the RPM's message ram + +- interrupts: + Usage: required + Value type: + Definition: three entries specifying the RPM's: + 1. acknowledgement interrupt + 2. error interrupt + 3. wakeup interrupt + +- interrupt-names: + Usage: required + Value type: + Definition: must be the three strings "ack", "err" and "wakeup", in order + +- qcom,ipc: + Usage: required + Value type: + + Definition: three entries specifying the outgoing ipc bit used for + signaling the RPM: + - phandle to a syscon node representing the apcs registers + - u32 representing offset to the register within the syscon + - u32 representing the ipc bit within the register + + += SUBNODES + +The RPM exposes resources to its subnodes. The below bindings specify the set +of valid subnodes that can operate on these resources. + +== Regulators + +Regulator nodes are identified by their compatible: + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-pm8058-regulators" + "qcom,rpm-pm8901-regulators" + "qcom,rpm-pm8921-regulators" + "qcom,rpm-pm8018-regulators" + +- vdd_l0_l1_lvs-supply: +- vdd_l2_l11_l12-supply: +- vdd_l3_l4_l5-supply: +- vdd_l6_l7-supply: +- vdd_l8-supply: +- vdd_l9-supply: +- vdd_l10-supply: +- vdd_l13_l16-supply: +- vdd_l14_l15-supply: +- vdd_l17_l18-supply: +- vdd_l19_l20-supply: +- vdd_l21-supply: +- vdd_l22-supply: +- vdd_l23_l24_l25-supply: +- vdd_ncp-supply: +- vdd_s0-supply: +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: + Usage: optional (pm8058 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- lvs0_in-supply: +- lvs1_in-supply: +- lvs2_in-supply: +- lvs3_in-supply: +- mvs_in-supply: +- vdd_l0-supply: +- vdd_l1-supply: +- vdd_l2-supply: +- vdd_l3-supply: +- vdd_l4-supply: +- vdd_l5-supply: +- vdd_l6-supply: +- vdd_s0-supply: +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: + Usage: optional (pm8901 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_l1_l2_l12_l18-supply: +- vdd_l3_l15_l17-supply: +- vdd_l4_l14-supply: +- vdd_l5_l8_l16-supply: +- vdd_l6_l7-supply: +- vdd_l9_l11-supply: +- vdd_l10_l22-supply: +- vdd_l21_l23_l29-supply: +- vdd_l24-supply: +- vdd_l25-supply: +- vdd_l26-supply: +- vdd_l27-supply: +- vdd_l28-supply: +- vdd_ncp-supply: +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: +- vin_5vs-supply: +- vin_lvs1_3_6-supply: +- vin_lvs2-supply: +- vin_lvs4_5_7-supply: + Usage: optional (pm8921 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vin_lvs1-supply: +- vdd_l7-supply: +- vdd_l8-supply: +- vdd_l9_l10_l11_l12-supply: + Usage: optional (pm8018 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +The regulator node houses sub-nodes for each regulator within the device. Each +sub-node is identified using the node's name, with valid values listed for each +of the pmics below. + +pm8058: + l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, + l16, l17, l18, l19, l20, l21, l22, l23, l24, l25, s0, s1, s2, s3, s4, + lvs0, lvs1, ncp + +pm8901: + l0, l1, l2, l3, l4, l5, l6, s0, s1, s2, s3, s4, lvs0, lvs1, lvs2, lvs3, + mvs + +pm8921: + s1, s2, s3, s4, s7, s8, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, + l12, l14, l15, l16, l17, l18, l21, l22, l23, l24, l25, l26, l27, l28, + l29, lvs1, lvs2, lvs3, lvs4, lvs5, lvs6, lvs7, usb-switch, hdmi-switch, + ncp + +pm8018: + s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, + l12, l14, lvs1 + +The content of each sub-node is defined by the standard binding for regulators - +see regulator.txt - with additional custom properties described below: + +=== Switch-mode Power Supply regulator custom properties + +- bias-pull-down: + Usage: optional + Value type: + Definition: enable pull down of the regulator when inactive + +- qcom,switch-mode-frequency: + Usage: required + Value type: + Definition: Frequency (Hz) of the switch-mode power supply; + must be one of: + 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, + 2740000, 2400000, 2130000, 1920000, 1750000, 1600000, + 1480000, 1370000, 1280000, 1200000 + +- qcom,force-mode: + Usage: optional (default if no other qcom,force-mode is specified) + Value type: + Definition: indicates that the regulator should be forced to a + particular mode, valid values are: + QCOM_RPM_FORCE_MODE_NONE - do not force any mode + QCOM_RPM_FORCE_MODE_LPM - force into low power mode + QCOM_RPM_FORCE_MODE_HPM - force into high power mode + QCOM_RPM_FORCE_MODE_AUTO - allow regulator to automatically + select its own mode based on + realtime current draw, only for: + pm8921 smps and ftsmps + +- qcom,power-mode-hysteretic: + Usage: optional + Value type: + Definition: select that the power supply should operate in hysteretic + mode, instead of the default pwm mode + +=== Low-dropout regulator custom properties + +- bias-pull-down: + Usage: optional + Value type: + Definition: enable pull down of the regulator when inactive + +- qcom,force-mode: + Usage: optional + Value type: + Definition: indicates that the regulator should not be forced to any + particular mode, valid values are: + QCOM_RPM_FORCE_MODE_NONE - do not force any mode + QCOM_RPM_FORCE_MODE_LPM - force into low power mode + QCOM_RPM_FORCE_MODE_HPM - force into high power mode + QCOM_RPM_FORCE_MODE_BYPASS - set regulator to use bypass + mode, i.e. to act as a switch + and not regulate, only for: + pm8921 pldo, nldo and nldo1200 + +=== Negative Charge Pump custom properties + +- qcom,switch-mode-frequency: + Usage: required + Value type: + Definition: Frequency (Hz) of the switch mode power supply; + must be one of: + 19200000, 9600000, 6400000, 4800000, 3840000, 3200000, + 2740000, 2400000, 2130000, 1920000, 1750000, 1600000, + 1480000, 1370000, 1280000, 1200000 + += EXAMPLE + + #include + + rpm@108000 { + compatible = "qcom,rpm-msm8960"; + reg = <0x108000 0x1000>; + qcom,ipc = <&apcs 0x8 2>; + + interrupts = <0 19 0>, <0 21 0>, <0 22 0>; + interrupt-names = "ack", "err", "wakeup"; + + regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vdd_l1_l2_l12_l18-supply = <&pm8921_s4>; + + s1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + + bias-pull-down; + + qcom,switch-mode-frequency = <3200000>; + }; + + pm8921_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + + qcom,force-mode = ; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/qriox.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/qriox.txt new file mode 100644 index 0000000000000000000000000000000000000000..f301e2d4ce7660f28b0d1a9ba6616d8e76296f40 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/qriox.txt @@ -0,0 +1,17 @@ +KEYMILE qrio Board Control CPLD + +The qrio is a multifunction device that controls the KEYMILE boards based on +the kmp204x design. +It is consists of a reset controller, watchdog timer, LEDs, and 2 IRQ capable +GPIO blocks. + +Required properties: +- compatible: "keymile,qriox" +- reg: access on the parent local bus (chip select, offset in chip select, size) + +Example: + + board-control@1,0 { + compatible = "keymile,qriox"; + reg = <1 0 0x80>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/retu.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/retu.txt new file mode 100644 index 0000000000000000000000000000000000000000..df3005dd3e3c05ed0d23f79e288af34cf6c73efd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/retu.txt @@ -0,0 +1,24 @@ +* Device tree bindings for Nokia Retu and Tahvo multi-function device + +Retu and Tahvo are a multi-function devices found on Nokia Internet +Tablets (770, N800 and N810). The Retu chip provides watchdog timer +and power button control functionalities while Tahvo chip provides +USB transceiver functionality. + +Required properties: +- compatible: "nokia,retu" or "nokia,tahvo" +- reg: Specifies the CBUS slave address of the ASIC chip +- interrupts: The interrupt line the device is connected to + +Example: + +cbus0 { + compatible = "i2c-cbus-gpio"; + ... + retu: retu@1 { + compatible = "nokia,retu"; + interrupt-parent = <&gpio4>; + interrupts = <12 IRQ_TYPE_EDGE_RISING>; + reg = <0x1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/rk808.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/rk808.txt new file mode 100644 index 0000000000000000000000000000000000000000..1683ec3245bcd1b2bf291ef9bb3ef9e045d16850 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/rk808.txt @@ -0,0 +1,233 @@ +RK8XX Power Management Integrated Circuit + +The rk8xx family current members: +rk805 +rk808 +rk818 + +Required properties: +- compatible: "rockchip,rk805" +- compatible: "rockchip,rk808" +- compatible: "rockchip,rk818" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller. +- #clock-cells: from common clock binding; shall be set to 1 (multiple clock + outputs). See for clock IDs. + +Optional properties: +- clock-output-names: From common clock binding to override the + default output clock name +- rockchip,system-power-controller: Telling whether or not this pmic is controlling + the system power. + +Optional RK805 properties: +- vcc1-supply: The input supply for DCDC_REG1 +- vcc2-supply: The input supply for DCDC_REG2 +- vcc3-supply: The input supply for DCDC_REG3 +- vcc4-supply: The input supply for DCDC_REG4 +- vcc5-supply: The input supply for LDO_REG1 and LDO_REG2 +- vcc6-supply: The input supply for LDO_REG3 + +Optional RK808 properties: +- vcc1-supply: The input supply for DCDC_REG1 +- vcc2-supply: The input supply for DCDC_REG2 +- vcc3-supply: The input supply for DCDC_REG3 +- vcc4-supply: The input supply for DCDC_REG4 +- vcc6-supply: The input supply for LDO_REG1 and LDO_REG2 +- vcc7-supply: The input supply for LDO_REG3 and LDO_REG7 +- vcc8-supply: The input supply for SWITCH_REG1 +- vcc9-supply: The input supply for LDO_REG4 and LDO_REG5 +- vcc10-supply: The input supply for LDO_REG6 +- vcc11-supply: The input supply for LDO_REG8 +- vcc12-supply: The input supply for SWITCH_REG2 +- dvs-gpios: buck1/2 can be controlled by gpio dvs, this is GPIO specifiers + for 2 host gpio's used for dvs. The format of the gpio specifier depends in + the gpio controller. If DVS GPIOs aren't present, voltage changes will happen + very quickly with no slow ramp time. + +Optional RK818 properties: +- vcc1-supply: The input supply for DCDC_REG1 +- vcc2-supply: The input supply for DCDC_REG2 +- vcc3-supply: The input supply for DCDC_REG3 +- vcc4-supply: The input supply for DCDC_REG4 +- boost-supply: The input supply for DCDC_BOOST +- vcc6-supply: The input supply for LDO_REG1 and LDO_REG2 +- vcc7-supply: The input supply for LDO_REG3, LDO_REG5 and LDO_REG7 +- vcc8-supply: The input supply for LDO_REG4, LDO_REG6 and LDO_REG8 +- vcc9-supply: The input supply for LDO_REG9 and SWITCH_REG +- h_5v-supply: The input supply for HDMI_SWITCH +- usb-supply: The input supply for OTG_SWITCH + +Regulators: All the regulators of RK8XX to be instantiated shall be +listed in a child node named 'regulators'. Each regulator is represented +by a child node of the 'regulators' node. + + regulator-name { + /* standard regulator bindings here */ + }; + +Following regulators of the RK805 PMIC regulators are supported. Note that +the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO +number as described in RK805 datasheet. + + - DCDC_REGn + - valid values for n are 1 to 4. + - LDO_REGn + - valid values for n are 1 to 3 + +Following regulators of the RK808 PMIC block are supported. Note that +the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO +number as described in RK808 datasheet. + + - DCDC_REGn + - valid values for n are 1 to 4. + - LDO_REGn + - valid values for n are 1 to 8. + - SWITCH_REGn + - valid values for n are 1 to 2 + +Following regulators of the RK818 PMIC block are supported. Note that +the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO +number as described in RK818 datasheet. + + - DCDC_REGn + - valid values for n are 1 to 4. + - LDO_REGn + - valid values for n are 1 to 9. + - SWITCH_REG + - HDMI_SWITCH + - OTG_SWITCH + +Standard regulator bindings are used inside regulator subnodes. Check + Documentation/devicetree/bindings/regulator/regulator.txt +for more details + +Example: + rk808: pmic@1b { + compatible = "rockchip,rk808"; + clock-output-names = "xin32k", "rk808-clkout2"; + interrupt-parent = <&gpio0>; + interrupts = <4 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int &dvs_1 &dvs_2>; + dvs-gpios = <&gpio7 11 GPIO_ACTIVE_HIGH>, + <&gpio7 15 GPIO_ACTIVE_HIGH>; + reg = <0x1b>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + + vcc8-supply = <&vcc_18>; + vcc9-supply = <&vcc_io>; + vcc10-supply = <&vcc_io>; + vcc12-supply = <&vcc_io>; + vddio-supply = <&vccio_pmu>; + + regulators { + vdd_cpu: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1300000>; + regulator-name = "vdd_arm"; + }; + + vdd_gpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <1250000>; + regulator-name = "vdd_gpu"; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_ddr"; + }; + + vcc_io: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_io"; + }; + + vccio_pmu: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_pmu"; + }; + + vcc_tp: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_tp"; + }; + + vdd_10: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd_10"; + }; + + vcc18_lcd: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc18_lcd"; + }; + + vccio_sd: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + }; + + vdd10_lcd: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-name = "vdd10_lcd"; + }; + + vcc_18: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_18"; + }; + + vcca_codec: LDO_REG8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcca_codec"; + }; + + vcc_wl: SWITCH_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_wl"; + }; + + vcc_lcd: SWITCH_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_lcd"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/rn5t618.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/rn5t618.txt new file mode 100644 index 0000000000000000000000000000000000000000..65c23263cc5418db378215612f152f8d887613f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/rn5t618.txt @@ -0,0 +1,43 @@ +* Ricoh RN5T567/RN5T618 PMIC + +Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which +integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators, +GPIOs, and a watchdog timer. It can be controlled through an I2C interface. +The RN5T618/RC5T619 provides additionally a Li-ion battery charger, +fuel gauge, and an ADC. +The RC5T619 additionnally includes USB charger detection and an RTC. + +Required properties: + - compatible: must be one of + "ricoh,rn5t567" + "ricoh,rn5t618" + "ricoh,rc5t619" + - reg: the I2C slave address of the device + +Sub-nodes: + - regulators: the node is required if the regulator functionality is + needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4 + (RN5T567/RC5T619), LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, LDO8, + LDO9, LDO10, LDORTC1 and LDORTC2. + LDO7-10 are specific to RC5T619. + The common bindings for each individual regulator can be found in: + Documentation/devicetree/bindings/regulator/regulator.txt + +Example: + + pmic@32 { + compatible = "ricoh,rn5t618"; + reg = <0x32>; + + regulators { + DCDC1 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + DCDC2 { + regulator-min-microvolt = <1175000>; + regulator-max-microvolt = <1175000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/rohm,bd71837-pmic.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/rohm,bd71837-pmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ca56fdb5ffeeb1233f39ec81716bd408104a678 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/rohm,bd71837-pmic.txt @@ -0,0 +1,62 @@ +* ROHM BD71837 Power Management Integrated Circuit bindings + +BD71837MWV is a programmable Power Management IC for powering single-core, +dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is optimized for +low BOM cost and compact solution footprint. It integrates 8 Buck +egulators and 7 LDOs to provide all the power rails required by the SoC and +the commonly used peripherals. + +Datasheet for PMIC is available at: +https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e + +Required properties: + - compatible : Should be "rohm,bd71837". + - reg : I2C slave address. + - interrupt-parent : Phandle to the parent interrupt controller. + - interrupts : The interrupt line the device is connected to. + - clocks : The parent clock connected to PMIC. If this is missing + 32768 KHz clock is assumed. + - #clock-cells : Should be 0. + - regulators: : List of child nodes that specify the regulators. + Please see ../regulator/rohm,bd71837-regulator.txt + +Optional properties: +- clock-output-names : Should contain name for output clock. + +Example: + + /* external oscillator node */ + osc: oscillator { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <32768>; + clock-output-names = "osc"; + }; + + pmic: pmic@4b { + compatible = "rohm,bd71837"; + reg = <0x4b>; + interrupt-parent = <&gpio1>; + interrupts = <29 GPIO_ACTIVE_LOW>; + interrupt-names = "irq"; + #clock-cells = <0>; + clocks = <&osc 0>; + clock-output-names = "bd71837-32k-out"; + + regulators { + buck1: BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; + }; + }; + }; + + /* Clock consumer node */ + rtc@0 { + compatible = "company,my-rtc"; + clock-names = "my-clock"; + clocks = <&pmic>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/samsung,exynos5433-lpass.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/samsung,exynos5433-lpass.txt new file mode 100644 index 0000000000000000000000000000000000000000..d759da606f757360d5498c92b41b713ffb66819c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/samsung,exynos5433-lpass.txt @@ -0,0 +1,72 @@ +Samsung Exynos SoC Low Power Audio Subsystem (LPASS) + +Required properties: + + - compatible : "samsung,exynos5433-lpass" + - reg : should contain the LPASS top SFR region location + and size + - clock-names : should contain following required clocks: "sfr0_ctrl" + - clocks : should contain clock specifiers of all clocks, which + input names have been specified in clock-names + property, in same order. + - #address-cells : should be 1 + - #size-cells : should be 1 + - ranges : must be present + +Each IP block of the Low Power Audio Subsystem should be specified as +an optional sub-node. For "samsung,exynos5433-lpass" compatible this includes: +UART, SLIMBUS, PCM, I2S, DMAC, Timers 0...4, VIC, WDT 0...1 devices. + +Bindings of the sub-nodes are described in: + ../serial/samsung_uart.txt + ../sound/samsung-i2s.txt + ../dma/arm-pl330.txt + + +Example: + +audio-subsystem { + compatible = "samsung,exynos5433-lpass"; + reg = <0x11400000 0x100>, <0x11500000 0x08>; + clocks = <&cmu_aud CLK_PCLK_SFR0_CTRL>; + clock-names = "sfr0_ctrl"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + adma: adma@11420000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x11420000 0x1000>; + interrupts = <0 73 0>; + clocks = <&cmu_aud CLK_ACLK_DMAC>; + clock-names = "apb_pclk"; + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <32>; + }; + + i2s0: i2s0@11440000 { + compatible = "samsung,exynos7-i2s"; + reg = <0x11440000 0x100>; + dmas = <&adma 0 &adma 2>; + dma-names = "tx", "rx"; + interrupts = <0 70 0>; + clocks = <&cmu_aud CLK_PCLK_AUD_I2S>, + <&cmu_aud CLK_SCLK_AUD_I2S>, + <&cmu_aud CLK_SCLK_I2S_BCLK>; + clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_bus>; + }; + + serial_3: serial@11460000 { + compatible = "samsung,exynos5433-uart"; + reg = <0x11460000 0x100>; + interrupts = <0 67 0>; + clocks = <&cmu_aud CLK_PCLK_AUD_UART>, + <&cmu_aud CLK_SCLK_AUD_UART>; + clock-names = "uart", "clk_uart_baud0"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_aud_bus>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/samsung,sec-core.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/samsung,sec-core.txt new file mode 100644 index 0000000000000000000000000000000000000000..c68cdd365153cbaaf4f00c0ca39c449109d0c227 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/samsung,sec-core.txt @@ -0,0 +1,86 @@ +Binding for Samsung S2M and S5M family multi-function device +============================================================ + +This is a part of device tree bindings for S2M and S5M family multi-function +devices. + +The Samsung S2MPA01, S2MPS11/13/14/15, S2MPU02 and S5M8767 is a family +of multi-function devices which include voltage and current regulators, RTC, +charger controller, clock outputs and other sub-blocks. It is interfaced +to the host controller using an I2C interface. Each sub-block is usually +addressed by the host system using different I2C slave addresses. + + +This document describes bindings for main device node. Optional sub-blocks +must be a sub-nodes to it. Bindings for them can be found in: + - bindings/regulator/samsung,s2mpa01.txt + - bindings/regulator/samsung,s2mps11.txt + - bindings/regulator/samsung,s5m8767.txt + - bindings/clock/samsung,s2mps11.txt + + +Required properties: + - compatible: Should be one of the following + - "samsung,s2mpa01-pmic", + - "samsung,s2mps11-pmic", + - "samsung,s2mps13-pmic", + - "samsung,s2mps14-pmic", + - "samsung,s2mps15-pmic", + - "samsung,s2mpu02-pmic", + - "samsung,s5m8767-pmic". + - reg: Specifies the I2C slave address of the pmic block. It should be 0x66. + +Optional properties: + - interrupts: Interrupt specifiers for interrupt sources. + - samsung,s2mps11-wrstbi-ground: Indicates that WRSTBI pin of PMIC is pulled + down. When the system is suspended it will always go down thus triggerring + unwanted buck warm reset (setting buck voltages to default values). + - samsung,s2mps11-acokb-ground: Indicates that ACOKB pin of S2MPS11 PMIC is + connected to the ground so the PMIC must manually set PWRHOLD bit in CTRL1 + register to turn off the power. Usually the ACOKB is pulled up to VBATT so + when PWRHOLD pin goes low, the rising ACOKB will trigger power off. + +Example: + + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + + s2m_osc: clocks { + compatible = "samsung,s2mps11-clk"; + #clock-cells = <1>; + clock-output-names = "xx", "yy", "zz"; + }; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ABB_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDD_ALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <50000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/sky81452.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/sky81452.txt new file mode 100644 index 0000000000000000000000000000000000000000..511764acd4d5f418664c014156788ebf8da06ec6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/sky81452.txt @@ -0,0 +1,35 @@ +SKY81452 bindings + +Required properties: +- compatible : Must be "skyworks,sky81452" +- reg : I2C slave address + +Required child nodes: +- backlight : container node for backlight following the binding + in leds/backlight/sky81452-backlight.txt +- regulator : container node for regulators following the binding + in regulator/sky81452-regulator.txt + +Example: + + sky81452@2c { + compatible = "skyworks,sky81452"; + reg = <0x2c>; + + backlight { + compatible = "skyworks,sky81452-backlight"; + name = "pwm-backlight"; + led-sources = <0 1 2 3 6>; + skyworks,ignore-pwm; + skyworks,phase-shift; + skyworks,current-limit = <2300>; + }; + + regulator { + lout { + regulator-name = "sky81452-lout"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <8000000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/sprd,sc27xx-pmic.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/sprd,sc27xx-pmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..21b9a897fca5db388efd2b688323846fcaace99b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/sprd,sc27xx-pmic.txt @@ -0,0 +1,40 @@ +Spreadtrum SC27xx Power Management Integrated Circuit (PMIC) + +The Spreadtrum SC27xx series PMICs contain SC2720, SC2721, SC2723, SC2730 +and SC2731. The Spreadtrum PMIC belonging to SC27xx series integrates all +mobile handset power management, audio codec, battery management and user +interface support function in a single chip. It has 6 major functional +blocks: +- DCDCs to support CPU, memory. +- LDOs to support both internal and external requirement. +- Battery management system, such as charger, fuel gauge. +- Audio codec. +- User interface function, such as indicator, flash LED and so on. +- IC level interface, such as power on/off control, RTC and typec and so on. + +Required properties: +- compatible: Should be one of the following: + "sprd,sc2720" + "sprd,sc2721" + "sprd,sc2723" + "sprd,sc2730" + "sprd,sc2731" +- reg: The address of the device chip select, should be 0. +- spi-max-frequency: Typically set to 26000000. +- interrupts: The interrupt line the device is connected to. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: The number of cells to describe an PMIC IRQ, must be 2. +- #address-cells: Child device offset number of cells, must be 1. +- #size-cells: Child device size number of cells, must be 0. + +Example: +pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/stm32-lptimer.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/stm32-lptimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a9ff29db9c9519697a3653edee8c0c2ed80be46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/stm32-lptimer.txt @@ -0,0 +1,48 @@ +STMicroelectronics STM32 Low-Power Timer + +The STM32 Low-Power Timer (LPTIM) is a 16-bit timer that provides several +functions: +- PWM output (with programmable prescaler, configurable polarity) +- Quadrature encoder, counter +- Trigger source for STM32 ADC/DAC (LPTIM_OUT) + +Required properties: +- compatible: Must be "st,stm32-lptimer". +- reg: Offset and length of the device's register set. +- clocks: Phandle to the clock used by the LP Timer module. +- clock-names: Must be "mux". +- #address-cells: Should be '<1>'. +- #size-cells: Should be '<0>'. + +Optional subnodes: +- pwm: See ../pwm/pwm-stm32-lp.txt +- counter: See ../iio/timer/stm32-lptimer-cnt.txt +- trigger: See ../iio/timer/stm32-lptimer-trigger.txt + +Example: + + timer@40002400 { + compatible = "st,stm32-lptimer"; + reg = <0x40002400 0x400>; + clocks = <&timer_clk>; + clock-names = "mux"; + #address-cells = <1>; + #size-cells = <0>; + + pwm { + compatible = "st,stm32-pwm-lp"; + pinctrl-names = "default"; + pinctrl-0 = <&lppwm1_pins>; + }; + + trigger@0 { + compatible = "st,stm32-lptimer-trigger"; + reg = <0>; + }; + + counter { + compatible = "st,stm32-lptimer-counter"; + pinctrl-names = "default"; + pinctrl-0 = <&lptim1_in_pins>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/stm32-timers.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/stm32-timers.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e900b52e8959cf2653c554f6f179bb2a44adab6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/stm32-timers.txt @@ -0,0 +1,66 @@ +STM32 Timers driver bindings + +This IP provides 3 types of timer along with PWM functionality: +- advanced-control timers consist of a 16-bit auto-reload counter driven by a programmable + prescaler, break input feature, PWM outputs and complementary PWM ouputs channels. +- general-purpose timers consist of a 16-bit or 32-bit auto-reload counter driven by a + programmable prescaler and PWM outputs. +- basic timers consist of a 16-bit auto-reload counter driven by a programmable prescaler. + +Required parameters: +- compatible: must be "st,stm32-timers" + +- reg: Physical base address and length of the controller's + registers. +- clock-names: Set to "int". +- clocks: Phandle to the clock used by the timer module. + For Clk properties, please refer to ../clock/clock-bindings.txt + +Optional parameters: +- resets: Phandle to the parent reset controller. + See ../reset/st,stm32-rcc.txt +- dmas: List of phandle to dma channels that can be used for + this timer instance. There may be up to 7 dma channels. +- dma-names: List of dma names. Must match 'dmas' property. Valid + names are: "ch1", "ch2", "ch3", "ch4", "up", "trig", + "com". + +Optional subnodes: +- pwm: See ../pwm/pwm-stm32.txt +- timer: See ../iio/timer/stm32-timer-trigger.txt + +Example: + timers@40010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32-timers"; + reg = <0x40010000 0x400>; + clocks = <&rcc 0 160>; + clock-names = "int"; + + pwm { + compatible = "st,stm32-pwm"; + pinctrl-0 = <&pwm1_pins>; + pinctrl-names = "default"; + }; + + timer@0 { + compatible = "st,stm32-timer-trigger"; + reg = <0>; + }; + }; + +Example with all dmas: + timer@40010000 { + ... + dmas = <&dmamux1 11 0x400 0x0>, + <&dmamux1 12 0x400 0x0>, + <&dmamux1 13 0x400 0x0>, + <&dmamux1 14 0x400 0x0>, + <&dmamux1 15 0x400 0x0>, + <&dmamux1 16 0x400 0x0>, + <&dmamux1 17 0x400 0x0>; + dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig", "com"; + ... + child nodes... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/stmpe.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/stmpe.txt new file mode 100644 index 0000000000000000000000000000000000000000..c797c05cd3c202da9e355f3ea21e8a2198a3af51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/stmpe.txt @@ -0,0 +1,28 @@ +* ST Microelectronics STMPE Multi-Functional Device + +STMPE is an MFD device which may expose the following inbuilt devices: gpio, +keypad, touchscreen, adc, pwm, rotator. + +Required properties: + - compatible : "st,stmpe[610|801|811|1600|1601|2401|2403]" + - reg : I2C/SPI address of the device + +Optional properties: + - interrupts : The interrupt outputs from the controller + - interrupt-controller : Marks the device node as an interrupt controller + - wakeup-source : Marks the input device as wakable + - st,autosleep-timeout : Valid entries (ms); 4, 16, 32, 64, 128, 256, 512 and 1024 + - irq-gpio : If present, which GPIO to use for event IRQ + +Example: + + stmpe1601: stmpe1601@40 { + compatible = "st,stmpe1601"; + reg = <0x40>; + interrupts = <26 0x4>; + interrupt-parent = <&gpio6>; + interrupt-controller; + + wakeup-source; + st,autosleep-timeout = <1024>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/sun4i-gpadc.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/sun4i-gpadc.txt new file mode 100644 index 0000000000000000000000000000000000000000..86dd8191b04c5e5787a5961b9129a5824089657a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/sun4i-gpadc.txt @@ -0,0 +1,59 @@ +Allwinner SoCs' GPADC Device Tree bindings +------------------------------------------ +The Allwinner SoCs all have an ADC that can also act as a thermal sensor +and sometimes as a touchscreen controller. + +Required properties: + - compatible: "allwinner,sun8i-a33-ths", + - reg: mmio address range of the chip, + - #thermal-sensor-cells: shall be 0, + - #io-channel-cells: shall be 0, + +Example: + ths: ths@1c25000 { + compatible = "allwinner,sun8i-a33-ths"; + reg = <0x01c25000 0x100>; + #thermal-sensor-cells = <0>; + #io-channel-cells = <0>; + }; + +sun4i, sun5i and sun6i SoCs are also supported via the older binding: + +sun4i resistive touchscreen controller +-------------------------------------- + +Required properties: + - compatible: "allwinner,sun4i-a10-ts", "allwinner,sun5i-a13-ts" or + "allwinner,sun6i-a31-ts" + - reg: mmio address range of the chip + - interrupts: interrupt to which the chip is connected + - #thermal-sensor-cells: shall be 0 + +Optional properties: + - allwinner,ts-attached : boolean indicating that an actual touchscreen + is attached to the controller + - allwinner,tp-sensitive-adjust : integer (4 bits) + adjust sensitivity of pen down detection + between 0 (least sensitive) and 15 + (defaults to 15) + - allwinner,filter-type : integer (2 bits) + select median and averaging filter + samples used for median / averaging filter + 0: 4/2 + 1: 5/3 + 2: 8/4 + 3: 16/8 + (defaults to 1) + +Example: + + rtp: rtp@1c25000 { + compatible = "allwinner,sun4i-a10-ts"; + reg = <0x01c25000 0x100>; + interrupts = <29>; + allwinner,ts-attached; + #thermal-sensor-cells = <0>; + /* sensitive/noisy touch panel */ + allwinner,tp-sensitive-adjust = <0>; + allwinner,filter-type = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/sun6i-prcm.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/sun6i-prcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..daa091c2e67ba06063e778ce0ca0c012c808a590 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/sun6i-prcm.txt @@ -0,0 +1,59 @@ +* Allwinner PRCM (Power/Reset/Clock Management) Multi-Functional Device + +PRCM is an MFD device exposing several Power Management related devices +(like clks and reset controllers). + +Required properties: + - compatible: "allwinner,sun6i-a31-prcm" or "allwinner,sun8i-a23-prcm" + - reg: The PRCM registers range + +The prcm node may contain several subdevices definitions: + - see Documentation/devicetree/bindings/clock/sunxi.txt for clock devices + - see Documentation/devicetree/bindings/reset/allwinner,sunxi-clock-reset.txt for reset + controller devices + + +Example: + + prcm: prcm@1f01400 { + compatible = "allwinner,sun6i-a31-prcm"; + reg = <0x01f01400 0x200>; + + /* Put subdevices here */ + ar100: ar100_clk { + compatible = "allwinner,sun6i-a31-ar100-clk"; + #clock-cells = <0>; + clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>; + }; + + ahb0: ahb0_clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clocks = <&ar100_div>; + clock-output-names = "ahb0"; + }; + + apb0: apb0_clk { + compatible = "allwinner,sun6i-a31-apb0-clk"; + #clock-cells = <0>; + clocks = <&ahb0>; + clock-output-names = "apb0"; + }; + + apb0_gates: apb0_gates_clk { + compatible = "allwinner,sun6i-a31-apb0-gates-clk"; + #clock-cells = <1>; + clocks = <&apb0>; + clock-output-names = "apb0_pio", "apb0_ir", + "apb0_timer01", "apb0_p2wi", + "apb0_uart", "apb0_1wire", + "apb0_i2c"; + }; + + apb0_rst: apb0_rst { + compatible = "allwinner,sun6i-a31-clock-reset"; + #reset-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/syscon.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/syscon.txt new file mode 100644 index 0000000000000000000000000000000000000000..25d9e9c2fd53aeae2dde3925a579654d4aef41b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/syscon.txt @@ -0,0 +1,32 @@ +* System Controller Registers R/W driver + +System controller node represents a register region containing a set +of miscellaneous registers. The registers are not cohesive enough to +represent as any specific type of device. The typical use-case is for +some other node's driver, or platform-specific code, to acquire a +reference to the syscon node (e.g. by phandle, node path, or search +using a specific compatible value), interrogate the node (or associated +OS driver) to determine the location of the registers, and access the +registers directly. + +Required properties: +- compatible: Should contain "syscon". +- reg: the register region can be accessed from syscon + +Optional property: +- reg-io-width: the size (in bytes) of the IO accesses that should be + performed on the device. +- hwlocks: reference to a phandle of a hardware spinlock provider node. + +Examples: +gpr: iomuxc-gpr@20e0000 { + compatible = "fsl,imx6q-iomuxc-gpr", "syscon"; + reg = <0x020e0000 0x38>; + hwlocks = <&hwlock1 1>; +}; + +hwlock1: hwspinlock@40500000 { + ... + reg = <0x40500000 0x1000>; + #hwlock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/tc3589x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/tc3589x.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f22b2b07dc5efb540514410810ce90aee23e64f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/tc3589x.txt @@ -0,0 +1,107 @@ +* Toshiba TC3589x multi-purpose expander + +The Toshiba TC3589x series are I2C-based MFD devices which may expose the +following built-in devices: gpio, keypad, rotator (vibrator), PWM (for +e.g. LEDs or vibrators) The included models are: + +- TC35890 +- TC35892 +- TC35893 +- TC35894 +- TC35895 +- TC35896 + +Required properties: + - compatible : must be "toshiba,tc35890", "toshiba,tc35892", "toshiba,tc35893", + "toshiba,tc35894", "toshiba,tc35895" or "toshiba,tc35896" + - reg : I2C address of the device + - interrupts : the interrupt on the parent the controller is connected to + - interrupt-controller : marks the device node as an interrupt controller + - #interrupt-cells : should be <1>, the first cell is the IRQ offset on this + TC3589x interrupt controller. + +Optional nodes: + +- GPIO + This GPIO module inside the TC3589x has 24 (TC35890, TC35892) or 20 + (other models) GPIO lines. + - compatible : must be "toshiba,tc3589x-gpio" + - interrupts : interrupt on the parent, which must be the tc3589x MFD device + - interrupt-controller : marks the device node as an interrupt controller + - #interrupt-cells : should be <2>, the first cell is the IRQ offset on this + TC3589x GPIO interrupt controller, the second cell is the interrupt flags + in accordance with . The following + flags are valid: + - IRQ_TYPE_LEVEL_LOW + - IRQ_TYPE_LEVEL_HIGH + - IRQ_TYPE_EDGE_RISING + - IRQ_TYPE_EDGE_FALLING + - IRQ_TYPE_EDGE_BOTH + - gpio-controller : marks the device node as a GPIO controller + - #gpio-cells : should be <2>, the first cell is the GPIO offset on this + GPIO controller, the second cell is the flags. + +- Keypad + This keypad is the same on all variants, supporting up to 96 different + keys. The linux-specific properties are modeled on those already existing + in other input drivers. + - compatible : must be "toshiba,tc3589x-keypad" + - debounce-delay-ms : debounce interval in milliseconds + - keypad,num-rows : number of rows in the matrix, see + bindings/input/matrix-keymap.txt + - keypad,num-columns : number of columns in the matrix, see + bindings/input/matrix-keymap.txt + - linux,keymap: the definition can be found in + bindings/input/matrix-keymap.txt + - linux,no-autorepeat: do no enable autorepeat feature. + - wakeup-source: use any event on keypad as wakeup event. + (Legacy property supported: "linux,wakeup") + +Example: + +tc35893@44 { + compatible = "toshiba,tc35893"; + reg = <0x44>; + interrupt-parent = <&gpio6>; + interrupts = <26 IRQ_TYPE_EDGE_RISING>; + + interrupt-controller; + #interrupt-cells = <1>; + + tc3589x_gpio { + compatible = "toshiba,tc3589x-gpio"; + interrupts = <0>; + + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; + tc3589x_keypad { + compatible = "toshiba,tc3589x-keypad"; + interrupts = <6>; + debounce-delay-ms = <4>; + keypad,num-columns = <8>; + keypad,num-rows = <8>; + linux,no-autorepeat; + linux,keymap = <0x0301006b + 0x04010066 + 0x06040072 + 0x040200d7 + 0x0303006a + 0x0205000e + 0x0607008b + 0x0500001c + 0x0403000b + 0x03040034 + 0x05020067 + 0x0305006c + 0x040500e7 + 0x0005009e + 0x06020073 + 0x01030039 + 0x07060069 + 0x050500d9>; + wakeup-source; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/ti-keystone-devctrl.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/ti-keystone-devctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..71a1f5963936b855d2ec7fc195e754cf5ad6ec02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/ti-keystone-devctrl.txt @@ -0,0 +1,19 @@ +* Device tree bindings for Texas Instruments keystone device state control + +The Keystone II devices have a set of registers that are used to control +the status of its peripherals. This node is intended to allow access to +this functionality. + +Required properties: + +- compatible: "ti,keystone-devctrl", "syscon" + +- reg: contains offset/length value for device state control + registers space. + +Example: + +devctrl: device-state-control@02620000 { + compatible = "ti,keystone-devctrl", "syscon"; + reg = <0x02620000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/ti-lmu.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/ti-lmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..c885cf89b8ce83ce29b9d603011859f5962493a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/ti-lmu.txt @@ -0,0 +1,243 @@ +TI LMU (Lighting Management Unit) device tree bindings + +TI LMU driver supports lighting devices below. + + Name Child nodes + ------ --------------------------------- + LM3532 Backlight + LM3631 Backlight and regulator + LM3632 Backlight and regulator + LM3633 Backlight, LED and fault monitor + LM3695 Backlight + LM3697 Backlight and fault monitor + +Required properties: + - compatible: Should be one of: + "ti,lm3532" + "ti,lm3631" + "ti,lm3632" + "ti,lm3633" + "ti,lm3695" + "ti,lm3697" + - reg: I2C slave address. + 0x11 for LM3632 + 0x29 for LM3631 + 0x36 for LM3633, LM3697 + 0x38 for LM3532 + 0x63 for LM3695 + +Optional property: + - enable-gpios: A GPIO specifier for hardware enable pin. + +Required node: + - backlight: All LMU devices have backlight child nodes. + For the properties, please refer to [1]. + +Optional nodes: + - fault-monitor: Hardware fault monitoring driver for LM3633 and LM3697. + Required properties: + - compatible: Should be one of: + "ti,lm3633-fault-monitor" + "ti,lm3697-fault-monitor" + - leds: LED properties for LM3633. Please refer to [2]. + - regulators: Regulator properties for LM3631 and LM3632. + Please refer to [3]. + +[1] ../leds/backlight/ti-lmu-backlight.txt +[2] ../leds/leds-lm3633.txt +[3] ../regulator/lm363x-regulator.txt + +lm3532@38 { + compatible = "ti,lm3532"; + reg = <0x38>; + + enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; + + backlight { + compatible = "ti,lm3532-backlight"; + + lcd { + led-sources = <0 1 2>; + ramp-up-msec = <30>; + ramp-down-msec = <0>; + }; + }; +}; + +lm3631@29 { + compatible = "ti,lm3631"; + reg = <0x29>; + + regulators { + compatible = "ti,lm363x-regulator"; + + vboost { + regulator-name = "lcd_boost"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <6350000>; + regulator-always-on; + }; + + vcont { + regulator-name = "lcd_vcont"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + voref { + regulator-name = "lcd_voref"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + vpos { + regulator-name = "lcd_vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + + vneg { + regulator-name = "lcd_vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + }; + + backlight { + compatible = "ti,lm3631-backlight"; + + lcd_bl { + led-sources = <0 1>; + ramp-up-msec = <300>; + }; + }; +}; + +lm3632@11 { + compatible = "ti,lm3632"; + reg = <0x11>; + + enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; /* PC2 */ + + regulators { + compatible = "ti,lm363x-regulator"; + + ti,lcm-en1-gpio = <&pioC 0 GPIO_ACTIVE_HIGH>; /* PC0 */ + ti,lcm-en2-gpio = <&pioC 1 GPIO_ACTIVE_HIGH>; /* PC1 */ + + vboost { + regulator-name = "lcd_boost"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <6400000>; + regulator-always-on; + }; + + vpos { + regulator-name = "lcd_vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + vneg { + regulator-name = "lcd_vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + }; + + backlight { + compatible = "ti,lm3632-backlight"; + + pwms = <&pwm0 0 10000 0>; /* pwm number, period, polarity */ + pwm-names = "lmu-backlight"; + + lcd { + led-sources = <0 1>; + pwm-period = <10000>; + }; + }; +}; + +lm3633@36 { + compatible = "ti,lm3633"; + reg = <0x36>; + + enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; + + backlight { + compatible = "ti,lm3633-backlight"; + + main { + label = "main_lcd"; + led-sources = <1 2>; + ramp-up-msec = <500>; + ramp-down-msec = <500>; + }; + + front { + label = "front_lcd"; + led-sources = <0>; + ramp-up-msec = <1000>; + ramp-down-msec = <0>; + }; + }; + + leds { + compatible = "ti,lm3633-leds"; + + chan1 { + label = "status"; + led-sources = <1>; + led-max-microamp = <6000>; + }; + + chan345 { + label = "rgb"; + led-sources = <3 4 5>; + led-max-microamp = <10000>; + }; + }; + + fault-monitor { + compatible = "ti,lm3633-fault-monitor"; + }; +}; + +lm3695@63 { + compatible = "ti,lm3695"; + reg = <0x63>; + + enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; + + backlight { + compatible = "ti,lm3695-backlight"; + + lcd { + label = "bl"; + led-sources = <0 1>; + }; + }; +}; + +lm3697@36 { + compatible = "ti,lm3697"; + reg = <0x36>; + + enable-gpios = <&pioC 2 GPIO_ACTIVE_HIGH>; + + backlight { + compatible = "ti,lm3697-backlight"; + + lcd { + led-sources = <0 1 2>; + ramp-up-msec = <200>; + ramp-down-msec = <200>; + }; + }; + + fault-monitor { + compatible = "ti,lm3697-fault-monitor"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/tps6105x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/tps6105x.txt new file mode 100644 index 0000000000000000000000000000000000000000..93602c7a19c8e296259198e7178dc8e9434f44a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/tps6105x.txt @@ -0,0 +1,17 @@ +* Device tree bindings for TI TPS61050/61052 Boost Converters + +The TP61050/TPS61052 is a high-power "white LED driver". The +device provides LED, GPIO and regulator functionalities. + +Required properties: +- compatible: "ti,tps61050" or "ti,tps61052" +- reg: Specifies the I2C slave address + +Example: + +i2c0 { + tps61052@33 { + compatible = "ti,tps61052"; + reg = <0x33>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/tps6507x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/tps6507x.txt new file mode 100644 index 0000000000000000000000000000000000000000..8fffa3c5ed401ca746df88de8df17ecd8e0e21e3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/tps6507x.txt @@ -0,0 +1,91 @@ +TPS6507x Power Management Integrated Circuit + +Required properties: +- compatible: "ti,tps6507x" +- reg: I2C slave address +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. Not all regulators for the + given device need to be present. The definition for each of these nodes + is defined using the standard binding for regulators found at + Documentation/devicetree/bindings/regulator/regulator.txt. + The regulator is matched with the regulator-compatible. + + The valid regulator-compatible values are: + tps6507x: vdcdc1, vdcdc2, vdcdc3, vldo1, vldo2 +- xxx-supply: Input voltage supply regulator. + These entries are required if regulators are enabled for a device. + Missing of these properties can cause the regulator registration + fails. + If some of input supply is powered through battery or always-on + supply then also it is require to have these parameters with proper + node handle of always on power supply. + tps6507x: + vindcdc1_2-supply: VDCDC1 and VDCDC2 input. + vindcdc3-supply : VDCDC3 input. + vldo1_2-supply : VLDO1 and VLDO2 input. + +Regulator Optional properties: +- defdcdc_default: It's property of DCDC2 and DCDC3 regulators. + 0: If defdcdc pin of DCDC2/DCDC3 is pulled to GND. + 1: If defdcdc pin of DCDC2/DCDC3 is driven HIGH. + If this property is not defined, it defaults to 0 (not enabled). + +Example: + + pmu: tps6507x@48 { + compatible = "ti,tps6507x"; + reg = <0x48>; + + vindcdc1_2-supply = <&vbat>; + vindcdc3-supply = <...>; + vinldo1_2-supply = <...>; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + vdcdc1_reg: regulator@0 { + regulator-compatible = "VDCDC1"; + reg = <0>; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3450000>; + regulator-always-on; + regulator-boot-on; + }; + vdcdc2_reg: regulator@1 { + regulator-compatible = "VDCDC2"; + reg = <1>; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <3450000>; + regulator-always-on; + regulator-boot-on; + defdcdc_default = <1>; + }; + vdcdc3_reg: regulator@2 { + regulator-compatible = "VDCDC3"; + reg = <2>; + regulator-min-microvolt = <950000> + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + defdcdc_default = <1>; + }; + ldo1_reg: regulator@3 { + regulator-compatible = "LDO1"; + reg = <3>; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1890000>; + regulator-always-on; + regulator-boot-on; + }; + ldo2_reg: regulator@4 { + regulator-compatible = "LDO2"; + reg = <4>; + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1320000>; + regulator-always-on; + regulator-boot-on; + }; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/tps65086.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/tps65086.txt new file mode 100644 index 0000000000000000000000000000000000000000..67eac0ed32df27e8d47877c76bab304ba5c84e73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/tps65086.txt @@ -0,0 +1,54 @@ +* TPS65086 Power Management Integrated Circuit (PMIC) bindings + +Required properties: + - compatible : Should be "ti,tps65086". + - reg : I2C slave address. + - interrupts : The interrupt line the device is connected to. + - interrupt-controller : Marks the device node as an interrupt controller. + - #interrupt-cells : The number of cells to describe an IRQ, should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as trigger + masks from ../interrupt-controller/interrupts.txt. + - gpio-controller : Marks the device node as a GPIO Controller. + - #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - regulators: : List of child nodes that specify the regulator + initialization data. Child nodes must be named + after their hardware counterparts: buck[1-6], + ldoa[1-3], swa1, swb[1-2], and vtt. Each child + node is defined using the standard binding for + regulators and the optional regulator properties + defined below. + +Optional regulator properties: + - ti,regulator-step-size-25mv : This is applicable for buck[1-6], set this + if the regulator is factory set with a 25mv + step voltage mapping. + - ti,regulator-decay : This is applicable for buck[1-6], set this if + the output needs to decay, default is for + the output to slew down. + +Example: + + pmic: tps65086@5e { + compatible = "ti,tps65086"; + reg = <0x5e>; + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + + regulators { + buck1 { + regulator-name = "vcc1"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1600000>; + regulator-boot-on; + ti,regulator-decay; + ti,regulator-step-size-25mv; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/tps65910.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/tps65910.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f62143afd240d7bd63010639f5635e6633cadc4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/tps65910.txt @@ -0,0 +1,205 @@ +TPS65910 Power Management Integrated Circuit + +Required properties: +- compatible: "ti,tps65910" or "ti,tps65911" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- #gpio-cells: number of cells to describe a GPIO, this should be 2. + The first cell is the GPIO number. + The second cell is used to specify additional options . +- gpio-controller: mark the device as a GPIO controller +- #interrupt-cells: the number of cells to describe an IRQ, this should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as the trigger masks from + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. Not all regulators for the given + device need to be present. The definition for each of these nodes is defined + using the standard binding for regulators found at + Documentation/devicetree/bindings/regulator/regulator.txt. + The regulator is matched with the regulator-compatible. + + The valid regulator-compatible values are: + tps65910: vrtc, vio, vdd1, vdd2, vdd3, vdig1, vdig2, vpll, vdac, vaux1, + vaux2, vaux33, vmmc, vbb + tps65911: vrtc, vio, vdd1, vdd2, vddctrl, ldo1, ldo2, ldo3, ldo4, ldo5, + ldo6, ldo7, ldo8 + +- xxx-supply: Input voltage supply regulator. + These entries are require if regulators are enabled for a device. Missing of these + properties can cause the regulator registration fails. + If some of input supply is powered through battery or always-on supply then + also it is require to have these parameters with proper node handle of always + on power supply. + tps65910: + vcc1-supply: VDD1 input. + vcc2-supply: VDD2 input. + vcc3-supply: VAUX33 and VMMC input. + vcc4-supply: VAUX1 and VAUX2 input. + vcc5-supply: VPLL and VDAC input. + vcc6-supply: VDIG1 and VDIG2 input. + vcc7-supply: VRTC and VBB input. + vccio-supply: VIO input. + tps65911: + vcc1-supply: VDD1 input. + vcc2-supply: VDD2 input. + vcc3-supply: LDO6, LDO7 and LDO8 input. + vcc4-supply: LDO5 input. + vcc5-supply: LDO3 and LDO4 input. + vcc6-supply: LDO1 and LDO2 input. + vcc7-supply: VRTC input. + vccio-supply: VIO input. + +Optional properties: +- ti,vmbch-threshold: (tps65911) main battery charged threshold + comparator. (see VMBCH_VSEL in TPS65910 datasheet) +- ti,vmbch2-threshold: (tps65911) main battery discharged threshold + comparator. (see VMBCH_VSEL in TPS65910 datasheet) +- ti,en-ck32k-xtal: enable external 32-kHz crystal oscillator (see CK32K_CTRL + in TPS6591X datasheet) +- ti,en-gpio-sleep: enable sleep control for gpios + There should be 9 entries here, one for each gpio. +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. +- ti,sleep-enable: Enable SLEEP state. +- ti,sleep-keep-therm: Keep thermal monitoring on in sleep state. +- ti,sleep-keep-ck32k: Keep the 32KHz clock output on in sleep state. +- ti,sleep-keep-hsclk: Keep high speed internal clock on in sleep state. + +Regulator Optional properties: +- ti,regulator-ext-sleep-control: enable external sleep + control through external inputs [0 (not enabled), 1 (EN1), 2 (EN2) or 4(EN3)] + If this property is not defined, it defaults to 0 (not enabled). + +Example: + + pmu: tps65910@d2 { + compatible = "ti,tps65910"; + reg = <0xd2>; + interrupt-parent = <&intc>; + interrupts = < 0 118 0x04 >; + + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-controller; + + ti,system-power-controller; + + ti,vmbch-threshold = 0; + ti,vmbch2-threshold = 0; + ti,en-ck32k-xtal; + ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>; + + vcc1-supply = <®_parent>; + vcc2-supply = <&some_reg>; + vcc3-supply = <...>; + vcc4-supply = <...>; + vcc5-supply = <...>; + vcc6-supply = <...>; + vcc7-supply = <...>; + vccio-supply = <...>; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + vdd1_reg: regulator@0 { + regulator-compatible = "vdd1"; + reg = <0>; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + ti,regulator-ext-sleep-control = <0>; + }; + vdd2_reg: regulator@1 { + regulator-compatible = "vdd2"; + reg = <1>; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + ti,regulator-ext-sleep-control = <4>; + }; + vddctrl_reg: regulator@2 { + regulator-compatible = "vddctrl"; + reg = <2>; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + ti,regulator-ext-sleep-control = <0>; + }; + vio_reg: regulator@3 { + regulator-compatible = "vio"; + reg = <3>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + ti,regulator-ext-sleep-control = <1>; + }; + ldo1_reg: regulator@4 { + regulator-compatible = "ldo1"; + reg = <4>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + ti,regulator-ext-sleep-control = <0>; + }; + ldo2_reg: regulator@5 { + regulator-compatible = "ldo2"; + reg = <5>; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + ti,regulator-ext-sleep-control = <0>; + }; + ldo3_reg: regulator@6 { + regulator-compatible = "ldo3"; + reg = <6>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + ti,regulator-ext-sleep-control = <0>; + }; + ldo4_reg: regulator@7 { + regulator-compatible = "ldo4"; + reg = <7>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + ti,regulator-ext-sleep-control = <0>; + }; + ldo5_reg: regulator@8 { + regulator-compatible = "ldo5"; + reg = <8>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + ti,regulator-ext-sleep-control = <0>; + }; + ldo6_reg: regulator@9 { + regulator-compatible = "ldo6"; + reg = <9>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + ti,regulator-ext-sleep-control = <0>; + }; + ldo7_reg: regulator@10 { + regulator-compatible = "ldo7"; + reg = <10>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + ti,regulator-ext-sleep-control = <1>; + }; + ldo8_reg: regulator@11 { + regulator-compatible = "ldo8"; + reg = <11>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + ti,regulator-ext-sleep-control = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/tps65912.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/tps65912.txt new file mode 100644 index 0000000000000000000000000000000000000000..8becb183a48e3b3a590628fe9556d57119b1fb65 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/tps65912.txt @@ -0,0 +1,49 @@ +* TPS65912 Power Management Integrated Circuit bindings + +Required properties: + - compatible : Should be "ti,tps65912". + - reg : Slave address or chip select number (I2C / SPI). + - interrupts : The interrupt line the device is connected to. + - interrupt-controller : Marks the device node as an interrupt controller. + - #interrupt-cells : The number of cells to describe an IRQ, should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as trigger + masks from ../interrupt-controller/interrupts.txt. + - gpio-controller : Marks the device node as a GPIO Controller. + - #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify flags. + See ../gpio/gpio.txt for more information. + - regulators: : List of child nodes that specify the regulator + initialization data. Child nodes must be named + after their hardware counterparts: dcdc[1-4] and + ldo[1-10]. Each child nodes is defined using the + standard binding for regulators. + +Example: + + pmic: tps65912@2d { + compatible = "ti,tps65912"; + reg = <0x2d>; + interrupt-parent = <&gpio1>; + interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + + regulators { + dcdc1 { + regulator-name = "vdd_core"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <1144000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/twl-familly.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/twl-familly.txt new file mode 100644 index 0000000000000000000000000000000000000000..56f244b5d8a4613fb35ab5bf7404e5c7bf1645de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/twl-familly.txt @@ -0,0 +1,46 @@ +Texas Instruments TWL family + +The TWLs are Integrated Power Management Chips. +Some version might contain much more analog function like +USB transceiver or Audio amplifier. +These chips are connected to an i2c bus. + + +Required properties: +- compatible : Must be "ti,twl4030"; + For Integrated power-management/audio CODEC device used in OMAP3 + based boards +- compatible : Must be "ti,twl6030"; + For Integrated power-management used in OMAP4 based boards +- interrupts : This i2c device has an IRQ line connected to the main SoC +- interrupt-controller : Since the twl support several interrupts internally, + it is considered as an interrupt controller cascaded to the SoC one. +- #interrupt-cells = <1>; + +Optional node: +- Child nodes contain in the twl. The twl family is made of several variants + that support a different number of features. + The children nodes will thus depend of the capability of the variant. + + +Example: +/* + * Integrated Power Management Chip + * http://www.ti.com/lit/ds/symlink/twl6030.pdf + */ +twl@48 { + compatible = "ti,twl6030"; + reg = <0x48>; + interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */ + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + #address-cells = <1>; + #size-cells = <0>; + + twl_rtc { + compatible = "ti,twl_rtc"; + interrupts = <11>; + reg = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/twl4030-audio.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/twl4030-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..414d2ae0adf6e1f1baf5e6e0d85162c0cef38ca8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/twl4030-audio.txt @@ -0,0 +1,46 @@ +Texas Instruments TWL family (twl4030) audio module + +The audio module inside the TWL family consist of an audio codec and a vibra +driver. + +Required properties: +- compatible : must be "ti,twl4030-audio" + +Optional properties, nodes: + +Audio functionality: +- codec { }: Need to be present if the audio functionality is used. Within this + section the following options can be used: +- ti,digimic_delay: Delay need after enabling the digimic to reduce artifacts + from the start of the recorded sample (in ms) +-ti,ramp_delay_value: HS ramp delay configuration to reduce pop noise +-ti,hs_extmute: Use external mute for HS pop reduction +-ti,hs_extmute_gpio: Use external GPIO to control the external mute +-ti,offset_cncl_path: Offset cancellation path selection, refer to TRM for the + valid values. + +Vibra functionality +- ti,enable-vibra: Need to be set to <1> if the vibra functionality is used. if + missing or it is 0, the vibra functionality is disabled. + +Example: +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + twl_audio: audio { + compatible = "ti,twl4030-audio"; + + ti,enable-vibra = <1>; + + codec { + ti,ramp_delay_value = <3>; + }; + + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/twl4030-power.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/twl4030-power.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d19963312ce0a8c9e0a06f597f899df3ad08905 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/twl4030-power.txt @@ -0,0 +1,48 @@ +Texas Instruments TWL family (twl4030) reset and power management module + +The power management module inside the TWL family provides several facilities +to control the power resources, including power scripts. For now, the +binding only supports the complete shutdown of the system after poweroff. + +Required properties: +- compatible : must be one of the following + "ti,twl4030-power" + "ti,twl4030-power-reset" + "ti,twl4030-power-idle" + "ti,twl4030-power-idle-osc-off" + +The use of ti,twl4030-power-reset is recommended at least on +3530 that needs a special configuration for warm reset to work. + +When using ti,twl4030-power-idle, the TI recommended configuration +for idle modes is loaded to the tlw4030 PMIC. + +When using ti,twl4030-power-idle-osc-off, the TI recommended +configuration is used with the external oscillator being shut +down during off-idle. Note that this does not work on all boards +depending on how the external oscillator is wired. + +Optional properties: + +- ti,system-power-controller: This indicates that TWL4030 is the + power supply master of the system. With this flag, the chip will + initiate an ACTIVE-to-OFF or SLEEP-to-OFF transition when the + system poweroffs. + +- ti,use_poweroff: Deprecated name for ti,system-power-controller + +Example: +&i2c1 { + clock-frequency = <2600000>; + + twl: twl@48 { + reg = <0x48>; + interrupts = <7>; /* SYS_NIRQ cascaded to intc */ + interrupt-parent = <&intc>; + + twl_power: power { + compatible = "ti,twl4030-power"; + ti,use_poweroff; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/twl6040.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/twl6040.txt new file mode 100644 index 0000000000000000000000000000000000000000..06e9dd7a0d96aa7e33cff239076bccce008074ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/twl6040.txt @@ -0,0 +1,67 @@ +Texas Instruments TWL6040 family + +The TWL6040s are 8-channel high quality low-power audio codecs providing audio, +vibra and GPO functionality on OMAP4+ platforms. +They are connected ot the host processor via i2c for commands, McPDM for audio +data and commands. + +Required properties: +- compatible : "ti,twl6040" for twl6040, "ti,twl6041" for twl6041 +- reg: must be 0x4b for i2c address +- interrupts: twl6040 has one interrupt line connecteded to the main SoC +- gpio-controller: +- #gpio-cells = <1>: twl6040 provides GPO lines. +- #clock-cells = <0>; twl6040 is a provider of pdmclk which is used by McPDM +- twl6040,audpwron-gpio: Power on GPIO line for the twl6040 + +- vio-supply: Regulator for the twl6040 VIO supply +- v2v1-supply: Regulator for the twl6040 V2V1 supply + +Optional properties, nodes: +- enable-active-high: To power on the twl6040 during boot. +- clocks: phandle to the clk32k and/or to mclk clock provider +- clock-names: Must be "clk32k" for the 32K clock and "mclk" for the MCLK. + +Vibra functionality +Required properties: +- vddvibl-supply: Regulator for the left vibra motor +- vddvibr-supply: Regulator for the right vibra motor +- vibra { }: Configuration section for vibra parameters containing the following + properties: +- ti,vibldrv-res: Resistance parameter for left driver +- ti,vibrdrv-res: Resistance parameter for right driver +- ti,viblmotor-res: Resistance parameter for left motor +- ti,viblmotor-res: Resistance parameter for right motor + +Optional properties within vibra { } section: +- vddvibl_uV: If the vddvibl default voltage need to be changed +- vddvibr_uV: If the vddvibr default voltage need to be changed + +Example: +&i2c1 { + twl6040: twl@4b { + compatible = "ti,twl6040"; + + interrupts = <0 119 4>; + interrupt-parent = <&gic>; + twl6040,audpwron-gpio = <&gpio4 31 0>; + + vio-supply = <&v1v8>; + v2v1-supply = <&v2v1>; + enable-active-high; + + /* regulators for vibra motor */ + vddvibl-supply = <&vbat>; + vddvibr-supply = <&vbat>; + + vibra { + /* Vibra driver, motor resistance parameters */ + ti,vibldrv-res = <8>; + ti,vibrdrv-res = <3>; + ti,viblmotor-res = <10>; + ti,vibrmotor-res = <10>; + }; + }; +}; + +/include/ "twl6040.dtsi" diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/wm831x.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/wm831x.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b84b1b0d01884776e399c74a64d21c0213eecc0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/wm831x.txt @@ -0,0 +1,81 @@ +Cirrus Logic/Wolfson Microelectronics wm831x PMICs + +System PMICs with a wide range of additional features. + +Required properties: + + - compatible : One of the following chip-specific strings: + "wlf,wm8310" + "wlf,wm8311" + "wlf,wm8312" + "wlf,wm8320" + "wlf,wm8321" + "wlf,wm8325" + "wlf,wm8326" + + - reg : I2C slave address when connected using I2C, chip select number + when using SPI. + + - gpio-controller : Indicates this device is a GPIO controller. + - #gpio-cells : Must be 2. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + + - interrupts : The interrupt line the IRQ signal for the device is + connected to. + + - interrupt-controller : wm831x devices contain interrupt controllers and + may provide interrupt services to other devices. + - #interrupt-cells: Must be 2. The first cell is the IRQ number, and the + second cell is the flags, encoded as the trigger masks from + ../interrupt-controller/interrupts.txt + +Optional sub-nodes: + - phys : Contains a phandle to the USB PHY. + - regulators : Contains sub-nodes for each of the regulators supplied by + the device. The regulators are bound using their names listed below: + + dcdc1 : DCDC1 + dcdc2 : DCDC2 + dcdc3 : DCDC3 + dcdc4 : DCDC3 + isink1 : ISINK1 + isink2 : ISINK2 + ldo1 : LDO1 + ldo2 : LDO2 + ldo3 : LDO3 + ldo4 : LDO4 + ldo5 : LDO5 + ldo7 : LDO7 + ldo11 : LDO11 + + The bindings details of each regulator can be found in: + ../regulator/regulator.txt + +Example: + +wm8310: pmic@36 { + compatible = "wlf,wm8310"; + reg = <0x36>; + + gpio-controller; + #gpio-cells = <2>; + + interrupts = <347>; + interrupt-parent = <&gic>; + + interrupt-controller; + #interrupt-cells = <2>; + + regulators { + dcdc1: dcdc1 { + regulator-name = "DCDC1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <600000>; + }; + ldo1: ldo1 { + regulator-name = "LDO1"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1700000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mfd/zii,rave-sp.txt b/arch/arm64/boot/dts/vendor/bindings/mfd/zii,rave-sp.txt new file mode 100644 index 0000000000000000000000000000000000000000..088eff9ddb786cdbdf0a26ea3d9fed27f048b021 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mfd/zii,rave-sp.txt @@ -0,0 +1,39 @@ +Zodiac Inflight Innovations RAVE Supervisory Processor + +RAVE Supervisory Processor communicates with SoC over UART. It is +expected that its Device Tree node is specified as a child of a node +corresponding to UART controller used for communication. + +Required parent device properties: + + - compatible: Should be one of: + - "zii,rave-sp-niu" + - "zii,rave-sp-mezz" + - "zii,rave-sp-esb" + - "zii,rave-sp-rdu1" + - "zii,rave-sp-rdu2" + + - current-speed: Should be set to baud rate SP device is using + +RAVE SP consists of the following sub-devices: + +Device Description +------ ----------- +rave-sp-wdt : Watchdog +rave-sp-nvmem : Interface to onborad EEPROM +rave-sp-backlight : Display backlight +rave-sp-hwmon : Interface to onboard hardware sensors +rave-sp-leds : Interface to onboard LEDs +rave-sp-input : Interface to onboard power button + +Example of usage: + + rdu { + compatible = "zii,rave-sp-rdu2"; + current-speed = <1000000>; + + watchdog { + compatible = "zii,rave-sp-watchdog"; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/ath79-soc.txt b/arch/arm64/boot/dts/vendor/bindings/mips/ath79-soc.txt new file mode 100644 index 0000000000000000000000000000000000000000..88a12a43e44e81ed8f61a364deb626510a4bb7e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/ath79-soc.txt @@ -0,0 +1,21 @@ +Binding for Qualcomm Atheros AR7xxx/AR9XXX SoC + +Each device tree must specify a compatible value for the AR SoC +it uses in the compatible property of the root node. The compatible +value must be one of the following values: + +- qca,ar7130 +- qca,ar7141 +- qca,ar7161 +- qca,ar7240 +- qca,ar7241 +- qca,ar7242 +- qca,ar9130 +- qca,ar9132 +- qca,ar9330 +- qca,ar9331 +- qca,ar9341 +- qca,ar9342 +- qca,ar9344 +- qca,qca9556 +- qca,qca9558 diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/brcm/brcm,bmips.txt b/arch/arm64/boot/dts/vendor/bindings/mips/brcm/brcm,bmips.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ef71b4085caf9f6bd048b7b8ffa242733b71080 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/brcm/brcm,bmips.txt @@ -0,0 +1,8 @@ +* Broadcom MIPS (BMIPS) CPUs + +Required properties: +- compatible: "brcm,bmips3300", "brcm,bmips4350", "brcm,bmips4380", + "brcm,bmips5000" + +- mips-hpt-frequency: This is common to all CPUs in the system so it lives + under the "cpus" node. diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/brcm/soc.txt b/arch/arm64/boot/dts/vendor/bindings/mips/brcm/soc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a66d3c483e1aad12298fcf297767931db09051a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/brcm/soc.txt @@ -0,0 +1,166 @@ +* Broadcom cable/DSL/settop platforms + +Required properties: + +- compatible: "brcm,bcm3368", "brcm,bcm3384", "brcm,bcm33843" + "brcm,bcm3384-viper", "brcm,bcm33843-viper" + "brcm,bcm6328", "brcm,bcm6358", "brcm,bcm6362", "brcm,bcm6368", + "brcm,bcm63168", "brcm,bcm63268", + "brcm,bcm7125", "brcm,bcm7346", "brcm,bcm7358", "brcm,bcm7360", + "brcm,bcm7362", "brcm,bcm7420", "brcm,bcm7425" + +The experimental -viper variants are for running Linux on the 3384's +BMIPS4355 cable modem CPU instead of the BMIPS5000 application processor. + +Power management +---------------- + +For power management (particularly, S2/S3/S5 system suspend), the following SoC +components are needed: + += Always-On control block (AON CTRL) + +This hardware provides control registers for the "always-on" (even in low-power +modes) hardware, such as the Power Management State Machine (PMSM). + +Required properties: +- compatible : should be one of + "brcm,bcm7425-aon-ctrl" + "brcm,bcm7429-aon-ctrl" + "brcm,bcm7435-aon-ctrl" and + "brcm,brcmstb-aon-ctrl" +- reg : the register start and length for the AON CTRL block + +Example: + +syscon@410000 { + compatible = "brcm,bcm7425-aon-ctrl", "brcm,brcmstb-aon-ctrl"; + reg = <0x410000 0x400>; +}; + += Memory controllers + +A Broadcom STB SoC typically has a number of independent memory controllers, +each of which may have several associated hardware blocks, which are versioned +independently (control registers, DDR PHYs, etc.). One might consider +describing these controllers as a parent "memory controllers" block, which +contains N sub-nodes (one for each controller in the system), each of which is +associated with a number of hardware register resources (e.g., its PHY. + +== MEMC (MEMory Controller) + +Represents a single memory controller instance. + +Required properties: +- compatible : should contain "brcm,brcmstb-memc" and "simple-bus" +- ranges : should contain the child address in the parent address + space, must be 0 here, and the register start and length of + the entire memory controller (including all sub nodes: DDR PHY, + arbiter, etc.) +- #address-cells : must be 1 +- #size-cells : must be 1 + +Example: + + memory-controller@0 { + compatible = "brcm,brcmstb-memc", "simple-bus"; + ranges = <0x0 0x0 0xa000>; + #address-cells = <1>; + #size-cells = <1>; + + memc-arb@1000 { + ... + }; + + memc-ddr@2000 { + ... + }; + + ddr-phy@6000 { + ... + }; + }; + +Should contain subnodes for any of the following relevant hardware resources: + +== DDR PHY control + +Control registers for this memory controller's DDR PHY. + +Required properties: +- compatible : should contain one of these + "brcm,brcmstb-ddr-phy-v64.5" + "brcm,brcmstb-ddr-phy" + +- reg : the DDR PHY register range and length + +Example: + + ddr-phy@6000 { + compatible = "brcm,brcmstb-ddr-phy-v64.5"; + reg = <0x6000 0xc8>; + }; + +== DDR memory controller sequencer + +Control registers for this memory controller's DDR memory sequencer + +Required properties: +- compatible : should contain one of these + "brcm,bcm7425-memc-ddr" + "brcm,bcm7429-memc-ddr" + "brcm,bcm7435-memc-ddr" and + "brcm,brcmstb-memc-ddr" + +- reg : the DDR sequencer register range and length + +Example: + + memc-ddr@2000 { + compatible = "brcm,bcm7425-memc-ddr", "brcm,brcmstb-memc-ddr"; + reg = <0x2000 0x300>; + }; + +== MEMC Arbiter + +The memory controller arbiter is responsible for memory clients allocation +(bandwidth, priorities etc.) and needs to have its contents restored during +deep sleep states (S3). + +Required properties: + +- compatible : should contain one of these + "brcm,brcmstb-memc-arb-v10.0.0.0" + "brcm,brcmstb-memc-arb" + +- reg : the DDR Arbiter register range and length + +Example: + + memc-arb@1000 { + compatible = "brcm,brcmstb-memc-arb-v10.0.0.0"; + reg = <0x1000 0x248>; + }; + +== Timers + +The Broadcom STB chips contain a timer block with several general purpose +timers that can be used. + +Required properties: + +- compatible : should contain one of: + "brcm,bcm7425-timers" + "brcm,bcm7429-timers" + "brcm,bcm7435-timers" and + "brcm,brcmstb-timers" +- reg : the timers register range +- interrupts : the interrupt line for this timer block + +Example: + + timers: timer@4067c0 { + compatible = "brcm,bcm7425-timers", "brcm,brcmstb-timers"; + reg = <0x4067c0 0x40>; + interrupts = <&periph_intc 19>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/bootbus.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/bootbus.txt new file mode 100644 index 0000000000000000000000000000000000000000..6581478225a230e011375692630dc050e8d8be6b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/bootbus.txt @@ -0,0 +1,126 @@ +* Boot Bus + +The Octeon Boot Bus is a configurable parallel bus with 8 chip +selects. Each chip select is independently configurable. + +Properties: +- compatible: "cavium,octeon-3860-bootbus" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the Boot Bus' register bank. + +- #address-cells: Must be <2>. The first cell is the chip select + within the bootbus. The second cell is the offset from the chip select. + +- #size-cells: Must be <1>. + +- ranges: There must be one one triplet of (child-bus-address, + parent-bus-address, length) for each active chip select. If the + length element for any triplet is zero, the chip select is disabled, + making it inactive. + +The configuration parameters for each chip select are stored in child +nodes. + +Configuration Properties: +- compatible: "cavium,octeon-3860-bootbus-config" + +- cavium,cs-index: A single cell indicating the chip select that + corresponds to this configuration. + +- cavium,t-adr: A cell specifying the ADR timing (in nS). + +- cavium,t-ce: A cell specifying the CE timing (in nS). + +- cavium,t-oe: A cell specifying the OE timing (in nS). + +- cavium,t-we: A cell specifying the WE timing (in nS). + +- cavium,t-rd-hld: A cell specifying the RD_HLD timing (in nS). + +- cavium,t-wr-hld: A cell specifying the WR_HLD timing (in nS). + +- cavium,t-pause: A cell specifying the PAUSE timing (in nS). + +- cavium,t-wait: A cell specifying the WAIT timing (in nS). + +- cavium,t-page: A cell specifying the PAGE timing (in nS). + +- cavium,t-rd-dly: A cell specifying the RD_DLY timing (in nS). + +- cavium,pages: A cell specifying the PAGES parameter (0 = 8 bytes, 1 + = 2 bytes, 2 = 4 bytes, 3 = 8 bytes). + +- cavium,wait-mode: Optional. If present, wait mode (WAITM) is selected. + +- cavium,page-mode: Optional. If present, page mode (PAGEM) is selected. + +- cavium,bus-width: A cell specifying the WIDTH parameter (in bits) of + the bus for this chip select. + +- cavium,ale-mode: Optional. If present, ALE mode is selected. + +- cavium,sam-mode: Optional. If present, SAM mode is selected. + +- cavium,or-mode: Optional. If present, OR mode is selected. + +Example: + bootbus: bootbus@1180000000000 { + compatible = "cavium,octeon-3860-bootbus"; + reg = <0x11800 0x00000000 0x0 0x200>; + /* The chip select number and offset */ + #address-cells = <2>; + /* The size of the chip select region */ + #size-cells = <1>; + ranges = <0 0 0x0 0x1f400000 0xc00000>, + <1 0 0x10000 0x30000000 0>, + <2 0 0x10000 0x40000000 0>, + <3 0 0x10000 0x50000000 0>, + <4 0 0x0 0x1d020000 0x10000>, + <5 0 0x0 0x1d040000 0x10000>, + <6 0 0x0 0x1d050000 0x10000>, + <7 0 0x10000 0x90000000 0>; + + cavium,cs-config@0 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <0>; + cavium,t-adr = <20>; + cavium,t-ce = <60>; + cavium,t-oe = <60>; + cavium,t-we = <45>; + cavium,t-rd-hld = <35>; + cavium,t-wr-hld = <45>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <35>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,bus-width = <8>; + }; + . + . + . + cavium,cs-config@6 { + compatible = "cavium,octeon-3860-bootbus-config"; + cavium,cs-index = <6>; + cavium,t-adr = <5>; + cavium,t-ce = <300>; + cavium,t-oe = <270>; + cavium,t-we = <150>; + cavium,t-rd-hld = <100>; + cavium,t-wr-hld = <70>; + cavium,t-pause = <0>; + cavium,t-wait = <0>; + cavium,t-page = <320>; + cavium,t-rd-dly = <0>; + + cavium,pages = <0>; + cavium,wait-mode; + cavium,bus-width = <16>; + }; + . + . + . + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/cib.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/cib.txt new file mode 100644 index 0000000000000000000000000000000000000000..410efa3222545874b192c1beeabce65a7936134d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/cib.txt @@ -0,0 +1,41 @@ +* Cavium Interrupt Bus widget + +Properties: +- compatible: "cavium,octeon-7130-cib" + + Compatibility with cn70XX SoCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: Two elements consisting of the addresses of the RAW and EN + registers of the CIB block + +- cavium,max-bits: The index (zero based) of the highest numbered bit + in the CIB block. + +- interrupts: The CIU line to which the CIB block is connected. + +- #interrupt-cells: Must be <2>. The first cell is the bit within the + CIB. The second cell specifies the triggering semantics of the + line. + +Example: + + interrupt-controller@107000000e000 { + compatible = "cavium,octeon-7130-cib"; + reg = <0x10700 0x0000e000 0x0 0x8>, /* RAW */ + <0x10700 0x0000e100 0x0 0x8>; /* EN */ + cavium,max-bits = <23>; + + interrupt-controller; + interrupt-parent = <&ciu>; + interrupts = <1 24>; + /* Interrupts are specified by two parts: + * 1) Bit number in the CIB* registers + * 2) Triggering (1 - edge rising + * 2 - edge falling + * 4 - level active high + * 8 - level active low) + */ + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c2d0746b43d1cf9e86ecc0b5cdd33121b266edf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu.txt @@ -0,0 +1,26 @@ +* Central Interrupt Unit + +Properties: +- compatible: "cavium,octeon-3860-ciu" + + Compatibility with all cn3XXX, cn5XXX and cn63XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is the bank within + the CIU and may have a value of 0 or 1. The second cell is the bit + within the bank and may have a value between 0 and 63. + +Example: + interrupt-controller@1070000000000 { + compatible = "cavium,octeon-3860-ciu"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0 or 1) + * 2) Bit within the register (0..63) + */ + #interrupt-cells = <2>; + reg = <0x10700 0x00000000 0x0 0x7000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu2.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu2.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ec7ba8bbbcb2bfc55d36acee83003e0ab4285de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu2.txt @@ -0,0 +1,27 @@ +* Central Interrupt Unit + +Properties: +- compatible: "cavium,octeon-6880-ciu2" + + Compatibility with 68XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is the bank within + the CIU and may have a value between 0 and 63. The second cell is + the bit within the bank and may also have a value between 0 and 63. + +Example: + interrupt-controller@1070100000000 { + compatible = "cavium,octeon-6880-ciu2"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Controller register (0..63) + * 2) Bit within the register (0..63) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10701 0x00000000 0x0 0x4000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu3.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu3.txt new file mode 100644 index 0000000000000000000000000000000000000000..616862ad2b71dba58a6658a4b8ed116fa6ea703e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/ciu3.txt @@ -0,0 +1,27 @@ +* Central Interrupt Unit v3 + +Properties: +- compatible: "cavium,octeon-7890-ciu3" + + Compatibility with 78XX and 73XX SOCs. + +- interrupt-controller: This is an interrupt controller. + +- reg: The base address of the CIU's register bank. + +- #interrupt-cells: Must be <2>. The first cell is source number. + The second cell indicates the triggering semantics, and may have a + value of either 4 for level semantics, or 1 for edge semantics. + +Example: + interrupt-controller@1010000000000 { + compatible = "cavium,octeon-7890-ciu3"; + interrupt-controller; + /* Interrupts are specified by two parts: + * 1) Source number (20 significant bits) + * 2) Trigger type: (4 == level, 1 == edge) + */ + #address-cells = <0>; + #interrupt-cells = <2>; + reg = <0x10100 0x00000000 0x0 0xb0000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/dma-engine.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/dma-engine.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5bdff400002e159d14e975f99d8bb2263ba7d85 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/dma-engine.txt @@ -0,0 +1,21 @@ +* DMA Engine. + +The Octeon DMA Engine transfers between the Boot Bus and main memory. +The DMA Engine will be referred to by phandle by any device that is +connected to it. + +Properties: +- compatible: "cavium,octeon-5750-bootbus-dma" + + Compatibility with all cn52XX, cn56XX and cn6XXX SOCs. + +- reg: The base address of the DMA Engine's register bank. + +- interrupts: A single interrupt specifier. + +Example: + dma0: dma-engine@1180000000100 { + compatible = "cavium,octeon-5750-bootbus-dma"; + reg = <0x11800 0x00000100 0x0 0x8>; + interrupts = <0 63>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/sata-uctl.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/sata-uctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bd3c2f0b9b1de7b22df8192eaae58d5580516ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/sata-uctl.txt @@ -0,0 +1,42 @@ +* UCTL SATA controller glue + +UCTL is the bridge unit between the I/O interconnect (an internal bus) +and the SATA AHCI host controller (UAHC). It performs the following functions: + - provides interfaces for the applications to access the UAHC AHCI + registers on the CN71XX I/O space. + - provides a bridge for UAHC to fetch AHCI command table entries and data + buffers from Level 2 Cache. + - posts interrupts to the CIU. + - contains registers that: + - control the behavior of the UAHC + - control the clock/reset generation to UAHC + - control endian swapping for all UAHC registers and DMA accesses + +Properties: + +- compatible: "cavium,octeon-7130-sata-uctl" + + Compatibility with the cn7130 SOC. + +- reg: The base address of the UCTL register bank. + +- #address-cells, #size-cells, ranges and dma-ranges must be present and hold + suitable values to map all child nodes. + +Example: + + uctl@118006c000000 { + compatible = "cavium,octeon-7130-sata-uctl"; + reg = <0x11800 0x6c000000 0x0 0x100>; + ranges; /* Direct mapping */ + dma-ranges; + #address-cells = <2>; + #size-cells = <2>; + + sata: sata@16c0000000000 { + compatible = "cavium,octeon-7130-ahci"; + reg = <0x16c00 0x00000000 0x0 0x200>; + interrupt-parent = <&cibsata>; + interrupts = <2 4>; /* Bit: 2, level */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cavium/uctl.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/uctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa66b9b8d8013df6a0b175a8c6697ce4c8f5204c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cavium/uctl.txt @@ -0,0 +1,46 @@ +* UCTL USB controller glue + +Properties: +- compatible: "cavium,octeon-6335-uctl" + + Compatibility with all cn6XXX SOCs. + +- reg: The base address of the UCTL register bank. + +- #address-cells: Must be <2>. + +- #size-cells: Must be <2>. + +- ranges: Empty to signify direct mapping of the children. + +- refclk-frequency: A single cell containing the reference clock + frequency in Hz. + +- refclk-type: A string describing the reference clock connection + either "crystal" or "external". + +Example: + uctl@118006f000000 { + compatible = "cavium,octeon-6335-uctl"; + reg = <0x11800 0x6f000000 0x0 0x100>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + /* 12MHz, 24MHz and 48MHz allowed */ + refclk-frequency = <24000000>; + /* Either "crystal" or "external" */ + refclk-type = "crystal"; + + ehci@16f0000000000 { + compatible = "cavium,octeon-6335-ehci","usb-ehci"; + reg = <0x16f00 0x00000000 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + ohci@16f0000000400 { + compatible = "cavium,octeon-6335-ohci","usb-ohci"; + reg = <0x16f00 0x00000400 0x0 0x100>; + interrupts = <0 56>; + big-endian-regs; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/cpu_irq.txt b/arch/arm64/boot/dts/vendor/bindings/mips/cpu_irq.txt new file mode 100644 index 0000000000000000000000000000000000000000..f080f06da6d89d8dc4c4751b5e8be4a392f9c7cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/cpu_irq.txt @@ -0,0 +1,47 @@ +MIPS CPU interrupt controller + +On MIPS the mips_cpu_irq_of_init() helper can be used to initialize the 8 CPU +IRQs from a devicetree file and create a irq_domain for IRQ controller. + +With the irq_domain in place we can describe how the 8 IRQs are wired to the +platforms internal interrupt controller cascade. + +Below is an example of a platform describing the cascade inside the devicetree +and the code used to load it inside arch_init_irq(). + +Required properties: +- compatible : Should be "mti,cpu-interrupt-controller" + +Example devicetree: + cpu-irq: cpu-irq { + #address-cells = <0>; + + interrupt-controller; + #interrupt-cells = <1>; + + compatible = "mti,cpu-interrupt-controller"; + }; + + intc: intc@200 { + compatible = "ralink,rt2880-intc"; + reg = <0x200 0x100>; + + interrupt-controller; + #interrupt-cells = <1>; + + interrupt-parent = <&cpu-irq>; + interrupts = <2>; + }; + + +Example platform irq.c: +static struct of_device_id __initdata of_irq_ids[] = { + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, + { .compatible = "ralink,rt2880-intc", .data = intc_of_init }, + {}, +}; + +void __init arch_init_irq(void) +{ + of_irq_init(of_irq_ids); +} diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/img/pistachio-marduk.txt b/arch/arm64/boot/dts/vendor/bindings/mips/img/pistachio-marduk.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d5126d529a21597c58405a9af19fff6378a212d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/img/pistachio-marduk.txt @@ -0,0 +1,10 @@ +Imagination Technologies' Pistachio SoC based Marduk Board +========================================================== + +Compatible string must be "img,pistachio-marduk", "img,pistachio" + +Hardware and other related documentation is available at +https://docs.creatordev.io/ci40/ + +It is also known as Creator Ci40. Marduk is legacy name and will +be there for decades. diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/img/pistachio.txt b/arch/arm64/boot/dts/vendor/bindings/mips/img/pistachio.txt new file mode 100644 index 0000000000000000000000000000000000000000..a736d889c2b87dc619229e9e86b29c9fbc0f9e22 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/img/pistachio.txt @@ -0,0 +1,42 @@ +Imagination Pistachio SoC +========================= + +Required properties: +-------------------- + - compatible: Must include "img,pistachio". + +CPU nodes: +---------- +A "cpus" node is required. Required properties: + - #address-cells: Must be 1. + - #size-cells: Must be 0. +A CPU sub-node is also required for at least CPU 0. Since the topology may +be probed via CPS, it is not necessary to specify secondary CPUs. Required +propertis: + - device_type: Must be "cpu". + - compatible: Must be "mti,interaptiv". + - reg: CPU number. + - clocks: Must include the CPU clock. See ../../clock/clock-bindings.txt for + details on clock bindings. +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "mti,interaptiv"; + reg = <0>; + clocks = <&clk_core CLK_MIPS>; + }; + }; + + +Boot protocol: +-------------- +In accordance with the MIPS UHI specification[1], the bootloader must pass the +following arguments to the kernel: + - $a0: -2. + - $a1: KSEG0 address of the flattened device-tree blob. + +[1] http://prplfoundation.org/wiki/MIPS_documentation diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/img/xilfpga.txt b/arch/arm64/boot/dts/vendor/bindings/mips/img/xilfpga.txt new file mode 100644 index 0000000000000000000000000000000000000000..57e7ee942166fb6b0092202c8016a6599a2017a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/img/xilfpga.txt @@ -0,0 +1,83 @@ +Imagination University Program MIPSfpga +======================================= + +Under the Imagination University Program, a microAptiv UP core has been +released for academic usage. + +As we are dealing with a MIPS core instantiated on an FPGA, specifications +are fluid and can be varied in RTL. + +This binding document is provided as baseline guidance for the example +project provided by IMG. + +The example project runs on the Nexys4DDR board by Digilent powered by +the ARTIX-7 FPGA by Xilinx. + +Relevant details about the example project and the Nexys4DDR board: + +- microAptiv UP core m14Kc +- 50MHz clock speed +- 128Mbyte DDR RAM at 0x0000_0000 +- 8Kbyte RAM at 0x1000_0000 +- axi_intc at 0x1020_0000 +- axi_uart16550 at 0x1040_0000 +- axi_gpio at 0x1060_0000 +- axi_i2c at 0x10A0_0000 +- custom_gpio at 0x10C0_0000 +- axi_ethernetlite at 0x10E0_0000 +- 8Kbyte BootRAM at 0x1FC0_0000 + +Required properties: +-------------------- + - compatible: Must include "digilent,nexys4ddr","img,xilfpga". + +CPU nodes: +---------- +A "cpus" node is required. Required properties: + - #address-cells: Must be 1. + - #size-cells: Must be 0. +A CPU sub-node is also required for at least CPU 0. Required properties: + - device_type: Must be "cpu". + - compatible: Must be "mips,m14Kc". + - reg: Must be <0>. + - clocks: phandle to ext clock for fixed-clock received by MIPS core. + +Example: + + compatible = "img,xilfpga","digilent,nexys4ddr"; + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "mips,m14Kc"; + reg = <0>; + clocks = <&ext>; + }; + }; + + ext: ext { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + }; + +Boot protocol: +-------------- + +The BootRAM is a writeable "RAM" in FPGA at 0x1FC0_0000. +This is for easy reprogrammibility via JTAG. + +The BootRAM initializes the cache and the axi_uart peripheral. + +DDR initialization is already handled by a HW IP block. + +When the example project bitstream is loaded, the cpu_reset button +needs to be pressed. + +The bootram initializes the cache and axi_uart. +Then outputs MIPSFPGA\n\r on the serial port on the Nexys4DDR board. + +At this point, the board is ready to load the Linux kernel +vmlinux file via JTAG. diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/fpi-bus.txt b/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/fpi-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a2df433833202fd80903720d9ca9e45dad306ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/fpi-bus.txt @@ -0,0 +1,31 @@ +Lantiq XWAY SoC FPI BUS binding +============================ + + +------------------------------------------------------------------------------- +Required properties: +- compatible : Should be one of + "lantiq,xrx200-fpi" +- reg : The address and length of the XBAR + configuration register. + Address and length of the FPI bus itself. +- lantiq,rcu : A phandle to the RCU syscon +- lantiq,offset-endianness : Offset of the endianness configuration + register + +------------------------------------------------------------------------------- +Example for the FPI on the xrx200 SoCs: + fpi@10000000 { + compatible = "lantiq,xrx200-fpi"; + ranges = <0x0 0x10000000 0xf000000>; + reg = <0x1f400000 0x1000>, + <0x10000000 0xf000000>; + lantiq,rcu = <&rcu0>; + lantiq,offset-endianness = <0x4c>; + #address-cells = <1>; + #size-cells = <1>; + + gptu@e100a00 { + ...... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/rcu-gphy.txt b/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/rcu-gphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0c19bd1ce6625e603a658aba8420e033cf60910 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/rcu-gphy.txt @@ -0,0 +1,36 @@ +Lantiq XWAY SoC GPHY binding +============================ + +This binding describes a software-defined ethernet PHY, provided by the RCU +module on newer Lantiq XWAY SoCs (xRX200 and newer). + +------------------------------------------------------------------------------- +Required properties: +- compatible : Should be one of + "lantiq,xrx200a1x-gphy" + "lantiq,xrx200a2x-gphy" + "lantiq,xrx300-gphy" + "lantiq,xrx330-gphy" +- reg : Addrress of the GPHY FW load address register +- resets : Must reference the RCU GPHY reset bit +- reset-names : One entry, value must be "gphy" or optional "gphy2" +- clocks : A reference to the (PMU) GPHY clock gate + +Optional properties: +- lantiq,gphy-mode : GPHY_MODE_GE (default) or GPHY_MODE_FE as defined in + + + +------------------------------------------------------------------------------- +Example for the GPHys on the xRX200 SoCs: + +#include + gphy0: gphy@20 { + compatible = "lantiq,xrx200a2x-gphy"; + reg = <0x20 0x4>; + + resets = <&reset0 31 30>, <&reset1 7 7>; + reset-names = "gphy", "gphy2"; + clocks = <&pmu0 XRX200_PMU_GATE_GPHY>; + lantiq,gphy-mode = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/rcu.txt b/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/rcu.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f0822b4beae404f630ba9d222b8560d5440fcec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/lantiq/rcu.txt @@ -0,0 +1,87 @@ +Lantiq XWAY SoC RCU binding +=========================== + +This binding describes the RCU (reset controller unit) multifunction device, +where each sub-device has it's own set of registers. + +The RCU register range is used for multiple purposes. Mostly one device +uses one or multiple register exclusively, but for some registers some +bits are for one driver and some other bits are for a different driver. +With this patch all accesses to the RCU registers will go through +syscon. + + +------------------------------------------------------------------------------- +Required properties: +- compatible : The first and second values must be: + "lantiq,xrx200-rcu", "simple-mfd", "syscon" +- reg : The address and length of the system control registers + + +------------------------------------------------------------------------------- +Example of the RCU bindings on a xRX200 SoC: + rcu0: rcu@203000 { + compatible = "lantiq,xrx200-rcu", "simple-mfd", "syscon"; + reg = <0x203000 0x100>; + ranges = <0x0 0x203000 0x100>; + big-endian; + + gphy0: gphy@20 { + compatible = "lantiq,xrx200a2x-gphy"; + reg = <0x20 0x4>; + + resets = <&reset0 31 30>, <&reset1 7 7>; + reset-names = "gphy", "gphy2"; + lantiq,gphy-mode = ; + }; + + gphy1: gphy@68 { + compatible = "lantiq,xrx200a2x-gphy"; + reg = <0x68 0x4>; + + resets = <&reset0 29 28>, <&reset1 6 6>; + reset-names = "gphy", "gphy2"; + lantiq,gphy-mode = ; + }; + + reset0: reset-controller@10 { + compatible = "lantiq,xrx200-reset"; + reg = <0x10 4>, <0x14 4>; + + #reset-cells = <2>; + }; + + reset1: reset-controller@48 { + compatible = "lantiq,xrx200-reset"; + reg = <0x48 4>, <0x24 4>; + + #reset-cells = <2>; + }; + + usb_phy0: usb2-phy@18 { + compatible = "lantiq,xrx200-usb2-phy"; + reg = <0x18 4>, <0x38 4>; + + resets = <&reset1 4 4>, <&reset0 4 4>; + reset-names = "phy", "ctrl"; + #phy-cells = <0>; + }; + + usb_phy1: usb2-phy@34 { + compatible = "lantiq,xrx200-usb2-phy"; + reg = <0x34 4>, <0x3C 4>; + + resets = <&reset1 5 4>, <&reset0 4 4>; + reset-names = "phy", "ctrl"; + #phy-cells = <0>; + }; + + reboot@10 { + compatible = "syscon-reboot"; + reg = <0x10 4>; + + regmap = <&rcu0>; + offset = <0x10>; + mask = <0x40000000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/mscc.txt b/arch/arm64/boot/dts/vendor/bindings/mips/mscc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae15ec33354274669e5589f5c076d2e5aeb97734 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/mscc.txt @@ -0,0 +1,43 @@ +* Microsemi MIPS CPUs + +Boards with a SoC of the Microsemi MIPS family shall have the following +properties: + +Required properties: +- compatible: "mscc,ocelot" + + +* Other peripherals: + +o CPU chip regs: + +The SoC has a few registers (DEVCPU_GCB:CHIP_REGS) handling miscellaneous +functionalities: chip ID, general purpose register for software use, reset +controller, hardware status and configuration, efuses. + +Required properties: +- compatible: Should be "mscc,ocelot-chip-regs", "simple-mfd", "syscon" +- reg : Should contain registers location and length + +Example: + syscon@71070000 { + compatible = "mscc,ocelot-chip-regs", "simple-mfd", "syscon"; + reg = <0x71070000 0x1c>; + }; + + +o CPU system control: + +The SoC has a few registers (ICPU_CFG:CPU_SYSTEM_CTRL) handling configuration of +the CPU: 8 general purpose registers, reset control, CPU en/disabling, CPU +endianness, CPU bus control, CPU status. + +Required properties: +- compatible: Should be "mscc,ocelot-cpu-syscon", "syscon" +- reg : Should contain registers location and length + +Example: + syscon@70000000 { + compatible = "mscc,ocelot-cpu-syscon", "syscon"; + reg = <0x70000000 0x2c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/ni.txt b/arch/arm64/boot/dts/vendor/bindings/mips/ni.txt new file mode 100644 index 0000000000000000000000000000000000000000..722bf2d62da9644f3595e8125d53a0c80c184d31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/ni.txt @@ -0,0 +1,7 @@ +National Instruments MIPS platforms + +required root node properties: + - compatible: must be "ni,169445" + +CPU Nodes + - compatible: must be "mti,mips14KEc" diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/pic32/microchip,pic32mzda.txt b/arch/arm64/boot/dts/vendor/bindings/mips/pic32/microchip,pic32mzda.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c8dbc45feec7ba34f7a1154ccc0013d4f8c8b99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/pic32/microchip,pic32mzda.txt @@ -0,0 +1,31 @@ +* Microchip PIC32MZDA Platforms + +PIC32MZDA Starter Kit +Required root node properties: + - compatible = "microchip,pic32mzda-sk", "microchip,pic32mzda" + +CPU nodes: +---------- +A "cpus" node is required. Required properties: + - #address-cells: Must be 1. + - #size-cells: Must be 0. +A CPU sub-node is also required. Required properties: + - device_type: Must be "cpu". + - compatible: Must be "mti,mips14KEc". +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "mti,mips14KEc"; + }; + }; + +Boot protocol +-------------- +In accordance with Unified Hosting Interface Reference Manual (MD01069), the +bootloader must pass the following arguments to the kernel: + - $a0: -2. + - $a1: KSEG0 address of the flattened device-tree blob. diff --git a/arch/arm64/boot/dts/vendor/bindings/mips/ralink.txt b/arch/arm64/boot/dts/vendor/bindings/mips/ralink.txt new file mode 100644 index 0000000000000000000000000000000000000000..a16e8d7fe56c55eb8c9486f1e8825a6e18fc16ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mips/ralink.txt @@ -0,0 +1,18 @@ +Ralink MIPS SoC device tree bindings + +1. SoCs + +Each device tree must specify a compatible value for the Ralink SoC +it uses in the compatible property of the root node. The compatible +value must be one of the following values: + + ralink,rt2880-soc + ralink,rt3050-soc + ralink,rt3052-soc + ralink,rt3350-soc + ralink,rt3352-soc + ralink,rt3883-soc + ralink,rt5350-soc + ralink,mt7620a-soc + ralink,mt7620n-soc + ralink,mt7628a-soc diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/allwinner,syscon.txt b/arch/arm64/boot/dts/vendor/bindings/misc/allwinner,syscon.txt new file mode 100644 index 0000000000000000000000000000000000000000..31494a24fe6989a9d8f384900366b744e37becc6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/allwinner,syscon.txt @@ -0,0 +1,20 @@ +* Allwinner sun8i system controller + +This file describes the bindings for the system controller present in +Allwinner SoC H3, A83T and A64. +The principal function of this syscon is to control EMAC PHY choice and +config. + +Required properties for the system controller: +- reg: address and length of the register for the device. +- compatible: should be "syscon" and one of the following string: + "allwinner,sun8i-h3-system-controller" + "allwinner,sun8i-v3s-system-controller" + "allwinner,sun50i-a64-system-controller" + "allwinner,sun8i-a83t-system-controller" + +Example: +syscon: syscon@1c00000 { + compatible = "allwinner,sun8i-h3-system-controller", "syscon"; + reg = <0x01c00000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/aspeed,cvic.txt b/arch/arm64/boot/dts/vendor/bindings/misc/aspeed,cvic.txt new file mode 100644 index 0000000000000000000000000000000000000000..d62c783d1d5ea24036671d8ae4d67edbfe32a84d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/aspeed,cvic.txt @@ -0,0 +1,35 @@ +* ASPEED AST2400 and AST2500 coprocessor interrupt controller + +This file describes the bindings for the interrupt controller present +in the AST2400 and AST2500 BMC SoCs which provides interrupt to the +ColdFire coprocessor. + +It is not a normal interrupt controller and it would be rather +inconvenient to create an interrupt tree for it as it somewhat shares +some of the same sources as the main ARM interrupt controller but with +different numbers. + +The AST2500 supports a SW generated interrupt + +Required properties: +- reg: address and length of the register for the device. +- compatible: "aspeed,cvic" and one of: + "aspeed,ast2400-cvic" + or + "aspeed,ast2500-cvic" + +- valid-sources: One cell, bitmap of supported sources for the implementation + +Optional properties; +- copro-sw-interrupts: List of interrupt numbers that can be used as + SW interrupts from the ARM to the coprocessor. + (AST2500 only) + +Example: + + cvic: copro-interrupt-controller@1e6c2000 { + compatible = "aspeed,ast2500-cvic"; + valid-sources = <0xffffffff>; + copro-sw-interrupts = <1>; + reg = <0x1e6c2000 0x80>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/atmel-ssc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/atmel-ssc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9fb412642fe09937adeeafd620859af858c0952 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/atmel-ssc.txt @@ -0,0 +1,50 @@ +* Atmel SSC driver. + +Required properties: +- compatible: "atmel,at91rm9200-ssc" or "atmel,at91sam9g45-ssc" + - atmel,at91rm9200-ssc: support pdc transfer + - atmel,at91sam9g45-ssc: support dma transfer +- reg: Should contain SSC registers location and length +- interrupts: Should contain SSC interrupt +- clock-names: tuple listing input clock names. + Required elements: "pclk" +- clocks: phandles to input clocks. + + +Required properties for devices compatible with "atmel,at91sam9g45-ssc": +- dmas: DMA specifier, consisting of a phandle to DMA controller node, + the memory interface and SSC DMA channel ID (for tx and rx). + See Documentation/devicetree/bindings/dma/atmel-dma.txt for details. +- dma-names: Must be "tx", "rx". + +Optional properties: + - atmel,clk-from-rk-pin: bool property. + - When SSC works in slave mode, according to the hardware design, the + clock can get from TK pin, and also can get from RK pin. So, add + this parameter to choose where the clock from. + - By default the clock is from TK pin, if the clock from RK pin, this + property is needed. + - #sound-dai-cells: Should contain <0>. + - This property makes the SSC into an automatically registered DAI. + +Examples: +- PDC transfer: +ssc0: ssc@fffbc000 { + compatible = "atmel,at91rm9200-ssc"; + reg = <0xfffbc000 0x4000>; + interrupts = <14 4 5>; + clocks = <&ssc0_clk>; + clock-names = "pclk"; +}; + +- DMA transfer: +ssc0: ssc@f0010000 { + compatible = "atmel,at91sam9g45-ssc"; + reg = <0xf0010000 0x4000>; + interrupts = <28 4 5>; + dmas = <&dma0 1 13>, + <&dma0 1 14>; + dma-names = "tx", "rx"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/brcm,kona-smc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/brcm,kona-smc.txt new file mode 100644 index 0000000000000000000000000000000000000000..05b47232ed9ed647a97df99e7b4c175352748fb6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/brcm,kona-smc.txt @@ -0,0 +1,15 @@ +Broadcom Secure Monitor Bounce buffer +----------------------------------------------------- +This binding defines the location of the bounce buffer +used for non-secure to secure communications. + +Required properties: +- compatible : "brcm,kona-smc" +- DEPRECATED: compatible : "bcm,kona-smc" +- reg : Location and size of bounce buffer + +Example: + smc@3404c000 { + compatible = "brcm,bcm11351-smc", "brcm,kona-smc"; + reg = <0x3404c000 0x400>; //1 KiB in SRAM + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/eeprom-93xx46.txt b/arch/arm64/boot/dts/vendor/bindings/misc/eeprom-93xx46.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8ebb4621f7903ee920636ec1ff5fc124efb695f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/eeprom-93xx46.txt @@ -0,0 +1,25 @@ +EEPROMs (SPI) compatible with Microchip Technology 93xx46 family. + +Required properties: +- compatible : shall be one of: + "atmel,at93c46d" + "eeprom-93xx46" +- data-size : number of data bits per word (either 8 or 16) + +Optional properties: +- read-only : parameter-less property which disables writes to the EEPROM +- select-gpios : if present, specifies the GPIO that will be asserted prior to + each access to the EEPROM (e.g. for SPI bus multiplexing) + +Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt +apply. In particular, "reg" and "spi-max-frequency" properties must be given. + +Example: + eeprom@0 { + compatible = "eeprom-93xx46"; + reg = <0>; + spi-max-frequency = <1000000>; + spi-cs-high; + data-size = <8>; + select-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/fpc,fpc1028.txt b/arch/arm64/boot/dts/vendor/bindings/misc/fpc,fpc1028.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fe3536a9292af344ac6970ee52e967243b0367e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/fpc,fpc1028.txt @@ -0,0 +1,85 @@ +Fingerprint Cards AB. Fpc1028 driver + +The fpc1028 fingerprint sensor is connected to the host processor via SPI. +The sensor will generates interrupts when the user touches the sensor. +The host controller is expected to read data over SPI and pass the data to +the rest of the system. + +This binding document describes the properties for this module. + +Properties: + +- compatible + Usage: required + Value type: + Definition: It must be "fpc,fpc1020" + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-parent + Usage: required + Value type: + Definition: phandle of the interrupt controller which services the + summary interrupt. + +- fpc,gpio_rst + Usage: required + Value type: + Definition: GPIO which connecting to the reset pin of fpc1028 + +- fpc,gpio_irq + Usage: required + Value type: + Definition: Specifies the GPIO which connecting to the irq pin of fpc1028. + +- vcc_spi-supply + Usage: optional + Value type: + Definition: The phandle of the regulator which supplies fpc1028 spi bus core. + +- vcc_io-supply + Usage: optional + Value type: + Definition: The phandle of the regulator which supplies fpc1028 io pins. + +- vcc_ana-supply + Usage: optional + Value type: + Definition: The phandle of the regulator which supplies fpc1028 analog circuit. + +- pinctrl-names: + Usage: required + Value type: + Definition: Pinctrl state names for each pin group configuration. + eg:"fpc1020_reset_reset", "fpc1020_reset_active", "fpc1020_irq_active". + refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + +- pinctrl-n: + Usage: required + Value type: + Definition: pinctrl state for each pin group + refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + + +Example: + + fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <48 0>; + fpc,gpio_rst = <&tlmm 124 0x0>; + fpc,gpio_irq = <&tlmm 48 0>; + vcc_spi-supply = <&pm8953_l5>; + vdd_io-supply = <&pm8953_l5>; + vdd_ana-supply = <&pm8953_l5>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&msm_gpio_124>; + pinctrl-1 = <&msm_gpio_124_output_high>; + pinctrl-2 = <&msm_gpio_48>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/fsl,qoriq-mc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/fsl,qoriq-mc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6611a7c2053ae669c89c3d74ba7aec836c54bdc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/fsl,qoriq-mc.txt @@ -0,0 +1,119 @@ +* Freescale Management Complex + +The Freescale Management Complex (fsl-mc) is a hardware resource +manager that manages specialized hardware objects used in +network-oriented packet processing applications. After the fsl-mc +block is enabled, pools of hardware resources are available, such as +queues, buffer pools, I/O interfaces. These resources are building +blocks that can be used to create functional hardware objects/devices +such as network interfaces, crypto accelerator instances, L2 switches, +etc. + +Required properties: + + - compatible + Value type: + Definition: Must be "fsl,qoriq-mc". A Freescale Management Complex + compatible with this binding must have Block Revision + Registers BRR1 and BRR2 at offset 0x0BF8 and 0x0BFC in + the MC control register region. + + - reg + Value type: + Definition: A standard property. Specifies one or two regions + defining the MC's registers: + + -the first region is the command portal for the + this machine and must always be present + + -the second region is the MC control registers. This + region may not be present in some scenarios, such + as in the device tree presented to a virtual machine. + + - msi-parent + Value type: + Definition: Must be present and point to the MSI controller node + handling message interrupts for the MC. + + - ranges + Value type: + Definition: A standard property. Defines the mapping between the child + MC address space and the parent system address space. + + The MC address space is defined by 3 components: + + + Valid values for region type are + 0x0 - MC portals + 0x1 - QBMAN portals + + - #address-cells + Value type: + Definition: Must be 3. (see definition in 'ranges' property) + + - #size-cells + Value type: + Definition: Must be 1. + +Sub-nodes: + + The fsl-mc node may optionally have dpmac sub-nodes that describe + the relationship between the Ethernet MACs which belong to the MC + and the Ethernet PHYs on the system board. + + The dpmac nodes must be under a node named "dpmacs" which contains + the following properties: + + - #address-cells + Value type: + Definition: Must be present if dpmac sub-nodes are defined and must + have a value of 1. + + - #size-cells + Value type: + Definition: Must be present if dpmac sub-nodes are defined and must + have a value of 0. + + These nodes must have the following properties: + + - compatible + Value type: + Definition: Must be "fsl,qoriq-mc-dpmac". + + - reg + Value type: + Definition: Specifies the id of the dpmac. + + - phy-handle + Value type: + Definition: Specifies the phandle to the PHY device node associated + with the this dpmac. + +Example: + + fsl_mc: fsl-mc@80c000000 { + compatible = "fsl,qoriq-mc"; + reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ + <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ + msi-parent = <&its>; + #address-cells = <3>; + #size-cells = <1>; + + /* + * Region type 0x0 - MC portals + * Region type 0x1 - QBMAN portals + */ + ranges = <0x0 0x0 0x0 0x8 0x0c000000 0x4000000 + 0x1 0x0 0x0 0x8 0x18000000 0x8000000>; + + dpmacs { + #address-cells = <1>; + #size-cells = <0>; + + dpmac@1 { + compatible = "fsl,qoriq-mc-dpmac"; + reg = <1>; + phy-handle = <&mdio0_phy0>; + } + } + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/ge-achc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/ge-achc.txt new file mode 100644 index 0000000000000000000000000000000000000000..77df94d7a32f57658976c87ab9dc0f33096fd7f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/ge-achc.txt @@ -0,0 +1,26 @@ +* GE Healthcare USB Management Controller + +A device which handles data aquisition from compatible USB based peripherals. +SPI is used for device management. + +Note: This device does not expose the peripherals as USB devices. + +Required properties: + +- compatible : Should be "ge,achc" + +Required SPI properties: + +- reg : Should be address of the device chip select within + the controller. + +- spi-max-frequency : Maximum SPI clocking speed of device in Hz, should be + 1MHz for the GE ACHC. + +Example: + +spidev0: spi@0 { + compatible = "ge,achc"; + reg = <0>; + spi-max-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/idt_89hpesx.txt b/arch/arm64/boot/dts/vendor/bindings/misc/idt_89hpesx.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9093b79ab7d596f5768b7c7ad0028166c73d13c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/idt_89hpesx.txt @@ -0,0 +1,44 @@ +EEPROM / CSR SMBus-slave interface of IDT 89HPESx devices + +Required properties: + - compatible : should be "," + Basically there is only one manufacturer: idt, but some + compatible devices may be produced in future. Following devices + are supported: 89hpes8nt2, 89hpes12nt3, 89hpes24nt6ag2, + 89hpes32nt8ag2, 89hpes32nt8bg2, 89hpes12nt12g2, 89hpes16nt16g2, + 89hpes24nt24g2, 89hpes32nt24ag2, 89hpes32nt24bg2; + 89hpes12n3, 89hpes12n3a, 89hpes24n3, 89hpes24n3a; + 89hpes32h8, 89hpes32h8g2, 89hpes48h12, 89hpes48h12g2, + 89hpes48h12ag2, 89hpes16h16, 89hpes22h16, 89hpes22h16g2, + 89hpes34h16, 89hpes34h16g2, 89hpes64h16, 89hpes64h16g2, + 89hpes64h16ag2; + 89hpes12t3g2, 89hpes24t3g2, 89hpes16t4, 89hpes4t4g2, + 89hpes10t4g2, 89hpes16t4g2, 89hpes16t4ag2, 89hpes5t5, + 89hpes6t5, 89hpes8t5, 89hpes8t5a, 89hpes24t6, 89hpes6t6g2, + 89hpes24t6g2, 89hpes16t7, 89hpes32t8, 89hpes32t8g2, + 89hpes48t12, 89hpes48t12g2. + - reg : I2C address of the IDT 89HPESx device. + +Optionally there can be EEPROM-compatible subnode: + - compatible: There are five EEPROM devices supported: 24c32, 24c64, 24c128, + 24c256 and 24c512 differed by size. + - reg: Custom address of EEPROM device (If not specified IDT 89HPESx + (optional) device will try to communicate with EEPROM sited by default + address - 0x50) + - read-only : Parameterless property disables writes to the EEPROM + (optional) + +Example: + idt@60 { + compatible = "idt,89hpes32nt8ag2"; + reg = <0x74>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@50 { + compatible = "onsemi,24c64"; + reg = <0x50>; + read-only; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/ifm-csi.txt b/arch/arm64/boot/dts/vendor/bindings/misc/ifm-csi.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bdfffb0b9f7c00ffcbe6c313d5c17f2b72dab1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/ifm-csi.txt @@ -0,0 +1,41 @@ +IFM camera sensor interface on mpc5200 LocalPlus bus + +Required properties: +- compatible: "ifm,o2d-csi" +- reg: specifies sensor chip select number and associated address range +- interrupts: external interrupt line number and interrupt sense mode + of the interrupt line signaling frame valid events +- gpios: three gpio-specifiers for "capture", "reset" and "master enable" + GPIOs (strictly in this order). +- ifm,csi-clk-handle: the phandle to a node in the DT describing the sensor + clock generator. This node is usually a general purpose timer controller. +- ifm,csi-addr-bus-width: address bus width (valid values are 16, 24, 25) +- ifm,csi-data-bus-width: data bus width (valid values are 8 and 16) +- ifm,csi-wait-cycles: sensor bus wait cycles + +Optional properties: +- ifm,csi-byte-swap: if this property is present, the byte swapping on + the bus will be enabled. + +Example: + + csi@3,0 { + compatible = "ifm,o2d-csi"; + reg = <3 0 0x00100000>; /* CS 3, 1 MiB range */ + interrupts = <1 1 2>; /* IRQ1, edge falling */ + + ifm,csi-clk-handle = <&timer7>; + gpios = <&gpio_simple 23 0 /* image_capture */ + &gpio_simple 26 0 /* image_reset */ + &gpio_simple 29 0>; /* image_master_en */ + + ifm,csi-addr-bus-width = <24>; + ifm,csi-data-bus-width = <8>; + ifm,csi-wait-cycles = <0>; + }; + +The base address of the used chip select is specified in the +ranges property of the parent localbus node, for example: + + ranges = <0 0 0xff000000 0x01000000 + 3 0 0xe3000000 0x00100000>; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/maxim-xrfancontroller.txt b/arch/arm64/boot/dts/vendor/bindings/misc/maxim-xrfancontroller.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f973c1e8c4add0763fa64bf82127942837be4ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/maxim-xrfancontroller.txt @@ -0,0 +1,10 @@ +MAXIM-FANCONTROLLER provides a way to configure maxim-fanconroller driver. + +Required properties: +- compatible : should be "maxim,xrfancontroller" + +Optional properties: +Example: + xrfancontroller { + compatible = "maxim,xrfancontroller"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/memory-state-time.txt b/arch/arm64/boot/dts/vendor/bindings/misc/memory-state-time.txt new file mode 100644 index 0000000000000000000000000000000000000000..c99a506c030d9bc07ca718318b387629c1e1ae2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/memory-state-time.txt @@ -0,0 +1,8 @@ +Memory bandwidth and frequency state tracking + +Required properties: +- compatible : should be: + "memory-state-time" +- freq-tbl: Should contain entries with each frequency in Hz. +- bw-buckets: Should contain upper-bound limits for each bandwidth bucket in Mbps. + Must match the framework power_profile.xml for the device. diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/nvidia,tegra186-misc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/nvidia,tegra186-misc.txt new file mode 100644 index 0000000000000000000000000000000000000000..892ba4384abc7c9ff42df64e414b5ebdb35f0aa9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/nvidia,tegra186-misc.txt @@ -0,0 +1,12 @@ +NVIDIA Tegra186 MISC register block + +The MISC register block found on Tegra186 SoCs contains registers that can be +used to identify a given chip and various strapping options. + +Required properties: +- compatible: Must be: + - Tegra186: "nvidia,tegra186-misc" +- reg: Should contain 2 entries: The first entry gives the physical address + and length of the register region which contains revision and debug + features. The second entry specifies the physical address and length + of the register region indicating the strapping options. diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/nvidia,tegra20-apbmisc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/nvidia,tegra20-apbmisc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4556359c58763bbd3cc60e36b0cea160b8e823fb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/nvidia,tegra20-apbmisc.txt @@ -0,0 +1,14 @@ +NVIDIA Tegra20/Tegra30/Tegr114/Tegra124 apbmisc block + +Required properties: +- compatible : For Tegra20, must be "nvidia,tegra20-apbmisc". For Tegra30, + must be "nvidia,tegra30-apbmisc". Otherwise, must contain + "nvidia,-apbmisc", plus one of the above, where is tegra114, + tegra124, tegra132. +- reg: Should contain 2 entries: the first entry gives the physical address + and length of the registers which contain revision and debug features. + The second entry gives the physical address and length of the + registers indicating the strapping options. + +Optional properties: +- nvidia,long-ram-code: If present, the RAM code is long (4 bit). If not, short (2 bit). diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/qpnp-misc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/qpnp-misc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ada8da9ea3d4e51da806f14b6eca74e033e4ba0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/qpnp-misc.txt @@ -0,0 +1,31 @@ +QPNP-MISC + +QPNP-MISC provides a way to read the PMIC part number and revision. + +Required properties: +- compatible : should be "qcom,qpnp-misc" +- reg : offset and length of the PMIC peripheral register map. + +Optional properties: +- qcom,pwm-sel: Select PWM source. Possible values: + 0: LOW + 1: PWM1_in + 2: PWM2_in + 3: PWM1_in & PWM2_in +- qcom,enable-gp-driver: Enable the GP driver. Should only be specified + if a non-zero PWM source is specified under + "qcom,pwm-sel" property. + +- qcom,support-twm-config Enable configuration for TWM mode. + +- qcom,twm-mode The TWM mode which PMIC enters post power-off. + Valid only if 'qcom,support-twm-config' is + defined. If not specified, the default mode + is 3. +Example: + qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + qcom,pwm-sel = <2>; + qcom,enable-gp-driver; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/misc/xr-stdalonevwr-misc.txt b/arch/arm64/boot/dts/vendor/bindings/misc/xr-stdalonevwr-misc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6769fec73d8539d12ccc4375a1a22f0bd1175f2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/misc/xr-stdalonevwr-misc.txt @@ -0,0 +1,10 @@ +XR-STDALONEVWR-MISC provides a way to configure xrstdalonevwr-misc driver. + +Required properties: +- compatible : should be "qcom,xr-stdalonevwr-misc" + +Optional properties: +Example: + qcom,xr-stdalonevwr-misc { + compatible = "qcom,xr-stdalonevwr-misc"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/amlogic,meson-gx.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/amlogic,meson-gx.txt new file mode 100644 index 0000000000000000000000000000000000000000..13e70409e8ac6250676eba2d6e31be6187410168 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/amlogic,meson-gx.txt @@ -0,0 +1,35 @@ +Amlogic SD / eMMC controller for S905/GXBB family SoCs + +The MMC 5.1 compliant host controller on Amlogic provides the +interface for SD, eMMC and SDIO devices. + +This file documents the properties in addition to those available in +the MMC core bindings, documented by mmc.txt. + +Required properties: +- compatible : contains one of: + - "amlogic,meson-gx-mmc" + - "amlogic,meson-gxbb-mmc" + - "amlogic,meson-gxl-mmc" + - "amlogic,meson-gxm-mmc" + - "amlogic,meson-axg-mmc" +- clocks : A list of phandle + clock-specifier pairs for the clocks listed in clock-names. +- clock-names: Should contain the following: + "core" - Main peripheral bus clock + "clkin0" - Parent clock of internal mux + "clkin1" - Other parent clock of internal mux + The driver has an internal mux clock which switches between clkin0 and clkin1 depending on the + clock rate requested by the MMC core. +- resets : phandle of the internal reset line + +Example: + + sd_emmc_a: mmc@70000 { + compatible = "amlogic,meson-gxbb-mmc"; + reg = <0x0 0x70000 0x0 0x2000>; + interrupts = < GIC_SPI 216 IRQ_TYPE_EDGE_RISING>; + clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>; + clock-names = "core", "clkin0", "clkin1"; + pinctrl-0 = <&emmc_pins>; + resets = <&reset RESET_SD_EMMC_A>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/amlogic,meson-mx-sdio.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/amlogic,meson-mx-sdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..8765c605e6bc761db2923ad748b5bb70d40ea830 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/amlogic,meson-mx-sdio.txt @@ -0,0 +1,54 @@ +* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller + +The highspeed MMC host controller on Amlogic SoCs provides an interface +for MMC, SD, SDIO and SDHC types of memory cards. + +Supported maximum speeds are the ones of the eMMC standard 4.41 as well +as the speed of SD standard 2.0. + +The hardware provides an internal "mux" which allows up to three slots +to be controlled. Only one slot can be accessed at a time. + +Required properties: + - compatible : must be one of + - "amlogic,meson8-sdio" + - "amlogic,meson8b-sdio" + along with the generic "amlogic,meson-mx-sdio" + - reg : mmc controller base registers + - interrupts : mmc controller interrupt + - #address-cells : must be 1 + - size-cells : must be 0 + - clocks : phandle to clock providers + - clock-names : must contain "core" and "clkin" + +Required child nodes: +A node for each slot provided by the MMC controller is required. +NOTE: due to a driver limitation currently only one slot (= child node) + is supported! + +Required properties on each child node (= slot): + - compatible : must be "mmc-slot" (see mmc.txt within this directory) + - reg : the slot (or "port") ID + +Optional properties on each child node (= slot): + - bus-width : must be 1 or 4 (8-bit bus is not supported) + - for cd and all other additional generic mmc parameters + please refer to mmc.txt within this directory + +Examples: + mmc@c1108c20 { + compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio"; + reg = <0xc1108c20 0x20>; + interrupts = <0 28 1>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>; + clock-names = "core", "clkin"; + + slot@1 { + compatible = "mmc-slot"; + reg = <1>; + + bus-width = <4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/arasan,sdhci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/arasan,sdhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6ddba31cb733ba75a8359b613f331268d601a17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/arasan,sdhci.txt @@ -0,0 +1,77 @@ +Device Tree Bindings for the Arasan SDHCI Controller + + The bindings follow the mmc[1], clock[2], interrupt[3] and phy[4] bindings. + Only deviations are documented here. + + [1] Documentation/devicetree/bindings/mmc/mmc.txt + [2] Documentation/devicetree/bindings/clock/clock-bindings.txt + [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + [4] Documentation/devicetree/bindings/phy/phy-bindings.txt + +Required Properties: + - compatible: Compatibility string. One of: + - "arasan,sdhci-8.9a": generic Arasan SDHCI 8.9a PHY + - "arasan,sdhci-4.9a": generic Arasan SDHCI 4.9a PHY + - "arasan,sdhci-5.1": generic Arasan SDHCI 5.1 PHY + - "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY + For this device it is strongly suggested to include arasan,soc-ctl-syscon. + - reg: From mmc bindings: Register location and length. + - clocks: From clock bindings: Handles to clock inputs. + - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" + - interrupts: Interrupt specifier + +Required Properties for "arasan,sdhci-5.1": + - phys: From PHY bindings: Phandle for the Generic PHY for arasan. + - phy-names: MUST be "phy_arasan". + +Optional Properties: + - arasan,soc-ctl-syscon: A phandle to a syscon device (see ../mfd/syscon.txt) + used to access core corecfg registers. Offsets of registers in this + syscon are determined based on the main compatible string for the device. + - clock-output-names: If specified, this will be the name of the card clock + which will be exposed by this device. Required if #clock-cells is + specified. + - #clock-cells: If specified this should be the value <0>. With this property + in place we will export a clock representing the Card Clock. This clock + is expected to be consumed by our PHY. You must also specify + - xlnx,fails-without-test-cd: when present, the controller doesn't work when + the CD line is not connected properly, and the line is not connected + properly. Test mode can be used to force the controller to function. + - xlnx,int-clock-stable-broken: when present, the controller always reports + that the internal clock is stable even when it is not. + +Example: + sdhci@e0100000 { + compatible = "arasan,sdhci-8.9a"; + reg = <0xe0100000 0x1000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&clkc 21>, <&clkc 32>; + interrupt-parent = <&gic>; + interrupts = <0 24 4>; + } ; + + sdhci@e2800000 { + compatible = "arasan,sdhci-5.1"; + reg = <0xe2800000 0x1000>; + clock-names = "clk_xin", "clk_ahb"; + clocks = <&cru 8>, <&cru 18>; + interrupt-parent = <&gic>; + interrupts = <0 24 4>; + phys = <&emmc_phy>; + phy-names = "phy_arasan"; + } ; + + sdhci: sdhci@fe330000 { + compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1"; + reg = <0x0 0xfe330000 0x0 0x10000>; + interrupts = ; + clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>; + clock-names = "clk_xin", "clk_ahb"; + arasan,soc-ctl-syscon = <&grf>; + assigned-clocks = <&cru SCLK_EMMC>; + assigned-clock-rates = <200000000>; + clock-output-names = "emmc_cardclock"; + phys = <&emmc_phy>; + phy-names = "phy_arasan"; + #clock-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/atmel-hsmci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/atmel-hsmci.txt new file mode 100644 index 0000000000000000000000000000000000000000..07ad02075a935455387f684c4b94435a68c70255 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/atmel-hsmci.txt @@ -0,0 +1,73 @@ +* Atmel High Speed MultiMedia Card Interface + +This controller on atmel products provides an interface for MMC, SD and SDIO +types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the atmel-mci driver. + +1) MCI node + +Required properties: +- compatible: should be "atmel,hsmci" +- #address-cells: should be one. The cell is the slot id. +- #size-cells: should be zero. +- at least one slot node +- clock-names: tuple listing input clock names. + Required elements: "mci_clk" +- clocks: phandles to input clocks. + +The node contains child nodes for each slot that the platform uses + +Example MCI node: + +mmc0: mmc@f0008000 { + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4>; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "mci_clk"; + clocks = <&mci0_clk>; + + [ child node definitions...] +}; + +2) slot nodes + +Required properties: +- reg: should contain the slot id. +- bus-width: number of data lines connected to the controller + +Optional properties: +- cd-gpios: specify GPIOs for card detection +- cd-inverted: invert the value of external card detect gpio line +- wp-gpios: specify GPIOs for write protection + +Example slot node: + +slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 0> + cd-inverted; +}; + +Example full MCI node: +mmc0: mmc@f0008000 { + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4>; + #address-cells = <1>; + #size-cells = <0>; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 0> + cd-inverted; + }; + slot@1 { + reg = <1>; + bus-width = <4>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/bluefield-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/bluefield-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b0f0999ea1a9681317c097674dc70e97e80709bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/bluefield-dw-mshc.txt @@ -0,0 +1,29 @@ +* Mellanox Bluefield SoC specific extensions to the Synopsys Designware + Mobile Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Mellanox Bluefield SoC +specific extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be one of the following. + - "mellanox,bluefield-dw-mshc": for controllers with Mellanox Bluefield SoC + specific extensions. + +Example: + + /* Mellanox Bluefield SoC MMC */ + mmc@6008000 { + compatible = "mellanox,bluefield-dw-mshc"; + reg = <0x6008000 0x400>; + interrupts = <32>; + fifo-depth = <0x100>; + clock-frequency = <24000000>; + bus-width = <8>; + cap-mmc-highspeed; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,bcm2835-sdhost.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,bcm2835-sdhost.txt new file mode 100644 index 0000000000000000000000000000000000000000..d876580ae3b837a9174e454d223c6fa4df7ce94e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,bcm2835-sdhost.txt @@ -0,0 +1,23 @@ +Broadcom BCM2835 SDHOST controller + +This file documents differences between the core properties described +by mmc.txt and the properties that represent the BCM2835 controller. + +Required properties: +- compatible: Should be "brcm,bcm2835-sdhost". +- clocks: The clock feeding the SDHOST controller. + +Optional properties: +- dmas: DMA channel for read and write. + See Documentation/devicetree/bindings/dma/dma.txt for details + +Example: + +sdhost: mmc@7e202000 { + compatible = "brcm,bcm2835-sdhost"; + reg = <0x7e202000 0x100>; + interrupts = <2 24>; + clocks = <&clocks BCM2835_CLOCK_VPU>; + dmas = <&dma 13>; + dma-names = "rx-tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,kona-sdhci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,kona-sdhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f5dd83f5bd95afd1b696e186681caae75c268b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,kona-sdhci.txt @@ -0,0 +1,21 @@ +Broadcom BCM281xx SDHCI + +This file documents differences between the core properties in mmc.txt +and the properties present in the bcm281xx SDHCI + +Required properties: +- compatible : Should be "brcm,kona-sdhci" +- DEPRECATED: compatible : Should be "bcm,kona-sdhci" +- clocks: phandle + clock specifier pair of the external clock + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + +Example: + +sdio2: sdio@3f1a0000 { + compatible = "brcm,kona-sdhci"; + reg = <0x3f1a0000 0x10000>; + clocks = <&sdio3_clk>; + interrupts = <0x0 74 0x4>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,sdhci-brcmstb.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,sdhci-brcmstb.txt new file mode 100644 index 0000000000000000000000000000000000000000..733b64a4d8eb73ea4424b6cb30d95c08189263eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,sdhci-brcmstb.txt @@ -0,0 +1,38 @@ +* BROADCOM BRCMSTB/BMIPS SDHCI Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-brcmstb driver. + +NOTE: The driver disables all UHS speed modes by default and depends +on Device Tree properties to enable them for SoC/Board combinations +that support them. + +Required properties: +- compatible: should be one of the following + - "brcm,bcm7425-sdhci" + - "brcm,bcm7445-sdhci" + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + +Example: + + sdhci@f03e0100 { + compatible = "brcm,bcm7425-sdhci"; + reg = <0xf03e0000 0x100>; + interrupts = <0x0 0x26 0x0>; + sdhci,auto-cmd12; + clocks = <&sw_sdio>; + sd-uhs-sdr50; + sd-uhs-ddr50; + }; + + sdhci@f03e0300 { + non-removable; + bus-width = <0x8>; + compatible = "brcm,bcm7425-sdhci"; + reg = <0xf03e0200 0x100>; + interrupts = <0x0 0x27 0x0>; + sdhci,auto-cmd12; + clocks = ; + mmc-hs200-1_8v; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,sdhci-iproc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,sdhci-iproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa90d253dc7ea00f79de2b7cb99477a87f1682b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/brcm,sdhci-iproc.txt @@ -0,0 +1,35 @@ +Broadcom IPROC SDHCI controller + +This file documents differences between the core properties described +by mmc.txt and the properties that represent the IPROC SDHCI controller. + +Required properties: +- compatible : Should be one of the following + "brcm,bcm2835-sdhci" + "brcm,sdhci-iproc-cygnus" + "brcm,sdhci-iproc" + +Use brcm2835-sdhci for Rasperry PI. + +Use sdhci-iproc-cygnus for Broadcom SDHCI Controllers +restricted to 32bit host accesses to SDHCI registers. + +Use sdhci-iproc for Broadcom SDHCI Controllers that allow standard +8, 16, 32-bit host access to SDHCI register. + +- clocks : The clock feeding the SDHCI controller. + +Optional properties: + - sdhci,auto-cmd12: specifies that controller should use auto CMD12. + +Example: + +sdhci0: sdhci@18041000 { + compatible = "brcm,sdhci-iproc-cygnus"; + reg = <0x18041000 0x100>; + interrupts = ; + clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>; + bus-width = <4>; + sdhci,auto-cmd12; + no-1-8-v; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/cavium-mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/cavium-mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1433e6201dff3c1b4bb4a79f80b8ccf47a33fdaf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/cavium-mmc.txt @@ -0,0 +1,57 @@ +* Cavium Octeon & ThunderX MMC controller + +The highspeed MMC host controller on Caviums SoCs provides an interface +for MMC and SD types of memory cards. + +Supported maximum speeds are the ones of the eMMC standard 4.41 as well +as the speed of SD standard 4.0. Only 3.3 Volt is supported. + +Required properties: + - compatible : should be one of: + cavium,octeon-6130-mmc + cavium,octeon-7890-mmc + cavium,thunder-8190-mmc + cavium,thunder-8390-mmc + mmc-slot + - reg : mmc controller base registers + - clocks : phandle + +Optional properties: + - for cd, bus-width and additional generic mmc parameters + please refer to mmc.txt within this directory + - cavium,cmd-clk-skew : number of coprocessor clocks before sampling command + - cavium,dat-clk-skew : number of coprocessor clocks before sampling data + +Deprecated properties: +- spi-max-frequency : use max-frequency instead +- cavium,bus-max-width : use bus-width instead +- power-gpios : use vmmc-supply instead +- cavium,octeon-6130-mmc-slot : use mmc-slot instead + +Examples: + mmc_1_4: mmc@1,4 { + compatible = "cavium,thunder-8390-mmc"; + reg = <0x0c00 0 0 0 0>; /* DEVFN = 0x0c (1:4) */ + #address-cells = <1>; + #size-cells = <0>; + clocks = <&sclk>; + + mmc-slot@0 { + compatible = "mmc-slot"; + reg = <0>; + vmmc-supply = <&mmc_supply_3v3>; + max-frequency = <42000000>; + bus-width = <4>; + cap-sd-highspeed; + }; + + mmc-slot@1 { + compatible = "mmc-slot"; + reg = <1>; + vmmc-supply = <&mmc_supply_3v3>; + max-frequency = <42000000>; + bus-width = <8>; + cap-mmc-highspeed; + non-removable; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/davinci_mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/davinci_mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..516fb0143d4c21d1c8e44a8846d55ea5458d7b74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/davinci_mmc.txt @@ -0,0 +1,32 @@ +* TI Highspeed MMC host controller for DaVinci + +The Highspeed MMC Host Controller on TI DaVinci family +provides an interface for MMC, SD and SDIO types of memory cards. + +This file documents the properties used by the davinci_mmc driver. + +Required properties: +- compatible: + Should be "ti,da830-mmc": for da830, da850, dm365 + Should be "ti,dm355-mmc": for dm355, dm644x + +Optional properties: +- bus-width: Number of data lines, can be <1>, <4>, or <8>, default <1> +- max-frequency: Maximum operating clock frequency, default 25MHz. +- dmas: List of DMA specifiers with the controller specific format + as described in the generic DMA client binding. A tx and rx + specifier is required. +- dma-names: RX and TX DMA request names. These strings correspond + 1:1 with the DMA specifiers listed in dmas. + +Example: +mmc0: mmc@1c40000 { + compatible = "ti,da830-mmc", + reg = <0x40000 0x1000>; + interrupts = <16>; + bus-width = <4>; + max-frequency = <50000000>; + dmas = <&edma 16 + &edma 17>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/exynos-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/exynos-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0419a63f73a01457a88e79bb9b61ff4b606fd011 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/exynos-dw-mshc.txt @@ -0,0 +1,92 @@ +* Samsung Exynos specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Samsung Exynos specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "samsung,exynos4210-dw-mshc": for controllers with Samsung Exynos4210 + specific extensions. + - "samsung,exynos4412-dw-mshc": for controllers with Samsung Exynos4412 + specific extensions. + - "samsung,exynos5250-dw-mshc": for controllers with Samsung Exynos5250 + specific extensions. + - "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420 + specific extensions. + - "samsung,exynos7-dw-mshc": for controllers with Samsung Exynos7 + specific extensions. + - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7 + specific extensions having an SMU. + +* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7. + +* samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value + in transmit mode and CIU clock phase shift value in receive mode for single + data rate mode operation. Refer notes below for the order of the cells and the + valid values. + +* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock phase shift value + in transmit mode and CIU clock phase shift value in receive mode for double + data rate mode operation. Refer notes below for the order of the cells and the + valid values. +* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase + shift value for hs400 mode operation. + + Notes for the sdr-timing and ddr-timing values: + + The order of the cells should be + - First Cell: CIU clock phase shift value for tx mode. + - Second Cell: CIU clock phase shift value for rx mode. + + Valid values for SDR and DDR CIU clock timing for Exynos5250: + - valid value for tx phase shift and rx phase shift is 0 to 7. + - when CIU clock divider value is set to 3, all possible 8 phase shift + values can be used. + - if CIU clock divider value is 0 (that is divide by 1), both tx and rx + phase shift clocks should be 0. + +* samsung,read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode + (Latency value for delay line in Read path) + +Required properties for a slot (Deprecated - Recommend to use one slot per host): + +* gpios: specifies a list of gpios used for command, clock and data bus. The + first gpio is the command line and the second gpio is the clock line. The + rest of the gpios (depending on the bus-width property) are the data lines in + no particular order. The format of the gpio specifier depends on the gpio + controller. +(Deprecated - Refer to Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt) + +Example: + + The MSHC controller node can be split into two portions, SoC specific and + board specific portions as listed below. + + dwmmc0@12200000 { + compatible = "samsung,exynos5250-dw-mshc"; + reg = <0x12200000 0x1000>; + interrupts = <0 75 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + dwmmc0@12200000 { + cap-mmc-highspeed; + cap-sd-highspeed; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + samsung,dw-mshc-ciu-div = <3>; + samsung,dw-mshc-sdr-timing = <2 3>; + samsung,dw-mshc-ddr-timing = <1 2>; + samsung,dw-mshc-hs400-timing = <0 2>; + samsung,read-strobe-delay = <90>; + bus-width = <8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-esdhc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-esdhc.txt new file mode 100644 index 0000000000000000000000000000000000000000..99c5cf8507e8d8311e4b55cd8116c334deb832ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-esdhc.txt @@ -0,0 +1,51 @@ +* Freescale Enhanced Secure Digital Host Controller (eSDHC) + +The Enhanced Secure Digital Host Controller provides an interface +for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the sdhci-esdhc driver. + +Required properties: + - compatible : should be "fsl,esdhc", or "fsl,-esdhc". + Possible compatibles for PowerPC: + "fsl,mpc8536-esdhc" + "fsl,mpc8378-esdhc" + "fsl,p2020-esdhc" + "fsl,p4080-esdhc" + "fsl,t1040-esdhc" + "fsl,t4240-esdhc" + Possible compatibles for ARM: + "fsl,ls1012a-esdhc" + "fsl,ls1088a-esdhc" + "fsl,ls1043a-esdhc" + "fsl,ls1046a-esdhc" + "fsl,ls2080a-esdhc" + - clock-frequency : specifies eSDHC base clock frequency. + +Optional properties: + - sdhci,wp-inverted : specifies that eSDHC controller reports + inverted write-protect state; New devices should use the generic + "wp-inverted" property. + - sdhci,1-bit-only : specifies that a controller can only handle + 1-bit data transfers. New devices should use the generic + "bus-width = <1>" property. + - sdhci,auto-cmd12: specifies that a controller can only handle auto + CMD12. + - voltage-ranges : two cells are required, first cell specifies minimum + slot voltage (mV), second cell specifies maximum slot voltage (mV). + Several ranges could be specified. + - little-endian : If the host controller is little-endian mode, specify + this property. The default endian mode is big-endian. + +Example: + +sdhci@2e000 { + compatible = "fsl,mpc8378-esdhc", "fsl,esdhc"; + reg = <0x2e000 0x1000>; + interrupts = <42 0x8>; + interrupt-parent = <&ipic>; + /* Filled in by U-Boot */ + clock-frequency = <0>; + voltage-ranges = <3300 3300>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-imx-esdhc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-imx-esdhc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e29050ec769653e54c7631c96e8dc698a2eb150 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-imx-esdhc.txt @@ -0,0 +1,54 @@ +* Freescale Enhanced Secure Digital Host Controller (eSDHC) for i.MX + +The Enhanced Secure Digital Host Controller on Freescale i.MX family +provides an interface for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the sdhci-esdhc-imx driver. + +Required properties: +- compatible : Should be "fsl,-esdhc", the supported chips include + "fsl,imx25-esdhc" + "fsl,imx35-esdhc" + "fsl,imx51-esdhc" + "fsl,imx53-esdhc" + "fsl,imx6q-usdhc" + "fsl,imx6sl-usdhc" + "fsl,imx6sx-usdhc" + "fsl,imx7d-usdhc" + +Optional properties: +- fsl,wp-controller : Indicate to use controller internal write protection +- fsl,delay-line : Specify the number of delay cells for override mode. + This is used to set the clock delay for DLL(Delay Line) on override mode + to select a proper data sampling window in case the clock quality is not good + due to signal path is too long on the board. Please refer to eSDHC/uSDHC + chapter, DLL (Delay Line) section in RM for details. +- voltage-ranges : Specify the voltage range in case there are software + transparent level shifters on the outputs of the controller. Two cells are + required, first cell specifies minimum slot voltage (mV), second cell + specifies maximum slot voltage (mV). Several ranges could be specified. +- fsl,tuning-start-tap: Specify the start dealy cell point when send first CMD19 + in tuning procedure. +- fsl,tuning-step: Specify the increasing delay cell steps in tuning procedure. + The uSDHC use one delay cell as default increasing step to do tuning process. + This property allows user to change the tuning step to more than one delay + cells which is useful for some special boards or cards when the default + tuning step can't find the proper delay window within limited tuning retries. + +Examples: + +esdhc@70004000 { + compatible = "fsl,imx51-esdhc"; + reg = <0x70004000 0x4000>; + interrupts = <1>; + fsl,wp-controller; +}; + +esdhc@70008000 { + compatible = "fsl,imx51-esdhc"; + reg = <0x70008000 0x4000>; + interrupts = <2>; + cd-gpios = <&gpio1 6 0>; /* GPIO1_6 */ + wp-gpios = <&gpio1 5 0>; /* GPIO1_5 */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-imx-mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-imx-mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..184ccffe273946dbb8f7e9c644fe135d55b8c7ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/fsl-imx-mmc.txt @@ -0,0 +1,23 @@ +* Freescale Secure Digital Host Controller for i.MX2/3 series + +This file documents differences to the properties defined in mmc.txt. + +Required properties: +- compatible : Should be "fsl,-mmc", chip can be imx21 or imx31 + +Optional properties: +- dmas: One DMA phandle with arguments as defined by the devicetree bindings + of the used DMA controller. +- dma-names: Has to be "rx-tx". + +Example: + +sdhci1: sdhci@10014000 { + compatible = "fsl,imx27-mmc", "fsl,imx21-mmc"; + reg = <0x10014000 0x1000>; + interrupts = <11>; + dmas = <&dma 7>; + dma-names = "rx-tx"; + bus-width = <4>; + cd-gpios = <&gpio3 29>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/hi3798cv200-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/hi3798cv200-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0693b7145f2aec0ee037ad5c1a5e9d626ed4dd4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/hi3798cv200-dw-mshc.txt @@ -0,0 +1,40 @@ +* Hisilicon Hi3798CV200 specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Hisilicon Hi3798CV200 +specific extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: +- compatible: Should contain "hisilicon,hi3798cv200-dw-mshc". +- clocks: A list of phandle + clock-specifier pairs for the clocks listed + in clock-names. +- clock-names: Should contain the following: + "ciu" - The ciu clock described in synopsys-dw-mshc.txt. + "biu" - The biu clock described in synopsys-dw-mshc.txt. + "ciu-sample" - Hi3798CV200 extended phase clock for ciu sampling. + "ciu-drive" - Hi3798CV200 extended phase clock for ciu driving. + +Example: + + emmc: mmc@9830000 { + compatible = "hisilicon,hi3798cv200-dw-mshc"; + reg = <0x9830000 0x10000>; + interrupts = ; + clocks = <&crg HISTB_MMC_CIU_CLK>, + <&crg HISTB_MMC_BIU_CLK>, + <&crg HISTB_MMC_SAMPLE_CLK>, + <&crg HISTB_MMC_DRV_CLK>; + clock-names = "ciu", "biu", "ciu-sample", "ciu-drive"; + fifo-depth = <256>; + clock-frequency = <200000000>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + non-removable; + bus-width = <8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/img-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/img-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c54e577eea0703c498d5fb397bd1d509f03faaa4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/img-dw-mshc.txt @@ -0,0 +1,28 @@ +* Imagination specific extensions to the Synopsys Designware Mobile Storage + Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Imagination specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "img,pistachio-dw-mshc": for Pistachio SoCs + +Example: + + mmc@18142000 { + compatible = "img,pistachio-dw-mshc"; + reg = <0x18142000 0x400>; + interrupts = ; + + clocks = <&system_clk>, <&sdhost_clk>; + clock-names = "biu", "ciu"; + + fifo-depth = <0x20>; + bus-width = <4>; + disable-wp; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/jz4740.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/jz4740.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cd8c432d7c8794eea64570aa233ea615432a6f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/jz4740.txt @@ -0,0 +1,38 @@ +* Ingenic JZ47xx MMC controllers + +This file documents the device tree properties used for the MMC controller in +Ingenic JZ4740/JZ4780 SoCs. These are in addition to the core MMC properties +described in mmc.txt. + +Required properties: +- compatible: Should be one of the following: + - "ingenic,jz4740-mmc" for the JZ4740 + - "ingenic,jz4780-mmc" for the JZ4780 +- reg: Should contain the MMC controller registers location and length. +- interrupts: Should contain the interrupt specifier of the MMC controller. +- clocks: Clock for the MMC controller. + +Optional properties: +- dmas: List of DMA specifiers with the controller specific format + as described in the generic DMA client binding. A tx and rx + specifier is required. +- dma-names: RX and TX DMA request names. + Should be "rx" and "tx", in that order. + +For additional details on DMA client bindings see ../dma/dma.txt. + +Example: + +mmc0: mmc@13450000 { + compatible = "ingenic,jz4780-mmc"; + reg = <0x13450000 0x1000>; + + interrupt-parent = <&intc>; + interrupts = <37>; + + clocks = <&cgu JZ4780_CLK_MSC0>; + clock-names = "mmc"; + + dmas = <&dma JZ4780_DMA_MSC0_RX 0xffffffff>, <&dma JZ4780_DMA_MSC0_TX 0xffffffff>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/k3-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/k3-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..07242d1417735c56576bc59742284957259a4660 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/k3-dw-mshc.txt @@ -0,0 +1,71 @@ +* Hisilicon specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Hisilicon specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be one of the following. + - "hisilicon,hi3660-dw-mshc": for controllers with hi3660 specific extensions. + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extensions. + - "hisilicon,hi6220-dw-mshc": for controllers with hi6220 specific extensions. + +Optional Properties: +- hisilicon,peripheral-syscon: phandle of syscon used to control peripheral. + +Example: + + /* for Hi3620 */ + + /* SoC portion */ + dwmmc_0: dwmmc0@fcd03000 { + compatible = "hisilicon,hi4511-dw-mshc"; + reg = <0xfcd03000 0x1000>; + interrupts = <0 16 4>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mmc_clock HI3620_SD_CIUCLK>, <&clock HI3620_DDRC_PER_CLK>; + clock-names = "ciu", "biu"; + }; + + /* Board portion */ + dwmmc0@fcd03000 { + vmmc-supply = <&ldo12>; + fifo-depth = <0x100>; + pinctrl-names = "default"; + pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>; + bus-width = <4>; + disable-wp; + cd-gpios = <&gpio10 3 0>; + cap-mmc-highspeed; + cap-sd-highspeed; + }; + + /* for Hi6220 */ + + dwmmc_1: dwmmc1@f723e000 { + compatible = "hisilicon,hi6220-dw-mshc"; + bus-width = <0x4>; + disable-wp; + cap-sd-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + card-detect-delay = <200>; + hisilicon,peripheral-syscon = <&ao_ctrl>; + reg = <0x0 0xf723e000 0x0 0x1000>; + interrupts = <0x0 0x49 0x4>; + clocks = <&clock_sys HI6220_MMC1_CIUCLK>, <&clock_sys HI6220_MMC1_CLK>; + clock-names = "ciu", "biu"; + cd-gpios = <&gpio1 0 1>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&sd_pmx_func &sd_clk_cfg_func &sd_cfg_func>; + pinctrl-1 = <&sd_pmx_idle &sd_clk_cfg_idle &sd_cfg_idle>; + vqmmc-supply = <&ldo7>; + vmmc-supply = <&ldo10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/marvell,xenon-sdhci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/marvell,xenon-sdhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed1456f5c94dda21ecaf2eebd86bcd7934d11376 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/marvell,xenon-sdhci.txt @@ -0,0 +1,172 @@ +Marvell Xenon SDHCI Controller device tree bindings +This file documents differences between the core mmc properties +described by mmc.txt and the properties used by the Xenon implementation. + +Multiple SDHCs might be put into a single Xenon IP, to save size and cost. +Each SDHC is independent and owns independent resources, such as register sets, +clock and PHY. +Each SDHC should have an independent device tree node. + +Required Properties: +- compatible: should be one of the following + - "marvell,armada-3700-sdhci": For controllers on Armada-3700 SoC. + Must provide a second register area and marvell,pad-type. + - "marvell,armada-ap806-sdhci": For controllers on Armada AP806. + - "marvell,armada-cp110-sdhci": For controllers on Armada CP110. + +- clocks: + Array of clocks required for SDHC. + Require at least input clock for Xenon IP core. For Armada AP806 and + CP110, the AXI clock is also mandatory. + +- clock-names: + Array of names corresponding to clocks property. + The input clock for Xenon IP core should be named as "core". + The input clock for the AXI bus must be named as "axi". + +- reg: + * For "marvell,armada-3700-sdhci", two register areas. + The first one for Xenon IP register. The second one for the Armada 3700 SoC + PHY PAD Voltage Control register. + Please follow the examples with compatible "marvell,armada-3700-sdhci" + in below. + Please also check property marvell,pad-type in below. + + * For other compatible strings, one register area for Xenon IP. + +Optional Properties: +- marvell,xenon-sdhc-id: + Indicate the corresponding bit index of current SDHC in + SDHC System Operation Control Register Bit[7:0]. + Set/clear the corresponding bit to enable/disable current SDHC. + If Xenon IP contains only one SDHC, this property is optional. + +- marvell,xenon-phy-type: + Xenon support multiple types of PHYs. + To select eMMC 5.1 PHY, set: + marvell,xenon-phy-type = "emmc 5.1 phy" + eMMC 5.1 PHY is the default choice if this property is not provided. + To select eMMC 5.0 PHY, set: + marvell,xenon-phy-type = "emmc 5.0 phy" + + All those types of PHYs can support eMMC, SD and SDIO. + Please note that this property only presents the type of PHY. + It doesn't stand for the entire SDHC type or property. + For example, "emmc 5.1 phy" doesn't mean that this Xenon SDHC only + supports eMMC 5.1. + +- marvell,xenon-phy-znr: + Set PHY ZNR value. + Only available for eMMC PHY. + Valid range = [0:0x1F]. + ZNR is set as 0xF by default if this property is not provided. + +- marvell,xenon-phy-zpr: + Set PHY ZPR value. + Only available for eMMC PHY. + Valid range = [0:0x1F]. + ZPR is set as 0xF by default if this property is not provided. + +- marvell,xenon-phy-nr-success-tun: + Set the number of required consecutive successful sampling points + used to identify a valid sampling window, in tuning process. + Valid range = [1:7]. + Set as 0x4 by default if this property is not provided. + +- marvell,xenon-phy-tun-step-divider: + Set the divider for calculating TUN_STEP. + Set as 64 by default if this property is not provided. + +- marvell,xenon-phy-slow-mode: + If this property is selected, transfers will bypass PHY. + Only available when bus frequency lower than 55MHz in SDR mode. + Disabled by default. Please only try this property if timing issues + always occur with PHY enabled in eMMC HS SDR, SD SDR12, SD SDR25, + SD Default Speed and HS mode and eMMC legacy speed mode. + +- marvell,xenon-tun-count: + Xenon SDHC SoC usually doesn't provide re-tuning counter in + Capabilities Register 3 Bit[11:8]. + This property provides the re-tuning counter. + If this property is not set, default re-tuning counter will + be set as 0x9 in driver. + +- marvell,pad-type: + Type of Armada 3700 SoC PHY PAD Voltage Controller register. + Only valid when "marvell,armada-3700-sdhci" is selected. + Two types: "sd" and "fixed-1-8v". + If "sd" is selected, SoC PHY PAD is set as 3.3V at the beginning and is + switched to 1.8V when later in higher speed mode. + If "fixed-1-8v" is selected, SoC PHY PAD is fixed 1.8V, such as for eMMC. + Please follow the examples with compatible "marvell,armada-3700-sdhci" + in below. + +Example: +- For eMMC: + + sdhci@aa0000 { + compatible = "marvell,armada-ap806-sdhci"; + reg = <0xaa0000 0x1000>; + interrupts = + clocks = <&emmc_clk>,<&axi_clk>; + clock-names = "core", "axi"; + bus-width = <4>; + marvell,xenon-phy-slow-mode; + marvell,xenon-tun-count = <11>; + non-removable; + no-sd; + no-sdio; + + /* Vmmc and Vqmmc are both fixed */ + }; + +- For SD/SDIO: + + sdhci@ab0000 { + compatible = "marvell,armada-cp110-sdhci"; + reg = <0xab0000 0x1000>; + interrupts = + vqmmc-supply = <&sd_vqmmc_regulator>; + vmmc-supply = <&sd_vmmc_regulator>; + clocks = <&sdclk>, <&axi_clk>; + clock-names = "core", "axi"; + bus-width = <4>; + marvell,xenon-tun-count = <9>; + }; + +- For eMMC with compatible "marvell,armada-3700-sdhci": + + sdhci@aa0000 { + compatible = "marvell,armada-3700-sdhci"; + reg = <0xaa0000 0x1000>, + ; + interrupts = + clocks = <&emmcclk>; + clock-names = "core"; + bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs400-1_8v; + non-removable; + no-sd; + no-sdio; + + /* Vmmc and Vqmmc are both fixed */ + + marvell,pad-type = "fixed-1-8v"; + }; + +- For SD/SDIO with compatible "marvell,armada-3700-sdhci": + + sdhci@ab0000 { + compatible = "marvell,armada-3700-sdhci"; + reg = <0xab0000 0x1000>, + ; + interrupts = + vqmmc-supply = <&sd_regulator>; + /* Vmmc is fixed */ + clocks = <&sdclk>; + clock-names = "core"; + bus-width = <4>; + + marvell,pad-type = "sd"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/microchip,sdhci-pic32.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/microchip,sdhci-pic32.txt new file mode 100644 index 0000000000000000000000000000000000000000..f064528effed31f30d1d1c6e0b49c02e215d99af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/microchip,sdhci-pic32.txt @@ -0,0 +1,29 @@ +* Microchip PIC32 SDHCI Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-pic32 driver. + +Required properties: +- compatible: Should be "microchip,pic32mzda-sdhci" +- interrupts: Should contain interrupt +- clock-names: Should be "base_clk", "sys_clk". + See: Documentation/devicetree/bindings/resource-names.txt +- clocks: Phandle to the clock. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- pinctrl-names: A pinctrl state names "default" must be defined. +- pinctrl-0: Phandle referencing pin configuration of the SDHCI controller. + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example: + + sdhci@1f8ec000 { + compatible = "microchip,pic32mzda-sdhci"; + reg = <0x1f8ec000 0x100>; + interrupts = <191 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rootclk REF4CLK>, <&rootclk PB5CLK>; + clock-names = "base_clk", "sys_clk"; + bus-width = <4>; + cap-sd-highspeed; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdhc1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-card.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d2d71758907ecd403af09f17799722d6b3c616c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-card.txt @@ -0,0 +1,30 @@ +mmc-card / eMMC bindings +------------------------ + +This documents describes the devicetree bindings for a mmc-host controller +child node describing a mmc-card / an eMMC, see "Use of Function subnodes" +in mmc.txt + +Required properties: +-compatible : Must be "mmc-card" +-reg : Must be <0> + +Optional properties: +-broken-hpi : Use this to indicate that the mmc-card has a broken hpi + implementation, and that hpi should not be used + +Example: + +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins_a>; + vmmc-supply = <®_vcc3v3>; + bus-width = <8>; + non-removable; + + mmccard: mmccard@0 { + reg = <0>; + compatible = "mmc-card"; + broken-hpi; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-emmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-emmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d965d57e00b302f1a216e5a3ecd7a4051902fbb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-emmc.txt @@ -0,0 +1,25 @@ +* The simple eMMC hardware reset provider + +The purpose of this driver is to perform standard eMMC hw reset +procedure, as described by Jedec 4.4 specification. This procedure is +performed just after MMC core enabled power to the given mmc host (to +fix possible issues if bootloader has left eMMC card in initialized or +unknown state), and before performing complete system reboot (also in +case of emergency reboot call). The latter is needed on boards, which +doesn't have hardware reset logic connected to emmc card and (limited or +broken) ROM bootloaders are unable to read second stage from the emmc +card if the card is left in unknown or already initialized state. + +Required properties: +- compatible : contains "mmc-pwrseq-emmc". +- reset-gpios : contains a GPIO specifier. The reset GPIO is asserted + and then deasserted to perform eMMC card reset. To perform + reset procedure as described in Jedec 4.4 specification, the + gpio line should be defined as GPIO_ACTIVE_LOW. + +Example: + + sdhci0_pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-sd8787.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-sd8787.txt new file mode 100644 index 0000000000000000000000000000000000000000..22e9340e4ba20dce393050b8ce0a0ce471210f57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-sd8787.txt @@ -0,0 +1,16 @@ +* Marvell SD8787 power sequence provider + +Required properties: +- compatible: must be "mmc-pwrseq-sd8787". +- powerdown-gpios: contains a power down GPIO specifier with the + default active state +- reset-gpios: contains a reset GPIO specifier with the default + active state + +Example: + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-sd8787"; + powerdown-gpios = <&twl_gpio 0 GPIO_ACTIVE_LOW>; + reset-gpios = <&twl_gpio 1 GPIO_ACTIVE_LOW>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-simple.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-simple.txt new file mode 100644 index 0000000000000000000000000000000000000000..9029b45b8a22a8d5b6a1afa3184bf389a85202f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-pwrseq-simple.txt @@ -0,0 +1,31 @@ +* The simple MMC power sequence provider + +The purpose of the simple MMC power sequence provider is to supports a set of +common properties between various SOC designs. It thus enables us to use the +same provider for several SOC designs. + +Required properties: +- compatible : contains "mmc-pwrseq-simple". + +Optional properties: +- reset-gpios : contains a list of GPIO specifiers. The reset GPIOs are asserted + at initialization and prior we start the power up procedure of the card. + They will be de-asserted right after the power has been provided to the + card. +- clocks : Must contain an entry for the entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entry: + "ext_clock" (External clock provided to the card). +- post-power-on-delay-ms : Delay in ms after powering the card and + de-asserting the reset-gpios (if any) +- power-off-delay-us : Delay in us after asserting the reset-gpios (if any) + during power off of the card. + +Example: + + sdhci0_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>; + clocks = <&clk_32768_ck>; + clock-names = "ext_clock"; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-spi-slot.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-spi-slot.txt new file mode 100644 index 0000000000000000000000000000000000000000..75486cca80541c6d83324a2767d6943294296403 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc-spi-slot.txt @@ -0,0 +1,29 @@ +MMC/SD/SDIO slot directly connected to a SPI bus + +This file documents differences between the core properties described +by mmc.txt and the properties used by the mmc_spi driver. + +Required properties: +- spi-max-frequency : maximum frequency for this device (Hz). +- voltage-ranges : two cells are required, first cell specifies minimum + slot voltage (mV), second cell specifies maximum slot voltage (mV). + Several ranges could be specified. + +Optional properties: +- gpios : may specify GPIOs in this order: Card-Detect GPIO, + Write-Protect GPIO. Note that this does not follow the + binding from mmc.txt, for historical reasons. + +Example: + + mmc-slot@0 { + compatible = "fsl,mpc8323rdb-mmc-slot", + "mmc-spi-slot"; + reg = <0>; + gpios = <&qe_pio_d 14 1 + &qe_pio_d 15 0>; + voltage-ranges = <3300 3300>; + spi-max-frequency = <50000000>; + interrupts = <42>; + interrupt-parent = <&PIC>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5a0923b34ca1e5dfd11f3c9ba03792a6963b5c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmc.txt @@ -0,0 +1,173 @@ +These properties are common to multiple MMC host controllers. Any host +that requires the respective functionality should implement them using +these definitions. + +Interpreted by the OF core: +- reg: Registers location and length. +- interrupts: Interrupts used by the MMC controller. + +Card detection: +If no property below is supplied, host native card detect is used. +Only one of the properties in this section should be supplied: + - broken-cd: There is no card detection available; polling must be used. + - cd-gpios: Specify GPIOs for card detection, see gpio binding + - non-removable: non-removable slot (like eMMC); assume always present. + +Optional properties: +- bus-width: Number of data lines, can be <1>, <4>, or <8>. The default + will be <1> if the property is absent. +- wp-gpios: Specify GPIOs for write protection, see gpio binding +- cd-inverted: when present, polarity on the CD line is inverted. See the note + below for the case, when a GPIO is used for the CD line +- cd-debounce-delay-ms: Set delay time before detecting card after card insert interrupt. + It's only valid when cd-gpios is present. +- wp-inverted: when present, polarity on the WP line is inverted. See the note + below for the case, when a GPIO is used for the WP line +- disable-wp: When set no physical WP line is present. This property should + only be specified when the controller has a dedicated write-protect + detection logic. If a GPIO is always used for the write-protect detection + logic it is sufficient to not specify wp-gpios property in the absence of a WP + line. +- max-frequency: maximum operating clock frequency +- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on + this system, even if the controller claims it is. +- cap-sd-highspeed: SD high-speed timing is supported +- cap-mmc-highspeed: MMC high-speed timing is supported +- sd-uhs-sdr12: SD UHS SDR12 speed is supported +- sd-uhs-sdr25: SD UHS SDR25 speed is supported +- sd-uhs-sdr50: SD UHS SDR50 speed is supported +- sd-uhs-sdr104: SD UHS SDR104 speed is supported +- sd-uhs-ddr50: SD UHS DDR50 speed is supported +- cap-power-off-card: powering off the card is safe +- cap-mmc-hw-reset: eMMC hardware reset is supported +- cap-sdio-irq: enable SDIO IRQ signalling on this interface +- full-pwr-cycle: full power cycle of the card is supported +- mmc-ddr-3_3v: eMMC high-speed DDR mode(3.3V I/O) is supported +- mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported +- mmc-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported +- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported +- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported +- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported +- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported +- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported +- dsr: Value the card's (optional) Driver Stage Register (DSR) should be + programmed with. Valid range: [0 .. 0xffff]. +- no-sdio: controller is limited to send sdio cmd during initialization +- no-sd: controller is limited to send sd cmd during initialization +- no-mmc: controller is limited to send mmc cmd during initialization +- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type. + The value is the driver type as specified in the eMMC specification + (table 206 in spec version 5.1). +- post-power-on-delay-ms : It was invented for MMC pwrseq-simple which could + be referred to mmc-pwrseq-simple.txt. But now it's reused as a tunable delay + waiting for I/O signalling and card power supply to be stable, regardless of + whether pwrseq-simple is used. Default to 10ms if no available. + +*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line +polarity properties, we have to fix the meaning of the "normal" and "inverted" +line levels. We choose to follow the SDHCI standard, which specifies both those +lines as "active low." Therefore, using the "cd-inverted" property means, that +the CD line is active high, i.e. it is high, when a card is inserted. Similar +logic applies to the "wp-inverted" property. + +CD and WP lines can be implemented on the hardware in one of two ways: as GPIOs, +specified in cd-gpios and wp-gpios properties, or as dedicated pins. Polarity of +dedicated pins can be specified, using *-inverted properties. GPIO polarity can +also be specified using the GPIO_ACTIVE_LOW flag. This creates an ambiguity +in the latter case. We choose to use the XOR logic for GPIO CD and WP lines. +This means, the two properties are "superimposed," for example leaving the +GPIO_ACTIVE_LOW flag clear and specifying the respective *-inverted property +property results in a double-inversion and actually means the "normal" line +polarity is in effect. + +Optional SDIO properties: +- keep-power-in-suspend: Preserves card power during a suspend/resume cycle +- wakeup-source: Enables wake up of host system on SDIO IRQ assertion + (Legacy property supported: "enable-sdio-wakeup") + +MMC power +--------- + +Controllers may implement power control from both the connected cards and +the IO signaling (for example to change to high-speed 1.8V signalling). If +the system supports this, then the following two properties should point +to valid regulator nodes: + +- vqmmc-supply: supply node for IO line power +- vmmc-supply: supply node for card's power + + +MMC power sequences: +-------------------- + +System on chip designs may specify a specific MMC power sequence. To +successfully detect an (e)MMC/SD/SDIO card, that power sequence must be +maintained while initializing the card. + +Optional property: +- mmc-pwrseq: phandle to the MMC power sequence node. See "mmc-pwrseq-*" + for documentation of MMC power sequence bindings. + + +Use of Function subnodes +------------------------ + +On embedded systems the cards connected to a host may need additional +properties. These can be specified in subnodes to the host controller node. +The subnodes are identified by the standard 'reg' property. +Which information exactly can be specified depends on the bindings for the +SDIO function driver for the subnode, as specified by the compatible string. + +Required host node properties when using function subnodes: +- #address-cells: should be one. The cell is the slot id. +- #size-cells: should be zero. + +Required function subnode properties: +- reg: Must contain the SDIO function number of the function this subnode + describes. A value of 0 denotes the memory SD function, values from + 1 to 7 denote the SDIO functions. + +Optional function subnode properties: +- compatible: name of SDIO function following generic names recommended practice + + +Examples +-------- + +Basic example: + +sdhci@ab000000 { + compatible = "sdhci"; + reg = <0xab000000 0x200>; + interrupts = <23>; + bus-width = <4>; + cd-gpios = <&gpio 69 0>; + cd-inverted; + wp-gpios = <&gpio 70 0>; + max-frequency = <50000000>; + keep-power-in-suspend; + wakeup-source; + mmc-pwrseq = <&sdhci0_pwrseq> +} + +Example with sdio function subnode: + +mmc3: mmc@1c12000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins_a>; + vmmc-supply = <®_vmmc3>; + bus-width = <4>; + non-removable; + mmc-pwrseq = <&sdhci0_pwrseq> + + brcmf: bcrmf@1 { + reg = <1>; + compatible = "brcm,bcm43xx-fmac"; + interrupt-parent = <&pio>; + interrupts = <10 8>; /* PH10 / EINT10 */ + interrupt-names = "host-wake"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mmci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mmci.txt new file mode 100644 index 0000000000000000000000000000000000000000..03796cf2d3e71353a0b169eb8f8323ff4d820730 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mmci.txt @@ -0,0 +1,61 @@ +* ARM PrimeCell MultiMedia Card Interface (MMCI) PL180/1 + +The ARM PrimeCell MMCI PL180 and PL181 provides an interface for +reading and writing to MultiMedia and SD cards alike. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the mmci driver. Using "st" as +the prefix for a property, indicates support by the ST Micro variant. + +Required properties: +- compatible : contains "arm,pl18x", "arm,primecell". +- vmmc-supply : phandle to the regulator device tree node, mentioned + as the VCC/VDD supply in the eMMC/SD specs. + +Optional properties: +- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides + the ID provided by the HW +- vqmmc-supply : phandle to the regulator device tree node, mentioned + as the VCCQ/VDD_IO supply in the eMMC/SD specs. +- st,sig-dir-dat0 : bus signal direction pin used for DAT[0]. +- st,sig-dir-dat2 : bus signal direction pin used for DAT[2]. +- st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1]. +- st,sig-dir-dat74 : bus signal direction pin used for DAT[4] to DAT[7]. +- st,sig-dir-cmd : cmd signal direction pin used for CMD. +- st,sig-pin-fbclk : feedback clock signal pin used. + +Deprecated properties: +- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable. +- mmc-cap-sd-highspeed : indicates whether SD is high speed capable. + +Example: + +sdi0_per1@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80126000 0x1000>; + interrupts = <0 60 IRQ_TYPE_LEVEL_HIGH>; + + dmas = <&dma 29 0 0x2>, /* Logical - DevToMem */ + <&dma 29 0 0x0>; /* Logical - MemToDev */ + dma-names = "rx", "tx"; + + clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; + clock-names = "sdi", "apb_pclk"; + + max-frequency = <100000000>; + bus-width = <4>; + cap-sd-highspeed; + cap-mmc-highspeed; + cd-gpios = <&gpio2 31 0x4>; // 95 + st,sig-dir-dat0; + st,sig-dir-dat2; + st,sig-dir-cmd; + st,sig-pin-fbclk; + + vmmc-supply = <&ab8500_ldo_aux3_reg>; + vqmmc-supply = <&vmmci>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdi0_default_mode>; + pinctrl-1 = <&sdi0_sleep_mode>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/moxa,moxart-mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/moxa,moxart-mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b63819149f22fbe13030d4fb90d101b7c3832f69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/moxa,moxart-mmc.txt @@ -0,0 +1,30 @@ +MOXA ART MMC Host Controller Interface + + Inherits from mmc binding[1]. + + [1] Documentation/devicetree/bindings/mmc/mmc.txt + +Required properties: + +- compatible : Must be "moxa,moxart-mmc" or "faraday,ftsdc010" +- reg : Should contain registers location and length +- interrupts : Should contain the interrupt number +- clocks : Should contain phandle for the clock feeding the MMC controller + +Optional properties: + +- dmas : Should contain two DMA channels, line request number must be 5 for + both channels +- dma-names : Must be "tx", "rx" + +Example: + + mmc: mmc@98e00000 { + compatible = "moxa,moxart-mmc"; + reg = <0x98e00000 0x5C>; + interrupts = <5 0>; + clocks = <&clk_apb>; + dmas = <&dma 5>, + <&dma 5>; + dma-names = "tx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mtk-sd.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mtk-sd.txt new file mode 100644 index 0000000000000000000000000000000000000000..f33467a54a05473560c6369663bb6a4c706f0959 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mtk-sd.txt @@ -0,0 +1,68 @@ +* MTK MMC controller + +The MTK MSDC can act as a MMC controller +to support MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties in mmc.txt +and the properties used by the msdc driver. + +Required properties: +- compatible: value should be either of the following. + "mediatek,mt8135-mmc": for mmc host ip compatible with mt8135 + "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173 + "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701 + "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712 + "mediatek,mt7622-mmc": for MT7622 SoC + "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC + +- reg: physical base address of the controller and length +- interrupts: Should contain MSDC interrupt number +- clocks: Should contain phandle for the clock feeding the MMC controller +- clock-names: Should contain the following: + "source" - source clock (required) + "hclk" - HCLK which used for host (required) + "source_cg" - independent source clock gate (required for MT2712) +- pinctrl-names: should be "default", "state_uhs" +- pinctrl-0: should contain default/high speed pin ctrl +- pinctrl-1: should contain uhs mode pin ctrl +- vmmc-supply: power to the Core +- vqmmc-supply: power to the IO + +Optional properties: +- assigned-clocks: PLL of the source clock +- assigned-clock-parents: parent of source clock, used for HS400 mode to get 400Mhz source clock +- hs400-ds-delay: HS400 DS delay setting +- mediatek,hs200-cmd-int-delay: HS200 command internal delay setting. + This field has total 32 stages. + The value is an integer from 0 to 31. +- mediatek,hs400-cmd-int-delay: HS400 command internal delay setting + This field has total 32 stages. + The value is an integer from 0 to 31. +- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection + If present,HS400 command responses are sampled on rising edges. + If not present,HS400 command responses are sampled on falling edges. +- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc + error caused by stop clock(fifo full) + Valid range = [0:0x7]. if not present, default value is 0. + applied to compatible "mediatek,mt2701-mmc". + +Examples: +mmc0: mmc@11230000 { + compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc"; + reg = <0 0x11230000 0 0x108>; + interrupts = ; + vmmc-supply = <&mt6397_vemc_3v3_reg>; + vqmmc-supply = <&mt6397_vio18_reg>; + clocks = <&pericfg CLK_PERI_MSDC30_0>, + <&topckgen CLK_TOP_MSDC50_0_H_SEL>; + clock-names = "source", "hclk"; + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_default>; + pinctrl-1 = <&mmc0_pins_uhs>; + assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>; + hs400-ds-delay = <0x14015>; + mediatek,hs200-cmd-int-delay = <26>; + mediatek,hs400-cmd-int-delay = <14>; + mediatek,hs400-cmd-resp-sel-rising; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/mxs-mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/mxs-mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..515addc200706293b21c654453a3dc8ba78eaa4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/mxs-mmc.txt @@ -0,0 +1,27 @@ +* Freescale MXS MMC controller + +The Freescale MXS Synchronous Serial Ports (SSP) can act as a MMC controller +to support MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties in mmc.txt +and the properties used by the mxsmmc driver. + +Required properties: +- compatible: Should be "fsl,-mmc". The supported chips include + imx23 and imx28. +- interrupts: Should contain ERROR interrupt number +- dmas: DMA specifier, consisting of a phandle to DMA controller node + and SSP DMA channel ID. + Refer to dma.txt and fsl-mxs-dma.txt for details. +- dma-names: Must be "rx-tx". + +Examples: + +ssp0: ssp@80010000 { + compatible = "fsl,imx28-mmc"; + reg = <0x80010000 2000>; + interrupts = <96>; + dmas = <&dma_apbh 0>; + dma-names = "rx-tx"; + bus-width = <8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/nvidia,tegra20-sdhci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/nvidia,tegra20-sdhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bce57862ed6ead2e693ee5bc2bcb6ef58f4c9f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/nvidia,tegra20-sdhci.txt @@ -0,0 +1,40 @@ +* NVIDIA Tegra Secure Digital Host Controller + +This controller on Tegra family SoCs provides an interface for MMC, SD, +and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the sdhci-tegra driver. + +Required properties: +- compatible : should be one of: + - "nvidia,tegra20-sdhci": for Tegra20 + - "nvidia,tegra30-sdhci": for Tegra30 + - "nvidia,tegra114-sdhci": for Tegra114 + - "nvidia,tegra124-sdhci": for Tegra124 and Tegra132 + - "nvidia,tegra210-sdhci": for Tegra210 + - "nvidia,tegra186-sdhci": for Tegra186 +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - sdhci + +Optional properties: +- power-gpios : Specify GPIOs for power control + +Example: + +sdhci@c8000200 { + compatible = "nvidia,tegra20-sdhci"; + reg = <0xc8000200 0x200>; + interrupts = <47>; + clocks = <&tegra_car 14>; + resets = <&tegra_car 14>; + reset-names = "sdhci"; + cd-gpios = <&gpio 69 0>; /* gpio PI5 */ + wp-gpios = <&gpio 57 0>; /* gpio PH1 */ + power-gpios = <&gpio 155 0>; /* gpio PT3 */ + bus-width = <8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/orion-sdio.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/orion-sdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..10f0818a34c59d9dfad7a5f2d80429fd1ebab7c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/orion-sdio.txt @@ -0,0 +1,16 @@ +* Marvell orion-sdio controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the orion-sdio driver. + +- compatible: Should be "marvell,orion-sdio" +- clocks: reference to the clock of the SDIO interface + +Example: + + mvsdio@d00d4000 { + compatible = "marvell,orion-sdio"; + reg = <0xd00d4000 0x200>; + interrupts = <54>; + clocks = <&gateclk 17>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/pxa-mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/pxa-mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f5c2bec2b8cdf42c6f771af2fe17361c9964915 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/pxa-mmc.txt @@ -0,0 +1,25 @@ +* PXA MMC drivers + +Driver bindings for the PXA MCI (MMC/SDIO) interfaces + +Required properties: +- compatible: Should be "marvell,pxa-mmc". +- vmmc-supply: A regulator for VMMC + +Optional properties: +- marvell,detect-delay-ms: sets the detection delay timeout in ms. + +In addition to the properties described in this docuent, the details +described in mmc.txt are supported. + +Examples: + +mmc0: mmc@41100000 { + compatible = "marvell,pxa-mmc"; + reg = <0x41100000 0x1000>; + interrupts = <23>; + vmmc-supply = <&mmc_regulator>; + cd-gpios = <&gpio 23 0>; + wp-gpios = <&gpio 24 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/renesas,mmcif.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/renesas,mmcif.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ff1e12c655a56b99804ed68bf3ffb954b371498 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/renesas,mmcif.txt @@ -0,0 +1,50 @@ +* Renesas Multi Media Card Interface (MMCIF) Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the MMCIF device. + + +Required properties: + +- compatible: should be "renesas,mmcif-", "renesas,sh-mmcif" as a + fallback. Examples with are: + - "renesas,mmcif-r7s72100" for the MMCIF found in r7s72100 SoCs + - "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs + - "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs + - "renesas,mmcif-r8a7743" for the MMCIF found in r8a7743 SoCs + - "renesas,mmcif-r8a7745" for the MMCIF found in r8a7745 SoCs + - "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs + - "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs + - "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs + - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs + - "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs + - "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs + +- interrupts: Some SoCs have only 1 shared interrupt, while others have either + 2 or 3 individual interrupts (error, int, card detect). Below is the number + of interrupts for each SoC: + 1: r8a73a4, r8a7743, r8a7745, r8a7778, r8a7790, r8a7791, r8a7793, r8a7794 + 2: r8a7740, sh73a0 + 3: r7s72100 + +- clocks: reference to the functional clock + +- dmas: reference to the DMA channels, one per channel name listed in the + dma-names property. +- dma-names: must contain "tx" for the transmit DMA channel and "rx" for the + receive DMA channel. +- max-frequency: Maximum operating clock frequency, driver uses default clock + frequency if it is not set. + + +Example: R8A7790 (R-Car H2) MMCIF0 + + mmcif0: mmc@ee200000 { + compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif"; + reg = <0 0xee200000 0 0x80>; + interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>; + dmas = <&dmac0 0xd1>, <&dmac0 0xd2>; + dma-names = "tx", "rx"; + max-frequency = <97500000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/rockchip-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/rockchip-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f629b12bd69bce2d11eea0f4cf0dde8d05afe84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/rockchip-dw-mshc.txt @@ -0,0 +1,49 @@ +* Rockchip specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Rockchip specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following, + before RK3288 + - "rockchip,rk3288-dw-mshc": for Rockchip RK3288 + - "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RV1108 + - "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip PX30 + - "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036 + - "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK322x + - "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3328 + - "rockchip,rk3368-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3368 + - "rockchip,rk3399-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3399 + +Optional Properties: +* clocks: from common clock binding: if ciu-drive and ciu-sample are + specified in clock-names, should contain handles to these clocks. + +* clock-names: Apart from the clock-names described in synopsys-dw-mshc.txt + two more clocks "ciu-drive" and "ciu-sample" are supported. They are used + to control the clock phases, "ciu-sample" is required for tuning high- + speed modes. + +* rockchip,default-sample-phase: The default phase to set ciu-sample at + probing, low speeds or in case where all phases work at tuning time. + If not specified 0 deg will be used. + +* rockchip,desired-num-phases: The desired number of times that the host + execute tuning when needed. If not specified, the host will do tuning + for 360 times, namely tuning for each degree. + +Example: + + rkdwmmc0@12200000 { + compatible = "rockchip,rk3288-dw-mshc"; + reg = <0x12200000 0x1000>; + interrupts = <0 75 0>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/samsung,s3cmci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/samsung,s3cmci.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f68feb9f9d61f2bd0cadfe38e8b5cd6d834cbec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/samsung,s3cmci.txt @@ -0,0 +1,42 @@ +* Samsung's S3C24XX MMC/SD/SDIO controller device tree bindings + +Samsung's S3C24XX MMC/SD/SDIO controller is used as a connectivity interface +with external MMC, SD and SDIO storage mediums. + +This file documents differences between the core mmc properties described by +mmc.txt and the properties used by the Samsung S3C24XX MMC/SD/SDIO controller +implementation. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "samsung,s3c2410-sdi": for controllers compatible with s3c2410 + - "samsung,s3c2412-sdi": for controllers compatible with s3c2412 + - "samsung,s3c2440-sdi": for controllers compatible with s3c2440 +- reg: register location and length +- interrupts: mmc controller interrupt +- clocks: Should reference the controller clock +- clock-names: Should contain "sdi" + +Required Board Specific Properties: +- pinctrl-0: Should specify pin control groups used for this controller. +- pinctrl-names: Should contain only one value - "default". + +Optional Properties: +- bus-width: number of data lines (see mmc.txt) +- cd-gpios: gpio for card detection (see mmc.txt) +- wp-gpios: gpio for write protection (see mmc.txt) + +Example: + + mmc0: mmc@5a000000 { + compatible = "samsung,s3c2440-sdi"; + pinctrl-names = "default"; + pinctrl-0 = <&sdi_pins>; + reg = <0x5a000000 0x100000>; + interrupts = <0 0 21 3>; + clocks = <&clocks PCLK_SDI>; + clock-names = "sdi"; + bus-width = <4>; + cd-gpios = <&gpg 8 GPIO_ACTIVE_LOW>; + wp-gpios = <&gph 8 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/samsung-sdhci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/samsung-sdhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..42e0a9afa1001104a499fa9de27e7ec742ee7848 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/samsung-sdhci.txt @@ -0,0 +1,32 @@ +* Samsung's SDHCI Controller device tree bindings + +Samsung's SDHCI controller is used as a connectivity interface with external +MMC, SD and eMMC storage mediums. This file documents differences between the +core mmc properties described by mmc.txt and the properties used by the +Samsung implementation of the SDHCI controller. + +Required SoC Specific Properties: +- compatible: should be one of the following + - "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci + controller. + - "samsung,exynos4210-sdhci": For controllers compatible with Exynos4 sdhci + controller. + +Required Board Specific Properties: +- pinctrl-0: Should specify pin control groups used for this controller. +- pinctrl-names: Should contain only one value - "default". + +Example: + sdhci@12530000 { + compatible = "samsung,exynos4210-sdhci"; + reg = <0x12530000 0x100>; + interrupts = <0 75 0>; + bus-width = <4>; + cd-gpios = <&gpk2 2 0>; + pinctrl-names = "default"; + pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>; + }; + + Note: This example shows both SoC specific and board specific properties + in a single device node. The properties can be actually be separated + into SoC specific node and board specific node. diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-atmel.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-atmel.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b662d7171a0f0b3c6b730df034bfbdb09676b11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-atmel.txt @@ -0,0 +1,21 @@ +* Atmel SDHCI controller + +This file documents the differences between the core properties in +Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the +sdhci-of-at91 driver. + +Required properties: +- compatible: Must be "atmel,sama5d2-sdhci". +- clocks: Phandlers to the clocks. +- clock-names: Must be "hclock", "multclk", "baseclk"; + + +Example: + +sdmmc0: sdio-host@a0000000 { + compatible = "atmel,sama5d2-sdhci"; + reg = <0xa0000000 0x300>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>; + clock-names = "hclock", "multclk", "baseclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-cadence.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-cadence.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa423c2778535bb50b89f805d1a295d1babbe210 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-cadence.txt @@ -0,0 +1,80 @@ +* Cadence SD/SDIO/eMMC Host Controller + +Required properties: +- compatible: should be one of the following: + "cdns,sd4hc" - default of the IP + "socionext,uniphier-sd4hc" - for Socionext UniPhier SoCs +- reg: offset and length of the register set for the device. +- interrupts: a single interrupt specifier. +- clocks: phandle to the input clock. + +Optional properties: +For eMMC configuration, supported speed modes are not indicated by the SDHCI +Capabilities Register. Instead, the following properties should be specified +if supported. See mmc.txt for details. +- mmc-ddr-1_8v +- mmc-ddr-1_2v +- mmc-hs200-1_8v +- mmc-hs200-1_2v +- mmc-hs400-1_8v +- mmc-hs400-1_2v + +Some PHY delays can be configured by following properties. +PHY DLL input delays: +They are used to delay the data valid window, and align the window +to sampling clock. The delay starts from 5ns (for delay parameter equal to 0) +and it is increased by 2.5ns in each step. +- cdns,phy-input-delay-sd-highspeed: + Value of the delay in the input path for SD high-speed timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-legacy: + Value of the delay in the input path for legacy timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-sd-uhs-sdr12: + Value of the delay in the input path for SD UHS SDR12 timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-sd-uhs-sdr25: + Value of the delay in the input path for SD UHS SDR25 timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-sd-uhs-sdr50: + Value of the delay in the input path for SD UHS SDR50 timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-sd-uhs-ddr50: + Value of the delay in the input path for SD UHS DDR50 timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-mmc-highspeed: + Value of the delay in the input path for MMC high-speed timing + Valid range = [0:0x1F]. +- cdns,phy-input-delay-mmc-ddr: + Value of the delay in the input path for eMMC high-speed DDR timing + Valid range = [0:0x1F]. + +PHY DLL clock delays: +Each delay property represents the fraction of the clock period. +The approximate delay value will be +(/128)*sdmclk_clock_period. +- cdns,phy-dll-delay-sdclk: + Value of the delay introduced on the sdclk output + for all modes except HS200, HS400 and HS400_ES. + Valid range = [0:0x7F]. +- cdns,phy-dll-delay-sdclk-hsmmc: + Value of the delay introduced on the sdclk output + for HS200, HS400 and HS400_ES speed modes. + Valid range = [0:0x7F]. +- cdns,phy-dll-delay-strobe: + Value of the delay introduced on the dat_strobe input + used in HS400 / HS400_ES speed modes. + Valid range = [0:0x7F]. + +Example: + emmc: sdhci@5a000000 { + compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc"; + reg = <0x5a000000 0x400>; + interrupts = <0 78 4>; + clocks = <&clk 4>; + bus-width = <8>; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + cdns,phy-dll-delay-sdclk = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-dove.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-dove.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae9aab9abcd70d0977d9f7ef39fe02e384efa97a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-dove.txt @@ -0,0 +1,14 @@ +* Marvell sdhci-dove controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers. + +- compatible: Should be "marvell,dove-sdhci". + +Example: + +sdio0: sdio@92000 { + compatible = "marvell,dove-sdhci"; + reg = <0x92000 0x100>; + interrupts = <35>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-fujitsu.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-fujitsu.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ee9263adf7354cfc7d62e0839f2fb91ef8bda5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-fujitsu.txt @@ -0,0 +1,32 @@ +* Fujitsu SDHCI controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci_f_sdh30 driver. + +Required properties: +- compatible: "fujitsu,mb86s70-sdhci-3.0" +- clocks: Must contain an entry for each entry in clock-names. It is a + list of phandles and clock-specifier pairs. + See ../clocks/clock-bindings.txt for details. +- clock-names: Should contain the following two entries: + "iface" - clock used for sdhci interface + "core" - core clock for sdhci controller + +Optional properties: +- vqmmc-supply: phandle to the regulator device tree node, mentioned + as the VCCQ/VDD_IO supply in the eMMC/SD specs. +- fujitsu,cmd-dat-delay-select: boolean property indicating that this host + requires the CMD_DAT_DELAY control to be enabled. + +Example: + + sdhci1: mmc@36600000 { + compatible = "fujitsu,mb86s70-sdhci-3.0"; + reg = <0 0x36600000 0x1000>; + interrupts = <0 172 0x4>, + <0 173 0x4>; + bus-width = <4>; + vqmmc-supply = <&vccq_sdhci1>; + clocks = <&clock 2 2 0>, <&clock 2 3 0>; + clock-names = "iface", "core"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-msm.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-msm.txt new file mode 100644 index 0000000000000000000000000000000000000000..81ed29fb6f846e73ebe2820bb2d100d7dc7a83f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-msm.txt @@ -0,0 +1,183 @@ +Qualcomm Technologies, Inc. Standard Secure Digital Host Controller (SDHC) + +Secure Digital Host Controller provides standard host interface to SD/MMC/SDIO cards. + +Required properties: + - compatible : should be "qcom,sdhci-msm" + For SDCC version 5.0.0, MCI registers are removed from SDCC interface + and some registers are moved to HC. New compatible string is added to + support this change - "qcom,sdhci-msm-v5". + To support SDCC version 4.0.0, compatible string is "qcom,sdhci-msm-v4" + - reg : should contain SDHC, SD Core register map. + - compatible: "qcom,sdhci-msm-cqe" - Optional in case the controller support CQE. + - reg-names : indicates various resources passed to driver (via reg proptery) by name. + Required "reg-names" are "hc_mem" and "core_mem" + optional ones are "tlmm_mem" + - interrupts : should contain SDHC interrupts. + - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name. + Required "interrupt-names" are "hc_irq" and "pwr_irq". + - -supply: phandle to the regulator device tree node + Required "supply-name" are "vdd" and "vdd-io". + +Required alias: +- The slot number is specified via an alias with the following format + 'sdhc{n}' where n is the slot number. + +Optional Properties: + - interrupt-names - "status_irq". This status_irq will be used for card + detection. + - qcom,bus-width - defines the bus I/O width that controller supports. + Units - number of bits. The valid bus-width values are + 1, 4 and 8. + - qcom,nonremovable - specifies whether the card in slot is + hot pluggable or hard wired. + - qcom,nonhotplug - specifies the card in slot is not hot pluggable. + if card lost or removed manually at runtime, don't retry + to redetect it until next reboot probe. + - qcom,bus-speed-mode - specifies supported bus speed modes by host. + The supported bus speed modes are : + "HS200_1p8v" - indicates that host can support HS200 at 1.8v. + "HS200_1p2v" - indicates that host can support HS200 at 1.2v. + "DDR_1p8v" - indicates that host can support DDR mode at 1.8v. + "DDR_1p2v" - indicates that host can support DDR mode at 1.2v. + - qcom,bus-aggr-clk-rates: this is an array that specifies the frequency for + the bus-aggr-clk which should be set corresponding to the + frequency used from clk-rate. The Frequency of this clock + should be decided based on the power mode in which the + apps clk would run with frequency in clk-rates. + - qcom,devfreq,freq-table - specifies supported frequencies for clock scaling. + Clock scaling logic shall toggle between these frequencies based + on card load. In case the defined frequencies are over or below + the supported card frequencies, they will be overridden + during card init. In case this entry is not supplied, + the driver will construct one based on the card + supported max and min frequencies. + The frequencies must be ordered from lowest to highest. + - qcom,pm-qos-irq-type - the PM QoS request type to be used for IRQ voting. + Can be either "affine_cores" or "affine_irq". If not specified, will default + to "affine_cores". Use "affine_irq" setting in case an IRQ balancer is active, + and IRQ affinity changes during runtime. + - qcom,pm-qos-irq-cpu - specifies the CPU for which IRQ voting shall be done. + If "affine_cores" was specified for property 'qcom,pm-qos-irq-type' + then this property must be defined, and is not relevant otherwise. + - qcom,pm-qos-irq-latency - a tuple defining two latency values with which + PM QoS IRQ voting shall be done. The first value is the latecy to be used + when load is high (performance mode) and the second is for low loads + (power saving mode). + - qcom,pm-qos-cpu-groups - defines cpu groups mapping. + Each cell represnets a group, which is a cpu bitmask defining which cpus belong + to that group. + - qcom,pm-qos--latency-us - where is either "cmdq" or "legacy". + An array of latency value tuples, each tuple corresponding to a cpu group in the order + defined in property 'qcom,pm-qos-cpu-groups'. The first value is the latecy to be used + when load is high (performance mode) and the second is for low loads + (power saving mode). These values will be used for cpu group voting for + command-queueing mode or legacy respectively. + - qcom,core_3_0v_support: an optional property that is used to fake + 3.0V support for SDIO devices. + - qcom,scaling-lower-bus-speed-mode: specifies the lower bus speed mode to be used + during clock scaling. If this property is not + defined, then it falls back to the default HS + bus speed mode to maintain backward compatibility. + - qcom,sdr104-wa: On Certain chipsets, SDR104 mode might be unstable causing CRC errors + on the interface. So there is a workaround implemented to skip printing + register dumps on CRC errors and also downgrade bus speed mode to + SDR50/DDR50 in case of continuous CRC errors. Set this flag to enable + this workaround. + - qcom,restore-after-cx-collapse - specifies whether the SDCC registers contents need + to be saved and restored by software when the CX Power Collapse feature is enabled. + On certain chipsets, coming out of the CX Power Collapse event, the SDCC registers + contents will not be retained. It is software responsibility to restore the + SDCC registers before resuming to normal operation. + - qcom,force-sdhc1-probe: Force probing sdhc1 even if it is not the boot device. + - qcom,dll-hsr-list: List of DLL-HSR values which are tuned for given process-node + and platform. The sequence of values in this list must follow the + sequence listed in sdhci_msm_dll_hsr data structure. +In the following, can be vdd (flash core voltage) or vdd-io (I/O voltage). + - qcom,-always-on - specifies whether supply should be kept "on" always. + - qcom,-lpm_sup - specifies whether supply can be kept in low power mode (lpm). + - qcom,-voltage_level - specifies voltage levels for supply. Should be + specified in pairs (min, max), units uV. + - qcom,-current_level - specifies load levels for supply in lpm or + high power mode (hpm). Should be specified in + pairs (lpm, hpm), units uA. + + - gpios - specifies gpios assigned for sdhc slot. + - qcom,gpio-names - a list of strings that map in order to the list of gpios + + Tlmm pins are specified as and starting with eMMC5.0 as + + + - Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + for following optional properties: + - pinctrl-names + - pinctrl-0, pinctrl-1,.. pinctrl-n + + - qcom,large-address-bus - specifies whether the soc is capable of + supporting larger than 32 bit address bus width. + + - qcom,wakeup-on-idle: if configured, the mmcqd thread will call + set_wake_up_idle(), thereby voting for it to be called on idle CPUs. + + - qcom,wakeup-on-idle: if configured, the mmcqd thread will call + set_wake_up_idle(), thereby voting for it to be called on idle CPUs. + +Example: + + aliases { + sdhc1 = &sdhc_1; + }; + + sdhc_1: qcom,sdhc@f9824900 { + compatible = "qcom,sdhci-msm"; + reg = <0xf9824900 0x11c>, <0xf9824000 0x800>; + reg-names = "hc_mem", "core_mem"; + interrupts = <0 123 0>, <0 138 0>; + interrupt-names = "hc_irq", "pwr_irq"; + + vdd-supply = <&pm8941_l21>; + vdd-io-supply = <&pm8941_l13>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <9000 800000>; + + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <6 22000>; + + qcom,devfreq,freq-table = <52000000 200000000>; + + qcom,devfreq,freq-table = <52000000 200000000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_on &sdc1_data_on>; + + + qcom,bus-width = <4>; + qcom,nonremovable; + qcom,large-address-bus; + qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + gpios = <&msmgpio 40 0>, /* CLK */ + <&msmgpio 39 0>, /* CMD */ + <&msmgpio 38 0>, /* DATA0 */ + <&msmgpio 37 0>, /* DATA1 */ + <&msmgpio 36 0>, /* DATA2 */ + <&msmgpio 35 0>; /* DATA3 */ + qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3"; + + qcom,pm-qos-irq-type = "affine_cores"; + qcom,pm-qos-irq-cpu = <0>; + qcom,pm-qos-irq-latency = <500 100>; + qcom,pm-qos-cpu-groups = <0x03 0x0c>; + qcom,pm-qos-cmdq-latency-us = <50 100>, <50 100>; + qcom,pm-qos-legacy-latency-us = <50 100>, <50 100>; + }; + + sdhc_2: qcom,sdhc@f98a4900 { + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <120 200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-of-dwcmshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-of-dwcmshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee4253b33be2574f095a06f5fa8abe2eed2f08de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-of-dwcmshc.txt @@ -0,0 +1,20 @@ +* Synopsys DesignWare Cores Mobile Storage Host Controller + +Required properties: +- compatible: should be one of the following: + "snps,dwcmshc-sdhci" +- reg: offset and length of the register set for the device. +- interrupts: a single interrupt specifier. +- clocks: Array of clocks required for SDHCI; requires at least one for + core clock. +- clock-names: Array of names corresponding to clocks property; shall be + "core" for core clock and "bus" for optional bus clock. + +Example: + sdhci2: sdhci@aa0000 { + compatible = "snps,dwcmshc-sdhci"; + reg = <0xaa0000 0x1000>; + interrupts = ; + clocks = <&emmcclk>; + bus-width = <8>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-omap.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..393848c2138e86f5cc026f1fd04cc68e85916c79 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-omap.txt @@ -0,0 +1,23 @@ +* TI OMAP SDHCI Controller + +Refer to mmc.txt for standard MMC bindings. + +Required properties: +- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers + Should be "ti,k2g-sdhci" for K2G +- ti,hwmods: Must be "mmc", is controller instance starting 1 + (Not required for K2G). +- pinctrl-names: Should be subset of "default", "hs", "sdr12", "sdr25", "sdr50", + "ddr50-rev11", "sdr104-rev11", "ddr50", "sdr104", + "ddr_1_8v-rev11", "ddr_1_8v" or "ddr_3_3v", "hs200_1_8v-rev11", + "hs200_1_8v", +- pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt + +Example: + mmc1: mmc@4809c000 { + compatible = "ti,dra7-sdhci"; + reg = <0x4809c000 0x400>; + ti,hwmods = "mmc1"; + bus-width = <4>; + vmmc-supply = <&vmmc>; /* phandle to regulator node */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-pxa.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-pxa.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d1b449d6097d4c71030e18b8ac73a8a283d4453 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-pxa.txt @@ -0,0 +1,50 @@ +* Marvell sdhci-pxa v2/v3 controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers. + +Required properties: +- compatible: Should be "mrvl,pxav2-mmc", "mrvl,pxav3-mmc" or + "marvell,armada-380-sdhci". +- reg: + * for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for + the SDHCI registers. + + * for "marvell,armada-380-sdhci", three register areas. The first + one for the SDHCI registers themselves, the second one for the + AXI/Mbus bridge registers of the SDHCI unit, the third one for the + SDIO3 Configuration register +- reg names: should be "sdhci", "mbus", "conf-sdio3". only mandatory + for "marvell,armada-380-sdhci" +- clocks: Array of clocks required for SDHCI; requires at least one for + I/O clock. +- clock-names: Array of names corresponding to clocks property; shall be + "io" for I/O clock and "core" for optional core clock. + +Optional properties: +- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning. + +Example: + +sdhci@d4280800 { + compatible = "mrvl,pxav3-mmc"; + reg = <0xd4280800 0x800>; + bus-width = <8>; + interrupts = <27>; + clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>; + clock-names = "io", "core"; + non-removable; + mrvl,clk-delay-cycles = <31>; +}; + +sdhci@d8000 { + compatible = "marvell,armada-380-sdhci"; + reg-names = "sdhci", "mbus", "conf-sdio3"; + reg = <0xd8000 0x1000>, + <0xdc000 0x100>; + <0x18454 0x4>; + interrupts = <0 25 0x4>; + clocks = <&gateclk 17>; + clock-names = "io"; + mrvl,clk-delay-cycles = <0x1F>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-sirf.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd6ed464bcb86432ec1fc6028cadb9080761ff5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-sirf.txt @@ -0,0 +1,18 @@ +* SiRFprimII/marco/atlas6 SDHCI Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-sirf driver. + +Required properties: +- compatible: sirf,prima2-sdhc + +Optional properties: +- cd-gpios: card detect gpio, with zero flags. + +Example: + + sd0: sdhci@56000000 { + compatible = "sirf,prima2-sdhc"; + reg = <0xcd000000 0x100000>; + cd-gpios = <&gpio 6 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-spear.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-spear.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd3643e7e467d0fee8c5c4a069eacf85cc41a764 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-spear.txt @@ -0,0 +1,18 @@ +* SPEAr SDHCI Controller + +This file documents differences between the core properties in mmc.txt +and the properties used by the sdhci-spear driver. + +Required properties: +- compatible: "st,spear300-sdhci" + +Optional properties: +- cd-gpios: card detect gpio, with zero flags. + +Example: + + sdhci@fc000000 { + compatible = "st,spear300-sdhci"; + reg = <0xfc000000 0x1000>; + cd-gpios = <&gpio0 6 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-st.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccf82b4ee838e0c86f5bfef9b1f14b19d3323fc4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci-st.txt @@ -0,0 +1,110 @@ +* STMicroelectronics sdhci-st MMC/SD controller + +This file documents the differences between the core properties in +Documentation/devicetree/bindings/mmc/mmc.txt and the properties +used by the sdhci-st driver. + +Required properties: +- compatible: Must be "st,sdhci" and it can be compatible to "st,sdhci-stih407" + to set the internal glue logic used for configuring the MMC + subsystem (mmcss) inside the FlashSS (available in STiH407 SoC + family). + +- clock-names: Should be "mmc" and "icn". (NB: The latter is not compulsory) + See: Documentation/devicetree/bindings/resource-names.txt +- clocks: Phandle to the clock. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt + +- interrupts: One mmc interrupt should be described here. +- interrupt-names: Should be "mmcirq". + +- pinctrl-names: A pinctrl state names "default" must be defined. +- pinctrl-0: Phandle referencing pin configuration of the sd/emmc controller. + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +- reg: This must provide the host controller base address and it can also + contain the FlashSS Top register for TX/RX delay used by the driver + to configure DLL inside the flashSS, if so reg-names must also be + specified. + +Optional properties: +- reg-names: Should be "mmc" and "top-mmc-delay". "top-mmc-delay" is optional + for eMMC on stih407 family silicon to configure DLL inside FlashSS. + +- non-removable: Non-removable slot. Also used for configuring mmcss in STiH407 SoC + family. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- bus-width: Number of data lines. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- max-frequency: Can be 200MHz, 100MHz or 50MHz (default) and used for + configuring the CCONFIG3 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- resets: Phandle and reset specifier pair to softreset line of HC IP. + See: Documentation/devicetree/bindings/reset/reset.txt + +- vqmmc-supply: Phandle to the regulator dt node, mentioned as the vcc/vdd + supply in eMMC/SD specs. + +- sd-uhs-sdr50: To enable the SDR50 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- sd-uhs-sdr104: To enable the SDR104 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +- sd-uhs-ddr50: To enable the DDR50 in the mmcss. + See: Documentation/devicetree/bindings/mmc/mmc.txt. + +Example: + +/* Example stih416e eMMC configuration */ + +mmc0: sdhci@fe81e000 { + compatible = "st,sdhci"; + reg = <0xfe81e000 0x1000>; + interrupts = ; + interrupt-names = "mmcirq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc0>; + clock-names = "mmc"; + clocks = <&clk_s_a1_ls 1>; + bus-width = <8> + +/* Example SD stih407 family configuration */ + +mmc1: sdhci@9080000 { + compatible = "st,sdhci-stih407", "st,sdhci"; + reg = <0x09080000 0x7ff>; + reg-names = "mmc"; + interrupts = ; + interrupt-names = "mmcirq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sd1>; + clock-names = "mmc"; + clocks = <&clk_s_c0_flexgen CLK_MMC_1>; + resets = <&softreset STIH407_MMC1_SOFTRESET>; + bus-width = <4>; +}; + +/* Example eMMC stih407 family configuration */ + +mmc0: sdhci@9060000 { + compatible = "st,sdhci-stih407", "st,sdhci"; + reg = <0x09060000 0x7ff>, <0x9061008 0x20>; + reg-names = "mmc", "top-mmc-delay"; + interrupts = ; + interrupt-names = "mmcirq"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc0>; + clock-names = "mmc"; + clocks = <&clk_s_c0_flexgen CLK_MMC_0>; + vqmmc-supply = <&vmmc_reg>; + max-frequency = <200000000>; + bus-width = <8>; + non-removable; + sd-uhs-sdr50; + sd-uhs-sdr104; + sd-uhs-ddr50; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e9923a64024f4ded9a94dc5ce06e631f637b091 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sdhci.txt @@ -0,0 +1,13 @@ +The properties specific for SD host controllers. For properties shared by MMC +host controllers refer to the mmc[1] bindings. + + [1] Documentation/devicetree/bindings/mmc/mmc.txt + +Optional properties: +- sdhci-caps-mask: The sdhci capabilities register is incorrect. This 64bit + property corresponds to the bits in the sdhci capability register. If the bit + is on in the mask then the bit is incorrect in the register and should be + turned off, before applying sdhci-caps. +- sdhci-caps: The sdhci capabilities register is incorrect. This 64bit + property corresponds to the bits in the sdhci capability register. If the + bit is on in the property then the bit should be turned on. diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/socfpga-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/socfpga-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4897bea7e3f81c24d5a1dba2ff596d9e8c3895fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/socfpga-dw-mshc.txt @@ -0,0 +1,23 @@ +* Altera SOCFPGA specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Altera SOCFPGA specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "altr,socfpga-dw-mshc": for Altera's SOCFPGA platform + +Example: + + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 129 4>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/sunxi-mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/sunxi-mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9cb3ec5e50295ee1e047bf26eafb45861a002c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/sunxi-mmc.txt @@ -0,0 +1,52 @@ +* Allwinner sunxi MMC controller + +The highspeed MMC host controller on Allwinner SoCs provides an interface +for MMC, SD and SDIO types of memory cards. + +Supported maximum speeds are the ones of the eMMC standard 4.5 as well +as the speed of SD standard 3.0. +Absolute maximum transfer rate is 200MB/s + +Required properties: + - compatible : should be one of: + * "allwinner,sun4i-a10-mmc" + * "allwinner,sun5i-a13-mmc" + * "allwinner,sun7i-a20-mmc" + * "allwinner,sun8i-a83t-emmc" + * "allwinner,sun9i-a80-mmc" + * "allwinner,sun50i-a64-emmc" + * "allwinner,sun50i-a64-mmc" + * "allwinner,sun50i-h6-emmc", "allwinner.sun50i-a64-emmc" + * "allwinner,sun50i-h6-mmc", "allwinner.sun50i-a64-mmc" + - reg : mmc controller base registers + - clocks : a list with 4 phandle + clock specifier pairs + - clock-names : must contain "ahb", "mmc", "output" and "sample" + - interrupts : mmc controller interrupt + +Optional properties: + - resets : phandle + reset specifier pair + - reset-names : must contain "ahb" + - for cd, bus-width and additional generic mmc parameters + please refer to mmc.txt within this directory + +Examples: + - Within .dtsi: + mmc0: mmc@1c0f000 { + compatible = "allwinner,sun5i-a13-mmc"; + reg = <0x01c0f000 0x1000>; + clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>; + clock-names = "ahb", "mod", "output", "sample"; + interrupts = <0 32 4>; + status = "disabled"; + }; + + - Within dts: + mmc0: mmc@1c0f000 { + pinctrl-names = "default", "default"; + pinctrl-0 = <&mmc0_pins_a>; + pinctrl-1 = <&mmc0_cd_pin_reference_design>; + bus-width = <4>; + cd-gpios = <&pio 7 1 0>; /* PH1 */ + cd-inverted; + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/synopsys-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/synopsys-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e5e427a22ce2473d2b3912598da368a3a0bf720 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/synopsys-dw-mshc.txt @@ -0,0 +1,141 @@ +* Synopsys Designware Mobile Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core mmc properties described by mmc.txt and the +properties used by the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - snps,dw-mshc: for controllers compliant with synopsys dw-mshc. +* #address-cells: should be 1. +* #size-cells: should be 0. + +# Slots (DEPRECATED): The slot specific information are contained within + child-nodes with each child-node representing a supported slot. There should + be atleast one child node representing a card slot. The name of the child node + representing the slot is recommended to be slot@n where n is the unique number + of the slot connected to the controller. The following are optional properties + which can be included in the slot child node. + + * reg: specifies the physical slot number. The valid values of this + property is 0 to (num-slots -1), where num-slots is the value + specified by the num-slots property. + + * bus-width: as documented in mmc core bindings. + + * wp-gpios: specifies the write protect gpio line. The format of the + gpio specifier depends on the gpio controller. If a GPIO is not used + for write-protect, this property is optional. + + * disable-wp: If the wp-gpios property isn't present then (by default) + we'd assume that the write protect is hooked up directly to the + controller's special purpose write protect line (accessible via + the WRTPRT register). However, it's possible that we simply don't + want write protect. In that case specify 'disable-wp'. + NOTE: This property is not required for slots known to always + connect to eMMC or SDIO cards. + +Optional properties: + +* resets: phandle + reset specifier pair, intended to represent hardware + reset signal present internally in some host controller IC designs. + See Documentation/devicetree/bindings/reset/reset.txt for details. + +* reset-names: request name for using "resets" property. Must be "reset". + (It will be used together with "resets" property.) + +* clocks: from common clock binding: handle to biu and ciu clocks for the + bus interface unit clock and the card interface unit clock. + +* clock-names: from common clock binding: Shall be "biu" and "ciu". + If the biu clock is missing we'll simply skip enabling it. If the + ciu clock is missing we'll just assume that the clock is running at + clock-frequency. It is an error to omit both the ciu clock and the + clock-frequency. + +* clock-frequency: should be the frequency (in Hz) of the ciu clock. If this + is specified and the ciu clock is specified then we'll try to set the ciu + clock to this at probe time. + +* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not + specified, the default value of the fifo size is determined from the + controller registers. + +* card-detect-delay: Delay in milli-seconds before detecting card after card + insert event. The default value is 0. + +* data-addr: Override fifo address with value provided by DT. The default FIFO reg + offset is assumed as 0x100 (version < 0x240A) and 0x200(version >= 0x240A) by + driver. If the controller does not follow this rule, please use this property + to set fifo address in device tree. + +* fifo-watermark-aligned: Data done irq is expected if data length is less than + watermark in PIO mode. But fifo watermark is requested to be aligned with data + length in some SoC so that TX/RX irq can be generated with data done irq. Add this + watermark quirk to mark this requirement and force fifo watermark setting + accordingly. + +* vmmc-supply: The phandle to the regulator to use for vmmc. If this is + specified we'll defer probe until we can find this regulator. + +* dmas: List of DMA specifiers with the controller specific format as described + in the generic DMA client binding. Refer to dma.txt for details. + +* dma-names: request names for generic DMA client binding. Must be "rx-tx". + Refer to dma.txt for details. + +Aliases: + +- All the MSHC controller nodes should be represented in the aliases node using + the following format 'mshc{n}' where n is a unique number for the alias. + +Example: + +The MSHC controller node can be split into two portions, SoC specific and +board specific portions as listed below. + + dwmmc0@12200000 { + compatible = "snps,dw-mshc"; + clocks = <&clock 351>, <&clock 132>; + clock-names = "biu", "ciu"; + reg = <0x12200000 0x1000>; + interrupts = <0 75 0>; + #address-cells = <1>; + #size-cells = <0>; + data-addr = <0x200>; + fifo-watermark-aligned; + resets = <&rst 20>; + reset-names = "reset"; + }; + +[board specific internal DMA resources] + + dwmmc0@12200000 { + clock-frequency = <400000000>; + clock-freq-min-max = <400000 200000000>; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + vmmc-supply = <&buck8>; + bus-width = <8>; + cap-mmc-highspeed; + cap-sd-highspeed; + }; + +[board specific generic DMA request binding] + + dwmmc0@12200000 { + clock-frequency = <400000000>; + clock-freq-min-max = <400000 200000000>; + broken-cd; + fifo-depth = <0x80>; + card-detect-delay = <200>; + vmmc-supply = <&buck8>; + bus-width = <8>; + cap-mmc-highspeed; + cap-sd-highspeed; + dmas = <&pdma 12>; + dma-names = "rx-tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/ti-omap-hsmmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/ti-omap-hsmmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..19f5508a75696b722624c550700ee74f72b2362f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/ti-omap-hsmmc.txt @@ -0,0 +1,134 @@ +* TI Highspeed MMC host controller for OMAP and 66AK2G family. + +The Highspeed MMC Host Controller on TI OMAP and 66AK2G family +provides an interface for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the omap_hsmmc driver. + +Required properties: +-------------------- +- compatible: + Should be "ti,omap2-hsmmc", for OMAP2 controllers + Should be "ti,omap3-hsmmc", for OMAP3 controllers + Should be "ti,omap3-pre-es3-hsmmc" for OMAP3 controllers pre ES3.0 + Should be "ti,omap4-hsmmc", for OMAP4 controllers + Should be "ti,am33xx-hsmmc", for AM335x controllers + Should be "ti,k2g-hsmmc", "ti,omap4-hsmmc" for 66AK2G controllers. + +SoC specific required properties: +--------------------------------- +The following are mandatory properties for OMAPs, AM33xx and AM43xx SoCs only: +- ti,hwmods: Must be "mmc", n is controller instance starting 1. + +The following are mandatory properties for 66AK2G SoCs only: +- power-domains:Should contain a phandle to a PM domain provider node + and an args specifier containing the MMC device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt +- clocks: Must contain an entry for each entry in clock-names. Should + be defined as per the he appropriate clock bindings consumer + usage in Documentation/devicetree/bindings/clock/ti,sci-clk.txt +- clock-names: Shall be "fck" for the functional clock, + and "mmchsdb_fck" for the debounce clock. + + +Optional properties: +-------------------- +- ti,dual-volt: boolean, supports dual voltage cards +- -supply: phandle to the regulator device tree node + "supply-name" examples are "vmmc", + "vmmc_aux"(deprecated)/"vqmmc" etc +- ti,non-removable: non-removable slot (like eMMC) +- ti,needs-special-reset: Requires a special softreset sequence +- ti,needs-special-hs-handling: HSMMC IP needs special setting + for handling High Speed +- dmas: List of DMA specifiers with the controller specific + format as described in the generic DMA client + binding. A tx and rx specifier is required. +- dma-names: List of DMA request names. These strings correspond + 1:1 with the DMA specifiers listed in dmas. + The string naming is to be "rx" and "tx" for + RX and TX DMA requests, respectively. + +Examples: + +[hwmod populated DMA resources] + + mmc1: mmc@4809c000 { + compatible = "ti,omap4-hsmmc"; + reg = <0x4809c000 0x400>; + ti,hwmods = "mmc1"; + ti,dual-volt; + bus-width = <4>; + vmmc-supply = <&vmmc>; /* phandle to regulator node */ + ti,non-removable; + }; + +[generic DMA request binding] + + mmc1: mmc@4809c000 { + compatible = "ti,omap4-hsmmc"; + reg = <0x4809c000 0x400>; + ti,hwmods = "mmc1"; + ti,dual-volt; + bus-width = <4>; + vmmc-supply = <&vmmc>; /* phandle to regulator node */ + ti,non-removable; + dmas = <&edma 24 + &edma 25>; + dma-names = "tx", "rx"; + }; + +[workaround for missing swakeup on am33xx] + +This SOC is missing the swakeup line, it will not detect SDIO irq +while in suspend. + + ------ + | PRCM | + ------ + ^ | + swakeup | | fclk + | v + ------ ------- ----- + | card | -- CIRQ --> | hsmmc | -- IRQ --> | CPU | + ------ ------- ----- + +In suspend the fclk is off and the module is disfunctional. Even register reads +will fail. A small logic in the host will request fclk restore, when an +external event is detected. Once the clock is restored, the host detects the +event normally. Since am33xx doesn't have this line it never wakes from +suspend. + +The workaround is to reconfigure the dat1 line as a GPIO upon suspend. To make +this work, we need to set the named pinctrl states "default" and "idle". +Prepare idle to remux dat1 as a gpio, and default to remux it back as sdio +dat1. The MMC driver will then toggle between idle and default state during +runtime. + +In summary: +1. select matching 'compatible' section, see example below. +2. specify pinctrl states "default" and "idle", "sleep" is optional. +3. specify the gpio irq used for detecting sdio irq in suspend + +If configuration is incomplete, a warning message is emitted "falling back to +polling". Also check the "sdio irq mode" in /sys/kernel/debug/mmc0/regs. Mind +not every application needs SDIO irq, e.g. MMC cards. + + mmc1: mmc@48060100 { + compatible = "ti,am33xx-hsmmc"; + ... + pinctrl-names = "default", "idle", "sleep" + pinctrl-0 = <&mmc1_pins>; + pinctrl-1 = <&mmc1_idle>; + pinctrl-2 = <&mmc1_sleep>; + ... + interrupts-extended = <&intc 64 &gpio2 28 GPIO_ACTIVE_LOW>; + }; + + mmc1_idle : pinmux_cirq_pin { + pinctrl-single,pins = < + 0x0f8 0x3f /* GPIO2_28 */ + >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/ti-omap.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/ti-omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..8de57996976359d96cb1b2c3fa672d8843ac83fb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/ti-omap.txt @@ -0,0 +1,54 @@ +* TI MMC host controller for OMAP1 and 2420 + +The MMC Host Controller on TI OMAP1 and 2420 family provides +an interface for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the omap mmc driver. + +Note that this driver will not work with omap2430 or later omaps, +please see the omap hsmmc driver for the current omaps. + +Required properties: +- compatible: Must be "ti,omap2420-mmc", for OMAP2420 controllers +- ti,hwmods: For 2420, must be "msdi", where n is controller + instance starting 1 + +Examples: + + msdi1: mmc@4809c000 { + compatible = "ti,omap2420-mmc"; + ti,hwmods = "msdi1"; + reg = <0x4809c000 0x80>; + interrupts = <83>; + dmas = <&sdma 61 &sdma 62>; + dma-names = "tx", "rx"; + }; + +* TI MMC host controller for OMAP1 and 2420 + +The MMC Host Controller on TI OMAP1 and 2420 family provides +an interface for MMC, SD, and SDIO types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the omap mmc driver. + +Note that this driver will not work with omap2430 or later omaps, +please see the omap hsmmc driver for the current omaps. + +Required properties: +- compatible: Must be "ti,omap2420-mmc", for OMAP2420 controllers +- ti,hwmods: For 2420, must be "msdi", where n is controller + instance starting 1 + +Examples: + + msdi1: mmc@4809c000 { + compatible = "ti,omap2420-mmc"; + ti,hwmods = "msdi1"; + reg = <0x4809c000 0x80>; + interrupts = <83>; + dmas = <&sdma 61 &sdma 62>; + dma-names = "tx", "rx"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/tmio_mmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/tmio_mmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c434200d19d534056f4884f593fee6c535471ba5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/tmio_mmc.txt @@ -0,0 +1,112 @@ +* Toshiba Mobile IO SD/MMC controller + +The tmio-mmc driver doesn't probe its devices actively, instead its binding to +devices is managed by either MFD drivers or by the sh_mobile_sdhi platform +driver. Those drivers supply the tmio-mmc driver with platform data, that either +describe hardware capabilities, known to them, or are obtained by them from +their own platform data or from their DT information. In the latter case all +compulsory and any optional properties, common to all SD/MMC drivers, as +described in mmc.txt, can be used. Additionally the following tmio_mmc-specific +optional bindings can be used. + +Required properties: +- compatible: should contain one or more of the following: + "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC + "renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC + "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC + "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC + "renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC + "renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC + "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC + "renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC + "renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC + "renesas,sdhi-r8a7791" - SDHI IP on R8A7791 SoC + "renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC + "renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC + "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC + "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC + "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC + "renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC + "renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC + "renesas,sdhi-r8a77990" - SDHI IP on R8A77990 SoC + "renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC + "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller + "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller + "renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1 + SDHI controller + "renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 SDHI controller + + + When compatible with the generic version, nodes must list + the SoC-specific version corresponding to the platform + first followed by the generic version. + +- clocks: Most controllers only have 1 clock source per channel. However, on + some variations of this controller, the internal card detection + logic that exists in this controller is sectioned off to be run by a + separate second clock source to allow the main core clock to be turned + off to save power. + If 2 clocks are specified by the hardware, you must name them as + "core" and "cd". If the controller only has 1 clock, naming is not + required. + Devices which have more than 1 clock are listed below: + 2: R7S72100 + +Optional properties: +- pinctrl-names: should be "default", "state_uhs" +- pinctrl-0: should contain default/high speed pin ctrl +- pinctrl-1: should contain uhs mode pin ctrl + +Example: R8A7790 (R-Car H2) SDHI controller nodes + + sdhi0: sd@ee100000 { + compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi"; + reg = <0 0xee100000 0 0x328>; + interrupts = ; + clocks = <&cpg CPG_MOD 314>; + dmas = <&dmac0 0xcd>, <&dmac0 0xce>, + <&dmac1 0xcd>, <&dmac1 0xce>; + dma-names = "tx", "rx", "tx", "rx"; + max-frequency = <195000000>; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; + resets = <&cpg 314>; + }; + + sdhi1: sd@ee120000 { + compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi"; + reg = <0 0xee120000 0 0x328>; + interrupts = ; + clocks = <&cpg CPG_MOD 313>; + dmas = <&dmac0 0xc9>, <&dmac0 0xca>, + <&dmac1 0xc9>, <&dmac1 0xca>; + dma-names = "tx", "rx", "tx", "rx"; + max-frequency = <195000000>; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; + resets = <&cpg 313>; + }; + + sdhi2: sd@ee140000 { + compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi"; + reg = <0 0xee140000 0 0x100>; + interrupts = ; + clocks = <&cpg CPG_MOD 312>; + dmas = <&dmac0 0xc1>, <&dmac0 0xc2>, + <&dmac1 0xc1>, <&dmac1 0xc2>; + dma-names = "tx", "rx", "tx", "rx"; + max-frequency = <97500000>; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; + resets = <&cpg 312>; + }; + + sdhi3: sd@ee160000 { + compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi"; + reg = <0 0xee160000 0 0x100>; + interrupts = ; + clocks = <&cpg CPG_MOD 311>; + dmas = <&dmac0 0xd3>, <&dmac0 0xd4>, + <&dmac1 0xd3>, <&dmac1 0xd4>; + dma-names = "tx", "rx", "tx", "rx"; + max-frequency = <97500000>; + power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; + resets = <&cpg 311>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/usdhi6rol0.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/usdhi6rol0.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d1b7971d0788b630b5a2b3367ea02ddbcaaa8e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/usdhi6rol0.txt @@ -0,0 +1,39 @@ +* Renesas usdhi6rol0 SD/SDIO host controller + +Required properties: + +- compatible: must be + "renesas,usdhi6rol0" +- interrupts: 3 interrupts, named "card detect", "data" and "SDIO" must be + specified +- clocks: a clock binding for the IMCLK input + +Optional properties: + +- vmmc-supply: a phandle of a regulator, supplying Vcc to the card +- vqmmc-supply: a phandle of a regulator, supplying VccQ to the card +- pinctrl-names: Can contain a "default" entry and a "state_uhs" + entry. The state_uhs entry is used together with the default + entry when the board requires distinct settings for UHS speeds. + +- pinctrl-N: One property for each name listed in pinctrl-names, see + ../pinctrl/pinctrl-bindings.txt. + +Additionally any standard mmc bindings from mmc.txt can be used. + +Example: + +sd0: sd@ab000000 { + compatible = "renesas,usdhi6rol0"; + reg = <0xab000000 0x200>; + interrupts = <0 23 0x4 + 0 24 0x4 + 0 25 0x4>; + interrupt-names = "card detect", "data", "SDIO"; + bus-width = <4>; + max-frequency = <50000000>; + cap-power-off-card; + clocks = <&imclk>; + vmmc-supply = <&vcc_sd0>; + vqmmc-supply = <&vccq_sd0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/vt8500-sdmmc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/vt8500-sdmmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7fb6abb3eb8c87e698ca4f30270c949878f3cbf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/vt8500-sdmmc.txt @@ -0,0 +1,23 @@ +* Wondermedia WM8505/WM8650 SD/MMC Host Controller + +This file documents differences between the core properties described +by mmc.txt and the properties used by the wmt-sdmmc driver. + +Required properties: +- compatible: Should be "wm,wm8505-sdhc". +- interrupts: Two interrupts are required - regular irq and dma irq. + +Optional properties: +- sdon-inverted: SD_ON bit is inverted on the controller + +Examples: + +sdhc@d800a000 { + compatible = "wm,wm8505-sdhc"; + reg = <0xd800a000 0x1000>; + interrupts = <20 21>; + clocks = <&sdhc>; + bus-width = <4>; + sdon-inverted; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mmc/zx-dw-mshc.txt b/arch/arm64/boot/dts/vendor/bindings/mmc/zx-dw-mshc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f59bd5361f530c4c6b343a2b5a39396637940f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mmc/zx-dw-mshc.txt @@ -0,0 +1,31 @@ +* ZTE specific extensions to the Synopsys Designware Mobile Storage + Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the ZTE specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "zte,zx296718-dw-mshc": for ZX SoCs + +Example: + + mmc1: mmc@1110000 { + compatible = "zte,zx296718-dw-mshc"; + reg = <0x01110000 0x1000>; + interrupts = ; + fifo-depth = <32>; + data-addr = <0x200>; + fifo-watermark-aligned; + bus-width = <4>; + clock-frequency = <50000000>; + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>; + clock-names = "biu", "ciu"; + max-frequency = <50000000>; + cap-sdio-irq; + cap-sd-highspeed; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/msm_hdcp/msm_hdcp.txt b/arch/arm64/boot/dts/vendor/bindings/msm_hdcp/msm_hdcp.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d5f55d7a8ca2428e822abb5a6efd7c59b3564dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/msm_hdcp/msm_hdcp.txt @@ -0,0 +1,14 @@ +MSM HDCP driver + +Standalone driver managing HDCP related communications +between TZ and HLOS for MSM chipset. + +Required properties: + +compatible = "qcom,msm-hdcp"; + +Example: + +qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/arm-versatile.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/arm-versatile.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ec28796a3c0ef1fb87292e520d2e2137b9bec1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/arm-versatile.txt @@ -0,0 +1,26 @@ +Flash device on ARM Versatile board + +These flash chips are found in the ARM reference designs like Integrator, +Versatile, RealView, Versatile Express etc. + +They are regular CFI compatible (Intel or AMD extended) flash chips with +some special write protect/VPP bits that can be controlled by the machine's +system controller. + +Required properties: +- compatible : must be "arm,versatile-flash", "cfi-flash"; +- reg : memory address for the flash chip +- bank-width : width in bytes of flash interface. + +For the rest of the properties, see mtd-physmap.txt. + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + +flash@34000000 { + compatible = "arm,versatile-flash", "cfi-flash"; + reg = <0x34000000 0x4000000>; + bank-width = <4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/aspeed-smc.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/aspeed-smc.txt new file mode 100644 index 0000000000000000000000000000000000000000..49f6528ef5472abc8e1d1ac45ab6cfef32432f9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/aspeed-smc.txt @@ -0,0 +1,51 @@ +* Aspeed Firmware Memory controller +* Aspeed SPI Flash Memory Controller + +The Firmware Memory Controller in the Aspeed AST2500 SoC supports +three chip selects, two of which are always of SPI type and the third +can be SPI or NOR type flash. These bindings only describe SPI. + +The two SPI flash memory controllers in the AST2500 each support two +chip selects. + +Required properties: + - compatible : Should be one of + "aspeed,ast2400-fmc" for the AST2400 Firmware Memory Controller + "aspeed,ast2400-spi" for the AST2400 SPI Flash memory Controller + "aspeed,ast2500-fmc" for the AST2500 Firmware Memory Controller + "aspeed,ast2500-spi" for the AST2500 SPI flash memory controllers + + - reg : the first contains the control register location and length, + the second contains the memory window mapping address and length + - #address-cells : must be 1 corresponding to chip select child binding + - #size-cells : must be 0 corresponding to chip select child binding + +Optional properties: + - interrupts : Should contain the interrupt for the dma device if an + FMC + +The child nodes are the SPI flash modules which must have a compatible +property as specified in bindings/mtd/jedec,spi-nor.txt + +Optionally, the child node can contain properties for SPI mode (may be +ignored): + - spi-max-frequency - max frequency of spi bus + + +Example: +fmc: fmc@1e620000 { + compatible = "aspeed,ast2500-fmc"; + reg = < 0x1e620000 0x94 + 0x20000000 0x02000000 >; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <19>; + flash@0 { + reg = < 0 >; + compatible = "jedec,spi-nor"; + /* spi-max-frequency = <>; */ + /* m25p,fast-read; */ + #address-cells = <1>; + #size-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-dataflash.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-dataflash.txt new file mode 100644 index 0000000000000000000000000000000000000000..1889a4db5b7c47ed1f4908dc785a2c87abff9c57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-dataflash.txt @@ -0,0 +1,17 @@ +* Atmel Data Flash + +Required properties: +- compatible : "atmel,", "atmel,", "atmel,dataflash". + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + +flash@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at45db321d", "atmel,at45", "atmel,dataflash"; + spi-max-frequency = <25000000>; + reg = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bb66e476672b3fa66b707f8f960d4a53ff2eb1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-nand.txt @@ -0,0 +1,235 @@ +Atmel NAND flash controller bindings + +The NAND flash controller node should be defined under the EBI bus (see +Documentation/devicetree/bindings/memory-controllers/atmel,ebi.txt). +One or several NAND devices can be defined under this NAND controller. +The NAND controller might be connected to an ECC engine. + +* NAND controller bindings: + +Required properties: +- compatible: should be one of the following + "atmel,at91rm9200-nand-controller" + "atmel,at91sam9260-nand-controller" + "atmel,at91sam9261-nand-controller" + "atmel,at91sam9g45-nand-controller" + "atmel,sama5d3-nand-controller" +- ranges: empty ranges property to forward EBI ranges definitions. +- #address-cells: should be set to 2. +- #size-cells: should be set to 1. +- atmel,nfc-io: phandle to the NFC IO block. Only required for sama5d3 + controllers. +- atmel,nfc-sram: phandle to the NFC SRAM block. Only required for sama5d3 + controllers. + +Optional properties: +- ecc-engine: phandle to the PMECC block. Only meaningful if the SoC embeds + a PMECC engine. + +* NAND device/chip bindings: + +Required properties: +- reg: describes the CS lines assigned to the NAND device. If the NAND device + exposes multiple CS lines (multi-dies chips), your reg property will + contain X tuples of 3 entries. + 1st entry: the CS line this NAND chip is connected to + 2nd entry: the base offset of the memory region assigned to this + device (always 0) + 3rd entry: the memory region size (always 0x800000) + +Optional properties: +- rb-gpios: the GPIO(s) used to check the Ready/Busy status of the NAND. +- cs-gpios: the GPIO(s) used to control the CS line. +- det-gpios: the GPIO used to detect if a Smartmedia Card is present. +- atmel,rb: an integer identifying the native Ready/Busy pin. Only meaningful + on sama5 SoCs. + +All generic properties described in +Documentation/devicetree/bindings/mtd/{common,nand}.txt also apply to the NAND +device node, and NAND partitions should be defined under the NAND node as +described in Documentation/devicetree/bindings/mtd/partition.txt. + +* ECC engine (PMECC) bindings: + +Required properties: +- compatible: should be one of the following + "atmel,at91sam9g45-pmecc" + "atmel,sama5d4-pmecc" + "atmel,sama5d2-pmecc" +- reg: should contain 2 register ranges. The first one is pointing to the PMECC + block, and the second one to the PMECC_ERRLOC block. + +* SAMA5 NFC I/O bindings: + +SAMA5 SoCs embed an advanced NAND controller logic to automate READ/WRITE page +operations. This interface to this logic is placed in a separate I/O range and +should thus have its own DT node. + +- compatible: should be "atmel,sama5d3-nfc-io", "syscon". +- reg: should contain the I/O range used to interact with the NFC logic. + +Example: + + nfc_io: nfc-io@70000000 { + compatible = "atmel,sama5d3-nfc-io", "syscon"; + reg = <0x70000000 0x8000000>; + }; + + pmecc: ecc-engine@ffffc070 { + compatible = "atmel,at91sam9g45-pmecc"; + reg = <0xffffc070 0x490>, + <0xffffc500 0x100>; + }; + + ebi: ebi@10000000 { + compatible = "atmel,sama5d3-ebi"; + #address-cells = <2>; + #size-cells = <1>; + atmel,smc = <&hsmc>; + reg = <0x10000000 0x10000000 + 0x40000000 0x30000000>; + ranges = <0x0 0x0 0x10000000 0x10000000 + 0x1 0x0 0x40000000 0x10000000 + 0x2 0x0 0x50000000 0x10000000 + 0x3 0x0 0x60000000 0x10000000>; + clocks = <&mck>; + + nand_controller: nand-controller { + compatible = "atmel,sama5d3-nand-controller"; + atmel,nfc-sram = <&nfc_sram>; + atmel,nfc-io = <&nfc_io>; + ecc-engine = <&pmecc>; + #address-cells = <2>; + #size-cells = <1>; + ranges; + + nand@3 { + reg = <0x3 0x0 0x800000>; + atmel,rb = <0>; + + /* + * Put generic NAND/MTD properties and + * subnodes here. + */ + }; + }; + }; + +----------------------------------------------------------------------- + +Deprecated bindings (should not be used in new device trees): + +Required properties: +- compatible: The possible values are: + "atmel,at91rm9200-nand" + "atmel,sama5d2-nand" + "atmel,sama5d4-nand" +- reg : should specify localbus address and size used for the chip, + and hardware ECC controller if available. + If the hardware ECC is PMECC, it should contain address and size for + PMECC and PMECC Error Location controller. + The PMECC lookup table address and size in ROM is optional. If not + specified, driver will build it in runtime. +- atmel,nand-addr-offset : offset for the address latch. +- atmel,nand-cmd-offset : offset for the command latch. +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. + +- gpios : specifies the gpio pins to control the NAND device. detect is an + optional gpio and may be set to 0 if not present. + +Optional properties: +- atmel,nand-has-dma : boolean to support dma transfer for nand read/write. +- nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default. + Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first", + "soft_bch". +- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware, + capable of BCH encoding and decoding, on devices where it is present. +- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC + Controller. Supported values are: 2, 4, 8, 12, 24. If the compatible string + is "atmel,sama5d2-nand", 32 is also valid. +- atmel,pmecc-sector-size : sector size for ECC computation. Supported values + are: 512, 1024. +- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM + for different sector size. First one is for sector size 512, the next is for + sector size 1024. If not specified, driver will build the table in runtime. +- nand-bus-width : 8 or 16 bus width if not present 8 +- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + +Nand Flash Controller(NFC) is an optional sub-node +Required properties: +- compatible : "atmel,sama5d3-nfc". +- reg : should specify the address and size used for NFC command registers, + NFC registers and NFC SRAM. NFC SRAM address and size can be absent + if don't want to use it. +- clocks: phandle to the peripheral clock +Optional properties: +- atmel,write-by-sram: boolean to enable NFC write by SRAM. + +Examples: +nand0: nand@40000000,0 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x40000000 0x10000000 + 0xffffe800 0x200 + >; + atmel,nand-addr-offset = <21>; /* ale */ + atmel,nand-cmd-offset = <22>; /* cle */ + nand-on-flash-bbt; + nand-ecc-mode = "soft"; + gpios = <&pioC 13 0 /* rdy */ + &pioC 14 0 /* nce */ + 0 /* cd */ + >; + partition@0 { + ... + }; +}; + +/* for PMECC supported chips */ +nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = < 0x40000000 0x10000000 /* bus addr & size */ + 0xffffe000 0x00000600 /* PMECC addr & size */ + 0xffffe600 0x00000200 /* PMECC ERRLOC addr & size */ + 0x00100000 0x00100000 /* ROM addr & size */ + >; + atmel,nand-addr-offset = <21>; /* ale */ + atmel,nand-cmd-offset = <22>; /* cle */ + nand-on-flash-bbt; + nand-ecc-mode = "hw"; + atmel,has-pmecc; /* enable PMECC */ + atmel,pmecc-cap = <2>; + atmel,pmecc-sector-size = <512>; + atmel,pmecc-lookup-table-offset = <0x8000 0x10000>; + gpios = <&pioD 5 0 /* rdy */ + &pioD 4 0 /* nce */ + 0 /* cd */ + >; + partition@0 { + ... + }; +}; + +/* for NFC supported chips */ +nand0: nand@40000000 { + compatible = "atmel,at91rm9200-nand"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + ... + nfc@70000000 { + compatible = "atmel,sama5d3-nfc"; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&hsmc_clk> + reg = < + 0x70000000 0x10000000 /* NFC Command Registers */ + 0xffffc000 0x00000070 /* NFC HSMC regs */ + 0x00200000 0x00100000 /* NFC SRAM banks */ + >; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-quadspi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-quadspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b93c1e2f25dd62ac878be49ee24ad8d7b54a9c6f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/atmel-quadspi.txt @@ -0,0 +1,31 @@ +* Atmel Quad Serial Peripheral Interface (QSPI) + +Required properties: +- compatible: Should be "atmel,sama5d2-qspi". +- reg: Should contain the locations and lengths of the base registers + and the mapped memory. +- reg-names: Should contain the resource reg names: + - qspi_base: configuration register address space + - qspi_mmap: memory mapped address space +- interrupts: Should contain the interrupt for the device. +- clocks: The phandle of the clock needed by the QSPI controller. +- #address-cells: Should be <1>. +- #size-cells: Should be <0>. + +Example: + +spi@f0020000 { + compatible = "atmel,sama5d2-qspi"; + reg = <0xf0020000 0x100>, <0xd0000000 0x8000000>; + reg-names = "qspi_base", "qspi_mmap"; + interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&spi0_clk>; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0_default>; + + m25p80@0 { + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/brcm,brcmnand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/brcm,brcmnand.txt new file mode 100644 index 0000000000000000000000000000000000000000..bcda1dfc4baccee9085ae0f98d8bdd83baddbb5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/brcm,brcmnand.txt @@ -0,0 +1,183 @@ +* Broadcom STB NAND Controller + +The Broadcom Set-Top Box NAND controller supports low-level access to raw NAND +flash chips. It has a memory-mapped register interface for both control +registers and for its data input/output buffer. On some SoCs, this controller is +paired with a custom DMA engine (inventively named "Flash DMA") which supports +basic PROGRAM and READ functions, among other features. + +This controller was originally designed for STB SoCs (BCM7xxx) but is now +available on a variety of Broadcom SoCs, including some BCM3xxx, BCM63xx, and +iProc/Cygnus. Its history includes several similar (but not fully register +compatible) versions. + +Required properties: +- compatible : May contain an SoC-specific compatibility string (see below) + to account for any SoC-specific hardware bits that may be + added on top of the base core controller. + In addition, must contain compatibility information about + the core NAND controller, of the following form: + "brcm,brcmnand" and an appropriate version compatibility + string, like "brcm,brcmnand-v7.0" + Possible values: + brcm,brcmnand-v4.0 + brcm,brcmnand-v5.0 + brcm,brcmnand-v6.0 + brcm,brcmnand-v6.1 + brcm,brcmnand-v6.2 + brcm,brcmnand-v7.0 + brcm,brcmnand-v7.1 + brcm,brcmnand-v7.2 + brcm,brcmnand +- reg : the register start and length for NAND register region. + (optional) Flash DMA register range (if present) + (optional) NAND flash cache range (if at non-standard offset) +- reg-names : a list of the names corresponding to the previous register + ranges. Should contain "nand" and (optionally) + "flash-dma" and/or "nand-cache". +- interrupts : The NAND CTLRDY interrupt and (if Flash DMA is available) + FLASH_DMA_DONE +- interrupt-names : May be "nand_ctlrdy" or "flash_dma_done", if broken out as + individual interrupts. + May be "nand", if the SoC has the individual NAND + interrupts multiplexed behind another custom piece of + hardware +- #address-cells : <1> - subnodes give the chip-select number +- #size-cells : <0> + +Optional properties: +- clock : reference to the clock for the NAND controller +- clock-names : "nand" (required for the above clock) +- brcm,nand-has-wp : Some versions of this IP include a write-protect + (WP) control bit. It is always available on >= + v7.0. Use this property to describe the rare + earlier versions of this core that include WP + + -- Additional SoC-specific NAND controller properties -- + +The NAND controller is integrated differently on the variety of SoCs on which it +is found. Part of this integration involves providing status and enable bits +with which to control the 8 exposed NAND interrupts, as well as hardware for +configuring the endianness of the data bus. On some SoCs, these features are +handled via standard, modular components (e.g., their interrupts look like a +normal IRQ chip), but on others, they are controlled in unique and interesting +ways, sometimes with registers that lump multiple NAND-related functions +together. The former case can be described simply by the standard interrupts +properties in the main controller node. But for the latter exceptional cases, +we define additional 'compatible' properties and associated register resources within the NAND controller node above. + + - compatible: Can be one of several SoC-specific strings. Each SoC may have + different requirements for its additional properties, as described below each + bullet point below. + + * "brcm,nand-bcm63138" + - reg: (required) the 'NAND_INT_BASE' register range, with separate status + and enable registers + - reg-names: (required) "nand-int-base" + + * "brcm,nand-bcm6368" + - compatible: should contain "brcm,nand-bcm", "brcm,nand-bcm6368" + - reg: (required) the 'NAND_INTR_BASE' register range, with combined status + and enable registers, and boot address registers + - reg-names: (required) "nand-int-base" + + * "brcm,nand-iproc" + - reg: (required) the "IDM" register range, for interrupt enable and APB + bus access endianness configuration, and the "EXT" register range, + for interrupt status/ack. + - reg-names: (required) a list of the names corresponding to the previous + register ranges. Should contain "iproc-idm" and "iproc-ext". + + +* NAND chip-select + +Each controller (compatible: "brcm,brcmnand") may contain one or more subnodes +to represent enabled chip-selects which (may) contain NAND flash chips. Their +properties are as follows. + +Required properties: +- compatible : should contain "brcm,nandcs" +- reg : a single integer representing the chip-select + number (e.g., 0, 1, 2, etc.) +- #address-cells : see partition.txt +- #size-cells : see partition.txt +- nand-ecc-strength : see nand.txt +- nand-ecc-step-size : must be 512 or 1024. See nand.txt + +Optional properties: +- nand-on-flash-bbt : boolean, to enable the on-flash BBT for this + chip-select. See nand.txt +- brcm,nand-oob-sector-size : integer, to denote the spare area sector size + expected for the ECC layout in use. This size, in + addition to the strength and step-size, + determines how the hardware BCH engine will lay + out the parity bytes it stores on the flash. + This property can be automatically determined by + the flash geometry (particularly the NAND page + and OOB size) in many cases, but when booting + from NAND, the boot controller has only a limited + number of available options for its default ECC + layout. + +Each nandcs device node may optionally contain sub-nodes describing the flash +partition mapping. See partition.txt for more detail. + + +Example: + +nand@f0442800 { + compatible = "brcm,brcmnand-v7.0", "brcm,brcmnand"; + reg = <0xF0442800 0x600>, + <0xF0443000 0x100>; + reg-names = "nand", "flash-dma"; + interrupt-parent = <&hif_intr2_intc>; + interrupts = <24>, <4>; + + #address-cells = <1>; + #size-cells = <0>; + + nandcs@1 { + compatible = "brcm,nandcs"; + reg = <1>; // Chip select 1 + nand-on-flash-bbt; + nand-ecc-strength = <12>; + nand-ecc-step-size = <512>; + + // Partitions + #address-cells = <1>; // <2>, for 64-bit offset + #size-cells = <1>; // <2>, for 64-bit length + flash0.rootfs@0 { + reg = <0 0x10000000>; + }; + flash0@0 { + reg = <0 0>; // MTDPART_SIZ_FULL + }; + flash0.kernel@10000000 { + reg = <0x10000000 0x400000>; + }; + }; +}; + +nand@10000200 { + compatible = "brcm,nand-bcm63168", "brcm,nand-bcm6368", + "brcm,brcmnand-v4.0", "brcm,brcmnand"; + reg = <0x10000200 0x180>, + <0x10000600 0x200>, + <0x100000b0 0x10>; + reg-names = "nand", "nand-cache", "nand-int-base"; + interrupt-parent = <&periph_intc>; + interrupts = <50>; + clocks = <&periph_clk 20>; + clock-names = "nand"; + + #address-cells = <1>; + #size-cells = <0>; + + nand0: nandcs@0 { + compatible = "brcm,nandcs"; + reg = <0>; + nand-on-flash-bbt; + nand-ecc-strength = <1>; + nand-ecc-step-size = <512>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/cadence-quadspi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/cadence-quadspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb2075df9b3826dd813dd23567ac470ffed5144e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/cadence-quadspi.txt @@ -0,0 +1,61 @@ +* Cadence Quad SPI controller + +Required properties: +- compatible : should be one of the following: + Generic default - "cdns,qspi-nor". + For TI 66AK2G SoC - "ti,k2g-qspi", "cdns,qspi-nor". +- reg : Contains two entries, each of which is a tuple consisting of a + physical address and length. The first entry is the address and + length of the controller register set. The second entry is the + address and length of the QSPI Controller data area. +- interrupts : Unit interrupt specifier for the controller interrupt. +- clocks : phandle to the Quad SPI clock. +- cdns,fifo-depth : Size of the data FIFO in words. +- cdns,fifo-width : Bus width of the data FIFO in bytes. +- cdns,trigger-address : 32-bit indirect AHB trigger address. + +Optional properties: +- cdns,is-decoded-cs : Flag to indicate whether decoder is used or not. +- cdns,rclk-en : Flag to indicate that QSPI return clock is used to latch + the read data rather than the QSPI clock. Make sure that QSPI return + clock is populated on the board before using this property. + +Optional subnodes: +Subnodes of the Cadence Quad SPI controller are spi slave nodes with additional +custom properties: +- cdns,read-delay : Delay for read capture logic, in clock cycles +- cdns,tshsl-ns : Delay in nanoseconds for the length that the master + mode chip select outputs are de-asserted between + transactions. +- cdns,tsd2d-ns : Delay in nanoseconds between one chip select being + de-activated and the activation of another. +- cdns,tchsh-ns : Delay in nanoseconds between last bit of current + transaction and deasserting the device chip select + (qspi_n_ss_out). +- cdns,tslch-ns : Delay in nanoseconds between setting qspi_n_ss_out low + and first bit transfer. + +Example: + + qspi: spi@ff705000 { + compatible = "cdns,qspi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xff705000 0x1000>, + <0xffa00000 0x1000>; + interrupts = <0 151 4>; + clocks = <&qspi_clk>; + cdns,is-decoded-cs; + cdns,fifo-depth = <128>; + cdns,fifo-width = <4>; + cdns,trigger-address = <0x00000000>; + + flash0: n25q00@0 { + ... + cdns,read-delay = <4>; + cdns,tshsl-ns = <50>; + cdns,tsd2d-ns = <50>; + cdns,tchsh-ns = <4>; + cdns,tslch-ns = <4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/common.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/common.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc068b923d7aa381ea5ccbc33f5854f5051a0ab9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/common.txt @@ -0,0 +1,15 @@ +* Common properties of all MTD devices + +Optional properties: +- label: user-defined MTD device name. Can be used to assign user + friendly names to MTD devices (instead of the flash model or flash + controller based name) in order to ease flash device identification + and/or describe what they are used for. + +Example: + + flash@0 { + label = "System-firmware"; + + /* flash type specific properties */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/cortina,gemini-flash.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/cortina,gemini-flash.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fa1b34d69ad2cbb234bce66af3245d685ea3ca9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/cortina,gemini-flash.txt @@ -0,0 +1,24 @@ +Flash device on Cortina Systems Gemini SoC + +This flash is regular CFI compatible (Intel or AMD extended) flash chips with +some special bits that can be controlled by the machine's system controller. + +Required properties: +- compatible : must be "cortina,gemini-flash", "cfi-flash"; +- reg : memory address for the flash chip +- syscon : must be a phandle to the system controller +- bank-width : width in bytes of flash interface, should be <2> + +For the rest of the properties, see mtd-physmap.txt. + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + +flash@30000000 { + compatible = "cortina,gemini-flash", "cfi-flash"; + reg = <0x30000000 0x01000000>; + syscon = <&syscon>; + bank-width = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/davinci-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/davinci-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfb18abe6001676dd4da590962eb39ffe7c6d561 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/davinci-nand.txt @@ -0,0 +1,94 @@ +Device tree bindings for Texas instruments Davinci/Keystone NAND controller + +This file provides information, what the device node for the davinci/keystone +NAND interface contains. + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf +Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf + +Required properties: + +- compatible: "ti,davinci-nand" + "ti,keystone-nand" + +- reg: Contains 2 offset/length values: + - offset and length for the access window. + - offset and length for accessing the AEMIF + control registers. + +- ti,davinci-chipselect: number of chipselect. Indicates on the + davinci_nand driver which chipselect is used + for accessing the nand. + Can be in the range [0-3]. + +Recommended properties : + +- ti,davinci-mask-ale: mask for ALE. Needed for executing address + phase. These offset will be added to the base + address for the chip select space the NAND Flash + device is connected to. + If not set equal to 0x08. + +- ti,davinci-mask-cle: mask for CLE. Needed for executing command + phase. These offset will be added to the base + address for the chip select space the NAND Flash + device is connected to. + If not set equal to 0x10. + +- ti,davinci-mask-chipsel: mask for chipselect address. Needed to mask + addresses for given chipselect. + +- nand-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4. + +- nand-bus-width: buswidth 8 or 16. If not present 8. + +- nand-on-flash-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Deprecated properties: + +- ti,davinci-ecc-mode: operation mode of the NAND ecc mode. ECC mode + valid values for davinci driver: + - "none" + - "soft" + - "hw" + +- ti,davinci-nand-buswidth: buswidth 8 or 16. If not present 8. + +- ti,davinci-nand-use-bbt: use flash based bad block table support. OOB + identifier is saved in OOB area. If not present + false. + +Nand device bindings may contain additional sub-nodes describing partitions of +the address space. See partition.txt for more detail. The NAND Flash timing +values must be programmed in the chip select’s node of AEMIF +memory-controller (see Documentation/devicetree/bindings/memory-controllers/ +davinci-aemif.txt). + +Example(da850 EVM ): + +nand_cs3@62000000 { + compatible = "ti,davinci-nand"; + reg = <0x62000000 0x807ff + 0x68000000 0x8000>; + ti,davinci-chipselect = <1>; + ti,davinci-mask-ale = <0>; + ti,davinci-mask-cle = <0>; + ti,davinci-mask-chipsel = <0>; + nand-ecc-mode = "hw"; + ti,davinci-ecc-bits = <4>; + nand-on-flash-bbt; + + partition@180000 { + label = "ubifs"; + reg = <0x180000 0x7e80000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/denali-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/denali-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..f33da87827410fffe9d799fcc7a780b73c010fb0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/denali-nand.txt @@ -0,0 +1,40 @@ +* Denali NAND controller + +Required properties: + - compatible : should be one of the following: + "altr,socfpga-denali-nand" - for Altera SOCFPGA + "socionext,uniphier-denali-nand-v5a" - for Socionext UniPhier (v5a) + "socionext,uniphier-denali-nand-v5b" - for Socionext UniPhier (v5b) + - reg : should contain registers location and length for data and reg. + - reg-names: Should contain the reg names "nand_data" and "denali_reg" + - interrupts : The interrupt number. + - clocks: should contain phandle of the controller core clock, the bus + interface clock, and the ECC circuit clock. + - clock-names: should contain "nand", "nand_x", "ecc" + +Optional properties: + - nand-ecc-step-size: see nand.txt for details. If present, the value must be + 512 for "altr,socfpga-denali-nand" + 1024 for "socionext,uniphier-denali-nand-v5a" + 1024 for "socionext,uniphier-denali-nand-v5b" + - nand-ecc-strength: see nand.txt for details. Valid values are: + 8, 15 for "altr,socfpga-denali-nand" + 8, 16, 24 for "socionext,uniphier-denali-nand-v5a" + 8, 16 for "socionext,uniphier-denali-nand-v5b" + - nand-ecc-maximize: see nand.txt for details + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Examples: + +nand: nand@ff900000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,socfpga-denali-nand"; + reg = <0xff900000 0x20>, <0xffb80000 0x1000>; + reg-names = "nand_data", "denali_reg"; + clocks = <&nand_clk>, <&nand_x_clk>, <&nand_ecc_clk>; + clock-names = "nand", "nand_x", "ecc"; + interrupts = <0 144 4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/diskonchip.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/diskonchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e13bfdbea5b834afbc494a1eb24daede7cfe951 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/diskonchip.txt @@ -0,0 +1,15 @@ +M-Systems and Sandisk DiskOnChip devices + +M-System DiskOnChip G3 +====================== +The Sandisk (formerly M-Systems) docg3 is a nand device of 64M to 256MB. + +Required properties: + - compatible: should be "m-systems,diskonchip-g3" + - reg: register base and size + +Example: + docg3: flash@0 { + compatible = "m-systems,diskonchip-g3"; + reg = <0x0 0x2000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/elm.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/elm.txt new file mode 100644 index 0000000000000000000000000000000000000000..59ddc61c10768dc1dfe73adbd5cf462e0dbc2da8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/elm.txt @@ -0,0 +1,16 @@ +Error location module + +Required properties: +- compatible: Must be "ti,am3352-elm" +- reg: physical base address and size of the registers map. +- interrupts: Interrupt number for the elm. + +Optional properties: +- ti,hwmods: Name of the hwmod associated to the elm + +Example: +elm: elm@0 { + compatible = "ti,am3352-elm"; + reg = <0x48080000 0x2000>; + interrupts = <4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/flctl-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/flctl-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..427f46dc60add1340418951cd365ab04d4fa9a1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/flctl-nand.txt @@ -0,0 +1,49 @@ +FLCTL NAND controller + +Required properties: +- compatible : "renesas,shmobile-flctl-sh7372" +- reg : Address range of the FLCTL +- interrupts : flste IRQ number +- nand-bus-width : bus width to NAND chip + +Optional properties: +- dmas: DMA specifier(s) +- dma-names: name for each DMA specifier. Valid names are + "data_tx", "data_rx", "ecc_tx", "ecc_rx" + +The DMA fields are not used yet in the driver but are listed here for +completing the bindings. + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + + flctl@e6a30000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "renesas,shmobile-flctl-sh7372"; + reg = <0xe6a30000 0x100>; + interrupts = <0x0d80>; + + nand-bus-width = <16>; + + dmas = <&dmac 1 /* data_tx */ + &dmac 2;> /* data_rx */ + dma-names = "data_tx", "data_rx"; + + system@0 { + label = "system"; + reg = <0x0 0x8000000>; + }; + + userdata@8000000 { + label = "userdata"; + reg = <0x8000000 0x10000000>; + }; + + cache@18000000 { + label = "cache"; + reg = <0x18000000 0x8000000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/fsl-quadspi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/fsl-quadspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..483e9cfac1b1b31d5856623813fdaa6e21d0093a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/fsl-quadspi.txt @@ -0,0 +1,65 @@ +* Freescale Quad Serial Peripheral Interface(QuadSPI) + +Required properties: + - compatible : Should be "fsl,vf610-qspi", "fsl,imx6sx-qspi", + "fsl,imx7d-qspi", "fsl,imx6ul-qspi", + "fsl,ls1021a-qspi" + or + "fsl,ls2080a-qspi" followed by "fsl,ls1021a-qspi", + "fsl,ls1043a-qspi" followed by "fsl,ls1021a-qspi" + - reg : the first contains the register location and length, + the second contains the memory mapping address and length + - reg-names: Should contain the reg names "QuadSPI" and "QuadSPI-memory" + - interrupts : Should contain the interrupt for the device + - clocks : The clocks needed by the QuadSPI controller + - clock-names : Should contain the name of the clocks: "qspi_en" and "qspi". + +Optional properties: + - fsl,qspi-has-second-chip: The controller has two buses, bus A and bus B. + Each bus can be connected with two NOR flashes. + Most of the time, each bus only has one NOR flash + connected, this is the default case. + But if there are two NOR flashes connected to the + bus, you should enable this property. + (Please check the board's schematic.) + - big-endian : That means the IP register is big endian + +Example: + +qspi0: quadspi@40044000 { + compatible = "fsl,vf610-qspi"; + reg = <0x40044000 0x1000>, <0x20000000 0x10000000>; + reg-names = "QuadSPI", "QuadSPI-memory"; + interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks VF610_CLK_QSPI0_EN>, + <&clks VF610_CLK_QSPI0>; + clock-names = "qspi_en", "qspi"; + + flash0: s25fl128s@0 { + .... + }; +}; + +Example showing the usage of two SPI NOR devices: + +&qspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi2>; + status = "okay"; + + flash0: n25q256a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a", "jedec,spi-nor"; + spi-max-frequency = <29000000>; + reg = <0>; + }; + + flash1: n25q256a@1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "micron,n25q256a", "jedec,spi-nor"; + spi-max-frequency = <29000000>; + reg = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/fsl-upm-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/fsl-upm-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..fce4894f5a98739f14b13abb87096191bbdb1b2b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/fsl-upm-nand.txt @@ -0,0 +1,67 @@ +Freescale Localbus UPM programmed to work with NAND flash + +Required properties: +- compatible : "fsl,upm-nand". +- reg : should specify localbus chip select and size used for the chip. +- fsl,upm-addr-offset : UPM pattern offset for the address latch. +- fsl,upm-cmd-offset : UPM pattern offset for the command latch. + +Optional properties: +- fsl,upm-wait-flags : add chip-dependent short delays after running the + UPM pattern (0x1), after writing a data byte (0x2) or after + writing out a buffer (0x4). +- fsl,upm-addr-line-cs-offsets : address offsets for multi-chip support. + The corresponding address lines are used to select the chip. +- gpios : may specify optional GPIOs connected to the Ready-Not-Busy pins + (R/B#). For multi-chip devices, "n" GPIO definitions are required + according to the number of chips. +- chip-delay : chip dependent delay for transferring data from array to + read registers (tR). Required if property "gpios" is not used + (R/B# pins not connected). + +Each flash chip described may optionally contain additional sub-nodes +describing partitions of the address space. See partition.txt for more +detail. + +Examples: + +upm@1,0 { + compatible = "fsl,upm-nand"; + reg = <1 0 1>; + fsl,upm-addr-offset = <16>; + fsl,upm-cmd-offset = <8>; + gpios = <&qe_pio_e 18 0>; + + flash { + #address-cells = <1>; + #size-cells = <1>; + compatible = "..."; + + partition@0 { + ... + }; + }; +}; + +upm@3,0 { + #address-cells = <0>; + #size-cells = <0>; + compatible = "tqc,tqm8548-upm-nand", "fsl,upm-nand"; + reg = <3 0x0 0x800>; + fsl,upm-addr-offset = <0x10>; + fsl,upm-cmd-offset = <0x08>; + /* Multi-chip NAND device */ + fsl,upm-addr-line-cs-offsets = <0x0 0x200>; + fsl,upm-wait-flags = <0x5>; + chip-delay = <25>; // in micro-seconds + + nand@0 { + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "fs"; + reg = <0x00000000 0x10000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/fsmc-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/fsmc-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..32636eb77304ce497f55b743d4f37c6ed2fed780 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/fsmc-nand.txt @@ -0,0 +1,60 @@ +ST Microelectronics Flexible Static Memory Controller (FSMC) +NAND Interface + +Required properties: +- compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand" +- reg : Address range of the mtd chip +- reg-names: Should contain the reg names "fsmc_regs", "nand_data", "nand_addr" and "nand_cmd" + +Optional properties: +- bank-width : Width (in bytes) of the device. If not present, the width + defaults to 1 byte +- nand-skip-bbtscan: Indicates the BBT scanning should be skipped +- timings: array of 6 bytes for NAND timings. The meanings of these bytes + are: + byte 0 TCLR : CLE to RE delay in number of AHB clock cycles, only 4 bits + are valid. Zero means one clockcycle, 15 means 16 clock + cycles. + byte 1 TAR : ALE to RE delay, 4 bits are valid. Same format as TCLR. + byte 2 THIZ : number of HCLK clock cycles during which the data bus is + kept in Hi-Z (tristate) after the start of a write access. + Only valid for write transactions. Zero means zero cycles, + 255 means 255 cycles. + byte 3 THOLD : number of HCLK clock cycles to hold the address (and data + when writing) after the command deassertation. Zero means + one cycle, 255 means 256 cycles. + byte 4 TWAIT : number of HCLK clock cycles to assert the command to the + NAND flash in response to SMWAITn. Zero means 1 cycle, + 255 means 256 cycles. + byte 5 TSET : number of HCLK clock cycles to assert the address before the + command is asserted. Zero means one cycle, 255 means 256 + cycles. +- bank: default NAND bank to use (0-3 are valid, 0 is the default). +- nand-ecc-mode : see nand.txt +- nand-ecc-strength : see nand.txt +- nand-ecc-step-size : see nand.txt + +Can support 1-bit HW ECC (default) or if stronger correction is required, +software-based BCH. + +Example: + + fsmc: flash@d1800000 { + compatible = "st,spear600-fsmc-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xd1800000 0x1000 /* FSMC Register */ + 0xd2000000 0x0010 /* NAND Base DATA */ + 0xd2020000 0x0010 /* NAND Base ADDR */ + 0xd2010000 0x0010>; /* NAND Base CMD */ + reg-names = "fsmc_regs", "nand_data", "nand_addr", "nand_cmd"; + + bank-width = <1>; + nand-skip-bbtscan; + timings = /bits/ 8 <0 0 0 2 3 0>; + bank = <1>; + + partition@0 { + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/gpio-control-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/gpio-control-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..486a17d533d7a33cce0ac8814a51979ebc7bc0ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/gpio-control-nand.txt @@ -0,0 +1,47 @@ +GPIO assisted NAND flash + +The GPIO assisted NAND flash uses a memory mapped interface to +read/write the NAND commands and data and GPIO pins for the control +signals. + +Required properties: +- compatible : "gpio-control-nand" +- reg : should specify localbus chip select and size used for the chip. The + resource describes the data bus connected to the NAND flash and all accesses + are made in native endianness. +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. +- gpios : Specifies the GPIO pins to control the NAND device. The order of + GPIO references is: RDY, nCE, ALE, CLE, and nWP. nCE and nWP are optional. + +Optional properties: +- bank-width : Width (in bytes) of the device. If not present, the width + defaults to 1 byte. +- chip-delay : chip dependent delay for transferring data from array to + read registers (tR). If not present then a default of 20us is used. +- gpio-control-nand,io-sync-reg : A 64-bit physical address for a read + location used to guard against bus reordering with regards to accesses to + the GPIO's and the NAND flash data bus. If present, then after changing + GPIO state and before and after command byte writes, this register will be + read to ensure that the GPIO accesses have completed. + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Examples: + +gpio-nand@1,0 { + compatible = "gpio-control-nand"; + reg = <1 0x0000 0x2>; + #address-cells = <1>; + #size-cells = <1>; + gpios = <&banka 1 0>, /* RDY */ + <0>, /* nCE */ + <&banka 3 0>, /* ALE */ + <&banka 4 0>, /* CLE */ + <0>; /* nWP */ + + partition@0 { + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..c059ab74ed8861f0a046f8462f14e95027ffc20e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-nand.txt @@ -0,0 +1,147 @@ +Device tree bindings for GPMC connected NANDs + +GPMC connected NAND (found on OMAP boards) are represented as child nodes of +the GPMC controller with a name of "nand". + +All timing relevant properties as well as generic gpmc child properties are +explained in a separate documents - please refer to +Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt + +For NAND specific properties such as ECC modes or bus width, please refer to +Documentation/devicetree/bindings/mtd/nand.txt + + +Required properties: + + - compatible: "ti,omap2-nand" + - reg: range id (CS number), base offset and length of the + NAND I/O space + - interrupts: Two interrupt specifiers, one for fifoevent, one for termcount. + +Optional properties: + + - nand-bus-width: Set this numeric value to 16 if the hardware + is wired that way. If not specified, a bus + width of 8 is assumed. + + - ti,nand-ecc-opt: A string setting the ECC layout to use. One of: + "sw" 1-bit Hamming ecc code via software + "hw" use "ham1" instead + "hw-romcode" use "ham1" instead + "ham1" 1-bit Hamming ecc code + "bch4" 4-bit BCH ecc code + "bch8" 8-bit BCH ecc code + "bch16" 16-bit BCH ECC code + Refer below "How to select correct ECC scheme for your device ?" + + - ti,nand-xfer-type: A string setting the data transfer type. One of: + + "prefetch-polled" Prefetch polled mode (default) + "polled" Polled mode, without prefetch + "prefetch-dma" Prefetch enabled DMA mode + "prefetch-irq" Prefetch enabled irq mode + + - elm_id: use "ti,elm-id" instead + - ti,elm-id: Specifies phandle of the ELM devicetree node. + ELM is an on-chip hardware engine on TI SoC which is used for + locating ECC errors for BCHx algorithms. SoC devices which have + ELM hardware engines should specify this device node in .dtsi + Using ELM for ECC error correction frees some CPU cycles. + - rb-gpios: GPIO specifier for the ready/busy# pin. + +For inline partition table parsing (optional): + + - #address-cells: should be set to 1 + - #size-cells: should be set to 1 + +Example for an AM33xx board: + + gpmc: gpmc@50000000 { + compatible = "ti,am3352-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x50000000 0x36c>; + interrupts = <100>; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <2>; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x08000000 0x1000000>; /* CS0 space, 16MB */ + elm_id = <&elm>; + interrupt-controller; + #interrupt-cells = <2>; + + nand@0,0 { + compatible = "ti,omap2-nand"; + reg = <0 0 4>; /* CS0, offset 0, NAND I/O window 4 */ + interrupt-parent = <&gpmc>; + interrupts = <0 IRQ_TYPE_NONE>, <1 IRQ_TYPE NONE>; + nand-bus-width = <16>; + ti,nand-ecc-opt = "bch8"; + ti,nand-xfer-type = "polled"; + rb-gpios = <&gpmc 0 GPIO_ACTIVE_HIGH>; /* gpmc_wait0 */ + + gpmc,sync-clk-ps = <0>; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <44>; + gpmc,cs-wr-off-ns = <44>; + gpmc,adv-on-ns = <6>; + gpmc,adv-rd-off-ns = <34>; + gpmc,adv-wr-off-ns = <44>; + gpmc,we-off-ns = <40>; + gpmc,oe-off-ns = <54>; + gpmc,access-ns = <64>; + gpmc,rd-cycle-ns = <82>; + gpmc,wr-cycle-ns = <82>; + gpmc,wr-access-ns = <40>; + gpmc,wr-data-mux-bus-ns = <0>; + + #address-cells = <1>; + #size-cells = <1>; + + /* partitions go here */ + }; + }; + +How to select correct ECC scheme for your device ? +-------------------------------------------------- +Higher ECC scheme usually means better protection against bit-flips and +increased system lifetime. However, selection of ECC scheme is dependent +on various other factors also like; + +(1) support of built in hardware engines. + Some legacy OMAP SoC do not have ELM harware engine, so those SoC cannot + support ecc-schemes with hardware error-correction (BCHx_HW). However + such SoC can use ecc-schemes with software library for error-correction + (BCHx_HW_DETECTION_SW). The error correction capability with software + library remains equivalent to their hardware counter-part, but there is + slight CPU penalty when too many bit-flips are detected during reads. + +(2) Device parameters like OOBSIZE. + Other factor which governs the selection of ecc-scheme is oob-size. + Higher ECC schemes require more OOB/Spare area to store ECC syndrome, + so the device should have enough free bytes available its OOB/Spare + area to accommodate ECC for entire page. In general following expression + helps in determining if given device can accommodate ECC syndrome: + "2 + (PAGESIZE / 512) * ECC_BYTES" >= OOBSIZE" + where + OOBSIZE number of bytes in OOB/spare area + PAGESIZE number of bytes in main-area of device page + ECC_BYTES number of ECC bytes generated to protect + 512 bytes of data, which is: + '3' for HAM1_xx ecc schemes + '7' for BCH4_xx ecc schemes + '14' for BCH8_xx ecc schemes + '26' for BCH16_xx ecc schemes + + Example(a): For a device with PAGESIZE = 2048 and OOBSIZE = 64 and + trying to use BCH16 (ECC_BYTES=26) ecc-scheme. + Number of ECC bytes per page = (2 + (2048 / 512) * 26) = 106 B + which is greater than capacity of NAND device (OOBSIZE=64) + Hence, BCH16 cannot be supported on given device. But it can + probably use lower ecc-schemes like BCH8. + + Example(b): For a device with PAGESIZE = 2048 and OOBSIZE = 128 and + trying to use BCH16 (ECC_BYTES=26) ecc-scheme. + Number of ECC bytes per page = (2 + (2048 / 512) * 26) = 106 B + which can be accommodated in the OOB/Spare area of this device + (OOBSIZE=128). So this device can use BCH16 ecc-scheme. diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-nor.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-nor.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8567b40fe13a02abaee0ffd2f037d0a4282a950 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-nor.txt @@ -0,0 +1,98 @@ +Device tree bindings for NOR flash connect to TI GPMC + +NOR flash connected to the TI GPMC (found on OMAP boards) are represented as +child nodes of the GPMC controller with a name of "nor". + +All timing relevant properties as well as generic GPMC child properties are +explained in a separate documents. Please refer to +Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt + +Required properties: +- bank-width: Width of NOR flash in bytes. GPMC supports 8-bit and + 16-bit devices and so must be either 1 or 2 bytes. +- compatible: Documentation/devicetree/bindings/mtd/mtd-physmap.txt +- gpmc,cs-on-ns: Chip-select assertion time +- gpmc,cs-rd-off-ns: Chip-select de-assertion time for reads +- gpmc,cs-wr-off-ns: Chip-select de-assertion time for writes +- gpmc,oe-on-ns: Output-enable assertion time +- gpmc,oe-off-ns: Output-enable de-assertion time +- gpmc,we-on-ns Write-enable assertion time +- gpmc,we-off-ns: Write-enable de-assertion time +- gpmc,access-ns: Start cycle to first data capture (read access) +- gpmc,rd-cycle-ns: Total read cycle time +- gpmc,wr-cycle-ns: Total write cycle time +- linux,mtd-name: Documentation/devicetree/bindings/mtd/mtd-physmap.txt +- reg: Chip-select, base address (relative to chip-select) + and size of NOR flash. Note that base address will be + typically 0 as this is the start of the chip-select. + +Optional properties: +- gpmc,XXX Additional GPMC timings and settings parameters. See + Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt + +Optional properties for partition table parsing: +- #address-cells: should be set to 1 +- #size-cells: should be set to 1 + +Example: + +gpmc: gpmc@6e000000 { + compatible = "ti,omap3430-gpmc", "simple-bus"; + ti,hwmods = "gpmc"; + reg = <0x6e000000 0x1000>; + interrupts = <20>; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <4>; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <0 0 0x10000000 0x08000000>; + + nor@0,0 { + compatible = "cfi-flash"; + linux,mtd-name= "intel,pf48f6000m0y1be"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0 0 0x08000000>; + bank-width = <2>; + + gpmc,mux-add-data; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <186>; + gpmc,cs-wr-off-ns = <186>; + gpmc,adv-on-ns = <12>; + gpmc,adv-rd-off-ns = <48>; + gpmc,adv-wr-off-ns = <48>; + gpmc,oe-on-ns = <54>; + gpmc,oe-off-ns = <168>; + gpmc,we-on-ns = <54>; + gpmc,we-off-ns = <168>; + gpmc,rd-cycle-ns = <186>; + gpmc,wr-cycle-ns = <186>; + gpmc,access-ns = <114>; + gpmc,page-burst-access-ns = <6>; + gpmc,bus-turnaround-ns = <12>; + gpmc,cycle2cycle-delay-ns = <18>; + gpmc,wr-data-mux-bus-ns = <90>; + gpmc,wr-access-ns = <186>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + partition@0 { + label = "bootloader-nor"; + reg = <0 0x40000>; + }; + partition@40000 { + label = "params-nor"; + reg = <0x40000 0x40000>; + }; + partition@80000 { + label = "kernel-nor"; + reg = <0x80000 0x200000>; + }; + partition@280000 { + label = "filesystem-nor"; + reg = <0x240000 0x7d80000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-onenand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-onenand.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9f01a963a0a3a8bdb9037f6a27d133430bbb523 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmc-onenand.txt @@ -0,0 +1,48 @@ +Device tree bindings for GPMC connected OneNANDs + +GPMC connected OneNAND (found on OMAP boards) are represented as child nodes of +the GPMC controller with a name of "onenand". + +All timing relevant properties as well as generic gpmc child properties are +explained in a separate documents - please refer to +Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt + +Required properties: + + - compatible: "ti,omap2-onenand" + - reg: The CS line the peripheral is connected to + - gpmc,device-width: Width of the ONENAND device connected to the GPMC + in bytes. Must be 1 or 2. + +Optional properties: + + - int-gpios: GPIO specifier for the INT pin. + +For inline partition table parsing (optional): + + - #address-cells: should be set to 1 + - #size-cells: should be set to 1 + +Example for an OMAP3430 board: + + gpmc: gpmc@6e000000 { + compatible = "ti,omap3430-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x6e000000 0x1000000>; + interrupts = <20>; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <4>; + #address-cells = <2>; + #size-cells = <1>; + + onenand@0 { + compatible = "ti,omap2-onenand"; + reg = <0 0 0>; /* CS0, offset 0 */ + gpmc,device-width = <2>; + + #address-cells = <1>; + #size-cells = <1>; + + /* partitions go here */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/gpmi-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmi-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..393588385c6e50cd2e8dbf0469f0ba17efaab1e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/gpmi-nand.txt @@ -0,0 +1,75 @@ +* Freescale General-Purpose Media Interface (GPMI) + +The GPMI nand controller provides an interface to control the +NAND flash chips. + +Required properties: + - compatible : should be "fsl,-gpmi-nand", chip can be: + * imx23 + * imx28 + * imx6q + * imx6sx + * imx7d + - reg : should contain registers location and length for gpmi and bch. + - reg-names: Should contain the reg names "gpmi-nand" and "bch" + - interrupts : BCH interrupt number. + - interrupt-names : Should be "bch". + - dmas: DMA specifier, consisting of a phandle to DMA controller node + and GPMI DMA channel ID. + Refer to dma.txt and fsl-mxs-dma.txt for details. + - dma-names: Must be "rx-tx". + - clocks : clocks phandle and clock specifier corresponding to each clock + specified in clock-names. + - clock-names : The "gpmi_io" clock is always required. Which clocks are + exactly required depends on chip: + * imx23/imx28 : "gpmi_io" + * imx6q/sx : "gpmi_io", "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch" + * imx7d : "gpmi_io", "gpmi_bch_apb" + +Optional properties: + - nand-on-flash-bbt: boolean to enable on flash bbt option if not + present false + - fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC + strength required. The required ECC strength is + automatically discoverable for some flash + (e.g., according to the ONFI standard). + However, note that if this strength is not + discoverable or this property is not enabled, + the software may chooses an implementation-defined + ECC scheme. + - fsl,no-blockmark-swap: Don't swap the bad block marker from the OOB + area with the byte in the data area but rely on the + flash based BBT for identifying bad blocks. + NOTE: this is only valid in conjunction with + 'nand-on-flash-bbt'. + WARNING: on i.MX28 blockmark swapping cannot be + disabled for the BootROM in the FCB. Thus, + partitions written from Linux with this feature + turned on may not be accessible by the BootROM + code. + - nand-ecc-strength: integer representing the number of bits to correct + per ECC step. Needs to be a multiple of 2. + - nand-ecc-step-size: integer representing the number of data bytes + that are covered by a single ECC step. The driver + supports 512 and 1024. + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Examples: + +gpmi-nand@8000c000 { + compatible = "fsl,imx28-gpmi-nand"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x8000c000 2000>, <0x8000a000 2000>; + reg-names = "gpmi-nand", "bch"; + interrupts = <41>; + interrupt-names = "bch"; + dmas = <&dma_apbh 4>; + dma-names = "rx-tx"; + + partition@0 { + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/hisi504-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/hisi504-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..2e35f0662912aa35d96839f919ec7c29ca507797 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/hisi504-nand.txt @@ -0,0 +1,47 @@ +Hisilicon Hip04 Soc NAND controller DT binding + +Required properties: + +- compatible: Should be "hisilicon,504-nfc". +- reg: The first contains base physical address and size of + NAND controller's registers. The second contains base + physical address and size of NAND controller's buffer. +- interrupts: Interrupt number for nfc. +- nand-bus-width: See nand.txt. +- nand-ecc-mode: Support none and hw ecc mode. +- #address-cells: Partition address, should be set 1. +- #size-cells: Partition size, should be set 1. + +Optional properties: + +- nand-ecc-strength: Number of bits to correct per ECC step. +- nand-ecc-step-size: Number of data bytes covered by a single ECC step. + +The following ECC strength and step size are currently supported: + + - nand-ecc-strength = <16>, nand-ecc-step-size = <1024> + +Flash chip may optionally contain additional sub-nodes describing partitions of +the address space. See partition.txt for more detail. + +Example: + + nand: nand@4020000 { + compatible = "hisilicon,504-nfc"; + reg = <0x4020000 0x10000>, <0x5000000 0x1000>; + interrupts = <0 379 4>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-ecc-strength = <16>; + nand-ecc-step-size = <1024>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "nand_text"; + reg = <0x00000000 0x00400000>; + }; + + ... + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/hisilicon,fmc-spi-nor.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/hisilicon,fmc-spi-nor.txt new file mode 100644 index 0000000000000000000000000000000000000000..74981520d6dd3a503500fb307c499818ec700b35 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/hisilicon,fmc-spi-nor.txt @@ -0,0 +1,24 @@ +HiSilicon SPI-NOR Flash Controller + +Required properties: +- compatible : Should be "hisilicon,fmc-spi-nor" and one of the following strings: + "hisilicon,hi3519-spi-nor" +- address-cells : Should be 1. +- size-cells : Should be 0. +- reg : Offset and length of the register set for the controller device. +- reg-names : Must include the following two entries: "control", "memory". +- clocks : handle to spi-nor flash controller clock. + +Example: +spi-nor-controller@10000000 { + compatible = "hisilicon,hi3519-spi-nor", "hisilicon,fmc-spi-nor"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10000000 0x1000>, <0x14000000 0x1000000>; + reg-names = "control", "memory"; + clocks = <&clock HI3519_FMC_CLK>; + spi-nor@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/ibm,ndfc.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/ibm,ndfc.txt new file mode 100644 index 0000000000000000000000000000000000000000..869f0b5f16e884a584e675528df1c14262ab3066 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/ibm,ndfc.txt @@ -0,0 +1,39 @@ +AMCC NDFC (NanD Flash Controller) + +Required properties: +- compatible : "ibm,ndfc". +- reg : should specify chip select and size used for the chip (0x2000). + +Optional properties: +- ccr : NDFC config and control register value (default 0). +- bank-settings : NDFC bank configuration register value (default 0). + +Notes: +- partition(s) - follows the OF MTD standard for partitions + +Example: + +ndfc@1,0 { + compatible = "ibm,ndfc"; + reg = <0x00000001 0x00000000 0x00002000>; + ccr = <0x00001000>; + bank-settings = <0x80002222>; + #address-cells = <1>; + #size-cells = <1>; + + nand { + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "kernel"; + reg = <0x00000000 0x00200000>; + }; + partition@200000 { + label = "root"; + reg = <0x00200000 0x03E00000>; + }; + }; +}; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/ingenic,jz4780-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/ingenic,jz4780-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..29ea5853ca9147bbc7f8277e33925193792b91c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/ingenic,jz4780-nand.txt @@ -0,0 +1,86 @@ +* Ingenic JZ4780 NAND/BCH + +This file documents the device tree bindings for NAND flash devices on the +JZ4780. NAND devices are connected to the NEMC controller (described in +memory-controllers/ingenic,jz4780-nemc.txt), and thus NAND device nodes must +be children of the NEMC node. + +Required NAND controller device properties: +- compatible: Should be set to "ingenic,jz4780-nand". +- reg: For each bank with a NAND chip attached, should specify a bank number, + an offset of 0 and a size of 0x1000000 (i.e. the whole NEMC bank). + +Optional NAND controller device properties: +- ingenic,bch-controller: To make use of the hardware BCH controller, this + property must contain a phandle for the BCH controller node. The required + properties for this node are described below. If this is not specified, + software BCH will be used instead. + +Optional children nodes: +- Individual NAND chips are children of the NAND controller node. + +Required children node properties: +- reg: An integer ranging from 1 to 6 representing the CS line to use. + +Optional children node properties: +- nand-ecc-step-size: ECC block size in bytes. +- nand-ecc-strength: ECC strength (max number of correctable bits). +- nand-ecc-mode: String, operation mode of the NAND ecc mode. "hw" by default +- nand-on-flash-bbt: boolean to enable on flash bbt option, if not present false +- rb-gpios: GPIO specifier for the busy pin. +- wp-gpios: GPIO specifier for the write protect pin. + +Optional child node of NAND chip nodes: +- partitions: see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + +nemc: nemc@13410000 { + ... + + nandc: nand-controller@1 { + compatible = "ingenic,jz4780-nand"; + reg = <1 0 0x1000000>; /* Bank 1 */ + + #address-cells = <1>; + #size-cells = <0>; + + ingenic,bch-controller = <&bch>; + + nand@1 { + reg = <1>; + + nand-ecc-step-size = <1024>; + nand-ecc-strength = <24>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + + rb-gpios = <&gpa 20 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpf 22 GPIO_ACTIVE_LOW>; + + partitions { + #address-cells = <2>; + #size-cells = <2>; + ... + } + }; + }; +}; + +The BCH controller is a separate SoC component used for error correction on +NAND devices. The following is a description of the device properties for a +BCH controller. + +Required BCH properties: +- compatible: Should be set to "ingenic,jz4780-bch". +- reg: Should specify the BCH controller registers location and length. +- clocks: Clock for the BCH controller. + +Example: + +bch: bch@134d0000 { + compatible = "ingenic,jz4780-bch"; + reg = <0x134d0000 0x10000>; + + clocks = <&cgu JZ4780_CLK_BCH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/jedec,spi-nor.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/jedec,spi-nor.txt new file mode 100644 index 0000000000000000000000000000000000000000..f03be904d3c228d8e46cc117ea0d5893f68e6e9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/jedec,spi-nor.txt @@ -0,0 +1,91 @@ +* SPI NOR flash: ST M25Pxx (and similar) serial flash chips + +Required properties: +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. +- compatible : May include a device-specific string consisting of the + manufacturer and name of the chip. A list of supported chip + names follows. + Must also include "jedec,spi-nor" for any SPI NOR flash that can + be identified by the JEDEC READ ID opcode (0x9F). + + Supported chip names: + at25df321a + at25df641 + at26df081a + mr25h128 + mr25h256 + mr25h10 + mr25h40 + mx25l4005a + mx25l1606e + mx25l6405d + mx25l12805d + mx25l25635e + n25q064 + n25q128a11 + n25q128a13 + n25q512a + s25fl256s1 + s25fl512s + s25sl12801 + s25fl008k + s25fl064k + sst25vf040b + m25p40 + m25p80 + m25p16 + m25p32 + m25p64 + m25p128 + w25x80 + w25x32 + w25q32 + w25q64 + w25q32dw + w25q80bl + w25q128 + w25q256 + + The following chip names have been used historically to + designate quirky versions of flash chips that do not support the + JEDEC READ ID opcode (0x9F): + m25p05-nonjedec + m25p10-nonjedec + m25p20-nonjedec + m25p40-nonjedec + m25p80-nonjedec + m25p16-nonjedec + m25p32-nonjedec + m25p64-nonjedec + m25p128-nonjedec + +- reg : Chip-Select number +- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at + +Optional properties: +- m25p,fast-read : Use the "fast read" opcode to read data from the chip instead + of the usual "read" opcode. This opcode is not supported by + all chips and support for it can not be detected at runtime. + Refer to your chips' datasheet to check if this is supported + by your chip. +- broken-flash-reset : Some flash devices utilize stateful addressing modes + (e.g., for 32-bit addressing) which need to be managed + carefully by a system. Because these sorts of flash don't + have a standardized software reset command, and because some + systems don't toggle the flash RESET# pin upon system reset + (if the pin even exists at all), there are systems which + cannot reboot properly if the flash is left in the "wrong" + state. This boolean flag can be used on such systems, to + denote the absence of a reliable reset mechanism. + +Example: + + flash: m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,m25p80", "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <40000000>; + m25p,fast-read; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/lpc32xx-mlc.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/lpc32xx-mlc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d60bc3063f51bd9827689014fce939f6e79953f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/lpc32xx-mlc.txt @@ -0,0 +1,50 @@ +NXP LPC32xx SoC NAND MLC controller + +Required properties: +- compatible: "nxp,lpc3220-mlc" +- reg: Address and size of the controller +- interrupts: The NAND interrupt specification +- gpios: GPIO specification for NAND write protect + +The following required properties are very controller specific. See the LPC32xx +User Manual 7.5.14 MLC NAND Timing Register (the values here are specified in +Hz, to make them independent of actual clock speed and to provide for good +accuracy:) +- nxp,tcea_delay: TCEA_DELAY +- nxp,busy_delay: BUSY_DELAY +- nxp,nand_ta: NAND_TA +- nxp,rd_high: RD_HIGH +- nxp,rd_low: RD_LOW +- nxp,wr_high: WR_HIGH +- nxp,wr_low: WR_LOW + +Optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + + mlc: flash@200a8000 { + compatible = "nxp,lpc3220-mlc"; + reg = <0x200A8000 0x11000>; + interrupts = <11 0>; + #address-cells = <1>; + #size-cells = <1>; + + nxp,tcea-delay = <333333333>; + nxp,busy-delay = <10000000>; + nxp,nand-ta = <18181818>; + nxp,rd-high = <31250000>; + nxp,rd-low = <45454545>; + nxp,wr-high = <40000000>; + nxp,wr-low = <83333333>; + gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */ + + mtd0@00000000 { + label = "boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + ... + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/lpc32xx-slc.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/lpc32xx-slc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d94edc0fc554bf1085410876d604320a7468f09e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/lpc32xx-slc.txt @@ -0,0 +1,52 @@ +NXP LPC32xx SoC NAND SLC controller + +Required properties: +- compatible: "nxp,lpc3220-slc" +- reg: Address and size of the controller +- nand-on-flash-bbt: Use bad block table on flash +- gpios: GPIO specification for NAND write protect + +The following required properties are very controller specific. See the LPC32xx +User Manual: +- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY) +- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY) +(The following values are specified in Hz, to make them independent of actual +clock speed:) +- nxp,wwidth: Write pulse width (W_WIDTH) +- nxp,whold: Write hold time (W_HOLD) +- nxp,wsetup: Write setup time (W_SETUP) +- nxp,rwidth: Read pulse width (R_WIDTH) +- nxp,rhold: Read hold time (R_HOLD) +- nxp,rsetup: Read setup time (R_SETUP) + +Optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + + slc: flash@20020000 { + compatible = "nxp,lpc3220-slc"; + reg = <0x20020000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + nxp,wdr-clks = <14>; + nxp,wwidth = <40000000>; + nxp,whold = <100000000>; + nxp,wsetup = <100000000>; + nxp,rdr-clks = <14>; + nxp,rwidth = <40000000>; + nxp,rhold = <66666666>; + nxp,rsetup = <100000000>; + nand-on-flash-bbt; + gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */ + + mtd0@00000000 { + label = "phy3250-boot"; + reg = <0x00000000 0x00064000>; + read-only; + }; + + ... + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/marvell-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/marvell-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0c790706b9b10646363548f432c92bf51fe48b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/marvell-nand.txt @@ -0,0 +1,126 @@ +Marvell NAND Flash Controller (NFC) + +Required properties: +- compatible: can be one of the following: + * "marvell,armada-8k-nand-controller" + * "marvell,armada370-nand-controller" + * "marvell,pxa3xx-nand-controller" + * "marvell,armada-8k-nand" (deprecated) + * "marvell,armada370-nand" (deprecated) + * "marvell,pxa3xx-nand" (deprecated) + Compatibles marked deprecated support only the old bindings described + at the bottom. +- reg: NAND flash controller memory area. +- #address-cells: shall be set to 1. Encode the NAND CS. +- #size-cells: shall be set to 0. +- interrupts: shall define the NAND controller interrupt. +- clocks: shall reference the NAND controller clocks, the second one is + is only needed for the Armada 7K/8K SoCs +- clock-names: mandatory if there is a second clock, in this case there + should be one clock named "core" and another one named "reg" +- marvell,system-controller: Set to retrieve the syscon node that handles + NAND controller related registers (only required with the + "marvell,armada-8k-nand[-controller]" compatibles). + +Optional properties: +- label: see partition.txt. New platforms shall omit this property. +- dmas: shall reference DMA channel associated to the NAND controller. + This property is only used with "marvell,pxa3xx-nand[-controller]" + compatible strings. +- dma-names: shall be "rxtx". + This property is only used with "marvell,pxa3xx-nand[-controller]" + compatible strings. + +Optional children nodes: +Children nodes represent the available NAND chips. + +Required properties: +- reg: shall contain the native Chip Select ids (0-3). +- nand-rb: see nand.txt (0-1). + +Optional properties: +- marvell,nand-keep-config: orders the driver not to take the timings + from the core and leaving them completely untouched. Bootloader + timings will then be used. +- label: MTD name. +- nand-on-flash-bbt: see nand.txt. +- nand-ecc-mode: see nand.txt. Will use hardware ECC if not specified. +- nand-ecc-algo: see nand.txt. This property is essentially useful when + not using hardware ECC. Howerver, it may be added when using hardware + ECC for clarification but will be ignored by the driver because ECC + mode is chosen depending on the page size and the strength required by + the NAND chip. This value may be overwritten with nand-ecc-strength + property. +- nand-ecc-strength: see nand.txt. +- nand-ecc-step-size: see nand.txt. Marvell's NAND flash controller does + use fixed strength (1-bit for Hamming, 16-bit for BCH), so the actual + step size will shrink or grow in order to fit the required strength. + Step sizes are not completely random for all and follow certain + patterns described in AN-379, "Marvell SoC NFC ECC". + +See Documentation/devicetree/bindings/mtd/nand.txt for more details on +generic bindings. + + +Example: +nand_controller: nand-controller@d0000 { + compatible = "marvell,armada370-nand-controller"; + reg = <0xd0000 0x54>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&coredivclk 0>; + + nand@0 { + reg = <0>; + label = "main-storage"; + nand-rb = <0>; + nand-ecc-mode = "hw"; + marvell,nand-keep-config; + nand-on-flash-bbt; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "Rootfs"; + reg = <0x00000000 0x40000000>; + }; + }; + }; +}; + + +Note on legacy bindings: One can find, in not-updated device trees, +bindings slightly different than described above with other properties +described below as well as the partitions node at the root of a so +called "nand" node (without clear controller/chip separation). + +Legacy properties: +- marvell,nand-enable-arbiter: To enable the arbiter, all boards blindly + used it, this bit was set by the bootloader for many boards and even if + it is marked reserved in several datasheets, it might be needed to set + it (otherwise it is harmless) so whether or not this property is set, + the bit is selected by the driver. +- num-cs: Number of chip-select lines to use, all boards blindly set 1 + to this and for a reason, other values would have failed. The value of + this property is ignored. + +Example: + + nand0: nand@43100000 { + compatible = "marvell,pxa3xx-nand"; + reg = <0x43100000 90>; + interrupts = <45>; + dmas = <&pdma 97 0>; + dma-names = "rxtx"; + #address-cells = <1>; + marvell,nand-keep-config; + marvell,nand-enable-arbiter; + num-cs = <1>; + /* Partitions (optional) */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/microchip,mchp23k256.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/microchip,mchp23k256.txt new file mode 100644 index 0000000000000000000000000000000000000000..7328eb92a03c323049713354545e88861387dd57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/microchip,mchp23k256.txt @@ -0,0 +1,18 @@ +* MTD SPI driver for Microchip 23K256 (and similar) serial SRAM + +Required properties: +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. +- compatible : Must be one of "microchip,mchp23k256" or "microchip,mchp23lcv1024" +- reg : Chip-Select number +- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at + +Example: + + spi-sram@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "microchip,mchp23k256"; + reg = <0>; + spi-max-frequency = <20000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/mtd-physmap.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/mtd-physmap.txt new file mode 100644 index 0000000000000000000000000000000000000000..232fa12e90efa59082ad5cb3c66640fc148d9976 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/mtd-physmap.txt @@ -0,0 +1,96 @@ +CFI or JEDEC memory-mapped NOR flash, MTD-RAM (NVRAM...) + +Flash chips (Memory Technology Devices) are often used for solid state +file systems on embedded devices. + + - compatible : should contain the specific model of mtd chip(s) + used, if known, followed by either "cfi-flash", "jedec-flash", + "mtd-ram" or "mtd-rom". + - reg : Address range(s) of the mtd chip(s) + It's possible to (optionally) define multiple "reg" tuples so that + non-identical chips can be described in one node. + - bank-width : Width (in bytes) of the bank. Equal to the + device width times the number of interleaved chips. + - device-width : (optional) Width of a single mtd chip. If + omitted, assumed to be equal to 'bank-width'. + - #address-cells, #size-cells : Must be present if the device has + sub-nodes representing partitions (see below). In this case + both #address-cells and #size-cells must be equal to 1. + - no-unaligned-direct-access: boolean to disable the default direct + mapping of the flash. + On some platforms (e.g. MPC5200) a direct 1:1 mapping may cause + problems with JFFS2 usage, as the local bus (LPB) doesn't support + unaligned accesses as implemented in the JFFS2 code via memcpy(). + By defining "no-unaligned-direct-access", the flash will not be + exposed directly to the MTD users (e.g. JFFS2) any more. + - linux,mtd-name: allow to specify the mtd name for retro capability with + physmap-flash drivers as boot loader pass the mtd partition via the old + device name physmap-flash. + - use-advanced-sector-protection: boolean to enable support for the + advanced sector protection (Spansion: PPB - Persistent Protection + Bits) locking. + +For JEDEC compatible devices, the following additional properties +are defined: + + - vendor-id : Contains the flash chip's vendor id (1 byte). + - device-id : Contains the flash chip's device id (1 byte). + +For ROM compatible devices (and ROM fallback from cfi-flash), the following +additional (optional) property is defined: + + - erase-size : The chip's physical erase block size in bytes. + + The device tree may optionally contain endianness property. + little-endian or big-endian : It Represents the endianness that should be used + by the controller to properly read/write data + from/to the flash. If this property is missing, + the endianness is chosen by the system + (potentially based on extra configuration options). + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + + flash@ff000000 { + compatible = "amd,am29lv128ml", "cfi-flash"; + reg = ; + bank-width = <4>; + device-width = <1>; + #address-cells = <1>; + #size-cells = <1>; + fs@0 { + label = "fs"; + reg = <0 f80000>; + }; + firmware@f80000 { + label ="firmware"; + reg = ; + read-only; + }; + }; + +Here an example with multiple "reg" tuples: + + flash@f0000000,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "intel,PC48F4400P0VB", "cfi-flash"; + reg = <0 0x00000000 0x02000000 + 0 0x02000000 0x02000000>; + bank-width = <2>; + partition@0 { + label = "test-part1"; + reg = <0 0x04000000>; + }; + }; + +An example using SRAM: + + sram@2,0 { + compatible = "samsung,k6f1616u6a", "mtd-ram"; + reg = <2 0 0x00200000>; + bank-width = <2>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/mtk-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/mtk-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d3ec5e4ff8a313d7e359e1d119e70dbf3643d8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/mtk-nand.txt @@ -0,0 +1,176 @@ +MTK SoCs NAND FLASH controller (NFC) DT binding + +This file documents the device tree bindings for MTK SoCs NAND controllers. +The functional split of the controller requires two drivers to operate: +the nand controller interface driver and the ECC engine driver. + +The hardware description for both devices must be captured as device +tree nodes. + +1) NFC NAND Controller Interface (NFI): +======================================= + +The first part of NFC is NAND Controller Interface (NFI) HW. +Required NFI properties: +- compatible: Should be one of + "mediatek,mt2701-nfc", + "mediatek,mt2712-nfc", + "mediatek,mt7622-nfc". +- reg: Base physical address and size of NFI. +- interrupts: Interrupts of NFI. +- clocks: NFI required clocks. +- clock-names: NFI clocks internal name. +- ecc-engine: Required ECC Engine node. +- #address-cells: NAND chip index, should be 1. +- #size-cells: Should be 0. + +Example: + + nandc: nfi@1100d000 { + compatible = "mediatek,mt2701-nfc"; + reg = <0 0x1100d000 0 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_NFI>, + <&pericfg CLK_PERI_NFI_PAD>; + clock-names = "nfi_clk", "pad_clk"; + ecc-engine = <&bch>; + #address-cells = <1>; + #size-cells = <0>; + }; + +Platform related properties, should be set in {platform_name}.dts: +- children nodes: NAND chips. + +Children nodes properties: +- reg: Chip Select Signal, default 0. + Set as reg = <0>, <1> when need 2 CS. +Optional: +- nand-on-flash-bbt: Store BBT on NAND Flash. +- nand-ecc-mode: the NAND ecc mode (check driver for supported modes) +- nand-ecc-step-size: Number of data bytes covered by a single ECC step. + valid values: + 512 and 1024 on mt2701 and mt2712. + 512 only on mt7622. + 1024 is recommended for large page NANDs. +- nand-ecc-strength: Number of bits to correct per ECC step. + The valid values that each controller supports: + mt2701: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60. + mt2712: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, + 32, 36, 40, 44, 48, 52, 56, 60, 68, 72, 80. + mt7622: 4, 6, 8, 10, 12, 14, 16. + The strength should be calculated as follows: + E = (S - F) * 8 / B + S = O / (P / Q) + E : nand-ecc-strength. + S : spare size per sector. + F : FDM size, should be in the range [1,8]. + It is used to store free oob data. + O : oob size. + P : page size. + Q : nand-ecc-step-size. + B : number of parity bits needed to correct + 1 bitflip. + According to MTK NAND controller design, + this number depends on max ecc step size + that MTK NAND controller supports. + If max ecc step size supported is 1024, + then it should be always 14. And if max + ecc step size is 512, then it should be + always 13. + If the result does not match any one of the listed + choices above, please select the smaller valid value from + the list. + (otherwise the driver will do the adjustment at runtime) +- pinctrl-names: Default NAND pin GPIO setting name. +- pinctrl-0: GPIO setting node. + +Example: + &pio { + nand_pins_default: nanddefault { + pins_dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + drive-strength = ; + bias-pull-up; + }; + + pins_we { + pinmux = ; + drive-strength = ; + bias-pull-up = ; + }; + + pins_ale { + pinmux = ; + drive-strength = ; + bias-pull-down = ; + }; + }; + }; + + &nandc { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins_default>; + nand@0 { + reg = <0>; + nand-on-flash-bbt; + nand-ecc-mode = "hw"; + nand-ecc-strength = <24>; + nand-ecc-step-size = <1024>; + }; + }; + +NAND chip optional subnodes: +- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt + +Example: + nand@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + preloader@0 { + label = "pl"; + read-only; + reg = <0x00000000 0x00400000>; + }; + android@00400000 { + label = "android"; + reg = <0x00400000 0x12c00000>; + }; + }; + }; + +2) ECC Engine: +============== + +Required BCH properties: +- compatible: Should be one of + "mediatek,mt2701-ecc", + "mediatek,mt2712-ecc", + "mediatek,mt7622-ecc". +- reg: Base physical address and size of ECC. +- interrupts: Interrupts of ECC. +- clocks: ECC required clocks. +- clock-names: ECC clocks internal name. + +Example: + + bch: ecc@1100e000 { + compatible = "mediatek,mt2701-ecc"; + reg = <0 0x1100e000 0 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_NFI_ECC>; + clock-names = "nfiecc_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/mtk-quadspi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/mtk-quadspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..56d3668e2c50e808fca1274436d151951f4ee6a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/mtk-quadspi.txt @@ -0,0 +1,49 @@ +* Serial NOR flash controller for MTK MT81xx (and similar) + +Required properties: +- compatible: For mt8173, compatible should be "mediatek,mt8173-nor", + and it's the fallback compatible for other Soc. + For every other SoC, should contain both the SoC-specific compatible + string and "mediatek,mt8173-nor". + The possible values are: + "mediatek,mt2701-nor", "mediatek,mt8173-nor" + "mediatek,mt2712-nor", "mediatek,mt8173-nor" + "mediatek,mt7622-nor", "mediatek,mt8173-nor" + "mediatek,mt7623-nor", "mediatek,mt8173-nor" + "mediatek,mt8173-nor" +- reg: physical base address and length of the controller's register +- clocks: the phandle of the clocks needed by the nor controller +- clock-names: the names of the clocks + the clocks should be named "spi" and "sf". "spi" is used for spi bus, + and "sf" is used for controller, these are the clocks witch + hardware needs to enabling nor flash and nor flash controller. + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- #address-cells: should be <1> +- #size-cells: should be <0> + +The SPI flash must be a child of the nor_flash node and must have a +compatible property. Also see jedec,spi-nor.txt. + +Required properties: +- compatible: May include a device-specific string consisting of the manufacturer + and name of the chip. Must also include "jedec,spi-nor" for any + SPI NOR flash that can be identified by the JEDEC READ ID opcode (0x9F). +- reg : Chip-Select number + +Example: + +nor_flash: spi@1100d000 { + compatible = "mediatek,mt8173-nor"; + reg = <0 0x1100d000 0 0xe0>; + clocks = <&pericfg CLK_PERI_SPI>, + <&topckgen CLK_TOP_SPINFI_IFR_SEL>; + clock-names = "spi", "sf"; + #address-cells = <1>; + #size-cells = <0>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/mxc-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/mxc-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5833d11c7be0e73f215165f61ef676a4d39f8a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/mxc-nand.txt @@ -0,0 +1,19 @@ +* Freescale's mxc_nand + +Required properties: +- compatible: "fsl,imxXX-nand" +- reg: address range of the nfc block +- interrupts: irq to be used +- nand-bus-width: see nand.txt +- nand-ecc-mode: see nand.txt +- nand-on-flash-bbt: see nand.txt + +Example: + + nand@d8000000 { + compatible = "fsl,imx27-nand"; + reg = <0xd8000000 0x1000>; + interrupts = <29>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..e949c778e9837e4a0963c005371463294823dc72 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/nand.txt @@ -0,0 +1,75 @@ +* NAND chip and NAND controller generic binding + +NAND controller/NAND chip representation: + +The NAND controller should be represented with its own DT node, and all +NAND chips attached to this controller should be defined as children nodes +of the NAND controller. This representation should be enforced even for +simple controllers supporting only one chip. + +Mandatory NAND controller properties: +- #address-cells: depends on your controller. Should at least be 1 to + encode the CS line id. +- #size-cells: depends on your controller. Put zero unless you need a + mapping between CS lines and dedicated memory regions + +Optional NAND controller properties +- ranges: only needed if you need to define a mapping between CS lines and + memory regions + +Optional NAND chip properties: + +- nand-ecc-mode : String, operation mode of the NAND ecc mode. + Supported values are: "none", "soft", "hw", "hw_syndrome", + "hw_oob_first", "on-die". + Deprecated values: + "soft_bch": use "soft" and nand-ecc-algo instead +- nand-ecc-algo: string, algorithm of NAND ECC. + Valid values are: "hamming", "bch", "rs". +- nand-bus-width : 8 or 16 bus width if not present 8 +- nand-on-flash-bbt: boolean to enable on flash bbt option if not present false + +- nand-ecc-strength: integer representing the number of bits to correct + per ECC step. + +- nand-ecc-step-size: integer representing the number of data bytes + that are covered by a single ECC step. + +- nand-ecc-maximize: boolean used to specify that you want to maximize ECC + strength. The maximum ECC strength is both controller and + chip dependent. The controller side has to select the ECC + config providing the best strength and taking the OOB area + size constraint into account. + This is particularly useful when only the in-band area is + used by the upper layers, and you want to make your NAND + as reliable as possible. +- nand-is-boot-medium: Whether the NAND chip is a boot medium. Drivers might use + this information to select ECC algorithms supported by + the boot ROM or similar restrictions. + +- nand-rb: shall contain the native Ready/Busy ids. + +The ECC strength and ECC step size properties define the correction capability +of a controller. Together, they say a controller can correct "{strength} bit +errors per {size} bytes". + +The interpretation of these parameters is implementation-defined, so not all +implementations must support all possible combinations. However, implementations +are encouraged to further specify the value(s) they support. + +Example: + + nand-controller { + #address-cells = <1>; + #size-cells = <0>; + + /* controller specific properties */ + + nand@0 { + reg = <0>; + nand-ecc-mode = "soft"; + nand-ecc-algo = "bch"; + + /* controller specific properties */ + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/nvidia-tegra20-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/nvidia-tegra20-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2f2ca12f9e64bb152f6f175719e355275067ced --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/nvidia-tegra20-nand.txt @@ -0,0 +1,64 @@ +NVIDIA Tegra NAND Flash controller + +Required properties: +- compatible: Must be one of: + - "nvidia,tegra20-nand" +- reg: MMIO address range +- interrupts: interrupt output of the NFC controller +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - nand +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - nand + +Optional children nodes: +Individual NAND chips are children of the NAND controller node. Currently +only one NAND chip supported. + +Required children node properties: +- reg: An integer ranging from 1 to 6 representing the CS line to use. + +Optional children node properties: +- nand-ecc-mode: String, operation mode of the NAND ecc mode. Currently only + "hw" is supported. +- nand-ecc-algo: string, algorithm of NAND ECC. + Supported values with "hw" ECC mode are: "rs", "bch". +- nand-bus-width : See nand.txt +- nand-on-flash-bbt: See nand.txt +- nand-ecc-strength: integer representing the number of bits to correct + per ECC step (always 512). Supported strength using HW ECC + modes are: + - RS: 4, 6, 8 + - BCH: 4, 8, 14, 16 +- nand-ecc-maximize: See nand.txt +- nand-is-boot-medium: Makes sure only ECC strengths supported by the boot ROM + are chosen. +- wp-gpios: GPIO specifier for the write protect pin. + +Optional child node of NAND chip nodes: +Partitions: see partition.txt + + Example: + nand-controller@70008000 { + compatible = "nvidia,tegra20-nand"; + reg = <0x70008000 0x100>; + interrupts = ; + clocks = <&tegra_car TEGRA20_CLK_NDFLASH>; + clock-names = "nand"; + resets = <&tegra_car 13>; + reset-names = "nand"; + + nand@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + nand-bus-width = <8>; + nand-on-flash-bbt; + nand-ecc-algo = "bch"; + nand-ecc-strength = <8>; + wp-gpios = <&gpio TEGRA_GPIO(S, 0) GPIO_ACTIVE_LOW>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/nxp-spifi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/nxp-spifi.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8b6b250654e53754b096484eb219d4a0c685bbd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/nxp-spifi.txt @@ -0,0 +1,58 @@ +* NXP SPI Flash Interface (SPIFI) + +NXP SPIFI is a specialized SPI interface for serial Flash devices. +It supports one Flash device with 1-, 2- and 4-bits width in SPI +mode 0 or 3. The controller operates in either command or memory +mode. In memory mode the Flash is accessible from the CPU as +normal memory. + +Required properties: + - compatible : Should be "nxp,lpc1773-spifi" + - reg : the first contains the register location and length, + the second contains the memory mapping address and length + - reg-names: Should contain the reg names "spifi" and "flash" + - interrupts : Should contain the interrupt for the device + - clocks : The clocks needed by the SPIFI controller + - clock-names : Should contain the clock names "spifi" and "reg" + +Optional properties: + - resets : phandle + reset specifier + +The SPI Flash must be a child of the SPIFI node and must have a +compatible property as specified in bindings/mtd/jedec,spi-nor.txt + +Optionally it can also contain the following properties. + - spi-cpol : Controller only supports mode 0 and 3 so either + both spi-cpol and spi-cpha should be present or + none of them + - spi-cpha : See above + - spi-rx-bus-width : Used to select how many pins that are used + for input on the controller + +See bindings/spi/spi-bus.txt for more information. + +Example: +spifi: spifi@40003000 { + compatible = "nxp,lpc1773-spifi"; + reg = <0x40003000 0x1000>, <0x14000000 0x4000000>; + reg-names = "spifi", "flash"; + interrupts = <30>; + clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>; + clock-names = "spifi", "reg"; + resets = <&rgu 53>; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-cpol; + spi-cpha; + spi-rx-bus-width = <4>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "data"; + reg = <0 0x200000>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/orion-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/orion-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d6ab660e6032a3c4147d2e22ab2f33e417d1155 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/orion-nand.txt @@ -0,0 +1,50 @@ +NAND support for Marvell Orion SoC platforms + +Required properties: +- compatible : "marvell,orion-nand". +- reg : Base physical address of the NAND and length of memory mapped + region + +Optional properties: +- cle : Address line number connected to CLE. Default is 0 +- ale : Address line number connected to ALE. Default is 1 +- bank-width : Width in bytes of the device. Default is 1 +- chip-delay : Chip dependent delay for transferring data from array to read + registers in usecs + +The device tree may optionally contain sub-nodes describing partitions of the +address space. See partition.txt for more detail. + +Example: + +nand@f4000000 { + #address-cells = <1>; + #size-cells = <1>; + cle = <0>; + ale = <1>; + bank-width = <1>; + chip-delay = <25>; + compatible = "marvell,orion-nand"; + reg = <0xf4000000 0x400>; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@100000 { + label = "uImage"; + reg = <0x0100000 0x200000>; + }; + + partition@300000 { + label = "dtb"; + reg = <0x0300000 0x100000>; + }; + + partition@400000 { + label = "root"; + reg = <0x0400000 0x7d00000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/oxnas-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/oxnas-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..56d5c19da41d804f2931374fb94859835fc57328 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/oxnas-nand.txt @@ -0,0 +1,41 @@ +* Oxford Semiconductor OXNAS NAND Controller + +Please refer to nand.txt for generic information regarding MTD NAND bindings. + +Required properties: + - compatible: "oxsemi,ox820-nand" + - reg: Base address and length for NAND mapped memory. + +Optional Properties: + - clocks: phandle to the NAND gate clock if needed. + - resets: phandle to the NAND reset control if needed. + +Example: + +nandc: nand-controller@41000000 { + compatible = "oxsemi,ox820-nand"; + reg = <0x41000000 0x100000>; + clocks = <&stdclk CLK_820_NAND>; + resets = <&reset RESET_NAND>; + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + nand-ecc-mode = "soft"; + nand-ecc-algo = "hamming"; + + partition@0 { + label = "boot"; + reg = <0x00000000 0x00e00000>; + read-only; + }; + + partition@e00000 { + label = "ubi"; + reg = <0x00e00000 0x07200000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/partition.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/partition.txt new file mode 100644 index 0000000000000000000000000000000000000000..afbbd870496de54417b67473eb4fbb4adc3859ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/partition.txt @@ -0,0 +1,157 @@ +Flash partitions in device tree +=============================== + +Flash devices can be partitioned into one or more functional ranges (e.g. "boot +code", "nvram", "kernel"). + +Different devices may be partitioned in a different ways. Some may use a fixed +flash layout set at production time. Some may use on-flash table that describes +the geometry and naming/purpose of each functional region. It is also possible +to see these methods mixed. + +To assist system software in locating partitions, we allow describing which +method is used for a given flash device. To describe the method there should be +a subnode of the flash device that is named 'partitions'. It must have a +'compatible' property, which is used to identify the method to use. + +When a single partition is represented with a DT node (it depends on a used +format) it may also be described using above rules ('compatible' and optionally +some extra properties / subnodes). It allows describing more complex, +hierarchical (multi-level) layouts and should be used if there is some +significant relation between partitions or some partition internally uses +another partitioning method. + +Available bindings are listed in the "partitions" subdirectory. + + +Fixed Partitions +================ + +Partitions can be represented by sub-nodes of a flash device. This can be used +on platforms which have strong conventions about which portions of a flash are +used for what purposes, but which don't use an on-flash partition table such +as RedBoot. + +The partition table should be a subnode of the flash node and should be named +'partitions'. This node should have the following property: +- compatible : (required) must be "fixed-partitions" +Partitions are then defined in subnodes of the partitions node. + +For backwards compatibility partitions as direct subnodes of the flash device are +supported. This use is discouraged. +NOTE: also for backwards compatibility, direct subnodes that have a compatible +string are not considered partitions, as they may be used for other bindings. + +#address-cells & #size-cells must both be present in the partitions subnode of the +flash device. There are two valid values for both: +<1>: for partitions that require a single 32-bit cell to represent their + size/address (aka the value is below 4 GiB) +<2>: for partitions that require two 32-bit cells to represent their + size/address (aka the value is 4 GiB or greater). + +Required properties: +- reg : The partition's offset and size within the flash + +Optional properties: +- label : The label / name for this partition. If omitted, the label is taken + from the node name (excluding the unit address). +- read-only : This parameter, if present, is a hint to Linux that this + partition should only be mounted read-only. This is usually used for flash + partitions containing early-boot firmware images or data which should not be + clobbered. +- lock : Do not unlock the partition at initialization time (not supported on + all devices) + +Examples: + + +flash@0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + uimage@100000 { + reg = <0x0100000 0x200000>; + }; + }; +}; + +flash@1 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <2>; + + /* a 4 GiB partition */ + partition@0 { + label = "filesystem"; + reg = <0x00000000 0x1 0x00000000>; + }; + }; +}; + +flash@2 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <2>; + #size-cells = <2>; + + /* an 8 GiB partition */ + partition@0 { + label = "filesystem #1"; + reg = <0x0 0x00000000 0x2 0x00000000>; + }; + + /* a 4 GiB partition */ + partition@200000000 { + label = "filesystem #2"; + reg = <0x2 0x00000000 0x1 0x00000000>; + }; + }; +}; + +flash@3 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x000000 0x100000>; + read-only; + }; + + firmware@100000 { + label = "firmware"; + reg = <0x100000 0xe00000>; + compatible = "brcm,trx"; + }; + + calibration@f00000 { + label = "calibration"; + reg = <0xf00000 0x100000>; + compatible = "fixed-partitions"; + ranges = <0 0xf00000 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "wifi0"; + reg = <0x000000 0x080000>; + }; + + partition@80000 { + label = "wifi1"; + reg = <0x080000 0x080000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d61a029395e76eac9b5cd90da7b44f63c514c17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/partitions/brcm,bcm947xx-cfe-partitions.txt @@ -0,0 +1,42 @@ +Broadcom BCM47xx Partitions +=========================== + +Broadcom is one of hardware manufacturers providing SoCs (BCM47xx) used in +home routers. Their BCM947xx boards using CFE bootloader have several partitions +without any on-flash partition table. On some devices their sizes and/or +meanings can also vary so fixed partitioning can't be used. + +Discovering partitions on these devices is possible thanks to having a special +header and/or magic signature at the beginning of each of them. They are also +block aligned which is important for determinig a size. + +Most of partitions use ASCII text based magic for determining a type. More +complex partitions (like TRX with its HDR0 magic) may include extra header +containing some details, including a length. + +A list of supported partitions includes: +1) Bootloader with Broadcom's CFE (Common Firmware Environment) +2) NVRAM with configuration/calibration data +3) Device manufacturer's data with some default values (e.g. SSIDs) +4) TRX firmware container which can hold up to 4 subpartitions +5) Backup TRX firmware used after failed upgrade + +As mentioned earlier, role of some partitions may depend on extra configuration. +For example both: main firmware and backup firmware use the same TRX format with +the same header. To distinguish currently used firmware a CFE's environment +variable "bootpartition" is used. + + +Devices using Broadcom partitions described above should should have flash node +with a subnode named "partitions" using following properties: + +Required properties: +- compatible : (required) must be "brcm,bcm947xx-cfe-partitions" + +Example: + +flash@0 { + partitions { + compatible = "brcm,bcm947xx-cfe-partitions"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/partitions/brcm,trx.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/partitions/brcm,trx.txt new file mode 100644 index 0000000000000000000000000000000000000000..b677147ca4e10843ae68c8629a5bf2cd4aa7c961 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/partitions/brcm,trx.txt @@ -0,0 +1,37 @@ +Broadcom TRX Container Partition +================================ + +TRX is Broadcom's official firmware format for the BCM947xx boards. It's used by +most of the vendors building devices based on Broadcom's BCM47xx SoCs and is +supported by the CFE bootloader. + +Design of the TRX format is very minimalistic. Its header contains +identification fields, CRC32 checksum and the locations of embedded partitions. +Its purpose is to store a few partitions in a format that can be distributed as +a standalone file and written in a flash memory. + +Container can hold up to 4 partitions. The first partition has to contain a +device executable binary (e.g. a kernel) as it's what the CFE bootloader starts +executing. Other partitions can be used for operating system purposes. This is +useful for systems that keep kernel and rootfs separated. + +TRX doesn't enforce any strict partition boundaries or size limits. All +partitions have to be less than the 4GiB max size limit. + +There are two existing/known TRX variants: +1) v1 which contains 3 partitions +2) v2 which contains 4 partitions + +There aren't separated compatible bindings for them as version can be trivialy +detected by a software parsing TRX header. + +Required properties: +- compatible : (required) must be "brcm,trx" + +Example: + +flash@0 { + partitions { + compatible = "brcm,trx"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/qcom_nandc.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/qcom_nandc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1123cc6d56ef3d52bfa9dd455b1981600872dfc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/qcom_nandc.txt @@ -0,0 +1,138 @@ +* Qualcomm NAND controller + +Required properties: +- compatible: must be one of the following: + * "qcom,ipq806x-nand" - for EBI2 NAND controller being used in IPQ806x + SoC and it uses ADM DMA + * "qcom,ipq4019-nand" - for QPIC NAND controller v1.4.0 being used in + IPQ4019 SoC and it uses BAM DMA + * "qcom,ipq8074-nand" - for QPIC NAND controller v1.5.0 being used in + IPQ8074 SoC and it uses BAM DMA + +- reg: MMIO address range +- clocks: must contain core clock and always on clock +- clock-names: must contain "core" for the core clock and "aon" for the + always on clock + +EBI2 specific properties: +- dmas: DMA specifier, consisting of a phandle to the ADM DMA + controller node and the channel number to be used for + NAND. Refer to dma.txt and qcom_adm.txt for more details +- dma-names: must be "rxtx" +- qcom,cmd-crci: must contain the ADM command type CRCI block instance + number specified for the NAND controller on the given + platform +- qcom,data-crci: must contain the ADM data type CRCI block instance + number specified for the NAND controller on the given + platform + +QPIC specific properties: +- dmas: DMA specifier, consisting of a phandle to the BAM DMA + and the channel number to be used for NAND. Refer to + dma.txt, qcom_bam_dma.txt for more details +- dma-names: must contain all 3 channel names : "tx", "rx", "cmd" +- #address-cells: <1> - subnodes give the chip-select number +- #size-cells: <0> + +* NAND chip-select + +Each controller may contain one or more subnodes to represent enabled +chip-selects which (may) contain NAND flash chips. Their properties are as +follows. + +Required properties: +- reg: a single integer representing the chip-select + number (e.g., 0, 1, 2, etc.) +- #address-cells: see partition.txt +- #size-cells: see partition.txt + +Optional properties: +- nand-bus-width: see nand.txt +- nand-ecc-strength: see nand.txt. If not specified, then ECC strength will + be used according to chip requirement and available + OOB size. + +Each nandcs device node may optionally contain a 'partitions' sub-node, which +further contains sub-nodes describing the flash partition mapping. See +partition.txt for more detail. + +Example: + +nand-controller@1ac00000 { + compatible = "qcom,ipq806x-nand"; + reg = <0x1ac00000 0x800>; + + clocks = <&gcc EBI2_CLK>, + <&gcc EBI2_AON_CLK>; + clock-names = "core", "aon"; + + dmas = <&adm_dma 3>; + dma-names = "rxtx"; + qcom,cmd-crci = <15>; + qcom,data-crci = <3>; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; + + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; + }; +}; + +nand-controller@79b0000 { + compatible = "qcom,ipq4019-nand"; + reg = <0x79b0000 0x1000>; + + clocks = <&gcc GCC_QPIC_CLK>, + <&gcc GCC_QPIC_AHB_CLK>; + clock-names = "core", "aon"; + + dmas = <&qpicbam 0>, + <&qpicbam 1>, + <&qpicbam 2>; + dma-names = "tx", "rx", "cmd"; + + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + nand-ecc-strength = <4>; + nand-bus-width = <8>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "boot-nand"; + reg = <0 0x58a0000>; + }; + + partition@58a0000 { + label = "fs-nand"; + reg = <0x58a0000 0x4000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/samsung-s3c2410.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/samsung-s3c2410.txt new file mode 100644 index 0000000000000000000000000000000000000000..0040eb8895e094c51803d6582809fb7ebf8781dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/samsung-s3c2410.txt @@ -0,0 +1,56 @@ +* Samsung S3C2410 and compatible NAND flash controller + +Required properties: +- compatible : The possible values are: + "samsung,s3c2410-nand" + "samsung,s3c2412-nand" + "samsung,s3c2440-nand" +- reg : register's location and length. +- #address-cells, #size-cells : see nand.txt +- clocks : phandle to the nand controller clock +- clock-names : must contain "nand" + +Optional child nodes: +Child nodes representing the available nand chips. + +Optional child properties: +- nand-ecc-mode : see nand.txt +- nand-on-flash-bbt : see nand.txt + +Each child device node may optionally contain a 'partitions' sub-node, +which further contains sub-nodes describing the flash partition mapping. +See partition.txt for more detail. + +Example: + +nand-controller@4e000000 { + compatible = "samsung,s3c2440-nand"; + reg = <0x4e000000 0x40>; + + #address-cells = <1>; + #size-cells = <0>; + + clocks = <&clocks HCLK_NAND>; + clock-names = "nand"; + + nand { + nand-ecc-mode = "soft"; + nand-on-flash-bbt; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0 0x040000>; + }; + + partition@40000 { + label = "kernel"; + reg = <0x040000 0x500000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/spear_smi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/spear_smi.txt new file mode 100644 index 0000000000000000000000000000000000000000..c41873e92d264b0fc9812a5805fa29d4491cc3b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/spear_smi.txt @@ -0,0 +1,29 @@ +* SPEAr SMI + +Required properties: +- compatible : "st,spear600-smi" +- reg : Address range of the mtd chip +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. +- interrupts: Should contain the STMMAC interrupts +- clock-rate : Functional clock rate of SMI in Hz + +Optional properties: +- st,smi-fast-mode : Flash supports read in fast mode + +Example: + + smi: flash@fc000000 { + compatible = "st,spear600-smi"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xfc000000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + clock-rate = <50000000>; /* 50MHz */ + + flash@f8000000 { + st,smi-fast-mode; + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/spi-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/spi-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b51f3b6d55cfe2a050891242c01ac175e11a5af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/spi-nand.txt @@ -0,0 +1,5 @@ +SPI NAND flash + +Required properties: +- compatible: should be "spi-nand" +- reg: should encode the chip-select line used to access the NAND chip diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/st-fsm.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/st-fsm.txt new file mode 100644 index 0000000000000000000000000000000000000000..54cef9ef3083d90689b69d5ec5ffbd591a0e3ba1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/st-fsm.txt @@ -0,0 +1,25 @@ +* ST-Microelectronics SPI FSM Serial (NOR) Flash Controller + +Required properties: + - compatible : Should be "st,spi-fsm" + - reg : Contains register's location and length. + - reg-names : Should contain the reg names "spi-fsm" + - interrupts : The interrupt number + - pinctrl-0 : Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt) + +Optional properties: + - st,syscfg : Phandle to boot-device system configuration registers + - st,boot-device-reg : Address of the aforementioned boot-device register(s) + - st,boot-device-spi : Expected boot-device value if booted via this device + +Example: + spifsm: spifsm@fe902000{ + compatible = "st,spi-fsm"; + reg = <0xfe902000 0x1000>; + reg-names = "spi-fsm"; + pinctrl-0 = <&pinctrl_fsm>; + st,syscfg = <&syscfg_rear>; + st,boot-device-reg = <0x958>; + st,boot-device-spi = <0x1a>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/stm32-quadspi.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/stm32-quadspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..ddd18c1351486d579606123aa900683848c29e65 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/stm32-quadspi.txt @@ -0,0 +1,43 @@ +* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI) + +Required properties: +- compatible: should be "st,stm32f469-qspi" +- reg: the first contains the register location and length. + the second contains the memory mapping address and length +- reg-names: should contain the reg names "qspi" "qspi_mm" +- interrupts: should contain the interrupt for the device +- clocks: the phandle of the clock needed by the QSPI controller +- A pinctrl must be defined to set pins in mode of operation for QSPI transfer + +Optional properties: +- resets: must contain the phandle to the reset controller. + +A spi flash must be a child of the nor_flash node and could have some +properties. Also see jedec,spi-nor.txt. + +Required properties: +- reg: chip-Select number (QSPI controller may connect 2 nor flashes) +- spi-max-frequency: max frequency of spi bus + +Optional property: +- spi-rx-bus-width: see ../spi/spi-bus.txt for the description + +Example: + +qspi: spi@a0001000 { + compatible = "st,stm32f469-qspi"; + reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>; + reg-names = "qspi", "qspi_mm"; + interrupts = <91>; + resets = <&rcc STM32F4_AHB3_RESET(QSPI)>; + clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi0>; + + flash@0 { + reg = <0>; + spi-rx-bus-width = <4>; + spi-max-frequency = <108000000>; + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/sunxi-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/sunxi-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcd5a5d80dc0ad535298f58d492607507752c02b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/sunxi-nand.txt @@ -0,0 +1,48 @@ +Allwinner NAND Flash Controller (NFC) + +Required properties: +- compatible : "allwinner,sun4i-a10-nand". +- reg : shall contain registers location and length for data and reg. +- interrupts : shall define the nand controller interrupt. +- #address-cells: shall be set to 1. Encode the nand CS. +- #size-cells : shall be set to 0. +- clocks : shall reference nand controller clocks. +- clock-names : nand controller internal clock names. Shall contain : + * "ahb" : AHB gating clock + * "mod" : nand controller clock + +Optional properties: +- dmas : shall reference DMA channel associated to the NAND controller. +- dma-names : shall be "rxtx". + +Optional children nodes: +Children nodes represent the available nand chips. + +Optional properties: +- reset : phandle + reset specifier pair +- reset-names : must contain "ahb" +- allwinner,rb : shall contain the native Ready/Busy ids. +- nand-ecc-mode : one of the supported ECC modes ("hw", "soft", "soft_bch" or + "none") + +see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings. + + +Examples: +nfc: nand@1c03000 { + compatible = "allwinner,sun4i-a10-nand"; + reg = <0x01c03000 0x1000>; + interrupts = <0 37 1>; + clocks = <&ahb_gates 13>, <&nand_clk>; + clock-names = "ahb", "mod"; + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>; + + nand@0 { + reg = <0>; + allwinner,rb = <0>; + nand-ecc-mode = "soft_bch"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/tango-nand.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/tango-nand.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd1bf2ac9055fc3561dbf6da805c8aa5ca3ea49c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/tango-nand.txt @@ -0,0 +1,38 @@ +Sigma Designs Tango4 NAND Flash Controller (NFC) + +Required properties: + +- compatible: "sigma,smp8758-nand" +- reg: address/size of nfc_reg, nfc_mem, and pbus_reg +- dmas: reference to the DMA channel used by the controller +- dma-names: "rxtx" +- clocks: reference to the system clock +- #address-cells: <1> +- #size-cells: <0> + +Children nodes represent the available NAND chips. +See Documentation/devicetree/bindings/mtd/nand.txt for generic bindings. + +Example: + + nandc: nand-controller@2c000 { + compatible = "sigma,smp8758-nand"; + reg = <0x2c000 0x30>, <0x2d000 0x800>, <0x20000 0x1000>; + dmas = <&dma0 3>; + dma-names = "rxtx"; + clocks = <&clkgen SYS_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; /* CS0 */ + nand-ecc-strength = <14>; + nand-ecc-step-size = <1024>; + }; + + nand@1 { + reg = <1>; /* CS1 */ + nand-ecc-strength = <14>; + nand-ecc-step-size = <1024>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mtd/vf610-nfc.txt b/arch/arm64/boot/dts/vendor/bindings/mtd/vf610-nfc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c96eeb65f4500fae46debf9fab9b31b8809c3223 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mtd/vf610-nfc.txt @@ -0,0 +1,59 @@ +Freescale's NAND flash controller (NFC) + +This variant of the Freescale NAND flash controller (NFC) can be found on +Vybrid (vf610), MPC5125, MCF54418 and Kinetis K70. + +Required properties: +- compatible: Should be set to "fsl,vf610-nfc". +- reg: address range of the NFC. +- interrupts: interrupt of the NFC. +- #address-cells: shall be set to 1. Encode the nand CS. +- #size-cells : shall be set to 0. +- assigned-clocks: main clock from the SoC, for Vybrid <&clks VF610_CLK_NFC>; +- assigned-clock-rates: The NAND bus timing is derived from this clock + rate and should not exceed maximum timing for any NAND memory chip + in a board stuffing. Typical NAND memory timings derived from this + clock are found in the SoC hardware reference manual. Furthermore, + there might be restrictions on maximum rates when using hardware ECC. + +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. + +Required children nodes: +Children nodes represent the available nand chips. Currently the driver can +only handle one NAND chip. + +Required properties: +- compatible: Should be set to "fsl,vf610-nfc-cs". +- nand-bus-width: see nand.txt +- nand-ecc-mode: see nand.txt + +Required properties for hardware ECC: +- nand-ecc-strength: supported strengths are 24 and 32 bit (see nand.txt) +- nand-ecc-step-size: step size equals page size, currently only 2k pages are + supported +- nand-on-flash-bbt: see nand.txt + +Example: + + nfc: nand@400e0000 { + compatible = "fsl,vf610-nfc"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x400e0000 0x4000>; + interrupts = ; + clocks = <&clks VF610_CLK_NFC>; + clock-names = "nfc"; + assigned-clocks = <&clks VF610_CLK_NFC>; + assigned-clock-rates = <33000000>; + + nand@0 { + compatible = "fsl,vf610-nfc-nandcs"; + reg = <0>; + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-ecc-strength = <32>; + nand-ecc-step-size = <2048>; + nand-on-flash-bbt; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mux/adi,adg792a.txt b/arch/arm64/boot/dts/vendor/bindings/mux/adi,adg792a.txt new file mode 100644 index 0000000000000000000000000000000000000000..96b787a69f500e47cf2f3bd0ea772452a7c2978b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mux/adi,adg792a.txt @@ -0,0 +1,75 @@ +Bindings for Analog Devices ADG792A/G Triple 4:1 Multiplexers + +Required properties: +- compatible : "adi,adg792a" or "adi,adg792g" +- #mux-control-cells : <0> if parallel (the three muxes are bound together + with a single mux controller controlling all three muxes), or <1> if + not (one mux controller for each mux). +* Standard mux-controller bindings as described in mux-controller.txt + +Optional properties for ADG792G: +- gpio-controller : if present, #gpio-cells below is required. +- #gpio-cells : should be <2> + - First cell is the GPO line number, i.e. 0 or 1 + - Second cell is used to specify active high (0) + or active low (1) + +Optional properties: +- idle-state : if present, array of states that the mux controllers will have + when idle. The special state MUX_IDLE_AS_IS is the default and + MUX_IDLE_DISCONNECT is also supported. + +States 0 through 3 correspond to signals A through D in the datasheet. + +Example: + + /* + * Three independent mux controllers (of which one is used). + * Mux 0 is disconnected when idle, mux 1 idles in the previously + * selected state and mux 2 idles with signal B. + */ + &i2c0 { + mux: mux-controller@50 { + compatible = "adi,adg792a"; + reg = <0x50>; + #mux-control-cells = <1>; + + idle-state = ; + }; + }; + + adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 0>; + io-channel-names = "parent"; + + mux-controls = <&mux 2>; + + channels = "sync-1", "", "out"; + }; + + + /* + * Three parallel muxes with one mux controller, useful e.g. if + * the adc is differential, thus needing two signals to be muxed + * simultaneously for correct operation. + */ + &i2c0 { + pmux: mux-controller@50 { + compatible = "adi,adg792a"; + reg = <0x50>; + #mux-control-cells = <0>; + + idle-state = <1>; + }; + }; + + diff-adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 0>; + io-channel-names = "parent"; + + mux-controls = <&pmux>; + + channels = "sync-1", "", "out"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mux/adi,adgs1408.txt b/arch/arm64/boot/dts/vendor/bindings/mux/adi,adgs1408.txt new file mode 100644 index 0000000000000000000000000000000000000000..be6947f4d86bc1f445cdba07362666f6570885d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mux/adi,adgs1408.txt @@ -0,0 +1,48 @@ +Bindings for Analog Devices ADGS1408/1409 8:1/Dual 4:1 Mux + +Required properties: +- compatible : Should be one of + * "adi,adgs1408" + * "adi,adgs1409" +* Standard mux-controller bindings as described in mux-controller.txt + +Optional properties for ADGS1408/1409: +- gpio-controller : if present, #gpio-cells is required. +- #gpio-cells : should be <2> + - First cell is the GPO line number, i.e. 0 to 3 + for ADGS1408 and 0 to 4 for ADGS1409 + - Second cell is used to specify active high (0) + or active low (1) + +Optional properties: +- idle-state : if present, the state that the mux controller will have + when idle. The special state MUX_IDLE_AS_IS is the default and + MUX_IDLE_DISCONNECT is also supported. + +States 0 through 7 correspond to signals S1 through S8 in the datasheet. +For ADGS1409 only states 0 to 3 are available. + +Example: + + /* + * One mux controller. + * Mux state set to idle as is (no idle-state declared) + */ + &spi0 { + mux: mux-controller@0 { + compatible = "adi,adgs1408"; + reg = <0>; + spi-max-frequency = <1000000>; + #mux-control-cells = <0>; + }; + } + + adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 1>; + io-channel-names = "parent"; + mux-controls = <&mux>; + + channels = "out_a0", "out_a1", "test0", "test1", + "out_b0", "out_b1", "testb0", "testb1"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mux/gpio-mux.txt b/arch/arm64/boot/dts/vendor/bindings/mux/gpio-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8f746344d801bd091e10389b46916e441453698 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mux/gpio-mux.txt @@ -0,0 +1,69 @@ +GPIO-based multiplexer controller bindings + +Define what GPIO pins are used to control a multiplexer. Or several +multiplexers, if the same pins control more than one multiplexer. + +Required properties: +- compatible : "gpio-mux" +- mux-gpios : list of gpios used to control the multiplexer, least + significant bit first. +- #mux-control-cells : <0> +* Standard mux-controller bindings as decribed in mux-controller.txt + +Optional properties: +- idle-state : if present, the state the mux will have when idle. The + special state MUX_IDLE_AS_IS is the default. + +The multiplexer state is defined as the number represented by the +multiplexer GPIO pins, where the first pin is the least significant +bit. An active pin is a binary 1, an inactive pin is a binary 0. + +Example: + + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>, + <&pioA 1 GPIO_ACTIVE_HIGH>; + }; + + adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 0>; + io-channel-names = "parent"; + + mux-controls = <&mux>; + + channels = "sync-1", "in", "out", "sync-2"; + }; + + i2c-mux { + compatible = "i2c-mux"; + i2c-parent = <&i2c1>; + + mux-controls = <&mux>; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + /* ... */ + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + /* ... */ + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mux/mmio-mux.txt b/arch/arm64/boot/dts/vendor/bindings/mux/mmio-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9bfb4d8b6ac8c7618b78a24bd7d30cff09c3656 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mux/mmio-mux.txt @@ -0,0 +1,60 @@ +MMIO register bitfield-based multiplexer controller bindings + +Define register bitfields to be used to control multiplexers. The parent +device tree node must be a syscon node to provide register access. + +Required properties: +- compatible : "mmio-mux" +- #mux-control-cells : <1> +- mux-reg-masks : an array of register offset and pre-shifted bitfield mask + pairs, each describing a single mux control. +* Standard mux-controller bindings as decribed in mux-controller.txt + +Optional properties: +- idle-states : if present, the state the muxes will have when idle. The + special state MUX_IDLE_AS_IS is the default. + +The multiplexer state of each multiplexer is defined as the value of the +bitfield described by the corresponding register offset and bitfield mask pair +in the mux-reg-masks array, accessed through the parent syscon. + +Example: + + syscon { + compatible = "syscon"; + + mux: mux-controller { + compatible = "mmio-mux"; + #mux-control-cells = <1>; + + mux-reg-masks = <0x3 0x30>, /* 0: reg 0x3, bits 5:4 */ + <0x3 0x40>, /* 1: reg 0x3, bit 6 */ + idle-states = , <0>; + }; + }; + + video-mux { + compatible = "video-mux"; + mux-controls = <&mux 0>; + + ports { + /* inputs 0..3 */ + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + }; + port@2 { + reg = <2>; + }; + port@3 { + reg = <3>; + }; + + /* output */ + port@4 { + reg = <4>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/mux/mux-controller.txt b/arch/arm64/boot/dts/vendor/bindings/mux/mux-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f47e4bd2fa05579ce00920f0c2a3da4d7fcf98f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/mux/mux-controller.txt @@ -0,0 +1,157 @@ +Common multiplexer controller bindings +====================================== + +A multiplexer (or mux) controller will have one, or several, consumer devices +that uses the mux controller. Thus, a mux controller can possibly control +several parallel multiplexers. Presumably there will be at least one +multiplexer needed by each consumer, but a single mux controller can of course +control several multiplexers for a single consumer. + +A mux controller provides a number of states to its consumers, and the state +space is a simple zero-based enumeration. I.e. 0-1 for a 2-way multiplexer, +0-7 for an 8-way multiplexer, etc. + + +Consumers +--------- + +Mux controller consumers should specify a list of mux controllers that they +want to use with a property containing a 'mux-ctrl-list': + + mux-ctrl-list ::= [mux-ctrl-list] + single-mux-ctrl ::= [mux-ctrl-specifier] + mux-ctrl-phandle : phandle to mux controller node + mux-ctrl-specifier : array of #mux-control-cells specifying the + given mux controller (controller specific) + +Mux controller properties should be named "mux-controls". The exact meaning of +each mux controller property must be documented in the device tree binding for +each consumer. An optional property "mux-control-names" may contain a list of +strings to label each of the mux controllers listed in the "mux-controls" +property. + +Drivers for devices that use more than a single mux controller can use the +"mux-control-names" property to map the name of the requested mux controller +to an index into the list given by the "mux-controls" property. + +mux-ctrl-specifier typically encodes the chip-relative mux controller number. +If the mux controller chip only provides a single mux controller, the +mux-ctrl-specifier can typically be left out. + +Example: + + /* One consumer of a 2-way mux controller (one GPIO-line) */ + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>; + }; + + adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 0>; + io-channel-names = "parent"; + + mux-controls = <&mux>; + mux-control-names = "adc"; + + channels = "sync", "in"; + }; + +Note that in the example above, specifying the "mux-control-names" is redundant +because there is only one mux controller in the list. However, if the driver +for the consumer node in fact asks for a named mux controller, that name is of +course still required. + + /* + * Two consumers (one for an ADC line and one for an i2c bus) of + * parallel 4-way multiplexers controlled by the same two GPIO-lines. + */ + mux: mux-controller { + compatible = "gpio-mux"; + #mux-control-cells = <0>; + + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>, + <&pioA 1 GPIO_ACTIVE_HIGH>; + }; + + adc-mux { + compatible = "io-channel-mux"; + io-channels = <&adc 0>; + io-channel-names = "parent"; + + mux-controls = <&mux>; + + channels = "sync-1", "in", "out", "sync-2"; + }; + + i2c-mux { + compatible = "i2c-mux"; + i2c-parent = <&i2c1>; + + mux-controls = <&mux>; + + #address-cells = <1>; + #size-cells = <0>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + ssd1307: oled@3c { + /* ... */ + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + pca9555: pca9555@20 { + /* ... */ + }; + }; + }; + + +Mux controller nodes +-------------------- + +Mux controller nodes must specify the number of cells used for the +specifier using the '#mux-control-cells' property. + +Optionally, mux controller nodes can also specify the state the mux should +have when it is idle. The idle-state property is used for this. If the +idle-state is not present, the mux controller is typically left as is when +it is idle. For multiplexer chips that expose several mux controllers, the +idle-state property is an array with one idle state for each mux controller. + +The special value (-1) may be used to indicate that the mux should be left +as is when it is idle. This is the default, but can still be useful for +mux controller chips with more than one mux controller, particularly when +there is a need to "step past" a mux controller and set some other idle +state for a mux controller with a higher index. + +Some mux controllers have the ability to disconnect the input/output of the +multiplexer. Using this disconnected high-impedance state as the idle state +is indicated with idle state (-2). + +These constants are available in + + #include + +as MUX_IDLE_AS_IS (-1) and MUX_IDLE_DISCONNECT (-2). + +An example mux controller node look like this (the adg972a chip is a triple +4-way multiplexer): + + mux: mux-controller@50 { + compatible = "adi,adg792a"; + reg = <0x50>; + #mux-control-cells = <1>; + + idle-state = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nds32/andestech-boards b/arch/arm64/boot/dts/vendor/bindings/nds32/andestech-boards new file mode 100644 index 0000000000000000000000000000000000000000..f5d75693e3c726c04d7571283c2d52d419a094c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nds32/andestech-boards @@ -0,0 +1,40 @@ +Andestech(nds32) AE3XX Platform +----------------------------------------------------------------------------- +The AE3XX prototype demonstrates the AE3XX example platform on the FPGA. It +is composed of one Andestech(nds32) processor and AE3XX. + +Required properties (in root node): +- compatible = "andestech,ae3xx"; + +Example: +/dts-v1/; +/ { + compatible = "andestech,ae3xx"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; +}; + +Andestech(nds32) AG101P Platform +----------------------------------------------------------------------------- +AG101P is a generic SoC Platform IP that works with any of Andestech(nds32) +processors to provide a cost-effective and high performance solution for +majority of embedded systems in variety of application domains. Users may +simply attach their IP on one of the system buses together with certain glue +logics to complete a SoC solution for a specific application. With +comprehensive simulation and design environments, users may evaluate the +system performance of their applications and track bugs of their designs +efficiently. The optional hardware development platform further provides real +system environment for early prototyping and software/hardware co-development. + +Required properties (in root node): + compatible = "andestech,ag101p"; + +Example: +/dts-v1/; +/ { + compatible = "andestech,ag101p"; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&intc>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/nds32/atl2c.txt b/arch/arm64/boot/dts/vendor/bindings/nds32/atl2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..da8ab8e7ae9b5146ba3f04f33c65c3fe47e90eae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nds32/atl2c.txt @@ -0,0 +1,28 @@ +* Andestech L2 cache Controller + +The level-2 cache controller plays an important role in reducing memory latency +for high performance systems, such as thoese designs with AndesCore processors. +Level-2 cache controller in general enhances overall system performance +signigicantly and the system power consumption might be reduced as well by +reducing DRAM accesses. + +This binding specifies what properties must be available in the device tree +representation of an Andestech L2 cache controller. + +Required properties: + - compatible: + Usage: required + Value type: + Definition: "andestech,atl2c" + - reg : Physical base address and size of cache controller's memory mapped + - cache-unified : Specifies the cache is a unified cache. + - cache-level : Should be set to 2 for a level 2 cache. + +* Example + + cache-controller@e0500000 { + compatible = "andestech,atl2c"; + reg = <0xe0500000 0x1000>; + cache-unified; + cache-level = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nds32/cpus.txt b/arch/arm64/boot/dts/vendor/bindings/nds32/cpus.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f9e311b6589f33cf85e058b12acc346769d12d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nds32/cpus.txt @@ -0,0 +1,38 @@ +* Andestech Processor Binding + +This binding specifies what properties must be available in the device tree +representation of a Andestech Processor Core, which is the root node in the +tree. + +Required properties: + + - compatible: + Usage: required + Value type: + Definition: Should be "andestech,", "andestech,nds32v3" as fallback. + Must contain "andestech,nds32v3" as the most generic value, in addition to + one of the following identifiers for a particular CPU core: + "andestech,n13" + "andestech,n15" + "andestech,d15" + "andestech,n10" + "andestech,d10" + - device_type + Usage: required + Value type: + Definition: must be "cpu" + - reg: Contains CPU index. + - clock-frequency: Contains the clock frequency for CPU, in Hz. + +* Examples + +/ { + cpus { + cpu@0 { + device_type = "cpu"; + compatible = "andestech,n13", "andestech,nds32v3"; + reg = <0x0>; + clock-frequency = <60000000> + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun4i-emac.txt b/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun4i-emac.txt new file mode 100644 index 0000000000000000000000000000000000000000..e98118aef5f6f245786f561ea8892dac9ac6fa9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun4i-emac.txt @@ -0,0 +1,19 @@ +* Allwinner EMAC ethernet controller + +Required properties: +- compatible: should be "allwinner,sun4i-a10-emac" (Deprecated: + "allwinner,sun4i-emac") +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device +- phy: see ethernet.txt file in the same directory. +- clocks: A phandle to the reference clock for this device + +Example: + +emac: ethernet@1c0b000 { + compatible = "allwinner,sun4i-a10-emac"; + reg = <0x01c0b000 0x1000>; + interrupts = <55>; + clocks = <&ahb_gates 17>; + phy = <&phy0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun4i-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun4i-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab5b8613b0efc6b66e2c45cc4ee03ee8214b7fb7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun4i-mdio.txt @@ -0,0 +1,27 @@ +* Allwinner A10 MDIO Ethernet Controller interface + +Required properties: +- compatible: should be "allwinner,sun4i-a10-mdio" + (Deprecated: "allwinner,sun4i-mdio"). +- reg: address and length of the register set for the device. + +Optional properties: +- phy-supply: phandle to a regulator if the PHY needs one + +Example at the SoC level: +mdio@1c0b080 { + compatible = "allwinner,sun4i-a10-mdio"; + reg = <0x01c0b080 0x14>; + #address-cells = <1>; + #size-cells = <0>; +}; + +And at the board level: + +mdio@1c0b080 { + phy-supply = <®_emac_3v3>; + + phy0: ethernet-phy@0 { + reg = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun7i-a20-gmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun7i-a20-gmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b3f953656e358dc5ad38103d0ce3565a42dc43c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/allwinner,sun7i-a20-gmac.txt @@ -0,0 +1,27 @@ +* Allwinner GMAC ethernet controller + +This device is a platform glue layer for stmmac. +Please see stmmac.txt for the other unchanged properties. + +Required properties: + - compatible: Should be "allwinner,sun7i-a20-gmac" + - clocks: Should contain the GMAC main clock, and tx clock + The tx clock type should be "allwinner,sun7i-a20-gmac-clk" + - clock-names: Should contain the clock names "stmmaceth", + and "allwinner_gmac_tx" + +Optional properties: +- phy-supply: phandle to a regulator if the PHY needs one + +Examples: + + gmac: ethernet@1c50000 { + compatible = "allwinner,sun7i-a20-gmac"; + reg = <0x01c50000 0x10000>, + <0x01c20164 0x4>; + interrupts = <0 85 1>; + interrupt-names = "macirq"; + clocks = <&ahb_gates 49>, <&gmac_tx>; + clock-names = "stmmaceth", "allwinner_gmac_tx"; + phy-mode = "mii"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/altera_tse.txt b/arch/arm64/boot/dts/vendor/bindings/net/altera_tse.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e21df94a53ffa221e6262f4323dc2ff60068a00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/altera_tse.txt @@ -0,0 +1,114 @@ +* Altera Triple-Speed Ethernet MAC driver (TSE) + +Required properties: +- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should + be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE. + ALTR is supported for legacy device trees, but is deprecated. + altr should be used for all new designs. +- reg: Address and length of the register set for the device. It contains + the information of registers in the same order as described by reg-names +- reg-names: Should contain the reg names + "control_port": MAC configuration space region + "tx_csr": xDMA Tx dispatcher control and status space region + "tx_desc": MSGDMA Tx dispatcher descriptor space region + "rx_csr" : xDMA Rx dispatcher control and status space region + "rx_desc": MSGDMA Rx dispatcher descriptor space region + "rx_resp": MSGDMA Rx dispatcher response space region + "s1": SGDMA descriptor memory +- interrupts: Should contain the TSE interrupts and it's mode. +- interrupt-names: Should contain the interrupt names + "rx_irq": xDMA Rx dispatcher interrupt + "tx_irq": xDMA Tx dispatcher interrupt +- rx-fifo-depth: MAC receive FIFO buffer depth in bytes +- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes +- phy-mode: See ethernet.txt in the same directory. +- phy-handle: See ethernet.txt in the same directory. +- phy-addr: See ethernet.txt in the same directory. A configuration should + include phy-handle or phy-addr. +- altr,has-supplementary-unicast: + If present, TSE supports additional unicast addresses. + Otherwise additional unicast addresses are not supported. +- altr,has-hash-multicast-filter: + If present, TSE supports a hash based multicast filter. + Otherwise, hash-based multicast filtering is not supported. + +- mdio device tree subnode: When the TSE has a phy connected to its local + mdio, there must be device tree subnode with the following + required properties: + + - compatible: Must be "altr,tse-mdio". + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For each phy on the mdio bus, there must be a node with the following + fields: + + - reg: phy id used to communicate to phy. + - device_type: Must be "ethernet-phy". + +Optional properties: +- local-mac-address: See ethernet.txt in the same directory. +- max-frame-size: See ethernet.txt in the same directory. + +Example: + + tse_sub_0_eth_tse_0: ethernet@1,00000000 { + compatible = "altr,tse-msgdma-1.0"; + reg = <0x00000001 0x00000000 0x00000400>, + <0x00000001 0x00000460 0x00000020>, + <0x00000001 0x00000480 0x00000020>, + <0x00000001 0x000004A0 0x00000008>, + <0x00000001 0x00000400 0x00000020>, + <0x00000001 0x00000420 0x00000020>; + reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc"; + interrupt-parent = <&hps_0_arm_gic_0>; + interrupts = <0 41 4>, <0 40 4>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <2048>; + tx-fifo-depth = <2048>; + address-bits = <48>; + max-frame-size = <1500>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-mode = "gmii"; + altr,has-supplementary-unicast; + altr,has-hash-multicast-filter; + phy-handle = <&phy0>; + mdio { + compatible = "altr,tse-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0x0>; + device_type = "ethernet-phy"; + }; + + phy1: ethernet-phy@1 { + reg = <0x1>; + device_type = "ethernet-phy"; + }; + + }; + }; + + tse_sub_1_eth_tse_0: ethernet@1,00001000 { + compatible = "altr,tse-msgdma-1.0"; + reg = <0x00000001 0x00001000 0x00000400>, + <0x00000001 0x00001460 0x00000020>, + <0x00000001 0x00001480 0x00000020>, + <0x00000001 0x000014A0 0x00000008>, + <0x00000001 0x00001400 0x00000020>, + <0x00000001 0x00001420 0x00000020>; + reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc"; + interrupt-parent = <&hps_0_arm_gic_0>; + interrupts = <0 43 4>, <0 42 4>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <2048>; + tx-fifo-depth = <2048>; + address-bits = <48>; + max-frame-size = <1500>; + local-mac-address = [ 00 00 00 00 00 00 ]; + phy-mode = "gmii"; + altr,has-supplementary-unicast; + altr,has-hash-multicast-filter; + phy-handle = <&phy1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/amd-xgbe.txt b/arch/arm64/boot/dts/vendor/bindings/net/amd-xgbe.txt new file mode 100644 index 0000000000000000000000000000000000000000..93dcb79a5f16408ac92694a2831b66b74e232a4f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/amd-xgbe.txt @@ -0,0 +1,75 @@ +* AMD 10GbE driver (amd-xgbe) + +Required properties: +- compatible: Should be "amd,xgbe-seattle-v1a" +- reg: Address and length of the register sets for the device + - MAC registers + - PCS registers + - SerDes Rx/Tx registers + - SerDes integration registers (1/2) + - SerDes integration registers (2/2) +- interrupts: Should contain the amd-xgbe interrupt(s). The first interrupt + listed is required and is the general device interrupt. If the optional + amd,per-channel-interrupt property is specified, then one additional + interrupt for each DMA channel supported by the device should be specified. + The last interrupt listed should be the PCS auto-negotiation interrupt. +- clocks: + - DMA clock for the amd-xgbe device (used for calculating the + correct Rx interrupt watchdog timer value on a DMA channel + for coalescing) + - PTP clock for the amd-xgbe device +- clock-names: Should be the names of the clocks + - "dma_clk" for the DMA clock + - "ptp_clk" for the PTP clock +- phy-mode: See ethernet.txt file in the same directory + +Optional properties: +- mac-address: mac address to be assigned to the device. Can be overridden + by UEFI. +- dma-coherent: Present if dma operations are coherent +- amd,per-channel-interrupt: Indicates that Rx and Tx complete will generate + a unique interrupt for each DMA channel - this requires an additional + interrupt be configured for each DMA channel +- amd,speed-set: Speed capabilities of the device + 0 - 1GbE and 10GbE (default) + 1 - 2.5GbE and 10GbE + +The following optional properties are represented by an array with each +value corresponding to a particular speed. The first array value represents +the setting for the 1GbE speed, the second value for the 2.5GbE speed and +the third value for the 10GbE speed. All three values are required if the +property is used. +- amd,serdes-blwc: Baseline wandering correction enablement + 0 - Off + 1 - On +- amd,serdes-cdr-rate: CDR rate speed selection +- amd,serdes-pq-skew: PQ (data sampling) skew +- amd,serdes-tx-amp: TX amplitude boost +- amd,serdes-dfe-tap-config: DFE taps available to run +- amd,serdes-dfe-tap-enable: DFE taps to enable + +Example: + xgbe@e0700000 { + compatible = "amd,xgbe-seattle-v1a"; + reg = <0 0xe0700000 0 0x80000>, + <0 0xe0780000 0 0x80000>, + <0 0xe1240800 0 0x00400>, + <0 0xe1250000 0 0x00060>, + <0 0xe1250080 0 0x00004>; + interrupt-parent = <&gic>; + interrupts = <0 325 4>, + <0 326 1>, <0 327 1>, <0 328 1>, <0 329 1>, + <0 323 4>; + amd,per-channel-interrupt; + clocks = <&xgbe_dma_clk>, <&xgbe_ptp_clk>; + clock-names = "dma_clk", "ptp_clk"; + phy-mode = "xgmii"; + mac-address = [ 02 a1 a2 a3 a4 a5 ]; + amd,speed-set = <0>; + amd,serdes-blwc = <1>, <1>, <0>; + amd,serdes-cdr-rate = <2>, <2>, <7>; + amd,serdes-pq-skew = <10>, <10>, <30>; + amd,serdes-tx-amp = <15>, <15>, <10>; + amd,serdes-dfe-tap-config = <3>, <3>, <1>; + amd,serdes-dfe-tap-enable = <0>, <0>, <127>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/anarion-gmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/anarion-gmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..fe678965ae690e7e2177c0dd3e43831da8af4bdb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/anarion-gmac.txt @@ -0,0 +1,25 @@ +* Adaptrum Anarion ethernet controller + +This device is a platform glue layer for stmmac. +Please see stmmac.txt for the other unchanged properties. + +Required properties: + - compatible: Should be "adaptrum,anarion-gmac", "snps,dwmac" + - phy-mode: Should be "rgmii". Other modes are not currently supported. + + +Examples: + + gmac1: ethernet@f2014000 { + compatible = "adaptrum,anarion-gmac", "snps,dwmac"; + reg = <0xf2014000 0x4000>, <0xf2018100 8>; + + interrupt-parent = <&core_intc>; + interrupts = <21>; + interrupt-names = "macirq"; + + clocks = <&core_clk>; + clock-names = "stmmaceth"; + + phy-mode = "rgmii"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/apm-xgene-enet.txt b/arch/arm64/boot/dts/vendor/bindings/net/apm-xgene-enet.txt new file mode 100644 index 0000000000000000000000000000000000000000..f591ab782dbcfa4c09399ee59f6a9669177d6a1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/apm-xgene-enet.txt @@ -0,0 +1,91 @@ +APM X-Gene SoC Ethernet nodes + +Ethernet nodes are defined to describe on-chip ethernet interfaces in +APM X-Gene SoC. + +Required properties for all the ethernet interfaces: +- compatible: Should state binding information from the following list, + - "apm,xgene-enet": RGMII based 1G interface + - "apm,xgene1-sgenet": SGMII based 1G interface + - "apm,xgene1-xgenet": XFI based 10G interface +- reg: Address and length of the register set for the device. It contains the + information of registers in the same order as described by reg-names +- reg-names: Should contain the register set names + - "enet_csr": Ethernet control and status register address space + - "ring_csr": Descriptor ring control and status register address space + - "ring_cmd": Descriptor ring command register address space +- interrupts: Two interrupt specifiers can be specified. + - First is the Rx interrupt. This irq is mandatory. + - Second is the Tx completion interrupt. + This is supported only on SGMII based 1GbE and 10GbE interfaces. +- channel: Ethernet to CPU, start channel (prefetch buffer) number + - Must map to the first irq and irqs must be sequential +- port-id: Port number (0 or 1) +- clocks: Reference to the clock entry. +- local-mac-address: MAC address assigned to this device +- phy-connection-type: Interface type between ethernet device and PHY device + +Required properties for ethernet interfaces that have external PHY: +- phy-handle: Reference to a PHY node connected to this device + +- mdio: Device tree subnode with the following required properties: + - compatible: Must be "apm,xgene-mdio". + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For the phy on the mdio bus, there must be a node with the following fields: + - compatible: PHY identifier. Please refer ./phy.txt for the format. + - reg: The ID number for the phy. + +Optional properties: +- status: Should be "ok" or "disabled" for enabled/disabled. Default is "ok". +- tx-delay: Delay value for RGMII bridge TX clock. + Valid values are between 0 to 7, that maps to + 417, 717, 1020, 1321, 1611, 1913, 2215, 2514 ps + Default value is 4, which corresponds to 1611 ps +- rx-delay: Delay value for RGMII bridge RX clock. + Valid values are between 0 to 7, that maps to + 273, 589, 899, 1222, 1480, 1806, 2147, 2464 ps + Default value is 2, which corresponds to 899 ps +- rxlos-gpios: Input gpio from SFP+ module to indicate availability of + incoming signal. + + +Example: + menetclk: menetclk { + compatible = "apm,xgene-device-clock"; + clock-output-names = "menetclk"; + status = "ok"; + }; + + menet: ethernet@17020000 { + compatible = "apm,xgene-enet"; + status = "disabled"; + reg = <0x0 0x17020000 0x0 0xd100>, + <0x0 0x17030000 0x0 0x400>, + <0x0 0x10000000 0x0 0x200>; + reg-names = "enet_csr", "ring_csr", "ring_cmd"; + interrupts = <0x0 0x3c 0x4>; + port-id = <0>; + clocks = <&menetclk 0>; + local-mac-address = [00 01 73 00 00 01]; + phy-connection-type = "rgmii"; + phy-handle = <&menetphy>; + mdio { + compatible = "apm,xgene-mdio"; + #address-cells = <1>; + #size-cells = <0>; + menetphy: menetphy@3 { + compatible = "ethernet-phy-id001c.c915"; + reg = <0x3>; + }; + + }; + }; + +/* Board-specific peripheral configurations */ +&menet { + tx-delay = <4>; + rx-delay = <2>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/apm-xgene-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/apm-xgene-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..78722d74cea830df4122b589843e24596a293b6e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/apm-xgene-mdio.txt @@ -0,0 +1,37 @@ +APM X-Gene SoC MDIO node + +MDIO node is defined to describe on-chip MDIO controller. + +Required properties: + - compatible: Must be "apm,xgene-mdio-rgmii" or "apm,xgene-mdio-xfi" + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + - reg: Address and length of the register set + - clocks: Reference to the clock entry + +For the phys on the mdio bus, there must be a node with the following fields: + - compatible: PHY identifier. Please refer ./phy.txt for the format. + - reg: The ID number for the phy. + +Example: + + mdio: mdio@17020000 { + compatible = "apm,xgene-mdio-rgmii"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x17020000 0x0 0xd100>; + clocks = <&menetclk 0>; + }; + + /* Board-specific peripheral configurations */ + &mdio { + menetphy: phy@3 { + reg = <0x3>; + }; + sgenet0phy: phy@4 { + reg = <0x4>; + }; + sgenet1phy: phy@5 { + reg = <0x5>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/arc_emac.txt b/arch/arm64/boot/dts/vendor/bindings/net/arc_emac.txt new file mode 100644 index 0000000000000000000000000000000000000000..c73a0e9c625e7fe852919fea75e4b204a7cf4637 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/arc_emac.txt @@ -0,0 +1,46 @@ +* Synopsys ARC EMAC 10/100 Ethernet driver (EMAC) + +Required properties: +- compatible: Should be "snps,arc-emac" +- reg: Address and length of the register set for the device +- interrupts: Should contain the EMAC interrupts +- max-speed: see ethernet.txt file in the same directory. +- phy: see ethernet.txt file in the same directory. + +Optional properties: +- phy-reset-gpios : Should specify the gpio for phy reset +- phy-reset-duration : Reset duration in milliseconds. Should present + only if property "phy-reset-gpios" is available. Missing the property + will have the duration be 1 millisecond. Numbers greater than 1000 are + invalid and 1 millisecond will be used instead. + +Clock handling: +The clock frequency is needed to calculate and set polling period of EMAC. +It must be provided by one of: +- clock-frequency: CPU frequency. +- clocks: reference to the clock supplying the EMAC. + +Child nodes of the driver are the individual PHY devices connected to the +MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. + +Examples: + + ethernet@c0fc2000 { + compatible = "snps,arc-emac"; + reg = <0xc0fc2000 0x3c>; + interrupts = <6>; + mac-address = [ 00 11 22 33 44 55 ]; + + clock-frequency = <80000000>; + /* or */ + clocks = <&emac_clock>; + + max-speed = <100>; + phy = <&phy0>; + + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/bluetooth.txt b/arch/arm64/boot/dts/vendor/bindings/net/bluetooth.txt new file mode 100644 index 0000000000000000000000000000000000000000..94797df751b870b3e073103ba9927139ac9897c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/bluetooth.txt @@ -0,0 +1,5 @@ +The following properties are common to the Bluetooth controllers: + +- local-bd-address: array of 6 bytes, specifies the BD address that was + uniquely assigned to the Bluetooth device, formatted with least significant + byte first (little-endian). diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,amac.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,amac.txt new file mode 100644 index 0000000000000000000000000000000000000000..0bfad656a9ff26fc4f672e06f1123198bb9259e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,amac.txt @@ -0,0 +1,30 @@ +Broadcom AMAC Ethernet Controller Device Tree Bindings +------------------------------------------------------------- + +Required properties: + - compatible: "brcm,amac" + "brcm,nsp-amac" + "brcm,ns2-amac" + - reg: Address and length of the register set for the device. It + contains the information of registers in the same order as + described by reg-names + - reg-names: Names of the registers. + "amac_base": Address and length of the GMAC registers + "idm_base": Address and length of the GMAC IDM registers + (required for NSP and Northstar2) + "nicpm_base": Address and length of the NIC Port Manager + registers (required for Northstar2) + - interrupts: Interrupt number + +Optional properties: +- mac-address: See ethernet.txt file in the same directory + +Examples: + +amac0: ethernet@18022000 { + compatible = "brcm,nsp-amac"; + reg = <0x18022000 0x1000>, + <0x18110000 0x1000>; + reg-names = "amac_base", "idm_base"; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,bcm7445-switch-v4.0.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,bcm7445-switch-v4.0.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7336b9d6a3c5e8a3ede785bdc88192087314c83 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,bcm7445-switch-v4.0.txt @@ -0,0 +1,132 @@ +* Broadcom Starfighter 2 integrated swich + +Required properties: + +- compatible: should be one of + "brcm,bcm7445-switch-v4.0" + "brcm,bcm7278-switch-v4.0" + "brcm,bcm7278-switch-v4.8" +- reg: addresses and length of the register sets for the device, must be 6 + pairs of register addresses and lengths +- interrupts: interrupts for the devices, must be two interrupts +- #address-cells: must be 1, see dsa/dsa.txt +- #size-cells: must be 0, see dsa/dsa.txt + +Deprecated binding required properties: + +- dsa,mii-bus: phandle to the MDIO bus controller, see dsa/dsa.txt +- dsa,ethernet: phandle to the CPU network interface controller, see dsa/dsa.txt +- #address-cells: must be 2, see dsa/dsa.txt + +Subnodes: + +The integrated switch subnode should be specified according to the binding +described in dsa/dsa.txt. + +Optional properties: + +- reg-names: litteral names for the device base register addresses, when present + must be: "core", "reg", "intrl2_0", "intrl2_1", "fcb", "acb" + +- interrupt-names: litternal names for the device interrupt lines, when present + must be: "switch_0" and "switch_1" + +- brcm,num-gphy: specify the maximum number of integrated gigabit PHYs in the + switch + +- brcm,num-rgmii-ports: specify the maximum number of RGMII interfaces supported + by the switch + +- brcm,fcb-pause-override: boolean property, if present indicates that the switch + supports Failover Control Block pause override capability + +- brcm,acb-packets-inflight: boolean property, if present indicates that the switch + Admission Control Block supports reporting the number of packets in-flight in a + switch queue + +Port subnodes: + +Optional properties: + +- brcm,use-bcm-hdr: boolean property, if present, indicates that the switch + port has Broadcom tags enabled (per-packet metadata) + +Example: + +switch_top@f0b00000 { + compatible = "simple-bus"; + #size-cells = <1>; + #address-cells = <1>; + ranges = <0 0xf0b00000 0x40804>; + + ethernet_switch@0 { + compatible = "brcm,bcm7445-switch-v4.0"; + #size-cells = <0>; + #address-cells = <1>; + reg = <0x0 0x40000 + 0x40000 0x110 + 0x40340 0x30 + 0x40380 0x30 + 0x40400 0x34 + 0x40600 0x208>; + reg-names = "core", "reg", intrl2_0", "intrl2_1", + "fcb, "acb"; + interrupts = <0 0x18 0 + 0 0x19 0>; + brcm,num-gphy = <1>; + brcm,num-rgmii-ports = <2>; + brcm,fcb-pause-override; + brcm,acb-packets-inflight; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + label = "gphy"; + reg = <0>; + }; + }; + }; +}; + +Example using the old DSA DeviceTree binding: + +switch_top@f0b00000 { + compatible = "simple-bus"; + #size-cells = <1>; + #address-cells = <1>; + ranges = <0 0xf0b00000 0x40804>; + + ethernet_switch@0 { + compatible = "brcm,bcm7445-switch-v4.0"; + #size-cells = <0>; + #address-cells = <2>; + reg = <0x0 0x40000 + 0x40000 0x110 + 0x40340 0x30 + 0x40380 0x30 + 0x40400 0x34 + 0x40600 0x208>; + interrupts = <0 0x18 0 + 0 0x19 0>; + brcm,num-gphy = <1>; + brcm,num-rgmii-ports = <2>; + brcm,fcb-pause-override; + brcm,acb-packets-inflight; + + ... + switch@0 { + reg = <0 0>; + #size-cells = <0>; + #address-cells <1>; + + port@0 { + label = "gphy"; + reg = <0>; + brcm,use-bcm-hdr; + }; + ... + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,bcmgenet.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,bcmgenet.txt new file mode 100644 index 0000000000000000000000000000000000000000..3956af1d30f37a8a732bae12ab0598e5c553975c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,bcmgenet.txt @@ -0,0 +1,124 @@ +* Broadcom BCM7xxx Ethernet Controller (GENET) + +Required properties: +- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2", + "brcm,genet-v3", "brcm,genet-v4", "brcm,genet-v5". +- reg: address and length of the register set for the device +- interrupts and/or interrupts-extended: must be two cells, the first cell + is the general purpose interrupt line, while the second cell is the + interrupt for the ring RX and TX queues operating in ring mode. An + optional third interrupt cell for Wake-on-LAN can be specified. + See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + for information on the property specifics. +- phy-mode: see ethernet.txt file in the same directory +- #address-cells: should be 1 +- #size-cells: should be 1 + +Optional properties: +- clocks: When provided, must be two phandles to the functional clocks nodes + of the GENET block. The first phandle is the main GENET clock used during + normal operation, while the second phandle is the Wake-on-LAN clock. +- clock-names: When provided, names of the functional clock phandles, first + name should be "enet" and second should be "enet-wol". + +- phy-handle: See ethernet.txt file in the same directory; used to describe + configurations where a PHY (internal or external) is used. + +- fixed-link: When the GENET interface is connected to a MoCA hardware block or + when operating in a RGMII to RGMII type of connection, or when the MDIO bus is + voluntarily disabled, this property should be used to describe the "fixed link". + See Documentation/devicetree/bindings/net/fixed-link.txt for information on + the property specifics + +Required child nodes: + +- mdio bus node: this node should always be present regardless of the PHY + configuration of the GENET instance + +MDIO bus node required properties: + +- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2" + "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5", the version + has to match the parent node compatible property (e.g: brcm,genet-v4 pairs + with brcm,genet-mdio-v4) +- reg: address and length relative to the parent node base register address +- #address-cells: address cell for MDIO bus addressing, should be 1 +- #size-cells: size of the cells for MDIO bus addressing, should be 0 + +Ethernet PHY node properties: + +See Documentation/devicetree/bindings/net/phy.txt for the list of required and +optional properties. + +Internal Gigabit PHY example: + +ethernet@f0b60000 { + phy-mode = "internal"; + phy-handle = <&phy1>; + mac-address = [ 00 10 18 36 23 1a ]; + compatible = "brcm,genet-v4"; + #address-cells = <0x1>; + #size-cells = <0x1>; + reg = <0xf0b60000 0xfc4c>; + interrupts = <0x0 0x14 0x0>, <0x0 0x15 0x0>; + + mdio@e14 { + compatible = "brcm,genet-mdio-v4"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0xe14 0x8>; + + phy1: ethernet-phy@1 { + max-speed = <1000>; + reg = <0x1>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; +}; + +MoCA interface / MAC to MAC example: + +ethernet@f0b80000 { + phy-mode = "moca"; + fixed-link = <1 0 1000 0 0>; + mac-address = [ 00 10 18 36 24 1a ]; + compatible = "brcm,genet-v4"; + #address-cells = <0x1>; + #size-cells = <0x1>; + reg = <0xf0b80000 0xfc4c>; + interrupts = <0x0 0x16 0x0>, <0x0 0x17 0x0>; + + mdio@e14 { + compatible = "brcm,genet-mdio-v4"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0xe14 0x8>; + }; +}; + + +External MDIO-connected Gigabit PHY/switch: + +ethernet@f0ba0000 { + phy-mode = "rgmii"; + phy-handle = <&phy0>; + mac-address = [ 00 10 18 36 26 1a ]; + compatible = "brcm,genet-v4"; + #address-cells = <0x1>; + #size-cells = <0x1>; + reg = <0xf0ba0000 0xfc4c>; + interrupts = <0x0 0x18 0x0>, <0x0 0x19 0x0>; + + mdio@e14 { + compatible = "brcm,genet-mdio-v4"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0xe14 0x8>; + + phy0: ethernet-phy@0 { + max-speed = <1000>; + reg = <0x0>; + compatible = "ethernet-phy-ieee802.3-c22"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,iproc-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,iproc-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ba9ed11d716f707bd5f21e19c690bc7e944e1ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,iproc-mdio.txt @@ -0,0 +1,23 @@ +* Broadcom iProc MDIO bus controller + +Required properties: +- compatible: should be "brcm,iproc-mdio" +- reg: address and length of the register set for the MDIO interface +- #size-cells: must be 1 +- #address-cells: must be 0 + +Child nodes of this MDIO bus controller node are standard Ethernet PHY device +nodes as described in Documentation/devicetree/bindings/net/phy.txt + +Example: + +mdio@18002000 { + compatible = "brcm,iproc-mdio"; + reg = <0x18002000 0x8>; + #size-cells = <1>; + #address-cells = <0>; + + enet-gphy@0 { + reg = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,mdio-mux-iproc.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,mdio-mux-iproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b58843f29591bf29842164897cd9cb58237e9c3a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,mdio-mux-iproc.txt @@ -0,0 +1,62 @@ +Properties for an MDIO bus multiplexer found in Broadcom iProc based SoCs. + +This MDIO bus multiplexer defines buses that could be internal as well as +external to SoCs and could accept MDIO transaction compatible to C-22 or +C-45 Clause. When child bus is selected, one needs to select these two +properties as well to generate desired MDIO transaction on appropriate bus. + +Required properties in addition to the generic multiplexer properties: + +MDIO multiplexer node: +- compatible: brcm,mdio-mux-iproc. + +Every non-ethernet PHY requires a compatible so that it could be probed based +on this compatible string. + +Optional properties: +- clocks: phandle of the core clock which drives the mdio block. + +Additional information regarding generic multiplexer properties can be found +at- Documentation/devicetree/bindings/net/mdio-mux.txt + + +for example: + mdio_mux_iproc: mdio-mux@66020000 { + compatible = "brcm,mdio-mux-iproc"; + reg = <0x66020000 0x250>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + pci_phy0: pci-phy@0 { + compatible = "brcm,ns2-pcie-phy"; + reg = <0x0>; + #phy-cells = <0>; + }; + }; + + mdio@7 { + reg = <0x7>; + #address-cells = <1>; + #size-cells = <0>; + + pci_phy1: pci-phy@0 { + compatible = "brcm,ns2-pcie-phy"; + reg = <0x0>; + #phy-cells = <0>; + }; + }; + mdio@10 { + reg = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + + gphy0: eth-phy@10 { + reg = <0x10>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,systemport.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,systemport.txt new file mode 100644 index 0000000000000000000000000000000000000000..83f29e0e11bacbda354677876d2b4d9b170999dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,systemport.txt @@ -0,0 +1,33 @@ +* Broadcom BCM7xxx Ethernet Systemport Controller (SYSTEMPORT) + +Required properties: +- compatible: should be one of: + "brcm,systemport-v1.00" + "brcm,systemportlite-v1.00" or + "brcm,systemport" +- reg: address and length of the register set for the device. +- interrupts: interrupts for the device, first cell must be for the rx + interrupts, and the second cell should be for the transmit queues. An + optional third interrupt cell for Wake-on-LAN can be specified +- local-mac-address: Ethernet MAC address (48 bits) of this adapter +- phy-mode: Should be a string describing the PHY interface to the + Ethernet switch/PHY, see Documentation/devicetree/bindings/net/ethernet.txt +- fixed-link: see Documentation/devicetree/bindings/net/fixed-link.txt for + the property specific details + +Optional properties: +- systemport,num-tier2-arb: number of tier 2 arbiters, an integer +- systemport,num-tier1-arb: number of tier 1 arbiters, an integer +- systemport,num-txq: number of HW transmit queues, an integer +- systemport,num-rxq: number of HW receive queues, an integer + +Example: +ethernet@f04a0000 { + compatible = "brcm,systemport-v1.00"; + reg = <0xf04a0000 0x4650>; + local-mac-address = [ 00 11 22 33 44 55 ]; + fixed-link = <0 1 1000 0 0>; + phy-mode = "gmii"; + interrupts = <0x0 0x16 0x0>, + <0x0 0x17 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/brcm,unimac-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/brcm,unimac-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..4648948f7c3b8f26391292b06aa01743100e8796 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/brcm,unimac-mdio.txt @@ -0,0 +1,40 @@ +* Broadcom UniMAC MDIO bus controller + +Required properties: +- compatible: should one from "brcm,genet-mdio-v1", "brcm,genet-mdio-v2", + "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", "brcm,genet-mdio-v5" or + "brcm,unimac-mdio" +- reg: address and length of the register set for the device, first one is the + base register, and the second one is optional and for indirect accesses to + larger than 16-bits MDIO transactions +- reg-names: name(s) of the register must be "mdio" and optional "mdio_indir_rw" +- #size-cells: must be 1 +- #address-cells: must be 0 + +Optional properties: +- interrupts: must be one if the interrupt is shared with the Ethernet MAC or + Ethernet switch this MDIO block is integrated from, or must be two, if there + are two separate interrupts, first one must be "mdio done" and second must be + for "mdio error" +- interrupt-names: must be "mdio_done_error" when there is a share interrupt fed + to this hardware block, or must be "mdio_done" for the first interrupt and + "mdio_error" for the second when there are separate interrupts + +Child nodes of this MDIO bus controller node are standard Ethernet PHY device +nodes as described in Documentation/devicetree/bindings/net/phy.txt + +Example: + +mdio@403c0 { + compatible = "brcm,unimac-mdio"; + reg = <0x403c0 0x8 0x40300 0x18>; + reg-names = "mdio", "mdio_indir_rw"; + #size-cells = <1>; + #address-cells = <0>; + + ... + phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/broadcom-bcm87xx.txt b/arch/arm64/boot/dts/vendor/bindings/net/broadcom-bcm87xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c86d5e28a0ed5a5d2c959db0d8b15d02aa1c89f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/broadcom-bcm87xx.txt @@ -0,0 +1,29 @@ +The Broadcom BCM87XX devices are a family of 10G Ethernet PHYs. They +have these bindings in addition to the standard PHY bindings. + +Compatible: Should contain "broadcom,bcm8706" or "broadcom,bcm8727" and + "ethernet-phy-ieee802.3-c45" + +Optional Properties: + +- broadcom,c45-reg-init : one of more sets of 4 cells. The first cell + is the MDIO Manageable Device (MMD) address, the second a register + address within the MMD, the third cell contains a mask to be ANDed + with the existing register value, and the fourth cell is ORed with + he result to yield the new register value. If the third cell has a + value of zero, no read of the existing value is performed. + +Example: + + ethernet-phy@5 { + reg = <5>; + compatible = "broadcom,bcm8706", "ethernet-phy-ieee802.3-c45"; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + /* + * Set PMD Digital Control Register for + * GPIO[1] Tx/Rx + * GPIO[0] R64 Sync Acquired + */ + broadcom,c45-reg-init = <1 0xc808 0xff8f 0x70>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/broadcom-bluetooth.txt b/arch/arm64/boot/dts/vendor/bindings/net/broadcom-bluetooth.txt new file mode 100644 index 0000000000000000000000000000000000000000..4194ff7e6ee678181f18b9cf1b9dc3e90bf93abb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/broadcom-bluetooth.txt @@ -0,0 +1,35 @@ +Broadcom Bluetooth Chips +--------------------- + +This documents the binding structure and common properties for serial +attached Broadcom devices. + +Serial attached Broadcom devices shall be a child node of the host UART +device the slave device is attached to. + +Required properties: + + - compatible: should contain one of the following: + * "brcm,bcm43438-bt" + +Optional properties: + + - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt + - shutdown-gpios: GPIO specifier, used to enable the BT module + - device-wakeup-gpios: GPIO specifier, used to wakeup the controller + - host-wakeup-gpios: GPIO specifier, used to wakeup the host processor + - clocks: clock specifier if external clock provided to the controller + - clock-names: should be "extclk" + + +Example: + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + + bluetooth { + compatible = "brcm,bcm43438-bt"; + max-speed = <921600>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/btusb.txt b/arch/arm64/boot/dts/vendor/bindings/net/btusb.txt new file mode 100644 index 0000000000000000000000000000000000000000..37d67926dd6d97748c63086055b73a0c95eb26be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/btusb.txt @@ -0,0 +1,41 @@ +Generic Bluetooth controller over USB (btusb driver) +--------------------------------------------------- + +Required properties: + + - compatible : should comply with the format "usbVID,PID" specified in + Documentation/devicetree/bindings/usb/usb-device.txt + At the time of writing, the only OF supported devices + (more may be added later) are: + + "usb1286,204e" (Marvell 8997) + +Also, vendors that use btusb may have device additional properties, e.g: +Documentation/devicetree/bindings/net/marvell-bt-8xxx.txt + +Optional properties: + + - interrupt-names: (see below) + - interrupts : The interrupt specified by the name "wakeup" is the interrupt + that shall be used for out-of-band wake-on-bt. Driver will + request this interrupt for wakeup. During system suspend, the + irq will be enabled so that the bluetooth chip can wakeup host + platform out of band. During system resume, the irq will be + disabled to make sure unnecessary interrupt is not received. + +Example: + +Following example uses irq pin number 3 of gpio0 for out of band wake-on-bt: + +&usb_host1_ehci { + #address-cells = <1>; + #size-cells = <0>; + + mvl_bt1: bt@1 { + compatible = "usb1286,204e"; + reg = <1>; + interrupt-parent = <&gpio0>; + interrupt-name = "wakeup"; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/calxeda-xgmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/calxeda-xgmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8ae996bd8f2e4403cd8c1bd7ed7507d9379f7d7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/calxeda-xgmac.txt @@ -0,0 +1,18 @@ +* Calxeda Highbank 10Gb XGMAC Ethernet + +Required properties: +- compatible : Should be "calxeda,hb-xgmac" +- reg : Address and length of the register set for the device +- interrupts : Should contain 3 xgmac interrupts. The 1st is main interrupt. + The 2nd is pwr mgt interrupt. The 3rd is low power state interrupt. + +Optional properties: +- dma-coherent : Present if dma operations are coherent + +Example: + +ethernet@fff50000 { + compatible = "calxeda,hb-xgmac"; + reg = <0xfff50000 0x1000>; + interrupts = <0 77 4 0 78 4 0 79 4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/atmel-can.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/atmel-can.txt new file mode 100644 index 0000000000000000000000000000000000000000..14e52a0d86ec2c96df5da66bea9ea148fe91fdd3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/atmel-can.txt @@ -0,0 +1,14 @@ +* AT91 CAN * + +Required properties: + - compatible: Should be "atmel,at91sam9263-can" or "atmel,at91sam9x5-can" + - reg: Should contain CAN controller registers location and length + - interrupts: Should contain IRQ line for the CAN controller + +Example: + + can0: can@f000c000 { + compatible = "atmel,at91sam9x5-can"; + reg = <0xf000c000 0x300>; + interrupts = <40 4 5> + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/c_can.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/c_can.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d504256b0d8e73183ebe114158f194a85e964d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/c_can.txt @@ -0,0 +1,65 @@ +Bosch C_CAN/D_CAN controller Device Tree Bindings +------------------------------------------------- + +Required properties: +- compatible : Should be "bosch,c_can" for C_CAN controllers and + "bosch,d_can" for D_CAN controllers. + Can be "ti,dra7-d_can", "ti,am3352-d_can" or + "ti,am4372-d_can". +- reg : physical base address and size of the C_CAN/D_CAN + registers map +- interrupts : property with a value describing the interrupt + number + +The following are mandatory properties for DRA7x, AM33xx and AM43xx SoCs only: +- ti,hwmods : Must be "d_can" or "c_can", n being the + instance number + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: +- power-domains : Should contain a phandle to a PM domain provider node + and an args specifier containing the DCAN device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt +- clocks : CAN functional clock phandle. This property is as per the + binding, + Documentation/devicetree/bindings/clock/ti,sci-clk.txt + +Optional properties: +- syscon-raminit : Handle to system control region that contains the + RAMINIT register, register offset to the RAMINIT + register and the CAN instance number (0 offset). + +Note: "ti,hwmods" field is used to fetch the base address and irq +resources from TI, omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Example: + +Step1: SoC common .dtsi file + + dcan1: d_can@481d0000 { + compatible = "bosch,d_can"; + reg = <0x481d0000 0x2000>; + interrupts = <55>; + interrupt-parent = <&intc>; + status = "disabled"; + }; + +(or) + + dcan1: d_can@481d0000 { + compatible = "bosch,d_can"; + ti,hwmods = "d_can1"; + reg = <0x481d0000 0x2000>; + interrupts = <55>; + interrupt-parent = <&intc>; + status = "disabled"; + }; + +Step 2: board specific .dts file + + &dcan1 { + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/can-transceiver.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/can-transceiver.txt new file mode 100644 index 0000000000000000000000000000000000000000..0011f53ff15900d85f8c5006847bcaa55273fae5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/can-transceiver.txt @@ -0,0 +1,24 @@ +Generic CAN transceiver Device Tree binding +------------------------------ + +CAN transceiver typically limits the max speed in standard CAN and CAN FD +modes. Typically these limitations are static and the transceivers themselves +provide no way to detect this limitation at runtime. For this situation, +the "can-transceiver" node can be used. + +Required Properties: + max-bitrate: a positive non 0 value that determines the max + speed that CAN/CAN-FD can run. Any other value + will be ignored. + +Examples: + +Based on Texas Instrument's TCAN1042HGV CAN Transceiver + +m_can0 { + .... + can-transceiver { + max-bitrate = <5000000>; + }; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/cc770.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/cc770.txt new file mode 100644 index 0000000000000000000000000000000000000000..77027bf6460a035a35e28c1f1334da076f5110f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/cc770.txt @@ -0,0 +1,53 @@ +Memory mapped Bosch CC770 and Intel AN82527 CAN controller + +Note: The CC770 is a CAN controller from Bosch, which is 100% +compatible with the old AN82527 from Intel, but with "bugs" being fixed. + +Required properties: + +- compatible : should be "bosch,cc770" for the CC770 and "intc,82527" + for the AN82527. + +- reg : should specify the chip select, address offset and size required + to map the registers of the controller. The size is usually 0x80. + +- interrupts : property with a value describing the interrupt source + (number and sensitivity) required for the controller. + +Optional properties: + +- bosch,external-clock-frequency : frequency of the external oscillator + clock in Hz. Note that the internal clock frequency used by the + controller is half of that value. If not specified, a default + value of 16000000 (16 MHz) is used. + +- bosch,clock-out-frequency : slock frequency in Hz on the CLKOUT pin. + If not specified or if the specified value is 0, the CLKOUT pin + will be disabled. + +- bosch,slew-rate : slew rate of the CLKOUT signal. If not specified, + a resonable value will be calculated. + +- bosch,disconnect-rx0-input : see data sheet. + +- bosch,disconnect-rx1-input : see data sheet. + +- bosch,disconnect-tx1-output : see data sheet. + +- bosch,polarity-dominant : see data sheet. + +- bosch,divide-memory-clock : see data sheet. + +- bosch,iso-low-speed-mux : see data sheet. + +For further information, please have a look to the CC770 or AN82527. + +Examples: + +can@3,100 { + compatible = "bosch,cc770"; + reg = <3 0x100 0x80>; + interrupts = <2 0>; + interrupt-parent = <&mpic>; + bosch,external-clock-frequency = <16000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/fsl-flexcan.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/fsl-flexcan.txt new file mode 100644 index 0000000000000000000000000000000000000000..bfc0c433654f4e094143bf371a2f10cef6611d8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/fsl-flexcan.txt @@ -0,0 +1,35 @@ +Flexcan CAN controller on Freescale's ARM and PowerPC system-on-a-chip (SOC). + +Required properties: + +- compatible : Should be "fsl,-flexcan" + + An implementation should also claim any of the following compatibles + that it is fully backwards compatible with: + + - fsl,p1010-flexcan + +- reg : Offset and length of the register set for this device +- interrupts : Interrupt tuple for this device + +Optional properties: + +- clock-frequency : The oscillator frequency driving the flexcan device + +- xceiver-supply: Regulator that powers the CAN transceiver + +- big-endian: This means the registers of FlexCAN controller are big endian. + This is optional property.i.e. if this property is not present in + device tree node then controller is assumed to be little endian. + if this property is present then controller is assumed to be big + endian. + +Example: + + can@1c000 { + compatible = "fsl,p1010-flexcan"; + reg = <0x1c000 0x1000>; + interrupts = <48 0x2>; + interrupt-parent = <&mpic>; + clock-frequency = <200000000>; // filled in by bootloader + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/grcan.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/grcan.txt new file mode 100644 index 0000000000000000000000000000000000000000..34ef3498f8870daa9071173e743dd514c39ddcc0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/grcan.txt @@ -0,0 +1,28 @@ +Aeroflex Gaisler GRCAN and GRHCAN CAN controllers. + +The GRCAN and CRHCAN CAN controllers are available in the GRLIB VHDL IP core +library. + +Note: These properties are built from the AMBA plug&play in a Leon SPARC system +(the ordinary environment for GRCAN and GRHCAN). There are no dts files for +sparc. + +Required properties: + +- name : Should be "GAISLER_GRCAN", "01_03d", "GAISLER_GRHCAN" or "01_034" + +- reg : Address and length of the register set for the device + +- freq : Frequency of the external oscillator clock in Hz (the frequency of + the amba bus in the ordinary case) + +- interrupts : Interrupt number for this device + +Optional properties: + +- systemid : If not present or if the value of the least significant 16 bits + of this 32-bit property is smaller than GRCAN_TXBUG_SAFE_GRLIB_VERSION + a bug workaround is activated. + +For further information look in the documentation for the GLIB IP core library: +http://www.gaisler.com/products/grlib/grip.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/holt_hi311x.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/holt_hi311x.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a9926f99937039022d283817beac8e9bcbbc926 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/holt_hi311x.txt @@ -0,0 +1,23 @@ +* Holt HI-311X stand-alone CAN controller device tree bindings + +Required properties: + - compatible: Should be one of the following: + - "holt,hi3110" for HI-3110 + - reg: SPI chip select. + - clocks: The clock feeding the CAN controller. + - interrupts: Should contain IRQ line for the CAN controller. + +Optional properties: + - vdd-supply: Regulator that powers the CAN controller. + - xceiver-supply: Regulator that powers the CAN transceiver. + +Example: + can0: can@1 { + compatible = "holt,hi3110"; + reg = <1>; + clocks = <&clk32m>; + interrupt-parent = <&gpio4>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + vdd-supply = <®5v0>; + xceiver-supply = <®5v0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/ifi_canfd.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/ifi_canfd.txt new file mode 100644 index 0000000000000000000000000000000000000000..20ea5c70ab824faa597948b3f3909c2521e1d230 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/ifi_canfd.txt @@ -0,0 +1,15 @@ +IFI CANFD controller +-------------------- + +Required properties: + - compatible: Should be "ifi,canfd-1.0" + - reg: Should contain CAN controller registers location and length + - interrupts: Should contain IRQ line for the CAN controller + +Example: + + canfd0: canfd@ff220000 { + compatible = "ifi,canfd-1.0"; + reg = <0xff220000 0x00001000>; + interrupts = <0 43 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/m_can.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/m_can.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed614383af9c4090fc3720b3118358872210a886 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/m_can.txt @@ -0,0 +1,75 @@ +Bosch MCAN controller Device Tree Bindings +------------------------------------------------- + +Required properties: +- compatible : Should be "bosch,m_can" for M_CAN controllers +- reg : physical base address and size of the M_CAN + registers map and Message RAM +- reg-names : Should be "m_can" and "message_ram" +- interrupts : Should be the interrupt number of M_CAN interrupt + line 0 and line 1, could be same if sharing + the same interrupt. +- interrupt-names : Should contain "int0" and "int1" +- clocks : Clocks used by controller, should be host clock + and CAN clock. +- clock-names : Should contain "hclk" and "cclk" +- pinctrl- : Pinctrl states as described in bindings/pinctrl/pinctrl-bindings.txt +- pinctrl-names : Names corresponding to the numbered pinctrl states +- bosch,mram-cfg : Message RAM configuration data. + Multiple M_CAN instances can share the same Message + RAM and each element(e.g Rx FIFO or Tx Buffer and etc) + number in Message RAM is also configurable, + so this property is telling driver how the shared or + private Message RAM are used by this M_CAN controller. + + The format should be as follows: + + The 'offset' is an address offset of the Message RAM + where the following elements start from. This is + usually set to 0x0 if you're using a private Message + RAM. The remain cells are used to specify how many + elements are used for each FIFO/Buffer. + + M_CAN includes the following elements according to user manual: + 11-bit Filter 0-128 elements / 0-128 words + 29-bit Filter 0-64 elements / 0-128 words + Rx FIFO 0 0-64 elements / 0-1152 words + Rx FIFO 1 0-64 elements / 0-1152 words + Rx Buffers 0-64 elements / 0-1152 words + Tx Event FIFO 0-32 elements / 0-64 words + Tx Buffers 0-32 elements / 0-576 words + + Please refer to 2.4.1 Message RAM Configuration in + Bosch M_CAN user manual for details. + +Optional Subnode: +- can-transceiver : Can-transceiver subnode describing maximum speed + that can be used for CAN/CAN-FD modes. See + Documentation/devicetree/bindings/net/can/can-transceiver.txt + for details. +Example: +SoC dtsi: +m_can1: can@20e8000 { + compatible = "bosch,m_can"; + reg = <0x020e8000 0x4000>, <0x02298000 0x4000>; + reg-names = "m_can", "message_ram"; + interrupts = <0 114 0x04>, + <0 114 0x04>; + interrupt-names = "int0", "int1"; + clocks = <&clks IMX6SX_CLK_CANFD>, + <&clks IMX6SX_CLK_CANFD>; + clock-names = "hclk", "cclk"; + bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>; +}; + +Board dts: +&m_can1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_m_can1>; + status = "enabled"; + + can-transceiver { + max-bitrate = <5000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/microchip,mcp251x.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/microchip,mcp251x.txt new file mode 100644 index 0000000000000000000000000000000000000000..188c8bd4eb67709bdc05bc1014fe86d692256be4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/microchip,mcp251x.txt @@ -0,0 +1,24 @@ +* Microchip MCP251X stand-alone CAN controller device tree bindings + +Required properties: + - compatible: Should be one of the following: + - "microchip,mcp2510" for MCP2510. + - "microchip,mcp2515" for MCP2515. + - reg: SPI chip select. + - clocks: The clock feeding the CAN controller. + - interrupts: Should contain IRQ line for the CAN controller. + +Optional properties: + - vdd-supply: Regulator that powers the CAN controller. + - xceiver-supply: Regulator that powers the CAN transceiver. + +Example: + can0: can@1 { + compatible = "microchip,mcp2515"; + reg = <1>; + clocks = <&clk24m>; + interrupt-parent = <&gpio4>; + interrupts = <13 0x2>; + vdd-supply = <®5v0>; + xceiver-supply = <®5v0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/microchip,mcp25xxfd.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/microchip,mcp25xxfd.txt new file mode 100644 index 0000000000000000000000000000000000000000..74f795b42ead02f61e074a25ea9b558e9571a054 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/microchip,mcp25xxfd.txt @@ -0,0 +1,31 @@ +* Microchip MCP2517 stand-alone CAN controller device tree bindings + +Required properties: + - compatible: Should be one of the following: + - "microchip,mcp2517fd" for MCP2517fd. + - reg: SPI chip select. + - clocks: The clock feeding the CAN controller. + - interrupt-parent: The parent interrupt controller. + - interrupts: Should contain IRQ line for the CAN controller. + - gpio-controller: Marks the device node as a GPIO controller + +Optional properties: + - vdd-supply: Regulator that powers the CAN controller. + - xceiver-supply: Regulator that powers the CAN transceiver. + - microchip,clock_out_div = <0|1|2|4|10>: Clock output pin divider + 0 = Start of Frame output + default: 10 + - microchip,clock_div2: bool: divide the internal clock by 2 + - gpio_opendrain: bool: enable open-drain for all pins (except cantx) + +Example: + can0: can@1 { + compatible = "microchip,mcp2517fd"; + reg = <1>; + clocks = <&clk24m>; + interrupt-parent = <&gpio4>; + interrupts = <13 0x8>; + vdd-supply = <®5v0>; + xceiver-supply = <®5v0>; + gpio-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/mpc5xxx-mscan.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/mpc5xxx-mscan.txt new file mode 100644 index 0000000000000000000000000000000000000000..2fa4fcd38fd6f97834c728bae84f52b69a30499f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/mpc5xxx-mscan.txt @@ -0,0 +1,53 @@ +CAN Device Tree Bindings +------------------------ + +(c) 2006-2009 Secret Lab Technologies Ltd +Grant Likely + +fsl,mpc5200-mscan nodes +----------------------- +In addition to the required compatible-, reg- and interrupt-properties, you can +also specify which clock source shall be used for the controller: + +- fsl,mscan-clock-source : a string describing the clock source. Valid values + are: "ip" for ip bus clock + "ref" for reference clock (XTAL) + "ref" is default in case this property is not + present. + +fsl,mpc5121-mscan nodes +----------------------- +In addition to the required compatible-, reg- and interrupt-properties, you can +also specify which clock source and divider shall be used for the controller: + +- fsl,mscan-clock-source : a string describing the clock source. Valid values + are: "ip" for ip bus clock + "ref" for reference clock + "sys" for system clock + If this property is not present, an optimal CAN + clock source and frequency based on the system + clock will be selected. If this is not possible, + the reference clock will be used. + +- fsl,mscan-clock-divider: for the reference and system clock, an additional + clock divider can be specified. By default, a + value of 1 is used. + +Note that the MPC5121 Rev. 1 processor is not supported. + +Examples: + can@1300 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <12 0x8>; + interrupt-parent = <&ipic>; + reg = <0x1300 0x80>; + }; + + can@1380 { + compatible = "fsl,mpc5121-mscan"; + interrupts = <13 0x8>; + interrupt-parent = <&ipic>; + reg = <0x1380 0x80>; + fsl,mscan-clock-source = "ref"; + fsl,mscan-clock-divider = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/rcar_can.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/rcar_can.txt new file mode 100644 index 0000000000000000000000000000000000000000..94a7f33ac5e95eb3fa92acc78aa5704839773019 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/rcar_can.txt @@ -0,0 +1,68 @@ +Renesas R-Car CAN controller Device Tree Bindings +------------------------------------------------- + +Required properties: +- compatible: "renesas,can-r8a7743" if CAN controller is a part of R8A7743 SoC. + "renesas,can-r8a7745" if CAN controller is a part of R8A7745 SoC. + "renesas,can-r8a7778" if CAN controller is a part of R8A7778 SoC. + "renesas,can-r8a7779" if CAN controller is a part of R8A7779 SoC. + "renesas,can-r8a7790" if CAN controller is a part of R8A7790 SoC. + "renesas,can-r8a7791" if CAN controller is a part of R8A7791 SoC. + "renesas,can-r8a7792" if CAN controller is a part of R8A7792 SoC. + "renesas,can-r8a7793" if CAN controller is a part of R8A7793 SoC. + "renesas,can-r8a7794" if CAN controller is a part of R8A7794 SoC. + "renesas,can-r8a7795" if CAN controller is a part of R8A7795 SoC. + "renesas,can-r8a7796" if CAN controller is a part of R8A7796 SoC. + "renesas,rcar-gen1-can" for a generic R-Car Gen1 compatible device. + "renesas,rcar-gen2-can" for a generic R-Car Gen2 or RZ/G1 + compatible device. + "renesas,rcar-gen3-can" for a generic R-Car Gen3 compatible device. + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: physical base address and size of the R-Car CAN register map. +- interrupts: interrupt specifier for the sole interrupt. +- clocks: phandles and clock specifiers for 3 CAN clock inputs. +- clock-names: 3 clock input name strings: "clkp1", "clkp2", "can_clk". +- pinctrl-0: pin control group to be used for this controller. +- pinctrl-names: must be "default". + +Required properties for "renesas,can-r8a7795" and "renesas,can-r8a7796" +compatible: +In R8A7795 and R8A7796 SoCs, "clkp2" can be CANFD clock. This is a div6 clock +and can be used by both CAN and CAN FD controller at the same time. It needs to +be scaled to maximum frequency if any of these controllers use it. This is done +using the below properties: + +- assigned-clocks: phandle of clkp2(CANFD) clock. +- assigned-clock-rates: maximum frequency of this clock. + +Optional properties: +- renesas,can-clock-select: R-Car CAN Clock Source Select. Valid values are: + <0x0> (default) : Peripheral clock (clkp1) + <0x1> : Peripheral clock (clkp2) + <0x3> : Externally input clock + +Example +------- + +SoC common .dtsi file: + + can0: can@e6e80000 { + compatible = "renesas,can-r8a7791", "renesas,rcar-gen2-can"; + reg = <0 0xe6e80000 0 0x1000>; + interrupts = <0 186 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7791_CLK_RCAN0>, + <&cpg_clocks R8A7791_CLK_RCAN>, <&can_clk>; + clock-names = "clkp1", "clkp2", "can_clk"; + status = "disabled"; + }; + +Board specific .dts file: + +&can0 { + pinctrl-0 = <&can0_pins>; + pinctrl-names = "default"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/rcar_canfd.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/rcar_canfd.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac71daa4619505030ac1373e678ca13241727f82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/rcar_canfd.txt @@ -0,0 +1,100 @@ +Renesas R-Car CAN FD controller Device Tree Bindings +---------------------------------------------------- + +Required properties: +- compatible: Must contain one or more of the following: + - "renesas,rcar-gen3-canfd" for R-Car Gen3 compatible controller. + - "renesas,r8a7795-canfd" for R8A7795 (R-Car H3) compatible controller. + - "renesas,r8a7796-canfd" for R8A7796 (R-Car M3-W) compatible controller. + - "renesas,r8a77970-canfd" for R8A77970 (R-Car V3M) compatible controller. + - "renesas,r8a77980-canfd" for R8A77980 (R-Car V3H) compatible controller. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first, followed by the + family-specific and/or generic versions. + +- reg: physical base address and size of the R-Car CAN FD register map. +- interrupts: interrupt specifiers for the Channel & Global interrupts +- clocks: phandles and clock specifiers for 3 clock inputs. +- clock-names: 3 clock input name strings: "fck", "canfd", "can_clk". +- pinctrl-0: pin control group to be used for this controller. +- pinctrl-names: must be "default". + +Required child nodes: +The controller supports two channels and each is represented as a child node. +The name of the child nodes are "channel0" and "channel1" respectively. Each +child node supports the "status" property only, which is used to +enable/disable the respective channel. + +Required properties for "renesas,r8a7795-canfd" and "renesas,r8a7796-canfd" +compatible: +In R8A7795 and R8A7796 SoCs, canfd clock is a div6 clock and can be used by both +CAN and CAN FD controller at the same time. It needs to be scaled to maximum +frequency if any of these controllers use it. This is done using the below +properties: + +- assigned-clocks: phandle of canfd clock. +- assigned-clock-rates: maximum frequency of this clock. + +Optional property: +The controller can operate in either CAN FD only mode (default) or +Classical CAN only mode. The mode is global to both the channels. In order to +enable the later, define the following optional property. + - renesas,no-can-fd: puts the controller in Classical CAN only mode. + +Example +------- + +SoC common .dtsi file: + + canfd: can@e66c0000 { + compatible = "renesas,r8a7795-canfd", + "renesas,rcar-gen3-canfd"; + reg = <0 0xe66c0000 0 0x8000>; + interrupts = , + ; + clocks = <&cpg CPG_MOD 914>, + <&cpg CPG_CORE R8A7795_CLK_CANFD>, + <&can_clk>; + clock-names = "fck", "canfd", "can_clk"; + assigned-clocks = <&cpg CPG_CORE R8A7795_CLK_CANFD>; + assigned-clock-rates = <40000000>; + power-domains = <&cpg>; + status = "disabled"; + + channel0 { + status = "disabled"; + }; + + channel1 { + status = "disabled"; + }; + }; + +Board specific .dts file: + +E.g. below enables Channel 1 alone in the board in Classical CAN only mode. + +&canfd { + pinctrl-0 = <&canfd1_pins>; + pinctrl-names = "default"; + renesas,no-can-fd; + status = "okay"; + + channel1 { + status = "okay"; + }; +}; + +E.g. below enables Channel 0 alone in the board using External clock +as fCAN clock. + +&canfd { + pinctrl-0 = <&canfd0_pins &can_clk_pins>; + pinctrl-names = "default"; + status = "okay"; + + channel0 { + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/sja1000.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/sja1000.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac3160eca96a2dc38f085f165aee2d912e8c927c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/sja1000.txt @@ -0,0 +1,58 @@ +Memory mapped SJA1000 CAN controller from NXP (formerly Philips) + +Required properties: + +- compatible : should be one of "nxp,sja1000", "technologic,sja1000". + +- reg : should specify the chip select, address offset and size required + to map the registers of the SJA1000. The size is usually 0x80. + +- interrupts: property with a value describing the interrupt source + (number and sensitivity) required for the SJA1000. + +Optional properties: + +- reg-io-width : Specify the size (in bytes) of the IO accesses that + should be performed on the device. Valid value is 1, 2 or 4. + This property is ignored for technologic version. + Default to 1 (8 bits). + +- nxp,external-clock-frequency : Frequency of the external oscillator + clock in Hz. Note that the internal clock frequency used by the + SJA1000 is half of that value. If not specified, a default value + of 16000000 (16 MHz) is used. + +- nxp,tx-output-mode : operation mode of the TX output control logic: + <0x0> : bi-phase output mode + <0x1> : normal output mode (default) + <0x2> : test output mode + <0x3> : clock output mode + +- nxp,tx-output-config : TX output pin configuration: + <0x01> : TX0 invert + <0x02> : TX0 pull-down (default) + <0x04> : TX0 pull-up + <0x06> : TX0 push-pull + <0x08> : TX1 invert + <0x10> : TX1 pull-down + <0x20> : TX1 pull-up + <0x30> : TX1 push-pull + +- nxp,clock-out-frequency : clock frequency in Hz on the CLKOUT pin. + If not specified or if the specified value is 0, the CLKOUT pin + will be disabled. + +- nxp,no-comparator-bypass : Allows to disable the CAN input comparator. + +For further information, please have a look to the SJA1000 data sheet. + +Examples: + +can@3,100 { + compatible = "nxp,sja1000"; + reg = <3 0x100 0x80>; + interrupts = <2 0>; + interrupt-parent = <&mpic>; + nxp,external-clock-frequency = <16000000>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/sun4i_can.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/sun4i_can.txt new file mode 100644 index 0000000000000000000000000000000000000000..f69845e6feaf4e2ab23a63be8ff67c7796756fd0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/sun4i_can.txt @@ -0,0 +1,36 @@ +Allwinner A10/A20 CAN controller Device Tree Bindings +----------------------------------------------------- + +Required properties: +- compatible: "allwinner,sun4i-a10-can" +- reg: physical base address and size of the Allwinner A10/A20 CAN register map. +- interrupts: interrupt specifier for the sole interrupt. +- clock: phandle and clock specifier. + +Example +------- + +SoC common .dtsi file: + + can0_pins_a: can0@0 { + allwinner,pins = "PH20","PH21"; + allwinner,function = "can"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; +... + can0: can@1c2bc00 { + compatible = "allwinner,sun4i-a10-can"; + reg = <0x01c2bc00 0x400>; + interrupts = <0 26 4>; + clocks = <&apb1_gates 4>; + status = "disabled"; + }; + +Board specific .dts file: + + can0: can@1c2bc00 { + pinctrl-names = "default"; + pinctrl-0 = <&can0_pins_a>; + status = "okay"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/ti_hecc.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/ti_hecc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0f0a7cfe3293893ae42fae3ca14571c29288a01 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/ti_hecc.txt @@ -0,0 +1,32 @@ +Texas Instruments High End CAN Controller (HECC) +================================================ + +This file provides information, what the device node +for the hecc interface contains. + +Required properties: +- compatible: "ti,am3517-hecc" +- reg: addresses and lengths of the register spaces for 'hecc', 'hecc-ram' + and 'mbx' +- reg-names :"hecc", "hecc-ram", "mbx" +- interrupts: interrupt mapping for the hecc interrupts sources +- clocks: clock phandles (see clock bindings for details) + +Optional properties: +- ti,use-hecc1int: if provided configures HECC to produce all interrupts + on HECC1INT interrupt line. By default HECC0INT interrupt + line will be used. +- xceiver-supply: regulator that powers the CAN transceiver + +Example: + +For am3517evm board: + hecc: can@5c050000 { + compatible = "ti,am3517-hecc"; + reg = <0x5c050000 0x80>, + <0x5c053000 0x180>, + <0x5c052000 0x200>; + reg-names = "hecc", "hecc-ram", "mbx"; + interrupts = <24>; + clocks = <&hecc_ck>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/can/xilinx_can.txt b/arch/arm64/boot/dts/vendor/bindings/net/can/xilinx_can.txt new file mode 100644 index 0000000000000000000000000000000000000000..060e2d46bad961d870467f6e86482a1714b58e45 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/can/xilinx_can.txt @@ -0,0 +1,60 @@ +Xilinx Axi CAN/Zynq CANPS controller Device Tree Bindings +--------------------------------------------------------- + +Required properties: +- compatible : Should be: + - "xlnx,zynq-can-1.0" for Zynq CAN controllers + - "xlnx,axi-can-1.00.a" for Axi CAN controllers + - "xlnx,canfd-1.0" for CAN FD controllers +- reg : Physical base address and size of the controller + registers map. +- interrupts : Property with a value describing the interrupt + number. +- clock-names : List of input clock names + - "can_clk", "pclk" (For CANPS), + - "can_clk", "s_axi_aclk" (For AXI CAN and CAN FD). + (See clock bindings for details). +- clocks : Clock phandles (see clock bindings for details). +- tx-fifo-depth : Can Tx fifo depth (Zynq, Axi CAN). +- rx-fifo-depth : Can Rx fifo depth (Zynq, Axi CAN, CAN FD in + sequential Rx mode). +- tx-mailbox-count : Can Tx mailbox buffer count (CAN FD). +- rx-mailbox-count : Can Rx mailbox buffer count (CAN FD in mailbox Rx + mode). + + +Example: + +For Zynq CANPS Dts file: + zynq_can_0: can@e0008000 { + compatible = "xlnx,zynq-can-1.0"; + clocks = <&clkc 19>, <&clkc 36>; + clock-names = "can_clk", "pclk"; + reg = <0xe0008000 0x1000>; + interrupts = <0 28 4>; + interrupt-parent = <&intc>; + tx-fifo-depth = <0x40>; + rx-fifo-depth = <0x40>; + }; +For Axi CAN Dts file: + axi_can_0: axi-can@40000000 { + compatible = "xlnx,axi-can-1.00.a"; + clocks = <&clkc 0>, <&clkc 1>; + clock-names = "can_clk","s_axi_aclk" ; + reg = <0x40000000 0x10000>; + interrupt-parent = <&intc>; + interrupts = <0 59 1>; + tx-fifo-depth = <0x40>; + rx-fifo-depth = <0x40>; + }; +For CAN FD Dts file: + canfd_0: canfd@40000000 { + compatible = "xlnx,canfd-1.0"; + clocks = <&clkc 0>, <&clkc 1>; + clock-names = "can_clk", "s_axi_aclk"; + reg = <0x40000000 0x2000>; + interrupt-parent = <&intc>; + interrupts = <0 59 1>; + tx-mailbox-count = <0x20>; + rx-fifo-depth = <0x20>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cavium-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/cavium-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..020df08b8a30f4df80766bb90e100ae6210a777b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cavium-mdio.txt @@ -0,0 +1,84 @@ +* System Management Interface (SMI) / MDIO + +Properties: +- compatible: One of: + + "cavium,octeon-3860-mdio": Compatibility with all cn3XXX, cn5XXX + and cn6XXX SOCs. + + "cavium,thunder-8890-mdio": Compatibility with all cn8XXX SOCs. + +- reg: The base address of the MDIO bus controller register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. MDIO addresses have no size component. + +Typically an MDIO bus might have several children. + +Example: + mdio@1180000001800 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001800 0x0 0x40>; + + ethernet-phy@0 { + ... + reg = <0>; + }; + }; + + +* System Management Interface (SMI) / MDIO Nexus + + Several mdio buses may be gathered as children of a single PCI + device, this PCI device is the nexus of the buses. + +Properties: + +- compatible: "cavium,thunder-8890-mdio-nexus"; + +- reg: The PCI device and function numbers of the nexus device. + +- #address-cells: Must be <2>. + +- #size-cells: Must be <2>. + +- ranges: As needed for mapping of the MDIO bus device registers. + +- assigned-addresses: As needed for mapping of the MDIO bus device registers. + +Example: + + mdio-nexus@1,3 { + compatible = "cavium,thunder-8890-mdio-nexus"; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0b00 0 0 0 0>; /* DEVFN = 0x0b (1:3) */ + assigned-addresses = <0x03000000 0x87e0 0x05000000 0x0 0x800000>; + ranges = <0x87e0 0x05000000 0x03000000 0x87e0 0x05000000 0x0 0x800000>; + + mdio0@87e0,05003800 { + compatible = "cavium,thunder-8890-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x87e0 0x05003800 0x0 0x30>; + + ethernet-phy@0 { + ... + reg = <0>; + }; + }; + mdio0@87e0,05003880 { + compatible = "cavium,thunder-8890-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x87e0 0x05003880 0x0 0x30>; + + ethernet-phy@0 { + ... + reg = <0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cavium-mix.txt b/arch/arm64/boot/dts/vendor/bindings/net/cavium-mix.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d7c3096390f59506552340b94bdba83dc717d30 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cavium-mix.txt @@ -0,0 +1,34 @@ +* MIX Ethernet controller. + +Properties: +- compatible: "cavium,octeon-5750-mix" + + Compatibility with all cn5XXX and cn6XXX SOCs populated with MIX + devices. + +- reg: The base addresses of four separate register banks. The first + bank contains the MIX registers. The second bank the corresponding + AGL registers. The third bank are the AGL registers shared by all + MIX devices present. The fourth bank is the AGL_PRT_CTL shared by + all MIX devices present. + +- cell-index: A single cell specifying which portion of the shared + register banks corresponds to this MIX device. + +- interrupts: Two interrupt specifiers. The first is the MIX + interrupt routing and the second the routing for the AGL interrupts. + +- phy-handle: Optional, see ethernet.txt file in the same directory. + +Example: + ethernet@1070000100800 { + compatible = "cavium,octeon-5750-mix"; + reg = <0x10700 0x00100800 0x0 0x100>, /* MIX */ + <0x11800 0xE0000800 0x0 0x300>, /* AGL */ + <0x11800 0xE0000400 0x0 0x400>, /* AGL_SHARED */ + <0x11800 0xE0002008 0x0 0x8>; /* AGL_PRT_CTL */ + cell-index = <1>; + interrupts = <1 18>, < 1 46>; + local-mac-address = [ 00 0f b7 10 63 54 ]; + phy-handle = <&phy1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cavium-pip.txt b/arch/arm64/boot/dts/vendor/bindings/net/cavium-pip.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3b8fe71762be70e0d071338827c59ecbdbe8c4f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cavium-pip.txt @@ -0,0 +1,99 @@ +* PIP Ethernet nexus. + +The PIP Ethernet nexus can control several data packet input/output +devices. The devices have a two level grouping scheme. There may be +several interfaces, and each interface may have several ports. These +ports might be an individual Ethernet PHY. + + +Properties for the PIP nexus: +- compatible: "cavium,octeon-3860-pip" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the PIP's register bank. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. + +Properties for PIP interfaces which is a child the PIP nexus: +- compatible: "cavium,octeon-3860-pip-interface" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The interface number. + +- #address-cells: Must be <1>. + +- #size-cells: Must be <0>. + +Properties for PIP port which is a child the PIP interface: +- compatible: "cavium,octeon-3860-pip-port" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The port number within the interface group. + +- phy-handle: Optional, see ethernet.txt file in the same directory. + +- rx-delay: Delay value for RGMII receive clock. Optional. Disabled if 0. + Value range is 1-31, and mapping to the actual delay varies depending on HW. + +- tx-delay: Delay value for RGMII transmit clock. Optional. Disabled if 0. + Value range is 1-31, and mapping to the actual delay varies depending on HW. + +Example: + + pip@11800a0000000 { + compatible = "cavium,octeon-3860-pip"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0xa0000000 0x0 0x2000>; + + interface@0 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 60 ]; + phy-handle = <&phy2>; + }; + ethernet@1 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x1>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 61 ]; + phy-handle = <&phy3>; + }; + ethernet@2 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x2>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 62 ]; + phy-handle = <&phy4>; + }; + ethernet@3 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x3>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 63 ]; + phy-handle = <&phy5>; + }; + }; + + interface@1 { + compatible = "cavium,octeon-3860-pip-interface"; + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; /* interface */ + + ethernet@0 { + compatible = "cavium,octeon-3860-pip-port"; + reg = <0x0>; /* Port */ + local-mac-address = [ 00 0f b7 10 63 64 ]; + phy-handle = <&phy6>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cirrus,cs89x0.txt b/arch/arm64/boot/dts/vendor/bindings/net/cirrus,cs89x0.txt new file mode 100644 index 0000000000000000000000000000000000000000..c070076bacb9cf7f86f0507301879b74c979b46d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cirrus,cs89x0.txt @@ -0,0 +1,13 @@ +* Cirrus Logic CS8900/CS8920 Network Controller + +Required properties: +- compatible : Should be "cirrus,cs8900" or "cirrus,cs8920". +- reg : Address and length of the IO space. +- interrupts : Should contain the controller interrupt line. + +Examples: + eth0: eth@10000000 { + compatible = "cirrus,cs8900"; + reg = <0x10000000 0x400>; + interrupts = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cortina,gemini-ethernet.txt b/arch/arm64/boot/dts/vendor/bindings/net/cortina,gemini-ethernet.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c559981d110d065dff607e3649c05337c04df34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cortina,gemini-ethernet.txt @@ -0,0 +1,92 @@ +Cortina Systems Gemini Ethernet Controller +========================================== + +This ethernet controller is found in the Gemini SoC family: +StorLink SL3512 and SL3516, also known as Cortina Systems +CS3512 and CS3516. + +Required properties: +- compatible: must be "cortina,gemini-ethernet" +- reg: must contain the global registers and the V-bit and A-bit + memory areas, in total three register sets. +- syscon: a phandle to the system controller +- #address-cells: must be specified, must be <1> +- #size-cells: must be specified, must be <1> +- ranges: should be state like this giving a 1:1 address translation + for the subnodes + +The subnodes represents the two ethernet ports in this device. +They are not independent of each other since they share resources +in the parent node, and are thus children. + +Required subnodes: +- port0: contains the resources for ethernet port 0 +- port1: contains the resources for ethernet port 1 + +Required subnode properties: +- compatible: must be "cortina,gemini-ethernet-port" +- reg: must contain two register areas: the DMA/TOE memory and + the GMAC memory area of the port +- interrupts: should contain the interrupt line of the port. + this is nominally a level interrupt active high. +- resets: this must provide an SoC-integrated reset line for + the port. +- clocks: this should contain a handle to the PCLK clock for + clocking the silicon in this port +- clock-names: must be "PCLK" + +Optional subnode properties: +- phy-mode: see ethernet.txt +- phy-handle: see ethernet.txt + +Example: + +mdio-bus { + (...) + phy0: ethernet-phy@1 { + reg = <1>; + device_type = "ethernet-phy"; + }; + phy1: ethernet-phy@3 { + reg = <3>; + device_type = "ethernet-phy"; + }; +}; + + +ethernet@60000000 { + compatible = "cortina,gemini-ethernet"; + reg = <0x60000000 0x4000>, /* Global registers, queue */ + <0x60004000 0x2000>, /* V-bit */ + <0x60006000 0x2000>; /* A-bit */ + syscon = <&syscon>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gmac0: ethernet-port@0 { + compatible = "cortina,gemini-ethernet-port"; + reg = <0x60008000 0x2000>, /* Port 0 DMA/TOE */ + <0x6000a000 0x2000>; /* Port 0 GMAC */ + interrupt-parent = <&intcon>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_GMAC0>; + clocks = <&syscon GEMINI_CLK_GATE_GMAC0>; + clock-names = "PCLK"; + phy-mode = "rgmii"; + phy-handle = <&phy0>; + }; + + gmac1: ethernet-port@1 { + compatible = "cortina,gemini-ethernet-port"; + reg = <0x6000c000 0x2000>, /* Port 1 DMA/TOE */ + <0x6000e000 0x2000>; /* Port 1 GMAC */ + interrupt-parent = <&intcon>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + resets = <&syscon GEMINI_RESET_GMAC1>; + clocks = <&syscon GEMINI_CLK_GATE_GMAC1>; + clock-names = "PCLK"; + phy-mode = "rgmii"; + phy-handle = <&phy1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cortina.txt b/arch/arm64/boot/dts/vendor/bindings/net/cortina.txt new file mode 100644 index 0000000000000000000000000000000000000000..40d0bd984113de4acf867654a01a057f04aa3dc0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cortina.txt @@ -0,0 +1,21 @@ +Cortina Phy Driver Device Tree Bindings +--------------------------------------- + +CORTINA is a registered trademark of Cortina Systems, Inc. + +The driver supports the Cortina Electronic Dispersion Compensation (EDC) +devices, equipped with clock and data recovery (CDR) circuits. These +devices make use of registers that are not compatible with Clause 45 or +Clause 22, therefore they need to be described using the +"ethernet-phy-id" compatible. + +Since the driver only implements polling mode support, interrupts info +can be skipped. + +Example (CS4340 phy): + mdio { + cs4340_phy@10 { + compatible = "ethernet-phy-id13e5.1002"; + reg = <0x10>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cpsw-phy-sel.txt b/arch/arm64/boot/dts/vendor/bindings/net/cpsw-phy-sel.txt new file mode 100644 index 0000000000000000000000000000000000000000..764c0c79b43d391435b847614c8d6c7aa4f06653 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cpsw-phy-sel.txt @@ -0,0 +1,30 @@ +TI CPSW Phy mode Selection Device Tree Bindings +----------------------------------------------- + +Required properties: +- compatible : Should be "ti,am3352-cpsw-phy-sel" for am335x platform and + "ti,dra7xx-cpsw-phy-sel" for dra7xx platform + "ti,am43xx-cpsw-phy-sel" for am43xx platform +- reg : physical base address and size of the cpsw + registers map +- reg-names : names of the register map given in "reg" node + +Optional properties: +-rmii-clock-ext : If present, the driver will configure the RMII + interface to external clock usage + +Examples: + + phy_sel: cpsw-phy-sel@44e10650 { + compatible = "ti,am3352-cpsw-phy-sel"; + reg= <0x44e10650 0x4>; + reg-names = "gmii-sel"; + }; + +(or) + phy_sel: cpsw-phy-sel@44e10650 { + compatible = "ti,am3352-cpsw-phy-sel"; + reg= <0x44e10650 0x4>; + reg-names = "gmii-sel"; + rmii-clock-ext; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/cpsw.txt b/arch/arm64/boot/dts/vendor/bindings/net/cpsw.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3acebe08eb0a9d4e3d4ac315cd513e340c65f16 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/cpsw.txt @@ -0,0 +1,124 @@ +TI SoC Ethernet Switch Controller Device Tree Bindings +------------------------------------------------------ + +Required properties: +- compatible : Should be one of the below:- + "ti,cpsw" for backward compatible + "ti,am335x-cpsw" for AM335x controllers + "ti,am4372-cpsw" for AM437x controllers + "ti,dra7-cpsw" for DRA7x controllers +- reg : physical base address and size of the cpsw + registers map +- interrupts : property with a value describing the interrupt + number +- cpdma_channels : Specifies number of channels in CPDMA +- ale_entries : Specifies No of entries ALE can hold +- bd_ram_size : Specifies internal descriptor RAM size +- mac_control : Specifies Default MAC control register content + for the specific platform +- slaves : Specifies number for slaves +- active_slave : Specifies the slave to use for time stamping, + ethtool and SIOCGMIIPHY +- cpsw-phy-sel : Specifies the phandle to the CPSW phy mode selection + device. See also cpsw-phy-sel.txt for it's binding. + Note that in legacy cases cpsw-phy-sel may be + a child device instead of a phandle. + +Optional properties: +- ti,hwmods : Must be "cpgmac0" +- dual_emac : Specifies Switch to act as Dual EMAC +- syscon : Phandle to the system control device node, which is + the control module device of the am33x +- mode-gpios : Should be added if one/multiple gpio lines are + required to be driven so that cpsw data lines + can be connected to the phy via selective mux. + For example in dra72x-evm, pcf gpio has to be + driven low so that cpsw slave 0 and phy data + lines are connected via mux. +- cpts_clock_mult : Numerator to convert input clock ticks into nanoseconds +- cpts_clock_shift : Denominator to convert input clock ticks into nanoseconds + Mult and shift will be calculated basing on CPTS + rftclk frequency if both cpts_clock_shift and + cpts_clock_mult properties are not provided. + +Slave Properties: +Required properties: +- phy-mode : See ethernet.txt file in the same directory + +Optional properties: +- dual_emac_res_vlan : Specifies VID to be used to segregate the ports +- mac-address : See ethernet.txt file in the same directory +- phy_id : Specifies slave phy id (deprecated, use phy-handle) +- phy-handle : See ethernet.txt file in the same directory + +Slave sub-nodes: +- fixed-link : See fixed-link.txt file in the same directory + +Note: Exactly one of phy_id, phy-handle, or fixed-link must be specified. + +Note: "ti,hwmods" field is used to fetch the base address and irq +resources from TI, omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples: + + mac: ethernet@4a100000 { + compatible = "ti,cpsw"; + reg = <0x4A100000 0x1000>; + interrupts = <55 0x4>; + interrupt-parent = <&intc>; + cpdma_channels = <8>; + ale_entries = <1024>; + bd_ram_size = <0x2000>; + rx_descs = <64>; + mac_control = <0x20>; + slaves = <2>; + active_slave = <0>; + cpts_clock_mult = <0x80000000>; + cpts_clock_shift = <29>; + syscon = <&cm>; + cpsw-phy-sel = <&phy_sel>; + cpsw_emac0: slave@0 { + phy_id = <&davinci_mdio>, <0>; + phy-mode = "rgmii-txid"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; + }; + cpsw_emac1: slave@1 { + phy_id = <&davinci_mdio>, <1>; + phy-mode = "rgmii-txid"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; + }; + }; + +(or) + mac: ethernet@4a100000 { + compatible = "ti,cpsw"; + ti,hwmods = "cpgmac0"; + cpdma_channels = <8>; + ale_entries = <1024>; + bd_ram_size = <0x2000>; + rx_descs = <64>; + mac_control = <0x20>; + slaves = <2>; + active_slave = <0>; + cpts_clock_mult = <0x80000000>; + cpts_clock_shift = <29>; + syscon = <&cm>; + cpsw-phy-sel = <&phy_sel>; + cpsw_emac0: slave@0 { + phy_id = <&davinci_mdio>, <0>; + phy-mode = "rgmii-txid"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; + }; + cpsw_emac1: slave@1 { + phy_id = <&davinci_mdio>, <1>; + phy-mode = "rgmii-txid"; + /* Filled in by U-Boot */ + mac-address = [ 00 00 00 00 00 00 ]; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/davicom-dm9000.txt b/arch/arm64/boot/dts/vendor/bindings/net/davicom-dm9000.txt new file mode 100644 index 0000000000000000000000000000000000000000..64c159e9cbf7709412e374ecc3c26d8fcc05aee2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/davicom-dm9000.txt @@ -0,0 +1,27 @@ +Davicom DM9000 Fast Ethernet controller + +Required properties: +- compatible = "davicom,dm9000"; +- reg : physical addresses and sizes of registers, must contain 2 entries: + first entry : address register, + second entry : data register. +- interrupts : interrupt specifier specific to interrupt controller + +Optional properties: +- davicom,no-eeprom : Configuration EEPROM is not available +- davicom,ext-phy : Use external PHY +- reset-gpios : phandle of gpio that will be used to reset chip during probe +- vcc-supply : phandle of regulator that will be used to enable power to chip + +Example: + + ethernet@18000000 { + compatible = "davicom,dm9000"; + reg = <0x18000000 0x2 0x18000004 0x2>; + interrupt-parent = <&gpn>; + interrupts = <7 4>; + local-mac-address = [00 00 de ad be ef]; + davicom,no-eeprom; + reset-gpios = <&gpf 12 GPIO_ACTIVE_LOW>; + vcc-supply = <ð0_power>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/davinci-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/davinci-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6527de80f10c0a0c5e3f5df8cf03ad425779656 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/davinci-mdio.txt @@ -0,0 +1,36 @@ +TI SoC Davinci/Keystone2 MDIO Controller Device Tree Bindings +--------------------------------------------------- + +Required properties: +- compatible : Should be "ti,davinci_mdio" + and "ti,keystone_mdio" for Keystone 2 SoCs + and "ti,cpsw-mdio" for am335x, am472x, am57xx/dra7, dm814x SoCs + and "ti,am4372-mdio" for am472x SoC +- reg : physical base address and size of the davinci mdio + registers map +- bus_freq : Mdio Bus frequency + +Optional properties: +- ti,hwmods : Must be "davinci_mdio" + +Note: "ti,hwmods" field is used to fetch the base address and irq +resources from TI, omap hwmod data base during device registration. +Future plan is to migrate hwmod data base contents into device tree +blob so that, all the required data will be used from device tree dts +file. + +Examples: + + mdio: davinci_mdio@4a101000 { + compatible = "ti,davinci_mdio"; + reg = <0x4A101000 0x1000>; + bus_freq = <1000000>; + }; + +(or) + + mdio: davinci_mdio@4a101000 { + compatible = "ti,davinci_mdio"; + ti,hwmods = "davinci_mdio"; + bus_freq = <1000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/davinci_emac.txt b/arch/arm64/boot/dts/vendor/bindings/net/davinci_emac.txt new file mode 100644 index 0000000000000000000000000000000000000000..24c5cdaba8d279a4b132fbd2f964ae1460b3fd0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/davinci_emac.txt @@ -0,0 +1,41 @@ +* Texas Instruments Davinci EMAC + +This file provides information, what the device node +for the davinci_emac interface contains. + +Required properties: +- compatible: "ti,davinci-dm6467-emac", "ti,am3517-emac" or + "ti,dm816-emac" +- reg: Offset and length of the register set for the device +- ti,davinci-ctrl-reg-offset: offset to control register +- ti,davinci-ctrl-mod-reg-offset: offset to control module register +- ti,davinci-ctrl-ram-offset: offset to control module ram +- ti,davinci-ctrl-ram-size: size of control module ram +- interrupts: interrupt mapping for the davinci emac interrupts sources: + 4 sources: + +Optional properties: +- phy-handle: See ethernet.txt file in the same directory. + If absent, davinci_emac driver defaults to 100/FULL. +- ti,davinci-rmii-en: 1 byte, 1 means use RMII +- ti,davinci-no-bd-ram: boolean, does EMAC have BD RAM? + +Example (enbw_cmc board): + eth0: emac@1e20000 { + compatible = "ti,davinci-dm6467-emac"; + reg = <0x220000 0x4000>; + ti,davinci-ctrl-reg-offset = <0x3000>; + ti,davinci-ctrl-mod-reg-offset = <0x2000>; + ti,davinci-ctrl-ram-offset = <0>; + ti,davinci-ctrl-ram-size = <0x2000>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <33 + 34 + 35 + 36 + >; + interrupt-parent = <&intc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/b53.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/b53.txt new file mode 100644 index 0000000000000000000000000000000000000000..1811e1972a7a1c9a162d51b5997bf36279a8a3ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/b53.txt @@ -0,0 +1,109 @@ +Broadcom BCM53xx Ethernet switches +================================== + +Required properties: + +- compatible: For external switch chips, compatible string must be exactly one + of: "brcm,bcm5325" + "brcm,bcm53115" + "brcm,bcm53125" + "brcm,bcm53128" + "brcm,bcm5365" + "brcm,bcm5395" + "brcm,bcm5389" + "brcm,bcm5397" + "brcm,bcm5398" + + For the BCM11360 SoC, must be: + "brcm,bcm11360-srab" and the mandatory "brcm,cygnus-srab" string + + For the BCM5310x SoCs with an integrated switch, must be one of: + "brcm,bcm53010-srab" + "brcm,bcm53011-srab" + "brcm,bcm53012-srab" + "brcm,bcm53018-srab" + "brcm,bcm53019-srab" and the mandatory "brcm,bcm5301x-srab" string + + For the BCM5831X/BCM1140x SoCs with an integrated switch, must be one of: + "brcm,bcm11404-srab" + "brcm,bcm11407-srab" + "brcm,bcm11409-srab" + "brcm,bcm58310-srab" + "brcm,bcm58311-srab" + "brcm,bcm58313-srab" and the mandatory "brcm,omega-srab" string + + For the BCM585xx/586XX/88312 SoCs with an integrated switch, must be one of: + "brcm,bcm58522-srab" + "brcm,bcm58523-srab" + "brcm,bcm58525-srab" + "brcm,bcm58622-srab" + "brcm,bcm58623-srab" + "brcm,bcm58625-srab" + "brcm,bcm88312-srab" and the mandatory "brcm,nsp-srab string + + For the BCM63xx/33xx SoCs with an integrated switch, must be one of: + "brcm,bcm3384-switch" + "brcm,bcm6328-switch" + "brcm,bcm6368-switch" and the mandatory "brcm,bcm63xx-switch" + +See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional +required and optional properties. + +Examples: + +Ethernet switch connected via MDIO to the host, CPU port wired to eth0: + + eth0: ethernet@10001000 { + compatible = "brcm,unimac"; + reg = <0x10001000 0x1000>; + + fixed-link { + speed = <1000>; + duplex-full; + }; + }; + + mdio0: mdio@10000000 { + compatible = "brcm,unimac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + switch0: ethernet-switch@30 { + compatible = "brcm,bcm53125"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + port0@0 { + reg = <0>; + label = "lan1"; + }; + + port1@1 { + reg = <1>; + label = "lan2"; + }; + + port5@5 { + reg = <5>; + label = "cable-modem"; + fixed-link { + speed = <1000>; + duplex-full; + }; + phy-mode = "rgmii-txid"; + }; + + port8@8 { + reg = <8>; + label = "cpu"; + fixed-link { + speed = <1000>; + duplex-full; + }; + phy-mode = "rgmii-txid"; + ethernet = <ð0>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/dsa.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/dsa.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ceeb8de11963572cc1bd8ce324433e0dbf6bd03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/dsa.txt @@ -0,0 +1,408 @@ +Distributed Switch Architecture Device Tree Bindings +---------------------------------------------------- + +Two bindings exist, one of which has been deprecated due to +limitations. + +Current Binding +--------------- + +Switches are true Linux devices and can be probes by any means. Once +probed, they register to the DSA framework, passing a node +pointer. This node is expected to fulfil the following binding, and +may contain additional properties as required by the device it is +embedded within. + +Required properties: + +- ports : A container for child nodes representing switch ports. + +Optional properties: + +- dsa,member : A two element list indicates which DSA cluster, and position + within the cluster a switch takes. <0 0> is cluster 0, + switch 0. <0 1> is cluster 0, switch 1. <1 0> is cluster 1, + switch 0. A switch not part of any cluster (single device + hanging off a CPU port) must not specify this property + +The ports container has the following properties + +Required properties: + +- #address-cells : Must be 1 +- #size-cells : Must be 0 + +Each port children node must have the following mandatory properties: +- reg : Describes the port address in the switch + +An uplink/downlink port between switches in the cluster has the following +mandatory property: + +- link : Should be a list of phandles to other switch's DSA + port. This port is used as the outgoing port + towards the phandle ports. The full routing + information must be given, not just the one hop + routes to neighbouring switches. + +A CPU port has the following mandatory property: + +- ethernet : Should be a phandle to a valid Ethernet device node. + This host device is what the switch port is + connected to. + +A user port has the following optional property: + +- label : Describes the label associated with this port, which + will become the netdev name. + +Port child nodes may also contain the following optional standardised +properties, described in binding documents: + +- phy-handle : Phandle to a PHY on an MDIO bus. See + Documentation/devicetree/bindings/net/ethernet.txt + for details. + +- phy-mode : See + Documentation/devicetree/bindings/net/ethernet.txt + for details. + +- fixed-link : Fixed-link subnode describing a link to a non-MDIO + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. + +Example + +The following example shows three switches on three MDIO busses, +linked into one DSA cluster. + +&mdio1 { + #address-cells = <1>; + #size-cells = <0>; + + switch0: switch0@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + + dsa,member = <0 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + label = "lan0"; + }; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + switch0port5: port@5 { + reg = <5>; + phy-mode = "rgmii-txid"; + link = <&switch1port6 + &switch2port9>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + port@6 { + reg = <6>; + ethernet = <&fec1>; + fixed-link { + speed = <100>; + full-duplex; + }; + }; + }; + }; +}; + +&mdio2 { + #address-cells = <1>; + #size-cells = <0>; + + switch1: switch1@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + + dsa,member = <0 1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + label = "lan3"; + phy-handle = <&switch1phy0>; + }; + + port@1 { + reg = <1>; + label = "lan4"; + phy-handle = <&switch1phy1>; + }; + + port@2 { + reg = <2>; + label = "lan5"; + phy-handle = <&switch1phy2>; + }; + + switch1port5: port@5 { + reg = <5>; + link = <&switch2port9>; + phy-mode = "rgmii-txid"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + switch1port6: port@6 { + reg = <6>; + phy-mode = "rgmii-txid"; + link = <&switch0port5>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + }; + switch1phy1: switch1phy0@1 { + reg = <1>; + }; + switch1phy2: switch1phy0@2 { + reg = <2>; + }; + }; + }; +}; + +&mdio4 { + #address-cells = <1>; + #size-cells = <0>; + + switch2: switch2@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + + dsa,member = <0 2>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + label = "lan6"; + }; + + port@1 { + reg = <1>; + label = "lan7"; + }; + + port@2 { + reg = <2>; + label = "lan8"; + }; + + port@3 { + reg = <3>; + label = "optical3"; + fixed-link { + speed = <1000>; + full-duplex; + link-gpios = <&gpio6 2 + GPIO_ACTIVE_HIGH>; + }; + }; + + port@4 { + reg = <4>; + label = "optical4"; + fixed-link { + speed = <1000>; + full-duplex; + link-gpios = <&gpio6 3 + GPIO_ACTIVE_HIGH>; + }; + }; + + switch2port9: port@9 { + reg = <9>; + phy-mode = "rgmii-txid"; + link = <&switch1port5 + &switch0port5>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; +}; + +Deprecated Binding +------------------ + +The deprecated binding makes use of a platform device to represent the +switches. The switches themselves are not Linux devices, and make use +of an MDIO bus for management. + +Required properties: +- compatible : Should be "marvell,dsa" +- #address-cells : Must be 2, first cell is the address on the MDIO bus + and second cell is the address in the switch tree. + Second cell is used only when cascading/chaining. +- #size-cells : Must be 0 +- dsa,ethernet : Should be a phandle to a valid Ethernet device node +- dsa,mii-bus : Should be a phandle to a valid MDIO bus device node + +Optional properties: +- interrupts : property with a value describing the switch + interrupt number (not supported by the driver) + +A DSA node can contain multiple switch chips which are therefore child nodes of +the parent DSA node. The maximum number of allowed child nodes is 4 +(DSA_MAX_SWITCHES). +Each of these switch child nodes should have the following required properties: + +- reg : Contains two fields. The first one describes the + address on the MII bus. The second is the switch + number that must be unique in cascaded configurations +- #address-cells : Must be 1 +- #size-cells : Must be 0 + +A switch child node has the following optional property: + +- eeprom-length : Set to the length of an EEPROM connected to the + switch. Must be set if the switch can not detect + the presence and/or size of a connected EEPROM, + otherwise optional. + +A switch may have multiple "port" children nodes + +Each port children node must have the following mandatory properties: +- reg : Describes the port address in the switch +- label : Describes the label associated with this port, special + labels are "cpu" to indicate a CPU port and "dsa" to + indicate an uplink/downlink port. + +Note that a port labelled "dsa" will imply checking for the uplink phandle +described below. + +Optional property: +- link : Should be a list of phandles to another switch's DSA port. + This property is only used when switches are being + chained/cascaded together. This port is used as outgoing port + towards the phandle port, which can be more than one hop away. + +- phy-handle : Phandle to a PHY on an external MDIO bus, not the + switch internal one. See + Documentation/devicetree/bindings/net/ethernet.txt + for details. + +- phy-mode : String representing the connection to the designated + PHY node specified by the 'phy-handle' property. See + Documentation/devicetree/bindings/net/ethernet.txt + for details. + +- mii-bus : Should be a phandle to a valid MDIO bus device node. + This mii-bus will be used in preference to the + global dsa,mii-bus defined above, for this switch. + +Optional subnodes: +- fixed-link : Fixed-link subnode describing a link to a non-MDIO + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. + +Example: + + dsa@0 { + compatible = "marvell,dsa"; + #address-cells = <2>; + #size-cells = <0>; + + interrupts = <10>; + dsa,ethernet = <ðernet0>; + dsa,mii-bus = <&mii_bus0>; + + switch@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <16 0>; /* MDIO address 16, switch 0 in tree */ + + port@0 { + reg = <0>; + label = "lan1"; + phy-handle = <&phy0>; + }; + + port@1 { + reg = <1>; + label = "lan2"; + }; + + port@5 { + reg = <5>; + label = "cpu"; + }; + + switch0port6: port@6 { + reg = <6>; + label = "dsa"; + link = <&switch1port0 + &switch2port0>; + }; + }; + + switch@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <17 1>; /* MDIO address 17, switch 1 in tree */ + mii-bus = <&mii_bus1>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + switch1port0: port@0 { + reg = <0>; + label = "dsa"; + link = <&switch0port6>; + }; + switch1port1: port@1 { + reg = <1>; + label = "dsa"; + link = <&switch2port1>; + }; + }; + + switch@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <18 2>; /* MDIO address 18, switch 2 in tree */ + mii-bus = <&mii_bus1>; + + switch2port0: port@0 { + reg = <0>; + label = "dsa"; + link = <&switch1port1 + &switch0port6>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/ksz.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/ksz.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac145b885e955336a533469b82c5cc1e9af9f72d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/ksz.txt @@ -0,0 +1,72 @@ +Microchip KSZ Series Ethernet switches +================================== + +Required properties: + +- compatible: For external switch chips, compatible string must be exactly one + of the following: + - "microchip,ksz9477" + - "microchip,ksz9897" + +See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional +required and optional properties. + +Examples: + +Ethernet switch connected via SPI to the host, CPU port wired to eth0: + + eth0: ethernet@10001000 { + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + spi1: spi@f8008000 { + pinctrl-0 = <&pinctrl_spi_ksz>; + cs-gpios = <&pioC 25 0>; + id = <1>; + + ksz9477: ksz9477@0 { + compatible = "microchip,ksz9477"; + reg = <0>; + + spi-max-frequency = <44000000>; + spi-cpha; + spi-cpol; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + label = "lan1"; + }; + port@1 { + reg = <1>; + label = "lan2"; + }; + port@2 { + reg = <2>; + label = "lan3"; + }; + port@3 { + reg = <3>; + label = "lan4"; + }; + port@4 { + reg = <4>; + label = "lan5"; + }; + port@5 { + reg = <5>; + label = "cpu"; + ethernet = <ð0>; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/lan9303.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/lan9303.txt new file mode 100644 index 0000000000000000000000000000000000000000..464d6bf87605392a5302349abf7b54e673ed5dc1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/lan9303.txt @@ -0,0 +1,102 @@ +SMSC/MicroChip LAN9303 three port ethernet switch +------------------------------------------------- + +Required properties: + +- compatible: should be + - "smsc,lan9303-i2c" for I2C managed mode + or + - "smsc,lan9303-mdio" for mdio managed mode + +Optional properties: + +- reset-gpios: GPIO to be used to reset the whole device +- reset-duration: reset duration in milliseconds, defaults to 200 ms + +Subnodes: + +The integrated switch subnode should be specified according to the binding +described in dsa/dsa.txt. The CPU port of this switch is always port 0. + +Note: always use 'reg = <0/1/2>;' for the three DSA ports, even if the device is +configured to use 1/2/3 instead. This hardware configuration will be +auto-detected and mapped accordingly. + +Example: + +I2C managed mode: + + master: masterdevice@X { + + fixed-link { /* RMII fixed link to LAN9303 */ + speed = <100>; + full-duplex; + }; + }; + + switch: switch@a { + compatible = "smsc,lan9303-i2c"; + reg = <0xa>; + reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>; + reset-duration = <200>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { /* RMII fixed link to master */ + reg = <0>; + label = "cpu"; + ethernet = <&master>; + }; + + port@1 { /* external port 1 */ + reg = <1>; + label = "lan1"; + }; + + port@2 { /* external port 2 */ + reg = <2>; + label = "lan2"; + }; + }; + }; + +MDIO managed mode: + + master: masterdevice@X { + phy-handle = <&switch>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch: switch-phy@0 { + compatible = "smsc,lan9303-mdio"; + reg = <0>; + reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>; + reset-duration = <100>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "cpu"; + ethernet = <&master>; + }; + + port@1 { /* external port 1 */ + reg = <1>; + label = "lan1"; + }; + + port@2 { /* external port 2 */ + reg = <2>; + label = "lan2"; + }; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/marvell.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/marvell.txt new file mode 100644 index 0000000000000000000000000000000000000000..feb007af13cbef05bb53169437ef7980ac0bdeeb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/marvell.txt @@ -0,0 +1,106 @@ +Marvell DSA Switch Device Tree Bindings +--------------------------------------- + +WARNING: This binding is currently unstable. Do not program it into a +FLASH never to be changed again. Once this binding is stable, this +warning will be removed. + +If you need a stable binding, use the old dsa.txt binding. + +Marvell Switches are MDIO devices. The following properties should be +placed as a child node of an mdio device. + +The properties described here are those specific to Marvell devices. +Additional required and optional properties can be found in dsa.txt. + +The compatibility string is used only to find an identification register, +which is at a different MDIO base address in different switch families. +- "marvell,mv88e6085" : Switch has base address 0x10. Use with models: + 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, + 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, + 6341, 6350, 6351, 6352 +- "marvell,mv88e6190" : Switch has base address 0x00. Use with models: + 6190, 6190X, 6191, 6290, 6390, 6390X + +Required properties: +- compatible : Should be one of "marvell,mv88e6085" or + "marvell,mv88e6190" as indicated above +- reg : Address on the MII bus for the switch. + +Optional properties: + +- reset-gpios : Should be a gpio specifier for a reset line +- interrupts : Interrupt from the switch +- interrupt-controller : Indicates the switch is itself an interrupt + controller. This is used for the PHY interrupts. +#interrupt-cells = <2> : Controller uses two cells, number and flag +- eeprom-length : Set to the length of an EEPROM connected to the + switch. Must be set if the switch can not detect + the presence and/or size of a connected EEPROM, + otherwise optional. +- mdio : Container of PHY and devices on the switches MDIO + bus. +- mdio? : Container of PHYs and devices on the external MDIO + bus. The node must contains a compatible string of + "marvell,mv88e6xxx-mdio-external" + +Example: + + mdio { + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + switch0: switch@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + interrupt-parent = <&switch0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + }; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <2>; + + switch0: switch@0 { + compatible = "marvell,mv88e6390"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + switch1phy0: switch1phy0@0 { + reg = <0>; + interrupt-parent = <&switch0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + mdio1 { + compatible = "marvell,mv88e6xxx-mdio-external"; + #address-cells = <1>; + #size-cells = <0>; + switch1phy9: switch1phy0@9 { + reg = <9>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/mt7530.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/mt7530.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa3527f71fdc7ee9377b95fba69adad5d2264955 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/mt7530.txt @@ -0,0 +1,92 @@ +Mediatek MT7530 Ethernet switch +================================ + +Required properties: + +- compatible: Must be compatible = "mediatek,mt7530"; +- #address-cells: Must be 1. +- #size-cells: Must be 0. +- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part + on multi-chip module belong to MT7623A has or the remotely standalone + chip as the function MT7623N reference board provided for. +- core-supply: Phandle to the regulator node necessary for the core power. +- io-supply: Phandle to the regulator node necessary for the I/O power. + See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt + for details for the regulator setup on these boards. + +If the property mediatek,mcm isn't defined, following property is required + +- reset-gpios: Should be a gpio specifier for a reset line. + +Else, following properties are required + +- resets : Phandle pointing to the system reset controller with + line index for the ethsys. +- reset-names : Should be set to "mcm". + +Required properties for the child nodes within ports container: + +- reg: Port address described must be 6 for CPU port and from 0 to 5 for + user ports. +- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled + "cpu". + +See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional +required, optional properties and how the integrated switch subnodes must +be specified. + +Example: + + &mdio0 { + switch@0 { + compatible = "mediatek,mt7530"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + core-supply = <&mt6323_vpa_reg>; + io-supply = <&mt6323_vemc3v3_reg>; + reset-gpios = <&pio 33 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + port@0 { + reg = <0>; + label = "lan0"; + }; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + + port@4 { + reg = <4>; + label = "wan"; + }; + + port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac0>; + phy-mode = "trgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/qca8k.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/qca8k.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbcb255c3150230978fba796b320a71c206ddbad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/qca8k.txt @@ -0,0 +1,110 @@ +* Qualcomm Atheros QCA8xxx switch family + +Required properties: + +- compatible: should be one of: + "qca,qca8334" + "qca,qca8337" + +- #size-cells: must be 0 +- #address-cells: must be 1 + +Subnodes: + +The integrated switch subnode should be specified according to the binding +described in dsa/dsa.txt. As the QCA8K switches do not have a N:N mapping of +port and PHY id, each subnode describing a port needs to have a valid phandle +referencing the internal PHY connected to it. The CPU port of this switch is +always port 0. + +A CPU port node has the following optional node: + +- fixed-link : Fixed-link subnode describing a link to a non-MDIO + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. + +For QCA8K the 'fixed-link' sub-node supports only the following properties: + +- 'speed' (integer, mandatory), to indicate the link speed. Accepted + values are 10, 100 and 1000 +- 'full-duplex' (boolean, optional), to indicate that full duplex is + used. When absent, half duplex is assumed. + +Example: + + + &mdio0 { + phy_port1: phy@0 { + reg = <0>; + }; + + phy_port2: phy@1 { + reg = <1>; + }; + + phy_port3: phy@2 { + reg = <2>; + }; + + phy_port4: phy@3 { + reg = <3>; + }; + + phy_port5: phy@4 { + reg = <4>; + }; + + switch0@0 { + compatible = "qca,qca8337"; + #address-cells = <1>; + #size-cells = <0>; + + reg = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + label = "cpu"; + ethernet = <&gmac1>; + phy-mode = "rgmii"; + fixed-link { + speed = 1000; + full-duplex; + }; + }; + + port@1 { + reg = <1>; + label = "lan1"; + phy-handle = <&phy_port1>; + }; + + port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&phy_port2>; + }; + + port@3 { + reg = <3>; + label = "lan3"; + phy-handle = <&phy_port3>; + }; + + port@4 { + reg = <4>; + label = "lan4"; + phy-handle = <&phy_port4>; + }; + + port@5 { + reg = <5>; + label = "wan"; + phy-handle = <&phy_port5>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/realtek-smi.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/realtek-smi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6ae8541bd55983212eb9e7a80b1ca0a9220526d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/realtek-smi.txt @@ -0,0 +1,153 @@ +Realtek SMI-based Switches +========================== + +The SMI "Simple Management Interface" is a two-wire protocol using +bit-banged GPIO that while it reuses the MDIO lines MCK and MDIO does +not use the MDIO protocol. This binding defines how to specify the +SMI-based Realtek devices. + +Required properties: + +- compatible: must be exactly one of: + "realtek,rtl8366" + "realtek,rtl8366rb" (4+1 ports) + "realtek,rtl8366s" (4+1 ports) + "realtek,rtl8367" + "realtek,rtl8367b" + "realtek,rtl8368s" (8 port) + "realtek,rtl8369" + "realtek,rtl8370" (8 port) + +Required properties: +- mdc-gpios: GPIO line for the MDC clock line. +- mdio-gpios: GPIO line for the MDIO data line. +- reset-gpios: GPIO line for the reset signal. + +Optional properties: +- realtek,disable-leds: if the LED drivers are not used in the + hardware design this will disable them so they are not turned on + and wasting power. + +Required subnodes: + +- interrupt-controller + + This defines an interrupt controller with an IRQ line (typically + a GPIO) that will demultiplex and handle the interrupt from the single + interrupt line coming out of one of the SMI-based chips. It most + importantly provides link up/down interrupts to the PHY blocks inside + the ASIC. + +Required properties of interrupt-controller: + +- interrupt: parent interrupt, see interrupt-controller/interrupts.txt +- interrupt-controller: see interrupt-controller/interrupts.txt +- #address-cells: should be <0> +- #interrupt-cells: should be <1> + +- mdio + + This defines the internal MDIO bus of the SMI device, mostly for the + purpose of being able to hook the interrupts to the right PHY and + the right PHY to the corresponding port. + +Required properties of mdio: + +- compatible: should be set to "realtek,smi-mdio" for all SMI devices + +See net/mdio.txt for additional MDIO bus properties. + +See net/dsa/dsa.txt for a list of additional required and optional properties +and subnodes of DSA switches. + +Examples: + +switch { + compatible = "realtek,rtl8366rb"; + /* 22 = MDIO (has input reads), 21 = MDC (clock, output only) */ + mdc-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + mdio-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + + switch_intc: interrupt-controller { + /* GPIO 15 provides the interrupt */ + interrupt-parent = <&gpio0>; + interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + port@0 { + reg = <0>; + label = "lan0"; + phy-handle = <&phy0>; + }; + port@1 { + reg = <1>; + label = "lan1"; + phy-handle = <&phy1>; + }; + port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&phy2>; + }; + port@3 { + reg = <3>; + label = "lan3"; + phy-handle = <&phy3>; + }; + port@4 { + reg = <4>; + label = "wan"; + phy-handle = <&phy4>; + }; + port@5 { + reg = <5>; + label = "cpu"; + ethernet = <&gmac0>; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + + mdio { + compatible = "realtek,smi-mdio", "dsa-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + phy0: phy@0 { + reg = <0>; + interrupt-parent = <&switch_intc>; + interrupts = <0>; + }; + phy1: phy@1 { + reg = <1>; + interrupt-parent = <&switch_intc>; + interrupts = <1>; + }; + phy2: phy@2 { + reg = <2>; + interrupt-parent = <&switch_intc>; + interrupts = <2>; + }; + phy3: phy@3 { + reg = <3>; + interrupt-parent = <&switch_intc>; + interrupts = <3>; + }; + phy4: phy@4 { + reg = <4>; + interrupt-parent = <&switch_intc>; + interrupts = <12>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dsa/vitesse,vsc73xx.txt b/arch/arm64/boot/dts/vendor/bindings/net/dsa/vitesse,vsc73xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed4710c406415428b03824a1e40844f4489a7af3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dsa/vitesse,vsc73xx.txt @@ -0,0 +1,81 @@ +Vitesse VSC73xx Switches +======================== + +This defines device tree bindings for the Vitesse VSC73xx switch chips. +The Vitesse company has been acquired by Microsemi and Microsemi in turn +acquired by Microchip but retains this vendor branding. + +The currently supported switch chips are: +Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch +Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch +Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch +Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch + +The device tree node is an SPI device so it must reside inside a SPI bus +device tree node, see spi/spi-bus.txt + +Required properties: + +- compatible: must be exactly one of: + "vitesse,vsc7385" + "vitesse,vsc7388" + "vitesse,vsc7395" + "vitesse,vsc7398" +- gpio-controller: indicates that this switch is also a GPIO controller, + see gpio/gpio.txt +- #gpio-cells: this must be set to <2> and indicates that we are a twocell + GPIO controller, see gpio/gpio.txt + +Optional properties: + +- reset-gpios: a handle to a GPIO line that can issue reset of the chip. + It should be tagged as active low. + +Required subnodes: + +See net/dsa/dsa.txt for a list of additional required and optional properties +and subnodes of DSA switches. + +Examples: + +switch@0 { + compatible = "vitesse,vsc7395"; + reg = <0>; + /* Specified for 2.5 MHz or below */ + spi-max-frequency = <2500000>; + gpio-controller; + #gpio-cells = <2>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan1"; + }; + port@1 { + reg = <1>; + label = "lan2"; + }; + port@2 { + reg = <2>; + label = "lan3"; + }; + port@3 { + reg = <3>; + label = "lan4"; + }; + vsc: port@6 { + reg = <6>; + label = "cpu"; + ethernet = <&gmac1>; + phy-mode = "rgmii"; + fixed-link { + speed = <1000>; + full-duplex; + pause; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/dwmac-sun8i.txt b/arch/arm64/boot/dts/vendor/bindings/net/dwmac-sun8i.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bb3a18cc38db84cb04be2c6bf081842e762a3ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/dwmac-sun8i.txt @@ -0,0 +1,200 @@ +* Allwinner sun8i GMAC ethernet controller + +This device is a platform glue layer for stmmac. +Please see stmmac.txt for the other unchanged properties. + +Required properties: +- compatible: must be one of the following string: + "allwinner,sun8i-a83t-emac" + "allwinner,sun8i-h3-emac" + "allwinner,sun8i-r40-gmac" + "allwinner,sun8i-v3s-emac" + "allwinner,sun50i-a64-emac" +- reg: address and length of the register for the device. +- interrupts: interrupt for the device +- interrupt-names: must be "macirq" +- clocks: A phandle to the reference clock for this device +- clock-names: must be "stmmaceth" +- resets: A phandle to the reset control for this device +- reset-names: must be "stmmaceth" +- phy-mode: See ethernet.txt +- phy-handle: See ethernet.txt +- syscon: A phandle to the device containing the EMAC or GMAC clock register + +Optional properties: +- allwinner,tx-delay-ps: TX clock delay chain value in ps. + Range is 0-700. Default is 0. + Unavailable for allwinner,sun8i-r40-gmac +- allwinner,rx-delay-ps: RX clock delay chain value in ps. + Range is 0-3100. Default is 0. + Range is 0-700 for allwinner,sun8i-r40-gmac +Both delay properties need to be a multiple of 100. They control the +clock delay for external RGMII PHY. They do not apply to the internal +PHY or external non-RGMII PHYs. + +Optional properties for the following compatibles: + - "allwinner,sun8i-h3-emac", + - "allwinner,sun8i-v3s-emac": +- allwinner,leds-active-low: EPHY LEDs are active low + +Required child node of emac: +- mdio bus node: should be named mdio with compatible "snps,dwmac-mdio" + +Required properties of the mdio node: +- #address-cells: shall be 1 +- #size-cells: shall be 0 + +The device node referenced by "phy" or "phy-handle" must be a child node +of the mdio node. See phy.txt for the generic PHY bindings. + +The following compatibles require that the emac node have a mdio-mux child +node called "mdio-mux": + - "allwinner,sun8i-h3-emac" + - "allwinner,sun8i-v3s-emac": +Required properties for the mdio-mux node: + - compatible = "allwinner,sun8i-h3-mdio-mux" + - mdio-parent-bus: a phandle to EMAC mdio + - one child mdio for the integrated mdio with the compatible + "allwinner,sun8i-h3-mdio-internal" + - one child mdio for the external mdio if present (V3s have none) +Required properties for the mdio-mux children node: + - reg: 1 for internal MDIO bus, 2 for external MDIO bus + +The following compatibles require a PHY node representing the integrated +PHY, under the integrated MDIO bus node if an mdio-mux node is used: + - "allwinner,sun8i-h3-emac", + - "allwinner,sun8i-v3s-emac": + +Additional information regarding generic multiplexer properties can be found +at Documentation/devicetree/bindings/net/mdio-mux.txt + +Required properties of the integrated phy node: +- clocks: a phandle to the reference clock for the EPHY +- resets: a phandle to the reset control for the EPHY +- Must be a child of the integrated mdio + +Example with integrated PHY: +emac: ethernet@1c0b000 { + compatible = "allwinner,sun8i-h3-emac"; + syscon = <&syscon>; + reg = <0x01c0b000 0x104>; + interrupts = ; + interrupt-names = "macirq"; + resets = <&ccu RST_BUS_EMAC>; + reset-names = "stmmaceth"; + clocks = <&ccu CLK_BUS_EMAC>; + clock-names = "stmmaceth"; + + phy-handle = <&int_mii_phy>; + phy-mode = "mii"; + allwinner,leds-active-low; + + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + }; + + mdio-mux { + compatible = "mdio-mux", "allwinner,sun8i-h3-mdio-mux"; + #address-cells = <1>; + #size-cells = <0>; + + mdio-parent-bus = <&mdio>; + + int_mdio: mdio@1 { + compatible = "allwinner,sun8i-h3-mdio-internal"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + int_mii_phy: ethernet-phy@1 { + reg = <1>; + clocks = <&ccu CLK_BUS_EPHY>; + resets = <&ccu RST_BUS_EPHY>; + phy-is-integrated; + }; + }; + ext_mdio: mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +Example with external PHY: +emac: ethernet@1c0b000 { + compatible = "allwinner,sun8i-h3-emac"; + syscon = <&syscon>; + reg = <0x01c0b000 0x104>; + interrupts = ; + interrupt-names = "macirq"; + resets = <&ccu RST_BUS_EMAC>; + reset-names = "stmmaceth"; + clocks = <&ccu CLK_BUS_EMAC>; + clock-names = "stmmaceth"; + + phy-handle = <&ext_rgmii_phy>; + phy-mode = "rgmii"; + allwinner,leds-active-low; + + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + }; + + mdio-mux { + compatible = "allwinner,sun8i-h3-mdio-mux"; + #address-cells = <1>; + #size-cells = <0>; + + mdio-parent-bus = <&mdio>; + + int_mdio: mdio@1 { + compatible = "allwinner,sun8i-h3-mdio-internal"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + int_mii_phy: ethernet-phy@1 { + reg = <1>; + clocks = <&ccu CLK_BUS_EPHY>; + resets = <&ccu RST_BUS_EPHY>; + }; + }; + ext_mdio: mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + ext_rgmii_phy: ethernet-phy@1 { + reg = <1>; + }; + }: + }; +}; + +Example with SoC without integrated PHY + +emac: ethernet@1c0b000 { + compatible = "allwinner,sun8i-a83t-emac"; + syscon = <&syscon>; + reg = <0x01c0b000 0x104>; + interrupts = ; + interrupt-names = "macirq"; + resets = <&ccu RST_BUS_EMAC>; + reset-names = "stmmaceth"; + clocks = <&ccu CLK_BUS_EMAC>; + clock-names = "stmmaceth"; + + phy-handle = <&ext_rgmii_phy>; + phy-mode = "rgmii"; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + ext_rgmii_phy: ethernet-phy@1 { + reg = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/emac_rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/net/emac_rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..05bd7dafce171fda64d9dd18cad4bdef1dcd8902 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/emac_rockchip.txt @@ -0,0 +1,52 @@ +* ARC EMAC 10/100 Ethernet platform driver for Rockchip RK3036/RK3066/RK3188 SoCs + +Required properties: +- compatible: should be "rockchip,-emac" + "rockchip,rk3036-emac": found on RK3036 SoCs + "rockchip,rk3066-emac": found on RK3066 SoCs + "rockchip,rk3188-emac": found on RK3188 SoCs +- reg: Address and length of the register set for the device +- interrupts: Should contain the EMAC interrupts +- rockchip,grf: phandle to the syscon grf used to control speed and mode + for emac. +- phy: see ethernet.txt file in the same directory. +- phy-mode: see ethernet.txt file in the same directory. + +Optional properties: +- phy-supply: phandle to a regulator if the PHY needs one + +Clock handling: +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Shall be "hclk" for the host clock needed to calculate and set + polling period of EMAC and "macref" for the reference clock needed to transfer + data to and from the phy. + +Child nodes of the driver are the individual PHY devices connected to the +MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. + +Examples: + +ethernet@10204000 { + compatible = "rockchip,rk3188-emac"; + reg = <0xc0fc2000 0x3c>; + interrupts = <6>; + mac-address = [ 00 11 22 33 44 55 ]; + + clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>; + clock-names = "hclk", "macref"; + + pinctrl-names = "default"; + pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>; + + rockchip,grf = <&grf>; + + phy = <&phy0>; + phy-mode = "rmii"; + phy-supply = <&vcc_rmii>; + + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ethernet.txt b/arch/arm64/boot/dts/vendor/bindings/net/ethernet.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfc376bc977aa0a25e64d4e1ef617a1a326fe634 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ethernet.txt @@ -0,0 +1,66 @@ +The following properties are common to the Ethernet controllers: + +NOTE: All 'phy*' properties documented below are Ethernet specific. For the +generic PHY 'phys' property, see +Documentation/devicetree/bindings/phy/phy-bindings.txt. + +- local-mac-address: array of 6 bytes, specifies the MAC address that was + assigned to the network device; +- mac-address: array of 6 bytes, specifies the MAC address that was last used by + the boot program; should be used in cases where the MAC address assigned to + the device by the boot program is different from the "local-mac-address" + property; +- nvmem-cells: phandle, reference to an nvmem node for the MAC address; +- nvmem-cell-names: string, should be "mac-address" if nvmem is to be used; +- max-speed: number, specifies maximum speed in Mbit/s supported by the device; +- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than + the maximum frame size (there's contradiction in the Devicetree + Specification). +- phy-mode: string, operation mode of the PHY interface. This is now a de-facto + standard property; supported values are: + * "internal" + * "mii" + * "gmii" + * "sgmii" + * "qsgmii" + * "tbi" + * "rev-mii" + * "rmii" + * "rgmii" (RX and TX delays are added by the MAC when required) + * "rgmii-id" (RGMII with internal RX and TX delays provided by the PHY, the + MAC should not add the RX or TX delays in this case) + * "rgmii-rxid" (RGMII with internal RX delay provided by the PHY, the MAC + should not add an RX delay in this case) + * "rgmii-txid" (RGMII with internal TX delay provided by the PHY, the MAC + should not add an TX delay in this case) + * "rtbi" + * "smii" + * "xgmii" + * "trgmii" + * "2000base-x", + * "2500base-x", + * "rxaui" + * "xaui" + * "10gbase-kr" (10GBASE-KR, XFI, SFI) +- phy-connection-type: the same as "phy-mode" property but described in the + Devicetree Specification; +- phy-handle: phandle, specifies a reference to a node representing a PHY + device; this property is described in the Devicetree Specification and so + preferred; +- phy: the same as "phy-handle" property, not recommended for new bindings. +- phy-device: the same as "phy-handle" property, not recommended for new + bindings. +- rx-fifo-depth: the size of the controller's receive fifo in bytes. This + is used for components that can have configurable receive fifo sizes, + and is useful for determining certain configuration settings such as + flow control thresholds. +- tx-fifo-depth: the size of the controller's transmit fifo in bytes. This + is used for components that can have configurable fifo sizes. +- managed: string, specifies the PHY management type. Supported values are: + "auto", "in-band-status". "auto" is the default, it usess MDIO for + management if fixed-link is not specified. + +Child nodes of the Ethernet controller are typically the individual PHY devices +connected via the MDIO bus (sometimes the MDIO bus controller is separate). +They are described in the phy.txt file in this same directory. +For non-MDIO PHY management see fixed-link.txt. diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ezchip_enet.txt b/arch/arm64/boot/dts/vendor/bindings/net/ezchip_enet.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e29b2b82873224a327d9ef30e0be841cc58d15a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ezchip_enet.txt @@ -0,0 +1,15 @@ +* EZchip NPS Management Ethernet port driver + +Required properties: +- compatible: Should be "ezchip,nps-mgt-enet" +- reg: Address and length of the register set for the device +- interrupts: Should contain the ENET interrupt + +Examples: + + ethernet@f0003000 { + compatible = "ezchip,nps-mgt-enet"; + reg = <0xf0003000 0x44>; + interrupts = <7>; + mac-address = [ 00 11 22 33 44 55 ]; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/faraday,ftmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/faraday,ftmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..be4f55e23bf778297f6e813f1889f205219038fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/faraday,ftmac.txt @@ -0,0 +1,24 @@ +Faraday Ethernet Controller + +Required properties: + +- compatible : Must contain "faraday,ftmac", as well as one of + the SoC specific identifiers: + "andestech,atmac100" + "moxa,moxart-mac" +- reg : Should contain register location and length +- interrupts : Should contain the mac interrupt number + +Example: + + mac0: mac@90900000 { + compatible = "moxa,moxart-mac"; + reg = <0x90900000 0x100>; + interrupts = <25 0>; + }; + + mac1: mac@92000000 { + compatible = "moxa,moxart-mac"; + reg = <0x92000000 0x100>; + interrupts = <27 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/fixed-link.txt b/arch/arm64/boot/dts/vendor/bindings/net/fixed-link.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec5d889fe3d83d17bcec0171893fed7519a28cf4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/fixed-link.txt @@ -0,0 +1,54 @@ +Fixed link Device Tree binding +------------------------------ + +Some Ethernet MACs have a "fixed link", and are not connected to a +normal MDIO-managed PHY device. For those situations, a Device Tree +binding allows to describe a "fixed link". + +Such a fixed link situation is described by creating a 'fixed-link' +sub-node of the Ethernet MAC device node, with the following +properties: + +* 'speed' (integer, mandatory), to indicate the link speed. Accepted + values are 10, 100 and 1000 +* 'full-duplex' (boolean, optional), to indicate that full duplex is + used. When absent, half duplex is assumed. +* 'pause' (boolean, optional), to indicate that pause should be + enabled. +* 'asym-pause' (boolean, optional), to indicate that asym_pause should + be enabled. +* 'link-gpios' ('gpio-list', optional), to indicate if a gpio can be read + to determine if the link is up. + +Old, deprecated 'fixed-link' binding: + +* A 'fixed-link' property in the Ethernet MAC node, with 5 cells, of the + form with the following accepted values: + - a: emulated PHY ID, choose any but but unique to the all specified + fixed-links, from 0 to 31 + - b: duplex configuration: 0 for half duplex, 1 for full duplex + - c: link speed in Mbits/sec, accepted values are: 10, 100 and 1000 + - d: pause configuration: 0 for no pause, 1 for pause + - e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for + asymmetric pause + +Examples: + +ethernet@0 { + ... + fixed-link { + speed = <1000>; + full-duplex; + }; + ... +}; + +ethernet@1 { + ... + fixed-link { + speed = <1000>; + pause; + link-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + }; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/fsl-fec.txt b/arch/arm64/boot/dts/vendor/bindings/net/fsl-fec.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d41fb96ce0a2b66acf309071f1534c6437f52cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/fsl-fec.txt @@ -0,0 +1,85 @@ +* Freescale Fast Ethernet Controller (FEC) + +Required properties: +- compatible : Should be "fsl,-fec" +- reg : Address and length of the register set for the device +- interrupts : Should contain fec interrupt +- phy-mode : See ethernet.txt file in the same directory + +Optional properties: +- phy-reset-gpios : Should specify the gpio for phy reset +- phy-reset-duration : Reset duration in milliseconds. Should present + only if property "phy-reset-gpios" is available. Missing the property + will have the duration be 1 millisecond. Numbers greater than 1000 are + invalid and 1 millisecond will be used instead. +- phy-reset-active-high : If present then the reset sequence using the GPIO + specified in the "phy-reset-gpios" property is reversed (H=reset state, + L=operation state). +- phy-reset-post-delay : Post reset delay in milliseconds. If present then + a delay of phy-reset-post-delay milliseconds will be observed after the + phy-reset-gpios has been toggled. Can be omitted thus no delay is + observed. Delay is in range of 1ms to 1000ms. Other delays are invalid. +- phy-supply : regulator that powers the Ethernet PHY. +- phy-handle : phandle to the PHY device connected to this device. +- fixed-link : Assume a fixed link. See fixed-link.txt in the same directory. + Use instead of phy-handle. +- fsl,num-tx-queues : The property is valid for enet-avb IP, which supports + hw multi queues. Should specify the tx queue number, otherwise set tx queue + number to 1. +- fsl,num-rx-queues : The property is valid for enet-avb IP, which supports + hw multi queues. Should specify the rx queue number, otherwise set rx queue + number to 1. +- fsl,magic-packet : If present, indicates that the hardware supports waking + up via magic packet. +- fsl,err006687-workaround-present: If present indicates that the system has + the hardware workaround for ERR006687 applied and does not need a software + workaround. + -interrupt-names: names of the interrupts listed in interrupts property in + the same order. The defaults if not specified are + __Number of interrupts__ __Default__ + 1 "int0" + 2 "int0", "pps" + 3 "int0", "int1", "int2" + 4 "int0", "int1", "int2", "pps" + The order may be changed as long as they correspond to the interrupts + property. Currently, only i.mx7 uses "int1" and "int2". They correspond to + tx/rx queues 1 and 2. "int0" will be used for queue 0 and ENET_MII interrupts. + For imx6sx, "int0" handles all 3 queues and ENET_MII. "pps" is for the pulse + per second interrupt associated with 1588 precision time protocol(PTP). + + +Optional subnodes: +- mdio : specifies the mdio bus in the FEC, used as a container for phy nodes + according to phy.txt in the same directory + +Example: + +ethernet@83fec000 { + compatible = "fsl,imx51-fec", "fsl,imx27-fec"; + reg = <0x83fec000 0x4000>; + interrupts = <87>; + phy-mode = "mii"; + phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; /* GPIO2_14 */ + local-mac-address = [00 04 9F 01 1B B9]; + phy-supply = <®_fec_supply>; +}; + +Example with phy specified: + +ethernet@83fec000 { + compatible = "fsl,imx51-fec", "fsl,imx27-fec"; + reg = <0x83fec000 0x4000>; + interrupts = <87>; + phy-mode = "mii"; + phy-reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; /* GPIO2_14 */ + local-mac-address = [00 04 9F 01 1B B9]; + phy-supply = <®_fec_supply>; + phy-handle = <ðphy>; + mdio { + ethphy: ethernet-phy@6 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <6>; + max-speed = <100>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/fsl-fman.txt b/arch/arm64/boot/dts/vendor/bindings/net/fsl-fman.txt new file mode 100644 index 0000000000000000000000000000000000000000..299c0dcd67db456fd8ded1b9ff71719ecaef9d2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/fsl-fman.txt @@ -0,0 +1,634 @@ +============================================================================= +Freescale Frame Manager Device Bindings + +CONTENTS + - FMan Node + - FMan Port Node + - FMan MURAM Node + - FMan dTSEC/XGEC/mEMAC Node + - FMan IEEE 1588 Node + - FMan MDIO Node + - Example + +============================================================================= +FMan Node + +DESCRIPTION + +Due to the fact that the FMan is an aggregation of sub-engines (ports, MACs, +etc.) the FMan node will have child nodes for each of them. + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must include "fsl,fman" + FMan version can be determined via FM_IP_REV_1 register in the + FMan block. The offset is 0xc4 from the beginning of the + Frame Processing Manager memory map (0xc3000 from the + beginning of the FMan node). + +- cell-index + Usage: required + Value type: + Definition: Specifies the index of the FMan unit. + + The cell-index value may be used by the SoC, to identify the + FMan unit in the SoC memory map. In the table below, + there's a description of the cell-index use in each SoC: + + - P1023: + register[bit] FMan unit cell-index + ============================================================ + DEVDISR[1] 1 0 + + - P2041, P3041, P4080 P5020, P5040: + register[bit] FMan unit cell-index + ============================================================ + DCFG_DEVDISR2[6] 1 0 + DCFG_DEVDISR2[14] 2 1 + (Second FM available only in P4080 and P5040) + + - B4860, T1040, T2080, T4240: + register[bit] FMan unit cell-index + ============================================================ + DCFG_CCSR_DEVDISR2[24] 1 0 + DCFG_CCSR_DEVDISR2[25] 2 1 + (Second FM available only in T4240) + + DEVDISR, DCFG_DEVDISR2 and DCFG_CCSR_DEVDISR2 are located in + the specific SoC "Device Configuration/Pin Control" Memory + Map. + +- reg + Usage: required + Value type: + Definition: A standard property. Specifies the offset of the + following configuration registers: + - BMI configuration registers. + - QMI configuration registers. + - DMA configuration registers. + - FPM configuration registers. + - FMan controller configuration registers. + +- ranges + Usage: required + Value type: + Definition: A standard property. + +- clocks + Usage: required + Value type: + Definition: phandle for the fman input clock. + +- clock-names + usage: required + Value type: + Definition: "fmanclk" for the fman input clock. + +- interrupts + Usage: required + Value type: + Definition: A pair of IRQs are specified in this property. + The first element is associated with the event interrupts and + the second element is associated with the error interrupts. + +- fsl,qman-channel-range + Usage: required + Value type: + Definition: Specifies the range of the available dedicated + channels in the FMan. The first cell specifies the beginning + of the range and the second cell specifies the number of + channels. + Further information available at: + "Work Queue (WQ) Channel Assignments in the QMan" section + in DPAA Reference Manual. + +- fsl,qman +- fsl,bman + Usage: required + Definition: See soc/fsl/qman.txt and soc/fsl/bman.txt + +============================================================================= +FMan MURAM Node + +DESCRIPTION + +FMan Internal memory - shared between all the FMan modules. +It contains data structures that are common and written to or read by +the modules. +FMan internal memory is split into the following parts: + Packet buffering (Tx/Rx FIFOs) + Frames internal context + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: Must include "fsl,fman-muram" + +- ranges + Usage: required + Value type: + Definition: A standard property. + Specifies the multi-user memory offset and the size within + the FMan. + +EXAMPLE + +muram@0 { + compatible = "fsl,fman-muram"; + ranges = <0 0x000000 0x28000>; +}; + +============================================================================= +FMan Port Node + +DESCRIPTION + +The Frame Manager (FMan) supports several types of hardware ports: + Ethernet receiver (RX) + Ethernet transmitter (TX) + Offline/Host command (O/H) + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include one of the following: + - "fsl,fman-v2-port-oh" for FManV2 OH ports + - "fsl,fman-v2-port-rx" for FManV2 RX ports + - "fsl,fman-v2-port-tx" for FManV2 TX ports + - "fsl,fman-v3-port-oh" for FManV3 OH ports + - "fsl,fman-v3-port-rx" for FManV3 RX ports + - "fsl,fman-v3-port-tx" for FManV3 TX ports + +- cell-index + Usage: required + Value type: + Definition: Specifies the hardware port id. + Each hardware port on the FMan has its own hardware PortID. + Super set of all hardware Port IDs available at FMan Reference + Manual under "FMan Hardware Ports in Freescale Devices" table. + + Each hardware port is assigned a 4KB, port-specific page in + the FMan hardware port memory region (which is part of the + FMan memory map). The first 4 KB in the FMan hardware ports + memory region is used for what are called common registers. + The subsequent 63 4KB pages are allocated to the hardware + ports. + The page of a specific port is determined by the cell-index. + +- reg + Usage: required + Value type: + Definition: There is one reg region describing the port + configuration registers. + +- fsl,fman-10g-port + Usage: optional + Value type: boolean + Definition: The default port rate is 1G. + If this property exists, the port is s 10G port. + +- fsl,fman-best-effort-port + Usage: optional + Value type: boolean + Definition: Can be defined only if 10G-support is set. + This property marks a best-effort 10G port (10G port that + may not be capable of line rate). + +EXAMPLE + +port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa8000 0x1000>; +}; + +port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x88000 0x1000>; +}; + +port@81000 { + cell-index = <0x1>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x81000 0x1000>; +}; + +============================================================================= +FMan dTSEC/XGEC/mEMAC Node + +DESCRIPTION + +mEMAC/dTSEC/XGEC are the Ethernet network interfaces + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include one of the following: + - "fsl,fman-dtsec" for dTSEC MAC + - "fsl,fman-xgec" for XGEC MAC + - "fsl,fman-memac" for mEMAC MAC + +- cell-index + Usage: required + Value type: + Definition: Specifies the MAC id. + + The cell-index value may be used by the FMan or the SoC, to + identify the MAC unit in the FMan (or SoC) memory map. + In the tables below there's a description of the cell-index + use, there are two tables, one describes the use of cell-index + by the FMan, the second describes the use by the SoC: + + 1. FMan Registers + + FManV2: + register[bit] MAC cell-index + ============================================================ + FM_EPI[16] XGEC 8 + FM_EPI[16+n] dTSECn n-1 + FM_NPI[11+n] dTSECn n-1 + n = 1,..,5 + + FManV3: + register[bit] MAC cell-index + ============================================================ + FM_EPI[16+n] mEMACn n-1 + FM_EPI[25] mEMAC10 9 + + FM_NPI[11+n] mEMACn n-1 + FM_NPI[10] mEMAC10 9 + FM_NPI[11] mEMAC9 8 + n = 1,..8 + + FM_EPI and FM_NPI are located in the FMan memory map. + + 2. SoC registers: + + - P2041, P3041, P4080 P5020, P5040: + register[bit] FMan MAC cell + Unit index + ============================================================ + DCFG_DEVDISR2[7] 1 XGEC 8 + DCFG_DEVDISR2[7+n] 1 dTSECn n-1 + DCFG_DEVDISR2[15] 2 XGEC 8 + DCFG_DEVDISR2[15+n] 2 dTSECn n-1 + n = 1,..5 + + - T1040, T2080, T4240, B4860: + register[bit] FMan MAC cell + Unit index + ============================================================ + DCFG_CCSR_DEVDISR2[n-1] 1 mEMACn n-1 + DCFG_CCSR_DEVDISR2[11+n] 2 mEMACn n-1 + n = 1,..6,9,10 + + EVDISR, DCFG_DEVDISR2 and DCFG_CCSR_DEVDISR2 are located in + the specific SoC "Device Configuration/Pin Control" Memory + Map. + +- reg + Usage: required + Value type: + Definition: A standard property. + +- fsl,fman-ports + Usage: required + Value type: + Definition: An array of two phandles - the first references is + the FMan RX port and the second is the TX port used by this + MAC. + +- ptp-timer + Usage required + Value type: + Definition: A phandle for 1EEE1588 timer. + +- pcsphy-handle + Usage required for "fsl,fman-memac" MACs + Value type: + Definition: A phandle for pcsphy. + +- tbi-handle + Usage required for "fsl,fman-dtsec" MACs + Value type: + Definition: A phandle for tbiphy. + +EXAMPLE + +fman1_tx28: port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa8000 0x1000>; +}; + +fman1_rx8: port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x88000 0x1000>; +}; + +ptp-timer: ptp_timer@fe000 { + compatible = "fsl,fman-ptp-timer"; + reg = <0xfe000 0x1000>; +}; + +ethernet@e0000 { + compatible = "fsl,fman-dtsec"; + cell-index = <0>; + reg = <0xe0000 0x1000>; + fsl,fman-ports = <&fman1_rx8 &fman1_tx28>; + ptp-timer = <&ptp-timer>; + tbi-handle = <&tbi0>; +}; + +============================================================================ +FMan IEEE 1588 Node + +Refer to Documentation/devicetree/bindings/ptp/ptp-qoriq.txt + +============================================================================= +FMan MDIO Node + +DESCRIPTION + +The MDIO is a bus to which the PHY devices are connected. + +PROPERTIES + +- compatible + Usage: required + Value type: + Definition: A standard property. + Must include "fsl,fman-mdio" for 1 Gb/s MDIO from FMan v2. + Must include "fsl,fman-xmdio" for 10 Gb/s MDIO from FMan v2. + Must include "fsl,fman-memac-mdio" for 1/10 Gb/s MDIO from + FMan v3. + +- reg + Usage: required + Value type: + Definition: A standard property. + +- bus-frequency + Usage: optional + Value type: + Definition: Specifies the external MDIO bus clock speed to + be used, if different from the standard 2.5 MHz. + This may be due to the standard speed being unsupported (e.g. + due to a hardware problem), or to advertise that all relevant + components in the system support a faster speed. + +- interrupts + Usage: required for external MDIO + Value type: + Definition: Event interrupt of external MDIO controller. + +- fsl,fman-internal-mdio + Usage: required for internal MDIO + Value type: boolean + Definition: Fman has internal MDIO for internal PCS(Physical + Coding Sublayer) PHYs and external MDIO for external PHYs. + The settings and programming routines for internal/external + MDIO are different. Must be included for internal MDIO. + +For internal PHY device on internal mdio bus, a PHY node should be created. +See the definition of the PHY node in booting-without-of.txt for an +example of how to define a PHY (Internal PHY has no interrupt line). +- For "fsl,fman-mdio" compatible internal mdio bus, the PHY is TBI PHY. +- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY, + PCS PHY addr must be '0'. + +EXAMPLE + +Example for FMan v2 external MDIO: + +mdio@f1000 { + compatible = "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + interrupts = <101 2 0 0>; +}; + +Example for FMan v2 internal MDIO: + +mdio@e3120 { + compatible = "fsl,fman-mdio"; + reg = <0xe3120 0xee0>; + fsl,fman-internal-mdio; + + tbi1: tbi-phy@8 { + reg = <0x8>; + device_type = "tbi-phy"; + }; +}; + +Example for FMan v3 internal MDIO: + +mdio@f1000 { + compatible = "fsl,fman-memac-mdio"; + reg = <0xf1000 0x1000>; + fsl,fman-internal-mdio; + + pcsphy6: ethernet-phy@0 { + reg = <0x0>; + }; +}; + +============================================================================= +Example + +fman@400000 { + #address-cells = <1>; + #size-cells = <1>; + cell-index = <1>; + compatible = "fsl,fman" + ranges = <0 0x400000 0x100000>; + reg = <0x400000 0x100000>; + clocks = <&fman_clk>; + clock-names = "fmanclk"; + interrupts = < + 96 2 0 0 + 16 2 1 1>; + fsl,qman-channel-range = <0x40 0xc>; + + muram@0 { + compatible = "fsl,fman-muram"; + reg = <0x0 0x28000>; + }; + + port@81000 { + cell-index = <1>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x81000 0x1000>; + }; + + port@82000 { + cell-index = <2>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x82000 0x1000>; + }; + + port@83000 { + cell-index = <3>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x83000 0x1000>; + }; + + port@84000 { + cell-index = <4>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x84000 0x1000>; + }; + + port@85000 { + cell-index = <5>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x85000 0x1000>; + }; + + port@86000 { + cell-index = <6>; + compatible = "fsl,fman-v2-port-oh"; + reg = <0x86000 0x1000>; + }; + + fman1_rx_0x8: port@88000 { + cell-index = <0x8>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x88000 0x1000>; + }; + + fman1_rx_0x9: port@89000 { + cell-index = <0x9>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x89000 0x1000>; + }; + + fman1_rx_0xa: port@8a000 { + cell-index = <0xa>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x8a000 0x1000>; + }; + + fman1_rx_0xb: port@8b000 { + cell-index = <0xb>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x8b000 0x1000>; + }; + + fman1_rx_0xc: port@8c000 { + cell-index = <0xc>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x8c000 0x1000>; + }; + + fman1_rx_0x10: port@90000 { + cell-index = <0x10>; + compatible = "fsl,fman-v2-port-rx"; + reg = <0x90000 0x1000>; + }; + + fman1_tx_0x28: port@a8000 { + cell-index = <0x28>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa8000 0x1000>; + }; + + fman1_tx_0x29: port@a9000 { + cell-index = <0x29>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xa9000 0x1000>; + }; + + fman1_tx_0x2a: port@aa000 { + cell-index = <0x2a>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xaa000 0x1000>; + }; + + fman1_tx_0x2b: port@ab000 { + cell-index = <0x2b>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xab000 0x1000>; + }; + + fman1_tx_0x2c: port@ac0000 { + cell-index = <0x2c>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xac000 0x1000>; + }; + + fman1_tx_0x30: port@b0000 { + cell-index = <0x30>; + compatible = "fsl,fman-v2-port-tx"; + reg = <0xb0000 0x1000>; + }; + + ethernet@e0000 { + compatible = "fsl,fman-dtsec"; + cell-index = <0>; + reg = <0xe0000 0x1000>; + fsl,fman-ports = <&fman1_rx_0x8 &fman1_tx_0x28>; + tbi-handle = <&tbi5>; + }; + + ethernet@e2000 { + compatible = "fsl,fman-dtsec"; + cell-index = <1>; + reg = <0xe2000 0x1000>; + fsl,fman-ports = <&fman1_rx_0x9 &fman1_tx_0x29>; + tbi-handle = <&tbi6>; + }; + + ethernet@e4000 { + compatible = "fsl,fman-dtsec"; + cell-index = <2>; + reg = <0xe4000 0x1000>; + fsl,fman-ports = <&fman1_rx_0xa &fman1_tx_0x2a>; + tbi-handle = <&tbi7>; + }; + + ethernet@e6000 { + compatible = "fsl,fman-dtsec"; + cell-index = <3>; + reg = <0xe6000 0x1000>; + fsl,fman-ports = <&fman1_rx_0xb &fman1_tx_0x2b>; + tbi-handle = <&tbi8>; + }; + + ethernet@e8000 { + compatible = "fsl,fman-dtsec"; + cell-index = <4>; + reg = <0xf0000 0x1000>; + fsl,fman-ports = <&fman1_rx_0xc &fman1_tx_0x2c>; + tbi-handle = <&tbi9>; + + ethernet@f0000 { + cell-index = <8>; + compatible = "fsl,fman-xgec"; + reg = <0xf0000 0x1000>; + fsl,fman-ports = <&fman1_rx_0x10 &fman1_tx_0x30>; + }; + + ptp-timer@fe000 { + compatible = "fsl,fman-ptp-timer"; + reg = <0xfe000 0x1000>; + }; + + mdio@f1000 { + compatible = "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + interrupts = <101 2 0 0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/fsl-tsec-phy.txt b/arch/arm64/boot/dts/vendor/bindings/net/fsl-tsec-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..047bdf7bdd2fa3e6dfad8ab957f478fbebb794a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/fsl-tsec-phy.txt @@ -0,0 +1,89 @@ +* MDIO IO device + +The MDIO is a bus to which the PHY devices are connected. For each +device that exists on this bus, a child node should be created. See +the definition of the PHY node in booting-without-of.txt for an example +of how to define a PHY. + +Required properties: + - reg : Offset and length of the register set for the device, and optionally + the offset and length of the TBIPA register (TBI PHY address + register). If TBIPA register is not specified, the driver will + attempt to infer it from the register set specified (your mileage may + vary). + - compatible : Should define the compatible device type for the + mdio. Currently supported strings/devices are: + - "fsl,gianfar-tbi" + - "fsl,gianfar-mdio" + - "fsl,etsec2-tbi" + - "fsl,etsec2-mdio" + - "fsl,ucc-mdio" + - "fsl,fman-mdio" + When device_type is "mdio", the following strings are also considered: + - "gianfar" + - "ucc_geth_phy" + +Example: + + mdio@24520 { + reg = <24520 20>; + compatible = "fsl,gianfar-mdio"; + + ethernet-phy@0 { + ...... + }; + }; + +* TBI Internal MDIO bus + +As of this writing, every tsec is associated with an internal TBI PHY. +This PHY is accessed through the local MDIO bus. These buses are defined +similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi". +The TBI PHYs underneath them are similar to normal PHYs, but the reg property +is considered instructive, rather than descriptive. The reg property should +be chosen so it doesn't interfere with other PHYs on the bus. + +* Gianfar-compatible ethernet nodes + +Properties: + + - device_type : Should be "network" + - model : Model of the device. Can be "TSEC", "eTSEC", or "FEC" + - compatible : Should be "gianfar" + - reg : Offset and length of the register set for the device + - interrupts : For FEC devices, the first interrupt is the device's + interrupt. For TSEC and eTSEC devices, the first interrupt is + transmit, the second is receive, and the third is error. + - phy-handle : See ethernet.txt file in the same directory. + - fixed-link : See fixed-link.txt in the same directory. + - phy-connection-type : See ethernet.txt file in the same directory. + This property is only really needed if the connection is of type + "rgmii-id", as all other connection types are detected by hardware. + - fsl,magic-packet : If present, indicates that the hardware supports + waking up via magic packet. + - fsl,wake-on-filer : If present, indicates that the hardware supports + waking up by Filer General Purpose Interrupt (FGPI) asserted on the + Rx int line. This is an advanced power management capability allowing + certain packet types (user) defined by filer rules to wake up the system. + - bd-stash : If present, indicates that the hardware supports stashing + buffer descriptors in the L2. + - rx-stash-len : Denotes the number of bytes of a received buffer to stash + in the L2. + - rx-stash-idx : Denotes the index of the first byte from the received + buffer to stash in the L2. + +Example: + ethernet@24000 { + device_type = "network"; + model = "TSEC"; + compatible = "gianfar"; + reg = <0x24000 0x1000>; + local-mac-address = [ 00 E0 0C 00 73 00 ]; + interrupts = <29 2 30 2 34 2>; + interrupt-parent = <&mpic>; + phy-handle = <&phy0> + }; + +* Gianfar PTP clock nodes + +Refer to Documentation/devicetree/bindings/ptp/ptp-qoriq.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ftgmac100.txt b/arch/arm64/boot/dts/vendor/bindings/net/ftgmac100.txt new file mode 100644 index 0000000000000000000000000000000000000000..72e7aaf7242e6cbfd80b02c21fcda9e6a920536b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ftgmac100.txt @@ -0,0 +1,34 @@ +* Faraday Technology FTGMAC100 gigabit ethernet controller + +Required properties: +- compatible: "faraday,ftgmac100" + + Must also contain one of these if used as part of an Aspeed AST2400 + or 2500 family SoC as they have some subtle tweaks to the + implementation: + + - "aspeed,ast2400-mac" + - "aspeed,ast2500-mac" + +- reg: Address and length of the register set for the device +- interrupts: Should contain ethernet controller interrupt + +Optional properties: +- phy-mode: See ethernet.txt file in the same directory. If the property is + absent, "rgmii" is assumed. Supported values are "rgmii*" and "rmii" for + aspeed parts. Other (unknown) parts will accept any value. +- use-ncsi: Use the NC-SI stack instead of an MDIO PHY. Currently assumes + rmii (100bT) but kept as a separate property in case NC-SI grows support + for a gigabit link. +- no-hw-checksum: Used to disable HW checksum support. Here for backward + compatibility as the driver now should have correct defaults based on + the SoC. + +Example: + + mac0: ethernet@1e660000 { + compatible = "aspeed,ast2500-mac", "faraday,ftgmac100"; + reg = <0x1e660000 0x180>; + interrupts = <2>; + use-ncsi; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/gpmc-eth.txt b/arch/arm64/boot/dts/vendor/bindings/net/gpmc-eth.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7da3d73ca1b2e15d71160b9ec811f2aad274e93 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/gpmc-eth.txt @@ -0,0 +1,97 @@ +Device tree bindings for Ethernet chip connected to TI GPMC + +Besides being used to interface with external memory devices, the +General-Purpose Memory Controller can be used to connect Pseudo-SRAM devices +such as ethernet controllers to processors using the TI GPMC as a data bus. + +Ethernet controllers connected to TI GPMC are represented as child nodes of +the GPMC controller with an "ethernet" name. + +All timing relevant properties as well as generic GPMC child properties are +explained in a separate documents. Please refer to +Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt + +For the properties relevant to the ethernet controller connected to the GPMC +refer to the binding documentation of the device. For example, the documentation +for the SMSC 911x is Documentation/devicetree/bindings/net/smsc911x.txt + +Child nodes need to specify the GPMC bus address width using the "bank-width" +property but is possible that an ethernet controller also has a property to +specify the I/O registers address width. Even when the GPMC has a maximum 16-bit +address width, it supports devices with 32-bit word registers. +For example with an SMSC LAN911x/912x controller connected to the TI GPMC on an +OMAP2+ board, "bank-width = <2>;" and "reg-io-width = <4>;". + +Required properties: +- bank-width: Address width of the device in bytes. GPMC supports 8-bit + and 16-bit devices and so must be either 1 or 2 bytes. +- compatible: Compatible string property for the ethernet child device. +- gpmc,cs-on-ns: Chip-select assertion time +- gpmc,cs-rd-off-ns: Chip-select de-assertion time for reads +- gpmc,cs-wr-off-ns: Chip-select de-assertion time for writes +- gpmc,oe-on-ns: Output-enable assertion time +- gpmc,oe-off-ns: Output-enable de-assertion time +- gpmc,we-on-ns: Write-enable assertion time +- gpmc,we-off-ns: Write-enable de-assertion time +- gpmc,access-ns: Start cycle to first data capture (read access) +- gpmc,rd-cycle-ns: Total read cycle time +- gpmc,wr-cycle-ns: Total write cycle time +- reg: Chip-select, base address (relative to chip-select) + and size of the memory mapped for the device. + Note that base address will be typically 0 as this + is the start of the chip-select. + +Optional properties: +- gpmc,XXX Additional GPMC timings and settings parameters. See + Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt + +Example: + +gpmc: gpmc@6e000000 { + compatible = "ti,omap3430-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x6e000000 0x1000>; + interrupts = <20>; + gpmc,num-cs = <8>; + gpmc,num-waitpins = <4>; + #address-cells = <2>; + #size-cells = <1>; + + ranges = <5 0 0x2c000000 0x1000000>; + + ethernet@5,0 { + compatible = "smsc,lan9221", "smsc,lan9115"; + reg = <5 0 0xff>; + bank-width = <2>; + + gpmc,mux-add-data; + gpmc,cs-on-ns = <0>; + gpmc,cs-rd-off-ns = <186>; + gpmc,cs-wr-off-ns = <186>; + gpmc,adv-on-ns = <12>; + gpmc,adv-rd-off-ns = <48>; + gpmc,adv-wr-off-ns = <48>; + gpmc,oe-on-ns = <54>; + gpmc,oe-off-ns = <168>; + gpmc,we-on-ns = <54>; + gpmc,we-off-ns = <168>; + gpmc,rd-cycle-ns = <186>; + gpmc,wr-cycle-ns = <186>; + gpmc,access-ns = <114>; + gpmc,page-burst-access-ns = <6>; + gpmc,bus-turnaround-ns = <12>; + gpmc,cycle2cycle-delay-ns = <18>; + gpmc,wr-data-mux-bus-ns = <90>; + gpmc,wr-access-ns = <186>; + gpmc,cycle2cycle-samecsen; + gpmc,cycle2cycle-diffcsen; + + interrupt-parent = <&gpio6>; + interrupts = <16>; + vmmc-supply = <&vddvario>; + vmmc_aux-supply = <&vdd33a>; + reg-io-width = <4>; + + smsc,save-mac-address; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-femac-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-femac-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..23a39a309d17d37124e378c191791e344828fa2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-femac-mdio.txt @@ -0,0 +1,22 @@ +Hisilicon Fast Ethernet MDIO Controller interface + +Required properties: +- compatible: should be "hisilicon,hisi-femac-mdio". +- reg: address and length of the register set for the device. +- clocks: A phandle to the reference clock for this device. + +- PHY subnode: inherits from phy binding [1] +[1] Documentation/devicetree/bindings/net/phy.txt + +Example: +mdio: mdio@10091100 { + compatible = "hisilicon,hisi-femac-mdio"; + reg = <0x10091100 0x10>; + clocks = <&crg HI3516CV300_MDIO_CLK>; + #address-cells = <1>; + #size-cells = <0>; + + phy0: phy@1 { + reg = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-femac.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-femac.txt new file mode 100644 index 0000000000000000000000000000000000000000..d11af5ecace8594cfe92d72d5bcdc4d2b2e63932 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-femac.txt @@ -0,0 +1,39 @@ +Hisilicon Fast Ethernet MAC controller + +Required properties: +- compatible: should contain one of the following version strings: + * "hisilicon,hisi-femac-v1" + * "hisilicon,hisi-femac-v2" + and the soc string "hisilicon,hi3516cv300-femac". +- reg: specifies base physical address(s) and size of the device registers. + The first region is the MAC core register base and size. + The second region is the global MAC control register. +- interrupts: should contain the MAC interrupt. +- clocks: A phandle to the MAC main clock. +- resets: should contain the phandle to the MAC reset signal(required) and + the PHY reset signal(optional). +- reset-names: should contain the reset signal name "mac"(required) + and "phy"(optional). +- mac-address: see ethernet.txt [1]. +- phy-mode: see ethernet.txt [1]. +- phy-handle: see ethernet.txt [1]. +- hisilicon,phy-reset-delays-us: triplet of delays if PHY reset signal given. + The 1st cell is reset pre-delay in micro seconds. + The 2nd cell is reset pulse in micro seconds. + The 3rd cell is reset post-delay in micro seconds. + +[1] Documentation/devicetree/bindings/net/ethernet.txt + +Example: + hisi_femac: ethernet@10090000 { + compatible = "hisilicon,hi3516cv300-femac","hisilicon,hisi-femac-v2"; + reg = <0x10090000 0x1000>,<0x10091300 0x200>; + interrupts = <12>; + clocks = <&crg HI3518EV200_ETH_CLK>; + resets = <&crg 0xec 0>,<&crg 0xec 3>; + reset-names = "mac","phy"; + mac-address = [00 00 00 00 00 00]; + phy-mode = "mii"; + phy-handle = <&phy0>; + hisilicon,phy-reset-delays-us = <10000 20000 20000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hip04-net.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hip04-net.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1df8a00e1f3b7828cfb66d2706dd81316343384 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hip04-net.txt @@ -0,0 +1,88 @@ +Hisilicon hip04 Ethernet Controller + +* Ethernet controller node + +Required properties: +- compatible: should be "hisilicon,hip04-mac". +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device. +- port-handle: + phandle, specifies a reference to the syscon ppe node + port, port number connected to the controller + channel, recv channel start from channel * number (RX_DESC_NUM) +- phy-mode: see ethernet.txt [1]. + +Optional properties: +- phy-handle: see ethernet.txt [1]. + +[1] Documentation/devicetree/bindings/net/ethernet.txt + + +* Ethernet ppe node: +Control rx & tx fifos of all ethernet controllers. +Have 2048 recv channels shared by all ethernet controllers, only if no overlap. +Each controller's recv channel start from channel * number (RX_DESC_NUM). + +Required properties: +- compatible: "hisilicon,hip04-ppe", "syscon". +- reg: address and length of the register set for the device. + + +* MDIO bus node: + +Required properties: + +- compatible: should be "hisilicon,mdio". +- Inherits from MDIO bus node binding [2] +[2] Documentation/devicetree/bindings/net/phy.txt + +Example: + mdio { + compatible = "hisilicon,mdio"; + reg = <0x28f1000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + marvell,reg-init = <18 0x14 0 0x8001>; + }; + + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + marvell,reg-init = <18 0x14 0 0x8001>; + }; + }; + + ppe: ppe@28c0000 { + compatible = "hisilicon,hip04-ppe", "syscon"; + reg = <0x28c0000 0x10000>; + }; + + fe: ethernet@28b0000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x28b0000 0x10000>; + interrupts = <0 413 4>; + phy-mode = "mii"; + port-handle = <&ppe 31 0>; + }; + + ge0: ethernet@2800000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x2800000 0x10000>; + interrupts = <0 402 4>; + phy-mode = "sgmii"; + port-handle = <&ppe 0 1>; + phy-handle = <&phy0>; + }; + + ge8: ethernet@2880000 { + compatible = "hisilicon,hip04-mac"; + reg = <0x2880000 0x10000>; + interrupts = <0 410 4>; + phy-mode = "sgmii"; + port-handle = <&ppe 8 2>; + phy-handle = <&phy1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hix5hd2-gmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hix5hd2-gmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..eea73adc678f963888c3171006516272abd37f62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hix5hd2-gmac.txt @@ -0,0 +1,58 @@ +Hisilicon hix5hd2 gmac controller + +Required properties: +- compatible: should contain one of the following SoC strings: + * "hisilicon,hix5hd2-gmac" + * "hisilicon,hi3798cv200-gmac" + * "hisilicon,hi3516a-gmac" + and one of the following version string: + * "hisilicon,hisi-gmac-v1" + * "hisilicon,hisi-gmac-v2" + The version v1 includes SoCs hix5hd2. + The version v2 includes SoCs hi3798cv200, hi3516a. +- reg: specifies base physical address(s) and size of the device registers. + The first region is the MAC register base and size. + The second region is external interface control register. +- interrupts: should contain the MAC interrupt. +- #address-cells: must be <1>. +- #size-cells: must be <0>. +- phy-mode: see ethernet.txt [1]. +- phy-handle: see ethernet.txt [1]. +- mac-address: see ethernet.txt [1]. +- clocks: clock phandle and specifier pair. +- clock-names: contain the clock name "mac_core"(required) and "mac_ifc"(optional). +- resets: should contain the phandle to the MAC core reset signal(optional), + the MAC interface reset signal(optional) + and the PHY reset signal(optional). +- reset-names: contain the reset signal name "mac_core"(optional), + "mac_ifc"(optional) and "phy"(optional). +- hisilicon,phy-reset-delays-us: triplet of delays if PHY reset signal given. + The 1st cell is reset pre-delay in micro seconds. + The 2nd cell is reset pulse in micro seconds. + The 3rd cell is reset post-delay in micro seconds. + +- PHY subnode: inherits from phy binding [2] + +[1] Documentation/devicetree/bindings/net/ethernet.txt +[2] Documentation/devicetree/bindings/net/phy.txt + +Example: + gmac0: ethernet@f9840000 { + compatible = "hisilicon,hi3798cv200-gmac", "hisilicon,hisi-gmac-v2"; + reg = <0xf9840000 0x1000>,<0xf984300c 0x4>; + interrupts = <0 71 4>; + #address-cells = <1>; + #size-cells = <0>; + phy-mode = "rgmii"; + phy-handle = <&phy2>; + mac-address = [00 00 00 00 00 00]; + clocks = <&crg HISTB_ETH0_MAC_CLK>, <&crg HISTB_ETH0_MACIF_CLK>; + clock-names = "mac_core", "mac_ifc"; + resets = <&crg 0xcc 8>, <&crg 0xcc 10>, <&crg 0xcc 12>; + reset-names = "mac_core", "mac_ifc", "phy"; + hisilicon,phy-reset-delays-us = <10000 10000 30000>; + + phy2: ethernet-phy@2 { + reg = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-dsaf.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-dsaf.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ee4b1cedae8071c3754d6daf3f4eed44d899739 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-dsaf.txt @@ -0,0 +1,90 @@ +Hisilicon DSA Fabric device controller + +Required properties: +- compatible: should be "hisilicon,hns-dsaf-v1" or "hisilicon,hns-dsaf-v2". + "hisilicon,hns-dsaf-v1" is for hip05. + "hisilicon,hns-dsaf-v2" is for Hi1610 and Hi1612. +- mode: dsa fabric mode string. only support one of dsaf modes like these: + "2port-64vf", + "6port-16rss", + "6port-16vf", + "single-port". +- interrupts: should contain the DSA Fabric and rcb interrupt. +- reg: specifies base physical address(es) and size of the device registers. + The first region is external interface control register base and size(optional, + only used when subctrl-syscon does not exist). It is recommended using + subctrl-syscon rather than this address. + The second region is SerDes base register and size(optional, only used when + serdes-syscon in port node does not exist). It is recommended using + serdes-syscon rather than this address. + The third region is the PPE register base and size. + The fourth region is dsa fabric base register and size. It is not required for + single-port mode. +- reg-names: may be ppe-base and(or) dsaf-base. It is used to find the + corresponding reg's index. + +- phy-handle: phy handle of physical port, 0 if not any phy device. It is optional + attribute. If port node exists, phy-handle in each port node will be used. + see ethernet.txt [1]. +- subctrl-syscon: is syscon handle for external interface control register. +- reset-field-offset: is offset of reset field. Its value depends on the hardware + user manual. +- buf-size: rx buffer size, should be 16-1024. +- desc-num: number of description in TX and RX queue, should be 512, 1024, 2048 or 4096. + +- port: subnodes of dsaf. A dsaf node may contain several port nodes(Depending + on mode of dsaf). Port node contain some attributes listed below: +- reg: is physical port index in one dsaf. +- phy-handle: phy handle of physical port. It is not required if there isn't + phy device. see ethernet.txt [1]. +- serdes-syscon: is syscon handle for SerDes register. +- cpld-syscon: is syscon handle + register offset pair for cpld register. It is + not required if there isn't cpld device. +- port-rst-offset: is offset of reset field for each port in dsaf. Its value + depends on the hardware user manual. +- port-mode-offset: is offset of port mode field for each port in dsaf. Its + value depends on the hardware user manual. +- mc-mac-mask: mask of multicast address, determines bit in multicast address + to set: + 1 stands for this bit will be precisely matched, TCAM will check this bit of + MAC address. + 0 stands for this bit will be fuzzy matched, TCAM won't care about this bit + of MAC address. + +[1] Documentation/devicetree/bindings/net/phy.txt + +Example: + +dsaf0: dsa@c7000000 { + compatible = "hisilicon,hns-dsaf-v1"; + mode = "6port-16rss"; + interrupt-parent = <&mbigen_dsa>; + reg = <0x0 0xc5000000 0x0 0x890000 + 0x0 0xc7000000 0x0 0x60000>; + reg-names = "ppe-base", "dsaf-base"; + subctrl-syscon = <&subctrl>; + reset-field-offset = 0; + interrupts = <131 4>,<132 4>, <133 4>,<134 4>, + <135 4>,<136 4>, <137 4>,<138 4>, + <139 4>,<140 4>, <141 4>,<142 4>, + <143 4>,<144 4>, <145 4>,<146 4>, + <147 4>,<148 4>, <384 1>,<385 1>, + <386 1>,<387 1>, <388 1>,<389 1>, + <390 1>,<391 1>, + buf-size = <4096>; + desc-num = <1024>; + dma-coherent; + + port@0 { + reg = 0; + phy-handle = <&phy0>; + serdes-syscon = <&serdes>; + mc-mac-mask = [ff f0 00 00 00 00]; + }; + + port@1 { + reg = 1; + serdes-syscon = <&serdes>; + mc-mac-mask = [ff f0 00 00 00 00]; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a7ede9657b08211675a7329ff5cc3b5bd6e90e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-mdio.txt @@ -0,0 +1,27 @@ +Hisilicon MDIO bus controller + +Properties: +- compatible: can be one of: + "hisilicon,hns-mdio" + "hisilicon,mdio" + "hisilicon,hns-mdio" is recommended to be used for hip05 and later SOCs, + while "hisilicon,mdio" is optional for backwards compatibility only on + hip04 Soc. +- reg: The base address of the MDIO bus controller register bank. +- #address-cells: Must be <1>. +- #size-cells: Must be <0>. MDIO addresses have no size component. + +Typically an MDIO bus might have several children. + +Example: + mdio@803c0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "hisilicon,hns-mdio","hisilicon,mdio"; + reg = <0x0 0x803c0000 0x0 0x10000>; + + ethernet-phy@0 { + ... + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-nic.txt b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-nic.txt new file mode 100644 index 0000000000000000000000000000000000000000..f0421ee3c7149fe08419eda6e4657a25872771d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/hisilicon-hns-nic.txt @@ -0,0 +1,76 @@ +Hisilicon Network Subsystem NIC controller + +Required properties: +- compatible: "hisilicon,hns-nic-v1" or "hisilicon,hns-nic-v2". + "hisilicon,hns-nic-v1" is for hip05. + "hisilicon,hns-nic-v2" is for Hi1610 and Hi1612. +- ae-handle: accelerator engine handle for hns, + specifies a reference to the associating hardware driver node. + see Documentation/devicetree/bindings/net/hisilicon-hns-dsaf.txt +- port-id: is the index of port provided by DSAF (the accelerator). DSAF can + connect to 8 PHYs. Port 0 to 1 are both used for administration purpose. They + are called debug ports. + + The remaining 6 PHYs are taken according to the mode of DSAF. + + In NIC mode of DSAF, all 6 PHYs are taken as ethernet ports to the CPU. The + port-id can be 2 to 7. Here is the diagram: + +-----+---------------+ + | CPU | + +-+-+-+---+-+-+-+-+-+-+ + | | | | | | | | + debug service + port port + (0,1) (2-7) + + In Switch mode of DSAF, all 6 PHYs are taken as physical ports connect to a + LAN Switch while the CPU side assume itself have one single NIC connect to + this switch. In this case, the port-id will be 2 only. + +-----+---------------+ + | CPU | + +-+-+-+---+-+-+-+-+-+-+ + | | service| port(2) + debug +------------+ + port | switch | + (0,1) +-+-+-+-+-+-++ + | | | | | | + external port + + This attribute is remained for compatible purpose. It is not recommended to + use it in new code. + +- port-idx-in-ae: is the index of port provided by AE. + In NIC mode of DSAF, all 6 PHYs of service DSAF are taken as ethernet ports + to the CPU. The port-idx-in-ae can be 0 to 5. Here is the diagram: + +-----+---------------+ + | CPU | + +-+-+-+---+-+-+-+-+-+-+ + | | | | | | | | + debug debug service + port port port + (0) (0) (0-5) + + In Switch mode of DSAF, all 6 PHYs of service DSAF are taken as physical + ports connected to a LAN Switch while the CPU side assume itself have one + single NIC connected to this switch. In this case, the port-idx-in-ae + will be 0 only. + +-----+-----+------+------+ + | CPU | + +-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | service| port(0) + debug debug +------------+ + port port | switch | + (0) (0) +-+-+-+-+-+-++ + | | | | | | + external port + +- local-mac-address: mac addr of the ethernet interface + +Example: + + ethernet@0{ + compatible = "hisilicon,hns-nic-v1"; + ae-handle = <&dsaf0>; + port-idx-in-ae = <0>; + local-mac-address = [a2 14 e4 4b 56 76]; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ibm,emac.txt b/arch/arm64/boot/dts/vendor/bindings/net/ibm,emac.txt new file mode 100644 index 0000000000000000000000000000000000000000..c0c14aa3f97c501d58bc597312f2bfe10efab956 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ibm,emac.txt @@ -0,0 +1,205 @@ + 4xx/Axon EMAC ethernet nodes + + The EMAC ethernet controller in IBM and AMCC 4xx chips, and also + the Axon bridge. To operate this needs to interact with a this + special McMAL DMA controller, and sometimes an RGMII or ZMII + interface. In addition to the nodes and properties described + below, the node for the OPB bus on which the EMAC sits must have a + correct clock-frequency property. + + i) The EMAC node itself + + Required properties: + - device_type : "network" + + - compatible : compatible list, contains 2 entries, first is + "ibm,emac-CHIP" where CHIP is the host ASIC (440gx, + 405gp, Axon) and second is either "ibm,emac" or + "ibm,emac4". For Axon, thus, we have: "ibm,emac-axon", + "ibm,emac4" + - interrupts : + - reg : + - local-mac-address : 6 bytes, MAC address + - mal-device : phandle of the associated McMAL node + - mal-tx-channel : 1 cell, index of the tx channel on McMAL associated + with this EMAC + - mal-rx-channel : 1 cell, index of the rx channel on McMAL associated + with this EMAC + - cell-index : 1 cell, hardware index of the EMAC cell on a given + ASIC (typically 0x0 and 0x1 for EMAC0 and EMAC1 on + each Axon chip) + - max-frame-size : 1 cell, maximum frame size supported in bytes + - rx-fifo-size : 1 cell, Rx fifo size in bytes for 10 and 100 Mb/sec + operations. + For Axon, 2048 + - tx-fifo-size : 1 cell, Tx fifo size in bytes for 10 and 100 Mb/sec + operations. + For Axon, 2048. + - fifo-entry-size : 1 cell, size of a fifo entry (used to calculate + thresholds). + For Axon, 0x00000010 + - mal-burst-size : 1 cell, MAL burst size (used to calculate thresholds) + in bytes. + For Axon, 0x00000100 (I think ...) + - phy-mode : string, mode of operations of the PHY interface. + Supported values are: "mii", "rmii", "smii", "rgmii", + "tbi", "gmii", rtbi", "sgmii". + For Axon on CAB, it is "rgmii" + - mdio-device : 1 cell, required iff using shared MDIO registers + (440EP). phandle of the EMAC to use to drive the + MDIO lines for the PHY used by this EMAC. + - zmii-device : 1 cell, required iff connected to a ZMII. phandle of + the ZMII device node + - zmii-channel : 1 cell, required iff connected to a ZMII. Which ZMII + channel or 0xffffffff if ZMII is only used for MDIO. + - rgmii-device : 1 cell, required iff connected to an RGMII. phandle + of the RGMII device node. + For Axon: phandle of plb5/plb4/opb/rgmii + - rgmii-channel : 1 cell, required iff connected to an RGMII. Which + RGMII channel is used by this EMAC. + Fox Axon: present, whatever value is appropriate for each + EMAC, that is the content of the current (bogus) "phy-port" + property. + + Optional properties: + - phy-address : 1 cell, optional, MDIO address of the PHY. If absent, + a search is performed. + - phy-map : 1 cell, optional, bitmap of addresses to probe the PHY + for, used if phy-address is absent. bit 0x00000001 is + MDIO address 0. + For Axon it can be absent, though my current driver + doesn't handle phy-address yet so for now, keep + 0x00ffffff in it. + - phy-handle : Used to describe configurations where a external PHY + is used. Please refer to: + Documentation/devicetree/bindings/net/ethernet.txt + - rx-fifo-size-gige : 1 cell, Rx fifo size in bytes for 1000 Mb/sec + operations (if absent the value is the same as + rx-fifo-size). For Axon, either absent or 2048. + - tx-fifo-size-gige : 1 cell, Tx fifo size in bytes for 1000 Mb/sec + operations (if absent the value is the same as + tx-fifo-size). For Axon, either absent or 2048. + - tah-device : 1 cell, optional. If connected to a TAH engine for + offload, phandle of the TAH device node. + - tah-channel : 1 cell, optional. If appropriate, channel used on the + TAH engine. + - fixed-link : Fixed-link subnode describing a link to a non-MDIO + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. + - mdio subnode : When the EMAC has a phy connected to its local + mdio, which us supported by the kernel's network + PHY library in drivers/net/phy, there must be device + tree subnode with the following required properties: + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For PHY definitions: Please refer to + Documentation/devicetree/bindings/net/phy.txt and + Documentation/devicetree/bindings/net/ethernet.txt + + Examples: + + EMAC0: ethernet@40000800 { + device_type = "network"; + compatible = "ibm,emac-440gp", "ibm,emac"; + interrupt-parent = <&UIC1>; + interrupts = <1c 4 1d 4>; + reg = <40000800 70>; + local-mac-address = [00 04 AC E3 1B 1E]; + mal-device = <&MAL0>; + mal-tx-channel = <0 1>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <5dc>; + rx-fifo-size = <1000>; + tx-fifo-size = <800>; + phy-mode = "rmii"; + phy-map = <00000001>; + zmii-device = <&ZMII0>; + zmii-channel = <0>; + }; + + EMAC1: ethernet@ef600c00 { + device_type = "network"; + compatible = "ibm,emac-apm821xx", "ibm,emac4sync"; + interrupt-parent = <&EMAC1>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0 &UIC2 0x10 IRQ_TYPE_LEVEL_HIGH /* Status */ + 1 &UIC2 0x14 IRQ_TYPE_LEVEL_HIGH /* Wake */>; + reg = <0xef600c00 0x000000c4>; + local-mac-address = [000000000000]; /* Filled in by U-Boot */ + mal-device = <&MAL0>; + mal-tx-channel = <0>; + mal-rx-channel = <0>; + cell-index = <0>; + max-frame-size = <9000>; + rx-fifo-size = <16384>; + tx-fifo-size = <2048>; + fifo-entry-size = <10>; + phy-mode = "rgmii"; + phy-handle = <&phy0>; + phy-map = <0x00000000>; + rgmii-device = <&RGMII0>; + rgmii-channel = <0>; + tah-device = <&TAH0>; + tah-channel = <0>; + has-inverted-stacr-oc; + has-new-stacr-staopc; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + }; + }; + }; + + + ii) McMAL node + + Required properties: + - device_type : "dma-controller" + - compatible : compatible list, containing 2 entries, first is + "ibm,mcmal-CHIP" where CHIP is the host ASIC (like + emac) and the second is either "ibm,mcmal" or + "ibm,mcmal2". + For Axon, "ibm,mcmal-axon","ibm,mcmal2" + - interrupts : . + For Axon: This is _different_ from the current + firmware. We use the "delayed" interrupts for txeob + and rxeob. Thus we end up with mapping those 5 MPIC + interrupts, all level positive sensitive: 10, 11, 32, + 33, 34 (in decimal) + - dcr-reg : < DCR registers range > + - dcr-parent : if needed for dcr-reg + - num-tx-chans : 1 cell, number of Tx channels + - num-rx-chans : 1 cell, number of Rx channels + + iii) ZMII node + + Required properties: + - compatible : compatible list, containing 2 entries, first is + "ibm,zmii-CHIP" where CHIP is the host ASIC (like + EMAC) and the second is "ibm,zmii". + For Axon, there is no ZMII node. + - reg : + + iv) RGMII node + + Required properties: + - compatible : compatible list, containing 2 entries, first is + "ibm,rgmii-CHIP" where CHIP is the host ASIC (like + EMAC) and the second is "ibm,rgmii". + For Axon, "ibm,rgmii-axon","ibm,rgmii" + - reg : + - revision : as provided by the RGMII new version register if + available. + For Axon: 0x0000012a diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/adf7242.txt b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/adf7242.txt new file mode 100644 index 0000000000000000000000000000000000000000..d24172cc6d32106e1ed7d02736694dcc75de886f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/adf7242.txt @@ -0,0 +1,18 @@ +* ADF7242 IEEE 802.15.4 * + +Required properties: + - compatible: should be "adi,adf7242", "adi,adf7241" + - spi-max-frequency: maximal bus speed (12.5 MHz) + - reg: the chipselect index + - interrupts: the interrupt generated by the device via pin IRQ1. + IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1) + +Example: + + adf7242@0 { + compatible = "adi,adf7242"; + spi-max-frequency = <10000000>; + reg = <0>; + interrupts = <98 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&gpio3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/at86rf230.txt b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/at86rf230.txt new file mode 100644 index 0000000000000000000000000000000000000000..168f1be509126ad2ad77c9e4bdcc4642847226b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/at86rf230.txt @@ -0,0 +1,27 @@ +* AT86RF230 IEEE 802.15.4 * + +Required properties: + - compatible: should be "atmel,at86rf230", "atmel,at86rf231", + "atmel,at86rf233" or "atmel,at86rf212" + - spi-max-frequency: maximal bus speed, should be set to 7500000 depends + sync or async operation mode + - reg: the chipselect index + - interrupts: the interrupt generated by the device. Non high-level + can occur deadlocks while handling isr. + +Optional properties: + - reset-gpio: GPIO spec for the rstn pin + - sleep-gpio: GPIO spec for the slp_tr pin + - xtal-trim: u8 value for fine tuning the internal capacitance + arrays of xtal pins: 0 = +0 pF, 0xf = +4.5 pF + +Example: + + at86rf231@0 { + compatible = "atmel,at86rf231"; + spi-max-frequency = <7500000>; + reg = <0>; + interrupts = <19 4>; + interrupt-parent = <&gpio3>; + xtal-trim = /bits/ 8 <0x06>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/ca8210.txt b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/ca8210.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1046e636fa14b494963f6770ffa578359dcd224 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/ca8210.txt @@ -0,0 +1,28 @@ +* CA8210 IEEE 802.15.4 * + +Required properties: + - compatible: Should be "cascoda,ca8210" + - reg: Controlling chip select + - spi-max-frequency: Maximum clock speed, should be *less than* + 4000000 + - spi-cpol: Requires inverted clock polarity + - reset-gpio: GPIO attached to reset + - irq-gpio: GPIO attached to IRQ +Optional properties: + - extclock-enable: Include for the ca8210 to route its 16MHz clock + to an output + - extclock-freq: Frequency in Hz of the external clock + - extclock-gpio: GPIO of the ca8210 to output the clock on + +Example: + ca8210@0 { + compatible = "cascoda,ca8210"; + reg = <0>; + spi-max-frequency = <3000000>; + spi-cpol; + reset-gpio = <&gpio1 1 GPIO_ACTIVE_HIGH>; + irq-gpio = <&gpio1 2 GPIO_ACTIVE_HIGH>; + extclock-enable; + extclock-freq = 16000000; + extclock-gpio = 2; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/cc2520.txt b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/cc2520.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb6d49f184edc5b4ef65524ff673fec4ca3a2ba6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/cc2520.txt @@ -0,0 +1,33 @@ +*CC2520 IEEE 802.15.4 Compatible Radio* + +Required properties: + - compatible: should be "ti,cc2520" + - spi-max-frequency: maximal bus speed (8000000), should be set to 4000000 depends + sync or async operation mode + - reg: the chipselect index + - pinctrl-0: pin control group to be used for this controller. + - pinctrl-names: must contain a "default" entry. + - fifo-gpio: GPIO spec for the FIFO pin + - fifop-gpio: GPIO spec for the FIFOP pin + - sfd-gpio: GPIO spec for the SFD pin + - cca-gpio: GPIO spec for the CCA pin + - vreg-gpio: GPIO spec for the VREG pin + - reset-gpio: GPIO spec for the RESET pin +Optional properties: + - amplified: include if the CC2520 is connected to a CC2591 amplifier + +Example: + cc2520@0 { + compatible = "ti,cc2520"; + reg = <0>; + spi-max-frequency = <4000000>; + amplified; + pinctrl-names = "default"; + pinctrl-0 = <&cc2520_cape_pins>; + fifo-gpio = <&gpio1 18 0>; + fifop-gpio = <&gpio1 19 0>; + sfd-gpio = <&gpio1 13 0>; + cca-gpio = <&gpio1 16 0>; + vreg-gpio = <&gpio0 31 0>; + reset-gpio = <&gpio1 12 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/mcr20a.txt b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/mcr20a.txt new file mode 100644 index 0000000000000000000000000000000000000000..2aaef567c5bebb8ec36ac4128a99af9d1600dccb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/mcr20a.txt @@ -0,0 +1,23 @@ +* MCR20A IEEE 802.15.4 * + +Required properties: + - compatible: should be "nxp,mcr20a" + - spi-max-frequency: maximal bus speed, should be set to a frequency + lower than 9000000 depends sync or async operation mode + - reg: the chipselect index + - interrupts: the interrupt generated by the device. Non high-level + can occur deadlocks while handling isr. + +Optional properties: + - rst_b-gpio: GPIO spec for the RST_B pin + +Example: + + mcr20a@0 { + compatible = "nxp,mcr20a"; + spi-max-frequency = <9000000>; + reg = <0>; + interrupts = <17 2>; + interrupt-parent = <&gpio>; + rst_b-gpio = <&gpio 27 1> + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/mrf24j40.txt b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/mrf24j40.txt new file mode 100644 index 0000000000000000000000000000000000000000..a4ed2efb5b73e6713a9d5df8f3049cba02911b97 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ieee802154/mrf24j40.txt @@ -0,0 +1,20 @@ +* MRF24J40 IEEE 802.15.4 * + +Required properties: + - compatible: should be "microchip,mrf24j40", "microchip,mrf24j40ma", + or "microchip,mrf24j40mc" depends on your transceiver + board + - spi-max-frequency: maximal bus speed, should be set something under or equal + 10000000 + - reg: the chipselect index + - interrupts: the interrupt generated by the device. + +Example: + + mrf24j40ma@0 { + compatible = "microchip,mrf24j40ma"; + spi-max-frequency = <8500000>; + reg = <0>; + interrupts = <19 8>; + interrupt-parent = <&gpio3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ipq806x-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/ipq806x-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d7ab4e524d45b9abdecf5e686dc2bf2512eaacb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ipq806x-dwmac.txt @@ -0,0 +1,35 @@ +* IPQ806x DWMAC Ethernet controller + +The device inherits all the properties of the dwmac/stmmac devices +described in the file net/stmmac.txt with the following changes. + +Required properties: + +- compatible: should be "qcom,ipq806x-gmac" along with "snps,dwmac" + and any applicable more detailed version number + described in net/stmmac.txt + +- qcom,nss-common: should contain a phandle to a syscon device mapping the + nss-common registers. + +- qcom,qsgmii-csr: should contain a phandle to a syscon device mapping the + qsgmii-csr registers. + +Example: + + gmac: ethernet@37000000 { + device_type = "network"; + compatible = "qcom,ipq806x-gmac"; + reg = <0x37000000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; + + qcom,nss-common = <&nss_common>; + qcom,qsgmii-csr = <&qsgmii_csr>; + + clocks = <&gcc GMAC_CORE1_CLK>; + clock-names = "stmmaceth"; + + resets = <&gcc GMAC_CORE1_RESET>; + reset-names = "stmmaceth"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/keystone-netcp.txt b/arch/arm64/boot/dts/vendor/bindings/net/keystone-netcp.txt new file mode 100644 index 0000000000000000000000000000000000000000..04ba1dc34fd62150ae1357e8c0c7804907f56313 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/keystone-netcp.txt @@ -0,0 +1,221 @@ +This document describes the device tree bindings associated with the +keystone network coprocessor(NetCP) driver support. + +The network coprocessor (NetCP) is a hardware accelerator that processes +Ethernet packets. NetCP has a gigabit Ethernet (GbE) subsystem with a ethernet +switch sub-module to send and receive packets. NetCP also includes a packet +accelerator (PA) module to perform packet classification operations such as +header matching, and packet modification operations such as checksum +generation. NetCP can also optionally include a Security Accelerator (SA) +capable of performing IPSec operations on ingress/egress packets. + +Keystone II SoC's also have a 10 Gigabit Ethernet Subsystem (XGbE) which +includes a 3-port Ethernet switch sub-module capable of 10Gb/s and 1Gb/s rates +per Ethernet port. + +Keystone NetCP driver has a plug-in module architecture where each of the NetCP +sub-modules exist as a loadable kernel module which plug in to the netcp core. +These sub-modules are represented as "netcp-devices" in the dts bindings. It is +mandatory to have the ethernet switch sub-module for the ethernet interface to +be operational. Any other sub-module like the PA is optional. + +NetCP Ethernet SubSystem Layout: + +----------------------------- + NetCP subsystem(10G or 1G) +----------------------------- + | + |-> NetCP Devices -> | + | |-> GBE/XGBE Switch + | | + | |-> Packet Accelerator + | | + | |-> Security Accelerator + | + | + | + |-> NetCP Interfaces -> | + |-> Ethernet Port 0 + | + |-> Ethernet Port 1 + | + |-> Ethernet Port 2 + | + |-> Ethernet Port 3 + + +NetCP subsystem properties: +Required properties: +- compatible: Should be "ti,netcp-1.0" +- clocks: phandle to the reference clocks for the subsystem. +- dma-id: Navigator packet dma instance id. +- ranges: address range of NetCP (includes, Ethernet SS, PA and SA) + +Optional properties: +- reg: register location and the size for the following register + regions in the specified order. + - Efuse MAC address register +- dma-coherent: Present if dma operations are coherent +- big-endian: Keystone devices can be operated in a mode where the DSP is in + the big endian mode. In such cases enable this option. This + option should also be enabled if the ARM is operated in + big endian mode with the DSP in little endian. + +NetCP device properties: Device specification for NetCP sub-modules. +1Gb/10Gb (gbe/xgbe) ethernet switch sub-module specifications. +Required properties: +- label: Must be "netcp-gbe" for 1Gb & "netcp-xgbe" for 10Gb. +- compatible: Must be one of below:- + "ti,netcp-gbe" for 1GbE on NetCP 1.4 + "ti,netcp-gbe-5" for 1GbE N NetCP 1.5 (N=5) + "ti,netcp-gbe-9" for 1GbE N NetCP 1.5 (N=9) + "ti,netcp-gbe-2" for 1GbE N NetCP 1.5 (N=2) + "ti,netcp-xgbe" for 10 GbE + +- reg: register location and the size for the following register + regions in the specified order. + - switch subsystem registers + - sgmii port3/4 module registers (only for NetCP 1.4) + - switch module registers + - serdes registers (only for 10G) + + NetCP 1.4 ethss, here is the order + index #0 - switch subsystem registers + index #1 - sgmii port3/4 module registers + index #2 - switch module registers + + NetCP 1.5 ethss 9 port, 5 port and 2 port + index #0 - switch subsystem registers + index #1 - switch module registers + index #2 - serdes registers + +- tx-channel: the navigator packet dma channel name for tx. +- tx-queue: the navigator queue number associated with the tx dma channel. +- interfaces: specification for each of the switch port to be registered as a + network interface in the stack. +-- slave-port: Switch port number, 0 based numbering. +-- link-interface: type of link interface, supported options are + - mac<->mac auto negotiate mode: 0 + - mac<->phy mode: 1 + - mac<->mac forced mode: 2 + - mac<->fiber mode: 3 + - mac<->phy mode with no mdio: 4 + - 10Gb mac<->phy mode : 10 + - 10Gb mac<->mac forced mode : 11 +----phy-handle: phandle to PHY device + +Optional properties: +- enable-ale: NetCP driver keeps the address learning feature in the ethernet + switch module disabled. This attribute is to enable the address + learning. +- secondary-slave-ports: specification for each of the switch port not be + registered as a network interface. NetCP driver + will only initialize these ports and attach PHY + driver to them if needed. + +NetCP interface properties: Interface specification for NetCP sub-modules. +Required properties: +- rx-channel: the navigator packet dma channel name for rx. +- rx-queue: the navigator queue number associated with rx dma channel. +- rx-pool: specifies the number of descriptors to be used & the region-id + for creating the rx descriptor pool. +- tx-pool: specifies the number of descriptors to be used & the region-id + for creating the tx descriptor pool. +- rx-queue-depth: number of descriptors in each of the free descriptor + queue (FDQ) for the pktdma Rx flow. There can be at + present a maximum of 4 queues per Rx flow. +- rx-buffer-size: the buffer size for each of the Rx flow FDQ. +- tx-completion-queue: the navigator queue number where the descriptors are + recycled after Tx DMA completion. + +Optional properties: +- efuse-mac: If this is 1, then the MAC address for the interface is + obtained from the device efuse mac address register. + If this is 2, the two DWORDs occupied by the MAC address + are swapped. The netcp driver will swap the two DWORDs + back to the proper order when this property is set to 2 + when it obtains the mac address from efuse. +- local-mac-address: the driver is designed to use the of_get_mac_address api + only if efuse-mac is 0. When efuse-mac is 0, the MAC + address is obtained from local-mac-address. If this + attribute is not present, then the driver will use a + random MAC address. +- "netcp-device label": phandle to the device specification for each of NetCP + sub-module attached to this interface. + +Example binding: + +netcp: netcp@2000000 { + reg = <0x2620110 0x8>; + reg-names = "efuse"; + compatible = "ti,netcp-1.0"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x2000000 0xfffff>; + clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>; + dma-coherent; + /* big-endian; */ + dma-id = <0>; + + netcp-devices { + #address-cells = <1>; + #size-cells = <1>; + ranges; + gbe@90000 { + label = "netcp-gbe"; + reg = <0x90000 0x300>, <0x90400 0x400>, <0x90800 0x700>; + /* enable-ale; */ + tx-queue = <648>; + tx-channel = <8>; + + interfaces { + gbe0: interface-0 { + slave-port = <0>; + link-interface = <4>; + }; + gbe1: interface-1 { + slave-port = <1>; + link-interface = <4>; + }; + }; + + secondary-slave-ports { + port-2 { + slave-port = <2>; + link-interface = <2>; + }; + port-3 { + slave-port = <3>; + link-interface = <2>; + }; + }; + }; + }; + + netcp-interfaces { + interface-0 { + rx-channel = <22>; + rx-pool = <1024 12>; + tx-pool = <1024 12>; + rx-queue-depth = <128 128 0 0>; + rx-buffer-size = <1518 4096 0 0>; + rx-queue = <8704>; + tx-completion-queue = <8706>; + efuse-mac = <1>; + netcp-gbe = <&gbe0>; + + }; + interface-1 { + rx-channel = <23>; + rx-pool = <1024 12>; + tx-pool = <1024 12>; + rx-queue-depth = <128 128 0 0>; + rx-buffer-size = <1518 4096 0 0>; + rx-queue = <8705>; + tx-completion-queue = <8707>; + efuse-mac = <0>; + local-mac-address = [02 18 31 7e 3e 6f]; + netcp-gbe = <&gbe1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/lpc-eth.txt b/arch/arm64/boot/dts/vendor/bindings/net/lpc-eth.txt new file mode 100644 index 0000000000000000000000000000000000000000..b92e927808b607e96c36d66f61fa6499c7ac0f1f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/lpc-eth.txt @@ -0,0 +1,23 @@ +* NXP LPC32xx SoC Ethernet Controller + +Required properties: +- compatible: Should be "nxp,lpc-eth" +- reg: Address and length of the register set for the device +- interrupts: Should contain ethernet controller interrupt + +Optional properties: +- phy-mode: See ethernet.txt file in the same directory. If the property is + absent, "rmii" is assumed. +- use-iram: Use LPC32xx internal SRAM (IRAM) for DMA buffering + +Example: + + mac: ethernet@31060000 { + compatible = "nxp,lpc-eth"; + reg = <0x31060000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <29 0>; + + phy-mode = "rmii"; + use-iram; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/macb.txt b/arch/arm64/boot/dts/vendor/bindings/net/macb.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e17ac1d5d58caa2c89dae53648c5b1d33efe0dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/macb.txt @@ -0,0 +1,49 @@ +* Cadence MACB/GEM Ethernet controller + +Required properties: +- compatible: Should be "cdns,[-]{macb|gem}" + Use "cdns,at91rm9200-emac" Atmel at91rm9200 SoC. + Use "cdns,at91sam9260-macb" for Atmel at91sam9 SoCs or the 10/100Mbit IP + available on sama5d3 SoCs. + Use "cdns,np4-macb" for NP4 SoC devices. + Use "cdns,at32ap7000-macb" for other 10/100 usage or use the generic form: "cdns,macb". + Use "cdns,pc302-gem" for Picochip picoXcell pc302 and later devices based on + the Cadence GEM, or the generic form: "cdns,gem". + Use "atmel,sama5d2-gem" for the GEM IP (10/100) available on Atmel sama5d2 SoCs. + Use "atmel,sama5d3-macb" for the 10/100Mbit IP available on Atmel sama5d3 SoCs. + Use "atmel,sama5d3-gem" for the Gigabit IP available on Atmel sama5d3 SoCs. + Use "atmel,sama5d4-gem" for the GEM IP (10/100) available on Atmel sama5d4 SoCs. + Use "cdns,zynq-gem" Xilinx Zynq-7xxx SoC. + Use "cdns,zynqmp-gem" for Zynq Ultrascale+ MPSoC. + Or the generic form: "cdns,emac". +- reg: Address and length of the register set for the device +- interrupts: Should contain macb interrupt +- phy-mode: See ethernet.txt file in the same directory. +- clock-names: Tuple listing input clock names. + Required elements: 'pclk', 'hclk' + Optional elements: 'tx_clk' + Optional elements: 'rx_clk' applies to cdns,zynqmp-gem + Optional elements: 'tsu_clk' +- clocks: Phandles to input clocks. + +Optional properties for PHY child node: +- reset-gpios : Should specify the gpio for phy reset +- magic-packet : If present, indicates that the hardware supports waking + up via magic packet. +- phy-handle : see ethernet.txt file in the same directory + +Examples: + + macb0: ethernet@fffc4000 { + compatible = "cdns,at32ap7000-macb"; + reg = <0xfffc4000 0x4000>; + interrupts = <21>; + phy-mode = "rmii"; + local-mac-address = [3a 0e 03 04 05 06]; + clock-names = "pclk", "hclk", "tx_clk"; + clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>; + ethernet-phy@1 { + reg = <0x1>; + reset-gpios = <&pioE 6 1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell,prestera.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell,prestera.txt new file mode 100644 index 0000000000000000000000000000000000000000..c329608fa887b1fad655f7c778ca539b4c5d36c6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell,prestera.txt @@ -0,0 +1,47 @@ +Marvell Prestera Switch Chip bindings +------------------------------------- + +Required properties: +- compatible: one of the following + "marvell,prestera-98dx3236", + "marvell,prestera-98dx3336", + "marvell,prestera-98dx4251", +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device + +Optional properties: +- dfx: phandle reference to the "DFX Server" node + +Example: + +switch { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0x03, 0x00) 0 0x100000>; + + packet-processor@0 { + compatible = "marvell,prestera-98dx3236"; + reg = <0 0x4000000>; + interrupts = <33>, <34>, <35>; + dfx = <&dfx>; + }; +}; + +DFX Server bindings +------------------- + +Required properties: +- compatible: must be "marvell,dfx-server", "simple-bus" +- ranges: describes the address mapping of a memory-mapped bus. +- reg: address and length of the register set for the device. + +Example: + +dfx-server { + compatible = "marvell,dfx-server", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; + reg = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-armada-370-neta.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-armada-370-neta.txt new file mode 100644 index 0000000000000000000000000000000000000000..bedcfd5a52cd3966ea867e5ea4326e2aa4e11511 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-armada-370-neta.txt @@ -0,0 +1,49 @@ +* Marvell Armada 370 / Armada XP / Armada 3700 Ethernet Controller (NETA) + +Required properties: +- compatible: could be one of the following: + "marvell,armada-370-neta" + "marvell,armada-xp-neta" + "marvell,armada-3700-neta" +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device +- phy: See ethernet.txt file in the same directory. +- phy-mode: See ethernet.txt file in the same directory +- clocks: List of clocks for this device. At least one clock is + mandatory for the core clock. If several clocks are given, then the + clock-names property must be used to identify them. + +Optional properties: +- tx-csum-limit: maximum mtu supported by port that allow TX checksum. + Value is presented in bytes. If not used, by default 1600B is set for + "marvell,armada-370-neta" and 9800B for others. +- clock-names: List of names corresponding to clocks property; shall be + "core" for core clock and "bus" for the optional bus clock. + + +Optional properties (valid only for Armada XP/38x): + +- buffer-manager: a phandle to a buffer manager node. Please refer to + Documentation/devicetree/bindings/net/marvell-neta-bm.txt +- bm,pool-long: ID of a pool, that will accept all packets of a size + higher than 'short' pool's threshold (if set) and up to MTU value. + Obligatory, when the port is supposed to use hardware + buffer management. +- bm,pool-short: ID of a pool, that will be used for accepting + packets of a size lower than given threshold. If not set, the port + will use a single 'long' pool for all packets, as defined above. + +Example: + +ethernet@70000 { + compatible = "marvell,armada-370-neta"; + reg = <0x70000 0x2500>; + interrupts = <8>; + clocks = <&gate_clk 4>; + tx-csum-limit = <9800> + phy = <&phy0>; + phy-mode = "rgmii-id"; + buffer-manager = <&bm>; + bm,pool-long = <0>; + bm,pool-short = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-bt-8xxx.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-bt-8xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..957e5e5c2927c5acb3703e1a15983cf09a72ecf5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-bt-8xxx.txt @@ -0,0 +1,83 @@ +Marvell 8897/8997 (sd8897/sd8997) bluetooth devices (SDIO or USB based) +------ +The 8997 devices supports multiple interfaces. When used on SDIO interfaces, +the btmrvl driver is used and when used on USB interface, the btusb driver is +used. + +Required properties: + + - compatible : should be one of the following: + * "marvell,sd8897-bt" (for SDIO) + * "marvell,sd8997-bt" (for SDIO) + * "usb1286,204e" (for USB) + +Optional properties: + + - marvell,cal-data: Calibration data downloaded to the device during + initialization. This is an array of 28 values(u8). + This is only applicable to SDIO devices. + + - marvell,wakeup-pin: It represents wakeup pin number of the bluetooth chip. + firmware will use the pin to wakeup host system (u16). + - marvell,wakeup-gap-ms: wakeup gap represents wakeup latency of the host + platform. The value will be configured to firmware. This + is needed to work chip's sleep feature as expected (u16). + - interrupt-names: Used only for USB based devices (See below) + - interrupts : specifies the interrupt pin number to the cpu. For SDIO, the + driver will use the first interrupt specified in the interrupt + array. For USB based devices, the driver will use the interrupt + named "wakeup" from the interrupt-names and interrupt arrays. + The driver will request an irq based on this interrupt number. + During system suspend, the irq will be enabled so that the + bluetooth chip can wakeup host platform under certain + conditions. During system resume, the irq will be disabled + to make sure unnecessary interrupt is not received. + +Example: + +IRQ pin 119 is used as system wakeup source interrupt. +wakeup pin 13 and gap 100ms are configured so that firmware can wakeup host +using this device side pin and wakeup latency. + +Example for SDIO device follows (calibration data is also available in +below example). + +&mmc3 { + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + cap-power-off-card; + keep-power-in-suspend; + + #address-cells = <1>; + #size-cells = <0>; + btmrvl: bluetooth@2 { + compatible = "marvell,sd8897-bt"; + reg = <2>; + interrupt-parent = <&pio>; + interrupts = <119 IRQ_TYPE_LEVEL_LOW>; + + marvell,cal-data = /bits/ 8 < + 0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02 + 0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0xf0 0x00>; + marvell,wakeup-pin = /bits/ 16 <0x0d>; + marvell,wakeup-gap-ms = /bits/ 16 <0x64>; + }; +}; + +Example for USB device: + +&usb_host1_ohci { + #address-cells = <1>; + #size-cells = <0>; + + mvl_bt1: bt@1 { + compatible = "usb1286,204e"; + reg = <1>; + interrupt-parent = <&gpio0>; + interrupt-names = "wakeup"; + interrupts = <119 IRQ_TYPE_LEVEL_LOW>; + marvell,wakeup-pin = /bits/ 16 <0x0d>; + marvell,wakeup-gap-ms = /bits/ 16 <0x64>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-neta-bm.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-neta-bm.txt new file mode 100644 index 0000000000000000000000000000000000000000..07b31050dbe51adf91d5decaaac3d973f64a962e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-neta-bm.txt @@ -0,0 +1,47 @@ +* Marvell Armada 380/XP Buffer Manager driver (BM) + +Required properties: + +- compatible: should be "marvell,armada-380-neta-bm". +- reg: address and length of the register set for the device. +- clocks: a pointer to the reference clock for this device. +- internal-mem: a phandle to BM internal SRAM definition. + +Optional properties (port): + +- pool<0 : 3>,capacity: size of external buffer pointers' ring maintained + in DRAM. Can be set for each pool (id 0 : 3) separately. The value has + to be chosen between 128 and 16352 and it also has to be aligned to 32. + Otherwise the driver would adjust a given number or choose default if + not set. +- pool<0 : 3>,pkt-size: maximum size of a packet accepted by a given buffer + pointers' pool (id 0 : 3). It will be taken into consideration only when pool + type is 'short'. For 'long' ones it would be overridden by port's MTU. + If not set a driver will choose a default value. + +In order to see how to hook the BM to a given ethernet port, please +refer to Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt. + +Example: + +- main node: + +bm: bm@c8000 { + compatible = "marvell,armada-380-neta-bm"; + reg = <0xc8000 0xac>; + clocks = <&gateclk 13>; + internal-mem = <&bm_bppi>; + pool2,capacity = <4096>; + pool1,pkt-size = <512>; +}; + +- internal SRAM node: + +bm_bppi: bm-bppi { + compatible = "mmio-sram"; + reg = ; + ranges = <0 MBUS_ID(0x0c, 0x04) 0 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&gateclk 13>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-orion-mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-orion-mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..42cd81090a2c77f959020328aee5f953b02703db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-orion-mdio.txt @@ -0,0 +1,54 @@ +* Marvell MDIO Ethernet Controller interface + +The Ethernet controllers of the Marvel Kirkwood, Dove, Orion5x, +MV78xx0, Armada 370, Armada XP, Armada 7k and Armada 8k have an +identical unit that provides an interface with the MDIO bus. +Additionally, Armada 7k and Armada 8k has a second unit which +provides an interface with the xMDIO bus. This driver handles +these interfaces. + +Required properties: +- compatible: "marvell,orion-mdio" or "marvell,xmdio" +- reg: address and length of the MDIO registers. When an interrupt is + not present, the length is the size of the SMI register (4 bytes) + otherwise it must be 0x84 bytes to cover the interrupt control + registers. + +Optional properties: +- interrupts: interrupt line number for the SMI error/done interrupt +- clocks: phandle for up to three required clocks for the MDIO instance + +The child nodes of the MDIO driver are the individual PHY devices +connected to this MDIO bus. They must have a "reg" property given the +PHY address on the MDIO bus. + +Example at the SoC level without an interrupt property: + +mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,orion-mdio"; + reg = <0xd0072004 0x4>; +}; + +Example with an interrupt property: + +mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "marvell,orion-mdio"; + reg = <0xd0072004 0x84>; + interrupts = <30>; +}; + +And at the board level: + +mdio { + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-orion-net.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-orion-net.txt new file mode 100644 index 0000000000000000000000000000000000000000..6fd988c84c4f9f4d7eb7df2f2c52283c27d164d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-orion-net.txt @@ -0,0 +1,83 @@ +Marvell Orion/Discovery ethernet controller +============================================= + +The Marvell Discovery ethernet controller can be found on Marvell Orion SoCs +(Kirkwood, Dove, Orion5x, and Discovery Innovation) and as part of Marvell +Discovery system controller chips (mv64[345]60). + +The Discovery ethernet controller is described with two levels of nodes. The +first level describes the ethernet controller itself and the second level +describes up to 3 ethernet port nodes within that controller. The reason for +the multiple levels is that the port registers are interleaved within a single +set of controller registers. Each port node describes port-specific properties. + +Note: The above separation is only true for Discovery system controllers. +For Orion SoCs we stick to the separation, although there each controller has +only one port associated. Multiple ports are implemented as multiple single-port +controllers. As Kirkwood has some issues with proper initialization after reset, +an extra compatible string is added for it. + +* Ethernet controller node + +Required controller properties: + - #address-cells: shall be 1. + - #size-cells: shall be 0. + - compatible: shall be one of "marvell,orion-eth", "marvell,kirkwood-eth". + - reg: address and length of the controller registers. + +Optional controller properties: + - clocks: phandle reference to the controller clock. + - marvell,tx-checksum-limit: max tx packet size for hardware checksum. + +* Ethernet port node + +Required port properties: + - compatible: shall be one of "marvell,orion-eth-port", + "marvell,kirkwood-eth-port". + - reg: port number relative to ethernet controller, shall be 0, 1, or 2. + - interrupts: port interrupt. + - local-mac-address: See ethernet.txt file in the same directory. + +Optional port properties: + - marvell,tx-queue-size: size of the transmit ring buffer. + - marvell,tx-sram-addr: address of transmit descriptor buffer located in SRAM. + - marvell,tx-sram-size: size of transmit descriptor buffer located in SRAM. + - marvell,rx-queue-size: size of the receive ring buffer. + - marvell,rx-sram-addr: address of receive descriptor buffer located in SRAM. + - marvell,rx-sram-size: size of receive descriptor buffer located in SRAM. + +and + + - phy-handle: See ethernet.txt file in the same directory. + - phy-mode: See ethernet.txt file in the same directory. + +or + + - speed: port speed if no PHY connected. + - duplex: port mode if no PHY connected. + +* Node example: + +mdio-bus { + ... + ethphy: ethernet-phy@8 { + ... + }; +}; + +eth: ethernet-controller@72000 { + compatible = "marvell,orion-eth"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x72000 0x2000>; + clocks = <&gate_clk 2>; + marvell,tx-checksum-limit = <1600>; + + ethernet@0 { + compatible = "marvell,orion-eth-port"; + reg = <0>; + interrupts = <29>; + phy-handle = <ðphy>; + local-mac-address = [00 00 00 00 00 00]; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-pp2.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-pp2.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc019df0d8638df3c08e51bc8827987623c0c244 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-pp2.txt @@ -0,0 +1,122 @@ +* Marvell Armada 375 Ethernet Controller (PPv2.1) + Marvell Armada 7K/8K Ethernet Controller (PPv2.2) + +Required properties: + +- compatible: should be one of: + "marvell,armada-375-pp2" + "marvell,armada-7k-pp2" +- reg: addresses and length of the register sets for the device. + For "marvell,armada-375-pp2", must contain the following register + sets: + - common controller registers + - LMS registers + - one register area per Ethernet port + For "marvell,armada-7k-pp2", must contain the following register + sets: + - packet processor registers + - networking interfaces registers + +- clocks: pointers to the reference clocks for this device, consequently: + - main controller clock (for both armada-375-pp2 and armada-7k-pp2) + - GOP clock (for both armada-375-pp2 and armada-7k-pp2) + - MG clock (only for armada-7k-pp2) + - MG Core clock (only for armada-7k-pp2) + - AXI clock (only for armada-7k-pp2) +- clock-names: names of used clocks, must be "pp_clk", "gop_clk", "mg_clk", + "mg_core_clk" and "axi_clk" (the 3 latter only for armada-7k-pp2). + +The ethernet ports are represented by subnodes. At least one port is +required. + +Required properties (port): + +- interrupts: interrupt for the port +- port-id: ID of the port from the MAC point of view +- gop-port-id: only for marvell,armada-7k-pp2, ID of the port from the + GOP (Group Of Ports) point of view. This ID is used to index the + per-port registers in the second register area. +- phy-mode: See ethernet.txt file in the same directory + +Optional properties (port): + +- marvell,loopback: port is loopback mode +- phy: a phandle to a phy node defining the PHY address (as the reg + property, a single integer). +- interrupt-names: if more than a single interrupt for rx is given, must + be the name associated to the interrupts listed. Valid + names are: "tx-cpu0", "tx-cpu1", "tx-cpu2", "tx-cpu3", + "rx-shared", "link". +- marvell,system-controller: a phandle to the system controller. + +Example for marvell,armada-375-pp2: + +ethernet@f0000 { + compatible = "marvell,armada-375-pp2"; + reg = <0xf0000 0xa000>, + <0xc0000 0x3060>, + <0xc4000 0x100>, + <0xc5000 0x100>; + clocks = <&gateclk 3>, <&gateclk 19>; + clock-names = "pp_clk", "gop_clk"; + + eth0: eth0@c4000 { + interrupts = ; + port-id = <0>; + phy = <&phy0>; + phy-mode = "gmii"; + }; + + eth1: eth1@c5000 { + interrupts = ; + port-id = <1>; + phy = <&phy3>; + phy-mode = "gmii"; + }; +}; + +Example for marvell,armada-7k-pp2: + +cpm_ethernet: ethernet@0 { + compatible = "marvell,armada-7k-pp22"; + reg = <0x0 0x100000>, <0x129000 0xb000>; + clocks = <&cpm_syscon0 1 3>, <&cpm_syscon0 1 9>, + <&cpm_syscon0 1 5>, <&cpm_syscon0 1 6>, <&cpm_syscon0 1 18>; + clock-names = "pp_clk", "gop_clk", "mg_clk", "mg_core_clk", "axi_clk"; + + eth0: eth0 { + interrupts = , + , + , + , + ; + interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3", "rx-shared"; + port-id = <0>; + gop-port-id = <0>; + }; + + eth1: eth1 { + interrupts = , + , + , + , + ; + interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3", "rx-shared"; + port-id = <1>; + gop-port-id = <2>; + }; + + eth2: eth2 { + interrupts = , + , + , + , + ; + interrupt-names = "tx-cpu0", "tx-cpu1", "tx-cpu2", + "tx-cpu3", "rx-shared"; + port-id = <2>; + gop-port-id = <3>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/marvell-pxa168.txt b/arch/arm64/boot/dts/vendor/bindings/net/marvell-pxa168.txt new file mode 100644 index 0000000000000000000000000000000000000000..845a148a346e9265e92f93f966a2e091b39ed058 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/marvell-pxa168.txt @@ -0,0 +1,36 @@ +* Marvell PXA168 Ethernet Controller + +Required properties: +- compatible: should be "marvell,pxa168-eth". +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device. +- clocks: pointer to the clock for the device. + +Optional properties: +- port-id: Ethernet port number. Should be '0','1' or '2'. +- #address-cells: must be 1 when using sub-nodes. +- #size-cells: must be 0 when using sub-nodes. +- phy-handle: see ethernet.txt file in the same directory. +- local-mac-address: see ethernet.txt file in the same directory. + +Sub-nodes: +Each PHY can be represented as a sub-node. This is not mandatory. + +Sub-nodes required properties: +- reg: the MDIO address of the PHY. + +Example: + + eth0: ethernet@f7b90000 { + compatible = "marvell,pxa168-eth"; + reg = <0xf7b90000 0x10000>; + clocks = <&chip CLKID_GETH0>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + phy-handle = <ðphy0>; + + ethphy0: ethernet-phy@0 { + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/maxim,ds26522.txt b/arch/arm64/boot/dts/vendor/bindings/net/maxim,ds26522.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee8bb725f245a6d86dfa28992b1cc55ee30be001 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/maxim,ds26522.txt @@ -0,0 +1,13 @@ +* Maxim (Dallas) DS26522 Dual T1/E1/J1 Transceiver + +Required properties: +- compatible: Should contain "maxim,ds26522". +- reg: SPI CS. +- spi-max-frequency: SPI clock. + +Example: + slic@1 { + compatible = "maxim,ds26522"; + reg = <1>; + spi-max-frequency = <2000000>; /* input clock */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mdio-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/net/mdio-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..8dbcf8295c6c9ceaa4eb7518694acf3b09095dc1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mdio-gpio.txt @@ -0,0 +1,26 @@ +MDIO on GPIOs + +Currently defined compatibles: +- virtual,gpio-mdio + +MDC and MDIO lines connected to GPIO controllers are listed in the +gpios property as described in section VIII.1 in the following order: + +MDC, MDIO. + +Note: Each gpio-mdio bus should have an alias correctly numbered in "aliases" +node. + +Example: + +aliases { + mdio-gpio0 = &mdio0; +}; + +mdio0: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qe_pio_a 11 + &qe_pio_c 6>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..694987d3c17a1085ba9fce589d81cc9ee99a7717 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux-gpio.txt @@ -0,0 +1,119 @@ +Properties for an MDIO bus multiplexer/switch controlled by GPIO pins. + +This is a special case of a MDIO bus multiplexer. One or more GPIO +lines are used to control which child bus is connected. + +Required properties in addition to the generic multiplexer properties: + +- compatible : mdio-mux-gpio. +- gpios : GPIO specifiers for each GPIO line. One or more must be specified. + + +Example : + + /* The parent MDIO bus. */ + smi1: mdio@1180000001900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001900 0x0 0x40>; + }; + + /* + An NXP sn74cbtlv3253 dual 1-of-4 switch controlled by a + pair of GPIO lines. Child busses 2 and 3 populated with 4 + PHYs each. + */ + mdio-mux { + compatible = "mdio-mux-gpio"; + gpios = <&gpio1 3 0>, <&gpio1 4 0>; + mdio-parent-bus = <&smi1>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + phy11: ethernet-phy@1 { + reg = <1>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy12: ethernet-phy@2 { + reg = <2>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy13: ethernet-phy@3 { + reg = <3>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy14: ethernet-phy@4 { + reg = <4>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + }; + + mdio@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + phy21: ethernet-phy@1 { + reg = <1>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy22: ethernet-phy@2 { + reg = <2>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy23: ethernet-phy@3 { + reg = <3>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy24: ethernet-phy@4 { + reg = <4>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux-mmioreg.txt b/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux-mmioreg.txt new file mode 100644 index 0000000000000000000000000000000000000000..065e8bdb957d9d577e987dca04ce49c84afb2935 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux-mmioreg.txt @@ -0,0 +1,75 @@ +Properties for an MDIO bus multiplexer controlled by a memory-mapped device + +This is a special case of a MDIO bus multiplexer. A memory-mapped device, +like an FPGA, is used to control which child bus is connected. The mdio-mux +node must be a child of the memory-mapped device. The driver currently only +supports devices with 8, 16 or 32-bit registers. + +Required properties in addition to the generic multiplexer properties: + +- compatible : string, must contain "mdio-mux-mmioreg" + +- reg : integer, contains the offset of the register that controls the bus + multiplexer. The size field in the 'reg' property is the size of + register, and must therefore be 1, 2, or 4. + +- mux-mask : integer, contains an eight-bit mask that specifies which + bits in the register control the actual bus multiplexer. The + 'reg' property of each child mdio-mux node must be constrained by + this mask. + +Example: + +The FPGA node defines a memory-mapped FPGA with a register space of 0x30 bytes. +For the "EMI2" MDIO bus, register 9 (BRDCFG1) controls the mux on that bus. +A bitmask of 0x6 means that bits 1 and 2 (bit 0 is lsb) are the bits on +BRDCFG1 that control the actual mux. + + /* The FPGA node */ + fpga: board-control@3,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,p5020ds-fpga", "fsl,fpga-ngpixis"; + reg = <3 0 0x30>; + ranges = <0 3 0 0x30>; + + mdio-mux-emi2 { + compatible = "mdio-mux-mmioreg", "mdio-mux"; + mdio-parent-bus = <&xmdio0>; + #address-cells = <1>; + #size-cells = <0>; + reg = <9 1>; // BRDCFG1 + mux-mask = <0x6>; // EMI2 + + emi2_slot1: mdio@0 { // Slot 1 XAUI (FM2) + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + phy_xgmii_slot1: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <4>; + }; + }; + + emi2_slot2: mdio@2 { // Slot 2 XAUI (FM1) + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + phy_xgmii_slot2: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + }; + }; + }; + }; + + /* The parent MDIO bus. */ + xmdio0: mdio@f1000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,fman-xmdio"; + reg = <0xf1000 0x1000>; + interrupts = <100 1 0 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux.txt b/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux.txt new file mode 100644 index 0000000000000000000000000000000000000000..f58571f36570fcd2e06df0628615e150c0b44cb5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mdio-mux.txt @@ -0,0 +1,129 @@ +Common MDIO bus multiplexer/switch properties. + +An MDIO bus multiplexer/switch will have several child busses that are +numbered uniquely in a device dependent manner. The nodes for an MDIO +bus multiplexer/switch will have one child node for each child bus. + +Required properties: +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- mdio-parent-bus : phandle to the parent MDIO bus. + +- Other properties specific to the multiplexer/switch hardware. + +Required properties for child nodes: +- #address-cells = <1>; +- #size-cells = <0>; +- reg : The sub-bus number. + + +Example : + + /* The parent MDIO bus. */ + smi1: mdio@1180000001900 { + compatible = "cavium,octeon-3860-mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x11800 0x00001900 0x0 0x40>; + }; + + /* + An NXP sn74cbtlv3253 dual 1-of-4 switch controlled by a + pair of GPIO lines. Child busses 2 and 3 populated with 4 + PHYs each. + */ + mdio-mux { + compatible = "mdio-mux-gpio"; + gpios = <&gpio1 3 0>, <&gpio1 4 0>; + mdio-parent-bus = <&smi1>; + #address-cells = <1>; + #size-cells = <0>; + + mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + phy11: ethernet-phy@1 { + reg = <1>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy12: ethernet-phy@2 { + reg = <2>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy13: ethernet-phy@3 { + reg = <3>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + phy14: ethernet-phy@4 { + reg = <4>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <10 8>; /* Pin 10, active low */ + }; + }; + + mdio@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + + phy21: ethernet-phy@1 { + reg = <1>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy22: ethernet-phy@2 { + reg = <2>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy23: ethernet-phy@3 { + reg = <3>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + phy24: ethernet-phy@4 { + reg = <4>; + marvell,reg-init = <3 0x10 0 0x5777>, + <3 0x11 0 0x00aa>, + <3 0x12 0 0x4105>, + <3 0x13 0 0x0a60>; + interrupt-parent = <&gpio>; + interrupts = <12 8>; /* Pin 12, active low */ + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mdio.txt b/arch/arm64/boot/dts/vendor/bindings/net/mdio.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3e1603f256c1a55ce956a403fce855e7bf58e0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mdio.txt @@ -0,0 +1,37 @@ +Common MDIO bus properties. + +These are generic properties that can apply to any MDIO bus. + +Optional properties: +- reset-gpios: One GPIO that control the RESET lines of all PHYs on that MDIO + bus. +- reset-delay-us: RESET pulse width in microseconds. + +A list of child nodes, one per device on the bus is expected. These +should follow the generic phy.txt, or a device specific binding document. + +The 'reset-delay-us' indicates the RESET signal pulse width in microseconds and +applies to all PHY devices. It must therefore be appropriately determined based +on all PHY requirements (maximum value of all per-PHY RESET pulse widths). + +Example : +This example shows these optional properties, plus other properties +required for the TI Davinci MDIO driver. + + davinci_mdio: ethernet@5c030000 { + compatible = "ti,davinci_mdio"; + reg = <0x5c030000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + reset-delay-us = <2>; + + ethphy0: ethernet-phy@1 { + reg = <1>; + }; + + ethphy1: ethernet-phy@3 { + reg = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mediatek,mt7620-gsw.txt b/arch/arm64/boot/dts/vendor/bindings/net/mediatek,mt7620-gsw.txt new file mode 100644 index 0000000000000000000000000000000000000000..358fed2fab434ff77834e04e28ef0b89c00cf9d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mediatek,mt7620-gsw.txt @@ -0,0 +1,24 @@ +Mediatek Gigabit Switch +======================= + +The mediatek gigabit switch can be found on Mediatek SoCs (mt7620, mt7621). + +Required properties: +- compatible: Should be "mediatek,mt7620-gsw" or "mediatek,mt7621-gsw" +- reg: Address and length of the register set for the device +- interrupts: Should contain the gigabit switches interrupt +- resets: Should contain the gigabit switches resets +- reset-names: Should contain the reset names "gsw" + +Example: + +gsw@10110000 { + compatible = "ralink,mt7620-gsw"; + reg = <0x10110000 8000>; + + resets = <&rstctrl 23>; + reset-names = "gsw"; + + interrupt-parent = <&intc>; + interrupts = <17>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mediatek-bluetooth.txt b/arch/arm64/boot/dts/vendor/bindings/net/mediatek-bluetooth.txt new file mode 100644 index 0000000000000000000000000000000000000000..14ceb2a5b4e81d242f48b58c4e64f0bdab043c34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mediatek-bluetooth.txt @@ -0,0 +1,35 @@ +MediaTek SoC built-in Bluetooth Devices +================================== + +This device is a serial attached device to BTIF device and thus it must be a +child node of the serial node with BTIF. The dt-bindings details for BTIF +device can be known via Documentation/devicetree/bindings/serial/8250.txt. + +Required properties: + +- compatible: Must be + "mediatek,mt7622-bluetooth": for MT7622 SoC +- clocks: Should be the clock specifiers corresponding to the entry in + clock-names property. +- clock-names: Should contain "ref" entries. +- power-domains: Phandle to the power domain that the device is part of + +Example: + + btif: serial@1100c000 { + compatible = "mediatek,mt7622-btif", + "mediatek,mtk-btif"; + reg = <0 0x1100c000 0 0x1000>; + interrupts = ; + clocks = <&pericfg CLK_PERI_BTIF_PD>; + clock-names = "main"; + reg-shift = <2>; + reg-io-width = <4>; + + bluetooth { + compatible = "mediatek,mt7622-bluetooth"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_WB>; + clocks = <&clk25m>; + clock-names = "ref"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mediatek-net.txt b/arch/arm64/boot/dts/vendor/bindings/net/mediatek-net.txt new file mode 100644 index 0000000000000000000000000000000000000000..503f2b9194e275458ba62ce8aba664a7e7112435 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mediatek-net.txt @@ -0,0 +1,87 @@ +MediaTek Frame Engine Ethernet controller +========================================= + +The frame engine ethernet controller can be found on MediaTek SoCs. These SoCs +have dual GMAC each represented by a child node.. + +* Ethernet controller node + +Required properties: +- compatible: Should be + "mediatek,mt2701-eth": for MT2701 SoC + "mediatek,mt7623-eth", "mediatek,mt2701-eth": for MT7623 SoC + "mediatek,mt7622-eth": for MT7622 SoC +- reg: Address and length of the register set for the device +- interrupts: Should contain the three frame engines interrupts in numeric + order. These are fe_int0, fe_int1 and fe_int2. +- clocks: the clock used by the core +- clock-names: the names of the clock listed in the clocks property. These are + "ethif", "esw", "gp2", "gp1" : For MT2701 and MT7623 SoC + "ethif", "esw", "gp0", "gp1", "gp2", "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", "sgmii_ck", "eth2pll" : For MT7622 SoC +- power-domains: phandle to the power domain that the ethernet is part of +- resets: Should contain phandles to the ethsys reset signals +- reset-names: Should contain the names of reset signal listed in the resets + property + These are "fe", "gmac" and "ppe" +- mediatek,ethsys: phandle to the syscon node that handles the port setup +- mediatek,sgmiisys: phandle to the syscon node that handles the SGMII setup + which is required for those SoCs equipped with SGMII such as MT7622 SoC. +- mediatek,pctl: phandle to the syscon node that handles the ports slew rate + and driver current: only for MT2701 and MT7623 SoC + +* Ethernet MAC node + +Required properties: +- compatible: Should be "mediatek,eth-mac" +- reg: The number of the MAC +- phy-handle: see ethernet.txt file in the same directory and + the phy-mode "trgmii" required being provided when reg + is equal to 0 and the MAC uses fixed-link to connect + with internal switch such as MT7530. + +Example: + +eth: ethernet@1b100000 { + compatible = "mediatek,mt7623-eth"; + reg = <0 0x1b100000 0 0x20000>; + clocks = <&topckgen CLK_TOP_ETHIF_SEL>, + <ðsys CLK_ETHSYS_ESW>, + <ðsys CLK_ETHSYS_GP2>, + <ðsys CLK_ETHSYS_GP1>; + clock-names = "ethif", "esw", "gp2", "gp1"; + interrupts = ; + power-domains = <&scpsys MT2701_POWER_DOMAIN_ETH>; + resets = <ðsys MT2701_ETHSYS_ETH_RST>; + reset-names = "eth"; + mediatek,ethsys = <ðsys>; + mediatek,pctl = <&syscfg_pctl_a>; + #address-cells = <1>; + #size-cells = <0>; + + gmac1: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-handle = <&phy0>; + }; + + gmac2: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-handle = <&phy1>; + }; + + mdio-bus { + phy0: ethernet-phy@0 { + reg = <0>; + phy-mode = "rgmii"; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + phy-mode = "rgmii"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/meson-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/meson-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..1321bb194ed99e455b9a1105fbf8dade63767b45 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/meson-dwmac.txt @@ -0,0 +1,71 @@ +* Amlogic Meson DWMAC Ethernet controller + +The device inherits all the properties of the dwmac/stmmac devices +described in the file stmmac.txt in the current directory with the +following changes. + +Required properties on all platforms: + +- compatible: Depending on the platform this should be one of: + - "amlogic,meson6-dwmac" + - "amlogic,meson8b-dwmac" + - "amlogic,meson8m2-dwmac" + - "amlogic,meson-gxbb-dwmac" + - "amlogic,meson-axg-dwmac" + Additionally "snps,dwmac" and any applicable more + detailed version number described in net/stmmac.txt + should be used. + +- reg: The first register range should be the one of the DWMAC + controller. The second range is is for the Amlogic specific + configuration (for example the PRG_ETHERNET register range + on Meson8b and newer) + +Required properties on Meson8b, Meson8m2, GXBB and newer: +- clock-names: Should contain the following: + - "stmmaceth" - see stmmac.txt + - "clkin0" - first parent clock of the internal mux + - "clkin1" - second parent clock of the internal mux + +Optional properties on Meson8b, Meson8m2, GXBB and newer: +- amlogic,tx-delay-ns: The internal RGMII TX clock delay (provided + by this driver) in nanoseconds. Allowed values + are: 0ns, 2ns, 4ns, 6ns. + When phy-mode is set to "rgmii" then the TX + delay should be explicitly configured. When + not configured a fallback of 2ns is used. + When the phy-mode is set to either "rgmii-id" + or "rgmii-txid" the TX clock delay is already + provided by the PHY. In that case this + property should be set to 0ns (which disables + the TX clock delay in the MAC to prevent the + clock from going off because both PHY and MAC + are adding a delay). + Any configuration is ignored when the phy-mode + is set to "rmii". + +Example for Meson6: + + ethmac: ethernet@c9410000 { + compatible = "amlogic,meson6-dwmac", "snps,dwmac"; + reg = <0xc9410000 0x10000 + 0xc1108108 0x4>; + interrupts = <0 8 1>; + interrupt-names = "macirq"; + clocks = <&clk81>; + clock-names = "stmmaceth"; + } + +Example for GXBB: + ethmac: ethernet@c9410000 { + compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac"; + reg = <0x0 0xc9410000 0x0 0x10000>, + <0x0 0xc8834540 0x0 0x8>; + interrupts = <0 8 1>; + interrupt-names = "macirq"; + clocks = <&clkc CLKID_ETH>, + <&clkc CLKID_FCLK_DIV2>, + <&clkc CLKID_MPLL2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; + phy-mode = "rgmii"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/micrel-ks8851.txt b/arch/arm64/boot/dts/vendor/bindings/net/micrel-ks8851.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbdf9a7359a2ef021c3d6f780e2c14e7f3434740 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/micrel-ks8851.txt @@ -0,0 +1,18 @@ +Micrel KS8851 Ethernet mac (MLL) + +Required properties: +- compatible = "micrel,ks8851-mll" of parallel interface +- reg : 2 physical address and size of registers for data and command +- interrupts : interrupt connection + +Micrel KS8851 Ethernet mac (SPI) + +Required properties: +- compatible = "micrel,ks8851" or the deprecated "ks8851" +- reg : chip select number +- interrupts : interrupt connection + +Optional properties: +- vdd-supply: analog 3.3V supply for Ethernet mac +- vdd-io-supply: digital 1.8V IO supply for Ethernet mac +- reset-gpios: reset_n input pin diff --git a/arch/arm64/boot/dts/vendor/bindings/net/micrel-ks8995.txt b/arch/arm64/boot/dts/vendor/bindings/net/micrel-ks8995.txt new file mode 100644 index 0000000000000000000000000000000000000000..281bc2498d12764740dab821e8cabcb5e0a3d8fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/micrel-ks8995.txt @@ -0,0 +1,20 @@ +Micrel KS8995 SPI controlled Ethernet Switch families + +Required properties (according to spi-bus.txt): +- compatible: either "micrel,ks8995", "micrel,ksz8864" or "micrel,ksz8795" + +Optional properties: +- reset-gpios : phandle of gpio that will be used to reset chip during probe + +Example: + +spi-master { + ... + switch@0 { + compatible = "micrel,ksz8795"; + + reg = <0>; + spi-max-frequency = <50000000>; + reset-gpios = <&gpio0 46 GPIO_ACTIVE_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/micrel-ksz90x1.txt b/arch/arm64/boot/dts/vendor/bindings/net/micrel-ksz90x1.txt new file mode 100644 index 0000000000000000000000000000000000000000..e22d8cfea687435550f72e56385da9b07a0b739e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/micrel-ksz90x1.txt @@ -0,0 +1,81 @@ +Micrel KSZ9021/KSZ9031 Gigabit Ethernet PHY + +Some boards require special tuning values, particularly when it comes +to clock delays. You can specify clock delay values in the PHY OF +device node. Deprecated, but still supported, these properties can +also be added to an Ethernet OF device node. + +Note that these settings are applied after any phy-specific fixup from +phy_fixup_list (see phy_init_hw() from drivers/net/phy/phy_device.c), +and therefore may overwrite them. + +KSZ9021: + + All skew control options are specified in picoseconds. The minimum + value is 0, the maximum value is 3000, and it is incremented by 200ps + steps. + + Optional properties: + + - rxc-skew-ps : Skew control of RXC pad + - rxdv-skew-ps : Skew control of RX CTL pad + - txc-skew-ps : Skew control of TXC pad + - txen-skew-ps : Skew control of TX CTL pad + - rxd0-skew-ps : Skew control of RX data 0 pad + - rxd1-skew-ps : Skew control of RX data 1 pad + - rxd2-skew-ps : Skew control of RX data 2 pad + - rxd3-skew-ps : Skew control of RX data 3 pad + - txd0-skew-ps : Skew control of TX data 0 pad + - txd1-skew-ps : Skew control of TX data 1 pad + - txd2-skew-ps : Skew control of TX data 2 pad + - txd3-skew-ps : Skew control of TX data 3 pad + +KSZ9031: + + All skew control options are specified in picoseconds. The minimum + value is 0, and the maximum is property-dependent. The increment + step is 60ps. The default value is the neutral setting, so setting + rxc-skew-ps=<0> actually results in -900 picoseconds adjustment. + + Optional properties: + + Maximum value of 1860, default value 900: + + - rxc-skew-ps : Skew control of RX clock pad + - txc-skew-ps : Skew control of TX clock pad + + Maximum value of 900, default value 420: + + - rxdv-skew-ps : Skew control of RX CTL pad + - txen-skew-ps : Skew control of TX CTL pad + - rxd0-skew-ps : Skew control of RX data 0 pad + - rxd1-skew-ps : Skew control of RX data 1 pad + - rxd2-skew-ps : Skew control of RX data 2 pad + - rxd3-skew-ps : Skew control of RX data 3 pad + - txd0-skew-ps : Skew control of TX data 0 pad + - txd1-skew-ps : Skew control of TX data 1 pad + - txd2-skew-ps : Skew control of TX data 2 pad + - txd3-skew-ps : Skew control of TX data 3 pad + + - micrel,force-master: + Boolean, force phy to master mode. Only set this option if the phy + reference clock provided at CLK125_NDO pin is used as MAC reference + clock because the clock jitter in slave mode is to high (errata#2). + Attention: The link partner must be configurable as slave otherwise + no link will be established. + +Examples: + + mdio { + phy0: ethernet-phy@0 { + rxc-skew-ps = <3000>; + rxdv-skew-ps = <0>; + txc-skew-ps = <3000>; + txen-skew-ps = <0>; + reg = <0>; + }; + }; + ethernet@70000 { + phy = <&phy0>; + phy-mode = "rgmii-id"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/micrel.txt b/arch/arm64/boot/dts/vendor/bindings/net/micrel.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d157f0295a502fd326eab4e2196f17654d8b484 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/micrel.txt @@ -0,0 +1,47 @@ +Micrel PHY properties. + +These properties cover the base properties Micrel PHYs. + +Optional properties: + + - micrel,led-mode : LED mode value to set for PHYs with configurable LEDs. + + Configure the LED mode with single value. The list of PHYs and the + bits that are currently supported: + + KSZ8001: register 0x1e, bits 15..14 + KSZ8041: register 0x1e, bits 15..14 + KSZ8021: register 0x1f, bits 5..4 + KSZ8031: register 0x1f, bits 5..4 + KSZ8051: register 0x1f, bits 5..4 + KSZ8081: register 0x1f, bits 5..4 + KSZ8091: register 0x1f, bits 5..4 + + See the respective PHY datasheet for the mode values. + + - micrel,rmii-reference-clock-select-25-mhz: RMII Reference Clock Select + bit selects 25 MHz mode + + Setting the RMII Reference Clock Select bit enables 25 MHz rather + than 50 MHz clock mode. + + Note that this option in only needed for certain PHY revisions with a + non-standard, inverted function of this configuration bit. + Specifically, a clock reference ("rmii-ref" below) is always needed to + actually select a mode. + + - clocks, clock-names: contains clocks according to the common clock bindings. + + supported clocks: + - KSZ8021, KSZ8031, KSZ8081, KSZ8091: "rmii-ref": The RMII reference + input clock. Used to determine the XI input clock. + + - micrel,fiber-mode: If present the PHY is configured to operate in fiber mode + + Some PHYs, such as the KSZ8041FTL variant, support fiber mode, enabled + by the FXEN boot strapping pin. It can't be determined from the PHY + registers whether the PHY is in fiber mode, so this boolean device tree + property can be used to describe it. + + In fiber mode, auto-negotiation is disabled and the PHY can only work in + 100base-fx (full and half duplex) modes. diff --git a/arch/arm64/boot/dts/vendor/bindings/net/microchip,enc28j60.txt b/arch/arm64/boot/dts/vendor/bindings/net/microchip,enc28j60.txt new file mode 100644 index 0000000000000000000000000000000000000000..24626e082b838f25a33e6fea0cebd8a0f75fcfef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/microchip,enc28j60.txt @@ -0,0 +1,55 @@ +* Microchip ENC28J60 + +This is a standalone 10 MBit ethernet controller with SPI interface. + +For each device connected to a SPI bus, define a child node within +the SPI master node. + +Required properties: +- compatible: Should be "microchip,enc28j60" +- reg: Specify the SPI chip select the ENC28J60 is wired to +- interrupts: Specify the interrupt index within the interrupt controller (referred + to above in interrupt-parent) and interrupt type. The ENC28J60 natively + generates falling edge interrupts, however, additional board logic + might invert the signal. +- pinctrl-names: List of assigned state names, see pinctrl binding documentation. +- pinctrl-0: List of phandles to configure the GPIO pin used as interrupt line, + see also generic and your platform specific pinctrl binding + documentation. + +Optional properties: +- spi-max-frequency: Maximum frequency of the SPI bus when accessing the ENC28J60. + According to the ENC28J80 datasheet, the chip allows a maximum of 20 MHz, however, + board designs may need to limit this value. +- local-mac-address: See ethernet.txt in the same directory. + + +Example (for NXP i.MX28 with pin control stuff for GPIO irq): + + ssp2: ssp@80014000 { + compatible = "fsl,imx28-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins_b &spi2_sck_cfg>; + + enc28j60: ethernet@0 { + compatible = "microchip,enc28j60"; + pinctrl-names = "default"; + pinctrl-0 = <&enc28j60_pins>; + reg = <0>; + interrupt-parent = <&gpio3>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + spi-max-frequency = <12000000>; + }; + }; + + pinctrl@80018000 { + enc28j60_pins: enc28j60_pins@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_AUART0_RTS__GPIO_3_3 /* Interrupt */ + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/microchip,lan78xx.txt b/arch/arm64/boot/dts/vendor/bindings/net/microchip,lan78xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..76786a0f6d3d7c06d5ce09ba15c311621def50cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/microchip,lan78xx.txt @@ -0,0 +1,54 @@ +Microchip LAN78xx Gigabit Ethernet controller + +The LAN78XX devices are usually configured by programming their OTP or with +an external EEPROM, but some platforms (e.g. Raspberry Pi 3 B+) have neither. +The Device Tree properties, if present, override the OTP and EEPROM. + +Required properties: +- compatible: Should be one of "usb424,7800", "usb424,7801" or "usb424,7850". + +Optional properties: +- local-mac-address: see ethernet.txt +- mac-address: see ethernet.txt + +Optional properties of the embedded PHY: +- microchip,led-modes: a 0..4 element vector, with each element configuring + the operating mode of an LED. Omitted LEDs are turned off. Allowed values + are defined in "include/dt-bindings/net/microchip-lan78xx.h". + +Example: + +/* Based on the configuration for a Raspberry Pi 3 B+ */ +&usb { + usb-port@1 { + compatible = "usb424,2514"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + usb-port@1 { + compatible = "usb424,2514"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + ethernet: ethernet@1 { + compatible = "usb424,7800"; + reg = <1>; + local-mac-address = [ 00 11 22 33 44 55 ]; + + mdio { + #address-cells = <0x1>; + #size-cells = <0x0>; + eth_phy: ethernet-phy@1 { + reg = <1>; + microchip,led-modes = < + LAN78XX_LINK_1000_ACTIVITY + LAN78XX_LINK_10_100_ACTIVITY + >; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mscc-miim.txt b/arch/arm64/boot/dts/vendor/bindings/net/mscc-miim.txt new file mode 100644 index 0000000000000000000000000000000000000000..7104679cf59d5ecde0c7d492daecf59fa7be8e29 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mscc-miim.txt @@ -0,0 +1,26 @@ +Microsemi MII Management Controller (MIIM) / MDIO +================================================= + +Properties: +- compatible: must be "mscc,ocelot-miim" +- reg: The base address of the MDIO bus controller register bank. Optionally, a + second register bank can be defined if there is an associated reset register + for internal PHYs +- #address-cells: Must be <1>. +- #size-cells: Must be <0>. MDIO addresses have no size component. +- interrupts: interrupt specifier (refer to the interrupt binding) + +Typically an MDIO bus might have several children. + +Example: + mdio@107009c { + #address-cells = <1>; + #size-cells = <0>; + compatible = "mscc,ocelot-miim"; + reg = <0x107009c 0x36>, <0x10700f0 0x8>; + interrupts = <14>; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mscc-ocelot.txt b/arch/arm64/boot/dts/vendor/bindings/net/mscc-ocelot.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a84711abece92049c9768bddb5fb95e5f6d812b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mscc-ocelot.txt @@ -0,0 +1,82 @@ +Microsemi Ocelot network Switch +=============================== + +The Microsemi Ocelot network switch can be found on Microsemi SoCs (VSC7513, +VSC7514) + +Required properties: +- compatible: Should be "mscc,vsc7514-switch" +- reg: Must contain an (offset, length) pair of the register set for each + entry in reg-names. +- reg-names: Must include the following entries: + - "sys" + - "rew" + - "qs" + - "hsio" + - "qsys" + - "ana" + - "portX" with X from 0 to the number of last port index available on that + switch +- interrupts: Should contain the switch interrupts for frame extraction and + frame injection +- interrupt-names: should contain the interrupt names: "xtr", "inj" +- ethernet-ports: A container for child nodes representing switch ports. + +The ethernet-ports container has the following properties + +Required properties: + +- #address-cells: Must be 1 +- #size-cells: Must be 0 + +Each port node must have the following mandatory properties: +- reg: Describes the port address in the switch + +Port nodes may also contain the following optional standardised +properties, described in binding documents: + +- phy-handle: Phandle to a PHY on an MDIO bus. See + Documentation/devicetree/bindings/net/ethernet.txt for details. + +Example: + + switch@1010000 { + compatible = "mscc,vsc7514-switch"; + reg = <0x1010000 0x10000>, + <0x1030000 0x10000>, + <0x1080000 0x100>, + <0x10d0000 0x10000>, + <0x11e0000 0x100>, + <0x11f0000 0x100>, + <0x1200000 0x100>, + <0x1210000 0x100>, + <0x1220000 0x100>, + <0x1230000 0x100>, + <0x1240000 0x100>, + <0x1250000 0x100>, + <0x1260000 0x100>, + <0x1270000 0x100>, + <0x1280000 0x100>, + <0x1800000 0x80000>, + <0x1880000 0x10000>; + reg-names = "sys", "rew", "qs", "hsio", "port0", + "port1", "port2", "port3", "port4", "port5", + "port6", "port7", "port8", "port9", "port10", + "qsys", "ana"; + interrupts = <21 22>; + interrupt-names = "xtr", "inj"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + port0: port@0 { + reg = <0>; + phy-handle = <&phy0>; + }; + port1: port@1 { + reg = <1>; + phy-handle = <&phy1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/mscc-phy-vsc8531.txt b/arch/arm64/boot/dts/vendor/bindings/net/mscc-phy-vsc8531.txt new file mode 100644 index 0000000000000000000000000000000000000000..0eedabe22cc3db8c79410b197ca0e8f0afc45710 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/mscc-phy-vsc8531.txt @@ -0,0 +1,73 @@ +* Microsemi - vsc8531 Giga bit ethernet phy + +Required properties: +- compatible : Should contain phy id as "ethernet-phy-idAAAA.BBBB" + The PHY device uses the binding described in + Documentation/devicetree/bindings/net/phy.txt + +Optional properties: +- vsc8531,vddmac : The vddmac in mV. Allowed values is listed + in the first row of Table 1 (below). + This property is only used in combination + with the 'edge-slowdown' property. + Default value is 3300. +- vsc8531,edge-slowdown : % the edge should be slowed down relative to + the fastest possible edge time. + Edge rate sets the drive strength of the MAC + interface output signals. Changing the + drive strength will affect the edge rate of + the output signal. The goal of this setting + is to help reduce electrical emission (EMI) + by being able to reprogram drive strength + and in effect slow down the edge rate if + desired. + To adjust the edge-slowdown, the 'vddmac' + must be specified. Table 1 lists the + supported edge-slowdown values for a given + 'vddmac'. + Default value is 0%. + Ref: Table:1 - Edge rate change (below). +- vsc8531,led-0-mode : LED mode. Specify how the LED[0] should behave. + Allowed values are define in + "include/dt-bindings/net/mscc-phy-vsc8531.h". + Default value is VSC8531_LINK_1000_ACTIVITY (1). +- vsc8531,led-1-mode : LED mode. Specify how the LED[1] should behave. + Allowed values are define in + "include/dt-bindings/net/mscc-phy-vsc8531.h". + Default value is VSC8531_LINK_100_ACTIVITY (2). + +Table: 1 - Edge rate change +----------------------------------------------------------------| +| Edge Rate Change (VDDMAC) | +| | +| 3300 mV 2500 mV 1800 mV 1500 mV | +|---------------------------------------------------------------| +| 0% 0% 0% 0% | +| (Fastest) (recommended) (recommended) | +|---------------------------------------------------------------| +| 2% 3% 5% 6% | +|---------------------------------------------------------------| +| 4% 6% 9% 14% | +|---------------------------------------------------------------| +| 7% 10% 16% 21% | +|(recommended) (recommended) | +|---------------------------------------------------------------| +| 10% 14% 23% 29% | +|---------------------------------------------------------------| +| 17% 23% 35% 42% | +|---------------------------------------------------------------| +| 29% 37% 52% 58% | +|---------------------------------------------------------------| +| 53% 63% 76% 77% | +| (slowest) | +|---------------------------------------------------------------| + +Example: + + vsc8531_0: ethernet-phy@0 { + compatible = "ethernet-phy-id0007.0570"; + vsc8531,vddmac = <3300>; + vsc8531,edge-slowdown = <7>; + vsc8531,led-0-mode = ; + vsc8531,led-1-mode = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/nfcmrvl.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/nfcmrvl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9b35251bb20d933f892bca518a7dc6752fa4c49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/nfcmrvl.txt @@ -0,0 +1,84 @@ +* Marvell International Ltd. NCI NFC Controller + +Required properties: +- compatible: Should be: + - "marvell,nfc-uart" or "mrvl,nfc-uart" for UART devices + - "marvell,nfc-i2c" for I2C devices + - "marvell,nfc-spi" for SPI devices + +Optional SoC specific properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. +- reset-n-io: Output GPIO pin used to reset the chip (active low). +- hci-muxed: Specifies that the chip is muxing NCI over HCI frames. + +Optional UART-based chip specific properties: +- flow-control: Specifies that the chip is using RTS/CTS. +- break-control: Specifies that the chip needs specific break management. + +Optional I2C-based chip specific properties: +- i2c-int-falling: Specifies that the chip read event shall be trigged on + falling edge. +- i2c-int-rising: Specifies that the chip read event shall be trigged on + rising edge. + +Example (for ARM-based BeagleBoard Black with 88W8887 on UART5): + +&uart5 { + + nfcmrvluart: nfcmrvluart@5 { + compatible = "marvell,nfc-uart"; + + reset-n-io = <&gpio3 16 0>; + + hci-muxed; + flow-control; + } +}; + + +Example (for ARM-based BeagleBoard Black with 88W8887 on I2C1): + +&i2c1 { + clock-frequency = <400000>; + + nfcmrvli2c0: i2c@1 { + compatible = "marvell,nfc-i2c"; + + reg = <0x8>; + + /* I2C INT configuration */ + interrupt-parent = <&gpio3>; + interrupts = <21 0>; + + /* I2C INT trigger configuration */ + i2c-int-rising; + + /* Reset IO */ + reset-n-io = <&gpio3 19 0>; + }; +}; + + +Example (for ARM-based BeagleBoard Black on SPI0): + +&spi0 { + + mrvlnfcspi0: spi@0 { + compatible = "marvell,nfc-spi"; + + reg = <0>; + + /* SPI Bus configuration */ + spi-max-frequency = <3000000>; + spi-cpha; + spi-cpol; + + /* SPI INT configuration */ + interrupt-parent = <&gpio1>; + interrupts = <17 0>; + + /* Reset IO */ + reset-n-io = <&gpio3 19 0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/nxp-nci.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/nxp-nci.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfaf8899891871b2f86d83cec69ef1effebe3fc9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/nxp-nci.txt @@ -0,0 +1,33 @@ +* NXP Semiconductors NXP NCI NFC Controllers + +Required properties: +- compatible: Should be "nxp,nxp-nci-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupts: GPIO interrupt to which the chip is connected +- enable-gpios: Output GPIO pin used for enabling/disabling the chip +- firmware-gpios: Output GPIO pin used to enter firmware download mode + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2): + +&i2c2 { + + + npc100: npc100@29 { + + compatible = "nxp,nxp-nci-i2c"; + + reg = <0x29>; + clock-frequency = <100000>; + + interrupt-parent = <&gpio1>; + interrupts = <29 GPIO_ACTIVE_HIGH>; + + enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/pn533-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/pn533-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..2efe3886b95b489fffb54170273d56deaeca3333 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/pn533-i2c.txt @@ -0,0 +1,29 @@ +* NXP Semiconductors PN532 NFC Controller + +Required properties: +- compatible: Should be "nxp,pn532-i2c" or "nxp,pn533-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupts: GPIO interrupt to which the chip is connected + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with PN532 on I2C2): + +&i2c2 { + + + pn532: pn532@24 { + + compatible = "nxp,pn532-i2c"; + + reg = <0x24>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio1>; + interrupts = <17 IRQ_TYPE_EDGE_FALLING>; + + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/pn544.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/pn544.txt new file mode 100644 index 0000000000000000000000000000000000000000..92f399ec22b87503029b8a86e40e50ef17c16434 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/pn544.txt @@ -0,0 +1,33 @@ +* NXP Semiconductors PN544 NFC Controller + +Required properties: +- compatible: Should be "nxp,pn544-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupts: GPIO interrupt to which the chip is connected +- enable-gpios: Output GPIO pin used for enabling/disabling the PN544 +- firmware-gpios: Output GPIO pin used to enter firmware download mode + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with PN544 on I2C2): + +&i2c2 { + + + pn544: pn544@28 { + + compatible = "nxp,pn544-i2c"; + + reg = <0x28>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio1>; + interrupts = <17 GPIO_ACTIVE_HIGH>; + + enable-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + firmware-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/s3fwrn5.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/s3fwrn5.txt new file mode 100644 index 0000000000000000000000000000000000000000..f02f6fb7f81c2157eb35352679303afce01ce5ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/s3fwrn5.txt @@ -0,0 +1,25 @@ +* Samsung S3FWRN5 NCI NFC Controller + +Required properties: +- compatible: Should be "samsung,s3fwrn5-i2c". +- reg: address on the bus +- interrupts: GPIO interrupt to which the chip is connected +- s3fwrn5,en-gpios: Output GPIO pin used for enabling/disabling the chip +- s3fwrn5,fw-gpios: Output GPIO pin used to enter firmware mode and + sleep/wakeup control + +Example: + +&hsi2c_4 { + s3fwrn5@27 { + compatible = "samsung,s3fwrn5-i2c"; + + reg = <0x27>; + + interrupt-parent = <&gpa1>; + interrupts = <3 0 0>; + + s3fwrn5,en-gpios = <&gpf1 4 0>; + s3fwrn5,fw-gpios = <&gpj0 2 0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/st-nci-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st-nci-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..baa8f8133d19f4355a70b5c0ded14b2bd815a16c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st-nci-i2c.txt @@ -0,0 +1,38 @@ +* STMicroelectronics SAS. ST NCI NFC Controller + +Required properties: +- compatible: Should be "st,st21nfcb-i2c" or "st,st21nfcc-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupts: GPIO interrupt to which the chip is connected +- reset-gpios: Output GPIO pin used to reset the ST21NFCB + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. +- ese-present: Specifies that an ese is physically connected to the nfc +controller. +- uicc-present: Specifies that the uicc swp signal can be physically +connected to the nfc controller. + +Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): + +&i2c2 { + + + st21nfcb: st21nfcb@8 { + + compatible = "st,st21nfcb-i2c"; + + reg = <0x08>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + + reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; + + ese-present; + uicc-present; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/st-nci-spi.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st-nci-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..d33343330b9448817bb41022dc2d2285c574f311 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st-nci-spi.txt @@ -0,0 +1,36 @@ +* STMicroelectronics SAS. ST NCI NFC Controller + +Required properties: +- compatible: Should be "st,st21nfcb-spi" +- spi-max-frequency: Maximum SPI frequency (<= 4000000). +- interrupts: GPIO interrupt to which the chip is connected +- reset-gpios: Output GPIO pin used to reset the ST21NFCB + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. +- ese-present: Specifies that an ese is physically connected to the nfc +controller. +- uicc-present: Specifies that the uicc swp signal can be physically +connected to the nfc controller. + +Example (for ARM-based BeagleBoard xM with ST21NFCB on SPI4): + +&mcspi4 { + + + st21nfcb: st21nfcb@0 { + + compatible = "st,st21nfcb-spi"; + + clock-frequency = <4000000>; + + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_EDGE_RISING>; + + reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; + + ese-present; + uicc-present; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/st21nfca.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st21nfca.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8bd90f80e12e7ba3f2d6bab8dfa9e6ea3f5c205 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st21nfca.txt @@ -0,0 +1,37 @@ +* STMicroelectronics SAS. ST21NFCA NFC Controller + +Required properties: +- compatible: Should be "st,st21nfca-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- enable-gpios: Output GPIO pin used for enabling/disabling the ST21NFCA + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. +- ese-present: Specifies that an ese is physically connected to the nfc +controller. +- uicc-present: Specifies that the uicc swp signal can be physically +connected to the nfc controller. + +Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): + +&i2c2 { + + + st21nfca: st21nfca@1 { + + compatible = "st,st21nfca-i2c"; + + reg = <0x01>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <2 IRQ_TYPE_LEVEL_LOW>; + + enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; + + ese-present; + uicc-present; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/st95hf.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st95hf.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f373a1e20ff3c03152ec914920a447dec18238f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/st95hf.txt @@ -0,0 +1,45 @@ +* STMicroelectronics : NFC Transceiver ST95HF + +ST NFC Transceiver is required to attach with SPI bus. +ST95HF node should be defined in DT as SPI slave device of SPI +master with which ST95HF transceiver is physically connected. +The properties defined below are required to be the part of DT +to include ST95HF transceiver into the platform. + +Required properties: +=================== +- reg: Address of SPI slave "ST95HF transceiver" on SPI master bus. + +- compatible: should be "st,st95hf" for ST95HF NFC transceiver + +- spi-max-frequency: Max. operating SPI frequency for ST95HF + transceiver. + +- enable-gpio: GPIO line to enable ST95HF transceiver. + +- interrupts : Standard way to define ST95HF transceiver's out + interrupt. + +Optional property: +================= +- st95hfvin-supply : This is an optional property. It contains a + phandle to ST95HF transceiver's regulator supply node in DT. + +Example: +======= +spi@9840000 { + reg = <0x9840000 0x110>; + #address-cells = <1>; + #size-cells = <0>; + cs-gpios = <&pio0 4>; + + st95hf@0{ + reg = <0>; + compatible = "st,st95hf"; + spi-max-frequency = <1000000>; + enable-gpio = <&pio4 0>; + interrupt-parent = <&pio0>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nfc/trf7970a.txt b/arch/arm64/boot/dts/vendor/bindings/net/nfc/trf7970a.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba1934b950e5d04ad8822b6e27c02a3a8c52a3da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nfc/trf7970a.txt @@ -0,0 +1,43 @@ +* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver + +Required properties: +- compatible: Should be "ti,trf7970a". +- spi-max-frequency: Maximum SPI frequency (<= 2000000). +- interrupts: A single interrupt specifier. +- ti,enable-gpios: One or two GPIO entries used for 'EN' and 'EN2' pins on the + TRF7970A. EN2 is optional. +- vin-supply: Regulator for supply voltage to VIN pin + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. +- autosuspend-delay: Specify autosuspend delay in milliseconds. +- irq-status-read-quirk: Specify that the trf7970a being used has the + "IRQ Status Read" erratum. +- en2-rf-quirk: Specify that the trf7970a being used has the "EN2 RF" + erratum. +- vdd-io-supply: Regulator specifying voltage for vdd-io +- clock-frequency: Set to specify that the input frequency to the trf7970a is 13560000Hz or 27120000Hz + +Example (for ARM-based BeagleBone with TRF7970A on SPI1): + +&spi1 { + + nfc@0 { + compatible = "ti,trf7970a"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&trf7970a_default>; + spi-max-frequency = <2000000>; + interrupt-parent = <&gpio2>; + interrupts = <14 0>; + ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>, + <&gpio2 5 GPIO_ACTIVE_HIGH>; + vin-supply = <&ldo3_reg>; + vdd-io-supply = <&ldo2_reg>; + autosuspend-delay = <30000>; + irq-status-read-quirk; + en2-rf-quirk; + clock-frequency = <27120000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nixge.txt b/arch/arm64/boot/dts/vendor/bindings/net/nixge.txt new file mode 100644 index 0000000000000000000000000000000000000000..e55af7f0881a10ac03915d03338d7932edd81a37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nixge.txt @@ -0,0 +1,32 @@ +* NI XGE Ethernet controller + +Required properties: +- compatible: Should be "ni,xge-enet-2.00" +- reg: Address and length of the register set for the device +- interrupts: Should contain tx and rx interrupt +- interrupt-names: Should be "rx" and "tx" +- phy-mode: See ethernet.txt file in the same directory. +- phy-handle: See ethernet.txt file in the same directory. +- nvmem-cells: Phandle of nvmem cell containing the MAC address +- nvmem-cell-names: Should be "address" + +Examples (10G generic PHY): + nixge0: ethernet@40000000 { + compatible = "ni,xge-enet-2.00"; + reg = <0x40000000 0x6000>; + + nvmem-cells = <ð1_addr>; + nvmem-cell-names = "address"; + + interrupts = <0 29 IRQ_TYPE_LEVEL_HIGH>, <0 30 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "rx", "tx"; + interrupt-parent = <&intc>; + + phy-mode = "xgmii"; + phy-handle = <ðernet_phy1>; + + ethernet_phy1: ethernet-phy@4 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nokia-bluetooth.txt b/arch/arm64/boot/dts/vendor/bindings/net/nokia-bluetooth.txt new file mode 100644 index 0000000000000000000000000000000000000000..42be7dc9a70ba7cb0f653270e4941dc85046b6e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nokia-bluetooth.txt @@ -0,0 +1,51 @@ +Nokia Bluetooth Chips +--------------------- + +Nokia phones often come with UART connected bluetooth chips from different +vendors and modified device API. Those devices speak a protocol named H4+ +(also known as h4p) by Nokia, which is similar to the H4 protocol from the +Bluetooth standard. In addition to the H4 protocol it specifies two more +UART status lines for wakeup of UART transceivers to improve power management +and a few new packet types used to negotiate uart speed. + +Required properties: + + - compatible: should contain "nokia,h4p-bluetooth" as well as one of the following: + * "brcm,bcm2048-nokia" + * "ti,wl1271-bluetooth-nokia" + - reset-gpios: GPIO specifier, used to reset the BT module (active low) + - bluetooth-wakeup-gpios: GPIO specifier, used to wakeup the BT module (active high) + - host-wakeup-gpios: GPIO specifier, used to wakeup the host processor (active high) + - clock-names: should be "sysclk" + - clocks: should contain a clock specifier for every name in clock-names + +Optional properties: + + - None + +Example: + +/ { + /* controlled (enabled/disabled) directly by BT module */ + bluetooth_clk: vctcxo { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <38400000>; + }; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + + bluetooth { + compatible = "ti,wl1271-bluetooth-nokia", "nokia,h4p-bluetooth"; + + reset-gpios = <&gpio1 26 GPIO_ACTIVE_LOW>; /* gpio26 */ + host-wakeup-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ + bluetooth-wakeup-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>; /* gpio37 */ + + clocks = <&bluetooth_clk>; + clock-names = "sysclk"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/nxp,lpc1850-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/nxp,lpc1850-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..7edba1264f6f2bf194b6e261a4ce50e4d2622c22 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/nxp,lpc1850-dwmac.txt @@ -0,0 +1,20 @@ +* NXP LPC1850 GMAC ethernet controller + +This device is a platform glue layer for stmmac. +Please see stmmac.txt for the other unchanged properties. + +Required properties: + - compatible: Should contain "nxp,lpc1850-dwmac" + +Examples: + +mac: ethernet@40010000 { + compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac"; + reg = <0x40010000 0x2000>; + interrupts = <5>; + interrupt-names = "macirq"; + clocks = <&ccu1 CLK_CPU_ETHERNET>; + clock-names = "stmmaceth"; + resets = <&rgu 22>; + reset-names = "stmmaceth"; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/net/opencores-ethoc.txt b/arch/arm64/boot/dts/vendor/bindings/net/opencores-ethoc.txt new file mode 100644 index 0000000000000000000000000000000000000000..2dc127c30d9b310f65389c282dddc0905624f687 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/opencores-ethoc.txt @@ -0,0 +1,22 @@ +* OpenCores MAC 10/100 Mbps + +Required properties: +- compatible: Should be "opencores,ethoc". +- reg: two memory regions (address and length), + first region is for the device registers and descriptor rings, + second is for the device packet memory. +- interrupts: interrupt for the device. + +Optional properties: +- clocks: phandle to refer to the clk used as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Examples: + + enet0: ethoc@fd030000 { + compatible = "opencores,ethoc"; + reg = <0xfd030000 0x4000 0xfd800000 0x4000>; + interrupts = <1>; + local-mac-address = [00 50 c2 13 6f 00]; + clocks = <&osc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/oxnas-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/oxnas-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7117a22fd870070950e2c6c811f244f2b8f2979 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/oxnas-dwmac.txt @@ -0,0 +1,38 @@ +* Oxford Semiconductor OXNAS DWMAC Ethernet controller + +The device inherits all the properties of the dwmac/stmmac devices +described in the file stmmac.txt in the current directory with the +following changes. + +Required properties on all platforms: + +- compatible: For the OX820 SoC, it should be : + - "oxsemi,ox820-dwmac" to select glue + - "snps,dwmac-3.512" to select IP version. + +- clocks: Should contain phandles to the following clocks +- clock-names: Should contain the following: + - "stmmaceth" for the host clock - see stmmac.txt + - "gmac" for the peripheral gate clock + +- oxsemi,sys-ctrl: a phandle to the system controller syscon node + +Example : + +etha: ethernet@40400000 { + compatible = "oxsemi,ox820-dwmac", "snps,dwmac-3.512"; + reg = <0x40400000 0x2000>; + interrupts = , + ; + interrupt-names = "macirq", "eth_wake_irq"; + mac-address = [000000000000]; /* Filled in by U-Boot */ + phy-mode = "rgmii"; + + clocks = <&stdclk CLK_820_ETHA>, <&gmacclk>; + clock-names = "gmac", "stmmaceth"; + resets = <&reset RESET_MAC>; + + /* Regmap for sys registers */ + oxsemi,sys-ctrl = <&sys>; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/phy.txt b/arch/arm64/boot/dts/vendor/bindings/net/phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..17c1d2bd00f6dd64ebb4891b3293d22a10c0b22b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/phy.txt @@ -0,0 +1,73 @@ +PHY nodes + +Required properties: + + - interrupts : interrupt specifier for the sole interrupt. + - reg : The ID number for the phy, usually a small integer + +Optional Properties: + +- compatible: Compatible list, may contain + "ethernet-phy-ieee802.3-c22" or "ethernet-phy-ieee802.3-c45" for + PHYs that implement IEEE802.3 clause 22 or IEEE802.3 clause 45 + specifications. If neither of these are specified, the default is to + assume clause 22. + + If the PHY reports an incorrect ID (or none at all) then the + "compatible" list may contain an entry with the correct PHY ID in the + form: "ethernet-phy-idAAAA.BBBB" where + AAAA - The value of the 16 bit Phy Identifier 1 register as + 4 hex digits. This is the chip vendor OUI bits 3:18 + BBBB - The value of the 16 bit Phy Identifier 2 register as + 4 hex digits. This is the chip vendor OUI bits 19:24, + followed by 10 bits of a vendor specific ID. + + The compatible list should not contain other values than those + listed here. + +- max-speed: Maximum PHY supported speed (10, 100, 1000...) + +- broken-turn-around: If set, indicates the PHY device does not correctly + release the turn around line low at the end of a MDIO transaction. + +- enet-phy-lane-swap: If set, indicates the PHY will swap the TX/RX lanes to + compensate for the board being designed with the lanes swapped. + +- enet-phy-lane-no-swap: If set, indicates that PHY will disable swap of the + TX/RX lanes. This property allows the PHY to work correcly after e.g. wrong + bootstrap configuration caused by issues in PCB layout design. + +- eee-broken-100tx: +- eee-broken-1000t: +- eee-broken-10gt: +- eee-broken-1000kx: +- eee-broken-10gkx4: +- eee-broken-10gkr: + Mark the corresponding energy efficient ethernet mode as broken and + request the ethernet to stop advertising it. + +- phy-is-integrated: If set, indicates that the PHY is integrated into the same + physical package as the Ethernet MAC. If needed, muxers should be configured + to ensure the integrated PHY is used. The absence of this property indicates + the muxers should be configured so that the external PHY is used. + +- reset-gpios: The GPIO phandle and specifier for the PHY reset signal. + +- reset-assert-us: Delay after the reset was asserted in microseconds. + If this property is missing the delay will be skipped. + +- reset-deassert-us: Delay after the reset was deasserted in microseconds. + If this property is missing the delay will be skipped. + +Example: + +ethernet-phy@0 { + compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22"; + interrupt-parent = <&PIC>; + interrupts = <35 IRQ_TYPE_EDGE_RISING>; + reg = <0>; + + reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + reset-assert-us = <1000>; + reset-deassert-us = <2000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/qca,qca7000.txt b/arch/arm64/boot/dts/vendor/bindings/net/qca,qca7000.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4a8a51086dfcbc2d766d7b3d21eb15b900f79fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/qca,qca7000.txt @@ -0,0 +1,85 @@ +* Qualcomm QCA7000 + +The QCA7000 is a serial-to-powerline bridge with a host interface which could +be configured either as SPI or UART slave. This configuration is done by +the QCA7000 firmware. + +(a) Ethernet over SPI + +In order to use the QCA7000 as SPI device it must be defined as a child of a +SPI master in the device tree. + +Required properties: +- compatible : Should be "qca,qca7000" +- reg : Should specify the SPI chip select +- interrupts : The first cell should specify the index of the source + interrupt and the second cell should specify the trigger + type as rising edge +- spi-cpha : Must be set +- spi-cpol : Must be set + +Optional properties: +- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at. + Numbers smaller than 1000000 or greater than 16000000 + are invalid. Missing the property will set the SPI + frequency to 8000000 Hertz. +- local-mac-address : see ./ethernet.txt +- qca,legacy-mode : Set the SPI data transfer of the QCA7000 to legacy mode. + In this mode the SPI master must toggle the chip select + between each data word. In burst mode these gaps aren't + necessary, which is faster. This setting depends on how + the QCA7000 is setup via GPIO pin strapping. If the + property is missing the driver defaults to burst mode. + +SPI Example: + +/* Freescale i.MX28 SPI master*/ +ssp2: spi@80014000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins_a>; + + qca7000: ethernet@0 { + compatible = "qca,qca7000"; + reg = <0x0>; + interrupt-parent = <&gpio3>; /* GPIO Bank 3 */ + interrupts = <25 0x1>; /* Index: 25, rising edge */ + spi-cpha; /* SPI mode: CPHA=1 */ + spi-cpol; /* SPI mode: CPOL=1 */ + spi-max-frequency = <8000000>; /* freq: 8 MHz */ + local-mac-address = [ A0 B0 C0 D0 E0 F0 ]; + }; +}; + +(b) Ethernet over UART + +In order to use the QCA7000 as UART slave it must be defined as a child of a +UART master in the device tree. It is possible to preconfigure the UART +settings of the QCA7000 firmware, but it's not possible to change them during +runtime. + +Required properties: +- compatible : Should be "qca,qca7000" + +Optional properties: +- local-mac-address : see ./ethernet.txt +- current-speed : current baud rate of QCA7000 which defaults to 115200 + if absent, see also ../serial/slave-device.txt + +UART Example: + +/* Freescale i.MX28 UART */ +auart0: serial@8006a000 { + compatible = "fsl,imx28-auart", "fsl,imx23-auart"; + reg = <0x8006a000 0x2000>; + pinctrl-names = "default"; + pinctrl-0 = <&auart0_2pins_a>; + + qca7000: ethernet { + compatible = "qca,qca7000"; + local-mac-address = [ A0 B0 C0 D0 E0 F0 ]; + current-speed = <38400>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/qcom-emac.txt b/arch/arm64/boot/dts/vendor/bindings/net/qcom-emac.txt new file mode 100644 index 0000000000000000000000000000000000000000..346e6c7f47b7d902abd5cac8cd2c850352547a82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/qcom-emac.txt @@ -0,0 +1,111 @@ +Qualcomm Technologies EMAC Gigabit Ethernet Controller + +This network controller consists of two devices: a MAC and an SGMII +internal PHY. Each device is represented by a device tree node. A phandle +connects the MAC node to its corresponding internal phy node. Another +phandle points to the external PHY node. + +Required properties: + +MAC node: +- compatible : Should be "qcom,fsm9900-emac". +- reg : Offset and length of the register regions for the device +- interrupts : Interrupt number used by this controller +- mac-address : The 6-byte MAC address. If present, it is the default + MAC address. +- internal-phy : phandle to the internal PHY node +- phy-handle : phandle the the external PHY node + +Internal PHY node: +- compatible : Should be "qcom,fsm9900-emac-sgmii" or "qcom,qdf2432-emac-sgmii". +- reg : Offset and length of the register region(s) for the device +- interrupts : Interrupt number used by this controller + +The external phy child node: +- reg : The phy address + +Example: + +FSM9900: + +soc { + #address-cells = <1>; + #size-cells = <1>; + + emac0: ethernet@feb20000 { + compatible = "qcom,fsm9900-emac"; + reg = <0xfeb20000 0x10000>, + <0xfeb36000 0x1000>; + interrupts = <76>; + + clocks = <&gcc 0>, <&gcc 1>, <&gcc 3>, <&gcc 4>, <&gcc 5>, + <&gcc 6>, <&gcc 7>; + clock-names = "axi_clk", "cfg_ahb_clk", "high_speed_clk", + "mdio_clk", "tx_clk", "rx_clk", "sys_clk"; + + internal-phy = <&emac_sgmii>; + + phy-handle = <&phy0>; + + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0>; + }; + + pinctrl-names = "default"; + pinctrl-0 = <&mdio_pins_a>; + }; + + emac_sgmii: ethernet@feb38000 { + compatible = "qcom,fsm9900-emac-sgmii"; + reg = <0xfeb38000 0x1000>; + interrupts = <80>; + }; + + tlmm: pinctrl@fd510000 { + compatible = "qcom,fsm9900-pinctrl"; + + mdio_pins_a: mdio { + state { + pins = "gpio123", "gpio124"; + function = "mdio"; + }; + }; + }; + + +QDF2432: + +soc { + #address-cells = <2>; + #size-cells = <2>; + + emac0: ethernet@38800000 { + compatible = "qcom,fsm9900-emac"; + reg = <0x0 0x38800000 0x0 0x10000>, + <0x0 0x38816000 0x0 0x1000>; + interrupts = <0 256 4>; + + clocks = <&gcc 0>, <&gcc 1>, <&gcc 3>, <&gcc 4>, <&gcc 5>, + <&gcc 6>, <&gcc 7>; + clock-names = "axi_clk", "cfg_ahb_clk", "high_speed_clk", + "mdio_clk", "tx_clk", "rx_clk", "sys_clk"; + + internal-phy = <&emac_sgmii>; + + phy-handle = <&phy0>; + + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@4 { + reg = <4>; + }; + }; + + emac_sgmii: ethernet@410400 { + compatible = "qcom,qdf2432-emac-sgmii"; + reg = <0x0 0x00410400 0x0 0xc00>, /* Base address */ + <0x0 0x00410000 0x0 0x400>; /* Per-lane digital */ + interrupts = <0 254 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/qrtr-fifo-xprt.txt b/arch/arm64/boot/dts/vendor/bindings/net/qrtr-fifo-xprt.txt new file mode 100644 index 0000000000000000000000000000000000000000..69debce623e64d65989cece550a859637945545b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/qrtr-fifo-xprt.txt @@ -0,0 +1,25 @@ +Qualcomm Technologies, Inc. IPC Router FIFO Transport + +Required properties: +- compatible: should be "qcom,ipcr-fifo-xprt" +- reg: the irq register to raise an interrupt +- interrupts: the receiving interrupt line +- qcom,ipc-shm: reference to shared memory phandle + +Example: + + fifo_vipc_irq@176 { + compatible = "qcom,ipcr-fifo-xprt"; + reg = <0x176>; + interrupts = <0x0 0x142 0x1>; + qcom,ipc-shm = <&ipc-shm>; + }; + + ipc-shm: shared-buffer@85af7000 { + compatible = "qcom,hypervisor-shared-memory"; + phandle = <0x1e4>; + reg = <0x0 0x85af7000 0x0 0x9000>; + label = "ipc_shm"; + qcom,tx-is-first; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/net/qualcomm-bluetooth.txt b/arch/arm64/boot/dts/vendor/bindings/net/qualcomm-bluetooth.txt new file mode 100644 index 0000000000000000000000000000000000000000..824c0e23c5443092302e95790f62e0822d39197f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/qualcomm-bluetooth.txt @@ -0,0 +1,55 @@ +Qualcomm Bluetooth Chips +--------------------- + +This documents the binding structure and common properties for serial +attached Qualcomm devices. + +Serial attached Qualcomm devices shall be a child node of the host UART +device the slave device is attached to. + +Required properties: + - compatible: should contain one of the following: + * "qcom,qca6174-bt" + * "qcom,wcn3990-bt" + +Optional properties for compatible string qcom,qca6174-bt: + + - enable-gpios: gpio specifier used to enable chip + - clocks: clock provided to the controller (SUSCLK_32KHZ) + +Required properties for compatible string qcom,wcn3990-bt: + + - vddio-supply: VDD_IO supply regulator handle. + - vddxo-supply: VDD_XO supply regulator handle. + - vddrf-supply: VDD_RF supply regulator handle. + - vddch0-supply: VDD_CH0 supply regulator handle. + +Optional properties for compatible string qcom,wcn3990-bt: + + - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt + +Examples: + +serial@7570000 { + label = "BT-UART"; + status = "okay"; + + bluetooth { + compatible = "qcom,qca6174-bt"; + + enable-gpios = <&pm8994_gpios 19 GPIO_ACTIVE_HIGH>; + clocks = <&divclk4>; + }; +}; + +serial@898000 { + bluetooth { + compatible = "qcom,wcn3990-bt"; + + vddio-supply = <&vreg_s4a_1p8>; + vddxo-supply = <&vreg_l7a_1p8>; + vddrf-supply = <&vreg_l17a_1p3>; + vddch0-supply = <&vreg_l25a_3p3>; + max-speed = <3200000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ralink,rt2880-net.txt b/arch/arm64/boot/dts/vendor/bindings/net/ralink,rt2880-net.txt new file mode 100644 index 0000000000000000000000000000000000000000..9fe1a0a22e441c2720e8950b2e22df17ef12389a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ralink,rt2880-net.txt @@ -0,0 +1,59 @@ +Ralink Frame Engine Ethernet controller +======================================= + +The Ralink frame engine ethernet controller can be found on Ralink and +Mediatek SoCs (RT288x, RT3x5x, RT366x, RT388x, rt5350, mt7620, mt7621, mt76x8). + +Depending on the SoC, there is a number of ports connected to the CPU port +directly and/or via a (gigabit-)switch. + +* Ethernet controller node + +Required properties: +- compatible: Should be one of "ralink,rt2880-eth", "ralink,rt3050-eth", + "ralink,rt3050-eth", "ralink,rt3883-eth", "ralink,rt5350-eth", + "mediatek,mt7620-eth", "mediatek,mt7621-eth" +- reg: Address and length of the register set for the device +- interrupts: Should contain the frame engines interrupt +- resets: Should contain the frame engines resets +- reset-names: Should contain the reset names "fe". If a switch is present + "esw" is also required. + + +* Ethernet port node + +Required properties: +- compatible: Should be "ralink,eth-port" +- reg: The number of the physical port +- phy-handle: reference to the node describing the phy + +Example: + +mdio-bus { + ... + phy0: ethernet-phy@0 { + phy-mode = "mii"; + reg = <0>; + }; +}; + +ethernet@400000 { + compatible = "ralink,rt2880-eth"; + reg = <0x00400000 10000>; + + #address-cells = <1>; + #size-cells = <0>; + + resets = <&rstctrl 18>; + reset-names = "fe"; + + interrupt-parent = <&cpuintc>; + interrupts = <5>; + + port@0 { + compatible = "ralink,eth-port"; + reg = <0>; + phy-handle = <&phy0>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ralink,rt3050-esw.txt b/arch/arm64/boot/dts/vendor/bindings/net/ralink,rt3050-esw.txt new file mode 100644 index 0000000000000000000000000000000000000000..87e315856efa0c998f43ddb7df83292cd581f87b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ralink,rt3050-esw.txt @@ -0,0 +1,30 @@ +Ralink Fast Ethernet Embedded Switch +==================================== + +The ralink fast ethernet embedded switch can be found on Ralink and Mediatek +SoCs (RT3x5x, RT5350, MT76x8). + +Required properties: +- compatible: Should be "ralink,rt3050-esw" +- reg: Address and length of the register set for the device +- interrupts: Should contain the embedded switches interrupt +- resets: Should contain the embedded switches resets +- reset-names: Should contain the reset names "esw" + +Optional properties: +- ralink,portmap: can be used to choose if the default switch setup is + llllw or wllll +- ralink,led_polarity: override the active high/low settings of the leds + +Example: + +esw@10110000 { + compatible = "ralink,rt3050-esw"; + reg = <0x10110000 8000>; + + resets = <&rstctrl 23>; + reset-names = "esw"; + + interrupt-parent = <&intc>; + interrupts = <17>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/renesas,ravb.txt b/arch/arm64/boot/dts/vendor/bindings/net/renesas,ravb.txt new file mode 100644 index 0000000000000000000000000000000000000000..da249b7c406c98983243f7639bd1031e5c488ff7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/renesas,ravb.txt @@ -0,0 +1,129 @@ +* Renesas Electronics Ethernet AVB + +This file provides information on what the device node for the Ethernet AVB +interface contains. + +Required properties: +- compatible: Must contain one or more of the following: + - "renesas,etheravb-r8a7743" for the R8A7743 SoC. + - "renesas,etheravb-r8a7745" for the R8A7745 SoC. + - "renesas,etheravb-r8a77470" for the R8A77470 SoC. + - "renesas,etheravb-r8a7790" for the R8A7790 SoC. + - "renesas,etheravb-r8a7791" for the R8A7791 SoC. + - "renesas,etheravb-r8a7792" for the R8A7792 SoC. + - "renesas,etheravb-r8a7793" for the R8A7793 SoC. + - "renesas,etheravb-r8a7794" for the R8A7794 SoC. + - "renesas,etheravb-rcar-gen2" as a fallback for the above + R-Car Gen2 and RZ/G1 devices. + + - "renesas,etheravb-r8a774a1" for the R8A774A1 SoC. + - "renesas,etheravb-r8a7795" for the R8A7795 SoC. + - "renesas,etheravb-r8a7796" for the R8A7796 SoC. + - "renesas,etheravb-r8a77965" for the R8A77965 SoC. + - "renesas,etheravb-r8a77970" for the R8A77970 SoC. + - "renesas,etheravb-r8a77980" for the R8A77980 SoC. + - "renesas,etheravb-r8a77990" for the R8A77990 SoC. + - "renesas,etheravb-r8a77995" for the R8A77995 SoC. + - "renesas,etheravb-rcar-gen3" as a fallback for the above + R-Car Gen3 and RZ/G2 devices. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first followed by + the generic version. + +- reg: Offset and length of (1) the register block and (2) the stream buffer. + The region for the register block is mandatory. + The region for the stream buffer is optional, as it is only present on + R-Car Gen2 and RZ/G1 SoCs, and on R-Car H3 (R8A7795), M3-W (R8A7796), + and M3-N (R8A77965). +- interrupts: A list of interrupt-specifiers, one for each entry in + interrupt-names. + If interrupt-names is not present, an interrupt specifier + for a single muxed interrupt. +- phy-mode: see ethernet.txt file in the same directory. +- phy-handle: see ethernet.txt file in the same directory. +- #address-cells: number of address cells for the MDIO bus, must be equal to 1. +- #size-cells: number of size cells on the MDIO bus, must be equal to 0. +- clocks: clock phandle and specifier pair. +- pinctrl-0: phandle, referring to a default pin configuration node. + +Optional properties: +- interrupt-names: A list of interrupt names. + For the R-Car Gen 3 SoCs this property is mandatory; + it should include one entry per channel, named "ch%u", + where %u is the channel number ranging from 0 to 24. + For other SoCs this property is optional; if present + it should contain "mux" for a single muxed interrupt. +- pinctrl-names: pin configuration state name ("default"). +- renesas,no-ether-link: boolean, specify when a board does not provide a proper + AVB_LINK signal. +- renesas,ether-link-active-low: boolean, specify when the AVB_LINK signal is + active-low instead of normal active-high. + +Example: + + ethernet@e6800000 { + compatible = "renesas,etheravb-r8a7795", "renesas,etheravb-rcar-gen3"; + reg = <0 0xe6800000 0 0x800>, <0 0xe6a00000 0 0x10000>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "ch0", "ch1", "ch2", "ch3", + "ch4", "ch5", "ch6", "ch7", + "ch8", "ch9", "ch10", "ch11", + "ch12", "ch13", "ch14", "ch15", + "ch16", "ch17", "ch18", "ch19", + "ch20", "ch21", "ch22", "ch23", + "ch24"; + clocks = <&cpg CPG_MOD 812>; + power-domains = <&cpg>; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + + pinctrl-0 = <ðer_pins>; + pinctrl-names = "default"; + renesas,no-ether-link; + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + rxc-skew-ps = <900>; + rxdv-skew-ps = <0>; + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txc-skew-ps = <900>; + txen-skew-ps = <0>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; + reg = <0>; + interrupt-parent = <&gpio2>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/rockchip-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/rockchip-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b71da7e87427759729fc7874d048c4c22f5eee0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/rockchip-dwmac.txt @@ -0,0 +1,76 @@ +Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC) + +The device node has following properties. + +Required properties: + - compatible: should be "rockchip,-gamc" + "rockchip,px30-gmac": found on PX30 SoCs + "rockchip,rk3128-gmac": found on RK312x SoCs + "rockchip,rk3228-gmac": found on RK322x SoCs + "rockchip,rk3288-gmac": found on RK3288 SoCs + "rockchip,rk3328-gmac": found on RK3328 SoCs + "rockchip,rk3366-gmac": found on RK3366 SoCs + "rockchip,rk3368-gmac": found on RK3368 SoCs + "rockchip,rk3399-gmac": found on RK3399 SoCs + "rockchip,rv1108-gmac": found on RV1108 SoCs + - reg: addresses and length of the register sets for the device. + - interrupts: Should contain the GMAC interrupts. + - interrupt-names: Should contain the interrupt names "macirq". + - rockchip,grf: phandle to the syscon grf used to control speed and mode. + - clocks: <&cru SCLK_MAC>: clock selector for main clock, from PLL or PHY. + <&cru SCLK_MAC_PLL>: PLL clock for SCLK_MAC + <&cru SCLK_MAC_RX>: clock gate for RX + <&cru SCLK_MAC_TX>: clock gate for TX + <&cru SCLK_MACREF>: clock gate for RMII referce clock + <&cru SCLK_MACREF_OUT> clock gate for RMII reference clock output + <&cru ACLK_GMAC>: AXI clock gate for GMAC + <&cru PCLK_GMAC>: APB clock gate for GMAC + - clock-names: One name for each entry in the clocks property. + - phy-mode: See ethernet.txt file in the same directory. + - pinctrl-names: Names corresponding to the numbered pinctrl states. + - pinctrl-0: pin-control mode. can be <&rgmii_pins> or <&rmii_pins>. + - clock_in_out: For RGMII, it must be "input", means main clock(125MHz) + is not sourced from SoC's PLL, but input from PHY; For RMII, "input" means + PHY provides the reference clock(50MHz), "output" means GMAC provides the + reference clock. + - snps,reset-gpio gpio number for phy reset. + - snps,reset-active-low boolean flag to indicate if phy reset is active low. + - assigned-clocks: main clock, should be <&cru SCLK_MAC>; + - assigned-clock-parents = parent of main clock. + can be <&ext_gmac> or <&cru SCLK_MAC_PLL>. + +Optional properties: + - tx_delay: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default. + - rx_delay: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default. + - phy-supply: phandle to a regulator if the PHY needs one + +Example: + +gmac: ethernet@ff290000 { + compatible = "rockchip,rk3288-gmac"; + reg = <0xff290000 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + rockchip,grf = <&grf>; + clocks = <&cru SCLK_MAC>, + <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>, + <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>, + <&cru ACLK_GMAC>, <&cru PCLK_GMAC>; + clock-names = "stmmaceth", + "mac_clk_rx", "mac_clk_tx", + "clk_mac_ref", "clk_mac_refout", + "aclk_mac", "pclk_mac"; + phy-mode = "rgmii"; + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins /*&rmii_pins*/>; + + clock_in_out = "input"; + snps,reset-gpio = <&gpio4 7 0>; + snps,reset-active-low; + + assigned-clocks = <&cru SCLK_MAC>; + assigned-clock-parents = <&ext_gmac>; + tx_delay = <0x30>; + rx_delay = <0x10>; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/samsung-sxgbe.txt b/arch/arm64/boot/dts/vendor/bindings/net/samsung-sxgbe.txt new file mode 100644 index 0000000000000000000000000000000000000000..46e591178911d28399c69b95f8b564b7f6d99dae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/samsung-sxgbe.txt @@ -0,0 +1,50 @@ +* Samsung 10G Ethernet driver (SXGBE) + +Required properties: +- compatible: Should be "samsung,sxgbe-v2.0a" +- reg: Address and length of the register set for the device +- interrupts: Should contain the SXGBE interrupts + These interrupts are ordered by fixed and follows variable + trasmit DMA interrupts, receive DMA interrupts and lpi interrupt. + index 0 - this is fixed common interrupt of SXGBE and it is always + available. + index 1 to 25 - 8 variable trasmit interrupts, variable 16 receive interrupts + and 1 optional lpi interrupt. +- phy-mode: String, operation mode of the PHY interface. + Supported values are: "sgmii", "xgmii". +- samsung,pbl: Integer, Programmable Burst Length. + Supported values are 1, 2, 4, 8, 16, or 32. +- samsung,burst-map: Integer, Program the possible bursts supported by sxgbe + This is an integer and represents allowable DMA bursts when fixed burst. + Allowable range is 0x01-0x3F. When this field is set fixed burst is enabled. + When fixed length is needed for burst mode, it can be set within allowable + range. + +Optional properties: +- mac-address: 6 bytes, mac address +- max-frame-size: Maximum Transfer Unit (IEEE defined MTU), rather + than the maximum frame size. + +Example: + + aliases { + ethernet0 = <&sxgbe0>; + }; + + sxgbe0: ethernet@1a040000 { + compatible = "samsung,sxgbe-v2.0a"; + reg = <0 0x1a040000 0 0x10000>; + interrupt-parent = <&gic>; + interrupts = <0 209 4>, <0 185 4>, <0 186 4>, <0 187 4>, + <0 188 4>, <0 189 4>, <0 190 4>, <0 191 4>, + <0 192 4>, <0 193 4>, <0 194 4>, <0 195 4>, + <0 196 4>, <0 197 4>, <0 198 4>, <0 199 4>, + <0 200 4>, <0 201 4>, <0 202 4>, <0 203 4>, + <0 204 4>, <0 205 4>, <0 206 4>, <0 207 4>, + <0 208 4>, <0 210 4>; + samsung,pbl = <0x08> + samsung,burst-map = <0x20> + mac-address = [ 00 11 22 33 44 55 ]; /* Filled in by U-Boot */ + max-frame-size = <9000>; + phy-mode = "xgmii"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/sff,sfp.txt b/arch/arm64/boot/dts/vendor/bindings/net/sff,sfp.txt new file mode 100644 index 0000000000000000000000000000000000000000..832139919f20a38150c794b811839faa454c840e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/sff,sfp.txt @@ -0,0 +1,85 @@ +Small Form Factor (SFF) Committee Small Form-factor Pluggable (SFP) +Transceiver + +Required properties: + +- compatible : must be one of + "sff,sfp" for SFP modules + "sff,sff" for soldered down SFF modules + +- i2c-bus : phandle of an I2C bus controller for the SFP two wire serial + interface + +Optional Properties: + +- mod-def0-gpios : GPIO phandle and a specifier of the MOD-DEF0 (AKA Mod_ABS) + module presence input gpio signal, active (module absent) high. Must + not be present for SFF modules + +- los-gpios : GPIO phandle and a specifier of the Receiver Loss of Signal + Indication input gpio signal, active (signal lost) high + +- tx-fault-gpios : GPIO phandle and a specifier of the Module Transmitter + Fault input gpio signal, active (fault condition) high + +- tx-disable-gpios : GPIO phandle and a specifier of the Transmitter Disable + output gpio signal, active (Tx disable) high + +- rate-select0-gpios : GPIO phandle and a specifier of the Rx Signaling Rate + Select (AKA RS0) output gpio signal, low: low Rx rate, high: high Rx rate + Must not be present for SFF modules + +- rate-select1-gpios : GPIO phandle and a specifier of the Tx Signaling Rate + Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high: + high Tx rate. Must not be present for SFF modules + +- maximum-power-milliwatt : Maximum module power consumption + Specifies the maximum power consumption allowable by a module in the + slot, in milli-Watts. Presently, modules can be up to 1W, 1.5W or 2W. + +Example #1: Direct serdes to SFP connection + +sfp_eth3: sfp-eth3 { + compatible = "sff,sfp"; + i2c-bus = <&sfp_1g_i2c>; + los-gpios = <&cpm_gpio2 22 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&cpm_gpio2 21 GPIO_ACTIVE_LOW>; + maximum-power-milliwatt = <1000>; + pinctrl-names = "default"; + pinctrl-0 = <&cpm_sfp_1g_pins &cps_sfp_1g_pins>; + tx-disable-gpios = <&cps_gpio1 24 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&cpm_gpio2 19 GPIO_ACTIVE_HIGH>; +}; + +&cps_emac3 { + phy-names = "comphy"; + phys = <&cps_comphy5 0>; + sfp = <&sfp_eth3>; +}; + +Example #2: Serdes to PHY to SFP connection + +sfp_eth0: sfp-eth0 { + compatible = "sff,sfp"; + i2c-bus = <&sfpp0_i2c>; + los-gpios = <&cps_gpio1 28 GPIO_ACTIVE_HIGH>; + mod-def0-gpios = <&cps_gpio1 27 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&cps_sfpp0_pins>; + tx-disable-gpios = <&cps_gpio1 29 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>; +}; + +p0_phy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c45"; + pinctrl-names = "default"; + pinctrl-0 = <&cpm_phy0_pins &cps_phy0_pins>; + reg = <0>; + interrupt = <&cpm_gpio2 18 IRQ_TYPE_EDGE_FALLING>; + sfp = <&sfp_eth0>; +}; + +&cpm_eth0 { + phy = <&p0_phy>; + phy-mode = "10gbase-kr"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/sh_eth.txt b/arch/arm64/boot/dts/vendor/bindings/net/sh_eth.txt new file mode 100644 index 0000000000000000000000000000000000000000..abc36274227c7299bf5ec088e21ebdeed25a3950 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/sh_eth.txt @@ -0,0 +1,69 @@ +* Renesas Electronics SH EtherMAC + +This file provides information on what the device node for the SH EtherMAC +interface contains. + +Required properties: +- compatible: Must contain one or more of the following: + "renesas,gether-r8a7740" if the device is a part of R8A7740 SoC. + "renesas,ether-r8a7743" if the device is a part of R8A7743 SoC. + "renesas,ether-r8a7745" if the device is a part of R8A7745 SoC. + "renesas,ether-r8a7778" if the device is a part of R8A7778 SoC. + "renesas,ether-r8a7779" if the device is a part of R8A7779 SoC. + "renesas,ether-r8a7790" if the device is a part of R8A7790 SoC. + "renesas,ether-r8a7791" if the device is a part of R8A7791 SoC. + "renesas,ether-r8a7793" if the device is a part of R8A7793 SoC. + "renesas,ether-r8a7794" if the device is a part of R8A7794 SoC. + "renesas,gether-r8a77980" if the device is a part of R8A77980 SoC. + "renesas,ether-r7s72100" if the device is a part of R7S72100 SoC. + "renesas,ether-r7s9210" if the device is a part of R7S9210 SoC. + "renesas,rcar-gen1-ether" for a generic R-Car Gen1 device. + "renesas,rcar-gen2-ether" for a generic R-Car Gen2 or RZ/G1 + device. + + When compatible with the generic version, nodes must list + the SoC-specific version corresponding to the platform + first followed by the generic version. + +- reg: offset and length of (1) the E-DMAC/feLic register block (required), + (2) the TSU register block (optional). +- interrupts: interrupt specifier for the sole interrupt. +- phy-mode: see ethernet.txt file in the same directory. +- phy-handle: see ethernet.txt file in the same directory. +- #address-cells: number of address cells for the MDIO bus, must be equal to 1. +- #size-cells: number of size cells on the MDIO bus, must be equal to 0. +- clocks: clock phandle and specifier pair. +- pinctrl-0: phandle, referring to a default pin configuration node. + +Optional properties: +- pinctrl-names: pin configuration state name ("default"). +- renesas,no-ether-link: boolean, specify when a board does not provide a proper + Ether LINK signal. +- renesas,ether-link-active-low: boolean, specify when the Ether LINK signal is + active-low instead of normal active-high. + +Example (Lager board): + + ethernet@ee700000 { + compatible = "renesas,ether-r8a7790", + "renesas,rcar-gen2-ether"; + reg = <0 0xee700000 0 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 162 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp8_clks R8A7790_CLK_ETHER>; + phy-mode = "rmii"; + phy-handle = <&phy1>; + pinctrl-0 = <ðer_pins>; + pinctrl-names = "default"; + renesas,ether-link-active-low; + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@1 { + reg = <1>; + interrupt-parent = <&irqc0>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&phy1_pins>; + pinctrl-names = "default"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/smsc-lan87xx.txt b/arch/arm64/boot/dts/vendor/bindings/net/smsc-lan87xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b7c719b0bb94ecef956387b866bcb5fa7b39c58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/smsc-lan87xx.txt @@ -0,0 +1,23 @@ +SMSC LAN87xx Ethernet PHY + +Some boards require special tuning values. Configure them +through an Ethernet OF device node. + +Optional properties: + +- smsc,disable-energy-detect: + If set, do not enable energy detect mode for the SMSC phy. + default: enable energy detect mode + +Examples: +smsc phy with disabled energy detect mode on an am335x based board. +&davinci_mdio { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&davinci_mdio_default>; + pinctrl-1 = <&davinci_mdio_sleep>; + + ethernetphy0: ethernet-phy@0 { + reg = <0>; + smsc,disable-energy-detect; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/smsc-lan91c111.txt b/arch/arm64/boot/dts/vendor/bindings/net/smsc-lan91c111.txt new file mode 100644 index 0000000000000000000000000000000000000000..309e37eb7c7cce4f548d954db0ad665be998d76f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/smsc-lan91c111.txt @@ -0,0 +1,17 @@ +SMSC LAN91c111 Ethernet mac + +Required properties: +- compatible = "smsc,lan91c111"; +- reg : physical address and size of registers +- interrupts : interrupt connection + +Optional properties: +- phy-device : see ethernet.txt file in the same directory +- reg-io-width : Mask of sizes (in bytes) of the IO accesses that + are supported on the device. Valid value for SMSC LAN91c111 are + 1, 2 or 4. If it's omitted or invalid, the size would be 2 meaning + 16-bit access only. +- power-gpios: GPIO to control the PWRDWN pin +- reset-gpios: GPIO to control the RESET pin +- pxa-u16-align4 : Boolean, put in place the workaround the force all + u16 writes to be 32 bits aligned diff --git a/arch/arm64/boot/dts/vendor/bindings/net/smsc911x.txt b/arch/arm64/boot/dts/vendor/bindings/net/smsc911x.txt new file mode 100644 index 0000000000000000000000000000000000000000..acfafc8e143c4c8599510eb7d2cbcb35af7e6f9f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/smsc911x.txt @@ -0,0 +1,43 @@ +* Smart Mixed-Signal Connectivity (SMSC) LAN911x/912x Controller + +Required properties: +- compatible : Should be "smsc,lan", "smsc,lan9115" +- reg : Address and length of the io space for SMSC LAN +- interrupts : one or two interrupt specifiers + - The first interrupt is the SMSC LAN interrupt line + - The second interrupt (if present) is the PME (power + management event) interrupt that is able to wake up the host + system with a 50ms pulse on network activity +- phy-mode : See ethernet.txt file in the same directory + +Optional properties: +- reg-shift : Specify the quantity to shift the register offsets by +- reg-io-width : Specify the size (in bytes) of the IO accesses that + should be performed on the device. Valid value for SMSC LAN is + 2 or 4. If it's omitted or invalid, the size would be 2. +- smsc,irq-active-high : Indicates the IRQ polarity is active-high +- smsc,irq-push-pull : Indicates the IRQ type is push-pull +- smsc,force-internal-phy : Forces SMSC LAN controller to use + internal PHY +- smsc,force-external-phy : Forces SMSC LAN controller to use + external PHY +- smsc,save-mac-address : Indicates that mac address needs to be saved + before resetting the controller +- reset-gpios : a GPIO line connected to the RESET (active low) signal + of the device. On many systems this is wired high so the device goes + out of reset at power-on, but if it is under program control, this + optional GPIO can wake up in response to it. +- vdd33a-supply, vddvario-supply : 3.3V analog and IO logic power supplies + +Examples: + +lan9220@f4000000 { + compatible = "smsc,lan9220", "smsc,lan9115"; + reg = <0xf4000000 0x2000000>; + phy-mode = "mii"; + interrupt-parent = <&gpio1>; + interrupts = <31>, <32>; + reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>; + reg-io-width = <4>; + smsc,irq-push-pull; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/snps,dwc-qos-ethernet.txt b/arch/arm64/boot/dts/vendor/bindings/net/snps,dwc-qos-ethernet.txt new file mode 100644 index 0000000000000000000000000000000000000000..36f1aef585f03fbf6ee6e4b0b3a7a216a07fad09 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/snps,dwc-qos-ethernet.txt @@ -0,0 +1,167 @@ +* Synopsys DWC Ethernet QoS IP version 4.10 driver (GMAC) + +This binding is deprecated, but it continues to be supported, but new +features should be preferably added to the stmmac binding document. + +This binding supports the Synopsys Designware Ethernet QoS (Quality Of Service) +IP block. The IP supports multiple options for bus type, clocking and reset +structure, and feature list. Consequently, a number of properties and list +entries in properties are marked as optional, or only required in specific HW +configurations. + +Required properties: +- compatible: One of: + - "axis,artpec6-eqos", "snps,dwc-qos-ethernet-4.10" + Represents the IP core when integrated into the Axis ARTPEC-6 SoC. + - "nvidia,tegra186-eqos", "snps,dwc-qos-ethernet-4.10" + Represents the IP core when integrated into the NVIDIA Tegra186 SoC. + - "snps,dwc-qos-ethernet-4.10" + This combination is deprecated. It should be treated as equivalent to + "axis,artpec6-eqos", "snps,dwc-qos-ethernet-4.10". It is supported to be + compatible with earlier revisions of this binding. +- reg: Address and length of the register set for the device +- clocks: Phandle and clock specifiers for each entry in clock-names, in the + same order. See ../clock/clock-bindings.txt. +- clock-names: May contain any/all of the following depending on the IP + configuration, in any order: + - "tx" + The EQOS transmit path clock. The HW signal name is clk_tx_i. + In some configurations (e.g. GMII/RGMII), this clock also drives the PHY TX + path. In other configurations, other clocks (such as tx_125, rmii) may + drive the PHY TX path. + - "rx" + The EQOS receive path clock. The HW signal name is clk_rx_i. + In some configurations (e.g. GMII/RGMII), this clock is derived from the + PHY's RX clock output. In other configurations, other clocks (such as + rx_125, rmii) may drive the EQOS RX path. + In cases where the PHY clock is directly fed into the EQOS receive path + without intervening logic, the DT need not represent this clock, since it + is assumed to be fully under the control of the PHY device/driver. In + cases where SoC integration adds additional logic to this path, such as a + SW-controlled clock gate, this clock should be represented in DT. + - "slave_bus" + The CPU/slave-bus (CSR) interface clock. This applies to any bus type; + APB, AHB, AXI, etc. The HW signal name is hclk_i (AHB) or clk_csr_i (other + buses). + - "master_bus" + The master bus interface clock. Only required in configurations that use a + separate clock for the master and slave bus interfaces. The HW signal name + is hclk_i (AHB) or aclk_i (AXI). + - "ptp_ref" + The PTP reference clock. The HW signal name is clk_ptp_ref_i. + - "phy_ref_clk" + This clock is deprecated and should not be used by new compatible values. + It is equivalent to "tx". + - "apb_pclk" + This clock is deprecated and should not be used by new compatible values. + It is equivalent to "slave_bus". + + Note: Support for additional IP configurations may require adding the + following clocks to this list in the future: clk_rx_125_i, clk_tx_125_i, + clk_pmarx_0_i, clk_pmarx1_i, clk_rmii_i, clk_revmii_rx_i, clk_revmii_tx_i. + Configurations exist where multiple similar clocks are used at once, e.g. all + of clk_rx_125_i, clk_pmarx_0_i, clk_pmarx1_i. For this reason it is best to + extend the binding with a separate clock-names entry for each of those RX + clocks, rather than repurposing the existing "rx" clock-names entry as a + generic/logical clock in a similar fashion to "master_bus" and "slave_bus". + This will allow easy support for configurations that support multiple PHY + interfaces using a mux, and hence need to have explicit control over + specific RX clocks. + + The following compatible values require the following set of clocks: + - "nvidia,tegra186-eqos", "snps,dwc-qos-ethernet-4.10": + - "slave_bus" + - "master_bus" + - "rx" + - "tx" + - "ptp_ref" + - "axis,artpec6-eqos", "snps,dwc-qos-ethernet-4.10": + - "slave_bus" + - "master_bus" + - "tx" + - "ptp_ref" + - "snps,dwc-qos-ethernet-4.10" (deprecated): + - "phy_ref_clk" + - "apb_clk" +- interrupts: Should contain the core's combined interrupt signal +- phy-mode: See ethernet.txt file in the same directory +- resets: Phandle and reset specifiers for each entry in reset-names, in the + same order. See ../reset/reset.txt. +- reset-names: May contain any/all of the following depending on the IP + configuration, in any order: + - "eqos". The reset to the entire module. The HW signal name is hreset_n + (AHB) or aresetn_i (AXI). + + The following compatible values require the following set of resets: + (the reset properties may be omitted if empty) + - "nvidia,tegra186-eqos", "snps,dwc-qos-ethernet-4.10": + - "eqos". + - "axis,artpec6-eqos", "snps,dwc-qos-ethernet-4.10": + - None. + - "snps,dwc-qos-ethernet-4.10" (deprecated): + - None. + +Optional properties: +- dma-coherent: Present if dma operations are coherent +- mac-address: See ethernet.txt in the same directory +- local-mac-address: See ethernet.txt in the same directory +- phy-reset-gpios: Phandle and specifier for any GPIO used to reset the PHY. + See ../gpio/gpio.txt. +- snps,en-lpi: If present it enables use of the AXI low-power interface +- snps,write-requests: Number of write requests that the AXI port can issue. + It depends on the SoC configuration. +- snps,read-requests: Number of read requests that the AXI port can issue. + It depends on the SoC configuration. +- snps,burst-map: Bitmap of allowed AXI burst lengts, with the LSB + representing 4, then 8 etc. +- snps,txpbl: DMA Programmable burst length for the TX DMA +- snps,rxpbl: DMA Programmable burst length for the RX DMA +- snps,en-tx-lpi-clockgating: Enable gating of the MAC TX clock during + TX low-power mode. +- phy-handle: See ethernet.txt file in the same directory +- mdio device tree subnode: When the GMAC has a phy connected to its local + mdio, there must be device tree subnode with the following + required properties: + - compatible: Must be "snps,dwc-qos-ethernet-mdio". + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For each phy on the mdio bus, there must be a node with the following + fields: + + - reg: phy id used to communicate to phy. + - device_type: Must be "ethernet-phy". + - fixed-mode device tree subnode: see fixed-link.txt in the same directory + +Examples: +ethernet2@40010000 { + clock-names = "phy_ref_clk", "apb_pclk"; + clocks = <&clkc 17>, <&clkc 15>; + compatible = "snps,dwc-qos-ethernet-4.10"; + interrupt-parent = <&intc>; + interrupts = <0x0 0x1e 0x4>; + reg = <0x40010000 0x4000>; + phy-handle = <&phy2>; + phy-mode = "gmii"; + phy-reset-gpios = <&gpioctlr 43 GPIO_ACTIVE_LOW>; + + snps,en-tx-lpi-clockgating; + snps,en-lpi; + snps,write-requests = <2>; + snps,read-requests = <16>; + snps,burst-map = <0x7>; + snps,txpbl = <8>; + snps,rxpbl = <2>; + + dma-coherent; + + mdio { + #address-cells = <0x1>; + #size-cells = <0x0>; + phy2: phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + device_type = "ethernet-phy"; + reg = <0x1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/socfpga-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/socfpga-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..17d6819669c8ccee0186f4dc797be638a1828097 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/socfpga-dwmac.txt @@ -0,0 +1,51 @@ +Altera SOCFPGA SoC DWMAC controller + +This is a variant of the dwmac/stmmac driver an inherits all descriptions +present in Documentation/devicetree/bindings/net/stmmac.txt. + +The device node has additional properties: + +Required properties: + - compatible : Should contain "altr,socfpga-stmmac" along with + "snps,dwmac" and any applicable more detailed + designware version numbers documented in stmmac.txt + - altr,sysmgr-syscon : Should be the phandle to the system manager node that + encompasses the glue register, the register offset, and the register shift. + - altr,f2h_ptp_ref_clk use f2h_ptp_ref_clk instead of default eosc1 clock + for ptp ref clk. This affects all emacs as the clock is common. + +Optional properties: +altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if + DWMAC controller is connected emac splitter. +phy-mode: The phy mode the ethernet operates in +altr,sgmii-to-sgmii-converter: phandle to the TSE SGMII converter + +This device node has additional phandle dependency, the sgmii converter: + +Required properties: + - compatible : Should be altr,gmii-to-sgmii-2.0 + - reg-names : Should be "eth_tse_control_port" + +Example: + +gmii_to_sgmii_converter: phy@100000240 { + compatible = "altr,gmii-to-sgmii-2.0"; + reg = <0x00000001 0x00000240 0x00000008>, + <0x00000001 0x00000200 0x00000040>; + reg-names = "eth_tse_control_port"; + clocks = <&sgmii_1_clk_0 &emac1 1 &sgmii_clk_125 &sgmii_clk_125>; + clock-names = "tse_pcs_ref_clk_clock_connection", "tse_rx_cdr_refclk"; +}; + +gmac0: ethernet@ff700000 { + compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; + altr,sysmgr-syscon = <&sysmgr 0x60 0>; + reg = <0xff700000 0x2000>; + interrupts = <0 115 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac_0_clk>; + clock-names = "stmmaceth"; + phy-mode = "sgmii"; + altr,gmii-to-sgmii-converter = <&gmii_to_sgmii_converter>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/socionext,uniphier-ave4.txt b/arch/arm64/boot/dts/vendor/bindings/net/socionext,uniphier-ave4.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc8f01718690d2cbbbf271cbb0d3117ea8c6041c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/socionext,uniphier-ave4.txt @@ -0,0 +1,64 @@ +* Socionext AVE ethernet controller + +This describes the devicetree bindings for AVE ethernet controller +implemented on Socionext UniPhier SoCs. + +Required properties: + - compatible: Should be + - "socionext,uniphier-pro4-ave4" : for Pro4 SoC + - "socionext,uniphier-pxs2-ave4" : for PXs2 SoC + - "socionext,uniphier-ld11-ave4" : for LD11 SoC + - "socionext,uniphier-ld20-ave4" : for LD20 SoC + - "socionext,uniphier-pxs3-ave4" : for PXs3 SoC + - reg: Address where registers are mapped and size of region. + - interrupts: Should contain the MAC interrupt. + - phy-mode: See ethernet.txt in the same directory. Allow to choose + "rgmii", "rmii", "mii", or "internal" according to the PHY. + The acceptable mode is SoC-dependent. + - phy-handle: Should point to the external phy device. + See ethernet.txt file in the same directory. + - clocks: A phandle to the clock for the MAC. + For Pro4 SoC, that is "socionext,uniphier-pro4-ave4", + another MAC clock, GIO bus clock and PHY clock are also required. + - clock-names: Should contain + - "ether", "ether-gb", "gio", "ether-phy" for Pro4 SoC + - "ether" for others + - resets: A phandle to the reset control for the MAC. For Pro4 SoC, + GIO bus reset is also required. + - reset-names: Should contain + - "ether", "gio" for Pro4 SoC + - "ether" for others + - socionext,syscon-phy-mode: A phandle to syscon with one argument + that configures phy mode. The argument is the ID of MAC instance. + +Optional properties: + - local-mac-address: See ethernet.txt in the same directory. + +Required subnode: + - mdio: A container for child nodes representing phy nodes. + See phy.txt in the same directory. + +Example: + + ether: ethernet@65000000 { + compatible = "socionext,uniphier-ld20-ave4"; + reg = <0x65000000 0x8500>; + interrupts = <0 66 4>; + phy-mode = "rgmii"; + phy-handle = <ðphy>; + clock-names = "ether"; + clocks = <&sys_clk 6>; + reset-names = "ether"; + resets = <&sys_rst 6>; + socionext,syscon-phy-mode = <&soc_glue 0>; + local-mac-address = [00 00 00 00 00 00]; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy: ethphy@1 { + reg = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/socionext-netsec.txt b/arch/arm64/boot/dts/vendor/bindings/net/socionext-netsec.txt new file mode 100644 index 0000000000000000000000000000000000000000..0cff94fb04334926a1c3eb8c08969db29993bd71 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/socionext-netsec.txt @@ -0,0 +1,53 @@ +* Socionext NetSec Ethernet Controller IP + +Required properties: +- compatible: Should be "socionext,synquacer-netsec" +- reg: Address and length of the control register area, followed by the + address and length of the EEPROM holding the MAC address and + microengine firmware +- interrupts: Should contain ethernet controller interrupt +- clocks: phandle to the PHY reference clock +- clock-names: Should be "phy_ref_clk" +- phy-mode: See ethernet.txt file in the same directory +- phy-handle: See ethernet.txt in the same directory. + +- mdio device tree subnode: When the Netsec has a phy connected to its local + mdio, there must be device tree subnode with the following + required properties: + + - #address-cells: Must be <1>. + - #size-cells: Must be <0>. + + For each phy on the mdio bus, there must be a node with the following + fields: + - compatible: Refer to phy.txt + - reg: phy id used to communicate to phy. + +Optional properties: (See ethernet.txt file in the same directory) +- dma-coherent: Boolean property, must only be present if memory + accesses performed by the device are cache coherent. +- local-mac-address: See ethernet.txt in the same directory. +- mac-address: See ethernet.txt in the same directory. +- max-speed: See ethernet.txt in the same directory. +- max-frame-size: See ethernet.txt in the same directory. + +Example: + eth0: ethernet@522d0000 { + compatible = "socionext,synquacer-netsec"; + reg = <0 0x522d0000 0x0 0x10000>, <0 0x10000000 0x0 0x10000>; + interrupts = ; + clocks = <&clk_netsec>; + clock-names = "phy_ref_clk"; + phy-mode = "rgmii"; + max-speed = <1000>; + max-frame-size = <9000>; + phy-handle = <&phy1>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/sti-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/sti-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..062c5174add3263d54a00fb1083fbfd810164f83 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/sti-dwmac.txt @@ -0,0 +1,60 @@ +STMicroelectronics SoC DWMAC glue layer controller + +This file documents differences between the core properties in +Documentation/devicetree/bindings/net/stmmac.txt +and what is needed on STi platforms to program the stmmac glue logic. + +The device node has following properties. + +Required properties: + - compatible : Can be "st,stih415-dwmac", "st,stih416-dwmac", + "st,stih407-dwmac", "st,stid127-dwmac". + - st,syscon : Should be phandle/offset pair. The phandle to the syscon node which + encompases the glue register, and the offset of the control register. + - st,gmac_en: this is to enable the gmac into a dedicated sysctl control + register available on STiH407 SoC. + - pinctrl-0: pin-control for all the MII mode supported. + +Optional properties: + - resets : phandle pointing to the system reset controller with correct + reset line index for ethernet reset. + - st,ext-phyclk: valid only for RMII where PHY can generate 50MHz clock or + MAC can generate it. + - st,tx-retime-src: This specifies which clk is wired up to the mac for + retimeing tx lines. This is totally board dependent and can take one of the + posssible values from "txclk", "clk_125" or "clkgen". + If not passed, the internal clock will be used by default. + - sti-ethclk: this is the phy clock. + - sti-clkconf: this is an extra sysconfig register, available in new SoCs, + to program the clk retiming. + - st,gmac_en: to enable the GMAC, this only is present in some SoCs; e.g. + STiH407. + +Example: + +ethernet0: dwmac@9630000 { + device_type = "network"; + compatible = "st,stih407-dwmac", "snps,dwmac", "snps,dwmac-3.710"; + reg = <0x9630000 0x8000>; + reg-names = "stmmaceth"; + + st,syscon = <&syscfg_sbc_reg 0x80>; + st,gmac_en; + resets = <&softreset STIH407_ETH1_SOFTRESET>; + reset-names = "stmmaceth"; + + interrupts = , + , + ; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + + snps,pbl = <32>; + snps,mixed-burst; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rgmii1>; + + clock-names = "stmmaceth", "sti-ethclk"; + clocks = <&CLK_S_C0_FLEXGEN CLK_EXT2F_A9>, + <&CLK_S_C0_FLEXGEN CLK_ETH_PHY>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/stm32-dwmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/stm32-dwmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..1341012722aa3b5f6ec1676a7c4950219ddaf9a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/stm32-dwmac.txt @@ -0,0 +1,45 @@ +STMicroelectronics STM32 / MCU DWMAC glue layer controller + +This file documents platform glue layer for stmmac. +Please see stmmac.txt for the other unchanged properties. + +The device node has following properties. + +Required properties: +- compatible: For MCU family should be "st,stm32-dwmac" to select glue, and + "snps,dwmac-3.50a" to select IP version. + For MPU family should be "st,stm32mp1-dwmac" to select + glue, and "snps,dwmac-4.20a" to select IP version. +- clocks: Must contain a phandle for each entry in clock-names. +- clock-names: Should be "stmmaceth" for the host clock. + Should be "mac-clk-tx" for the MAC TX clock. + Should be "mac-clk-rx" for the MAC RX clock. + For MPU family need to add also "ethstp" for power mode clock and, + "syscfg-clk" for SYSCFG clock. +- interrupt-names: Should contain a list of interrupt names corresponding to + the interrupts in the interrupts property, if available. + Should be "macirq" for the main MAC IRQ + Should be "eth_wake_irq" for the IT which wake up system +- st,syscon : Should be phandle/offset pair. The phandle to the syscon node which + encompases the glue register, and the offset of the control register. + +Optional properties: +- clock-names: For MPU family "mac-clk-ck" for PHY without quartz +- st,int-phyclk (boolean) : valid only where PHY do not have quartz and need to be clock + by RCC + +Example: + + ethernet@40028000 { + compatible = "st,stm32-dwmac", "snps,dwmac-3.50a"; + reg = <0x40028000 0x8000>; + reg-names = "stmmaceth"; + interrupts = <0 61 0>, <0 62 0>; + interrupt-names = "macirq", "eth_wake_irq"; + clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx"; + clocks = <&rcc 0 25>, <&rcc 0 26>, <&rcc 0 27>; + st,syscon = <&syscfg 0x4>; + snps,pbl = <8>; + snps,mixed-burst; + dma-ranges; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/stmmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/stmmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb694062afff0896ed6e67c2ee12c7a9826f91a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/stmmac.txt @@ -0,0 +1,178 @@ +* STMicroelectronics 10/100/1000/2500/10000 Ethernet (GMAC/XGMAC) + +Required properties: +- compatible: Should be "snps,dwmac-", "snps,dwmac" or + "snps,dwxgmac-", "snps,dwxgmac". + For backwards compatibility: "st,spear600-gmac" is also supported. +- reg: Address and length of the register set for the device +- interrupts: Should contain the STMMAC interrupts +- interrupt-names: Should contain a list of interrupt names corresponding to + the interrupts in the interrupts property, if available. + Valid interrupt names are: + - "macirq" (combined signal for various interrupt events) + - "eth_wake_irq" (the interrupt to manage the remote wake-up packet detection) + - "eth_lpi" (the interrupt that occurs when Rx exits the LPI state) +- phy-mode: See ethernet.txt file in the same directory. +- snps,reset-gpio gpio number for phy reset. +- snps,reset-active-low boolean flag to indicate if phy reset is active low. +- snps,reset-delays-us is triplet of delays + The 1st cell is reset pre-delay in micro seconds. + The 2nd cell is reset pulse in micro seconds. + The 3rd cell is reset post-delay in micro seconds. + +Optional properties: +- resets: Should contain a phandle to the STMMAC reset signal, if any +- reset-names: Should contain the reset signal name "stmmaceth", if a + reset phandle is given +- max-frame-size: See ethernet.txt file in the same directory +- clocks: If present, the first clock should be the GMAC main clock and + the second clock should be peripheral's register interface clock. Further + clocks may be specified in derived bindings. +- clock-names: One name for each entry in the clocks property, the + first one should be "stmmaceth" and the second one should be "pclk". +- ptp_ref: this is the PTP reference clock; in case of the PTP is available + this clock is used for programming the Timestamp Addend Register. If not + passed then the system clock will be used and this is fine on some + platforms. +- tx-fifo-depth: See ethernet.txt file in the same directory +- rx-fifo-depth: See ethernet.txt file in the same directory +- snps,pbl Programmable Burst Length (tx and rx) +- snps,txpbl Tx Programmable Burst Length. Only for GMAC and newer. + If set, DMA tx will use this value rather than snps,pbl. +- snps,rxpbl Rx Programmable Burst Length. Only for GMAC and newer. + If set, DMA rx will use this value rather than snps,pbl. +- snps,no-pbl-x8 Don't multiply the pbl/txpbl/rxpbl values by 8. + For core rev < 3.50, don't multiply the values by 4. +- snps,aal Address-Aligned Beats +- snps,fixed-burst Program the DMA to use the fixed burst mode +- snps,mixed-burst Program the DMA to use the mixed burst mode +- snps,force_thresh_dma_mode Force DMA to use the threshold mode for + both tx and rx +- snps,force_sf_dma_mode Force DMA to use the Store and Forward + mode for both tx and rx. This flag is + ignored if force_thresh_dma_mode is set. +- snps,en-tx-lpi-clockgating Enable gating of the MAC TX clock during + TX low-power mode +- snps,multicast-filter-bins: Number of multicast filter hash bins + supported by this device instance +- snps,perfect-filter-entries: Number of perfect filter entries supported + by this device instance +- snps,ps-speed: port selection speed that can be passed to the core when + PCS is supported. For example, this is used in case of SGMII + and MAC2MAC connection. +- snps,tso: this enables the TSO feature otherwise it will be managed by + MAC HW capability register. Only for GMAC4 and newer. +- AXI BUS Mode parameters: below the list of all the parameters to program the + AXI register inside the DMA module: + - snps,lpi_en: enable Low Power Interface + - snps,xit_frm: unlock on WoL + - snps,wr_osr_lmt: max write outstanding req. limit + - snps,rd_osr_lmt: max read outstanding req. limit + - snps,kbbe: do not cross 1KiB boundary. + - snps,blen: this is a vector of supported burst length. + - snps,fb: fixed-burst + - snps,mb: mixed-burst + - snps,rb: rebuild INCRx Burst +- mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus. +- Multiple RX Queues parameters: below the list of all the parameters to + configure the multiple RX queues: + - snps,rx-queues-to-use: number of RX queues to be used in the driver + - Choose one of these RX scheduling algorithms: + - snps,rx-sched-sp: Strict priority + - snps,rx-sched-wsp: Weighted Strict priority + - For each RX queue + - Choose one of these modes: + - snps,dcb-algorithm: Queue to be enabled as DCB + - snps,avb-algorithm: Queue to be enabled as AVB + - snps,map-to-dma-channel: Channel to map + - Specifiy specific packet routing: + - snps,route-avcp: AV Untagged Control packets + - snps,route-ptp: PTP Packets + - snps,route-dcbcp: DCB Control Packets + - snps,route-up: Untagged Packets + - snps,route-multi-broad: Multicast & Broadcast Packets + - snps,priority: RX queue priority (Range: 0x0 to 0xF) +- Multiple TX Queues parameters: below the list of all the parameters to + configure the multiple TX queues: + - snps,tx-queues-to-use: number of TX queues to be used in the driver + - Choose one of these TX scheduling algorithms: + - snps,tx-sched-wrr: Weighted Round Robin + - snps,tx-sched-wfq: Weighted Fair Queuing + - snps,tx-sched-dwrr: Deficit Weighted Round Robin + - snps,tx-sched-sp: Strict priority + - For each TX queue + - snps,weight: TX queue weight (if using a DCB weight algorithm) + - Choose one of these modes: + - snps,dcb-algorithm: TX queue will be working in DCB + - snps,avb-algorithm: TX queue will be working in AVB + [Attention] Queue 0 is reserved for legacy traffic + and so no AVB is available in this queue. + - Configure Credit Base Shaper (if AVB Mode selected): + - snps,send_slope: enable Low Power Interface + - snps,idle_slope: unlock on WoL + - snps,high_credit: max write outstanding req. limit + - snps,low_credit: max read outstanding req. limit + - snps,priority: TX queue priority (Range: 0x0 to 0xF) +Examples: + + stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <0xf>; + snps,rd_osr_lmt = <0xf>; + snps,blen = <256 128 64 32 0 0 0>; + }; + + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <1>; + snps,rx-sched-sp; + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,priority = <0x0>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <2>; + snps,tx-sched-wrr; + queue0 { + snps,weight = <0x10>; + snps,dcb-algorithm; + snps,priority = <0x0>; + }; + + queue1 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3E800>; + snps,low_credit = <0xFFC18000>; + snps,priority = <0x1>; + }; + }; + + gmac0: ethernet@e0800000 { + compatible = "st,spear600-gmac"; + reg = <0xe0800000 0x8000>; + interrupt-parent = <&vic1>; + interrupts = <24 23 22>; + interrupt-names = "macirq", "eth_wake_irq", "eth_lpi"; + mac-address = [000000000000]; /* Filled in by U-Boot */ + max-frame-size = <3800>; + phy-mode = "gmii"; + snps,multicast-filter-bins = <256>; + snps,perfect-filter-entries = <128>; + rx-fifo-depth = <16384>; + tx-fifo-depth = <16384>; + clocks = <&clock>; + clock-names = "stmmaceth"; + snps,axi-config = <&stmmac_axi_setup>; + mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy1: ethernet-phy@0 { + }; + }; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ti,dp83867.txt b/arch/arm64/boot/dts/vendor/bindings/net/ti,dp83867.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ef9338aaee18655f7f97e7c98e3f2a2cacdc650 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ti,dp83867.txt @@ -0,0 +1,48 @@ +* Texas Instruments - dp83867 Giga bit ethernet phy + +Required properties: + - reg - The ID number for the phy, usually a small integer + - ti,rx-internal-delay - RGMII Receive Clock Delay - see dt-bindings/net/ti-dp83867.h + for applicable values. Required only if interface type is + PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_RXID + - ti,tx-internal-delay - RGMII Transmit Clock Delay - see dt-bindings/net/ti-dp83867.h + for applicable values. Required only if interface type is + PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_TXID + - ti,fifo-depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h + for applicable values + +Optional property: + - ti,min-output-impedance - MAC Interface Impedance control to set + the programmable output impedance to + minimum value (35 ohms). + - ti,max-output-impedance - MAC Interface Impedance control to set + the programmable output impedance to + maximum value (70 ohms). + - ti,dp83867-rxctrl-strap-quirk - This denotes the fact that the + board has RX_DV/RX_CTRL pin strapped in + mode 1 or 2. To ensure PHY operation, + there are specific actions that + software needs to take when this pin is + strapped in these modes. See data manual + for details. + - ti,clk-output-sel - Muxing option for CLK_OUT pin - see dt-bindings/net/ti-dp83867.h + for applicable values. + +Note: ti,min-output-impedance and ti,max-output-impedance are mutually + exclusive. When both properties are present ti,max-output-impedance + takes precedence. + +Default child nodes are standard Ethernet PHY device +nodes as described in Documentation/devicetree/bindings/net/phy.txt + +Example: + + ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,fifo-depth = ; + }; + +Datasheet can be found: +http://www.ti.com/product/DP83867IR/datasheet diff --git a/arch/arm64/boot/dts/vendor/bindings/net/ti-bluetooth.txt b/arch/arm64/boot/dts/vendor/bindings/net/ti-bluetooth.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d03ff8c7068135ed95d51dc1224266ae43b26e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/ti-bluetooth.txt @@ -0,0 +1,61 @@ +Texas Instruments Bluetooth Chips +--------------------------------- + +This documents the binding structure and common properties for serial +attached TI Bluetooth devices. The following chips are included in this +binding: + +* TI CC256x Bluetooth devices +* TI WiLink 7/8 (wl12xx/wl18xx) Shared Transport BT/FM/GPS devices + +TI WiLink devices have a UART interface for providing Bluetooth, FM radio, +and GPS over what's called "shared transport". The shared transport is +standard BT HCI protocol with additional channels for the other functions. + +TI WiLink devices also have a separate WiFi interface as described in +wireless/ti,wlcore.txt. + +This bindings follows the UART slave device binding in +../serial/slave-device.txt. + +Required properties: + - compatible: should be one of the following: + "ti,cc2560" + "ti,wl1271-st" + "ti,wl1273-st" + "ti,wl1281-st" + "ti,wl1283-st" + "ti,wl1285-st" + "ti,wl1801-st" + "ti,wl1805-st" + "ti,wl1807-st" + "ti,wl1831-st" + "ti,wl1835-st" + "ti,wl1837-st" + +Optional properties: + - enable-gpios : GPIO signal controlling enabling of BT. Active high. + - vio-supply : Vio input supply (1.8V) + - vbat-supply : Vbat input supply (2.9-4.8V) + - clocks : Must contain an entry, for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names : Must include the following entry: + "ext_clock" (External clock provided to the TI combo chip). + - nvmem-cells: phandle to nvmem data cell that contains a 6 byte BD address + with the most significant byte first (big-endian). + - nvmem-cell-names: "bd-address" (required when nvmem-cells is specified) + +Example: + +&serial0 { + compatible = "ns16550a"; + ... + bluetooth { + compatible = "ti,wl1835-st"; + enable-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + clocks = <&clk32k_wl18xx>; + clock-names = "ext_clock"; + nvmem-cells = <&bd_address>; + nvmem-cell-names = "bd-address"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/via-rhine.txt b/arch/arm64/boot/dts/vendor/bindings/net/via-rhine.txt new file mode 100644 index 0000000000000000000000000000000000000000..334eca2bf937cc4a383be87f952ed7b5acbbeb59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/via-rhine.txt @@ -0,0 +1,17 @@ +* VIA Rhine 10/100 Network Controller + +Required properties: +- compatible : Should be "via,vt8500-rhine" for integrated + Rhine controllers found in VIA VT8500, WonderMedia WM8950 + and similar. These are listed as 1106:3106 rev. 0x84 on the + virtual PCI bus under vendor-provided kernels +- reg : Address and length of the io space +- interrupts : Should contain the controller interrupt line + +Examples: + +ethernet@d8004000 { + compatible = "via,vt8500-rhine"; + reg = <0xd8004000 0x100>; + interrupts = <10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/via-velocity.txt b/arch/arm64/boot/dts/vendor/bindings/net/via-velocity.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3db469b1ad7e65483ccd5f6213e551de7c664a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/via-velocity.txt @@ -0,0 +1,20 @@ +* VIA Velocity 10/100/1000 Network Controller + +Required properties: +- compatible : Should be "via,velocity-vt6110" +- reg : Address and length of the io space +- interrupts : Should contain the controller interrupt line + +Optional properties: +- no-eeprom : PCI network cards use an external EEPROM to store data. Embedded + devices quite often set this data in uboot and do not provide an eeprom. + Specify this option if you have no external eeprom. + +Examples: + +eth0@d8004000 { + compatible = "via,velocity-vt6110"; + reg = <0xd8004000 0x400>; + interrupts = <10>; + no-eeprom; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/brcm,bcm43xx-fmac.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/brcm,bcm43xx-fmac.txt new file mode 100644 index 0000000000000000000000000000000000000000..cffb2d6876e349c43d4c38aeb6dba29809ac7b80 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/brcm,bcm43xx-fmac.txt @@ -0,0 +1,38 @@ +Broadcom BCM43xx Fullmac wireless SDIO devices + +This node provides properties for controlling the Broadcom wireless device. The +node is expected to be specified as a child node to the SDIO controller that +connects the device to the system. + +Required properties: + + - compatible : Should be "brcm,bcm4329-fmac". + +Optional properties: + - brcm,drive-strength : drive strength used for SDIO pins on device in mA + (default = 6). + - interrupts : specifies attributes for the out-of-band interrupt (host-wake). + When not specified the device will use in-band SDIO interrupts. + - interrupt-names : name of the out-of-band interrupt, which must be set + to "host-wake". + +Example: + +mmc3: mmc@1c12000 { + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&mmc3_pins_a>; + vmmc-supply = <®_vmmc3>; + bus-width = <4>; + non-removable; + + brcmf: wifi@1 { + reg = <1>; + compatible = "brcm,bcm4329-fmac"; + interrupt-parent = <&pio>; + interrupts = <10 8>; /* PH10 / EINT10 */ + interrupt-names = "host-wake"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/esp,esp8089.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/esp,esp8089.txt new file mode 100644 index 0000000000000000000000000000000000000000..6830c4786f8ab82d658067b0a16587b436f02abd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/esp,esp8089.txt @@ -0,0 +1,30 @@ +Espressif ESP8089 wireless SDIO devices + +This node provides properties for controlling the ESP8089 wireless device. +The node is expected to be specified as a child node to the SDIO controller +that connects the device to the system. + +Required properties: + + - compatible : Should be "esp,esp8089". + +Optional properties: + - esp,crystal-26M-en: Integer value for the crystal_26M_en firmware parameter + +Example: + +&mmc1 { + #address-cells = <1>; + #size-cells = <0>; + + vmmc-supply = <®_dldo1>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + non-removable; + + esp8089: sdio_wifi@1 { + compatible = "esp,esp8089"; + reg = <1>; + esp,crystal-26M-en = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/ieee80211.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ieee80211.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6442b1397f50f77c5dc68c861ad11483ba44134 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ieee80211.txt @@ -0,0 +1,24 @@ +Common IEEE 802.11 properties + +This provides documentation of common properties that are valid for all wireless +devices. + +Optional properties: + - ieee80211-freq-limit : list of supported frequency ranges in KHz. This can be + used for devices that in a given config support less channels than + normally. It may happen chipset supports a wide wireless band but it is + limited to some part of it due to used antennas or power amplifier. + An example case for this can be tri-band wireless router with two + identical chipsets used for two different 5 GHz subbands. Using them + incorrectly could not work or decrease performance noticeably. + +Example: + +pcie@0,0 { + reg = <0x0000 0 0 0 0>; + wifi@0,0 { + reg = <0x0000 0 0 0 0>; + ieee80211-freq-limit = <2402000 2482000>, + <5170000 5250000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/marvell-8xxx.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/marvell-8xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bf9bbac16e250fdc674c90a7074aa7724d0ce89 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/marvell-8xxx.txt @@ -0,0 +1,68 @@ +Marvell 8787/8897/8997 (sd8787/sd8897/sd8997/pcie8997) SDIO/PCIE devices +------ + +This node provides properties for controlling the Marvell SDIO/PCIE wireless device. +The node is expected to be specified as a child node to the SDIO/PCIE controller that +connects the device to the system. + +Required properties: + + - compatible : should be one of the following: + * "marvell,sd8787" + * "marvell,sd8897" + * "marvell,sd8997" + * "pci11ab,2b42" + * "pci1b4b,2b42" + +Optional properties: + + - marvell,caldata* : A series of properties with marvell,caldata prefix, + represent calibration data downloaded to the device during + initialization. This is an array of unsigned 8-bit values. + the properties should follow below property name and + corresponding array length: + "marvell,caldata-txpwrlimit-2g" (length = 566). + "marvell,caldata-txpwrlimit-5g-sub0" (length = 502). + "marvell,caldata-txpwrlimit-5g-sub1" (length = 688). + "marvell,caldata-txpwrlimit-5g-sub2" (length = 750). + "marvell,caldata-txpwrlimit-5g-sub3" (length = 502). + - marvell,wakeup-pin : a wakeup pin number of wifi chip which will be configured + to firmware. Firmware will wakeup the host using this pin + during suspend/resume. + - interrupts : interrupt pin number to the cpu. driver will request an irq based on + this interrupt number. during system suspend, the irq will be enabled + so that the wifi chip can wakeup host platform under certain condition. + during system resume, the irq will be disabled to make sure + unnecessary interrupt is not received. + - vmmc-supply: a phandle of a regulator, supplying VCC to the card + - mmc-pwrseq: phandle to the MMC power sequence node. See "mmc-pwrseq-*" + for documentation of MMC power sequence bindings. + +Example: + +Tx power limit calibration data is configured in below example. +The calibration data is an array of unsigned values, the length +can vary between hw versions. +IRQ pin 38 is used as system wakeup source interrupt. wakeup pin 3 is configured +so that firmware can wakeup host using this device side pin. + +&mmc3 { + vmmc-supply = <&wlan_en_reg>; + mmc-pwrseq = <&wifi_pwrseq>; + bus-width = <4>; + cap-power-off-card; + keep-power-in-suspend; + + #address-cells = <1>; + #size-cells = <0>; + mwifiex: wifi@1 { + compatible = "marvell,sd8897"; + reg = <1>; + interrupt-parent = <&pio>; + interrupts = <38 IRQ_TYPE_LEVEL_LOW>; + + marvell,caldata_00_txpwrlimit_2g_cfg_set = /bits/ 8 < + 0x01 0x00 0x06 0x00 0x08 0x02 0x89 0x01>; + marvell,wakeup-pin = <3>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/mediatek,mt76.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/mediatek,mt76.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c17a0ec9b7b29c97a5dad64efac66b650828862 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/mediatek,mt76.txt @@ -0,0 +1,32 @@ +* MediaTek mt76xx devices + +This node provides properties for configuring the MediaTek mt76xx wireless +device. The node is expected to be specified as a child node of the PCI +controller to which the wireless chip is connected. + +Optional properties: + +- mac-address: See ethernet.txt in the parent directory +- local-mac-address: See ethernet.txt in the parent directory +- ieee80211-freq-limit: See ieee80211.txt +- mediatek,mtd-eeprom: Specify a MTD partition + offset containing EEPROM data + +Optional nodes: +- led: Properties for a connected LED + Optional properties: + - led-sources: See Documentation/devicetree/bindings/leds/common.txt + +&pcie { + pcie0 { + wifi@0,0 { + compatible = "mediatek,mt76"; + reg = <0x0000 0 0 0 0>; + ieee80211-freq-limit = <5000000 6000000>; + mediatek,mtd-eeprom = <&factory 0x8000>; + + led { + led-sources = <2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/qca,ath9k.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/qca,ath9k.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7396c8c271cd339784b777a234862aa3786cf1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/qca,ath9k.txt @@ -0,0 +1,48 @@ +* Qualcomm Atheros ath9k wireless devices + +This node provides properties for configuring the ath9k wireless device. The +node is expected to be specified as a child node of the PCI controller to +which the wireless chip is connected. + +Required properties: +- compatible: For PCI and PCIe devices this should be an identifier following + the format as defined in "PCI Bus Binding to Open Firmware" + Revision 2.1. One of the possible formats is "pciVVVV,DDDD" + where VVVV is the PCI vendor ID and DDDD is PCI device ID. + Typically QCA's PCI vendor ID 168c is used while the PCI device + ID depends on the chipset - see the following (possibly + incomplete) list: + - 0023 for AR5416 + - 0024 for AR5418 + - 0027 for AR9160 + - 0029 for AR9220 and AR9223 + - 002a for AR9280 and AR9283 + - 002b for AR9285 + - 002c for AR2427 + - 002d for AR9227 + - 002e for AR9287 + - 0030 for AR9380, AR9381 and AR9382 + - 0032 for AR9485 + - 0033 for AR9580 and AR9590 + - 0034 for AR9462 + - 0036 for AR9565 + - 0037 for AR9485 +- reg: Address and length of the register set for the device. + +Optional properties: +- qca,no-eeprom: Indicates that there is no physical EEPROM connected to the + ath9k wireless chip (in this case the calibration / + EEPROM data will be loaded from userspace using the + kernel firmware loader). +- mac-address: See ethernet.txt in the parent directory +- local-mac-address: See ethernet.txt in the parent directory + + +In this example, the node is defined as child node of the PCI controller: +&pci0 { + wifi@168c,002d { + compatible = "pci168c,002d"; + reg = <0x7000 0 0 0 0x1000>; + qca,no-eeprom; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/qcom,ath10k.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/qcom,ath10k.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fd4e8ce4149a9663ec93f95c9ce5c5dc4741aca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/qcom,ath10k.txt @@ -0,0 +1,152 @@ +* Qualcomm Atheros ath10k wireless devices + +Required properties: +- compatible: Should be one of the following: + * "qcom,ath10k" + * "qcom,ipq4019-wifi" + * "qcom,wcn3990-wifi" + +PCI based devices uses compatible string "qcom,ath10k" and takes calibration +data along with board specific data via "qcom,ath10k-calibration-data". +Rest of the properties are not applicable for PCI based devices. + +AHB based devices (i.e. ipq4019) uses compatible string "qcom,ipq4019-wifi" +and also uses most of the properties defined in this doc (except +"qcom,ath10k-calibration-data"). It uses "qcom,ath10k-pre-calibration-data" +to carry pre calibration data. + +In general, entry "qcom,ath10k-pre-calibration-data" and +"qcom,ath10k-calibration-data" conflict with each other and only one +can be provided per device. + +SNOC based devices (i.e. wcn3990) uses compatible string "qcom,wcn3990-wifi". + +Optional properties: +- reg: Address and length of the register set for the device. +- reg-names: Must include the list of following reg names, + "membase" +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reseti.txt for details. +- reset-names: Must include the list of following reset names, + "wifi_cpu_init" + "wifi_radio_srif" + "wifi_radio_warm" + "wifi_radio_cold" + "wifi_core_warm" + "wifi_core_cold" +- clocks: List of clock specifiers, must contain an entry for each required + entry in clock-names. +- clock-names: Should contain the clock names "wifi_wcss_cmd", "wifi_wcss_ref", + "wifi_wcss_rtc". +- interrupts: List of interrupt lines. Must contain an entry + for each entry in the interrupt-names property. +- interrupt-names: Must include the entries for MSI interrupt + names ("msi0" to "msi15") and legacy interrupt + name ("legacy"), +- qcom,msi_addr: MSI interrupt address. +- qcom,msi_base: Base value to add before writing MSI data into + MSI address register. +- qcom,ath10k-calibration-variant: string to search for in the board-2.bin + variant list with the same bus and device + specific ids +- qcom,ath10k-calibration-data : calibration data + board specific data + as an array, the length can vary between + hw versions. +- qcom,ath10k-pre-calibration-data : pre calibration data as an array, + the length can vary between hw versions. +- -supply: handle to the regulator device tree node + optional "supply-name" is "vdd-0.8-cx-mx". + +Example (to supply the calibration data alone): + +In this example, the node is defined as child node of the PCI controller. + +pci { + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + + ath10k@0,0 { + reg = <0 0 0 0 0>; + device_type = "pci"; + qcom,ath10k-calibration-data = [ 01 02 03 ... ]; + }; + }; +}; + +Example (to supply ipq4019 SoC wifi block details): + +wifi0: wifi@a000000 { + compatible = "qcom,ipq4019-wifi"; + reg = <0xa000000 0x200000>; + resets = <&gcc WIFI0_CPU_INIT_RESET>, + <&gcc WIFI0_RADIO_SRIF_RESET>, + <&gcc WIFI0_RADIO_WARM_RESET>, + <&gcc WIFI0_RADIO_COLD_RESET>, + <&gcc WIFI0_CORE_WARM_RESET>, + <&gcc WIFI0_CORE_COLD_RESET>; + reset-names = "wifi_cpu_init", + "wifi_radio_srif", + "wifi_radio_warm", + "wifi_radio_cold", + "wifi_core_warm", + "wifi_core_cold"; + clocks = <&gcc GCC_WCSS2G_CLK>, + <&gcc GCC_WCSS2G_REF_CLK>, + <&gcc GCC_WCSS2G_RTC_CLK>; + clock-names = "wifi_wcss_cmd", + "wifi_wcss_ref", + "wifi_wcss_rtc"; + interrupts = <0 0x20 0x1>, + <0 0x21 0x1>, + <0 0x22 0x1>, + <0 0x23 0x1>, + <0 0x24 0x1>, + <0 0x25 0x1>, + <0 0x26 0x1>, + <0 0x27 0x1>, + <0 0x28 0x1>, + <0 0x29 0x1>, + <0 0x2a 0x1>, + <0 0x2b 0x1>, + <0 0x2c 0x1>, + <0 0x2d 0x1>, + <0 0x2e 0x1>, + <0 0x2f 0x1>, + <0 0xa8 0x0>; + interrupt-names = "msi0", "msi1", "msi2", "msi3", + "msi4", "msi5", "msi6", "msi7", + "msi8", "msi9", "msi10", "msi11", + "msi12", "msi13", "msi14", "msi15", + "legacy"; + qcom,msi_addr = <0x0b006040>; + qcom,msi_base = <0x40>; + qcom,ath10k-pre-calibration-data = [ 01 02 03 ... ]; +}; + +Example (to supply wcn3990 SoC wifi block details): + +wifi@18000000 { + compatible = "qcom,wcn3990-wifi"; + reg = <0x18800000 0x800000>; + reg-names = "membase"; + clocks = <&clock_gcc clk_aggre2_noc_clk>; + clock-names = "smmu_aggre2_noc_clk" + interrupts = + <0 130 0 /* CE0 */ >, + <0 131 0 /* CE1 */ >, + <0 132 0 /* CE2 */ >, + <0 133 0 /* CE3 */ >, + <0 134 0 /* CE4 */ >, + <0 135 0 /* CE5 */ >, + <0 136 0 /* CE6 */ >, + <0 137 0 /* CE7 */ >, + <0 138 0 /* CE8 */ >, + <0 139 0 /* CE9 */ >, + <0 140 0 /* CE10 */ >, + <0 141 0 /* CE11 */ >; + vdd-0.8-cx-mx-supply = <&pm8998_l5>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wl1251.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wl1251.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb2fcde6f7ffb62fc2cf37617b332501d4c0625e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wl1251.txt @@ -0,0 +1,37 @@ +* Texas Instruments wl1251 wireless lan controller + +The wl1251 chip can be connected via SPI or via SDIO. This +document describes the binding for the SPI connected chip. + +Required properties: +- compatible : Should be "ti,wl1251" +- reg : Chip select address of device +- spi-max-frequency : Maximum SPI clocking speed of device in Hz +- interrupts : Should contain interrupt line +- vio-supply : phandle to regulator providing VIO +- ti,power-gpio : GPIO connected to chip's PMEN pin + +Optional properties: +- ti,wl1251-has-eeprom : boolean, the wl1251 has an eeprom connected, which + provides configuration data (calibration, MAC, ...) +- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt + for optional SPI connection related properties, + +Examples: + +&spi1 { + wl1251@0 { + compatible = "ti,wl1251"; + + reg = <0>; + spi-max-frequency = <48000000>; + spi-cpol; + spi-cpha; + + interrupt-parent = <&gpio2>; + interrupts = <10 IRQ_TYPE_NONE>; /* gpio line 42 */ + + vio-supply = <&vio>; + ti,power-gpio = <&gpio3 23 GPIO_ACTIVE_HIGH>; /* 87 */ + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wlcore,spi.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wlcore,spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb5c9e1569ca530098e9422481b4edb8a7bb19a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wlcore,spi.txt @@ -0,0 +1,57 @@ +* Texas Instruments wl12xx/wl18xx wireless lan controller + +The wl12xx/wl18xx chips can be connected via SPI or via SDIO. This +document describes the binding for the SPI connected chip. + +Required properties: +- compatible : Should be one of the following: + * "ti,wl1271" + * "ti,wl1273" + * "ti,wl1281" + * "ti,wl1283" + * "ti,wl1801" + * "ti,wl1805" + * "ti,wl1807" + * "ti,wl1831" + * "ti,wl1835" + * "ti,wl1837" +- reg : Chip select address of device +- spi-max-frequency : Maximum SPI clocking speed of device in Hz +- interrupts : Should contain parameters for 1 interrupt line. +- vwlan-supply : Point the node of the regulator that powers/enable the + wl12xx/wl18xx chip + +Optional properties: +- ref-clock-frequency : Reference clock frequency (should be set for wl12xx) +- clock-xtal : boolean, clock is generated from XTAL + +- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt + for optional SPI connection related properties, + +Examples: + +For wl12xx family: +&spi1 { + wlcore: wlcore@1 { + compatible = "ti,wl1271"; + reg = <1>; + spi-max-frequency = <48000000>; + interrupt-parent = <&gpio3>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + vwlan-supply = <&vwlan_fixed>; + clock-xtal; + ref-clock-frequency = <38400000>; + }; +}; + +For wl18xx family: +&spi0 { + wlcore: wlcore@0 { + compatible = "ti,wl1835"; + reg = <0>; + spi-max-frequency = <48000000>; + interrupt-parent = <&gpio0>; + interrupts = <27 IRQ_TYPE_EDGE_RISING>; + vwlan-supply = <&vwlan_fixed>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wlcore.txt b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wlcore.txt new file mode 100644 index 0000000000000000000000000000000000000000..9306c4dadd46aea75f0db773d746c1bf48b7945b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/wireless/ti,wlcore.txt @@ -0,0 +1,45 @@ +TI Wilink 6/7/8 (wl12xx/wl18xx) SDIO devices + +This node provides properties for controlling the wilink wireless device. The +node is expected to be specified as a child node to the SDIO controller that +connects the device to the system. + +Required properties: + - compatible: should be one of the following: + * "ti,wl1271" + * "ti,wl1273" + * "ti,wl1281" + * "ti,wl1283" + * "ti,wl1285" + * "ti,wl1801" + * "ti,wl1805" + * "ti,wl1807" + * "ti,wl1831" + * "ti,wl1835" + * "ti,wl1837" + - interrupts : specifies attributes for the out-of-band interrupt. + +Optional properties: + - ref-clock-frequency : ref clock frequency in Hz + - tcxo-clock-frequency : tcxo clock frequency in Hz + +Note: the *-clock-frequency properties assume internal clocks. In case of external +clock, new bindings (for parsing the clock nodes) have to be added. + +Example: + +&mmc3 { + vmmc-supply = <&wlan_en_reg>; + bus-width = <4>; + cap-power-off-card; + keep-power-in-suspend; + + #address-cells = <1>; + #size-cells = <0>; + wlcore: wlcore@2 { + compatible = "ti,wl1835"; + reg = <2>; + interrupt-parent = <&gpio0>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/xilinx_axienet.txt b/arch/arm64/boot/dts/vendor/bindings/net/xilinx_axienet.txt new file mode 100644 index 0000000000000000000000000000000000000000..38f9ec076743a607e57775b9806b7f09b04c6fd1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/xilinx_axienet.txt @@ -0,0 +1,55 @@ +XILINX AXI ETHERNET Device Tree Bindings +-------------------------------------------------------- + +Also called AXI 1G/2.5G Ethernet Subsystem, the xilinx axi ethernet IP core +provides connectivity to an external ethernet PHY supporting different +interfaces: MII, GMII, RGMII, SGMII, 1000BaseX. It also includes two +segments of memory for buffering TX and RX, as well as the capability of +offloading TX/RX checksum calculation off the processor. + +Management configuration is done through the AXI interface, while payload is +sent and received through means of an AXI DMA controller. This driver +includes the DMA driver code, so this driver is incompatible with AXI DMA +driver. + +For more details about mdio please refer phy.txt file in the same directory. + +Required properties: +- compatible : Must be one of "xlnx,axi-ethernet-1.00.a", + "xlnx,axi-ethernet-1.01.a", "xlnx,axi-ethernet-2.01.a" +- reg : Address and length of the IO space. +- interrupts : Should be a list of two interrupt, TX and RX. +- phy-handle : Should point to the external phy device. + See ethernet.txt file in the same directory. +- xlnx,rxmem : Set to allocated memory buffer for Rx/Tx in the hardware + +Optional properties: +- phy-mode : See ethernet.txt +- xlnx,phy-type : Deprecated, do not use, but still accepted in preference + to phy-mode. +- xlnx,txcsum : 0 or empty for disabling TX checksum offload, + 1 to enable partial TX checksum offload, + 2 to enable full TX checksum offload +- xlnx,rxcsum : Same values as xlnx,txcsum but for RX checksum offload + +Example: + axi_ethernet_eth: ethernet@40c00000 { + compatible = "xlnx,axi-ethernet-1.00.a"; + device_type = "network"; + interrupt-parent = <µblaze_0_axi_intc>; + interrupts = <2 0>; + phy-mode = "mii"; + reg = <0x40c00000 0x40000>; + xlnx,rxcsum = <0x2>; + xlnx,rxmem = <0x800>; + xlnx,txcsum = <0x2>; + phy-handle = <&phy0>; + axi_ethernetlite_0_mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: phy@0 { + device_type = "ethernet-phy"; + reg = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/net/xilinx_gmii2rgmii.txt b/arch/arm64/boot/dts/vendor/bindings/net/xilinx_gmii2rgmii.txt new file mode 100644 index 0000000000000000000000000000000000000000..038dda48b8e616ad9a62c32acb4ade21813a7c1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/net/xilinx_gmii2rgmii.txt @@ -0,0 +1,35 @@ +XILINX GMIITORGMII Converter Driver Device Tree Bindings +-------------------------------------------------------- + +The Gigabit Media Independent Interface (GMII) to Reduced Gigabit Media +Independent Interface (RGMII) core provides the RGMII between RGMII-compliant +Ethernet physical media devices (PHY) and the Gigabit Ethernet controller. +This core can be used in all three modes of operation(10/100/1000 Mb/s). +The Management Data Input/Output (MDIO) interface is used to configure the +Speed of operation. This core can switch dynamically between the three +Different speed modes by configuring the conveter register through mdio write. + +This converter sits between the ethernet MAC and the external phy. +MAC <==> GMII2RGMII <==> RGMII_PHY + +For more details about mdio please refer phy.txt file in the same directory. + +Required properties: +- compatible : Should be "xlnx,gmii-to-rgmii-1.0" +- reg : The ID number for the phy, usually a small integer +- phy-handle : Should point to the external phy device. + See ethernet.txt file in the same directory. + +Example: + mdio { + #address-cells = <1>; + #size-cells = <0>; + phy: ethernet-phy@0 { + ...... + }; + gmiitorgmii: gmiitorgmii@8 { + compatible = "xlnx,gmii-to-rgmii-1.0"; + reg = <8>; + phy-handle = <&phy>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nfc/nq-nci.txt b/arch/arm64/boot/dts/vendor/bindings/nfc/nq-nci.txt new file mode 100644 index 0000000000000000000000000000000000000000..d18a0c592a91063db0b6c7268bd6831d90b60cbf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nfc/nq-nci.txt @@ -0,0 +1,55 @@ +Qualcomm Technologies, Inc NQxxxx NFC NCI device + +Near Field Communication (NFC) device is based on NFC Controller Interface (NCI) + +Required properties: + +- compatible: "qcom,nq-nci" +- reg: NCI i2c slave address. +- qcom,nq-ven: specific gpio for hardware reset. +- qcom,nq-irq: specific gpio for read interrupt. +- qcom,nq-firm: gpio for firmware download +- qcom,nq-clkreq: gpio for clock +- interrupt-parent: Should be phandle for the interrupt controller + that services interrupts for this device. +- interrupts: Nfc read interrupt,gpio-clk-req interrupt + + +Recommended properties: + +- interrupt-names: names of interrupts, should include "nfc_irq", used for reference + + +Optional properties: + +- pinctrl-names, pinctrl-0, pincntrl-1: references to our pincntrl settings +- clocks, clock-names: must contain the NQxxxx's core clock. +- qcom,nq-esepwr: gpio to control power of secure element +- qcom,nq-vdd-1p8-supply: name of LDO to which NFC is connected +- qcom,nq-vdd-1p8-voltage: min and max voltage(in uV) requirement for NFC +- qcom,nq-vdd-1p8-current: max current(in uA) expected by NFC +- qcom,clk-src: NFC clock for antenna + +Example: + + nq-nci@2b { + compatible = "qcom,nq-nci"; + reg = <0x2b>; + qcom,nq-irq = <&tlmm 29 0x00>; + qcom,nq-ven = <&tlmm 30 0x00>; + qcom,nq-firm = <&tlmm 93 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + qcom,nq-vdd-1p8-supply = <&L11A>; + qcom,nq-vdd-1p8-voltage = <1800000 1800000>; + qcom,nq-vdd-1p8-current = <157000>; + qcom,clk-src = "BBCLK2"; + interrupt-parent = <&tlmm>; + interrupts = <29 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active","nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_rpm clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nios2/nios2.txt b/arch/arm64/boot/dts/vendor/bindings/nios2/nios2.txt new file mode 100644 index 0000000000000000000000000000000000000000..b95e831bcba3f9824bebf3ce75ee11c2a0b4f203 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nios2/nios2.txt @@ -0,0 +1,62 @@ +* Nios II Processor Binding + +This binding specifies what properties available in the device tree +representation of a Nios II Processor Core. + +Users can use sopc2dts tool for generating device tree sources (dts) from a +Qsys system. See more detail in: http://www.alterawiki.com/wiki/Sopc2dts + +Required properties: + +- compatible: Compatible property value should be "altr,nios2-1.0". +- reg: Contains CPU index. +- interrupt-controller: Specifies that the node is an interrupt controller +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source, should be 1. +- clock-frequency: Contains the clock frequency for CPU, in Hz. +- dcache-line-size: Contains data cache line size. +- icache-line-size: Contains instruction line size. +- dcache-size: Contains data cache size. +- icache-size: Contains instruction cache size. +- altr,pid-num-bits: Specifies the number of bits to use to represent the process + identifier (PID). +- altr,tlb-num-ways: Specifies the number of set-associativity ways in the TLB. +- altr,tlb-num-entries: Specifies the number of entries in the TLB. +- altr,tlb-ptr-sz: Specifies size of TLB pointer. +- altr,has-mul: Specifies CPU hardware multipy support, should be 1. +- altr,has-mmu: Specifies CPU support MMU support, should be 1. +- altr,has-initda: Specifies CPU support initda instruction, should be 1. +- altr,reset-addr: Specifies CPU reset address +- altr,fast-tlb-miss-addr: Specifies CPU fast TLB miss exception address +- altr,exception-addr: Specifies CPU exception address + +Optional properties: +- altr,has-div: Specifies CPU hardware divide support +- altr,implementation: Nios II core implementation, this should be "fast"; + +Example: + +cpu@0 { + device_type = "cpu"; + compatible = "altr,nios2-1.0"; + reg = <0>; + interrupt-controller; + #interrupt-cells = <1>; + clock-frequency = <125000000>; + dcache-line-size = <32>; + icache-line-size = <32>; + dcache-size = <32768>; + icache-size = <32768>; + altr,implementation = "fast"; + altr,pid-num-bits = <8>; + altr,tlb-num-ways = <16>; + altr,tlb-num-entries = <128>; + altr,tlb-ptr-sz = <7>; + altr,has-div = <1>; + altr,has-mul = <1>; + altr,reset-addr = <0xc2800000>; + altr,fast-tlb-miss-addr = <0xc7fff400>; + altr,exception-addr = <0xd0000020>; + altr,has-initda = <1>; + altr,has-mmu = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/numa.txt b/arch/arm64/boot/dts/vendor/bindings/numa.txt new file mode 100644 index 0000000000000000000000000000000000000000..21b35053ca5a7c3abca7cfe4c779eb14e14ea9c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/numa.txt @@ -0,0 +1,275 @@ +============================================================================== +NUMA binding description. +============================================================================== + +============================================================================== +1 - Introduction +============================================================================== + +Systems employing a Non Uniform Memory Access (NUMA) architecture contain +collections of hardware resources including processors, memory, and I/O buses, +that comprise what is commonly known as a NUMA node. +Processor accesses to memory within the local NUMA node is generally faster +than processor accesses to memory outside of the local NUMA node. +DT defines interfaces that allow the platform to convey NUMA node +topology information to OS. + +============================================================================== +2 - numa-node-id +============================================================================== + +For the purpose of identification, each NUMA node is associated with a unique +token known as a node id. For the purpose of this binding +a node id is a 32-bit integer. + +A device node is associated with a NUMA node by the presence of a +numa-node-id property which contains the node id of the device. + +Example: + /* numa node 0 */ + numa-node-id = <0>; + + /* numa node 1 */ + numa-node-id = <1>; + +============================================================================== +3 - distance-map +============================================================================== + +The optional device tree node distance-map describes the relative +distance (memory latency) between all numa nodes. + +- compatible : Should at least contain "numa-distance-map-v1". + +- distance-matrix + This property defines a matrix to describe the relative distances + between all numa nodes. + It is represented as a list of node pairs and their relative distance. + + Note: + 1. Each entry represents distance from first node to second node. + The distances are equal in either direction. + 2. The distance from a node to self (local distance) is represented + with value 10 and all internode distance should be represented with + a value greater than 10. + 3. distance-matrix should have entries in lexicographical ascending + order of nodes. + 4. There must be only one device node distance-map which must + reside in the root node. + 5. If the distance-map node is not present, a default + distance-matrix is used. + +Example: + 4 nodes connected in mesh/ring topology as below, + + 0_______20______1 + | | + | | + 20 20 + | | + | | + |_______________| + 3 20 2 + + if relative distance for each hop is 20, + then internode distance would be, + 0 -> 1 = 20 + 1 -> 2 = 20 + 2 -> 3 = 20 + 3 -> 0 = 20 + 0 -> 2 = 40 + 1 -> 3 = 40 + + and dt presentation for this distance matrix is, + + distance-map { + compatible = "numa-distance-map-v1"; + distance-matrix = <0 0 10>, + <0 1 20>, + <0 2 40>, + <0 3 20>, + <1 0 20>, + <1 1 10>, + <1 2 20>, + <1 3 40>, + <2 0 40>, + <2 1 20>, + <2 2 10>, + <2 3 20>, + <3 0 20>, + <3 1 40>, + <3 2 20>, + <3 3 10>; + }; + +============================================================================== +4 - Example dts +============================================================================== + +Dual socket system consists of 2 boards connected through ccn bus and +each board having one socket/soc of 8 cpus, memory and pci bus. + + memory@c00000 { + device_type = "memory"; + reg = <0x0 0xc00000 0x0 0x80000000>; + /* node 0 */ + numa-node-id = <0>; + }; + + memory@10000000000 { + device_type = "memory"; + reg = <0x100 0x0 0x0 0x80000000>; + /* node 1 */ + numa-node-id = <1>; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + /* node 0 */ + numa-node-id = <0>; + }; + cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + enable-method = "psci"; + numa-node-id = <0>; + }; + cpu@8 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x8>; + enable-method = "psci"; + /* node 1 */ + numa-node-id = <1>; + }; + cpu@9 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x9>; + enable-method = "psci"; + numa-node-id = <1>; + }; + cpu@a { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0xa>; + enable-method = "psci"; + numa-node-id = <1>; + }; + cpu@b { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0xb>; + enable-method = "psci"; + numa-node-id = <1>; + }; + cpu@c { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0xc>; + enable-method = "psci"; + numa-node-id = <1>; + }; + cpu@d { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0xd>; + enable-method = "psci"; + numa-node-id = <1>; + }; + cpu@e { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0xe>; + enable-method = "psci"; + numa-node-id = <1>; + }; + cpu@f { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0xf>; + enable-method = "psci"; + numa-node-id = <1>; + }; + }; + + pcie0: pcie0@848000000000 { + compatible = "arm,armv8"; + device_type = "pci"; + bus-range = <0 255>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0x8480 0x00000000 0 0x10000000>; /* Configuration space */ + ranges = <0x03000000 0x8010 0x00000000 0x8010 0x00000000 0x70 0x00000000>; + /* node 0 */ + numa-node-id = <0>; + }; + + pcie1: pcie1@948000000000 { + compatible = "arm,armv8"; + device_type = "pci"; + bus-range = <0 255>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0x9480 0x00000000 0 0x10000000>; /* Configuration space */ + ranges = <0x03000000 0x9010 0x00000000 0x9010 0x00000000 0x70 0x00000000>; + /* node 1 */ + numa-node-id = <1>; + }; + + distance-map { + compatible = "numa-distance-map-v1"; + distance-matrix = <0 0 10>, + <0 1 20>, + <1 1 10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/allwinner,sunxi-sid.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/allwinner,sunxi-sid.txt new file mode 100644 index 0000000000000000000000000000000000000000..e319fe5e205ac5d32af9726285afe942848f934c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/allwinner,sunxi-sid.txt @@ -0,0 +1,27 @@ +Allwinner sunxi-sid + +Required properties: +- compatible: Should be one of the following: + "allwinner,sun4i-a10-sid" + "allwinner,sun7i-a20-sid" + "allwinner,sun8i-a83t-sid" + "allwinner,sun8i-h3-sid" + "allwinner,sun50i-a64-sid" + +- reg: Should contain registers location and length + += Data cells = +Are child nodes of qfprom, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example for sun4i: + sid@1c23800 { + compatible = "allwinner,sun4i-a10-sid"; + reg = <0x01c23800 0x10> + }; + +Example for sun7i: + sid@1c23800 { + compatible = "allwinner,sun7i-a20-sid"; + reg = <0x01c23800 0x200> + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/amlogic-efuse.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/amlogic-efuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3298e18de26b55580a8ec5e1241a8d32060d330 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/amlogic-efuse.txt @@ -0,0 +1,39 @@ += Amlogic Meson GX eFuse device tree bindings = + +Required properties: +- compatible: should be "amlogic,meson-gxbb-efuse" + += Data cells = +Are child nodes of eFuse, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + efuse: efuse { + compatible = "amlogic,meson-gxbb-efuse"; + #address-cells = <1>; + #size-cells = <1>; + + sn: sn@14 { + reg = <0x14 0x10>; + }; + + eth_mac: eth_mac@34 { + reg = <0x34 0x10>; + }; + + bid: bid@46 { + reg = <0x46 0x30>; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +For example: + + eth_mac { + ... + nvmem-cells = <ð_mac>; + nvmem-cell-names = "eth_mac"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/amlogic-meson-mx-efuse.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/amlogic-meson-mx-efuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3c63954a1a4e7dc66fd09373e8af6e13469ef5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/amlogic-meson-mx-efuse.txt @@ -0,0 +1,22 @@ +Amlogic Meson6/Meson8/Meson8b efuse + +Required Properties: +- compatible: depending on the SoC this should be one of: + - "amlogic,meson6-efuse" + - "amlogic,meson8-efuse" + - "amlogic,meson8b-efuse" +- reg: base address and size of the efuse registers +- clocks: a reference to the efuse core gate clock +- clock-names: must be "core" + +All properties and sub-nodes as well as the consumer bindings +defined in nvmem.txt in this directory are also supported. + + +Example: + efuse: nvmem@0 { + compatible = "amlogic,meson8-efuse"; + reg = <0x0 0x2000>; + clocks = <&clkc CLKID_EFUSE>; + clock-names = "core"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/brcm,ocotp.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/brcm,ocotp.txt new file mode 100644 index 0000000000000000000000000000000000000000..0415265c215a6480cc5e9389183783f36b2220c6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/brcm,ocotp.txt @@ -0,0 +1,17 @@ +Broadcom OTP memory controller + +Required Properties: +- compatible: "brcm,ocotp" for the first generation Broadcom OTPC which is used + in Cygnus and supports 32 bit read/write. Use "brcm,ocotp-v2" for the second + generation Broadcom OTPC which is used in SoC's such as Stingray and supports + 64-bit read/write. +- reg: Base address of the OTP controller. +- brcm,ocotp-size: Amount of memory available, in 32 bit words + +Example: + +otp: otp@301c800 { + compatible = "brcm,ocotp"; + reg = <0x0301c800 0x2c>; + brcm,ocotp-size = <2048>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/imx-iim.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/imx-iim.txt new file mode 100644 index 0000000000000000000000000000000000000000..1978c5bcd96d1ff6f6c83520e9ad536349112b07 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/imx-iim.txt @@ -0,0 +1,22 @@ +Freescale i.MX IC Identification Module (IIM) device tree bindings + +This binding represents the IC Identification Module (IIM) found on +i.MX25, i.MX27, i.MX31, i.MX35, i.MX51 and i.MX53 SoCs. + +Required properties: +- compatible: should be one of + "fsl,imx25-iim", "fsl,imx27-iim", + "fsl,imx31-iim", "fsl,imx35-iim", + "fsl,imx51-iim", "fsl,imx53-iim", +- reg: Should contain the register base and length. +- interrupts: Should contain the interrupt for the IIM +- clocks: Should contain a phandle pointing to the gated peripheral clock. + +Example: + + iim: iim@63f98000 { + compatible = "fsl,imx53-iim", "fsl,imx27-iim"; + reg = <0x63f98000 0x4000>; + interrupts = <69>; + clocks = <&clks IMX5_CLK_IIM_GATE>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/imx-ocotp.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/imx-ocotp.txt new file mode 100644 index 0000000000000000000000000000000000000000..792bc5fafeb9630473d84fcd3b1b121672eba6d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/imx-ocotp.txt @@ -0,0 +1,43 @@ +Freescale i.MX6 On-Chip OTP Controller (OCOTP) device tree bindings + +This binding represents the on-chip eFuse OTP controller found on +i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL and i.MX6SLL SoCs. + +Required properties: +- compatible: should be one of + "fsl,imx6q-ocotp" (i.MX6Q/D/DL/S), + "fsl,imx6sl-ocotp" (i.MX6SL), or + "fsl,imx6sx-ocotp" (i.MX6SX), + "fsl,imx6ul-ocotp" (i.MX6UL), + "fsl,imx7d-ocotp" (i.MX7D/S), + "fsl,imx6sll-ocotp" (i.MX6SLL), + followed by "syscon". +- #address-cells : Should be 1 +- #size-cells : Should be 1 +- reg: Should contain the register base and length. +- clocks: Should contain a phandle pointing to the gated peripheral clock. + +Optional properties: +- read-only: disable write access + +Optional Child nodes: + +- Data cells of ocotp: + Detailed bindings are described in bindings/nvmem/nvmem.txt + +Example: + ocotp: ocotp@21bc000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,imx6sx-ocotp", "syscon"; + reg = <0x021bc000 0x4000>; + clocks = <&clks IMX6SX_CLK_OCOTP>; + + tempmon_calib: calib@38 { + reg = <0x38 4>; + }; + + tempmon_temp_grade: temp-grade@20 { + reg = <0x20 4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/lpc1850-otp.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/lpc1850-otp.txt new file mode 100644 index 0000000000000000000000000000000000000000..853b6a75464453e6959b906f9b160b48201cd70f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/lpc1850-otp.txt @@ -0,0 +1,20 @@ +* NXP LPC18xx OTP memory + +Internal OTP (One Time Programmable) memory for NXP LPC18xx/43xx devices. + +Required properties: + - compatible: Should be "nxp,lpc1850-otp" + - reg: Must contain an entry with the physical base address and length + for each entry in reg-names. + - address-cells: must be set to 1. + - size-cells: must be set to 1. + +See nvmem.txt for more information. + +Example: + otp: otp@40045000 { + compatible = "nxp,lpc1850-otp"; + reg = <0x40045000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/lpc1857-eeprom.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/lpc1857-eeprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..809df68f6e1482a3c8966c5dd92ef18cb73f66fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/lpc1857-eeprom.txt @@ -0,0 +1,28 @@ +* NXP LPC18xx EEPROM memory NVMEM driver + +Required properties: + - compatible: Should be "nxp,lpc1857-eeprom" + - reg: Must contain an entry with the physical base address and length + for each entry in reg-names. + - reg-names: Must include the following entries. + - reg: EEPROM registers. + - mem: EEPROM address space. + - clocks: Must contain an entry for each entry in clock-names. + - clock-names: Must include the following entries. + - eeprom: EEPROM operating clock. + - resets: Should contain a reference to the reset controller asserting + the EEPROM in reset. + - interrupts: Should contain EEPROM interrupt. + +Example: + + eeprom: eeprom@4000e000 { + compatible = "nxp,lpc1857-eeprom"; + reg = <0x4000e000 0x1000>, + <0x20040000 0x4000>; + reg-names = "reg", "mem"; + clocks = <&ccu1 CLK_CPU_EEPROM>; + clock-names = "eeprom"; + resets = <&rgu 27>; + interrupts = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/mtk-efuse.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/mtk-efuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..0668c45a156d3324fa41f920870b72057fb9567c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/mtk-efuse.txt @@ -0,0 +1,39 @@ += Mediatek MTK-EFUSE device tree bindings = + +This binding is intended to represent MTK-EFUSE which is found in most Mediatek SOCs. + +Required properties: +- compatible: should be + "mediatek,mt7622-efuse", "mediatek,efuse": for MT7622 + "mediatek,mt7623-efuse", "mediatek,efuse": for MT7623 + "mediatek,mt8173-efuse" or "mediatek,efuse": for MT8173 +- reg: Should contain registers location and length + += Data cells = +Are child nodes of MTK-EFUSE, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + efuse: efuse@10206000 { + compatible = "mediatek,mt8173-efuse"; + reg = <0 0x10206000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + /* Data cells */ + thermal_calibration: calib@528 { + reg = <0x528 0xc>; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +For example: + + thermal { + ... + nvmem-cells = <&thermal_calibration>; + nvmem-cell-names = "calibration"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/mxs-ocotp.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/mxs-ocotp.txt new file mode 100644 index 0000000000000000000000000000000000000000..372c72fd64dcdf70b258f41993400e55e44fd65c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/mxs-ocotp.txt @@ -0,0 +1,24 @@ +On-Chip OTP Memory for Freescale i.MX23/i.MX28 + +Required properties : +- compatible : + - "fsl,imx23-ocotp" for i.MX23 + - "fsl,imx28-ocotp" for i.MX28 +- #address-cells : Should be 1 +- #size-cells : Should be 1 +- reg : Address and length of OTP controller registers +- clocks : Should contain a reference to the hbus clock + += Data cells = +Are child nodes of mxs-ocotp, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example for i.MX28: + + ocotp: ocotp@8002c000 { + compatible = "fsl,imx28-ocotp", "fsl,ocotp"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x8002c000 0x2000>; + clocks = <&clks 25>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/nvmem.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/nvmem.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd06c09b822b91b6aa0184d699df9b682884dc1f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/nvmem.txt @@ -0,0 +1,80 @@ += NVMEM(Non Volatile Memory) Data Device Tree Bindings = + +This binding is intended to represent the location of hardware +configuration data stored in NVMEMs like eeprom, efuses and so on. + +On a significant proportion of boards, the manufacturer has stored +some data on NVMEM, for the OS to be able to retrieve these information +and act upon it. Obviously, the OS has to know about where to retrieve +these data from, and where they are stored on the storage device. + +This document is here to document this. + += Data providers = +Contains bindings specific to provider drivers and data cells as children +of this node. + +Optional properties: + read-only: Mark the provider as read only. + += Data cells = +These are the child nodes of the provider which contain data cell +information like offset and size in nvmem provider. + +Required properties: +reg: specifies the offset in byte within the storage device. + +Optional properties: + +bits: Is pair of bit location and number of bits, which specifies offset + in bit and number of bits within the address range specified by reg property. + Offset takes values from 0-7. + +For example: + + /* Provider */ + qfprom: qfprom@700000 { + ... + + /* Data cells */ + tsens_calibration: calib@404 { + reg = <0x404 0x10>; + }; + + tsens_calibration_bckp: calib_bckp@504 { + reg = <0x504 0x11>; + bits = <6 128> + }; + + pvs_version: pvs-version@6 { + reg = <0x6 0x2> + bits = <7 2> + }; + + speed_bin: speed-bin@c{ + reg = <0xc 0x1>; + bits = <2 3>; + + }; + ... + }; + += Data consumers = +Are device nodes which consume nvmem data cells/providers. + +Required-properties: +nvmem-cells: list of phandle to the nvmem data cells. +nvmem-cell-names: names for the each nvmem-cells specified. Required if + nvmem-cells is used. + +Optional-properties: +nvmem : list of phandles to nvmem providers. +nvmem-names: names for the each nvmem provider. required if nvmem is used. + +For example: + + tsens { + ... + nvmem-cells = <&tsens_calibration>; + nvmem-cell-names = "calibration"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/qcom-spmi-sdam.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/qcom-spmi-sdam.txt new file mode 100644 index 0000000000000000000000000000000000000000..b849a22e2c20b1024bb41a5385f45dd777028a1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/qcom-spmi-sdam.txt @@ -0,0 +1,49 @@ +Qualcomm Technologies, Inc. Shared Direct Access Memory (SDAM) + +The SDAM provides scratch register space for the PMIC clients. +This memory can be used by software to store information or communicate +to/from the PBUS. + +Below are the DT bindings for this module + +Supported properties: + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,spmi-sdam" + +- reg + Usage: required + Value type: + Definition: The base address and size of the sdam peripheral. + +- Data cells + Usage: required + Value type: Subnodes with bindings described in bindings/nvmem/nvmem.txt. + Definition: Cells defining the shared memory usage and configuration. + +Example: + + sdam_1: sdam@b000 { + compatible = "qcom,spmi-sdam"; + reg = <0xb000 0x100>; + + .... + /* Data cells */ + restart_reason: restart@50 { + reg = <0x50 0x1>; + bits = <7 2>; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +Example: + + { + ... + nvmem-cells = <&restart_reason>; + nvmem-cell-names = "pmic_restart_reason"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/qfprom.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/qfprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..26fe878d5c8688da2c86d8eb5c61b7c55ba7a815 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/qfprom.txt @@ -0,0 +1,35 @@ += Qualcomm QFPROM device tree bindings = + +This binding is intended to represent QFPROM which is found in most QCOM SOCs. + +Required properties: +- compatible: should be "qcom,qfprom" +- reg: Should contain registers location and length + += Data cells = +Are child nodes of qfprom, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + qfprom: qfprom@700000 { + compatible = "qcom,qfprom"; + reg = <0x00700000 0x8000>; + ... + /* Data cells */ + tsens_calibration: calib@404 { + reg = <0x4404 0x10>; + }; + }; + + += Data consumers = +Are device nodes which consume nvmem data cells. + +For example: + + tsens { + ... + nvmem-cells = <&tsens_calibration>; + nvmem-cell-names = "calibration"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/rockchip-efuse.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/rockchip-efuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..265bdb7dc8aa524fc75383ee01512b2eabcf5dd0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/rockchip-efuse.txt @@ -0,0 +1,54 @@ += Rockchip eFuse device tree bindings = + +Required properties: +- compatible: Should be one of the following. + - "rockchip,rk3066a-efuse" - for RK3066a SoCs. + - "rockchip,rk3188-efuse" - for RK3188 SoCs. + - "rockchip,rk3228-efuse" - for RK3228 SoCs. + - "rockchip,rk3288-efuse" - for RK3288 SoCs. + - "rockchip,rk3328-efuse" - for RK3328 SoCs. + - "rockchip,rk3368-efuse" - for RK3368 SoCs. + - "rockchip,rk3399-efuse" - for RK3399 SoCs. +- reg: Should contain the registers location and exact eFuse size +- clocks: Should be the clock id of eFuse +- clock-names: Should be "pclk_efuse" + +Optional properties: +- rockchip,efuse-size: Should be exact eFuse size in byte, the eFuse + size in property will be invalid if define this property. + +Deprecated properties: +- compatible: "rockchip,rockchip-efuse" + Old efuse compatible value compatible to rk3066a, rk3188 and rk3288 + efuses + += Data cells = +Are child nodes of eFuse, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + efuse: efuse@ffb40000 { + compatible = "rockchip,rk3288-efuse"; + reg = <0xffb40000 0x20>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&cru PCLK_EFUSE256>; + clock-names = "pclk_efuse"; + + /* Data cells */ + cpu_leakage: cpu_leakage { + reg = <0x17 0x1>; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +Example: + + cpu_leakage { + ... + nvmem-cells = <&cpu_leakage>; + nvmem-cell-names = "cpu_leakage"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/sc27xx-efuse.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/sc27xx-efuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..586c08286aa9afeb7f1a882ddf85942b39860bac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/sc27xx-efuse.txt @@ -0,0 +1,52 @@ += Spreadtrum SC27XX PMIC eFuse device tree bindings = + +Required properties: +- compatible: Should be one of the following. + "sprd,sc2720-efuse" + "sprd,sc2721-efuse" + "sprd,sc2723-efuse" + "sprd,sc2730-efuse" + "sprd,sc2731-efuse" +- reg: Specify the address offset of efuse controller. +- hwlocks: Reference to a phandle of a hwlock provider node. + += Data cells = +Are child nodes of eFuse, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + efuse@380 { + compatible = "sprd,sc2731-efuse"; + reg = <0x380>; + #address-cells = <1>; + #size-cells = <1>; + hwlocks = <&hwlock 12>; + + /* Data cells */ + thermal_calib: calib@10 { + reg = <0x10 0x2>; + }; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +Example: + + thermal { + ... + nvmem-cells = <&thermal_calib>; + nvmem-cell-names = "calibration"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/snvs-lpgpr.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/snvs-lpgpr.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cb170896658699e8fd89deb4bca0bd5d0065297 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/snvs-lpgpr.txt @@ -0,0 +1,21 @@ +Device tree bindings for Low Power General Purpose Register found in i.MX6Q/D +and i.MX7 Secure Non-Volatile Storage. + +This DT node should be represented as a sub-node of a "syscon", +"simple-mfd" node. + +Required properties: +- compatible: should be one of the fallowing variants: + "fsl,imx6q-snvs-lpgpr" for Freescale i.MX6Q/D/DL/S + "fsl,imx6ul-snvs-lpgpr" for Freescale i.MX6UL + "fsl,imx7d-snvs-lpgpr" for Freescale i.MX7D/S + +Example: +snvs: snvs@020cc000 { + compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd"; + reg = <0x020cc000 0x4000>; + + snvs_lpgpr: snvs-lpgpr { + compatible = "fsl,imx6q-snvs-lpgpr"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/uniphier-efuse.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/uniphier-efuse.txt new file mode 100644 index 0000000000000000000000000000000000000000..eccf490d5a6d5dbeec7a78ae23db5ea088f1818c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/uniphier-efuse.txt @@ -0,0 +1,49 @@ += UniPhier eFuse device tree bindings = + +This UniPhier eFuse must be under soc-glue. + +Required properties: +- compatible: should be "socionext,uniphier-efuse" +- reg: should contain the register location and length + += Data cells = +Are child nodes of efuse, bindings of which as described in +bindings/nvmem/nvmem.txt + +Example: + + soc-glue@5f900000 { + compatible = "socionext,uniphier-ld20-soc-glue-debug", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x5f900000 0x2000>; + + efuse@100 { + compatible = "socionext,uniphier-efuse"; + reg = <0x100 0x28>; + }; + + efuse@200 { + compatible = "socionext,uniphier-efuse"; + reg = <0x200 0x68>; + #address-cells = <1>; + #size-cells = <1>; + + /* Data cells */ + usb_mon: usb-mon@54 { + reg = <0x54 0xc>; + }; + }; + }; + += Data consumers = +Are device nodes which consume nvmem data cells. + +Example: + + usb { + ... + nvmem-cells = <&usb_mon>; + nvmem-cell-names = "usb_mon"; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/vf610-ocotp.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/vf610-ocotp.txt new file mode 100644 index 0000000000000000000000000000000000000000..56ed481c3e2626c78660e54c5b4c2077a564b55c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/vf610-ocotp.txt @@ -0,0 +1,19 @@ +On-Chip OTP Memory for Freescale Vybrid + +Required Properties: + compatible: + - "fsl,vf610-ocotp" for VF5xx/VF6xx + #address-cells : Should be 1 + #size-cells : Should be 1 + reg : Address and length of OTP controller and fuse map registers + clocks : ipg clock we associate with the OCOTP peripheral + +Example for Vybrid VF5xx/VF6xx: + + ocotp: ocotp@400a5000 { + compatible = "fsl,vf610-ocotp"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x400a5000 0xCF0>; + clocks = <&clks VF610_CLK_OCOTP>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/nvmem/zii,rave-sp-eeprom.txt b/arch/arm64/boot/dts/vendor/bindings/nvmem/zii,rave-sp-eeprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..0df79d9e07ec22f50ef7c6641afea3ba6c311aa0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/nvmem/zii,rave-sp-eeprom.txt @@ -0,0 +1,40 @@ +Zodiac Inflight Innovations RAVE EEPROM Bindings + +RAVE SP EEPROM device is a "MFD cell" device exposing physical EEPROM +attached to RAVE Supervisory Processor. It is expected that its Device +Tree node is specified as a child of the node corresponding to the +parent RAVE SP device (as documented in +Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) + +Required properties: + +- compatible: Should be "zii,rave-sp-eeprom" + +Optional properties: + +- zii,eeprom-name: Unique EEPROM identifier describing its function in the + system. Will be used as created NVMEM deivce's name. + +Data cells: + +Data cells are child nodes of eerpom node, bindings for which are +documented in Documentation/devicetree/bindings/nvmem/nvmem.txt + +Example: + + rave-sp { + compatible = "zii,rave-sp-rdu1"; + current-speed = <38400>; + + eeprom@a4 { + compatible = "zii,rave-sp-eeprom"; + reg = <0xa4 0x4000>; + #address-cells = <1>; + #size-cells = <1>; + zii,eeprom-name = "main-eeprom"; + + wdt_timeout: wdt-timeout@81 { + reg = <0x81 2>; + }; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/openrisc/opencores/or1ksim.txt b/arch/arm64/boot/dts/vendor/bindings/openrisc/opencores/or1ksim.txt new file mode 100644 index 0000000000000000000000000000000000000000..4950c794ecbb5fea57cb39ed4de4898798c305c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/openrisc/opencores/or1ksim.txt @@ -0,0 +1,39 @@ +OpenRISC Generic SoC +==================== + +Boards and FPGA SoC's which support the OpenRISC standard platform. The +platform essentially follows the conventions of the OpenRISC architecture +specification, however some aspects, such as the boot protocol have been defined +by the Linux port. + +Required properties +------------------- + - compatible: Must include "opencores,or1ksim" + +CPU nodes: +---------- +A "cpus" node is required. Required properties: + - #address-cells: Must be 1. + - #size-cells: Must be 0. +A CPU sub-node is also required for at least CPU 0. Since the topology may +be probed via CPS, it is not necessary to specify secondary CPUs. Required +properties: + - compatible: Must be "opencores,or1200-rtlsvn481". + - reg: CPU number. + - clock-frequency: The CPU clock frequency in Hz. +Example: + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + compatible = "opencores,or1200-rtlsvn481"; + reg = <0>; + clock-frequency = <20000000>; + }; + }; + + +Boot protocol +------------- +The bootloader may pass the following arguments to the kernel: + - r3: address of a flattened device-tree blob or 0x0. diff --git a/arch/arm64/boot/dts/vendor/bindings/opp/kryo-cpufreq.txt b/arch/arm64/boot/dts/vendor/bindings/opp/kryo-cpufreq.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2127b96805a3e7b3c723fbb432bbcebaacbd545 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/opp/kryo-cpufreq.txt @@ -0,0 +1,680 @@ +Qualcomm Technologies, Inc. KRYO CPUFreq and OPP bindings +=================================== + +In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996 +that have KRYO processors, the CPU ferequencies subset and voltage value +of each OPP varies based on the silicon variant in use. +Qualcomm Technologies, Inc. Process Voltage Scaling Tables +defines the voltage and frequency value based on the msm-id in SMEM +and speedbin blown in the efuse combination. +The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC +to provide the OPP framework with required information (existing HW bitmap). +This is used to determine the voltage and frequency value for each OPP of +operating-points-v2 table when it is parsed by the OPP framework. + +Required properties: +-------------------- +In 'cpus' nodes: +- operating-points-v2: Phandle to the operating-points-v2 table to use. + +In 'operating-points-v2' table: +- compatible: Should be + - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996. +- nvmem-cells: A phandle pointing to a nvmem-cells node representing the + efuse registers that has information about the + speedbin that is used to select the right frequency/voltage + value pair. + Please refer the for nvmem-cells + bindings Documentation/devicetree/bindings/nvmem/nvmem.txt + and also examples below. + +In every OPP node: +- opp-supported-hw: A single 32 bit bitmap value, representing compatible HW. + Bitmap: + 0: MSM8996 V3, speedbin 0 + 1: MSM8996 V3, speedbin 1 + 2: MSM8996 V3, speedbin 2 + 3: unused + 4: MSM8996 SG, speedbin 0 + 5: MSM8996 SG, speedbin 1 + 6: MSM8996 SG, speedbin 2 + 7-31: unused + +Example 1: +--------- + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x0>; + enable-method = "psci"; + clocks = <&kryocc 0>; + cpu-supply = <&pm8994_s11_saw>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; + next-level-cache = <&L2_0>; + L2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x1>; + enable-method = "psci"; + clocks = <&kryocc 0>; + cpu-supply = <&pm8994_s11_saw>; + operating-points-v2 = <&cluster0_opp>; + #cooling-cells = <2>; + next-level-cache = <&L2_0>; + }; + + CPU2: cpu@100 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x100>; + enable-method = "psci"; + clocks = <&kryocc 1>; + cpu-supply = <&pm8994_s11_saw>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; + next-level-cache = <&L2_1>; + L2_1: l2-cache { + compatible = "cache"; + cache-level = <2>; + }; + }; + + CPU3: cpu@101 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x101>; + enable-method = "psci"; + clocks = <&kryocc 1>; + cpu-supply = <&pm8994_s11_saw>; + operating-points-v2 = <&cluster1_opp>; + #cooling-cells = <2>; + next-level-cache = <&L2_1>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU2>; + }; + + core1 { + cpu = <&CPU3>; + }; + }; + }; + }; + + cluster0_opp: opp_table0 { + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&speedbin_efuse>; + opp-shared; + + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-422400000 { + opp-hz = /bits/ 64 <422400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-460800000 { + opp-hz = /bits/ 64 <460800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-537600000 { + opp-hz = /bits/ 64 <537600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-556800000 { + opp-hz = /bits/ 64 <556800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-614400000 { + opp-hz = /bits/ 64 <614400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-652800000 { + opp-hz = /bits/ 64 <652800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-691200000 { + opp-hz = /bits/ 64 <691200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-729600000 { + opp-hz = /bits/ 64 <729600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-768000000 { + opp-hz = /bits/ 64 <768000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-844800000 { + opp-hz = /bits/ 64 <844800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-902400000 { + opp-hz = /bits/ 64 <902400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-960000000 { + opp-hz = /bits/ 64 <960000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-979200000 { + opp-hz = /bits/ 64 <979200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1036800000 { + opp-hz = /bits/ 64 <1036800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1056000000 { + opp-hz = /bits/ 64 <1056000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1113600000 { + opp-hz = /bits/ 64 <1113600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1132800000 { + opp-hz = /bits/ 64 <1132800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1190400000 { + opp-hz = /bits/ 64 <1190400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1209600000 { + opp-hz = /bits/ 64 <1209600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1228800000 { + opp-hz = /bits/ 64 <1228800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1286400000 { + opp-hz = /bits/ 64 <1286400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1324800000 { + opp-hz = /bits/ 64 <1324800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x5>; + clock-latency-ns = <200000>; + }; + opp-1363200000 { + opp-hz = /bits/ 64 <1363200000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x72>; + clock-latency-ns = <200000>; + }; + opp-1401600000 { + opp-hz = /bits/ 64 <1401600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x5>; + clock-latency-ns = <200000>; + }; + opp-1440000000 { + opp-hz = /bits/ 64 <1440000000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1478400000 { + opp-hz = /bits/ 64 <1478400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <200000>; + }; + opp-1497600000 { + opp-hz = /bits/ 64 <1497600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x4>; + clock-latency-ns = <200000>; + }; + opp-1516800000 { + opp-hz = /bits/ 64 <1516800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1593600000 { + opp-hz = /bits/ 64 <1593600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x71>; + clock-latency-ns = <200000>; + }; + opp-1996800000 { + opp-hz = /bits/ 64 <1996800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x20>; + clock-latency-ns = <200000>; + }; + opp-2188800000 { + opp-hz = /bits/ 64 <2188800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x10>; + clock-latency-ns = <200000>; + }; + }; + + cluster1_opp: opp_table1 { + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&speedbin_efuse>; + opp-shared; + + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x77>; + clock-latency-ns = <200000>; + }; + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-403200000 { + opp-hz = /bits/ 64 <403200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-460800000 { + opp-hz = /bits/ 64 <460800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-537600000 { + opp-hz = /bits/ 64 <537600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-556800000 { + opp-hz = /bits/ 64 <556800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-614400000 { + opp-hz = /bits/ 64 <614400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-652800000 { + opp-hz = /bits/ 64 <652800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-691200000 { + opp-hz = /bits/ 64 <691200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-729600000 { + opp-hz = /bits/ 64 <729600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-748800000 { + opp-hz = /bits/ 64 <748800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-806400000 { + opp-hz = /bits/ 64 <806400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-825600000 { + opp-hz = /bits/ 64 <825600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-883200000 { + opp-hz = /bits/ 64 <883200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-902400000 { + opp-hz = /bits/ 64 <902400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-940800000 { + opp-hz = /bits/ 64 <940800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-979200000 { + opp-hz = /bits/ 64 <979200000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1036800000 { + opp-hz = /bits/ 64 <1036800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1056000000 { + opp-hz = /bits/ 64 <1056000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1113600000 { + opp-hz = /bits/ 64 <1113600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1132800000 { + opp-hz = /bits/ 64 <1132800000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1190400000 { + opp-hz = /bits/ 64 <1190400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1209600000 { + opp-hz = /bits/ 64 <1209600000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1248000000 { + opp-hz = /bits/ 64 <1248000000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1286400000 { + opp-hz = /bits/ 64 <1286400000>; + opp-microvolt = <905000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1324800000 { + opp-hz = /bits/ 64 <1324800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1363200000 { + opp-hz = /bits/ 64 <1363200000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1401600000 { + opp-hz = /bits/ 64 <1401600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1440000000 { + opp-hz = /bits/ 64 <1440000000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1478400000 { + opp-hz = /bits/ 64 <1478400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1516800000 { + opp-hz = /bits/ 64 <1516800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1555200000 { + opp-hz = /bits/ 64 <1555200000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1593600000 { + opp-hz = /bits/ 64 <1593600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1632000000 { + opp-hz = /bits/ 64 <1632000000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1670400000 { + opp-hz = /bits/ 64 <1670400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1708800000 { + opp-hz = /bits/ 64 <1708800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1747200000 { + opp-hz = /bits/ 64 <1747200000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x70>; + clock-latency-ns = <200000>; + }; + opp-1785600000 { + opp-hz = /bits/ 64 <1785600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + opp-1804800000 { + opp-hz = /bits/ 64 <1804800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x6>; + clock-latency-ns = <200000>; + }; + opp-1824000000 { + opp-hz = /bits/ 64 <1824000000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x71>; + clock-latency-ns = <200000>; + }; + opp-1900800000 { + opp-hz = /bits/ 64 <1900800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x74>; + clock-latency-ns = <200000>; + }; + opp-1920000000 { + opp-hz = /bits/ 64 <1920000000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <200000>; + }; + opp-1977600000 { + opp-hz = /bits/ 64 <1977600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x30>; + clock-latency-ns = <200000>; + }; + opp-1996800000 { + opp-hz = /bits/ 64 <1996800000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <200000>; + }; + opp-2054400000 { + opp-hz = /bits/ 64 <2054400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x30>; + clock-latency-ns = <200000>; + }; + opp-2073600000 { + opp-hz = /bits/ 64 <2073600000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x1>; + clock-latency-ns = <200000>; + }; + opp-2150400000 { + opp-hz = /bits/ 64 <2150400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x31>; + clock-latency-ns = <200000>; + }; + opp-2246400000 { + opp-hz = /bits/ 64 <2246400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x10>; + clock-latency-ns = <200000>; + }; + opp-2342400000 { + opp-hz = /bits/ 64 <2342400000>; + opp-microvolt = <1140000 905000 1140000>; + opp-supported-hw = <0x10>; + clock-latency-ns = <200000>; + }; + }; + +.... + +reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; +.... + smem_mem: smem-mem@86000000 { + reg = <0x0 0x86000000 0x0 0x200000>; + no-map; + }; +.... +}; + +smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; +}; + +soc { +.... + qfprom: qfprom@74000 { + compatible = "qcom,qfprom"; + reg = <0x00074000 0x8ff>; + #address-cells = <1>; + #size-cells = <1>; + .... + speedbin_efuse: speedbin@133 { + reg = <0x133 0x1>; + bits = <5 3>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/opp/opp.txt b/arch/arm64/boot/dts/vendor/bindings/opp/opp.txt new file mode 100644 index 0000000000000000000000000000000000000000..c396c4c0af92db1faa8d0f7ee7fe44b6a7fac242 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/opp/opp.txt @@ -0,0 +1,545 @@ +Generic OPP (Operating Performance Points) Bindings +---------------------------------------------------- + +Devices work at voltage-current-frequency combinations and some implementations +have the liberty of choosing these. These combinations are called Operating +Performance Points aka OPPs. This document defines bindings for these OPPs +applicable across wide range of devices. For illustration purpose, this document +uses CPU as a device. + +This document contain multiple versions of OPP binding and only one of them +should be used per device. + +Binding 1: operating-points +============================ + +This binding only supports voltage-frequency pairs. + +Properties: +- operating-points: An array of 2-tuples items, and each item consists + of frequency and voltage like . + freq: clock frequency in kHz + vol: voltage in microvolt + +Examples: + +cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + operating-points = < + /* kHz uV */ + 792000 1100000 + 396000 950000 + 198000 850000 + >; +}; + + +Binding 2: operating-points-v2 +============================ + +* Property: operating-points-v2 + +Devices supporting OPPs must set their "operating-points-v2" property with +phandle to a OPP table in their DT node. The OPP core will use this phandle to +find the operating points for the device. + +This can contain more than one phandle for power domain providers that provide +multiple power domains. That is, one phandle for each power domain. If only one +phandle is available, then the same OPP table will be used for all power domains +provided by the power domain provider. + +If required, this can be extended for SoC vendor specific bindings. Such bindings +should be documented as Documentation/devicetree/bindings/power/-opp.txt +and should have a compatible description like: "operating-points-v2-". + +* OPP Table Node + +This describes the OPPs belonging to a device. This node can have following +properties: + +Required properties: +- compatible: Allow OPPs to express their compatibility. It should be: + "operating-points-v2". + +- OPP nodes: One or more OPP nodes describing voltage-current-frequency + combinations. Their name isn't significant but their phandle can be used to + reference an OPP. + +Optional properties: +- opp-shared: Indicates that device nodes using this OPP Table Node's phandle + switch their DVFS state together, i.e. they share clock/voltage/current lines. + Missing property means devices have independent clock/voltage/current lines, + but they share OPP tables. + +- status: Marks the OPP table enabled/disabled. + + +* OPP Node + +This defines voltage-current-frequency combinations along with other related +properties. + +Required properties: +- opp-hz: Frequency in Hz, expressed as a 64-bit big-endian integer. This is a + required property for all device nodes but devices like power domains. The + power domain nodes must have another (implementation dependent) property which + uniquely identifies the OPP nodes. + +Optional properties: +- opp-microvolt: voltage in micro Volts. + + A single regulator's voltage is specified with an array of size one or three. + Single entry is for target voltage and three entries are for + voltages. + + Entries for multiple regulators shall be provided in the same field separated + by angular brackets <>. The OPP binding doesn't provide any provisions to + relate the values to their power supplies or the order in which the supplies + need to be configured and that is left for the implementation specific + binding. + + Entries for all regulators shall be of the same size, i.e. either all use a + single value or triplets. + +- opp-microvolt-: Named opp-microvolt property. This is exactly similar to + the above opp-microvolt property, but allows multiple voltage ranges to be + provided for the same OPP. At runtime, the platform can pick a and + matching opp-microvolt- property will be enabled for all OPPs. If the + platform doesn't pick a specific or the doesn't match with any + opp-microvolt- properties, then opp-microvolt property shall be used, if + present. + +- opp-microamp: The maximum current drawn by the device in microamperes + considering system specific parameters (such as transients, process, aging, + maximum operating temperature range etc.) as necessary. This may be used to + set the most efficient regulator operating mode. + + Should only be set if opp-microvolt is set for the OPP. + + Entries for multiple regulators shall be provided in the same field separated + by angular brackets <>. If current values aren't required for a regulator, + then it shall be filled with 0. If current values aren't required for any of + the regulators, then this field is not required. The OPP binding doesn't + provide any provisions to relate the values to their power supplies or the + order in which the supplies need to be configured and that is left for the + implementation specific binding. + +- opp-microamp-: Named opp-microamp property. Similar to + opp-microvolt- property, but for microamp instead. + +- clock-latency-ns: Specifies the maximum possible transition latency (in + nanoseconds) for switching to this OPP from any other OPP. + +- turbo-mode: Marks the OPP to be used only for turbo modes. Turbo mode is + available on some platforms, where the device can run over its operating + frequency for a short duration of time limited by the device's power, current + and thermal limits. + +- opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in + the table should have this. + +- opp-supported-hw: This enables us to select only a subset of OPPs from the + larger OPP table, based on what version of the hardware we are running on. We + still can't have multiple nodes with the same opp-hz value in OPP table. + + It's a user defined array containing a hierarchy of hardware version numbers, + supported by the OPP. For example: a platform with hierarchy of three levels + of versions (A, B and C), this field should be like , where X + corresponds to Version hierarchy A, Y corresponds to version hierarchy B and Z + corresponds to version hierarchy C. + + Each level of hierarchy is represented by a 32 bit value, and so there can be + only 32 different supported version per hierarchy. i.e. 1 bit per version. A + value of 0xFFFFFFFF will enable the OPP for all versions for that hierarchy + level. And a value of 0x00000000 will disable the OPP completely, and so we + never want that to happen. + + If 32 values aren't sufficient for a version hierarchy, than that version + hierarchy can be contained in multiple 32 bit values. i.e. in the + above example, Z1 & Z2 refer to the version hierarchy Z. + +- status: Marks the node enabled/disabled. + +- required-opps: This contains phandle to an OPP node in another device's OPP + table. It may contain an array of phandles, where each phandle points to an + OPP of a different device. It should not contain multiple phandles to the OPP + nodes in the same OPP table. This specifies the minimum required OPP of the + device(s), whose OPP's phandle is present in this property, for the + functioning of the current device at the current OPP (where this property is + present). + +Example 1: Single cluster Dual-core ARM cortex A9, switch DVFS states together. + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu0_opp_table>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + clock-latency-ns = <290000>; + turbo-mode; + }; + }; +}; + +Example 2: Single cluster, Quad-core Qualcom-krait, switches DVFS states +independently. + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "qcom,krait"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@1 { + compatible = "qcom,krait"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@2 { + compatible = "qcom,krait"; + reg = <2>; + next-level-cache = <&L2>; + clocks = <&clk_controller 2>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply2>; + operating-points-v2 = <&cpu_opp_table>; + }; + + cpu@3 { + compatible = "qcom,krait"; + reg = <3>; + next-level-cache = <&L2>; + clocks = <&clk_controller 3>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply3>; + operating-points-v2 = <&cpu_opp_table>; + }; + }; + + cpu_opp_table: opp_table { + compatible = "operating-points-v2"; + + /* + * Missing opp-shared property means CPUs switch DVFS states + * independently. + */ + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + opp-microamp = <90000; + lock-latency-ns = <290000>; + turbo-mode; + }; + }; +}; + +Example 3: Dual-cluster, Dual-core per cluster. CPUs within a cluster switch +DVFS state together. + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a7"; + reg = <0>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cluster0_opp>; + }; + + cpu@1 { + compatible = "arm,cortex-a7"; + reg = <1>; + next-level-cache = <&L2>; + clocks = <&clk_controller 0>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply0>; + operating-points-v2 = <&cluster0_opp>; + }; + + cpu@100 { + compatible = "arm,cortex-a15"; + reg = <100>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cluster1_opp>; + }; + + cpu@101 { + compatible = "arm,cortex-a15"; + reg = <101>; + next-level-cache = <&L2>; + clocks = <&clk_controller 1>; + clock-names = "cpu"; + cpu-supply = <&cpu_supply1>; + operating-points-v2 = <&cluster1_opp>; + }; + }; + + cluster0_opp: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + opp-microamp = <70000>; + clock-latency-ns = <300000>; + opp-suspend; + }; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + opp-microamp = <80000>; + clock-latency-ns = <310000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <1025000>; + opp-microamp = <90000>; + clock-latency-ns = <290000>; + turbo-mode; + }; + }; + + cluster1_opp: opp_table1 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1300000000 { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1050000 1045000 1055000>; + opp-microamp = <95000>; + clock-latency-ns = <400000>; + opp-suspend; + }; + opp-1400000000 { + opp-hz = /bits/ 64 <1400000000>; + opp-microvolt = <1075000>; + opp-microamp = <100000>; + clock-latency-ns = <400000>; + }; + opp-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1100000 1010000 1110000>; + opp-microamp = <95000>; + clock-latency-ns = <400000>; + turbo-mode; + }; + }; +}; + +Example 4: Handling multiple regulators + +/ { + cpus { + cpu@0 { + compatible = "vendor,cpu-type"; + ... + + vcc0-supply = <&cpu_supply0>; + vcc1-supply = <&cpu_supply1>; + vcc2-supply = <&cpu_supply2>; + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <970000>, /* Supply 0 */ + <960000>, /* Supply 1 */ + <960000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <70000>, /* Supply 1 */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + + /* OR */ + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>, /* Supply 0 */ + <965000 960000 975000>, /* Supply 1 */ + <965000 960000 975000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <70000>, /* Supply 1 */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + + /* OR */ + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>, /* Supply 0 */ + <965000 960000 975000>, /* Supply 1 */ + <965000 960000 975000>; /* Supply 2 */ + opp-microamp = <70000>, /* Supply 0 */ + <0>, /* Supply 1 doesn't need this */ + <70000>; /* Supply 2 */ + clock-latency-ns = <300000>; + }; + }; +}; + +Example 5: opp-supported-hw +(example: three level hierarchy of versions: cuts, substrate and process) + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-a7"; + ... + + cpu-supply = <&cpu_supply> + operating-points-v2 = <&cpu0_opp_table_slow>; + }; + }; + + opp_table { + compatible = "operating-points-v2"; + opp-shared; + + opp-600000000 { + /* + * Supports all substrate and process versions for 0xF + * cuts, i.e. only first four cuts. + */ + opp-supported-hw = <0xF 0xFFFFFFFF 0xFFFFFFFF> + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <915000 900000 925000>; + ... + }; + + opp-800000000 { + /* + * Supports: + * - cuts: only one, 6th cut (represented by 6th bit). + * - substrate: supports 16 different substrate versions + * - process: supports 9 different process versions + */ + opp-supported-hw = <0x20 0xff0000ff 0x0000f4f0> + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <915000 900000 925000>; + ... + }; + }; +}; + +Example 6: opp-microvolt-, opp-microamp-: +(example: device with two possible microvolt ranges: slow and fast) + +/ { + cpus { + cpu@0 { + compatible = "arm,cortex-a7"; + ... + + operating-points-v2 = <&cpu0_opp_table>; + }; + }; + + cpu0_opp_table: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt-slow = <915000 900000 925000>; + opp-microvolt-fast = <975000 970000 985000>; + opp-microamp-slow = <70000>; + opp-microamp-fast = <71000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt-slow = <915000 900000 925000>, /* Supply vcc0 */ + <925000 910000 935000>; /* Supply vcc1 */ + opp-microvolt-fast = <975000 970000 985000>, /* Supply vcc0 */ + <965000 960000 975000>; /* Supply vcc1 */ + opp-microamp = <70000>; /* Will be used for both slow/fast */ + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/opp/ti-omap5-opp-supply.txt b/arch/arm64/boot/dts/vendor/bindings/opp/ti-omap5-opp-supply.txt new file mode 100644 index 0000000000000000000000000000000000000000..832346e489a30a434bbf191c5d82a9c273e73fb3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/opp/ti-omap5-opp-supply.txt @@ -0,0 +1,63 @@ +Texas Instruments OMAP compatible OPP supply description + +OMAP5, DRA7, and AM57 family of SoCs have Class0 AVS eFuse registers which +contain data that can be used to adjust voltages programmed for some of their +supplies for more efficient operation. This binding provides the information +needed to read these values and use them to program the main regulator during +an OPP transitions. + +Also, some supplies may have an associated vbb-supply which is an Adaptive Body +Bias regulator which much be transitioned in a specific sequence with regards +to the vdd-supply and clk when making an OPP transition. By supplying two +regulators to the device that will undergo OPP transitions we can make use +of the multi regulator binding that is part of the OPP core described here [1] +to describe both regulators needed by the platform. + +[1] Documentation/devicetree/bindings/opp/opp.txt + +Required Properties for Device Node: +- vdd-supply: phandle to regulator controlling VDD supply +- vbb-supply: phandle to regulator controlling Body Bias supply + (Usually Adaptive Body Bias regulator) + +Required Properties for opp-supply node: +- compatible: Should be one of: + "ti,omap-opp-supply" - basic OPP supply controlling VDD and VBB + "ti,omap5-opp-supply" - OMAP5+ optimized voltages in efuse(class0)VDD + along with VBB + "ti,omap5-core-opp-supply" - OMAP5+ optimized voltages in efuse(class0) VDD + but no VBB. +- reg: Address and length of the efuse register set for the device (mandatory + only for "ti,omap5-opp-supply") +- ti,efuse-settings: An array of u32 tuple items providing information about + optimized efuse configuration. Each item consists of the following: + volt: voltage in uV - reference voltage (OPP voltage) + efuse_offseet: efuse offset from reg where the optimized voltage is stored. +- ti,absolute-max-voltage-uv: absolute maximum voltage for the OPP supply. + +Example: + +/* Device Node (CPU) */ +cpus { + cpu0: cpu@0 { + device_type = "cpu"; + + ... + + vdd-supply = <&vcc>; + vbb-supply = <&abb_mpu>; + }; +}; + +/* OMAP OPP Supply with Class0 registers */ +opp_supply_mpu: opp_supply@4a003b20 { + compatible = "ti,omap5-opp-supply"; + reg = <0x4a003b20 0x8>; + ti,efuse-settings = < + /* uV offset */ + 1060000 0x0 + 1160000 0x4 + 1210000 0x8 + >; + ti,absolute-max-voltage-uv = <1500000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/83xx-512x-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/83xx-512x-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9165b72473c10f6245bd656a6ac169d67cd3257 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/83xx-512x-pci.txt @@ -0,0 +1,40 @@ +* Freescale 83xx and 512x PCI bridges + +Freescale 83xx and 512x SOCs include the same PCI bridge core. + +83xx/512x specific notes: +- reg: should contain two address length tuples + The first is for the internal PCI bridge registers + The second is for the PCI config space access registers + +Example (MPC8313ERDB) + pci0: pci@e0008500 { + cell-index = <1>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x0E -mini PCI */ + 0x7000 0x0 0x0 0x1 &ipic 18 0x8 + 0x7000 0x0 0x0 0x2 &ipic 18 0x8 + 0x7000 0x0 0x0 0x3 &ipic 18 0x8 + 0x7000 0x0 0x0 0x4 &ipic 18 0x8 + + /* IDSEL 0x0F - PCI slot */ + 0x7800 0x0 0x0 0x1 &ipic 17 0x8 + 0x7800 0x0 0x0 0x2 &ipic 18 0x8 + 0x7800 0x0 0x0 0x3 &ipic 17 0x8 + 0x7800 0x0 0x0 0x4 &ipic 18 0x8>; + interrupt-parent = <&ipic>; + interrupts = <66 0x8>; + bus-range = <0x0 0x0>; + ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000 + 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000 + 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>; + clock-frequency = <66666666>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0xe0008500 0x100 /* internal registers */ + 0xe0008300 0x8>; /* config space access registers */ + compatible = "fsl,mpc8349-pci"; + device_type = "pci"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/aardvark-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/aardvark-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..310ef7145c47e1b2068648ceb21d190ec1d0aca5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/aardvark-pci.txt @@ -0,0 +1,55 @@ +Aardvark PCIe controller + +This PCIe controller is used on the Marvell Armada 3700 ARM64 SoC. + +The Device Tree node describing an Aardvark PCIe controller must +contain the following properties: + + - compatible: Should be "marvell,armada-3700-pcie" + - reg: range of registers for the PCIe controller + - interrupts: the interrupt line of the PCIe controller + - #address-cells: set to <3> + - #size-cells: set to <2> + - device_type: set to "pci" + - ranges: ranges for the PCI memory and I/O regions + - #interrupt-cells: set to <1> + - msi-controller: indicates that the PCIe controller can itself + handle MSI interrupts + - msi-parent: pointer to the MSI controller to be used + - interrupt-map-mask and interrupt-map: standard PCI properties to + define the mapping of the PCIe interface to interrupt numbers. + - bus-range: PCI bus numbers covered + +In addition, the Device Tree describing an Aardvark PCIe controller +must include a sub-node that describes the legacy interrupt controller +built into the PCIe controller. This sub-node must have the following +properties: + + - interrupt-controller + - #interrupt-cells: set to <1> + +Example: + + pcie0: pcie@d0070000 { + compatible = "marvell,armada-3700-pcie"; + device_type = "pci"; + reg = <0 0xd0070000 0 0x20000>; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; + interrupts = ; + #interrupt-cells = <1>; + msi-controller; + msi-parent = <&pcie0>; + ranges = <0x82000000 0 0xe8000000 0 0xe8000000 0 0x1000000 /* Port 0 MEM */ + 0x81000000 0 0xe9000000 0 0xe9000000 0 0x10000>; /* Port 0 IO*/ + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 0>, + <0 0 0 2 &pcie_intc 1>, + <0 0 0 3 &pcie_intc 2>, + <0 0 0 4 &pcie_intc 3>; + pcie_intc: interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/altera-pcie-msi.txt b/arch/arm64/boot/dts/vendor/bindings/pci/altera-pcie-msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..9514c327d31b7bf16a74b195b2928935590dddeb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/altera-pcie-msi.txt @@ -0,0 +1,27 @@ +* Altera PCIe MSI controller + +Required properties: +- compatible: should contain "altr,msi-1.0" +- reg: specifies the physical base address of the controller and + the length of the memory mapped region. +- reg-names: must include the following entries: + "csr": CSR registers + "vector_slave": vectors slave port region +- interrupts: specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends on the + parent interrupt controller. +- num-vectors: number of vectors, range 1 to 32. +- msi-controller: indicates that this is MSI controller node + + +Example +msi0: msi@0xFF200000 { + compatible = "altr,msi-1.0"; + reg = <0xFF200000 0x00000010 + 0xFF200010 0x00000080>; + reg-names = "csr", "vector_slave"; + interrupt-parent = <&hps_0_arm_gic_0>; + interrupts = <0 42 4>; + msi-controller; + num-vectors = <32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/altera-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/altera-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c396f17c91a82fd45d162ead2faa50274a2995b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/altera-pcie.txt @@ -0,0 +1,48 @@ +* Altera PCIe controller + +Required properties: +- compatible : should contain "altr,pcie-root-port-1.0" +- reg: a list of physical base address and length for TXS and CRA. +- reg-names: must include the following entries: + "Txs": TX slave port region + "Cra": Control register access region +- interrupts: specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends + on the parent interrupt controller. +- device_type: must be "pci" +- #address-cells: set to <3> +- #size-cells: set to <2> +- #interrupt-cells: set to <1> +- ranges: describes the translation of addresses for root ports and + standard PCI regions. +- interrupt-map-mask and interrupt-map: standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers. + +Optional properties: +- msi-parent: Link to the hardware entity that serves as the MSI controller + for this PCIe controller. +- bus-range: PCI bus numbers covered + +Example + pcie_0: pcie@c00000000 { + compatible = "altr,pcie-root-port-1.0"; + reg = <0xc0000000 0x20000000>, + <0xff220000 0x00004000>; + reg-names = "Txs", "Cra"; + interrupt-parent = <&hps_0_arm_gic_0>; + interrupts = <0 40 4>; + interrupt-controller; + #interrupt-cells = <1>; + bus-range = <0x0 0xFF>; + device_type = "pci"; + msi-parent = <&msi_to_gic_gen_0>; + #address-cells = <3>; + #size-cells = <2>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_0 1>, + <0 0 0 2 &pcie_0 2>, + <0 0 0 3 &pcie_0 3>, + <0 0 0 4 &pcie_0 4>; + ranges = <0x82000000 0x00000000 0x00000000 0xc0000000 0x00000000 0x10000000 + 0x82000000 0x00000000 0x10000000 0xd0000000 0x00000000 0x10000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/arm,juno-r1-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/arm,juno-r1-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7514c170a326256f27da23bb893f232d5f1b6e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/arm,juno-r1-pcie.txt @@ -0,0 +1,10 @@ +* ARM Juno R1 PCIe interface + +This PCIe host controller is based on PLDA XpressRICH3-AXI IP +and thus inherits all the common properties defined in plda,xpressrich3-axi.txt +as well as the base properties defined in host-generic-pci.txt. + +Required properties: + - compatible: "arm,juno-r1-pcie" + - dma-coherent: The host controller bridges the AXI transactions into PCIe bus + in a manner that makes the DMA operations to appear coherent to the CPUs. diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/axis,artpec6-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/axis,artpec6-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..979dc7b6cfe85c5db4de3ff007e18e17d65457b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/axis,artpec6-pcie.txt @@ -0,0 +1,50 @@ +* Axis ARTPEC-6 PCIe interface + +This PCIe host controller is based on the Synopsys DesignWare PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: "axis,artpec6-pcie", "snps,dw-pcie" for ARTPEC-6 in RC mode; + "axis,artpec6-pcie-ep", "snps,dw-pcie" for ARTPEC-6 in EP mode; + "axis,artpec7-pcie", "snps,dw-pcie" for ARTPEC-7 in RC mode; + "axis,artpec7-pcie-ep", "snps,dw-pcie" for ARTPEC-7 in EP mode; +- reg: base addresses and lengths of the PCIe controller (DBI), + the PHY controller, and configuration address space. +- reg-names: Must include the following entries: + - "dbi" + - "phy" + - "config" +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + - "msi": The interrupt that is asserted when an MSI is received +- axis,syscon-pcie: A phandle pointing to the ARTPEC-6 system controller, + used to enable and control the Synopsys IP. + +Example: + + pcie@f8050000 { + compatible = "axis,artpec6-pcie", "snps,dw-pcie"; + reg = <0xf8050000 0x2000 + 0xf8040000 0x1000 + 0xc0000000 0x2000>; + reg-names = "dbi", "phy", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + /* downstream I/O */ + ranges = <0x81000000 0 0 0xc0002000 0 0x00010000 + /* non-prefetchable memory */ + 0x82000000 0 0xc0012000 0xc0012000 0 0x1ffee000>; + num-lanes = <2>; + bus-range = <0x00 0xff>; + interrupts = ; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>; + axis,syscon-pcie = <&syscon>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/brcm,iproc-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/brcm,iproc-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..df065aa53a832e07b37eba6d6244f4c97b2156d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/brcm,iproc-pcie.txt @@ -0,0 +1,133 @@ +* Broadcom iProc PCIe controller with the platform bus interface + +Required properties: +- compatible: + "brcm,iproc-pcie" for the first generation of PAXB based controller, +used in SoCs including NSP, Cygnus, NS2, and Pegasus + "brcm,iproc-pcie-paxb-v2" for the second generation of PAXB-based +controllers, used in Stingray + "brcm,iproc-pcie-paxc" for the first generation of PAXC based +controller, used in NS2 + "brcm,iproc-pcie-paxc-v2" for the second generation of PAXC based +controller, used in Stingray + PAXB-based root complex is used for external endpoint devices. PAXC-based +root complex is connected to emulated endpoint devices internal to the ASIC +- reg: base address and length of the PCIe controller I/O register space +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map, standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers +- linux,pci-domain: PCI domain ID. Should be unique for each host controller +- bus-range: PCI bus numbers covered +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions + +Optional properties: +- phys: phandle of the PCIe PHY device +- phy-names: must be "pcie-phy" +- dma-coherent: present if DMA operations are coherent +- dma-ranges: Some PAXB-based root complexes do not have inbound mapping done + by the ASIC after power on reset. In this case, SW is required to configure +the mapping, based on inbound memory regions specified by this property. + +- brcm,pcie-ob: Some iProc SoCs do not have the outbound address mapping done +by the ASIC after power on reset. In this case, SW needs to configure it + +If the brcm,pcie-ob property is present, the following properties become +effective: + +Required: +- brcm,pcie-ob-axi-offset: The offset from the AXI address to the internal +address used by the iProc PCIe core (not the PCIe address) + +MSI support (optional): + +For older platforms without MSI integrated in the GIC, iProc PCIe core provides +an event queue based MSI support. The iProc MSI uses host memories to store +MSI posted writes in the event queues + +On newer iProc platforms, gicv2m or gicv3-its based MSI support should be used + +- msi-map: Maps a Requester ID to an MSI controller and associated MSI +sideband data + +- msi-parent: Link to the device node of the MSI controller, used when no MSI +sideband data is passed between the iProc PCIe controller and the MSI +controller + +Refer to the following binding documents for more detailed description on +the use of 'msi-map' and 'msi-parent': + Documentation/devicetree/bindings/pci/pci-msi.txt + Documentation/devicetree/bindings/interrupt-controller/msi.txt + +When the iProc event queue based MSI is used, one needs to define the +following properties in the MSI device node: +- compatible: Must be "brcm,iproc-msi" +- msi-controller: claims itself as an MSI controller +- interrupts: List of interrupt IDs from its parent interrupt device + +Optional properties: +- brcm,pcie-msi-inten: Needs to be present for some older iProc platforms that +require the interrupt enable registers to be set explicitly to enable MSI + +Example: + pcie0: pcie@18012000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18012000 0x1000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>; + + linux,pci-domain = <0>; + + bus-range = <0x00 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x28000000 0 0x00010000 + 0x82000000 0 0x20000000 0x20000000 0 0x04000000>; + + phys = <&phy 0 5>; + phy-names = "pcie-phy"; + + brcm,pcie-ob; + brcm,pcie-ob-axi-offset = <0x00000000>; + + msi-parent = <&msi0>; + + /* iProc event queue based MSI */ + msi0: msi@18012000 { + compatible = "brcm,iproc-msi"; + msi-controller; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + }; + }; + + pcie1: pcie@18013000 { + compatible = "brcm,iproc-pcie"; + reg = <0x18013000 0x1000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>; + + linux,pci-domain = <1>; + + bus-range = <0x00 0xff>; + + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x48000000 0 0x00010000 + 0x82000000 0 0x40000000 0x40000000 0 0x04000000>; + + phys = <&phy 1 6>; + phy-names = "pcie-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/cdns,cdns-pcie-ep.txt b/arch/arm64/boot/dts/vendor/bindings/pci/cdns,cdns-pcie-ep.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a0475e2ba7ec1c86b2290323329b4dea86cacb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/cdns,cdns-pcie-ep.txt @@ -0,0 +1,27 @@ +* Cadence PCIe endpoint controller + +Required properties: +- compatible: Should contain "cdns,cdns-pcie-ep" to identify the IP used. +- reg: Should contain the controller register base address and AXI interface + region base address respectively. +- reg-names: Must be "reg" and "mem" respectively. +- cdns,max-outbound-regions: Set to maximum number of outbound regions + +Optional properties: +- max-functions: Maximum number of functions that can be configured (default 1). +- phys: From PHY bindings: List of Generic PHY phandles. One per lane if more + than one in the list. If only one PHY listed it must manage all lanes. +- phy-names: List of names to identify the PHY. + +Example: + +pcie@fc000000 { + compatible = "cdns,cdns-pcie-ep"; + reg = <0x0 0xfc000000 0x0 0x01000000>, + <0x0 0x80000000 0x0 0x40000000>; + reg-names = "reg", "mem"; + cdns,max-outbound-regions = <16>; + max-functions = /bits/ 8 <8>; + phys = <&ep_phy0 &ep_phy1>; + phy-names = "pcie-lane0","pcie-lane1"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/cdns,cdns-pcie-host.txt b/arch/arm64/boot/dts/vendor/bindings/pci/cdns,cdns-pcie-host.txt new file mode 100644 index 0000000000000000000000000000000000000000..91de69c713a940badd081d11133c063d9b22309d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/cdns,cdns-pcie-host.txt @@ -0,0 +1,66 @@ +* Cadence PCIe host controller + +This PCIe controller inherits the base properties defined in +host-generic-pci.txt. + +Required properties: +- compatible: Should contain "cdns,cdns-pcie-host" to identify the IP used. +- reg: Should contain the controller register base address, PCIe configuration + window base address, and AXI interface region base address respectively. +- reg-names: Must be "reg", "cfg" and "mem" respectively. +- #address-cells: Set to <3> +- #size-cells: Set to <2> +- device_type: Set to "pci" +- ranges: Ranges for the PCI memory and I/O regions +- #interrupt-cells: Set to <1> +- interrupt-map-mask and interrupt-map: Standard PCI properties to define the + mapping of the PCIe interface to interrupt numbers. + +Optional properties: +- cdns,max-outbound-regions: Set to maximum number of outbound regions + (default 32) +- cdns,no-bar-match-nbits: Set into the no BAR match register to configure the + number of least significant bits kept during inbound (PCIe -> AXI) address + translations (default 32) +- vendor-id: The PCI vendor ID (16 bits, default is design dependent) +- device-id: The PCI device ID (16 bits, default is design dependent) +- phys: From PHY bindings: List of Generic PHY phandles. One per lane if more + than one in the list. If only one PHY listed it must manage all lanes. +- phy-names: List of names to identify the PHY. + +Example: + +pcie@fb000000 { + compatible = "cdns,cdns-pcie-host"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0xff>; + linux,pci-domain = <0>; + cdns,max-outbound-regions = <16>; + cdns,no-bar-match-nbits = <32>; + vendor-id = /bits/ 16 <0x17cd>; + device-id = /bits/ 16 <0x0200>; + + reg = <0x0 0xfb000000 0x0 0x01000000>, + <0x0 0x41000000 0x0 0x00001000>, + <0x0 0x40000000 0x0 0x04000000>; + reg-names = "reg", "cfg", "mem"; + + ranges = <0x02000000 0x0 0x42000000 0x0 0x42000000 0x0 0x1000000>, + <0x01000000 0x0 0x43000000 0x0 0x43000000 0x0 0x0010000>; + + #interrupt-cells = <0x1>; + + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0x0 0x0 14 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0x0 0x0 15 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0x0 0x0 16 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0x0 0x0 17 0x1>; + + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + + msi-parent = <&its_pci>; + + phys = <&pcie_phy0>; + phy-names = "pcie-phy"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/designware-pcie-ecam.txt b/arch/arm64/boot/dts/vendor/bindings/pci/designware-pcie-ecam.txt new file mode 100644 index 0000000000000000000000000000000000000000..515b2f9542e548d7bb4dbc631307bcbe8bb304df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/designware-pcie-ecam.txt @@ -0,0 +1,42 @@ +* Synopsys DesignWare PCIe root complex in ECAM shift mode + +In some cases, firmware may already have configured the Synopsys DesignWare +PCIe controller in RC mode with static ATU window mappings that cover all +config, MMIO and I/O spaces in a [mostly] ECAM compatible fashion. +In this case, there is no need for the OS to perform any low level setup +of clocks, PHYs or device registers, nor is there any reason for the driver +to reconfigure ATU windows for config and/or IO space accesses at runtime. + +In cases where the IP was synthesized with a minimum ATU window size of +64 KB, it cannot be supported by the generic ECAM driver, because it +requires special config space accessors that filter accesses to device #1 +and beyond on the first bus. + +Required properties: +- compatible: "marvell,armada8k-pcie-ecam" or + "socionext,synquacer-pcie-ecam" or + "snps,dw-pcie-ecam" (must be preceded by a more specific match) + +Please refer to the binding document of "pci-host-ecam-generic" in the +file host-generic-pci.txt for a description of the remaining required +and optional properties. + +Example: + + pcie1: pcie@7f000000 { + compatible = "socionext,synquacer-pcie-ecam", "snps,dw-pcie-ecam"; + device_type = "pci"; + reg = <0x0 0x7f000000 0x0 0xf00000>; + bus-range = <0x0 0xe>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x1000000 0x00 0x00010000 0x00 0x7ff00000 0x0 0x00010000>, + <0x2000000 0x00 0x70000000 0x00 0x70000000 0x0 0x0f000000>, + <0x3000000 0x3f 0x00000000 0x3f 0x00000000 0x1 0x00000000>; + + #interrupt-cells = <0x1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &gic 0x0 0x0 0x0 182 0x4>; + msi-map = <0x0 &its 0x0 0x10000>; + dma-coherent; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/designware-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/designware-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..c124f9bc11f3a46579887ec06fd270af372d577b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/designware-pcie.txt @@ -0,0 +1,70 @@ +* Synopsys DesignWare PCIe interface + +Required properties: +- compatible: + "snps,dw-pcie" for RC mode; + "snps,dw-pcie-ep" for EP mode; +- reg: Should contain the configuration address space. +- reg-names: Must be "config" for the PCIe configuration space. + (The old way of getting the configuration address space from "ranges" + is deprecated and should be avoided.) +- num-lanes: number of lanes to use +RC mode: +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI + properties to define the mapping of the PCIe interface to interrupt + numbers. +EP mode: +- num-ib-windows: number of inbound address translation windows +- num-ob-windows: number of outbound address translation windows + +Optional properties: +- num-lanes: number of lanes to use (this property should be specified unless + the link is brought already up in BIOS) +- reset-gpio: GPIO pin number of power good signal +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - "pcie" + - "pcie_bus" +RC mode: +- num-viewport: number of view ports configured in hardware. If a platform + does not specify it, the driver assumes 2. +- bus-range: PCI bus numbers covered (it is recommended for new devicetrees + to specify this property, to keep backwards compatibility a range of + 0x00-0xff is assumed if not present) + +EP mode: +- max-functions: maximum number of functions that can be configured + +Example configuration: + + pcie: pcie@dfc00000 { + compatible = "snps,dw-pcie"; + reg = <0xdfc00000 0x0001000>, /* IP registers */ + <0xd0000000 0x0002000>; /* Configuration space */ + reg-names = "dbi", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0x00000000 0xde000000 0 0x00010000 + 0x82000000 0 0xd0400000 0xd0400000 0 0x0d000000>; + interrupts = <25>, <24>; + #interrupt-cells = <1>; + num-lanes = <1>; + }; +or + pcie: pcie@dfc00000 { + compatible = "snps,dw-pcie-ep"; + reg = <0xdfc00000 0x0001000>, /* IP registers 1 */ + <0xdfc01000 0x0001000>, /* IP registers 2 */ + <0xd0000000 0x2000000>; /* Configuration space */ + reg-names = "dbi", "dbi2", "addr_space"; + num-ib-windows = <6>; + num-ob-windows = <2>; + num-lanes = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/faraday,ftpci100.txt b/arch/arm64/boot/dts/vendor/bindings/pci/faraday,ftpci100.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f8cb4962f8d64d3ab78c48314d221455fe0d0b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/faraday,ftpci100.txt @@ -0,0 +1,135 @@ +Faraday Technology FTPCI100 PCI Host Bridge + +This PCI bridge is found inside that Cortina Systems Gemini SoC platform and +is a generic IP block from Faraday Technology. It exists in two variants: +plain and dual PCI. The plain version embeds a cascading interrupt controller +into the host bridge. The dual version routes the interrupts to the host +chips interrupt controller. + +The host controller appear on the PCI bus with vendor ID 0x159b (Faraday +Technology) and product ID 0x4321. + +Mandatory properties: + +- compatible: ranging from specific to generic, should be one of + "cortina,gemini-pci", "faraday,ftpci100" + "cortina,gemini-pci-dual", "faraday,ftpci100-dual" + "faraday,ftpci100" + "faraday,ftpci100-dual" +- reg: memory base and size for the host bridge +- #address-cells: set to <3> +- #size-cells: set to <2> +- #interrupt-cells: set to <1> +- bus-range: set to <0x00 0xff> +- device_type, set to "pci" +- ranges: see pci.txt +- interrupt-map-mask: see pci.txt +- interrupt-map: see pci.txt +- dma-ranges: three ranges for the inbound memory region. The ranges must + be aligned to a 1MB boundary, and may be 1MB, 2MB, 4MB, 8MB, 16MB, 32MB, 64MB, + 128MB, 256MB, 512MB, 1GB or 2GB in size. The memory should be marked as + pre-fetchable. + +Optional properties: +- clocks: when present, this should contain the peripheral clock (PCLK) and the + PCI clock (PCICLK). If these are not present, they are assumed to be + hard-wired enabled and always on. The PCI clock will be 33 or 66 MHz. +- clock-names: when present, this should contain "PCLK" for the peripheral + clock and "PCICLK" for the PCI-side clock. + +Mandatory subnodes: +- For "faraday,ftpci100" a node representing the interrupt-controller inside the + host bridge is mandatory. It has the following mandatory properties: + - interrupt: see interrupt-controller/interrupts.txt + - interrupt-controller: see interrupt-controller/interrupts.txt + - #address-cells: set to <0> + - #interrupt-cells: set to <1> + +I/O space considerations: + +The plain variant has 128MiB of non-prefetchable memory space, whereas the +"dual" variant has 64MiB. Take this into account when describing the ranges. + +Interrupt map considerations: + +The "dual" variant will get INT A, B, C, D from the system interrupt controller +and should point to respective interrupt in that controller in its +interrupt-map. + +The code which is the only documentation of how the Faraday PCI (the non-dual +variant) interrupts assigns the default interrupt mapping/swizzling has +typically been like this, doing the swizzling on the interrupt controller side +rather than in the interconnect: + +interrupt-map-mask = <0xf800 0 0 7>; +interrupt-map = + <0x4800 0 0 1 &pci_intc 0>, /* Slot 9 */ + <0x4800 0 0 2 &pci_intc 1>, + <0x4800 0 0 3 &pci_intc 2>, + <0x4800 0 0 4 &pci_intc 3>, + <0x5000 0 0 1 &pci_intc 1>, /* Slot 10 */ + <0x5000 0 0 2 &pci_intc 2>, + <0x5000 0 0 3 &pci_intc 3>, + <0x5000 0 0 4 &pci_intc 0>, + <0x5800 0 0 1 &pci_intc 2>, /* Slot 11 */ + <0x5800 0 0 2 &pci_intc 3>, + <0x5800 0 0 3 &pci_intc 0>, + <0x5800 0 0 4 &pci_intc 1>, + <0x6000 0 0 1 &pci_intc 3>, /* Slot 12 */ + <0x6000 0 0 2 &pci_intc 0>, + <0x6000 0 0 3 &pci_intc 1>, + <0x6000 0 0 4 &pci_intc 2>; + +Example: + +pci@50000000 { + compatible = "cortina,gemini-pci", "faraday,ftpci100"; + reg = <0x50000000 0x100>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>, /* PCI A */ + <26 IRQ_TYPE_LEVEL_HIGH>, /* PCI B */ + <27 IRQ_TYPE_LEVEL_HIGH>, /* PCI C */ + <28 IRQ_TYPE_LEVEL_HIGH>; /* PCI D */ + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + bus-range = <0x00 0xff>; + ranges = /* 1MiB I/O space 0x50000000-0x500fffff */ + <0x01000000 0 0 0x50000000 0 0x00100000>, + /* 128MiB non-prefetchable memory 0x58000000-0x5fffffff */ + <0x02000000 0 0x58000000 0x58000000 0 0x08000000>; + + /* DMA ranges */ + dma-ranges = + /* 128MiB at 0x00000000-0x07ffffff */ + <0x02000000 0 0x00000000 0x00000000 0 0x08000000>, + /* 64MiB at 0x00000000-0x03ffffff */ + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>, + /* 64MiB at 0x00000000-0x03ffffff */ + <0x02000000 0 0x00000000 0x00000000 0 0x04000000>; + + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = + <0x4800 0 0 1 &pci_intc 0>, /* Slot 9 */ + <0x4800 0 0 2 &pci_intc 1>, + <0x4800 0 0 3 &pci_intc 2>, + <0x4800 0 0 4 &pci_intc 3>, + <0x5000 0 0 1 &pci_intc 1>, /* Slot 10 */ + <0x5000 0 0 2 &pci_intc 2>, + <0x5000 0 0 3 &pci_intc 3>, + <0x5000 0 0 4 &pci_intc 0>, + <0x5800 0 0 1 &pci_intc 2>, /* Slot 11 */ + <0x5800 0 0 2 &pci_intc 3>, + <0x5800 0 0 3 &pci_intc 0>, + <0x5800 0 0 4 &pci_intc 1>, + <0x6000 0 0 1 &pci_intc 3>, /* Slot 12 */ + <0x6000 0 0 2 &pci_intc 0>, + <0x6000 0 0 3 &pci_intc 0>, + <0x6000 0 0 4 &pci_intc 0>; + pci_intc: interrupt-controller { + interrupt-parent = <&intcon>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/fsl,imx6q-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/fsl,imx6q-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb33421184a07f944fba2cff555a4217dce65708 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/fsl,imx6q-pcie.txt @@ -0,0 +1,78 @@ +* Freescale i.MX6 PCIe interface + +This PCIe host controller is based on the Synopsys DesignWare PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: + - "fsl,imx6q-pcie" + - "fsl,imx6sx-pcie", + - "fsl,imx6qp-pcie" + - "fsl,imx7d-pcie" +- reg: base address and length of the PCIe controller +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + - "msi": The interrupt that is asserted when an MSI is received +- clock-names: Must include the following additional entries: + - "pcie_phy" + +Optional properties: +- fsl,tx-deemph-gen1: Gen1 De-emphasis value. Default: 0 +- fsl,tx-deemph-gen2-3p5db: Gen2 (3.5db) De-emphasis value. Default: 0 +- fsl,tx-deemph-gen2-6db: Gen2 (6db) De-emphasis value. Default: 20 +- fsl,tx-swing-full: Gen2 TX SWING FULL value. Default: 127 +- fsl,tx-swing-low: TX launch amplitude swing_low value. Default: 127 +- fsl,max-link-speed: Specify PCI gen for link capability. Must be '2' for + gen2, otherwise will default to gen1. Note that the IMX6 LVDS clock outputs + do not meet gen2 jitter requirements and thus for gen2 capability a gen2 + compliant clock generator should be used and configured. +- reset-gpio: Should specify the GPIO for controlling the PCI bus device reset + signal. It's not polarity aware and defaults to active-low reset sequence + (L=reset state, H=operation state). +- reset-gpio-active-high: If present then the reset sequence using the GPIO + specified in the "reset-gpio" property is reversed (H=reset state, + L=operation state). +- vpcie-supply: Should specify the regulator in charge of PCIe port power. + The regulator will be enabled when initializing the PCIe host and + disabled either as part of the init process or when shutting down the + host. + +Additional required properties for imx6sx-pcie: +- clock names: Must include the following additional entries: + - "pcie_inbound_axi" +- power-domains: Must be set to a phandle pointing to the PCIE_PHY power domain + +Additional required properties for imx7d-pcie: +- power-domains: Must be set to a phandle pointing to PCIE_PHY power domain +- resets: Must contain phandles to PCIe-related reset lines exposed by SRC + IP block +- reset-names: Must contain the following entires: + - "pciephy" + - "apps" + +Example: + + pcie@01000000 { + compatible = "fsl,imx6q-pcie", "snps,dw-pcie"; + reg = <0x01ffc000 0x04000>, + <0x01f00000 0x80000>; + reg-names = "dbi", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x00000800 0 0x01f00000 0x01f00000 0 0x00080000 + 0x81000000 0 0 0x01f80000 0 0x00010000 + 0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; + num-lanes = <1>; + interrupts = ; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 144>, <&clks 206>, <&clks 189>; + clock-names = "pcie", "pcie_bus", "pcie_phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/fsl,pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/fsl,pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..d8ac4a768e7e65b465f83308cc918ec471309dcf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/fsl,pci.txt @@ -0,0 +1,27 @@ +* Bus Enumeration by Freescale PCI-X Agent + +Typically any Freescale PCI-X bridge hardware strapped into Agent mode +is prevented from enumerating the bus. The PrPMC form-factor requires +all mezzanines to be PCI-X Agents, but one per system may still +enumerate the bus. + +The property defined below will allow a PCI-X bridge to be used for bus +enumeration despite being strapped into Agent mode. + +Required properties: +- fsl,pci-agent-force-enum : There is no value associated with this + property. The property itself is treated as a boolean. + +Example: + + /* PCI-X bridge known to be PrPMC Monarch */ + pci0: pci@ef008000 { + fsl,pci-agent-force-enum; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci"; + device_type = "pci"; + ... + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/hisilicon-histb-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/hisilicon-histb-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..760b4d7406162ddb45f922d0777fbde962d08d72 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/hisilicon-histb-pcie.txt @@ -0,0 +1,69 @@ +HiSilicon STB PCIe host bridge DT description + +The HiSilicon STB PCIe host controller is based on the DesignWare PCIe core. +It shares common functions with the DesignWare PCIe core driver and inherits +common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt. + +Additional properties are described here: + +Required properties +- compatible: Should be one of the following strings: + "hisilicon,hi3798cv200-pcie" +- reg: Should contain sysctl, rc_dbi, config registers location and length. +- reg-names: Must include the following entries: + "control": control registers of PCIe controller; + "rc-dbi": configuration space of PCIe controller; + "config": configuration transaction space of PCIe controller. +- bus-range: PCI bus numbers covered. +- interrupts: MSI interrupt. +- interrupt-names: Must include "msi" entries. +- clocks: List of phandle and clock specifier pairs as listed in clock-names + property. +- clock-name: Must include the following entries: + "aux": auxiliary gate clock; + "pipe": pipe gate clock; + "sys": sys gate clock; + "bus": bus gate clock. +- resets: List of phandle and reset specifier pairs as listed in reset-names + property. +- reset-names: Must include the following entries: + "soft": soft reset; + "sys": sys reset; + "bus": bus reset. + +Optional properties: +- reset-gpios: The gpio to generate PCIe PERST# assert and deassert signal. +- vpcie-supply: The regulator in charge of PCIe port power. +- phys: List of phandle and phy mode specifier, should be 0. +- phy-names: Must be "phy". + +Example: + pcie@f9860000 { + compatible = "hisilicon,hi3798cv200-pcie"; + reg = <0xf9860000 0x1000>, + <0xf0000000 0x2000>, + <0xf2000000 0x01000000>; + reg-names = "control", "rc-dbi", "config"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0 15>; + num-lanes = <1>; + ranges=<0x81000000 0 0 0xf4000000 0 0x00010000 + 0x82000000 0 0xf3000000 0xf3000000 0 0x01000000>; + interrupts = ; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&crg PCIE_AUX_CLK>, + <&crg PCIE_PIPE_CLK>, + <&crg PCIE_SYS_CLK>, + <&crg PCIE_BUS_CLK>; + clock-names = "aux", "pipe", "sys", "bus"; + resets = <&crg 0x18c 6>, <&crg 0x18c 5>, <&crg 0x18c 4>; + reset-names = "soft", "sys", "bus"; + phys = <&combphy1 PHY_TYPE_PCIE>; + phy-names = "phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/hisilicon-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/hisilicon-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dcb87d6554fdaa2f8c36dc37ab6ea545f80bc86 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/hisilicon-pcie.txt @@ -0,0 +1,85 @@ +HiSilicon Hip05 and Hip06 PCIe host bridge DT description + +HiSilicon PCIe host controller is based on the Synopsys DesignWare PCI core. +It shares common functions with the PCIe DesignWare core driver and inherits +common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt. + +Additional properties are described here: + +Required properties +- compatible: Should contain "hisilicon,hip05-pcie" or "hisilicon,hip06-pcie". +- reg: Should contain rc_dbi, config registers location and length. +- reg-names: Must include the following entries: + "rc_dbi": controller configuration registers; + "config": PCIe configuration space registers. +- msi-parent: Should be its_pcie which is an ITS receiving MSI interrupts. +- port-id: Should be 0, 1, 2 or 3. + +Optional properties: +- status: Either "ok" or "disabled". +- dma-coherent: Present if DMA operations are coherent. + +Hip05 Example (note that Hip06 is the same except compatible): + pcie@b0080000 { + compatible = "hisilicon,hip05-pcie", "snps,dw-pcie"; + reg = <0 0xb0080000 0 0x10000>, <0x220 0x00000000 0 0x2000>; + reg-names = "rc_dbi", "config"; + bus-range = <0 15>; + msi-parent = <&its_pcie>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + ranges = <0x82000000 0 0x00000000 0x220 0x00000000 0 0x10000000>; + num-lanes = <8>; + port-id = <1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = <0x0 0 0 1 &mbigen_pcie 1 10 + 0x0 0 0 2 &mbigen_pcie 2 11 + 0x0 0 0 3 &mbigen_pcie 3 12 + 0x0 0 0 4 &mbigen_pcie 4 13>; + }; + +HiSilicon Hip06/Hip07 PCIe host bridge DT (almost-ECAM) description. + +Some BIOSes place the host controller in a mode where it is ECAM +compliant for all devices other than the root complex. In such cases, +the host controller should be described as below. + +The properties and their meanings are identical to those described in +host-generic-pci.txt except as listed below. + +Properties of the host controller node that differ from +host-generic-pci.txt: + +- compatible : Must be "hisilicon,hip06-pcie-ecam", or + "hisilicon,hip07-pcie-ecam" + +- reg : Two entries: First the ECAM configuration space for any + other bus underneath the root bus. Second, the base + and size of the HiSilicon host bridge registers include + the RC's own config space. + +Example: + pcie0: pcie@a0090000 { + compatible = "hisilicon,hip06-pcie-ecam"; + reg = <0 0xb0000000 0 0x2000000>, /* ECAM configuration space */ + <0 0xa0090000 0 0x10000>; /* host bridge registers */ + bus-range = <0 31>; + msi-map = <0x0000 &its_dsa 0x0000 0x2000>; + msi-map-mask = <0xffff>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + ranges = <0x02000000 0 0xb2000000 0x0 0xb2000000 0 0x5ff0000 + 0x01000000 0 0 0 0xb7ff0000 0 0x10000>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = <0x0 0 0 1 &mbigen_pcie0 650 4 + 0x0 0 0 2 &mbigen_pcie0 650 4 + 0x0 0 0 3 &mbigen_pcie0 650 4 + 0x0 0 0 4 &mbigen_pcie0 650 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/host-generic-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/host-generic-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f1d3fca62bbf6a62afd1d270d271582c6c2e20e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/host-generic-pci.txt @@ -0,0 +1,101 @@ +* Generic PCI host controller + +Firmware-initialised PCI host controllers and PCI emulations, such as the +virtio-pci implementations found in kvmtool and other para-virtualised +systems, do not require driver support for complexities such as regulator +and clock management. In fact, the controller may not even require the +configuration of a control interface by the operating system, instead +presenting a set of fixed windows describing a subset of IO, Memory and +Configuration Spaces. + +Such a controller can be described purely in terms of the standardized device +tree bindings communicated in pci.txt: + + +Properties of the host controller node: + +- compatible : Must be "pci-host-cam-generic" or "pci-host-ecam-generic" + depending on the layout of configuration space (CAM vs + ECAM respectively). + +- device_type : Must be "pci". + +- ranges : As described in IEEE Std 1275-1994, but must provide + at least a definition of non-prefetchable memory. One + or both of prefetchable Memory and IO Space may also + be provided. + +- bus-range : Optional property (also described in IEEE Std 1275-1994) + to indicate the range of bus numbers for this controller. + If absent, defaults to <0 255> (i.e. all buses). + +- #address-cells : Must be 3. + +- #size-cells : Must be 2. + +- reg : The Configuration Space base address and size, as accessed + from the parent bus. The base address corresponds to + the first bus in the "bus-range" property. If no + "bus-range" is specified, this will be bus 0 (the default). + +Properties of the /chosen node: + +- linux,pci-probe-only + : Optional property which takes a single-cell argument. + If '0', then Linux will assign devices in its usual manner, + otherwise it will not try to assign devices and instead use + them as they are configured already. + +Configuration Space is assumed to be memory-mapped (as opposed to being +accessed via an ioport) and laid out with a direct correspondence to the +geography of a PCI bus address by concatenating the various components to +form an offset. + +For CAM, this 24-bit offset is: + + cfg_offset(bus, device, function, register) = + bus << 16 | device << 11 | function << 8 | register + +Whilst ECAM extends this by 4 bits to accommodate 4k of function space: + + cfg_offset(bus, device, function, register) = + bus << 20 | device << 15 | function << 12 | register + +Interrupt mapping is exactly as described in `Open Firmware Recommended +Practice: Interrupt Mapping' and requires the following properties: + +- #interrupt-cells : Must be 1 + +- interrupt-map : + +- interrupt-map-mask : + + +Example: + +pci { + compatible = "pci-host-cam-generic" + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x0 0x1>; + + // CPU_PHYSICAL(2) SIZE(2) + reg = <0x0 0x40000000 0x0 0x1000000>; + + // BUS_ADDRESS(3) CPU_PHYSICAL(2) SIZE(2) + ranges = <0x01000000 0x0 0x01000000 0x0 0x01000000 0x0 0x00010000>, + <0x02000000 0x0 0x41000000 0x0 0x41000000 0x0 0x3f000000>; + + + #interrupt-cells = <0x1>; + + // PCI_DEVICE(3) INT#(1) CONTROLLER(PHANDLE) CONTROLLER_DATA(3) + interrupt-map = < 0x0 0x0 0x0 0x1 &gic 0x0 0x4 0x1 + 0x800 0x0 0x0 0x1 &gic 0x0 0x5 0x1 + 0x1000 0x0 0x0 0x1 &gic 0x0 0x6 0x1 + 0x1800 0x0 0x0 0x1 &gic 0x0 0x7 0x1>; + + // PCI_DEVICE(3) INT#(1) + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/kirin-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/kirin-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..6bbe43818ad5d23d1e726cbc408ef08a86ea46fb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/kirin-pcie.txt @@ -0,0 +1,50 @@ +HiSilicon Kirin SoCs PCIe host DT description + +Kirin PCIe host controller is based on the Synopsys DesignWare PCI core. +It shares common functions with the PCIe DesignWare core driver and +inherits common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt. + +Additional properties are described here: + +Required properties +- compatible: + "hisilicon,kirin960-pcie" for PCIe of Kirin960 SoC +- reg: Should contain rc_dbi, apb, phy, config registers location and length. +- reg-names: Must include the following entries: + "dbi": controller configuration registers; + "apb": apb Ctrl register defined by Kirin; + "phy": apb PHY register defined by Kirin; + "config": PCIe configuration space registers. +- reset-gpios: The GPIO to generate PCIe PERST# assert and deassert signal. + +Optional properties: + +Example based on kirin960: + + pcie@f4000000 { + compatible = "hisilicon,kirin-pcie"; + reg = <0x0 0xf4000000 0x0 0x1000>, <0x0 0xff3fe000 0x0 0x1000>, + <0x0 0xf3f20000 0x0 0x40000>, <0x0 0xF4000000 0 0x2000>; + reg-names = "dbi","apb","phy", "config"; + bus-range = <0x0 0x1>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x02000000 0x0 0x00000000 0x0 0xf5000000 0x0 0x2000000>; + num-lanes = <1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = <0x0 0 0 1 &gic 0 0 0 282 4>, + <0x0 0 0 2 &gic 0 0 0 283 4>, + <0x0 0 0 3 &gic 0 0 0 284 4>, + <0x0 0 0 4 &gic 0 0 0 285 4>; + clocks = <&crg_ctrl HI3660_PCIEPHY_REF>, + <&crg_ctrl HI3660_CLK_GATE_PCIEAUX>, + <&crg_ctrl HI3660_PCLK_GATE_PCIE_PHY>, + <&crg_ctrl HI3660_PCLK_GATE_PCIE_SYS>, + <&crg_ctrl HI3660_ACLK_GATE_PCIE>; + clock-names = "pcie_phy_ref", "pcie_aux", + "pcie_apb_phy", "pcie_apb_sys", "pcie_aclk"; + reset-gpios = <&gpio11 1 0 >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/layerscape-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/layerscape-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..66df1e81e0b8d218ad39396e41be2c2d2e504f5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/layerscape-pci.txt @@ -0,0 +1,60 @@ +Freescale Layerscape PCIe controller + +This PCIe host controller is based on the Synopsys DesignWare PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +This controller derives its clocks from the Reset Configuration Word (RCW) +which is used to describe the PLL settings at the time of chip-reset. + +Also as per the available Reference Manuals, there is no specific 'version' +register available in the Freescale PCIe controller register set, +which can allow determining the underlying DesignWare PCIe controller version +information. + +Required properties: +- compatible: should contain the platform identifier such as: + "fsl,ls1021a-pcie", "snps,dw-pcie" + "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", "snps,dw-pcie" + "fsl,ls2088a-pcie" + "fsl,ls1088a-pcie" + "fsl,ls1046a-pcie" + "fsl,ls1012a-pcie" +- reg: base addresses and lengths of the PCIe controller register blocks. +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + "intr": The interrupt that is asserted for controller interrupts +- fsl,pcie-scfg: Must include two entries. + The first entry must be a link to the SCFG device node + The second entry must be '0' or '1' based on physical PCIe controller index. + This is used to get SCFG PEXN registers +- dma-coherent: Indicates that the hardware IP block can ensure the coherency + of the data transferred from/to the IP block. This can avoid the software + cache flush/invalid actions, and improve the performance significantly. + +Example: + + pcie@3400000 { + compatible = "fsl,ls1021a-pcie", "snps,dw-pcie"; + reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ + 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; + interrupts = ; /* controller interrupt */ + interrupt-names = "intr"; + fsl,pcie-scfg = <&scfg 0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + dma-coherent; + num-lanes = <4>; + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0xc2000000 0x0 0x20000000 0x40 0x20000000 0x0 0x20000000 /* prefetchable memory */ + 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>, + <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/mediatek-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/mediatek-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..20227a875ac8f253adf2e91b5d795bf5db793bf5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/mediatek-pcie.txt @@ -0,0 +1,279 @@ +MediaTek Gen2 PCIe controller + +Required properties: +- compatible: Should contain one of the following strings: + "mediatek,mt2701-pcie" + "mediatek,mt2712-pcie" + "mediatek,mt7622-pcie" + "mediatek,mt7623-pcie" +- device_type: Must be "pci" +- reg: Base addresses and lengths of the PCIe subsys and root ports. +- reg-names: Names of the above areas to use during resource lookup. +- #address-cells: Address representation for root ports (must be 3) +- #size-cells: Size representation for root ports (must be 2) +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: + Mandatory entries: + - sys_ckN :transaction layer and data link layer clock + Required entries for MT2701/MT7623: + - free_ck :for reference clock of PCIe subsys + Required entries for MT2712/MT7622: + - ahb_ckN :AHB slave interface operating clock for CSR access and RC + initiated MMIO access + Required entries for MT7622: + - axi_ckN :application layer MMIO channel operating clock + - aux_ckN :pe2_mac_bridge and pe2_mac_core operating clock when + pcie_mac_ck/pcie_pipe_ck is turned off + - obff_ckN :OBFF functional block operating clock + - pipe_ckN :LTSSM and PHY/MAC layer operating clock + where N starting from 0 to one less than the number of root ports. +- phys: List of PHY specifiers (used by generic PHY framework). +- phy-names : Must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the + number of PHYs as specified in *phys* property. +- power-domains: A phandle and power domain specifier pair to the power domain + which is responsible for collapsing and restoring power to the peripheral. +- bus-range: Range of bus numbers associated with this controller. +- ranges: Ranges for the PCI memory and I/O regions. + +Required properties for MT7623/MT2701: +- #interrupt-cells: Size representation for interrupts (must be 1) +- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties + Please refer to the standard PCI bus binding document for a more detailed + explanation. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must be "pcie-rst0", "pcie-rst1", "pcie-rstN".. based on the + number of root ports. + +Required properties for MT2712/MT7622: +-interrupts: A list of interrupt outputs of the controller, must have one + entry for each PCIe port + +In addition, the device tree node must have sub-nodes describing each +PCIe port interface, having the following mandatory properties: + +Required properties: +- device_type: Must be "pci" +- reg: Only the first four bytes are used to refer to the correct bus number + and device number. +- #address-cells: Must be 3 +- #size-cells: Must be 2 +- #interrupt-cells: Must be 1 +- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties + Please refer to the standard PCI bus binding document for a more detailed + explanation. +- ranges: Sub-ranges distributed from the PCIe controller node. An empty + property is sufficient. +- num-lanes: Number of lanes to use for this port. + +Examples for MT7623: + + hifsys: syscon@1a000000 { + compatible = "mediatek,mt7623-hifsys", + "mediatek,mt2701-hifsys", + "syscon"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + pcie: pcie@1a140000 { + compatible = "mediatek,mt7623-pcie"; + device_type = "pci"; + reg = <0 0x1a140000 0 0x1000>, /* PCIe shared registers */ + <0 0x1a142000 0 0x1000>, /* Port0 registers */ + <0 0x1a143000 0 0x1000>, /* Port1 registers */ + <0 0x1a144000 0 0x1000>; /* Port2 registers */ + reg-names = "subsys", "port0", "port1", "port2"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xf800 0 0 0>; + interrupt-map = <0x0000 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>, + <0x0800 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>, + <0x1000 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>; + clocks = <&topckgen CLK_TOP_ETHIF_SEL>, + <&hifsys CLK_HIFSYS_PCIE0>, + <&hifsys CLK_HIFSYS_PCIE1>, + <&hifsys CLK_HIFSYS_PCIE2>; + clock-names = "free_ck", "sys_ck0", "sys_ck1", "sys_ck2"; + resets = <&hifsys MT2701_HIFSYS_PCIE0_RST>, + <&hifsys MT2701_HIFSYS_PCIE1_RST>, + <&hifsys MT2701_HIFSYS_PCIE2_RST>; + reset-names = "pcie-rst0", "pcie-rst1", "pcie-rst2"; + phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>, + <&pcie2_phy PHY_TYPE_PCIE>; + phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_HIF>; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0 0x1a160000 0 0x1a160000 0 0x00010000 /* I/O space */ + 0x83000000 0 0x60000000 0 0x60000000 0 0x10000000>; /* memory space */ + + pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 193 IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + }; + + pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 194 IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + }; + + pcie@2,0 { + reg = <0x1000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &sysirq GIC_SPI 195 IRQ_TYPE_LEVEL_LOW>; + ranges; + num-lanes = <1>; + }; + }; + +Examples for MT2712: + + pcie: pcie@11700000 { + compatible = "mediatek,mt2712-pcie"; + device_type = "pci"; + reg = <0 0x11700000 0 0x1000>, + <0 0x112ff000 0 0x1000>; + reg-names = "port0", "port1"; + #address-cells = <3>; + #size-cells = <2>; + interrupts = , + ; + clocks = <&topckgen CLK_TOP_PE2_MAC_P0_SEL>, + <&topckgen CLK_TOP_PE2_MAC_P1_SEL>, + <&pericfg CLK_PERI_PCIE0>, + <&pericfg CLK_PERI_PCIE1>; + clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1"; + phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>; + phy-names = "pcie-phy0", "pcie-phy1"; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; + + pcie0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, + <0 0 0 3 &pcie_intc0 2>, + <0 0 0 4 &pcie_intc0 3>; + pcie_intc0: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pcie1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; + pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; + +Examples for MT7622: + + pcie: pcie@1a140000 { + compatible = "mediatek,mt7622-pcie"; + device_type = "pci"; + reg = <0 0x1a140000 0 0x1000>, + <0 0x1a143000 0 0x1000>, + <0 0x1a145000 0 0x1000>; + reg-names = "subsys", "port0", "port1"; + #address-cells = <3>; + #size-cells = <2>; + interrupts = , + ; + clocks = <&pciesys CLK_PCIE_P0_MAC_EN>, + <&pciesys CLK_PCIE_P1_MAC_EN>, + <&pciesys CLK_PCIE_P0_AHB_EN>, + <&pciesys CLK_PCIE_P1_AHB_EN>, + <&pciesys CLK_PCIE_P0_AUX_EN>, + <&pciesys CLK_PCIE_P1_AUX_EN>, + <&pciesys CLK_PCIE_P0_AXI_EN>, + <&pciesys CLK_PCIE_P1_AXI_EN>, + <&pciesys CLK_PCIE_P0_OBFF_EN>, + <&pciesys CLK_PCIE_P1_OBFF_EN>, + <&pciesys CLK_PCIE_P0_PIPE_EN>, + <&pciesys CLK_PCIE_P1_PIPE_EN>; + clock-names = "sys_ck0", "sys_ck1", "ahb_ck0", "ahb_ck1", + "aux_ck0", "aux_ck1", "axi_ck0", "axi_ck1", + "obff_ck0", "obff_ck1", "pipe_ck0", "pipe_ck1"; + phys = <&pcie0_phy PHY_TYPE_PCIE>, <&pcie1_phy PHY_TYPE_PCIE>; + phy-names = "pcie-phy0", "pcie-phy1"; + power-domains = <&scpsys MT7622_POWER_DOMAIN_HIF0>; + bus-range = <0x00 0xff>; + ranges = <0x82000000 0 0x20000000 0x0 0x20000000 0 0x10000000>; + + pcie0: pcie@0,0 { + reg = <0x0000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, + <0 0 0 3 &pcie_intc0 2>, + <0 0 0 4 &pcie_intc0 3>; + pcie_intc0: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + pcie1: pcie@1,0 { + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges; + num-lanes = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; + pcie_intc1: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/mobiveil-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/mobiveil-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..a618d4787dd786b18d9aeb29139f9b69576b7e0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/mobiveil-pcie.txt @@ -0,0 +1,70 @@ +* Mobiveil AXI PCIe Root Port Bridge DT description + +Mobiveil's GPEX 4.0 is a PCIe Gen4 root port bridge IP. This configurable IP +has up to 8 outbound and inbound windows for the address translation. + +Required properties: +- #address-cells: Address representation for root ports, set to <3> +- #size-cells: Size representation for root ports, set to <2> +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. +- compatible: Should contain "mbvl,gpex40-pcie" +- reg: Should contain PCIe registers location and length + "config_axi_slave": PCIe controller registers + "csr_axi_slave" : Bridge config registers + "gpio_slave" : GPIO registers to control slot power + "apb_csr" : MSI registers + +- device_type: must be "pci" +- apio-wins : number of requested apio outbound windows + default 2 outbound windows are configured - + 1. Config window + 2. Memory window +- ppio-wins : number of requested ppio inbound windows + default 1 inbound memory window is configured. +- bus-range: PCI bus numbers covered +- interrupt-controller: identifies the node as an interrupt controller +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. +- interrupts: The interrupt line of the PCIe controller + last cell of this field is set to 4 to + denote it as IRQ_TYPE_LEVEL_HIGH type interrupt. +- interrupt-map-mask, + interrupt-map: standard PCI properties to define the mapping of the + PCI interface to interrupt numbers. +- ranges: ranges for the PCI memory regions (I/O space region is not + supported by hardware) + Please refer to the standard PCI bus binding document for a more + detailed explanation + + +Example: +++++++++ + pcie0: pcie@a0000000 { + #address-cells = <3>; + #size-cells = <2>; + compatible = "mbvl,gpex40-pcie"; + reg = <0xa0000000 0x00001000>, + <0xb0000000 0x00010000>, + <0xff000000 0x00200000>, + <0xb0010000 0x00001000>; + reg-names = "config_axi_slave", + "csr_axi_slave", + "gpio_slave", + "apb_csr"; + device_type = "pci"; + apio-wins = <2>; + ppio-wins = <1>; + bus-range = <0x00000000 0x000000ff>; + interrupt-controller; + interrupt-parent = <&gic>; + #interrupt-cells = <1>; + interrupts = < 0 89 4 >; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 0 &pci_express 0>, + <0 0 0 1 &pci_express 1>, + <0 0 0 2 &pci_express 2>, + <0 0 0 3 &pci_express 3>; + ranges = < 0x83000000 0 0x00000000 0xa8000000 0 0x8000000>; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/mvebu-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/mvebu-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..6173af6885f86731a9e81182737afc0a185cd212 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/mvebu-pci.txt @@ -0,0 +1,294 @@ +* Marvell EBU PCIe interfaces + +Mandatory properties: + +- compatible: one of the following values: + marvell,armada-370-pcie + marvell,armada-xp-pcie + marvell,dove-pcie + marvell,kirkwood-pcie +- #address-cells, set to <3> +- #size-cells, set to <2> +- #interrupt-cells, set to <1> +- bus-range: PCI bus numbers covered +- device_type, set to "pci" +- ranges: ranges describing the MMIO registers to control the PCIe + interfaces, and ranges describing the MBus windows needed to access + the memory and I/O regions of each PCIe interface. +- msi-parent: Link to the hardware entity that serves as the Message + Signaled Interrupt controller for this PCI controller. + +The ranges describing the MMIO registers have the following layout: + + 0x82000000 0 r MBUS_ID(0xf0, 0x01) r 0 s + +where: + + * r is a 32-bits value that gives the offset of the MMIO + registers of this PCIe interface, from the base of the internal + registers. + + * s is a 32-bits value that give the size of this MMIO + registers area. This range entry translates the '0x82000000 0 r' PCI + address into the 'MBUS_ID(0xf0, 0x01) r' CPU address, which is part + of the internal register window (as identified by MBUS_ID(0xf0, + 0x01)). + +The ranges describing the MBus windows have the following layout: + + 0x8t000000 s 0 MBUS_ID(w, a) 0 1 0 + +where: + + * t is the type of the MBus window (as defined by the standard PCI DT + bindings), 1 for I/O and 2 for memory. + + * s is the PCI slot that corresponds to this PCIe interface + + * w is the 'target ID' value for the MBus window + + * a the 'attribute' value for the MBus window. + +Since the location and size of the different MBus windows is not fixed in +hardware, and only determined in runtime, those ranges cover the full first +4 GB of the physical address space, and do not translate into a valid CPU +address. + +In addition, the device tree node must have sub-nodes describing each +PCIe interface, having the following mandatory properties: + +- reg: used only for interrupt mapping, so only the first four bytes + are used to refer to the correct bus number and device number. +- assigned-addresses: reference to the MMIO registers used to control + this PCIe interface. +- clocks: the clock associated to this PCIe interface +- marvell,pcie-port: the physical PCIe port number +- status: either "disabled" or "okay" +- device_type, set to "pci" +- #address-cells, set to <3> +- #size-cells, set to <2> +- #interrupt-cells, set to <1> +- ranges, translating the MBus windows ranges of the parent node into + standard PCI addresses. +- interrupt-map-mask and interrupt-map, standard PCI properties to + define the mapping of the PCIe interface to interrupt numbers. + +and the following optional properties: +- marvell,pcie-lane: the physical PCIe lane number, for ports having + multiple lanes. If this property is not found, we assume that the + value is 0. +- reset-gpios: optional GPIO to PERST# +- reset-delay-us: delay in us to wait after reset de-assertion, if not + specified will default to 100ms, as required by the PCIe specification. + +Example: + +pcie-controller { + compatible = "marvell,armada-xp-pcie"; + device_type = "pci"; + + #address-cells = <3>; + #size-cells = <2>; + + bus-range = <0x00 0xff>; + msi-parent = <&mpic>; + + ranges = + <0x82000000 0 0x40000 MBUS_ID(0xf0, 0x01) 0x40000 0 0x00002000 /* Port 0.0 registers */ + 0x82000000 0 0x42000 MBUS_ID(0xf0, 0x01) 0x42000 0 0x00002000 /* Port 2.0 registers */ + 0x82000000 0 0x44000 MBUS_ID(0xf0, 0x01) 0x44000 0 0x00002000 /* Port 0.1 registers */ + 0x82000000 0 0x48000 MBUS_ID(0xf0, 0x01) 0x48000 0 0x00002000 /* Port 0.2 registers */ + 0x82000000 0 0x4c000 MBUS_ID(0xf0, 0x01) 0x4c000 0 0x00002000 /* Port 0.3 registers */ + 0x82000000 0 0x80000 MBUS_ID(0xf0, 0x01) 0x80000 0 0x00002000 /* Port 1.0 registers */ + 0x82000000 0 0x82000 MBUS_ID(0xf0, 0x01) 0x82000 0 0x00002000 /* Port 3.0 registers */ + 0x82000000 0 0x84000 MBUS_ID(0xf0, 0x01) 0x84000 0 0x00002000 /* Port 1.1 registers */ + 0x82000000 0 0x88000 MBUS_ID(0xf0, 0x01) 0x88000 0 0x00002000 /* Port 1.2 registers */ + 0x82000000 0 0x8c000 MBUS_ID(0xf0, 0x01) 0x8c000 0 0x00002000 /* Port 1.3 registers */ + 0x82000000 0x1 0 MBUS_ID(0x04, 0xe8) 0 1 0 /* Port 0.0 MEM */ + 0x81000000 0x1 0 MBUS_ID(0x04, 0xe0) 0 1 0 /* Port 0.0 IO */ + 0x82000000 0x2 0 MBUS_ID(0x04, 0xd8) 0 1 0 /* Port 0.1 MEM */ + 0x81000000 0x2 0 MBUS_ID(0x04, 0xd0) 0 1 0 /* Port 0.1 IO */ + 0x82000000 0x3 0 MBUS_ID(0x04, 0xb8) 0 1 0 /* Port 0.2 MEM */ + 0x81000000 0x3 0 MBUS_ID(0x04, 0xb0) 0 1 0 /* Port 0.2 IO */ + 0x82000000 0x4 0 MBUS_ID(0x04, 0x78) 0 1 0 /* Port 0.3 MEM */ + 0x81000000 0x4 0 MBUS_ID(0x04, 0x70) 0 1 0 /* Port 0.3 IO */ + + 0x82000000 0x5 0 MBUS_ID(0x08, 0xe8) 0 1 0 /* Port 1.0 MEM */ + 0x81000000 0x5 0 MBUS_ID(0x08, 0xe0) 0 1 0 /* Port 1.0 IO */ + 0x82000000 0x6 0 MBUS_ID(0x08, 0xd8) 0 1 0 /* Port 1.1 MEM */ + 0x81000000 0x6 0 MBUS_ID(0x08, 0xd0) 0 1 0 /* Port 1.1 IO */ + 0x82000000 0x7 0 MBUS_ID(0x08, 0xb8) 0 1 0 /* Port 1.2 MEM */ + 0x81000000 0x7 0 MBUS_ID(0x08, 0xb0) 0 1 0 /* Port 1.2 IO */ + 0x82000000 0x8 0 MBUS_ID(0x08, 0x78) 0 1 0 /* Port 1.3 MEM */ + 0x81000000 0x8 0 MBUS_ID(0x08, 0x70) 0 1 0 /* Port 1.3 IO */ + + 0x82000000 0x9 0 MBUS_ID(0x04, 0xf8) 0 1 0 /* Port 2.0 MEM */ + 0x81000000 0x9 0 MBUS_ID(0x04, 0xf0) 0 1 0 /* Port 2.0 IO */ + + 0x82000000 0xa 0 MBUS_ID(0x08, 0xf8) 0 1 0 /* Port 3.0 MEM */ + 0x81000000 0xa 0 MBUS_ID(0x08, 0xf0) 0 1 0 /* Port 3.0 IO */>; + + pcie@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x40000 0 0x2000>; + reg = <0x0800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x1 0 1 0 + 0x81000000 0 0 0x81000000 0x1 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 58>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <0>; + /* low-active PERST# reset on GPIO 25 */ + reset-gpios = <&gpio0 25 1>; + /* wait 20ms for device settle after reset deassertion */ + reset-delay-us = <20000>; + clocks = <&gateclk 5>; + }; + + pcie@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x44000 0 0x2000>; + reg = <0x1000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x2 0 1 0 + 0x81000000 0 0 0x81000000 0x2 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 59>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <1>; + clocks = <&gateclk 6>; + }; + + pcie@3,0 { + device_type = "pci"; + assigned-addresses = <0x82001800 0 0x48000 0 0x2000>; + reg = <0x1800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x3 0 1 0 + 0x81000000 0 0 0x81000000 0x3 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 60>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <2>; + clocks = <&gateclk 7>; + }; + + pcie@4,0 { + device_type = "pci"; + assigned-addresses = <0x82002000 0 0x4c000 0 0x2000>; + reg = <0x2000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x4 0 1 0 + 0x81000000 0 0 0x81000000 0x4 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 61>; + marvell,pcie-port = <0>; + marvell,pcie-lane = <3>; + clocks = <&gateclk 8>; + }; + + pcie@5,0 { + device_type = "pci"; + assigned-addresses = <0x82002800 0 0x80000 0 0x2000>; + reg = <0x2800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x5 0 1 0 + 0x81000000 0 0 0x81000000 0x5 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 62>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <0>; + clocks = <&gateclk 9>; + }; + + pcie@6,0 { + device_type = "pci"; + assigned-addresses = <0x82003000 0 0x84000 0 0x2000>; + reg = <0x3000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x6 0 1 0 + 0x81000000 0 0 0x81000000 0x6 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 63>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <1>; + clocks = <&gateclk 10>; + }; + + pcie@7,0 { + device_type = "pci"; + assigned-addresses = <0x82003800 0 0x88000 0 0x2000>; + reg = <0x3800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x7 0 1 0 + 0x81000000 0 0 0x81000000 0x7 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 64>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <2>; + clocks = <&gateclk 11>; + }; + + pcie@8,0 { + device_type = "pci"; + assigned-addresses = <0x82004000 0 0x8c000 0 0x2000>; + reg = <0x4000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x8 0 1 0 + 0x81000000 0 0 0x81000000 0x8 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 65>; + marvell,pcie-port = <1>; + marvell,pcie-lane = <3>; + clocks = <&gateclk 12>; + }; + + pcie@9,0 { + device_type = "pci"; + assigned-addresses = <0x82004800 0 0x42000 0 0x2000>; + reg = <0x4800 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0x9 0 1 0 + 0x81000000 0 0 0x81000000 0x9 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 99>; + marvell,pcie-port = <2>; + marvell,pcie-lane = <0>; + clocks = <&gateclk 26>; + }; + + pcie@a,0 { + device_type = "pci"; + assigned-addresses = <0x82005000 0 0x82000 0 0x2000>; + reg = <0x5000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + ranges = <0x82000000 0 0 0x82000000 0xa 0 1 0 + 0x81000000 0 0 0x81000000 0xa 0 1 0>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &mpic 103>; + marvell,pcie-port = <3>; + marvell,pcie-lane = <0>; + clocks = <&gateclk 27>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/nvidia,tegra20-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/nvidia,tegra20-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..145a4f04194fa053f069e478bad6f0a59feb00b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/nvidia,tegra20-pcie.txt @@ -0,0 +1,674 @@ +NVIDIA Tegra PCIe controller + +Required properties: +- compatible: Must be: + - "nvidia,tegra20-pcie": for Tegra20 + - "nvidia,tegra30-pcie": for Tegra30 + - "nvidia,tegra124-pcie": for Tegra124 and Tegra132 + - "nvidia,tegra210-pcie": for Tegra210 + - "nvidia,tegra186-pcie": for Tegra186 +- power-domains: To ungate power partition by BPMP powergate driver. Must + contain BPMP phandle and PCIe power partition ID. This is required only + for Tegra186. +- device_type: Must be "pci" +- reg: A list of physical base address and length for each set of controller + registers. Must contain an entry for each entry in the reg-names property. +- reg-names: Must include the following entries: + "pads": PADS registers + "afi": AFI registers + "cs": configuration space region +- interrupts: A list of interrupt outputs of the controller. Must contain an + entry for each entry in the interrupt-names property. +- interrupt-names: Must include the following entries: + "intr": The Tegra interrupt that is asserted for controller interrupts + "msi": The Tegra interrupt that is asserted when an MSI is received +- bus-range: Range of bus numbers associated with this controller +- #address-cells: Address representation for root ports (must be 3) + - cell 0 specifies the bus and device numbers of the root port: + [23:16]: bus number + [15:11]: device number + - cell 1 denotes the upper 32 address bits and should be 0 + - cell 2 contains the lower 32 address bits and is used to translate to the + CPU address space +- #size-cells: Size representation for root ports (must be 2) +- ranges: Describes the translation of addresses for root ports and standard + PCI regions. The entries must be 6 cells each, where the first three cells + correspond to the address as described for the #address-cells property + above, the fourth cell is the physical CPU address to translate to and the + fifth and six cells are as described for the #size-cells property above. + - The first two entries are expected to translate the addresses for the root + port registers, which are referenced by the assigned-addresses property of + the root port nodes (see below). + - The remaining entries setup the mapping for the standard I/O, memory and + prefetchable PCI regions. The first cell determines the type of region + that is setup: + - 0x81000000: I/O memory region + - 0x82000000: non-prefetchable memory region + - 0xc2000000: prefetchable memory region + Please refer to the standard PCI bus binding document for a more detailed + explanation. +- #interrupt-cells: Size representation for interrupts (must be 1) +- interrupt-map-mask and interrupt-map: Standard PCI IRQ mapping properties + Please refer to the standard PCI bus binding document for a more detailed + explanation. +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - pex + - afi + - pll_e + - cml (not required for Tegra20) +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - pex + - afi + - pcie_x + +Required properties on Tegra124 and later (deprecated): +- phys: Must contain an entry for each entry in phy-names. +- phy-names: Must include the following entries: + - pcie + +These properties are deprecated in favour of per-lane PHYs define in each of +the root ports (see below). + +Power supplies for Tegra20: +- avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V. +- vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. +- avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must + supply 1.05 V. +- avdd-plle-supply: Power supply for PLLE, which is shared with SATA. Must + supply 1.05 V. +- vddio-pex-clk-supply: Power supply for PCIe clock. Must supply 3.3 V. + +Power supplies for Tegra30: +- Required: + - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must + supply 1.05 V. + - avdd-plle-supply: Power supply for PLLE, which is shared with SATA. Must + supply 1.05 V. + - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must + supply 1.8 V. + - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks. + Must supply 3.3 V. +- Optional: + - If lanes 0 to 3 are used: + - avdd-pexa-supply: Power supply for analog PCIe logic. Must supply 1.05 V. + - vdd-pexa-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. + - If lanes 4 or 5 are used: + - avdd-pexb-supply: Power supply for analog PCIe logic. Must supply 1.05 V. + - vdd-pexb-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. + +Power supplies for Tegra124: +- Required: + - avddio-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V. + - dvddio-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. + - avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must + supply 1.05 V. + - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks. + Must supply 3.3 V. + - hvdd-pex-pll-e-supply: High-voltage supply for PLLE (shared with USB3). + Must supply 3.3 V. + - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must + supply 2.8-3.3 V. + - avdd-pll-erefe-supply: Power supply for PLLE (shared with USB3). Must + supply 1.05 V. + +Power supplies for Tegra210: +- Required: + - avdd-pll-uerefe-supply: Power supply for PLLE (shared with USB3). Must + supply 1.05 V. + - hvddio-pex-supply: High-voltage supply for PCIe I/O and PCIe output + clocks. Must supply 1.8 V. + - dvddio-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. + - dvdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must + supply 1.05 V. + - hvdd-pex-pll-e-supply: High-voltage supply for PLLE (shared with USB3). + Must supply 3.3 V. + - vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must + supply 1.8 V. + +Power supplies for Tegra186: +- Required: + - dvdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V. + - hvdd-pex-pll-supply: High-voltage supply for PLLE (shared with USB3). Must + supply 1.8 V. + - hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks. + Must supply 1.8 V. + - vddio-pexctl-aud-supply: Power supply for PCIe side band signals. Must + supply 1.8 V. + +Root ports are defined as subnodes of the PCIe controller node. + +Required properties: +- device_type: Must be "pci" +- assigned-addresses: Address and size of the port configuration registers +- reg: PCI bus address of the root port +- #address-cells: Must be 3 +- #size-cells: Must be 2 +- ranges: Sub-ranges distributed from the PCIe controller node. An empty + property is sufficient. +- nvidia,num-lanes: Number of lanes to use for this port. Valid combinations + are: + - Root port 0 uses 4 lanes, root port 1 is unused. + - Both root ports use 2 lanes. + +Required properties for Tegra124 and later: +- phys: Must contain an phandle to a PHY for each entry in phy-names. +- phy-names: Must include an entry for each active lane. Note that the number + of entries does not have to (though usually will) be equal to the specified + number of lanes in the nvidia,num-lanes property. Entries are of the form + "pcie-N": where N ranges from 0 to the value specified in nvidia,num-lanes. + +Examples: +========= + +Tegra20: +-------- + +SoC DTSI: + + pcie-controller@80003000 { + compatible = "nvidia,tegra20-pcie"; + device_type = "pci"; + reg = <0x80003000 0x00000800 /* PADS registers */ + 0x80003800 0x00000200 /* AFI registers */ + 0x90000000 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + interrupts = <0 98 0x04 /* controller interrupt */ + 0 99 0x04>; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x80000000 0x80000000 0 0x00001000 /* port 0 registers */ + 0x82000000 0 0x80001000 0x80001000 0 0x00001000 /* port 1 registers */ + 0x81000000 0 0 0x82000000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0xa0000000 0xa0000000 0 0x10000000 /* non-prefetchable memory */ + 0xc2000000 0 0xb0000000 0xb0000000 0 0x10000000>; /* prefetchable memory */ + + clocks = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 118>; + clock-names = "pex", "afi", "pll_e"; + resets = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x80000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + + ranges; + + nvidia,num-lanes = <2>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x80001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + + ranges; + + nvidia,num-lanes = <2>; + }; + }; + +Board DTS: + + pcie-controller@80003000 { + status = "okay"; + + vdd-supply = <&pci_vdd_reg>; + pex-clk-supply = <&pci_clk_reg>; + + /* root port 00:01.0 */ + pci@1,0 { + status = "okay"; + + /* bridge 01:00.0 (optional) */ + pci@0,0 { + reg = <0x010000 0 0 0 0>; + + #address-cells = <3>; + #size-cells = <2>; + + device_type = "pci"; + + /* endpoint 02:00.0 */ + pci@0,0 { + reg = <0x020000 0 0 0 0>; + }; + }; + }; + }; + +Note that devices on the PCI bus are dynamically discovered using PCI's bus +enumeration and therefore don't need corresponding device nodes in DT. However +if a device on the PCI bus provides a non-probeable bus such as I2C or SPI, +device nodes need to be added in order to allow the bus' children to be +instantiated at the proper location in the operating system's device tree (as +illustrated by the optional nodes in the example above). + +Tegra30: +-------- + +SoC DTSI: + + pcie-controller@3000 { + compatible = "nvidia,tegra30-pcie"; + device_type = "pci"; + reg = <0x00003000 0x00000800 /* PADS registers */ + 0x00003800 0x00000200 /* AFI registers */ + 0x10000000 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + interrupts = ; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x00000000 0x00000000 0 0x00001000 /* port 0 configuration space */ + 0x82000000 0 0x00001000 0x00001000 0 0x00001000 /* port 1 configuration space */ + 0x82000000 0 0x00004000 0x00004000 0 0x00001000 /* port 2 configuration space */ + 0x81000000 0 0 0x02000000 0 0x00010000 /* downstream I/O */ + 0x82000000 0 0x20000000 0x20000000 0 0x08000000 /* non-prefetchable memory */ + 0xc2000000 0 0x28000000 0x28000000 0 0x18000000>; /* prefetchable memory */ + + clocks = <&tegra_car TEGRA30_CLK_PCIE>, + <&tegra_car TEGRA30_CLK_AFI>, + <&tegra_car TEGRA30_CLK_PLL_E>, + <&tegra_car TEGRA30_CLK_CML0>; + clock-names = "pex", "afi", "pll_e", "cml"; + resets = <&tegra_car 70>, + <&tegra_car 72>, + <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x00000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <2>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x00001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <2>; + }; + + pci@3,0 { + device_type = "pci"; + assigned-addresses = <0x82001800 0 0x00004000 0 0x1000>; + reg = <0x001800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <2>; + }; + }; + +Board DTS: + + pcie-controller@3000 { + status = "okay"; + + avdd-pexa-supply = <&ldo1_reg>; + vdd-pexa-supply = <&ldo1_reg>; + avdd-pexb-supply = <&ldo1_reg>; + vdd-pexb-supply = <&ldo1_reg>; + avdd-pex-pll-supply = <&ldo1_reg>; + avdd-plle-supply = <&ldo1_reg>; + vddio-pex-ctl-supply = <&sys_3v3_reg>; + hvdd-pex-supply = <&sys_3v3_pexs_reg>; + + pci@1,0 { + status = "okay"; + }; + + pci@3,0 { + status = "okay"; + }; + }; + +Tegra124: +--------- + +SoC DTSI: + + pcie-controller@1003000 { + compatible = "nvidia,tegra124-pcie"; + device_type = "pci"; + reg = <0x0 0x01003000 0x0 0x00000800 /* PADS registers */ + 0x0 0x01003800 0x0 0x00000800 /* AFI registers */ + 0x0 0x02000000 0x0 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + interrupts = , /* controller interrupt */ + ; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x01000000 0x0 0x01000000 0 0x00001000 /* port 0 configuration space */ + 0x82000000 0 0x01001000 0x0 0x01001000 0 0x00001000 /* port 1 configuration space */ + 0x81000000 0 0x0 0x0 0x12000000 0 0x00010000 /* downstream I/O (64 KiB) */ + 0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000 /* non-prefetchable memory (208 MiB) */ + 0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */ + + clocks = <&tegra_car TEGRA124_CLK_PCIE>, + <&tegra_car TEGRA124_CLK_AFI>, + <&tegra_car TEGRA124_CLK_PLL_E>, + <&tegra_car TEGRA124_CLK_CML0>; + clock-names = "pex", "afi", "pll_e", "cml"; + resets = <&tegra_car 70>, + <&tegra_car 72>, + <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x01000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <2>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x01001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + }; + +Board DTS: + + pcie-controller@1003000 { + status = "okay"; + + avddio-pex-supply = <&vdd_1v05_run>; + dvddio-pex-supply = <&vdd_1v05_run>; + avdd-pex-pll-supply = <&vdd_1v05_run>; + hvdd-pex-supply = <&vdd_3v3_lp0>; + hvdd-pex-pll-e-supply = <&vdd_3v3_lp0>; + vddio-pex-ctl-supply = <&vdd_3v3_lp0>; + avdd-pll-erefe-supply = <&avdd_1v05_run>; + + /* Mini PCIe */ + pci@1,0 { + phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-4}>; + phy-names = "pcie-0"; + status = "okay"; + }; + + /* Gigabit Ethernet */ + pci@2,0 { + phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>; + phy-names = "pcie-0"; + status = "okay"; + }; + }; + +Tegra210: +--------- + +SoC DTSI: + + pcie-controller@1003000 { + compatible = "nvidia,tegra210-pcie"; + device_type = "pci"; + reg = <0x0 0x01003000 0x0 0x00000800 /* PADS registers */ + 0x0 0x01003800 0x0 0x00000800 /* AFI registers */ + 0x0 0x02000000 0x0 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + interrupts = , /* controller interrupt */ + ; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x01000000 0x0 0x01000000 0 0x00001000 /* port 0 configuration space */ + 0x82000000 0 0x01001000 0x0 0x01001000 0 0x00001000 /* port 1 configuration space */ + 0x81000000 0 0x0 0x0 0x12000000 0 0x00010000 /* downstream I/O (64 KiB) */ + 0x82000000 0 0x13000000 0x0 0x13000000 0 0x0d000000 /* non-prefetchable memory (208 MiB) */ + 0xc2000000 0 0x20000000 0x0 0x20000000 0 0x20000000>; /* prefetchable memory (512 MiB) */ + + clocks = <&tegra_car TEGRA210_CLK_PCIE>, + <&tegra_car TEGRA210_CLK_AFI>, + <&tegra_car TEGRA210_CLK_PLL_E>, + <&tegra_car TEGRA210_CLK_CML0>; + clock-names = "pex", "afi", "pll_e", "cml"; + resets = <&tegra_car 70>, + <&tegra_car 72>, + <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x01000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <4>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x01001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + }; + +Board DTS: + + pcie-controller@1003000 { + status = "okay"; + + avdd-pll-uerefe-supply = <&avdd_1v05_pll>; + hvddio-pex-supply = <&vdd_1v8>; + dvddio-pex-supply = <&vdd_pex_1v05>; + dvdd-pex-pll-supply = <&vdd_pex_1v05>; + hvdd-pex-pll-e-supply = <&vdd_1v8>; + vddio-pex-ctl-supply = <&vdd_1v8>; + + pci@1,0 { + phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>, + <&{/padctl@7009f000/pads/pcie/lanes/pcie-1}>, + <&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>, + <&{/padctl@7009f000/pads/pcie/lanes/pcie-3}>; + phy-names = "pcie-0", "pcie-1", "pcie-2", "pcie-3"; + status = "okay"; + }; + + pci@2,0 { + phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-4}>; + phy-names = "pcie-0"; + status = "okay"; + }; + }; + +Tegra186: +--------- + +SoC DTSI: + + pcie@10003000 { + compatible = "nvidia,tegra186-pcie"; + power-domains = <&bpmp TEGRA186_POWER_DOMAIN_PCX>; + device_type = "pci"; + reg = <0x0 0x10003000 0x0 0x00000800 /* PADS registers */ + 0x0 0x10003800 0x0 0x00000800 /* AFI registers */ + 0x0 0x40000000 0x0 0x10000000>; /* configuration space */ + reg-names = "pads", "afi", "cs"; + + interrupts = , /* controller interrupt */ + ; /* MSI interrupt */ + interrupt-names = "intr", "msi"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + + bus-range = <0x00 0xff>; + #address-cells = <3>; + #size-cells = <2>; + + ranges = <0x82000000 0 0x10000000 0x0 0x10000000 0 0x00001000 /* port 0 configuration space */ + 0x82000000 0 0x10001000 0x0 0x10001000 0 0x00001000 /* port 1 configuration space */ + 0x82000000 0 0x10004000 0x0 0x10004000 0 0x00001000 /* port 2 configuration space */ + 0x81000000 0 0x0 0x0 0x50000000 0 0x00010000 /* downstream I/O (64 KiB) */ + 0x82000000 0 0x50100000 0x0 0x50100000 0 0x07F00000 /* non-prefetchable memory (127 MiB) */ + 0xc2000000 0 0x58000000 0x0 0x58000000 0 0x28000000>; /* prefetchable memory (640 MiB) */ + + clocks = <&bpmp TEGRA186_CLK_AFI>, + <&bpmp TEGRA186_CLK_PCIE>, + <&bpmp TEGRA186_CLK_PLLE>; + clock-names = "afi", "pex", "pll_e"; + + resets = <&bpmp TEGRA186_RESET_AFI>, + <&bpmp TEGRA186_RESET_PCIE>, + <&bpmp TEGRA186_RESET_PCIEXCLK>; + reset-names = "afi", "pex", "pcie_x"; + + status = "disabled"; + + pci@1,0 { + device_type = "pci"; + assigned-addresses = <0x82000800 0 0x10000000 0 0x1000>; + reg = <0x000800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <2>; + }; + + pci@2,0 { + device_type = "pci"; + assigned-addresses = <0x82001000 0 0x10001000 0 0x1000>; + reg = <0x001000 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + + pci@3,0 { + device_type = "pci"; + assigned-addresses = <0x82001800 0 0x10004000 0 0x1000>; + reg = <0x001800 0 0 0 0>; + status = "disabled"; + + #address-cells = <3>; + #size-cells = <2>; + ranges; + + nvidia,num-lanes = <1>; + }; + }; + +Board DTS: + + pcie@10003000 { + status = "okay"; + + dvdd-pex-supply = <&vdd_pex>; + hvdd-pex-pll-supply = <&vdd_1v8>; + hvdd-pex-supply = <&vdd_1v8>; + vddio-pexctl-aud-supply = <&vdd_1v8>; + + pci@1,0 { + nvidia,num-lanes = <4>; + status = "okay"; + }; + + pci@2,0 { + nvidia,num-lanes = <0>; + status = "disabled"; + }; + + pci@3,0 { + nvidia,num-lanes = <1>; + status = "disabled"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-armada8k.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-armada8k.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e3fc15e1af88d0853e07b78ebc0b5e62a9d064a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-armada8k.txt @@ -0,0 +1,40 @@ +* Marvell Armada 7K/8K PCIe interface + +This PCIe host controller is based on the Synopsys DesignWare PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: "marvell,armada8k-pcie" +- reg: must contain two register regions + - the control register region + - the config space region +- reg-names: + - "ctrl" for the control register region + - "config" for the config space region +- interrupts: Interrupt specifier for the PCIe controler +- clocks: reference to the PCIe controller clocks +- clock-names: mandatory if there is a second clock, in this case the + name must be "core" for the first clock and "reg" for the second + one + +Example: + + pcie@f2600000 { + compatible = "marvell,armada8k-pcie", "snps,dw-pcie"; + reg = <0 0xf2600000 0 0x10000>, <0 0xf6f00000 0 0x80000>; + reg-names = "ctrl", "config"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + device_type = "pci"; + dma-coherent; + + bus-range = <0 0xff>; + ranges = <0x81000000 0 0xf9000000 0 0xf9000000 0 0x10000 /* downstream I/O */ + 0x82000000 0 0xf6000000 0 0xf6000000 0 0xf00000>; /* non-prefetchable memory */ + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; + interrupts = ; + num-lanes = <1>; + clocks = <&cpm_syscon0 1 13>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-iommu.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-iommu.txt new file mode 100644 index 0000000000000000000000000000000000000000..0def586fdcdf67df5ba3bd4c34b17bca72abd444 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-iommu.txt @@ -0,0 +1,171 @@ +This document describes the generic device tree binding for describing the +relationship between PCI(e) devices and IOMMU(s). + +Each PCI(e) device under a root complex is uniquely identified by its Requester +ID (AKA RID). A Requester ID is a triplet of a Bus number, Device number, and +Function number. + +For the purpose of this document, when treated as a numeric value, a RID is +formatted such that: + +* Bits [15:8] are the Bus number. +* Bits [7:3] are the Device number. +* Bits [2:0] are the Function number. +* Any other bits required for padding must be zero. + +IOMMUs may distinguish PCI devices through sideband data derived from the +Requester ID. While a given PCI device can only master through one IOMMU, a +root complex may split masters across a set of IOMMUs (e.g. with one IOMMU per +bus). + +The generic 'iommus' property is insufficient to describe this relationship, +and a mechanism is required to map from a PCI device to its IOMMU and sideband +data. + +For generic IOMMU bindings, see +Documentation/devicetree/bindings/iommu/iommu.txt. + + +PCI root complex +================ + +Optional properties +------------------- + +- iommu-map: Maps a Requester ID to an IOMMU and associated IOMMU specifier + data. + + The property is an arbitrary number of tuples of + (rid-base,iommu,iommu-base,length). + + Any RID r in the interval [rid-base, rid-base + length) is associated with + the listed IOMMU, with the IOMMU specifier (r - rid-base + iommu-base). + +- iommu-map-mask: A mask to be applied to each Requester ID prior to being + mapped to an IOMMU specifier per the iommu-map property. + + +Example (1) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + iommu: iommu@a { + reg = <0xa 0x1>; + compatible = "vendor,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the IOMMU is the RID, + * identity-mapped. + */ + iommu-map = <0x0 &iommu 0x0 0x10000>; + }; +}; + + +Example (2) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + iommu: iommu@a { + reg = <0xa 0x1>; + compatible = "vendor,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the IOMMU is the RID with the + * function bits masked out. + */ + iommu-map = <0x0 &iommu 0x0 0x10000>; + iommu-map-mask = <0xfff8>; + }; +}; + + +Example (3) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + iommu: iommu@a { + reg = <0xa 0x1>; + compatible = "vendor,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the IOMMU is the RID, + * but the high bits of the bus number are flipped. + */ + iommu-map = <0x0000 &iommu 0x8000 0x8000>, + <0x8000 &iommu 0x0000 0x8000>; + }; +}; + + +Example (4) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + iommu_a: iommu@a { + reg = <0xa 0x1>; + compatible = "vendor,some-iommu"; + #iommu-cells = <1>; + }; + + iommu_b: iommu@b { + reg = <0xb 0x1>; + compatible = "vendor,some-iommu"; + #iommu-cells = <1>; + }; + + iommu_c: iommu@c { + reg = <0xc 0x1>; + compatible = "vendor,some-iommu"; + #iommu-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * Devices with bus number 0-127 are mastered via IOMMU + * a, with sideband data being RID[14:0]. + * Devices with bus number 128-255 are mastered via + * IOMMU b, with sideband data being RID[14:0]. + * No devices master via IOMMU c. + */ + iommu-map = <0x0000 &iommu_a 0x0000 0x8000>, + <0x8000 &iommu_b 0x0000 0x8000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-keystone.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-keystone.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dd17de549a7880d3c43d1175e3bede131d6f68f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-keystone.txt @@ -0,0 +1,60 @@ +TI Keystone PCIe interface + +Keystone PCI host Controller is based on the Synopsys DesignWare PCI +hardware version 3.65. It shares common functions with the PCIe DesignWare +core driver and inherits common properties defined in +Documentation/devicetree/bindings/pci/designware-pcie.txt + +Please refer to Documentation/devicetree/bindings/pci/designware-pcie.txt +for the details of DesignWare DT bindings. Additional properties are +described here as well as properties that are not applicable. + +Required Properties:- + +compatibility: "ti,keystone-pcie" +reg: index 1 is the base address and length of DW application registers. + index 2 is the base address and length of PCI device ID register. + +pcie_msi_intc : Interrupt controller device node for MSI IRQ chip + interrupt-cells: should be set to 1 + interrupts: GIC interrupt lines connected to PCI MSI interrupt lines + + Example: + pcie_msi_intc: msi-interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + +pcie_intc: Interrupt controller device node for Legacy IRQ chip + interrupt-cells: should be set to 1 + + Example: + pcie_intc: legacy-interrupt-controller { + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + +Optional properties:- + phys: phandle to generic Keystone SerDes PHY for PCI + phy-names: name of the generic Keystone SerDes PHY for PCI + - If boot loader already does PCI link establishment, then phys and + phy-names shouldn't be present. + interrupts: platform interrupt for error interrupts. + +DesignWare DT Properties not applicable for Keystone PCI + +1. pcie_bus clock-names not used. Instead, a phandle to phys is used. diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-msi.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..9b3cc817d181a08f772e3ec4c51829df96f5b8ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-msi.txt @@ -0,0 +1,220 @@ +This document describes the generic device tree binding for describing the +relationship between PCI devices and MSI controllers. + +Each PCI device under a root complex is uniquely identified by its Requester ID +(AKA RID). A Requester ID is a triplet of a Bus number, Device number, and +Function number. + +For the purpose of this document, when treated as a numeric value, a RID is +formatted such that: + +* Bits [15:8] are the Bus number. +* Bits [7:3] are the Device number. +* Bits [2:0] are the Function number. +* Any other bits required for padding must be zero. + +MSIs may be distinguished in part through the use of sideband data accompanying +writes. In the case of PCI devices, this sideband data may be derived from the +Requester ID. A mechanism is required to associate a device with both the MSI +controllers it can address, and the sideband data that will be associated with +its writes to those controllers. + +For generic MSI bindings, see +Documentation/devicetree/bindings/interrupt-controller/msi.txt. + + +PCI root complex +================ + +Optional properties +------------------- + +- msi-map: Maps a Requester ID to an MSI controller and associated + msi-specifier data. The property is an arbitrary number of tuples of + (rid-base,msi-controller,msi-base,length), where: + + * rid-base is a single cell describing the first RID matched by the entry. + + * msi-controller is a single phandle to an MSI controller + + * msi-base is an msi-specifier describing the msi-specifier produced for the + first RID matched by the entry. + + * length is a single cell describing how many consecutive RIDs are matched + following the rid-base. + + Any RID r in the interval [rid-base, rid-base + length) is associated with + the listed msi-controller, with the msi-specifier (r - rid-base + msi-base). + +- msi-map-mask: A mask to be applied to each Requester ID prior to being mapped + to an msi-specifier per the msi-map property. + +- msi-parent: Describes the MSI parent of the root complex itself. Where + the root complex and MSI controller do not pass sideband data with MSI + writes, this property may be used to describe the MSI controller(s) + used by PCI devices under the root complex, if defined as such in the + binding for the root complex. + + +Example (1) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi: msi-controller@a { + reg = <0xa 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the MSI controller is + * the RID, identity-mapped. + */ + msi-map = <0x0 &msi_a 0x0 0x10000>, + }; +}; + + +Example (2) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi: msi-controller@a { + reg = <0xa 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the MSI controller is + * the RID, masked to only the device and function bits. + */ + msi-map = <0x0 &msi_a 0x0 0x100>, + msi-map-mask = <0xff> + }; +}; + + +Example (3) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi: msi-controller@a { + reg = <0xa 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the MSI controller is + * the RID, but the high bit of the bus number is + * ignored. + */ + msi-map = <0x0000 &msi 0x0000 0x8000>, + <0x8000 &msi 0x0000 0x8000>; + }; +}; + + +Example (4) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi: msi-controller@a { + reg = <0xa 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + pci: pci@f { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to the MSI controller is + * the RID, but the high bit of the bus number is + * negated. + */ + msi-map = <0x0000 &msi 0x8000 0x8000>, + <0x8000 &msi 0x0000 0x8000>; + }; +}; + + +Example (5) +=========== + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi_a: msi-controller@a { + reg = <0xa 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + msi_b: msi-controller@b { + reg = <0xb 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + msi_c: msi-controller@c { + reg = <0xc 0x1>; + compatible = "vendor,some-controller"; + msi-controller; + #msi-cells = <1>; + }; + + pci: pci@c { + reg = <0xf 0x1>; + compatible = "vendor,pcie-root-complex"; + device_type = "pci"; + + /* + * The sideband data provided to MSI controller a is the + * RID, but the high bit of the bus number is negated. + * The sideband data provided to MSI controller b is the + * RID, identity-mapped. + * MSI controller c is not addressable. + */ + msi-map = <0x0000 &msi_a 0x8000 0x08000>, + <0x8000 &msi_a 0x0000 0x08000>, + <0x0000 &msi_b 0x0000 0x10000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-msm-msi.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-msm-msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..446a06738c8f604426147705d17177967a964fed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-msm-msi.txt @@ -0,0 +1,74 @@ +* MSM PCIe MSI controller + +========= +Main node +========= + +- compatible: + Usage: required + Value type: + Definition: Value to identify this is a MSM PCIe MSI controller + +- msi-controller: + Usage: required + Value type: + Definition: Indicates that this is a MSM PCIe MSI controller node + +- reg: + Usage: required + Value type: + Definition: Physical QGIC address (0x17a00040), MSI message address + +-interrupt-parent: + Usage: required + Value type: + Definition: Phandle of the interrupt controller that services + interrupts for this device + +-interrupts: + Usage: required + Value type: + Definition: Array of tuples which describe interrupt lines for PCIe MSI + +======= +Example +======= + +pcie0_msi: qcom,pcie0_msi { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a00040 0x0 0x0 0x0 0xff>; + interrupt-parent = <&pdc>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-msm.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-msm.txt new file mode 100644 index 0000000000000000000000000000000000000000..626e9ad09802729d525eff7096b93394997fe71a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-msm.txt @@ -0,0 +1,544 @@ +* MSM PCI express root complex + +========= +Main node +========= + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,pci-msm" + +- reg: + Usage: required + Value type: + Definition: Register ranges as listed in the reg-names property + +- reg-names: + Usage: required + Value type: + Definition: Should contain: + - "parf" MSM specific registers + - "phy" PCIe PHY registers + - "dbi" DesignWare PCIe registers + - "elbi" External local bus interface registers + - "iatu" Internal translation unit registers + - "config" PCIe device configuration space + - "io" PCIe device I/O registers + - "bars" PCIe device base address registers + - "tcsr" (opt) PCIe clock scheme register + - "rumi" (opt) PCIe RUMI register + +- cell-index: + Usage: required + Value type: + Definition: defines root complex ID. + +- linux,pci-domain: + Usage: required + Value type: + Definition: As specified in pci.txt + +- #address-cells: + Usage: required + Value type: + Definition: Should be 3. As specified in designware-pcie.txt + +- #size-cells: + Usage: required + Value type: + Definition: Should be 2. As specified in designware-pcie.txt + +- ranges: + Usage: required + Value type: + Definition: As specified in designware-pcie.txt + +- interrupt-parent: + Usage: required + Value type: + Definition: Phandle of the interrupt controller that services + interrupts for this device + +- interrupts: + Usage: required + Value type: + Definition: PCIe root complex related interrupts + +- interrupt-names: + Usage: required + Value type: + Definition: Should contain + - "int_msi" + - "int_a" + - "int_b" + - "int_c" + - "int_d", + - "int_global_int" + +- #interrupt-cells: + Usage: required + Value type: + Definition: Should be 1. As specified in designware-pcie.txt + +- interrupt-map-mask: + Usage: required + Value type: + Definition: As specified in designware-pcie.txt + +- interrupt-map: + Usage: required + Value type: + Definition: As specified in designware-pcie.txt + +- msi-parent: + Usage: required + Value type: + Definition: As specified in pci-msi.txt + +- -gpio: + Usage: required + Value type: + Definition: List of phandle and GPIO specifier pairs. Should contain: + - "perst-gpio" PCIe reset signal line + - "wake-gpio" PCIe wake signal line + - "qcom,ep-gpio" (opt) PCIe endpoint specific signal line + +- pinctrl-names: + Usage: required + Value type: + Definition: Name of pin configuration groups. Should contain: + - "default" + - "sleep" (opt) + +- pinctrl-: + Usage: required + Value type: + Definition: As specified in pinctrl-bindings.txt + +- -supply: + Usage: required + Value type: + Definition: Phandle to PCIe core and PHY power supply. Should contain: + - "gdsc-vdd-supply" PCIe power domain control + - "vreg-1.8-supply" power supply for PCIe PHY + - "vreg-0.9-supply" power supply for PCIe PHY + - "vreg-cx-supply" power supply for PCIe core + - "vreg-3.3-supply" (opt) power supply for PCIe endpoint + +- qcom,-voltage-level: + Usage: required + Value type: + Definition: List of max/min voltage(uV) and optimal current(uA) tuple + for power supply + +- qcom,bw-scale: + Usage: optional + Value type: + Definition: List of CX voltage corner and rate change clock frequency + pair for each PCIe GEN speed + +- qcom,msm-bus,: + Usage: required + Value type: + Definition: As specified in msm_bus.txt + +- clocks: + Usage: required + Value type: + Definition: List of phandle and clock specifier pairs as listed + in clock-names property + +- clock-names: + Usage: required + Value type: + Definition: List of clock names that corresponds with listed "clocks" + +- max-clock-frequency-hz: + Usage: optional + Value type: + Definition: List of clock frequencies for each PCIe clock. Only need to + specify the ones that needs to be changed + +- resets: + Usage: required + Value type: + Definition: List of phandle and reset specifier pairs as listed + in reset-names property + +- reset-names: + Usage: required + Value type: + Definition: Should contain: + - "pcie__core_reset" Core reset + - "pcie__phy_reset" PHY reset + +- qcom,smmu-sid-base: + Usage: optional + Value: + Definition: Base SID for PCIe + +- iommu-map: + Usage: optional. Required if qcom,smmu-sid-base is defined + Value type: + Definition: As defined in pci-iommu.txt. Should contain: + - + +- qcom,target-link-speed: + Usage: optional + Value type: + Definition: Override maximum GEN speed. Options: + - 0x1 GEN 1 + - 0x2 GEN 2 + - 0x3 GEN 3 + +- qcom,link-check-max-count + Usage: optional + Value type: + Definition: Max number of retries for link training. Delay between each + check is 5ms + +- qcom,boot-option: + Usage: optional + Value type: + Definition: Controls PCIe bus driver boot sequence. Options: + - BIT(0) PCIe bus driver will not start enumeration + during its probe. Clients will control when + PCIe bus driver should do enumeration + - BIT(1) PCIe bus driver will not start enumeration if it + receives a WAKE interrupt + +- qcom,drv-supported: + Usage: optional + Value type: + Definition: Direct resource vote (DRV) is supported. APPS PCIe + root complex driver can hand off PCIe resources to another + subsystem. This will allow APPS to enter lower power modes + while keeping PCIe core, PHY, and link funtional. In addition, + the system can enter CX power collapse once the DRV subsystem + removes its PCIe votes. + +- qcom,drv-l1ss-timeout-us: + Usage: optional depends on qcom,drv-supported + Value type: + Definition: This timeout determines when DRV subsystem will put the + link into l1ss sleep while idle in l1ss. If this is omitted, + the default timeout is 100ms. + +- qcom,use-19p2mhz-aux-clk: + Usage: optional + Value type: + Definition: Set PCIe AUX clock frequency to 19.2MHz + +- qcom,common-clk-en: + Usage: optional + Value type: + Definition: Support common clock configuration + +- qcom,clk-power-manage-en: + Usage: optional + Value type: + Definition: Support clock power management + +- qcom,n-fts: + Usage: optional + Value type: + Definition: Number of fast training sequences sent when the link + transitions from L0s to L0 + +- qcom,no-l0s-supported: + Usage: optional + Value type: + Definition: L0s is not supported + +- qcom,no-l1-supported: + Usage: optional + Value type: + Definition: L1 is not supported + +- qcom,no-l1ss-supported: + Usage: optional + Value type: + Definition: L1 sub-state (L1ss) is not supported + +- qcom,no-aux-clk-sync: + Usage: optional + Value type: + Definition: The AUX clock is not synchronous to the Core clock to + support L1ss + +- qcom,l1-2-th-scale: + Usage: optional + Value type: + Definition: Determines the multiplier for L1.2 LTR threshold value + - 0 1ns + - 1 32ns + - 2 1us + - 3 32us + - 4 1ms + - 5 32ms + +- qcom,l1-2-th-value: + Usage: optional + Value type: + Definition: L1.2 LTR threshold value to be multipled with scale to + define L1.2 latency tolerance reporting (LTR) + +- qcom,slv-addr-space-size: + Usage: required + Value type: + Definition: Memory block size dedicated to PCIe root complex + +- qcom,wr-halt-size: + Usage: optional + Value type: + Definition: Exponent (base 2) that determines the data size(bytes) that + PCIe core will halt for each write + +- qcom,tlp-rd-size: + Usage: optional + Value type: + Definition: Determines the maximum read request size(bytes). Options: + - 0 128 + - 1 256 + - 2 512 + - 3 1K + - 4 2K + - 5 4K + +- qcom,cpl-timeout: + Usage: optional + Value type: + Definition: Determines the timeout range PCIe root complex will send + out a completion packet if no ACK is seen for TLP. Options: + - BIT(0) 50us to 10ms + - BIT(1) 10ms to 250ms + - BIT(2) 250ms to 4s + - BIT(3) 4s to 64s + +- qcom,perst-delay-us-min: + Usage: optional + Value type: + Definition: Minimum allowed time(us) to sleep after asserting or + de-asserting PERST GPI. + +- qcom,perst-delay-us-max: + Usage: optional + Value type: + Definition: Maximum allowed time(us) to sleep after asserting or + de-asserting PERST GPIO + +- qcom,ep-latency: + Usage: optional + Value type: + Definition: The latency(ms) between when PCIe PHY is up and PERST is + de-asserted. This guarantees the 100MHz clock is available for + the PCIe devices + +- qcom,switch-latency: + Usage: optional + Definition: The latency(ms) between when PCIe link is up and before + any device over the switch is accessed + +- qcom,core-preset: + Usage: optional + Definition: Determines how aggressive the PCIe PHY equalization is for + Gen3 cores. The following are recommended settings: + - short channels: 0x55555555 (default) + - long channels: 0x77777777 + +- qcom,pcie-phy-ver: + Usage: required + Value type: + Definition: States the PCIe PHY version + +- qcom,phy-status-offset: + Usage: required + Value type: + Definition: Offset from PCIe PHY base to check if PCIe PHY status + +- qcom,phy-status-bit: + Usage: required + Value type: + Definition: BIT to check PCIe PHY status + +- qcom,phy-power-down-offset: + Usage: required + Value type: + Definition: Offset from PCIe PHY base to control PHY power state + +- qcom,phy-sequence: + Usage: required + Value type: + Definition: PCIe PHY initialization sequence + + +============== +Root port node +============== + +Root port are defined as subnodes of the PCIe controller node + +- reg: + Usage: required + Value type: + Definition: First cell is devfn, which is determined by pci bus + topology. Assign the other cells 0 since they are not used + +- qcom,iommu-cfg: + Usage: optional + Value type: + Definition: Defines PCIe root port SMMU configuration. Options: + - BIT(0) Indicates if SMMU is present + - BIT(1) Set IOMMU attribute S1_BYPASS + - BIT(2) Set IOMMU attribute FAST + - BIT(3) Set IOMMU attribute ATOMIC + - BIT(4) Set IOMMU attribute FORCE COHERENT + +- qcom,iommu-range: + Usage: optional + Value type: Array of + Definition: Pair of values describing iova base and size to allocate + +======= +Example +======= + + pcie0: qcom,pcie@1c00000 { + compatible = "qcom,pci-msm"; + + reg = <0x1c00000 0x4000>, + <0x1c04000 0x1000>, + <0x60000000 0xf1d>, + <0x60000f20 0xa8>, + <0x60001000 0x1000>, + <0x60100000 0x100000>, + <0x60200000 0x100000>, + <0x60300000 0x3d00000>; + reg-names = "parf", "phy", "dm_core", "elbi", "iatu", "conf", + "io", "bars", "tcsr", "rumi"; + + cell-index = <0>; + device_type = "pci"; + linux,pci-domain = <0>; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x60200000 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x60300000 0x0 0x3d00000>; + + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4 5>; + interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d", + "int_global_int", + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 141 0 + 0 0 0 1 &intc 0 149 0 + 0 0 0 2 &intc 0 150 0 + 0 0 0 3 &intc 0 151 0 + 0 0 0 4 &intc 0 152 0 + 0 0 0 5 &intc 0 140 0>; + msi-parent = <&pcie0_msi>; + + perst-gpio = <&tlmm 35 0>; + wake-gpio = <&tlmm 37 0>; + qcom,ep-gpio = <&tlmm 94 0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + pinctrl-1 = <&pcie0_clkreq_sleep + &pcie0_perst_sleep + &pcie0_wake_sleep>; + + gdsc-vdd-supply = <&pcie_0_gdsc>; + vreg-1.8-supply = <&pm8150l_l3>; + vreg-0.9-supply = <&pm8150_l5>; + vreg-cx-supply = <&VDD_CX_LEVEL>; + vreg-3.3-supply = <&pm8150_l1>; + qcom,vreg-1.8-voltage-level = <1800000 1800000 1000>; + qcom,vreg-0.9-voltage-level = <950000 950000 24000>; + qcom,vreg-cx-voltage-level = ; + qcom,bw-scale = ; /* Gen3 */ + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_0_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_0_AUX_CLK>, + <&clock_gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE0_PHY_REFGEN_CLK>, + <&clock_gcc GCC_PCIE_PHY_AUX_CLK>; + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_phy_aux_clk"; + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + + qcom,smmu-sid-base = <0x1e00>; + iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, + <0x100 &apps_smmu 0x1e01 0x1>; + + qcom,target-link-speed = <0x2>; + qcom,link-check-max-count = <40> /* 200ms */ + qcom,boot-option = <0x1>; + qcom,drv-supported; + qcom,use-19p2mhz-aux-clk; + qcom,common-clk-en; + qcom,clk-power-manage-en; + qcom,n-fts = <0x50>; + qcom,no-l0s-supported; + qcom,no-l1-supported; + qcom,no-l1ss-supported; + qcom,no-aux-clk-sync; + qcom,slv-addr-space-size = <0x1000000>; /* 16MB */ + qcom,wr-halt-size = <0xa>; /* 1KB */ + qcom,tlp-rd-size = <0x5>; /* 4KB */ + qcom,cpl-timeout = <0x2>; /* 10ms to 250ms */ + qcom,perst-delay-us-min = <10>; + qcom,perst-delay-us-max = <15>; + qcom,ep-latency = <20>; + qcom,switch-latency = <25>; + + qcom,core-preset = <0x55555555> /* short channel */ + qcom,pcie-phy-ver = <0x2101>; /* v2 version 1.01 */ + qcom,phy-status-offset = <0x814>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0x840>; + qcom,phy-sequence = <0x0840 0x03 0x0 + 0x0094 0x08 0x0 + 0x0154 0x34 0x0 + 0x016c 0x08 0x0 + 0x0058 0x0f 0x0 + 0x00a4 0x42 0x0 + 0x0110 0x24 0x0 + 0x0800 0x00 0x0 + 0x0844 0x03 0x0>; + + pcie0_rp: pcie0_rp { + reg = <0x0 0x0 0x0 0x0 0x0>; + qcom,iommu-cfg = <0x3> /* SMMU PRESENT. SET S1 BYPASS */ + qcom,iommu-range = <0x0 0x10000000 0x0 0x40000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-rcar-gen2.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-rcar-gen2.txt new file mode 100644 index 0000000000000000000000000000000000000000..9fe7e12a7bf37b7c874a3e93bea590452845d093 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-rcar-gen2.txt @@ -0,0 +1,82 @@ +Renesas AHB to PCI bridge +------------------------- + +This is the bridge used internally to connect the USB controllers to the +AHB. There is one bridge instance per USB port connected to the internal +OHCI and EHCI controllers. + +Required properties: +- compatible: "renesas,pci-r8a7743" for the R8A7743 SoC; + "renesas,pci-r8a7745" for the R8A7745 SoC; + "renesas,pci-r8a7790" for the R8A7790 SoC; + "renesas,pci-r8a7791" for the R8A7791 SoC; + "renesas,pci-r8a7793" for the R8A7793 SoC; + "renesas,pci-r8a7794" for the R8A7794 SoC; + "renesas,pci-rcar-gen2" for a generic R-Car Gen2 or + RZ/G1 compatible device. + + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: A list of physical regions to access the device: the first is + the operational registers for the OHCI/EHCI controllers and the + second is for the bridge configuration and control registers. +- interrupts: interrupt for the device. +- clocks: The reference to the device clock. +- bus-range: The PCI bus number range; as this is a single bus, the range + should be specified as the same value twice. +- #address-cells: must be 3. +- #size-cells: must be 2. +- #interrupt-cells: must be 1. +- interrupt-map: standard property used to define the mapping of the PCI + interrupts to the GIC interrupts. +- interrupt-map-mask: standard property that helps to define the interrupt + mapping. + +Optional properties: +- dma-ranges: a single range for the inbound memory region. If not supplied, + defaults to 1GiB at 0x40000000. Note there are hardware restrictions on the + allowed combinations of address and size. + +Example SoC configuration: + + pci0: pci@ee090000 { + compatible = "renesas,pci-r8a7790", "renesas,pci-rcar-gen2"; + clocks = <&mstp7_clks R8A7790_CLK_EHCI>; + reg = <0x0 0xee090000 0x0 0xc00>, + <0x0 0xee080000 0x0 0x1100>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000>; + interrupt-map-mask = <0xff00 0 0 0x7>; + interrupt-map = <0x0000 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH + 0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH + 0x1000 0 0 2 &gic 0 108 IRQ_TYPE_LEVEL_HIGH>; + + usb@1,0 { + reg = <0x800 0 0 0 0>; + phys = <&usb0 0>; + phy-names = "usb"; + }; + + usb@2,0 { + reg = <0x1000 0 0 0 0>; + phys = <&usb0 0>; + phy-names = "usb"; + }; + }; + +Example board setup: + +&pci0 { + status = "okay"; + pinctrl-0 = <&usb0_pins>; + pinctrl-names = "default"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-thunder-ecam.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-thunder-ecam.txt new file mode 100644 index 0000000000000000000000000000000000000000..f478874b79cedd1805c7237c3b3c87279f683427 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-thunder-ecam.txt @@ -0,0 +1,30 @@ +* ThunderX PCI host controller for pass-1.x silicon + +Firmware-initialized PCI host controller to on-chip devices found on +some Cavium ThunderX processors. These devices have ECAM-based config +access, but the BARs are all at fixed addresses. We handle the fixed +addresses by synthesizing Enhanced Allocation (EA) capabilities for +these devices. + +The properties and their meanings are identical to those described in +host-generic-pci.txt except as listed below. + +Properties of the host controller node that differ from +host-generic-pci.txt: + +- compatible : Must be "cavium,pci-host-thunder-ecam" + +Example: + + pcie@84b000000000 { + compatible = "cavium,pci-host-thunder-ecam"; + device_type = "pci"; + msi-parent = <&its>; + msi-map = <0 &its 0x30000 0x10000>; + bus-range = <0 31>; + #size-cells = <2>; + #address-cells = <3>; + #stream-id-cells = <1>; + reg = <0x84b0 0x00000000 0 0x02000000>; /* Configuration space */ + ranges = <0x03000000 0x8180 0x00000000 0x8180 0x00000000 0x80 0x00000000>; /* mem ranges */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci-thunder-pem.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci-thunder-pem.txt new file mode 100644 index 0000000000000000000000000000000000000000..f131faea3b7c0e112a6d9bee6392b8b9038e4d9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci-thunder-pem.txt @@ -0,0 +1,43 @@ +* ThunderX PEM PCIe host controller + +Firmware-initialized PCI host controller found on some Cavium +ThunderX processors. + +The properties and their meanings are identical to those described in +host-generic-pci.txt except as listed below. + +Properties of the host controller node that differ from +host-generic-pci.txt: + +- compatible : Must be "cavium,pci-host-thunder-pem" + +- reg : Two entries: First the configuration space for down + stream devices base address and size, as accessed + from the parent bus. Second, the register bank of + the PEM device PCIe bridge. + +Example: + + pci@87e0,c2000000 { + compatible = "cavium,pci-host-thunder-pem"; + device_type = "pci"; + msi-parent = <&its>; + msi-map = <0 &its 0x10000 0x10000>; + bus-range = <0x8f 0xc7>; + #size-cells = <2>; + #address-cells = <3>; + + reg = <0x8880 0x8f000000 0x0 0x39000000>, /* Configuration space */ + <0x87e0 0xc2000000 0x0 0x00010000>; /* PEM space */ + ranges = <0x01000000 0x00 0x00020000 0x88b0 0x00020000 0x00 0x00010000>, /* I/O */ + <0x03000000 0x00 0x10000000 0x8890 0x10000000 0x0f 0xf0000000>, /* mem64 */ + <0x43000000 0x10 0x00000000 0x88a0 0x00000000 0x10 0x00000000>, /* mem64-pref */ + <0x03000000 0x87e0 0xc2f00000 0x87e0 0xc2000000 0x00 0x00100000>; /* mem64 PEM BAR4 */ + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &gic0 0 0 0 24 4>, /* INTA */ + <0 0 0 2 &gic0 0 0 0 25 4>, /* INTB */ + <0 0 0 3 &gic0 0 0 0 26 4>, /* INTC */ + <0 0 0 4 &gic0 0 0 0 27 4>; /* INTD */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..c77981c5dd18f6edff3affcb40cd88720633b5db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/pci.txt @@ -0,0 +1,26 @@ +PCI bus bridges have standardized Device Tree bindings: + +PCI Bus Binding to: IEEE Std 1275-1994 +http://www.devicetree.org/open-firmware/bindings/pci/pci2_1.pdf + +And for the interrupt mapping part: + +Open Firmware Recommended Practice: Interrupt Mapping +http://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf + +Additionally to the properties specified in the above standards a host bridge +driver implementation may support the following properties: + +- linux,pci-domain: + If present this property assigns a fixed PCI domain number to a host bridge, + otherwise an unstable (across boots) unique number will be assigned. + It is required to either not set this property at all or set it for all + host bridges in the system, otherwise potentially conflicting domain numbers + may be assigned to root buses behind different host bridges. The domain + number for each host bridge in the system must be unique. +- max-link-speed: + If present this property specifies PCI gen for link capability. Host + drivers could add this as a strategy to avoid unnecessary operation for + unsupported link speed, for instance, trying to do training for + unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2' + for gen2, and '1' for gen1. Any other values are invalid. diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/plda,xpressrich3-axi.txt b/arch/arm64/boot/dts/vendor/bindings/pci/plda,xpressrich3-axi.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3f75bfb42bcb21c1e158e3c61decc4e8e96f59b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/plda,xpressrich3-axi.txt @@ -0,0 +1,12 @@ +* PLDA XpressRICH3-AXI host controller + +The PLDA XpressRICH3-AXI host controller can be configured in a manner that +makes it compliant with the SBSA[1] standard published by ARM Ltd. For those +scenarios, the host-generic-pci.txt bindings apply with the following additions +to the compatible property: + +Required properties: + - compatible: should contain "plda,xpressrich3-axi" to identify the IP used. + + +[1] http://infocenter.arm.com/help/topic/com.arm.doc.den0029a/ diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/qcom,pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/qcom,pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..1fd703bd73e0f1f20fea286738f9f525d86b01eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/qcom,pcie.txt @@ -0,0 +1,290 @@ +* Qualcomm PCI express root complex + +- compatible: + Usage: required + Value type: + Definition: Value should contain + - "qcom,pcie-ipq8064" for ipq8064 + - "qcom,pcie-apq8064" for apq8064 + - "qcom,pcie-apq8084" for apq8084 + - "qcom,pcie-msm8996" for msm8996 or apq8096 + - "qcom,pcie-ipq4019" for ipq4019 + - "qcom,pcie-ipq8074" for ipq8074 + +- reg: + Usage: required + Value type: + Definition: Register ranges as listed in the reg-names property + +- reg-names: + Usage: required + Value type: + Definition: Must include the following entries + - "parf" Qualcomm specific registers + - "dbi" DesignWare PCIe registers + - "elbi" External local bus interface registers + - "config" PCIe configuration space + +- device_type: + Usage: required + Value type: + Definition: Should be "pci". As specified in designware-pcie.txt + +- #address-cells: + Usage: required + Value type: + Definition: Should be 3. As specified in designware-pcie.txt + +- #size-cells: + Usage: required + Value type: + Definition: Should be 2. As specified in designware-pcie.txt + +- ranges: + Usage: required + Value type: + Definition: As specified in designware-pcie.txt + +- interrupts: + Usage: required + Value type: + Definition: MSI interrupt + +- interrupt-names: + Usage: required + Value type: + Definition: Should contain "msi" + +- #interrupt-cells: + Usage: required + Value type: + Definition: Should be 1. As specified in designware-pcie.txt + +- interrupt-map-mask: + Usage: required + Value type: + Definition: As specified in designware-pcie.txt + +- interrupt-map: + Usage: required + Value type: + Definition: As specified in designware-pcie.txt + +- clocks: + Usage: required + Value type: + Definition: List of phandle and clock specifier pairs as listed + in clock-names property + +- clock-names: + Usage: required + Value type: + Definition: Should contain the following entries + - "iface" Configuration AHB clock + +- clock-names: + Usage: required for ipq/apq8064 + Value type: + Definition: Should contain the following entries + - "core" Clocks the pcie hw block + - "phy" Clocks the pcie PHY block +- clock-names: + Usage: required for apq8084/ipq4019 + Value type: + Definition: Should contain the following entries + - "aux" Auxiliary (AUX) clock + - "bus_master" Master AXI clock + - "bus_slave" Slave AXI clock + +- clock-names: + Usage: required for msm8996/apq8096 + Value type: + Definition: Should contain the following entries + - "pipe" Pipe Clock driving internal logic + - "aux" Auxiliary (AUX) clock + - "cfg" Configuration clock + - "bus_master" Master AXI clock + - "bus_slave" Slave AXI clock + +- clock-names: + Usage: required for ipq8074 + Value type: + Definition: Should contain the following entries + - "iface" PCIe to SysNOC BIU clock + - "axi_m" AXI Master clock + - "axi_s" AXI Slave clock + - "ahb" AHB clock + - "aux" Auxiliary clock + +- resets: + Usage: required + Value type: + Definition: List of phandle and reset specifier pairs as listed + in reset-names property + +- reset-names: + Usage: required for ipq/apq8064 + Value type: + Definition: Should contain the following entries + - "axi" AXI reset + - "ahb" AHB reset + - "por" POR reset + - "pci" PCI reset + - "phy" PHY reset + +- reset-names: + Usage: required for apq8084 + Value type: + Definition: Should contain the following entries + - "core" Core reset + +- reset-names: + Usage: required for ipq/apq8064 + Value type: + Definition: Should contain the following entries + - "axi_m" AXI master reset + - "axi_s" AXI slave reset + - "pipe" PIPE reset + - "axi_m_vmid" VMID reset + - "axi_s_xpu" XPU reset + - "parf" PARF reset + - "phy" PHY reset + - "axi_m_sticky" AXI sticky reset + - "pipe_sticky" PIPE sticky reset + - "pwr" PWR reset + - "ahb" AHB reset + - "phy_ahb" PHY AHB reset + +- reset-names: + Usage: required for ipq8074 + Value type: + Definition: Should contain the following entries + - "pipe" PIPE reset + - "sleep" Sleep reset + - "sticky" Core Sticky reset + - "axi_m" AXI Master reset + - "axi_s" AXI Slave reset + - "ahb" AHB Reset + - "axi_m_sticky" AXI Master Sticky reset + +- power-domains: + Usage: required for apq8084 and msm8996/apq8096 + Value type: + Definition: A phandle and power domain specifier pair to the + power domain which is responsible for collapsing + and restoring power to the peripheral + +- vdda-supply: + Usage: required + Value type: + Definition: A phandle to the core analog power supply + +- vdda_phy-supply: + Usage: required for ipq/apq8064 + Value type: + Definition: A phandle to the analog power supply for PHY + +- vdda_refclk-supply: + Usage: required for ipq/apq8064 + Value type: + Definition: A phandle to the analog power supply for IC which generates + reference clock +- vddpe-3v3-supply: + Usage: optional + Value type: + Definition: A phandle to the PCIe endpoint power supply + +- phys: + Usage: required for apq8084 + Value type: + Definition: List of phandle(s) as listed in phy-names property + +- phy-names: + Usage: required for apq8084 + Value type: + Definition: Should contain "pciephy" + +- -gpios: + Usage: optional + Value type: + Definition: List of phandle and GPIO specifier pairs. Should contain + - "perst-gpios" PCIe endpoint reset signal line + - "wake-gpios" PCIe endpoint wake signal line + +* Example for ipq/apq8064 + pcie@1b500000 { + compatible = "qcom,pcie-apq8064", "qcom,pcie-ipq8064", "snps,dw-pcie"; + reg = <0x1b500000 0x1000 + 0x1b502000 0x80 + 0x1b600000 0x100 + 0x0ff00000 0x100000>; + reg-names = "dbi", "elbi", "parf", "config"; + device_type = "pci"; + linux,pci-domain = <0>; + bus-range = <0x00 0xff>; + num-lanes = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0 0 0x0fe00000 0 0x00100000 /* I/O */ + 0x82000000 0 0 0x08000000 0 0x07e00000>; /* memory */ + interrupts = ; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ + <0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ + <0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ + <0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ + clocks = <&gcc PCIE_A_CLK>, + <&gcc PCIE_H_CLK>, + <&gcc PCIE_PHY_CLK>; + clock-names = "core", "iface", "phy"; + resets = <&gcc PCIE_ACLK_RESET>, + <&gcc PCIE_HCLK_RESET>, + <&gcc PCIE_POR_RESET>, + <&gcc PCIE_PCI_RESET>, + <&gcc PCIE_PHY_RESET>; + reset-names = "axi", "ahb", "por", "pci", "phy"; + pinctrl-0 = <&pcie_pins_default>; + pinctrl-names = "default"; + }; + +* Example for apq8084 + pcie0@fc520000 { + compatible = "qcom,pcie-apq8084", "snps,dw-pcie"; + reg = <0xfc520000 0x2000>, + <0xff000000 0x1000>, + <0xff001000 0x1000>, + <0xff002000 0x2000>; + reg-names = "parf", "dbi", "elbi", "config"; + device_type = "pci"; + linux,pci-domain = <0>; + bus-range = <0x00 0xff>; + num-lanes = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0 0 0xff200000 0 0x00100000 /* I/O */ + 0x82000000 0 0x00300000 0xff300000 0 0x00d00000>; /* memory */ + interrupts = ; + interrupt-names = "msi"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &intc 0 244 IRQ_TYPE_LEVEL_HIGH>, /* int_a */ + <0 0 0 2 &intc 0 245 IRQ_TYPE_LEVEL_HIGH>, /* int_b */ + <0 0 0 3 &intc 0 247 IRQ_TYPE_LEVEL_HIGH>, /* int_c */ + <0 0 0 4 &intc 0 248 IRQ_TYPE_LEVEL_HIGH>; /* int_d */ + clocks = <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&gcc GCC_PCIE_0_AUX_CLK>; + clock-names = "iface", "master_bus", "slave_bus", "aux"; + resets = <&gcc GCC_PCIE_0_BCR>; + reset-names = "core"; + power-domains = <&gcc PCIE0_GDSC>; + vdda-supply = <&pma8084_l3>; + phys = <&pciephy0>; + phy-names = "pciephy"; + perst-gpio = <&tlmm 70 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie0_pins_default>; + pinctrl-names = "default"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/ralink,rt3883-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/ralink,rt3883-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..ffba4f63d71fdebf184effa3aea537f0b8f56dec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/ralink,rt3883-pci.txt @@ -0,0 +1,187 @@ +* Mediatek/Ralink RT3883 PCI controller + +1) Main node + + Required properties: + + - compatible: must be "ralink,rt3883-pci" + + - reg: specifies the physical base address of the controller and + the length of the memory mapped region. + + - #address-cells: specifies the number of cells needed to encode an + address. The value must be 1. + + - #size-cells: specifies the number of cells used to represent the size + of an address. The value must be 1. + + - ranges: specifies the translation between child address space and parent + address space + + Optional properties: + + - status: indicates the operational status of the device. + Value must be either "disabled" or "okay". + +2) Child nodes + + The main node must have two child nodes which describes the built-in + interrupt controller and the PCI host bridge. + + a) Interrupt controller: + + Required properties: + + - interrupt-controller: identifies the node as an interrupt controller + + - #address-cells: specifies the number of cells needed to encode an + address. The value must be 0. As such, 'interrupt-map' nodes do not + have to specify a parent unit address. + + - #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. + + - interrupts: specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends on the + parent interrupt controller. + + b) PCI host bridge: + + Required properties: + + - #address-cells: specifies the number of cells needed to encode an + address. The value must be 0. + + - #size-cells: specifies the number of cells used to represent the size + of an address. The value must be 2. + + - #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. + + - device_type: must be "pci" + + - bus-range: PCI bus numbers covered + + - ranges: specifies the ranges for the PCI memory and I/O regions + + - interrupt-map-mask, + - interrupt-map: standard PCI properties to define the mapping of the + PCI interface to interrupt numbers. + + The PCI host bridge node might have additional sub-nodes representing + the onboard PCI devices/PCI slots. Each such sub-node must have the + following mandatory properties: + + - reg: used only for interrupt mapping, so only the first four bytes + are used to refer to the correct bus number and device number. + + - device_type: must be "pci" + + If a given sub-node represents a PCI bridge it must have following + mandatory properties as well: + + - #address-cells: must be set to <3> + + - #size-cells: must set to <2> + + - #interrupt-cells: must be set to <1> + + - interrupt-map-mask, + - interrupt-map: standard PCI properties to define the mapping of the + PCI interface to interrupt numbers. + + Besides the required properties the sub-nodes may have these optional + properties: + + - status: indicates the operational status of the sub-node. + Value must be either "disabled" or "okay". + +3) Example: + + a) SoC specific dtsi file: + + pci@10140000 { + compatible = "ralink,rt3883-pci"; + reg = <0x10140000 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; /* direct mapping */ + + status = "disabled"; + + pciintc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + + interrupt-parent = <&cpuintc>; + interrupts = <4>; + }; + + host-bridge { + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + device_type = "pci"; + + bus-range = <0 255>; + ranges = < + 0x02000000 0 0x00000000 0x20000000 0 0x10000000 /* pci memory */ + 0x01000000 0 0x00000000 0x10160000 0 0x00010000 /* io space */ + >; + + interrupt-map-mask = <0xf800 0 0 7>; + interrupt-map = < + /* IDSEL 17 */ + 0x8800 0 0 1 &pciintc 18 + 0x8800 0 0 2 &pciintc 18 + 0x8800 0 0 3 &pciintc 18 + 0x8800 0 0 4 &pciintc 18 + /* IDSEL 18 */ + 0x9000 0 0 1 &pciintc 19 + 0x9000 0 0 2 &pciintc 19 + 0x9000 0 0 3 &pciintc 19 + 0x9000 0 0 4 &pciintc 19 + >; + + pci-bridge@1 { + reg = <0x0800 0 0 0 0>; + device_type = "pci"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + + interrupt-map-mask = <0x0 0 0 0>; + interrupt-map = <0x0 0 0 0 &pciintc 20>; + + status = "disabled"; + }; + + pci-slot@17 { + reg = <0x8800 0 0 0 0>; + device_type = "pci"; + + status = "disabled"; + }; + + pci-slot@18 { + reg = <0x9000 0 0 0 0>; + device_type = "pci"; + + status = "disabled"; + }; + }; + }; + + b) Board specific dts file: + + pci@10140000 { + status = "okay"; + + host-bridge { + pci-bridge@1 { + status = "okay"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/rcar-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/rcar-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5f7fc62d10e98221eed5314771c8cc09b8622ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/rcar-pci.txt @@ -0,0 +1,64 @@ +* Renesas R-Car PCIe interface + +Required properties: +compatible: "renesas,pcie-r8a7743" for the R8A7743 SoC; + "renesas,pcie-r8a7779" for the R8A7779 SoC; + "renesas,pcie-r8a7790" for the R8A7790 SoC; + "renesas,pcie-r8a7791" for the R8A7791 SoC; + "renesas,pcie-r8a7793" for the R8A7793 SoC; + "renesas,pcie-r8a7795" for the R8A7795 SoC; + "renesas,pcie-r8a7796" for the R8A7796 SoC; + "renesas,pcie-r8a77980" for the R8A77980 SoC; + "renesas,pcie-rcar-gen2" for a generic R-Car Gen2 or + RZ/G1 compatible device. + "renesas,pcie-rcar-gen3" for a generic R-Car Gen3 compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: base address and length of the PCIe controller registers. +- #address-cells: set to <3> +- #size-cells: set to <2> +- bus-range: PCI bus numbers covered +- device_type: set to "pci" +- ranges: ranges for the PCI memory and I/O regions. +- dma-ranges: ranges for the inbound memory regions. +- interrupts: two interrupt sources for MSI interrupts, followed by interrupt + source for hardware related interrupts (e.g. link speed change). +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties + to define the mapping of the PCIe interface to interrupt numbers. +- clocks: from common clock binding: clock specifiers for the PCIe controller + and PCIe bus clocks. +- clock-names: from common clock binding: should be "pcie" and "pcie_bus". + +Optional properties: +- phys: from common PHY binding: PHY phandle and specifier (only make sense + for R-Car gen3 SoCs where the PCIe PHYs have their own register blocks). +- phy-names: from common PHY binding: should be "pcie". + +Example: + +SoC-specific DT Entry: + + pcie: pcie@fe000000 { + compatible = "renesas,pcie-r8a7791", "renesas,pcie-rcar-gen2"; + reg = <0 0xfe000000 0 0x80000>; + #address-cells = <3>; + #size-cells = <2>; + bus-range = <0x00 0xff>; + device_type = "pci"; + ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000 + 0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000 + 0x02000000 0 0x30000000 0 0x30000000 0 0x08000000 + 0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>; + dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000 + 0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>; + interrupts = <0 116 4>, <0 117 4>, <0 118 4>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic 0 116 4>; + clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>; + clock-names = "pcie", "pcie_bus"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/rockchip-pcie-ep.txt b/arch/arm64/boot/dts/vendor/bindings/pci/rockchip-pcie-ep.txt new file mode 100644 index 0000000000000000000000000000000000000000..778467307a93228553d79fc8f57d755f7f284b25 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/rockchip-pcie-ep.txt @@ -0,0 +1,62 @@ +* Rockchip AXI PCIe Endpoint Controller DT description + +Required properties: +- compatible: Should contain "rockchip,rk3399-pcie-ep" +- reg: Two register ranges as listed in the reg-names property +- reg-names: Must include the following names + - "apb-base" + - "mem-base" +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - "aclk" + - "aclk-perf" + - "hclk" + - "pm" +- resets: Must contain seven entries for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following names + - "core" + - "mgmt" + - "mgmt-sticky" + - "pipe" + - "pm" + - "aclk" + - "pclk" +- pinctrl-names : The pin control state names +- pinctrl-0: The "default" pinctrl state +- phys: Must contain an phandle to a PHY for each entry in phy-names. +- phy-names: Must include 4 entries for all 4 lanes even if some of + them won't be used for your cases. Entries are of the form "pcie-phy-N": + where N ranges from 0 to 3. + (see example below and you MUST also refer to ../phy/rockchip-pcie-phy.txt + for changing the #phy-cells of phy node to support it) +- rockchip,max-outbound-regions: Maximum number of outbound regions + +Optional Property: +- num-lanes: number of lanes to use +- max-functions: Maximum number of functions that can be configured (default 1). + +pcie0-ep: pcie@f8000000 { + compatible = "rockchip,rk3399-pcie-ep"; + #address-cells = <3>; + #size-cells = <2>; + rockchip,max-outbound-regions = <16>; + clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>, + <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>; + clock-names = "aclk", "aclk-perf", + "hclk", "pm"; + max-functions = /bits/ 8 <8>; + num-lanes = <4>; + reg = <0x0 0xfd000000 0x0 0x1000000>, <0x0 0x80000000 0x0 0x20000>; + reg-names = "apb-base", "mem-base"; + resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>, + <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE> , + <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>, <&cru SRST_A_PCIE>; + reset-names = "core", "mgmt", "mgmt-sticky", "pipe", + "pm", "pclk", "aclk"; + phys = <&pcie_phy 0>, <&pcie_phy 1>, <&pcie_phy 2>, <&pcie_phy 3>; + phy-names = "pcie-phy-0", "pcie-phy-1", "pcie-phy-2", "pcie-phy-3"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clkreq>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/rockchip-pcie-host.txt b/arch/arm64/boot/dts/vendor/bindings/pci/rockchip-pcie-host.txt new file mode 100644 index 0000000000000000000000000000000000000000..af34c65773fd7fc540411b06be96011cc84828d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/rockchip-pcie-host.txt @@ -0,0 +1,135 @@ +* Rockchip AXI PCIe Root Port Bridge DT description + +Required properties: +- #address-cells: Address representation for root ports, set to <3> +- #size-cells: Size representation for root ports, set to <2> +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. +- compatible: Should contain "rockchip,rk3399-pcie" +- reg: Two register ranges as listed in the reg-names property +- reg-names: Must include the following names + - "axi-base" + - "apb-base" +- clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - "aclk" + - "aclk-perf" + - "hclk" + - "pm" +- msi-map: Maps a Requester ID to an MSI controller and associated + msi-specifier data. See ./pci-msi.txt +- interrupts: Three interrupt entries must be specified. +- interrupt-names: Must include the following names + - "sys" + - "legacy" + - "client" +- resets: Must contain seven entries for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following names + - "core" + - "mgmt" + - "mgmt-sticky" + - "pipe" + - "pm" + - "aclk" + - "pclk" +- pinctrl-names : The pin control state names +- pinctrl-0: The "default" pinctrl state +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. +- interrupt-map-mask and interrupt-map: standard PCI properties + +Required properties for legacy PHY model (deprecated): +- phys: From PHY bindings: Phandle for the Generic PHY for PCIe. +- phy-names: MUST be "pcie-phy". + +Required properties for per-lane PHY model (preferred): +- phys: Must contain an phandle to a PHY for each entry in phy-names. +- phy-names: Must include 4 entries for all 4 lanes even if some of + them won't be used for your cases. Entries are of the form "pcie-phy-N": + where N ranges from 0 to 3. + (see example below and you MUST also refer to ../phy/rockchip-pcie-phy.txt + for changing the #phy-cells of phy node to support it) + +Optional Property: +- aspm-no-l0s: RC won't support ASPM L0s. This property is needed if + using 24MHz OSC for RC's PHY. +- ep-gpios: contain the entry for pre-reset GPIO +- num-lanes: number of lanes to use +- vpcie12v-supply: The phandle to the 12v regulator to use for PCIe. +- vpcie3v3-supply: The phandle to the 3.3v regulator to use for PCIe. +- vpcie1v8-supply: The phandle to the 1.8v regulator to use for PCIe. +- vpcie0v9-supply: The phandle to the 0.9v regulator to use for PCIe. + +*Interrupt controller child node* +The core controller provides a single interrupt for legacy INTx. The PCIe node +should contain an interrupt controller node as a target for the PCI +'interrupt-map' property. This node represents the domain at which the four +INTx interrupts are decoded and routed. + + +Required properties for Interrupt controller child node: +- interrupt-controller: identifies the node as an interrupt controller +- #address-cells: specifies the number of cells needed to encode an + address. The value must be 0. +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. + +Example: + +pcie0: pcie@f8000000 { + compatible = "rockchip,rk3399-pcie"; + #address-cells = <3>; + #size-cells = <2>; + clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>, + <&cru PCLK_PCIE>, <&cru SCLK_PCIE_PM>; + clock-names = "aclk", "aclk-perf", + "hclk", "pm"; + bus-range = <0x0 0x1>; + interrupts = , + , + ; + interrupt-names = "sys", "legacy", "client"; + assigned-clocks = <&cru SCLK_PCIEPHY_REF>; + assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>; + assigned-clock-rates = <100000000>; + ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; + ranges = <0x83000000 0x0 0xfa000000 0x0 0xfa000000 0x0 0x600000 + 0x81000000 0x0 0xfa600000 0x0 0xfa600000 0x0 0x100000>; + num-lanes = <4>; + msi-map = <0x0 &its 0x0 0x1000>; + reg = <0x0 0xf8000000 0x0 0x2000000>, <0x0 0xfd000000 0x0 0x1000000>; + reg-names = "axi-base", "apb-base"; + resets = <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>, + <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE> , + <&cru SRST_PCIE_PM>, <&cru SRST_P_PCIE>, <&cru SRST_A_PCIE>; + reset-names = "core", "mgmt", "mgmt-sticky", "pipe", + "pm", "pclk", "aclk"; + /* deprecated legacy PHY model */ + phys = <&pcie_phy>; + phy-names = "pcie-phy"; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clkreq>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie0_intc 0>, + <0 0 0 2 &pcie0_intc 1>, + <0 0 0 3 &pcie0_intc 2>, + <0 0 0 4 &pcie0_intc 3>; + pcie0_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; +}; + +pcie0: pcie@f8000000 { + ... + + /* preferred per-lane PHY model */ + phys = <&pcie_phy 0>, <&pcie_phy 1>, <&pcie_phy 2>, <&pcie_phy 3>; + phy-names = "pcie-phy-0", "pcie-phy-1", "pcie-phy-2", "pcie-phy-3"; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/samsung,exynos5440-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/samsung,exynos5440-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..651d957d1051def00548673e5829ecbd302be7ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/samsung,exynos5440-pcie.txt @@ -0,0 +1,58 @@ +* Samsung Exynos 5440 PCIe interface + +This PCIe host controller is based on the Synopsys DesignWare PCIe IP +and thus inherits all the common properties defined in designware-pcie.txt. + +Required properties: +- compatible: "samsung,exynos5440-pcie" +- reg: base addresses and lengths of the PCIe controller, +- reg-names : First name should be set to "elbi". + And use the "config" instead of getting the configuration address space + from "ranges". + NOTE: When using the "config" property, reg-names must be set. +- interrupts: A list of interrupt outputs for level interrupt, + pulse interrupt, special interrupt. +- phys: From PHY binding. Phandle for the generic PHY. + Refer to Documentation/devicetree/bindings/phy/samsung-phy.txt + +For other common properties, refer to + Documentation/devicetree/bindings/pci/designware-pcie.txt + +Example: + +SoC-specific DT Entry (with using PHY framework): + + pcie_phy0: pcie-phy@270000 { + ... + reg = <0x270000 0x1000>, <0x271000 0x40>; + reg-names = "phy", "block"; + ... + }; + + pcie@290000 { + compatible = "samsung,exynos5440-pcie", "snps,dw-pcie"; + reg = <0x290000 0x1000>, <0x40000000 0x1000>; + reg-names = "elbi", "config"; + clocks = <&clock 28>, <&clock 27>; + clock-names = "pcie", "pcie_bus"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + phys = <&pcie_phy0>; + ranges = <0x81000000 0 0 0x60001000 0 0x00010000 + 0x82000000 0 0x60011000 0x60011000 0 0x1ffef000>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0>; + interrupt-map = <0 0 0 0 &gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; + num-lanes = <4>; + }; + +Board-specific DT Entry: + + pcie@290000 { + reset-gpio = <&pin_ctrl 5 0>; + }; + + pcie@2a0000 { + reset-gpio = <&pin_ctrl 22 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/spear13xx-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/spear13xx-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..d5a14f5dad46cc5937031045cc0bd698610130f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/spear13xx-pcie.txt @@ -0,0 +1,14 @@ +SPEAr13XX PCIe DT detail: +================================ + +SPEAr13XX uses the Synopsys DesignWare PCIe controller and ST MiPHY as PHY +controller. + +Required properties: +- compatible : should be "st,spear1340-pcie", "snps,dw-pcie". +- phys : phandle to PHY node associated with PCIe controller +- phy-names : must be "pcie-phy" +- All other definitions as per generic PCI bindings + + Optional properties: +- st,pcie-is-gen1 indicates that forced gen1 initialization is needed. diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/tango-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/tango-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..244683836a7954656b32c5e09b36a547ede43c1f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/tango-pcie.txt @@ -0,0 +1,29 @@ +Sigma Designs Tango PCIe controller + +Required properties: + +- compatible: "sigma,smp8759-pcie" +- reg: address/size of PCI configuration space, address/size of register area +- bus-range: defined by size of PCI configuration space +- device_type: "pci" +- #size-cells: <2> +- #address-cells: <3> +- msi-controller +- ranges: translation from system to bus addresses +- interrupts: spec for misc interrupts, spec for MSI + +Example: + + pcie@2e000 { + compatible = "sigma,smp8759-pcie"; + reg = <0x50000000 0x400000>, <0x2e000 0x100>; + bus-range = <0 3>; + device_type = "pci"; + #size-cells = <2>; + #address-cells = <3>; + msi-controller; + ranges = <0x02000000 0x0 0x00400000 0x50400000 0x0 0x3c00000>; + interrupts = + <54 IRQ_TYPE_LEVEL_HIGH>, /* misc interrupts */ + <55 IRQ_TYPE_LEVEL_HIGH>; /* MSI */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/ti-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/ti-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f7af3044016a6b4578cb4df6e8ff90e2a7ed45c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/ti-pci.txt @@ -0,0 +1,90 @@ +TI PCI Controllers + +PCIe DesignWare Controller + - compatible: Should be "ti,dra7-pcie" for RC + Should be "ti,dra7-pcie-ep" for EP + - phys : list of PHY specifiers (used by generic PHY framework) + - phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the + number of PHYs as specified in *phys* property. + - ti,hwmods : Name of the hwmod associated to the pcie, "pcie", + where is the instance number of the pcie from the HW spec. + - num-lanes as specified in ../designware-pcie.txt + +HOST MODE +========= + - reg : Two register ranges as listed in the reg-names property + - reg-names : The first entry must be "ti-conf" for the TI-specific registers + The second entry must be "rc-dbics" for the DesignWare PCIe + registers + The third entry must be "config" for the PCIe configuration space + - interrupts : Two interrupt entries must be specified. The first one is for + main interrupt line and the second for MSI interrupt line. + - #address-cells, + #size-cells, + #interrupt-cells, + device_type, + ranges, + interrupt-map-mask, + interrupt-map : as specified in ../designware-pcie.txt + +DEVICE MODE +=========== + - reg : Four register ranges as listed in the reg-names property + - reg-names : "ti-conf" for the TI-specific registers + "ep_dbics" for the standard configuration registers as + they are locally accessed within the DIF CS space + "ep_dbics2" for the standard configuration registers as + they are locally accessed within the DIF CS2 space + "addr_space" used to map remote RC address space + - interrupts : one interrupt entries must be specified for main interrupt. + - num-ib-windows : number of inbound address translation windows + - num-ob-windows : number of outbound address translation windows + - ti,syscon-unaligned-access: phandle to the syscon DT node. The 1st argument + should contain the register offset within syscon + and the 2nd argument should contain the bit field + for setting the bit to enable unaligned + access. + +Optional Property: + - gpios : Should be added if a GPIO line is required to drive PERST# line + +NOTE: Two DT nodes may be added for each PCI controller; one for host +mode and another for device mode. So in order for PCI to +work in host mode, EP mode DT node should be disabled and in order to PCI to +work in EP mode, host mode DT node should be disabled. Host mode and EP +mode are mutually exclusive. + +Example: +axi { + compatible = "simple-bus"; + #size-cells = <1>; + #address-cells = <1>; + ranges = <0x51000000 0x51000000 0x3000 + 0x0 0x20000000 0x10000000>; + pcie@51000000 { + compatible = "ti,dra7-pcie"; + reg = <0x51000000 0x2000>, <0x51002000 0x14c>, <0x1000 0x2000>; + reg-names = "rc_dbics", "ti_conf", "config"; + interrupts = <0 232 0x4>, <0 233 0x4>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + ranges = <0x81000000 0 0 0x03000 0 0x00010000 + 0x82000000 0 0x20013000 0x13000 0 0xffed000>; + #interrupt-cells = <1>; + num-lanes = <1>; + ti,hwmods = "pcie1"; + phys = <&pcie1_phy>; + phy-names = "pcie-phy0"; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 1>, + <0 0 0 2 &pcie_intc 2>, + <0 0 0 3 &pcie_intc 3>, + <0 0 0 4 &pcie_intc 4>; + pcie_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/v3-v360epc-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/v3-v360epc-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..11063293f76190dd9662849bf97c9abe5e61624d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/v3-v360epc-pci.txt @@ -0,0 +1,76 @@ +V3 Semiconductor V360 EPC PCI bridge + +This bridge is found in the ARM Integrator/AP (Application Platform) + +Required properties: +- compatible: should be one of: + "v3,v360epc-pci" + "arm,integrator-ap-pci", "v3,v360epc-pci" +- reg: should contain two register areas: + first the base address of the V3 host bridge controller, 64KB + second the configuration area register space, 16MB +- interrupts: should contain a reference to the V3 error interrupt + as routed on the system. +- bus-range: see pci.txt +- ranges: this follows the standard PCI bindings in the IEEE Std + 1275-1994 (see pci.txt) with the following restriction: + - The non-prefetchable and prefetchable memory windows must + each be exactly 256MB (0x10000000) in size. + - The prefetchable memory window must be immediately adjacent + to the non-prefetcable memory window +- dma-ranges: three ranges for the inbound memory region. The ranges must + be aligned to a 1MB boundary, and may be 1MB, 2MB, 4MB, 8MB, 16MB, 32MB, + 64MB, 128MB, 256MB, 512MB, 1GB or 2GB in size. The memory should be marked + as pre-fetchable. Two ranges are supported by the hardware. + +Integrator-specific required properties: +- syscon: should contain a link to the syscon device node, since + on the Integrator, some registers in the syscon are required to + operate the V3 host bridge. + +Example: + +pci: pciv3@62000000 { + compatible = "arm,integrator-ap-pci", "v3,v360epc-pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = <0x62000000 0x10000>, <0x61000000 0x01000000>; + interrupt-parent = <&pic>; + interrupts = <17>; /* Bus error IRQ */ + clocks = <&pciclk>; + bus-range = <0x00 0xff>; + ranges = 0x01000000 0 0x00000000 /* I/O space @00000000 */ + 0x60000000 0 0x01000000 /* 16 MiB @ LB 60000000 */ + 0x02000000 0 0x40000000 /* non-prefectable memory @40000000 */ + 0x40000000 0 0x10000000 /* 256 MiB @ LB 40000000 1:1 */ + 0x42000000 0 0x50000000 /* prefetchable memory @50000000 */ + 0x50000000 0 0x10000000>; /* 256 MiB @ LB 50000000 1:1 */ + dma-ranges = <0x02000000 0 0x20000000 /* EBI memory space */ + 0x20000000 0 0x20000000 /* 512 MB @ LB 20000000 1:1 */ + 0x02000000 0 0x80000000 /* Core module alias memory */ + 0x80000000 0 0x40000000>; /* 1GB @ LB 80000000 */ + interrupt-map-mask = <0xf800 0 0 0x7>; + interrupt-map = < + /* IDSEL 9 */ + 0x4800 0 0 1 &pic 13 /* INT A on slot 9 is irq 13 */ + 0x4800 0 0 2 &pic 14 /* INT B on slot 9 is irq 14 */ + 0x4800 0 0 3 &pic 15 /* INT C on slot 9 is irq 15 */ + 0x4800 0 0 4 &pic 16 /* INT D on slot 9 is irq 16 */ + /* IDSEL 10 */ + 0x5000 0 0 1 &pic 14 /* INT A on slot 10 is irq 14 */ + 0x5000 0 0 2 &pic 15 /* INT B on slot 10 is irq 15 */ + 0x5000 0 0 3 &pic 16 /* INT C on slot 10 is irq 16 */ + 0x5000 0 0 4 &pic 13 /* INT D on slot 10 is irq 13 */ + /* IDSEL 11 */ + 0x5800 0 0 1 &pic 15 /* INT A on slot 11 is irq 15 */ + 0x5800 0 0 2 &pic 16 /* INT B on slot 11 is irq 16 */ + 0x5800 0 0 3 &pic 13 /* INT C on slot 11 is irq 13 */ + 0x5800 0 0 4 &pic 14 /* INT D on slot 11 is irq 14 */ + /* IDSEL 12 */ + 0x6000 0 0 1 &pic 16 /* INT A on slot 12 is irq 16 */ + 0x6000 0 0 2 &pic 13 /* INT B on slot 12 is irq 13 */ + 0x6000 0 0 3 &pic 14 /* INT C on slot 12 is irq 14 */ + 0x6000 0 0 4 &pic 15 /* INT D on slot 12 is irq 15 */ + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/versatile.txt b/arch/arm64/boot/dts/vendor/bindings/pci/versatile.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a702b13d2acc28a5e460f033384e2d4f57dbc25 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/versatile.txt @@ -0,0 +1,59 @@ +* ARM Versatile Platform Baseboard PCI interface + +PCI host controller found on the ARM Versatile PB board's FPGA. + +Required properties: +- compatible: should contain "arm,versatile-pci" to identify the Versatile PCI + controller. +- reg: base addresses and lengths of the PCI controller. There must be 3 + entries: + - Versatile-specific registers + - Self Config space + - Config space +- #address-cells: set to <3> +- #size-cells: set to <2> +- device_type: set to "pci" +- bus-range: set to <0 0xff> +- ranges: ranges for the PCI memory and I/O regions +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties to define + the mapping of the PCI interface to interrupt numbers. + +Example: + +pci-controller@10001000 { + compatible = "arm,versatile-pci"; + device_type = "pci"; + reg = <0x10001000 0x1000 + 0x41000000 0x10000 + 0x42000000 0x100000>; + bus-range = <0 0xff>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + + ranges = <0x01000000 0 0x00000000 0x43000000 0 0x00010000 /* downstream I/O */ + 0x02000000 0 0x50000000 0x50000000 0 0x10000000 /* non-prefetchable memory */ + 0x42000000 0 0x60000000 0x60000000 0 0x10000000>; /* prefetchable memory */ + + interrupt-map-mask = <0x1800 0 0 7>; + interrupt-map = <0x1800 0 0 1 &sic 28 + 0x1800 0 0 2 &sic 29 + 0x1800 0 0 3 &sic 30 + 0x1800 0 0 4 &sic 27 + + 0x1000 0 0 1 &sic 27 + 0x1000 0 0 2 &sic 28 + 0x1000 0 0 3 &sic 29 + 0x1000 0 0 4 &sic 30 + + 0x0800 0 0 1 &sic 30 + 0x0800 0 0 2 &sic 27 + 0x0800 0 0 3 &sic 28 + 0x0800 0 0 4 &sic 29 + + 0x0000 0 0 1 &sic 29 + 0x0000 0 0 2 &sic 30 + 0x0000 0 0 3 &sic 27 + 0x0000 0 0 4 &sic 28>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/xgene-pci-msi.txt b/arch/arm64/boot/dts/vendor/bindings/pci/xgene-pci-msi.txt new file mode 100644 index 0000000000000000000000000000000000000000..85d9b95234f7d914af80ae1c81b98cd2ff31cdae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/xgene-pci-msi.txt @@ -0,0 +1,68 @@ +* AppliedMicro X-Gene v1 PCIe MSI controller + +Required properties: + +- compatible: should be "apm,xgene1-msi" to identify + X-Gene v1 PCIe MSI controller block. +- msi-controller: indicates that this is an X-Gene v1 PCIe MSI controller node +- reg: physical base address (0x79000000) and length (0x900000) for controller + registers. These registers include the MSI termination address and data + registers as well as the MSI interrupt status registers. +- reg-names: not required +- interrupts: A list of 16 interrupt outputs of the controller, starting from + interrupt number 0x10 to 0x1f. +- interrupt-names: not required + +Each PCIe node needs to have property msi-parent that points to an MSI +controller node + +Examples: + +SoC DTSI: + + + MSI node: + msi@79000000 { + compatible = "apm,xgene1-msi"; + msi-controller; + reg = <0x00 0x79000000 0x0 0x900000>; + interrupts = <0x0 0x10 0x4> + <0x0 0x11 0x4> + <0x0 0x12 0x4> + <0x0 0x13 0x4> + <0x0 0x14 0x4> + <0x0 0x15 0x4> + <0x0 0x16 0x4> + <0x0 0x17 0x4> + <0x0 0x18 0x4> + <0x0 0x19 0x4> + <0x0 0x1a 0x4> + <0x0 0x1b 0x4> + <0x0 0x1c 0x4> + <0x0 0x1d 0x4> + <0x0 0x1e 0x4> + <0x0 0x1f 0x4>; + }; + + + PCIe controller node with msi-parent property pointing to MSI node: + pcie0: pcie@1f2b0000 { + device_type = "pci"; + compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ + 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */ + 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 + 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; + dma-coherent; + clocks = <&pcie0clk 0>; + msi-parent= <&msi>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/xgene-pci.txt b/arch/arm64/boot/dts/vendor/bindings/pci/xgene-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..92490330dc1c7e7444dfe1176944cbb06b36a97b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/xgene-pci.txt @@ -0,0 +1,50 @@ +* AppliedMicro X-Gene PCIe interface + +Required properties: +- device_type: set to "pci" +- compatible: should contain "apm,xgene-pcie" to identify the core. +- reg: A list of physical base address and length for each set of controller + registers. Must contain an entry for each entry in the reg-names + property. +- reg-names: Must include the following entries: + "csr": controller configuration registers. + "cfg": PCIe configuration space registers. +- #address-cells: set to <3> +- #size-cells: set to <2> +- ranges: ranges for the outbound memory, I/O regions. +- dma-ranges: ranges for the inbound memory regions. +- #interrupt-cells: set to <1> +- interrupt-map-mask and interrupt-map: standard PCI properties + to define the mapping of the PCIe interface to interrupt + numbers. +- clocks: from common clock binding: handle to pci clock. + +Optional properties: +- status: Either "ok" or "disabled". +- dma-coherent: Present if DMA operations are coherent + +Example: + + pcie0: pcie@1f2b0000 { + status = "disabled"; + device_type = "pci"; + compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */ + 0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */ + reg-names = "csr", "cfg"; + ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */ + 0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */ + dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000 + 0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1 + 0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1 + 0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1 + 0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>; + dma-coherent; + clocks = <&pcie0clk 0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/xilinx-nwl-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/xilinx-nwl-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..01bf7fdf4c19208f38dba304909e432a45b90560 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/xilinx-nwl-pcie.txt @@ -0,0 +1,70 @@ +* Xilinx NWL PCIe Root Port Bridge DT description + +Required properties: +- compatible: Should contain "xlnx,nwl-pcie-2.11" +- #address-cells: Address representation for root ports, set to <3> +- #size-cells: Size representation for root ports, set to <2> +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. +- reg: Should contain Bridge, PCIe Controller registers location, + configuration space, and length +- reg-names: Must include the following entries: + "breg": bridge registers + "pcireg": PCIe controller registers + "cfg": configuration space region +- device_type: must be "pci" +- interrupts: Should contain NWL PCIe interrupt +- interrupt-names: Must include the following entries: + "msi1, msi0": interrupt asserted when an MSI is received + "intx": interrupt asserted when a legacy interrupt is received + "misc": interrupt asserted when miscellaneous interrupt is received +- interrupt-map-mask and interrupt-map: standard PCI properties to define the + mapping of the PCI interface to interrupt numbers. +- ranges: ranges for the PCI memory regions (I/O space region is not + supported by hardware) + Please refer to the standard PCI bus binding document for a more + detailed explanation +- msi-controller: indicates that this is MSI controller node +- msi-parent: MSI parent of the root complex itself +- legacy-interrupt-controller: Interrupt controller device node for Legacy + interrupts + - interrupt-controller: identifies the node as an interrupt controller + - #interrupt-cells: should be set to 1 + - #address-cells: specifies the number of cells needed to encode an + address. The value must be 0. + + +Example: +++++++++ + +nwl_pcie: pcie@fd0e0000 { + #address-cells = <3>; + #size-cells = <2>; + compatible = "xlnx,nwl-pcie-2.11"; + #interrupt-cells = <1>; + msi-controller; + device_type = "pci"; + interrupt-parent = <&gic>; + interrupts = <0 114 4>, <0 115 4>, <0 116 4>, <0 117 4>, <0 118 4>; + interrupt-names = "msi0", "msi1", "intx", "dummy", "misc"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc 0x1>, + <0x0 0x0 0x0 0x2 &pcie_intc 0x2>, + <0x0 0x0 0x0 0x3 &pcie_intc 0x3>, + <0x0 0x0 0x0 0x4 &pcie_intc 0x4>; + + msi-parent = <&nwl_pcie>; + reg = <0x0 0xfd0e0000 0x0 0x1000>, + <0x0 0xfd480000 0x0 0x1000>, + <0x80 0x00000000 0x0 0x1000000>; + reg-names = "breg", "pcireg", "cfg"; + ranges = <0x02000000 0x00000000 0xe0000000 0x00000000 0xe0000000 0x00000000 0x10000000 /* non-prefetchable memory */ + 0x43000000 0x00000006 0x00000000 0x00000006 0x00000000 0x00000002 0x00000000>;/* prefetchable memory */ + + pcie_intc: legacy-interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pci/xilinx-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/pci/xilinx-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd57a81180a4759be7fcbfb4bf23ea3f2985bde7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pci/xilinx-pcie.txt @@ -0,0 +1,88 @@ +* Xilinx AXI PCIe Root Port Bridge DT description + +Required properties: +- #address-cells: Address representation for root ports, set to <3> +- #size-cells: Size representation for root ports, set to <2> +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. +- compatible: Should contain "xlnx,axi-pcie-host-1.00.a" +- reg: Should contain AXI PCIe registers location and length +- device_type: must be "pci" +- interrupts: Should contain AXI PCIe interrupt +- interrupt-map-mask, + interrupt-map: standard PCI properties to define the mapping of the + PCI interface to interrupt numbers. +- ranges: ranges for the PCI memory regions (I/O space region is not + supported by hardware) + Please refer to the standard PCI bus binding document for a more + detailed explanation + +Optional properties for Zynq/Microblaze: +- bus-range: PCI bus numbers covered + +Interrupt controller child node ++++++++++++++++++++++++++++++++ +Required properties: +- interrupt-controller: identifies the node as an interrupt controller +- #address-cells: specifies the number of cells needed to encode an + address. The value must be 0. +- #interrupt-cells: specifies the number of cells needed to encode an + interrupt source. The value must be 1. + +NOTE: +The core provides a single interrupt for both INTx/MSI messages. So, +created a interrupt controller node to support 'interrupt-map' DT +functionality. The driver will create an IRQ domain for this map, decode +the four INTx interrupts in ISR and route them to this domain. + + +Example: +++++++++ +Zynq: + pci_express: axi-pcie@50000000 { + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + compatible = "xlnx,axi-pcie-host-1.00.a"; + reg = < 0x50000000 0x1000000 >; + device_type = "pci"; + interrupts = < 0 52 4 >; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 1>, + <0 0 0 2 &pcie_intc 2>, + <0 0 0 3 &pcie_intc 3>, + <0 0 0 4 &pcie_intc 4>; + ranges = < 0x02000000 0 0x60000000 0x60000000 0 0x10000000 >; + + pcie_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + }; + + +Microblaze: + pci_express: axi-pcie@10000000 { + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + compatible = "xlnx,axi-pcie-host-1.00.a"; + reg = <0x10000000 0x4000000>; + device_type = "pci"; + interrupt-parent = <µblaze_0_intc>; + interrupts = <1 2>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0 0 0 1 &pcie_intc 1>, + <0 0 0 2 &pcie_intc 2>, + <0 0 0 3 &pcie_intc 3>, + <0 0 0 4 &pcie_intc 4>; + ranges = <0x02000000 0x00000000 0x80000000 0x80000000 0x00000000 0x10000000>; + + pcie_intc: interrupt-controller { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/perf/apm-xgene-pmu.txt b/arch/arm64/boot/dts/vendor/bindings/perf/apm-xgene-pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..afb11cf693c0c6dcf3dfd2f344b0db286cbc5b32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/perf/apm-xgene-pmu.txt @@ -0,0 +1,112 @@ +* APM X-Gene SoC PMU bindings + +This is APM X-Gene SoC PMU (Performance Monitoring Unit) module. +The following PMU devices are supported: + + L3C - L3 cache controller + IOB - IO bridge + MCB - Memory controller bridge + MC - Memory controller + +The following section describes the SoC PMU DT node binding. + +Required properties: +- compatible : Shall be "apm,xgene-pmu" for revision 1 or + "apm,xgene-pmu-v2" for revision 2. +- regmap-csw : Regmap of the CPU switch fabric (CSW) resource. +- regmap-mcba : Regmap of the MCB-A (memory bridge) resource. +- regmap-mcbb : Regmap of the MCB-B (memory bridge) resource. +- reg : First resource shall be the CPU bus PMU resource. +- interrupts : Interrupt-specifier for PMU IRQ. + +Required properties for L3C subnode: +- compatible : Shall be "apm,xgene-pmu-l3c". +- reg : First resource shall be the L3C PMU resource. + +Required properties for IOB subnode: +- compatible : Shall be "apm,xgene-pmu-iob". +- reg : First resource shall be the IOB PMU resource. + +Required properties for MCB subnode: +- compatible : Shall be "apm,xgene-pmu-mcb". +- reg : First resource shall be the MCB PMU resource. +- enable-bit-index : The bit indicates if the according MCB is enabled. + +Required properties for MC subnode: +- compatible : Shall be "apm,xgene-pmu-mc". +- reg : First resource shall be the MC PMU resource. +- enable-bit-index : The bit indicates if the according MC is enabled. + +Example: + csw: csw@7e200000 { + compatible = "apm,xgene-csw", "syscon"; + reg = <0x0 0x7e200000 0x0 0x1000>; + }; + + mcba: mcba@7e700000 { + compatible = "apm,xgene-mcb", "syscon"; + reg = <0x0 0x7e700000 0x0 0x1000>; + }; + + mcbb: mcbb@7e720000 { + compatible = "apm,xgene-mcb", "syscon"; + reg = <0x0 0x7e720000 0x0 0x1000>; + }; + + pmu: pmu@78810000 { + compatible = "apm,xgene-pmu-v2"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + regmap-csw = <&csw>; + regmap-mcba = <&mcba>; + regmap-mcbb = <&mcbb>; + reg = <0x0 0x78810000 0x0 0x1000>; + interrupts = <0x0 0x22 0x4>; + + pmul3c@7e610000 { + compatible = "apm,xgene-pmu-l3c"; + reg = <0x0 0x7e610000 0x0 0x1000>; + }; + + pmuiob@7e940000 { + compatible = "apm,xgene-pmu-iob"; + reg = <0x0 0x7e940000 0x0 0x1000>; + }; + + pmucmcb@7e710000 { + compatible = "apm,xgene-pmu-mcb"; + reg = <0x0 0x7e710000 0x0 0x1000>; + enable-bit-index = <0>; + }; + + pmucmcb@7e730000 { + compatible = "apm,xgene-pmu-mcb"; + reg = <0x0 0x7e730000 0x0 0x1000>; + enable-bit-index = <1>; + }; + + pmucmc@7e810000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e810000 0x0 0x1000>; + enable-bit-index = <0>; + }; + + pmucmc@7e850000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e850000 0x0 0x1000>; + enable-bit-index = <1>; + }; + + pmucmc@7e890000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e890000 0x0 0x1000>; + enable-bit-index = <2>; + }; + + pmucmc@7e8d0000 { + compatible = "apm,xgene-pmu-mc"; + reg = <0x0 0x7e8d0000 0x0 0x1000>; + enable-bit-index = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/perf/arm-ccn.txt b/arch/arm64/boot/dts/vendor/bindings/perf/arm-ccn.txt new file mode 100644 index 0000000000000000000000000000000000000000..43b5a71a5a9dde70aeebc38510e5a478e1d8d742 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/perf/arm-ccn.txt @@ -0,0 +1,22 @@ +* ARM CCN (Cache Coherent Network) + +Required properties: + +- compatible: (standard compatible string) should be one of: + "arm,ccn-502" + "arm,ccn-504" + "arm,ccn-508" + +- reg: (standard registers property) physical address and size + (16MB) of the configuration registers block + +- interrupts: (standard interrupt property) single interrupt + generated by the control block + +Example: + + ccn@2000000000 { + compatible = "arm,ccn-504"; + reg = <0x20 0x00000000 0 0x1000000>; + interrupts = <0 181 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/perf/qcom-l2-counters.txt b/arch/arm64/boot/dts/vendor/bindings/perf/qcom-l2-counters.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa2c037f214121057b800a510dfa9dfc4a240f60 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/perf/qcom-l2-counters.txt @@ -0,0 +1,61 @@ +* Qualcomm Technologies, L2CACHE COUNTERS Bindings + +This represents the several hardware counters located in each cluster levels. +And each counter counter specific transactions on cluster level like. + +DDR write counter : Write-Back, Write-Clean and Write-Evict transactions on + GNOC Interface. + +DDR read counter : Read-Shared, Read-Unique, Read-Clean and + Read-Not-Shared-Dirty transactions on GNOC interface. + +Snoop read counter : Read-Once, Read-Shared, Read-Unique, Read-Clean and + Read-Not-Shared-Dirty transactions from GNOC to Cluster + interface. + +ACP write counter : Write-Back, Write-Clean and Write-Evict transactions to ACP + port of Collapsed Cluster. + +Tenure counter : Low-Power mode tenure is used to count tenure (no. of XO - + 19.2MHz) of L2 Low-Power mode. + +Low/Mid/High +occurrence counter : Based on threshold set for low and mid tenure counter, + current tenure count compared against them and based + on which category it belongs respective counter + (low/mid/high occurrence counters) gets incremented. + e.g : + +1. 0 < Current Tenure <= Low-tenure threshold : Low-Tenure category +2. Low-tenure < Current Tenure <= Mid-tenure threshold : Mid-Tenure category +3. Mid-tenure < Current tenure : High-Tenure category + + +The follow section describes the L2 CACHE Counters DT node binding. + +Required properties: +- compatible : Shall be "qcom,l2cache-pmu" +- reg : There shall be one resource per cluster of the form + < base_address total_size > representing the counters + register region. +- irq : There shall be one interrupt resource per cluster. + +e.g: +l2cache_pmu { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,l2cache-pmu"; + ranges; + + cluster0@f111000 { + cluster-id = <0>; + interrupts = ; + reg = <0xf111000 0x1000>; + }; + + cluster1@f011000 { + cluster-id = <1>; + interrupts = ; + reg = <0xf011000 0x1000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/perf/qcom-llcc-pmu.txt b/arch/arm64/boot/dts/vendor/bindings/perf/qcom-llcc-pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd2a249167ae437240e0af65d9640ef60a8b7a92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/perf/qcom-llcc-pmu.txt @@ -0,0 +1,22 @@ +* QCOM LLCC PMU Bindings + +This represents the miss counters located in the LLCC hardware counters. +Only one event is supported: + + 0x1000 - LLCC misses + +The follow section describes the LLCC PMU DT node binding. + +Required properties: +- compatible : Shall be "qcom,llcc-pmu-ver1" or "qcom,llcc-pmu-ver2" +- reg : There shall be one resource, a pair of the form + < base_address total_size > representing the DDR_LAGG + region. +- reg-names : Shall be "lagg-base". + +Example: + llcc_pmu: llcc-pmu { + compatible = "qcom,qcom-llcc-pmu"; + reg = < 0x090CC000 0x300 >; + reg-names = "lagg-base"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/apm-xgene-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/apm-xgene-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1bb12711fbf8266bccecde2cbac1cf39ea29b94 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/apm-xgene-phy.txt @@ -0,0 +1,76 @@ +* APM X-Gene 15Gbps Multi-purpose PHY nodes + +PHY nodes are defined to describe on-chip 15Gbps Multi-purpose PHY. Each +PHY (pair of lanes) has its own node. + +Required properties: +- compatible : Shall be "apm,xgene-phy". +- reg : PHY memory resource is the SDS PHY access resource. +- #phy-cells : Shall be 1 as it expects one argument for setting + the mode of the PHY. Possible values are 0 (SATA), + 1 (SGMII), 2 (PCIe), 3 (USB), and 4 (XFI). + +Optional properties: +- status : Shall be "ok" if enabled or "disabled" if disabled. + Default is "ok". +- clocks : Reference to the clock entry. +- apm,tx-eye-tuning : Manual control to fine tune the capture of the serial + bit lines from the automatic calibrated position. + Two set of 3-tuple setting for each (up to 3) + supported link speed on the host. Range from 0 to + 127 in unit of one bit period. Default is 10. +- apm,tx-eye-direction : Eye tuning manual control direction. 0 means sample + data earlier than the nominal sampling point. 1 means + sample data later than the nominal sampling point. + Two set of 3-tuple setting for each (up to 3) + supported link speed on the host. Default is 0. +- apm,tx-boost-gain : Frequency boost AC (LSB 3-bit) and DC (2-bit) + gain control. Two set of 3-tuple setting for each + (up to 3) supported link speed on the host. Range is + between 0 to 31 in unit of dB. Default is 3. +- apm,tx-amplitude : Amplitude control. Two set of 3-tuple setting for + each (up to 3) supported link speed on the host. + Range is between 0 to 199500 in unit of uV. + Default is 199500 uV. +- apm,tx-pre-cursor1 : 1st pre-cursor emphasis taps control. Two set of + 3-tuple setting for each (up to 3) supported link + speed on the host. Range is 0 to 273000 in unit of + uV. Default is 0. +- apm,tx-pre-cursor2 : 2st pre-cursor emphasis taps control. Two set of + 3-tuple setting for each (up to 3) supported link + speed on the host. Range is 0 to 127400 in unit uV. + Default is 0x0. +- apm,tx-post-cursor : Post-cursor emphasis taps control. Two set of + 3-tuple setting for Gen1, Gen2, and Gen3. Range is + between 0 to 0x1f in unit of 18.2mV. Default is 0xf. +- apm,tx-speed : Tx operating speed. One set of 3-tuple for each + supported link speed on the host. + 0 = 1-2Gbps + 1 = 2-4Gbps (1st tuple default) + 2 = 4-8Gbps + 3 = 8-15Gbps (2nd tuple default) + 4 = 2.5-4Gbps + 5 = 4-5Gbps + 6 = 5-6Gbps + 7 = 6-16Gbps (3rd tuple default) + +NOTE: PHY override parameters are board specific setting. + +Example: + phy1: phy@1f21a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f21a000 0x0 0x100>; + #phy-cells = <1>; + }; + + phy2: phy@1f22a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f22a000 0x0 0x100>; + #phy-cells = <1>; + }; + + phy3: phy@1f23a000 { + compatible = "apm,xgene-phy"; + reg = <0x0 0x1f23a000 0x0 0x100>; + #phy-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/bcm-ns-usb2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/bcm-ns-usb2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7aee9ea8926c409add88e6992b50b32261ce358 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/bcm-ns-usb2-phy.txt @@ -0,0 +1,21 @@ +Driver for Broadcom Northstar USB 2.0 PHY + +Required properties: +- compatible: brcm,ns-usb2-phy +- reg: iomem address range of DMU (Device Management Unit) +- reg-names: "dmu", the only needed & supported reg right now +- clocks: USB PHY reference clock +- clock-names: "phy-ref-clk", the only needed & supported clock right now + +To initialize USB 2.0 PHY driver needs to setup PLL correctly. To do this it +requires passing phandle to the USB PHY reference clock. + +Example: + usb2-phy { + compatible = "brcm,ns-usb2-phy"; + reg = <0x1800c000 0x1000>; + reg-names = "dmu"; + #phy-cells = <0>; + clocks = <&genpll BCM_NSP_GENPLL_USB_PHY_REF_CLK>; + clock-names = "phy-ref-clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/bcm-ns-usb3-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/bcm-ns-usb3-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..32f05726035194b30ac01a5a34dfb6c2336146a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/bcm-ns-usb3-phy.txt @@ -0,0 +1,34 @@ +Driver for Broadcom Northstar USB 3.0 PHY + +Required properties: + +- compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy". +- reg: address of MDIO bus device +- usb3-dmp-syscon: phandle to syscon with DMP (Device Management Plugin) + registers +- #phy-cells: must be 0 + +Initialization of USB 3.0 PHY depends on Northstar version. There are currently +three known series: Ax, Bx and Cx. +Known A0: BCM4707 rev 0 +Known B0: BCM4707 rev 4, BCM53573 rev 2 +Known B1: BCM4707 rev 6 +Known C0: BCM47094 rev 0 + +Example: + mdio: mdio@0 { + reg = <0x0>; + #size-cells = <1>; + #address-cells = <0>; + + usb3-phy@10 { + compatible = "brcm,ns-ax-usb3-phy"; + reg = <0x10>; + usb3-dmp-syscon = <&usb3_dmp>; + #phy-cells = <0>; + }; + }; + + usb3_dmp: syscon@18105000 { + reg = <0x18105000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/berlin-sata-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/berlin-sata-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..c0155f842f62a60caf6ba77d44adc0c288715c99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/berlin-sata-phy.txt @@ -0,0 +1,36 @@ +Berlin SATA PHY +--------------- + +Required properties: +- compatible: should be one of + "marvell,berlin2-sata-phy" + "marvell,berlin2q-sata-phy" +- address-cells: should be 1 +- size-cells: should be 0 +- phy-cells: from the generic PHY bindings, must be 1 +- reg: address and length of the register +- clocks: reference to the clock entry + +Sub-nodes: +Each PHY should be represented as a sub-node. + +Sub-nodes required properties: +- reg: the PHY number + +Example: + sata_phy: phy@f7e900a0 { + compatible = "marvell,berlin2q-sata-phy"; + reg = <0xf7e900a0 0x200>; + clocks = <&chip CLKID_SATA>; + #address-cells = <1>; + #size-cells = <0>; + #phy-cells = <1>; + + sata-phy@0 { + reg = <0>; + }; + + sata-phy@1 { + reg = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/berlin-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/berlin-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..be33780f668e7c58ef86aa19c6d552a8385d3390 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/berlin-usb-phy.txt @@ -0,0 +1,16 @@ +* Marvell Berlin USB PHY + +Required properties: +- compatible: "marvell,berlin2-usb-phy" or "marvell,berlin2cd-usb-phy" +- reg: base address and length of the registers +- #phys-cells: should be 0 +- resets: reference to the reset controller + +Example: + + usb-phy@f774000 { + compatible = "marvell,berlin2-usb-phy"; + reg = <0xf774000 0x128>; + #phy-cells = <0>; + resets = <&chip 0x104 14>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm,brcmstb-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,brcmstb-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..24a0d06acd1d3508a4b45d2df8dff0c9141018b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,brcmstb-usb-phy.txt @@ -0,0 +1,43 @@ +Broadcom STB USB PHY + +Required properties: + - compatible: brcm,brcmstb-usb-phy + - reg: two offset and length pairs. + The first pair specifies a manditory set of memory mapped + registers used for general control of the PHY. + The second pair specifies optional registers used by some of + the SoCs that support USB 3.x + - #phy-cells: Shall be 1 as it expects one argument for setting + the type of the PHY. Possible values are: + - PHY_TYPE_USB2 for USB1.1/2.0 PHY + - PHY_TYPE_USB3 for USB3.x PHY + +Optional Properties: +- clocks : clock phandles. +- clock-names: String, clock name. +- brcm,ipp: Boolean, Invert Port Power. + Possible values are: 0 (Don't invert), 1 (Invert) +- brcm,ioc: Boolean, Invert Over Current detection. + Possible values are: 0 (Don't invert), 1 (Invert) +NOTE: one or both of the following two properties must be set +- brcm,has-xhci: Boolean indicating the phy has an XHCI phy. +- brcm,has-eohci: Boolean indicating the phy has an EHCI/OHCI phy. +- dr_mode: String, PHY Device mode. + Possible values are: "host", "peripheral ", "drd" or "typec-pd" + If this property is not defined, the phy will default to "host" mode. + +Example: + +usbphy_0: usb-phy@f0470200 { + reg = <0xf0470200 0xb8>, + <0xf0471940 0x6c0>; + compatible = "brcm,brcmstb-usb-phy"; + #phy-cells = <1>; + dr_mode = "host" + brcm,ioc = <1>; + brcm,ipp = <1>; + brcm,has-xhci; + brcm,has-eohci; + clocks = <&usb20>, <&usb30>; + clock-names = "sw_usb", "sw_usb3"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm,cygnus-pcie-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,cygnus-pcie-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..10efff28b52b247161e5bce5e7abb37ae39e07e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,cygnus-pcie-phy.txt @@ -0,0 +1,47 @@ +Broadcom Cygnus PCIe PHY + +Required properties: +- compatible: must be "brcm,cygnus-pcie-phy" +- reg: base address and length of the PCIe PHY block +- #address-cells: must be 1 +- #size-cells: must be 0 + +Each PCIe PHY should be represented by a child node + +Required properties For the child node: +- reg: the PHY ID +0 - PCIe RC 0 +1 - PCIe RC 1 +- #phy-cells: must be 0 + +Example: + pcie_phy: phy@301d0a0 { + compatible = "brcm,cygnus-pcie-phy"; + reg = <0x0301d0a0 0x14>; + + pcie0_phy: phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + pcie1_phy: phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; + + /* users of the PCIe phy */ + + pcie0: pcie@18012000 { + ... + ... + phys = <&pcie0_phy>; + phy-names = "pcie-phy"; + }; + + pcie1: pcie@18013000 { + ... + ... + phys = ; + phy-names = "pcie-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm,kona-usb2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,kona-usb2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dc8b3d2ffbbeed6e6afeba5d3ee04c803efbaab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,kona-usb2-phy.txt @@ -0,0 +1,15 @@ +BROADCOM KONA USB2 PHY + +Required properties: + - compatible: brcm,kona-usb2-phy + - reg: offset and length of the PHY registers + - #phy-cells: must be 0 +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Example: + + usbphy: usb-phy@3f130000 { + compatible = "brcm,kona-usb2-phy"; + reg = <0x3f130000 0x28>; + #phy-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm,mdio-mux-bus-pci.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,mdio-mux-bus-pci.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b51007c6f244850e5c1734b920829ef19789d5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,mdio-mux-bus-pci.txt @@ -0,0 +1,27 @@ +* Broadcom NS2 PCIe PHY binding document + +Required bus properties: +- reg: MDIO Bus number for the MDIO interface +- #address-cells: must be 1 +- #size-cells: must be 0 + +Required PHY properties: +- compatible: should be "brcm,ns2-pcie-phy" +- reg: MDIO Phy ID for the MDIO interface +- #phy-cells: must be 0 + +This is a child bus node of "brcm,mdio-mux-iproc" node. + +Example: + +mdio@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + pci_phy0: pci-phy@0 { + compatible = "brcm,ns2-pcie-phy"; + reg = <0x0>; + #phy-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm,ns2-drd-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,ns2-drd-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..04f063aa788301f7e8fbeb9a0803f13c00f7b7ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,ns2-drd-phy.txt @@ -0,0 +1,30 @@ +BROADCOM NORTHSTAR2 USB2 (DUAL ROLE DEVICE) PHY + +Required properties: + - compatible: brcm,ns2-drd-phy + - reg: offset and length of the NS2 PHY related registers. + - reg-names + The below registers must be provided. + icfg - for DRD ICFG configurations + rst-ctrl - for DRD IDM reset + crmu-ctrl - for CRMU core vdd, PHY and PHY PLL reset + usb2-strap - for port over current polarity reversal + - #phy-cells: Must be 0. No args required. + - vbus-gpios: vbus gpio binding + - id-gpios: id gpio binding + +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Example: + usbdrd_phy: phy@66000960 { + #phy-cells = <0>; + compatible = "brcm,ns2-drd-phy"; + reg = <0x66000960 0x24>, + <0x67012800 0x4>, + <0x6501d148 0x4>, + <0x664d0700 0x4>; + reg-names = "icfg", "rst-ctrl", + "crmu-ctrl", "usb2-strap"; + id-gpios = <&gpio_g 30 0>; + vbus-gpios = <&gpio_g 31 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm,sr-pcie-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,sr-pcie-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8d82286beb9d6b3924df09908a59154be265a8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm,sr-pcie-phy.txt @@ -0,0 +1,41 @@ +Broadcom Stingray PCIe PHY + +Required properties: +- compatible: must be "brcm,sr-pcie-phy" +- reg: base address and length of the PCIe SS register space +- brcm,sr-cdru: phandle to the CDRU syscon node +- brcm,sr-mhb: phandle to the MHB syscon node +- #phy-cells: Must be 1, denotes the PHY index + +For PAXB based root complex, one can have a configuration of up to 8 PHYs +PHY index goes from 0 to 7 + +For the internal PAXC based root complex, PHY index is always 8 + +Example: + mhb: syscon@60401000 { + compatible = "brcm,sr-mhb", "syscon"; + reg = <0 0x60401000 0 0x38c>; + }; + + cdru: syscon@6641d000 { + compatible = "brcm,sr-cdru", "syscon"; + reg = <0 0x6641d000 0 0x400>; + }; + + pcie_phy: phy@40000000 { + compatible = "brcm,sr-pcie-phy"; + reg = <0 0x40000000 0 0x800>; + brcm,sr-cdru = <&cdru>; + brcm,sr-mhb = <&mhb>; + #phy-cells = <1>; + }; + + /* users of the PCIe PHY */ + + pcie0: pcie@48000000 { + ... + ... + phys = <&pcie_phy 0>; + phy-names = "pcie-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/brcm-sata-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/brcm-sata-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..0aced97d8092abedfd9684981fa0f5e7d1697dde --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/brcm-sata-phy.txt @@ -0,0 +1,56 @@ +* Broadcom SATA3 PHY + +Required properties: +- compatible: should be one or more of + "brcm,bcm7425-sata-phy" + "brcm,bcm7445-sata-phy" + "brcm,iproc-ns2-sata-phy" + "brcm,iproc-nsp-sata-phy" + "brcm,phy-sata3" + "brcm,iproc-sr-sata-phy" +- address-cells: should be 1 +- size-cells: should be 0 +- reg: register ranges for the PHY PCB interface +- reg-names: should be "phy" and "phy-ctrl" + The "phy-ctrl" registers are only required for + "brcm,iproc-ns2-sata-phy" and "brcm,iproc-sr-sata-phy". + +Sub-nodes: + Each port's PHY should be represented as a sub-node. + +Sub-nodes required properties: +- reg: the PHY number +- phy-cells: generic PHY binding; must be 0 + +Sub-nodes optional properties: +- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port + This property is not applicable for "brcm,iproc-ns2-sata-phy", + "brcm,iproc-nsp-sata-phy" and "brcm,iproc-sr-sata-phy". + +- brcm,rxaeq-mode: string that indicates the desired RX equalizer + mode, possible values are: + "off" (equivalent to not specifying the property) + "auto" + "manual" (brcm,rxaeq-value is used in that case) + +- brcm,rxaeq-value: when 'rxaeq-mode' is set to "manual", provides the RX + equalizer value that should be used. Allowed range is 0..63. + +Example + sata-phy@f0458100 { + compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3"; + reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>; + reg-names = "phy"; + #address-cells = <1>; + #size-cells = <0>; + + sata-phy@0 { + reg = <0>; + #phy-cells = <0>; + }; + + sata-phy@1 { + reg = <1>; + #phy-cells = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/calxeda-combophy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/calxeda-combophy.txt new file mode 100644 index 0000000000000000000000000000000000000000..6622bdb2e8bcd2f78f3293bd6688d0ddc9f31d5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/calxeda-combophy.txt @@ -0,0 +1,17 @@ +Calxeda Highbank Combination Phys for SATA + +Properties: +- compatible : Should be "calxeda,hb-combophy" +- #phy-cells: Should be 1. +- reg : Address and size for Combination Phy registers. +- phydev: device ID for programming the combophy. + +Example: + + combophy5: combo-phy@fff5d000 { + compatible = "calxeda,hb-combophy"; + #phy-cells = <1>; + reg = <0xfff5d000 0x1000>; + phydev = <31>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/dm816x-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/dm816x-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..2fe3d11d063d37f530ccbcea4cabd3d009c7833b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/dm816x-phy.txt @@ -0,0 +1,24 @@ +Device tree binding documentation for am816x USB PHY +========================= + +Required properties: +- compatible : should be "ti,dm816x-usb-phy" +- reg : offset and length of the PHY register set. +- reg-names : name for the phy registers +- clocks : phandle to the clock +- clock-names : name of the clock +- syscon: phandle for the syscon node to access misc registers +- #phy-cells : from the generic PHY bindings, must be 1 +- syscon: phandle for the syscon node to access misc registers + +Example: + +usb_phy0: usb-phy@20 { + compatible = "ti,dm8168-usb-phy"; + reg = <0x20 0x8>; + reg-names = "phy"; + clocks = <&main_fapll 6>; + clock-names = "refclk"; + #phy-cells = <0>; + syscon = <&scm_conf>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/hix5hd2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/hix5hd2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..296168b74d246bd05fbce7702418e46a18e43ea7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/hix5hd2-phy.txt @@ -0,0 +1,22 @@ +Hisilicon hix5hd2 SATA PHY +----------------------- + +Required properties: +- compatible: should be "hisilicon,hix5hd2-sata-phy" +- reg: offset and length of the PHY registers +- #phy-cells: must be 0 +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Optional Properties: +- hisilicon,peripheral-syscon: phandle of syscon used to control peripheral. +- hisilicon,power-reg: offset and bit number within peripheral-syscon, + register of controlling sata power supply. + +Example: + sata_phy: phy@f9900000 { + compatible = "hisilicon,hix5hd2-sata-phy"; + reg = <0xf9900000 0x10000>; + #phy-cells = <0>; + hisilicon,peripheral-syscon = <&peripheral_ctrl>; + hisilicon,power-reg = <0x8 10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/keystone-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/keystone-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..300830dda0bf2f72a5e70308ed7e4ff85c4457c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/keystone-usb-phy.txt @@ -0,0 +1,19 @@ +TI Keystone USB PHY + +Required properties: + - compatible: should be "ti,keystone-usbphy". + - #address-cells, #size-cells : should be '1' if the device has sub-nodes + with 'reg' property. + - reg : Address and length of the usb phy control register set. + +The main purpose of this PHY driver is to enable the USB PHY reference clock +gate on the Keystone SOC for both the USB2 and USB3 PHY. Otherwise it is just +an NOP PHY driver. Hence this node is referenced as both the usb2 and usb3 +phy node in the USB Glue layer driver node. + +usb_phy: usb_phy@2620738 { + compatible = "ti,keystone-usbphy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2620738 32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/meson-gxl-usb2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/meson-gxl-usb2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..b84a02ebffdf0373cd5bfc88d50579966fc7699a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/meson-gxl-usb2-phy.txt @@ -0,0 +1,21 @@ +* Amlogic Meson GXL and GXM USB2 PHY binding + +Required properties: +- compatible: Should be "amlogic,meson-gxl-usb2-phy" +- reg: The base address and length of the registers +- #phys-cells: must be 0 (see phy-bindings.txt in this directory) + +Optional properties: +- clocks: a phandle to the clock of this PHY +- clock-names: must be "phy" +- resets: a phandle to the reset line of this PHY +- reset-names: must be "phy" +- phy-supply: see phy-bindings.txt in this directory + + +Example: + usb2_phy0: phy@78000 { + compatible = "amlogic,meson-gxl-usb2-phy"; + #phy-cells = <0>; + reg = <0x0 0x78000 0x0 0x20>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/meson-gxl-usb3-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/meson-gxl-usb3-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..114947e1de3da3a00b41370080ddac18d93c765d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/meson-gxl-usb3-phy.txt @@ -0,0 +1,31 @@ +* Amlogic Meson GXL and GXM USB3 PHY and OTG detection binding + +Required properties: +- compatible: Should be "amlogic,meson-gxl-usb3-phy" +- #phys-cells: must be 0 (see phy-bindings.txt in this directory) +- reg: The base address and length of the registers +- interrupts: the interrupt specifier for the OTG detection +- clocks: phandles to the clocks for + - the USB3 PHY + - and peripheral mode/OTG detection +- clock-names: must contain "phy" and "peripheral" +- resets: phandle to the reset lines for: + - the USB3 PHY and + - peripheral mode/OTG detection +- reset-names: must contain "phy" and "peripheral" + +Optional properties: +- phy-supply: see phy-bindings.txt in this directory + + +Example: + usb3_phy0: phy@78080 { + compatible = "amlogic,meson-gxl-usb3-phy"; + #phy-cells = <0>; + reg = <0x0 0x78080 0x0 0x20>; + interrupts = ; + clocks = <&clkc CLKID_USB_OTG>, <&clkc_AO CLKID_AO_CEC_32K>; + clock-names = "phy", "peripheral"; + resets = <&reset RESET_USB_OTG>, <&reset RESET_USB_OTG>; + reset-names = "phy", "peripheral"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/meson8b-usb2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/meson8b-usb2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..d81d73aea6082f4b26bd36db9eeff471e59e82bf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/meson8b-usb2-phy.txt @@ -0,0 +1,28 @@ +* Amlogic Meson8, Meson8b and GXBB USB2 PHY + +Required properties: +- compatible: Depending on the platform this should be one of: + "amlogic,meson8-usb2-phy" + "amlogic,meson8b-usb2-phy" + "amlogic,meson-gxbb-usb2-phy" +- reg: The base address and length of the registers +- #phys-cells: should be 0 (see phy-bindings.txt in this directory) +- clocks: phandle and clock identifier for the phy clocks +- clock-names: "usb_general" and "usb" + +Optional properties: +- resets: reference to the reset controller +- phy-supply: see phy-bindings.txt in this directory + + +Example: + +usb0_phy: usb-phy@c0000000 { + compatible = "amlogic,meson-gxbb-usb2-phy"; + #phy-cells = <0>; + reg = <0x0 0xc0000000 0x0 0x20>; + resets = <&reset RESET_USB_OTG>; + clocks = <&clkc CLKID_USB>, <&clkc CLKID_USB0>; + clock-names = "usb_general", "usb"; + phy-supply = <&usb_vbus>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/mxs-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/mxs-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ac98b3b5f57b5a9e8dff47c0d51ce1dd7562ab9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/mxs-usb-phy.txt @@ -0,0 +1,31 @@ +* Freescale MXS USB Phy Device + +Required properties: +- compatible: should contain: + * "fsl,imx23-usbphy" for imx23 and imx28 + * "fsl,imx6q-usbphy" for imx6dq and imx6dl + * "fsl,imx6sl-usbphy" for imx6sl + * "fsl,vf610-usbphy" for Vybrid vf610 + * "fsl,imx6sx-usbphy" for imx6sx + "fsl,imx23-usbphy" is still a fallback for other strings +- reg: Should contain registers location and length +- interrupts: Should contain phy interrupt +- fsl,anatop: phandle for anatop register, it is only for imx6 SoC series + +Optional properties: +- fsl,tx-cal-45-dn-ohms: Integer [30-55]. Resistance (in ohms) of switchable + high-speed trimming resistor connected in parallel with the 45 ohm resistor + that terminates the DN output signal. Default: 45 +- fsl,tx-cal-45-dp-ohms: Integer [30-55]. Resistance (in ohms) of switchable + high-speed trimming resistor connected in parallel with the 45 ohm resistor + that terminates the DP output signal. Default: 45 +- fsl,tx-d-cal: Integer [79-119]. Current trimming value (as a percentage) of + the 17.78mA TX reference current. Default: 100 + +Example: +usbphy1: usbphy@20c9000 { + compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy"; + reg = <0x020c9000 0x1000>; + interrupts = <0 44 0x04>; + fsl,anatop = <&anatop>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/nvidia,tegra124-xusb-padctl.txt b/arch/arm64/boot/dts/vendor/bindings/phy/nvidia,tegra124-xusb-padctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..3742c152c46787a26e9c49f80c623727d239f758 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/nvidia,tegra124-xusb-padctl.txt @@ -0,0 +1,733 @@ +Device tree binding for NVIDIA Tegra XUSB pad controller +======================================================== + +The Tegra XUSB pad controller manages a set of I/O lanes (with differential +signals) which connect directly to pins/pads on the SoC package. Each lane +is controlled by a HW block referred to as a "pad" in the Tegra hardware +documentation. Each such "pad" may control either one or multiple lanes, +and thus contains any logic common to all its lanes. Each lane can be +separately configured and powered up. + +Some of the lanes are high-speed lanes, which can be used for PCIe, SATA or +super-speed USB. Other lanes are for various types of low-speed, full-speed +or high-speed USB (such as UTMI, ULPI and HSIC). The XUSB pad controller +contains a software-configurable mux that sits between the I/O controller +ports (e.g. PCIe) and the lanes. + +In addition to per-lane configuration, USB 3.0 ports may require additional +settings on a per-board basis. + +Pads will be represented as children of the top-level XUSB pad controller +device tree node. Each lane exposed by the pad will be represented by its +own subnode and can be referenced by users of the lane using the standard +PHY bindings, as described by the phy-bindings.txt file in this directory. + +The Tegra hardware documentation refers to the connection between the XUSB +pad controller and the XUSB controller as "ports". This is confusing since +"port" is typically used to denote the physical USB receptacle. The device +tree binding in this document uses the term "port" to refer to the logical +abstraction of the signals that are routed to a USB receptacle (i.e. a PHY +for the USB signal, the VBUS power supply, the USB 2.0 companion port for +USB 3.0 receptacles, ...). + +Required properties: +-------------------- +- compatible: Must be: + - Tegra124: "nvidia,tegra124-xusb-padctl" + - Tegra132: "nvidia,tegra132-xusb-padctl", "nvidia,tegra124-xusb-padctl" + - Tegra210: "nvidia,tegra210-xusb-padctl" +- reg: Physical base address and length of the controller's registers. +- resets: Must contain an entry for each entry in reset-names. +- reset-names: Must include the following entries: + - "padctl" + + +Pad nodes: +========== + +A required child node named "pads" contains a list of subnodes, one for each +of the pads exposed by the XUSB pad controller. Each pad may need additional +resources that can be referenced in its pad node. + +The "status" property is used to enable or disable the use of a pad. If set +to "disabled", the pad will not be used on the given board. In order to use +the pad and any of its lanes, this property must be set to "okay". + +For Tegra124 and Tegra132, the following pads exist: usb2, ulpi, hsic, pcie +and sata. No extra resources are required for operation of these pads. + +For Tegra210, the following pads exist: usb2, hsic, pcie and sata. Below is +a description of the properties of each pad. + +UTMI pad: +--------- + +Required properties: +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Must contain the following entries: + - "trk": phandle and specifier referring to the USB2 tracking clock + +HSIC pad: +--------- + +Required properties: +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Must contain the following entries: + - "trk": phandle and specifier referring to the HSIC tracking clock + +PCIe pad: +--------- + +Required properties: +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Must contain the following entries: + - "pll": phandle and specifier referring to the PLLE +- resets: Must contain an entry for each entry in reset-names. +- reset-names: Must contain the following entries: + - "phy": reset for the PCIe UPHY block + +SATA pad: +--------- + +Required properties: +- resets: Must contain an entry for each entry in reset-names. +- reset-names: Must contain the following entries: + - "phy": reset for the SATA UPHY block + + +PHY nodes: +========== + +Each pad node has a child named "lanes" that contains one or more children of +its own, each representing one of the lanes controlled by the pad. + +Required properties: +-------------------- +- status: Defines the operation status of the PHY. Valid values are: + - "disabled": the PHY is disabled + - "okay": the PHY is enabled +- #phy-cells: Should be 0. Since each lane represents a single PHY, there is + no need for an additional specifier. +- nvidia,function: The output function of the PHY. See below for a list of + valid functions per SoC generation. + +For Tegra124 and Tegra132, the list of valid PHY nodes is given below: +- usb2: usb2-0, usb2-1, usb2-2 + - functions: "snps", "xusb", "uart" +- ulpi: ulpi-0 + - functions: "snps", "xusb" +- hsic: hsic-0, hsic-1 + - functions: "snps", "xusb" +- pcie: pcie-0, pcie-1, pcie-2, pcie-3, pcie-4 + - functions: "pcie", "usb3-ss" +- sata: sata-0 + - functions: "usb3-ss", "sata" + +For Tegra210, the list of valid PHY nodes is given below: +- usb2: usb2-0, usb2-1, usb2-2, usb2-3 + - functions: "snps", "xusb", "uart" +- hsic: hsic-0, hsic-1 + - functions: "snps", "xusb" +- pcie: pcie-0, pcie-1, pcie-2, pcie-3, pcie-4, pcie-5, pcie-6 + - functions: "pcie-x1", "usb3-ss", "pcie-x4" +- sata: sata-0 + - functions: "usb3-ss", "sata" + + +Port nodes: +=========== + +A required child node named "ports" contains a list of all the ports exposed +by the XUSB pad controller. Per-port configuration is only required for USB. + +USB2 ports: +----------- + +Required properties: +- status: Defines the operation status of the port. Valid values are: + - "disabled": the port is disabled + - "okay": the port is enabled +- mode: A string that determines the mode in which to run the port. Valid + values are: + - "host": for USB host mode + - "device": for USB device mode + - "otg": for USB OTG mode + +Optional properties: +- nvidia,internal: A boolean property whose presence determines that a port + is internal. In the absence of this property the port is considered to be + external. +- vbus-supply: phandle to a regulator supplying the VBUS voltage. + +ULPI ports: +----------- + +Optional properties: +- status: Defines the operation status of the port. Valid values are: + - "disabled": the port is disabled + - "okay": the port is enabled +- nvidia,internal: A boolean property whose presence determines that a port + is internal. In the absence of this property the port is considered to be + external. +- vbus-supply: phandle to a regulator supplying the VBUS voltage. + +HSIC ports: +----------- + +Required properties: +- status: Defines the operation status of the port. Valid values are: + - "disabled": the port is disabled + - "okay": the port is enabled + +Optional properties: +- vbus-supply: phandle to a regulator supplying the VBUS voltage. + +Super-speed USB ports: +---------------------- + +Required properties: +- status: Defines the operation status of the port. Valid values are: + - "disabled": the port is disabled + - "okay": the port is enabled +- nvidia,usb2-companion: A single cell that specifies the physical port number + to map this super-speed USB port to. The range of valid port numbers varies + with the SoC generation: + - 0-2: for Tegra124 and Tegra132 + - 0-3: for Tegra210 + +Optional properties: +- nvidia,internal: A boolean property whose presence determines that a port + is internal. In the absence of this property the port is considered to be + external. + +For Tegra124 and Tegra132, the XUSB pad controller exposes the following +ports: +- 3x USB2: usb2-0, usb2-1, usb2-2 +- 1x ULPI: ulpi-0 +- 2x HSIC: hsic-0, hsic-1 +- 2x super-speed USB: usb3-0, usb3-1 + +For Tegra210, the XUSB pad controller exposes the following ports: +- 4x USB2: usb2-0, usb2-1, usb2-2, usb2-3 +- 2x HSIC: hsic-0, hsic-1 +- 4x super-speed USB: usb3-0, usb3-1, usb3-2, usb3-3 + + +Examples: +========= + +Tegra124 and Tegra132: +---------------------- + +SoC include: + + padctl@7009f000 { + /* for Tegra124 */ + compatible = "nvidia,tegra124-xusb-padctl"; + /* for Tegra132 */ + compatible = "nvidia,tegra132-xusb-padctl", + "nvidia,tegra124-xusb-padctl"; + reg = <0x0 0x7009f000 0x0 0x1000>; + resets = <&tegra_car 142>; + reset-names = "padctl"; + + pads { + usb2 { + status = "disabled"; + + lanes { + usb2-0 { + status = "disabled"; + #phy-cells = <0>; + }; + + usb2-1 { + status = "disabled"; + #phy-cells = <0>; + }; + + usb2-2 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + ulpi { + status = "disabled"; + + lanes { + ulpi-0 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + hsic { + status = "disabled"; + + lanes { + hsic-0 { + status = "disabled"; + #phy-cells = <0>; + }; + + hsic-1 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + pcie { + status = "disabled"; + + lanes { + pcie-0 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-1 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-2 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-3 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-4 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + sata { + status = "disabled"; + + lanes { + sata-0 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + }; + + ports { + usb2-0 { + status = "disabled"; + }; + + usb2-1 { + status = "disabled"; + }; + + usb2-2 { + status = "disabled"; + }; + + ulpi-0 { + status = "disabled"; + }; + + hsic-0 { + status = "disabled"; + }; + + hsic-1 { + status = "disabled"; + }; + + usb3-0 { + status = "disabled"; + }; + + usb3-1 { + status = "disabled"; + }; + }; + }; + +Board file: + + padctl@7009f000 { + status = "okay"; + + pads { + usb2 { + status = "okay"; + + lanes { + usb2-0 { + nvidia,function = "xusb"; + status = "okay"; + }; + + usb2-1 { + nvidia,function = "xusb"; + status = "okay"; + }; + + usb2-2 { + nvidia,function = "xusb"; + status = "okay"; + }; + }; + }; + + pcie { + status = "okay"; + + lanes { + pcie-0 { + nvidia,function = "usb3-ss"; + status = "okay"; + }; + + pcie-2 { + nvidia,function = "pcie"; + status = "okay"; + }; + + pcie-4 { + nvidia,function = "pcie"; + status = "okay"; + }; + }; + }; + + sata { + status = "okay"; + + lanes { + sata-0 { + nvidia,function = "sata"; + status = "okay"; + }; + }; + }; + }; + + ports { + /* Micro A/B */ + usb2-0 { + status = "okay"; + mode = "otg"; + }; + + /* Mini PCIe */ + usb2-1 { + status = "okay"; + mode = "host"; + }; + + /* USB3 */ + usb2-2 { + status = "okay"; + mode = "host"; + + vbus-supply = <&vdd_usb3_vbus>; + }; + + usb3-0 { + nvidia,port = <2>; + status = "okay"; + }; + }; + }; + +Tegra210: +--------- + +SoC include: + + padctl@7009f000 { + compatible = "nvidia,tegra210-xusb-padctl"; + reg = <0x0 0x7009f000 0x0 0x1000>; + resets = <&tegra_car 142>; + reset-names = "padctl"; + + status = "disabled"; + + pads { + usb2 { + clocks = <&tegra_car TEGRA210_CLK_USB2_TRK>; + clock-names = "trk"; + status = "disabled"; + + lanes { + usb2-0 { + status = "disabled"; + #phy-cells = <0>; + }; + + usb2-1 { + status = "disabled"; + #phy-cells = <0>; + }; + + usb2-2 { + status = "disabled"; + #phy-cells = <0>; + }; + + usb2-3 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + hsic { + clocks = <&tegra_car TEGRA210_CLK_HSIC_TRK>; + clock-names = "trk"; + status = "disabled"; + + lanes { + hsic-0 { + status = "disabled"; + #phy-cells = <0>; + }; + + hsic-1 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + pcie { + clocks = <&tegra_car TEGRA210_CLK_PLL_E>; + clock-names = "pll"; + resets = <&tegra_car 205>; + reset-names = "phy"; + status = "disabled"; + + lanes { + pcie-0 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-1 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-2 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-3 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-4 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-5 { + status = "disabled"; + #phy-cells = <0>; + }; + + pcie-6 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + + sata { + clocks = <&tegra_car TEGRA210_CLK_PLL_E>; + clock-names = "pll"; + resets = <&tegra_car 204>; + reset-names = "phy"; + status = "disabled"; + + lanes { + sata-0 { + status = "disabled"; + #phy-cells = <0>; + }; + }; + }; + }; + + ports { + usb2-0 { + status = "disabled"; + }; + + usb2-1 { + status = "disabled"; + }; + + usb2-2 { + status = "disabled"; + }; + + usb2-3 { + status = "disabled"; + }; + + hsic-0 { + status = "disabled"; + }; + + hsic-1 { + status = "disabled"; + }; + + usb3-0 { + status = "disabled"; + }; + + usb3-1 { + status = "disabled"; + }; + + usb3-2 { + status = "disabled"; + }; + + usb3-3 { + status = "disabled"; + }; + }; + }; + +Board file: + + padctl@7009f000 { + status = "okay"; + + pads { + usb2 { + status = "okay"; + + lanes { + usb2-0 { + nvidia,function = "xusb"; + status = "okay"; + }; + + usb2-1 { + nvidia,function = "xusb"; + status = "okay"; + }; + + usb2-2 { + nvidia,function = "xusb"; + status = "okay"; + }; + + usb2-3 { + nvidia,function = "xusb"; + status = "okay"; + }; + }; + }; + + pcie { + status = "okay"; + + lanes { + pcie-0 { + nvidia,function = "pcie-x1"; + status = "okay"; + }; + + pcie-1 { + nvidia,function = "pcie-x4"; + status = "okay"; + }; + + pcie-2 { + nvidia,function = "pcie-x4"; + status = "okay"; + }; + + pcie-3 { + nvidia,function = "pcie-x4"; + status = "okay"; + }; + + pcie-4 { + nvidia,function = "pcie-x4"; + status = "okay"; + }; + + pcie-5 { + nvidia,function = "usb3-ss"; + status = "okay"; + }; + + pcie-6 { + nvidia,function = "usb3-ss"; + status = "okay"; + }; + }; + }; + + sata { + status = "okay"; + + lanes { + sata-0 { + nvidia,function = "sata"; + status = "okay"; + }; + }; + }; + }; + + ports { + usb2-0 { + status = "okay"; + mode = "otg"; + }; + + usb2-1 { + status = "okay"; + vbus-supply = <&vdd_5v0_rtl>; + mode = "host"; + }; + + usb2-2 { + status = "okay"; + vbus-supply = <&vdd_usb_vbus>; + mode = "host"; + }; + + usb2-3 { + status = "okay"; + mode = "host"; + }; + + usb3-0 { + status = "okay"; + nvidia,lanes = "pcie-6"; + nvidia,port = <1>; + }; + + usb3-1 { + status = "okay"; + nvidia,lanes = "pcie-5"; + nvidia,port = <2>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/nvidia,tegra20-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/nvidia,tegra20-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..1aa6f2674af52d1430f706661a4ce5ad1b670c68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/nvidia,tegra20-usb-phy.txt @@ -0,0 +1,74 @@ +Tegra SOC USB PHY + +The device node for Tegra SOC USB PHY: + +Required properties : + - compatible : For Tegra20, must contain "nvidia,tegra20-usb-phy". + For Tegra30, must contain "nvidia,tegra30-usb-phy". Otherwise, must contain + "nvidia,-usb-phy" plus at least one of the above, where is + tegra114, tegra124, tegra132, or tegra210. + - reg : Defines the following set of registers, in the order listed: + - The PHY's own register set. + Always present. + - The register set of the PHY containing the UTMI pad control registers. + Present if-and-only-if phy_type == utmi. + - phy_type : Should be one of "utmi", "ulpi" or "hsic". + - clocks : Defines the clocks listed in the clock-names property. + - clock-names : The following clock names must be present: + - reg: The clock needed to access the PHY's own registers. This is the + associated EHCI controller's clock. Always present. + - pll_u: PLL_U. Always present. + - timer: The timeout clock (clk_m). Present if phy_type == utmi. + - utmi-pads: The clock needed to access the UTMI pad control registers. + Present if phy_type == utmi. + - ulpi-link: The clock Tegra provides to the ULPI PHY (usually pad DAP_MCLK2 + with pad group aka "nvidia,pins" cdev2 and pin mux option config aka + "nvidia,function" pllp_out4). + Present if phy_type == ulpi, and ULPI link mode is in use. + - resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names : Must include the following entries: + - usb: The PHY's own reset signal. + - utmi-pads: The reset of the PHY containing the chip-wide UTMI pad control + registers. Required even if phy_type == ulpi. + +Required properties for phy_type == ulpi: + - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. + +Required PHY timing params for utmi phy, for all chips: + - nvidia,hssync-start-delay : Number of 480 Mhz clock cycles to wait before + start of sync launches RxActive + - nvidia,elastic-limit : Variable FIFO Depth of elastic input store + - nvidia,idle-wait-delay : Number of 480 Mhz clock cycles of idle to wait + before declare IDLE. + - nvidia,term-range-adj : Range adjusment on terminations + - Either one of the following for HS driver output control: + - nvidia,xcvr-setup : integer, uses the provided value. + - nvidia,xcvr-setup-use-fuses : boolean, indicates that the value is read + from the on-chip fuses + If both are provided, nvidia,xcvr-setup-use-fuses takes precedence. + - nvidia,xcvr-lsfslew : LS falling slew rate control. + - nvidia,xcvr-lsrslew : LS rising slew rate control. + +Required PHY timing params for utmi phy, only on Tegra30 and above: + - nvidia,xcvr-hsslew : HS slew rate control. + - nvidia,hssquelch-level : HS squelch detector level. + - nvidia,hsdiscon-level : HS disconnect detector level. + +Optional properties: + - nvidia,has-legacy-mode : boolean indicates whether this controller can + operate in legacy mode (as APX 2500 / 2600). In legacy mode some + registers are accessed through the APB_MISC base address instead of + the USB controller. + - nvidia,is-wired : boolean. Indicates whether we can do certain kind of power + optimizations for the devices that are always connected. e.g. modem. + - dr_mode : dual role mode. Indicates the working mode for the PHY. Can be + "host", "peripheral", or "otg". Defaults to "host" if not defined. + host means this is a host controller + peripheral means it is device controller + otg means it can operate as either ("on the go") + - nvidia,has-utmi-pad-registers : boolean indicates whether this controller + contains the UTMI pad control registers common to all USB controllers. + +VBUS control (required for dr_mode == otg, optional for dr_mode == host): + - vbus-supply: regulator for VBUS diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-ath79-usb.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-ath79-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3a29c5feea3792a23922ff55ab1260bf7cda172 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-ath79-usb.txt @@ -0,0 +1,18 @@ +* Atheros AR71XX/9XXX USB PHY + +Required properties: +- compatible: "qca,ar7100-usb-phy" +- #phys-cells: should be 0 +- reset-names: "phy"[, "suspend-override"] +- resets: references to the reset controllers + +Example: + + usb-phy { + compatible = "qca,ar7100-usb-phy"; + + reset-names = "phy", "suspend-override"; + resets = <&rst 4>, <&rst 3>; + + #phy-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-bindings.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-bindings.txt new file mode 100644 index 0000000000000000000000000000000000000000..a403b81d0679622d0b473edf545898618fc66836 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-bindings.txt @@ -0,0 +1,72 @@ +This document explains only the device tree data binding. For general +information about PHY subsystem refer to Documentation/phy.txt + +PHY device node +=============== + +Required Properties: +#phy-cells: Number of cells in a PHY specifier; The meaning of all those + cells is defined by the binding for the phy node. The PHY + provider can use the values in cells to find the appropriate + PHY. + +Optional Properties: +phy-supply: Phandle to a regulator that provides power to the PHY. This + regulator will be managed during the PHY power on/off sequence. + +For example: + +phys: phy { + compatible = "xxx"; + reg = <...>; + . + . + #phy-cells = <1>; + . + . +}; + +That node describes an IP block (PHY provider) that implements 2 different PHYs. +In order to differentiate between these 2 PHYs, an additional specifier should be +given while trying to get a reference to it. + +PHY user node +============= + +Required Properties: +phys : the phandle for the PHY device (used by the PHY subsystem; not to be + confused with the Ethernet specific 'phy' and 'phy-handle' properties, + see Documentation/devicetree/bindings/net/ethernet.txt for these) +phy-names : the names of the PHY corresponding to the PHYs present in the + *phys* phandle + +Example 1: +usb1: usb_otg_ss@xxx { + compatible = "xxx"; + reg = ; + . + . + phys = <&usb2_phy>, <&usb3_phy>; + phy-names = "usb2phy", "usb3phy"; + . + . +}; + +This node represents a controller that uses two PHYs, one for usb2 and one for +usb3. + +Example 2: +usb2: usb_otg_ss@xxx { + compatible = "xxx"; + reg = ; + . + . + phys = <&phys 1>; + phy-names = "usbphy"; + . + . +}; + +This node represents a controller that uses one of the PHYs of the PHY provider +device defined previously. Note that the phy handle has an additional specifier +"1" to differentiate between the two PHYs. diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-cpcap-usb.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-cpcap-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..2eb9b2b69037f75f07256ae7a17df9ac2272f28a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-cpcap-usb.txt @@ -0,0 +1,40 @@ +Motorola CPCAP PMIC USB PHY binding + +Required properties: +compatible: Shall be either "motorola,cpcap-usb-phy" or + "motorola,mapphone-cpcap-usb-phy" +#phy-cells: Shall be 0 +interrupts: CPCAP PMIC interrupts used by the USB PHY +interrupt-names: Interrupt names +io-channels: IIO ADC channels used by the USB PHY +io-channel-names: IIO ADC channel names +vusb-supply: Regulator for the PHY + +Optional properties: +pinctrl: Optional alternate pin modes for the PHY +pinctrl-names: Names for optional pin modes +mode-gpios: Optional GPIOs for configuring alternate modes + +Example: +cpcap_usb2_phy: phy { + compatible = "motorola,mapphone-cpcap-usb-phy"; + pinctrl-0 = <&usb_gpio_mux_sel1 &usb_gpio_mux_sel2>; + pinctrl-1 = <&usb_ulpi_pins>; + pinctrl-2 = <&usb_utmi_pins>; + pinctrl-3 = <&uart3_pins>; + pinctrl-names = "default", "ulpi", "utmi", "uart"; + #phy-cells = <0>; + interrupts-extended = < + &cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0 + &cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0 + &cpcap 48 1 + >; + interrupt-names = + "id_ground", "id_float", "se0conn", "vbusvld", + "sessvld", "sessend", "se1", "dm", "dp"; + mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH + &gpio1 0 GPIO_ACTIVE_HIGH>; + io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>; + io-channel-names = "vbus", "id"; + vusb-supply = <&vusb>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-da8xx-usb.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-da8xx-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..c26478be391b43030d2a2f28251d427b2455aac6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-da8xx-usb.txt @@ -0,0 +1,40 @@ +TI DA8xx/OMAP-L1xx/AM18xx USB PHY + +Required properties: + - compatible: must be "ti,da830-usb-phy". + - #phy-cells: must be 1. + +This device controls the PHY for both the USB 1.1 OHCI and USB 2.0 OTG +controllers on DA8xx SoCs. Consumers of this device should use index 0 for +the USB 2.0 phy device and index 1 for the USB 1.1 phy device. + +It also requires a "syscon" node with compatible = "ti,da830-cfgchip", "syscon" +to access the CFGCHIP2 register. + +Example: + + cfgchip: cfgchip@1417c { + compatible = "ti,da830-cfgchip", "syscon"; + reg = <0x1417c 0x14>; + }; + + usb_phy: usb-phy { + compatible = "ti,da830-usb-phy"; + #phy-cells = <1>; + }; + + usb20: usb@200000 { + compatible = "ti,da830-musb"; + reg = <0x200000 0x1000>; + interrupts = <58>; + phys = <&usb_phy 0>; + phy-names = "usb-phy"; + }; + + usb11: usb@225000 { + compatible = "ti,da830-ohci"; + reg = <0x225000 0x1000>; + interrupts = <59>; + phys = <&usb_phy 1>; + phy-names = "usb-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-hi3798cv200-combphy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-hi3798cv200-combphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..17b0c761370a4a607d43388786f1d28625f0bce6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-hi3798cv200-combphy.txt @@ -0,0 +1,59 @@ +HiSilicon STB PCIE/SATA/USB3 PHY + +Required properties: +- compatible: Should be "hisilicon,hi3798cv200-combphy" +- reg: Should be the address space for COMBPHY configuration and state + registers in peripheral controller, e.g. PERI_COMBPHY0_CFG and + PERI_COMBPHY0_STATE for COMBPHY0 Hi3798CV200 SoC. +- #phy-cells: Should be 1. The cell number is used to select the phy mode + as defined in . +- clocks: The phandle to clock provider and clock specifier pair. +- resets: The phandle to reset controller and reset specifier pair. + +Refer to phy/phy-bindings.txt for the generic PHY binding properties. + +Optional properties: +- hisilicon,fixed-mode: If the phy device doesn't support mode select + but a fixed mode setting, the property should be present to specify + the particular mode. +- hisilicon,mode-select-bits: If the phy device support mode select, + this property should be present to specify the register bits in + peripheral controller, as a 3 integers tuple: + . + +Notes: +- Between hisilicon,fixed-mode and hisilicon,mode-select-bits, one and only + one of them should be present. +- The device node should be a child of peripheral controller that contains + COMBPHY configuration/state and PERI_CTRL register used to select PHY mode. + Refer to arm/hisilicon/hisilicon.txt for the parent peripheral controller + bindings. + +Examples: + +perictrl: peripheral-controller@8a20000 { + compatible = "hisilicon,hi3798cv200-perictrl", "syscon", + "simple-mfd"; + reg = <0x8a20000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x8a20000 0x1000>; + + combphy0: phy@850 { + compatible = "hisilicon,hi3798cv200-combphy"; + reg = <0x850 0x8>; + #phy-cells = <1>; + clocks = <&crg HISTB_COMBPHY0_CLK>; + resets = <&crg 0x188 4>; + hisilicon,fixed-mode = ; + }; + + combphy1: phy@858 { + compatible = "hisilicon,hi3798cv200-combphy"; + reg = <0x858 0x8>; + #phy-cells = <1>; + clocks = <&crg HISTB_COMBPHY1_CLK>; + resets = <&crg 0x188 12>; + hisilicon,mode-select-bits = <0x0008 11 (0x3 << 11)>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-hi6220-usb.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-hi6220-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..f17a56e2152f0442c320bec6130b05d9f84c48dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-hi6220-usb.txt @@ -0,0 +1,16 @@ +Hisilicon hi6220 usb PHY +----------------------- + +Required properties: +- compatible: should be "hisilicon,hi6220-usb-phy" +- #phy-cells: must be 0 +- hisilicon,peripheral-syscon: phandle of syscon used to control phy. +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Example: + usb_phy: usbphy { + compatible = "hisilicon,hi6220-usb-phy"; + #phy-cells = <0>; + phy-supply = <&fixed_5v_hub>; + hisilicon,peripheral-syscon = <&sys_ctrl>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-hisi-inno-usb2.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-hisi-inno-usb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d70c8341095dbb3f464cca6eebaebd77807a189 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-hisi-inno-usb2.txt @@ -0,0 +1,71 @@ +Device tree bindings for HiSilicon INNO USB2 PHY + +Required properties: +- compatible: Should be one of the following strings: + "hisilicon,inno-usb2-phy", + "hisilicon,hi3798cv200-usb2-phy". +- reg: Should be the address space for PHY configuration register in peripheral + controller, e.g. PERI_USB0 for USB 2.0 PHY01 on Hi3798CV200 SoC. +- clocks: The phandle and clock specifier pair for INNO USB2 PHY device + reference clock. +- resets: The phandle and reset specifier pair for INNO USB2 PHY device reset + signal. +- #address-cells: Must be 1. +- #size-cells: Must be 0. + +The INNO USB2 PHY device should be a child node of peripheral controller that +contains the PHY configuration register, and each device suppports up to 2 PHY +ports which are represented as child nodes of INNO USB2 PHY device. + +Required properties for PHY port node: +- reg: The PHY port instance number. +- #phy-cells: Defined by generic PHY bindings. Must be 0. +- resets: The phandle and reset specifier pair for PHY port reset signal. + +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Example: + +perictrl: peripheral-controller@8a20000 { + compatible = "hisilicon,hi3798cv200-perictrl", "simple-mfd"; + reg = <0x8a20000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x8a20000 0x1000>; + + usb2_phy1: usb2-phy@120 { + compatible = "hisilicon,hi3798cv200-usb2-phy"; + reg = <0x120 0x4>; + clocks = <&crg HISTB_USB2_PHY1_REF_CLK>; + resets = <&crg 0xbc 4>; + #address-cells = <1>; + #size-cells = <0>; + + usb2_phy1_port0: phy@0 { + reg = <0>; + #phy-cells = <0>; + resets = <&crg 0xbc 8>; + }; + + usb2_phy1_port1: phy@1 { + reg = <1>; + #phy-cells = <0>; + resets = <&crg 0xbc 9>; + }; + }; + + usb2_phy2: usb2-phy@124 { + compatible = "hisilicon,hi3798cv200-usb2-phy"; + reg = <0x124 0x4>; + clocks = <&crg HISTB_USB2_PHY2_REF_CLK>; + resets = <&crg 0xbc 6>; + #address-cells = <1>; + #size-cells = <0>; + + usb2_phy2_port0: phy@0 { + reg = <0>; + #phy-cells = <0>; + resets = <&crg 0xbc 10>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-lantiq-rcu-usb2.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-lantiq-rcu-usb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..643948b6b576515ac83d4c39e0ff24087947e61b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-lantiq-rcu-usb2.txt @@ -0,0 +1,40 @@ +Lantiq XWAY SoC RCU USB 1.1/2.0 PHY binding +=========================================== + +This binding describes the USB PHY hardware provided by the RCU module on the +Lantiq XWAY SoCs. + +This node has to be a sub node of the Lantiq RCU block. + +------------------------------------------------------------------------------- +Required properties (controller (parent) node): +- compatible : Should be one of + "lantiq,ase-usb2-phy" + "lantiq,danube-usb2-phy" + "lantiq,xrx100-usb2-phy" + "lantiq,xrx200-usb2-phy" + "lantiq,xrx300-usb2-phy" +- reg : Defines the following sets of registers in the parent + syscon device + - Offset of the USB PHY configuration register + - Offset of the USB Analog configuration + register (only for xrx200 and xrx200) +- clocks : References to the (PMU) "phy" clk gate. +- clock-names : Must be "phy" +- resets : References to the RCU USB configuration reset bits. +- reset-names : Must be one of the following: + "phy" (optional) + "ctrl" (shared) + +------------------------------------------------------------------------------- +Example for the USB PHYs on an xRX200 SoC: + usb_phy0: usb2-phy@18 { + compatible = "lantiq,xrx200-usb2-phy"; + reg = <0x18 4>, <0x38 4>; + + clocks = <&pmu PMU_GATE_USB0_PHY>; + clock-names = "phy"; + resets = <&reset1 4 4>, <&reset0 4 4>; + reset-names = "phy", "ctrl"; + #phy-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-lpc18xx-usb-otg.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-lpc18xx-usb-otg.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bb821cd6a7f3fa247655b1e3bc377abf580d28f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-lpc18xx-usb-otg.txt @@ -0,0 +1,26 @@ +NXP LPC18xx/43xx internal USB OTG PHY binding +--------------------------------------------- + +This file contains documentation for the internal USB OTG PHY found +in NXP LPC18xx and LPC43xx SoCs. + +Required properties: +- compatible : must be "nxp,lpc1850-usb-otg-phy" +- clocks : must be exactly one entry +See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- #phy-cells : must be 0 for this phy +See: Documentation/devicetree/bindings/phy/phy-bindings.txt + +The phy node must be a child of the creg syscon node. + +Example: +creg: syscon@40043000 { + compatible = "nxp,lpc1850-creg", "syscon", "simple-mfd"; + reg = <0x40043000 0x1000>; + + usb0_otg_phy: phy { + compatible = "nxp,lpc1850-usb-otg-phy"; + clocks = <&ccu1 CLK_USB0>; + #phy-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-mapphone-mdm6600.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mapphone-mdm6600.txt new file mode 100644 index 0000000000000000000000000000000000000000..29427d4f047a15891e345ad31465dc141f92af0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mapphone-mdm6600.txt @@ -0,0 +1,29 @@ +Device tree binding documentation for Motorola Mapphone MDM6600 USB PHY + +Required properties: +- compatible Must be "motorola,mapphone-mdm6600" +- enable-gpios GPIO to enable the USB PHY +- power-gpios GPIO to power on the device +- reset-gpios GPIO to reset the device +- motorola,mode-gpios Two GPIOs to configure MDM6600 USB start-up mode for + normal mode versus USB flashing mode +- motorola,cmd-gpios Three GPIOs to control the power state of the MDM6600 +- motorola,status-gpios Three GPIOs to read the power state of the MDM6600 + +Example: + +usb-phy { + compatible = "motorola,mapphone-mdm6600"; + enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; + power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>; + motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>, + <&gpio5 21 GPIO_ACTIVE_HIGH>; + motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>, + <&gpio4 8 GPIO_ACTIVE_HIGH>, + <&gpio5 14 GPIO_ACTIVE_HIGH>; + motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>, + <&gpio2 21 GPIO_ACTIVE_HIGH>, + <&gpio2 23 GPIO_ACTIVE_HIGH>; + #phy-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-miphy28lp.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-miphy28lp.txt new file mode 100644 index 0000000000000000000000000000000000000000..89caa885d08cd56d49c243fc0cd20289b4d6f07e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-miphy28lp.txt @@ -0,0 +1,117 @@ +STMicroelectronics STi MIPHY28LP PHY binding +============================================ + +This binding describes a miphy device that is used to control PHY hardware +for SATA, PCIe or USB3. + +Required properties (controller (parent) node): +- compatible : Should be "st,miphy28lp-phy". +- st,syscfg : Should be a phandle of the system configuration register group + which contain the SATA, PCIe or USB3 mode setting bits. + +Required nodes : A sub-node is required for each channel the controller + provides. Address range information including the usual + 'reg' and 'reg-names' properties are used inside these + nodes to describe the controller's topology. These nodes + are translated by the driver's .xlate() function. + +Required properties (port (child) node): +- #phy-cells : Should be 1 (See second example) + Cell after port phandle is device type from: + - PHY_TYPE_SATA + - PHY_TYPE_PCI + - PHY_TYPE_USB3 +- reg : Address and length of the register set for the device. +- reg-names : The names of the register addresses corresponding to the registers + filled in "reg". It can also contain the offset of the system configuration + registers used as glue-logic to setup the device for SATA/PCIe or USB3 + devices. +- st,syscfg : Offset of the parent configuration register. +- resets : phandle to the parent reset controller. +- reset-names : Associated name must be "miphy-sw-rst". + +Optional properties (port (child) node): +- st,osc-rdy : to check the MIPHY0_OSC_RDY status in the glue-logic. This + is not available in all the MiPHY. For example, for STiH407, only the + MiPHY0 has this bit. +- st,osc-force-ext : to select the external oscillator. This can change from + different MiPHY inside the same SoC. +- st,sata_gen : to select which SATA_SPDMODE has to be set in the SATA system config + register. +- st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive + line). +- st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe). +- st,tx-impedance-comp : to compensate tx impedance avoiding out of range values. + +example: + + miphy28lp_phy: miphy28lp@9b22000 { + compatible = "st,miphy28lp-phy"; + st,syscfg = <&syscfg_core>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + phy_port0: port@9b22000 { + reg = <0x9b22000 0xff>, + <0x9b09000 0xff>, + <0x9b04000 0xff>; + reg-names = "sata-up", + "pcie-up", + "pipew"; + + st,syscfg = <0x114 0x818 0xe0 0xec>; + #phy-cells = <1>; + st,osc-rdy; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY0_SOFTRESET>; + }; + + phy_port1: port@9b2a000 { + reg = <0x9b2a000 0xff>, + <0x9b19000 0xff>, + <0x9b14000 0xff>; + reg-names = "sata-up", + "pcie-up", + "pipew"; + + st,syscfg = <0x118 0x81c 0xe4 0xf0>; + + #phy-cells = <1>; + st,osc-force-ext; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY1_SOFTRESET>; + }; + + phy_port2: port@8f95000 { + reg = <0x8f95000 0xff>, + <0x8f90000 0xff>; + reg-names = "pipew", + "usb3-up"; + + st,syscfg = <0x11c 0x820>; + + #phy-cells = <1>; + reset-names = "miphy-sw-rst"; + resets = <&softreset STIH407_MIPHY2_SOFTRESET>; + }; + }; + + +Specifying phy control of devices +================================= + +Device nodes should specify the configuration required in their "phys" +property, containing a phandle to the miphy device node and an index +specifying which configuration to use, as described in phy-bindings.txt. + +example: + sata0: sata@9b20000 { + ... + phys = <&phy_port0 PHY_TYPE_SATA>; + ... + }; + +Macro definitions for the supported miphy configuration can be found in: + +include/dt-bindings/phy/phy.h diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-miphy365x.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-miphy365x.txt new file mode 100644 index 0000000000000000000000000000000000000000..8772900e056a06cd71579a2e6cf005993e38a472 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-miphy365x.txt @@ -0,0 +1,77 @@ +STMicroelectronics STi MIPHY365x PHY binding +============================================ + +This binding describes a miphy device that is used to control PHY hardware +for SATA and PCIe. + +Required properties (controller (parent) node): +- compatible : Should be "st,miphy365x-phy" +- st,syscfg : Phandle / integer array property. Phandle of sysconfig group + containing the miphy registers and integer array should contain + an entry for each port sub-node, specifying the control + register offset inside the sysconfig group. + +Required nodes : A sub-node is required for each channel the controller + provides. Address range information including the usual + 'reg' and 'reg-names' properties are used inside these + nodes to describe the controller's topology. These nodes + are translated by the driver's .xlate() function. + +Required properties (port (child) node): +- #phy-cells : Should be 1 (See second example) + Cell after port phandle is device type from: + - PHY_TYPE_SATA + - PHY_TYPE_PCI +- reg : Address and length of register sets for each device in + "reg-names" +- reg-names : The names of the register addresses corresponding to the + registers filled in "reg": + - sata: For SATA devices + - pcie: For PCIe devices + +Optional properties (port (child) node): +- st,sata-gen : Generation of locally attached SATA IP. Expected values + are {1,2,3). If not supplied generation 1 hardware will + be expected +- st,pcie-tx-pol-inv : Bool property to invert the polarity PCIe Tx (Txn/Txp) +- st,sata-tx-pol-inv : Bool property to invert the polarity SATA Tx (Txn/Txp) + +Example: + + miphy365x_phy: miphy365x@fe382000 { + compatible = "st,miphy365x-phy"; + st,syscfg = <&syscfg_rear 0x824 0x828>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + phy_port0: port@fe382000 { + reg = <0xfe382000 0x100>, <0xfe394000 0x100>; + reg-names = "sata", "pcie"; + #phy-cells = <1>; + st,sata-gen = <3>; + }; + + phy_port1: port@fe38a000 { + reg = <0xfe38a000 0x100>, <0xfe804000 0x100>;; + reg-names = "sata", "pcie", "syscfg"; + #phy-cells = <1>; + st,pcie-tx-pol-inv; + }; + }; + +Specifying phy control of devices +================================= + +Device nodes should specify the configuration required in their "phys" +property, containing a phandle to the phy port node and a device type. + +Example: + +#include + + sata0: sata@fe380000 { + ... + phys = <&phy_port0 PHY_TYPE_SATA>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-mtk-tphy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mtk-tphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5f7a4f0dbc1a8609270b32b761a447183222a57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mtk-tphy.txt @@ -0,0 +1,150 @@ +MediaTek T-PHY binding +-------------------------- + +T-phy controller supports physical layer functionality for a number of +controllers on MediaTek SoCs, such as, USB2.0, USB3.0, PCIe, and SATA. + +Required properties (controller (parent) node): + - compatible : should be one of + "mediatek,generic-tphy-v1" + "mediatek,generic-tphy-v2" + "mediatek,mt2701-u3phy" (deprecated) + "mediatek,mt2712-u3phy" (deprecated) + "mediatek,mt8173-u3phy"; + make use of "mediatek,generic-tphy-v1" on mt2701 instead and + "mediatek,generic-tphy-v2" on mt2712 instead. + - clocks : (deprecated, use port's clocks instead) a list of phandle + + clock-specifier pairs, one for each entry in clock-names + - clock-names : (deprecated, use port's one instead) must contain + "u3phya_ref": for reference clock of usb3.0 analog phy. + +Required nodes : a sub-node is required for each port the controller + provides. Address range information including the usual + 'reg' property is used inside these nodes to describe + the controller's topology. + +Optional properties (controller (parent) node): + - reg : offset and length of register shared by multiple ports, + exclude port's private register. It is needed on mt2701 + and mt8173, but not on mt2712. + - mediatek,src-ref-clk-mhz : frequency of reference clock for slew rate + calibrate + - mediatek,src-coef : coefficient for slew rate calibrate, depends on + SoC process + +Required properties (port (child) node): +- reg : address and length of the register set for the port. +- clocks : a list of phandle + clock-specifier pairs, one for each + entry in clock-names +- clock-names : must contain + "ref": 48M reference clock for HighSpeed analog phy; and 26M + reference clock for SuperSpeed analog phy, sometimes is + 24M, 25M or 27M, depended on platform. +- #phy-cells : should be 1 (See second example) + cell after port phandle is phy type from: + - PHY_TYPE_USB2 + - PHY_TYPE_USB3 + - PHY_TYPE_PCIE + - PHY_TYPE_SATA + +Optional properties (PHY_TYPE_USB2 port (child) node): +- mediatek,eye-src : u32, the value of slew rate calibrate +- mediatek,eye-vrt : u32, the selection of VRT reference voltage +- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage +- mediatek,bc12 : bool, enable BC12 of u2phy if support it + +Example: + +u3phy: usb-phy@11290000 { + compatible = "mediatek,mt8173-u3phy"; + reg = <0 0x11290000 0 0x800>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + u2port0: usb-phy@11290800 { + reg = <0 0x11290800 0 0x100>; + clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + u3port0: usb-phy@11290900 { + reg = <0 0x11290800 0 0x700>; + clocks = <&clk26m>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + u2port1: usb-phy@11291000 { + reg = <0 0x11291000 0 0x100>; + clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>; + clock-names = "ref"; + #phy-cells = <1>; + }; +}; + +Specifying phy control of devices +--------------------------------- + +Device nodes should specify the configuration required in their "phys" +property, containing a phandle to the phy port node and a device type; +phy-names for each port are optional. + +Example: + +#include + +usb30: usb@11270000 { + ... + phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>; + phy-names = "usb2-0", "usb3-0"; + ... +}; + + +Layout differences of banks between mt8173/mt2701 and mt2712 +------------------------------------------------------------- +mt8173 and mt2701: +port offset bank +shared 0x0000 SPLLC + 0x0100 FMREG +u2 port0 0x0800 U2PHY_COM +u3 port0 0x0900 U3PHYD + 0x0a00 U3PHYD_BANK2 + 0x0b00 U3PHYA + 0x0c00 U3PHYA_DA +u2 port1 0x1000 U2PHY_COM +u3 port1 0x1100 U3PHYD + 0x1200 U3PHYD_BANK2 + 0x1300 U3PHYA + 0x1400 U3PHYA_DA +u2 port2 0x1800 U2PHY_COM + ... + +mt2712: +port offset bank +u2 port0 0x0000 MISC + 0x0100 FMREG + 0x0300 U2PHY_COM +u3 port0 0x0700 SPLLC + 0x0800 CHIP + 0x0900 U3PHYD + 0x0a00 U3PHYD_BANK2 + 0x0b00 U3PHYA + 0x0c00 U3PHYA_DA +u2 port1 0x1000 MISC + 0x1100 FMREG + 0x1300 U2PHY_COM +u3 port1 0x1700 SPLLC + 0x1800 CHIP + 0x1900 U3PHYD + 0x1a00 U3PHYD_BANK2 + 0x1b00 U3PHYA + 0x1c00 U3PHYA_DA +u2 port2 0x2000 MISC + ... + + SPLLC shared by u3 ports and FMREG shared by u2 ports on +mt8173/mt2701 are put back into each port; a new bank MISC for +u2 ports and CHIP for u3 ports are added on mt2712. diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-mtk-xsphy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mtk-xsphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7caefa0b9c2687475e1458098c3ebb6dbbf66bf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mtk-xsphy.txt @@ -0,0 +1,109 @@ +MediaTek XS-PHY binding +-------------------------- + +The XS-PHY controller supports physical layer functionality for USB3.1 +GEN2 controller on MediaTek SoCs. + +Required properties (controller (parent) node): + - compatible : should be "mediatek,-xsphy", "mediatek,xsphy", + soc-model is the name of SoC, such as mt3611 etc; + when using "mediatek,xsphy" compatible string, you need SoC specific + ones in addition, one of: + - "mediatek,mt3611-xsphy" + + - #address-cells, #size-cells : should use the same values as the root node + - ranges: must be present + +Optional properties (controller (parent) node): + - reg : offset and length of register shared by multiple U3 ports, + exclude port's private register, if only U2 ports provided, + shouldn't use the property. + - mediatek,src-ref-clk-mhz : u32, frequency of reference clock for slew rate + calibrate + - mediatek,src-coef : u32, coefficient for slew rate calibrate, depends on + SoC process + +Required nodes : a sub-node is required for each port the controller + provides. Address range information including the usual + 'reg' property is used inside these nodes to describe + the controller's topology. + +Required properties (port (child) node): +- reg : address and length of the register set for the port. +- clocks : a list of phandle + clock-specifier pairs, one for each + entry in clock-names +- clock-names : must contain + "ref": 48M reference clock for HighSpeed analog phy; and 26M + reference clock for SuperSpeedPlus analog phy, sometimes is + 24M, 25M or 27M, depended on platform. +- #phy-cells : should be 1 + cell after port phandle is phy type from: + - PHY_TYPE_USB2 + - PHY_TYPE_USB3 + +The following optional properties are only for debug or HQA test +Optional properties (PHY_TYPE_USB2 port (child) node): +- mediatek,eye-src : u32, the value of slew rate calibrate +- mediatek,eye-vrt : u32, the selection of VRT reference voltage +- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage +- mediatek,efuse-intr : u32, the selection of Internal Resistor + +Optional properties (PHY_TYPE_USB3 port (child) node): +- mediatek,efuse-intr : u32, the selection of Internal Resistor +- mediatek,efuse-tx-imp : u32, the selection of TX Impedance +- mediatek,efuse-rx-imp : u32, the selection of RX Impedance + +Banks layout of xsphy +------------------------------------------------------------- +port offset bank +u2 port0 0x0000 MISC + 0x0100 FMREG + 0x0300 U2PHY_COM +u2 port1 0x1000 MISC + 0x1100 FMREG + 0x1300 U2PHY_COM +u2 port2 0x2000 MISC + ... +u31 common 0x3000 DIG_GLB + 0x3100 PHYA_GLB +u31 port0 0x3400 DIG_LN_TOP + 0x3500 DIG_LN_TX0 + 0x3600 DIG_LN_RX0 + 0x3700 DIG_LN_DAIF + 0x3800 PHYA_LN +u31 port1 0x3a00 DIG_LN_TOP + 0x3b00 DIG_LN_TX0 + 0x3c00 DIG_LN_RX0 + 0x3d00 DIG_LN_DAIF + 0x3e00 PHYA_LN + ... + +DIG_GLB & PHYA_GLB are shared by U31 ports. + +Example: + +u3phy: usb-phy@11c40000 { + compatible = "mediatek,mt3611-xsphy", "mediatek,xsphy"; + reg = <0 0x11c43000 0 0x0200>; + mediatek,src-ref-clk-mhz = <26>; + mediatek,src-coef = <17>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + u2port0: usb-phy@11c40000 { + reg = <0 0x11c40000 0 0x0400>; + clocks = <&clk48m>; + clock-names = "ref"; + mediatek,eye-src = <4>; + #phy-cells = <1>; + }; + + u3port0: usb-phy@11c43000 { + reg = <0 0x11c43400 0 0x0500>; + clocks = <&clk26m>; + clock-names = "ref"; + mediatek,efuse-intr = <28>; + #phy-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-mvebu-comphy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mvebu-comphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..bfcf80341657ce6ba39891ff10b1c9c19d775a0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mvebu-comphy.txt @@ -0,0 +1,43 @@ +mvebu comphy driver +------------------- + +A comphy controller can be found on Marvell Armada 7k/8k on the CP110. It +provides a number of shared PHYs used by various interfaces (network, sata, +usb, PCIe...). + +Required properties: + +- compatible: should be "marvell,comphy-cp110" +- reg: should contain the comphy register location and length. +- marvell,system-controller: should contain a phandle to the + system controller node. +- #address-cells: should be 1. +- #size-cells: should be 0. + +A sub-node is required for each comphy lane provided by the comphy. + +Required properties (child nodes): + +- reg: comphy lane number. +- #phy-cells : from the generic phy bindings, must be 1. Defines the + input port to use for a given comphy lane. + +Example: + + cpm_comphy: phy@120000 { + compatible = "marvell,comphy-cp110"; + reg = <0x120000 0x6000>; + marvell,system-controller = <&cpm_syscon0>; + #address-cells = <1>; + #size-cells = <0>; + + cpm_comphy0: phy@0 { + reg = <0>; + #phy-cells = <1>; + }; + + cpm_comphy1: phy@1 { + reg = <1>; + #phy-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-mvebu.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mvebu.txt new file mode 100644 index 0000000000000000000000000000000000000000..64afdd13d91dfd4a9f1f299d632b64689f8a8b8d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-mvebu.txt @@ -0,0 +1,42 @@ +* Marvell MVEBU SATA PHY + +Power control for the SATA phy found on Marvell MVEBU SoCs. + +This document extends the binding described in phy-bindings.txt + +Required properties : + + - reg : Offset and length of the register set for the SATA device + - compatible : Should be "marvell,mvebu-sata-phy" + - clocks : phandle of clock and specifier that supplies the device + - clock-names : Should be "sata" + +Example: + sata-phy@84000 { + compatible = "marvell,mvebu-sata-phy"; + reg = <0x84000 0x0334>; + clocks = <&gate_clk 15>; + clock-names = "sata"; + #phy-cells = <0>; + }; + +Armada 375 USB cluster +---------------------- + +Armada 375 comes with an USB2 host and device controller and an USB3 +controller. The USB cluster control register allows to manage common +features of both USB controllers. + +Required properties: + +- compatible: "marvell,armada-375-usb-cluster" +- reg: Should contain usb cluster register location and length. +- #phy-cells : from the generic phy bindings, must be 1. Possible +values are 1 (USB2), 2 (USB3). + +Example: + usbcluster: usb-cluster@18400 { + compatible = "marvell,armada-375-usb-cluster"; + reg = <0x18400 0x4>; + #phy-cells = <1> + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-rockchip-inno-usb2.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-rockchip-inno-usb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..074a7b3b0425ddadac96079d0cdd83f7f9352582 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-rockchip-inno-usb2.txt @@ -0,0 +1,78 @@ +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK + +Required properties (phy (parent) node): + - compatible : should be one of the listed compatibles: + * "rockchip,rk3228-usb2phy" + * "rockchip,rk3328-usb2phy" + * "rockchip,rk3366-usb2phy" + * "rockchip,rk3399-usb2phy" + * "rockchip,rv1108-usb2phy" + - reg : the address offset of grf for usb-phy configuration. + - #clock-cells : should be 0. + - clock-output-names : specify the 480m output clock name. + +Optional properties: + - clocks : phandle + phy specifier pair, for the input clock of phy. + - clock-names : input clock name of phy, must be "phyclk". + - assigned-clocks : phandle of usb 480m clock. + - assigned-clock-parents : parent of usb 480m clock, select between + usb-phy output 480m and xin24m. + Refer to clk/clock-bindings.txt for generic clock + consumer properties. + - rockchip,usbgrf : phandle to the syscon managing the "usb general + register files". When set driver will request its + phandle as one companion-grf for some special SoCs + (e.g RV1108). + +Required nodes : a sub-node is required for each port the phy provides. + The sub-node name is used to identify host or otg port, + and shall be the following entries: + * "otg-port" : the name of otg port. + * "host-port" : the name of host port. + +Required properties (port (child) node): + - #phy-cells : must be 0. See ./phy-bindings.txt for details. + - interrupts : specify an interrupt for each entry in interrupt-names. + - interrupt-names : a list which should be one of the following cases: + Regular case: + * "otg-id" : for the otg id interrupt. + * "otg-bvalid" : for the otg vbus interrupt. + * "linestate" : for the host/otg linestate interrupt. + Some SoCs use one interrupt with the above muxed together, so for these + * "otg-mux" : otg-port interrupt, which mux otg-id/otg-bvalid/linestate + to one. + +Optional properties: + - phy-supply : phandle to a regulator that provides power to VBUS. + See ./phy-bindings.txt for details. + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + +... + + u2phy: usb2-phy@700 { + compatible = "rockchip,rk3366-usb2phy"; + reg = <0x700 0x2c>; + #clock-cells = <0>; + clock-output-names = "sclk_otgphy0_480m"; + + u2phy_otg: otg-port { + #phy-cells = <0>; + interrupts = , + , + ; + interrupt-names = "otg-id", "otg-bvalid", "linestate"; + }; + + u2phy_host: host-port { + #phy-cells = <0>; + interrupts = ; + interrupt-names = "linestate"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-rockchip-typec.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-rockchip-typec.txt new file mode 100644 index 0000000000000000000000000000000000000000..960da7fcaa9e4d0aa3b2d957429e26aabec34e82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-rockchip-typec.txt @@ -0,0 +1,84 @@ +* ROCKCHIP type-c PHY +--------------------- + +Required properties: + - compatible : must be "rockchip,rk3399-typec-phy" + - reg: Address and length of the usb phy control register set + - rockchip,grf : phandle to the syscon managing the "general + register files" + - clocks : phandle + clock specifier for the phy clocks + - clock-names : string, clock name, must be "tcpdcore", "tcpdphy-ref"; + - assigned-clocks: main clock, should be <&cru SCLK_UPHY0_TCPDCORE> or + <&cru SCLK_UPHY1_TCPDCORE>; + - assigned-clock-rates : the phy core clk frequency, shall be: 50000000 + - resets : a list of phandle + reset specifier pairs + - reset-names : string reset name, must be: + "uphy", "uphy-pipe", "uphy-tcphy" + +Optional properties: + - extcon : extcon specifier for the Power Delivery + +Required nodes : a sub-node is required for each port the phy provides. + The sub-node name is used to identify dp or usb3 port, + and shall be the following entries: + * "dp-port" : the name of DP port. + * "usb3-port" : the name of USB3 port. + +Required properties (port (child) node): +- #phy-cells : must be 0, See ./phy-bindings.txt for details. + +Deprecated properties, do not use in new device tree sources, these +properties are determined by the compatible value: + - rockchip,typec-conn-dir + - rockchip,usb3tousb2-en + - rockchip,external-psm + - rockchip,pipe-status + +Example: + tcphy0: phy@ff7c0000 { + compatible = "rockchip,rk3399-typec-phy"; + reg = <0x0 0xff7c0000 0x0 0x40000>; + rockchip,grf = <&grf>; + extcon = <&fusb0>; + clocks = <&cru SCLK_UPHY0_TCPDCORE>, + <&cru SCLK_UPHY0_TCPDPHY_REF>; + clock-names = "tcpdcore", "tcpdphy-ref"; + assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>; + assigned-clock-rates = <50000000>; + resets = <&cru SRST_UPHY0>, + <&cru SRST_UPHY0_PIPE_L00>, + <&cru SRST_P_UPHY0_TCPHY>; + reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + + tcphy0_dp: dp-port { + #phy-cells = <0>; + }; + + tcphy0_usb3: usb3-port { + #phy-cells = <0>; + }; + }; + + tcphy1: phy@ff800000 { + compatible = "rockchip,rk3399-typec-phy"; + reg = <0x0 0xff800000 0x0 0x40000>; + rockchip,grf = <&grf>; + extcon = <&fusb1>; + clocks = <&cru SCLK_UPHY1_TCPDCORE>, + <&cru SCLK_UPHY1_TCPDPHY_REF>; + clock-names = "tcpdcore", "tcpdphy-ref"; + assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>; + assigned-clock-rates = <50000000>; + resets = <&cru SRST_UPHY1>, + <&cru SRST_UPHY1_PIPE_L00>, + <&cru SRST_P_UPHY1_TCPHY>; + reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; + + tcphy1_dp: dp-port { + #phy-cells = <0>; + }; + + tcphy1_usb3: usb3-port { + #phy-cells = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-stih407-usb.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-stih407-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..de6a706abcdbe900fda70080f76bc9214c1400f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-stih407-usb.txt @@ -0,0 +1,24 @@ +ST STiH407 USB PHY controller + +This file documents the dt bindings for the usb picoPHY driver which is the PHY for both USB2 and USB3 +host controllers (when controlling usb2/1.1 devices) available on STiH407 SoC family from STMicroelectronics. + +Required properties: +- compatible : should be "st,stih407-usb2-phy" +- st,syscfg : phandle of sysconfig bank plus integer array containing phyparam and phyctrl register offsets +- resets : list of phandle and reset specifier pairs. There should be two entries, one + for the whole phy and one for the port +- reset-names : list of reset signal names. Should be "global" and "port" +See: Documentation/devicetree/bindings/reset/st,sti-powerdown.txt +See: Documentation/devicetree/bindings/reset/reset.txt + +Example: + +usb2_picophy0: usbpicophy@f8 { + compatible = "st,stih407-usb2-phy"; + #phy-cells = <0>; + st,syscfg = <&syscfg_core 0x100 0xf4>; + resets = <&softreset STIH407_PICOPHY_SOFTRESET>, + <&picophyreset STIH407_PICOPHY0_RESET>; + reset-names = "global", "port"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-stih41x-usb.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-stih41x-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..744b4809542edd3b3c8a3b64a17bcc4fc4012ce3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-stih41x-usb.txt @@ -0,0 +1,24 @@ +STMicroelectronics STiH41x USB PHY binding +------------------------------------------ + +This file contains documentation for the usb phy found in STiH415/6 SoCs from +STMicroelectronics. + +Required properties: +- compatible : should be "st,stih416-usb-phy" or "st,stih415-usb-phy" +- st,syscfg : should be a phandle of the syscfg node +- clock-names : must contain "osc_phy" +- clocks : must contain an entry for each name in clock-names. +See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- #phy-cells : must be 0 for this phy +See: Documentation/devicetree/bindings/phy/phy-bindings.txt + +Example: + +usb2_phy: usb2phy@0 { + compatible = "st,stih416-usb-phy"; + #phy-cells = <0>; + st,syscfg = <&syscfg_rear>; + clocks = <&clk_sysin>; + clock-names = "osc_phy"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/phy-stm32-usbphyc.txt b/arch/arm64/boot/dts/vendor/bindings/phy/phy-stm32-usbphyc.txt new file mode 100644 index 0000000000000000000000000000000000000000..725ae71ae6535a0bdb8ccbf2ed83e168d3002d56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/phy-stm32-usbphyc.txt @@ -0,0 +1,73 @@ +STMicroelectronics STM32 USB HS PHY controller + +The STM32 USBPHYC block contains a dual port High Speed UTMI+ PHY and a UTMI +switch. It controls PHY configuration and status, and the UTMI+ switch that +selects either OTG or HOST controller for the second PHY port. It also sets +PLL configuration. + +USBPHYC + |_ PLL + | + |_ PHY port#1 _________________ HOST controller + | _ | + | / 1|________________| + |_ PHY port#2 ----| |________________ + | \_0| | + |_ UTMI switch_______| OTG controller + + +Phy provider node +================= + +Required properties: +- compatible: must be "st,stm32mp1-usbphyc" +- reg: address and length of the usb phy control register set +- clocks: phandle + clock specifier for the PLL phy clock +- #address-cells: number of address cells for phys sub-nodes, must be <1> +- #size-cells: number of size cells for phys sub-nodes, must be <0> + +Optional properties: +- assigned-clocks: phandle + clock specifier for the PLL phy clock +- assigned-clock-parents: the PLL phy clock parent +- resets: phandle + reset specifier + +Required nodes: one sub-node per port the controller provides. + +Phy sub-nodes +============== + +Required properties: +- reg: phy port index +- phy-supply: phandle to the regulator providing 3V3 power to the PHY, + see phy-bindings.txt in the same directory. +- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY +- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY +- #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY + port#1 and must be <1> for PHY port#2, to select USB controller + + +Example: + usbphyc: usb-phy@5a006000 { + compatible = "st,stm32mp1-usbphyc"; + reg = <0x5a006000 0x1000>; + clocks = <&rcc_clk USBPHY_K>; + resets = <&rcc_rst USBPHY_R>; + #address-cells = <1>; + #size-cells = <0>; + + usbphyc_port0: usb-phy@0 { + reg = <0>; + phy-supply = <&vdd_usb>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18> + #phy-cells = <0>; + }; + + usbphyc_port1: usb-phy@1 { + reg = <1>; + phy-supply = <&vdd_usb>; + vdda1v1-supply = <®11>; + vdda1v8-supply = <®18> + #phy-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/pistachio-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/pistachio-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..afbc7e24a3de3e776225574d9d34d24575a4e009 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/pistachio-usb-phy.txt @@ -0,0 +1,29 @@ +IMG Pistachio USB PHY +===================== + +Required properties: +-------------------- + - compatible: Must be "img,pistachio-usb-phy". + - #phy-cells: Must be 0. See ./phy-bindings.txt for details. + - clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. + - clock-names: Must include "usb_phy". + - img,cr-top: Must constain a phandle to the CR_TOP syscon node. + - img,refclk: Indicates the reference clock source for the USB PHY. + See for a list of valid values. + +Optional properties: +-------------------- + - phy-supply: USB VBUS supply. Must supply 5.0V. + +Example: +-------- +usb_phy: usb-phy { + compatible = "img,pistachio-usb-phy"; + clocks = <&clk_core CLK_USB_PHY>; + clock-names = "usb_phy"; + phy-supply = <&usb_vbus>; + img,refclk = ; + img,cr-top = <&cr_top>; + #phy-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/pxa1928-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/pxa1928-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..660a13ca90b34fbf2e319d1c9a84dda4700ede71 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/pxa1928-usb-phy.txt @@ -0,0 +1,18 @@ +* Marvell PXA1928 USB and HSIC PHYs + +Required properties: +- compatible: "marvell,pxa1928-usb-phy" or "marvell,pxa1928-hsic-phy" +- reg: base address and length of the registers +- clocks - A single clock. From common clock binding. +- #phys-cells: should be 0. From commmon phy binding. +- resets: reference to the reset controller + +Example: + + usbphy: phy@7000 { + compatible = "marvell,pxa1928-usb-phy"; + reg = <0x7000 0xe0>; + clocks = <&apmu_clocks PXA1928_CLK_USB>; + #phy-cells = <0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-8x16-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-8x16-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..2cb2168cef411b145673089d9ce47043c9d08cfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-8x16-phy.txt @@ -0,0 +1,76 @@ +Qualcomm's APQ8016/MSM8916 USB transceiver controller + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,usb-8x16-phy". + +- reg: + Usage: required + Value type: + Definition: USB PHY base address and length of the register map + +- clocks: + Usage: required + Value type: + Definition: See clock-bindings.txt section "consumers". List of + two clock specifiers for interface and core controller + clocks. + +- clock-names: + Usage: required + Value type: + Definition: Must contain "iface" and "core" strings. + +- vddcx-supply: + Usage: required + Value type: + Definition: phandle to the regulator VDCCX supply node. + +- v1p8-supply: + Usage: required + Value type: + Definition: phandle to the regulator 1.8V supply node. + +- v3p3-supply: + Usage: required + Value type: + Definition: phandle to the regulator 3.3V supply node. + +- resets: + Usage: required + Value type: + Definition: See reset.txt section "consumers". PHY reset specifier. + +- reset-names: + Usage: required + Value type: + Definition: Must contain "phy" string. + +- switch-gpio: + Usage: optional + Value type: + Definition: Some boards are using Dual SPDT USB Switch, witch is + controlled by GPIO to de/multiplex D+/D- USB lines + between connectors. + +Example: + usb_phy: phy@78d9000 { + compatible = "qcom,usb-8x16-phy"; + reg = <0x78d9000 0x400>; + + vddcx-supply = <&pm8916_s1_corner>; + v1p8-supply = <&pm8916_l7>; + v3p3-supply = <&pm8916_l13>; + + clocks = <&gcc GCC_USB_HS_AHB_CLK>, + <&gcc GCC_USB_HS_SYSTEM_CLK>; + clock-names = "iface", "core"; + + resets = <&gcc GCC_USB2A_PHY_BCR>; + reset-names = "phy"; + + // D+/D- lines: 1 - Routed to HUB, 0 - Device connector + switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-hs-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-hs-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3b75c1e6285f2a24f5b62e748538d4cb607b41e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-hs-phy.txt @@ -0,0 +1,84 @@ +Qualcomm's USB HS PHY + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,usb-hs-phy" and more specifically one of the + following: + + "qcom,usb-hs-phy-apq8064" + "qcom,usb-hs-phy-msm8916" + "qcom,usb-hs-phy-msm8974" + +- #phy-cells: + Usage: required + Value type: + Definition: Should contain 0 + +- clocks: + Usage: required + Value type: + Definition: Should contain clock specifier for the reference and sleep + clocks + +- clock-names: + Usage: required + Value type: + Definition: Should contain "ref" and "sleep" for the reference and sleep + clocks respectively + +- resets: + Usage: required + Value type: + Definition: Should contain the phy and POR resets + +- reset-names: + Usage: required + Value type: + Definition: Should contain "phy" and "por" for the phy and POR resets + respectively + +- v3p3-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 3.3V supply + +- v1p8-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V supply + +- extcon: + Usage: optional + Value type: + Definition: Should contain the vbus extcon + +- qcom,init-seq: + Usage: optional + Value type: + Definition: Should contain a sequence of ULPI address and value pairs to + program into the ULPI_EXT_VENDOR_SPECIFIC area. This is related + to Device Mode Eye Diagram test. The addresses are offsets + from the ULPI_EXT_VENDOR_SPECIFIC address, for example, + <0x1 0x53> would mean "write the value 0x53 to address 0x81". + +EXAMPLE + +otg: usb-controller { + ulpi { + phy { + compatible = "qcom,usb-hs-phy-msm8974", "qcom,usb-hs-phy"; + #phy-cells = <0>; + clocks = <&xo_board>, <&gcc GCC_USB2A_PHY_SLEEP_CLK>; + clock-names = "ref", "sleep"; + resets = <&gcc GCC_USB2A_PHY_BCR>, <&otg 0>; + reset-names = "phy", "por"; + v3p3-supply = <&pm8941_l24>; + v1p8-supply = <&pm8941_l6>; + extcon = <&smbb>; + qcom,init-seq = /bits/ 8 <0x1 0x63>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-hsic-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-hsic-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c7cb2be4b126db581976ca01a984b11cbed03a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom,usb-hsic-phy.txt @@ -0,0 +1,65 @@ +Qualcomm's USB HSIC PHY + +PROPERTIES + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,usb-hsic-phy" and more specifically one of the + following: + + "qcom,usb-hsic-phy-mdm9615" + "qcom,usb-hsic-phy-msm8974" + +- #phy-cells: + Usage: required + Value type: + Definition: Should contain 0 + +- clocks: + Usage: required + Value type: + Definition: Should contain clock specifier for phy, calibration and + a calibration sleep clock + +- clock-names: + Usage: required + Value type: + Definition: Should contain "phy, "cal" and "cal_sleep" + +- pinctrl-names: + Usage: required + Value type: + Definition: Should contain "init" and "default" in that order + +- pinctrl-0: + Usage: required + Value type: + Definition: List of pinctrl settings to apply to keep HSIC pins in a glitch + free state + +- pinctrl-1: + Usage: required + Value type: + Definition: List of pinctrl settings to apply to mux out the HSIC pins + +EXAMPLE + +usb-controller { + ulpi { + phy { + compatible = "qcom,usb-hsic-phy-msm8974", + "qcom,usb-hsic-phy"; + #phy-cells = <0>; + pinctrl-names = "init", "default"; + pinctrl-0 = <&hsic_sleep>; + pinctrl-1 = <&hsic_default>; + clocks = <&gcc GCC_USB_HSIC_CLK>, + <&gcc GCC_USB_HSIC_IO_CAL_CLK>, + <&gcc GCC_USB_HSIC_IO_CAL_SLEEP_CLK>; + clock-names = "phy", "cal", "cal_sleep"; + assigned-clocks = <&gcc GCC_USB_HSIC_IO_CAL_CLK>; + assigned-clock-rates = <960000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom-apq8064-sata-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-apq8064-sata-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..952f6c96bab903deb9df684ef63a059b9900076d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-apq8064-sata-phy.txt @@ -0,0 +1,24 @@ +Qualcomm APQ8064 SATA PHY Controller +------------------------------------ + +SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. +Each SATA PHY controller should have its own node. + +Required properties: +- compatible: compatible list, contains "qcom,apq8064-sata-phy". +- reg: offset and length of the SATA PHY register set; +- #phy-cells: must be zero +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. +- clock-names: must be "cfg" for phy config clock. + +Example: + sata_phy: sata-phy@1b400000 { + compatible = "qcom,apq8064-sata-phy"; + reg = <0x1b400000 0x200>; + + clocks = <&gcc SATA_PHY_CFG_CLK>; + clock-names = "cfg"; + + #phy-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom-dwc3-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-dwc3-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1697c27aecde4f3e0f7633c700f4e8c20eab4b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-dwc3-usb-phy.txt @@ -0,0 +1,37 @@ +Qualcomm DWC3 HS AND SS PHY CONTROLLER +-------------------------------------- + +DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer +controllers. Each DWC3 PHY controller should have its own node. + +Required properties: +- compatible: should contain one of the following: + - "qcom,dwc3-hs-usb-phy" for High Speed Synopsis PHY controller + - "qcom,dwc3-ss-usb-phy" for Super Speed Synopsis PHY controller +- reg: offset and length of the DWC3 PHY controller register set +- #phy-cells: must be zero +- clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. +- clock-names: Should contain "ref" for the PHY reference clock + +Optional clocks: + "xo" External reference clock + +Example: + phy@100f8800 { + compatible = "qcom,dwc3-hs-usb-phy"; + reg = <0x100f8800 0x30>; + clocks = <&gcc USB30_0_UTMI_CLK>; + clock-names = "ref"; + #phy-cells = <0>; + + }; + + phy@100f8830 { + compatible = "qcom,dwc3-ss-usb-phy"; + reg = <0x100f8830 0x30>; + clocks = <&gcc USB30_0_MASTER_CLK>; + clock-names = "ref"; + #phy-cells = <0>; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom-ipq806x-sata-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-ipq806x-sata-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..76bfbd056202e43ab7238724a058202ab1b173e3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-ipq806x-sata-phy.txt @@ -0,0 +1,23 @@ +Qualcomm IPQ806x SATA PHY Controller +------------------------------------ + +SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. +Each SATA PHY controller should have its own node. + +Required properties: +- compatible: compatible list, contains "qcom,ipq806x-sata-phy" +- reg: offset and length of the SATA PHY register set; +- #phy-cells: must be zero +- clocks: must be exactly one entry +- clock-names: must be "cfg" + +Example: + sata_phy: sata-phy@1b400000 { + compatible = "qcom,ipq806x-sata-phy"; + reg = <0x1b400000 0x200>; + + clocks = <&gcc SATA_PHY_CFG_CLK>; + clock-names = "cfg"; + + #phy-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom-qmp-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-qmp-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c7629e88bf3ac8c02094403c19272beea966f4f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-qmp-phy.txt @@ -0,0 +1,132 @@ +Qualcomm QMP PHY controller +=========================== + +QMP phy controller supports physical layer functionality for a number of +controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB. + +Required properties: + - compatible: compatible list, contains: + "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074 + "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996, + "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996, + "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, + "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845. + + - reg: + - For "qcom,sdm845-qmp-usb3-phy": + - index 0: address and length of register set for PHY's common serdes + block. + - named register "dp_com" (using reg-names): address and length of the + DP_COM control block. + - For all others: + - offset and length of register set for PHY's common serdes block. + + - #clock-cells: must be 1 + - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe + interface (for pipe based PHYs). These clock are then gate-controlled + by gcc. + - #address-cells: must be 1 + - #size-cells: must be 1 + - ranges: must be present + + - clocks: a list of phandles and clock-specifier pairs, + one for each entry in clock-names. + - clock-names: "cfg_ahb" for phy config clock, + "aux" for phy aux clock, + "ref" for 19.2 MHz ref clk, + "com_aux" for phy common block aux clock, + For "qcom,msm8996-qmp-pcie-phy" must contain: + "aux", "cfg_ahb", "ref". + For "qcom,msm8996-qmp-usb3-phy" must contain: + "aux", "cfg_ahb", "ref". + For "qcom,qmp-v3-usb3-phy" must contain: + "aux", "cfg_ahb", "ref", "com_aux". + + - resets: a list of phandles and reset controller specifier pairs, + one for each entry in reset-names. + - reset-names: "phy" for reset of phy block, + "common" for phy common block reset, + "cfg" for phy's ahb cfg block reset (Optional). + For "qcom,msm8996-qmp-pcie-phy" must contain: + "phy", "common", "cfg". + For "qcom,msm8996-qmp-usb3-phy" must contain + "phy", "common". + For "qcom,ipq8074-qmp-pcie-phy" must contain: + "phy", "common". + + - vdda-phy-supply: Phandle to a regulator supply to PHY core block. + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block. + +Optional properties: + - vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk + pll block. + +Required nodes: + - Each device node of QMP phy is required to have as many child nodes as + the number of lanes the PHY has. + +Required properties for child node: + - reg: list of offset and length pairs of register sets for PHY blocks - + - index 0: tx + - index 1: rx + - index 2: pcs + - index 3: pcs_misc (optional) + + - #phy-cells: must be 0 + + - clocks: a list of phandles and clock-specifier pairs, + one for each entry in clock-names. + - clock-names: Must contain following for pcie and usb qmp phys: + "pipe" for pipe clock specific to each lane. + - clock-output-names: Name of the PHY clock that will be the parent for + the above pipe clock. + + For "qcom,ipq8074-qmp-pcie-phy": + - "pcie20_phy0_pipe_clk" Pipe Clock parent + (or) + "pcie20_phy1_pipe_clk" + + - resets: a list of phandles and reset controller specifier pairs, + one for each entry in reset-names. + - reset-names: Must contain following for pcie qmp phys: + "lane" for reset specific to each lane. + +Example: + phy@34000 { + compatible = "qcom,msm8996-qmp-pcie-phy"; + reg = <0x34000 0x488>; + #clock-cells = <1>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, + <&gcc GCC_PCIE_PHY_CFG_AHB_CLK>, + <&gcc GCC_PCIE_CLKREF_CLK>; + clock-names = "aux", "cfg_ahb", "ref"; + + vdda-phy-supply = <&pm8994_l28>; + vdda-pll-supply = <&pm8994_l12>; + + resets = <&gcc GCC_PCIE_PHY_BCR>, + <&gcc GCC_PCIE_PHY_COM_BCR>, + <&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>; + reset-names = "phy", "common", "cfg"; + + pciephy_0: lane@35000 { + reg = <0x35000 0x130>, + <0x35200 0x200>, + <0x35400 0x1dc>; + #phy-cells = <0>; + + clocks = <&gcc GCC_PCIE_0_PIPE_CLK>; + clock-names = "pipe0"; + clock-output-names = "pcie_0_pipe_clk_src"; + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "lane0"; + }; + + pciephy_1: lane@36000 { + ... + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/qcom-qusb2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-qusb2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..03025d97998b48276ceec27adaa230debd9febfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/qcom-qusb2-phy.txt @@ -0,0 +1,67 @@ +Qualcomm QUSB2 phy controller +============================= + +QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets. + +Required properties: + - compatible: compatible list, contains + "qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996, + "qcom,sdm845-qusb2-phy" for 10nm PHY on sdm845. + + - reg: offset and length of the PHY register set. + - #phy-cells: must be 0. + + - clocks: a list of phandles and clock-specifier pairs, + one for each entry in clock-names. + - clock-names: must be "cfg_ahb" for phy config clock, + "ref" for 19.2 MHz ref clk, + "iface" for phy interface clock (Optional). + + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block. + - vdda-phy-dpdm-supply: Phandle to 3.1V regulator supply to Dp/Dm port signals. + + - resets: Phandle to reset to phy block. + +Optional properties: + - nvmem-cells: Phandle to nvmem cell that contains 'HS Tx trim' + tuning parameter value for qusb2 phy. + + - qcom,tcsr-syscon: Phandle to TCSR syscon register region. + - qcom,imp-res-offset-value: It is a 6 bit value that specifies offset to be + added to PHY refgen RESCODE via IMP_CTRL1 register. It is a PHY + tuning parameter that may vary for different boards of same SOC. + This property is applicable to only QUSB2 v2 PHY (sdm845). + - qcom,hstx-trim-value: It is a 4 bit value that specifies tuning for HSTX + output current. + Possible range is - 15mA to 24mA (stepsize of 600 uA). + See dt-bindings/phy/phy-qcom-qusb2.h for applicable values. + This property is applicable to only QUSB2 v2 PHY (sdm845). + Default value is 22.2mA for sdm845. + - qcom,preemphasis-level: It is a 2 bit value that specifies pre-emphasis level. + Possible range is 0 to 15% (stepsize of 5%). + See dt-bindings/phy/phy-qcom-qusb2.h for applicable values. + This property is applicable to only QUSB2 v2 PHY (sdm845). + Default value is 10% for sdm845. +- qcom,preemphasis-width: It is a 1 bit value that specifies how long the HSTX + pre-emphasis (specified using qcom,preemphasis-level) must be in + effect. Duration could be half-bit of full-bit. + See dt-bindings/phy/phy-qcom-qusb2.h for applicable values. + This property is applicable to only QUSB2 v2 PHY (sdm845). + Default value is full-bit width for sdm845. + +Example: + hsusb_phy: phy@7411000 { + compatible = "qcom,msm8996-qusb2-phy"; + reg = <0x7411000 0x180>; + #phy-cells = <0>; + + clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_RX1_USB2_CLKREF_CLK>, + clock-names = "cfg_ahb", "ref"; + + vdda-pll-supply = <&pm8994_l12>; + vdda-phy-dpdm-supply = <&pm8994_l24>; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + nvmem-cells = <&qusb2p_hstx_trim>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/ralink-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/ralink-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d2868a437abfad18af5dfb68a185ebff0132397 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/ralink-usb-phy.txt @@ -0,0 +1,23 @@ +Mediatek/Ralink USB PHY + +Required properties: + - compatible: "ralink,rt3352-usbphy" + "mediatek,mt7620-usbphy" + "mediatek,mt7628-usbphy" + - reg: required for "mediatek,mt7628-usbphy", unused otherwise + - #phy-cells: should be 0 + - ralink,sysctl: a phandle to a ralink syscon register region + - resets: the two reset controllers for host and device + - reset-names: the names of the 2 reset controllers + +Example: + +usbphy: phy { + compatible = "mediatek,mt7628-usbphy"; + reg = <0x10120000 0x1000>; + #phy-cells = <0>; + + ralink,sysctl = <&sysc>; + resets = <&rstctrl 22 &rstctrl 25>; + reset-names = "host", "device"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen2-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen2-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..eeb9e1874ea627f7cadaa90439f963b25dc6e8dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen2-phy.txt @@ -0,0 +1,61 @@ +* Renesas R-Car generation 2 USB PHY + +This file provides information on what the device node for the R-Car generation +2 USB PHY contains. + +Required properties: +- compatible: "renesas,usb-phy-r8a7743" if the device is a part of R8A7743 SoC. + "renesas,usb-phy-r8a7745" if the device is a part of R8A7745 SoC. + "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. + "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. + "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. + "renesas,rcar-gen2-usb-phy" for a generic R-Car Gen2 or + RZ/G1 compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: offset and length of the register block. +- #address-cells: number of address cells for the USB channel subnodes, must + be <1>. +- #size-cells: number of size cells for the USB channel subnodes, must be <0>. +- clocks: clock phandle and specifier pair. +- clock-names: string, clock input name, must be "usbhs". + +The USB PHY device tree node should have the subnodes corresponding to the USB +channels. These subnodes must contain the following properties: +- reg: the USB controller selector; see the table below for the values. +- #phy-cells: see phy-bindings.txt in the same directory, must be <1>. + +The phandle's argument in the PHY specifier is the USB controller selector for +the USB channel; see the selector meanings below: + ++-----------+---------------+---------------+ +|\ Selector | | | ++ --------- + 0 | 1 | +| Channel \| | | ++-----------+---------------+---------------+ +| 0 | PCI EHCI/OHCI | HS-USB | +| 2 | PCI EHCI/OHCI | xHCI | ++-----------+---------------+---------------+ + +Example (Lager board): + + usb-phy@e6590100 { + compatible = "renesas,usb-phy-r8a7790", "renesas,rcar-gen2-usb-phy"; + reg = <0 0xe6590100 0 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mstp7_clks R8A7790_CLK_HSUSB>; + clock-names = "usbhs"; + + usb-channel@0 { + reg = <0>; + #phy-cells = <1>; + }; + usb-channel@2 { + reg = <2>; + #phy-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-pcie.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-pcie.txt new file mode 100644 index 0000000000000000000000000000000000000000..63853b35e0830d21ec1fb08483faecfe35232c44 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-pcie.txt @@ -0,0 +1,24 @@ +* Renesas R-Car generation 3 PCIe PHY + +This file provides information on what the device node for the R-Car +generation 3 PCIe PHY contains. + +Required properties: +- compatible: "renesas,r8a77980-pcie-phy" if the device is a part of the + R8A77980 SoC. +- reg: offset and length of the register block. +- clocks: clock phandle and specifier pair. +- power-domains: power domain phandle and specifier pair. +- resets: reset phandle and specifier pair. +- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. + +Example (R-Car V3H): + + pcie-phy@e65d0000 { + compatible = "renesas,r8a77980-pcie-phy"; + reg = <0 0xe65d0000 0 0x8000>; + #phy-cells = <0>; + clocks = <&cpg CPG_MOD 319>; + power-domains = <&sysc 32>; + resets = <&cpg 319>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-usb2.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-usb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb4a204da2bf197e8990d74ef56320583cfd3450 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-usb2.txt @@ -0,0 +1,48 @@ +* Renesas R-Car generation 3 USB 2.0 PHY + +This file provides information on what the device node for the R-Car generation +3 USB 2.0 PHY contains. + +Required properties: +- compatible: "renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795 + SoC. + "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796 + SoC. + "renesas,usb2-phy-r8a77965" if the device is a part of an + R8A77965 SoC. + "renesas,usb2-phy-r8a77990" if the device is a part of an + R8A77990 SoC. + "renesas,usb2-phy-r8a77995" if the device is a part of an + R8A77995 SoC. + "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: offset and length of the partial USB 2.0 Host register block. +- clocks: clock phandle and specifier pair(s). +- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. + +Optional properties: +To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are +combined, the device tree node should set interrupt properties to use the +channel as USB OTG: +- interrupts: interrupt specifier for the PHY. +- vbus-supply: Phandle to a regulator that provides power to the VBUS. This + regulator will be managed during the PHY power on/off sequence. + +Example (R-Car H3): + + usb-phy@ee080200 { + compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; + reg = <0 0xee080200 0 0x700>; + interrupts = ; + clocks = <&cpg CPG_MOD 703>; + }; + + usb-phy@ee0a0200 { + compatible = "renesas,usb2-phy-r8a7795", "renesas,rcar-gen3-usb2-phy"; + reg = <0 0xee0a0200 0 0x700>; + clocks = <&cpg CPG_MOD 702>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-usb3.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-usb3.txt new file mode 100644 index 0000000000000000000000000000000000000000..47dd296ecead9598e94835d4d5ce41386ef7940d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rcar-gen3-phy-usb3.txt @@ -0,0 +1,48 @@ +* Renesas R-Car generation 3 USB 3.0 PHY + +This file provides information on what the device node for the R-Car generation +3 USB 3.0 PHY contains. +If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL +instead of USB3_CLK. However, if you don't want to these features, you don't +need this driver. + +Required properties: +- compatible: "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 + SoC. + "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 + SoC. + "renesas,r8a77965-usb3-phy" if the device is a part of an + R8A77965 SoC. + "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible + device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: offset and length of the USB 3.0 PHY register block. +- clocks: A list of phandles and clock-specifier pairs. +- clock-names: Name of the clocks. + - The funcional clock must be "usb3-if". + - The usb3's external clock must be "usb3s_clk". + - The usb2's external clock must be "usb_extal". If you want to use the ssc, + the clock-frequency must not be 0. +- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. + +Optional properties: +- renesas,ssc-range: Enable/disable spread spectrum clock (ssc) by using + the following values as u32: + - 0 (or the property doesn't exist): disable the ssc + - 4980: enable the ssc as -4980 ppm + - 4492: enable the ssc as -4492 ppm + - 4003: enable the ssc as -4003 ppm + +Example (R-Car H3): + + usb-phy@e65ee000 { + compatible = "renesas,r8a7795-usb3-phy", + "renesas,rcar-gen3-usb3-phy"; + reg = <0 0xe65ee000 0 0x90>; + clocks = <&cpg CPG_MOD 328>, <&usb3s0_clk>, <&usb_extal>; + clock-names = "usb3-if", "usb3s_clk", "usb_extal"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-dp-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-dp-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3b4809fbe82c4798b7e5bef55e666505d6df527 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-dp-phy.txt @@ -0,0 +1,26 @@ +Rockchip specific extensions to the Analogix Display Port PHY +------------------------------------ + +Required properties: +- compatible : should be one of the following supported values: + - "rockchip.rk3288-dp-phy" +- clocks: from common clock binding: handle to dp clock. + of memory mapped region. +- clock-names: from common clock binding: + Required elements: "24m" +- #phy-cells : from the generic PHY bindings, must be 0; + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd"; + +... + + edp_phy: edp-phy { + compatible = "rockchip,rk3288-dp-phy"; + clocks = <&cru SCLK_EDP_24M>; + clock-names = "24m"; + #phy-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-emmc-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-emmc-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3ea55763b0ac5945b108d6f1d6a4fb443a8d9b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-emmc-phy.txt @@ -0,0 +1,34 @@ +Rockchip EMMC PHY +----------------------- + +Required properties: + - compatible: rockchip,rk3399-emmc-phy + - #phy-cells: must be 0 + - reg: PHY register address offset and length in "general + register files" + +Optional clocks using the clock bindings (see ../clock/clock-bindings.txt), +specified by name: + - clock-names: Should contain "emmcclk". Although this is listed as optional + (because most boards can get basic functionality without having + access to it), it is strongly suggested. + - clocks: Should have a phandle to the card clock exported by the SDHCI driver. + +Example: + + +grf: syscon@ff770000 { + compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + +... + + emmcphy: phy@f780 { + compatible = "rockchip,rk3399-emmc-phy"; + reg = <0xf780 0x20>; + clocks = <&sdhci>; + clock-names = "emmcclk"; + #phy-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-pcie-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-pcie-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..b496042f1f4436f4543b7b835d41afd1d1e4adb7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-pcie-phy.txt @@ -0,0 +1,36 @@ +Rockchip PCIE PHY +----------------------- + +Required properties: + - compatible: rockchip,rk3399-pcie-phy + - clocks: Must contain an entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must be "refclk" + - resets: Must contain an entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must be "phy" + +Required properties for legacy PHY mode (deprecated): + - #phy-cells: must be 0 + +Required properties for per-lane PHY mode (preferred): + - #phy-cells: must be 1 + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + + ... + + pcie_phy: pcie-phy { + compatible = "rockchip,rk3399-pcie-phy"; + #phy-cells = <0>; + clocks = <&cru SCLK_PCIEPHY_REF>; + clock-names = "refclk"; + resets = <&cru SRST_PCIEPHY>; + reset-names = "phy"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ed569046daf919e487d0147b47720cdd44817aa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/rockchip-usb-phy.txt @@ -0,0 +1,52 @@ +ROCKCHIP USB2 PHY + +Required properties: + - compatible: matching the soc type, one of + "rockchip,rk3066a-usb-phy" + "rockchip,rk3188-usb-phy" + "rockchip,rk3288-usb-phy" + - #address-cells: should be 1 + - #size-cells: should be 0 + +Deprecated properties: + - rockchip,grf : phandle to the syscon managing the "general + register files" - phy should be a child of the GRF instead + +Sub-nodes: +Each PHY should be represented as a sub-node. + +Sub-nodes +required properties: +- #phy-cells: should be 0 +- reg: PHY configure reg address offset in GRF + "0x320" - for PHY attach to OTG controller + "0x334" - for PHY attach to HOST0 controller + "0x348" - for PHY attach to HOST1 controller + +Optional Properties: +- clocks : phandle + clock specifier for the phy clocks +- clock-names: string, clock name, must be "phyclk" +- #clock-cells: for users of the phy-pll, should be 0 +- reset-names: Only allow the following entries: + - phy-reset +- resets: Must contain an entry for each entry in reset-names. +- vbus-supply: power-supply phandle for vbus power source + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3288-grf", "syscon", "simple-mfd"; + +... + + usbphy: phy { + compatible = "rockchip,rk3288-usb-phy"; + #address-cells = <1>; + #size-cells = <0>; + + usbphy0: usb-phy0 { + #phy-cells = <0>; + reg = <0x320>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/samsung-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/samsung-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c40ccd40ce4402735d72ad80dc4d3c28f44eb1f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/samsung-phy.txt @@ -0,0 +1,209 @@ +Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY +------------------------------------------------- + +Required properties: +- compatible : should be one of the listed compatibles: + - "samsung,s5pv210-mipi-video-phy" + - "samsung,exynos5420-mipi-video-phy" + - "samsung,exynos5433-mipi-video-phy" +- #phy-cells : from the generic phy bindings, must be 1; + +In case of s5pv210 and exynos5420 compatible PHYs: +- syscon - phandle to the PMU system controller + +In case of exynos5433 compatible PHY: + - samsung,pmu-syscon - phandle to the PMU system controller + - samsung,disp-sysreg - phandle to the DISP system registers controller + - samsung,cam0-sysreg - phandle to the CAM0 system registers controller + - samsung,cam1-sysreg - phandle to the CAM1 system registers controller + +For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in +the PHY specifier identifies the PHY and its meaning is as follows: + 0 - MIPI CSIS 0, + 1 - MIPI DSIM 0, + 2 - MIPI CSIS 1, + 3 - MIPI DSIM 1. +"samsung,exynos5420-mipi-video-phy" and "samsung,exynos5433-mipi-video-phy" +supports additional fifth PHY: + 4 - MIPI CSIS 2. + +Samsung EXYNOS SoC series Display Port PHY +------------------------------------------------- + +Required properties: +- compatible : should be one of the following supported values: + - "samsung,exynos5250-dp-video-phy" + - "samsung,exynos5420-dp-video-phy" +- samsung,pmu-syscon: phandle for PMU system controller interface, used to + control pmu registers for power isolation. +- #phy-cells : from the generic PHY bindings, must be 0; + +Samsung S5P/EXYNOS SoC series USB PHY +------------------------------------------------- + +Required properties: +- compatible : should be one of the listed compatibles: + - "samsung,exynos3250-usb2-phy" + - "samsung,exynos4210-usb2-phy" + - "samsung,exynos4x12-usb2-phy" + - "samsung,exynos5250-usb2-phy" + - "samsung,s5pv210-usb2-phy" +- reg : a list of registers used by phy driver + - first and obligatory is the location of phy modules registers +- samsung,sysreg-phandle - handle to syscon used to control the system registers +- samsung,pmureg-phandle - handle to syscon used to control PMU registers +- #phy-cells : from the generic phy bindings, must be 1; +- clocks and clock-names: + - the "phy" clock is required by the phy module, used as a gate + - the "ref" clock is used to get the rate of the clock provided to the + PHY module + +Optional properties: +- vbus-supply: power-supply phandle for vbus power source + +The first phandle argument in the PHY specifier identifies the PHY, its +meaning is compatible dependent. For the currently supported SoCs (Exynos 4210 +and Exynos 4212) it is as follows: + 0 - USB device ("device"), + 1 - USB host ("host"), + 2 - HSIC0 ("hsic0"), + 3 - HSIC1 ("hsic1"), +Exynos3250 has only USB device phy available as phy 0. + +Exynos 4210 and Exynos 4212 use mode switching and require that mode switch +register is supplied. + +Example: + +For Exynos 4412 (compatible with Exynos 4212): + +usbphy: phy@125b0000 { + compatible = "samsung,exynos4x12-usb2-phy"; + reg = <0x125b0000 0x100>; + clocks = <&clock 305>, <&clock 2>; + clock-names = "phy", "ref"; + #phy-cells = <1>; + samsung,sysreg-phandle = <&sys_reg>; + samsung,pmureg-phandle = <&pmu_reg>; +}; + +Then the PHY can be used in other nodes such as: + +phy-consumer@12340000 { + phys = <&usbphy 2>; + phy-names = "phy"; +}; + +Refer to DT bindings documentation of particular PHY consumer devices for more +information about required PHYs and the way of specification. + +Samsung SATA PHY Controller +--------------------------- + +SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers. +Each SATA PHY controller should have its own node. + +Required properties: +- compatible : compatible list, contains "samsung,exynos5250-sata-phy" +- reg : offset and length of the SATA PHY register set; +- #phy-cells : must be zero +- clocks : must be exactly one entry +- clock-names : must be "sata_phyctrl" +- samsung,exynos-sataphy-i2c-phandle : a phandle to the I2C device, no arguments +- samsung,syscon-phandle : a phandle to the PMU system controller, no arguments + +Example: + sata_phy: sata-phy@12170000 { + compatible = "samsung,exynos5250-sata-phy"; + reg = <0x12170000 0x1ff>; + clocks = <&clock 287>; + clock-names = "sata_phyctrl"; + #phy-cells = <0>; + samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>; + samsung,syscon-phandle = <&pmu_syscon>; + }; + +Device-Tree bindings for sataphy i2c client driver +-------------------------------------------------- + +Required properties: +compatible: Should be "samsung,exynos-sataphy-i2c" +- reg: I2C address of the sataphy i2c device. + +Example: + + sata_phy_i2c:sata-phy@38 { + compatible = "samsung,exynos-sataphy-i2c"; + reg = <0x38>; + }; + +Samsung Exynos5 SoC series USB DRD PHY controller +-------------------------------------------------- + +Required properties: +- compatible : Should be set to one of the following supported values: + - "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC, + - "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC. + - "samsung,exynos5433-usbdrd-phy" - for exynos5433 SoC. + - "samsung,exynos7-usbdrd-phy" - for exynos7 SoC. +- reg : Register offset and length of USB DRD PHY register set; +- clocks: Clock IDs array as required by the controller +- clock-names: names of clocks correseponding to IDs in the clock property; + Required clocks: + - phy: main PHY clock (same as USB DRD controller i.e. DWC3 IP clock), + used for register access. + - ref: PHY's reference clock (usually crystal clock), used for + PHY operations, associated by phy name. It is used to + determine bit values for clock settings register. + For Exynos5420 this is given as 'sclk_usbphy30' in CMU. + - optional clocks: Exynos5433 & Exynos7 SoC has now following additional + gate clocks available: + - phy_pipe: for PIPE3 phy + - phy_utmi: for UTMI+ phy + - itp: for ITP generation +- samsung,pmu-syscon: phandle for PMU system controller interface, used to + control pmu registers for power isolation. +- #phy-cells : from the generic PHY bindings, must be 1; + +For "samsung,exynos5250-usbdrd-phy" and "samsung,exynos5420-usbdrd-phy" +compatible PHYs, the second cell in the PHY specifier identifies the +PHY id, which is interpreted as follows: + 0 - UTMI+ type phy, + 1 - PIPE3 type phy, + +Example: + usbdrd_phy: usbphy@12100000 { + compatible = "samsung,exynos5250-usbdrd-phy"; + reg = <0x12100000 0x100>; + clocks = <&clock 286>, <&clock 1>; + clock-names = "phy", "ref"; + samsung,pmu-syscon = <&pmu_system_controller>; + #phy-cells = <1>; + }; + +- aliases: For SoCs like Exynos5420 having multiple USB 3.0 DRD PHY controllers, + 'usbdrd_phy' nodes should have numbered alias in the aliases node, + in the form of usbdrdphyN, N = 0, 1... (depending on number of + controllers). +Example: + aliases { + usbdrdphy0 = &usb3_phy0; + usbdrdphy1 = &usb3_phy1; + }; + +Samsung Exynos SoC series PCIe PHY controller +-------------------------------------------------- +Required properties: +- compatible : Should be set to "samsung,exynos5440-pcie-phy" +- #phy-cells : Must be zero +- reg : a register used by phy driver. + - First is for phy register, second is for block register. +- reg-names : Must be set to "phy" and "block". + +Example: + pcie_phy0: pcie-phy@270000 { + #phy-cells = <0>; + compatible = "samsung,exynos5440-pcie-phy"; + reg = <0x270000 0x1000>, <0x271000 0x40>; + reg-names = "phy", "block"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/st-spear-miphy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/st-spear-miphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a6bfdcc09b3e0e8c3acd2753cd43f5dbfe07e68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/st-spear-miphy.txt @@ -0,0 +1,15 @@ +ST SPEAr miphy DT details +========================= + +ST Microelectronics SPEAr miphy is a phy controller supporting PCIe and SATA. + +Required properties: +- compatible : should be "st,spear1310-miphy" or "st,spear1340-miphy" +- reg : offset and length of the PHY register set. +- misc: phandle for the syscon node to access misc registers +- #phy-cells : from the generic PHY bindings, must be 1. + - cell[1]: 0 if phy used for SATA, 1 for PCIe. + +Optional properties: +- phy-id: Instance id of the phy. Only required when there are multiple phys + present on a implementation. diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/sun4i-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/sun4i-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..07ca4ec4a745c94e38e65474e63e49c93a0e30c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/sun4i-usb-phy.txt @@ -0,0 +1,66 @@ +Allwinner sun4i USB PHY +----------------------- + +Required properties: +- compatible : should be one of + * allwinner,sun4i-a10-usb-phy + * allwinner,sun5i-a13-usb-phy + * allwinner,sun6i-a31-usb-phy + * allwinner,sun7i-a20-usb-phy + * allwinner,sun8i-a23-usb-phy + * allwinner,sun8i-a33-usb-phy + * allwinner,sun8i-a83t-usb-phy + * allwinner,sun8i-h3-usb-phy + * allwinner,sun8i-r40-usb-phy + * allwinner,sun8i-v3s-usb-phy + * allwinner,sun50i-a64-usb-phy +- reg : a list of offset + length pairs +- reg-names : + * "phy_ctrl" + * "pmu0" for H3, V3s and A64 + * "pmu1" + * "pmu2" for sun4i, sun6i, sun7i, sun8i-a83t or sun8i-h3 + * "pmu3" for sun8i-h3 +- #phy-cells : from the generic phy bindings, must be 1 +- clocks : phandle + clock specifier for the phy clocks +- clock-names : + * "usb_phy" for sun4i, sun5i or sun7i + * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i + * "usb0_phy", "usb1_phy" for sun8i + * "usb0_phy", "usb1_phy", "usb2_phy" and "usb2_hsic_12M" for sun8i-a83t + * "usb0_phy", "usb1_phy", "usb2_phy" and "usb3_phy" for sun8i-h3 +- resets : a list of phandle + reset specifier pairs +- reset-names : + * "usb0_reset" + * "usb1_reset" + * "usb2_reset" for sun4i, sun6i, sun7i, sun8i-a83t or sun8i-h3 + * "usb3_reset" for sun8i-h3 + +Optional properties: +- usb0_id_det-gpios : gpio phandle for reading the otg id pin value +- usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus +- usb0_vbus_power-supply: power-supply phandle for usb0 vbus presence detect +- usb0_vbus-supply : regulator phandle for controller usb0 vbus +- usb1_vbus-supply : regulator phandle for controller usb1 vbus +- usb2_vbus-supply : regulator phandle for controller usb2 vbus +- usb3_vbus-supply : regulator phandle for controller usb3 vbus + +Example: + usbphy: phy@01c13400 { + #phy-cells = <1>; + compatible = "allwinner,sun4i-a10-usb-phy"; + /* phy base regs, phy1 pmu reg, phy2 pmu reg */ + reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>; + reg-names = "phy_ctrl", "pmu1", "pmu2"; + clocks = <&usb_clk 8>; + clock-names = "usb_phy"; + resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>; + reset-names = "usb0_reset", "usb1_reset", "usb2_reset"; + pinctrl-names = "default"; + pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>; + usb0_id_det-gpios = <&pio 7 19 GPIO_ACTIVE_HIGH>; /* PH19 */ + usb0_vbus_det-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */ + usb0_vbus-supply = <®_usb0_vbus>; + usb1_vbus-supply = <®_usb1_vbus>; + usb2_vbus-supply = <®_usb2_vbus>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/sun9i-usb-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/sun9i-usb-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..64f7109aea1f79f11f046de4119e7147fc1b2ca5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/sun9i-usb-phy.txt @@ -0,0 +1,37 @@ +Allwinner sun9i USB PHY +----------------------- + +Required properties: +- compatible : should be one of + * allwinner,sun9i-a80-usb-phy +- reg : a list of offset + length pairs +- #phy-cells : from the generic phy bindings, must be 0 +- phy_type : "hsic" for HSIC usage; + other values or absence of this property indicates normal USB +- clocks : phandle + clock specifier for the phy clocks +- clock-names : depending on the "phy_type" property, + * "phy" for normal USB + * "hsic_480M", "hsic_12M" for HSIC +- resets : a list of phandle + reset specifier pairs +- reset-names : depending on the "phy_type" property, + * "phy" for normal USB + * "hsic" for HSIC + +Optional Properties: +- phy-supply : from the generic phy bindings, a phandle to a regulator that + provides power to VBUS. + +It is recommended to list all clocks and resets available. +The driver will only use those matching the phy_type. + +Example: + usbphy1: phy@a01800 { + compatible = "allwinner,sun9i-a80-usb-phy"; + reg = <0x00a01800 0x4>; + clocks = <&usb_phy_clk 2>, <&usb_phy_clk 10>, + <&usb_phy_clk 3>; + clock-names = "hsic_480M", "hsic_12M", "phy"; + resets = <&usb_phy_clk 18>, <&usb_phy_clk 19>; + reset-names = "hsic", "phy"; + #phy-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/phy/ti-phy.txt b/arch/arm64/boot/dts/vendor/bindings/phy/ti-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..57dfda8a7a1da5cb0a4799882f75a154dd2750af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/phy/ti-phy.txt @@ -0,0 +1,134 @@ +TI PHY: DT DOCUMENTATION FOR PHYs in TI PLATFORMs + +OMAP CONTROL PHY + +Required properties: + - compatible: Should be one of + "ti,control-phy-otghs" - if it has otghs_control mailbox register as on OMAP4. + "ti,control-phy-usb2" - if it has Power down bit in control_dev_conf register + e.g. USB2_PHY on OMAP5. + "ti,control-phy-pipe3" - if it has DPLL and individual Rx & Tx power control + e.g. USB3 PHY and SATA PHY on OMAP5. + "ti,control-phy-pcie" - for pcie to support external clock for pcie and to + set PCS delay value. + e.g. PCIE PHY in DRA7x + "ti,control-phy-usb2-dra7" - if it has power down register like USB2 PHY on + DRA7 platform. + "ti,control-phy-usb2-am437" - if it has power down register like USB2 PHY on + AM437 platform. + - reg : register ranges as listed in the reg-names property + - reg-names: "otghs_control" for control-phy-otghs + "power", "pcie_pcs" and "control_sma" for control-phy-pcie + "power" for all other types + +omap_control_usb: omap-control-usb@4a002300 { + compatible = "ti,control-phy-otghs"; + reg = <0x4a00233c 0x4>; + reg-names = "otghs_control"; +}; + +OMAP USB2 PHY + +Required properties: + - compatible: Should be "ti,omap-usb2" + Should be "ti,dra7x-usb2" for the 1st instance of USB2 PHY on + DRA7x + Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY + in DRA7x + - reg : Address and length of the register set for the device. + - #phy-cells: determine the number of cells that should be given in the + phandle while referencing this phy. + - clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + - clock-names: should include: + * "wkupclk" - wakeup clock. + * "refclk" - reference clock (optional). + +Deprecated properties: + - ctrl-module : phandle of the control module used by PHY driver to power on + the PHY. + +Recommended properies: +- syscon-phy-power : phandle/offset pair. Phandle to the system control + module and the register offset to power on/off the PHY. + +This is usually a subnode of ocp2scp to which it is connected. + +usb2phy@4a0ad080 { + compatible = "ti,omap-usb2"; + reg = <0x4a0ad080 0x58>; + ctrl-module = <&omap_control_usb>; + #phy-cells = <0>; + clocks = <&usb_phy_cm_clk32k>, <&usb_otg_ss_refclk960m>; + clock-names = "wkupclk", "refclk"; +}; + +TI PIPE3 PHY + +Required properties: + - compatible: Should be "ti,phy-usb3", "ti,phy-pipe3-sata" or + "ti,phy-pipe3-pcie. "ti,omap-usb3" is deprecated. + - reg : Address and length of the register set for the device. + - reg-names: The names of the register addresses corresponding to the registers + filled in "reg". + - #phy-cells: determine the number of cells that should be given in the + phandle while referencing this phy. + - clocks: a list of phandles and clock-specifier pairs, one for each entry in + clock-names. + - clock-names: should include: + * "wkupclk" - wakeup clock. + * "sysclk" - system clock. + * "refclk" - reference clock. + * "dpll_ref" - external dpll ref clk + * "dpll_ref_m2" - external dpll ref clk + * "phy-div" - divider for apll + * "div-clk" - apll clock + +Optional properties: + - id: If there are multiple instance of the same type, in order to + differentiate between each instance "id" can be used (e.g., multi-lane PCIe + PHY). If "id" is not provided, it is set to default value of '1'. + - syscon-pllreset: Handle to system control region that contains the + CTRL_CORE_SMA_SW_0 register and register offset to the CTRL_CORE_SMA_SW_0 + register that contains the SATA_PLL_SOFT_RESET bit. Only valid for sata_phy. + - syscon-pcs : phandle/offset pair. Phandle to the system control module and the + register offset to write the PCS delay value. + +Deprecated properties: + - ctrl-module : phandle of the control module used by PHY driver to power on + the PHY. + +Recommended properies: + - syscon-phy-power : phandle/offset pair. Phandle to the system control + module and the register offset to power on/off the PHY. + +This is usually a subnode of ocp2scp to which it is connected. + +usb3phy@4a084400 { + compatible = "ti,phy-usb3"; + reg = <0x4a084400 0x80>, + <0x4a084800 0x64>, + <0x4a084c00 0x40>; + reg-names = "phy_rx", "phy_tx", "pll_ctrl"; + ctrl-module = <&omap_control_usb>; + #phy-cells = <0>; + clocks = <&usb_phy_cm_clk32k>, + <&sys_clkin>, + <&usb_otg_ss_refclk960m>; + clock-names = "wkupclk", + "sysclk", + "refclk"; +}; + +sata_phy: phy@4a096000 { + compatible = "ti,phy-pipe3-sata"; + reg = <0x4A096000 0x80>, /* phy_rx */ + <0x4A096400 0x64>, /* phy_tx */ + <0x4A096800 0x40>; /* pll_ctrl */ + reg-names = "phy_rx", "phy_tx", "pll_ctrl"; + ctrl-module = <&omap_control_sata>; + clocks = <&sys_clkin1>, <&sata_ref_clk>; + clock-names = "sysclk", "refclk"; + syscon-pllreset = <&scm_conf 0x3fc>; + #phy-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pil/pil-q6v5-mss.txt b/arch/arm64/boot/dts/vendor/bindings/pil/pil-q6v5-mss.txt new file mode 100644 index 0000000000000000000000000000000000000000..5486ff0d0efc50cab4066fa25eb46e0b469b1d87 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pil/pil-q6v5-mss.txt @@ -0,0 +1,142 @@ +Qualcomm Technologies, Inc. MSS QDSP6v5 Peripheral Image Loader + +pil-qdsp6v5-mss is a peripheral image loader (PIL) driver. It is used for +loading QDSP6v5 (Hexagon) firmware images for modem subsystems into memory and +preparing the subsystem's processor to execute code. It's also responsible for +shutting down the processor when it's not needed. + +Required properties: +- compatible: Must be "qcom,pil-q6v5-mss" or "qcom,pil-q6v55-mss" or + "qcom,pil-q6v56-mss". +- reg: Pairs of physical base addresses and region sizes of + memory mapped registers. +- reg-names: Names of the bases for the above registers. "qdsp6_base", + "rmb_base", "restart_reg" or "restart_reg_sec"(optional + for secure mode) are expected. + If "halt_base" is in same 4K pages this register then + this will be defined else "halt_q6", "halt_modem", + "halt_nc" is required. +- interrupts: The modem watchdog interrupt +- vdd_cx-supply: Reference to the regulator that supplies the vdd_cx domain. +- vdd_cx-voltage: Voltage corner/level(max) for cx rail. +- vdd_mx-supply: Reference to the regulator that supplies the memory rail. +- vdd_mx-uV: Voltage setting for the mx rail. +- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp" + +Optional properties: +- vdd_mss-supply: Reference to the regulator that supplies the processor. + This may be a shared regulator that is already voted + on in the PIL proxy voting code (and also managed by the + modem on its own), hence we mark it as as optional. +- vdd_pll-supply: Reference to the regulator that supplies the PLL's rail. +- qcom,vdd_pll: Voltage to be set for the PLL's rail. +- reg-names: "cxrail_bhs_reg" - control register for modem power + domain. +- clocks: Array of listing + all the clocks that are accesed by this subsystem. +- qcom,proxy-clock-names: Names of the clocks that need to be turned on/off during + proxy voting/unvoting. +- qcom,active-clock-names: Names of the clocks that need to be turned on for the + subsystem to run. Turned off when the subsystem is shutdown. +- clock-names: Names of all the clocks that are accessed by the subsystem. +- qcom,is-not-loadable: Boolean- Present if the image does not need to + be loaded. +- qcom,pil-self-auth: Boolean- True if authentication is required. +- qcom,mem-protect-id: Virtual ID used by PIL to call into TZ/HYP to protect/unprotect + subsystem related memory. +- qcom,gpio-err-fatal: GPIO used by the modem to indicate error fatal to the apps. +- qcom,gpio-err-ready: GPIO used by the modem to indicate error ready to the apps. +- qcom,gpio-proxy-unvote: GPIO used by the modem to trigger proxy unvoting in + the apps. +- qcom,gpio-force-stop: GPIO used by the apps to force the modem to shutdown. +- qcom,gpio-stop-ack: GPIO used by the modem to ack force stop or a graceful stop + to the apps. +- qcom,gpio-ramdump-disable: GPIO used by the modem to inform the apps that ramdump + collection should be disabled. +- qcom,gpio-shutdown-ack: GPIO used by the modem to indicate that it has done the + necessary cleanup and that the apps can move forward with + the shutdown sequence. +- qcom,restart-group: List of subsystems that will need to restart together. +- qcom,mba-image-is-not-elf: Boolean- Present if MBA image doesn't use the ELF + format. +- qcom,ssctl-instance-id: Instance id used by the subsystem to connect with the SSCTL + service. +- qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem. +- qcom,override-acc: Boolean- Present if we need to override the default ACC settings +- qcom,ahb-clk-vote: Boolean- Present if we need to remove the vote for the mss_cfg_ahb + clock after the modem boots up +- qcom,pnoc-clk-vote: Boolean- Present if the modem needs the PNOC bus to be + clocked before it boots up +- qcom,qdsp6v56-1-3: Boolean- Present if the qdsp version is v56 1.3 +- qcom,qdsp6v56-1-5: Boolean- Present if the qdsp version is v56 1.5 +- qcom,edge: GLINK logical name of the remote subsystem +- qcom,pil-force-shutdown: Boolean. If set, the SSR framework will not trigger graceful shutdown + on behalf of the subsystem driver. +- qcom,pil-mss-memsetup: Boolean - True if TZ need to be informed of modem start address and size. +- qcom,pas-id: pas_id of the subsystem. +- qcom,qdsp6v56-1-8: Boolean- Present if the qdsp version is v56 1.8 +- qcom,qdsp6v56-1-8-inrush-current: Boolean- Present if the qdsp version is V56 1.8 and has in-rush + current issue. +- qcom,qdsp6v61-1-1: Boolean- Present if the qdsp version is v61 1.1 +- qcom,qdsp6v62-1-2: Boolean- Present if the qdsp version is v62 1.2 +- qcom,qdsp6v62-1-4: Boolean- Present if the qdsp version is v62 1.4 +- qcom,qdsp6v62-1-5: Boolean- Present if the qdsp version is v62 1.5 +- qcom,mx-spike-wa: Boolean- Present if we need to assert QDSP6 I/O clamp, memory + wordline clamp, and compiler memory clamp during MSS restart. +- qcom,qdsp6v56-1-10: Boolean- Present if the qdsp version is v56 1.10 +- qcom,override-acc-1: Override the default ACC settings with this value if present. +- qcom,minidump-id: Unique id for each subsystem +- qcom,reset-clk: Enable clock after MSS restart + +One child node to represent the MBA image may be specified, when the MBA image +needs to be loaded in a specifically carved out memory region. + +Required properties: +- compatible: Must be "qcom,pil-mba-mem" +- memory-region: A phandle that points to a reserved memory where the MBA image will be loaded. + +Example: + qcom,mss@fc880000 { + compatible = "qcom,pil-q6v5-mss"; + reg = <0xfc880000 0x100>, + <0xfd485000 0x400>, + <0xfc820000 0x020>, + <0xfc401680 0x004>; + reg-names = "qdsp6_base", "halt_base", "rmb_base", + "restart_reg"; + interrupts = <0 24 1>; + vdd_mss-supply = <&pm8841_s3>; + vdd_cx-supply = <&pm8841_s2>; + vdd_cx-voltage = <7>; + vdd_mx-supply = <&pm8841_s1>; + vdd_mx-uV = <105000>; + + clocks = <&clock_rpm clk_xo_pil_mss_clk>, + <&clock_gcc clk_gcc_mss_cfg_ahb_clk>, + <&clock_gcc clk_gcc_mss_q6_bimc_axi_clk>, + <&clock_gcc clk_gcc_boot_rom_ahb_clk>; + clock-names = "xo", "iface_clk", "bus_clk", "mem_clk"; + qcom,proxy-clock-names = "xo"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk"; + + qcom,is-not-loadable; + qcom,firmware-name = "mba"; + qcom,pil-self-auth; + qcom,mba-image-is-not-elf; + qcom,override-acc; + + /* GPIO inputs from mss */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>; + + /* GPIO output to mss */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + qcom,ssctl-instance-id = <12>; + qcom,sysmon-id = <0>; + + qcom,mba-mem@0 { + compatible = "qcom,pil-mba-mem"; + memory-region = <&peripheral_mem>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pil/subsys-pil-tz.txt b/arch/arm64/boot/dts/vendor/bindings/pil/subsys-pil-tz.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b207f49bd5c8ee84f1a3bbbfd81dea28116f3a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pil/subsys-pil-tz.txt @@ -0,0 +1,163 @@ +* Generic Subsystem Peripheral Image Loader + +subsys-pil-tz is a generic peripheral image loader (PIL) driver. It is +used for loading the firmware images of the subsystems into memory and +preparing the subsystem's processor to execute code. It's also responsible +for shutting down the processor when it's not needed. + +Required properties: +- compatible: Must be "qcom,pil-tz-generic" +- qcom,firmware-name: Base name of the firmware image. + +Optional properties: +- reg: Pairs of physical base addresses and region sizes of + memory mapped registers. +- reg-names: Names of the bases for the above registers. Not required for + PIL usage. Ex. "wrapper_base", "vbif_base". +- interrupts: Subsystem to Apps watchdog bite interrupt. +- vdd_'reg'-supply: Reference to the regulator that supplies the corresponding + 'reg' domain. +- qcom,proxy-reg-names: Names of the regulators that need to be turned on/off + during proxy voting/unvoting. +- qcom,active-reg-names: Names of the regulators that need to be turned on for the + subsystem to run. Turned off when the subsystem is shutdown. +- qcom,vdd_'reg'-uV-uA: Voltage and current values for the 'reg' regulator. +- qcom,proxy-clock-names: Names of the clocks that need to be turned on/off during + proxy voting/unvoting. +- qcom,active-clock-names: Names of the clocks that need to be turned on for the + subsystem to run. Turned off when the subsystem is shutdown. +- clock-names: Names of all the clocks that are accessed by the subsystem. +- qcom,-freq: Frequency to be set for that clock in Hz. If the property + isn't added for a clock, then the default clock frequency + would be set to 19200000 Hz. +- qcom,msm-bus,name: Name of the bus client for the subsystem. +- qcom,msm-bus,num-cases: Number of use-cases. +- qcom,msm-bus,num-paths: Number of paths. +- qcom,msm-bus,active-only: If not set, uses the dual context by default. +- qcom,msm-bus,vectors-KBps: Vector array of master id, slave id, arbitrated + bandwidth and instantaneous bandwidth. +- qcom,pas-id: pas_id of the subsystem. +- qcom,proxy-timeout-ms: Proxy vote timeout value for the subsystem. +- qcom,smem-id: ID of the SMEM item for the subsystem. +- qcom,is-not-loadable: Boolean. Present if the subsystem's firmware image does not + need to be loaded. +- qcom,pil-no-auth: Boolean. Present if the subsystem is not authenticated and brought + out of reset by using the PIL ops. +- qcom,mem-protect-id: Virtual ID used by PIL to call into TZ/HYP to protect/unprotect + subsystem related memory. +- qcom,gpio-err-fatal: GPIO used by the subsystem to indicate error fatal to the apps. +- qcom,gpio-err-ready: GPIO used by the subsystem to indicate error ready to the apps. +- qcom,gpio-proxy-unvote: GPIO used by the subsystem to trigger proxy unvoting in + the apps. +- qcom,gpio-force-stop: GPIO used by the apps to force the subsystem to shutdown. +- qcom,gpio-stop-ack: GPIO used by the subsystem to ack force stop or a graceful stop + to the apps. +- qcom,restart-group: List of subsystems that will need to restart together. +- qcom,keep-proxy-regs-on: Boolean. Present if during proxy unvoting, PIL needs to leave + the regulators enabled after removing the voltage/current votes. +- qcom,edge: GLINK logical name of the remote subsystem +- qcom,ssctl-instance-id: Instance id used by the subsystem to connect with the SSCTL + service. +- qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem. +- qcom,pil-force-shutdown: Boolean. If set, the SSR framework will not trigger graceful shutdown + on behalf of the subsystem driver. +- qcom,pil-generic-irq-handler: generic interrupt handler used for communication with subsytem + based on bit values in scsr registers. +- qcom,spss-scsr-bits: array of bit positions into the scsr registers used in generic handler. +- qcom,complete-ramdump: Boolean. If set, complete ramdump i.e. region between start address of + first segment to end address of last segment will be collected without + leaving any hole in between. +- qcom,ignore-ssr-failure: Boolean. If set, SSR failures are not considered fatal. +- qcom,signal-aop: Boolean. If set, when subsystem is brought up, pil will send a notification + to AOP through qmp mailbox driver. +- qcom,minidump-id: ID that is used to index into the global minidump table of + contents to access a subsystem's minidump table of + contents. +- qcom,aux-minidump-ids: List of IDs that index into the global minidump table + of contents to access the table of contents for + additional minidump entries that should be collected + along with the subsystem's minidump. +- qcom,pon-depends-on: String that indicates the name of the subsystem that has + to be powered-on before this subsystem is powered-on. + If the dependednt subsystem is already powered-on, + regardless of the fact that it's requested to power-on + explicitly, the framework won't try to power it back up again. + +- qcom,poff-depends-on: String that indicates the name of the subsystem that has + to be powered-off before this subsystem is powered-off. + If the dependednt subsystem is already powered-off, + regardless of the fact that it's requested to power-off + explicitly, the framework won't try to power it off again. + +- qcom,minidump-as-elf32: Boolean. If set, minidump is collected in ELF32 format. + +- qcom,mas-crypto: phandle to the bus master of crypto core. + +Example: + qcom,venus@fdce0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xfdce0000 0x4000>, + <0xfdc80000 0x400>; + + vdd-supply = <&gdsc_venus>; + qcom,proxy-reg-names = "vdd"; + clock-names = "core_clk", "iface_clk", "bus_clk", "mem_clk", + "scm_core_clk", "scm_iface_clk", "scm_bus_clk", + "scm_core_clk_src"; + qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk", + "mem_clk", "scm_core_clk", + "scm_iface_clk", "scm_bus_clk", + "scm_core_clk_src"; + qcom,scm_core_clk_src-freq = <50000000>; + + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only = <0>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + + qcom,pas-id = <9>; + qcom,proxy-timeout-ms = <2000>; + qcom,firmware-name = "venus"; + }; + + qcom,lpass@fe200000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xfe200000 0x00100>, + <0xfd485100 0x00010>, + <0xfc4016c0 0x00004>; + + interrupts = <0 162 1>; + + vdd_cx-supply = <&pm8841_s2_corner>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = <7 100000>; + clock-names = "bus_clk", "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,active-clock-names = "bus_clk"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,scm_core_clk_src-freq = <50000000>; + + qcom,smem-id = <423>; + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,firmware-name = "adsp"; + qcom,edge = "lpass"; + + /* GPIO inputs from lpass */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>; + + /* GPIO output to lpass */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>; + qcom,ssctl-instance-id = <14>; + qcom,sysmon-id = <1>; + + /* Power-off venus before LPASS */ + qcom,poff-depends-on = "venus"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/abilis,tb10x-iomux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/abilis,tb10x-iomux.txt new file mode 100644 index 0000000000000000000000000000000000000000..c591b9cb5ba0161024a377ceb50e9a9be0f0634a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/abilis,tb10x-iomux.txt @@ -0,0 +1,80 @@ +Abilis Systems TB10x pin controller +=================================== + +Required properties +------------------- + +- compatible: should be "abilis,tb10x-iomux"; +- reg: should contain the physical address and size of the pin controller's + register range. + + +Function definitions +-------------------- + +Functions are defined (and referenced) by sub-nodes of the pin controller. +Every sub-node defines exactly one function (implying a set of pins). +Every function is associated to one named pin group inside the pin controller +driver and these names are used to associate pin group predefinitions to pin +controller sub-nodes. + +Required function definition subnode properties: + - abilis,function: should be set to the name of the function's pin group. + +The following pin groups are available: + - GPIO ports: gpioa, gpiob, gpioc, gpiod, gpioe, gpiof, gpiog, + gpioh, gpioi, gpioj, gpiok, gpiol, gpiom, gpion + - Serial TS input ports: mis0, mis1, mis2, mis3, mis4, mis5, mis6, mis7 + - Parallel TS input ports: mip1, mip3, mip5, mip7 + - Serial TS output ports: mos0, mos1, mos2, mos3 + - Parallel TS output port: mop + - CI+ port: ciplus + - CableCard (Mcard) port: mcard + - Smart card ports: stc0, stc1 + - UART ports: uart0, uart1 + - SPI ports: spi1, spi3 + - JTAG: jtag + +All other ports of the chip are not multiplexed and thus not managed by this +driver. + + +GPIO ranges definition +---------------------- + +The named pin groups of GPIO ports can be used to define GPIO ranges as +explained in Documentation/devicetree/bindings/gpio/gpio.txt. + + +Example +------- + +iomux: iomux@ff10601c { + compatible = "abilis,tb10x-iomux"; + reg = <0xFF10601c 0x4>; + pctl_gpio_a: pctl-gpio-a { + abilis,function = "gpioa"; + }; + pctl_uart0: pctl-uart0 { + abilis,function = "uart0"; + }; +}; +uart@ff100000 { + compatible = "snps,dw-apb-uart"; + reg = <0xFF100000 0x100>; + clock-frequency = <166666666>; + interrupts = <25 1>; + reg-shift = <2>; + reg-io-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pctl_uart0>; +}; +gpioa: gpio@ff140000 { + compatible = "abilis,tb10x-gpio"; + reg = <0xFF140000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + ngpio = <3>; + gpio-ranges = <&iomux 0 0>; + gpio-ranges-group-names = "gpioa"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/actions,s900-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/actions,s900-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..81b58dddd3edcbc2748950ed8d1435ce0573190a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/actions,s900-pinctrl.txt @@ -0,0 +1,204 @@ +Actions Semi S900 Pin Controller + +This binding describes the pin controller found in the S900 SoC. + +Required Properties: + +- compatible: Should be "actions,s900-pinctrl" +- reg: Should contain the register base address and size of + the pin controller. +- clocks: phandle of the clock feeding the pin controller +- gpio-controller: Marks the device node as a GPIO controller. +- gpio-ranges: Specifies the mapping between gpio controller and + pin-controller pins. +- #gpio-cells: Should be two. The first cell is the gpio pin number + and the second cell is used for optional parameters. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt. Shall be set to 2. The first cell + defines the interrupt number, the second encodes + the trigger flags described in + bindings/interrupt-controller/interrupts.txt +- interrupts: The interrupt outputs from the controller. There is one GPIO + interrupt per GPIO bank. The number of interrupts listed depends + on the number of GPIO banks on the SoC. The interrupts must be + ordered by bank, starting with bank 0. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +Pinmux functions are available only for the pin groups while pinconf +parameters are available for both pin groups and individual pins. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +Required Properties: + +- pins: An array of strings, each string containing the name of a pin. + These pins are used for selecting the pull control and schmitt + trigger parameters. The following are the list of pins + available: + + eth_txd0, eth_txd1, eth_txen, eth_rxer, eth_crs_dv, + eth_rxd1, eth_rxd0, eth_ref_clk, eth_mdc, eth_mdio, + sirq0, sirq1, sirq2, i2s_d0, i2s_bclk0, i2s_lrclk0, + i2s_mclk0, i2s_d1, i2s_bclk1, i2s_lrclk1, i2s_mclk1, + pcm1_in, pcm1_clk, pcm1_sync, pcm1_out, eram_a5, + eram_a6, eram_a7, eram_a8, eram_a9, eram_a10, eram_a11, + lvds_oep, lvds_oen, lvds_odp, lvds_odn, lvds_ocp, + lvds_ocn, lvds_obp, lvds_obn, lvds_oap, lvds_oan, + lvds_eep, lvds_een, lvds_edp, lvds_edn, lvds_ecp, + lvds_ecn, lvds_ebp, lvds_ebn, lvds_eap, lvds_ean, + sd0_d0, sd0_d1, sd0_d2, sd0_d3, sd1_d0, sd1_d1, + sd1_d2, sd1_d3, sd0_cmd, sd0_clk, sd1_cmd, sd1_clk, + spi0_sclk, spi0_ss, spi0_miso, spi0_mosi, uart0_rx, + uart0_tx, uart2_rx, uart2_tx, uart2_rtsb, uart2_ctsb, + uart3_rx, uart3_tx, uart3_rtsb, uart3_ctsb, uart4_rx, + uart4_tx, i2c0_sclk, i2c0_sdata, i2c1_sclk, i2c1_sdata, + i2c2_sclk, i2c2_sdata, csi0_dn0, csi0_dp0, csi0_dn1, + csi0_dp1, csi0_cn, csi0_cp, csi0_dn2, csi0_dp2, csi0_dn3, + csi0_dp3, dsi_dp3, dsi_dn3, dsi_dp1, dsi_dn1, dsi_cp, + dsi_cn, dsi_dp0, dsi_dn0, dsi_dp2, dsi_dn2, sensor0_pclk, + csi1_dn0,csi1_dp0,csi1_dn1, csi1_dp1, csi1_cn, csi1_cp, + sensor0_ckout, nand0_d0, nand0_d1, nand0_d2, nand0_d3, + nand0_d4, nand0_d5, nand0_d6, nand0_d7, nand0_dqs, + nand0_dqsn, nand0_ale, nand0_cle, nand0_ceb0, nand0_ceb1, + nand0_ceb2, nand0_ceb3, nand1_d0, nand1_d1, nand1_d2, + nand1_d3, nand1_d4, nand1_d5, nand1_d6, nand1_d7, nand1_dqs, + nand1_dqsn, nand1_ale, nand1_cle, nand1_ceb0, nand1_ceb1, + nand1_ceb2, nand1_ceb3, sgpio0, sgpio1, sgpio2, sgpio3 + +- groups: An array of strings, each string containing the name of a pin + group. These pin groups are used for selecting the pinmux + functions. + + lvds_oxx_uart4_mfp, rmii_mdc_mfp, rmii_mdio_mfp, sirq0_mfp, + sirq1_mfp, rmii_txd0_mfp, rmii_txd1_mfp, rmii_txen_mfp, + rmii_rxer_mfp, rmii_crs_dv_mfp, rmii_rxd1_mfp, rmii_rxd0_mfp, + rmii_ref_clk_mfp, i2s_d0_mfp, i2s_d1_mfp, i2s_lr_m_clk0_mfp, + i2s_bclk0_mfp, i2s_bclk1_mclk1_mfp, pcm1_in_out_mfp, + pcm1_clk_mfp, pcm1_sync_mfp, eram_a5_mfp, eram_a6_mfp, + eram_a7_mfp, eram_a8_mfp, eram_a9_mfp, eram_a10_mfp, + eram_a11_mfp, lvds_oep_odn_mfp, lvds_ocp_obn_mfp, + lvds_oap_oan_mfp, lvds_e_mfp, spi0_sclk_mosi_mfp, spi0_ss_mfp, + spi0_miso_mfp, uart2_rtsb_mfp, uart2_ctsb_mfp, uart3_rtsb_mfp, + uart3_ctsb_mfp, sd0_d0_mfp, sd0_d1_mfp, sd0_d2_d3_mfp, + sd1_d0_d3_mfp, sd0_cmd_mfp, sd0_clk_mfp, sd1_cmd_clk_mfp, + uart0_rx_mfp, nand0_d0_ceb3_mfp, uart0_tx_mfp, i2c0_mfp, + csi0_cn_cp_mfp, csi0_dn0_dp3_mfp, csi1_dn0_cp_mfp, + dsi_dp3_dn1_mfp, dsi_cp_dn0_mfp, dsi_dp2_dn2_mfp, + nand1_d0_ceb1_mfp, nand1_ceb3_mfp, nand1_ceb0_mfp, + csi1_dn0_dp0_mfp, uart4_rx_tx_mfp + + + These pin groups are used for selecting the drive strength + parameters. + + sgpio3_drv, sgpio2_drv, sgpio1_drv, sgpio0_drv, + rmii_tx_d0_d1_drv, rmii_txen_rxer_drv, rmii_crs_dv_drv, + rmii_rx_d1_d0_drv, rmii_ref_clk_drv, rmii_mdc_mdio_drv, + sirq_0_1_drv, sirq2_drv, i2s_d0_d1_drv, i2s_lr_m_clk0_drv, + i2s_blk1_mclk1_drv, pcm1_in_out_drv, lvds_oap_oan_drv, + lvds_oep_odn_drv, lvds_ocp_obn_drv, lvds_e_drv, sd0_d3_d0_drv, + sd1_d3_d0_drv, sd0_sd1_cmd_clk_drv, spi0_sclk_mosi_drv, + spi0_ss_miso_drv, uart0_rx_tx_drv, uart4_rx_tx_drv, uart2_drv, + uart3_drv, i2c0_drv, i2c1_drv, i2c2_drv, sensor0_drv + + These pin groups are used for selecting the slew rate + parameters. + + sgpio3_sr, sgpio2_sr, sgpio1_sr, sgpio0_sr, rmii_tx_d0_d1_sr, + rmii_txen_rxer_sr, rmii_crs_dv_sr, rmii_rx_d1_d0_sr, + rmii_ref_clk_sr, rmii_mdc_mdio_sr, sirq_0_1_sr, sirq2_sr, + i2s_do_d1_sr, i2s_lr_m_clk0_sr, i2s_bclk0_mclk1_sr, + pcm1_in_out_sr, sd1_d3_d0_sr, sd0_sd1_clk_cmd_sr, + spi0_sclk_mosi_sr, spi0_ss_miso_sr, uart0_rx_tx_sr, + uart4_rx_tx_sr, uart2_sr, uart3_sr, i2c0_sr, i2c1_sr, i2c2_sr, + sensor0_sr + +- function: An array of strings, each string containing the name of the + pinmux functions. These functions can only be selected by + the corresponding pin groups. The following are the list of + pinmux functions available: + + eram, eth_rmii, eth_smii, spi0, spi1, spi2, spi3, sens0, + uart0, uart1, uart2, uart3, uart4, uart5, uart6, i2s0, i2s1, + pcm0, pcm1, jtag, pwm0, pwm1, pwm2, pwm3, pwm4, pwm5, sd0, + sd1, sd2, sd3, i2c0, i2c1, i2c2, i2c3, i2c4, i2c5, lvds, + usb30, usb20, gpu, mipi_csi0, mipi_csi1, mipi_dsi, nand0, + nand1, spdif, sirq0, sirq1, sirq2 + +Optional Properties: + +- bias-bus-hold: No arguments. The specified pins should retain the previous + state value. +- bias-high-impedance: No arguments. The specified pins should be configured + as high impedance. +- bias-pull-down: No arguments. The specified pins should be configured as + pull down. +- bias-pull-up: No arguments. The specified pins should be configured as + pull up. +- input-schmitt-enable: No arguments: Enable schmitt trigger for the specified + pins +- input-schmitt-disable: No arguments: Disable schmitt trigger for the specified + pins +- slew-rate: Integer. Sets slew rate for the specified pins. + Valid values are: + <0> - Slow + <1> - Fast +- drive-strength: Integer. Selects the drive strength for the specified + pins in mA. + Valid values are: + <2> + <4> + <8> + <12> + +Example: + + pinctrl: pinctrl@e01b0000 { + compatible = "actions,s900-pinctrl"; + reg = <0x0 0xe01b0000 0x0 0x1000>; + clocks = <&cmu CLK_GPIO>; + gpio-controller; + gpio-ranges = <&pinctrl 0 0 146>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + , + , + , + ; + + uart2-default: uart2-default { + pinmux { + groups = "lvds_oep_odn_mfp"; + function = "uart2"; + }; + pinconf { + groups = "lvds_oep_odn_drv"; + drive-strength = <12>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/allwinner,sunxi-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..258a4648ab813304b9008daf7572c32ee7b973ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/allwinner,sunxi-pinctrl.txt @@ -0,0 +1,148 @@ +* Allwinner A1X Pin Controller + +The pins controlled by sunXi pin controller are organized in banks, +each bank has 32 pins. Each pin has 7 multiplexing functions, with +the first two functions being GPIO in and out. The configuration on +the pins includes drive strength and pull-up. + +Required properties: +- compatible: Should be one of the following (depending on your SoC): + "allwinner,sun4i-a10-pinctrl" + "allwinner,sun5i-a10s-pinctrl" + "allwinner,sun5i-a13-pinctrl" + "allwinner,sun6i-a31-pinctrl" + "allwinner,sun6i-a31s-pinctrl" + "allwinner,sun6i-a31-r-pinctrl" + "allwinner,sun7i-a20-pinctrl" + "allwinner,sun8i-a23-pinctrl" + "allwinner,sun8i-a23-r-pinctrl" + "allwinner,sun8i-a33-pinctrl" + "allwinner,sun9i-a80-pinctrl" + "allwinner,sun9i-a80-r-pinctrl" + "allwinner,sun8i-a83t-pinctrl" + "allwinner,sun8i-a83t-r-pinctrl" + "allwinner,sun8i-h3-pinctrl" + "allwinner,sun8i-h3-r-pinctrl" + "allwinner,sun8i-r40-pinctrl" + "allwinner,sun50i-a64-pinctrl" + "allwinner,sun50i-a64-r-pinctrl" + "allwinner,sun50i-h5-pinctrl" + "allwinner,sun50i-h6-pinctrl" + "allwinner,sun50i-h6-r-pinctrl" + "nextthing,gr8-pinctrl" + +- reg: Should contain the register physical address and length for the + pin controller. + +- clocks: phandle to the clocks feeding the pin controller: + - "apb": the gated APB parent clock + - "hosc": the high frequency oscillator in the system + - "losc": the low frequency oscillator in the system + +Note: For backward compatibility reasons, the hosc and losc clocks are only +required if you need to use the optional input-debounce property. Any new +device tree should set them. + +Optional properties: + - input-debounce: Array of debouncing periods in microseconds. One period per + irq bank found in the controller. 0 if no setup required. + + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +A pinctrl node should contain at least one subnodes representing the +pinctrl groups available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, drive strength and pullups. If one of these options is +not set, its actual value will be unspecified. + +Allwinner A1X Pin Controller supports the generic pin multiplexing and +configuration bindings. For details on each properties, you can refer to + ./pinctrl-bindings.txt. + +Required sub-node properties: + - pins + - function + +Optional sub-node properties: + - bias-disable + - bias-pull-up + - bias-pull-down + - drive-strength + +*** Deprecated pin configuration and multiplexing binding + +Required subnode-properties: + +- allwinner,pins: List of strings containing the pin name. +- allwinner,function: Function to mux the pins listed above to. + +Optional subnode-properties: +- allwinner,drive: Integer. Represents the current sent to the pin + 0: 10 mA + 1: 20 mA + 2: 30 mA + 3: 40 mA +- allwinner,pull: Integer. + 0: No resistor + 1: Pull-up resistor + 2: Pull-down resistor + +Examples: + +pio: pinctrl@1c20800 { + compatible = "allwinner,sun5i-a13-pinctrl"; + reg = <0x01c20800 0x400>; + #address-cells = <1>; + #size-cells = <0>; + + uart1_pins_a: uart1@0 { + allwinner,pins = "PE10", "PE11"; + allwinner,function = "uart1"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + uart1_pins_b: uart1@1 { + allwinner,pins = "PG3", "PG4"; + allwinner,function = "uart1"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; +}; + + +GPIO and interrupt controller +----------------------------- + +This hardware also acts as a GPIO controller and an interrupt +controller. + +Consumers that would want to refer to one or the other (or both) +should provide through the usual *-gpios and interrupts properties a +cell with 3 arguments, first the number of the bank, then the pin +inside that bank, and finally the flags for the GPIO/interrupts. + +Example: + +xio: gpio@38 { + compatible = "nxp,pcf8574a"; + reg = <0x38>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-parent = <&pio>; + interrupts = <6 0 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +reg_usb1_vbus: usb1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb1-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&pio 7 6 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/atmel,at91-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/atmel,at91-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e23fece99dabda20f18e649b708702524e02454 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/atmel,at91-pinctrl.txt @@ -0,0 +1,151 @@ +* Atmel AT91 Pinmux Controller + +The AT91 Pinmux Controller, enables the IC +to share one PAD to several functional blocks. The sharing is done by +multiplexing the PAD input/output signals. For each PAD there are up to +8 muxing options (called periph modes). Since different modules require +different PAD settings (like pull up, keeper, etc) the controller controls +also the PAD settings parameters. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Atmel AT91 pin configuration node is a node of a group of pins which can be +used for a specific device or function. This node represents both mux and config +of the pins in that group. The 'pins' selects the function mode(also named pin +mode) this pin can work on and the 'config' configures various pad settings +such as pull-up, multi drive, etc. + +Required properties for iomux controller: +- compatible: "atmel,at91rm9200-pinctrl" or "atmel,at91sam9x5-pinctrl" + or "atmel,sama5d3-pinctrl" +- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be + configured in this periph mode. All the periph and bank need to be describe. + +How to create such array: + +Each column will represent the possible peripheral of the pinctrl +Each line will represent a pio bank + +Take an example on the 9260 +Peripheral: 2 ( A and B) +Bank: 3 (A, B and C) +=> + + /* A B */ + 0xffffffff 0xffc00c3b /* pioA */ + 0xffffffff 0x7fff3ccf /* pioB */ + 0xffffffff 0x007fffff /* pioC */ + +For each peripheral/bank we will descibe in a u32 if a pin can be +configured in it by putting 1 to the pin bit (1 << pin) + +Let's take the pioA on peripheral B +From the datasheet Table 10-2. +Peripheral B +PA0 MCDB0 +PA1 MCCDB +PA2 +PA3 MCDB3 +PA4 MCDB2 +PA5 MCDB1 +PA6 +PA7 +PA8 +PA9 +PA10 ETX2 +PA11 ETX3 +PA12 +PA13 +PA14 +PA15 +PA16 +PA17 +PA18 +PA19 +PA20 +PA21 +PA22 ETXER +PA23 ETX2 +PA24 ETX3 +PA25 ERX2 +PA26 ERX3 +PA27 ERXCK +PA28 ECRS +PA29 ECOL +PA30 RXD4 +PA31 TXD4 + +=> 0xffc00c3b + +Required properties for pin configuration node: +- atmel,pins: 4 integers array, represents a group of pins mux and config + setting. The format is atmel,pins = . + The PERIPH 0 means gpio, PERIPH 1 is periph A, PERIPH 2 is periph B... + PIN_BANK 0 is pioA, PIN_BANK 1 is pioB... + +Bits used for CONFIG: +PULL_UP (1 << 0): indicate this pin needs a pull up. +MULTIDRIVE (1 << 1): indicate this pin needs to be configured as multi-drive. + Multi-drive is equivalent to open-drain type output. +DEGLITCH (1 << 2): indicate this pin needs deglitch. +PULL_DOWN (1 << 3): indicate this pin needs a pull down. +DIS_SCHMIT (1 << 4): indicate this pin needs to the disable schmitt trigger. +DRIVE_STRENGTH (3 << 5): indicate the drive strength of the pin using the + following values: + 00 - No change (reset state value kept) + 01 - Low + 10 - Medium + 11 - High +OUTPUT (1 << 7): indicate this pin need to be configured as an output. +OUTPUT_VAL (1 << 8): output val (1 = high, 0 = low) +DEBOUNCE (1 << 16): indicate this pin needs debounce. +DEBOUNCE_VAL (0x3fff << 17): debounce value. + +NOTE: +Some requirements for using atmel,at91rm9200-pinctrl binding: +1. We have pin function node defined under at91 controller node to represent + what pinmux functions this SoC supports. +2. The driver can use the function node's name and pin configuration node's + name describe the pin function and group hierarchy. + For example, Linux at91 pinctrl driver takes the function node's name + as the function name and pin configuration node's name as group name to + create the map table. +3. Each pin configuration node should have a phandle, devices can set pins + configurations by referring to the phandle of that pin configuration node. +4. The gpio controller must be describe in the pinctrl simple-bus. + +Examples: + +pinctrl@fffff400 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "atmel,at91rm9200-pinctrl", "simple-bus"; + reg = <0xfffff400 0x600>; + + atmel,mux-mask = < + /* A B */ + 0xffffffff 0xffc00c3b /* pioA */ + 0xffffffff 0x7fff3ccf /* pioB */ + 0xffffffff 0x007fffff /* pioC */ + >; + + /* shared pinctrl settings */ + dbgu { + pinctrl_dbgu: dbgu-0 { + atmel,pins = + <1 14 0x1 0x0 /* PB14 periph A */ + 1 15 0x1 0x1>; /* PB15 periph A with pullup */ + }; + }; +}; + +dbgu: serial@fffff200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfffff200 0x200>; + interrupts = <1 4 7>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dbgu>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/atmel,at91-pio4-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/atmel,at91-pio4-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..04d16fb69eb7c5d260a908be0bc750eeeee3fe7a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/atmel,at91-pio4-pinctrl.txt @@ -0,0 +1,93 @@ +* Atmel PIO4 Controller + +The Atmel PIO4 controller is used to select the function of a pin and to +configure it. + +Required properties: +- compatible: "atmel,sama5d2-pinctrl". +- reg: base address and length of the PIO controller. +- interrupts: interrupt outputs from the controller, one for each bank. +- interrupt-controller: mark the device node as an interrupt controller. +- #interrupt-cells: should be two. +- gpio-controller: mark the device node as a gpio controller. +- #gpio-cells: should be two. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +Subnode format +Each node (or subnode) will list the pins it needs and how to configured these +pins. + + node { + pinmux = ; + GENERIC_PINCONFIG; + }; + +Required properties: +- pinmux: integer array. Each integer represents a pin number plus mux and +ioset settings. Use the macros from boot/dts/-pinfunc.h file to get the +right representation of the pin. + +Optional properties: +- GENERIC_PINCONFIG: generic pinconfig options to use, bias-disable, +bias-pull-down, bias-pull-up, drive-open-drain, input-schmitt-enable, +input-debounce, output-low, output-high. +- atmel,drive-strength: 0 or 1 for low drive, 2 for medium drive and 3 for +high drive. The default value is low drive. + +Example: + +#include + +... +{ + pioA: pinctrl@fc038000 { + compatible = "atmel,sama5d2-pinctrl"; + reg = <0xfc038000 0x600>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH 7>, + <68 IRQ_TYPE_LEVEL_HIGH 7>, + <69 IRQ_TYPE_LEVEL_HIGH 7>, + <70 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pioA_clk>; + + pinctrl_i2c0_default: i2c0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_led_gpio_default: led_gpio_default { + pinmux = , + ; + bias-pull-up; + atmel,drive-strength = ; + }; + + pinctrl_sdmmc1_default: sdmmc1_default { + cmd_data { + pinmux = , + , + , + , + ; + bias-pull-up; + }; + + ck_cd { + pinmux = , + ; + bias-disable; + }; + }; + ... + }; +}; +... diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/axis,artpec6-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/axis,artpec6-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..678f5097058ee99892429a774046c3df23338b4f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/axis,artpec6-pinctrl.txt @@ -0,0 +1,87 @@ +Axis ARTPEC-6 Pin Controller + +Required properties: +- compatible: "axis,artpec6-pinctrl". +- reg: Should contain the register physical address and length for the pin + controller. + +A pinctrl node should contain at least one subnode representing the pinctrl +groups available on the machine. Each subnode will list the mux function +required and what pin group it will use. Each subnode will also configure the +drive strength and bias pullup of the pin group. If either of these options is +not set, its actual value will be unspecified. + + +Required subnode-properties: +- function: Function to mux. +- groups: Name of the pin group to use for the function above. + + Available functions and groups (function: group0, group1...): + gpio: cpuclkoutgrp0, udlclkoutgrp0, i2c1grp0, i2c2grp0, + i2c3grp0, i2s0grp0, i2s1grp0, i2srefclkgrp0, spi0grp0, + spi1grp0, pciedebuggrp0, uart0grp0, uart0grp1, uart0grp2, + uart1grp0, uart1grp1, uart2grp0, uart2grp1, uart2grp2, + uart3grp0, uart4grp0, uart4grp1, uart5grp0, uart5grp1, + uart5nocts + cpuclkout: cpuclkoutgrp0 + udlclkout: udlclkoutgrp0 + i2c1: i2c1grp0 + i2c2: i2c2grp0 + i2c3: i2c3grp0 + i2s0: i2s0grp0 + i2s1: i2s1grp0 + i2srefclk: i2srefclkgrp0 + spi0: spi0grp0 + spi1: spi1grp0 + pciedebug: pciedebuggrp0 + uart0: uart0grp0, uart0grp1, uart0grp2 + uart1: uart1grp0, uart1grp1 + uart2: uart2grp0, uart2grp1, uart2grp2 + uart3: uart3grp0 + uart4: uart4grp0, uart4grp1 + uart5: uart5grp0, uart5grp1, uart5nocts + nand: nandgrp0 + sdio0: sdio0grp0 + sdio1: sdio1grp0 + ethernet: ethernetgrp0 + + +Optional subnode-properties (see pinctrl-bindings.txt): +- drive-strength: 4, 6, 8, 9 mA. For SD and NAND pins, this is for 3.3V VCCQ3. +- bias-pull-up +- bias-disable + +Examples: +pinctrl@f801d000 { + compatible = "axis,artpec6-pinctrl"; + reg = <0xf801d000 0x400>; + + pinctrl_uart0: uart0grp { + function = "uart0"; + groups = "uart0grp0"; + drive-strength = <4>; + bias-pull-up; + }; + pinctrl_uart3: uart3grp { + function = "uart3"; + groups = "uart3grp0"; + }; +}; +uart0: uart@f8036000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xf8036000 0x1000>; + interrupts = <0 104 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pll2div24>, <&apb_pclk>; + clock-names = "uart_clk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart0>; +}; +uart3: uart@f8039000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0xf8039000 0x1000>; + interrupts = <0 128 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&pll2div24>, <&apb_pclk>; + clock-names = "uart_clk", "apb_pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/berlin,pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/berlin,pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a2d5516e1f3988e969ac7f5f16d1aa22728e795 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/berlin,pinctrl.txt @@ -0,0 +1,47 @@ +* Pin-controller driver for the Marvell Berlin SoCs + +Pin control registers are part of both chip controller and system +controller register sets. Pin controller nodes should be a sub-node of +either the chip controller or system controller node. The pins +controlled are organized in groups, so no actual pin information is +needed. + +A pin-controller node should contain subnodes representing the pin group +configurations, one per function. Each subnode has the group name and +the muxing function used. + +Be aware the Marvell Berlin datasheets use the keyword 'mode' for what +is called a 'function' in the pin-controller subsystem. + +Required properties: +- compatible: should be one of: + "marvell,berlin2-soc-pinctrl", + "marvell,berlin2-system-pinctrl", + "marvell,berlin2cd-soc-pinctrl", + "marvell,berlin2cd-system-pinctrl", + "marvell,berlin2q-soc-pinctrl", + "marvell,berlin2q-system-pinctrl", + "marvell,berlin4ct-avio-pinctrl", + "marvell,berlin4ct-soc-pinctrl", + "marvell,berlin4ct-system-pinctrl", + "syna,as370-soc-pinctrl" + +Required subnode-properties: +- groups: a list of strings describing the group names. +- function: a string describing the function used to mux the groups. + +Example: + +sys_pinctrl: pin-controller { + compatible = "marvell,berlin2q-system-pinctrl"; + + uart0_pmux: uart0-pmux { + groups = "GSM12"; + function = "uart0"; + }; +}; + +&uart0 { + pinctrl-0 = <&uart0_pmux>; + pinctrl-names = "default"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,bcm11351-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,bcm11351-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..4eaae32821aead3fe29314c10eedea734d5ea736 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,bcm11351-pinctrl.txt @@ -0,0 +1,461 @@ +Broadcom BCM281xx Pin Controller + +This is a pin controller for the Broadcom BCM281xx SoC family, which includes +BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs. + +=== Pin Controller Node === + +Required Properties: + +- compatible: Must be "brcm,bcm11351-pinctrl" +- reg: Base address of the PAD Controller register block and the size + of the block. + +For example, the following is the bare minimum node: + + pinctrl@35004800 { + compatible = "brcm,bcm11351-pinctrl"; + reg = <0x35004800 0x430>; + }; + +As a pin controller device, in addition to the required properties, this node +should also contain the pin configuration nodes that client devices reference, +if any. + +=== Pin Configuration Node === + +Each pin configuration node is a sub-node of the pin controller node and is a +container of an arbitrary number of subnodes, called pin group nodes in this +document. + +Please refer to the pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the definition of a +"pin configuration node". + +=== Pin Group Node === + +A pin group node specifies the desired pin mux and/or pin configuration for an +arbitrary number of pins. The name of the pin group node is optional and not +used. + +A pin group node only affects the properties specified in the node, and has no +effect on any properties that are omitted. + +The pin group node accepts a subset of the generic pin config properties. For +details generic pin config properties, please refer to pinctrl-bindings.txt +and . + +Each pin controlled by this pin controller belong to one of three types: +Standard, I2C, and HDMI. Each type accepts a different set of pin config +properties. A list of pins and their types is provided below. + +Required Properties (applicable to all pins): + +- pins: Multiple strings. Specifies the name(s) of one or more pins to + be configured by this node. + +Optional Properties (for standard pins): + +- function: String. Specifies the pin mux selection. Values + must be one of: "alt1", "alt2", "alt3", "alt4" +- input-schmitt-enable: No arguments. Enable schmitt-trigger mode. +- input-schmitt-disable: No arguments. Disable schmitt-trigger mode. +- bias-pull-up: No arguments. Pull up on pin. +- bias-pull-down: No arguments. Pull down on pin. +- bias-disable: No arguments. Disable pin bias. +- slew-rate: Integer. Meaning depends on configured pin mux: + *_SCL or *_SDA: + 0: Standard(100kbps)& Fast(400kbps) mode + 1: Highspeed (3.4Mbps) mode + IC_DM or IC_DP: + 0: normal slew rate + 1: fast slew rate + Otherwise: + 0: fast slew rate + 1: normal slew rate +- input-enable: No arguments. Enable input (does not affect + output.) +- input-disable: No arguments. Disable input (does not affect + output.) +- drive-strength: Integer. Drive strength in mA. Valid values are + 2, 4, 6, 8, 10, 12, 14, 16 mA. + +Optional Properties (for I2C pins): + +- function: String. Specifies the pin mux selection. Values + must be one of: "alt1", "alt2", "alt3", "alt4" +- bias-pull-up: Integer. Pull up strength in Ohm. There are 3 + pull-up resisitors (1.2k, 1.8k, 2.7k) available + in parallel for I2C pins, so the valid values + are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm. +- bias-disable: No arguments. Disable pin bias. +- slew-rate: Integer. Meaning depends on configured pin mux: + *_SCL or *_SDA: + 0: Standard(100kbps)& Fast(400kbps) mode + 1: Highspeed (3.4Mbps) mode + IC_DM or IC_DP: + 0: normal slew rate + 1: fast slew rate + Otherwise: + 0: fast slew rate + 1: normal slew rate +- input-enable: No arguments. Enable input (does not affect + output.) +- input-disable: No arguments. Disable input (does not affect + output.) + +Optional Properties (for HDMI pins): + +- function: String. Specifies the pin mux selection. Values + must be one of: "alt1", "alt2", "alt3", "alt4" +- slew-rate: Integer. Controls slew rate. + 0: Standard(100kbps)& Fast(400kbps) mode + 1: Highspeed (3.4Mbps) mode +- input-enable: No arguments. Enable input (does not affect + output.) +- input-disable: No arguments. Disable input (does not affect + output.) + +Example: +// pin controller node +pinctrl@35004800 { + compatible = "brcm,bcm11351-pinctrl"; + reg = <0x35004800 0x430>; + + // pin configuration node + dev_a_default: dev_a_active { + //group node defining 1 standard pin + grp_1 { + pins = "std_pin1"; + function = "alt1"; + input-schmitt-enable; + bias-disable; + slew-rate = <1>; + drive-strength = <4>; + }; + + // group node defining 2 I2C pins + grp_2 { + pins = "i2c_pin1", "i2c_pin2"; + function = "alt2"; + bias-pull-up = <720>; + input-enable; + }; + + // group node defining 2 HDMI pins + grp_3 { + pins = "hdmi_pin1", "hdmi_pin2"; + function = "alt3"; + slew-rate = <1>; + }; + + // other pin group nodes + ... + }; + + // other pin configuration nodes + ... +}; + +In the example above, "dev_a_active" is a pin configuration node with a number +of sub-nodes. In the pin group node "grp_1", one pin, "std_pin1", is defined in +the "pins" property. Thus, the remaining properties in the "grp_1" node applies +only to this pin, including the following settings: + - setting pinmux to "alt1" + - enabling schmitt-trigger (hystersis) mode + - disabling pin bias + - setting the slew-rate to 1 + - setting the drive strength to 4 mA +Note that neither "input-enable" nor "input-disable" was specified - the pinctrl +subsystem will therefore leave this property unchanged from whatever state it +was in before applying these changes. + +The "pins" property in the pin group node "grp_2" specifies two pins - +"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node, +therefore, applies to both of these pins. The properties include: + - setting pinmux to "alt2" + - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors + in parallel) + - enabling both pins' input +"slew-rate" is not specified in this pin group node, so the slew-rate for these +pins are left as-is. + +Finally, "grp_3" defines two HDMI pins. The following properties are applied to +both pins: + - setting pinmux to "alt3" + - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps + Highspeed mode +The input is neither enabled or disabled, and is left untouched. + +=== Pin Names and Type === + +The following are valid pin names and their pin types: + + "adcsync", Standard + "bat_rm", Standard + "bsc1_scl", I2C + "bsc1_sda", I2C + "bsc2_scl", I2C + "bsc2_sda", I2C + "classgpwr", Standard + "clk_cx8", Standard + "clkout_0", Standard + "clkout_1", Standard + "clkout_2", Standard + "clkout_3", Standard + "clkreq_in_0", Standard + "clkreq_in_1", Standard + "cws_sys_req1", Standard + "cws_sys_req2", Standard + "cws_sys_req3", Standard + "digmic1_clk", Standard + "digmic1_dq", Standard + "digmic2_clk", Standard + "digmic2_dq", Standard + "gpen13", Standard + "gpen14", Standard + "gpen15", Standard + "gpio00", Standard + "gpio01", Standard + "gpio02", Standard + "gpio03", Standard + "gpio04", Standard + "gpio05", Standard + "gpio06", Standard + "gpio07", Standard + "gpio08", Standard + "gpio09", Standard + "gpio10", Standard + "gpio11", Standard + "gpio12", Standard + "gpio13", Standard + "gpio14", Standard + "gps_pablank", Standard + "gps_tmark", Standard + "hdmi_scl", HDMI + "hdmi_sda", HDMI + "ic_dm", Standard + "ic_dp", Standard + "kp_col_ip_0", Standard + "kp_col_ip_1", Standard + "kp_col_ip_2", Standard + "kp_col_ip_3", Standard + "kp_row_op_0", Standard + "kp_row_op_1", Standard + "kp_row_op_2", Standard + "kp_row_op_3", Standard + "lcd_b_0", Standard + "lcd_b_1", Standard + "lcd_b_2", Standard + "lcd_b_3", Standard + "lcd_b_4", Standard + "lcd_b_5", Standard + "lcd_b_6", Standard + "lcd_b_7", Standard + "lcd_g_0", Standard + "lcd_g_1", Standard + "lcd_g_2", Standard + "lcd_g_3", Standard + "lcd_g_4", Standard + "lcd_g_5", Standard + "lcd_g_6", Standard + "lcd_g_7", Standard + "lcd_hsync", Standard + "lcd_oe", Standard + "lcd_pclk", Standard + "lcd_r_0", Standard + "lcd_r_1", Standard + "lcd_r_2", Standard + "lcd_r_3", Standard + "lcd_r_4", Standard + "lcd_r_5", Standard + "lcd_r_6", Standard + "lcd_r_7", Standard + "lcd_vsync", Standard + "mdmgpio0", Standard + "mdmgpio1", Standard + "mdmgpio2", Standard + "mdmgpio3", Standard + "mdmgpio4", Standard + "mdmgpio5", Standard + "mdmgpio6", Standard + "mdmgpio7", Standard + "mdmgpio8", Standard + "mphi_data_0", Standard + "mphi_data_1", Standard + "mphi_data_2", Standard + "mphi_data_3", Standard + "mphi_data_4", Standard + "mphi_data_5", Standard + "mphi_data_6", Standard + "mphi_data_7", Standard + "mphi_data_8", Standard + "mphi_data_9", Standard + "mphi_data_10", Standard + "mphi_data_11", Standard + "mphi_data_12", Standard + "mphi_data_13", Standard + "mphi_data_14", Standard + "mphi_data_15", Standard + "mphi_ha0", Standard + "mphi_hat0", Standard + "mphi_hat1", Standard + "mphi_hce0_n", Standard + "mphi_hce1_n", Standard + "mphi_hrd_n", Standard + "mphi_hwr_n", Standard + "mphi_run0", Standard + "mphi_run1", Standard + "mtx_scan_clk", Standard + "mtx_scan_data", Standard + "nand_ad_0", Standard + "nand_ad_1", Standard + "nand_ad_2", Standard + "nand_ad_3", Standard + "nand_ad_4", Standard + "nand_ad_5", Standard + "nand_ad_6", Standard + "nand_ad_7", Standard + "nand_ale", Standard + "nand_cen_0", Standard + "nand_cen_1", Standard + "nand_cle", Standard + "nand_oen", Standard + "nand_rdy_0", Standard + "nand_rdy_1", Standard + "nand_wen", Standard + "nand_wp", Standard + "pc1", Standard + "pc2", Standard + "pmu_int", Standard + "pmu_scl", I2C + "pmu_sda", I2C + "rfst2g_mtsloten3g", Standard + "rgmii_0_rx_ctl", Standard + "rgmii_0_rxc", Standard + "rgmii_0_rxd_0", Standard + "rgmii_0_rxd_1", Standard + "rgmii_0_rxd_2", Standard + "rgmii_0_rxd_3", Standard + "rgmii_0_tx_ctl", Standard + "rgmii_0_txc", Standard + "rgmii_0_txd_0", Standard + "rgmii_0_txd_1", Standard + "rgmii_0_txd_2", Standard + "rgmii_0_txd_3", Standard + "rgmii_1_rx_ctl", Standard + "rgmii_1_rxc", Standard + "rgmii_1_rxd_0", Standard + "rgmii_1_rxd_1", Standard + "rgmii_1_rxd_2", Standard + "rgmii_1_rxd_3", Standard + "rgmii_1_tx_ctl", Standard + "rgmii_1_txc", Standard + "rgmii_1_txd_0", Standard + "rgmii_1_txd_1", Standard + "rgmii_1_txd_2", Standard + "rgmii_1_txd_3", Standard + "rgmii_gpio_0", Standard + "rgmii_gpio_1", Standard + "rgmii_gpio_2", Standard + "rgmii_gpio_3", Standard + "rtxdata2g_txdata3g1", Standard + "rtxen2g_txdata3g2", Standard + "rxdata3g0", Standard + "rxdata3g1", Standard + "rxdata3g2", Standard + "sdio1_clk", Standard + "sdio1_cmd", Standard + "sdio1_data_0", Standard + "sdio1_data_1", Standard + "sdio1_data_2", Standard + "sdio1_data_3", Standard + "sdio4_clk", Standard + "sdio4_cmd", Standard + "sdio4_data_0", Standard + "sdio4_data_1", Standard + "sdio4_data_2", Standard + "sdio4_data_3", Standard + "sim_clk", Standard + "sim_data", Standard + "sim_det", Standard + "sim_resetn", Standard + "sim2_clk", Standard + "sim2_data", Standard + "sim2_det", Standard + "sim2_resetn", Standard + "sri_c", Standard + "sri_d", Standard + "sri_e", Standard + "ssp_extclk", Standard + "ssp0_clk", Standard + "ssp0_fs", Standard + "ssp0_rxd", Standard + "ssp0_txd", Standard + "ssp2_clk", Standard + "ssp2_fs_0", Standard + "ssp2_fs_1", Standard + "ssp2_fs_2", Standard + "ssp2_fs_3", Standard + "ssp2_rxd_0", Standard + "ssp2_rxd_1", Standard + "ssp2_txd_0", Standard + "ssp2_txd_1", Standard + "ssp3_clk", Standard + "ssp3_fs", Standard + "ssp3_rxd", Standard + "ssp3_txd", Standard + "ssp4_clk", Standard + "ssp4_fs", Standard + "ssp4_rxd", Standard + "ssp4_txd", Standard + "ssp5_clk", Standard + "ssp5_fs", Standard + "ssp5_rxd", Standard + "ssp5_txd", Standard + "ssp6_clk", Standard + "ssp6_fs", Standard + "ssp6_rxd", Standard + "ssp6_txd", Standard + "stat_1", Standard + "stat_2", Standard + "sysclken", Standard + "traceclk", Standard + "tracedt00", Standard + "tracedt01", Standard + "tracedt02", Standard + "tracedt03", Standard + "tracedt04", Standard + "tracedt05", Standard + "tracedt06", Standard + "tracedt07", Standard + "tracedt08", Standard + "tracedt09", Standard + "tracedt10", Standard + "tracedt11", Standard + "tracedt12", Standard + "tracedt13", Standard + "tracedt14", Standard + "tracedt15", Standard + "txdata3g0", Standard + "txpwrind", Standard + "uartb1_ucts", Standard + "uartb1_urts", Standard + "uartb1_urxd", Standard + "uartb1_utxd", Standard + "uartb2_urxd", Standard + "uartb2_utxd", Standard + "uartb3_ucts", Standard + "uartb3_urts", Standard + "uartb3_urxd", Standard + "uartb3_utxd", Standard + "uartb4_ucts", Standard + "uartb4_urts", Standard + "uartb4_urxd", Standard + "uartb4_utxd", Standard + "vc_cam1_scl", I2C + "vc_cam1_sda", I2C + "vc_cam2_scl", I2C + "vc_cam2_sda", I2C + "vc_cam3_scl", I2C + "vc_cam3_sda", I2C diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,bcm2835-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,bcm2835-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fac0a061bcc7c5b1cc6dbfa76b4b006e6876f48 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,bcm2835-gpio.txt @@ -0,0 +1,92 @@ +Broadcom BCM2835 GPIO (and pinmux) controller + +The BCM2835 GPIO module is a combined GPIO controller, (GPIO) interrupt +controller, and pinmux/control device. + +Required properties: +- compatible: "brcm,bcm2835-gpio" +- reg: Should contain the physical address of the GPIO module's registers. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- interrupts : The interrupt outputs from the controller. One interrupt per + individual bank followed by the "all banks" interrupt. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells : Should be 2. + The first cell is the GPIO number. + The second cell is used to specify flags: + bits[3:0] trigger type and level flags: + 1 = low-to-high edge triggered. + 2 = high-to-low edge triggered. + 4 = active high level-sensitive. + 8 = active low level-sensitive. + Valid combinations are 1, 2, 3, 4, 8. + +Please refer to ../gpio/gpio.txt for a general description of GPIO bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Each pin configuration node lists the pin(s) to which it applies, and one or +more of the mux function to select on those pin(s), and pull-up/down +configuration. Each subnode only affects those parameters that are explicitly +listed. In other words, a subnode that lists only a mux function implies no +information about any pull configuration. Similarly, a subnode that lists only +a pul parameter implies no information about the mux function. + +The BCM2835 pin configuration and multiplexing supports the generic bindings. +For details on each properties, you can refer to ./pinctrl-bindings.txt. + +Required sub-node properties: + - pins + - function + +Optional sub-node properties: + - bias-disable + - bias-pull-up + - bias-pull-down + - output-high + - output-low + +Legacy pin configuration and multiplexing binding: +*** (Its use is deprecated, use generic multiplexing and configuration +bindings instead) + +Required subnode-properties: +- brcm,pins: An array of cells. Each cell contains the ID of a pin. Valid IDs + are the integer GPIO IDs; 0==GPIO0, 1==GPIO1, ... 53==GPIO53. + +Optional subnode-properties: +- brcm,function: Integer, containing the function to mux to the pin(s): + 0: GPIO in + 1: GPIO out + 2: alt5 + 3: alt4 + 4: alt0 + 5: alt1 + 6: alt2 + 7: alt3 +- brcm,pull: Integer, representing the pull-down/up to apply to the pin(s): + 0: none + 1: down + 2: up + +Each of brcm,function and brcm,pull may contain either a single value which +will be applied to all pins in brcm,pins, or 1 value for each entry in +brcm,pins. + +Example: + + gpio: gpio { + compatible = "brcm,bcm2835-gpio"; + reg = <0x2200000 0xb4>; + interrupts = <2 17>, <2 19>, <2 18>, <2 20>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,cygnus-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,cygnus-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..3914529a3214b61b6dbc8c2fa6e49cd90bc8d6a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,cygnus-pinmux.txt @@ -0,0 +1,132 @@ +Broadcom Cygnus IOMUX Controller + +The Cygnus IOMUX controller supports group based mux configuration. In +addition, certain pins can be muxed to GPIO function individually. + +Required properties: + +- compatible: + Must be "brcm,cygnus-pinmux" + +- reg: + Define the base and range of the I/O address space that contains the Cygnus +IOMUX registers + +Properties in subnodes: + +- function: + The mux function to select + +- groups: + The list of groups to select with a given function + +For more details, refer to +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +For example: + + pinmux: pinmux@0301d0c8 { + compatible = "brcm,cygnus-pinmux"; + reg = <0x0301d0c8 0x1b0>; + + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_default>; + + i2s0_default: i2s0_default { + mux { + function = "i2s0"; + groups = "i2s0_0_grp", "i2s0_1_grp"; + }; + }; + }; + +List of supported functions and groups in Cygnus: + +"i2s0": "i2s0_0_grp", "i2s0_1_grp" + +"i2s1": "i2s1_0_grp", "i2s1_1_grp" + +"i2s2": "i2s2_0_grp", "i2s2_1_grp", "i2s2_2_grp", "i2s2_3_grp", "i2s2_4_grp" + +"spdif": "spdif_grp" + +"pwm0": "pwm0_grp" + +"pwm1": "pwm1_grp" + +"pwm2": "pwm2_grp" + +"pwm3": "pwm3_grp" + +"pwm4": "pwm4_grp" + +"pwm5": "pwm5_grp" + +"key": "key0_grp", "key1_grp", "key2_grp", "key3_grp", "key4_grp", "key5_grp", +"key6_grp", "key7_grp", "key8_grp", "key9_grp", "key10_grp", "key11_grp", +"key12_grp", "key13_grp", "key14_grp", "key15_grp" + +"audio_dte": "audio_dte0_grp", "audio_dte1_grp", "audio_dte2_grp", "audio_dte3_grp" + +"smart_card0": "smart_card0_grp", "smart_card0_fcb_grp" + +"smart_card1": "smart_card1_grp", "smart_card1_fcb_grp" + +"spi0": "spi0_grp" + +"spi1": "spi1_grp" + +"spi2": "spi2_grp" + +"spi3": "spi3_grp" + +"spi4": "spi4_0_grp", "spi4_1_grp" + +"spi5": "spi5_grp" + +"sw_led0": "sw_led0_0_grp", "sw_led0_1_grp" + +"sw_led1": "sw_led1_grp" + +"sw_led2": "sw_led2_0_grp", "sw_led2_1_grp" + +"d1w": "d1w_grp" + +"lcd": "lcd_grp" + +"sram": "sram_0_grp", "sram_1_grp" + +"uart0": "uart0_grp" + +"uart1": "uart1_grp", "uart1_dte_grp" + +"uart2": "uart2_grp" + +"uart3": "uart3_grp" + +"uart4": "uart4_grp" + +"qspi": "qspi_0_grp", "qspi_1_grp" + +"nand": "nand_grp" + +"sdio0": "sdio0_grp", "sdio0_cd_grp", "sdio0_mmc_grp" + +"sdio1": "sdio1_data_0_grp", "sdio1_data_1_grp", "sdio1_cd_grp", +"sdio1_led_grp", "sdio1_mmc_grp" + +"can0": "can0_grp" + +"can1": "can1_grp" + +"cam": "cam_led_grp", "cam_0_grp", "cam_1_grp" + +"bsc1": "bsc1_grp" + +"pcie_clkreq": "pcie_clkreq_grp" + +"usb0_oc": "usb0_oc_grp" + +"usb1_oc": "usb1_oc_grp" + +"usb2_oc": "usb2_oc_grp" diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,iproc-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,iproc-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..a73cbeb0f309dea99c3823bc1d79898f89285bcd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,iproc-gpio.txt @@ -0,0 +1,123 @@ +Broadcom iProc GPIO/PINCONF Controller + +Required properties: + +- compatible: + "brcm,iproc-gpio" for the generic iProc based GPIO controller IP that + supports full-featured pinctrl and GPIO functions used in various iProc + based SoCs + + May contain an SoC-specific compatibility string to accommodate any + SoC-specific features + + "brcm,cygnus-ccm-gpio", "brcm,cygnus-asiu-gpio", or + "brcm,cygnus-crmu-gpio" for Cygnus SoCs + + "brcm,iproc-nsp-gpio" for the iProc NSP SoC that has drive strength support + disabled + + "brcm,iproc-stingray-gpio" for the iProc Stingray SoC that has the general + pinctrl support completely disabled in this IP block. In Stingray, a + different IP block is used to handle pinctrl related functions + +- reg: + Define the base and range of the I/O address space that contains SoC +GPIO/PINCONF controller registers + +- ngpios: + Total number of in-use slots in GPIO controller + +- #gpio-cells: + Must be two. The first cell is the GPIO pin number (within the +controller's pin space) and the second cell is used for the following: + bit[0]: polarity (0 for active high and 1 for active low) + +- gpio-controller: + Specifies that the node is a GPIO controller + +Optional properties: + +- interrupts: + Interrupt ID + +- interrupt-controller: + Specifies that the node is an interrupt controller + +- gpio-ranges: + Specifies the mapping between gpio controller and pin-controllers pins. + This requires 4 fields in cells defined as - + 1. Phandle of pin-controller. + 2. GPIO base pin offset. + 3 Pin-control base pin offset. + 4. number of gpio pins which are linearly mapped from pin base. + +Supported generic PINCONF properties in child nodes: + +- pins: + The list of pins (within the controller's own pin space) that properties +in the node apply to. Pin names are "gpio-" + +- bias-disable: + Disable pin bias + +- bias-pull-up: + Enable internal pull up resistor + +- bias-pull-down: + Enable internal pull down resistor + +- drive-strength: + Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA) + +Example: + gpio_ccm: gpio@1800a000 { + compatible = "brcm,cygnus-ccm-gpio"; + reg = <0x1800a000 0x50>, + <0x0301d164 0x20>; + ngpios = <24>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + interrupt-controller; + + touch_pins: touch_pins { + pwr: pwr { + pins = "gpio-0"; + drive-strength = <16>; + }; + + event: event { + pins = "gpio-1"; + bias-pull-up; + }; + }; + }; + + gpio_asiu: gpio@180a5000 { + compatible = "brcm,cygnus-asiu-gpio"; + reg = <0x180a5000 0x668>; + ngpios = <146>; + #gpio-cells = <2>; + gpio-controller; + interrupts = ; + interrupt-controller; + gpio-ranges = <&pinctrl 0 42 1>, + <&pinctrl 1 44 3>; + }; + + /* + * Touchscreen that uses the CCM GPIO 0 and 1 + */ + tsc { + ... + ... + gpio-pwr = <&gpio_ccm 0 0>; + gpio-event = <&gpio_ccm 1 0>; + }; + + /* Bluetooth that uses the ASIU GPIO 5, with polarity inverted */ + bluetooth { + ... + ... + bcm,rfkill-bank-sel = <&gpio_asiu 5 1> + } diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,ns2-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,ns2-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..e295dda4bbbab958ea2e229e1899c99bc4394540 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,ns2-pinmux.txt @@ -0,0 +1,102 @@ +Broadcom Northstar2 IOMUX Controller + +The Northstar2 IOMUX controller supports group based mux configuration. There +are some individual pins that support modifying the pinconf parameters. + +Required properties: + +- compatible: + Must be "brcm,ns2-pinmux" + +- reg: + Define the base and range of the I/O address space that contains the + Northstar2 IOMUX and pin configuration registers. + +Properties in sub nodes: + +- function: + The mux function to select + +- groups: + The list of groups to select with a given function + +- pins: + List of pin names to change configuration + +The generic properties bias-disable, bias-pull-down, bias-pull-up, +drive-strength, slew-rate, input-enable, input-disable are supported +for some individual pins listed at the end. + +For more details, refer to +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +For example: + + pinctrl: pinctrl@6501d130 { + compatible = "brcm,ns2-pinmux"; + reg = <0x6501d130 0x08>, + <0x660a0028 0x04>, + <0x660009b0 0x40>; + + pinctrl-names = "default"; + pinctrl-0 = <&nand_sel &uart3_rx &sdio0_d4>; + + /* Select nand function */ + nand_sel: nand_sel { + function = "nand"; + groups = "nand_grp"; + }; + + /* Pull up the uart3 rx pin */ + uart3_rx: uart3_rx { + pins = "uart3_sin"; + bias-pull-up; + }; + + /* Set the drive strength of sdio d4 pin */ + sdio0_d4: sdio0_d4 { + pins = "sdio0_data4"; + drive-strength = <8>; + }; + }; + +List of supported functions and groups in Northstar2: + +"nand": "nand_grp" + +"nor": "nor_data_grp", "nor_adv_grp", "nor_addr_0_3_grp", "nor_addr_4_5_grp", + "nor_addr_6_7_grp", "nor_addr_8_9_grp", "nor_addr_10_11_grp", + "nor_addr_12_15_grp" + +"gpio": "gpio_0_1_grp", "gpio_2_5_grp", "gpio_6_7_grp", "gpio_8_9_grp", + "gpio_10_11_grp", "gpio_12_13_grp", "gpio_14_17_grp", "gpio_18_19_grp", + "gpio_20_21_grp", "gpio_22_23_grp", "gpio_24_25_grp", "gpio_26_27_grp", + "gpio_28_29_grp", "gpio_30_31_grp" + +"pcie": "pcie_ab1_clk_wak_grp", "pcie_a3_clk_wak_grp", "pcie_b3_clk_wak_grp", + "pcie_b2_clk_wak_grp", "pcie_a2_clk_wak_grp" + +"uart0": "uart0_modem_grp", "uart0_rts_cts_grp", "uart0_in_out_grp" + +"uart1": "uart1_ext_clk_grp", "uart1_dcd_dsr_grp", "uart1_ri_dtr_grp", + "uart1_rts_cts_grp", "uart1_in_out_grp" + +"uart2": "uart2_rts_cts_grp" + +"pwm": "pwm_0_grp", "pwm_1_grp", "pwm_2_grp", "pwm_3_grp" + + +List of pins that support pinconf parameters: + +"qspi_wp", "qspi_hold", "qspi_cs", "qspi_sck", "uart3_sin", "uart3_sout", +"qspi_mosi", "qspi_miso", "spi0_fss", "spi0_rxd", "spi0_txd", "spi0_sck", +"spi1_fss", "spi1_rxd", "spi1_txd", "spi1_sck", "sdio0_data7", +"sdio0_emmc_rst", "sdio0_led_on", "sdio0_wp", "sdio0_data3", "sdio0_data4", +"sdio0_data5", "sdio0_data6", "sdio0_cmd", "sdio0_data0", "sdio0_data1", +"sdio0_data2", "sdio1_led_on", "sdio1_wp", "sdio0_cd_l", "sdio0_clk", +"sdio1_data5", "sdio1_data6", "sdio1_data7", "sdio1_emmc_rst", "sdio1_data1", +"sdio1_data2", "sdio1_data3", "sdio1_data4", "sdio1_cd_l", "sdio1_clk", +"sdio1_cmd", "sdio1_data0", "ext_mdio_0", "ext_mdc_0", "usb3_p1_vbus_ppc", +"usb3_p1_overcurrent", "usb3_p0_vbus_ppc", "usb3_p0_overcurrent", +"usb2_presence_indication", "usb2_vbus_present", "usb2_vbus_ppc", +"usb2_overcurrent", "sata_led1", "sata_led0" diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,nsp-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,nsp-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..0844168a6dd4b0a68be830f9d868c143df84e737 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,nsp-gpio.txt @@ -0,0 +1,80 @@ +Broadcom Northstar plus (NSP) GPIO/PINCONF Controller + +Required properties: +- compatible: + Must be "brcm,nsp-gpio-a" + +- reg: + Should contain the register physical address and length for each of + GPIO base, IO control registers + +- #gpio-cells: + Must be two. The first cell is the GPIO pin number (within the + controller's pin space) and the second cell is used for the following: + bit[0]: polarity (0 for active high and 1 for active low) + +- gpio-controller: + Specifies that the node is a GPIO controller + +- ngpios: + Number of gpios supported (58x25 supports 32 and 58x23 supports 24) + +Optional properties: +- interrupts: + Interrupt ID + +- interrupt-controller: + Specifies that the node is an interrupt controller + +- gpio-ranges: + Specifies the mapping between gpio controller and pin-controllers pins. + This requires 4 fields in cells defined as - + 1. Phandle of pin-controller. + 2. GPIO base pin offset. + 3 Pin-control base pin offset. + 4. number of gpio pins which are linearly mapped from pin base. + +Supported generic PINCONF properties in child nodes: +- pins: + The list of pins (within the controller's own pin space) that properties + in the node apply to. Pin names are "gpio-" + +- bias-disable: + Disable pin bias + +- bias-pull-up: + Enable internal pull up resistor + +- bias-pull-down: + Enable internal pull down resistor + +- drive-strength: + Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA) + +Example: + + gpioa: gpio@18000020 { + compatible = "brcm,nsp-gpio-a"; + reg = <0x18000020 0x100>, + <0x1803f1c4 0x1c>; + #gpio-cells = <2>; + gpio-controller; + ngpios = <32>; + gpio-ranges = <&pinctrl 0 0 31>; + interrupt-controller; + interrupts = ; + + /* Hog a few default settings */ + pinctrl-names = "default"; + pinctrl-0 = <&led>; + led: led { + pins = "gpio-1"; + bias-pull-up; + }; + + pwr: pwr { + gpio-hog; + gpios = <3 1>; + output-high; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,nsp-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,nsp-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..603564e5fe6f0e54b2dfd042be9806a8f4687a98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/brcm,nsp-pinmux.txt @@ -0,0 +1,79 @@ +Broadcom NSP (Northstar plus) IOMUX Controller + +The NSP IOMUX controller supports group based mux configuration. In +addition, certain pins can be muxed to GPIO function individually. + +Required properties: +- compatible: + Must be "brcm,nsp-pinmux" + +- reg: + Should contain the register physical address and length for each of + GPIO_CONTROL0, GP_AUX_SEL and IPROC_CONFIG IOMUX registers + +Properties in subnodes: +- function: + The mux function to select + +- groups: + The list of groups to select with a given function + +For more details, refer to +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +For example: + + pinmux: pinmux@1803f1c0 { + compatible = "brcm,nsp-pinmux"; + reg = <0x1803f1c0 0x04>, + <0x18030028 0x04>, + <0x1803f408 0x04>; + + pinctrl-names = "default"; + pinctrl-0 = <&pwm &gpio_b &nand_sel>; + + pwm: pwm { + function = "pwm"; + groups = "pwm0_grp", "pwm1_grp"; + }; + + gpio_b: gpio_b { + function = "gpio_b"; + groups = "gpio_b_0_grp", "gpio_b_1_grp"; + }; + + nand_sel: nand_sel { + function = "nand"; + groups = "nand_grp"; + }; + }; + +List of supported functions and groups in Northstar Plus: + +"spi": "spi_grp" + +"i2c": "i2c_grp" + +"mdio": "mdio_grp" + +"pwm": "pwm0_grp", "pwm1_grp", "pwm2_grp", "pwm3_grp" + +"gpio_b": "gpio_b_0_grp", "gpio_b_1_grp", "gpio_b_2_grp", "gpio_b_3_grp" + +"uart1": "uart1_grp" + +"uart2": "uart2_grp" + +"synce": "synce_grp" + +"sata_led_grps": "sata0_led_grp", "sata1_led_grp" + +"xtal_out": "xtal_out_grp" + +"sdio": "sdio_pwr_grp", "sdio_1p8v_grp" + +"switch_led": "switch_p05_led0_grp", "switch_p05_led1_grp" + +"nand": "nand_grp" + +"emmc": "emmc_grp" diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/cirrus,madera-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/cirrus,madera-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..b0e36cf0d289eaaebdc1de6f13409835ddeb74b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/cirrus,madera-pinctrl.txt @@ -0,0 +1,99 @@ +Cirrus Logic Madera class audio codecs pinctrl driver + +The Cirrus Logic Madera codecs provide a number of GPIO functions for +interfacing to external hardware and to provide logic outputs to other devices. +Certain groups of GPIO pins also have an alternate function, normally as an +audio interface. + +The set of available GPIOs, functions and alternate function groups differs +between codecs so refer to the datasheet for the codec for further information +on what is supported on that device. + +The properties for this driver exist within the parent MFD driver node. + +See also + the core bindings for the parent MFD driver: + Documentation/devicetree/bindings/mfd/madera.txt + + the generic pinmix bindings: + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Required properties of parent mfd node: + - pinctrl-names : must be "default" + - pinctrl-0 : a phandle to the node containing the subnodes containing default + configurations + +Required subnodes: + One subnode is required to contain the default settings. It contains an + arbitrary number of configuration subnodes, one for each group or pin + configuration you want to apply as a default. + +Required properties of configuration subnodes: + - groups : name of one pin group to configure. One of: + aif1, aif2, aif3, aif4, mif1, mif2, mif3, pdmspk1, pdmspk2, + dmic4, dmic5, dmic6, + gpio1, gpio2, ..., gpio40 + The gpioN groups select the single pin of this name for configuration + +Optional properties of configuration subnodes: + Any configuration option not explicitly listed in the dts will be left at + chip default setting. + + - function : name of function to assign to this group. One of: + aif1, aif2, aif3, aif4, mif1, mif2, mif3, pdmspk1, pdmspk2, + dmic3, dmic4, dmic5, dmic6, + io, dsp-gpio, irq1, irq2, + fll1-clk, fll1-lock, fll2-clk, fll2-lock, fll3-clk, fll3-lock, + fllao-clk, fllao-lock, + opclk, opclk-async, pwm1, pwm2, spdif, + asrc1-in1-lock, asrc1-in2-lock, asrc2-in1-lock, asrc2-in2-lock, + spkl-short-circuit, spkr-short-circuit, spk-shutdown, + spk-overheat-shutdown, spk-overheat-warn, + timer1-sts, timer2-sts, timer3-sts, timer4-sts, timer5-sts, timer6-sts, + timer7-sts, timer8-sts, + log1-fifo-ne, log2-fifo-ne, log3-fifo-ne, log4-fifo-ne, log5-fifo-ne, + log6-fifo-ne, log7-fifo-ne, log8-fifo-ne, + + - bias-disable : disable pull-up and pull-down + - bias-bus-hold : enable buskeeper + - bias-pull-up : output is pulled-up + - bias-pull-down : output is pulled-down + - drive-push-pull : CMOS output + - drive-open-drain : open-drain output + - drive-strength : drive strength in mA. Valid values are 4 or 8 + - input-schmitt-enable : enable schmitt-trigger mode + - input-schmitt-disable : disable schmitt-trigger mode + - input-debounce : A value of 0 disables debounce, a value !=0 enables + debounce + - output-low : set the pin to output mode with low level + - output-high : set the pin to output mode with high level + +Example: + +cs47l85@0 { + compatible = "cirrus,cs47l85"; + + pinctrl-names = "default"; + pinctrl-0 = <&cs47l85_defaults>; + + cs47l85_defaults: cs47l85-gpio-defaults { + aif1 { + groups = "aif1"; + function = "aif1"; + bias-bus-hold; + }; + + aif2 { + groups = "aif2"; + function = "aif2"; + bias-bus-hold; + }; + + opclk { + groups = "gpio1"; + function = "opclk"; + bias-pull-up; + drive-strength = <8>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/cnxt,cx92755-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/cnxt,cx92755-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..23ce8dc26990b662436420965fd0066c7b697d91 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/cnxt,cx92755-pinctrl.txt @@ -0,0 +1,86 @@ +Conexant Digicolor CX92755 General Purpose Pin Mapping + +This document describes the device tree binding of the pin mapping hardware +modules in the Conexant Digicolor CX92755 SoCs. The CX92755 in one of the +Digicolor series of SoCs. + +=== Pin Controller Node === + +Required Properties: + +- compatible: Must be "cnxt,cx92755-pinctrl" +- reg: Base address of the General Purpose Pin Mapping register block and the + size of the block. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Must be <2>. The first cell is the pin number and the + second cell is used to specify flags. See include/dt-bindings/gpio/gpio.h + for possible values. + +For example, the following is the bare minimum node: + + pinctrl: pinctrl@f0000e20 { + compatible = "cnxt,cx92755-pinctrl"; + reg = <0xf0000e20 0x100>; + gpio-controller; + #gpio-cells = <2>; + }; + +As a pin controller device, in addition to the required properties, this node +should also contain the pin configuration nodes that client devices reference, +if any. + +For a general description of GPIO bindings, please refer to ../gpio/gpio.txt. + +=== Pin Configuration Node === + +Each pin configuration node is a sub-node of the pin controller node and is a +container of an arbitrary number of subnodes, called pin group nodes in this +document. + +Please refer to the pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the definition of a +"pin configuration node". + +=== Pin Group Node === + +A pin group node specifies the desired pin mux for an arbitrary number of +pins. The name of the pin group node is optional and not used. + +A pin group node only affects the properties specified in the node, and has no +effect on any properties that are omitted. + +The pin group node accepts a subset of the generic pin config properties. For +details generic pin config properties, please refer to pinctrl-bindings.txt +and . + +Required Pin Group Node Properties: + +- pins: Multiple strings. Specifies the name(s) of one or more pins to be + configured by this node. The format of a pin name string is "GP_xy", where x + is an uppercase character from 'A' to 'R', and y is a digit from 0 to 7. +- function: String. Specifies the pin mux selection. Values must be one of: + "gpio", "client_a", "client_b", "client_c" + +Example: + pinctrl: pinctrl@f0000e20 { + compatible = "cnxt,cx92755-pinctrl"; + reg = <0xf0000e20 0x100>; + + uart0_default: uart0_active { + data_signals { + pins = "GP_O0", "GP_O1"; + function = "client_b"; + }; + }; + }; + + uart0: uart@f0000740 { + compatible = "cnxt,cx92755-usart"; + ... + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + }; + +In the example above, a single pin group configuration node defines the +"client select" for the Rx and Tx signals of uart0. The uart0 node references +that pin configuration node using the &uart0_default phandle. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/cortina,gemini-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/cortina,gemini-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..4346ff2dd8e680353557f4861671f096cbec6890 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/cortina,gemini-pinctrl.txt @@ -0,0 +1,68 @@ +Cortina Systems Gemini pin controller + +This pin controller is found in the Cortina Systems Gemini SoC family, +see further arm/gemini.txt. It is a purely group-based multiplexing pin +controller. + +The pin controller node must be a subnode of the system controller node. + +Required properties: +- compatible: "cortina,gemini-pinctrl" + +Subnodes of the pin controller contain pin control multiplexing set-up +and pin configuration of individual pins. + +Please refer to pinctrl-bindings.txt for generic pin multiplexing nodes +and generic pin config nodes. + +Supported configurations: +- skew-delay is supported on the Ethernet pins +- drive-strength with 4, 8, 12 or 16 mA as argument is supported for + entire groups on the groups "idegrp", "gmii_gmac0_grp", "gmii_gmac1_grp" + and "pcigrp". + +Example: + + +syscon { + compatible = "cortina,gemini-syscon"; + ... + pinctrl { + compatible = "cortina,gemini-pinctrl"; + pinctrl-names = "default"; + pinctrl-0 = <&dram_default_pins>, <&system_default_pins>, + <&vcontrol_default_pins>; + + dram_default_pins: pinctrl-dram { + mux { + function = "dram"; + groups = "dramgrp"; + }; + }; + rtc_default_pins: pinctrl-rtc { + mux { + function = "rtc"; + groups = "rtcgrp"; + }; + }; + power_default_pins: pinctrl-power { + mux { + function = "power"; + groups = "powergrp"; + }; + }; + system_default_pins: pinctrl-system { + mux { + function = "system"; + groups = "systemgrp"; + }; + }; + (...) + uart_default_pins: pinctrl-uart { + mux { + function = "uart"; + groups = "uartrxtxgrp"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1050b5982ec307d2769e804f107b4b2659670c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx-pinctrl.txt @@ -0,0 +1,93 @@ +* Freescale IOMUX Controller (IOMUXC) for i.MX + +The IOMUX Controller (IOMUXC), together with the IOMUX, enables the IC +to share one PAD to several functional blocks. The sharing is done by +multiplexing the PAD input/output signals. For each PAD there are up to +8 muxing options (called ALT modes). Since different modules require +different PAD settings (like pull up, keeper, etc) the IOMUXC controls +also the PAD settings parameters. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Freescale IMX pin configuration node is a node of a group of pins which can be +used for a specific device or function. This node represents both mux and config +of the pins in that group. The 'mux' selects the function mode(also named mux +mode) this pin can work on and the 'config' configures various pad settings +such as pull-up, open drain, drive strength, etc. + +Required properties for iomux controller: +- compatible: "fsl,-iomuxc" + Please refer to each fsl,-pinctrl.txt binding doc for supported SoCs. + +Required properties for pin configuration node: +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx*-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. And that's why fsl,pins entry + looks like in the example below. + +Bits used for CONFIG: +NO_PAD_CTL(1 << 31): indicate this pin does not need config. + +SION(1 << 30): Software Input On Field. +Force the selected mux mode input path no matter of MUX_MODE functionality. +By default the input path is determined by functionality of the selected +mux mode (regular). + +Other bits are used for PAD setting. +Please refer to each fsl,-pinctrl,txt binding doc for SoC specific part +of bits definitions. + +NOTE: +Some requirements for using fsl,imx-pinctrl binding: +1. We have pin function node defined under iomux controller node to represent + what pinmux functions this SoC supports. +2. The pin configuration node intends to work on a specific function should + to be defined under that specific function node. + The function node's name should represent well about what function + this group of pins in this pin configuration node are working on. +3. The driver can use the function node's name and pin configuration node's + name describe the pin function and group hierarchy. + For example, Linux IMX pinctrl driver takes the function node's name + as the function name and pin configuration node's name as group name to + create the map table. +4. Each pin configuration node should have a phandle, devices can set pins + configurations by referring to the phandle of that pin configuration node. + +Examples: +usdhc@219c000 { /* uSDHC4 */ + non-removable; + vmmc-supply = <®_3p3v>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usdhc4_1>; +}; + +iomuxc@20e0000 { + compatible = "fsl,imx6q-iomuxc"; + reg = <0x020e0000 0x4000>; + + /* shared pinctrl settings */ + usdhc4 { + pinctrl_usdhc4_1: usdhc4grp-1 { + fsl,pins = < + MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059 + MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059 + MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059 + MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059 + MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059 + MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059 + MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059 + MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059 + MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059 + MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059 + >; + }; + .... +}; +Refer to the IOMUXC controller chapter in imx6q datasheet, +0x17059 means enable hysteresis, 47KOhm Pull Up, 50Mhz speed, +80Ohm driver strength and Fast Slew Rate. +User should refer to each SoC spec to set the correct value. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx25-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx25-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd653bde18d53b054f2053bb0b6ad4e232ab1ab0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx25-pinctrl.txt @@ -0,0 +1,23 @@ +* Freescale IMX25 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE_CMOS (0 << 3) +PAD_CTL_ODE_OPENDRAIN (1 << 3) +PAD_CTL_DSE_NOMINAL (0 << 1) +PAD_CTL_DSE_HIGH (1 << 1) +PAD_CTL_DSE_MAX (2 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx25-pinfunc.h in device tree source folder for all available +imx25 PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx27-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx27-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1706ea8257230121f2843bd7684faccd160198b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx27-pinctrl.txt @@ -0,0 +1,121 @@ +* Freescale IMX27 IOMUX Controller + +Required properties: +- compatible: "fsl,imx27-iomuxc" + +The iomuxc driver node should define subnodes containing of pinctrl configuration subnodes. + +Required properties for pin configuration node: +- fsl,pins: three integers array, represents a group of pins mux and config + setting. The format is fsl,pins = . + + PIN is an integer between 0 and 0xbf. imx27 has 6 ports with 32 configurable + configurable pins each. PIN is PORT * 32 + PORT_PIN, PORT_PIN is the pin + number on the specific port (between 0 and 31). + + MUX_ID is + function + (direction << 2) + (gpio_oconf << 4) + (gpio_iconfa << 8) + (gpio_iconfb << 10) + + function value is used to select the pin function. + Possible values: + 0 - Primary function + 1 - Alternate function + 2 - GPIO + Registers: GIUS (GPIO In Use), GPR (General Purpose Register) + + direction defines the data direction of the pin. + Possible values: + 0 - Input + 1 - Output + Register: DDIR + + gpio_oconf configures the gpio submodule output signal. This does not + have any effect unless GPIO function is selected. A/B/C_IN are output + signals of function blocks A,B and C. Specific function blocks are + described in the reference manual. + Possible values: + 0 - A_IN + 1 - B_IN + 2 - C_IN + 3 - Data Register + Registers: OCR1, OCR2 + + gpio_iconfa/b configures the gpio submodule input to functionblocks A and + B. GPIO function should be selected if this is configured. + Possible values: + 0 - GPIO_IN + 1 - Interrupt Status Register + 2 - Pulldown + 3 - Pullup + Registers ICONFA1, ICONFA2, ICONFB1 and ICONFB2 + + CONFIG can be 0 or 1, meaning Pullup disable/enable. + + +The iomux controller has gpio child nodes which are embedded in the iomux +control registers. They have to be defined as child nodes of the iomux device +node. If gpio subnodes are defined "#address-cells", "#size-cells" and "ranges" +properties for the iomux device node are required. + +Example: + +iomuxc: iomuxc@10015000 { + compatible = "fsl,imx27-iomuxc"; + reg = <0x10015000 0x600>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio1: gpio@10015000 { + ... + }; + + ... + + uart { + pinctrl_uart1: uart-1 { + fsl,pins = < + 0x8c 0x004 0x0 /* UART1_TXD__UART1_TXD */ + 0x8d 0x000 0x0 /* UART1_RXD__UART1_RXD */ + 0x8e 0x004 0x0 /* UART1_CTS__UART1_CTS */ + 0x8f 0x000 0x0 /* UART1_RTS__UART1_RTS */ + >; + }; + + ... + }; +}; + + +For convenience there are macros defined in imx27-pinfunc.h which provide PIN +and MUX_ID. They are structured as MX27_PAD___. The names +are defined in the i.MX27 reference manual. + +The above example using macros: + +iomuxc: iomuxc@10015000 { + compatible = "fsl,imx27-iomuxc"; + reg = <0x10015000 0x600>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio1: gpio@10015000 { + ... + }; + + ... + + uart { + pinctrl_uart1: uart-1 { + fsl,pins = < + MX27_PAD_UART1_TXD__UART1_TXD 0x0 + MX27_PAD_UART1_RXD__UART1_RXD 0x0 + MX27_PAD_UART1_CTS__UART1_CTS 0x0 + MX27_PAD_UART1_RTS__UART1_RTS 0x0 + >; + }; + + ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx35-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx35-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c083dfd25db9317e79c1c318a8db62f9b7141723 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx35-pinctrl.txt @@ -0,0 +1,33 @@ +* Freescale IMX35 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx35-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx35 datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_DRIVE_VOLAGAGE_18 (1 << 13) +PAD_CTL_DRIVE_VOLAGAGE_33 (0 << 13) +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE_CMOS (0 << 3) +PAD_CTL_ODE_OPENDRAIN (1 << 3) +PAD_CTL_DSE_NOMINAL (0 << 1) +PAD_CTL_DSE_HIGH (1 << 1) +PAD_CTL_DSE_MAX (2 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx35-pinfunc.h in device tree source folder for all available +imx35 PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx51-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx51-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d1408fcc99cfbc86bf65fb7a5b9479798da345c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx51-pinctrl.txt @@ -0,0 +1,32 @@ +* Freescale IMX51 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx51-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx51 datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HVE (1 << 13) +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE (1 << 3) +PAD_CTL_DSE_LOW (0 << 1) +PAD_CTL_DSE_MED (1 << 1) +PAD_CTL_DSE_HIGH (2 << 1) +PAD_CTL_DSE_MAX (3 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx51-pinfunc.h in device tree source folder for all available +imx51 PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx53-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx53-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..25dcb77cfaf7412594e406a1d65c2ef16375634a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx53-pinctrl.txt @@ -0,0 +1,32 @@ +* Freescale IMX53 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx53-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx53 datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HVE (1 << 13) +PAD_CTL_HYS (1 << 8) +PAD_CTL_PKE (1 << 7) +PAD_CTL_PUE (1 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_ODE (1 << 3) +PAD_CTL_DSE_LOW (0 << 1) +PAD_CTL_DSE_MED (1 << 1) +PAD_CTL_DSE_HIGH (2 << 1) +PAD_CTL_DSE_MAX (3 << 1) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx53-pinfunc.h in device tree source folder for all available +imx53 PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6dl-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6dl-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ac5bee875056de7292616fc6025ecdbc58d4d9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6dl-pinctrl.txt @@ -0,0 +1,38 @@ +* Freescale IMX6 DualLite/Solo IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6dl-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx6dl datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (1 << 6) +PAD_CTL_SPEED_MED (2 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_240ohm (1 << 3) +PAD_CTL_DSE_120ohm (2 << 3) +PAD_CTL_DSE_80ohm (3 << 3) +PAD_CTL_DSE_60ohm (4 << 3) +PAD_CTL_DSE_48ohm (5 << 3) +PAD_CTL_DSE_40ohm (6 << 3) +PAD_CTL_DSE_34ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx6dl-pinfunc.h in device tree source folder for all available +imx6dl PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6q-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6q-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..546610cf2ae71cb26bda5cf171c70e9f8986746f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6q-pinctrl.txt @@ -0,0 +1,38 @@ +* Freescale IMX6Q IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6q-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx6q datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (1 << 6) +PAD_CTL_SPEED_MED (2 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_240ohm (1 << 3) +PAD_CTL_DSE_120ohm (2 << 3) +PAD_CTL_DSE_80ohm (3 << 3) +PAD_CTL_DSE_60ohm (4 << 3) +PAD_CTL_DSE_48ohm (5 << 3) +PAD_CTL_DSE_40ohm (6 << 3) +PAD_CTL_DSE_34ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx6q-pinfunc.h in device tree source folder for all available +imx6q PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sl-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sl-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..e5f6d1f065a4217d2f969d430a8aaa9e0f802559 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sl-pinctrl.txt @@ -0,0 +1,39 @@ +* Freescale IMX6 SoloLite IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6sl-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is a + pin working on a specific function, CONFIG is the pad setting value like + pull-up for this pin. Please refer to imx6sl datasheet for the valid pad + config settings. + +CONFIG bits definition: +PAD_CTL_LVE (1 << 22) +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (1 << 6) +PAD_CTL_SPEED_MED (2 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_240ohm (1 << 3) +PAD_CTL_DSE_120ohm (2 << 3) +PAD_CTL_DSE_80ohm (3 << 3) +PAD_CTL_DSE_60ohm (4 << 3) +PAD_CTL_DSE_48ohm (5 << 3) +PAD_CTL_DSE_40ohm (6 << 3) +PAD_CTL_DSE_34ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx6sl-pinfunc.h in device tree source folder for all available +imx6sl PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sll-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sll-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..175e8939a3018d01642d10d27c580fc92a61527b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sll-pinctrl.txt @@ -0,0 +1,40 @@ +* Freescale i.MX6 SLL IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6sll-iomuxc" +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx6sll-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX6SLL + Reference Manual for detailed CONFIG settings. + +CONFIG bits definition: +PAD_CTL_LVE (1 << 22) +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (0 << 6) +PAD_CTL_SPEED_MED (1 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_260ohm (1 << 3) +PAD_CTL_DSE_130ohm (2 << 3) +PAD_CTL_DSE_87ohm (3 << 3) +PAD_CTL_DSE_65ohm (4 << 3) +PAD_CTL_DSE_52ohm (5 << 3) +PAD_CTL_DSE_43ohm (6 << 3) +PAD_CTL_DSE_37ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) + +Refer to imx6sll-pinfunc.h in device tree source folder for all available +imx6sll PIN_FUNC_ID. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sx-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sx-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1b595220f1bd91115cae549b2109f18ee5cd046 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6sx-pinctrl.txt @@ -0,0 +1,36 @@ +* Freescale i.MX6 SoloX IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6sx-iomuxc" +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx6sx-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX6 SoloX + Reference Manual for detailed CONFIG settings. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (0 << 6) +PAD_CTL_SPEED_MED (1 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_260ohm (1 << 3) +PAD_CTL_DSE_130ohm (2 << 3) +PAD_CTL_DSE_87ohm (3 << 3) +PAD_CTL_DSE_65ohm (4 << 3) +PAD_CTL_DSE_52ohm (5 << 3) +PAD_CTL_DSE_43ohm (6 << 3) +PAD_CTL_DSE_37ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6ul-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6ul-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ca4f6118d9a07ff296739f0f4b23147a15d99c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx6ul-pinctrl.txt @@ -0,0 +1,37 @@ +* Freescale i.MX6 UltraLite IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx6ul-iomuxc" for main IOMUX controller or + "fsl,imx6ull-iomuxc-snvs" for i.MX 6ULL's SNVS IOMUX controller. +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx6ul-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX6 UltraLite + Reference Manual for detailed CONFIG settings. + +CONFIG bits definition: +PAD_CTL_HYS (1 << 16) +PAD_CTL_PUS_100K_DOWN (0 << 14) +PAD_CTL_PUS_47K_UP (1 << 14) +PAD_CTL_PUS_100K_UP (2 << 14) +PAD_CTL_PUS_22K_UP (3 << 14) +PAD_CTL_PUE (1 << 13) +PAD_CTL_PKE (1 << 12) +PAD_CTL_ODE (1 << 11) +PAD_CTL_SPEED_LOW (0 << 6) +PAD_CTL_SPEED_MED (1 << 6) +PAD_CTL_SPEED_HIGH (3 << 6) +PAD_CTL_DSE_DISABLE (0 << 3) +PAD_CTL_DSE_260ohm (1 << 3) +PAD_CTL_DSE_130ohm (2 << 3) +PAD_CTL_DSE_87ohm (3 << 3) +PAD_CTL_DSE_65ohm (4 << 3) +PAD_CTL_DSE_52ohm (5 << 3) +PAD_CTL_DSE_43ohm (6 << 3) +PAD_CTL_DSE_37ohm (7 << 3) +PAD_CTL_SRE_FAST (1 << 0) +PAD_CTL_SRE_SLOW (0 << 0) diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx7d-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx7d-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..6666277c3acb72988131d13e3d176b78956a727a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx7d-pinctrl.txt @@ -0,0 +1,87 @@ +* Freescale i.MX7 Dual IOMUX Controller + +iMX7D supports two iomuxc controllers, fsl,imx7d-iomuxc controller is similar +as previous iMX SoC generation and fsl,imx7d-iomuxc-lpsr which provides low +power state retention capabilities on gpios that are part of iomuxc-lpsr +(GPIO1_IO7..GPIO1_IO0). While iomuxc-lpsr provides its own set of registers for +mux and pad control settings, it shares the input select register from main +iomuxc controller for daisy chain settings, the fsl,input-sel property extends +fsl,imx-pinctrl driver to support iomuxc-lpsr controller. + +iomuxc_lpsr: iomuxc-lpsr@302c0000 { + compatible = "fsl,imx7d-iomuxc-lpsr"; + reg = <0x302c0000 0x10000>; + fsl,input-sel = <&iomuxc>; +}; + +iomuxc: iomuxc@30330000 { + compatible = "fsl,imx7d-iomuxc"; + reg = <0x30330000 0x10000>; +}; + +Peripherals using pads from iomuxc-lpsr support low state retention power +state, under LPSR mode GPIO's state of pads are retain. + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,imx7d-iomuxc" for main IOMUXC controller, or + "fsl,imx7d-iomuxc-lpsr" for Low Power State Retention IOMUXC controller. +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx7d-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX7 Dual + Reference Manual for detailed CONFIG settings. +- fsl,input-sel: required property for iomuxc-lpsr controller, this property is + a phandle for main iomuxc controller which shares the input select register for + daisy chain settings. + +CONFIG bits definition: +PAD_CTL_PUS_100K_DOWN (0 << 5) +PAD_CTL_PUS_5K_UP (1 << 5) +PAD_CTL_PUS_47K_UP (2 << 5) +PAD_CTL_PUS_100K_UP (3 << 5) +PAD_CTL_PUE (1 << 4) +PAD_CTL_HYS (1 << 3) +PAD_CTL_SRE_SLOW (1 << 2) +PAD_CTL_SRE_FAST (0 << 2) +PAD_CTL_DSE_X1 (0 << 0) +PAD_CTL_DSE_X2 (1 << 0) +PAD_CTL_DSE_X3 (2 << 0) +PAD_CTL_DSE_X4 (3 << 0) + +Examples: +While iomuxc-lpsr is intended to be used by dedicated peripherals to take +advantages of LPSR power mode, is also possible that an IP to use pads from +any of the iomux controllers. For example the I2C1 IP can use SCL pad from +iomuxc-lpsr controller and SDA pad from iomuxc controller as: + +i2c1: i2c@30a20000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_1 &pinctrl_i2c1_2>; +}; + +iomuxc-lpsr@302c0000 { + compatible = "fsl,imx7d-iomuxc-lpsr"; + reg = <0x302c0000 0x10000>; + fsl,input-sel = <&iomuxc>; + + pinctrl_i2c1_1: i2c1grp-1 { + fsl,pins = < + MX7D_PAD_GPIO1_IO04__I2C1_SCL 0x4000007f + >; + }; +}; + +iomuxc@30330000 { + compatible = "fsl,imx7d-iomuxc"; + reg = <0x30330000 0x10000>; + + pinctrl_i2c1_2: i2c1grp-2 { + fsl,pins = < + MX7D_PAD_I2C1_SDA__I2C1_SDA 0x4000007f + >; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx7ulp-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx7ulp-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..44ad670ae11e14eec28685bddc1506789e4f5e61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx7ulp-pinctrl.txt @@ -0,0 +1,61 @@ +* Freescale i.MX7ULP IOMUX Controller + +i.MX 7ULP has three IOMUXC instances: IOMUXC0 for M4 ports, IOMUXC1 for A7 +ports and IOMUXC DDR for DDR interface. + +Note: +This binding doc is only for the IOMUXC1 support in A7 Domain and it only +supports generic pin config. + +Please also refer pinctrl-bindings.txt in this directory for generic pinctrl +binding. + +=== Pin Controller Node === + +Required properties: +- compatible: "fsl,imx7ulp-iomuxc1" +- reg: Should contain the base physical address and size of the iomuxc + registers. + +=== Pin Configuration Node === +- pinmux: One integers array, represents a group of pins mux setting. + The format is pinmux = , PIN_FUNC_ID is a pin working on + a specific function. + + NOTE: i.MX7ULP PIN_FUNC_ID consists of 4 integers as it shares one mux + and config register as follows: + + + Refer to imx7ulp-pinfunc.h in in device tree source folder for all + available imx7ulp PIN_FUNC_ID. + +Optional Properties: +- drive-strength Integer. Controls Drive Strength + 0: Standard + 1: Hi Driver +- drive-push-pull Bool. Enable Pin Push-pull +- drive-open-drain Bool. Enable Pin Open-drian +- slew-rate: Integer. Controls Slew Rate + 0: Standard + 1: Slow +- bias-disable: Bool. Pull disabled +- bias-pull-down: Bool. Pull down on pin +- bias-pull-up: Bool. Pull up on pin + +Examples: +#include "imx7ulp-pinfunc.h" + +/* Pin Controller Node */ +iomuxc1: iomuxc@40ac0000 { + compatible = "fsl,imx7ulp-iomuxc1"; + reg = <0x40ac0000 0x1000>; + + /* Pin Configuration Node */ + pinctrl_lpuart4: lpuart4grp { + pinmux = < + IMX7ULP_PAD_PTC3__LPUART4_RX + IMX7ULP_PAD_PTC2__LPUART4_TX + >; + bias-pull-up; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx8mq-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx8mq-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..66de75090458083a6e2ec344350fe32136a442c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,imx8mq-pinctrl.txt @@ -0,0 +1,36 @@ +* Freescale IMX8MQ IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory +for common binding part and usage. + +Required properties: +- compatible: "fsl,imx8mq-iomuxc" +- reg: should contain the base physical address and size of the iomuxc + registers. + +Required properties in sub-nodes: +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx8mq-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX8M Quad + Reference Manual for detailed CONFIG settings. + +Examples: + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +iomuxc: pinctrl@30330000 { + compatible = "fsl,imx8mq-iomuxc"; + reg = <0x0 0x30330000 0x0 0x10000>; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 + MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 + >; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,mxs-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,mxs-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e70a8aff2600ec72eba7e5f707da425aa19fc4e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,mxs-pinctrl.txt @@ -0,0 +1,127 @@ +* Freescale MXS Pin Controller + +The pins controlled by mxs pin controller are organized in banks, each bank +has 32 pins. Each pin has 4 multiplexing functions, and generally, the 4th +function is GPIO. The configuration on the pins includes drive strength, +voltage and pull-up. + +Required properties: +- compatible: "fsl,imx23-pinctrl" or "fsl,imx28-pinctrl" +- reg: Should contain the register physical address and length for the + pin controller. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +The node of mxs pin controller acts as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for +a group of pins, and only affects those parameters that are explicitly listed. +In other words, a subnode that describes a drive strength parameter implies no +information about pull-up. For this reason, even seemingly boolean values are +actually tristates in this binding: unspecified, off, or on. Unspecified is +represented as an absent property, and off/on are represented as integer +values 0 and 1. + +Those subnodes under mxs pin controller node will fall into two categories. +One is to set up a group of pins for a function, both mux selection and pin +configurations, and it's called group node in the binding document. The other +one is to adjust the pin configuration for some particular pins that need a +different configuration than what is defined in group node. The binding +document calls this type of node config node. + +On mxs, there is no hardware pin group. The pin group in this binding only +means a group of pins put together for particular peripheral to work in +particular function, like SSP0 functioning as mmc0-8bit. That said, the +group node should include all the pins needed for one function rather than +having these pins defined in several group nodes. It also means each of +"pinctrl-*" phandle in client device node should only have one group node +pointed in there, while the phandle can have multiple config node referenced +there to adjust configurations for some pins in the group. + +Required subnode-properties: +- fsl,pinmux-ids: An integer array. Each integer in the array specify a pin + with given mux function, with bank, pin and mux packed as below. + + [15..12] : bank number + [11..4] : pin number + [3..0] : mux selection + + This integer with mux selection packed is used as an entity by both group + and config nodes to identify a pin. The mux selection in the integer takes + effects only on group node, and will get ignored by driver with config node, + since config node is only meant to set up pin configurations. + + Valid values for these integers are listed below. + +- reg: Should be the index of the group nodes for same function. This property + is required only for group nodes, and should not be present in any config + nodes. + +Optional subnode-properties: +- fsl,drive-strength: Integer. + 0: MXS_DRIVE_4mA + 1: MXS_DRIVE_8mA + 2: MXS_DRIVE_12mA + 3: MXS_DRIVE_16mA +- fsl,voltage: Integer. + 0: MXS_VOLTAGE_LOW - 1.8 V + 1: MXS_VOLTAGE_HIGH - 3.3 V +- fsl,pull-up: Integer. + 0: MXS_PULL_DISABLE - Disable the internal pull-up + 1: MXS_PULL_ENABLE - Enable the internal pull-up + +Note that when enabling the pull-up, the internal pad keeper gets disabled. +Also, some pins doesn't have a pull up, in that case, setting the fsl,pull-up +will only disable the internal pad keeper. + +Examples: + +pinctrl@80018000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-pinctrl"; + reg = <0x80018000 2000>; + + mmc0_8bit_pins_a: mmc0-8bit@0 { + reg = <0>; + fsl,pinmux-ids = < + MX28_PAD_SSP0_DATA0__SSP0_D0 + MX28_PAD_SSP0_DATA1__SSP0_D1 + MX28_PAD_SSP0_DATA2__SSP0_D2 + MX28_PAD_SSP0_DATA3__SSP0_D3 + MX28_PAD_SSP0_DATA4__SSP0_D4 + MX28_PAD_SSP0_DATA5__SSP0_D5 + MX28_PAD_SSP0_DATA6__SSP0_D6 + MX28_PAD_SSP0_DATA7__SSP0_D7 + MX28_PAD_SSP0_CMD__SSP0_CMD + MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT + MX28_PAD_SSP0_SCK__SSP0_SCK + >; + fsl,drive-strength = ; + fsl,voltage = ; + fsl,pull-up = ; + }; + + mmc_cd_cfg: mmc-cd-cfg { + fsl,pinmux-ids = ; + fsl,pull-up = ; + }; + + mmc_sck_cfg: mmc-sck-cfg { + fsl,pinmux-ids = ; + fsl,drive-strength = ; + fsl,pull-up = ; + }; +}; + +In this example, group node mmc0-8bit defines a group of pins for mxs SSP0 +to function as a 8-bit mmc device, with 8mA, 3.3V and pull-up configurations +applied on all these pins. And config nodes mmc-cd-cfg and mmc-sck-cfg are +adjusting the configuration for pins card-detection and clock from what group +node mmc0-8bit defines. Only the configuration properties to be adjusted need +to be listed in the config nodes. + +Valid values for i.MX28/i.MX23 pinmux-id are defined in +arch/arm/boot/dts/imx28-pinfunc.h and arch/arm/boot/dts/imx23-pinfunc.h. +The definitions for the padconfig properties can be found in +arch/arm/boot/dts/mxs-pinfunc.h. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,vf610-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,vf610-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..ddcdeb697c292532d4d74747577854450bb9259f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/fsl,vf610-pinctrl.txt @@ -0,0 +1,41 @@ +Freescale Vybrid VF610 IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: "fsl,vf610-iomuxc" +- fsl,pins: two integers array, represents a group of pins mux and config + setting. The format is fsl,pins = , PIN_FUNC_ID is + a pin working on a specific function, CONFIG is the pad setting value + such as pull-up, speed, ode for this pin. Please refer to Vybrid VF610 + datasheet for the valid pad config settings. + +CONFIG bits definition: +PAD_CTL_SPEED_LOW (1 << 12) +PAD_CTL_SPEED_MED (2 << 12) +PAD_CTL_SPEED_HIGH (3 << 12) +PAD_CTL_SRE_FAST (1 << 11) +PAD_CTL_SRE_SLOW (0 << 11) +PAD_CTL_ODE (1 << 10) +PAD_CTL_HYS (1 << 9) +PAD_CTL_DSE_DISABLE (0 << 6) +PAD_CTL_DSE_150ohm (1 << 6) +PAD_CTL_DSE_75ohm (2 << 6) +PAD_CTL_DSE_50ohm (3 << 6) +PAD_CTL_DSE_37ohm (4 << 6) +PAD_CTL_DSE_30ohm (5 << 6) +PAD_CTL_DSE_25ohm (6 << 6) +PAD_CTL_DSE_20ohm (7 << 6) +PAD_CTL_PUS_100K_DOWN (0 << 4) +PAD_CTL_PUS_47K_UP (1 << 4) +PAD_CTL_PUS_100K_UP (2 << 4) +PAD_CTL_PUS_22K_UP (3 << 4) +PAD_CTL_PKE (1 << 3) +PAD_CTL_PUE (1 << 2) +PAD_CTL_OBE_ENABLE (1 << 1) +PAD_CTL_IBE_ENABLE (1 << 0) +PAD_CTL_OBE_IBE_ENABLE (3 << 0) + +Please refer to vf610-pinfunc.h in device tree source folder +for all available PIN_FUNC_ID for Vybrid VF610. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/img,pistachio-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/img,pistachio-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..a72dc3178179e1a854952b990ed7e671e4674163 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/img,pistachio-pinctrl.txt @@ -0,0 +1,217 @@ +Imagination Technologies Pistachio SoC pin controllers +====================================================== + +The pin controllers on Pistachio are a combined GPIO controller, (GPIO) +interrupt controller, and pinmux + pinconf device. The system ("east") pin +controller on Pistachio has 99 pins, 90 of which are MFIOs which can be +configured as GPIOs. The 90 GPIOs are divided into 6 banks of up to 16 GPIOs +each. The GPIO banks are represented as sub-nodes of the pad controller node. + +Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and +../interrupt-controller/interrupts.txt for generic information regarding +pin controller, GPIO, and interrupt bindings. + +Required properties for pin controller node: +-------------------------------------------- + - compatible: "img,pistachio-system-pinctrl". + - reg: Address range of the pinctrl registers. + +Required properties for GPIO bank sub-nodes: +-------------------------------------------- + - interrupts: Interrupt line for the GPIO bank. + - gpio-controller: Indicates the device is a GPIO controller. + - #gpio-cells: Must be two. The first cell is the GPIO pin number and the + second cell indicates the polarity. See for + a list of possible values. + - interrupt-controller: Indicates the device is an interrupt controller. + - #interrupt-cells: Must be two. The first cell is the GPIO pin number and + the second cell encodes the interrupt flags. See + for a list of valid flags. + +Note that the N GPIO bank sub-nodes *must* be named gpio0, gpio1, ... gpioN-1. + +Required properties for pin configuration sub-nodes: +---------------------------------------------------- + - pins: List of pins to which the configuration applies. See below for a + list of possible pins. + +Optional properties for pin configuration sub-nodes: +---------------------------------------------------- + - function: Mux function for the specified pins. This is not applicable for + non-MFIO pins. See below for a list of valid functions for each pin. + - bias-high-impedance: Enable high-impedance mode. + - bias-pull-up: Enable weak pull-up. + - bias-pull-down: Enable weak pull-down. + - bias-bus-hold: Enable bus-keeper mode. + - drive-strength: Drive strength in mA. Supported values: 2, 4, 8, 12. + - input-schmitt-enable: Enable Schmitt trigger. + - input-schmitt-disable: Disable Schmitt trigger. + - slew-rate: Slew rate control. 0 for slow, 1 for fast. + +Pin Functions +--- --------- +mfio0 spim1 +mfio1 spim1, spim0, uart1 +mfio2 spim1, spim0, uart1 +mfio3 spim1 +mfio4 spim1 +mfio5 spim1 +mfio6 spim1 +mfio7 spim1 +mfio8 spim0 +mfio9 spim0 +mfio10 spim0 +mfio11 spis +mfio12 spis +mfio13 spis +mfio14 spis +mfio15 sdhost, mips_trace_clk, mips_trace_data +mfio16 sdhost, mips_trace_dint, mips_trace_data +mfio17 sdhost, mips_trace_trigout, mips_trace_data +mfio18 sdhost, mips_trace_trigin, mips_trace_data +mfio19 sdhost, mips_trace_dm, mips_trace_data +mfio20 sdhost, mips_trace_probe_n, mips_trace_data +mfio21 sdhost, mips_trace_data +mfio22 sdhost, mips_trace_data +mfio23 sdhost +mfio24 sdhost +mfio25 sdhost +mfio26 sdhost +mfio27 sdhost +mfio28 i2c0, spim0 +mfio29 i2c0, spim0 +mfio30 i2c1, spim0 +mfio31 i2c1, spim1 +mfio32 i2c2 +mfio33 i2c2 +mfio34 i2c3 +mfio35 i2c3 +mfio36 i2s_out, audio_clk_in +mfio37 i2s_out, debug_raw_cca_ind +mfio38 i2s_out, debug_ed_sec20_cca_ind +mfio39 i2s_out, debug_ed_sec40_cca_ind +mfio40 i2s_out, debug_agc_done_0 +mfio41 i2s_out, debug_agc_done_1 +mfio42 i2s_out, debug_ed_cca_ind +mfio43 i2s_out, debug_s2l_done +mfio44 i2s_out +mfio45 i2s_dac_clk, audio_sync +mfio46 audio_trigger +mfio47 i2s_in +mfio48 i2s_in +mfio49 i2s_in +mfio50 i2s_in +mfio51 i2s_in +mfio52 i2s_in +mfio53 i2s_in +mfio54 i2s_in, spdif_in +mfio55 uart0, spim0, spim1 +mfio56 uart0, spim0, spim1 +mfio57 uart0, spim0, spim1 +mfio58 uart0, spim1 +mfio59 uart1 +mfio60 uart1 +mfio61 spdif_out +mfio62 spdif_in +mfio63 eth, mips_trace_clk, mips_trace_data +mfio64 eth, mips_trace_dint, mips_trace_data +mfio65 eth, mips_trace_trigout, mips_trace_data +mfio66 eth, mips_trace_trigin, mips_trace_data +mfio67 eth, mips_trace_dm, mips_trace_data +mfio68 eth, mips_trace_probe_n, mips_trace_data +mfio69 eth, mips_trace_data +mfio70 eth, mips_trace_data +mfio71 eth +mfio72 ir +mfio73 pwmpdm, mips_trace_clk, sram_debug +mfio74 pwmpdm, mips_trace_dint, sram_debug +mfio75 pwmpdm, mips_trace_trigout, rom_debug +mfio76 pwmpdm, mips_trace_trigin, rom_debug +mfio77 mdc_debug, mips_trace_dm, rpu_debug +mfio78 mdc_debug, mips_trace_probe_n, rpu_debug +mfio79 ddr_debug, mips_trace_data, mips_debug +mfio80 ddr_debug, mips_trace_data, mips_debug +mfio81 dreq0, mips_trace_data, eth_debug +mfio82 dreq1, mips_trace_data, eth_debug +mfio83 mips_pll_lock, mips_trace_data, usb_debug +mfio84 audio_pll_lock, mips_trace_data, usb_debug +mfio85 rpu_v_pll_lock, mips_trace_data, sdhost_debug +mfio86 rpu_l_pll_lock, mips_trace_data, sdhost_debug +mfio87 sys_pll_lock, dreq2, socif_debug +mfio88 wifi_pll_lock, dreq3, socif_debug +mfio89 bt_pll_lock, dreq4, dreq5 +tck +trstn +tdi +tms +tdo +jtag_comply +safe_mode +por_disable +resetn + +Example: +-------- +pinctrl@18101c00 { + compatible = "img,pistachio-system-pinctrl"; + reg = <0x18101C00 0x400>; + + gpio0: gpio0 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ... + + gpio5: gpio5 { + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ... + + uart0_xfer: uart0-xfer { + uart0-rxd { + pins = "mfio55"; + function = "uart0"; + }; + uart0-txd { + pins = "mfio56"; + function = "uart0"; + }; + }; + + uart0_rts_cts: uart0-rts-cts { + uart0-rts { + pins = "mfio57"; + function = "uart0"; + }; + uart0-cts { + pins = "mfio58"; + function = "uart0"; + }; + }; +}; + +uart@... { + ... + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer>, <&uart0_rts_cts>; + ... +}; + +usb_vbus: fixed-regulator { + ... + gpio = <&gpio5 6 GPIO_ACTIVE_HIGH>; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/ingenic,pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ingenic,pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca313a7aeaff67837d551e77b04edaabbfbf1ac7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ingenic,pinctrl.txt @@ -0,0 +1,41 @@ +Ingenic jz47xx pin controller + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may +be used as GPIOs, multiplexed device functions are configured within the +GPIO port configuration registers and it is typical to refer to pins using the +naming scheme "PxN" where x is a character identifying the GPIO port with +which the pin is associated and N is an integer from 0 to 31 identifying the +pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and +PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to +PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a +total of 192 pins. + + +Required properties: +-------------------- + + - compatible: One of: + - "ingenic,jz4740-pinctrl" + - "ingenic,jz4770-pinctrl" + - "ingenic,jz4780-pinctrl" + - reg: Address range of the pinctrl registers. + + +GPIO sub-nodes +-------------- + +The pinctrl node can have optional sub-nodes for the Ingenic GPIO driver; +please refer to ../gpio/ingenic,gpio.txt. + + +Example: +-------- + +pinctrl: pin-controller@10010000 { + compatible = "ingenic,jz4740-pinctrl"; + reg = <0x10010000 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/lantiq,pinctrl-falcon.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/lantiq,pinctrl-falcon.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac4da9fe07bd1fe28d2ceabacbca5453ff41e7a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/lantiq,pinctrl-falcon.txt @@ -0,0 +1,83 @@ +Lantiq FALCON pinmux controller + +Required properties: +- compatible: "lantiq,pinctrl-falcon" +- reg: Should contain the physical address and length of the gpio/pinmux + register range + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Lantiq's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those group(s), and two pin configuration parameters: +pull-up and open-drain + +The name of each subnode is not important as long as it is unique; all subnodes +should be enumerated and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +We support 2 types of nodes. + +Definition of mux function groups: + +Required subnode-properties: +- lantiq,groups : An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. +- lantiq,function: A string containing the name of the function to mux to the + group. Valid values for function names are listed below. + +Valid values for group and function names: + + mux groups: + por, ntr, ntr8k, hrst, mdio, bootled, asc0, spi, spi cs0, spi cs1, i2c, + jtag, slic, pcm, asc1 + + functions: + rst, ntr, mdio, led, asc, spi, i2c, jtag, slic, pcm + + +Definition of pin configurations: + +Required subnode-properties: +- lantiq,pins : An array of strings. Each string contains the name of a pin. + Valid values for these names are listed below. + +Optional subnode-properties: +- lantiq,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down +- lantiq,drive-current: Boolean, enables drive-current +- lantiq,slew-rate: Boolean, enables slew-rate + +Example: + pinmux0 { + compatible = "lantiq,pinctrl-falcon"; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinmux { + asc0 { + lantiq,groups = "asc0"; + lantiq,function = "asc"; + }; + ntr { + lantiq,groups = "ntr8k"; + lantiq,function = "ntr"; + }; + i2c { + lantiq,groups = "i2c"; + lantiq,function = "i2c"; + }; + hrst { + lantiq,groups = "hrst"; + lantiq,function = "rst"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/lantiq,pinctrl-xway.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/lantiq,pinctrl-xway.txt new file mode 100644 index 0000000000000000000000000000000000000000..4658f105fa09e43f0b24731207ddb344194fa217 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/lantiq,pinctrl-xway.txt @@ -0,0 +1,191 @@ +Lantiq XWAY pinmux controller + +Required properties: +- compatible: "lantiq,pinctrl-xway", (DEPRECATED: Use "lantiq,pinctrl-danube") + "lantiq,pinctrl-xr9", (DEPRECATED: Use "lantiq,xrx100-pinctrl" or + "lantiq,xrx200-pinctrl") + "lantiq,pinctrl-ase", (DEPRECATED: Use "lantiq,ase-pinctrl") + "lantiq,-pinctrl", where is: + "ase" (XWAY AMAZON Family) + "danube" (XWAY DANUBE Family) + "xrx100" (XWAY xRX100 Family) + "xrx200" (XWAY xRX200 Family) + "xrx300" (XWAY xRX300 Family) +- reg: Should contain the physical address and length of the gpio/pinmux + register range + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Lantiq's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those group(s), and two pin configuration parameters: +pull-up and open-drain + +The name of each subnode is not important as long as it is unique; all subnodes +should be enumerated and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +We support 2 types of nodes. + +Definition of mux function groups: + +Required subnode-properties: +- lantiq,groups : An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. +- lantiq,function: A string containing the name of the function to mux to the + group. Valid values for function names are listed below. + +Valid values for group and function names: + +XWAY: (DEPRECATED: Use DANUBE) + mux groups: + exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1, + ebu wait, nand ale, nand cs1, nand cle, spi, spi_cs1, spi_cs2, spi_cs3, + spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, + gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, req1, req2, + req3 + + functions: + spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu + +XR9: ( DEPRECATED: Use xRX100/xRX200) + mux groups: + exin0, exin1, exin2, exin3, exin4, jtag, ebu a23, ebu a24, ebu a25, + ebu clk, ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, + nand rd, spi, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6, + asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1, + clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio, + gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2 + + functions: + spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio, gphy + +AMAZON: + mux groups: + exin0, exin1, exin2, jtag, spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, + spi_cs3, spi_cs4, spi_cs5, spi_cs6, asc, stp, gpt1, gpt2, gpt3, clkout0, + clkout1, clkout2, mdio, dfe led0, dfe led1, ephy led0, ephy led1, ephy led2 + + functions: + spi, asc, cgu, jtag, exin, stp, gpt, mdio, ephy, dfe + +DANUBE: + mux groups: + exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1, + ebu wait, nand ale, nand cs1, nand cle, spi_di, spi_do, spi_clk, spi_cs1, + spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi, + gpt1, gpt2, gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, + req1, req2, req3, dfe led0, dfe led1 + + functions: + spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, dfe + +xRX100: + mux groups: + exin0, exin1, exin2, exin3, exin4, ebu a23, ebu a24, ebu a25, ebu clk, + ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, nand rd, + spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5, + spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1, + clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio, + dfe led0, dfe led1 + + functions: + spi, asc, cgu, exin, stp, gpt, nmi, pci, ebu, mdio, dfe + +xRX200: + mux groups: + exin0, exin1, exin2, exin3, exin4, ebu a23, ebu a24, ebu a25, ebu clk, + ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, nand rd, + spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5, + spi_cs6, usif uart_rx, usif uart_tx, usif uart_rts, usif uart_cts, + usif uart_dtr, usif uart_dsr, usif uart_dcd, usif uart_ri, usif spi_di, + usif spi_do, usif spi_clk, usif spi_cs0, usif spi_cs1, usif spi_cs2, + stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, + gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio, dfe led0, dfe led1, + gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2 + + functions: + spi, usif, cgu, exin, stp, gpt, nmi, pci, ebu, mdio, dfe, gphy + +xRX300: + mux groups: + exin0, exin1, exin2, exin4, nand ale, nand cs0, nand cs1, nand cle, + nand rdy, nand rd, nand_d0, nand_d1, nand_d2, nand_d3, nand_d4, nand_d5, + nand_d6, nand_d7, nand_d1, nand wr, nand wp, nand se, spi_di, spi_do, + spi_clk, spi_cs1, spi_cs4, spi_cs6, usif uart_rx, usif uart_tx, + usif spi_di, usif spi_do, usif spi_clk, usif spi_cs0, stp, clkout2, + mdio, dfe led0, dfe led1, ephy0 led0, ephy0 led1, ephy1 led0, ephy1 led1 + + functions: + spi, usif, cgu, exin, stp, ebu, mdio, dfe, ephy + + +Definition of pin configurations: + +Required subnode-properties: +- lantiq,pins : An array of strings. Each string contains the name of a pin. + Valid values for these names are listed below. + +Optional subnode-properties: +- lantiq,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- lantiq,open-drain: Boolean, enables open-drain on the defined pin. + +Valid values for XWAY pin names: (DEPRECATED: Use DANUBE) + Pinconf pins can be referenced via the names io0-io31. + +Valid values for XR9 pin names: (DEPRECATED: Use xrX100/xRX200) + Pinconf pins can be referenced via the names io0-io55. + +Valid values for AMAZON pin names: + Pinconf pins can be referenced via the names io0-io31. + +Valid values for DANUBE pin names: + Pinconf pins can be referenced via the names io0-io31. + +Valid values for xRX100 pin names: + Pinconf pins can be referenced via the names io0-io55. + +Valid values for xRX200 pin names: + Pinconf pins can be referenced via the names io0-io49. + +Valid values for xRX300 pin names: + Pinconf pins can be referenced via the names io0-io1,io3-io6,io8-io11, + io13-io19,io23-io27,io34-io36, + io42-io43,io48-io61. + +Example: + gpio: pinmux@e100b10 { + compatible = "lantiq,danube-pinctrl"; + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + #gpio-cells = <2>; + gpio-controller; + reg = <0xE100B10 0xA0>; + + state_default: pinmux { + stp { + lantiq,groups = "stp"; + lantiq,function = "stp"; + }; + pci { + lantiq,groups = "gnt1"; + lantiq,function = "pci"; + }; + conf_out { + lantiq,pins = "io4", "io5", "io6"; /* stp */ + lantiq,open-drain; + lantiq,pull = <0>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-370-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-370-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..8662f3aaf312d9484a8e74373a5971a47d6b908a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-370-pinctrl.txt @@ -0,0 +1,99 @@ +* Marvell Armada 370 SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f6710-pinctrl" +- reg: register specifier of MPP registers + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, uart0(rxd) +mpp1 1 gpo, uart0(txd) +mpp2 2 gpio, i2c0(sck), uart0(txd) +mpp3 3 gpio, i2c0(sda), uart0(rxd) +mpp4 4 gpio, vdd(cpu-pd) +mpp5 5 gpo, ge0(txclkout), uart1(txd), spi1(sck), audio(mclk) +mpp6 6 gpio, ge0(txd0), sata0(prsnt), tdm(rst), audio(sdo) +mpp7 7 gpo, ge0(txd1), tdm(dtx), audio(lrclk) +mpp8 8 gpio, ge0(txd2), uart0(rts), tdm(drx), audio(bclk) +mpp9 9 gpo, ge0(txd3), uart1(txd), sd0(clk), audio(spdifo) +mpp10 10 gpio, ge0(txctl), uart0(cts), tdm(fsync), audio(sdi) +mpp11 11 gpio, ge0(rxd0), uart1(rxd), sd0(cmd), spi0(cs1), + sata1(prsnt), spi1(cs1) +mpp12 12 gpio, ge0(rxd1), i2c1(sda), sd0(d0), spi1(cs0), + audio(spdifi) +mpp13 13 gpio, ge0(rxd2), i2c1(sck), sd0(d1), tdm(pclk), + audio(rmclk) +mpp14 14 gpio, ge0(rxd3), pcie(clkreq0), sd0(d2), spi1(mosi), + spi0(cs2) +mpp15 15 gpio, ge0(rxctl), pcie(clkreq1), sd0(d3), spi1(miso), + spi0(cs3) +mpp16 16 gpio, ge0(rxclk), uart1(rxd), tdm(int), audio(extclk) +mpp17 17 gpo, ge(mdc) +mpp18 18 gpio, ge(mdio) +mpp19 19 gpio, ge0(txclk), ge1(txclkout), tdm(pclk) +mpp20 20 gpo, ge0(txd4), ge1(txd0) +mpp21 21 gpo, ge0(txd5), ge1(txd1), uart1(txd) +mpp22 22 gpo, ge0(txd6), ge1(txd2), uart0(rts) +mpp23 23 gpo, ge0(txd7), ge1(txd3), spi1(mosi) +mpp24 24 gpio, ge0(col), ge1(txctl), spi1(cs0) +mpp25 25 gpio, ge0(rxerr), ge1(rxd0), uart1(rxd) +mpp26 26 gpio, ge0(crs), ge1(rxd1), spi1(miso) +mpp27 27 gpio, ge0(rxd4), ge1(rxd2), uart0(cts) +mpp28 28 gpio, ge0(rxd5), ge1(rxd3) +mpp29 29 gpio, ge0(rxd6), ge1(rxctl), i2c1(sda) +mpp30 30 gpio, ge0(rxd7), ge1(rxclk), i2c1(sck) +mpp31 31 gpio, tclk, ge0(txerr) +mpp32 32 gpio, spi0(cs0) +mpp33 33 gpio, dev(bootcs), spi0(cs0) +mpp34 34 gpo, dev(we0), spi0(mosi) +mpp35 35 gpo, dev(oe), spi0(sck) +mpp36 36 gpo, dev(a1), spi0(miso) +mpp37 37 gpo, dev(a0), sata0(prsnt) +mpp38 38 gpio, dev(ready), uart1(cts), uart0(cts) +mpp39 39 gpo, dev(ad0), audio(spdifo) +mpp40 40 gpio, dev(ad1), uart1(rts), uart0(rts) +mpp41 41 gpio, dev(ad2), uart1(rxd) +mpp42 42 gpo, dev(ad3), uart1(txd) +mpp43 43 gpo, dev(ad4), audio(bclk) +mpp44 44 gpo, dev(ad5), audio(mclk) +mpp45 45 gpo, dev(ad6), audio(lrclk) +mpp46 46 gpo, dev(ad7), audio(sdo) +mpp47 47 gpo, dev(ad8), sd0(clk), audio(spdifo) +mpp48 48 gpio, dev(ad9), uart0(rts), sd0(cmd), sata1(prsnt), + spi0(cs1) +mpp49 49 gpio, dev(ad10), pcie(clkreq1), sd0(d0), spi1(cs0), + audio(spdifi) +mpp50 50 gpio, dev(ad11), uart0(cts), sd0(d1), spi1(miso), + audio(rmclk) +mpp51 51 gpio, dev(ad12), i2c1(sda), sd0(d2), spi1(mosi) +mpp52 52 gpio, dev(ad13), i2c1(sck), sd0(d3), spi1(sck) +mpp53 53 gpio, dev(ad14), sd0(clk), tdm(pclk), spi0(cs2), + pcie(clkreq1) +mpp54 54 gpo, dev(ad15), tdm(dtx) +mpp55 55 gpio, dev(cs1), uart1(txd), tdm(rst), sata1(prsnt), + sata0(prsnt) +mpp56 56 gpio, dev(cs2), uart1(cts), uart0(cts), spi0(cs3), + pcie(clkreq0), spi1(cs1) +mpp57 57 gpio, dev(cs3), uart1(rxd), tdm(fsync), sata0(prsnt), + audio(sdo) +mpp58 58 gpio, dev(cs0), uart1(rts), tdm(int), audio(extclk), + uart0(rts) +mpp59 59 gpo, dev(ale0), uart1(rts), uart0(rts), audio(bclk) +mpp60 60 gpio, dev(ale1), uart1(rxd), sata0(prsnt), pcie(rstout), + audio(sdi) +mpp61 61 gpo, dev(we1), uart1(txd), audio(lrclk) +mpp62 62 gpio, dev(a2), uart1(cts), tdm(drx), pcie(clkreq0), + audio(mclk), uart0(cts) +mpp63 63 gpio, spi0(sck), tclk +mpp64 64 gpio, spi0(miso), spi0(cs1) +mpp65 65 gpio, spi0(mosi), spi0(cs2) + +Note: According to the datasheet mpp63 is a gpo but there is at least +one example of a gpio usage on the board D-Link DNS-327L diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-375-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-375-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..06e5bb0367f5270fcbe959de96a778e59ce02ecb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-375-pinctrl.txt @@ -0,0 +1,82 @@ +* Marvell Armada 375 SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f6720-pinctrl" +- reg: register specifier of MPP registers + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, dev(ad2), spi0(cs1), spi1(cs1) +mpp1 1 gpio, dev(ad3), spi0(mosi), spi1(mosi) +mpp2 2 gpio, dev(ad4), ptp(evreq), led(c0), audio(sdi) +mpp3 3 gpio, dev(ad5), ptp(trig), led(p3), audio(mclk) +mpp4 4 gpio, dev(ad6), spi0(miso), spi1(miso) +mpp5 5 gpio, dev(ad7), spi0(cs2), spi1(cs2) +mpp6 6 gpio, dev(ad0), led(p1), audio(lrclk) +mpp7 7 gpio, dev(ad1), ptp(clk), led(p2), audio(extclk) +mpp8 8 gpio, dev (bootcs), spi0(cs0), spi1(cs0) +mpp9 9 gpio, spi0(sck), spi1(sck), nand(we) +mpp10 10 gpio, dram(vttctrl), led(c1), nand(re) +mpp11 11 gpio, dev(a0), led(c2), audio(sdo) +mpp12 12 gpio, dev(a1), audio(bclk) +mpp13 13 gpio, dev(ready), pcie0(rstout), pcie1(rstout) +mpp14 14 gpio, i2c0(sda), uart1(txd) +mpp15 15 gpio, i2c0(sck), uart1(rxd) +mpp16 16 gpio, uart0(txd) +mpp17 17 gpio, uart0(rxd) +mpp18 18 gpio, tdm(int) +mpp19 19 gpio, tdm(rst) +mpp20 20 gpio, tdm(pclk) +mpp21 21 gpio, tdm(fsync) +mpp22 22 gpio, tdm(drx) +mpp23 23 gpio, tdm(dtx) +mpp24 24 gpio, led(p0), ge1(rxd0), sd(cmd), uart0(rts) +mpp25 25 gpio, led(p2), ge1(rxd1), sd(d0), uart0(cts) +mpp26 26 gpio, pcie0(clkreq), ge1(rxd2), sd(d2), uart1(rts) +mpp27 27 gpio, pcie1(clkreq), ge1(rxd3), sd(d1), uart1(cts) +mpp28 28 gpio, led(p3), ge1(txctl), sd(clk) +mpp29 29 gpio, pcie1(clkreq), ge1(rxclk), sd(d3) +mpp30 30 gpio, ge1(txd0), spi1(cs0) +mpp31 31 gpio, ge1(txd1), spi1(mosi) +mpp32 32 gpio, ge1(txd2), spi1(sck), ptp(trig) +mpp33 33 gpio, ge1(txd3), spi1(miso) +mpp34 34 gpio, ge1(txclkout), spi1(sck) +mpp35 35 gpio, ge1(rxctl), spi1(cs1), spi0(cs2) +mpp36 36 gpio, pcie0(clkreq) +mpp37 37 gpio, pcie0(clkreq), tdm(int), ge(mdc) +mpp38 38 gpio, pcie1(clkreq), ge(mdio) +mpp39 39 gpio, ref(clkout) +mpp40 40 gpio, uart1(txd) +mpp41 41 gpio, uart1(rxd) +mpp42 42 gpio, spi1(cs2), led(c0) +mpp43 43 gpio, sata0(prsnt), dram(vttctrl) +mpp44 44 gpio, sata0(prsnt) +mpp45 45 gpio, spi0(cs2), pcie0(rstout) +mpp46 46 gpio, led(p0), ge0(txd0), ge1(txd0), dev(we1) +mpp47 47 gpio, led(p1), ge0(txd1), ge1(txd1) +mpp48 48 gpio, led(p2), ge0(txd2), ge1(txd2) +mpp49 49 gpio, led(p3), ge0(txd3), ge1(txd3) +mpp50 50 gpio, led(c0), ge0(rxd0), ge1(rxd0) +mpp51 51 gpio, led(c1), ge0(rxd1), ge1(rxd1) +mpp52 52 gpio, led(c2), ge0(rxd2), ge1(rxd2) +mpp53 53 gpio, pcie1(rstout), ge0(rxd3), ge1(rxd3) +mpp54 54 gpio, pcie0(rstout), ge0(rxctl), ge1(rxctl) +mpp55 55 gpio, ge0(rxclk), ge1(rxclk) +mpp56 56 gpio, ge0(txclkout), ge1(txclkout) +mpp57 57 gpio, ge0(txctl), ge1(txctl), dev(we0) +mpp58 58 gpio, led(c0) +mpp59 59 gpio, led(c1) +mpp60 60 gpio, uart1(txd), led(c2) +mpp61 61 gpio, i2c1(sda), uart1(rxd), spi1(cs2), led(p0) +mpp62 62 gpio, i2c1(sck), led(p1) +mpp63 63 gpio, ptp(trig), led(p2), dev(burst/last) +mpp64 64 gpio, dram(vttctrl), led(p3) +mpp65 65 gpio, sata1(prsnt) +mpp66 66 gpio, ptp(evreq), spi1(cs3) diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7c088d2dd503df005904b46a486d75e437e37e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt @@ -0,0 +1,183 @@ +* Marvell Armada 37xx SoC pin and gpio controller + +Each Armada 37xx SoC come with two pin and gpio controller one for the +south bridge and the other for the north bridge. + +Inside this set of register the gpio latch allows exposing some +configuration of the SoC and especially the clock frequency of the +xtal. Hence, this node is a represent as syscon allowing sharing the +register between multiple hardware block. + +GPIO and pin controller: +------------------------ + +Main node: + +Refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning +of the phrase "pin configuration node". + +Required properties for pinctrl driver: + +- compatible: "marvell,armada3710-sb-pinctrl", "syscon, "simple-mfd" + for the south bridge + "marvell,armada3710-nb-pinctrl", "syscon, "simple-mfd" + for the north bridge +- reg: The first set of register are for pinctrl/gpio and the second + set for the interrupt controller +- interrupts: list of the interrupt use by the gpio + +Available groups and functions for the North bridge: + +group: jtag + - pins 20-24 + - functions jtag, gpio + +group sdio0 + - pins 8-10 + - functions sdio, gpio + +group emmc_nb + - pins 27-35 + - functions emmc, gpio + +group pwm0 + - pin 11 (GPIO1-11) + - functions pwm, gpio + +group pwm1 + - pin 12 + - functions pwm, gpio + +group pwm2 + - pin 13 + - functions pwm, gpio + +group pwm3 + - pin 14 + - functions pwm, gpio + +group pmic1 + - pin 17 + - functions pmic, gpio + +group pmic0 + - pin 16 + - functions pmic, gpio + +group i2c2 + - pins 2-3 + - functions i2c, gpio + +group i2c1 + - pins 0-1 + - functions i2c, gpio + +group spi_cs1 + - pin 17 + - functions spi, gpio + +group spi_cs2 + - pin 18 + - functions spi, gpio + +group spi_cs3 + - pin 19 + - functions spi, gpio + +group onewire + - pin 4 + - functions onewire, gpio + +group uart1 + - pins 25-26 + - functions uart, gpio + +group spi_quad + - pins 15-16 + - functions spi, gpio + +group uart2 + - pins 9-10 and 18-19 + - functions uart, gpio + +Available groups and functions for the South bridge: + +group usb32_drvvbus0 + - pin 36 + - functions drvbus, gpio + +group usb2_drvvbus1 + - pin 37 + - functions drvbus, gpio + +group sdio_sb + - pins 60-64 + - functions sdio, gpio + +group rgmii + - pins 42-55 + - functions mii, gpio + +group pcie1 + - pins 39-40 + - functions pcie, gpio + +group ptp + - pins 56-58 + - functions ptp, gpio + +group ptp_clk + - pin 57 + - functions ptp, mii + +group ptp_trig + - pin 58 + - functions ptp, mii + +group mii_col + - pin 59 + - functions mii, mii_err + +GPIO subnode: + +Please refer to gpio.txt in this directory for details of gpio-ranges property +and the common GPIO bindings used by client devices. + +Required properties for gpio driver under the gpio subnode: +- interrupts: List of interrupt specifier for the controllers interrupt. +- gpio-controller: Marks the device node as a gpio controller. +- #gpio-cells: Should be 2. The first cell is the GPIO number and the + second cell specifies GPIO flags, as defined in + . Only the GPIO_ACTIVE_HIGH and + GPIO_ACTIVE_LOW flags are supported. +- gpio-ranges: Range of pins managed by the GPIO controller. + +Xtal Clock bindings for Marvell Armada 37xx SoCs +------------------------------------------------ + +see Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt + + +Example: +pinctrl_sb: pinctrl-sb@18800 { + compatible = "marvell,armada3710-sb-pinctrl", "syscon", "simple-mfd"; + reg = <0x18800 0x100>, <0x18C00 0x20>; + gpio { + #gpio-cells = <2>; + gpio-ranges = <&pinctrl_sb 0 0 29>; + gpio-controller; + interrupts = + , + , + , + , + ; + }; + + rgmii_pins: mii-pins { + groups = "rgmii"; + function = "mii"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-38x-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-38x-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..54ec4c0a0d0edd51182f598ec5cafb015485876c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-38x-pinctrl.txt @@ -0,0 +1,80 @@ +* Marvell Armada 380/385 SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f6810-pinctrl", "marvell,88f6820-pinctrl" or + "marvell,88f6828-pinctrl" depending on the specific variant of the + SoC being used. +- reg: register specifier of MPP registers + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, ua0(rxd) +mpp1 1 gpio, ua0(txd) +mpp2 2 gpio, i2c0(sck) +mpp3 3 gpio, i2c0(sda) +mpp4 4 gpio, ge(mdc), ua1(txd), ua0(rts) +mpp5 5 gpio, ge(mdio), ua1(rxd), ua0(cts) +mpp6 6 gpio, ge0(txclkout), ge0(crs), dev(cs3) +mpp7 7 gpio, ge0(txd0), dev(ad9) +mpp8 8 gpio, ge0(txd1), dev(ad10) +mpp9 9 gpio, ge0(txd2), dev(ad11) +mpp10 10 gpio, ge0(txd3), dev(ad12) +mpp11 11 gpio, ge0(txctl), dev(ad13) +mpp12 12 gpio, ge0(rxd0), pcie0(rstout), spi0(cs1), dev(ad14), pcie3(clkreq) +mpp13 13 gpio, ge0(rxd1), pcie0(clkreq), pcie1(clkreq) [1], spi0(cs2), dev(ad15), pcie2(clkreq) +mpp14 14 gpio, ge0(rxd2), ptp(clk), dram(vttctrl), spi0(cs3), dev(we1), pcie3(clkreq) +mpp15 15 gpio, ge0(rxd3), ge(mdc slave), pcie0(rstout), spi0(mosi) +mpp16 16 gpio, ge0(rxctl), ge(mdio slave), dram(deccerr), spi0(miso), pcie0(clkreq), pcie1(clkreq) [1] +mpp17 17 gpio, ge0(rxclk), ptp(clk), ua1(rxd), spi0(sck), sata1(prsnt), sata0(prsnt) +mpp18 18 gpio, ge0(rxerr), ptp(trig), ua1(txd), spi0(cs0) +mpp19 19 gpio, ge0(col), ptp(evreq), ge0(txerr), sata1(prsnt), ua0(cts) +mpp20 20 gpio, ge0(txclk), ptp(clk), sata0(prsnt), ua0(rts) +mpp21 21 gpio, spi0(cs1), ge1(rxd0), sata0(prsnt), sd0(cmd), dev(bootcs), sata1(prsnt) +mpp22 22 gpio, spi0(mosi), dev(ad0) +mpp23 23 gpio, spi0(sck), dev(ad2) +mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready) +mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd0(d5), dev(cs0) +mpp26 26 gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1) +mpp27 27 gpio, spi0(cs3), ge1(txclkout), i2c1(sda), sd0(d7), dev(cs2) +mpp28 28 gpio, ge1(txd0), sd0(clk), dev(ad5) +mpp29 29 gpio, ge1(txd1), dev(ale0) +mpp30 30 gpio, ge1(txd2), dev(oe) +mpp31 31 gpio, ge1(txd3), dev(ale1) +mpp32 32 gpio, ge1(txctl), dev(we0) +mpp33 33 gpio, dram(deccerr), dev(ad3) +mpp34 34 gpio, dev(ad1) +mpp35 35 gpio, ref(clk_out1), dev(a1) +mpp36 36 gpio, ptp(trig), dev(a0) +mpp37 37 gpio, ptp(clk), ge1(rxclk), sd0(d3), dev(ad8) +mpp38 38 gpio, ptp(evreq), ge1(rxd1), ref(clk_out0), sd0(d0), dev(ad4) +mpp39 39 gpio, i2c1(sck), ge1(rxd2), ua0(cts), sd0(d1), dev(a2) +mpp40 40 gpio, i2c1(sda), ge1(rxd3), ua0(rts), sd0(d2), dev(ad6) +mpp41 41 gpio, ua1(rxd), ge1(rxctl), ua0(cts), spi1(cs3), dev(burst/last), nand(rb0) +mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7) +mpp43 43 gpio, pcie0(clkreq), dram(vttctrl), dram(deccerr), spi1(cs2), dev(clkout), nand(rb1) +mpp44 44 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [3] +mpp45 45 gpio, ref(clk_out0), pcie0(rstout), ua1(rxd) +mpp46 46 gpio, ref(clk_out1), pcie0(rstout), ua1(txd) +mpp47 47 gpio, sata0(prsnt), sata1(prsnt), sata2(prsnt) [2], sata3(prsnt) [2] +mpp48 48 gpio, sata0(prsnt), dram(vttctrl), tdm(pclk), audio(mclk), sd0(d4), pcie0(clkreq) +mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm(fsync), audio(lrclk), sd0(d5), pcie1(clkreq) +mpp50 50 gpio, pcie0(rstout), tdm(drx), audio(extclk), sd0(cmd) +mpp51 51 gpio, tdm(dtx), audio(sdo), dram(deccerr), ptp(trig) +mpp52 52 gpio, pcie0(rstout), tdm(int), audio(sdi), sd0(d6), ptp(clk) +mpp53 53 gpio, sata1(prsnt), sata0(prsnt), tdm(rst), audio(bclk), sd0(d7), ptp(evreq) +mpp54 54 gpio, sata0(prsnt), sata1(prsnt), pcie0(rstout), ge0(txerr), sd0(d3) +mpp55 55 gpio, ua1(cts), ge(mdio), pcie1(clkreq) [1], spi1(cs1), sd0(d0), ua1(rxd) +mpp56 56 gpio, ua1(rts), ge(mdc), dram(deccerr), spi1(mosi), ua1(txd) +mpp57 57 gpio, spi1(sck), sd0(clk), ua1(txd) +mpp58 58 gpio, pcie1(clkreq) [1], i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1), ua1(rxd) +mpp59 59 gpio, pcie0(rstout), i2c1(sda), spi1(cs0), sd0(d2) + +[1]: only available on 88F6820 and 88F6828 +[2]: only available on 88F6828 diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-39x-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-39x-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..a40b60f1ca4c42b2bef730065fcd4b405184ab0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-39x-pinctrl.txt @@ -0,0 +1,84 @@ +* Marvell Armada 39x SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f6920-pinctrl", "marvell,88f6925-pinctrl" or + "marvell,88f6928-pinctrl" depending on the specific variant of the + SoC being used. +- reg: register specifier of MPP registers + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +name pins functions +================================================================================ +mpp0 0 gpio, ua0(rxd) +mpp1 1 gpio, ua0(txd) +mpp2 2 gpio, i2c0(sck) +mpp3 3 gpio, i2c0(sda) +mpp4 4 gpio, ua1(txd), ua0(rts), smi(mdc) +mpp5 5 gpio, ua1(rxd), ua0(cts), smi(mdio) +mpp6 6 gpio, dev(cs3), xsmi(mdio) +mpp7 7 gpio, dev(ad9), xsmi(mdc) +mpp8 8 gpio, dev(ad10), ptp(trig) +mpp9 9 gpio, dev(ad11), ptp(clk) +mpp10 10 gpio, dev(ad12), ptp(evreq) +mpp11 11 gpio, dev(ad13), led(clk) +mpp12 12 gpio, pcie0(rstout), dev(ad14), led(stb) +mpp13 13 gpio, dev(ad15), pcie2(clkreq), led(data) +mpp14 14 gpio, dram(vttctrl), dev(we1), ua1(txd) +mpp15 15 gpio, pcie0(rstout), spi0(mosi), i2c1(sck) +mpp16 16 gpio, dram(deccerr), spi0(miso), pcie0(clkreq), i2c1(sda) +mpp17 17 gpio, ua1(rxd), spi0(sck), sata1(prsnt) [1], sata0(prsnt) [1], smi(mdio) +mpp18 18 gpio, ua1(txd), spi0(cs0), i2c2(sck) +mpp19 19 gpio, sata1(prsnt) [1], ua0(cts), ua1(rxd), i2c2(sda) +mpp20 20 gpio, sata0(prsnt) [1], ua0(rts), ua1(txd), smi(mdc) +mpp21 21 gpio, spi0(cs1), sata0(prsnt) [1], sd0(cmd), dev(bootcs), + sata1(prsnt) [1], ge(rxd0) +mpp22 22 gpio, spi0(mosi), dev(ad0) +mpp23 23 gpio, spi0(sck), dev(ad2) +mpp24 24 gpio, spi0(miso), ua0(cts), ua1(rxd), sd0(d4), dev(ready) +mpp25 25 gpio, spi0(cs0), ua0(rts), ua1(txd), sd0(d5), dev(cs0) +mpp26 26 gpio, spi0(cs2), i2c1(sck), sd0(d6), dev(cs1) +mpp27 27 gpio, spi0(cs3), i2c1(sda), sd0(d7), dev(cs2), ge(txclkout) +mpp28 28 gpio, sd0(clk), dev(ad5), ge(txd0) +mpp29 29 gpio, dev(ale0), ge(txd1) +mpp30 30 gpio, dev(oe), ge(txd2) +mpp31 31 gpio, dev(ale1), ge(txd3) +mpp32 32 gpio, dev(we0), ge(txctl) +mpp33 33 gpio, dram(deccerr), dev(ad3) +mpp34 34 gpio, dev(ad1) +mpp35 35 gpio, ref(clk), dev(a1) +mpp36 36 gpio, dev(a0) +mpp37 37 gpio, sd0(d3), dev(ad8), ge(rxclk) +mpp38 38 gpio, ref(clk), sd0(d0), dev(ad4), ge(rxd1) +mpp39 39 gpio, i2c1(sck), ua0(cts), sd0(d1), dev(a2), ge(rxd2) +mpp40 40 gpio, i2c1(sda), ua0(rts), sd0(d2), dev(ad6), ge(rxd3) +mpp41 41 gpio, ua1(rxd), ua0(cts), spi1(cs3), dev(burst/last), nand(rb0), ge(rxctl) +mpp42 42 gpio, ua1(txd), ua0(rts), dev(ad7) +mpp43 43 gpio, pcie0(clkreq), dram(vttctrl), dram(deccerr), spi1(cs2), dev(clkout), nand(rb1) +mpp44 44 gpio, sata0(prsnt) [1], sata1(prsnt) [1], sata2(prsnt) [2], + sata3(prsnt) [2], led(clk) +mpp45 45 gpio, ref(clk), pcie0(rstout), ua1(rxd) +mpp46 46 gpio, ref(clk), pcie0(rstout), ua1(txd), led(stb) +mpp47 47 gpio, sata0(prsnt) [1], sata1(prsnt) [1], sata2(prsnt) [2], + sata3(prsnt) [2], led(data) +mpp48 48 gpio, sata0(prsnt) [1], dram(vttctrl), tdm(pclk) [2], audio(mclk) [2], sd0(d4), pcie0(clkreq), ua1(txd) +mpp49 49 gpio, sata2(prsnt) [2], sata3(prsnt) [2], tdm(fsync) [2], + audio(lrclk) [2], sd0(d5), ua2(rxd) +mpp50 50 gpio, pcie0(rstout), tdm(drx) [2], audio(extclk) [2], sd0(cmd), ua2(rxd) +mpp51 51 gpio, tdm(dtx) [2], audio(sdo) [2], dram(deccerr), ua2(txd) +mpp52 52 gpio, pcie0(rstout), tdm(int) [2], audio(sdi) [2], sd0(d6), i2c3(sck) +mpp53 53 gpio, sata1(prsnt) [1], sata0(prsnt) [1], tdm(rst) [2], audio(bclk) [2], sd0(d7), i2c3(sda) +mpp54 54 gpio, sata0(prsnt) [1], sata1(prsnt) [1], pcie0(rstout), sd0(d3), ua3(txd) +mpp55 55 gpio, ua1(cts), spi1(cs1), sd0(d0), ua1(rxd), ua3(rxd) +mpp56 56 gpio, ua1(rts), dram(deccerr), spi1(mosi), ua1(txd) +mpp57 57 gpio, spi1(sck), sd0(clk), ua1(txd) +mpp58 58 gpio, i2c1(sck), pcie2(clkreq), spi1(miso), sd0(d1), ua1(rxd) +mpp59 59 gpio, pcie0(rstout), i2c1(sda), spi1(cs0), sd0(d2) + +[1]: only available on 88F6925/88F6928 +[2]: only available on 88F6928 diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..97aef67ee76917e83024c3061d7ed13ffe14c43a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt @@ -0,0 +1,46 @@ +* Marvell 98dx3236 pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage + +Required properties: +- compatible: "marvell,98dx3236-pinctrl" or "marvell,98dx4251-pinctrl" +- reg: register specifier of MPP registers + +This driver supports all 98dx3236, 98dx3336 and 98dx4251 variants + +name pins functions +================================================================================ +mpp0 0 gpo, spi0(mosi), dev(ad8) +mpp1 1 gpio, spi0(miso), dev(ad9) +mpp2 2 gpo, spi0(sck), dev(ad10) +mpp3 3 gpio, spi0(cs0), dev(ad11) +mpp4 4 gpio, spi0(cs1), smi(mdc), dev(cs0) +mpp5 5 gpio, pex(rsto), sd0(cmd), dev(bootcs) +mpp6 6 gpo, sd0(clk), dev(a2) +mpp7 7 gpio, sd0(d0), dev(ale0) +mpp8 8 gpio, sd0(d1), dev(ale1) +mpp9 9 gpio, sd0(d2), dev(ready0) +mpp10 10 gpio, sd0(d3), dev(ad12) +mpp11 11 gpio, uart1(rxd), uart0(cts), dev(ad13) +mpp12 12 gpo, uart1(txd), uart0(rts), dev(ad14) +mpp13 13 gpio, intr(out), dev(ad15) +mpp14 14 gpio, i2c0(sck) +mpp15 15 gpio, i2c0(sda) +mpp16 16 gpo, dev(oe) +mpp17 17 gpo, dev(clkout) +mpp18 18 gpio, uart1(txd) +mpp19 19 gpio, uart1(rxd), dev(rb) +mpp20 20 gpo, dev(we0) +mpp21 21 gpo, dev(ad0) +mpp22 22 gpo, dev(ad1) +mpp23 23 gpo, dev(ad2) +mpp24 24 gpo, dev(ad3) +mpp25 25 gpo, dev(ad4) +mpp26 26 gpo, dev(ad5) +mpp27 27 gpo, dev(ad6) +mpp28 28 gpo, dev(ad7) +mpp29 29 gpo, dev(a0) +mpp30 30 gpo, dev(a1) +mpp31 31 gpio, slv_smi(mdc), smi(mdc), dev(we1) +mpp32 32 gpio, slv_smi(mdio), smi(mdio), dev(cs1) diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-xp-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-xp-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..76da7222ff92d1139886692e6c7b3befd81be047 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,armada-xp-pinctrl.txt @@ -0,0 +1,99 @@ +* Marvell Armada XP SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,mv78230-pinctrl", "marvell,mv78260-pinctrl", + "marvell,mv78460-pinctrl" +- reg: register specifier of MPP registers + +This driver supports all Armada XP variants, i.e. mv78230, mv78260, and mv78460. + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +* Marvell Armada XP (all variants) + +name pins functions +================================================================================ +mpp0 0 gpio, ge0(txclkout), lcd(d0) +mpp1 1 gpio, ge0(txd0), lcd(d1) +mpp2 2 gpio, ge0(txd1), lcd(d2) +mpp3 3 gpio, ge0(txd2), lcd(d3) +mpp4 4 gpio, ge0(txd3), lcd(d4) +mpp5 5 gpio, ge0(txctl), lcd(d5) +mpp6 6 gpio, ge0(rxd0), lcd(d6) +mpp7 7 gpio, ge0(rxd1), lcd(d7) +mpp8 8 gpio, ge0(rxd2), lcd(d8) +mpp9 9 gpio, ge0(rxd3), lcd(d9) +mpp10 10 gpio, ge0(rxctl), lcd(d10) +mpp11 11 gpio, ge0(rxclk), lcd(d11) +mpp12 12 gpio, ge0(txd4), ge1(txclkout), lcd(d12) +mpp13 13 gpio, ge0(txd5), ge1(txd0), spi1(mosi), lcd(d13) +mpp14 14 gpio, ge0(txd6), ge1(txd1), spi1(sck), lcd(d15) +mpp15 15 gpio, ge0(txd7), ge1(txd2), lcd(d16) +mpp16 16 gpio, ge0(txd7), ge1(txd3), spi1(cs0), lcd(d16) +mpp17 17 gpio, ge0(col), ge1(txctl), spi1(miso), lcd(d17) +mpp18 18 gpio, ge0(rxerr), ge1(rxd0), lcd(d18), ptp(trig) +mpp19 19 gpio, ge0(crs), ge1(rxd1), lcd(d19), ptp(evreq) +mpp20 20 gpio, ge0(rxd4), ge1(rxd2), lcd(d20), ptp(clk) +mpp21 21 gpio, ge0(rxd5), ge1(rxd3), lcd(d21), dram(bat) +mpp22 22 gpio, ge0(rxd6), ge1(rxctl), lcd(d22), sata0(prsnt) +mpp23 23 gpio, ge0(rxd7), ge1(rxclk), lcd(d23), sata1(prsnt) +mpp24 24 gpio, lcd(hsync), sata1(prsnt), tdm(rst) +mpp25 25 gpio, lcd(vsync), sata0(prsnt), tdm(pclk) +mpp26 26 gpio, lcd(clk), tdm(fsync) +mpp27 27 gpio, lcd(e), tdm(dtx), ptp(trig) +mpp28 28 gpio, lcd(pwm), tdm(drx), ptp(evreq) +mpp29 29 gpio, lcd(ref-clk), tdm(int0), ptp(clk) +mpp30 30 gpio, tdm(int1), sd0(clk) +mpp31 31 gpio, tdm(int2), sd0(cmd) +mpp32 32 gpio, tdm(int3), sd0(d0) +mpp33 33 gpio, tdm(int4), sd0(d1), dram(bat), dram(vttctrl) +mpp34 34 gpio, tdm(int5), sd0(d2), sata0(prsnt), dram(deccerr) +mpp35 35 gpio, tdm(int6), sd0(d3), sata1(prsnt) +mpp36 36 gpio, spi0(mosi) +mpp37 37 gpio, spi0(miso) +mpp38 38 gpio, spi0(sck) +mpp39 39 gpio, spi0(cs0) +mpp40 40 gpio, spi0(cs1), uart2(cts), lcd(vga-hsync), pcie(clkreq0), + spi1(cs1) +mpp41 41 gpio, spi0(cs2), uart2(rts), lcd(vga-vsync), sata1(prsnt), + pcie(clkreq1), spi1(cs2) +mpp42 42 gpio, uart2(rxd), uart0(cts), tdm(int7), tdm(timer) +mpp43 43 gpio, uart2(txd), uart0(rts), spi0(cs3), pcie(rstout), + spi1(cs3) +mpp44 44 gpio, uart2(cts), uart3(rxd), spi0(cs4), pcie(clkreq2), + dram(bat), spi1(cs4) +mpp45 45 gpio, uart2(rts), uart3(txd), spi0(cs5), sata1(prsnt), + spi1(cs5), dram(vttctrl) +mpp46 46 gpio, uart3(rts), uart1(rts), spi0(cs6), sata0(prsnt), + spi1(cs6) +mpp47 47 gpio, uart3(cts), uart1(cts), spi0(cs7), pcie(clkreq3), + ref(clkout), spi1(cs7) +mpp48 48 gpio, dev(clkout), dev(burst/last), nand(rb) + +* Marvell Armada XP (mv78260 and mv78460 only) + +name pins functions +================================================================================ +mpp49 49 gpio, dev(we3) +mpp50 50 gpio, dev(we2) +mpp51 51 gpio, dev(ad16) +mpp52 52 gpio, dev(ad17) +mpp53 53 gpio, dev(ad18) +mpp54 54 gpio, dev(ad19) +mpp55 55 gpio, dev(ad20) +mpp56 56 gpio, dev(ad21) +mpp57 57 gpio, dev(ad22) +mpp58 58 gpio, dev(ad23) +mpp59 59 gpio, dev(ad24) +mpp60 60 gpio, dev(ad25) +mpp61 61 gpio, dev(ad26) +mpp62 62 gpio, dev(ad27) +mpp63 63 gpio, dev(ad28) +mpp64 64 gpio, dev(ad29) +mpp65 65 gpio, dev(ad30) +mpp66 66 gpio, dev(ad31) diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,dove-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,dove-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..cf52477cc7ee3affd5527ccfeaef0fd841e80cff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,dove-pinctrl.txt @@ -0,0 +1,90 @@ +* Marvell Dove SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,dove-pinctrl" +- clocks: (optional) phandle of pdma clock +- reg: register specifiers of MPP, MPP4, and PMU MPP registers + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. +Note: pmu* also allows for Power Management functions listed below + +name pins functions +================================================================================ +mpp0 0 gpio, pmu, uart2(rts), sdio0(cd), lcd0(pwm), pmu* +mpp1 1 gpio, pmu, uart2(cts), sdio0(wp), lcd1(pwm), pmu* +mpp2 2 gpio, pmu, uart2(txd), sdio0(buspwr), sata(prsnt), + uart1(rts), pmu* +mpp3 3 gpio, pmu, uart2(rxd), sdio0(ledctrl), sata(act), + uart1(cts), lcd-spi(cs1), pmu* +mpp4 4 gpio, pmu, uart3(rts), sdio1(cd), spi1(miso), pmu* +mpp5 5 gpio, pmu, uart3(cts), sdio1(wp), spi1(cs), pmu* +mpp6 6 gpio, pmu, uart3(txd), sdio1(buspwr), spi1(mosi), pmu* +mpp7 7 gpio, pmu, uart3(rxd), sdio1(ledctrl), spi1(sck), pmu* +mpp8 8 gpio, pmu, watchdog(rstout), pmu* +mpp9 9 gpio, pmu, pex1(clkreq), pmu* +mpp10 10 gpio, pmu, ssp(sclk), pmu* +mpp11 11 gpio, pmu, sata(prsnt), sata-1(act), sdio0(ledctrl), + sdio1(ledctrl), pex0(clkreq), pmu* +mpp12 12 gpio, pmu, uart2(rts), audio0(extclk), sdio1(cd), + sata(act), pmu* +mpp13 13 gpio, pmu, uart2(cts), audio1(extclk), sdio1(wp), + ssp(extclk), pmu* +mpp14 14 gpio, pmu, uart2(txd), sdio1(buspwr), ssp(rxd), pmu* +mpp15 15 gpio, pmu, uart2(rxd), sdio1(ledctrl), ssp(sfrm), pmu* +mpp16 16 gpio, uart3(rts), sdio0(cd), ac97(sdi1), lcd-spi(cs1) +mpp17 17 gpio, uart3(cts), sdio0(wp), ac97(sdi2), twsi(sda), + ac97-1(sysclko) +mpp18 18 gpio, uart3(txd), sdio0(buspwr), ac97(sdi3), lcd0(pwm) +mpp19 19 gpio, uart3(rxd), sdio0(ledctrl), twsi(sck) +mpp20 20 gpio, sdio0(cd), sdio1(cd), spi1(miso), lcd-spi(miso), + ac97(sysclko) +mpp21 21 gpio, sdio0(wp), sdio1(wp), spi1(cs), lcd-spi(cs0), + uart1(cts), ssp(sfrm) +mpp22 22 gpio, sdio0(buspwr), sdio1(buspwr), spi1(mosi), + lcd-spi(mosi), uart1(cts), ssp(txd) +mpp23 23 gpio, sdio0(ledctrl), sdio1(ledctrl), spi1(sck), + lcd-spi(sck), ssp(sclk) +mpp_camera 24-39 gpio, camera +mpp_sdio0 40-45 gpio, sdio0 +mpp_sdio1 46-51 gpio, sdio1 +mpp_audio1 52-57 gpio, i2s1/spdifo, i2s1, spdifo, twsi, ssp/spdifo, ssp, + ssp/twsi +mpp_spi0 58-61 gpio, spi0 +mpp_uart1 62-63 gpio, uart1 +mpp_nand 64-71 gpo, nand +audio0 - i2s, ac97 +twsi - none, opt1, opt2, opt3 + +Power Management functions (pmu*): +pmu-nc Pin not driven by any PM function +pmu-low Pin driven low (0) +pmu-high Pin driven high (1) +pmic(sdi) Pin is used for PMIC SDI +cpu-pwr-down Pin is used for CPU_PWRDWN +standby-pwr-down Pin is used for STBY_PWRDWN +core-pwr-good Pin is used for CORE_PWR_GOOD (Pins 0-7 only) +cpu-pwr-good Pin is used for CPU_PWR_GOOD (Pins 8-15 only) +bat-fault Pin is used for BATTERY_FAULT +ext0-wakeup Pin is used for EXT0_WU +ext1-wakeup Pin is used for EXT0_WU +ext2-wakeup Pin is used for EXT0_WU +pmu-blink Pin is used for blink function + +Notes: +* group "mpp_audio1" allows the following functions and gpio pins: + - gpio : gpio on pins 52-57 + - i2s1/spdifo : audio1 i2s on pins 52-55 and spdifo on 57, no gpios + - i2s1 : audio1 i2s on pins 52-55, gpio on pins 56,57 + - spdifo : spdifo on pin 57, gpio on pins 52-55 + - twsi : twsi on pins 56,57, gpio on pins 52-55 + - ssp/spdifo : ssp on pins 52-55, spdifo on pin 57, no gpios + - ssp : ssp on pins 52-55, gpio on pins 56,57 + - ssp/twsi : ssp on pins 52-55, twsi on pins 56,57, no gpios +* group "audio0" internally muxes i2s0 or ac97 controller to the dedicated + audio0 pins. +* group "twsi" internally muxes twsi controller to the dedicated or option pins. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,kirkwood-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,kirkwood-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..6c0ea155b708980c7a6cdaeeccc962bd383f66cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,kirkwood-pinctrl.txt @@ -0,0 +1,319 @@ +* Marvell Kirkwood SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f6180-pinctrl", + "marvell,88f6190-pinctrl", "marvell,88f6192-pinctrl", + "marvell,88f6281-pinctrl", "marvell,88f6282-pinctrl" + "marvell,98dx4122-pinctrl" +- reg: register specifier of MPP registers + +This driver supports all kirkwood variants, i.e. 88f6180, 88f619x, and 88f628x. +It also support the 88f6281-based variant in the 98dx412x Bobcat SoCs. + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +* Marvell Kirkwood 88f6180 + +name pins functions +================================================================================ +mpp0 0 gpio, nand(io2), spi(cs) +mpp1 1 gpo, nand(io3), spi(mosi) +mpp2 2 gpo, nand(io4), spi(sck) +mpp3 3 gpo, nand(io5), spi(miso) +mpp4 4 gpio, nand(io6), uart0(rxd), ptp(clk) +mpp5 5 gpo, nand(io7), uart0(txd), ptp(trig) +mpp6 6 sysrst(out), spi(mosi), ptp(trig) +mpp7 7 gpo, pex(rsto), spi(cs), ptp(trig) +mpp8 8 gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk), + mii(col) +mpp9 9 gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq), + mii(crs) +mpp10 10 gpo, spi(sck), uart0(txd), ptp(trig) +mpp11 11 gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq), + ptp-2(trig) +mpp12 12 gpo, sdio(clk) +mpp13 13 gpio, sdio(cmd), uart1(txd) +mpp14 14 gpio, sdio(d0), uart1(rxd), mii(col) +mpp15 15 gpio, sdio(d1), uart0(rts), uart1(txd) +mpp16 16 gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs) +mpp17 17 gpio, sdio(d3) +mpp18 18 gpo, nand(io0) +mpp19 19 gpo, nand(io1) +mpp35 35 gpio, mii(rxerr) +mpp36 36 gpio, audio(spdifi) +mpp37 37 gpio, audio(spdifo) +mpp38 38 gpio, audio(rmclk) +mpp39 39 gpio, audio(bclk) +mpp40 40 gpio, audio(sdo) +mpp41 41 gpio, audio(lrclk) +mpp42 42 gpio, audio(mclk) +mpp43 43 gpio, audio(sdi) +mpp44 44 gpio, audio(extclk) + +* Marvell Kirkwood 88f6190 + +name pins functions +================================================================================ +mpp0 0 gpio, nand(io2), spi(cs) +mpp1 1 gpo, nand(io3), spi(mosi) +mpp2 2 gpo, nand(io4), spi(sck) +mpp3 3 gpo, nand(io5), spi(miso) +mpp4 4 gpio, nand(io6), uart0(rxd), ptp(clk) +mpp5 5 gpo, nand(io7), uart0(txd), ptp(trig), sata0(act) +mpp6 6 sysrst(out), spi(mosi), ptp(trig) +mpp7 7 gpo, pex(rsto), spi(cs), ptp(trig) +mpp8 8 gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk), + mii(col), mii-1(rxerr) +mpp9 9 gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq), + mii(crs), sata0(prsnt) +mpp10 10 gpo, spi(sck), uart0(txd), ptp(trig) +mpp11 11 gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq), + ptp-2(trig), sata0(act) +mpp12 12 gpo, sdio(clk) +mpp13 13 gpio, sdio(cmd), uart1(txd) +mpp14 14 gpio, sdio(d0), uart1(rxd), mii(col) +mpp15 15 gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act) +mpp16 16 gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs) +mpp17 17 gpio, sdio(d3), sata0(prsnt) +mpp18 18 gpo, nand(io0) +mpp19 19 gpo, nand(io1) +mpp20 20 gpio, ge1(txd0) +mpp21 21 gpio, ge1(txd1), sata0(act) +mpp22 22 gpio, ge1(txd2) +mpp23 23 gpio, ge1(txd3), sata0(prsnt) +mpp24 24 gpio, ge1(rxd0) +mpp25 25 gpio, ge1(rxd1) +mpp26 26 gpio, ge1(rxd2) +mpp27 27 gpio, ge1(rxd3) +mpp28 28 gpio, ge1(col) +mpp29 29 gpio, ge1(txclk) +mpp30 30 gpio, ge1(rxclk) +mpp31 31 gpio, ge1(rxclk) +mpp32 32 gpio, ge1(txclko) +mpp33 33 gpo, ge1(txclk) +mpp34 34 gpio, ge1(txen) +mpp35 35 gpio, ge1(rxerr), sata0(act), mii(rxerr) + +* Marvell Kirkwood 88f6192 + +name pins functions +================================================================================ +mpp0 0 gpio, nand(io2), spi(cs) +mpp1 1 gpo, nand(io3), spi(mosi) +mpp2 2 gpo, nand(io4), spi(sck) +mpp3 3 gpo, nand(io5), spi(miso) +mpp4 4 gpio, nand(io6), uart0(rxd), ptp(clk), sata1(act) +mpp5 5 gpo, nand(io7), uart0(txd), ptp(trig), sata0(act) +mpp6 6 sysrst(out), spi(mosi), ptp(trig) +mpp7 7 gpo, pex(rsto), spi(cs), ptp(trig) +mpp8 8 gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk), + mii(col), mii-1(rxerr), sata1(prsnt) +mpp9 9 gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq), + mii(crs), sata0(prsnt) +mpp10 10 gpo, spi(sck), uart0(txd), ptp(trig), sata1(act) +mpp11 11 gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq), + ptp-2(trig), sata0(act) +mpp12 12 gpo, sdio(clk) +mpp13 13 gpio, sdio(cmd), uart1(txd) +mpp14 14 gpio, sdio(d0), uart1(rxd), mii(col), sata1(prsnt) +mpp15 15 gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act) +mpp16 16 gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs), + sata1(act) +mpp17 17 gpio, sdio(d3), sata0(prsnt) +mpp18 18 gpo, nand(io0) +mpp19 19 gpo, nand(io1) +mpp20 20 gpio, ge1(txd0), ts(mp0), tdm(tx0ql), audio(spdifi), + sata1(act) +mpp21 21 gpio, ge1(txd1), sata0(act), ts(mp1), tdm(rx0ql), + audio(spdifo) +mpp22 22 gpio, ge1(txd2), ts(mp2), tdm(tx2ql), audio(rmclk), + sata1(prsnt) +mpp23 23 gpio, ge1(txd3), sata0(prsnt), ts(mp3), tdm(rx2ql), + audio(bclk) +mpp24 24 gpio, ge1(rxd0), ts(mp4), tdm(spi-cs0), audio(sdo) +mpp25 25 gpio, ge1(rxd1), ts(mp5), tdm(spi-sck), audio(lrclk) +mpp26 26 gpio, ge1(rxd2), ts(mp6), tdm(spi-miso), audio(mclk) +mpp27 27 gpio, ge1(rxd3), ts(mp7), tdm(spi-mosi), audio(sdi) +mpp28 28 gpio, ge1(col), ts(mp8), tdm(int), audio(extclk) +mpp29 29 gpio, ge1(txclk), ts(mp9), tdm(rst) +mpp30 30 gpio, ge1(rxclk), ts(mp10), tdm(pclk) +mpp31 31 gpio, ge1(rxclk), ts(mp11), tdm(fs) +mpp32 32 gpio, ge1(txclko), ts(mp12), tdm(drx) +mpp33 33 gpo, ge1(txclk), tdm(drx) +mpp34 34 gpio, ge1(txen), tdm(spi-cs1) +mpp35 35 gpio, ge1(rxerr), sata0(act), mii(rxerr), tdm(tx0ql) + +* Marvell Kirkwood 88f6281 + +name pins functions +================================================================================ +mpp0 0 gpio, nand(io2), spi(cs) +mpp1 1 gpo, nand(io3), spi(mosi) +mpp2 2 gpo, nand(io4), spi(sck) +mpp3 3 gpo, nand(io5), spi(miso) +mpp4 4 gpio, nand(io6), uart0(rxd), ptp(clk), sata1(act) +mpp5 5 gpo, nand(io7), uart0(txd), ptp(trig), sata0(act) +mpp6 6 sysrst(out), spi(mosi), ptp(trig) +mpp7 7 gpo, pex(rsto), spi(cs), ptp(trig) +mpp8 8 gpio, twsi0(sda), uart0(rts), uart1(rts), ptp(clk), + mii(col), mii-1(rxerr), sata1(prsnt) +mpp9 9 gpio, twsi(sck), uart0(cts), uart1(cts), ptp(evreq), + mii(crs), sata0(prsnt) +mpp10 10 gpo, spi(sck), uart0(txd), ptp(trig), sata1(act) +mpp11 11 gpio, spi(miso), uart0(rxd), ptp(clk), ptp-1(evreq), + ptp-2(trig), sata0(act) +mpp12 12 gpio, sdio(clk) +mpp13 13 gpio, sdio(cmd), uart1(txd) +mpp14 14 gpio, sdio(d0), uart1(rxd), mii(col), sata1(prsnt) +mpp15 15 gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act) +mpp16 16 gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs), + sata1(act) +mpp17 17 gpio, sdio(d3), sata0(prsnt) +mpp18 18 gpo, nand(io0) +mpp19 19 gpo, nand(io1) +mpp20 20 gpio, ge1(txd0), ts(mp0), tdm(tx0ql), audio(spdifi), + sata1(act) +mpp21 21 gpio, ge1(txd1), sata0(act), ts(mp1), tdm(rx0ql), + audio(spdifo) +mpp22 22 gpio, ge1(txd2), ts(mp2), tdm(tx2ql), audio(rmclk), + sata1(prsnt) +mpp23 23 gpio, ge1(txd3), sata0(prsnt), ts(mp3), tdm(rx2ql), + audio(bclk) +mpp24 24 gpio, ge1(rxd0), ts(mp4), tdm(spi-cs0), audio(sdo) +mpp25 25 gpio, ge1(rxd1), ts(mp5), tdm(spi-sck), audio(lrclk) +mpp26 26 gpio, ge1(rxd2), ts(mp6), tdm(spi-miso), audio(mclk) +mpp27 27 gpio, ge1(rxd3), ts(mp7), tdm(spi-mosi), audio(sdi) +mpp28 28 gpio, ge1(col), ts(mp8), tdm(int), audio(extclk) +mpp29 29 gpio, ge1(txclk), ts(mp9), tdm(rst) +mpp30 30 gpio, ge1(rxclk), ts(mp10), tdm(pclk) +mpp31 31 gpio, ge1(rxclk), ts(mp11), tdm(fs) +mpp32 32 gpio, ge1(txclko), ts(mp12), tdm(drx) +mpp33 33 gpo, ge1(txclk), tdm(drx) +mpp34 34 gpio, ge1(txen), tdm(spi-cs1), sata1(act) +mpp35 35 gpio, ge1(rxerr), sata0(act), mii(rxerr), tdm(tx0ql) +mpp36 36 gpio, ts(mp0), tdm(spi-cs1), audio(spdifi) +mpp37 37 gpio, ts(mp1), tdm(tx2ql), audio(spdifo) +mpp38 38 gpio, ts(mp2), tdm(rx2ql), audio(rmclk) +mpp39 39 gpio, ts(mp3), tdm(spi-cs0), audio(bclk) +mpp40 40 gpio, ts(mp4), tdm(spi-sck), audio(sdo) +mpp41 41 gpio, ts(mp5), tdm(spi-miso), audio(lrclk) +mpp42 42 gpio, ts(mp6), tdm(spi-mosi), audio(mclk) +mpp43 43 gpio, ts(mp7), tdm(int), audio(sdi) +mpp44 44 gpio, ts(mp8), tdm(rst), audio(extclk) +mpp45 45 gpio, ts(mp9), tdm(pclk) +mpp46 46 gpio, ts(mp10), tdm(fs) +mpp47 47 gpio, ts(mp11), tdm(drx) +mpp48 48 gpio, ts(mp12), tdm(dtx) +mpp49 49 gpio, ts(mp9), tdm(rx0ql), ptp(clk) + +* Marvell Kirkwood 88f6282 + +name pins functions +================================================================================ +mpp0 0 gpio, nand(io2), spi(cs) +mpp1 1 gpo, nand(io3), spi(mosi) +mpp2 2 gpo, nand(io4), spi(sck) +mpp3 3 gpo, nand(io5), spi(miso) +mpp4 4 gpio, nand(io6), uart0(rxd), sata1(act), lcd(hsync) +mpp5 5 gpo, nand(io7), uart0(txd), sata0(act), lcd(vsync) +mpp6 6 sysrst(out), spi(mosi) +mpp7 7 gpo, spi(cs), lcd(pwm) +mpp8 8 gpio, twsi0(sda), uart0(rts), uart1(rts), mii(col), + mii-1(rxerr), sata1(prsnt) +mpp9 9 gpio, twsi(sck), uart0(cts), uart1(cts), mii(crs), + sata0(prsnt) +mpp10 10 gpo, spi(sck), uart0(txd), sata1(act) +mpp11 11 gpio, spi(miso), uart0(rxd), sata0(act) +mpp12 12 gpo, sdio(clk), audio(spdifo), spi(mosi), twsi(sda) +mpp13 13 gpio, sdio(cmd), uart1(txd), audio(rmclk), lcd(pwm) +mpp14 14 gpio, sdio(d0), uart1(rxd), mii(col), sata1(prsnt), + audio(spdifi), audio-1(sdi) +mpp15 15 gpio, sdio(d1), uart0(rts), uart1(txd), sata0(act), + spi(cs) +mpp16 16 gpio, sdio(d2), uart0(cts), uart1(rxd), mii(crs), + sata1(act), lcd(extclk) +mpp17 17 gpio, sdio(d3), sata0(prsnt), sata1(act), twsi1(sck) +mpp18 18 gpo, nand(io0), pex(clkreq) +mpp19 19 gpo, nand(io1) +mpp20 20 gpio, ge1(txd0), ts(mp0), tdm(tx0ql), audio(spdifi), + sata1(act), lcd(d0) +mpp21 21 gpio, ge1(txd1), sata0(act), ts(mp1), tdm(rx0ql), + audio(spdifo), lcd(d1) +mpp22 22 gpio, ge1(txd2), ts(mp2), tdm(tx2ql), audio(rmclk), + sata1(prsnt), lcd(d2) +mpp23 23 gpio, ge1(txd3), sata0(prsnt), ts(mp3), tdm(rx2ql), + audio(bclk), lcd(d3) +mpp24 24 gpio, ge1(rxd0), ts(mp4), tdm(spi-cs0), audio(sdo), + lcd(d4) +mpp25 25 gpio, ge1(rxd1), ts(mp5), tdm(spi-sck), audio(lrclk), + lcd(d5) +mpp26 26 gpio, ge1(rxd2), ts(mp6), tdm(spi-miso), audio(mclk), + lcd(d6) +mpp27 27 gpio, ge1(rxd3), ts(mp7), tdm(spi-mosi), audio(sdi), + lcd(d7) +mpp28 28 gpio, ge1(col), ts(mp8), tdm(int), audio(extclk), + lcd(d8) +mpp29 29 gpio, ge1(txclk), ts(mp9), tdm(rst), lcd(d9) +mpp30 30 gpio, ge1(rxclk), ts(mp10), tdm(pclk), lcd(d10) +mpp31 31 gpio, ge1(rxclk), ts(mp11), tdm(fs), lcd(d11) +mpp32 32 gpio, ge1(txclko), ts(mp12), tdm(drx), lcd(d12) +mpp33 33 gpo, ge1(txclk), tdm(drx), lcd(d13) +mpp34 34 gpio, ge1(txen), tdm(spi-cs1), sata1(act), lcd(d14) +mpp35 35 gpio, ge1(rxerr), sata0(act), mii(rxerr), tdm(tx0ql), + lcd(d15) +mpp36 36 gpio, ts(mp0), tdm(spi-cs1), audio(spdifi), twsi1(sda) +mpp37 37 gpio, ts(mp1), tdm(tx2ql), audio(spdifo), twsi1(sck) +mpp38 38 gpio, ts(mp2), tdm(rx2ql), audio(rmclk), lcd(d18) +mpp39 39 gpio, ts(mp3), tdm(spi-cs0), audio(bclk), lcd(d19) +mpp40 40 gpio, ts(mp4), tdm(spi-sck), audio(sdo), lcd(d20) +mpp41 41 gpio, ts(mp5), tdm(spi-miso), audio(lrclk), lcd(d21) +mpp42 42 gpio, ts(mp6), tdm(spi-mosi), audio(mclk), lcd(d22) +mpp43 43 gpio, ts(mp7), tdm(int), audio(sdi), lcd(d23) +mpp44 44 gpio, ts(mp8), tdm(rst), audio(extclk), lcd(clk) +mpp45 45 gpio, ts(mp9), tdm(pclk), lcd(e) +mpp46 46 gpio, ts(mp10), tdm(fs), lcd(hsync) +mpp47 47 gpio, ts(mp11), tdm(drx), lcd(vsync) +mpp48 48 gpio, ts(mp12), tdm(dtx), lcd(d16) +mpp49 49 gpo, tdm(rx0ql), pex(clkreq), lcd(d17) + +* Marvell Bobcat 98dx4122 + +name pins functions +================================================================================ +mpp0 0 gpio, nand(io2), spi(cs) +mpp1 1 gpo, nand(io3), spi(mosi) +mpp2 2 gpo, nand(io4), spi(sck) +mpp3 3 gpo, nand(io5), spi(miso) +mpp4 4 gpio, nand(io6), uart0(rxd) +mpp5 5 gpo, nand(io7), uart0(txd) +mpp6 6 sysrst(out), spi(mosi) +mpp7 7 gpo, pex(rsto), spi(cs) +mpp8 8 gpio, twsi0(sda), uart0(rts), uart1(rts) +mpp9 9 gpio, twsi(sck), uart0(cts), uart1(cts) +mpp10 10 gpo, spi(sck), uart0(txd) +mpp11 11 gpio, spi(miso), uart0(rxd) +mpp13 13 gpio, uart1(txd) +mpp14 14 gpio, uart1(rxd) +mpp15 15 gpio, uart0(rts) +mpp16 16 gpio, uart0(cts) +mpp18 18 gpo, nand(io0) +mpp19 19 gpo, nand(io1) +mpp34 34 gpio +mpp35 35 gpio +mpp36 36 gpio +mpp37 37 gpio +mpp38 38 gpio +mpp39 39 gpio +mpp40 40 gpio +mpp41 41 gpio +mpp42 42 gpio +mpp43 43 gpio +mpp44 44 gpio +mpp45 45 gpio +mpp49 49 gpio + diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,mvebu-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,mvebu-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c09f4eb2af09db6aa785d6c6ea70f0086de6240 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,mvebu-pinctrl.txt @@ -0,0 +1,46 @@ +* Marvell SoC pinctrl core driver for mpp + +The pinctrl driver enables Marvell SoCs to configure the multi-purpose pins +(mpp) to a specific function. For each SoC family there is a SoC specific +driver using this core driver. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +A Marvell SoC pin configuration node is a node of a group of pins which can +be used for a specific device or function. Each node requires one or more +mpp pins or group of pins and a mpp function common to all pins. + +Required properties for pinctrl driver: +- compatible: "marvell,-pinctrl" + Please refer to each marvell,-pinctrl.txt binding doc for supported SoCs. + +Required properties for pin configuration node: +- marvell,pins: string array of mpp pins or group of pins to be muxed. +- marvell,function: string representing a function to mux to for all + marvell,pins given in this pin configuration node. The function has to be + common for all marvell,pins. Please refer to marvell,-pinctrl.txt for + valid pin/pin group names and available function names for each SoC. + +Examples: + +uart1: serial@12100 { + compatible = "ns16550a"; + reg = <0x12100 0x100>; + reg-shift = <2>; + interrupts = <7>; + + pinctrl-0 = <&pmx_uart1_sw>; + pinctrl-names = "default"; +}; + +pinctrl: pinctrl@d0200 { + compatible = "marvell,dove-pinctrl"; + reg = <0xd0200 0x14>, <0xd0440 0x04>, <0xd802c 0x08>; + + pmx_uart1_sw: pmx-uart1-sw { + marvell,pins = "mpp_uart1"; + marvell,function = "uart1"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,orion-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,orion-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec8aa3c6936bc82630edf8fd74504f431551cfb3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/marvell,orion-pinctrl.txt @@ -0,0 +1,93 @@ +* Marvell Orion SoC pinctrl driver for mpp + +Please refer to marvell,mvebu-pinctrl.txt in this directory for common binding +part and usage. + +Required properties: +- compatible: "marvell,88f5181-pinctrl", + "marvell,88f5181l-pinctrl", + "marvell,88f5182-pinctrl", + "marvell,88f5281-pinctrl" + +- reg: two register areas, the first one describing the first two + contiguous MPP registers, and the second one describing the single + final MPP register, separated from the previous one. + +Available mpp pins/groups and functions: +Note: brackets (x) are not part of the mpp name for marvell,function and given +only for more detailed description in this document. + +* Marvell Orion 88f5181l + +name pins functions +================================================================================ +mpp0 0 pcie(rstout), pci(req2), gpio +mpp1 1 gpio, pci(gnt2) +mpp2 2 gpio, pci(req3), pci-1(pme) +mpp3 3 gpio, pci(gnt3) +mpp4 4 gpio, pci(req4) +mpp5 5 gpio, pci(gnt4) +mpp6 6 gpio, pci(req5), pci-1(clk) +mpp7 7 gpio, pci(gnt5), pci-1(clk) +mpp8 8 gpio, ge(col) +mpp9 9 gpio, ge(rxerr) +mpp10 10 gpio, ge(crs) +mpp11 11 gpio, ge(txerr) +mpp12 12 gpio, ge(txd4) +mpp13 13 gpio, ge(txd5) +mpp14 14 gpio, ge(txd6) +mpp15 15 gpio, ge(txd7) +mpp16 16 ge(rxd4) +mpp17 17 ge(rxd5) +mpp18 18 ge(rxd6) +mpp19 19 ge(rxd7) + +* Marvell Orion 88f5182 + +name pins functions +================================================================================ +mpp0 0 pcie(rstout), pci(req2), gpio +mpp1 1 gpio, pci(gnt2) +mpp2 2 gpio, pci(req3), pci-1(pme) +mpp3 3 gpio, pci(gnt3) +mpp4 4 gpio, pci(req4), bootnand(re), sata0(prsnt) +mpp5 5 gpio, pci(gnt4), bootnand(we), sata1(prsnt) +mpp6 6 gpio, pci(req5), nand(re0), sata0(act) +mpp7 7 gpio, pci(gnt5), nand(we0), sata1(act) +mpp8 8 gpio, ge(col) +mpp9 9 gpio, ge(rxerr) +mpp10 10 gpio, ge(crs) +mpp11 11 gpio, ge(txerr) +mpp12 12 gpio, ge(txd4), nand(re1), sata0(ledprsnt) +mpp13 13 gpio, ge(txd5), nand(we1), sata1(ledprsnt) +mpp14 14 gpio, ge(txd6), nand(re2), sata0(ledact) +mpp15 15 gpio, ge(txd7), nand(we2), sata1(ledact) +mpp16 16 uart1(rxd), ge(rxd4), gpio +mpp17 17 uart1(txd), ge(rxd5), gpio +mpp18 18 uart1(cts), ge(rxd6), gpio +mpp19 19 uart1(rts), ge(rxd7), gpio + +* Marvell Orion 88f5281 + +name pins functions +================================================================================ +mpp0 0 pcie(rstout), pci(req2), gpio +mpp1 1 gpio, pci(gnt2) +mpp2 2 gpio, pci(req3), pci(pme) +mpp3 3 gpio, pci(gnt3) +mpp4 4 gpio, pci(req4), bootnand(re) +mpp5 5 gpio, pci(gnt4), bootnand(we) +mpp6 6 gpio, pci(req5), nand(re0) +mpp7 7 gpio, pci(gnt5), nand(we0) +mpp8 8 gpio, ge(col) +mpp9 9 gpio, ge(rxerr) +mpp10 10 gpio, ge(crs) +mpp11 11 gpio, ge(txerr) +mpp12 12 gpio, ge(txd4), nand(re1) +mpp13 13 gpio, ge(txd5), nand(we1) +mpp14 14 gpio, ge(txd6), nand(re2) +mpp15 15 gpio, ge(txd7), nand(we2) +mpp16 16 uart1(rxd), ge(rxd4) +mpp17 17 uart1(txd), ge(rxd5) +mpp18 18 uart1(cts), ge(rxd6) +mpp19 19 uart1(rts), ge(rxd7) diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/meson,pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/meson,pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..54ecb8ab778836e7c6d6b95641b64a01d0ca3485 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/meson,pinctrl.txt @@ -0,0 +1,80 @@ +== Amlogic Meson pinmux controller == + +Required properties for the root node: + - compatible: one of "amlogic,meson8-cbus-pinctrl" + "amlogic,meson8b-cbus-pinctrl" + "amlogic,meson8m2-cbus-pinctrl" + "amlogic,meson8-aobus-pinctrl" + "amlogic,meson8b-aobus-pinctrl" + "amlogic,meson8m2-aobus-pinctrl" + "amlogic,meson-gxbb-periphs-pinctrl" + "amlogic,meson-gxbb-aobus-pinctrl" + "amlogic,meson-gxl-periphs-pinctrl" + "amlogic,meson-gxl-aobus-pinctrl" + "amlogic,meson-axg-periphs-pinctrl" + "amlogic,meson-axg-aobus-pinctrl" + - reg: address and size of registers controlling irq functionality + +=== GPIO sub-nodes === + +The GPIO bank for the controller is represented as a sub-node and it acts as a +GPIO controller. + +Required properties for sub-nodes are: + - reg: should contain address and size for mux, pull-enable, pull and + gpio register sets + - reg-names: an array of strings describing the "reg" entries. Must + contain "mux", "pull" and "gpio". "pull-enable" is optional and + when it is missing the "pull" registers are used instead + - gpio-controller: identifies the node as a gpio controller + - #gpio-cells: must be 2 + +=== Other sub-nodes === + +Child nodes without the "gpio-controller" represent some desired +configuration for a pin or a group. Those nodes can be pinmux nodes or +configuration nodes. + +Required properties for pinmux nodes are: + - groups: a list of pinmux groups. The list of all available groups + depends on the SoC and can be found in driver sources. + - function: the name of a function to activate for the specified set + of groups. The list of all available functions depends on the SoC + and can be found in driver sources. + +Required properties for configuration nodes: + - pins: a list of pin names + +Configuration nodes support the generic properties "bias-disable", +"bias-pull-up" and "bias-pull-down", described in file +pinctrl-bindings.txt + +=== Example === + + pinctrl: pinctrl@c1109880 { + compatible = "amlogic,meson8-cbus-pinctrl"; + reg = <0xc1109880 0x10>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio: banks@c11080b0 { + reg = <0xc11080b0 0x28>, + <0xc11080e8 0x18>, + <0xc1108120 0x18>, + <0xc1108030 0x30>; + reg-names = "mux", "pull", "pull-enable", "gpio"; + gpio-controller; + #gpio-cells = <2>; + }; + + nand { + mux { + groups = "nand_io", "nand_io_ce0", "nand_io_ce1", + "nand_io_rb0", "nand_ale", "nand_cle", + "nand_wen_clk", "nand_ren_clk", "nand_dqs", + "nand_ce2", "nand_ce3"; + function = "nand"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/microchip,pic32-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/microchip,pic32-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..29b72e303ebf938fd40aabde70f02b941767b15d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/microchip,pic32-pinctrl.txt @@ -0,0 +1,60 @@ +* Microchip PIC32 Pin Controller + +Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and +../interrupt-controller/interrupts.txt for generic information regarding +pin controller, GPIO, and interrupt bindings. + +PIC32 'pin configuration node' is a node of a group of pins which can be +used for a specific device or function. This node represents configuraions of +pins, optional function, and optional mux related configuration. + +Required properties for pin controller node: + - compatible: "microchip,pic32mada-pinctrl" + - reg: Address range of the pinctrl registers. + - clocks: Clock specifier (see clock bindings for details) + +Required properties for pin configuration sub-nodes: + - pins: List of pins to which the configuration applies. + +Optional properties for pin configuration sub-nodes: +---------------------------------------------------- + - function: Mux function for the specified pins. + - bias-pull-up: Enable weak pull-up. + - bias-pull-down: Enable weak pull-down. + - input-enable: Set the pin as an input. + - output-low: Set the pin as an output level low. + - output-high: Set the pin as an output level high. + - microchip,digital: Enable digital I/O. + - microchip,analog: Enable analog I/O. + +Example: + +pic32_pinctrl: pinctrl@1f801400{ + #address-cells = <1>; + #size-cells = <1>; + compatible = "microchip,pic32mzda-pinctrl"; + reg = <0x1f801400 0x400>; + clocks = <&rootclk PB1CLK>; + + pinctrl_uart2: pinctrl_uart2 { + uart2-tx { + pins = "G9"; + function = "U2TX"; + microchip,digital; + output-low; + }; + uart2-rx { + pins = "B0"; + function = "U2RX"; + microchip,digital; + input-enable; + }; + }; +}; + +uart2: serial@1f822200 { + compatible = "microchip,pic32mzda-uart"; + reg = <0x1f822200 0x50>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/mscc,ocelot-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/mscc,ocelot-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..24a210e0c59add5676516d62c72d13769eafc032 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/mscc,ocelot-pinctrl.txt @@ -0,0 +1,39 @@ +Microsemi Ocelot pin controller Device Tree Bindings +---------------------------------------------------- + +Required properties: + - compatible : Should be "mscc,ocelot-pinctrl" + - reg : Address and length of the register set for the device + - gpio-controller : Indicates this device is a GPIO controller + - #gpio-cells : Must be 2. + The first cell is the pin number and the + second cell specifies GPIO flags, as defined in + . + - gpio-ranges : Range of pins managed by the GPIO controller. + + +The ocelot-pinctrl driver uses the generic pin multiplexing and generic pin +configuration documented in pinctrl-bindings.txt. + +The following generic properties are supported: + - function + - pins + +Example: + gpio: pinctrl@71070034 { + compatible = "mscc,ocelot-pinctrl"; + reg = <0x71070034 0x28>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&gpio 0 0 22>; + + uart_pins: uart-pins { + pins = "GPIO_6", "GPIO_7"; + function = "uart"; + }; + + uart2_pins: uart2-pins { + pins = "GPIO_12", "GPIO_13"; + function = "uart2"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra114-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra114-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb70856c5b510e274d0518411ee19c33c5d854df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra114-pinmux.txt @@ -0,0 +1,131 @@ +NVIDIA Tegra114 pinmux controller + +The Tegra114 pinctrl binding is very similar to the Tegra20 and Tegra30 +pinctrl binding, as described in nvidia,tegra20-pinmux.txt and +nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as +a baseline, and only documents the differences between the two bindings. + +Required properties: +- compatible: "nvidia,tegra114-pinmux" +- reg: Should contain the register physical address and length for each of + the pad control and mux registers. The first bank of address must be the + driver strength pad control register address and second bank address must + be pinmux register address. + +Tegra114 adds the following optional properties for pin configuration subnodes: +- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes. +- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. 0: no, 1: yes. +- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes. +- nvidia,rcv-sel: Integer. Select VIL/VIH receivers. 0: normal, 1: high. +- nvidia,drive-type: Integer. Valid range 0...3. + +As with Tegra20 and Terga30, see the Tegra TRM for complete details regarding +which groups support which functionality. + +Valid values for pin and group names are: + + per-pin mux groups: + + These all support nvidia,function, nvidia,tristate, nvidia,pull, + nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain, + nvidia,io-reset and nvidia,rcv-sel. + + ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3, ulpi_data3_po4, + ulpi_data4_po5, ulpi_data5_po6, ulpi_data6_po7, ulpi_data7_po0, + ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0, + dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0, + sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, + sdmmc1_dat0_py7, clk2_out_pw5, clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4, + ddc_sda_pv5, uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6, + uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7, uart3_cts_n_pa1, + uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4, pu5, pu6, gen1_i2c_sda_pc5, + gen1_i2c_scl_pc4, dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, + clk3_out_pee0, clk3_req_pee1, gmi_wp_n_pc7, gmi_iordy_pi5, gmi_wait_pi7, + gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs0_n_pj0, gmi_cs1_n_pj2, gmi_cs2_n_pk3, + gmi_cs3_n_pk4, gmi_cs4_n_pk2, gmi_cs6_n_pi3, gmi_cs7_n_pi6, gmi_ad0_pg0, + gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5, + gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2, + gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7, + gmi_a16_pj7, gmi_a17_pb0, gmi_a18_pb1, gmi_a19_pk7, gmi_wr_n_pi0, + gmi_oe_n_pi1, gmi_dqs_p_pj3, gmi_rst_n_pi4, gen2_i2c_scl_pt5, + gen2_i2c_sda_pt6, sdmmc4_clk_pcc4, sdmmc4_cmd_pt7, sdmmc4_dat0_paa0, + sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, + sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, cam_mclk_pcc0, + pcc1, pbb0, cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, + pbb7, pcc2, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0, kb_row1_pr1, + kb_row2_pr2, kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, + kb_row7_pr7, kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_col0_pq0, + kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, + kb_col6_pq6, kb_col7_pq7, clk_32k_out_pa0, sys_clk_req_pz5, core_pwr_req, + cpu_pwr_req, pwr_int_n, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2, + dap1_sclk_pn3, clk1_req_pee2, clk1_out_pw4, spdif_in_pk6, spdif_out_pk5, + dap2_fs_pa2, dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3, dvfs_pwm_px0, + gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2, gpio_x4_aud_px4, + gpio_x5_aud_px5, gpio_x6_aud_px6, gpio_x7_aud_px7, sdmmc3_clk_pa6, + sdmmc3_cmd_pa7, sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, sdmmc3_dat2_pb5, + sdmmc3_dat3_pb4, hdmi_cec_pee3, sdmmc1_wp_n_pv3, sdmmc3_cd_n_pv2, + gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4, usb_vbus_en1_pn5, + sdmmc3_clk_lb_in_pee5, sdmmc3_clk_lb_out_pee4, reset_out_n. + + drive groups: + + These all support nvidia,pull-down-strength, nvidia,pull-up-strength, + nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all + support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode + and nvidia,drive-type. + + ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, dap1, dap2, dap3, dap4, + dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg, + gmh, owr, uda. + +Valid values for nvidia,functions are: + + blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3, displaya, + displaya_alt, displayb, dtv, emc_dll, extperiph1, extperiph2, + extperiph3, gmi, gmi_alt, hda, hsi, i2c1, i2c2, i2c3, i2c4, i2cpwr, + i2s0, i2s1, i2s2, i2s3, i2s4, irda, kbc, nand, nand_alt, owr, pmi, + pwm0, pwm1, pwm2, pwm3, pwron, reset_out_n, rsvd1, rsvd2, rsvd3, + rsvd4, sdmmc1, sdmmc2, sdmmc3, sdmmc4, soc, spdif, spi1, spi2, spi3, + spi4, spi5, spi6, sysclk, trace, uarta, uartb, uartc, uartd, ulpi, + usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, vi, vi_alt1, vi_alt3 + +Example: + + pinmux: pinmux { + compatible = "nvidia,tegra114-pinmux"; + reg = <0x70000868 0x148 /* Pad control registers */ + 0x70003000 0x40c>; /* PinMux registers */ + }; + +Example board file extract: + + pinctrl { + sdmmc4_default: pinmux { + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + nvidia,function = "sdmmc4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@78000400 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc4_default>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0e886b7352783da41b93270b425aef5232ba59e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt @@ -0,0 +1,59 @@ +Device tree binding for NVIDIA Tegra DPAUX pad controller +======================================================== + +The Tegra Display Port Auxiliary (DPAUX) pad controller manages two pins +which can be assigned to either the DPAUX channel or to an I2C +controller. + +This document defines the device-specific binding for the DPAUX pad +controller. Refer to pinctrl-bindings.txt in this directory for generic +information about pin controller device tree bindings. Please refer to +the binding document ../display/tegra/nvidia,tegra20-host1x.txt for more +details on the DPAUX binding. + +Pin muxing: +----------- + +Child nodes contain the pinmux configurations following the conventions +from the pinctrl-bindings.txt document. + +Since only three configurations are possible, only three child nodes are +needed to describe the pin mux'ing options for the DPAUX pads. +Furthermore, given that the pad functions are only applicable to a +single set of pads, the child nodes only need to describe the pad group +the functions are being applied to rather than the individual pads. + +Required properties: +- groups: Must be "dpaux-io" +- function: Must be either "aux", "i2c" or "off". + +Example: +-------- + + dpaux@545c0000 { + ... + + state_dpaux_aux: pinmux-aux { + groups = "dpaux-io"; + function = "aux"; + }; + + state_dpaux_i2c: pinmux-i2c { + groups = "dpaux-io"; + function = "i2c"; + }; + + state_dpaux_off: pinmux-off { + groups = "dpaux-io"; + function = "off"; + }; + }; + + ... + + i2c@7000d100 { + ... + pinctrl-0 = <&state_dpaux_i2c>; + pinctrl-1 = <&state_dpaux_off>; + pinctrl-names = "default", "idle"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4d06bb0b55a8848ebb137443cfb616bb020c6f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-pinmux.txt @@ -0,0 +1,153 @@ +NVIDIA Tegra124 pinmux controller + +The Tegra124 pinctrl binding is very similar to the Tegra20 and Tegra30 +pinctrl binding, as described in nvidia,tegra20-pinmux.txt and +nvidia,tegra30-pinmux.txt. In fact, this document assumes that binding as +a baseline, and only documents the differences between the two bindings. + +Required properties: +- compatible: For Tegra124, must contain "nvidia,tegra124-pinmux". For + Tegra132, must contain '"nvidia,tegra132-pinmux", "nvidia-tegra124-pinmux"'. +- reg: Should contain a list of base address and size pairs for: + -- first entry - the drive strength and pad control registers. + -- second entry - the pinmux registers + -- third entry - the MIPI_PAD_CTRL register + +Tegra124 adds the following optional properties for pin configuration subnodes. +The macros for options are defined in the + include/dt-binding/pinctrl/pinctrl-tegra.h. +- nvidia,enable-input: Integer. Enable the pin's input path. + enable :TEGRA_PIN_ENABLE and + disable or output only: TEGRA_PIN_DISABLE. +- nvidia,open-drain: Integer. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,io-reset: Integer. Reset the IO path. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,rcv-sel: Integer. Select VIL/VIH receivers. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE + +Please refer the Tegra TRM for complete details regarding which groups +support which functionality. + +Valid values for pin and group names are: + + per-pin mux groups: + + These all support nvidia,function, nvidia,tristate, nvidia,pull, + nvidia,enable-input. Some support nvidia,lock nvidia,open-drain, + nvidia,io-reset and nvidia,rcv-sel. + + ulpi_data0_po1, ulpi_data1_po2, ulpi_data2_po3, ulpi_data3_po4, + ulpi_data4_po5, ulpi_data5_po6, ulpi_data6_po7, ulpi_data7_po0, + ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, dap3_fs_pp0, + dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, pv0, pv1, sdmmc1_clk_pz0, + sdmmc1_cmd_pz1, sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, + sdmmc1_dat0_py7, clk2_out_pw5, clk2_req_pcc5, hdmi_int_pn7, ddc_scl_pv4, + ddc_sda_pv5, uart2_rxd_pc3, uart2_txd_pc2, uart2_rts_n_pj6, + uart2_cts_n_pj5, uart3_txd_pw6, uart3_rxd_pw7, uart3_cts_n_pa1, + uart3_rts_n_pc0, pu0, pu1, pu2, pu3, pu4, pu5, pu6, gen1_i2c_scl_pc4, + gen1_i2c_sda_pc5, dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, + dap4_sclk_pp7, clk3_out_pee0, clk3_req_pee1, pc7, pi5, pi7, pk0, pk1, + pj0, pj2, pk3, pk4, pk2, pi3, pi6, pg0, pg1, pg2, pg3, pg4, pg5, pg6, + pg7, ph0, ph1, ph2, ph3, ph4, ph5, ph6, ph7, pj7, pb0, pb1, pk7, pi0, + pi1, pi2, pi4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6, sdmmc4_clk_pcc4, + sdmmc4_cmd_pt7, sdmmc4_dat0_paa0, sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, + sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, + sdmmc4_dat7_paa7, cam_mclk_pcc0, pcc1, pbb0, cam_i2c_scl_pbb1, + cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7, pcc2, jtag_rtck, + pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2, + kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7, + kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4, + kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, kb_col0_pq0, kb_col1_pq1, + kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, kb_col6_pq6, + kb_col7_pq7, clk_32k_out_pa0, core_pwr_req, cpu_pwr_req, pwr_int_n, + clk_32k_in, owr, dap1_fs_pn0, dap1_din_pn1, dap1_dout_pn2, + dap1_sclk_pn3, dap_mclk1_req_pee2, dap_mclk1_pw4, spdif_in_pk6, + spdif_out_pk5, dap2_fs_pa2, dap2_din_pa4, dap2_dout_pa5, dap2_sclk_pa3, + dvfs_pwm_px0, gpio_x1_aud_px1, gpio_x3_aud_px3, dvfs_clk_px2, + gpio_x4_aud_px4, gpio_x5_aud_px5, gpio_x6_aud_px6, gpio_x7_aud_px7, + sdmmc3_clk_pa6, sdmmc3_cmd_pa7, sdmmc3_dat0_pb7, sdmmc3_dat1_pb6, + sdmmc3_dat2_pb5, sdmmc3_dat3_pb4, pex_l0_rst_n_pdd1, + pex_l0_clkreq_n_pdd2, pex_wake_n_pdd3, pex_l1_rst_n_pdd5, + pex_l1_clkreq_n_pdd6, hdmi_cec_pee3, sdmmc1_wp_n_pv3, + sdmmc3_cd_n_pv2, gpio_w2_aud_pw2, gpio_w3_aud_pw3, usb_vbus_en0_pn4, + usb_vbus_en1_pn5, sdmmc3_clk_lb_out_pee4, sdmmc3_clk_lb_in_pee5, + gmi_clk_lb, reset_out_n, kb_row16_pt0, kb_row17_pt1, usb_vbus_en2_pff1, + pff2, dp_hpd_pff0, + + drive groups: + + These all support nvidia,pull-down-strength, nvidia,pull-up-strength, + nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all + support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode + and nvidia,drive-type. + + ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, dap1, dap2, dap3, dap4, + dbg, sdio3, spi, uaa, uab, uart2, uart3, sdio1, ddc, gma, gme, gmf, gmg, + gmh, owr, uda, gpv, dev3, cec, usb_vbus_en, ao3, ao0, hv0, sdio4, ao4. + + MIPI pad control groups: + + These support only the nvidia,function property. + + dsi_b + +Valid values for nvidia,functions are: + + blink, cec, cldvfs, clk12, cpu, dap, dap1, dap2, dev3, displaya, + displaya_alt, displayb, dtv, extperiph1, extperiph2, extperiph3, + gmi, gmi_alt, hda, hsi, i2c1, i2c2, i2c3, i2c4, i2cpwr, i2s0, + i2s1, i2s2, i2s3, i2s4, irda, kbc, owr, pmi, pwm0, pwm1, pwm2, pwm3, + pwron, reset_out_n, rsvd1, rsvd2, rsvd3, rsvd4, sdmmc1, sdmmc2, sdmmc3, + sdmmc4, soc, spdif, spi1, spi2, spi3, spi4, spi5, spi6, trace, uarta, + uartb, uartc, uartd, ulpi, usb, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, + vi, vi_alt1, vi_alt3, vimclk2, vimclk2_alt, sata, ccla, pe0, pe, pe1, + dp, rtck, sys, clk tmds, csi, dsi_b + +Example: + + pinmux: pinmux { + compatible = "nvidia,tegra124-pinmux"; + reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */ + <0x0 0x70003000 0x0 0x434>, /* Mux registers */ + <0x0 0x70000820 0x0 0x8>; /* MIPI pad control */ + }; + +Example pinmux entries: + + pinctrl { + sdmmc4_default: pinmux { + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + }; + + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = ; + nvidia,tristate = ; + }; + }; + }; + + sdhci@78000400 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc4_default>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt new file mode 100644 index 0000000000000000000000000000000000000000..02e971c39d815ea11f0baf45bb66091cbcb10bf1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt @@ -0,0 +1,135 @@ +Device tree binding for NVIDIA Tegra XUSB pad controller +======================================================== + +NOTE: It turns out that this binding isn't an accurate description of the XUSB +pad controller. While the description is good enough for the functional subset +required for PCIe and SATA, it lacks the flexibility to represent the features +needed for USB. For the new binding, see ../phy/nvidia,tegra-xusb-padctl.txt. +The binding described in this file is deprecated and should not be used. + +The Tegra XUSB pad controller manages a set of lanes, each of which can be +assigned to one out of a set of different pads. Some of these pads have an +associated PHY that must be powered up before the pad can be used. + +This document defines the device-specific binding for the XUSB pad controller. + +Refer to pinctrl-bindings.txt in this directory for generic information about +pin controller device tree bindings and ../phy/phy-bindings.txt for details on +how to describe and reference PHYs in device trees. + +Required properties: +-------------------- +- compatible: For Tegra124, must contain "nvidia,tegra124-xusb-padctl". + Otherwise, must contain '"nvidia,-xusb-padctl", + "nvidia-tegra124-xusb-padctl"', where is tegra132 or tegra210. +- reg: Physical base address and length of the controller's registers. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - padctl +- #phy-cells: Should be 1. The specifier is the index of the PHY to reference. + See for the list of valid values. + +Lane muxing: +------------ + +Child nodes contain the pinmux configurations following the conventions from +the pinctrl-bindings.txt document. Typically a single, static configuration is +given and applied at boot time. + +Each subnode describes groups of lanes along with parameters and pads that +they should be assigned to. The name of these subnodes is not important. All +subnodes should be parsed solely based on their content. + +Each subnode only applies the parameters that are explicitly listed. In other +words, if a subnode that lists a function but no pin configuration parameters +implies no information about any pin configuration parameters. Similarly, a +subnode that describes only an IDDQ parameter implies no information about +what function the pins are assigned to. For this reason even seemingly boolean +values are actually tristates in this binding: unspecified, off or on. +Unspecified is represented as an absent property, and off/on are represented +as integer values 0 and 1. + +Required properties: +- nvidia,lanes: An array of strings. Each string is the name of a lane. + +Optional properties: +- nvidia,function: A string that is the name of the function (pad) that the + pin or group should be assigned to. Valid values for function names are + listed below. +- nvidia,iddq: Enables IDDQ mode of the lane. (0: no, 1: yes) + +Note that not all of these properties are valid for all lanes. Lanes can be +divided into three groups: + + - otg-0, otg-1, otg-2: + + Valid functions for this group are: "snps", "xusb", "uart", "rsvd". + + The nvidia,iddq property does not apply to this group. + + - ulpi-0, hsic-0, hsic-1: + + Valid functions for this group are: "snps", "xusb". + + The nvidia,iddq property does not apply to this group. + + - pcie-0, pcie-1, pcie-2, pcie-3, pcie-4, sata-0: + + Valid functions for this group are: "pcie", "usb3", "sata", "rsvd". + + +Example: +======== + +SoC file extract: +----------------- + + padctl@7009f000 { + compatible = "nvidia,tegra124-xusb-padctl"; + reg = <0x0 0x7009f000 0x0 0x1000>; + resets = <&tegra_car 142>; + reset-names = "padctl"; + + #phy-cells = <1>; + }; + +Board file extract: +------------------- + + pcie-controller@1003000 { + ... + + phys = <&padctl 0>; + phy-names = "pcie"; + + ... + }; + + ... + + padctl: padctl@7009f000 { + pinctrl-0 = <&padctl_default>; + pinctrl-names = "default"; + + padctl_default: pinmux { + usb3 { + nvidia,lanes = "pcie-0", "pcie-1"; + nvidia,function = "usb3"; + nvidia,iddq = <0>; + }; + + pcie { + nvidia,lanes = "pcie-2", "pcie-3", + "pcie-4"; + nvidia,function = "pcie"; + nvidia,iddq = <0>; + }; + + sata { + nvidia,lanes = "sata-0"; + nvidia,function = "sata"; + nvidia,iddq = <0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra20-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra20-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c8ce28baad63b164513875221a298dca5bb2066 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra20-pinmux.txt @@ -0,0 +1,143 @@ +NVIDIA Tegra20 pinmux controller + +Required properties: +- compatible: "nvidia,tegra20-pinmux" +- reg: Should contain the register physical address and length for each of + the tri-state, mux, pull-up/down, and pad control register sets. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Tegra's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, tristate, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function or tristate parameter. For this +reason, even seemingly boolean values are actually tristates in this binding: +unspecified, off, or on. Unspecified is represented as an absent property, +and off/on are represented as integer values 0 and 1. + +Required subnode-properties: +- nvidia,pins : An array of strings. Each string contains the name of a pin or + group. Valid values for these names are listed below. + +Optional subnode-properties: +- nvidia,function: A string containing the name of the function to mux to the + pin or group. Valid values for function names are listed below. See the Tegra + TRM to determine which are valid for each pin or group. +- nvidia,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- nvidia,tristate: Integer. + 0: drive, 1: tristate. +- nvidia,high-speed-mode: Integer. Enable high speed mode the pins. + 0: no, 1: yes. +- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input. + 0: no, 1: yes. +- nvidia,low-power-mode: Integer. Valid values 0-3. 0 is least power, 3 is + most power. Controls the drive power or current. See "Low Power Mode" + or "LPMD1" and "LPMD0" in the Tegra TRM. +- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVDN" in the + Tegra TRM. +- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVUP" in the + Tegra TRM. +- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVDN_SLWR" in the Tegra TRM. +- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVUP_SLWF" in the Tegra TRM. + +Note that many of these properties are only valid for certain specific pins +or groups. See the Tegra TRM and various pinmux spreadsheets for complete +details regarding which groups support which functionality. The Linux pinctrl +driver may also be a useful reference, since it consolidates, disambiguates, +and corrects data from all those sources. + +Valid values for pin and group names are: + + mux groups: + + These all support nvidia,function, nvidia,tristate, and many support + nvidia,pull. + + ata, atb, atc, atd, ate, cdev1, cdev2, crtp, csus, dap1, dap2, dap3, dap4, + ddc, dta, dtb, dtc, dtd, dte, dtf, gma, gmb, gmc, gmd, gme, gpu, gpu7, + gpv, hdint, i2cp, irrx, irtx, kbca, kbcb, kbcc, kbcd, kbce, kbcf, lcsn, + ld0, ld1, ld2, ld3, ld4, ld5, ld6, ld7, ld8, ld9, ld10, ld11, ld12, ld13, + ld14, ld15, ld16, ld17, ldc, ldi, lhp0, lhp1, lhp2, lhs, lm0, lm1, lpp, + lpw0, lpw1, lpw2, lsc0, lsc1, lsck, lsda, lsdi, lspi, lvp0, lvp1, lvs, + owc, pmc, pta, rm, sdb, sdc, sdd, sdio1, slxa, slxc, slxd, slxk, spdi, + spdo, spia, spib, spic, spid, spie, spif, spig, spih, uaa, uab, uac, uad, + uca, ucb, uda. + + tristate groups: + + These only support nvidia,pull. + + ck32, ddrc, pmca, pmcb, pmcc, pmcd, pmce, xm2c, xm2d, ls, lc, ld17_0, + ld19_18, ld21_20, ld23_22. + + drive groups: + + With some exceptions, these support nvidia,high-speed-mode, + nvidia,schmitt, nvidia,low-power-mode, nvidia,pull-down-strength, + nvidia,pull-up-strength, nvidia,slew-rate-rising, nvidia,slew-rate-falling. + + drive_ao1, drive_ao2, drive_at1, drive_at2, drive_cdev1, drive_cdev2, + drive_csus, drive_dap1, drive_dap2, drive_dap3, drive_dap4, drive_dbg, + drive_lcd1, drive_lcd2, drive_sdmmc2, drive_sdmmc3, drive_spi, drive_uaa, + drive_uab, drive_uart2, drive_uart3, drive_vi1, drive_vi2, drive_xm2a, + drive_xm2c, drive_xm2d, drive_xm2clk, drive_sdio1, drive_crt, drive_ddc, + drive_gma, drive_gmb, drive_gmc, drive_gmd, drive_gme, drive_owr, + drive_uda. + +Valid values for nvidia,functions are: + + ahb_clk, apb_clk, audio_sync, crt, dap1, dap2, dap3, dap4, dap5, + displaya, displayb, emc_test0_dll, emc_test1_dll, gmi, gmi_int, + hdmi, i2cp, i2c1, i2c2, i2c3, ide, irda, kbc, mio, mipi_hs, nand, + osc, owr, pcie, plla_out, pllc_out1, pllm_out1, pllp_out2, pllp_out3, + pllp_out4, pwm, pwr_intr, pwr_on, rsvd1, rsvd2, rsvd3, rsvd4, rtck, + sdio1, sdio2, sdio3, sdio4, sflash, spdif, spi1, spi2, spi2_alt, + spi3, spi4, trace, twc, uarta, uartb, uartc, uartd, uarte, ulpi, + vi, vi_sensor_clk, xio + +Example: + + pinctrl@70000000 { + compatible = "nvidia,tegra20-pinmux"; + reg = < 0x70000014 0x10 /* Tri-state registers */ + 0x70000080 0x20 /* Mux registers */ + 0x700000a0 0x14 /* Pull-up/down registers */ + 0x70000868 0xa8 >; /* Pad control registers */ + }; + +Example board file extract: + + pinctrl@70000000 { + sdio4_default: sdio4_default { + atb { + nvidia,pins = "atb", "gma", "gme"; + nvidia,function = "sdio4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@c8000600 { + pinctrl-names = "default"; + pinctrl-0 = <&sdio4_default>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra210-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra210-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..85f211436b8ea9a82c80bff16998c805d21b5434 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra210-pinmux.txt @@ -0,0 +1,166 @@ +NVIDIA Tegra210 pinmux controller + +Required properties: +- compatible: "nvidia,tegra210-pinmux" +- reg: Should contain a list of base address and size pairs for: + - first entry: The APB_MISC_GP_*_PADCTRL registers (pad control) + - second entry: The PINMUX_AUX_* registers (pinmux) + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Tegra's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, tristate, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function or tristate parameter. For this +reason, even seemingly boolean values are actually tristates in this binding: +unspecified, off, or on. Unspecified is represented as an absent property, +and off/on are represented as integer values 0 and 1. + +See the TRM to determine which properties and values apply to each pin/group. +Macro values for property values are defined in +include/dt-binding/pinctrl/pinctrl-tegra.h. + +Required subnode-properties: +- nvidia,pins : An array of strings. Each string contains the name of a pin or + group. Valid values for these names are listed below. + +Optional subnode-properties: +- nvidia,function: A string containing the name of the function to mux to the + pin or group. +- nvidia,pull: Integer, representing the pull-down/up to apply to the pin. + 0: none, 1: down, 2: up. +- nvidia,tristate: Integer. + 0: drive, 1: tristate. +- nvidia,enable-input: Integer. Enable the pin's input path. + enable :TEGRA_PIN_ENABLE and + disable or output only: TEGRA_PIN_DISABLE. +- nvidia,open-drain: Integer. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. + enable: TEGRA_PIN_ENABLE. + disable: TEGRA_PIN_DISABLE. +- nvidia,io-hv: Integer. Select high-voltage receivers. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE +- nvidia,high-speed-mode: Integer. Enable high speed mode the pins. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE +- nvidia,schmitt: Integer. Enables Schmitt Trigger on the input. + normal: TEGRA_PIN_DISABLE + high: TEGRA_PIN_ENABLE +- nvidia,drive-type: Integer. Valid range 0...3. +- nvidia,pull-down-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVDN" in the + Tegra TRM. +- nvidia,pull-up-strength: Integer. Controls drive strength. 0 is weakest. + The range of valid values depends on the pingroup. See "CAL_DRVUP" in the + Tegra TRM. +- nvidia,slew-rate-rising: Integer. Controls rising signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVDN_SLWR" in the Tegra TRM. +- nvidia,slew-rate-falling: Integer. Controls falling signal slew rate. 0 is + fastest. The range of valid values depends on the pingroup. See + "DRVUP_SLWF" in the Tegra TRM. + +Valid values for pin and group names (nvidia,pin) are: + + Mux groups: + + These correspond to Tegra PINMUX_AUX_* (pinmux) registers. Any property + that exists in those registers may be set for the following pin names. + + In Tegra210, many pins also have a dedicated APB_MISC_GP_*_PADCTRL + register. Where that is true, and property that exists in that register + may also be set on the following pin names. + + als_prox_int_px3, ap_ready_pv5, ap_wake_bt_ph3, ap_wake_nfc_ph7, + aud_mclk_pbb0, batt_bcl, bt_rst_ph4, bt_wake_ap_ph5, button_home_py1, + button_power_on_px5, button_slide_sw_py0, button_vol_down_px7, + button_vol_up_px6, cam1_mclk_ps0, cam1_pwdn_ps7, cam1_strobe_pt1, + cam2_mclk_ps1, cam2_pwdn_pt0, cam_af_en_ps5, cam_flash_en_ps6, + cam_i2c_scl_ps2, cam_i2c_sda_ps3, cam_rst_ps4cam_rst_ps4, clk_32k_in, + clk_32k_out_py5, clk_req, core_pwr_req, cpu_pwr_req, dap1_din_pb1, + dap1_dout_pb2, dap1_fs_pb0, dap1_sclk_pb3, dap2_din_paa2, dap2_dout_paa3, + dap2_fs_paa0, dap2_sclk_paa1, dap4_din_pj5, dap4_dout_pj6, dap4_fs_pj4, + dap4_sclk_pj7, dmic1_clk_pe0, dmic1_dat_pe1, dmic2_clk_pe2, dmic2_dat_pe3, + dmic3_clk_pe4, dmic3_dat_pe5, dp_hpd0_pcc6, dvfs_clk_pbb2, dvfs_pwm_pbb1, + gen1_i2c_scl_pj1, gen1_i2c_sda_pj0, gen2_i2c_scl_pj2, gen2_i2c_sda_pj3, + gen3_i2c_scl_pf0, gen3_i2c_sda_pf1, gpio_x1_aud_pbb3, gpio_x3_aud_pbb4, + gps_en_pi2, gps_rst_pi3, hdmi_cec_pcc0, hdmi_int_dp_hpd_pcc1, jtag_rtck, + lcd_bl_en_pv1, lcd_bl_pwm_pv0, lcd_gpio1_pv3, lcd_gpio2_pv4, lcd_rst_pv2, + lcd_te_py2, modem_wake_ap_px0, motion_int_px2, nfc_en_pi0, nfc_int_pi1, + pa6, pcc7, pe6, pe7, pex_l0_clkreq_n_pa1, pex_l0_rst_n_pa0, + pex_l1_clkreq_n_pa4, pex_l1_rst_n_pa3, pex_wake_n_pa2, ph6, pk0, pk1, pk2, + pk3, pk4, pk5, pk6, pk7, pl0, pl1, pwr_i2c_scl_py3, pwr_i2c_sda_py4, + pwr_int_n, pz0, pz1, pz2, pz3, pz4, pz5, qspi_cs_n_pee1, qspi_io0_pee2, + qspi_io1_pee3, qspi_io2_pee4, qspi_io3_pee5, qspi_sck_pee0, + sata_led_active_pa5, sdmmc1_clk_pm0, sdmmc1_cmd_pm1, sdmmc1_dat0_pm5, + sdmmc1_dat1_pm4, sdmmc1_dat2_pm3, sdmmc1_dat3_pm2, sdmmc3_clk_pp0, + sdmmc3_cmd_pp1, sdmmc3_dat0_pp5, sdmmc3_dat1_pp4, sdmmc3_dat2_pp3, + sdmmc3_dat3_pp2, shutdown, spdif_in_pcc3, spdif_out_pcc2, spi1_cs0_pc3, + spi1_cs1_pc4, spi1_miso_pc1, spi1_mosi_pc0, spi1_sck_pc2, spi2_cs0_pb7, + spi2_cs1_pdd0, spi2_miso_pb5, spi2_mosi_pb4, spi2_sck_pb6, spi4_cs0_pc6, + spi4_miso_pd0, spi4_mosi_pc7, spi4_sck_pc5, temp_alert_px4, touch_clk_pv7, + touch_int_px1, touch_rst_pv6, uart1_cts_pu3, uart1_rts_pu2, uart1_rx_pu1, + uart1_tx_pu0, uart2_cts_pg3, uart2_rts_pg2, uart2_rx_pg1, uart2_tx_pg0, + uart3_cts_pd4, uart3_rts_pd3, uart3_rx_pd2, uart3_tx_pd1, uart4_cts_pi7, + uart4_rts_pi6, uart4_rx_pi5, uart4_tx_pi4, usb_vbus_en0_pcc4, + usb_vbus_en1_pcc5, wifi_en_ph0, wifi_rst_ph1, wifi_wake_ap_ph2 + + Drive groups: + + These correspond to the Tegra APB_MISC_GP_*_PADCTRL (pad control) + registers. Note that where one of these registers controls a single pin + for which a PINMUX_AUX_* exists, see the list above for the pin name to + use when configuring the pinmux. + + pa6, pcc7, pe6, pe7, ph6, pk0, pk1, pk2, pk3, pk4, pk5, pk6, pk7, pl0, pl1, + pz0, pz1, pz2, pz3, pz4, pz5, sdmmc1, sdmmc2, sdmmc3, sdmmc4 + +Valid values for nvidia,functions are: + + aud, bcl, blink, ccla, cec, cldvfs, clk, core, cpu, displaya, displayb, + dmic1, dmic2, dmic3, dp, dtv, extperiph3, i2c1, i2c2, i2c3, i2cpmu, i2cvi, + i2s1, i2s2, i2s3, i2s4a, i2s4b, i2s5a, i2s5b, iqc0, iqc1, jtag, pe, pe0, + pe1, pmi, pwm0, pwm1, pwm2, pwm3, qspi, rsvd0, rsvd1, rsvd2, rsvd3, sata, + sdmmc1, sdmmc3, shutdown, soc, sor0, sor1, spdif, spi1, spi2, spi3, spi4, + sys, touch, uart, uarta, uartb, uartc, uartd, usb, vgp1, vgp2, vgp3, vgp4, + vgp5, vgp6, vimclk, vimclk2 + +Example: + + pinmux: pinmux@70000800 { + compatible = "nvidia,tegra210-pinmux"; + reg = <0x0 0x700008d4 0x0 0x2a8>, /* Pad control registers */ + <0x0 0x70003000 0x0 0x1000>; /* Mux registers */ + + pinctrl-names = "boot"; + pinctrl-0 = <&state_boot>; + + state_boot: pinmux { + gen1_i2c_scl_pj1 { + nvidia,pins = "gen1_i2c_scl_pj1", + nvidia,function = "i2c1"; + nvidia,pull = ; + nvidia,tristate = ; + nvidia,enable-input = ; + nvidia,open-drain = ; + nvidia,io-hv = ; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra30-pinmux.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra30-pinmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e6354c11e6db985a8fe834fe7afced2f3e2d7bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nvidia,tegra30-pinmux.txt @@ -0,0 +1,144 @@ +NVIDIA Tegra30 pinmux controller + +The Tegra30 pinctrl binding is very similar to the Tegra20 pinctrl binding, +as described in nvidia,tegra20-pinmux.txt. In fact, this document assumes +that binding as a baseline, and only documents the differences between the +two bindings. + +Required properties: +- compatible: "nvidia,tegra30-pinmux" +- reg: Should contain the register physical address and length for each of + the pad control and mux registers. + +Tegra30 adds the following optional properties for pin configuration subnodes: +- nvidia,enable-input: Integer. Enable the pin's input path. 0: no, 1: yes. +- nvidia,open-drain: Integer. Enable open drain mode. 0: no, 1: yes. +- nvidia,lock: Integer. Lock the pin configuration against further changes + until reset. 0: no, 1: yes. +- nvidia,io-reset: Integer. Reset the IO path. 0: no, 1: yes. + +As with Tegra20, see the Tegra TRM for complete details regarding which groups +support which functionality. + +Valid values for pin and group names are: + + per-pin mux groups: + + These all support nvidia,function, nvidia,tristate, nvidia,pull, + nvidia,enable-input, nvidia,lock. Some support nvidia,open-drain, + nvidia,io-reset. + + clk_32k_out_pa0, uart3_cts_n_pa1, dap2_fs_pa2, dap2_sclk_pa3, + dap2_din_pa4, dap2_dout_pa5, sdmmc3_clk_pa6, sdmmc3_cmd_pa7, gmi_a17_pb0, + gmi_a18_pb1, lcd_pwr0_pb2, lcd_pclk_pb3, sdmmc3_dat3_pb4, sdmmc3_dat2_pb5, + sdmmc3_dat1_pb6, sdmmc3_dat0_pb7, uart3_rts_n_pc0, lcd_pwr1_pc1, + uart2_txd_pc2, uart2_rxd_pc3, gen1_i2c_scl_pc4, gen1_i2c_sda_pc5, + lcd_pwr2_pc6, gmi_wp_n_pc7, sdmmc3_dat5_pd0, sdmmc3_dat4_pd1, lcd_dc1_pd2, + sdmmc3_dat6_pd3, sdmmc3_dat7_pd4, vi_d1_pd5, vi_vsync_pd6, vi_hsync_pd7, + lcd_d0_pe0, lcd_d1_pe1, lcd_d2_pe2, lcd_d3_pe3, lcd_d4_pe4, lcd_d5_pe5, + lcd_d6_pe6, lcd_d7_pe7, lcd_d8_pf0, lcd_d9_pf1, lcd_d10_pf2, lcd_d11_pf3, + lcd_d12_pf4, lcd_d13_pf5, lcd_d14_pf6, lcd_d15_pf7, gmi_ad0_pg0, + gmi_ad1_pg1, gmi_ad2_pg2, gmi_ad3_pg3, gmi_ad4_pg4, gmi_ad5_pg5, + gmi_ad6_pg6, gmi_ad7_pg7, gmi_ad8_ph0, gmi_ad9_ph1, gmi_ad10_ph2, + gmi_ad11_ph3, gmi_ad12_ph4, gmi_ad13_ph5, gmi_ad14_ph6, gmi_ad15_ph7, + gmi_wr_n_pi0, gmi_oe_n_pi1, gmi_dqs_pi2, gmi_cs6_n_pi3, gmi_rst_n_pi4, + gmi_iordy_pi5, gmi_cs7_n_pi6, gmi_wait_pi7, gmi_cs0_n_pj0, lcd_de_pj1, + gmi_cs1_n_pj2, lcd_hsync_pj3, lcd_vsync_pj4, uart2_cts_n_pj5, + uart2_rts_n_pj6, gmi_a16_pj7, gmi_adv_n_pk0, gmi_clk_pk1, gmi_cs4_n_pk2, + gmi_cs2_n_pk3, gmi_cs3_n_pk4, spdif_out_pk5, spdif_in_pk6, gmi_a19_pk7, + vi_d2_pl0, vi_d3_pl1, vi_d4_pl2, vi_d5_pl3, vi_d6_pl4, vi_d7_pl5, + vi_d8_pl6, vi_d9_pl7, lcd_d16_pm0, lcd_d17_pm1, lcd_d18_pm2, lcd_d19_pm3, + lcd_d20_pm4, lcd_d21_pm5, lcd_d22_pm6, lcd_d23_pm7, dap1_fs_pn0, + dap1_din_pn1, dap1_dout_pn2, dap1_sclk_pn3, lcd_cs0_n_pn4, lcd_sdout_pn5, + lcd_dc0_pn6, hdmi_int_pn7, ulpi_data7_po0, ulpi_data0_po1, ulpi_data1_po2, + ulpi_data2_po3, ulpi_data3_po4, ulpi_data4_po5, ulpi_data5_po6, + ulpi_data6_po7, dap3_fs_pp0, dap3_din_pp1, dap3_dout_pp2, dap3_sclk_pp3, + dap4_fs_pp4, dap4_din_pp5, dap4_dout_pp6, dap4_sclk_pp7, kb_col0_pq0, + kb_col1_pq1, kb_col2_pq2, kb_col3_pq3, kb_col4_pq4, kb_col5_pq5, + kb_col6_pq6, kb_col7_pq7, kb_row0_pr0, kb_row1_pr1, kb_row2_pr2, + kb_row3_pr3, kb_row4_pr4, kb_row5_pr5, kb_row6_pr6, kb_row7_pr7, + kb_row8_ps0, kb_row9_ps1, kb_row10_ps2, kb_row11_ps3, kb_row12_ps4, + kb_row13_ps5, kb_row14_ps6, kb_row15_ps7, vi_pclk_pt0, vi_mclk_pt1, + vi_d10_pt2, vi_d11_pt3, vi_d0_pt4, gen2_i2c_scl_pt5, gen2_i2c_sda_pt6, + sdmmc4_cmd_pt7, pu0, pu1, pu2, pu3, pu4, pu5, pu6, jtag_rtck_pu7, pv0, + pv1, pv2, pv3, ddc_scl_pv4, ddc_sda_pv5, crt_hsync_pv6, crt_vsync_pv7, + lcd_cs1_n_pw0, lcd_m1_pw1, spi2_cs1_n_pw2, spi2_cs2_n_pw3, clk1_out_pw4, + clk2_out_pw5, uart3_txd_pw6, uart3_rxd_pw7, spi2_mosi_px0, spi2_miso_px1, + spi2_sck_px2, spi2_cs0_n_px3, spi1_mosi_px4, spi1_sck_px5, spi1_cs0_n_px6, + spi1_miso_px7, ulpi_clk_py0, ulpi_dir_py1, ulpi_nxt_py2, ulpi_stp_py3, + sdmmc1_dat3_py4, sdmmc1_dat2_py5, sdmmc1_dat1_py6, sdmmc1_dat0_py7, + sdmmc1_clk_pz0, sdmmc1_cmd_pz1, lcd_sdin_pz2, lcd_wr_n_pz3, lcd_sck_pz4, + sys_clk_req_pz5, pwr_i2c_scl_pz6, pwr_i2c_sda_pz7, sdmmc4_dat0_paa0, + sdmmc4_dat1_paa1, sdmmc4_dat2_paa2, sdmmc4_dat3_paa3, sdmmc4_dat4_paa4, + sdmmc4_dat5_paa5, sdmmc4_dat6_paa6, sdmmc4_dat7_paa7, pbb0, + cam_i2c_scl_pbb1, cam_i2c_sda_pbb2, pbb3, pbb4, pbb5, pbb6, pbb7, + cam_mclk_pcc0, pcc1, pcc2, sdmmc4_rst_n_pcc3, sdmmc4_clk_pcc4, + clk2_req_pcc5, pex_l2_rst_n_pcc6, pex_l2_clkreq_n_pcc7, + pex_l0_prsnt_n_pdd0, pex_l0_rst_n_pdd1, pex_l0_clkreq_n_pdd2, + pex_wake_n_pdd3, pex_l1_prsnt_n_pdd4, pex_l1_rst_n_pdd5, + pex_l1_clkreq_n_pdd6, pex_l2_prsnt_n_pdd7, clk3_out_pee0, clk3_req_pee1, + clk1_req_pee2, hdmi_cec_pee3, clk_32k_in, core_pwr_req, cpu_pwr_req, owr, + pwr_int_n. + + drive groups: + + These all support nvidia,pull-down-strength, nvidia,pull-up-strength, + nvidia,slew-rate-rising, nvidia,slew-rate-falling. Most but not all + support nvidia,high-speed-mode, nvidia,schmitt, nvidia,low-power-mode. + + ao1, ao2, at1, at2, at3, at4, at5, cdev1, cdev2, cec, crt, csus, dap1, + dap2, dap3, dap4, dbg, ddc, dev3, gma, gmb, gmc, gmd, gme, gmf, gmg, + gmh, gpv, lcd1, lcd2, owr, sdio1, sdio2, sdio3, spi, uaa, uab, uart2, + uart3, uda, vi1. + +Valid values for nvidia,functions are: + + blink, cec, clk_12m_out, clk_32k_in, core_pwr_req, cpu_pwr_req, crt, + dap, ddr, dev3, displaya, displayb, dtv, extperiph1, extperiph2, + extperiph3, gmi, gmi_alt, hda, hdcp, hdmi, hsi, i2c1, i2c2, i2c3, + i2c4, i2cpwr, i2s0, i2s1, i2s2, i2s3, i2s4, invalid, kbc, mio, nand, + nand_alt, owr, pcie, pwm0, pwm1, pwm2, pwm3, pwr_int_n, rsvd1, rsvd2, + rsvd3, rsvd4, rtck, sata, sdmmc1, sdmmc2, sdmmc3, sdmmc4, spdif, spi1, + spi2, spi2_alt, spi3, spi4, spi5, spi6, sysclk, test, trace, uarta, + uartb, uartc, uartd, uarte, ulpi, vgp1, vgp2, vgp3, vgp4, vgp5, vgp6, + vi, vi_alt1, vi_alt2, vi_alt3 + +Example: + + pinctrl@70000000 { + compatible = "nvidia,tegra30-pinmux"; + reg = < 0x70000868 0xd0 /* Pad control registers */ + 0x70003000 0x3e0 >; /* Mux registers */ + }; + +Example board file extract: + + pinctrl@70000000 { + sdmmc4_default: pinmux { + sdmmc4_clk_pcc4 { + nvidia,pins = "sdmmc4_clk_pcc4", + "sdmmc4_rst_n_pcc3"; + nvidia,function = "sdmmc4"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; + sdmmc4_dat0_paa0 { + nvidia,pins = "sdmmc4_dat0_paa0", + "sdmmc4_dat1_paa1", + "sdmmc4_dat2_paa2", + "sdmmc4_dat3_paa3", + "sdmmc4_dat4_paa4", + "sdmmc4_dat5_paa5", + "sdmmc4_dat6_paa6", + "sdmmc4_dat7_paa7"; + nvidia,function = "sdmmc4"; + nvidia,pull = <2>; + nvidia,tristate = <0>; + }; + }; + }; + + sdhci@78000400 { + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc4_default>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/nxp,lpc1850-scu.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nxp,lpc1850-scu.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd8b0c69fa447b056221814d1c0a25375d18620b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/nxp,lpc1850-scu.txt @@ -0,0 +1,71 @@ +NXP LPC18xx/43xx SCU pin controller Device Tree Bindings +-------------------------------------------------------- + +Required properties: +- compatible : Should be "nxp,lpc1850-scu" +- reg : Address and length of the register set for the device +- clocks : Clock specifier (see clock bindings for details) + +The lpc1850-scu driver uses the generic pin multiplexing and generic pin +configuration documented in pinctrl-bindings.txt. + +The following generic nodes are supported: + - function + - pins + - bias-disable + - bias-pull-up + - bias-pull-down + - drive-strength + - input-enable + - input-disable + - input-schmitt-enable + - input-schmitt-disable + - slew-rate + +NXP specific properties: + - nxp,gpio-pin-interrupt : Assign pin to gpio pin interrupt controller + irq number 0 to 7. See example below. + +Not all pins support all properties so either refer to the NXP 1850/4350 +user manual or the pin table in the pinctrl-lpc18xx driver for supported +pin properties. + +Example: +pinctrl: pinctrl@40086000 { + compatible = "nxp,lpc1850-scu"; + reg = <0x40086000 0x1000>; + clocks = <&ccu1 CLK_CPU_SCU>; + + i2c0_pins: i2c0-pins { + i2c0_pins_cfg { + pins = "i2c0_scl", "i2c0_sda"; + function = "i2c0"; + input-enable; + }; + }; + + uart0_pins: uart0-pins { + uart0_rx_cfg { + pins = "pf_11"; + function = "uart0"; + bias-disable; + input-enable; + }; + + uart0_tx_cfg { + pins = "pf_10"; + function = "uart0"; + bias-disable; + }; + }; + + gpio_joystick_pins: gpio-joystick-pins { + gpio_joystick_1_cfg { + pins = "p9_0"; + function = "gpio"; + nxp,gpio-pin-interrupt = <0>; + input-enable; + bias-disable; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/oxnas,pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/oxnas,pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1159434f593285b3299fb0ee0b38486078e6b4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/oxnas,pinctrl.txt @@ -0,0 +1,56 @@ +* Oxford Semiconductor OXNAS SoC Family Pin Controller + +Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and +../interrupt-controller/interrupts.txt for generic information regarding +pin controller, GPIO, and interrupt bindings. + +OXNAS 'pin configuration node' is a node of a group of pins which can be +used for a specific device or function. This node represents configurations of +pins, optional function, and optional mux related configuration. + +Required properties for pin controller node: + - compatible: "oxsemi,ox810se-pinctrl" or "oxsemi,ox820-pinctrl" + - oxsemi,sys-ctrl: a phandle to the system controller syscon node + +Required properties for pin configuration sub-nodes: + - pins: List of pins to which the configuration applies. + +Optional properties for pin configuration sub-nodes: +---------------------------------------------------- + - function: Mux function for the specified pins. + - bias-pull-up: Enable weak pull-up. + +Example: + +pinctrl: pinctrl { + compatible = "oxsemi,ox810se-pinctrl"; + + /* Regmap for sys registers */ + oxsemi,sys-ctrl = <&sys>; + + pinctrl_uart2: pinctrl_uart2 { + uart2a { + pins = "gpio31"; + function = "fct3"; + }; + uart2b { + pins = "gpio32"; + function = "fct3"; + }; + }; +}; + +uart2: serial@900000 { + compatible = "ns16550a"; + reg = <0x900000 0x100000>; + clocks = <&sysclk>; + interrupts = <29>; + reg-shift = <0>; + fifo-size = <16>; + reg-io-width = <1>; + current-speed = <115200>; + no-loopback-test; + resets = <&reset 22>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-aspeed.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-aspeed.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b7266c7c43888f3977be3ee0aee2c636dde5a64 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-aspeed.txt @@ -0,0 +1,172 @@ +====================== +Aspeed Pin Controllers +====================== + +The Aspeed SoCs vary in functionality inside a generation but have a common mux +device register layout. + +Required properties for g4: +- compatible : Should be one of the following: + "aspeed,ast2400-pinctrl" + "aspeed,g4-pinctrl" + +Required properties for g5: +- compatible : Should be one of the following: + "aspeed,ast2500-pinctrl" + "aspeed,g5-pinctrl" + +- aspeed,external-nodes: A cell of phandles to external controller nodes: + 0: compatible with "aspeed,ast2500-gfx", "syscon" + 1: compatible with "aspeed,ast2500-lhc", "syscon" + +The pin controller node should be the child of a syscon node with the required +property: + +- compatible : Should be one of the following: + "aspeed,ast2400-scu", "syscon", "simple-mfd" + "aspeed,g4-scu", "syscon", "simple-mfd" + "aspeed,ast2500-scu", "syscon", "simple-mfd" + "aspeed,g5-scu", "syscon", "simple-mfd" + +Refer to the the bindings described in +Documentation/devicetree/bindings/mfd/syscon.txt + +Subnode Format +============== + +The required properties of pinmux child nodes are: +- function: the mux function to select +- groups : the list of groups to select with this function + +Required properties of pinconf child nodes are: +- groups: A list of groups to select (either this or "pins" must be + specified) +- pins : A list of ball names as strings, eg "D14" (either this or "groups" + must be specified) + +Optional properties of pinconf child nodes are: +- bias-disable : disable any pin bias +- bias-pull-down: pull down the pin +- drive-strength: sink or source at most X mA + +Definitions are as specified in +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt, with any +further limitations as described above. + +For pinmux, each mux function has only one associated pin group. Each group is +named by its function. The following values for the function and groups +properties are supported: + +aspeed,ast2400-pinctrl, aspeed,g4-pinctrl: + +ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6 +ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT EXTRST FLACK FLBUSY FLWP GPID GPID0 GPID2 +GPID4 GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 +I2C5 I2C6 I2C7 I2C8 I2C9 LPCPD LPCPME LPCRST LPCSMI MAC1LINK MAC2LINK MDIO1 +MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1 NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4 +NDTR1 NDTR2 NDTR3 NDTR4 NDTS4 NRI1 NRI2 NRI3 NRI4 NRTS1 NRTS2 NRTS3 OSCCLK PWM0 +PWM1 PWM2 PWM3 PWM4 PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 ROM16 ROM8 ROMCS1 +ROMCS2 ROMCS3 ROMCS4 RXD1 RXD2 RXD3 RXD4 SALT1 SALT2 SALT3 SALT4 SD1 SD2 SGPMCK +SGPMI SGPMLD SGPMO SGPSCK SGPSI0 SGPSI1 SGPSLD SIOONCTRL SIOPBI SIOPBO SIOPWREQ +SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1DEBUG SPI1PASSTHRU SPICS1 TIMER3 TIMER4 +TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2 TXD3 TXD4 UART6 USB11D1 USB11H2 USB2D1 +USB2H1 USBCKI VGABIOS_ROM VGAHS VGAVS VPI18 VPI24 VPI30 VPO12 VPO24 WDTRST1 +WDTRST2 + +aspeed,ast2500-pinctrl, aspeed,g5-pinctrl: + +ACPI ADC0 ADC1 ADC10 ADC11 ADC12 ADC13 ADC14 ADC15 ADC2 ADC3 ADC4 ADC5 ADC6 +ADC7 ADC8 ADC9 BMCINT DDCCLK DDCDAT ESPI FWSPICS1 FWSPICS2 GPID0 GPID2 GPID4 +GPID6 GPIE0 GPIE2 GPIE4 GPIE6 I2C10 I2C11 I2C12 I2C13 I2C14 I2C3 I2C4 I2C5 I2C6 +I2C7 I2C8 I2C9 LAD0 LAD1 LAD2 LAD3 LCLK LFRAME LPCHC LPCPD LPCPLUS LPCPME +LPCRST LPCSMI LSIRQ MAC1LINK MAC2LINK MDIO1 MDIO2 NCTS1 NCTS2 NCTS3 NCTS4 NDCD1 +NDCD2 NDCD3 NDCD4 NDSR1 NDSR2 NDSR3 NDSR4 NDTR1 NDTR2 NDTR3 NDTR4 NRI1 NRI2 +NRI3 NRI4 NRTS1 NRTS2 NRTS3 NRTS4 OSCCLK PEWAKE PNOR PWM0 PWM1 PWM2 PWM3 PWM4 +PWM5 PWM6 PWM7 RGMII1 RGMII2 RMII1 RMII2 RXD1 RXD2 RXD3 RXD4 SALT1 SALT10 +SALT11 SALT12 SALT13 SALT14 SALT2 SALT3 SALT4 SALT5 SALT6 SALT7 SALT8 SALT9 +SCL1 SCL2 SD1 SD2 SDA1 SDA2 SGPS1 SGPS2 SIOONCTRL SIOPBI SIOPBO SIOPWREQ +SIOPWRGD SIOS3 SIOS5 SIOSCI SPI1 SPI1CS1 SPI1DEBUG SPI1PASSTHRU SPI2CK SPI2CS0 +SPI2CS1 SPI2MISO SPI2MOSI TIMER3 TIMER4 TIMER5 TIMER6 TIMER7 TIMER8 TXD1 TXD2 +TXD3 TXD4 UART6 USB11BHID USB2AD USB2AH USB2BD USB2BH USBCKI VGABIOSROM VGAHS +VGAVS VPI24 VPO WDTRST1 WDTRST2 + +Examples +======== + +g4 Example +---------- + +syscon: scu@1e6e2000 { + compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd"; + reg = <0x1e6e2000 0x1a8>; + + pinctrl: pinctrl { + compatible = "aspeed,g4-pinctrl"; + + pinctrl_i2c3_default: i2c3_default { + function = "I2C3"; + groups = "I2C3"; + }; + + pinctrl_gpioh0_unbiased_default: gpioh0 { + pins = "A8"; + bias-disable; + }; + }; +}; + +g5 Example +---------- + +ahb { + apb { + syscon: scu@1e6e2000 { + compatible = "aspeed,ast2500-scu", "syscon", "simple-mfd"; + reg = <0x1e6e2000 0x1a8>; + + pinctrl: pinctrl { + compatible = "aspeed,g5-pinctrl"; + aspeed,external-nodes = <&gfx &lhc>; + + pinctrl_i2c3_default: i2c3_default { + function = "I2C3"; + groups = "I2C3"; + }; + + pinctrl_gpioh0_unbiased_default: gpioh0 { + pins = "A18"; + bias-disable; + }; + }; + }; + + gfx: display@1e6e6000 { + compatible = "aspeed,ast2500-gfx", "syscon"; + reg = <0x1e6e6000 0x1000>; + }; + }; + + lpc: lpc@1e789000 { + compatible = "aspeed,ast2500-lpc", "simple-mfd"; + reg = <0x1e789000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x1e789000 0x1000>; + + lpc_host: lpc-host@80 { + compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon"; + reg = <0x80 0x1e0>; + reg-io-width = <4>; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x80 0x1e0>; + + lhc: lhc@20 { + compatible = "aspeed,ast2500-lhc"; + reg = <0x20 0x24 0x48 0x8>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-atlas7.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-atlas7.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf9b07016c8730f29a199e100065d19e90e9200a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-atlas7.txt @@ -0,0 +1,109 @@ +CSR SiRFatlas7 pinmux controller + +Required properties: +- compatible : "sirf,atlas7-ioc" +- reg : Address range of the pinctrl registers + +For example, pinctrl might have properties like the following: + pinctrl: ioc@18880000 { + compatible = "sirf,atlas7-ioc"; + reg = <0x18880000 0x1000>; + + a_ac97_pmx: ac97@0 { + ac97 { + groups = "audio_ac97_grp"; + function = "audio_ac97"; + }; + }; + + ... + + sd2_pmx: sd2@0 { + sd2 { + groups = "sd2_grp0"; + function = "sd2"; + }; + }; + + ... + + + sample0_cfg: sample0@0 { + sample0 { + pins = "ldd_0", "ldd_1"; + bias-pull-up; + }; + }; + + sample1_cfg: sample1@0 { + sample1 { + pins = "ldd_2", "ldd_3"; + input-schmitt-enable; + }; + }; + + sample2_cfg: sample2@0 { + sample2 { + groups = "uart4_nopause_grp"; + bias-pull-down; + }; + }; + + sample3_cfg: sample3@0 { + sample3 { + pins = "ldd_4", "ldd_5"; + drive-strength = <2>; + }; + }; + }; + +Please refer to pinctrl-bindings.txt in this directory for details of the common +pinctrl bindings used by client devices. + +SiRFatlas7's pinmux nodes act as a container for an abitrary number of subnodes. +Each of these subnodes represents some desired configuration for a group of pins. + +Required subnode-properties: +- groups : An array of strings. Each string contains the name of a group. +- function: A string containing the name of the function to mux to the + group. + + Valid values for group and function names can be found from looking at the + group and function arrays in driver files: + drivers/pinctrl/pinctrl-sirf.c + +For example, pinctrl might have subnodes like the following: + sd0_pmx: sd0@0 { + sd0 { + groups = "sd0_grp"; + function = "sd0"; + }; + }; + + sd1_pmx0: sd1@0 { + sd1 { + groups = "sd1_grp0"; + function = "sd1_m0"; + }; + }; + + sd1_pmx1: sd1@1 { + sd1 { + groups = "sd1_grp1"; + function = "sd1_m1"; + }; + }; + +For a specific board, if it wants to use sd1, +it can add the following to its board-specific .dts file. +sd1: sd@12340000 { + pinctrl-names = "default"; + pinctrl-0 = <&sd1_pmx0>; +} + +or + +sd1: sd@12340000 { + pinctrl-names = "default"; + pinctrl-0 = <&sd1_pmx1>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-bindings.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-bindings.txt new file mode 100644 index 0000000000000000000000000000000000000000..cef2b5855d60fdaef2c62960e19dd0f087564cc5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-bindings.txt @@ -0,0 +1,333 @@ +== Introduction == + +Hardware modules that control pin multiplexing or configuration parameters +such as pull-up/down, tri-state, drive-strength etc are designated as pin +controllers. Each pin controller must be represented as a node in device tree, +just like any other hardware module. + +Hardware modules whose signals are affected by pin configuration are +designated client devices. Again, each client device must be represented as a +node in device tree, just like any other hardware module. + +For a client device to operate correctly, certain pin controllers must +set up certain specific pin configurations. Some client devices need a +single static pin configuration, e.g. set up during initialization. Others +need to reconfigure pins at run-time, for example to tri-state pins when the +device is inactive. Hence, each client device can define a set of named +states. The number and names of those states is defined by the client device's +own binding. + +The common pinctrl bindings defined in this file provide an infrastructure +for client device device tree nodes to map those state names to the pin +configuration used by those states. + +Note that pin controllers themselves may also be client devices of themselves. +For example, a pin controller may set up its own "active" state when the +driver loads. This would allow representing a board's static pin configuration +in a single place, rather than splitting it across multiple client device +nodes. The decision to do this or not somewhat rests with the author of +individual board device tree files, and any requirements imposed by the +bindings for the individual client devices in use by that board, i.e. whether +they require certain specific named states for dynamic pin configuration. + +== Pinctrl client devices == + +For each client device individually, every pin state is assigned an integer +ID. These numbers start at 0, and are contiguous. For each state ID, a unique +property exists to define the pin configuration. Each state may also be +assigned a name. When names are used, another property exists to map from +those names to the integer IDs. + +Each client device's own binding determines the set of states that must be +defined in its device tree node, and whether to define the set of state +IDs that must be provided, or whether to define the set of state names that +must be provided. + +Required properties: +pinctrl-0: List of phandles, each pointing at a pin configuration + node. These referenced pin configuration nodes must be child + nodes of the pin controller that they configure. Multiple + entries may exist in this list so that multiple pin + controllers may be configured, or so that a state may be built + from multiple nodes for a single pin controller, each + contributing part of the overall configuration. See the next + section of this document for details of the format of these + pin configuration nodes. + + In some cases, it may be useful to define a state, but for it + to be empty. This may be required when a common IP block is + used in an SoC either without a pin controller, or where the + pin controller does not affect the HW module in question. If + the binding for that IP block requires certain pin states to + exist, they must still be defined, but may be left empty. + +Optional properties: +pinctrl-1: List of phandles, each pointing at a pin configuration + node within a pin controller. +... +pinctrl-n: List of phandles, each pointing at a pin configuration + node within a pin controller. +pinctrl-names: The list of names to assign states. List entry 0 defines the + name for integer state ID 0, list entry 1 for state ID 1, and + so on. + +For example: + + /* For a client device requiring named states */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* For the same device if using state IDs */ + device { + pinctrl-0 = <&state_0_node_a>; + pinctrl-1 = <&state_1_node_a &state_1_node_b>; + }; + + /* + * For an IP block whose binding supports pin configuration, + * but in use on an SoC that doesn't have any pin control hardware + */ + device { + pinctrl-names = "active", "idle"; + pinctrl-0 = <>; + pinctrl-1 = <>; + }; + +== Pin controller devices == +Required properties: See the pin controller driver specific documentation + +Optional properties: +#pinctrl-cells: Number of pin control cells in addition to the index within the + pin controller device instance + +pinctrl-use-default: Boolean. Indicates that the OS can use the boot default + pin configuration. This allows using an OS that does not have a + driver for the pin controller. This property can be set either + globally for the pin controller or in child nodes for individual + pin group control. + +Pin controller devices should contain the pin configuration nodes that client +devices reference. + +For example: + + pincontroller { + ... /* Standard DT properties for the device itself elided */ + + state_0_node_a { + ... + }; + state_1_node_a { + ... + }; + state_1_node_b { + ... + }; + } + +The contents of each of those pin configuration child nodes is defined +entirely by the binding for the individual pin controller device. There +exists no common standard for this content. The pinctrl framework only +provides generic helper bindings that the pin controller driver can use. + +The pin configuration nodes need not be direct children of the pin controller +device; they may be grandchildren, for example. Whether this is legal, and +whether there is any interaction between the child and intermediate parent +nodes, is again defined entirely by the binding for the individual pin +controller device. + +== Generic pin multiplexing node content == + +pin multiplexing nodes: + +function - the mux function to select +groups - the list of groups to select with this function + (either this or "pins" must be specified) +pins - the list of pins to select with this function (either + this or "groups" must be specified) + +Example: + +state_0_node_a { + uart0 { + function = "uart0"; + groups = "u0rxtx", "u0rtscts"; + }; +}; +state_1_node_a { + spi0 { + function = "spi0"; + groups = "spi0pins"; + }; +}; +state_2_node_a { + function = "i2c0"; + pins = "mfio29", "mfio30"; +}; + +Optionally an alternative binding can be used if more suitable depending on the +pin controller hardware. For hardware where there is a large number of identical +pin controller instances, naming each pin and function can easily become +unmaintainable. This is especially the case if the same controller is used for +different pins and functions depending on the SoC revision and packaging. + +For cases like this, the pin controller driver may use pinctrl-pin-array helper +binding with a hardware based index and a number of pin configuration values: + +pincontroller { + ... /* Standard DT properties for the device itself elided */ + #pinctrl-cells = <2>; + + state_0_node_a { + pinctrl-pin-array = < + 0 A_DELAY_PS(0) G_DELAY_PS(120) + 4 A_DELAY_PS(0) G_DELAY_PS(360) + ... + >; + }; + ... +}; + +Above #pinctrl-cells specifies the number of value cells in addition to the +index of the registers. This is similar to the interrupts-extended binding with +one exception. There is no need to specify the phandle for each entry as that +is already known as the defined pins are always children of the pin controller +node. Further having the phandle pointing to another pin controller would not +currently work as the pinctrl framework uses named modes to group pins for each +pin control device. + +The index for pinctrl-pin-array must relate to the hardware for the pinctrl +registers, and must not be a virtual index of pin instances. The reason for +this is to avoid mapping of the index in the dts files and the pin controller +driver as it can change. + +For hardware where pin multiplexing configurations have to be specified for +each single pin the number of required sub-nodes containing "pin" and +"function" properties can quickly escalate and become hard to write and +maintain. + +For cases like this, the pin controller driver may use the pinmux helper +property, where the pin identifier is provided with mux configuration settings +in a pinmux group. A pinmux group consists of the pin identifier and mux +settings represented as a single integer or an array of integers. + +The pinmux property accepts an array of pinmux groups, each of them describing +a single pin multiplexing configuration. + +pincontroller { + state_0_node_a { + pinmux = , , ...; + }; +}; + +Each individual pin controller driver bindings documentation shall specify +how pin IDs and pin multiplexing configuration are defined and assembled +together in a pinmux group. + +== Generic pin configuration node content == + +Many data items that are represented in a pin configuration node are common +and generic. Pin control bindings should use the properties defined below +where they are applicable; not all of these properties are relevant or useful +for all hardware or binding structures. Each individual binding document +should state which of these generic properties, if any, are used, and the +structure of the DT nodes that contain these properties. + +Supported generic properties are: + +pins - the list of pins that properties in the node + apply to (either this, "group" or "pinmux" has to be + specified) +group - the group to apply the properties to, if the driver + supports configuration of whole groups rather than + individual pins (either this, "pins" or "pinmux" has + to be specified) +pinmux - the list of numeric pin ids and their mux settings + that properties in the node apply to (either this, + "pins" or "groups" have to be specified) +bias-disable - disable any pin bias +bias-high-impedance - high impedance mode ("third-state", "floating") +bias-bus-hold - latch weakly +bias-pull-up - pull up the pin +bias-pull-down - pull down the pin +bias-pull-pin-default - use pin-default pull state +drive-push-pull - drive actively high and low +drive-open-drain - drive with open drain +drive-open-source - drive with open source +drive-strength - sink or source at most X mA +input-enable - enable input on pin (no effect on output, such as + enabling an input buffer) +input-disable - disable input on pin (no effect on output, such as + disabling an input buffer) +input-schmitt-enable - enable schmitt-trigger mode +input-schmitt-disable - disable schmitt-trigger mode +input-debounce - debounce mode with debound time X +power-source - select between different power supplies +low-power-enable - enable low power mode +low-power-disable - disable low power mode +output-disable - disable output on a pin (such as disable an output + buffer) +output-enable - enable output on a pin without actively driving it + (such as enabling an output buffer) +output-low - set the pin to output mode with low level +output-high - set the pin to output mode with high level +sleep-hardware-state - indicate this is sleep related state which will be programmed + into the registers for the sleep state. +slew-rate - set the slew rate +skew-delay - this affects the expected clock skew on input pins + and the delay before latching a value to an output + pin. Typically indicates how many double-inverters are + used to delay the signal. + +For example: + +state_0_node_a { + cts_rxd { + pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */ + bias-pull-up; + }; +}; +state_1_node_a { + rts_txd { + pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */ + output-high; + }; +}; +state_2_node_a { + foo { + group = "foo-group"; + bias-pull-up; + }; +}; +state_3_node_a { + mux { + pinmux = , ; + input-enable; + }; +}; + +Some of the generic properties take arguments. For those that do, the +arguments are described below. + +- pins takes a list of pin names or IDs as a required argument. The specific + binding for the hardware defines: + - Whether the entries are integers or strings, and their meaning. + +- pinmux takes a list of pin IDs and mux settings as required argument. The + specific bindings for the hardware defines: + - How pin IDs and mux settings are defined and assembled together in a single + integer or an array of integers. + +- bias-pull-up, -down and -pin-default take as optional argument on hardware + supporting it the pull strength in Ohm. bias-disable will disable the pull. + +- drive-strength takes as argument the target strength in mA. + +- input-debounce takes the debounce time in usec as argument + or 0 to disable debouncing + +More in-depth documentation on these parameters can be found in + diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-max77620.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-max77620.txt new file mode 100644 index 0000000000000000000000000000000000000000..511fc234558bf1743c76c2f2d03c4c40b2a22bfd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-max77620.txt @@ -0,0 +1,127 @@ +Pincontrol driver for MAX77620 Power management IC from Maxim Semiconductor. + +Device has 8 GPIO pins which can be configured as GPIO as well as the +special IO functions. + +Please refer file +for details of the common pinctrl bindings used by client devices, +including the meaning of the phrase "pin configuration node". + +Optional Pinmux properties: +-------------------------- +Following properties are required if default setting of pins are required +at boot. +- pinctrl-names: A pinctrl state named per . +- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per + . + +The pin configurations are defined as child of the pinctrl states node. Each +sub-node have following properties: + +Required properties: +------------------ +- pins: List of pins. Valid values of pins properties are: + gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6, gpio7. + +Optional properties: +------------------- +Following are optional properties defined as pinmux DT binding document +. Absence of properties will leave the configuration +on default. + function, + drive-push-pull, + drive-open-drain, + bias-pull-up, + bias-pull-down. + +Valid values for function properties are: + gpio, lpm-control-in, fps-out, 32k-out, sd0-dvs-in, sd1-dvs-in, + reference-out + +Theres is also customised properties for the GPIO1, GPIO2 and GPIO3. These +customised properties are required to configure FPS configuration parameters +of these GPIOs. Please refer for more +detail of Flexible Power Sequence (FPS). + +- maxim,active-fps-source: FPS source for the GPIOs to get + enabled/disabled when system is in + active state. Valid values are: + - MAX77620_FPS_SRC_0, + FPS source is FPS0. + - MAX77620_FPS_SRC_1, + FPS source is FPS1 + - MAX77620_FPS_SRC_2 and + FPS source is FPS2 + - MAX77620_FPS_SRC_NONE. + GPIO is not controlled + by FPS events and it gets + enabled/disabled by register + access. + Absence of this property will leave + the FPS configuration register for that + GPIO to default configuration. + +- maxim,active-fps-power-up-slot: Sequencing event slot number on which + the GPIO get enabled when + master FPS input event set to HIGH. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + +- maxim,active-fps-power-down-slot: Sequencing event slot number on which + the GPIO get disabled when master + FPS input event set to LOW. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + +- maxim,suspend-fps-source: This is same as property + "maxim,active-fps-source" but value + get configured when system enters in + to suspend state. + +- maxim,suspend-fps-power-up-slot: This is same as property + "maxim,active-fps-power-up-slot" but + this value get configured into FPS + configuration register when system + enters into suspend. + This is applicable if suspend state + FPS source is selected as FPS0, FPS1 or + +- maxim,suspend-fps-power-down-slot: This is same as property + "maxim,active-fps-power-down-slot" but + this value get configured into FPS + configuration register when system + enters into suspend. + This is applicable if suspend state + FPS source is selected as FPS0, FPS1 or + FPS2. + +Example: +-------- +#include +... +max77620@3c { + + pinctrl-names = "default"; + pinctrl-0 = <&spmic_default>; + + spmic_default: pinmux@0 { + pin_gpio0 { + pins = "gpio0"; + function = "gpio"; + }; + + pin_gpio1 { + pins = "gpio1"; + function = "fps-out"; + maxim,active-fps-source = ; + }; + + pin_gpio2 { + pins = "gpio2"; + function = "fps-out"; + maxim,active-fps-source = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mcp23s08.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mcp23s08.txt new file mode 100644 index 0000000000000000000000000000000000000000..625a22e2f2115050477e59c076203be38346ae91 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mcp23s08.txt @@ -0,0 +1,146 @@ +Microchip MCP2308/MCP23S08/MCP23017/MCP23S17 driver for +8-/16-bit I/O expander with serial interface (I2C/SPI) + +Required properties: +- compatible : Should be + - "mcp,mcp23s08" (DEPRECATED) for 8 GPIO SPI version + - "mcp,mcp23s17" (DEPRECATED) for 16 GPIO SPI version + - "mcp,mcp23008" (DEPRECATED) for 8 GPIO I2C version or + - "mcp,mcp23017" (DEPRECATED) for 16 GPIO I2C version of the chip + + - "microchip,mcp23s08" for 8 GPIO SPI version + - "microchip,mcp23s17" for 16 GPIO SPI version + - "microchip,mcp23s18" for 16 GPIO SPI version + - "microchip,mcp23008" for 8 GPIO I2C version or + - "microchip,mcp23017" for 16 GPIO I2C version of the chip + - "microchip,mcp23018" for 16 GPIO I2C version + NOTE: Do not use the old mcp prefix any more. It is deprecated and will be + removed. +- #gpio-cells : Should be two. + - first cell is the pin number + - second cell is used to specify flags as described in + 'Documentation/devicetree/bindings/gpio/gpio.txt'. Allowed values defined by + 'include/dt-bindings/gpio/gpio.h' (e.g. GPIO_ACTIVE_LOW). +- gpio-controller : Marks the device node as a GPIO controller. +- reg : For an address on its bus. I2C uses this a the I2C address of the chip. + SPI uses this to specify the chipselect line which the chip is + connected to. The driver and the SPI variant of the chip support + multiple chips on the same chipselect. Have a look at + microchip,spi-present-mask below. + +Required device specific properties (only for SPI chips): +- mcp,spi-present-mask (DEPRECATED) +- microchip,spi-present-mask : This is a present flag, that makes only sense for SPI + chips - as the name suggests. Multiple SPI chips can share the same + SPI chipselect. Set a bit in bit0-7 in this mask to 1 if there is a + chip connected with the corresponding spi address set. For example if + you have a chip with address 3 connected, you have to set bit3 to 1, + which is 0x08. mcp23s08 chip variant only supports bits 0-3. It is not + possible to mix mcp23s08 and mcp23s17 on the same chipselect. Set at + least one bit to 1 for SPI chips. + NOTE: Do not use the old mcp prefix any more. It is deprecated and will be + removed. +- spi-max-frequency = The maximum frequency this chip is able to handle + +Optional properties: +- #interrupt-cells : Should be two. + - first cell is the pin number + - second cell is used to specify flags. +- interrupt-controller: Marks the device node as a interrupt controller. +- drive-open-drain: Sets the ODR flag in the IOCON register. This configures + the IRQ output as open drain active low. + +Optional device specific properties: +- microchip,irq-mirror: Sets the mirror flag in the IOCON register. Devices + with two interrupt outputs (these are the devices ending with 17 and + those that have 16 IOs) have two IO banks: IO 0-7 form bank 1 and + IO 8-15 are bank 2. These chips have two different interrupt outputs: + One for bank 1 and another for bank 2. If irq-mirror is set, both + interrupts are generated regardless of the bank that an input change + occurred on. If it is not set, the interrupt are only generated for the + bank they belong to. + On devices with only one interrupt output this property is useless. +- microchip,irq-active-high: Sets the INTPOL flag in the IOCON register. This + configures the IRQ output polarity as active high. + +Example I2C (with interrupt): +gpiom1: gpio@20 { + compatible = "microchip,mcp23017"; + gpio-controller; + #gpio-cells = <2>; + reg = <0x20>; + + interrupt-parent = <&gpio1>; + interrupts = <17 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells=<2>; + microchip,irq-mirror; +}; + +Example SPI: +gpiom1: gpio@0 { + compatible = "microchip,mcp23s17"; + gpio-controller; + #gpio-cells = <2>; + spi-present-mask = <0x01>; + reg = <0>; + spi-max-frequency = <1000000>; +}; + +Pull-up configuration +===================== + +If pins are used as output, they can also be configured with pull-ups. This is +done with pinctrl. + +Please refer file +for details of the common pinctrl bindings used by client devices, +including the meaning of the phrase "pin configuration node". + +Optional Pinmux properties: +-------------------------- +Following properties are required if default setting of pins are required +at boot. +- pinctrl-names: A pinctrl state named per . +- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per + . + +The pin configurations are defined as child of the pinctrl states node. Each +sub-node have following properties: + +Required properties: +------------------ +- pins: List of pins. Valid values of pins properties are: + gpio0 ... gpio7 for the devices with 8 GPIO pins and + gpio0 ... gpio15 for the devices with 16 GPIO pins. + +Optional properties: +------------------- +The following optional property is defined in the pinmux DT binding document +. Absence of this property will leave the configuration +in its default state. + bias-pull-up + +Example with pinctrl to pull-up output pins: +gpio21: gpio@21 { + compatible = "microchip,mcp23017"; + gpio-controller; + #gpio-cells = <0x2>; + reg = <0x21>; + interrupt-parent = <&socgpio>; + interrupts = <0x17 0x8>; + interrupt-names = "mcp23017@21 irq"; + interrupt-controller; + #interrupt-cells = <0x2>; + microchip,irq-mirror; + pinctrl-names = "default"; + pinctrl-0 = <&i2cgpio0irq &gpio21pullups>; + + gpio21pullups: pinmux { + pins = "gpio0", "gpio1", "gpio2", "gpio3", + "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15"; + bias-pull-up; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mt65xx.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mt65xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7d6f81c227f84628c8bbc5e2d3afa669d4ec61c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mt65xx.txt @@ -0,0 +1,153 @@ +* Mediatek MT65XX Pin Controller + +The Mediatek's Pin controller is used to control SoC pins. + +Required properties: +- compatible: value should be one of the following. + "mediatek,mt2701-pinctrl", compatible with mt2701 pinctrl. + "mediatek,mt2712-pinctrl", compatible with mt2712 pinctrl. + "mediatek,mt6397-pinctrl", compatible with mt6397 pinctrl. + "mediatek,mt7623-pinctrl", compatible with mt7623 pinctrl. + "mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl. + "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl. + "mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl. +- pins-are-numbered: Specify the subnodes are using numbered pinmux to + specify pins. +- gpio-controller : Marks the device node as a gpio controller. +- #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO + binding is used, the amount of cells must be specified as 2. See the below + mentioned gpio binding representation for description of particular cells. + + Eg: <&pio 6 0> + <[phandle of the gpio controller node] + [line number within the gpio controller] + [flags]> + + Values for gpio specifier: + - Line number: is a value between 0 to 202. + - Flags: bit field of flags, as defined in . + Only the following flags are supported: + 0 - GPIO_ACTIVE_HIGH + 1 - GPIO_ACTIVE_LOW + +Optional properties: +- mediatek,pctl-regmap: Should be a phandle of the syscfg node. +- reg: physicall address base for EINT registers +- interrupt-controller: Marks the device node as an interrupt controller +- #interrupt-cells: Should be two. +- interrupts : The interrupt outputs from the controller. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. + +Subnode format +A pinctrl node should contain at least one subnodes representing the +pinctrl groups available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, pullups, drive strength, input enable/disable and input schmitt. + + node { + pinmux = ; + GENERIC_PINCONFIG; + }; + +Required properties: +- pinmux: integer array, represents gpio pin number and mux setting. + Supported pin number and mux varies for different SoCs, and are defined + as macros in boot/dts/-pinfunc.h directly. + +Optional properties: +- GENERIC_PINCONFIG: is the generic pinconfig options to use, bias-disable, + bias-pull-down, bias-pull-up, input-enable, input-disable, output-low, output-high, + input-schmitt-enable, input-schmitt-disable and drive-strength are valid. + + Some special pins have extra pull up strength, there are R0 and R1 pull-up + resistors available, but for user, it's only need to set R1R0 as 00, 01, 10 or 11. + So when config bias-pull-up, it support arguments for those special pins. + Some macros have been defined for this usage, such as MTK_PUPD_SET_R1R0_00. + See dt-bindings/pinctrl/mt65xx.h. + + When config drive-strength, it can support some arguments, such as + MTK_DRIVE_4mA, MTK_DRIVE_6mA, etc. See dt-bindings/pinctrl/mt65xx.h. + +Examples: + +#include "mt8135-pinfunc.h" + +... +{ + syscfg_pctl_a: syscfg-pctl-a@10005000 { + compatible = "mediatek,mt8135-pctl-a-syscfg", "syscon"; + reg = <0 0x10005000 0 0x1000>; + }; + + syscfg_pctl_b: syscfg-pctl-b@1020c020 { + compatible = "mediatek,mt8135-pctl-b-syscfg", "syscon"; + reg = <0 0x1020C020 0 0x1000>; + }; + + pinctrl@1c20800 { + compatible = "mediatek,mt8135-pinctrl"; + reg = <0 0x1000B000 0 0x1000>; + mediatek,pctl-regmap = <&syscfg_pctl_a &syscfg_pctl_b>; + pins-are-numbered; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + ; + + i2c0_pins_a: i2c0@0 { + pins1 { + pinmux = , + ; + bias-disable; + }; + }; + + i2c1_pins_a: i2c1@0 { + pins { + pinmux = , + ; + bias-pull-up = <55>; + }; + }; + + i2c2_pins_a: i2c2@0 { + pins1 { + pinmux = ; + bias-pull-down; + }; + + pins2 { + pinmux = ; + bias-pull-up; + }; + }; + + i2c3_pins_a: i2c3@0 { + pins1 { + pinmux = , + ; + bias-pull-up = <55>; + }; + + pins2 { + pinmux = , + ; + output-low; + bias-pull-up = <55>; + }; + + pins3 { + pinmux = , + ; + drive-strength = <32>; + }; + }; + + ... + } +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mt7622.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mt7622.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b695131c51bdee18a8f706f845ba5a64868d79d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-mt7622.txt @@ -0,0 +1,359 @@ +== MediaTek MT7622 pinctrl controller == + +Required properties for the root node: + - compatible: Should be one of the following + "mediatek,mt7622-pinctrl" for MT7622 SoC + - reg: offset and length of the pinctrl space + + - gpio-controller: Marks the device node as a GPIO controller. + - #gpio-cells: Should be two. The first cell is the pin number and the + second is the GPIO flags. + +Optional properties: +- interrupt-controller : Marks the device node as an interrupt controller + +If the property interrupt-controller is defined, following property is required +- reg-names: A string describing the "reg" entries. Must contain "eint". +- interrupts : The interrupt output from the controller. +- #interrupt-cells: Should be two. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +MT7622 pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, slew rate, etc. + +We support 2 types of configuration nodes. Those nodes can be either pinmux +nodes or pinconf nodes. Each configuration node can consist of multiple nodes +describing the pinmux and pinconf options. + +The name of each subnode doesn't matter as long as it is unique; all subnodes +should be enumerated and processed purely based on their content. + +== pinmux nodes content == + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinmux subnode: + +Required properties are: + - groups: An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. + - function: A string containing the name of the function to mux to the + group. Valid values for function names are listed below. + +== pinconf nodes content == + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinconf subnode: + +Required properties are: + - pins: An array of strings. Each string contains the name of a pin. + Valid values for these names are listed below. + - groups: An array of strings. Each string contains the name of a group. + Valid values for these names are listed below. + +Optional properies are: + bias-disable, bias-pull, bias-pull-down, input-enable, + input-schmitt-enable, input-schmitt-disable, output-enable + output-low, output-high, drive-strength, slew-rate + + Valid arguments for 'slew-rate' are '0' for no slew rate controlled and '1' for + slower slew rate respectively. + Valid arguments for 'drive-strength', 4, 8, 12, or 16 in mA. + +The following specific properties as defined are valid to specify in a pinconf +subnode: + +Optional properties are: + - mediatek,tdsel: An integer describing the steps for output level shifter duty + cycle when asserted (high pulse width adjustment). Valid arguments are from 0 + to 15. + - mediatek,rdsel: An integer describing the steps for input level shifter duty + cycle when asserted (high pulse width adjustment). Valid arguments are from 0 + to 63. + +== Valid values for pins, function and groups on MT7622 == + +Valid values for pins are: +pins can be referenced via the pin names as the below table shown and the +related physical number is also put ahead of those names which helps cross +references to pins between groups to know whether pins assignment conflict +happens among devices try to acquire those available pins. + + Pin #: Valid values for pins + ----------------------------- + PIN 0: "GPIO_A" + PIN 1: "I2S1_IN" + PIN 2: "I2S1_OUT" + PIN 3: "I2S_BCLK" + PIN 4: "I2S_WS" + PIN 5: "I2S_MCLK" + PIN 6: "TXD0" + PIN 7: "RXD0" + PIN 8: "SPI_WP" + PIN 9: "SPI_HOLD" + PIN 10: "SPI_CLK" + PIN 11: "SPI_MOSI" + PIN 12: "SPI_MISO" + PIN 13: "SPI_CS" + PIN 14: "I2C_SDA" + PIN 15: "I2C_SCL" + PIN 16: "I2S2_IN" + PIN 17: "I2S3_IN" + PIN 18: "I2S4_IN" + PIN 19: "I2S2_OUT" + PIN 20: "I2S3_OUT" + PIN 21: "I2S4_OUT" + PIN 22: "GPIO_B" + PIN 23: "MDC" + PIN 24: "MDIO" + PIN 25: "G2_TXD0" + PIN 26: "G2_TXD1" + PIN 27: "G2_TXD2" + PIN 28: "G2_TXD3" + PIN 29: "G2_TXEN" + PIN 30: "G2_TXC" + PIN 31: "G2_RXD0" + PIN 32: "G2_RXD1" + PIN 33: "G2_RXD2" + PIN 34: "G2_RXD3" + PIN 35: "G2_RXDV" + PIN 36: "G2_RXC" + PIN 37: "NCEB" + PIN 38: "NWEB" + PIN 39: "NREB" + PIN 40: "NDL4" + PIN 41: "NDL5" + PIN 42: "NDL6" + PIN 43: "NDL7" + PIN 44: "NRB" + PIN 45: "NCLE" + PIN 46: "NALE" + PIN 47: "NDL0" + PIN 48: "NDL1" + PIN 49: "NDL2" + PIN 50: "NDL3" + PIN 51: "MDI_TP_P0" + PIN 52: "MDI_TN_P0" + PIN 53: "MDI_RP_P0" + PIN 54: "MDI_RN_P0" + PIN 55: "MDI_TP_P1" + PIN 56: "MDI_TN_P1" + PIN 57: "MDI_RP_P1" + PIN 58: "MDI_RN_P1" + PIN 59: "MDI_RP_P2" + PIN 60: "MDI_RN_P2" + PIN 61: "MDI_TP_P2" + PIN 62: "MDI_TN_P2" + PIN 63: "MDI_TP_P3" + PIN 64: "MDI_TN_P3" + PIN 65: "MDI_RP_P3" + PIN 66: "MDI_RN_P3" + PIN 67: "MDI_RP_P4" + PIN 68: "MDI_RN_P4" + PIN 69: "MDI_TP_P4" + PIN 70: "MDI_TN_P4" + PIN 71: "PMIC_SCL" + PIN 72: "PMIC_SDA" + PIN 73: "SPIC1_CLK" + PIN 74: "SPIC1_MOSI" + PIN 75: "SPIC1_MISO" + PIN 76: "SPIC1_CS" + PIN 77: "GPIO_D" + PIN 78: "WATCHDOG" + PIN 79: "RTS3_N" + PIN 80: "CTS3_N" + PIN 81: "TXD3" + PIN 82: "RXD3" + PIN 83: "PERST0_N" + PIN 84: "PERST1_N" + PIN 85: "WLED_N" + PIN 86: "EPHY_LED0_N" + PIN 87: "AUXIN0" + PIN 88: "AUXIN1" + PIN 89: "AUXIN2" + PIN 90: "AUXIN3" + PIN 91: "TXD4" + PIN 92: "RXD4" + PIN 93: "RTS4_N" + PIN 94: "CST4_N" + PIN 95: "PWM1" + PIN 96: "PWM2" + PIN 97: "PWM3" + PIN 98: "PWM4" + PIN 99: "PWM5" + PIN 100: "PWM6" + PIN 101: "PWM7" + PIN 102: "GPIO_E" + +Valid values for function are: + "emmc", "eth", "i2c", "i2s", "ir", "led", "flash", "pcie", + "pmic", "pwm", "sd", "spi", "tdm", "uart", "watchdog" + +Valid values for groups are: +additional data is put followingly with valid value allowing us to know which +applicable function and which relevant pins (in pin#) are able applied for that +group. + + Valid value function pins (in pin#) + ------------------------------------------------------------------------- + "emmc" "emmc" 40, 41, 42, 43, 44, 45, + 47, 48, 49, 50 + "emmc_rst" "emmc" 37 + "esw" "eth" 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, + 69, 70 + "esw_p0_p1" "eth" 51, 52, 53, 54, 55, 56, + 57, 58 + "esw_p2_p3_p4" "eth" 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70 + "rgmii_via_esw" "eth" 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70 + "rgmii_via_gmac1" "eth" 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70 + "rgmii_via_gmac2" "eth" 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36 + "mdc_mdio" "eth" 23, 24 + "i2c0" "i2c" 14, 15 + "i2c1_0" "i2c" 55, 56 + "i2c1_1" "i2c" 73, 74 + "i2c1_2" "i2c" 87, 88 + "i2c2_0" "i2c" 57, 58 + "i2c2_1" "i2c" 75, 76 + "i2c2_2" "i2c" 89, 90 + "i2s_in_mclk_bclk_ws" "i2s" 3, 4, 5 + "i2s1_in_data" "i2s" 1 + "i2s2_in_data" "i2s" 16 + "i2s3_in_data" "i2s" 17 + "i2s4_in_data" "i2s" 18 + "i2s_out_mclk_bclk_ws" "i2s" 3, 4, 5 + "i2s1_out_data" "i2s" 2 + "i2s2_out_data" "i2s" 19 + "i2s3_out_data" "i2s" 20 + "i2s4_out_data" "i2s" 21 + "ir_0_tx" "ir" 16 + "ir_1_tx" "ir" 59 + "ir_2_tx" "ir" 99 + "ir_0_rx" "ir" 17 + "ir_1_rx" "ir" 60 + "ir_2_rx" "ir" 100 + "ephy_leds" "led" 86, 91, 92, 93, 94 + "ephy0_led" "led" 86 + "ephy1_led" "led" 91 + "ephy2_led" "led" 92 + "ephy3_led" "led" 93 + "ephy4_led" "led" 94 + "wled" "led" 85 + "par_nand" "flash" 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, + 49, 50 + "snfi" "flash" 8, 9, 10, 11, 12, 13 + "spi_nor" "flash" 8, 9, 10, 11, 12, 13 + "pcie0_0_waken" "pcie" 14 + "pcie0_1_waken" "pcie" 79 + "pcie1_0_waken" "pcie" 14 + "pcie0_0_clkreq" "pcie" 15 + "pcie0_1_clkreq" "pcie" 80 + "pcie1_0_clkreq" "pcie" 15 + "pcie0_pad_perst" "pcie" 83 + "pcie1_pad_perst" "pcie" 84 + "pmic_bus" "pmic" 71, 72 + "pwm_ch1_0" "pwm" 51 + "pwm_ch1_1" "pwm" 73 + "pwm_ch1_2" "pwm" 95 + "pwm_ch2_0" "pwm" 52 + "pwm_ch2_1" "pwm" 74 + "pwm_ch2_2" "pwm" 96 + "pwm_ch3_0" "pwm" 53 + "pwm_ch3_1" "pwm" 75 + "pwm_ch3_2" "pwm" 97 + "pwm_ch4_0" "pwm" 54 + "pwm_ch4_1" "pwm" 67 + "pwm_ch4_2" "pwm" 76 + "pwm_ch4_3" "pwm" 98 + "pwm_ch5_0" "pwm" 68 + "pwm_ch5_1" "pwm" 77 + "pwm_ch5_2" "pwm" 99 + "pwm_ch6_0" "pwm" 69 + "pwm_ch6_1" "pwm" 78 + "pwm_ch6_2" "pwm" 81 + "pwm_ch6_3" "pwm" 100 + "pwm_ch7_0" "pwm" 70 + "pwm_ch7_1" "pwm" 82 + "pwm_ch7_2" "pwm" 101 + "sd_0" "sd" 16, 17, 18, 19, 20, 21 + "sd_1" "sd" 25, 26, 27, 28, 29, 30 + "spic0_0" "spi" 63, 64, 65, 66 + "spic0_1" "spi" 79, 80, 81, 82 + "spic1_0" "spi" 67, 68, 69, 70 + "spic1_1" "spi" 73, 74, 75, 76 + "spic2_0_wp_hold" "spi" 8, 9 + "spic2_0" "spi" 10, 11, 12, 13 + "tdm_0_out_mclk_bclk_ws" "tdm" 8, 9, 10 + "tdm_0_in_mclk_bclk_ws" "tdm" 11, 12, 13 + "tdm_0_out_data" "tdm" 20 + "tdm_0_in_data" "tdm" 21 + "tdm_1_out_mclk_bclk_ws" "tdm" 57, 58, 59 + "tdm_1_in_mclk_bclk_ws" "tdm" 60, 61, 62 + "tdm_1_out_data" "tdm" 55 + "tdm_1_in_data" "tdm" 56 + "uart0_0_tx_rx" "uart" 6, 7 + "uart1_0_tx_rx" "uart" 55, 56 + "uart1_0_rts_cts" "uart" 57, 58 + "uart1_1_tx_rx" "uart" 73, 74 + "uart1_1_rts_cts" "uart" 75, 76 + "uart2_0_tx_rx" "uart" 3, 4 + "uart2_0_rts_cts" "uart" 1, 2 + "uart2_1_tx_rx" "uart" 51, 52 + "uart2_1_rts_cts" "uart" 53, 54 + "uart2_2_tx_rx" "uart" 59, 60 + "uart2_2_rts_cts" "uart" 61, 62 + "uart2_3_tx_rx" "uart" 95, 96 + "uart3_0_tx_rx" "uart" 57, 58 + "uart3_1_tx_rx" "uart" 81, 82 + "uart3_1_rts_cts" "uart" 79, 80 + "uart4_0_tx_rx" "uart" 61, 62 + "uart4_1_tx_rx" "uart" 91, 92 + "uart4_1_rts_cts" "uart" 93, 94 + "uart4_2_tx_rx" "uart" 97, 98 + "uart4_2_rts_cts" "uart" 95, 96 + "watchdog" "watchdog" 78 + +Example: + + pio: pinctrl@10211000 { + compatible = "mediatek,mt7622-pinctrl"; + reg = <0 0x10211000 0 0x1000>; + gpio-controller; + #gpio-cells = <2>; + + pinctrl_eth_default: eth-default { + mux-mdio { + groups = "mdc_mdio"; + function = "eth"; + drive-strength = <12>; + }; + + mux-gmac2 { + groups = "gmac2"; + function = "eth"; + drive-strength = <12>; + }; + + mux-esw { + groups = "esw"; + function = "eth"; + drive-strength = <8>; + }; + + conf-mdio { + pins = "MDC"; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-palmas.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-palmas.txt new file mode 100644 index 0000000000000000000000000000000000000000..c28d4eb83b7687fbb630af467c7b49fb5e7e25f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-palmas.txt @@ -0,0 +1,105 @@ +Palmas Pincontrol bindings + +The pins of Palmas device can be set on different option and provides +the configuration for Pull UP/DOWN, open drain etc. + +Required properties: +- compatible: It must be one of following: + - "ti,palmas-pinctrl" for Palma series of the pincontrol. + - "ti,tps65913-pinctrl" for Palma series device TPS65913. + - "ti,tps80036-pinctrl" for Palma series device TPS80036. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Palmas's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +list of pins. This configuration can include the mux function to select on +those pin(s), and various pin configuration parameters, such as pull-up, +open drain. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +Optional properties: +- ti,palmas-enable-dvfs1: Enable DVFS1. Configure pins for DVFS1 mode. + Selection primary or secondary function associated to I2C2_SCL_SCE, + I2C2_SDA_SDO pin/pad for DVFS1 interface +- ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode. + Selection primary or secondary function associated to GPADC_START + and SYSEN2 pin/pad for DVFS2 interface +- ti,palmas-override-powerhold: This is applicable for PMICs for which + GPIO7 is configured in POWERHOLD mode which has higher priority + over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON + bit is turned off. This property enables driver to over ride the + POWERHOLD value to GPIO7 so as to turn off the PMIC in power off + scenarios. So for GPIO7 if ti,palmas-override-powerhold is set + then the GPIO_7 field should never be muxed to anything else. + It should be set to POWERHOLD by default and only in case of + power off scenarios the driver will over ride the mux value. + +This binding uses the following generic properties as defined in +pinctrl-bindings.txt: + +Required: pins +Options: function, bias-disable, bias-pull-up, bias-pull-down, + drive-open-drain. + +Note that many of these properties are only valid for certain specific pins. +See the Palmas device datasheet for complete details regarding which pins +support which functionality. + +Valid values for pin names are: + gpio0, gpio1, gpio2, gpio3, gpio4, gpio5, gpio6, gpio7, gpio8, gpio9, + gpio10, gpio11, gpio12, gpio13, gpio14, gpio15, vac, powergood, + nreswarm, pwrdown, gpadc_start, reset_in, nsleep, enable1, enable2, + int. + +Valid value of function names are: + gpio, led, pwm, regen, sysen, clk32kgaudio, id, vbus_det, chrg_det, + vac, vacok, powergood, usb_psel, msecure, pwrhold, int, nreswarm, + simrsto, simrsti, low_vbat, wireless_chrg1, rcm, pwrdown, gpadc_start, + reset_in, nsleep, enable. + +There are 4 special functions: opt0, opt1, opt2 and opt3. If any of these +functions is selected then directly pins register will be written with 0, 1, 2 +or 3 respectively if it is valid for that pins or list of pins. + +Example: + palmas: tps65913 { + .... + pinctrl { + compatible = "ti,tps65913-pinctrl"; + ti,palmas-enable-dvfs1; + pinctrl-names = "default"; + pinctrl-0 = <&palmas_pins_state>; + + palmas_pins_state: pinmux { + gpio0 { + pins = "gpio0"; + function = "id"; + bias-pull-up; + }; + + vac { + pins = "vac"; + function = "vacok"; + bias-pull-down; + }; + + gpio5 { + pins = "gpio5"; + function = "opt0"; + drive-open-drain = <1>; + }; + }; + }; + .... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-rk805.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-rk805.txt new file mode 100644 index 0000000000000000000000000000000000000000..cbcbd31e3ce850bf9d3cd501027350991bfefaf4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-rk805.txt @@ -0,0 +1,63 @@ +Pincontrol driver for RK805 Power management IC. + +RK805 has 2 pins which can be configured as GPIO output only. + +Please refer file +for details of the common pinctrl bindings used by client devices, +including the meaning of the phrase "pin configuration node". + +Optional Pinmux properties: +-------------------------- +Following properties are required if default setting of pins are required +at boot. +- pinctrl-names: A pinctrl state named per . +- pinctrl[0...n]: Properties to contain the phandle for pinctrl states per + . + +The pin configurations are defined as child of the pinctrl states node. Each +sub-node have following properties: + +Required properties: +------------------ +- #gpio-cells: Should be two. The first cell is the pin number and the + second is the GPIO flags. + +- gpio-controller: Marks the device node as a GPIO controller. + +- pins: List of pins. Valid values of pins properties are: gpio0, gpio1. + +First 2 properties must be added in the RK805 PMIC node, documented in +Documentation/devicetree/bindings/mfd/rk808.txt + +Optional properties: +------------------- +Following are optional properties defined as pinmux DT binding document +. Absence of properties will leave the configuration +on default. + function, + output-low, + output-high. + +Valid values for function properties are: gpio. + +Theres is also not customised properties for any GPIO. + +Example: +-------- +rk805: rk805@18 { + compatible = "rockchip,rk805"; + ... + gpio-controller; + #gpio-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>, <&rk805_default>; + + rk805_default: pinmux { + gpio01 { + pins = "gpio0", "gpio1"; + function = "gpio"; + output-high; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-single.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-single.txt new file mode 100644 index 0000000000000000000000000000000000000000..e705acd3612ccc4c1ec487f79f3f2ed6fb46fc47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-single.txt @@ -0,0 +1,255 @@ +One-register-per-pin type device tree based pinctrl driver + +Required properties: +- compatible : "pinctrl-single" or "pinconf-single". + "pinctrl-single" means that pinconf isn't supported. + "pinconf-single" means that generic pinconf is supported. + +- reg : offset and length of the register set for the mux registers + +- #pinctrl-cells : number of cells in addition to the index, set to 1 + for pinctrl-single,pins and 2 for pinctrl-single,bits + +- pinctrl-single,register-width : pinmux register access width in bits + +- pinctrl-single,function-mask : mask of allowed pinmux function bits + in the pinmux register + +Optional properties: +- pinctrl-single,function-off : function off mode for disabled state if + available and same for all registers; if not specified, disabling of + pin functions is ignored + +- pinctrl-single,bit-per-mux : boolean to indicate that one register controls + more than one pin, for which "pinctrl-single,function-mask" property specifies + position mask of pin. + +- pinctrl-single,drive-strength : array of value that are used to configure + drive strength in the pinmux register. They're value of drive strength + current and drive strength mask. + + /* drive strength current, mask */ + pinctrl-single,power-source = <0x30 0xf0>; + +- pinctrl-single,bias-pullup : array of value that are used to configure the + input bias pullup in the pinmux register. + + /* input, enabled pullup bits, disabled pullup bits, mask */ + pinctrl-single,bias-pullup = <0 1 0 1>; + +- pinctrl-single,bias-pulldown : array of value that are used to configure the + input bias pulldown in the pinmux register. + + /* input, enabled pulldown bits, disabled pulldown bits, mask */ + pinctrl-single,bias-pulldown = <2 2 0 2>; + + * Two bits to control input bias pullup and pulldown: User should use + pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. One bit means + pullup, and the other one bit means pulldown. + * Three bits to control input bias enable, pullup and pulldown. User should + use pinctrl-single,bias-pullup & pinctrl-single,bias-pulldown. Input bias + enable bit should be included in pullup or pulldown bits. + * Although driver could set PIN_CONFIG_BIAS_DISABLE, there's no property as + pinctrl-single,bias-disable. Because pinctrl single driver could implement + it by calling pulldown, pullup disabled. + +- pinctrl-single,input-schmitt : array of value that are used to configure + input schmitt in the pinmux register. In some silicons, there're two input + schmitt value (rising-edge & falling-edge) in the pinmux register. + + /* input schmitt value, mask */ + pinctrl-single,input-schmitt = <0x30 0x70>; + +- pinctrl-single,input-schmitt-enable : array of value that are used to + configure input schmitt enable or disable in the pinmux register. + + /* input, enable bits, disable bits, mask */ + pinctrl-single,input-schmitt-enable = <0x30 0x40 0 0x70>; + +- pinctrl-single,low-power-mode : array of value that are used to configure + low power mode of this pin. For some silicons, the low power mode will + control the output of the pin when the pad including the pin enter low + power mode. + /* low power mode value, mask */ + pinctrl-single,low-power-mode = <0x288 0x388>; + +- pinctrl-single,gpio-range : list of value that are used to configure a GPIO + range. They're value of subnode phandle, pin base in pinctrl device, pin + number in this range, GPIO function value of this GPIO range. + The number of parameters is depend on #pinctrl-single,gpio-range-cells + property. + + /* pin base, nr pins & gpio function */ + pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1>; + +- interrupt-controller : standard interrupt controller binding if using + interrupts for wake-up events for example. In this case pinctrl-single + is set up as a chained interrupt controller and the wake-up interrupts + can be requested by the drivers using request_irq(). + +- #interrupt-cells : standard interrupt binding if using interrupts + +This driver assumes that there is only one register for each pin (unless the +pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as +specified in the pinctrl-bindings.txt document in this directory. + +The pin configuration nodes for pinctrl-single are specified as pinctrl +register offset and value pairs using pinctrl-single,pins. Only the bits +specified in pinctrl-single,function-mask are updated. For example, setting +a pin for a device could be done with: + + pinctrl-single,pins = <0xdc 0x118>; + +Where 0xdc is the offset from the pinctrl register base address for the +device pinctrl register, and 0x118 contains the desired value of the +pinctrl register. See the device example and static board pins example +below for more information. + +In case when one register changes more than one pin's mux the +pinctrl-single,bits need to be used which takes three parameters: + + pinctrl-single,bits = <0xdc 0x18 0xff>; + +Where 0xdc is the offset from the pinctrl register base address for the +device pinctrl register, 0x18 is the desired value, and 0xff is the sub mask to +be used when applying this change to the register. + + +Optional sub-node: In case some pins could be configured as GPIO in the pinmux +register, those pins could be defined as a GPIO range. This sub-node is required +by pinctrl-single,gpio-range property. + +Required properties in sub-node: +- #pinctrl-single,gpio-range-cells : the number of parameters after phandle in + pinctrl-single,gpio-range property. + + range: gpio-range { + #pinctrl-single,gpio-range-cells = <3>; + }; + + +Example: + +/* SoC common file */ + +/* first controller instance for pins in core domain */ +pmx_core: pinmux@4a100040 { + compatible = "pinctrl-single"; + reg = <0x4a100040 0x0196>; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0xffff>; +}; + +/* second controller instance for pins in wkup domain */ +pmx_wkup: pinmux@4a31e040 { + compatible = "pinctrl-single"; + reg = <0x4a31e040 0x0038>; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + pinctrl-single,register-width = <16>; + pinctrl-single,function-mask = <0xffff>; +}; + +control_devconf0: pinmux@48002274 { + compatible = "pinctrl-single"; + reg = <0x48002274 4>; /* Single register */ + #address-cells = <1>; + #size-cells = <0>; + pinctrl-single,bit-per-mux; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <0x5F>; +}; + +/* third controller instance for pins in gpio domain */ +pmx_gpio: pinmux@d401e000 { + compatible = "pinconf-single"; + reg = <0xd401e000 0x0330>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <7>; + + /* sparse GPIO range could be supported */ + pinctrl-single,gpio-range = <&range 0 3 0 &range 3 9 1 + &range 12 1 0 &range 13 29 1 + &range 43 1 0 &range 44 49 1 + &range 94 1 1 &range 96 2 1>; + + range: gpio-range { + #pinctrl-single,gpio-range-cells = <3>; + }; +}; + + +/* board specific .dts file */ + +&pmx_core { + + /* + * map all board specific static pins enabled by the pinctrl driver + * itself during the boot (or just set them up in the bootloader) + */ + pinctrl-names = "default"; + pinctrl-0 = <&board_pins>; + + board_pins: pinmux_board_pins { + pinctrl-single,pins = < + 0x6c 0xf + 0x6e 0xf + 0x70 0xf + 0x72 0xf + >; + }; + + uart0_pins: pinmux_uart0_pins { + pinctrl-single,pins = < + 0x208 0 /* UART0_RXD (IOCFG138) */ + 0x20c 0 /* UART0_TXD (IOCFG139) */ + >; + pinctrl-single,bias-pulldown = <0 2 2>; + pinctrl-single,bias-pullup = <0 1 1>; + }; + + /* map uart2 pins */ + uart2_pins: pinmux_uart2_pins { + pinctrl-single,pins = < + 0xd8 0x118 + 0xda 0 + 0xdc 0x118 + 0xde 0 + >; + }; +}; + +&control_devconf0 { + mcbsp1_pins: pinmux_mcbsp1_pins { + pinctrl-single,bits = < + 0x00 0x18 0x18 /* FSR/CLKR signal from FSX/CLKX pin */ + >; + }; + + mcbsp2_clks_pins: pinmux_mcbsp2_clks_pins { + pinctrl-single,bits = < + 0x00 0x40 0x40 /* McBSP2 CLKS from McBSP_CLKS pin */ + >; + }; + +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-sirf.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8420520e14bf6d48467585c8260455f12da1540 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-sirf.txt @@ -0,0 +1,47 @@ +CSR SiRFprimaII pinmux controller + +Required properties: +- compatible : "sirf,prima2-pinctrl" +- reg : Address range of the pinctrl registers +- interrupts : Interrupts used by every GPIO group +- gpio-controller : Indicates this device is a GPIO controller +- interrupt-controller : Marks the device node as an interrupt controller +Optional properties: +- sirf,pullups : if n-th bit of m-th bank is set, set a pullup on GPIO-n of bank m +- sirf,pulldowns : if n-th bit of m-th bank is set, set a pulldown on GPIO-n of bank m + +Please refer to pinctrl-bindings.txt in this directory for details of the common +pinctrl bindings used by client devices. + +SiRFprimaII's pinmux nodes act as a container for an arbitrary number of subnodes. +Each of these subnodes represents some desired configuration for a group of pins. + +Required subnode-properties: +- sirf,pins : An array of strings. Each string contains the name of a group. +- sirf,function: A string containing the name of the function to mux to the + group. + + Valid values for group and function names can be found from looking at the + group and function arrays in driver files: + drivers/pinctrl/pinctrl-sirf.c + +For example, pinctrl might have subnodes like the following: + uart2_pins_a: uart2@0 { + uart { + sirf,pins = "uart2grp"; + sirf,function = "uart2"; + }; + }; + uart2_noflow_pins_a: uart2@1 { + uart { + sirf,pins = "uart2_nostreamctrlgrp"; + sirf,function = "uart2_nostreamctrl"; + }; + }; + +For a specific board, if it wants to use uart2 without hardware flow control, +it can add the following to its board-specific .dts file. +uart2: uart@b0070000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_noflow_pins_a>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-st.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..48b9be48af18fc2dfeda3866bbd67548e7c626bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-st.txt @@ -0,0 +1,174 @@ +*ST pin controller. + +Each multi-function pin is controlled, driven and routed through the +PIO multiplexing block. Each pin supports GPIO functionality (ALT0) +and multiple alternate functions(ALT1 - ALTx) that directly connect +the pin to different hardware blocks. + +When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and +Pull Up (PU) are driven by the related PIO block. + +ST pinctrl driver controls PIO multiplexing block and also interacts with +gpio driver to configure a pin. + +GPIO bank can have one of the two possible types of interrupt-wirings. + +First type is via irqmux, single interrupt is used by multiple gpio banks. This +reduces number of overall interrupts numbers required. All these banks belong to +a single pincontroller. + _________ + | |----> [gpio-bank (n) ] + | |----> [gpio-bank (n + 1)] + [irqN]-- | irq-mux |----> [gpio-bank (n + 2)] + | |----> [gpio-bank (... )] + |_________|----> [gpio-bank (n + 7)] + +Second type has a dedicated interrupt per gpio bank. + + [irqN]----> [gpio-bank (n)] + + +Pin controller node: +Required properties: +- compatible : should be "st,stih407--pinctrl" +- st,syscfg : Should be a phandle of the syscfg node. +- st,retime-pin-mask : Should be mask to specify which pins can be retimed. + If the property is not present, it is assumed that all the pins in the + bank are capable of retiming. Retiming is mainly used to improve the + IO timing margins of external synchronous interfaces. +- ranges : defines mapping between pin controller node (parent) to gpio-bank + node (children). + +Optional properties: +- interrupts : Interrupt number of the irqmux. If the interrupt is shared + with other gpio banks via irqmux. + a irqline and gpio banks. +- reg : irqmux memory resource. If irqmux is present. +- reg-names : irqmux resource should be named as "irqmux". + +GPIO controller/bank node. +Required properties: +- gpio-controller : Indicates this device is a GPIO controller +- #gpio-cells : Must be two. + - First cell: specifies the pin number inside the controller + - Second cell: specifies whether the pin is logically inverted. + - 0 = active high + - 1 = active low +- st,bank-name : Should be a name string for this bank as specified in + datasheet. + +Optional properties: +- interrupts : Interrupt number for this gpio bank. If there is a dedicated + interrupt wired up for this gpio bank. + +- interrupt-controller : Indicates this device is a interrupt controller. GPIO + bank can be an interrupt controller iff one of the interrupt type either via +irqmux or a dedicated interrupt per bank is specified. + +- #interrupt-cells: the value of this property should be 2. + - First Cell: represents the external gpio interrupt number local to the + gpio interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered +for related macros look in: +include/dt-bindings/interrupt-controller/irq.h + +Example: + pin-controller-sbc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stih407-sbc-pinctrl"; + st,syscfg = <&syscfg_sbc>; + reg = <0x0961f080 0x4>; + reg-names = "irqmux"; + interrupts = ; + interrupt-names = "irqmux"; + ranges = <0 0x09610000 0x6000>; + + pio0: gpio@9610000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x0 0x100>; + st,bank-name = "PIO0"; + }; + ... + pin-functions nodes follow... + }; + + +Contents of function subnode node: +---------------------- +Required properties for pin configuration node: +- st,pins : Child node with list of pins with configuration. + +Below is the format of how each pin conf should look like. + + + +Every PIO is represented with 4-7 parameters depending on retime configuration. +Each parameter is explained as below. + +-bank : Should be bank phandle to which this PIO belongs. +-offset : Offset in the PIO bank. +-mux : Should be alternate function number associated this pin. + Use same numbers from datasheet. +-mode :pin configuration is selected from one of the below values. + IN + IN_PU + OUT + BIDIR + BIDIR_PU + +-rt_type Retiming Configuration for the pin. + Possible retime configuration are: + + ------- ------------- + value args + ------- ------------- + NICLK + ICLK_IO + BYPASS + DE_IO + SE_ICLK_IO + SE_NICLK_IO + +- delay is retime delay in pico seconds as mentioned in data sheet. + +- rt_clk :clk to be use for retime. + Possible values are: + CLK_A + CLK_B + CLK_C + CLK_D + +Example of mmcclk pin which is a bi-direction pull pu with retime config +as non inverted clock retimed with CLK_B and delay of 0 pico seconds: + +pin-controller { + ... + mmc0 { + pinctrl_mmc: mmc { + st,pins { + mmcclk = <&PIO13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>; + ... + }; + }; + ... + }; +}; + +sdhci0:sdhci@fe810000{ + ... + interrupt-parent = <&pio3>; + #interrupt-cells = <2>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; /* Interrupt line via PIO3-3 */ + interrupt-names = "card-detect"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-sx150x.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-sx150x.txt new file mode 100644 index 0000000000000000000000000000000000000000..4023bad2fe39acc72ac1cb48bd332f3c31cdcd18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-sx150x.txt @@ -0,0 +1,72 @@ +SEMTECH SX150x GPIO expander bindings + +Please refer to pinctrl-bindings.txt, ../gpio/gpio.txt, and +../interrupt-controller/interrupts.txt for generic information regarding +pin controller, GPIO, and interrupt bindings. + +Required properties: +- compatible: should be one of : + "semtech,sx1501q", + "semtech,sx1502q", + "semtech,sx1503q", + "semtech,sx1504q", + "semtech,sx1505q", + "semtech,sx1506q", + "semtech,sx1507q", + "semtech,sx1508q", + "semtech,sx1509q". + +- reg: The I2C slave address for this device. + +- #gpio-cells: Should be 2. The first cell is the GPIO number and the + second cell is used to specify optional parameters: + bit 0: polarity (0: normal, 1: inverted) + +- gpio-controller: Marks the device as a GPIO controller. + +Optional properties : +- interrupts: Interrupt specifier for the controllers interrupt. + +- interrupt-controller: Marks the device as a interrupt controller. + +- semtech,probe-reset: Will trigger a reset of the GPIO expander on probe, + only for sx1507q, sx1508q and sx1509q + +The GPIO expander can optionally be used as an interrupt controller, in +which case it uses the default two cell specifier. + +Required properties for pin configuration sub-nodes: + - pins: List of pins to which the configuration applies. + +Optional properties for pin configuration sub-nodes: +---------------------------------------------------- + - bias-disable: disable any pin bias, except the OSCIO pin + - bias-pull-up: pull up the pin, except the OSCIO pin + - bias-pull-down: pull down the pin, except the OSCIO pin + - bias-pull-pin-default: use pin-default pull state, except the OSCIO pin + - drive-push-pull: drive actively high and low + - drive-open-drain: drive with open drain only for sx1507q, sx1508q and sx1509q and except the OSCIO pin + - output-low: set the pin to output mode with low level + - output-high: set the pin to output mode with high level + +Example: + + i2c0gpio-expander@20{ + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "semtech,sx1506q"; + reg = <0x20>; + interrupt-parent = <&gpio_1>; + interrupts = <16 0>; + + gpio-controller; + interrupt-controller; + + pinctrl-names = "default"; + pinctrl-0 = <&gpio1_cfg_pins>; + + gpio1_cfg_pins: gpio1-cfg { + pins = "gpio1"; + bias-pull-up; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-vt8500.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-vt8500.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3aa90f0ce448dbd0a024a7faf5aa33aa6dad31a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-vt8500.txt @@ -0,0 +1,57 @@ +VIA VT8500 and Wondermedia WM8xxx-series pinmux/gpio controller + +These SoCs contain a combined Pinmux/GPIO module. Each pin may operate as +either a GPIO in, GPIO out or as an alternate function (I2C, SPI etc). + +Required properties: +- compatible: "via,vt8500-pinctrl", "wm,wm8505-pinctrl", "wm,wm8650-pinctrl", + "wm8750-pinctrl" or "wm,wm8850-pinctrl" +- reg: Should contain the physical address of the module's registers. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters. + bit 0 - active low + +Please refer to ../gpio/gpio.txt for a general description of GPIO bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Each pin configuration node lists the pin(s) to which it applies, and one or +more of the mux functions to select on those pin(s), and pull-up/down +configuration. Each subnode only affects those parameters that are explicitly +listed. In other words, a subnode that lists only a mux function implies no +information about any pull configuration. Similarly, a subnode that lists only +a pull parameter implies no information about the mux function. + +Required subnode-properties: +- wm,pins: An array of cells. Each cell contains the ID of a pin. + +Optional subnode-properties: +- wm,function: Integer, containing the function to mux to the pin(s): + 0: GPIO in + 1: GPIO out + 2: alternate + +- wm,pull: Integer, representing the pull-down/up to apply to the pin(s): + 0: none + 1: down + 2: up + +Each of wm,function and wm,pull may contain either a single value which +will be applied to all pins in wm,pins, or one value for each entry in +wm,pins. + +Example: + + pinctrl: pinctrl { + compatible = "wm,wm8505-pinctrl"; + reg = <0xD8110000 0x10000>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-zx.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-zx.txt new file mode 100644 index 0000000000000000000000000000000000000000..39170f372599b2a95f5ce23db7a33967387f8ea7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl-zx.txt @@ -0,0 +1,84 @@ +* ZTE ZX Pin Controller + +The pin controller on ZTE ZX platforms is kinda of hybrid. It consists of +a main controller and an auxiliary one. For example, on ZX296718 SoC, the +main controller is TOP_PMM and the auxiliary one is AON_IOCFG. Both +controllers work together to control pin multiplexing and configuration in +the way illustrated as below. + + + GMII_RXD3 ---+ + | + DVI1_HS ---+----------------------------- GMII_RXD3 (TOP pin) + | + BGPIO16 ---+ ^ + | pinconf + ^ | + | pinmux | + | | + + TOP_PMM (main) AON_IOCFG (aux) + + | | | + | pinmux | | + | pinmux v | + v | pinconf + KEY_ROW2 ---+ v + PORT1_LCD_TE ---+ | + | AGPIO10 ---+------ KEY_ROW2 (AON pin) + I2S0_DOUT3 ---+ | + |-----------------------+ + PWM_OUT3 ---+ + | + VGA_VS1 ---+ + + +For most of pins like GMII_RXD3 in the figure, the pinmux function is +controlled by TOP_PMM block only, and this type of pins are meant by term +'TOP pins'. For pins like KEY_ROW2, the pinmux is controlled by both +TOP_PMM and AON_IOCFG blocks, as the available multiplexing functions for +the pin spread in both controllers. This type of pins are called 'AON pins'. +Though pinmux implementation is quite different, pinconf is same for both +types of pins. Both are controlled by auxiliary controller, i.e. AON_IOCFG +on ZX296718. + +Required properties: +- compatible: should be "zte,zx296718-pmm". +- reg: the register physical address and length. +- zte,auxiliary-controller: phandle to the auxiliary pin controller which + implements pinmux for AON pins and pinconf for all pins. + +The following pin configuration are supported. Please refer to +pinctrl-bindings.txt in this directory for more details of the common +pinctrl bindings used by client devices. + +- bias-pull-up +- bias-pull-down +- drive-strength +- input-enable +- slew-rate + +Examples: + +iocfg: pin-controller@119000 { + compatible = "zte,zx296718-iocfg"; + reg = <0x119000 0x1000>; +}; + +pmm: pin-controller@1462000 { + compatible = "zte,zx296718-pmm"; + reg = <0x1462000 0x1000>; + zte,auxiliary-controller = <&iocfg>; +}; + +&pmm { + vga_pins: vga { + pins = "KEY_COL1", "KEY_COL2", "KEY_ROW1", "KEY_ROW2"; + function = "VGA"; + }; +}; + +&vga { + pinctrl-names = "default"; + pinctrl-0 = <&vga_pins>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl_spear.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl_spear.txt new file mode 100644 index 0000000000000000000000000000000000000000..458615596946f6d29ccd60401f87a419fbe0e84a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/pinctrl_spear.txt @@ -0,0 +1,155 @@ +ST Microelectronics, SPEAr pinmux controller + +Required properties: +- compatible : "st,spear300-pinmux" + : "st,spear310-pinmux" + : "st,spear320-pinmux" + : "st,spear1310-pinmux" + : "st,spear1340-pinmux" +- reg : Address range of the pinctrl registers +- st,pinmux-mode: Mandatory for SPEAr300 and SPEAr320 and invalid for others. + - Its values for SPEAr300: + - NAND_MODE : <0> + - NOR_MODE : <1> + - PHOTO_FRAME_MODE : <2> + - LEND_IP_PHONE_MODE : <3> + - HEND_IP_PHONE_MODE : <4> + - LEND_WIFI_PHONE_MODE : <5> + - HEND_WIFI_PHONE_MODE : <6> + - ATA_PABX_WI2S_MODE : <7> + - ATA_PABX_I2S_MODE : <8> + - CAML_LCDW_MODE : <9> + - CAMU_LCD_MODE : <10> + - CAMU_WLCD_MODE : <11> + - CAML_LCD_MODE : <12> + - Its values for SPEAr320: + - AUTO_NET_SMII_MODE : <0> + - AUTO_NET_MII_MODE : <1> + - AUTO_EXP_MODE : <2> + - SMALL_PRINTERS_MODE : <3> + - EXTENDED_MODE : <4> + +Please refer to pinctrl-bindings.txt in this directory for details of the common +pinctrl bindings used by client devices. + +SPEAr's pinmux nodes act as a container for an arbitrary number of subnodes. Each +of these subnodes represents muxing for a pin, a group, or a list of pins or +groups. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Required subnode-properties: +- st,pins : An array of strings. Each string contains the name of a pin or + group. +- st,function: A string containing the name of the function to mux to the pin or + group. See the SPEAr's TRM to determine which are valid for each pin or group. + + Valid values for group and function names can be found from looking at the + group and function arrays in driver files: + drivers/pinctrl/spear/pinctrl-spear3*0.c + +Valid values for group names are: +For All SPEAr3xx machines: + "firda_grp", "i2c0_grp", "ssp_cs_grp", "ssp0_grp", "mii0_grp", + "gpio0_pin0_grp", "gpio0_pin1_grp", "gpio0_pin2_grp", "gpio0_pin3_grp", + "gpio0_pin4_grp", "gpio0_pin5_grp", "uart0_ext_grp", "uart0_grp", + "timer_0_1_grp", timer_0_1_pins, "timer_2_3_grp" + +For SPEAr300 machines: + "fsmc_2chips_grp", "fsmc_4chips_grp", "clcd_lcdmode_grp", + "clcd_pfmode_grp", "tdm_grp", "i2c_clk_grp_grp", "caml_grp", "camu_grp", + "dac_grp", "i2s_grp", "sdhci_4bit_grp", "sdhci_8bit_grp", + "gpio1_0_to_3_grp", "gpio1_4_to_7_grp" + +For SPEAr310 machines: + "emi_cs_0_to_5_grp", "uart1_grp", "uart2_grp", "uart3_grp", "uart4_grp", + "uart5_grp", "fsmc_grp", "rs485_0_grp", "rs485_1_grp", "tdm_grp" + +For SPEAr320 machines: + "clcd_grp", "emi_grp", "fsmc_8bit_grp", "fsmc_16bit_grp", "spp_grp", + "sdhci_led_grp", "sdhci_cd_12_grp", "sdhci_cd_51_grp", "i2s_grp", + "uart1_grp", "uart1_modem_2_to_7_grp", "uart1_modem_31_to_36_grp", + "uart1_modem_34_to_45_grp", "uart1_modem_80_to_85_grp", "uart2_grp", + "uart3_8_9_grp", "uart3_15_16_grp", "uart3_41_42_grp", + "uart3_52_53_grp", "uart3_73_74_grp", "uart3_94_95_grp", + "uart3_98_99_grp", "uart4_6_7_grp", "uart4_13_14_grp", + "uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp", + "uart4_100_101_grp", "uart5_4_5_grp", "uart5_37_38_grp", + "uart5_69_70_grp", "uart5_90_91_grp", "uart6_2_3_grp", + "uart6_88_89_grp", "rs485_grp", "touchscreen_grp", "can0_grp", + "can1_grp", "pwm0_1_pin_8_9_grp", "pwm0_1_pin_14_15_grp", + "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp", "pwm0_1_pin_42_43_grp", + "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp", "pwm2_pin_7_grp", + "pwm2_pin_13_grp", "pwm2_pin_29_grp", "pwm2_pin_34_grp", + "pwm2_pin_41_grp", "pwm2_pin_58_grp", "pwm2_pin_87_grp", + "pwm3_pin_6_grp", "pwm3_pin_12_grp", "pwm3_pin_28_grp", + "pwm3_pin_40_grp", "pwm3_pin_57_grp", "pwm3_pin_86_grp", + "ssp1_17_20_grp", "ssp1_36_39_grp", "ssp1_48_51_grp", "ssp1_65_68_grp", + "ssp1_94_97_grp", "ssp2_13_16_grp", "ssp2_32_35_grp", "ssp2_44_47_grp", + "ssp2_61_64_grp", "ssp2_90_93_grp", "mii2_grp", "smii0_1_grp", + "rmii0_1_grp", "i2c1_8_9_grp", "i2c1_98_99_grp", "i2c2_0_1_grp", + "i2c2_2_3_grp", "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp" + +For SPEAr1310 machines: + "i2c0_grp", "ssp0_grp", "ssp0_cs0_grp", "ssp0_cs1_2_grp", "i2s0_grp", + "i2s1_grp", "clcd_grp", "clcd_high_res_grp", "arm_gpio_grp", + "smi_2_chips_grp", "smi_4_chips_grp", "gmii_grp", "rgmii_grp", + "smii_0_1_2_grp", "ras_mii_txclk_grp", "nand_8bit_grp", + "nand_16bit_grp", "nand_4_chips_grp", "keyboard_6x6_grp", + "keyboard_rowcol6_8_grp", "uart0_grp", "uart0_modem_grp", + "gpt0_tmr0_grp", "gpt0_tmr1_grp", "gpt1_tmr0_grp", "gpt1_tmr1_grp", + "sdhci_grp", "cf_grp", "xd_grp", "touch_xy_grp", + "uart1_disable_i2c_grp", "uart1_disable_sd_grp", "uart2_3_grp", + "uart4_grp", "uart5_grp", "rs485_0_1_tdm_0_1_grp", "i2c_1_2_grp", + "i2c3_dis_smi_clcd_grp", "i2c3_dis_sd_i2s0_grp", "i2c_4_5_dis_smi_grp", + "i2c4_dis_sd_grp", "i2c5_dis_sd_grp", "i2c_6_7_dis_kbd_grp", + "i2c6_dis_sd_grp", "i2c7_dis_sd_grp", "can0_dis_nor_grp", + "can0_dis_sd_grp", "can1_dis_sd_grp", "can1_dis_kbd_grp", "pcie0_grp", + "pcie1_grp", "pcie2_grp", "sata0_grp", "sata1_grp", "sata2_grp", + "ssp1_dis_kbd_grp", "ssp1_dis_sd_grp", "gpt64_grp" + +For SPEAr1340 machines: + "pads_as_gpio_grp", "fsmc_8bit_grp", "fsmc_16bit_grp", "fsmc_pnor_grp", + "keyboard_row_col_grp", "keyboard_col5_grp", "spdif_in_grp", + "spdif_out_grp", "gpt_0_1_grp", "pwm0_grp", "pwm1_grp", "pwm2_grp", + "pwm3_grp", "vip_mux_grp", "vip_mux_cam0_grp", "vip_mux_cam1_grp", + "vip_mux_cam2_grp", "vip_mux_cam3_grp", "cam0_grp", "cam1_grp", + "cam2_grp", "cam3_grp", "smi_grp", "ssp0_grp", "ssp0_cs1_grp", + "ssp0_cs2_grp", "ssp0_cs3_grp", "uart0_grp", "uart0_enh_grp", + "uart1_grp", "i2s_in_grp", "i2s_out_grp", "gmii_grp", "rgmii_grp", + "rmii_grp", "sgmii_grp", "i2c0_grp", "i2c1_grp", "cec0_grp", "cec1_grp", + "sdhci_grp", "cf_grp", "xd_grp", "clcd_grp", "arm_trace_grp", + "miphy_dbg_grp", "pcie_grp", "sata_grp" + +Valid values for function names are: +For All SPEAr3xx machines: + "firda", "i2c0", "ssp_cs", "ssp0", "mii0", "gpio0", "uart0_ext", + "uart0", "timer_0_1", "timer_2_3" + +For SPEAr300 machines: + "fsmc", "clcd", "tdm", "i2c1", "cam", "dac", "i2s", "sdhci", "gpio1" + +For SPEAr310 machines: + "emi", "uart1", "uart2", "uart3", "uart4", "uart5", "fsmc", "rs485_0", + "rs485_1", "tdm" + +For SPEAr320 machines: + "clcd", "emi", "fsmc", "spp", "sdhci", "i2s", "uart1", "uart1_modem", + "uart2", "uart3", "uart4", "uart5", "uart6", "rs485", "touchscreen", + "can0", "can1", "pwm0_1", "pwm2", "pwm3", "ssp1", "ssp2", "mii2", + "mii0_1", "i2c1", "i2c2" + + +For SPEAr1310 machines: + "i2c0", "ssp0", "i2s0", "i2s1", "clcd", "arm_gpio", "smi", "gmii", + "rgmii", "smii_0_1_2", "ras_mii_txclk", "nand", "keyboard", "uart0", + "gpt0", "gpt1", "sdhci", "cf", "xd", "touchscreen", "uart1", "uart2_3", + "uart4", "uart5", "rs485_0_1_tdm_0_1", "i2c_1_2", "i2c3_i2s1", + "i2c_4_5", "i2c_6_7", "can0", "can1", "pci", "sata", "ssp1", "gpt64" + +For SPEAr1340 machines: + "pads_as_gpio", "fsmc", "keyboard", "spdif_in", "spdif_out", "gpt_0_1", + "pwm", "vip", "cam0", "cam1", "cam2", "cam3", "smi", "ssp0", "uart0", + "uart1", "i2s", "gmac", "i2c0", "i2c1", "cec0", "cec1", "sdhci", "cf", + "xd", "clcd", "arm_trace", "miphy_dbg", "pcie", "sata" diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,apq8064-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,apq8064-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2dbb3e8d84035f91a79e963ec96420afdcbfc87 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,apq8064-pinctrl.txt @@ -0,0 +1,95 @@ +Qualcomm APQ8064 TLMM block + +Required properties: +- compatible: "qcom,apq8064-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. +- gpio-ranges: see ../gpio/gpio.txt + +Optional properties: + +- gpio-reserved-ranges: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength, + output-low, output-high. + +Non-empty subnodes must specify the 'pins' property. + +Valid values for pins are: + gpio0-gpio89 + +Valid values for function are: + cam_mclk, codec_mic_i2s, codec_spkr_i2s, gp_clk_0a, gp_clk_0b, gp_clk_1a, + gp_clk_1b, gp_clk_2a, gp_clk_2b, gpio, gsbi1, gsbi2, gsbi3, gsbi4, + gsbi4_cam_i2c, gsbi5, gsbi5_spi_cs1, gsbi5_spi_cs2, gsbi5_spi_cs3, gsbi6, + gsbi6_spi_cs1, gsbi6_spi_cs2, gsbi6_spi_cs3, gsbi7, gsbi7_spi_cs1, + gsbi7_spi_cs2, gsbi7_spi_cs3, gsbi_cam_i2c, hdmi, mi2s, riva_bt, riva_fm, + riva_wlan, sdc2, sdc4, slimbus, spkr_i2s, tsif1, tsif2, usb2_hsic, ps_hold + +Example: + + msmgpio: pinctrl@800000 { + compatible = "qcom,apq8064-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0x4>; + + pinctrl-names = "default"; + pinctrl-0 = <&gsbi5_uart_default>; + gpio-ranges = <&msmgpio 0 0 90>; + + gsbi5_uart_default: gsbi5_uart_default { + mux { + pins = "gpio51", "gpio52"; + function = "gsbi5"; + }; + + tx { + pins = "gpio51"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio52"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,apq8084-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,apq8084-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..68e93d5b7ede1cd8874e8c24b29289b4f8deb7bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,apq8084-pinctrl.txt @@ -0,0 +1,188 @@ +Qualcomm APQ8084 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8960 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,apq8084-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio146, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc2_clk, + sdc2_cmd, + sdc2_data + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + adsp_ext, audio_ref, blsp_i2c1, blsp_i2c2, blsp_i2c3, + blsp_i2c4, blsp_i2c5, blsp_i2c6, blsp_i2c7, blsp_i2c8, + blsp_i2c9, blsp_i2c10, blsp_i2c11, blsp_i2c12, + blsp_spi1, blsp_spi2, blsp_spi3, blsp_spi4, blsp_spi5, + blsp_spi6, blsp_spi7, blsp_spi8, blsp_spi9, blsp_spi10, + blsp_spi11, blsp_spi12, blsp_uart1, blsp_uart2, blsp_uart3, + blsp_uart4, blsp_uart5, blsp_uart6, blsp_uart7, blsp_uart8, + blsp_uart9, blsp_uart10, blsp_uart11, blsp_uart12, + blsp_uim1, blsp_uim2, blsp_uim3, blsp_uim4, blsp_uim5, + blsp_uim6, blsp_uim7, blsp_uim8, blsp_uim9, blsp_uim10, + blsp_uim11, blsp_uim12, cam_mclk0, cam_mclk1, cam_mclk2, + cam_mclk3, cci_async, cci_async_in0, cci_i2c0, cci_i2c1, + cci_timer0, cci_timer1, cci_timer2, cci_timer3, cci_timer4, + edp_hpd, gcc_gp1, gcc_gp2, gcc_gp3, gcc_obt, gcc_vtt,i + gp_mn, gp_pdm0, gp_pdm1, gp_pdm2, gp0_clk, gp1_clk, gpio, + hdmi_cec, hdmi_ddc, hdmi_dtest, hdmi_hpd, hdmi_rcv, hsic, + ldo_en, ldo_update, mdp_vsync, pci_e0, pci_e0_n, pci_e0_rst, + pci_e1, pci_e1_rst, pci_e1_rst_n, pci_e1_clkreq_n, pri_mi2s, + qua_mi2s, sata_act, sata_devsleep, sata_devsleep_n, + sd_write, sdc_emmc_mode, sdc3, sdc4, sec_mi2s, slimbus, + spdif_tx, spkr_i2s, spkr_i2s_ws, spss_geni, ter_mi2s, tsif1, + tsif2, uim, uim_batt_alarm + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@fd510000 { + compatible = "qcom,apq8084-pinctrl"; + reg = <0xfd510000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 147>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 208 0>; + + uart2: uart2-default { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + tx { + pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,bengal-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,bengal-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb627041b268828d54af1f99dc4f0cc74a19630a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,bengal-pinctrl.txt @@ -0,0 +1,187 @@ +Qualcomm Technologies, Inc. BENGAL TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +BENGAL platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,bengal-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio112 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@400000 { + compatible = "qcom,bengal-pinctrl"; + reg = <0x400000 0xc00000>; + interrupts = <0 227 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq4019-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq4019-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..991be0cd094873e7bfcb292e89669d4dc51717e1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq4019-pinctrl.txt @@ -0,0 +1,84 @@ +Qualcomm Atheros IPQ4019 TLMM block + +This is the Top Level Mode Multiplexor block found on the Qualcomm IPQ8019 +platform, it provides pinctrl, pinmux, pinconf, and gpiolib facilities. + +Required properties: +- compatible: "qcom,ipq4019-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. +- gpio-ranges: see ../gpio/gpio.txt + +Optional properties: + +- gpio-reserved-ranges: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an abitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength. + +Non-empty subnodes must specify the 'pins' property. +Note that not all properties are valid for all pins. + + +Valid values for qcom,pins are: + gpio0-gpio99 + Supports mux, bias and drive-strength + +Valid values for qcom,function are: +aud_pin, audio_pwm, blsp_i2c0, blsp_i2c1, blsp_spi0, blsp_spi1, blsp_uart0, +blsp_uart1, chip_rst, gpio, i2s_rx, i2s_spdif_in, i2s_spdif_out, i2s_td, i2s_tx, +jtag, led0, led1, led2, led3, led4, led5, led6, led7, led8, led9, led10, led11, +mdc, mdio, pcie, pmu, prng_rosc, qpic, rgmii, rmii, sdio, smart0, smart1, +smart2, smart3, tm, wifi0, wifi1 + +Example: + + tlmm: pinctrl@1000000 { + compatible = "qcom,ipq4019-pinctrl"; + reg = <0x1000000 0x300000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 100>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 208 0>; + + serial_pins: serial_pinmux { + mux { + pins = "gpio60", "gpio61"; + function = "blsp_uart0"; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq8064-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq8064-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ed56a1b70fc179e28cc4099565fcf247312b868 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq8064-pinctrl.txt @@ -0,0 +1,101 @@ +Qualcomm IPQ8064 TLMM block + +Required properties: +- compatible: "qcom,ipq8064-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. +- gpio-ranges: see ../gpio/gpio.txt + +Optional properties: + +- gpio-reserved-ranges: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength, + output-low, output-high. + +Non-empty subnodes must specify the 'pins' property. + +Valid values for qcom,pins are: + gpio0-gpio68 + Supports mux, bias, and drive-strength + + sdc3_clk, sdc3_cmd, sdc3_data + Supports bias and drive-strength + + +Valid values for function are: + mdio, mi2s, pdm, ssbi, spmi, audio_pcm, gpio, gsbi1, gsbi2, gsbi4, gsbi5, + gsbi5_spi_cs1, gsbi5_spi_cs2, gsbi5_spi_cs3, gsbi6, gsbi7, nss_spi, sdc1, + spdif, nand, tsif1, tsif2, usb_fs_n, usb_fs, usb2_hsic, rgmii2, sata, + pcie1_rst, pcie1_prsnt, pcie1_pwren_n, pcie1_pwren, pcie1_pwrflt, + pcie1_clk_req, pcie2_rst, pcie2_prsnt, pcie2_pwren_n, pcie2_pwren, + pcie2_pwrflt, pcie2_clk_req, pcie3_rst, pcie3_prsnt, pcie3_pwren_n, + pcie3_pwren, pcie3_pwrflt, pcie3_clk_req, ps_hold + +Example: + + pinmux: pinctrl@800000 { + compatible = "qcom,ipq8064-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinmux 0 0 69>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 32 0x4>; + + pinctrl-names = "default"; + pinctrl-0 = <&gsbi5_uart_default>; + + gsbi5_uart_default: gsbi5_uart_default { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + }; + + tx { + pins = "gpio18"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq8074-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq8074-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..6dd72f8599e91dd89913098ea8ee94808389025a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,ipq8074-pinctrl.txt @@ -0,0 +1,181 @@ +Qualcomm Technologies, Inc. IPQ8074 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +IPQ8074 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,ipq8074-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio69 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + atest_char, atest_char0, atest_char1, atest_char2, + atest_char3, audio_rxbclk, audio_rxd, audio_rxfsync, + audio_rxmclk, audio_txbclk, audio_txd, audio_txfsync, + audio_txmclk, blsp0_i2c, blsp0_spi, blsp0_uart, blsp1_i2c, + blsp1_spi, blsp1_uart, blsp2_i2c, blsp2_spi, blsp2_uart, + blsp3_i2c, blsp3_spi, blsp3_spi0, blsp3_spi1, blsp3_spi2, + blsp3_spi3, blsp3_uart, blsp4_i2c0, blsp4_i2c1, blsp4_spi0, + blsp4_spi1, blsp4_uart0, blsp4_uart1, blsp5_i2c, blsp5_spi, + blsp5_uart, burn0, burn1, cri_trng, cri_trng0, cri_trng1, + cxc0, cxc1, dbg_out, gcc_plltest, gcc_tlmm, gpio, ldo_en, + ldo_update, led0, led1, led2, mac0_sa0, mac0_sa1, mac1_sa0, + mac1_sa1, mac1_sa2, mac1_sa3, mac2_sa0, mac2_sa1, mdc, + mdio, pcie0_clk, pcie0_rst, pcie0_wake, pcie1_clk, + pcie1_rst, pcie1_wake, pcm_drx, pcm_dtx, pcm_fsync, + pcm_pclk, pcm_zsi0, pcm_zsi1, prng_rosc, pta1_0, pta1_1, + pta1_2, pta2_0, pta2_1, pta2_2, pwm0, pwm1, pwm2, pwm3, + qdss_cti_trig_in_a0, qdss_cti_trig_in_a1, + qdss_cti_trig_in_b0, qdss_cti_trig_in_b1, + qdss_cti_trig_out_a0, qdss_cti_trig_out_a1, + qdss_cti_trig_out_b0, qdss_cti_trig_out_b1, + qdss_traceclk_a, qdss_traceclk_b, qdss_tracectl_a, + qdss_tracectl_b, qdss_tracedata_a, qdss_tracedata_b, + qpic, rx0, rx1, rx2, sd_card, sd_write, tsens_max, wci2a, + wci2b, wci2c, wci2d + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@1000000 { + compatible = "qcom,ipq8074-pinctrl"; + reg = <0x1000000 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 70>; + interrupt-controller; + #interrupt-cells = <2>; + + uart2: uart2-default { + mux { + pins = "gpio23", "gpio24"; + function = "blsp4_uart1"; + }; + + rx { + pins = "gpio23"; + drive-strength = <4>; + bias-disable; + }; + + tx { + pins = "gpio24"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,kona-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,kona-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..78d6e0d4329790a9c1b5e9f06d5f1a70d51b0eb2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,kona-pinctrl.txt @@ -0,0 +1,192 @@ +Qualcomm Technologies, Inc. KONA TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +KONA platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,kona-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- wakeup-parent: + Usage: optional + Value type: + Definition: A phandle to the wakeup interrupt controller for the SoC. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio149 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@03000000 { + compatible = "qcom,kona-pinctrl"; + reg = <0x03000000 0xdc2000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lagoon-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lagoon-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..444e54a13978ad76c833b5dffc23d2ed8906e256 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lagoon-pinctrl.txt @@ -0,0 +1,187 @@ +Qualcomm Technologies, Inc. LAGOON TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +LAGOON platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,lagoon-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + This can be followed by optional direct connect IRQs. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio155 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@f000000 { + compatible = "qcom,lagoon-pinctrl"; + reg = <0x0f000000 0x1000000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lito-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lito-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7acea3208278043b05c5d8d9bb733d104ff62b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lito-pinctrl.txt @@ -0,0 +1,192 @@ +Qualcomm Technologies, Inc. LITO TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +LITO platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,lito-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- wakeup-parent: + Usage: optional + Value type: + Definition: A phandle to the wakeup interrupt controller for the SoC. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio145 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@f000000 { + compatible = "qcom,lito-pinctrl"; + reg = <0x0f000000 0x1000000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lpi-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lpi-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd60bfb22be878990d899cad3734894ab4598a72 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,lpi-pinctrl.txt @@ -0,0 +1,203 @@ +Qualcomm Technologies, Inc. LPI GPIO controller driver + +This DT bindings describes the GPIO controller driver +being added for supporting LPI (Low Power Island) TLMM +from QTI chipsets. + +Following properties are for LPI GPIO controller device main node. +- compatible: + Usage: required + Value type: + Definition: must be "qcom,lpi-pinctrl" + +- reg: + Usage: required + Value type: + Definition: Register base of the GPIO controller and length. + +- qcom,num-gpios: + Usage: required + Value type: + Definition: Number of GPIOs supported by the controller. + +- qcom,lpi-offset-tbl + Usage: required + Value type: + Definition: Offset table of GPIOs supported by the controller. + +- gpio-controller: + Usage: required + Value type: + Definition: Used to mark the device node as a GPIO controller. + +- #gpio-cells: + Usage: required + Value type: + Definition: Must be 2; + The first cell will be used to define gpio number and the + second denotes the flags for this gpio. + +- #qcom,slew-reg: + Usage: optional + Value type: + Definition: Register base of the slew register and length. + +- #qcom,lpi-slew-offset-tbl: + Usage: optional + Value type: + Definition: Offset table that points to each pin's shift value + position in bits in the slew register base for slew + settings. + +- #qcom,lpi-slew-base-tbl: + Usage: optional + Value type: + Definition: Table points to physical address for corresponding + slew registers. + +Please refer to ../gpio/gpio.txt for general description of GPIO bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin or a list of pins. This configuration can include the +mux function to select on those pin(s), and various pin configuration +parameters, as listed below. + +SUBNODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: gpio0-gpio31 for LPI. + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Valid values are: + "gpio", + "func1", + "func2", + "func3", + "func4", + "func5" + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configured as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull down. + +- bias-bus-hold: + Usage: optional + Value type: + Definition: The specified pins should be configured as bus-keeper mode. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull up. + +- input-enable: + Usage: optional + Value type: + Definition: The specified pins are put in input mode. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- qcom,drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins. + +- slew-rate: + Usage: optional + Value type: + Definition: Selects the slew rate for the specified pins. + +Example: + + lpi_tlmm: lpi_pinctrl@152c000 { + compatible = "qcom,lpi-pinctrl"; + qcom,num-gpios = <32>; + reg = <0x152c000 0>; + qcom,slew-reg = <0x355a000 0x0>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = <0x00000010>, <0x00000020>, + <0x00000030>, <0x00000040>, + <0x00000050>, <0x00000060>, + <0x00000070>, <0x00000080>, + <0x00000090>, <0x00000100>, + <0x00000110>, <0x00000120>, + <0x00000130>, <0x00000140>, + <0x00000150>, <0x00000160>, + <0x00000170>, <0x00000180>, + <0x00000190>, <0x00000200>, + <0x00000210>; + qcom,lpi-slew-offset-tbl = <0x00000000>, <0x00000002>, + <0x00000004>, <0x00000008>, + <0x0000000A>, <0x0000000C>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000010>, <0x00000012>, + <0x00000000>, <0x00000000>; + + hph_comp_active: hph_comp_active { + mux { + pins = "gpio22"; + function = "func1"; + }; + + config { + pins = "gpio22"; + output-high; + qcom,drive-strength = <8>; + }; + }; + + hph_comp_sleep: hph_comp_sleep { + mux { + pins = "gpio22"; + function = "func1"; + }; + + config { + pins = "gpio22"; + qcom,drive-strength = <2>; + slew-rate = <1>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,mdm9615-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,mdm9615-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..86ecdcfc4fb8a1fe70617186de1208ccb7bf9a2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,mdm9615-pinctrl.txt @@ -0,0 +1,161 @@ +Qualcomm MDM9615 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MDM9615 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,mdm9615-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio87 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. + Valid values are: + gpio, gsbi2_i2c, gsbi3, gsbi4, gsbi5_i2c, gsbi5_uart, + sdc2, ebi2_lcdc, ps_hold, prim_audio, sec_audio, + cdc_mclk + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + msmgpio: pinctrl@800000 { + compatible = "qcom,mdm9615-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&msmgpio 0 0 88>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0x4>; + + gsbi8_uart: gsbi8-uart { + mux { + pins = "gpio34", "gpio35"; + function = "gsbi8"; + }; + + tx { + pins = "gpio34"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8660-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8660-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..cdc4787e59d2eb3c738a3b589a9d26b9264eedbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8660-pinctrl.txt @@ -0,0 +1,96 @@ +Qualcomm MSM8660 TLMM block + +Required properties: +- compatible: "qcom,msm8660-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. +- gpio-ranges: see ../gpio/gpio.txt + +Optional properties: + +- gpio-reserved-ranges: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength, + output-low, output-high. + +Non-empty subnodes must specify the 'pins' property. + +Valid values for pins are: + gpio0-gpio172, sdc3_clk, sdc3_cmd, sdc3_data sdc4_clk, sdc4_cmd, sdc4_data + +Valid values for function are: + gpio, cam_mclk, dsub, ext_gps, gp_clk_0a, gp_clk_0b, gp_clk_1a, gp_clk_1b, + gp_clk_2a, gp_clk_2b, gp_mn, gsbi1, gsbi1_spi_cs1_n, gsbi1_spi_cs2a_n, + gsbi1_spi_cs2b_n, gsbi1_spi_cs3_n, gsbi2, gsbi2_spi_cs1_n, gsbi2_spi_cs2_n, + gsbi2_spi_cs3_n, gsbi3, gsbi3_spi_cs1_n, gsbi3_spi_cs2_n, gsbi3_spi_cs3_n, + gsbi4, gsbi5, gsbi6, gsbi7, gsbi8, gsbi9, gsbi10, gsbi11, gsbi12, hdmi, i2s, + lcdc, mdp_vsync, mi2s, pcm, ps_hold, sdc1, sdc2, sdc5, tsif1, tsif2, usb_fs1, + usb_fs1_oe_n, usb_fs2, usb_fs2_oe_n, vfe, vsens_alarm, ebi2, ebi2cs + +Example: + + msmgpio: pinctrl@800000 { + compatible = "qcom,msm8660-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&msmgpio 0 0 173>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0x4>; + + pinctrl-names = "default"; + pinctrl-0 = <&gsbi12_uart>; + + gsbi12_uart: gsbi12-uart { + mux { + pins = "gpio117", "gpio118"; + function = "gsbi12"; + }; + + tx { + pins = "gpio118"; + drive-strength = <8>; + bias-disable; + }; + + rx { + pins = "gpio117"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8916-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8916-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..195a7a0ef0ccbc842f5a65c4e1d7c57378ee6abf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8916-pinctrl.txt @@ -0,0 +1,195 @@ +Qualcomm MSM8916 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8916 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8916-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio121, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc2_clk, + sdc2_cmd, + sdc2_data, + qdsd_cmd, + qdsd_data0, + qdsd_data1, + qdsd_data2, + qdsd_data3 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + adsp_ext, alsp_int, atest_bbrx0, atest_bbrx1, atest_char, atest_char0, + atest_char1, atest_char2, atest_char3, atest_combodac, atest_gpsadc0, + atest_gpsadc1, atest_tsens, atest_wlan0, atest_wlan1, backlight_en, + bimc_dte0,bimc_dte1, blsp_i2c1, blsp_i2c2, blsp_i2c3, blsp_i2c4, + blsp_i2c5, blsp_i2c6, blsp_spi1, blsp_spi1_cs1, blsp_spi1_cs2, + blsp_spi1_cs3, blsp_spi2, blsp_spi2_cs1, blsp_spi2_cs2, blsp_spi2_cs3, + blsp_spi3, blsp_spi3_cs1, blsp_spi3_cs2, blsp_spi3_cs3, blsp_spi4, + blsp_spi5, blsp_spi6, blsp_uart1, blsp_uart2, blsp_uim1, blsp_uim2, + cam1_rst, cam1_standby, cam_mclk0, cam_mclk1, cci_async, cci_i2c, + cci_timer0, cci_timer1, cci_timer2, cdc_pdm0, codec_mad, dbg_out, + display_5v, dmic0_clk, dmic0_data, dsi_rst, ebi0_wrcdc, euro_us, + ext_lpass, flash_strobe, gcc_gp1_clk_a, gcc_gp1_clk_b, gcc_gp2_clk_a, + gcc_gp2_clk_b, gcc_gp3_clk_a, gcc_gp3_clk_b, gpio, gsm0_tx0, gsm0_tx1, + gsm1_tx0, gsm1_tx1, gyro_accl, kpsns0, kpsns1, kpsns2, ldo_en, + ldo_update, mag_int, mdp_vsync, modem_tsync, m_voc, nav_pps, nav_tsync, + pa_indicator, pbs0, pbs1, pbs2, pri_mi2s, pri_mi2s_ws, prng_rosc, + pwr_crypto_enabled_a, pwr_crypto_enabled_b, pwr_modem_enabled_a, + pwr_modem_enabled_b, pwr_nav_enabled_a, pwr_nav_enabled_b, + qdss_ctitrig_in_a0, qdss_ctitrig_in_a1, qdss_ctitrig_in_b0, + qdss_ctitrig_in_b1, qdss_ctitrig_out_a0, qdss_ctitrig_out_a1, + qdss_ctitrig_out_b0, qdss_ctitrig_out_b1, qdss_traceclk_a, + qdss_traceclk_b, qdss_tracectl_a, qdss_tracectl_b, qdss_tracedata_a, + qdss_tracedata_b, reset_n, sd_card, sd_write, sec_mi2s, smb_int, + ssbi_wtr0, ssbi_wtr1, uim1, uim2, uim3, uim_batt, wcss_bt, wcss_fm, + wcss_wlan, webcam1_rst + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@1000000 { + compatible = "qcom,msm8916-pinctrl"; + reg = <0x1000000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 122>; + interrupt-controller; + #interrupt-cells = <2>; + + uart2: uart2-default { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + tx { + pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8960-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8960-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..5034eb6653c74a4294e57f60b1b83291a82ad077 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8960-pinctrl.txt @@ -0,0 +1,190 @@ +Qualcomm MSM8960 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8960 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8960-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio151, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc3_clk, + sdc3_cmd, + sdc3_data + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + audio_pcm, bt, cam_mclk0, cam_mclk1, cam_mclk2, + codec_mic_i2s, codec_spkr_i2s, ext_gps, fm, gps_blanking, + gps_pps_in, gps_pps_out, gp_clk_0a, gp_clk_0b, gp_clk_1a, + gp_clk_1b, gp_clk_2a, gp_clk_2b, gp_mn, gp_pdm_0a, + gp_pdm_0b, gp_pdm_1a, gp_pdm_1b, gp_pdm_2a, gp_pdm_2b, gpio, + gsbi1, gsbi1_spi_cs1_n, gsbi1_spi_cs2a_n, gsbi1_spi_cs2b_n, + gsbi1_spi_cs3_n, gsbi2, gsbi2_spi_cs1_n, gsbi2_spi_cs2_n, + gsbi2_spi_cs3_n, gsbi3, gsbi4, gsbi4_3d_cam_i2c_l, + gsbi4_3d_cam_i2c_r, gsbi5, gsbi5_3d_cam_i2c_l, + gsbi5_3d_cam_i2c_r, gsbi6, gsbi7, gsbi8, gsbi9, gsbi10, + gsbi11, gsbi11_spi_cs1a_n, gsbi11_spi_cs1b_n, + gsbi11_spi_cs2a_n, gsbi11_spi_cs2b_n, gsbi11_spi_cs3_n, + gsbi12, hdmi_cec, hdmi_ddc_clock, hdmi_ddc_data, + hdmi_hot_plug_detect, hsic, mdp_vsync, mi2s, mic_i2s, + pmb_clk, pmb_ext_ctrl, ps_hold, rpm_wdog, sdc2, sdc4, sdc5, + slimbus1, slimbus2, spkr_i2s, ssbi1, ssbi2, ssbi_ext_gps, + ssbi_pmic2, ssbi_qpa1, ssbi_ts, tsif1, tsif2, ts_eoc, + usb_fs1, usb_fs1_oe, usb_fs1_oe_n, usb_fs2, usb_fs2_oe, + usb_fs2_oe_n, vfe_camif_timer1_a, vfe_camif_timer1_b, + vfe_camif_timer2, vfe_camif_timer3_a, vfe_camif_timer3_b, + vfe_camif_timer4_a, vfe_camif_timer4_b, vfe_camif_timer4_c, + vfe_camif_timer5_a, vfe_camif_timer5_b, vfe_camif_timer6_a, + vfe_camif_timer6_b, vfe_camif_timer6_c, vfe_camif_timer7_a, + vfe_camif_timer7_b, vfe_camif_timer7_c, wlan + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + msmgpio: pinctrl@800000 { + compatible = "qcom,msm8960-pinctrl"; + reg = <0x800000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&msmgpio 0 0 152>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 16 0x4>; + + gsbi8_uart: gsbi8-uart { + mux { + pins = "gpio34", "gpio35"; + function = "gsbi8"; + }; + + tx { + pins = "gpio34"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8974-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8974-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..c22e6c425d0b725809f736dfc3beeb87982e1a7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8974-pinctrl.txt @@ -0,0 +1,121 @@ +Qualcomm MSM8974 TLMM block + +Required properties: +- compatible: "qcom,msm8974-pinctrl" +- reg: Should be the base address and length of the TLMM block. +- interrupts: Should be the parent IRQ of the TLMM block. +- interrupt-controller: Marks the device node as an interrupt controller. +- #interrupt-cells: Should be two. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells : Should be two. + The first cell is the gpio pin number and the + second cell is used for optional parameters. +- gpio-ranges: see ../gpio/gpio.txt + +Optional properties: + +- gpio-reserved-ranges: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Qualcomm's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + pins, function, bias-disable, bias-pull-down, bias-pull,up, drive-strength. + +Non-empty subnodes must specify the 'pins' property. +Note that not all properties are valid for all pins. + + +Valid values for pins are: + gpio0-gpio145 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data, sdc2_clk, sdc2_cmd, sdc2_data + Supports bias and drive-strength + + hsic_data, hsic_strobe + Supports only mux + +Valid values for function are: + cci_i2c0, cci_i2c1, uim1, uim2, uim_batt_alarm, + blsp_uim1, blsp_uart1, blsp_i2c1, blsp_spi1, + blsp_uim2, blsp_uart2, blsp_i2c2, blsp_spi2, + blsp_uim3, blsp_uart3, blsp_i2c3, blsp_spi3, + blsp_uim4, blsp_uart4, blsp_i2c4, blsp_spi4, + blsp_uim5, blsp_uart5, blsp_i2c5, blsp_spi5, + blsp_uim6, blsp_uart6, blsp_i2c6, blsp_spi6, + blsp_uim7, blsp_uart7, blsp_i2c7, blsp_spi7, + blsp_uim8, blsp_uart8, blsp_i2c8, blsp_spi8, + blsp_uim9, blsp_uart9, blsp_i2c9, blsp_spi9, + blsp_uim10, blsp_uart10, blsp_i2c10, blsp_spi10, + blsp_uim11, blsp_uart11, blsp_i2c11, blsp_spi11, + blsp_uim12, blsp_uart12, blsp_i2c12, blsp_spi12, + blsp_spi1_cs1, blsp_spi2_cs2, blsp_spi_cs3, blsp_spi2_cs1, blsp_spi2_cs2 + blsp_spi2_cs3, blsp_spi10_cs1, blsp_spi10_cs2, blsp_spi10_cs3, + sdc3, sdc4, gcc_gp_clk1, gcc_gp_clk2, gcc_gp_clk3, cci_timer0, cci_timer1, + cci_timer2, cci_timer3, cci_async_in0, cci_async_in1, cci_async_in2, + cam_mckl0, cam_mclk1, cam_mclk2, cam_mclk3, mdp_vsync, hdmi_cec, hdmi_ddc, + hdmi_hpd, edp_hpd, gp_pdm0, gp_pdm1, gp_pdm2, gp_pdm3, gp0_clk, gp1_clk, + gp_mn, tsif1, tsif2, hsic, grfc, audio_ref_clk, qua_mi2s, pri_mi2s, spkr_mi2s, + ter_mi2s, sec_mi2s, bt, fm, wlan, slimbus, hsic_ctl, gpio + + (Note that this is not yet the complete list of functions) + + + +Example: + + msmgpio: pinctrl@fd510000 { + compatible = "qcom,msm8974-pinctrl"; + reg = <0xfd510000 0x4000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&msmgpio 0 0 146>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <0 208 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart2_default>; + + uart2_default: uart2_default { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + tx { + pins = "gpio4"; + drive-strength = <4>; + bias-disable; + }; + + rx { + pins = "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8994-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8994-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..f15443f6e78eb77b5edab227069a4f953839b28c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8994-pinctrl.txt @@ -0,0 +1,186 @@ +Qualcomm MSM8994 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8994 platform. + +- compatible: + Usage: required + Value type: + Definition: Should contain one of: + "qcom,msm8992-pinctrl", + "qcom,msm8994-pinctrl". + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio145 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc1_rclk, sdc2_clk, + sdc2_cmd, sdc2_data + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + audio_ref_clk, blsp_i2c1, blsp_i2c2, blsp_i2c3, blsp_i2c4, blsp_i2c5, + blsp_i2c6, blsp_i2c7, blsp_i2c8, blsp_i2c9, blsp_i2c10, blsp_i2c11, + blsp_i2c12, blsp_spi1, blsp_spi1_cs1, blsp_spi1_cs2, blsp_spi1_cs3, + blsp_spi2, blsp_spi2_cs1, blsp_spi2_cs2, blsp_spi2_cs3, blsp_spi3, + blsp_spi4, blsp_spi5, blsp_spi6, blsp_spi7, blsp_spi8, blsp_spi9, + blsp_spi10, blsp_spi10_cs1, blsp_spi10_cs2, blsp_spi10_cs3, blsp_spi11, + blsp_spi12, blsp_uart1, blsp_uart2, blsp_uart3, blsp_uart4, blsp_uart5, + blsp_uart6, blsp_uart7, blsp_uart8, blsp_uart9, blsp_uart10, blsp_uart11, + blsp_uart12, blsp_uim1, blsp_uim2, blsp_uim3, blsp_uim4, blsp_uim5, + blsp_uim6, blsp_uim7, blsp_uim8, blsp_uim9, blsp_uim10, blsp_uim11, + blsp_uim12, blsp11_i2c_scl_b, blsp11_i2c_sda_b, blsp11_uart_rx_b, + blsp11_uart_tx_b, cam_mclk0, cam_mclk1, cam_mclk2, cam_mclk3, + cci_async_in0, cci_async_in1, cci_async_in2, cci_i2c0, cci_i2c1, + cci_timer0, cci_timer1, cci_timer2, cci_timer3, cci_timer4, + gcc_gp1_clk_a, gcc_gp1_clk_b, gcc_gp2_clk_a, gcc_gp2_clk_b, gcc_gp3_clk_a, + gcc_gp3_clk_b, gp_mn, gp_pdm0, gp_pdm1, gp_pdm2, gp0_clk, + gp1_clk, gps_tx, gsm_tx, hdmi_cec, hdmi_ddc, hdmi_hpd, hdmi_rcv, + mdp_vsync, mss_lte, nav_pps, nav_tsync, qdss_cti_trig_in_a, + qdss_cti_trig_in_b, qdss_cti_trig_in_c, qdss_cti_trig_in_d, + qdss_cti_trig_out_a, qdss_cti_trig_out_b, qdss_cti_trig_out_c, + qdss_cti_trig_out_d, qdss_traceclk_a, qdss_traceclk_b, qdss_tracectl_a, + qdss_tracectl_b, qdss_tracedata_a, qdss_tracedata_b, qua_mi2s, pci_e0, + pci_e1, pri_mi2s, sdc4, sec_mi2s, slimbus, spkr_i2s, ter_mi2s, tsif1, + tsif2, uim_batt_alarm, uim1, uim2, uim3, uim4, gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + msmgpio: pinctrl@fd510000 { + compatible = "qcom,msm8994-pinctrl"; + reg = <0xfd510000 0x4000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&msmgpio 0 0 146>; + interrupt-controller; + #interrupt-cells = <2>; + + blsp1_uart2_default: blsp1_uart2_default { + pinmux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + pinconf { + pins = "gpio4", "gpio5"; + drive-strength = <16>; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8996-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8996-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa97f609fe45146c665e0e6a535bc1602ff6bf70 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8996-pinctrl.txt @@ -0,0 +1,208 @@ +Qualcomm MSM8996 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8996 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8996-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-ranges: + Usage: required + Definition: see ../gpio/gpio.txt + +- gpio-reserved-ranges: + Usage: optional + Definition: see ../gpio/gpio.txt + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio149 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@1010000 { + compatible = "qcom,msm8996-pinctrl"; + reg = <0x01010000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + gpio-ranges = <&tlmm 0 0 150>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart8"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8998-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8998-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..e70c79bbbc5b28617ecf91b30151933685480fdf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,msm8998-pinctrl.txt @@ -0,0 +1,193 @@ +Qualcomm MSM8998 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +MSM8998 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,msm8998-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio149 + Supports mux, bias and drive-strength + + sdc2_clk, sdc2_cmd, sdc2_data + Supports bias and drive-strength + + ufs_reset + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + gpio, adsp_ext, agera_pll, atest_char, atest_gpsadc0, + atest_gpsadc1, atest_tsens, atest_tsens2, atest_usb1, + atest_usb10, atest_usb11, atest_usb12, atest_usb13, + audio_ref, bimc_dte0, bimc_dte1, blsp10_spi, blsp10_spi_a, + blsp10_spi_b, blsp11_i2c, blsp1_spi, blsp1_spi_a, + blsp1_spi_b, blsp2_spi, blsp9_spi, blsp_i2c1, blsp_i2c2, + blsp_i2c3, blsp_i2c4, blsp_i2c5, blsp_i2c6, blsp_i2c7, + blsp_i2c8, blsp_i2c9, blsp_i2c10, blsp_i2c11, blsp_i2c12, + blsp_spi1, blsp_spi2, blsp_spi3, blsp_spi4, blsp_spi5, + blsp_spi6, blsp_spi7, blsp_spi8, blsp_spi9, blsp_spi10, + blsp_spi11, blsp_spi12, blsp_uart1_a, blsp_uart1_b, + blsp_uart2_a, blsp_uart2_b, blsp_uart3_a, blsp_uart3_b, + blsp_uart7_a, blsp_uart7_b, blsp_uart8, blsp_uart8_a, + blsp_uart8_b, blsp_uart9_a, blsp_uart9_b, blsp_uim1_a, + blsp_uim1_b, blsp_uim2_a, blsp_uim2_b, blsp_uim3_a, + blsp_uim3_b, blsp_uim7_a, blsp_uim7_b, blsp_uim8_a, + blsp_uim8_b, blsp_uim9_a, blsp_uim9_b, bt_reset, + btfm_slimbus, cam_mclk, cci_async, cci_i2c, cci_timer0, + cci_timer1, cci_timer2, cci_timer3, cci_timer4, cri_trng, + cri_trng0, cri_trng1, dbg_out, ddr_bist, edp_hot, edp_lcd, + gcc_gp1_a, gcc_gp1_b, gcc_gp2_a, gcc_gp2_b, gcc_gp3_a, + gcc_gp3_b, hdmi_cec, hdmi_ddc, hdmi_hot, hdmi_rcv, + isense_dbg, jitter_bist, ldo_en, ldo_update, lpass_slimbus, + m_voc, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2, + mdp_vsync3, mdp_vsync_a, mdp_vsync_b, modem_tsync, mss_lte, + nav_dr, nav_pps, pa_indicator, pci_e0, phase_flag, + pll_bypassnl, pll_reset, pri_mi2s, pri_mi2s_ws, prng_rosc, + pwr_crypto, pwr_modem, pwr_nav, qdss_cti0_a, qdss_cti0_b, + qdss_cti1_a, qdss_cti1_b, qdss, qlink_enable, + qlink_request, qua_mi2s, sd_card, sd_write, sdc40, sdc41, + sdc42, sdc43, sdc4_clk, sdc4_cmd, sec_mi2s, sp_cmu, + spkr_i2s, ssbi1, ssc_irq, ter_mi2s, tgu_ch0, tgu_ch1, + tsense_pwm1, tsense_pwm2, tsif1_clk, tsif1_data, tsif1_en, + tsif1_error, tsif1_sync, tsif2_clk, tsif2_data, tsif2_en, + tsif2_error, tsif2_sync, uim1_clk, uim1_data, uim1_present, + uim1_reset, uim2_clk, uim2_data, uim2_present, uim2_reset, + uim_batt, usb_phy, vfr_1, vsense_clkout, vsense_data0, + vsense_data1, vsense_mode, wlan1_adc0, wlan1_adc1, + wlan2_adc0, wlan2_adc1, + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@03400000 { + compatible = "qcom,msm8998-pinctrl"; + reg = <0x03400000 0xc00000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart8_a"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,pmic-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,pmic-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..a00984fe276b64e3991479ef4f1000375989a8e3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,pmic-gpio.txt @@ -0,0 +1,262 @@ +Qualcomm PMIC GPIO block + +This binding describes the GPIO block(s) found in the 8xxx series of +PMIC's from Qualcomm. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8005-gpio" + "qcom,pm8018-gpio" + "qcom,pm8038-gpio" + "qcom,pm8058-gpio" + "qcom,pm8916-gpio" + "qcom,pm8917-gpio" + "qcom,pm8921-gpio" + "qcom,pm8941-gpio" + "qcom,pm8994-gpio" + "qcom,pm8998-gpio" + "qcom,pma8084-gpio" + "qcom,pmi8994-gpio" + + And must contain either "qcom,spmi-gpio" or "qcom,ssbi-gpio" + if the device is on an spmi bus or an ssbi bus respectively + +- reg: + Usage: required + Value type: + Definition: Register base of the GPIO block and length. + +- interrupts: + Usage: required + Value type: + Definition: Must contain an array of encoded interrupt specifiers for + each available GPIO + +- gpio-controller: + Usage: required + Value type: + Definition: Mark the device node as a GPIO controller + +- #gpio-cells: + Usage: required + Value type: + Definition: Must be 2; + the first cell will be used to define gpio number and the + second denotes the flags for this gpio + +- qcom,gpios-disallowed: + Usage: optional + Value type: + Definition: Array of the GPIO hardware numbers corresponding to GPIOs + which the APSS processor is not allowed to configure. + The hardware numbers are indexed from 1. + The interrupt resources for these GPIOs must not be defined + in "interrupts" and "interrupt-names" properties. + GPIOs defined in this array won't be registered as pins + in the pinctrl device or gpios in the gpio chip. + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin or a list of pins. This configuration can include the +mux function to select on those pin(s), and various pin configuration +parameters, as listed below. + + +SUBNODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio1-gpio4 for pm8005 + gpio1-gpio6 for pm8018 + gpio1-gpio12 for pm8038 + gpio1-gpio40 for pm8058 + gpio1-gpio4 for pm8916 + gpio1-gpio38 for pm8917 + gpio1-gpio44 for pm8921 + gpio1-gpio36 for pm8941 + gpio1-gpio22 for pm8994 + gpio1-gpio26 for pm8998 + gpio1-gpio22 for pma8084 + gpio1-gpio10 for pmi8994 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Valid values are: + "normal", + "paired", + "func1", + "func2", + "dtest1", + "dtest2", + "dtest3", + "dtest4", + And following values are supported by LV/MV GPIO subtypes: + "func3", + "func4" + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configured as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull up. + +- qcom,pull-up-strength: + Usage: optional + Value type: + Definition: Specifies the strength to use for pull up, if selected. + Valid values are; as defined in + : + 1: 30uA (PMIC_GPIO_PULL_UP_30) + 2: 1.5uA (PMIC_GPIO_PULL_UP_1P5) + 3: 31.5uA (PMIC_GPIO_PULL_UP_31P5) + 4: 1.5uA + 30uA boost (PMIC_GPIO_PULL_UP_1P5_30) + If this property is omitted 30uA strength will be used if + pull up is selected + +- bias-high-impedance: + Usage: optional + Value type: + Definition: The specified pins will put in high-Z mode and disabled. + +- input-enable: + Usage: optional + Value type: + Definition: The specified pins are put in input mode. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- power-source: + Usage: optional + Value type: + Definition: Selects the power source for the specified pins. Valid + power sources are defined per chip in + + +- qcom,drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins. Value + drive strengths are: + 0: no (PMIC_GPIO_STRENGTH_NO) + 1: high (PMIC_GPIO_STRENGTH_HIGH) 0.9mA @ 1.8V - 1.9mA @ 2.6V + 2: medium (PMIC_GPIO_STRENGTH_MED) 0.6mA @ 1.8V - 1.25mA @ 2.6V + 3: low (PMIC_GPIO_STRENGTH_LOW) 0.15mA @ 1.8V - 0.3mA @ 2.6V + as defined in + +- drive-push-pull: + Usage: optional + Value type: + Definition: The specified pins are configured in push-pull mode. + +- drive-open-drain: + Usage: optional + Value type: + Definition: The specified pins are configured in open-drain mode. + +- drive-open-source: + Usage: optional + Value type: + Definition: The specified pins are configured in open-source mode. + +- qcom,analog-pass: + Usage: optional + Value type: + Definition: The specified pins are configured in analog-pass-through mode. + +- qcom,atest: + Usage: optional + Value type: + Definition: Selects ATEST rail to route to GPIO when it's configured + in analog-pass-through mode. + Valid values are 1-4 corresponding to ATEST1 to ATEST4. + +- qcom,dtest-buffer: + Usage: optional + Value type: + Definition: Selects DTEST rail to route to GPIO when it's configured + as digital input. + Valid values are 1-4 corresponding to DTEST1 to DTEST4. + +Example: + + pm8921_gpio: gpio@150 { + compatible = "qcom,pm8921-gpio", "qcom,ssbi-gpio"; + reg = <0x150 0x160>; + interrupts = <192 1>, <193 1>, <194 1>, + <195 1>, <196 1>, <197 1>, + <198 1>, <199 1>, <200 1>, + <201 1>, <202 1>, <203 1>, + <204 1>, <205 1>, <206 1>, + <207 1>, <208 1>, <209 1>, + <210 1>, <211 1>, <212 1>, + <213 1>, <214 1>, <215 1>, + <216 1>, <217 1>, <218 1>, + <219 1>, <220 1>, <221 1>, + <222 1>, <223 1>, <224 1>, + <225 1>, <226 1>, <227 1>, + <228 1>, <229 1>, <230 1>, + <231 1>, <232 1>, <233 1>, + <234 1>, <235 1>; + + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <1 20>; + + pm8921_gpio_keys: gpio-keys { + volume-keys { + pins = "gpio20", "gpio21"; + function = "normal"; + + input-enable; + bias-pull-up; + drive-push-pull; + qcom,drive-strength = ; + power-source = ; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,pmic-mpp.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,pmic-mpp.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ab95bc26066ce54e09f3866611af2aded817d13 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,pmic-mpp.txt @@ -0,0 +1,181 @@ +Qualcomm PMIC Multi-Purpose Pin (MPP) block + +This binding describes the MPP block(s) found in the 8xxx series +of PMIC's from Qualcomm. + +- compatible: + Usage: required + Value type: + Definition: Should contain one of: + "qcom,pm8018-mpp", + "qcom,pm8038-mpp", + "qcom,pm8058-mpp", + "qcom,pm8821-mpp", + "qcom,pm8841-mpp", + "qcom,pm8916-mpp", + "qcom,pm8917-mpp", + "qcom,pm8921-mpp", + "qcom,pm8941-mpp", + "qcom,pm8994-mpp", + "qcom,pma8084-mpp", + + And must contain either "qcom,spmi-mpp" or "qcom,ssbi-mpp" + if the device is on an spmi bus or an ssbi bus respectively. + +- reg: + Usage: required + Value type: + Definition: Register base of the MPP block and length. + +- interrupts: + Usage: required + Value type: + Definition: Must contain an array of encoded interrupt specifiers for + each available MPP + +- gpio-controller: + Usage: required + Value type: + Definition: Mark the device node as a GPIO controller + +- #gpio-cells: + Usage: required + Value type: + Definition: Must be 2; + the first cell will be used to define MPP number and the + second denotes the flags for this MPP + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin or a list of pins. This configuration can include the +mux function to select on those pin(s), and various pin configuration +parameters, as listed below. + +SUBNODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of MPP pins affected by the properties specified in + this subnode. Valid pins are: + mpp1-mpp4 for pm8841 + mpp1-mpp4 for pm8916 + mpp1-mpp8 for pm8941 + mpp1-mpp4 for pma8084 + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Valid values are: + "digital", + "analog", + "sink" + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configured as no pull. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configured as pull up. + Valid values are 600, 10000 and 30000 in bidirectional mode + only, i.e. when operating in qcom,analog-mode and input and + outputs are enabled. The hardware ignores the configuration + when operating in other modes. + +- bias-high-impedance: + Usage: optional + Value type: + Definition: The specified pins will put in high-Z mode and disabled. + +- input-enable: + Usage: optional + Value type: + Definition: The specified pins are put in input mode, i.e. their input + buffer is enabled + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + +- power-source: + Usage: optional + Value type: + Definition: Selects the power source for the specified pins. Valid power + sources are defined in + +- qcom,analog-level: + Usage: optional + Value type: + Definition: Selects the source for analog output. Valued values are + defined in + PMIC_MPP_AOUT_LVL_* + +- qcom,dtest: + Usage: optional + Value type: + Definition: Selects which dtest rail to be routed in the various functions. + Valid values are 1-4 + +- qcom,amux-route: + Usage: optional + Value type: + Definition: Selects the source for analog input. Valid values are + defined in + PMIC_MPP_AMUX_ROUTE_CH5, PMIC_MPP_AMUX_ROUTE_CH6... +- qcom,paired: + Usage: optional + Value type: + Definition: Indicates that the pin should be operating in paired mode. + +Example: + + mpps@a000 { + compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; + reg = <0xa000>; + gpio-controller; + #gpio-cells = <2>; + interrupts = <4 0xa0 0 0>, <4 0xa1 0 0>, <4 0xa2 0 0>, <4 0xa3 0 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8841_default>; + + pm8841_default: default { + gpio { + pins = "mpp1", "mpp2", "mpp3", "mpp4"; + function = "digital"; + input-enable; + power-source = ; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,scuba-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,scuba-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a51180cdba928a20f0a02b017a5d73523e6b4a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,scuba-pinctrl.txt @@ -0,0 +1,187 @@ +Qualcomm Technologies, Inc. Scuba TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +BENGAL platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,scuba-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio126 + Supports mux, bias and drive-strength + + sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd, + sdc2_data sdc1_rclk + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@400000 { + compatible = "qcom,scuba-pinctrl"; + reg = <0x500000 0x300000>; + interrupts = <0 227 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,sdm660-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,sdm660-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..dbd4baf0825a62da5f2d59fba5f6d4ac15e82b98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,sdm660-pinctrl.txt @@ -0,0 +1,199 @@ +Qualcomm Technologies, Inc. SDM660 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +SDM660 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm660-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio0-gpio149, + sdc1_clk, + sdc1_cmd, + sdc1_data + sdc2_clk, + sdc2_cmd, + sdc2_data + sdc1_rclk, + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens, + bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8, + qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b, + dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10, + blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12, + mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11, + atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char, + cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b, + pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c, + qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4, + qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5, + atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6, + atest_usb20, atest_char0, dac_calib10, qdss_stm10, + qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6, + blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11, + qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1, + qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11, + dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6, + qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14, + dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem, + dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto, + dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0, + dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25, + sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2, + qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3, + uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9, + blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7, + qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11, + blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0, + cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4, + blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4, + qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus, + isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s, + qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b, + sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b, + gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12, + qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29, + tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27, + qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk, + sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b, + sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b, + ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b, + blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt, + pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11, + qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx, + qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3, + gpio + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@01010000 { + compatible = "qcom,sdm660-pinctrl"; + reg = <0x01010000 0x300000>; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart8"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,sdm845-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,sdm845-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..665aadb5ea289fc7bca563d35e21557ce7fa9124 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/qcom,sdm845-pinctrl.txt @@ -0,0 +1,176 @@ +Qualcomm SDM845 TLMM block + +This binding describes the Top Level Mode Multiplexer block found in the +SDM845 platform. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-pinctrl" + +- reg: + Usage: required + Value type: + Definition: the base address and size of the TLMM register space. + +- interrupts: + Usage: required + Value type: + Definition: should specify the TLMM summary IRQ. + +- interrupt-controller: + Usage: required + Value type: + Definition: identifies this node as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +- gpio-controller: + Usage: required + Value type: + Definition: identifies this node as a gpio controller + +- #gpio-cells: + Usage: required + Value type: + Definition: must be 2. Specifying the pin number and flags, as defined + in + +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, drive strength, etc. + + +PIN CONFIGURATION NODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: + Definition: List of gpio pins affected by the properties specified in + this subnode. + + Valid pins are: + gpio0-gpio149 + Supports mux, bias and drive-strength + + sdc2_clk, sdc2_cmd, sdc2_data + Supports bias and drive-strength + +- function: + Usage: required + Value type: + Definition: Specify the alternative function to be configured for the + specified pins. Functions are only valid for gpio pins. + Valid values are: + + gpio, adsp_ext, agera_pll, atest_char, atest_tsens, + atest_tsens2, atest_usb1, atest_usb10, atest_usb11, + atest_usb12, atest_usb13, atest_usb2, atest_usb20, + atest_usb21, atest_usb22, atest_usb23, audio_ref, + btfm_slimbus, cam_mclk, cci_async, cci_i2c, cci_timer0, + cci_timer1, cci_timer2, cci_timer3, cci_timer4, cri_trng, + cri_trng0, cri_trng1, dbg_out, ddr_bist, ddr_pxi0, + ddr_pxi1, ddr_pxi2, ddr_pxi3, edp_hot, edp_lcd, gcc_gp1, + gcc_gp2, gcc_gp3, jitter_bist, ldo_en, ldo_update, + lpass_slimbus, m_voc, mdp_vsync, mdp_vsync0, mdp_vsync1, + mdp_vsync2, mdp_vsync3, mss_lte, nav_pps, pa_indicator, + pci_e0, pci_e1, phase_flag, pll_bist, pll_bypassnl, + pll_reset, pri_mi2s, pri_mi2s_ws, prng_rosc, qdss_cti, + qdss, qlink_enable, qlink_request, qua_mi2s, qup0, qup1, + qup10, qup11, qup12, qup13, qup14, qup15, qup2, qup3, qup4, + qup5, qup6, qup7, qup8, qup9, qup_l4, qup_l5, qup_l6, + qspi_clk, qspi_cs, qspi_data, sd_write, sdc4_clk, sdc4_cmd, + sdc4_data, sec_mi2s, sp_cmu, spkr_i2s, ter_mi2s, tgu_ch0, + tgu_ch1, tgu_ch2, tgu_ch3, tsense_pwm1, tsense_pwm2, + tsif1_clk, tsif1_data, tsif1_en, tsif1_error, tsif1_sync, + tsif2_clk, tsif2_data, tsif2_en, tsif2_error, tsif2_sync, + uim1_clk, uim1_data, uim1_present, uim1_reset, uim2_clk, + uim2_data, uim2_present, uim2_reset, uim_batt, usb_phy, + vfr_1, vsense_trigger, wlan1_adc0, wlan1_adc1, wlan2_adc0, + wlan2_adc1, + +- bias-disable: + Usage: optional + Value type: + Definition: The specified pins should be configued as no pull. + +- bias-pull-down: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull down. + +- bias-pull-up: + Usage: optional + Value type: + Definition: The specified pins should be configued as pull up. + +- output-high: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + high. + Not valid for sdc pins. + +- output-low: + Usage: optional + Value type: + Definition: The specified pins are configured in output mode, driven + low. + Not valid for sdc pins. + +- drive-strength: + Usage: optional + Value type: + Definition: Selects the drive strength for the specified pins, in mA. + Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16 + +Example: + + tlmm: pinctrl@3400000 { + compatible = "qcom,sdm845-pinctrl"; + reg = <0x03400000 0xc00000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + qup9_active: qup9-active { + mux { + pins = "gpio4", "gpio5"; + function = "qup9"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/renesas,pfc-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/renesas,pfc-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..abd8fbcf1e62d480562a0fb9d1471020c0c29d75 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -0,0 +1,181 @@ +* Renesas Pin Function Controller (GPIO and Pin Mux/Config) + +The Pin Function Controller (PFC) is a Pin Mux/Config controller. On SH73A0, +R8A73A4 and R8A7740 it also acts as a GPIO controller. + + +Pin Control +----------- + +Required Properties: + + - compatible: should be one of the following. + - "renesas,pfc-emev2": for EMEV2 (EMMA Mobile EV2) compatible pin-controller. + - "renesas,pfc-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible pin-controller. + - "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller. + - "renesas,pfc-r8a7743": for R8A7743 (RZ/G1M) compatible pin-controller. + - "renesas,pfc-r8a7745": for R8A7745 (RZ/G1E) compatible pin-controller. + - "renesas,pfc-r8a77470": for R8A77470 (RZ/G1C) compatible pin-controller. + - "renesas,pfc-r8a7778": for R8A7778 (R-Car M1) compatible pin-controller. + - "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller. + - "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller. + - "renesas,pfc-r8a7791": for R8A7791 (R-Car M2-W) compatible pin-controller. + - "renesas,pfc-r8a7792": for R8A7792 (R-Car V2H) compatible pin-controller. + - "renesas,pfc-r8a7793": for R8A7793 (R-Car M2-N) compatible pin-controller. + - "renesas,pfc-r8a7794": for R8A7794 (R-Car E2) compatible pin-controller. + - "renesas,pfc-r8a7795": for R8A7795 (R-Car H3) compatible pin-controller. + - "renesas,pfc-r8a7796": for R8A7796 (R-Car M3-W) compatible pin-controller. + - "renesas,pfc-r8a77965": for R8A77965 (R-Car M3-N) compatible pin-controller. + - "renesas,pfc-r8a77970": for R8A77970 (R-Car V3M) compatible pin-controller. + - "renesas,pfc-r8a77980": for R8A77980 (R-Car V3H) compatible pin-controller. + - "renesas,pfc-r8a77990": for R8A77990 (R-Car E3) compatible pin-controller. + - "renesas,pfc-r8a77995": for R8A77995 (R-Car D3) compatible pin-controller. + - "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller. + + - reg: Base address and length of each memory resource used by the pin + controller hardware module. + +Optional properties: + + - #gpio-range-cells: Mandatory when the PFC doesn't handle GPIO, forbidden + otherwise. Should be 3. + + - interrupts-extended: Specify the interrupts associated with external + IRQ pins. This property is mandatory when the PFC handles GPIOs and + forbidden otherwise. When specified, it must contain one interrupt per + external IRQ, sorted by external IRQ number. + +The PFC node also acts as a container for pin configuration nodes. Please refer +to pinctrl-bindings.txt in this directory for the definition of the term "pin +configuration node" and for the common pinctrl bindings used by client devices. + +Each pin configuration node represents a desired configuration for a pin, a +pin group, or a list of pins or pin groups. The configuration can include the +function to select on those pin(s) and pin configuration parameters (such as +pull-up and pull-down). + +Pin configuration nodes contain pin configuration properties, either directly +or grouped in child subnodes. Both pin muxing and configuration parameters can +be grouped in that way and referenced as a single pin configuration node by +client devices. + +A configuration node or subnode must reference at least one pin (through the +pins or pin groups properties) and contain at least a function or one +configuration parameter. When the function is present only pin groups can be +used to reference pins. + +All pin configuration nodes and subnodes names are ignored. All of those nodes +are parsed through phandles and processed purely based on their content. + +Pin Configuration Node Properties: + +- pins : An array of strings, each string containing the name of a pin. +- groups : An array of strings, each string containing the name of a pin + group. + +- function: A string containing the name of the function to mux to the pin + group(s) specified by the groups property. + + Valid values for pin, group and function names can be found in the group and + function arrays of the PFC data file corresponding to the SoC + (drivers/pinctrl/sh-pfc/pfc-*.c) + +The pin configuration parameters use the generic pinconf bindings defined in +pinctrl-bindings.txt in this directory. The supported parameters are +bias-disable, bias-pull-up, bias-pull-down, drive-strength and power-source. For +pins that have a configurable I/O voltage, the power-source value should be the +nominal I/O voltage in millivolts. + + +GPIO +---- + +On SH73A0, R8A73A4 and R8A7740 the PFC node is also a GPIO controller node. + +Required Properties: + + - gpio-controller: Marks the device node as a gpio controller. + + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second + cell specifies GPIO flags, as defined in . Only the + GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported. + +The syntax of the gpio specifier used by client nodes should be the following +with values derived from the SoC user manual. + + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [flags]> + +On other mach-shmobile platforms GPIO is handled by the gpio-rcar driver. +Please refer to Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +for documentation of the GPIO device tree bindings on those platforms. + + +Examples +-------- + +Example 1: SH73A0 (SH-Mobile AG5) pin controller node + + pfc: pin-controller@e6050000 { + compatible = "renesas,pfc-sh73a0"; + reg = <0xe6050000 0x8000>, + <0xe605801c 0x1c>; + gpio-controller; + #gpio-cells = <2>; + interrupts-extended = + <&irqpin0 0 0>, <&irqpin0 1 0>, <&irqpin0 2 0>, <&irqpin0 3 0>, + <&irqpin0 4 0>, <&irqpin0 5 0>, <&irqpin0 6 0>, <&irqpin0 7 0>, + <&irqpin1 0 0>, <&irqpin1 1 0>, <&irqpin1 2 0>, <&irqpin1 3 0>, + <&irqpin1 4 0>, <&irqpin1 5 0>, <&irqpin1 6 0>, <&irqpin1 7 0>, + <&irqpin2 0 0>, <&irqpin2 1 0>, <&irqpin2 2 0>, <&irqpin2 3 0>, + <&irqpin2 4 0>, <&irqpin2 5 0>, <&irqpin2 6 0>, <&irqpin2 7 0>, + <&irqpin3 0 0>, <&irqpin3 1 0>, <&irqpin3 2 0>, <&irqpin3 3 0>, + <&irqpin3 4 0>, <&irqpin3 5 0>, <&irqpin3 6 0>, <&irqpin3 7 0>; + }; + +Example 2: A GPIO LED node that references a GPIO + + #include + + leds { + compatible = "gpio-leds"; + led1 { + gpios = <&pfc 20 GPIO_ACTIVE_LOW>; + }; + }; + +Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps + for the MMCIF and SCIFA4 devices + + &pfc { + pinctrl-0 = <&scifa4_pins>; + pinctrl-names = "default"; + + mmcif_pins: mmcif { + mux { + groups = "mmc0_data8_0", "mmc0_ctrl_0"; + function = "mmc0"; + }; + cfg { + groups = "mmc0_data8_0"; + pins = "PORT279"; + bias-pull-up; + }; + }; + + scifa4_pins: scifa4 { + groups = "scifa4_data", "scifa4_ctrl"; + function = "scifa4"; + }; + }; + +Example 4: KZM-A9-GT (SH-Mobile AG5) default pin state for the MMCIF device + + &mmcif { + pinctrl-0 = <&mmcif_pins>; + pinctrl-names = "default"; + + bus-width = <8>; + vmmc-supply = <®_1p8v>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/renesas,rza1-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/renesas,rza1-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd3696eb36bf307e00f061cc8f5329d2afa8594c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/renesas,rza1-pinctrl.txt @@ -0,0 +1,223 @@ +Renesas RZ/A1 combined Pin and GPIO controller + +The Renesas SoCs of the RZ/A1 family feature a combined Pin and GPIO controller, +named "Ports" in the hardware reference manual. +Pin multiplexing and GPIO configuration is performed on a per-pin basis +writing configuration values to per-port register sets. +Each "port" features up to 16 pins, each of them configurable for GPIO +function (port mode) or in alternate function mode. +Up to 8 different alternate function modes exist for each single pin. + +Pin controller node +------------------- + +Required properties: + - compatible: should be: + - "renesas,r7s72100-ports": for RZ/A1H + - "renesas,r7s72101-ports", "renesas,r7s72100-ports": for RZ/A1M + - "renesas,r7s72102-ports": for RZ/A1L + + - reg + address base and length of the memory area where the pin controller + hardware is mapped to. + +Example: +Pin controller node for RZ/A1H SoC (r7s72100) + +pinctrl: pin-controller@fcfe3000 { + compatible = "renesas,r7s72100-ports"; + + reg = <0xfcfe3000 0x4230>; +}; + +Sub-nodes +--------- + +The child nodes of the pin controller node describe a pin multiplexing +function or a GPIO controller alternatively. + +- Pin multiplexing sub-nodes: + A pin multiplexing sub-node describes how to configure a set of + (or a single) pin in some desired alternate function mode. + A single sub-node may define several pin configurations. + A few alternate function require special pin configuration flags to be + supplied along with the alternate function configuration number. + The hardware reference manual specifies when a pin function requires + "software IO driven" mode to be specified. To do so use the generic + properties from the header file + to instruct the pin controller to perform the desired pin configuration + operation. + Please refer to pinctrl-bindings.txt to get to know more on generic + pin properties usage. + + The allowed generic formats for a pin multiplexing sub-node are the + following ones: + + node-1 { + pinmux = , , ... ; + GENERIC_PINCONFIG; + }; + + node-2 { + sub-node-1 { + pinmux = , , ... ; + GENERIC_PINCONFIG; + }; + + sub-node-2 { + pinmux = , , ... ; + GENERIC_PINCONFIG; + }; + + ... + + sub-node-n { + pinmux = , , ... ; + GENERIC_PINCONFIG; + }; + }; + + Use the second format when pins part of the same logical group need to have + different generic pin configuration flags applied. + + Client sub-nodes shall refer to pin multiplexing sub-nodes using the phandle + of the most external one. + + Eg. + + client-1 { + ... + pinctrl-0 = <&node-1>; + ... + }; + + client-2 { + ... + pinctrl-0 = <&node-2>; + ... + }; + + Required properties: + - pinmux: + integer array representing pin number and pin multiplexing configuration. + When a pin has to be configured in alternate function mode, use this + property to identify the pin by its global index, and provide its + alternate function configuration number along with it. + When multiple pins are required to be configured as part of the same + alternate function they shall be specified as members of the same + argument list of a single "pinmux" property. + Helper macros to ease assembling the pin index from its position + (port where it sits on and pin number) and alternate function identifier + are provided by the pin controller header file at: + + Integers values in "pinmux" argument list are assembled as: + ((PORT * 16 + PIN) | MUX_FUNC << 16) + + Optional generic properties: + - input-enable: + enable input bufer for pins requiring software driven IO input + operations. + - output-high: + enable output buffer for pins requiring software driven IO output + operations. output-low can be used alternatively, as line value is + ignored by the driver. + + The hardware reference manual specifies when a pin has to be configured to + work in bi-directional mode and when the IO direction has to be specified + by software. Bi-directional pins are managed by the pin controller driver + internally, while software driven IO direction has to be explicitly + selected when multiple options are available. + + Example: + A serial communication interface with a TX output pin and an RX input pin. + + &pinctrl { + scif2_pins: serial2 { + pinmux = , ; + }; + }; + + Pin #0 on port #3 is configured as alternate function #6. + Pin #2 on port #3 is configured as alternate function #4. + + Example 2: + I2c master: both SDA and SCL pins need bi-directional operations + + &pinctrl { + i2c2_pins: i2c2 { + pinmux = , ; + }; + }; + + Pin #4 on port #1 is configured as alternate function #1. + Pin #5 on port #1 is configured as alternate function #1. + Both need to work in bi-directional mode, the driver manages this internally. + + Example 3: + Multi-function timer input and output compare pins. + Configure TIOC0A as software driven input and TIOC0B as software driven + output. + + &pinctrl { + tioc0_pins: tioc0 { + tioc0_input_pins { + pinumx = ; + input-enable; + }; + + tioc0_output_pins { + pinmux = ; + output-enable; + }; + }; + }; + + &tioc0 { + ... + pinctrl-0 = <&tioc0_pins>; + ... + }; + + Pin #0 on port #4 is configured as alternate function #2 with IO direction + specified by software as input. + Pin #1 on port #4 is configured as alternate function #1 with IO direction + specified by software as output. + +- GPIO controller sub-nodes: + Each port of the r7s72100 pin controller hardware is itself a GPIO controller. + Different SoCs have different numbers of available pins per port, but + generally speaking, each of them can be configured in GPIO ("port") mode + on this hardware. + Describe GPIO controllers using sub-nodes with the following properties. + + Required properties: + - gpio-controller + empty property as defined by the GPIO bindings documentation. + - #gpio-cells + number of cells required to identify and configure a GPIO. + Shall be 2. + - gpio-ranges + Describes a GPIO controller specifying its specific pin base, the pin + base in the global pin numbering space, and the number of controlled + pins, as defined by the GPIO bindings documentation. Refer to + Documentation/devicetree/bindings/gpio/gpio.txt file for a more detailed + description. + + Example: + A GPIO controller node, controlling 16 pins indexed from 0. + The GPIO controller base in the global pin indexing space is pin 48, thus + pins [0 - 15] on this controller map to pins [48 - 63] in the global pin + indexing space. + + port3: gpio-3 { + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + A device node willing to use pins controlled by this GPIO controller, shall + refer to it as follows: + + led1 { + gpios = <&port3 10 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/rockchip,pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/rockchip,pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..0919db294c174e66710280d8d6688f78d436e3cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/rockchip,pinctrl.txt @@ -0,0 +1,168 @@ +* Rockchip Pinmux Controller + +The Rockchip Pinmux Controller, enables the IC +to share one PAD to several functional blocks. The sharing is done by +multiplexing the PAD input/output signals. For each PAD there are several +muxing options with option 0 being the use as a GPIO. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The Rockchip pin configuration node is a node of a group of pins which can be +used for a specific device or function. This node represents both mux and +config of the pins in that group. The 'pins' selects the function mode(also +named pin mode) this pin can work on and the 'config' configures various pad +settings such as pull-up, etc. + +The pins are grouped into up to 5 individual pin banks which need to be +defined as gpio sub-nodes of the pinmux controller. + +Required properties for iomux controller: + - compatible: should be + "rockchip,px30-pinctrl": for Rockchip PX30 + "rockchip,rv1108-pinctrl": for Rockchip RV1108 + "rockchip,rk2928-pinctrl": for Rockchip RK2928 + "rockchip,rk3066a-pinctrl": for Rockchip RK3066a + "rockchip,rk3066b-pinctrl": for Rockchip RK3066b + "rockchip,rk3128-pinctrl": for Rockchip RK3128 + "rockchip,rk3188-pinctrl": for Rockchip RK3188 + "rockchip,rk3228-pinctrl": for Rockchip RK3228 + "rockchip,rk3288-pinctrl": for Rockchip RK3288 + "rockchip,rk3328-pinctrl": for Rockchip RK3328 + "rockchip,rk3368-pinctrl": for Rockchip RK3368 + "rockchip,rk3399-pinctrl": for Rockchip RK3399 + + - rockchip,grf: phandle referencing a syscon providing the + "general register files" + +Optional properties for iomux controller: + - rockchip,pmu: phandle referencing a syscon providing the pmu registers + as some SoCs carry parts of the iomux controller registers there. + Required for at least rk3188 and rk3288. On the rk3368 this should + point to the PMUGRF syscon. + +Deprecated properties for iomux controller: + - reg: first element is the general register space of the iomux controller + It should be large enough to contain also separate pull registers. + second element is the separate pull register space of the rk3188. + Use rockchip,grf and rockchip,pmu described above instead. + +Required properties for gpio sub nodes: + - compatible: "rockchip,gpio-bank" + - reg: register of the gpio bank (different than the iomux registerset) + - interrupts: base interrupt of the gpio bank in the interrupt controller + - clocks: clock that drives this bank + - gpio-controller: identifies the node as a gpio controller and pin bank. + - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO + binding is used, the amount of cells must be specified as 2. See generic + GPIO binding documentation for description of particular cells. + - interrupt-controller: identifies the controller node as interrupt-parent. + - #interrupt-cells: the value of this property should be 2 and the interrupt + cells should use the standard two-cell scheme described in + bindings/interrupt-controller/interrupts.txt + +Deprecated properties for gpio sub nodes: + - compatible: "rockchip,rk3188-gpio-bank0" + - reg: second element: separate pull register for rk3188 bank0, use + rockchip,pmu described above instead + +Required properties for pin configuration node: + - rockchip,pins: 3 integers array, represents a group of pins mux and config + setting. The format is rockchip,pins = . + The MUX 0 means gpio and MUX 1 to N mean the specific device function. + The phandle of a node containing the generic pinconfig options + to use, as described in pinctrl-bindings.txt in this directory. + +Examples: + +#include + +... + +pinctrl@20008000 { + compatible = "rockchip,rk3066a-pinctrl"; + rockchip,grf = <&grf>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio0: gpio0@20034000 { + compatible = "rockchip,gpio-bank"; + reg = <0x20034000 0x100>; + interrupts = ; + clocks = <&clk_gates8 9>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ... + + pcfg_pull_default: pcfg_pull_default { + bias-pull-pin-default + }; + + uart2 { + uart2_xfer: uart2-xfer { + rockchip,pins = , + ; + }; + }; +}; + +uart2: serial@20064000 { + compatible = "snps,dw-apb-uart"; + reg = <0x20064000 0x400>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <1>; + clocks = <&mux_uart2>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart2_xfer>; +}; + +Example for rk3188: + + pinctrl@20008000 { + compatible = "rockchip,rk3188-pinctrl"; + rockchip,grf = <&grf>; + rockchip,pmu = <&pmu>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + gpio0: gpio0@2000a000 { + compatible = "rockchip,rk3188-gpio-bank0"; + reg = <0x2000a000 0x100>; + interrupts = ; + clocks = <&clk_gates8 9>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpio1: gpio1@2003c000 { + compatible = "rockchip,gpio-bank"; + reg = <0x2003c000 0x100>; + interrupts = ; + clocks = <&clk_gates8 10>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ... + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/samsung-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/samsung-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..70659c917bdc4a0636693cf943f244bb2e724954 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/samsung-pinctrl.txt @@ -0,0 +1,380 @@ +Samsung GPIO and Pin Mux/Config controller + +Samsung's ARM based SoC's integrates a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pads/pins +and also provides ability to multiplex and configure the output of various +on-chip controllers onto these pads. + +Required Properties: +- compatible: should be one of the following. + - "samsung,s3c2412-pinctrl": for S3C2412-compatible pin-controller, + - "samsung,s3c2416-pinctrl": for S3C2416-compatible pin-controller, + - "samsung,s3c2440-pinctrl": for S3C2440-compatible pin-controller, + - "samsung,s3c2450-pinctrl": for S3C2450-compatible pin-controller, + - "samsung,s3c64xx-pinctrl": for S3C64xx-compatible pin-controller, + - "samsung,s5pv210-pinctrl": for S5PV210-compatible pin-controller, + - "samsung,exynos3250-pinctrl": for Exynos3250 compatible pin-controller. + - "samsung,exynos4210-pinctrl": for Exynos4210 compatible pin-controller. + - "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller. + - "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller. + - "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller. + - "samsung,exynos5410-pinctrl": for Exynos5410 compatible pin-controller. + - "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller. + - "samsung,exynos5433-pinctrl": for Exynos5433 compatible pin-controller. + - "samsung,exynos7-pinctrl": for Exynos7 compatible pin-controller. + +- reg: Base address of the pin controller hardware module and length of + the address space it occupies. + + - reg: Second base address of the pin controller if the specific registers + of the pin controller are separated into the different base address. + + Eg: GPF[1-5] of Exynos5433 are separated into the two base address. + - First base address is for GPAx and GPF[1-5] external interrupt + registers. + - Second base address is for GPF[1-5] pinctrl registers. + + pinctrl_0: pinctrl@10580000 { + compatible = "samsung,exynos5433-pinctrl"; + reg = <0x10580000 0x1a20>, <0x11090000 0x100>; + + wakeup-interrupt-controller { + compatible = "samsung,exynos7-wakeup-eint"; + interrupts = <0 16 0>; + }; + }; + +- Pin banks as child nodes: Pin banks of the controller are represented by child + nodes of the controller node. Bank name is taken from name of the node. Each + bank node must contain following properties: + + - gpio-controller: identifies the node as a gpio controller and pin bank. + - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO + binding is used, the amount of cells must be specified as 2. See the below + mentioned gpio binding representation for description of particular cells. + + Eg: <&gpx2 6 0> + <[phandle of the gpio controller node] + [pin number within the gpio controller] + [flags]> + + Values for gpio specifier: + - Pin number: is a value between 0 to 7. + - Flags: 0 - Active High + 1 - Active Low + +- Pin mux/config groups as child nodes: The pin mux (selecting pin function + mode) and pin config (pull up/down, driver strength) settings are represented + as child nodes of the pin-controller node. There should be atleast one + child node and there is no limit on the count of these child nodes. It is + also possible for a child node to consist of several further child nodes + to allow grouping multiple pinctrl groups into one. The format of second + level child nodes is exactly the same as for first level ones and is + described below. + + The child node should contain a list of pin(s) on which a particular pin + function selection or pin configuration (or both) have to applied. This + list of pins is specified using the property name "samsung,pins". There + should be atleast one pin specfied for this property and there is no upper + limit on the count of pins that can be specified. The pins are specified + using pin names which are derived from the hardware manual of the SoC. As + an example, the pins in GPA0 bank of the pin controller can be represented + as "gpa0-0", "gpa0-1", "gpa0-2" and so on. The names should be in lower case. + The format of the pin names should be (as per the hardware manual) + "[pin bank name]-[pin number within the bank]". + + The pin function selection that should be applied on the pins listed in the + child node is specified using the "samsung,pin-function" property. The value + of this property that should be applied to each of the pins listed in the + "samsung,pins" property should be picked from the hardware manual of the SoC + for the specified pin group. This property is optional in the child node if + no specific function selection is desired for the pins listed in the child + node. The value of this property is used as-is to program the pin-controller + function selector register of the pin-bank. + + The child node can also optionally specify one or more of the pin + configuration that should be applied on all the pins listed in the + "samsung,pins" property of the child node. The following pin configuration + properties are supported. + + - samsung,pin-val: Initial value of pin output buffer. + - samsung,pin-pud: Pull up/down configuration. + - samsung,pin-drv: Drive strength configuration. + - samsung,pin-pud-pdn: Pull up/down configuration in power down mode. + - samsung,pin-drv-pdn: Drive strength configuration in power down mode. + + The values specified by these config properties should be derived from the + hardware manual and these values are programmed as-is into the pin + pull up/down and driver strength register of the pin-controller. + + Note: A child should include atleast a pin function selection property or + pin configuration property (one or more) or both. + + The client nodes that require a particular pin function selection and/or + pin configuration should use the bindings listed in the "pinctrl-bindings.txt" + file. + +External GPIO and Wakeup Interrupts: + +The controller supports two types of external interrupts over gpio. The first +is the external gpio interrupt and second is the external wakeup interrupts. +The difference between the two is that the external wakeup interrupts can be +used as system wakeup events. + +A. External GPIO Interrupts: For supporting external gpio interrupts, the + following properties should be specified in the pin-controller device node. + + - interrupts: interrupt specifier for the controller. The format and value of + the interrupt specifier depends on the interrupt parent for the controller. + + In addition, following properties must be present in node of every bank + of pins supporting GPIO interrupts: + + - interrupt-controller: identifies the controller node as interrupt-parent. + - #interrupt-cells: the value of this property should be 2. + - First Cell: represents the external gpio interrupt number local to the + external gpio interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered + +B. External Wakeup Interrupts: For supporting external wakeup interrupts, a + child node representing the external wakeup interrupt controller should be + included in the pin-controller device node. + + Only one pin-controller device node can include external wakeup interrupts + child node (in other words, only one External Wakeup Interrupts + pin-controller is supported). + + This child node should include following properties: + + - compatible: identifies the type of the external wakeup interrupt controller + The possible values are: + - samsung,s3c2410-wakeup-eint: represents wakeup interrupt controller + found on Samsung S3C24xx SoCs except S3C2412 and S3C2413, + - samsung,s3c2412-wakeup-eint: represents wakeup interrupt controller + found on Samsung S3C2412 and S3C2413 SoCs, + - samsung,s3c64xx-wakeup-eint: represents wakeup interrupt controller + found on Samsung S3C64xx SoCs, + - samsung,s5pv210-wakeup-eint: represents wakeup interrupt controller + found on Samsung S5Pv210 SoCs, + - samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller + found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs. + - samsung,exynos7-wakeup-eint: represents wakeup interrupt controller + found on Samsung Exynos7 SoC. + - interrupts: interrupt used by multiplexed wakeup interrupts. + + In addition, following properties must be present in node of every bank + of pins supporting wake-up interrupts: + + - interrupt-controller: identifies the node as interrupt-parent. + - #interrupt-cells: the value of this property should be 2 + - First Cell: represents the external wakeup interrupt number local to + the external wakeup interrupt space of the controller. + - Second Cell: flags to identify the type of the interrupt + - 1 = rising edge triggered + - 2 = falling edge triggered + - 3 = rising and falling edge triggered + - 4 = high level triggered + - 8 = low level triggered + + Node of every bank of pins supporting direct wake-up interrupts (without + multiplexing) must contain following properties: + + - interrupts: interrupts of the interrupt parent which are used for external + wakeup interrupts from pins of the bank, must contain interrupts for all + pins of the bank. + +Aliases: + +All the pin controller nodes should be represented in the aliases node using +the following format 'pinctrl{n}' where n is a unique number for the alias. + +Aliases for controllers compatible with "samsung,exynos7-pinctrl": +- pinctrl0: pin controller of ALIVE block, +- pinctrl1: pin controller of BUS0 block, +- pinctrl2: pin controller of NFC block, +- pinctrl3: pin controller of TOUCH block, +- pinctrl4: pin controller of FF block, +- pinctrl5: pin controller of ESE block, +- pinctrl6: pin controller of FSYS0 block, +- pinctrl7: pin controller of FSYS1 block, +- pinctrl8: pin controller of BUS1 block, +- pinctrl9: pin controller of AUDIO block, + +Example: A pin-controller node with pin banks: + + pinctrl_0: pinctrl@11400000 { + compatible = "samsung,exynos4210-pinctrl"; + reg = <0x11400000 0x1000>; + interrupts = <0 47 0>; + + /* ... */ + + /* Pin bank without external interrupts */ + gpy0: gpy0 { + gpio-controller; + #gpio-cells = <2>; + }; + + /* ... */ + + /* Pin bank with external GPIO or muxed wake-up interrupts */ + gpj0: gpj0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ... */ + + /* Pin bank with external direct wake-up interrupts */ + gpx0: gpx0 { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + interrupt-parent = <&gic>; + interrupts = <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>, + <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>; + #interrupt-cells = <2>; + }; + + /* ... */ + }; + +Example 1: A pin-controller node with pin groups. + + #include + + pinctrl_0: pinctrl@11400000 { + compatible = "samsung,exynos4210-pinctrl"; + reg = <0x11400000 0x1000>; + interrupts = <0 47 0>; + + /* ... */ + + uart0_data: uart0-data { + samsung,pins = "gpa0-0", "gpa0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart0_fctl: uart0-fctl { + samsung,pins = "gpa0-2", "gpa0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart1_data: uart1-data { + samsung,pins = "gpa0-4", "gpa0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart1_fctl: uart1-fctl { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + i2c2_bus: i2c2-bus { + samsung,pins = "gpa0-6", "gpa0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd4_bus8: sd4-bus-width8 { + part-1 { + samsung,pins = "gpk0-3", "gpk0-4", + "gpk0-5", "gpk0-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + part-2 { + samsung,pins = "gpk1-3", "gpk1-4", + "gpk1-5", "gpk1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + }; + }; + +Example 2: A pin-controller node with external wakeup interrupt controller node. + + pinctrl_1: pinctrl@11000000 { + compatible = "samsung,exynos4210-pinctrl"; + reg = <0x11000000 0x1000>; + interrupts = <0 46 0> + + /* ... */ + + wakeup-interrupt-controller { + compatible = "samsung,exynos4210-wakeup-eint"; + interrupt-parent = <&gic>; + interrupts = <0 32 0>; + }; + }; + +Example 3: A uart client node that supports 'default' and 'flow-control' states. + + uart@13800000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x13800000 0x100>; + interrupts = <0 52 0>; + pinctrl-names = "default", "flow-control; + pinctrl-0 = <&uart0_data>; + pinctrl-1 = <&uart0_data &uart0_fctl>; + }; + +Example 4: Set up the default pin state for uart controller. + + static int s3c24xx_serial_probe(struct platform_device *pdev) { + struct pinctrl *pinctrl; + + /* ... */ + + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + } + +Example 5: A display port client node that supports 'default' pinctrl state + and gpio binding. + + display-port-controller { + /* ... */ + + samsung,hpd-gpio = <&gpx2 6 0>; + pinctrl-names = "default"; + pinctrl-0 = <&dp_hpd>; + }; + +Example 6: Request the gpio for display port controller + + static int exynos_dp_probe(struct platform_device *pdev) + { + int hpd_gpio, ret; + struct device *dev = &pdev->dev; + struct device_node *dp_node = dev->of_node; + + /* ... */ + + hpd_gpio = of_get_named_gpio(dp_node, "samsung,hpd-gpio", 0); + + /* ... */ + + ret = devm_gpio_request_one(&pdev->dev, hpd_gpio, GPIOF_IN, + "hpd_gpio"); + /* ... */ + } diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/socionext,uniphier-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/socionext,uniphier-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..8173b12138ad78b32594f46a07539a650078f9ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/socionext,uniphier-pinctrl.txt @@ -0,0 +1,27 @@ +UniPhier SoCs pin controller + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-pinctrl" - for LD4 SoC + "socionext,uniphier-pro4-pinctrl" - for Pro4 SoC + "socionext,uniphier-sld8-pinctrl" - for sLD8 SoC + "socionext,uniphier-pro5-pinctrl" - for Pro5 SoC + "socionext,uniphier-pxs2-pinctrl" - for PXs2 SoC + "socionext,uniphier-ld6b-pinctrl" - for LD6b SoC + "socionext,uniphier-ld11-pinctrl" - for LD11 SoC + "socionext,uniphier-ld20-pinctrl" - for LD20 SoC + "socionext,uniphier-pxs3-pinctrl" - for PXs3 SoC + +Note: +The UniPhier pinctrl should be a subnode of a "syscon" compatible node. + +Example: + soc-glue@5f800000 { + compatible = "socionext,uniphier-pro4-soc-glue", + "simple-mfd", "syscon"; + reg = <0x5f800000 0x2000>; + + pinctrl: pinctrl { + compatible = "socionext,uniphier-pro4-pinctrl"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/sprd,pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/sprd,pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..b1cea7a3a0715df1c954779331bbe94926c31946 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/sprd,pinctrl.txt @@ -0,0 +1,83 @@ +* Spreadtrum Pin Controller + +The Spreadtrum pin controller are organized in 3 blocks (types). + +The first block comprises some global control registers, and each +register contains several bit fields with one bit or several bits +to configure for some global common configuration, such as domain +pad driving level, system control select and so on ("domain pad +driving level": One pin can output 3.0v or 1.8v, depending on the +related domain pad driving selection, if the related domain pad +slect 3.0v, then the pin can output 3.0v. "system control" is used +to choose one function (like: UART0) for which system, since we +have several systems (AP/CP/CM4) on one SoC.). + +There are too much various configuration that we can not list all +of them, so we can not make every Spreadtrum-special configuration +as one generic configuration, and maybe it will add more strange +global configuration in future. Then we add one "sprd,control" to +set these various global control configuration, and we need use +magic number for this property. + +Moreover we recognise every fields comprising one bit or several +bits in one global control register as one pin, thus we should +record every pin's bit offset, bit width and register offset to +configure this field (pin). + +The second block comprises some common registers which have unified +register definition, and each register described one pin is used +to configure the pin sleep mode, function select and sleep related +configuration. + +Now we have 4 systems for sleep mode on SC9860 SoC: AP system, +PUBCP system, TGLDSP system and AGDSP system. And the pin sleep +related configuration are: +- input-enable +- input-disable +- output-high +- output-low +- bias-pull-up +- bias-pull-down + +In some situation we need set the pin sleep mode and pin sleep related +configuration, to set the pin sleep related configuration automatically +by hardware when the system specified by sleep mode goes into deep +sleep mode. For example, if we set the pin sleep mode as PUBCP_SLEEP +and set the pin sleep related configuration as "input-enable", which +means when PUBCP system goes into deep sleep mode, this pin will be set +input enable automatically. + +Moreover we can not use the "sleep" state, since some systems (like: +PUBCP system) do not run linux kernel OS (only AP system run linux +kernel on SC9860 platform), then we can not select "sleep" state +when the PUBCP system goes into deep sleep mode. Thus we introduce +"sprd,sleep-mode" property to set pin sleep mode. + +The last block comprises some misc registers which also have unified +register definition, and each register described one pin is used to +configure drive strength, pull up/down and so on. Especially for pull +up, we have two kind pull up resistor: 20K and 4.7K. + +Required properties for Spreadtrum pin controller: +- compatible: "sprd,-pinctrl" + Please refer to each sprd,-pinctrl.txt binding doc for supported SoCs. +- reg: The register address of pin controller device. +- pins : An array of pin names. + +Optional properties: +- function: Specified the function name. +- drive-strength: Drive strength in mA. +- input-schmitt-disable: Enable schmitt-trigger mode. +- input-schmitt-enable: Disable schmitt-trigger mode. +- bias-disable: Disable pin bias. +- bias-pull-down: Pull down on pin. +- bias-pull-up: Pull up on pin. +- input-enable: Enable pin input. +- input-disable: Enable pin output. +- output-high: Set the pin as an output level high. +- output-low: Set the pin as an output level low. +- sleep-hardware-state: Indicate these configs in this state are sleep related. +- sprd,control: Control values referring to databook for global control pins. +- sprd,sleep-mode: Sleep mode selection. + +Please refer to each sprd,-pinctrl.txt binding doc for supported values. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/sprd,sc9860-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/sprd,sc9860-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a628333d52f2466caaa4ebe0d7823040396e526 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/sprd,sc9860-pinctrl.txt @@ -0,0 +1,70 @@ +* Spreadtrum SC9860 Pin Controller + +Please refer to sprd,pinctrl.txt in this directory for common binding part +and usage. + +Required properties: +- compatible: Must be "sprd,sc9860-pinctrl". +- reg: The register address of pin controller device. +- pins : An array of strings, each string containing the name of a pin. + +Optional properties: +- function: A string containing the name of the function, values must be + one of: "func1", "func2", "func3" and "func4". +- drive-strength: Drive strength in mA. Supported values: 2, 4, 6, 8, 10, + 12, 14, 16, 20, 21, 24, 25, 27, 29, 31 and 33. +- input-schmitt-disable: Enable schmitt-trigger mode. +- input-schmitt-enable: Disable schmitt-trigger mode. +- bias-disable: Disable pin bias. +- bias-pull-down: Pull down on pin. +- bias-pull-up: Pull up on pin. Supported values: 20000 for pull-up resistor + is 20K and 4700 for pull-up resistor is 4.7K. +- input-enable: Enable pin input. +- input-disable: Enable pin output. +- output-high: Set the pin as an output level high. +- output-low: Set the pin as an output level low. +- sleep-hardware-state: Indicate these configs in this state are sleep related. +- sprd,control: Control values referring to databook for global control pins. +- sprd,sleep-mode: Choose the pin sleep mode, and supported values are: + AP_SLEEP, PUBCP_SLEEP, TGLDSP_SLEEP and AGDSP_SLEEP. + +Pin sleep mode definition: +enum pin_sleep_mode { + AP_SLEEP = BIT(0), + PUBCP_SLEEP = BIT(1), + TGLDSP_SLEEP = BIT(2), + AGDSP_SLEEP = BIT(3), +}; + +Example: +pin_controller: pinctrl@402a0000 { + compatible = "sprd,sc9860-pinctrl"; + reg = <0x402a0000 0x10000>; + + grp1: sd0 { + pins = "SC9860_VIO_SD2_IRTE", "SC9860_VIO_SD0_IRTE"; + sprd,control = <0x1>; + }; + + grp2: rfctl_33 { + pins = "SC9860_RFCTL33"; + function = "func2"; + sprd,sleep-mode = ; + grp2_sleep_mode: rfctl_33_sleep { + pins = "SC9860_RFCTL33"; + sleep-hardware-state; + output-low; + } + }; + + grp3: rfctl_misc_20 { + pins = "SC9860_RFCTL20_MISC"; + drive-strength = <10>; + bias-pull-up = <4700>; + grp3_sleep_mode: rfctl_misc_sleep { + pins = "SC9860_RFCTL20_MISC"; + sleep-hardware-state; + bias-pull-up; + } + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/st,stm32-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/st,stm32-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef4f2ff4a1aae3390cde17fd7d0a48063330a03a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/st,stm32-pinctrl.txt @@ -0,0 +1,205 @@ +* STM32 GPIO and Pin Mux/Config controller + +STMicroelectronics's STM32 MCUs intregrate a GPIO and Pin mux/config hardware +controller. It controls the input/output settings on the available pins and +also provides ability to multiplex and configure the output of various on-chip +controllers onto these pads. + +Pin controller node: +Required properies: + - compatible: value should be one of the following: + "st,stm32f429-pinctrl" + "st,stm32f469-pinctrl" + "st,stm32f746-pinctrl" + "st,stm32f769-pinctrl" + "st,stm32h743-pinctrl" + "st,stm32mp157-pinctrl" + "st,stm32mp157-z-pinctrl" + - #address-cells: The value of this property must be 1 + - #size-cells : The value of this property must be 1 + - ranges : defines mapping between pin controller node (parent) to + gpio-bank node (children). + - pins-are-numbered: Specify the subnodes are using numbered pinmux to + specify pins. + +GPIO controller/bank node: +Required properties: + - gpio-controller : Indicates this device is a GPIO controller + - #gpio-cells : Should be two. + The first cell is the pin number + The second one is the polarity: + - 0 for active high + - 1 for active low + - reg : The gpio address range, relative to the pinctrl range + - clocks : clock that drives this bank + - st,bank-name : Should be a name string for this bank as specified in + the datasheet + +Optional properties: + - reset: : Reference to the reset controller + - st,syscfg: Should be phandle/offset/mask. + -The phandle to the syscon node which includes IRQ mux selection register. + -The offset of the IRQ mux selection register + -The field mask of IRQ mux, needed if different of 0xf. + - gpio-ranges: Define a dedicated mapping between a pin-controller and + a gpio controller. Format is <&phandle a b c> with: + -(phandle): phandle of pin-controller. + -(a): gpio base offset in range. + -(b): pin base offset in range. + -(c): gpio count in range + This entry has to be used either if there are holes inside a bank: + GPIOB0/B1/B2/B14/B15 (see example 2) + or if banks are not contiguous: + GPIOA/B/C/E... + NOTE: If "gpio-ranges" is used for a gpio controller, all gpio-controller + have to use a "gpio-ranges" entry. + More details in Documentation/devicetree/bindings/gpio/gpio.txt. + - st,bank-ioport: should correspond to the EXTI IOport selection (EXTI line + used to select GPIOs as interrupts). + +Example 1: +#include +... + + pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32f429-pinctrl"; + ranges = <0 0x40020000 0x3000>; + pins-are-numbered; + + gpioa: gpio@40020000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + resets = <&reset_ahb1 0>; + st,bank-name = "GPIOA"; + }; + ... + pin-functions nodes follow... + }; + +Example 2: +#include +... + + pinctrl: pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32f429-pinctrl"; + ranges = <0 0x40020000 0x3000>; + pins-are-numbered; + + gpioa: gpio@40020000 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + resets = <&reset_ahb1 0>; + st,bank-name = "GPIOA"; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@40020400 { + gpio-controller; + #gpio-cells = <2>; + reg = <0x0 0x400>; + resets = <&reset_ahb1 0>; + st,bank-name = "GPIOB"; + ngpios = 4; + gpio-ranges = <&pinctrl 0 16 3>, + <&pinctrl 14 30 2>; + }; + + + ... + pin-functions nodes follow... + }; + + +Contents of function subnode node: +---------------------------------- +Subnode format +A pinctrl node should contain at least one subnode representing the +pinctrl group available on the machine. Each subnode will list the +pins it needs, and how they should be configured, with regard to muxer +configuration, pullups, drive, output high/low and output speed. + + node { + pinmux = ; + GENERIC_PINCONFIG; + }; + +Required properties: +- pinmux: integer array, represents gpio pin number and mux setting. + Supported pin number and mux varies for different SoCs, and are defined in + dt-bindings/pinctrl/-pinfunc.h directly. + These defines are calculated as: + ((port * 16 + line) << 8) | function + With: + - port: The gpio port index (PA = 0, PB = 1, ..., PK = 11) + - line: The line offset within the port (PA0 = 0, PA1 = 1, ..., PA15 = 15) + - function: The function number, can be: + * 0 : GPIO + * 1 : Alternate Function 0 + * 2 : Alternate Function 1 + * 3 : Alternate Function 2 + * ... + * 16 : Alternate Function 15 + * 17 : Analog + + To simplify the usage, macro is available to generate "pinmux" field. + This macro is available here: + - include/dt-bindings/pinctrl/stm32-pinfunc.h + + Some examples of using macro: + /* GPIO A9 set as alernate function 2 */ + ... { + pinmux = ; + }; + /* GPIO A9 set as GPIO */ + ... { + pinmux = ; + }; + /* GPIO A9 set as analog */ + ... { + pinmux = ; + }; + +Optional properties: +- GENERIC_PINCONFIG: is the generic pinconfig options to use. + Available options are: + - bias-disable, + - bias-pull-down, + - bias-pull-up, + - drive-push-pull, + - drive-open-drain, + - output-low + - output-high + - slew-rate = , with x being: + < 0 > : Low speed + < 1 > : Medium speed + < 2 > : Fast speed + < 3 > : High speed + +Example: + +pin-controller { +... + usart1_pins_a: usart1@0 { + pins1 { + pinmux = ; + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; + bias-disable; + }; + }; +}; + +&usart1 { + pinctrl-0 = <&usart1_pins_a>; + pinctrl-names = "default"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/ste,abx500.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ste,abx500.txt new file mode 100644 index 0000000000000000000000000000000000000000..87697420439e84ab63c2e88a211baaabbfc05f67 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ste,abx500.txt @@ -0,0 +1,318 @@ +ST Ericsson abx500 pinmux controller + +Required properties: +- compatible: "stericsson,ab8500-gpio", "stericsson,ab8540-gpio", + "stericsson,ab8505-gpio", "stericsson,ab9540-gpio", + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +ST Ericsson's pin configuration nodes use the generic pin multiplexing +and pin configuration bindings, see pinctrl-bindings.txt + +Example board file extract: + +&pinctrl_abx500 { + pinctrl-names = "default"; + pinctrl-0 = <&sysclkreq2_default_mode>, <&sysclkreq3_default_mode>, <&gpio3_default_mode>, <&sysclkreq6_default_mode>, <&pwmout1_default_mode>, <&pwmout2_default_mode>, <&pwmout3_default_mode>, <&adi1_default_mode>, <&dmic12_default_mode>, <&dmic34_default_mode>, <&dmic56_default_mode>, <&sysclkreq5_default_mode>, <&batremn_default_mode>, <&service_default_mode>, <&pwrctrl0_default_mode>, <&pwrctrl1_default_mode>, <&pwmextvibra1_default_mode>, <&pwmextvibra2_default_mode>, <&gpio51_default_mode>, <&gpio52_default_mode>, <&gpio53_default_mode>, <&gpio54_default_mode>, <&pdmclkdat_default_mode>; + + sysclkreq2 { + sysclkreq2_default_mode: sysclkreq2_default { + default_mux { + function = "sysclkreq"; + groups = "sysclkreq2_d_1"; + }; + default_cfg { + pins = "GPIO1"; + bias-disable; + }; + }; + }; + sysclkreq3 { + sysclkreq3_default_mode: sysclkreq3_default { + default_mux { + function = "sysclkreq"; + groups = "sysclkreq3_d_1"; + }; + default_cfg { + pins = "GPIO2"; + output-low; + }; + }; + }; + gpio3 { + gpio3_default_mode: gpio3_default { + default_mux { + function = "gpio"; + groups = "gpio3_a_1"; + }; + default_cfg { + pins = "GPIO3"; + output-low; + }; + }; + }; + sysclkreq6 { + sysclkreq6_default_mode: sysclkreq6_default { + default_mux { + function = "sysclkreq"; + groups = "sysclkreq6_d_1"; + }; + default_cfg { + pins = "GPIO4"; + bias-disable; + }; + }; + }; + pwmout1 { + pwmout1_default_mode: pwmout1_default { + default_mux { + function = "pwmout"; + groups = "pwmout1_d_1"; + }; + default_cfg { + pins = "GPIO14"; + output-low; + }; + }; + }; + pwmout2 { + pwmout2_default_mode: pwmout2_default { + pwmout2_default_mux { + function = "pwmout"; + groups = "pwmout2_d_1"; + }; + pwmout2_default_cfg { + pins = "GPIO15"; + output-low; + }; + }; + }; + pwmout3 { + pwmout3_default_mode: pwmout3_default { + pwmout3_default_mux { + function = "pwmout"; + groups = "pwmout3_d_1"; + }; + pwmout3_default_cfg { + pins = "GPIO16"; + output-low; + }; + }; + }; + adi1 { + + adi1_default_mode: adi1_default { + adi1_default_mux { + function = "adi1"; + groups = "adi1_d_1"; + }; + adi1_default_cfg1 { + pins = "GPIO17","GPIO19","GPIO20"; + bias-disable; + }; + adi1_default_cfg2 { + pins = "GPIO18"; + output-low; + }; + }; + }; + dmic12 { + dmic12_default_mode: dmic12_default { + dmic12_default_mux { + function = "dmic"; + groups = "dmic12_d_1"; + }; + dmic12_default_cfg1 { + pins = "GPIO27"; + output-low; + }; + dmic12_default_cfg2 { + pins = "GPIO28"; + bias-disable; + }; + }; + }; + dmic34 { + dmic34_default_mode: dmic34_default { + dmic34_default_mux { + function = "dmic"; + groups = "dmic34_d_1"; + }; + dmic34_default_cfg1 { + pins = "GPIO29"; + output-low; + }; + dmic34_default_cfg2 { + pins = "GPIO30"; + bias-disable;{ + + }; + }; + }; + dmic56 { + dmic56_default_mode: dmic56_default { + dmic56_default_mux { + function = "dmic"; + groups = "dmic56_d_1"; + }; + dmic56_default_cfg1 { + pins = "GPIO31"; + output-low; + }; + dmic56_default_cfg2 { + pins = "GPIO32"; + bias-disable; + }; + }; + }; + sysclkreq5 { + sysclkreq5_default_mode: sysclkreq5_default { + sysclkreq5_default_mux { + function = "sysclkreq"; + groups = "sysclkreq5_d_1"; + }; + sysclkreq5_default_cfg { + pins = "GPIO42"; + output-low; + }; + }; + }; + batremn { + batremn_default_mode: batremn_default { + batremn_default_mux { + function = "batremn"; + groups = "batremn_d_1"; + }; + batremn_default_cfg { + pins = "GPIO43"; + bias-disable; + }; + }; + }; + service { + service_default_mode: service_default { + service_default_mux { + function = "service"; + groups = "service_d_1"; + }; + service_default_cfg { + pins = "GPIO44"; + bias-disable; + }; + }; + }; + pwrctrl0 { + pwrctrl0_default_mux: pwrctrl0_mux { + pwrctrl0_default_mux { + function = "pwrctrl"; + groups = "pwrctrl0_d_1"; + }; + }; + pwrctrl0_default_mode: pwrctrl0_default { + pwrctrl0_default_cfg { + pins = "GPIO45"; + bias-disable; + }; + }; + }; + pwrctrl1 { + pwrctrl1_default_mux: pwrctrl1_mux { + pwrctrl1_default_mux { + function = "pwrctrl"; + groups = "pwrctrl1_d_1"; + }; + }; + pwrctrl1_default_mode: pwrctrl1_default { + pwrctrl1_default_cfg { + pins = "GPIO46"; + bias-disable; + }; + }; + }; + pwmextvibra1 { + pwmextvibra1_default_mode: pwmextvibra1_default { + pwmextvibra1_default_mux { + function = "pwmextvibra"; + groups = "pwmextvibra1_d_1"; + }; + pwmextvibra1_default_cfg { + pins = "GPIO47"; + bias-disable; + }; + }; + }; + pwmextvibra2 { + pwmextvibra2_default_mode: pwmextvibra2_default { + pwmextvibra2_default_mux { + function = "pwmextvibra"; + groups = "pwmextvibra2_d_1"; + }; + pwmextvibra1_default_cfg { + pins = "GPIO48"; + bias-disable; + }; + }; + }; + gpio51 { + gpio51_default_mode: gpio51_default { + gpio51_default_mux { + function = "gpio"; + groups = "gpio51_a_1"; + }; + gpio51_default_cfg { + pins = "GPIO51"; + output-low; + }; + }; + }; + gpio52 { + gpio52_default_mode: gpio52_default { + gpio52_default_mux { + function = "gpio"; + groups = "gpio52_a_1"; + }; + gpio52_default_cfg { + pins = "GPIO52"; + bias-pull-down; + }; + }; + }; + gpio53 { + gpio53_default_mode: gpio53_default { + gpio53_default_mux { + function = "gpio"; + groups = "gpio53_a_1"; + }; + gpio53_default_cfg { + pins = "GPIO53"; + bias-pull-down; + }; + }; + }; + gpio54 { + gpio54_default_mode: gpio54_default { + gpio54_default_mux { + function = "gpio"; + groups = "gpio54_a_1"; + }; + gpio54_default_cfg { + pins = "GPIO54"; + output-low; + }; + }; + }; + pdmclkdat { + pdmclkdat_default_mode: pdmclkdat_default { + pdmclkdat_default_mux { + function = "pdm"; + groups = "pdmclkdat_d_1"; + }; + pdmclkdat_default_cfg { + pins = "GPIO55", "GPIO56"; + bias-disable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/ste,nomadik.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ste,nomadik.txt new file mode 100644 index 0000000000000000000000000000000000000000..2213802435e00da9be96ae94c3cdad69756f7974 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ste,nomadik.txt @@ -0,0 +1,148 @@ +ST Ericsson Nomadik pinmux controller + +Required properties: +- compatible: "stericsson,db8500-pinctrl", "stericsson,db8540-pinctrl", + "stericsson,stn8815-pinctrl" +- nomadik-gpio-chips: array of phandles to the corresponding GPIO chips + (these have the register ranges used by the pin controller). +- prcm: phandle to the PRCMU managing the back end of this pin controller + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +ST Ericsson's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as input, output, pull up, pull down... + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. The subnodes use the generic +pin multiplexing node layout from the standard pin control bindings +(see pinctrl-bindings.txt): + +Required pin multiplexing subnode properties: +- function: A string containing the name of the function to mux to the + pin or group. +- groups : An array of strings. Each string contains the name of a pin + group that will be combined with the function to form a multiplexing + set-up. + +Required pin configuration subnode properties: +- pins: A string array describing the pins affected by the configuration + in the node. +- ste,config: Handle of pin configuration node + (e.g. ste,config = <&slpm_in_wkup_pdis>) + +- ste,input : <0/1/2> + 0: input with no pull + 1: input with pull up, + 2: input with pull down, + +- ste,output: <0/1/2> + 0: output low, + 1: output high, + 2: output (value is not specified). + +- ste,sleep: <0/1> + 0: sleep mode disable, + 1: sleep mode enable. + +- ste,sleep-input: <0/1/2/3> + 0: sleep input with no pull, + 1: sleep input with pull up, + 2: sleep input with pull down. + 3: sleep input and keep last input configuration (no pull, pull up or pull down). + +- ste,sleep-output: <0/1/2> + 0: sleep output low, + 1: sleep output high, + 2: sleep output (value is not specified). + +- ste,sleep-gpio: <0/1> + 0: disable sleep gpio mode, + 1: enable sleep gpio mode. + +- ste,sleep-wakeup: <0/1> + 0: wake-up detection enabled, + 1: wake-up detection disabled. + +- ste,sleep-pull-disable: <0/1> + 0: GPIO pull-up or pull-down resistor is enabled, when pin is an input, + 1: GPIO pull-up and pull-down resistor are disabled. + +Example board file extract: + + pinctrl@80157000 { + compatible = "stericsson,db8500-pinctrl"; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>; + prcm = <&prcmu>; + + pinctrl-names = "default"; + + slpm_in_wkup_pdis: slpm_in_wkup_pdis { + ste,sleep = <1>; + ste,sleep-input = <3>; + ste,sleep-wakeup = <1>; + ste,sleep-pull-disable = <0>; + }; + + slpm_out_hi_wkup_pdis: slpm_out_hi_wkup_pdis { + ste,sleep = <1>; + ste,sleep-output = <1>; + ste,sleep-wakeup = <1>; + ste,sleep-pull-disable = <0>; + }; + + slpm_out_wkup_pdis: slpm_out_wkup_pdis { + ste,sleep = <1>; + ste,sleep-output = <2>; + ste,sleep-wakeup = <1>; + ste,sleep-pull-disable = <0>; + }; + + uart0 { + uart0_default_mux: uart0_mux { + u0_default_mux { + function = "u0"; + pins = "u0_a_1"; + }; + }; + uart0_default_mode: uart0_default { + uart0_default_cfg1 { + pins = "GPIO0", "GPIO2"; + ste,input = <1>; + }; + + uart0_default_cfg2 { + pins = "GPIO1", "GPIO3"; + ste,output = <1>; + }; + }; + uart0_sleep_mode: uart0_sleep { + uart0_sleep_cfg1 { + pins = "GPIO0", "GPIO2"; + ste,config = <&slpm_in_wkup_pdis>; + }; + uart0_sleep_cfg2 { + pins = "GPIO1"; + ste,config = <&slpm_out_hi_wkup_pdis>; + }; + uart0_sleep_cfg3 { + pins = "GPIO3"; + ste,config = <&slpm_out_wkup_pdis>; + }; + }; + }; + }; + + uart@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 0x4>; + + pinctrl-names = "default","sleep"; + pinctrl-0 = <&uart0_default_mux>, <&uart0_default_mode>; + pinctrl-1 = <&uart0_sleep_mode>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,da850-pupd.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,da850-pupd.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f2980567c9f713db7f73fccdf63dc25b6deb11c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,da850-pupd.txt @@ -0,0 +1,55 @@ +* Pin configuration for TI DA850/OMAP-L138/AM18x + +These SoCs have a separate controller for setting bias (internal pullup/down). +Bias can only be selected for groups rather than individual pins. + +Required Properties: + + - compatible: Must be "ti,da850-pupd" + - reg: Base address and length of the memory resource used by the pullup/down + controller hardware module. + +The controller node also acts as a container for pin group configuration nodes. +The names of these groups are ignored. + +Pin Group Node Properties: + +- groups: An array of strings, each string containing the name of a pin group. + Valid names are "cp0".."cp31". + +The pin configuration parameters use the generic pinconf bindings defined in +pinctrl-bindings.txt in this directory. The supported parameters are +bias-disable, bias-pull-up, bias-pull-down. + + +Example +------- + +In common dtsi file: + + pinconf: pin-controller@22c00c { + compatible = "ti,da850-pupd"; + reg = <0x22c00c 0x8>; + }; + +In board-specific file: + + &pinconf { + pinctrl-0 = <&pinconf_bias_groups>; + pinctrl-names = "default"; + + pinconf_bias_groups: bias-groups { + pull-up { + groups = "cp30", "cp31"; + bias-pull-up; + }; + pull-down { + groups = "cp29", "cp28"; + bias-pull-down; + }; + disable { + groups = "cp27", "cp26"; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,iodelay.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,iodelay.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3ed1232b6a399e8c4c4e83d94ee01e8edad8eec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,iodelay.txt @@ -0,0 +1,47 @@ +* Pin configuration for TI IODELAY controller + +TI dra7 based SoCs such as am57xx have a controller for setting the IO delay +for each pin. For most part the IO delay values are programmed by the bootloader, +but some pins need to be configured dynamically by the kernel such as the +MMC pins. + +Required Properties: + + - compatible: Must be "ti,dra7-iodelay" + - reg: Base address and length of the memory resource used + - #address-cells: Number of address cells + - #size-cells: Size of cells + - #pinctrl-cells: Number of pinctrl cells, must be 2. See also + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Example +------- + +In the SoC specific dtsi file: + + dra7_iodelay_core: padconf@4844a000 { + compatible = "ti,dra7-iodelay"; + reg = <0x4844a000 0x0d1c>; + #address-cells = <1>; + #size-cells = <0>; + #pinctrl-cells = <2>; + }; + +In board-specific file: + +&dra7_iodelay_core { + mmc2_iodelay_3v3_conf: mmc2_iodelay_3v3_conf { + pinctrl-pin-array = < + 0x18c A_DELAY_PS(0) G_DELAY_PS(120) /* CFG_GPMC_A19_IN */ + 0x1a4 A_DELAY_PS(265) G_DELAY_PS(360) /* CFG_GPMC_A20_IN */ + 0x1b0 A_DELAY_PS(0) G_DELAY_PS(120) /* CFG_GPMC_A21_IN */ + 0x1bc A_DELAY_PS(0) G_DELAY_PS(120) /* CFG_GPMC_A22_IN */ + 0x1c8 A_DELAY_PS(287) G_DELAY_PS(420) /* CFG_GPMC_A23_IN */ + 0x1d4 A_DELAY_PS(144) G_DELAY_PS(240) /* CFG_GPMC_A24_IN */ + 0x1e0 A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_A25_IN */ + 0x1ec A_DELAY_PS(120) G_DELAY_PS(0) /* CFG_GPMC_A26_IN */ + 0x1f8 A_DELAY_PS(120) G_DELAY_PS(180) /* CFG_GPMC_A27_IN */ + 0x360 A_DELAY_PS(0) G_DELAY_PS(0) /* CFG_GPMC_CS1_IN */ + >; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,omap-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,omap-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..88c80273da910c0ef226313aee7acf3cfab6a2b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/ti,omap-pinctrl.txt @@ -0,0 +1,13 @@ +OMAP Pinctrl definitions + +Required properties: +- compatible : Should be one of: + "ti,omap2420-padconf" - OMAP2420 compatible pinctrl + "ti,omap2430-padconf" - OMAP2430 compatible pinctrl + "ti,omap3-padconf" - OMAP3 compatible pinctrl + "ti,omap4-padconf" - OMAP4 compatible pinctrl + "ti,omap5-padconf" - OMAP5 compatible pinctrl + "ti,dra7-padconf" - DRA7 compatible pinctrl + "ti,am437-padconf" - AM437x compatible pinctrl + +See Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt for further details. diff --git a/arch/arm64/boot/dts/vendor/bindings/pinctrl/xlnx,zynq-pinctrl.txt b/arch/arm64/boot/dts/vendor/bindings/pinctrl/xlnx,zynq-pinctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..f488b0f7740638b7ff745a594d2ae7e266b294e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pinctrl/xlnx,zynq-pinctrl.txt @@ -0,0 +1,105 @@ + Binding for Xilinx Zynq Pinctrl + +Required properties: +- compatible: "xlnx,zynq-pinctrl" +- syscon: phandle to SLCR +- reg: Offset and length of pinctrl space in SLCR + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +Zynq's pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin, a group, or a list of pins or groups. This configuration can include the +mux function to select on those pin(s)/group(s), and various pin configuration +parameters, such as pull-up, slew rate, etc. + +Each configuration node can consist of multiple nodes describing the pinmux and +pinconf options. Those nodes can be pinmux nodes or pinconf nodes. + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Required properties for pinmux nodes are: + - groups: A list of pinmux groups. + - function: The name of a pinmux function to activate for the specified set + of groups. + +Required properties for configuration nodes: +One of: + - pins: a list of pin names + - groups: A list of pinmux groups. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinmux subnode: + groups, function + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pinconf subnode: + groups, pins, bias-disable, bias-high-impedance, bias-pull-up, slew-rate, + low-power-disable, low-power-enable + + Valid arguments for 'slew-rate' are '0' and '1' to select between slow and fast + respectively. + + Valid values for groups are: + ethernet0_0_grp, ethernet1_0_grp, mdio0_0_grp, mdio1_0_grp, + qspi0_0_grp, qspi1_0_grp, qspi_fbclk, qspi_cs1_grp, spi0_0_grp - spi0_2_grp, + spi0_X_ssY (X=0..2, Y=0..2), spi1_0_grp - spi1_3_grp, + spi1_X_ssY (X=0..3, Y=0..2), sdio0_0_grp - sdio0_2_grp, + sdio1_0_grp - sdio1_3_grp, sdio0_emio_wp, sdio0_emio_cd, sdio1_emio_wp, + sdio1_emio_cd, smc0_nor, smc0_nor_cs1_grp, smc0_nor_addr25_grp, smc0_nand, + can0_0_grp - can0_10_grp, can1_0_grp - can1_11_grp, uart0_0_grp - uart0_10_grp, + uart1_0_grp - uart1_11_grp, i2c0_0_grp - i2c0_10_grp, i2c1_0_grp - i2c1_10_grp, + ttc0_0_grp - ttc0_2_grp, ttc1_0_grp - ttc1_2_grp, swdt0_0_grp - swdt0_4_grp, + gpio0_0_grp - gpio0_53_grp, usb0_0_grp, usb1_0_grp + + Valid values for pins are: + MIO0 - MIO53 + + Valid values for function are: + ethernet0, ethernet1, mdio0, mdio1, qspi0, qspi1, qspi_fbclk, qspi_cs1, + spi0, spi0_ss, spi1, spi1_ss, sdio0, sdio0_pc, sdio0_cd, sdio0_wp, + sdio1, sdio1_pc, sdio1_cd, sdio1_wp, + smc0_nor, smc0_nor_cs1, smc0_nor_addr25, smc0_nand, can0, can1, uart0, uart1, + i2c0, i2c1, ttc0, ttc1, swdt0, gpio0, usb0, usb1 + +The following driver-specific properties as defined here are valid to specify in +a pin configuration subnode: + - io-standard: Configure the pin to use the selected IO standard according to + this mapping: + 1: LVCMOS18 + 2: LVCMOS25 + 3: LVCMOS33 + 4: HSTL + +Example: + pinctrl0: pinctrl@700 { + compatible = "xlnx,pinctrl-zynq"; + reg = <0x700 0x200>; + syscon = <&slcr>; + + pinctrl_uart1_default: uart1-default { + mux { + groups = "uart1_10_grp"; + function = "uart1"; + }; + + conf { + groups = "uart1_10_grp"; + slew-rate = <0>; + io-standard = <1>; + }; + + conf-rx { + pins = "MIO49"; + bias-high-impedance; + }; + + conf-tx { + pins = "MIO48"; + bias-disable; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa.txt new file mode 100644 index 0000000000000000000000000000000000000000..a43890f8ca3d2437beeceaff47018beea22ed761 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa.txt @@ -0,0 +1,222 @@ +Qualcomm technologies inc. Internet Packet Accelerator + +Internet Packet Accelerator (IPA) is a programmable protocol +processor HW block. It is designed to support generic HW processing +of UL/DL IP packets for various use cases independent of radio technology. + +Required properties: + +IPA node: + +- compatible : "qcom,ipa" +- reg: Specifies the base physical addresses and the sizes of the IPA + registers. +- reg-names: "ipa-base" - string to identify the IPA CORE base registers. + "bam-base" - string to identify the IPA BAM base registers. + "a2-bam-base" - string to identify the A2 BAM base registers. +- interrupts: Specifies the interrupt associated with IPA. +- interrupt-names: "ipa-irq" - string to identify the IPA core interrupt. + "bam-irq" - string to identify the IPA BAM interrupt. + "a2-bam-irq" - string to identify the A2 BAM interrupt. +- qcom,ipa-hw-ver: Specifies the IPA hardware version. + +Optional: + +- qcom,lan-rx-napi: Enable NAPI in the LAN RX data path. +- qcom,wan-rx-ring-size: size of WAN rx ring, default is 192 +- qcom,lan-rx-ring-size: size of LAN rx ring, default is 192 +- qcom,arm-smmu: SMMU is present and ARM SMMU driver is used +- qcom,msm-smmu: SMMU is present and QSMMU driver is used +- qcom,iommu-dma = "fastmap": Context flag to set SMMU to fastpath mode +- ipa_smmu_ap: AP general purpose SMMU device + compatible "qcom,ipa-smmu-ap-cb" +- ipa_smmu_wlan: WDI SMMU device + compatible "qcom,ipa-smmu-wlan-cb" +- ipa_smmu_uc: uc SMMU device + compatible "qcom,ipa-smmu-uc-cb" +- ipa_smmu_11ad: 11AD SMMU device + compatible "qcom,ipa-smmu-11ad-cb" +- qcom,shared-cb: context bank page tables sharing with other hw +- qcom,use-ipa-tethering-bridge: determine if tethering bridge will be used +- qcom,use-ipa-in-mhi-mode: Boolean context flag to indicate whether + device booting in MHI config or not. +- qcom,ee: which EE is assigned to (non-secure) APPS from IPA-BAM POV. This +is a number +- qcom,ipa-hw-mode: IPA hardware mode - Normal, Virtual memory allocation, +memory allocation over a PCIe bridge +-qcom,platform-type: MDM platform, MSM platform or APQ platform +- qcom,msm-bus,name: String representing the client-name +- qcom,msm-bus,num-cases: Total number of usecases +- qcom,msm-bus,active-only: Boolean context flag for requests in active or + dual (active & sleep) contex +- qcom,msm-bus,num-paths: Total number of master-slave pairs +- qcom,msm-bus,vectors-KBps: Arrays of unsigned integers representing: + master-id, slave-id, arbitrated bandwidth + in KBps, instantaneous bandwidth in KBps +- qcom,ipa-bam-remote-mode: Boolean context flag to determine if ipa bam + is in remote mode. +- qcom,modem-cfg-emb-pipe-flt: Boolean context flag to determine if modem + configures embedded pipe filtering rules +- qcom,skip-uc-pipe-reset: Boolean context flag to indicate whether + a pipe reset via the IPA uC is required +- qcom,ipa-wdi2: Boolean context flag to indicate whether + using wdi-2.0 or not +- qcom,ipa-wdi3-over-gsi: Boolean context flag to indicate whether + using wdi-3.0 or not +- qcom,bandwidth-vote-for-ipa: Boolean context flag to indicate whether + ipa clock voting is done by bandwidth + voting via msm-bus-scale driver or not +- qcom,use-64-bit-dma-mask: Boolean context flag to indicate whether + using 64bit dma mask or not +- qcom,use-dma-zone: Boolean context flag to indicate whether memory + allocations controlled by IPA driver that do not + specify a struct device * should use GFP_DMA to + workaround IPA HW limitations +- qcom,use-rg10-limitation-mitigation: Boolean context flag to activate + the mitigation to register group 10 + AP access limitation +- qcom,do-not-use-ch-gsi-20: Boolean context flag to activate + software workaround for IPA limitation + to not use GSI physical channel 20 +- qcom,tethered-flow-control: Boolean context flag to indicate whether + apps based flow control is needed for tethered + call. +- qcom,rx-polling-sleep-ms: Receive Polling Timeout in millisecond, + default is 1 millisecond. +- qcom,ipa-polling-iteration: IPA Polling Iteration Count,default is 40. +- qcom,mhi-event-ring-id-limits: Two elements property. Start and End limits + for MHI event rings ids. +- qcom,ipa-tz-unlock-reg: Register start addresses and ranges which + need to be unlocked by TZ. +- qcom,ipa-uc-monitor-holb: Boolean context flag to indicate whether + monitoring of holb via IPA uc is required. +-qcom,ipa-fltrt-not-hashable: Boolean context flag to indicate filter/route rules + hashing not supported. +- qcom,wlan-ce-db-over-pcie: Boolean context flag to represent WLAN CE DB + over pcie bus or not. +- qcom,ipa-wdi2_over_gsi: Boolean context flag to indicate WDI2 offload over GSI + supported or not. +- qcom,register-collection-on-crash: Boolean that controls IPA/GSI register + collection upon system crash (i.e. SSR). +- qcom,testbus-collection-on-crash: Boolean that controls testbus register + collection upon system crash. +- qcom,non-tn-collection-on-crash: Boolean to control a certain subset of IPA/GSI + register collection relative to an SSR. Accessing + these registers can cause stalling, hence this + control. +- qcom,entire-ipa-block-size: Complete size of the ipa block in which all + registers, collected upon crash, reside. +- qcom,secure-debug-check-action: Drives secure memory debug check. Three values allowed: + 0 (use scm call), + 1 (override scm call as though it returned true), and + 2 (override scm call as though it returned false) +- qcom,ram-collection-on-crash: Boolean that controls IPA/GSI memory + collection upon system crash +- qcom,skip-ieob-mask-wa: Boolean context flag to indicate ieob mask workaround + supported or not. +- qcom,use-gsi-ipa-fw: string to indicate which GSI firmware file to use. +- qcom,use-uc-ipa-fw: string to indicate which uC firmware file to use. + +Optional properties: +-qcom,ipa-pipe-mem: Specifies the base physical address and the + size of the IPA pipe memory region. + Pipe memory is a feature which may be supported by the + target (HW platform). The Driver support using pipe + memory instead of system memory. In case this property + will not appear in the IPA DTS entry, the driver will + use system memory. +- clocks: This property shall provide a list of entries each of which + contains a phandle to clock controller device and a macro that is + the clock's name in hardware.This should be "clock_rpm" as clock + controller phandle and "clk_ipa_clk" as macro for "iface_clk" +- clock-names: This property shall contain the clock input names used + by driver in same order as the clocks property.This should be "iface_clk" +- emulator-bar0-offset: Specifies the offset, within PCIe BAR0, where + IPA/GSI programmable registers reside. This property is used only + with the IPA/GSI emulation system, which is connected to and + communicated with via PCIe. + +IPA SMMU sub nodes + +-compatible: "qcom,ipa-smmu-ap-cb" - represents the AP context bank. + +-compatible: "qcom,ipa-smmu-wlan-cb" - represents IPA WLAN context bank. + +-compatible: "qcom,ipa-smmu-uc-cb" - represents IPA uC context bank (for uC + offload scenarios). + +- qcom,iommu-dma = "bypass": Context flag to set SMMU to S1 bypass. + +- dma-coherent: Indicate using dma-coherent or not in SMMU block + +- iommus : the phandle and stream IDs for the SMMU used by this root + +- qcom,iommu-dma-addr-pool: specifies the start address and size of iova space. + +- qcom,additional-mapping: specifies any addtional mapping needed for this + context bank. The format is + +IPA SMP2P sub nodes + +-compatible: "qcom,smp2p-map-ipa-1-out" - represents the out smp2p from + ipa driver to modem. + +-compatible: "qcom,smp2p-map-ipa-1-in" - represents the in smp2p to + ipa driver from modem. + + +Example: + +qcom,ipa@fd4c0000 { + compatible = "qcom,ipa"; + reg = <0xfd4c0000 0x26000>, + <0xfd4c4000 0x14818>; + <0xfc834000 0x7000>; + reg-names = "ipa-base", "bam-base"; "a2-bam-base"; + interrupts = <0 252 0>, + <0 253 0>; + <0 29 1>; + interrupt-names = "ipa-irq", "bam-irq"; "a2-bam-irq"; + qcom,ipa-hw-ver = <1>; + + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <90 512 0 0>, <90 585 0 0>, /* No vote */ + <90 512 100000 800000>, <90 585 100000 800000>, /* SVS */ + <90 512 100000 1200000>, <90 585 100000 1200000>; /* PERF */ + qcom,bus-vector-names = "MIN", "SVS", "PERF"; + + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x720>; + qcom,iommu-dma-addr-pool = <0x20000000 0x40000000>; + qcom,additional-mapping = + /* modem tables in IMEM */ + <0x146bd000 0x146bd000 0x2000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x721>; + qcom,additional-mapping = + /* ipa-uc ram */ + <0x1e60000 0x1e60000 0x80000>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x722>; + qcom,iommu-dma-addr-pool = <0x40000000 0x20000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa_mhi_proxy.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa_mhi_proxy.txt new file mode 100644 index 0000000000000000000000000000000000000000..d3483d81572c3052d86228259a8ca44a18928463 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa_mhi_proxy.txt @@ -0,0 +1,27 @@ +* Qualcomm Technologies, Inc. IPA MHI proxy driver module + +This module enables modem to modem communication using IPA +and MHI. + +Required properties: +- compatible: Must be "qcom,ipa-mhi-proxy" +- qcom,mhi-chdb-base: MHI channel doorbell base address in MMIO space +- qcom,mhi-erdb-base: MHI event doorbell base address in MMIO space + +Optional: +- qcom,ctrl-iova: Pair of start address and size of the IOVA space + dedicated for MHI control structures + (such as transfer rings and event rings). + If not present, SMMU S1 is considered to be in bypass mode. +- qcom,data-iova: Pair of start address and size of the IOVA space + dedicated for MHI data buffers. + If not present, SMMU S1 is considered to be in bypass mode. + +Example: + imp: qcom,ipa-mhi-proxy { + compatible = "qcom,ipa-mhi-proxy"; + qcom,ctrl-iova = <0x00010000 0x0FFF0000>; + qcom,data-iova = <0x10000000 0x0FFFFFFF>; + qcom,mhi-chdb-base = <0x40300300>; + qcom,mhi-erdb-base = <0x40300700>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa_mpm.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa_mpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..a32b320282aa6cbe910e038e3910ebe7eed285df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/ipa_mpm.txt @@ -0,0 +1,23 @@ +* Qualcomm Technologies, Inc. IPA MHI Prime Manager driver module + +This module enables IPA Modem to IPA APQ communication using +MHI Prime. + +Required properties: +- compatible: Must be "qcom,ipa-mpm". +- qcom,mhi-chdb-base: MHI channel doorbell base address in MMIO space. +- qcom,mhi-erdb-base: MHI event doorbell base address in MMIO space. + +Optional: +- qcom,iova-mapping: Start address and size of the carved IOVA space + dedicated for MHI control structures + (such as transfer rings, event rings, doorbells). + If not present, SMMU S1 is considered to be in bypass mode. + +Example: + ipa_mpm: qcom,ipa-mpm { + compatible = "qcom,ipa-mpm"; + qcom,mhi-chdb-base = <0x40300300>; + qcom,mhi-erdb-base = <0x40300700>; + qcom,iova-mapping = <0x10000000 0x1FFFFFFF>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_demux.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_demux.txt new file mode 100644 index 0000000000000000000000000000000000000000..c192a43d58f94418fa78a96569ff0d54793db15c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_demux.txt @@ -0,0 +1,13 @@ +* Demux + +Demux is responsible for demuxing the transport stream contents +to respective elementary streams + +Required properties: +- compatible : Should be "qcom,demux" + +Example: + + demux { + compatible = "qcom,demux"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_gsi.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_gsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b297249554f0417858a7466d5873743d475204e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_gsi.txt @@ -0,0 +1,15 @@ +* Qualcomm Technologies, Inc. GSI driver module + +GSI is a HW accelerator that supports Generic SW Interfaces (GSI) which are +peripheral specific (IPA in this case). +GSI translates SW transfer elements (TRE) into TLV transactions which are +then processed by the peripheral. +This Driver configures and communicates with GSI HW. + +Required properties: +- compatible: Must be "qcom,msm_gsi" + +Example: + qcom,msm-gsi { + compatible = "qcom,msm_gsi"; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_tspp.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_tspp.txt new file mode 100644 index 0000000000000000000000000000000000000000..70377b4a9551bb43a3cd367fde1f492ba111dea9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/msm_tspp.txt @@ -0,0 +1,83 @@ +* TSPP ( QTI Transport Stream Packet Processor ) + +Hardware driver for QTI TSIF 12seg wrapper core, which consists of a TSPP, a +BAM (Bus access manager, used for DMA) and two TSIF inputs. + +The TSPP driver is responsible for: + - TSPP/TSIF hardware configuration (using SPS driver to configure BAM hardware) + - TSIF GPIO/Clocks configuration + - Memory resource management + - Handling TSIF/TSPP interrupts and BAM events + - TSPP Power management + +Required properties: +- compatible : Should be "qcom,msm_tspp" +- reg : Specifies the base physical addresses and sizes of TSIF, TSPP & BAM registers. +- reg-names : Specifies the register names of TSIF, TSPP & BAM base registers. +- interrupts : Specifies the interrupts associated with TSIF 12 seg core. +- interrupt-names: Specifies interrupt names for TSIF, TSPP & BAM interrupts. +- clock-names: Specifies the clock names used for interface & reference clocks. +- clocks: GCC_TSIF_AHB_CLK clock for interface clock & GCC_TSIF_REF_CLK clock for reference clock. +- qcom, msm_bus,name: Should be "tsif" +- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling +- qcom, msm_bus,num_paths: The paths for source and destination ports +- qcom, msm_bus,vectors: Vectors for bus topology. +- pinctrl-names: Names for the TSIF mode configuration to specify which TSIF interface is active. +- qcom,smmu-s1-bypass : Boolean flag to bypass SMMU stage 1 translation. +- iommus : A list of phandle and IOMMU specifier pairs that describe the IOMMU master interfaces of the device. + +Example: + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x20 0x0f>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/qcom-geni-se.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/qcom-geni-se.txt new file mode 100644 index 0000000000000000000000000000000000000000..dde8231484a5a6fbd9fc4d43363241fdbb17e3d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/qcom-geni-se.txt @@ -0,0 +1,42 @@ +Qualcomm Technologies, Inc. GENI Serial Engine Driver + +GENI Serial Engine Driver is used to configure and read the configuration +from the Serial Engines on Qualcomm Technologies, Inc. Universal Peripheral +(QUPv3) core. It is also used to enable the stage1 IOMMU translation and +manage resources associated with the QUPv3 core. + +Required properties: +- compatible: Must be "qcom,qupv3-geni-se". +- reg: Must contain QUPv3 register address and length. +- qcom,bus-mas-id: Master Endpoint ID for bus driver. +- qcom,bus-slv-id: Slave Endpoint ID for bus driver. + +Optional properties: +- qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation. +- qcom,msm-bus,num-paths: Number of paths to put vote for. +- qcom,msm-bus,vectors-bus-ids: Master and slave Endpoint IDs for DDR + and Corex/2x paths. +- qcom,vote-for-bw: Boolean flag to check if ab/ib vote should be given + as bandwidth or BCM threashold. + +Optional subnodes: +qcom,iommu_qupv3_geni_se_cb: Child node representing the QUPV3 context + bank. + +Subnode Required properties: +- compatible : Must be "qcom,qupv3-geni-se-cb"; +- iommus: A list of phandle and IOMMU specifier pairs that + describe the IOMMU master interfaces of the device. + +Example: + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x6000>; + qcom,bus-mas-id = <100>; + qcom,bus-slv-id = <300>; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x1 0x0>; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-revid.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-revid.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd14890123e6e26b82f0f0b6596d4ba7940ebf34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-revid.txt @@ -0,0 +1,19 @@ +QPNP-REVID + +QPNP-REVID provides a way to read the PMIC part number and revision. + +Required properties: +- compatible : should be "qcom,qpnp-revid" +- reg : offset and length of the PMIC peripheral register map. + +Optional property: +- qcom,fab-id-valid: Use this property when support to read Fab + identification from REV ID peripheral is available. +- qcom,tp-rev-valid: Use this property when support to read TP + revision identification from REV ID peripheral. + +Example: + qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/rmnet_ipa3.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/rmnet_ipa3.txt new file mode 100644 index 0000000000000000000000000000000000000000..728bb366ef90c8c0210b4d9716f43d0ddd9cc248 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/rmnet_ipa3.txt @@ -0,0 +1,21 @@ +* Qualcomm Technologies, Inc. RmNet IPA driver module + +This module enables embedded data calls using IPA v3 HW. + +Required properties: +- compatible: Must be "qcom,rmnet-ipa3" + +Optional: +- qcom,rmnet-ipa-ssr: determine if modem SSR is supported +- qcom,ipa-advertise-sg-support: determine how to respond to a query +regarding scatter-gather capability +- qcom,ipa-napi-enable: Boolean context flag to indicate whether + to enable napi framework or not +- qcom,wan-rx-desc-size: size of WAN rx desc fifo ring, default is 256 + +Example: + qcom,rmnet-ipa3 { + compatible = "qcom,rmnet-ipa3"; + qcom,wan-rx-desc-size = <256>; + } + diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/usb-bam.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/usb-bam.txt new file mode 100644 index 0000000000000000000000000000000000000000..00848c9e944f177e14927601843193ebd3ca5c29 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/usb-bam.txt @@ -0,0 +1,102 @@ +MSM USB Bus Access Manager (BAM) + +This describes the device used to interface the USB controller +with the Smart Peripheral Subsystem (SPS). The BAM serves to +connect USB directly with other peer peripherals in the system +and is statically configured with a number of unidirectional pipes. + +Required properties: +- compatible: should be "qcom,usb-bam-msm" +- reg : pair of physical base addresses and region size of BAM device +- interrupts: IRQ line for BAM device +- qcom,usb-bam-num-pipes: max number of pipes that can be used + +Optional properties: +- qcom,usb-bam-fifo-baseaddr: base address for bam pipe's data and descriptor + fifos. This can be on chip memory (ocimem). This + property is required if sub-node's mem-type is ocimem or usb private mem. +- qcom,disable-clk-gating: If present then disable BAM clock gating. +- qcom,usb-bam-override-threshold: If present then the default 512 byte threshold + is overridden. This threshold configures the threshold value for Read/Write + event generation by the BAM towards another BAM. +- qcom,usb-bam-max-mbps-highspeed: max mbps in high speed connection + for either rx or tx direction. +- qcom,usb-bam-max-mbps-superspeed: max mbps in super speed connection + for either rx or tx direction. +- qcom,reset-bam-on-connect: If present then BAM is RESET before connecting + pipe. This may be required if BAM peripheral is also reset before connect. +- qcom,reset-bam-on-disconnect: If present then BAM is RESET after disconnecting pipes. + +A number of USB BAM pipe parameters are represented as sub-nodes: + +Subnode Required: +- label: a string describing uniquely the usb bam pipe. The string can be + constracted as follows: ---. + core options: hsusb, ssusb/dwc3, hsic + peer options: qdss, ipa + direction options: in (from peer to usb), out (from usb to peer) + pipe num options: 0..127 +- qcom,usb-bam-mem-type: Type of memory used by this PIPE. Can be one of + 0 - Uses SPS's dedicated pipe memory + 1 - System RAM allocated by driver + 2 - OCI memory residing @ 'qcom,usb-bam-fifo-baseaddr' +- qcom,dir: pipe direction + 0 - from usb (out) + 1 - to usb (in) +- qcom,pipe-num: pipe number +- qcom,peer-bam: peer BAM can be one of + 0 - QDSS_P_BAM + 1 - IPA_P_BAM +- qcom,data-fifo-size: data fifo size +- qcom,descriptor-fifo-size: descriptor fifo size + +Optional Properties for Subnode: +- qcom,peer-bam-physical-address: peer BAM's physical address. + Not specified for IPA and used only for qdss connection +- qcom,dst-bam-pipe-index: destination BAM pipe index +- qcom,src-bam-pipe-index: source BAM pipe index +- qcom,data-fifo-offset: data fifo offset address +- qcom,descriptor-fifo-offset: descriptor fifo offset address +- qcom,pipe-connection-type: type of pipe connection. Can be one of + 0 - BAM2BAM (default if not specified) + 1 - SYS2BAM (only supported on UL) + +Example USB BAM controller device node: + + qcom,usbbam@f9a44000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xf9a44000 0x11000>; + interrupts = <0 135 0>; + qcom,usb-bam-num-pipes = <16>; + qcom,ignore-core-reset-ack; + qcom,disable-clk-gating; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,bam-type = <1>; + qcom,bam-mode = <0>; + + qcom,pipe0 { + label = "hsusb-ipa-out-0"; + qcom,usb-bam-mem-type = <0>; + qcom,dir = <0>; + qcom,pipe-num = <0>; + qcom,peer-bam = <2>; + qcom,src-bam-pipe-index = <1>; + qcom,data-fifo-offset = <0x2200>; + qcom,data-fifo-size = <0x1e00>; + qcom,descriptor-fifo-offset = <0x2100>; + qcom,descriptor-fifo-size = <0x100>; + }; + qcom,pipe1 { + label = "hsusb-ipa-in-0"; + qcom,usb-bam-mem-type = <0>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <2>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x300>; + qcom,data-fifo-size = <0x1e00>; + qcom,descriptor-fifo-offset = <0>; + qcom,descriptor-fifo-size = <0x300>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pmem/pmem-region.txt b/arch/arm64/boot/dts/vendor/bindings/pmem/pmem-region.txt new file mode 100644 index 0000000000000000000000000000000000000000..5cfa4f016a00a03731a3b44c66279fd82b08cd4d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pmem/pmem-region.txt @@ -0,0 +1,65 @@ +Device-tree bindings for persistent memory regions +----------------------------------------------------- + +Persistent memory refers to a class of memory devices that are: + + a) Usable as main system memory (i.e. cacheable), and + b) Retain their contents across power failure. + +Given b) it is best to think of persistent memory as a kind of memory mapped +storage device. To ensure data integrity the operating system needs to manage +persistent regions separately to the normal memory pool. To aid with that this +binding provides a standardised interface for discovering where persistent +memory regions exist inside the physical address space. + +Bindings for the region nodes: +----------------------------- + +Required properties: + - compatible = "pmem-region" + + - reg = ; + The reg property should specificy an address range that is + translatable to a system physical address range. This address + range should be mappable as normal system memory would be + (i.e cacheable). + + If the reg property contains multiple address ranges + each address range will be treated as though it was specified + in a separate device node. Having multiple address ranges in a + node implies no special relationship between the two ranges. + +Optional properties: + - Any relevant NUMA assocativity properties for the target platform. + + - volatile; This property indicates that this region is actually + backed by non-persistent memory. This lets the OS know that it + may skip the cache flushes required to ensure data is made + persistent after a write. + + If this property is absent then the OS must assume that the region + is backed by non-volatile memory. + +Examples: +-------------------- + + /* + * This node specifies one 4KB region spanning from + * 0x5000 to 0x5fff that is backed by non-volatile memory. + */ + pmem@5000 { + compatible = "pmem-region"; + reg = <0x00005000 0x00001000>; + }; + + /* + * This node specifies two 4KB regions that are backed by + * volatile (normal) memory. + */ + pmem@6000 { + compatible = "pmem-region"; + reg = < 0x00006000 0x00001000 + 0x00008000 0x00001000 >; + volatile; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/power/actions,owl-sps.txt b/arch/arm64/boot/dts/vendor/bindings/power/actions,owl-sps.txt new file mode 100644 index 0000000000000000000000000000000000000000..78edd63641e87230dabd23465978e1b52c4a65d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/actions,owl-sps.txt @@ -0,0 +1,19 @@ +Actions Semi Owl Smart Power System (SPS) + +Required properties: +- compatible : "actions,s500-sps" for S500 + "actions,s700-sps" for S700 +- reg : Offset and length of the register set for the device. +- #power-domain-cells : Must be 1. + See macros in: + include/dt-bindings/power/owl-s500-powergate.h for S500 + include/dt-bindings/power/owl-s700-powergate.h for S700 + + +Example: + + sps: power-controller@b01b0100 { + compatible = "actions,s500-sps"; + reg = <0xb01b0100 0x100>; + #power-domain-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/amlogic,meson-gx-pwrc.txt b/arch/arm64/boot/dts/vendor/bindings/power/amlogic,meson-gx-pwrc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1cd050b4054ca28295417595c732825a534b091a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/amlogic,meson-gx-pwrc.txt @@ -0,0 +1,61 @@ +Amlogic Meson Power Controller +============================== + +The Amlogic Meson SoCs embeds an internal Power domain controller. + +VPU Power Domain +---------------- + +The Video Processing Unit power domain is controlled by this power controller, +but the domain requires some external resources to meet the correct power +sequences. +The bindings must respect the power domain bindings as described in the file +power_domain.txt + +Device Tree Bindings: +--------------------- + +Required properties: +- compatible: should be "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs +- #power-domain-cells: should be 0 +- amlogic,hhi-sysctrl: phandle to the HHI sysctrl node +- resets: phandles to the reset lines needed for this power demain sequence + as described in ../reset/reset.txt +- clocks: from common clock binding: handle to VPU and VAPB clocks +- clock-names: from common clock binding: must contain "vpu", "vapb" + corresponding to entry in the clocks property. + +Parent node should have the following properties : +- compatible: "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd" +- reg: base address and size of the AO system control register space. + +Example: +------- + +ao_sysctrl: sys-ctrl@0 { + compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"; + reg = <0x0 0x0 0x0 0x100>; + + pwrc_vpu: power-controller-vpu { + compatible = "amlogic,meson-gx-pwrc-vpu"; + #power-domain-cells = <0>; + amlogic,hhi-sysctrl = <&sysctrl>; + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, + <&reset RESET_VCBUS>, + <&reset RESET_BT656>, + <&reset RESET_DVIN_RESET>, + <&reset RESET_RDMA>, + <&reset RESET_VENCI>, + <&reset RESET_VENCP>, + <&reset RESET_VDAC>, + <&reset RESET_VDI6>, + <&reset RESET_VENCL>, + <&reset RESET_VID_LOCK>; + clocks = <&clkc CLKID_VPU>, + <&clkc CLKID_VAPB>; + clock-names = "vpu", "vapb"; + }; +}; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/power/domain-idle-state.txt b/arch/arm64/boot/dts/vendor/bindings/power/domain-idle-state.txt new file mode 100644 index 0000000000000000000000000000000000000000..eefc7ed22ca269129b142a7bea78e568a73e9bdc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/domain-idle-state.txt @@ -0,0 +1,33 @@ +PM Domain Idle State Node: + +A domain idle state node represents the state parameters that will be used to +select the state when there are no active components in the domain. + +The state node has the following parameters - + +- compatible: + Usage: Required + Value type: + Definition: Must be "domain-idle-state". + +- entry-latency-us + Usage: Required + Value type: + Definition: u32 value representing worst case latency in + microseconds required to enter the idle state. + The exit-latency-us duration may be guaranteed + only after entry-latency-us has passed. + +- exit-latency-us + Usage: Required + Value type: + Definition: u32 value representing worst case latency + in microseconds required to exit the idle state. + +- min-residency-us + Usage: Required + Value type: + Definition: u32 value representing minimum residency duration + in microseconds after which the idle state will yield + power benefits after overcoming the overhead in entering +i the idle state. diff --git a/arch/arm64/boot/dts/vendor/bindings/power/fsl,imx-gpc.txt b/arch/arm64/boot/dts/vendor/bindings/power/fsl,imx-gpc.txt new file mode 100644 index 0000000000000000000000000000000000000000..726ec2875223d8038b2a8fa7300d7ccfd8db2884 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/fsl,imx-gpc.txt @@ -0,0 +1,91 @@ +Freescale i.MX General Power Controller +======================================= + +The i.MX6 General Power Control (GPC) block contains DVFS load tracking +counters and Power Gating Control (PGC). + +Required properties: +- compatible: Should be one of the following: + - fsl,imx6q-gpc + - fsl,imx6qp-gpc + - fsl,imx6sl-gpc + - fsl,imx6sx-gpc +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain one interrupt specifier for the GPC interrupt +- clocks: Must contain an entry for each entry in clock-names. + See Documentation/devicetree/bindings/clock/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - ipg + +The power domains are generic power domain providers as documented in +Documentation/devicetree/bindings/power/power_domain.txt. They are described as +subnodes of the power gating controller 'pgc' node of the GPC and should +contain the following: + +Required properties: +- reg: Must contain the DOMAIN_INDEX of this power domain + The following DOMAIN_INDEX values are valid for i.MX6Q: + ARM_DOMAIN 0 + PU_DOMAIN 1 + The following additional DOMAIN_INDEX value is valid for i.MX6SL: + DISPLAY_DOMAIN 2 + The following additional DOMAIN_INDEX value is valid for i.MX6SX: + PCI_DOMAIN 3 + +- #power-domain-cells: Should be 0 + +Optional properties: +- clocks: a number of phandles to clocks that need to be enabled during domain + power-up sequencing to ensure reset propagation into devices located inside + this power domain +- power-supply: a phandle to the regulator powering this domain + +Example: + + gpc: gpc@20dc000 { + compatible = "fsl,imx6q-gpc"; + reg = <0x020dc000 0x4000>; + interrupts = <0 89 IRQ_TYPE_LEVEL_HIGH>, + <0 90 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks IMX6QDL_CLK_IPG>; + clock-names = "ipg"; + + pgc { + #address-cells = <1>; + #size-cells = <0>; + + power-domain@0 { + reg = <0>; + #power-domain-cells = <0>; + }; + + pd_pu: power-domain@1 { + reg = <1>; + #power-domain-cells = <0>; + power-supply = <®_pu>; + clocks = <&clks IMX6QDL_CLK_GPU3D_CORE>, + <&clks IMX6QDL_CLK_GPU3D_SHADER>, + <&clks IMX6QDL_CLK_GPU2D_CORE>, + <&clks IMX6QDL_CLK_GPU2D_AXI>, + <&clks IMX6QDL_CLK_OPENVG_AXI>, + <&clks IMX6QDL_CLK_VPU_AXI>; + }; + }; + }; + + +Specifying power domain for IP modules +====================================== + +IP cores belonging to a power domain should contain a 'power-domains' property +that is a phandle pointing to the power domain the device belongs to. + +Example of a device that is part of the PU power domain: + + vpu: vpu@2040000 { + reg = <0x02040000 0x3c000>; + /* ... */ + power-domains = <&pd_pu>; + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/fsl,imx-gpcv2.txt b/arch/arm64/boot/dts/vendor/bindings/power/fsl,imx-gpcv2.txt new file mode 100644 index 0000000000000000000000000000000000000000..9acce75b29abd9615e8ad0f0d7714231353eab7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/fsl,imx-gpcv2.txt @@ -0,0 +1,71 @@ +Freescale i.MX General Power Controller v2 +========================================== + +The i.MX7S/D General Power Control (GPC) block contains Power Gating +Control (PGC) for various power domains. + +Required properties: + +- compatible: Should be "fsl,imx7d-gpc" + +- reg: should be register base and length as documented in the + datasheet + +- interrupts: Should contain GPC interrupt request 1 + +Power domains contained within GPC node are generic power domain +providers, documented in +Documentation/devicetree/bindings/power/power_domain.txt, which are +described as subnodes of the power gating controller 'pgc' node, +which, in turn, is expected to contain the following: + +Required properties: + +- reg: Power domain index. Valid values are defined in + include/dt-bindings/power/imx7-power.h + +- #power-domain-cells: Should be 0 + +Optional properties: + +- power-supply: Power supply used to power the domain + +Example: + + gpc: gpc@303a0000 { + compatible = "fsl,imx7d-gpc"; + reg = <0x303a0000 0x1000>; + interrupt-controller; + interrupts = ; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + + pgc { + #address-cells = <1>; + #size-cells = <0>; + + pgc_pcie_phy: power-domain@1 { + #power-domain-cells = <0>; + + reg = <1>; + power-supply = <®_1p0d>; + }; + }; + }; + + +Specifying power domain for IP modules +====================================== + +IP cores belonging to a power domain should contain a 'power-domains' +property that is a phandle for PGC node representing the domain. + +Example of a device that is part of the PCIE_PHY power domain: + + pcie: pcie@33800000 { + reg = <0x33800000 0x4000>, + <0x4ff00000 0x80000>; + /* ... */ + power-domains = <&pgc_pcie_phy>; + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/mti,mips-cpc.txt b/arch/arm64/boot/dts/vendor/bindings/power/mti,mips-cpc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6b82511ae8a00e4396b2385fb872fa3c43b6964 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/mti,mips-cpc.txt @@ -0,0 +1,8 @@ +Binding for MIPS Cluster Power Controller (CPC). + +This binding allows a system to specify where the CPC registers are +located. + +Required properties: +compatible : Should be "mti,mips-cpc". +regs: Should describe the address & size of the CPC register region. diff --git a/arch/arm64/boot/dts/vendor/bindings/power/pd-samsung.txt b/arch/arm64/boot/dts/vendor/bindings/power/pd-samsung.txt new file mode 100644 index 0000000000000000000000000000000000000000..92ef355e8f6433c58c14f4bc3d05f39fbf7ea858 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/pd-samsung.txt @@ -0,0 +1,45 @@ +* Samsung Exynos Power Domains + +Exynos processors include support for multiple power domains which are used +to gate power to one or more peripherals on the processor. + +Required Properties: +- compatible: should be one of the following. + * samsung,exynos4210-pd - for exynos4210 type power domain. + * samsung,exynos5433-pd - for exynos5433 type power domain. +- reg: physical base address of the controller and length of memory mapped + region. +- #power-domain-cells: number of cells in power domain specifier; + must be 0. + +Optional Properties: +- label: Human readable string with domain name. Will be visible in userspace + to let user to distinguish between multiple domains in SoC. +- power-domains: phandle pointing to the parent power domain, for more details + see Documentation/devicetree/bindings/power/power_domain.txt + +Deprecated Properties: +- clocks +- clock-names + +Node of a device using power domains must have a power-domains property +defined with a phandle to respective power domain. + +Example: + + lcd0: power-domain-lcd0 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10023C00 0x10>; + #power-domain-cells = <0>; + label = "LCD0"; + }; + + mfc_pd: power-domain@10044060 { + compatible = "samsung,exynos4210-pd"; + reg = <0x10044060 0x20>; + #power-domain-cells = <0>; + label = "MFC"; + }; + +See Documentation/devicetree/bindings/power/power_domain.txt for description +of consumer-side bindings. diff --git a/arch/arm64/boot/dts/vendor/bindings/power/power-controller.txt b/arch/arm64/boot/dts/vendor/bindings/power/power-controller.txt new file mode 100644 index 0000000000000000000000000000000000000000..e45affea80781292316c75ed387ba38402501c5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/power-controller.txt @@ -0,0 +1,17 @@ +* Generic system power control capability + +Power-management integrated circuits or miscellaneous hardware components are +sometimes able to control the system power. The device driver associated with these +components might need to define this capability, which tells the kernel that +it can be used to switch off the system. The corresponding device must have the +standard property "system-power-controller" in its device node. This property +marks the device as able to control the system power. In order to test if this +property is found programmatically, use the helper function +"of_device_is_system_power_controller" from of.h . + +Example: + +act8846: act8846@5 { + compatible = "active-semi,act8846"; + system-power-controller; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/power/power_domain.txt b/arch/arm64/boot/dts/vendor/bindings/power/power_domain.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f8b25a24b8f4bc0f67178d47fc0bed4b4e2f608 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/power_domain.txt @@ -0,0 +1,205 @@ +* Generic PM domains + +System on chip designs are often divided into multiple PM domains that can be +used for power gating of selected IP blocks for power saving by reduced leakage +current. + +This device tree binding can be used to bind PM domain consumer devices with +their PM domains provided by PM domain providers. A PM domain provider can be +represented by any node in the device tree and can provide one or more PM +domains. A consumer node can refer to the provider by a phandle and a set of +phandle arguments (so called PM domain specifiers) of length specified by the +#power-domain-cells property in the PM domain provider node. + +==PM domain providers== + +Required properties: + - #power-domain-cells : Number of cells in a PM domain specifier; + Typically 0 for nodes representing a single PM domain and 1 for nodes + providing multiple PM domains (e.g. power controllers), but can be any value + as specified by device tree binding documentation of particular provider. + +Optional properties: + - power-domains : A phandle and PM domain specifier as defined by bindings of + the power controller specified by phandle. + Some power domains might be powered from another power domain (or have + other hardware specific dependencies). For representing such dependency + a standard PM domain consumer binding is used. When provided, all domains + created by the given provider should be subdomains of the domain + specified by this binding. More details about power domain specifier are + available in the next section. + +- domain-idle-states : A phandle of an idle-state that shall be soaked into a + generic domain power state. The idle state definitions are + compatible with domain-idle-state specified in [1]. phandles + that are not compatible with domain-idle-state will be + ignored. + The domain-idle-state property reflects the idle state of this PM domain and + not the idle states of the devices or sub-domains in the PM domain. Devices + and sub-domains have their own idle-states independent of the parent + domain's idle states. In the absence of this property, the domain would be + considered as capable of being powered-on or powered-off. + +- operating-points-v2 : Phandles to the OPP tables of power domains provided by + a power domain provider. If the provider provides a single power domain only + or all the power domains provided by the provider have identical OPP tables, + then this shall contain a single phandle. Refer to ../opp/opp.txt for more + information. + +Example: + + power: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <1>; + }; + +The node above defines a power controller that is a PM domain provider and +expects one cell as its phandle argument. + +Example 2: + + parent: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <1>; + }; + + child: power-controller@12341000 { + compatible = "foo,power-controller"; + reg = <0x12341000 0x1000>; + power-domains = <&parent 0>; + #power-domain-cells = <1>; + }; + +The nodes above define two power controllers: 'parent' and 'child'. +Domains created by the 'child' power controller are subdomains of '0' power +domain provided by the 'parent' power controller. + +Example 3: + parent: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <0>; + domain-idle-states = <&DOMAIN_RET>, <&DOMAIN_PWR_DN>; + }; + + child: power-controller@12341000 { + compatible = "foo,power-controller"; + reg = <0x12341000 0x1000>; + power-domains = <&parent>; + #power-domain-cells = <0>; + domain-idle-states = <&DOMAIN_PWR_DN>; + }; + + DOMAIN_RET: state@0 { + compatible = "domain-idle-state"; + reg = <0x0>; + entry-latency-us = <1000>; + exit-latency-us = <2000>; + min-residency-us = <10000>; + }; + + DOMAIN_PWR_DN: state@1 { + compatible = "domain-idle-state"; + reg = <0x1>; + entry-latency-us = <5000>; + exit-latency-us = <8000>; + min-residency-us = <7000>; + }; + +==PM domain consumers== + +Required properties: + - power-domains : A list of PM domain specifiers, as defined by bindings of + the power controller that is the PM domain provider. + +Optional properties: + - power-domain-names : A list of power domain name strings sorted in the same + order as the power-domains property. Consumers drivers will use + power-domain-names to match power domains with power-domains + specifiers. + +Example: + + leaky-device@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 0>; + power-domain-names = "io"; + }; + + leaky-device@12351000 { + compatible = "foo,i-leak-current"; + reg = <0x12351000 0x1000>; + power-domains = <&power 0>, <&power 1> ; + power-domain-names = "io", "clk"; + }; + +The first example above defines a typical PM domain consumer device, which is +located inside a PM domain with index 0 of a power controller represented by a +node with the label "power". +In the second example the consumer device are partitioned across two PM domains, +the first with index 0 and the second with index 1, of a power controller that +is represented by a node with the label "power". + +Optional properties: +- required-opps: This contains phandle to an OPP node in another device's OPP + table. It may contain an array of phandles, where each phandle points to an + OPP of a different device. It should not contain multiple phandles to the OPP + nodes in the same OPP table. This specifies the minimum required OPP of the + device(s), whose OPP's phandle is present in this property, for the + functioning of the current device at the current OPP (where this property is + present). + +Example: +- OPP table for domain provider that provides two domains. + + domain0_opp_table: opp-table0 { + compatible = "operating-points-v2"; + + domain0_opp_0: opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + opp-microvolt = <975000 970000 985000>; + }; + domain0_opp_1: opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <1000000 980000 1010000>; + }; + }; + + domain1_opp_table: opp-table1 { + compatible = "operating-points-v2"; + + domain1_opp_0: opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <975000 970000 985000>; + }; + domain1_opp_1: opp-1300000000 { + opp-hz = /bits/ 64 <1300000000>; + opp-microvolt = <1000000 980000 1010000>; + }; + }; + + power: power-controller@12340000 { + compatible = "foo,power-controller"; + reg = <0x12340000 0x1000>; + #power-domain-cells = <1>; + operating-points-v2 = <&domain0_opp_table>, <&domain1_opp_table>; + }; + + leaky-device0@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 0>; + required-opps = <&domain0_opp_0>; + }; + + leaky-device1@12350000 { + compatible = "foo,i-leak-current"; + reg = <0x12350000 0x1000>; + power-domains = <&power 1>; + required-opps = <&domain1_opp_1>; + }; + +[1]. Documentation/devicetree/bindings/power/domain-idle-state.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/power/renesas,apmu.txt b/arch/arm64/boot/dts/vendor/bindings/power/renesas,apmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..f747f95eee582419178f2b5fb5ca500b2c9bb137 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/renesas,apmu.txt @@ -0,0 +1,33 @@ +DT bindings for the Renesas Advanced Power Management Unit + +Renesas R-Car and RZ/G1 SoCs utilize one or more APMU hardware units +for CPU core power domain control including SMP boot and CPU Hotplug. + +Required properties: + +- compatible: Should be "renesas,-apmu", "renesas,apmu" as fallback. + Examples with soctypes are: + - "renesas,r8a7743-apmu" (RZ/G1M) + - "renesas,r8a7745-apmu" (RZ/G1E) + - "renesas,r8a7790-apmu" (R-Car H2) + - "renesas,r8a7791-apmu" (R-Car M2-W) + - "renesas,r8a7792-apmu" (R-Car V2H) + - "renesas,r8a7793-apmu" (R-Car M2-N) + - "renesas,r8a7794-apmu" (R-Car E2) + +- reg: Base address and length of the I/O registers used by the APMU. + +- cpus: This node contains a list of CPU cores, which should match the order + of CPU cores used by the WUPCR and PSTR registers in the Advanced Power + Management Unit section of the device's datasheet. + + +Example: + +This shows the r8a7791 APMU that can control CPU0 and CPU1. + + apmu@e6152000 { + compatible = "renesas,r8a7791-apmu", "renesas,apmu"; + reg = <0 0xe6152000 0 0x188>; + cpus = <&cpu0 &cpu1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/renesas,rcar-sysc.txt b/arch/arm64/boot/dts/vendor/bindings/power/renesas,rcar-sysc.txt new file mode 100644 index 0000000000000000000000000000000000000000..180ae65be753ae43ecc39a294a3a7163bdb517d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/renesas,rcar-sysc.txt @@ -0,0 +1,57 @@ +DT bindings for the Renesas R-Car (RZ/G) System Controller + +== System Controller Node == + +The R-Car (RZ/G) System Controller provides power management for the CPU cores +and various coprocessors. + +Required properties: + - compatible: Must contain exactly one of the following: + - "renesas,r8a7743-sysc" (RZ/G1M) + - "renesas,r8a7745-sysc" (RZ/G1E) + - "renesas,r8a77470-sysc" (RZ/G1C) + - "renesas,r8a7779-sysc" (R-Car H1) + - "renesas,r8a7790-sysc" (R-Car H2) + - "renesas,r8a7791-sysc" (R-Car M2-W) + - "renesas,r8a7792-sysc" (R-Car V2H) + - "renesas,r8a7793-sysc" (R-Car M2-N) + - "renesas,r8a7794-sysc" (R-Car E2) + - "renesas,r8a7795-sysc" (R-Car H3) + - "renesas,r8a7796-sysc" (R-Car M3-W) + - "renesas,r8a77965-sysc" (R-Car M3-N) + - "renesas,r8a77970-sysc" (R-Car V3M) + - "renesas,r8a77980-sysc" (R-Car V3H) + - "renesas,r8a77990-sysc" (R-Car E3) + - "renesas,r8a77995-sysc" (R-Car D3) + - reg: Address start and address range for the device. + - #power-domain-cells: Must be 1. + + +Example: + + sysc: system-controller@e6180000 { + compatible = "renesas,r8a7791-sysc"; + reg = <0 0xe6180000 0 0x0200>; + #power-domain-cells = <1>; + }; + + +== PM Domain Consumers == + +Devices residing in a power area must refer to that power area, as documented +by the generic PM domain bindings in +Documentation/devicetree/bindings/power/power_domain.txt. + +Required properties: + - power-domains: A phandle and symbolic PM domain specifier, as defined in + . + + +Example: + + L2_CA15: cache-controller@0 { + compatible = "cache"; + power-domains = <&sysc R8A7791_PD_CA15_SCU>; + cache-unified; + cache-level = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/renesas,sysc-rmobile.txt b/arch/arm64/boot/dts/vendor/bindings/power/renesas,sysc-rmobile.txt new file mode 100644 index 0000000000000000000000000000000000000000..beda7d2efc304350aa7dc48f2cc6212bfc6ee795 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/renesas,sysc-rmobile.txt @@ -0,0 +1,100 @@ +DT bindings for the Renesas R-Mobile System Controller + +== System Controller Node == + +The R-Mobile System Controller provides the following functions: + - Boot mode management, + - Reset generation, + - Power management. + +Required properties: +- compatible: Should be "renesas,sysc-", "renesas,sysc-rmobile" as + fallback. + Examples with soctypes are: + - "renesas,sysc-r8a73a4" (R-Mobile APE6) + - "renesas,sysc-r8a7740" (R-Mobile A1) + - "renesas,sysc-sh73a0" (SH-Mobile AG5) +- reg: Two address start and address range blocks for the device: + - The first block refers to the normally accessible registers, + - the second block refers to the registers protected by the HPB + semaphore. + +Optional nodes: +- pm-domains: This node contains a hierarchy of PM domain nodes, which should + match the Power Area Hierarchy in the Power Domain Specifications section of + the device's datasheet. + + +== PM Domain Nodes == + +Each of the PM domain nodes represents a PM domain, as documented by the +generic PM domain bindings in +Documentation/devicetree/bindings/power/power_domain.txt. + +The nodes should be named by the real power area names, and thus their names +should be unique. + +Required properties: + - #power-domain-cells: Must be 0. + +Optional properties: +- reg: If the PM domain is not always-on, this property must contain the bit + index number for the corresponding power area in the various Power + Control and Status Registers. The parent's node must contain the + following two properties: + - #address-cells: Must be 1, + - #size-cells: Must be 0. + If the PM domain is always-on, this property must be omitted. + + +Example: + +This shows a subset of the r8a7740 PM domain hierarchy, containing the +C5 "always-on" domain, 2 of its subdomains (A4S and A4SU), and the A3SP domain, +which is a subdomain of A4S. + + sysc: system-controller@e6180000 { + compatible = "renesas,sysc-r8a7740", "renesas,sysc-rmobile"; + reg = <0xe6180000 0x8000>, <0xe6188000 0x8000>; + + pm-domains { + pd_c5: c5 { + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <0>; + + pd_a4s: a4s@10 { + reg = <10>; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <0>; + + pd_a3sp: a3sp@11 { + reg = <11>; + #power-domain-cells = <0>; + }; + }; + + pd_a4su: a4su@20 { + reg = <20>; + #power-domain-cells = <0>; + }; + }; + }; + }; + + +== PM Domain Consumers == + +Hardware blocks belonging to a PM domain should contain a "power-domains" +property that is a phandle pointing to the corresponding PM domain node. + +Example: + + tpu: pwm@e6600000 { + compatible = "renesas,tpu-r8a7740", "renesas,tpu"; + reg = <0xe6600000 0x100>; + clocks = <&mstp3_clks R8A7740_CLK_TPU0>; + power-domains = <&pd_a3sp>; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/axxia-reset.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/axxia-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..47e720d249d2a7bc4c6b0e42b3a634749fda2c99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/axxia-reset.txt @@ -0,0 +1,20 @@ +Axxia Restart Driver + +This driver can do reset of the Axxia SoC. It uses the registers in the syscon +block to initiate a chip reset. + +Required Properties: + -compatible: "lsi,axm55xx-reset" + -syscon: phandle to the syscon node. + +Example: + + syscon: syscon@2010030000 { + compatible = "lsi,axxia-syscon", "syscon"; + reg = <0x20 0x10030000 0 0x2000>; + }; + + reset: reset@2010031000 { + compatible = "lsi,axm55xx-reset"; + syscon = <&syscon>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/brcm,bcm21664-resetmgr.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/brcm,bcm21664-resetmgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..93f31ca1ef4b30db647a4341a8d8181ace8c2dc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/brcm,bcm21664-resetmgr.txt @@ -0,0 +1,14 @@ +Broadcom Kona Family Reset Manager +---------------------------------- + +The reset manager is used on the Broadcom BCM21664 SoC. + +Required properties: + - compatible: brcm,bcm21664-resetmgr + - reg: memory address & range + +Example: + brcm,resetmgr@35001f00 { + compatible = "brcm,bcm21664-resetmgr"; + reg = <0x35001f00 0x24>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/gemini-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/gemini-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fec3e100214c618bd2b5d1ba3a0bb01bc9df04e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/gemini-poweroff.txt @@ -0,0 +1,17 @@ +* Device-Tree bindings for Cortina Systems Gemini Poweroff + +This is a special IP block in the Cortina Gemini SoC that only +deals with different ways to power the system down. + +Required properties: +- compatible: should be "cortina,gemini-power-controller" +- reg: should contain the physical memory base and size +- interrupts: should contain the power management interrupt + +Example: + +power-controller@4b000000 { + compatible = "cortina,gemini-power-controller"; + reg = <0x4b000000 0x100>; + interrupts = <26 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/gpio-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/gpio-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d8980c18c3485ea55ee44cfbe33babc3a7f95b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/gpio-poweroff.txt @@ -0,0 +1,39 @@ +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. +- timeout-ms: Time to wait before asserting a WARN_ON(1). If nothing is + specified, 3000 ms is used. + +Examples: + +gpio-poweroff { + compatible = "gpio-poweroff"; + gpios = <&gpio 4 0>; + timeout-ms = <3000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/gpio-restart.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/gpio-restart.txt new file mode 100644 index 0000000000000000000000000000000000000000..af3701bc15c48b131e4c77a8cf2c35bcf7ad7975 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/gpio-restart.txt @@ -0,0 +1,54 @@ +Drive a GPIO line that can be used to restart the system from a restart +handler. + +This binding supports level and edge triggered reset. At driver load +time, the driver will request the given gpio line and install a restart +handler. If the optional properties 'open-source' is not found, the GPIO line +will be driven in the inactive state. Otherwise its not driven until +the restart is initiated. + +When the system is restarted, the restart handler will be invoked in +priority order. The gpio is configured as an output, and driven active, +triggering a level triggered reset condition. This will also cause an +inactive->active edge condition, triggering positive edge triggered +reset. After a delay specified by active-delay, the GPIO is set to +inactive, thus causing an active->inactive edge, triggering negative edge +triggered reset. After a delay specified by inactive-delay, the GPIO +is driven active again. After a delay specified by wait-delay, the +restart handler completes allowing other restart handlers to be attempted. + +Required properties: +- compatible : should be "gpio-restart". +- gpios : The GPIO to set high/low, see "gpios property" in + Documentation/devicetree/bindings/gpio/gpio.txt. If the pin should be + low to reset the board set it to "Active Low", otherwise set + gpio to "Active High". + +Optional properties: +- open-source : Treat the GPIO as being open source and defer driving + it to when the restart is initiated. If this optional property is not + specified, the GPIO is initialized as an output in its inactive state. +- priority : A priority ranging from 0 to 255 (default 128) according to + the following guidelines: + 0: Restart handler of last resort, with limited restart + capabilities + 128: Default restart handler; use if no other restart handler is + expected to be available, and/or if restart functionality is + sufficient to restart the entire system + 255: Highest priority restart handler, will preempt all other + restart handlers +- active-delay: Delay (default 100) to wait after driving gpio active [ms] +- inactive-delay: Delay (default 100) to wait after driving gpio inactive [ms] +- wait-delay: Delay (default 3000) to wait after completing restart + sequence [ms] + +Examples: + +gpio-restart { + compatible = "gpio-restart"; + gpios = <&gpio 4 0>; + priority = <128>; + active-delay = <100>; + inactive-delay = <100>; + wait-delay = <3000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/keystone-reset.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/keystone-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5c03789ed1e2a0f09a17ac4768f9cf8405f00b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/keystone-reset.txt @@ -0,0 +1,67 @@ +* Device tree bindings for Texas Instruments keystone reset + +This node is intended to allow SoC reset in case of software reset +of selected watchdogs. + +The Keystone SoCs can contain up to 4 watchdog timers to reset +SoC. Each watchdog timer event input is connected to the Reset Mux +block. The Reset Mux block can be configured to cause reset or not. + +Additionally soft or hard reset can be configured. + +Required properties: + +- compatible: ti,keystone-reset + +- ti,syscon-pll: phandle/offset pair. The phandle to syscon used to + access pll controller registers and the offset to use + reset control registers. + +- ti,syscon-dev: phandle/offset pair. The phandle to syscon used to + access device state control registers and the offset + in order to use mux block registers for all watchdogs. + +Optional properties: + +- ti,soft-reset: Boolean option indicating soft reset. + By default hard reset is used. + +- ti,wdt-list: WDT list that can cause SoC reset. It's not related + to WDT driver, it's just needed to enable a SoC related + reset that's triggered by one of WDTs. The list is + in format: <0>, <2>; It can be in random order and + begins from 0 to 3, as keystone can contain up to 4 SoC + reset watchdogs and can be in random order. + +Example 1: +Setup keystone reset so that in case software reset or +WDT0 is triggered it issues hard reset for SoC. + +pllctrl: pll-controller@2310000 { + compatible = "ti,keystone-pllctrl", "syscon"; + reg = <0x02310000 0x200>; +}; + +devctrl: device-state-control@2620000 { + compatible = "ti,keystone-devctrl", "syscon"; + reg = <0x02620000 0x1000>; +}; + +rstctrl: reset-controller { + compatible = "ti,keystone-reset"; + ti,syscon-pll = <&pllctrl 0xe4>; + ti,syscon-dev = <&devctrl 0x328>; + ti,wdt-list = <0>; +}; + +Example 2: +Setup keystone reset so that in case of software reset or +WDT0 or WDT2 is triggered it issues soft reset for SoC. + +rstctrl: reset-controller { + compatible = "ti,keystone-reset"; + ti,syscon-pll = <&pllctrl 0xe4>; + ti,syscon-dev = <&devctrl 0x328>; + ti,wdt-list = <0>, <2>; + ti,soft-reset; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/ltc2952-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/ltc2952-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd2d7f58a9d732040336a1c27bebbb89f7c361e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/ltc2952-poweroff.txt @@ -0,0 +1,29 @@ +Binding for the LTC2952 PowerPath controller + +This chip is used to externally trigger a system shut down. Once the trigger has +been sent, the chip's watchdog has to be reset to gracefully shut down. +A full powerdown can be triggered via the kill signal. + +Required properties: + +- compatible: Must contain: "lltc,ltc2952" +- watchdog-gpios: phandle + gpio-specifier for the GPIO connected to the + chip's watchdog line +- kill-gpios: phandle + gpio-specifier for the GPIO connected to the + chip's kill line + +Optional properties: +- trigger-gpios: phandle + gpio-specifier for the GPIO connected to the + chip's trigger line. If this property is not set, the + trigger function is ignored and the chip is kept alive + until an explicit kill signal is received + +Example: + +ltc2952 { + compatible = "lltc,ltc2952"; + + trigger-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + watchdog-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>; + kill-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/msm-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/msm-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..1492616eed6dd5e03027fb74158d5078c9c99a38 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/msm-poweroff.txt @@ -0,0 +1,21 @@ +MSM Restart Driver + +A power supply hold (ps-hold) bit is set to power the msm chipsets. +Clearing that bit allows us to restart/poweroff. The difference +between poweroff and restart is determined by unique power manager IC +settings. + +Required Properties: +-compatible: "qcom,pshold" +-reg: Specifies the physical address of the ps-hold register + +Optional Properties: +-qcom,force-warm-reboot: Issue a warm reboot, even for the traditional cases + where hard reboot is issued. + +Example: + + restart@fc4ab000 { + compatible = "qcom,pshold"; + reg = <0xfc4ab000 0x4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/ocelot-reset.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/ocelot-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b4213eb34731422bb954931db05c457ff48df74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/ocelot-reset.txt @@ -0,0 +1,14 @@ +Microsemi Ocelot reset controller + +The DEVCPU_GCB:CHIP_REGS have a SOFT_RST register that can be used to reset the +SoC MIPS core. + +Required Properties: + - compatible: "mscc,ocelot-chip-reset" + +Example: + reset@1070008 { + compatible = "mscc,ocelot-chip-reset"; + reg = <0x1070008 0x4>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/qcom,pon.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/qcom,pon.txt new file mode 100644 index 0000000000000000000000000000000000000000..651491bb63b728814ea4923c7a5b371a3e4a5ef1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/qcom,pon.txt @@ -0,0 +1,45 @@ +Qualcomm PON Device + +The Power On device for Qualcomm PM8xxx is MFD supporting pwrkey +and resin along with the Android reboot-mode. + +This DT node has pwrkey and resin as sub nodes. + +Required Properties: +-compatible: "qcom,pm8916-pon" +-reg: Specifies the physical address of the pon register + +Optional subnode: +-pwrkey: Specifies the subnode pwrkey and should follow the + qcom,pm8941-pwrkey.txt description. +-resin: Specifies the subnode resin and should follow the + qcom,pm8xxx-pwrkey.txt description. + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + + pon@800 { + compatible = "qcom,pm8916-pon"; + + reg = <0x800>; + mode-bootloader = <0x2>; + mode-recovery = <0x1>; + + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + + resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/qnap-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/qnap-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..c363d7173129dbe40ea2019ff3fc342188d03488 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/qnap-poweroff.txt @@ -0,0 +1,15 @@ +* QNAP Power Off + +QNAP NAS devices have a microcontroller controlling the main power +supply. This microcontroller is connected to UART1 of the Kirkwood and +Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the +microcontroller to turn the power off. + +Synology NAS devices use a similar scheme, but a different baud rate, +9600, and a different character, '1'. + +Required Properties: +- compatible: Should be "qnap,power-off" or "synology,power-off" + +- reg: Address and length of the register set for UART1 +- clocks: tclk clock diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/reboot-mode.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/reboot-mode.txt new file mode 100644 index 0000000000000000000000000000000000000000..de34f27d509ee7fafa5e4e183e5fdec44f9565d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/reboot-mode.txt @@ -0,0 +1,25 @@ +Generic reboot mode core map driver + +This driver get reboot mode arguments and call the write +interface to store the magic value in special register +or ram. Then the bootloader can read it and take different +action according to the argument stored. + +All mode properties are vendor specific, it is a indication to tell +the bootloader what to do when the system reboots, and should be named +as mode-xxx = (xxx is mode name, magic should be a none-zero value). + +For example modes common on Android platform: +- mode-normal: Normal reboot mode, system reboot with command "reboot". +- mode-recovery: Android Recovery mode, it is a mode to format the device or update a new image. +- mode-bootloader: Android fastboot mode, it's a mode to re-flash partitions on the Android based device. +- mode-loader: A bootloader mode, it's a mode used to download image on Rockchip platform, + usually used in development. + +Example: + reboot-mode { + mode-normal = ; + mode-recovery = ; + mode-bootloader = ; + mode-loader = ; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/restart-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/restart-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..5776e684afda5be2ec245f52bc97f2f9108af72d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/restart-poweroff.txt @@ -0,0 +1,8 @@ +* Restart Power Off + +Buffalo Linkstation LS-XHL and LS-CHLv2, and other devices power off +by restarting and letting u-boot keep hold of the machine until the +user presses a button. + +Required Properties: +- compatible: Should be "restart-poweroff" diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/st-reset.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/st-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..b63948737d806913bd24bfe57d7650dae63f2caa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/st-reset.txt @@ -0,0 +1,11 @@ +*Device-Tree bindings for ST SW reset functionality + +Required properties: +- compatible: should be "stih407-restart". +- st,syscfg: should be a phandle of the syscfg node. + +Example node: + restart { + compatible = "st,stih407-restart"; + st,syscfg = <&syscfg_sbc_reg>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-poweroff.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-poweroff.txt new file mode 100644 index 0000000000000000000000000000000000000000..022ed1f3bc808351752ae1130dd226e7c7e7cb38 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-poweroff.txt @@ -0,0 +1,30 @@ +Generic SYSCON mapped register poweroff driver + +This is a generic poweroff driver using syscon to map the poweroff register. +The poweroff is generally performed with a write to the poweroff register +defined by the register map pointed by syscon reference plus the offset +with the value and mask defined in the poweroff node. + +Required properties: +- compatible: should contain "syscon-poweroff" +- regmap: this is phandle to the register map node +- offset: offset in the register map for the poweroff register (in bytes) +- value: the poweroff value written to the poweroff register (32 bit access) + +Optional properties: +- mask: update only the register bits defined by the mask (32 bit) + +Legacy usage: +If a node doesn't contain a value property but contains a mask property, the +mask property is used as the value. + +Default will be little endian mode, 32 bit access only. + +Examples: + + poweroff { + compatible = "syscon-poweroff"; + regmap = <®mapnode>; + offset = <0x0>; + mask = <0x7a>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-reboot-mode.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-reboot-mode.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7ce1d8af04ae2d2f427ff942adfeb84c5800764 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-reboot-mode.txt @@ -0,0 +1,35 @@ +SYSCON reboot mode driver + +This driver gets reboot mode magic value form reboot-mode driver +and stores it in a SYSCON mapped register. Then the bootloader +can read it and take different action according to the magic +value stored. + +This DT node should be represented as a sub-node of a "syscon", "simple-mfd" +node. + +Required properties: +- compatible: should be "syscon-reboot-mode" +- offset: offset in the register map for the storage register (in bytes) + +Optional property: +- mask: bits mask of the bits in the register to store the reboot mode magic value, + default set to 0xffffffff if missing. + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + pmu: pmu@20004000 { + compatible = "rockchip,rk3066-pmu", "syscon", "simple-mfd"; + reg = <0x20004000 0x100>; + + reboot-mode { + compatible = "syscon-reboot-mode"; + offset = <0x40>; + mode-normal = ; + mode-recovery = ; + mode-bootloader = ; + mode-loader = ; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-reboot.txt b/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-reboot.txt new file mode 100644 index 0000000000000000000000000000000000000000..11906316b43d0860133efce69c70f5a3e5a52157 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/reset/syscon-reboot.txt @@ -0,0 +1,23 @@ +Generic SYSCON mapped register reset driver + +This is a generic reset driver using syscon to map the reset register. +The reset is generally performed with a write to the reset register +defined by the register map pointed by syscon reference plus the offset +with the mask defined in the reboot node. + +Required properties: +- compatible: should contain "syscon-reboot" +- regmap: this is phandle to the register map node +- offset: offset in the register map for the reboot register (in bytes) +- mask: the reset value written to the reboot register (32 bit access) + +Default will be little endian mode, 32 bit access only. + +Examples: + + reboot { + compatible = "syscon-reboot"; + regmap = <®mapnode>; + offset = <0x0>; + mask = <0x1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/rockchip-io-domain.txt b/arch/arm64/boot/dts/vendor/bindings/power/rockchip-io-domain.txt new file mode 100644 index 0000000000000000000000000000000000000000..e66fd4eab71cba5d6af32870156c5cb54aa091cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/rockchip-io-domain.txt @@ -0,0 +1,135 @@ +Rockchip SRAM for IO Voltage Domains: +------------------------------------- + +IO domain voltages on some Rockchip SoCs are variable but need to be +kept in sync between the regulators and the SoC using a special +register. + +A specific example using rk3288: +- If the regulator hooked up to a pin like SDMMC0_VDD is 3.3V then + bit 7 of GRF_IO_VSEL needs to be 0. If the regulator hooked up to + that same pin is 1.8V then bit 7 of GRF_IO_VSEL needs to be 1. + +Said another way, this driver simply handles keeping bits in the SoC's +general register file (GRF) in sync with the actual value of a voltage +hooked up to the pins. + +Note that this driver specifically doesn't include: +- any logic for deciding what voltage we should set regulators to +- any logic for deciding whether regulators (or internal SoC blocks) + should have power or not have power + +If there were some other software that had the smarts of making +decisions about regulators, it would work in conjunction with this +driver. When that other software adjusted a regulator's voltage then +this driver would handle telling the SoC about it. A good example is +vqmmc for SD. In that case the dw_mmc driver simply is told about a +regulator. It changes the regulator between 3.3V and 1.8V at the +right time. This driver notices the change and makes sure that the +SoC is on the same page. + + +Required properties: +- compatible: should be one of: + - "rockchip,px30-io-voltage-domain" for px30 + - "rockchip,px30-pmu-io-voltage-domain" for px30 pmu-domains + - "rockchip,rk3188-io-voltage-domain" for rk3188 + - "rockchip,rk3228-io-voltage-domain" for rk3228 + - "rockchip,rk3288-io-voltage-domain" for rk3288 + - "rockchip,rk3328-io-voltage-domain" for rk3328 + - "rockchip,rk3368-io-voltage-domain" for rk3368 + - "rockchip,rk3368-pmu-io-voltage-domain" for rk3368 pmu-domains + - "rockchip,rk3399-io-voltage-domain" for rk3399 + - "rockchip,rk3399-pmu-io-voltage-domain" for rk3399 pmu-domains + - "rockchip,rv1108-io-voltage-domain" for rv1108 + - "rockchip,rv1108-pmu-io-voltage-domain" for rv1108 pmu-domains + +Deprecated properties: +- rockchip,grf: phandle to the syscon managing the "general register files" + Systems should move the io-domains to a sub-node of the grf simple-mfd. + +You specify supplies using the standard regulator bindings by including +a phandle the relevant regulator. All specified supplies must be able +to report their voltage. The IO Voltage Domain for any non-specified +supplies will be not be touched. + +Possible supplies for PX30: +- vccio6-supply: The supply connected to VCCIO6. +- vccio1-supply: The supply connected to VCCIO1. +- vccio2-supply: The supply connected to VCCIO2. +- vccio3-supply: The supply connected to VCCIO3. +- vccio4-supply: The supply connected to VCCIO4. +- vccio5-supply: The supply connected to VCCIO5. +- vccio-oscgpi-supply: The supply connected to VCCIO_OSCGPI. + +Possible supplies for PX30 pmu-domains: +- pmuio1-supply: The supply connected to PMUIO1. +- pmuio2-supply: The supply connected to PMUIO2. + +Possible supplies for rk3188: +- ap0-supply: The supply connected to AP0_VCC. +- ap1-supply: The supply connected to AP1_VCC. +- cif-supply: The supply connected to CIF_VCC. +- flash-supply: The supply connected to FLASH_VCC. +- lcdc0-supply: The supply connected to LCD0_VCC. +- lcdc1-supply: The supply connected to LCD1_VCC. +- vccio0-supply: The supply connected to VCCIO0. +- vccio1-supply: The supply connected to VCCIO1. + Sometimes also labeled VCCIO1 and VCCIO2. + +Possible supplies for rk3228: +- vccio1-supply: The supply connected to VCCIO1. +- vccio2-supply: The supply connected to VCCIO2. +- vccio3-supply: The supply connected to VCCIO3. +- vccio4-supply: The supply connected to VCCIO4. + +Possible supplies for rk3288: +- audio-supply: The supply connected to APIO4_VDD. +- bb-supply: The supply connected to APIO5_VDD. +- dvp-supply: The supply connected to DVPIO_VDD. +- flash0-supply: The supply connected to FLASH0_VDD. Typically for eMMC +- flash1-supply: The supply connected to FLASH1_VDD. Also known as SDIO1. +- gpio30-supply: The supply connected to APIO1_VDD. +- gpio1830 The supply connected to APIO2_VDD. +- lcdc-supply: The supply connected to LCDC_VDD. +- sdcard-supply: The supply connected to SDMMC0_VDD. +- wifi-supply: The supply connected to APIO3_VDD. Also known as SDIO0. + +Possible supplies for rk3368: +- audio-supply: The supply connected to APIO3_VDD. +- dvp-supply: The supply connected to DVPIO_VDD. +- flash0-supply: The supply connected to FLASH0_VDD. Typically for eMMC +- gpio30-supply: The supply connected to APIO1_VDD. +- gpio1830 The supply connected to APIO4_VDD. +- sdcard-supply: The supply connected to SDMMC0_VDD. +- wifi-supply: The supply connected to APIO2_VDD. Also known as SDIO0. + +Possible supplies for rk3368 pmu-domains: +- pmu-supply: The supply connected to PMUIO_VDD. +- vop-supply: The supply connected to LCDC_VDD. + +Possible supplies for rk3399: +- bt656-supply: The supply connected to APIO2_VDD. +- audio-supply: The supply connected to APIO5_VDD. +- sdmmc-supply: The supply connected to SDMMC0_VDD. +- gpio1830 The supply connected to APIO4_VDD. + +Possible supplies for rk3399 pmu-domains: +- pmu1830-supply:The supply connected to PMUIO2_VDD. + +Example: + + io-domains { + compatible = "rockchip,rk3288-io-voltage-domain"; + rockchip,grf = <&grf>; + + audio-supply = <&vcc18_codec>; + bb-supply = <&vcc33_io>; + dvp-supply = <&vcc_18>; + flash0-supply = <&vcc18_flashio>; + gpio1830-supply = <&vcc33_io>; + gpio30-supply = <&vcc33_pmuio>; + lcdc-supply = <&vcc33_lcd>; + sdcard-supply = <&vccio_sd>; + wifi-supply = <&vcc18_wl>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/btemp.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/btemp.txt new file mode 100644 index 0000000000000000000000000000000000000000..f181e46d8e077c333fe3e6ea71d976bee0ec61a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/btemp.txt @@ -0,0 +1,16 @@ +=== AB8500 Battery Temperature Monitor Driver === + +The properties below describes the node for btemp driver. + +Required Properties: +- compatible = Shall be: "stericsson,ab8500-btemp" +- battery = Shall be battery specific information + + Example: + ab8500_btemp { + compatible = "stericsson,ab8500-btemp"; + battery = <&ab8500_battery>; + }; + +For information on battery specific node, Ref: +Documentation/devicetree/bindings/power/supply/ab8500/fg.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/chargalg.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/chargalg.txt new file mode 100644 index 0000000000000000000000000000000000000000..56636f927203e8398a6430d61b47da4b65cfed49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/chargalg.txt @@ -0,0 +1,16 @@ +=== AB8500 Charging Algorithm Driver === + +The properties below describes the node for chargalg driver. + +Required Properties: +- compatible = Shall be: "stericsson,ab8500-chargalg" +- battery = Shall be battery specific information + +Example: +ab8500_chargalg { + compatible = "stericsson,ab8500-chargalg"; + battery = <&ab8500_battery>; +}; + +For information on battery specific node, Ref: +Documentation/devicetree/bindings/power/supply/ab8500/fg.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..24ada03e07b4dda824fc479a61ce35ea18834dea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/charger.txt @@ -0,0 +1,25 @@ +=== AB8500 Charger Driver === + +Required Properties: +- compatible = Shall be "stericsson,ab8500-charger" +- battery = Shall be battery specific information + Example: + ab8500_charger { + compatible = "stericsson,ab8500-charger"; + battery = <&ab8500_battery>; + }; + +- vddadc-supply: Supply for USB and Main charger + Example: + ab8500-charger { + vddadc-supply = <&ab8500_ldo_tvout_reg>; + } +- autopower_cfg: + Boolean value depicting the presence of 'automatic poweron after powerloss' + Example: + ab8500-charger { + autopower_cfg; + }; + +For information on battery specific node, Ref: +Documentation/devicetree/bindings/power/supply/ab8500/fg.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/fg.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/fg.txt new file mode 100644 index 0000000000000000000000000000000000000000..ccafcb9112fb9294cc6508e9908807efaadf3dc4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ab8500/fg.txt @@ -0,0 +1,58 @@ +=== AB8500 Fuel Gauge Driver === + +AB8500 is a mixed signal multimedia and power management +device comprising: power and energy-management-module, +wall-charger, usb-charger, audio codec, general purpose adc, +tvout, clock management and sim card interface. + +Fuelgauge support is part of energy-management-modules, other +components of this module are: +main-charger, usb-combo-charger and battery-temperature-monitoring. + +The properties below describes the node for fuelgauge driver. + +Required Properties: +- compatible = This shall be: "stericsson,ab8500-fg" +- battery = Shall be battery specific information + Example: + ab8500_fg { + compatible = "stericsson,ab8500-fg"; + battery = <&ab8500_battery>; + }; + +dependent node: + ab8500_battery: ab8500_battery { + }; + This node will provide information on 'thermistor interface' and + 'battery technology type' used. + +Properties of this node are: +thermistor-on-batctrl: + A boolean value indicating thermistor interface to battery + + Note: + 'btemp' and 'batctrl' are the pins interfaced for battery temperature + measurement, 'btemp' signal is used when NTC(negative temperature + coefficient) resister is interfaced external to battery whereas + 'batctrl' pin is used when NTC resister is internal to battery. + + Example: + ab8500_battery: ab8500_battery { + thermistor-on-batctrl; + }; + indicates: NTC resister is internal to battery, 'batctrl' is used + for thermal measurement. + + The absence of property 'thermal-on-batctrl' indicates + NTC resister is external to battery and 'btemp' signal is used + for thermal measurement. + +battery-type: + This shall be the battery manufacturing technology type, + allowed types are: + "UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn" + Example: + ab8500_battery: ab8500_battery { + stericsson,battery-type = "LIPO"; + } + diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/act8945a-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/act8945a-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7dfb7cecf4048536c2e653d309a320c09ecde3e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/act8945a-charger.txt @@ -0,0 +1,44 @@ +Device-Tree bindings for charger of Active-semi ACT8945A Multi-Function Device + +Required properties: + - compatible: "active-semi,act8945a-charger". + - active-semi,chglev-gpios: charge current level phandle with args + as described in ../gpio/gpio.txt. + - active-semi,lbo-gpios: specify the low battery voltage detect phandle + with args as as described in ../gpio/gpio.txt. + - interrupts: where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. + +Optional properties: + - active-semi,input-voltage-threshold-microvolt: unit: mV; + Specifies the charger's input over-voltage threshold value; + The value can be: 6600, 7000, 7500, 8000; default: 6600 + - active-semi,precondition-timeout: unit: minutes; + Specifies the charger's PRECONDITION safety timer setting value; + The value can be: 40, 60, 80, 0; If 0, it means to disable this timer; + default: 40. + - active-semi,total-timeout: unit: hours; + Specifies the charger's total safety timer setting value; + The value can be: 3, 4, 5, 0; If 0, it means to disable this timer; + default: 3. + +Example: + pmic@5b { + compatible = "active-semi,act8945a"; + reg = <0x5b>; + + charger { + compatible = "active-semi,act8945a-charger"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>; + interrupt-parent = <&pioA>; + interrupts = <45 GPIO_ACTIVE_LOW>; + + active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>; + active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>; + active-semi,input-voltage-threshold-microvolt = <6600>; + active-semi,precondition-timeout = <40>; + active-semi,total-timeout = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_ac_power.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_ac_power.txt new file mode 100644 index 0000000000000000000000000000000000000000..826e8a8791211fd4501057e5d91d5ef6a11e3830 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_ac_power.txt @@ -0,0 +1,22 @@ +AXP20X and AXP22X PMICs' AC power supply + +Required Properties: + - compatible: One of: + "x-powers,axp202-ac-power-supply" + "x-powers,axp221-ac-power-supply" + +This node is a subnode of the axp20x PMIC. + +The AXP20X can read the current current and voltage supplied by AC by +reading ADC channels from the AXP20X ADC. + +The AXP22X is only able to tell if an AC power supply is present and +usable. + +Example: + +&axp209 { + ac_power_supply: ac-power-supply { + compatible = "x-powers,axp202-ac-power-supply"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..41916f69902c585bd422bf898f2e59f3d5599ce7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_battery.txt @@ -0,0 +1,20 @@ +AXP20x and AXP22x battery power supply + +Required Properties: + - compatible, one of: + "x-powers,axp209-battery-power-supply" + "x-powers,axp221-battery-power-supply" + "x-powers,axp813-battery-power-supply" + +This node is a subnode of its respective PMIC DT node. + +The supported devices can read the battery voltage, charge and discharge +currents of the battery by reading ADC channels from the ADC. + +Example: + +&axp209 { + battery_power_supply: battery-power-supply { + compatible = "x-powers,axp209-battery-power-supply"; + } +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_usb_power.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_usb_power.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba8d35f66cbe292e4ee42dd22b64c621467430dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/axp20x_usb_power.txt @@ -0,0 +1,40 @@ +AXP20x USB power supply + +Required Properties: +-compatible: One of: "x-powers,axp202-usb-power-supply" + "x-powers,axp221-usb-power-supply" + "x-powers,axp223-usb-power-supply" + +The AXP223 PMIC shares most of its behaviour with the AXP221 but has slight +variations such as the former being able to set the VBUS power supply max +current to 100mA, unlike the latter. + +This node is a subnode of the axp20x PMIC. + +Example: + +axp209: pmic@34 { + compatible = "x-powers,axp209"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupt-controller; + #interrupt-cells = <1>; + + regulators { + x-powers,dcdc-freq = <1500>; + + vdd_cpu: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1450000>; + regulator-name = "vdd-cpu"; + }; + + ... + }; + + usb-power-supply: usb-power-supply { + compatible = "x-powers,axp202-usb-power-supply"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4d3b4a10b43e284fecfbbe0571260d8b0e1b9cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/battery.txt @@ -0,0 +1,57 @@ +Battery Characteristics + +The devicetree battery node provides static battery characteristics. +In smart batteries, these are typically stored in non-volatile memory +on a fuel gauge chip. The battery node should be used where there is +no appropriate non-volatile memory, or it is unprogrammed/incorrect. + +Upstream dts files should not include battery nodes, unless the battery +represented cannot easily be replaced in the system by one of a +different type. This prevents unpredictable, potentially harmful, +behavior should a replacement that changes the battery type occur +without a corresponding update to the dtb. + +Required Properties: + - compatible: Must be "simple-battery" + +Optional Properties: + - voltage-min-design-microvolt: drained battery voltage + - energy-full-design-microwatt-hours: battery design energy + - charge-full-design-microamp-hours: battery design capacity + - precharge-current-microamp: current for pre-charge phase + - charge-term-current-microamp: current for charge termination phase + - constant-charge-current-max-microamp: maximum constant input current + - constant-charge-voltage-max-microvolt: maximum constant input voltage + +Battery properties are named, where possible, for the corresponding +elements in enum power_supply_property, defined in +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/power_supply.h + +Batteries must be referenced by chargers and/or fuel-gauges +using a phandle. The phandle's property should be named +"monitored-battery". + +Example: + + bat: battery { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3200000>; + energy-full-design-microwatt-hours = <5290000>; + charge-full-design-microamp-hours = <1430000>; + precharge-current-microamp = <256000>; + charge-term-current-microamp = <128000>; + constant-charge-current-max-microamp = <900000>; + constant-charge-voltage-max-microvolt = <4200000>; + }; + + charger: charger@11 { + .... + monitored-battery = <&bat>; + ... + }; + + fuel_gauge: fuel-gauge@22 { + .... + monitored-battery = <&bat>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/bq2415x.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq2415x.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0327f0b59addf018193ac4a133552a81a3fec05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq2415x.txt @@ -0,0 +1,47 @@ +Binding for TI bq2415x Li-Ion Charger + +Required properties: +- compatible: Should contain one of the following: + * "ti,bq24150" + * "ti,bq24150" + * "ti,bq24150a" + * "ti,bq24151" + * "ti,bq24151a" + * "ti,bq24152" + * "ti,bq24153" + * "ti,bq24153a" + * "ti,bq24155" + * "ti,bq24156" + * "ti,bq24156a" + * "ti,bq24158" +- reg: integer, i2c address of the device. +- ti,current-limit: integer, initial maximum current charger can pull + from power supply in mA. +- ti,weak-battery-voltage: integer, weak battery voltage threshold in mV. + The chip will use slow precharge if battery voltage + is below this value. +- ti,battery-regulation-voltage: integer, maximum charging voltage in mV. +- ti,charge-current: integer, maximum charging current in mA. +- ti,termination-current: integer, charge will be terminated when current in + constant-voltage phase drops below this value (in mA). +- ti,resistor-sense: integer, value of sensing resistor in milliohm. + +Optional properties: +- ti,usb-charger-detection: phandle to usb charger detection device. + (required for auto mode) + +Example from Nokia N900: + +bq24150a { + compatible = "ti,bq24150a"; + reg = <0x6b>; + + ti,current-limit = <100>; + ti,weak-battery-voltage = <3400>; + ti,battery-regulation-voltage = <4200>; + ti,charge-current = <650>; + ti,termination-current = <100>; + ti,resistor-sense = <68>; + + ti,usb-charger-detection = <&isp1704>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/bq24190.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq24190.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e517d307070ab9a461d11996d575e72b991650a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq24190.txt @@ -0,0 +1,51 @@ +TI BQ24190 Li-Ion Battery Charger + +Required properties: +- compatible: contains one of the following: + * "ti,bq24190" + * "ti,bq24192i" +- reg: integer, I2C address of the charger. +- interrupts[-extended]: configuration for charger INT pin. + +Optional properties: +- monitored-battery: phandle of battery characteristics devicetree node + The charger uses the following battery properties: + + precharge-current-microamp: maximum charge current during precharge + phase (typically 20% of battery capacity). + + charge-term-current-microamp: a charge cycle terminates when the + battery voltage is above recharge threshold, and the current is below + this setting (typically 10% of battery capacity). + See also Documentation/devicetree/bindings/power/supply/battery.txt +- ti,system-minimum-microvolt: when power is connected and the battery is below + minimum system voltage, the system will be regulated above this setting. + +Notes: +- Some circuit boards wire the chip's "OTG" pin high (enabling 500mA default + charge current on USB SDP ports, among other features). To simulate this on + boards that wire the pin to a GPIO, set a gpio-hog. + +Example: + + bat: battery { + compatible = "simple-battery"; + precharge-current-microamp = <256000>; + charge-term-current-microamp = <128000>; + // etc. + }; + + bq24190: charger@6a { + compatible = "ti,bq24190"; + reg = <0x6a>; + interrupts-extended = <&gpiochip 10 IRQ_TYPE_EDGE_FALLING>; + monitored-battery = <&bat>; + ti,system-minimum-microvolt = <3200000>; + }; + + &twl_gpio { + otg { + gpio-hog; + gpios = <6 0>; + output-high; + line-name = "otg-gpio"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/bq24257.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq24257.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8f5a1685bb956541bec8eeff61f44e49e58caf8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq24257.txt @@ -0,0 +1,62 @@ +Binding for TI bq24250/bq24251/bq24257 Li-Ion Charger + +Required properties: +- compatible: Should contain one of the following: + * "ti,bq24250" + * "ti,bq24251" + * "ti,bq24257" +- reg: integer, i2c address of the device. +- interrupts: Interrupt mapping for GPIO IRQ (configure for both edges). Use in + conjunction with "interrupt-parent". +- ti,battery-regulation-voltage: integer, maximum charging voltage in uV. +- ti,charge-current: integer, maximum charging current in uA. +- ti,termination-current: integer, charge will be terminated when current in + constant-voltage phase drops below this value (in uA). + +Optional properties: +- pg-gpios: GPIO used for connecting the bq2425x device PG (Power Good) pin. + This pin is not available on all devices however it should be used if + possible as this is the recommended way to obtain the charger's input PG + state. If this pin is not specified a software-based approach for PG + detection is used. +- ti,current-limit: The maximum current to be drawn from the charger's input + (in uA). If this property is not specified, the input limit current is + set automatically using USB D+/D- signal based charger type detection. + If the hardware does not support the D+/D- based detection, a default + of 500,000 is used (=500mA) instead. +- ti,ovp-voltage: Configures the over voltage protection voltage (in uV). If + not specified a default of 6,5000,000 (=6.5V) is used. +- ti,in-dpm-voltage: Configures the threshold input voltage for the dynamic + power path management (in uV). If not specified a default of 4,360,000 + (=4.36V) is used. + +Example: + +bq24257 { + compatible = "ti,bq24257"; + reg = <0x6a>; + interrupt-parent = <&gpio1>; + interrupts = <16 IRQ_TYPE_EDGE_BOTH>; + + pg-gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>; + + ti,battery-regulation-voltage = <4200000>; + ti,charge-current = <1000000>; + ti,termination-current = <50000>; +}; + +Example: + +bq24250 { + compatible = "ti,bq24250"; + reg = <0x6a>; + interrupt-parent = <&gpio1>; + interrupts = <16 IRQ_TYPE_EDGE_BOTH>; + + ti,battery-regulation-voltage = <4200000>; + ti,charge-current = <500000>; + ti,termination-current = <50000>; + ti,current-limit = <900000>; + ti,ovp-voltage = <9500000>; + ti,in-dpm-voltage = <4440000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/bq25890.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq25890.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9dd17d142adf9e33460c6cfbfed58e5aff201f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq25890.txt @@ -0,0 +1,46 @@ +Binding for TI bq25890 Li-Ion Charger + +Required properties: +- compatible: Should contain one of the following: + * "ti,bq25890" +- reg: integer, i2c address of the device. +- ti,battery-regulation-voltage: integer, maximum charging voltage (in uV); +- ti,charge-current: integer, maximum charging current (in uA); +- ti,termination-current: integer, charge will be terminated when current in + constant-voltage phase drops below this value (in uA); +- ti,precharge-current: integer, maximum charge current during precharge + phase (in uA); +- ti,minimum-sys-voltage: integer, when battery is charging and it is below + minimum system voltage, the system will be regulated above + minimum-sys-voltage setting (in uV); +- ti,boost-voltage: integer, VBUS voltage level in boost mode (in uV); +- ti,boost-max-current: integer, maximum allowed current draw in boost mode + (in uA). + +Optional properties: +- ti,boost-low-freq: boolean, if present boost mode frequency will be 500kHz, + otherwise 1.5MHz; +- ti,use-ilim-pin: boolean, if present the ILIM resistor will be used and the + input current will be the lower between the resistor setting and the IINLIM + register setting; +- ti,thermal-regulation-threshold: integer, temperature above which the charge + current is lowered, to avoid overheating (in degrees Celsius). If omitted, + the default setting will be used (120 degrees); + +Example: + +bq25890 { + compatible = "ti,bq25890"; + reg = <0x6a>; + + ti,battery-regulation-voltage = <4200000>; + ti,charge-current = <1000000>; + ti,termination-current = <50000>; + ti,precharge-current = <128000>; + ti,minimum-sys-voltage = <3600000>; + ti,boost-voltage = <5000000>; + ti,boost-max-current = <1000000>; + + ti,use-ilim-pin; + ti,thermal-regulation-threshold = <120>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/bq27xxx.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq27xxx.txt new file mode 100644 index 0000000000000000000000000000000000000000..37994fdb18cae7afec76cded46b009e11de8dfaf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/bq27xxx.txt @@ -0,0 +1,55 @@ +TI BQ27XXX fuel gauge family + +Required properties: +- compatible: contains one of the following: + * "ti,bq27200" - BQ27200 + * "ti,bq27210" - BQ27210 + * "ti,bq27500" - deprecated, use revision specific property below + * "ti,bq27510" - deprecated, use revision specific property below + * "ti,bq27520" - deprecated, use revision specific property below + * "ti,bq27500-1" - BQ27500/1 + * "ti,bq27510g1" - BQ27510-g1 + * "ti,bq27510g2" - BQ27510-g2 + * "ti,bq27510g3" - BQ27510-g3 + * "ti,bq27520g1" - BQ27520-g1 + * "ti,bq27520g2" - BQ27520-g2 + * "ti,bq27520g3" - BQ27520-g3 + * "ti,bq27520g4" - BQ27520-g4 + * "ti,bq27521" - BQ27521 + * "ti,bq27530" - BQ27530 + * "ti,bq27531" - BQ27531 + * "ti,bq27541" - BQ27541 + * "ti,bq27542" - BQ27542 + * "ti,bq27546" - BQ27546 + * "ti,bq27742" - BQ27742 + * "ti,bq27545" - BQ27545 + * "ti,bq27421" - BQ27421 + * "ti,bq27425" - BQ27425 + * "ti,bq27426" - BQ27426 + * "ti,bq27441" - BQ27441 + * "ti,bq27621" - BQ27621 +- reg: integer, I2C address of the fuel gauge. + +Optional properties: +- monitored-battery: phandle of battery characteristics node + The fuel gauge uses the following battery properties: + + energy-full-design-microwatt-hours + + charge-full-design-microamp-hours + + voltage-min-design-microvolt + Both or neither of the *-full-design-*-hours properties must be set. + See Documentation/devicetree/bindings/power/supply/battery.txt + +Example: + + bat: battery { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3200000>; + energy-full-design-microwatt-hours = <5290000>; + charge-full-design-microamp-hours = <1430000>; + }; + + bq27510g3: fuel-gauge@55 { + compatible = "ti,bq27510g3"; + reg = <0x55>; + monitored-battery = <&bat>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/charger-manager.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/charger-manager.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec4fe9de313735a8b15225da1f53889b67342829 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/charger-manager.txt @@ -0,0 +1,81 @@ +charger-manager bindings +~~~~~~~~~~~~~~~~~~~~~~~~ + +Required properties : + - compatible : "charger-manager" + - <>-supply : for regulator consumer + - cm-num-chargers : number of chargers + - cm-chargers : name of chargers + - cm-fuel-gauge : name of battery fuel gauge + - subnode : + - cm-regulator-name : name of charger regulator + - subnode : + - cm-cable-name : name of charger cable + - cm-cable-extcon : name of extcon dev +(optional) - cm-cable-min : minimum current of cable +(optional) - cm-cable-max : maximum current of cable + +Optional properties : + - cm-name : charger manager's name (default : "battery") + - cm-poll-mode : polling mode (enum polling_modes) + - cm-poll-interval : polling interval + - cm-battery-stat : battery status (enum data_source) + - cm-fullbatt-* : data for full battery checking + - cm-thermal-zone : name of external thermometer's thermal zone + - cm-battery-* : threshold battery temperature for charging + -cold : critical cold temperature of battery for charging + -cold-in-minus : flag that cold temperature is in minus degrees + -hot : critical hot temperature of battery for charging + -temp-diff : temperature difference to allow recharging + - cm-dis/charging-max = limits of charging duration + +Example : + charger-manager@0 { + compatible = "charger-manager"; + chg-reg-supply = <&charger_regulator>; + + cm-name = "battery"; + /* Always polling ON : 30s */ + cm-poll-mode = <1>; + cm-poll-interval = <30000>; + + cm-fullbatt-vchkdrop-ms = <30000>; + cm-fullbatt-vchkdrop-volt = <150000>; + cm-fullbatt-soc = <100>; + + cm-battery-stat = <3>; + + cm-num-chargers = <3>; + cm-chargers = "charger0", "charger1", "charger2"; + + cm-fuel-gauge = "fuelgauge0"; + + cm-thermal-zone = "thermal_zone.1" + /* in deci centigrade */ + cm-battery-cold = <50>; + cm-battery-cold-in-minus; + cm-battery-hot = <800>; + cm-battery-temp-diff = <100>; + + /* Allow charging for 5hr */ + cm-charging-max = <18000000>; + /* Allow discharging for 2hr */ + cm-discharging-max = <7200000>; + + regulator@0 { + cm-regulator-name = "chg-reg"; + cable@0 { + cm-cable-name = "USB"; + cm-cable-extcon = "extcon-dev.0"; + cm-cable-min = <475000>; + cm-cable-max = <500000>; + }; + cable@1 { + cm-cable-name = "TA"; + cm-cable-extcon = "extcon-dev.0"; + cm-cable-min = <650000>; + cm-cable-max = <675000>; + }; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/cpcap-battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/cpcap-battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..a04efa22da0181911f446bb95f93c3fb431935a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/cpcap-battery.txt @@ -0,0 +1,31 @@ +Motorola CPCAP PMIC battery driver binding + +Required properties: +- compatible: Shall be "motorola,cpcap-battery" +- interrupts: Interrupt specifier for each name in interrupt-names +- interrupt-names: Should contain the following entries: + "lowbph", "lowbpl", "chrgcurr1", "battdetb" +- io-channels: IIO ADC channel specifier for each name in io-channel-names +- io-channel-names: Should contain the following entries: + "battdetb", "battp", "chg_isense", "batti" +- power-supplies: List of phandles for power-supplying devices, as + described in power_supply.txt. Typically a reference + to cpcap_charger. + +Example: + +cpcap_battery: battery { + compatible = "motorola,cpcap-battery"; + interrupts-extended = < + &cpcap 5 0 &cpcap 3 0 + &cpcap 20 0 &cpcap 54 0 + >; + interrupt-names = + "lowbph", "lowbpl", + "chrgcurr1", "battdetb"; + io-channels = <&cpcap_adc 0 &cpcap_adc 1 + &cpcap_adc 5 &cpcap_adc 6>; + io-channel-names = "battdetb", "battp", + "chg_isense", "batti"; + power-supplies = <&cpcap_charger>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/cpcap-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/cpcap-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..80bd873c3b1de4c2db3612f0fa0fe302fca3c1fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/cpcap-charger.txt @@ -0,0 +1,37 @@ +Motorola CPCAP PMIC battery charger binding + +Required properties: +- compatible: Shall be "motorola,mapphone-cpcap-charger" +- interrupts: Interrupt specifier for each name in interrupt-names +- interrupt-names: Should contain the following entries: + "chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", + "rvrs_mode", "chrgcurr1", "vbusvld", "battdetb" +- io-channels: IIO ADC channel specifier for each name in io-channel-names +- io-channel-names: Should contain the following entries: + "battdetb", "battp", "vbus", "chg_isense", "batti" + +Optional properties: +- mode-gpios: Optionally CPCAP charger can have a companion wireless + charge controller that is controlled with two GPIOs + that are active low. + +Example: + +cpcap_charger: charger { + compatible = "motorola,mapphone-cpcap-charger"; + interrupts-extended = < + &cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0 + &cpcap 22 0 &cpcap 20 0 &cpcap 19 0 &cpcap 54 0 + >; + interrupt-names = + "chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn", + "rvrs_mode", "chrgcurr1", "vbusvld", "battdetb"; + mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW + &gpio3 23 GPIO_ACTIVE_LOW>; + io-channels = <&cpcap_adc 0 &cpcap_adc 1 + &cpcap_adc 2 &cpcap_adc 5 + &cpcap_adc 6>; + io-channel-names = "battdetb", "battp", + "vbus", "chg_isense", + "batti"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/da9150-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/da9150-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3906663c45453dbd31e71ca277f45e4997a2a13 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/da9150-charger.txt @@ -0,0 +1,26 @@ +Dialog Semiconductor DA9150 Charger Power Supply bindings + +Required properties: +- compatible: "dlg,da9150-charger" for DA9150 Charger Power Supply + +Optional properties: +- io-channels: List of phandle and IIO specifier pairs +- io-channel-names: List of channel names used by charger + ["CHAN_IBUS", "CHAN_VBUS", "CHAN_TJUNC", "CHAN_VBAT"] + (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info) + + +Example: + + da9150-charger { + compatible = "dlg,da9150-charger"; + + io-channels = <&gpadc 0>, + <&gpadc 2>, + <&gpadc 8>, + <&gpadc 5>; + io-channel-names = "CHAN_IBUS", + "CHAN_VBUS", + "CHAN_TJUNC", + "CHAN_VBAT"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/da9150-fg.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/da9150-fg.txt new file mode 100644 index 0000000000000000000000000000000000000000..00236fe3ea319c92f0b01b46bc17b75a76b5e881 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/da9150-fg.txt @@ -0,0 +1,23 @@ +Dialog Semiconductor DA9150 Fuel-Gauge Power Supply bindings + +Required properties: +- compatible: "dlg,da9150-fuel-gauge" for DA9150 Fuel-Gauge Power Supply + +Optional properties: +- dlg,update-interval: Interval time (milliseconds) between battery level checks. +- dlg,warn-soc-level: Battery discharge level (%) where warning event raised. + [1 - 100] +- dlg,crit-soc-level: Battery discharge level (%) where critical event raised. + This value should be lower than the warning level. + [1 - 100] + + +Example: + + fuel-gauge { + compatible = "dlg,da9150-fuel-gauge"; + + dlg,update-interval = <10000>; + dlg,warn-soc-level = /bits/ 8 <15>; + dlg,crit-soc-level = /bits/ 8 <5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/gpio-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/gpio-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..adbb5dc5b6e9ec05f54986a0bd40fccc36372a7c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/gpio-charger.txt @@ -0,0 +1,27 @@ +gpio-charger + +Required properties : + - compatible : "gpio-charger" + - gpios : GPIO indicating the charger presence. + See GPIO binding in bindings/gpio/gpio.txt . + - charger-type : power supply type, one of + unknown + battery + ups + mains + usb-sdp (USB standard downstream port) + usb-dcp (USB dedicated charging port) + usb-cdp (USB charging downstream port) + usb-aca (USB accessory charger adapter) + +Example: + + usb_charger: charger { + compatible = "gpio-charger"; + charger-type = "usb-sdp"; + gpios = <&gpf0 2 0 0 0>; + } + + battery { + power-supplies = <&usb_charger>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/hl6111r.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/hl6111r.txt new file mode 100644 index 0000000000000000000000000000000000000000..932ddfbfa7d3752f52a0c9083499dca217053606 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/hl6111r.txt @@ -0,0 +1,26 @@ +Halo Microelectronics Co. Ltd. HL6111R Specific Bindings + +HL6111R is a wireless charging power receiver IC that has a maximum +power output of 15 W, a maximum current output of 2.2 A, and a +programmable output voltage range of 4 V to 20 V with different step +sizes. It supports both the A4WP and WPC wireless charging standards. + +Required properties: + +- compatible + Usage: required + Value type: + Definition: Must be "halo,hl6111r" + +- reg + Usage: required + Value type: + Definition: 7-bit I2C address of the device. + +Example: + +halo,hl6111r@25 { + compatible = "halo,hl6111r"; + reg = <0x25>; + status = "ok"; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/isp1704.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/isp1704.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa3596907967ea4a358bc95611d5af6d69cbea73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/isp1704.txt @@ -0,0 +1,17 @@ +Binding for NXP ISP1704 USB Charger Detection + +Required properties: +- compatible: Should contain one of the following: + * "nxp,isp1704" +- nxp,enable-gpio: Should contain a phandle + gpio-specifier + to the GPIO pin connected to the chip's enable pin. +- usb-phy: Should contain a phandle to the USB PHY + the ISP1704 is connected to. + +Example: + +isp1704 { + compatible = "nxp,isp1704"; + nxp,enable-gpio = <&gpio3 3 GPIO_ACTIVE_LOW>; + usb-phy = <&usb2_phy>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/lego_ev3_battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/lego_ev3_battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..5485633b1faa4798909892c4a9d8c0b2de362c5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/lego_ev3_battery.txt @@ -0,0 +1,21 @@ +LEGO MINDSTORMS EV3 Battery +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LEGO MINDSTORMS EV3 has some built-in capability for monitoring the battery. +It uses 6 AA batteries or a special Li-ion rechargeable battery pack that is +detected by a key switch in the battery compartment. + +Required properties: + - compatible: Must be "lego,ev3-battery" + - io-channels: phandles to analog inputs for reading voltage and current + - io-channel-names: Must be "voltage", "current" + - rechargeable-gpios: phandle to the rechargeable battery indication gpio + +Example: + + battery { + compatible = "lego,ev3-battery"; + io-channels = <&adc 4>, <&adc 3>; + io-channel-names = "voltage", "current"; + rechargeable-gpios = <&gpio 136 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/lp8727_charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/lp8727_charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..0355a4b68f79afac3c5b271605603e66c09c9b24 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/lp8727_charger.txt @@ -0,0 +1,43 @@ +Binding for TI/National Semiconductor LP8727 Charger + +Required properties: +- compatible: "ti,lp8727" +- reg: I2C slave address 27h + +Optional properties: +- interrupts: interrupt specifier (see interrupt binding[0]) +- debounce-ms: interrupt debounce time. (u32) + +AC and USB charging parameters +- charger-type: "ac" or "usb" (string) +- eoc-level: value of 'enum lp8727_eoc_level' (u8) +- charging-current: value of 'enum lp8727_ichg' (u8) + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + +Example) + +lp8727@27 { + compatible = "ti,lp8727"; + reg = <0x27>; + + /* GPIO 134 is used for LP8728 interrupt pin */ + interrupt-parent = <&gpio5>; /* base = 128 */ + interrupts = <6 0x2>; /* offset = 6, falling edge type */ + + debounce-ms = <300>; + + /* AC charger: 5% EOC and 500mA charging current */ + ac { + charger-type = "ac"; + eoc-level = /bits/ 8 <0>; + charging-current = /bits/ 8 <4>; + }; + + /* USB charger: 10% EOC and 400mA charging current */ + usb { + charger-type = "usb"; + eoc-level = /bits/ 8 <1>; + charging-current = /bits/ 8 <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ltc2941.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ltc2941.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b9ba147b04171c748cfd4aaac12c6d8692a85d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ltc2941.txt @@ -0,0 +1,28 @@ +binding for LTC2941, LTC2942, LTC2943 and LTC2944 battery gauges + +All chips measure battery capacity. +The LTC2942 is pin compatible with the LTC2941, it adds voltage and +temperature monitoring, and is runtime detected. LTC2943 and LTC2944 +is software compatible, uses a slightly different conversion formula +for the charge counter and adds voltage, current and temperature monitoring. + +Required properties: +- compatible: Should contain "lltc,ltc2941", "lltc,ltc2942", "lltc,ltc2943" + or "lltc,ltc2944" which also indicates the type of I2C chip attached. +- reg: The 7-bit I2C address. +- lltc,resistor-sense: The sense resistor value in milli-ohms. Can be a 32-bit + negative value when the battery has been connected to the wrong end of the + resistor. +- lltc,prescaler-exponent: The prescaler exponent as explained in the datasheet. + This determines the range and accuracy of the gauge. The value is programmed + into the chip only if it differs from the current setting. The setting is + lost when the battery is disconnected. + +Example from the Topic Miami Florida board: + + fuelgauge: ltc2943@64 { + compatible = "lltc,ltc2943"; + reg = <0x64>; + lltc,resistor-sense = <15>; + lltc,prescaler-exponent = <5>; /* 2^(2*5) = 1024 */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ltc3651-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ltc3651-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..71f2840e82098eef341143f360224a8e42ab23be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ltc3651-charger.txt @@ -0,0 +1,27 @@ +ltc3651-charger + +Required properties: + - compatible: "lltc,ltc3651-charger" + - lltc,acpr-gpios: Connect to ACPR output. See remark below. + +Optional properties: + - lltc,fault-gpios: Connect to FAULT output. See remark below. + - lltc,chrg-gpios: Connect to CHRG output. See remark below. + +The ltc3651 outputs are open-drain type and active low. The driver assumes the +GPIO reports "active" when the output is asserted, so if the pins have been +connected directly, the GPIO flags should be set to active low also. + +The driver will attempt to aquire interrupts for all GPIOs to detect changes in +line state. If the system is not capabale of providing interrupts, the driver +cannot report changes and userspace will need to periodically read the sysfs +attributes to detect changes. + +Example: + + charger: battery-charger { + compatible = "lltc,ltc3651-charger"; + lltc,acpr-gpios = <&gpio0 68 GPIO_ACTIVE_LOW>; + lltc,fault-gpios = <&gpio0 64 GPIO_ACTIVE_LOW>; + lltc,chrg-gpios = <&gpio0 63 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/max17042_battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/max17042_battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f3894aaeebcf9f02f3505f4ad675c99e0d14460 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/max17042_battery.txt @@ -0,0 +1,31 @@ +max17042_battery +~~~~~~~~~~~~~~~~ + +Required properties : + - compatible : "maxim,max17042" + +Optional properties : + - maxim,rsns-microohm : Resistance of rsns resistor in micro Ohms + (datasheet-recommended value is 10000). + Defining this property enables current-sense functionality. + +Optional threshold properties : + If skipped the condition won't be reported. + - maxim,cold-temp : Temperature threshold to report battery + as cold (in tenths of degree Celsius). + - maxim,over-heat-temp : Temperature threshold to report battery + as over heated (in tenths of degree Celsius). + - maxim,dead-volt : Voltage threshold to report battery + as dead (in mV). + - maxim,over-volt : Voltage threshold to report battery + as over voltage (in mV). + +Example: + + battery-charger@36 { + compatible = "maxim,max17042"; + reg = <0x36>; + maxim,rsns-microohm = <10000>; + maxim,over-heat-temp = <600>; + maxim,over-volt = <4300>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/max8903-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/max8903-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..bab947fef025e5250a299934877800c1881c8799 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/max8903-charger.txt @@ -0,0 +1,24 @@ +Maxim Semiconductor MAX8903 Battery Charger bindings + +Required properties: +- compatible: "maxim,max8903" for MAX8903 Battery Charger +- dok-gpios: Valid DC power has been detected (active low, input), optional if uok-gpios is provided +- uok-gpios: Valid USB power has been detected (active low, input), optional if dok-gpios is provided + +Optional properties: +- cen-gpios: Charge enable pin (active low, output) +- chg-gpios: Charger status pin (active low, input) +- flt-gpios: Fault pin (active low, output) +- dcm-gpios: Current limit mode setting (DC=1 or USB=0, output) +- usus-gpios: USB suspend pin (active high, output) + + +Example: + + max8903-charger { + compatible = "maxim,max8903"; + dok-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; + flt-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>; + chg-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; + cen-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/max8925_battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/max8925_battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7e3e0c0f71d8828e245af828360e6efc38122d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/max8925_battery.txt @@ -0,0 +1,18 @@ +max8925-battery bindings +~~~~~~~~~~~~~~~~ + +Optional properties : + - batt-detect: whether support battery detect + - topoff-threshold: set charging current in topoff mode + - fast-charge: set charging current in fast mode + - no-temp-support: whether support temperature protection detect + - no-insert-detect: whether support insert detect + +Example: + charger { + batt-detect = <0>; + topoff-threshold = <1>; + fast-charge = <7>; + no-temp-support = <0>; + no-insert-detect = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/maxim,ds2760.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/maxim,ds2760.txt new file mode 100644 index 0000000000000000000000000000000000000000..55967a0bee11a37f23cb1bf069fa44b192793ce1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/maxim,ds2760.txt @@ -0,0 +1,26 @@ +Devicetree bindings for Maxim DS2760 +==================================== + +The ds2760 is a w1 slave device and must hence have its sub-node in DT +under a w1 bus master node. + +The device exposes a power supply, so the details described in +Documentation/devicetree/bindings/power/supply/power_supply.txt apply. + +Required properties: +- compatible: must be "maxim,ds2760" + +Optional properties: +- power-supplies: Refers to one or more power supplies connected to + this battery. +- maxim,pmod-enabled: This boolean property enables the DS2760 to enter + sleep mode when the DQ line goes low for greater + than 2 seconds and leave sleep Mode when the DQ + line goes high. +- maxim,cache-time-ms: Time im milliseconds to cache the data for. When + this time expires, the values are read again from + the hardware. Defaults to 1000. +- rated-capacity-microamp-hours: + The rated capacity of the battery, in mAh. + If not specified, the value stored in the + non-volatile chip memory is used. diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/maxim,max14656.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/maxim,max14656.txt new file mode 100644 index 0000000000000000000000000000000000000000..f956247d493e8479dbd8484724f8acc078eb7bdd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/maxim,max14656.txt @@ -0,0 +1,23 @@ +Maxim MAX14656 / AL32 USB Charger Detector + +Required properties : +- compatible : "maxim,max14656"; +- reg: i2c slave address +- interrupts: interrupt line + +Example: + +&i2c2 { + clock-frequency = <50000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + + max14656@35 { + compatible = "maxim,max14656"; + reg = <0x35>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_charger_detect>; + interrupt-parent = <&gpio6>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/olpc_battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/olpc_battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8901b3992d9cac28620df3063be44233d282233 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/olpc_battery.txt @@ -0,0 +1,5 @@ +OLPC battery +~~~~~~~~~~~~ + +Required properties: + - compatible : "olpc,xo1-battery" diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/power_supply.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/power_supply.txt new file mode 100644 index 0000000000000000000000000000000000000000..8391bfa0edac50cd463db1830ca83628251812a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/power_supply.txt @@ -0,0 +1,23 @@ +Power Supply Core Support + +Optional Properties: + - power-supplies : This property is added to a supply in order to list the + devices which supply it power, referenced by their phandles. + +Example: + + usb-charger: power@e { + compatible = "some,usb-charger"; + ... + }; + + ac-charger: power@c { + compatible = "some,ac-charger"; + ... + }; + + battery@b { + compatible = "some,battery"; + ... + power-supplies = <&usb-charger>, <&ac-charger>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom,coincell-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom,coincell-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..747899223262fbc8b44867e39c1b5d7a09a16c88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom,coincell-charger.txt @@ -0,0 +1,48 @@ +Qualcomm Coincell Charger: + +The hardware block controls charging for a coincell or capacitor that is +used to provide power backup for certain features of the power management +IC (PMIC) + +- compatible: + Usage: required + Value type: + Definition: must be: "qcom,pm8941-coincell" + +- reg: + Usage: required + Value type: + Definition: base address of the coincell charger registers + +- qcom,rset-ohms: + Usage: required + Value type: + Definition: resistance (in ohms) for current-limiting resistor + must be one of: 800, 1200, 1700, 2100 + +- qcom,vset-millivolts: + Usage: required + Value type: + Definition: voltage (in millivolts) to apply for charging + must be one of: 2500, 3000, 3100, 3200 + +- qcom,charger-disable: + Usage: optional + Value type: + Definition: defining this property disables charging + +This charger is a sub-node of one of the 8941 PMIC blocks, and is specified +as a child node in DTS of that node. See ../mfd/qcom,spmi-pmic.txt and +../mfd/qcom-pm8xxx.txt + +Example: + + pm8941@0 { + coincell@2800 { + compatible = "qcom,pm8941-coincell"; + reg = <0x2800>; + + qcom,rset-ohms = <2100>; + qcom,vset-millivolts = <3000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-fg-gen3.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-fg-gen3.txt new file mode 100644 index 0000000000000000000000000000000000000000..099d3b2dfab9391ee255648610b396e75b33f2a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-fg-gen3.txt @@ -0,0 +1,535 @@ +Qualcomm Technologies, Inc. QPNP PMIC Fuel Gauge Gen3 Device + +QPNP PMIC FG Gen3 device provides interface to the clients to read properties +related to the battery. Its main function is to retrieve the State of Charge +(SOC), in percentage scale representing the amount of charge left in the +battery. + +======================= +Required Node Structure +======================= + +FG Gen3 device must be described in two levels of device nodes. The first +level describes the FG Gen3 device. The second level describes one or more +peripherals managed by FG Gen3 driver. All the peripheral specific parameters +such as base address, interrupts etc., should be under second level node. + +==================================== +First Level Node - FG Gen3 device +==================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,fg-gen3". + +- qcom,pmic-revid + Usage: required + Value type: + Definition: Should specify the phandle of PMIC revid module. This is + used to identify the PMIC subtype. + +- io-channels +- io-channel-names + Usage: required + Value type: + Definition: For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- qcom,rradc-base + Usage: required + Value type: + Definition: Should specify the base address of RR_ADC peripheral. This + is used for reading certain peripheral registers under it. + +- qcom,fg-cutoff-voltage + Usage: optional + Value type: + Definition: The voltage (in mV) where the fuel gauge will steer the SOC + to be zero. For example, if the cutoff voltage is set to + 3400mv, the fuel gauge will try to count SoC so that the + battery SOC will be 0 when it is 3400mV. If this property + is not specified, then the default value used will be + 3200mV. + +- qcom,fg-empty-voltage + Usage: optional + Value type: + Definition: The voltage threshold (in mV) based on which the empty soc + interrupt will be triggered. When the empty soc interrupt + fires, battery soc will be set to 0 and the userspace will + be notified via the power supply framework. The userspace + will read 0% soc and immediately shutdown. If this property + is not specified, then the default value used will be + 2800mV. + +- qcom,fg-vbatt-low-thr + Usage: optional + Value type: + Definition: The voltage threshold (in mV) which upon set will be used + for configuring the low battery voltage threshold. + +- qcom,fg-recharge-voltage + Usage: optional + Value type: + Definition: The voltage threshold (in mV) based on which the charging + will be resumed once the charging is complete. If this + property is not specified, then the default value will be + 4250mV. + +- qcom,fg-chg-term-current + Usage: optional + Value type: + Definition: Battery current (in mA) at which the fuel gauge will issue + an end of charge if the charger is configured to use the + fuel gauge ADC for end of charge detection. If this + property is not specified, then the default value used + will be 100mA. + +- qcom,fg-sys-term-current + Usage: optional + Value type: + Definition: Battery current (in mA) at which the fuel gauge will try to + scale towards 100%. When the charge current goes above this + the SOC should be at 100%. If this property is not + specified, then the default value used will be -125mA. + This value has to be specified in negative values for + the charging current. + +- qcom,fg-chg-term-base-current + Usage: optional + Value type: + Definition: Battery current (in mA) upper boundary at which the fuel + gauge will issue an end of charge during discharging. If + this property is not specified, then the default value used + will be 75mA. + +- qcom,fg-cutoff-current + Usage: optional + Value type: + Definition: Minimum Battery current (in mA) used for cutoff SOC + estimate. If this property is not specified, then a default + value of 500 mA will be applied. + +- qcom,fg-delta-soc-thr + Usage: optional + Value type: + Definition: Percentage of SOC increase upon which the delta monotonic & + battery SOC interrupts will be triggered. If this property + is not specified, then the default value will be 1. + Possible values are in the range of 0 to 12. + +- qcom,fg-recharge-soc-thr + Usage: optional + Value type: + Definition: Percentage of monotonic SOC upon which the charging will + will be resumed once the charging is complete. If this + property is not specified, then the default value will be + 95. + +- qcom,fg-rsense-sel + Usage: optional + Value type: + Definition: Specifies the source of sense resistor. + Allowed values are: + 0 - Rsense is from Battery FET + 2 - Rsense is Battery FET and SMB + Option 2 can be used only when a parallel charger is + present. If this property is not specified, then the + default value will be 2. + +- qcom,fg-jeita-thresholds + Usage: optional + Value type: + Definition: A list of integers which holds the jeita thresholds (degC) + in the following order. Allowed size is 4. + Element 0 - JEITA cold threshold + Element 1 - JEITA cool threshold + Element 2 - JEITA warm threshold + Element 3 - JEITA hot threshold + If these parameters are not specified, then the default + values used will be 0, 5, 45, 50. + +- qcom,fg-esr-timer-charging + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the battery is + charging. Array of 2 elements if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-timer-awake + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the system is + awake and the battery is discharging. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-timer-asleep + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the system is + asleep and the battery is discharging. This option requires + qcom,fg-esr-timer-awake to be defined. Array of 2 elements + if specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-timer-shutdown + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses at/after shutdwon.This is + defined when TWM (traditional watch mode) is supported. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-pulse-thresh-ma + Usage: optional + Value type: + Definition: ESR pulse qualification threshold in mA. If this is not + specified, a default value of 110 mA will be configured. + Allowed values are from 1 to 997. + +- qcom,fg-esr-meas-curr-ma + Usage: optional + Value type: + Definition: ESR measurement current in mA. If this is not specified, + a default value of 120 mA will be configured. Allowed + values are 60, 120, 180 and 240. + +- qcom,cycle-counter-en + Usage: optional + Value type: + Definition: Enables the cycle counter feature. + +- qcom,fg-force-load-profile + Usage: optional + Value type: + Definition: If set, battery profile will be force loaded if the profile + loaded earlier by bootloader doesn't match with the profile + available in the device tree. + +- qcom,cl-start-capacity + Usage: optional + Value type: + Definition: Battery SOC threshold to start the capacity learning. + If this is not specified, then the default value used + will be 15. + +- qcom,cl-min-temp + Usage: optional + Value type: + Definition: Lower limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 150 (15 C). Unit is in decidegC. + +- qcom,cl-max-temp + Usage: optional + Value type: + Definition: Upper limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 500 (50 C). Unit is in decidegC. + +- qcom,cl-max-increment + Usage: optional + Value type: + Definition: Maximum capacity increment allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 5 (0.5%). Unit is in decipercentage. + +- qcom,cl-max-decrement + Usage: optional + Value type: + Definition: Maximum capacity decrement allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 100 (10%). Unit is in decipercentage. + +- qcom,cl-min-limit + Usage: optional + Value type: + Definition: Minimum limit that the capacity cannot go below in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-max-limit + Usage: optional + Value type: + Definition: Maximum limit that the capacity cannot go above in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,battery-thermal-coefficients + Usage: optional + Value type: + Definition: Byte array of battery thermal coefficients. + This should be exactly 3 bytes in length. + +- qcom,fg-jeita-hyst-temp + Usage: optional + Value type: + Definition: Hysteresis applied to Jeita temperature comparison. + Possible values are: + 0 - No hysteresis + 1,2,3 - Value in Celsius. + +- qcom,fg-batt-temp-delta + Usage: optional + Value type: + Definition: Battery temperature delta interrupt threshold. Possible + values are: 2, 4, 6 and 10. Unit is in Kelvin. + +- qcom,hold-soc-while-full + Usage: optional + Value type: + Definition: A boolean property that when defined holds SOC at 100% when + the battery is full. + +- qcom,linearize-soc + Usage: optional + Value type: + Definition: A boolean property that when defined linearizes SOC when + the SOC drops after charge termination monotonically to + improve the user experience. This is applicable only if + "qcom,hold-soc-while-full" is specified. + +- qcom,ki-coeff-soc-dischg + Usage: optional + Value type: + Definition: Array of monotonic SOC threshold values to change the ki + coefficient for medium discharge current during discharge. + This should be defined in the ascending order and in the + range of 0-100. Array limit is set to 3. + +- qcom,ki-coeff-med-dischg + Usage: optional + Value type: + Definition: Array of ki coefficient values for medium discharge current + during discharge. These values will be applied when the + monotonic SOC goes below the SOC threshold specified under + qcom,ki-coeff-soc-dischg. Array limit is set to 3. This + property should be specified if qcom,ki-coeff-soc-dischg + is specified to make it fully functional. Value has no + unit. Allowed range is 0 to 62200 in micro units. + +- qcom,ki-coeff-hi-dischg + Usage: optional + Value type: + Definition: Array of ki coefficient values for high discharge current + during discharge. These values will be applied when the + monotonic SOC goes below the SOC threshold specified under + qcom,ki-coeff-soc-dischg. Array limit is set to 3. This + property should be specified if qcom,ki-coeff-soc-dischg + is specified to make it fully functional. Value has no + unit. Allowed range is 0 to 62200 in micro units. + +- qcom,ki-coeff-full-dischg + Usage: optional + Value type: + Definition: Ki coefficient full SOC value that will be applied during + discharging. If not specified, a value of 0 will be set. + Allowed range is from 245 to 62256. + +- qcom,fg-rconn-mohms + Usage: optional + Value type: + Definition: Battery connector resistance (Rconn) in milliohms. If Rconn + is specified, then ESR to Rslow scaling factors will be + updated to account it for an accurate ESR. + +- qcom,fg-esr-clamp-mohms + Usage: optional + Value type: + Definition: Equivalent series resistance (ESR) in milliohms. If this + is specified, then ESR will be clamped to this value when + ESR is found to be dropping below this. Default value is + 20. + +- qcom,fg-esr-filter-switch-temp + Usage: optional + Value type: + Definition: Battery temperature threshold below which low temperature + ESR filter coefficients will be switched to normal + temperature ESR filter coefficients. If this is not + specified, then the default value used will be 100. Unit is + in decidegC. + +- qcom,fg-esr-tight-filter-micro-pct + Usage: optional + Value type: + Definition: Value in micro percentage for ESR tight filter. If this is + not specified, then a default value of 3907 (0.39 %) will + be used. Lowest possible value is 1954 (0.19 %). + +- qcom,fg-esr-broad-filter-micro-pct + Usage: optional + Value type: + Definition: Value in micro percentage for ESR broad filter. If this is + not specified, then a default value of 99610 (9.96 %) will + be used. Lowest possible value is 1954 (0.19 %). + +- qcom,fg-esr-tight-lt-filter-micro-pct + Usage: optional + Value type: + Definition: Value in micro percentage for low temperature ESR tight + filter. If this is not specified, then a default value of + 30000 (3 %) will be used. Lowest possible value is 1954 + (0.19 %). + +- qcom,fg-esr-broad-lt-filter-micro-pct + Usage: optional + Value type: + Definition: Value in micro percentage for low temperature ESR broad + filter. If this is not specified, then a default value of + 30000 (3 %) will be used. Lowest possible value is + 1954 (0.19 %). + +- qcom,fg-esr-rt-filter-switch-temp + Usage: optional + Value type: + Definition: Battery temperature threshold below which ESR relax + filter coefficients will be applied after a certain + number of delta battery temperature interrupts firing in + an interval of time. This will be applied only when Qnovo + is enabled. If this is not specified, then the default + value used will be -100. Unit is in decidegC. + +- qcom,fg-esr-tight-rt-filter-micro-pct + Usage: optional + Value type: + Definition: Value in micro percentage for relax temperature ESR tight + filter. If this is not specified, then a default value of + 5860 will be used. Lowest possible value is 1954 (0.19 %). + This will be applied only if Qnovo is enabled. + +- qcom,fg-esr-broad-rt-filter-micro-pct + Usage: optional + Value type: + Definition: Value in micro percentage for relax temperature ESR broad + filter. If this is not specified, then a default value of + 156250 will be used. Lowest possible value is 1954 (0.19 %). + This will be applied only if Qnovo is enabled. + +- qcom,fg-auto-recharge-soc + Usage: optional + Value type: + Definition: A boolean property when defined will configure automatic + recharge SOC threshold. If not specified, automatic + recharge voltage threshold will be configured. This has + to be configured in conjunction with the charger side + configuration for proper functionality. + +- qcom,slope-limit-temp-threshold + Usage: optional + Value type: + Definition: Battery temperature threshold to decide when slope limit + coefficients should be applied along with charging status. + Unit is in decidegC. + +- qcom,slope-limit-coeffs + Usage: optional + Value type: + Definition: A list of integers which holds the slope limit coefficients + in the following order. Allowed size is 4. Possible values + are from 0 to 31. Unit is in decipercentage. + Element 0 - Low temperature discharging + Element 1 - Low temperature charging + Element 2 - High temperature discharging + Element 3 - High temperature charging + These coefficients have to be specified along with the + property "qcom,slope-limit-temp-threshold" to make dynamic + slope limit adjustment functional. + +- qcom,fg-bmd-en-delay-ms + Usage: optional + Value type: + Definition: The delay in ms for FG to enable BMD after reading RID. + +- qcom,fg-use-sw-esr + Usage: optional + Value type: + Definition: A boolean property when defined uses software based + ESR during charging. + +- qcom,fg-disable-esr-pull-dn + Usage: optional + Value type: + Definition: A boolean property which disables ESR pull-down. + This is to be used for debug purposes only. + +- qcom,fg-sync-sleep-threshold-ma + Usage: optional + Value type: + Definition: The minimum battery current for FG to enter into sync-sleep. + +- qcom,fg-disable-in-twm + Usage: optional + Value type: + Definition: A boolean property which disables FG during TWM entry. + +========================================================== +Second Level Nodes - Peripherals managed by FG Gen3 driver +========================================================== +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the specified peripheral + +- interrupts + Usage: optional + Value type: + Definition: Interrupt mapping as per the interrupt encoding + +- interrupt-names + Usage: optional + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======== +Example +======== + +pmi8998_fg: qpnp,fg { + compatible = "qcom,fg-gen3"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pmi8998_revid>; + io-channels = <&pmi8998_rradc 3>; + io-channel-names = "rradc_batt_id"; + qcom,rradc-base = <0x4500>; + qcom,ki-coeff-soc-dischg = <30 60 90>; + qcom,ki-coeff-med-dischg = <800 1000 1400>; + qcom,ki-coeff-hi-dischg = <1200 1500 2100>; + qcom,slope-limit-temp-threshold = <100>; + qcom,slope-limit-coeffs = <10 11 12 13>; + qcom,battery-thermal-coefficients = [9d 50 ff]; + status = "okay"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x3 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta"; + + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x3 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "batt-missing"; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-fg-gen4.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-fg-gen4.txt new file mode 100644 index 0000000000000000000000000000000000000000..8bdbf936da2d14bf99e96dac19ee6831fb09eab1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-fg-gen4.txt @@ -0,0 +1,687 @@ +Qualcomm Technologies, Inc. PMIC Fuel Gauge Gen4 Device + +QTI PMIC FG Gen4 device provides interface to the clients to read properties +related to the battery. Its main function is to retrieve the State of Charge +(SOC), in percentage scale representing the amount of charge left in the +battery. + +======================= +Required Node Structure +======================= + +FG Gen4 device must be described in two levels of device nodes. The first +level describes the FG Gen4 device. The second level describes one or more +peripherals managed by FG Gen4 driver. All the peripheral specific parameters +such as base address, interrupts etc., should be under second level node. + +==================================== +First Level Node - FG Gen4 device +==================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,fg-gen4". + +- qcom,pmic-revid + Usage: required + Value type: + Definition: Should specify the phandle of PMIC revid module. This is + used to identify the PMIC subtype. + +- qcom,pmic-pbs + Usage: optional + Value type: + Definition: Should specify the phandle of PMIC PBS module. This is + used to trigger PBS for certain configurations. + +- #thermal-sensor-cells: Should be 0. See thermal.txt for the description. + +- nvmem-names: + Usage: optional + Value type: + Definition: Nvmem device name for SDAM to store parameters like cycle + counters and learned capacity. It must be defined as + "fg_sdam". + +- nvmem: + Usage: optional + Value type: + Definition: Phandle of the nvmem device name to access SDAM to store + parameters. + +- io-channels +- io-channel-names + Usage: optional + Value type: + Definition: Specified if battery id is obtained through ADC channel + If specified, it should have a name "batt_id". + For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- qcom,batt-id-pullup-kohms + Usage: optional + Value type: + Definition: Battery id pull up resistor value in KOhms. This needs to + be specified if battery id is obtained through ADC channel. + If not specified, a default value of 100 KOhms is used. + +- qcom,fg-cutoff-voltage + Usage: optional + Value type: + Definition: The voltage (in mV) where the fuel gauge will steer the SOC + to be zero. For example, if the cutoff voltage is set to + 3400mv, the fuel gauge will try to count SoC so that the + battery SOC will be 0 when it is 3400 mV. If this property + is not specified, then the default value used will be + 3000 mV. + +- qcom,fg-empty-voltage + Usage: optional + Value type: + Definition: The voltage threshold (in mV) based on which the empty soc + interrupt will be triggered. When the empty soc interrupt + fires, battery soc will be set to 0 and the userspace will + be notified via the power supply framework. The userspace + will read 0% soc and immediately shutdown. If this property + is not specified, then the default value used will be + 2812 mV. + +- qcom,fg-sys-min-voltage + Usage: optional + Value type: + Definition: The voltage threshold (in mV) which describes the system + minimum voltage as per the hardware recommendation. This + is not used for any configuration but only for calculating + the available power. If this property is not specified, + then the default value used is 2800 mV. + +- qcom,fg-sys-term-current + Usage: optional + Value type: + Definition: Battery current (in mA) at which the fuel gauge will try to + scale towards 100%. When the charge current goes above this + the SOC should be at 100%. If this property is not + specified, then the default value used will be -125 mA. + This value has to be specified in negative values for + the charging current. + +- qcom,fg-cutoff-current + Usage: optional + Value type: + Definition: Minimum Battery current (in mA) used for cutoff SOC + estimate. If this property is not specified, then a default + value of 200 mA will be applied. + +- qcom,fg-delta-soc-thr + Usage: optional + Value type: + Definition: Percentage of SOC increase upon which the delta monotonic & + battery SOC interrupts will be triggered. If this property + is not specified, then the default value will be 5 (0.5 %). + Unit is in deci-percentage. Possible values are in the range + of 1 to 124. + +- qcom,fg-esr-timer-chg-fast + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the battery is + charging for fast calibration. Array of 2 elements if + specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-timer-dischg-fast + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the battery is + discharging for fast calibration. Array of 2 elements if + specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-timer-chg-slow + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the battery is + charging for default calibration. Array of 2 elements if + specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-timer-dischg-slow + Usage: optional + Value type: + Definition: Number of cycles between ESR pulses while the battery is + discharging for default calibration. Array of 2 elements if + specified. + Element 0 - Retry value for timer + Element 1 - Maximum value for timer + +- qcom,fg-esr-cal-soc-thresh + Usage: optional + Value type: + Definition: SOC thresholds applied when ESR fast calibration is done. + Array of 2 elements if specified. This should be specified + if ESR fast calibration algorithm is needed. + Element 0 - Minimum SOC threshold in percentage + Element 1 - Maximum SOC threshold in percentage + +- qcom,fg-esr-cal-temp-thresh + Usage: optional + Value type: + Definition: Battery temperature thresholds applied when ESR fast + calibration is done. Array of 2 elements if specified. + This should be specified if ESR fast calibration algorithm + is needed. + Element 0 - Minimum temperature threshold in Celsius + Element 1 - Maximum temperature threshold in Celsius + +- qcom,fg-delta-esr-disable-count + Usage: optional + Value type: + Definition: Value after which delta ESR interrupt will be disabled. + This is applicable only when ESR fast calibration is + enabled. Default value is 10. + +- qcom,fg-delta-esr-thr + Usage: optional + Value type: + Definition: Threshold for delta ESR interrupt in uOhms. Default value + is 1832. If ESR fast calibration algorithm is enabled, this + will be overridden with a maximum value. + +- qcom,fg-esr-filter-factor + Usage: optional + Value type: + Definition: ESR filter factor used in ESR fast calibration algorithm. + This factor will be used when ESR correction delta is + applied after the calculation. Default value is 2. + +- qcom,fg-esr-calib-dischg: + Usage: optional + Value type: + Definition: Enables ESR calibration only during discharging. This + should be specified only when ESR fast calibration is not + required. Also, ESR discharging timers should be specified + for the proper functionality. + +- qcom,fg-esr-pulse-thresh-ma + Usage: optional + Value type: + Definition: ESR pulse qualification threshold in mA. If this is not + specified, a default value of 110 mA will be configured. + Allowed values are from 1 to 1000. + +- qcom,fg-esr-meas-curr-ma + Usage: optional + Value type: + Definition: ESR measurement current in mA. If this is not specified, + a default value of 120 mA will be configured. Allowed + values are 60, 120, 180 and 240. + +- qcom,fg-batt-temp-delta + Usage: optional + Value type: + Definition: Battery temperature delta interrupt threshold. Possible + values are: 0, 1, 2 and 3. Unit is in Kelvin or Celsius. + +- qcom,fg-batt-temp-cold-thresh + Usage: optional + Value type: + Definition: Battery temperature cold interrupt threshold. Allowed + values are from -128 to 127. Unit is in Kelvin or Celsius. + +- qcom,fg-batt-temp-hot-thresh + Usage: optional + Value type: + Definition: Battery temperature hot interrupt threshold. Allowed + values are from -128 to 127. Unit is in Kelvin or Celsius. + +- qcom,fg-batt-temp-hyst + Usage: optional + Value type: + Definition: Battery temperature hysteresis threshold. Possible values + are: 0, 1, 2 and 3. Unit is in Kelvin or Celsius. + +- qcom,fg-batt-therm-freq + Usage: optional + Value type: + Definition: Battery thermistor interval in seconds. Possible values + are from 1-255. If not specified, then the default value + configured is 8. + +- qcom,fg-force-load-profile + Usage: optional + Value type: + Definition: If set, battery profile will be force loaded if the profile + loaded earlier by bootloader doesn't match with the profile + available in the device tree. + +- qcom,cl-start-capacity + Usage: optional + Value type: + Definition: Battery SOC threshold to start the capacity learning. + If this is not specified, then the default value used + will be 15. Unit is in percentage. + +- qcom,cl-min-temp + Usage: optional + Value type: + Definition: Lower limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 150 (15 C). Unit is in decidegC. + +- qcom,cl-max-temp + Usage: optional + Value type: + Definition: Upper limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 500 (50 C). Unit is in decidegC. + +- qcom,cl-max-increment + Usage: optional + Value type: + Definition: Maximum capacity increment allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 5 (0.5%). Unit is in decipercentage. + +- qcom,cl-max-decrement + Usage: optional + Value type: + Definition: Maximum capacity decrement allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 100 (10%). Unit is in decipercentage. + +- qcom,cl-min-limit + Usage: optional + Value type: + Definition: Minimum limit that the capacity cannot go below in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-max-limit + Usage: optional + Value type: + Definition: Maximum limit that the capacity cannot go above in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-min-delta-batt-soc + Usage: optional + Value type: + Definition: Minimum change in battery SOC to qualify for capacity + learning. If this is not specified, then the default + value is 10. Unit is in percentage. + +- qcom,cl-wt-enable + Usage: optional + Value type: + Definition: A boolean property to enable weighted capacity learning + based on change in battery SOC during a charging cycle. + If this is specified "qcom,cl-start-capacity" is not used. + +- qcom,cl-skew + Usage: optional + Value type: + Definition: Skew in decipercentage which when specified will be applied + to the final learned capacity. + +- qcom,cl-ibat-flt-thresh-ma + Usage: optional + Value type: + Definition: Filtered battery current to qualify the capacity learning + algorithm to begin. If this is not specified, then the + default value is 100 mA. + +- qcom,hold-soc-while-full + Usage: optional + Value type: + Definition: A boolean property that when defined holds SOC at 100% when + the battery is full. + +- qcom,linearize-soc + Usage: optional + Value type: + Definition: A boolean property that when defined linearizes SOC when + the SOC drops after charge termination monotonically to + improve the user experience. This is applicable only if + "qcom,hold-soc-while-full" is specified. + +- qcom,ki-coeff-soc-dischg + Usage: optional + Value type: + Definition: Array of monotonic SOC threshold values to change the ki + coefficient for medium discharge current during discharge. + This should be defined in the ascending order and in the + range of 0-100. Array limit is set to 3. + +- qcom,ki-coeff-low-dischg + Usage: optional + Value type: + Definition: Array of ki coefficient values for low discharge current + during discharge. These values will be applied when the + monotonic SOC goes below the SOC threshold specified under + qcom,ki-coeff-soc-dischg. Array limit is set to 3. This + property should be specified if qcom,ki-coeff-soc-dischg + is specified to make it fully functional. Value has no + unit. Allowed range is 0 to 15564 in micro units. If this + is not specified, the default value used will be 367. + +- qcom,ki-coeff-med-dischg + Usage: optional + Value type: + Definition: Array of ki coefficient values for medium discharge current + during discharge. These values will be applied when the + monotonic SOC goes below the SOC threshold specified under + qcom,ki-coeff-soc-dischg. Array limit is set to 3. This + property should be specified if qcom,ki-coeff-soc-dischg + is specified to make it fully functional. Value has no + unit. Allowed range is 0 to 15564 in micro units. If this + is not specified, the default value used will be 62. + +- qcom,ki-coeff-hi-dischg + Usage: optional + Value type: + Definition: Array of ki coefficient values for high discharge current + during discharge. These values will be applied when the + monotonic SOC goes below the SOC threshold specified under + qcom,ki-coeff-soc-dischg. Array limit is set to 3. This + property should be specified if qcom,ki-coeff-soc-dischg + is specified to make it fully functional. Value has no + unit. Allowed range is 0 to 15564 in micro units. If this + is not specified, the default value used will be 0. + +- qcom,ki-coeff-dischg-low-med-thresh-ma + Usage: optional + Value type: + Definition: Threshold value of discharging current that decides which ki + coefficient will be applied: qcom,ki-coeff-low-dischg if the + threshold is not breached, and qcom,ki-coeff-med-dischg + otherwise. Allowed range is 0 to 3984 milliamperes. If this + is not specified, the default value used will be 50 (50 mA). + +- qcom,ki-coeff-dischg-med-hi-thresh-ma + Usage: optional + Value type: + Definition: Threshold value of discharging current that decides which ki + coefficient will be applied: qcom,ki-coeff-med-dischg if the + threshold is not breached, and qcom,ki-coeff-hi-dischg + otherwise. Allowed range is 0 to 3984 milliamperes. If this + is not specified, the default value used will be 100 + (100 mA). + +- qcom,ki-coeff-low-chg + Usage: optional + Value type: + Definition: ki coefficient value for low charge current during + charging. Value has no unit. Allowed range is 0 to 15564 + in micro units. If this is not specified, the default value + used will be 184. + +- qcom,ki-coeff-med-chg + Usage: optional + Value type: + Definition: ki coefficient value for medium charge current during + charging. Value has no unit. Allowed range is 0 to 15564 + in micro units. If this is not specified, the default value + used will be 62. + +- qcom,ki-coeff-hi-chg + Usage: optional + Value type: + Definition: ki coefficient value for high charge current during + charging. Value has no unit. Allowed range is 0 to 15564 + in micro units. If this is not specified, the default value + used will be 0. + +- qcom,ki-coeff-chg-low-med-thresh-ma + Usage: optional + Value type: + Definition: Threshold value of charging current that decides which ki + coefficient will be applied: qcom,ki-coeff-low-chg if the + threshold is not breached, and qcom,ki-coeff-med-chg + otherwise. Allowed range is 0 to 3984 milliamperes. If this + is not specified, the default value used will be 500 + (500 mA). + +- qcom,ki-coeff-chg-med-hi-thresh-ma + Usage: optional + Value type: + Definition: Threshold value of charging current that decides which ki + coefficient will be applied: qcom,ki-coeff-med-chg if the + threshold is not breached, and qcom,ki-coeff-hi-chg + otherwise. Allowed range is 0 to 3984 milliamperes. If this + is not specified, the default value used will be 1000 + (1000 mA). + +- qcom,ki-coeff-cutoff + Usage: optional + Value type: + Definition: ki coefficient value for cutoff integration gain. Value has + no unit. Allowed range is 62 to 15564 in micro units. + +- qcom,ki-coeff-full-dischg + Usage: optional + Value type: + Definition: Array of Ki coefficient full SOC values that needs to be + applied during discharging. If not specified, a value of + 0 will be set. + Allowed range is from 62 to 15564. + Element 0 - Ki coefficient for full SOC in room temperature + Element 1 - Ki coefficient for full SOC in low temperature + +- qcom,fg-rconn-uohms + Usage: optional + Value type: + Definition: Battery connector resistance (Rconn) in microohms. If it's + already configured in bootloader, then it will not be + configured again by GEN4 FG driver. + +- qcom,slope-limit-temp-threshold + Usage: optional + Value type: + Definition: Battery temperature threshold to decide when slope limit + coefficients should be applied along with charging status. + Unit is in decidegC. + +- qcom,slope-limit-coeffs + Usage: optional + Value type: + Definition: A list of integers which holds the slope limit coefficients + in the following order. Allowed size is 4. Possible values + are from 123 to 31128. Unit is in micro-percentage. + Element 0 - Low temperature discharging + Element 1 - Low temperature charging + Element 2 - High temperature discharging + Element 3 - High temperature charging + These coefficients have to be specified along with the + property "qcom,slope-limit-temp-threshold" to make dynamic + slope limit adjustment functional. + +- qcom,rapid-soc-dec-en + Usage: optional + Value type: + Definition: A boolean property that when defined enables rapid SOC + decrease when the battery SOC is low but not converging to + zero with battery voltage dropping rapidly below Vcutoff. + +- qcom,five-pin-battery + Usage: optional + Value type: + Definition: A boolean property that when specified indicates that a + five pin battery is used. Based on this, time to full + calculations would use the Rbatt calculated properly. + +- qcom,multi-profile-load + Usage: optional + Value type: + Definition: A boolean property that when specified indicates that + multiple profile loading needs to be enabled. This requires + multiple battery profiles to be specified for a battery for + proper functionality. + +- qcom,soc-hi-res + Usage: optional + Value type: + Definition: A boolean property that when specified shows high + resolution of monotonic SOC under CAPACITY_RAW property + during charging in the scale of 0-10000. + +- qcom,soc-scale-mode-en + Usage: optional + Value type: + Definition: A boolean property that when specified will enable scaling + of the SOC linearly, based on the filtered battery voltage + after crossing below a Vbatt threshold. + +- qcom,soc-scale-vbatt-mv + Usage: optional + Value type: + Definition: Threshold voltage to decide when SOC should + be scaled based on filtered voltage when + qcom,soc-scale-mode-en is specified. If this + is not specified, then the default value is 3400. + Unit is in mV. + +- qcom,soc-scale-time-ms + Usage: optional + Value type: + Definition: Timer value for doing SOC calculation based on + filtered voltage when qcom,soc-scale-mode-en is + specified. If this is not specified, then the + default value is 10000. Unit is in ms. + +- qcom,force-calib-level + Usage: optional + Value type: + Definition: Calibration level in decimal. When specified, + the calibration level is forced to this value. + Possible values are in the range of 1 to 130. + +========================================================== +Second Level Nodes - Peripherals managed by FG Gen4 driver +========================================================== +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the specified peripheral + +- interrupts + Usage: optional + Value type: + Definition: Interrupt mapping as per the interrupt encoding + +- interrupt-names + Usage: optional + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======== +Example +======== + +pm8150b_fg: qpnp,fg { + compatible = "qcom,fg-gen4"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm8150b_revid>; + nvmem-names = "fg_sdam"; + nvmem = <&pm8150_sdam_2>; + io-channels = <&pm8150b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt_id"; + #thermal-sensor-cells = <0>; + status = "okay"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta", + "msoc-low", + "msoc-empty", + "msoc-high", + "msoc-full"; + + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x3 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbatt-low", + "vbatt-pred-delta", + "esr-delta"; + }; + + qcom,adc-rr@4200 { + status = "okay"; + reg = <0x4200 0x100>; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x4 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "batt-missing", + "batt-id", + "batt-temp-delta", + "batt-temp-hot", + "batt-temp-cold"; + }; + + qcom,fg-memif@4300 { + status = "okay"; + reg = <0x4300 0x100>; + interrupts = <0x2 0x43 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x43 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x43 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x43 0x3 IRQ_TYPE_EDGE_BOTH>, + interrupt-names = "ima-rdy", + "ima-xcp", + "dma-xcp", + "dma-grant", + }; + +}; + +====================================== +Example for thermal zone configuration +====================================== + +thermal_zones { + pm8150b_fg { + polling-delay-passive = <200>; + polling-delay = <200>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_fg>; + + pm8150b_fg_trip1: pm8150b-fg-trip1 { + temperature = <40000>; + hysteresis = <0>; + type = "passive"; + }; + pm8150b_fg_trip2: pm8150b-fg-trip2 { + temperature = <45000>; + hysteresis = <0>; + type = "passive"; + }; + pm8150b_fg_trip3: pm8150b-fg-trip3 { + temperature = <55000>; + hysteresis = <0>; + type = "passive"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qg.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qg.txt new file mode 100644 index 0000000000000000000000000000000000000000..904e4d503f84a4c36a38bd026b396c67fbabd821 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qg.txt @@ -0,0 +1,518 @@ +Qualcomm Technologies, Inc. QPNP PMIC QGAUGE (QG) Device + +QPNP PMIC QGAUGE device provides the ability to gauge the State-of-Charge +of the battery. It provides an interface to the clients to read various +battery related parameters. + +======================= +Required Node Structure +======================= + +Qgauge device must be described in two level of nodes. The first level +describes the properties of the Qgauge device and the second level +describes the peripherals managed/used of the module. + +==================================== +First Level Node - QGAUGE device +==================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,qpnp-qg" or "qcom,qpnp-qg-lite". + +- qcom,pmic-revid + Usage: required + Value type: + Definition: Should specify the phandle of PMIC revid module. This is + used to identify the PMIC subtype. + +- qcom,qg-vadc + Usage: required + Value type: + Definition: Phandle for the VADC node, it is used for BATT_ID and + BATT_THERM readings. + +- qcom,vbatt-empty-mv + Usage: optional + Value type: + Definition: The battery voltage threshold (in mV) at which the + vbatt-empty interrupt fires. The SOC is forced to 0 + when this interrupt fires. If not specified, the + default value is 3200 mV. + +- qcom,vbatt-empty-cold-mv + Usage: optional + Value type: + Definition: The battery voltage threshold (in mV) at which the + vbatt-empty interrupt fires. This threshold is only + applied at cold temperature specified by + 'qcom,cold-temp-threshold'. The SOC is forced to 0 + when this interrupt fires. If not specified, the + default value is 3000 mV. + +- qcom,vbatt-cutoff-mv + Usage: optional + Value type: + Definition: The battery voltage threshold (in mV) at which the + the Qgauge algorithm converges to 0 SOC. If not specified + the default value is 3400 mV. + +- qcom,vbatt-low-mv + Usage: optional + Value type: + Definition: The battery voltage threshold (in mV) at which the + the VBAT_LOW interrupt fires. Software can take necessary + the action when this interrupt fires. If not specified + the default value is 3500 mV. + +- qcom,vbatt-low-cold-mv + Usage: optional + Value type: + Definition: The battery voltage threshold (in mV) at which the + the VBAT_LOW interrupt fires. The threshold is only + applied at cold temperature specified by + 'qcom,cold-temp-threshold'. Software can take necessary + the action when this interrupt fires. If not specified + the default value is 3800 mV. + +- qcom,qg-iterm-ma + Usage: optional + Value type: + Definition: The battery current (in mA) at which the the QG algorithm + converges the SOC to 100% during charging and can be used to + terminate charging. If not specified, the default value is + 100mA. + +- qcom,delta-soc + Usage: optional + Value type: + Definition: The SOC percentage increase at which the SOC is + periodically reported to the userspace. If not specified, + the value defaults to 1%. + +- qcom,s2-fifo-length + Usage: optional + Value type: + Definition: The total number if FIFO samples which need to be filled up + in S2 state of QG to fire the FIFO DONE interrupt. + Minimum value = 1 Maximum Value = 8. If not specified, + the default value is 5. + +- qcom,s2-acc-length + Usage: optional + Value type: + Definition: The number of distinct V & I samples to be accumulated + in each FIFO in the S2 state of QG. + Minimum Value = 0 Maximum Value = 256. If not specified, + the default value is 128. + +- qcom,s2-acc-interval-ms + Usage: optional + Value type: + Definition: The time (in ms) between each of the V & I samples being + accumulated in FIFO. + Minimum Value = 0 ms Maximum Value = 2550 ms. If not + specified the default value is 100 ms. + +- qcom,ocv-timer-expiry-min + Usage: optional + Value type: + Definition: The maximum time (in minutes) for the QG to transition from + S3 to S2 state. + Minimum Value = 2 min Maximum Value = 30 min. If not + specified the hardware default is set to 14 min. + +- qcom,ocv-tol-threshold-uv + Usage: optional + Value type: + Definition: The OCV detection error tolerance (in uV). The maximum + voltage allowed between 2 VBATT readings in the S3 state + to qualify for a valid OCV. + Minimum Value = 0 uV Maximum Value = 12262 uV Step = 195 uV + +- qcom,s3-entry-fifo-length + Usage: optional + Value type: + Definition: The minimum number if FIFO samples which have to qualify the + S3 IBAT entry threshold (qcom,s3-entry-ibat-ua) for QG + to enter into S3 state. + Minimum Value = 1 Maximum Value = 8. The hardware default + is configured to 3. + +- qcom,s3-entry-ibat-ua + Usage: optional + Value type: + Definition: The battery current (in uA) for the QG to enter into the S3 + state. The QG algorithm enters into S3 if the battery + current is lower than this threshold consecutive for + the FIFO length specified in 'qcom,s3-entry-fifo-length'. + Minimum Value = 0 uA Maximum Value = 155550 uA + Step = 610 uA. + +- qcom,s3-exit-ibat-ua + Usage: optional + Value type: + Definition: The battery current (in uA) for the QG to exit S3 state. + If the battery current is higher than this threshold QG + exists S3 state. + Minimum Value = 0 uA Maximum Value = 155550 uA + Step = 610 uA. + +- qcom,rbat-conn-mohm + Usage: optional + Value type: + Definition: Resistance of the battery connectors in mOhms. + +- qcom,ignore-shutdown-soc-secs + Usage: optional + Value type: + Definition: Time in seconds beyond which shutdown SOC is ignored. + If not specified the default value is 360 secs. + +- qcom,hold-soc-while-full + Usage: optional + Value type: + Definition: A boolean property that when defined holds SOC at 100% when + the battery is full until recharge starts. + +- qcom,linearize-soc + Usage: optional + Value type: + Definition: A boolean property that when defined linearizes SOC when + the SOC drops after charge termination monotonically to + improve the user experience. This is applicable only if + "qcom,hold-soc-while-full" is specified. + +- qcom,cold-temp-threshold + Usage: optional + Value type: + Definition: Temperature threshold in decidegree at which the low + temperature specific configuration as applied. If not + specified, the default value is 0 degree centigrade. + +- qcom,cl-disable + Usage: optional + Value type: + Definition: A boolean property to disable the battery capacity + learning when charging. + +- qcom,cl-feedback-on + Usage: optional + Value type: + Definition: A boolean property to feedback the learned capacity into + the capacity lerning algorithm. This has to be used only if the + property "qcom,cl-disable" is not specified. + +- qcom,cl-max-start-soc + Usage: optional + Value type: + Definition: Battery SOC has to be below or equal to this value at the + start of a charge cycle to start the capacity learning. + If this is not specified, then the default value used + will be 15. Unit is in percentage. + +- qcom,cl-min-start-soc + Usage: optional + Value type: + Definition: Battery SOC has to be above or equal to this value at the + start of a charge cycle to start the capacity learning. + If this is not specified, then the default value used + will be 10. Unit is in percentage. + +- qcom,cl-min-temp + Usage: optional + Value type: + Definition: Lower limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 150 (15 C). Unit is in decidegC. + +- qcom,cl-max-temp + Usage: optional + Value type: + Definition: Upper limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 500 (50 C). Unit is in decidegC. + +- qcom,cl-max-increment + Usage: optional + Value type: + Definition: Maximum capacity increment allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 5 (0.5%). Unit is in decipercentage. + +- qcom,cl-max-decrement + Usage: optional + Value type: + Definition: Maximum capacity decrement allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 100 (10%). Unit is in decipercentage. + +- qcom,cl-min-limit + Usage: optional + Value type: + Definition: Minimum limit that the capacity cannot go below in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-max-limit + Usage: optional + Value type: + Definition: Maximum limit that the capacity cannot go above in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-min-delta-batt-soc + Usage: optional + Value type: + Definition: Minimum change in battery SOC to qualify for capacity + learning. If this is not specified, then the default + value is 10. Unit is in percentage. + +- qcom,cl-wt-enable + Usage: optional + Value type: + Definition: A boolean property to enable weighted capacity learning + based on change in battery SOC during a charging cycle. + If this is specified, then "qcom,cl-min-start-soc" and + "qcom,cl-max-start-soc" is not used. + +- qcom,esr-disable + Usage: optional + Value type: + Definition: Boolean property to disable ESR estimation. If not defined + ESR estimation stays enabled for charge-cycles. + +- qcom,esr-discharge-enable + Usage: optional + Value type: + Definition: Boolean property to enable ESR estimation during discharge. + Only valid if 'qcom,esr-disable' is not defined. + +- qcom,esr-qual-current-ua + Usage: optional + Value type: + Definition: Minimum current differential in uA to qualify an ESR + reading as valid. If not defined the value defaults + to 130mA. + +- qcom,esr-qual-vbatt-uv + Usage: optional + Value type: + Definition: Minimum vbatt differential in uV to qualify an ESR + reading as valid. If not defined the value defaults + to 7mV. + +- qcom,esr-disable-soc + Usage: optional + Value type: + Definition: Minimum battery SOC below which ESR will not be + attempted by QG. If not defined the value defaults + to 10%. + +- qcom,esr-chg-min-ibat-ua + Usage: optional + Value type: + Definition: Minimun charge current (IBAT) in uA at which ESR will + be attempted. If not specified the default value is + in -450mA. + +- qcom,qg-ext-sns + Usage: optional + Value type: + Definition: Boolean property to support external-rsense based + configuration. + +- qcom,shutdown-temp-diff + Usage: optional + Value type: + Definition: The allowed battery temperature in deci-degree difference + between shutdown and power-on to continue with the shutdown + SOC. If not specified the default value is 6 degrees C (60). + +- qcom,shutdown-soc-threshold + Usage: optional + Value type: + Definition: The SOC difference allowed between PON and SHUTDOWN SOC + for the shutdown SOC to be used. If the difference is + beyond this value the PON SOC is used. + +- qcom,qg-use-s7-ocv + Usage: optional + Value type: + Definition: Boolean property to use S7 for PON OCV. + +- qcom,min-sleep-time-secs + Usage: optional + Value type: + Definition: The minimum sleep time in secs to allow a SOC + jump if there has been a GOOD_OCV. + +- qcom,qg-sys-min-voltage + Usage: optional + Value type: + Definition: The voltage threshold (in mV) which describes the system + minimum voltage as per the hardware recommendation. This + is not used for any configuration but only for calculating + the available power. If this property is not specified, + then the default value used is 2800 mV. + +- qcom,qg-sleep-config + Usage: optional + Value type: bool + Definition: Enables sleep-state configurtion for QG. This + allows configuring the FIFO length, accumulator + interval and the accumulator length when system + enters sleep. + +- qcom,sleep-s2-fifo-length + Usage: optional + Value type: + Definition: The FIFO length to be applied when system enters sleep + while discharging. Takes effect only if + 'qcom,qg-sleep-config' is enabled. the default value + if not specified is 8. + +- qcom,sleep-s2-acc-length + Usage: optional + Value type: + Definition: The accululator length to be applied when system + enters sleep while discharging. Takes effect only if + 'qcom,qg-sleep-config' is enabled. the default value + if not specified is 256. + +- qcom,sleep-s2-acc-intvl-ms + Usage: optional + Value type: + Definition: The accululator count to be applied when system + enters sleep while discharging. Takes effect only if + 'qcom,qg-sleep-config' is enabled. the default value + if not specified is 200ms. + +- qcom,qg-fast-chg-config + Usage: optional + Value type: bool + Definition: Enables fast-charge configurtion for QG. This + allows configuring the FIFO length during + fast charge. + +- qcom,fast-chg-s2-fifo-length + Usage: optional + Value type: + Definition: The FIFO length to be applied when system enters + fast-chargging. Takes effect only if + 'qcom,qg-fast-chg-config' is enabled. The + default value if not specified is 1. + +- qcom,fvss-enable + Usage: optional + Value type: bool + Definition: Enable Filtered Voltage based SOC scaling. + This logic enables SOC scaling to report + 0 at the cutoff voltage. + +- qcom,fvss-vbatt-mv + Usage: optional + Value type: + Definition: Battery voltage threshold at which FVSS is + enabled. Applicable only if 'qcom,fvss-enable' + is set. + +- qcom,multi-profile-load + Usage: optional + Value type: + Definition: A boolean property that when specified indicates that + multiple profile loading needs to be enabled. This requires + multiple battery profiles to be specified for a battery for + proper functionality. + +- qcom,tcss-enable + Usage: optional + Value type: bool + Definition: Enable Termination current based SOC scaling. + This logic enables SOC scaling to report + 100% at the QG termination current defined by + qcom,qg-iterm-ma. + +- qcom,tcss-entry-soc + Usage: optional + Value type: + Definition: SOC threshold at which TCSS starts. The default + value is 90%. This property is valid only if + qcom,tcss-enable is defined. + +- qcom,bass-enable + Usage: optional + Value type: bool + Definition: Enable Battery SOC based SOC scaling. This logic + allows monotonic-SOC scaling at low-temperatures + when there is variation in system-SOC due to + changes in the load. + +- qcom,use-cp-iin-sns + Usage: optional + Value type: bool + Definition: Enable SMB-sensing for CP. Enabling this property + will enable QG summing the SMB current. + +- qcom,esr-low-temp-threshold + Usage: optional + Value type: + Definition: Battery temperature threshold below which ESR is ignored. + The default value is 10degC. + +========================================================== +Second Level Nodes - Peripherals managed by QGAUGE driver +========================================================== +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the specified peripheral + +- interrupts + Usage: optional + Value type: + Definition: Interrupt mapping as per the interrupt encoding + +- interrupt-names + Usage: optional + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======== +Example +======== + +pmi632_qg: qpnp,qg { + compatible = "qcom,qpnp-qg"; + qcom,pmic-revid = <&pmi632_revid>; + qcom,qg-vadc = <&pmi632_vadc>; + qcom,vbatt-empty-mv = <3200>; + qcom,vbatt-low-mv = <3500>; + qcom,vbatt-cutoff-mv = <3400>; + qcom,qg-iterm-ma = <100>; + + qcom,qgauge@4800 { + status = "okay"; + reg = <0x4800 0x100>; + interrupts = <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x6 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "qg-batt-missing", + "qg-vbat-low", + "qg-vbat-empty", + "qg-fifo-done", + "qg-good-ocv", + "qg-fsm-state-chg", + "qg-event"; + }; + + qcom,qg-sdam@b000 { + status = "okay"; + reg = <0xb000 0x100>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo5.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo5.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb2772876c07a07eeb94b9aa30c4a90c30b49a50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo5.txt @@ -0,0 +1,55 @@ +QPNP Qnovo5 pulse engine + +QPNP Qnovo5 is a PBS based pulse charging engine which works in tandem with the +QPNP SMB5 Charger device. It configures the QPNP SMB5 charger to +charge/discharge as per pulse characteristics. + +The QPNP Qnovo5 pulse engine has a single peripheral assigned to it. + +Properties: +- compatible: + Usage: required + Value type: + Definition: It must be "qcom,qpnp-qnovo5". + +- reg: + Usage: required + Value type: + Definition: Specifies the base address of the module. Qnovo5 is using a + SDAM peripheral so this is the address of the SDAM module + being used. + +- interrupts: + Usage: required + Value type: + Definition: Specifies the interrupt associated with Qnovo5. + +- interrupt-names: + Usage: required + Value type: + Definition: Specifies the interrupt name for Qnovo5. There is only one + interrupt named as "ptrain-done". + +- pinctrl-N: + Usage: optional + Value type: + Definition: Specifies the pinctrl configuration that needs to be applied + when the charger is removed for controlling external FET. + +- pinctrl-names: + Usage: optional + Value type: + Definition: Specifies the names for pinctrl configurations defined above. + Allowed names are "q_state1" and "q_state2". + +Example: + +qcom,qpnp-qnovo@b000 { + compatible = "qcom,qpnp-qnovo5"; + reg = <0xb000 0x100>; + interrupts = <0x2 0xb0 0x1 IRQ_TYPE_NONE>; + interrupt-names = "ptrain-done"; + pinctrl-names = "q_state1", "q_state2"; + pinctrl-0 = <&qnovo_fet_ctrl_state1>; + pinctrl-1 = <&qnovo_fet_ctrl_state2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smb2.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..330e166a8f021bff3f0dfb65717bc3d2725e0449 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smb2.txt @@ -0,0 +1,349 @@ +Qualcomm Technologies, Inc. SMB2 Charger Specific Bindings + +SMB2 Charger is an efficient programmable battery charger capable of charging a +high-capacity lithium-ion battery over micro-USB or USB Type-C ultrafast with +Quick Charge 2.0, Quick Charge 3.0, and USB Power Delivery support. Wireless +charging features full A4WP Rezence 1.2, WPC 1.2, and PMA support. + +======================= +Required Node Structure +======================= + +SMB2 Charger must be described in two levels of devices nodes. + +=============================== +First Level Node - SMB2 Charger +=============================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-smb2". + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of PMI's revid module. This is used to + identify the PMI subtype. + +- qcom,batteryless-platform + Usage: optional + Value type: + Definition: Boolean flag which indicates that the platform does not have a + battery, and therefore charging should be disabled. In + addition battery properties will be faked such that the device + assumes normal operation. + +- qcom,use-extcon + Usage: optional + Value type: + Definition: Boolean flag which specify that SMB2 will act as main charger + to do extcon USB calls. If not defined, other charger driver can + act as main charger to do extcon USB calls. + +- qcom,fcc-max-ua + Usage: optional + Value type: + Definition: Specifies the maximum fast charge current in micro-amps. + If the value is not present, 1Amp is used as default. + +- qcom,fv-max-uv + Usage: optional + Value type: + Definition: Specifies the maximum float voltage in micro-volts. + If the value is not present, 4.35V is used as default. + +- qcom,usb-icl-ua + Usage: optional + Value type: + Definition: Specifies the USB input current limit in micro-amps. + If the value is not present, 1.5Amps is used as default. + +- qcom,usb-ocl-ua + Usage: optional + Value type: + Definition: Specifies the OTG output current limit in micro-amps. + If the value is not present, 1.5Amps is used as default + +- qcom,dc-icl-ua + Usage: optional + Value type: + Definition: Specifies the DC input current limit in micro-amps. + +- qcom,boost-threshold-ua + Usage: optional + Value type: + Definition: Specifies the boost current threshold in micro-amps. + If the value is not present, 100mA is used as default. + +- qcom,wipower-max-uw + Usage: optional + Value type: + Definition: Specifies the DC input power limit in micro-watts. + If the value is not present, 8W is used as default. + +- qcom,thermal-mitigation + Usage: optional + Value type: Array of + Definition: Array of fast charge current limit values for + different system thermal mitigation levels. + This should be a flat array that denotes the + maximum charge current in mA for each thermal + level. + +- io-channels + Usage: optional + Value type: List of + Definition: List of phandle and IIO specifier pairs, one pair + for each IIO input to the device. Note: if the + IIO provider specifies '0' for #io-channel-cells, + then only the phandle portion of the pair will appear. + +- io-channel-names + Usage: optional + Value type: List of + Definition: List of IIO input name strings sorted in the same + order as the io-channels property. Consumer drivers + will use io-channel-names to match IIO input names + with IIO specifiers. + +- qcom,float-option + Usage: optional + Value type: + Definition: Configures how the charger behaves when a float charger is + detected by APSD + 1 - Treat as a DCP + 2 - Treat as a SDP + 3 - Disable charging + 4 - Suspend USB input + +- qcom,hvdcp-disable + Usage: optional + Value type: + Definition: Specifies if hvdcp charging is to be enabled or not. + If this property is not specified hvdcp will be enabled. + If this property is specified, hvdcp 2.0 detection will still + happen but the adapter won't be asked to switch to a higher + voltage point. + +- qcom,chg-inhibit-threshold-mv + Usage: optional + Value type: + Definition: Charge inhibit threshold in milli-volts. Charging will be + inhibited when the battery voltage is within this threshold + from Vfloat at charger insertion. If this is not specified + then charge inhibit will be disabled by default. + Allowed values are: 50, 100, 200, 300. + +- qcom,auto-recharge-soc + Usage: optional + Value type: + Definition: Specifies if automatic recharge needs to be based off battery + SOC. If this property is not specified, then auto recharge will + be based off battery voltage. For both SOC and battery voltage, + charger receives the signal from FG to resume charging. + +- qcom,suspend-input-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present enables input suspend for + debug battery. + +- qcom,min-freq-khz + Usage: optional + Value type: + Definition: Specifies the minimum charger buck/boost switching frequency + in KHz. It overrides the min frequency defined for the charger. + +- qcom,max-freq-khz + Usage: optional + Value type: + Definition: Specifies the maximum charger buck/boost switching frequency in + KHz. It overrides the max frequency defined for the charger. + +- qcom,otg-deglitch-time-ms + Usage: optional + Value type: + Definition: Specifies the deglitch interval for OTG detection. + If the value is not present, 50 msec is used as default. + +- qcom,step-charging-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables step-charging. + +- qcom,wd-bark-time-secs + Usage: optional + Value type: + Definition: WD bark-timeout in seconds. The possible values are + 16, 32, 64, 128. If not defined it defaults to 64. + +- qcom,sw-jeita-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables sw compensation for jeita + +- qcom,battery-data + Usage: optional + Value type: + Definition: Specifies the phandle of the node which contains the battery + profiles supported on the device. This is only specified + when step charging and sw-jeita configurations are desired + to be get from these properties defined in battery profile: + qcom,step-chg-ranges, qcom,jeita-fcc-ranges, qcom,jeita-fv-ranges. + +- qcom,disable-stat-sw-override + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables STAT pin default software + override configuration. + +- qcom,fcc-stepping-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables stepwise change in FCC. + The default stepping rate is 100mA/sec. + + +============================================= +Second Level Nodes - SMB2 Charger Peripherals +============================================= + +Peripheral specific properties: +- reg + Usage: required + Value type: + Definition: Address and size of the peripheral's register block. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +pmi8998_charger: qcom,qpnp-smb2 { + compatible = "qcom,qpnp-smb2"; + #address-cells = <1>; + #size-cells = <1>; + + io-channels = <&pmic_rradc 0>; + io-channel-names = "rradc_batt_id"; + + dpdm-supply = <&qusb_phy0>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, + <0x2 0x10 0x1 IRQ_TYPE_NONE>, + <0x2 0x10 0x2 IRQ_TYPE_NONE>, + <0x2 0x10 0x3 IRQ_TYPE_NONE>, + <0x2 0x10 0x4 IRQ_TYPE_NONE>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>, + <0x2 0x11 0x1 IRQ_TYPE_NONE>, + <0x2 0x11 0x2 IRQ_TYPE_NONE>, + <0x2 0x11 0x3 IRQ_TYPE_NONE>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>, + <0x2 0x12 0x1 IRQ_TYPE_NONE>, + <0x2 0x12 0x2 IRQ_TYPE_NONE>, + <0x2 0x12 0x3 IRQ_TYPE_NONE>, + <0x2 0x12 0x4 IRQ_TYPE_NONE>, + <0x2 0x12 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>, + <0x2 0x13 0x1 IRQ_TYPE_NONE>, + <0x2 0x13 0x2 IRQ_TYPE_NONE>, + <0x2 0x13 0x3 IRQ_TYPE_NONE>, + <0x2 0x13 0x4 IRQ_TYPE_NONE>, + <0x2 0x13 0x5 IRQ_TYPE_NONE>, + <0x2 0x13 0x6 IRQ_TYPE_NONE>, + <0x2 0x13 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>, + <0x2 0x14 0x1 IRQ_TYPE_NONE>, + <0x2 0x14 0x2 IRQ_TYPE_NONE>, + <0x2 0x14 0x3 IRQ_TYPE_NONE>, + <0x2 0x14 0x4 IRQ_TYPE_NONE>, + <0x2 0x14 0x5 IRQ_TYPE_NONE>, + <0x2 0x14 0x6 IRQ_TYPE_NONE>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>, + <0x2 0x16 0x1 IRQ_TYPE_NONE>, + <0x2 0x16 0x2 IRQ_TYPE_NONE>, + <0x2 0x16 0x3 IRQ_TYPE_NONE>, + <0x2 0x16 0x4 IRQ_TYPE_NONE>, + <0x2 0x16 0x5 IRQ_TYPE_NONE>, + <0x2 0x16 0x6 IRQ_TYPE_NONE>, + <0x2 0x16 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smb5.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smb5.txt new file mode 100644 index 0000000000000000000000000000000000000000..f85a40c5035aa9e7243114fed182b25cf84d3ca5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smb5.txt @@ -0,0 +1,569 @@ +Qualcomm Technologies, Inc. SMB5 Charger Specific Bindings + +SMB5 Charger is an efficient programmable battery charger capable of charging a +high-capacity lithium-ion battery over micro-USB or USB Type-C ultrafast with +Quick Charge 2.0, Quick Charge 3.0, and USB Power Delivery support. Wireless +charging features full A4WP Rezence 1.2, WPC 1.2, and PMA support. + +======================= +Required Node Structure +======================= + +SMB5 Charger must be described in two levels of devices nodes. + +=============================== +First Level Node - SMB5 Charger +=============================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-smb5". + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of PMI's revid module. This is used to + identify the PMI subtype. + +- qcom,sec-charger-config + Usage: optional + Value type: + Definition: Specify how the secondary chargers are configured. + 0 - No secondary charger. + 1 - Charge Pump SMB1390. + 2 - SMB1355 parallel charger. + 3 - Both Charge Pump and SMB1355. + If the value is not present, 0 is used as default. + +- io-channels +- io-channel-names + Usage: optional + Value type: + Definition: For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- qcom,batteryless-platform + Usage: optional + Value type: + Definition: Boolean flag which indicates that the platform does not have a + battery, and therefore charging should be disabled. In + addition battery properties will be faked such that the device + assumes normal operation. + +- qcom,charger-temp-max + Usage: optional + Value type: + Definition: Specifies the charger temp REG_H_THRESHOLD for PM8150B in deciDegC. + If the value is not present, use the setting read from the device. + +- qcom,smb-temp-max + Usage: optional + Value type: + Definition: Specifies the charger temp REG_H_THRESHOLD for SMB1355 in deciDegC. + If the value is not present, use the setting read from the device. + +- qcom,fcc-max-ua + Usage: optional + Value type: + Definition: Specifies the maximum fast charge current in micro-amps. + If the value is not present, 1Amp is used as default. + +- qcom,fv-max-uv + Usage: optional + Value type: + Definition: Specifies the maximum float voltage in micro-volts. + If the value is not present, 4.35V is used as default. + +- qcom,usb-icl-ua + Usage: optional + Value type: + Definition: Specifies the USB input current limit in micro-amps. + If the value is not present, 1.5Amps is used as default. + +- qcom,usb-ocl-ua + Usage: optional + Value type: + Definition: Specifies the OTG output current limit in micro-amps. + If the value is not present, 1.5Amps is used as default. + +- qcom,dc-icl-ua + Usage: optional + Value type: + Definition: Specifies the DC input current limit in micro-amps. + +- qcom,boost-threshold-ua + Usage: optional + Value type: + Definition: Specifies the boost current threshold in micro-amps. + If the value is not present, 100mA is used as default. + +- qcom,thermal-mitigation + Usage: optional + Value type: Array of + Definition: Array of fast charge current limit values for + different system thermal mitigation levels. + This should be a flat array that denotes the + maximum charge current in mA for each thermal + level. + +- qcom,float-option + Usage: optional + Value type: + Definition: Configures how the charger behaves when a float charger is + detected by APSD. + 1 - Treat as a DCP. + 2 - Treat as a SDP. + 3 - Disable charging. + 4 - Suspend USB input. + +- qcom,hvdcp-disable + Usage: optional + Value type: + Definition: Specifies if hvdcp charging is to be enabled or not. + If this property is not specified hvdcp will be enabled. + If this property is specified, hvdcp 2.0 detection will still + happen but the adapter won't be asked to switch to a higher + voltage point. + +- qcom,chg-inhibit-threshold-mv + Usage: optional + Value type: + Definition: Charge inhibit threshold in milli-volts. Charging will be + inhibited when the battery voltage is within this threshold + from Vfloat at charger insertion. If this is not specified + then charge inhibit will be disabled by default. + Allowed values are: 50, 100, 200, 300. + +- qcom,chg-term-src + Usage: optional + Value type: + Definition: Specify either the ADC or analog comparators to be used in order + to set threshold values for charge termination current. + 0 - Unspecified + 1 - Select ADC comparator + 2 - Select ANALOG comparator + +- qcom,chg-term-current-ma + Usage: optional + Value type: + Definition: When ADC comparator is selected as qcom,chg-term-src, this + parameter should be set to the desired upper threshold. + +- qcom,chg-term-base-current-ma + Usage: optional + Value type: + Definition: When ADC comparator is selected as qcom,chg-term-src, this + parameter should be set to the desired lower threshold. + +- qcom,auto-recharge-soc + Usage: optional + Value type: + Definition: Specifies the SOC threshold at which the charger will + restart charging after termination. The value specified + ranges from 0 - 100. The feature is enabled if this + property is specified with a valid SOC value. + +- qcom,auto-recharge-vbat-mv + Usage: optional + Value type: + Definition: Specifies the battery voltage threshold at which the charger + will restart charging after termination. The value specified + is in milli-volts. + +- qcom,suspend-input-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present enables input suspend for + debug battery. + +- qcom,fake-chg-status-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present shows charging status as + unknown for debug battery. This needs to be specified only if + the device needs to be kept powered on always with + "svc power stayon true". + +- qcom,min-freq-khz + Usage: optional + Value type: + Definition: Specifies the minimum charger buck/boost switching frequency + in KHz. It overrides the min frequency defined for the charger. + +- qcom,max-freq-khz + Usage: optional + Value type: + Definition: Specifies the maximum charger buck/boost switching frequency in + KHz. It overrides the max frequency defined for the charger. + +- qcom,otg-deglitch-time-ms + Usage: optional + Value type: + Definition: Specifies the deglitch interval for OTG detection. + If the value is not present, 50 msec is used as default. + +- qcom,step-charging-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables step-charging. + +- qcom,typec-legacy-rp-icl + Usage: optional + Value type: bool + Definition: Boolean property to enable setting ICL based on Rp for + Type-C non-compliant legacy cables. + +- qcom,wd-bark-time-secs + Usage: optional + Value type: + Definition: WD bark-timeout in seconds. The possible values are + 16, 32, 64, 128. If not defined it defaults to 64. + +- qcom,sw-jeita-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables sw compensation for + jeita. + +- qcom,battery-data + Usage: optional + Value type: + Definition: Specifies the phandle of the node which contains the battery + profiles supported on the device. + +- qcom,flash-derating-soc + Usage: optional + Value type: + Definition: SOC threshold in percentage below which hardware will start + derating flash. This is only applicable to certain PMICs like + PMI632 which has SCHGM_FLASH peripheral. + +- qcom,flash-disable-soc + Usage: optional + Value type: + Definition: SOC threshold in percentage below which hardware will disable + flash. This is only applicable to certain PMICs like PMI632 + which has SCHGM_FLASH peripheral. + +- qcom,headroom-mode + Usage: optional + Value type: + Definition: Specifies flash hardware headroom management policy. The + possible values are: + <0>: Fixed mode, constant 5V at flash input. + <1>: Adaptive mode allows charger output voltage to be + dynamically controlled by the flash module based on the + required flash headroom. + This is only applicable to certain PMICs like PMI632 which + has SCHGM_FLASH peripheral. + +- qcom,fcc-stepping-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables stepwise change in FCC. + The default stepping rate is 100mA/sec. + +- qcom,disable-suspend-on-collapse + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables suspend on collapse + feature of charger hardware. + +- qcom,uusb-moisture-protection-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables mositure protection + feature for uUSB connector type. + +- qcom,hvdcp-autonomous-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables hardware-controlled + operation of HVDCP. + +- qcom,usb-pd-disable + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables USB-PD operation. + +- qcom,lpd-disable + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables liquid presence + detection. + +- qcom,hw-die-temp-mitigation + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables h/w based thermal + mitigation. + +- qcom,hw-connector-mitigation + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables h/w based + connector temperature mitigation. + +- qcom,hw-skin-temp-mitigation + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables h/w based skin + temperature mitigation. + +- qcom,en-skin-therm-mitigation + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables skin + thermal mitigation. + +- qcom,connector-internal-pull-kohm + Usage: optional + Value type: + Definition: Specifies internal pull-up configuration to be applied to + connector THERM. The only valid values are (0/30/100/400). + If not specified 100K is used as default pull-up. + +- qcom,smb-internal-pull-kohm + Usage: optional + Value type: + Definition: Specifies internal pull-up configuration to be applied to + connector THERM, only valid values are (0/30/100/400). + If not specified 100K is used as default pull-up. + +- qcom,wd-snarl-time-config + Usage: optional + Value type: + Definition: WDOG snarl timeout configuration value. The possible values are + 0 to 7, where 0 = 62.5ms, 1 = 125ms, 2 = 250ms, 3 = 500ms, + 4 = 1s, 5 = 2s, 6 = 4s and 7 = 8s. If not defined, wdog-snarl + irq is disabled by default. + +- qcom,adc-based-aicl + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables ADC based AICL. + +- qcom,wls-current-max-ua + Usage: optional + Value type: + Definition: Upper limit of charging current supplied by the wireless charger. + If left unspecified, the HW min value of 1.5 A is applied by + default. + +- qcom,fcc-step-delay-ms + Usage: optional + Value type: + Definition: Specifies the delay between each step of FCC stepper algorithm. + If left unspecified, the default value is 1 Sec. + +- qcom,fcc-step-size-ua + Usage: optional + Value type: + Definition: Specifies the step size of each step of FCC stepper algorithm. + If left unspecified, the default value is 100mA. + +- qcom,hvdcp2-max-icl-ua + Usage: optional + Value type: + Definition: Specifies the maximum input current limit that can be configured + for HVDCP2 adapter. + If left unspecified, the default value is 3000mA. + +- qcom,hvdcp3-max-icl-ua + Usage: optional + Value type: + Definition: Specifies the maximum input current limit that can be configured + for HVDCP3 adapter. + If left unspecified, the default value is 3000mA. + +- qcom,hvdcp3-standalone-config + Usage: optional + Value type: bool + Definition: Boolean flag which when present indicates that the charging is + only done by the main charger (standalone, no CP) with a QC 3.0 + adapter. + +- qcom,disable-fcc-restriction + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables FCC restriction. + +- qcom,qc4-max-icl-ua + Usage: optional + Value type: + Definition: Specifies the maximum input current limit that can be configured + for PPS adapter in CV mode. + If left unspecified, the default value is 4000mA. + +============================================= +Second Level Nodes - SMB5 Charger Peripherals +============================================= + +Peripheral specific properties: +- reg + Usage: required + Value type: + Definition: Address and size of the peripheral's register block. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +pm8150b_charger: qcom,qpnp-smb5 { + compatible = "qcom,qpnp-smb5"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,pmic-revid = <&pm8150b_revid>; + + dpdm-supply = <&qusb_phy0>; + + qcom,sec-charger-config = <1>; + + io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x2 0x10 0x0 IRQ_TYPE_NONE>, + <0x2 0x10 0x1 IRQ_TYPE_NONE>, + <0x2 0x10 0x2 IRQ_TYPE_NONE>, + <0x2 0x10 0x3 IRQ_TYPE_NONE>, + <0x2 0x10 0x4 IRQ_TYPE_NONE>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_NONE>, + <0x2 0x11 0x1 IRQ_TYPE_NONE>, + <0x2 0x11 0x2 IRQ_TYPE_NONE>, + <0x2 0x11 0x3 IRQ_TYPE_NONE>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x2 0x12 0x0 IRQ_TYPE_NONE>, + <0x2 0x12 0x1 IRQ_TYPE_NONE>, + <0x2 0x12 0x2 IRQ_TYPE_NONE>, + <0x2 0x12 0x3 IRQ_TYPE_NONE>, + <0x2 0x12 0x4 IRQ_TYPE_NONE>, + <0x2 0x12 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x2 0x13 0x0 IRQ_TYPE_NONE>, + <0x2 0x13 0x1 IRQ_TYPE_NONE>, + <0x2 0x13 0x2 IRQ_TYPE_NONE>, + <0x2 0x13 0x3 IRQ_TYPE_NONE>, + <0x2 0x13 0x4 IRQ_TYPE_NONE>, + <0x2 0x13 0x5 IRQ_TYPE_NONE>, + <0x2 0x13 0x6 IRQ_TYPE_NONE>, + <0x2 0x13 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x2 0x14 0x0 IRQ_TYPE_NONE>, + <0x2 0x14 0x1 IRQ_TYPE_NONE>, + <0x2 0x14 0x2 IRQ_TYPE_NONE>, + <0x2 0x14 0x3 IRQ_TYPE_NONE>, + <0x2 0x14 0x4 IRQ_TYPE_NONE>, + <0x2 0x14 0x5 IRQ_TYPE_NONE>, + <0x2 0x14 0x6 IRQ_TYPE_NONE>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x2 0x16 0x0 IRQ_TYPE_NONE>, + <0x2 0x16 0x1 IRQ_TYPE_NONE>, + <0x2 0x16 0x2 IRQ_TYPE_NONE>, + <0x2 0x16 0x3 IRQ_TYPE_NONE>, + <0x2 0x16 0x4 IRQ_TYPE_NONE>, + <0x2 0x16 0x5 IRQ_TYPE_NONE>, + <0x2 0x16 0x6 IRQ_TYPE_NONE>, + <0x2 0x16 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; + + qcom,schgm-flash@a600 { + reg = <0xa600 0x100>; + interrupts = <0x2 0xa6 0x0 IRQ_TYPE_NONE>, + <0x2 0xa6 0x1 IRQ_TYPE_NONE>, + <0x2 0xa6 0x2 IRQ_TYPE_NONE>, + <0x2 0xa6 0x3 IRQ_TYPE_NONE>, + <0x2 0xa6 0x4 IRQ_TYPE_NONE>, + <0x2 0xa6 0x5 IRQ_TYPE_NONE>, + <0x2 0xa6 0x6 IRQ_TYPE_NONE>, + <0x2 0xa6 0x7 IRQ_TYPE_NONE>; + + interrupt-names = "flash-en", + "torch-req", + "flash-state-change", + "vout-up", + "vout-down", + "ilim1-s1", + "ilim2-s2", + "vreg-ok"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smblite.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smblite.txt new file mode 100644 index 0000000000000000000000000000000000000000..137518e988ebb19c6715a69a480f46299450d20c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-smblite.txt @@ -0,0 +1,334 @@ +Qualcomm Technologies, Inc. SMBLITE Charger Specific Bindings + +SMBLITE Charger is an efficient programmable battery charger capable of charging a +lithium-ion battery over micro-USB or USB Type-C. + +======================= +Required Node Structure +======================= + +SMBLITE Charger must be described in two levels of devices nodes. + +=================================== +First Level Node - SMBLITE Charger +=================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,qpnp-smblite". + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of PMI's revid module. This is used to + identify the PMI subtype. + +- io-channels +- io-channel-names + Usage: optional + Value type: + Definition: For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- qcom,batteryless-platform + Usage: optional + Value type: + Definition: Boolean flag which indicates that the platform does not have a + battery, and therefore charging should be disabled. In + addition battery properties will be faked such that the device + assumes normal operation. + +- qcom,fcc-max-ua + Usage: optional + Value type: + Definition: Specifies the maximum fast charge current in micro-amps in + battery profile. + If the value is not present, 1Amp is used as default. + +- qcom,fv-max-uv + Usage: optional + Value type: + Definition: Specifies the maximum float voltage in micro-volts in + battery profile. + If the value is not present, 4.35V is used as default. + +- qcom,usb-icl-ua + Usage: optional + Value type: + Definition: Specifies the USB input current limit in micro-amps. + If the value is not present, 1.5Amps is used as default. + +- qcom,thermal-mitigation + Usage: optional + Value type: Array of + Definition: Array of fast charge current limit values for + different system thermal mitigation levels. + This should be a flat array that denotes the + maximum charge current in mA for each thermal + level. + +- qcom,chg-inhibit-threshold-mv + Usage: optional + Value type: + Definition: Charge inhibit threshold in milli-volts. Charging will be + inhibited when the battery voltage is within this threshold + from Vfloat at charger insertion. If this is not specified + then charge inhibit will be disabled by default. + Allowed values are: 50, 100, 200, 300. + +- qcom,chg-term-src + Usage: optional + Value type: + Definition: Specify either the ADC or analog comparators to be used in order + to set threshold values for charge termination current. + 0 - Unspecified + 1 - Select ADC comparator + 2 - Select ANALOG comparator + +- qcom,chg-term-current-ma + Usage: optional + Value type: + Definition: When ADC comparator is selected as qcom,chg-term-src, this + parameter should be set to the desired upper threshold. + +- qcom,chg-term-base-current-ma + Usage: optional + Value type: + Definition: When ADC comparator is selected as qcom,chg-term-src, this + parameter should be set to the desired lower threshold. + +- qcom,auto-recharge-soc + Usage: optional + Value type: + Definition: Specifies the SOC threshold at which the charger will + restart charging after termination. The value specified + ranges from 0 - 100. The feature is enabled if this + property is specified with a valid SOC value. + +- qcom,auto-recharge-vbat-mv + Usage: optional + Value type: + Definition: Specifies the battery voltage threshold at which the charger + will restart charging after termination. The value specified + is in milli-volts. + +- qcom,suspend-input-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present enables input suspend for + debug battery. + +- qcom,fake-chg-status-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present shows charging status as + unknown for debug battery. This needs to be specified only if + the device needs to be kept powered on always with + "svc power stayon true". + +- qcom,typec-legacy-rp-icl + Usage: optional + Value type: bool + Definition: Boolean property to enable setting ICL based on Rp for + Type-C non-compliant legacy cables. + +- qcom,wd-bark-time-secs + Usage: optional + Value type: + Definition: WD bark-timeout in seconds. The possible values are + 16, 32, 64, 128. If not defined it defaults to 64. + +- qcom,battery-data + Usage: optional + Value type: + Definition: Specifies the phandle of the node which contains the battery + profiles supported on the device. + +- qcom,flash-derating-soc + Usage: optional + Value type: + Definition: SOC threshold in percentage below which hardware will start + derating flash. This is only applicable to certain PMICs like + PMI632 which has SCHGM_FLASH peripheral. + +- qcom,flash-disable-soc + Usage: optional + Value type: + Definition: SOC threshold in percentage below which hardware will disable + flash. This is only applicable to certain PMICs like PMI632 + which has SCHGM_FLASH peripheral. + +- qcom,headroom-mode + Usage: optional + Value type: + Definition: Specifies flash hardware headroom management policy. The + possible values are: + <0>: Fixed mode, constant 5V at flash input. + <1>: Adaptive mode allows charger output voltage to be + dynamically controlled by the flash module based on the + required flash headroom. + This is only applicable to certain PMICs like PMI632 which + has SCHGM_FLASH peripheral. + +- qcom,fcc-stepping-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables stepwise change in FCC. + The default stepping rate is 100mA/sec. + +- qcom,disable-suspend-on-collapse + Usage: optional + Value type: bool + Definition: Boolean flag which when present disables suspend on collapse + feature of charger hardware. + +- qcom,fcc-step-delay-ms + Usage: optional + Value type: + Definition: Specifies the delay between each step of FCC stepper algorithm. + If left unspecified, the default value is 1 Sec. + +- qcom,fcc-step-size-ua + Usage: optional + Value type: + Definition: Specifies the step size of each step of FCC stepper algorithm. + If left unspecified, the default value is 100mA. + +================================================= +Second Level Nodes - SMBLITE Charger Peripherals +================================================= + +Peripheral specific properties: +- reg + Usage: required + Value type: + Definition: Address and size of the peripheral's register block. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +pm2250_charger: qcom,qpnp-smblite { + compatible = "qcom,qpnp-smblite"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,pmic-revid = <&pm2250_revid>; + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "chgr-error", + "chg-state-change", + "buck-oc", + "vph-ov"; + }; + + qcom,dcdc@1100 { + reg = <0x1100 0x100>; + interrupts = + <0x0 0x11 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-fault", + "skip-mode", + "input-current-limiting", + "switcher-power-ok"; + }; + + qcom,batif@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x0 0x12 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x4 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "bat-temp", + "bat-therm-or-id-missing", + "bat-low", + "bat-ov", + "bsm-active"; + }; + + qcom,usb@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-plugin", + "usbin-collapse", + "usbin-uv", + "usbin-ov", + "usbin-gtvt", + "usbin-icl-change"; + }; + + qcom,typec@1500 { + reg = <0x1500 0x100>; + interrupts = + <0x0 0x15 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x15 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x15 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x15 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x15 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x15 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x15 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "typec-or-rid-detect-change", + "typec-vpd-detect", + "typec-cc-state-change", + "typec-vbus-change", + "typec-attach-detach", + "typec-legacy-cable-detect", + "typec-try-snk-src-detect"; + }; + + qcom,misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x6 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "imp-trigger", + "all-chnl-cond-done", + "temp-change"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1351-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1351-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..6170e3ecf7bacf0856354b0a4b69e229c0591ab0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1351-charger.txt @@ -0,0 +1,120 @@ +Summit smb1351 battery charger + +SMB1351 is a single-cell battery charger. It can charge +the battery and power the system via the USB/AC adapter input. + +The smb1351 interface is via I2C bus. + +Required Properties: +- compatible Must be "qcom,smb1351-charger". +- reg The device 7-bit I2C address. + +Required Properties for standalone charger: +- regulator-name A string used as a descriptive name for OTG regulator. +- pinctrl-names The state name of the pin configuration. Only + support "default". +- pinctrl-0 The phandle of the pin configuration node in + pinctrl for smb_int_pin. + +Optional Properties: + +- interrupts This indicates the IRQ number of the GPIO + connected to the STAT pin. +- qcom,fastchg-current-max-ma Fast Charging current in mA. Supported range is + from 1000mA to 4500mA. +- qcom,chg-autonomous-mode This is a bool property and it indicates that the + charger is configured for autonomous operation and + does not require any software configuration. +- qcom,disable-apsd This is a bool property which disables automatic + power source detection (APSD). If this is set + charger detection is done by DCIN UV irq. +- qcom,charging-disabled This is a bool property which disables charging + by suspending usb. +- qcom,batt-charging-disabled This is a bool property which disables battery + charging. +- qcom,using-pmic-therm This property indicates thermal pin connected to pmic or smb. +- qcom,bms-psy-name This is a string and it points to the bms + power supply name. +- qcom,iterm-ma Specifies the termination current to indicate end-of-charge. + Possible values in mA - 70, 100, 200, 300, 400, 500, 600, 700. +- qcom,iterm-disabled Disables the termination current feature. This is a bool + property. +- qcom,float-voltage-mv Float Voltage in mV - the maximum voltage up to which + the battery is charged. Supported range 3500mV to 4500mV +- qcom,recharge-mv Recharge threshold in mV - the offset from the float-volatge + as which the charger restarts charging. Possible + values are 50mV and 100mV. +- qcom,recharge-disabled Boolean value which disables the auto-recharge. +- qcom,bms-controlled-charging This property enables BMS to control EOC and + recharge. BMS and charger communicates with each + other via power_supply framework. This + property should be used with 'qcom,iterm-disabled' + to ensure EOC detection in charger is disabled. +- qcom,force-hvdcp-2p0 Boolean value which allows to force hvdcp working on 2.0 mode. +- qcom,parallel-charger Boolean value which enables the parallel charger. +- qcom,chg-vadc Corresponding VADC device's phandle. +- qcom,chg-adc_tm phandle to the corresponding VADC device to read the ADC channels. +- qcom,batt-cold-decidegc Cold battery temperature in decidegC. +- qcom,batt-hot-decidegc Hot battery temperature in decidegC. +- qcom,batt-missing-decidegc This is a property indicating battery missing temperature, if + higher than it, battery should exist. +- qcom,batt-warm-decidegc: Warm battery temperature in decidegC. After hitting this threshold, + "qcom,warm-bat-ma" defines maximum charging current and + "qcom,warm-bat-mv" defines maximum target voltage. +- qcom,batt-cool-decidegc: Cool battery temperature in decidegC. After hitting this threshold, + "qcom,cool-bat-ma" defines maximum charging current and + "qcom,cool-bat-mv" defines maximum target voltage. +- qcom,batt-warm-ma: Maximum warm battery charge current in milli-amps. +- qcom,batt-cool-ma: Maximum cool battery charge current in milli-amps. +- qcom,batt-warm-mv: Maximum warm battery target voltage in milli-volts. +- qcom,batt-cool-mv: Maximum cool battery target voltage in milli-volts. +- qcom,parallel-en-pin-polarity Specify the polarity of enable signal controlled + via pin in a parallel-charger configuration. + 0 - Active low and 1 - Active high. + If not specified the default value is active-low. +- qcom,parallel-external-current-sense If present specifies external rsense is + used for charge current sensing. +- qcom,stacked-batfet: Boolean flag. Specifies if parallel charger has stacked BATFET + cofiguration. +- qcom,otg-enable: Boolean value which enables OTG(On-The-Go) + functionality. + +Example for standalone charger: + +&i2c_4 { + smb1351_otg_supply: smb1351-charger@57 { + compatible = "qcom,smb1351-charger"; + reg = <0x57>; + interrupt-parent = <&msm_gpio>; + interrupts = <62 2>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,iterm-ma = <100>; + qcom,recharge-mv = <100>; + qcom,bms-psy-name = "bms"; + regulator-name = "smb1351_otg_vreg"; + qcom,using-pmic-therm; + qcom,chg-adc_tm = <&pm8916_adc_tm>; + qcom,chg-vadc = <&pm8916_vadc>; + qcom,batt-hot-decidegc = <550>; + qcom,batt-cold-decidegc = <0>; + qcom,batt-missing-decidegc = <(-200)>; + qcom,batt-warm-decidegc = <500>; + qcom,batt-cool-decidegc = <50>; + qcom,batt-warm-ma = <350>; + qcom,batt-cool-ma = <350>; + qcom,batt-warm-mv = <4200>; + qcom,batt-cool-mv = <4200>; + }; +}; + +Example for parallel charger: + +&i2c_11 { + smb1351-charger@1d { + compatible = "qcom,smb1351-charger"; + reg = <0x1d>; + qcom,parallel-charger; + qcom,recharge-mv = <100>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1355-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1355-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..528c285a936147c1d6d4aebb48c6d75b0524dfa4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1355-charger.txt @@ -0,0 +1,107 @@ +Qualcomm Technologies, Inc. SMB1355 Charger Specific Bindings + +SMB1355 slave charger is paired with QTI family of standalone chargers to +enable a high current, low profile Li+ battery charging system. + +The device provides 28V DC withstand, wide operating input range of 3.8 to +14.2V for standard 5V USB inputs as well as a wide variety of HVDCP Travel +Adapters and is compatible with QTI's Quick Charge technology. + +======================= +Required Node Structure +======================= + +SMB1355 Charger must be described in two levels of device nodes. + +================================== +First Level Node - SMB1355 Charger +================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,smb1355". + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of SMB's revid module. This is used + to identify the SMB subtype. + +- qcom,disable-ctm + Usage: optional + Value type: + Definition: boolean flag. Usually a thermistor near usb/typeC connector is + connected to AUX. Set this flag to indicate the thermistor + doesn't exist. + +- qcom,parallel-mode + Usage: optional + Value type: + Definition: Specifies parallel charging mode. If not specified, MID-MID + option is selected by default. + +- qcom,stacked-batfet + Usage: optional + Value type: + Definition: boolean flag. Specifies if parallel charger has stacked BATFET + configuration. + In stacked batfet the main and parallel charger's batfet are + stacked one after the other and thus all the charge current + (FCC) flows through main. In a non-stacked configuration each + charger controls the charge current (FCC) separately. + +- qcom,die-temp-threshold-degc + Usage: optional + Value type: + Definition: Specifies DIE temp threshold beyond which h/w starts mitigation. + If not sepcified, 90 degrees centigrade is used. + +- qcom,hw-die-temp-mitigation + Usage: optional + Value type: bool + Definition: Boolean property to enable h/w controlled die temp mitigation. + +================================================ +Second Level Nodes - SMB1355 Charger Peripherals +================================================ + +Peripheral specific properties: +- reg + Usage: required + Value type: + Definition: Address and size of the peripheral's register block. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +smb1355_charger: qcom,smb1355-charger { + compatible = "qcom,smb1355"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "wdog-bark"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb138x-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb138x-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd2729fb60fbdfbe0cd4d8b8cc388417b30dcddb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb138x-charger.txt @@ -0,0 +1,247 @@ +Qualcomm Technologies, Inc. SMB138X Charger Specific Bindings + +SMB138X Charger is an efficient programmable battery charger capable of charging +a high-capacity lithium-ion battery over micro-USB or USB Type-C ultrafast with +Quick Charge 2.0, Quick Charge 3.0 support. Wireless charging features full +A4WP Rezence 1.2, WPC 1.2, and PMA support. + +======================= +Required Node Structure +======================= + +SMB138X Charger must be described in two levels of devices nodes. + +================================== +First Level Node - SMB138X Charger +================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: String which indicates the charging mode. Can be one of the + following: + Standalone/Parallel Master - "qcom,smb138x-charger" + Parallel Slave - "qcom,smb138x-parallel-slave" + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of SMB's + revid module. This is used to identify + the SMB subtype. + +- qcom,parallel-mode + Usage: optional + Value type: + Definition: Specifies parallel charging mode. If not specified, MID-MID + option is selected by default. + +- qcom,suspend-input + Usage: optional + Value type: + Definition: Boolean flag which indicates that the charger should not draw + current from any of its input sources (USB, DC). + +- qcom,use-extcon + Usage: optional + Value type: + Definition: Boolean flag which specify that smb138x will act as main charger + to do extcon USB calls. If not defined, other charger driver can + act as main charger to do extcon USB calls. + +- qcom,fcc-max-ua + Usage: optional + Value type: + Definition: Specifies the maximum fast charge current in micro-amps. + +- qcom,usb-icl-ua + Usage: optional + Value type: + Definition: Specifies the USB input current limit in micro-amps. + +- qcom,dc-icl-ua + Usage: optional + Value type: + Definition: Specifies the DC input current limit in micro-amps. + +- qcom,charger-temp-max-mdegc + Usage: optional + Value type: + Definition: Specifies the maximum charger temperature in milli-degrees + Celsius. If unspecified a default of 80000 will be used. + +- qcom,connector-temp-max-mdegc + Usage: optional + Value type: + Definition: Specifies the maximum connector temperature in milli-degrees + Celsius. If unspecified a default value of 105000 will be used. + +- io-channels + Usage: optional + Value type: List of + Definition: List of phandle and IIO specifier pairs, one pair + for each IIO input to the device. Note: if the + IIO provider specifies '0' for #io-channel-cells, + then only the phandle portion of the pair will appear. + +- io-channel-names + Usage: optional + Value type: List of + Definition: List of IIO input name strings sorted in the same + order as the io-channels property. Consumer drivers + will use io-channel-names to match IIO input names + with IIO specifiers. + +================================================ +Second Level Nodes - SMB138X Charger Peripherals +================================================ + +Peripheral specific properties: +- reg + Usage: required + Value type: + Definition: Address and size of the peripheral's register block. + +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======================================= +Second Level Nodes - SMB138X Regulators +======================================= + +The following regulator nodes are supported: +"qcom,smb138x-vbus" - Regulator for enabling VBUS +"qcom,smb138x-vconn" - Regulator for enabling VCONN + +- regulator-name + Usage: required + Value type: + Definition: Specifies the name for this regulator. + +======= +Example +======= + +smb138x_charger: qcom,smb138x-charger { + compatible = "qcom,qpnp-smb138x-charger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,suspend-input; + dpdm-supply = <&qusb_phy0>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x4 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x11 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x11 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x11 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x11 0x3 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x12 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x12 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x12 0x5 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x13 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = <0x14 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x14 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x14 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x14 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x14 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x14 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x14 0x6 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x16 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1390-charger-psy.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1390-charger-psy.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5bcb13f58e9efa18093e9e4e468a6a4e051282b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1390-charger-psy.txt @@ -0,0 +1,119 @@ +Qualcomm Technologies, Inc. SMB1390 Charger Specific Bindings + +SMB1390 charge pump is paired with QTI family of standalone chargers to +enable a high current, high efficiency Li+ battery charging system. + +======================= +Required Node Structure +======================= + +SMB1390 Charger must be described in two levels of device nodes. + +================================== +First Level Node - SMB1390 Charger +================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,smb1390-charger-psy" for master SMB1390 and + "qcom,smb1390-slave" for slave SMB1390. + +- qcom,pmic-revid + Usage: required + Value type: phandle + Definition: Should specify the phandle of SMB's revid module. This is used + to identify the SMB subtype. + +- io-channels +- io-channel-names + Usage: required + Value type: + Definition: For details about IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + +- qcom,min-ilim-ua + Usage: optional + Value type: + Definition: Minimum ILIM supported, if requested ILIM goes below this value + disable SMB1390. If this values is not specified default minimum + ILIM is 1A. + +- qcom,max-temp-alarm-degc + Usage: optional + Value type: + Definition: Maximum die temperature to trigger temp alarm. The value + must be one of the following: + 80, 90, 105, 115. + If this value is not specified or is not one of the above + then default value is 105. + +- qcom,max-cutoff-soc + Usage: optional + Value type: + Definition: SOC beyond which SMB1390 is kept disabled. + If this value is not specified then default value is 85%. + +- qcom,parallel-output-mode + Usage: optional + Value type: + Definition: Defines the SMB1390 output connection topology. + This should be one of the following: + 0 - If SMB1390 output is not connected to anything; + 1 - If SMB1390 output is connected to VPH_PWR; + 2 - If SMB1390 output is connected to VBATT. + If this value is not specified then default value is 1. + +- qcom,parallel-input-mode + Usage: optional + Value type: + Definition: Defines the SMB1390 input connection topology. + This should be one of the following: + 0 - If SMB1390 input is not connected to anything; + 1 - If SMB1390 input is connected to USBIN; + 3 - If SMB1390 input is connected to USBMID. + If this value is not specified then default value is 3. + +================================================ +Second Level Nodes - SMB1390 Charger Peripherals +================================================ + +Peripheral specific properties: +- interrupts + Usage: required + Value type: + Definition: Peripheral interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. + +======= +Example +======= + +smb1390_charger: qcom,charge_pump { + compatible = "qcom,smb1390-charger-psy"; + qcom,pmic-revid = <&smb1390_revid>; + interrupt-parent = <&smb1390>; + status = "disabled"; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + + qcom,core { + interrupts = <0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x10 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "switcher-off-window", + "switcher-off-fault", + "vph-ov-soft", + "ilim", + "temp-alarm"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1398-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1398-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f1588f6a647e1514fdf408ec65f9037e8a75e68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/smb1398-charger.txt @@ -0,0 +1,106 @@ +Qualcomm Technologies, Inc. SMB1398 Charger Specific Bindings + +SMB1398 combo charge chip can be working in different modes: +(1) DIV2 charge pump mode to work as a companion charger that can be paired + with Qualcomm Technologies, Inc. family of standalone chargers; +(2) DIV2 and 3-level buck combo mode to regulate output power from wireless + charger receiver and provide input power for downstream chargers. + +======================= +Required Node Structure +======================= + +SMB1398 Charger must be described in two levels of device nodes. + +================================== +First Level Node - SMB1398 Charger +================================== + +Charger specific properties: +- compatible + Usage: required + Value type: + Definition: "qcom,smb1396-div2-cp-master" for SMB1396 working in DIV2 + mode as a companion master charger. + "qcom,smb1396-div2-cp-slave" for SMB1396 working in DIV2 + mode as a companion slave charger. + "qcom,smb1398-pre-regulator" for SMB1398 working in combo + mode (auto transition between DIV2 CP and 3-level buck) as a + pre-regulator stand between wireless receiver and downstream + chargers. + +- interrupts + Usage: optional + Value type: + Definition: Peripheral interrupt specifier. This is required when SMB1396 + working as a DIV2 CP master. + +- interrupt-names + Usage: optional + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. This is + required when SMB1396 working as a DIV2 CP master. + +- io-channels +- io-channel-names + Usage: optional + Value type: + Definition: The IIO channel for measuring SMB1398 die temperature, + io-channel-names should be "die-temp". For other details about + IIO bindings see: + Documentation/devicetree/bindings/iio/iio-bindings.txt + These properties are required when SMB1396 working as a DIV2 CP + master. + +- qcom,div2-cp-min-ilim-ua + Usage: optional + Value type: + Definition: The minimum ILIM settings to enable SMB1398 working in DIV2 mode. + The switcher is disabled when ILIM is below this value. + If this values is not specified, the default minimum ILIM is 1A. + This is only applicable when SMB1396 working as a DIV2 CP master. + +- qcom,max-cutoff-soc + Usage: optional + Value type: + Definition: SOC beyond which SMB1398 is kept disabled. + If this value is not specified then default value is 85%. + This is only applicable when SMB1396 working as a DIV2 CP master. + +- qcom,ilim-ua-disable-slave + Usage: optional + Value type: + Definition: The minimum ILIM setting to disable slave CP after hitting taper. + If this value is not specified, the default value is 3 times of + "qcom,div2-cp-min-ilim-ua". This is only applicable when both + SMB1396 DIV2 CP master and slave are present. + +Peripheral specific properties: +======= +Example +======= + +smb1398_charger: qcom,combo_charger { + compatible = "qcom,smb1396-div2-cp-master"; + interrupt-parent = <&smb1398>; + status = "disabled"; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "die_temp"; + + interrupts = <0x26 0x1 IRQ_TYPE_EDGE_RISING>, + <0x26 0x3 IRQ_TYPE_EDGE_RISING>, + <0x26 0x5 IRQ_TYPE_EDGE_RISING>, + <0x26 0x7 IRQ_TYPE_EDGE_RISING>, + <0x27 0x5 IRQ_TYPE_EDGE_RISING>, + <0x27 0x6 IRQ_TYPE_EDGE_RISING>, + <0x27 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "temp-shdwn", + "div2-irev", + "usbin-uv", + "usbin-ov", + "div2-ilim", + "div2-win-uv", + "div2-win-ov"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom_smbb.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom_smbb.txt new file mode 100644 index 0000000000000000000000000000000000000000..06f8a5ddb68ef8470f21c28c69f0a5386338e7c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom_smbb.txt @@ -0,0 +1,150 @@ +Qualcomm Switch-Mode Battery Charger and Boost + +PROPERTIES +- compatible: + Usage: required + Value type: + Description: Must be one of: + - "qcom,pm8941-charger" + +- reg: + Usage: required + Value type: + Description: Base address of registers for SMBB block + +- interrupts: + Usage: required + Value type: + Description: The format of the specifier is defined by the binding document + describing the node's interrupt parent. Must contain one + specifier for each of the following interrupts, in order: + - charge done + - charge fast mode + - charge trickle mode + - battery temperature ok + - battery present + - charger disconnected + - USB-in valid + - DC-in valid + +- interrupt-names: + Usage: required + Value type: + Description: Must contain the following list, strictly ordered: + "chg-done", + "chg-fast", + "chg-trkl", + "bat-temp-ok", + "bat-present", + "chg-gone", + "usb-valid", + "dc-valid" + +- qcom,fast-charge-current-limit: + Usage: optional (default: 1A, or pre-configured value) + Value type: ; uA; range [100mA : 3A] + Description: Maximum charge current; May be clamped to safety limits. + +- qcom,fast-charge-low-threshold-voltage: + Usage: optional (default: 3.2V, or pre-configured value) + Value type: ; uV; range [2.1V : 3.6V] + Description: Battery voltage limit above which fast charging may operate; + Below this value linear or switch-mode auto-trickle-charging + will operate. + +- qcom,fast-charge-high-threshold-voltage: + Usage: optional (default: 4.2V, or pre-configured value) + Value type: ; uV; range [3.24V : 5V] + Description: Battery voltage limit below which fast charging may operate; + The fast charger will attempt to charge the battery to this + voltage. May be clamped to safety limits. + +- qcom,fast-charge-safe-voltage: + Usage: optional (default: 4.2V, or pre-configured value) + Value type: ; uV; range [3.24V : 5V] + Description: Maximum safe battery voltage; May be pre-set by bootloader, in + which case, setting this will harmlessly fail. The property + 'fast-charge-high-watermark' will be clamped by this value. + +- qcom,fast-charge-safe-current: + Usage: optional (default: 1A, or pre-configured value) + Value type: ; uA; range [100mA : 3A] + Description: Maximum safe battery charge current; May pre-set by bootloader, + in which case, setting this will harmlessly fail. The property + 'qcom,fast-charge-current-limit' will be clamped by this value. + +- qcom,auto-recharge-threshold-voltage: + Usage: optional (default: 4.1V, or pre-configured value) + Value type: ; uV; range [3.24V : 5V] + Description: Battery voltage limit below which auto-recharge functionality + will restart charging after end-of-charge; The high cutoff + limit for auto-recharge is 5% above this value. + +- qcom,minimum-input-voltage: + Usage: optional (default: 4.3V, or pre-configured value) + Value type: ; uV; range [4.2V : 9.6V] + Description: Input voltage level above which charging may operate + +- qcom,dc-current-limit: + Usage: optional (default: 100mA, or pre-configured value) + Value type: ; uA; range [100mA : 2.5A] + Description: Default DC charge current limit + +- qcom,disable-dc: + Usage: optional (default: false) + Value type: boolean: or + Description: Disable DC charger + +- qcom,jeita-extended-temp-range: + Usage: optional (default: false) + Value type: boolean: or + Description: Enable JEITA extended temperature range; This does *not* + adjust the maximum charge voltage or current in the extended + temperature range. It only allows charging when the battery + is in the extended temperature range. Voltage/current + regulation must be done externally to fully comply with + the JEITA safety guidelines if this flag is set. + +- usb_otg_in-supply: + Usage: optional + Value type: + Description: Reference to the regulator supplying power to the USB_OTG_IN + pin. + +child nodes: +- otg-vbus: + Usage: optional + Description: This node defines a regulator used to control the direction + of VBUS voltage - specifically: whether to supply voltage + to VBUS for host mode operation of the OTG port, or allow + input voltage from external VBUS for charging. In the + hardware, the supply for this regulator comes from + usb_otg_in-supply. + +EXAMPLE +charger@1000 { + compatible = "qcom,pm8941-charger"; + reg = <0x1000 0x700>; + interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "chg-done", + "chg-fast", + "chg-trkl", + "bat-temp-ok", + "bat-present", + "chg-gone", + "usb-valid", + "dc-valid"; + + qcom,fast-charge-current-limit = <1000000>; + qcom,dc-charge-current-limit = <1000000>; + usb_otg_in-supply = <&pm8941_5vs1>; + + otg-vbus {}; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/rt9455_charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/rt9455_charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e6107c7578e8da55e613579d586ac3c56b1427f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/rt9455_charger.txt @@ -0,0 +1,46 @@ +Binding for Richtek rt9455 battery charger + +Required properties: +- compatible: it should contain one of the following: + "richtek,rt9455". +- reg: integer, i2c address of the device. +- interrupts: interrupt mapping for GPIO IRQ, it should be + configured with IRQ_TYPE_LEVEL_LOW flag. +- richtek,output-charge-current: integer, output current from the charger to the + battery, in uA. +- richtek,end-of-charge-percentage: integer, percent of the output charge current. + When the current in constant-voltage phase drops + below output_charge_current x end-of-charge-percentage, + charge is terminated. +- richtek,battery-regulation-voltage: integer, maximum battery voltage in uV. +- richtek,boost-output-voltage: integer, maximum voltage provided to consumer + devices, when the charger is in boost mode, in uV. + +Optional properties: +- richtek,min-input-voltage-regulation: integer, input voltage level in uV, used to + decrease voltage level when the over current + of the input power source occurs. + This prevents input voltage drop due to insufficient + current provided by the power source. + Default: 4500000 uV (4.5V) +- richtek,avg-input-current-regulation: integer, input current value in uA drained by the + charger from the power source. + Default: 500000 uA (500mA) + +Example: + +rt9455@22 { + compatible = "richtek,rt9455"; + reg = <0x22>; + + interrupt-parent = <&gpio1>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + + richtek,output-charge-current = <500000>; + richtek,end-of-charge-percentage = <10>; + richtek,battery-regulation-voltage = <4200000>; + richtek,boost-output-voltage = <5050000>; + + richtek,min-input-voltage-regulation = <4500000>; + richtek,avg-input-current-regulation = <500000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/rx51-battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/rx51-battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..90438453db58d8692657c0817bcf7854dbf51bba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/rx51-battery.txt @@ -0,0 +1,25 @@ +Binding for Nokia N900 battery + +The Nokia N900 battery status can be read via the TWL4030's A/D converter. + +Required properties: +- compatible: Should contain one of the following: + * "nokia,n900-battery" +- io-channels: Should contain IIO channel specifiers + for each element in io-channel-names. +- io-channel-names: Should contain the following values: + * "temp" - The ADC channel for temperature reading + * "bsi" - The ADC channel for battery size identification + * "vbat" - The ADC channel to measure the battery voltage + +Example from Nokia N900: + +battery: n900-battery { + compatible = "nokia,n900-battery"; + io-channels = <&twl4030_madc 0>, + <&twl4030_madc 4>, + <&twl4030_madc 12>; + io-channel-names = "temp", + "bsi", + "vbat"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs,sbs-manager.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs,sbs-manager.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b2195571a49e9c3338f2b2cfe68ba58450cc0a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs,sbs-manager.txt @@ -0,0 +1,66 @@ +Binding for sbs-manager + +Required properties: +- compatible: ",", "sbs,sbs-charger" as fallback. The part + number compatible string might be used in order to take care of vendor + specific registers. +- reg: integer, i2c address of the device. Should be <0xa>. +Optional properties: +- gpio-controller: Marks the port as GPIO controller. + See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt. +- #gpio-cells: Should be <2>. The first cell is the pin number, the second cell + is used to specify optional parameters: + See "gpio-specifier" in .../devicetree/bindings/gpio/gpio.txt. + +From OS view the device is basically an i2c-mux used to communicate with up to +four smart battery devices at address 0xb. The driver actually implements this +behaviour. So standard i2c-mux nodes can be used to register up to four slave +batteries. Channels will be numerated starting from 1 to 4. + +Example: + +batman@a { + compatible = "lltc,ltc1760", "sbs,sbs-manager"; + reg = <0x0a>; + #address-cells = <1>; + #size-cells = <0>; + + gpio-controller; + #gpio-cells = <2>; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + battery@b { + compatible = "ti,bq2060", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&batman 1 1>; + }; + }; + + i2c@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + battery@b { + compatible = "ti,bq2060", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&batman 2 1>; + }; + }; + + i2c@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + + battery@b { + compatible = "ti,bq2060", "sbs,sbs-battery"; + reg = <0x0b>; + sbs,battery-detect-gpios = <&batman 3 1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs_sbs-battery.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs_sbs-battery.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e78e51018ebd917a265e3fa3cf71c901eb50646 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs_sbs-battery.txt @@ -0,0 +1,27 @@ +SBS sbs-battery +~~~~~~~~~~ + +Required properties : + - compatible: ",", "sbs,sbs-battery" as fallback. The + part number compatible string might be used in order to take care of + vendor specific registers. + Known ,: + ti,bq20z75 + +Optional properties : + - sbs,i2c-retry-count : The number of times to retry i2c transactions on i2c + IO failure. + - sbs,poll-retry-count : The number of times to try looking for new status + after an external change notification. + - sbs,battery-detect-gpios : The gpio which signals battery detection and + a flag specifying its polarity. + +Example: + + battery@b { + compatible = "ti,bq20z75", "sbs,sbs-battery"; + reg = <0xb>; + sbs,i2c-retry-count = <2>; + sbs,poll-retry-count = <10>; + sbs,battery-detect-gpios = <&gpio-controller 122 1>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs_sbs-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs_sbs-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..84e74151eef219bb5841ab8cdd64b1f713e9775a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/sbs_sbs-charger.txt @@ -0,0 +1,21 @@ +SBS sbs-charger +~~~~~~~~~~ + +Required properties: + - compatible: ",", "sbs,sbs-charger" as fallback. The part + number compatible string might be used in order to take care of vendor + specific registers. + +Optional properties: +- interrupts: Interrupt mapping for GPIO IRQ. Use in conjunction with + "interrupt-parent". If an interrupt is not provided the driver will switch + automatically to polling. + +Example: + + ltc4100@9 { + compatible = "lltc,ltc4100", "sbs,sbs-charger"; + reg = <0x9>; + interrupt-parent = <&gpio6>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/ti,bq24735.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/ti,bq24735.txt new file mode 100644 index 0000000000000000000000000000000000000000..de45e1a2a4d9e3e35851255316e7574ea187cbe2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/ti,bq24735.txt @@ -0,0 +1,39 @@ +TI BQ24735 Charge Controller +~~~~~~~~~~ + +Required properties : + - compatible : "ti,bq24735" + +Optional properties : + - interrupts : Specify the interrupt to be used to trigger when the AC + adapter is either plugged in or removed. + - ti,ac-detect-gpios : This GPIO is optionally used to read the AC adapter + status. This is a Host GPIO that is configured as an input and connected + to the ACOK pin on the bq24735. Note: for backwards compatibility reasons, + the GPIO must be active on AC adapter absence despite ACOK being active + (high) on AC adapter presence. + - ti,charge-current : Used to control and set the charging current. This value + must be between 128mA and 8.128A with a 64mA step resolution. The POR value + is 0x0000h. This number is in mA (e.g. 8192), see spec for more information + about the ChargeCurrent (0x14h) register. + - ti,charge-voltage : Used to control and set the charging voltage. This value + must be between 1.024V and 19.2V with a 16mV step resolution. The POR value + is 0x0000h. This number is in mV (e.g. 19200), see spec for more information + about the ChargeVoltage (0x15h) register. + - ti,input-current : Used to control and set the charger input current. This + value must be between 128mA and 8.064A with a 128mA step resolution. The + POR value is 0x1000h. This number is in mA (e.g. 8064), see the spec for + more information about the InputCurrent (0x3fh) register. + - ti,external-control : Indicates that the charger is configured externally + and that the host should not attempt to enable/disable charging or set the + charge voltage/current. + - poll-interval : In case 'interrupts' is not specified, poll AC adapter + presence with this interval (milliseconds). + +Example: + + bq24735@9 { + compatible = "ti,bq24735"; + reg = <0x9>; + ti,ac-detect-gpios = <&gpio 72 0x1>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/tps65090.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/tps65090.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e5e0d3910dfcfeb18b3a05c0047669a9dd69319 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/tps65090.txt @@ -0,0 +1,17 @@ +TPS65090 Frontend PMU with Switchmode Charger + +Required Properties: +-compatible: "ti,tps65090-charger" + +Optional Properties: +-ti,enable-low-current-chrg: Enables charging when a low current is detected + while the default logic is to stop charging. + +This node is a subnode of the tps65090 PMIC. + +Example: + + tps65090-charger { + compatible = "ti,tps65090-charger"; + ti,enable-low-current-chrg; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/tps65217_charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/tps65217_charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..a11072c5a8660d362958995a6fd27123c296b2fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/tps65217_charger.txt @@ -0,0 +1,17 @@ +TPS65217 Charger + +Required Properties: +-compatible: "ti,tps65217-charger" +-interrupts: TPS65217 interrupt numbers for the AC and USB charger input change. + Should be <0> for the USB charger and <1> for the AC adapter. +-interrupt-names: Should be "USB" and "AC" + +This node is a subnode of the tps65217 PMIC. + +Example: + + tps65217-charger { + compatible = "ti,tps65217-charger"; + interrupts = <0>, <1>; + interrupt-names = "USB", "AC"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/twl-charger.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/twl-charger.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b4ea1b73b38293619c11c5483ef583229317611 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/twl-charger.txt @@ -0,0 +1,30 @@ +TWL BCI (Battery Charger Interface) + +The battery charger needs to interact with the USB phy in order +to know when charging is permissible, and when there is a connection +or disconnection. + +The choice of phy cannot be configured at a hardware level, so there +is no value in explicit configuration in device-tree. Rather +if there is a sibling of the BCI node which is compatible with +"ti,twl4030-usb", then that is used to determine when and how +use USB power for charging. + +Required properties: +- compatible: + - "ti,twl4030-bci" +- interrupts: two interrupt lines from the TWL SIH (secondary + interrupt handler) - interrupts 9 and 2. + +Optional properties: +- ti,bb-uvolt: microvolts for charging the backup battery. +- ti,bb-uamp: microamps for charging the backup battery. + +Examples: + +bci { + compatible = "ti,twl4030-bci"; + interrupts = <9>, <2>; + ti,bb-uvolt = <3200000>; + ti,bb-uamp = <150>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/ti-smartreflex.txt b/arch/arm64/boot/dts/vendor/bindings/power/ti-smartreflex.txt new file mode 100644 index 0000000000000000000000000000000000000000..21ef14d6af12f3d65d7cef1c7bf6956525368c49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/ti-smartreflex.txt @@ -0,0 +1,47 @@ +Texas Instruments SmartReflex binding + +SmartReflex is used to set and adjust the SoC operating points. + + +Required properties: + +compatible: Shall be one of the following: + "ti,omap3-smartreflex-core" + "ti,omap3-smartreflex-mpu-iva" + "ti,omap4-smartreflex-core" + "ti,omap4-smartreflex-mpu" + "ti,omap4-smartreflex-iva" + +reg: Shall contain the device instance IO range + +interrupts: Shall contain the device instance interrupt + + +Optional properties: + +ti,hwmods: Shall contain the TI interconnect module name if needed + by the SoC + + +Example: + + smartreflex_iva: smartreflex@4a0db000 { + compatible = "ti,omap4-smartreflex-iva"; + reg = <0x4a0db000 0x80>; + interrupts = ; + ti,hwmods = "smartreflex_iva"; + }; + + smartreflex_core: smartreflex@4a0dd000 { + compatible = "ti,omap4-smartreflex-core"; + reg = <0x4a0dd000 0x80>; + interrupts = ; + ti,hwmods = "smartreflex_core"; + }; + + smartreflex_mpu: smartreflex@4a0d9000 { + compatible = "ti,omap4-smartreflex-mpu"; + reg = <0x4a0d9000 0x80>; + interrupts = ; + ti,hwmods = "smartreflex_mpu"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/power/wakeup-source.txt b/arch/arm64/boot/dts/vendor/bindings/power/wakeup-source.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfd74659fbed03e00a6de0e7f0150b32fbf3713b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/wakeup-source.txt @@ -0,0 +1,70 @@ +Specifying wakeup capability for devices +============================================ + +Any device nodes +---------------- +Nodes that describe devices which has wakeup capability must contain an +"wakeup-source" boolean property. + +Also, if device is marked as a wakeup source, then all the primary +interrupt(s) can be used as wakeup interrupt(s). + +However if the devices have dedicated interrupt as the wakeup source +then they need to specify/identify the same using device specific +interrupt name. In such cases only that interrupt can be used as wakeup +interrupt. + +List of legacy properties and respective binding document +--------------------------------------------------------- + +1. "enable-sdio-wakeup" Documentation/devicetree/bindings/mmc/mmc.txt +2. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt +3. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt +4. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt + Documentation/devicetree/bindings/mfd/tc3589x.txt + Documentation/devicetree/bindings/input/touchscreen/ads7846.txt +5. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt +6. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt +7. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt + +Examples +-------- + +1. With "wakeup" interrupt name + + device@10000 { + compatible = "vendor,device-id"; + reg = <0x10000 0x1000>; + interrupts = <0 19 4>, <0 21 4>, <0 22 4>; + interrupt-names = "ack", "err", "wakeup"; + wakeup-source; + }; + +2. Without "wakeup" interrupt name + + embedded-controller { + compatible = "google,cros-ec-i2c"; + reg = <0x1e>; + interrupts = <6 0>; + interrupt-parent = <&gpx1>; + pinctrl-names = "default"; + pinctrl-0 = <&ec_irq>; + wakeup-source; + }; + +3. Without interrupts + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button@1 { + debounce-interval = <50>; + wakeup-source; + linux,code = <116>; + label = "POWER"; + gpios = <&iofpga_gpio0 0 0x4>; + }; + [....] + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/akebono.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/akebono.txt new file mode 100644 index 0000000000000000000000000000000000000000..940fd78e3363b192a340de49feb3588a3e3ec107 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/akebono.txt @@ -0,0 +1,52 @@ + +IBM Akebono board device tree +============================= + +The IBM Akebono board is a development board for the PPC476GTR SoC. + +0) The root node + + Required properties: + + - model : "ibm,akebono". + - compatible : "ibm,akebono" , "ibm,476gtr". + +1.a) The Secure Digital Host Controller Interface (SDHCI) node + + Represent the Secure Digital Host Controller Interfaces. + + Required properties: + + - compatible : should be "ibm,476gtr-sdhci","generic-sdhci". + - reg : should contain the SDHCI registers location and length. + - interrupts : should contain the SDHCI interrupt. + +1.b) The Advanced Host Controller Interface (AHCI) SATA node + + Represents the advanced host controller SATA interface. + + Required properties: + + - compatible : should be "ibm,476gtr-ahci". + - reg : should contain the AHCI registers location and length. + - interrupts : should contain the AHCI interrupt. + +1.c) The FPGA node + + The Akebono board stores some board information such as the revision + number in an FPGA which is represented by this node. + + Required properties: + + - compatible : should be "ibm,akebono-fpga". + - reg : should contain the FPGA registers location and length. + +1.d) The AVR node + + The Akebono board has an Atmel AVR microprocessor attached to the I2C + bus as a power controller for the board. + + Required properties: + + - compatible : should be "ibm,akebono-avr". + - reg : should contain the I2C bus address for the AVR. diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/cpm.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/cpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee459806d35e3256e9a36d820f6cf3758c89543b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/cpm.txt @@ -0,0 +1,52 @@ +PPC4xx Clock Power Management (CPM) node + +Required properties: + - compatible : compatible list, currently only "ibm,cpm" + - dcr-access-method : "native" + - dcr-reg : < DCR register range > + +Optional properties: + - er-offset : All 4xx SoCs with a CPM controller have + one of two different order for the CPM + registers. Some have the CPM registers + in the following order (ER,FR,SR). The + others have them in the following order + (SR,ER,FR). For the second case set + er-offset = <1>. + - unused-units : specifier consist of one cell. For each + bit in the cell, the corresponding bit + in CPM will be set to turn off unused + devices. + - idle-doze : specifier consist of one cell. For each + bit in the cell, the corresponding bit + in CPM will be set to turn off unused + devices. This is usually just CPM[CPU]. + - standby : specifier consist of one cell. For each + bit in the cell, the corresponding bit + in CPM will be set on standby and + restored on resume. + - suspend : specifier consist of one cell. For each + bit in the cell, the corresponding bit + in CPM will be set on suspend (mem) and + restored on resume. Note, for standby + and suspend the corresponding bits can + be different or the same. Usually for + standby only class 2 and 3 units are set. + However, the interface does not care. + If they are the same, the additional + power saving will be seeing if support + is available to put the DDR in self + refresh mode and any additional power + saving techniques for the specific SoC. + +Example: + CPM0: cpm { + compatible = "ibm,cpm"; + dcr-access-method = "native"; + dcr-reg = <0x160 0x003>; + er-offset = <0>; + unused-units = <0x00000100>; + idle-doze = <0x02000000>; + standby = <0xfeff0000>; + suspend = <0xfeff791d>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/hsta.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/hsta.txt new file mode 100644 index 0000000000000000000000000000000000000000..66dbd9ff56f7c3ccd3d2b9fea6ca1021ab6265a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/hsta.txt @@ -0,0 +1,18 @@ + +ppc476gtr High Speed Serial Assist (HSTA) node +============================================== + +The 476gtr SoC contains a high speed serial assist module attached +between the plb4 and plb6 system buses to provide high speed data +transfer between memory and system peripherals as well as support for +PCI message signalled interrupts. + +Currently only the MSI support is used by Linux using the following +device tree entries: + +Require properties: +- compatible : "ibm,476gtr-hsta-msi", "ibm,hsta-msi" +- reg : register mapping for the HSTA MSI space +- interrupts : ordered interrupt mapping for each MSI in the register + space. The first interrupt should be associated with a + register offset of 0x00, the second to 0x10, etc. diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/ppc440spe-adma.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/ppc440spe-adma.txt new file mode 100644 index 0000000000000000000000000000000000000000..de6a5f7d4aa4807d9bf3de0ef7dececee60b59c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/ppc440spe-adma.txt @@ -0,0 +1,91 @@ +PPC440SPe DMA/XOR (DMA Controller and XOR Accelerator) + +Device nodes needed for operation of the ppc440spe-adma driver +are specified hereby. These are I2O/DMA, DMA and XOR nodes +for DMA engines and Memory Queue Module node. The latter is used +by ADMA driver for configuration of RAID-6 H/W capabilities of +the PPC440SPe. In addition to the nodes and properties described +below, the ranges property of PLB node must specify ranges for +DMA devices. + + i) The I2O node + + Required properties: + + - compatible : "ibm,i2o-440spe"; + - reg : + - dcr-reg : + + Example: + + I2O: i2o@400100000 { + compatible = "ibm,i2o-440spe"; + reg = <0x00000004 0x00100000 0x100>; + dcr-reg = <0x060 0x020>; + }; + + + ii) The DMA node + + Required properties: + + - compatible : "ibm,dma-440spe"; + - cell-index : 1 cell, hardware index of the DMA engine + (typically 0x0 and 0x1 for DMA0 and DMA1) + - reg : + - dcr-reg : + - interrupts : . + + Example: + + DMA0: dma0@400100100 { + compatible = "ibm,dma-440spe"; + cell-index = <0>; + reg = <0x00000004 0x00100100 0x100>; + dcr-reg = <0x060 0x020>; + interrupt-parent = <&DMA0>; + interrupts = <0 1>; + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = < + 0 &UIC0 0x14 4 + 1 &UIC1 0x16 4>; + }; + + + iii) XOR Accelerator node + + Required properties: + + - compatible : "amcc,xor-accelerator"; + - reg : + - interrupts : + + Example: + + xor-accel@400200000 { + compatible = "amcc,xor-accelerator"; + reg = <0x00000004 0x00200000 0x400>; + interrupt-parent = <&UIC1>; + interrupts = <0x1f 4>; + }; + + + iv) Memory Queue Module node + + Required properties: + + - compatible : "ibm,mq-440spe"; + - dcr-reg : + + Example: + + MQ0: mq { + compatible = "ibm,mq-440spe"; + dcr-reg = <0x040 0x020>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/reboot.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/reboot.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bc63551319e6656c41205cc9f116fea307c2e0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/4xx/reboot.txt @@ -0,0 +1,18 @@ +Reboot property to control system reboot on PPC4xx systems: + +By setting "reset_type" to one of the following values, the default +software reset mechanism may be overridden. Here the possible values of +"reset_type": + + 1 - PPC4xx core reset + 2 - PPC4xx chip reset + 3 - PPC4xx system reset (default) + +Example: + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,440SPe"; + ... + reset-type = <2>; /* Use chip-reset */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/cache_sram.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/cache_sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..781955f5217d55cec05746dd2316a96ac04cdbad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/cache_sram.txt @@ -0,0 +1,20 @@ +* Freescale PQ3 and QorIQ based Cache SRAM + +Freescale's mpc85xx and some QorIQ platforms provide an +option of configuring a part of (or full) cache memory +as SRAM. This cache SRAM representation in the device +tree should be done as under:- + +Required properties: + +- compatible : should be "fsl,p2020-cache-sram" +- fsl,cache-sram-ctlr-handle : points to the L2 controller +- reg : offset and length of the cache-sram. + +Example: + +cache-sram@fff00000 { + fsl,cache-sram-ctlr-handle = <&L2>; + reg = <0 0xfff00000 0 0x10000>; + compatible = "fsl,p2020-cache-sram"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/ccf.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/ccf.txt new file mode 100644 index 0000000000000000000000000000000000000000..454da7e08acdc0fcd11826654699b03d2b54d099 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/ccf.txt @@ -0,0 +1,46 @@ +Freescale CoreNet Coherency Fabric(CCF) Device Tree Binding + +DESCRIPTION + +The CoreNet coherency fabric is a fabric-oriented, connectivity infrastructure +that enables the implementation of coherent, multicore systems. + +Required properties: + +- compatible: + fsl,corenet1-cf - CoreNet coherency fabric version 1. + Example chips: T4240, B4860 + + fsl,corenet2-cf - CoreNet coherency fabric version 2. + Example chips: P5040, P5020, P4080, P3041, P2041 + + fsl,corenet-cf - Used to represent the common registers + between CCF version 1 and CCF version 2. This compatible + is retained for compatibility reasons, as it was already + used for both CCF version 1 chips and CCF version 2 + chips. It should be specified after either + "fsl,corenet1-cf" or "fsl,corenet2-cf". + +- reg: + A standard property. Represents the CCF registers. + +- interrupts: + Interrupt mapping for CCF error interrupt. + +- fsl,ccf-num-csdids: + Specifies the number of Coherency Subdomain ID Port Mapping + Registers that are supported by the CCF. + +- fsl,ccf-num-snoopids: + Specifies the number of Snoop ID Port Mapping Registers that + are supported by CCF. + +Example: + + corenet-cf@18000 { + compatible = "fsl,corenet2-cf", "fsl,corenet-cf"; + reg = <0x18000 0x1000>; + interrupts = <16 2 1 31>; + fsl,ccf-num-csdids = <32>; + fsl,ccf-num-snoopids = <32>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/diu.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/diu.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb45db1ecee590cc7f7094058c8bafdf7c03ec00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/diu.txt @@ -0,0 +1,32 @@ +* Freescale Display Interface Unit + +The Freescale DIU is a LCD controller, with proper hardware, it can also +drive DVI monitors. + +Required properties: +- compatible : should be "fsl,diu" or "fsl,mpc5121-diu". +- reg : should contain at least address and length of the DIU register + set. +- interrupts : one DIU interrupt should be described here. + +Optional properties: +- edid : verbatim EDID data block describing attached display. + Data from the detailed timing descriptor will be used to + program the display controller. + +Example (MPC8610HPCD): + display@2c000 { + compatible = "fsl,diu"; + reg = <0x2c000 100>; + interrupts = <72 2>; + interrupt-parent = <&mpic>; + }; + +Example for MPC5121: + display@2100 { + compatible = "fsl,mpc5121-diu"; + reg = <0x2100 0x100>; + interrupts = <64 0x8>; + interrupt-parent = <&ipic>; + edid = [edid-data]; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/dma.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..c11ad5c6db2190bf38c160632d9997122e169945 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/dma.txt @@ -0,0 +1,204 @@ +* Freescale DMA Controllers + +** Freescale Elo DMA Controller + This is a little-endian 4-channel DMA controller, used in Freescale mpc83xx + series chips such as mpc8315, mpc8349, mpc8379 etc. + +Required properties: + +- compatible : must include "fsl,elo-dma" +- reg : DMA General Status Register, i.e. DGSR which contains + status for all the 4 DMA channels +- ranges : describes the mapping between the address space of the + DMA channels and the address space of the DMA controller +- cell-index : controller index. 0 for controller @ 0x8100 +- interrupts : interrupt specifier for DMA IRQ + +- DMA channel nodes: + - compatible : must include "fsl,elo-dma-channel" + However, see note below. + - reg : DMA channel specific registers + - cell-index : DMA channel index starts at 0. + +Optional properties: + - interrupts : interrupt specifier for DMA channel IRQ + (on 83xx this is expected to be identical to + the interrupts property of the parent node) + +Example: + dma@82a8 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8349-dma", "fsl,elo-dma"; + reg = <0x82a8 4>; + ranges = <0 0x8100 0x1a4>; + interrupt-parent = <&ipic>; + interrupts = <71 8>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; + cell-index = <0>; + reg = <0 0x80>; + interrupt-parent = <&ipic>; + interrupts = <71 8>; + }; + dma-channel@80 { + compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; + cell-index = <1>; + reg = <0x80 0x80>; + interrupt-parent = <&ipic>; + interrupts = <71 8>; + }; + dma-channel@100 { + compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; + cell-index = <2>; + reg = <0x100 0x80>; + interrupt-parent = <&ipic>; + interrupts = <71 8>; + }; + dma-channel@180 { + compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel"; + cell-index = <3>; + reg = <0x180 0x80>; + interrupt-parent = <&ipic>; + interrupts = <71 8>; + }; + }; + +** Freescale EloPlus DMA Controller + This is a 4-channel DMA controller with extended addresses and chaining, + mainly used in Freescale mpc85xx/86xx, Pxxx and BSC series chips, such as + mpc8540, mpc8641 p4080, bsc9131 etc. + +Required properties: + +- compatible : must include "fsl,eloplus-dma" +- reg : DMA General Status Register, i.e. DGSR which contains + status for all the 4 DMA channels +- cell-index : controller index. 0 for controller @ 0x21000, + 1 for controller @ 0xc000 +- ranges : describes the mapping between the address space of the + DMA channels and the address space of the DMA controller + +- DMA channel nodes: + - compatible : must include "fsl,eloplus-dma-channel" + However, see note below. + - cell-index : DMA channel index starts at 0. + - reg : DMA channel specific registers + - interrupts : interrupt specifier for DMA channel IRQ + +Example: + dma@21300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma"; + reg = <0x21300 4>; + ranges = <0 0x21100 0x200>; + cell-index = <0>; + dma-channel@0 { + compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel"; + reg = <0 0x80>; + cell-index = <0>; + interrupt-parent = <&mpic>; + interrupts = <20 2>; + }; + dma-channel@80 { + compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + cell-index = <1>; + interrupt-parent = <&mpic>; + interrupts = <21 2>; + }; + dma-channel@100 { + compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + cell-index = <2>; + interrupt-parent = <&mpic>; + interrupts = <22 2>; + }; + dma-channel@180 { + compatible = "fsl,mpc8540-dma-channel", "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + cell-index = <3>; + interrupt-parent = <&mpic>; + interrupts = <23 2>; + }; + }; + +** Freescale Elo3 DMA Controller + DMA controller which has same function as EloPlus except that Elo3 has 8 + channels while EloPlus has only 4, it is used in Freescale Txxx and Bxxx + series chips, such as t1040, t4240, b4860. + +Required properties: + +- compatible : must include "fsl,elo3-dma" +- reg : contains two entries for DMA General Status Registers, + i.e. DGSR0 which includes status for channel 1~4, and + DGSR1 for channel 5~8 +- ranges : describes the mapping between the address space of the + DMA channels and the address space of the DMA controller + +- DMA channel nodes: + - compatible : must include "fsl,eloplus-dma-channel" + - reg : DMA channel specific registers + - interrupts : interrupt specifier for DMA channel IRQ + +Example: +dma@100300 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elo3-dma"; + reg = <0x100300 0x4>, + <0x100600 0x4>; + ranges = <0x0 0x100100 0x500>; + dma-channel@0 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x0 0x80>; + interrupts = <28 2 0 0>; + }; + dma-channel@80 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x80 0x80>; + interrupts = <29 2 0 0>; + }; + dma-channel@100 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x100 0x80>; + interrupts = <30 2 0 0>; + }; + dma-channel@180 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x180 0x80>; + interrupts = <31 2 0 0>; + }; + dma-channel@300 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x300 0x80>; + interrupts = <76 2 0 0>; + }; + dma-channel@380 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x380 0x80>; + interrupts = <77 2 0 0>; + }; + dma-channel@400 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x400 0x80>; + interrupts = <78 2 0 0>; + }; + dma-channel@480 { + compatible = "fsl,eloplus-dma-channel"; + reg = <0x480 0x80>; + interrupts = <79 2 0 0>; + }; +}; + +Note on DMA channel compatible properties: The compatible property must say +"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA +driver (fsldma). Any DMA channel used by fsldma cannot be used by another +DMA driver, such as the SSI sound drivers for the MPC8610. Therefore, any DMA +channel that should be used for another driver should not use +"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel". For the SSI drivers, for +example, the compatible property should be "fsl,ssi-dma-channel". See ssi.txt +for more information. diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/l2cache.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/l2cache.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a70696395a7de942d7ae0e69c86d8ae693e974a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/l2cache.txt @@ -0,0 +1,61 @@ +Freescale L2 Cache Controller + +L2 cache is present in Freescale's QorIQ and QorIQ Qonverge platforms. +The cache bindings explained below are Devicetree Specification compliant + +Required Properties: + +- compatible : Should include one of the following: + "fsl,8540-l2-cache-controller" + "fsl,8541-l2-cache-controller" + "fsl,8544-l2-cache-controller" + "fsl,8548-l2-cache-controller" + "fsl,8555-l2-cache-controller" + "fsl,8568-l2-cache-controller" + "fsl,b4420-l2-cache-controller" + "fsl,b4860-l2-cache-controller" + "fsl,bsc9131-l2-cache-controller" + "fsl,bsc9132-l2-cache-controller" + "fsl,c293-l2-cache-controller" + "fsl,mpc8536-l2-cache-controller" + "fsl,mpc8540-l2-cache-controller" + "fsl,mpc8541-l2-cache-controller" + "fsl,mpc8544-l2-cache-controller" + "fsl,mpc8548-l2-cache-controller" + "fsl,mpc8555-l2-cache-controller" + "fsl,mpc8560-l2-cache-controller" + "fsl,mpc8568-l2-cache-controller" + "fsl,mpc8569-l2-cache-controller" + "fsl,mpc8572-l2-cache-controller" + "fsl,p1010-l2-cache-controller" + "fsl,p1011-l2-cache-controller" + "fsl,p1012-l2-cache-controller" + "fsl,p1013-l2-cache-controller" + "fsl,p1014-l2-cache-controller" + "fsl,p1015-l2-cache-controller" + "fsl,p1016-l2-cache-controller" + "fsl,p1020-l2-cache-controller" + "fsl,p1021-l2-cache-controller" + "fsl,p1022-l2-cache-controller" + "fsl,p1023-l2-cache-controller" + "fsl,p1024-l2-cache-controller" + "fsl,p1025-l2-cache-controller" + "fsl,p2010-l2-cache-controller" + "fsl,p2020-l2-cache-controller" + "fsl,t2080-l2-cache-controller" + "fsl,t4240-l2-cache-controller" + and "cache". +- reg : Address and size of L2 cache controller registers +- cache-size : Size of the entire L2 cache +- interrupts : Error interrupt of L2 controller +- cache-line-size : Size of L2 cache lines + +Example: + + L2: l2-cache-controller@20000 { + compatible = "fsl,bsc9132-l2-cache-controller", "cache"; + reg = <0x20000 0x1000>; + cache-line-size = <32>; // 32 bytes + cache-size = <0x40000>; // L2,256K + interrupts = <16 2 1 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/lbc.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/lbc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c80fcedebb52049721fbd61c4dd4c57133bd47c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/lbc.txt @@ -0,0 +1,43 @@ +* Chipselect/Local Bus + +Properties: +- name : Should be localbus +- #address-cells : Should be either two or three. The first cell is the + chipselect number, and the remaining cells are the + offset into the chipselect. +- #size-cells : Either one or two, depending on how large each chipselect + can be. +- ranges : Each range corresponds to a single chipselect, and cover + the entire access window as configured. + +Example: + localbus@f0010100 { + compatible = "fsl,mpc8272-localbus", + "fsl,pq2-localbus"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0xf0010100 0x40>; + + ranges = <0x0 0x0 0xfe000000 0x02000000 + 0x1 0x0 0xf4500000 0x00008000 + 0x2 0x0 0xfd810000 0x00010000>; + + flash@0,0 { + compatible = "jedec-flash"; + reg = <0x0 0x0 0x2000000>; + bank-width = <4>; + device-width = <1>; + }; + + board-control@1,0 { + reg = <0x1 0x0 0x20>; + compatible = "fsl,mpc8272ads-bcsr"; + }; + + simple-periph@2,0 { + compatible = "fsl,elbc-gpcm-uio"; + reg = <0x2 0x0 0x10000>; + elbc-gpcm-br = <0xfd810800>; + elbc-gpcm-or = <0xffff09f7>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mcu-mpc8349emitx.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mcu-mpc8349emitx.txt new file mode 100644 index 0000000000000000000000000000000000000000..37f91fa576545aa245d893c24248bdbb2c0fcc07 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mcu-mpc8349emitx.txt @@ -0,0 +1,17 @@ +Freescale MPC8349E-mITX-compatible Power Management Micro Controller Unit (MCU) + +Required properties: +- compatible : "fsl,-", "fsl,mcu-mpc8349emitx". +- reg : should specify I2C address (0x0a). +- #gpio-cells : should be 2. +- gpio-controller : should be present. + +Example: + +mcu@a { + #gpio-cells = <2>; + compatible = "fsl,mc9s08qg8-mpc8349emitx", + "fsl,mcu-mpc8349emitx"; + reg = <0x0a>; + gpio-controller; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc5121-psc.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc5121-psc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5dfd68f1a4237b0892b4f511b4aa85f5949d2e9e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc5121-psc.txt @@ -0,0 +1,78 @@ +MPC5121 PSC Device Tree Bindings + +PSC in UART mode +---------------- + +For PSC in UART mode the needed PSC serial devices +are specified by fsl,mpc5121-psc-uart nodes in the +fsl,mpc5121-immr SoC node. Additionally the PSC FIFO +Controller node fsl,mpc5121-psc-fifo is required there: + +fsl,mpc512x-psc-uart nodes +-------------------------- + +Required properties : + - compatible : Should contain "fsl,-psc-uart" and "fsl,-psc" + Supported s: mpc5121, mpc5125 + - reg : Offset and length of the register set for the PSC device + - interrupts : where a is the interrupt number of the + PSC FIFO Controller and b is a field that represents an + encoding of the sense and level information for the interrupt. + +Recommended properties : + - fsl,rx-fifo-size : the size of the RX fifo slice (a multiple of 4) + - fsl,tx-fifo-size : the size of the TX fifo slice (a multiple of 4) + +PSC in SPI mode +--------------- + +Similar to the UART mode a PSC can be operated in SPI mode. The compatible used +for that is fsl,mpc5121-psc-spi. It requires a fsl,mpc5121-psc-fifo as well. +The required and recommended properties are identical to the +fsl,mpc5121-psc-uart nodes, just use spi instead of uart in the compatible +string. + +fsl,mpc512x-psc-fifo node +------------------------- + +Required properties : + - compatible : Should be "fsl,-psc-fifo" + Supported s: mpc5121, mpc5125 + - reg : Offset and length of the register set for the PSC + FIFO Controller + - interrupts : where a is the interrupt number of the + PSC FIFO Controller and b is a field that represents an + encoding of the sense and level information for the interrupt. + +Recommended properties : + - clocks : specifies the clock needed to operate the fifo controller + - clock-names : name(s) for the clock(s) listed in clocks + +Example for a board using PSC0 and PSC1 devices in serial mode: + +serial@11000 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <0>; + reg = <0x11000 0x100>; + interrupts = <40 0x8>; + interrupt-parent = < &ipic >; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; +}; + +serial@11100 { + compatible = "fsl,mpc5121-psc-uart", "fsl,mpc5121-psc"; + cell-index = <1>; + reg = <0x11100 0x100>; + interrupts = <40 0x8>; + interrupt-parent = < &ipic >; + fsl,rx-fifo-size = <16>; + fsl,tx-fifo-size = <16>; +}; + +pscfifo@11f00 { + compatible = "fsl,mpc5121-psc-fifo"; + reg = <0x11f00 0x100>; + interrupts = <40 0x8>; + interrupt-parent = < &ipic >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc512x_lpbfifo.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc512x_lpbfifo.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3b392fe1f61fbecfe1593ae4e216176505f7407 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc512x_lpbfifo.txt @@ -0,0 +1,21 @@ +Freescale MPC512x LocalPlus Bus FIFO (called SCLPC in the Reference Manual) + +Required properties: +- compatible: should be "fsl,mpc512x-lpbfifo"; +- reg: should contain the offset and length of SCLPC register set; +- interrupts: should contain the interrupt specifier for SCLPC; syntax of an + interrupt client node is described in interrupt-controller/interrupts.txt; +- dmas: should contain the DMA specifier for SCLPC as described at + dma/dma.txt and dma/mpc512x-dma.txt; +- dma-names: should be "rx-tx"; + +Example: + + sclpc@10100 { + compatible = "fsl,mpc512x-lpbfifo"; + reg = <0x10100 0x50>; + interrupts = <7 0x8>; + dmas = <&dma0 26>; + dma-names = "rx-tx"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc5200.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc5200.txt new file mode 100644 index 0000000000000000000000000000000000000000..d096cf461d81ccf196c9b5b41f948259a71271b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpc5200.txt @@ -0,0 +1,198 @@ +MPC5200 Device Tree Bindings +---------------------------- + +(c) 2006-2009 Secret Lab Technologies Ltd +Grant Likely + +Naming conventions +------------------ +For mpc5200 on-chip devices, the format for each compatible value is +-[-]. The OS should be able to match a device driver +to the device based solely on the compatible value. If two drivers +match on the compatible list; the 'most compatible' driver should be +selected. + +The split between the MPC5200 and the MPC5200B leaves a bit of a +conundrum. How should the compatible property be set up to provide +maximum compatibility information; but still accurately describe the +chip? For the MPC5200; the answer is easy. Most of the SoC devices +originally appeared on the MPC5200. Since they didn't exist anywhere +else; the 5200 compatible properties will contain only one item; +"fsl,mpc5200-". + +The 5200B is almost the same as the 5200, but not quite. It fixes +silicon bugs and it adds a small number of enhancements. Most of the +devices either provide exactly the same interface as on the 5200. A few +devices have extra functions but still have a backwards compatible mode. +To express this information as completely as possible, 5200B device trees +should have two items in the compatible list: + compatible = "fsl,mpc5200b-","fsl,mpc5200-"; + +It is *strongly* recommended that 5200B device trees follow this convention +(instead of only listing the base mpc5200 item). + +ie. ethernet on mpc5200: compatible = "fsl,mpc5200-fec"; + ethernet on mpc5200b: compatible = "fsl,mpc5200b-fec", "fsl,mpc5200-fec"; + +Modal devices, like PSCs, also append the configured function to the +end of the compatible field. ie. A PSC in i2s mode would specify +"fsl,mpc5200-psc-i2s", not "fsl,mpc5200-i2s". This convention is chosen to +avoid naming conflicts with non-psc devices providing the same +function. For example, "fsl,mpc5200-spi" and "fsl,mpc5200-psc-spi" describe +the mpc5200 simple spi device and a PSC spi mode respectively. + +At the time of writing, exact chip may be either 'fsl,mpc5200' or +'fsl,mpc5200b'. + +The soc node +------------ +This node describes the on chip SOC peripherals. Every mpc5200 based +board will have this node, and as such there is a common naming +convention for SOC devices. + +Required properties: +name description +---- ----------- +ranges Memory range of the internal memory mapped registers. + Should be <0 [baseaddr] 0xc000> +reg Should be <[baseaddr] 0x100> +compatible mpc5200: "fsl,mpc5200-immr" + mpc5200b: "fsl,mpc5200b-immr" +system-frequency 'fsystem' frequency in Hz; XLB, IPB, USB and PCI + clocks are derived from the fsystem clock. +bus-frequency IPB bus frequency in Hz. Clock rate + used by most of the soc devices. + +soc child nodes +--------------- +Any on chip SOC devices available to Linux must appear as soc5200 child nodes. + +Note: The tables below show the value for the mpc5200. A mpc5200b device +tree should use the "fsl,mpc5200b-","fsl,mpc5200-" form. + +Required soc5200 child nodes: +name compatible Description +---- ---------- ----------- +cdm@ fsl,mpc5200-cdm Clock Distribution +interrupt-controller@ fsl,mpc5200-pic need an interrupt + controller to boot +bestcomm@ fsl,mpc5200-bestcomm Bestcomm DMA controller + +Recommended soc5200 child nodes; populate as needed for your board +name compatible Description +---- ---------- ----------- +timer@ fsl,mpc5200-gpt General purpose timers +gpio@ fsl,mpc5200-gpio MPC5200 simple gpio controller +gpio@ fsl,mpc5200-gpio-wkup MPC5200 wakeup gpio controller +rtc@ fsl,mpc5200-rtc Real time clock +mscan@ fsl,mpc5200-mscan CAN bus controller +pci@ fsl,mpc5200-pci PCI bridge +serial@ fsl,mpc5200-psc-uart PSC in serial mode +i2s@ fsl,mpc5200-psc-i2s PSC in i2s mode +ac97@ fsl,mpc5200-psc-ac97 PSC in ac97 mode +spi@ fsl,mpc5200-psc-spi PSC in spi mode +irda@ fsl,mpc5200-psc-irda PSC in IrDA mode +spi@ fsl,mpc5200-spi MPC5200 spi device +ethernet@ fsl,mpc5200-fec MPC5200 ethernet device +ata@ fsl,mpc5200-ata IDE ATA interface +i2c@ fsl,mpc5200-i2c I2C controller +usb@ fsl,mpc5200-ohci,ohci-be USB controller +xlb@ fsl,mpc5200-xlb XLB arbitrator + +fsl,mpc5200-gpt nodes +--------------------- +On the mpc5200 and 5200b, GPT0 has a watchdog timer function. If the board +design supports the internal wdt, then the device node for GPT0 should +include the empty property 'fsl,has-wdt'. Note that this does not activate +the watchdog. The timer will function as a GPT if the timer api is used, and +it will function as watchdog if the watchdog device is used. The watchdog +mode has priority over the gpt mode, i.e. if the watchdog is activated, any +gpt api call to this timer will fail with -EBUSY. + +If you add the property + fsl,wdt-on-boot = ; +GPT0 will be marked as in-use watchdog, i.e. blocking every gpt access to it. +If n>0, the watchdog is started with a timeout of n seconds. If n=0, the +configuration of the watchdog is not touched. This is useful in two cases: +- just mark GPT0 as watchdog, blocking gpt accesses, and configure it later; +- do not touch a configuration assigned by the boot loader which supervises + the boot process itself. + +The watchdog will respect the CONFIG_WATCHDOG_NOWAYOUT option. + +An mpc5200-gpt can be used as a single line GPIO controller. To do so, +add the following properties to the gpt node: + gpio-controller; + #gpio-cells = <2>; +When referencing the GPIO line from another node, the first cell must always +be zero and the second cell represents the gpio flags and described in the +gpio device tree binding. + +An mpc5200-gpt can be used as a single line edge sensitive interrupt +controller. To do so, add the following properties to the gpt node: + interrupt-controller; + #interrupt-cells = <1>; +When referencing the IRQ line from another node, the cell represents the +sense mode; 1 for edge rising, 2 for edge falling. + +fsl,mpc5200-psc nodes +--------------------- +The PSCs should include a cell-index which is the index of the PSC in +hardware. cell-index is used to determine which shared SoC registers to +use when setting up PSC clocking. cell-index number starts at '0'. ie: + PSC1 has 'cell-index = <0>' + PSC4 has 'cell-index = <3>' + +PSC in i2s mode: The mpc5200 and mpc5200b PSCs are not compatible when in +i2s mode. An 'mpc5200b-psc-i2s' node cannot include 'mpc5200-psc-i2s' in the +compatible field. + + +fsl,mpc5200-gpio and fsl,mpc5200-gpio-wkup nodes +------------------------------------------------ +Each GPIO controller node should have the empty property gpio-controller and +#gpio-cells set to 2. First cell is the GPIO number which is interpreted +according to the bit numbers in the GPIO control registers. The second cell +is for flags which is currently unused. + +fsl,mpc5200-fec nodes +--------------------- +The FEC node can specify one of the following properties to configure +the MII link: +- fsl,7-wire-mode - An empty property that specifies the link uses 7-wire + mode instead of MII +- current-speed - Specifies that the MII should be configured for a fixed + speed. This property should contain two cells. The + first cell specifies the speed in Mbps and the second + should be '0' for half duplex and '1' for full duplex +- phy-handle - Contains a phandle to an Ethernet PHY. + +Interrupt controller (fsl,mpc5200-pic) node +------------------------------------------- +The mpc5200 pic binding splits hardware IRQ numbers into two levels. The +split reflects the layout of the PIC hardware itself, which groups +interrupts into one of three groups; CRIT, MAIN or PERP. Also, the +Bestcomm dma engine has it's own set of interrupt sources which are +cascaded off of peripheral interrupt 0, which the driver interprets as a +fourth group, SDMA. + +The interrupts property for device nodes using the mpc5200 pic consists +of three cells; + + L1 := [CRIT=0, MAIN=1, PERP=2, SDMA=3] + L2 := interrupt number; directly mapped from the value in the + "ICTL PerStat, MainStat, CritStat Encoded Register" + level := [LEVEL_HIGH=0, EDGE_RISING=1, EDGE_FALLING=2, LEVEL_LOW=3] + +For external IRQs, use the following interrupt property values (how to +specify external interrupts is a frequently asked question): +External interrupts: + external irq0: interrupts = <0 0 n>; + external irq1: interrupts = <1 1 n>; + external irq2: interrupts = <1 2 n>; + external irq3: interrupts = <1 3 n>; +'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low) + +fsl,mpc5200-mscan nodes +----------------------- +See file Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpic-msgr.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpic-msgr.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc8ded641ab63d9b404a0e256ecf6b3ee63f5137 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpic-msgr.txt @@ -0,0 +1,63 @@ +* FSL MPIC Message Registers + +This binding specifies what properties must be available in the device tree +representation of the message register blocks found in some FSL MPIC +implementations. + +Required properties: + + - compatible: Specifies the compatibility list for the message register + block. The type shall be and the value shall be of the form + "fsl,mpic-v-msgr", where is the version number of + the MPIC containing the message registers. + + - reg: Specifies the base physical address(s) and size(s) of the + message register block's addressable register space. The type shall be + . + + - interrupts: Specifies a list of interrupt-specifiers which are available + for receiving interrupts. Interrupt-specifier consists of two cells: first + cell is interrupt-number and second cell is level-sense. The type shall be + . + +Optional properties: + + - mpic-msgr-receive-mask: Specifies what registers in the containing block + are allowed to receive interrupts. The value is a bit mask where a set + bit at bit 'n' indicates that message register 'n' can receive interrupts. + Note that "bit 'n'" is numbered from LSB for PPC hardware. The type shall + be . If not present, then all of the message registers in the block + are available. + +Aliases: + + An alias should be created for every message register block. They are not + required, though. However, a particular implementation of this binding + may require aliases to be present. Aliases are of the form + 'mpic-msgr-block', where is an integer specifying the block's number. + Numbers shall start at 0. + +Example: + + aliases { + mpic-msgr-block0 = &mpic_msgr_block0; + mpic-msgr-block1 = &mpic_msgr_block1; + }; + + mpic_msgr_block0: mpic-msgr-block@41400 { + compatible = "fsl,mpic-v3.1-msgr"; + reg = <0x41400 0x200>; + // Message registers 0 and 2 in this block can receive interrupts on + // sources 0xb0 and 0xb2, respectively. + interrupts = <0xb0 2 0xb2 2>; + mpic-msgr-receive-mask = <0x5>; + }; + + mpic_msgr_block1: mpic-msgr-block@42400 { + compatible = "fsl,mpic-v3.1-msgr"; + reg = <0x42400 0x200>; + // Message registers 0 and 2 in this block can receive interrupts on + // sources 0xb4 and 0xb6, respectively. + interrupts = <0xb4 2 0xb6 2>; + mpic-msgr-receive-mask = <0x5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpic-timer.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpic-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..df41958140e8a975d798ead9ef0b370d2d967a3f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/mpic-timer.txt @@ -0,0 +1,38 @@ +* Freescale MPIC timers + +Required properties: +- compatible: "fsl,mpic-global-timer" + +- reg : Contains two regions. The first is the main timer register bank + (GTCCRxx, GTBCRxx, GTVPRxx, GTDRxx). The second is the timer control + register (TCRx) for the group. + +- fsl,available-ranges: use style section to define which + timer interrupts can be used. This property is optional; without this, + all timers within the group can be used. + +- interrupts: one interrupt per timer in the group, in order, starting + with timer zero. If timer-available-ranges is present, only the + interrupts that correspond to available timers shall be present. + +Example: + /* Note that this requires #interrupt-cells to be 4 */ + timer0: timer@41100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x41100 0x100 0x41300 4>; + + /* Another AMP partition is using timers 0 and 1 */ + fsl,available-ranges = <2 2>; + + interrupts = <2 0 3 0 + 3 0 3 0>; + }; + + timer1: timer@42100 { + compatible = "fsl,mpic-global-timer"; + reg = <0x42100 0x100 0x42300 4>; + interrupts = <4 0 3 0 + 5 0 3 0 + 6 0 3 0 + 7 0 3 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/msi-pic.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/msi-pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..f8d2b7fe06d695971d48ba21ab67e5b72a212fe9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/msi-pic.txt @@ -0,0 +1,111 @@ +* Freescale MSI interrupt controller + +Required properties: +- compatible : compatible list, may contain one or two entries + The first is "fsl,CHIP-msi", where CHIP is the processor(mpc8610, mpc8572, + etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" or + "fsl,mpic-msi-v4.3" depending on the parent type and version. If mpic + version is 4.3, the number of MSI registers is increased to 16, MSIIR1 is + provided to access these 16 registers, and compatible "fsl,mpic-msi-v4.3" + should be used. The first entry is optional; the second entry is + required. + +- reg : It may contain one or two regions. The first region should contain + the address and the length of the shared message interrupt register set. + The second region should contain the address of aliased MSIIR or MSIIR1 + register for platforms that have such an alias, if using MSIIR1, the second + region must be added because different MSI group has different MSIIR1 offset. + +- interrupts : each one of the interrupts here is one entry per 32 MSIs, + and routed to the host interrupt controller. the interrupts should + be set as edge sensitive. If msi-available-ranges is present, only + the interrupts that correspond to available ranges shall be present. + +Optional properties: +- msi-available-ranges: use style section to define which + msi interrupt can be used in the 256 msi interrupts. This property is + optional, without this, all the MSI interrupts can be used. + Each available range must begin and end on a multiple of 32 (i.e. + no splitting an individual MSI register or the associated PIC interrupt). + MPIC v4.3 does not support this property because the 32 interrupts of an + individual register are not continuous when using MSIIR1. + +- msi-address-64: 64-bit PCI address of the MSIIR register. The MSIIR register + is used for MSI messaging. The address of MSIIR in PCI address space is + the MSI message address. + + This property may be used in virtualized environments where the hypervisor + has created an alternate mapping for the MSIR block. See below for an + explanation. + + +Example: + msi@41600 { + compatible = "fsl,mpc8610-msi", "fsl,mpic-msi"; + reg = <0x41600 0x80>; + msi-available-ranges = <0 0x100>; + interrupts = < + 0xe0 0 + 0xe1 0 + 0xe2 0 + 0xe3 0 + 0xe4 0 + 0xe5 0 + 0xe6 0 + 0xe7 0>; + interrupt-parent = <&mpic>; + }; + + msi@41600 { + compatible = "fsl,mpic-msi-v4.3"; + reg = <0x41600 0x200 0x44148 4>; + interrupts = < + 0xe0 0 0 0 + 0xe1 0 0 0 + 0xe2 0 0 0 + 0xe3 0 0 0 + 0xe4 0 0 0 + 0xe5 0 0 0 + 0xe6 0 0 0 + 0xe7 0 0 0 + 0x100 0 0 0 + 0x101 0 0 0 + 0x102 0 0 0 + 0x103 0 0 0 + 0x104 0 0 0 + 0x105 0 0 0 + 0x106 0 0 0 + 0x107 0 0 0>; + }; + +The Freescale hypervisor and msi-address-64 +------------------------------------------- +Normally, PCI devices have access to all of CCSR via an ATMU mapping. The +Freescale MSI driver calculates the address of MSIIR (in the MSI register +block) and sets that address as the MSI message address. + +In a virtualized environment, the hypervisor may need to create an IOMMU +mapping for MSIIR. The Freescale ePAPR hypervisor has this requirement +because of hardware limitations of the Peripheral Access Management Unit +(PAMU), which is currently the only IOMMU that the hypervisor supports. +The ATMU is programmed with the guest physical address, and the PAMU +intercepts transactions and reroutes them to the true physical address. + +In the PAMU, each PCI controller is given only one primary window. The +PAMU restricts DMA operations so that they can only occur within a window. +Because PCI devices must be able to DMA to memory, the primary window must +be used to cover all of the guest's memory space. + +PAMU primary windows can be divided into 256 subwindows, and each +subwindow can have its own address mapping ("guest physical" to "true +physical"). However, each subwindow has to have the same alignment, which +means they cannot be located at just any address. Because of these +restrictions, it is usually impossible to create a 4KB subwindow that +covers MSIIR where it's normally located. + +Therefore, the hypervisor has to create a subwindow inside the same +primary window used for memory, but mapped to the MSIR block (where MSIIR +lives). The first subwindow after the end of guest memory is used for +this. The address specified in the msi-address-64 property is the PCI +address of MSIIR. The hypervisor configures the PAMU to map that address to +the true physical address of MSIIR. diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/pamu.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/pamu.txt new file mode 100644 index 0000000000000000000000000000000000000000..b21ab85de6e7821c85f1a8ca64fcbe9f5386d638 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/pamu.txt @@ -0,0 +1,148 @@ +Freescale Peripheral Management Access Unit (PAMU) Device Tree Binding + +DESCRIPTION + +The PAMU is an I/O MMU that provides device-to-memory access control and +address translation capabilities. + +Required properties: + +- compatible : + First entry is a version-specific string, such as + "fsl,pamu-v1.0". The second is "fsl,pamu". +- ranges : + A standard property. Utilized to describe the memory mapped + I/O space utilized by the controller. The size should + be set to the total size of the register space of all + physically present PAMU controllers. For example, for + PAMU v1.0, on an SOC that has five PAMU devices, the size + is 0x5000. +- interrupts : + Interrupt mappings. The first tuple is the normal PAMU + interrupt, used for reporting access violations. The second + is for PAMU hardware errors, such as PAMU operation errors + and ECC errors. +- #address-cells: + A standard property. +- #size-cells : + A standard property. + +Optional properties: +- reg : + A standard property. It represents the CCSR registers of + all child PAMUs combined. Include it to provide support + for legacy drivers. +- fsl,portid-mapping : + The Coherency Subdomain ID Port Mapping Registers and + Snoop ID Port Mapping registers, which are part of the + CoreNet Coherency fabric (CCF), provide a CoreNet + Coherency Subdomain ID/CoreNet Snoop ID to pamu mapping + functions. Certain bits from these registers should be + set if PAMUs should be snooped. This property defines + a bitmask which selects the bits that should be set if + PAMUs should be snooped. + +Child nodes: + +Each child node represents one PAMU controller. Each SOC device that is +connected to a specific PAMU device should have a "fsl,pamu-phandle" property +that links to the corresponding specific child PAMU controller. + +- reg : + A standard property. Specifies the physical address and + length (relative to the parent 'ranges' property) of this + PAMU controller's configuration registers. The size should + be set to the size of this PAMU controllers's register space. + For PAMU v1.0, this size is 0x1000. +- fsl,primary-cache-geometry + : + Two cells that specify the geometry of the primary PAMU + cache. The first is the number of cache lines, and the + second is the number of "ways". For direct-mapped caches, + specify a value of 1. +- fsl,secondary-cache-geometry + : + Two cells that specify the geometry of the secondary PAMU + cache. The first is the number of cache lines, and the + second is the number of "ways". For direct-mapped caches, + specify a value of 1. + +Device nodes: + +Devices that have LIODNs need to specify links to the parent PAMU controller +(the actual PAMU controller that this device is connected to) and a pointer to +the LIODN register, if applicable. + +- fsl,iommu-parent + : + Phandle to the single, specific PAMU controller node to which + this device is connect. The PAMU topology is represented in + the device tree to assist code that dynamically determines the + best LIODN values to minimize PAMU cache thrashing. + +- fsl,liodn-reg : + Two cells that specify the location of the LIODN register + for this device. Required for devices that have a single + LIODN. The first cell is a phandle to a node that contains + the registers where the LIODN is to be set. The second is + the offset from the first "reg" resource of the node where + the specific LIODN register is located. + + +Example: + + iommu@20000 { + compatible = "fsl,pamu-v1.0", "fsl,pamu"; + reg = <0x20000 0x5000>; + ranges = <0 0x20000 0x5000>; + fsl,portid-mapping = <0xf80000>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = < + 24 2 0 0 + 16 2 1 30>; + + pamu0: pamu@0 { + reg = <0 0x1000>; + fsl,primary-cache-geometry = <32 1>; + fsl,secondary-cache-geometry = <128 2>; + }; + + pamu1: pamu@1000 { + reg = <0x1000 0x1000>; + fsl,primary-cache-geometry = <32 1>; + fsl,secondary-cache-geometry = <128 2>; + }; + + pamu2: pamu@2000 { + reg = <0x2000 0x1000>; + fsl,primary-cache-geometry = <32 1>; + fsl,secondary-cache-geometry = <128 2>; + }; + + pamu3: pamu@3000 { + reg = <0x3000 0x1000>; + fsl,primary-cache-geometry = <32 1>; + fsl,secondary-cache-geometry = <128 2>; + }; + + pamu4: pamu@4000 { + reg = <0x4000 0x1000>; + fsl,primary-cache-geometry = <32 1>; + fsl,secondary-cache-geometry = <128 2>; + }; + }; + + guts: global-utilities@e0000 { + compatible = "fsl,qoriq-device-config-1.0"; + reg = <0xe0000 0xe00>; + fsl,has-rstcr; + #sleep-cells = <1>; + fsl,liodn-bits = <12>; + }; + +/include/ "qoriq-dma-0.dtsi" + dma@100300 { + fsl,iommu-parent = <&pamu0>; + fsl,liodn-reg = <&guts 0x584>; /* DMA2LIODNR */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/pmc.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/pmc.txt new file mode 100644 index 0000000000000000000000000000000000000000..07256b7ffcaab2ba57b33cf279df45d830ce33b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/pmc.txt @@ -0,0 +1,63 @@ +* Power Management Controller + +Properties: +- compatible: "fsl,-pmc". + + "fsl,mpc8349-pmc" should be listed for any chip whose PMC is + compatible. "fsl,mpc8313-pmc" should also be listed for any chip + whose PMC is compatible, and implies deep-sleep capability. + + "fsl,mpc8548-pmc" should be listed for any chip whose PMC is + compatible. "fsl,mpc8536-pmc" should also be listed for any chip + whose PMC is compatible, and implies deep-sleep capability. + + "fsl,mpc8641d-pmc" should be listed for any chip whose PMC is + compatible; all statements below that apply to "fsl,mpc8548-pmc" also + apply to "fsl,mpc8641d-pmc". + + Compatibility does not include bit assignments in SCCR/PMCDR/DEVDISR; these + bit assignments are indicated via the sleep specifier in each device's + sleep property. + +- reg: For devices compatible with "fsl,mpc8349-pmc", the first resource + is the PMC block, and the second resource is the Clock Configuration + block. + + For devices compatible with "fsl,mpc8548-pmc", the first resource + is a 32-byte block beginning with DEVDISR. + +- interrupts: For "fsl,mpc8349-pmc"-compatible devices, the first + resource is the PMC block interrupt. + +- fsl,mpc8313-wakeup-timer: For "fsl,mpc8313-pmc"-compatible devices, + this is a phandle to an "fsl,gtm" node on which timer 4 can be used as + a wakeup source from deep sleep. + +Sleep specifiers: + + fsl,mpc8349-pmc: Sleep specifiers consist of one cell. For each bit + that is set in the cell, the corresponding bit in SCCR will be saved + and cleared on suspend, and restored on resume. This sleep controller + supports disabling and resuming devices at any time. + + fsl,mpc8536-pmc: Sleep specifiers consist of three cells, the third of + which will be ORed into PMCDR upon suspend, and cleared from PMCDR + upon resume. The first two cells are as described for fsl,mpc8578-pmc. + This sleep controller only supports disabling devices during system + sleep, or permanently. + + fsl,mpc8548-pmc: Sleep specifiers consist of one or two cells, the + first of which will be ORed into DEVDISR (and the second into + DEVDISR2, if present -- this cell should be zero or absent if the + hardware does not have DEVDISR2) upon a request for permanent device + disabling. This sleep controller does not support configuring devices + to disable during system sleep (unless supported by another compatible + match), or dynamically. + +Example: + + power@b00 { + compatible = "fsl,mpc8313-pmc", "fsl,mpc8349-pmc"; + reg = <0xb00 0x100 0xa00 0x100>; + interrupts = <80 8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/raideng.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/raideng.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ad29b9ac2acf93bb212e4b1d80650ccc0964eb1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/raideng.txt @@ -0,0 +1,81 @@ +* Freescale 85xx RAID Engine nodes + +RAID Engine nodes are defined to describe on-chip RAID accelerators. Each RAID +Engine should have a separate node. + +Supported chips: +P5020, P5040 + +Required properties: + +- compatible: Should contain "fsl,raideng-v1.0" as the value + This identifies RAID Engine block. 1 in 1.0 represents + major number whereas 0 represents minor number. The + version matches the hardware IP version. +- reg: offset and length of the register set for the device +- ranges: standard ranges property specifying the translation + between child address space and parent address space + +Example: + /* P5020 */ + raideng: raideng@320000 { + compatible = "fsl,raideng-v1.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x320000 0x10000>; + ranges = <0 0x320000 0x10000>; + }; + + +There must be a sub-node for each job queue present in RAID Engine +This node must be a sub-node of the main RAID Engine node + +- compatible: Should contain "fsl,raideng-v1.0-job-queue" as the value + This identifies the job queue interface +- reg: offset and length of the register set for job queue +- ranges: standard ranges property specifying the translation + between child address space and parent address space + +Example: + /* P5020 */ + raideng_jq0@1000 { + compatible = "fsl,raideng-v1.0-job-queue"; + reg = <0x1000 0x1000>; + ranges = <0x0 0x1000 0x1000>; + }; + + +There must be a sub-node for each job ring present in RAID Engine +This node must be a sub-node of job queue node + +- compatible: Must contain "fsl,raideng-v1.0-job-ring" as the value + This identifies job ring. Should contain either + "fsl,raideng-v1.0-hp-ring" or "fsl,raideng-v1.0-lp-ring" + depending upon whether ring has high or low priority +- reg: offset and length of the register set for job ring +- interrupts: interrupt mapping for job ring IRQ + +Optional property: + +- fsl,liodn: Specifies the LIODN to be used for Job Ring. This + property is normally set by firmware. Value + is of 12-bits which is the LIODN number for this JR. + This property is used by the IOMMU (PAMU) to distinquish + transactions from this JR and than be able to do address + translation & protection accordingly. + +Example: + /* P5020 */ + raideng_jq0@1000 { + compatible = "fsl,raideng-v1.0-job-queue"; + reg = <0x1000 0x1000>; + ranges = <0x0 0x1000 0x1000>; + + raideng_jr0: jr@0 { + compatible = "fsl,raideng-v1.0-job-ring", "fsl,raideng-v1.0-hp-ring"; + reg = <0x0 0x400>; + interrupts = <139 2 0 0>; + interrupt-parent = <&mpic>; + fsl,liodn = <0x41>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/scfg.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/scfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..0532c46b3372a632b008b79abd0a2b677dbb608b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/scfg.txt @@ -0,0 +1,18 @@ +Freescale Supplement configuration unit (SCFG) + +SCFG is the supplemental configuration unit, that provides SoC specific +configuration and status registers for the chip. Such as getting PEX port +status. + +Required properties: + +- compatible: should be "fsl,-scfg" +- reg: should contain base address and length of SCFG memory-mapped +registers + +Example: + + scfg: global-utilities@fc000 { + compatible = "fsl,t1040-scfg"; + reg = <0xfc000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/srio-rmu.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/srio-rmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..0496ada4bba49a1046cfbfe5f0d4a3178f90341e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/srio-rmu.txt @@ -0,0 +1,163 @@ +Message unit node: + +For SRIO controllers that implement the message unit as part of the controller +this node is required. For devices with RMAN this node should NOT exist. The +node is composed of three types of sub-nodes ("fsl-srio-msg-unit", +"fsl-srio-dbell-unit" and "fsl-srio-port-write-unit"). + +See srio.txt for more details about generic SRIO controller details. + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,srio-rmu-vX.Y", "fsl,srio-rmu". + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - fsl,liodn + Usage: optional-but-recommended (for devices with PAMU) + Value type: + Definition: The logical I/O device number for the PAMU (IOMMU) to be + correctly configured for SRIO accesses. The property should + not exist on devices that do not support PAMU. + + The LIODN value is associated with all RMU transactions + (msg-unit, doorbell, port-write). + +Sub-Nodes for RMU: The RMU node is composed of multiple sub-nodes that +correspond to the actual sub-controllers in the RMU. The manual for a given +SoC will detail which and how many of these sub-controllers are implemented. + +Message Unit: + + - compatible + Usage: required + Value type: + Definition: Must include "fsl,srio-msg-unit-vX.Y", "fsl,srio-msg-unit". + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A pair of IRQs are specified in this property. The first + element is associated with the transmit (TX) interrupt and the + second element is associated with the receive (RX) interrupt. + +Doorbell Unit: + + - compatible + Usage: required + Value type: + Definition: Must include: + "fsl,srio-dbell-unit-vX.Y", "fsl,srio-dbell-unit" + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A pair of IRQs are specified in this property. The first + element is associated with the transmit (TX) interrupt and the + second element is associated with the receive (RX) interrupt. + +Port-Write Unit: + + - compatible + Usage: required + Value type: + Definition: Must include: + "fsl,srio-port-write-unit-vX.Y", "fsl,srio-port-write-unit" + + The version X.Y should match the general SRIO controller's IP Block + revision register's Major(X) and Minor (Y) value. + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers for message units + and doorbell units. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A single IRQ that handles port-write conditions is + specified by this property. (Typically shared with error). + + Note: All other standard properties (see the Devicetree Specification) + are allowed but are optional. + +Example: + rmu: rmu@d3000 { + compatible = "fsl,srio-rmu"; + reg = <0xd3000 0x400>; + ranges = <0x0 0xd3000 0x400>; + fsl,liodn = <0xc8>; + + message-unit@0 { + compatible = "fsl,srio-msg-unit"; + reg = <0x0 0x100>; + interrupts = < + 60 2 0 0 /* msg1_tx_irq */ + 61 2 0 0>;/* msg1_rx_irq */ + }; + message-unit@100 { + compatible = "fsl,srio-msg-unit"; + reg = <0x100 0x100>; + interrupts = < + 62 2 0 0 /* msg2_tx_irq */ + 63 2 0 0>;/* msg2_rx_irq */ + }; + doorbell-unit@400 { + compatible = "fsl,srio-dbell-unit"; + reg = <0x400 0x80>; + interrupts = < + 56 2 0 0 /* bell_outb_irq */ + 57 2 0 0>;/* bell_inb_irq */ + }; + port-write-unit@4e0 { + compatible = "fsl,srio-port-write-unit"; + reg = <0x4e0 0x20>; + interrupts = <16 2 1 11>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/srio.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/srio.txt new file mode 100644 index 0000000000000000000000000000000000000000..86ee6ea737542ba616d6d07aac6d94021d8283ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/fsl/srio.txt @@ -0,0 +1,104 @@ +* Freescale Serial RapidIO (SRIO) Controller + +RapidIO port node: +Properties: + - compatible + Usage: required + Value type: + Definition: Must include "fsl,srio" for IP blocks with IP Block + Revision Register (SRIO IPBRR1) Major ID equal to 0x01c0. + + Optionally, a compatible string of "fsl,srio-vX.Y" where X is Major + version in IP Block Revision Register and Y is Minor version. If this + compatible is provided it should be ordered before "fsl,srio". + + - reg + Usage: required + Value type: + Definition: A standard property. Specifies the physical address and + length of the SRIO configuration registers. The size should + be set to 0x11000. + + - interrupts + Usage: required + Value type: + Definition: Specifies the interrupts generated by this device. The + value of the interrupts property consists of one interrupt + specifier. The format of the specifier is defined by the + binding document describing the node's interrupt parent. + + A single IRQ that handles error conditions is specified by this + property. (Typically shared with port-write). + + - fsl,srio-rmu-handle: + Usage: required if rmu node is defined + Value type: + Definition: A single value that points to the RMU. + (See srio-rmu.txt for more details on RMU node binding) + +Port Child Nodes: There should a port child node for each port that exists in +the controller. The ports are numbered starting at one (1) and should have +the following properties: + + - cell-index + Usage: required + Value type: + Definition: A standard property. Matches the port id. + + - ranges + Usage: required if local access windows preset + Value type: + Definition: A standard property. Utilized to describe the memory mapped + IO space utilized by the controller. This corresponds to the + setting of the local access windows that are targeted to this + SRIO port. + + - fsl,liodn + Usage: optional-but-recommended (for devices with PAMU) + Value type: + Definition: The logical I/O device number for the PAMU (IOMMU) to be + correctly configured for SRIO accesses. The property should + not exist on devices that do not support PAMU. + + For HW (ie, the P4080) that only supports a LIODN for both + memory and maintenance transactions then a single LIODN is + represented in the property for both transactions. + + For HW (ie, the P304x/P5020, etc) that supports an LIODN for + memory transactions and a unique LIODN for maintenance + transactions then a pair of LIODNs are represented in the + property. Within the pair, the first element represents the + LIODN associated with memory transactions and the second element + represents the LIODN associated with maintenance transactions + for the port. + +Note: All other standard properties (see the Devicetree Specification) +are allowed but are optional. + +Example: + + rapidio: rapidio@ffe0c0000 { + #address-cells = <2>; + #size-cells = <2>; + reg = <0xf 0xfe0c0000 0 0x11000>; + compatible = "fsl,srio"; + interrupts = <16 2 1 11>; /* err_irq */ + fsl,srio-rmu-handle = <&rmu>; + ranges; + + port1 { + cell-index = <1>; + #address-cells = <2>; + #size-cells = <2>; + fsl,liodn = <34>; + ranges = <0 0 0xc 0x20000000 0 0x10000000>; + }; + + port2 { + cell-index = <2>; + #address-cells = <2>; + #size-cells = <2>; + fsl,liodn = <48>; + ranges = <0 0 0xc 0x30000000 0 0x10000000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/ibm,powerpc-cpu-features.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/ibm,powerpc-cpu-features.txt new file mode 100644 index 0000000000000000000000000000000000000000..5af426e13334def9d1e7738e264953cae46fcb46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/ibm,powerpc-cpu-features.txt @@ -0,0 +1,248 @@ +*** NOTE *** +This document is copied from OPAL firmware +(skiboot/doc/device-tree/ibm,powerpc-cpu-features/binding.txt) + +There is more complete overview and documentation of features in that +source tree. All patches and modifications should go there. +************ + +ibm,powerpc-cpu-features binding +================================ + +This device tree binding describes CPU features available to software, with +enablement, privilege, and compatibility metadata. + +More general description of design and implementation of this binding is +found in design.txt, which also points to documentation of specific features. + + +/cpus/ibm,powerpc-cpu-features node binding +------------------------------------------- + +Node: ibm,powerpc-cpu-features + +Description: Container of CPU feature nodes. + +The node name must be "ibm,powerpc-cpu-features". + +It is implemented as a child of the node "/cpus", but this must not be +assumed by parsers. + +The node is optional but should be provided by new OPAL firmware. + +Properties: + +- compatible + Usage: required + Value type: string + Definition: "ibm,powerpc-cpu-features" + + This compatibility refers to backwards compatibility of the overall + design with parsers that behave according to these guidelines. This can + be extended in a backward compatible manner which would not warrant a + revision of the compatible property. + +- isa + Usage: required + Value type: + Definition: + + isa that the CPU is currently running in. This provides instruction set + compatibility, less the individual feature nodes. For example, an ISA v3.0 + implementation that lacks the "transactional-memory" cpufeature node + should not use transactional memory facilities. + + Value corresponds to the "Power ISA Version" multiplied by 1000. + For example, <3000> corresponds to Version 3.0, <2070> to Version 2.07. + The minor digit is available for revisions. + +- display-name + Usage: optional + Value type: string + Definition: + + A human readable name for the CPU. + +/cpus/ibm,powerpc-cpu-features/example-feature node bindings +---------------------------------------------------------------- + +Each child node of cpu-features represents a CPU feature / capability. + +Node: A string describing an architected CPU feature, e.g., "floating-point". + +Description: A feature or capability supported by the CPUs. + +The name of the node is a human readable string that forms the interface +used to describe features to software. Features are currently documented +in the code where they are implemented in skiboot/core/cpufeatures.c + +Presence of the node indicates the feature is available. + +Properties: + +- isa + Usage: required + Value type: + Definition: + + First level of the Power ISA that the feature appears in. + Software should filter out features when constraining the + environment to a particular ISA version. + + Value is defined similarly to /cpus/features/isa + +- usable-privilege + Usage: required + Value type: bit mask + Definition: + Bit numbers are LSB0 + bit 0 - PR (problem state / user mode) + bit 1 - OS (privileged state) + bit 2 - HV (hypervisor state) + All other bits reserved and should be zero. + + This property describes the privilege levels and/or software components + that can use the feature. + + If bit 0 is set, then the hwcap-bit-nr property will exist. + + +- hv-support + Usage: optional + Value type: bit mask + Definition: + Bit numbers are LSB0 + bit 0 - HFSCR + All other bits reserved and should be zero. + + This property describes the HV privilege support required to enable the + feature to lesser privilege levels. If the property does not exist then no + support is required. + + If no bits are set, the hypervisor must have explicit/custom support for + this feature. + + If the HFSCR bit is set, then the hfscr-bit-nr property will exist and + the feature may be enabled by setting this bit in the HFSCR register. + + +- os-support + Usage: optional + Value type: bit mask + Definition: + Bit numbers are LSB0 + bit 0 - FSCR + All other bits reserved and should be zero. + + This property describes the OS privilege support required to enable the + feature to lesser privilege levels. If the property does not exist then no + support is required. + + If no bits are set, the operating system must have explicit/custom support + for this feature. + + If the FSCR bit is set, then the fscr-bit-nr property will exist and + the feature may be enabled by setting this bit in the FSCR register. + + +- hfscr-bit-nr + Usage: optional + Value type: + Definition: HFSCR bit position (LSB0) + + This property exists when the hv-support property HFSCR bit is set. This + property describes the bit number in the HFSCR register that the + hypervisor must set in order to enable this feature. + + This property also exists if an HFSCR bit corresponds with this feature. + This makes CPU feature parsing slightly simpler. + + +- fscr-bit-nr + Usage: optional + Value type: + Definition: FSCR bit position (LSB0) + + This property exists when the os-support property FSCR bit is set. This + property describes the bit number in the FSCR register that the + operating system must set in order to enable this feature. + + This property also exists if an FSCR bit corresponds with this feature. + This makes CPU feature parsing slightly simpler. + + +- hwcap-bit-nr + Usage: optional + Value type: + Definition: Linux ELF AUX vector bit position (LSB0) + + This property may exist when the usable-privilege property value has PR bit set. + This property describes the bit number that should be set in the ELF AUX + hardware capability vectors in order to advertise this feature to userspace. + Bits 0-31 correspond to bits 0-31 in AT_HWCAP vector. Bits 32-63 correspond + to 0-31 in AT_HWCAP2 vector, and so on. Missing AT_HWCAPx vectors implies + that the feature is not enabled or can not be advertised. Operating systems + may provide a number of unassigned hardware capability bits to allow for new + features to be advertised. + + Some properties representing features created before this binding are + advertised to userspace without a one-to-one hwcap bit number may not specify + this bit. Operating system will handle those bits specifically. All new + features usable by userspace will have a hwcap-bit-nr property. + + +- dependencies + Usage: optional + Value type: + Definition: + + If this property exists then it is a list of phandles to cpu feature + nodes that must be enabled for this feature to be enabled. + + +Example +------- + + /cpus/ibm,powerpc-cpu-features { + compatible = "ibm,powerpc-cpu-features"; + + isa = <3020>; + + darn { + isa = <3000>; + usable-privilege = <1 | 2 | 4>; + hwcap-bit-nr = ; + }; + + scv { + isa = <3000>; + usable-privilege = <1 | 2>; + os-support = <0>; + hwcap-bit-nr = ; + }; + + stop { + isa = <3000>; + usable-privilege = <2 | 4>; + hv-support = <0>; + os-support = <0>; + }; + + vsx2 (hypothetical) { + isa = <3010>; + usable-privilege = <1 | 2 | 4>; + hv-support = <0>; + os-support = <0>; + hwcap-bit-nr = ; + }; + + vsx2-newinsns { + isa = <3020>; + usable-privilege = <1 | 2 | 4>; + os-support = <1>; + fscr-bit-nr = ; + hwcap-bit-nr = ; + dependencies = <&vsx2>; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/ibm,vas.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/ibm,vas.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf11d2faf7b8c8029bffe0f6a512a6544c00732f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/ibm,vas.txt @@ -0,0 +1,22 @@ +* IBM Powerpc Virtual Accelerator Switchboard (VAS) + +VAS is a hardware mechanism that allows kernel subsystems and user processes +to directly submit compression and other requests to Nest accelerators (NX) +or other coprocessors functions. + +Required properties: +- compatible : should be "ibm,vas". +- ibm,vas-id : A unique identifier for each instance of VAS in the system +- reg : Should contain 4 pairs of 64-bit fields specifying the Hypervisor + window context start and length, OS/User window context start and length, + "Paste address" start and length, "Paste window id" start bit and number + of bits) + +Example: + + vas@6019100000000 { + compatible = "ibm,vas", "ibm,power9-vas"; + reg = <0x6019100000000 0x2000000 0x6019000000000 0x100000000 0x8000000000000 0x100000000 0x20 0x10>; + name = "vas"; + ibm,vas-id = <0x1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/nintendo/gamecube.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/nintendo/gamecube.txt new file mode 100644 index 0000000000000000000000000000000000000000..b558585b1aaffd7f4ddf90caaaa1cdbb01169682 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/nintendo/gamecube.txt @@ -0,0 +1,109 @@ + +Nintendo GameCube device tree +============================= + +1) The "flipper" node + + This node represents the multi-function "Flipper" chip, which packages + many of the devices found in the Nintendo GameCube. + + Required properties: + + - compatible : Should be "nintendo,flipper" + +1.a) The Video Interface (VI) node + + Represents the interface between the graphics processor and a external + video encoder. + + Required properties: + + - compatible : should be "nintendo,flipper-vi" + - reg : should contain the VI registers location and length + - interrupts : should contain the VI interrupt + +1.b) The Processor Interface (PI) node + + Represents the data and control interface between the main processor + and graphics and audio processor. + + Required properties: + + - compatible : should be "nintendo,flipper-pi" + - reg : should contain the PI registers location and length + +1.b.i) The "Flipper" interrupt controller node + + Represents the interrupt controller within the "Flipper" chip. + The node for the "Flipper" interrupt controller must be placed under + the PI node. + + Required properties: + + - compatible : should be "nintendo,flipper-pic" + +1.c) The Digital Signal Procesor (DSP) node + + Represents the digital signal processor interface, designed to offload + audio related tasks. + + Required properties: + + - compatible : should be "nintendo,flipper-dsp" + - reg : should contain the DSP registers location and length + - interrupts : should contain the DSP interrupt + +1.c.i) The Auxiliary RAM (ARAM) node + + Represents the non cpu-addressable ram designed mainly to store audio + related information. + The ARAM node must be placed under the DSP node. + + Required properties: + + - compatible : should be "nintendo,flipper-aram" + - reg : should contain the ARAM start (zero-based) and length + +1.d) The Disk Interface (DI) node + + Represents the interface used to communicate with mass storage devices. + + Required properties: + + - compatible : should be "nintendo,flipper-di" + - reg : should contain the DI registers location and length + - interrupts : should contain the DI interrupt + +1.e) The Audio Interface (AI) node + + Represents the interface to the external 16-bit stereo digital-to-analog + converter. + + Required properties: + + - compatible : should be "nintendo,flipper-ai" + - reg : should contain the AI registers location and length + - interrupts : should contain the AI interrupt + +1.f) The Serial Interface (SI) node + + Represents the interface to the four single bit serial interfaces. + The SI is a proprietary serial interface used normally to control gamepads. + It's NOT a RS232-type interface. + + Required properties: + + - compatible : should be "nintendo,flipper-si" + - reg : should contain the SI registers location and length + - interrupts : should contain the SI interrupt + +1.g) The External Interface (EXI) node + + Represents the multi-channel SPI-like interface. + + Required properties: + + - compatible : should be "nintendo,flipper-exi" + - reg : should contain the EXI registers location and length + - interrupts : should contain the EXI interrupt + diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/nintendo/wii.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/nintendo/wii.txt new file mode 100644 index 0000000000000000000000000000000000000000..c4d78f28d23c7672f4063908884abfc89f9e2687 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/nintendo/wii.txt @@ -0,0 +1,176 @@ + +Nintendo Wii device tree +======================== + +0) The root node + + This node represents the Nintendo Wii video game console. + + Required properties: + + - model : Should be "nintendo,wii" + - compatible : Should be "nintendo,wii" + +1) The "hollywood" node + + This node represents the multi-function "Hollywood" chip, which packages + many of the devices found in the Nintendo Wii. + + Required properties: + + - compatible : Should be "nintendo,hollywood" + +1.a) The Video Interface (VI) node + + Represents the interface between the graphics processor and a external + video encoder. + + Required properties: + + - compatible : should be "nintendo,hollywood-vi","nintendo,flipper-vi" + - reg : should contain the VI registers location and length + - interrupts : should contain the VI interrupt + +1.b) The Processor Interface (PI) node + + Represents the data and control interface between the main processor + and graphics and audio processor. + + Required properties: + + - compatible : should be "nintendo,hollywood-pi","nintendo,flipper-pi" + - reg : should contain the PI registers location and length + +1.b.i) The "Flipper" interrupt controller node + + Represents the "Flipper" interrupt controller within the "Hollywood" chip. + The node for the "Flipper" interrupt controller must be placed under + the PI node. + + Required properties: + + - #interrupt-cells : <1> + - compatible : should be "nintendo,flipper-pic" + - interrupt-controller + +1.c) The Digital Signal Procesor (DSP) node + + Represents the digital signal processor interface, designed to offload + audio related tasks. + + Required properties: + + - compatible : should be "nintendo,hollywood-dsp","nintendo,flipper-dsp" + - reg : should contain the DSP registers location and length + - interrupts : should contain the DSP interrupt + +1.d) The Serial Interface (SI) node + + Represents the interface to the four single bit serial interfaces. + The SI is a proprietary serial interface used normally to control gamepads. + It's NOT a RS232-type interface. + + Required properties: + + - compatible : should be "nintendo,hollywood-si","nintendo,flipper-si" + - reg : should contain the SI registers location and length + - interrupts : should contain the SI interrupt + +1.e) The Audio Interface (AI) node + + Represents the interface to the external 16-bit stereo digital-to-analog + converter. + + Required properties: + + - compatible : should be "nintendo,hollywood-ai","nintendo,flipper-ai" + - reg : should contain the AI registers location and length + - interrupts : should contain the AI interrupt + +1.f) The External Interface (EXI) node + + Represents the multi-channel SPI-like interface. + + Required properties: + + - compatible : should be "nintendo,hollywood-exi","nintendo,flipper-exi" + - reg : should contain the EXI registers location and length + - interrupts : should contain the EXI interrupt + +1.g) The Open Host Controller Interface (OHCI) nodes + + Represent the USB 1.x Open Host Controller Interfaces. + + Required properties: + + - compatible : should be "nintendo,hollywood-usb-ohci","usb-ohci" + - reg : should contain the OHCI registers location and length + - interrupts : should contain the OHCI interrupt + +1.h) The Enhanced Host Controller Interface (EHCI) node + + Represents the USB 2.0 Enhanced Host Controller Interface. + + Required properties: + + - compatible : should be "nintendo,hollywood-usb-ehci","usb-ehci" + - reg : should contain the EHCI registers location and length + - interrupts : should contain the EHCI interrupt + +1.i) The Secure Digital Host Controller Interface (SDHCI) nodes + + Represent the Secure Digital Host Controller Interfaces. + + Required properties: + + - compatible : should be "nintendo,hollywood-sdhci","sdhci" + - reg : should contain the SDHCI registers location and length + - interrupts : should contain the SDHCI interrupt + +1.j) The Inter-Processor Communication (IPC) node + + Represent the Inter-Processor Communication interface. This interface + enables communications between the Broadway and the Starlet processors. + + - compatible : should be "nintendo,hollywood-ipc" + - reg : should contain the IPC registers location and length + - interrupts : should contain the IPC interrupt + +1.k) The "Hollywood" interrupt controller node + + Represents the "Hollywood" interrupt controller within the + "Hollywood" chip. + + Required properties: + + - #interrupt-cells : <1> + - compatible : should be "nintendo,hollywood-pic" + - reg : should contain the controller registers location and length + - interrupt-controller + - interrupts : should contain the cascade interrupt of the "flipper" pic + +1.l) The General Purpose I/O (GPIO) controller node + + see Documentation/devicetree/bindings/gpio/nintendo,hollywood-gpio.txt + +1.m) The control node + + Represents the control interface used to setup several miscellaneous + settings of the "Hollywood" chip like boot memory mappings, resets, + disk interface mode, etc. + + Required properties: + + - compatible : should be "nintendo,hollywood-control" + - reg : should contain the control registers location and length + +1.n) The Disk Interface (DI) node + + Represents the interface used to communicate with mass storage devices. + + Required properties: + + - compatible : should be "nintendo,hollywood-di" + - reg : should contain the DI registers location and length + - interrupts : should contain the DI interrupt + diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/oppanel-opal.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/oppanel-opal.txt new file mode 100644 index 0000000000000000000000000000000000000000..dffb79108b61d03d80b08af55f72d2481dec299b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/oppanel-opal.txt @@ -0,0 +1,14 @@ +IBM OPAL Operator Panel Binding +------------------------------- + +Required properties: +- compatible : Should be "ibm,opal-oppanel". +- #lines : Number of lines on the operator panel e.g. <0x2>. +- #length : Number of characters per line of the operator panel e.g. <0x10>. + +Example: + oppanel { + compatible = "ibm,opal-oppanel"; + #lines = <0x2>; + #length = <0x10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/power-mgt.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/power-mgt.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d619e9555769242730893673c05c85f8e06a634 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/power-mgt.txt @@ -0,0 +1,118 @@ +IBM Power-Management Bindings +============================= + +Linux running on baremetal POWER machines has access to the processor +idle states. The description of these idle states is exposed via the +node @power-mgt in the device-tree by the firmware. + +Definitions: +---------------- +Typically each idle state has the following associated properties: + +- name: The name of the idle state as defined by the firmware. + +- flags: indicating some aspects of this idle states such as the + extent of state-loss, whether timebase is stopped on this + idle states and so on. The flag bits are as follows: + +- exit-latency: The latency involved in transitioning the state of the + CPU from idle to running. + +- target-residency: The minimum time that the CPU needs to reside in + this idle state in order to accrue power-savings + benefit. + +Properties +---------------- +The following properties provide details about the idle states. These +properties are exposed as arrays. Each entry in the property array +provides the value of that property for the idle state associated with +the array index of that entry. + +If idle-states are defined, then the properties +"ibm,cpu-idle-state-names" and "ibm,cpu-idle-state-flags" are +required. The other properties are required unless mentioned +otherwise. The length of all the property arrays must be the same. + +- ibm,cpu-idle-state-names: + Array of strings containing the names of the idle states. + +- ibm,cpu-idle-state-flags: + Array of unsigned 32-bit values containing the values of the + flags associated with the the aforementioned idle-states. The + flag bits are as follows: + 0x00000001 /* Decrementer would stop */ + 0x00000002 /* Needs timebase restore */ + 0x00001000 /* Restore GPRs like nap */ + 0x00002000 /* Restore hypervisor resource from PACA pointer */ + 0x00004000 /* Program PORE to restore PACA pointer */ + 0x00010000 /* This is a nap state (POWER7,POWER8) */ + 0x00020000 /* This is a fast-sleep state (POWER8)*/ + 0x00040000 /* This is a winkle state (POWER8) */ + 0x00080000 /* This is a fast-sleep state which requires a */ + /* software workaround for restoring the */ + /* timebase (POWER8) */ + 0x00800000 /* This state uses SPR PMICR instruction */ + /* (POWER8)*/ + 0x00100000 /* This is a fast stop state (POWER9) */ + 0x00200000 /* This is a deep-stop state (POWER9) */ + +- ibm,cpu-idle-state-latencies-ns: + Array of unsigned 32-bit values containing the values of the + exit-latencies (in ns) for the idle states in + ibm,cpu-idle-state-names. + +- ibm,cpu-idle-state-residency-ns: + Array of unsigned 32-bit values containing the values of the + target-residency (in ns) for the idle states in + ibm,cpu-idle-state-names. On POWER8 this is an optional + property. If the property is absent, the target residency for + the "Nap", "FastSleep" are defined to 10000 and 300000000 + respectively by the kernel. On POWER9 this property is required. + +- ibm,cpu-idle-state-psscr: + Array of unsigned 64-bit values containing the values for the + PSSCR for each of the idle states in ibm,cpu-idle-state-names. + This property is required on POWER9 and absent on POWER8. + +- ibm,cpu-idle-state-psscr-mask: + Array of unsigned 64-bit values containing the masks + indicating which psscr fields are set in the corresponding + entries of ibm,cpu-idle-state-psscr. This property is + required on POWER9 and absent on POWER8. + + Whenever the firmware sets an entry in + ibm,cpu-idle-state-psscr-mask value to 0xf, it implies that + only the Requested Level (RL) field of the corresponding entry + in ibm,cpu-idle-state-psscr should be considered by the + kernel. For such idle states, the kernel would set the + remaining fields of the psscr to the following sane-default + values. + + - ESL and EC bits are to 1. So wakeup from any stop + state will be at vector 0x100. + + - MTL and PSLL are set to the maximum allowed value as + per the ISA, i.e. 15. + + - The Transition Rate, TR is set to the Maximum value + 3. + + For all the other values of the entry in + ibm,cpu-idle-state-psscr-mask, the kernel expects all the + psscr fields of the corresponding entry in + ibm,cpu-idle-state-psscr to be correctly set by the firmware. + +- ibm,cpu-idle-state-pmicr: + Array of unsigned 64-bit values containing the pmicr values + for the idle states in ibm,cpu-idle-state-names. This 64-bit + register value is to be set in pmicr for the corresponding + state if the flag indicates that pmicr SPR should be set. This + is an optional property on POWER8 and is absent on + POWER9. + +- ibm,cpu-idle-state-pmicr-mask: + Array of unsigned 64-bit values containing the mask indicating + which of the fields of the PMICR are set in the corresponding + entries in ibm,cpu-idle-state-pmicr. This is an optional + property on POWER8 and is absent on POWER9. diff --git a/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/sensor-groups.txt b/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/sensor-groups.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ad881cbffdac9deca377804d2c9505245768c5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/powerpc/opal/sensor-groups.txt @@ -0,0 +1,27 @@ +IBM OPAL Sensor Groups Binding +------------------------------- + +Node: /ibm,opal/sensor-groups + +Description: Contains sensor groups available in the Powernv P9 +servers. Each child node indicates a sensor group. + +- compatible : Should be "ibm,opal-sensor-group" + +Each child node contains below properties: + +- type : String to indicate the type of sensor-group + +- sensor-group-id: Abstract unique identifier provided by firmware of + type which is used for sensor-group + operations like clearing the min/max history of all + sensors belonging to the group. + +- ibm,chip-id : Chip ID + +- sensors : Phandle array of child nodes of /ibm,opal/sensor/ + belonging to this group + +- ops : Array of opal-call numbers indicating available operations on + sensor groups like clearing min/max, enabling/disabling sensor + group. diff --git a/arch/arm64/boot/dts/vendor/bindings/pps/pps-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/pps/pps-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..3683874832ae10a03c9fe842299d315e4d305d7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pps/pps-gpio.txt @@ -0,0 +1,23 @@ +Device-Tree Bindings for a PPS Signal on GPIO + +These properties describe a PPS (pulse-per-second) signal connected to +a GPIO pin. + +Required properties: +- compatible: should be "pps-gpio" +- gpios: one PPS GPIO in the format described by ../gpio/gpio.txt + +Optional properties: +- assert-falling-edge: when present, assert is indicated by a falling edge + (instead of by a rising edge) + +Example: + pps { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pps>; + + gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>; + assert-falling-edge; + + compatible = "pps-gpio"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/prng/msm-rng.txt b/arch/arm64/boot/dts/vendor/bindings/prng/msm-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e2d8b800888982d3cc7c1deddeefb78993a61d7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/prng/msm-rng.txt @@ -0,0 +1,19 @@ +* RNG (Random Number Generator) + +Required properties: +- compatible : Should be "qcom,msm-rng" +- reg : Offset and length of the register set for the device + +Optional property: +- qcom,msm-rng-iface-clk : If the device uses iface-clk. +- qcom,msm-rng-hwkm-clk : If the device uses hwkm clock. +- qcom,no-qrng-config : Flag to decide whether the driver do the hardware configuration or not. + +Example: + + qcom,msm-rng@f9bff000 { + compatible = "qcom,msm-rng"; + reg = <0xf9bff000 0x200>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/property-units.txt b/arch/arm64/boot/dts/vendor/bindings/property-units.txt new file mode 100644 index 0000000000000000000000000000000000000000..45ce054d844d4deb4d3dea2f2fbcc17e14251dd8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/property-units.txt @@ -0,0 +1,42 @@ +Standard Unit Suffixes for Property names + +Properties which have a unit of measure are recommended to have a unit +suffix appended to the property name. The list below contains the +recommended suffixes. Other variations exist in bindings, but should not +be used in new bindings or added here. The inconsistency in the unit +prefixes is due to selecting the most commonly used variants. + +It is also recommended to use the units listed here and not add additional +unit prefixes. + +Time/Frequency +---------------------------------------- +-mhz : megahertz +-hz : Hertz (preferred) +-sec : seconds +-ms : milliseconds +-us : microseconds +-ns : nanoseconds + +Distance +---------------------------------------- +-mm : millimeters + +Electricity +---------------------------------------- +-microamp : micro amps +-microamp-hours : micro amp-hours +-ohms : Ohms +-micro-ohms : micro Ohms +-microwatt-hours: micro Watt-hours +-microvolt : micro volts +-picofarads : picofarads + +Temperature +---------------------------------------- +-celsius : Degrees Celsius +-millicelsius : Degreee milli-Celsius + +Pressure +---------------------------------------- +-kpascal : kiloPascal diff --git a/arch/arm64/boot/dts/vendor/bindings/ptp/brcm,ptp-dte.txt b/arch/arm64/boot/dts/vendor/bindings/ptp/brcm,ptp-dte.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b1075ee8a3025f58c0609da564521afbec70ff7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ptp/brcm,ptp-dte.txt @@ -0,0 +1,19 @@ +* Broadcom Digital Timing Engine(DTE) based PTP clock + +Required properties: +- compatible: should contain the core compatibility string + and the SoC compatibility string. The SoC + compatibility string is to handle SoC specific + hardware differences. + Core compatibility string: + "brcm,ptp-dte" + SoC compatibility strings: + "brcm,iproc-ptp-dte" - for iproc based SoC's +- reg: address and length of the DTE block's NCO registers + +Example: + +ptp: ptp-dte@180af650 { + compatible = "brcm,iproc-ptp-dte", "brcm,ptp-dte"; + reg = <0x180af650 0x10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/ptp/ptp-qoriq.txt b/arch/arm64/boot/dts/vendor/bindings/ptp/ptp-qoriq.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5d0e7998e2b0a09546ab068dade2176b194d864 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ptp/ptp-qoriq.txt @@ -0,0 +1,78 @@ +* Freescale QorIQ 1588 timer based PTP clock + +General Properties: + + - compatible Should be "fsl,etsec-ptp" for eTSEC + Should be "fsl,fman-ptp-timer" for DPAA FMan + - reg Offset and length of the register set for the device + - interrupts There should be at least two interrupts. Some devices + have as many as four PTP related interrupts. + +Clock Properties: + + - fsl,cksel Timer reference clock source. + - fsl,tclk-period Timer reference clock period in nanoseconds. + - fsl,tmr-prsc Prescaler, divides the output clock. + - fsl,tmr-add Frequency compensation value. + - fsl,tmr-fiper1 Fixed interval period pulse generator. + - fsl,tmr-fiper2 Fixed interval period pulse generator. + - fsl,max-adj Maximum frequency adjustment in parts per billion. + + These properties set the operational parameters for the PTP + clock. You must choose these carefully for the clock to work right. + Here is how to figure good values: + + TimerOsc = selected reference clock MHz + tclk_period = desired clock period nanoseconds + NominalFreq = 1000 / tclk_period MHz + FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0) + tmr_add = ceil(2^32 / FreqDivRatio) + OutputClock = NominalFreq / tmr_prsc MHz + PulseWidth = 1 / OutputClock microseconds + FiperFreq1 = desired frequency in Hz + FiperDiv1 = 1000000 * OutputClock / FiperFreq1 + tmr_fiper1 = tmr_prsc * tclk_period * FiperDiv1 - tclk_period + max_adj = 1000000000 * (FreqDivRatio - 1.0) - 1 + + The calculation for tmr_fiper2 is the same as for tmr_fiper1. The + driver expects that tmr_fiper1 will be correctly set to produce a 1 + Pulse Per Second (PPS) signal, since this will be offered to the PPS + subsystem to synchronize the Linux clock. + + Reference clock source is determined by the value, which is holded + in CKSEL bits in TMR_CTRL register. "fsl,cksel" property keeps the + value, which will be directly written in those bits, that is why, + according to reference manual, the next clock sources can be used: + + For eTSEC, + <0> - external high precision timer reference clock (TSEC_TMR_CLK + input is used for this purpose); + <1> - eTSEC system clock; + <2> - eTSEC1 transmit clock; + <3> - RTC clock input. + + For DPAA FMan, + <0> - external high precision timer reference clock (TMR_1588_CLK) + <1> - MAC system clock (1/2 FMan clock) + <2> - reserved + <3> - RTC clock oscillator + + When this attribute is not used, the IEEE 1588 timer reference clock + will use the eTSEC system clock (for Gianfar) or the MAC system + clock (for DPAA). + +Example: + + ptp_clock@24e00 { + compatible = "fsl,etsec-ptp"; + reg = <0x24E00 0xB0>; + interrupts = <12 0x8 13 0x8>; + interrupt-parent = < &ipic >; + fsl,cksel = <1>; + fsl,tclk-period = <10>; + fsl,tmr-prsc = <100>; + fsl,tmr-add = <0x999999A4>; + fsl,tmr-fiper1 = <0x3B9AC9F6>; + fsl,tmr-fiper2 = <0x00018696>; + fsl,max-adj = <659999998>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-hlcdc-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-hlcdc-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfda0d57d302a425c7732926965ace77e993fc57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-hlcdc-pwm.txt @@ -0,0 +1,29 @@ +Device-Tree bindings for Atmel's HLCDC (High-end LCD Controller) PWM driver + +The Atmel HLCDC PWM is subdevice of the HLCDC MFD device. +See ../mfd/atmel-hlcdc.txt for more details. + +Required properties: + - compatible: value should be one of the following: + "atmel,hlcdc-pwm" + - pinctr-names: the pin control state names. Should contain "default". + - pinctrl-0: should contain the pinctrl states described by pinctrl + default. + - #pwm-cells: should be set to 3. This PWM chip use the default 3 cells + bindings defined in pwm.txt in this directory. + +Example: + + hlcdc: hlcdc@f0030000 { + compatible = "atmel,sama5d3-hlcdc"; + reg = <0xf0030000 0x2000>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8c831d7b0d1bb9d90cfc9b3022b57b9e6a2f74d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-pwm.txt @@ -0,0 +1,34 @@ +Atmel PWM controller + +Required properties: + - compatible: should be one of: + - "atmel,at91sam9rl-pwm" + - "atmel,sama5d3-pwm" + - "atmel,sama5d2-pwm" + - reg: physical base address and length of the controller's registers + - #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Example: + + pwm0: pwm@f8034000 { + compatible = "atmel,at91sam9rl-pwm"; + reg = <0xf8034000 0x400>; + #pwm-cells = <3>; + }; + + pwmleds { + compatible = "pwm-leds"; + + d1 { + label = "d1"; + pwms = <&pwm0 3 5000 0> + max-brightness = <255>; + }; + + d2 { + label = "d2"; + pwms = <&pwm0 1 5000 1> + max-brightness = <255>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-tcb-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-tcb-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8031148bcf85ad7a8f516d6b985d0c0493c8ae27 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/atmel-tcb-pwm.txt @@ -0,0 +1,16 @@ +Atmel TCB PWM controller + +Required properties: +- compatible: should be "atmel,tcb-pwm" +- #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. The only third cell flag supported by this binding is + PWM_POLARITY_INVERTED. +- tc-block: The Timer Counter block to use as a PWM chip. + +Example: + +pwm { + compatible = "atmel,tcb-pwm"; + #pwm-cells = <3>; + tc-block = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,bcm7038-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,bcm7038-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..d9254a6da5ed258badb17e0d924725a9c882b865 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,bcm7038-pwm.txt @@ -0,0 +1,20 @@ +Broadcom BCM7038 PWM controller (BCM7xxx Set Top Box PWM controller) + +Required properties: + +- compatible: must be "brcm,bcm7038-pwm" +- reg: physical base address and length for this controller +- #pwm-cells: should be 2. See pwm.txt in this directory for a description + of the cells format +- clocks: a phandle to the reference clock for this block which is fed through + its internal variable clock frequency generator + + +Example: + + pwm: pwm@f0408000 { + compatible = "brcm,bcm7038-pwm"; + reg = <0xf0408000 0x28>; + #pwm-cells = <2>; + clocks = <&upg_fixed>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,iproc-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,iproc-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..21f75bbd6dae4524cf489289cf00d35e0d2f1f04 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,iproc-pwm.txt @@ -0,0 +1,21 @@ +Broadcom iProc PWM controller device tree bindings + +This controller has 4 channels. + +Required Properties : +- compatible: must be "brcm,iproc-pwm" +- reg: physical base address and length of the controller's registers +- clocks: phandle + clock specifier pair for the external clock +- #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + +Example: + +pwm: pwm@18031000 { + compatible = "brcm,iproc-pwm"; + reg = <0x18031000 0x28>; + clocks = <&osc>; + #pwm-cells = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,kona-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,kona-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8eae9fe7841cf8e9891000231297125fa13b13d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/brcm,kona-pwm.txt @@ -0,0 +1,21 @@ +Broadcom Kona PWM controller device tree bindings + +This controller has 6 channels. + +Required Properties : +- compatible: should contain "brcm,kona-pwm" +- reg: physical base address and length of the controller's registers +- clocks: phandle + clock specifier pair for the external clock +- #pwm-cells: Should be 3. See pwm.txt in this directory for a + description of the cells format. + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + +Example: + +pwm: pwm@3e01a000 { + compatible = "brcm,bcm11351-pwm", "brcm,kona-pwm"; + reg = <0x3e01a000 0xc4>; + clocks = <&pwm_clk>; + #pwm-cells = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/cirrus,clps711x-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/cirrus,clps711x-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..c0b2028238d6a901bd912cbceb39db4ba8a36a32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/cirrus,clps711x-pwm.txt @@ -0,0 +1,15 @@ +* Cirris Logic CLPS711X PWM controller + +Required properties: +- compatible: Shall contain "cirrus,ep7209-pwm". +- reg: Physical base address and length of the controller's registers. +- clocks: phandle + clock specifier pair of the PWM reference clock. +- #pwm-cells: Should be 1. The cell specifies the index of the channel. + +Example: + pwm: pwm@80000400 { + compatible = "cirrus,ep7312-pwm", "cirrus,ep7209-pwm"; + reg = <0x80000400 0x4>; + clocks = <&clks 8>; + #pwm-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/google,cros-ec-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/google,cros-ec-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..472bd46ab5a4dc6714358b45be33d7beafb63b68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/google,cros-ec-pwm.txt @@ -0,0 +1,23 @@ +* PWM controlled by ChromeOS EC + +Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller +(EC) and controlled via a host-command interface. + +An EC PWM node should be only found as a sub-node of the EC node (see +Documentation/devicetree/bindings/mfd/cros-ec.txt). + +Required properties: +- compatible: Must contain "google,cros-ec-pwm" +- #pwm-cells: Should be 1. The cell specifies the PWM index. + +Example: + cros-ec@0 { + compatible = "google,cros-ec-spi"; + + ... + + cros_ec_pwm: ec-pwm { + compatible = "google,cros-ec-pwm"; + #pwm-cells = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/img-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/img-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..fade5f26fcacc5a0aeb388ccfa6561883ab90da8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/img-pwm.txt @@ -0,0 +1,24 @@ +*Imagination Technologies PWM DAC driver + +Required properties: + - compatible: Should be "img,pistachio-pwm" + - reg: Should contain physical base address and length of pwm registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. + - clock-names: Must include the following entries. + - pwm: PWM operating clock. + - sys: PWM system interface clock. + - #pwm-cells: Should be 2. See pwm.txt in this directory for the + description of the cells format. + - img,cr-periph: Must contain a phandle to the peripheral control + syscon node which contains PWM control registers. + +Example: + pwm: pwm@18101300 { + compatible = "img,pistachio-pwm"; + reg = <0x18101300 0x100>; + clocks = <&pwm_clk>, <&system_clk>; + clock-names = "pwm", "sys"; + #pwm-cells = <2>; + img,cr-periph = <&cr_periph>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/imx-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/imx-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..c61bdf8cd41bc775f0923a104cdeafe3562f5f0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/imx-pwm.txt @@ -0,0 +1,27 @@ +Freescale i.MX PWM controller + +Required properties: +- compatible : should be "fsl,-pwm" and one of the following + compatible strings: + - "fsl,imx1-pwm" for PWM compatible with the one integrated on i.MX1 + - "fsl,imx27-pwm" for PWM compatible with the one integrated on i.MX27 +- reg: physical base address and length of the controller's registers +- #pwm-cells: 2 for i.MX1 and 3 for i.MX27 and newer SoCs. See pwm.txt + in this directory for a description of the cells format. +- clocks : Clock specifiers for both ipg and per clocks. +- clock-names : Clock names should include both "ipg" and "per" +See the clock consumer binding, + Documentation/devicetree/bindings/clock/clock-bindings.txt +- interrupts: The interrupt for the pwm controller + +Example: + +pwm1: pwm@53fb4000 { + #pwm-cells = <3>; + compatible = "fsl,imx53-pwm", "fsl,imx27-pwm"; + reg = <0x53fb4000 0x4000>; + clocks = <&clks IMX5_CLK_PWM1_IPG_GATE>, + <&clks IMX5_CLK_PWM1_HF_GATE>; + clock-names = "ipg", "per"; + interrupts = <61>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/ingenic,jz47xx-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/ingenic,jz47xx-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d9d3f90641b7df9be72f9abc05cf97c3a392a6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/ingenic,jz47xx-pwm.txt @@ -0,0 +1,25 @@ +Ingenic JZ47xx PWM Controller +============================= + +Required properties: +- compatible: One of: + * "ingenic,jz4740-pwm" + * "ingenic,jz4770-pwm" + * "ingenic,jz4780-pwm" +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description + of the cells format. +- clocks : phandle to the external clock. +- clock-names : Should be "ext". + + +Example: + + pwm: pwm@10002000 { + compatible = "ingenic,jz4740-pwm"; + reg = <0x10002000 0x1000>; + + #pwm-cells = <3>; + + clocks = <&ext>; + clock-names = "ext"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/lpc1850-sct-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/lpc1850-sct-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..36e49d4325cdb6af36cab7405de706707042aa93 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/lpc1850-sct-pwm.txt @@ -0,0 +1,20 @@ +* NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver + +Required properties: + - compatible: Should be "nxp,lpc1850-sct-pwm" + - reg: Should contain physical base address and length of pwm registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. + - clock-names: Must include the following entries. + - pwm: PWM operating clock. + - #pwm-cells: Should be 3. See pwm.txt in this directory for the description + of the cells format. + +Example: + pwm: pwm@40000000 { + compatible = "nxp,lpc1850-sct-pwm"; + reg = <0x40000000 0x1000>; + clocks =<&ccu1 CLK_CPU_SCT>; + clock-names = "pwm"; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/lpc32xx-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/lpc32xx-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..74b5bc5dd19ac32ce6a7fdb8e4f7e25ad5542df8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/lpc32xx-pwm.txt @@ -0,0 +1,17 @@ +LPC32XX PWM controller + +Required properties: +- compatible: should be "nxp,lpc3220-pwm" +- reg: physical base address and length of the controller's registers + +Examples: + +pwm@4005c000 { + compatible = "nxp,lpc3220-pwm"; + reg = <0x4005c000 0x4>; +}; + +pwm@4005c004 { + compatible = "nxp,lpc3220-pwm"; + reg = <0x4005c004 0x4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/mxs-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/mxs-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..96cdde5f6208eb1817a7cba95fdba96b5dc3beaa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/mxs-pwm.txt @@ -0,0 +1,17 @@ +Freescale MXS PWM controller + +Required properties: +- compatible: should be "fsl,imx23-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. +- fsl,pwm-number: the number of PWM devices + +Example: + +pwm: pwm@80064000 { + compatible = "fsl,imx28-pwm", "fsl,imx23-pwm"; + reg = <0x80064000 0x2000>; + #pwm-cells = <2>; + fsl,pwm-number = <8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/nvidia,tegra20-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/nvidia,tegra20-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..c57e11b8d9375b85b882407a3477f7ff2ac58553 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/nvidia,tegra20-pwm.txt @@ -0,0 +1,76 @@ +Tegra SoC PWFM controller + +Required properties: +- compatible: Must be: + - "nvidia,tegra20-pwm": for Tegra20 + - "nvidia,tegra30-pwm", "nvidia,tegra20-pwm": for Tegra30 + - "nvidia,tegra114-pwm", "nvidia,tegra20-pwm": for Tegra114 + - "nvidia,tegra124-pwm", "nvidia,tegra20-pwm": for Tegra124 + - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132 + - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210 + - "nvidia,tegra186-pwm": for Tegra186 +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - pwm + +Optional properties: +============================ +In some of the interface like PWM based regulator device, it is required +to configure the pins differently in different states, especially in suspend +state of the system. The configuration of pin is provided via the pinctrl +DT node as detailed in the pinctrl DT binding document + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +The PWM node will have following optional properties. +pinctrl-names: Pin state names. Must be "default" and "sleep". +pinctrl-0: phandle for the default/active state of pin configurations. +pinctrl-1: phandle for the sleep state of pin configurations. + +Example: + + pwm: pwm@7000a000 { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + clocks = <&tegra_car 17>; + resets = <&tegra_car 17>; + reset-names = "pwm"; + }; + + +Example with the pin configuration for suspend and resume: +========================================================= +Suppose pin PE7 (On Tegra210) interfaced with the regulator device and +it requires PWM output to be tristated when system enters suspend. +Following will be DT binding to achieve this: + +#include + + pinmux@700008d4 { + pwm_active_state: pwm_active_state { + pe7 { + nvidia,pins = "pe7"; + nvidia,tristate = ; + }; + }; + + pwm_sleep_state: pwm_sleep_state { + pe7 { + nvidia,pins = "pe7"; + nvidia,tristate = ; + }; + }; + }; + + pwm@7000a000 { + /* Mandatory PWM properties */ + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pwm_active_state>; + pinctrl-1 = <&pwm_sleep_state>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/nxp,pca9685-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/nxp,pca9685-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..f84ec9d291ea885d8d30045c3093876fa4b0e455 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/nxp,pca9685-pwm.txt @@ -0,0 +1,27 @@ +NXP PCA9685 16-channel 12-bit PWM LED controller +================================================ + +Required properties: + - compatible: "nxp,pca9685-pwm" + - #pwm-cells: Should be 2. See pwm.txt in this directory for a description of + the cells format. + The index 16 is the ALLCALL channel, that sets all PWM channels at the same + time. + +Optional properties: + - invert (bool): boolean to enable inverted logic + - open-drain (bool): boolean to configure outputs with open-drain structure; + if omitted use totem-pole structure + +Example: + +For LEDs that are directly connected to the PCA, the following setting is +applicable: + +pca: pca@41 { + compatible = "nxp,pca9685-pwm"; + #pwm-cells = <2>; + reg = <0x41>; + invert; + open-drain; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-bcm2835.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-bcm2835.txt new file mode 100644 index 0000000000000000000000000000000000000000..8cf87d1bfca53c7d896a3ca610c09e068f78f7eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-bcm2835.txt @@ -0,0 +1,30 @@ +BCM2835 PWM controller (Raspberry Pi controller) + +Required properties: +- compatible: should be "brcm,bcm2835-pwm" +- reg: physical base address and length of the controller's registers +- clocks: This clock defines the base clock frequency of the PWM hardware + system, the period and the duty_cycle of the PWM signal is a multiple of + the base period. +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Examples: + +pwm@2020c000 { + compatible = "brcm,bcm2835-pwm"; + reg = <0x2020c000 0x28>; + clocks = <&clk_pwm>; + #pwm-cells = <3>; +}; + +clocks { + .... + clk_pwm: pwm { + compatible = "fixed-clock"; + reg = <3>; + #clock-cells = <0>; + clock-frequency = <9200000>; + }; + .... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-berlin.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-berlin.txt new file mode 100644 index 0000000000000000000000000000000000000000..82cbe16fcbbceee7ad9251a352a45c29422e0f50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-berlin.txt @@ -0,0 +1,17 @@ +Berlin PWM controller + +Required properties: +- compatible: should be "marvell,berlin-pwm" +- reg: physical base address and length of the controller's registers +- clocks: phandle to the input clock +- #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. + +Example: + +pwm: pwm@f7f20000 { + compatible = "marvell,berlin-pwm"; + reg = <0xf7f20000 0x40>; + clocks = <&chip_clk CLKID_CFG>; + #pwm-cells = <3>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-fsl-ftm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-fsl-ftm.txt new file mode 100644 index 0000000000000000000000000000000000000000..576ad002bc833bd1ffb1d088d9da04aff0acba98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-fsl-ftm.txt @@ -0,0 +1,55 @@ +Freescale FlexTimer Module (FTM) PWM controller + +The same FTM PWM device can have a different endianness on different SoCs. The +device tree provides a property to describing this so that an operating system +device driver can handle all variants of the device. Refer to the table below +for the endianness of the FTM PWM block as integrated into the existing SoCs: + + SoC | FTM-PWM endianness + --------+------------------- + Vybrid | LE + LS1 | BE + LS2 | LE + +Please see ../regmap/regmap.txt for more detail about how to specify endian +modes in device tree. + + +Required properties: +- compatible : should be "fsl,-ftm-pwm" and one of the following + compatible strings: + - "fsl,vf610-ftm-pwm" for PWM compatible with the one integrated on VF610 + - "fsl,imx8qm-ftm-pwm" for PWM compatible with the one integrated on i.MX8QM +- reg: Physical base address and length of the controller's registers +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. +- clock-names: Should include the following module clock source entries: + "ftm_sys" (module clock, also can be used as counter clock), + "ftm_ext" (external counter clock), + "ftm_fix" (fixed counter clock), + "ftm_cnt_clk_en" (external and fixed counter clock enable/disable). +- clocks: Must contain a phandle and clock specifier for each entry in + clock-names, please see clock/clock-bindings.txt for details of the property + values. +- pinctrl-names: Must contain a "default" entry. +- pinctrl-NNN: One property must exist for each entry in pinctrl-names. + See pinctrl/pinctrl-bindings.txt for details of the property values. +- big-endian: Boolean property, required if the FTM PWM registers use a big- + endian rather than little-endian layout. + +Example: + +pwm0: pwm@40038000 { + compatible = "fsl,vf610-ftm-pwm"; + reg = <0x40038000 0x1000>; + #pwm-cells = <3>; + clock-names = "ftm_sys", "ftm_ext", + "ftm_fix", "ftm_cnt_clk_en"; + clocks = <&clks VF610_CLK_FTM0>, + <&clks VF610_CLK_FTM0_EXT_SEL>, + <&clks VF610_CLK_FTM0_FIX_SEL>, + <&clks VF610_CLK_FTM0_EXT_FIX_EN>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_1>; + big-endian; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-hibvt.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-hibvt.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa7849d67836b1dbc39c69f65e2767e7128c1310 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-hibvt.txt @@ -0,0 +1,21 @@ +Hisilicon PWM controller + +Required properties: +-compatible: should contain one SoC specific compatible string + The SoC specific strings supported including: + "hisilicon,hi3516cv300-pwm" + "hisilicon,hi3519v100-pwm" +- reg: physical base address and length of the controller's registers. +- clocks: phandle and clock specifier of the PWM reference clock. +- resets: phandle and reset specifier for the PWM controller reset. +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Example: + pwm: pwm@12130000 { + compatible = "hisilicon,hi3516cv300-pwm"; + reg = <0x12130000 0x10000>; + clocks = <&crg_ctrl HI3516CV300_PWM_CLK>; + resets = <&crg_ctrl 0x38 0>; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-lp3943.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-lp3943.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bd9d3b12ce10cd2030aee146e377f864b86b762 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-lp3943.txt @@ -0,0 +1,58 @@ +TI/National Semiconductor LP3943 PWM controller + +Required properties: + - compatible: "ti,lp3943-pwm" + - #pwm-cells: Should be 2. See pwm.txt in this directory for a + description of the cells format. + Note that this hardware limits the period length to the + range 6250~1600000. + - ti,pwm0 or ti,pwm1: Output pin number(s) for PWM channel 0 or 1. + 0 = output 0 + 1 = output 1 + . + . + 15 = output 15 + +Example: +PWM 0 is for RGB LED brightness control +PWM 1 is for brightness control of LP8557 backlight device + +&i2c3 { + lp3943@60 { + compatible = "ti,lp3943"; + reg = <0x60>; + + /* + * PWM 0 : output 8, 9 and 10 + * PWM 1 : output 15 + */ + pwm3943: pwm { + compatible = "ti,lp3943-pwm"; + #pwm-cells = <2>; + ti,pwm0 = <8 9 10>; + ti,pwm1 = <15>; + }; + }; + +}; + +/* LEDs control with PWM 0 of LP3943 */ +pwmleds { + compatible = "pwm-leds"; + rgb { + label = "indi::rgb"; + pwms = <&pwm3943 0 10000>; + max-brightness = <255>; + }; +}; + +&i2c4 { + /* Backlight control with PWM 1 of LP3943 */ + backlight@2c { + compatible = "ti,lp8557"; + reg = <0x2c>; + + pwms = <&pwm3943 1 10000>; + pwm-names = "lp8557"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-mediatek.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-mediatek.txt new file mode 100644 index 0000000000000000000000000000000000000000..991728cb46cb8cf24a2793ecc1ec8a417aa2df0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-mediatek.txt @@ -0,0 +1,40 @@ +MediaTek PWM controller + +Required properties: + - compatible: should be "mediatek,-pwm": + - "mediatek,mt2712-pwm": found on mt2712 SoC. + - "mediatek,mt7622-pwm": found on mt7622 SoC. + - "mediatek,mt7623-pwm": found on mt7623 SoC. + - "mediatek,mt7628-pwm": found on mt7628 SoC. + - reg: physical base address and length of the controller's registers. + - #pwm-cells: must be 2. See pwm.txt in this directory for a description of + the cell format. + - clocks: phandle and clock specifier of the PWM reference clock. + - clock-names: must contain the following, except for MT7628 which + has no clocks + - "top": the top clock generator + - "main": clock used by the PWM core + - "pwm1-8": the eight per PWM clocks for mt2712 + - "pwm1-6": the six per PWM clocks for mt7622 + - "pwm1-5": the five per PWM clocks for mt7623 + - pinctrl-names: Must contain a "default" entry. + - pinctrl-0: One property must exist for each entry in pinctrl-names. + See pinctrl/pinctrl-bindings.txt for details of the property values. + +Example: + pwm0: pwm@11006000 { + compatible = "mediatek,mt7623-pwm"; + reg = <0 0x11006000 0 0x1000>; + #pwm-cells = <2>; + clocks = <&topckgen CLK_TOP_PWM_SEL>, + <&pericfg CLK_PERI_PWM>, + <&pericfg CLK_PERI_PWM1>, + <&pericfg CLK_PERI_PWM2>, + <&pericfg CLK_PERI_PWM3>, + <&pericfg CLK_PERI_PWM4>, + <&pericfg CLK_PERI_PWM5>; + clock-names = "top", "main", "pwm1", "pwm2", + "pwm3", "pwm4", "pwm5"; + pinctrl-names = "default"; + pinctrl-0 = <&pwm0_pins>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-meson.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-meson.txt new file mode 100644 index 0000000000000000000000000000000000000000..1fa3f718213342f20e910a224b95e23efede87be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-meson.txt @@ -0,0 +1,26 @@ +Amlogic Meson PWM Controller +============================ + +Required properties: +- compatible: Shall contain "amlogic,meson8b-pwm" + or "amlogic,meson-gxbb-pwm" + or "amlogic,meson-gxbb-ao-pwm" + or "amlogic,meson-axg-ee-pwm" + or "amlogic,meson-axg-ao-pwm" +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Optional properties: +- clocks: Could contain one or two parents clocks phandle for each of the two + PWM channels. +- clock-names: Could contain at least the "clkin0" and/or "clkin1" names. + +Example: + + pwm_ab: pwm@8550 { + compatible = "amlogic,meson-gxbb-pwm"; + reg = <0x0 0x08550 0x0 0x10>; + #pwm-cells = <3>; + clocks = <&xtal>, <&xtal>; + clock-names = "clkin0", "clkin1"; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-mtk-disp.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-mtk-disp.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f8af2bcc7b77110298b45c7d178066c44abca7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-mtk-disp.txt @@ -0,0 +1,43 @@ +MediaTek display PWM controller + +Required properties: + - compatible: should be "mediatek,-disp-pwm": + - "mediatek,mt2701-disp-pwm": found on mt2701 SoC. + - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. + - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. + - reg: physical base address and length of the controller's registers. + - #pwm-cells: must be 2. See pwm.txt in this directory for a description of + the cell format. + - clocks: phandle and clock specifier of the PWM reference clock. + - clock-names: must contain the following: + - "main": clock used to generate PWM signals. + - "mm": sync signals from the modules of mmsys. + - pinctrl-names: Must contain a "default" entry. + - pinctrl-0: One property must exist for each entry in pinctrl-names. + See pinctrl/pinctrl-bindings.txt for details of the property values. + +Example: + pwm0: pwm@1401e000 { + compatible = "mediatek,mt8173-disp-pwm", + "mediatek,mt6595-disp-pwm"; + reg = <0 0x1401e000 0 0x1000>; + #pwm-cells = <2>; + clocks = <&mmsys CLK_MM_DISP_PWM026M>, + <&mmsys CLK_MM_DISP_PWM0MM>; + clock-names = "main", "mm"; + pinctrl-names = "default"; + pinctrl-0 = <&disp_pwm0_pins>; + }; + + backlight_lcd: backlight_lcd { + compatible = "pwm-backlight"; + pwms = <&pwm0 0 1000000>; + brightness-levels = < + 0 16 32 48 64 80 96 112 + 128 144 160 176 192 208 224 240 + 255 + >; + default-brightness-level = <9>; + power-supply = <&mt6397_vio18_reg>; + enable-gpios = <&pio 95 GPIO_ACTIVE_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-omap-dmtimer.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-omap-dmtimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ccfcc82da08347e9ed073c353ad2210731c4024 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-omap-dmtimer.txt @@ -0,0 +1,22 @@ +* OMAP PWM for dual-mode timers + +Required properties: +- compatible: Shall contain "ti,omap-dmtimer-pwm". +- ti,timers: phandle to PWM capable OMAP timer. See timer/ti,timer.txt for info + about these timers. +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Optional properties: +- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet +- ti,clock-source: Set dmtimer parent clock, values between 0 and 2: + - 0x00 - high-frequency system clock (timer_sys_ck) + - 0x01 - 32-kHz always-on clock (timer_32k_ck) + - 0x02 - external clock (timer_ext_ck, OMAP2 only) + +Example: + pwm9: dmtimer-pwm@9 { + compatible = "ti,omap-dmtimer-pwm"; + ti,timers = <&timer9>; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-qti-lpg.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-qti-lpg.txt new file mode 100644 index 0000000000000000000000000000000000000000..d92ab53999702481f98246f601553c695aaa3cbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-qti-lpg.txt @@ -0,0 +1,253 @@ +Qualcomm Technologies, Inc. LPG driver specific bindings + +This binding document describes the properties of LPG (Light Pulse Generator) +device module in Qualcomm Technologies, Inc. PMIC chips. + +- compatible: + Usage: required + Value type: + Definition: Must be "qcom,pwm-lpg". + +- reg: + Usage: required + Value type: + Definition: Register base for LPG and LUT modules. + +- reg-names: + Usage: required + Value type: + Definition: The name of the register defined in the reg property. + It must have "lpg-base", "lut-base" is optional but + it's required if any LPG channels support LUT mode + with a LUT module. + +- #pwm-cells: + Usage: required + Value type: + Definition: The number of cells in "pwms" property specified in + PWM user nodes. It should be 2. The first cell is + the PWM channel ID indexed from 0, and the second + cell is the PWM default period in nanoseconds. + +- qcom,num-lpg-channels: + Usage: required + Value type: + Definition: The number of the consecutive LPG/PWM channels in the chip. + +- nvmem-names: + Usage: optional + Value type: + Definition: The nvmem device name for the SDAM module where the LUT + pattern is stored. It must be "ppg_sdam". This property + is required only when LUT mode is supported with a SDAM + module instead of a LUT module. + +- nvmem: + Usage: optional + Value type: + Definition: Phandle of the nvmem device to access the LUT stored + in the SDAM module. This property is required only when + LUT mode is supported and the LUT pattern is stored in a + SDAM module instead of a LUT module. + +- qcom,pbs-client + Usage: optional + Value type: + Definition: Phandle of the PBS client used for sending the PBS + trigger. This property is required when LUT mode is + supported and the LUT pattern is stored in a SDAM + module instead of a LUT module. + +- qcom,lut-sdam-base: + Usage: optional + Value type: + Definition: The register base of the LUT entries stored in SDAM. This + property is required only when LUT mode is supported and + the LUT pattern is stored in a SDAM module instead of a + LUT module. + +- qcom,lut-patterns: + Usage: optional + Value type: + Definition: Duty ratios in percentages for LPG working at LUT mode. + These duty ratios will be translated into PWM values + and stored in LUT or SDAM module shared for all LPG + channels. The LUT module has resource to store 47 PWM + values at max while SDAM module can store upto 64 PWM + values. This property is required if any LPG channels + support LUT mode. + +- qcom,sync-channel-ids: + Usage: optional + Value type: + Definition: The hardware IDs of the LPG channel that required be + grouped together. These channels will share the same LUT + ramping configuration so that they will be enabled with a + synchronized pattern. If the LUT ramping configuration + differs for the channels grouped for synchronization, + configuration of the first channel will be applied for + all others. + +Subnode is optional if LUT mode is not required, it's required if any LPG +channels expected to be supported in LUT mode. + +Subnode properties: +Subnodes for each LPG channel (lpg@X) can be defined if any of the following +parameters needs to be configured for that channel. + +- qcom,lpg-chan-id: + Usage: required + Value type: + Definition: The LPG channel's hardware ID indexed from 1. Allowed + range is 1 - 8. Maximum value depends on the number of + channels supported on PMIC. + +- qcom,lpg-sdam-base: + Usage: optional + Value type: + Definition: Register base address for LPG configuration in SDAM for + the LPG channel specified under "qcom,lpg-chan-id". + This property is required if LUT mode is supported with + a SDAM module. + +- qcom,ramp-step-ms: + Usage: required + Value type: + Definition: The step duration in milliseconds for LPG staying at each + duty specified in the LUT pattern. Allowed range: + 1 - 511 when LUT module is used, and 8 - 2000 when SDAM + is used. + +- qcom,ramp-high-index: + Usage: required + Value type: + Definition: The high index of the LUT pattern where LPG ends up + ramping to. Allowed range: 1 - 47 when LUT module + is used, and 1 - 64 when SDAM module is used. + +- qcom,ramp-low-index: + Usage: required + Value type: + Definition: The low index of the LUT pattern from where LPG begins + ramping from. The ramp-low-index should be always less + than ramp-high-index when SDAM module is used. Allowed + range: 0 - 46 when LUT module is used, and 0 - 63 when + SDAM module is used. + +- qcom,ramp-pattern-repeat: + Usage: optional + Value type: + Definition: The flag to specify if LPG would be ramping with the LUT + pattern repeatedly. + +- qcom,ramp-from-low-to-high: + Usage: optional + Value type: + Definition: The flag to specify the LPG ramping direction. The ramping + direction is from low index to high index of the LUT + pattern if it's specified. This property is not required + when SDAM module is used. + +- qcom,ramp-toggle: + Usage: optional + Value type: + Definition: The flag to specify if LPG would toggle the LUT pattern + in ramping. If toggling enabled, LPG would return to the + low index when high index is reached, or return to the high + index when low index is reached. This property is not + required when SDAM module is used. + +- qcom,ramp-pause-hi-count: + Usage: optional + Value type: + Definition: The step count that LPG stop the output when it ramped up + to the high index of the LUT. This property is not + required when SDAM module is used. + +- qcom,ramp-pause-lo-count: + Usage: optional + Value type: + Definition: The step count that LPG stop the output when it ramped up + to the low index of the LUT. This property is not + required when SDAM module is used. + +Example when LUT pattern is stored in a LUT module: + + pm8150l_lpg: lpg@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x600>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; + qcom,num-lpg-channels = <6>; + #pwm-cells = <2>; + qcom,lut-patterns = <0 14 28 42 56 70 84 100 + 100 84 70 56 42 28 14 0>; + lpg@1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <200>; + qcom,ramp-pause-hi-count = <10>; + qcom,ramp-pause-lo-count = <10>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + lpg@2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <200>; + qcom,ramp-pause-hi-count = <10>; + qcom,ramp-pause-lo-count = <10>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + lpg@3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <200>; + qcom,ramp-pause-hi-count = <10>; + qcom,ramp-pause-lo-count = <10>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + }; + +Example when LUT pattern is stored in a SDAM module: + + pmi632_lpg: lpg@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x600>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + nvmem-names = "ppg_sdam"; + nvmem = <&sdam7>; + qcom,pbs-client = <&pbs_client_3>; + qcom,lut-sdam-base = <0x80>; + qcom,lut-patterns = <0 14 28 42 56 70 84 100 + 100 84 70 56 42 28 14 0>; + lpg@1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x48>: + }; + lpg@2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x56>; + }; + lpg@3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <15>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x64>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c5e52a5bede2da427a91b5dbf8996462f393551 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-rockchip.txt @@ -0,0 +1,27 @@ +Rockchip PWM controller + +Required properties: + - compatible: should be "rockchip,-pwm" + "rockchip,rk2928-pwm": found on RK29XX,RK3066 and RK3188 SoCs + "rockchip,rk3288-pwm": found on RK3288 SOC + "rockchip,rv1108-pwm", "rockchip,rk3288-pwm": found on RV1108 SoC + "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC + - reg: physical base address and length of the controller's registers + - clocks: See ../clock/clock-bindings.txt + - For older hardware (rk2928, rk3066, rk3188, rk3228, rk3288, rk3399): + - There is one clock that's used both to derive the functional clock + for the device and as the bus clock. + - For newer hardware (rk3328 and future socs): specified by name + - "pwm": This is used to derive the functional clock. + - "pclk": This is the APB bus clock. + - #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory + for a description of the cell format. + +Example: + + pwm0: pwm@20030000 { + compatible = "rockchip,rk2928-pwm"; + reg = <0x20030000 0x10>; + clocks = <&cru PCLK_PWM01>; + #pwm-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-samsung.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-samsung.txt new file mode 100644 index 0000000000000000000000000000000000000000..5538de9c20077566c4dec8243fcba0f78778f4fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-samsung.txt @@ -0,0 +1,51 @@ +* Samsung PWM timers + +Samsung SoCs contain PWM timer blocks which can be used for system clock source +and clock event timers, as well as to drive SoC outputs with PWM signal. Each +PWM timer block provides 5 PWM channels (not all of them can drive physical +outputs - see SoC and board manual). + +Be aware that the clocksource driver supports only uniprocessor systems. + +Required properties: +- compatible : should be one of following: + samsung,s3c2410-pwm - for 16-bit timers present on S3C24xx SoCs + samsung,s3c6400-pwm - for 32-bit timers present on S3C64xx SoCs + samsung,s5p6440-pwm - for 32-bit timers present on S5P64x0 SoCs + samsung,s5pc100-pwm - for 32-bit timers present on S5PC100, S5PV210, + Exynos4210 rev0 SoCs + samsung,exynos4210-pwm - for 32-bit timers present on Exynos4210, + Exynos4x12, Exynos5250 and Exynos5420 SoCs +- reg: base address and size of register area +- interrupts: list of timer interrupts (one interrupt per timer, starting at + timer 0) +- clock-names: should contain all following required clock names: + - "timers" - PWM base clock used to generate PWM signals, + and any subset of following optional clock names: + - "pwm-tclk0" - first external PWM clock source, + - "pwm-tclk1" - second external PWM clock source. + Note that not all IP variants allow using all external clock sources. + Refer to SoC documentation to learn which clock source configurations + are available. +- clocks: should contain clock specifiers of all clocks, which input names + have been specified in clock-names property, in same order. +- #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. The only third cell flag supported by this binding is + PWM_POLARITY_INVERTED. + +Optional properties: +- samsung,pwm-outputs: list of PWM channels used as PWM outputs on particular + platform - an array of up to 5 elements being indices of PWM channels + (from 0 to 4), the order does not matter. + +Example: + pwm@7f006000 { + compatible = "samsung,s3c6400-pwm"; + reg = <0x7f006000 0x1000>; + interrupt-parent = <&vic0>; + interrupts = <23>, <24>, <25>, <27>, <28>; + clocks = <&clock 67>; + clock-names = "timers"; + samsung,pwm-outputs = <0>, <1>; + #pwm-cells = <3>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-st.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..19fce774cafad1773cf4acc499ae1fff072d4c28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-st.txt @@ -0,0 +1,43 @@ +STMicroelectronics PWM driver bindings +-------------------------------------- + +Required parameters: +- compatible : "st,pwm" +- #pwm-cells : Number of cells used to specify a PWM. First cell + specifies the per-chip index of the PWM to use and the + second cell is the period in nanoseconds - fixed to 2 + for STiH41x. +- reg : Physical base address and length of the controller's + registers. +- pinctrl-names: Set to "default". +- pinctrl-0: List of phandles pointing to pin configuration nodes + for PWM module. + For Pinctrl properties, please refer to [1]. +- clock-names: Valid entries are "pwm" and/or "capture". +- clocks: phandle of the clock used by the PWM module. + For Clk properties, please refer to [2]. +- interrupts: IRQ for the Capture device + +Optional properties: +- st,pwm-num-chan: Number of available PWM channels. Default is 0. +- st,capture-num-chan: Number of available Capture channels. Default is 0. + +[1] Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +[2] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Example: + +pwm1: pwm@fe510000 { + compatible = "st,pwm"; + reg = <0xfe510000 0x68>; + #pwm-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1_chan0_default + &pinctrl_pwm1_chan1_default + &pinctrl_pwm1_chan2_default + &pinctrl_pwm1_chan3_default>; + clocks = <&clk_sysin>; + clock-names = "pwm"; + st,pwm-num-chan = <4>; + st,capture-num-chan = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-stm32-lp.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-stm32-lp.txt new file mode 100644 index 0000000000000000000000000000000000000000..bd23302e84becbb255ab567be8da7a9489ad9184 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-stm32-lp.txt @@ -0,0 +1,27 @@ +STMicroelectronics STM32 Low-Power Timer PWM + +STM32 Low-Power Timer provides single channel PWM. + +Must be a sub-node of an STM32 Low-Power Timer device tree node. +See ../mfd/stm32-lptimer.txt for details about the parent node. + +Required parameters: +- compatible: Must be "st,stm32-pwm-lp". +- #pwm-cells: Should be set to 3. This PWM chip uses the default 3 cells + bindings defined in pwm.txt. + +Optional properties: +- pinctrl-names: Set to "default". +- pinctrl-0: Phandle pointing to pin configuration node for PWM. + +Example: + timer@40002400 { + compatible = "st,stm32-lptimer"; + ... + pwm { + compatible = "st,stm32-pwm-lp"; + #pwm-cells = <3>; + pinctrl-names = "default"; + pinctrl-0 = <&lppwm1_pins>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-stm32.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-stm32.txt new file mode 100644 index 0000000000000000000000000000000000000000..3e6d55018d7ac40d8484e60e9566dedaff38e30d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-stm32.txt @@ -0,0 +1,35 @@ +STMicroelectronics STM32 Timers PWM bindings + +Must be a sub-node of an STM32 Timers device tree node. +See ../mfd/stm32-timers.txt for details about the parent node. + +Required parameters: +- compatible: Must be "st,stm32-pwm". +- pinctrl-names: Set to "default". +- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module. + For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt + +Optional parameters: +- st,breakinput: One or two to describe break input configurations. + "index" indicates on which break input (0 or 1) the configuration + should be applied. + "level" gives the active level (0=low or 1=high) of the input signal + for this configuration. + "filter" gives the filtering value to be applied. + +Example: + timers@40010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32-timers"; + reg = <0x40010000 0x400>; + clocks = <&rcc 0 160>; + clock-names = "int"; + + pwm { + compatible = "st,stm32-pwm"; + pinctrl-0 = <&pwm1_pins>; + pinctrl-names = "default"; + st,breakinput = <0 1 5>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-sun4i.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-sun4i.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a1affbff45ecb81e371e14355045c6986100b3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-sun4i.txt @@ -0,0 +1,24 @@ +Allwinner sun4i and sun7i SoC PWM controller + +Required properties: + - compatible: should be one of: + - "allwinner,sun4i-a10-pwm" + - "allwinner,sun5i-a10s-pwm" + - "allwinner,sun5i-a13-pwm" + - "allwinner,sun7i-a20-pwm" + - "allwinner,sun8i-h3-pwm" + - "allwinner,sun50i-a64-pwm", "allwinner,sun5i-a13-pwm" + - "allwinner,sun50i-h5-pwm", "allwinner,sun5i-a13-pwm" + - reg: physical base address and length of the controller's registers + - #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. + - clocks: From common clock binding, handle to the parent clock. + +Example: + + pwm: pwm@1c20e00 { + compatible = "allwinner,sun7i-a20-pwm"; + reg = <0x01c20e00 0xc>; + clocks = <&osc24M>; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tiecap.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tiecap.txt new file mode 100644 index 0000000000000000000000000000000000000000..06a363d9ccef9069124ae813bfb449d8cab182c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tiecap.txt @@ -0,0 +1,50 @@ +TI SOC ECAP based APWM controller + +Required properties: +- compatible: Must be "ti,-ecap". + for am33xx - compatible = "ti,am3352-ecap", "ti,am33xx-ecap"; + for am4372 - compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; + for da850 - compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; + for dra746 - compatible = "ti,dra746-ecap", "ti,am3352-ecap"; + for 66ak2g - compatible = "ti,k2g-ecap", "ti,am3352-ecap"; +- #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. The PWM channel index ranges from 0 to 4. The only third + cell flag supported by this binding is PWM_POLARITY_INVERTED. +- reg: physical base address and size of the registers map. + +Optional properties: +- clocks: Handle to the ECAP's functional clock. +- clock-names: Must be set to "fck". + +Example: + +ecap0: ecap@48300100 { /* ECAP on am33xx */ + compatible = "ti,am3352-ecap", "ti,am33xx-ecap"; + #pwm-cells = <3>; + reg = <0x48300100 0x80>; + clocks = <&l4ls_gclk>; + clock-names = "fck"; +}; + +ecap0: ecap@48300100 { /* ECAP on am4372 */ + compatible = "ti,am4372-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; + #pwm-cells = <3>; + reg = <0x48300100 0x80>; + ti,hwmods = "ecap0"; + clocks = <&l4ls_gclk>; + clock-names = "fck"; +}; + +ecap0: ecap@1f06000 { /* ECAP on da850 */ + compatible = "ti,da850-ecap", "ti,am3352-ecap", "ti,am33xx-ecap"; + #pwm-cells = <3>; + reg = <0x1f06000 0x80>; +}; + +ecap0: ecap@4843e100 { + compatible = "ti,dra746-ecap", "ti,am3352-ecap"; + #pwm-cells = <3>; + reg = <0x4843e100 0x80>; + clocks = <&l4_root_clk_div>; + clock-names = "fck"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tiehrpwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tiehrpwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..944fe356bb4569600619b3434dafeddadd164b18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tiehrpwm.txt @@ -0,0 +1,49 @@ +TI SOC EHRPWM based PWM controller + +Required properties: +- compatible: Must be "ti,-ehrpwm". + for am33xx - compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; + for am4372 - compatible = "ti,am4372-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm"; + for da850 - compatible = "ti,da850-ehrpwm", "ti-am3352-ehrpwm", "ti,am33xx-ehrpwm"; + for dra746 - compatible = "ti,dra746-ehrpwm", "ti-am3352-ehrpwm"; +- #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. The only third cell flag supported by this binding is + PWM_POLARITY_INVERTED. +- reg: physical base address and size of the registers map. + +Optional properties: +- clocks: Handle to the PWM's time-base and functional clock. +- clock-names: Must be set to "tbclk" and "fck". + +Example: + +ehrpwm0: pwm@48300200 { /* EHRPWM on am33xx */ + compatible = "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; + #pwm-cells = <3>; + reg = <0x48300200 0x100>; + clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; + clock-names = "tbclk", "fck"; +}; + +ehrpwm0: pwm@48300200 { /* EHRPWM on am4372 */ + compatible = "ti,am4372-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; + #pwm-cells = <3>; + reg = <0x48300200 0x80>; + clocks = <&ehrpwm0_tbclk>, <&l4ls_gclk>; + clock-names = "tbclk", "fck"; + ti,hwmods = "ehrpwm0"; +}; + +ehrpwm0: pwm@1f00000 { /* EHRPWM on da850 */ + compatible = "ti,da850-ehrpwm", "ti,am3352-ehrpwm", "ti,am33xx-ehrpwm"; + #pwm-cells = <3>; + reg = <0x1f00000 0x2000>; +}; + +ehrpwm0: pwm@4843e200 { /* EHRPWM on dra746 */ + compatible = "ti,dra746-ehrpwm", "ti,am3352-ehrpwm"; + #pwm-cells = <3>; + reg = <0x4843e200 0x80>; + clocks = <&ehrpwm0_tbclk>, <&l4_root_clk_div>; + clock-names = "tbclk", "fck"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tipwmss.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tipwmss.txt new file mode 100644 index 0000000000000000000000000000000000000000..4633697fbda1f53a1e897663bfc53cf602cb8ad9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-tipwmss.txt @@ -0,0 +1,58 @@ +TI SOC based PWM Subsystem + +Required properties: +- compatible: Must be "ti,-pwmss". + for am33xx - compatible = "ti,am33xx-pwmss"; + for am4372 - compatible = "ti,am4372-pwmss","ti,am33xx-pwmss"; + for dra746 - compatible = "ti,dra746-pwmss", "ti,am33xx-pwmss" + +- reg: physical base address and size of the registers map. +- address-cells: Specify the number of u32 entries needed in child nodes. + Should set to 1. +- size-cells: specify number of u32 entries needed to specify child nodes size + in reg property. Should set to 1. +- ranges: describes the address mapping of a memory-mapped bus. Should set to + physical address map of child's base address, physical address within + parent's address space and length of the address map. For am33xx, + 3 set of child register maps present, ECAP register space, EQEP + register space, EHRPWM register space. + +Also child nodes should also populated under PWMSS DT node. + +Example: +epwmss0: epwmss@48300000 { /* PWMSS for am33xx */ + compatible = "ti,am33xx-pwmss"; + reg = <0x48300000 0x10>; + ti,hwmods = "epwmss0"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x48300100 0x48300100 0x80 /* ECAP */ + 0x48300180 0x48300180 0x80 /* EQEP */ + 0x48300200 0x48300200 0x80>; /* EHRPWM */ + + /* child nodes go here */ +}; + +epwmss0: epwmss@48300000 { /* PWMSS for am4372 */ + compatible = "ti,am4372-pwmss","ti,am33xx-pwmss" + reg = <0x48300000 0x10>; + ti,hwmods = "epwmss0"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x48300100 0x48300100 0x80 /* ECAP */ + 0x48300180 0x48300180 0x80 /* EQEP */ + 0x48300200 0x48300200 0x80>; /* EHRPWM */ + + /* child nodes go here */ +}; + +epwmss0: epwmss@4843e000 { /* PWMSS for DRA7xx */ + compatible = "ti,dra746-pwmss", "ti,am33xx-pwmss"; + reg = <0x4843e000 0x30>; + ti,hwmods = "epwmss0"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* child nodes go here */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-zx.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-zx.txt new file mode 100644 index 0000000000000000000000000000000000000000..a6bcc75c9164eb95786ab18c4b01581e83c89946 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm-zx.txt @@ -0,0 +1,22 @@ +ZTE ZX PWM controller + +Required properties: + - compatible: Should be "zte,zx296718-pwm". + - reg: Physical base address and length of the controller's registers. + - clocks : The phandle and specifier referencing the controller's clocks. + - clock-names: "pclk" for PCLK, "wclk" for WCLK to the PWM controller. The + PCLK is for register access, while WCLK is the reference clock for + calculating period and duty cycles. + - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Example: + + pwm: pwm@1439000 { + compatible = "zte,zx296718-pwm"; + reg = <0x1439000 0x1000>; + clocks = <&lsp1crm LSP1_PWM_PCLK>, + <&lsp1crm LSP1_PWM_WCLK>; + clock-names = "pclk", "wclk"; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..8556263b85026af7943d957659b74bc1ae2c0d23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pwm.txt @@ -0,0 +1,69 @@ +Specifying PWM information for devices +====================================== + +1) PWM user nodes +----------------- + +PWM users should specify a list of PWM devices that they want to use +with a property containing a 'pwm-list': + + pwm-list ::= [pwm-list] + single-pwm ::= + pwm-phandle : phandle to PWM controller node + pwm-specifier : array of #pwm-cells specifying the given PWM + (controller specific) + +PWM properties should be named "pwms". The exact meaning of each pwms +property must be documented in the device tree binding for each device. +An optional property "pwm-names" may contain a list of strings to label +each of the PWM devices listed in the "pwms" property. If no "pwm-names" +property is given, the name of the user node will be used as fallback. + +Drivers for devices that use more than a single PWM device can use the +"pwm-names" property to map the name of the PWM device requested by the +pwm_get() call to an index into the list given by the "pwms" property. + +The following example could be used to describe a PWM-based backlight +device: + + pwm: pwm { + #pwm-cells = <2>; + }; + + [...] + + bl: backlight { + pwms = <&pwm 0 5000000>; + pwm-names = "backlight"; + }; + +Note that in the example above, specifying the "pwm-names" is redundant +because the name "backlight" would be used as fallback anyway. + +pwm-specifier typically encodes the chip-relative PWM number and the PWM +period in nanoseconds. + +Optionally, the pwm-specifier can encode a number of flags (defined in +) in a third cell: +- PWM_POLARITY_INVERTED: invert the PWM signal polarity + +Example with optional PWM specifier for inverse polarity + + bl: backlight { + pwms = <&pwm 0 5000000 PWM_POLARITY_INVERTED>; + pwm-names = "backlight"; + }; + +2) PWM controller nodes +----------------------- + +PWM controller nodes must specify the number of cells used for the +specifier using the '#pwm-cells' property. + +An example PWM controller might look like this: + + pwm: pwm@7000a000 { + compatible = "nvidia,tegra20-pwm"; + reg = <0x7000a000 0x100>; + #pwm-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/pxa-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/pxa-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ae9f1e3c33896b3f305de8d727b9b859a706b11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/pxa-pwm.txt @@ -0,0 +1,30 @@ +Marvell PWM controller + +Required properties: +- compatible: should be one or more of: + - "marvell,pxa250-pwm" + - "marvell,pxa270-pwm" + - "marvell,pxa168-pwm" + - "marvell,pxa910-pwm" +- reg: Physical base address and length of the registers used by the PWM channel + Note that one device instance must be created for each PWM that is used, so the + length covers only the register window for one PWM output, not that of the + entire PWM controller. Currently length is 0x10 for all supported devices. +- #pwm-cells: Should be 1. This cell is used to specify the period in + nanoseconds. + +Example PWM device node: + +pwm0: pwm@40b00000 { + compatible = "marvell,pxa250-pwm"; + reg = <0x40b00000 0x10>; + #pwm-cells = <1>; +}; + +Example PWM client node: + +backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 5000000>; + ... +} diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/renesas,pwm-rcar.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/renesas,pwm-rcar.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1ef6afbe3a74a89d9040b9d6642cd2c22aa2a0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/renesas,pwm-rcar.txt @@ -0,0 +1,35 @@ +* Renesas R-Car PWM Timer Controller + +Required Properties: +- compatible: should be "renesas,pwm-rcar" and one of the following. + - "renesas,pwm-r8a7743": for RZ/G1M + - "renesas,pwm-r8a7745": for RZ/G1E + - "renesas,pwm-r8a7778": for R-Car M1A + - "renesas,pwm-r8a7779": for R-Car H1 + - "renesas,pwm-r8a7790": for R-Car H2 + - "renesas,pwm-r8a7791": for R-Car M2-W + - "renesas,pwm-r8a7794": for R-Car E2 + - "renesas,pwm-r8a7795": for R-Car H3 + - "renesas,pwm-r8a7796": for R-Car M3-W + - "renesas,pwm-r8a77965": for R-Car M3-N + - "renesas,pwm-r8a77990": for R-Car E3 + - "renesas,pwm-r8a77995": for R-Car D3 +- reg: base address and length of the registers block for the PWM. +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. +- clocks: clock phandle and specifier pair. +- pinctrl-0: phandle, referring to a default pin configuration node. +- pinctrl-names: Set to "default". + +Example: R8A7743 (RZ/G1M) PWM Timer node + + pwm0: pwm@e6e30000 { + compatible = "renesas,pwm-r8a7743", "renesas,pwm-rcar"; + reg = <0 0xe6e30000 0 0x8>; + clocks = <&cpg CPG_MOD 523>; + power-domains = <&sysc R8A7743_PD_ALWAYS_ON>; + resets = <&cpg 523>; + #pwm-cells = <2>; + pinctrl-0 = <&pwm0_pins>; + pinctrl-names = "default"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/renesas,tpu-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/renesas,tpu-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..d53a16715da6ac33dea19a4a66ad38310feacc95 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/renesas,tpu-pwm.txt @@ -0,0 +1,29 @@ +* Renesas R-Car Timer Pulse Unit PWM Controller + +Required Properties: + + - compatible: should be one of the following. + - "renesas,tpu-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible PWM controller. + - "renesas,tpu-r8a7740": for R8A7740 (R-Mobile A1) compatible PWM controller. + - "renesas,tpu-r8a7743": for R8A7743 (RZ/G1M) compatible PWM controller. + - "renesas,tpu-r8a7745": for R8A7745 (RZ/G1E) compatible PWM controller. + - "renesas,tpu-r8a7790": for R8A7790 (R-Car H2) compatible PWM controller. + - "renesas,tpu": for generic R-Car and RZ/G1 TPU PWM controller. + + - reg: Base address and length of each memory resource used by the PWM + controller hardware module. + + - #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. The only third cell flag supported by this binding is + PWM_POLARITY_INVERTED. + +Please refer to pwm.txt in this directory for details of the common PWM bindings +used by client devices. + +Example: R8A7740 (R-Mobile A1) TPU controller node + + tpu: pwm@e6600000 { + compatible = "renesas,tpu-r8a7740", "renesas,tpu"; + reg = <0xe6600000 0x148>; + #pwm-cells = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/spear-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/spear-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..b486de2c3fe31b92c128e1bef22a4c4f9eff6e66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/spear-pwm.txt @@ -0,0 +1,17 @@ +== ST SPEAr SoC PWM controller == + +Required properties: +- compatible: should be one of: + - "st,spear320-pwm" + - "st,spear1340-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. + +Example: + + pwm: pwm@a8000000 { + compatible ="st,spear320-pwm"; + reg = <0xa8000000 0x1000>; + #pwm-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/st,stmpe-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/st,stmpe-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb209646bf132c555e1e2f9111683a2fd14254fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/st,stmpe-pwm.txt @@ -0,0 +1,18 @@ +== ST STMPE PWM controller == + +This is a PWM block embedded in the ST Microelectronics STMPE +(ST Multi-Purpose Expander) chips. The PWM is registered as a +subdevices of the STMPE MFD device. + +Required properties: +- compatible: should be: + - "st,stmpe-pwm" +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. + +Example: + +pwm0: pwm { + compatible = "st,stmpe-pwm"; + #pwm-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/ti,twl-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/ti,twl-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..4e32bee11201b6a968ef89f3dc547df45c0fc47b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/ti,twl-pwm.txt @@ -0,0 +1,17 @@ +Texas Instruments TWL series PWM drivers + +Supported PWMs: +On TWL4030 series: PWM1 and PWM2 +On TWL6030 series: PWM0 and PWM1 + +Required properties: +- compatible: "ti,twl4030-pwm" or "ti,twl6030-pwm" +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. + +Example: + +twl_pwm: pwm { + compatible = "ti,twl6030-pwm"; + #pwm-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/ti,twl-pwmled.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/ti,twl-pwmled.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f4b460907827909f012ec4e36ddbbaf44cc1369 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/ti,twl-pwmled.txt @@ -0,0 +1,17 @@ +Texas Instruments TWL series PWM drivers connected to LED terminals + +Supported PWMs: +On TWL4030 series: PWMA and PWMB (connected to LEDA and LEDB terminals) +On TWL6030 series: LED PWM (mainly used as charging indicator LED) + +Required properties: +- compatible: "ti,twl4030-pwmled" or "ti,twl6030-pwmled" +- #pwm-cells: should be 2. See pwm.txt in this directory for a description of + the cells format. + +Example: + +twl_pwmled: pwmled { + compatible = "ti,twl6030-pwmled"; + #pwm-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/pwm/vt8500-pwm.txt b/arch/arm64/boot/dts/vendor/bindings/pwm/vt8500-pwm.txt new file mode 100644 index 0000000000000000000000000000000000000000..a76390e6df2efb63bafbd6376b56557eb89958c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/pwm/vt8500-pwm.txt @@ -0,0 +1,18 @@ +VIA/Wondermedia VT8500/WM8xxx series SoC PWM controller + +Required properties: +- compatible: should be "via,vt8500-pwm" +- reg: physical base address and length of the controller's registers +- #pwm-cells: should be 3. See pwm.txt in this directory for a description of + the cells format. The only third cell flag supported by this binding is + PWM_POLARITY_INVERTED. +- clocks: phandle to the PWM source clock + +Example: + +pwm1: pwm@d8220000 { + #pwm-cells = <3>; + compatible = "via,vt8500-pwm"; + reg = <0xd8220000 0x1000>; + clocks = <&clkpwm>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/qbt_handler/qbt_handler.txt b/arch/arm64/boot/dts/vendor/bindings/qbt_handler/qbt_handler.txt new file mode 100644 index 0000000000000000000000000000000000000000..168aa24fd9a7393ef4b7cdb0512ab3896638db57 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/qbt_handler/qbt_handler.txt @@ -0,0 +1,35 @@ +Qualcomm Technologies, Inc. QBT_HANDLER Specific Bindings + +QBT is a fingerprint sensor ASIC capable of performing fingerprint image scans +and detecting finger presence on the sensor using programmable firmware. + +======================= +Required Node Structure +======================= + +- compatible + Usage: required + Value type: + Definition: "qcom,qbt-handler". + +- qcom,ipc-gpio + Usage: required + Value type: + Definition: phandle for GPIO to be used for IPC. + +- qcom,finger-detect-gpio + Usage: required + Value type: + Definition: phandle for GPIO to be used for finger detect. + +======= +Example +======= + +qcom,qbt_handler { + compatible = "qcom,qbt-handler"; + qcom,ipc-gpio = <&tlmm 23 0>; + pinctrl-names = "default"; + pinctrl-0 = <&key_home_default>; + qcom,finger-detect-gpio = <&pm8150_gpios 1 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-cdsp-loader.txt b/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-cdsp-loader.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e0d4f250be855cb5dcf9acef0a0823aa2b6f2bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-cdsp-loader.txt @@ -0,0 +1,16 @@ +Qualcomm Technologies, Inc. CDSP Loader Driver + +msm-cdsp-loader driver implements a mechanism to load the Compute DSP firmware images. + +Required properties: + + - compatible: This must be "qcom,msm-cdsp-loader". + - qcom,proc-img-to-load: CDSP firmware name, must be "cdsp". + +Example: + The following is an example: + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-fastrpc.txt b/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-fastrpc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d839212bd658feab20e51cfb82e15383ce49f4be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-fastrpc.txt @@ -0,0 +1,100 @@ +Qualcomm Technologies, Inc. FastRPC Driver + +The MSM FastRPC driver implements an IPC (Inter-Processor Communication) +mechanism that allows for clients to transparently make remote method +invocations across DSP and APPS boundaries. This enables developers +to offload tasks to the DSP and free up the application processor for +other tasks. + +Required properties: +- compatible : Must be one of "qcom,msm-fastrpc-adsp" or "qcom,msm-fastrpc-compute" + +Optional properties: +- qcom,rpc-latency-us : FastRPC QoS latency vote +- qcom,adsp-remoteheap-vmid : FastRPC remote heap VMID list +- qcom,secure-context-bank : Bool indicating secure FastRPC context bank. +- qcom,fastrpc-legacy-remote-heap : Bool indicating hypervisor is not supported. +- qcom,fastrpc-adsp-audio-pdr : Flag to enable ADSP Audio PDR +- qcom,secure-domains : FastRPC secure domain configuration +- qcom,fastrpc-adsp-sensors-pdr : Flag to enable Sensors PDR + +Optional subnodes: +- qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context banks +- qcom,msm-fastrpc-rpmsg : Child node for rpmsg instead of glink for IPC + +Subnode Required properties: +- compatible : Must be "qcom,msm-fastrpc-compute-cb" +- label : Label describing the channel this context bank belongs to +- iommus : A list of phandle and IOMMU specifier pairs that describe the + IOMMU master interfaces of the device +- dma-coherent : A flag marking a context bank as I/O coherent +- shared-cb : A value indicating how many fastrpc sessions can share a + context bank + +Example: + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,fastrpc-rpmsg; + qcom,rpc-latency-us = <235>; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-sensors-pdr; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + intents = <0x64 64>; + }; + + qcom,msm_fastrpc_compute_cb_1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1401 0x0>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb_2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x1402 0x0>; + shared-cb = <5>; + }; + }; + +Legacy SMMU v1/v2: + +Required properties: +- compatible : Must be "qcom,msm-fastprc-legacy-compute-cb" + +Required subnode: +- qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context + banks + +Required subnode properties: +- qcom,adsp-shared-phandle : phandle that describe the context bank handle +- qcom,adsp-shared-sids : A list of SID associated with the context bank +- qcom,virtual-addr-pool : Virtual address range that the context bank + will be using + +Example: + qcom,adsprpc_domains { + compatible = "qcom,msm-fastrpc-legacy-compute-cb"; + qcom,msm_fastrpc_compute_cb { + qcom,adsp-shared-phandle = <&adsp_shared>; + qcom,adsp-shared-sids = <0x8 0x9>; + qcom,virtual-addr-pool = <0x80000000 0x7FFFFFFF>; + }; + }; + +Remote Heap: + +Required properties: +- compatible : Must be "qcom,msm-adsprpc-mem-region" +- memory-region : CMA region which is owned by this device +- restrict-access : Blocking vote for hyp_assign_phys function call + +Example: + qcom,adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-ssc-sensors.txt b/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-ssc-sensors.txt new file mode 100644 index 0000000000000000000000000000000000000000..a77c0b0fb6b0979a56531319458df4b5bed10442 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/qdsp/msm-ssc-sensors.txt @@ -0,0 +1,21 @@ +Qualcomm Technologies, Inc. SSC Driver + +msm-ssc-sensors driver implements the mechanism that allows to load SLPI firmware images. + +Required properties: + + - compatible: This must be "qcom,msm-ssc-sensors". + +Optional properties: + + - qcom,firmware-name: SLPI firmware name, must be "slpi" or "slpi_v1" or "slpi_v2" + Firmware name is not required, if sensors driver is sharing processor for execution. + + +Example: + The following for sdm845. + + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + qcom,firmware-name = "slpi"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/qseecom/qseecom.txt b/arch/arm64/boot/dts/vendor/bindings/qseecom/qseecom.txt new file mode 100644 index 0000000000000000000000000000000000000000..8200afda6779d653d07c3dd890e9846d66cf8ba9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/qseecom/qseecom.txt @@ -0,0 +1,85 @@ +* QSEECOM (QTI Secure Execution Environment Communicator) + +Required properties: +- compatible : Should be "qcom,qseecom" +- reg : should contain memory region address reserved for loading secure apps. +- qcom,disk-encrypt-pipe-pair : indicates what CE HW pipe pair is used for disk encryption +- qcom,file-encrypt-pipe-pair : indicates what CE HW pipe pair is used for file encryption +- qcom,support-multiple-ce-hw-instance : indicates if multicore CE support is supported. +- qcom,hlos-num-ce-hw-instances : indicates number of CE HW instances hlos can use. +- qcom,hlos-ce-hw-instance : indicates what CE HW is used by HLOS crypto driver +- qcom,qsee-ce-hw-instance : indicates what CE HW is used by secure domain (TZ) crypto driver +- qcom, msm_bus,name: Should be "qseecom-noc" +- qcom, msm_bus,num_cases: Depends on the use cases for bus scaling +- qcom, msm_bus,num_paths: The paths for source and destination ports +- qcom, msm_bus,vectors: Vectors for bus topology. +- qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target. +- qcom,full-disk-encrypt-info : Vectors defining full disk encryption unit, crypto engine, pipe pair configuration in +- qcom,per-file-encrypt-info : Vectors defining per file encryption unit, crypto engine, pipe pair configuration in + +Optional properties: + - qcom,support-bus-scaling : indicates if driver support scaling the bus for crypto operation. + - qcom,support-fde : indicates if driver support key managing for full disk encryption feature. + - qcom,support-pfe : indicates if driver support key managing for per file encryption feature. + - qcom,no-clock-support : indicates clocks are not handled by qseecom (could be handled by RPM) + - qcom,appsbl-qseecom-support : indicates if there is qseecom support in appsbootloader + - vdd-hba-supply : handle for fixed power regulator + - qcom,qsee-reentrancy-support: indicates the qsee reentrancy phase supported by the target + - qcom,commonlib64-loaded-by-uefi: indicates commonlib64 is loaded by uefi already + - qcom,fde-key-size: indicates which FDE key size is used in device. + +Example: + qcom,qseecom@7f00000 { + compatible = "qcom,qseecom"; + reg = <0x7f00000 0x500000>; + reg-names = "secapp-region"; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,file-encrypt-pipe-pair = <0>; + qcom,support-multiple-ce-hw-instance; + qcom,hlos-num-ce-hw-instances = <2>; + qcom,hlos-ce-hw-instance = <1 2>; + qcom,qsee-ce-hw-instance = <0>; + qcom,support-fde; + qcom,support-pfe; + qcom,msm_bus,name = "qseecom-noc"; + qcom,msm_bus,num_cases = <4>; + qcom,msm_bus,active_only = <0>; + qcom,msm_bus,num_paths = <1>; + qcom,no-clock-support; + qcom,appsbl-qseecom-support; + qcom,fde-key-size; + qcom,msm_bus,vectors = + <55 512 0 0>, + <55 512 3936000000 393600000>, + <55 512 3936000000 393600000>, + <55 512 3936000000 393600000>; + qcom,ce-opp-freq = <100000000>; + vdd-hba-supply = <&gdsc_ufs>; + }; + +Example: The following dts setup is the same as the example above. + + qcom,qseecom@7f00000 { + compatible = "qcom,qseecom"; + reg = <0x7f00000 0x500000>; + reg-names = "secapp-region"; + qcom,support-fde; + qcom,full-disk-encrypt-info = <0 1 2>, <0 2 2>; + qcom,support-pfe; + qcom,per-file-encrypt-info = <0 1 0>, <0 2 0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,msm_bus,name = "qseecom-noc"; + qcom,msm_bus,num_cases = <4>; + qcom,msm_bus,active_only = <0>; + qcom,msm_bus,num_paths = <1>; + qcom,no-clock-support; + qcom,appsbl-qseecom-support; + qcom,fde-key-size; + qcom,msm_bus,vectors = + <55 512 0 0>, + <55 512 3936000000 393600000>, + <55 512 3936000000 393600000>, + <55 512 3936000000 393600000>; + qcom,ce-opp-freq = <100000000>; + vdd-hba-supply = <&gdsc_ufs>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regmap/regmap.txt b/arch/arm64/boot/dts/vendor/bindings/regmap/regmap.txt new file mode 100644 index 0000000000000000000000000000000000000000..873096be0278b769e596e3fd16259d807e6d6859 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regmap/regmap.txt @@ -0,0 +1,29 @@ +Devicetree binding for regmap + +Optional properties: + + little-endian, + big-endian, + native-endian: See common-properties.txt for a definition + +Note: +Regmap defaults to little-endian register access on MMIO based +devices, this is by far the most common setting. On CPU +architectures that typically run big-endian operating systems +(e.g. PowerPC), registers can be defined as big-endian and must +be marked that way in the devicetree. + +On SoCs that can be operated in both big-endian and little-endian +modes, with a single hardware switch controlling both the endianness +of the CPU and a byteswap for MMIO registers (e.g. many Broadcom MIPS +chips), "native-endian" is used to allow using the same device tree +blob in both cases. + +Examples: +Scenario 1 : a register set in big-endian mode. +dev: dev@40031000 { + compatible = "syscon"; + reg = <0x40031000 0x1000>; + big-endian; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/88pg86x.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/88pg86x.txt new file mode 100644 index 0000000000000000000000000000000000000000..13b7f49a2ea808e1685fce863c9435ad83a5e526 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/88pg86x.txt @@ -0,0 +1,22 @@ +Marvell 88PG867/88PG868 voltage regulators + +Required properties: +- compatible: one of "marvell,88pg867", "marvell,88pg868"; +- reg: I2C slave address. + +Optional subnodes for regulators: "buck1", "buck2", using common regulator +bindings given in . + +Example: + + pg868@19 { + compatible = "marvell,88pg868"; + reg = <0x19>; + + vcpu: buck1 { + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1350000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/88pm800.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/88pm800.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8a54c2a582159d8940a81860095944701b19aa3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/88pm800.txt @@ -0,0 +1,38 @@ +Marvell 88PM800 regulator + +Required properties: +- compatible: "marvell,88pm800" +- reg: I2C slave address +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name (or the deprecated + regulator-compatible property if present), with valid values listed below. + The content of each sub-node is defined by the standard binding for + regulators; see regulator.txt. + +The valid names for regulators are: + + buck1, buck2, buck3, buck4, buck5, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, + ldo8, ldo9, ldo10, ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19 + +Example: + + pmic: 88pm800@31 { + compatible = "marvell,88pm800"; + reg = <0x31>; + + regulators { + buck1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3950000>; + regulator-boot-on; + regulator-always-on; + }; + ldo1 { + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <15000000>; + regulator-boot-on; + regulator-always-on; + }; +... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/88pm860x.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/88pm860x.txt new file mode 100644 index 0000000000000000000000000000000000000000..1267b3e1a2cca17436442f277b850ab4635fa1eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/88pm860x.txt @@ -0,0 +1,30 @@ +Marvell 88PM860x regulator + +Required properties: +- compatible: "marvell,88pm860x" +- reg: I2C slave address +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the regulator-compatible + property, with valid values listed below. + +Example: + + pmic: 88pm860x@34 { + compatible = "marvell,88pm860x"; + reg = <0x34>; + + regulators { + BUCK1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + BUCK3 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/act8865-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/act8865-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ae9f1088845ba4fecf43b90102256317f4b71e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/act8865-regulator.txt @@ -0,0 +1,94 @@ +ACT88xx regulators +------------------- + +Required properties: +- compatible: "active-semi,act8846" or "active-semi,act8865" or "active-semi,act8600" +- reg: I2C slave address + +Optional properties: +- system-power-controller: Telling whether or not this pmic is controlling + the system power. See Documentation/devicetree/bindings/power/power-controller.txt . +- active-semi,vsel-high: Indicates the VSEL pin is high. + If this property is missing, assume the VSEL pin is low(0). + +Optional input supply properties: +- for act8600: + - vp1-supply: The input supply for DCDC_REG1 + - vp2-supply: The input supply for DCDC_REG2 + - vp3-supply: The input supply for DCDC_REG3 + - inl-supply: The input supply for LDO_REG5, LDO_REG6, LDO_REG7 and LDO_REG8 + SUDCDC_REG4, LDO_REG9 and LDO_REG10 do not have separate supplies. +- for act8846: + - vp1-supply: The input supply for REG1 + - vp2-supply: The input supply for REG2 + - vp3-supply: The input supply for REG3 + - vp4-supply: The input supply for REG4 + - inl1-supply: The input supply for REG5, REG6 and REG7 + - inl2-supply: The input supply for REG8 and LDO_REG9 + - inl3-supply: The input supply for REG10, REG11 and REG12 +- for act8865: + - vp1-supply: The input supply for DCDC_REG1 + - vp2-supply: The input supply for DCDC_REG2 + - vp3-supply: The input supply for DCDC_REG3 + - inl45-supply: The input supply for LDO_REG1 and LDO_REG2 + - inl67-supply: The input supply for LDO_REG3 and LDO_REG4 + +Any standard regulator properties can be used to configure the single regulator. + +The valid names for regulators are: + - for act8846: + REG1, REG2, REG3, REG4, REG5, REG6, REG7, REG8, REG9, REG10, REG11, REG12 + - for act8865: + DCDC_REG1, DCDC_REG2, DCDC_REG3, LDO_REG1, LDO_REG2, LDO_REG3, LDO_REG4. + - for act8600: + DCDC_REG1, DCDC_REG2, DCDC_REG3, SUDCDC_REG4, LDO_REG5, LDO_REG6, LDO_REG7, + LDO_REG8, LDO_REG9, LDO_REG10, + +Example: +-------- + + i2c1: i2c@f0018000 { + pmic: act8865@5b { + compatible = "active-semi,act8865"; + reg = <0x5b>; + active-semi,vsel-high; + + regulators { + vcc_1v8_reg: DCDC_REG1 { + regulator-name = "VCC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vcc_1v2_reg: DCDC_REG2 { + regulator-name = "VCC_1V2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-suspend-mem-microvolt = <1150000>; + regulator-suspend-standby-microvolt = <1150000>; + regulator-always-on; + }; + + vcc_3v3_reg: DCDC_REG3 { + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vddana_reg: LDO_REG1 { + regulator-name = "VDDANA"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vddfuse_reg: LDO_REG2 { + regulator-name = "FUSE_2V5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/act8945a-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/act8945a-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac955dea00d16c50a89a75922672030dde122cbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/act8945a-regulator.txt @@ -0,0 +1,79 @@ +Device-Tree bindings for regulators of Active-semi ACT8945A Multi-Function Device + +Required properties: + - compatible: "active-semi,act8945a", please refer to ../mfd/act8945a.txt. + +Optional properties: +- active-semi,vsel-high: Indicates if the VSEL pin is set to logic-high. + If this property is missing, assume the VSEL pin is set to logic-low. + +Optional input supply properties: + - vp1-supply: The input supply for REG_DCDC1 + - vp2-supply: The input supply for REG_DCDC2 + - vp3-supply: The input supply for REG_DCDC3 + - inl45-supply: The input supply for REG_LDO1 and REG_LDO2 + - inl67-supply: The input supply for REG_LDO3 and REG_LDO4 + +Any standard regulator properties can be used to configure the single regulator. + +The valid names for regulators are: + REG_DCDC1, REG_DCDC2, REG_DCDC3, REG_LDO1, REG_LDO2, REG_LDO3, REG_LDO4. + +Example: + pmic@5b { + compatible = "active-semi,act8945a"; + reg = <0x5b>; + + active-semi,vsel-high; + + regulators { + vdd_1v35_reg: REG_DCDC1 { + regulator-name = "VDD_1V35"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + vdd_1v2_reg: REG_DCDC2 { + regulator-name = "VDD_1V2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + + vdd_3v3_reg: REG_DCDC3 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_fuse_reg: REG_LDO1 { + regulator-name = "VDD_FUSE"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vdd_3v3_lp_reg: REG_LDO2 { + regulator-name = "VDD_3V3_LP"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_led_reg: REG_LDO3 { + regulator-name = "VDD_LED"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_sdhc_1v8_reg: REG_LDO4 { + regulator-name = "VDD_SDHC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/anatop-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/anatop-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3106c72fbeaa1a862f85b49693490cd74457963 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/anatop-regulator.txt @@ -0,0 +1,40 @@ +Anatop Voltage regulators + +Required properties: +- compatible: Must be "fsl,anatop-regulator" +- regulator-name: A string used as a descriptive name for regulator outputs +- anatop-reg-offset: Anatop MFD register offset +- anatop-vol-bit-shift: Bit shift for the register +- anatop-vol-bit-width: Number of bits used in the register +- anatop-min-bit-val: Minimum value of this register +- anatop-min-voltage: Minimum voltage of this regulator +- anatop-max-voltage: Maximum voltage of this regulator + +Optional properties: +- anatop-delay-reg-offset: Anatop MFD step time register offset +- anatop-delay-bit-shift: Bit shift for the step time register +- anatop-delay-bit-width: Number of bits used in the step time register +- vin-supply: The supply for this regulator +- anatop-enable-bit: Regulator enable bit offset + +Any property defined as part of the core regulator +binding, defined in regulator.txt, can also be used. + +Example: + + regulator-vddpu { + compatible = "fsl,anatop-regulator"; + regulator-name = "vddpu"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + anatop-reg-offset = <0x140>; + anatop-vol-bit-shift = <9>; + anatop-vol-bit-width = <5>; + anatop-delay-reg-offset = <0x170>; + anatop-delay-bit-shift = <24>; + anatop-delay-bit-width = <2>; + anatop-min-bit-val = <1>; + anatop-min-voltage = <725000>; + anatop-max-voltage = <1300000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/arizona-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/arizona-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..443564d7784fdc8ebd66e0530ae9f06c22c1f646 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/arizona-regulator.txt @@ -0,0 +1,17 @@ +Cirrus Logic Arizona class audio SoCs + +These devices are audio SoCs with extensive digital capabilities and a range +of analogue I/O. + +This document lists regulator specific bindings, see the primary binding +document: + ../mfd/arizona.txt + +Optional properties: + - wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA + +Optional subnodes: + - ldo1 : Initial data for the LDO1 regulator, as covered in + Documentation/devicetree/bindings/regulator/regulator.txt + - micvdd : Initial data for the MICVDD regulator, as covered in + Documentation/devicetree/bindings/regulator/regulator.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/as3722-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/as3722-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..caad0c8a258d23097e712c8b040dea8ed203a922 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/as3722-regulator.txt @@ -0,0 +1,91 @@ +Regulator of AMS AS3722 PMIC. +Name of the regulator subnode must be "regulators". + +Optional properties: +-------------------- +The input supply of regulators are the optional properties on the +regulator node. The AS3722 is having 7 DCDC step-down regulators as +sd[0-6], 10 LDOs as ldo[0-7], ldo[9-11]. The input supply of these +regulators are provided through following properties: +vsup-sd2-supply: Input supply for SD2. +vsup-sd3-supply: Input supply for SD3. +vsup-sd4-supply: Input supply for SD4. +vsup-sd5-supply: Input supply for SD5. +vin-ldo0-supply: Input supply for LDO0. +vin-ldo1-6-supply: Input supply for LDO1 and LDO6. +vin-ldo2-5-7-supply: Input supply for LDO2, LDO5 and LDO7. +vin-ldo3-4-supply: Input supply for LDO3 and LDO4. +vin-ldo9-10-supply: Input supply for LDO9 and LDO10. +vin-ldo11-supply: Input supply for LDO11. + +Optional nodes: +-------------- +- regulators : Must contain a sub-node per regulator from the list below. + Each sub-node should contain the constraints and initialization + information for that regulator. See regulator.txt for a + description of standard properties for these sub-nodes. + Additional custom properties are listed below. + sd[0-6], ldo[0-7], ldo[9-11]. + + Optional sub-node properties: + ---------------------------- + ams,ext-control: External control of the rail. The option of + this properties will tell which external input is + controlling this rail. Valid values are 0, 1, 2 ad 3. + 0: There is no external control of this rail. + 1: Rail is controlled by ENABLE1 input pin. + 2: Rail is controlled by ENABLE2 input pin. + 3: Rail is controlled by ENABLE3 input pin. + ams,enable-tracking: Enable tracking with SD1, only supported + by LDO3. + +Example: +------- + ams3722: ams3722 { + compatible = "ams,as3722"; + reg = <0x40>; + ... + + regulators { + vsup-sd2-supply = <...>; + ... + + sd0 { + regulator-name = "vdd_cpu"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + ams,ext-control = <2>; + }; + + sd1 { + regulator-name = "vdd_core"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + ams,ext-control = <1>; + }; + + sd2 { + regulator-name = "vddio_ddr"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + sd4 { + regulator-name = "avdd-hdmi-pex"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + }; + + sd5 { + regulator-name = "vdd-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + .... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/cpcap-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/cpcap-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..36f5e2f5cc0fb4f0866feb9ed499d20ff1a1de31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/cpcap-regulator.txt @@ -0,0 +1,35 @@ +Motorola CPCAP PMIC voltage regulators +------------------------------------ + +Requires node properties: +- "compatible" value one of: + "motorola,cpcap-regulator" + "motorola,mapphone-cpcap-regulator" + "motorola,xoom-cpcap-regulator" + +Required regulator properties: +- "regulator-name" +- "regulator-enable-ramp-delay" +- "regulator-min-microvolt" +- "regulator-max-microvolt" + +Optional regulator properties: +- "regulator-boot-on" + +See Documentation/devicetree/bindings/regulator/regulator.txt +for more details about the regulator properties. + +Example: + +cpcap_regulator: regulator { + compatible = "motorola,cpcap-regulator"; + + cpcap_regulators: regulators { + sw5: SW5 { + regulator-min-microvolt = <5050000>; + regulator-max-microvolt = <5050000>; + regulator-enable-ramp-delay = <50000>; + regulator-boot-on; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/cpr3-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/cpr3-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..f32f46c7ea7bd8b8b012051c8ca884b6f5a23c14 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/cpr3-regulator.txt @@ -0,0 +1,622 @@ +Qualcomm Technologies, Inc. CPR3 Regulator - Platform Independent Bindings + +Core Power Reduction (CPR) version 3 controllers are used by some +Qualcomm Technologies, Inc. (QTI) SoCs to manage important voltage regulators. +CPR3 controllers are capable of monitoring several ring oscillator sensing loops +simultaneously. The CPR3 controller informs software when the silicon +conditions require the supply voltage to be increased or decreased. On certain +supply rails, the CPR3 controller is able to propagate the voltage increase +or decrease requests all the way to the PMIC without software involvement. + +This document describes the common platform independent bindings that apply +to all CPR3 controllers. + +======================= +Required Node Structure +======================= + +CPR3 regulators must be described in three levels of devices nodes. The first +level describes the CPR3 controller. The second level describes one or more +hardware threads managed by the controller. The third level describes one or +more logical regulators handled by each CPR thread. + +==================================== +First Level Nodes - CPR3 Controllers +==================================== + +Platform independent properties: +- compatible + Usage: required + Value type: + Definition: The value to use for this property is defined in the + platform specific cpr3-regulator binding documentation + files. + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the CPR3 controller, + the first fuse row, and optionally a register used to check + if aging measurements are possible. + +- reg-names + Usage: required + Value type: + Definition: Address names. Must include "cpr_ctrl" and "fuse_base". + "aging_allowed" may also be specified. The strings must be + specified in the same order as the corresponding addresses + are specified in the reg property. + +- qcom,cpr-ctrl-name + Usage: required + Value type: + Definition: Name for this CPR controller + +- vdd-supply + Usage: required + Value type: + Definition: phandle of the underlying regulator device that is managed + by this CPR controller. + +- system-supply + Usage: optional + Value type: + Definition: phandle of the system-level regulator device which the + vdd-supply depends upon. Requests for this regulator must + be made before increasing the vdd-supply voltage and after + decreasing the vdd-supply voltage. + +- mem-acc-supply + Usage: optional + Value type: + Definition: phandle of the mem-acc regulator device which is used to + configure memory array circuitry settings based upon + the performance operating point. Requests for this regulator + must be made before decreasing the vdd-supply voltage and + after increasing the vdd-supply voltage. + +- clocks + Usage: optional + Value type: + Definition: Array of clock tuples in which each tuple consists of a + phandle to a clock device and a clock ID number. The CPR3 + core clock must be specified for some targets. See platform + specific cpr3-regulator binding documentation for additional + clocks that may also need to be specified. + +- clock-names + Usage: optional + Value type: + Definition: Clock names. This list must match up 1-to-1 with the clocks + specified in the 'clocks' property. "core_clk" must be + specified for some platforms. Other clocks may be required + for some platforms. + +- interrupts + Usage: required + Value type: + Definition: CPR interrupt specifier and optionally a hardware + closed-loop ceiling interrupt specifier. + +- interrupt-names + Usage: required + Value type: + Definition: Interrupt names. This list must match up 1-to-1 with the + interrupts specified in the 'interrupts' property. "cpr" + must be specified. "ceiling" may be specified for some + platforms. + +- qcom,cpr-interrupt-affinity + Usage: optional + Value type: + Definition: A list of CPU phandles which correspond to the cores that + the "cpr" interrupt should have affinity for. + +- qcom,cpr-sensor-time + Usage: required + Value type: + Definition: The time in nanoseconds that each CPR sensor within the + sensing loop takes to perform a measurement. + +- qcom,cpr-loop-time + Usage: required + Value type: + Definition: The time in nanoseconds between consecutive CPR + measurements. + +- qcom,cpr-idle-cycles + Usage: required + Value type: + Definition: The number of CPR core clock cycles for the CPR controller + to wait in transitional states. + Supported values: 0 - 31. + +- qcom,voltage-step + Usage: required + Value type: + Definition: The voltage in microvolts of a single step of the VDD supply + regulator being controlled by CPR. + +- qcom,cpr-step-quot-init-min + Usage: required + Value type: + Definition: The default minimum CPR step quotient value. The step + quotient is the number of additional ring oscillator ticks + observed for each qcom,voltage-step increase in vdd-supply + output voltage. Supported values: 0 - 63. + +- qcom,cpr-step-quot-init-max + Usage: required + Value type: + Definition: The default maximum CPR step quotient value. + Supported values: 0 - 63. + +- qcom,cpr-count-mode + Usage: required + Value type: + Definition: The CPR counting mode to use during CPR measurements. + Supported values: + 0 - Read all sensors at once and use the minimum + quotient value observed in repeated measurements. + 1 - Read all sensors at once and use the maximum + quotient value observed in repeated measurements. + 2 - Read each sensor once in a sequential, staggered + fashion. + +- qcom,cpr-count-repeat + Usage: optional + Value type: + Definition: The number of times to read CPR sensors during a single CPR + measurement when using one of the all-at-once count modes. + +- qcom,cpr-enable + Usage: optional + Value type: + Definition: Boolean flag which indicates that the CPR3 controller + should operate in closed-loop mode (i.e. CPR sensing loop + enabled) as opposed to open-loop mode (i.e. CPR sensing loop + disabled) by default. + +- qcom,cpr-aging-ref-voltage + Usage: required if qcom,allow-aging-voltage-adjustment is specified + for any third level nodes + Value type: + Definition: Specifies the CPR aging reference voltage in microvolts. + This is the voltage that vdd-supply must be set to when + performing an aging measurement. + +- qcom,cpr-aging-allowed-reg-mask + Usage: required if "aging_allowed" register is specified + Value type: + Definition: Bitmask used to mask off the "aging_allowed" register. + +- qcom,cpr-aging-allowed-reg-value + Usage: required if "aging_allowed" register is specified + Value type: + Definition: Value required in the masked off "aging_allowed" register + bits in order for a CPR aging measurement to be possible. + +- qcom,cpr-panic-reg-addr-list + Usage: optional + Value type: + Definition: Array of register addresses to be dumped when device resets. + +- qcom,cpr-panic-reg-name-list + Usage: optional, though only meaningful if + qcom,cpr-panic-reg-addr-list is specified + Value type: + Definition: Address names. Must be specified in the same order + as the corresponding addresses are specified in + the qcom,cpr-panic-reg-addr-list property. + +================================================= +Second Level Nodes - CPR Threads for a Controller +================================================= + +Platform independent properties: +- qcom,cpr-thread-id + Usage: required + Value type: + Definition: Specifies the hardware thread ID of this thread within the + CPR controller. + +- qcom,cpr-consecutive-up + Usage: required + Value type: + Definition: The number of consecutive CPR step up events needed to + to trigger an up interrupt. Supported values: 0 - 15. + +- qcom,cpr-consecutive-down + Usage: required + Value type: + Definition: The number of consecutive CPR step down events needed to + to trigger a down interrupt. Supported values: 0 - 15. + +- qcom,cpr-up-threshold + Usage: required + Value type: + Definition: The number CPR error steps required to generate an up event. + Supported values: 0 - 31. + +- qcom,cpr-down-threshold + Usage: required + Value type: + Definition: The number CPR error steps required to generate a down + event. Supported values: 0 - 31. + +=============================================== +Third Level Nodes - CPR Regulators for a Thread +=============================================== + +Platform independent properties: +- regulator-name + Usage: required + Value type: + Definition: Specifies the name for this CPR3 regulator. + +- regulator-min-microvolt + Usage: required + Value type: + Definition: Minimum corner value which should be 1 to represent the + lowest supported corner. + +- regulator-max-microvolt + Usage: required + Value type: + Definition: Maximum corner value which should be equal to largest value + listed in qcom,cpr-corners. + +- qcom,cpr-fuse-corners + Usage: required + Value type: + Definition: Specifies the number of fuse corners. See platform specific + binding files for further requirements. + +- qcom,cpr-fuse-combos + Usage: required + Value type: + Definition: Specifies the number of fuse combinations being supported by + the device. This value is utilized by several other + properties. Supported values are 1 up to the maximum + possible for a given regulator type. See platform specific + binding files for further details. + +- qcom,cpr-speed-bins + Usage: optional + Value type: + Definition: Specifies the number of speed bins being supported by the + device. This value is utilized by several other properties. + Supported values are 1 up to the maximum possible for a + given regulator type. See platform specific binding files + for further details. + + This property can only be utilized if the number of corners + for all fuse combinations associated with a given speed bin + is the same. + +- qcom,cpr-corners + Usage: required + Value type: + Definition: A list of integers which defines how many voltage corners + are to be used for each fuse combination. The list must + contain either qcom,cpr-fuse-combos number of elements in + which case the corner counts are applied to fuse + combinations 1-to-1 or the list must contain exactly 1 + element which is used regardless of the fuse combination + found on a given chip. + +- qcom,cpr-speed-bin-corners + Usage: required if qcom,cpr-speed-bins is specified + Value type: + Definition: A list of integers which defines how many voltage corners + are to be used for each speed bin. The list must contain + qcom,cpr-speed-bins number of elements. + +- qcom,cpr-corner-fmax-map + Usage: required + Value type: + Definition: A list of integer tuples which each define the highest + (i.e. maximum frequency) 1-based corner value associated + with each fuse-corner. + + Each tuple must have a number of elements equal to the value + of the qcom,cpr-fuse-corners property. The elements of a + tuple are ordered from lowest to highest fuse corner. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + +- qcom,cpr-voltage-ceiling + Usage: required + Value type: + Definition: A list of integer tuples which each define the CPR ceiling + voltage in microvolts for each voltage corner in order from + lowest to highest. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the + corresponding element of the qcom,cpr-corners property or + the qcom,cpr-speed-bins property. A single tuple may only + be specified if all of the corner counts in qcom,cpr-corners + are the same. + +- qcom,cpr-voltage-floor + Usage: required + Value type: + Definition: A list of integer tuples which each define the CPR floor + voltage in microvolts for each voltage corner in order from + lowest to highest. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + +- qcom,cpr-floor-to-ceiling-max-range + Usage: optional + Value type: + Definition: A list of integer tuples which each define the maximum + allowed difference between the final floor voltage and the + final ceiling voltage in microvolts for each voltage corner + in order from lowest to highest. A negative value may be + specified for an element to indicate that there is no + limitation of the floor to ceiling voltage range for the + corresponding corner. + + In the case that the initial floor to ceiling voltage is + greater than the max range specified, the floor voltage will + be increased in order to satisfy the max range constraint. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + +- qcom,system-voltage + Usage: optional + Value type: + Definition: A list of integer tuples which each define the system-supply + voltage in microvolts or corners or levels for each voltage + corner in order from lowest to highest. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + +- qcom,corner-frequencies + Usage: required + Value type: + Definition: A list of integer tuples which each define the CPU frequency + in Hertz corresponding to each voltage corner in order from + lowest to highest. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + +- qcom,allow-voltage-interpolation + Usage: optional + Value type: + Definition: Boolean flag which indicates that it is acceptable to use + interpolated open-loop voltage values. These values are + interpolated between the open-loop voltage Fmax fuse values. + +- qcom,cpr-scaled-open-loop-voltage-as-ceiling + Usage: optional + Value type: + Definition: Boolean flag which indicates that it is acceptable to use + the interpolated open-loop voltage for each corner as the + CPR ceiling voltage for each corner. + +- qcom,cpr-open-loop-voltage-fuse-adjustment + Usage: optional + Value type: + Definition: A list of integer tuples which each define the open-loop + voltage adjustment in microvolts for each fused voltage + corner in order from lowest to highest. This adjustment is + applied to the values read from fuses before the values are + used in interpolation for intermediate corners. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-corner-fmax-map above. + + The open-loop voltage for a given fuse corner corresponds to + the voltage that is safe to use under all circumstances. + It is used as a starting voltage for CPR and may also be + specified as a ceiling voltage for CPR scaling. + +- qcom,cpr-open-loop-voltage-adjustment + Usage: optional + Value type: + Definition: A list of integer tuples which each define the open-loop + voltage adjustment in microvolts for each voltage corner in + order from lowest to highest. This adjustment is applied to + the open-loop voltage values after they have been + interpolated for intermediate corners. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + +- qcom,cpr-open-loop-voltage-min-diff + Usage: optional; only meaningful if the + qcom,cpr-open-loop-voltage-adjustment property is specified + Value type: + Definition: A list of integer tuples which each define the minimum + allowed open-loop voltage difference in microvolts between + each voltage corner and the one immediately preceding it. + The elements in a tuple are ordered from the lowest to the + highest corner. The value specified for the first corner is + ignored since there is no corner before it. + + Negative voltage values may be specified for this property. + A negative value means that the open-loop voltage of a + corner may be lower than that of the preceding corner. + + The minimum difference is enforced after the open-loop + voltage values have been interpolated for intermediate + corners and after adjustments have been applied. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + + If this property is not specified, then the minimum + difference is assumed to be 0 uV for all corners. + +- qcom,cpr-closed-loop-voltage-fuse-adjustment + Usage: optional + Value type: + Definition: A list of integer tuples which each define the closed-loop + voltage adjustment in microvolts for each fused voltage + corner in order from lowest to highest. This adjustment is + applied to the values read from fuses before the values are + used in interpolation for intermediate corners. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-corner-fmax-map above. + + The qcom,cpr-ro-scaling-factor property must be specified in + order to utilize this property. + + The closed-loop voltage for a given fuse corner corresponds + to the voltage that the CPR controller settles the VDD + supply rail to based upon the programmed CPR target + quotients and the current silicon conditions. + +- qcom,cpr-closed-loop-voltage-adjustment + Usage: optional + Value type: + Definition: A list of integer tuples which each define the closed-loop + voltage adjustment in microvolts for each voltage corner in + order from lowest to highest. This adjustment is applied to + target quotient values after they have been interpolated + for intermediate corners. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + + The qcom,cpr-ro-scaling-factor property must be specified in + order to utilize this property. + +- qcom,cpr-ro-scaling-factor + Usage: required if qcom,cpr-closed-loop-voltage-fuse-adjustment, + qcom,cpr-closed-loop-voltage-adjustment, or + qcom,allow-aging-voltage-adjustment is specified + Value type: + Definition: A grouping of integer tuple lists. Each tuple defines the + CPR ring oscillator (RO) scaling factor with units of QUOT/V + for each RO for a given fuse corner. Since CPR3 supports + exactly 16 ROs, each tuple must contain 16 elements + corresponding to RO0 through RO15 in order. If a given RO + is unused for a fuse corner, then its scaling factor may be + specified as 0. + + Each tuple list must contain the number of tuples defined in + the qcom,cpr-fuse-corners property. The tuples in a given + list are ordered from the lowest fuse corner to the highest + fuse corner. + + The tuple list grouping must contain qcom,cpr-fuse-combos + number of tuple lists in which case the lists are matched to + fuse combinations 1-to-1 or qcom,cpr-speed-bins number of + tuple lists in which case the lists are matched to + speed bins 1-to-1 or exactly 1 list which is used regardless + of the fuse combination and speed bin found on a given chip. + + The target quotient adjustment to apply for each RO of a + given corner is determined by multiplying the adjustment + value in qcom,cpr-closed-loop-voltage-fuse-adjustment or + qcom,cpr-closed-loop-voltage-adjustment by the relevant RO + scaling factor in this property. + +- qcom,allow-aging-voltage-adjustment + Usage: optional + Value type: + Definition: A list of integers which specifies if CPR aging adjustment + should be performed for each fuse combination. + Supported per-combo element values: + 0 - do not perform CPR aging adjustment + 1 - perform CPR aging adjustment + + The list must contain qcom,cpr-fuse-combos number of + elements in which case the elements are matched to fuse + combinations 1-to-1 or qcom,cpr-speed-bins number of + elements in which case the elements are matched to + speed bins 1-to-1 or exactly 1 element which is used + regardless of the fuse combination and speed bin found + on a given chip. + +- qcom,allow-aging-open-loop-voltage-adjustment + Usage: optional + Value type: + Definition: A list of integers which specifies if CPR aging adjustment + should be applied to open-loop voltages for each fuse + combination. Note that aging adjustment must be allowed via + qcom,allow-aging-voltage-adjustment in order for this + property to have an effect. + Supported per-combo element values: + 0 - do not perform CPR aging adjustment + 1 - perform CPR aging adjustment + + The list must meet the same size requirements as those + specified for qcom,allow-aging-voltage-adjustment above. + +- qcom,cpr-aging-max-voltage-adjustment + Usage: required if qcom,allow-aging-voltage-adjustment is specified + Value type: + Definition: A list of integers which defines the maximum CPR aging + voltage margin adjustment in microvolts that may be added + for each fuse combination. If this property is specified + and the adjustment specified is greater than 0, then aging + adjustments are required for this regulator. + + The list must meet the same size requirements as those + specified for qcom,allow-aging-voltage-adjustment above. + +- qcom,cpr-aging-ref-corner + Usage: required if qcom,allow-aging-voltage-adjustment is specified + Value type: + Definition: A list of integers which defines the CPR reference corner + for this regulator to use during aging measurements for each + fuse combination. + + The list must meet the same size requirements as those + specified for qcom,allow-aging-voltage-adjustment above. + +- qcom,cpr-aging-ro-scaling-factor + Usage: required if qcom,allow-aging-voltage-adjustment is specified + Value type: + Definition: A list of integers which defines the CPR aging ring + oscillator (RO) scaling factor with units of QUOT/V to use + during aging measurements for each fuse combination. + + The list must meet the same size requirements as those + specified for qcom,allow-aging-voltage-adjustment above. + +- qcom,cpr-aging-derate + Usage: optional, though only meaningful if + qcom,allow-aging-voltage-adjustment is specified + Value type: + Definition: A list of integer tuples which each define the CPR aging + derating scaling factor to apply to the closed-loop voltage + margin adjustment for each corner. The individual scaling + factors have units of uV/mV and are ordered from lowest to + highest corner per tuple. For example, a value of 900 + specifies that the voltage adjustment for the corner should + be 90% (900/1000) of that for the reference corner. + + The list and tuples must meet the same size requirements as + those specified for qcom,cpr-voltage-ceiling above. + + If this property is not specified, then it is assumed that + no corners require derating (i.e. the scaling factor would + be 1000). + +All properties specified within the core regulator framework can also be used in +third level nodes. These bindings can be found in: +Documentation/devicetree/bindings/regulator/regulator.txt. + +See platform specific cpr3-regulator binding documentation files for examples. diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/cpr4-mmss-ldo-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/cpr4-mmss-ldo-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..851528517f4cedd861fd4fd16da38c74a27f9a10 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/cpr4-mmss-ldo-regulator.txt @@ -0,0 +1,321 @@ +Qualcomm Technologies, Inc. CPR4 Regulator - MMSS LDO Specific Bindings + +MMSS LDO CPR4 controllers each support one CPR thread that monitors the voltage +of the graphics processor (MMSS) supply regulator. The CPR open-loop voltages +are stored in hardware fuses for MMSS CPR4 controllers. However, the CPR target +quotients must be defined in device tree. + +This document describes the MMSS LDO specific CPR4 bindings. + +======================= +Required Node Structure +======================= + +CPR3 regulators must be described in three levels of devices nodes. The first +level describes the CPR3 controller. The second level describes exacly one +hardware thread managed by the controller. The third level describes one or +more logical regulators handled by the CPR thread. + +All platform independent cpr3-regulator binding guidelines defined in +cpr3-regulator.txt also apply to cpr4-mmss-ldo-regulator devices. + +==================================== +First Level Nodes - CPR3 Controllers +==================================== + +MMSS LDO specific properties: +- compatible + Usage: required + Value type: + Definition: should be the following: + "qcom,cpr4-sdm660-mmss-ldo-regulator". + +- clocks + Usage: required + Value type: + Definition: Array of clock tuples in which each tuple consists of a + phandle to a clock device and a clock ID number. The + following clocks must be specified: MMSS RBCPR and MMSS + RBCPR AHB. + +- clock-names + Usage: required + Value type: + Definition: Clock names. This list must match up 1-to-1 with the clocks + specified in the 'clocks' property. "core_clk", and "bus_clk" + must be specified. + +- qcom,cpr-step-quot-fixed + Usage: Optional + Value type: + Definition: Fixed step quotient value used by controller for applying + the SDELTA margin adjustments on the programmed target + quotient values. The step quotient is the number of + additional ring oscillator ticks observed for each + qcom,voltage-step increase in vdd-supply output voltage. + Supported values: 0 - 63. + +================================================= +Second Level Nodes - CPR Threads for a Controller +================================================= + +MMSS specific properties: +N/A + +=============================================== +Third Level Nodes - CPR Regulators for a Thread +=============================================== + +MMSS specific properties: +- qcom,cpr-fuse-corners + Usage: required + Value type: + Definition: Specifies the number of fuse corners. This value must be 6 + for sdm660 GFX LDO. These fuse corners are: MinSVS, + LowSVS, SVS, SVSP, NOM and NOMP. The open-loop voltage fuses + are allocated for LowSVS, SVS, NOM and NOMP corners. The + open-loop voltages for MinSVS and SVSP are derived by + applying fixed offset from LowSVS and NOM open-loop voltages + respectively. The closed-loop offset voltage fuses are + allocated for LowSVS, SVS, NOM and NOMP corners. The MinSVS + and SVSP corners use the closed-loop offset voltage fuses of + LowSVS and NOM corners respectively. + +- qcom,cpr-fuse-combos + Usage: required + Value type: + Definition: Specifies the number of fuse combinations being supported by + the device. This value is utilized by several other + properties. Supported values are 1 up to the maximum + possible for a given regulator type. For MMSS the maximum + supported value is 8. These combos correspond to CPR + revision fuse values from 0 to 7 in order. + +- qcom,mem-acc-voltage + Usage: required if mem-acc-supply is specified for the CPR3 controller + containing this CPR3 regulator + Value type: + Definition: A list of integer tuples which each define the mem-acc-supply + corner for each voltage corner in order from lowest to highest. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the + corresponding element of the qcom,cpr-corners property or + the qcom,cpr-speed-bins property. A single tuple may only + be specified if all of the corner counts in qcom,cpr-corners + are the same. + +- qcom,cpr-target-quotients + Usage: required + Value type: + Definition: A grouping of integer tuple lists. Each tuple defines the + CPR target quotient for each ring oscillator (RO) for a + given corner. Since CPR3 supports exactly 16 ROs, each + tuple must contain 16 elements corresponding to RO0 through + RO15 in order. If a given RO is unused for a corner, then + its target quotient should be specified as 0. + + Each tuple list in the grouping must meet the same size + requirements as those specified for qcom,mem-acc-voltage + above. The tuples in a given list are ordered from the + lowest corner to the highest corner. + +- qcom,cpr-ro-scaling-factor + Usage: required if qcom,cpr-closed-loop-voltage-adjustment is + specified + Value type: + Definition: The common definition of this property in cpr3-regulator.txt + is accurate for MMSS CPR3 controllers except for this + modification: + + Each tuple list must contain the number of tuples defined in + the corresponding element of the qcom,cpr-corners property + or the qcom,cpr-speed-bins property as opposed to the value + of the qcom,cpr-fuse-corners property. + +- qcom,cpr-fused-closed-loop-voltage-adjustment-map + Usage: optional + Value type: + Definition: A list of integer tuples which each define the CPR fused + corner closed-loop offset adjustment fuse to utilize for + each voltage corner in order from lowest to highest. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the + corresponding element of the qcom,cpr-corners property or + the qcom,cpr-speed-bins property. A single tuple may only + be specified if all of the corner counts in qcom,cpr-corners + are the same. + + Each tuple element must be either 0 or in the range 1 to + qcom,cpr-fuse-corners. A value of 0 signifies that no fuse + based adjustment should be applied to the fuse corner. + Values 1 to qcom,cpr-fuse-corners denote the specific fuse + corner that should be used by a given voltage corner. + +- qcom,cpr-corner-allow-ldo-mode + Usage: optional + Value type: + Definition: A list of integer tuples which each define the LDO mode + allowed state for each voltage corner in order from lowest + to highest. Each element in the tuple should be either + 0 (LDO mode not allowed) or 1 (LDO mode allowed). + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the + corresponding element of the qcom,cpr-corners property or + the qcom,cpr-speed-bin-corners property. A single tuple may + only be specified if all of the corner counts in + qcom,cpr-corners are the same. + +- qcom,cpr-corner-allow-closed-loop + Usage: optional + Value type: + Definition: A list of integer tuples which each define the CPR + closed-loop operation allowed state for each voltage corner + in order from lowest to highest. Each element in the tuple + should be either 0 (CPR closed-loop operation not allowed) + or 1 (CPR closed-loop operation allowed). + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the + corresponding element of the qcom,cpr-corners property or + the qcom,cpr-speed-bin-corners property. A single tuple may + only be specified if all of the corner counts in + qcom,cpr-corners are the same. + +Note that the qcom,cpr-closed-loop-voltage-fuse-adjustment property is not +meaningful for MMSS LDO CPR3 regulator nodes since target quotients are not +defined in fuses. + +======= +Example +======= + +gfx_cpr: cpr4-ctrl@05061000 { + compatible = "qcom,cpr4-sdm660-mmss-ldo-regulator"; + reg = <0x05061000 0x4000>, <0x00784000 0x1000>; + reg-names = "cpr_ctrl", "fuse_base"; + interrupts = ; + interrupt-names = "cpr"; + qcom,cpr-ctrl-name = "gfx"; + + qcom,cpr-sensor-time = <1000>; + qcom,cpr-loop-time = <5000000>; + qcom,cpr-idle-cycles = <15>; + qcom,cpr-step-quot-init-min = <8>; + qcom,cpr-step-quot-init-max = <12>; + qcom,cpr-count-mode = <0>; /* All at once */ + + vdd-supply = <&gfx_stub_vreg>; + mem-acc-supply = <&gfx_mem_acc_vreg>; + system-supply = <&pm660l_s3_level>; /* vdd_cx */ + qcom,voltage-step = <5000>; + vdd-thread0-ldo-supply = <&gfx_ldo_vreg>; + + qcom,cpr-enable; + + thread@0 { + qcom,cpr-thread-id = <0>; + qcom,cpr-consecutive-up = <0>; + qcom,cpr-consecutive-down = <2>; + qcom,cpr-up-threshold = <0>; + qcom,cpr-down-threshold = <2>; + + gfx_vreg_corner: regulator { + regulator-name = "gfx_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,cpr-fuse-corners = <6>; + qcom,cpr-fuse-combos = <8>; + qcom,cpr-corners = <7>; + + qcom,cpr-corner-fmax-map = <1 2 3 4 5 6>; + + qcom,cpr-voltage-ceiling = + <584000 644000 724000 788000 + 868000 924000 1068000>; + qcom,cpr-voltage-floor = + <504000 504000 596000 652000 + 712000 744000 1068000>; + + qcom,mem-acc-voltage = <1 1 1 2 2 2 2>; + qcom,system-voltage = + , + , + , + , + , + , + ; + + qcom,corner-frequencies = + <160000000 266000000 370000000 + 465000000 588000000 647000000 + 800000000>; + + qcom,cpr-target-quotients = + <0 0 0 0 0 0 185 179 + 291 299 304 319 0 0 0 0>, + <0 0 0 0 0 0 287 273 + 425 426 443 453 0 0 0 0>, + <0 0 0 0 0 0 414 392 + 584 576 608 612 0 0 0 0>, + <0 0 0 0 0 0 459 431 + 684 644 692 679 0 0 0 0>, + <0 0 0 0 0 0 577 543 + 798 768 823 810 0 0 0 0>, + <0 0 0 0 0 0 669 629 + 886 864 924 911 0 0 0 0>, + <0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0>; + + qcom,cpr-ro-scaling-factor = + < 0 0 0 0 0 0 2035 1917 + 1959 2131 2246 2253 0 0 0 0>, + < 0 0 0 0 0 0 2035 1917 + 1959 2131 2246 2253 0 0 0 0>, + < 0 0 0 0 0 0 2035 1917 + 1959 2131 2246 2253 0 0 0 0>, + < 0 0 0 0 0 0 2035 1917 + 1959 2131 2246 2253 0 0 0 0>, + < 0 0 0 0 0 0 2035 1917 + 1959 2131 2246 2253 0 0 0 0>, + < 0 0 0 0 0 0 2035 1917 + 1959 2131 2246 2253 0 0 0 0>, + < 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0>; + + qcom,cpr-scaled-open-loop-voltage-as-ceiling; + qcom,cpr-corner-ldo-mode-allowed = + <1 1 1 1 1 1 0>; + qcom,cpr-corner-use-closed-loop = + <1 1 1 1 1 1 0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/cprh-kbss-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/cprh-kbss-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff800352cc0549d87c31c4056fca4ad48cedf89a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/cprh-kbss-regulator.txt @@ -0,0 +1,459 @@ +Qualcomm Technologies, Inc. CPRh Regulator - KBSS Specific Bindings + +KBSS CPRh controllers each support one CPR thread that monitors the voltage +of a single Kryo-B CPU subystem (KBSS) cluster that is powered by a single +regulator supply. The DCVSh block interacts with the CPRh controller for full +hardware DCVS support. + +Both CPR open-loop voltages and CPR target quotients are stored in hardware +fuses for KBSS CPRh controllers. + +This document describes the KBSS specific CPRh bindings. + +======================= +Required Node Structure +======================= + +CPRh regulators must be described in three levels of devices nodes. The first +level describes the CPRh controller. The second level describes one hardware +thread managed by the controller. The third level describes one regulator +handled by the CPR thread. + +All platform independent cpr3-regulator binding guidelines defined in +cpr3-regulator.txt also apply to cprh-kbss-regulator devices. + +==================================== +First Level Nodes - CPR3 Controllers +==================================== + +KBSS specific properties: +- compatible + Usage: required + Value type: + Definition: should be one of the following: + "qcom,cprh-msm8998-v1-kbss-regulator", + "qcom,cprh-msm8998-v2-kbss-regulator", + "qcom,cprh-msm8998-kbss-regulator", + "qcom,cprh-sdm660-kbss-regulator". + If the SoC revision is not specified, then it is assumed to + be the most recent revision of MSM8998, i.e. v2. + +- qcom,cpr-controller-id + Usage: required + Value type: + Definition: Identifies the controller number for subsystems that are managed + by multiple CPR controllers. For KBSS, the supported values are 0 + and 1, corresponding to each cluster. + +- qcom,apm-threshold-voltage + Usage: optional + Value type: + Definition: Specifies the APM threshold voltage in microvolts. The + floor to ceiling range for every corner is adjusted to ensure + it does not intersect this voltage. The value of this property + must match with the APM threshold voltage defined in the OSM + device to ensure that if the VDD_APCC supply voltage is above + this level, then the APM is switched to use VDD_APCC and if + VDD_APCC is below this level, then the APM is switched to use + VDD_MX. + +- qcom,apm-crossover-voltage + Usage: required if qcom,apm-threshold-voltage is specified + Value type: + Definition: Specifies the APM crossover voltage in microvolts which + corresponds to the voltage the VDD supply must be set at + during an APM switch transition. + +- qcom,apm-hysteresis-voltage + Usage: optional + Value type: + Definition: Specifies the voltage in microvolts used to adjust floor + voltages with respect to the APM threshold voltage. This + voltage is used to reduce the number of corners whose floor + must be raised to ensure stable operation with manual APM + switching. If this property is not specified, then a value + of 0 is assumed. + +- qcom,mem-acc-threshold-voltage + Usage: optional + Value type: + Definition: Specifies the highest memory accelerator (MEM ACC) threshold + voltage in microvolts. The floor to ceiling voltage range + for every corner is adjusted to ensure that it does not + intersect this voltage. The value of this property must + match with the MEM ACC threshold voltage defined in the OSM + device to ensure that MEM ACC settings are switched + appropriately. + +- qcom,mem-acc-crossover-voltage + Usage: required if qcom,mem-acc-threshold-voltage is specified + Value type: + Definition: Specifies the MEM ACC crossover voltage in microvolts which + corresponds to the voltage the VDD supply must be set to + when switching the MEM ACC configuration. + +- qcom,voltage-base + Usage: required + Value type: + Definition: Specifies the voltage in microvolts used by the CRR controller + to resolve open-loop and floor voltages. In particular, this + voltage is added to the programmed open-loop and floor voltages + and it corresponds to the minimum supported setpoint of the + vdd-supply. + +- qcom,cpr-saw-use-unit-mV + Usage: optional + Value type: + Definition: Boolean flag which indicates that the unit used in SAW PVC + interface is mV. Use this for vdd-supply regulators which + do not use PMIC voltage control register LSBs per actually + unique PMIC regulator output voltage. + +- qcom,cpr-up-down-delay-time + Usage: required + Value type: + Definition: The time to delay in nanoseconds between consecutive CPR + measurements when the last measurement recommended + increasing or decreasing the vdd-supply voltage. + +- qcom,cpr-down-error-step-limit + Usage: required + Value type: + Definition: CPRh hardware closed-loop down error step limit which + defines the maximum number of vdd-supply regulator steps + that the voltage may be reduced as the result of a single + CPR measurement. + +- qcom,cpr-up-error-step-limit + Usage: required + Value type: + Definition: CPRh hardware closed-loop up error step limit which defines + the maximum number of vdd-supply regulator steps that the + voltage may be increased as the result of a single + CPR measurement. + +- qcom,cpr-step-quot-fixed + Usage: optional + Value type: + Definition: Fixed step quotient value used by controller for applying + the SDELTA margin adjustments on the programmed target + quotient values. The step quotient is the number of + additional ring oscillator ticks observed for each + qcom,voltage-step increase in vdd-supply output voltage. + Supported values: 0 - 63. + +- qcom,cpr-voltage-settling-time + Usage: optional + Value type: + The time in nanoseconds that it takes for the vdd-supply + voltage to settle after being increased or decreased by + qcom,voltage-step microvolts. This is used as the wait + time after applying SDELTA voltage margin adjustments. + +- qcom,cpr-corner-switch-delay-time + Usage: optional + Value type: + The time in nanoseconds that the CPR controller must delay + to allow voltage settling per 1 mV of voltage change after a + corner change. + +- qcom,cpr-hw-closed-loop + Usage: optional + Value type: + Definition: Boolean flag which indicates that the KBSS CPRh controller + should operate in hardware closed-loop mode as opposed to + open-loop. + +- qcom,cpr-temp-point-map + Usage: required if qcom,corner-band-allow-temp-adjustment is specified + for at least one of the CPR3 regulators. + Value type: + Definition: The temperature points in decidegrees Celsius which indicate + the range of temperature bands supported. If t1, t2, and t3 + are the temperature points, then the temperature bands are: + (-inf, t1], (t1, t2], (t2, t3], and (t3, inf). A maximum of + three temperature points can be specified to define a total + of four different temperature bands. + +- qcom,cpr-initial-temp-band + Usage: required if qcom,corner-band-allow-temp-adjustment is specified + for at least one of the CPR3 regulators. + Value type: + Definition: The initial temp band considering 0-based index at which + the baseline target quotients are derived and fused. + +================================================= +Second Level Nodes - CPR Threads for a Controller +================================================= + +KBSS specific properties: +N/A + +=============================================== +Third Level Nodes - CPR Regulators for a Thread +=============================================== + +KBSS specific properties: +- qcom,cpr-fuse-corners + Usage: required + Value type: + Definition: Specifies the number of fuse corners. This value must be 4 + for KBSS. These fuse corners are: LowSVS, SVS, Nominal, + and Turbo. + +- qcom,cpr-fuse-combos + Usage: required + Value type: + Definition: Specifies the number of fuse combinations being supported by + the device. This value is utilized by several other + properties. Supported values are 1 up to the maximum + possible for a given regulator type. For KBSS the maximum + supported value is 8. These combos correspond to CPR + revision fuse values 0 to 7 in order. + +- qcom,allow-quotient-interpolation + Usage: optional + Value type: + Definition: Boolean flag which indicates that it is acceptable to use + interpolated CPR target quotient values. These values are + interpolated between the target quotient Fmax fuse values. + +- qcom,cpr-corner-bands + Usage: required if qcom,corner-band-allow-core-count-adjustment + or qcom,corner-band-allow-temp-adjustment is specified + for this CPR3 regulator. + Value type: + Definition: A list of integers which defines how many corner bands + exist for each fuse combination. Supported values are 1 to 4. + The list must contain either qcom,cpr-fuse-combos number of + elements in which case the corner band counts are applied to + fuse combinations 1-to-1 or the list must contain exactly 1 + element which is used regardless of the fuse combination + found on a given chip. + +- qcom,cpr-speed-bin-corner-bands + Usage: required if qcom,cpr-speed-bins and + qcom,corner-band-allow-core-count-adjustment or + qcom,corner-band-allow-temp-adjustment are specified for + this CPR3 regulator. + Value type: + Definition: A list of integers which defines how many corner bands + are to be used for each speed bin. The list must contain + qcom,cpr-speed-bins number of elements. + +- qcom,corner-band-allow-core-count-adjustment + Usage: optional + Value type: + Definition: A list of integer tuples which each define the CPR core + count adjustment feature enable state for each corner band + in order from lowest to highest. Each element in the tuple + should be either 0 (per-core-count adjustment not allowed) + or 1 (per-core-count adjustment allowed). A maximum of four + corner bands may be used to partition the corner space into + contiguous corner ranges. For all corners within a corner band, + the same per-core-count adjustments are applied. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the corresponding + element of the qcom,cpr-corner-bands property. + +- qcom,max-core-count + Usage: required if qcom,corner-band-allow-core-count-adjustment is + specified for this CPR3 regulator. + Value type: + Definition: The maximum number of cores considered for core-count vmin + adjustments specified for this regulator's corner bands. + +- qcom,corner-band-allow-temp-adjustment + Usage: optional + Value type: + Definition: A list of integer tuples which each define the temperature + adjustment feature enable state for each corner band + in order from lowest to highest. Each element in the tuple + should be either 0 (temperature adjustment not allowed) + or 1 (temperature adjustment allowed). A maximum of four + corner bands may be used to partition the corner space into + contiguous corner ranges. For all corners within a corner band, + the same temperature adjustments are applied. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the corresponding + element of the qcom,cpr-corner-bands property. + +- qcom,cpr-corner-band-map + Usage: required if qcom,corner-band-allow-core-count-adjustment + or qcom,corner-band-allow-temp-adjustment is specified + for this CPR3 regulator. + Value type: + Definition: A list of integer tuples which correspond to corner numbers + and define the corner bands to be used for temperature or + per-core-count adjustments. The corner numbers must be specified + in increasing order to result in partitioning the corner space + into contiguous corner ranges. The supported tuple size is 1 + to 4 elements. For example, a tuple with corners defined as + c1, c2, c3, c4 results in the following corner band mapping: + + [c1, c2) -> Corner Band 1 + [c2, c3) -> Corner Band 2 + [c3, c4) -> Corner Band 3 + [c4, inf)-> Corner Band 4 + + Corners less than c1 will have no per-core-count or temperature + adjustments. Adjustments associated with each corner band X are + defined in the corresponding + qcom,cpr-corner-bandX-temp-core-voltage-adjustment property. + + The list must contain qcom,cpr-fuse-combos number of tuples + in which case the tuples are matched to fuse combinations + 1-to-1 or qcom,cpr-speed-bins number of tuples in which case + the tuples are matched to speed bins 1-to-1 or exactly 1 + tuple which is used regardless of the fuse combination and + speed bin found on a given chip. + + Each tuple must be of the length defined in the corresponding + element of the qcom,cpr-corner-bands property. + +- qcom,cpr-corner-bandX-temp-core-voltage-adjustment + Usage: required if qcom,corner-band-allow-core-count-adjustment + is specified for this CPR3 regulator. + Value type: + Definition: A grouping of integer tuple lists for corner bandX. The possible + values for X are 1 to 4. Each tuple defines the temperature based + voltage adjustment in microvolts for each temperature band + from lowest to highest for a given number of online cores. Each + tuple must have a number of elements equal to either (the number + of elements in qcom,cpr-temp-point-map + 1), if + qcom,cpr-temp-point-map is specified, or 1. + + Each tuple list must contain a number of tuples equal to + either qcom,max-core-count, if qcom,max-core-count is + specified, or 1. The tuples should be ordered from lowest + to highest core count. + + The tuple list grouping must contain qcom,cpr-fuse-combos + number of tuple lists in which case the lists are matched to + fuse combinations 1-to-1 or qcom,cpr-speed-bins number of + tuple lists in which case the lists are matched to + speed bins 1-to-1 or exactly 1 list which is used regardless + of the fuse combination and speed bin found on a given chip. + +======= +Example +======= + +apc0_cpr: cprh-ctrl@179c8000 { + compatible = "qcom,cprh-msm8998-kbss-regulator"; + reg = <0x179c8000 0x4000>, <0x00784000 0x1000>; + reg-names = "cpr_ctrl", "fuse_base"; + clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; + clock-names = "core_clk"; + qcom,cpr-ctrl-name = "apc0"; + qcom,cpr-controller-id = <0>; + + qcom,cpr-sensor-time = <1000>; + qcom,cpr-loop-time = <5000000>; + qcom,cpr-idle-cycles = <15>; + qcom,cpr-up-down-delay-time = <3000>; + qcom,cpr-step-quot-init-min = <11>; + qcom,cpr-step-quot-init-max = <13>; + qcom,cpr-count-mode = <2>; /* Staggered */ + qcom,cpr-down-error-step-limit = <1>; + qcom,cpr-up-error-step-limit = <1>; + qcom,cpr-corner-switch-delay-time = <1600>; + qcom,cpr-voltage-settling-time = <1600>; + + qcom,apm-threshold-voltage = <800000>; + qcom,apm-hysteresis-voltage = <4000>; + qcom,voltage-step = <4000>; + qcom,voltage-base = <352000>; + qcom,cpr-saw-use-unit-mV; + + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + + qcom,cpr-initial-temp-band = <3>; + qcom,cpr-temp-point-map = <0 25 85>; + + thread@0 { + qcom,cpr-thread-id = <0>; + qcom,cpr-consecutive-up = <2>; + qcom,cpr-consecutive-down = <2>; + qcom,cpr-up-threshold = <0>; + qcom,cpr-down-threshold = <0>; + + apc0_pwrcl_vreg: regulator-pwrcl { + regulator-name = "apc0_pwrcl_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <24>; + + qcom,cpr-fuse-corners = <4>; + qcom,cpr-fuse-combos = <1>; + qcom,cpr-corners = <23>; + + qcom,cpr-corner-fmax-map = <7 10 17 23>; + + qcom,cpr-voltage-ceiling = + <632000 632000 632000 632000 632000 + 632000 632000 700000 700000 700000 + 828000 828000 828000 828000 828000 + 828000 828000 1024000 1024000 1024000 + 1024000 1024000 1024000>; + + qcom,cpr-voltage-floor = + <572000 572000 572000 572000 572000 + 572000 572000 568000 568000 568000 + 684000 684000 684000 684000 684000 + 684000 684000 856000 856000 856000 + 856000 856000 856000>; + + qcom,corner-frequencies = + <300000000 345600000 422400000 + 499200000 576000000 633600000 + 710400000 806400000 883200000 + 960000000 1036800000 1113600000 + 1190400000 1248000000 1324800000 + 1401600000 1478400000 1497600000 + 1574400000 1651200000 1728000000 + 1804800000 1881600000>; + }; + + qcom,cpr-corner-bands = <4>; + qcom,corner-band-allow-core-count-adjustment = <1 1 1 1>; + qcom,corner-band-allow-temp-adjustment = <1 0 0 0>; + qcom,cpr-corner-band-map = <7 14 18 20>; + qcom,max-core-count = <4>; + qcom,cpr-corner-band1-temp-core-voltage-adjustment = + <(-24000) (-20000) (-20000) (-16000)>, + <(-16000) (-16000) (-12000) (-8000)>, + <(-8000) (-8000) (-4000) (-4000)>, + <0 0 0 0>; + qcom,cpr-corner-band2-temp-core-voltage-adjustment = + <(-36000) 0 0 0>, + <(-32000) 0 0 0>, + <(-24000) 0 0 0>, + < 0 0 0 0>; + qcom,cpr-corner-band3-temp-core-voltage-adjustment = + <(-40000) 0 0 0>, + <(-36000) 0 0 0>, + <(-32000) 0 0 0>, + < 0 0 0 0>; + qcom,cpr-corner-band4-temp-core-voltage-adjustment = + <(-44000) 0 0 0>, + <(-32000) 0 0 0>, + <(-24000) 0 0 0>, + < 0 0 0 0>; + }; + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/da9210.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/da9210.txt new file mode 100644 index 0000000000000000000000000000000000000000..58065ca9e3b46892559b383927837bbaaecb1b58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/da9210.txt @@ -0,0 +1,29 @@ +* Dialog Semiconductor DA9210 Multi-phase 12A DCDC BUCK Converter + +Required properties: + +- compatible: must be "dlg,da9210" +- reg: the i2c slave address of the regulator. It should be 0x68. + +Optional properties: + +- interrupts: a reference to the DA9210 interrupt, if available. + +Any standard regulator properties can be used to configure the single da9210 +DCDC. + +Example: + + da9210@68 { + compatible = "dlg,da9210"; + reg = <0x68>; + + interrupt-parent = <...>; + interrupts = <...>; + + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <1600000>; + regulator-max-microamp = <4600000>; + regulator-boot-on; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/da9211.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/da9211.txt new file mode 100644 index 0000000000000000000000000000000000000000..27717e816e7134460a6aca8b691d51235d9bb09a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/da9211.txt @@ -0,0 +1,201 @@ +* Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 + Voltage Regulator + +Required properties: +- compatible: "dlg,da9211" or "dlg,da9212" or "dlg,da9213" or "dlg,da9223" + or "dlg,da9214" or "dlg,da9224" or "dlg,da9215" or "dlg,da9225" +- reg: I2C slave address, usually 0x68. +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + BUCKA and BUCKB. + +Optional properties: +- enable-gpios: platform gpio for control of BUCKA/BUCKB. +- Any optional property defined in regulator.txt + +Example 1) DA9211 + pmic: da9211@68 { + compatible = "dlg,da9211"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <2000000>; + regulator-max-microamp = <5000000>; + enable-gpios = <&gpio 27 0>; + }; + }; + }; + +Example 2) DA9212 + pmic: da9212@68 { + compatible = "dlg,da9212"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <2000000>; + regulator-max-microamp = <5000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <2000000>; + regulator-max-microamp = <5000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; + +Example 3) DA9213 + pmic: da9213@68 { + compatible = "dlg,da9213"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 27 0>; + }; + }; + }; + +Example 4) DA9223 + pmic: da9223@68 { + compatible = "dlg,da9223"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 27 0>; + }; + }; + }; + +Example 5) DA9214 + pmic: da9214@68 { + compatible = "dlg,da9214"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; + +Example 6) DA9224 + pmic: da9224@68 { + compatible = "dlg,da9224"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <3000000>; + regulator-max-microamp = <6000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; + +Example 7) DA9215 + pmic: da9215@68 { + compatible = "dlg,da9215"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; + +Example 8) DA9225 + pmic: da9225@68 { + compatible = "dlg,da9225"; + reg = <0x68>; + interrupts = <3 27>; + + regulators { + BUCKA { + regulator-name = "VBUCKA"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 27 0>; + }; + BUCKB { + regulator-name = "VBUCKB"; + regulator-min-microvolt = < 300000>; + regulator-max-microvolt = <1570000>; + regulator-min-microamp = <4000000>; + regulator-max-microamp = <7000000>; + enable-gpios = <&gpio 17 0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/fan53555.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/fan53555.txt new file mode 100644 index 0000000000000000000000000000000000000000..54a3f2c80e3acd085a48782881dcac9bcbf318a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/fan53555.txt @@ -0,0 +1,23 @@ +Binding for Fairchild FAN53555 regulators + +Required properties: + - compatible: one of "fcs,fan53555", "silergy,syr827", "silergy,syr828" + - reg: I2C address + +Optional properties: + - fcs,suspend-voltage-selector: declare which of the two available + voltage selector registers should be used for the suspend + voltage. The other one is used for the runtime voltage setting + Possible values are either <0> or <1> + - vin-supply: regulator supplying the vin pin + +Example: + + regulator@40 { + compatible = "fcs,fan53555"; + regulator-name = "fan53555"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&parent_reg>; + fcs,suspend-voltage-selector = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/fixed-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/fixed-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c2a6c8a15369faba1d1615288fea505220e9449 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/fixed-regulator.txt @@ -0,0 +1,35 @@ +Fixed Voltage regulators + +Required properties: +- compatible: Must be "regulator-fixed"; +- regulator-name: Defined in regulator.txt as optional, but required here. + +Optional properties: +- gpio: gpio to use for enable control +- startup-delay-us: startup time in microseconds +- enable-active-high: Polarity of GPIO is Active high +If this property is missing, the default assumed is Active low. +- gpio-open-drain: GPIO is open drain type. + If this property is missing then default assumption is false. +-vin-supply: Input supply name. + +Any property defined as part of the core regulator +binding, defined in regulator.txt, can also be used. +However a fixed voltage regulator is expected to have the +regulator-min-microvolt and regulator-max-microvolt +to be the same. + +Example: + + abc: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio1 16 0>; + startup-delay-us = <70000>; + enable-active-high; + regulator-boot-on; + gpio-open-drain; + vin-supply = <&parent_reg>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/gdsc-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/gdsc-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f31737f9aefa00d4050170f8cf7b8c8bafc6893 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/gdsc-regulator.txt @@ -0,0 +1,89 @@ +QTI Global Distributed Switch Controller (GDSC) Regulator Driver + +The GDSC driver, implemented under the regulator framework, is responsible for +safely collapsing and restoring power to peripheral and multimedia cores on +chipsets like SDM845 for power savings. + +Required properties: + - compatible: Must be "qcom,gdsc" + - regulator-name: A string used as a descriptive name for regulator outputs + - reg: The address of the GDSCR register + +Optional properties: + - parent-supply: phandle to the parent supply/regulator node + - clock-names: List of string names for core clocks + - qcom,retain-mem: Presence denotes a hardware requirement to leave the + forced core memory retention signals in the core's clock + branch control registers asserted. + - qcom,retain-periph: Presence denotes a hardware requirement to leave the + forced periph memory retention signal in the core's clock + branch control registers asserted. + - qcom,retain-regs: Presence denotes a hardware requirement to enable the + usage of retention registers which maintain their state + after the GDSC is disabled and re-enabled. + - qcom,skip-logic-collapse: Presence denotes a requirement to leave power to + the core's logic enabled. + - qcom,support-hw-trigger: Presence denotes a hardware feature to switch + on/off this regulator based on internal HW signals + to save more power. + - qcom,enable-root-clk: Presence denotes that the clocks in the "clocks" + property are required to be enabled before gdsc is + turned on and disabled before turning off gdsc. This + will be used in subsystems where reset is synchronous + and root clk is active without sw being aware of its + state. The clock-name which denotes the root clock + should be named as "core_root_clk". + - qcom,force-enable-root-clk: If set, denotes that the root clock should be + force enabled before turning on the GDSC and then be + immediately force disabled. Likewise for GDSC disable. + This is used in cases where the core root clock needs + to be force-enabled prior to turning on the core. The + clock-name which denotes the root clock should be + "core_root_clk". + - qcom,clk-dis-wait-val: Input value for CLK_DIS_WAIT controls state transition + delay after halting clock in the collapsible core. + - reg-names: Names of the bases for the above "reg" registers. + Ex. "base", "domain-addr", "sw-reset", "hw-ctrl-addr". + - qcom,no-status-check-on-disable: Do not poll the status bit when GDSC + is disabled. + - qcom,disallow-clear: Presence denotes the periph & core memory will not be + cleared, unless the required subsystem does not invoke + the api which will allow clearing the bits. + - qcom,gds-timeout: Maximum time (in usecs) that might be taken by a GDSC + to enable. + - qcom,reset-aon-logic: If present, the GPU DEMET cells need to be reset while + enabling the GX GDSC. + - vdd_parent-supply: phandle to the regulator that this GDSC gates. If + present, need to vote for a minimum operational voltage + (LOW_SVS) on the GDSC parent regulator prior to + configuring it. The vote is removed once the GDSC FSM + has latched on to the new state. + - resets: reset specifier pair consisting of phandle for the reset controller + and reset lines used by this controller. These can be + supplied only if we support qcom,skip-logic-collapse. + - reset-names: reset signal name strings sorted in the same order as the resets + property. These can be supplied only if we support + qcom,skip-logic-collapse. + - qcom,msm-bus,name: Name to use for the bus client. See [1] for details. + - qcom,msm-bus,num-cases: Must be 2 if qcom,msm-bus,name is specified. The + first case corresponds to no bus request and the second + case corresponds to a minimum bus request. See [1] for + details. + - qcom,msm-bus,num-paths: Should be 1 if qcom,msm-bus,name is specified. See + [1] for details. + - qcom,msm-bus,vectors-KBps: Required if qcom,msm-bus,name is specified. See + [1] for an explanation of the data format. + - qcom,skip-disable-before-sw-enable : Presence denotes a hardware requirement + to leave the GDSC on that has been + enabled by an entity external to HLOS. + +[1]: Documentation/devicetree/bindings/arm/msm/msm_bus.txt + +Example: + gdsc_oxili_gx: qcom,gdsc@fd8c4024 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_oxili_gx"; + parent-supply = <&pm8841_s4>; + reg = <0xfd8c4024 0x4>; + clock-names = "core_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/gpio-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/gpio-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f496159e2bb9ec3638dc6c977388c66cdb65a80 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/gpio-regulator.txt @@ -0,0 +1,43 @@ +GPIO controlled regulators + +Required properties: +- compatible : Must be "regulator-gpio". +- regulator-name : Defined in regulator.txt as optional, but required + here. +- states : Selection of available voltages and GPIO configs. + if there are no states, then use a fixed regulator + +Optional properties: +- enable-gpio : GPIO to use to enable/disable the regulator. +- gpios : GPIO group used to control voltage. +- gpios-states : gpios pin's initial states array. 0: LOW, 1: HIGH. + defualt is LOW if nothing is specified. +- startup-delay-us : Startup time in microseconds. +- enable-active-high : Polarity of GPIO is active high (default is low). +- regulator-type : Specifies what is being regulated, must be either + "voltage" or "current", defaults to voltage. + +Any property defined as part of the core regulator binding defined in +regulator.txt can also be used. + +Example: + + mmciv: gpio-regulator { + compatible = "regulator-gpio"; + + regulator-name = "mmci-gpio-supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2600000>; + regulator-boot-on; + + enable-gpio = <&gpio0 23 0x4>; + gpios = <&gpio0 24 0x4 + &gpio0 25 0x4>; + states = <1800000 0x3 + 2200000 0x2 + 2600000 0x1 + 2900000 0x0>; + + startup-delay-us = <100000>; + enable-active-high; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/hisilicon,hi655x-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/hisilicon,hi655x-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..14cfdc564159ac07c655d86903de8721db2a371a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/hisilicon,hi655x-regulator.txt @@ -0,0 +1,29 @@ +Hisilicon Hi655x Voltage regulators + +Note: +The Hi655x regulator control is managed by Hi655x PMIC. +So the node of this regulator must be child node of Hi655x +PMIC node. + +The driver uses the regulator core framework, so please also +take the bindings of regulator.txt for reference. + +The valid names for regulators are: + +LDO2_2V8 LDO7_SDIO LDO10_2V85 LDO13_1V8 LDO14_2V8 +LDO15_1V8 LDO17_2V5 LDO19_3V0 LDO21_1V8 LDO22_1V2 + +Example: + pmic: pmic@f8000000 { + compatible = "hisilicon,hi655x-pmic"; + ... + regulators { + ldo2: LDO2@a21 { + regulator-name = "LDO2_2V8"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3200000>; + regulator-enable-ramp-delay = <120>; + }; + ... + } + } diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/isl9305.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/isl9305.txt new file mode 100644 index 0000000000000000000000000000000000000000..d6e7c9ec9413c0ddb0d6c66ee25812cce1683702 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/isl9305.txt @@ -0,0 +1,36 @@ +Intersil ISL9305/ISL9305H voltage regulator + +Required properties: + +- compatible: "isil,isl9305" or "isil,isl9305h" +- reg: I2C slave address, usually 0x68. +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values being "dcd1", "dcd2", "ldo1" and "ldo2". The content of each sub-node + is defined by the standard binding for regulators; see regulator.txt. +- VINDCD1-supply: A phandle to a regulator node supplying VINDCD1. + VINDCD2-supply: A phandle to a regulator node supplying VINDCD2. + VINLDO1-supply: A phandle to a regulator node supplying VINLDO1. + VINLDO2-supply: A phandle to a regulator node supplying VINLDO2. + +Optional properties: +- Per-regulator optional properties are defined in regulator.txt + +Example + + pmic: isl9305@68 { + compatible = "isil,isl9305"; + reg = <0x68>; + + VINDCD1-supply = <&system_power>; + VINDCD2-supply = <&system_power>; + VINLDO1-supply = <&system_power>; + VINLDO2-supply = <&system_power>; + + regulators { + dcd1 { + regulator-name = "VDD_DSP"; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/lm363x-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/lm363x-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..cc5a6151d85ff40c966a88098236b9fee9a6ea74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/lm363x-regulator.txt @@ -0,0 +1,108 @@ +TI LMU LM363x regulator device tree bindings + +LM363x regulator driver supports LM3631 and LM3632. +LM3631 has five regulators and LM3632 supports three regulators. + +Required property: + - compatible: "ti,lm363x-regulator" + +Optional properties: + LM3632 has external enable pins for two LDOs. + - enable-gpios: Two GPIO specifiers for Vpos and Vneg control pins. + The first entry is Vpos, the second is Vneg enable pin. + +Child nodes: + LM3631 + - vboost + - vcont + - voref + - vpos + - vneg + + LM3632 + - vboost + - vpos + - vneg + + Optional properties of a child node: + Each sub-node should contain the constraints and initialization. + Please refer to [1]. + +Examples: Please refer to ti-lmu dt-bindings [2]. + +lm3631@29 { + compatible = "ti,lm3631"; + reg = <0x29>; + + regulators { + compatible = "ti,lm363x-regulator"; + + vboost { + regulator-name = "lcd_boost"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <6350000>; + regulator-always-on; + }; + + vcont { + regulator-name = "lcd_vcont"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + voref { + regulator-name = "lcd_voref"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + vpos { + regulator-name = "lcd_vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + + vneg { + regulator-name = "lcd_vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + regulator-boot-on; + }; + }; +}; + +lm3632@11 { + compatible = "ti,lm3632"; + reg = <0x11>; + + regulators { + compatible = "ti,lm363x-regulator"; + + /* GPIO1_16 for Vpos, GPIO1_28 is for Vneg */ + enable-gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>, + <&gpio1 28 GPIO_ACTIVE_HIGH>; + + vboost { + regulator-name = "lcd_boost"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <6400000>; + regulator-always-on; + }; + + vpos { + regulator-name = "lcd_vpos"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + vneg { + regulator-name = "lcd_vneg"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + }; +}; + +[1] ../regulator/regulator.txt +[2] ../mfd/ti-lmu.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/lp872x.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/lp872x.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca58a68ffdf1c1f830a2a6daa3149d28c6d9bf89 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/lp872x.txt @@ -0,0 +1,161 @@ +Binding for TI/National Semiconductor LP872x Driver + +Required properties: + - compatible: "ti,lp8720" or "ti,lp8725" + - reg: I2C slave address. 0x7d = LP8720, 0x7a = LP8725 + +Optional properties: + - ti,general-config: the value of LP872X_GENERAL_CFG register (u8) + (LP8720) + bit[2]: BUCK output voltage control by external DVS pin or register + 1 = external pin, 0 = bit7 of register 08h + bit[1]: sleep control by external DVS pin or register + 1 = external pin, 0 = bit6 of register 08h + bit[0]: time step unit(usec). 1 = 25, 0 = 50 + + (LP8725) + bit[7:6]: time step unit(usec). 00 = 32, 01 = 64, 10 = 128, 11 = 256 + bit[4]: BUCK2 enable control. 1 = enable, 0 = disable + bit[3]: BUCK2 output voltage register address. 1 = 0Ah, 0 = 0Bh + bit[2]: BUCK1 output voltage control by external DVS pin or register + 1 = register 08h, 0 = DVS + bit[1]: LDO sleep control. 1 = sleep mode, 0 = normal + bit[0]: BUCK1 enable control, 1 = enable, 0 = disable + + For more details, please see the datasheet. + + - ti,update-config: define it when LP872X_GENERAL_CFG register should be set + - ti,dvs-gpio: GPIO specifier for external DVS pin control of LP872x devices. + - ti,dvs-vsel: DVS selector. 0 = SEL_V1, 1 = SEL_V2. + - ti,dvs-state: initial DVS pin state. 0 = DVS_LOW, 1 = DVS_HIGH. + - enable-gpios: GPIO specifier for EN pin control of LP872x devices. + + Sub nodes for regulator_init_data + LP8720 has maximum 6 nodes. (child name: ldo1 ~ 5 and buck) + LP8725 has maximum 9 nodes. (child name: ldo1 ~ 5, lilo1,2 and buck1,2) + For more details, please see the following binding document. + (Documentation/devicetree/bindings/regulator/regulator.txt) + +Datasheet + - LP8720: http://www.ti.com/lit/ds/symlink/lp8720.pdf + - LP8725: http://www.ti.com/lit/ds/symlink/lp8725.pdf + +Example 1) LP8720 + +lp8720@7d { + compatible = "ti,lp8720"; + reg = <0x7d>; + + /* external DVS pin used, timestep is 25usec */ + ti,general-config = /bits/ 8 <0x03>; + ti,update-config; + + /* + * The dvs-gpio depends on the processor environment. + * For example, following GPIO specifier means GPIO134 in OMAP4. + */ + ti,dvs-gpio = <&gpio5 6 0>; + ti,dvs-vsel = /bits/ 8 <1>; /* SEL_V2 */ + ti,dvs-state = /bits/ 8 <1>; /* DVS_HIGH */ + + vaf: ldo1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + vmmc: ldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + vcam_io: ldo3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + vcam_core: ldo4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2850000>; + regulator-boot-on; + }; + + vcam: ldo5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + vcc: buck { + regulator-name = "VBUCK"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2300000>; + }; +}; + +Example 2) LP8725 + +lp8725@7a { + compatible = "ti,lp8725"; + reg = <0x7a>; + + /* Enable BUCK1,2, no DVS, normal LDO mode, timestep is 256usec */ + ti,general-config = /bits/ 8 <0xdd>; + ti,update-config; + + vcam_io: ldo1 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + vcam_core: ldo2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + vcam: ldo3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + }; + + vcmmb_io: ldo4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + vcmmb_core: ldo5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + vaux1: lilo1 { + regulator-name = "VAUX1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + vaux2: lilo2 { + regulator-name = "VAUX2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + vcc1: buck1 { + regulator-name = "VBUCK1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3000000>; + regulator-min-microamp = <460000>; + regulator-max-microamp = <1370000>; + regulator-boot-on; + }; + + vcc2: buck2 { + regulator-name = "VBUCK2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3000000>; + regulator-min-microamp = <460000>; + regulator-max-microamp = <1370000>; + regulator-boot-on; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/ltc3589.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/ltc3589.txt new file mode 100644 index 0000000000000000000000000000000000000000..801053036146596d8c7593a5212bc1b95e6d61ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/ltc3589.txt @@ -0,0 +1,99 @@ +Linear Technology LTC3589, LTC3589-1, and LTC3589-2 8-output regulators + +Required properties: +- compatible: "lltc,ltc3589", "lltc,ltc3589-1" or "lltc,ltc3589-2" +- reg: I2C slave address + +Required child node: +- regulators: Contains eight regulator child nodes sw1, sw2, sw3, bb-out, + ldo1, ldo2, ldo3, and ldo4, specifying the initialization data as + documented in Documentation/devicetree/bindings/regulator/regulator.txt. + +Each regulator is defined using the standard binding for regulators. The +nodes for sw1, sw2, sw3, bb-out, ldo1, and ldo2 additionally need to specify +the resistor values of their external feedback voltage dividers: + +Required properties (not on ldo3, ldo4): +- lltc,fb-voltage-divider: An array of two integers containing the resistor + values R1 and R2 of the feedback voltage divider in ohms. + +Regulators sw1, sw2, sw3, and ldo2 can regulate the feedback reference from +0.3625 V to 0.75 V in 12.5 mV steps. The output voltage thus ranges between +0.3625 * (1 + R1/R2) V and 0.75 * (1 + R1/R2) V. Regulators bb-out and ldo1 +have a fixed 0.8 V reference and thus output 0.8 * (1 + R1/R2) V. The ldo3 +regulator is fixed to 1.8 V on LTC3589 and to 2.8 V on LTC3589-1,2. The ldo4 +regulator can output between 1.8 V and 3.3 V on LTC3589 and between 1.2 V +and 3.2 V on LTC3589-1,2 in four steps. The ldo1 standby regulator can not +be disabled and thus should have the regulator-always-on property set. + +Example: + + ltc3589: pmic@34 { + compatible = "lltc,ltc3589-1"; + reg = <0x34>; + + regulators { + sw1_reg: sw1 { + regulator-min-microvolt = <591930>; + regulator-max-microvolt = <1224671>; + lltc,fb-voltage-divider = <100000 158000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <704123>; + regulator-max-microvolt = <1456803>; + lltc,fb-voltage-divider = <180000 191000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-min-microvolt = <1341250>; + regulator-max-microvolt = <2775000>; + lltc,fb-voltage-divider = <270000 100000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + bb_out_reg: bb-out { + regulator-min-microvolt = <3387341>; + regulator-max-microvolt = <3387341>; + lltc,fb-voltage-divider = <511000 158000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1_reg: ldo1 { + regulator-min-microvolt = <1306329>; + regulator-max-microvolt = <1306329>; + lltc,fb-voltage-divider = <100000 158000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = <704123>; + regulator-max-microvolt = <1456806>; + lltc,fb-voltage-divider = <180000 191000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-boot-on; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3200000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/ltc3676.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/ltc3676.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4eb366ce18ce2e9f9fbfa7db166c6c3abaa8d8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/ltc3676.txt @@ -0,0 +1,94 @@ +Linear Technology LTC3676 8-output regulators + +Required properties: +- compatible: "lltc,ltc3676" +- reg: I2C slave address + +Required child node: +- regulators: Contains eight regulator child nodes sw1, sw2, sw3, sw4, + ldo1, ldo2, ldo3, and ldo4, specifying the initialization data as + documented in Documentation/devicetree/bindings/regulator/regulator.txt. + +Each regulator is defined using the standard binding for regulators. The +nodes for sw1, sw2, sw3, sw4, ldo1, ldo2 and ldo4 additionally need to specify +the resistor values of their external feedback voltage dividers: + +Required properties (not on ldo3): +- lltc,fb-voltage-divider: An array of two integers containing the resistor + values R1 and R2 of the feedback voltage divider in ohms. + +Regulators sw1, sw2, sw3, sw4 can regulate the feedback reference from: +412.5mV to 800mV in 12.5 mV steps. The output voltage thus ranges between +0.4125 * (1 + R1/R2) V and 0.8 * (1 + R1/R2) V. + +Regulators ldo1, ldo2, and ldo4 have a fixed 0.725 V reference and thus output +0.725 * (1 + R1/R2) V. The ldo3 regulator is fixed to 1.8 V. The ldo1 standby +regulator can not be disabled and thus should have the regulator-always-on +property set. + +Example: + + ltc3676: pmic@3c { + compatible = "lltc,ltc3676"; + reg = <0x3c>; + + regulators { + sw1_reg: sw1 { + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <1308000>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1033310>; + regulator-max-microvolt = <200400>; + lltc,fb-voltage-divider = <301000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-min-microvolt = <674400>; + regulator-max-microvolt = <130800>; + lltc,fb-voltage-divider = <127000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <868310>; + regulator-max-microvolt = <168400>; + lltc,fb-voltage-divider = <221000 200000>; + regulator-ramp-delay = <7000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = <2490375>; + regulator-max-microvolt = <2490375>; + lltc,fb-voltage-divider = <487000 200000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <3023250>; + regulator-max-microvolt = <3023250>; + lltc,fb-voltage-divider = <634000 200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max1586-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max1586-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..c050c1744cb885f32e71c31d963906fd1bd2ec54 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max1586-regulator.txt @@ -0,0 +1,28 @@ +Maxim MAX1586 voltage regulator + +Required properties: +- compatible: must be "maxim,max1586" +- reg: I2C slave address, usually 0x14 +- v3-gain: integer specifying the V3 gain as per datasheet + (1 + R24/R25 + R24/185.5kOhm) +- any required generic properties defined in regulator.txt + +Example: + + i2c_master { + max1586@14 { + compatible = "maxim,max1586"; + reg = <0x14>; + v3-gain = <1000000>; + + regulators { + vcc_core: v3 { + regulator-name = "vcc_core"; + regulator-compatible = "Output_V3"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1705000>; + regulator-always-on; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max77686.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max77686.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9f7578ca09a2babc5c0a87e75bde6eb0ee2af37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max77686.txt @@ -0,0 +1,71 @@ +Binding for Maxim MAX77686 regulators + +This is a part of the device tree bindings of MAX77686 multi-function device. +More information can be found in ../mfd/max77686.txt file. + +The MAX77686 PMIC has 9 high-efficiency Buck and 26 Low-DropOut (LDO) +regulators that can be controlled over I2C. + +Following properties should be present in main device node of the MFD chip. + +Optional node: +- voltage-regulators : The regulators of max77686 have to be instantiated + under subnode named "voltage-regulators" using the following format. + + regulator_name { + regulator-compatible = LDOn/BUCKn + standard regulator constraints.... + }; + refer Documentation/devicetree/bindings/regulator/regulator.txt + + The regulator node's name should be initialized with a string +to get matched with their hardware counterparts as follow: + + -LDOn : for LDOs, where n can lie in range 1 to 26. + example: LDO1, LDO2, LDO26. + -BUCKn : for BUCKs, where n can lie in range 1 to 9. + example: BUCK1, BUCK5, BUCK9. + + Regulators which can be turned off during system suspend: + -LDOn : 2, 6-8, 10-12, 14-16, + -BUCKn : 1-4. + Use standard regulator bindings for it ('regulator-off-in-suspend'). + + LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable + control. To turn this feature on this property must be added to the regulator + sub-node: + - maxim,ena-gpios : one GPIO specifier enable control (the gpio + flags are actually ignored and always + ACTIVE_HIGH is used) + +Example: + + max77686: pmic@9 { + compatible = "maxim,max77686"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 IRQ_TYPE_NONE>; + reg = <0x09>; + + voltage-regulators { + ldo11_reg: LDO11 { + regulator-name = "vdd_ldo11"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + + buck9_reg: BUCK9 { + regulator-name = "CAM_ISP_CORE_1.2V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max77802.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max77802.txt new file mode 100644 index 0000000000000000000000000000000000000000..b82943d836770abd95819ab13236f3599f700407 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max77802.txt @@ -0,0 +1,111 @@ +Binding for Maxim MAX77802 regulators + +This is a part of device tree bindings of MAX77802 multi-function device. +More information can be found in bindings/mfd/max77802.txt file. + +The MAX77802 PMIC has 10 high-efficiency Buck and 32 Low-dropout (LDO) +regulators that can be controlled over I2C. + +Following properties should be present in main device node of the MFD chip. + +Optional properties: +- inb1-supply: The input supply for BUCK1 +- inb2-supply: The input supply for BUCK2 +- inb3-supply: The input supply for BUCK3 +- inb4-supply: The input supply for BUCK4 +- inb5-supply: The input supply for BUCK5 +- inb6-supply: The input supply for BUCK6 +- inb7-supply: The input supply for BUCK7 +- inb8-supply: The input supply for BUCK8 +- inb9-supply: The input supply for BUCK9 +- inb10-supply: The input supply for BUCK10 +- inl1-supply: The input supply for LDO8 and LDO15 +- inl2-supply: The input supply for LDO17, LDO27, LDO30 and LDO35 +- inl3-supply: The input supply for LDO3, LDO5, LDO6 and LDO7 +- inl4-supply: The input supply for LDO10, LDO11, LDO13 and LDO14 +- inl5-supply: The input supply for LDO9 and LDO19 +- inl6-supply: The input supply for LDO4, LDO21, LDO24 and LDO33 +- inl7-supply: The input supply for LDO18, LDO20, LDO28 and LDO29 +- inl9-supply: The input supply for LDO12, LDO23, LDO25, LDO26, LDO32 and LDO34 +- inl10-supply: The input supply for LDO1 and LDO2 + +Optional nodes: +- regulators : The regulators of max77802 have to be instantiated + under subnode named "regulators" using the following format. + + regulator-name { + standard regulator constraints.... + }; + refer Documentation/devicetree/bindings/regulator/regulator.txt + +The regulator node name should be initialized with a string to get matched +with their hardware counterparts as follow. The valid names are: + + -LDOn : for LDOs, where n can lie in ranges 1-15, 17-21, 23-30 + and 32-35. + example: LDO1, LDO2, LDO35. + -BUCKn : for BUCKs, where n can lie in range 1 to 10. + example: BUCK1, BUCK5, BUCK10. + +The max77802 regulator supports two different operating modes: Normal and Low +Power Mode. Some regulators support the modes to be changed at startup or by +the consumers during normal operation while others only support to change the +mode during system suspend. The standard regulator suspend states binding can +be used to configure the regulator operating mode. + +The regulators that support the standard "regulator-initial-mode" property, +changing their mode during normal operation are: LDOs 1, 3, 20 and 21. + +The possible values for "regulator-initial-mode" and "regulator-mode" are: + 1: Normal regulator voltage output mode. + 3: Low Power which reduces the quiescent current down to only 1uA + +The valid modes list is defined in the dt-bindings/regulator/maxim,max77802.h +header and can be included by device tree source files. + +The standard "regulator-mode" property can only be used for regulators that +support changing their mode to Low Power Mode during suspend. These regulators +are: BUCKs 2-4 and LDOs 1-35. Also, it only takes effect if the regulator has +been enabled for the given suspend state using "regulator-on-in-suspend" and +has not been disabled for that state using "regulator-off-in-suspend". + +Example: + + max77802@9 { + compatible = "maxim,max77802"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 0>; + reg = <0x09>; + #address-cells = <1>; + #size-cells = <0>; + + inb1-supply = <&parent_reg>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "vdd_1v0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + regulator-initial-mode = ; + }; + + ldo11_reg: LDO11 { + regulator-name = "vdd_ldo11"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + regulator-always-on; + regulator-state-mem { + regulator-on-in-suspend; + regulator-mode = ; + }; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max8660.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max8660.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ba994d8a142c7e23b824edafd5f0be45d424a18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max8660.txt @@ -0,0 +1,47 @@ +Maxim MAX8660 voltage regulator + +Required properties: +- compatible: must be one of "maxim,max8660", "maxim,max8661" +- reg: I2C slave address, usually 0x34 +- any required generic properties defined in regulator.txt + +Example: + + i2c_master { + max8660@34 { + compatible = "maxim,max8660"; + reg = <0x34>; + + regulators { + regulator@0 { + regulator-compatible= "V3(DCDC)"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1800000>; + }; + + regulator@1 { + regulator-compatible= "V4(DCDC)"; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1800000>; + }; + + regulator@2 { + regulator-compatible= "V5(LDO)"; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2000000>; + }; + + regulator@3 { + regulator-compatible= "V6(LDO)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + regulator@4 { + regulator-compatible= "V7(LDO)"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max8907.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max8907.txt new file mode 100644 index 0000000000000000000000000000000000000000..371eccd1cd6897b0395e53ad6a717b964722ba34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max8907.txt @@ -0,0 +1,69 @@ +MAX8907 regulator + +Required properties: +- compatible: "maxim,max8907" +- reg: I2C slave address +- interrupts: The interrupt output of the controller +- mbatt-supply: The input supply for MBATT, BBAT, SDBY, VRTC. +- in-v1-supply: The input supply for SD1. +- in-v2-supply: The input supply for SD2. +- in-v3-supply: The input supply for SD3. +- in1-supply: The input supply for LDO1. +... +- in20-supply: The input supply for LDO20. +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name (or the deprecated + regulator-compatible property if present), with valid values listed below. + The content of each sub-node is defined by the standard binding for + regulators; see regulator.txt. + +Optional properties: +- maxim,system-power-controller: Boolean property indicating that the PMIC + controls the overall system power. + +The valid names for regulators are: + + sd1, sd2, sd3, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, ldo8, ldo9, ldo10, + ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19, ldo20, out5v, + out33v, bbat, sdby, vrtc. + +Example: + + max8907@3c { + compatible = "maxim,max8907"; + reg = <0x3c>; + interrupts = <0 86 0x4>; + + maxim,system-power-controller; + + mbatt-supply = <&some_reg>; + in-v1-supply = <&mbatt_reg>; + ... + in1-supply = <&mbatt_reg>; + ... + + regulators { + mbatt_reg: mbatt { + regulator-name = "vbat_pmu"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + sd1 { + regulator-name = "nvvdd_sv1,vdd_cpu_pmu"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-always-on; + }; + + sd2 { + regulator-name = "nvvdd_sv2,vdd_core"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; +... + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max8925-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max8925-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..0057695aae8fac441e4658ffadf5a7f113eceeed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max8925-regulator.txt @@ -0,0 +1,40 @@ +Max8925 Voltage regulators + +Required nodes: +-nodes: + - SDV1 for SDV SDV1 + - SDV2 for SDV SDV2 + - SDV3 for SDV SDV3 + - LDO1 for LDO LDO1 + - LDO2 for LDO LDO2 + - LDO3 for LDO LDO3 + - LDO4 for LDO LDO4 + - LDO5 for LDO LDO5 + - LDO6 for LDO LDO6 + - LDO7 for LDO LDO7 + - LDO8 for LDO LDO8 + - LDO9 for LDO LDO9 + - LDO10 for LDO LDO10 + - LDO11 for LDO LDO11 + - LDO12 for LDO LDO12 + - LDO13 for LDO LDO13 + - LDO14 for LDO LDO14 + - LDO15 for LDO LDO15 + - LDO16 for LDO LDO16 + - LDO17 for LDO LDO17 + - LDO18 for LDO LDO18 + - LDO19 for LDO LDO19 + - LDO20 for LDO LDO20 + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt + +Example: + + SDV1 { + regulator-min-microvolt = <637500>; + regulator-max-microvolt = <1425000>; + regulator-boot-on; + regulator-always-on; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max8952.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max8952.txt new file mode 100644 index 0000000000000000000000000000000000000000..866fcdd0f4ebd2abcea051aed3e758172604baf5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max8952.txt @@ -0,0 +1,52 @@ +Maxim MAX8952 voltage regulator + +Required properties: +- compatible: must be equal to "maxim,max8952" +- reg: I2C slave address, usually 0x60 +- max8952,dvs-mode-microvolt: array of 4 integer values defining DVS voltages + in microvolts. All values must be from range <770000, 1400000> +- any required generic properties defined in regulator.txt + +Optional properties: +- max8952,vid-gpios: array of two GPIO pins used for DVS voltage selection +- max8952,en-gpio: GPIO used to control enable status of regulator +- max8952,default-mode: index of default DVS voltage, from <0, 3> range +- max8952,sync-freq: sync frequency, must be one of following values: + - 0: 26 MHz + - 1: 13 MHz + - 2: 19.2 MHz + Defaults to 26 MHz if not specified. +- max8952,ramp-speed: voltage ramp speed, must be one of following values: + - 0: 32mV/us + - 1: 16mV/us + - 2: 8mV/us + - 3: 4mV/us + - 4: 2mV/us + - 5: 1mV/us + - 6: 0.5mV/us + - 7: 0.25mV/us + Defaults to 32mV/us if not specified. +- any available generic properties defined in regulator.txt + +Example: + + vdd_arm_reg: pmic@60 { + compatible = "maxim,max8952"; + reg = <0x60>; + + /* max8952-specific properties */ + max8952,vid-gpios = <&gpx0 3 0>, <&gpx0 4 0>; + max8952,en-gpio = <&gpx0 1 0>; + max8952,default-mode = <0>; + max8952,dvs-mode-microvolt = <1250000>, <1200000>, + <1050000>, <950000>; + max8952,sync-freq = <0>; + max8952,ramp-speed = <0>; + + /* generic regulator properties */ + regulator-name = "vdd_arm"; + regulator-min-microvolt = <770000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max8973-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max8973-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..c2c68fcc1b41b21ef20dd0a671d281eea30c0763 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max8973-regulator.txt @@ -0,0 +1,52 @@ +* Maxim MAX8973 Voltage Regulator + +Required properties: + +- compatible: must be one of following: + "maxim,max8973" + "maxim,max77621". +- reg: the i2c slave address of the regulator. It should be 0x1b. + +Any standard regulator properties can be used to configure the single max8973 +DCDC. + +Optional properties: + +-maxim,externally-enable: boolean, externally control the regulator output + enable/disable. +-maxim,enable-gpio: GPIO for enable control. If the valid GPIO is provided + then externally enable control will be considered. +-maxim,dvs-gpio: GPIO which is connected to DVS pin of device. +-maxim,dvs-default-state: Default state of GPIO during initialisation. + 1 for HIGH and 0 for LOW. +-maxim,enable-remote-sense: boolean, enable reote sense. +-maxim,enable-falling-slew-rate: boolean, enable falling slew rate. +-maxim,enable-active-discharge: boolean: enable active discharge. +-maxim,enable-frequency-shift: boolean, enable 9% frequency shift. +-maxim,enable-bias-control: boolean, enable bias control. By enabling this + startup delay can be reduce to 20us from 220us. +-maxim,enable-etr: boolean, enable Enhanced Transient Response. +-maxim,enable-high-etr-sensitivity: boolean, Enhanced transient response + circuit is enabled and set for high sensitivity. If this + property is available then etr will be enable default. + +Enhanced transient response (ETR) will affect the configuration of CKADV. + +-junction-warn-millicelsius: u32, junction warning temperature threshold + in millicelsius. If die temperature crosses this level then + device generates the warning interrupts. + +Please note that thermal functionality is only supported on MAX77621. The +supported threshold warning temperature for MAX77621 are 120 degC and 140 degC. + +Example: + + max8973@1b { + compatible = "maxim,max8973"; + reg = <0x1b>; + + regulator-min-microvolt = <935000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/max8997-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/max8997-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..6fe825b8ac1b2335cefc50ab23b6677552087998 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/max8997-regulator.txt @@ -0,0 +1,144 @@ +* Maxim MAX8997 Voltage and Current Regulator + +The Maxim MAX8997 is a multi-function device which includes voltage and +current regulators, rtc, charger controller and other sub-blocks. It is +interfaced to the host controller using a i2c interface. Each sub-block is +addressed by the host system using different i2c slave address. This document +describes the bindings for 'pmic' sub-block of max8997. + +Required properties: +- compatible: Should be "maxim,max8997-pmic". +- reg: Specifies the i2c slave address of the pmic block. It should be 0x66. + +- max8997,pmic-buck1-dvs-voltage: A set of 8 voltage values in micro-volt (uV) + units for buck1 when changing voltage using gpio dvs. Refer to [1] below + for additional information. + +- max8997,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV) + units for buck2 when changing voltage using gpio dvs. Refer to [1] below + for additional information. + +- max8997,pmic-buck5-dvs-voltage: A set of 8 voltage values in micro-volt (uV) + units for buck5 when changing voltage using gpio dvs. Refer to [1] below + for additional information. + +[1] If none of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional + property is specified, the 'max8997,pmic-buck[1/2/5]-dvs-voltage' + property should specify atleast one voltage level (which would be a + safe operating voltage). + + If either of the 'max8997,pmic-buck[1/2/5]-uses-gpio-dvs' optional + property is specified, then all the eight voltage values for the + 'max8997,pmic-buck[1/2/5]-dvs-voltage' should be specified. + +Optional properties: +- interrupts: Interrupt specifiers for two interrupt sources. + - First interrupt specifier is for 'irq1' interrupt. + - Second interrupt specifier is for 'alert' interrupt. +- max8997,pmic-buck1-uses-gpio-dvs: 'buck1' can be controlled by gpio dvs. +- max8997,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs. +- max8997,pmic-buck5-uses-gpio-dvs: 'buck5' can be controlled by gpio dvs. + +Additional properties required if either of the optional properties are used: +- max8997,pmic-ignore-gpiodvs-side-effect: When GPIO-DVS mode is used for + multiple bucks, changing the voltage value of one of the bucks may affect + that of another buck, which is the side effect of the change (set_voltage). + Use this property to ignore such side effects and change the voltage. + +- max8997,pmic-buck125-default-dvs-idx: Default voltage setting selected from + the possible 8 options selectable by the dvs gpios. The value of this + property should be between 0 and 7. If not specified or if out of range, the + default value of this property is set to 0. + +- max8997,pmic-buck125-dvs-gpios: GPIO specifiers for three host gpio's used + for dvs. The format of the gpio specifier depends in the gpio controller. + +Regulators: The regulators of max8997 that have to be instantiated should be +included in a sub-node named 'regulators'. Regulator nodes included in this +sub-node should be of the format as listed below. + + regulator_name { + standard regulator bindings here + }; + +The following are the names of the regulators that the max8997 pmic block +supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number +as per the datasheet of max8997. + + - LDOn + - valid values for n are 1 to 18 and 21 + - Example: LDO0, LD01, LDO2, LDO21 + - BUCKn + - valid values for n are 1 to 7. + - Example: BUCK1, BUCK2, BUCK3, BUCK7 + + - ENVICHG: Battery Charging Current Monitor Output. This is a fixed + voltage type regulator + + - ESAFEOUT1: (ldo19) + - ESAFEOUT2: (ld020) + + - CHARGER_CV: main battery charger voltage control + - CHARGER: main battery charger current control + - CHARGER_TOPOFF: end of charge current threshold level + +The bindings inside the regulator nodes use the standard regulator bindings +which are documented elsewhere. + +Example: + + max8997_pmic@66 { + compatible = "maxim,max8997-pmic"; + interrupt-parent = <&wakeup_eint>; + reg = <0x66>; + interrupts = <4 0>, <3 0>; + + max8997,pmic-buck1-uses-gpio-dvs; + max8997,pmic-buck2-uses-gpio-dvs; + max8997,pmic-buck5-uses-gpio-dvs; + + max8997,pmic-ignore-gpiodvs-side-effect; + max8997,pmic-buck125-default-dvs-idx = <0>; + + max8997,pmic-buck125-dvs-gpios = <&gpx0 0 1 0 0>, /* SET1 */ + <&gpx0 1 1 0 0>, /* SET2 */ + <&gpx0 2 1 0 0>; /* SET3 */ + + max8997,pmic-buck1-dvs-voltage = <1350000>, <1300000>, + <1250000>, <1200000>, + <1150000>, <1100000>, + <1000000>, <950000>; + + max8997,pmic-buck2-dvs-voltage = <1100000>, <1100000>, + <1100000>, <1100000>, + <1000000>, <1000000>, + <1000000>, <1000000>; + + max8997,pmic-buck5-dvs-voltage = <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ABB_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDD_ALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "VDD_ARM_1.2V"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/mem-acc-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/mem-acc-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a681f4854b3af6b8749d1088d4793a646a9820d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/mem-acc-regulator.txt @@ -0,0 +1,288 @@ +Qualcomm Technologies, Inc. Memory Accelerator + +Memory accelerator configures the power-mode (corner) for the +accelerator. + +Required properties: +- compatible: Must be "qcom,mem-acc-regulator" +- regulator-name: A string used to describe the regulator +- regulator-min-microvolt: Minimum corner value as min constraint, which + should be 1 for SVS corner +- regulator-max-microvolt: Maximum corner value as max constraint, which + should be 4 for SUPER_TURBO or 3 for TURBO + +Optional properties: +- reg: Register addresses for acc-sel-l1, acc-sel-l2 control, acc-en, + MEM ACC eFuse address, acc-l1-custom , acc-l2-custom, + mem-acc-type1, mem-acc-type2, mem-acc-type3, mem-acc-type4, + mem-acc-type5 and mem-acc-type6. +- reg-names: Register names. Must be "acc-sel-l1", + "acc-sel-l2", "acc-en", "efuse_addr", + "acc-l1-custom", "acc-l2-custom", "mem-acc-type1", + "mem-acc-type2", "mem-acc-type3", "mem-acc-type4", + "mem-acc-type5", "mem-acc-type6". + A given mem-acc-regulator driver must have "acc-sel-l1" or + "acc-sel-l2" or "mem-acc-type*" reg-names property and + related register address property. +- qcom,corner-acc-map Array which maps the APC (application processor) + corner value to the accelerator corner. The number of elements + in this property defines the number of accelerator corners. + Either qcom,corner-acc-map property or qcom,cornerX-reg-config + properties should be specified. +- qcom,acc-en-bit-pos Array which specifies bit positions in the + 'acc-en' register. Setting these bits forces the + the acclerator to use the corner value specified + in the 'acc-sel-l1' and 'acc-sel-l2' register. +- qcom,acc-sel-l1-bit-size Integer which specifies the number of bits in + the 'acc-sel-l1' register which define each L1 + select parameter. If this property is not + specified, then a default value of 2 is assumed. +- qcom,acc-sel-l1-bit-pos Array which specifies bit positions in the + 'acc-sel-l1' register. Each element in this array + is the LSB of an N-bit value where 'N' is + defined by the qcom,acc-sel-l1-bit-size + property. This N-bit value specifies the corner + value used by the accelerator for the L1 cache. +- qcom,acc-sel-l2-bit-size Integer which specifies the number of bits in + the 'acc-sel-l2' register which define each L2 + select parameter. If this property is not + specified, then a default value of 2 is assumed. +- qcom,acc-sel-l2-bit-pos Array which specifies bit positions in the + 'acc-sel-l2' register. Each element in this array + is the LSB of an N-bit value where 'N' is + defined by the qcom,acc-sel-l2-bit-size + property. This N-bit value specifies the corner + value used by the accelerator for the L2 cache. +- qcom,l1-acc-custom-data: Array which maps APC corner values to L1 ACC custom data values. + The corresponding custom data is written into the custom register + while switching between APC corners. The custom register address + is specified by "acc-11-custom" reg-property. The length of the array + should be equal to number of APC corners. +- qcom,l2-acc-custom-data: Array which maps APC corner values to L2 ACC custom data values. + The corresponding custom data is written into the custom register + while switching between APC corners. The custom register address + is specified by "acc-l2-custom" reg-property. The length of the array + should be equal to number of APC corners. +- qcom,override-acc-fuse-sel: Array of 4 elements which specify the way to read the override fuse. + The override fuse value is used by the qcom,override-fuse-version-map + to identify the correct set of override properties. + The 4 elements with index [0..4] are: + [0] => the fuse row number of the selector + [1] => LSB bit position of the bits + [2] => number of bits + [3] => fuse reading method, 0 for direct reading or 1 for SCM reading +- qcom,override-fuse-version-map: Array of integers which each match to a override fuse value. + Any element in a tuple may use the value 0xffffffff as a wildcard. + The index of the first value (in the array) which matches the override fuse + is used to select the right tuples from the other override properties. +- qcom,override-corner-acc-map: Array of tuples which overrides the existing acc-corner map + (specified by qcom,corner-acc-map) with corner values selected + from this property. "qcom,override-corner-acc-map" must contain the + same number of tuples as "qcom,override-fuse-version-map". These tuples + are then mapped one-to-one in the order specified. If the + "qcom,override-fuse-version-map" property is not specified, then + "qcom,override-corner-acc-map" must contain a single tuple which is then + applied unconditionally. +- qcom,override-l1-acc-custom-data: Array of tuples of which overrides the existing l1-acc-custom data + (specified by qcom,l1-acc-custom-data), with values specified in this property. + The corresponding custom data is written into the custom register while + switching between APC corners. The custom register address is specified by + "acc-11-custom" reg-property. This property can only be specified if the + "qcom,l1-acc-custom-data" is already defined. If the + "qcom,override-fuse-version-map" property is specified, then + qcom,override-l1-acc-custom-data must contain the same number of tuples + as "qcom,override-fuse-version-map". These tuples are then mapped one-to-one + in the order specified. If the qcom,override-fuse-version-map property is + not specified, then "qcom,override-l1-acc-custom-data" must contain a single + tuple which is then applied unconditionally. +- qcom,override-l2-acc-custom-data: Array of tuples of which overrides the existing l1-acc-custom data + (specified by qcom,l2-acc-custom-data), with values specified in this property. + The corresponding custom data is written into the custom register while + switching between APC corners. The custom register address is specified by + "acc-12-custom" reg-property. This property can only be specified if the + "qcom,l2-acc-custom-data" is already defined. If the + "qcom,override-fuse-version-map" property is specified, then + "qcom,override-l2-acc-custom-data" must contain the same number of tuples + as "qcom,override-fuse-version-map". These tuples are then mapped one-to-one + in the order specified. If the qcom,override-fuse-version-map property is + not specified, then "qcom,override-l2-acc-custom-data" must contain a single + tuple which is then applied unconditionally. +- qcom,mem-acc-type1: Array which specifies the value to be written to the mem acc type1 register for each fuse + corner, from the lowest fuse corner to the highest fuse corner. The length of the array + must be equal to the number of APC fuse corners. This property must be present if reg names + specifies mem-acc-type1. +- qcom,mem-acc-type2: Same as qcom,mem-acc-type1 except for mem acc type2 register. +- qcom,mem-acc-type3: Same as qcom,mem-acc-type1 except for mem acc type3 register. +- qcom,mem-acc-type4: Same as qcom,mem-acc-type1 except for mem acc type4 register. +- qcom,mem-acc-type5: Same as qcom,mem-acc-type1 except for mem acc type5 register. +- qcom,mem-acc-type6: Same as qcom,mem-acc-type1 except for mem acc type6 register. +- qcom,acc-reg-addr-list: Array of register addresses which need to be programmed during any corner switch. + This property can be used when multi register configuration is needed during a corner switch. +- qcom,acc-init-reg-config: Array of tuples specify the multi register configuration sequence need to be programmed + one time during device boot. + The format of each tuple as below: + + Where register-address-index is used as an index in to qcom,acc-reg-addr-list property + to get the required register address and the value is programmed in to the corresponding + mapped register address. This property is required if qcom,acc-corner-addr-val-map + property specified. +- qcom,cornerX-reg-config: Array of tuples specify the multi register configuration sequence need to be programmed + when switching from acc corner X to any other corner. The possible values for X are {1, N}, + where N is the value defined in qcom,num-acc-corners. + The format of each tuple as below: + + Where register-address-index is used as an index in to qcom,acc-reg-addr-list property + to get the required register address and the value is programmed in to the corresponding + mapped register address. Same index can be used multiple times when the register is + required to configure multiple times with different values in the sequence. + The number of register configuration sequences should be equal to N, where N is the + value specified in qcom,num-acc-corners property. Also, the number of tuples in each + register configuration sequence should be same and must be equal to the maximum required + register configurations in any sequence. The invalid register configuration can be + specified as <(-1) (-1)>. This property can only be specified when qcom,acc-corner-addr-val-map + property already defined. Either this property or qcom,corner-acc-map should be specified. +- qcom,num-acc-corners: The number of acc corners supported. This property is required if qcom,cornerX-reg-config + property specified. +- qcom,boot-acc-corner: The acc corner used during device boot. This property is required if qcom,cornerX-reg-config + property specified. +- qcom,override-cornerX-reg-config: A grouping of register configuration sequence lists. Each list is same as + the qcom,cornerX-reg-config property. The possible values for X are {1, N} where N is + the value defined in qcom,num-acc-corners. This property is used to specify the different + register configuration sequence lists and select one list among them based on the selected + index in qcom,override-fuse-version-map property. The selected list overrides the existing + register configuration sequence list specified in "qcom,cornerX-reg-config". If the + "qcom,override-fuse-version-map" property is specified, then + "qcom,override-cornerX-reg-config" must contain the same number of register + configuration sequence lists as the number of tuples in "qcom,override-fuse-version-map". + These register configuration sequence lists are then mapped one-to-one + in the order specified. If the qcom,override-fuse-version-map property is + not specified, then "qcom,override-cornerX-reg-config" must contain a single + register configuration sequence list which is then applied unconditionally. + This property can only be specified if qcom,cornerX-reg-config property is already defined. +- qcom,override-acc-range-fuse-list: Array of tuples define the selection parameters used for selecting the override + mem-acc configuration. The fused values for these selection parameters are used by the + qcom,override-fuse-range-map to identify the correct set of override properties. + Each tuple contains 4 elements as defined below: + [0] => the fuse row number of the selector + [1] => LSB bit position of the bits + [2] => number of bits + [3] => fuse reading method, 0 for direct reading or 1 for SCM reading +- qcom,override-fuse-range-map: Array of tuples where each tuple specifies the allowed range for all the selection parameters + defined in qcom,override-acc-range-fuse-list. The fused values of these selection parameters + are compared against their allowed range in each tuple starting from 0th tuple and use the + first matched tuple index to select the right tuples from the other override properties. + Either qcom,override-fuse-range-map or qcom,override-fuse-version-map is used to select + the override configuration. The qcom,override-fuse-range-map is used if both the + properties are specified. + +mem_acc_vreg_corner: regulator@fd4aa044 { + compatible = "qcom,mem-acc-regulator"; + reg = <0xfd4aa048 0x1>, <0xfd4aa044 0x1>, <0xfd4af000 0x1>, + <0x58000 0x1000>, <0x01942124 0x4>, <0xf900d084 1>, + <0xf900d088 1>, <0xf900d08c 1>, <0xf900d090 1>; + reg-names = "acc-en", "acc-sel-l1" , "acc-sel-l2", + "efuse_addr", "acc-l2-custom", "mem-acc-type1", + "mem-acc-type2", "mem-acc-type3", "mem-acc-type4"; + regulator-name = "mem_acc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <3>; + + qcom,acc-en-bit-pos = <0>; + qcom,acc-sel-l1-bit-pos = <0>; + qcom,acc-sel-l2-bit-pos = <0>; + qcom,acc-sel-l1-bit-size = <2>; + qcom,acc-sel-l2-bit-size = <2>; + qcom,corner-acc-map = <0 1 3>; + qcom,l2-acc-custom-data = <0x0 0x3000 0x3000>; + + qcom,override-acc-fuse-sel = <0 52 2 0>; + qcom,override-fuse-version-map = <0>, + <2>, + <(-1)>; + qcom,override-acc-range-fuse-list = + <37 40 3 0>, + <36 30 8 0>; + qcom,override-fuse-range-map = + <0 0>, < 0 0>, <49 63>, + <1 1>, < 0 0>, <50 63>, + <0 1>, < 95 255>, < 0 63>; + qcom,override-corner-acc-map = <0 0 1>, + <0 1 2>, + <0 1 1>; + qcom,override-l2-acc-custom-data = <0x0 0x0 0x3000>, + <0x0 0x3000 0x3000>, + <0x0 0x0 0x0>; + qcom,mem-acc-type1 = <0x02 0x02 0x00>; + qcom,mem-acc-type2 = <0x02 0x02 0x00>; + qcom,mem-acc-type3 = <0x02 0x02 0x00>; + qcom,mem-acc-type4 = <0x02 0x02 0x00>; + + qcom,acc-reg-addr-list = <0x01942130 0x01942124 0x01942120>; + qcom,acc-init-reg-config = <1 0x55> <2 0x02>; + + qcom,num-acc-corners = <3>; + qcom,boot-acc-corner = <2>; + qcom,corner1-reg-config = + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 1 -> 1 */ + < 1 0x155>, < 2 0x0>, < 3 0x155>, /* 1 -> 2 */ + < 1 0x0>, < 2 0x155>, <(-1) (-1)>; /* 1 -> 3 */ + + qcom,corner2-reg-config = + < 1 0x155>, <(-1) (-1)>, <(-1) (-1)>, /* 2 -> 1 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 2 -> 2 */ + < 1 0x155>, < 2 0x0>, < 3 0x155>; /* 2 -> 3 */ + + qcom,corner3-reg-config = + < 1 0x0>, < 2 0x155>, <(-1) (-1)>, /* 3 -> 1 */ + < 1 0x155>, <(-1) (-1)>, <(-1) (-1)>, /* 3 -> 2 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>; /* 3 -> 3 */ + + qcom,override-corner1-reg-config = + /* 1st fuse version tuple matched */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 1 -> 1 */ + < 1 0x155>, < 2 0x0>, < 3 0x155>, /* 1 -> 2 */ + < 1 0x0>, < 2 0x155>, <(-1) (-1)>, /* 1 -> 3 */ + + /* 2nd fuse version tuple matched */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 1 -> 1 */ + < 1 0x155>, < 2 0x0>, < 3 0x155>, /* 1 -> 2 */ + < 1 0x0>, < 2 0x155>, <(-1) (-1)>, /* 1 -> 3 */ + + /* 3rd fuse version tuple matched */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 1 -> 1 */ + < 1 0x155>, < 3 0x22>, < 3 0x155>, /* 1 -> 2 */ + < 1 0x0>, < 2 0x155>, < 3 0x144>; /* 1 -> 3 */ + + qcom,override-corner2-reg-config = + /* 1st fuse version tuple matched */ + < 1 0x144>, < 1 0x11>, <(-1) (-1)>, /* 2 -> 1 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 2 -> 2 */ + < 1 0x155>, < 2 0x0>, < 3 0x155>, /* 2 -> 3 */ + + /* 2nd fuse version tuple matched */ + < 1 0x144>, < 2 0x133>, <(-1) (-1)>, /* 2 -> 1 */ + <(-1) (-1)>, < 1 0x33>, <(-1) (-1)>, /* 2 -> 2 */ + < 1 0x133>, < 2 0x0>, < 3 0x155>, /* 2 -> 3 */ + + /* 3rd fuse version tuple matched */ + < 1 0x144>, < 1 0x11>, <(-1) (-1)>, /* 2 -> 1 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 2 -> 2 */ + < 1 0x155>, < 2 0x22>, < 3 0x155>; /* 2 -> 3 */ + + + qcom,override-corner3-reg-config = + /* 1st fuse version tuple matched */ + < 1 0x0>, < 2 0x155>, <(-1) (-1)>, /* 3 -> 1 */ + < 1 0x155>, <(-1) (-1)>, <(-1) (-1)>, /* 3 -> 2 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 3 -> 3 */ + + /* 2nd fuse version tuple matched */ + < 1 0x0>, < 2 0x155>, <(-1) (-1)>, /* 3 -> 1 */ + < 1 0x155>, <(-1) (-1)>, <(-1) (-1)>, /* 3 -> 2 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, /* 3 -> 3 */ + + /* 3rd fuse version tuple matched */ + < 1 0x0>, < 2 0x155>, <(-1) (-1)>, /* 3 -> 1 */ + < 1 0x155>, < 3 0x11>, <(-1) (-1)>, /* 3 -> 2 */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>; /* 3 -> 3 */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/msm_gfx_ldo.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/msm_gfx_ldo.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcbb120eea2a8ea28549f04ab1063fe8ac42888e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/msm_gfx_ldo.txt @@ -0,0 +1,148 @@ +Qualcomm Technologies, Inc. GFX LDO for Graphics + +The GPU core on MSM 8953 can be powered by an internal (on-die) +MSM LDO or BHS based on its operating corner. + +This document describes the bindings that apply for the GFX LDO regulator. + +- compatible + Usage: required + Value type: + Definition: should be "qcom,msm8953-gfx-ldo" for MSM8953 and + "qcom,sdm660-gfx-ldo" for SDM660 + +- reg + Usage: required + Value type: + Definition: Addresses and sizes for the memory of the GFX ldo + +- reg-names + Usage: required + Value type: + Definition: Address names. "ldo_addr", "efuse_addr". Must be + specified in the same order as the corresponding addresses + are specified in the reg property. + +- regulator-name + Usage: required + Value type: + Definition: A string used to describe the regulator. + +- regulator-min-microvolt + Usage: required + Value type: + Definition: Minimum corner value which should be 1 to represent the + lowest supported corner. + +- regulator-max-microvolt + Usage: required + Value type: + Definition: Maximum corner value which should be equal to qcom,num-corners. + +- qcom,num-corners + Usage: required + Value type: + Definition: Number of voltage corners present. Many other + properties are sized based upon this value. + +- qcom,num-ldo-corners + Usage: required + Value type: + Definition: Number of voltage corners defined for the ldo. It is a + subset of qcom,num-corners (i.e. 1 to qcom,num-ldo-corners + are the corners for ldo operation) + +- qcom,init-corner + Usage: required + Value type: + Definition: The initial-corner at which the GFX rail is powered on. + +- qcom,ldo-enable-corner-map + Usage: required + Value type: + Definition: Integer values ( / 0) which indicate the GFX corners in which + ldo is to enabled. The length of this property + should be equal to qcom,num-corners. + +- qcom,ldo-voltage-ceiling + Usage: required + Value type: + Definition: Array of ceiling voltages in microvolts for voltage corners + ordered from lowest voltage corner to highest voltage corner. + This property must be of length defined by qcom,num-ldo-corners. + +- qcom,ldo-voltage-floor + Usage: required + Value type: + Definition: Array of floor voltages in microvolts for voltage corners + ordered from lowest voltage corner to highest voltage corner. + This property must be of length defined by qcom,num-ldo-corners. + +- vdd-cx-supply + Usage: optional + Value type: + Definition: Parent regulator supply to the ldo. + +- qcom,vdd-cx-corner-map + Usage: required if vdd-cx-supply is specified. + Value type: + Definition: Array of integers which define the mapping of the VDD_CX corner + to the corresponding GFX voltage corner. The elements in + the array are ordered from lowest voltage corner to highest + voltage corner. The length of this property must be equal to + the value defined by qcom,num-corners. +- mem-acc-supply + Usage: optional + Value type: + Definition: Regulator to vote for the memory accelerator configuration. + Not Present: memory accelerator configuration not supported. + +- qcom,mem-acc-corner-map: + Usage: optional + Value type: + Definition: Array of integer which defines the mapping from mem-acc + corner value for each gfx corner. The elements in the array + are ordered from lowest voltage corner to highest voltage corner. + +- qcom,ldo-init-voltage-adjustment + Usage: optional + Value type: + Definition: Array of voltages in microvolts which indicate the static + adjustment to be applied to the open-loop voltages for the + LDO supported corners. The length of this property must be + equal to qcom,num-ldo-corners. + +======= +Example +======= + + gfx_vreg_corner: ldo@0185f000 { + compatible = "qcom,msm8953-gfx-ldo"; + reg = <0x0185f000 0x30>, <0xa0000 0x1000>; + reg-names = "ldo_addr", "efuse_addr"; + + regulator-name = "msm_gfx_ldo"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,ldo-voltage-ceiling = <500000 700000 900000>; + qcom,ldo-voltage-floor = <400000 600000 800000>; + + qcom,num-corners = <7>; + qcom,num-ldo-corners = <3>; + qcom,ldo-enable-corner-map = <1 1 1 0 0 0 0>; + qcom,init-corner = <5>; + + vdd-cx-supply = <&pm8953_s2_level>; + qcom,vdd-cx-corner-map = , + , + , + , + , + , + ; + + mem-acc-supply = <&gfx_mem_acc>; + qcom,mem-acc-corner-map = <1 1 2 2 2 2 2>; + qcom,ldo-init-voltage-adjustment = <10000 20000 30000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/mt6311-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6311-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..84d544d8c1b1424546485a9619d45aa27e8de017 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6311-regulator.txt @@ -0,0 +1,35 @@ +Mediatek MT6311 Regulator + +Required properties: +- compatible: "mediatek,mt6311-regulator" +- reg: I2C slave address, usually 0x6b. +- regulators: List of regulators provided by this controller. It is named + to VDVFS and VBIASN. + The definition for each of these nodes is defined using the standard binding + for regulators at Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are: +BUCK: + VDVFS +LDO: + VBIASN + +Example: + mt6311: pmic@6b { + compatible = "mediatek,mt6311-regulator"; + reg = <0x6b>; + + regulators { + mt6311_vcpu_reg: VDVFS { + regulator-name = "VDVFS"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <10000>; + }; + mt6311_ldo_reg: VBIASN { + regulator-name = "VBIASN"; + regulator-min-microvolt = <200000>; + regulator-max-microvolt = <800000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/mt6323-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6323-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a48749db4df36810961dbe1d74246487b7e3c26b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6323-regulator.txt @@ -0,0 +1,237 @@ +Mediatek MT6323 Regulator + +All voltage regulators are defined as subnodes of the regulators node. A list +of regulators provided by this controller are defined as subnodes of the +PMIC's node. Each regulator is named according to its regulator type, +buck_ and ldo_. The definition for each of these nodes is defined +using the standard binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are:: +BUCK: + buck_vproc, buck_vsys, buck_vpa +LDO: + ldo_vtcxo, ldo_vcn28, ldo_vcn33_bt, ldo_vcn33_wifi, ldo_va, ldo_vcama, + ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, ldo_vemc3v3, ldo_vgp1, ldo_vgp2, + ldo_vgp3, ldo_vcn18, ldo_vsim1, ldo_vsim2, ldo_vrtc, ldo_vcamaf, ldo_vibr, + ldo_vrf18, ldo_vm, ldo_vio18, ldo_vcamd, ldo_vcamio + +Example: + + pmic: mt6323 { + mt6323regulator: regulators { + mt6323_vproc_reg: buck_vproc{ + regulator-name = "vproc"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vsys_reg: buck_vsys{ + regulator-name = "vsys"; + regulator-min-microvolt = <1400000>; + regulator-max-microvolt = <2987500>; + regulator-ramp-delay = <25000>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vpa_reg: buck_vpa{ + regulator-name = "vpa"; + regulator-min-microvolt = < 500000>; + regulator-max-microvolt = <3650000>; + }; + + mt6323_vtcxo_reg: ldo_vtcxo{ + regulator-name = "vtcxo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <90>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcn28_reg: ldo_vcn28{ + regulator-name = "vcn28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <185>; + }; + + mt6323_vcn33_bt_reg: ldo_vcn33_bt{ + regulator-name = "vcn33_bt"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <185>; + }; + + mt6323_vcn33_wifi_reg: ldo_vcn33_wifi{ + regulator-name = "vcn33_wifi"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + regulator-enable-ramp-delay = <185>; + }; + + mt6323_va_reg: ldo_va{ + regulator-name = "va"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcama_reg: ldo_vcama{ + regulator-name = "vcama"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vio28_reg: ldo_vio28{ + regulator-name = "vio28"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vusb_reg: ldo_vusb{ + regulator-name = "vusb"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + regulator-boot-on; + }; + + mt6323_vmc_reg: ldo_vmc{ + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + mt6323_vmch_reg: ldo_vmch{ + regulator-name = "vmch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + mt6323_vemc3v3_reg: ldo_vemc3v3{ + regulator-name = "vemc3v3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + regulator-boot-on; + }; + + mt6323_vgp1_reg: ldo_vgp1{ + regulator-name = "vgp1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vgp2_reg: ldo_vgp2{ + regulator-name = "vgp2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vgp3_reg: ldo_vgp3{ + regulator-name = "vgp3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vcn18_reg: ldo_vcn18{ + regulator-name = "vcn18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vsim1_reg: ldo_vsim1{ + regulator-name = "vsim1"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vsim2_reg: ldo_vsim2{ + regulator-name = "vsim2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vrtc_reg: ldo_vrtc{ + regulator-name = "vrtc"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcamaf_reg: ldo_vcamaf{ + regulator-name = "vcamaf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vibr_reg: ldo_vibr{ + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <36>; + }; + + mt6323_vrf18_reg: ldo_vrf18{ + regulator-name = "vrf18"; + regulator-min-microvolt = <1825000>; + regulator-max-microvolt = <1825000>; + regulator-enable-ramp-delay = <187>; + }; + + mt6323_vm_reg: ldo_vm{ + regulator-name = "vm"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vio18_reg: ldo_vio18{ + regulator-name = "vio18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + regulator-always-on; + regulator-boot-on; + }; + + mt6323_vcamd_reg: ldo_vcamd{ + regulator-name = "vcamd"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + + mt6323_vcamio_reg: ldo_vcamio{ + regulator-name = "vcamio"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <216>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/mt6380-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6380-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..0058441f16d2c9f0d955d58c009c666035f3212b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6380-regulator.txt @@ -0,0 +1,89 @@ +MediaTek MT6380 Regulator + +All voltage regulators provided by the MT6380 PMIC are described as the +subnodes of the MT6380 regulators node. Each regulator is named according +to its regulator type, buck- and ldo-. The definition for each +of these nodes is defined using the standard binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are: +BUCK: + buck-core1, buck-vcore, buck-vrf +LDO: + ldo-vm ,ldo-va , ldo-vphy, ldo-vddr, ldo-vt + +Example: + + regulators { + compatible = "mediatek,mt6380-regulator"; + + mt6380_vcpu_reg: buck-vcore1 { + regulator-name = "vcore1"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-ramp-delay = <6250>; + regulator-always-on; + regulator-boot-on; + }; + + mt6380_vcore_reg: buck-vcore { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1393750>; + regulator-ramp-delay = <6250>; + }; + + mt6380_vrf_reg: buck-vrf { + regulator-name = "vrf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1575000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + mt6380_vm_reg: ldo-vm { + regulator-name = "vm"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + mt6380_va_reg: ldo-va { + regulator-name = "va"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + mt6380_vphy_reg: ldo-vphy { + regulator-name = "vphy"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + mt6380_vddr_reg: ldo-vddr { + regulator-name = "vddr"; + regulator-min-microvolt = <1240000>; + regulator-max-microvolt = <1840000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + + mt6380_vt_reg: ldo-vt { + regulator-name = "vt"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <0>; + regulator-always-on; + regulator-boot-on; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/mt6397-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6397-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..01141fb0087569a265832266ba8b23675d94359f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/mt6397-regulator.txt @@ -0,0 +1,217 @@ +Mediatek MT6397 Regulator + +Required properties: +- compatible: "mediatek,mt6397-regulator" +- mt6397regulator: List of regulators provided by this controller. It is named + according to its regulator type, buck_ and ldo_. + The definition for each of these nodes is defined using the standard binding + for regulators at Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are:: +BUCK: + buck_vpca15, buck_vpca7, buck_vsramca15, buck_vsramca7, buck_vcore, buck_vgpu, + buck_vdrm, buck_vio18 +LDO: + ldo_vtcxo, ldo_va28, ldo_vcama, ldo_vio28, ldo_vusb, ldo_vmc, ldo_vmch, + ldo_vemc3v3, ldo_vgp1, ldo_vgp2, ldo_vgp3, ldo_vgp4, ldo_vgp5, ldo_vgp6, + ldo_vibr + +Example: + pmic { + compatible = "mediatek,mt6397"; + + mt6397regulator: mt6397regulator { + compatible = "mediatek,mt6397-regulator"; + + mt6397_vpca15_reg: buck_vpca15 { + regulator-compatible = "buck_vpca15"; + regulator-name = "vpca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <200>; + }; + + mt6397_vpca7_reg: buck_vpca7 { + regulator-compatible = "buck_vpca7"; + regulator-name = "vpca7"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vsramca15_reg: buck_vsramca15 { + regulator-compatible = "buck_vsramca15"; + regulator-name = "vsramca15"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + + }; + + mt6397_vsramca7_reg: buck_vsramca7 { + regulator-compatible = "buck_vsramca7"; + regulator-name = "vsramca7"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + + }; + + mt6397_vcore_reg: buck_vcore { + regulator-compatible = "buck_vcore"; + regulator-name = "vcore"; + regulator-min-microvolt = < 850000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vgpu_reg: buck_vgpu { + regulator-compatible = "buck_vgpu"; + regulator-name = "vgpu"; + regulator-min-microvolt = < 700000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <115>; + }; + + mt6397_vdrm_reg: buck_vdrm { + regulator-compatible = "buck_vdrm"; + regulator-name = "vdrm"; + regulator-min-microvolt = < 800000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <500>; + }; + + mt6397_vio18_reg: buck_vio18 { + regulator-compatible = "buck_vio18"; + regulator-name = "vio18"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2120000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <500>; + }; + + mt6397_vtcxo_reg: ldo_vtcxo { + regulator-compatible = "ldo_vtcxo"; + regulator-name = "vtcxo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <90>; + }; + + mt6397_va28_reg: ldo_va28 { + regulator-compatible = "ldo_va28"; + regulator-name = "va28"; + /* fixed output 2.8 V */ + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vcama_reg: ldo_vcama { + regulator-compatible = "ldo_vcama"; + regulator-name = "vcama"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vio28_reg: ldo_vio28 { + regulator-compatible = "ldo_vio28"; + regulator-name = "vio28"; + /* fixed output 2.8 V */ + regulator-enable-ramp-delay = <240>; + }; + + mt6397_usb_reg: ldo_vusb { + regulator-compatible = "ldo_vusb"; + regulator-name = "vusb"; + /* fixed output 3.3 V */ + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vmc_reg: ldo_vmc { + regulator-compatible = "ldo_vmc"; + regulator-name = "vmc"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vmch_reg: ldo_vmch { + regulator-compatible = "ldo_vmch"; + regulator-name = "vmch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vemc_3v3_reg: ldo_vemc3v3 { + regulator-compatible = "ldo_vemc3v3"; + regulator-name = "vemc_3v3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp1_reg: ldo_vgp1 { + regulator-compatible = "ldo_vgp1"; + regulator-name = "vcamd"; + regulator-min-microvolt = <1220000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <240>; + }; + + mt6397_vgp2_reg: ldo_vgp2 { + egulator-compatible = "ldo_vgp2"; + regulator-name = "vcamio"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp3_reg: ldo_vgp3 { + regulator-compatible = "ldo_vgp3"; + regulator-name = "vcamaf"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp4_reg: ldo_vgp4 { + regulator-compatible = "ldo_vgp4"; + regulator-name = "vgp4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp5_reg: ldo_vgp5 { + regulator-compatible = "ldo_vgp5"; + regulator-name = "vgp5"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3000000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vgp6_reg: ldo_vgp6 { + regulator-compatible = "ldo_vgp6"; + regulator-name = "vgp6"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + + mt6397_vibr_reg: ldo_vibr { + regulator-compatible = "ldo_vibr"; + regulator-name = "vibr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <218>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/palmas-pmic.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/palmas-pmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..84bc76a7c39e8f1fb2d5d8f951da1de1fe6873de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/palmas-pmic.txt @@ -0,0 +1,89 @@ +* palmas regulator IP block devicetree bindings + +The tps659038 for the AM57x class have OTP spins that +have different part numbers but the same functionality. There +is not a need to add the OTP spins to the palmas driver. The +spin devices should use the tps659038 as it's compatible value. +This is the list of those devices: +tps659037 + +Required properties: +- compatible : Should be from the list + ti,twl6035-pmic + ti,twl6036-pmic + ti,twl6037-pmic + ti,tps65913-pmic + ti,tps65914-pmic + ti,tps65917-pmic + ti,tps659038-pmic +and also the generic series names + ti,palmas-pmic +- interrupts : The interrupt number and the type which can be looked up here: + arch/arm/boot/dts/include/dt-bindings/interrupt-controller/irq.h +- interrupts-name: The names of the individual interrupts. + +Optional properties: +- ti,ldo6-vibrator : ldo6 is in vibrator mode + +Optional nodes: +- regulators : Must contain a sub-node per regulator from the list below. + Each sub-node should contain the constraints and initialization + information for that regulator. See regulator.txt for a + description of standard properties for these sub-nodes. + Additional custom properties are listed below. + + For ti,palmas-pmic - smps12, smps123, smps3 depending on OTP, + smps45, smps457, smps7 depending on variant, smps6, smps[8-9], + smps10_out2, smps10_out1, ldo[1-9], ldoln, ldousb. + + Optional sub-node properties: + ti,warm-reset - maintain voltage during warm reset(boolean) + ti,roof-floor - This takes as optional argument on platform supporting + the rail from desired external control. If there is no argument then + it will be assume that it is controlled by NSLEEP pin. + The valid value for external pins are: + ENABLE1 then 1, + ENABLE2 then 2 or + NSLEEP then 3. + ti,mode-sleep - mode to adopt in pmic sleep 0 - off, 1 - auto, + 2 - eco, 3 - forced pwm + ti,smps-range - OTP has the wrong range set for the hardware so override + 0 - low range, 1 - high range. + +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. + +Example: + +#include + +pmic { + compatible = "ti,twl6035-pmic", "ti,palmas-pmic"; + interrupt-parent = <&palmas>; + interrupts = <14 IRQ_TYPE_NONE>; + interrupts-name = "short-irq"; + + ti,ldo6-vibrator; + + ti,system-power-controller; + + regulators { + smps12_reg : smps12 { + regulator-name = "smps12"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1500000>; + regulator-always-on; + regulator-boot-on; + ti,warm-reset; + ti,roof-floor = <1>; /* ENABLE1 control */ + ti,mode-sleep = <0>; + ti,smps-range = <1>; + }; + + ldo1_reg: ldo1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/pbias-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/pbias-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..acbcb452a69ab40d528954634517dc94f9620065 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/pbias-regulator.txt @@ -0,0 +1,32 @@ +PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs. + +Required properties: +- compatible: + - should be "ti,pbias-dra7" for DRA7 + - should be "ti,pbias-omap2" for OMAP2 + - should be "ti,pbias-omap3" for OMAP3 + - should be "ti,pbias-omap4" for OMAP4 + - should be "ti,pbias-omap5" for OMAP5 + - "ti,pbias-omap" is deprecated +- reg: pbias register offset from syscon base and size of pbias register. +- syscon : phandle of the system control module +- regulator-name : should be + pbias_mmc_omap2430 for OMAP2430, OMAP3 SoCs + pbias_sim_omap3 for OMAP3 SoCs + pbias_mmc_omap4 for OMAP4 SoCs + pbias_mmc_omap5 for OMAP5 and DRA7 SoC + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt + +Example: + + pbias_regulator: pbias_regulator { + compatible = "ti,pbias-omap"; + reg = <0 0x4>; + syscon = <&omap5_padconf_global>; + pbias_mmc_reg: pbias_mmc_omap5 { + regulator-name = "pbias_mmc_omap5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/pfuze100.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/pfuze100.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7610718adfff69fd8e98068721534c4cdf7f7c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/pfuze100.txt @@ -0,0 +1,389 @@ +PFUZE100 family of regulators + +Required properties: +- compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000", "fsl,pfuze3001" +- reg: I2C slave address + +Optional properties: +- fsl,pfuze-support-disable-sw: Boolean, if present disable all unused switch + regulators to save power consumption. Attention, ensure that all important + regulators (e.g. DDR ref, DDR supply) has set the "regulator-always-on" + property. If not present, the switched regualtors are always on and can't be + disabled. This binding is a workaround to keep backward compatibility with + old dtb's which rely on the fact that the switched regulators are always on + and don't mark them explicit as "regulator-always-on". + +Required child node: +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. Please refer to below doc + Documentation/devicetree/bindings/regulator/regulator.txt. + + The valid names for regulators are: + --PFUZE100 + sw1ab,sw1c,sw2,sw3a,sw3b,sw4,swbst,vsnvs,vrefddr,vgen1~vgen6 + --PFUZE200 + sw1ab,sw2,sw3a,sw3b,swbst,vsnvs,vrefddr,vgen1~vgen6,coin + --PFUZE3000 + sw1a,sw1b,sw2,sw3,swbst,vsnvs,vrefddr,vldo1,vldo2,vccsd,v33,vldo3,vldo4 + --PFUZE3001 + sw1,sw2,sw3,vsnvs,vldo1,vldo2,vccsd,v33,vldo3,vldo4 + +Each regulator is defined using the standard binding for regulators. + +Example 1: PFUZE100 + + pfuze100: pmic@8 { + compatible = "fsl,pfuze100"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + + +Example 2: PFUZE200 + + pfuze200: pmic@8 { + compatible = "fsl,pfuze200"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1875000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3a { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3b_reg: sw3b { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1975000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vgen1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen2_reg: vgen2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vgen3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + vgen4_reg: vgen4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vgen5 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vgen6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + coin_reg: coin { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + +Example 3: PFUZE3000 + + pfuze3000: pmic@8 { + compatible = "fsl,pfuze3000"; + reg = <0x08>; + + regulators { + sw1a_reg: sw1a { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + /* use sw1c_reg to align with pfuze100/pfuze200 */ + sw1c_reg: sw1b { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1475000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <6250>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3a_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5150000>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + +Example 4: PFUZE 3001 + + pfuze3001: pmic@8 { + compatible = "fsl,pfuze3001"; + reg = <0x08>; + + regulators { + sw1_reg: sw1 { + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + sw3_reg: sw3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1650000>; + regulator-boot-on; + regulator-always-on; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + regulator-always-on; + }; + + vgen1_reg: vldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen2_reg: vldo2 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1550000>; + regulator-always-on; + }; + + vgen3_reg: vccsd { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen4_reg: v33 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen5_reg: vldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vgen6_reg: vldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/proxy-consumer.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/proxy-consumer.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3fddd78f3f5dde2c848e7fdb89c0c8f299da01d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/proxy-consumer.txt @@ -0,0 +1,32 @@ +Regulator Proxy Consumer Bindings + +Regulator proxy consumers provide a means to use a default regulator state +during bootup only which is removed at the end of boot. This feature can be +used in situations where a shared regulator can be scaled between several +possible voltages and hardware requires that it be at a high level at the +beginning of boot before the consumer device responsible for requesting the +high level has probed. + +Optional properties: +proxy-supply: phandle of the regulator's own device node. + This property is required if any of the three + properties below are specified. +qcom,proxy-consumer-enable: Boolean indicating that the regulator must be + kept enabled during boot. +qcom,proxy-consumer-voltage: List of two integers corresponding the minimum + and maximum voltage allowed during boot in + microvolts. +qcom,proxy-consumer-current: Minimum current in microamps required during + boot. + +Example: + + foo_vreg: regulator@0 { + regulator-name = "foo"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2000000>; + proxy-supply = <&foo_vreg>; + qcom,proxy-consumer-voltage = <1500000 2000000>; + qcom,proxy-consumer-current = <25000>; + qcom,proxy-consumer-enable; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/pv88060.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/pv88060.txt new file mode 100644 index 0000000000000000000000000000000000000000..10a6dadc008eb38d6cae1f439b364f52efa82194 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/pv88060.txt @@ -0,0 +1,124 @@ +* Powerventure Semiconductor PV88060 Voltage Regulator + +Required properties: +- compatible: "pvs,pv88060". +- reg: I2C slave address, usually 0x49. +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + BUCK1, LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, SW1, SW2, SW3, SW4, + SW5, and SW6. + +Optional properties: +- Any optional property defined in regulator.txt + +Example + + pmic: pv88060@49 { + compatible = "pvs,pv88060"; + reg = <0x49>; + interrupt-parent = <&gpio>; + interrupts = <24 24>; + + regulators { + BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <4387500>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + regulator-boot-on; + }; + + LDO1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + LDO2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + LDO3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + LDO4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + LDO5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + LDO6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + LDO7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3350000>; + regulator-boot-on; + }; + + SW1 { + regulator-name = "sw1"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + SW2 { + regulator-name = "sw2"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + SW3 { + regulator-name = "sw3"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + SW4 { + regulator-name = "sw4"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + SW5 { + regulator-name = "sw5"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + }; + + SW6 { + regulator-name = "sw6"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + }; + }; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/pv88080.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/pv88080.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6e4b9c82d8902a1a4a5f806fd4c0b2b5f891437 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/pv88080.txt @@ -0,0 +1,62 @@ +* Powerventure Semiconductor PV88080 Voltage Regulator + +Required properties: +- compatible: Must be one of the following, depending on the + silicon version: + - "pvs,pv88080" (DEPRECATED) + + - "pvs,pv88080-aa" for PV88080 AA or AB silicon + - "pvs,pv88080-ba" for PV88080 BA or BB silicon + NOTE: The use of the compatibles with no silicon version is deprecated. +- reg: I2C slave address, usually 0x49 +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + BUCK1, BUCK2, BUCK3 and HVBUCK. + +Optional properties: +- Any optional property defined in regulator.txt + +Example: + + pmic: pv88080@49 { + compatible = "pvs,pv88080-ba"; + reg = <0x49>; + interrupt-parent = <&gpio>; + interrupts = <24 24>; + + regulators { + BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = < 220000>; + regulator-max-microamp = <7040000>; + }; + + BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + }; + + BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <1400000>; + regulator-max-microvolt = <2193750>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + }; + + HVBUCK { + regulator-name = "hvbuck"; + regulator-min-microvolt = < 5000>; + regulator-max-microvolt = <1275000>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/pv88090.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/pv88090.txt new file mode 100644 index 0000000000000000000000000000000000000000..e52b2a95cdde05ac123871f3a6c6945beb9da51a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/pv88090.txt @@ -0,0 +1,65 @@ +* Powerventure Semiconductor PV88090 Voltage Regulator + +Required properties: +- compatible: "pvs,pv88090". +- reg: I2C slave address, usually 0x48. +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + BUCK1, BUCK2, BUCK3, LDO1, and LDO2. + +Optional properties: +- Any optional property defined in regulator.txt + +Example + + pmic: pv88090@48 { + compatible = "pvs,pv88090"; + reg = <0x48>; + interrupt-parent = <&gpio>; + interrupts = <24 24>; + + regulators { + BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = < 220000>; + regulator-max-microamp = <7040000>; + regulator-boot-on; + }; + + BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + }; + + BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1393750>; + regulator-min-microamp = <1496000>; + regulator-max-microamp = <4189000>; + regulator-boot-on; + }; + + LDO1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <4350000>; + regulator-boot-on; + }; + + LDO2 { + regulator-name = "ldo2"; + regulator-min-microvolt = < 650000>; + regulator-max-microvolt = <2225000>; + regulator-boot-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/pwm-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/pwm-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d78d507e29fee9390cdb9525549deff250db8a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/pwm-regulator.txt @@ -0,0 +1,92 @@ +Bindings for the Generic PWM Regulator +====================================== + +Currently supports 2 modes of operation: + +Voltage Table: When in this mode, a voltage table (See below) of + predefined voltage <=> duty-cycle values must be + provided via DT. Limitations are that the regulator can + only operate at the voltages supplied in the table. + Intermediary duty-cycle values which would normally + allow finer grained voltage selection are ignored and + rendered useless. Although more control is given to + the user if the assumptions made in continuous-voltage + mode do not reign true. + +Continuous Voltage: This mode uses the regulator's maximum and minimum + supplied voltages specified in the + regulator-{min,max}-microvolt properties to calculate + appropriate duty-cycle values. This allows for a much + more fine grained solution when compared with + voltage-table mode above. This solution does make an + assumption that a %50 duty-cycle value will cause the + regulator voltage to run at half way between the + supplied max_uV and min_uV values. + +Required properties: +-------------------- +- compatible: Should be "pwm-regulator" + +- pwms: PWM specification (See: ../pwm/pwm.txt) + +Only required for Voltage Table Mode: +- voltage-table: Voltage and Duty-Cycle table consisting of 2 cells + First cell is voltage in microvolts (uV) + Second cell is duty-cycle in percent (%) + +Optional properties for Continuous mode: +- pwm-dutycycle-unit: Integer value encoding the duty cycle unit. If not + defined, <100> is assumed, meaning that + pwm-dutycycle-range contains values expressed in + percent. + +- pwm-dutycycle-range: Should contain 2 entries. The first entry is encoding + the dutycycle for regulator-min-microvolt and the + second one the dutycycle for regulator-max-microvolt. + Duty cycle values are expressed in pwm-dutycycle-unit. + If not defined, <0 100> is assumed. + +NB: To be clear, if voltage-table is provided, then the device will be used +in Voltage Table Mode. If no voltage-table is provided, then the device will +be used in Continuous Voltage Mode. + +Optional properties: +-------------------- +- enable-gpios: GPIO to use to enable/disable the regulator + +Any property defined as part of the core regulator binding can also be used. +(See: ../regulator/regulator.txt) + +Continuous Voltage With Enable GPIO Example: + pwm_regulator { + compatible = "pwm-regulator"; + pwms = <&pwm1 0 8448 0>; + enable-gpios = <&gpio0 23 GPIO_ACTIVE_HIGH>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + /* unit == per-mille */ + pwm-dutycycle-unit = <1000>; + /* + * Inverted PWM logic, and the duty cycle range is limited + * to 30%-70%. + */ + pwm-dutycycle-range = <700 300>; /* */ + }; + +Voltage Table Example: + pwm_regulator { + compatible = "pwm-regulator"; + pwms = <&pwm1 0 8448 0>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + + /* Voltage Duty-Cycle */ + voltage-table = <1114000 0>, + <1095000 10>, + <1076000 20>, + <1056000 30>, + <1036000 40>, + <1016000 50>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,pm8008-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,pm8008-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5cf233d2819a9196f88827aafd2a442048c3181 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,pm8008-regulator.txt @@ -0,0 +1,143 @@ +Qualcomm Technologies, Inc. PM8008 Regulator + +PM8008 is an I2C based PMIC regulator chip. + +======================= +Required Node Structure +======================= + +============================================== +PM8008 chip specific device +============================================== +PM8008 chip specific properties: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,pm8008-chip" + +- pinctrl-names: + Usage: required + Value type: + Definition: must be "default" + +- pinctrl-0: + Usage: required + Value type: + Definition: pinctrol handle for chip enable GPIO. + +- interrupts: + Usage: optional + Value type: + Definition: PM8008 LDO over current protection (OCP) summary interrupt. + +- interrupt-names + Usage: required if 'interrupts' property is specified. + Value type: + Definition: This should be "ocp" for the PM8008 LDO OCP interrupt. + +- regulator sub-node: + Usage: required + Value type: + Definition: Chip enable regulator device to control chip enable + functionality. Must be "qcom,pm8008-chip-en". +Example: + qcom,pm8008-chip@900 { + compatible = "qcom,pm8008-chip"; + + interrupts = <0x09 4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ocp"; + + PM8008_EN: qcom,pm8008-chip-en { + regulator-name = "pm8008-chip-en"; + }; + }; + + +======================================================== +PM8008 regulator device +======================================================== +PM8008 chip regulator specific properties: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,pm8008-regulator" + +- -supply: + Usage: optional + Value type: + Definition: Reference to parent regulator supplying the input pin, as + described in the data sheet. + Must be one of the following: + vdd_l1_l2-supply: supply for LDO1/LDO2 of PM8008 + vdd_l3_l4-supply: supply for LDO3/LDO4 of PM8008 + vdd_l5-supply: supply for LDO5 of PM8008 + vdd_l6-supply: supply for LDO6 of PM8008 + vdd_l7-supply: supply for LDO7 of PM8008 + +- pm8008_en-supply: + Usage: required + Value type: + Definition: Reference to PM8008 chip enable regulator, which manages + chip enable functionlity of PM8008. + +- qcom,enable-ocp-broadcast: + Usage: optional + Value type: + Definition: Property if present enables the LDO OCP broadcast bit. + This property is required only when the "ocp" interrupt + in the pm8008 chip module is enabled. + +============================================================================ +Second Level Nodes - PM8008 regulator peripherals of PM8008 regulator device +============================================================================ + +- qcom,hpm-min-load: + Usage: optional + Value type: + Definition: Load current in uA which corresponds to the minimum load + which requires the regulator to be in high power mode. + +- qcom,min-dropout-voltage: + Usage: optional + Value type: + Definition: Specifies the minimum voltage in microvolts that the parent + supply regulator must output above the output of this + regulator. It is only meaningful if the corresponding parent + supply property has been specified in the first level node. + +- qcom,init-voltage + Usage: optional + Value type: + Definition: Specifies the initial voltage in microvolts to for a regulator. + +- qcom,strong-pd + Usage: optional + Value type: + Definition: Property if present enables strong pull-down. + +The content of each sub-node is defined by the standard binding for regulators - +see regulator.txt - with additional custom properties described below: + +Example: + + qcom,pm8008-regulator { + compatible = "qcom,pm8008-regulator"; + + pm8008_en-supply = <&PM8008_EN>; + vdd_l1_l2-supply = <&parent-supply>; + qcom,enable-ocp-broadcast; + ... + + L1: qcom,pm8008-l1@4000 { + reg = /bits/ 16 <0x4000>; + regulator-name = "pm8008_l1"; + regulator-min-microvolt = <2900000>; + regulator-max-microvolt = <3100000>; + qcom,min-dropout-voltage = <100000>; + qcom,hpm-min-load = <10000>; + } + + ..... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,refgen.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,refgen.txt new file mode 100644 index 0000000000000000000000000000000000000000..4410d0da9c222d0334c6800417175bfd05f4c23d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,refgen.txt @@ -0,0 +1,40 @@ +Qualcomm Technologies, Inc. REFGEN Regulator + +Some Qualcomm Technologies, Inc. SoCs utilize reference bias generators for +various internal PHY blocks. These are called REFGENs. + +Supported properties: +- compatible + Usage: required + Value type: + Definition: Must be one of: "qcom,refgen-regulator", + "qcom,refgen-sdm845-regulator", or + "qcom,refgen-kona-regulator". + +- reg + Usage: required + Value type: + Definition: Address and size of the REFGEN registers. + +- regulator-name + Usage: required + Value type: + Definition: Specifies the name for this REFGEN regulator. + +- regulator-enable-ramp-delay + Usage: optional + Value type: + Definition: REFGEN enable time in microseconds. + +- parent-supply + Usage: optional + Value type: + Definition: phandle to the parent supply/regulator node if one exists. + +Example: + +refgen-regulator@ff1000 { + compatible = "qcom,refgen-regulator"; + reg = <0xff1000 0x60>; + regulator-name = "refgen"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,rpmh-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,rpmh-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ef2dbe48e8a8cb86bfebcbc385cae1618bbdffe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,rpmh-regulator.txt @@ -0,0 +1,160 @@ +Qualcomm Technologies, Inc. RPMh Regulators + +rpmh-regulator devices support PMIC regulator management via the Voltage +Regulator Manager (VRM) and Oscillator Buffer (XOB) RPMh accelerators. The APPS +processor communicates with these hardware blocks via a Resource State +Coordinator (RSC) using command packets. The VRM allows changing three +parameters for a given regulator: enable state, output voltage, and operating +mode. The XOB allows changing only a single parameter for a given regulator: +its enable state. Despite its name, the XOB is capable of controlling the +enable state of any PMIC peripheral. It is used for clock buffers, low-voltage +switches, and LDO/SMPS regulators which have a fixed voltage and mode. + +======================= +Required Node Structure +======================= + +RPMh regulators must be described in two levels of device nodes. The first +level describes the PMIC containing the regulators and must reside within an +RPMh device node. The second level describes each regulator within the PMIC +which is to be used on the board. Each of these regulators maps to a single +RPMh resource. + +The names used for regulator nodes must match those supported by a given PMIC. +Supported regulator node names: + PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2 + PMI8998: bob + PM8005: smps1 - smps4 + +======================== +First Level Nodes - PMIC +======================== + +- compatible + Usage: required + Value type: + Definition: Must be one of: "qcom,pm8998-rpmh-regulators", + "qcom,pmi8998-rpmh-regulators" or + "qcom,pm8005-rpmh-regulators". + +- qcom,pmic-id + Usage: required + Value type: + Definition: RPMh resource name suffix used for the regulators found on + this PMIC. Typical values: "a", "b", "c", "d", "e", "f". + +- vdd-s1-supply +- vdd-s2-supply +- vdd-s3-supply +- vdd-s4-supply + Usage: optional (PM8998 and PM8005 only) + Value type: + Definition: phandle of the parent supply regulator of one or more of the + regulators for this PMIC. + +- vdd-s5-supply +- vdd-s6-supply +- vdd-s7-supply +- vdd-s8-supply +- vdd-s9-supply +- vdd-s10-supply +- vdd-s11-supply +- vdd-s12-supply +- vdd-s13-supply +- vdd-l1-l27-supply +- vdd-l2-l8-l17-supply +- vdd-l3-l11-supply +- vdd-l4-l5-supply +- vdd-l6-supply +- vdd-l7-l12-l14-l15-supply +- vdd-l9-supply +- vdd-l10-l23-l25-supply +- vdd-l13-l19-l21-supply +- vdd-l16-l28-supply +- vdd-l18-l22-supply +- vdd-l20-l24-supply +- vdd-l26-supply +- vin-lvs-1-2-supply + Usage: optional (PM8998 only) + Value type: + Definition: phandle of the parent supply regulator of one or more of the + regulators for this PMIC. + +- vdd-bob-supply + Usage: optional (PMI8998 only) + Value type: + Definition: BOB regulator parent supply phandle + +=============================== +Second Level Nodes - Regulators +=============================== + +- qcom,always-wait-for-ack + Usage: optional + Value type: + Definition: Boolean flag which indicates that the application processor + must wait for an ACK or a NACK from RPMh for every request + sent for this regulator including those which are for a + strictly lower power state. + +Other properties defined in Documentation/devicetree/bindings/regulator.txt +may also be used. regulator-initial-mode and regulator-allowed-modes may be +specified for VRM regulators using mode values from +include/dt-bindings/regulator/qcom,rpmh-regulator.h. regulator-allow-bypass +may be specified for BOB type regulators managed via VRM. +regulator-allow-set-load may be specified for LDO type regulators managed via +VRM. + +======== +Examples +======== + +#include + +&apps_rsc { + pm8998-rpmh-regulators { + compatible = "qcom,pm8998-rpmh-regulators"; + qcom,pmic-id = "a"; + + vdd-l7-l12-l14-l15-supply = <&pm8998_s5>; + + smps2 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + pm8998_s5: smps5 { + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2040000>; + }; + + ldo7 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allowed-modes = + ; + regulator-allow-set-load; + }; + + lvs1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + + pmi8998-rpmh-regulators { + compatible = "qcom,pmi8998-rpmh-regulators"; + qcom,pmic-id = "b"; + + bob { + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3600000>; + regulator-allowed-modes = + ; + regulator-initial-mode = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,smd-rpm-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,smd-rpm-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..58a1d97972f5aad1bf78f2f14556a8011c905237 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,smd-rpm-regulator.txt @@ -0,0 +1,263 @@ +QCOM SMD RPM REGULATOR + +The Qualcomm RPM over SMD regulator is modelled as a subdevice of the RPM. +Because SMD is used as the communication transport mechanism, the RPM resides as +a subnode of the SMD. As such, the SMD-RPM regulator requires that the SMD and +RPM nodes be present. + +Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt for +information pertaining to the SMD node. + +Please refer to Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt for +information regarding the RPM node. + +== Regulator + +Regulator nodes are identified by their compatible: + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-pm8841-regulators" + "qcom,rpm-pm8916-regulators" + "qcom,rpm-pm8941-regulators" + "qcom,rpm-pm8994-regulators" + "qcom,rpm-pm8998-regulators" + "qcom,rpm-pma8084-regulators" + "qcom,rpm-pmi8998-regulators" + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: + Usage: optional (pm8841 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_l1_l2_l3-supply: +- vdd_l4_l5_l6-supply: +- vdd_l7-supply: +- vdd_l8_l9_l10_l11_l12_l13_l14_l15_l16_l17_l18-supply: + Usage: optional (pm8916 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_l1_l3-supply: +- vdd_l2_lvs1_2_3-supply: +- vdd_l4_l11-supply: +- vdd_l5_l7-supply: +- vdd_l6_l12_l14_l15-supply: +- vdd_l8_l16_l18_l19-supply: +- vdd_l9_l10_l17_l22-supply: +- vdd_l13_l20_l23_l24-supply: +- vdd_l21-supply: +- vin_5vs-supply: + Usage: optional (pm8941 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: +- vdd_s9-supply: +- vdd_s10-supply: +- vdd_s11-supply: +- vdd_s12-supply: +- vdd_l1-supply: +- vdd_l2_l26_l28-supply: +- vdd_l3_l11-supply: +- vdd_l4_l27_l31-supply: +- vdd_l5_l7-supply: +- vdd_l6_l12_l32-supply: +- vdd_l5_l7-supply: +- vdd_l8_l16_l30-supply: +- vdd_l9_l10_l18_l22-supply: +- vdd_l9_l10_l18_l22-supply: +- vdd_l3_l11-supply: +- vdd_l6_l12_l32-supply: +- vdd_l13_l19_l23_l24-supply: +- vdd_l14_l15-supply: +- vdd_l14_l15-supply: +- vdd_l8_l16_l30-supply: +- vdd_l17_l29-supply: +- vdd_l9_l10_l18_l22-supply: +- vdd_l13_l19_l23_l24-supply: +- vdd_l20_l21-supply: +- vdd_l20_l21-supply: +- vdd_l9_l10_l18_l22-supply: +- vdd_l13_l19_l23_l24-supply: +- vdd_l13_l19_l23_l24-supply: +- vdd_l25-supply: +- vdd_l2_l26_l28-supply: +- vdd_l4_l27_l31-supply: +- vdd_l2_l26_l28-supply: +- vdd_l17_l29-supply: +- vdd_l8_l16_l30-supply: +- vdd_l4_l27_l31-supply: +- vdd_l6_l12_l32-supply: +- vdd_lvs1_2-supply: + Usage: optional (pm8994 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: +- vdd_s9-supply: +- vdd_s10-supply: +- vdd_s11-supply: +- vdd_s12-supply: +- vdd_s13-supply: +- vdd_l1_l27-supply: +- vdd_l20_l24-supply: +- vdd_l26-supply: +- vdd_l2_l8_l17-supply: +- vdd_l3_l11-supply: +- vdd_l4_l5-supply: +- vdd_l6-supply: +- vdd_l7_l12_l14_l15-supply: +- vdd_l9-supply: +- vdd_l10_l23_l25-supply: +- vdd_l13_l19_l21-supply: +- vdd_l16_l28-supply: +- vdd_l18_l22-supply: +- vdd_lvs1_lvs2-supply: + Usage: optional (pmi8998 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: +- vdd_s9-supply: +- vdd_s10-supply: +- vdd_s11-supply: +- vdd_s12-supply: +- vdd_l1_l11-supply: +- vdd_l2_l3_l4_l27-supply: +- vdd_l5_l7-supply: +- vdd_l6_l12_l14_l15_l26-supply: +- vdd_l8-supply: +- vdd_l9_l10_l13_l20_l23_l24-supply: +- vdd_l16_l25-supply: +- vdd_l17-supply: +- vdd_l18-supply: +- vdd_l19-supply: +- vdd_l21-supply: +- vdd_l22-supply: + Usage: optional (pma8084 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +- vdd_bob-supply: + Usage: optional (pmi8998 only) + Value type: + Definition: reference to regulator supplying the input pin, as + described in the data sheet + +The regulator node houses sub-nodes for each regulator within the device. Each +sub-node is identified using the node's name, with valid values listed for each +of the pmics below. + +pm8841: + s1, s2, s3, s4, s5, s6, s7, s8 + +pm8916: + s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, + l14, l15, l16, l17, l18 + +pm8941: + s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, + l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, + lvs3, 5vs1, 5vs2 + +pm8994: + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5, + l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, + l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2 + +pm8998: + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, l1, l2, l3, l4, + l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, + l20, l21, l22, l23, l24, l25, l26, l27, l28, lvs1, lvs2 + +pma8084: + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5, + l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, + l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1 + +pmi8998: + bob + +The content of each sub-node is defined by the standard binding for regulators - +see regulator.txt. + += EXAMPLE + + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8974"; + qcom,smd-channels = "rpm_requests"; + + pm8941-regulators { + compatible = "qcom,rpm-pm8941-regulators"; + vdd_l13_l20_l23_l24-supply = <&pm8941_boost>; + + pm8941_s3: s3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8941_boost: s4 { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + pm8941_l20: l20 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,spmi-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,spmi-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..406f2e570c50de2650c30fbba09d809efe0cb888 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qcom,spmi-regulator.txt @@ -0,0 +1,268 @@ +Qualcomm SPMI Regulators + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,pm8841-regulators" + "qcom,pm8916-regulators" + "qcom,pm8941-regulators" + "qcom,pm8994-regulators" + "qcom,pmi8994-regulators" + +- interrupts: + Usage: optional + Value type: + Definition: List of OCP interrupts. + +- interrupt-names: + Usage: required if 'interrupts' property present + Value type: + Definition: List of strings defining the names of the + interrupts in the 'interrupts' property 1-to-1. + Supported values are "ocp-", where + corresponds to a voltage switch + type regulator. + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: + Usage: optional (pm8841 only) + Value type: + Definition: Reference to regulator supplying the input pin, as + described in the data sheet. + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_l1_l3-supply: +- vdd_l2-supply: +- vdd_l4_l5_l6-supply: +- vdd_l7-supply: +- vdd_l8_l11_l14_l15_l16-supply: +- vdd_l9_l10_l12_l13_l17_l18-supply: + Usage: optional (pm8916 only) + Value type: + Definition: Reference to regulator supplying the input pin, as + described in the data sheet. + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_l1_l3-supply: +- vdd_l2_lvs_1_2_3-supply: +- vdd_l4_l11-supply: +- vdd_l5_l7-supply: +- vdd_l6_l12_l14_l15-supply: +- vdd_l8_l16_l18_19-supply: +- vdd_l9_l10_l17_l22-supply: +- vdd_l13_l20_l23_l24-supply: +- vdd_l21-supply: +- vin_5vs-supply: + Usage: optional (pm8941 only) + Value type: + Definition: Reference to regulator supplying the input pin, as + described in the data sheet. + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_s4-supply: +- vdd_s5-supply: +- vdd_s6-supply: +- vdd_s7-supply: +- vdd_s8-supply: +- vdd_s9-supply: +- vdd_s10-supply: +- vdd_s11-supply: +- vdd_s12-supply: +- vdd_l1-supply: +- vdd_l2_l26_l28-supply: +- vdd_l3_l11-supply: +- vdd_l4_l27_l31-supply: +- vdd_l5_l7-supply: +- vdd_l6_l12_l32-supply: +- vdd_l8_l16_l30-supply: +- vdd_l9_l10_l18_l22-supply: +- vdd_l13_l19_l23_l24-supply: +- vdd_l14_l15-supply: +- vdd_l17_l29-supply: +- vdd_l20_l21-supply: +- vdd_l25-supply: +- vdd_lvs_1_2-supply: + Usage: optional (pm8994 only) + Value type: + Definition: Reference to regulator supplying the input pin, as + described in the data sheet. + +- vdd_s1-supply: +- vdd_s2-supply: +- vdd_s3-supply: +- vdd_l1-supply: + Usage: optional (pmi8994 only) + Value type: + Definition: Reference to regulator supplying the input pin, as + described in the data sheet. + +- qcom,saw-reg: + Usage: optional + Value type: + Description: Reference to syscon node defining the SAW registers. + + +The regulator node houses sub-nodes for each regulator within the device. Each +sub-node is identified using the node's name, with valid values listed for each +of the PMICs below. + +pm8841: + s1, s2, s3, s4, s5, s6, s7, s8 + +pm8916: + s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, + l14, l15, l16, l17, l18 + +pm8941: + s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, + l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3, + 5vs1, 5vs2 + +pm8994: + s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, l1, l2, l3, l4, l5, + l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, + l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, l31, l32, lvs1, lvs2 + +pmi8994: + s1, s2, s3, l1 + +The content of each sub-node is defined by the standard binding for regulators - +see regulator.txt - with additional custom properties described below: + +- regulator-initial-mode: + Usage: optional + Value type: + Description: 2 = Set initial mode to auto mode (automatically select + between HPM and LPM); not available on boost type + regulators. + + 1 = Set initial mode to high power mode (HPM), also referred + to as NPM. HPM consumes more ground current than LPM, but + it can source significantly higher load current. HPM is not + available on boost type regulators. For voltage switch type + regulators, HPM implies that over current protection and + soft start are active all the time. + + 0 = Set initial mode to low power mode (LPM). + +- qcom,ocp-max-retries: + Usage: optional + Value type: + Description: Maximum number of times to try toggling a voltage switch + off and back on as a result of consecutive over current + events. + +- qcom,ocp-retry-delay: + Usage: optional + Value type: + Description: Time to delay in milliseconds between each voltage switch + toggle after an over current event takes place. + +- qcom,pin-ctrl-enable: + Usage: optional + Value type: + Description: Bit mask specifying which hardware pins should be used to + enable the regulator, if any; supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + +- qcom,pin-ctrl-hpm: + Usage: optional + Value type: + Description: Bit mask specifying which hardware pins should be used to + force the regulator into high power mode, if any; + supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state + +- qcom,vs-soft-start-strength: + Usage: optional + Value type: + Description: This property sets the soft start strength for voltage + switch type regulators; supported values are: + 0 = 0.05 uA + 1 = 0.25 uA + 2 = 0.55 uA + 3 = 0.75 uA + +- qcom,saw-slave: + Usage: optional + Value type: + Description: SAW controlled gang slave. Will not be configured. + +- qcom,saw-leader: + Usage: optional + Value type: + Description: SAW controlled gang leader. Will be configured as + SAW regulator. + +Example: + + regulators { + compatible = "qcom,pm8941-regulators"; + vdd_l1_l3-supply = <&s1>; + + s1: s1 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1400000>; + }; + + ... + + l1: l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1300000>; + }; + + .... + }; + +Example 2: + + saw3: syscon@9A10000 { + compatible = "syscon"; + reg = <0x9A10000 0x1000>; + }; + + ... + + spm-regulators { + compatible = "qcom,pm8994-regulators"; + qcom,saw-reg = <&saw3>; + s8 { + qcom,saw-slave; + }; + s9 { + qcom,saw-slave; + }; + s10 { + qcom,saw-slave; + }; + pm8994_s11_saw: s11 { + qcom,saw-leader; + regulator-always-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1140000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-amoled-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-amoled-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..eaf2ded872d457a0a4630019a1f4b57d9654e3e3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-amoled-regulator.txt @@ -0,0 +1,103 @@ +QPNP AMOLED Triple power supply regulator devices + +QPNP OLEDB module provides AVDD voltage rail output for bias and QPNP AB/IBB +module provides ELVDD/ELVSS voltage rail output to power up AMOLED panels. + +For PM8150A, allowed voltage levels are as below: +AVDD - Programmable output from 4.925 V to 8.1 V. +ELVDD - Programmable output from 4.6 V to 6.1 V. +ELVSS - Programmable output from -0.8 V to -5.4 V. + + +This document describes the bindings for AMOLED regulator devices. + +======================= +Required Node Structure +======================= + +AMOLED regulator device must be described in two level of device nodes. + +- compatible: + Usage: required + Value type: + Definition: should be "qcom,qpnp-amoled-regulator" + +========================================== +Second Level Nodes - OLEDB/AB/IBB specific +========================================== + +Subnode common properties for OLEDB and AB/IBB regulator devices. + +- reg: + Usage: required + Value type: + Definition: Register base and length for OLEDB, AB and IBB modules + which are represented as child nodes. + +- reg-names: + Usage: required + Value type: + Definition: The name of the register defined in the reg property. + +- regulator-name: + Usage: required + Value type: + Definition: A string used to describe the regulator. + +- regulator-min-microvolt: + Usage: required + Value type: + Definition: Minimum voltage (in uV) supported by the regulator. + +- regulator-max-microvolt: + Usage: required + Value type: + Definition: Maximum voltage (in uV) supported by the regulator. + +- qcom,swire-control: + Usage: optional + Value type: + Definition: A boolean property to specify that the regulator output is + controlled by SWIRE signal. When this is specified, output + voltage of the regulator is not controlled by SW. + +- qcom,aod-pd-control: + Usage: optional + Value type: + Definition: A boolean property to specify that the pull down control + for AB/IBB needs to be configured during AOD mode. + +Example: + +pm8150a_amoled: oledb@e000 { + compatible = "qcom,qpnp-amoled-regulator"; + + oledb_vreg: oledb@e000 { + reg = <0xe000 0x100>; + reg-names = "oledb_base"; + regulator-name = "oledb_vreg"; + regulator-min-microvolt = <4925000>; + regulator-max-microvolt = <8100000>; + qcom,swire-control; + }; + + ab_vreg: ab@de00 { + reg = <0xde00 0x100>; + reg-names = "ab_base"; + regulator-name = "ab_vreg"; + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6100000>; + qcom,swire-control; + qcom,aod-pd-control; + }; + + ibb_vreg: ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_base"; + regulator-name = "ibb_vreg"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <5400000>; + qcom,swire-control; + qcom,aod-pd-control; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-labibb-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-labibb-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a5e607de69d8d258b53b2fa49c88f98cf0204339 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-labibb-regulator.txt @@ -0,0 +1,422 @@ +QTI's LAB (LCD/AMOLED BOOST)/IBB (Inverting Buck-Boost) Regulator + +LAB can be used as a standalone positive boost power supply for general purpose +applications. IBB can be used as a standalone negative power supply for general +applications. Also, LAB and IBB can be used together to provide power supply for +display panels, LCD or AMOLED. + +Main node required properties: + +- compatible: Must be "qcom,qpnp-labibb-regulator" +- qcom,qpnp-labibb-mode: A string used to specify the working mode of LAB/IBB + regulators when bootloader does not turned on the + display panel. Could be "lcd" or "amoled". + "lcd" means using LAB and IBB regulators are + configured for LCD mode. + "amoled" means using LAB and IBB regulators are + configured for AMOLED mode. +- qcom,pmic-revid: Specifies the phandle of the PMIC revid module. + Used to identify the PMIC subtype. + +Main node optional properties: + +- qcom,qpnp-labibb-touch-to-wake-en: A boolean property which upon set will + enable support for touch-to-wake mode + by configuring the required settings + in LAB and IBB modules. Make sure the + hardware has needed support before + enabling this property. +- qcom,swire-control: A boolean property which indicates if the LAB/IBB is + controlled by the SWIRE interface. Enable only + if qcom,qpnp-labibb-mode = "amoled". +- qcom,labibb-ttw-force-lab-on: A boolean property which forces LAB to be + always on during TTW mode. +- qcom,skip-2nd-swire-cmd: A boolean property which indicates if + the second SWIRE command needs to be skipped. +- qcom,swire-2nd-cmd-delay: An integer value which specifes the + delay in millisecs between the first and second + SWIRE command. If not specified this value + defaults to 20ms. This delay is applied only + if 'qcom,skip-2nd-swire-cmd' is defined. +- qcom,swire-ibb-ps-enable-delay: An integer value which specifes the delay + in millisecs to enable IBB pulse-skipping + after the skip-2nd-swire-cmd workaround is applied. + If not specified this value default to 200ms. + This property is applicable only if + 'qcom,skip-2nd-swire-cmd' is specified. +- qcom,labibb-standalone: A boolean property which forces LAB and + IBB to operate in standalone mode. If + this is not specified, then LAB and IBB + are controlled together in dual mode. +- parent-supply: Parent supply that is needed for LAB + and IBB regulators. This will be mostly + needed when LAB and IBB are operating + in standalone mode to vote for MBG. + +Following properties are available only for PM660A: + +- qcom,pbs-control: A boolean property which indicates if + the LAB/IBB is controlled by the PBS + sequencer. If this mode is enabled the + PBS sequencer does the SWIRE remapping + and program the voltages based on the + SWIRE count. + +LAB subnode required properties: + +- reg: Specifies the SPMI address and size for this peripheral. +- reg-names: Register names. Must be "lab". +- regulator-name: A string used to describe the regulator. +- regulator-min-microvolt: Minimum voltage in microvolts supported by this regulator. +- regulator-max-microvolt: Maximum voltage in microvolts supported by this regulator. + +- qcom,qpnp-lab-min-voltage: The minimum voltage in microvolts LAB regulator can support. +- qcom,qpnp-lab-step-size: The step size in microvolts of LAB regulator. +- qcom,qpnp-lab-slew-rate: The time in us taken by the regulator to change + voltage value in one step. + +- qcom,qpnp-lab-init-voltage: The default initial voltage when the bootloader + does not turn on LAB regulator. +- qcom,qpnp-lab-init-amoled-voltage: The default output voltage when LAB regulator + is configured in amoled mode. +- qcom,qpnp-lab-init-lcd-voltage: The default output voltage when LAB regulator + is configured in lcd mode. +- qcom,qpnp-lab-ps-threshold: The threshold in mA of Pulse Skip Mode for + LAB regulator. Supported values for + PMI8994/6 are 20, 30, 40 and 50. + Supported values for PMI8998/PM660A are + 50, 60, 70 and 80. +- interrupts: Specify the interrupts as per the interrupt + encoding. + Currently "lab-vreg-ok" is required and "lab-sc_err" + is optional for LCD mode in pmi8998. + For AMOLED mode, "lab-vreg-ok" is required + only when SWIRE control is enabled and skipping + 2nd SWIRE pulse is required in pmi8952/8996. +- interrupt-names: Interrupt names to match up 1-to-1 with + the interrupts specified in 'interrupts' + property. + +LAB subnode optional properties: + +- qcom,qpnp-lab-current-sense: If this property is specified, the LAB current + sense gain will be programmed for LAB regulator. + Otherwise, LAB current sense gain will be + default to "1x". A string is used to specify the + LAB current sense gain. Could be "0.5x" or "1x" + or "1.5x" or "2x". For e.g. "0.5x" means current + sense gain is 0.5. +- qcom,qpnp-lab-ps-enable: A boolean proerty which upon set will enable + pulse skip mode for LAB regulator. Otherwise, + it is disabled. +- qcom,qpnp-lab-full-pull-down: A boolean property which upon set will enable + the pull down strength of LAB regulator to + full. Otherwise, the pull down strength is + configured to half. +- qcom,qpnp-lab-pull-down-enable: A boolean property which upon set will enable + the pull down for LAB regulator. Otherwise, + it is disabled. +- qcom,qpnp-lab-max-precharge-enable: A boolean property which upon set will + enable fast precharge. Otherwise, it is + disabled. +- qcom,qpnp-lab-ring-suppression-enable: A boolean property which upon set will + enable ring suppression for LAB + regulator. Otherwise, it is disabled. +- qcom,qpnp-lab-limit-max-current-enable: A boolean property which upon set will + enforce maximum inductor current constraint + for LAB regulator. Otherwise, there is no + maximum current constraint. +- qcom,qpnp-lab-switching-clock-frequency: The PWM switching clock frequency in + kHz of Lab regulator, Supported values + are: 3200, 2740, 2400, 2130, 1920, + 1750, 1600, 1480, 1370, 1280, 1200, + 1130, 1070, 1010, 960, 910. +- qcom,qpnp-lab-limit-maximum-current: The maximum inductor current limit in + mA of LAB regulator. Supported values + are 200, 400, 600, 800, 1000, 1200, + 1400 and 1600. +- qcom,qpnp-lab-pfet-size: PFET size in percentage. Supported values + are 25, 50, 75 and 100. +- qcom,qpnp-lab-nfet-size: NFET size in percentage. Supported values + are 25, 50, 75 and 100. +- qcom,qpnp-lab-max-precharge-time: Precharge time in uS for LAB regulator. + Supported values are 200, 300, 400 and 500. + Suggested values for LCD and AMOLED mode + are 500 and 300uS respectively. +- qcom,qpnp-lab-use-default-voltage: A boolean property which upon set will + use the value specified in + qcom,qpnp-lab-init-voltage property. + This will be used only if the bootloader + doesn't configure the output voltage + already. If it it not specified, then + output voltage can be configured to + any value in the allowed limit. +- qcom,notify-lab-vreg-ok-sts: A boolean property which upon set will + poll and notify the lab_vreg_ok status. +- qcom,qpnp-lab-sc-wait-time-ms: This property is used to specify the time + (in ms) to poll for the short circuit + detection. If not specified the default time + is 5 sec. + +Following properties are available only for PM660A: + +- qcom,qpnp-lab-soft-start: The soft start time in us of LAB regulator. + Supported value are 200, 400, 600 and 800. +- qcom,qpnp-lab-ldo-pulldown-enable: This property is used to enable/disable + the LDO pull down. + 1 - enable pulldown + 0 - disable pulldown +- qcom,qpnp-lab-enable-sw-high-psrr: A boolean property to enable the + software high psrr + (Power Suppy Rejection Rate) mode. +- qcom,qpnp-lab-high-psrr-src-select: This property is used to select the LAB + HW high psrr source. + The supported values are: + 0 = Either vph_high or high_psrr enable + 1 = vph_high only + 2 = high_psrr enable only + 3 = Either vph_high or high_psrr enable + This property is not valid if the + qcom,qpnp-lab-enable-sw-high-psrr property + is specified. +- qcom,qpnp-lab-vref-high-psrr-select: This property is required if the + qcom,qpnp-lab-high-psrr-src-select is + specified. The supported values (in mV) + are 350, 400, 450 and 500. Once the + rejection rate crosses the selected + high-psrr voltage the LDO is enabled + based on the value specified under + qcom,qpnp-lab-high-psrr-src-select + property. + This property is not valid if the + qcom,qpnp-lab-enable-sw-high-psrr property + is specified. + +IBB subnode required properties: + +- reg: Specifies the SPMI address and size for this peripheral. +- reg-names: Register names. Must be "ibb". +- regulator-name: A string used to describe the regulator. +- regulator-min-microvolt: Minimum voltage in microvolts supported by this regulator. +- regulator-max-microvolt: Maximum voltage in microvolts supported by this regulator. + +- qcom,qpnp-ibb-min-voltage: The minimum voltage in microvolts IBB regulator can support. +- qcom,qpnp-ibb-step-size: The step size in microvolts of IBB regulator. +- qcom,qpnp-ibb-soft-start: The soft start time in us of IBB regulator. + +- qcom,qpnp-ibb-init-voltage: The default initial voltage when the bootloader does + not turn on IBB regulator. +- qcom,qpnp-ibb-init-amoled-voltage: The default output voltage when IBB regulator + is configured in amoled mode. +- qcom,qpnp-ibb-init-lcd-voltage: The default output voltage when IBB regulator + is configured in lcd mode. + +IBB subnode optional properties: + +- interrupts: Specify the interrupts as per the interrupt + encoding. + Currently "ibb-sc-err" could be used for LCD mode + in pmi8998 to detect the short circuit fault. +- interrupt-names: Interrupt names to match up 1-to-1 with + the interrupts specified in 'interrupts' + property. + +- qcom,qpnp-ibb-discharge-resistor: The discharge resistor in Kilo Ohms which + controls the soft start time. Supported values + are 300, 64, 32 and 16. + +- qcom,qpnp-ibb-slew-rate: The time (in us) taken by the regulator to change + voltage value in one step. This property is not + applicable to PM660A. + The following properties can be used as an + alternate. + qcom,qpnp-ibb-slew-rate-config + qcom,qpnp-ibb-fast-slew-rate + qcom,qpnp-ibb-slow-slew-rate +- qcom,qpnp-ibb-ps-enable: A boolean property which upon set will enable + pulse skip mode for IBB regulator. Otherwise, + it is disabled. +- qcom,qpnp-ibb-num-swire-trans: The number of SWIRE transactions + after which the pulse skipping is + enabled. This property is required when + qpnp-ibb-smart-ps-enable property is + set. +- qcom,qpnp-ibb-neg-curr-limit: This property must be set when the + qpnp-ibb-smart-ps-enable is specified. + The supported values in mA are 1, 2, 3, + 4, 5, 6 and 7. The recommended value is +- qcom,qpnp-ibb-full-pull-down: A boolean property which upon set will + enable the pull down strength of IBB + regulator to full. Otherwise, the pull + down strength is configured to half. +- qcom,qpnp-ibb-pull-down-enable: A boolean property which upon set will enable + the pull down for IBB regulator. Otherwise, + it is disabled. +- qcom,qpnp-ibb-lab-pwrup-delay: Power up delay (in us) for IBB regulator when + it is enabled or turned on. Supported values + are 1000, 2000, 4000 and 8000. +- qcom,qpnp-ibb-lab-pwrdn-delay: Power down delay (in us) for IBB regulator + when it is disabled or turned off. Supported + values are 1000, 2000, 4000 and 8000. +- qcom,qpnp-ibb-switching-clock-frequency: The PWM switching clock frequency in + kHz of IBB regulator. Supported values + are: 3200, 2740, 2400, 2130, 1920, + 1750, 1600, 1480, 1370, 1280, 1200, + 1130, 1070, 1010, 960, 910. +- qcom,qpnp-ibb-limit-maximum-current: The maximum inductor current limit in + mA of IBB regulator. Supported values + are: 0, 50, 100, 150, 200, 250, 300, + 350, 400, 450, 500, 550, 600, 650, 700, + 750, 800, 850, 900, 950, 1000, 1050, + 1100, 1150, 1200, 1250, 1300, 1350, + 1400, 1450, 1500 and 1550. +- qcom,qpnp-ibb-debounce-cycle: The debounce cycle of IBB regulator. + Supported values are 8, 16, 32 and 64. +- qcom,qpnp-ibb-en-discharge: A boolean property which upon set will + enable discharge for IBB regulator. + Otherwise, it is kept disabled. +- qcom,qpnp-ibb-ring-suppression-enable: A boolean property which upon set will + enable ring suppression for IBB + regulator. Otherwise, it is disabled. +- qcom,qpnp-ibb-limit-max-current-enable: A boolean property which upon set will + enforce maximum inductor current constraint + for IBB regulator. Otherwise, there is no + maximum current constraint. +- qcom,qpnp-ibb-use-default-voltage: A boolean property which upon set will + use the value specified in + qcom,qpnp-ibb-init-voltage property. + This will be used only if the bootloader + doesn't configure the output voltage + already. If it it not specified, then + output voltage can be configured to + any value in the allowed limit. +- qcom,output-voltage-one-pulse: The expected voltage (in mV) of VDISN signal + on the first SWIRE pulse. This property + can be specified only if 'qcom,swire-control' + is defined. The minimum and maximum values + are 1400mV and 7700mV. + +Following properties are available only for PM660A: + +- qcom,qpnp-ibb-smart-ps-enable: A boolean property which upon set + enables smart pulse skip mode for IBB + regulator. Otherwise, it is disabled. + This property is only applicable to + PM660A. +- qcom,qpnp-ibb-enable-pfm-mode: A boolean property which enables the IBB to work + in pfm mode. +- qcom,qpnp-ibb-pfm-peak-curr: The PFM peak current limit settings in mA. + Supported values are 150, 200, 250, 300, + 350, 400, 450 and 500. This property is + required if the qcom,qpnp-ibb-enable-pfm-mode + is true. +- qcom,qpnp-ibb-pfm-hysteresis: The PFM hysteresis voltage threshold in mV. + Supported values are 0, 25 and 50. + This property is required if the + qcom,qpnp-ibb-enable-pfm-mode is specified. +- qcom,qpnp-ibb-overload-blank: A boolean property which upon set enables + the IBB overload blanking. +- qcom,qpnp-ibb-overload-debounce: The expected overload debounce time (in ms) + values are 1, 2, 4 and 8. + This property is required only when the + qcom,qpnp-ibb-overload-blank is set. +- qcom,qpnp-ibb-vreg-ok-debounce: The expected vreg-ok-debounce time (us) + values are 4, 8, 16 and 32. + This property is required only when the + qcom,qpnp-ibb-overload-blank is set. +- qcom,qpnp-ibb-slew-rate-config: A boolean property to configure the + ibb fast/slow slew rate. + Either qcom,qpnp-ibb-fast-slew-rate or + qcom,qpnp-ibb-slow-slew-rate has to be + specified. Otherwise the + qcom,qpnp-ibb-slow-slew-rate takes precedence + over the qcom,qpnp-ibb-fast-slew-rate. +- qcom,qpnp-ibb-fast-slew-rate: This property is required if the qcom, + qpnp-ibb-slew-rate-config property is + specified. Supported values (in us) are + 100, 200, 500, 1000, 2000, 10000, 12000 + and 15000. +- qcom,qpnp-ibb-slow-slew-rate: This property is required if the qcom, + qpnp-ibb-slew-rate-config property is + specified. Supported values (in us) are + 100, 200, 500, 1000, 2000, 10000, 12000 + and 15000. + +Example: + qcom,pmi8994@3 { + qpnp-labibb-regulator { + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-labibb-mode = "lcd"; + qcom,pmic-revid = <&pmi8994_revid>; + qcom,skip-2nd-swire-cmd; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + + interrupts = <0x3 0xde 0x0 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "lab-vreg-ok"; + + regulator-name = "lab_reg"; + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-use-default-voltage; + qcom,qpnp-lab-init-voltage = <5500000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + qcom,qpnp-lab-init-lcd-voltage = <5500000>; + + qcom,qpnp-lab-soft-start = <400>; + + qcom,qpnp-lab-full-pull-down; + qcom,qpnp-lab-pull-down-enable; + qcom,qpnp-lab-switching-clock-frequency = <1600>; + qcom,qpnp-lab-limit-maximum-current = <1600>; + qcom,qpnp-lab-limit-max-current-enable; + qcom,qpnp-lab-ps-threshold = <40>; + qcom,qpnp-lab-ps-enable; + qcom,qpnp-lab-nfet-size = <100>; + qcom,qpnp-lab-pfet-size = <100>; + qcom,qpnp-lab-max-precharge-time = <200>; + }; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-use-default-voltage; + qcom,qpnp-ibb-init-voltage = <5500000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + qcom,qpnp-ibb-init-lcd-voltage = <5500000>; + + qcom,qpnp-ibb-soft-start = <400>; + + qcom,qpnp-ibb-discharge-resistor = <300>; + qcom,qpnp-ibb-lab-pwrup-delay = <8000>; + qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; + qcom,qpnp-ibb-en-discharge; + + qcom,qpnp-ibb-full-pull-down; + qcom,qpnp-ibb-pull-down-enable; + qcom,qpnp-ibb-switching-clock-frequency = <1480>; + qcom,qpnp-ibb-limit-maximum-current = <1550>; + qcom,qpnp-ibb-debounce-cycle = <16>; + qcom,qpnp-ibb-limit-max-current-enable; + qcom,qpnp-ibb-ps-enable; + }; + + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-lcdb-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-lcdb-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..601a8e73733bb077a2c8b55b5d137f77115a400b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-lcdb-regulator.txt @@ -0,0 +1,276 @@ +QPNP LCDB (LCD Bias) Regulator + +QPNP LCDB module provides voltage bias to the LCD display panel. The biases +are positive (VDISP - supported by LDO) and negative (VDISN - supported by +NCP) voltage signals. The module also supports TTW (touch-to-wake) capability. + +This document describes the bindings for QPNP LCDB module. + +======================= +Required Node Structure +======================= + +LCDB module must be described in two level of device nodes. + +============================== +First Level Node - LCDB module +============================== + +- compatible + Usage: required + Value type: + Definition: should be "qcom,qpnp-lcdb-regulator" + +- reg + Usage: required + Value type: + Definition: Base address of the LCDB SPMI peripheral. + +- qcom,pmic-revid + Usage: required + Value type: + Definition: Phandle to the PMIC's revid node + +- qcom,voltage-step-ramp + Usage: optional + Value type: + Definition: Required only if the voltage needs to be set in the + steps of 500 mV starting from the 4500 mV. This needs + to be enabled only on platforms where voltage needs to + be ramped up with multiple steps. + +- qcom,pwrdn-delay-ms + Usage: optional + Value type: + Definition: Required to control the LDO power down delay. + Possible values are 0, 1, 4, 8. + +Touch-to-wake (TTW) properties: + +TTW supports 2 modes of operation - HW and SW. In the HW mode the enable/disable +logic is controlled by an external signal (pin) where as in the SW mode it is +is controlled by a pre-configured timer (ton/toff) programmed in the TTW +register. + +Properties below are specific to TTW mode only. They are sepecified in the +main node. + +- qcom,ttw-enable + Usage: optional + Value type: + Definition: Touch to wake-up support enabled. + +- qcom,ttw-mode-sw + Usage: optional + Value type: + Definition: Touch to wake supported in SW mode. + If not defined, ttw is enabled by HW pin. + +- qcom,attw-toff-ms + Usage: required if 'qcom,ttw-mode-sw' is true. + Value type: + Definition: Off time (in mS) for the VDISP/VDISN signals. + Possible values are 4, 8, 16, 32. + +- qcom,attw-ton-ms + Usage: required if 'qcom,ttw-mode-sw' is true. + Value type: + Definition: ON time (in mS) for the VDISP/VDISN signals. + Possible values are 4, 8, 16, 32. + +======================================== +Second Level Nodes - LDO/NCP/BOOST block +======================================== + +LDO / NCP subnode common properties: + +Properties below are common to the LDO and NCP bias. + +- label + Usage: required + Value type: + Definition: A string used to describe the bias type. + Possible values are ldo, ncp, bst. + +- regulator-name + Usage: required + Value type: + Definition: A string used to describe the regulator. + +- regulator-min-microvolt + Usage: required + Value type: + Definition: Minimum voltage (in uV) supported by the bias. + +- regulator-max-microvolt + Usage: required + Value type: + Definition: Maximum voltage (in uV) supported by the bias. + + +LDO subnode properties: + +Properties below are specific to LDO bias only. + +- qcom,ldo-voltage-mv + Usage: optional + Value type: + Definition: Voltage (in mV) progammed for the LDO (VDISP). + Possile values are 4000mV to 6000mV. The range + 4000mV to 4900mV is in 100mV steps and 4900mV to + 6000mV is in 50mV steps. + +- qcom,ldo-pd + Usage: optional + Value type: + Definition: Pull-down configuration of LDO. Possible values are: + 1 - Enable pull-down + 0 - Disable pull-down + +- qcom,ldo-pd-strength + Usage: optional + Value type: + Definition: Pull-down strength. Possible values are: + 0 - Weak pull-down + 1 - Strong pull-down + +- qcom,ldo-ilim-ma + Usage: optional + Value type: + Definition: Current limit (in mA) of the LDO bias. + Possible values are 110, 160, 210, 260, 310, 360, 410, 460. + +- qcom,ldo-soft-start-us + Usage: optional + Value type: + Definition: Soft-start time (in uS) of the LDO bias. + Possible values are 0, 500, 1000, 2000. + + +NCP subnode properties: + +Properties below are specific to NCP bias only. + +- qcom,ncp-voltage-mv + Usage: optional + Value type: + Definition: Voltage (in mV) progammed for the NCP (VDISN). + Possile values are 4000mV to 6000mV. The range + 4000mV to 4900mV is in 100mV steps and 4900mV to + 6000mV is in 50mV steps. + +- qcom,ncp-pd + Usage: optional + Value type: + Definition: Pull-down configuration of NCP. Possible values are: + 1 - Enable pull-down + 0 - Disable pull-down + +- qcom,ncp-pd-strength + Usage: optional + Value type: + Definition: Pull-down strength. Possible values are: + 0 - Weak pull-down + 1 - Strong pull-down + +- qcom,ncp-ilim-ma + Usage: optional + Value type: + Definition: Current limit (in mA) of the NCP bias. + Possible values are 260, 460, 640, 810. + +- qcom,ncp-soft-start-us + Usage: optional + Value type: + Definition: Soft-start time (in uS) of the NCP bias. + Possible values are 0, 500, 1000, 2000. + + +BOOST subnode properties: + +Properties below are specific to BOOST subnode only. + +- qcom,bst-pd + Usage: optional + Value type: + Definition: Pull-down configuration of BOOST. Possible values are: + 1 - Enable pull-down + 0 - Disable pull-down + +- qcom,bst-pd-strength + Usage: optional + Value type: + Definition: Pull-down strength. Possible values are: + 0 - Weak pull-down + 1 - Strong pull-down + +- qcom,bst-ps + Usage: optional + Value type: + Definition: Pulse-skip configuration for boost. Possible values are: + 1 - Enable Pulse-skip + 0 - Disable Pulse-skip + +- qcom,bst-ps-threshold-ma + Usage: optional + Value type: + Definition: Current threshold (in mA) at which pulse-skip is entered. + Possible values are 50, 60, 70, 80. + +- qcom,bst-ilim-ma + Usage: optional + Value type: + Definition: Current limit (in mA) of the BOOST rail. + Possible values are 200 to 1600mA in 200mA steps. + +- qcom,bst-headroom-mv + Usage: optional + Value type: + Definition: Headroom of the boost (in mV). If not specified, then the + default value is 200 mV (PM660L) or 150 mV (for PM8150L or + PMI632). + +======= +Example +======= + +pm660l_lcdb: qpnp-lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + + qcom,ttw-enable; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + + qcom,ldo-voltage-mv = <5400>; + qcom,ldo-pd = <1>; + qcom,ldo-pd-strength = <1>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + + qcom,ncp-voltage-mv = <5400>; + qcom,ncp-pd = <1>; + qcom,ncp-pd-strength = <1>; + }; + + lcdb_bst: bst { + label = "bst"; + + qcom,bst-pd = <1>; + qcom,bst-pd-strength = <1>; + qcom,bst-ps = <1>; + qcom,bst-ps-threshold-ma = <50>; + qcom,bst-headroom-mv = <200>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-oledb-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-oledb-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..55fde0d4feb6321295314745e07b3316af5c9f60 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/qpnp-oledb-regulator.txt @@ -0,0 +1,243 @@ +QPNP OLEDB (AMOLED AVDD Bias) Regulator + +QPNP OLEDB module provides AVDD voltage bias to the AMOLED display panel. +The supported voltage range is 5V to 8.1V. + +This document describes the bindings for QPNP OLEDB module. + +======================= +Required Node Structure +======================= + +- compatible + Usage: required + Value type: + Definition: should be "qcom,qpnp-oledb-regulator". + +- qcom,pmic-revid + Usage: required + Value type: + Definition: Used to identify the PMIC subtype. + +- reg + Usage: required + Value type: + Definition: Base address of the OLEDB SPMI peripheral. + +- label + Usage: required + Value type: + Definition: A string used to describe the bias type(oledb). + +- regulator-name + Usage: required + Value type: + Definition: A string used to describe the regulator. + +- regulator-min-microvolt + Usage: required + Value type: + Definition: Minimum voltage (in uV) supported by the bias (5000000uV). + +- regulator-max-microvolt + Usage: required + Value type: + Definition: Maximum voltage (in uV) supported by the bias (8100000uV). + +- qcom,swire-control + Usage: optional + Value type: + Definition: Enables the voltage programming through SWIRE signal. + +- qcom,ext-pin-control + Usage: optional + Value type: + Definition: Configures the OLED module to be enabled by a external pin. + +- qcom,dynamic-ext-pinctl-config + Usage: optional + Value type: + Definition: Used to dynamically enable/disable the OLEDB module + using external pin to avoid the glitches on the voltage + rail. This property is applicable only if qcom,ext-pin-ctl + property is specified and it is specific to PM660A. + +- qcom,pbs-client + Usage: optional + Value type: + Definition: Used to send the PBS trigger to the specified PBS client. + This property is applicable only if qcom,force-pd-control + property is specified. + +- qcom,pbs-control + Usage: optional + Value type: + Definition: PMIC PBS logic directly configures the output voltage update + and pull down control. + +- qcom,oledb-init-voltage-mv + Usage: optional + Value type: + Definition: Sets the AVDD bias voltage (in mV) when the module is + already enabled. Applicable only if the qcom,swire-control + property is not specified. Supported values are from 5.0V + to 8.1V with a step of 100mV. + +- qcom,oledb-default-voltage-mv + Usage: optional + Value type: + Definition: Sets the default AVDD bias voltage (in mV) before module + enable. Supported values are from 5.0V to 8.1V with the + step of 100mV. + +- qcom,bias-gen-warmup-delay-ns + Usage: optional + Value type: + Definition: Bias generator warm-up time (ns). Supported values are + 6700, 13300, 267000, 534000. + +- qcom,peak-curr-limit-ma + Usage: optional + Value type: + Definition: Peak current limit (in mA). Supported values are 115, 265, + 415, 570, 720, 870, 1020, 1170. + +- qcom,pull-down-enable + Usage: optional + Value type: + Definition: Pull down configuration of OLEDB. + 1 - Enable pull-down + 0 - Disable pull-down + +- qcom,negative-curr-limit-enable + Usage: optional + Value type: + Definition: negative current limit enable/disable. + 1 = enable negative current limit + 0 = disable negative current limit + +- qcom,negative-curr-limit-ma + Usage: optional + Value type: + Definition: Negative current limit (in mA). Supported values are + 170, 300, 420, 550. + +- qcom,enable-short-circuit + Usage: optional + Value type: + Definition: Short circuit protection enable/disable. + 1 = enable short circuit protection + 0 = disable short circuit protection + +- qcom,short-circuit-dbnc-time + usage: optional + Value type: + Definitioan: Short circuit debounce time (in Fsw). Supported + values are 2, 4, 8, 16. + +Fast precharge properties: +------------------------- + +- qcom,fast-precharge-ppulse-enable + usage: optional + Value type: + Definitioan: Fast precharge pfet pulsing enable/disable. + 1 = enable fast precharge pfet pulsing + 0 = disable fast precharge pfet pulsing + +- qcom,precharge-debounce-time-ms + usage: optional + Value type: + Definitioan: Fast precharge debounce time (in ms). Supported + values are 1, 2, 4, 8. + +- qcom,precharge-pulse-period-us + usage: optional + Value type: + Definitioan: Fast precharge pulse period (in us). Supported + values are 3, 6, 9, 12. + +- qcom,precharge-pulse-on-time-us + usage: optional + Value type: + Definitioan: Fast precharge pulse on time (in ns). Supported + values are 1200, 1800, 2400, 3000. + +Pulse Skip Modulation (PSM) properties: +-------------------------------------- + +- qcom,psm-enable + Usage: optional + Value type: + Definition: Pulse Skip Modulation mode. + 1 - Enable PSM mode + 0 - Disable PSM mode + +- qcom,psm-hys-mv + Usage: optional + Value type: + Definition: PSM hysterysis voltage (in mV). + Supported values are 13mV and 26mV. + +- qcom,psm-vref-mv + Usage: optional + Value type: + Definition: Reference voltage(in mV) control for PSM comparator. + Supported values are 440, 510, 580, 650, 715, 780, 850, + and 920. + +Pulse Frequency Modulation (PFM) properties: +------------------------------------------- + +- qcom,pfm-enable + Usage: optional + Value type: + Definition: Pulse Frequency Modulation mode. + 1 - Enable PFM mode + 0 - Disable PFM mode + +- qcom,pfm-hys-mv + Usage: optional + Value type: + Definition: PFM hysterysis voltage (in mV). + Supported values are 13mV and 26mV. + +- qcom,pfm-curr-limit-ma + Usage: optional + Value type: + Definition: PFM current limit (in mA). + Supported values are 130, 200, 270, 340. + +- qcom,pfm-off-time-ns + Usage: optional + Value type: + Definition: NFET off time at PFM (in ns). + Supported values are 110, 240, 350, 480. + +======= +Example +======= + +pm660a_oledb: qpnp-oledb@e000 { + compatible = "qcom,qpnp-oledb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; + reg = <0xe000 0x100>; + + label = "oledb"; + regulator-name = "regulator-oledb"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <8100000>; + + qcom,swire-control; + qcom,ext-pin-control; + + qcom,oledb-default-voltage-mv = <5000>; + qcom,bias-gen-warmup-delay-ns = <6700>; + qcom,pull-down-enable = <1>; + qcom,peak-curr-limit-ma = <570>; + + qcom, enable-psm = <1>; + qcom,psm-hys-mv = <13>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/regulator-max77620.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/regulator-max77620.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c4bfe786736ae002badcf9cc4cf07e14de30119 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/regulator-max77620.txt @@ -0,0 +1,222 @@ +Regulator DT binding for MAX77620 Power management IC from Maxim Semiconductor. + +Device has multiple DCDC(sd[0-3] and LDOs(ldo[0-8]). The input supply +of these regulators are defined under parent device node. +Details of regulator properties are defined as child node under +sub-node "regulators" which is child node of device node. + +Please refer file +for common regulator bindings used by client. + +Following are properties of parent node related to regulators. + +Optional properties: +------------------- +The input supply of regulators are the optional properties on the +parent device node. The input supply of these regulators are provided +through following properties: +in-sd0-supply: Input supply for SD0, INA-SD0 or INB-SD0 pins. +in-sd1-supply: Input supply for SD1. +in-sd2-supply: Input supply for SD2. +in-sd3-supply: Input supply for SD3. +in-ldo0-1-supply: Input supply for LDO0 and LDO1. +in-ldo2-supply: Input supply for LDO2. +in-ldo3-5-supply: Input supply for LDO3 and LDO5 +in-ldo4-6-supply: Input supply for LDO4 and LDO6. +in-ldo7-8-supply: Input supply for LDO7 and LDO8. + +Optional sub nodes for regulators under "regulators" subnode: +------------------------------------------------------------ +The subnodes name is the name of regulator and it must be one of: + sd[0-3], ldo[0-8] + +Each sub-node should contain the constraints and initialization +information for that regulator. The definition for each of these +nodes is defined using the standard binding for regulators found at +. + +Theres are also additional properties for SD/LDOs. These additional properties +are required to configure FPS configuration parameters for SDs and LDOs. +Please refer for more detail of Flexible +Power Sequence (FPS). +Following are additional properties: + +- maxim,active-fps-source: FPS source for the regulators to get + enabled/disabled when system is in + active state. Valid values are: + - MAX77620_FPS_SRC_0, + FPS source is FPS0. + - MAX77620_FPS_SRC_1, + FPS source is FPS1 + - MAX77620_FPS_SRC_2 and + FPS source is FPS2 + - MAX77620_FPS_SRC_NONE. + Regulator is not controlled + by FPS events and it gets + enabled/disabled by register + access. + Absence of this property will leave + the FPS configuration register for that + regulator to default configuration. + +- maxim,active-fps-power-up-slot: Sequencing event slot number on which + the regulator get enabled when + master FPS input event set to HIGH. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + +- maxim,active-fps-power-down-slot: Sequencing event slot number on which + the regulator get disabled when master + FPS input event set to LOW. + Valid values are 0 to 7. + This is applicable if FPS source is + selected as FPS0, FPS1 or FPS2. + +- maxim,suspend-fps-source: This is same as property + "maxim,active-fps-source" but value + get configured when system enters in + to suspend state. + +- maxim,suspend-fps-power-up-slot: This is same as property + "maxim,active-fps-power-up-slot" but + this value get configured into FPS + configuration register when system + enters into suspend. + This is applicable if suspend state + FPS source is selected as FPS0, FPS1 or + +- maxim,suspend-fps-power-down-slot: This is same as property + "maxim,active-fps-power-down-slot" but + this value get configured into FPS + configuration register when system + enters into suspend. + This is applicable if suspend state + FPS source is selected as FPS0, FPS1 or + FPS2. +- maxim,ramp-rate-setting: integer, ramp rate(uV/us) setting to be + configured to the device. + The platform may have different ramp + rate than advertised ramp rate if it has + design variation from Maxim's + recommended. On this case, platform + specific ramp rate is used for ramp time + calculation and this property is used + for device register configurations. + The measured ramp rate of platform is + provided by the regulator-ramp-delay + as described in . + Maxim Max77620 supports following ramp + delay: + SD: 13.75mV/us, 27.5mV/us, 55mV/us + LDOs: 5mV/us, 100mV/us + +Note: If the measured ramp delay is same as advertised ramp delay then it is not +required to provide the ramp delay with property "maxim,ramp-rate-setting". The +ramp rate can be provided by the regulator-ramp-delay which will be used for +ramp time calculation for voltage change as well as for device configuration. + +Example: +-------- +#include +... +max77620@3c { + in-ldo0-1-supply = <&max77620_sd2>; + in-ldo7-8-supply = <&max77620_sd2>; + regulators { + sd0 { + regulator-name = "vdd-core"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + maxim,active-fps-source = ; + }; + + sd1 { + regulator-name = "vddio-ddr"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + maxim,active-fps-source = ; + }; + + sd2 { + regulator-name = "vdd-pre-reg"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + }; + + sd3 { + regulator-name = "vdd-1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo0 { + regulator-name = "avdd-sys"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo1 { + regulator-name = "vdd-pex"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + ldo2 { + regulator-name = "vddio-sdmmc3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + + ldo3 { + regulator-name = "vdd-cam-hv"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo4 { + regulator-name = "vdd-rtc"; + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <1250000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo5 { + regulator-name = "avdd-ts-hv"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + ldo6 { + regulator-name = "vdd-ts"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo7 { + regulator-name = "vdd-gen-pll-edp"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + regulator-boot-on; + }; + + ldo8 { + regulator-name = "vdd-hdmi-dp"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7cd36877bfe046905f5d8a4020985a0e6736c7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/regulator.txt @@ -0,0 +1,133 @@ +Voltage/Current Regulators + +Optional properties: +- regulator-name: A string used as a descriptive name for regulator outputs +- regulator-min-microvolt: smallest voltage consumers may set +- regulator-max-microvolt: largest voltage consumers may set +- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops +- regulator-min-microamp: smallest current consumers may set +- regulator-max-microamp: largest current consumers may set +- regulator-input-current-limit-microamp: maximum input current regulator allows +- regulator-always-on: boolean, regulator should never be disabled +- regulator-boot-on: bootloader/firmware enabled regulator +- regulator-allow-bypass: allow the regulator to go into bypass mode +- regulator-allow-set-load: allow the regulator performance level to be configured +- -supply: phandle to the parent supply/regulator node +- regulator-ramp-delay: ramp delay for regulator(in uV/us) + For hardware which supports disabling ramp rate, it should be explicitly + initialised to zero (regulator-ramp-delay = <0>) for disabling ramp delay. +- regulator-enable-ramp-delay: The time taken, in microseconds, for the supply + rail to reach the target voltage, plus/minus whatever tolerance the board + design requires. This property describes the total system ramp time + required due to the combination of internal ramping of the regulator itself, + and board design issues such as trace capacitance and load on the supply. +- regulator-settling-time-us: Settling time, in microseconds, for voltage + change if regulator have the constant time for any level voltage change. + This is useful when regulator have exponential voltage change. +- regulator-settling-time-up-us: Settling time, in microseconds, for voltage + increase if the regulator needs a constant time to settle after voltage + increases of any level. This is useful for regulators with exponential + voltage changes. +- regulator-settling-time-down-us: Settling time, in microseconds, for voltage + decrease if the regulator needs a constant time to settle after voltage + decreases of any level. This is useful for regulators with exponential + voltage changes. +- regulator-soft-start: Enable soft start so that voltage ramps slowly +- regulator-state-mem sub-root node for Suspend-to-RAM mode + : suspend to memory, the device goes to sleep, but all data stored in memory, + only some external interrupt can wake the device. +- regulator-state-disk sub-root node for Suspend-to-DISK mode + : suspend to disk, this state operates similarly to Suspend-to-RAM, + but includes a final step of writing memory contents to disk. +- regulator-state-[mem/disk] node has following common properties: + - regulator-on-in-suspend: regulator should be on in suspend state. + - regulator-off-in-suspend: regulator should be off in suspend state. + - regulator-suspend-min-microvolt: minimum voltage may be set in + suspend state. + - regulator-suspend-max-microvolt: maximum voltage may be set in + suspend state. + - regulator-suspend-microvolt: the default voltage which regulator + would be set in suspend. This property is now deprecated, instead + setting voltage for suspend mode via the API which regulator + driver provides is recommended. + - regulator-changeable-in-suspend: whether the default voltage and + the regulator on/off in suspend can be changed in runtime. + - regulator-mode: operating mode in the given suspend state. + The set of possible operating modes depends on the capabilities of + every hardware so the valid modes are documented on each regulator + device tree binding document. +- regulator-initial-mode: initial operating mode. The set of possible operating + modes depends on the capabilities of every hardware so each device binding + documentation explains which values the regulator supports. +- regulator-allowed-modes: list of operating modes that software is allowed to + configure for the regulator at run-time. Elements may be specified in any + order. The set of possible operating modes depends on the capabilities of + every hardware so each device binding document explains which values the + regulator supports. +- regulator-system-load: Load in uA present on regulator that is not captured by + any consumer request. +- regulator-pull-down: Enable pull down resistor when the regulator is disabled. +- regulator-over-current-protection: Enable over current protection. +- regulator-active-discharge: tristate, enable/disable active discharge of + regulators. The values are: + 0: Disable active discharge. + 1: Enable active discharge. + Absence of this property will leave configuration to default. +- regulator-coupled-with: Regulators with which the regulator + is coupled. The linkage is 2-way - all coupled regulators should be linked + with each other. A regulator should not be coupled with its supplier. +- regulator-coupled-max-spread: Max spread between voltages of coupled regulators + in microvolts. + +Deprecated properties: +- regulator-compatible: If a regulator chip contains multiple + regulators, and if the chip's binding contains a child node that + describes each regulator, then this property indicates which regulator + this child node is intended to configure. If this property is missing, + the node's name will be used instead. + +Example: + + xyzreg: regulator@0 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + vin-supply = <&vin>; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + +Regulator Consumers: +Consumer nodes can reference one or more of its supplies/ +regulators using the below bindings. + +- -supply: phandle to the regulator node + +These are the same bindings that a regulator in the above +example used to reference its own supply, in which case +its just seen as a special case of a regulator being a +consumer itself. + +Example of a consumer device node (mmc) referencing two +regulators (twl_reg1 and twl_reg2), + + twl_reg1: regulator@0 { + ... + ... + ... + }; + + twl_reg2: regulator@1 { + ... + ... + ... + }; + + mmc: mmc@0 { + ... + ... + vmmc-supply = <&twl_reg1>; + vmmcaux-supply = <&twl_reg2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/rohm,bd71837-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/rohm,bd71837-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..76ead07072b130a54c84a80e88c1f965c7cc6de0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/rohm,bd71837-regulator.txt @@ -0,0 +1,118 @@ +ROHM BD71837 Power Management Integrated Circuit (PMIC) regulator bindings + +Required properties: + - regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7" + +List of regulators provided by this controller. BD71837 regulators node +should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at +Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt +Regulator nodes should be named to BUCK_ and LDO_. The +definition for each of these nodes is defined using the standard +binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. +Note that if BD71837 starts at RUN state you probably want to use +regulator-boot-on at least for BUCK6 and BUCK7 so that those are not +disabled by driver at startup. LDO5 and LDO6 are supplied by those and +if they are disabled at startup the voltage monitoring for LDO5/LDO6 will +cause PMIC to reset. + +The valid names for regulator nodes are: +BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8 +LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7 + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt + +Example: +regulators { + buck1: BUCK1 { + regulator-name = "buck1"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-ramp-delay = <1250>; + }; + buck2: BUCK2 { + regulator-name = "buck2"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <1250>; + }; + buck3: BUCK3 { + regulator-name = "buck3"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + }; + buck4: BUCK4 { + regulator-name = "buck4"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1300000>; + regulator-boot-on; + }; + buck5: BUCK5 { + regulator-name = "buck5"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1350000>; + regulator-boot-on; + }; + buck6: BUCK6 { + regulator-name = "buck6"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + buck7: BUCK7 { + regulator-name = "buck7"; + regulator-min-microvolt = <1605000>; + regulator-max-microvolt = <1995000>; + regulator-boot-on; + }; + buck8: BUCK8 { + regulator-name = "buck8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1400000>; + }; + + ldo1: LDO1 { + regulator-name = "ldo1"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + ldo2: LDO2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + }; + ldo3: LDO3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + ldo4: LDO4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + }; + ldo5: LDO5 { + regulator-name = "ldo5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; + ldo6: LDO6 { + regulator-name = "ldo6"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + }; + ldo7_reg: LDO7 { + regulator-name = "ldo7"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + }; +}; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/rpm-smd-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/rpm-smd-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..a44b6a73499cd27ec487346c55586e6b37bb0c36 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/rpm-smd-regulator.txt @@ -0,0 +1,336 @@ +Qualcomm Technologies, Inc. RPM Regulators + +rpm-regulator-smd is a regulator driver which supports regulators inside of +PMICs which are controlled by the RPM processor. Communication with the RPM +processor takes place over SMD. + +Required structure: +- RPM regulators must be described in two levels of devices nodes. The first + level describes the interface with the RPM. The second level describes + properties of one regulator framework interface (of potentially many) to + the regulator. + +[First Level Nodes] + +Required properties: +- compatible: Must be "qcom,rpm-smd-regulator-resource" +- qcom,resource-name: Resource name string for this regulator to be used in RPM + transactions. Length is 4 characters max. +- qcom,resource-id: Resource instance ID for this regulator to be used in RPM + transactions. +- qcom,regulator-type: Type of this regulator. Supported values are: + 0 = LDO + 1 = SMPS + 2 = VS + 3 = NCP + 4 = Buck or Boost (BoB) + +Optional properties: +- qcom,allow-atomic: Flag specifying if atomic access is allowed for this + regulator. Supported values are: + 0 or not present = mutex locks used + 1 = spinlocks used +- qcom,enable-time: Time in us to delay after enabling the regulator +- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load + which requires the regulator to be in high power mode. +- qcom,apps-only: Flag which indicates that the regulator only has + consumers on the application processor. If this flag + is specified, then voltage and current updates are + only sent to the RPM if the regulator is enabled. +- qcom,always-wait-for-ack: Flag which indicates that the application + processor must wait for an ACK or a NACK from the RPM + for every request sent for this regulator including + those which are for a strictly lower power state. + +- qcom,regulator-hw-type: Specifies the regulator LDO hardware type. This + property must be specified if "qcom,regulator-type" + has been specified with a value of 0 (LDO). + + Must be one of the below: + "pmic4-ldo" for PMIC4. + "pmic5-ldo" for PMIC5. + +[Second Level Nodes] + +Required properties: +- compatible: Must be "qcom,rpm-smd-regulator" +- regulator-name: A string used as a descriptive name for regulator outputs +- qcom,set: Specifies which sets that requests made with this + regulator interface should be sent to. Regulator + requests sent in the active set take effect immediately. + Requests sent in the sleep set take effect when the Apps + processor transitions into RPM assisted power collapse. + Supported values are: + 1 = Active set only + 2 = Sleep set only + 3 = Both active and sleep sets + + + +Optional properties: +- parent-supply: phandle to the parent supply/regulator node +- qcom,system-load: Load in uA present on regulator that is not + captured by any consumer request +- qcom,use-voltage-corner: Flag that signifies if regulator_set_voltage + calls should modify the corner parameter instead + of the voltage parameter. When used, voltages + specified inside of the regulator framework + represent corners that have been incremented by + 1. This value shift is necessary to work around + limitations in the regulator framework which + treat 0 uV as an error. +- qcom,use-voltage-floor-corner: Flag that signifies if regulator_set_voltage + calls should modify the floor corner parameter + instead of the voltage parameter. When used, + voltages specified inside of the regulator + framework represent corners that have been + incremented by 1. The properties + qcom,use-voltage-corner and + qcom,use-voltage-floor-corner are mutually + exclusive. Only one may be specified for a + given regulator. +- qcom,use-voltage-level: Flag that signifies if regulator_set_voltage + calls should modify the level parameter instead + of the voltage parameter. +- qcom,use-voltage-floor-level: Flag that signifies if regulator_set_voltage + calls should modify the floor level parameter + instead of the voltage parameter. + The properties qcom,use-voltage-level and + qcom,use-voltage-floor-level are mutually + exclusive. Only one may be specified for a + given regulator. +- qcom,use-pin-ctrl-voltage1: Flag which indicates that updates to voltage + should be sent to the pin control voltage 1 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,use-pin-ctrl-voltage2: Flag which indicates that updates to voltage + should be sent to the pin control voltage 2 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,use-pin-ctrl-voltage3: Flag which indicates that updates to voltage + should be sent to the pin control voltage 3 + parameter. Only one pin may be specified per + regulator. This property only applies to BoB + type regulators. +- qcom,always-send-voltage: Flag which indicates that updates to the + voltage, voltage corner or voltage level set + point should always be sent immediately to the + RPM. If this flag is not specified, then + voltage set point updates are only sent if the + given regulator has also been enabled by a + Linux consumer. +- qcom,always-send-current: Flag which indicates that updates to the load + current should always be sent immediately to the + RPM. If this flag is not specified, then load + current updates are only sent if the given + regulator has also been enabled by a Linux + consumer. +- qcom,send-defaults: Boolean flag which indicates that the initial + parameter values should be sent to the RPM + before consumers make their own requests. If + this flag is not specified, then initial + parameters values will only be sent after some + consumer makes a request. +- qcom,enable-with-pin-ctrl: Double in which the first element corresponds to + the pin control enable parameter value to send + when all consumers have requested the regulator + to be disabled. The second element corresponds + to the pin control enable parameter value to + send when any consumer has requested the + regulator to be enabled. Each element supports + the same set of values as the + qcom,init-pin-ctrl-enable property listed below. + +The following properties specify initial values for parameters to be sent to the +RPM in regulator requests. +- qcom,init-enable: 0 = regulator disabled + 1 = regulator enabled +- qcom,init-voltage: Voltage in uV +- qcom,init-current: Current in mA +- qcom,init-ldo-mode: Operating mode to be used with LDO regulators + Supported values are: + 0 = mode determined by current requests + 1 = force HPM (NPM) +- qcom,init-smps-mode: Operating mode to be used with SMPS regulators + Supported values are: + 0 = auto; hardware determines mode + 1 = mode determined by current requests + 2 = force HPM (PWM) +- qcom,init-bob-mode: Operating mode to be used with BoB regulators + Supported values are: + 0 = pass; use priority order + 1 = force PFM + 2 = auto; hardware determines mode + 3 = force PWM +- qcom,init-pin-ctrl-enable: Bit mask specifying which hardware pins should be + used to enable the regulator, if any; supported + bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal +- qcom,init-pin-ctrl-mode: Bit mask specifying which hardware pins should be + used to force the regulator into high power + mode, if any. Supported bits are: + 0 = ignore all hardware enable signals + BIT(0) = follow HW0_EN signal + BIT(1) = follow HW1_EN signal + BIT(2) = follow HW2_EN signal + BIT(3) = follow HW3_EN signal + BIT(4) = follow PMIC awake state +- qcom,init-pin-ctrl-voltage1: Minimum voltage in micro-volts to use while pin + control 1 is enabled. This property only + applies to BoB type regulators. +- qcom,init-pin-ctrl-voltage2: Minimum voltage in micro-volts to use while pin + control 2 is enabled. This property only + applies to BoB type regulators. +- qcom,init-pin-ctrl-voltage3: Minimum voltage in micro-volts to use while pin + control 3 is enabled. This property only + applies to BoB type regulators. +- qcom,init-frequency: Switching frequency divisor for SMPS regulators. + Supported values are n = 0 to 31 where + freq = 19.2 MHz / (n + 1). +- qcom,init-head-room: Voltage head room in mV required for the + regulator. This head room value should be used + in situations where the device connected to the + output of the regulator has low noise tolerance. + Note that the RPM independently enforces a + safety head room value for subregulated LDOs + which is sufficient to account for LDO drop-out + voltage. +- qcom,init-quiet-mode: Specify that quiet mode is needed for an SMPS + regulator in order to have lower output noise. + Supported values are: + 0 = No quiet mode + 1 = Quiet mode + 2 = Super quiet mode +- qcom,init-freq-reason: Consumer requiring specified frequency for an + SMPS regulator. Supported values are: + 0 = None + 1 = Bluetooth + 2 = GPS + 4 = WLAN + 8 = WAN +- qcom,init-voltage-corner: Performance corner to use in order to determine + voltage set point. This value corresponds to + the actual value that will be sent and is not + incremented by 1 like the values used inside of + the regulator framework. The meaning of corner + values is set by the RPM. It is possible that + different regulators on a given platform or + similar regulators on different platforms will + utilize different corner values. These are + corner values supported on MSM8974 for PMIC + PM8841 SMPS 2 (VDD_Dig); nominal voltages for + these corners are also shown: + 0 = None (don't care) + 1 = Retention (0.5000 V) + 2 = SVS Krait (0.7250 V) + 3 = SVS SOC (0.8125 V) + 4 = Normal (0.9000 V) + 5 = Turbo (0.9875 V) + 6 = Super Turbo (1.0500 V) +- qcom,init-disallow-bypass: Specify that bypass mode should not be used for a + given LDO regulator. When in bypass mode, an + LDO performs no regulation and acts as a simple + switch. The RPM can utilize this mode for an + LDO that is subregulated from an SMPS when it is + possible to reduce the SMPS voltage to the + desired LDO output level. Bypass mode may be + disallowed if lower LDO output noise is + required. Supported values are: + 0 = Allow RPM to utilize LDO bypass mode + if possible + 1 = Disallow LDO bypass mode +- qcom,init-voltage-floor-corner: Minimum performance corner to use if any + processor in the system is awake. This property + supports the same values as + qcom,init-voltage-corner. +- qcom,init-voltage-level: Performance level to use in order to determine + voltage set point. The meaning of level + values is set by the RPM. It is possible that + different regulators on a given platform or + similar regulators on different platforms will + utilize different level values. These are + level values supported on MSM8952 for PMIC + PM8952 SMPS 2 (VDD_Dig); nominal voltages for + these level are also shown: + 16 = Retention (0.5000 V) + 128 = SVS (1.0500 V) + 192 = SVS+ (1.1550 V) + 256 = Normal (1.2250 V) + 320 = Normal+ (1.2875 V) + 384 = Turbo (1.3500 V) +- qcom,init-voltage-floor-level: Minimum performance level to use if any + processor in the system is awake. This property + supports the same values as + qcom,init-voltage-level. + +All properties specified within the core regulator framework can also be used in +second level nodes. These bindings can be found in: +Documentation/devicetree/bindings/regulator/regulator.txt. + +Examples: + +rpm-regulator-smpb1 { + qcom,resource-name = "smpb"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + compatible = "qcom,rpm-smd-regulator-resource"; + status = "disabled"; + + pm8841_s1: regulator-s1 { + regulator-name = "8841_s1"; + qcom,set = <3>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1150000>; + qcom,init-voltage = <1150000>; + compatible = "qcom,rpm-smd-regulator"; + }; + pm8841_s1_ao: regulator-s1-ao { + regulator-name = "8841_s1_ao"; + qcom,set = <1>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1150000>; + compatible = "qcom,rpm-smd-regulator"; + }; + pm8841_s1_corner: regulator-s1-corner { + regulator-name = "8841_s1_corner"; + qcom,set = <3>; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <6>; + qcom,init-voltage-corner = <3>; + qcom,use-voltage-corner; + compatible = "qcom,rpm-smd-regulator"; + }; +}; + +rpm-regulator-ldoa2 { + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,hpm-min-load = <10000>; + compatible = "qcom,rpm-smd-regulator-resource"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8941_l2"; + qcom,set = <3>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + }; + regulator-l2-pin-ctrl { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "8941_l2_pin_ctrl"; + qcom,set = <3>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + qcom,init-voltage = <1225000>; + qcom,enable-with-pin-ctrl = <0 1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/rpmh-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/rpmh-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..db7d7d4997e70d3093ed80e4585a4720b8074ca3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/rpmh-regulator.txt @@ -0,0 +1,285 @@ +Qualcomm Technologies, Inc. RPMh Regulators + +rpmh-regulator devices support PMIC regulator management via the VRM, ARC and +XOB RPMh accelerators. The APPS processor communicates with these hardware +blocks via an RSC using command packets. The VRM allows changing four +parameters for a given regulator: enable state, output voltage, operating mode, +and minimum headroom voltage. The ARC allows changing only a single parameter +for a given regulator: its operating level. This operating level is fed into +CPR which then decides upon a final explicit voltage for the regulator. The XOB +allows changing only a single parameter for a given regulator: its enable state. + +======================= +Required Node Structure +======================= + +RPMh regulators must be described in two levels of device nodes. The first +level describes the interface with RPMh (resource) and must reside within an +RPMh device node. The second level describes properties of one regulator +framework interface (of potentially many) for the regulator resource. + +================================== +First Level Nodes - RPMh Interface +================================== + +- compatible + Usage: required + Value type: + Definition: Must be "qcom,rpmh-vrm-regulator", "qcom,rpmh-arc-regulator" + or "qcom,rpmh-xob-regulator" depending upon the hardware + type, VRM, ARC or XOB, of the RPMh managed regulator + resource. + +- qcom,resource-name + Usage: required + Value type: + Definition: RPMh resource name which encodes the the specific instance + of a given type of regulator (LDO, SMPS, VS, etc) within + a particular PMIC found in the system. This name must match + to one that is defined by the bootloader. + +- qcom,regulator-type + Usage: required if qcom,supported-modes is specified or if + qcom,init-mode is specified in any subnodes + Value type: + Definition: The physical type of the regulator including the PMIC + family. This is used for mode control. Supported values: + "pmic4-ldo", "pmic4-hfsmps", "pmic4-ftsmps", "pmic4-bob", + "pmic5-ldo", "pmic5-hfsmps", "pmic5-ftsmps", and + "pmic5-bob". + +- qcom,always-wait-for-ack + Usage: optional + Value type: + Definition: Boolean flag which indicates that the application processor + must wait for an ACK or a NACK from RPMh for every request + sent for this regulator including those which are for a + strictly lower power state. + +- -parent-supply + Usage: optional + Value type: + Definition: phandle of the parent supply regulator of one of the + regulators for this RPMh resource. The property name is + defined by the value specified for the regulator-name + property. + +- qcom,supported-modes + Usage: optional; VRM regulators only + Value type: + Definition: A list of integers specifying the PMIC regulator modes + supported by this regulator. Supported values are + RPMH_REGULATOR_MODE_* (i.e. 0 to 4). Elements must be + specified in order from lowest to highest. + +- qcom,mode-threshold-currents + Usage: required if qcom,supported-modes is specified + Value type: + Definition: A list of integers specifying minimum allowed current in + microamps for each of the modes listed in + qcom,supported-modes. The first element should always be 0. + Elements must be specified in order from lowest to highest. + +- qcom,send-defaults + Usage: optional + Value type: + Definition: Boolean flag which indicates that the initial parameter + values should be sent to RPMh before consumers make their + own requests. If this flag is not specified, then initial + parameters values will only be sent after some consumer + makes a request. + +========================================= +Second Level Nodes - Regulator Interfaces +========================================= + +- regulator-name + Usage: required + Value type: + Definition: Specifies the name for this RPMh regulator. + +- regulator-min-microvolt + Usage: required + Value type: + Definition: For VRM resources, this is the minimum supported voltage in + microvolts. For ARC resources, this is the minimum + supported voltage level from RPMH_REGULATOR_LEVEL_*. + +- regulator-max-microvolt + Usage: required + Value type: + Definition: For VRM resources, this is the maximum supported voltage in + microvolts. For ARC resources, this is the maximum + supported voltage level from RPMH_REGULATOR_LEVEL_*. + + - regulator-enable-ramp-delay + Usage: optional + Value type: + Definition: For VRM and XOB resources, the time in microseconds to delay + after enabling a regulator. + +- qcom,set + Usage: required + Value type: + Definition: Specifies which sets that requests made with this regulator + interface should be sent to. Regulator requests sent in the + active set take effect immediately. Requests sent in the + sleep set take effect when the Apps processor transitions + into RPMh assisted power collapse. Supported values are + one of RPMH_REGULATOR_SET_* (i.e. 1, 2, or 3). + +- qcom,init-enable + Usage: optional; VRM and XOB regulators only + Value type: + Definition: Specifies the initial enable state to request for a VRM + regulator. Supported values are 0 (regulator disabled) and + 1 (regulator enabled). + +- qcom,init-voltage + Usage: optional; VRM regulators only + Value type: + Definition: Specifies the initial voltage in microvolts to request for a + VRM regulator. Supported values are 0 to 8191000. + +- qcom,init-mode + Usage: optional; VRM regulators only + Value type: + Definition: Specifies the initial mode to request for a VRM regulator. + Supported values are RPMH_REGULATOR_MODE_* (i.e. 0 to 4). + +- qcom,init-headroom-voltage + Usage: optional; VRM regulators only + Value type: + Definition: Specifies the initial headroom voltage in microvolts to + request for a VRM regulator. RPMh ensures that the parent + of this regulator outputs a voltage high enough to satisfy + the requested headroom. Supported values are 0 to 511000. + +- qcom,init-voltage-level + Usage: optional; ARC regulators only + Value type: + Definition: Specifies the initial voltage level to request for an ARC + regulator. Supported values are RPMH_REGULATOR_LEVEL_* + (i.e. 1 to ~513). + +- qcom,min-dropout-voltage + Usage: optional; VRM regulators only + Value type: + Definition: Specifies the minimum voltage in microvolts that the parent + supply regulator must output above the output of this + regulator. It is only meaningful if the property + -parent-supply has been specified in the + first level node. + +- qcom,min-dropout-voltage-level + Usage: optional; ARC regulators only + Value type: + Definition: Specifies the minimum voltage level difference that the + parent supply regulator must output above the output of this + regulator. It is only meaningful if the property + -parent-supply has been specified in the + first level node. + +======== +Examples +======== + +#include + +&apps_rsc { + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "cx.lvl"; + qcom,send-defaults; + pm8998_s9_level: regulator-s9-level { + regulator-name = "pm8998_s9_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = ; + }; + + pm8998_s9_level_ao: regulator-s9-level-ao { + regulator-name = "pm8998_s9_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-smpa2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa2"; + qcom,regulator-type = "pmic4-smps"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 2000000>; + pm8998_s2: regulator-s2 { + regulator-name = "pm8998_s2"; + qcom,set = ; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <200>; + qcom,init-mode = ; + qcom,init-voltage = <1150000>; + }; + }; + + rpmh-regulator-ldoa4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa4"; + qcom,regulator-type = "pmic4-ldo"; + pm8998_l4-parent-supply = <&pm8998_s2>; + pm8998_l4: regulator-l4 { + regulator-name = "pm8998_l4"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <1000000>; + }; + }; + + rpmh-regulator-ldoc1 { + compatible = "qcom,rpmh-xob-regulator"; + qcom,resource-name = "ldoc1"; + pm8150l_l1: regulator-pm8150l-l1 { + regulator-name = "pm8150l_l1"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; +}; + +&disp_rsc { + rpmh-regulator-ldoa3-disp { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + qcom,always-wait-for-ack; + pm8998_l3_disp_ao: regulator-l3-ao { + regulator-name = "pm8998_l3_disp_ao"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1000000>; + qcom,init-headroom-voltage = <60000>; + }; + pm8998_l3_disp_so: regulator-l3-so { + regulator-name = "pm8998_l3_disp_so"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + qcom,init-mode = ; + qcom,init-voltage = <1000000>; + qcom,init-enable = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s2mpa01.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s2mpa01.txt new file mode 100644 index 0000000000000000000000000000000000000000..bae3c7f838cf710d890480c9b139d096fa98524c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s2mpa01.txt @@ -0,0 +1,79 @@ +Binding for Samsung S2MPA01 regulator block +=========================================== + +This is a part of device tree bindings for S2M family multi-function devices. +More information can be found in bindings/mfd/sec-core.txt file. + +The S2MPA01 device provide buck and LDO regulators. + +To register these with regulator framework instantiate under main device node +a sub-node named "regulators" with more sub-nodes for each regulator using the +common regulator binding documented in: + - Documentation/devicetree/bindings/regulator/regulator.txt + + +Names of regulators supported by S2MPA01 device: + - LDOn + - valid values for n are 1 to 26 + - Example: LDO1, LD02, LDO26 + - BUCKn + - valid values for n are 1 to 10. + - Example: BUCK1, BUCK2, BUCK9 +Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number +as per the datasheet of device. + + +Optional properties of buck regulator nodes under "regulators" sub-node: + - regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500 + (default), 25000, or 50000. May be 0 for disabling the ramp delay on + BUCK{1,2,3,4}. + + In the absence of the regulator-ramp-delay property, the default ramp + delay will be used. + + Note: Some bucks share the ramp rate setting i.e. same ramp value + will be set for a particular group of bucks so provide the same + regulator-ramp-delay value for them. + Groups sharing ramp rate: + - buck{1,6}, + - buck{2,4}, + - buck{8,9,10}. + +Example: + + s2mpa01_pmic@66 { + compatible = "samsung,s2mpa01-pmic"; + reg = <0x66>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ALIVE"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDDQ_MMC2"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <50000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s2mps11.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s2mps11.txt new file mode 100644 index 0000000000000000000000000000000000000000..27a48bf1b185b1c5e4757d21c52daf94841e2bf4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s2mps11.txt @@ -0,0 +1,102 @@ +Binding for Samsung S2M family regulator block +============================================== + +This is a part of device tree bindings for S2M family multi-function devices. +More information can be found in bindings/mfd/sec-core.txt file. + +The S2MPS11/13/14/15 and S2MPU02 devices provide buck and LDO regulators. + +To register these with regulator framework instantiate under main device node +a sub-node named "regulators" with more sub-nodes for each regulator using the +common regulator binding documented in: + - Documentation/devicetree/bindings/regulator/regulator.txt + + +Names of regulators supported by different devices: + - LDOn + - valid values for n are: + - S2MPS11: 1 to 38 + - S2MPS13: 1 to 40 + - S2MPS14: 1 to 25 + - S2MPS15: 1 to 27 + - S2MPU02: 1 to 28 + - Example: LDO1, LDO2, LDO28 + - BUCKn + - valid values for n are: + - S2MPS11: 1 to 10 + - S2MPS13: 1 to 10 + - S2MPS14: 1 to 5 + - S2MPS15: 1 to 10 + - S2MPU02: 1 to 7 + - Example: BUCK1, BUCK2, BUCK9 +Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number +as per the datasheet of device. + + +Optional properties of the nodes under "regulators" sub-node: + - regulator-ramp-delay: ramp delay in uV/us. May be 6250, 12500, + 25000 (default) or 50000. + + Additionally S2MPS11 supports disabling ramp delay for BUCK{2,3,4,6} + by setting it to <0>. + + Note: On S2MPS11 some bucks share the ramp rate setting i.e. same ramp value + will be set for a particular group of bucks so provide the same + regulator-ramp-delay value for them. + Groups sharing ramp rate: + - buck{1,6}, + - buck{3,4}, + - buck{7,8,10}. + + - samsung,ext-control-gpios: On S2MPS14 the LDO10, LDO11 and LDO12 can be + configured to external control over GPIO. To turn this feature on this + property must be added to the regulator sub-node: + - samsung,ext-control-gpios: GPIO specifier for one GPIO + controlling this regulator (enable/disable) + Example: + LDO12 { + regulator-name = "V_EMMC_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + samsung,ext-control-gpios = <&gpk0 2 0>; + }; + + +Example: + + s2mps11_pmic@66 { + compatible = "samsung,s2mps11-pmic"; + reg = <0x66>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ABB_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo2_reg: LDO2 { + regulator-name = "VDD_ALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + buck2_reg: BUCK2 { + regulator-name = "vdd_arm"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + regulator-ramp-delay = <50000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s5m8767.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s5m8767.txt new file mode 100644 index 0000000000000000000000000000000000000000..093edda0c8dfcaa4a3b1d7fbb731ba7e84577117 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/samsung,s5m8767.txt @@ -0,0 +1,145 @@ +Binding for Samsung S5M8767 regulator block +=========================================== + +This is a part of device tree bindings for S5M family multi-function devices. +More information can be found in bindings/mfd/sec-core.txt file. + +The S5M8767 device provide buck and LDO regulators. + +To register these with regulator framework instantiate under main device node +a sub-node named "regulators" with more sub-nodes for each regulator using the +common regulator binding documented in: + - Documentation/devicetree/bindings/regulator/regulator.txt + + +Required properties of the main device node (the parent!): + - s5m8767,pmic-buck2-dvs-voltage: A set of 8 voltage values in micro-volt (uV) + units for buck2 when changing voltage using gpio dvs. Refer to [1] below + for additional information. + + - s5m8767,pmic-buck3-dvs-voltage: A set of 8 voltage values in micro-volt (uV) + units for buck3 when changing voltage using gpio dvs. Refer to [1] below + for additional information. + + - s5m8767,pmic-buck4-dvs-voltage: A set of 8 voltage values in micro-volt (uV) + units for buck4 when changing voltage using gpio dvs. Refer to [1] below + for additional information. + + - s5m8767,pmic-buck-ds-gpios: GPIO specifiers for three host gpio's used + for selecting GPIO DVS lines. It is one-to-one mapped to dvs gpio lines. + + [1] If none of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional + property is specified, the 's5m8767,pmic-buck[2/3/4]-dvs-voltage' + property should specify atleast one voltage level (which would be a + safe operating voltage). + + If either of the 's5m8767,pmic-buck[2/3/4]-uses-gpio-dvs' optional + property is specified, then all the eight voltage values for the + 's5m8767,pmic-buck[2/3/4]-dvs-voltage' should be specified. + +Optional properties of the main device node (the parent!): + - s5m8767,pmic-buck2-uses-gpio-dvs: 'buck2' can be controlled by gpio dvs. + - s5m8767,pmic-buck3-uses-gpio-dvs: 'buck3' can be controlled by gpio dvs. + - s5m8767,pmic-buck4-uses-gpio-dvs: 'buck4' can be controlled by gpio dvs. + +Additional properties required if either of the optional properties are used: + + - s5m8767,pmic-buck234-default-dvs-idx: Default voltage setting selected from + the possible 8 options selectable by the dvs gpios. The value of this + property should be between 0 and 7. If not specified or if out of range, the + default value of this property is set to 0. + + - s5m8767,pmic-buck-dvs-gpios: GPIO specifiers for three host gpio's used + for dvs. The format of the gpio specifier depends in the gpio controller. + + +Names of regulators supported by S5M8767 device: + - LDOn + - valid values for n are 1 to 28 + - Example: LDO1, LDO2, LDO28 + - BUCKn + - valid values for n are 1 to 9. + - Example: BUCK1, BUCK2, BUCK9 +Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number +as per the datasheet of device. + + +Optional properties of the nodes under "regulators" sub-node: + - op_mode: describes the different operating modes of the LDO's with + power mode change in SOC. The different possible values are, + 0 - always off mode + 1 - on in normal mode + 2 - low power mode + 3 - suspend mode + - s5m8767,pmic-ext-control-gpios: (optional) GPIO specifier for one + GPIO controlling this regulator + (enable/disable); This is valid only + for buck9. + +Example: + + s5m8767_pmic@66 { + compatible = "samsung,s5m8767-pmic"; + reg = <0x66>; + + s5m8767,pmic-buck2-uses-gpio-dvs; + s5m8767,pmic-buck3-uses-gpio-dvs; + s5m8767,pmic-buck4-uses-gpio-dvs; + + s5m8767,pmic-buck-default-dvs-idx = <0>; + + s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 0>, /* DVS1 */ + <&gpx0 1 0>, /* DVS2 */ + <&gpx0 2 0>; /* DVS3 */ + + s5m8767,pmic-buck-ds-gpios = <&gpx2 3 0>, /* SET1 */ + <&gpx2 4 0>, /* SET2 */ + <&gpx2 5 0>; /* SET3 */ + + s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>, + <1250000>, <1200000>, + <1150000>, <1100000>, + <1000000>, <950000>; + + s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>, + <1100000>, <1100000>, + <1000000>, <1000000>, + <1000000>, <1000000>; + + s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>, + <1200000>, <1200000>; + + regulators { + ldo1_reg: LDO1 { + regulator-name = "VDD_ABB_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + op_mode = <1>; /* Normal Mode */ + }; + + ldo2_reg: LDO2 { + regulator-name = "VDD_ALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "VDD_MIF_1.2V"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-boot-on; + }; + + vemmc_reg: BUCK9 { + regulator-name = "VMEM_VDD_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + op_mode = <3>; /* Standby Mode */ + s5m8767,pmic-ext-control-gpios = <&gpk0 2 0>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/sky81452-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/sky81452-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9acbc1f3c6bdf0cebf3d21810f4ca5b284fab2b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/sky81452-regulator.txt @@ -0,0 +1,18 @@ +SKY81452 voltage regulator + +Required properties: +- regulator node named lout. +- any required generic properties defined in regulator.txt + +Optional properties: +- any available generic properties defined in regulator.txt + +Example: + + regulator { + lout { + regulator-name = "sky81452-lout"; + regulator-min-microvolt = <4500000>; + regulator-max-microvolt = <8000000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/sprd,sc2731-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/sprd,sc2731-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..63dc07877cd6412e2d3bed7925a9b69f63e034ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/sprd,sc2731-regulator.txt @@ -0,0 +1,43 @@ +Spreadtrum SC2731 Voltage regulators + +The SC2731 integrates low-voltage and low quiescent current DCDC/LDO. +14 LDO and 3 DCDCs are designed for external use. All DCDCs/LDOs have +their own bypass (power-down) control signals. External tantalum or MLCC +ceramic capacitors are recommended to use with these LDOs. + +Required properties: + - compatible: should be "sprd,sc27xx-regulator". + +List of regulators provided by this controller. It is named according to +its regulator type, BUCK_ and LDO_. The definition for each +of these nodes is defined using the standard binding for regulators at +Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are: +BUCK: + BUCK_CPU0, BUCK_CPU1, BUCK_RF +LDO: + LDO_CAMA0, LDO_CAMA1, LDO_CAMMOT, LDO_VLDO, LDO_EMMCCORE, LDO_SDCORE, + LDO_SDIO, LDO_WIFIPA, LDO_USB33, LDO_CAMD0, LDO_CAMD1, LDO_CON, + LDO_CAMIO, LDO_SRAM + +Example: + regulators { + compatible = "sprd,sc27xx-regulator"; + + vddarm0: BUCK_CPU0 { + regulator-name = "vddarm0"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1996875>; + regulator-ramp-delay = <25000>; + regulator-always-on; + }; + + vddcama0: LDO_CAMA0 { + regulator-name = "vddcama0"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3750000>; + regulator-enable-ramp-delay = <100>; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/st,stm32-vrefbuf.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/st,stm32-vrefbuf.txt new file mode 100644 index 0000000000000000000000000000000000000000..5ddb8500a9295b9a7cc00a64ae50dc2f99553b85 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/st,stm32-vrefbuf.txt @@ -0,0 +1,20 @@ +STM32 VREFBUF - Voltage reference buffer + +Some STM32 devices embed a voltage reference buffer which can be used as +voltage reference for ADCs, DACs and also as voltage reference for external +components through the dedicated VREF+ pin. + +Required properties: +- compatible: Must be "st,stm32-vrefbuf". +- reg: Offset and length of VREFBUF register set. +- clocks: Must contain an entry for peripheral clock. + +Example: + vrefbuf: regulator@58003c00 { + compatible = "st,stm32-vrefbuf"; + reg = <0x58003C00 0x8>; + clocks = <&rcc VREF_CK>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2500000>; + vdda-supply = <&vdda>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/stub-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/stub-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..1057e175c9986baf85d59e27006cbcbffe6eeb37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/stub-regulator.txt @@ -0,0 +1,48 @@ +Stub Voltage Regulators + +stub-regulators are place-holder regulator devices which do not impact any +hardware state. They provide a means for consumer devices to utilize all +regulator features for testing purposes. + +Required properties: +- compatible: Must be "qcom,stub-regulator". +- regulator-name: A string used as a descriptive name for regulator outputs. + +Optional properties: +- parent-supply: phandle to the parent supply/regulator node if one exists. +- qcom,hpm-min-load: Load current in uA which corresponds to the minimum load + which requires the regulator to be in high power mode. +- qcom,system-load: Load in uA present on regulator that is not captured by any + consumer request. + +All properties specified within the core regulator framework can also be used. +These bindings can be found in regulator.txt. + +Example: + +/ { + pm8026_s3: regulator-s3 { + compatible = "qcom,stub-regulator"; + regulator-name = "8026_s3"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + }; + + pm8026_l1: regulator-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "8026_l1"; + parent-supply = <&pm8026_s3>; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8026_l20: regulator-l20 { + compatible = "qcom,stub-regulator"; + regulator-name = "8026_l20"; + qcom,hpm-min-load = <5000>; + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/sy8106a-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/sy8106a-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..39a8ca73f5721b8943c6711f863e81a69463ced3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/sy8106a-regulator.txt @@ -0,0 +1,23 @@ +SY8106A Voltage regulator + +Required properties: +- compatible: Must be "silergy,sy8106a" +- reg: I2C slave address - must be <0x65> +- silergy,fixed-microvolt - the voltage when I2C regulating is disabled (set + by external resistor like a fixed voltage) + +Any property defined as part of the core regulator binding, defined in +./regulator.txt, can also be used. + +Example: + + sy8106a { + compatible = "silergy,sy8106a"; + reg = <0x65>; + regulator-name = "sy8106a-vdd"; + silergy,fixed-microvolt = <1200000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/ti-abb-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/ti-abb-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a23ad9ac53a4cabc85a6bc592a873f38c7c144b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/ti-abb-regulator.txt @@ -0,0 +1,132 @@ +Adaptive Body Bias(ABB) SoC internal LDO regulator for Texas Instruments SoCs + +Required Properties: +- compatible: Should be one of: + - "ti,abb-v1" for older SoCs like OMAP3 + - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5 + - "ti,abb-v3" for a generic definition where setup and control registers are + provided (example: DRA7) +- reg: Address and length of the register set for the device. It contains + the information of registers in the same order as described by reg-names +- reg-names: Should contain the reg names + - "base-address" - contains base address of ABB module (ti,abb-v1,ti,abb-v2) + - "control-address" - contains control register address of ABB module (ti,abb-v3) + - "setup-address" - contains setup register address of ABB module (ti,abb-v3) + - "int-address" - contains address of interrupt register for ABB module + (also see Optional properties) +- #address-cells: should be 0 +- #size-cells: should be 0 +- clocks: should point to the clock node used by ABB module +- ti,settling-time: Settling time in uSecs from SoC documentation for ABB module + to settle down(target time for SR2_WTCNT_VALUE). +- ti,clock-cycles: SoC specific data about count of system ti,clock-cycles used for + computing settling time from SoC Documentation for ABB module(clock + cycles for SR2_WTCNT_VALUE). +- ti,tranxdone-status-mask: Mask to the int-register to write-to-clear mask + indicating LDO tranxdone (operation complete). +- ti,abb_info: An array of 6-tuples u32 items providing information about ABB + configuration needed per operational voltage of the device. + Each item consists of the following in the same order: + volt: voltage in uV - Only used to index ABB information. + ABB mode: one of the following: + 0-bypass + 1-Forward Body Bias(FBB) + 3-Reverse Body Bias(RBB) + efuse: (see Optional properties) + RBB enable efuse Mask: (See Optional properties) + FBB enable efuse Mask: (See Optional properties) + Vset value efuse Mask: (See Optional properties) + + NOTE: If more than 1 entry is present, then regulator is setup to change + voltage, allowing for various modes to be selected indexed off + the regulator. Further, ABB LDOs are considered always-on by + default. + +Optional Properties: +- reg-names: In addition to the required properties, the following are optional + - "efuse-address" - Contains efuse base address used to pick up ABB info. + - "ldo-address" - Contains address of ABB LDO override register. + "efuse-address" is required for this. +- ti,ldovbb-vset-mask - Required if ldo-address is set, mask for LDO override + register to provide override vset value. +- ti,ldovbb-override-mask - Required if ldo-address is set, mask for LDO + override register to enable override vset value. +- ti,abb_opp_sel: Addendum to the description in required properties + efuse: Mandatory if 'efuse-address' register is defined. Provides offset + from efuse-address to pick up ABB characteristics. Set to 0 if + 'efuse-address' is not defined. + RBB enable efuse Mask: Optional if 'efuse-address' register is defined. + 'ABB mode' is force set to RBB mode if value at "efuse-address" + + efuse maps to RBB mask. Set to 0 to ignore this. + FBB enable efuse Mask: Optional if 'efuse-address' register is defined. + 'ABB mode' is force set to FBB mode if value at "efuse-address" + + efuse maps to FBB mask (valid only if RBB mask does not match) + Set to 0 to ignore this. + Vset value efuse Mask: Mandatory if ldo-address is set. Picks up from + efuse the value to set in 'ti,ldovbb-vset-mask' at ldo-address. + +Example #1: Simplest configuration (no efuse data, hard coded ABB table): +abb_x: regulator-abb-x { + compatible = "ti,abb-v1"; + regulator-name = "abb_x"; + #address-cells = <0>; + #size-cells = <0>; + reg = <0x483072f0 0x8>, <0x48306818 0x4>; + reg-names = "base-address", "int-address"; + ti,tranxdone-status-mask = <0x4000000>; + clocks = <&sysclk>; + ti,settling-time = <30>; + ti,clock-cycles = <8>; + ti,abb_info = < + /* uV ABB efuse rbb_m fbb_m vset_m */ + 1012500 0 0 0 0 0 /* Bypass */ + 1200000 3 0 0 0 0 /* RBB mandatory */ + 1320000 1 0 0 0 0 /* FBB mandatory */ + >; +}; + +Example #2: Efuse bits contain ABB mode setting (no LDO override capability) +abb_y: regulator-abb-y { + compatible = "ti,abb-v2"; + regulator-name = "abb_y"; + #address-cells = <0>; + #size-cells = <0>; + reg = <0x4a307bd0 0x8>, <0x4a306014 0x4>, <0x4A002268 0x8>; + reg-names = "base-address", "int-address", "efuse-address"; + ti,tranxdone-status-mask = <0x4000000>; + clocks = <&sysclk>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + ti,abb_info = < + /* uV ABB efuse rbb_m fbb_m vset_m */ + 975000 0 0 0 0 0 /* Bypass */ + 1012500 0 0 0x40000 0 0 /* RBB optional */ + 1200000 0 0x4 0 0x40000 0 /* FBB optional */ + 1320000 1 0 0 0 0 /* FBB mandatory */ + >; +}; + +Example #3: Efuse bits contain ABB mode setting and LDO override capability +abb_z: regulator-abb-z { + compatible = "ti,abb-v2"; + regulator-name = "abb_z"; + #address-cells = <0>; + #size-cells = <0>; + reg = <0x4ae07ce4 0x8>, <0x4ae06010 0x4>, + <0x4a002194 0x8>, <0x4ae0C314 0x4>; + reg-names = "base-address", "int-address", + "efuse-address", "ldo-address"; + ti,tranxdone-status-mask = <0x8000000>; + /* LDOVBBMM_MUX_CTRL */ + ti,ldovbb-override-mask = <0x400>; + /* LDOVBBMM_VSET_OUT */ + ti,ldovbb-vset-mask = <0x1F>; + clocks = <&sysclk>; + ti,settling-time = <50>; + ti,clock-cycles = <16>; + ti,abb_info = < + /* uV ABB efuse rbb_m fbb_m vset_m */ + 975000 0 0 0 0 0 /* Bypass */ + 1200000 0 0x4 0 0x40000 0x1f00 /* FBB optional, vset */ + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps51632-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps51632-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f7e44a96414a35890396481c6d4f08b26552568 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps51632-regulator.txt @@ -0,0 +1,27 @@ +TPS51632 Voltage regulators + +Required properties: +- compatible: Must be "ti,tps51632" +- reg: I2C slave address + +Optional properties: +- ti,enable-pwm-dvfs: Enable the DVFS voltage control through the PWM interface. +- ti,dvfs-step-20mV: The 20mV step voltage when PWM DVFS enabled. Missing this + will set 10mV step voltage in PWM DVFS mode. In normal mode, the voltage + step is 10mV as per datasheet. + +Any property defined as part of the core regulator binding, defined in +regulator.txt, can also be used. + +Example: + + tps51632 { + compatible = "ti,tps51632"; + reg = <0x43>; + regulator-name = "tps51632-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + ti,enable-pwm-dvfs; + ti,dvfs-step-20mV; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps62360-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps62360-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b20c3dbcdb89485afc1ff9f1c116d7c72127b7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps62360-regulator.txt @@ -0,0 +1,44 @@ +TPS62360 Voltage regulators + +Required properties: +- compatible: Must be one of the following. + "ti,tps62360" + "ti,tps62361", + "ti,tps62362", + "ti,tps62363", +- reg: I2C slave address + +Optional properties: +- ti,enable-vout-discharge: Enable output discharge. This is boolean value. +- ti,enable-pull-down: Enable pull down. This is boolean value. +- ti,vsel0-gpio: GPIO for controlling VSEL0 line. + If this property is missing, then assume that there is no GPIO + for vsel0 control. +- ti,vsel1-gpio: Gpio for controlling VSEL1 line. + If this property is missing, then assume that there is no GPIO + for vsel1 control. +- ti,vsel0-state-high: Initial state of vsel0 input is high. + If this property is missing, then assume the state as low (0). +- ti,vsel1-state-high: Initial state of vsel1 input is high. + If this property is missing, then assume the state as low (0). + +Any property defined as part of the core regulator binding, defined in +regulator.txt, can also be used. + +Example: + + abc: tps62360 { + compatible = "ti,tps62361"; + reg = <0x60>; + regulator-name = "tps62361-vout"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on + ti,vsel0-gpio = <&gpio1 16 0>; + ti,vsel1-gpio = <&gpio1 17 0>; + ti,vsel0-state-high; + ti,vsel1-state-high; + ti,enable-pull-down; + ti,enable-force-pwm; + ti,enable-vout-discharge; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps65023.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65023.txt new file mode 100644 index 0000000000000000000000000000000000000000..a4714e4da370bc9ff69053707d0888362718c83b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65023.txt @@ -0,0 +1,60 @@ +TPS65023 family of regulators + +Required properties: +- compatible: Must be one of the following. + "ti,tps65020", + "ti,tps65021", + "ti,tps65023", +- reg: I2C slave address +- regulators: list of regulators provided by this controller, must be named + after their hardware counterparts: VDCDC[1-3] and LDO[1-2] +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. The definition for each of + these nodes is defined using the standard binding for regulators found at + Documentation/devicetree/bindings/regulator/regulator.txt. + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps65023@48 { + compatible = "ti,tps65023"; + reg = <0x48>; + + regulators { + VDCDC1 { + regulator-name = "vdd_mpu"; + regulator-always-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + VDCDC2 { + regulator-name = "vdd_core"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + VDCDC3 { + regulator-name = "vdd_io"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO1 { + regulator-name = "vdd_usb18"; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + LDO2 { + regulator-name = "vdd_usb33"; + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps65090.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65090.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae326f26359740bce4fe7ac119288447649b6429 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65090.txt @@ -0,0 +1,126 @@ +TPS65090 regulators + +Required properties: +- compatible: "ti,tps65090" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values listed below. The content of each sub-node is defined by the + standard binding for regulators; see regulator.txt. + dcdc[1-3], fet[1-7] and ldo[1-2] respectively. +- vsys[1-3]-supply: The input supply for DCDC[1-3] respectively. +- infet[1-7]-supply: The input supply for FET[1-7] respectively. +- vsys-l[1-2]-supply: The input supply for LDO[1-2] respectively. + +Optional properties: +- ti,enable-ext-control: This is applicable for DCDC1, DCDC2 and DCDC3. + If DCDCs are externally controlled then this property should be there. +- dcdc-ext-control-gpios: This is applicable for DCDC1, DCDC2 and DCDC3. + If DCDCs are externally controlled and if it is from GPIO then GPIO + number should be provided. If it is externally controlled and no GPIO + entry then driver will just configure this rails as external control + and will not provide any enable/disable APIs. +- ti,overcurrent-wait: This is applicable to FET registers, which have a + poorly defined "overcurrent wait" field. If this property is present it + should be between 0 - 3. If this property isn't present we won't touch the + "overcurrent wait" field and we'll leave it to the BIOS/EC to deal with. + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps65090@48 { + compatible = "ti,tps65090"; + reg = <0x48>; + interrupts = <0 88 0x4>; + + vsys1-supply = <&some_reg>; + vsys2-supply = <&some_reg>; + vsys3-supply = <&some_reg>; + infet1-supply = <&some_reg>; + infet2-supply = <&some_reg>; + infet3-supply = <&some_reg>; + infet4-supply = <&some_reg>; + infet5-supply = <&some_reg>; + infet6-supply = <&some_reg>; + infet7-supply = <&some_reg>; + vsys-l1-supply = <&some_reg>; + vsys-l2-supply = <&some_reg>; + + regulators { + dcdc1 { + regulator-name = "dcdc1"; + regulator-boot-on; + regulator-always-on; + ti,enable-ext-control; + dcdc-ext-control-gpios = <&gpio 10 0>; + }; + + dcdc2 { + regulator-name = "dcdc2"; + regulator-boot-on; + regulator-always-on; + }; + + dcdc3 { + regulator-name = "dcdc3"; + regulator-boot-on; + regulator-always-on; + }; + + fet1 { + regulator-name = "fet1"; + regulator-boot-on; + regulator-always-on; + }; + + fet2 { + regulator-name = "fet2"; + regulator-boot-on; + regulator-always-on; + }; + + fet3 { + regulator-name = "fet3"; + regulator-boot-on; + regulator-always-on; + }; + + fet4 { + regulator-name = "fet4"; + regulator-boot-on; + regulator-always-on; + }; + + fet5 { + regulator-name = "fet5"; + regulator-boot-on; + regulator-always-on; + }; + + fet6 { + regulator-name = "fet6"; + regulator-boot-on; + regulator-always-on; + }; + + fet7 { + regulator-name = "fet7"; + regulator-boot-on; + regulator-always-on; + }; + + ldo1 { + regulator-name = "ldo1"; + regulator-boot-on; + regulator-always-on; + }; + + ldo2 { + regulator-name = "ldo2"; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps65132-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65132-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a3505520c692b5fd9e3f5ff1f6a88d732954b43 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65132-regulator.txt @@ -0,0 +1,46 @@ +TPS65132 regulators + +Required properties: +- compatible: "ti,tps65132" +- reg: I2C slave address + +Optional Subnode: +Device supports two regulators OUTP and OUTN. A sub node within the + device node describe the properties of these regulators. The sub-node + names must be as follows: + -For regulator outp, the sub node name should be "outp". + -For regulator outn, the sub node name should be "outn". + +-enable-gpios:(active high, output) Regulators are controlled by the input pins. + If it is connected to GPIO through host system then provide the + gpio number as per gpio.txt. +-active-discharge-gpios: (active high, output) Some configurations use delay mechanisms + on the enable pin, to keep the regulator enabled for some time after + the enable signal goes low. This GPIO is used to actively discharge + the delay mechanism. Requires specification of ti,active-discharge-time-us +-ti,active-discharge-time-us: how long the active discharge gpio should be + asserted for during active discharge, in microseconds. + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps65132@3e { + compatible = "ti,tps65132"; + reg = <0x3e>; + + outp { + regulator-name = "outp"; + regulator-boot-on; + regulator-always-on; + enable-gpios = <&gpio 23 0>; + }; + + outn { + regulator-name = "outn"; + regulator-boot-on; + regulator-always-on; + regulator-active-discharge = <0>; + enable-gpios = <&gpio 40 0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps65217.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65217.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f05d208c95cfeac7ebbc217003d34f08e0f4772 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65217.txt @@ -0,0 +1,78 @@ +TPS65217 family of regulators + +Required properties: +- compatible: "ti,tps65217" +- reg: I2C slave address +- regulators: list of regulators provided by this controller, must be named + after their hardware counterparts: dcdc[1-3] and ldo[1-4] +- regulators: This is the list of child nodes that specify the regulator + initialization data for defined regulators. Not all regulators for the given + device need to be present. The definition for each of these nodes is defined + using the standard binding for regulators found at + Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: +- ti,pmic-shutdown-controller: Telling the PMIC to shutdown on PWR_EN toggle. + + The valid names for regulators are: + tps65217: dcdc1, dcdc2, dcdc3, ldo1, ldo2, ldo3 and ldo4 + +Each regulator is defined using the standard binding for regulators. + +Example: + + tps: tps@24 { + compatible = "ti,tps65217"; + ti,pmic-shutdown-controller; + + regulators { + dcdc1_reg: dcdc1 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc2_reg: dcdc2 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc3_reg: dcc3 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1_reg: ldo1 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps65218.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65218.txt new file mode 100644 index 0000000000000000000000000000000000000000..02f0e9bbfbf8a43a447ddb67d96924789dcd7618 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps65218.txt @@ -0,0 +1,78 @@ +TPS65218 family of regulators + +Required properties: +- compatible: "ti,tps65218" +- reg: I2C slave address + +- List of regulators provided by this controller, must be named + after their hardware counterparts: dcdc[1-6] and ldo1 +- This is the list of child nodes that specify the regulator + initialization data for defined regulators. Not all regulators for the given + device need to be present. The definition for each of these nodes is defined + using the standard binding for regulators found at ./regulator.txt. + + The valid names for regulators are: + tps65217: regulator-dcdc1, regulator-dcdc2, regulator-dcdc3, regulator-dcdc4, + regulator-dcdc5, regulator-dcdc6, regulator-ldo1, regulator-ls3. + Each regulator is defined using the standard binding for regulators. + +Example: +tps65218: tps65218@24 { + reg = <0x24>; + compatible = "ti,tps65218"; + interrupts = ; /* NMIn */ + interrupt-controller; + #interrupt-cells = <2>; + + dcdc1: regulator-dcdc1 { + regulator-name = "vdd_core"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <1144000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc2: regulator-dcdc2 { + regulator-name = "vdd_mpu"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <1378000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc3: regulator-dcdc3 { + regulator-name = "vdcdc3"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc5: regulator-dcdc5 { + regulator-name = "v1_0bat"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + regulator-boot-on; + regulator-always-on; + }; + + dcdc6: regulator-dcdc6 { + regulator-name = "v1_8bat"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo1: regulator-ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ls3: regulator-ls3 { + regulator-min-microvolt = <100000>; + regulator-max-microvolt = <1000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/tps6586x.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/tps6586x.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b40cac24d93959740b828f8614736177028f066 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/tps6586x.txt @@ -0,0 +1,135 @@ +TPS6586x family of regulators + +Required properties: +- compatible: "ti,tps6586x" +- reg: I2C slave address +- interrupts: the interrupt outputs of the controller +- #gpio-cells: number of cells to describe a GPIO +- gpio-controller: mark the device as a GPIO controller +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name (or the deprecated + regulator-compatible property if present), with valid values listed below. + The content of each sub-node is defined by the standard binding for + regulators; see regulator.txt. + sys, sm[0-2], ldo[0-9] and ldo_rtc +- sys-supply: The input supply for SYS. +- vin-sm0-supply: The input supply for the SM0. +- vin-sm1-supply: The input supply for the SM1. +- vin-sm2-supply: The input supply for the SM2. +- vinldo01-supply: The input supply for the LDO1 and LDO2 +- vinldo23-supply: The input supply for the LDO2 and LDO3 +- vinldo4-supply: The input supply for the LDO4 +- vinldo678-supply: The input supply for the LDO6, LDO7 and LDO8 +- vinldo9-supply: The input supply for the LDO9 + +Optional properties: +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. + +Each regulator is defined using the standard binding for regulators. + +Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver + take care of making proper parent child relationship. + +Example: + + pmu: tps6586x@34 { + compatible = "ti,tps6586x"; + reg = <0x34>; + interrupts = <0 88 0x4>; + + #gpio-cells = <2>; + gpio-controller; + + ti,system-power-controller; + + sys-supply = <&some_reg>; + vin-sm0-supply = <&some_reg>; + vin-sm1-supply = <&some_reg>; + vin-sm2-supply = <&some_reg>; + vinldo01-supply = <...>; + vinldo23-supply = <...>; + vinldo4-supply = <...>; + vinldo678-supply = <...>; + vinldo9-supply = <...>; + + regulators { + sys_reg: sys { + regulator-name = "vdd_sys"; + regulator-boot-on; + regulator-always-on; + }; + + sm0_reg: sm0 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm1_reg: sm1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + regulator-boot-on; + regulator-always-on; + }; + + sm2_reg: sm2 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <4550000>; + regulator-boot-on; + regulator-always-on; + }; + + ldo0_reg: ldo0 { + regulator-name = "PCIE CLK"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo1_reg: ldo1 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo2_reg: ldo2 { + regulator-min-microvolt = < 725000>; + regulator-max-microvolt = <1500000>; + }; + + ldo3_reg: ldo3 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo4_reg: ldo4 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2475000>; + }; + + ldo5_reg: ldo5 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo6_reg: ldo6 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7_reg: ldo7 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo8_reg: ldo8 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + + ldo9_reg: ldo9 { + regulator-min-microvolt = <1250000>; + regulator-max-microvolt = <3300000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/twl-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/twl-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..74a91c4f8530a4cd17cb5d184554c6cd283163e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/twl-regulator.txt @@ -0,0 +1,73 @@ +TWL family of regulators + +Required properties: +For twl6030 regulators/LDOs +- compatible: + - "ti,twl6030-vaux1" for VAUX1 LDO + - "ti,twl6030-vaux2" for VAUX2 LDO + - "ti,twl6030-vaux3" for VAUX3 LDO + - "ti,twl6030-vmmc" for VMMC LDO + - "ti,twl6030-vpp" for VPP LDO + - "ti,twl6030-vusim" for VUSIM LDO + - "ti,twl6030-vana" for VANA LDO + - "ti,twl6030-vcxio" for VCXIO LDO + - "ti,twl6030-vdac" for VDAC LDO + - "ti,twl6030-vusb" for VUSB LDO + - "ti,twl6030-v1v8" for V1V8 LDO + - "ti,twl6030-v2v1" for V2V1 LDO + - "ti,twl6030-vdd1" for VDD1 SMPS + - "ti,twl6030-vdd2" for VDD2 SMPS + - "ti,twl6030-vdd3" for VDD3 SMPS +For twl6032 regulators/LDOs +- compatible: + - "ti,twl6032-ldo1" for LDO1 LDO + - "ti,twl6032-ldo2" for LDO2 LDO + - "ti,twl6032-ldo3" for LDO3 LDO + - "ti,twl6032-ldo4" for LDO4 LDO + - "ti,twl6032-ldo5" for LDO5 LDO + - "ti,twl6032-ldo6" for LDO6 LDO + - "ti,twl6032-ldo7" for LDO7 LDO + - "ti,twl6032-ldoln" for LDOLN LDO + - "ti,twl6032-ldousb" for LDOUSB LDO + - "ti,twl6032-smps3" for SMPS3 SMPS + - "ti,twl6032-smps4" for SMPS4 SMPS + - "ti,twl6032-vio" for VIO SMPS +For twl4030 regulators/LDOs +- compatible: + - "ti,twl4030-vaux1" for VAUX1 LDO + - "ti,twl4030-vaux2" for VAUX2 LDO + - "ti,twl5030-vaux2" for VAUX2 LDO + - "ti,twl4030-vaux3" for VAUX3 LDO + - "ti,twl4030-vaux4" for VAUX4 LDO + - "ti,twl4030-vmmc1" for VMMC1 LDO + - "ti,twl4030-vmmc2" for VMMC2 LDO + - "ti,twl4030-vpll1" for VPLL1 LDO + - "ti,twl4030-vpll2" for VPLL2 LDO + - "ti,twl4030-vsim" for VSIM LDO + - "ti,twl4030-vdac" for VDAC LDO + - "ti,twl4030-vintana2" for VINTANA2 LDO + - "ti,twl4030-vio" for VIO LDO + - "ti,twl4030-vdd1" for VDD1 SMPS + - "ti,twl4030-vdd2" for VDD2 SMPS + - "ti,twl4030-vintana1" for VINTANA1 LDO + - "ti,twl4030-vintdig" for VINTDIG LDO + - "ti,twl4030-vusb1v5" for VUSB1V5 LDO + - "ti,twl4030-vusb1v8" for VUSB1V8 LDO + - "ti,twl4030-vusb3v1" for VUSB3V1 LDO + +Optional properties: +- Any optional property defined in bindings/regulator/regulator.txt +For twl4030 regulators/LDOs: + - regulator-initial-mode: + - 0x08 - Sleep mode, the nominal output voltage is maintained with low power + consumption with low load current capability. + - 0x0e - Active mode, the regulator can deliver its nominal output voltage + with full-load current capability. + +Example: + + xyz: regulator@0 { + compatible = "ti,twl6030-vaux1"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <3000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/uniphier-regulator.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/uniphier-regulator.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9919f4b92d2121ef25471c1f22df69f621a911c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/uniphier-regulator.txt @@ -0,0 +1,57 @@ +Socionext UniPhier Regulator Controller + +This describes the devicetree bindings for regulator controller implemented +on Socionext UniPhier SoCs. + +USB3 Controller +--------------- + +This regulator controls VBUS and belongs to USB3 glue layer. Before using +the regulator, it is necessary to control the clocks and resets to enable +this layer. These clocks and resets should be described in each property. + +Required properties: +- compatible: Should be + "socionext,uniphier-pro4-usb3-regulator" - for Pro4 SoC + "socionext,uniphier-pxs2-usb3-regulator" - for PXs2 SoC + "socionext,uniphier-ld20-usb3-regulator" - for LD20 SoC + "socionext,uniphier-pxs3-usb3-regulator" - for PXs3 SoC +- reg: Specifies offset and length of the register set for the device. +- clocks: A list of phandles to the clock gate for USB3 glue layer. + According to the clock-names, appropriate clocks are required. +- clock-names: Should contain + "gio", "link" - for Pro4 SoC + "link" - for others +- resets: A list of phandles to the reset control for USB3 glue layer. + According to the reset-names, appropriate resets are required. +- reset-names: Should contain + "gio", "link" - for Pro4 SoC + "link" - for others + +See Documentation/devicetree/bindings/regulator/regulator.txt +for more details about the regulator properties. + +Example: + + usb-glue@65b00000 { + compatible = "socionext,uniphier-ld20-dwc3-glue", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x65b00000 0x400>; + + usb_vbus0: regulators@100 { + compatible = "socionext,uniphier-ld20-usb3-regulator"; + reg = <0x100 0x10>; + clock-names = "link"; + clocks = <&sys_clk 14>; + reset-names = "link"; + resets = <&sys_rst 14>; + }; + + phy { + ... + phy-supply = <&usb_vbus0>; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/vctrl.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/vctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..601328d7fdbb725647d48e0e10d6b19dc5ca6254 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/vctrl.txt @@ -0,0 +1,49 @@ +Bindings for Voltage controlled regulators +========================================== + +Required properties: +-------------------- +- compatible : must be "vctrl-regulator". +- regulator-min-microvolt : smallest voltage consumers may set +- regulator-max-microvolt : largest voltage consumers may set +- ctrl-supply : The regulator supplying the control voltage. +- ctrl-voltage-range : an array of two integer values describing the range + (min/max) of the control voltage. The values specify + the control voltage needed to generate the corresponding + regulator-min/max-microvolt output voltage. + +Optional properties: +-------------------- +- ovp-threshold-percent : overvoltage protection (OVP) threshold of the + regulator in percent. Some regulators have an OVP + circuitry which shuts down the regulator when the + actual output voltage deviates beyond a certain + margin from the expected value for a given control + voltage. On larger voltage decreases this can occur + undesiredly since the output voltage does not adjust + inmediately to changes in the control voltage. To + avoid this situation the vctrl driver breaks down + larger voltage decreases into multiple steps, where + each step is within the OVP threshold. +- min-slew-down-rate : Describes how slowly the regulator voltage will decay + down in the worst case (lightest expected load). + Specified in uV / us (like main regulator ramp rate). + This value is required when ovp-threshold-percent is + specified. + +Example: + + vctrl-reg { + compatible = "vctrl-regulator"; + regulator-name = "vctrl_reg"; + + ctrl-supply = <&ctrl_reg>; + + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1500000>; + + ctrl-voltage-range = <200000 500000>; + + min-slew-down-rate = <225>; + ovp-threshold-percent = <16>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/regulator/vexpress.txt b/arch/arm64/boot/dts/vendor/bindings/regulator/vexpress.txt new file mode 100644 index 0000000000000000000000000000000000000000..d775f72487aa35758c082f9c38234e4dd36d8a9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/regulator/vexpress.txt @@ -0,0 +1,32 @@ +Versatile Express voltage regulators +------------------------------------ + +Requires node properties: +- "compatible" value: "arm,vexpress-volt" +- "arm,vexpress-sysreg,func" when controlled via vexpress-sysreg + (see Documentation/devicetree/bindings/arm/vexpress-sysreg.txt + for more details) + +Required regulator properties: +- "regulator-name" +- "regulator-always-on" + +Optional regulator properties: +- "regulator-min-microvolt" +- "regulator-max-microvolt" + +See Documentation/devicetree/bindings/regulator/regulator.txt +for more details about the regulator properties. + +When no "regulator-[min|max]-microvolt" properties are defined, +the device is treated as fixed (or rather "read-only") regulator. + +Example: + volt@0 { + compatible = "arm,vexpress-volt"; + arm,vexpress-sysreg,func = <2 0>; + regulator-name = "Cores"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1050000>; + regulator-always-on; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/imx-rproc.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/imx-rproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbcefd965dc42c1d5a39c8f88d092561523fd788 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/imx-rproc.txt @@ -0,0 +1,33 @@ +NXP iMX6SX/iMX7D Co-Processor Bindings +---------------------------------------- + +This binding provides support for ARM Cortex M4 Co-processor found on some +NXP iMX SoCs. + +Required properties: +- compatible Should be one of: + "fsl,imx7d-cm4" + "fsl,imx6sx-cm4" +- clocks Clock for co-processor (See: ../clock/clock-bindings.txt) +- syscon Phandle to syscon block which provide access to + System Reset Controller + +Optional properties: +- memory-region list of phandels to the reserved memory regions. + (See: ../reserved-memory/reserved-memory.txt) + +Example: + m4_reserved_sysmem1: cm4@80000000 { + reg = <0x80000000 0x80000>; + }; + + m4_reserved_sysmem2: cm4@81000000 { + reg = <0x81000000 0x80000>; + }; + + imx7d-cm4 { + compatible = "fsl,imx7d-cm4"; + memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>; + syscon = <&src>; + clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,adsp.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,adsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..728e4193f7a689e1cc406ba2cb29e29534c93283 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,adsp.txt @@ -0,0 +1,134 @@ +Qualcomm ADSP Peripheral Image Loader + +This document defines the binding for a component that loads and boots firmware +on the Qualcomm ADSP Hexagon core. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,msm8974-adsp-pil" + "qcom,msm8996-adsp-pil" + "qcom,msm8996-slpi-pil" + +- interrupts-extended: + Usage: required + Value type: + Definition: must list the watchdog, fatal IRQs ready, handover and + stop-ack IRQs + +- interrupt-names: + Usage: required + Value type: + Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack" + +- clocks: + Usage: required + Value type: + Definition: reference to the xo clock and optionally aggre2 clock to be + held on behalf of the booting Hexagon core + +- clock-names: + Usage: required + Value type: + Definition: must be "xo" and optionally include "aggre2" + +- cx-supply: + Usage: required + Value type: + Definition: reference to the regulator to be held on behalf of the + booting Hexagon core + +- px-supply: + Usage: required + Value type: + Definition: reference to the px regulator to be held on behalf of the + booting Hexagon core + +- memory-region: + Usage: required + Value type: + Definition: reference to the reserved-memory for the ADSP + +- qcom,smem-states: + Usage: required + Value type: + Definition: reference to the smem state for requesting the ADSP to + shut down + +- qcom,smem-state-names: + Usage: required + Value type: + Definition: must be "stop" + + += SUBNODES +The adsp node may have an subnode named either "smd-edge" or "glink-edge" that +describes the communication edge, channels and devices related to the ADSP. +See ../soc/qcom/qcom,smd.txt and ../soc/qcom/qcom,glink.txt for details on how +to describe these. + + += EXAMPLE +The following example describes the resources needed to boot control the +ADSP, as it is found on MSM8974 boards. + + adsp { + compatible = "qcom,msm8974-adsp-pil"; + + interrupts-extended = <&intc 0 162 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmcc RPM_CXO_CLK>; + clock-names = "xo"; + + cx-supply = <&pm8841_s2>; + + memory-region = <&adsp_region>; + + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + smd-edge { + interrupts = <0 156 IRQ_TYPE_EDGE_RISING>; + + qcom,ipc = <&apcs 8 8>; + qcom,smd-edge = <1>; + }; + }; + +The following example describes the resources needed to boot control the +SLPI, as it is found on MSM8996 boards. + + slpi { + compatible = "qcom,msm8996-slpi-pil"; + interrupts-extended = <&intc 0 390 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&slpi_smp2p_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmcc MSM8996_RPM_SMD_XO_CLK_SRC>, + <&rpmcc MSM8996_RPM_SMD_AGGR2_NOC_CLK>; + clock-names = "xo", "aggre2"; + + cx-supply = <&pm8994_l26>; + px-supply = <&pm8994_lvs2>; + + memory-region = <&slpi_region>; + qcom,smem-states = <&slpi_smp2p_out 0>; + qcom,smem-state-names = "stop"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,q6v5.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,q6v5.txt new file mode 100644 index 0000000000000000000000000000000000000000..601dd9f389aa927c5dcf5aa1ebd5d032d3e9619e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,q6v5.txt @@ -0,0 +1,151 @@ +Qualcomm Hexagon Peripheral Image Loader + +This document defines the binding for a component that loads and boots firmware +on the Qualcomm Hexagon core. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,q6v5-pil", + "qcom,ipq8074-wcss-pil" + "qcom,msm8916-mss-pil", + "qcom,msm8974-mss-pil" + "qcom,msm8996-mss-pil" + "qcom,sdm845-mss-pil" + +- reg: + Usage: required + Value type: + Definition: must specify the base address and size of the qdsp6 and + rmb register blocks + +- reg-names: + Usage: required + Value type: + Definition: must be "q6dsp" and "rmb" + +- interrupts-extended: + Usage: required + Value type: + Definition: must list the watchdog, fatal IRQs ready, handover and + stop-ack IRQs + +- interrupt-names: + Usage: required + Value type: + Definition: must be "wdog", "fatal", "ready", "handover", "stop-ack" + +- clocks: + Usage: required + Value type: + Definition: reference to the iface, bus and mem clocks to be held on + behalf of the booting of the Hexagon core + +- clock-names: + Usage: required + Value type: + Definition: must be "iface", "bus", "mem" + +- resets: + Usage: required + Value type: + Definition: reference to the reset-controller for the modem sub-system + reference to the list of 3 reset-controllers for the + wcss sub-system + +- reset-names: + Usage: required + Value type: + Definition: must be "mss_restart" for the modem sub-system + Definition: must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset" + for the wcss syb-system + +- cx-supply: +- mss-supply: +- mx-supply: +- pll-supply: + Usage: required + Value type: + Definition: reference to the regulators to be held on behalf of the + booting of the Hexagon core + +- qcom,smem-states: + Usage: required + Value type: + Definition: reference to the smem state for requesting the Hexagon to + shut down + +- qcom,smem-state-names: + Usage: required + Value type: + Definition: must be "stop" + +- qcom,halt-regs: + Usage: required + Value type: + Definition: a phandle reference to a syscon representing TCSR followed + by the three offsets within syscon for q6, modem and nc + halt registers. + += SUBNODES: +The Hexagon node must contain two subnodes, named "mba" and "mpss" representing +the memory regions used by the Hexagon firmware. Each sub-node must contain: + +- memory-region: + Usage: required + Value type: + Definition: reference to the reserved-memory for the region + +The Hexagon node may also have an subnode named either "smd-edge" or +"glink-edge" that describes the communication edge, channels and devices +related to the Hexagon. See ../soc/qcom/qcom,smd.txt and +../soc/qcom/qcom,glink.txt for details on how to describe these. + += EXAMPLE +The following example describes the resources needed to boot control the +Hexagon, as it is found on MSM8974 boards. + + modem-rproc@fc880000 { + compatible = "qcom,q6v5-pil"; + reg = <0xfc880000 0x100>, + <0xfc820000 0x020>; + reg-names = "qdsp6", "rmb"; + + interrupts-extended = <&intc 0 24 1>, + <&modem_smp2p_in 0 0>, + <&modem_smp2p_in 1 0>, + <&modem_smp2p_in 2 0>, + <&modem_smp2p_in 3 0>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, + <&gcc GCC_MSS_CFG_AHB_CLK>, + <&gcc GCC_BOOT_ROM_AHB_CLK>; + clock-names = "iface", "bus", "mem"; + + qcom,halt-regs = <&tcsr_mutex_block 0x1180 0x1200 0x1280>; + + resets = <&gcc GCC_MSS_RESTART>; + reset-names = "mss_restart"; + + cx-supply = <&pm8841_s2>; + mss-supply = <&pm8841_s3>; + mx-supply = <&pm8841_s1>; + pll-supply = <&pm8941_l12>; + + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + mba { + memory-region = <&mba_region>; + }; + + mpss { + memory-region = <&mpss_region>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,wcnss-pil.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,wcnss-pil.txt new file mode 100644 index 0000000000000000000000000000000000000000..d420f84ddfb06efd8ae6fd4ac0851ef345f252b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/qcom,wcnss-pil.txt @@ -0,0 +1,158 @@ +Qualcomm WCNSS Peripheral Image Loader + +This document defines the binding for a component that loads and boots firmware +on the Qualcomm WCNSS core. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,riva-pil", + "qcom,pronto-v1-pil", + "qcom,pronto-v2-pil" + +- reg: + Usage: required + Value type: + Definition: must specify the base address and size of the CCU, DXE and + PMU register blocks + +- reg-names: + Usage: required + Value type: + Definition: must be "ccu", "dxe", "pmu" + +- interrupts-extended: + Usage: required + Value type: + Definition: must list the watchdog and fatal IRQs and may specify the + ready, handover and stop-ack IRQs + +- interrupt-names: + Usage: required + Value type: + Definition: should be "wdog", "fatal", optionally followed by "ready", + "handover", "stop-ack" + +- vddmx-supply: +- vddcx-supply: +- vddpx-supply: + Usage: required + Value type: + Definition: reference to the regulators to be held on behalf of the + booting of the WCNSS core + +- qcom,smem-states: + Usage: optional + Value type: + Definition: reference to the SMEM state used to indicate to WCNSS that + it should shut down + +- qcom,smem-state-names: + Usage: optional + Value type: + Definition: should be "stop" + +- memory-region: + Usage: required + Value type: + Definition: reference to reserved-memory node for the remote processor + see ../reserved-memory/reserved-memory.txt + += SUBNODES +A required subnode of the WCNSS PIL is used to describe the attached rf module +and its resource dependencies. It is described by the following properties: + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,wcn3620", + "qcom,wcn3660", + "qcom,wcn3680" + +- clocks: + Usage: required + Value type: + Definition: should specify the xo clock and optionally the rf clock + +- clock-names: + Usage: required + Value type: + Definition: should be "xo", optionally followed by "rf" + +- vddxo-supply: +- vddrfa-supply: +- vddpa-supply: +- vdddig-supply: + Usage: required + Value type: + Definition: reference to the regulators to be held on behalf of the + booting of the WCNSS core + + +The wcnss node can also have an subnode named "smd-edge" that describes the SMD +edge, channels and devices related to the WCNSS. +See ../soc/qcom/qcom,smd.txt for details on how to describe the SMD edge. + += EXAMPLE +The following example describes the resources needed to boot control the WCNSS, +with attached WCN3680, as it is commonly found on MSM8974 boards. + +pronto@fb204000 { + compatible = "qcom,pronto-v2-pil"; + reg = <0xfb204000 0x2000>, <0xfb202000 0x1000>, <0xfb21b000 0x3000>; + reg-names = "ccu", "dxe", "pmu"; + + interrupts-extended = <&intc 0 149 1>, + <&wcnss_smp2p_slave 0 0>, + <&wcnss_smp2p_slave 1 0>, + <&wcnss_smp2p_slave 2 0>, + <&wcnss_smp2p_slave 3 0>; + interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack"; + + vddmx-supply = <&pm8841_s1>; + vddcx-supply = <&pm8841_s2>; + vddpx-supply = <&pm8941_s3>; + + qcom,smem-states = <&wcnss_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + memory-region = <&wcnss_region>; + + pinctrl-names = "default"; + pinctrl-0 = <&wcnss_pin_a>; + + iris { + compatible = "qcom,wcn3680"; + + clocks = <&rpmcc RPM_CXO_CLK_SRC>, <&rpmcc RPM_CXO_A2>; + clock-names = "xo", "rf"; + + vddxo-supply = <&pm8941_l6>; + vddrfa-supply = <&pm8941_l11>; + vddpa-supply = <&pm8941_l19>; + vdddig-supply = <&pm8941_s3>; + }; + + smd-edge { + interrupts = <0 142 1>; + + qcom,ipc = <&apcs 8 17>; + qcom,smd-edge = <6>; + qcom,remote-pid = <4>; + + label = "pronto"; + + wcnss { + compatible = "qcom,wcnss"; + qcom,smd-channels = "WCNSS_CTRL"; + + qcom,mmio = <&pronto>; + + bt { + compatible = "qcom,wcnss-bt"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/st-rproc.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/st-rproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1031bcd90a792cb6cf0a7c3d2a5787e44e596452 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/st-rproc.txt @@ -0,0 +1,41 @@ +STMicroelectronics Co-Processor Bindings +---------------------------------------- + +This binding provides support for adjunct processors found on ST SoCs. + +Co-processors can be controlled from the bootloader or the primary OS. If +the bootloader starts a co-processor, the primary OS must detect its state +and act accordingly. + +Required properties: +- compatible Should be one of: + "st,st231-rproc" + "st,st40-rproc" +- memory-region Reserved memory (See: ../reserved-memory/reserved-memory.txt) +- resets Reset lines (See: ../reset/reset.txt) +- reset-names Must be "sw_reset" and "pwr_reset" +- clocks Clock for co-processor (See: ../clock/clock-bindings.txt) +- clock-frequency Clock frequency to set co-processor at if the bootloader + hasn't already done so +- st,syscfg System configuration register which holds the boot vector + for the co-processor + 1st cell: Phandle to syscon block + 2nd cell: Boot vector register offset + +Example: + + audio_reserved: rproc@42000000 { + compatible = "shared-dma-pool"; + reg = <0x42000000 0x01000000>; + no-map; + }; + + st231-audio { + compatible = "st,st231-rproc"; + memory-region = <&audio_reserved>; + resets = <&softreset STIH407_ST231_AUD_SOFTRESET>; + reset-names = "sw_reset"; + clocks = <&clk_s_c0_flexgen CLK_ST231_AUD_0>; + clock-frequency = <600000000>; + st,syscfg = <&syscfg_core 0x228>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/ti,davinci-rproc.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/ti,davinci-rproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..25f8658e216ff03c46b244fcd7679d0e65cf6797 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/ti,davinci-rproc.txt @@ -0,0 +1,80 @@ +TI Davinci DSP devices +======================= + +Binding status: Unstable - Subject to changes for DT representation of clocks + and resets + +The TI Davinci family of SoCs usually contains a TI DSP Core sub-system that +is used to offload some of the processor-intensive tasks or algorithms, for +achieving various system level goals. + +The processor cores in the sub-system usually contain additional sub-modules +like L1 and/or L2 caches/SRAMs, an Interrupt Controller, an external memory +controller, a dedicated local power/sleep controller etc. The DSP processor +core used in Davinci SoCs is usually a C674x DSP CPU. + +DSP Device Node: +================ +Each DSP Core sub-system is represented as a single DT node. + +Required properties: +-------------------- +The following are the mandatory properties: + +- compatible: Should be one of the following, + "ti,da850-dsp" for DSPs on OMAP-L138 SoCs + +- reg: Should contain an entry for each value in 'reg-names'. + Each entry should have the memory region's start address + and the size of the region, the representation matching + the parent node's '#address-cells' and '#size-cells' values. + +- reg-names: Should contain strings with the following names, each + representing a specific internal memory region or a + specific register space, + "l2sram", "l1pram", "l1dram", "host1cfg", "chipsig_base" + +- interrupts: Should contain the interrupt number used to receive the + interrupts from the DSP. The value should follow the + interrupt-specifier format as dictated by the + 'interrupt-parent' node. + +- memory-region: phandle to the reserved memory node to be associated + with the remoteproc device. The reserved memory node + can be a CMA memory node, and should be defined as + per the bindings in + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt + + +Example: +-------- + + /* DSP Reserved Memory node */ + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dsp_memory_region: dsp-memory@c3000000 { + compatible = "shared-dma-pool"; + reg = <0xc3000000 0x1000000>; + reusable; + }; + }; + + /* DSP node */ + { + dsp: dsp@11800000 { + compatible = "ti,da850-dsp"; + reg = <0x11800000 0x40000>, + <0x11e00000 0x8000>, + <0x11f00000 0x8000>, + <0x01c14044 0x4>, + <0x01c14174 0x8>; + reg-names = "l2sram", "l1pram", "l1dram", "host1cfg", + "chipsig"; + interrupt-parent = <&intc>; + interrupts = <28>; + memory-region = <&dsp_memory_region>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/ti,keystone-rproc.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/ti,keystone-rproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..461dc1d8d570d439f35815d3f3017f1c341fa48f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/ti,keystone-rproc.txt @@ -0,0 +1,182 @@ +TI Keystone DSP devices +======================= + +The TI Keystone 2 family of SoCs usually have one or more (upto 8) TI DSP Core +sub-systems that are used to offload some of the processor-intensive tasks or +algorithms, for achieving various system level goals. + +These processor sub-systems usually contain additional sub-modules like L1 +and/or L2 caches/SRAMs, an Interrupt Controller, an external memory controller, +a dedicated local power/sleep controller etc. The DSP processor core in +Keystone 2 SoCs is usually a TMS320C66x CorePac processor. + +DSP Device Node: +================ +Each DSP Core sub-system is represented as a single DT node, and should also +have an alias with the stem 'rproc' defined. Each node has a number of required +or optional properties that enable the OS running on the host processor (ARM +CorePac) to perform the device management of the remote processor and to +communicate with the remote processor. + +Required properties: +-------------------- +The following are the mandatory properties: + +- compatible: Should be one of the following, + "ti,k2hk-dsp" for DSPs on Keystone 2 66AK2H/K SoCs + "ti,k2l-dsp" for DSPs on Keystone 2 66AK2L SoCs + "ti,k2e-dsp" for DSPs on Keystone 2 66AK2E SoCs + "ti,k2g-dsp" for DSPs on Keystone 2 66AK2G SoCs + +- reg: Should contain an entry for each value in 'reg-names'. + Each entry should have the memory region's start address + and the size of the region, the representation matching + the parent node's '#address-cells' and '#size-cells' values. + +- reg-names: Should contain strings with the following names, each + representing a specific internal memory region, and + should be defined in this order, + "l2sram", "l1pram", "l1dram" + +- ti,syscon-dev: Should be a pair of the phandle to the Keystone Device + State Control node, and the register offset of the DSP + boot address register within that node's address space. + +- resets: Should contain the phandle to the reset controller node + managing the resets for this device, and a reset + specifier. Please refer to either of the following reset + bindings for the reset argument specifier as per SoC, + Documentation/devicetree/bindings/reset/ti-syscon-reset.txt + for 66AK2HK/66AK2L/66AK2E SoCs or, + Documentation/devicetree/bindings/reset/ti,sci-reset.txt + for 66AK2G SoCs + +- interrupts: Should contain an entry for each value in 'interrupt-names'. + Each entry should have the interrupt source number used by + the remote processor to the host processor. The values should + follow the interrupt-specifier format as dictated by the + 'interrupt-parent' node. The purpose of each is as per the + description in the 'interrupt-names' property. + +- interrupt-names: Should contain strings with the following names, each + representing a specific interrupt, + "vring" - interrupt for virtio based IPC + "exception" - interrupt for exception notification + +- kick-gpios: Should specify the gpio device needed for the virtio IPC + stack. This will be used to interrupt the remote processor. + The gpio device to be used is as per the bindings in, + Documentation/devicetree/bindings/gpio/gpio-dsp-keystone.txt + +SoC-specific Required properties: +--------------------------------- +The following are mandatory properties for Keystone 2 66AK2HK, 66AK2L and 66AK2E +SoCs only: + +- clocks: Should contain the device's input clock, and should be + defined as per the bindings in, + Documentation/devicetree/bindings/clock/keystone-gate.txt + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the DSP device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt + +Optional properties: +-------------------- + +- memory-region: phandle to the reserved memory node to be associated + with the remoteproc device. The reserved memory node + can be a CMA memory node, and should be defined as + per the bindings in + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt + + +Examples: +--------- + +1. + /* 66AK2H/K DSP aliases */ + aliases { + rproc0 = &dsp0; + rproc1 = &dsp1; + rproc2 = &dsp2; + rproc3 = &dsp3; + rproc4 = &dsp4; + rproc5 = &dsp5; + rproc6 = &dsp6; + rproc7 = &dsp7; + }; + + /* 66AK2H/K DSP memory node */ + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dsp_common_memory: dsp-common-memory@81f800000 { + compatible = "shared-dma-pool"; + reg = <0x00000008 0x1f800000 0x00000000 0x800000>; + reusable; + }; + }; + + /* 66AK2H/K DSP node */ + soc { + dsp0: dsp@10800000 { + compatible = "ti,k2hk-dsp"; + reg = <0x10800000 0x00100000>, + <0x10e00000 0x00008000>, + <0x10f00000 0x00008000>; + reg-names = "l2sram", "l1pram", "l1dram"; + clocks = <&clkgem0>; + ti,syscon-dev = <&devctrl 0x40>; + resets = <&pscrst 0>; + interrupt-parent = <&kirq0>; + interrupts = <0 8>; + interrupt-names = "vring", "exception"; + kick-gpios = <&dspgpio0 27 0>; + memory-region = <&dsp_common_memory>; + }; + + }; + +2. + /* 66AK2G DSP alias */ + aliases { + rproc0 = &dsp0; + }; + + /* 66AK2G DSP memory node */ + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dsp_common_memory: dsp-common-memory@81f800000 { + compatible = "shared-dma-pool"; + reg = <0x00000008 0x1f800000 0x00000000 0x800000>; + reusable; + }; + }; + + /* 66AK2G DSP node */ + soc { + dsp0: dsp@10800000 { + compatible = "ti,k2g-dsp"; + reg = <0x10800000 0x00100000>, + <0x10e00000 0x00008000>, + <0x10f00000 0x00008000>; + reg-names = "l2sram", "l1pram", "l1dram"; + power-domains = <&k2g_pds 0x0046>; + ti,syscon-dev = <&devctrl 0x40>; + resets = <&k2g_reset 0x0046 0x1>; + interrupt-parent = <&kirq0>; + interrupts = <0 8>; + interrupt-names = "vring", "exception"; + kick-gpios = <&dspgpio0 27 0>; + memory-region = <&dsp_common_memory>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/remoteproc/wkup_m3_rproc.txt b/arch/arm64/boot/dts/vendor/bindings/remoteproc/wkup_m3_rproc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a70073797eb83a340fe75fb41d3296c8c81b9ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/remoteproc/wkup_m3_rproc.txt @@ -0,0 +1,52 @@ +TI Wakeup M3 Remoteproc Driver +============================== + +The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor +(commonly referred to as Wakeup M3 or CM3) to help with various low power tasks +that cannot be controlled from the MPU. This CM3 processor requires a firmware +binary to accomplish this. The wkup_m3 remoteproc driver handles the loading of +the firmware and booting of the CM3. + +Wkup M3 Device Node: +==================== +A wkup_m3 device node is used to represent the Wakeup M3 processor instance +within the SoC. It is added as a child node of the parent interconnect bus +(l4_wkup) through which it is accessible to the MPU. + +Required properties: +-------------------- +- compatible: Should be one of, + "ti,am3352-wkup-m3" for AM33xx SoCs + "ti,am4372-wkup-m3" for AM43xx SoCs +- reg: Should contain the address ranges for the two internal + memory regions, UMEM and DMEM. The parent node should + provide an appropriate ranges property for properly + translating these into bus addresses. +- reg-names: Contains the corresponding names for the two memory + regions. These should be named "umem" & "dmem". +- ti,hwmods: Name of the hwmod associated with the wkupm3 device. +- ti,pm-firmware: Name of firmware file to be used for loading and + booting the wkup_m3 remote processor. + +Example: +-------- +/* AM33xx */ +ocp { + l4_wkup: l4_wkup@44c00000 { + compatible = "am335-l4-wkup", "simple-bus"; + ranges = <0 0x44c00000 0x400000>; + #address-cells = <1>; + #size-cells = <1>; + + wkup_m3: wkup_m3@100000 { + compatible = "ti,am3352-wkup-m3"; + reg = <0x100000 0x4000>, + <0x180000 0x2000>; + reg-names = "umem", "dmem"; + ti,hwmods = "wkup_m3"; + ti,pm-firmware = "am335x-pm-firmware.elf"; + }; + }; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reserved-memory/qcom,cmd-db.txt b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/qcom,cmd-db.txt new file mode 100644 index 0000000000000000000000000000000000000000..68395530c0a5095cd184d8e344ab2b413b36b4b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/qcom,cmd-db.txt @@ -0,0 +1,37 @@ +Command DB +--------- + +Command DB is a database that provides a mapping between resource key and the +resource address for a system resource managed by a remote processor. The data +is stored in a shared memory region and is loaded by the remote processor. + +Some of the Qualcomm Technologies Inc SoC's have hardware accelerators for +controlling shared resources. Depending on the board configuration the shared +resource properties may change. These properties are dynamically probed by the +remote processor and made available in the shared memory. + +The bindings for Command DB is specified in the reserved-memory section in +devicetree. The devicetree representation of the command DB driver should be: + +Properties: +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,cmd-db" + +- reg: + Usage: required + Value type: + Definition: The register address that points to the actual location of + the Command DB in memory. + +Example: + + reserved-memory { + [...] + reserved-memory@85fe0000 { + reg = <0x0 0x85fe0000 0x0 0x20000>; + compatible = "qcom,cmd-db"; + no-map; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reserved-memory/qcom,rmtfs-mem.txt b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/qcom,rmtfs-mem.txt new file mode 100644 index 0000000000000000000000000000000000000000..8562ba1dce69253bd7cfb6a9c8dd115d297d2b76 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/qcom,rmtfs-mem.txt @@ -0,0 +1,51 @@ +Qualcomm Remote File System Memory binding + +This binding describes the Qualcomm remote filesystem memory, which serves the +purpose of describing the shared memory region used for remote processors to +access block device data using the Remote Filesystem protocol. + +- compatible: + Usage: required + Value type: + Definition: must be: + "qcom,rmtfs-mem" + +- reg: + Usage: required for static allocation + Value type: + Definition: must specify base address and size of the memory region, + as described in reserved-memory.txt + +- size: + Usage: required for dynamic allocation + Value type: + Definition: must specify a size of the memory region, as described in + reserved-memory.txt + +- qcom,client-id: + Usage: required + Value type: + Definition: identifier of the client to use this region for buffers. + +- qcom,vmid: + Usage: optional + Value type: + Definition: vmid of the remote processor, to set up memory protection. + += EXAMPLE +The following example shows the remote filesystem memory setup for APQ8016, +with the rmtfs region for the Hexagon DSP (id #1) located at 0x86700000. + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + rmtfs@86700000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0x86700000 0x0 0xe0000>; + no-map; + + qcom,client-id = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reserved-memory/ramoops.txt b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/ramoops.txt new file mode 100644 index 0000000000000000000000000000000000000000..0eba562fe5c6421e3cd29d9c5b022d7b3d31647a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/ramoops.txt @@ -0,0 +1,51 @@ +Ramoops oops/panic logger +========================= + +ramoops provides persistent RAM storage for oops and panics, so they can be +recovered after a reboot. This is a child-node of "/reserved-memory", and +is named "ramoops" after the backend, rather than "pstore" which is the +subsystem. + +Parts of this storage may be set aside for other persistent log buffers, such +as kernel log messages, or for optional ECC error-correction data. The total +size of these optional buffers must fit in the reserved region. + +Any remaining space will be used for a circular buffer of oops and panic +records. These records have a configurable size, with a size of 0 indicating +that they should be disabled. + +At least one of "record-size", "console-size", "ftrace-size", or "pmsg-size" +must be set non-zero, but are otherwise optional as listed below. + + +Required properties: + +- compatible: must be "ramoops" + +- reg: region of memory that is preserved between reboots + + +Optional properties: + +- ecc-size: enables ECC support and specifies ECC buffer size in bytes + (defaults to 0: no ECC) + +- record-size: maximum size in bytes of each dump done on oops/panic + (defaults to 0: disabled) + +- console-size: size in bytes of log buffer reserved for kernel messages + (defaults to 0: disabled) + +- ftrace-size: size in bytes of log buffer reserved for function tracing and + profiling (defaults to 0: disabled) + +- pmsg-size: size in bytes of log buffer reserved for userspace messages + (defaults to 0: disabled) + +- unbuffered: if present, use unbuffered mappings to map the reserved region + (defaults to buffered mappings) + +- no-dump-oops: if present, only dump panics (defaults to panics and oops) + +- flags: if present, pass ramoops behavioral flags (defaults to 0, + see include/linux/pstore_ram.h RAMOOPS_FLAG_* for flag values). diff --git a/arch/arm64/boot/dts/vendor/bindings/reserved-memory/reserved-memory.txt b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/reserved-memory.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c0e7b50335339962886c060026decfb31857324 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reserved-memory/reserved-memory.txt @@ -0,0 +1,138 @@ +*** Reserved memory regions *** + +Reserved memory is specified as a node under the /reserved-memory node. +The operating system shall exclude reserved memory from normal usage +one can create child nodes describing particular reserved (excluded from +normal use) memory regions. Such memory regions are usually designed for +the special usage by various device drivers. + +Parameters for each memory region can be encoded into the device tree +with the following nodes: + +/reserved-memory node +--------------------- +#address-cells, #size-cells (required) - standard definition + - Should use the same values as the root node +ranges (required) - standard definition + - Should be empty + +/reserved-memory/ child nodes +----------------------------- +Each child of the reserved-memory node specifies one or more regions of +reserved memory. Each child node may either use a 'reg' property to +specify a specific range of reserved memory, or a 'size' property with +optional constraints to request a dynamically allocated block of memory. + +Following the generic-names recommended practice, node names should +reflect the purpose of the node (ie. "framebuffer" or "dma-pool"). Unit +address (@
) should be appended to the name if the node is a +static allocation. + +Properties: +Requires either a) or b) below. +a) static allocation + reg (required) - standard definition +b) dynamic allocation + size (required) - length based on parent's #size-cells + - Size in bytes of memory to reserve. + alignment (optional) - length based on parent's #size-cells + - Address boundary for alignment of allocation. + alloc-ranges (optional) - prop-encoded-array (address, length pairs). + - Specifies regions of memory that are + acceptable to allocate from. + +If both reg and size are present, then the reg property takes precedence +and size is ignored. + +Additional properties: +compatible (optional) - standard definition + - may contain the following strings: + - shared-dma-pool: This indicates a region of memory meant to be + used as a shared pool of DMA buffers for a set of devices. It can + be used by an operating system to instantiate the necessary pool + management subsystem if necessary. + - removed-dma-pool: This indicates a region of memory which is meant to + be carved out and not exposed to kernel. + - vendor specific string in the form ,[-] +no-map (optional) - empty property + - Indicates the operating system must not create a virtual mapping + of the region as part of its standard mapping of system memory, + nor permit speculative access to it under any circumstances other + than under the control of the device driver using the region. +reusable (optional) - empty property + - The operating system can use the memory in this region with the + limitation that the device driver(s) owning the region need to be + able to reclaim it back. Typically that means that the operating + system can use that region to store volatile or cached data that + can be otherwise regenerated or migrated elsewhere. + +Linux implementation note: +- If a "linux,cma-default" property is present, then Linux will use the + region for the default pool of the contiguous memory allocator. + +- If a "linux,dma-default" property is present, then Linux will use the + region for the default pool of the consistent DMA allocator. + +Device node references to reserved memory +----------------------------------------- +Regions in the /reserved-memory node may be referenced by other device +nodes by adding a memory-region property to the device node. + +memory-region (optional) - phandle, specifier pairs to children of /reserved-memory + +Example +------- +This example defines 3 contiguous regions are defined for Linux kernel: +one default of all device drivers (named linux,cma@72000000 and 64MiB in size), +one dedicated to the framebuffer device (named framebuffer@78000000, 8MiB), and +one for multimedia processing (named multimedia-memory@77000000, 64MiB). + +/ { + #address-cells = <1>; + #size-cells = <1>; + + memory { + reg = <0x40000000 0x40000000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x4000000>; + alignment = <0x2000>; + linux,cma-default; + }; + + display_reserved: framebuffer@78000000 { + reg = <0x78000000 0x800000>; + }; + + multimedia_reserved: multimedia@77000000 { + compatible = "acme,multimedia-memory"; + reg = <0x77000000 0x4000000>; + }; + }; + + /* ... */ + + fb0: video@12300000 { + memory-region = <&display_reserved>; + /* ... */ + }; + + scaler: scaler@12500000 { + memory-region = <&multimedia_reserved>; + /* ... */ + }; + + codec: codec@12600000 { + memory-region = <&multimedia_reserved>; + /* ... */ + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/allwinner,sunxi-clock-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/allwinner,sunxi-clock-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ca66c96fe97e7b98da4eba0cbdcf6158ffac35c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/allwinner,sunxi-clock-reset.txt @@ -0,0 +1,21 @@ +Allwinner sunxi Peripheral Reset Controller +=========================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be one of the following: + "allwinner,sun6i-a31-ahb1-reset" + "allwinner,sun6i-a31-clock-reset" +- reg: should be register base and length as documented in the + datasheet +- #reset-cells: 1, see below + +example: + +ahb1_rst: reset@1c202c0 { + #reset-cells = <1>; + compatible = "allwinner,sun6i-a31-ahb1-reset"; + reg = <0x01c202c0 0xc>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/amlogic,meson-axg-audio-arb.txt b/arch/arm64/boot/dts/vendor/bindings/reset/amlogic,meson-axg-audio-arb.txt new file mode 100644 index 0000000000000000000000000000000000000000..26e542eb96dfa227769fe4a9695ce1744b3a2b99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/amlogic,meson-axg-audio-arb.txt @@ -0,0 +1,21 @@ +* Amlogic audio memory arbiter controller + +The Amlogic Audio ARB is a simple device which enables or +disables the access of Audio FIFOs to DDR on AXG based SoC. + +Required properties: +- compatible: 'amlogic,meson-axg-audio-arb' +- reg: physical base address of the controller and length of memory + mapped region. +- clocks: phandle to the fifo peripheral clock provided by the audio + clock controller. +- #reset-cells: must be 1. + +Example on the A113 SoC: + +arb: reset-controller@280 { + compatible = "amlogic,meson-axg-audio-arb"; + reg = <0x0 0x280 0x0 0x4>; + #reset-cells = <1>; + clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/amlogic,meson-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/amlogic,meson-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..28ef6c295c766cd711136d66258bffa8eddf88f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/amlogic,meson-reset.txt @@ -0,0 +1,19 @@ +Amlogic Meson SoC Reset Controller +======================================= + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "amlogic,meson8b-reset", "amlogic,meson-gxbb-reset" or + "amlogic,meson-axg-reset". +- reg: should contain the register address base +- #reset-cells: 1, see below + +example: + +reset: reset-controller { + compatible = "amlogic,meson-gxbb-reset"; + reg = <0x0 0x04404 0x0 0x20>; + #reset-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/ath79-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/ath79-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c56330bf398b9db1466c089abb3d4d4c30feb7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/ath79-reset.txt @@ -0,0 +1,20 @@ +Binding for Qualcomm Atheros AR7xxx/AR9XXX reset controller + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required Properties: +- compatible: has to be "qca,-reset", "qca,ar7100-reset" + as fallback +- reg: Base address and size of the controllers memory area +- #reset-cells : Specifies the number of cells needed to encode reset + line, should be 1 + +Example: + + reset-controller@1806001c { + compatible = "qca,ar9132-reset", "qca,ar7100-reset"; + reg = <0x1806001c 0x4>; + + #reset-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/berlin,reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/berlin,reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..514fee098b4bb62de8f896863026429e0bfaf9b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/berlin,reset.txt @@ -0,0 +1,23 @@ +Marvell Berlin reset controller +=============================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +The reset controller node must be a sub-node of the chip controller +node on Berlin SoCs. + +Required properties: +- compatible: should be "marvell,berlin2-reset" +- #reset-cells: must be set to 2 + +Example: + +chip_rst: reset { + compatible = "marvell,berlin2-reset"; + #reset-cells = <2>; +}; + +&usb_phy0 { + resets = <&chip_rst 0x104 12>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/brcm,bcm63138-pmb.txt b/arch/arm64/boot/dts/vendor/bindings/reset/brcm,bcm63138-pmb.txt new file mode 100644 index 0000000000000000000000000000000000000000..a98872d27872e98124bc2c2686681e08673941f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/brcm,bcm63138-pmb.txt @@ -0,0 +1,19 @@ +Broadcom BCM63138 Processor Monitor Bus binding +=============================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Require properties: + +- compatible: must be "brcm,bcm63138-pmb" +- reg: base register address and size for this bus controller +- #reset-cells: must be 2 first cell is the address within the bus instance designated + by the phandle, and the second is the number of zones for this peripheral + +Example: + pmb0: reset-controller@4800c0 { + compatible = "brcm,bcm63138-pmb"; + reg = <0x4800c0 0x10>; + #reset-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/fsl,imx-src.txt b/arch/arm64/boot/dts/vendor/bindings/reset/fsl,imx-src.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ed79e60248a73e3cc1f58b1a91d3f770f9082f6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/fsl,imx-src.txt @@ -0,0 +1,49 @@ +Freescale i.MX System Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "fsl,-src" +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain SRC interrupt and CPU WDOG interrupt, + in this order. +- #reset-cells: 1, see below + +example: + +src: src@20d8000 { + compatible = "fsl,imx6q-src"; + reg = <0x020d8000 0x4000>; + interrupts = <0 91 0x04 0 96 0x04>; + #reset-cells = <1>; +}; + +Specifying reset lines connected to IP modules +============================================== + +The system reset controller can be used to reset the GPU, VPU, +IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device +nodes should specify the reset line on the SRC in their resets +property, containing a phandle to the SRC device node and a +RESET_INDEX specifying which module to reset, as described in +reset.txt + +example: + + ipu1: ipu@2400000 { + resets = <&src 2>; + }; + ipu2: ipu@2800000 { + resets = <&src 4>; + }; + +The following RESET_INDEX values are valid for i.MX5: +GPU_RESET 0 +VPU_RESET 1 +IPU1_RESET 2 +OPEN_VG_RESET 3 +The following additional RESET_INDEX value is valid for i.MX6: +IPU2_RESET 4 diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/fsl,imx7-src.txt b/arch/arm64/boot/dts/vendor/bindings/reset/fsl,imx7-src.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e1afc3d8480d45c9b75be4f0fdf2007e47a3d65 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/fsl,imx7-src.txt @@ -0,0 +1,47 @@ +Freescale i.MX7 System Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "fsl,imx7-src", "syscon" +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain SRC interrupt +- #reset-cells: 1, see below + +example: + +src: reset-controller@30390000 { + compatible = "fsl,imx7d-src", "syscon"; + reg = <0x30390000 0x2000>; + interrupts = ; + #reset-cells = <1>; +}; + + +Specifying reset lines connected to IP modules +============================================== + +The system reset controller can be used to reset various set of +peripherals. Device nodes that need access to reset lines should +specify them as a reset phandle in their corresponding node as +specified in reset.txt. + +Example: + + pcie: pcie@33800000 { + + ... + + resets = <&src IMX7_RESET_PCIEPHY>, + <&src IMX7_RESET_PCIE_CTRL_APPS_EN>; + reset-names = "pciephy", "apps"; + + ... + }; + + +For list of all valid reset indicies see + diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/hisilicon,hi3660-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/hisilicon,hi3660-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..2bf3344b2a026955454ee8a6d62556f18f16cd34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/hisilicon,hi3660-reset.txt @@ -0,0 +1,43 @@ +Hisilicon System Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +The reset controller registers are part of the system-ctl block on +hi3660 SoC. + +Required properties: +- compatible: should be + "hisilicon,hi3660-reset" +- hisi,rst-syscon: phandle of the reset's syscon. +- #reset-cells : Specifies the number of cells needed to encode a + reset source. The type shall be a and the value shall be 2. + + Cell #1 : offset of the reset assert control + register from the syscon register base + offset + 4: deassert control register + offset + 8: status control register + Cell #2 : bit position of the reset in the reset control register + +Example: + iomcu: iomcu@ffd7e000 { + compatible = "hisilicon,hi3660-iomcu", "syscon"; + reg = <0x0 0xffd7e000 0x0 0x1000>; + }; + + iomcu_rst: iomcu_rst_controller { + compatible = "hisilicon,hi3660-reset"; + hisi,rst-syscon = <&iomcu>; + #reset-cells = <2>; + }; + +Specifying reset lines connected to IP modules +============================================== +example: + + i2c0: i2c@..... { + ... + resets = <&iomcu_rst 0x20 3>; /* offset: 0x20; bit: 3 */ + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/hisilicon,hi6220-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/hisilicon,hi6220-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..c25da39df7073ed6be8b0b7c0b90c4aee325d99a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/hisilicon,hi6220-reset.txt @@ -0,0 +1,36 @@ +Hisilicon System Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +The reset controller registers are part of the system-ctl block on +hi6220 SoC. + +Required properties: +- compatible: should be one of the following: + - "hisilicon,hi6220-sysctrl", "syscon" : For peripheral reset controller. + - "hisilicon,hi6220-mediactrl", "syscon" : For media reset controller. +- reg: should be register base and length as documented in the + datasheet +- #reset-cells: 1, see below + +Example: +sys_ctrl: sys_ctrl@f7030000 { + compatible = "hisilicon,hi6220-sysctrl", "syscon"; + reg = <0x0 0xf7030000 0x0 0x2000>; + #clock-cells = <1>; + #reset-cells = <1>; +}; + +Specifying reset lines connected to IP modules +============================================== +example: + + uart1: serial@..... { + ... + resets = <&sys_ctrl PERIPH_RSTEN3_UART1>; + ... + }; + +The index could be found in . diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/img,pistachio-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/img,pistachio-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c05d16367df88a9a52e93e56d803f05e0752d2c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/img,pistachio-reset.txt @@ -0,0 +1,55 @@ +Pistachio Reset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable individual IP blocks within the Pistachio SoC using "soft reset" +control bits found in the Pistachio SoC top level registers. + +The actual action taken when soft reset is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers, and following an assert/deassert sequence the hardware's previous +state may no longer be valid. + +Please refer to Documentation/devicetree/bindings/reset/reset.txt +for common reset controller binding usage. + +Required properties: + +- compatible: Contains "img,pistachio-reset" + +- #reset-cells: Contains 1 + +Example: + + cr_periph: clk@18148000 { + compatible = "img,pistachio-cr-periph", "syscon", "simple-mfd"; + reg = <0x18148000 0x1000>; + clocks = <&clk_periph PERIPH_CLK_SYS>; + clock-names = "sys"; + #clock-cells = <1>; + + pistachio_reset: reset-controller { + compatible = "img,pistachio-reset"; + #reset-cells = <1>; + }; + }; + +Specifying reset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the pistachio reset device node and an +index specifying which reset to use, as described in +Documentation/devicetree/bindings/reset/reset.txt. + +Example: + + spdif_out: spdif-out@18100d00 { + ... + resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>; + reset-names = "rst"; + ... + }; + +Macro definitions for the supported resets can be found in: +include/dt-bindings/reset/pistachio-resets.h diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/lantiq,reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/lantiq,reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6aef36b7d150e4adf7ad2c2eae4041b2eef4e9f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/lantiq,reset.txt @@ -0,0 +1,30 @@ +Lantiq XWAY SoC RCU reset controller binding +============================================ + +This binding describes a reset-controller found on the RCU module on Lantiq +XWAY SoCs. + +This node has to be a sub node of the Lantiq RCU block. + +------------------------------------------------------------------------------- +Required properties: +- compatible : Should be one of + "lantiq,danube-reset" + "lantiq,xrx200-reset" +- reg : Defines the following sets of registers in the parent + syscon device + - Offset of the reset set register + - Offset of the reset status register +- #reset-cells : Specifies the number of cells needed to encode the + reset line, should be 2. + The first cell takes the reset set bit and the + second cell takes the status bit. + +------------------------------------------------------------------------------- +Example for the reset-controllers on the xRX200 SoCs: + reset0: reset-controller@10 { + compatible = "lantiq,xrx200-reset"; + reg <0x10 0x04>, <0x14 0x04>; + + #reset-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/nxp,lpc1850-rgu.txt b/arch/arm64/boot/dts/vendor/bindings/reset/nxp,lpc1850-rgu.txt new file mode 100644 index 0000000000000000000000000000000000000000..05d5be48dae44d39a165a257d915348c406a8008 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/nxp,lpc1850-rgu.txt @@ -0,0 +1,83 @@ +NXP LPC1850 Reset Generation Unit (RGU) +======================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "nxp,lpc1850-rgu" +- reg: register base and length +- clocks: phandle and clock specifier to RGU clocks +- clock-names: should contain "delay" and "reg" +- #reset-cells: should be 1 + +See table below for valid peripheral reset numbers. Numbers not +in the table below are either reserved or not applicable for +normal operation. + +Reset Peripheral + 9 System control unit (SCU) + 12 ARM Cortex-M0 subsystem core (LPC43xx only) + 13 CPU core + 16 LCD controller + 17 USB0 + 18 USB1 + 19 DMA + 20 SDIO + 21 External memory controller (EMC) + 22 Ethernet + 25 Flash bank A + 27 EEPROM + 28 GPIO + 29 Flash bank B + 32 Timer0 + 33 Timer1 + 34 Timer2 + 35 Timer3 + 36 Repetitive Interrupt timer (RIT) + 37 State Configurable Timer (SCT) + 38 Motor control PWM (MCPWM) + 39 QEI + 40 ADC0 + 41 ADC1 + 42 DAC + 44 USART0 + 45 UART1 + 46 USART2 + 47 USART3 + 48 I2C0 + 49 I2C1 + 50 SSP0 + 51 SSP1 + 52 I2S0 and I2S1 + 53 Serial Flash Interface (SPIFI) + 54 C_CAN1 + 55 C_CAN0 + 56 ARM Cortex-M0 application core (LPC4370 only) + 57 SGPIO (LPC43xx only) + 58 SPI (LPC43xx only) + 60 ADCHS (12-bit ADC) (LPC4370 only) + +Refer to NXP LPC18xx or LPC43xx user manual for more details about +the reset signals and the connected block/peripheral. + +Reset provider example: +rgu: reset-controller@40053000 { + compatible = "nxp,lpc1850-rgu"; + reg = <0x40053000 0x1000>; + clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_BUS>; + clock-names = "delay", "reg"; + #reset-cells = <1>; +}; + +Reset consumer example: +mac: ethernet@40010000 { + compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac"; + reg = <0x40010000 0x2000>; + interrupts = <5>; + interrupt-names = "macirq"; + clocks = <&ccu1 CLK_CPU_ETHERNET>; + clock-names = "stmmaceth"; + resets = <&rgu 22>; + reset-names = "stmmaceth"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/oxnas,reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/oxnas,reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..d27ccb5d04fc362352bbbdc1762b2a34f1bce54c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/oxnas,reset.txt @@ -0,0 +1,32 @@ +Oxford Semiconductor OXNAS SoC Family RESET Controller +================================================ + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: For OX810SE, should be "oxsemi,ox810se-reset" + For OX820, should be "oxsemi,ox820-reset" +- #reset-cells: 1, see below + +Parent node should have the following properties : +- compatible: For OX810SE, should be : + "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd" + For OX820, should be : + "oxsemi,ox820-sys-ctrl", "syscon", "simple-mfd" + +Reset indices are in dt-bindings include files : +- For OX810SE: include/dt-bindings/reset/oxsemi,ox810se.h +- For OX820: include/dt-bindings/reset/oxsemi,ox820.h + +example: + +sys: sys-ctrl@000000 { + compatible = "oxsemi,ox810se-sys-ctrl", "syscon", "simple-mfd"; + reg = <0x000000 0x100000>; + + reset: reset-controller { + compatible = "oxsemi,ox810se-reset"; + #reset-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/qcom,aoss-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/qcom,aoss-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..510c748656ec5d429b10e9359a29c851121c8b9e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/qcom,aoss-reset.txt @@ -0,0 +1,52 @@ +Qualcomm AOSS Reset Controller +====================================== + +This binding describes a reset-controller found on AOSS-CC (always on subsystem) +for Qualcomm SDM845 SoCs. + +Required properties: +- compatible: + Usage: required + Value type: + Definition: must be: + "qcom,sdm845-aoss-cc" + +- reg: + Usage: required + Value type: + Definition: must specify the base address and size of the register + space. + +- #reset-cells: + Usage: required + Value type: + Definition: must be 1; cell entry represents the reset index. + +Example: + +aoss_reset: reset-controller@c2a0000 { + compatible = "qcom,sdm845-aoss-cc"; + reg = <0xc2a0000 0x31000>; + #reset-cells = <1>; +}; + +Specifying reset lines connected to IP modules +============================================== + +Device nodes that need access to reset lines should +specify them as a reset phandle in their corresponding node as +specified in reset.txt. + +For list of all valid reset indicies see + + +Example: + +modem-pil@4080000 { + ... + + resets = <&aoss_reset AOSS_CC_MSS_RESTART>; + reset-names = "mss_restart"; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/renesas,rst.txt b/arch/arm64/boot/dts/vendor/bindings/reset/renesas,rst.txt new file mode 100644 index 0000000000000000000000000000000000000000..67e83b02e10b63e33615e7f516618cfe238c84c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/renesas,rst.txt @@ -0,0 +1,43 @@ +DT bindings for the Renesas R-Car and RZ/G Reset Controllers + +The R-Car and RZ/G Reset Controllers provide reset control, and implement the +following functions: + - Latching of the levels on mode pins when PRESET# is negated, + - Mode monitoring register, + - Reset control of peripheral devices (on R-Car Gen1), + - Watchdog timer (on R-Car Gen1), + - Register-based reset control and boot address registers for the various CPU + cores (on R-Car Gen2 and Gen3, and on RZ/G). + + +Required properties: + - compatible: Should be + - "renesas,-reset-wdt" for R-Car Gen1, + - "renesas,-rst" for R-Car Gen2 and Gen3, and RZ/G + Examples with soctypes are: + - "renesas,r8a7743-rst" (RZ/G1M) + - "renesas,r8a7745-rst" (RZ/G1E) + - "renesas,r8a77470-rst" (RZ/G1C) + - "renesas,r8a7778-reset-wdt" (R-Car M1A) + - "renesas,r8a7779-reset-wdt" (R-Car H1) + - "renesas,r8a7790-rst" (R-Car H2) + - "renesas,r8a7791-rst" (R-Car M2-W) + - "renesas,r8a7792-rst" (R-Car V2H + - "renesas,r8a7793-rst" (R-Car M2-N) + - "renesas,r8a7794-rst" (R-Car E2) + - "renesas,r8a7795-rst" (R-Car H3) + - "renesas,r8a7796-rst" (R-Car M3-W) + - "renesas,r8a77965-rst" (R-Car M3-N) + - "renesas,r8a77970-rst" (R-Car V3M) + - "renesas,r8a77980-rst" (R-Car V3H) + - "renesas,r8a77990-rst" (R-Car E3) + - "renesas,r8a77995-rst" (R-Car D3) + - reg: Address start and address range for the device. + + +Example: + + rst: reset-controller@e6160000 { + compatible = "renesas,r8a7795-rst"; + reg = <0 0xe6160000 0 0x0200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..31db6ff849084fa7e90d01c5dd63d529a7727dc4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/reset.txt @@ -0,0 +1,75 @@ += Reset Signal Device Tree Bindings = + +This binding is intended to represent the hardware reset signals present +internally in most IC (SoC, FPGA, ...) designs. Reset signals for whole +standalone chips are most likely better represented as GPIOs, although there +are likely to be exceptions to this rule. + +Hardware blocks typically receive a reset signal. This signal is generated by +a reset provider (e.g. power management or clock module) and received by a +reset consumer (the module being reset, or a module managing when a sub- +ordinate module is reset). This binding exists to represent the provider and +consumer, and provide a way to couple the two together. + +A reset signal is represented by the phandle of the provider, plus a reset +specifier - a list of DT cells that represents the reset signal within the +provider. The length (number of cells) and semantics of the reset specifier +are dictated by the binding of the reset provider, although common schemes +are described below. + +A word on where to place reset signal consumers in device tree: It is possible +in hardware for a reset signal to affect multiple logically separate HW blocks +at once. In this case, it would be unwise to represent this reset signal in +the DT node of each affected HW block, since if activated, an unrelated block +may be reset. Instead, reset signals should be represented in the DT node +where it makes most sense to control it; this may be a bus node if all +children of the bus are affected by the reset signal, or an individual HW +block node for dedicated reset signals. The intent of this binding is to give +appropriate software access to the reset signals in order to manage the HW, +rather than to slavishly enumerate the reset signal that affects each HW +block. + += Reset providers = + +Required properties: +#reset-cells: Number of cells in a reset specifier; Typically 0 for nodes + with a single reset output and 1 for nodes with multiple + reset outputs. + +For example: + + rst: reset-controller { + #reset-cells = <1>; + }; + += Reset consumers = + +Required properties: +resets: List of phandle and reset specifier pairs, one pair + for each reset signal that affects the device, or that the + device manages. Note: if the reset provider specifies '0' for + #reset-cells, then only the phandle portion of the pair will + appear. + +Optional properties: +reset-names: List of reset signal name strings sorted in the same order as + the resets property. Consumers drivers will use reset-names to + match reset signal names with reset specifiers. + +For example: + + device { + resets = <&rst 20>; + reset-names = "reset"; + }; + +This represents a device with a single reset signal named "reset". + + bus { + resets = <&rst 10> <&rst 11> <&rst 12> <&rst 11>; + reset-names = "i2s1", "i2s2", "dma", "mixer"; + }; + +This represents a bus that controls the reset signal of each of four sub- +ordinate devices. Consider for example a bus that fails to operate unless no +child device has reset asserted. diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/sirf,rstc.txt b/arch/arm64/boot/dts/vendor/bindings/reset/sirf,rstc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0505de742d30d4eb963985858343594dd60d0cab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/sirf,rstc.txt @@ -0,0 +1,42 @@ +CSR SiRFSoC Reset Controller +====================================== + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "sirf,prima2-rstc" or "sirf,marco-rstc" +- reg: should be register base and length as documented in the + datasheet +- #reset-cells: 1, see below + +example: + +rstc: reset-controller@88010000 { + compatible = "sirf,prima2-rstc"; + reg = <0x88010000 0x1000>; + #reset-cells = <1>; +}; + +Specifying reset lines connected to IP modules +============================================== + +The reset controller(rstc) manages various reset sources. This module provides +reset signals for most blocks in system. Those device nodes should specify the +reset line on the rstc in their resets property, containing a phandle to the +rstc device node and a RESET_INDEX specifying which module to reset, as described +in reset.txt. + +For SiRFSoC, RESET_INDEX is just reset_bit defined in SW_RST0 and SW_RST1 registers. +For modules whose rest_bit is in SW_RST0, its RESET_INDEX is 0~31. For modules whose +rest_bit is in SW_RST1, its RESET_INDEX is 32~63. + +example: + +vpp@90020000 { + compatible = "sirf,prima2-vpp"; + reg = <0x90020000 0x10000>; + interrupts = <31>; + clocks = <&clks 35>; + resets = <&rstc 6>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/snps,axs10x-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/snps,axs10x-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..32d8435a41dfbf088344e158cf8c07d10ec9eb09 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/snps,axs10x-reset.txt @@ -0,0 +1,33 @@ +Binding for the AXS10x reset controller + +This binding describes the ARC AXS10x boards custom IP-block which allows +to control reset signals of selected peripherals. For example DW GMAC, etc... +This block is controlled via memory-mapped register (AKA CREG) which +represents up-to 32 reset lines. + +As of today only the following lines are used: + - DW GMAC - line 5 + +This binding uses the common reset binding[1]. + +[1] Documentation/devicetree/bindings/reset/reset.txt + +Required properties: +- compatible: should be "snps,axs10x-reset". +- reg: should always contain pair address - length: for creg reset + bits register. +- #reset-cells: from common reset binding; Should always be set to 1. + +Example: + reset: reset-controller@11220 { + compatible = "snps,axs10x-reset"; + #reset-cells = <1>; + reg = <0x11220 0x4>; + }; + +Specifying reset lines connected to IP modules: + ethernet@.... { + .... + resets = <&reset 5>; + .... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/snps,hsdk-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/snps,hsdk-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..830069b1c37c4163f878f87a3780f135af4a2d7c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/snps,hsdk-reset.txt @@ -0,0 +1,28 @@ +Binding for the Synopsys HSDK reset controller + +This binding uses the common reset binding[1]. + +[1] Documentation/devicetree/bindings/reset/reset.txt + +Required properties: +- compatible: should be "snps,hsdk-reset". +- reg: should always contain 2 pairs address - length: first for reset + configuration register and second for corresponding SW reset and status bits + register. +- #reset-cells: from common reset binding; Should always be set to 1. + +Example: + reset: reset@880 { + compatible = "snps,hsdk-reset"; + #reset-cells = <1>; + reg = <0x8A0 0x4>, <0xFF0 0x4>; + }; + +Specifying reset lines connected to IP modules: + ethernet@.... { + .... + resets = <&reset HSDK_V1_ETH_RESET>; + .... + }; + +The index could be found in diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/socfpga-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/socfpga-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..98c9f560e5c5bf633b799500cfe36272d0a564e3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/socfpga-reset.txt @@ -0,0 +1,15 @@ +Altera SOCFPGA Reset Manager + +Required properties: +- compatible : "altr,rst-mgr" +- reg : Should contain 1 register ranges(address and length) +- altr,modrst-offset : Should contain the offset of the first modrst register. +- #reset-cells: 1 + +Example: + rstmgr@ffd05000 { + #reset-cells = <1>; + compatible = "altr,rst-mgr"; + reg = <0xffd05000 0x1000>; + altr,modrst-offset = <0x10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-picophyreset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-picophyreset.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ca27761f8116116cd379222c15d1503550e077f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-picophyreset.txt @@ -0,0 +1,42 @@ +STMicroelectronics STi family Sysconfig Picophy SoftReset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip PicoPHY USB2 phy(s) using "softreset" control bits found in +the STi family SoC system configuration registers. + +The actual action taken when softreset is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to Documentation/devicetree/bindings/reset/reset.txt +for common reset controller binding usage. + +Required properties: +- compatible: Should be "st,stih407-picophyreset" +- #reset-cells: 1, see below + +Example: + + picophyreset: picophyreset-controller { + compatible = "st,stih407-picophyreset"; + #reset-cells = <1>; + }; + +Specifying picophyreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the picophyreset device node and an +index specifying which channel to use, as described in +Documentation/devicetree/bindings/reset/reset.txt. + +Example: + + usb2_picophy0: usbpicophy@0 { + resets = <&picophyreset STIH407_PICOPHY0_RESET>; + }; + +Macro definitions for the supported reset channels can be found in: +include/dt-bindings/reset/stih407-resets.h diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-powerdown.txt b/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-powerdown.txt new file mode 100644 index 0000000000000000000000000000000000000000..92527138bc931b6635dbfa7cb3be2804a2f5d228 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-powerdown.txt @@ -0,0 +1,45 @@ +STMicroelectronics STi family Sysconfig Peripheral Powerdown Reset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip peripheral controllers such as USB and SATA, using +"powerdown" control bits found in the STi family SoC system configuration +registers. These have been grouped together into a single reset controller +device for convenience. + +The actual action taken when powerdown is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "st,stih407-powerdown" +- #reset-cells: 1, see below + +example: + + powerdown: powerdown-controller { + compatible = "st,stih407-powerdown"; + #reset-cells = <1>; + }; + + +Specifying powerdown control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the powerdown device node and an +index specifying which channel to use, as described in reset.txt + +example: + + st_dwc3: dwc3@8f94000 { + resets = <&powerdown STIH407_USB3_POWERDOWN>, + }; + +Macro definitions for the supported reset channels can be found in: + +include/dt-bindings/reset/stih407-resets.h diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-softreset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-softreset.txt new file mode 100644 index 0000000000000000000000000000000000000000..3661e6153a92bf8df66cea43d5f41415cc497786 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/st,sti-softreset.txt @@ -0,0 +1,44 @@ +STMicroelectronics STi family Sysconfig Peripheral SoftReset Controller +============================================================================= + +This binding describes a reset controller device that is used to enable and +disable on-chip peripheral controllers such as USB and SATA, using +"softreset" control bits found in the STi family SoC system configuration +registers. + +The actual action taken when softreset is asserted is hardware dependent. +However, when asserted it may not be possible to access the hardware's +registers and after an assert/deassert sequence the hardware's previous state +may no longer be valid. + +Please refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: Should be "st,stih407-softreset"; +- #reset-cells: 1, see below + +example: + + softreset: softreset-controller { + #reset-cells = <1>; + compatible = "st,stih407-softreset"; + }; + + +Specifying softreset control of devices +======================================= + +Device nodes should specify the reset channel required in their "resets" +property, containing a phandle to the softreset device node and an +index specifying which channel to use, as described in reset.txt + +example: + + ethernet0{ + resets = <&softreset STIH415_ETH0_SOFTRESET>; + }; + +Macro definitions for the supported reset channels can be found in: + +include/dt-bindings/reset/stih407-resets.h diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/st,stm32-rcc.txt b/arch/arm64/boot/dts/vendor/bindings/reset/st,stm32-rcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..01db34375192e64e151d68ea77805bc987885109 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/st,stm32-rcc.txt @@ -0,0 +1,6 @@ +STMicroelectronics STM32 Peripheral Reset Controller +==================================================== + +The RCC IP is both a reset and a clock controller. + +Please see Documentation/devicetree/bindings/clock/st,stm32-rcc.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/st,stm32mp1-rcc.txt b/arch/arm64/boot/dts/vendor/bindings/reset/st,stm32mp1-rcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b4edaf7c7ff3d77f11ecd4bb8645ab735a5bab6a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/st,stm32mp1-rcc.txt @@ -0,0 +1,6 @@ +STMicroelectronics STM32MP1 Peripheral Reset Controller +======================================================= + +The RCC IP is both a reset and a clock controller. + +Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/ti,sci-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/ti,sci-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b1cf022f18a2e51a4747a944d78e7bef9e18a2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/ti,sci-reset.txt @@ -0,0 +1,62 @@ +Texas Instruments System Control Interface (TI-SCI) Reset Controller +===================================================================== + +Some TI SoCs contain a system controller (like the Power Management Micro +Controller (PMMC) on Keystone 66AK2G SoC) that are responsible for controlling +the state of the various hardware modules present on the SoC. Communication +between the host processor running an OS and the system controller happens +through a protocol called TI System Control Interface (TI-SCI protocol). +For TI SCI details, please refer to the document, +Documentation/devicetree/bindings/arm/keystone/ti,sci.txt + +TI-SCI Reset Controller Node +============================ +This reset controller node uses the TI SCI protocol to perform the reset +management of various hardware modules present on the SoC. Must be a child +node of the associated TI-SCI system controller node. + +Required properties: +-------------------- + - compatible : Should be "ti,sci-reset" + - #reset-cells : Should be 2. Please see the reset consumer node below for + usage details. + +TI-SCI Reset Consumer Nodes +=========================== +Each of the reset consumer nodes should have the following properties, +in addition to their own properties. + +Required properties: +-------------------- + - resets : A phandle and reset specifier pair, one pair for each reset + signal that affects the device, or that the device manages. + The phandle should point to the TI-SCI reset controller node, + and the reset specifier should have 2 cell-values. The first + cell should contain the device ID. The second cell should + contain the reset mask value used by system controller. + Please refer to the protocol documentation for these values + to be used for different devices, + http://processors.wiki.ti.com/index.php/TISCI#66AK2G02_Data + +Please also refer to Documentation/devicetree/bindings/reset/reset.txt for +common reset controller usage by consumers. + +Example: +-------- +The following example demonstrates both a TI-SCI reset controller node and a +consumer (a DSP device) on the 66AK2G SoC. + +pmmc: pmmc { + compatible = "ti,k2g-sci"; + + k2g_reset: reset-controller { + compatible = "ti,sci-reset"; + #reset-cells = <2>; + }; +}; + +dsp0: dsp@10800000 { + ... + resets = <&k2g_reset 0x0046 0x1>; + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/ti-syscon-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/ti-syscon-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..86945502ccb509279e7d30e719a03a6c160a2038 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/ti-syscon-reset.txt @@ -0,0 +1,91 @@ +TI SysCon Reset Controller +======================= + +Almost all SoCs have hardware modules that require reset control in addition +to clock and power control for their functionality. The reset control is +typically provided by means of memory-mapped I/O registers. These registers are +sometimes a part of a larger register space region implementing various +functionalities. This register range is best represented as a syscon node to +allow multiple entities to access their relevant registers in the common +register space. + +A SysCon Reset Controller node defines a device that uses a syscon node +and provides reset management functionality for various hardware modules +present on the SoC. + +SysCon Reset Controller Node +============================ +Each of the reset provider/controller nodes should be a child of a syscon +node and have the following properties. + +Required properties: +-------------------- + - compatible : Should be, + "ti,k2e-pscrst" + "ti,k2l-pscrst" + "ti,k2hk-pscrst" + "ti,syscon-reset" + - #reset-cells : Should be 1. Please see the reset consumer node below + for usage details + - ti,reset-bits : Contains the reset control register information + Should contain 7 cells for each reset exposed to + consumers, defined as: + Cell #1 : offset of the reset assert control + register from the syscon register base + Cell #2 : bit position of the reset in the reset + assert control register + Cell #3 : offset of the reset deassert control + register from the syscon register base + Cell #4 : bit position of the reset in the reset + deassert control register + Cell #5 : offset of the reset status register + from the syscon register base + Cell #6 : bit position of the reset in the + reset status register + Cell #7 : Flags used to control reset behavior, + availible flags defined in the DT include + file + +SysCon Reset Consumer Nodes +=========================== +Each of the reset consumer nodes should have the following properties, +in addition to their own properties. + +Required properties: +-------------------- + - resets : A phandle to the reset controller node and an index number + to a reset specifier as defined above. + +Please also refer to Documentation/devicetree/bindings/reset/reset.txt for +common reset controller usage by consumers. + +Example: +-------- +The following example demonstrates a syscon node, the reset controller node +using the syscon node, and a consumer (a DSP device) on the TI Keystone 2 +66AK2E SoC. + +/ { + soc { + psc: power-sleep-controller@2350000 { + compatible = "syscon", "simple-mfd"; + reg = <0x02350000 0x1000>; + + pscrst: reset-controller { + compatible = "ti,k2e-pscrst", "ti,syscon-reset"; + #reset-cells = <1>; + + ti,reset-bits = < + 0xa3c 8 0xa3c 8 0x83c 8 (ASSERT_CLEAR | DEASSERT_SET | STATUS_CLEAR) /* 0: dsp0 */ + 0xa40 5 0xa44 3 0 0 (ASSERT_SET | DEASSERT_CLEAR | STATUS_NONE) /* 1: example */ + >; + }; + }; + + dsp0: dsp0 { + ... + resets = <&pscrst 0>; + ... + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/uniphier-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/uniphier-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..101743dda2235766b19564061a66282a35d02e0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/uniphier-reset.txt @@ -0,0 +1,176 @@ +UniPhier reset controller + + +System reset +------------ + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-reset" - for LD4 SoC + "socionext,uniphier-pro4-reset" - for Pro4 SoC + "socionext,uniphier-sld8-reset" - for sLD8 SoC + "socionext,uniphier-pro5-reset" - for Pro5 SoC + "socionext,uniphier-pxs2-reset" - for PXs2/LD6b SoC + "socionext,uniphier-ld11-reset" - for LD11 SoC + "socionext,uniphier-ld20-reset" - for LD20 SoC + "socionext,uniphier-pxs3-reset" - for PXs3 SoC +- #reset-cells: should be 1. + +Example: + + sysctrl@61840000 { + compatible = "socionext,uniphier-ld11-sysctrl", + "simple-mfd", "syscon"; + reg = <0x61840000 0x4000>; + + reset { + compatible = "socionext,uniphier-ld11-reset"; + #reset-cells = <1>; + }; + + other nodes ... + }; + + +Media I/O (MIO) reset, SD reset +------------------------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-mio-reset" - for LD4 SoC + "socionext,uniphier-pro4-mio-reset" - for Pro4 SoC + "socionext,uniphier-sld8-mio-reset" - for sLD8 SoC + "socionext,uniphier-pro5-sd-reset" - for Pro5 SoC + "socionext,uniphier-pxs2-sd-reset" - for PXs2/LD6b SoC + "socionext,uniphier-ld11-mio-reset" - for LD11 SoC (MIO) + "socionext,uniphier-ld11-sd-reset" - for LD11 SoC (SD) + "socionext,uniphier-ld20-sd-reset" - for LD20 SoC + "socionext,uniphier-pxs3-sd-reset" - for PXs3 SoC +- #reset-cells: should be 1. + +Example: + + mioctrl@59810000 { + compatible = "socionext,uniphier-ld11-mioctrl", + "simple-mfd", "syscon"; + reg = <0x59810000 0x800>; + + reset { + compatible = "socionext,uniphier-ld11-mio-reset"; + #reset-cells = <1>; + }; + + other nodes ... + }; + + +Peripheral reset +---------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld4-peri-reset" - for LD4 SoC + "socionext,uniphier-pro4-peri-reset" - for Pro4 SoC + "socionext,uniphier-sld8-peri-reset" - for sLD8 SoC + "socionext,uniphier-pro5-peri-reset" - for Pro5 SoC + "socionext,uniphier-pxs2-peri-reset" - for PXs2/LD6b SoC + "socionext,uniphier-ld11-peri-reset" - for LD11 SoC + "socionext,uniphier-ld20-peri-reset" - for LD20 SoC + "socionext,uniphier-pxs3-peri-reset" - for PXs3 SoC +- #reset-cells: should be 1. + +Example: + + perictrl@59820000 { + compatible = "socionext,uniphier-ld11-perictrl", + "simple-mfd", "syscon"; + reg = <0x59820000 0x200>; + + reset { + compatible = "socionext,uniphier-ld11-peri-reset"; + #reset-cells = <1>; + }; + + other nodes ... + }; + + +Analog signal amplifier reset +----------------------------- + +Required properties: +- compatible: should be one of the following: + "socionext,uniphier-ld11-adamv-reset" - for LD11 SoC + "socionext,uniphier-ld20-adamv-reset" - for LD20 SoC +- #reset-cells: should be 1. + +Example: + + adamv@57920000 { + compatible = "socionext,uniphier-ld11-adamv", + "simple-mfd", "syscon"; + reg = <0x57920000 0x1000>; + + adamv_rst: reset { + compatible = "socionext,uniphier-ld11-adamv-reset"; + #reset-cells = <1>; + }; + + other nodes ... + }; + + +USB3 core reset +--------------- + +USB3 core reset belongs to USB3 glue layer. Before using the core reset, +it is necessary to control the clocks and resets to enable this layer. +These clocks and resets should be described in each property. + +Required properties: +- compatible: Should be + "socionext,uniphier-pro4-usb3-reset" - for Pro4 SoC + "socionext,uniphier-pxs2-usb3-reset" - for PXs2 SoC + "socionext,uniphier-ld20-usb3-reset" - for LD20 SoC + "socionext,uniphier-pxs3-usb3-reset" - for PXs3 SoC +- #reset-cells: Should be 1. +- reg: Specifies offset and length of the register set for the device. +- clocks: A list of phandles to the clock gate for USB3 glue layer. + According to the clock-names, appropriate clocks are required. +- clock-names: Should contain + "gio", "link" - for Pro4 SoC + "link" - for others +- resets: A list of phandles to the reset control for USB3 glue layer. + According to the reset-names, appropriate resets are required. +- reset-names: Should contain + "gio", "link" - for Pro4 SoC + "link" - for others + +Example: + + usb-glue@65b00000 { + compatible = "socionext,uniphier-ld20-dwc3-glue", + "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x65b00000 0x400>; + + usb_rst: reset@0 { + compatible = "socionext,uniphier-ld20-usb3-reset"; + reg = <0x0 0x4>; + #reset-cells = <1>; + clock-names = "link"; + clocks = <&sys_clk 14>; + reset-names = "link"; + resets = <&sys_rst 14>; + }; + + regulator { + ... + }; + + phy { + ... + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/zte,zx2967-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/zte,zx2967-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..b015508f978015b0395ac33e7b60dd552b394283 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/zte,zx2967-reset.txt @@ -0,0 +1,20 @@ +ZTE zx2967 SoCs Reset Controller +======================================= + +Please also refer to reset.txt in this directory for common reset +controller binding usage. + +Required properties: +- compatible: should be one of the following. + * zte,zx296718-reset +- reg: physical base address of the controller and length of memory mapped + region. +- #reset-cells: must be 1. + +example: + + reset: reset-controller@1461060 { + compatible = "zte,zx296718-reset"; + reg = <0x01461060 0x8>; + #reset-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/reset/zynq-reset.txt b/arch/arm64/boot/dts/vendor/bindings/reset/zynq-reset.txt new file mode 100644 index 0000000000000000000000000000000000000000..5860120e30640436bc14e23b18cba9eafc3e37f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/reset/zynq-reset.txt @@ -0,0 +1,68 @@ +Xilinx Zynq Reset Manager + +The Zynq AP-SoC has several different resets. + +See Chapter 26 of the Zynq TRM (UG585) for more information about Zynq resets. + +Required properties: +- compatible: "xlnx,zynq-reset" +- reg: SLCR offset and size taken via syscon <0x200 0x48> +- syscon: <&slcr> + This should be a phandle to the Zynq's SLCR registers. +- #reset-cells: Must be 1 + +The Zynq Reset Manager needs to be a childnode of the SLCR. + +Example: + rstc: rstc@200 { + compatible = "xlnx,zynq-reset"; + reg = <0x200 0x48>; + #reset-cells = <1>; + syscon = <&slcr>; + }; + +Reset outputs: + 0 : soft reset + 32 : ddr reset + 64 : topsw reset + 96 : dmac reset + 128: usb0 reset + 129: usb1 reset + 160: gem0 reset + 161: gem1 reset + 164: gem0 rx reset + 165: gem1 rx reset + 166: gem0 ref reset + 167: gem1 ref reset + 192: sdio0 reset + 193: sdio1 reset + 196: sdio0 ref reset + 197: sdio1 ref reset + 224: spi0 reset + 225: spi1 reset + 226: spi0 ref reset + 227: spi1 ref reset + 256: can0 reset + 257: can1 reset + 258: can0 ref reset + 259: can1 ref reset + 288: i2c0 reset + 289: i2c1 reset + 320: uart0 reset + 321: uart1 reset + 322: uart0 ref reset + 323: uart1 ref reset + 352: gpio reset + 384: lqspi reset + 385: qspi ref reset + 416: smc reset + 417: smc ref reset + 448: ocm reset + 512: fpga0 out reset + 513: fpga1 out reset + 514: fpga2 out reset + 515: fpga3 out reset + 544: a9 reset 0 + 545: a9 reset 1 + 552: peri reset + diff --git a/arch/arm64/boot/dts/vendor/bindings/resource-names.txt b/arch/arm64/boot/dts/vendor/bindings/resource-names.txt new file mode 100644 index 0000000000000000000000000000000000000000..e280fef6f2654f5b363ca346da54eedd07a85769 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/resource-names.txt @@ -0,0 +1,54 @@ +Some properties contain an ordered list of 1 or more datum which are +normally accessed by index. However, some devices will have multiple +values which are more naturally accessed by name. Device nodes can +include a supplemental property for assigning names to each of the list +items. The names property consists of a list of strings in the same +order as the data in the resource property. + +The following supplemental names properties are defined. + +Resource Property Supplemental Names Property +----------------- --------------------------- +reg reg-names +clocks clock-names +interrupts interrupt-names + +Usage: + +The -names property must be used in conjunction with the normal resource +property. If not it will be ignored. + +Examples: + +l4-abe { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0x48000000 0x00001000>, /* MPU path */ + <1 0 0x49000000 0x00001000>; /* L3 path */ + mcasp { + compatible = "ti,mcasp"; + reg = <0 0x10 0x10>, <0 0x20 0x10>, + <1 0x10 0x10>, <1 0x20 0x10>; + reg-names = "mpu", "dat", + "dma", "dma_dat"; + interrupts = <11>, <12>; + interrupt-names = "rx", "tx"; + }; + + timer { + compatible = "ti,timer"; + reg = <0 0x40 0x10>, <1 0x40 0x10>; + reg-names = "mpu", "dma"; + }; +}; + + +usb { + compatible = "ti,usb-host"; + reg = <0x4a064000 0x800>, <0x4a064800 0x200>, + <0x4a064c00 0x200>; + reg-names = "config", "ohci", "ehci"; + interrupts = <14>, <15>; + interrupt-names = "ohci", "ehci"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/riscv/cpus.txt b/arch/arm64/boot/dts/vendor/bindings/riscv/cpus.txt new file mode 100644 index 0000000000000000000000000000000000000000..adf7b7af5dc35532c488398c28ccb14b4237b0ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/riscv/cpus.txt @@ -0,0 +1,162 @@ +=================== +RISC-V CPU Bindings +=================== + +The device tree allows to describe the layout of CPUs in a system through +the "cpus" node, which in turn contains a number of subnodes (ie "cpu") +defining properties for every cpu. + +Bindings for CPU nodes follow the Devicetree Specification, available from: + +https://www.devicetree.org/specifications/ + +with updates for 32-bit and 64-bit RISC-V systems provided in this document. + +=========== +Terminology +=========== + +This document uses some terminology common to the RISC-V community that is not +widely used, the definitions of which are listed here: + +* hart: A hardware execution context, which contains all the state mandated by + the RISC-V ISA: a PC and some registers. This terminology is designed to + disambiguate software's view of execution contexts from any particular + microarchitectural implementation strategy. For example, my Intel laptop is + described as having one socket with two cores, each of which has two hyper + threads. Therefore this system has four harts. + +===================================== +cpus and cpu node bindings definition +===================================== + +The RISC-V architecture, in accordance with the Devicetree Specification, +requires the cpus and cpu nodes to be present and contain the properties +described below. + +- cpus node + + Description: Container of cpu nodes + + The node name must be "cpus". + + A cpus node must define the following properties: + + - #address-cells + Usage: required + Value type: + Definition: must be set to 1 + - #size-cells + Usage: required + Value type: + Definition: must be set to 0 + +- cpu node + + Description: Describes a hart context + + PROPERTIES + + - device_type + Usage: required + Value type: + Definition: must be "cpu" + - reg + Usage: required + Value type: + Definition: The hart ID of this CPU node + - compatible: + Usage: required + Value type: + Definition: must contain "riscv", may contain one of + "sifive,rocket0" + - mmu-type: + Usage: optional + Value type: + Definition: Specifies the CPU's MMU type. Possible values are + "riscv,sv32" + "riscv,sv39" + "riscv,sv48" + - riscv,isa: + Usage: required + Value type: + Definition: Contains the RISC-V ISA string of this hart. These + ISA strings are defined by the RISC-V ISA manual. + +Example: SiFive Freedom U540G Development Kit +--------------------------------------------- + +This system contains two harts: a hart marked as disabled that's used for +low-level system tasks and should be ignored by Linux, and a second hart that +Linux is allowed to run on. + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <1000000>; + cpu@0 { + clock-frequency = <1600000000>; + compatible = "sifive,rocket0", "riscv"; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <16384>; + next-level-cache = <&L15 &L0>; + reg = <0>; + riscv,isa = "rv64imac"; + status = "disabled"; + L10: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + cpu@1 { + clock-frequency = <1600000000>; + compatible = "sifive,rocket0", "riscv"; + d-cache-block-size = <64>; + d-cache-sets = <64>; + d-cache-size = <32768>; + d-tlb-sets = <1>; + d-tlb-size = <32>; + device_type = "cpu"; + i-cache-block-size = <64>; + i-cache-sets = <64>; + i-cache-size = <32768>; + i-tlb-sets = <1>; + i-tlb-size = <32>; + mmu-type = "riscv,sv39"; + next-level-cache = <&L15 &L0>; + reg = <1>; + riscv,isa = "rv64imafdc"; + status = "okay"; + tlb-split; + L13: interrupt-controller { + #interrupt-cells = <1>; + compatible = "riscv,cpu-intc"; + interrupt-controller; + }; + }; + }; + +Example: Spike ISA Simulator with 1 Hart +---------------------------------------- + +This device tree matches the Spike ISA golden model as run with `spike -p1`. + + cpus { + cpu@0 { + device_type = "cpu"; + reg = <0x00000000>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdc"; + mmu-type = "riscv,sv48"; + clock-frequency = <0x3b9aca00>; + interrupt-controller { + #interrupt-cells = <0x00000001>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + } + } + } diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/amlogic,meson-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/amlogic,meson-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d403645ac9b3dcd513c5f55a7217542a1eb1d37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/amlogic,meson-rng.txt @@ -0,0 +1,21 @@ +Amlogic Meson Random number generator +===================================== + +Required properties: + +- compatible : should be "amlogic,meson-rng" +- reg : Specifies base physical address and size of the registers. + +Optional properties: + +- clocks : phandle to the following named clocks +- clock-names: Name of core clock, must be "core" + +Example: + +rng { + compatible = "amlogic,meson-rng"; + reg = <0x0 0xc8834000 0x0 0x4>; + clocks = <&clkc CLKID_RNG0>; + clock-names = "core"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/apm,rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/apm,rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dde4b06cdd9edf72e8554a03bc979ac3e4bf2d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/apm,rng.txt @@ -0,0 +1,17 @@ +APM X-Gene SoC random number generator. + +Required properties: + +- compatible : should be "apm,xgene-rng" +- reg : specifies base physical address and size of the registers map +- clocks : phandle to clock-controller plus clock-specifier pair +- interrupts : specify the fault interrupt for the RNG device + +Example: + + rng: rng@10520000 { + compatible = "apm,xgene-rng"; + reg = <0x0 0x10520000 0x0 0x100>; + interrupts = <0x0 0x41 0x4>; + clocks = <&rngpkaclk 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/atmel-trng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/atmel-trng.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ac5aaa2d024147e5cb88c812a6b92f710b0b6a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/atmel-trng.txt @@ -0,0 +1,16 @@ +Atmel TRNG (True Random Number Generator) block + +Required properties: +- compatible : Should be "atmel,at91sam9g45-trng" +- reg : Offset and length of the register set of this block +- interrupts : the interrupt number for the TRNG block +- clocks: should contain the TRNG clk source + +Example: + +trng@fffcc000 { + compatible = "atmel,at91sam9g45-trng"; + reg = <0xfffcc000 0x4000>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&trng_clk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/brcm,bcm2835.txt b/arch/arm64/boot/dts/vendor/bindings/rng/brcm,bcm2835.txt new file mode 100644 index 0000000000000000000000000000000000000000..aaac7975f61c7b6f6cb8736a8362272e40dd8464 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/brcm,bcm2835.txt @@ -0,0 +1,40 @@ +BCM2835/6368 Random number generator + +Required properties: + +- compatible : should be one of + "brcm,bcm2835-rng" + "brcm,bcm-nsp-rng" + "brcm,bcm5301x-rng" or + "brcm,bcm6368-rng" +- reg : Specifies base physical address and size of the registers. + +Optional properties: + +- clocks : phandle to clock-controller plus clock-specifier pair +- clock-names : "ipsec" as a clock name + +Optional properties: + +- interrupts: specify the interrupt for the RNG block + +Example: + +rng { + compatible = "brcm,bcm2835-rng"; + reg = <0x7e104000 0x10>; + interrupts = <2 29>; +}; + +rng@18033000 { + compatible = "brcm,bcm-nsp-rng"; + reg = <0x18033000 0x14>; +}; + +random: rng@10004180 { + compatible = "brcm,bcm6368-rng"; + reg = <0x10004180 0x14>; + + clocks = <&periph_clk 18>; + clock-names = "ipsec"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/brcm,iproc-rng200.txt b/arch/arm64/boot/dts/vendor/bindings/rng/brcm,iproc-rng200.txt new file mode 100644 index 0000000000000000000000000000000000000000..0014da9145af73f64218dd5f335863421474ca22 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/brcm,iproc-rng200.txt @@ -0,0 +1,14 @@ +HWRNG support for the iproc-rng200 driver + +Required properties: +- compatible : Must be one of: + "brcm,bcm7278-rng200" + "brcm,iproc-rng200" +- reg : base address and size of control register block + +Example: + +rng { + compatible = "brcm,iproc-rng200"; + reg = <0x18032000 0x28>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/hisi-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/hisi-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..d04d55a6c2f591ac1b33069b4bc8e24294da69b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/hisi-rng.txt @@ -0,0 +1,12 @@ +Hisilicon Random Number Generator + +Required properties: +- compatible : Should be "hisilicon,hip04-rng" or "hisilicon,hip05-rng" +- reg : Offset and length of the register set of this block + +Example: + +rng@d1010000 { + compatible = "hisilicon,hip05-rng"; + reg = <0xd1010000 0x100>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/imx-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/imx-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..405c2b00ccb0a420155505fb10bee74bf8c94a2e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/imx-rng.txt @@ -0,0 +1,20 @@ +Freescale RNGA/RNGB/RNGC (Random Number Generator Versions A, B and C) + +Required properties: +- compatible : should be one of + "fsl,imx21-rnga" + "fsl,imx31-rnga" (backward compatible with "fsl,imx21-rnga") + "fsl,imx25-rngb" + "fsl,imx35-rngc" +- reg : offset and length of the register set of this block +- interrupts : the interrupt number for the RNG block +- clocks : the RNG clk source + +Example: + +rng@53fb0000 { + compatible = "fsl,imx25-rngb"; + reg = <0x53fb0000 0x4000>; + interrupts = <22>; + clocks = <&trng_clk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/ks-sa-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/ks-sa-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7a65b48790158b0fc192ff2477fb326b555fd94 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/ks-sa-rng.txt @@ -0,0 +1,21 @@ +Keystone SoC Hardware Random Number Generator(HWRNG) Module + +On Keystone SoCs HWRNG module is a submodule of the Security Accelerator. + +- compatible: should be "ti,keystone-rng" +- ti,syscon-sa-cfg: phandle to syscon node of the SA configuration registers. + This registers are shared between hwrng and crypto drivers. +- clocks: phandle to the reference clocks for the subsystem +- clock-names: functional clock name. Should be set to "fck" +- reg: HWRNG module register space + +Example: +/* K2HK */ + +rng@24000 { + compatible = "ti,keystone-rng"; + ti,syscon-sa-cfg = <&sa_config>; + clocks = <&clksa>; + clock-names = "fck"; + reg = <0x24000 0x1000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/microchip,pic32-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/microchip,pic32-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6d1003befb772375c36b04b82da008d5ee1a603 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/microchip,pic32-rng.txt @@ -0,0 +1,17 @@ +* Microchip PIC32 Random Number Generator + +The PIC32 RNG provides a pseudo random number generator which can be seeded by +another true random number generator. + +Required properties: +- compatible : should be "microchip,pic32mzda-rng" +- reg : Specifies base physical address and size of the registers. +- clocks: clock phandle. + +Example: + + rng: rng@1f8e6000 { + compatible = "microchip,pic32mzda-rng"; + reg = <0x1f8e6000 0x1000>; + clocks = <&PBCLK5>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/mtk-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/mtk-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..366b99bff8cd472e850c2e1d806992ab3a7d6f9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/mtk-rng.txt @@ -0,0 +1,20 @@ +Device-Tree bindings for Mediatek random number generator +found in Mediatek SoC family + +Required properties: +- compatible : Should be + "mediatek,mt7622-rng", "mediatek,mt7623-rng" : for MT7622 + "mediatek,mt7623-rng" : for MT7623 +- clocks : list of clock specifiers, corresponding to + entries in clock-names property; +- clock-names : Should contain "rng" entries; +- reg : Specifies base physical address and size of the registers + +Example: + +rng: rng@1020f000 { + compatible = "mediatek,mt7623-rng"; + reg = <0 0x1020f000 0 0x1000>; + clocks = <&infracfg CLK_INFRA_TRNG>; + clock-names = "rng"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/omap_rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/omap_rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea434ce50f36fad854429933566ae82a50d42737 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/omap_rng.txt @@ -0,0 +1,38 @@ +OMAP SoC and Inside-Secure HWRNG Module + +Required properties: + +- compatible : Should contain entries for this and backward compatible + RNG versions: + - "ti,omap2-rng" for OMAP2. + - "ti,omap4-rng" for OMAP4, OMAP5 and AM33XX. + - "inside-secure,safexcel-eip76" for SoCs with EIP76 IP block + Note that these two versions are incompatible. +- ti,hwmods: Name of the hwmod associated with the RNG module +- reg : Offset and length of the register set for the module +- interrupts : the interrupt number for the RNG module. + Used for "ti,omap4-rng" and "inside-secure,safexcel-eip76" +- clocks: the trng clock source. Only mandatory for the + "inside-secure,safexcel-eip76" compatible, the second clock is + needed for the Armada 7K/8K SoCs +- clock-names: mandatory if there is a second clock, in this case the + name must be "core" for the first clock and "reg" for the second + one + + +Example: +/* AM335x */ +rng: rng@48310000 { + compatible = "ti,omap4-rng"; + ti,hwmods = "rng"; + reg = <0x48310000 0x2000>; + interrupts = <111>; +}; + +/* SafeXcel IP-76 */ +trng: rng@f2760000 { + compatible = "inside-secure,safexcel-eip76"; + reg = <0xf2760000 0x7d>; + interrupts = ; + clocks = <&cpm_syscon0 1 25>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/samsung,exynos4-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/samsung,exynos4-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..a13fbdb4bd88d9030a2183048e223dc08e7e6ea4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/samsung,exynos4-rng.txt @@ -0,0 +1,19 @@ +Exynos Pseudo Random Number Generator + +Required properties: + +- compatible : One of: + - "samsung,exynos4-rng" for Exynos4210 and Exynos4412 + - "samsung,exynos5250-prng" for Exynos5250+ +- reg : Specifies base physical address and size of the registers map. +- clocks : Phandle to clock-controller plus clock-specifier pair. +- clock-names : "secss" as a clock name. + +Example: + + rng@10830400 { + compatible = "samsung,exynos4-rng"; + reg = <0x10830400 0x200>; + clocks = <&clock CLK_SSS>; + clock-names = "secss"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/sparc_sun_oracle_rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/sparc_sun_oracle_rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..b0b211194c714806480c02ba270adb84fea054d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/sparc_sun_oracle_rng.txt @@ -0,0 +1,30 @@ +HWRNG support for the n2_rng driver + +Required properties: +- reg : base address to sample from +- compatible : should contain one of the following + RNG versions: + - 'SUNW,n2-rng' for Niagara 2 Platform (SUN UltraSPARC T2 CPU) + - 'SUNW,vf-rng' for Victoria Falls Platform (SUN UltraSPARC T2 Plus CPU) + - 'SUNW,kt-rng' for Rainbow/Yosemite Falls Platform (SUN SPARC T3/T4), (UltraSPARC KT/Niagara 3 - development names) + more recent systems (after Oracle acquisition of SUN) + - 'ORCL,m4-rng' for SPARC T5/M5 + - 'ORCL,m7-rng' for SPARC T7/M7 + +Examples: +/* linux LDOM on SPARC T5-2 */ +Node 0xf029a4f4 + .node: f029a4f4 + rng-#units: 00000002 + compatible: 'ORCL,m4-rng' + reg: 0000000e + name: 'random-number-generator' + +/* solaris on SPARC M7-8 */ +Node 0xf028c08c + rng-#units: 00000003 + compatible: 'ORCL,m7-rng' + reg: 0000000e + name: 'random-number-generator' + +PS: see as well prtconfs.git by DaveM diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/st,rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/st,rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..35734bc282e95ac3bffe63e0bc4afea995dda859 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/st,rng.txt @@ -0,0 +1,15 @@ +STMicroelectronics HW Random Number Generator +---------------------------------------------- + +Required parameters: +compatible : Should be "st,rng" +reg : Base address and size of IP's register map. +clocks : Phandle to device's clock (See: ../clocks/clock-bindings.txt) + +Example: + +rng@fee80000 { + compatible = "st,rng"; + reg = <0xfee80000 0x1000>; + clocks = <&clk_sysin>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/st,stm32-rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/st,stm32-rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..1dfa7d51e006d755ad82af526b8fe67a82491e96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/st,stm32-rng.txt @@ -0,0 +1,25 @@ +STMicroelectronics STM32 HW RNG +=============================== + +The STM32 hardware random number generator is a simple fixed purpose IP and +is fully separated from other crypto functions. + +Required properties: + +- compatible : Should be "st,stm32-rng" +- reg : Should be register base and length as documented in the datasheet +- interrupts : The designated IRQ line for the RNG +- clocks : The clock needed to enable the RNG + +Optional properties: +- resets : The reset to properly start RNG +- clock-error-detect : Enable the clock detection management + +Example: + + rng: rng@50060800 { + compatible = "st,stm32-rng"; + reg = <0x50060800 0x400>; + interrupts = <80>; + clocks = <&rcc 0 38>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rng/timeriomem_rng.txt b/arch/arm64/boot/dts/vendor/bindings/rng/timeriomem_rng.txt new file mode 100644 index 0000000000000000000000000000000000000000..214940093b550cc9c756fc72c0201921a3f1b31f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rng/timeriomem_rng.txt @@ -0,0 +1,25 @@ +HWRNG support for the timeriomem_rng driver + +Required properties: +- compatible : "timeriomem_rng" +- reg : base address to sample from +- period : wait time in microseconds to use between samples + +Optional properties: +- quality : estimated number of bits of true entropy per 1024 bits read from the + rng. Defaults to zero which causes the kernel's default quality to + be used instead. Note that the default quality is usually zero + which disables using this rng to automatically fill the kernel's + entropy pool. + +N.B. currently 'reg' must be four bytes wide and aligned + +Example: + +hwrng@44 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "timeriomem_rng"; + reg = <0x44 0x04>; + period = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/abracon,abx80x.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/abracon,abx80x.txt new file mode 100644 index 0000000000000000000000000000000000000000..be789685a1c24256e8b9846121ccb407d9f39e94 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/abracon,abx80x.txt @@ -0,0 +1,30 @@ +Abracon ABX80X I2C ultra low power RTC/Alarm chip + +The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801, +ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805 +is the superset of ab180x. + +Required properties: + + - "compatible": should one of: + "abracon,abx80x" + "abracon,ab0801" + "abracon,ab0803" + "abracon,ab0804" + "abracon,ab0805" + "abracon,ab1801" + "abracon,ab1803" + "abracon,ab1804" + "abracon,ab1805" + Using "abracon,abx80x" will enable chip autodetection. + - "reg": I2C bus address of the device + +Optional properties: + +The abx804 and abx805 have a trickle charger that is able to charge the +connected battery or supercap. Both the following properties have to be defined +and valid to enable charging: + + - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V) + - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output + resistor, the other values are in ohm. diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/alphascale,asm9260-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/alphascale,asm9260-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..76ebca568db9eb2bb5a6b9302fab68cdf6f9d875 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/alphascale,asm9260-rtc.txt @@ -0,0 +1,19 @@ +* Alphascale asm9260 SoC Real Time Clock + +Required properties: +- compatible: Should be "alphascale,asm9260-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ line for the RTC. +- clocks: Reference to the clock entry. +- clock-names: should contain: + * "ahb" for the SoC RTC clock + +Example: +rtc0: rtc@800a0000 { + compatible = "alphascale,asm9260-rtc"; + reg = <0x800a0000 0x100>; + clocks = <&acc CLKID_AHB_RTC>; + clock-names = "ahb"; + interrupts = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/armada-380-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/armada-380-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3c9a1226f9aa622702d590f593618506509b3b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/armada-380-rtc.txt @@ -0,0 +1,24 @@ +* Real Time Clock of the Armada 38x/7K/8K SoCs + +RTC controller for the Armada 38x, 7K and 8K SoCs + +Required properties: +- compatible : Should be one of the following: + "marvell,armada-380-rtc" for Armada 38x SoC + "marvell,armada-8k-rtc" for Aramda 7K/8K SoCs +- reg: a list of base address and size pairs, one for each entry in + reg-names +- reg names: should contain: + * "rtc" for the RTC registers + * "rtc-soc" for the SoC related registers and among them the one + related to the interrupt. +- interrupts: IRQ line for the RTC. + +Example: + +rtc@a3800 { + compatible = "marvell,armada-380-rtc"; + reg = <0xa3800 0x20>, <0x184a0 0x0c>; + reg-names = "rtc", "rtc-soc"; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/atmel,at91rm9200-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/atmel,at91rm9200-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d3791e789c6ba6ca04f9f17dda5f3c9aeafe83c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/atmel,at91rm9200-rtc.txt @@ -0,0 +1,17 @@ +Atmel AT91RM9200 Real Time Clock + +Required properties: +- compatible: should be: "atmel,at91rm9200-rtc" or "atmel,at91sam9x5-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: rtc alarm/event interrupt +- clocks: phandle to input clock. + +Example: + +rtc@fffffe00 { + compatible = "atmel,at91rm9200-rtc"; + reg = <0xfffffe00 0x100>; + interrupts = <1 4 7>; + clocks = <&clk32k>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/atmel,at91sam9-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/atmel,at91sam9-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ae79d1843f3b81b9dc0d3e1cb4d12b9c33787c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/atmel,at91sam9-rtc.txt @@ -0,0 +1,23 @@ +Atmel AT91SAM9260 Real Time Timer + +Required properties: +- compatible: should be: "atmel,at91sam9260-rtt" +- reg: should encode the memory region of the RTT controller +- interrupts: rtt alarm/event interrupt +- clocks: should contain the 32 KHz slow clk that will drive the RTT block. +- atmel,rtt-rtc-time-reg: should encode the GPBR register used to store + the time base when the RTT is used as an RTC. + The first cell should point to the GPBR node and the second one + encode the offset within the GPBR block (or in other words, the + GPBR register used to store the time base). + + +Example: + +rtt@fffffd20 { + compatible = "atmel,at91sam9260-rtt"; + reg = <0xfffffd20 0x10>; + interrupts = <1 4 7>; + clocks = <&clk32k>; + atmel,rtt-rtc-time-reg = <&gpbr 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/brcm,brcmstb-waketimer.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/brcm,brcmstb-waketimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..d946f28502b32770b5cc66bfa6984c32f5e6e533 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/brcm,brcmstb-waketimer.txt @@ -0,0 +1,20 @@ +Broadcom STB wake-up Timer + +The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the +ability to wake up the system from low-power suspend/standby modes. + +Required properties: +- compatible : should contain "brcm,brcmstb-waketimer" +- reg : the register start and length for the WKTMR block +- interrupts : The TIMER interrupt +- clocks : The phandle to the UPG fixed clock (27Mhz domain) + +Example: + +waketimer@f0411580 { + compatible = "brcm,brcmstb-waketimer"; + reg = <0xf0411580 0x14>; + interrupts = <0x3>; + interrupt-parent = <&aon_pm_l2_intc>; + clocks = <&upg_fixed>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/cpcap-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/cpcap-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..45750ff3112d26448506fdf1aa3f239cfe9f3f3c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/cpcap-rtc.txt @@ -0,0 +1,18 @@ +Motorola CPCAP PMIC RTC +----------------------- + +This module is part of the CPCAP. For more details about the whole +chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt. + +Requires node properties: +- compatible: should contain "motorola,cpcap-rtc" +- interrupts: An interrupt specifier for alarm and 1 Hz irq + +Example: + +&cpcap { + cpcap_rtc: rtc { + compatible = "motorola,cpcap-rtc"; + interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/dallas,ds1390.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/dallas,ds1390.txt new file mode 100644 index 0000000000000000000000000000000000000000..9882b819f173f3277e55b73cbbcffa4b89f4e1cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/dallas,ds1390.txt @@ -0,0 +1,18 @@ +* Dallas DS1390 SPI Serial Real-Time Clock + +Required properties: +- compatible: Should contain "dallas,ds1390". +- reg: SPI address for chip + +Optional properties: +- trickle-resistor-ohms : Selected resistor for trickle charger + Values usable for ds1390 are 250, 2000, 4000 + Should be given if trickle charger should be enabled +- trickle-diode-disable : Do not use internal trickle charger diode + Should be given if internal trickle charger diode should be disabled +Example: + ds1390: rtc@0 { + compatible = "dallas,ds1390"; + trickle-resistor-ohms = <250>; + reg = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/digicolor-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/digicolor-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d464986012cd98e6cd8a9bc4c2a8e9066e58b223 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/digicolor-rtc.txt @@ -0,0 +1,17 @@ +Conexant Digicolor Real Time Clock controller + +This binding currently supports the CX92755 SoC. + +Required properties: +- compatible: should be "cnxt,cx92755-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: rtc alarm interrupt + +Example: + + rtc@f0000c30 { + compatible = "cnxt,cx92755-rtc"; + reg = <0xf0000c30 0x18>; + interrupts = <25>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/dw-apb.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/dw-apb.txt new file mode 100644 index 0000000000000000000000000000000000000000..c703d51abb6c08f96a80a897b104f21e0d649893 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/dw-apb.txt @@ -0,0 +1,32 @@ +* Designware APB timer + +Required properties: +- compatible: One of: + "snps,dw-apb-timer" + "snps,dw-apb-timer-sp" + "snps,dw-apb-timer-osc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: IRQ line for the timer. +- either clocks+clock-names or clock-frequency properties + +Optional properties: +- clocks : list of clock specifiers, corresponding to entries in + the clock-names property; +- clock-names : should contain "timer" and "pclk" entries, matching entries + in the clocks property. +- clock-frequency: The frequency in HZ of the timer. +- clock-freq: For backwards compatibility with picoxcell + +If using the clock specifiers, the pclk clock is optional, as not all +systems may use one. + + +Example: + timer@ffe00000 { + compatible = "snps,dw-apb-timer"; + interrupts = <0 170 4>; + reg = <0xffe00000 0x1000>; + clocks = <&timer_clk>, <&timer_pclk>; + clock-names = "timer", "pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rtc7301.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rtc7301.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f9df3f1467cbb968859a639794d27cf7b845668 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rtc7301.txt @@ -0,0 +1,16 @@ +EPSON TOYOCOM RTC-7301SF/DG + +Required properties: + +- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg" +- reg: Specifies base physical address and size of the registers. +- interrupts: A single interrupt specifier. + +Example: + +rtc: rtc@44a00000 { + compatible = "epson,rtc7301dg"; + reg = <0x44a00000 0x10000>; + interrupt-parent = <&axi_intc_0>; + interrupts = <3 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rx6110.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rx6110.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dc313e01f77e1ab20ee991e437e8506997d0d8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rx6110.txt @@ -0,0 +1,39 @@ +Epson RX6110 Real Time Clock +============================ + +The Epson RX6110 can be used with SPI or I2C busses. The kind of +bus depends on the SPISEL pin and can not be configured via software. + +I2C mode +-------- + +Required properties: + - compatible: should be: "epson,rx6110" + - reg : the I2C address of the device for I2C + +Example: + + rtc: rtc@32 { + compatible = "epson,rx6110" + reg = <0x32>; + }; + +SPI mode +-------- + +Required properties: + - compatible: should be: "epson,rx6110" + - reg: chip select number + - spi-cs-high: RX6110 needs chipselect high + - spi-cpha: RX6110 works with SPI shifted clock phase + - spi-cpol: RX6110 works with SPI inverse clock polarity + +Example: + + rtc: rtc@3 { + compatible = "epson,rx6110" + reg = <3> + spi-cs-high; + spi-cpha; + spi-cpol; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rx8900.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rx8900.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f61e516ecf68808352317735bbfee5fc8f4df82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/epson,rx8900.txt @@ -0,0 +1,22 @@ +Real Time Clock driver for: + - Epson RX8900 + - Micro Crystal rv8803 + +Required properties: +- compatible: should be: "microcrystal,rv8803" or "epson,rx8900" +- reg : the I2C address of the device for I2C + +Optional properties: +- epson,vdet-disable : boolean, if present will disable voltage detector. + Should be set if no backup battery is used. +- trickle-diode-disable : boolean, if present will disable internal trickle + charger diode + +Example: + + rtc: rtc@32 { + compatible = "epson,rx8900" + reg = <0x32>; + epson,vdet-disable; + trickle-diode-disable; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/faraday,ftrtc010.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/faraday,ftrtc010.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3938f5e0b6c210cf6368d1731d07118f01948f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/faraday,ftrtc010.txt @@ -0,0 +1,28 @@ +* Faraday Technology FTRTC010 Real Time Clock + +This RTC appears in for example the Storlink Gemini family of +SoCs. + +Required properties: +- compatible : Should be one of: + "faraday,ftrtc010" + "cortina,gemini-rtc", "faraday,ftrtc010" + +Optional properties: +- clocks: when present should contain clock references to the + PCLK and EXTCLK clocks. Faraday calls the later CLK1HZ and + says the clock should be 1 Hz, but implementers actually seem + to choose different clocks here, like Cortina who chose + 32768 Hz (a typical low-power clock). +- clock-names: should name the clocks "PCLK" and "EXTCLK" + respectively. + +Examples: + +rtc@45000000 { + compatible = "cortina,gemini-rtc"; + reg = <0x45000000 0x100>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&foo 0>, <&foo 1>; + clock-names = "PCLK", "EXTCLK"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/google,goldfish-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/google,goldfish-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..634312dd95ca7e84b7ac0b5624569d34256f98b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/google,goldfish-rtc.txt @@ -0,0 +1,17 @@ +Android Goldfish RTC + +Android Goldfish RTC device used by Android emulator. + +Required properties: + +- compatible : should contain "google,goldfish-rtc" +- reg : +- interrupts : + +Example: + + goldfish_timer@9020000 { + compatible = "google,goldfish-rtc"; + reg = <0x9020000 0x1000>; + interrupts = <0x3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/haoyu,hym8563.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/haoyu,hym8563.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8934fe2ab4c19c8186e0bad5dbca2a1b29f1579 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/haoyu,hym8563.txt @@ -0,0 +1,30 @@ +Haoyu Microelectronics HYM8563 Real Time Clock + +The HYM8563 provides basic rtc and alarm functionality +as well as a clock output of up to 32kHz. + +Required properties: +- compatible: should be: "haoyu,hym8563" +- reg: i2c address +- #clock-cells: the value should be 0 + +Optional properties: +- clock-output-names: From common clock binding +- interrupts: rtc alarm/event interrupt + +Example: + +hym8563: hym8563@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + #clock-cells = <0>; +}; + +device { +... + clocks = <&hym8563>; +... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/imxdi-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/imxdi-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c797bc9d77d2296a225c8d6da9922fb187243f9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/imxdi-rtc.txt @@ -0,0 +1,20 @@ +* i.MX25 Real Time Clock controller + +Required properties: +- compatible: should be: "fsl,imx25-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: should contain the phandle for the rtc clock +- interrupts: rtc alarm interrupt + +Optional properties: +- interrupts: dryice security violation interrupt (second entry) + +Example: + +rtc@53ffc000 { + compatible = "fsl,imx25-rtc"; + reg = <0x53ffc000 0x4000>; + clocks = <&clks 81>; + interrupts = <25 56>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/ingenic,jz4740-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/ingenic,jz4740-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..41c7ae18fd7bb7835dd10d9bc4b494138b3105c6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/ingenic,jz4740-rtc.txt @@ -0,0 +1,37 @@ +JZ4740 and similar SoCs real-time clock driver + +Required properties: + +- compatible: One of: + - "ingenic,jz4740-rtc" - for use with the JZ4740 SoC + - "ingenic,jz4780-rtc" - for use with the JZ4780 SoC +- reg: Address range of rtc register set +- interrupts: IRQ number for the alarm interrupt +- clocks: phandle to the "rtc" clock +- clock-names: must be "rtc" + +Optional properties: +- system-power-controller: To use this component as the + system power controller +- reset-pin-assert-time-ms: Reset pin low-level assertion + time after wakeup (default 60ms; range 0-125ms if RTC clock + at 32 kHz) +- min-wakeup-pin-assert-time-ms: Minimum wakeup pin assertion + time (default 100ms; range 0-2s if RTC clock at 32 kHz) + +Example: + +rtc@10003000 { + compatible = "ingenic,jz4740-rtc"; + reg = <0x10003000 0x40>; + + interrupt-parent = <&intc>; + interrupts = <32>; + + clocks = <&rtc_clock>; + clock-names = "rtc"; + + system-power-controller; + reset-pin-assert-time-ms = <60>; + min-wakeup-pin-assert-time-ms = <100>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl12026.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl12026.txt new file mode 100644 index 0000000000000000000000000000000000000000..2e0be45193bb9d26fafa64011e301df12b877e1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl12026.txt @@ -0,0 +1,28 @@ +ISL12026 I2C RTC/EEPROM + +ISL12026 is an I2C RTC/EEPROM combination device. The RTC and control +registers respond at bus address 0x6f, and the EEPROM array responds +at bus address 0x57. The canonical "reg" value will be for the RTC portion. + +Required properties supported by the device: + + - "compatible": must be "isil,isl12026" + - "reg": I2C bus address of the device (always 0x6f) + +Optional properties: + + - "isil,pwr-bsw": If present PWR.BSW bit must be set to the specified + value for proper operation. + + - "isil,pwr-sbib": If present PWR.SBIB bit must be set to the specified + value for proper operation. + + +Example: + + rtc@6f { + compatible = "isil,isl12026"; + reg = <0x6f>; + isil,pwr-bsw = <0>; + isil,pwr-sbib = <1>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl12057.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl12057.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff7c43555199c28f193789e32ccca223975ec0b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl12057.txt @@ -0,0 +1,74 @@ +Intersil ISL12057 I2C RTC/Alarm chip + +ISL12057 is a trivial I2C device (it has simple device tree bindings, +consisting of a compatible field, an address and possibly an interrupt +line). + +Nonetheless, it also supports an option boolean property +("wakeup-source") to handle the specific use-case found +on at least three in-tree users of the chip (NETGEAR ReadyNAS 102, 104 +and 2120 ARM-based NAS); On those devices, the IRQ#2 pin of the chip +(associated with the alarm supported by the driver) is not connected +to the SoC but to a PMIC. It allows the device to be powered up when +RTC alarm rings. In order to mark the device has a wakeup source and +get access to the 'wakealarm' sysfs entry, this specific property can +be set when the IRQ#2 pin of the chip is not connected to the SoC but +can wake up the device. + +Required properties supported by the device: + + - "compatible": must be "isil,isl12057" + - "reg": I2C bus address of the device + +Optional properties: + + - "wakeup-source": mark the chip as a wakeup source, independently of + the availability of an IRQ line connected to the SoC. + + +Example isl12057 node without IRQ#2 pin connected (no alarm support): + + isl12057: isl12057@68 { + compatible = "isil,isl12057"; + reg = <0x68>; + }; + + +Example isl12057 node with IRQ#2 pin connected to main SoC via MPP6 (note +that the pinctrl-related properties below are given for completeness and +may not be required or may be different depending on your system or +SoC, and the main function of the MPP used as IRQ line, i.e. +"interrupt-parent" and "interrupts" are usually sufficient): + + pinctrl { + ... + + rtc_alarm_pin: rtc_alarm_pin { + marvell,pins = "mpp6"; + marvell,function = "gpio"; + }; + + ... + + }; + + ... + + isl12057: isl12057@68 { + compatible = "isil,isl12057"; + reg = <0x68>; + pinctrl-0 = <&rtc_alarm_pin>; + pinctrl-names = "default"; + interrupt-parent = <&gpio0>; + interrupts = <6 IRQ_TYPE_EDGE_FALLING>; + }; + + +Example isl12057 node without IRQ#2 pin connected to the SoC but to a +PMIC, allowing the device to be started based on configured alarm: + + isl12057: isl12057@68 { + compatible = "isil,isl12057"; + reg = <0x68>; + wakeup-source; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl1219.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl1219.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3efd48e91c2e0b9b8e3ebefcec20b5db77baa14 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/isil,isl1219.txt @@ -0,0 +1,29 @@ +Intersil ISL1219 I2C RTC/Alarm chip with event in + +ISL1219 has additional pins EVIN and #EVDET for tamper detection. + +Required properties supported by the device: + + - "compatible": must be "isil,isl1219" + - "reg": I2C bus address of the device + +Optional properties: + + - "interrupt-names": list which may contains "irq" and "evdet" + - "interrupts": list of interrupts for "irq" and "evdet" + - "isil,ev-evienb": if present EV.EVIENB bit is set to the specified + value for proper operation. + + +Example isl1219 node with #IRQ pin connected to SoC gpio1 pin12 + and #EVDET pin connected to SoC gpio2 pin 24: + + isl1219: rtc@68 { + compatible = "isil,isl1219"; + reg = <0x68>; + interrupt-names = "irq", "evdet"; + interrupts-extended = <&gpio1 12 IRQ_TYPE_EDGE_FALLING>, + <&gpio2 24 IRQ_TYPE_EDGE_FALLING>; + isil,ev-evienb = <1>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/lpc32xx-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/lpc32xx-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a87a1e9bc060d8dc4673f927f6838d753cd45269 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/lpc32xx-rtc.txt @@ -0,0 +1,15 @@ +* NXP LPC32xx SoC Real Time Clock controller + +Required properties: +- compatible: must be "nxp,lpc3220-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The RTC interrupt + +Example: + + rtc@40024000 { + compatible = "nxp,lpc3220-rtc"; + reg = <0x40024000 0x1000>; + interrupts = <52 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,ds1742.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,ds1742.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0f937c355b5a5917d966eee861a541b1eec1fab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,ds1742.txt @@ -0,0 +1,12 @@ +* Maxim (Dallas) DS1742/DS1743 Real Time Clock + +Required properties: +- compatible: Should contain "maxim,ds1742". +- reg: Physical base address of the RTC and length of memory + mapped region. + +Example: + rtc: rtc@10000000 { + compatible = "maxim,ds1742"; + reg = <0x10000000 0x800>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,ds3231.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,ds3231.txt new file mode 100644 index 0000000000000000000000000000000000000000..85be53a421809c0b8e04c6bf1dfa9833ff84a99d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,ds3231.txt @@ -0,0 +1,38 @@ +* Maxim DS3231 Real Time Clock + +Required properties: +- compatible: Should contain "maxim,ds3231". +- reg: I2C address for chip. + +Optional property: +- #clock-cells: Should be 1. +- clock-output-names: + overwrite the default clock names "ds3231_clk_sqw" and "ds3231_clk_32khz". + +Each clock is assigned an identifier and client nodes can use this identifier +to specify the clock which they consume. Following indices are allowed: + - 0: square-wave output on the SQW pin + - 1: square-wave output on the 32kHz pin + +- interrupts: rtc alarm/event interrupt. When this property is selected, + clock on the SQW pin cannot be used. + +Example: + +ds3231: ds3231@51 { + compatible = "maxim,ds3231"; + reg = <0x68>; + #clock-cells = <1>; +}; + +device1 { +... + clocks = <&ds3231 0>; +... +}; + +device2 { +... + clocks = <&ds3231 1>; +... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,mcp795.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,mcp795.txt new file mode 100644 index 0000000000000000000000000000000000000000..a59fdd8c236d2a7beee87b7b581408cda7aa6a17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim,mcp795.txt @@ -0,0 +1,11 @@ +* Maxim MCP795 SPI Serial Real-Time Clock + +Required properties: +- compatible: Should contain "maxim,mcp795". +- reg: SPI address for chip + +Example: + mcp795: rtc@0 { + compatible = "maxim,mcp795"; + reg = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/maxim-ds1302.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim-ds1302.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba470c56cdec978b2bf90991301722e2b2b5f218 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/maxim-ds1302.txt @@ -0,0 +1,46 @@ +* Maxim/Dallas Semiconductor DS-1302 RTC + +Simple device which could be used to store date/time between reboots. + +The device uses the standard MicroWire half-duplex transfer timing. +Master output is set on low clock and sensed by the RTC on the rising +edge. Master input is set by the RTC on the trailing edge and is sensed +by the master on low clock. + +Required properties: + +- compatible : Should be "maxim,ds1302" + +Required SPI properties: + +- reg : Should be address of the device chip select within + the controller. + +- spi-max-frequency : DS-1302 has 500 kHz if powered at 2.2V, + and 2MHz if powered at 5V. + +- spi-3wire : The device has a shared signal IN/OUT line. + +- spi-lsb-first : DS-1302 requires least significant bit first + transfers. + +- spi-cs-high: DS-1302 has active high chip select line. This is + required unless inverted in hardware. + +Example: + +spi@901c { + #address-cells = <1>; + #size-cells = <0>; + compatible = "icpdas,lp8841-spi-rtc"; + reg = <0x901c 0x1>; + + rtc@0 { + compatible = "maxim,ds1302"; + reg = <0>; + spi-max-frequency = <500000>; + spi-3wire; + spi-lsb-first; + spi-cs-high; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/microchip,pic32-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/microchip,pic32-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..180b7144bfcc53b680fce4239715a9dee5919181 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/microchip,pic32-rtc.txt @@ -0,0 +1,21 @@ +* Microchip PIC32 Real Time Clock and Calendar + +The RTCC keeps time in hours, minutes, and seconds, and one half second. It +provides a calendar in weekday, date, month, and year. It also provides a +configurable alarm. + +Required properties: +- compatible: should be: "microchip,pic32mzda-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: RTC alarm/event interrupt +- clocks: clock phandle + +Example: + + rtc: rtc@1f8c0000 { + compatible = "microchip,pic32mzda-rtc"; + reg = <0x1f8c0000 0x60>; + interrupts = <166 IRQ_TYPE_EDGE_RISING>; + clocks = <&PBCLK6>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/moxa,moxart-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/moxa,moxart-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..c9d3ac1477feb84ccbad62a3527779bb78e05e8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/moxa,moxart-rtc.txt @@ -0,0 +1,17 @@ +MOXA ART real-time clock + +Required properties: + +- compatible : Should be "moxa,moxart-rtc" +- gpio-rtc-sclk : RTC sclk gpio, with zero flags +- gpio-rtc-data : RTC data gpio, with zero flags +- gpio-rtc-reset : RTC reset gpio, with zero flags + +Example: + + rtc: rtc { + compatible = "moxa,moxart-rtc"; + gpio-rtc-sclk = <&gpio 5 0>; + gpio-rtc-data = <&gpio 6 0>; + gpio-rtc-reset = <&gpio 7 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/nvidia,tegra20-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/nvidia,tegra20-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7d98ed3e098c5206e5846993a70899b3830be35 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/nvidia,tegra20-rtc.txt @@ -0,0 +1,24 @@ +NVIDIA Tegra20 real-time clock + +The Tegra RTC maintains seconds and milliseconds counters, and five alarm +registers. The alarms and other interrupts may wake the system from low-power +state. + +Required properties: + +- compatible : For Tegra20, must contain "nvidia,tegra20-rtc". Otherwise, + must contain '"nvidia,-rtc", "nvidia,tegra20-rtc"', where + can be tegra30, tegra114, tegra124, or tegra132. +- reg : Specifies base physical address and size of the registers. +- interrupts : A single interrupt specifier. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +Example: + +timer { + compatible = "nvidia,tegra20-rtc"; + reg = <0x7000e000 0x100>; + interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/nxp,lpc1788-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/nxp,lpc1788-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c97bd180592a405d21421b27bc5403e51c61f36 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/nxp,lpc1788-rtc.txt @@ -0,0 +1,21 @@ +NXP LPC1788 real-time clock + +The LPC1788 RTC provides calendar and clock functionality +together with periodic tick and alarm interrupt support. + +Required properties: +- compatible : must contain "nxp,lpc1788-rtc" +- reg : Specifies base physical address and size of the registers. +- interrupts : A single interrupt specifier. +- clocks : Must contain clock specifiers for rtc and register clock +- clock-names : Must contain "rtc" and "reg" + See ../clocks/clock-bindings.txt for details. + +Example: +rtc: rtc@40046000 { + compatible = "nxp,lpc1788-rtc"; + reg = <0x40046000 0x1000>; + interrupts = <47>; + clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>; + clock-names = "rtc", "reg"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/nxp,rtc-2123.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/nxp,rtc-2123.txt new file mode 100644 index 0000000000000000000000000000000000000000..811124a36d167dda3f8a873e859eb5baf69a99c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/nxp,rtc-2123.txt @@ -0,0 +1,16 @@ +NXP PCF2123 SPI Real Time Clock + +Required properties: +- compatible: should be: "nxp,rtc-pcf2123" +- reg: should be the SPI slave chipselect address + +Optional properties: +- spi-cs-high: PCF2123 needs chipselect high + +Example: + +pcf2123: rtc@3 { + compatible = "nxp,rtc-pcf2123" + reg = <3> + spi-cs-high; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/olpc-xo1-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/olpc-xo1-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2891ceb63449437d4283b8e4a7ed2741cacf40e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/olpc-xo1-rtc.txt @@ -0,0 +1,5 @@ +OLPC XO-1 RTC +~~~~~~~~~~~~~ + +Required properties: + - compatible : "olpc,xo1-rtc" diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/orion-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/orion-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3bf63ffa516059ad8d0a19f3c6077f24ded45825 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/orion-rtc.txt @@ -0,0 +1,18 @@ +* Mvebu Real Time Clock + +RTC controller for the Kirkwood, the Dove, the Armada 370 and the +Armada XP SoCs + +Required properties: +- compatible : Should be "marvell,orion-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: IRQ line for the RTC. + +Example: + +rtc@10300 { + compatible = "marvell,orion-rtc"; + reg = <0xd0010300 0x20>; + interrupts = <50>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/pcf85363.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/pcf85363.txt new file mode 100644 index 0000000000000000000000000000000000000000..76fdabc5974232a08cbcbe10b60cd08db942b7cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/pcf85363.txt @@ -0,0 +1,17 @@ +NXP PCF85363 Real Time Clock +============================ + +Required properties: +- compatible: Should contain "nxp,pcf85363". +- reg: I2C address for chip. + +Optional properties: +- interrupts: IRQ line for the RTC (not implemented). + +Example: + +pcf85363: pcf85363@51 { + compatible = "nxp,pcf85363"; + reg = <0x51>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/pcf8563.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/pcf8563.txt new file mode 100644 index 0000000000000000000000000000000000000000..36984acbb383c275c57a25ff0d8cf756292ed45d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/pcf8563.txt @@ -0,0 +1,26 @@ +* Philips PCF8563/Epson RTC8564 Real Time Clock + +Philips PCF8563/Epson RTC8564 Real Time Clock + +Required properties: +- compatible: Should contain "nxp,pcf8563". +- reg: I2C address for chip. + +Optional property: +- #clock-cells: Should be 0. +- clock-output-names: + overwrite the default clock name "pcf8563-clkout" + +Example: + +pcf8563: pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; +}; + +device { +... + clocks = <&pcf8563>; +... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/pxa-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/pxa-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c6672a1b7d7df5affc04816265e39cf08f61284 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/pxa-rtc.txt @@ -0,0 +1,14 @@ +* PXA RTC + +PXA specific RTC driver. + +Required properties: +- compatible : Should be "marvell,pxa-rtc" + +Examples: + +rtc@40900000 { + compatible = "marvell,pxa-rtc"; + reg = <0x40900000 0x3c>; + interrupts = <30 31>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/qpnp-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/qpnp-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0934b2aa82fa4751e11660bc0039e8ca1319744 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/qpnp-rtc.txt @@ -0,0 +1,60 @@ +* msm-qpnp-rtc + +msm-qpnp-rtc is a RTC driver that supports 32 bit RTC housed inside PMIC. +Driver utilizes MSM SPMI interface to communicate with the RTC module. +RTC device is divided into two sub-peripherals one which controls basic RTC +and other for controlling alarm. + +[PMIC RTC Device Declarations] + +-Root Node- + +Required properties : + - compatible: Must be "qcom,qpnp-rtc" + - #address-cells: The number of cells dedicated to represent an address + This must be set to '1'. + - #size-cells: The number of cells dedicated to represent address + space range of a peripheral. This must be set to '1'. + +Optional properties: + - qcom,qpnp-rtc-write: This property enables/disables rtc write + operation. If not mentioned rtc driver keeps + rtc writes disabled. + 0 = Disable rtc writes. + 1 = Enable rtc writes. + - qcom,qpnp-rtc-alarm-pwrup: This property enables/disables feature of + powering up phone (from power down state) + through alarm interrupt. + If not mentioned rtc driver will disable + feature of powring-up phone through alarm. + 0 = Disable powering up of phone through + alarm interrupt. + 1 = Enable powering up of phone through + alarm interrupt. + +-Child Nodes- + +Required properties : + - reg : Specify the spmi offset and size for device. + - interrupts: Specifies alarm interrupt, only for rtc_alarm + sub-peripheral. + +Example: + qcom,pm8941_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8941_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + + qcom,pm8941_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1>; + }; + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/realtek,rtd119x.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/realtek,rtd119x.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbf1ccb5df318acd1eef28bff1e06b92402e7816 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/realtek,rtd119x.txt @@ -0,0 +1,16 @@ +Realtek RTD129x Real-Time Clock +=============================== + +Required properties: +- compatible : Should be "realtek,rtd1295-rtc" +- reg : Specifies the physical base address and size +- clocks : Specifies the clock gate + + +Example: + + rtc@9801b600 { + compatible = "realtek,rtd1295-clk"; + reg = <0x9801b600 0x100>; + clocks = <&clkc RTD1295_CLK_EN_MISC_RTC>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-cmos.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-cmos.txt new file mode 100644 index 0000000000000000000000000000000000000000..b94b35f3600ba108c8bca790315f080a13281489 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-cmos.txt @@ -0,0 +1,27 @@ + Motorola mc146818 compatible RTC +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Required properties: + - compatible : "motorola,mc146818" + - reg : should contain registers location and length. + +Optional properties: + - interrupts : should contain interrupt. + - ctrl-reg : Contains the initial value of the control register also + called "Register B". + - freq-reg : Contains the initial value of the frequency register also + called "Regsiter A". + +"Register A" and "B" are usually initialized by the firmware (BIOS for +instance). If this is not done, it can be performed by the driver. + +ISA Example: + + rtc@70 { + compatible = "motorola,mc146818"; + interrupts = <8 3>; + interrupt-parent = <&ioapic1>; + ctrl-reg = <2>; + freq-reg = <0x26>; + reg = <1 0x70 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-ds1307.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-ds1307.txt new file mode 100644 index 0000000000000000000000000000000000000000..eebfbe04207a0e02f8e4d517f4dfb4ce0678a1e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-ds1307.txt @@ -0,0 +1,44 @@ +Dallas DS1307 and compatible RTC + +Required properties: +- compatible: should be one of: + "dallas,ds1307", + "dallas,ds1308", + "dallas,ds1337", + "dallas,ds1338", + "dallas,ds1339", + "dallas,ds1388", + "dallas,ds1340", + "dallas,ds1341", + "maxim,ds3231", + "st,m41t0", + "st,m41t00", + "st,m41t11", + "microchip,mcp7940x", + "microchip,mcp7941x", + "pericom,pt7c4338", + "epson,rx8025", + "isil,isl12057" +- reg: I2C bus address of the device + +Optional properties: +- interrupts: rtc alarm interrupt. +- clock-output-names: From common clock binding to override the default output + clock name +- wakeup-source: Enables wake up of host system on alarm +- trickle-resistor-ohms : ds1339, ds1340 and ds 1388 only + Selected resistor for trickle charger + Possible values are 250, 2000, 4000 + Should be given if trickle charger should be enabled +- trickle-diode-disable : ds1339, ds1340 and ds 1388 only + Do not use internal trickle charger diode + Should be given if internal trickle charger diode should be disabled + +Example: + rtc1: ds1339@68 { + compatible = "dallas,ds1339"; + reg = <0x68>; + interrupt-parent = <&gpio4>; + interrupts = <20 0>; + trickle-resistor-ohms = <250>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-m41t80.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-m41t80.txt new file mode 100644 index 0000000000000000000000000000000000000000..c746cb2212103c8aca59ff52f1652ce15dbc0e54 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-m41t80.txt @@ -0,0 +1,30 @@ +ST M41T80 family of RTC and compatible + +Required properties: +- compatible: should be one of: + "st,m41t62", + "st,m41t65", + "st,m41t80", + "st,m41t81", + "st,m41t81s", + "st,m41t82", + "st,m41t83", + "st,m41t84", + "st,m41t85", + "st,m41t87", + "microcrystal,rv4162", +- reg: I2C bus address of the device + +Optional properties: +- interrupts: rtc alarm interrupt. +- clock-output-names: From common clock binding to override the default output + clock name +- wakeup-source: Enables wake up of host system on alarm + +Example: + rtc@68 { + compatible = "st,m41t80"; + reg = <0x68>; + interrupt-parent = <&UIC0>; + interrupts = <0x9 0x8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mt7622.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mt7622.txt new file mode 100644 index 0000000000000000000000000000000000000000..09fe8f51476f8638216279ceb68b0d3a736dc920 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mt7622.txt @@ -0,0 +1,21 @@ +Device-Tree bindings for MediaTek SoC based RTC + +Required properties: +- compatible : Should be + "mediatek,mt7622-rtc", "mediatek,soc-rtc" : for MT7622 SoC +- reg : Specifies base physical address and size of the registers; +- interrupts : Should contain the interrupt for RTC alarm; +- clocks : Specifies list of clock specifiers, corresponding to + entries in clock-names property; +- clock-names : Should contain "rtc" entries + +Example: + +rtc: rtc@10212800 { + compatible = "mediatek,mt7622-rtc", + "mediatek,soc-rtc"; + reg = <0 0x10212800 0 0x200>; + interrupts = ; + clocks = <&topckgen CLK_TOP_RTC>; + clock-names = "rtc"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mxc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mxc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bcd31d995b097729d134d7c33877f6f22a55169 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mxc.txt @@ -0,0 +1,26 @@ +* Real Time Clock of the i.MX SoCs + +RTC controller for the i.MX SoCs + +Required properties: +- compatible: Should be "fsl,imx1-rtc" or "fsl,imx21-rtc". +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: IRQ line for the RTC. +- clocks: should contain two entries: + * one for the input reference + * one for the the SoC RTC +- clock-names: should contain: + * "ref" for the input reference clock + * "ipg" for the SoC RTC clock + +Example: + +rtc@10007000 { + compatible = "fsl,imx21-rtc"; + reg = <0x10007000 0x1000>; + interrupts = <22>; + clocks = <&clks IMX27_CLK_CKIL>, + <&clks IMX27_CLK_RTC_IPG_GATE>; + clock-names = "ref", "ipg"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mxc_v2.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mxc_v2.txt new file mode 100644 index 0000000000000000000000000000000000000000..79d7e87b0d91c4f1d8bf1f8786a1b663789b58e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-mxc_v2.txt @@ -0,0 +1,17 @@ +* i.MX53 Secure Real Time Clock (SRTC) + +Required properties: +- compatible: should be: "fsl,imx53-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: should contain the phandle for the rtc clock +- interrupts: rtc alarm interrupt + +Example: + +rtc@53fa4000 { + compatible = "fsl,imx53-rtc"; + reg = <0x53fa4000 0x4000>; + interrupts = <24>; + clocks = <&clks IMX5_CLK_SRTC_GATE>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-omap.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..062ebb14cecfa713ecbba88ca290b18742c0239c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-omap.txt @@ -0,0 +1,53 @@ +TI Real Time Clock + +Required properties: +- compatible: + - "ti,da830-rtc" - for RTC IP used similar to that on DA8xx SoC family. + - "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family. + This RTC IP has special WAKE-EN Register to enable + Wakeup generation for event Alarm. It can also be + used to control an external PMIC via the + pmic_power_en pin. + - "ti,am4372-rtc" - for RTC IP used similar to that on AM437X SoC family. +- reg: Address range of rtc register set +- interrupts: rtc timer, alarm interrupts in order + +Optional properties: +- system-power-controller: whether the rtc is controlling the system power + through pmic_power_en +- clocks: Any internal or external clocks feeding in to rtc +- clock-names: Corresponding names of the clocks +- pinctrl-0: a phandle pointing to the pin settings for the device +- pinctrl-names: should be "default" + +Optional subnodes: +- generic pinctrl node + +Required pinctrl subnodes properties: +- pins - Names of ext_wakeup pins to configure + +Optional pinctrl subnodes properties: +- input-enable - Enables ext_wakeup +- ti,active-high - Set input active high (by default active low) + +Example: + +rtc@1c23000 { + compatible = "ti,da830-rtc"; + reg = <0x23000 0x1000>; + interrupts = <19 + 19>; + interrupt-parent = <&intc>; + system-power-controller; + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; + + pinctrl-0 = <&ext_wakeup>; + pinctrl-names = "default"; + + ext_wakeup: ext-wakeup { + pins = "ext_wakeup0"; + input-enable; + ti,active-high; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-opal.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-opal.txt new file mode 100644 index 0000000000000000000000000000000000000000..2340938cd0f5bca661ac97534d8a3f46205f9610 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-opal.txt @@ -0,0 +1,17 @@ +IBM OPAL real-time clock +------------------------ + +Required properties: +- compatible: Should be "ibm,opal-rtc" + +Optional properties: +- wakeup-source: Decides if the wakeup is supported or not + (Legacy property supported: "has-tpo") + +Example: + rtc { + compatible = "ibm,opal-rtc"; + wakeup-source; + phandle = <0x10000029>; + linux,phandle = <0x10000029>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-palmas.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-palmas.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6cf37758a77a36dd5b4c572da631a6b5a6e73f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-palmas.txt @@ -0,0 +1,32 @@ +Palmas RTC controller bindings + +Required properties: +- compatible: + - "ti,palmas-rtc" for palma series of the RTC controller +- interrupts: Interrupt number of RTC submodule on device. + +Optional properties: + +- ti,backup-battery-chargeable: The Palmas series device like TPS65913 or + TPS80036 supports the backup battery for powering the RTC when main + battery is removed or in very low power state. The backup battery + can be chargeable or non-chargeable. This flag will tells whether + battery is chargeable or not. If charging battery then driver can + enable the charging. +- ti,backup-battery-charge-high-current: Enable high current charging in + backup battery. Device supports the < 100uA and > 100uA charging. + The high current will be > 100uA. Absence of this property will + charge battery to lower current i.e. < 100uA. + +Example: + palmas: tps65913@58 { + ... + palmas_rtc: rtc { + compatible = "ti,palmas-rtc"; + interrupt-parent = <&palmas>; + interrupts = <8 0>; + ti,backup-battery-chargeable; + ti,backup-battery-charge-high-current; + }; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-sh.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-sh.txt new file mode 100644 index 0000000000000000000000000000000000000000..7676c7d2887403733965bac7c234e0665a2216c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-sh.txt @@ -0,0 +1,28 @@ +* Real Time Clock for Renesas SH and ARM SoCs + +Required properties: +- compatible: Should be "renesas,r7s72100-rtc" and "renesas,sh-rtc" as a + fallback. +- reg: physical base address and length of memory mapped region. +- interrupts: 3 interrupts for alarm, period, and carry. +- interrupt-names: The interrupts should be labeled as "alarm", "period", and + "carry". +- clocks: The functional clock source for the RTC controller must be listed + first (if exists). Additionally, potential clock counting sources are to be + listed. +- clock-names: The functional clock must be labeled as "fck". Other clocks + may be named in accordance to the SoC hardware manuals. + + +Example: +rtc: rtc@fcff1000 { + compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc"; + reg = <0xfcff1000 0x2e>; + interrupts = ; + interrupt-names = "alarm", "period", "carry"; + clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>, + <&rtc_x3_clk>, <&extal_clk>; + clock-names = "fck", "rtc_x1", "rtc_x3", "extal"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-st-lpc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-st-lpc.txt new file mode 100644 index 0000000000000000000000000000000000000000..daf88265df32391004a72238c5c39061d707eb84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/rtc-st-lpc.txt @@ -0,0 +1,28 @@ +STMicroelectronics Low Power Controller (LPC) - RTC +=================================================== + +LPC currently supports Watchdog OR Real Time Clock OR Clocksource +functionality. + +[See: ../watchdog/st_lpc_wdt.txt for Watchdog options] +[See: ../timer/st,stih407-lpc for Clocksource options] + +Required properties + +- compatible : Must be: "st,stih407-lpc" +- reg : LPC registers base address + size +- interrupts : LPC interrupt line number and associated flags +- clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) +- st,lpc-mode : The LPC can run either one of three modes: + ST_LPC_MODE_RTC [0] + ST_LPC_MODE_WDT [1] + ST_LPC_MODE_CLKSRC [2] + One (and only one) mode must be selected. + +Example: + lpc@fde05000 { + compatible = "st,stih407-lpc"; + reg = <0xfde05000 0x1000>; + clocks = <&clk_s_d3_flexgen CLK_LPC_0>; + st,lpc-mode = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/s3c-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/s3c-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdde63a5419cb1942ea1480a761beb963db08479 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/s3c-rtc.txt @@ -0,0 +1,31 @@ +* Samsung's S3C Real Time Clock controller + +Required properties: +- compatible: should be one of the following. + * "samsung,s3c2410-rtc" - for controllers compatible with s3c2410 rtc. + * "samsung,s3c2416-rtc" - for controllers compatible with s3c2416 rtc. + * "samsung,s3c2443-rtc" - for controllers compatible with s3c2443 rtc. + * "samsung,s3c6410-rtc" - for controllers compatible with s3c6410 rtc. + * "samsung,exynos3250-rtc" - (deprecated) for controllers compatible with + exynos3250 rtc (use "samsung,s3c6410-rtc"). +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: Two interrupt numbers to the cpu should be specified. First + interrupt number is the rtc alarm interrupt and second interrupt number + is the rtc tick interrupt. The number of cells representing a interrupt + depends on the parent interrupt controller. +- clocks: Must contain a list of phandle and clock specifier for the rtc + clock and in the case of a s3c6410 compatible controller, also + a source clock. +- clock-names: Must contain "rtc" and for a s3c6410 compatible controller, + a "rtc_src" sorted in the same order as the clocks property. + +Example: + + rtc@10070000 { + compatible = "samsung,s3c6410-rtc"; + reg = <0x10070000 0x100>; + interrupts = <44 0 45 0>; + clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>; + clock-names = "rtc", "rtc_src"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/sa1100-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/sa1100-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..968ac820254bbbae3ddd8cdb5b9e174c6a477083 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/sa1100-rtc.txt @@ -0,0 +1,17 @@ +* Marvell Real Time Clock controller + +Required properties: +- compatible: should be "mrvl,sa1100-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: Should be two. The first interrupt number is the rtc alarm + interrupt and the second interrupt number is the rtc hz interrupt. +- interrupt-names: Assign name of irq resource. + +Example: + rtc: rtc@d4010000 { + compatible = "mrvl,mmp-rtc"; + reg = <0xd4010000 0x1000>; + interrupts = <5>, <6>; + interrupt-names = "rtc 1Hz", "rtc alarm"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/sirf,prima2-sysrtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/sirf,prima2-sysrtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..58885b55da21360187dd836c53690d33a8de9066 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/sirf,prima2-sysrtc.txt @@ -0,0 +1,13 @@ +SiRFSoC Real Time Clock + +Required properties: +- compatible: must be "sirf,prima2-sysrtc" +- reg: address range of rtc register set. +- interrupts: rtc alarm interrupts. + +Example: + rtc@2000 { + compatible = "sirf,prima2-sysrtc"; + reg = <0x2000 0x1000>; + interrupts = <52 53 54>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/snvs-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/snvs-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fb61ed77ada36b9469416affe7de6baf53f6b67f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/snvs-rtc.txt @@ -0,0 +1 @@ +See Documentation/devicetree/bindings/crypto/fsl-sec4.txt for details. diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/spear-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/spear-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fecf8e4ad4b4acfb4751a3138e94c5ac40f6bd0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/spear-rtc.txt @@ -0,0 +1,15 @@ +* SPEAr RTC + +Required properties: +- compatible : "st,spear600-rtc" +- reg : Address range of the rtc registers +- interrupt: Should contain the rtc interrupt number + +Example: + + rtc@fc000000 { + compatible = "st,spear600-rtc"; + reg = <0xfc000000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <12>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/sprd,sc27xx-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/sprd,sc27xx-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f5754299d31e4463b534bd90fe2f245b7deaceb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/sprd,sc27xx-rtc.txt @@ -0,0 +1,26 @@ +Spreadtrum SC27xx Real Time Clock + +Required properties: +- compatible: should be "sprd,sc2731-rtc". +- reg: address offset of rtc register. +- interrupts: rtc alarm interrupt. + +Example: + + sc2731_pmic: pmic@0 { + compatible = "sprd,sc2731"; + reg = <0>; + spi-max-frequency = <26000000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@280 { + compatible = "sprd,sc2731-rtc"; + reg = <0x280>; + interrupt-parent = <&sc2731_pmic>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/st,stm32-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/st,stm32-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..130ca5b9825384c9f8c15525c990909daab04325 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/st,stm32-rtc.txt @@ -0,0 +1,61 @@ +STM32 Real Time Clock + +Required properties: +- compatible: can be one of the following: + - "st,stm32-rtc" for devices compatible with stm32(f4/f7). + - "st,stm32h7-rtc" for devices compatible with stm32h7. + - "st,stm32mp1-rtc" for devices compatible with stm32mp1. +- reg: address range of rtc register set. +- clocks: can use up to two clocks, depending on part used: + - "rtc_ck": RTC clock source. + - "pclk": RTC APB interface clock. + It is not present on stm32(f4/f7). + It is required on stm32(h7/mp1). +- clock-names: must be "rtc_ck" and "pclk". + It is required on stm32(h7/mp1). +- interrupts: rtc alarm interrupt. On stm32mp1, a second interrupt is required + for rtc alarm wakeup interrupt. +- st,syscfg: phandle/offset/mask triplet. The phandle to pwrcfg used to + access control register at offset, and change the dbp (Disable Backup + Protection) bit represented by the mask, mandatory to disable/enable backup + domain (RTC registers) write protection. + It is required on stm32(f4/f7/h7). + +Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7): +- assigned-clocks: reference to the rtc_ck clock entry. +- assigned-clock-parents: phandle of the new parent clock of rtc_ck. + +Example: + + rtc: rtc@40002800 { + compatible = "st,stm32-rtc"; + reg = <0x40002800 0x400>; + clocks = <&rcc 1 CLK_RTC>; + assigned-clocks = <&rcc 1 CLK_RTC>; + assigned-clock-parents = <&rcc 1 CLK_LSE>; + interrupt-parent = <&exti>; + interrupts = <17 1>; + st,syscfg = <&pwrcfg 0x00 0x100>; + }; + + rtc: rtc@58004000 { + compatible = "st,stm32h7-rtc"; + reg = <0x58004000 0x400>; + clocks = <&rcc RTCAPB_CK>, <&rcc RTC_CK>; + clock-names = "pclk", "rtc_ck"; + assigned-clocks = <&rcc RTC_CK>; + assigned-clock-parents = <&rcc LSE_CK>; + interrupt-parent = <&exti>; + interrupts = <17 1>; + interrupt-names = "alarm"; + st,syscfg = <&pwrcfg 0x00 0x100>; + }; + + rtc: rtc@5c004000 { + compatible = "st,stm32mp1-rtc"; + reg = <0x5c004000 0x400>; + clocks = <&rcc RTCAPB>, <&rcc RTC>; + clock-names = "pclk", "rtc_ck"; + interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>, + <&exti 19 1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/stericsson,coh901331.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/stericsson,coh901331.txt new file mode 100644 index 0000000000000000000000000000000000000000..e615a897b20e3a519e03410edff93d53cb09f4b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/stericsson,coh901331.txt @@ -0,0 +1,16 @@ +ST-Ericsson COH 901 331 Real Time Clock + +Required properties: +- compatible: must be "stericsson,coh901331" +- reg: address range of rtc register set. +- interrupts: rtc alarm interrupt. +- clocks: phandle to the rtc clock source + +Example: + rtc: rtc@c0017000 { + compatible = "stericsson,coh901331"; + reg = <0xc0017000 0x1000>; + interrupt-parent = <&vicb>; + interrupts = <10>; + clocks = <&rtc_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/stmp3xxx-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/stmp3xxx-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fa6a9422666982b03eb659a2726845a81514d01d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/stmp3xxx-rtc.txt @@ -0,0 +1,21 @@ +* STMP3xxx/i.MX28 Time Clock controller + +Required properties: +- compatible: should be one of the following. + * "fsl,stmp3xxx-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: rtc alarm interrupt + +Optional properties: +- stmp,crystal-freq: override crystal frequency as determined from fuse bits. + Only <32000> and <32768> are possible for the hardware. Use <0> for + "no crystal". + +Example: + +rtc@80056000 { + compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc"; + reg = <0x80056000 2000>; + interrupts = <29>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/sun6i-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/sun6i-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..12c083c1140a33962fa4ef120e0c3cae9af33bea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/sun6i-rtc.txt @@ -0,0 +1,27 @@ +* sun6i Real Time Clock + +RTC controller for the Allwinner A31 + +Required properties: +- compatible : Should be "allwinner,sun6i-a31-rtc" +- reg : physical base address of the controller and length of + memory mapped region. +- interrupts : IRQ lines for the RTC alarm 0 and alarm 1, in that order. + +Required properties for new device trees +- clocks : phandle to the 32kHz external oscillator +- clock-output-names : names of the LOSC and its external output clocks created +- #clock-cells : must be equals to 1. The RTC provides two clocks: the + LOSC and its external output, with index 0 and 1 + respectively. + +Example: + +rtc: rtc@1f00000 { + compatible = "allwinner,sun6i-a31-rtc"; + reg = <0x01f00000 0x54>; + interrupts = <0 40 4>, <0 41 4>; + clock-output-names = "osc32k", "osc32k-out"; + clocks = <&ext_osc32k>; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/sunxi-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/sunxi-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a8d79c1cf08167dd036d19a8b83c18d80b8d8f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/sunxi-rtc.txt @@ -0,0 +1,17 @@ +* sun4i/sun7i Real Time Clock + +RTC controller for the Allwinner A10/A20 + +Required properties: +- compatible : Should be "allwinner,sun4i-a10-rtc" or "allwinner,sun7i-a20-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: IRQ line for the RTC. + +Example: + +rtc: rtc@1c20d00 { + compatible = "allwinner,sun4i-a10-rtc"; + reg = <0x01c20d00 0x20>; + interrupts = <24>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/ti,bq32k.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/ti,bq32k.txt new file mode 100644 index 0000000000000000000000000000000000000000..e204906b9ad3b16111825aab5082992cc4997339 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/ti,bq32k.txt @@ -0,0 +1,18 @@ +* TI BQ32000 I2C Serial Real-Time Clock + +Required properties: +- compatible: Should contain "ti,bq32000". +- reg: I2C address for chip + +Optional properties: +- trickle-resistor-ohms : Selected resistor for trickle charger + Values usable are 1120 and 20180 + Should be given if trickle charger should be enabled +- trickle-diode-disable : Do not use internal trickle charger diode + Should be given if internal trickle charger diode should be disabled +Example: + bq32000: rtc@68 { + compatible = "ti,bq32000"; + trickle-resistor-ohms = <1120>; + reg = <0x68>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/twl-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/twl-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f9a94f2f8969911e4490b744563c180a413426b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/twl-rtc.txt @@ -0,0 +1,11 @@ +* Texas Instruments TWL4030/6030 RTC + +Required properties: +- compatible : Should be "ti,twl4030-rtc" +- interrupts : Should be the interrupt number. + +Example: + rtc { + compatible = "ti,twl4030-rtc"; + interrupts = <11>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/via,vt8500-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/via,vt8500-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c0484c4958225d8bf4d9d31cbceb1671b9582e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/via,vt8500-rtc.txt @@ -0,0 +1,15 @@ +VIA/Wondermedia VT8500 Realtime Clock Controller +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-rtc" +- reg : Should contain 1 register ranges(address and length) +- interrupts : alarm interrupt + +Example: + + rtc@d8100000 { + compatible = "via,vt8500-rtc"; + reg = <0xd8100000 0x10000>; + interrupts = <48>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/xgene-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/xgene-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..fd195c358446ba52b1484609dd23a0412f707ce7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/xgene-rtc.txt @@ -0,0 +1,28 @@ +* APM X-Gene Real Time Clock + +RTC controller for the APM X-Gene Real Time Clock + +Required properties: +- compatible : Should be "apm,xgene-rtc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: IRQ line for the RTC. +- #clock-cells: Should be 1. +- clocks: Reference to the clock entry. + +Example: + +rtcclk: rtcclk { + compatible = "fixed-clock"; + #clock-cells = <1>; + clock-frequency = <100000000>; + clock-output-names = "rtcclk"; +}; + +rtc: rtc@10510000 { + compatible = "apm,xgene-rtc"; + reg = <0x0 0x10510000 0x0 0x400>; + interrupts = <0x0 0x46 0x4>; + #clock-cells = <1>; + clocks = <&rtcclk 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/rtc/xlnx-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/rtc/xlnx-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..0df6f016b1b771611fe4c83a8db76fc00d9db0f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/rtc/xlnx-rtc.txt @@ -0,0 +1,25 @@ +* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock + +RTC controller for the Xilinx Zynq MPSoC Real Time Clock +Separate IRQ lines for seconds and alarm + +Required properties: +- compatible: Should be "xlnx,zynqmp-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ lines for the RTC. +- interrupt-names: interrupt line names eg. "sec" "alarm" + +Optional: +- calibration: calibration value for 1 sec period which will + be programmed directly to calibration register + +Example: +rtc: rtc@ffa60000 { + compatible = "xlnx,zynqmp-rtc"; + reg = <0x0 0xffa60000 0x100>; + interrupt-parent = <&gic>; + interrupts = <0 26 4>, <0 27 4>; + interrupt-names = "alarm", "sec"; + calibration = <0x198233>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/scsi/hisilicon-sas.txt b/arch/arm64/boot/dts/vendor/bindings/scsi/hisilicon-sas.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c6659ed2cfc8218a1f531c77a4c0aa67745add4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/scsi/hisilicon-sas.txt @@ -0,0 +1,98 @@ +* HiSilicon SAS controller + +The HiSilicon SAS controller supports SAS/SATA. + +Main node required properties: + - compatible : value should be as follows: + (a) "hisilicon,hip05-sas-v1" for v1 hw in hip05 chipset + (b) "hisilicon,hip06-sas-v2" for v2 hw in hip06 chipset + (c) "hisilicon,hip07-sas-v2" for v2 hw in hip07 chipset + - sas-addr : array of 8 bytes for host SAS address + - reg : Contains two regions. The first is the address and length of the SAS + register. The second is the address and length of CPLD register for + SGPIO control. The second is optional, and should be set only when + we use a CPLD for directly attached disk LED control. + - hisilicon,sas-syscon: phandle of syscon used for sas control + - ctrl-reset-reg : offset to controller reset register in ctrl reg + - ctrl-reset-sts-reg : offset to controller reset status register in ctrl reg + - ctrl-clock-ena-reg : offset to controller clock enable register in ctrl reg + - queue-count : number of delivery and completion queues in the controller + - phy-count : number of phys accessible by the controller + - interrupts : For v1 hw: Interrupts for phys, completion queues, and fatal + sources; the interrupts are ordered in 3 groups, as follows: + - Phy interrupts + - Completion queue interrupts + - Fatal interrupts + Phy interrupts : Each phy has 3 interrupt sources: + - broadcast + - phyup + - abnormal + The phy interrupts are ordered into groups of 3 per phy + (broadcast, phyup, and abnormal) in increasing order. + Completion queue interrupts : each completion queue has 1 + interrupt source. + The interrupts are ordered in increasing order. + Fatal interrupts : the fatal interrupts are ordered as follows: + - ECC + - AXI bus + For v2 hw: Interrupts for phys, Sata, and completion queues; + the interrupts are ordered in 3 groups, as follows: + - Phy interrupts + - Sata interrupts + - Completion queue interrupts + Phy interrupts : Each controller has 2 phy interrupts: + - phy up/down + - channel interrupt + Sata interrupts : Each phy on the controller has 1 Sata + interrupt. The interrupts are ordered in increasing + order. + Completion queue interrupts : each completion queue has 1 + interrupt source. The interrupts are ordered in + increasing order. + +Optional main node properties: + - hip06-sas-v2-quirk-amt : when set, indicates that the v2 controller has the + "am-max-transmissions" limitation. + - hisilicon,signal-attenuation : array of 3 32-bit values, containing de-emphasis, + preshoot, and boost attenuation readings for the board. They + are used to describe the signal attenuation of the board. These + values' range is 7600 to 12400, and used to represent -24dB to + 24dB. + The formula is "y = (x-10000)/10000". For example, 10478 + means 4.78dB. + +Example: + sas0: sas@c1000000 { + compatible = "hisilicon,hip05-sas-v1"; + sas-addr = [50 01 88 20 16 00 00 0a]; + reg = <0x0 0xc1000000 0x0 0x10000>; + hisilicon,sas-syscon = <&pcie_sas>; + ctrl-reset-reg = <0xa60>; + ctrl-reset-sts-reg = <0x5a30>; + ctrl-clock-ena-reg = <0x338>; + queue-count = <32>; + phy-count = <8>; + dma-coherent; + interrupt-parent = <&mbigen_dsa>; + interrupts = <259 4>,<263 4>,<264 4>,/* phy0 */ + <269 4>,<273 4>,<274 4>,/* phy1 */ + <279 4>,<283 4>,<284 4>,/* phy2 */ + <289 4>,<293 4>,<294 4>,/* phy3 */ + <299 4>,<303 4>,<304 4>,/* phy4 */ + <309 4>,<313 4>,<314 4>,/* phy5 */ + <319 4>,<323 4>,<324 4>,/* phy6 */ + <329 4>,<333 4>,<334 4>,/* phy7 */ + <336 1>,<337 1>,<338 1>,/* cq0-2 */ + <339 1>,<340 1>,<341 1>,/* cq3-5 */ + <342 1>,<343 1>,<344 1>,/* cq6-8 */ + <345 1>,<346 1>,<347 1>,/* cq9-11 */ + <348 1>,<349 1>,<350 1>,/* cq12-14 */ + <351 1>,<352 1>,<353 1>,/* cq15-17 */ + <354 1>,<355 1>,<356 1>,/* cq18-20 */ + <357 1>,<358 1>,<359 1>,/* cq21-23 */ + <360 1>,<361 1>,<362 1>,/* cq24-26 */ + <363 1>,<364 1>,<365 1>,/* cq27-29 */ + <366 1>,<367 1>/* cq30-31 */ + <376 4>,/* fatal ecc */ + <381 4>;/* fatal axi */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/security/tpm/ibmvtpm.txt b/arch/arm64/boot/dts/vendor/bindings/security/tpm/ibmvtpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..d89f99971368c3adcba6bcc96c47885eac51e4bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/security/tpm/ibmvtpm.txt @@ -0,0 +1,41 @@ +* Device Tree Bindings for IBM Virtual Trusted Platform Module(vtpm) + +Required properties: + +- compatible : property name that conveys the platform architecture + identifiers, as 'IBM,vtpm' +- device_type : specifies type of virtual device +- interrupts : property specifying the interrupt source number and + sense code associated with this virtual I/O Adapters +- ibm,my-drc-index : integer index for the connector between the device + and its parent - present only if Dynamic + Reconfiguration(DR) Connector is enabled +- ibm,#dma-address-cells: specifies the number of cells that are used to + encode the physical address field of dma-window + properties +- ibm,#dma-size-cells : specifies the number of cells that are used to + encode the size field of dma-window properties +- ibm,my-dma-window : specifies DMA window associated with this virtual + IOA +- ibm,loc-code : specifies the unique and persistent location code + associated with this virtual I/O Adapters +- linux,sml-base : 64-bit base address of the reserved memory allocated + for the firmware event log +- linux,sml-size : size of the memory allocated for the firmware event log + +Example (IBM Virtual Trusted Platform Module) +--------------------------------------------- + + vtpm@30000003 { + ibm,#dma-size-cells = <0x2>; + compatible = "IBM,vtpm"; + device_type = "IBM,vtpm"; + ibm,my-drc-index = <0x30000003>; + ibm,#dma-address-cells = <0x2>; + linux,sml-base = <0xc60e 0x0>; + interrupts = <0xa0003 0x0>; + ibm,my-dma-window = <0x10000003 0x0 0x0 0x0 0x10000000>; + ibm,loc-code = "U8286.41A.10082DV-V3-C3"; + reg = <0x30000003>; + linux,sml-size = <0xbce10200>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/security/tpm/st33zp24-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/security/tpm/st33zp24-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dc121b6eace9ad340780a687debc7f3c5e03ec3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/security/tpm/st33zp24-i2c.txt @@ -0,0 +1,34 @@ +* STMicroelectronics SAS. ST33ZP24 TPM SoC + +Required properties: +- compatible: Should be "st,st33zp24-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus + +Optional ST33ZP24 Properties: +- interrupts: GPIO interrupt to which the chip is connected +- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. +If set, power must be present when the platform is going into sleep/hibernate mode. + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2): + +&i2c2 { + + + st33zp24: st33zp24@13 { + + compatible = "st,st33zp24-i2c"; + + reg = <0x13>; + clock-frequency = <400000>; + + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/security/tpm/st33zp24-spi.txt b/arch/arm64/boot/dts/vendor/bindings/security/tpm/st33zp24-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..37198971f17b64a96fc9357d1703fc68d3a6c51c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/security/tpm/st33zp24-spi.txt @@ -0,0 +1,32 @@ +* STMicroelectronics SAS. ST33ZP24 TPM SoC + +Required properties: +- compatible: Should be "st,st33zp24-spi". +- spi-max-frequency: Maximum SPI frequency (<= 10000000). + +Optional ST33ZP24 Properties: +- interrupts: GPIO interrupt to which the chip is connected +- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. +If set, power must be present when the platform is going into sleep/hibernate mode. + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with ST33ZP24 on SPI4): + +&mcspi4 { + + + st33zp24@0 { + + compatible = "st,st33zp24-spi"; + + spi-max-frequency = <10000000>; + + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..a65d7b71e81a2a22bfc23ab79ede461a25d2de37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm-i2c.txt @@ -0,0 +1,26 @@ +* Device Tree Bindings for I2C based Trusted Platform Module(TPM) + +Required properties: + +- compatible : 'manufacturer,model', eg. nuvoton,npct650 +- label : human readable string describing the device, eg. "tpm" +- linux,sml-base : 64-bit base address of the reserved memory allocated for + the firmware event log +- linux,sml-size : size of the memory allocated for the firmware event log + +Optional properties: + +- powered-while-suspended: present when the TPM is left powered on between + suspend and resume (makes the suspend/resume + callbacks do nothing). + +Example (for OpenPower Systems with Nuvoton TPM 2.0 on I2C) +---------------------------------------------------------- + +tpm@57 { + reg = <0x57>; + label = "tpm"; + compatible = "nuvoton,npct650", "nuvoton,npct601"; + linux,sml-base = <0x7f 0xfd450000>; + linux,sml-size = <0x10000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm_tis_mmio.txt b/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm_tis_mmio.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c6304426da1a57e078690fde5c75e4e7cf64a7f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm_tis_mmio.txt @@ -0,0 +1,25 @@ +Trusted Computing Group MMIO Trusted Platform Module + +The TCG defines multi vendor standard for accessing a TPM chip, this +is the standard protocol defined to access the TPM via MMIO. Typically +this interface will be implemented over Intel's LPC bus. + +Refer to the 'TCG PC Client Specific TPM Interface Specification (TIS)' TCG +publication for the specification. + +Required properties: + +- compatible: should contain a string below for the chip, followed by + "tcg,tpm-tis-mmio". Valid chip strings are: + * "atmel,at97sc3204" +- reg: The location of the MMIO registers, should be at least 0x5000 bytes +- interrupts: An optional interrupt indicating command completion. + +Example: + + tpm_tis@90000 { + compatible = "atmel,at97sc3204", "tcg,tpm-tis-mmio"; + reg = <0x90000 0x5000>; + interrupt-parent = <&EIC0>; + interrupts = <1 2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm_tis_spi.txt b/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm_tis_spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b800667da92b82555d74a194b65d201dda86da61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/security/tpm/tpm_tis_spi.txt @@ -0,0 +1,23 @@ +Required properties: +- compatible: should be one of the following + "st,st33htpm-spi" + "infineon,slb9670" + "tcg,tpm_tis-spi" +- spi-max-frequency: Maximum SPI frequency (depends on TPMs). + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBoard xM with TPM_TIS on SPI4): + +&mcspi4 { + + + tpm_tis@0 { + + compatible = "tcg,tpm_tis-spi"; + + spi-max-frequency = <10000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/8250.txt b/arch/arm64/boot/dts/vendor/bindings/serial/8250.txt new file mode 100644 index 0000000000000000000000000000000000000000..aeb6db4e35c3bb816d41da1345f35eed1b83b09c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/8250.txt @@ -0,0 +1,74 @@ +* UART (Universal Asynchronous Receiver/Transmitter) + +Required properties: +- compatible : one of: + - "ns8250" + - "ns16450" + - "ns16550a" + - "ns16550" + - "ns16750" + - "ns16850" + - For Tegra20, must contain "nvidia,tegra20-uart" + - For other Tegra, must contain '"nvidia,-uart", + "nvidia,tegra20-uart"' where is tegra30, tegra114, tegra124, + tegra132, or tegra210. + - "nxp,lpc3220-uart" + - "ralink,rt2880-uart" + - For MediaTek BTIF, must contain '"mediatek,-btif", + "mediatek,mtk-btif"' where is mt7622, mt7623. + - "altr,16550-FIFO32" + - "altr,16550-FIFO64" + - "altr,16550-FIFO128" + - "fsl,16550-FIFO64" + - "fsl,ns16550" + - "ti,da830-uart" + - "aspeed,ast2400-vuart" + - "aspeed,ast2500-vuart" + - "nuvoton,npcm750-uart" + - "serial" if the port type is unknown. +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. +- clock-frequency : the input clock frequency for the UART + or + clocks phandle to refer to the clk used as per Documentation/devicetree + /bindings/clock/clock-bindings.txt + +Optional properties: +- current-speed : the current active speed of the UART. +- reg-offset : offset to apply to the mapbase from the start of the registers. +- reg-shift : quantity to shift the register offsets by. +- reg-io-width : the size (in bytes) of the IO accesses that should be + performed on the device. There are some systems that require 32-bit + accesses to the UART (e.g. TI davinci). +- used-by-rtas : set to indicate that the port is in use by the OpenFirmware + RTAS and should not be registered. +- no-loopback-test: set to indicate that the port does not implements loopback + test mode +- fifo-size: the fifo size of the UART. +- auto-flow-control: one way to enable automatic flow control support. The + driver is allowed to detect support for the capability even without this + property. +- tx-threshold: Specify the TX FIFO low water indication for parts with + programmable TX FIFO thresholds. +- resets : phandle + reset specifier pairs + +Note: +* fsl,ns16550: + ------------ + Freescale DUART is very similar to the PC16552D (and to a + pair of NS16550A), albeit with some nonstandard behavior such as + erratum A-004737 (relating to incorrect BRK handling). + + Represents a single port that is compatible with the DUART found + on many Freescale chips (examples include mpc8349, mpc8548, + mpc8641d, p4080 and ls2085a). + +Example: + + uart@80230000 { + compatible = "ns8250"; + reg = <0x80230000 0x100>; + clock-frequency = <3686400>; + interrupts = <10>; + reg-shift = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/actions,owl-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/actions,owl-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa873eada02de63d19615ba307991005109ebedf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/actions,owl-uart.txt @@ -0,0 +1,16 @@ +Actions Semi Owl UART + +Required properties: +- compatible : "actions,s500-uart", "actions,owl-uart" for S500 + "actions,s900-uart", "actions,owl-uart" for S900 +- reg : Offset and length of the register set for the device. +- interrupts : Should contain UART interrupt. + + +Example: + + uart3: serial@b0126000 { + compatible = "actions,s500-uart", "actions,owl-uart"; + reg = <0xb0126000 0x1000>; + interrupts = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/altera_jtaguart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/altera_jtaguart.txt new file mode 100644 index 0000000000000000000000000000000000000000..55a901051e8fb5c3e64ba359593606cb9fa9a23a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/altera_jtaguart.txt @@ -0,0 +1,5 @@ +Altera JTAG UART + +Required properties: +- compatible : should be "ALTR,juart-1.0" +- compatible : should be "altr,juart-1.0" diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/altera_uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/altera_uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..81bf7ffb1a810a3c337896b46b3ee4f23146b211 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/altera_uart.txt @@ -0,0 +1,8 @@ +Altera UART + +Required properties: +- compatible : should be "ALTR,uart-1.0" +- compatible : should be "altr,uart-1.0" + +Optional properties: +- clock-frequency : frequency of the clock input to the UART diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/amlogic,meson-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/amlogic,meson-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..c06c045126fc9070ca8f4faefc18b17a8de85ee6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/amlogic,meson-uart.txt @@ -0,0 +1,38 @@ +Amlogic Meson SoC UART Serial Interface +======================================= + +The Amlogic Meson SoC UART Serial Interface is present on a large range +of SoCs, and can be present either in the "Always-On" power domain or the +"Everything-Else" power domain. + +The particularity of the "Always-On" Serial Interface is that the hardware +is active since power-on and does not need any clock gating and is usable +as very early serial console. + +Required properties: +- compatible : compatible: value should be different for each SoC family as : + - Meson6 : "amlogic,meson6-uart" + - Meson8 : "amlogic,meson8-uart" + - Meson8b : "amlogic,meson8b-uart" + - GX (GXBB, GXL, GXM) : "amlogic,meson-gx-uart" + eventually followed by : "amlogic,meson-ao-uart" if this UART interface + is in the "Always-On" power domain. +- reg : offset and length of the register set for the device. +- interrupts : identifier to the device interrupt +- clocks : a list of phandle + clock-specifier pairs, one for each + entry in clock names. +- clock-names : + * "xtal" for external xtal clock identifier + * "pclk" for the bus core clock, either the clk81 clock or the gate clock + * "baud" for the source of the baudrate generator, can be either the xtal + or the pclk. + +e.g. +uart_A: serial@84c0 { + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x84c0 0x0 0x14>; + interrupts = ; + /* Use xtal as baud rate clock source */ + clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/arc-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/arc-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..256cc150ca7e55fb2c077f5c72db964dfeb891bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/arc-uart.txt @@ -0,0 +1,25 @@ +* Synopsys ARC UART : Non standard UART used in some of the ARC FPGA boards + +Required properties: +- compatible : "snps,arc-uart" +- reg : offset and length of the register set for the device. +- interrupts : device interrupt +- clock-frequency : the input clock frequency for the UART +- current-speed : baud rate for UART + +e.g. + +arcuart0: serial@c0fc1000 { + compatible = "snps,arc-uart"; + reg = <0xc0fc1000 0x100>; + interrupts = <5>; + clock-frequency = <80000000>; + current-speed = <115200>; +}; + +Note: Each port should have an alias correctly numbered in "aliases" node. + +e.g. +aliases { + serial0 = &arcuart0; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/arm,mps2-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/arm,mps2-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..128cc6aed001081f32abd6a86da15b84e37e7282 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/arm,mps2-uart.txt @@ -0,0 +1,19 @@ +ARM MPS2 UART + +Required properties: +- compatible : Should be "arm,mps2-uart" +- reg : Address and length of the register set +- interrupts : Reference to the UART RX, TX and overrun interrupts + +Required clocking property: +- clocks : The input clock of the UART + + +Examples: + +uart0: serial@40004000 { + compatible = "arm,mps2-uart"; + reg = <0x40004000 0x1000>; + interrupts = <0 1 12>; + clocks = <&sysclk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/arm_sbsa_uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/arm_sbsa_uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..4163e7eb7763077ef674ce04ffe62f4f9a8867cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/arm_sbsa_uart.txt @@ -0,0 +1,10 @@ +* ARM SBSA defined generic UART +This UART uses a subset of the PL011 registers and consequently lives +in the PL011 driver. It's baudrate and other communication parameters +cannot be adjusted at runtime, so it lacks a clock specifier here. + +Required properties: +- compatible: must be "arm,sbsa-uart" +- reg: exactly one register range +- interrupts: exactly one interrupt specifier +- current-speed: the (fixed) baud rate set by the firmware diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/atmel-usart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/atmel-usart.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c0d6b2f53e4c96ae8855746733cbbf1cbeaa11a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/atmel-usart.txt @@ -0,0 +1,64 @@ +* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART) + +Required properties: +- compatible: Should be "atmel,-usart" or "atmel,-dbgu" + The compatible indicated will be the first SoC to support an + additional mode or an USART new feature. + For the dbgu UART, use "atmel,-dbgu", "atmel,-usart" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt +- clock-names: tuple listing input clock names. + Required elements: "usart" +- clocks: phandles to input clocks. + +Optional properties: +- atmel,use-dma-rx: use of PDC or DMA for receiving data +- atmel,use-dma-tx: use of PDC or DMA for transmitting data +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD line respectively. + It will use specified PIO instead of the peripheral function pin for the USART feature. + If unsure, don't specify this property. +- add dma bindings for dma transfer: + - dmas: DMA specifier, consisting of a phandle to DMA controller node, + memory peripheral interface and USART DMA channel ID, FIFO configuration. + Refer to dma.txt and atmel-dma.txt for details. + - dma-names: "rx" for RX channel, "tx" for TX channel. +- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO + capable USARTs. +- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt + + compatible description: +- at91rm9200: legacy USART support +- at91sam9260: generic USART implementation for SAM9 SoCs + +Example: +- use PDC: + usart0: serial@fff8c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff8c000 0x4000>; + interrupts = <7>; + clocks = <&usart0_clk>; + clock-names = "usart"; + atmel,use-dma-rx; + atmel,use-dma-tx; + rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>; + cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>; + dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>; + dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>; + dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>; + rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>; + }; + +- use DMA: + usart0: serial@f001c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf001c000 0x100>; + interrupts = <12 4 5>; + clocks = <&usart0_clk>; + clock-names = "usart"; + atmel,use-dma-rx; + atmel,use-dma-tx; + dmas = <&dma0 2 0x3>, + <&dma0 2 0x204>; + dma-names = "tx", "rx"; + atmel,fifo-size = <32>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/brcm,bcm2835-aux-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/brcm,bcm2835-aux-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5cc6297cd1b554183da4d189c992cdf3b7fc1d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/brcm,bcm2835-aux-uart.txt @@ -0,0 +1,18 @@ +* BCM2835 AUXILIAR UART + +Required properties: + +- compatible: "brcm,bcm2835-aux-uart" +- reg: The base address of the UART register bank. +- interrupts: A single interrupt specifier. +- clocks: Clock driving the hardware; used to figure out the baud rate + divisor. + +Example: + + uart1: serial@7e215040 { + compatible = "brcm,bcm2835-aux-uart"; + reg = <0x7e215040 0x40>; + interrupts = <1 29>; + clocks = <&aux BCM2835_AUX_CLOCK_UART>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/brcm,bcm6345-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/brcm,bcm6345-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b2b0460259a76b95401cfe7565e1a13621ac470 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/brcm,bcm6345-uart.txt @@ -0,0 +1,36 @@ +* BCM63xx UART + +Required properties: + +- compatible: "brcm,bcm6345-uart" + +- reg: The base address of the UART register bank. + +- interrupts: A single interrupt specifier. + +- clocks: Clock driving the hardware; used to figure out the baud rate + divisor. + + +Optional properties: + +- clock-names: Should be "refclk". + +Example: + + uart0: serial@14e00520 { + compatible = "brcm,bcm6345-uart"; + reg = <0x14e00520 0x18>; + interrupt-parent = <&periph_intc>; + interrupts = <2>; + clocks = <&periph_clk>; + clock-names = "refclk"; + }; + + clocks { + periph_clk: periph_clk@0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <54000000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/cavium-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/cavium-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..87a6c375cd44dbaee054d9994aaa47c3e04fe001 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/cavium-uart.txt @@ -0,0 +1,19 @@ +* Universal Asynchronous Receiver/Transmitter (UART) + +- compatible: "cavium,octeon-3860-uart" + + Compatibility with all cn3XXX, cn5XXX and cn6XXX SOCs. + +- reg: The base address of the UART register bank. + +- interrupts: A single interrupt specifier. + +- current-speed: Optional, the current bit rate in bits per second. + +Example: + uart1: serial@1180000000c00 { + compatible = "cavium,octeon-3860-uart","ns16550"; + reg = <0x11800 0x00000c00 0x0 0x400>; + current-speed = <115200>; + interrupts = <0 35>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/cdns,uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/cdns,uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..227bb770b0276af8cb716bd89d88e8c055c168f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/cdns,uart.txt @@ -0,0 +1,22 @@ +Binding for Cadence UART Controller + +Required properties: +- compatible : + Use "xlnx,xuartps","cdns,uart-r1p8" for Zynq-7xxx SoC. + Use "xlnx,zynqmp-uart","cdns,uart-r1p12" for Zynq Ultrascale+ MPSoC. +- reg: Should contain UART controller registers location and length. +- interrupts: Should contain UART controller interrupts. +- clocks: Must contain phandles to the UART clocks + See ../clocks/clock-bindings.txt for details. +- clock-names: Tuple to identify input clocks, must contain "uart_clk" and "pclk" + See ../clocks/clock-bindings.txt for details. + + +Example: + uart@e0000000 { + compatible = "cdns,uart-r1p8"; + clocks = <&clkc 23>, <&clkc 40>; + clock-names = "uart_clk", "pclk"; + reg = <0xE0000000 0x1000>; + interrupts = <0 27 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/cirrus,clps711x-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/cirrus,clps711x-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..07013fa60a4849e795ebcd9dce5e0f119b2c11b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/cirrus,clps711x-uart.txt @@ -0,0 +1,31 @@ +* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART) + +Required properties: +- compatible: Should be "cirrus,ep7209-uart". +- reg: Address and length of the register set for the device. +- interrupts: Should contain UART TX and RX interrupt. +- clocks: Should contain UART core clock number. +- syscon: Phandle to SYSCON node, which contain UART control bits. + +Optional properties: +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD + line respectively. + +Note: Each UART port should have an alias correctly numbered +in "aliases" node. + +Example: + aliases { + serial0 = &uart1; + }; + + uart1: uart@80000480 { + compatible = "cirrus,ep7312-uart","cirrus,ep7209-uart"; + reg = <0x80000480 0x80>; + interrupts = <12 13>; + clocks = <&clks 11>; + syscon = <&syscon1>; + cts-gpios = <&sysgpio 0 GPIO_ACTIVE_LOW>; + dsr-gpios = <&sysgpio 1 GPIO_ACTIVE_LOW>; + dcd-gpios = <&sysgpio 2 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/digicolor-usart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/digicolor-usart.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d3ede66889ddc9949a35847389892b6ca5a5b0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/digicolor-usart.txt @@ -0,0 +1,27 @@ +Binding for Conexant Digicolor USART + +Note: this binding is only applicable for using the USART peripheral as +UART. USART also support synchronous serial protocols like SPI and I2S. Use +the binding that matches the wiring of your system. + +Required properties: +- compatible : should be "cnxt,cx92755-usart". +- reg: Should contain USART controller registers location and length. +- interrupts: Should contain a single USART controller interrupt. +- clocks: Must contain phandles to the USART clock + See ../clocks/clock-bindings.txt for details. + +Note: Each UART port should have an alias correctly numbered +in "aliases" node. + +Example: + aliases { + serial0 = &uart0; + }; + + uart0: uart@f0000740 { + compatible = "cnxt,cx92755-usart"; + reg = <0xf0000740 0x20>; + clocks = <&main_clk>; + interrupts = <44>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/efm32-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/efm32-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f8d8fde0c1c2a0728ac3c331d694e7a1bdbd423 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/efm32-uart.txt @@ -0,0 +1,20 @@ +* Energymicro efm32 UART + +Required properties: +- compatible : Should be "energymicro,efm32-uart" +- reg : Address and length of the register set +- interrupts : Should contain uart interrupt + +Optional properties: +- energymicro,location : Decides the location of the USART I/O pins. + Allowed range : [0 .. 5] + Default: 0 + +Example: + +uart@4000c400 { + compatible = "energymicro,efm32-uart"; + reg = <0x4000c400 0x400>; + interrupts = <15>; + energymicro,location = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/fsl-imx-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/fsl-imx-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..35957cbf1571e4f674e7e6602807cabad140f78f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/fsl-imx-uart.txt @@ -0,0 +1,36 @@ +* Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART) + +Required properties: +- compatible : Should be "fsl,-uart" +- reg : Address and length of the register set for the device +- interrupts : Should contain uart interrupt + +Optional properties: +- fsl,dte-mode : Indicate the uart works in DTE mode. The uart works + in DCE mode by default. +- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, + linux,rs485-enabled-at-boot-time: see rs485.txt. Note that for RS485 + you must enable either the "uart-has-rtscts" or the "rts-gpios" + properties. In case you use "uart-has-rtscts" the signal that controls + the transceiver is actually CTS_B, not RTS_B. CTS_B is always output, + and RTS_B is input, regardless of dte-mode. + +Please check Documentation/devicetree/bindings/serial/serial.txt +for the complete list of generic properties. + +Note: Each uart controller should have an alias correctly numbered +in "aliases" node. + +Example: + +aliases { + serial0 = &uart1; +}; + +uart1: serial@73fbc000 { + compatible = "fsl,imx51-uart", "fsl,imx21-uart"; + reg = <0x73fbc000 0x4000>; + interrupts = <31>; + uart-has-rtscts; + fsl,dte-mode; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/fsl-lpuart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/fsl-lpuart.txt new file mode 100644 index 0000000000000000000000000000000000000000..6bd3f2e93d61d9818bda71c6c328c407b082a884 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/fsl-lpuart.txt @@ -0,0 +1,35 @@ +* Freescale low power universal asynchronous receiver/transmitter (lpuart) + +Required properties: +- compatible : + - "fsl,vf610-lpuart" for lpuart compatible with the one integrated + on Vybrid vf610 SoC with 8-bit register organization + - "fsl,ls1021a-lpuart" for lpuart compatible with the one integrated + on LS1021A SoC with 32-bit big-endian register organization + - "fsl,imx7ulp-lpuart" for lpuart compatible with the one integrated + on i.MX7ULP SoC with 32-bit little-endian register organization +- reg : Address and length of the register set for the device +- interrupts : Should contain uart interrupt +- clocks : phandle + clock specifier pairs, one for each entry in clock-names +- clock-names : should contain: "ipg" - the uart clock + +Optional properties: +- dmas: A list of two dma specifiers, one for each entry in dma-names. +- dma-names: should contain "tx" and "rx". +- rs485-rts-delay, rs485-rts-active-low, rs485-rx-during-tx, + linux,rs485-enabled-at-boot-time: see rs485.txt + +Note: Optional properties for DMA support. Write them both or both not. + +Example: + +uart0: serial@40027000 { + compatible = "fsl,vf610-lpuart"; + reg = <0x40027000 0x1000>; + interrupts = <0 61 0x00>; + clocks = <&clks VF610_CLK_UART0>; + clock-names = "ipg"; + dmas = <&edma0 0 2>, + <&edma0 0 3>; + dma-names = "rx","tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/fsl-mxs-auart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/fsl-mxs-auart.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c96d41899f19532eda9e9bff2be34ebce97ce4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/fsl-mxs-auart.txt @@ -0,0 +1,53 @@ +* Freescale MXS Application UART (AUART) + +Required properties for all SoCs: +- compatible : Should be one of fallowing variants: + "fsl,imx23-auart" - Freescale i.MX23 + "fsl,imx28-auart" - Freescale i.MX28 + "alphascale,asm9260-auart" - Alphascale ASM9260 +- reg : Address and length of the register set for the device +- interrupts : Should contain the auart interrupt numbers +- dmas: DMA specifier, consisting of a phandle to DMA controller node + and AUART DMA channel ID. + Refer to dma.txt and fsl-mxs-dma.txt for details. +- dma-names: "rx" for RX channel, "tx" for TX channel. + +Required properties for "alphascale,asm9260-auart": +- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt +- clock-names : should be set to + "mod" - source for tick counter. + "ahb" - ahb gate. + +Optional properties: +- uart-has-rtscts : Indicate the UART has RTS and CTS lines + for hardware flow control, + it also means you enable the DMA support for this UART. +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD + line respectively. It will use specified PIO instead of the peripheral + function pin for the USART feature. + If unsure, don't specify this property. + +Example: +auart0: serial@8006a000 { + compatible = "fsl,imx28-auart", "fsl,imx23-auart"; + reg = <0x8006a000 0x2000>; + interrupts = <112>; + dmas = <&dma_apbx 8>, <&dma_apbx 9>; + dma-names = "rx", "tx"; + cts-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; +}; + +Note: Each auart port should have an alias correctly numbered in "aliases" +node. + +Example: + +aliases { + serial0 = &auart0; + serial1 = &auart1; + serial2 = &auart2; + serial3 = &auart3; + serial4 = &auart4; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/ingenic,uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/ingenic,uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3c6406d5cfe528fb776b8a4edd4eb37b4ff6f2d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/ingenic,uart.txt @@ -0,0 +1,27 @@ +* Ingenic SoC UART + +Required properties: +- compatible : One of: + - "ingenic,jz4740-uart", + - "ingenic,jz4760-uart", + - "ingenic,jz4770-uart", + - "ingenic,jz4775-uart", + - "ingenic,jz4780-uart". +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. +- clocks : phandles to the module & baud clocks. +- clock-names: tuple listing input clock names. + Required elements: "baud", "module" + +Example: + +uart0: serial@10030000 { + compatible = "ingenic,jz4740-uart"; + reg = <0x10030000 0x100>; + + interrupt-parent = <&intc>; + interrupts = <9>; + + clocks = <&ext>, <&cgu JZ4740_CLK_UART0>; + clock-names = "baud", "module"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/lantiq_asc.txt b/arch/arm64/boot/dts/vendor/bindings/serial/lantiq_asc.txt new file mode 100644 index 0000000000000000000000000000000000000000..3acbd309ab9d1add560c2e0f2155e935fda476bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/lantiq_asc.txt @@ -0,0 +1,16 @@ +Lantiq SoC ASC serial controller + +Required properties: +- compatible : Should be "lantiq,asc" +- reg : Address and length of the register set for the device +- interrupts: the 3 (tx rx err) interrupt numbers. The interrupt specifier + depends on the interrupt-parent interrupt controller. + +Example: + +asc1: serial@e100c00 { + compatible = "lantiq,asc"; + reg = <0xE100C00 0x400>; + interrupt-parent = <&icu0>; + interrupts = <112 113 114>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/maxim,max310x.txt b/arch/arm64/boot/dts/vendor/bindings/serial/maxim,max310x.txt new file mode 100644 index 0000000000000000000000000000000000000000..79e10a05a96ac94687faee98693b3b5dbc6e0343 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/maxim,max310x.txt @@ -0,0 +1,48 @@ +* Maxim MAX310X advanced Universal Asynchronous Receiver-Transmitter (UART) + +Required properties: +- compatible: Should be one of the following: + - "maxim,max3107" for Maxim MAX3107, + - "maxim,max3108" for Maxim MAX3108, + - "maxim,max3109" for Maxim MAX3109, + - "maxim,max14830" for Maxim MAX14830. +- reg: SPI chip select number. +- interrupts: Specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends on the + parent interrupt controller. +- clocks: phandle to the IC source clock. +- clock-names: Should be "xtal" if clock is an external crystal or + "osc" if an external clock source is used. + +Optional properties: +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be two. The first cell is the GPIO number and + the second cell is used to specify the GPIO polarity: + 0 = active high, + 1 = active low. + +Example: + +/ { + clocks { + spi_uart_clk: osc_max14830 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <3686400>; + }; + + }; +}; + +&spi0 { + max14830: max14830@0 { + compatible = "maxim,max14830"; + reg = <0>; + clocks = <&spi_uart_clk>; + clock-names = "osc"; + interrupt-parent = <&gpio3>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/microchip,pic32-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/microchip,pic32-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8dd440e97470b3f3c237545d2b7ba879caae411 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/microchip,pic32-uart.txt @@ -0,0 +1,29 @@ +* Microchip Universal Asynchronous Receiver Transmitter (UART) + +Required properties: +- compatible: Should be "microchip,pic32mzda-uart" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt +- clocks: Phandle to the clock. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt +- pinctrl-names: A pinctrl state names "default" must be defined. +- pinctrl-0: Phandle referencing pin configuration of the UART peripheral. + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +Optional properties: +- cts-gpios: CTS pin for UART + +Example: + uart1: serial@1f822000 { + compatible = "microchip,pic32mzda-uart"; + reg = <0x1f822000 0x50>; + interrupts = <112 IRQ_TYPE_LEVEL_HIGH>, + <113 IRQ_TYPE_LEVEL_HIGH>, + <114 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rootclk PB2CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1 + &pinctrl_uart1_cts + &pinctrl_uart1_rts>; + cts-gpios = <&gpio1 15 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/mrvl,pxa-ssp.txt b/arch/arm64/boot/dts/vendor/bindings/serial/mrvl,pxa-ssp.txt new file mode 100644 index 0000000000000000000000000000000000000000..d10cc06c0c37e1389ba9ba996924e68b1e505aba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/mrvl,pxa-ssp.txt @@ -0,0 +1,64 @@ +Device tree bindings for Marvell PXA SSP ports + +Required properties: + + - compatible: Must be one of + mrvl,pxa25x-ssp + mvrl,pxa25x-nssp + mrvl,pxa27x-ssp + mrvl,pxa3xx-ssp + mvrl,pxa168-ssp + mrvl,pxa910-ssp + mrvl,ce4100-ssp + + - reg: The memory base + - dmas: Two dma phandles, one for rx, one for tx + - dma-names: Must be "rx", "tx" + + +Example for PXA3xx: + + ssp0: ssp@41000000 { + compatible = "mrvl,pxa3xx-ssp"; + reg = <0x41000000 0x40>; + ssp-id = <1>; + interrupts = <24>; + clock-names = "pxa27x-ssp.0"; + dmas = <&dma 13 + &dma 14>; + dma-names = "rx", "tx"; + }; + + ssp1: ssp@41700000 { + compatible = "mrvl,pxa3xx-ssp"; + reg = <0x41700000 0x40>; + ssp-id = <2>; + interrupts = <16>; + clock-names = "pxa27x-ssp.1"; + dmas = <&dma 15 + &dma 16>; + dma-names = "rx", "tx"; + }; + + ssp2: ssp@41900000 { + compatibl3 = "mrvl,pxa3xx-ssp"; + reg = <0x41900000 0x40>; + ssp-id = <3>; + interrupts = <0>; + clock-names = "pxa27x-ssp.2"; + dmas = <&dma 66 + &dma 67>; + dma-names = "rx", "tx"; + }; + + ssp3: ssp@41a00000 { + compatible = "mrvl,pxa3xx-ssp"; + reg = <0x41a00000 0x40>; + ssp-id = <4>; + interrupts = <13>; + clock-names = "pxa27x-ssp.3"; + dmas = <&dma 2 + &dma 3>; + dma-names = "rx", "tx"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/mrvl-serial.txt b/arch/arm64/boot/dts/vendor/bindings/serial/mrvl-serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..d744340de887ce650853185e1f0360ee4c8bd829 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/mrvl-serial.txt @@ -0,0 +1,4 @@ +PXA UART controller + +Required properties: +- compatible : should be "mrvl,mmp-uart" or "mrvl,pxa-uart". diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/msm_serial_hs.txt b/arch/arm64/boot/dts/vendor/bindings/serial/msm_serial_hs.txt new file mode 100644 index 0000000000000000000000000000000000000000..24f75100c62ac4d6d66e0f0d8cb969928da30a17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/msm_serial_hs.txt @@ -0,0 +1,121 @@ +* Qualcomm Technologies, Inc. MSM HSUART + +Required properties: +- compatible : + - "qcom,msm-hsuart-v14" to be used for UARTDM Core v1.4 +- reg : offset and length of the register set for both the device, + uart core and bam core +- reg-names : + - "core_mem" to be used as name of the uart core + - "bam_mem" to be used as name of the bam core +- interrupts : interrupts for both the device,uart core and bam core +- interrupt-names : + - "core_irq" to be used as uart irq + - "bam irq" to be used as bam irq +- #interrupt-cells: Specifies the number of cells needed to encode an interrupt + source. The type shall be a and the value shall be 1 +- #address-cells: Specifies the number of cells needed to encode an address. + The type shall be and the value shall be 0 +- interrupt-parent = It is needed for interrupt mapping +- bam-tx-ep-pipe-index : BAM TX Endpoint Pipe Index for HSUART +- bam-rx-ep-pipe-index : BAM RX Endpoint Pipe Index for HSUART + +BLSP has a static pipe allocation and assumes a pair-pipe for each uart core. +Pipes [2*i : 2*i+1] are allocated for UART cores where i = [0 : 5]. +Hence, Minimum and Maximum permitted value of endpoint pipe index to be used +with uart core is 0 and 11 respectively. + +There is one HSUART block used in MSM devices, +"qcom,msm-hsuart-v14". The msm-serial-hs driver is +able to handle this, and matches against the "qcom,msm-hsuart-v14" +as the compatibility. + +The registers for the "qcom,msm-hsuart-v14" device need to specify both +register blocks - uart core and bam core. + +Example: + + uart7: uart@f995d000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0xf995d000 0x1000>, + <0xf9944000 0x5000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq"; + #address-cells = <0>; + interrupt-parent = <&uart7>; + interrupts = <0 1>; + #interrupt-cells = <1>; + interrupt-map = <0 &intc 0 113 0 + 1 &intc 0 239 0> + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + }; + +Optional properties: +- qcom,-gpio : handle to the GPIO node, see "gpios property" in +Documentation/devicetree/bindings/gpio/gpio.txt. +"gpio-name" can be "tx", "rx", "cts" and "rfr" based on number of UART GPIOs +need to configured. +Gpio's are optional if it is required to be not configured by UART driver or +case where there is nothing connected and we want to use internal loopback mode +for uart. +- qcom, wakeup_irq : UART RX GPIO IRQ line to be configured as wakeup source. +- qcom,inject-rx-on-wakeup : inject_rx_on_wakeup enables feature where on +receiving interrupt with UART RX GPIO IRQ line (i.e. above wakeup_irq property), +HSUART driver injects provided character with property rx_to_inject. +- qcom, rx-char-to-inject : The character to be inserted on wakeup. +- qcom, no-suspend-delay : This decides system to go to suspend immediately +or not + +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for +below optional properties: + - qcom,msm_bus,name + - qcom,msm_bus,num_cases + - qcom,msm_bus,active_only + - qcom,msm_bus,num_paths + - qcom,msm_bus,vectors + +Aliases : +An alias may be optionally used to bind the UART device to a TTY device +(ttyHS) with a given alias number. Aliases are of the form +uart where is an integer representing the alias number to use. +On systems with multiple UART devices present, an alias may optionally be +defined for such devices. The alias value should be from 0 to 255. + +Example: + + aliases { + uart4 = &uart7; // This device will be enumerated as ttyHS4 + }; + + uart7: uart@f995d000 { + compatible = "qcom,msm-hsuart-v14" + reg = <0x19c40000 0x1000">, + <0xf9944000 0x5000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&uart7>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 113 0 + 1 &intc 0 239 0 + 2 &msmgpio 42 0>; + qcom,tx-gpio = <&msmgpio 41 0x00>; + qcom,rx-gpio = <&msmgpio 42 0x00>; + qcom,cts-gpio = <&msmgpio 43 0x00>; + qcom,rfr-gpio = <&msmgpio 44 0x00>; + qcom,inject-rx-on-wakeup = <1>; + qcom,rx-char-to-inject = <0xFD>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + + qcom,msm-bus,name = "uart7"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/mtk-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/mtk-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..742cb470595ba4d7e2a3e467328d33a8bf5335b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/mtk-uart.txt @@ -0,0 +1,42 @@ +* Mediatek Universal Asynchronous Receiver/Transmitter (UART) + +Required properties: +- compatible should contain: + * "mediatek,mt2701-uart" for MT2701 compatible UARTS + * "mediatek,mt2712-uart" for MT2712 compatible UARTS + * "mediatek,mt6580-uart" for MT6580 compatible UARTS + * "mediatek,mt6582-uart" for MT6582 compatible UARTS + * "mediatek,mt6589-uart" for MT6589 compatible UARTS + * "mediatek,mt6755-uart" for MT6755 compatible UARTS + * "mediatek,mt6765-uart" for MT6765 compatible UARTS + * "mediatek,mt6795-uart" for MT6795 compatible UARTS + * "mediatek,mt6797-uart" for MT6797 compatible UARTS + * "mediatek,mt7622-uart" for MT7622 compatible UARTS + * "mediatek,mt7623-uart" for MT7623 compatible UARTS + * "mediatek,mt8127-uart" for MT8127 compatible UARTS + * "mediatek,mt8135-uart" for MT8135 compatible UARTS + * "mediatek,mt8173-uart" for MT8173 compatible UARTS + * "mediatek,mt6577-uart" for MT6577 and all of the above + +- reg: The base address of the UART register bank. + +- interrupts: A single interrupt specifier. + +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names: + - "baud": The clock the baudrate is derived from + - "bus": The bus clock for register accesses (optional) + +For compatibility with older device trees an unnamed clock is used for the +baud clock if the baudclk does not exist. Do not use this for new designs. + +Example: + + uart0: serial@11006000 { + compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart"; + reg = <0x11006000 0x400>; + interrupts = ; + clocks = <&uart_clk>, <&bus_clk>; + clock-names = "baud", "bus"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/mvebu-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/mvebu-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7e0e32b9ac62c1029ba93998b8257ce71478de4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/mvebu-uart.txt @@ -0,0 +1,53 @@ +* Marvell UART : Non standard UART used in some of Marvell EBU SoCs + e.g., Armada-3700. + +Required properties: +- compatible: + - "marvell,armada-3700-uart" for the standard variant of the UART + (32 bytes FIFO, no DMA, level interrupts, 8-bit access to the + FIFO, baudrate limited to 230400). + - "marvell,armada-3700-uart-ext" for the extended variant of the + UART (128 bytes FIFO, DMA, front interrupts, 8-bit or 32-bit + accesses to the FIFO, baudrate unlimited by the dividers). +- reg: offset and length of the register set for the device. +- clocks: UART reference clock used to derive the baudrate. If no clock + is provided (possible only with the "marvell,armada-3700-uart" + compatible string for backward compatibility), it will only work + if the baudrate was initialized by the bootloader and no baudrate + change will then be possible. +- interrupts: + - Must contain three elements for the standard variant of the IP + (marvell,armada-3700-uart): "uart-sum", "uart-tx" and "uart-rx", + respectively the UART sum interrupt, the UART TX interrupt and + UART RX interrupt. A corresponding interrupt-names property must + be defined. + - Must contain two elements for the extended variant of the IP + (marvell,armada-3700-uart-ext): "uart-tx" and "uart-rx", + respectively the UART TX interrupt and the UART RX interrupt. A + corresponding interrupt-names property must be defined. + - For backward compatibility reasons, a single element interrupts + property is also supported for the standard variant of the IP, + containing only the UART sum interrupt. This form is deprecated + and should no longer be used. + +Example: + uart0: serial@12000 { + compatible = "marvell,armada-3700-uart"; + reg = <0x12000 0x200>; + clocks = <&xtalclk>; + interrupts = + , + , + ; + interrupt-names = "uart-sum", "uart-tx", "uart-rx"; + }; + + uart1: serial@12200 { + compatible = "marvell,armada-3700-uart-ext"; + reg = <0x12200 0x30>; + clocks = <&xtalclk>; + interrupts = + , + ; + interrupt-names = "uart-tx", "uart-rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/nvidia,tegra20-hsuart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/nvidia,tegra20-hsuart.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7edf732eb7f5716f8feb5e9d8398cb8a3ac1dbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/nvidia,tegra20-hsuart.txt @@ -0,0 +1,36 @@ +NVIDIA Tegra20/Tegra30 high speed (DMA based) UART controller driver. + +Required properties: +- compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart". +- reg: Should contain UART controller registers location and length. +- interrupts: Should contain UART controller interrupts. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - serial +- dmas : Must contain an entry for each entry in dma-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx + +Optional properties: +- nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable + only if all 8 lines of UART controller are pinmuxed. + +Example: + +serial@70006000 { + compatible = "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart"; + reg = <0x70006000 0x40>; + reg-shift = <2>; + interrupts = <0 36 0x04>; + nvidia,enable-modem-interrupt; + clocks = <&tegra_car 6>; + resets = <&tegra_car 6>; + reset-names = "serial"; + dmas = <&apbdma 8>, <&apbdma 8>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/nxp,lpc1850-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/nxp,lpc1850-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..04e23e63ee4f343b140e60d96be9f94cbb32f113 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/nxp,lpc1850-uart.txt @@ -0,0 +1,28 @@ +* NXP LPC1850 UART + +Required properties: +- compatible : "nxp,lpc1850-uart", "ns16550a". +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. +- clocks : phandle to the input clocks. +- clock-names : required elements: "uartclk", "reg". + +Optional properties: +- dmas : Two or more DMA channel specifiers following the + convention outlined in bindings/dma/dma.txt +- dma-names : Names for the dma channels, if present. There must + be at least one channel named "tx" for transmit + and named "rx" for receive. + +Since it's also possible to also use the of_serial.c driver all +parameters from 8250.txt also apply but are optional. + +Example: +uart0: serial@40081000 { + compatible = "nxp,lpc1850-uart", "ns16550a"; + reg = <0x40081000 0x1000>; + reg-shift = <2>; + interrupts = <24>; + clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>; + clock-names = "uartclk", "reg"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/nxp,sc16is7xx.txt b/arch/arm64/boot/dts/vendor/bindings/serial/nxp,sc16is7xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7921a8e276b67ad76f4fb6f0b969a882bb93633 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/nxp,sc16is7xx.txt @@ -0,0 +1,66 @@ +* NXP SC16IS7xx advanced Universal Asynchronous Receiver-Transmitter (UART) +* i2c as bus + +Required properties: +- compatible: Should be one of the following: + - "nxp,sc16is740" for NXP SC16IS740, + - "nxp,sc16is741" for NXP SC16IS741, + - "nxp,sc16is750" for NXP SC16IS750, + - "nxp,sc16is752" for NXP SC16IS752, + - "nxp,sc16is760" for NXP SC16IS760, + - "nxp,sc16is762" for NXP SC16IS762. +- reg: I2C address of the SC16IS7xx device. +- interrupts: Should contain the UART interrupt +- clocks: Reference to the IC source clock. + +Optional properties: +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be two. The first cell is the GPIO number and + the second cell is used to specify the GPIO polarity: + 0 = active high, + 1 = active low. + +Example: + sc16is750: sc16is750@51 { + compatible = "nxp,sc16is750"; + reg = <0x51>; + clocks = <&clk20m>; + interrupt-parent = <&gpio3>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; + +* spi as bus + +Required properties: +- compatible: Should be one of the following: + - "nxp,sc16is740" for NXP SC16IS740, + - "nxp,sc16is741" for NXP SC16IS741, + - "nxp,sc16is750" for NXP SC16IS750, + - "nxp,sc16is752" for NXP SC16IS752, + - "nxp,sc16is760" for NXP SC16IS760, + - "nxp,sc16is762" for NXP SC16IS762. +- reg: SPI chip select number. +- interrupts: Specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends on the + parent interrupt controller. +- clocks: phandle to the IC source clock. + +Optional properties: +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Should be two. The first cell is the GPIO number and + the second cell is used to specify the GPIO polarity: + 0 = active high, + 1 = active low. + +Example: + sc16is750: sc16is750@0 { + compatible = "nxp,sc16is750"; + reg = <0>; + clocks = <&clk20m>; + interrupt-parent = <&gpio3>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/nxp-lpc32xx-hsuart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/nxp-lpc32xx-hsuart.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d439dfc1aa5bad5215ec62ea583dbf97b34a5e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/nxp-lpc32xx-hsuart.txt @@ -0,0 +1,14 @@ +* NXP LPC32xx SoC High Speed UART + +Required properties: +- compatible: Should be "nxp,lpc3220-hsuart" +- reg: Should contain registers location and length +- interrupts: Should contain interrupt + +Example: + + uart1: serial@40014000 { + compatible = "nxp,lpc3220-hsuart"; + reg = <0x40014000 0x1000>; + interrupts = <26 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/omap_serial.txt b/arch/arm64/boot/dts/vendor/bindings/serial/omap_serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..c35d5ece11562f3b020f5f3819202aef72b082af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/omap_serial.txt @@ -0,0 +1,36 @@ +OMAP UART controller + +Required properties: +- compatible : should be "ti,am654-uart" for AM654 controllers +- compatible : should be "ti,omap2-uart" for OMAP2 controllers +- compatible : should be "ti,omap3-uart" for OMAP3 controllers +- compatible : should be "ti,omap4-uart" for OMAP4 controllers +- compatible : should be "ti,am4372-uart" for AM437x controllers +- compatible : should be "ti,am3352-uart" for AM335x controllers +- compatible : should be "ti,dra742-uart" for DRA7x controllers +- reg : address and length of the register space +- interrupts or interrupts-extended : Should contain the uart interrupt + specifier or both the interrupt + controller phandle and interrupt + specifier. +- ti,hwmods : Must be "uart", n being the instance number (1-based) + +Optional properties: +- clock-frequency : frequency of the clock input to the UART +- dmas : DMA specifier, consisting of a phandle to the DMA controller + node and a DMA channel number. +- dma-names : "rx" for receive channel, "tx" for transmit channel. +- rs485-rts-delay, rs485-rx-during-tx, linux,rs485-enabled-at-boot-time: see rs485.txt +- rs485-rts-active-high: drive RTS high when sending (default is low). + +Example: + + uart4: serial@49042000 { + compatible = "ti,omap3-uart"; + reg = <0x49042000 0x400>; + interrupts = <80>; + dmas = <&sdma 81 &sdma 82>; + dma-names = "tx", "rx"; + ti,hwmods = "uart4"; + clock-frequency = <48000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/pl011.txt b/arch/arm64/boot/dts/vendor/bindings/serial/pl011.txt new file mode 100644 index 0000000000000000000000000000000000000000..77863aefe9ef1eafe648b530c1570333aea7940b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/pl011.txt @@ -0,0 +1,51 @@ +* ARM AMBA Primecell PL011 serial UART + +Required properties: +- compatible: must be "arm,primecell", "arm,pl011", "zte,zx296702-uart" +- reg: exactly one register range with length 0x1000 +- interrupts: exactly one interrupt specifier + +Optional properties: +- pinctrl: + When present, must have one state named "default", + and may contain a second name named "sleep". The former + state sets up pins for ordinary operation whereas + the latter state will put the associated pins to sleep + when the UART is unused +- clocks: + When present, the first clock listed must correspond to + the clock named UARTCLK on the IP block, i.e. the clock + to the external serial line, whereas the second clock + must correspond to the PCLK clocking the internal logic + of the block. Just listing one clock (the first one) is + deprecated. +- clock-names: + When present, the first clock listed must be named + "uartclk" and the second clock listed must be named + "apb_pclk" +- dmas: + When present, may have one or two dma channels. + The first one must be named "rx", the second one + must be named "tx". +- auto-poll: + Enables polling when using RX DMA. +- poll-rate-ms: + Rate at which poll occurs when auto-poll is set, + default 100ms. +- poll-timeout-ms: + Poll timeout when auto-poll is set, default + 3000ms. + +See also bindings/arm/primecell.txt + +Example: + +uart@80120000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x80120000 0x1000>; + interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>; + dma-names = "rx", "tx"; + clocks = <&foo_clk>, <&bar_clk>; + clock-names = "uartclk", "apb_pclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/qca,ar9330-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/qca,ar9330-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d65126bd1d7736ed7a6b88b0631d64b532a4c69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/qca,ar9330-uart.txt @@ -0,0 +1,31 @@ +* Qualcomm Atheros AR9330 High-Speed UART + +Required properties: + +- compatible: Must be "qca,ar9330-uart" + +- reg: Specifies the physical base address of the controller and + the length of the memory mapped region. + +- interrupts: Specifies the interrupt source of the parent interrupt + controller. The format of the interrupt specifier depends on the + parent interrupt controller. + +Additional requirements: + + Each UART port must have an alias correctly numbered in "aliases" + node. + +Example: + + aliases { + serial0 = &uart0; + }; + + uart0: uart@18020000 { + compatible = "qca,ar9330-uart"; + reg = <0x18020000 0x14>; + + interrupt-parent = <&intc>; + interrupts = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-geni-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-geni-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..54382e843bd41f65331022fb39985fbb799c524a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-geni-uart.txt @@ -0,0 +1,43 @@ +* MSM Serial UART for GENI based cores. + +The MSM serial UART driver supports low speed and high speed use-cases. +This is meant only for QUPv3 GENI based cores and isn't backwards compatible. +There is support for console usecases and for higher speed usecases that need +DMA. + +Required properties: +- compatible: should contain "qcom,msm-geni-uart, qcom,msm-geni-console" + for UART console usecases, "qcom,msm-geni-uart, qcom,msm-geni-serial-hs" + for High Speed (HS) usecases. +- reg: Should contain UART register location and length. +- interrupts: Should contain UART core interrupts. +- clocks: clocks needed for UART, includes the core and AHB clock. +- pinctrl-names/pinctrl-0/1/2: The GPIOs assigned to this core. The names + Should be "default", "active" and "sleep" for the pin confuguration. + It should be in "default" for the default pin configuration during probe, + in "active" when core is active or in "sleep" when entering in sleep state. +- qcom,wrapper-core: Wrapper QUPv3 core containing this UART controller. + +Optional properties: +- qcom,wakeup-byte: Byte to be injected in the tty layer during wakeup isr. +- qcom,change-sampling-rate: This is a boolean parameter and use this to decide + the samping rate at which sequencer engine runs. + +Example: +qupv3_uart11: qcom,qup_uart@0xa88000 { + compatible = "qcom,msm-geni-uart"; + reg = <0xa88000 0x7000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "active", "sleep"; + pinctrl-0 = <&qup_1_uart_3_default>; + pinctrl-1 = <&qup_1_uart_3_active>; + pinctrl-2 = <&qup_1_uart_3_sleep>; + interrupts = <0 355 0>; + qcom,wrapper-core = <&qupv3_0>; + qcom,change-sampling-rate; + qcom,wakeup-byte = <0xFF>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce8c9016195922682f433bfcb3742279de6aa132 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-uart.txt @@ -0,0 +1,25 @@ +* MSM Serial UART + +The MSM serial UART hardware is designed for low-speed use cases where a +dma-engine isn't needed. From a software perspective it's mostly compatible +with the MSM serial UARTDM except that it only supports reading and writing one +character at a time. + +Required properties: +- compatible: Should contain "qcom,msm-uart" +- reg: Should contain UART register location and length. +- interrupts: Should contain UART interrupt. +- clocks: Should contain the core clock. +- clock-names: Should be "core". + +Example: + +A uart device at 0xa9c00000 with interrupt 11. + +serial@a9c00000 { + compatible = "qcom,msm-uart"; + reg = <0xa9c00000 0x1000>; + interrupts = <11>; + clocks = <&uart_cxc>; + clock-names = "core"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-uartdm.txt b/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-uartdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d098cf73b533171be76b3caaa10ec4532f38cfd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/qcom,msm-uartdm.txt @@ -0,0 +1,81 @@ +* MSM Serial UARTDM + +The MSM serial UARTDM hardware is designed for high-speed use cases where the +transmit and/or receive channels can be offloaded to a dma-engine. From a +software perspective it's mostly compatible with the MSM serial UART except +that it supports reading and writing multiple characters at a time. + +Required properties: +- compatible: Should contain at least "qcom,msm-uartdm". + A more specific property should be specified as follows depending + on the version: + "qcom,msm-uartdm-v1.1" + "qcom,msm-uartdm-v1.2" + "qcom,msm-uartdm-v1.3" + "qcom,msm-uartdm-v1.4" +- reg: Should contain UART register locations and lengths. The first + register shall specify the main control registers. An optional second + register location shall specify the GSBI control region. + "qcom,msm-uartdm-v1.3" is the only compatible value that might + need the GSBI control region. +- interrupts: Should contain UART interrupt. +- clocks: Should contain the core clock and the AHB clock. +- clock-names: Should be "core" for the core clock and "iface" for the + AHB clock. + +Optional properties: +- dmas: Should contain dma specifiers for transmit and receive channels +- dma-names: Should contain "tx" for transmit and "rx" for receive channels +- qcom,tx-crci: Identificator for Client Rate Control Interface to be + used with TX DMA channel. Required when using DMA for transmission + with UARTDM v1.3 and below. +- qcom,rx-crci: Identificator for Client Rate Control Interface to be + used with RX DMA channel. Required when using DMA for reception + with UARTDM v1.3 and below. + +Note: Aliases may be defined to ensure the correct ordering of the UARTs. +The alias serialN will result in the UART being assigned port N. If any +serialN alias exists, then an alias must exist for each enabled UART. The +serialN aliases should be in a .dts file instead of in a .dtsi file. + +Examples: + +- A uartdm v1.4 device with dma capabilities. + + serial@f991e000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xf991e000 0x1000>; + interrupts = <0 108 0x0>; + clocks = <&blsp1_uart2_apps_cxc>, <&blsp1_ahb_cxc>; + clock-names = "core", "iface"; + dmas = <&dma0 0>, <&dma0 1>; + dma-names = "tx", "rx"; + }; + +- A uartdm v1.3 device without dma capabilities and part of a GSBI complex. + + serial@19c40000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x19c40000 0x1000>, + <0x19c00000 0x1000>; + interrupts = <0 195 0x0>; + clocks = <&gsbi5_uart_cxc>, <&gsbi5_ahb_cxc>; + clock-names = "core", "iface"; + }; + +- serialN alias. + + aliases { + serial0 = &uarta; + serial1 = &uartc; + serial2 = &uartb; + }; + + uarta: serial@12490000 { + }; + + uartb: serial@16340000 { + }; + + uartc: serial@1a240000 { + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/renesas,rzn1-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/renesas,rzn1-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b9e0d4dc2e47db32c55edda36bf3e25db72bfad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/renesas,rzn1-uart.txt @@ -0,0 +1,10 @@ +Renesas RZ/N1 UART + +This controller is based on the Synopsys DesignWare ABP UART and inherits all +properties defined in snps-dw-apb-uart.txt except for the compatible property. + +Required properties: +- compatible : The device specific string followed by the generic RZ/N1 string. + Therefore it must be one of: + "renesas,r9a06g032-uart", "renesas,rzn1-uart" + "renesas,r9a06g033-uart", "renesas,rzn1-uart" diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/renesas,sci-serial.txt b/arch/arm64/boot/dts/vendor/bindings/serial/renesas,sci-serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..eaca9da79d83af982a79abe8e1b911f944a64ed1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/renesas,sci-serial.txt @@ -0,0 +1,134 @@ +* Renesas SH-Mobile Serial Communication Interface + +Required properties: + + - compatible: Must contain one or more of the following: + + - "renesas,scif-r7s72100" for R7S72100 (RZ/A1H) SCIF compatible UART. + - "renesas,scif-r7s9210" for R7S9210 (RZ/A2) SCIF compatible UART. + - "renesas,scifa-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFA compatible UART. + - "renesas,scifb-r8a73a4" for R8A73A4 (R-Mobile APE6) SCIFB compatible UART. + - "renesas,scifa-r8a7740" for R8A7740 (R-Mobile A1) SCIFA compatible UART. + - "renesas,scifb-r8a7740" for R8A7740 (R-Mobile A1) SCIFB compatible UART. + - "renesas,scif-r8a7743" for R8A7743 (RZ/G1M) SCIF compatible UART. + - "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART. + - "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART. + - "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART. + - "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART. + - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART. + - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART. + - "renesas,hscif-r8a7745" for R8A7745 (RZ/G1E) HSCIF compatible UART. + - "renesas,scif-r8a77470" for R8A77470 (RZ/G1C) SCIF compatible UART. + - "renesas,hscif-r8a77470" for R8A77470 (RZ/G1C) HSCIF compatible UART. + - "renesas,scif-r8a7778" for R8A7778 (R-Car M1) SCIF compatible UART. + - "renesas,scif-r8a7779" for R8A7779 (R-Car H1) SCIF compatible UART. + - "renesas,scif-r8a7790" for R8A7790 (R-Car H2) SCIF compatible UART. + - "renesas,scifa-r8a7790" for R8A7790 (R-Car H2) SCIFA compatible UART. + - "renesas,scifb-r8a7790" for R8A7790 (R-Car H2) SCIFB compatible UART. + - "renesas,hscif-r8a7790" for R8A7790 (R-Car H2) HSCIF compatible UART. + - "renesas,scif-r8a7791" for R8A7791 (R-Car M2-W) SCIF compatible UART. + - "renesas,scifa-r8a7791" for R8A7791 (R-Car M2-W) SCIFA compatible UART. + - "renesas,scifb-r8a7791" for R8A7791 (R-Car M2-W) SCIFB compatible UART. + - "renesas,hscif-r8a7791" for R8A7791 (R-Car M2-W) HSCIF compatible UART. + - "renesas,scif-r8a7792" for R8A7792 (R-Car V2H) SCIF compatible UART. + - "renesas,hscif-r8a7792" for R8A7792 (R-Car V2H) HSCIF compatible UART. + - "renesas,scif-r8a7793" for R8A7793 (R-Car M2-N) SCIF compatible UART. + - "renesas,scifa-r8a7793" for R8A7793 (R-Car M2-N) SCIFA compatible UART. + - "renesas,scifb-r8a7793" for R8A7793 (R-Car M2-N) SCIFB compatible UART. + - "renesas,hscif-r8a7793" for R8A7793 (R-Car M2-N) HSCIF compatible UART. + - "renesas,scif-r8a7794" for R8A7794 (R-Car E2) SCIF compatible UART. + - "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART. + - "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART. + - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART. + - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART. + - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. + - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART. + - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART. + - "renesas,scif-r8a77965" for R8A77965 (R-Car M3-N) SCIF compatible UART. + - "renesas,hscif-r8a77965" for R8A77965 (R-Car M3-N) HSCIF compatible UART. + - "renesas,scif-r8a77970" for R8A77970 (R-Car V3M) SCIF compatible UART. + - "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART. + - "renesas,scif-r8a77980" for R8A77980 (R-Car V3H) SCIF compatible UART. + - "renesas,hscif-r8a77980" for R8A77980 (R-Car V3H) HSCIF compatible UART. + - "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART. + - "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART. + - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. + - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. + - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART, + - "renesas,rcar-gen2-scif" for R-Car Gen2 SCIF compatible UART, + - "renesas,rcar-gen3-scif" for R-Car Gen3 SCIF compatible UART, + - "renesas,rcar-gen2-scifa" for R-Car Gen2 SCIFA compatible UART, + - "renesas,rcar-gen2-scifb" for R-Car Gen2 SCIFB compatible UART, + - "renesas,rcar-gen1-hscif" for R-Car Gen1 HSCIF compatible UART, + - "renesas,rcar-gen2-hscif" for R-Car Gen2 HSCIF compatible UART, + - "renesas,rcar-gen3-hscif" for R-Car Gen3 HSCIF compatible UART, + - "renesas,scif" for generic SCIF compatible UART. + - "renesas,scifa" for generic SCIFA compatible UART. + - "renesas,scifb" for generic SCIFB compatible UART. + - "renesas,hscif" for generic HSCIF compatible UART. + - "renesas,sci" for generic SCI compatible UART. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first, followed by the + family-specific and/or generic versions. + + - reg: Base address and length of the I/O registers used by the UART. + - interrupts: Must contain one or more interrupt-specifiers for the SCIx. + If a single interrupt is expressed, then all events are + multiplexed into this single interrupt. + + If multiple interrupts are provided by the hardware, the order + in which the interrupts are listed must match order below. Note + that some HW interrupt events may be muxed together resulting + in duplicate entries. + The interrupt order is as follows: + 1. Error (ERI) + 2. Receive buffer full (RXI) + 3. Transmit buffer empty (TXI) + 4. Break (BRI) + 5. Data Ready (DRI) + 6. Transmit End (TEI) + + - clocks: Must contain a phandle and clock-specifier pair for each entry + in clock-names. + - clock-names: Must contain "fck" for the SCIx UART functional clock. + Apart from the divided functional clock, there may be other possible + sources for the sampling clock, depending on SCIx variant. + On (H)SCI(F) and some SCIFA, an additional clock may be specified: + - "hsck" for the optional external clock input (on HSCIF), + - "sck" for the optional external clock input (on other variants). + On UARTs equipped with a Baud Rate Generator for External Clock (BRG) + (some SCIF and HSCIF), additional clocks may be specified: + - "brg_int" for the optional internal clock source for the frequency + divider (typically the (AXI or SHwy) bus clock), + - "scif_clk" for the optional external clock source for the frequency + divider (SCIF_CLK). + +Note: Each enabled SCIx UART may have an optional "serialN" alias in the +"aliases" node. + +Optional properties: + - dmas: Must contain a list of two references to DMA specifiers, one for + transmission, and one for reception. + - dma-names: Must contain a list of two DMA names, "tx" and "rx". + - {cts,dsr,dcd,rng,rts,dtr}-gpios: Specify GPIOs for modem lines, cfr. the + generic serial DT bindings in serial.txt. + - uart-has-rtscts: Indicates dedicated lines for RTS/CTS hardware flow + control, cfr. the generic serial DT bindings in serial.txt. + +Example: + aliases { + serial0 = &scifa0; + }; + + scifa0: serial@e6c40000 { + compatible = "renesas,scifa-r8a7790", + "renesas,rcar-gen2-scifa", "renesas,scifa"; + reg = <0 0xe6c40000 0 64>; + interrupt-parent = <&gic>; + interrupts = <0 144 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7790_CLK_SCIFA0>; + clock-names = "fck"; + dmas = <&dmac0 0x21>, <&dmac0 0x22>; + dma-names = "tx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/rs485.txt b/arch/arm64/boot/dts/vendor/bindings/serial/rs485.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7c29f74ebb2e0a3bf9cea65e4dc559ed7e3bb5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/rs485.txt @@ -0,0 +1,31 @@ +* RS485 serial communications + +The RTS signal is capable of automatically controlling line direction for +the built-in half-duplex mode. +The properties described hereafter shall be given to a half-duplex capable +UART node. + +Optional properties: +- rs485-rts-delay: prop-encoded-array where: + * a is the delay between rts signal and beginning of data sent in milliseconds. + it corresponds to the delay before sending data. + * b is the delay between end of data sent and rts signal in milliseconds + it corresponds to the delay after sending data and actual release of the line. + If this property is not specified, <0 0> is assumed. +- rs485-rts-active-low: drive RTS low when sending (default is high). +- linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485 + feature at boot time. It can be disabled later with proper ioctl. +- rs485-rx-during-tx: empty property that enables the receiving of data even + whilst sending data. + +RS485 example for Atmel USART: + usart0: serial@fff8c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfff8c000 0x4000>; + interrupts = <7>; + atmel,use-dma-rx; + atmel,use-dma-tx; + linux,rs485-enabled-at-boot-time; + rs485-rts-delay = <0 200>; // in milliseconds + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/samsung_uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/samsung_uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..e85f37ec33f0277b27ab7aa4f39c4b34c4cbfcd2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/samsung_uart.txt @@ -0,0 +1,58 @@ +* Samsung's UART Controller + +The Samsung's UART controller is used for interfacing SoC with serial +communicaion devices. + +Required properties: +- compatible: should be one of following: + - "samsung,exynos4210-uart" - Exynos4210 SoC, + - "samsung,s3c2410-uart" - compatible with ports present on S3C2410 SoC, + - "samsung,s3c2412-uart" - compatible with ports present on S3C2412 SoC, + - "samsung,s3c2440-uart" - compatible with ports present on S3C2440 SoC, + - "samsung,s3c6400-uart" - compatible with ports present on S3C6400 SoC, + - "samsung,s5pv210-uart" - compatible with ports present on S5PV210 SoC. + +- reg: base physical address of the controller and length of memory mapped + region. + +- interrupts: a single interrupt signal to SoC interrupt controller, + according to interrupt bindings documentation [1]. + +- clock-names: input names of clocks used by the controller: + - "uart" - controller bus clock, + - "clk_uart_baudN" - Nth baud base clock input (N = 0, 1, ...), + according to SoC User's Manual (only N = 0 is allowedfor SoCs without + internal baud clock mux). +- clocks: phandles and specifiers for all clocks specified in "clock-names" + property, in the same order, according to clock bindings documentation [2]. + +[1] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[2] Documentation/devicetree/bindings/clock/clock-bindings.txt + +Optional properties: +- samsung,uart-fifosize: The fifo size supported by the UART channel + +Note: Each Samsung UART should have an alias correctly numbered in the +"aliases" node, according to serialN format, where N is the port number +(non-negative decimal integer) as specified by User's Manual of respective +SoC. + +Example: + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + }; + +Example: + uart1: serial@7f005400 { + compatible = "samsung,s3c6400-uart"; + reg = <0x7f005400 0x100>; + interrupt-parent = <&vic1>; + interrupts = <6>; + clock-names = "uart", "clk_uart_baud2", + "clk_uart_baud3"; + clocks = <&clocks PCLK_UART1>, <&clocks PCLK_UART1>, + <&clocks SCLK_UART>; + samsung,uart-fifosize = <16>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/serial.txt b/arch/arm64/boot/dts/vendor/bindings/serial/serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..863c2893759e715161db4e00df15a2643031cf4b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/serial.txt @@ -0,0 +1,56 @@ +Generic Serial DT Bindings + +This document lists a set of generic properties for describing UARTs in a +device tree. Whether these properties apply to a particular device depends on +the DT bindings for the actual device. + +Optional properties: + - cts-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's CTS line. + - dcd-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's DCD line. + - dsr-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's DSR line. + - dtr-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's DTR line. + - rng-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's RNG line. + - rts-gpios: Must contain a GPIO specifier, referring to the GPIO pin to be + used as the UART's RTS line. + + - uart-has-rtscts: The presence of this property indicates that the + UART has dedicated lines for RTS/CTS hardware flow control, and that + they are available for use (wired and enabled by pinmux configuration). + This depends on both the UART hardware and the board wiring. + Note that this property is mutually-exclusive with "cts-gpios" and + "rts-gpios" above, unless support is provided to switch between modes + dynamically. + + +Examples: + + uart1: serial@48022000 { + compatible = "ti,am3352-uart", "ti,omap3-uart"; + ti,hwmods = "uart2"; + clock-frequency = <48000000>; + reg = <0x48022000 0x2000>; + interrupts = <73>; + dmas = <&edma 28 0>, <&edma 29 0>; + dma-names = "tx", "rx"; + dtr-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; + dsr-gpios = <&gpio2 23 GPIO_ACTIVE_LOW>; + dcd-gpios = <&gpio2 24 GPIO_ACTIVE_LOW>; + rng-gpios = <&gpio2 25 GPIO_ACTIVE_LOW>; + cts-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + rts-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + }; + + scifa4: serial@e6c80000 { + compatible = "renesas,scifa-sh73a0", "renesas,scifa"; + reg = <0xe6c80000 0x100>; + interrupts = ; + clocks = <&mstp2_clks SH73A0_CLK_SCIFA4>; + clock-names = "fck"; + power-domains = <&pd_a3sp>; + uart-has-rtscts; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/sirf-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/sirf-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e48bbbeecc6dd277d21bfc67a8ea7393480aa41 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/sirf-uart.txt @@ -0,0 +1,34 @@ +* CSR SiRFprimaII/atlasVI Universal Synchronous Asynchronous Receiver/Transmitter * + +Required properties: +- compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart", + "sirf,atlas7-uart" or "sirf,atlas7-usp-uart". +- reg : Offset and length of the register set for the device +- interrupts : Should contain uart interrupt +- fifosize : Should define hardware rx/tx fifo size +- clocks : Should contain uart clock number + +Optional properties: +- uart-has-rtscts: we have hardware flow controller pins in hardware +- rts-gpios: RTS pin for USP-based UART if uart-has-rtscts is true +- cts-gpios: CTS pin for USP-based UART if uart-has-rtscts is true + +Example: + +uart0: uart@b0050000 { + cell-index = <0>; + compatible = "sirf,prima2-uart"; + reg = <0xb0050000 0x1000>; + interrupts = <17>; + fifosize = <128>; + clocks = <&clks 13>; +}; + +On the board-specific dts, we can put rts-gpios and cts-gpios like + +usp@b0090000 { + compatible = "sirf,prima2-usp-uart"; + uart-has-rtscts; + rts-gpios = <&gpio 15 0>; + cts-gpios = <&gpio 46 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/slave-device.txt b/arch/arm64/boot/dts/vendor/bindings/serial/slave-device.txt new file mode 100644 index 0000000000000000000000000000000000000000..40110e0196209fde2c6a3347b83b72deeaf8a0b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/slave-device.txt @@ -0,0 +1,45 @@ +Serial Slave Device DT binding + +This documents the binding structure and common properties for serial +attached devices. Common examples include Bluetooth, WiFi, NFC and GPS +devices. + +Serial attached devices shall be a child node of the host UART device the +slave device is attached to. It is expected that the attached device is +the only child node of the UART device. The slave device node name shall +reflect the generic type of device for the node. + +Required Properties: + +- compatible : A string reflecting the vendor and specific device the node + represents. + +Optional Properties: + +- max-speed : The maximum baud rate the device operates at. This should + only be present if the maximum is less than the slave device + can support. For example, a particular board has some signal + quality issue or the host processor can't support higher + baud rates. +- current-speed : The current baud rate the device operates at. This should + only be present in case a driver has no chance to know + the baud rate of the slave device. + Examples: + * device supports auto-baud + * the rate is setup by a bootloader and there is no + way to reset the device + * device baud rate is configured by its firmware but + there is no way to request the actual settings + +Example: + +serial@1234 { + compatible = "ns16550a"; + interrupts = <1>; + + bluetooth { + compatible = "brcm,bcm43341-bt"; + interrupt-parent = <&gpio>; + interrupts = <10>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/snps-dw-apb-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/snps-dw-apb-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..12bbe9f22560c59d29ac8bd45bdbe5ad9be8bf2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/snps-dw-apb-uart.txt @@ -0,0 +1,76 @@ +* Synopsys DesignWare ABP UART + +Required properties: +- compatible : "snps,dw-apb-uart" +- reg : offset and length of the register set for the device. +- interrupts : should contain uart interrupt. + +Clock handling: +The clock rate of the input clock needs to be supplied by one of +- clock-frequency : the input clock frequency for the UART. +- clocks : phandle to the input clock + +The supplying peripheral clock can also be handled, needing a second property +- clock-names: tuple listing input clock names. + Required elements: "baudclk", "apb_pclk" + +Optional properties: +- snps,uart-16550-compatible : reflects the value of UART_16550_COMPATIBLE + configuration parameter. Define this if your UART does not implement the busy + functionality. +- resets : phandle to the parent reset controller. +- reg-shift : quantity to shift the register offsets by. If this property is + not present then the register offsets are not shifted. +- reg-io-width : the size (in bytes) of the IO accesses that should be + performed on the device. If this property is not present then single byte + accesses are used. +- dcd-override : Override the DCD modem status signal. This signal will always + be reported as active instead of being obtained from the modem status + register. Define this if your serial port does not use this pin. +- dsr-override : Override the DTS modem status signal. This signal will always + be reported as active instead of being obtained from the modem status + register. Define this if your serial port does not use this pin. +- cts-override : Override the CTS modem status signal. This signal will always + be reported as active instead of being obtained from the modem status + register. Define this if your serial port does not use this pin. +- ri-override : Override the RI modem status signal. This signal will always be + reported as inactive instead of being obtained from the modem status register. + Define this if your serial port does not use this pin. + +Example: + + uart@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clock-frequency = <3686400>; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + dcd-override; + dsr-override; + cts-override; + ri-override; + }; + +Example with one clock: + + uart@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clocks = <&baudclk>; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + }; + +Example with two clocks: + + uart@80230000 { + compatible = "snps,dw-apb-uart"; + reg = <0x80230000 0x100>; + clocks = <&baudclk>, <&apb_pclk>; + clock-names = "baudclk", "apb_pclk"; + interrupts = <10>; + reg-shift = <2>; + reg-io-width = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/sprd-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/sprd-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..cab40f0f6f497ab7bc0b3ab9640bcc0563a8cddb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/sprd-uart.txt @@ -0,0 +1,19 @@ +* Spreadtrum serial UART + +Required properties: +- compatible: must be one of: + * "sprd,sc9836-uart" + * "sprd,sc9860-uart", "sprd,sc9836-uart" + +- reg: offset and length of the register set for the device +- interrupts: exactly one interrupt specifier +- clocks: phandles to input clocks. + +Example: + uart0: serial@0 { + compatible = "sprd,sc9860-uart", + "sprd,sc9836-uart"; + reg = <0x0 0x100>; + interrupts = ; + clocks = <&ext_26m>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/st,stm32-usart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/st,stm32-usart.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d3efed55deb243ff26e440f87496cfb23683c26 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/st,stm32-usart.txt @@ -0,0 +1,51 @@ +* STMicroelectronics STM32 USART + +Required properties: +- compatible: can be either: + - "st,stm32-uart", + - "st,stm32f7-uart", + - "st,stm32h7-uart". + depending is compatible with stm32(f4), stm32f7 or stm32h7. +- reg: The address and length of the peripheral registers space +- interrupts: + - The interrupt line for the USART instance, + - An optional wake-up interrupt. +- clocks: The input clock of the USART instance + +Optional properties: +- pinctrl: The reference on the pins configuration +- st,hw-flow-ctrl: bool flag to enable hardware flow control. +- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, + linux,rs485-enabled-at-boot-time: see rs485.txt. +- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt +- dma-names: "rx" and/or "tx" + +Examples: +usart4: serial@40004c00 { + compatible = "st,stm32-uart"; + reg = <0x40004c00 0x400>; + interrupts = <52>; + clocks = <&clk_pclk1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart4>; +}; + +usart2: serial@40004400 { + compatible = "st,stm32-uart"; + reg = <0x40004400 0x400>; + interrupts = <38>; + clocks = <&clk_pclk1>; + st,hw-flow-ctrl; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart2 &pinctrl_usart2_rtscts>; +}; + +usart1: serial@40011000 { + compatible = "st,stm32-uart"; + reg = <0x40011000 0x400>; + interrupts = <37>; + clocks = <&rcc 0 164>; + dmas = <&dma2 2 4 0x414 0x0>, + <&dma2 7 4 0x414 0x0>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/st-asc.txt b/arch/arm64/boot/dts/vendor/bindings/serial/st-asc.txt new file mode 100644 index 0000000000000000000000000000000000000000..75d877f5968fd4de74cf0f4a112ac7cb7b70b6ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/st-asc.txt @@ -0,0 +1,18 @@ +*st-asc(Serial Port) + +Required properties: +- compatible : Should be "st,asc". +- reg, reg-names, interrupts, interrupt-names : Standard way to define device + resources with names. look in + Documentation/devicetree/bindings/resource-names.txt + +Optional properties: +- st,hw-flow-ctrl bool flag to enable hardware flow control. +- st,force-m1 bool flat to force asc to be in Mode-1 recommeded + for high bit rates (above 19.2K) +Example: +serial@fe440000{ + compatible = "st,asc"; + reg = <0xfe440000 0x2c>; + interrupts = <0 209 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/uniphier-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/uniphier-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b3892a7a528ce34b9f4e4626e19c6a388a6573b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/uniphier-uart.txt @@ -0,0 +1,23 @@ +UniPhier UART controller + +Required properties: +- compatible: should be "socionext,uniphier-uart". +- reg: offset and length of the register set for the device. +- interrupts: a single interrupt specifier. +- clocks: phandle to the input clock. + +Optional properties: +- fifo-size: the RX/TX FIFO size. Defaults to 64 if not specified. + +Example: + aliases { + serial0 = &serial0; + }; + + serial0: serial@54006800 { + compatible = "socionext,uniphier-uart"; + reg = <0x54006800 0x40>; + interrupts = <0 33 4>; + clocks = <&uart_clk>; + fifo-size = <64>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/vt8500-uart.txt b/arch/arm64/boot/dts/vendor/bindings/serial/vt8500-uart.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b64e6107fb3a8e2d07403d6df386b8d9f5cbb83 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/vt8500-uart.txt @@ -0,0 +1,27 @@ +* VIA VT8500 and WonderMedia WM8xxx UART Controller + +Required properties: +- compatible: should be "via,vt8500-uart" (for VIA/WonderMedia chips up to and + including WM8850/WM8950), or "wm,wm8880-uart" (for WM8880 and later) + +- reg: base physical address of the controller and length of memory mapped + region. + +- interrupts: hardware interrupt number + +- clocks: shall be the input parent clock phandle for the clock. This should + be the 24Mhz reference clock. + +Aliases may be defined to ensure the correct ordering of the uarts. + +Example: + aliases { + serial0 = &uart0; + }; + + uart0: serial@d8200000 { + compatible = "via,vt8500-uart"; + reg = <0xd8200000 0x1040>; + interrupts = <32>; + clocks = <&clkuart0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serial/xlnx,opb-uartlite.txt b/arch/arm64/boot/dts/vendor/bindings/serial/xlnx,opb-uartlite.txt new file mode 100644 index 0000000000000000000000000000000000000000..c37deb44deadabbe9e90285115917453efe0e250 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serial/xlnx,opb-uartlite.txt @@ -0,0 +1,23 @@ +Xilinx Axi Uartlite controller Device Tree Bindings +--------------------------------------------------------- + +Required properties: +- compatible : Can be either of + "xlnx,xps-uartlite-1.00.a" + "xlnx,opb-uartlite-1.00.b" +- reg : Physical base address and size of the Axi Uartlite + registers map. +- interrupts : Should contain the UART controller interrupt. + +Optional properties: +- port-number : Set Uart port number +- clock-names : Should be "s_axi_aclk" +- clocks : Input clock specifier. Refer to common clock bindings. + +Example: +serial@800c0000 { + compatible = "xlnx,xps-uartlite-1.00.a"; + reg = <0x0 0x800c0000 0x10000>; + interrupts = <0x0 0x6e 0x1>; + port-number = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serio/allwinner,sun4i-ps2.txt b/arch/arm64/boot/dts/vendor/bindings/serio/allwinner,sun4i-ps2.txt new file mode 100644 index 0000000000000000000000000000000000000000..75996b6111bb7d95f5f6effb28d27679fc1a5400 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serio/allwinner,sun4i-ps2.txt @@ -0,0 +1,22 @@ +* Device tree bindings for Allwinner A10, A20 PS2 host controller + +A20 PS2 is dual role controller (PS2 host and PS2 device). These bindings are +for PS2 A10/A20 host controller. IBM compliant IBM PS2 and AT-compatible keyboard +and mouse can be connected. + +Required properties: + + - reg : Offset and length of the register set for the device. + - compatible : Should be as of the following: + - "allwinner,sun4i-a10-ps2" + - interrupts : The interrupt line connected to the PS2. + - clocks : The gate clk connected to the PS2. + + +Example: + ps20: ps2@01c2a000 { + compatible = "allwinner,sun4i-a10-ps2"; + reg = <0x01c2a000 0x400>; + interrupts = <0 62 4>; + clocks = <&apb1_gates 6>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/serio/altera_ps2.txt b/arch/arm64/boot/dts/vendor/bindings/serio/altera_ps2.txt new file mode 100644 index 0000000000000000000000000000000000000000..520199e2e3477396e792f88d18b4059cb5635568 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serio/altera_ps2.txt @@ -0,0 +1,5 @@ +Altera UP PS/2 controller + +Required properties: +- compatible : should be "ALTR,ps2-1.0". +- compatible : should be "altr,ps2-1.0". diff --git a/arch/arm64/boot/dts/vendor/bindings/serio/olpc,ap-sp.txt b/arch/arm64/boot/dts/vendor/bindings/serio/olpc,ap-sp.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e72183f52bc9dc5926b34f414941780e70847cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serio/olpc,ap-sp.txt @@ -0,0 +1,13 @@ +OLPC AP-SP serio interface + +Required properties: +- compatible : "olpc,ap-sp" +- reg : base address and length of SoC's WTM registers +- interrupts : SP-AP interrupt + +Example: + ap-sp@d4290000 { + compatible = "olpc,ap-sp"; + reg = <0xd4290000 0x1000>; + interrupts = <40>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/serio/ps2-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/serio/ps2-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b7bc9cdf9861257f6886029c432b1b08ce1e52b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serio/ps2-gpio.txt @@ -0,0 +1,23 @@ +Device-Tree binding for ps/2 gpio device + +Required properties: + - compatible = "ps2-gpio" + - data-gpios: the data pin + - clk-gpios: the clock pin + - interrupts: Should trigger on the falling edge of the clock line. + +Optional properties: + - write-enable: Indicates whether write function is provided + to serio device. Possibly providing the write fn will not work, because + of the tough timing requirements. + +Example nodes: + +ps2@0 { + compatible = "ps2-gpio"; + interrupt-parent = <&gpio>; + interrupts = <23 IRQ_TYPE_EDGE_FALLING>; + data-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; + clk-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; + write-enable; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/serio/snps-arc_ps2.txt b/arch/arm64/boot/dts/vendor/bindings/serio/snps-arc_ps2.txt new file mode 100644 index 0000000000000000000000000000000000000000..38c2f21e80449da37dbafc5aa31ace29cb8a20a2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/serio/snps-arc_ps2.txt @@ -0,0 +1,16 @@ +* ARC PS/2 driver: PS/2 block used in some ARC FPGA's & nSIM OSCI model + +Required properties: +- compatible : "snps,arc_ps2" +- reg : offset and length (always 0x14) of registers +- interrupts : interrupt +- interrupt-names : name of interrupt, must be "arc_ps2_irq" + +Example: + +serio@c9000400 { + compatible = "snps,arc_ps2"; + reg = <0xc9000400 0x14>; + interrupts = <13>; + interrupt-names = "arc_ps2_irq"; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/siox/eckelmann,siox-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/siox/eckelmann,siox-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..55259cf39c251880dac825e4917ff938b847b728 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/siox/eckelmann,siox-gpio.txt @@ -0,0 +1,19 @@ +Eckelmann SIOX GPIO bus + +Required properties: +- compatible : "eckelmann,siox-gpio" +- din-gpios, dout-gpios, dclk-gpios, dld-gpios: references gpios for the + corresponding bus signals. + +Examples: + + siox { + compatible = "eckelmann,siox-gpio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_siox>; + + din-gpios = <&gpio6 11 0>; + dout-gpios = <&gpio6 8 0>; + dclk-gpios = <&gpio6 9 0>; + dld-gpios = <&gpio6 10 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/slimbus/slim-msm-ctrl.txt b/arch/arm64/boot/dts/vendor/bindings/slimbus/slim-msm-ctrl.txt new file mode 100644 index 0000000000000000000000000000000000000000..118a446af634630164cc382bb44692a154e5691f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/slimbus/slim-msm-ctrl.txt @@ -0,0 +1,100 @@ + Qualcomm Technologies,Inc SLIMBUS controller + Qualcomm Technologies,Inc implements 2 type of slimbus controllers: +1. "qcom,slim-msm": This controller is used if applications processor + driver is controlling slimbus master component. This driver is + responsible for communicating with slave HW directly using + messaging interface, and doing data channel management. Driver + also communicates with satellite component (driver implemented + by other execution environment, such as ADSP) to get its + requirements for data channel and bandwidth requirements. +2. "qcom,slim-ngd": This controller is used if applications processor + driver is controlling slimbus satellite component (also known as + Non-ported Generic Device, or NGD). This is light-weight slimbus + controller responsible for communicating with slave HW directly + over bus messaging interface, and communicating with master component + (driver residing on other execution environment, such as ADSP) + for bandwidth and data channel management. + +Required properties: + + - reg : Offset and length of the register region(s) for the device + - reg-names : Register region name(s) referenced in reg above + Required register resource entries are: + "slimbus_physical": Physical adderss of controller register blocks + "slimbus_bam_physical": Physical address of Bus Access Module (BAM) + for this controller + - compatible : should be "qcom,slim-msm" if this is master component driver + - compatible : should be "qcom,slim-ngd" if this is satellite component driver + - cell-index : SLIMBUS number used for this controller + - interrupts : Interrupt numbers used by this controller + - interrupt-names : Required interrupt resource entries are: + "slimbus_irq" : Interrupt for SLIMBUS core + "slimbus_bam_irq" : Interrupt for controller core's BAM + +Optional property: + - reg entry for slew rate : If slew rate control register is provided, this + entry should be used. + - reg-name for slew rate: "slimbus_slew_reg" + - reg entry for LPASS memory: If LPASS memory is to be used instead of DDR by + slimbus, this entry should be used. + - reg-names for LPASS memory: "slimbus_lpass_mem" + - qcom,min-clk-gear : Minimum clock gear at which this controller can be run + (range: 1-10) + Default value will be 1 if this entry is not specified + - qcom,max-clk-gear: Maximum clock gear at which this controller can be run + (range: 1-10) + Default value will be 10 if this entry is not specified + - qcom,rxreg-access: This boolean indicates that slimbus RX should use direct + register access to receive data. This flag is only needed if + BAM pipe is not available to receive data from slimbus + - qcom,apps-ch-pipes: This value represents BAM pipe-mask used by application + processor for data channels. If this property is not defined, + default mask of 0 is used indicating that application + processor does not use BAM pipes for data channels. + - qcom,ea-pc: This value represents product code (PC) field of enumeration + address (EA) for the QTI slimbus controller hardware. + This value is needed if data-channels originating from apps + are to be used, so that application processor can query + logical address of the ported generic device to be used. + Other than PC, fields of EA are same across platforms. + - qcom,slim-mdm: This value provides the identifier of slimbus component on + external mdm. This property enables the slimbus driver to + register and receive subsytem restart notification from mdm + and follow appropriate steps to ensure communication on the bus + can be resumed after mdm-restart. + - qcom,subsys-name: This value provides the subsystem name where slimbus master + is present. This property enables the slimbus driver to + register and receive subsytem restart notification from subsystem + and follow appropriate steps to ensure communication on the bus + can be resumed after subsytem restart. By default slimbus driver + register with ADSP subsystem. + - qcom,iommu-s1-bypass: Boolean flag to bypass IOMMU stage 1 translation. + +Optional subnodes: +qcom,iommu_slim_ctrl_cb : Child node representing the Slimbus controller + context bank. + +Subnode Required properties: +- compatible : Must be "qcom,slim-ctrl-cb"; +- iommus : A list of phandle and IOMMU specifier pairs that + describe the IOMMU master interfaces of the device. + +Example: + slim@fe12f000 { + cell-index = <1>; + compatible = "qcom,slim-msm"; + reg = <0xfe12f000 0x35000>, + <0xfe104000 0x20000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0 0 164 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,min-clk-gear = <10>; + qcom,rxreg-access; + qcom,apps-ch-pipes = <0x60000000>; + qcom,ea-pc = <0x30>; + + iommu_slim_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1 0x0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/smcinvoke/smcinvoke.txt b/arch/arm64/boot/dts/vendor/bindings/smcinvoke/smcinvoke.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0e201c83bf4a671a47d205d40fb1cd2ba1700fb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/smcinvoke/smcinvoke.txt @@ -0,0 +1,11 @@ +* SMCInvoke driver to provide transport between TZ and Linux + +Required properties: +- compatible : Should be "qcom,smcinvoke" +- reg : should contain memory region address reserved for loading secure apps. + +Example: + qcom_smcinvoke: smcinvoke@87900000 { + compatible = "qcom,smcinvoke"; + reg = <0x87900000 0x2200000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/bcm/brcm,bcm2835-vchiq.txt b/arch/arm64/boot/dts/vendor/bindings/soc/bcm/brcm,bcm2835-vchiq.txt new file mode 100644 index 0000000000000000000000000000000000000000..8dd7b3a7de65cde0e6a9907630547c7d6d5a0aaf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/bcm/brcm,bcm2835-vchiq.txt @@ -0,0 +1,16 @@ +Broadcom VCHIQ firmware services + +Required properties: + +- compatible: Should be "brcm,bcm2835-vchiq" +- reg: Physical base address and length of the doorbell register pair +- interrupts: The interrupt number + See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt + +Example: + +mailbox@7e00b840 { + compatible = "brcm,bcm2835-vchiq"; + reg = <0x7e00b840 0xf>; + interrupts = <0 2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/bcm/raspberrypi,bcm2835-power.txt b/arch/arm64/boot/dts/vendor/bindings/soc/bcm/raspberrypi,bcm2835-power.txt new file mode 100644 index 0000000000000000000000000000000000000000..30942cf7992ba40c3458b905b074ab4c4a1b1cb7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/bcm/raspberrypi,bcm2835-power.txt @@ -0,0 +1,47 @@ +Raspberry Pi power domain driver + +Required properties: + +- compatible: Should be "raspberrypi,bcm2835-power". +- firmware: Reference to the RPi firmware device node. +- #power-domain-cells: Should be <1>, we providing multiple power domains. + +The valid defines for power domain are: + + RPI_POWER_DOMAIN_I2C0 + RPI_POWER_DOMAIN_I2C1 + RPI_POWER_DOMAIN_I2C2 + RPI_POWER_DOMAIN_VIDEO_SCALER + RPI_POWER_DOMAIN_VPU1 + RPI_POWER_DOMAIN_HDMI + RPI_POWER_DOMAIN_USB + RPI_POWER_DOMAIN_VEC + RPI_POWER_DOMAIN_JPEG + RPI_POWER_DOMAIN_H264 + RPI_POWER_DOMAIN_V3D + RPI_POWER_DOMAIN_ISP + RPI_POWER_DOMAIN_UNICAM0 + RPI_POWER_DOMAIN_UNICAM1 + RPI_POWER_DOMAIN_CCP2RX + RPI_POWER_DOMAIN_CSI2 + RPI_POWER_DOMAIN_CPI + RPI_POWER_DOMAIN_DSI0 + RPI_POWER_DOMAIN_DSI1 + RPI_POWER_DOMAIN_TRANSPOSER + RPI_POWER_DOMAIN_CCP2TX + RPI_POWER_DOMAIN_CDP + RPI_POWER_DOMAIN_ARM + +Example: + +power: power { + compatible = "raspberrypi,bcm2835-power"; + firmware = <&firmware>; + #power-domain-cells = <1>; +}; + +Example for using power domain: + +&usb { + power-domains = <&power RPI_POWER_DOMAIN_USB>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/dove/pmu.txt b/arch/arm64/boot/dts/vendor/bindings/soc/dove/pmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..edd40b796b74aacb8050e7f6ce39cc71e4b8ece1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/dove/pmu.txt @@ -0,0 +1,56 @@ +Device Tree bindings for Marvell PMU + +Required properties: + - compatible: value should be "marvell,dove-pmu". + May also include "simple-bus" if there are child devices, in which + case the ranges node is required. + - reg: two base addresses and sizes of the PM controller and PMU. + - interrupts: single interrupt number for the PMU interrupt + - interrupt-controller: must be specified as the PMU itself is an + interrupt controller. + - #interrupt-cells: must be 1. + - #reset-cells: must be 1. + - domains: sub-node containing domain descriptions + +Optional properties: + - ranges: defines the address mapping for child devices, as per the + standard property of this name. Required when compatible includes + "simple-bus". + +Power domain descriptions are listed as child nodes of the "domains" +sub-node. Each domain has the following properties: + +Required properties: + - #power-domain-cells: must be 0. + +Optional properties: + - marvell,pmu_pwr_mask: specifies the mask value for PMU power register + - marvell,pmu_iso_mask: specifies the mask value for PMU isolation register + - resets: points to the reset manager (PMU node) and reset index. + +Example: + + pmu: power-management@d0000 { + compatible = "marvell,dove-pmu"; + reg = <0xd0000 0x8000>, <0xd8000 0x8000>; + interrupts = <33>; + interrupt-controller; + #interrupt-cells = <1>; + #reset-cells = <1>; + + domains { + vpu_domain: vpu-domain { + #power-domain-cells = <0>; + marvell,pmu_pwr_mask = <0x00000008>; + marvell,pmu_iso_mask = <0x00000001>; + resets = <&pmu 16>; + }; + + gpu_domain: gpu-domain { + #power-domain-cells = <0>; + marvell,pmu_pwr_mask = <0x00000004>; + marvell,pmu_iso_mask = <0x00000002>; + resets = <&pmu 18>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..160c752484b4a74ea11ff6366a6b6613f97af316 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm.txt @@ -0,0 +1,67 @@ +* Freescale Communications Processor Module + +NOTE: This is an interim binding, and will likely change slightly, +as more devices are supported. The QE bindings especially are +incomplete. + +* Root CPM node + +Properties: +- compatible : "fsl,cpm1", "fsl,cpm2", or "fsl,qe". +- reg : A 48-byte region beginning with CPCR. + +Example: + cpm@119c0 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + compatible = "fsl,mpc8272-cpm", "fsl,cpm2"; + reg = <119c0 30>; + } + +* Properties common to multiple CPM/QE devices + +- fsl,cpm-command : This value is ORed with the opcode and command flag + to specify the device on which a CPM command operates. + +- fsl,cpm-brg : Indicates which baud rate generator the device + is associated with. If absent, an unused BRG + should be dynamically allocated. If zero, the + device uses an external clock rather than a BRG. + +- reg : Unless otherwise specified, the first resource represents the + scc/fcc/ucc registers, and the second represents the device's + parameter RAM region (if it has one). + +* Multi-User RAM (MURAM) + +The multi-user/dual-ported RAM is expressed as a bus under the CPM node. + +Ranges must be set up subject to the following restrictions: + +- Children's reg nodes must be offsets from the start of all muram, even + if the user-data area does not begin at zero. +- If multiple range entries are used, the difference between the parent + address and the child address must be the same in all, so that a single + mapping can cover them all while maintaining the ability to determine + CPM-side offsets with pointer subtraction. It is recommended that + multiple range entries not be used. +- A child address of zero must be translatable, even if no reg resources + contain it. + +A child "data" node must exist, compatible with "fsl,cpm-muram-data", to +indicate the portion of muram that is usable by the OS for arbitrary +purposes. The data node may have an arbitrary number of reg resources, +all of which contribute to the allocatable muram pool. + +Example, based on mpc8272: + muram@0 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 10000>; + + data@0 { + compatible = "fsl,cpm-muram-data"; + reg = <0 2000 9800 800>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/brg.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/brg.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c7d45eaf0253fc67131890d74edce90a4840b7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/brg.txt @@ -0,0 +1,21 @@ +* Baud Rate Generators + +Currently defined compatibles: +fsl,cpm-brg +fsl,cpm1-brg +fsl,cpm2-brg + +Properties: +- reg : There may be an arbitrary number of reg resources; BRG + numbers are assigned to these in order. +- clock-frequency : Specifies the base frequency driving + the BRG. + +Example: + brg@119f0 { + compatible = "fsl,mpc8272-brg", + "fsl,cpm2-brg", + "fsl,cpm-brg"; + reg = <119f0 10 115f0 10>; + clock-frequency = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/i2c.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..87bc6048667ee36b9e69f9e5332ce6a852fa90be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/i2c.txt @@ -0,0 +1,41 @@ +* I2C + +The I2C controller is expressed as a bus under the CPM node. + +Properties: +- compatible : "fsl,cpm1-i2c", "fsl,cpm2-i2c" +- reg : On CPM2 devices, the second resource doesn't specify the I2C + Parameter RAM itself, but the I2C_BASE field of the CPM2 Parameter RAM + (typically 0x8afc 0x2). +- #address-cells : Should be one. The cell is the i2c device address with + the r/w bit set to zero. +- #size-cells : Should be zero. +- clock-frequency : Can be used to set the i2c clock frequency. If + unspecified, a default frequency of 60kHz is being used. +The following two properties are deprecated. They are only used by legacy +i2c drivers to find the bus to probe: +- linux,i2c-index : Can be used to hard code an i2c bus number. By default, + the bus number is dynamically assigned by the i2c core. +- linux,i2c-class : Can be used to override the i2c class. The class is used + by legacy i2c device drivers to find a bus in a specific context like + system management, video or sound. By default, I2C_CLASS_HWMON (1) is + being used. The definition of the classes can be found in + include/i2c/i2c.h + +Example, based on mpc823: + + i2c@860 { + compatible = "fsl,mpc823-i2c", + "fsl,cpm1-i2c"; + reg = <0x860 0x20 0x3c80 0x30>; + interrupts = <16>; + interrupt-parent = <&CPM_PIC>; + fsl,cpm-command = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@68 { + compatible = "dallas,ds1307"; + reg = <0x68>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/pic.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/pic.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e3ee1681618742b6ac007ca92c8f2283060b504 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/pic.txt @@ -0,0 +1,18 @@ +* Interrupt Controllers + +Currently defined compatibles: +- fsl,cpm1-pic + - only one interrupt cell +- fsl,pq1-pic +- fsl,cpm2-pic + - second interrupt cell is level/sense: + - 2 is falling edge + - 8 is active low + +Example: + interrupt-controller@10c00 { + #interrupt-cells = <2>; + interrupt-controller; + reg = <10c00 80>; + compatible = "mpc8272-pic", "fsl,cpm2-pic"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/usb.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..74bfda4bb8243e5d79cc88caa9b57a0d9aa59423 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/cpm/usb.txt @@ -0,0 +1,15 @@ +* USB (Universal Serial Bus Controller) + +Properties: +- compatible : "fsl,cpm1-usb", "fsl,cpm2-usb", "fsl,qe-usb" + +Example: + usb@11bc0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,cpm2-usb"; + reg = <11b60 18 8b00 100>; + interrupts = ; + interrupt-parent = <&PIC>; + fsl,cpm-command = <2e600000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/gpio.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..cce3cd71e85a0000bcd54c69d2b132e5a40f4f74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/gpio.txt @@ -0,0 +1,56 @@ +Every GPIO controller node must have #gpio-cells property defined, +this information will be used to translate gpio-specifiers. + +On CPM1 devices, all ports are using slightly different register layouts. +Ports A, C and D are 16bit ports and Ports B and E are 32bit ports. + +On CPM2 devices, all ports are 32bit ports and use a common register layout. + +Required properties: +- compatible : "fsl,cpm1-pario-bank-a", "fsl,cpm1-pario-bank-b", + "fsl,cpm1-pario-bank-c", "fsl,cpm1-pario-bank-d", + "fsl,cpm1-pario-bank-e", "fsl,cpm2-pario-bank" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). +- gpio-controller : Marks the port as GPIO controller. +Optional properties: +- fsl,cpm1-gpio-irq-mask : For banks having interrupt capability (like port C + on CPM1), this item tells which ports have an associated interrupt (ports are + listed in the same order as in PCINT register) +- interrupts : This property provides the list of interrupt for each GPIO having + one as described by the fsl,cpm1-gpio-irq-mask property. There should be as + many interrupts as number of ones in the mask property. The first interrupt in + the list corresponds to the most significant bit of the mask. + +Example of four SOC GPIO banks defined as gpio-controller nodes: + + CPM1_PIO_A: gpio-controller@950 { + #gpio-cells = <2>; + compatible = "fsl,cpm1-pario-bank-a"; + reg = <0x950 0x10>; + gpio-controller; + }; + + CPM1_PIO_B: gpio-controller@ab8 { + #gpio-cells = <2>; + compatible = "fsl,cpm1-pario-bank-b"; + reg = <0xab8 0x10>; + gpio-controller; + }; + + CPM1_PIO_C: gpio-controller@960 { + #gpio-cells = <2>; + compatible = "fsl,cpm1-pario-bank-c"; + reg = <0x960 0x10>; + fsl,cpm1-gpio-irq-mask = <0x0fff>; + interrupts = <1 2 6 9 10 11 14 15 23 24 26 31>; + interrupt-parent = <&CPM_PIC>; + gpio-controller; + }; + + CPM1_PIO_E: gpio-controller@ac8 { + #gpio-cells = <2>; + compatible = "fsl,cpm1-pario-bank-e"; + reg = <0xac8 0x18>; + gpio-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/network.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/network.txt new file mode 100644 index 0000000000000000000000000000000000000000..03c741602c6d1d2178216afd4c6721a479111d98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/network.txt @@ -0,0 +1,124 @@ +* Network + +Currently defined compatibles: +- fsl,cpm1-scc-enet +- fsl,cpm2-scc-enet +- fsl,cpm1-fec-enet +- fsl,cpm2-fcc-enet (third resource is GFEMR) +- fsl,qe-enet + +Example: + + ethernet@11300 { + compatible = "fsl,mpc8272-fcc-enet", + "fsl,cpm2-fcc-enet"; + reg = <11300 20 8400 100 11390 1>; + local-mac-address = [ 00 00 00 00 00 00 ]; + interrupts = <20 8>; + interrupt-parent = <&PIC>; + phy-handle = <&PHY0>; + fsl,cpm-command = <12000300>; + }; + +* MDIO + +Currently defined compatibles: +fsl,pq1-fec-mdio (reg is same as first resource of FEC device) +fsl,cpm2-mdio-bitbang (reg is port C registers) + +Properties for fsl,cpm2-mdio-bitbang: +fsl,mdio-pin : pin of port C controlling mdio data +fsl,mdc-pin : pin of port C controlling mdio clock + +Example: + mdio@10d40 { + compatible = "fsl,mpc8272ads-mdio-bitbang", + "fsl,mpc8272-mdio-bitbang", + "fsl,cpm2-mdio-bitbang"; + reg = <10d40 14>; + #address-cells = <1>; + #size-cells = <0>; + fsl,mdio-pin = <12>; + fsl,mdc-pin = <13>; + }; + +* HDLC + +Currently defined compatibles: +- fsl,ucc-hdlc + +Properties for fsl,ucc-hdlc: +- rx-clock-name +- tx-clock-name + Usage: required + Value type: + Definition : Must be "brg1"-"brg16" for internal clock source, + Must be "clk1"-"clk24" for external clock source. + +- fsl,tdm-interface + Usage: optional + Value type: + Definition : Specify that hdlc is based on tdm-interface + +The property below is dependent on fsl,tdm-interface: +- fsl,rx-sync-clock + Usage: required + Value type: + Definition : Must be "none", "rsync_pin", "brg9-11" and "brg13-15". + +- fsl,tx-sync-clock + Usage: required + Value type: + Definition : Must be "none", "tsync_pin", "brg9-11" and "brg13-15". + +- fsl,tdm-framer-type + Usage: required for tdm interface + Value type: + Definition : "e1" or "t1".Now e1 and t1 are used, other framer types + are not supported. + +- fsl,tdm-id + Usage: required for tdm interface + Value type: + Definition : number of TDM ID + +- fsl,tx-timeslot-mask +- fsl,rx-timeslot-mask + Usage: required for tdm interface + Value type: + Definition : time slot mask for TDM operation. Indicates which time + slots used for transmitting and receiving. + +- fsl,siram-entry-id + Usage: required for tdm interface + Value type: + Definition : Must be 0,2,4...64. the number of TDM entry. + +- fsl,tdm-internal-loopback + usage: optional for tdm interface + value type: + Definition : Internal loopback connecting on TDM layer. + +Example for tdm interface: + + ucc@2000 { + compatible = "fsl,ucc-hdlc"; + rx-clock-name = "clk8"; + tx-clock-name = "clk9"; + fsl,rx-sync-clock = "rsync_pin"; + fsl,tx-sync-clock = "tsync_pin"; + fsl,tx-timeslot-mask = <0xfffffffe>; + fsl,rx-timeslot-mask = <0xfffffffe>; + fsl,tdm-framer-type = "e1"; + fsl,tdm-id = <0>; + fsl,siram-entry-id = <0>; + fsl,tdm-interface; + }; + +Example for hdlc without tdm interface: + + ucc@2000 { + compatible = "fsl,ucc-hdlc"; + rx-clock-name = "brg1"; + tx-clock-name = "brg1"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7afaff5faffb8c3e5d0bf6393984ddb3fa78af8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe.txt @@ -0,0 +1,167 @@ +* Freescale QUICC Engine module (QE) +This represents qe module that is installed on PowerQUICC II Pro. + +NOTE: This is an interim binding; it should be updated to fit +in with the CPM binding later in this document. + +Basically, it is a bus of devices, that could act more or less +as a complete entity (UCC, USB etc ). All of them should be siblings on +the "root" qe node, using the common properties from there. +The description below applies to the qe of MPC8360 and +more nodes and properties would be extended in the future. + +i) Root QE device + +Required properties: +- compatible : should be "fsl,qe"; +- model : precise model of the QE, Can be "QE", "CPM", or "CPM2" +- reg : offset and length of the device registers. +- bus-frequency : the clock frequency for QUICC Engine. +- fsl,qe-num-riscs: define how many RISC engines the QE has. +- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the + threads. + +Optional properties: +- fsl,firmware-phandle: + Usage: required only if there is no fsl,qe-firmware child node + Value type: + Definition: Points to a firmware node (see "QE Firmware Node" below) + that contains the firmware that should be uploaded for this QE. + The compatible property for the firmware node should say, + "fsl,qe-firmware". + +Recommended properties +- brg-frequency : the internal clock source frequency for baud-rate + generators in Hz. + +Example: + qe@e0100000 { + #address-cells = <1>; + #size-cells = <1>; + #interrupt-cells = <2>; + compatible = "fsl,qe"; + ranges = <0 e0100000 00100000>; + reg = ; + brg-frequency = <0>; + bus-frequency = <179A7B00>; + } + +* Multi-User RAM (MURAM) + +Required properties: +- compatible : should be "fsl,qe-muram", "fsl,cpm-muram". +- mode : the could be "host" or "slave". +- ranges : Should be defined as specified in 1) to describe the + translation of MURAM addresses. +- data-only : sub-node which defines the address area under MURAM + bus that can be allocated as data/parameter + +Example: + + muram@10000 { + compatible = "fsl,qe-muram", "fsl,cpm-muram"; + ranges = <0 00010000 0000c000>; + + data-only@0{ + compatible = "fsl,qe-muram-data", + "fsl,cpm-muram-data"; + reg = <0 c000>; + }; + }; + +* Interrupt Controller (IC) + +Required properties: +- compatible : should be "fsl,qe-ic". +- reg : Address range of IC register set. +- interrupts : interrupts generated by the device. +- interrupt-controller : this device is a interrupt controller. + +Example: + + qeic: interrupt-controller@80 { + interrupt-controller; + compatible = "fsl,qe-ic"; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0x80 0x80>; + interrupts = <95 2 0 0 94 2 0 0>; + }; + +* Serial Interface Block (SI) + +The SI manages the routing of eight TDM lines to the QE block serial drivers +, the MCC and the UCCs, for receive and transmit. + +Required properties: +- compatible : must be "fsl,-qe-si". For t1040, must contain + "fsl,t1040-qe-si". +- reg : Address range of SI register set. + +Example: + + si1: si@700 { + compatible = "fsl,t1040-qe-si"; + reg = <0x700 0x80>; + }; + +* Serial Interface Block RAM(SIRAM) + +store the routing entries of SI + +Required properties: +- compatible : should be "fsl,-qe-siram". For t1040, must contain + "fsl,t1040-qe-siram". +- reg : Address range of SI RAM. + +Example: + + siram1: siram@1000 { + compatible = "fsl,t1040-qe-siram"; + reg = <0x1000 0x800>; + }; + +* QE Firmware Node + +This node defines a firmware binary that is embedded in the device tree, for +the purpose of passing the firmware from bootloader to the kernel, or from +the hypervisor to the guest. + +The firmware node itself contains the firmware binary contents, a compatible +property, and any firmware-specific properties. The node should be placed +inside a QE node that needs it. Doing so eliminates the need for a +fsl,firmware-phandle property. Other QE nodes that need the same firmware +should define an fsl,firmware-phandle property that points to the firmware node +in the first QE node. + +The fsl,firmware property can be specified in the DTS (possibly using incbin) +or can be inserted by the boot loader at boot time. + +Required properties: + - compatible + Usage: required + Value type: + Definition: A standard property. Specify a string that indicates what + kind of firmware it is. For QE, this should be "fsl,qe-firmware". + + - fsl,firmware + Usage: required + Value type: , encoded as an array of bytes + Definition: A standard property. This property contains the firmware + binary "blob". + +Example: + qe1@e0080000 { + compatible = "fsl,qe"; + qe_firmware:qe-firmware { + compatible = "fsl,qe-firmware"; + fsl,firmware = [0x70 0xcd 0x00 0x00 0x01 0x46 0x45 ...]; + }; + ... + }; + + qe2@e0090000 { + compatible = "fsl,qe"; + fsl,firmware-phandle = <&qe_firmware>; + ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/firmware.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/firmware.txt new file mode 100644 index 0000000000000000000000000000000000000000..249db3a15d15c16c1ca105335bcc51d91b68b301 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/firmware.txt @@ -0,0 +1,24 @@ +* Uploaded QE firmware + + If a new firmware has been uploaded to the QE (usually by the + boot loader), then a 'firmware' child node should be added to the QE + node. This node provides information on the uploaded firmware that + device drivers may need. + + Required properties: + - id: The string name of the firmware. This is taken from the 'id' + member of the qe_firmware structure of the uploaded firmware. + Device drivers can search this string to determine if the + firmware they want is already present. + - extended-modes: The Extended Modes bitfield, taken from the + firmware binary. It is a 64-bit number represented + as an array of two 32-bit numbers. + - virtual-traps: The virtual traps, taken from the firmware binary. + It is an array of 8 32-bit numbers. + +Example: + firmware { + id = "Soft-UART"; + extended-modes = <0 0>; + virtual-traps = <0 0 0 0 0 0 0 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/par_io.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/par_io.txt new file mode 100644 index 0000000000000000000000000000000000000000..09b1b05fa6779c60e8df5dfd07c42297da7ff4c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/par_io.txt @@ -0,0 +1,51 @@ +* Parallel I/O Ports + +This node configures Parallel I/O ports for CPUs with QE support. +The node should reside in the "soc" node of the tree. For each +device that using parallel I/O ports, a child node should be created. +See the definition of the Pin configuration nodes below for more +information. + +Required properties: +- device_type : should be "par_io". +- reg : offset to the register set and its length. +- num-ports : number of Parallel I/O ports + +Example: +par_io@1400 { + reg = <1400 100>; + #address-cells = <1>; + #size-cells = <0>; + device_type = "par_io"; + num-ports = <7>; + ucc_pin@1 { + ...... + }; + +Note that "par_io" nodes are obsolete, and should not be used for +the new device trees. Instead, each Par I/O bank should be represented +via its own gpio-controller node: + +Required properties: +- #gpio-cells : should be "2". +- compatible : should be "fsl,-qe-pario-bank", + "fsl,mpc8323-qe-pario-bank". +- reg : offset to the register set and its length. +- gpio-controller : node to identify gpio controllers. + +Example: + qe_pio_a: gpio-controller@1400 { + #gpio-cells = <2>; + compatible = "fsl,mpc8360-qe-pario-bank", + "fsl,mpc8323-qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + }; + + qe_pio_e: gpio-controller@1460 { + #gpio-cells = <2>; + compatible = "fsl,mpc8360-qe-pario-bank", + "fsl,mpc8323-qe-pario-bank"; + reg = <0x1460 0x18>; + gpio-controller; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/pincfg.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/pincfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..5bde8b98a8c9f7c43adc156bfdf5c774451ba554 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/pincfg.txt @@ -0,0 +1,57 @@ +* Pin configuration nodes + +Required properties: +- pio-map : array of pin configurations. Each pin is defined by 6 + integers. The six numbers are respectively: port, pin, dir, + open_drain, assignment, has_irq. + - port : port number of the pin; 0-6 represent port A-G in UM. + - pin : pin number in the port. + - dir : direction of the pin, should encode as follows: + + 0 = The pin is disabled + 1 = The pin is an output + 2 = The pin is an input + 3 = The pin is I/O + + - open_drain : indicates the pin is normal or wired-OR: + + 0 = The pin is actively driven as an output + 1 = The pin is an open-drain driver. As an output, the pin is + driven active-low, otherwise it is three-stated. + + - assignment : function number of the pin according to the Pin Assignment + tables in User Manual. Each pin can have up to 4 possible functions in + QE and two options for CPM. + - has_irq : indicates if the pin is used as source of external + interrupts. + +Example: + ucc_pin@1 { + pio-map = < + /* port pin dir open_drain assignment has_irq */ + 0 3 1 0 1 0 /* TxD0 */ + 0 4 1 0 1 0 /* TxD1 */ + 0 5 1 0 1 0 /* TxD2 */ + 0 6 1 0 1 0 /* TxD3 */ + 1 6 1 0 3 0 /* TxD4 */ + 1 7 1 0 1 0 /* TxD5 */ + 1 9 1 0 2 0 /* TxD6 */ + 1 a 1 0 2 0 /* TxD7 */ + 0 9 2 0 1 0 /* RxD0 */ + 0 a 2 0 1 0 /* RxD1 */ + 0 b 2 0 1 0 /* RxD2 */ + 0 c 2 0 1 0 /* RxD3 */ + 0 d 2 0 1 0 /* RxD4 */ + 1 1 2 0 2 0 /* RxD5 */ + 1 0 2 0 2 0 /* RxD6 */ + 1 4 2 0 2 0 /* RxD7 */ + 0 7 1 0 1 0 /* TX_EN */ + 0 8 1 0 1 0 /* TX_ER */ + 0 f 2 0 1 0 /* RX_DV */ + 0 10 2 0 1 0 /* RX_ER */ + 0 0 2 0 1 0 /* RX_CLK */ + 2 9 1 0 3 0 /* GTX_CLK - CLK10 */ + 2 8 2 0 1 0>; /* GTX125 - CLK9 */ + }; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/ucc.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/ucc.txt new file mode 100644 index 0000000000000000000000000000000000000000..5efb7ac94c7971c7c53ecae1c1d1e2d8e79235be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/ucc.txt @@ -0,0 +1,68 @@ +* UCC (Unified Communications Controllers) + +Required properties: +- device_type : should be "network", "hldc", "uart", "transparent" + "bisync", "atm", or "serial". +- compatible : could be "ucc_geth" or "fsl_atm" and so on. +- cell-index : the ucc number(1-8), corresponding to UCCx in UM. +- reg : Offset and length of the register set for the device +- interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. +- pio-handle : The phandle for the Parallel I/O port configuration. +- port-number : for UART drivers, the port number to use, between 0 and 3. + This usually corresponds to the /dev/ttyQE device, e.g. <0> = /dev/ttyQE0. + The port number is added to the minor number of the device. Unlike the + CPM UART driver, the port-number is required for the QE UART driver. +- soft-uart : for UART drivers, if specified this means the QE UART device + driver should use "Soft-UART" mode, which is needed on some SOCs that have + broken UART hardware. Soft-UART is provided via a microcode upload. +- rx-clock-name: the UCC receive clock source + "none": clock source is disabled + "brg1" through "brg16": clock source is BRG1-BRG16, respectively + "clk1" through "clk24": clock source is CLK1-CLK24, respectively +- tx-clock-name: the UCC transmit clock source + "none": clock source is disabled + "brg1" through "brg16": clock source is BRG1-BRG16, respectively + "clk1" through "clk24": clock source is CLK1-CLK24, respectively +The following two properties are deprecated. rx-clock has been replaced +with rx-clock-name, and tx-clock has been replaced with tx-clock-name. +Drivers that currently use the deprecated properties should continue to +do so, in order to support older device trees, but they should be updated +to check for the new properties first. +- rx-clock : represents the UCC receive clock source. + 0x00 : clock source is disabled; + 0x1~0x10 : clock source is BRG1~BRG16 respectively; + 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively. +- tx-clock: represents the UCC transmit clock source; + 0x00 : clock source is disabled; + 0x1~0x10 : clock source is BRG1~BRG16 respectively; + 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively. + +Required properties for network device_type: +- mac-address : list of bytes representing the ethernet address. +- phy-handle : The phandle for the PHY connected to this controller. + +Recommended properties: +- phy-connection-type : a string naming the controller/PHY interface type, + i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id" (Internal + Delay), "rgmii-txid" (delay on TX only), "rgmii-rxid" (delay on RX only), + "tbi", or "rtbi". + +Example: + ucc@2000 { + device_type = "network"; + compatible = "ucc_geth"; + cell-index = <1>; + reg = <2000 200>; + interrupts = ; + interrupt-parent = <700>; + mac-address = [ 00 04 9f 00 23 23 ]; + rx-clock = "none"; + tx-clock = "clk9"; + phy-handle = <212000>; + phy-connection-type = "gmii"; + pio-handle = <140001>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/usb.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..da13999337a400a1796c10321a50ce33972e0d25 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/qe/usb.txt @@ -0,0 +1,36 @@ +Freescale QUICC Engine USB Controller + +Required properties: +- compatible : should be "fsl,-qe-usb", "fsl,mpc8323-qe-usb". +- reg : the first two cells should contain usb registers location and + length, the next two two cells should contain PRAM location and + length. +- interrupts : should contain USB interrupt. +- fsl,fullspeed-clock : specifies the full speed USB clock source: + "none": clock source is disabled + "brg1" through "brg16": clock source is BRG1-BRG16, respectively + "clk1" through "clk24": clock source is CLK1-CLK24, respectively +- fsl,lowspeed-clock : specifies the low speed USB clock source: + "none": clock source is disabled + "brg1" through "brg16": clock source is BRG1-BRG16, respectively + "clk1" through "clk24": clock source is CLK1-CLK24, respectively +- hub-power-budget : USB power budget for the root hub, in mA. +- gpios : should specify GPIOs in this order: USBOE, USBTP, USBTN, USBRP, + USBRN, SPEED (optional), and POWER (optional). + +Example: + +usb@6c0 { + compatible = "fsl,mpc8360-qe-usb", "fsl,mpc8323-qe-usb"; + reg = <0x6c0 0x40 0x8b00 0x100>; + interrupts = <11>; + interrupt-parent = <&qeic>; + fsl,fullspeed-clock = "clk21"; + gpios = <&qe_pio_b 2 0 /* USBOE */ + &qe_pio_b 3 0 /* USBTP */ + &qe_pio_b 8 0 /* USBTN */ + &qe_pio_b 9 0 /* USBRP */ + &qe_pio_b 11 0 /* USBRN */ + &qe_pio_e 20 0 /* SPEED */ + &qe_pio_e 21 0 /* POWER */>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/serial.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ea76d9d137c56fc41a160b534612a3542ba94b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/serial.txt @@ -0,0 +1,32 @@ +* Serial + +Currently defined compatibles: +- fsl,cpm1-smc-uart +- fsl,cpm2-smc-uart +- fsl,cpm1-scc-uart +- fsl,cpm2-scc-uart +- fsl,qe-uart + +Modem control lines connected to GPIO controllers are listed in the gpios +property as described in booting-without-of.txt, section IX.1 in the following +order: + +CTS, RTS, DCD, DSR, DTR, and RI. + +The gpios property is optional and can be left out when control lines are +not used. + +Example: + + serial@11a00 { + device_type = "serial"; + compatible = "fsl,mpc8272-scc-uart", + "fsl,cpm2-scc-uart"; + reg = <11a00 20 8000 100>; + interrupts = <28 8>; + interrupt-parent = <&PIC>; + fsl,cpm-brg = <1>; + fsl,cpm-command = <00800000>; + gpios = <&gpio_c 15 0 + &gpio_d 29 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/uqe_serial.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/uqe_serial.txt new file mode 100644 index 0000000000000000000000000000000000000000..8823c86c8085478b5df5d78afef3118dc2073148 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/cpm_qe/uqe_serial.txt @@ -0,0 +1,17 @@ +* Serial + +Required Properties: +compatible : must be "fsl,-ucc-uart". For t1040, must be +"fsl,t1040-ucc-uart". +port-number : port number of UCC-UART +tx/rx-clock-name : should be "brg1"-"brg16" for internal clock source, + should be "clk1"-"clk28" for external clock source. + +Example: + + ucc_serial: ucc@2200 { + compatible = "fsl,t1040-ucc-uart"; + port-number = <0>; + rx-clock-name = "brg2"; + tx-clock-name = "brg2"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/guts.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/guts.txt new file mode 100644 index 0000000000000000000000000000000000000000..07adca914d3dcaf1560de8a54bc155f4f16db8b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/guts.txt @@ -0,0 +1,44 @@ +* Global Utilities Block + +The global utilities block controls power management, I/O device +enabling, power-on-reset configuration monitoring, general-purpose +I/O signal configuration, alternate function selection for multiplexed +signals, and clock control. + +Required properties: + + - compatible : Should define the compatible device type for + global-utilities. + Possible compatibles: + "fsl,qoriq-device-config-1.0" + "fsl,qoriq-device-config-2.0" + "fsl,-device-config" + "fsl,-guts" + - reg : Offset and length of the register set for the device. + +Recommended properties: + + - fsl,has-rstcr : Indicates that the global utilities register set + contains a functioning "reset control register" (i.e. the board + is wired to reset upon setting the HRESET_REQ bit in this register). + + - fsl,liodn-bits : Indicates the number of defined bits in the LIODN + registers, for those SOCs that have a PAMU device. + + - little-endian : Indicates that the global utilities block is little + endian. The default is big endian. + +Examples: + global-utilities@e0000 { /* global utilities block */ + compatible = "fsl,mpc8548-guts"; + reg = ; + fsl,has-rstcr; + }; + + guts: global-utilities@e0000 { + compatible = "fsl,qoriq-device-config-1.0"; + reg = <0xe0000 0xe00>; + fsl,has-rstcr; + #sleep-cells = <1>; + fsl,liodn-bits = <12>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/fsl/rcpm.txt b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/rcpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..e284e4e1ccd543c5d82ac96fd2d008a603401a23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/fsl/rcpm.txt @@ -0,0 +1,63 @@ +* Run Control and Power Management +------------------------------------------- +The RCPM performs all device-level tasks associated with device run control +and power management. + +Required properites: + - reg : Offset and length of the register set of the RCPM block. + - fsl,#rcpm-wakeup-cells : The number of IPPDEXPCR register cells in the + fsl,rcpm-wakeup property. + - compatible : Must contain a chip-specific RCPM block compatible string + and (if applicable) may contain a chassis-version RCPM compatible + string. Chip-specific strings are of the form "fsl,-rcpm", + such as: + * "fsl,p2041-rcpm" + * "fsl,p5020-rcpm" + * "fsl,t4240-rcpm" + + Chassis-version strings are of the form "fsl,qoriq-rcpm-", + such as: + * "fsl,qoriq-rcpm-1.0": for chassis 1.0 rcpm + * "fsl,qoriq-rcpm-2.0": for chassis 2.0 rcpm + * "fsl,qoriq-rcpm-2.1": for chassis 2.1 rcpm + +All references to "1.0" and "2.0" refer to the QorIQ chassis version to +which the chip complies. +Chassis Version Example Chips +--------------- ------------------------------- +1.0 p4080, p5020, p5040, p2041, p3041 +2.0 t4240, b4860, b4420 +2.1 t1040, ls1021 + +Example: +The RCPM node for T4240: + rcpm: global-utilities@e2000 { + compatible = "fsl,t4240-rcpm", "fsl,qoriq-rcpm-2.0"; + reg = <0xe2000 0x1000>; + fsl,#rcpm-wakeup-cells = <2>; + }; + +* Freescale RCPM Wakeup Source Device Tree Bindings +------------------------------------------- +Required fsl,rcpm-wakeup property should be added to a device node if the device +can be used as a wakeup source. + + - fsl,rcpm-wakeup: Consists of a phandle to the rcpm node and the IPPDEXPCR + register cells. The number of IPPDEXPCR register cells is defined in + "fsl,#rcpm-wakeup-cells" in the rcpm node. The first register cell is + the bit mask that should be set in IPPDEXPCR0, and the second register + cell is for IPPDEXPCR1, and so on. + + Note: IPPDEXPCR(IP Powerdown Exception Control Register) provides a + mechanism for keeping certain blocks awake during STANDBY and MEM, in + order to use them as wake-up sources. + +Example: + lpuart0: serial@2950000 { + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x2950000 0x0 0x1000>; + interrupts = ; + clocks = <&sysclk>; + clock-names = "ipg"; + fsl,rcpm-wakeup = <&rcpm 0x0 0x40000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/mediatek/pwrap.txt b/arch/arm64/boot/dts/vendor/bindings/soc/mediatek/pwrap.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9987c30f0d52c75eeafdbf3d3c50982ebd9b5f6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/mediatek/pwrap.txt @@ -0,0 +1,64 @@ +MediaTek PMIC Wrapper Driver + +This document describes the binding for the MediaTek PMIC wrapper. + +On MediaTek SoCs the PMIC is connected via SPI. The SPI master interface +is not directly visible to the CPU, but only through the PMIC wrapper +inside the SoC. The communication between the SoC and the PMIC can +optionally be encrypted. Also a non standard Dual IO SPI mode can be +used to increase speed. + +IP Pairing + +on MT8135 the pins of some SoC internal peripherals can be on the PMIC. +The signals of these pins are routed over the SPI bus using the pwrap +bridge. In the binding description below the properties needed for bridging +are marked with "IP Pairing". These are optional on SoCs which do not support +IP Pairing + +Required properties in pwrap device node. +- compatible: + "mediatek,mt2701-pwrap" for MT2701/7623 SoCs + "mediatek,mt6797-pwrap" for MT6797 SoCs + "mediatek,mt7622-pwrap" for MT7622 SoCs + "mediatek,mt8135-pwrap" for MT8135 SoCs + "mediatek,mt8173-pwrap" for MT8173 SoCs +- interrupts: IRQ for pwrap in SOC +- reg-names: Must include the following entries: + "pwrap": Main registers base + "pwrap-bridge": bridge base (IP Pairing) +- reg: Must contain an entry for each entry in reg-names. +- reset-names: Must include the following entries: + "pwrap" + "pwrap-bridge" (IP Pairing) +- resets: Must contain an entry for each entry in reset-names. +- clock-names: Must include the following entries: + "spi": SPI bus clock + "wrap": Main module clock +- clocks: Must contain an entry for each entry in clock-names. + +Optional properities: +- pmic: Using either MediaTek PMIC MFD as the child device of pwrap + See the following for child node definitions: + Documentation/devicetree/bindings/mfd/mt6397.txt + or the regulator-only device as the child device of pwrap, such as MT6380. + See the following definitions for such kinds of devices. + Documentation/devicetree/bindings/regulator/mt6380-regulator.txt + +Example: + pwrap: pwrap@1000f000 { + compatible = "mediatek,mt8135-pwrap"; + reg = <0 0x1000f000 0 0x1000>, + <0 0x11017000 0 0x1000>; + reg-names = "pwrap", "pwrap-bridge"; + interrupts = ; + resets = <&infracfg MT8135_INFRA_PMIC_WRAP_RST>, + <&pericfg MT8135_PERI_PWRAP_BRIDGE_SW_RST>; + reset-names = "pwrap", "pwrap-bridge"; + clocks = <&clk26m>, <&clk26m>; + clock-names = "spi", "wrap"; + + pmic { + compatible = "mediatek,mt6397"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/mediatek/scpsys.txt b/arch/arm64/boot/dts/vendor/bindings/soc/mediatek/scpsys.txt new file mode 100644 index 0000000000000000000000000000000000000000..d6fe16f094af5c42973639efaf9e7e448091d34d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/mediatek/scpsys.txt @@ -0,0 +1,71 @@ +MediaTek SCPSYS +=============== + +The System Control Processor System (SCPSYS) has several power management +related tasks in the system. The tasks include thermal measurement, dynamic +voltage frequency scaling (DVFS), interrupt filter and lowlevel sleep control. +The System Power Manager (SPM) inside the SCPSYS is for the MTCMOS power +domain control. + +The driver implements the Generic PM domain bindings described in +power/power_domain.txt. It provides the power domains defined in +- include/dt-bindings/power/mt8173-power.h +- include/dt-bindings/power/mt6797-power.h +- include/dt-bindings/power/mt2701-power.h +- include/dt-bindings/power/mt2712-power.h +- include/dt-bindings/power/mt7622-power.h + +Required properties: +- compatible: Should be one of: + - "mediatek,mt2701-scpsys" + - "mediatek,mt2712-scpsys" + - "mediatek,mt6797-scpsys" + - "mediatek,mt7622-scpsys" + - "mediatek,mt7623-scpsys", "mediatek,mt2701-scpsys": For MT7623 SoC + - "mediatek,mt7623a-scpsys": For MT7623A SoC + - "mediatek,mt8173-scpsys" +- #power-domain-cells: Must be 1 +- reg: Address range of the SCPSYS unit +- infracfg: must contain a phandle to the infracfg controller +- clock, clock-names: clocks according to the common clock binding. + These are clocks which hardware needs to be + enabled before enabling certain power domains. + Required clocks for MT2701 or MT7623: "mm", "mfg", "ethif" + Required clocks for MT2712: "mm", "mfg", "venc", "jpgdec", "audio", "vdec" + Required clocks for MT6797: "mm", "mfg", "vdec" + Required clocks for MT7622: "hif_sel" + Required clocks for MT7622A: "ethif" + Required clocks for MT8173: "mm", "mfg", "venc", "venc_lt" + +Optional properties: +- vdec-supply: Power supply for the vdec power domain +- venc-supply: Power supply for the venc power domain +- isp-supply: Power supply for the isp power domain +- mm-supply: Power supply for the mm power domain +- venc_lt-supply: Power supply for the venc_lt power domain +- audio-supply: Power supply for the audio power domain +- usb-supply: Power supply for the usb power domain +- mfg_async-supply: Power supply for the mfg_async power domain +- mfg_2d-supply: Power supply for the mfg_2d power domain +- mfg-supply: Power supply for the mfg power domain + +Example: + + scpsys: scpsys@10006000 { + #power-domain-cells = <1>; + compatible = "mediatek,mt8173-scpsys"; + reg = <0 0x10006000 0 0x1000>; + infracfg = <&infracfg>; + clocks = <&clk26m>, + <&topckgen CLK_TOP_MM_SEL>; + <&topckgen CLK_TOP_VENC_SEL>, + <&topckgen CLK_TOP_VENC_LT_SEL>; + clock-names = "mfg", "mm", "venc", "venc_lt"; + }; + +Example consumer: + + afe: mt8173-afe-pcm@11220000 { + compatible = "mediatek,mt8173-afe-pcm"; + power-domains = <&scpsys MT8173_POWER_DOMAIN_AUDIO>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/avtimer.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/avtimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c70b1eb3b553ddf995ab7cb202b104623a4dbf5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/avtimer.txt @@ -0,0 +1,35 @@ +* avtimer + +Avtimer provides an interface for clients to enable avtimer block +on qdsp6. 64 bit AVtimer exposed by qdsp6 is used for audio and video +stream synchronization during capture and playback usecases. + +Required properties: +- reg : physical address and length of avtimer register +- reg-names : AVtimer register name + Required register resource entries are: + "avtimer_lsb_addr" : AVtimer lsb physical address + "avtimer_msb_addr" : AVtimer msb physical address +- compatible : Must be "qcom,avtimer" + +Optional properties: +- clk-div : Divisor to divide the ticks value to get msec value. + If the clock is at 27MHz, the ticks value read from AVTimer + registers will have to be divided by 27, to achieve the msec value. +- clk-mult : Multiplier to multiply the ticks value in order to avoid + a floating point operation if the clock is of decimal value. + E.g. To get msec out of ticks from a 19.2MHz clock source, the ticks + value will have to be divided by 19.2, which will then become a + floating point operation. However, to avoid using a floating point + operation, the msec can be calculated by multiplying ticks with 10 + and dividing the result by 192. i.e. msec = (ticks * 10) / 192; + +Example: + qcom,avtimer@90f7000 { + compatible = "qcom,avtimer"; + reg = <0x90f700c 0x4>, + <0x90f7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <27>; + qcom,clk-mult = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/cdsprm.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/cdsprm.txt new file mode 100644 index 0000000000000000000000000000000000000000..68db0071609a049bbdcfae1b572d8aaf7f590e1c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/cdsprm.txt @@ -0,0 +1,78 @@ +Qualcomm Technologies, Inc. CDSP Request Manager driver + +CDSP Request Manager driver implements an rpmsg interface with +CDSP subsystem to serve L3 frequency and CPU QoS requests from CDSP. +It also interacts with NPU, Camera modules for Cx iPeak mitigations and +thermal module via CDSP/HVX cooling devices for thermal mitigation of +CDSP core. + +Required properties: +- compatible: Must be "qcom,msm-cdsprm-rpmsg" +- qcom,glink-channels: Glink channel for communication with CDSP +- qcom,intents: A list of + +- qcom,msm-cdsp-rm: A sub-device node to define CDSPM RM, Cx iPeak mitigation + driver and CDSP core thermal cooling device + Required properties: + - compatible: Must be "qcom,msm-cdsp-rm" + - qcom,qos-latency-us: pm_qos latency vote to be applied on CDSP request in + micro seconds + - qcom,qos-maxhold-ms: Maximum hold time for pm_qos latency vote from CDSP + in milli seconds + - qcom,compute-cx-limit-en: To enable CX ipeak limit management for compute + subsystem + - qcom,compute-priority-mode: when Cx iPeak mitigation is enabled, + this field sets desired compute priority mode + for AIX and HVX concurrency cases based on + following values, where in HVX and NPU cores, + if required, are throttled in concurrency based + on the selected priority mode + 1 : HVX_MAX - Allows HVX to run at maximum possible + frequency during concurrency with NPU + 2 : AIX_MAX - Allows NPU to run at maximum possible + frequency during concurrency with HVX + 3 : HVX_OVER_AIX - Allows HVX to run at a higher + frequency than NPU during concurrency + 4 : AIX_OVER_HVX - Allows NPU to run at a higher + frequency than HVX during concurrency + - #cooling-cells: Number of cooling cells for CDSP cooling device based on + CDSP Q6 core clock throttling + +- qcom,msm-hvx-rm: A sub-device node to define HVX based thermal cooling device + Required properties: + - compatible: Must be "qcom,msm-hvx-rm" + - #cooling-cells: Number of cooling cells for CDSP cooling device based on + HVX hardware throttling + +- qcom,cdsp-l3: A sub-device node to define CDSP L3 target device for L3 + clock voting + Required properties: + - compatible: Must be "qcom,cdsp-l3" + - qcom,target-dev: The DT device that corresponds to the CDSP L3 + devfreq-simple-dev + +Example: + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x14 64>; + + qcom,cdsp-l3 { + compatible = "qcom,cdsp-l3"; + qcom,target-dev = <&cdsp-cdsp-l3-lat>; + }; + + qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <100>; + qcom,qos-maxhold-ms = <20>; + qcom,compute-cx-limit-en; + qcom,compute-priority-mode = <2>; + #cooling-cells = <2>; + }; + + msm_hvx_rm: qcom,msm_hvx_rm { + compatible = "qcom,msm-hvx-rm"; + #cooling-cells = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/dcc.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/dcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..29cda2db7aedc9c2acc71ffd41bcdd730b37a243 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/dcc.txt @@ -0,0 +1,86 @@ +* Data Capture and Compare (DCC) + +DCC (Data Capture and Compare) is a DMA engine, which is used to save +configuration data or system memory contents during catastrophic failure or +SW trigger. +It can also perform CRC over the same configuration or memory space. + +Required properties: + +- compatible : name of the component used for driver matching, should be + "qcom,dcc" or "qcom,dcc-v2" + +- reg : physical base address and length of the register set(s), SRAM and XPU + of the component. + +- reg-names : names corresponding to each reg property value. + dcc-base: Base address for DCC configuration reg + dcc-ram-base: Start of HLOS address space in SRAM + dcc-xpu-base: Base address for XPU configuration reg + +- dcc-ram-offset: Address offset from the start of the SRAM address space. + +Optional properties: + +- clocks: phandle reference to the parent clock. + +- clock-names: Name of the clock that needs to be enabled for the HW to run. + Turned off when the subsystem is disabled. + +- qcom,save-reg: boolean, To save dcc registers state in memory after dcc + enable and disable + +- link-list subnode: Each link-list subnode represents a link-list configured by default. + It supports configure multiple link-list nodes. + +link-list subnode properties: + +- qcom,data-sink: string, To specify default data sink for dcc, should be one + of the following: + "atb" : To send captured data over ATB to a trace sink + "sram" : To save captured data in dcc internal SRAM. + +- qcom,curr-link-list: int, To specify the link list to use for the default list. + +- qcom,link-list: The values to be programmed into the default link list. + The enum values for DCC operations is defined in dt-bindings/soc/qcom,dcc_v2.h + The following gives basic structure to be used for each operation: + + val is to be interpreted based on what operation is to be performed. + +Example: + + dcc: dcc@4b3000 { + compatible = "qcom,dcc"; + reg = <0x4b3000 0x1000>, + <0x4b4000 0x2000>, + <0x4b0000 0x1>; + reg-names = "dcc-base", "dcc-ram-base", "dcc-xpu-base"; + + clocks = <&clock_gcc clk_gcc_dcc_ahb_clk>; + clock-names = "dcc_clk"; + qcom,save-reg; + + link_list_0 { + qcom,curr-link-list = <2>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + ; + }; + + link_list_2 { + qcom,curr-link-list = <3>; + qcom,data-sink = "atb"; + qcom,link-list = , + , + , + , + , + ; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/fsa4480-i2c.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/fsa4480-i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae128eb7d4643eef0741be33541ddef94d14b40c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/fsa4480-i2c.txt @@ -0,0 +1,18 @@ +Qualcomm Technologies, Inc. + +Fairchild FSA4480 Device + +This device is used for switching orientation of USB-C analog +and for display. It uses I2C communication to set the registers +to configure the switches inside the FSA4480 chip to change +orientation and also to set SBU1/SBU2 connections of USB-C. + +Required properties: + - compatible: Should be "qcom,fsa4480-i2c". + - reg: I2C device address of the device + +Example: + fsa4480: fsa4480@43 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x43>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,apr.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,apr.txt new file mode 100644 index 0000000000000000000000000000000000000000..bcc612cc74232235e553072fddd7169e08f7794e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,apr.txt @@ -0,0 +1,84 @@ +Qualcomm APR (Asynchronous Packet Router) binding + +This binding describes the Qualcomm APR. APR is a IPC protocol for +communication between Application processor and QDSP. APR is mainly +used for audio/voice services on the QDSP. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,apr-v", example "qcom,apr-v2" + +- reg + Usage: required + Value type: + Definition: Destination processor ID. + Possible values are : + 1 - APR simulator + 2 - PC + 3 - MODEM + 4 - ADSP + 5 - APPS + 6 - MODEM2 + 7 - APPS2 + += APR SERVICES +Each subnode of the APR node represents service tied to this apr. The name +of the nodes are not important. The properties of these nodes are defined +by the individual bindings for the specific service +- All APR services MUST contain the following property: + +- reg + Usage: required + Value type: + Definition: APR Service ID + Possible values are : + 3 - DSP Core Service + 4 - Audio Front End Service. + 5 - Voice Stream Manager Service. + 6 - Voice processing manager. + 7 - Audio Stream Manager Service. + 8 - Audio Device Manager Service. + 9 - Multimode voice manager. + 10 - Core voice stream. + 11 - Core voice processor. + 12 - Ultrasound stream manager. + 13 - Listen stream manager. + += EXAMPLE +The following example represents a QDSP based sound card on a MSM8996 device +which uses apr as communication between Apps and QDSP. + + apr@4 { + compatible = "qcom,apr-v2"; + reg = ; + + q6core@3 { + compatible = "qcom,q6core"; + reg = ; + }; + + q6afe@4 { + compatible = "qcom,q6afe"; + reg = ; + + dais { + #sound-dai-cells = <1>; + hdmi@1 { + reg = <1>; + }; + }; + }; + + q6asm@7 { + compatible = "qcom,q6asm"; + reg = ; + ... + }; + + q6adm@8 { + compatible = "qcom,q6adm"; + reg = ; + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,cx_ipeak.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,cx_ipeak.txt new file mode 100644 index 0000000000000000000000000000000000000000..afcdb433d010f539347b9b84e1935a77fd15ef8c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,cx_ipeak.txt @@ -0,0 +1,37 @@ +* Cx iPeak driver to handle requests from various multimedia clients. + +Cx ipeak HW module is used to limit the current drawn by various subsystem +blocks on Cx power rail. Each client needs to set their bit in tcsr register +if it is going to cross its own threshold. If all clients are going to cross +their thresholds then Cx ipeak hw module will raise an interrupt to cDSP block +to throttle cDSP's fmax. +There are SOC like SCUBA in which Cx ipeak HW module raise interrupt to throttle +frequency of other victim clients. + +Required properties: + +- compatible : name of the component used for driver matching, should be one + "qcom,cx-ipeak-v1", "qcom,cx-ipeak-v2" + +- reg : physical base address and length of the register set(s), SRAM and XPU + of the component. + +Optional properties: +- interrupts : Danger and Safe interrupts details having interrupt number and + type of interrupt. + +- interrupt-names : Identifier names for Danger and Safe interrupts. + +- victims_table : Victim clients details having client ID, victim ID and limit + frequency to be applied in case of danger interrupt. + +Example: + + cx_ipeak_lm: cx_ipeak@1fe5040 { + compatible = "qcom,cx-ipeak-v1"; + reg = <0x01fe5040 0x28>; + interrupts = <0 415 IRQ_TYPE_EDGE_RISING>, + <0 416 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "cx_ipeak_danger", "cx_ipeak_safe"; + victims_table = <1 0 844800000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,geni-se.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,geni-se.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff92e5a41bedcc15d4126f9a93306f3efe70b1f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,geni-se.txt @@ -0,0 +1,119 @@ +Qualcomm Technologies, Inc. GENI Serial Engine QUP Wrapper Controller + +Generic Interface (GENI) based Qualcomm Universal Peripheral (QUP) wrapper +is a programmable module for supporting a wide range of serial interfaces +like UART, SPI, I2C, I3C, etc. A single QUP module can provide upto 8 Serial +Interfaces, using its internal Serial Engines. The GENI Serial Engine QUP +Wrapper controller is modeled as a node with zero or more child nodes each +representing a serial engine. + +Required properties: +- compatible: Must be "qcom,geni-se-qup". +- reg: Must contain QUP register address and length. +- clock-names: Must contain "m-ahb" and "s-ahb". +- clocks: AHB clocks needed by the device. + +Required properties if child node exists: +- #address-cells: Must be <1> for Serial Engine Address +- #size-cells: Must be <1> for Serial Engine Address Size +- ranges: Must be present + +Properties for children: + +A GENI based QUP wrapper controller node can contain 0 or more child nodes +representing serial devices. These serial devices can be a QCOM UART, I2C +controller, SPI controller, or some combination of aforementioned devices. +Please refer below the child node definitions for the supported serial +interface protocols. + +Qualcomm Technologies Inc. GENI Serial Engine based I2C Controller + +Required properties: +- compatible: Must be "qcom,geni-i2c". +- reg: Must contain QUP register address and length. +- interrupts: Must contain I2C interrupt. +- clock-names: Must contain "se". +- clocks: Serial engine core clock needed by the device. +- #address-cells: Must be <1> for I2C device address. +- #size-cells: Must be <0> as I2C addresses have no size component. + +Optional property: +- clock-frequency: Desired I2C bus clock frequency in Hz. + When missing default to 100000Hz. + +Child nodes should conform to I2C bus binding as described in i2c.txt. + +Qualcomm Technologies Inc. GENI Serial Engine based UART Controller + +Required properties: +- compatible: Must be "qcom,geni-debug-uart" or "qcom,geni-uart". +- reg: Must contain UART register location and length. +- interrupts: Must contain UART core interrupts. +- clock-names: Must contain "se". +- clocks: Serial engine core clock needed by the device. + +Qualcomm Technologies Inc. GENI Serial Engine based SPI Controller + +Required properties: +- compatible: Must contain "qcom,geni-spi". +- reg: Must contain SPI register location and length. +- interrupts: Must contain SPI controller interrupts. +- clock-names: Must contain "se". +- clocks: Serial engine core clock needed by the device. +- spi-max-frequency: Specifies maximum SPI clock frequency, units - Hz. +- #address-cells: Must be <1> to define a chip select address on + the SPI bus. +- #size-cells: Must be <0>. + +SPI slave nodes must be children of the SPI master node and conform to SPI bus +binding as described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x8c0000 0x6000>; + clock-names = "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + i2c0: i2c@a94000 { + compatible = "qcom,geni-i2c"; + reg = <0xa94000 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qup_1_i2c_5_active>; + pinctrl-1 = <&qup_1_i2c_5_sleep>; + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: serial@a88000 { + compatible = "qcom,geni-debug-uart"; + reg = <0xa88000 0x7000>; + interrupts = ; + clock-names = "se"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qup_1_uart_3_active>; + pinctrl-1 = <&qup_1_uart_3_sleep>; + }; + + spi0: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0xa84000 0x4000>; + interrupts = ; + clock-names = "se"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qup_1_spi_2_active>; + pinctrl-1 = <&qup_1_spi_2_sleep>; + spi-max-frequency = <19200000>; + #address-cells = <1>; + #size-cells = <0>; + }; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink-pkt.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink-pkt.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5c660c808e0921b643c40d72a69e270138db515 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink-pkt.txt @@ -0,0 +1,40 @@ +Qualcomm Technologies, Inc. G-Link Packet Driver (glinkpkt) + +[Root level node] +Required properties: +-compatible : should be "qcom,glinkpkt" + +[Second level nodes] +qcom,glinkpkt-channel-names +Required properties: +-qcom,glinkpkt-transport : the glinkpkt transport layer +-qcom,glinkpkt-edge : the remote subsystem name +-qcom,glinkpkt-ch-name : the glink channel name +-qcom,glinkpkt-dev-name : the glinkpkt device name + +Example: + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-transport = "smd_trans"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-loopback-cntl { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl"; + }; + + qcom,glinkpkt-loopback-data { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink-probe.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink-probe.txt new file mode 100644 index 0000000000000000000000000000000000000000..badb9f9bcd53cb5ebb093f58623a185201b8ab9e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink-probe.txt @@ -0,0 +1,69 @@ +Qualcomm Technologies, Inc. GLINK Probe + +This binding describes the GLINK Probe driver, a device +that initializes the GLINK edge pairs within the system. + +- compatible : + Usage: required + Value type: + Definition: must be "qcom,glink" + += SUBNODES +The GLINK probe node must contain subnodes that describes the +edge-pairs. See qcom,glink.txt for details on how to describe them. + +In addition to the properties in qcom,glink.txt, The GLINK Probe driver +requires the qcom,glink-label and transport type to be specified in the +subnodes. + +- transport : + Usage: required + Value type: + Definition: must be "smem", "spss", or "spi" + +- qcom,glink-label : + Usage: required + Value type: + Definition: specifies the identifier of the remote proc of this edge. + += GLINK_SSR +The GLINK probe driver also initializes the GLINK_SSR channel for the edges +that it brings up. The channel should be specified as a subnode to each edge. In +addition to the properties in qcom,glink.txt to specify a channel device node, +the qcom,notify-edges property must be defined. + +- qcom,notify-edges : + Usage: required + Value type: + Definition: list of phandles that specify the subsystems this glink edge + needs to receive ssr notifications about. + += EXAMPLE +qcom,glink { + compatible = "qcom,glink"; + glink_modem: modem { + transport = "smem"; + qcom,remote-pid = <0>; + mboxes = <&apcs_glb 8>; + mbox-names = "mpss_smem"; + interrupts = ; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>; + }; + }; + + glink_adsp: adsp { + transport = "smem"; + qcom,remote-pid = <2>; + mboxes = <&apcs_glb 4>; + mbox-names = "adsp_smem"; + interrupts = ; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink.txt new file mode 100644 index 0000000000000000000000000000000000000000..39049996ebb7711a7b40e811f060c9be44808715 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,glink.txt @@ -0,0 +1,129 @@ +Qualcomm GLINK edge binding + +This binding describes a Qualcomm GLINK edge, a fifo based mechanism for +communication between subsystem-pairs on various Qualcomm platforms. Two types +of edges can be described by the binding; the GLINK RPM edge and a SMEM based +edge. + +- compatible: + Usage: required for glink-rpm + Value type: + Definition: must be "qcom,glink-rpm" + +- label: + Usage: optional + Value type: + Definition: should specify the subsystem name this edge corresponds to. + +- interrupts: + Usage: required + Value type: + Definition: should specify the IRQ used by the remote processor to + signal this processor about communication related events + +- qcom,rpm-msg-ram: + Usage: required for glink-rpm + Value type: + Definition: handle to RPM message memory resource + +- mboxes: + Usage: required + Value type: + Definition: reference to the "rpm_hlos" mailbox in APCS, as described + in mailbox/mailbox.txt + +- cpu-affinity: + Usage: optional + Value type: + Definition: cores to pin the irq to + += GLINK SPSS +The remote proc on a GLINK SPSS edge expects the descriptors and fifos to be +allocated by this processor. The following bindings are required to inform the +remote proc of the allocated smem. + +- reg-names: + Usage: required for glink-spss + Value type: + Definition: must contain the following registers + "qcom,spss-addr" - to handoff SPSS smem address to rproc + "qcom,spss-size" - to handoff SPSS smem size to rproc + +- reg: + Usage: required for glink-spss + Value type: + Definition: address and size pairs describing the GLINK SPSS registers, + the order must match the entries in reg-names + += GLINK SPI +The following bindings are required for a GLINK SPI edge. They describe the +physical address where the FIFO descriptors are located. The wcd-spi driver +uses these physical address when writing to the spi bus. + +- tx-descriptors: + Usage: required for glink-spi + Value type: + Definition: must contain the physical addresses of the outgoing FIFO + head and tail descriptors. The array should be + +- rx-descriptors: + Usage: required for glink-spi + Value type: + Definition: must contain the physical addresses of the incoming FIFO + head and tail descriptors. The array should be + += GLINK DEVICES +Each subnode of the GLINK node represent function tied to a virtual +communication channel. The name of the nodes are not important. The properties +of these nodes are defined by the individual bindings for the specific function +- but must contain the following property: + +- qcom,glink-channels: + Usage: required + Value type: + Definition: a list of channels tied to this function, used for matching + the function to a set of virtual channels + +- qcom,intents: + Usage: optional + Value type: + Definition: a list of size,amount pairs describing what intents should + be preallocated for this virtual channel. This can be used + to tweak the default intents available for the channel to + meet expectations of the remote. + += EXAMPLE +The following example represents the GLINK RPM node on a MSM8996 device, with +the function for the "rpm_request" channel defined, which is used for +regualtors and root clocks. + + apcs_glb: mailbox@9820000 { + compatible = "qcom,msm8996-apcs-hmss-global"; + reg = <0x9820000 0x1000>; + + #mbox-cells = <1>; + }; + + rpm_msg_ram: memory@68000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0x68000 0x6000>; + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + + interrupts = ; + + qcom,rpm-msg-ram = <&rpm_msg_ram>; + + mboxes = <&apcs_glb 0>; + + rpm-requests { + compatible = "qcom,rpm-msm8996"; + qcom,glink-channels = "rpm_requests"; + + qcom,intents = <0x400 5 + 0x800 1>; + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,gsbi.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,gsbi.txt new file mode 100644 index 0000000000000000000000000000000000000000..fe1855f09dcc36f765e3a48760001db0f9b79361 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,gsbi.txt @@ -0,0 +1,87 @@ +QCOM GSBI (General Serial Bus Interface) Driver + +The GSBI controller is modeled as a node with zero or more child nodes, each +representing a serial sub-node device that is mux'd as part of the GSBI +configuration settings. The mode setting will govern the input/output mode of +the 4 GSBI IOs. + +Required properties: +- compatible: Should contain "qcom,gsbi-v1.0.0" +- cell-index: Should contain the GSBI index +- reg: Address range for GSBI registers +- clocks: required clock +- clock-names: must contain "iface" entry +- qcom,mode : indicates MUX value for configuration of the serial interface. + Please reference dt-bindings/soc/qcom,gsbi.h for valid mux values. + +Optional properties: +- qcom,crci : indicates CRCI MUX value for QUP CRCI ports. Please reference + dt-bindings/soc/qcom,gsbi.h for valid CRCI mux values. +- syscon-tcsr: indicates phandle of TCSR syscon node. Required if child uses + dma. + +Required properties if child node exists: +- #address-cells: Must be 1 +- #size-cells: Must be 1 +- ranges: Must be present + +Properties for children: + +A GSBI controller node can contain 0 or more child nodes representing serial +devices. These serial devices can be a QCOM UART, I2C controller, spi +controller, or some combination of aforementioned devices. + +See the following for child node definitions: +Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt +Documentation/devicetree/bindings/spi/qcom,spi-qup.txt +Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt + +Example for APQ8064: + +#include + + gsbi4@16300000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <4>; + reg = <0x16300000 0x100>; + clocks = <&gcc GSBI4_H_CLK>; + clock-names = "iface"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + qcom,mode = ; + qcom,crci = ; + + syscon-tcsr = <&tcsr>; + + /* child nodes go under here */ + + i2c_qup4: i2c@16380000 { + compatible = "qcom,i2c-qup-v1.1.1"; + reg = <0x16380000 0x1000>; + interrupts = <0 153 0>; + + clocks = <&gcc GSBI4_QUP_CLK>, <&gcc GSBI4_H_CLK>; + clock-names = "core", "iface"; + + clock-frequency = <200000>; + + #address-cells = <1>; + #size-cells = <0>; + + }; + + uart4: serial@16340000 { + compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; + reg = <0x16340000 0x1000>, + <0x16300000 0x1000>; + interrupts = <0 152 0x0>; + clocks = <&gcc GSBI4_UART_CLK>, <&gcc GSBI4_H_CLK>; + clock-names = "core", "iface"; + }; + }; + + tcsr: syscon@1a400000 { + compatible = "qcom,apq8064-tcsr", "syscon"; + reg = <0x1a400000 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,ipcc-self-ping-test.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,ipcc-self-ping-test.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a14355c686244eb77cef6545c25ceae0eb5177c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,ipcc-self-ping-test.txt @@ -0,0 +1,38 @@ +The document describes the device tree binding for testing the IPCC +(Inter-Processor Communication Controller) driver. The test driver triggers a +self-ping onto itself. The expected behavior would be the driver raising +an interrupt using the mailbox interface onto the IPCC driver, which in turn +raises an interrupt on the IPCC hardware. Since the test driver is configured +as loopback, the interrupt generated should come back and hit the APPS +(Application Processor Subsystem). The IPCC driver would hear this interrupt +and forwards it to the IPCC test driver. Hence, the test exercises the inbound +and outbound paths of the driver. + +For details on the IPCC driver, please see qcom,ipcc.txt + +- compatible: + Usage: required + Value type: + Definition: Must be "qcom,ipcc-self-ping" + +- interrupts-extended: + Usage: required + Value type: + Definition: One entry specifying the phandle to the IPCC protocol, the APPS' + client-id, signal-id and IRQ type. + +- mboxes: + Usage: required + Value type: + Definition: One entry specifying the phandle to the IPCC protocol, the APPS' + client-id and the signal-id (same as interrupts-extended). + +Example +------- + ipcc_self_ping: ipcc-self-ping { + compatible = "qcom,ipcc-self-ping"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_APSS + IPCC_MPROC_SIGNAL_SMP2P IRQ_TYPE_LEVEL_HIGH>; + mboxes = <&ipcc_mproc IPCC_CLIENT_APSS IPCC_MPROC_SIGNAL_SMP2P>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,ipcc.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,ipcc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed30505c784a7d8d2dbd8241745ae4c6d188ba4a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,ipcc.txt @@ -0,0 +1,75 @@ +Qualcomm Technologies, Inc. Inter-Processor Communication Controller binding + +The Inter-Processor Communication Controller (IPCC) is a centralized hardware +to route the interrupts across various subsystems. It involves a three-level +addressing scheme: protocol, client and signal. For example, consider an entity +on the Application Processor Subsystem (APSS) that wants to listen to Modem's +interrupts via Shared Memory Point to Point (SMP2P) interface. In such a case, +the client would be Modem (client-id: 2) and the signal would be SMP2P +(signal-id: 2). The SMP2P itself falls under the Multiprocessor (MPROC) protocol +(protocol-id: 0). Please visit include/dt-bindings/soc/qcom/qcom,ipcc.h for the +list of IDs. + +Each protocol has a dedicated interrupt line, and as a result, each protocol is +exposed as a separate interrupt controller. One of the duties of this interrupt +controller driver would be to forward the interrupt to the correct entity +on the APPS. The children inheriting the interrupt-controller would be +mentioning the client-id and signal-id that it's interested in. + +On the other hand, sending an interrupt to a subsystem is done through the +mailbox interface, which again requires client-id and signal-id. + +- compatible: + Usage: required + Value type: + Definition: Must be "qcom,ipcc" + +- reg: + Usage: required + Value type: + Definition: One entry specifying the base address and size corresponding to + the protocol frame + +- interrupts: + Usage: required + Value type: + Definition: One entry specifying the protocol's interrupt + +- interrupt-controller: + Usage: required + Value type: + Definition: Specifies that the device acts as an interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: must be 3 - denoting client-id, signal-id and interrupt type + +- mbox-cells: + Usage: required + Value type: + Definition: must be 2 - denoting client-id and signal-id + +Example +------- + #include + + ipcc_mproc: qcom,ipcc@408000 { + compatible = "qcom,ipcc"; + reg = <0x408000 0x1000>; + interrupts = , + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + }; + +Client-example +-------------- + qcom,smp2p-modem@1799000c { + compatible = "qcom,smp2p"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_SMP2P>; + + /* Other SMP2P fields */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,msm-eud.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,msm-eud.txt new file mode 100644 index 0000000000000000000000000000000000000000..fef7c9e2faa64653e9f8ae7b829b25db9e99cbd7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,msm-eud.txt @@ -0,0 +1,43 @@ +* Qualcomm Technologies Inc Embedded USB Debugger (EUD) + +The EUD (Embedded USB Debugger) is a mini-USB hub implemented +on chip to support the USB-based debug and trace capabilities. + +Required properties: + + - compatible: Should be "qcom,msm-eud" + - interrupt-names: Should be "eud_irq" + - interrupts: Interrupt number + - reg: Should be address and size of EUD register space + - reg-names: Should be "eud_base" + +Optional properties: + - reg-names: Can be "eud_mode_mgr2" for secure eud. + "eud_tcsr_check_reg" needs to be defined, in + case the "eud_mode_mgr2" is protected by this + register. + - qcom,secure-eud-en: To enable secure eud + - qcom,eud-clock-vote-req: To enable clock voting from eud + - qcom,eud-tcsr-check-enable: Boolean- Present if we need to set + "eud_tcsr_check_reg" register before setting + the "eud_mode_mgr2" register. + +Driver notifies clients via extcon for VBUS spoof attach/detach +and charger enable/disable events. Clients registered for these +notifications should have extcon property set to eud. + +An example for EUD device node: + + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x88e0000 0x4000>; + reg-names = "eud_base"; + }; + +An example for EUD extcon client: + + usb3 { + extcon = <&eud>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smd-rpm.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smd-rpm.txt new file mode 100644 index 0000000000000000000000000000000000000000..89e1cb9212f6899a51851ee7488bd6b73cc24db6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smd-rpm.txt @@ -0,0 +1,59 @@ +Qualcomm Resource Power Manager (RPM) over SMD + +This driver is used to interface with the Resource Power Manager (RPM) found in +various Qualcomm platforms. The RPM allows each component in the system to vote +for state of the system resources, such as clocks, regulators and bus +frequencies. + +The SMD information for the RPM edge should be filled out. See qcom,smd.txt for +the required edge properties. All SMD related properties will reside within the +RPM node itself. + += SUBDEVICES + +The RPM exposes resources to its subnodes. The rpm_requests node must be +present and this subnode may contain children that designate regulator +resources. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,rpm-apq8084" + "qcom,rpm-msm8916" + "qcom,rpm-msm8974" + "qcom,rpm-msm8998" + +- qcom,smd-channels: + Usage: required + Value type: + Definition: must be "rpm_requests" + +Refer to Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt +for information on the regulator subnodes that can exist under the rpm_requests. + +Example: + + soc { + apcs: syscon@f9011000 { + compatible = "syscon"; + reg = <0xf9011000 0x1000>; + }; + }; + + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8974"; + qcom,smd-channels = "rpm_requests"; + + ... + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smd.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smd.txt new file mode 100644 index 0000000000000000000000000000000000000000..234ae2256501b7511976ffe6272d34a5c327c769 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smd.txt @@ -0,0 +1,98 @@ +Qualcomm Shared Memory Driver (SMD) binding + +This binding describes the Qualcomm Shared Memory Driver, a fifo based +communication channel for sending data between the various subsystems in +Qualcomm platforms. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,smd" + += EDGES + +Each subnode of the SMD node represents a remote subsystem or a remote +processor of some sort - or in SMD language an "edge". The name of the edges +are not important. +The edge is described by the following properties: + +- interrupts: + Usage: required + Value type: + Definition: should specify the IRQ used by the remote processor to + signal this processor about communication related updates + +- mboxes: + Usage: required + Value type: + Definition: reference to the associated doorbell in APCS, as described + in mailbox/mailbox.txt + +- qcom,ipc: + Usage: required, unless mboxes is specified + Value type: + Definition: three entries specifying the outgoing ipc bit used for + signaling the remote processor: + - phandle to a syscon node representing the apcs registers + - u32 representing offset to the register within the syscon + - u32 representing the ipc bit within the register + +- qcom,smd-edge: + Usage: required + Value type: + Definition: the identifier of the remote processor in the smd channel + allocation table + +- qcom,remote-pid: + Usage: optional + Value type: + Definition: the identifier for the remote processor as known by the rest + of the system. + +- label: + Usage: optional + Value type: + Definition: name of the edge, used for debugging and identification + purposes. The node name will be used if this is not + present. + += SMD DEVICES + +In turn, subnodes of the "edges" represent devices tied to SMD channels on that +"edge". The names of the devices are not important. The properties of these +nodes are defined by the individual bindings for the SMD devices - but must +contain the following property: + +- qcom,smd-channels: + Usage: required + Value type: + Definition: a list of channels tied to this device, used for matching + the device to channels + += EXAMPLE + +The following example represents a smd node, with one edge representing the +"rpm" subsystem. For the "rpm" subsystem we have a device tied to the +"rpm_request" channel. + + apcs: syscon@f9011000 { + compatible = "syscon"; + reg = <0xf9011000 0x1000>; + }; + + smd { + compatible = "qcom,smd"; + + rpm { + interrupts = <0 168 1>; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm_requests { + compatible = "qcom,rpm-msm8974"; + qcom,smd-channels = "rpm_requests"; + + ... + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smem.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smem.txt new file mode 100644 index 0000000000000000000000000000000000000000..9326cdf6e1b1c80083b04e12e95e9387bf48e3ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smem.txt @@ -0,0 +1,57 @@ +Qualcomm Shared Memory Manager binding + +This binding describes the Qualcomm Shared Memory Manager, used to share data +between various subsystems and OSes in Qualcomm platforms. + +- compatible: + Usage: required + Value type: + Definition: must be: + "qcom,smem" + +- memory-region: + Usage: required + Value type: + Definition: handle to memory reservation for main SMEM memory region. + +- qcom,rpm-msg-ram: + Usage: required + Value type: + Definition: handle to RPM message memory resource + +- hwlocks: + Usage: required + Value type: + Definition: reference to a hwspinlock used to protect allocations from + the shared memory + += EXAMPLE +The following example shows the SMEM setup for MSM8974, with a main SMEM region +at 0xfa00000 and the RPM message ram at 0xfc428000: + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + smem_region: smem@fa00000 { + reg = <0xfa00000 0x200000>; + no-map; + }; + }; + + smem@fa00000 { + compatible = "qcom,smem"; + + memory-region = <&smem_region>; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + + hwlocks = <&tcsr_mutex 3>; + }; + + soc { + rpm_msg_ram: memory@fc428000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0xfc428000 0x4000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smp2p.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smp2p.txt new file mode 100644 index 0000000000000000000000000000000000000000..a35af2dafdad6a78b989f7a519f4887203a50735 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smp2p.txt @@ -0,0 +1,110 @@ +Qualcomm Shared Memory Point 2 Point binding + +The Shared Memory Point to Point (SMP2P) protocol facilitates communication of +a single 32-bit value between two processors. Each value has a single writer +(the local side) and a single reader (the remote side). Values are uniquely +identified in the system by the directed edge (local processor ID to remote +processor ID) and a string identifier. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,smp2p" + +- interrupts: + Usage: required + Value type: + Definition: one entry specifying the smp2p notification interrupt + +- mboxes: + Usage: required + Value type: + Definition: reference to the associated doorbell in APCS, as described + in mailbox/mailbox.txt + +- qcom,ipc: + Usage: required, unless mboxes is specified + Value type: + Definition: three entries specifying the outgoing ipc bit used for + signaling the remote end of the smp2p edge: + - phandle to a syscon node representing the apcs registers + - u32 representing offset to the register within the syscon + - u32 representing the ipc bit within the register + +- qcom,smem: + Usage: required + Value type: + Definition: two identifiers of the inbound and outbound smem items used + for this edge + +- qcom,local-pid: + Usage: required + Value type: + Definition: specifies the identfier of the local endpoint of this edge + +- qcom,remote-pid: + Usage: required + Value type: + Definition: specifies the identfier of the remote endpoint of this edge + += SUBNODES +Each SMP2P pair contain a set of inbound and outbound entries, these are +described in subnodes of the smp2p device node. The node names are not +important. + +- qcom,entry-name: + Usage: required + Value type: + Definition: specifies the name of this entry, for inbound entries this + will be used to match against the remotely allocated entry + and for outbound entries this name is used for allocating + entries + +- interrupt-controller: + Usage: required for incoming entries + Value type: + Definition: marks the entry as inbound; the node should be specified + as a two cell interrupt-controller as defined in + "../interrupt-controller/interrupts.txt" + If not specified this node will denote the outgoing entry + +- #interrupt-cells: + Usage: required for incoming entries + Value type: + Definition: must be 2 - denoting the bit in the entry and IRQ flags + +- #qcom,smem-state-cells: + Usage: required for outgoing entries + Value type: + Definition: must be 1 - denoting the bit in the entry + += EXAMPLE +The following example shows the SMP2P setup with the wireless processor, +defined from the 8974 apps processor's point-of-view. It encompasses one +inbound and one outbound entry: + +wcnss-smp2p { + compatible = "qcom,smp2p"; + qcom,smem = <431>, <451>; + + interrupts = <0 143 1>; + + qcom,ipc = <&apcs 8 18>; + + qcom,local-pid = <0>; + qcom,remote-pid = <4>; + + wcnss_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + + #qcom,smem-state-cells = <1>; + }; + + wcnss_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smsm.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smsm.txt new file mode 100644 index 0000000000000000000000000000000000000000..2993b5a97dd648c1da9c560bc431aa5b99ea6615 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,smsm.txt @@ -0,0 +1,104 @@ +Qualcomm Shared Memory State Machine + +The Shared Memory State Machine facilitates broadcasting of single bit state +information between the processors in a Qualcomm SoC. Each processor is +assigned 32 bits of state that can be modified. A processor can through a +matrix of bitmaps signal subscription of notifications upon changes to a +certain bit owned by a certain remote processor. + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,smsm" + +- qcom,ipc-N: + Usage: required + Value type: + Definition: three entries specifying the outgoing ipc bit used for + signaling the N:th remote processor + - phandle to a syscon node representing the apcs registers + - u32 representing offset to the register within the syscon + - u32 representing the ipc bit within the register + +- qcom,local-host: + Usage: optional + Value type: + Definition: identifier of the local processor in the list of hosts, or + in other words specifier of the column in the subscription + matrix representing the local processor + defaults to host 0 + +- #address-cells: + Usage: required + Value type: + Definition: must be 1 + +- #size-cells: + Usage: required + Value type: + Definition: must be 0 + += SUBNODES +Each processor's state bits are described by a subnode of the smsm device node. +Nodes can either be flagged as an interrupt-controller to denote a remote +processor's state bits or the local processors bits. The node names are not +important. + +- reg: + Usage: required + Value type: + Definition: specifies the offset, in words, of the first bit for this + entry + +- #qcom,smem-state-cells: + Usage: required for local entry + Value type: + Definition: must be 1 - denotes bit number + +- interrupt-controller: + Usage: required for remote entries + Value type: + Definition: marks the entry as a interrupt-controller and the state bits + to belong to a remote processor + +- #interrupt-cells: + Usage: required for remote entries + Value type: + Definition: must be 2 - denotes bit number and IRQ flags + +- interrupts: + Usage: required for remote entries + Value type: + Definition: one entry specifying remote IRQ used by the remote processor + to signal changes of its state bits + + += EXAMPLE +The following example shows the SMEM setup for controlling properties of the +wireless processor, defined from the 8974 apps processor's point-of-view. It +encompasses one outbound entry and the outgoing interrupt for the wireless +processor. + +smsm { + compatible = "qcom,smsm"; + + #address-cells = <1>; + #size-cells = <0>; + + qcom,ipc-3 = <&apcs 8 19>; + + apps_smsm: apps@0 { + reg = <0>; + + #qcom,smem-state-cells = <1>; + }; + + wcnss_smsm: wcnss@7 { + reg = <7>; + interrupts = <0 144 1>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,wcnss.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,wcnss.txt new file mode 100644 index 0000000000000000000000000000000000000000..042a2e4159bd64db798a2efaa878ee3e7fd6efa5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qcom,wcnss.txt @@ -0,0 +1,124 @@ +Qualcomm WCNSS Binding + +This binding describes the Qualcomm WCNSS hardware. It consists of control +block and a BT, WiFi and FM radio block, all using SMD as command channels. + +- compatible: + Usage: required + Value type: + Definition: must be: "qcom,wcnss", + +- qcom,smd-channel: + Usage: required + Value type: + Definition: standard SMD property specifying the SMD channel used for + communication with the WiFi firmware. + Should be "WCNSS_CTRL". + +- qcom,mmio: + Usage: required + Value type: + Definition: reference to a node specifying the wcnss "ccu" and "dxe" + register blocks. The node must be compatible with one of + the following: + "qcom,riva", + "qcom,pronto" + += SUBNODES +The subnodes of the wcnss node are optional and describe the individual blocks in +the WCNSS. + +== Bluetooth +The following properties are defined to the bluetooth node: + +- compatible: + Usage: required + Value type: + Definition: must be: + "qcom,wcnss-bt" + +- local-bd-address: + Usage: optional + Value type: + Definition: see Documentation/devicetree/bindings/net/bluetooth.txt + +== WiFi +The following properties are defined to the WiFi node: + +- compatible: + Usage: required + Value type: + Definition: must be one of: + "qcom,wcnss-wlan", + +- interrupts: + Usage: required + Value type: + Definition: should specify the "rx" and "tx" interrupts + +- interrupt-names: + Usage: required + Value type: + Definition: must contain "rx" and "tx" + +- qcom,smem-state: + Usage: required + Value type: + Definition: should reference the tx-enable and tx-rings-empty SMEM states + +- qcom,smem-state-names: + Usage: required + Value type: + Definition: must contain "tx-enable" and "tx-rings-empty" + += EXAMPLE +The following example represents a SMD node, with one edge representing the +"pronto" subsystem, with the wcnss device and its wcn3680 BT and WiFi blocks +described; as found on the 8974 platform. + +smd { + compatible = "qcom,smd"; + + pronto-edge { + interrupts = <0 142 1>; + + qcom,ipc = <&apcs 8 17>; + qcom,smd-edge = <6>; + + wcnss { + compatible = "qcom,wcnss"; + qcom,smd-channels = "WCNSS_CTRL"; + + #address-cells = <1>; + #size-cells = <1>; + + qcom,mmio = <&pronto>; + + bt { + compatible = "qcom,wcnss-bt"; + + /* BD address 00:11:22:33:44:55 */ + local-bd-address = [ 55 44 33 22 11 00 ]; + }; + + wlan { + compatible = "qcom,wcnss-wlan"; + + interrupts = <0 145 0>, <0 146 0>; + interrupt-names = "tx", "rx"; + + qcom,smem-state = <&apps_smsm 10>, <&apps_smsm 9>; + qcom,smem-state-names = "tx-enable", "tx-rings-empty"; + }; + }; + }; +}; + +soc { + pronto: pronto { + compatible = "qcom,pronto"; + + reg = <0xfb204000 0x2000>, <0xfb202000 0x1000>, <0xfb21b000 0x3000>; + reg-names = "ccu", "dxe", "pmu"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qpnp-pbs.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qpnp-pbs.txt new file mode 100644 index 0000000000000000000000000000000000000000..d7aefbf9c19c01bed55f49bd160aa4d8e86d72e9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/qpnp-pbs.txt @@ -0,0 +1,30 @@ +QPNP PBS + +QPNP (Qualcomm Technologies, Inc. Plug N Play) PBS is programmable boot sequence +and this driver is for helping the client drivers triggering such sequence +to be configured in PMIC. + +This document describes the bindings for QPNP PBS driver. + +======================= +Required Node Structure +======================= + +- compatible + Usage: required + Value type: + Definition: should be "qcom,qpnp-pbs". + +- reg + Usage: required + Value type: + Definition: Base address of the PBS registers. + + +======= +Example +======= + pm660l_pbs: qcom,pbs@7300 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7300 0x100>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/qcom/rpmh-rsc.txt b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/rpmh-rsc.txt new file mode 100644 index 0000000000000000000000000000000000000000..f2e94b2907a0f5e675df6b16c01beafb8ea12925 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/qcom/rpmh-rsc.txt @@ -0,0 +1,137 @@ +RPMH RSC: +------------ + +Resource Power Manager Hardened (RPMH) is the mechanism for communicating with +the hardened resource accelerators on Qualcomm Technologies, Inc. SoCs. +Requests to the resources can be written to the Trigger Command Set (TCS) +registers and using a (addr, val) pair and triggered. Messages in the TCS are +then sent in sequence over an internal bus. + +The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity +(Resource State Coordinator a.k.a RSC) that can handle multiple sleep and +active/wake resource requests. Multiple such DRVs can exist in a SoC and can +be written to from Linux. The structure of each DRV follows the same template +with a few variations that are captured by the properties here. + +A TCS may be triggered from Linux or triggered by the F/W after all the CPUs +have powered off to facilitate idle power saving. TCS could be classified as - + + ACTIVE /* Triggered by Linux */ + SLEEP /* Triggered by F/W */ + WAKE /* Triggered by F/W */ + CONTROL /* Triggered by F/W */ + +The order in which they are described in the DT, should match the hardware +configuration. + +Requests can be made for the state of a resource, when the subsystem is active +or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state +will be an aggregate of the sleep votes from each of those subsystems. Clients +may request a sleep value for their shared resources in addition to the active +mode requests. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: Should be "qcom,rpmh-rsc". + +- reg: + Usage: required + Value type: + Definition: The first register specifies the base address of the + DRV(s). The number of DRVs in the dependent on the RSC. + The tcs-offset specifies the start address of the + TCS in the DRVs. + +- reg-names: + Usage: required + Value type: + Definition: Maps the register specified in the reg property. Must be + "drv-0", "drv-1", "drv-2" etc and "tcs-offset". The + +- interrupts: + Usage: required + Value type: + Definition: The interrupt that trips when a message complete/response + is received for this DRV from the accelerators. + +- qcom,drv-id: + Usage: required + Value type: + Definition: The id of the DRV in the RSC block that will be used by + this controller. + +- qcom,tcs-config: + Usage: required + Value type: + Definition: The tuple defining the configuration of TCS. + Must have 2 cells which describe each TCS type. + . + The order of the TCS must match the hardware + configuration. + - Cell #1 (TCS Type): TCS types to be specified - + ACTIVE_TCS + SLEEP_TCS + WAKE_TCS + CONTROL_TCS + - Cell #2 (Number of TCS): + +- label: + Usage: optional + Value type: + Definition: Name for the RSC. The name would be used in trace logs. + +Drivers that want to use the RSC to communicate with RPMH must specify their +bindings as child nodes of the RSC controllers they wish to communicate with. + +Example 1: + +For a TCS whose RSC base address is is 0x179C0000 and is at a DRV id of 2, the +register offsets for DRV2 start at 0D00, the register calculations are like +this - +DRV0: 0x179C0000 +DRV2: 0x179C0000 + 0x10000 = 0x179D0000 +DRV2: 0x179C0000 + 0x10000 * 2 = 0x179E0000 +TCS-OFFSET: 0xD00 + + apps_rsc: rsc@179c0000 { + label = "apps_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0x179c0000 0x10000>, + <0x179d0000 0x10000>, + <0x179e0000 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + }; + +Example 2: + +For a TCS whose RSC base address is 0xAF20000 and is at DRV id of 0, the +register offsets for DRV0 start at 01C00, the register calculations are like +this - +DRV0: 0xAF20000 +TCS-OFFSET: 0x1C00 + + disp_rsc: rsc@af20000 { + label = "disp_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0xaf20000 0x10000>; + reg-names = "drv-0"; + interrupts = ; + qcom,tcs-offset = <0x1c00>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/rockchip/grf.txt b/arch/arm64/boot/dts/vendor/bindings/soc/rockchip/grf.txt new file mode 100644 index 0000000000000000000000000000000000000000..7dc5ce858a0ee3a6659cc0be7a0d3194f7a6fa3e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/rockchip/grf.txt @@ -0,0 +1,47 @@ +* Rockchip General Register Files (GRF) + +The general register file will be used to do static set by software, which +is composed of many registers for system control. + +From RK3368 SoCs, the GRF is divided into two sections, +- GRF, used for general non-secure system, +- SGRF, used for general secure system, +- PMUGRF, used for always on system + +On RK3328 SoCs, the GRF adds a section for USB2PHYGRF, + +Required Properties: + +- compatible: GRF should be one of the following: + - "rockchip,rk3036-grf", "syscon": for rk3036 + - "rockchip,rk3066-grf", "syscon": for rk3066 + - "rockchip,rk3188-grf", "syscon": for rk3188 + - "rockchip,rk3228-grf", "syscon": for rk3228 + - "rockchip,rk3288-grf", "syscon": for rk3288 + - "rockchip,rk3328-grf", "syscon": for rk3328 + - "rockchip,rk3368-grf", "syscon": for rk3368 + - "rockchip,rk3399-grf", "syscon": for rk3399 + - "rockchip,rv1108-grf", "syscon": for rv1108 +- compatible: PMUGRF should be one of the following: + - "rockchip,rk3368-pmugrf", "syscon": for rk3368 + - "rockchip,rk3399-pmugrf", "syscon": for rk3399 +- compatible: SGRF should be one of the following + - "rockchip,rk3288-sgrf", "syscon": for rk3288 +- compatible: USB2PHYGRF should be one of the followings + - "rockchip,rk3328-usb2phy-grf", "syscon": for rk3328 +- compatible: USBGRF should be one of the following + - "rockchip,rv1108-usbgrf", "syscon": for rv1108 +- reg: physical base address of the controller and length of memory mapped + region. + +Example: GRF and PMUGRF of RK3399 SoCs + + pmugrf: syscon@ff320000 { + compatible = "rockchip,rk3399-pmugrf", "syscon"; + reg = <0x0 0xff320000 0x0 0x1000>; + }; + + grf: syscon@ff770000 { + compatible = "rockchip,rk3399-grf", "syscon"; + reg = <0x0 0xff770000 0x0 0x10000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/rockchip/power_domain.txt b/arch/arm64/boot/dts/vendor/bindings/soc/rockchip/power_domain.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d49d0a2ff29df92201d62f1171eeaec5e5f9d22 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/rockchip/power_domain.txt @@ -0,0 +1,132 @@ +* Rockchip Power Domains + +Rockchip processors include support for multiple power domains which can be +powered up/down by software based on different application scenes to save power. + +Required properties for power domain controller: +- compatible: Should be one of the following. + "rockchip,px30-power-controller" - for PX30 SoCs. + "rockchip,rk3036-power-controller" - for RK3036 SoCs. + "rockchip,rk3128-power-controller" - for RK3128 SoCs. + "rockchip,rk3228-power-controller" - for RK3228 SoCs. + "rockchip,rk3288-power-controller" - for RK3288 SoCs. + "rockchip,rk3328-power-controller" - for RK3328 SoCs. + "rockchip,rk3366-power-controller" - for RK3366 SoCs. + "rockchip,rk3368-power-controller" - for RK3368 SoCs. + "rockchip,rk3399-power-controller" - for RK3399 SoCs. +- #power-domain-cells: Number of cells in a power-domain specifier. + Should be 1 for multiple PM domains. +- #address-cells: Should be 1. +- #size-cells: Should be 0. + +Required properties for power domain sub nodes: +- reg: index of the power domain, should use macros in: + "include/dt-bindings/power/px30-power.h" - for PX30 type power domain. + "include/dt-bindings/power/rk3036-power.h" - for RK3036 type power domain. + "include/dt-bindings/power/rk3128-power.h" - for RK3128 type power domain. + "include/dt-bindings/power/rk3228-power.h" - for RK3228 type power domain. + "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. + "include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain. + "include/dt-bindings/power/rk3366-power.h" - for RK3366 type power domain. + "include/dt-bindings/power/rk3368-power.h" - for RK3368 type power domain. + "include/dt-bindings/power/rk3399-power.h" - for RK3399 type power domain. +- clocks (optional): phandles to clocks which need to be enabled while power domain + switches state. +- pm_qos (optional): phandles to qos blocks which need to be saved and restored + while power domain switches state. + +Qos Example: + + qos_gpu: qos_gpu@ffaf0000 { + compatible ="syscon"; + reg = <0x0 0xffaf0000 0x0 0x20>; + }; + +Example: + + power: power-controller { + compatible = "rockchip,rk3288-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + pd_gpu { + reg = ; + clocks = <&cru ACLK_GPU>; + pm_qos = <&qos_gpu>; + }; + }; + + power: power-controller { + compatible = "rockchip,rk3368-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + pd_gpu_1 { + reg = ; + clocks = <&cru ACLK_GPU_CFG>; + }; + }; + +Example 2: + power: power-controller { + compatible = "rockchip,rk3399-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + pd_vio { + #address-cells = <1>; + #size-cells = <0>; + reg = ; + + pd_vo { + #address-cells = <1>; + #size-cells = <0>; + reg = ; + + pd_vopb { + reg = ; + }; + + pd_vopl { + reg = ; + }; + }; + }; + }; + +Node of a device using power domains must have a power-domains property, +containing a phandle to the power device node and an index specifying which +power domain to use. +The index should use macros in: + "include/dt-bindings/power/px30-power.h" - for px30 type power domain. + "include/dt-bindings/power/rk3036-power.h" - for rk3036 type power domain. + "include/dt-bindings/power/rk3128-power.h" - for rk3128 type power domain. + "include/dt-bindings/power/rk3128-power.h" - for rk3228 type power domain. + "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain. + "include/dt-bindings/power/rk3328-power.h" - for rk3328 type power domain. + "include/dt-bindings/power/rk3366-power.h" - for rk3366 type power domain. + "include/dt-bindings/power/rk3368-power.h" - for rk3368 type power domain. + "include/dt-bindings/power/rk3399-power.h" - for rk3399 type power domain. + +Example of the node using power domain: + + node { + /* ... */ + power-domains = <&power RK3288_PD_GPU>; + /* ... */ + }; + + node { + /* ... */ + power-domains = <&power RK3368_PD_GPU_1>; + /* ... */ + }; + + node { + /* ... */ + power-domains = <&power RK3399_PD_VOPB>; + /* ... */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/ti/keystone-navigator-dma.txt b/arch/arm64/boot/dts/vendor/bindings/soc/ti/keystone-navigator-dma.txt new file mode 100644 index 0000000000000000000000000000000000000000..337c4ea5c57b8583562bacbd9169db246f22f17e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/ti/keystone-navigator-dma.txt @@ -0,0 +1,111 @@ +Keystone Navigator DMA Controller + +This document explains the device tree bindings for the packet dma +on keystone devices. The Keystone Navigator DMA driver sets up the dma +channels and flows for the QMSS(Queue Manager SubSystem) who triggers +the actual data movements across clients using destination queues. Every +client modules like NETCP(Network Coprocessor), SRIO(Serial Rapid IO), +CRYPTO Engines etc has its own instance of dma hardware. QMSS has also +an internal packet DMA module which is used as an infrastructure DMA +with zero copy. + +Navigator DMA cloud layout: + ------------------ + | Navigator DMAs | + ------------------ + | + |-> DMA instance #0 + | + |-> DMA instance #1 + . + . + | + |-> DMA instance #n + +Navigator DMA properties: +Required properties: + - compatible: Should be "ti,keystone-navigator-dma" + - clocks: phandle to dma instances clocks. The clock handles can be as + many as the dma instances. The order should be maintained as per + the dma instances. + - ti,navigator-cloud-address: Should contain base address for the multi-core + navigator cloud and number of addresses depends on SOC integration + configuration.. Navigator cloud global address needs to be programmed + into DMA and the DMA uses it as the physical addresses to reach queue + managers. Note that these addresses though points to queue managers, + they are relevant only from DMA perspective. The QMSS may not choose to + use them since it has a different address space view to reach all + its components. + +DMA instance properties: +Required properties: + - reg: Should contain register location and length of the following dma + register regions. Register regions should be specified in the following + order. + - Global control register region (global). + - Tx DMA channel configuration register region (txchan). + - Rx DMA channel configuration register region (rxchan). + - Tx DMA channel Scheduler configuration register region (txsched). + - Rx DMA flow configuration register region (rxflow). + +Optional properties: + - reg-names: Names for the register regions. + - ti,enable-all: Enable all DMA channels vs clients opening specific channels + what they need. This property is useful for the userspace fast path + case where the linux drivers enables the channels used by userland + stack. + - ti,loop-back: To loopback Tx streaming I/F to Rx streaming I/F. Used for + infrastructure transfers. + - ti,rx-retry-timeout: Number of dma cycles to wait before retry on buffer + starvation. + +Example: + + knav_dmas: knav_dmas@0 { + compatible = "ti,keystone-navigator-dma"; + clocks = <&papllclk>, <&clkxge>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + ti,navigator-cloud-address = <0x23a80000 0x23a90000 + 0x23aa0000 0x23ab0000>; + + dma_gbe: dma_gbe@0 { + reg = <0x2004000 0x100>, + <0x2004400 0x120>, + <0x2004800 0x300>, + <0x2004c00 0x120>, + <0x2005000 0x400>; + reg-names = "global", "txchan", "rxchan", + "txsched", "rxflow"; + }; + + dma_xgbe: dma_xgbe@0 { + reg = <0x2fa1000 0x100>, + <0x2fa1400 0x200>, + <0x2fa1800 0x200>, + <0x2fa1c00 0x200>, + <0x2fa2000 0x400>; + reg-names = "global", "txchan", "rxchan", + "txsched", "rxflow"; + }; + }; + +Navigator DMA client: +Required properties: + - ti,navigator-dmas: List of one or more DMA specifiers, each consisting of + - A phandle pointing to DMA instance node + - A DMA channel number as a phandle arg. + - ti,navigator-dma-names: Contains dma channel name for each DMA specifier in + the 'ti,navigator-dmas' property. + +Example: + + netcp: netcp@2090000 { + .. + ti,navigator-dmas = <&dma_gbe 22>, + <&dma_gbe 23>, + <&dma_gbe 8>; + ti,navigator-dma-names = "netrx0", "netrx1", "nettx"; + .. + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/ti/keystone-navigator-qmss.txt b/arch/arm64/boot/dts/vendor/bindings/soc/ti/keystone-navigator-qmss.txt new file mode 100644 index 0000000000000000000000000000000000000000..b025770eeb928876748ec9c10ab4cb6abb0a305f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/ti/keystone-navigator-qmss.txt @@ -0,0 +1,238 @@ +* Texas Instruments Keystone Navigator Queue Management SubSystem driver + +The QMSS (Queue Manager Sub System) found on Keystone SOCs is one of +the main hardware sub system which forms the backbone of the Keystone +multi-core Navigator. QMSS consist of queue managers, packed-data structure +processors(PDSP), linking RAM, descriptor pools and infrastructure +Packet DMA. +The Queue Manager is a hardware module that is responsible for accelerating +management of the packet queues. Packets are queued/de-queued by writing or +reading descriptor address to a particular memory mapped location. The PDSPs +perform QMSS related functions like accumulation, QoS, or event management. +Linking RAM registers are used to link the descriptors which are stored in +descriptor RAM. Descriptor RAM is configurable as internal or external memory. +The QMSS driver manages the PDSP setups, linking RAM regions, +queue pool management (allocation, push, pop and notify) and descriptor +pool management. + + +Required properties: +- compatible : Must be "ti,keystone-navigator-qmss". + : Must be "ti,66ak2g-navss-qm" for QMSS on K2G SoC. +- clocks : phandle to the reference clock for this device. +- queue-range : total range of queue numbers for the device. +- linkram0 :
for internal link ram, where size is the total + link ram entries. +- linkram1 :
for external link ram, where size is the total + external link ram entries. If the address is specified as "0" + driver will allocate memory. +- qmgrs : child node describing the individual queue managers on the + SoC. On keystone 1 devices there should be only one node. + On keystone 2 devices there can be more than 1 node. + -- managed-queues : the actual queues managed by each queue manager + instance, specified as <"base queue #" "# of queues">. + -- reg : Address and size of the register set for the device. + Register regions should be specified in the following + order + - Queue Peek region. + - Queue status RAM. + - Queue configuration region. + - Descriptor memory setup region. + - Queue Management/Queue Proxy region for queue Push. + - Queue Management/Queue Proxy region for queue Pop. + +For QMSS on K2G SoC, following QM reg indexes are used in that order + - Queue Peek region. + - Queue configuration region. + - Queue Management/Queue Proxy region for queue Push/Pop. + +- queue-pools : child node classifying the queue ranges into pools. + Queue ranges are grouped into 3 type of pools: + - qpend : pool of qpend(interruptible) queues + - general-purpose : pool of general queues, primarily used + as free descriptor queues or the + transmit DMA queues. + - accumulator : pool of queues on PDSP accumulator channel + Each range can have the following properties: + -- qrange : number of queues to use per queue range, specified as + <"base queue #" "# of queues">. + -- interrupts : Optional property to specify the interrupt mapping + for interruptible queues. The driver additionally sets + the interrupt affinity hint based on the cpu mask. + -- qalloc-by-id : Optional property to specify that the queues in this + range can only be allocated by queue id. + -- accumulator : Accumulator channel specification. Any of the PDSPs in + QMSS can be loaded with the accumulator firmware. The + accumulator firmware’s job is to poll a select number of + queues looking for descriptors that have been pushed + into them. Descriptors are popped from the queue and + placed in a buffer provided by the host. When the list + becomes full or a programmed time period expires, the + accumulator triggers an interrupt to the host to read + the buffer for descriptor information. This firmware + comes in 16, 32, and 48 channel builds. Each of these + channels can be configured to monitor 32 contiguous + queues. Accumulator channel property is specified as: + + pdsp-id : QMSS PDSP running accumulator firmware + on which the channel has to be + configured + channel : Accumulator channel number + entries : Size of the accumulator descriptor list + pacing mode : Interrupt pacing mode + 0 : None, i.e interrupt on list full only + 1 : Time delay since last interrupt + 2 : Time delay since first new packet + 3 : Time delay since last new packet + latency : time to delay the interrupt, specified + in microseconds. + -- multi-queue : Optional property to specify that the channel has to + monitor up to 32 queues starting at the base queue #. +- descriptor-regions : child node describing the memory regions for keystone + navigator packet DMA descriptors. The memory for + descriptors will be allocated by the driver. + -- id : region number in QMSS. + -- region-spec : specifies the number of descriptors in the + region, specified as + <"# of descriptors" "descriptor size">. + -- link-index : start index, i.e. index of the first + descriptor in the region. + +Optional properties: +- dma-coherent : Present if DMA operations are coherent. +- pdsps : child node describing the PDSP configuration. + -- firmware : firmware to be loaded on the PDSP. + -- id : the qmss pdsp that will run the firmware. + -- reg : Address and size of the register set for the PDSP. + Register regions should be specified in the following + order + - PDSP internal RAM region. + - PDSP control/status region registers. + - QMSS interrupt distributor registers. + - PDSP command interface region. + +Example: + +qmss: qmss@2a40000 { + compatible = "ti,keystone-qmss"; + dma-coherent; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&chipclk13>; + ranges; + queue-range = <0 0x4000>; + linkram0 = <0x100000 0x8000>; + linkram1 = <0x0 0x10000>; + + qmgrs { + #address-cells = <1>; + #size-cells = <1>; + ranges; + qmgr0 { + managed-queues = <0 0x2000>; + reg = <0x2a40000 0x20000>, + <0x2a06000 0x400>, + <0x2a02000 0x1000>, + <0x2a03000 0x1000>, + <0x23a80000 0x20000>, + <0x2a80000 0x20000>; + }; + + qmgr1 { + managed-queues = <0x2000 0x2000>; + reg = <0x2a60000 0x20000>, + <0x2a06400 0x400>, + <0x2a04000 0x1000>, + <0x2a05000 0x1000>, + <0x23aa0000 0x20000>, + <0x2aa0000 0x20000>; + }; + }; + queue-pools { + qpend { + qpend-0 { + qrange = <658 8>; + interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; + }; + qpend-1 { + qrange = <8704 16>; + interrupts = <0 48 0xf04 0 49 0xf04 0 50 0xf04 + 0 51 0xf04 0 52 0xf04 0 53 0xf04 + 0 54 0xf04 0 55 0xf04 0 56 0xf04 + 0 57 0xf04 0 58 0xf04 0 59 0xf04 + 0 60 0xf04 0 61 0xf04 0 62 0xf04 + 0 63 0xf04>; + qalloc-by-id; + }; + qpend-2 { + qrange = <8720 16>; + interrupts = <0 64 0xf04 0 65 0xf04 0 66 0xf04 + 0 59 0xf04 0 68 0xf04 0 69 0xf04 + 0 70 0xf04 0 71 0xf04 0 72 0xf04 + 0 73 0xf04 0 74 0xf04 0 75 0xf04 + 0 76 0xf04 0 77 0xf04 0 78 0xf04 + 0 79 0xf04>; + }; + }; + general-purpose { + gp-0 { + qrange = <4000 64>; + }; + netcp-tx { + qrange = <640 9>; + qalloc-by-id; + }; + }; + accumulator { + acc-0 { + qrange = <128 32>; + accumulator = <0 36 16 2 50>; + interrupts = <0 215 0xf01>; + multi-queue; + qalloc-by-id; + }; + acc-1 { + qrange = <160 32>; + accumulator = <0 37 16 2 50>; + interrupts = <0 216 0xf01>; + multi-queue; + }; + acc-2 { + qrange = <192 32>; + accumulator = <0 38 16 2 50>; + interrupts = <0 217 0xf01>; + multi-queue; + }; + acc-3 { + qrange = <224 32>; + accumulator = <0 39 16 2 50>; + interrupts = <0 218 0xf01>; + multi-queue; + }; + }; + }; + descriptor-regions { + #address-cells = <1>; + #size-cells = <1>; + ranges; + region-12 { + id = <12>; + region-spec = <8192 128>; /* num_desc desc_size */ + link-index = <0x4000>; + }; + }; + pdsps { + #address-cells = <1>; + #size-cells = <1>; + ranges; + pdsp0@2a10000 { + reg = <0x2a10000 0x1000>, + <0x2a0f000 0x100>, + <0x2a0c000 0x3c8>, + <0x2a20000 0x4000>; + id = <0>; + }; + }; +}; /* qmss */ diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/ti/sci-pm-domain.txt b/arch/arm64/boot/dts/vendor/bindings/soc/ti/sci-pm-domain.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7b00a7c0f68944b7b29a9f515f342bd96d3da63 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/ti/sci-pm-domain.txt @@ -0,0 +1,58 @@ +Texas Instruments TI-SCI Generic Power Domain +--------------------------------------------- + +Some TI SoCs contain a system controller (like the PMMC, etc...) that is +responsible for controlling the state of the IPs that are present. +Communication between the host processor running an OS and the system +controller happens through a protocol known as TI-SCI [1]. + +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt + +PM Domain Node +============== +The PM domain node represents the global PM domain managed by the PMMC, which +in this case is the implementation as documented by the generic PM domain +bindings in Documentation/devicetree/bindings/power/power_domain.txt. Because +this relies on the TI SCI protocol to communicate with the PMMC it must be a +child of the pmmc node. + +Required Properties: +-------------------- +- compatible: should be "ti,sci-pm-domain" +- #power-domain-cells: Must be 1 so that an id can be provided in each + device node. + +Example (K2G): +------------- + pmmc: pmmc { + compatible = "ti,k2g-sci"; + ... + + k2g_pds: power-controller { + compatible = "ti,sci-pm-domain"; + #power-domain-cells = <1>; + }; + }; + +PM Domain Consumers +=================== +Hardware blocks belonging to a PM domain should contain a "power-domains" +property that is a phandle pointing to the corresponding PM domain node +along with an index representing the device id to be passed to the PMMC +for device control. + +Required Properties: +-------------------- +- power-domains: phandle pointing to the corresponding PM domain node + and an ID representing the device. + +See http://processors.wiki.ti.com/index.php/TISCI#66AK2G02_Data for the list +of valid identifiers for k2g. + +Example (K2G): +-------------------- + uart0: serial@2530c00 { + compatible = "ns16550a"; + ... + power-domains = <&k2g_pds 0x002c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/ti/wkup_m3_ipc.txt b/arch/arm64/boot/dts/vendor/bindings/soc/ti/wkup_m3_ipc.txt new file mode 100644 index 0000000000000000000000000000000000000000..401550487ed6f69f036a810dd6e01edcef745b87 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/ti/wkup_m3_ipc.txt @@ -0,0 +1,57 @@ +Wakeup M3 IPC Driver +===================== + +The TI AM33xx and AM43xx family of devices use a small Cortex M3 co-processor +(commonly referred to as Wakeup M3 or CM3) to help with various low power tasks +that cannot be controlled from the MPU, like suspend/resume and certain deep +C-states for CPU Idle. Once the wkup_m3_ipc driver uses the wkup_m3_rproc driver +to boot the wkup_m3, it handles communication with the CM3 using IPC registers +present in the SoC's control module and a mailbox. The wkup_m3_ipc exposes an +API to allow the SoC PM code to execute specific PM tasks. + +Wkup M3 Device Node: +==================== +A wkup_m3_ipc device node is used to represent the IPC registers within an +SoC. + +Required properties: +-------------------- +- compatible: Should be, + "ti,am3352-wkup-m3-ipc" for AM33xx SoCs + "ti,am4372-wkup-m3-ipc" for AM43xx SoCs +- reg: Contains the IPC register address space to communicate + with the Wakeup M3 processor +- interrupts: Contains the interrupt information for the wkup_m3 + interrupt that signals the MPU. +- ti,rproc: phandle to the wkup_m3 rproc node so the IPC driver + can boot it. +- mboxes: phandles used by IPC framework to get correct mbox + channel for communication. Must point to appropriate + mbox_wkupm3 child node. + +Example: +-------- +/* AM33xx */ + l4_wkup: l4_wkup@44c00000 { + ... + + scm: scm@210000 { + compatible = "ti,am3-scm", "simple-bus"; + reg = <0x210000 0x2000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x210000 0x2000>; + + ... + + wkup_m3_ipc: wkup_m3_ipc@1324 { + compatible = "ti,am3352-wkup-m3-ipc"; + reg = <0x1324 0x24>; + interrupts = <78>; + ti,rproc = <&wkup_m3>; + mboxes = <&mailbox &mbox_wkupm3>; + }; + + ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/xilinx/xlnx,vcu.txt b/arch/arm64/boot/dts/vendor/bindings/soc/xilinx/xlnx,vcu.txt new file mode 100644 index 0000000000000000000000000000000000000000..6786d6715df004175de1bd1964e13bddee26df0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/xilinx/xlnx,vcu.txt @@ -0,0 +1,31 @@ +LogicoreIP designed compatible with Xilinx ZYNQ family. +------------------------------------------------------- + +General concept +--------------- + +LogicoreIP design to provide the isolation between processing system +and programmable logic. Also provides the list of register set to configure +the frequency. + +Required properties: +- compatible: shall be one of: + "xlnx,vcu" + "xlnx,vcu-logicoreip-1.0" +- reg, reg-names: There are two sets of registers need to provide. + 1. vcu slcr + 2. Logicore + reg-names should contain name for the each register sequence. +- clocks: phandle for aclk and pll_ref clocksource +- clock-names: The identification string, "aclk", is always required for + the axi clock. "pll_ref" is required for pll. +Example: + + xlnx_vcu: vcu@a0040000 { + compatible = "xlnx,vcu-logicoreip-1.0"; + reg = <0x0 0xa0040000 0x0 0x1000>, + <0x0 0xa0041000 0x0 0x1000>; + reg-names = "vcu_slcr", "logicore"; + clocks = <&si570_1>, <&clkc 71>; + clock-names = "pll_ref", "aclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/soc/zte/pd-2967xx.txt b/arch/arm64/boot/dts/vendor/bindings/soc/zte/pd-2967xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..7629de1c2c727fa9c14117e8b591c4ccb778d8b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/soc/zte/pd-2967xx.txt @@ -0,0 +1,19 @@ +* ZTE zx2967 family Power Domains + +zx2967 family includes support for multiple power domains which are used +to gate power to one or more peripherals on the processor. + +Required Properties: + - compatible: should be one of the following. + * zte,zx296718-pcu - for zx296718 power domain. + - reg: physical base address of the controller and length of memory mapped + region. + - #power-domain-cells: Must be 1. + +Example: + + pcu_domain: pcu@117000 { + compatible = "zte,zx296718-pcu"; + reg = <0x00117000 0x1000>; + #power-domain-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ac97-bus.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ac97-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..103c428f2595f5760a70e8f07e654a0f68d592f5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ac97-bus.txt @@ -0,0 +1,32 @@ +Generic AC97 Device Properties + +This documents describes the devicetree bindings for an ac97 controller child +node describing ac97 codecs. + +Required properties: +-compatible : Must be "ac97,vendor_id1,vendor_id2 + The ids shall be the 4 characters hexadecimal encoding, such as + given by "%04x" formatting of printf +-reg : Must be the ac97 codec number, between 0 and 3 + +Example: +ac97: sound@40500000 { + compatible = "marvell,pxa270-ac97"; + reg = < 0x40500000 0x1000 >; + interrupts = <14>; + reset-gpios = <&gpio 95 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = < &pinctrl_ac97_default >; + clocks = <&clks CLK_AC97>, <&clks CLK_AC97CONF>; + clock-names = "AC97CLK", "AC97CONFCLK"; + + #address-cells = <1>; + #size-cells = <0>; + audio-codec@0 { + reg = <0>; + compatible = "ac97,574d,4c13"; + clocks = <&fixed_wm9713_clock>; + clock-names = "ac97_clk"; + } +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau1701.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau1701.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d1128ce2ea733d5cea0c369b4dc4969280a2d85 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau1701.txt @@ -0,0 +1,39 @@ +Analog Devices ADAU1701 + +Required properties: + + - compatible: Should contain "adi,adau1701" + - reg: The i2c address. Value depends on the state of ADDR0 + and ADDR1, as wired in hardware. + +Optional properties: + + - reset-gpio: A GPIO spec to define which pin is connected to the + chip's !RESET pin. If specified, the driver will + assert a hardware reset at probe time. + - adi,pll-mode-gpios: An array of two GPIO specs to describe the GPIOs + the ADAU's PLL config pins are connected to. + The state of the pins are set according to the + configured clock divider on ASoC side before the + firmware is loaded. + - adi,pin-config: An array of 12 numerical values selecting one of the + pin configurations as described in the datasheet, + table 53. Note that the value of this property has + to be prefixed with '/bits/ 8'. + - avdd-supply: Power supply for AVDD, providing 3.3V + - dvdd-supply: Power supply for DVDD, providing 3.3V + +Examples: + + i2c_bus { + adau1701@34 { + compatible = "adi,adau1701"; + reg = <0x34>; + reset-gpio = <&gpio 23 0>; + avdd-supply = <&vdd_3v3_reg>; + dvdd-supply = <&vdd_3v3_reg>; + adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>; + adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4 + 0x4 0x4 0x4 0x4 0x4 0x4>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau17x1.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau17x1.txt new file mode 100644 index 0000000000000000000000000000000000000000..1447dec281252cb1f71374742e54331ebebd7c5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau17x1.txt @@ -0,0 +1,32 @@ +Analog Devices ADAU1361/ADAU1461/ADAU1761/ADAU1961/ADAU1381/ADAU1781 + +Required properties: + + - compatible: Should contain one of the following: + "adi,adau1361" + "adi,adau1461" + "adi,adau1761" + "adi,adau1961" + "adi,adau1381" + "adi,adau1781" + + - reg: The i2c address. Value depends on the state of ADDR0 + and ADDR1, as wired in hardware. + +Optional properties: + - clock-names: If provided must be "mclk". + - clocks: phandle + clock-specifiers for the clock that provides + the audio master clock for the device. + +Examples: +#include + + i2c_bus { + adau1361@38 { + compatible = "adi,adau1761"; + reg = <0x38>; + + clock-names = "mclk"; + clocks = <&audio_clock>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau7002.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau7002.txt new file mode 100644 index 0000000000000000000000000000000000000000..f144ee1abf8550faf4c088c79bb9edbd714368b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,adau7002.txt @@ -0,0 +1,19 @@ +Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter + +Required properties: + + - compatible: Must be "adi,adau7002" + +Optional properties: + + - IOVDD-supply: Phandle and specifier for the power supply providing the IOVDD + supply as covered in Documentation/devicetree/bindings/regulator/regulator.txt + + If this property is not present it is assumed that the supply pin is + hardwired to always on. + +Example: + adau7002: pdm-to-i2s { + compatible = "adi,adau7002"; + IOVDD-supply = <&supply>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,axi-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,axi-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..4248b662deff04e4fbbbc3effa487e09fa140bee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,axi-i2s.txt @@ -0,0 +1,31 @@ +ADI AXI-I2S controller + +Required properties: + - compatible : Must be "adi,axi-i2s-1.00.a" + - reg : Must contain I2S core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's clocks. + The controller expects two clocks, the clock used for the AXI interface and + the clock used as the sampling rate reference clock sample. + - clock-names : "axi" for the clock to the AXI interface, "ref" for the sample + rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channels that are used by + the core. The core expects two dma channels, one for transmit and one for + receive. + - dma-names : "tx" for the transmit channel, "rx" for the receive channel. + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties +please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + i2s: i2s@77600000 { + compatible = "adi,axi-i2s-1.00.a"; + reg = <0x77600000 0x1000>; + clocks = <&clk 15>, <&audio_clock>; + clock-names = "axi", "ref"; + dmas = <&ps7_dma 0>, <&ps7_dma 1>; + dma-names = "tx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,axi-spdif-tx.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,axi-spdif-tx.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b664e7cb4ae99dfae7f1beb52bba140f6ee1dd7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,axi-spdif-tx.txt @@ -0,0 +1,30 @@ +ADI AXI-SPDIF controller + +Required properties: + - compatible : Must be "adi,axi-spdif-tx-1.00.a" + - reg : Must contain SPDIF core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's clocks. + The controller expects two clocks, the clock used for the AXI interface and + the clock used as the sampling rate reference clock sample. + - clock-names: "axi" for the clock to the AXI interface, "ref" for the sample + rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channel that is used by + the core. The core expects one dma channel for transmit. + - dma-names : Must be "tx" + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties +please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + spdif: spdif@77400000 { + compatible = "adi,axi-spdif-tx-1.00.a"; + reg = <0x77600000 0x1000>; + clocks = <&clk 15>, <&audio_clock>; + clock-names = "axi", "ref"; + dmas = <&ps7_dma 0>; + dma-names = "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,ssm2305.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,ssm2305.txt new file mode 100644 index 0000000000000000000000000000000000000000..a9c9d83c8a30af344545234adebcc6236f513291 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,ssm2305.txt @@ -0,0 +1,14 @@ +Analog Devices SSM2305 Speaker Amplifier +======================================== + +Required properties: + - compatible : "adi,ssm2305" + - shutdown-gpios : The gpio connected to the shutdown pin. + The gpio signal is ACTIVE_LOW. + +Example: + +ssm2305: analog-amplifier { + compatible = "adi,ssm2305"; + shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/adi,ssm2602.txt b/arch/arm64/boot/dts/vendor/bindings/sound/adi,ssm2602.txt new file mode 100644 index 0000000000000000000000000000000000000000..3b3302fe399b95ee4aba829e20496d020407ce75 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/adi,ssm2602.txt @@ -0,0 +1,19 @@ +Analog Devices SSM2602, SSM2603 and SSM2604 I2S audio CODEC devices + +SSM2602 support both I2C and SPI as the configuration interface, +the selection is made by the MODE strap-in pin. +SSM2603 and SSM2604 only support I2C as the configuration interface. + +Required properties: + + - compatible : One of "adi,ssm2602", "adi,ssm2603" or "adi,ssm2604" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + + Example: + + ssm2602: ssm2602@1a { + compatible = "adi,ssm2602"; + reg = <0x1a>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak4104.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak4104.txt new file mode 100644 index 0000000000000000000000000000000000000000..deca5e18f304bd2a45723acd4579959a6fe8ce61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak4104.txt @@ -0,0 +1,25 @@ +AK4104 S/PDIF transmitter + +This device supports SPI mode only. + +Required properties: + + - compatible : "asahi-kasei,ak4104" + + - reg : The chip select number on the SPI bus + + - vdd-supply : A regulator node, providing 2.7V - 3.6V + +Optional properties: + + - reset-gpio : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the device starts. + +Example: + +spdif: ak4104@0 { + compatible = "asahi-kasei,ak4104"; + reg = <0>; + spi-max-frequency = <5000000>; + vdd-supply = <&vdd_3v3_reg>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak4458.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak4458.txt new file mode 100644 index 0000000000000000000000000000000000000000..7839be78448dcb7b0396ad8f6909cc1af9af937e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak4458.txt @@ -0,0 +1,23 @@ +AK4458 audio DAC + +This device supports I2C mode. + +Required properties: + +- compatible : "asahi-kasei,ak4458" +- reg : The I2C address of the device for I2C + +Optional properties: +- reset-gpios: A GPIO specifier for the power down & reset pin +- mute-gpios: A GPIO specifier for the soft mute pin + +Example: + +&i2c { + ak4458: dac@10 { + compatible = "asahi-kasei,ak4458"; + reg = <0x10>; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW> + mute-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH> + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak4554.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak4554.txt new file mode 100644 index 0000000000000000000000000000000000000000..934fa02754b38878a9b7cd110f63287cade24252 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak4554.txt @@ -0,0 +1,11 @@ +AK4554 ADC/DAC + +Required properties: + + - compatible : "asahi-kasei,ak4554" + +Example: + +ak4554-adc-dac { + compatible = "asahi-kasei,ak4554"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak4613.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak4613.txt new file mode 100644 index 0000000000000000000000000000000000000000..49a2e74fd9cb1489b145b1132f2f892209c8b448 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak4613.txt @@ -0,0 +1,27 @@ +AK4613 I2C transmitter + +This device supports I2C mode only. + +Required properties: + +- compatible : "asahi-kasei,ak4613" +- reg : The chip select number on the I2C bus + +Optional properties: +- asahi-kasei,in1-single-end : Boolean. Indicate input / output pins are single-ended. +- asahi-kasei,in2-single-end rather than differential. +- asahi-kasei,out1-single-end +- asahi-kasei,out2-single-end +- asahi-kasei,out3-single-end +- asahi-kasei,out4-single-end +- asahi-kasei,out5-single-end +- asahi-kasei,out6-single-end + +Example: + +&i2c { + ak4613: ak4613@10 { + compatible = "asahi-kasei,ak4613"; + reg = <0x10>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak4642.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak4642.txt new file mode 100644 index 0000000000000000000000000000000000000000..58e48ee9717547f2766a2c0a89fec19536431634 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak4642.txt @@ -0,0 +1,37 @@ +AK4642 I2C transmitter + +This device supports I2C mode only. + +Required properties: + + - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648" + - reg : The chip select number on the I2C bus + +Optional properties: + + - #clock-cells : common clock binding; shall be set to 0 + - clocks : common clock binding; MCKI clock + - clock-frequency : common clock binding; frequency of MCKO + - clock-output-names : common clock binding; MCKO clock name + +Example 1: + +&i2c { + ak4648: ak4648@12 { + compatible = "asahi-kasei,ak4642"; + reg = <0x12>; + }; +}; + +Example 2: + +&i2c { + ak4643: codec@12 { + compatible = "asahi-kasei,ak4643"; + reg = <0x12>; + #clock-cells = <0>; + clocks = <&audio_clock>; + clock-frequency = <12288000>; + clock-output-names = "ak4643_mcko"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak5386.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak5386.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec3df3abba0cf06dec5252b8564a35c1efd7aa0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak5386.txt @@ -0,0 +1,23 @@ +AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC + +This device has no control interface. + +Required properties: + + - compatible : "asahi-kasei,ak5386" + +Optional properties: + + - reset-gpio : a GPIO spec for the reset/power down pin. + If specified, it will be deasserted at probe time. + - va-supply : a regulator spec, providing 5.0V + - vd-supply : a regulator spec, providing 3.3V + +Example: + +spdif: ak5386@0 { + compatible = "asahi-kasei,ak5386"; + reset-gpio = <&gpio0 23>; + va-supply = <&vdd_5v0_reg>; + vd-supply = <&vdd_3v3_reg>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ak5558.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ak5558.txt new file mode 100644 index 0000000000000000000000000000000000000000..7d67ca6ced80942ddbecccb494a87a6ac2db1508 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ak5558.txt @@ -0,0 +1,22 @@ +AK5558 8 channel differential 32-bit delta-sigma ADC + +This device supports I2C mode only. + +Required properties: + +- compatible : "asahi-kasei,ak5558" +- reg : The I2C address of the device. + +Optional properties: + +- reset-gpios: A GPIO specifier for the power down & reset pin. + +Example: + +&i2c { + ak5558: adc@10 { + compatible = "asahi-kasei,ak5558"; + reg = <0x10>; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/alc5623.txt b/arch/arm64/boot/dts/vendor/bindings/sound/alc5623.txt new file mode 100644 index 0000000000000000000000000000000000000000..26c86c98d6713e5cc83bde48017f9d1b5cf560c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/alc5623.txt @@ -0,0 +1,25 @@ +ALC5621/ALC5622/ALC5623 audio Codec + +Required properties: + + - compatible: "realtek,alc5623" + - reg: the I2C address of the device. + +Optional properties: + + - add-ctrl: Default register value for Reg-40h, Additional Control + Register. If absent or has the value of 0, the + register is untouched. + + - jack-det-ctrl: Default register value for Reg-5Ah, Jack Detect + Control Register. If absent or has value 0, the + register is untouched. + +Example: + + alc5621: alc5621@1a { + compatible = "alc5621"; + reg = <0x1a>; + add-ctrl = <0x3700>; + jack-det-ctrl = <0x4810>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/alc5632.txt b/arch/arm64/boot/dts/vendor/bindings/sound/alc5632.txt new file mode 100644 index 0000000000000000000000000000000000000000..ffd886d110bdcbc6aa79d2372149ae14867b2449 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/alc5632.txt @@ -0,0 +1,43 @@ +ALC5632 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "realtek,alc5632" + + - reg : the I2C address of the device. + + - gpio-controller : Indicates this device is a GPIO controller. + + - #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + +Pins on the device (for linking into audio routes): + + * SPK_OUTP + * SPK_OUTN + * HP_OUT_L + * HP_OUT_R + * AUX_OUT_P + * AUX_OUT_N + * LINE_IN_L + * LINE_IN_R + * PHONE_P + * PHONE_N + * MIC1_P + * MIC1_N + * MIC2_P + * MIC2_N + * MICBIAS1 + * DMICDAT + +Example: + +alc5632: alc5632@1e { + compatible = "realtek,alc5632"; + reg = <0x1a>; + + gpio-controller; + #gpio-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-fifo.txt b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-fifo.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dfc2515e5c672702121e5720618800508007f64 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-fifo.txt @@ -0,0 +1,23 @@ +* Amlogic Audio FIFO controllers + +Required properties: +- compatible: 'amlogic,axg-toddr' or + 'amlogic,axg-frddr' +- reg: physical base address of the controller and length of memory + mapped region. +- interrupts: interrupt specifier for the fifo. +- clocks: phandle to the fifo peripheral clock provided by the audio + clock controller. +- resets: phandle to memory ARB line provided by the arb reset controller. +- #sound-dai-cells: must be 0. + +Example of FRDDR A on the A113 SoC: + +frddr_a: audio-controller@1c0 { + compatible = "amlogic,axg-frddr"; + reg = <0x0 0x1c0 0x0 0x1c>; + #sound-dai-cells = <0>; + interrupts = ; + clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; + resets = <&arb AXG_ARB_FRDDR_A>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-sound-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-sound-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..80b411296480fba0e1d9521ed838bc40d736b936 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-sound-card.txt @@ -0,0 +1,124 @@ +Amlogic AXG sound card: + +Required properties: + +- compatible: "amlogic,axg-sound-card" +- model : User specified audio sound card name, one string + +Optional properties: + +- audio-aux-devs : List of phandles pointing to auxiliary devices +- audio-widgets : Please refer to widgets.txt. +- audio-routing : A list of the connections between audio components. + +Subnodes: + +- dai-link: Container for dai-link level properties and the CODEC + sub-nodes. There should be at least one (and probably more) + subnode of this type. + +Required dai-link properties: + +- sound-dai: phandle and port of the CPU DAI. + +Required TDM Backend dai-link properties: +- dai-format : CPU/CODEC common audio format + +Optional TDM Backend dai-link properties: +- dai-tdm-slot-rx-mask-{0,1,2,3}: Receive direction slot masks +- dai-tdm-slot-tx-mask-{0,1,2,3}: Transmit direction slot masks + When omitted, mask is assumed to have to no + slots. A valid must have at one slot, so at + least one these mask should be provided with + an enabled slot. +- dai-tdm-slot-num : Please refer to tdm-slot.txt. + If omitted, slot number is set to accommodate the largest + mask provided. +- dai-tdm-slot-width : Please refer to tdm-slot.txt. default to 32 if omitted. +- mclk-fs : Multiplication factor between stream rate and mclk + +Backend dai-link subnodes: + +- codec: dai-link representing backend links should have at least one subnode. + One subnode for each codec of the dai-link. + dai-link representing frontend links have no codec, therefore have no + subnodes + +Required codec subnodes properties: + +- sound-dai: phandle and port of the CODEC DAI. + +Optional codec subnodes properties: + +- dai-tdm-slot-tx-mask : Please refer to tdm-slot.txt. +- dai-tdm-slot-rx-mask : Please refer to tdm-slot.txt. + +Example: + +sound { + compatible = "amlogic,axg-sound-card"; + model = "AXG-S420"; + audio-aux-devs = <&tdmin_a>, <&tdmout_c>; + audio-widgets = "Line", "Lineout", + "Line", "Linein", + "Speaker", "Speaker1 Left", + "Speaker", "Speaker1 Right"; + "Speaker", "Speaker2 Left", + "Speaker", "Speaker2 Right"; + audio-routing = "TDMOUT_C IN 0", "FRDDR_A OUT 2", + "SPDIFOUT IN 0", "FRDDR_A OUT 3", + "TDM_C Playback", "TDMOUT_C OUT", + "TDMIN_A IN 2", "TDM_C Capture", + "TDMIN_A IN 5", "TDM_C Loopback", + "TODDR_A IN 0", "TDMIN_A OUT", + "Lineout", "Lineout AOUTL", + "Lineout", "Lineout AOUTR", + "Speaker1 Left", "SPK1 OUT_A", + "Speaker2 Left", "SPK2 OUT_A", + "Speaker1 Right", "SPK1 OUT_B", + "Speaker2 Right", "SPK2 OUT_B", + "Linein AINL", "Linein", + "Linein AINR", "Linein"; + + dai-link@0 { + sound-dai = <&frddr_a>; + }; + + dai-link@1 { + sound-dai = <&toddr_a>; + }; + + dai-link@2 { + sound-dai = <&tdmif_c>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + dai-tdm-slot-rx-mask-1 = <1 1>; + mclk-fs = <256>; + + codec@0 { + sound-dai = <&lineout>; + }; + + codec@1 { + sound-dai = <&speaker_amp1>; + }; + + codec@2 { + sound-dai = <&speaker_amp2>; + }; + + codec@3 { + sound-dai = <&linein>; + }; + + }; + + dai-link@3 { + sound-dai = <&spdifout>; + + codec { + sound-dai = <&spdif_dit>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-spdifout.txt b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-spdifout.txt new file mode 100644 index 0000000000000000000000000000000000000000..521c38ad89e718635311084d2e9317b296bb08e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-spdifout.txt @@ -0,0 +1,20 @@ +* Amlogic Audio SPDIF Output + +Required properties: +- compatible: 'amlogic,axg-spdifout' +- clocks: list of clock phandle, one for each entry clock-names. +- clock-names: should contain the following: + * "pclk" : peripheral clock. + * "mclk" : master clock +- #sound-dai-cells: must be 0. + +Example on the A113 SoC: + +spdifout: audio-controller@480 { + compatible = "amlogic,axg-spdifout"; + reg = <0x0 0x480 0x0 0x50>; + #sound-dai-cells = <0>; + clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, + <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; + clock-names = "pclk", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-tdm-formatters.txt b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-tdm-formatters.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c1b7490554ea10dcfb361f7c1f5d91b3a4bd720 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-tdm-formatters.txt @@ -0,0 +1,28 @@ +* Amlogic Audio TDM formatters + +Required properties: +- compatible: 'amlogic,axg-tdmin' or + 'amlogic,axg-tdmout' +- reg: physical base address of the controller and length of memory + mapped region. +- clocks: list of clock phandle, one for each entry clock-names. +- clock-names: should contain the following: + * "pclk" : peripheral clock. + * "sclk" : bit clock. + * "sclk_sel" : bit clock input multiplexer. + * "lrclk" : sample clock + * "lrclk_sel": sample clock input multiplexer + +Example of TDMOUT_A on the A113 SoC: + +tdmout_a: audio-controller@500 { + compatible = "amlogic,axg-tdmout"; + reg = <0x0 0x500 0x0 0x40>; + clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, + <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, + <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, + <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; + clock-names = "pclk", "sclk", "sclk_sel", + "lrclk", "lrclk_sel"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-tdm-iface.txt b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-tdm-iface.txt new file mode 100644 index 0000000000000000000000000000000000000000..cabfb26a5f227b40760dd0ab8073820f48153b2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/amlogic,axg-tdm-iface.txt @@ -0,0 +1,22 @@ +* Amlogic Audio TDM Interfaces + +Required properties: +- compatible: 'amlogic,axg-tdm-iface' +- clocks: list of clock phandle, one for each entry clock-names. +- clock-names: should contain the following: + * "sclk" : bit clock. + * "lrclk": sample clock + * "mclk" : master clock + -> optional if the interface is in clock slave mode. +- #sound-dai-cells: must be 0. + +Example of TDM_A on the A113 SoC: + +tdmif_a: audio-controller@0 { + compatible = "amlogic,axg-tdm-iface"; + #sound-dai-cells = <0>; + clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, + <&clkc_audio AUD_CLKID_MST_A_SCLK>, + <&clkc_audio AUD_CLKID_MST_A_LRCLK>; + clock-names = "mclk", "sclk", "lrclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/armada-370db-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/armada-370db-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..953c092db72f044fb461f9f674e445db692e3478 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/armada-370db-audio.txt @@ -0,0 +1,26 @@ +Device Tree bindings for the Armada 370 DB audio +================================================ + +These Device Tree bindings are used to describe the audio complex +found on the Armada 370 DB platform. + +Mandatory properties: + + * compatible: must be "marvell,a370db-audio" + + * marvell,audio-controller: a phandle that points to the audio + controller of the Armada 370 SoC. + + * marvell,audio-codec: a set of three phandles that points to: + + 1/ the analog audio codec connected to the Armada 370 SoC + 2/ the S/PDIF transceiver + 3/ the S/PDIF receiver + +Example: + + sound { + compatible = "marvell,a370db-audio"; + marvell,audio-controller = <&audio_controller>; + marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/arndale.txt b/arch/arm64/boot/dts/vendor/bindings/sound/arndale.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e76946385aed9c5e3a73ad4509470687763b752 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/arndale.txt @@ -0,0 +1,24 @@ +Audio Binding for Arndale boards + +Required properties: +- compatible : Can be the following, + "samsung,arndale-rt5631" + +- samsung,audio-cpu: The phandle of the Samsung I2S controller +- samsung,audio-codec: The phandle of the audio codec + +Optional: +- samsung,model: The name of the sound-card + +Arndale Boards has many audio daughter cards, one of them is +rt5631/alc5631. Below example shows audio bindings for rt5631/ +alc5631 based codec. + +Example: + +sound { + compatible = "samsung,arndale-rt5631"; + + samsung,audio-cpu = <&i2s0> + samsung,audio-codec = <&rt5631>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c5a9947b64d454a892e1e4148ff06be7c33d6cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-at91sam9g20ek-wm8731-audio.txt @@ -0,0 +1,26 @@ +* Atmel at91sam9g20ek wm8731 audio complex + +Required properties: + - compatible: "atmel,at91sam9g20ek-wm8731-audio" + - atmel,model: The user-visible name of this sound complex. + - atmel,audio-routing: A list of the connections between audio components. + - atmel,ssc-controller: The phandle of the SSC controller + - atmel,audio-codec: The phandle of the WM8731 audio codec +Optional properties: + - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt + +Example: +sound { + compatible = "atmel,at91sam9g20ek-wm8731-audio"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_mck>; + + atmel,model = "wm8731 @ AT91SAMG20EK"; + + atmel,audio-routing = + "Ext Spk", "LHPOUT", + "Int MIC", "MICIN"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8731>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel-classd.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-classd.txt new file mode 100644 index 0000000000000000000000000000000000000000..898551076382abef7941b3772cbbc5511a8ac476 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-classd.txt @@ -0,0 +1,55 @@ +* Atmel ClassD driver under ALSA SoC architecture + +Required properties: +- compatible + Should be "atmel,sama5d2-classd". +- reg + Should contain ClassD registers location and length. +- interrupts + Should contain the IRQ line for the ClassD. +- dmas + One DMA specifiers as described in atmel-dma.txt and dma.txt files. +- dma-names + Must be "tx". +- clock-names + Tuple listing input clock names. + Required elements: "pclk" and "gclk". +- clocks + Please refer to clock-bindings.txt. +- assigned-clocks + Should be <&classd_gclk>. + +Optional properties: +- pinctrl-names, pinctrl-0 + Please refer to pinctrl-bindings.txt. +- atmel,model + The user-visible name of this sound complex. + The default value is "CLASSD". +- atmel,pwm-type + PWM modulation type, "single" or "diff". + The default value is "single". +- atmel,non-overlap-time + Set non-overlapping time, the unit is nanosecond(ns). + There are four values, + <5>, <10>, <15>, <20>, the default value is <10>. + Non-overlapping will be disabled if not specified. + +Example: +classd: classd@fc048000 { + compatible = "atmel,sama5d2-classd"; + reg = <0xfc048000 0x100>; + interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(47))>; + dma-names = "tx"; + clocks = <&classd_clk>, <&classd_gclk>; + clock-names = "pclk", "gclk"; + assigned-clocks = <&classd_gclk>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_classd_default>; + atmel,model = "classd @ SAMA5D2-Xplained"; + atmel,pwm-type = "diff"; + atmel,non-overlap-time = <10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..40549f496a81ccdfb59d49da32682ab8cba2107f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-i2s.txt @@ -0,0 +1,46 @@ +* Atmel I2S controller + +Required properties: +- compatible: Should be "atmel,sama5d2-i2s". +- reg: Should be the physical base address of the controller and the + length of memory mapped region. +- interrupts: Should contain the interrupt for the controller. +- dmas: Should be one per channel name listed in the dma-names property, + as described in atmel-dma.txt and dma.txt files. +- dma-names: Two dmas have to be defined, "tx" and "rx". + This IP also supports one shared channel for both rx and tx; + if this mode is used, one "rx-tx" name must be used. +- clocks: Must contain an entry for each entry in clock-names. + Please refer to clock-bindings.txt. +- clock-names: Should be one of each entry matching the clocks phandles list: + - "pclk" (peripheral clock) Required. + - "gclk" (generated clock) Optional (1). + - "muxclk" (I2S mux clock) Optional (1). + +Optional properties: +- pinctrl-0: Should specify pin control groups used for this controller. +- princtrl-names: Should contain only one value - "default". + + +(1) : Only the peripheral clock is required. The generated clock and the I2S + mux clock are optional and should only be set together, when Master Mode + is required. + +Example: + + i2s@f8050000 { + compatible = "atmel,sama5d2-i2s"; + reg = <0xf8050000 0x300>; + interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(31))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(32))>; + dma-names = "tx", "rx"; + clocks = <&i2s0_clk>, <&i2s0_gclk>, <&i2s0muxck>; + clock-names = "pclk", "gclk", "muxclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s0_default>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel-pdmic.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-pdmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0875f17c229b5ead26344e41a47ce8f44b3923e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-pdmic.txt @@ -0,0 +1,55 @@ +* Atmel PDMIC driver under ALSA SoC architecture + +Required properties: +- compatible + Should be "atmel,sama5d2-pdmic". +- reg + Should contain PDMIC registers location and length. +- interrupts + Should contain the IRQ line for the PDMIC. +- dmas + One DMA specifiers as described in atmel-dma.txt and dma.txt files. +- dma-names + Must be "rx". +- clock-names + Required elements: + - "pclk" peripheral clock + - "gclk" generated clock +- clocks + Must contain an entry for each required entry in clock-names. + Please refer to clock-bindings.txt. +- atmel,mic-min-freq + The minimal frequency that the micphone supports. +- atmel,mic-max-freq + The maximal frequency that the micphone supports. + +Optional properties: +- pinctrl-names, pinctrl-0 + Please refer to pinctrl-bindings.txt. +- atmel,model + The user-visible name of this sound card. + The default value is "PDMIC". +- atmel,mic-offset + The offset that should be added. + The range is from -32768 to 32767. + The default value is 0. + +Example: + pdmic@f8018000 { + compatible = "atmel,sama5d2-pdmic"; + reg = <0xf8018000 0x124>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(50))>; + dma-names = "rx"; + clocks = <&pdmic_clk>, <&pdmic_gclk>; + clock-names = "pclk", "gclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pdmic_default>; + atmel,model = "PDMIC @ sama5d2_xplained"; + atmel,mic-min-freq = <1000000>; + atmel,mic-max-freq = <3246000>; + atmel,mic-offset = <0x0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel-sam9x5-wm8731-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-sam9x5-wm8731-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..0720857089a7d0b3464fdc57927b01a27b5394af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-sam9x5-wm8731-audio.txt @@ -0,0 +1,35 @@ +* Atmel at91sam9x5ek wm8731 audio complex + +Required properties: + - compatible: "atmel,sam9x5-wm8731-audio" + - atmel,model: The user-visible name of this sound complex. + - atmel,ssc-controller: The phandle of the SSC controller + - atmel,audio-codec: The phandle of the WM8731 audio codec + - atmel,audio-routing: A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headphone Jack + * Line In Jack + +wm8731 pins: +cf Documentation/devicetree/bindings/sound/wm8731.txt + +Example: +sound { + compatible = "atmel,sam9x5-wm8731-audio"; + + atmel,model = "wm8731 @ AT91SAM9X5EK"; + + atmel,audio-routing = + "Headphone Jack", "RHPOUT", + "Headphone Jack", "LHPOUT", + "LLINEIN", "Line In Jack", + "RLINEIN", "Line In Jack"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8731>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel-wm8904.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-wm8904.txt new file mode 100644 index 0000000000000000000000000000000000000000..8bbe50c884b69612a51254a5174ab6dbe178a383 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel-wm8904.txt @@ -0,0 +1,55 @@ +Atmel ASoC driver with wm8904 audio codec complex + +Required properties: + - compatible: "atmel,asoc-wm8904" + - atmel,model: The user-visible name of this sound complex. + - atmel,audio-routing: A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the WM8904's pins, and the jacks on the board: + + WM8904 pins: + + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * MICBIAS + + Board connectors: + + * Headphone Jack + * Line In Jack + * Mic + + - atmel,ssc-controller: The phandle of the SSC controller + - atmel,audio-codec: The phandle of the WM8904 audio codec + +Optional properties: + - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt + +Example: +sound { + compatible = "atmel,asoc-wm8904"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_mck>; + + atmel,model = "wm8904 @ AT91SAM9N12EK"; + + atmel,audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "IN2L", "Line In Jack", + "IN2R", "Line In Jack", + "Mic", "MICBIAS", + "IN1L", "Mic"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8904>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/atmel_ac97c.txt b/arch/arm64/boot/dts/vendor/bindings/sound/atmel_ac97c.txt new file mode 100644 index 0000000000000000000000000000000000000000..b151bd902ce3d59335114cd8c2ce7258c4df5fbb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/atmel_ac97c.txt @@ -0,0 +1,20 @@ +* Atmel AC97 controller + +Required properties: + - compatible: "atmel,at91sam9263-ac97c" + - reg: Address and length of the register set for the device + - interrupts: Should contain AC97 interrupt + - ac97-gpios: Please refer to soc-ac97link.txt, only ac97-reset is used +Optional properties: + - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt + +Example: +sound@fffa0000 { + compatible = "atmel,at91sam9263-ac97c"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ac97>; + reg = <0xfffa0000 0x4000>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH 5>; + + ac97-gpios = <&pioB 0 0 &pioB 2 0 &pioC 29 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/audio-graph-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/audio-graph-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e63e53a901c65db905b4ded8b46462de43a5267 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/audio-graph-card.txt @@ -0,0 +1,132 @@ +Audio Graph Card: + +Audio Graph Card specifies audio DAI connections of SoC <-> codec. +It is based on common bindings for device graphs. +see ${LINUX}/Documentation/devicetree/bindings/graph.txt + +Basically, Audio Graph Card property is same as Simple Card. +see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt + +Below are same as Simple-Card. + +- label +- widgets +- routing +- dai-format +- frame-master +- bitclock-master +- bitclock-inversion +- frame-inversion +- mclk-fs +- hp-det-gpio +- mic-det-gpio +- dai-tdm-slot-num +- dai-tdm-slot-width +- clocks / system-clock-frequency + +Required properties: + +- compatible : "audio-graph-card"; +- dais : list of CPU DAI port{s} + +Optional properties: +- pa-gpios: GPIO used to control external amplifier. + +Example: Single DAI case + + sound_card { + compatible = "audio-graph-card"; + + dais = <&cpu_port>; + }; + + dai-controller { + ... + cpu_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + }; + + audio-codec { + ... + port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; + }; + +Example: Multi DAI case + + sound-card { + compatible = "audio-graph-card"; + + label = "sound-card"; + + dais = <&cpu_port0 + &cpu_port1 + &cpu_port2>; + }; + + audio-codec@0 { + ... + port { + codec0_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint0>; + }; + }; + }; + + audio-codec@1 { + ... + port { + codec1_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint1>; + }; + }; + }; + + audio-codec@2 { + ... + port { + codec2_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint2>; + }; + }; + }; + + dai-controller { + ... + ports { + cpu_port0: port@0 { + cpu_endpoint0: endpoint { + remote-endpoint = <&codec0_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + cpu_port1: port@1 { + cpu_endpoint1: endpoint { + remote-endpoint = <&codec1_endpoint>; + + dai-format = "i2s"; + ... + }; + }; + cpu_port2: port@2 { + cpu_endpoint2: endpoint { + remote-endpoint = <&codec2_endpoint>; + + dai-format = "i2s"; + ... + }; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/audio-graph-scu-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/audio-graph-scu-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..441dd6f29df13ba987316c5b6a4102c7bf73e636 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/audio-graph-scu-card.txt @@ -0,0 +1,123 @@ +Audio-Graph-SCU-Card: + +Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM". + +It is based on common bindings for device graphs. +see ${LINUX}/Documentation/devicetree/bindings/graph.txt + +Basically, Audio-Graph-SCU-Card property is same as +Simple-Card / Simple-SCU-Card / Audio-Graph-Card. +see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt + ${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt + ${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt + +Below are same as Simple-Card / Audio-Graph-Card. + +- label +- dai-format +- frame-master +- bitclock-master +- bitclock-inversion +- frame-inversion +- dai-tdm-slot-num +- dai-tdm-slot-width +- clocks / system-clock-frequency + +Below are same as Simple-SCU-Card. + +- convert-rate +- convert-channels +- prefix +- routing + +Required properties: + +- compatible : "audio-graph-scu-card"; +- dais : list of CPU DAI port{s} + +Example 1. Sampling Rate Conversion + + sound_card { + compatible = "audio-graph-scu-card"; + + label = "sound-card"; + prefix = "codec"; + routing = "codec Playback", "DAI0 Playback", + "DAI0 Capture", "codec Capture"; + convert-rate = <48000>; + + dais = <&cpu_port>; + }; + + audio-codec { + ... + + port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; + }; + + dai-controller { + ... + cpu_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + + dai-format = "left_j"; + ... + }; + }; + }; + +Example 2. 2 CPU 1 Codec (Mixing) + + sound_card { + compatible = "audio-graph-scu-card"; + + label = "sound-card"; + prefix = "codec"; + routing = "codec Playback", "DAI0 Playback", + "codec Playback", "DAI1 Playback", + "DAI0 Capture", "codec Capture"; + convert-rate = <48000>; + + dais = <&cpu_port0 + &cpu_port1>; + }; + + audio-codec { + ... + + port { + codec_endpoint0: endpoint { + remote-endpoint = <&cpu_endpoint0>; + }; + codec_endpoint1: endpoint { + remote-endpoint = <&cpu_endpoint1>; + }; + }; + }; + + dai-controller { + ... + ports { + cpu_port0: port { + cpu_endpoint0: endpoint { + remote-endpoint = <&codec_endpoint0>; + + dai-format = "left_j"; + ... + }; + }; + cpu_port1: port { + cpu_endpoint1: endpoint { + remote-endpoint = <&codec_endpoint1>; + + dai-format = "left_j"; + ... + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/axentia,tse850-pcm5142.txt b/arch/arm64/boot/dts/vendor/bindings/sound/axentia,tse850-pcm5142.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d049d4bfd58f5ab6d1d56cf19956f7615668b6b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/axentia,tse850-pcm5142.txt @@ -0,0 +1,92 @@ +Devicetree bindings for the Axentia TSE-850 audio complex + +Required properties: + - compatible: "axentia,tse850-pcm5142" + - axentia,cpu-dai: The phandle of the cpu dai. + - axentia,audio-codec: The phandle of the PCM5142 codec. + - axentia,add-gpios: gpio specifier that controls the mixer. + - axentia,loop1-gpios: gpio specifier that controls loop relays on channel 1. + - axentia,loop2-gpios: gpio specifier that controls loop relays on channel 2. + - axentia,ana-supply: Regulator that supplies the output amplifier. Must + support voltages in the 2V - 20V range, in 1V steps. + +The schematics explaining the gpios are as follows: + + loop1 relays + IN1 +---o +------------+ o---+ OUT1 + \ / + + + + | / | + +--o +--. | + | add | | + | V | + | .---. | + DAC +----------->|Sum|---+ + | '---' | + | | + + + + + IN2 +---o--+------------+--o---+ OUT2 + loop2 relays + +The 'loop1' gpio pin controlls two relays, which are either in loop position, +meaning that input and output are directly connected, or they are in mixer +position, meaning that the signal is passed through the 'Sum' mixer. Similarly +for 'loop2'. + +In the above, the 'loop1' relays are inactive, thus feeding IN1 to the mixer +(if 'add' is active) and feeding the mixer output to OUT1. The 'loop2' relays +are active, short-cutting the TSE-850 from channel 2. IN1, IN2, OUT1 and OUT2 +are TSE-850 connectors and DAC is the PCB name of the (filtered) output from +the PCM5142 codec. + +Example: + + &ssc0 { + #sound-dai-cells = <0>; + + }; + + &i2c { + codec: pcm5142@4c { + compatible = "ti,pcm5142"; + + reg = <0x4c>; + + AVDD-supply = <®_3v3>; + DVDD-supply = <®_3v3>; + CPVDD-supply = <®_3v3>; + + clocks = <&sck>; + + pll-in = <3>; + pll-out = <6>; + }; + }; + + ana: ana-reg { + compatible = "pwm-regulator"; + + regulator-name = "ANA"; + + pwms = <&pwm0 2 1000 PWM_POLARITY_INVERTED>; + pwm-dutycycle-unit = <1000>; + pwm-dutycycle-range = <100 1000>; + + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <20000000>; + regulator-ramp-delay = <1000>; + }; + + sound { + compatible = "axentia,tse850-pcm5142"; + + axentia,cpu-dai = <&ssc0>; + axentia,audio-codec = <&codec>; + + axentia,add-gpios = <&pioA 8 GPIO_ACTIVE_LOW>; + axentia,loop1-gpios = <&pioA 10 GPIO_ACTIVE_LOW>; + axentia,loop2-gpios = <&pioA 11 GPIO_ACTIVE_LOW>; + + axentia,ana-supply = <&ana>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/brcm,bcm2835-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/brcm,bcm2835-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bb0362828ecbd6472a32457d2134b746b3182f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/brcm,bcm2835-i2s.txt @@ -0,0 +1,24 @@ +* Broadcom BCM2835 SoC I2S/PCM module + +Required properties: +- compatible: "brcm,bcm2835-i2s" +- reg: Should contain PCM registers location and length. +- clocks: the (PCM) clock to use +- dmas: List of DMA controller phandle and DMA request line ordered pairs. +- dma-names: Identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. + + One of the DMA channels will be responsible for transmission (should be + named "tx") and one for reception (should be named "rx"). + +Example: + +bcm2835_i2s: i2s@7e203000 { + compatible = "brcm,bcm2835-i2s"; + reg = <0x7e203000 0x24>; + clocks = <&clocks BCM2835_CLOCK_PCM>; + + dmas = <&dma 2>, + <&dma 3>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/brcm,cygnus-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/brcm,cygnus-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..630bf7c0344d1a459050ed3904de8a5f08f68904 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/brcm,cygnus-audio.txt @@ -0,0 +1,63 @@ +BROADCOM Cygnus Audio I2S/TDM/SPDIF controller + +Required properties: + - compatible : "brcm,cygnus-audio" + - #address-cells: 32bit valued, 1 cell. + - #size-cells: 32bit valued, 0 cell. + - reg : Should contain audio registers location and length + - reg-names: names of the registers listed in "reg" property + Valid names are "aud" and "i2s_in". "aud" contains a + set of DMA, I2S_OUT and SPDIF registers. "i2s_in" contains + a set of I2S_IN registers. + - clocks: PLL and leaf clocks used by audio ports + - assigned-clocks: PLL and leaf clocks + - assigned-clock-parents: parent clocks of the assigned clocks + (usually the PLL) + - assigned-clock-rates: List of clock frequencies of the + assigned clocks + - clock-names: names of 3 leaf clocks used by audio ports + Valid names are "ch0_audio", "ch1_audio", "ch2_audio" + - interrupts: audio DMA interrupt number + +SSP Subnode properties: +- reg: The index of ssp port interface to use + Valid value are 0, 1, 2, or 3 (for spdif) + +Example: + cygnus_audio: audio@180ae000 { + compatible = "brcm,cygnus-audio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x180ae000 0xafd>, <0x180aec00 0x1f8>; + reg-names = "aud", "i2s_in"; + clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>, + <&audiopll BCM_CYGNUS_AUDIOPLL_CH1>, + <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>; + assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>, + <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>, + <&audiopll BCM_CYGNUS_AUDIOPLL_CH1>, + <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>; + assigned-clock-parents = <&audiopll BCM_CYGNUS_AUDIOPLL>; + assigned-clock-rates = <1769470191>, + <0>, + <0>, + <0>; + clock-names = "ch0_audio", "ch1_audio", "ch2_audio"; + interrupts = ; + + ssp0: ssp_port@0 { + reg = <0>; + }; + + ssp1: ssp_port@1 { + reg = <1>; + }; + + ssp2: ssp_port@2 { + reg = <2>; + }; + + spdif: spdif_port@3 { + reg = <3>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/bt-sco.txt b/arch/arm64/boot/dts/vendor/bindings/sound/bt-sco.txt new file mode 100644 index 0000000000000000000000000000000000000000..641edf75e18466f4cf917418e3fc4d5640103cdc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/bt-sco.txt @@ -0,0 +1,13 @@ +Bluetooth-SCO audio CODEC + +This device support generic Bluetooth SCO link. + +Required properties: + + - compatible : "delta,dfbmcs320" or "linux,bt-sco" + +Example: + +codec: bt_sco { + compatible = "delta,dfbmcs320"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cdns,xtfpga-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cdns,xtfpga-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..860fc0da39c02003d6f6149f3c2a96990cfa4414 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cdns,xtfpga-i2s.txt @@ -0,0 +1,18 @@ +Bindings for I2S controller built into xtfpga Xtensa bitstreams. + +Required properties: +- compatible: shall be "cdns,xtfpga-i2s". +- reg: memory region (address and length) with device registers. +- interrupts: interrupt for the device. +- clocks: phandle to the clk used as master clock. I2S bus clock + is derived from it. + +Examples: + + i2s0: xtfpga-i2s@d080000 { + #sound-dai-cells = <0>; + compatible = "cdns,xtfpga-i2s"; + reg = <0x0d080000 0x40>; + interrupts = <2 1>; + clocks = <&cdce706 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs35l32.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l32.txt new file mode 100644 index 0000000000000000000000000000000000000000..1417d3f5cc221930a928443e66783cffd4570189 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l32.txt @@ -0,0 +1,62 @@ +CS35L32 audio CODEC + +Required properties: + + - compatible : "cirrus,cs35l32" + + - reg : the I2C address of the device for I2C. Address is determined by the level + of the AD0 pin. Level 0 is 0x40 while Level 1 is 0x41. + + - VA-supply, VP-supply : power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - cirrus,boost-manager : Boost voltage control. + 0 = Automatically managed. Boost-converter output voltage is the higher + of the two: Class G or adaptive LED voltage. + 1 = Automatically managed irrespective of audio, adapting for low-power + dissipation when LEDs are ON, and operating in Fixed-Boost Bypass Mode + if LEDs are OFF (VBST = VP). + 2 = (Default) Boost voltage fixed in Bypass Mode (VBST = VP). + 3 = Boost voltage fixed at 5 V. + + - cirrus,sdout-datacfg : Data configuration for dual CS35L32 applications only. + Determines the data packed in a two-CS35L32 configuration. + 0 = Left/right channels VMON[11:0], IMON[11:0], VPMON[7:0]. + 1 = Left/right channels VMON[11:0], IMON[11:0], STATUS. + 2 = (Default) left/right channels VMON[15:0], IMON [15:0]. + 3 = Left/right channels VPMON[7:0], STATUS. + + - cirrus,sdout-share : SDOUT sharing. Determines whether one or two CS35L32 + devices are on board sharing SDOUT. + 0 = (Default) One IC. + 1 = Two IC's. + + - cirrus,battery-recovery : Low battery nominal recovery threshold, rising VP. + 0 = 3.1V + 1 = 3.2V + 2 = 3.3V (Default) + 3 = 3.4V + + - cirrus,battery-threshold : Low battery nominal threshold, falling VP. + 0 = 3.1V + 1 = 3.2V + 2 = 3.3V + 3 = 3.4V (Default) + 4 = 3.5V + 5 = 3.6V + +Example: + +codec: codec@40 { + compatible = "cirrus,cs35l32"; + reg = <0x40>; + reset-gpios = <&gpio 10 0>; + cirrus,boost-manager = <0x03>; + cirrus,sdout-datacfg = <0x02>; + VA-supply = <®_audio>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs35l33.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l33.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc5a355d1a19e05d1acfb9b4deaf642add8be77b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l33.txt @@ -0,0 +1,124 @@ +CS35L33 Speaker Amplifier + +Required properties: + + - compatible : "cirrus,cs35l33" + + - reg : the I2C address of the device for I2C + + - VA-supply, VP-supply : power supplies for the device, + as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - reset-gpios : gpio used to reset the amplifier + + - interrupts : IRQ line info CS35L33. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + for further information relating to interrupt properties) + + - cirrus,boost-ctl : Booster voltage use to supply the amp. If the value is + 0, then VBST = VP. If greater than 0, the boost voltage will be 3300mV with + a value of 1 and will increase at a step size of 100mV until a maximum of + 8000mV. + + - cirrus,ramp-rate : On power up, it affects the time from when the power + up sequence begins to the time the audio reaches a full-scale output. + On power down, it affects the time from when the power-down sequence + begins to when the amplifier disables the PWM outputs. If this property + is not set then soft ramping will be disabled and ramp time would be + 20ms. If this property is set to 0,1,2,3 then ramp times would be 40ms, + 60ms,100ms,175ms respectively for 48KHz sample rate. + + - cirrus,boost-ipk : The maximum current allowed for the boost converter. + The range starts at 1850000uA and goes to a maximum of 3600000uA + with a step size of 15625uA. The default is 2500000uA. + + - cirrus,imon-adc-scale : Configures the scaling of data bits from the IMON + ADC data word. This property can be set as a value of 0 for bits 15 down + to 0, 6 for 21 down to 6, 7, for 22 down to 7, 8 for 23 down to 8. + + +Optional H/G Algorithm sub-node: + +The cs35l33 node can have a single "cirrus,hg-algo" sub-node that will enable +the internal H/G Algorithm. + + - cirrus,hg-algo : Sub-node for internal Class H/G algorithm that + controls the amplifier supplies. + +Optional properties for the "cirrus,hg-algo" sub-node: + + - cirrus,mem-depth : Memory depth for the Class H/G algorithm measured in + LRCLK cycles. If this property is set to 0, 1, 2, or 3 then the memory + depths will be 1, 4, 8, 16 LRCLK cycles. The default is 16 LRCLK cycles. + + cirrus,release-rate : The number of consecutive LRCLK periods before + allowing release condition tracking updates. The number of LRCLK periods + start at 3 to a maximum of 255. + + - cirrus,ldo-thld : Configures the signal threshold at which the PWM output + stage enters LDO operation. Starts as a default value of 50mV for a value + of 1 and increases with a step size of 50mV to a maximum of 750mV (value of + 0xF). + + - cirrus,ldo-path-disable : This is a boolean property. If present, the H/G + algorithm uses the max detection path. If not present, the LDO + detection path is used. + + - cirrus,ldo-entry-delay : The LDO entry delay in milliseconds before the H/G + algorithm switches to the LDO voltage. This property can be set to values + from 0 to 7 for delays of 5ms, 10ms, 50ms, 100ms, 200ms, 500ms, 1000ms. + The default is 100ms. + + - cirrus,vp-hg-auto : This is a boolean property. When set, class H/G VPhg + automatic updating is enabled. + + - cirrus,vp-hg : Class H/G algorithm VPhg. Controls the H/G algorithm's + reference to the VP voltage for when to start generating a boosted VBST. + The reference voltage starts at 3000mV with a value of 0x3 and is increased + by 100mV per step to a maximum of 5500mV. + + - cirrus,vp-hg-rate : The rate (number of LRCLK periods) at which the VPhg is + allowed to increase to a higher voltage when using VPhg automatic + tracking. This property can be set to values from 0 to 3 with rates of 128 + periods, 2048 periods, 32768 periods, and 524288 periods. + The default is 32768 periods. + + - cirrus,vp-hg-va : VA calculation reference for automatic VPhg tracking + using VPMON. This property can be set to values from 0 to 6 starting at + 1800mV with a step size of 50mV up to a maximum value of 1750mV. + Default is 1800mV. + +Example: + +cs35l33: cs35l33@40 { + compatible = "cirrus,cs35l33"; + reg = <0x40>; + + VA-supply = <&ldo5_reg>; + VP-supply = <&ldo5_reg>; + + interrupt-parent = <&gpio8>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&cs47l91 34 0>; + + cirrus,ramp-rate = <0x0>; + cirrus,boost-ctl = <0x30>; /* VBST = 8000mV */ + cirrus,boost-ipk = <0xE0>; /* 3600mA */ + cirrus,imon-adc-scale = <0> /* Bits 15 down to 0 */ + + cirrus,hg-algo { + cirrus,mem-depth = <0x3>; + cirrus,release-rate = <0x3>; + cirrus,ldo-thld = <0x1>; + cirrus,ldo-path-disable = <0x0>; + cirrus,ldo-entry-delay=<0x4>; + cirrus,vp-hg-auto; + cirrus,vp-hg=<0xF>; + cirrus,vp-hg-rate=<0x2>; + cirrus,vp-hg-va=<0x0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs35l34.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l34.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f7606b7d542e2da8a2cdbd440beebe56202fc00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l34.txt @@ -0,0 +1,62 @@ +CS35L34 Speaker Amplifier + +Required properties: + + - compatible : "cirrus,cs35l34" + + - reg : the I2C address of the device for I2C. + + - VA-supply, VP-supply : power supplies for the device, + as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + + - cirrus,boost-vtge-millivolt : Boost Voltage Value. Configures the boost + converter's output voltage in mV. The range is from VP to 8V with + increments of 100mV. + + - cirrus,boost-nanohenry: Inductor value for boost converter. The value is + in nH and they can be values of 1000nH, 1100nH, 1200nH, 1500nH, and 2200nH. + +Optional properties: + + - reset-gpios: GPIO used to reset the amplifier. + + - interrupts : IRQ line info CS35L34. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + for further information relating to interrupt properties) + + - cirrus,boost-peak-milliamp : Boost converter peak current limit in mA. The + range starts at 1200mA and goes to a maximum of 3840mA with increments of + 80mA. The default value is 2480mA. + + - cirrus,i2s-sdinloc : ADSP SDIN I2S channel location. Indicates whether the + received mono data is in the left or right portion of the I2S frame + according to the AD0 pin or directly via this configuration. + 0x0 (Default) = Selected by AD0 input (if AD0 = LOW, use left channel), + 0x2 = Left, + 0x1 = Selected by the inversion of the AD0 input (if AD0 = LOW, use right + channel), + 0x3 = Right. + + - cirrus,gain-zc-disable: Boolean property. If set, the gain change will take + effect without waiting for a zero cross. + + - cirrus,tdm-rising-edge: Boolean property. If set, data is on the rising edge of + SCLK. Otherwise, data is on the falling edge of SCLK. + + +Example: + +cs35l34: cs35l34@40 { + compatible = "cirrus,cs35l34"; + reg = <0x40>; + + interrupt-parent = <&gpio8>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&gpio 10 0>; + + cirrus,boost-vtge-milltvolt = <8000>; /* 8V */ + cirrus,boost-ind-nanohenry = <1000>; /* 1uH */ + cirrus,boost-peak-milliamp = <3000>; /* 3A */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs35l35.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l35.txt new file mode 100644 index 0000000000000000000000000000000000000000..7915897f8a81bbb5df41395eaf3ff1020c3c2678 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs35l35.txt @@ -0,0 +1,181 @@ +CS35L35 Boosted Speaker Amplifier + +Required properties: + + - compatible : "cirrus,cs35l35" + + - reg : the I2C address of the device for I2C + + - VA-supply, VP-supply : power supplies for the device, + as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + + - interrupts : IRQ line info CS35L35. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + for further information relating to interrupt properties) + + - cirrus,boost-ind-nanohenry: Inductor value for boost converter. The value is + in nH and they can be values of 1000nH, 1200nH, 1500nH, and 2200nH. + +Optional properties: + - reset-gpios : gpio used to reset the amplifier + + - cirrus,stereo-config : Boolean to determine if there are 2 AMPs for a + Stereo configuration + + - cirrus,audio-channel : Set Location of Audio Signal on Serial Port + 0 = Data Packet received on Left I2S Channel + 1 = Data Packet received on Right I2S Channel + + - cirrus,advisory-channel : Set Location of Advisory Signal on Serial Port + 0 = Data Packet received on Left I2S Channel + 1 = Data Packet received on Right I2S Channel + + - cirrus,shared-boost : Boolean to enable ClassH tracking of Advisory Signal + if 2 Devices share Boost BST_CTL + + - cirrus,external-boost : Boolean to specify the device is using an external + boost supply, note that sharing a boost from another cs35l35 would constitute + using an external supply for the slave device + + - cirrus,sp-drv-strength : Value for setting the Serial Port drive strength + Table 3-10 of the datasheet lists drive-strength specifications + 0 = 1x (Default) + 1 = .5x + - cirrus,sp-drv-unused : Determines how unused slots should be driven on the + Serial Port. + 0 - Hi-Z + 2 - Drive 0's (Default) + 3 - Drive 1's + + - cirrus,bst-pdn-fet-on : Boolean to determine if the Boost PDN control + powers down with a rectification FET On or Off. If VSPK is supplied + externally then FET is off. + + - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost + converter's output voltage in mV. The range is from 2600mV to 9000mV with + increments of 100mV. + (Default) VP + + - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA. + Configures the peak current by monitoring the current through the boost FET. + Range starts at 1680mA and goes to a maximum of 4480mA with increments of + 110mA. + (Default) 2.46 Amps + + - cirrus,amp-gain-zc : Boolean to determine if to use Amplifier gain-change + zero-cross + +Optional H/G Algorithm sub-node: + + The cs35l35 node can have a single "cirrus,classh-internal-algo" sub-node + that will disable automatic control of the internal H/G Algorithm. + + It is strongly recommended that the Datasheet be referenced when adjusting + or using these Class H Algorithm controls over the internal Algorithm. + Serious damage can occur to the Device and surrounding components. + + - cirrus,classh-internal-algo : Sub-node for the Internal Class H Algorithm + See Section 4.3 Internal Class H Algorithm in the Datasheet. + If not used, the device manages the ClassH Algorithm internally. + +Optional properties for the "cirrus,classh-internal-algo" Sub-node + + Section 7.29 Class H Control + - cirrus,classh-bst-overide : Boolean + - cirrus,classh-bst-max-limit + - cirrus,classh-mem-depth + + Section 7.30 Class H Headroom Control + - cirrus,classh-headroom + + Section 7.31 Class H Release Rate + - cirrus,classh-release-rate + + Section 7.32 Class H Weak FET Drive Control + - cirrus,classh-wk-fet-disable + - cirrus,classh-wk-fet-delay + - cirrus,classh-wk-fet-thld + + Section 7.34 Class H VP Control + - cirrus,classh-vpch-auto + - cirrus,classh-vpch-rate + - cirrus,classh-vpch-man + +Optional Monitor Signal Format sub-node: + + The cs35l35 node can have a single "cirrus,monitor-signal-format" sub-node + for adjusting the Depth, Location and Frame of the Monitoring Signals + for Algorithms. + + See Sections 4.8.2 through 4.8.4 Serial-Port Control in the Datasheet + + -cirrus,monitor-signal-format : Sub-node for the Monitor Signaling Formating + on the I2S Port. Each of the 3 8 bit values in the array contain the settings + for depth, location, and frame. + + If not used, the defaults for the 6 monitor signals is used. + + Sections 7.44 - 7.53 lists values for the depth, location, and frame + for each monitoring signal. + + - cirrus,imon : 4 8 bit values to set the depth, location, frame and ADC + scale of the IMON monitor signal. + + - cirrus,vmon : 3 8 bit values to set the depth, location, and frame + of the VMON monitor signal. + + - cirrus,vpmon : 3 8 bit values to set the depth, location, and frame + of the VPMON monitor signal. + + - cirrus,vbstmon : 3 8 bit values to set the depth, location, and frame + of the VBSTMON monitor signal + + - cirrus,vpbrstat : 3 8 bit values to set the depth, location, and frame + of the VPBRSTAT monitor signal + + - cirrus,zerofill : 3 8 bit values to set the depth, location, and frame\ + of the ZEROFILL packet in the monitor signal + +Example: + +cs35l35: cs35l35@20 { + compatible = "cirrus,cs35l35"; + reg = <0x20>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + reset-gpios = <&axi_gpio 54 0>; + interrupt-parent = <&gpio8>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + cirrus,boost-ctl-millivolt = <9000>; + + cirrus,stereo-config; + cirrus,audio-channel = <0x00>; + cirrus,advisory-channel = <0x01>; + cirrus,shared-boost; + + cirrus,classh-internal-algo { + cirrus,classh-bst-overide; + cirrus,classh-bst-max-limit = <0x01>; + cirrus,classh-mem-depth = <0x01>; + cirrus,classh-release-rate = <0x08>; + cirrus,classh-headroom-millivolt = <0x0B>; + cirrus,classh-wk-fet-disable = <0x01>; + cirrus,classh-wk-fet-delay = <0x04>; + cirrus,classh-wk-fet-thld = <0x01>; + cirrus,classh-vpch-auto = <0x01>; + cirrus,classh-vpch-rate = <0x02>; + cirrus,classh-vpch-man = <0x05>; + }; + + /* Depth, Location, Frame */ + cirrus,monitor-signal-format { + cirrus,imon = /bits/ 8 <0x03 0x00 0x01>; + cirrus,vmon = /bits/ 8 <0x03 0x00 0x00>; + cirrus,vpmon = /bits/ 8 <0x03 0x04 0x00>; + cirrus,vbstmon = /bits/ 8 <0x03 0x04 0x01>; + cirrus,vpbrstat = /bits/ 8 <0x00 0x04 0x00>; + cirrus,zerofill = /bits/ 8 <0x00 0x00 0x00>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs4265.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs4265.txt new file mode 100644 index 0000000000000000000000000000000000000000..380fff8e4e8323c73bad184e497eae3b830fabc5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs4265.txt @@ -0,0 +1,29 @@ +CS4265 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "cirrus,cs4265" + + - reg : the I2C address of the device for I2C. The I2C address depends on + the state of the AD0 pin. If AD0 is high, the i2c address is 0x4f. + If it is low, the i2c address is 0x4e. + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + +Examples: + +codec_ad0_high: cs4265@4f { /* AD0 Pin is high */ + compatible = "cirrus,cs4265"; + reg = <0x4f>; +}; + + +codec_ad0_low: cs4265@4e { /* AD0 Pin is low */ + compatible = "cirrus,cs4265"; + reg = <0x4e>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs4270.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs4270.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b222f9b8ef535b6477e6c236b4ed8ac43d2fe02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs4270.txt @@ -0,0 +1,21 @@ +CS4270 audio CODEC + +The driver for this device currently only supports I2C. + +Required properties: + + - compatible : "cirrus,cs4270" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset-gpio : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + +Example: + +codec: cs4270@48 { + compatible = "cirrus,cs4270"; + reg = <0x48>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs4271.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs4271.txt new file mode 100644 index 0000000000000000000000000000000000000000..6e699ceabacdedcc9d27043bb74cf53d88c5544a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs4271.txt @@ -0,0 +1,57 @@ +Cirrus Logic CS4271 DT bindings + +This driver supports both the I2C and the SPI bus. + +Required properties: + + - compatible: "cirrus,cs4271" + +For required properties on SPI, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Required properties on I2C: + + - reg: the i2c address + + +Optional properties: + + - reset-gpio: a GPIO spec to define which pin is connected to the chip's + !RESET pin + - cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag + is enabled. + - cirrus,enable-soft-reset: + The CS4271 requires its LRCLK and MCLK to be stable before its RESET + line is de-asserted. That also means that clocks cannot be changed + without putting the chip back into hardware reset, which also requires + a complete re-initialization of all registers. + + One (undocumented) workaround is to assert and de-assert the PDN bit + in the MODE2 register. This workaround can be enabled with this DT + property. + + Note that this is not needed in case the clocks are stable + throughout the entire runtime of the codec. + + - vd-supply: Digital power + - vl-supply: Logic power + - va-supply: Analog Power + +Examples: + + codec_i2c: cs4271@10 { + compatible = "cirrus,cs4271"; + reg = <0x10>; + reset-gpio = <&gpio 23 0>; + vd-supply = <&vdd_3v3_reg>; + vl-supply = <&vdd_3v3_reg>; + va-supply = <&vdd_3v3_reg>; + }; + + codec_spi: cs4271@0 { + compatible = "cirrus,cs4271"; + reg = <0x0>; + reset-gpio = <&gpio 23 0>; + spi-max-frequency = <6000000>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs42l42.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l42.txt new file mode 100644 index 0000000000000000000000000000000000000000..7dfaa2ab906fbd520680051097a8af3ebe53270e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l42.txt @@ -0,0 +1,107 @@ +CS42L42 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l42" + + - reg : the I2C address of the device for I2C. + + - VP-supply, VCP-supply, VD_FILT-supply, VL-supply, VA-supply : + power supplies for the device, as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - interrupts : IRQ line info CS42L42. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + for further information relating to interrupt properties) + + - cirrus,ts-inv : Boolean property. For jacks that invert the tip sense + polarity. Normal jacks will short tip sense pin to HS1 when headphones are + plugged in and leave tip sense floating when not plugged in. Inverting jacks + short tip sense when unplugged and float when plugged in. + + 0 = (Default) Non-inverted + 1 = Inverted + + - cirrus,ts-dbnc-rise : Debounce the rising edge of TIP_SENSE_PLUG. With no + debounce, the tip sense pin might be noisy on a plug event. + + 0 - 0ms, + 1 - 125ms, + 2 - 250ms, + 3 - 500ms, + 4 - 750ms, + 5 - (Default) 1s, + 6 - 1.25s, + 7 - 1.5s, + + - cirrus,ts-dbnc-fall : Debounce the falling edge of TIP_SENSE_UNPLUG. + With no debounce, the tip sense pin might be noisy on an unplug event. + + 0 - 0ms, + 1 - 125ms, + 2 - 250ms, + 3 - 500ms, + 4 - 750ms, + 5 - (Default) 1s, + 6 - 1.25s, + 7 - 1.5s, + + - cirrus,btn-det-init-dbnce : This sets how long the driver sleeps after + enabling button detection interrupts. After auto-detection and before + servicing button interrupts, the HS bias needs time to settle. If you + don't wait, there is possibility for erroneous button interrupt. + + 0ms - 200ms, + Default = 100ms + + - cirrus,btn-det-event-dbnce : This sets how long the driver delays after + receiving a button press interrupt. With level detect interrupts, you want + to wait a small amount of time to make sure the button press is making a + clean connection with the bias resistors. + + 0ms - 20ms, + Default = 10ms + + - cirrus,bias-lvls : For a level-detect headset button scheme, each button + will bias the mic pin to a certain voltage. To determine which button was + pressed, the driver will compare this biased voltage to sequential, + decreasing voltages and will stop when a comparator is tripped, + indicating a comparator voltage < bias voltage. This value represents a + percentage of the internally generated HS bias voltage. For different + hardware setups, a designer might want to tweak this. This is an array of + descending values for the comparator voltage. + + Array of 4 values + Each 0-63 + < x1 x2 x3 x4 > + Default = < 15 8 4 1> + + +Example: + +cs42l42: cs42l42@48 { + compatible = "cirrus,cs42l42"; + reg = <0x48>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + VCP-supply = <&dummy_vreg>; + VD_FILT-supply = <&dummy_vreg>; + VL-supply = <&dummy_vreg>; + + reset-gpios = <&axi_gpio_0 1 0>; + interrupt-parent = <&gpio0>; + interrupts = <55 8> + + cirrus,ts-inv = <0x00>; + cirrus,ts-dbnc-rise = <0x05>; + cirrus,ts-dbnc-fall = <0x00>; + cirrus,btn-det-init-dbnce = <100>; + cirrus,btn-det-event-dbnce = <10>; + cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>; + cirrus,hs-bias-ramp-rate = <0x02>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs42l52.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l52.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc03c9312a19462431fa567c148e4af4dcb3759c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l52.txt @@ -0,0 +1,46 @@ +CS42L52 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l52" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - cirrus,reset-gpio : GPIO controller's phandle and the number + of the GPIO used to reset the codec. + + - cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency. + Allowable values of 0x00 through 0x0F. These are raw values written to the + register, not the actual frequency. The frequency is determined by the following. + Frequency = (64xFs)/(N+2) + N = chgfreq_val + Fs = Sample Rate (variable) + + - cirrus,mica-differential-cfg : boolean, If present, then the MICA input is configured + as a differential input. If not present then the MICA input is configured as + Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input. + + - cirrus,micb-differential-cfg : boolean, If present, then the MICB input is configured + as a differential input. If not present then the MICB input is configured as + Single-ended input. Single-ended mode allows for MIC1 or MIC2 muxing for input. + + - cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin + 0 = 0.5 x VA + 1 = 0.6 x VA + 2 = 0.7 x VA + 3 = 0.8 x VA + 4 = 0.83 x VA + 5 = 0.91 x VA + +Example: + +codec: codec@4a { + compatible = "cirrus,cs42l52"; + reg = <0x4a>; + reset-gpio = <&gpio 10 0>; + cirrus,chgfreq-divisor = <0x05>; + cirrus.mica-differential-cfg; + cirrus,micbias-lvl = <5>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs42l56.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l56.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ba520a28ae8fcafb286819fb0123c9228df4f68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l56.txt @@ -0,0 +1,63 @@ +CS42L52 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l56" + + - reg : the I2C address of the device for I2C + + - VA-supply, VCP-supply, VLDO-supply : power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - cirrus,gpio-nreset : GPIO controller's phandle and the number + of the GPIO used to reset the codec. + + - cirrus,chgfreq-divisor : Values used to set the Charge Pump Frequency. + Allowable values of 0x00 through 0x0F. These are raw values written to the + register, not the actual frequency. The frequency is determined by the following. + Frequency = MCLK / 4 * (N+2) + N = chgfreq_val + MCLK = Where MCLK is the frequency of the mclk signal after the MCLKDIV2 circuit. + + - cirrus,ain1a-ref-cfg, ain1b-ref-cfg : boolean, If present, AIN1A or AIN1B are configured + as a pseudo-differential input referenced to AIN1REF/AIN3A. + + - cirrus,ain2a-ref-cfg, ain2b-ref-cfg : boolean, If present, AIN2A or AIN2B are configured + as a pseudo-differential input referenced to AIN2REF/AIN3B. + + - cirrus,micbias-lvl: Set the output voltage level on the MICBIAS Pin. + 0 = 0.5 x VA + 1 = 0.6 x VA + 2 = 0.7 x VA + 3 = 0.8 x VA + 4 = 0.83 x VA + 5 = 0.91 x VA + + - cirrus,adaptive-pwr-cfg : Configures how the power to the Headphone and Lineout + Amplifiers adapt to the output signal levels. + 0 = Adapt to Volume Mode. Voltage level determined by the sum of the relevant volume settings. + 1 = Fixed - Headphone and Line Amp supply = + or - VCP/2. + 2 = Fixed - Headphone and Line Amp supply = + or - VCP. + 3 = Adapted to Signal; Voltage level is dynamically determined by the output signal. + + - cirrus,hpf-left-freq, hpf-right-freq : Sets the corner frequency (-3dB point) for the internal High-Pass + Filter. + 0 = 1.8Hz + 1 = 119Hz + 2 = 236Hz + 3 = 464Hz + + +Example: + +codec: codec@4b { + compatible = "cirrus,cs42l56"; + reg = <0x4b>; + cirrus,gpio-nreset = <&gpio 10 0>; + cirrus,chgfreq-divisor = <0x05>; + cirrus.ain1_ref_cfg; + cirrus,micbias-lvl = <5>; + VA-supply = <®_audio>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs42l73.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l73.txt new file mode 100644 index 0000000000000000000000000000000000000000..80ae910dbf6c388021ff5cb590e00f9f035cefd1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs42l73.txt @@ -0,0 +1,22 @@ +CS42L73 audio CODEC + +Required properties: + + - compatible : "cirrus,cs42l73" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset_gpio : a GPIO spec for the reset pin. + - chgfreq : Charge Pump Frequency values 0x00-0x0F + + +Example: + +codec: cs42l73@4a { + compatible = "cirrus,cs42l73"; + reg = <0x4a>; + reset_gpio = <&gpio 10 0>; + chgfreq = <0x05>; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs42xx8.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs42xx8.txt new file mode 100644 index 0000000000000000000000000000000000000000..8619a156d038bdd76e342351fe83af63b4105746 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs42xx8.txt @@ -0,0 +1,28 @@ +CS42448/CS42888 audio CODEC + +Required properties: + + - compatible : must contain one of "cirrus,cs42448" and "cirrus,cs42888" + + - reg : the I2C address of the device for I2C + + - clocks : a list of phandles + clock-specifiers, one for each entry in + clock-names + + - clock-names : must contain "mclk" + + - VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt + +Example: + +cs42888: codec@48 { + compatible = "cirrus,cs42888"; + reg = <0x48>; + clocks = <&codec_mclk 0>; + clock-names = "mclk"; + VA-supply = <®_audio>; + VD-supply = <®_audio>; + VLS-supply = <®_audio>; + VLC-supply = <®_audio>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs43130.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs43130.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b1dd5aeb00467bee506ea4f82420ab7672f8e53 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs43130.txt @@ -0,0 +1,67 @@ +CS43130 DAC + +Required properties: + + - compatible : "cirrus,cs43130", "cirrus,cs4399", "cirrus,cs43131", + "cirrus,cs43198" + + - reg : the I2C address of the device for I2C + + - VA-supply, VP-supply, VL-supply, VCP-supply, VD-supply: + power supplies for the device, as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + + +Optional properties: + + - reset-gpios : Active low GPIO used to reset the device + + - cirrus,xtal-ibias: + When external MCLK is generated by external crystal + oscillator, CS43130 can be used to provide bias current + for external crystal. Amount of bias current sent is + set as: + 1 = 7.5uA + 2 = 12.5uA + 3 = 15uA + + - cirrus,dc-measure: + Boolean, define to enable headphone DC impedance measurement. + + - cirrus,ac-measure: + Boolean, define to enable headphone AC impedance measurement. + DC impedance must also be enabled for AC impedance measurement. + + - cirrus,dc-threshold: + Define 2 DC impedance thresholds in ohms for HP output control. + Default values are 50 and 120 Ohms. + + - cirrus,ac-freq: + Define the frequencies at which to measure HP AC impedance. + Only used if "cirrus,dc-measure" is defined. + Exactly 10 frequencies must be defined. + If this properties is undefined, by default, + following frequencies are used: + <24 43 93 200 431 928 2000 4309 9283 20000> + The above frequencies are logarithmically equally spaced. + Log base is 10. + +Example: + +cs43130: audio-codec@30 { + compatible = "cirrus,cs43130"; + reg = <0x30>; + reset-gpios = <&axi_gpio 54 0>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; + VL-supply = <&dummy_vreg>; + VCP-supply = <&dummy_vreg>; + VD-supply = <&dummy_vreg>; + cirrus,xtal-ibias = <2>; + interrupt-parent = <&gpio0>; + interrupts = <55 8>; + cirrus,dc-measure; + cirrus,ac-measure; + cirrus,dc-threshold = /bits/ 16 <20 100>; + cirrus,ac-freq = /bits/ 16 <24 43 93 200 431 928 2000 4309 9283 20000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs4349.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs4349.txt new file mode 100644 index 0000000000000000000000000000000000000000..54c117b59dba54bf666fa22c9e92a2f805045899 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs4349.txt @@ -0,0 +1,19 @@ +CS4349 audio CODEC + +Required properties: + + - compatible : "cirrus,cs4349" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. + +Example: + +codec: cs4349@48 { + compatible = "cirrus,cs4349"; + reg = <0x48>; + reset-gpios = <&gpio 54 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/cs53l30.txt b/arch/arm64/boot/dts/vendor/bindings/sound/cs53l30.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dbfb8274cd9b5b86261655678fe2cff24f20bd4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/cs53l30.txt @@ -0,0 +1,44 @@ +CS53L30 audio CODEC + +Required properties: + + - compatible : "cirrus,cs53l30" + + - reg : the I2C address of the device + + - VA-supply, VP-supply : power supplies for the device, + as covered in Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. + + - mute-gpios : a GPIO spec for the MUTE pin. The active state can be either + GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW, which would be handled + by the driver automatically. + + - cirrus,micbias-lvl : Set the output voltage level on the MICBIAS Pin. + 0 = Hi-Z + 1 = 1.80 V + 2 = 2.75 V + + - cirrus,use-sdout2 : This is a boolean property. If present, it indicates + the hardware design connects both SDOUT1 and SDOUT2 + pins to output data. Otherwise, it indicates that + only SDOUT1 is connected for data output. + * CS53l30 supports 4-channel data output in the same + * frame using two different ways: + * 1) Normal I2S mode on two data pins -- each SDOUT + * carries 2-channel data in the same time. + * 2) TDM mode on one signle data pin -- SDOUT1 carries + * 4-channel data per frame. + +Example: + +codec: cs53l30@48 { + compatible = "cirrus,cs53l30"; + reg = <0x48>; + reset-gpios = <&gpio 54 0>; + VA-supply = <&cs53l30_va>; + VP-supply = <&cs53l30_vp>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/da7213.txt b/arch/arm64/boot/dts/vendor/bindings/sound/da7213.txt new file mode 100644 index 0000000000000000000000000000000000000000..58902802d56c0a22d523e5b069e7b116b69a5757 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/da7213.txt @@ -0,0 +1,41 @@ +Dialog Semiconductor DA7213 Audio Codec bindings + +====== + +Required properties: +- compatible : Should be "dlg,da7213" +- reg: Specifies the I2C slave address + +Optional properties: +- clocks : phandle and clock specifier for codec MCLK. +- clock-names : Clock name string for 'clocks' attribute, should be "mclk". + +- dlg,micbias1-lvl : Voltage (mV) for Mic Bias 1 + [<1600>, <2200>, <2500>, <3000>] +- dlg,micbias2-lvl : Voltage (mV) for Mic Bias 2 + [<1600>, <2200>, <2500>, <3000>] +- dlg,dmic-data-sel : DMIC channel select based on clock edge. + ["lrise_rfall", "lfall_rrise"] +- dlg,dmic-samplephase : When to sample audio from DMIC. + ["on_clkedge", "between_clkedge"] +- dlg,dmic-clkrate : DMIC clock frequency (Hz). + [<1500000>, <3000000>] + +====== + +Example: + + codec_i2c: da7213@1a { + compatible = "dlg,da7213"; + reg = <0x1a>; + + clocks = <&clks 201>; + clock-names = "mclk"; + + dlg,micbias1-lvl = <2500>; + dlg,micbias2-lvl = <2500>; + + dlg,dmic-data-sel = "lrise_rfall"; + dlg,dmic-samplephase = "between_clkedge"; + dlg,dmic-clkrate = <3000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/da7218.txt b/arch/arm64/boot/dts/vendor/bindings/sound/da7218.txt new file mode 100644 index 0000000000000000000000000000000000000000..2cf30899bd0d760515b35e01cbec20032ef67da1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/da7218.txt @@ -0,0 +1,102 @@ +Dialog Semiconductor DA7218 Audio Codec bindings + +DA7218 is an audio codec with HP detect feature. + +====== + +Required properties: +- compatible : Should be "dlg,da7217" or "dlg,da7218" +- reg: Specifies the I2C slave address + +- VDD-supply: VDD power supply for the device +- VDDMIC-supply: VDDMIC power supply for the device +- VDDIO-supply: VDDIO power supply for the device + (See Documentation/devicetree/bindings/regulator/regulator.txt for further + information relating to regulators) + +Optional properties: +- interrupts: IRQ line info for DA7218 chip. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for + further information relating to interrupt properties) +- interrupt-names : Name associated with interrupt line. Should be "wakeup" if + interrupt is to be used to wake system, otherwise "irq" should be used. +- wakeup-source: Flag to indicate this device can wake system (suspend/resume). + +- clocks : phandle and clock specifier for codec MCLK. +- clock-names : Clock name string for 'clocks' attribute, should be "mclk". + +- dlg,micbias1-lvl-millivolt : Voltage (mV) for Mic Bias 1 + [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>] +- dlg,micbias2-lvl-millivolt : Voltage (mV) for Mic Bias 2 + [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>] +- dlg,mic1-amp-in-sel : Mic1 input source type + ["diff", "se_p", "se_n"] +- dlg,mic2-amp-in-sel : Mic2 input source type + ["diff", "se_p", "se_n"] +- dlg,dmic1-data-sel : DMIC1 channel select based on clock edge. + ["lrise_rfall", "lfall_rrise"] +- dlg,dmic1-samplephase : When to sample audio from DMIC1. + ["on_clkedge", "between_clkedge"] +- dlg,dmic1-clkrate-hz : DMic1 clock frequency (Hz). + [<1500000>, <3000000>] +- dlg,dmic2-data-sel : DMic2 channel select based on clock edge. + ["lrise_rfall", "lfall_rrise"] +- dlg,dmic2-samplephase : When to sample audio from DMic2. + ["on_clkedge", "between_clkedge"] +- dlg,dmic2-clkrate-hz : DMic2 clock frequency (Hz). + [<1500000>, <3000000>] +- dlg,hp-diff-single-supply : Boolean flag, use single supply for HP + (DA7217 only) + +====== + +Optional Child node - 'da7218_hpldet' (DA7218 only): + +Optional properties: +- dlg,jack-rate-us : Time between jack detect measurements (us) + [<5>, <10>, <20>, <40>, <80>, <160>, <320>, <640>] +- dlg,jack-debounce : Number of debounce measurements taken for jack detect + [<0>, <2>, <3>, <4>] +- dlg,jack-threshold-pct : Threshold level for jack detection (% of VDD) + [<84>, <88>, <92>, <96>] +- dlg,comp-inv : Boolean flag, invert comparator output +- dlg,hyst : Boolean flag, enable hysteresis +- dlg,discharge : Boolean flag, auto discharge of Mic Bias on jack removal + +====== + +Example: + + codec: da7218@1a { + compatible = "dlg,da7218"; + reg = <0x1a>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + wakeup-source; + + VDD-supply = <®_audio>; + VDDMIC-supply = <®_audio>; + VDDIO-supply = <®_audio>; + + clocks = <&clks 201>; + clock-names = "mclk"; + + dlg,micbias1-lvl-millivolt = <2600>; + dlg,micbias2-lvl-millivolt = <2600>; + dlg,mic1-amp-in-sel = "diff"; + dlg,mic2-amp-in-sel = "diff"; + + dlg,dmic1-data-sel = "lrise_rfall"; + dlg,dmic1-samplephase = "on_clkedge"; + dlg,dmic1-clkrate-hz = <3000000>; + dlg,dmic2-data-sel = "lrise_rfall"; + dlg,dmic2-samplephase = "on_clkedge"; + dlg,dmic2-clkrate-hz = <3000000>; + + da7218_hpldet { + dlg,jack-rate-us = <40>; + dlg,jack-debounce = <2>; + dlg,jack-threshold-pct = <84>; + dlg,hyst; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/da7219.txt b/arch/arm64/boot/dts/vendor/bindings/sound/da7219.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9d0baeb94e28f76e310ea76373a55cceafdad71 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/da7219.txt @@ -0,0 +1,112 @@ +Dialog Semiconductor DA7219 Audio Codec bindings + +DA7219 is an audio codec with advanced accessory detect features. + +====== + +Required properties: +- compatible : Should be "dlg,da7219" +- reg: Specifies the I2C slave address + +- interrupts : IRQ line info for DA7219. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for + further information relating to interrupt properties) + +- VDD-supply: VDD power supply for the device +- VDDMIC-supply: VDDMIC power supply for the device +- VDDIO-supply: VDDIO power supply for the device + (See Documentation/devicetree/bindings/regulator/regulator.txt for further + information relating to regulators) + +Optional properties: +- interrupt-names : Name associated with interrupt line. Should be "wakeup" if + interrupt is to be used to wake system, otherwise "irq" should be used. +- wakeup-source: Flag to indicate this device can wake system (suspend/resume). + +- #clock-cells : Should be set to '<0>', only one clock source provided; +- clock-output-names : Name given for DAI clocks output; + +- clocks : phandle and clock specifier for codec MCLK. +- clock-names : Clock name string for 'clocks' attribute, should be "mclk". + +- dlg,micbias-lvl : Voltage (mV) for Mic Bias + [<1600>, <1800>, <2000>, <2200>, <2400>, <2600>] +- dlg,mic-amp-in-sel : Mic input source type + ["diff", "se_p", "se_n"] + +Deprecated properties: +- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine + (LDO unavailable in production HW so property no longer required). + +====== + +Child node - 'da7219_aad': + +Optional properties: +- dlg,micbias-pulse-lvl : Mic bias higher voltage pulse level (mV). + [<2800>, <2900>] +- dlg,micbias-pulse-time : Mic bias higher voltage pulse duration (ms) +- dlg,btn-cfg : Periodic button press measurements for 4-pole jack (ms) + [<2>, <5>, <10>, <50>, <100>, <200>, <500>] +- dlg,mic-det-thr : Impedance threshold for mic detection measurement (Ohms) + [<200>, <500>, <750>, <1000>] +- dlg,jack-ins-deb : Debounce time for jack insertion (ms) + [<5>, <10>, <20>, <50>, <100>, <200>, <500>, <1000>] +- dlg,jack-det-rate: Jack type detection latency (3/4 pole) + ["32ms_64ms", "64ms_128ms", "128ms_256ms", "256ms_512ms"] +- dlg,jack-rem-deb : Debounce time for jack removal (ms) + [<1>, <5>, <10>, <20>] +- dlg,a-d-btn-thr : Impedance threshold between buttons A and D + [0x0 - 0xFF] +- dlg,d-b-btn-thr : Impedance threshold between buttons D and B + [0x0 - 0xFF] +- dlg,b-c-btn-thr : Impedance threshold between buttons B and C + [0x0 - 0xFF] +- dlg,c-mic-btn-thr : Impedance threshold between button C and Mic + [0x0 - 0xFF] +- dlg,btn-avg : Number of 8-bit readings for averaged button measurement + [<1>, <2>, <4>, <8>] +- dlg,adc-1bit-rpt : Repeat count for 1-bit button measurement + [<1>, <2>, <4>, <8>] + +====== + +Example: + + codec: da7219@1a { + compatible = "dlg,da7219"; + reg = <0x1a>; + + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + + VDD-supply = <®_audio>; + VDDMIC-supply = <®_audio>; + VDDIO-supply = <®_audio>; + + #clock-cells = <0>; + clock-output-names = "dai-clks"; + + clocks = <&clks 201>; + clock-names = "mclk"; + + dlg,ldo-lvl = <1200>; + dlg,micbias-lvl = <2600>; + dlg,mic-amp-in-sel = "diff"; + + da7219_aad { + dlg,btn-cfg = <50>; + dlg,mic-det-thr = <500>; + dlg,jack-ins-deb = <20>; + dlg,jack-det-rate = "32ms_64ms"; + dlg,jack-rem-deb = <1>; + + dlg,a-d-btn-thr = <0xa>; + dlg,d-b-btn-thr = <0x16>; + dlg,b-c-btn-thr = <0x21>; + dlg,c-mic-btn-thr = <0x3E>; + + dlg,btn-avg = <4>; + dlg,adc-1bit-rpt = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/da9055.txt b/arch/arm64/boot/dts/vendor/bindings/sound/da9055.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed1b7cc6f249efdbc4795842d3b62e74f0826a83 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/da9055.txt @@ -0,0 +1,22 @@ +* Dialog DA9055 Audio CODEC + +DA9055 provides Audio CODEC support (I2C only). + +The Audio CODEC device in DA9055 has it's own I2C address which is configurable, +so the device is instantiated separately from the PMIC (MFD) device. + +For details on accompanying PMIC I2C device, see the following: +Documentation/devicetree/bindings/mfd/da9055.txt + +Required properties: + + - compatible: "dlg,da9055-codec" + - reg: Specifies the I2C slave address + + +Example: + + codec: da9055-codec@1a { + compatible = "dlg,da9055-codec"; + reg = <0x1a>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/davinci-evm-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/davinci-evm-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..963e100514c27d892069d1d504e70f249f620b2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/davinci-evm-audio.txt @@ -0,0 +1,49 @@ +* Texas Instruments SoC audio setups with TLV320AIC3X Codec + +Required properties: +- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx +- ti,model : The user-visible name of this sound complex. +- ti,audio-codec : The phandle of the TLV320AIC3x audio codec +- ti,mcasp-controller : The phandle of the McASP controller +- ti,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the codec's pins, and the jacks on the board: + +Optional properties: +- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec. +- clocks : Reference to the master clock +- clock-names : The clock should be named "mclk" +- Either codec-clock-rate or the codec-clock reference has to be defined. If + the both are defined the driver attempts to set referenced clock to the + defined rate and takes the rate from the clock reference. + + Board connectors: + + * Headphone Jack + * Line Out + * Mic Jack + * Line In + + +Example: + +sound { + compatible = "ti,da830-evm-audio"; + ti,model = "DA830 EVM"; + ti,audio-codec = <&tlv320aic3x>; + ti,mcasp-controller = <&mcasp1>; + ti,codec-clock-rate = <12000000>; + ti,audio-routing = + "Headphone Jack", "HPLOUT", + "Headphone Jack", "HPROUT", + "Line Out", "LLOUT", + "Line Out", "RLOUT", + "MIC3L", "Mic Bias 2V", + "MIC3R", "Mic Bias 2V", + "Mic Bias 2V", "Mic Jack", + "LINE1L", "Line In", + "LINE2L", "Line In", + "LINE1R", "Line In", + "LINE2R", "Line In"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/davinci-mcasp-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/davinci-mcasp-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..46bc9829c71aabe7041bbe4af60d586aa590c1ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/davinci-mcasp-audio.txt @@ -0,0 +1,60 @@ +Texas Instruments McASP controller + +Required properties: +- compatible : + "ti,dm646x-mcasp-audio" : for DM646x platforms + "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms + "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx) + "ti,dra7-mcasp-audio" : for DRA7xx platforms + +- reg : Should contain reg specifiers for the entries in the reg-names property. +- reg-names : Should contain: + * "mpu" for the main registers (required). For compatibility with + existing software, it is recommended this is the first entry. + * "dat" for separate data port register access (optional). +- op-mode : I2S/DIT ops mode. 0 for I2S mode. 1 for DIT mode used for S/PDIF, + IEC60958-1, and AES-3 formats. +- tdm-slots : Slots for TDM operation. Indicates number of channels transmitted + or received over one serializer. +- serial-dir : A list of serializer configuration. Each entry is a number + indication for serializer pin direction. + (0 - INACTIVE, 1 - TX, 2 - RX) +- dmas: two element list of DMA controller phandles and DMA request line + ordered pairs. +- dma-names: identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. The dma + identifiers must be "rx" and "tx". + +Optional properties: + +- ti,hwmods : Must be "mcasp", n is controller instance starting 0 +- tx-num-evt : FIFO levels. +- rx-num-evt : FIFO levels. +- sram-size-playback : size of sram to be allocated during playback +- sram-size-capture : size of sram to be allocated during capture +- interrupts : Interrupt numbers for McASP +- interrupt-names : Known interrupt names are "tx" and "rx" +- pinctrl-0: Should specify pin control group used for this controller. +- pinctrl-names: Should contain only one value - "default", for more details + please refer to pinctrl-bindings.txt +- fck_parent : Should contain a valid clock name which will be used as parent + for the McASP fck + +Example: + +mcasp0: mcasp0@1d00000 { + compatible = "ti,da830-mcasp-audio"; + reg = <0x100000 0x3000>; + reg-names "mpu"; + interrupts = <82>, <83>; + interrupt-names = "tx", "rx"; + op-mode = <0>; /* MCASP_IIS_MODE */ + tdm-slots = <2>; + serial-dir = < + 0 0 0 0 /* 0: INACTIVE, 1: TX, 2: RX */ + 0 0 0 0 + 0 0 0 1 + 2 0 0 0 >; + tx-num-evt = <1>; + rx-num-evt = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/davinci-mcbsp.txt b/arch/arm64/boot/dts/vendor/bindings/sound/davinci-mcbsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ffc2562fb31a24165ed4ae374ef011b43317007 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/davinci-mcbsp.txt @@ -0,0 +1,50 @@ +Texas Instruments DaVinci McBSP module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This binding describes the "Multi-channel Buffered Serial Port" (McBSP) +audio interface found in some TI DaVinci processors like the OMAP-L138 or AM180x. + + +Required properties: +~~~~~~~~~~~~~~~~~~~~ +- compatible : + "ti,da850-mcbsp" : for DA850, AM180x and OPAM-L138 platforms + +- reg : physical base address and length of the controller memory mapped + region(s). +- reg-names : Should contain: + * "mpu" for the main registers (required). + * "dat" for the data FIFO (optional). + +- dmas: three element list of DMA controller phandles, DMA request line and + TC channel ordered triplets. +- dma-names: identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. The dma + identifiers must be "rx" and "tx". + +Optional properties: +~~~~~~~~~~~~~~~~~~~~ +- interrupts : Interrupt numbers for McBSP +- interrupt-names : Known interrupt names are "rx" and "tx" + +- pinctrl-0: Should specify pin control group used for this controller. +- pinctrl-names: Should contain only one value - "default", for more details + please refer to pinctrl-bindings.txt + +Example (AM1808): +~~~~~~~~~~~~~~~~~ + +mcbsp0: mcbsp@1d10000 { + compatible = "ti,da850-mcbsp"; + pinctrl-names = "default"; + pinctrl-0 = <&mcbsp0_pins>; + + reg = <0x00110000 0x1000>, + <0x00310000 0x1000>; + reg-names = "mpu", "dat"; + interrupts = <97 98>; + interrupt-names = "rx", "tx"; + dmas = <&edma0 3 1 + &edma0 2 1>; + dma-names = "tx", "rx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/designware-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/designware-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..6a536d570e294bb662610b392f5fd4866af18223 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/designware-i2s.txt @@ -0,0 +1,35 @@ +DesignWare I2S controller + +Required properties: + - compatible : Must be "snps,designware-i2s" + - reg : Must contain the I2S core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's + clocks. The controller expects one clock: the clock used as the sampling + rate reference clock sample. + - clock-names : "i2sclk" for the sample rate reference clock. + - dmas: Pairs of phandle and specifier for the DMA channels that are used by + the core. The core expects one or two dma channels: one for transmit and + one for receive. + - dma-names : "tx" for the transmit channel, "rx" for the receive channel. + +Optional properties: + - interrupts: The interrupt line number for the I2S controller. Add this + parameter if the I2S controller that you are using does not support DMA. + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' +properties please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + + soc_i2s: i2s@7ff90000 { + compatible = "snps,designware-i2s"; + reg = <0x0 0x7ff90000 0x0 0x1000>; + clocks = <&scpi_i2sclk 0>; + clock-names = "i2sclk"; + #sound-dai-cells = <0>; + dmas = <&dma0 5>; + dma-names = "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/dmic.txt b/arch/arm64/boot/dts/vendor/bindings/sound/dmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..e957b41367160bf1a01437f74d3b2dd494ebe887 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/dmic.txt @@ -0,0 +1,20 @@ +Device-Tree bindings for Digital microphone (DMIC) codec + +This device support generic PDM digital microphone. + +Required properties: + - compatible: should be "dmic-codec". + +Optional properties: + - dmicen-gpios: GPIO specifier for dmic to control start and stop + - num-channels: Number of microphones on this DAI + - wakeup-delay-ms: Delay (in ms) after enabling the DMIC + +Example node: + + dmic_codec: dmic@0 { + compatible = "dmic-codec"; + dmicen-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + num-channels = <1>; + wakeup-delay-ms <50>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/es8328.txt b/arch/arm64/boot/dts/vendor/bindings/sound/es8328.txt new file mode 100644 index 0000000000000000000000000000000000000000..33fbf058c997c65f5afa899df614e7900f5bfe69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/es8328.txt @@ -0,0 +1,38 @@ +Everest ES8328 audio CODEC + +This device supports both I2C and SPI. + +Required properties: + + - compatible : Should be "everest,es8328" or "everest,es8388" + - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V + - AVDD-supply : Regulator providing analog supply voltage 3.3V + - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V + - IPVDD-supply : Regulator providing analog output voltage 3.3V + - clocks : A 22.5792 or 11.2896 MHz clock + - reg : the I2C address of the device for I2C, the chip select number for SPI + +Pins on the device (for linking into audio routes): + + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * RINPUT1 + * LINPUT2 + * RINPUT2 + * Mic Bias + + +Example: + +codec: es8328@11 { + compatible = "everest,es8328"; + DVDD-supply = <®_3p3v>; + AVDD-supply = <®_3p3v>; + PVDD-supply = <®_3p3v>; + HPVDD-supply = <®_3p3v>; + clocks = <&clks 169>; + reg = <0x11>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/eukrea-tlv320.txt b/arch/arm64/boot/dts/vendor/bindings/sound/eukrea-tlv320.txt new file mode 100644 index 0000000000000000000000000000000000000000..6dfa88c4dc1e8b3aea1e39b79eaa62185e64c240 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/eukrea-tlv320.txt @@ -0,0 +1,26 @@ +Audio complex for Eukrea boards with tlv320aic23 codec. + +Required properties: + + - compatible : "eukrea,asoc-tlv320" + + - eukrea,model : The user-visible name of this sound complex. + + - ssi-controller : The phandle of the SSI controller. + + - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). + + - fsl,mux-ext-port : The external port of the i.MX audio muxer. + +Note: The AUDMUX port numbering should start at 1, which is consistent with +hardware manual. + +Example: + + sound { + compatible = "eukrea,asoc-tlv320"; + eukrea,model = "imx51-eukrea-tlv320aic23"; + ssi-controller = <&ssi2>; + fsl,mux-int-port = <2>; + fsl,mux-ext-port = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/everest,es7134.txt b/arch/arm64/boot/dts/vendor/bindings/sound/everest,es7134.txt new file mode 100644 index 0000000000000000000000000000000000000000..091666069bde1e6d885a05346499fc0e651c7d34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/everest,es7134.txt @@ -0,0 +1,15 @@ +ES7134 i2s DA converter + +Required properties: +- compatible : "everest,es7134" or + "everest,es7144" or + "everest,es7154" +- VDD-supply : regulator phandle for the VDD supply +- PVDD-supply: regulator phandle for the PVDD supply for the es7154 + +Example: + +i2s_codec: external-codec { + compatible = "everest,es7134"; + VDD-supply = <&vcc_5v>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/everest,es7241.txt b/arch/arm64/boot/dts/vendor/bindings/sound/everest,es7241.txt new file mode 100644 index 0000000000000000000000000000000000000000..28f82cf4959f41dae1bace4c00e23c1ebebd838b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/everest,es7241.txt @@ -0,0 +1,28 @@ +ES7241 i2s AD converter + +Required properties: +- compatible : "everest,es7241" +- VDDP-supply: regulator phandle for the VDDA supply +- VDDA-supply: regulator phandle for the VDDP supply +- VDDD-supply: regulator phandle for the VDDD supply + +Optional properties: +- reset-gpios: gpio connected to the reset pin +- m0-gpios : gpio connected to the m0 pin +- m1-gpios : gpio connected to the m1 pin +- everest,sdout-pull-down: + Format used by the serial interface is controlled by pulling + the sdout. If the sdout is pulled down, leftj format is used. + If this property is not provided, sdout is assumed to pulled + up and i2s format is used + +Example: + +linein: audio-codec@2 { + #sound-dai-cells = <0>; + compatible = "everest,es7241"; + VDDA-supply = <&vcc_3v3>; + VDDP-supply = <&vcc_3v3>; + VDDD-supply = <&vcc_3v3>; + reset-gpios = <&gpio GPIOH_42>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/fsl,asrc.txt b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,asrc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d4d9f938689f39b5214a730991ac068aec02f35 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,asrc.txt @@ -0,0 +1,66 @@ +Freescale Asynchronous Sample Rate Converter (ASRC) Controller + +The Asynchronous Sample Rate Converter (ASRC) converts the sampling rate of a +signal associated with an input clock into a signal associated with a different +output clock. The driver currently works as a Front End of DPCM with other Back +Ends Audio controller such as ESAI, SSI and SAI. It has three pairs to support +three substreams within totally 10 channels. + +Required properties: + + - compatible : Contains "fsl,imx35-asrc" or "fsl,imx53-asrc". + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the spdif interrupt. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Contains "rxa", "rxb", "rxc", "txa", "txb" and "txc". + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Contains the following entries + "mem" Peripheral access clock to access registers. + "ipg" Peripheral clock to driver module. + "asrck_<0-f>" Clock sources for input and output clock. + "spba" The spba clock is required when ASRC is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. + + - fsl,asrc-rate : Defines a mutual sample rate used by DPCM Back Ends. + + - fsl,asrc-width : Defines a mutual sample width used by DPCM Back Ends. + +Optional properties: + + - big-endian : If this property is absent, the little endian mode + will be in use as default. Otherwise, the big endian + mode will be in use for all the device registers. + +Example: + +asrc: asrc@2034000 { + compatible = "fsl,imx53-asrc"; + reg = <0x02034000 0x4000>; + interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clks 107>, <&clks 107>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 0>, <&clks 0>, <&clks 0>, <&clks 0>, + <&clks 107>, <&clks 0>, <&clks 0>; + clock-names = "mem", "ipg", "asrck0", + "asrck_1", "asrck_2", "asrck_3", "asrck_4", + "asrck_5", "asrck_6", "asrck_7", "asrck_8", + "asrck_9", "asrck_a", "asrck_b", "asrck_c", + "asrck_d", "asrck_e", "asrck_f"; + dmas = <&sdma 17 23 1>, <&sdma 18 23 1>, <&sdma 19 23 1>, + <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; + dma-names = "rxa", "rxb", "rxc", + "txa", "txb", "txc"; + fsl,asrc-rate = <48000>; + fsl,asrc-width = <16>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/fsl,esai.txt b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,esai.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b9914367610315d8aaab3a614dd318de9408c6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,esai.txt @@ -0,0 +1,64 @@ +Freescale Enhanced Serial Audio Interface (ESAI) Controller + +The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port +for serial communication with a variety of serial devices, including industry +standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and +other DSPs. It has up to six transmitters and four receivers. + +Required properties: + + - compatible : Compatible list, must contain "fsl,imx35-esai" or + "fsl,vf610-esai" + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the spdif interrupt. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Two dmas have to be defined, "tx" and "rx". + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "core" The core clock used to access registers + "extal" The esai baud clock for esai controller used to + derive HCK, SCK and FS. + "fsys" The system clock derived from ahb clock used to + derive HCK, SCK and FS. + "spba" The spba clock is required when ESAI is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. + + - fsl,fifo-depth : The number of elements in the transmit and receive + FIFOs. This number is the maximum allowed value for + TFCR[TFWM] or RFCR[RFWM]. + + - fsl,esai-synchronous: This is a boolean property. If present, indicating + that ESAI would work in the synchronous mode, which + means all the settings for Receiving would be + duplicated from Transmition related registers. + +Optional properties: + + - big-endian : If this property is absent, the native endian mode + will be in use as default, or the big endian mode + will be in use for all the device registers. + +Example: + +esai: esai@2024000 { + compatible = "fsl,imx35-esai"; + reg = <0x02024000 0x4000>; + interrupts = <0 51 0x04>; + clocks = <&clks 208>, <&clks 118>, <&clks 208>; + clock-names = "core", "extal", "fsys"; + dmas = <&sdma 23 21 0>, <&sdma 24 21 0>; + dma-names = "rx", "tx"; + fsl,fifo-depth = <128>; + fsl,esai-synchronous; + big-endian; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/fsl,spdif.txt b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,spdif.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b324f82a7828013c06a1688c80c7316558c47ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,spdif.txt @@ -0,0 +1,64 @@ +Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller + +The Freescale S/PDIF audio block is a stereo transceiver that allows the +processor to receive and transmit digital audio via an coaxial cable or +a fibre cable. + +Required properties: + + - compatible : Compatible list, must contain "fsl,imx35-spdif". + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the spdif interrupt. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Two dmas have to be defined, "tx" and "rx". + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "core" The core clock of spdif controller. + "rxtx<0-7>" Clock source list for tx and rx clock. + This clock list should be identical to the source + list connecting to the spdif clock mux in "SPDIF + Transceiver Clock Diagram" of SoC reference manual. + It can also be referred to TxClk_Source bit of + register SPDIF_STC. + "spba" The spba clock is required when SPDIF is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. + +Optional properties: + + - big-endian : If this property is absent, the native endian mode + will be in use as default, or the big endian mode + will be in use for all the device registers. + +Example: + +spdif: spdif@2004000 { + compatible = "fsl,imx35-spdif"; + reg = <0x02004000 0x4000>; + interrupts = <0 52 0x04>; + dmas = <&sdma 14 18 0>, + <&sdma 15 18 0>; + dma-names = "rx", "tx"; + + clocks = <&clks 197>, <&clks 3>, + <&clks 197>, <&clks 107>, + <&clks 0>, <&clks 118>, + <&clks 62>, <&clks 139>, + <&clks 0>; + clock-names = "core", "rxtx0", + "rxtx1", "rxtx2", + "rxtx3", "rxtx4", + "rxtx5", "rxtx6", + "rxtx7"; + + big-endian; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/fsl,ssi.txt b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,ssi.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e15a85cecd2872042272e2f9b48007ca893ac75 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/fsl,ssi.txt @@ -0,0 +1,87 @@ +Freescale Synchronous Serial Interface + +The SSI is a serial device that communicates with audio codecs. It can +be programmed in AC97, I2S, left-justified, or right-justified modes. + +Required properties: +- compatible: Compatible list, should contain one of the following + compatibles: + fsl,mpc8610-ssi + fsl,imx51-ssi + fsl,imx35-ssi + fsl,imx21-ssi +- cell-index: The SSI, <0> = SSI1, <1> = SSI2, and so on. +- reg: Offset and length of the register set for the device. +- interrupts: where a is the interrupt number and b is a + field that represents an encoding of the sense and + level information for the interrupt. This should be + encoded based on the information in section 2) + depending on the type of interrupt controller you + have. +- fsl,fifo-depth: The number of elements in the transmit and receive FIFOs. + This number is the maximum allowed value for SFCSR[TFWM0]. + - clocks: "ipg" - Required clock for the SSI unit + "baud" - Required clock for SSI master mode. Otherwise this + clock is not used + +Required are also ac97 link bindings if ac97 is used. See +Documentation/devicetree/bindings/sound/soc-ac97link.txt for the necessary +bindings. + +Optional properties: +- codec-handle: Phandle to a 'codec' node that defines an audio + codec connected to this SSI. This node is typically + a child of an I2C or other control node. +- fsl,fiq-stream-filter: Bool property. Disabled DMA and use FIQ instead to + filter the codec stream. This is necessary for some boards + where an incompatible codec is connected to this SSI, e.g. + on pca100 and pcm043. +- dmas: Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. +- dma-names: Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq + is not defined. +- fsl,mode: The operating mode for the AC97 interface only. + "ac97-slave" - AC97 mode, SSI is clock slave + "ac97-master" - AC97 mode, SSI is clock master +- fsl,ssi-asynchronous: + If specified, the SSI is to be programmed in asynchronous + mode. In this mode, pins SRCK, STCK, SRFS, and STFS must + all be connected to valid signals. In synchronous mode, + SRCK and SRFS are ignored. Asynchronous mode allows + playback and capture to use different sample sizes and + sample rates. Some drivers may require that SRCK and STCK + be connected together, and SRFS and STFS be connected + together. This would still allow different sample sizes, + but not different sample rates. +- fsl,playback-dma: Phandle to a node for the DMA channel to use for + playback of audio. This is typically dictated by SOC + design. See the notes below. + Only used on Power Architecture. +- fsl,capture-dma: Phandle to a node for the DMA channel to use for + capture (recording) of audio. This is typically dictated + by SOC design. See the notes below. + Only used on Power Architecture. + +Child 'codec' node required properties: +- compatible: Compatible list, contains the name of the codec + +Child 'codec' node optional properties: +- clock-frequency: The frequency of the input clock, which typically comes + from an on-board dedicated oscillator. + +Notes on fsl,playback-dma and fsl,capture-dma: + +On SOCs that have an SSI, specific DMA channels are hard-wired for playback +and capture. On the MPC8610, for example, SSI1 must use DMA channel 0 for +playback and DMA channel 1 for capture. SSI2 must use DMA channel 2 for +playback and DMA channel 3 for capture. The developer can choose which +DMA controller to use, but the channels themselves are hard-wired. The +purpose of these two properties is to represent this hardware design. + +The device tree nodes for the DMA channels that are referenced by +"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with +"fsl,ssi-dma-channel". The SOC-specific compatible string (e.g. +"fsl,mpc8610-dma-channel") can remain. If these nodes are left as +"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA +drivers (fsldma) will attempt to use them, and it will conflict with the +sound drivers. diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/fsl-asoc-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/fsl-asoc-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..c60a5732d29c15edfcd7e574f292eba802397b41 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/fsl-asoc-card.txt @@ -0,0 +1,94 @@ +Freescale Generic ASoC Sound Card with ASRC support + +The Freescale Generic ASoC Sound Card can be used, ideally, for all Freescale +SoCs connecting with external CODECs. + +The idea of this generic sound card is a bit like ASoC Simple Card. However, +for Freescale SoCs (especially those released in recent years), most of them +have ASRC (Documentation/devicetree/bindings/sound/fsl,asrc.txt) inside. And +this is a specific feature that might be painstakingly controlled and merged +into the Simple Card. + +So having this generic sound card allows all Freescale SoC users to benefit +from the simplification of a new card support and the capability of the wide +sample rates support through ASRC. + +Note: The card is initially designed for those sound cards who use AC'97, I2S + and PCM DAI formats. However, it'll be also possible to support those non + AC'97/I2S/PCM type sound cards, such as S/PDIF audio and HDMI audio, as + long as the driver has been properly upgraded. + + +The compatible list for this generic sound card currently: + "fsl,imx-audio-ac97" + + "fsl,imx-audio-cs42888" + + "fsl,imx-audio-cs427x" + (compatible with CS4271 and CS4272) + + "fsl,imx-audio-wm8962" + + "fsl,imx-audio-sgtl5000" + (compatible with Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt) + + "fsl,imx-audio-wm8960" + +Required properties: + + - compatible : Contains one of entries in the compatible list. + + - model : The user-visible name of this sound complex + + - audio-cpu : The phandle of an CPU DAI controller + + - audio-codec : The phandle of an audio codec + + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. There're a few pre-designed board connectors: + * Line Out Jack + * Line In Jack + * Headphone Jack + * Mic Jack + * Ext Spk + * AMIC (stands for Analog Microphone Jack) + * DMIC (stands for Digital Microphone Jack) + + Note: The "Mic Jack" and "AMIC" are redundant while + coexisting in order to support the old bindings + of wm8962 and sgtl5000. + +Optional properties: + + - audio-asrc : The phandle of ASRC. It can be absent if there's no + need to add ASRC support via DPCM. + +Optional unless SSI is selected as a CPU DAI: + + - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) + + - mux-ext-port : The external port of the i.MX audio muxer + +Example: +sound-cs42888 { + compatible = "fsl,imx-audio-cs42888"; + model = "cs42888-audio"; + audio-cpu = <&esai>; + audio-asrc = <&asrc>; + audio-codec = <&cs42888>; + audio-routing = + "Line Out Jack", "AOUT1L", + "Line Out Jack", "AOUT1R", + "Line Out Jack", "AOUT2L", + "Line Out Jack", "AOUT2R", + "Line Out Jack", "AOUT3L", + "Line Out Jack", "AOUT3R", + "Line Out Jack", "AOUT4L", + "Line Out Jack", "AOUT4R", + "AIN1L", "Line In Jack", + "AIN1R", "Line In Jack", + "AIN2L", "Line In Jack", + "AIN2R", "Line In Jack"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/fsl-sai.txt b/arch/arm64/boot/dts/vendor/bindings/sound/fsl-sai.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd9e59738e0820b4db57b737e34a37c11c90fd55 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/fsl-sai.txt @@ -0,0 +1,80 @@ +Freescale Synchronous Audio Interface (SAI). + +The SAI is based on I2S module that used communicating with audio codecs, +which provides a synchronous audio interface that supports fullduplex +serial interfaces with frame synchronization such as I2S, AC97, TDM, and +codec/DSP interfaces. + +Required properties: + + - compatible : Compatible list, contains "fsl,vf610-sai", + "fsl,imx6sx-sai" or "fsl,imx6ul-sai" + + - reg : Offset and length of the register set for the device. + + - clocks : Must contain an entry for each entry in clock-names. + + - clock-names : Must include the "bus" for register access and + "mclk1", "mclk2", "mclk3" for bit clock and frame + clock providing. + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Two dmas have to be defined, "tx" and "rx". + + - pinctrl-names : Must contain a "default" entry. + + - pinctrl-NNN : One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. + + - lsb-first : Configures whether the LSB or the MSB is transmitted + first for the fifo data. If this property is absent, + the MSB is transmitted first as default, or the LSB + is transmitted first. + + - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating + that SAI will work in the synchronous mode (sync Tx + with Rx) which means both the transimitter and the + receiver will send and receive data by following + receiver's bit clocks and frame sync clocks. + + - fsl,sai-asynchronous: This is a boolean property. If present, indicating + that SAI will work in the asynchronous mode, which + means both transimitter and receiver will send and + receive data by following their own bit clocks and + frame sync clocks separately. + +Optional properties: + + - big-endian : Boolean property, required if all the SAI + registers are big-endian rather than little-endian. + +Optional properties (for mx6ul): + + - fsl,sai-mclk-direction-output: This is a boolean property. If present, + indicates that SAI will output the SAI MCLK clock. + +Note: +- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the + default synchronous mode (sync Rx with Tx) will be used, which means both + transimitter and receiver will send and receive data by following clocks + of transimitter. +- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive. + +Example: +sai2: sai@40031000 { + compatible = "fsl,vf610-sai"; + reg = <0x40031000 0x1000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai2_1>; + clocks = <&clks VF610_CLK_PLATFORM_BUS>, + <&clks VF610_CLK_SAI2>, + <&clks 0>, <&clks 0>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dma-names = "tx", "rx"; + dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>, + <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>; + big-endian; + lsb-first; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/gtm601.txt b/arch/arm64/boot/dts/vendor/bindings/sound/gtm601.txt new file mode 100644 index 0000000000000000000000000000000000000000..5efc8c068de0d270f1013b0a25b795b3b94ce281 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/gtm601.txt @@ -0,0 +1,13 @@ +GTM601 UMTS modem audio interface CODEC + +This device has no configuration interface. Sample rate is fixed - 8kHz. + +Required properties: + + - compatible : "option,gtm601" + +Example: + +codec: gtm601_codec { + compatible = "option,gtm601"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/hdmi.txt b/arch/arm64/boot/dts/vendor/bindings/sound/hdmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..56407c30e954d507423500900908b1f0b9764f23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/hdmi.txt @@ -0,0 +1,16 @@ +Device-Tree bindings for dummy HDMI codec + +Required properties: + - compatible: should be "linux,hdmi-audio". + +CODEC output pins: + * TX + +CODEC input pins: + * RX + +Example node: + + hdmi_audio: hdmi_audio@0 { + compatible = "linux,hdmi-audio"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/hisilicon,hi6210-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/hisilicon,hi6210-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a296784eb37489dbad5ca68fb2cf9217e69080d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/hisilicon,hi6210-i2s.txt @@ -0,0 +1,42 @@ +* Hisilicon 6210 i2s controller + +Required properties: + +- compatible: should be one of the following: + - "hisilicon,hi6210-i2s" +- reg: physical base address of the i2s controller unit and length of + memory mapped region. +- interrupts: should contain the i2s interrupt. +- clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. +- clock-names: should contain following: + - "dacodec" + - "i2s-base" +- dmas: DMA specifiers for tx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should be "tx" and "rx" +- hisilicon,sysctrl-syscon: phandle to sysctrl syscon +- #sound-dai-cells: Should be set to 1 (for multi-dai) + - The dai cell indexes reference the following interfaces: + 0: S2 interface + (Currently that is the only one available, but more may be + supported in the future) + +Example for the hi6210 i2s controller: + +i2s0: i2s@f7118000{ + compatible = "hisilicon,hi6210-i2s"; + reg = <0x0 0xf7118000 0x0 0x8000>; /* i2s unit */ + interrupts = ; /* 155 "DigACodec_intr"-32 */ + clocks = <&sys_ctrl HI6220_DACODEC_PCLK>, + <&sys_ctrl HI6220_BBPPLL0_DIV>; + clock-names = "dacodec", "i2s-base"; + dmas = <&dma0 15 &dma0 14>; + dma-names = "rx", "tx"; + hisilicon,sysctrl-syscon = <&sys_ctrl>; + #sound-dai-cells = <1>; +}; + +Then when referencing the i2s controller: + sound-dai = <&i2s0 0>; /* index 0 => S2 interface */ + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ics43432.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ics43432.txt new file mode 100644 index 0000000000000000000000000000000000000000..b02e3a6c0fef978d4d3fbfadc2a61e402423432d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ics43432.txt @@ -0,0 +1,17 @@ +Invensense ICS-43432 MEMS microphone with I2S output. + +There are no software configuration options for this device, indeed, the only +host connection is the I2S interface. Apart from requirements on clock +frequency (460 kHz to 3.379 MHz according to the data sheet) there must be +64 clock cycles in each stereo output frame; 24 of the 32 available bits +contain audio data. A hardware pin determines if the device outputs data +on the left or right channel of the I2S frame. + +Required properties: + - compatible : Must be "invensense,ics43432" + +Example: + + ics43432: ics43432 { + compatible = "invensense,ics43432"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/img,i2s-in.txt b/arch/arm64/boot/dts/vendor/bindings/sound/img,i2s-in.txt new file mode 100644 index 0000000000000000000000000000000000000000..423265cfc3d6ae8b750427f16f25c7dcad7db780 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/img,i2s-in.txt @@ -0,0 +1,47 @@ +Imagination Technologies I2S Input Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,i2s-in" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Must include the following entry: + "sys" The system clock + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "rx" Single DMA channel used by all active I2S channels + + - img,i2s-channels : Number of I2S channels instantiated in the I2S in block + +Optional Properties: + + - interrupts : Contains the I2S in interrupts. Depending on + the configuration, there may be no interrupts, one interrupt, + or an interrupt per I2S channel. For the case where there is + one interrupt per channel, the interrupts should be listed + in ascending channel order + + - resets: Contains a phandle to the I2S in reset signal + + - reset-names: Contains the reset signal name "rst" + +Example: + +i2s_in: i2s-in@18100800 { + compatible = "img,i2s-in"; + reg = <0x18100800 0x200>; + interrupts = ; + dmas = <&mdc 30 0xffffffff 0>; + dma-names = "rx"; + clocks = <&cr_periph SYS_CLK_I2S_IN>; + clock-names = "sys"; + img,i2s-channels = <6>; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/img,i2s-out.txt b/arch/arm64/boot/dts/vendor/bindings/sound/img,i2s-out.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b0ee9b7e11b907182ff642179a3131ce9c4c164 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/img,i2s-out.txt @@ -0,0 +1,51 @@ +Imagination Technologies I2S Output Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,i2s-out" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Must include the following entries: + "sys" The system clock + "ref" The reference clock + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "tx" Single DMA channel used by all active I2S channels + + - img,i2s-channels : Number of I2S channels instantiated in the I2S out block + + - resets: Contains a phandle to the I2S out reset signal + + - reset-names: Contains the reset signal name "rst" + +Optional Properties: + + - interrupts : Contains the I2S out interrupts. Depending on + the configuration, there may be no interrupts, one interrupt, + or an interrupt per I2S channel. For the case where there is + one interrupt per channel, the interrupts should be listed + in ascending channel order + +Example: + +i2s_out: i2s-out@18100a00 { + compatible = "img,i2s-out"; + reg = <0x18100A00 0x200>; + interrupts = ; + dmas = <&mdc 23 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_I2S_OUT>, + <&clk_core CLK_I2S>; + clock-names = "sys", "ref"; + img,i2s-channels = <6>; + resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/img,parallel-out.txt b/arch/arm64/boot/dts/vendor/bindings/sound/img,parallel-out.txt new file mode 100644 index 0000000000000000000000000000000000000000..37a3f94cc126cf194b2a6db10b07cd9e1546201f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/img,parallel-out.txt @@ -0,0 +1,44 @@ +Imagination Technologies Parallel Output Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,parallel-out". + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device. + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "tx" + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "sys" The system clock + "ref" The reference clock + + - resets: Contains a phandle to the parallel out reset signal + + - reset-names: Contains the reset signal name "rst" + +Optional Properties: + + - interrupts : Contains the parallel out interrupt, if present + +Example: + +parallel_out: parallel-out@18100c00 { + compatible = "img,parallel-out"; + reg = <0x18100C00 0x100>; + interrupts = ; + dmas = <&mdc 16 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_PAUD_OUT>, + <&clk_core CLK_AUDIO_DAC>; + clock-names = "sys", "ref"; + resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/img,pistachio-internal-dac.txt b/arch/arm64/boot/dts/vendor/bindings/sound/img,pistachio-internal-dac.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cc18fc0477ead04c5f7998ffbae718f9696a633 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/img,pistachio-internal-dac.txt @@ -0,0 +1,18 @@ +Pistachio internal DAC DT bindings + +Required properties: + + - compatible: "img,pistachio-internal-dac" + + - img,cr-top : Must contain a phandle to the top level control syscon + node which contains the internal dac control registers + + - VDD-supply : Digital power supply regulator (+1.8V or +3.3V) + +Examples: + +internal_dac: internal-dac { + compatible = "img,pistachio-internal-dac"; + img,cr-top = <&cr_top>; + VDD-supply = <&supply3v3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/img,spdif-in.txt b/arch/arm64/boot/dts/vendor/bindings/sound/img,spdif-in.txt new file mode 100644 index 0000000000000000000000000000000000000000..f7ea8c87bf34683d507c98b93518142f2a7d94b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/img,spdif-in.txt @@ -0,0 +1,41 @@ +Imagination Technologies SPDIF Input Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,spdif-in" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "rx" + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Includes the following entries: + "sys" The system clock + +Optional Properties: + + - resets: Should contain a phandle to the spdif in reset signal, if any + + - reset-names: Should contain the reset signal name "rst", if a + reset phandle is given + + - interrupts : Contains the spdif in interrupt, if present + +Example: + +spdif_in: spdif-in@18100e00 { + compatible = "img,spdif-in"; + reg = <0x18100E00 0x100>; + interrupts = ; + dmas = <&mdc 15 0xffffffff 0>; + dma-names = "rx"; + clocks = <&cr_periph SYS_CLK_SPDIF_IN>; + clock-names = "sys"; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/img,spdif-out.txt b/arch/arm64/boot/dts/vendor/bindings/sound/img,spdif-out.txt new file mode 100644 index 0000000000000000000000000000000000000000..413ed8b0187021c3c930e0cca2a1b67ffc23dd47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/img,spdif-out.txt @@ -0,0 +1,44 @@ +Imagination Technologies SPDIF Output Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,spdif-out" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "tx" + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "sys" The system clock + "ref" The reference clock + + - resets: Contains a phandle to the spdif out reset signal + + - reset-names: Contains the reset signal name "rst" + +Optional Properties: + + - interrupts : Contains the parallel out interrupt, if present + +Example: + +spdif_out: spdif-out@18100d00 { + compatible = "img,spdif-out"; + reg = <0x18100D00 0x100>; + interrupts = ; + dmas = <&mdc 14 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_SPDIF_OUT>, + <&clk_core CLK_SPDIF>; + clock-names = "sys", "ref"; + resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-es8328.txt b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-es8328.txt new file mode 100644 index 0000000000000000000000000000000000000000..07b68ab206fbcf6499cce26e2b9e2b642836cebc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-es8328.txt @@ -0,0 +1,60 @@ +Freescale i.MX audio complex with ES8328 codec + +Required properties: +- compatible : "fsl,imx-audio-es8328" +- model : The user-visible name of this sound complex +- ssi-controller : The phandle of the i.MX SSI controller +- jack-gpio : Optional GPIO for headphone jack +- audio-amp-supply : Power regulator for speaker amps +- audio-codec : The phandle of the ES8328 audio codec +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, ES8328 + pins, and the jacks on the board: + + Power supplies: + * audio-amp + + ES8328 pins: + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * LINPUT2 + * RINPUT1 + * RINPUT2 + * Mic PGA + + Board connectors: + * Headphone + * Speaker + * Mic Jack +- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) +- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX) + +Note: The AUDMUX port numbering should start at 1, which is consistent with +hardware manual. + +Example: + +sound { + compatible = "fsl,imx-audio-es8328"; + model = "imx-audio-es8328"; + ssi-controller = <&ssi1>; + audio-codec = <&codec>; + jack-gpio = <&gpio5 15 0>; + audio-amp-supply = <®_audio_amp>; + audio-routing = + "Speaker", "LOUT2", + "Speaker", "ROUT2", + "Speaker", "audio-amp", + "Headphone", "ROUT1", + "Headphone", "LOUT1", + "LINPUT1", "Mic Jack", + "RINPUT1", "Mic Jack", + "Mic Jack", "Mic Bias"; + mux-int-port = <1>; + mux-ext-port = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-sgtl5000.txt b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-sgtl5000.txt new file mode 100644 index 0000000000000000000000000000000000000000..2f89db88fd57c7f121bdaeb4244b4e525578fc9e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-sgtl5000.txt @@ -0,0 +1,56 @@ +Freescale i.MX audio complex with SGTL5000 codec + +Required properties: + + - compatible : "fsl,imx-audio-sgtl5000" + + - model : The user-visible name of this sound complex + + - ssi-controller : The phandle of the i.MX SSI controller + + - audio-codec : The phandle of the SGTL5000 audio codec + + - audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk + + - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) + + - mux-ext-port : The external port of the i.MX audio muxer + +Note: The AUDMUX port numbering should start at 1, which is consistent with +hardware manual. + +Example: + +sound { + compatible = "fsl,imx51-babbage-sgtl5000", + "fsl,imx-audio-sgtl5000"; + model = "imx51-babbage-sgtl5000"; + ssi-controller = <&ssi1>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; + mux-int-port = <1>; + mux-ext-port = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-spdif.txt b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-spdif.txt new file mode 100644 index 0000000000000000000000000000000000000000..da84a442ccea52d9d276fa8a50cefbbc4acfe0cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audio-spdif.txt @@ -0,0 +1,36 @@ +Freescale i.MX audio complex with S/PDIF transceiver + +Required properties: + + - compatible : "fsl,imx-audio-spdif" + + - model : The user-visible name of this sound complex + + - spdif-controller : The phandle of the i.MX S/PDIF controller + + +Optional properties: + + - spdif-out : This is a boolean property. If present, the + transmitting function of S/PDIF will be enabled, + indicating there's a physical S/PDIF out connector + or jack on the board or it's connecting to some + other IP block, such as an HDMI encoder or + display-controller. + + - spdif-in : This is a boolean property. If present, the receiving + function of S/PDIF will be enabled, indicating there + is a physical S/PDIF in connector/jack on the board. + +* Note: At least one of these two properties should be set in the DT binding. + + +Example: + +sound-spdif { + compatible = "fsl,imx-audio-spdif"; + model = "imx-spdif"; + spdif-controller = <&spdif>; + spdif-out; + spdif-in; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/imx-audmux.txt b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audmux.txt new file mode 100644 index 0000000000000000000000000000000000000000..2db4dcbee1b928fabffc9c03531d9fd846be423c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/imx-audmux.txt @@ -0,0 +1,28 @@ +Freescale Digital Audio Mux (AUDMUX) device + +Required properties: + + - compatible : "fsl,imx21-audmux" for AUDMUX version firstly used + on i.MX21, or "fsl,imx31-audmux" for the version + firstly used on i.MX31. + + - reg : Should contain AUDMUX registers location and length. + +An initial configuration can be setup using child nodes. + +Required properties of optional child nodes: + + - fsl,audmux-port : Integer of the audmux port that is configured by this + child node. + + - fsl,port-config : List of configuration options for the specific port. + For imx31-audmux and above, it is a list of tuples + . For imx21-audmux it is a list of pcr + values. + +Example: + +audmux@21d8000 { + compatible = "fsl,imx6q-audmux", "fsl,imx31-audmux"; + reg = <0x021d8000 0x4000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ingenic,jz4740-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ingenic,jz4740-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..b623d50004fb016195d865179ce71b378c8fc98c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ingenic,jz4740-i2s.txt @@ -0,0 +1,23 @@ +Ingenic JZ4740 I2S controller + +Required properties: +- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s" +- reg : I2S registers location and length +- clocks : AIC and I2S PLL clock specifiers. +- clock-names: "aic" and "i2s" +- dmas: DMA controller phandle and DMA request line for I2S Tx and Rx channels +- dma-names: Must be "tx" and "rx" + +Example: + +i2s: i2s@10020000 { + compatible = "ingenic,jz4740-i2s"; + reg = <0x10020000 0x94>; + + clocks = <&cgu JZ4740_CLK_AIC>, <&cgu JZ4740_CLK_I2SPLL>; + clock-names = "aic", "i2s"; + + dmas = <&dma 2>, <&dma 3>; + dma-names = "tx", "rx"; + +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/inno-rk3036.txt b/arch/arm64/boot/dts/vendor/bindings/sound/inno-rk3036.txt new file mode 100644 index 0000000000000000000000000000000000000000..758de8e27561f2e534c195976ec13e75e2e2a7c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/inno-rk3036.txt @@ -0,0 +1,20 @@ +Inno audio codec for RK3036 + +Inno audio codec is integrated inside RK3036 SoC. + +Required properties: +- compatible : Should be "rockchip,rk3036-codec". +- reg : The registers of codec. +- clock-names : Should be "acodec_pclk". +- clocks : The clock of codec. +- rockchip,grf : The phandle of grf device node. + +Example: + + acodec: acodec-ana@20030000 { + compatible = "rk3036-codec"; + reg = <0x20030000 0x4000>; + rockchip,grf = <&grf>; + clock-names = "acodec_pclk"; + clocks = <&cru ACLK_VCODEC>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/marvell,pxa2xx-ac97.txt b/arch/arm64/boot/dts/vendor/bindings/sound/marvell,pxa2xx-ac97.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ea85d5be6a43bb1d1779d0094df14adb0f2f43f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/marvell,pxa2xx-ac97.txt @@ -0,0 +1,27 @@ +Marvell PXA2xx audio complex + +This descriptions matches the AC97 controller found in pxa2xx and pxa3xx series. + +Required properties: + - compatible: should be one of the following: + "marvell,pxa250-ac97" + "marvell,pxa270-ac97" + "marvell,pxa300-ac97" + - reg: device MMIO address space + - interrupts: single interrupt generated by AC97 IP + - clocks: input clock of the AC97 IP, refer to clock-bindings.txt + +Optional properties: + - pinctrl-names, pinctrl-0: refer to pinctrl-bindings.txt + - reset-gpios: gpio used for AC97 reset, refer to gpio.txt + +Example: + ac97: sound@40500000 { + compatible = "marvell,pxa250-ac97"; + reg = < 0x40500000 0x1000 >; + interrupts = <14>; + reset-gpios = <&gpio 113 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = < &pmux_ac97_default >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max98090.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max98090.txt new file mode 100644 index 0000000000000000000000000000000000000000..7e1bbd5c27fd061602bd7683a223def6cbcd5b2e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max98090.txt @@ -0,0 +1,59 @@ +MAX98090 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "maxim,max98090" or "maxim,max98091". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC + +- clock-names: Should be "mclk" + +- #sound-dai-cells : should be 0. + +- maxim,dmic-freq: Frequency at which to clock DMIC + +- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are: + 0 - 2.2v + 1 - 2.55v + 2 - 2.4v + 3 - 2.8v + +Pins on the device (for linking into audio routes): + + * MIC1 + * MIC2 + * DMICL + * DMICR + * IN1 + * IN2 + * IN3 + * IN4 + * IN5 + * IN6 + * IN12 + * IN34 + * IN56 + * HPL + * HPR + * SPKL + * SPKR + * RCVL + * RCVR + * MICBIAS + +Example: + +audio-codec@10 { + compatible = "maxim,max98090"; + reg = <0x10>; + interrupt-parent = <&gpio>; + interrupts = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max98095.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max98095.txt new file mode 100644 index 0000000000000000000000000000000000000000..318a4c82f17f8781d3e18a4cc110ade66cd8386b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max98095.txt @@ -0,0 +1,22 @@ +MAX98095 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "maxim,max98095". + +- reg : The I2C address of the device. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC + +- clock-names: Should be "mclk" + +Example: + +max98095: codec@11 { + compatible = "maxim,max98095"; + reg = <0x11>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max98357a.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max98357a.txt new file mode 100644 index 0000000000000000000000000000000000000000..28645a2ff885e029de228ce9a599b21ff0ef9461 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max98357a.txt @@ -0,0 +1,18 @@ +Maxim MAX98357A audio DAC + +This node models the Maxim MAX98357A DAC. + +Required properties: +- compatible : "maxim,max98357a" + +Optional properties: +- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin. + If this option is not specified then driver does not manage + the pin state (e.g. chip is always on). + +Example: + +max98357a { + compatible = "maxim,max98357a"; + sdmode-gpios = <&qcom_pinmux 25 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max98371.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max98371.txt new file mode 100644 index 0000000000000000000000000000000000000000..8b2b2704b574e248c426565514076e2a42aa0631 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max98371.txt @@ -0,0 +1,17 @@ +max98371 codec + +This device supports I2C mode only. + +Required properties: + +- compatible : "maxim,max98371" +- reg : The chip select number on the I2C bus + +Example: + +&i2c { + max98371: max98371@31 { + compatible = "maxim,max98371"; + reg = <0x31>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max98373.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max98373.txt new file mode 100644 index 0000000000000000000000000000000000000000..456cb1c59353d2e5140eaf2a1d35540e485dcdcb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max98373.txt @@ -0,0 +1,40 @@ +Maxim Integrated MAX98373 Speaker Amplifier + +This device supports I2C. + +Required properties: + + - compatible : "maxim,max98373" + + - reg : the I2C address of the device. + +Optional properties: + + - maxim,vmon-slot-no : slot number used to send voltage information + or in inteleave mode this will be used as + interleave slot. + slot range : 0 ~ 15, Default : 0 + + - maxim,imon-slot-no : slot number used to send current information + slot range : 0 ~ 15, Default : 0 + + - maxim,spkfb-slot-no : slot number used to send speaker feedback information + slot range : 0 ~ 15, Default : 0 + + - maxim,interleave-mode : For cases where a single combined channel + for the I/V sense data is not sufficient, the device can also be configured + to share a single data output channel on alternating frames. + In this configuration, the current and voltage data will be frame interleaved + on a single output channel. + Boolean, define to enable the interleave mode, Default : false + +Example: + +codec: max98373@31 { + compatible = "maxim,max98373"; + reg = <0x31>; + maxim,vmon-slot-no = <0>; + maxim,imon-slot-no = <1>; + maxim,spkfb-slot-no = <2>; + maxim,interleave-mode; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max98504.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max98504.txt new file mode 100644 index 0000000000000000000000000000000000000000..583ed5fdfb289042fd4aa44b803a0e535386ee03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max98504.txt @@ -0,0 +1,44 @@ +Maxim MAX98504 class D mono speaker amplifier + +This device supports I2C control interface and an IRQ output signal. It features +a PCM and PDM digital audio interface (DAI) and a differential analog input. + +Required properties: + + - compatible : "maxim,max98504" + - reg : should contain the I2C slave device address + - DVDD-supply, DIOVDD-supply, PVDD-supply: power supplies for the device, + as covered in ../regulator/regulator.txt + - interrupts : should specify the interrupt line the device is connected to, + as described in ../interrupt-controller/interrupts.txt + +Optional properties: + + - maxim,brownout-threshold - the PVDD brownout threshold, the value must be + from 0, 1...21 range, corresponding to 2.6V, 2.65V...3.65V voltage range + - maxim,brownout-attenuation - the brownout attenuation to the speaker gain + applied during the "attack hold" and "timed hold" phase, the value must be + from 0...6 (dB) range + - maxim,brownout-attack-hold-ms - the brownout attack hold phase time in ms, + 0...255 (VBATBROWN_ATTK_HOLD, register 0x0018) + - maxim,brownout-timed-hold-ms - the brownout timed hold phase time in ms, + 0...255 (VBATBROWN_TIME_HOLD, register 0x0019) + - maxim,brownout-release-rate-ms - the brownout release phase step time in ms, + 0...255 (VBATBROWN_RELEASE, register 0x001A) + +The default value when the above properties are not specified is 0, +the maxim,brownout-threshold property must be specified to actually enable +the PVDD brownout protection. + +Example: + + max98504@31 { + compatible = "maxim,max98504"; + reg = <0x31>; + interrupt-parent = <&gpio_bank_0>; + interrupts = <2 0>; + + DVDD-supply = <®ulator>; + DIOVDD-supply = <®ulator>; + PVDD-supply = <®ulator>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max9860.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max9860.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0d4e95e31b33ac9bfc1fcaa85ac72da0481b002 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max9860.txt @@ -0,0 +1,28 @@ +MAX9860 Mono Audio Voice Codec + +Required properties: + + - compatible : "maxim,max9860" + + - reg : the I2C address of the device + + - AVDD-supply, DVDD-supply and DVDDIO-supply : power supplies for + the device, as covered in bindings/regulator/regulator.txt + + - clock-names : Required element: "mclk". + + - clocks : A clock specifier for the clock connected as MCLK. + +Examples: + + max9860: max9860@10 { + compatible = "maxim,max9860"; + reg = <0x10>; + + AVDD-supply = <®_1v8>; + DVDD-supply = <®_1v8>; + DVDDIO-supply = <®_3v0>; + + clock-names = "mclk"; + clocks = <&pck2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max9867.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max9867.txt new file mode 100644 index 0000000000000000000000000000000000000000..b8bd914ee697b1435f0ebb47e4d3062961c61859 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max9867.txt @@ -0,0 +1,17 @@ +max9867 codec + +This device supports I2C mode only. + +Required properties: + +- compatible : "maxim,max9867" +- reg : The chip select number on the I2C bus + +Example: + +&i2c { + max9867: max9867@18 { + compatible = "maxim,max9867"; + reg = <0x18>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/max9892x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/max9892x.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6171591ddc61daa71f2fb58e84aff5c2744297e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/max9892x.txt @@ -0,0 +1,41 @@ +Maxim Integrated MAX98925/MAX98926/MAX98927 Speaker Amplifier + +This device supports I2C. + +Required properties: + + - compatible : should be one of the following + - "maxim,max98925" + - "maxim,max98926" + - "maxim,max98927" + + - vmon-slot-no : slot number used to send voltage information + or in inteleave mode this will be used as + interleave slot. + MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0 + MAX98927 slot range : 0 ~ 15, Default : 0 + + - imon-slot-no : slot number used to send current information + MAX98925/MAX98926 slot range : 0 ~ 30, Default : 0 + MAX98927 slot range : 0 ~ 15, Default : 0 + + - interleave-mode : When using two MAX9892X in a system it is + possible to create ADC data that that will + overflow the frame size. Digital Audio Interleave + mode provides a means to output VMON and IMON data + from two devices on a single DOUT line when running + smaller frames sizes such as 32 BCLKS per LRCLK or + 48 BCLKS per LRCLK. + Range : 0 (off), 1 (on), Default : 0 + + - reg : the I2C address of the device for I2C + +Example: + +codec: max98927@3a { + compatible = "maxim,max98927"; + vmon-slot-no = <0>; + imon-slot-no = <1>; + interleave-mode = <0>; + reg = <0x3a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/maxim,max9759.txt b/arch/arm64/boot/dts/vendor/bindings/sound/maxim,max9759.txt new file mode 100644 index 0000000000000000000000000000000000000000..737a996374d34e47b64a648e24a63bdc3f895424 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/maxim,max9759.txt @@ -0,0 +1,18 @@ +Maxim MAX9759 Speaker Amplifier +=============================== + +Required properties: +- compatible : "maxim,max9759" +- shutdown-gpios : the gpio connected to the shutdown pin +- mute-gpios : the gpio connected to the mute pin +- gain-gpios : the 2 gpios connected to the g1 and g2 pins + +Example: + +max9759: analog-amplifier { + compatible = "maxim,max9759"; + shutdown-gpios = <&gpio3 20 GPIO_ACTIVE_LOW>; + mute-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; + gain-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>, + <&gpio3 25 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mrvl,pxa-ssp.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mrvl,pxa-ssp.txt new file mode 100644 index 0000000000000000000000000000000000000000..feef39b4a4fdb71934961714c1c790f8f1852e32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mrvl,pxa-ssp.txt @@ -0,0 +1,34 @@ +Marvell PXA SSP CPU DAI bindings + +Required properties: + + compatible Must be "mrvl,pxa-ssp-dai" + port A phandle reference to a PXA ssp upstream device + +Optional properties: + + clock-names + clocks Through "clock-names" and "clocks", external clocks + can be configured. If a clock names "extclk" exists, + it will be set to the mclk rate of the audio stream + and be used as clock provider of the DAI. + +Example: + + /* upstream device */ + + ssp1: ssp@41000000 { + compatible = "mrvl,pxa3xx-ssp"; + reg = <0x41000000 0x40>; + interrupts = <24>; + clock-names = "pxa27x-ssp.0"; + }; + + /* DAI as user */ + + ssp_dai0: ssp_dai@0 { + compatible = "mrvl,pxa-ssp-dai"; + port = <&ssp1>; + #sound-dai-cells = <0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-afe-pcm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-afe-pcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..560762e0a1681b37ef1a66750e14474868a137c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-afe-pcm.txt @@ -0,0 +1,146 @@ +Mediatek AFE PCM controller for mt2701 + +Required properties: +- compatible: should be one of the followings. + - "mediatek,mt2701-audio" + - "mediatek,mt7622-audio" +- interrupts: should contain AFE and ASYS interrupts +- interrupt-names: should be "afe" and "asys" +- power-domains: should define the power domain +- clocks: Must contain an entry for each entry in clock-names + See ../clocks/clock-bindings.txt for details +- clock-names: should have these clock names: + "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; +- assigned-clocks: list of input clocks and dividers for the audio system. + See ../clocks/clock-bindings.txt for details. +- assigned-clocks-parents: parent of input clocks of assigned clocks. +- assigned-clock-rates: list of clock frequencies of assigned clocks. + +Must be a subnode of MediaTek audsys device tree node. +See ../arm/mediatek/mediatek,audsys.txt for details about the parent node. + +Example: + + audsys: audio-subsystem@11220000 { + compatible = "mediatek,mt2701-audsys", "syscon"; + ... + + afe: audio-controller { + compatible = "mediatek,mt2701-audio"; + interrupts = , + ; + interrupt-names = "afe", "asys"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_48K_TIMING>, + <&topckgen CLK_TOP_AUD_44K_TIMING>, + <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, + <&topckgen CLK_TOP_AUD_I2S1_MCLK>, + <&topckgen CLK_TOP_AUD_I2S2_MCLK>, + <&topckgen CLK_TOP_AUD_I2S3_MCLK>, + <&topckgen CLK_TOP_AUD_I2S4_MCLK>, + <&audsys CLK_AUD_I2SO1>, + <&audsys CLK_AUD_I2SO2>, + <&audsys CLK_AUD_I2SO3>, + <&audsys CLK_AUD_I2SO4>, + <&audsys CLK_AUD_I2SIN1>, + <&audsys CLK_AUD_I2SIN2>, + <&audsys CLK_AUD_I2SIN3>, + <&audsys CLK_AUD_I2SIN4>, + <&audsys CLK_AUD_ASRCO1>, + <&audsys CLK_AUD_ASRCO2>, + <&audsys CLK_AUD_ASRCO3>, + <&audsys CLK_AUD_ASRCO4>, + <&audsys CLK_AUD_AFE>, + <&audsys CLK_AUD_AFE_CONN>, + <&audsys CLK_AUD_A1SYS>, + <&audsys CLK_AUD_A2SYS>, + <&audsys CLK_AUD_AFE_MRGIF>; + + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; + + assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>; + assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>; + assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-cs42448.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-cs42448.txt new file mode 100644 index 0000000000000000000000000000000000000000..05574446ceb61bb39afdd6338e98be4cddb10393 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-cs42448.txt @@ -0,0 +1,43 @@ +MT2701 with CS42448 CODEC + +Required properties: +- compatible: "mediatek,mt2701-cs42448-machine" +- mediatek,platform: the phandle of MT2701 ASoC platform +- audio-routing: a list of the connections between audio +- mediatek,audio-codec: the phandles of cs42448 codec +- mediatek,audio-codec-bt-mrg the phandles of bt-sco dummy codec +- pinctrl-names: Should contain only one value - "default" +- pinctrl-0: Should specify pin control groups used for this controller. +- i2s1-in-sel-gpio1, i2s1-in-sel-gpio2: Should specify two gpio pins to + control I2S1-in mux. + +Example: + + sound:sound { + compatible = "mediatek,mt2701-cs42448-machine"; + mediatek,platform = <&afe>; + /* CS42448 Machine name */ + audio-routing = + "Line Out Jack", "AOUT1L", + "Line Out Jack", "AOUT1R", + "Line Out Jack", "AOUT2L", + "Line Out Jack", "AOUT2R", + "Line Out Jack", "AOUT3L", + "Line Out Jack", "AOUT3R", + "Line Out Jack", "AOUT4L", + "Line Out Jack", "AOUT4R", + "AIN1L", "AMIC", + "AIN1R", "AMIC", + "AIN2L", "Tuner In", + "AIN2R", "Tuner In", + "AIN3L", "Satellite Tuner In", + "AIN3R", "Satellite Tuner In", + "AIN3L", "AUX In", + "AIN3R", "AUX In"; + mediatek,audio-codec = <&cs42448>; + mediatek,audio-codec-bt-mrg = <&bt_sco_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&aud_pins_default>; + i2s1-in-sel-gpio1 = <&pio 53 0>; + i2s1-in-sel-gpio2 = <&pio 54 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-wm8960.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-wm8960.txt new file mode 100644 index 0000000000000000000000000000000000000000..809b609ea9d0b56e0761305f916bcf8c860e5f90 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt2701-wm8960.txt @@ -0,0 +1,24 @@ +MT2701 with WM8960 CODEC + +Required properties: +- compatible: "mediatek,mt2701-wm8960-machine" +- mediatek,platform: the phandle of MT2701 ASoC platform +- audio-routing: a list of the connections between audio +- mediatek,audio-codec: the phandles of wm8960 codec +- pinctrl-names: Should contain only one value - "default" +- pinctrl-0: Should specify pin control groups used for this controller. + +Example: + + sound:sound { + compatible = "mediatek,mt2701-wm8960-machine"; + mediatek,platform = <&afe>; + audio-routing = + "Headphone", "HP_L", + "Headphone", "HP_R", + "LINPUT1", "AMIC", + "RINPUT1", "AMIC"; + mediatek,audio-codec = <&wm8960>; + pinctrl-names = "default"; + pinctrl-0 = <&aud_pins_default>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt6351.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt6351.txt new file mode 100644 index 0000000000000000000000000000000000000000..7fb2cb99245ed5e966cf915c84f58fec1802f5bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt6351.txt @@ -0,0 +1,16 @@ +Mediatek MT6351 Audio Codec + +The communication between MT6351 and SoC is through Mediatek PMIC wrapper. +For more detail, please visit Mediatek PMIC wrapper documentation. + +Must be a child node of PMIC wrapper. + +Required properties: + +- compatible : "mediatek,mt6351-sound". + +Example: + +mt6351_snd { + compatible = "mediatek,mt6351-sound"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt6797-afe-pcm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt6797-afe-pcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..0ae29de15bfd6419f389a01c79753a6a999dcfa4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt6797-afe-pcm.txt @@ -0,0 +1,42 @@ +Mediatek AFE PCM controller for mt6797 + +Required properties: +- compatible = "mediatek,mt6797-audio"; +- reg: register location and size +- interrupts: should contain AFE interrupt +- power-domains: should define the power domain +- clocks: Must contain an entry for each entry in clock-names +- clock-names: should have these clock names: + "infra_sys_audio_clk", + "infra_sys_audio_26m", + "mtkaif_26m_clk", + "top_mux_audio", + "top_mux_aud_intbus", + "top_sys_pll3_d4", + "top_sys_pll1_d4", + "top_clk26m_clk"; + +Example: + + afe: mt6797-afe-pcm@11220000 { + compatible = "mediatek,mt6797-audio"; + reg = <0 0x11220000 0 0x1000>; + interrupts = ; + power-domains = <&scpsys MT6797_POWER_DOMAIN_AUDIO>; + clocks = <&infrasys CLK_INFRA_AUDIO>, + <&infrasys CLK_INFRA_AUDIO_26M>, + <&infrasys CLK_INFRA_AUDIO_26M_PAD_TOP>, + <&topckgen CLK_TOP_MUX_AUDIO>, + <&topckgen CLK_TOP_MUX_AUD_INTBUS>, + <&topckgen CLK_TOP_SYSPLL3_D4>, + <&topckgen CLK_TOP_SYSPLL1_D4>, + <&clk26m>; + clock-names = "infra_sys_audio_clk", + "infra_sys_audio_26m", + "mtkaif_26m_clk", + "top_mux_audio", + "top_mux_aud_intbus", + "top_sys_pll3_d4", + "top_sys_pll1_d4", + "top_clk26m_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt6797-mt6351.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt6797-mt6351.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d95a8840f196be1cb0e7e314fc482b0e150cb0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt6797-mt6351.txt @@ -0,0 +1,14 @@ +MT6797 with MT6351 CODEC + +Required properties: +- compatible: "mediatek,mt6797-mt6351-sound" +- mediatek,platform: the phandle of MT6797 ASoC platform +- mediatek,audio-codec: the phandles of MT6351 codec + +Example: + + sound { + compatible = "mediatek,mt6797-mt6351-sound"; + mediatek,audio-codec = <&mt6351_snd>; + mediatek,platform = <&afe>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-max98090.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-max98090.txt new file mode 100644 index 0000000000000000000000000000000000000000..519e97c8f1b8c2029c30785cc39a97ae317e9e64 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-max98090.txt @@ -0,0 +1,15 @@ +MT8173 with MAX98090 CODEC + +Required properties: +- compatible : "mediatek,mt8173-max98090" +- mediatek,audio-codec: the phandle of the MAX98090 audio codec +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-max98090"; + mediatek,audio-codec = <&max98090>; + mediatek,platform = <&afe>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650-rt5514.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650-rt5514.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8b3c80c6fffd1b2dcc94070e49762170f13120e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650-rt5514.txt @@ -0,0 +1,15 @@ +MT8173 with RT5650 RT5514 CODECS + +Required properties: +- compatible : "mediatek,mt8173-rt5650-rt5514" +- mediatek,audio-codec: the phandles of rt5650 and rt5514 codecs +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650-rt5514"; + mediatek,audio-codec = <&rt5650 &rt5514>; + mediatek,platform = <&afe>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650-rt5676.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650-rt5676.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac28cdb4910efbf29500b9040492ba3827115b86 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650-rt5676.txt @@ -0,0 +1,16 @@ +MT8173 with RT5650 RT5676 CODECS and HDMI via I2S + +Required properties: +- compatible : "mediatek,mt8173-rt5650-rt5676" +- mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs + and of the hdmi encoder node +- mediatek,platform: the phandle of MT8173 ASoC platform + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650-rt5676"; + mediatek,audio-codec = <&rt5650 &rt5676 &hdmi0>; + mediatek,platform = <&afe>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650.txt new file mode 100644 index 0000000000000000000000000000000000000000..29dce2ac8773a9e57387647d23bfbca4bfe2709e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mt8173-rt5650.txt @@ -0,0 +1,31 @@ +MT8173 with RT5650 CODECS and HDMI via I2S + +Required properties: +- compatible : "mediatek,mt8173-rt5650" +- mediatek,audio-codec: the phandles of rt5650 codecs + and of the hdmi encoder node +- mediatek,platform: the phandle of MT8173 ASoC platform + +Optional subnodes: +- codec-capture : the subnode of rt5650 codec capture +Required codec-capture subnode properties: +- sound-dai: audio codec dai name on capture path + <&rt5650 0> : Default setting. Connect rt5650 I2S1 for capture. (dai_name = rt5645-aif1) + <&rt5650 1> : Connect rt5650 I2S2 for capture. (dai_name = rt5645-aif2) + +- mediatek,mclk: the MCLK source + 0 : external oscillator, MCLK = 12.288M + 1 : internal source from mt8173, MCLK = sampling rate*256 + +Example: + + sound { + compatible = "mediatek,mt8173-rt5650"; + mediatek,audio-codec = <&rt5650 &hdmi0>; + mediatek,platform = <&afe>; + mediatek,mclk = <0>; + codec-capture { + sound-dai = <&rt5650 1>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mtk-afe-pcm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mtk-afe-pcm.txt new file mode 100644 index 0000000000000000000000000000000000000000..e302c7f43b959d048f98f705e4dac2a2515458ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mtk-afe-pcm.txt @@ -0,0 +1,45 @@ +Mediatek AFE PCM controller + +Required properties: +- compatible = "mediatek,mt8173-afe-pcm"; +- reg: register location and size +- interrupts: Should contain AFE interrupt +- clock-names: should have these clock names: + "infra_sys_audio_clk", + "top_pdn_audio", + "top_pdn_aud_intbus", + "bck0", + "bck1", + "i2s0_m", + "i2s1_m", + "i2s2_m", + "i2s3_m", + "i2s3_b"; + +Example: + + afe: mt8173-afe-pcm@11220000 { + compatible = "mediatek,mt8173-afe-pcm"; + reg = <0 0x11220000 0 0x1000>; + interrupts = ; + clocks = <&infracfg INFRA_AUDIO>, + <&topckgen TOP_AUDIO_SEL>, + <&topckgen TOP_AUD_INTBUS_SEL>, + <&topckgen TOP_APLL1_DIV0>, + <&topckgen TOP_APLL2_DIV0>, + <&topckgen TOP_I2S0_M_CK_SEL>, + <&topckgen TOP_I2S1_M_CK_SEL>, + <&topckgen TOP_I2S2_M_CK_SEL>, + <&topckgen TOP_I2S3_M_CK_SEL>, + <&topckgen TOP_I2S3_B_CK_SEL>; + clock-names = "infra_sys_audio_clk", + "top_pdn_audio", + "top_pdn_aud_intbus", + "bck0", + "bck1", + "i2s0_m", + "i2s1_m", + "i2s2_m", + "i2s3_m", + "i2s3_b"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mvebu-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mvebu-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..cb8c07c81ce4498e77a94003ae16bfb9ec9b2e5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mvebu-audio.txt @@ -0,0 +1,34 @@ +* mvebu (Kirkwood, Dove, Armada 370) audio controller + +Required properties: + +- compatible: + "marvell,kirkwood-audio" for Kirkwood platforms + "marvell,dove-audio" for Dove platforms + "marvell,armada370-audio" for Armada 370 platforms + +- reg: physical base address of the controller and length of memory mapped + region. + +- interrupts: + with "marvell,kirkwood-audio", the audio interrupt + with "marvell,dove-audio", a list of two interrupts, the first for + the data flow, and the second for errors. + +- clocks: one or two phandles. + The first one is mandatory and defines the internal clock. + The second one is optional and defines an external clock. + +- clock-names: names associated to the clocks: + "internal" for the internal clock + "extclk" for the external clock + +Example: + +i2s1: audio-controller@b4000 { + compatible = "marvell,dove-audio"; + reg = <0xb4000 0x2210>; + interrupts = <21>, <22>; + clocks = <&gate_clk 13>; + clock-names = "internal"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mxs-audio-sgtl5000.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mxs-audio-sgtl5000.txt new file mode 100644 index 0000000000000000000000000000000000000000..4eb980bd02874063e154ecc97379ea8809cf2c78 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mxs-audio-sgtl5000.txt @@ -0,0 +1,42 @@ +* Freescale MXS audio complex with SGTL5000 codec + +Required properties: +- compatible : "fsl,mxs-audio-sgtl5000" +- model : The user-visible name of this sound complex +- saif-controllers : The phandle list of the MXS SAIF controller +- audio-codec : The phandle of the SGTL5000 audio codec +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, SGTL5000 + pins, and the jacks on the board: + + Power supplies: + * Mic Bias + + SGTL5000 pins: + * MIC_IN + * LINE_IN + * HP_OUT + * LINE_OUT + + Board connectors: + * Mic Jack + * Line In Jack + * Headphone Jack + * Line Out Jack + * Ext Spk + +Example: + +sound { + compatible = "fsl,imx28-evk-sgtl5000", + "fsl,mxs-audio-sgtl5000"; + model = "imx28-evk-sgtl5000"; + saif-controllers = <&saif0 &saif1>; + audio-codec = <&sgtl5000>; + audio-routing = + "MIC_IN", "Mic Jack", + "Mic Jack", "Mic Bias", + "Headphone Jack", "HP_OUT"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/mxs-saif.txt b/arch/arm64/boot/dts/vendor/bindings/sound/mxs-saif.txt new file mode 100644 index 0000000000000000000000000000000000000000..7ba07a118e370deb7ac43e72fb18b307aa4a33c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/mxs-saif.txt @@ -0,0 +1,41 @@ +* Freescale MXS Serial Audio Interface (SAIF) + +Required properties: +- compatible: Should be "fsl,-saif" +- reg: Should contain registers location and length +- interrupts: Should contain ERROR interrupt number +- dmas: DMA specifier, consisting of a phandle to DMA controller node + and SAIF DMA channel ID. + Refer to dma.txt and fsl-mxs-dma.txt for details. +- dma-names: Must be "rx-tx". + +Optional properties: +- fsl,saif-master: phandle to the master SAIF. It's only required for + the slave SAIF. + +Note: Each SAIF controller should have an alias correctly numbered +in "aliases" node. + +Example: + +aliases { + saif0 = &saif0; + saif1 = &saif1; +}; + +saif0: saif@80042000 { + compatible = "fsl,imx28-saif"; + reg = <0x80042000 2000>; + interrupts = <59>; + dmas = <&dma_apbx 4>; + dma-names = "rx-tx"; +}; + +saif1: saif@80046000 { + compatible = "fsl,imx28-saif"; + reg = <0x80046000 2000>; + interrupts = <58>; + dmas = <&dma_apbx 5>; + dma-names = "rx-tx"; + fsl,saif-master = <&saif0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/name-prefix.txt b/arch/arm64/boot/dts/vendor/bindings/sound/name-prefix.txt new file mode 100644 index 0000000000000000000000000000000000000000..6457759086570626c78c11b6c1675534444a1662 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/name-prefix.txt @@ -0,0 +1,24 @@ +Name prefix: + +Card implementing the routing property define the connection between +audio components as list of string pair. Component using the same +sink/source names may use the name prefix property to prepend the +name of their sinks/sources with the provided string. + +Optional name prefix property: +- sound-name-prefix : string using as prefix for the sink/source names of + the component. + +Example: Two instances of the same component. + +amp0: analog-amplifier@0 { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio GPIOH_3 0>; + sound-name-prefix = "FRONT"; +}; + +amp1: analog-amplifier@1 { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio GPIOH_4 0>; + sound-name-prefix = "BACK"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nau8540.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nau8540.txt new file mode 100644 index 0000000000000000000000000000000000000000..307a765283208ef441c8be17a6e9efe5d00bc805 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nau8540.txt @@ -0,0 +1,16 @@ +NAU85L40 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "nuvoton,nau8540" + + - reg : the I2C address of the device. + +Example: + +codec: nau8540@1c { + compatible = "nuvoton,nau8540"; + reg = <0x1c>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nau8810.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nau8810.txt new file mode 100644 index 0000000000000000000000000000000000000000..05830e477acd7846fd2c6be4de7b11a4a51e22d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nau8810.txt @@ -0,0 +1,16 @@ +NAU8810 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "nuvoton,nau8810" + + - reg : the I2C address of the device. + +Example: + +codec: nau8810@1a { + compatible = "nuvoton,nau8810"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nau8824.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nau8824.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0058b97e49a48240dee993beca7ae27ea994f8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nau8824.txt @@ -0,0 +1,88 @@ +Nuvoton NAU8824 audio codec + +This device supports I2C only. + +Required properties: + - compatible : Must be "nuvoton,nau8824" + + - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1). + +Optional properties: + - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low. + + - nuvoton,vref-impedance: VREF Impedance selection + 0 - Open + 1 - 25 kOhm + 2 - 125 kOhm + 3 - 2.5 kOhm + + - nuvoton,micbias-voltage: Micbias voltage level. + 0 - VDDA + 1 - VDDA + 2 - VDDA * 1.1 + 3 - VDDA * 1.2 + 4 - VDDA * 1.3 + 5 - VDDA * 1.4 + 6 - VDDA * 1.53 + 7 - VDDA * 1.53 + + - nuvoton,sar-threshold-num: Number of buttons supported + - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as + SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) + where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance. + Refer datasheet section 10.2 for more information about threshold calculation. + + - nuvoton,sar-hysteresis: Button impedance measurement hysteresis. + + - nuvoton,sar-voltage: Reference voltage for button impedance measurement. + 0 - VDDA + 1 - VDDA + 2 - VDDA * 1.1 + 3 - VDDA * 1.2 + 4 - VDDA * 1.3 + 5 - VDDA * 1.4 + 6 - VDDA * 1.53 + 7 - VDDA * 1.53 + + - nuvoton,sar-compare-time: SAR compare time + 0 - 500 ns + 1 - 1 us + 2 - 2 us + 3 - 4 us + + - nuvoton,sar-sampling-time: SAR sampling time + 0 - 2 us + 1 - 4 us + 2 - 8 us + 3 - 16 us + + - nuvoton,short-key-debounce: Button short key press debounce time. + 0 - 30 ms + 1 - 50 ms + 2 - 100 ms + + - nuvoton,jack-eject-debounce: Jack ejection debounce time. + 0 - 0 ms + 1 - 1 ms + 2 - 10 ms + + +Example: + + headset: nau8824@1a { + compatible = "nuvoton,nau8824"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = ; + nuvoton,vref-impedance = <2>; + nuvoton,micbias-voltage = <6>; + // Setup 4 buttons impedance according to Android specification + nuvoton,sar-threshold-num = <4>; + nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>; + nuvoton,sar-hysteresis = <0>; + nuvoton,sar-voltage = <6>; + nuvoton,sar-compare-time = <1>; + nuvoton,sar-sampling-time = <1>; + nuvoton,short-key-debounce = <0>; + nuvoton,jack-eject-debounce = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nau8825.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nau8825.txt new file mode 100644 index 0000000000000000000000000000000000000000..d16d96839bcbf1a9aeb9c11fc5ffb79c25115c43 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nau8825.txt @@ -0,0 +1,105 @@ +Nuvoton NAU8825 audio codec + +This device supports I2C only. + +Required properties: + - compatible : Must be "nuvoton,nau8825" + + - reg : the I2C address of the device. This is either 0x1a (CSB=0) or 0x1b (CSB=1). + +Optional properties: + - nuvoton,jkdet-enable: Enable jack detection via JKDET pin. + - nuvoton,jkdet-pull-enable: Enable JKDET pin pull. If set - pin pull enabled, + otherwise pin in high impedance state. + - nuvoton,jkdet-pull-up: Pull-up JKDET pin. If set then JKDET pin is pull up, otherwise pull down. + - nuvoton,jkdet-polarity: JKDET pin polarity. 0 - active high, 1 - active low. + + - nuvoton,vref-impedance: VREF Impedance selection + 0 - Open + 1 - 25 kOhm + 2 - 125 kOhm + 3 - 2.5 kOhm + + - nuvoton,micbias-voltage: Micbias voltage level. + 0 - VDDA + 1 - VDDA + 2 - VDDA * 1.1 + 3 - VDDA * 1.2 + 4 - VDDA * 1.3 + 5 - VDDA * 1.4 + 6 - VDDA * 1.53 + 7 - VDDA * 1.53 + + - nuvoton,sar-threshold-num: Number of buttons supported + - nuvoton,sar-threshold: Impedance threshold for each button. Array that contains up to 8 buttons configuration. SAR value is calculated as + SAR = 255 * MICBIAS / SAR_VOLTAGE * R / (2000 + R) + where MICBIAS is configured by 'nuvoton,micbias-voltage', SAR_VOLTAGE is configured by 'nuvoton,sar-voltage', R - button impedance. + Refer datasheet section 10.2 for more information about threshold calculation. + + - nuvoton,sar-hysteresis: Button impedance measurement hysteresis. + + - nuvoton,sar-voltage: Reference voltage for button impedance measurement. + 0 - VDDA + 1 - VDDA + 2 - VDDA * 1.1 + 3 - VDDA * 1.2 + 4 - VDDA * 1.3 + 5 - VDDA * 1.4 + 6 - VDDA * 1.53 + 7 - VDDA * 1.53 + + - nuvoton,sar-compare-time: SAR compare time + 0 - 500 ns + 1 - 1 us + 2 - 2 us + 3 - 4 us + + - nuvoton,sar-sampling-time: SAR sampling time + 0 - 2 us + 1 - 4 us + 2 - 8 us + 3 - 16 us + + - nuvoton,short-key-debounce: Button short key press debounce time. + 0 - 30 ms + 1 - 50 ms + 2 - 100 ms + 3 - 30 ms + + - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms + - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms + + - nuvoton,crosstalk-enable: make crosstalk function enable if set. + + - clocks: list of phandle and clock specifier pairs according to common clock bindings for the + clocks described in clock-names + - clock-names: should include "mclk" for the MCLK master clock + +Example: + + headset: nau8825@1a { + compatible = "nuvoton,nau8825"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = ; + nuvoton,jkdet-enable; + nuvoton,jkdet-pull-enable; + nuvoton,jkdet-pull-up; + nuvoton,jkdet-polarity = ; + nuvoton,vref-impedance = <2>; + nuvoton,micbias-voltage = <6>; + // Setup 4 buttons impedance according to Android specification + nuvoton,sar-threshold-num = <4>; + nuvoton,sar-threshold = <0xc 0x1e 0x38 0x60>; + nuvoton,sar-hysteresis = <1>; + nuvoton,sar-voltage = <0>; + nuvoton,sar-compare-time = <0>; + nuvoton,sar-sampling-time = <0>; + nuvoton,short-key-debounce = <2>; + nuvoton,jack-insert-debounce = <7>; + nuvoton,jack-eject-debounce = <7>; + nuvoton,crosstalk-enable; + + clock-names = "mclk"; + clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nokia,rx51.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nokia,rx51.txt new file mode 100644 index 0000000000000000000000000000000000000000..72f93d9962736399983b2c05e471228481507d8a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nokia,rx51.txt @@ -0,0 +1,27 @@ +* Nokia N900 audio setup + +Required properties: +- compatible: Should contain "nokia,n900-audio" +- nokia,cpu-dai: phandle for the McBSP node +- nokia,audio-codec: phandles for the main TLV320AIC3X node and the + auxiliary TLV320AIC3X node (in this order) +- nokia,headphone-amplifier: phandle for the TPA6130A2 node +- tvout-selection-gpios: GPIO for tvout selection +- jack-detection-gpios: GPIO for jack detection +- eci-switch-gpios: GPIO for ECI (Enhancement Control Interface) switch +- speaker-amplifier-gpios: GPIO for speaker amplifier + +Example: + +sound { + compatible = "nokia,n900-audio"; + + nokia,cpu-dai = <&mcbsp2>; + nokia,audio-codec = <&tlv320aic3x>, <&tlv320aic3x_aux>; + nokia,headphone-amplifier = <&tpa6130a2>; + + tvout-selection-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>; /* 40 */ + jack-detection-gpios = <&gpio6 17 GPIO_ACTIVE_HIGH>; /* 177 */ + eci-switch-gpios = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* 182 */ + speaker-amplifier-gpios = <&twl_gpio 7 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-alc5632.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-alc5632.txt new file mode 100644 index 0000000000000000000000000000000000000000..57f40f93453ecabbf89763ef66a2f709ca29af7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-alc5632.txt @@ -0,0 +1,48 @@ +NVIDIA Tegra audio complex + +Required properties: +- compatible : "nvidia,tegra-audio-alc5632" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the ALC5632's pins as documented in the binding for the device + and: + + * Headset Stereophone + * Int Spk + * Headset Mic + * Digital Mic + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller +- nvidia,audio-codec : The phandle of the ALC5632 audio codec + +Example: + +sound { + compatible = "nvidia,tegra-audio-alc5632-paz00", + "nvidia,tegra-audio-alc5632"; + + nvidia,model = "Compal PAZ00"; + + nvidia,audio-routing = + "Int Spk", "SPK_OUTP", + "Int Spk", "SPK_OUTN", + "Headset Mic","MICBIAS1", + "MIC1_N", "Headset Mic", + "MIC1_P", "Headset Mic", + "Headset Stereophone", "HP_OUT_R", + "Headset Stereophone", "HP_OUT_L"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&alc5632>; + + clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-max98090.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-max98090.txt new file mode 100644 index 0000000000000000000000000000000000000000..c3495beba35841773cd1ec0c7d3efe1d952d22c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-max98090.txt @@ -0,0 +1,53 @@ +NVIDIA Tegra audio complex, with MAX98090 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-max98090" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the MAX98090's pins (as documented in its binding), and the jacks + on the board: + + * Headphones + * Speakers + * Mic Jack + * Int Mic + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the MAX98090 audio codec. + +Optional properties: +- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in +- nvidia,mic-det-gpios : The GPIO that detect microphones are plugged in + +Example: + +sound { + compatible = "nvidia,tegra-audio-max98090-venice2", + "nvidia,tegra-audio-max98090"; + nvidia,model = "NVIDIA Tegra Venice2"; + + nvidia,audio-routing = + "Headphones", "HPR", + "Headphones", "HPL", + "Speakers", "SPKR", + "Speakers", "SPKL", + "Mic Jack", "MICBIAS", + "IN34", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&acodec>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-rt5640.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-rt5640.txt new file mode 100644 index 0000000000000000000000000000000000000000..7788808dcd0bb20d5183bdce92d2591f9ac90bdb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-rt5640.txt @@ -0,0 +1,52 @@ +NVIDIA Tegra audio complex, with RT5640 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-rt5640" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the RT5640's pins (as documented in its binding), and the jacks + on the board: + + * Headphones + * Speakers + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the RT5640 audio codec. This binding + assumes that AIF1 on the CODEC is connected to Tegra. + +Optional properties: +- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in + +Example: + +sound { + compatible = "nvidia,tegra-audio-rt5640-dalmore", + "nvidia,tegra-audio-rt5640"; + nvidia,model = "NVIDIA Tegra Dalmore"; + + nvidia,audio-routing = + "Headphones", "HPOR", + "Headphones", "HPOL", + "Speakers", "SPORP", + "Speakers", "SPORN", + "Speakers", "SPOLP", + "Speakers", "SPOLN"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5640>; + + nvidia,hp-det-gpios = <&gpio 143 0>; /* GPIO PR7 */ + + clocks = <&tegra_car 216>, <&tegra_car 217>, <&tegra_car 120>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-rt5677.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-rt5677.txt new file mode 100644 index 0000000000000000000000000000000000000000..a4589cda214ee35894b6b8a2cb85f465b6dc007a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-rt5677.txt @@ -0,0 +1,67 @@ +NVIDIA Tegra audio complex, with RT5677 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-rt5677" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the RT5677's pins (as documented in its binding), and the jacks + on the board: + + * Headphone + * Speaker + * Headset Mic + * Internal Mic 1 + * Internal Mic 2 + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding + assumes that AIF1 on the CODEC is connected to Tegra. + +Optional properties: +- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in +- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier +- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in +- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal + +Example: + +sound { + compatible = "nvidia,tegra-audio-rt5677-ryu", + "nvidia,tegra-audio-rt5677"; + nvidia,model = "NVIDIA Tegra Ryu"; + + nvidia,audio-routing = + "Headphone", "LOUT2", + "Headphone", "LOUT1", + "Headset Mic", "MICBIAS1", + "IN1P", "Headset Mic", + "IN1N", "Headset Mic", + "DMIC L1", "Internal Mic 1", + "DMIC R1", "Internal Mic 1", + "DMIC L2", "Internal Mic 2", + "DMIC R2", "Internal Mic 2", + "Speaker", "PDM1L", + "Speaker", "PDM1R"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&rt5677>; + + nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>; + nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>; + nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>; + nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>; + + clocks = <&tegra_car TEGRA124_CLK_PLL_A>, + <&tegra_car TEGRA124_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA124_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-sgtl5000.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-sgtl5000.txt new file mode 100644 index 0000000000000000000000000000000000000000..5da7da4ea07ab1d33c71c456f017f51a7eba600d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-sgtl5000.txt @@ -0,0 +1,42 @@ +NVIDIA Tegra audio complex, with SGTL5000 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-sgtl5000" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the SGTL5000's pins (as documented in its binding), and the jacks + on the board: + + * Headphone Jack + * Line In Jack + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the SGTL5000 audio codec. + +Example: + +sound { + compatible = "toradex,tegra-audio-sgtl5000-apalis_t30", + "nvidia,tegra-audio-sgtl5000"; + nvidia,model = "Toradex Apalis T30"; + nvidia,audio-routing = + "Headphone Jack", "HP_OUT", + "LINE_IN", "Line In Jack", + "MIC_IN", "Mic Jack"; + nvidia,i2s-controller = <&tegra_i2s2>; + nvidia,audio-codec = <&sgtl5000>; + clocks = <&tegra_car TEGRA30_CLK_PLL_A>, + <&tegra_car TEGRA30_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA30_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-trimslice.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-trimslice.txt new file mode 100644 index 0000000000000000000000000000000000000000..ef1fe735827914611661293049f0dca05ba57d00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-trimslice.txt @@ -0,0 +1,21 @@ +NVIDIA Tegra audio complex for TrimSlice + +Required properties: +- compatible : "nvidia,tegra-audio-trimslice" +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Must include the following entries: + "pll_a" (The Tegra clock of that name), + "pll_a_out0" (The Tegra clock of that name), + "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller +- nvidia,audio-codec : The phandle of the WM8903 audio codec + +Example: + +sound { + compatible = "nvidia,tegra-audio-trimslice"; + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&codec>; + clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm8753.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm8753.txt new file mode 100644 index 0000000000000000000000000000000000000000..96f6a57dd6b40669b5addf6fbd9319b81c501fae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm8753.txt @@ -0,0 +1,40 @@ +NVIDIA Tegra audio complex + +Required properties: +- compatible : "nvidia,tegra-audio-wm8753" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the WM8753's pins as documented in the binding for the WM8753, + and the jacks on the board: + + * Headphone Jack + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller +- nvidia,audio-codec : The phandle of the WM8753 audio codec +Example: + +sound { + compatible = "nvidia,tegra-audio-wm8753-whistler", + "nvidia,tegra-audio-wm8753" + nvidia,model = "tegra-wm8753-harmony"; + + nvidia,audio-routing = + "Headphone Jack", "LOUT1", + "Headphone Jack", "ROUT1"; + + nvidia,i2s-controller = <&i2s1>; + nvidia,audio-codec = <&wm8753>; + + clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm8903.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm8903.txt new file mode 100644 index 0000000000000000000000000000000000000000..b795d282818d8acd34b9c57fdc53cb5e721d009a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm8903.txt @@ -0,0 +1,60 @@ +NVIDIA Tegra audio complex + +Required properties: +- compatible : "nvidia,tegra-audio-wm8903" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the WM8903's pins (documented in the WM8903 binding document), + and the jacks on the board: + + * Headphone Jack + * Int Spk + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller +- nvidia,audio-codec : The phandle of the WM8903 audio codec + +Optional properties: +- nvidia,spkr-en-gpios : The GPIO that enables the speakers +- nvidia,hp-mute-gpios : The GPIO that mutes the headphones +- nvidia,hp-det-gpios : The GPIO that detect headphones are plugged in +- nvidia,int-mic-en-gpios : The GPIO that enables the internal microphone +- nvidia,ext-mic-en-gpios : The GPIO that enables the external microphone + +Example: + +sound { + compatible = "nvidia,tegra-audio-wm8903-harmony", + "nvidia,tegra-audio-wm8903" + nvidia,model = "tegra-wm8903-harmony"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&codec 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ + nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */ + nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */ + + clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm9712.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm9712.txt new file mode 100644 index 0000000000000000000000000000000000000000..436f6cd9d07cdfc6cdc4dc93416329e3db7ecdad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra-audio-wm9712.txt @@ -0,0 +1,60 @@ +NVIDIA Tegra audio complex + +Required properties: +- compatible : "nvidia,tegra-audio-wm9712" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the WM9712's pins, and the jacks on the board: + + WM9712 pins: + + * MONOOUT + * HPOUTL + * HPOUTR + * LOUT2 + * ROUT2 + * OUT3 + * LINEINL + * LINEINR + * PHONE + * PCBEEP + * MIC1 + * MIC2 + * Mic Bias + + Board connectors: + + * Headphone + * LineIn + * Mic + +- nvidia,ac97-controller : The phandle of the Tegra AC97 controller + + +Example: + +sound { + compatible = "nvidia,tegra-audio-wm9712-colibri_t20", + "nvidia,tegra-audio-wm9712"; + nvidia,model = "Toradex Colibri T20"; + + nvidia,audio-routing = + "Headphone", "HPOUTL", + "Headphone", "HPOUTR", + "LineIn", "LINEINL", + "LineIn", "LINEINR", + "Mic", "MIC1"; + + nvidia,ac97-controller = <&ac97>; + + clocks = <&tegra_car 112>, <&tegra_car 113>, <&tegra_car 93>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-ac97.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-ac97.txt new file mode 100644 index 0000000000000000000000000000000000000000..eaf00102d92c295765ddd895f9a937511a9cc80b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-ac97.txt @@ -0,0 +1,36 @@ +NVIDIA Tegra 20 AC97 controller + +Required properties: +- compatible : "nvidia,tegra20-ac97" +- reg : Should contain AC97 controller registers location and length +- interrupts : Should contain AC97 interrupt +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - ac97 +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number + of the GPIO used to reset the external AC97 codec +- nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number + of the GPIO corresponding with the AC97 DAP _FS line + +Example: + +ac97@70002000 { + compatible = "nvidia,tegra20-ac97"; + reg = <0x70002000 0x200>; + interrupts = <0 81 0x04>; + nvidia,codec-reset-gpio = <&gpio 170 0>; + nvidia,codec-sync-gpio = <&gpio 120 0>; + clocks = <&tegra_car 3>; + resets = <&tegra_car 3>; + reset-names = "ac97"; + dmas = <&apbdma 12>, <&apbdma 12>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-das.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-das.txt new file mode 100644 index 0000000000000000000000000000000000000000..6de3a7ee4efb1f949d43a1d6f35212c148619661 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-das.txt @@ -0,0 +1,12 @@ +NVIDIA Tegra 20 DAS (Digital Audio Switch) controller + +Required properties: +- compatible : "nvidia,tegra20-das" +- reg : Should contain DAS registers location and length + +Example: + +das@70000c00 { + compatible = "nvidia,tegra20-das"; + reg = <0x70000c00 0x80>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc30c6bfbe95fc60a2642695fcacc7125221cc75 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra20-i2s.txt @@ -0,0 +1,30 @@ +NVIDIA Tegra 20 I2S controller + +Required properties: +- compatible : "nvidia,tegra20-i2s" +- reg : Should contain I2S registers location and length +- interrupts : Should contain I2S interrupt +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2s +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +Example: + +i2s@70002800 { + compatible = "nvidia,tegra20-i2s"; + reg = <0x70002800 0x200>; + interrupts = < 45 >; + clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-ahub.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-ahub.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e9a1895d7fb063d6e61a7c18525b4a60843b035 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-ahub.txt @@ -0,0 +1,88 @@ +NVIDIA Tegra30 AHUB (Audio Hub) + +Required properties: +- compatible : For Tegra30, must contain "nvidia,tegra30-ahub". For Tegra114, + must contain "nvidia,tegra114-ahub". For Tegra124, must contain + "nvidia,tegra124-ahub". Otherwise, must contain "nvidia,-ahub", + plus at least one of the above, where is tegra132. +- reg : Should contain the register physical address and length for each of + the AHUB's register blocks. + - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks. + - Tegra114 requires an additional entry, for the APBIF2 register block. +- interrupts : Should contain AHUB interrupt +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - d_audio + - apbif +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + Tegra30 and later: + - d_audio + - apbif + - i2s0 + - i2s1 + - i2s2 + - i2s3 + - i2s4 + - dam0 + - dam1 + - dam2 + - spdif + Tegra114 and later additionally require: + - amx + - adx + Tegra124 and later additionally require: + - amx1 + - adx1 + - afc0 + - afc1 + - afc2 + - afc3 + - afc4 + - afc5 +- ranges : The bus address mapping for the configlink register bus. + Can be empty since the mapping is 1:1. +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx0 .. rx + - tx0 .. tx + ... where n is: + Tegra30: 3 + Tegra114, Tegra124: 9 +- #address-cells : For the configlink bus. Should be <1>; +- #size-cells : For the configlink bus. Should be <1>. + +AHUB client modules need to specify the IDs of their CIFs (Client InterFaces). +For RX CIFs, the numbers indicate the register number within AHUB routing +register space (APBIF 0..3 RX, I2S 0..5 RX, DAM 0..2 RX 0..1, SPDIF RX 0..1). +For TX CIFs, the numbers indicate the bit position within the AHUB routing +registers (APBIF 0..3 TX, I2S 0..5 TX, DAM 0..2 TX, SPDIF TX 0..1). + +Example: + +ahub@70080000 { + compatible = "nvidia,tegra30-ahub"; + reg = <0x70080000 0x200 0x70080200 0x100>; + interrupts = < 0 103 0x04 >; + nvidia,dma-request-selector = <&apbdma 1>; + clocks = <&tegra_car 106>, <&tegra_car 107>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, + <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>, + <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>, + <&tegra_car 110>, <&tegra_car 10>; + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + "i2s3", "i2s4", "dam0", "dam1", "dam2", + "spdif"; + dmas = <&apbdma 1>, <&apbdma 1>; + <&apbdma 2>, <&apbdma 2>; + <&apbdma 3>, <&apbdma 3>; + <&apbdma 4>, <&apbdma 4>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", "rx3", "tx3"; + ranges; + #address-cells = <1>; + #size-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-hda.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-hda.txt new file mode 100644 index 0000000000000000000000000000000000000000..44d27456e8a4862a11e67785b459fd5ef721cc82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-hda.txt @@ -0,0 +1,30 @@ +NVIDIA Tegra30 HDA controller + +Required properties: +- compatible : For Tegra30, must contain "nvidia,tegra30-hda". Otherwise, + must contain '"nvidia,-hda", "nvidia,tegra30-hda"', where is + tegra114, tegra124, or tegra132. +- reg : Should contain the HDA registers location and length. +- interrupts : The interrupt from the HDA controller. +- clocks : Must contain an entry for each required entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: hda, hda2hdmi, hda2codec_2x + +Example: + +hda@70030000 { + compatible = "nvidia,tegra124-hda", "nvidia,tegra30-hda"; + reg = <0x0 0x70030000 0x0 0x10000>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_HDA>, + <&tegra_car TEGRA124_CLK_HDA2HDMI>, + <&tegra_car TEGRA124_CLK_HDA2CODEC_2X>; + clock-names = "hda", "hda2hdmi", "hda2codec_2x"; + resets = <&tegra_car 125>, /* hda */ + <&tegra_car 128>, /* hda2hdmi */ + <&tegra_car 111>; /* hda2codec_2x */ + reset-names = "hda", "hda2hdmi", "hda2codec_2x"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..38caa936f6f8aeb96fe09dba1269431e03b225a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/nvidia,tegra30-i2s.txt @@ -0,0 +1,27 @@ +NVIDIA Tegra30 I2S controller + +Required properties: +- compatible : For Tegra30, must contain "nvidia,tegra30-i2s". For Tegra124, + must contain "nvidia,tegra124-i2s". Otherwise, must contain + "nvidia,-i2s" plus at least one of the above, where is + tegra114 or tegra132. +- reg : Should contain I2S registers location and length +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2s +- nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback) + first, tx (capture) second. See nvidia,tegra30-ahub.txt for values. + +Example: + +i2s@70080300 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080300 0x100>; + nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/omap-abe-twl6040.txt b/arch/arm64/boot/dts/vendor/bindings/sound/omap-abe-twl6040.txt new file mode 100644 index 0000000000000000000000000000000000000000..462b04e8209f4d8de453005b52967ed16a63224b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/omap-abe-twl6040.txt @@ -0,0 +1,91 @@ +* Texas Instruments OMAP4+ and twl6040 based audio setups + +Required properties: +- compatible: "ti,abe-twl6040" +- ti,model: Name of the sound card ( for example "SDP4430") +- ti,mclk-freq: MCLK frequency for HPPLL operation +- ti,mcpdm: phandle for the McPDM node +- ti,twl6040: phandle for the twl6040 core node +- ti,audio-routing: List of connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + +Optional properties: +- ti,dmic: phandle for the OMAP dmic node if the machine have it connected +- ti,jack-detection: Need to be present if the board capable to detect jack + insertion, removal. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Earphone Spk + * Ext Spk + * Line Out + * Vibrator + * Headset Mic + * Main Handset Mic + * Sub Handset Mic + * Line In + * Digital Mic + +twl6040 pins: + * HSOL + * HSOR + * EP + * HFL + * HFR + * AUXL + * AUXR + * VIBRAL + * VIBRAR + * HSMIC + * MAINMIC + * SUBMIC + * AFML + * AFMR + + * Headset Mic Bias + * Main Mic Bias + * Digital Mic1 Bias + * Digital Mic2 Bias + +Digital mic pins: + * DMic + +Example: + +sound { + compatible = "ti,abe-twl6040"; + ti,model = "SDP4430"; + + ti,jack-detection; + ti,mclk-freq = <38400000>; + + ti,mcpdm = <&mcpdm>; + ti,dmic = <&dmic>; + + ti,twl6040 = <&twl6040>; + + /* Audio routing */ + ti,audio-routing = + "Headset Stereophone", "HSOL", + "Headset Stereophone", "HSOR", + "Earphone Spk", "EP", + "Ext Spk", "HFL", + "Ext Spk", "HFR", + "Line Out", "AUXL", + "Line Out", "AUXR", + "Vibrator", "VIBRAL", + "Vibrator", "VIBRAR", + "HSMIC", "Headset Mic", + "Headset Mic", "Headset Mic Bias", + "MAINMIC", "Main Handset Mic", + "Main Handset Mic", "Main Mic Bias", + "SUBMIC", "Sub Handset Mic", + "Sub Handset Mic", "Main Mic Bias", + "AFML", "Line In", + "AFMR", "Line In", + "DMic", "Digital Mic", + "Digital Mic", "Digital Mic1 Bias"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/omap-dmic.txt b/arch/arm64/boot/dts/vendor/bindings/sound/omap-dmic.txt new file mode 100644 index 0000000000000000000000000000000000000000..418e30e72e893550169bde60c5c73b4899b68665 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/omap-dmic.txt @@ -0,0 +1,20 @@ +* Texas Instruments OMAP4+ Digital Microphone Module + +Required properties: +- compatible: "ti,omap4-dmic" +- reg: Register location and size as an array: + , + ; +- interrupts: Interrupt number for DMIC +- ti,hwmods: Name of the hwmod associated with OMAP dmic IP + +Example: + +dmic: dmic@4012e000 { + compatible = "ti,omap4-dmic"; + reg = <0x4012e000 0x7f>, /* MPU private access */ + <0x4902e000 0x7f>; /* L3 Interconnect */ + interrupts = <0 114 0x4>; + interrupt-parent = <&gic>; + ti,hwmods = "dmic"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/omap-mcbsp.txt b/arch/arm64/boot/dts/vendor/bindings/sound/omap-mcbsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae8bf703ce7ac8105ee913f0d753ec6a134c709b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/omap-mcbsp.txt @@ -0,0 +1,36 @@ +* Texas Instruments OMAP2+ McBSP module + +Required properties: +- compatible: "ti,omap2420-mcbsp" for McBSP on OMAP2420 + "ti,omap2430-mcbsp" for McBSP on OMAP2430 + "ti,omap3-mcbsp" for McBSP on OMAP3 + "ti,omap4-mcbsp" for McBSP on OMAP4 and newer SoC +- reg: Register location and size, for OMAP4+ as an array: + , + ; +- reg-names: Array of strings associated with the address space +- interrupts: Interrupt numbers for the McBSP port, as an array in case the + McBSP IP have more interrupt lines: + , + , + ; +- interrupt-names: Array of strings associated with the interrupt numbers +- ti,buffer-size: Size of the FIFO on the port (OMAP2430 and newer SoC) +- ti,hwmods: Name of the hwmod associated to the McBSP port + +Example: + +mcbsp2: mcbsp@49022000 { + compatible = "ti,omap3-mcbsp"; + reg = <0x49022000 0xff>, + <0x49028000 0xff>; + reg-names = "mpu", "sidetone"; + interrupts = <0 17 0x4>, /* OCP compliant interrupt */ + <0 62 0x4>, /* TX interrupt */ + <0 63 0x4>, /* RX interrupt */ + <0 4 0x4>; /* Sidetone */ + interrupt-names = "common", "tx", "rx", "sidetone"; + interrupt-parent = <&intc>; + ti,buffer-size = <1280>; + ti,hwmods = "mcbsp2"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/omap-mcpdm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/omap-mcpdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..5f4e68ca228cb7aec18555533e59a51eecd62ec7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/omap-mcpdm.txt @@ -0,0 +1,20 @@ +* Texas Instruments OMAP4+ McPDM + +Required properties: +- compatible: "ti,omap4-mcpdm" +- reg: Register location and size as an array: + , + ; +- interrupts: Interrupt number for McPDM +- ti,hwmods: Name of the hwmod associated to the McPDM + +Example: + +mcpdm: mcpdm@40132000 { + compatible = "ti,omap4-mcpdm"; + reg = <0x40132000 0x7f>, /* MPU private access */ + <0x49032000 0x7f>; /* L3 Interconnect */ + interrupts = <0 112 0x4>; + interrupt-parent = <&gic>; + ti,hwmods = "mcpdm"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/omap-twl4030.txt b/arch/arm64/boot/dts/vendor/bindings/sound/omap-twl4030.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6a715e4ef43c1e0d7b5402188dbf310795e9caa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/omap-twl4030.txt @@ -0,0 +1,62 @@ +* Texas Instruments SoC with twl4030 based audio setups + +Required properties: +- compatible: "ti,omap-twl4030" +- ti,model: Name of the sound card (for example "omap3beagle") +- ti,mcbsp: phandle for the McBSP node + +Optional properties: +- ti,codec: phandle for the twl4030 audio node +- ti,mcbsp-voice: phandle for the McBSP node connected to the voice port of twl +- ti, jack-det-gpio: Jack detect GPIO +- ti,audio-routing: List of connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. + If the routing is not provided all possible connection will be available + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Earpiece Spk + * Handsfree Spk + * Ext Spk + * Main Mic + * Sub Mic + * Headset Mic + * Carkit Mic + * Digital0 Mic + * Digital1 Mic + * Line In + +twl4030 pins: + * HSOL + * HSOR + * EARPIECE + * HFL + * HFR + * PREDRIVEL + * PREDRIVER + * CARKITL + * CARKITR + * MAINMIC + * SUBMIC + * HSMIC + * DIGIMIC0 + * DIGIMIC1 + * CARKITMIC + * AUXL + * AUXR + + * Headset Mic Bias + * Mic Bias 1 /* Used for Main Mic or Digimic0 */ + * Mic Bias 2 /* Used for Sub Mic or Digimic1 */ + +Example: + +sound { + compatible = "ti,omap-twl4030"; + ti,model = "omap3beagle"; + + ti,mcbsp = <&mcbsp2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/pcm1789.txt b/arch/arm64/boot/dts/vendor/bindings/sound/pcm1789.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c74ed220ac25ebfda604145362e3ea9815f815f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/pcm1789.txt @@ -0,0 +1,22 @@ +Texas Instruments pcm1789 DT bindings + +PCM1789 is a simple audio codec that can be connected via +I2C or SPI. Currently, only I2C bus is supported. + +Required properties: + + - compatible: "ti,pcm1789" + +Required properties on I2C: + + - reg: the I2C address + - reset-gpios: GPIO to control the RESET pin + +Examples: + + audio-codec@4c { + compatible = "ti,pcm1789"; + reg = <0x4c>; + reset-gpios = <&gpio2 14 GPIO_ACTIVE_LOW>; + #sound-dai-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/pcm179x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/pcm179x.txt new file mode 100644 index 0000000000000000000000000000000000000000..436c2b247693f5a9a60a58b28c365aecd1741644 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/pcm179x.txt @@ -0,0 +1,27 @@ +Texas Instruments pcm179x DT bindings + +This driver supports both the I2C and SPI bus. + +Required properties: + + - compatible: "ti,pcm1792a" + +For required properties on SPI, please consult +Documentation/devicetree/bindings/spi/spi-bus.txt + +Required properties on I2C: + + - reg: the I2C address + + +Examples: + + codec_spi: 1792a@0 { + compatible = "ti,pcm1792a"; + spi-max-frequency = <600000>; + }; + + codec_i2c: 1792a@4c { + compatible = "ti,pcm1792a"; + reg = <0x4c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/pcm186x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/pcm186x.txt new file mode 100644 index 0000000000000000000000000000000000000000..1087f48559807edece39ee79fde95be9a0f94c6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/pcm186x.txt @@ -0,0 +1,42 @@ +Texas Instruments PCM186x Universal Audio ADC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "ti,pcm1862", + "ti,pcm1863", + "ti,pcm1864", + "ti,pcm1865" + + - reg : The I2C address of the device for I2C, the chip select + number for SPI. + + - avdd-supply: Analog core power supply (3.3v) + - dvdd-supply: Digital core power supply + - iovdd-supply: Digital IO power supply + See regulator/regulator.txt for more information + +CODEC input pins: + * VINL1 + * VINR1 + * VINL2 + * VINR2 + * VINL3 + * VINR3 + * VINL4 + * VINR4 + +The pins can be used in referring sound node's audio-routing property. + +Example: + + pcm186x: audio-codec@4a { + compatible = "ti,pcm1865"; + reg = <0x4a>; + + avdd-supply = <®_3v3_analog>; + dvdd-supply = <®_3v3>; + iovdd-supply = <®_1v8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/pcm5102a.txt b/arch/arm64/boot/dts/vendor/bindings/sound/pcm5102a.txt new file mode 100644 index 0000000000000000000000000000000000000000..c63ab0b6ee196e0d81c06a1fd79026494f584706 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/pcm5102a.txt @@ -0,0 +1,13 @@ +PCM5102a audio CODECs + +These devices does not use I2C or SPI. + +Required properties: + + - compatible : set as "ti,pcm5102a" + +Examples: + + pcm5102a: pcm5102a { + compatible = "ti,pcm5102a"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/pcm512x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/pcm512x.txt new file mode 100644 index 0000000000000000000000000000000000000000..3aae3b41bd8e8f48ed4af639b312690d7c6f9a33 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/pcm512x.txt @@ -0,0 +1,52 @@ +PCM512x audio CODECs + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or + "ti,pcm5142" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + + - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the + device, as covered in bindings/regulator/regulator.txt + +Optional properties: + + - clocks : A clock specifier for the clock connected as SCLK. If this + is absent the device will be configured to clock from BCLK. If pll-in + and pll-out are specified in addition to a clock, the device is + configured to accept clock input on a specified gpio pin. + + - pll-in, pll-out : gpio pins used to connect the pll using <1> + 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. + +Examples: + + pcm5122: pcm5122@4c { + compatible = "ti,pcm5122"; + reg = <0x4c>; + + AVDD-supply = <®_3v3_analog>; + DVDD-supply = <®_1v8>; + CPVDD-supply = <®_3v3>; + }; + + + pcm5142: pcm5142@4c { + compatible = "ti,pcm5142"; + reg = <0x4c>; + + AVDD-supply = <®_3v3_analog>; + DVDD-supply = <®_1v8>; + CPVDD-supply = <®_3v3>; + + clocks = <&sck>; + pll-in = <3>; + pll-out = <6>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,apq8016-sbc.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,apq8016-sbc.txt new file mode 100644 index 0000000000000000000000000000000000000000..84b28dbe9f15452bbe341f3dbf5e6f5452b72a19 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,apq8016-sbc.txt @@ -0,0 +1,89 @@ +* Qualcomm Technologies APQ8016 SBC ASoC machine driver + +This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver + +Required properties: + +- compatible : "qcom,apq8016-sbc-sndcard" + +- pinctrl-N : One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. +- pinctrl-names : Must contain a "default" entry. +- reg : Must contain an address for each entry in reg-names. +- reg-names : A list which must include the following entries: + * "mic-iomux" + * "spkr-iomux" +- qcom,model : Name of the sound card. + +- qcom,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, MicBias + of msm8x16_wcd codec and the jacks on the board: + + Power supplies: + * MIC BIAS External1 + * MIC BIAS External2 + * MIC BIAS Internal1 + * MIC BIAS Internal2 + + Board connectors: + * Headset Mic + * Secondary Mic + * DMIC + * Ext Spk + +Dai-link subnode properties and subnodes: + +Required dai-link subnodes: + +- cpu : CPU sub-node +- codec : CODEC sub-node + +Required CPU/CODEC subnodes properties: + +-link-name : Name of the dai link. +-sound-dai : phandle/s and port of CPU/CODEC + +Example: + +sound: sound { + compatible = "qcom,apq8016-sbc-sndcard"; + reg = <0x07702000 0x4>, <0x07702004 0x4>; + reg-names = "mic-iomux", "spkr-iomux"; + qcom,model = "DB410c"; + + qcom,audio-routing = + "MIC BIAS External1", "Handset Mic", + "MIC BIAS Internal2", "Headset Mic", + "MIC BIAS External1", "Secondary Mic", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1", + "DMIC1", "MIC BIAS Internal1", + "MIC BIAS Internal1", "Digital Mic1", + "DMIC2", "MIC BIAS Internal1", + "MIC BIAS Internal1", "Digital Mic2"; + + /* I2S - Internal codec */ + internal-dai-link@0 { + cpu { /* PRIMARY */ + sound-dai = <&lpass MI2S_PRIMARY>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; + }; + }; + + /* External Primary or External Secondary -ADV7533 HDMI */ + external-dai-link@0 { + link-name = "ADV7533"; + cpu { /* QUAT */ + sound-dai = <&lpass MI2S_QUATERNARY>; + }; + codec { + sound-dai = <&adv_bridge 0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,apq8096.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,apq8096.txt new file mode 100644 index 0000000000000000000000000000000000000000..c814e867850fac66010ca1c1e50410de899e08c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,apq8096.txt @@ -0,0 +1,120 @@ +* Qualcomm Technologies APQ8096 ASoC sound card driver + +This binding describes the APQ8096 sound card, which uses qdsp for audio. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,apq8096-sndcard" + +- audio-routing: + Usage: Optional + Value type: + Definition: A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, MicBias + of codec and the jacks on the board: + Valid names include: + + Board Connectors: + "Headphone Left" + "Headphone Right" + "Earphone" + "Line Out1" + "Line Out2" + "Line Out3" + "Line Out4" + "Analog Mic1" + "Analog Mic2" + "Analog Mic3" + "Analog Mic4" + "Analog Mic5" + "Analog Mic6" + "Digital Mic2" + "Digital Mic3" + + Audio pins and MicBias on WCD9335 Codec: + "MIC_BIAS1" + "MIC_BIAS2" + "MIC_BIAS3" + "MIC_BIAS4" + "AMIC1" + "AMIC2" + "AMIC3" + "AMIC4" + "AMIC5" + "AMIC6" + "AMIC6" + "DMIC1" + "DMIC2" + "DMIC3" + +- model: + Usage: required + Value type: + Definition: The user-visible name of this sound card. + += dailinks +Each subnode of sndcard represents either a dailink, and subnodes of each +dailinks would be cpu/codec/platform dais. + +- link-name: + Usage: required + Value type: + Definition: User friendly name for dai link + += CPU, PLATFORM, CODEC dais subnodes +- cpu: + Usage: required + Value type: + Definition: cpu dai sub-node + +- codec: + Usage: Optional + Value type: + Definition: codec dai sub-node + +- platform: + Usage: Optional + Value type: + Definition: platform dai sub-node + +- sound-dai: + Usage: required + Value type: + Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node. + +Obsolete: + qcom,model: String for soundcard name (Use model instead) + qcom,audio-routing: A list of the connections between audio components. + (Use audio-routing instead) + +Example: + +audio { + compatible = "qcom,apq8096-sndcard"; + model = "DB820c"; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + hdmi-dai-link { + link-name = "HDMI Playback"; + cpu { + sound-dai = <&q6afe HDMI_RX>; + }; + + platform { + sound-dai = <&q6adm>; + }; + + codec { + sound-dai = <&hdmi 0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,lpass-cpu.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,lpass-cpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..21c648328be9ad20bff726282187c4dc7df9d89d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,lpass-cpu.txt @@ -0,0 +1,54 @@ +* Qualcomm Technologies LPASS CPU DAI + +This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS). + +Required properties: + +- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu" +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : A list which must include the following entries: + * "ahbix-clk" + * "mi2s-osr-clk" + * "mi2s-bit-clk" + : required clocks for "qcom,lpass-cpu-apq8016" + * "ahbix-clk" + * "mi2s-bit-clk0" + * "mi2s-bit-clk1" + * "mi2s-bit-clk2" + * "mi2s-bit-clk3" + * "pcnoc-mport-clk" + * "pcnoc-sway-clk" + +- interrupts : Must contain an entry for each entry in + interrupt-names. +- interrupt-names : A list which must include the following entries: + * "lpass-irq-lpaif" +- pinctrl-N : One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. +- pinctrl-names : Must contain a "default" entry. +- reg : Must contain an address for each entry in reg-names. +- reg-names : A list which must include the following entries: + * "lpass-lpaif" + + + +Optional properties: + +- qcom,adsp : Phandle for the audio DSP node + +Example: + +lpass@28100000 { + compatible = "qcom,lpass-cpu"; + clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>; + clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk"; + interrupts = <0 85 1>; + interrupt-names = "lpass-irq-lpaif"; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&mi2s_default>; + pinctrl-1 = <&mi2s_idle>; + reg = <0x28100000 0x10000>; + reg-names = "lpass-lpaif"; + qcom,adsp = <&adsp>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,msm8916-wcd-analog.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,msm8916-wcd-analog.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdcea3d12ee531fc02df2bdae7e79f4856deb600 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,msm8916-wcd-analog.txt @@ -0,0 +1,100 @@ +msm8916 analog audio CODEC + +Bindings for codec Analog IP which is integrated in pmic pm8916, + +## Bindings for codec core on pmic: + +Required properties + - compatible = "qcom,pm8916-wcd-analog-codec"; + - reg: represents the slave base address provided to the peripheral. + - interrupts: List of interrupts in given SPMI peripheral. + - interrupt-names: Names specified to above list of interrupts in same + order. List of supported interrupt names are: + "cdc_spk_cnp_int" - Speaker click and pop interrupt. + "cdc_spk_clip_int" - Speaker clip interrupt. + "cdc_spk_ocp_int" - Speaker over current protect interrupt. + "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1. + "mbhc_but_rel_det" - button release interrupt. + "mbhc_but_press_det" - button press event + "mbhc_ins_rem_det" - jack insert removal detect interrupt. + "mbhc_switch_int" - multi button headset interrupt. + "cdc_ear_ocp_int" - Earphone over current protect interrupt. + "cdc_hphr_ocp_int" - Headphone R over current protect interrupt. + "cdc_hphl_ocp_det" - Headphone L over current protect interrupt. + "cdc_ear_cnp_int" - earphone cnp interrupt. + "cdc_hphr_cnp_int" - hphr click and pop interrupt. + "cdc_hphl_cnp_int" - hphl click and pop interrupt. + + - clocks: Handle to mclk. + - clock-names: should be "mclk" + - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. + - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. + - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. +Optional Properties: + - qcom,mbhc-vthreshold-low: Array of 5 threshold voltages in mV for 5 buttons + detection on headset when the mbhc is powered up + by internal current source, this is a low power. + - qcom,mbhc-vthreshold-high: Array of 5 thresold voltages in mV for 5 buttons + detection on headset when mbhc is powered up + from micbias. +- qcom,micbias-lvl: Voltage (mV) for Mic Bias +- qcom,hphl-jack-type-normally-open: boolean, present if hphl pin on jack is a + NO (Normally Open). If not specified, then + its assumed that hphl pin on jack is NC + (Normally Closed). +- qcom,gnd-jack-type-normally-open: boolean, present if gnd pin on jack is + NO (Normally Open). If not specified, then + its assumed that gnd pin on jack is NC + (Normally Closed). +- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor + connected. +- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor + connected. + +Example: + +spmi_bus { + ... + audio-codec@f000{ + compatible = "qcom,pm8916-wcd-analog-codec"; + reg = <0xf000 0x200>; + reg-names = "pmic-codec-core"; + clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "mclk"; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, + <0x1 0xf0 0x1 IRQ_TYPE_NONE>, + <0x1 0xf0 0x2 IRQ_TYPE_NONE>, + <0x1 0xf0 0x3 IRQ_TYPE_NONE>, + <0x1 0xf0 0x4 IRQ_TYPE_NONE>, + <0x1 0xf0 0x5 IRQ_TYPE_NONE>, + <0x1 0xf0 0x6 IRQ_TYPE_NONE>, + <0x1 0xf0 0x7 IRQ_TYPE_NONE>, + <0x1 0xf1 0x0 IRQ_TYPE_NONE>, + <0x1 0xf1 0x1 IRQ_TYPE_NONE>, + <0x1 0xf1 0x2 IRQ_TYPE_NONE>, + <0x1 0xf1 0x3 IRQ_TYPE_NONE>, + <0x1 0xf1 0x4 IRQ_TYPE_NONE>, + <0x1 0xf1 0x5 IRQ_TYPE_NONE>; + interrupt-names = "cdc_spk_cnp_int", + "cdc_spk_clip_int", + "cdc_spk_ocp_int", + "mbhc_ins_rem_det1", + "mbhc_but_rel_det", + "mbhc_but_press_det", + "mbhc_ins_rem_det", + "mbhc_switch_int", + "cdc_ear_ocp_int", + "cdc_hphr_ocp_int", + "cdc_hphl_ocp_det", + "cdc_ear_cnp_int", + "cdc_hphr_cnp_int", + "cdc_hphl_cnp_int"; + VDD-CDC-IO-supply = <&pm8916_l5>; + VDD-CDC-TX-RX-CX-supply = <&pm8916_l5>; + VDD-MICBIAS-supply = <&pm8916_l13>; + #sound-dai-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,msm8916-wcd-digital.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,msm8916-wcd-digital.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c8e4cb2517662f1eeff74ab5771e59200ae56d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,msm8916-wcd-digital.txt @@ -0,0 +1,20 @@ +msm8916 digital audio CODEC + +## Bindings for codec core in lpass: + +Required properties + - compatible = "qcom,msm8916-wcd-digital-codec"; + - reg: address space for lpass codec. + - clocks: Handle to mclk and ahbclk + - clock-names: should be "mclk", "ahbix-clk". + +Example: + +audio-codec@771c000{ + compatible = "qcom,msm8916-wcd-digital-codec"; + reg = <0x0771c000 0x400>; + clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>, + <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "ahbix-clk", "mclk"; + #sound-dai-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6adm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6adm.txt new file mode 100644 index 0000000000000000000000000000000000000000..bbae426cdfb19d67f573b2dd4502f8e9480a1e05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6adm.txt @@ -0,0 +1,39 @@ +Qualcomm Audio Device Manager (Q6ADM) binding + +Q6ADM is one of the APR audio service on Q6DSP. +Please refer to qcom,apr.txt for details of the coommon apr service bindings +used by the apr service device. + +- but must contain the following property: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6adm-v.". + Or "qcom,q6adm" where the version number can be queried + from DSP. + example "qcom,q6adm-v2.0" + + += ADM routing +"routing" subnode of the ADM node represents adm routing specific configuration + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6adm-routing". + +- #sound-dai-cells + Usage: required + Value type: + Definition: Must be 0 + += EXAMPLE +q6adm@8 { + compatible = "qcom,q6adm"; + reg = ; + q6routing: routing { + compatible = "qcom,q6adm-routing"; + #sound-dai-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6afe.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6afe.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8179409c1945a58bebe84ee86ab858a1d927386 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6afe.txt @@ -0,0 +1,178 @@ +Qualcomm Audio Front End (Q6AFE) binding + +AFE is one of the APR audio service on Q6DSP +Please refer to qcom,apr.txt for details of the common apr service bindings +used by all apr services. Must contain the following properties. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6afe-v." + Or "qcom,q6afe" where the version number can be queried + from DSP. + example "qcom,q6afe" + += AFE DAIs (Digial Audio Interface) +"dais" subnode of the AFE node. It represents afe dais, each afe dai is a +subnode of "dais" representing board specific dai setup. +"dais" node should have following properties followed by dai children. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6afe-dais" + +- #sound-dai-cells + Usage: required + Value type: + Definition: Must be 1 + +- #address-cells + Usage: required + Value type: + Definition: Must be 1 + +- #size-cells + Usage: required + Value type: + Definition: Must be 0 + +== AFE DAI is subnode of "dais" and represent a dai, it includes board specific +configuration of each dai. Must contain the following properties. + +- reg + Usage: required + Value type: + Definition: Must be dai id + +- qcom,sd-lines + Usage: required for mi2s interface + Value type: + Definition: Must be list of serial data lines used by this dai. + should be one or more of the 1-4 sd lines. + + - qcom,tdm-sync-mode: + Usage: required for tdm interface + Value type: + Definition: Synchronization mode. + 0 - Short sync bit mode + 1 - Long sync mode + 2 - Short sync slot mode + + - qcom,tdm-sync-src: + Usage: required for tdm interface + Value type: + Definition: Synchronization source. + 0 - External source + 1 - Internal source + + - qcom,tdm-data-out: + Usage: required for tdm interface + Value type: + Definition: Data out signal to drive with other masters. + 0 - Disable + 1 - Enable + + - qcom,tdm-invert-sync: + Usage: required for tdm interface + Value type: + Definition: Invert the sync. + 0 - Normal + 1 - Invert + + - qcom,tdm-data-delay: + Usage: required for tdm interface + Value type: + Definition: Number of bit clock to delay data + with respect to sync edge. + 0 - 0 bit clock cycle + 1 - 1 bit clock cycle + 2 - 2 bit clock cycle + + - qcom,tdm-data-align: + Usage: required for tdm interface + Value type: + Definition: Indicate how data is packed + within the slot. For example, 32 slot width in case of + sample bit width is 24. + 0 - MSB + 1 - LSB + += EXAMPLE + +q6afe@4 { + compatible = "qcom,q6afe"; + reg = ; + + dais { + compatible = "qcom,q6afe-dais"; + #sound-dai-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + hdmi@1 { + reg = <1>; + }; + + tdm@24 { + reg = <24>; + qcom,tdm-sync-mode = <1>: + qcom,tdm-sync-src = <1>; + qcom,tdm-data-out = <0>; + qcom,tdm-invert-sync = <1>; + qcom,tdm-data-delay = <1>; + qcom,tdm-data-align = <0>; + + }; + + tdm@25 { + reg = <25>; + qcom,tdm-sync-mode = <1>: + qcom,tdm-sync-src = <1>; + qcom,tdm-data-out = <0>; + qcom,tdm-invert-sync = <1>; + qcom,tdm-data-delay <1>: + qcom,tdm-data-align = <0>; + }; + + prim-mi2s-rx@16 { + reg = <16>; + qcom,sd-lines = <1 3>; + }; + + prim-mi2s-tx@17 { + reg = <17>; + qcom,sd-lines = <2>; + }; + + sec-mi2s-rx@18 { + reg = <18>; + qcom,sd-lines = <1 4>; + }; + + sec-mi2s-tx@19 { + reg = <19>; + qcom,sd-lines = <2>; + }; + + tert-mi2s-rx@20 { + reg = <20>; + qcom,sd-lines = <2 4>; + }; + + tert-mi2s-tx@21 { + reg = <21>; + qcom,sd-lines = <1>; + }; + + quat-mi2s-rx@22 { + reg = <22>; + qcom,sd-lines = <1>; + }; + + quat-mi2s-tx@23 { + reg = <23>; + qcom,sd-lines = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6asm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6asm.txt new file mode 100644 index 0000000000000000000000000000000000000000..f9c7bd8c1bc0fa8f3bb61cbe95ec09639d66122d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6asm.txt @@ -0,0 +1,39 @@ +Qualcomm Audio Stream Manager (Q6ASM) binding + +Q6ASM is one of the APR audio service on Q6DSP. +Please refer to qcom,apr.txt for details of the common apr service bindings +used by the apr service device. + +- but must contain the following property: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6asm-v.". + Or "qcom,q6asm" where the version number can be queried + from DSP. + example "qcom,q6asm-v2.0" + += ASM DAIs (Digial Audio Interface) +"dais" subnode of the ASM node represents dai specific configuration + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6asm-dais". + +- #sound-dai-cells + Usage: required + Value type: + Definition: Must be 1 + += EXAMPLE + +q6asm@7 { + compatible = "qcom,q6asm"; + reg = ; + q6asmdai: dais { + compatible = "qcom,q6asm-dais"; + #sound-dai-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6core.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6core.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f36ff8bec1817c679315da642e6de10989c0eec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,q6core.txt @@ -0,0 +1,21 @@ +Qualcomm ADSP Core service binding + +Q6CORE is one of the APR audio service on Q6DSP. +Please refer to qcom,apr.txt for details of the common apr service bindings +used by the apr service device. + +- but must contain the following property: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6core-v.". + Or "qcom,q6core" where the version number can be queried + from DSP. + example "qcom,q6core-v2.0" + += EXAMPLE +q6core@3 { + compatible = "qcom,q6core"; + reg = ; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,sdm845.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,sdm845.txt new file mode 100644 index 0000000000000000000000000000000000000000..408c4837e6d52f5533c7f37a61b01a746e7bda6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,sdm845.txt @@ -0,0 +1,80 @@ +* Qualcomm Technologies Inc. SDM845 ASoC sound card driver + +This binding describes the SDM845 sound card, which uses qdsp for audio. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,sdm845-sndcard" + +- audio-routing: + Usage: Optional + Value type: + Definition: A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, MicBias + of codec and the jacks on the board. + +- model: + Usage: required + Value type: + Definition: The user-visible name of this sound card. + += dailinks +Each subnode of sndcard represents either a dailink, and subnodes of each +dailinks would be cpu/codec/platform dais. + +- link-name: + Usage: required + Value type: + Definition: User friendly name for dai link + += CPU, PLATFORM, CODEC dais subnodes +- cpu: + Usage: required + Value type: + Definition: cpu dai sub-node + +- codec: + Usage: required + Value type: + Definition: codec dai sub-node + +- platform: + Usage: Optional + Value type: + Definition: platform dai sub-node + +- sound-dai: + Usage: required + Value type: + Definition: dai phandle/s and port of CPU/CODEC/PLATFORM node. + +Example: + +audio { + compatible = "qcom,sdm845-sndcard"; + model = "sdm845-snd-card"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active>; + pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep>; + + mm1-dai-link { + link-name = "MultiMedia1"; + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + pri-mi2s-dai-link { + link-name = "PRI MI2S Playback"; + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom,wcd9335.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,wcd9335.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d8d49e30af70fce524ffad5b2b6553435571b52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom,wcd9335.txt @@ -0,0 +1,123 @@ +QCOM WCD9335 Codec + +Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC, supports +Qualcomm Technologies, Inc. (QTI) multimedia solutions, including +the MSM8996, MSM8976, and MSM8956 chipsets. It has in-built +Soundwire controller, interrupt mux. It supports both I2S/I2C and +SLIMbus audio interfaces. + +Required properties with SLIMbus Interface: + +- compatible: + Usage: required + Value type: + Definition: For SLIMbus interface it should be "slimMID,PID", + textual representation of Manufacturer ID, Product Code, + shall be in lower case hexadecimal with leading zeroes + suppressed. Refer to slimbus/bus.txt for details. + Should be: + "slim217,1a0" for MSM8996 and APQ8096 SoCs with SLIMbus. + +- reg + Usage: required + Value type: + Definition: Should be ('Device index', 'Instance ID') + +- interrupts + Usage: required + Value type: + Definition: Interrupts via WCD INTR1 and INTR2 pins + +- interrupt-names: + Usage: required + Value type: + Definition: Interrupt names of WCD INTR1 and INTR2 + Should be: "intr1", "intr2" + +- reset-gpio: + Usage: required + Value type: + Definition: Reset gpio line + +- qcom,ifd: + Usage: required + Value type: + Definition: SLIM interface device + +- clocks: + Usage: required + Value type: + Definition: See clock-bindings.txt section "consumers". List of + three clock specifiers for mclk, mclk2 and slimbus clock. + +- clock-names: + Usage: required + Value type: + Definition: Must contain "mclk", "mclk2" and "slimbus" strings. + +- vdd-buck-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V buck supply + +- vdd-buck-sido-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V SIDO buck supply + +- vdd-rx-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V rx supply + +- vdd-tx-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V tx supply + +- vdd-vbat-supply: + Usage: Optional + Value type: + Definition: Should contain a reference to the vbat supply + +- vdd-micbias-supply: + Usage: required + Value type: + Definition: Should contain a reference to the micbias supply + +- vdd-io-supply: + Usage: required + Value type: + Definition: Should contain a reference to the 1.8V io supply + +- interrupt-controller: + Usage: required + Definition: Indicating that this is a interrupt controller + +- #interrupt-cells: + Usage: required + Value type: + Definition: should be 1 + +#sound-dai-cells + Usage: required + Value type: + Definition: Must be 1 + +codec@1{ + compatible = "slim217,1a0"; + reg = <1 0>; + interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "intr2" + reset-gpio = <&msmgpio 64 0>; + qcom,ifd = <&wc9335_ifd>; + clock-names = "mclk", "native"; + clocks = <&rpmcc RPM_SMD_DIV_CLK1>, + <&rpmcc RPM_SMD_BB_CLK1>; + vdd-buck-supply = <&pm8994_s4>; + vdd-rx-supply = <&pm8994_s4>; + vdd-buck-sido-supply = <&pm8994_s4>; + vdd-tx-supply = <&pm8994_s4>; + vdd-io-supply = <&pm8994_s4>; + #sound-dai-cells = <1>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom-audio-dev.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom-audio-dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..c83aaec589d7bba39f88401bc1d3535c9643e2cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom-audio-dev.txt @@ -0,0 +1,2305 @@ +Qualcomm Technologies, Inc. Audio devices for ALSA sound SoC + +* msm-pcm + +Required properties: + + - compatible : "qcom,msm-pcm-dsp" + + - qcom,msm-pcm-dsp-id : device node id + +* msm-pcm-low-latency + +Required properties: + + - compatible : "qcom,msm-pcm-dsp" + + - qcom,msm-pcm-dsp-id : device node id + +Optional properties: + + - qcom,msm-pcm-low-latency : Flag indicating whether + the device node is of type low latency. + + - qcom,latency-level : Flag indicating whether the device node + is of type regular low latency or ultra + low latency. + regular : regular low latency stream + ultra : ultra low latency stream + ull-pp : ultra low latency stream with post-processing capability + +* msm-pcm-dsp-noirq + +Required properties: + + - compatible : "qcom,msm-pcm-dsp-noirq"; + +Optional properties: + + - qcom,msm-pcm-low-latency : Flag indicating whether + the device node is of type low latency. + + - qcom,latency-level : Flag indicating whether the device node + is of type low latency or ultra low latency + ultra : ultra low latency stream + ull-pp : ultra low latency stream with post-processing capability +* msm-pcm-routing + +Required properties: + + - compatible : "qcom,msm-pcm-routing" + +* msm-pcm-lpa + +Required properties: + + - compatible : "qcom,msm-pcm-lpa" + +* msm-compr-dsp + +Required properties: + + - compatible : "qcom,msm-compr-dsp" + +* msm-compress-dsp + +Required properties: + + - compatible : "qcom,msm-compress-dsp" + +Optional properties: + - qcom,adsp-version: + This property can be used to specify the ADSP version/name. + Based on ADSP version, we decide if we have to use older + ADSP APIs or newer. Right now we are adding "MDSP 1.2" for + 8909 purpose. If the ADSP version is anything other than this + we use new ADSP APIs. + +* msm-voip-dsp + +Required properties: + + - compatible : "qcom,msm-voip-dsp" + +* msm-pcm-voice + +Required properties: + + - compatible : "qcom,msm-pcm-voice" + - qcom,destroy-cvd : Flag indicating whether to destroy cvd at + the end of call for low memory targets + +* msm-voice-host-pcm + +Required properties: + + - compatible : "qcom,msm-voice-host-pcm" + +* msm-voice-svc + +Required properties: + + - compatible : "qcom,msm-voice-svc" + +* msm-stub-codec + +Required properties: + + - compatible : "qcom,msm-stub-codec" + +* msm-hdmi-dba-codec-rx + +Required properties: + + - compatible : "qcom,msm-hdmi-dba-codec-rx" + - qcom,dba-bridge-chip: String info to indicate which bridge-chip + is used for HDMI using DBA. + +* msm-dai-fe + +Required properties: + + - compatible : "qcom,msm-dai-fe" + +* msm-pcm-afe + +Required properties: + + - compatible : "qcom,msm-pcm-afe" + +* msm-pcm-dtmf + +Required properties: + + - compatible : "qcom,msm-pcm-dtmf" + - qcom,msm-pcm-dtmf : Enable DTMF driver in Audio. DTMF driver is + used for generation and detection of DTMF tones, when user is in + active voice call. APR commands are sent from DTMF driver to ADSP. + +* msm-dai-stub + +[First Level Nodes] + +Required properties: + + - compatible : "msm-dai-stub" + +[Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-stub-dev" + - qcom,msm-dai-stub-dev-id : Stub dai port ID value is from 0 to 3. + This enables stub CPU dai in Audio. The stub dai is used when + there is no real backend in Audio. + +* msm-dai-q6-spdif + +Optional properties: + + - compatible : "msm-dai-q6-spdif" + +* msm-dai-q6-hdmi + +Required properties: + - compatible : "msm-dai-q6-hdmi" + - qcom,msm-dai-q6-dev-id : The hdmi multi channel port ID. + It is passed onto the dsp from the apps to form an audio + path to the HDMI device. Currently the only supported value + is 8, which indicates the rx path used for audio playback + on HDMI device. + +* msm-lsm-client + +Required properties: + + - compatible : "qcom,msm-lsm-client" + +* msm-pcm-loopback + +Required properties: + + - compatible : "qcom,msm-pcm-loopback" + +Optional properties: + + - qcom,msm-pcm-loopback-low-latency : Flag indicating whether + the device node is of type low latency. + +* msm-transcode-loopback + +Required properties: + + - compatible : "qcom,msm-transcode-loopback" + +* msm-dai-q6 + +[First Level Nodes] + +Required properties: + + - compatible : "msm-dai-q6" + +Optional properties: + + - qcom,ext-spk-amp-supply : External speaker amplifier power supply. + - qcom,ext-spk-amp-gpio : External speaker amplifier enable signal. + +[Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-q6-dev" + - qcom,msm-dai-q6-dev-id : The slimbus multi channel port ID + Value is from 16384 to 16397. + BT SCO port ID value from 12288 to 12289. + RT Proxy port ID values from 224 to 225 and 240 to + 241. + FM Rx and TX port ID values from 12292 to 12293. + incall record Rx and TX port ID values from 32771 to 32772. + inCall Music Delivery port ID is 32773. + incall Music 2 Delivery port ID is 32770. + +Optional properties: + + - qcom,msm-dai-q6-slim-dev-id : The Slimbus HW device (instance) ID associated + with Slimbus ports. + 0 - Slimbus HW device ID 0 (first instance) + 1 - Slimbus HW device ID 1 (second instance) + +* msm_dai_cdc_dma + +[First Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-cdc-dma" + +[Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-cdc-dma-dev" + - qcom,msm-dai-cdc-dma-dev-id : WSA codec dma port ID + Value is from 45056 to 45061. + VA codec dma port ID Value is from 45089 to 45091. + RX and TX codec dma port ID values from 45120 + to 45135. + +Optional properties: + +- qcom,msm-dai-is-island-supported: Defines whether this dai supported in + island mode or not. + 0 - Unsupported + 1 - Supported + +* msm-auxpcm + +Required properties: + + - compatible : "qcom,msm-auxpcm-dev" + + - qcom,msm-cpudai-auxpcm-mode: mode information. The first value is + for 8khz mode, the second is for + 16khz + 0 - for PCM + + - qcom,msm-cpudai-auxpcm-sync: sync information. The first value is + for 8khz mode, the second is for + 16khz + + - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame. The first + value is for 8khz mode, the second + is for 16khz + 5 - 256BPF + 4 - 128BPF + + - qcom,msm-cpudai-auxpcm-quant: Type of quantization. The first + value is for 8khz mode, the second + is for 16khz + 2 - Linear quantization + + - qcom,msm-cpudai-auxpcm-num-slots: Number of slots per mode in the + msm-cpudai-auxpcm-slot-mapping + array. + The first value is for 8khz mode, the + second is for 16khz. Max number of + slots supported by DSP is 4, anything + above 4 will be truncated to 4 when + sent to DSP. + + - qcom,msm-cpudai-auxpcm-slot-mapping: Array of slot numbers for multi + slot scenario. The first array + is for 8khz mode, the second is + for 16khz. The size of the array + is determined by the value in + qcom,msm-cpudai-auxpcm-num-slots + + - qcom,msm-cpudai-auxpcm-data: Data field - 0. The first value is + for 8khz mode, the second is for + 16khz + + - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000. The + first value is for 8khz mode, the + second is for 16KHz mode. When clock + rate is set to zero, then external + clock is assumed. + + - qcom,msm-auxpcm-interface: name of AUXPCM interface "primary" + indicates primary AUXPCM interface + "secondary" indicates secondary + AUXPCM interface +Optional properties: + +- pinctrl-names: Pinctrl state names for each pin + group configuration. +- pinctrl-x: Defines pinctrl state for each pin + group +- qcom,msm-cpudai-afe-clk-ver: Indicates version of AFE clock + interface to be used for enabling + PCM clock. If not defined, selects + default AFE clock interface. +- qcom,msm-dai-is-island-supported: Defines whether this dai supported in + island mode or not. + 0 - Unsupported + 1 - Supported + +* msm-pcm-hostless + +Required properties: + + - compatible : "qcom,msm-pcm-hostless" + +* msm-audio-apr + +Required properties: + + - compatible : "qcom,msm-audio-apr" + This device is added to represent APR module. + + - qcom,subsys-name: This value provides the subsystem name where codec + is present. It can be "apr_modem" or "apr_adsp". This + property enable apr driver to receive subsystem up/down + notification from modem/adsp. + +* Bolero codec + +Required properties: + + - compatible : "qcom,bolero-codec" + This device is added to represent bolero codec. + +Optional properties: + - qcom,bolero-version: Provides info relating to bolero version. + +* msm-ocmem-audio + +Required properties: + + - compatible : "qcom,msm-ocmem-audio" + + - qcom,msm_bus,name: Client name + + - qcom,msm_bus,num_cases: Total number of use cases + + - qcom,msm_bus,active_only: Context flag for requests in active + or dual (active & sleep) contex + + - qcom,msm_bus,num_paths: Total number of master-slave pairs + + - qcom,msm_bus,vectors: Arrays of unsigned integers + representing: + master-id, slave-id, arbitrated + bandwidth, + instantaneous bandwidth +* wcd9xxx_intc + +Required properties: + + - compatible : "qcom,wcd9xxx-irq" + + - interrupt-controller : Mark this device node as an + interrupt controller + + - #interrupt-cells : Should be 1 + + - interrupt-parent : Parent interrupt controller + + - qcom,gpio-connect Gpio that connects to parent + interrupt controller + +* audio-ext-clk-up + +Required properties: + + - compatible : "qcom,audio-ref-clk" + + - qcom,codec-ext-clk-src: Clock source type like PMIC, LPASS + requested to enable reference + or external clock. + +Optional properties: + + - qcom,codec-lpass-ext-clk-freq: Property used to specify frequency. + + - qcom,codec-lpass-clk-id: Property used to specify LPASS clock + ID value. + + - clock-names: Name of the PMIC clock that needs + to be enabled for audio ref clock. + This clock is set as parent. + + - clocks: phandle reference to the parent + clock. + + - qcom,mclk-clk-reg: Indicate the register address for mclk. + + - qcom,use-pinctrl: Indicates pinctrl required or not for this + clock node. + +* audio_slimslave + +Required properties: + + - compatible : "qcom,audio-slimslave" + + - elemental-addr: slimbus slave enumeration address. + +* msm-cpe-lsm + +Required properties: + + - compatible : "qcom,msm-cpe-lsm" + - qcom,msm-cpe-lsm-id : lsm afe port ID. CPE lsm driver uses + this property to find out the input afe port ID. Currently + only supported values are 1 and 3. + +* wcd_us_euro_gpio + +Required properties: + + - compatible : "qcom,msm-cdc-pinctrl" + +Optional properties: + - qcom,lpi-gpios : This boolean property is added if GPIOs are under + LPI TLMM. + - qcom,chip-wakeup-reg : This lists registers related to control interrupt mask + for respective LPI TLMM GPIOs. + - qcom,chip-wakeup-maskbit : This gives info on maskbit for given list of registers. + - qcom,chip-wakeup-default-val : This gives info on default value to be updated + for given chip regs. + +* msm-dai-slim + +Required properties: + + - compatible : "qcom,msm-dai-slim" + + - elemental-addr: slimbus slave enumeration address. + +* wcd_gpio_ctrl + +Required properties: + + - compatible : "qcom,msm-cdc-pinctrl" + + - qcom,cdc-rst-n-gpio : TLMM GPIO number + + - pinctrl-names: Pinctrl state names for each pin + group configuration. + - pinctrl-x: Defines pinctrl state for each pin + group. +* msm_cdc_pinctrl + +Required properties: + + - compatible : "qcom,msm-cdc-pinctrl" + + - pinctrl-names: Pinctrl state names for each pin + group configuration. + - pinctrl-x: Defines pinctrl state for each pin + group. + +* wcd_dsp_glink + +Required properties: + + - compatible : "qcom,wcd-dsp-glink" + - qcom,wdsp-channels: List of wdsp supported channel names. + +* msm_ext_disp_audio_codec_rx + +Required properties: + + - compatible : "qcom,msm-ext-disp-audio-codec-rx" + +Example: + + qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + }; + + qcom,msm-pcm-loopback-low-latency { + compatible = "qcom,msm-pcm-loopback"; + qcom,msm-pcm-loopback-low-latency; + }; + + qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + qcom,msm-pcm-lpa { + compatible = "qcom,msm-pcm-lpa"; + }; + + qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + qcom,msm-voice-host-pcm { + compatible = "qcom,msm-voice-host-pcm"; + }; + + qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + qcom,msm-pcm-dtmf { + compatible = "qcom,msm-pcm-dtmf"; + }; + + qcom,msm-dai-stub { + compatible = "qcom,msm-dai-stub"; + }; + + qcom,msm-dai-q6-spdif { + compatible = "qcom,msm-dai-q6-spdif"; + }; + + qcom,msm-dai-q6-hdmi { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <8>; + }; + + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <24608>; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + qcom,msm-dai-q6-sb-0-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16384>; + qcom,msm-dai-q6-slim-dev-id = <0>; + }; + + qcom,msm-dai-q6-sb-0-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16385>; + }; + + qcom,msm-dai-q6-sb-1-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16386>; + }; + + qcom,msm-dai-q6-sb-1-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16387>; + }; + + qcom,msm-dai-q6-sb-3-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16390>; + }; + + qcom,msm-dai-q6-sb-3-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16391>; + }; + + qcom,msm-dai-q6-sb-4-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16392>; + }; + + qcom,msm-dai-q6-sb-4-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16393>; + }; + + qcom,msm-dai-q6-sb-5-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16395>; + }; + + qcom,msm-dai-q6-sb-6-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16396>; + }; + + qcom,msm-dai-q6-sb-6-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16397>; + }; + + qcom,msm-dai-q6-bt-sco-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12288>; + }; + + qcom,msm-dai-q6-bt-sco-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12289>; + }; + + qcom,msm-dai-q6-int-fm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12292>; + }; + + qcom,msm-dai-q6-int-fm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12293>; + }; + + qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + }; + + qcom,msm-pri-auxpcm { + qcom,msm-cpudai-auxpcm-mode = <1>, <1>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <4>, <4>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1 0 0 0>, <1 3 0 0>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + compatible = "qcom,msm-auxpcm-dev"; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&pri_aux_pcm_active &pri_aux_pcm_din_active>; + pinctrl-1 = <&pri_aux_pcm_sleep &pri_aux_pcm_din_sleep>; + }; + + qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + + audio_apr: qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + qcom,subsys-name = "apr_adsp"; + q6core { + compatible = "qcom,q6core-audio"; + bolero: bolero-cdc { + compatible = "qcom,bolero-codec"; + }; + }; + }; + + qcom,msm-ocmem-audio { + compatible = "qcom,msm-ocmem-audio"; + qcom,msm_bus,name = "audio-ocmem"; + qcom,msm_bus,num_cases = <2>; + qcom,msm_bus,active_only = <0>; + qcom,msm_bus,num_paths = <1>; + qcom,msm_bus,vectors = + <11 604 0 0>, + <11 604 32505856 325058560>; + }; + + wcd9xxx_intc: wcd9xxx-irq { + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&msmgpio>; + interrupts = <72 0>; + interrupt-names = "cdc-int"; + }; + + clock_audio: audio_ext_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = <2>; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <1>; + clock-names = "osr_clk"; + clocks = <&clock_rpm clk_div_clk1>; + #clock-cells = <1>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&spkr_i2s_clk_sleep>; + pinctrl-1 = <&spkr_i2s_clk_active>; + }; + + audio_slimslave { + compatible = "qcom,audio-slimslave"; + elemental-addr = [ff ff ff ff 17 02]; + }; + + msm_dai_slim { + compatible = "qcom,msm_dai_slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; + + wcd_gpio_ctrl { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 64 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; + + msm_cdc_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; + + wcd_dsp_glink { + compatible = "qcom,wcd-dsp-glink"; + }; + + msm_ext_disp_audio_codec_rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + +* msm-dai-mi2s + +[First Level Nodes] + +Required properties: + + - compatible : "msm-dai-mi2s" + + [Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-q6-mi2s" + - qcom,msm-dai-q6-mi2s-dev-id: MSM or MDM can use Slimbus or I2S interface to + transfer data to (WCD9XXX) codec. + If slimbus interface is used then "msm-dai-q6" + needs to be filled with correct data for + slimbus interface. + The sections "msm-dai-mi2s" is used by MDM or + MSM to use I2S interface with codec. + This section is used by CPU driver in ASOC MSM + to configure MI2S interface. MSM internally + has multiple MI2S namely Primary, Secondary, + Tertiary and Quaternary MI2S. + They are represented with id 0, 1, 2, 3 + respectively. + The field "qcom,msm-dai-q6-mi2s-dev-id" + represents which of the MI2S block is used. + These MI2S are connected to I2S interface. + + - qcom,msm-mi2s-rx-lines: Each MI2S interface in MSM has one or more SD + lines. These lines are used for data transfer + between codec and MSM. + This element in indicates which output RX lines + are used in the MI2S interface. + + - qcom,msm-mi2s-tx-lines: Each MI2S interface in MSM has one or more SD + lines. These lines are used for data transfer + between codec and MSM. + This element in indicates which input TX lines + are used in the MI2S interface. + +Optional properties: + +- pinctrl-names: Pinctrl state names for each pin group + configuration. +- pinctrl-x: Defines pinctrl state for each pin group +- qcom,msm-dai-is-island-supported: Defines whether this dai supported in + island mode or not. + 0 - Unsupported + 1 - Supported + +Example: + +qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + qcom,msm-dai-q6-mi2s-prim { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&tert_mi2s_active &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sleep &tert_mi2s_sd0_sleep>; + }; +}; + +* msm-dai-spdif + +[First Level Nodes] + +Required properties: + + - compatible : "msm-dai-spdif" + + [Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-q6-spdif" + - qcom,msm-dai-q6-dev-id: The SPDIF port ID + Value is from 20480 to 20483. + +Example: + +qcom,msm-dai-spdif { + compatible = "qcom,msm-dai-spdif"; + qcom,msm-dai-q6-spdif-pri-rx { + compatible = "qcom,msm-dai-q6-spdif"; + qcom,msm-dai-q6-dev-id = <20480>; + }; +}; + +* msm-adsp-loader + +Required properties: + - compatible : "qcom,adsp-loader" + - qcom,adsp-state: + It is possible that some MSM use PIL to load the ADSP image. While + other MSM may use SBL to load the ADSP image at boot. Audio APR needs + state of ADSP to register and enable APR to be used for sending commands + to ADSP. so adsp-state represents the state of ADSP to ADSP loader. + Value of 0 indicates ADSP loader needs to use PIL and value of 2 means + ADSP image is already loaded by SBL. + +Optional properties: + - qcom,proc-img-to-load: + This property can be used to override default ADSP + loading by PIL. Based on string input, different proc is + loaded. Right now we are adding option "modem" + for 8916 purpose. Default image will be "adsp" which + will load LPASS Q6 for other targets as expected. + "adsp" option need not be explicitly mentioned in + DTSI file, as it is default option. + - adsp-fuse-not-supported: + When ADSP variant read from fuse register is not + supported, set this to true to check if image with different fw image + name needs to be loaded + - adsp-fw-name: + ADSP fw name with which PIL API to load DSP needs to be called + +Example: + +qcom,msm-adsp-loader { + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <2>; + qcom,proc-img-to-load = "modem"; + adsp-fuse-not-supported = <1>; + adsp-fw-name = "adsp2"; +}; + +* msm-audio-ion + +Required properties: + - compatible : "qcom,msm-audio-ion" + +Optional properties: + - qcom,smmu-version: + version ID to provide info regarding smmu version + used in chipset. If ARM SMMU HW - use id value as 1, + If QSMMU HW - use id value as 2. + + - qcom,smmu-sid-mask: + Mask for the Stream ID part of SMMU SID. + + - qcom,smmu-enabled: + It is possible that some MSM have SMMU in ADSP. While other MSM use + no SMMU. Audio lib introduce wrapper for ION APIs. The wrapper needs + presence of SMMU in ADSP to handle ION APIs differently. + Presence of this property means ADSP has SMMU in it. + - iommus: + A phandle parsed by smmu driver. Number of entries will vary across + targets. + +Example: + + qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion; + qcom,smmu-enabled; + }; + +* msm-dai-tdm + +[First Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-tdm" + - qcom,msm-cpudai-tdm-group-id: ID of the group device. TDM interface + supports up to 8 groups: + Primary RX: 37120 + Primary TX: 37121 + Secondary RX: 37136 + Secondary TX: 37137 + Tertiary RX: 37152 + Tertiary TX: 37153 + Quaternary RX: 37168 + Quaternary TX: 37169 + + - qcom,msm-cpudai-tdm-group-num-ports: Number of ports in + msm-cpudai-tdm-group-port-id array. + Max number of ports supported by DSP is 8. + + - qcom,msm-cpudai-tdm-group-port-id: Array of TDM port IDs of the group. + The size of the array is determined by + the value in msm-cpudai-tdm-group-num-ports. + Each group supports up to 8 ports: + Primary RX: 36864, 36866, 36868, 36870, + 36872, 36874, 36876, 36878 + Primary TX: 36865, 36867, 36869, 36871, + 36873, 36875, 36877, 36879 + Secondary RX: 36880, 36882, 36884, 36886, + 36888, 36890, 36892, 36894 + Secondary TX: 36881, 36883, 36885, 36887, + 36889, 36891, 36893, 36895 + Tertiary RX: 36896, 36898, 36900, 36902, + 36904, 36906, 36908, 36910 + Tertiary TX: 36897, 36899, 36901, 36903, + 36905, 36907, 36909, 36911 + Quaternary RX: 36912, 36914, 36916, 36918, + 36920, 36922, 36924, 36926 + Quaternary TX: 36913, 36915, 36917, 36919, + 36921, 36923, 36925, 36927 + + - qcom,msm-cpudai-tdm-clk-rate: Clock rate for tdm - 12288000. + When clock rate is set to zero, + then external clock is assumed. + + - qcom,msm-cpudai-tdm-clk-internal: Clock Source. + 0 - EBIT clock from clk tree + 1 - IBIT clock from clk tree + + - qcom,msm-cpudai-tdm-sync-mode: Synchronization setting. + 0 - Short sync bit mode + 1 - Long sync mode + 2 - Short sync slot mode + + - qcom,msm-cpudai-tdm-sync-src: Synchronization source. + 0 - External source + 1 - Internal source + + - qcom,msm-cpudai-tdm-data-out: Data out signal to drive with other masters. + 0 - Disable + 1 - Enable + + - qcom,msm-cpudai-tdm-invert-sync: Invert the sync. + 0 - Normal + 1 - Invert + + - qcom,msm-cpudai-tdm-data-delay: Number of bit clock to delay data + with respect to sync edge. + 0 - 0 bit clock cycle + 1 - 1 bit clock cycle + 2 - 2 bit clock cycle + + [Second Level Nodes] + +Required properties: + + - compatible : "qcom,msm-dai-q6-tdm" + - qcom,msm-dai-q6-mi2s-dev-id: TDM port ID. + + - qcom,msm-cpudai-tdm-data-align: Indicate how data is packed + within the slot. For example, 32 slot width in case of + sample bit width is 24. + 0 - MSB + 1 - LSB + +Optional properties: + + - qcom,msm-cpudai-tdm-header-start-offset: TDM Custom header start offset + in bytes from this sub-frame. The bytes is counted from 0. + 0 is mapped to the 1st byte in or out of + the digital serial data line this sub-frame belong to. + Supported value: 0, 4, 8. + + - qcom,msm-cpudai-tdm-header-width: Header width per frame followed. + 2 bytes for MOST/TDM case. + Supported value: 2. + + - qcom,msm-cpudai-tdm-header-num-frame-repeat: Number of header followed. + Supported value: 8. + + - pinctrl-names: Pinctrl state names for each pin group + configuration. + + - pinctrl-x: Defines pinctrl state for each pin group. + + - qcom,msm-dai-is-island-supported: Defines whether this dai supported in + island mode or not. + 0 - Unsupported + 1 - Supported + +Example: + + qcom,msm-dai-tdm-quat-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37168>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36912>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&quat_tdm_active &quat_tdm_dout_active>; + pinctrl-1 = <&quat_tdm_sleep &quat_tdm_dout_sleep>; + dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36912>; + qcom,msm-cpudai-tdm-data-align = <0>; + qcom,msm-cpudai-tdm-header-start-offset = <0>; + qcom,msm-cpudai-tdm-header-width = <2>; + qcom,msm-cpudai-tdm-header-num-frame-repeat = <8>; + }; + }; + +* MSMSTUB ASoC Machine driver + +Required properties: +- compatible : "qcom,sm8150-asoc-snd-stub" for SM8150 target. +- compatible : "qcom,kona-asoc-snd-stub" for Kona target. +- qcom,model : The user-visible name of this sound card. +- qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target + +Example: + + sound_stub { + compatible = "qcom,sm8150-asoc-snd-stub"; + qcom,model = "sm8150-stub-snd-card"; + + qcom,tasha-mclk-clk-freq = <9600000>; + asoc-platform = <&pcm0>; + asoc-platform-names = "msm-pcm-dsp.0"; + asoc-cpu = <&sb_0_rx>, <&sb_0_tx>; + asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <0>; + }; + +* WCD DSP manager driver + +Required properties: +- compatible : "qcom,wcd-dsp-mgr" +- qcom,wdsp-components : This is phandle list containing the references to the + components of the manager driver. Manager driver will + register to component framework with these phandles. +- qcom,img-filename : String property to provide the dsp image file name that is + to be read from file system and downloaded to dsp memory +Optional properties: +- qcom,wdsp-cmpnt-dev-name : Property that manager driver will parse, but defined + in the child's DT entry that is given to manager driver + with phandle. This property will be used by the manager + driver in case the manager driver cannot match child's + of_node pointer to registered phandle. + +Example: + + qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi 2>; + qcom,img-filename = "cpe_9340"; + }; + +Example of child node that would have qcom,wdsp-cmpnt-dev-name property + + wcd934x_cdc: tavil_codec { + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + }; + +* msm-mdf + +Required properties: + - compatible : "qcom,msm-mdf" + +Optional subnodes: + - qcom,msm_mdf_cb : Child nodes representing the compute context banks. + +Subnode Required properties: + - compatible : "qcom,msm-mdf-cb" + - label: Label describing the subsystem this context bank belongs to. + +Subnode Optional properties: + - qcom,smmu-enabled: + It is possible that some MSM subsystems have SMMU, while other MSM + subsystems do not. MDF platform driver needs to handle SMMU APIs + differently according to the availability of SMMU. + Presence of this property means the subsystem has SMMU in it. + - iommus : A list of phandle and IOMMU specifier pairs that describe the + IOMMU master interfaces of the device. + +Example: + qcom,msm-mdf { + compatible = "qcom,msm-mdf"; + + qcom,msm_mdf_cb1 { + compatible = "qcom,msm-mdf-cb"; + label = "adsp"; + qcom,smmu-enabled; + }; + qcom,msm_mdf_cb2 { + compatible = "qcom,msm-mdf-cb"; + label = "dsps"; + }; + qcom,msm_mdf_cb3 { + compatible = "qcom,msm-mdf-cb"; + label = "modem"; + }; + }; + +* msm-mdf-mem + +Required properties: + - compatible : "qcom,msm-mdf-mem-region" + - qcom,msm-mdf-mem-data-size: indicates the size of memory + for MDF purpose + - memory-region : CMA region which is owned by this device. + +Example: + qcom,msm-mdf-mem { + compatible = "qcom,msm-mdf-mem-region"; + memory-region = <&mdf_mem>; + }; + +* SM8150 ASoC Machine driver + +Required properties: +- compatible : "qcom,sm8150-asoc-snd-pahu-aqt" for pahu codec and + "qcom,sm8150-asoc-snd-tavil" for tavil codec. +- qcom,model : The user-visible name of this sound card. +- qcom,pahu-ext-clk-freq : External CLK frequency value for pahu codec +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- clock-names : clock name defined for external clock. +- clocks : external clock defined for codec clock. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target + +Example: + + sound-pahu { + compatible = "qcom,sm8150-asoc-snd-pahu-aqt"; + qcom,model = "sm8150-pahu-aqt-snd-card"; + qcom,ext-disp-audio-rx; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + + reg = <0x1711a000 0x4>, + <0x1711b000 0x4>, + <0x1711c000 0x4>, + <0x1711d000 0x4>; + reg-names = "lpaif_pri_mode_muxsel", + "lpaif_sec_mode_muxsel", + "lpaif_tert_mode_muxsel", + "lpaif_quat_mode_muxsel"; + + qcom,audio-routing = + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "AMIC3", "MIC BIAS2", + "AMIC4", "MIC BIAS2", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,pahu-ext-clk-freq = <19200000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + +* QCS405 ASoC Machine driver + +Required properties: +- compatible : "qcom,qcs405-asoc-snd". +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- clock-names : clock name defined for external clock. +- clocks : external clock defined for codec clock. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target +- qcom,wsa_bolero_codec : Property to specify if WSA macro in Bolero codec is used for this target +- qcom,va_bolero_codec : Property to specify if VA macro in Bolero codec is used for this target +- qcom,tasha_codec : Property to specify if Tasha codec is used for this target +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,csra-codec : Property to specify if CSRA66x0 is used for this target +- qcom,csra-max-devs : Maximum number of CSRA66x0 devices present in the target +- qcom,csra-devs : List of phandles of all possible CSRA66x0 devices supported for the target +- qcom,csra-aux-dev-prefix : Name prefix in multi-channel configuration for CSRA66x0 device +Example: + + qcs405_snd { + compatible = "qcom,qcs405-asoc-snd"; + qcom,wsa_bolero_codec = <1>; + qcom,va_bolero_codec = <1>; + qcom,tasha_codec = <1>; + qcom,ext-disp-audio-rx = <1>; + qcom,wcn-btfm = <1>; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + + qcom,audio-routing = + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "AMIC3", "MIC BIAS2", + "AMIC4", "MIC BIAS2", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, <&va_cdc_dma_0_tx>, + <&va_cdc_dma_1_tx>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-cdc-dma-dev.45056", + "msm-dai-q6-cdc-dma-dev.45057", + "msm-dai-q6-cdc-dma-dev.45058", + "msm-dai-q6-cdc-dma-dev.45059", + "msm-dai-q6-cdc-dma-dev.45061", + "msm-dai-q6-cdc-dma-dev.45089", + "msm-dai-q6-cdc-dma-dev.45091"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>, + <&bolero>;; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx", + "bolero_codec"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>, + <&cdc_dmic56_gpios>, <&cdc_dmic78_gpios>; + }; + +* SM6150 ASoC Machine driver + +Required properties: +- compatible : "qcom,sm6150-asoc-snd". +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,codec-aux-devs: This is phandle list containing the references to Auxilary + codec devices. + +Optional properties: +- qcom,msm-mi2s-master: This property is used to inform machine driver + if MSM is the clock master of mi2s. 1 means master and 0 means slave. The + first entry is primary mi2s; the second entry is secondary mi2s, and so on. +- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,ext-disp-audio-rx: Property to specify if Audio over Display port is supported for the target +- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target +- qcom,mi2s-audio-intf: Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf: Property to specify if Aux PCM interface is used for the target +- qcom,tavil_codec : Property to specify if Tavil codec is used for this target +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,msm_audio_ssr_devs: List the snd event framework clients + +Example: + sm6150_snd: sound { + status = "okay"; + compatible = "qcom,sm6150-asoc-snd"; + qcom,ext-disp-audio-rx = <1>; + qcom,wcn-btfm = <1>; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&tx_cdc_dma_6_tx>, <&tx_cdc_dma_7_tx>; + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45120", + "msm-dai-cdc-dma-dev.45121", + "msm-dai-cdc-dma-dev.45122", + "msm-dai-cdc-dma-dev.45123", + "msm-dai-cdc-dma-dev.45124", + "msm-dai-cdc-dma-dev.45125", + "msm-dai-cdc-dma-dev.45126", + "msm-dai-cdc-dma-dev.45127", + "msm-dai-cdc-dma-dev.45128", + "msm-dai-cdc-dma-dev.45129", + "msm-dai-cdc-dma-dev.45130", + "msm-dai-cdc-dma-dev.45131", + "msm-dai-cdc-dma-dev.45133", + "msm-dai-cdc-dma-dev.45135"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, + <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero-codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-aux-devs = <&wcd937x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; + }; +}; + +* MSMSTUB ASoC Machine driver + +Required properties: +- compatible : "qcom,sm6150-asoc-snd-stub" for SM6150 target. +- qcom,model : The user-visible name of this sound card. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target + +Example: + + sound_stub { + compatible = "qcom,sm6150-asoc-snd-stub"; + qcom,model = "sm6150-stub-snd-card"; + + asoc-platform = <&pcm0>; + asoc-platform-names = "msm-pcm-dsp.0"; + asoc-cpu = <&sb_0_rx>, <&sb_0_tx>; + asoc-cpu-names = "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <0>; + }; + +* SA8155 ASoC Machine driver + +Required properties: +- compatible : "qcom,sa8155-asoc-snd-auto" for auto adp codec and + "qcom,sa8155-asoc-snd-auto-custom" for auto custom codec. +- qcom,model : The user-visible name of this sound card. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,mi2s-audio-intf : Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf : Property to specify if AUX PCM interface is used for the target +- qcom,msm-mi2s-master : List of master/slave configuration for MI2S interfaces + +Example: + + sound-adp-star { + compatible = "qcom,sa8155-asoc-snd-adp-star"; + qcom,model = "sa8155-adp-star-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq", "msm-pcm-loopback.1", + "msm-pcm-dtmf"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, + <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, + <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, + <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>, + <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>, + <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, + <&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>, + <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, + <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, + <&dai_quin_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", + "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", + "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", + "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901", + "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917", + "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", + "msm-dai-q6-tdm.36935"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; + +* BENGAL ASoC Machine driver + +Required properties: +- compatible : "qcom,bengal-asoc-snd". +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,codec-aux-devs: This is phandle list containing the references to Auxilary + codec devices. + +Optional properties: +- qcom,msm-mi2s-master: This property is used to inform machine driver + if MSM is the clock master of mi2s. 1 means master and 0 means slave. The + first entry is primary mi2s; the second entry is secondary mi2s, and so on. +- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,ext-disp-audio-rx: Property to specify if Audio over Display port is supported for the target +- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target +- qcom,mi2s-audio-intf: Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf: Property to specify if Aux PCM interface is used for the target +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,msm_audio_ssr_devs: List the snd event framework clients +- qcom,afe-rxtx-lb: AFE RX to TX loopback. +- qcom,tlmm-gpio: TLMM gpio number for corresponding LPASS gpio +- qcom,va-bolero-codec: Property to specify VA macro supported. +- qcom,rxtx-bolero-codec: Property to specify RX-TX macros supported. +- qcom,wsa-bolero-codec: Property to specify WSA macro supported. +- qcom,tdm-audio-intf: Property to specify if Aux PCM interface is used for the target + +Example: + bengal_snd: sound { + status = "okay"; + compatible = "qcom,bengal-asoc-snd"; + qcom,wcn-btfm = <1>; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + qcom,afe-rxtx-lb = <1>; + qcom,va-bolero-codec = <1>; + qcom,rxtx-bolero-codec = <1>; + qcom,tdm-audio-intf = <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&tx_cdc_dma_6_tx>, <&tx_cdc_dma_7_tx>; + asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45120", + "msm-dai-cdc-dma-dev.45121", + "msm-dai-cdc-dma-dev.45122", + "msm-dai-cdc-dma-dev.45123", + "msm-dai-cdc-dma-dev.45124", + "msm-dai-cdc-dma-dev.45125", + "msm-dai-cdc-dma-dev.45126", + "msm-dai-cdc-dma-dev.45127", + "msm-dai-cdc-dma-dev.45128", + "msm-dai-cdc-dma-dev.45129", + "msm-dai-cdc-dma-dev.45130", + "msm-dai-cdc-dma-dev.45131", + "msm-dai-cdc-dma-dev.45133", + "msm-dai-cdc-dma-dev.45135"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>; + asoc-codec = <&stub_codec>, <&bolero>; + asoc-codec-names = "msm-stub-codec.1", "bolero-codec"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_i2c_f>; + qcom,wsa-aux-dev-prefix = "SpkrMono"; + qcom,codec-aux-devs = <&wcd937x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; + }; + +* KONA ASoC Machine driver + +Required properties: +- compatible : "qcom,kona-asoc-snd". +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,codec-aux-devs: This is phandle list containing the references to Auxilary + codec devices. + +Optional properties: +- qcom,msm-mi2s-master: This property is used to inform machine driver + if MSM is the clock master of mi2s. 1 means master and 0 means slave. The + first entry is primary mi2s; the second entry is secondary mi2s, and so on. +- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,ext-disp-audio-rx: Property to specify if Audio over Display port is supported for the target +- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target +- qcom,mi2s-audio-intf: Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf: Property to specify if Aux PCM interface is used for the target +- qcom,tdm-audio-intf: Property to specify if Aux PCM interface is used for the target +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,msm_audio_ssr_devs: List the snd event framework clients +- qcom,afe-rxtx-lb: AFE RX to TX loopback. +- qcom,tlmm-gpio: TLMM gpio number for corresponding LPASS gpio + +Example: + kona_snd: sound { + status = "okay"; + compatible = "qcom,kona-asoc-snd"; + qcom,ext-disp-audio-rx = <1>; + qcom,wcn-btfm = <1>; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + qcom,tdm-audio-intf = <1>; + qcom,afe-rxtx-lb = <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&tx_cdc_dma_6_tx>, <&tx_cdc_dma_7_tx>; + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45120", + "msm-dai-cdc-dma-dev.45121", + "msm-dai-cdc-dma-dev.45122", + "msm-dai-cdc-dma-dev.45123", + "msm-dai-cdc-dma-dev.45124", + "msm-dai-cdc-dma-dev.45125", + "msm-dai-cdc-dma-dev.45126", + "msm-dai-cdc-dma-dev.45127", + "msm-dai-cdc-dma-dev.45128", + "msm-dai-cdc-dma-dev.45129", + "msm-dai-cdc-dma-dev.45130", + "msm-dai-cdc-dma-dev.45131", + "msm-dai-cdc-dma-dev.45133", + "msm-dai-cdc-dma-dev.45135"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic-gpios = <&cdc_dmic12_gpios>, <&cdc_dmic34_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, + <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero-codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-aux-devs = <&wcd937x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; + }; + +* voice-mhi-audio + +Required properties: + - compatible : "qcom,voice-mhi-audio" + - memory-region : CMA region owned by this device + +Optional properties: + - voice_mhi_voting : Property that defines whether voting is needed or not for this device + +Example: + + qcom,voice-mhi-audio { + compatible = "qcom,voice-mhi-audio"; + memory-region = <&mailbox_mem>; + voice_mhi_voting; + }; + +}; + +* LITO ASoC Machine driver + +Required properties: +- compatible : "qcom,lito-asoc-snd". +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,codec-aux-devs: This is phandle list containing the references to Auxilary + codec devices. + +Optional properties: +- qcom,msm-mi2s-master: This property is used to inform machine driver + if MSM is the clock master of mi2s. 1 means master and 0 means slave. The + first entry is primary mi2s; the second entry is secondary mi2s, and so on. +- qcom,msm-mbhc-hphl-swh: This property is used to distinguish headset HPHL + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,msm-mbhc-gnd-swh: This property is used to distinguish headset GND + switch type on target typically the switch type will be normally open or + normally close, value for this property 0 for normally close and 1 for + normally open. +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,ext-disp-audio-rx: Property to specify if Audio over Display port is supported for the target +- qcom,wcn-btfm : Property to specify if WCN BT/FM chip is used for the target +- qcom,mi2s-audio-intf: Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf: Property to specify if Aux PCM interface is used for the target +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,msm_audio_ssr_devs: List the snd event framework clients +- qcom,afe-rxtx-lb: AFE RX to TX loopback. +- qcom,tlmm-gpio: TLMM gpio number for corresponding LPASS gpio +- qcom,lito-is-v2-enabled: Check if lito v2 is enabled as lito v2 has gpio support + for swr tx data3 slew rate. Change port params for lito v2. + +Example: + lito_snd: sound { + status = "okay"; + compatible = "qcom,lito-asoc-snd"; + qcom,ext-disp-audio-rx = <1>; + qcom,wcn-btfm = <1>; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + qcom,afe-rxtx-lb = <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&tx_cdc_dma_6_tx>, <&tx_cdc_dma_7_tx>; + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45120", + "msm-dai-cdc-dma-dev.45121", + "msm-dai-cdc-dma-dev.45122", + "msm-dai-cdc-dma-dev.45123", + "msm-dai-cdc-dma-dev.45124", + "msm-dai-cdc-dma-dev.45125", + "msm-dai-cdc-dma-dev.45126", + "msm-dai-cdc-dma-dev.45127", + "msm-dai-cdc-dma-dev.45128", + "msm-dai-cdc-dma-dev.45129", + "msm-dai-cdc-dma-dev.45130", + "msm-dai-cdc-dma-dev.45131", + "msm-dai-cdc-dma-dev.45133", + "msm-dai-cdc-dma-dev.45135"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic-gpios = <&cdc_dmic01_gpios>, <&cdc_dmic23_gpios>, + <&cdc_dmic45_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, + <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero-codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/qcom-usb-audio-qmi-dev.txt b/arch/arm64/boot/dts/vendor/bindings/sound/qcom-usb-audio-qmi-dev.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d3fb78f96a7754820c318963f78cf127efe89fb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/qcom-usb-audio-qmi-dev.txt @@ -0,0 +1,26 @@ +QTI USB Audio QMI Device + +USB Audio QMI device is used to attach to remote processor IOMMU and +map USB Audio driver specific memory to iova to share with remote +processor. + +Required Properties: + +- compatible : "qcom,usb-audio-qmi-dev" + +- iommus : A list of phandle and IOMMU specifier pairs that describe the + IOMMU master interfaces of the device. + +- qcom,usb-audio-stream-id : Stream id is prepended to iova before passing + iova to remote processor. This allows remote processor to access iova. + +- qcom,usb-audio-intr-num : Interrupter number for external sub system + destination. + +Example: + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&lpass_q6_smmu 12>; + qcom,usb-audio-stream-id = <12>; + qcom,usb-audio-intr-num = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/renesas,fsi.txt b/arch/arm64/boot/dts/vendor/bindings/sound/renesas,fsi.txt new file mode 100644 index 0000000000000000000000000000000000000000..0cf0f819b8236e250fd0f0db1bc0dba879e9dcd4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/renesas,fsi.txt @@ -0,0 +1,31 @@ +Renesas FSI + +Required properties: +- compatible : "renesas,fsi2-", + "renesas,sh_fsi2" or "renesas,sh_fsi" as + fallback. + Examples with soctypes are: + - "renesas,fsi2-r8a7740" (R-Mobile A1) + - "renesas,fsi2-sh73a0" (SH-Mobile AG5) +- reg : Should contain the register physical address and length +- interrupts : Should contain FSI interrupt + +- fsia,spdif-connection : FSI is connected by S/PDIF +- fsia,stream-mode-support : FSI supports 16bit stream mode. +- fsia,use-internal-clock : FSI uses internal clock when master mode. + +- fsib,spdif-connection : same as fsia +- fsib,stream-mode-support : same as fsia +- fsib,use-internal-clock : same as fsia + +Example: + +sh_fsi2: sh_fsi2@ec230000 { + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupts = <0 146 0x4>; + + fsia,spdif-connection; + fsia,stream-mode-support; + fsia,use-internal-clock; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/renesas,rsnd.txt b/arch/arm64/boot/dts/vendor/bindings/sound/renesas,rsnd.txt new file mode 100644 index 0000000000000000000000000000000000000000..9e764270c36b869768429950b6fabcb88a3e6f7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/renesas,rsnd.txt @@ -0,0 +1,684 @@ +Renesas R-Car sound + +============================================= +* Modules +============================================= + +Renesas R-Car and RZ/G sound is constructed from below modules +(for Gen2 or later) + + SCU : Sampling Rate Converter Unit + - SRC : Sampling Rate Converter + - CMD + - CTU : Channel Transfer Unit + - MIX : Mixer + - DVC : Digital Volume and Mute Function + SSIU : Serial Sound Interface Unit + SSI : Serial Sound Interface + +See detail of each module's channels, connection, limitation on datasheet + +============================================= +* Multi channel +============================================= + +Multi channel is supported by Multi-SSI, or TDM-SSI. + + Multi-SSI : 6ch case, you can use stereo x 3 SSI + TDM-SSI : 6ch case, you can use TDM + +============================================= +* Enable/Disable each modules +============================================= + +See datasheet to check SRC/CTU/MIX/DVC connect-limitation. +DT controls enabling/disabling module. +${LINUX}/arch/arm/boot/dts/r8a7790-lager.dts can be good example. +This is example of + +Playback: [MEM] -> [SRC2] -> [DVC0] -> [SSIU0/SSI0] -> [codec] +Capture: [MEM] <- [DVC1] <- [SRC3] <- [SSIU1/SSI1] <- [codec] + + &rcar_sound { + ... + rcar_sound,dai { + dai0 { + playback = <&ssi0 &src2 &dvc0>; + capture = <&ssi1 &src3 &dvc1>; + }; + }; + }; + +You can use below. +${LINUX}/arch/arm/boot/dts/r8a7790.dts can be good example. + + &src0 &ctu00 &mix0 &dvc0 &ssi0 + &src1 &ctu01 &mix1 &dvc1 &ssi1 + &src2 &ctu02 &ssi2 + &src3 &ctu03 &ssi3 + &src4 &ssi4 + &src5 &ctu10 &ssi5 + &src6 &ctu11 &ssi6 + &src7 &ctu12 &ssi7 + &src8 &ctu13 &ssi8 + &src9 &ssi9 + +============================================= +* SRC (Sampling Rate Converter) +============================================= + + [xx]Hz [yy]Hz + ------> [SRC] ------> + +SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes + + Asynchronous mode: input data / output data are based on different clocks. + you can use this mode on Playback / Capture + Synchronous mode: input data / output data are based on same clocks. + This mode will be used if system doesn't have its input clock, + for example digital TV case. + you can use this mode on Playback + +------------------ +** Asynchronous mode +------------------ + +You need to use "simple-scu-audio-card" sound card for it. +example) + + sound { + compatible = "simple-scu-audio-card"; + ... + /* + * SRC Asynchronous mode setting + * Playback: + * All input data will be converted to 48kHz + * Capture: + * Inputed 48kHz data will be converted to + * system specified Hz + */ + simple-audio-card,convert-rate = <48000>; + ... + simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + simple-audio-card,codec { + ... + }; + }; + +------------------ +** Synchronous mode +------------------ + + > amixer set "SRC Out Rate" on + > aplay xxxx.wav + > amixer set "SRC Out Rate" 48000 + > amixer set "SRC Out Rate" 44100 + +============================================= +* CTU (Channel Transfer Unit) +============================================= + + [xx]ch [yy]ch + ------> [CTU] --------> + +CTU can convert [xx]ch to [yy]ch, or exchange outputed channel. +CTU conversion needs matrix settings. +For more detail information, see below + + Renesas R-Car datasheet + - Sampling Rate Converter Unit (SCU) + - SCU Operation + - CMD Block + - Functional Blocks in CMD + + Renesas R-Car datasheet + - Sampling Rate Converter Unit (SCU) + - Register Description + - CTUn Scale Value exx Register (CTUn_SVxxR) + + ${LINUX}/sound/soc/sh/rcar/ctu.c + - comment of header + +You need to use "simple-scu-audio-card" sound card for it. +example) + + sound { + compatible = "simple-scu-audio-card"; + ... + /* + * CTU setting + * All input data will be converted to 2ch + * as output data + */ + simple-audio-card,convert-channels = <2>; + ... + simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + simple-audio-card,codec { + ... + }; + }; + +Ex) Exchange output channel + Input -> Output + 1ch -> 0ch + 0ch -> 1ch + + example of using matrix + output 0ch = (input 0ch x 0) + (input 1ch x 1) + output 1ch = (input 0ch x 1) + (input 1ch x 0) + + amixer set "CTU Reset" on + amixer set "CTU Pass" 9,10 + amixer set "CTU SV0" 0,4194304 + amixer set "CTU SV1" 4194304,0 + + example of changing connection + amixer set "CTU Reset" on + amixer set "CTU Pass" 2,1 + +============================================= +* MIX (Mixer) +============================================= + +MIX merges 2 sounds path. You can see 2 sound interface on system, +and these sounds will be merged by MIX. + + aplay -D plughw:0,0 xxxx.wav & + aplay -D plughw:0,1 yyyy.wav + +You need to use "simple-scu-audio-card" sound card for it. +Ex) + [MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0] + | + [MEM] -> [SRC2] -> [CTU03] -+ + + sound { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "simple-scu-audio-card"; + ... + simple-audio-card,cpu@0 { + reg = <0>; + sound-dai = <&rcar_sound 0>; + }; + simple-audio-card,cpu@1 { + reg = <1>; + sound-dai = <&rcar_sound 1>; + }; + simple-audio-card,codec { + ... + }; + }; + + &rcar_sound { + ... + rcar_sound,dai { + dai0 { + playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>; + }; + dai1 { + playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; + }; + }; + }; + +============================================= +* DVC (Digital Volume and Mute Function) +============================================= + +DVC controls Playback/Capture volume. + +Playback Volume + amixer set "DVC Out" 100% + +Capture Volume + amixer set "DVC In" 100% + +Playback Mute + amixer set "DVC Out Mute" on + +Capture Mute + amixer set "DVC In Mute" on + +Volume Ramp + amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps" + amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps" + amixer set "DVC Out Ramp" on + aplay xxx.wav & + amixer set "DVC Out" 80% // Volume Down + amixer set "DVC Out" 100% // Volume Up + +============================================= +* SSIU (Serial Sound Interface Unit) +============================================= + +There is no DT settings for SSIU, because SSIU will be automatically +selected via SSI. +SSIU can avoid some under/over run error, because it has some buffer. +But you can't use it if SSI was PIO mode. +In DMA mode, you can select not to use SSIU by using "no-busif" on DT. + + &ssi0 { + no-busif; + }; + +============================================= +* SSI (Serial Sound Interface) +============================================= + +** PIO mode + +You can use PIO mode which is for connection check by using. +Note: The system will drop non-SSI modules in PIO mode +even though if DT is selecting other modules. + + &ssi0 { + pio-transfer + }; + +** DMA mode without SSIU + +You can use DMA without SSIU. +Note: under/over run, or noise are likely to occur + + &ssi0 { + no-busif; + }; + +** PIN sharing + +Each SSI can share WS pin. It is based on platform. +This is example if SSI1 want to share WS pin with SSI0 + + &ssi1 { + shared-pin; + }; + +** Multi-SSI + +You can use Multi-SSI. +This is example of SSI0/SSI1/SSI2 (= for 6ch) + + &rcar_sound { + ... + rcar_sound,dai { + dai0 { + playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>; + }; + }; + }; + +** TDM-SSI + +You can use TDM with SSI. +This is example of TDM 6ch. +Driver can automatically switches TDM <-> stereo mode in this case. + + rsnd_tdm: sound { + compatible = "simple-audio-card"; + ... + simple-audio-card,cpu { + /* system can use TDM 6ch */ + dai-tdm-slot-num = <6>; + sound-dai = <&rcar_sound>; + }; + simple-audio-card,codec { + ... + }; + }; + + +============================================= +Required properties: +============================================= + +- compatible : "renesas,rcar_sound-", fallbacks + "renesas,rcar_sound-gen1" if generation1, and + "renesas,rcar_sound-gen2" if generation2 (or RZ/G1) + "renesas,rcar_sound-gen3" if generation3 + Examples with soctypes are: + - "renesas,rcar_sound-r8a7743" (RZ/G1M) + - "renesas,rcar_sound-r8a7745" (RZ/G1E) + - "renesas,rcar_sound-r8a7778" (R-Car M1A) + - "renesas,rcar_sound-r8a7779" (R-Car H1) + - "renesas,rcar_sound-r8a7790" (R-Car H2) + - "renesas,rcar_sound-r8a7791" (R-Car M2-W) + - "renesas,rcar_sound-r8a7793" (R-Car M2-N) + - "renesas,rcar_sound-r8a7794" (R-Car E2) + - "renesas,rcar_sound-r8a7795" (R-Car H3) + - "renesas,rcar_sound-r8a7796" (R-Car M3-W) + - "renesas,rcar_sound-r8a77965" (R-Car M3-N) +- reg : Should contain the register physical address. + required register is + SRU/ADG/SSI if generation1 + SRU/ADG/SSIU/SSI if generation2 +- rcar_sound,ssi : Should contain SSI feature. + The number of SSI subnode should be same as HW. + see below for detail. +- rcar_sound,src : Should contain SRC feature. + The number of SRC subnode should be same as HW. + see below for detail. +- rcar_sound,ctu : Should contain CTU feature. + The number of CTU subnode should be same as HW. + see below for detail. +- rcar_sound,mix : Should contain MIX feature. + The number of MIX subnode should be same as HW. + see below for detail. +- rcar_sound,dvc : Should contain DVC feature. + The number of DVC subnode should be same as HW. + see below for detail. +- rcar_sound,dai : DAI contents. + The number of DAI subnode should be same as HW. + see below for detail. +- #sound-dai-cells : it must be 0 if your system is using single DAI + it must be 1 if your system is using multi DAI +- clocks : References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks. +- clock-names : List of necessary clock names. + "ssi-all", "ssi.X", "src.X", "mix.X", "ctu.X", + "dvc.X", "clk_a", "clk_b", "clk_c", "clk_i" + +Optional properties: +- #clock-cells : it must be 0 if your system has audio_clkout + it must be 1 if your system has audio_clkout0/1/2/3 +- clock-frequency : for all audio_clkout0/1/2/3 +- clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn + is asynchronizes with lr-clock. +- resets : References to SSI resets. +- reset-names : List of valid reset names. + "ssi-all", "ssi.X" + +SSI subnode properties: +- interrupts : Should contain SSI interrupt for PIO transfer +- shared-pin : if shared clock pin +- pio-transfer : use PIO transfer mode +- no-busif : BUSIF is not ussed when [mem -> SSI] via DMA case +- dma : Should contain Audio DMAC entry +- dma-names : SSI case "rx" (=playback), "tx" (=capture) + SSIU case "rxu" (=playback), "txu" (=capture) + +SRC subnode properties: +- dma : Should contain Audio DMAC entry +- dma-names : "rx" (=playback), "tx" (=capture) + +DVC subnode properties: +- dma : Should contain Audio DMAC entry +- dma-names : "tx" (=playback/capture) + +DAI subnode properties: +- playback : list of playback modules +- capture : list of capture modules + + +============================================= +Example: +============================================= + +rcar_sound: sound@ec500000 { + #sound-dai-cells = <1>; + compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2"; + reg = <0 0xec500000 0 0x1000>, /* SCU */ + <0 0xec5a0000 0 0x100>, /* ADG */ + <0 0xec540000 0 0x1000>, /* SSIU */ + <0 0xec541000 0 0x1280>, /* SSI */ + <0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/ + reg-names = "scu", "adg", "ssiu", "ssi", "audmapp"; + + clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>, + <&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>, + <&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>, + <&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>, + <&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>, + <&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>, + <&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>, + <&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>, + <&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>, + <&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>, + <&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>, + <&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>; + clock-names = "ssi-all", + "ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5", + "ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0", + "src.9", "src.8", "src.7", "src.6", "src.5", + "src.4", "src.3", "src.2", "src.1", "src.0", + "dvc.0", "dvc.1", + "clk_a", "clk_b", "clk_c", "clk_i"; + + rcar_sound,dvc { + dvc0: dvc-0 { + dmas = <&audma0 0xbc>; + dma-names = "tx"; + }; + dvc1: dvc-1 { + dmas = <&audma0 0xbe>; + dma-names = "tx"; + }; + }; + + rcar_sound,mix { + mix0: mix-0 { }; + mix1: mix-1 { }; + }; + + rcar_sound,ctu { + ctu00: ctu-0 { }; + ctu01: ctu-1 { }; + ctu02: ctu-2 { }; + ctu03: ctu-3 { }; + ctu10: ctu-4 { }; + ctu11: ctu-5 { }; + ctu12: ctu-6 { }; + ctu13: ctu-7 { }; + }; + + rcar_sound,src { + src0: src-0 { + interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x85>, <&audma1 0x9a>; + dma-names = "rx", "tx"; + }; + src1: src-1 { + interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x87>, <&audma1 0x9c>; + dma-names = "rx", "tx"; + }; + src2: src-2 { + interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x89>, <&audma1 0x9e>; + dma-names = "rx", "tx"; + }; + src3: src-3 { + interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8b>, <&audma1 0xa0>; + dma-names = "rx", "tx"; + }; + src4: src-4 { + interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8d>, <&audma1 0xb0>; + dma-names = "rx", "tx"; + }; + src5: src-5 { + interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x8f>, <&audma1 0xb2>; + dma-names = "rx", "tx"; + }; + src6: src-6 { + interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x91>, <&audma1 0xb4>; + dma-names = "rx", "tx"; + }; + src7: src-7 { + interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x93>, <&audma1 0xb6>; + dma-names = "rx", "tx"; + }; + src8: src-8 { + interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x95>, <&audma1 0xb8>; + dma-names = "rx", "tx"; + }; + src9: src-9 { + interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x97>, <&audma1 0xba>; + dma-names = "rx", "tx"; + }; + }; + + rcar_sound,ssi { + ssi0: ssi-0 { + interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi1: ssi-1 { + interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi2: ssi-2 { + interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi3: ssi-3 { + interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi4: ssi-4 { + interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi5: ssi-5 { + interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi6: ssi-6 { + interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi7: ssi-7 { + interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi8: ssi-8 { + interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + ssi9: ssi-9 { + interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>; + dma-names = "rx", "tx", "rxu", "txu"; + }; + }; + + rcar_sound,dai { + dai0 { + playback = <&ssi5 &src5>; + capture = <&ssi6>; + }; + dai1 { + playback = <&ssi3>; + }; + dai2 { + capture = <&ssi4>; + }; + dai3 { + playback = <&ssi7>; + }; + dai4 { + capture = <&ssi8>; + }; + }; +}; + +============================================= +Example: simple sound card +============================================= + + rsnd_ak4643: sound { + compatible = "simple-audio-card"; + + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&ak4643>; + clocks = <&audio_clock>; + }; + }; + +&rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + + rcar_sound,dai { + dai0 { + playback = <&ssi0 &src2 &dvc0>; + capture = <&ssi1 &src3 &dvc1>; + }; + }; +}; + +&ssi1 { + shared-pin; +}; + +============================================= +Example: simple sound card for TDM +============================================= + + rsnd_tdm: sound { + compatible = "simple-audio-card"; + + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + dai-tdm-slot-num = <6>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&xxx>; + }; + }; + +============================================= +Example: simple sound card for Multi channel +============================================= + +&rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + + rcar_sound,dai { + dai0 { + playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,pdm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,pdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..47f164fbd1d72f80f8caedb7e6d62ad991351897 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,pdm.txt @@ -0,0 +1,41 @@ +* Rockchip PDM controller + +Required properties: + +- compatible: "rockchip,pdm" +- reg: physical base address of the controller and length of memory mapped + region. +- dmas: DMA specifiers for rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should include "rx". +- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +- clock-names: should contain following: + - "pdm_hclk": clock for PDM BUS + - "pdm_clk" : clock for PDM controller +- pinctrl-names: Must contain a "default" entry. +- pinctrl-N: One property must exist for each entry in + pinctrl-names. See ../pinctrl/pinctrl-bindings.txt + for details of the property values. + +Example for rk3328 PDM controller: + +pdm: pdm@ff040000 { + compatible = "rockchip,pdm"; + reg = <0x0 0xff040000 0x0 0x1000>; + clocks = <&clk_pdm>, <&clk_gates28 0>; + clock-names = "pdm_clk", "pdm_hclk"; + dmas = <&pdma 16>; + #dma-cells = <1>; + dma-names = "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pdmm0_clk + &pdmm0_sdi0 + &pdmm0_sdi1 + &pdmm0_sdi2 + &pdmm0_sdi3>; + pinctrl-1 = <&pdmm0_clk_sleep + &pdmm0_sdi0_sleep + &pdmm0_sdi1_sleep + &pdmm0_sdi2_sleep + &pdmm0_sdi3_sleep>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,rk3288-hdmi-analog.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,rk3288-hdmi-analog.txt new file mode 100644 index 0000000000000000000000000000000000000000..e5430d1d34e400402ffd365f0851deb08f47b36e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,rk3288-hdmi-analog.txt @@ -0,0 +1,36 @@ +ROCKCHIP RK3288 with HDMI and analog audio + +Required properties: +- compatible: "rockchip,rk3288-hdmi-analog" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the analog audio codec. +- rockchip,routing: A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. For this driver the first string should always be + "Analog". + +Optionnal properties: +- rockchip,hp-en-gpios = The phandle of the GPIO that power up/down the + headphone (when the analog output is an headphone). +- rockchip,hp-det-gpios = The phandle of the GPIO that detects the headphone + (when the analog output is an headphone). +- pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt + +Example: + +sound { + compatible = "rockchip,rk3288-hdmi-analog"; + rockchip,model = "Analog audio output"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&es8388>; + rockchip,routing = "Analog", "LOUT2", + "Analog", "ROUT2"; + rockchip,hp-en-gpios = <&gpio8 0 GPIO_ACTIVE_HIGH>; + rockchip,hp-det-gpios = <&gpio7 7 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&headphone>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,rk3399-gru-sound.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,rk3399-gru-sound.txt new file mode 100644 index 0000000000000000000000000000000000000000..72d3cf4c2606006ecaae21a126b6e2c2045a4ec0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip,rk3399-gru-sound.txt @@ -0,0 +1,22 @@ +ROCKCHIP with MAX98357A/RT5514/DA7219 codecs on GRU boards + +Required properties: +- compatible: "rockchip,rk3399-gru-sound" +- rockchip,cpu: The phandle of the Rockchip I2S controller that's + connected to the codecs +- rockchip,codec: The phandle of the audio codecs + +Optional properties: +- dmic-wakeup-delay-ms : specify delay time (ms) for DMIC ready. + If this option is specified, which means it's required dmic need + delay for DMIC to ready so that rt5514 can avoid recording before + DMIC send valid data + +Example: + +sound { + compatible = "rockchip,rk3399-gru-sound"; + rockchip,cpu = <&i2s0>; + rockchip,codec = <&max98357a &rt5514 &da7219>; + dmic-wakeup-delay-ms = <20>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..54aefab71f2cb1b3c4e276ff905a4fed8d8ab568 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-i2s.txt @@ -0,0 +1,49 @@ +* Rockchip I2S controller + +The I2S bus (Inter-IC sound bus) is a serial link for digital +audio data transfer between devices in the system. + +Required properties: + +- compatible: should be one of the following: + - "rockchip,rk3066-i2s": for rk3066 + - "rockchip,px30-i2s", "rockchip,rk3066-i2s": for px30 + - "rockchip,rk3036-i2s", "rockchip,rk3066-i2s": for rk3036 + - "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188 + - "rockchip,rk3228-i2s", "rockchip,rk3066-i2s": for rk3228 + - "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288 + - "rockchip,rk3328-i2s", "rockchip,rk3066-i2s": for rk3328 + - "rockchip,rk3366-i2s", "rockchip,rk3066-i2s": for rk3366 + - "rockchip,rk3368-i2s", "rockchip,rk3066-i2s": for rk3368 + - "rockchip,rk3399-i2s", "rockchip,rk3066-i2s": for rk3399 +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: should contain the I2S interrupt. +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should include "tx" and "rx". +- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +- clock-names: should contain the following: + - "i2s_hclk": clock for I2S BUS + - "i2s_clk" : clock for I2S controller +- rockchip,playback-channels: max playback channels, if not set, 8 channels default. +- rockchip,capture-channels: max capture channels, if not set, 2 channels default. + +Required properties for controller which support multi channels +playback/capture: + +- rockchip,grf: the phandle of the syscon node for GRF register. + +Example for rk3288 I2S controller: + +i2s@ff890000 { + compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s"; + reg = <0xff890000 0x10000>; + interrupts = ; + dmas = <&pdma1 0>, <&pdma1 1>; + dma-names = "tx", "rx"; + clock-names = "i2s_hclk", "i2s_clk"; + clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>; + rockchip,playback-channels = <8>; + rockchip,capture-channels = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-max98090.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-max98090.txt new file mode 100644 index 0000000000000000000000000000000000000000..a805aa99ad7513364d824e9428d44bf926f85e86 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-max98090.txt @@ -0,0 +1,19 @@ +ROCKCHIP with MAX98090 CODEC + +Required properties: +- compatible: "rockchip,rockchip-audio-max98090" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the MAX98090 audio codec +- rockchip,headset-codec: The phandle of Ext chip for jack detection + +Example: + +sound { + compatible = "rockchip,rockchip-audio-max98090"; + rockchip,model = "ROCKCHIP-I2S"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&max98090>; + rockchip,headset-codec = <&headsetcodec>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-rt5645.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-rt5645.txt new file mode 100644 index 0000000000000000000000000000000000000000..411a62b3ff4140d60c11d552428fe3e03f55ebf0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-rt5645.txt @@ -0,0 +1,17 @@ +ROCKCHIP with RT5645/RT5650 CODECS + +Required properties: +- compatible: "rockchip,rockchip-audio-rt5645" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the RT5645/RT5650 audio codec + +Example: + +sound { + compatible = "rockchip,rockchip-audio-rt5645"; + rockchip,model = "ROCKCHIP-I2S"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&rt5645>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-spdif.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-spdif.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec20c1271e929c17e8c24e736989cdbbd4ec9ce9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rockchip-spdif.txt @@ -0,0 +1,45 @@ +* Rockchip SPDIF transceiver + +The S/PDIF audio block is a stereo transceiver that allows the +processor to receive and transmit digital audio via an coaxial cable or +a fibre cable. + +Required properties: + +- compatible: should be one of the following: + - "rockchip,rk3066-spdif" + - "rockchip,rk3188-spdif" + - "rockchip,rk3228-spdif" + - "rockchip,rk3288-spdif" + - "rockchip,rk3328-spdif" + - "rockchip,rk3366-spdif" + - "rockchip,rk3368-spdif" + - "rockchip,rk3399-spdif" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: should contain the SPDIF interrupt. +- dmas: DMA specifiers for tx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should be "tx" +- clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. +- clock-names: should contain following: + - "hclk": clock for SPDIF controller + - "mclk" : clock for SPDIF bus + +Required properties on RK3288: + - rockchip,grf: the phandle of the syscon node for the general register + file (GRF) + +Example for the rk3188 SPDIF controller: + +spdif: spdif@1011e000 { + compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif"; + reg = <0x1011e000 0x2000>; + interrupts = ; + dmas = <&dmac1_s 8>; + dma-names = "tx"; + clock-names = "hclk", "mclk"; + clocks = <&cru HCLK_SPDIF>, <&cru SCLK_SPDIF>; + #sound-dai-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rohm,bd28623.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rohm,bd28623.txt new file mode 100644 index 0000000000000000000000000000000000000000..d84557c2686ee1a661467bbac3e28b0ed90331a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rohm,bd28623.txt @@ -0,0 +1,29 @@ +ROHM BD28623MUV Class D speaker amplifier for digital input + +This codec does not have any control buses such as I2C, it detect format and +rate of I2S signal automatically. It has two signals that can be connected +to GPIOs: reset and mute. + +Required properties: +- compatible : should be "rohm,bd28623" +- #sound-dai-cells: should be 0. +- VCCA-supply : regulator phandle for the VCCA supply +- VCCP1-supply : regulator phandle for the VCCP1 supply +- VCCP2-supply : regulator phandle for the VCCP2 supply + +Optional properties: +- reset-gpios : GPIO specifier for the active low reset line +- mute-gpios : GPIO specifier for the active low mute line + +Example: + + codec { + compatible = "rohm,bd28623"; + #sound-dai-cells = <0>; + + VCCA-supply = <&vcc_reg>; + VCCP1-supply = <&vcc_reg>; + VCCP2-supply = <&vcc_reg>; + reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>; + mute-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt274.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt274.txt new file mode 100644 index 0000000000000000000000000000000000000000..791a1bd767b9166e9330bf9a0fc4f90dfcfc62b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt274.txt @@ -0,0 +1,33 @@ +RT274 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt274". + +- reg : The I2C address of the device. + +Optional properties: + +- interrupts : The CODEC's interrupt output. + + +Pins on the device (for linking into audio routes) for RT274: + + * DMIC1 Pin + * DMIC2 Pin + * MIC + * LINE1 + * LINE2 + * HPO Pin + * SPDIF + * LINE3 + +Example: + +rt274: codec@1c { + compatible = "realtek,rt274"; + reg = <0x1c>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5514.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5514.txt new file mode 100644 index 0000000000000000000000000000000000000000..d2cc171f22f2aedd918ad75df8bb2ca6daa51bd4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5514.txt @@ -0,0 +1,37 @@ +RT5514 audio CODEC + +This device supports both I2C and SPI. + +Required properties: + +- compatible : "realtek,rt5514". + +- reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC +- clock-names: Should be "mclk" + +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. + +- realtek,dmic-init-delay-ms + Set the DMIC initial delay (ms) to wait it ready for I2C. + +Pins on the device (for linking into audio routes) for I2C: + + * DMIC1L + * DMIC1R + * DMIC2L + * DMIC2R + * AMICL + * AMICR + +Example: + +rt5514: codec@57 { + compatible = "realtek,rt5514"; + reg = <0x57>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5616.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5616.txt new file mode 100644 index 0000000000000000000000000000000000000000..540a4bf252e48eb4dcce34061b0b9ee537ab0d23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5616.txt @@ -0,0 +1,32 @@ +RT5616 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5616". + +- reg : The I2C address of the device. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC. + +- clock-names: Should be "mclk". + +Pins on the device (for linking into audio routes) for RT5616: + + * IN1P + * IN2P + * IN2N + * LOUTL + * LOUTR + * HPOL + * HPOR + +Example: + +rt5616: codec@1b { + compatible = "realtek,rt5616"; + reg = <0x1b>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5631.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5631.txt new file mode 100644 index 0000000000000000000000000000000000000000..92b986ca337bf82ad048106e4157aea981be4c7a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5631.txt @@ -0,0 +1,48 @@ +ALC5631/RT5631 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "realtek,alc5631" or "realtek,rt5631" + + - reg : the I2C address of the device. + +Pins on the device (for linking into audio routes): + + * SPK_OUT_R_P + * SPK_OUT_R_N + * SPK_OUT_L_P + * SPK_OUT_L_N + * HP_OUT_L + * HP_OUT_R + * AUX_OUT2_LP + * AUX_OUT2_RN + * AUX_OUT1_LP + * AUX_OUT1_RN + * AUX_IN_L_JD + * AUX_IN_R_JD + * MONO_IN_P + * MONO_IN_N + * MIC1_P + * MIC1_N + * MIC2_P + * MIC2_N + * MONO_OUT_P + * MONO_OUT_N + * MICBIAS1 + * MICBIAS2 + +Example: + +alc5631: alc5631@1a { + compatible = "realtek,alc5631"; + reg = <0x1a>; +}; + +or + +rt5631: rt5631@1a { + compatible = "realtek,rt5631"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5640.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5640.txt new file mode 100644 index 0000000000000000000000000000000000000000..e40e4893eed8014352cb81ab86c42f21da38e123 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5640.txt @@ -0,0 +1,94 @@ +RT5640/RT5639 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5640" or "realtek,rt5639". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC +- clock-names: Should be "mclk" + +- realtek,in1-differential +- realtek,in2-differential +- realtek,in3-differential + Boolean. Indicate MIC1/2/3 input are differential, rather than single-ended. + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using IN1P pin as dmic1 data pin + 2: using GPIO3 pin as dmic1 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using IN1N pin as dmic2 data pin + 2: using GPIO4 pin as dmic2 data pin + +- realtek,jack-detect-source + u32. Valid values: + 0: jack-detect is not used + 1: Use GPIO1 for jack-detect + 2: Use JD1_IN4P for jack-detect + 3: Use JD2_IN4N for jack-detect + 4: Use GPIO2 for jack-detect + 5: Use GPIO3 for jack-detect + 6: Use GPIO4 for jack-detect + +- realtek,jack-detect-not-inverted + bool. Normal jack-detect switches give an inverted signal, set this bool + in the rare case you've a jack-detect switch which is not inverted. + +- realtek,over-current-threshold-microamp + u32, micbias over-current detection threshold in µA, valid values are + 600, 1500 and 2000µA. + +- realtek,over-current-scale-factor + u32, micbias over-current detection scale-factor, valid values are: + 0: Scale current by 0.5 + 1: Scale current by 0.75 + 2: Scale current by 1.0 + 3: Scale current by 1.5 + +Pins on the device (for linking into audio routes) for RT5639/RT5640: + + * DMIC1 + * DMIC2 + * MICBIAS1 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * HPOL + * HPOR + * LOUTL + * LOUTR + * SPOLP + * SPOLN + * SPORP + * SPORN + +Additional pins on the device for RT5640: + + * MONOP + * MONON + +Example: + +rt5640 { + compatible = "realtek,rt5640"; + reg = <0x1c>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5645.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5645.txt new file mode 100644 index 0000000000000000000000000000000000000000..a03f9a872a71667ddc2ab9197ece633ee337af96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5645.txt @@ -0,0 +1,72 @@ +RT5650/RT5645 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5645" or "realtek,rt5650". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- hp-detect-gpios: + a GPIO spec for the external headphone detect pin. If jd-mode = 0, + we will get the JD status by getting the value of hp-detect-gpios. + +- realtek,in2-differential + Boolean. Indicate MIC2 input are differential, rather than single-ended. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using IN2P pin as dmic1 data pin + 2: using GPIO6 pin as dmic1 data pin + 3: using GPIO10 pin as dmic1 data pin + 4: using GPIO12 pin as dmic1 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using IN2N pin as dmic2 data pin + 2: using GPIO5 pin as dmic2 data pin + 3: using GPIO11 pin as dmic2 data pin + +-- realtek,jd-mode : The JD mode of rt5645/rt5650 + 0 : rt5645/rt5650 JD function is not used + 1 : Mode-0 (VDD=3.3V), two port jack detection + 2 : Mode-1 (VDD=3.3V), one port jack detection + 3 : Mode-2 (VDD=1.8V), one port jack detection + +Pins on the device (for linking into audio routes) for RT5645/RT5650: + + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * Haptic Generator + * HPOL + * HPOR + * LOUTL + * LOUTR + * PDM1L + * PDM1R + * SPOL + * SPOR + +Example: + +codec: rt5650@1a { + compatible = "realtek,rt5650"; + reg = <0x1a>; + hp-detect-gpios = <&gpio 19 0>; + interrupt-parent = <&gpio>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + realtek,dmic-en = "true"; + realtek,en-jd-func = "true"; + realtek,jd-mode = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5651.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5651.txt new file mode 100644 index 0000000000000000000000000000000000000000..a41199a5cd79b5225b2b732bacfef782d9286d54 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5651.txt @@ -0,0 +1,58 @@ +RT5651 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5651". + +- reg : The I2C address of the device. + +Optional properties: + +- realtek,in2-differential + Boolean. Indicate MIC2 input are differential, rather than single-ended. + +- realtek,dmic-en + Boolean. true if dmic is used. + +- realtek,jack-detect-source + u32. Valid values: + 1: Use JD1_1 pin for jack-detect + 2: Use JD1_2 pin for jack-detect + 3: Use JD2 pin for jack-detect + +- realtek,over-current-threshold-microamp + u32, micbias over-current detection threshold in µA, valid values are + 600, 1500 and 2000µA. + +- realtek,over-current-scale-factor + u32, micbias over-current detection scale-factor, valid values are: + 0: Scale current by 0.5 + 1: Scale current by 0.75 + 2: Scale current by 1.0 + 3: Scale current by 1.5 + +Pins on the device (for linking into audio routes) for RT5651: + + * DMIC L1 + * DMIC R1 + * IN1P + * IN2P + * IN2N + * IN3P + * HPOL + * HPOR + * LOUTL + * LOUTR + * PDML + * PDMR + +Example: + +rt5651: codec@1a { + compatible = "realtek,rt5651"; + reg = <0x1a>; + realtek,dmic-en = "true"; + realtek,in2-diff = "false"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5659.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5659.txt new file mode 100644 index 0000000000000000000000000000000000000000..1766e0543fc51b85ee045eba78fe72e4b62f7a58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5659.txt @@ -0,0 +1,78 @@ +RT5659/RT5658 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5659" or "realtek,rt5658". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC +- clock-names: Should be "mclk" + +- realtek,in1-differential +- realtek,in3-differential +- realtek,in4-differential + Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using IN2N pin as dmic1 data pin + 2: using GPIO5 pin as dmic1 data pin + 3: using GPIO9 pin as dmic1 data pin + 4: using GPIO11 pin as dmic1 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using IN2P pin as dmic2 data pin + 2: using GPIO6 pin as dmic2 data pin + 3: using GPIO10 pin as dmic2 data pin + 4: using GPIO12 pin as dmic2 data pin + +- realtek,jd-src + 0: No JD is used + 1: using JD3 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. +- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin. + +Pins on the device (for linking into audio routes) for RT5659/RT5658: + + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * IN4P + * IN4N + * HPOL + * HPOR + * SPOL + * SPOR + * LOUTL + * LOUTR + * MONOOUT + * PDML + * PDMR + * SPDIF + +Example: + +rt5659 { + compatible = "realtek,rt5659"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5660.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5660.txt new file mode 100644 index 0000000000000000000000000000000000000000..30be5f9219301205466cb8a4b88089c4ef12e610 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5660.txt @@ -0,0 +1,47 @@ +RT5660 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5660". + +- reg : The I2C address of the device. + +Optional properties: + +- clocks: The phandle of the master clock to the CODEC +- clock-names: Should be "mclk" + +- realtek,in1-differential +- realtek,in3-differential + Boolean. Indicate MIC1/3 input are differential, rather than single-ended. + +- realtek,poweroff-in-suspend + Boolean. If the codec will be powered off in suspend, the resume should be + added delay time for waiting codec power ready. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using GPIO2 pin as dmic1 data pin + 2: using IN1P pin as dmic1 data pin + +Pins on the device (for linking into audio routes) for RT5660: + + * DMIC L1 + * DMIC R1 + * IN1P + * IN1N + * IN2P + * IN3P + * IN3N + * SPO + * LOUTL + * LOUTR + +Example: + +rt5660 { + compatible = "realtek,rt5660"; + reg = <0x1c>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5663.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5663.txt new file mode 100644 index 0000000000000000000000000000000000000000..23386446c63d6fde5b63c35b8badd989a8ada56b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5663.txt @@ -0,0 +1,54 @@ +RT5663 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5663". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- "realtek,dc_offset_l_manual" +- "realtek,dc_offset_r_manual" +- "realtek,dc_offset_l_manual_mic" +- "realtek,dc_offset_r_manual_mic" + Based on the different PCB layout, add the manual offset value to + compensate the DC offset for each L and R channel, and they are different + between headphone and headset. +- "realtek,impedance_sensing_num" + The matrix row number of the impedance sensing table. + If the value is 0, it means the impedance sensing is not supported. +- "realtek,impedance_sensing_table" + The matrix rows of the impedance sensing table are consisted by impedance + minimum, impedance maximun, volume, DC offset w/o and w/ mic of each L and + R channel accordingly. Example is shown as following. + < 0 300 7 0xffd160 0xffd1c0 0xff8a10 0xff8ab0 + 301 65535 4 0xffe470 0xffe470 0xffb8e0 0xffb8e0> + The first and second column are defined for the impedance range. If the + detected impedance value is in the range, then the volume value of the + third column will be set to codec. In our codec design, each volume value + should compensate different DC offset to avoid the pop sound, and it is + also different between headphone and headset. In the example, the + "realtek,impedance_sensing_num" is 2. It means that there are 2 ranges of + impedance in the impedance sensing function. + +Pins on the device (for linking into audio routes) for RT5663: + + * IN1P + * IN1N + * IN2P + * IN2N + * HPOL + * HPOR + +Example: + +rt5663: codec@12 { + compatible = "realtek,rt5663"; + reg = <0x12>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5665.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5665.txt new file mode 100644 index 0000000000000000000000000000000000000000..8df1705069863c1261a4b80866b6bf040cdbea32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5665.txt @@ -0,0 +1,68 @@ +RT5665/RT5666 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5665", "realtek,rt5666". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- realtek,in1-differential +- realtek,in2-differential +- realtek,in3-differential +- realtek,in4-differential + Boolean. Indicate MIC1/2/3/4 input are differential, rather than single-ended. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using GPIO4 pin as dmic1 data pin + 2: using IN2N pin as dmic2 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using GPIO5 pin as dmic2 data pin + 2: using IN2P pin as dmic2 data pin + +- realtek,jd-src + 0: No JD is used + 1: using JD1 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. + +Pins on the device (for linking into audio routes) for RT5659/RT5658: + + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * IN4P + * IN4N + * HPOL + * HPOR + * LOUTL + * LOUTR + * MONOOUT + * PDML + * PDMR + +Example: + +rt5659 { + compatible = "realtek,rt5665"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5668.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5668.txt new file mode 100644 index 0000000000000000000000000000000000000000..c88b96e7764b78ae850d3a451cfb40ece40d361c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5668.txt @@ -0,0 +1,50 @@ +RT5668B audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5668b" + +- reg : The I2C address of the device. + +Optional properties: + +- interrupts : The CODEC's interrupt output. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using GPIO2 pin as dmic1 data pin + 2: using GPIO5 pin as dmic1 data pin + +- realtek,dmic1-clk-pin + 0: using GPIO1 pin as dmic1 clock pin + 1: using GPIO3 pin as dmic1 clock pin + +- realtek,jd-src + 0: No JD is used + 1: using JD1 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. + +Pins on the device (for linking into audio routes) for RT5668B: + + * DMIC L1 + * DMIC R1 + * IN1P + * HPOL + * HPOR + +Example: + +rt5668 { + compatible = "realtek,rt5668b"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + realtek,dmic1-data-pin = <1>; + realtek,dmic1-clk-pin = <1>; + realtek,jd-src = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5677.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5677.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b3c13d206ffed5150ac78f0beefb159fc44eaba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5677.txt @@ -0,0 +1,78 @@ +RT5677 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5677". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +- gpio-controller : Indicates this device is a GPIO controller. + +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + +Optional properties: + +- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. +- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low. + +- realtek,in1-differential +- realtek,in2-differential +- realtek,lout1-differential +- realtek,lout2-differential +- realtek,lout3-differential + Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, + rather than single-ended. + +- realtek,gpio-config + Array of six 8bit elements that configures GPIO. + 0 - floating (reset value) + 1 - pull down + 2 - pull up + +- realtek,jd1-gpio + Configures GPIO Mic Jack detection 1. + Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively. + +- realtek,jd2-gpio +- realtek,jd3-gpio + Configures GPIO Mic Jack detection 2 and 3. + Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively. + +Pins on the device (for linking into audio routes): + + * IN1P + * IN1N + * IN2P + * IN2N + * MICBIAS1 + * DMIC1 + * DMIC2 + * DMIC3 + * DMIC4 + * LOUT1 + * LOUT2 + * LOUT3 + +Example: + +rt5677 { + compatible = "realtek,rt5677"; + reg = <0x2c>; + interrupt-parent = <&gpio>; + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + realtek,pow-ldo2-gpio = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; + realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>; + realtek,in1-differential = "true"; + realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ + realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/rt5682.txt b/arch/arm64/boot/dts/vendor/bindings/sound/rt5682.txt new file mode 100644 index 0000000000000000000000000000000000000000..312e9a129530cf3a2f6a45d9224968a67786a619 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/rt5682.txt @@ -0,0 +1,50 @@ +RT5682 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5682" or "realtek,rt5682i" + +- reg : The I2C address of the device. + +Optional properties: + +- interrupts : The CODEC's interrupt output. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using GPIO2 pin as dmic1 data pin + 2: using GPIO5 pin as dmic1 data pin + +- realtek,dmic1-clk-pin + 0: using GPIO1 pin as dmic1 clock pin + 1: using GPIO3 pin as dmic1 clock pin + +- realtek,jd-src + 0: No JD is used + 1: using JD1 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. + +Pins on the device (for linking into audio routes) for RT5682: + + * DMIC L1 + * DMIC R1 + * IN1P + * HPOL + * HPOR + +Example: + +rt5682 { + compatible = "realtek,rt5682i"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + realtek,dmic1-data-pin = <1>; + realtek,dmic1-clk-pin = <1>; + realtek,jd-src = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/samsung,odroid.txt b/arch/arm64/boot/dts/vendor/bindings/sound/samsung,odroid.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9da2200e1737cc821e2a624ac75ce0df9ff1190 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/samsung,odroid.txt @@ -0,0 +1,54 @@ +Samsung Exynos Odroid XU3/XU4 audio complex with MAX98090 codec + +Required properties: + + - compatible - "hardkernel,odroid-xu3-audio" - for Odroid XU3 board, + "hardkernel,odroid-xu4-audio" - for Odroid XU4 board (deprecated), + "samsung,odroid-xu3-audio" - for Odroid XU3 board (deprecated), + "samsung,odroid-xu4-audio" - for Odroid XU4 board (deprecated) + - model - the user-visible name of this sound complex + - clocks - should contain entries matching clock names in the clock-names + property + - samsung,audio-widgets - this property specifies off-codec audio elements + like headphones or speakers, for details see widgets.txt + - samsung,audio-routing - a list of the connections between audio + components; each entry is a pair of strings, the first being the + connection's sink, the second being the connection's source; + valid names for sources and sinks are the MAX98090's pins (as + documented in its binding), and the jacks on the board + + For Odroid X2: + "Headphone Jack", "Mic Jack", "DMIC" + + For Odroid U3, XU3: + "Headphone Jack", "Speakers" + + For Odroid XU4: + no entries + +Required sub-nodes: + + - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S + controller + - 'codec' subnode with a 'sound-dai' property containing list of phandles + to the CODEC nodes, first entry must be corresponding to the MAX98090 + CODEC and the second entry must be the phandle of the HDMI IP block node + +Example: + +sound { + compatible = "hardkernel,odroid-xu3-audio"; + model = "Odroid-XU3"; + samsung,audio-routing = + "Headphone Jack", "HPL", + "Headphone Jack", "HPR", + "IN1", "Mic Jack", + "Mic Jack", "MICBIAS"; + + cpu { + sound-dai = <&i2s0 0>; + }; + codec { + sound-dai = <&hdmi>, <&max98090>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/samsung,smdk-wm8994.txt b/arch/arm64/boot/dts/vendor/bindings/sound/samsung,smdk-wm8994.txt new file mode 100644 index 0000000000000000000000000000000000000000..4686646fb122b1a23c85255104c63d9ae6ddb606 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/samsung,smdk-wm8994.txt @@ -0,0 +1,14 @@ +Samsung SMDK audio complex + +Required properties: +- compatible : "samsung,smdk-wm8994" +- samsung,i2s-controller: The phandle of the Samsung I2S0 controller +- samsung,audio-codec: The phandle of the WM8994 audio codec +Example: + +sound { + compatible = "samsung,smdk-wm8994"; + + samsung,i2s-controller = <&i2s0>; + samsung,audio-codec = <&wm8994>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/samsung,tm2-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/samsung,tm2-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..f5ccc12ddc00e28dccd626bcc5de637fdafc8c52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/samsung,tm2-audio.txt @@ -0,0 +1,42 @@ +Samsung Exynos5433 TM2(E) audio complex with WM5110 codec + +Required properties: + + - compatible : "samsung,tm2-audio" + - model : the user-visible name of this sound complex + - audio-codec : the first entry should be phandle of the wm5110 audio + codec node, as described in ../mfd/arizona.txt; + the second entry should be phandle of the HDMI + transmitter node + - i2s-controller : the list of phandle and argument tuples pointing to + I2S controllers, the first entry should be I2S0 and + the second one I2S1 + - audio-amplifier : the phandle of the MAX98504 amplifier + - samsung,audio-routing : a list of the connections between audio components; + each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source; valid names for sources and sinks are the + WM5110's and MAX98504's pins and the jacks on the + board: HP, SPK, Main Mic, Sub Mic, Third Mic, + Headset Mic + - mic-bias-gpios : GPIO pin that enables the Main Mic bias regulator + + +Example: + +sound { + compatible = "samsung,tm2-audio"; + audio-codec = <&wm5110>, <&hdmi>; + i2s-controller = <&i2s0 0>, <&i2s1 0>; + audio-amplifier = <&max98504>; + mic-bias-gpios = <&gpr3 2 0>; + model = "wm5110"; + samsung,audio-routing = + "HP", "HPOUT1L", + "HP", "HPOUT1R", + "SPK", "SPKOUT", + "SPKOUT", "HPOUT2L", + "SPKOUT", "HPOUT2R", + "Main Mic", "MICBIAS2", + "IN1R", "Main Mic"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/samsung-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/samsung-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..a88cb00fa09660c035db33f7306b977e3687d636 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/samsung-i2s.txt @@ -0,0 +1,84 @@ +* Samsung I2S controller + +Required SoC Specific Properties: + +- compatible : should be one of the following. + - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S. + - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with + secondary fifo, s/w reset control and internal mux for root clk src. + - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for + playback, stereo channel capture, secondary fifo using internal + or external dma, s/w reset control, internal mux for root clk src + and 7.1 channel TDM support for playback. TDM (Time division multiplexing) + is to allow transfer of multiple channel audio data on single data line. + - samsung,exynos7-i2s: with all the available features of exynos5 i2s, + exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo + with only external dma and more no.of root clk sampling frequencies. + - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports + stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with + slightly modified bit offsets. + +- reg: physical base address of the controller and length of memory mapped + region. +- dmas: list of DMA controller phandle and DMA request line ordered pairs. +- dma-names: identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. +- clocks: Handle to iis clock and RCLK source clk. +- clock-names: + i2s0 uses some base clocks from CMU and some are from audio subsystem internal + clock controller. The clock names for i2s0 should be "iis", "i2s_opclk0" and + "i2s_opclk1" as shown in the example below. + i2s1 and i2s2 uses clocks from CMU. The clock names for i2s1 and i2s2 should + be "iis" and "i2s_opclk0". + "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root + clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2 + doesn't have any such mux. +- #clock-cells: should be 1, this property must be present if the I2S device + is a clock provider in terms of the common clock bindings, described in + ../clock/clock-bindings.txt. +- clock-output-names (deprecated): from the common clock bindings, names of + the CDCLK I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1", + "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices respectively. + +There are following clocks available at the I2S device nodes: + CLK_I2S_CDCLK - the CDCLK (CODECLKO) gate clock, + CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the + IISPSR register), + CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in + IISMOD register). + +Refer to the SoC datasheet for availability of the above clocks. +The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available +in the IIS Multi Audio Interface. + +Note: Old DTs may not have the #clock-cells property and then not use the I2S +node as a clock supplier. + +Optional SoC Specific Properties: + +- samsung,idma-addr: Internal DMA register base address of the audio + sub system(used in secondary sound source). +- pinctrl-0: Should specify pin control groups used for this controller. +- pinctrl-names: Should contain only one value - "default". +- #sound-dai-cells: should be 1. + + +Example: + +i2s0: i2s@3830000 { + compatible = "samsung,s5pv210-i2s"; + reg = <0x03830000 0x100>; + dmas = <&pdma0 10 + &pdma0 9 + &pdma0 8>; + dma-names = "tx", "rx", "tx-sec"; + clocks = <&clock_audss EXYNOS_I2S_BUS>, + <&clock_audss EXYNOS_I2S_BUS>, + <&clock_audss EXYNOS_SCLK_I2S>; + clock-names = "iis", "i2s_opclk0", "i2s_opclk1"; + #clock-cells = <1>; + samsung,idma-addr = <0x03000000>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0_bus>; + #sound-dai-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sgtl5000.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sgtl5000.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c58f724396ab0881e851eaef1ed3a5902c14115 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sgtl5000.txt @@ -0,0 +1,51 @@ +* Freescale SGTL5000 Stereo Codec + +Required properties: +- compatible : "fsl,sgtl5000". + +- reg : the I2C address of the device + +- #sound-dai-cells: must be equal to 0 + +- clocks : the clock provider of SYS_MCLK + +- VDDA-supply : the regulator provider of VDDA + +- VDDIO-supply: the regulator provider of VDDIO + +Optional properties: + +- VDDD-supply : the regulator provider of VDDD + +- micbias-resistor-k-ohms : the bias resistor to be used in kOhms + The resistor can take values of 2k, 4k or 8k. + If set to 0 it will be off. + If this node is not mentioned or if the value is unknown, then + micbias resistor is set to 4K. + +- micbias-voltage-m-volts : the bias voltage to be used in mVolts + The voltage can take values from 1.25V to 3V by 250mV steps + If this node is not mentioned or the value is unknown, then + the value is set to 1.25V. + +- lrclk-strength: the LRCLK pad strength. Possible values are: +0, 1, 2 and 3 as per the table below: + +VDDIO 1.8V 2.5V 3.3V +0 = Disable +1 = 1.66 mA 2.87 mA 4.02 mA +2 = 3.33 mA 5.74 mA 8.03 mA +3 = 4.99 mA 8.61 mA 12.05 mA + +Example: + +sgtl5000: codec@a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; + #sound-dai-cells = <0>; + clocks = <&clks 150>; + micbias-resistor-k-ohms = <2>; + micbias-voltage-m-volts = <2250>; + VDDA-supply = <®_3p3v>; + VDDIO-supply = <®_3p3v>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/simple-amplifier.txt b/arch/arm64/boot/dts/vendor/bindings/sound/simple-amplifier.txt new file mode 100644 index 0000000000000000000000000000000000000000..8647edae7af038a64d2eadf5a1d6a403ecc2cacf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/simple-amplifier.txt @@ -0,0 +1,12 @@ +Simple Amplifier Audio Driver + +Required properties: +- compatible : "dioo,dio2125" or "simple-audio-amplifier" +- enable-gpios : the gpio connected to the enable pin of the simple amplifier + +Example: + +amp: analog-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio GPIOH_3 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/simple-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/simple-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..a4c72d09cd45718e6ce5197d6f8fce1e782deeac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/simple-card.txt @@ -0,0 +1,212 @@ +Simple-Card: + +Simple-Card specifies audio DAI connections of SoC <-> codec. + +Required properties: + +- compatible : "simple-audio-card" + +Optional properties: + +- simple-audio-card,name : User specified audio sound card name, one string + property. +- simple-audio-card,widgets : Please refer to widgets.txt. +- simple-audio-card,routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. +- simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec + mclk. When defined, mclk-fs property defined in + dai-link sub nodes are ignored. +- simple-audio-card,hp-det-gpio : Reference to GPIO that signals when + headphones are attached. +- simple-audio-card,mic-det-gpio : Reference to GPIO that signals when + a microphone is attached. +- simple-audio-card,aux-devs : List of phandles pointing to auxiliary devices, such + as amplifiers, to be added to the sound card. + +Optional subnodes: + +- simple-audio-card,dai-link : Container for dai-link level + properties and the CPU and CODEC + sub-nodes. This container may be + omitted when the card has only one + DAI link. See the examples and the + section below. + +Dai-link subnode properties and subnodes: + +If dai-link subnode is omitted and the subnode properties are directly +under "sound"-node the subnode property and subnode names have to be +prefixed with "simple-audio-card,"-prefix. + +Required dai-link subnodes: + +- cpu : CPU sub-node +- codec : CODEC sub-node + +Optional dai-link subnode properties: + +- format : CPU/CODEC common audio format. + "i2s", "right_j", "left_j" , "dsp_a" + "dsp_b", "ac97", "pdm", "msb", "lsb" +- frame-master : Indicates dai-link frame master. + phandle to a cpu or codec subnode. +- bitclock-master : Indicates dai-link bit clock master. + phandle to a cpu or codec subnode. +- bitclock-inversion : bool property. Add this if the + dai-link uses bit clock inversion. +- frame-inversion : bool property. Add this if the + dai-link uses frame clock inversion. +- mclk-fs : Multiplication factor between stream + rate and codec mclk, applied only for + the dai-link. + +For backward compatibility the frame-master and bitclock-master +properties can be used as booleans in codec subnode to indicate if the +codec is the dai-link frame or bit clock master. In this case there +should be no dai-link node, the same properties should not be present +at sound-node level, and the bitclock-inversion and frame-inversion +properties should also be placed in the codec node if needed. + +Required CPU/CODEC subnodes properties: + +- sound-dai : phandle and port of CPU/CODEC + +Optional CPU/CODEC subnodes properties: + +- dai-tdm-slot-num : Please refer to tdm-slot.txt. +- dai-tdm-slot-width : Please refer to tdm-slot.txt. +- clocks / system-clock-frequency : specify subnode's clock if needed. + it can be specified via "clocks" if system has + clock node (= common clock), or "system-clock-frequency" + (if system doens't support common clock) + If a clock is specified, it is + enabled with clk_prepare_enable() + in dai startup() and disabled with + clk_disable_unprepare() in dai + shutdown(). + If a clock is specified and a + multiplication factor is given with + mclk-fs, the clock will be set to the + calculated mclk frequency when the + stream starts. +- system-clock-direction-out : specifies clock direction as 'out' on + initialization. It is useful for some aCPUs with + fixed clocks. + +Example 1 - single DAI link: + +sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "VF610-Tower-Sound-Card"; + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&dailink0_master>; + simple-audio-card,frame-master = <&dailink0_master>; + simple-audio-card,widgets = + "Microphone", "Microphone Jack", + "Headphone", "Headphone Jack", + "Speaker", "External Speaker"; + simple-audio-card,routing = + "MIC_IN", "Microphone Jack", + "Headphone Jack", "HP_OUT", + "External Speaker", "LINE_OUT"; + + simple-audio-card,cpu { + sound-dai = <&sh_fsi2 0>; + }; + + dailink0_master: simple-audio-card,codec { + sound-dai = <&ak4648>; + clocks = <&osc>; + }; +}; + +&i2c0 { + ak4648: ak4648@12 { + #sound-dai-cells = <0>; + compatible = "asahi-kasei,ak4648"; + reg = <0x12>; + }; +}; + +sh_fsi2: sh_fsi2@ec230000 { + #sound-dai-cells = <1>; + compatible = "renesas,sh_fsi2"; + reg = <0xec230000 0x400>; + interrupt-parent = <&gic>; + interrupts = <0 146 0x4>; +}; + +Example 2 - many DAI links: + +sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "Cubox Audio"; + + simple-audio-card,dai-link@0 { /* I2S - HDMI */ + reg = <0>; + format = "i2s"; + cpu { + sound-dai = <&audio1 0>; + }; + codec { + sound-dai = <&tda998x 0>; + }; + }; + + simple-audio-card,dai-link@1 { /* S/PDIF - HDMI */ + reg = <1>; + cpu { + sound-dai = <&audio1 1>; + }; + codec { + sound-dai = <&tda998x 1>; + }; + }; + + simple-audio-card,dai-link@2 { /* S/PDIF - S/PDIF */ + reg = <2>; + cpu { + sound-dai = <&audio1 1>; + }; + codec { + sound-dai = <&spdif_codec>; + }; + }; +}; + +Example 3 - route audio from IMX6 SSI2 through TLV320DAC3100 codec +through TPA6130A2 amplifier to headphones: + +&i2c0 { + codec: tlv320dac3100@18 { + compatible = "ti,tlv320dac3100"; + ... + } + + amp: tpa6130a2@60 { + compatible = "ti,tpa6130a2"; + ... + } +} + +sound { + compatible = "simple-audio-card"; + ... + simple-audio-card,widgets = + "Headphone", "Headphone Jack"; + simple-audio-card,routing = + "Headphone Jack", "HPLEFT", + "Headphone Jack", "HPRIGHT", + "LEFTIN", "HPL", + "RIGHTIN", "HPR"; + simple-audio-card,aux-devs = <&>; + simple-audio-card,cpu { + sound-dai = <&ssi2>; + }; + simple-audio-card,codec { + sound-dai = <&codec>; + clocks = ... + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/simple-scu-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/simple-scu-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..32f8dbce5241d4a9ad612c7c47e0890fc3438625 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/simple-scu-card.txt @@ -0,0 +1,94 @@ +ASoC Simple SCU Sound Card + +Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM". +For example, you can use this driver if you want to exchange sampling rate convert, +Mixing, etc... + +Required properties: + +- compatible : "simple-scu-audio-card" + "renesas,rsrc-card" +Optional properties: + +- simple-audio-card,name : see simple-audio-card.txt +- simple-audio-card,cpu : see simple-audio-card.txt +- simple-audio-card,codec : see simple-audio-card.txt + +Optional subnode properties: + +- simple-audio-card,format : see simple-audio-card.txt +- simple-audio-card,frame-master : see simple-audio-card.txt +- simple-audio-card,bitclock-master : see simple-audio-card.txt +- simple-audio-card,bitclock-inversion : see simple-audio-card.txt +- simple-audio-card,frame-inversion : see simple-audio-card.txt +- simple-audio-card,convert-rate : platform specified sampling rate convert +- simple-audio-card,convert-channels : platform specified converted channel size (2 - 8 ch) +- simple-audio-card,prefix : see routing +- simple-audio-card,widgets : Please refer to widgets.txt. +- simple-audio-card,routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources. + use audio-prefix if some components is using same sink/sources naming. + it can be used if compatible was "renesas,rsrc-card"; + +Required CPU/CODEC subnodes properties: + +- sound-dai : see simple-audio-card.txt + +Optional CPU/CODEC subnodes properties: + +- clocks / system-clock-frequency : see simple-audio-card.txt + +Example 1. Sampling Rate Conversion + +sound { + compatible = "simple-scu-audio-card"; + + simple-audio-card,name = "rsnd-ak4643"; + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + simple-audio-card,convert-rate = <48000>; + + simple-audio-card,prefix = "ak4642"; + simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", + "DAI0 Capture", "ak4642 Capture"; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&ak4643>; + system-clock-frequency = <11289600>; + }; +}; + +Example 2. 2 CPU 1 Codec (Mixing) + +sound { + compatible = "simple-scu-audio-card"; + + simple-audio-card,name = "rsnd-ak4643"; + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&dpcmcpu>; + simple-audio-card,frame-master = <&dpcmcpu>; + + simple-audio-card,prefix = "ak4642"; + simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback", + "ak4642 Playback", "DAI1 Playback"; + + dpcmcpu: cpu@0 { + sound-dai = <&rcar_sound 0>; + }; + + cpu@1 { + sound-dai = <&rcar_sound 1>; + }; + + codec { + sound-dai = <&ak4643>; + clocks = <&audio_clock>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio-codec.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio-codec.txt new file mode 100644 index 0000000000000000000000000000000000000000..062f5ec36f9b69fb3a8061642e041e5cd410d486 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio-codec.txt @@ -0,0 +1,17 @@ +SiRF internal audio CODEC + +Required properties: + + - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec" + + - reg : the register address of the device. + + - clocks: the clock of SiRF internal audio codec + +Example: + +audiocodec: audiocodec@b0040000 { + compatible = "sirf,atlas6-audio-codec"; + reg = <0xb0040000 0x10000>; + clocks = <&clks 27>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio-port.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio-port.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f66de3c8f0053a7f029feb135d0f53cd2d7a032 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio-port.txt @@ -0,0 +1,20 @@ +* SiRF SoC audio port + +Required properties: +- compatible: "sirf,audio-port" +- reg: Base address and size entries: +- dmas: List of DMA controller phandle and DMA request line ordered pairs. +- dma-names: Identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. + + One of the DMA channels will be responsible for transmission (should be + named "tx") and one for reception (should be named "rx"). + +Example: + +audioport: audioport@b0040000 { + compatible = "sirf,audio-port"; + reg = <0xb0040000 0x10000>; + dmas = <&dmac1 3>, <&dmac1 8>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio.txt new file mode 100644 index 0000000000000000000000000000000000000000..c88882ca3704a5b5fc3dcf56deb474f856931e96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-audio.txt @@ -0,0 +1,41 @@ +* SiRF atlas6 and prima2 internal audio codec and port based audio setups + +Required properties: +- compatible: "sirf,sirf-audio-card" +- sirf,audio-platform: phandle for the platform node +- sirf,audio-codec: phandle for the SiRF internal codec node + +Optional properties: +- hp-pa-gpios: Need to be present if the board need control external + headphone amplifier. +- spk-pa-gpios: Need to be present if the board need control external + speaker amplifier. +- hp-switch-gpios: Need to be present if the board capable to detect jack + insertion, removal. + +Available audio endpoints for the audio-routing table: + +Board connectors: + * Headset Stereophone + * Ext Spk + * Line In + * Mic + +SiRF internal audio codec pins: + * HPOUTL + * HPOUTR + * SPKOUT + * Ext Mic + * Mic Bias + +Example: + +sound { + compatible = "sirf,sirf-audio-card"; + sirf,audio-codec = <&audiocodec>; + sirf,audio-platform = <&audioport>; + hp-pa-gpios = <&gpio 44 0>; + spk-pa-gpios = <&gpio 46 0>; + hp-switch-gpios = <&gpio 45 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sirf-usp.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-usp.txt new file mode 100644 index 0000000000000000000000000000000000000000..02f85b32d3598333dafb94971c2ecf88ae4c8f20 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sirf-usp.txt @@ -0,0 +1,27 @@ +* SiRF SoC USP module + +Required properties: +- compatible: "sirf,prima2-usp-pcm" +- reg: Base address and size entries: +- dmas: List of DMA controller phandle and DMA request line ordered pairs. +- dma-names: Identifier string for each DMA request line in the dmas property. + These strings correspond 1:1 with the ordered pairs in dmas. + + One of the DMA channels will be responsible for transmission (should be + named "tx") and one for reception (should be named "rx"). + +- clocks: USP controller clock source +- pinctrl-names: Must contain a "default" entry. +- pinctrl-NNN: One property must exist for each entry in pinctrl-names. + +Example: +usp0: usp@b0080000 { + compatible = "sirf,prima2-usp-pcm"; + reg = <0xb0080000 0x10000>; + clocks = <&clks 28>; + dmas = <&dmac1 1>, <&dmac1 2>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&usp0_only_utfs_pins_a>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/snow.txt b/arch/arm64/boot/dts/vendor/bindings/sound/snow.txt new file mode 100644 index 0000000000000000000000000000000000000000..80fd9a87bb3fba53e03ef608b678686517f6172a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/snow.txt @@ -0,0 +1,31 @@ +Audio Binding for Snow boards + +Required properties: +- compatible : Can be one of the following, + "google,snow-audio-max98090" or + "google,snow-audio-max98091" or + "google,snow-audio-max98095" +- samsung,i2s-controller (deprecated): The phandle of the Samsung I2S controller +- samsung,audio-codec (deprecated): The phandle of the audio codec + +Required sub-nodes: + + - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S + controller + - 'codec' subnode with a 'sound-dai' property containing list of phandles + to the CODEC nodes, first entry must be the phandle of the MAX98090, + MAX98091 or MAX98095 CODEC (exact device type is indicated by the compatible + string) and the second entry must be the phandle of the HDMI IP block node + +Optional: +- samsung,model: The name of the sound-card + +Example: + +sound { + compatible = "google,snow-audio-max98095"; + + samsung,model = "Snow-I2S-MAX98095"; + samsung,i2s-controller = <&i2s0>; + samsung,audio-codec = <&max98095>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/soc-ac97link.txt b/arch/arm64/boot/dts/vendor/bindings/sound/soc-ac97link.txt new file mode 100644 index 0000000000000000000000000000000000000000..80152a87f239aa16d2f7d62944324e2a23c8b4de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/soc-ac97link.txt @@ -0,0 +1,28 @@ +AC97 link bindings + +These bindings can be included within any other device node. + +Required properties: + - pinctrl-names: Has to contain following states to setup the correct + pinmuxing for the used gpios: + "ac97-running": AC97-link is active + "ac97-reset": AC97-link reset state + "ac97-warm-reset": AC97-link warm reset state + - ac97-gpios: List of gpio phandles with args in the order ac97-sync, + ac97-sdata, ac97-reset + + +Example: + +ssi { + ... + + pinctrl-names = "default", "ac97-running", "ac97-reset", "ac97-warm-reset"; + pinctrl-0 = <&ac97link_running>; + pinctrl-1 = <&ac97link_running>; + pinctrl-2 = <&ac97link_reset>; + pinctrl-3 = <&ac97link_warm_reset>; + ac97-gpios = <&gpio3 20 0 &gpio3 22 0 &gpio3 28 0>; + + ... +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/spdif-receiver.txt b/arch/arm64/boot/dts/vendor/bindings/sound/spdif-receiver.txt new file mode 100644 index 0000000000000000000000000000000000000000..80f807bf8a1d1f068b0e19c187b79b6fa5365bd3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/spdif-receiver.txt @@ -0,0 +1,10 @@ +Device-Tree bindings for dummy spdif receiver + +Required properties: + - compatible: should be "linux,spdif-dir". + +Example node: + + codec: spdif-receiver { + compatible = "linux,spdif-dir"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/spdif-transmitter.txt b/arch/arm64/boot/dts/vendor/bindings/sound/spdif-transmitter.txt new file mode 100644 index 0000000000000000000000000000000000000000..55a85841dd8546fd82b0e3a0db418e257b42ab92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/spdif-transmitter.txt @@ -0,0 +1,10 @@ +Device-Tree bindings for dummy spdif transmitter + +Required properties: + - compatible: should be "linux,spdif-dit". + +Example node: + + codec: spdif-transmitter { + compatible = "linux,spdif-dit"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ssm2518.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ssm2518.txt new file mode 100644 index 0000000000000000000000000000000000000000..59381a778c7979bb56d7e494906641baf088f402 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ssm2518.txt @@ -0,0 +1,20 @@ +SSM2518 audio amplifier + +This device supports I2C only. + +Required properties: + - compatible : Must be "adi,ssm2518" + - reg : the I2C address of the device. This will either be 0x34 (ADDR pin low) + or 0x35 (ADDR pin high) + +Optional properties: + - gpios : GPIO connected to the nSD pin. If the property is not present it is + assumed that the nSD pin is hardwired to always on. + +Example: + + ssm2518: ssm2518@34 { + compatible = "adi,ssm2518"; + reg = <0x34>; + gpios = <&gpio 5 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ssm4567.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ssm4567.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec3d9e7004b59edb173d54ea715c807993b2da68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ssm4567.txt @@ -0,0 +1,15 @@ +Analog Devices SSM4567 audio amplifier + +This device supports I2C only. + +Required properties: + - compatible : Must be "adi,ssm4567" + - reg : the I2C address of the device. This will either be 0x34 (LR_SEL/ADDR connected to AGND), + 0x35 (LR_SEL/ADDR connected to IOVDD) or 0x36 (LR_SEL/ADDR open). + +Example: + + ssm4567: ssm4567@34 { + compatible = "adi,ssm4567"; + reg = <0x34>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,sta32x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,sta32x.txt new file mode 100644 index 0000000000000000000000000000000000000000..255de3ae5b2ff5e9cb58f33983b76e120fac0699 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,sta32x.txt @@ -0,0 +1,92 @@ +STA32X audio CODEC + +The driver for this device only supports I2C. + +Required properties: + + - compatible: "st,sta32x" + - reg: the I2C address of the device for I2C + - reset-gpios: a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - power-down-gpios: a GPIO spec for the power down pin. If specified, + it will be deasserted before communication to the codec + starts. + + - Vdda-supply: regulator spec, providing 3.3V + - Vdd3-supply: regulator spec, providing 3.3V + - Vcc-supply: regulator spec, providing 5V - 26V + +Optional properties: + + - st,output-conf: number, Selects the output configuration: + 0: 2-channel (full-bridge) power, 2-channel data-out + 1: 2 (half-bridge). 1 (full-bridge) on-board power + 2: 2 Channel (Full-Bridge) Power, 1 Channel FFX + 3: 1 Channel Mono-Parallel + If parameter is missing, mode 0 will be enabled. + This property has to be specified as '/bits/ 8' value. + + - st,ch1-output-mapping: Channel 1 output mapping + - st,ch2-output-mapping: Channel 2 output mapping + - st,ch3-output-mapping: Channel 3 output mapping + 0: Channel 1 + 1: Channel 2 + 2: Channel 3 + If parameter is missing, channel 1 is chosen. + This properties have to be specified as '/bits/ 8' values. + + - st,thermal-warning-recover: + If present, thermal warning recovery is enabled. + + - st,thermal-warning-adjustment: + If present, thermal warning adjustment is enabled. + + - st,fault-detect-recovery: + If present, then fault recovery will be enabled. + + - st,drop-compensation-ns: number + Only required for "st,ffx-power-output-mode" == + "variable-drop-compensation". + Specifies the drop compensation in nanoseconds. + The value must be in the range of 0..300, and only + multiples of 20 are allowed. Default is 140ns. + + - st,max-power-use-mpcc: + If present, then MPCC bits are used for MPC coefficients, + otherwise standard MPC coefficients are used. + + - st,max-power-corr: + If present, power bridge correction for THD reduction near maximum + power output is enabled. + + - st,am-reduction-mode: + If present, FFX mode runs in AM reduction mode, otherwise normal + FFX mode is used. + + - st,odd-pwm-speed-mode: + If present, PWM speed mode run on odd speed mode (341.3 kHz) on all + channels. If not present, normal PWM spped mode (384 kHz) will be used. + + - st,invalid-input-detect-mute: + If present, automatic invalid input detect mute is enabled. + +Example: + +codec: sta32x@38 { + compatible = "st,sta32x"; + reg = <0x1c>; + reset-gpios = <&gpio1 19 0>; + power-down-gpios = <&gpio1 16 0>; + st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel + // (full-bridge) power, + // 2-channel data-out + st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1 + st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1 + st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1 + st,max-power-correction; // enables power bridge + // correction for THD reduction + // near maximum power output + st,invalid-input-detect-mute; // mute if no valid digital + // audio signal is provided. +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,sta350.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,sta350.txt new file mode 100644 index 0000000000000000000000000000000000000000..307398ef2317d4a5f31937579a74c1409d1487df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,sta350.txt @@ -0,0 +1,131 @@ +STA350 audio CODEC + +The driver for this device only supports I2C. + +Required properties: + + - compatible: "st,sta350" + - reg: the I2C address of the device for I2C + - reset-gpios: a GPIO spec for the reset pin. If specified, it will be + deasserted before communication to the codec starts. + + - power-down-gpios: a GPIO spec for the power down pin. If specified, + it will be deasserted before communication to the codec + starts. + + - vdd-dig-supply: regulator spec, providing 3.3V + - vdd-pll-supply: regulator spec, providing 3.3V + - vcc-supply: regulator spec, providing 5V - 26V + +Optional properties: + + - st,output-conf: number, Selects the output configuration: + 0: 2-channel (full-bridge) power, 2-channel data-out + 1: 2 (half-bridge). 1 (full-bridge) on-board power + 2: 2 Channel (Full-Bridge) Power, 1 Channel FFX + 3: 1 Channel Mono-Parallel + If parameter is missing, mode 0 will be enabled. + This property has to be specified as '/bits/ 8' value. + + - st,ch1-output-mapping: Channel 1 output mapping + - st,ch2-output-mapping: Channel 2 output mapping + - st,ch3-output-mapping: Channel 3 output mapping + 0: Channel 1 + 1: Channel 2 + 2: Channel 3 + If parameter is missing, channel 1 is chosen. + This properties have to be specified as '/bits/ 8' values. + + - st,thermal-warning-recover: + If present, thermal warning recovery is enabled. + + - st,thermal-warning-adjustment: + If present, thermal warning adjustment is enabled. + + - st,fault-detect-recovery: + If present, then fault recovery will be enabled. + + - st,ffx-power-output-mode: string + The FFX power output mode selects how the FFX output timing is + configured. Must be one of these values: + - "drop-compensation" + - "tapered-compensation" + - "full-power-mode" + - "variable-drop-compensation" (default) + + - st,drop-compensation-ns: number + Only required for "st,ffx-power-output-mode" == + "variable-drop-compensation". + Specifies the drop compensation in nanoseconds. + The value must be in the range of 0..300, and only + multiples of 20 are allowed. Default is 140ns. + + - st,overcurrent-warning-adjustment: + If present, overcurrent warning adjustment is enabled. + + - st,max-power-use-mpcc: + If present, then MPCC bits are used for MPC coefficients, + otherwise standard MPC coefficients are used. + + - st,max-power-corr: + If present, power bridge correction for THD reduction near maximum + power output is enabled. + + - st,am-reduction-mode: + If present, FFX mode runs in AM reduction mode, otherwise normal + FFX mode is used. + + - st,odd-pwm-speed-mode: + If present, PWM speed mode run on odd speed mode (341.3 kHz) on all + channels. If not present, normal PWM spped mode (384 kHz) will be used. + + - st,distortion-compensation: + If present, distortion compensation variable uses DCC coefficient. + If not present, preset DC coefficient is used. + + - st,invalid-input-detect-mute: + If present, automatic invalid input detect mute is enabled. + + - st,activate-mute-output: + If present, a mute output will be activated in ase the volume will + reach a value lower than -76 dBFS. + + - st,bridge-immediate-off: + If present, the bridge will be switched off immediately after the + power-down-gpio goes low. Otherwise, the bridge will wait for 13 + million clock cycles to pass before shutting down. + + - st,noise-shape-dc-cut: + If present, the noise-shaping technique on the DC cutoff filter are + enabled. + + - st,powerdown-master-volume: + If present, the power-down pin and I2C power-down functions will + act on the master volume. Otherwise, the functions will act on the + mute commands. + + - st,powerdown-delay-divider: + If present, the bridge power-down time will be divided by the provided + value. If not specified, a divider of 1 will be used. Allowed values + are 1, 2, 4, 8, 16, 32, 64 and 128. + This property has to be specified as '/bits/ 8' value. + +Example: + +codec: sta350@38 { + compatible = "st,sta350"; + reg = <0x1c>; + reset-gpios = <&gpio1 19 0>; + power-down-gpios = <&gpio1 16 0>; + st,output-conf = /bits/ 8 <0x3>; // set output to 2-channel + // (full-bridge) power, + // 2-channel data-out + st,ch1-output-mapping = /bits/ 8 <0>; // set channel 1 output ch 1 + st,ch2-output-mapping = /bits/ 8 <0>; // set channel 2 output ch 1 + st,ch3-output-mapping = /bits/ 8 <0>; // set channel 3 output ch 1 + st,max-power-correction; // enables power bridge + // correction for THD reduction + // near maximum power output + st,invalid-input-detect-mute; // mute if no valid digital + // audio signal is provided. +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,sti-asoc-card.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,sti-asoc-card.txt new file mode 100644 index 0000000000000000000000000000000000000000..4d51f3f5ea98c3188da684d3584ea6af79cca814 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,sti-asoc-card.txt @@ -0,0 +1,164 @@ +STMicroelectronics sti ASoC cards + +The sti ASoC Sound Card can be used, for all sti SoCs using internal sti-sas +codec or external codecs. + +sti sound drivers allows to expose sti SoC audio interface through the +generic ASoC simple card. For details about sound card declaration please refer to +Documentation/devicetree/bindings/sound/simple-card.txt. + +1) sti-uniperiph-dai: audio dai device. +--------------------------------------- + +Required properties: + - compatible: "st,stih407-uni-player-hdmi", "st,stih407-uni-player-pcm-out", + "st,stih407-uni-player-dac", "st,stih407-uni-player-spdif", + "st,stih407-uni-reader-pcm_in", "st,stih407-uni-reader-hdmi", + + - st,syscfg: phandle to boot-device system configuration registers + + - clock-names: name of the clocks listed in clocks property in the same order + + - reg: CPU DAI IP Base address and size entries, listed in same + order than the CPU_DAI properties. + + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + + - interrupts: CPU_DAI interrupt line, listed in the same order than the + CPU_DAI properties. + + - dma: CPU_DAI DMA controller phandle and DMA request line, listed in the same + order than the CPU_DAI properties. + + - dma-names: identifier string for each DMA request line in the dmas property. + "tx" for "st,sti-uni-player" compatibility + "rx" for "st,sti-uni-reader" compatibility + +Required properties ("st,sti-uni-player" compatibility only): + - clocks: CPU_DAI IP clock source, listed in the same order than the + CPU_DAI properties. + +Optional properties: + - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for + external codecs connection. + + - pinctrl-names: should contain only one value - "default". + + - st,tdm-mode: to declare to set TDM mode for unireader and uniplayer IPs. + Only compartible with IPs in charge of the external I2S/TDM bus. + Should be declared depending on associated codec. + +Example: + + sti_uni_player1: sti-uni-player@8d81000 { + compatible = "st,stih407-uni-player-hdmi"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_PCM_1>; + reg = <0x8D81000 0x158>; + interrupts = ; + dmas = <&fdma0 3 0 1>; + dma-names = "tx"; + st,tdm-mode = <1>; + }; + + sti_uni_player2: sti-uni-player@8d82000 { + compatible = "st,stih407-uni-player-pcm-out"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_PCM_2>; + reg = <0x8D82000 0x158>; + interrupts = ; + dmas = <&fdma0 4 0 1>; + dma-names = "tx"; + }; + + sti_uni_player3: sti-uni-player@8d85000 { + compatible = "st,stih407-uni-player-spdif"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_SPDIFF>; + reg = <0x8D85000 0x158>; + interrupts = ; + dmas = <&fdma0 7 0 1>; + dma-names = "tx"; + }; + + sti_uni_reader1: sti-uni-reader@8d84000 { + compatible = "st,stih407-uni-reader-hdmi"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + reg = <0x8D84000 0x158>; + interrupts = ; + dmas = <&fdma0 6 0 1>; + dma-names = "rx"; + }; + +2) sti-sas-codec: internal audio codec IPs driver +------------------------------------------------- + +Required properties: + - compatible: "st,sti-sas-codec" . + Should be chip "st,stih416-sas-codec" or "st,stih407-sas-codec" + + - st,syscfg: phandle to boot-device system configuration registers. + + - pinctrl-0: SPDIF PIO description. + + - pinctrl-names: should contain only one value - "default". + +Example: + sti_sas_codec: sti-sas-codec { + compatible = "st,stih407-sas-codec"; + #sound-dai-cells = <1>; + st,reg_audio = <&syscfg_core>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif_out >; + }; + +Example of audio card declaration: + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sti audio card"; + + simple-audio-card,dai-link@0 { + /* DAC */ + format = "i2s"; + dai-tdm-slot-width = <32>; + cpu { + sound-dai = <&sti_uni_player2>; + }; + + codec { + sound-dai = <&sti_sasg_codec 1>; + }; + }; + simple-audio-card,dai-link@1 { + /* SPDIF */ + format = "left_j"; + cpu { + sound-dai = <&sti_uni_player3>; + }; + + codec { + sound-dai = <&sti_sasg_codec 0>; + }; + }; + simple-audio-card,dai-link@2 { + /* TDM playback */ + format = "left_j"; + frame-inversion = <1>; + cpu { + sound-dai = <&sti_uni_player1>; + dai-tdm-slot-num = <16>; + dai-tdm-slot-width = <16>; + dai-tdm-slot-tx-mask = + <1 1 1 1 0 0 0 0 0 0 1 1 0 0 1 1>; + }; + + codec { + sound-dai = <&sti_sasg_codec 3>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-adfsdm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-adfsdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..864f5b00b031460c0db5295fab0d118159d507bb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-adfsdm.txt @@ -0,0 +1,63 @@ +STMicroelectronics Audio Digital Filter Sigma Delta modulators(DFSDM) + +The DFSDM allows PDM microphones capture through SPI interface. The Audio +interface is seems as a sub block of the DFSDM device. +For details on DFSDM bindings refer to ../iio/adc/st,stm32-dfsdm-adc.txt + +Required properties: + - compatible: "st,stm32h7-dfsdm-dai". + + - #sound-dai-cells : Must be equal to 0 + + - io-channels : phandle to iio dfsdm instance node. + +Example of a sound card using audio DFSDM node. + + sound_card { + compatible = "audio-graph-card"; + + dais = <&cpu_port>; + }; + + dfsdm: dfsdm@40017000 { + compatible = "st,stm32h7-dfsdm"; + reg = <0x40017000 0x400>; + clocks = <&rcc DFSDM1_CK>; + clock-names = "dfsdm"; + #interrupt-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + dfsdm_adc0: filter@0 { + compatible = "st,stm32-dfsdm-dmic"; + reg = <0>; + interrupts = <110>; + dmas = <&dmamux1 101 0x400 0x00>; + dma-names = "rx"; + st,adc-channels = <1>; + st,adc-channel-names = "dmic0"; + st,adc-channel-types = "SPI_R"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <5>; + + dfsdm_dai0: dfsdm-dai { + compatible = "st,stm32h7-dfsdm-dai"; + #sound-dai-cells = <0>; + io-channels = <&dfsdm_adc0 0>; + cpu_port: port { + dfsdm_endpoint: endpoint { + remote-endpoint = <&dmic0_endpoint>; + }; + }; + }; + }; + + dmic0: dmic@0 { + compatible = "dmic-codec"; + #sound-dai-cells = <0>; + port { + dmic0_endpoint: endpoint { + remote-endpoint = <&dfsdm_endpoint>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..58c341300552578018be27280517d36a24da35e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-i2s.txt @@ -0,0 +1,62 @@ +STMicroelectronics STM32 SPI/I2S Controller + +The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. +Only some SPI instances support I2S. + +Required properties: + - compatible: Must be "st,stm32h7-i2s" + - reg: Offset and length of the device's register set. + - interrupts: Must contain the interrupt line id. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". + "i2sclk": clock which feeds the internal clock generator + "pclk": clock which feeds the peripheral bus interface + "x8k": I2S parent clock for sampling rates multiple of 8kHz. + "x11k": I2S parent clock for sampling rates multiple of 11.025kHz. + - dmas: DMA specifiers for tx and rx dma. + See Documentation/devicetree/bindings/dma/stm32-dma.txt. + - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". + - pinctrl-names: should contain only value "default" + - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt + +Optional properties: + - resets: Reference to a reset controller asserting the reset controller + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +graph.txt. + +Example: +sound_card { + compatible = "audio-graph-card"; + dais = <&i2s2_port>; +}; + +i2s2: audio-controller@40003800 { + compatible = "st,stm32h7-i2s"; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>; + clock-names = "pclk", "i2sclk", "x8k", "x11k"; + dmas = <&dmamux2 2 39 0x400 0x1>, + <&dmamux2 3 40 0x400 0x1>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s2>; + + i2s2_port: port@0 { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + format = "i2s"; + }; + }; +}; + +audio-codec { + codec_port: port@0 { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-sai.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-sai.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a3fc506e43ae8ce727e03f14f0073a10008adfa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-sai.txt @@ -0,0 +1,100 @@ +STMicroelectronics STM32 Serial Audio Interface (SAI). + +The SAI interface (Serial Audio Interface) offers a wide set of audio protocols +as I2S standards, LSB or MSB-justified, PCM/DSP, TDM, and AC'97. +The SAI contains two independent audio sub-blocks. Each sub-block has +its own clock generator and I/O lines controller. + +Required properties: + - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai" + - reg: Base address and size of SAI common register set. + - clocks: Must contain phandle and clock specifier pairs for each entry + in clock-names. + - clock-names: Must contain "pclk" "x8k" and "x11k" + "pclk": Clock which feeds the peripheral bus interface. + Mandatory for "st,stm32h7-sai" compatible. + Not used for "st,stm32f4-sai" compatible. + "x8k": SAI parent clock for sampling rates multiple of 8kHz. + "x11k": SAI parent clock for sampling rates multiple of 11.025kHz. + - interrupts: cpu DAI interrupt line shared by SAI sub-blocks + +Optional properties: + - resets: Reference to a reset controller asserting the SAI + +SAI subnodes: +Two subnodes corresponding to SAI sub-block instances A et B can be defined. +Subnode can be omitted for unsused sub-block. + +SAI subnodes required properties: + - compatible: Should be "st,stm32-sai-sub-a" or "st,stm32-sai-sub-b" + for SAI sub-block A or B respectively. + - reg: Base address and size of SAI sub-block register set. + - clocks: Must contain one phandle and clock specifier pair + for sai_ck which feeds the internal clock generator. + - clock-names: Must contain "sai_ck". + - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt + - dma-names: identifier string for each DMA request line + "tx": if sai sub-block is configured as playback DAI + "rx": if sai sub-block is configured as capture DAI + - pinctrl-names: should contain only value "default" + - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt + +SAI subnodes Optional properties: + - st,sync: specify synchronization mode. + By default SAI sub-block is in asynchronous mode. + This property sets SAI sub-block as slave of another SAI sub-block. + Must contain the phandle and index of the sai sub-block providing + the synchronization. + - st,iec60958: support S/PDIF IEC6958 protocol for playback + IEC60958 protocol is not available for capture. + By default, custom protocol is assumed, meaning that protocol is + configured according to protocol defined in related DAI link node, + such as i2s, left justified, right justified, dsp and pdm protocols. + Note: ac97 protocol is not supported by SAI driver + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +graph.txt. + +Example: +sound_card { + compatible = "audio-graph-card"; + dais = <&sai1b_port>; +}; + +sai1: sai1@40015800 { + compatible = "st,stm32h7-sai"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x40015800 0x400>; + reg = <0x40015800 0x4>; + clocks = <&rcc SAI1_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>; + clock-names = "pclk", "x8k", "x11k"; + interrupts = <87>; + + sai1a: audio-controller@40015804 { + compatible = "st,stm32-sai-sub-a"; + reg = <0x4 0x1C>; + clocks = <&rcc SAI1_CK>; + clock-names = "sai_ck"; + dmas = <&dmamux1 1 87 0x400 0x0>; + dma-names = "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai1a>; + + sai1b_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + format = "i2s"; + }; + }; + }; +}; + +audio-codec { + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-spdifrx.txt b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-spdifrx.txt new file mode 100644 index 0000000000000000000000000000000000000000..33826f2459fa80215753f918f732056b0fecf322 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/st,stm32-spdifrx.txt @@ -0,0 +1,56 @@ +STMicroelectronics STM32 S/PDIF receiver (SPDIFRX). + +The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with +IEC-60958 and IEC-61937. + +Required properties: + - compatible: should be "st,stm32h7-spdifrx" + - reg: cpu DAI IP base address and size + - clocks: must contain an entry for kclk (used as S/PDIF signal reference) + - clock-names: must contain "kclk" + - interrupts: cpu DAI interrupt line + - dmas: DMA specifiers for audio data DMA and iec control flow DMA + See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt + - dma-names: two dmas have to be defined, "rx" and "rx-ctrl" + +Optional properties: + - resets: Reference to a reset controller asserting the SPDIFRX + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +graph.txt. + +Example: +spdifrx: spdifrx@40004000 { + compatible = "st,stm32h7-spdifrx"; + reg = <0x40004000 0x400>; + clocks = <&rcc SPDIFRX_CK>; + clock-names = "kclk"; + interrupts = <97>; + dmas = <&dmamux1 2 93 0x400 0x0>, + <&dmamux1 3 94 0x400 0x0>; + dma-names = "rx", "rx-ctrl"; + pinctrl-0 = <&spdifrx_pins>; + pinctrl-names = "default"; + + spdifrx_port: port { + cpu_endpoint: endpoint { + remote-endpoint = <&codec_endpoint>; + }; + }; +}; + +spdif_in: spdif-in { + compatible = "linux,spdif-dir"; + + codec_port: port { + codec_endpoint: endpoint { + remote-endpoint = <&cpu_endpoint>; + }; + }; +}; + +soundcard { + compatible = "audio-graph-card"; + dais = <&spdifrx_port>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/storm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/storm.txt new file mode 100644 index 0000000000000000000000000000000000000000..062a4c185fa9d06d726eccbbcf69a6e566ec0441 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/storm.txt @@ -0,0 +1,23 @@ +* Sound complex for Storm boards + +Models a soundcard for Storm boards with the Qualcomm Technologies IPQ806x SOC +connected to a MAX98357A DAC via I2S. + +Required properties: + +- compatible : "google,storm-audio" +- cpu : Phandle of the CPU DAI +- codec : Phandle of the codec DAI + +Optional properties: + +- qcom,model : The user-visible name of this sound card. + +Example: + +sound { + compatible = "google,storm-audio"; + qcom,model = "ipq806x-storm"; + cpu = <&lpass_cpu>; + codec = <&max98357a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sun4i-codec.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sun4i-codec.txt new file mode 100644 index 0000000000000000000000000000000000000000..66579bbd329455ddc5b18a89ecd17bd2dd805856 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sun4i-codec.txt @@ -0,0 +1,94 @@ +* Allwinner A10 Codec + +Required properties: +- compatible: must be one of the following compatibles: + - "allwinner,sun4i-a10-codec" + - "allwinner,sun6i-a31-codec" + - "allwinner,sun7i-a20-codec" + - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" + - "allwinner,sun8i-v3s-codec" +- reg: must contain the registers location and length +- interrupts: must contain the codec interrupt +- dmas: DMA channels for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should include "tx" and "rx". +- clocks: a list of phandle + clock-specifer pairs, one for each entry + in clock-names. +- clock-names: should contain the following: + - "apb": the parent APB clock for this controller + - "codec": the parent module clock + +Optional properties: +- allwinner,pa-gpios: gpio to enable external amplifier + +Required properties for the following compatibles: + - "allwinner,sun6i-a31-codec" + - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" + - "allwinner,sun8i-v3s-codec" +- resets: phandle to the reset control for this device +- allwinner,audio-routing: A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names include: + + Audio pins on the SoC: + "HP" + "HPCOM" + "LINEIN" (not on sun8i-v3s) + "LINEOUT" (not on sun8i-a23 or sun8i-v3s) + "MIC1" + "MIC2" (not on sun8i-v3s) + "MIC3" (sun6i-a31 only) + + Microphone biases from the SoC: + "HBIAS" + "MBIAS" (not on sun8i-v3s) + + Board connectors: + "Headphone" + "Headset Mic" + "Line In" + "Line Out" + "Mic" + "Speaker" + +Required properties for the following compatibles: + - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" + - "allwinner,sun8i-v3s-codec" +- allwinner,codec-analog-controls: A phandle to the codec analog controls + block in the PRCM. + +Example: +codec: codec@1c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun7i-a20-codec"; + reg = <0x01c22c00 0x40>; + interrupts = <0 30 4>; + clocks = <&apb0_gates 0>, <&codec_clk>; + clock-names = "apb", "codec"; + dmas = <&dma 0 19>, <&dma 0 19>; + dma-names = "rx", "tx"; +}; + +codec: codec@1c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun6i-a31-codec"; + reg = <0x01c22c00 0x98>; + interrupts = ; + clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>; + clock-names = "apb", "codec"; + resets = <&ccu RST_APB1_CODEC>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; + allwinner,audio-routing = + "Headphone", "HP", + "Speaker", "LINEOUT", + "LINEIN", "Line In", + "MIC1", "MBIAS", + "MIC1", "Mic", + "MIC2", "HBIAS", + "MIC2", "Headset Mic"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sun4i-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sun4i-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9d50d6cdef30cb402f354c11958f3c77a759a22 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sun4i-i2s.txt @@ -0,0 +1,43 @@ +* Allwinner A10 I2S controller + +The I2S bus (Inter-IC sound bus) is a serial link for digital +audio data transfer between devices in the system. + +Required properties: + +- compatible: should be one of the following: + - "allwinner,sun4i-a10-i2s" + - "allwinner,sun6i-a31-i2s" + - "allwinner,sun8i-a83t-i2s" + - "allwinner,sun8i-h3-i2s" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: should contain the I2S interrupt. +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: should include "tx" and "rx". +- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. +- clock-names: should contain the following: + - "apb" : clock for the I2S bus interface + - "mod" : module clock for the I2S controller +- #sound-dai-cells : Must be equal to 0 + +Required properties for the following compatibles: + - "allwinner,sun6i-a31-i2s" + - "allwinner,sun8i-a83t-i2s" + - "allwinner,sun8i-h3-i2s" +- resets: phandle to the reset line for this codec + +Example: + +i2s0: i2s@1c22400 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun4i-a10-i2s"; + reg = <0x01c22400 0x400>; + interrupts = ; + clocks = <&apb0_gates 3>, <&i2s0_clk>; + clock-names = "apb", "mod"; + dmas = <&dma SUN4I_DMA_NORMAL 3>, + <&dma SUN4I_DMA_NORMAL 3>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sun8i-a33-codec.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sun8i-a33-codec.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ca3d138528ec340526704e3cb7c865c3f486b70 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sun8i-a33-codec.txt @@ -0,0 +1,63 @@ +Allwinner SUN8I audio codec +------------------------------------ + +On Sun8i-A33 SoCs, the audio is separated in different parts: + - A DAI driver. It uses the "sun4i-i2s" driver which is + documented here: + Documentation/devicetree/bindings/sound/sun4i-i2s.txt + - An analog part of the codec which is handled as PRCM registers. + See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt + - An digital part of the codec which is documented in this current + binding documentation. + - And finally, an audio card which links all the above components. + The simple-audio card will be used. + See Documentation/devicetree/bindings/sound/simple-card.txt + +This bindings documentation exposes Sun8i codec (digital part). + +Required properties: +- compatible: must be "allwinner,sun8i-a33-codec" +- reg: must contain the registers location and length +- interrupts: must contain the codec interrupt +- clocks: a list of phandle + clock-specifer pairs, one for each entry + in clock-names. +- clock-names: should contain followings: + - "bus": the parent APB clock for this controller + - "mod": the parent module clock + +Here is an example to add a sound card and the codec binding on sun8i SoCs that +are similar to A33 using simple-card: + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sun8i-a33-audio"; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&link_codec>; + simple-audio-card,bitclock-master = <&link_codec>; + simple-audio-card,mclk-fs = <512>; + simple-audio-card,aux-devs = <&codec_analog>; + simple-audio-card,routing = + "Left DAC", "Digital Left DAC", + "Right DAC", "Digital Right DAC"; + + simple-audio-card,cpu { + sound-dai = <&dai>; + }; + + link_codec: simple-audio-card,codec { + sound-dai = <&codec>; + }; + + soc@1c00000 { + [...] + + audio-codec@1c22e00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun8i-a33-codec"; + reg = <0x01c22e00 0x400>; + interrupts = ; + clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>; + clock-names = "bus", "mod"; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sun8i-codec-analog.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sun8i-codec-analog.txt new file mode 100644 index 0000000000000000000000000000000000000000..07356758bd91448e0ba54f0a8b9b654812fcf5fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sun8i-codec-analog.txt @@ -0,0 +1,17 @@ +* Allwinner Codec Analog Controls + +Required properties: +- compatible: must be one of the following compatibles: + - "allwinner,sun8i-a23-codec-analog" + - "allwinner,sun8i-h3-codec-analog" + - "allwinner,sun8i-v3s-codec-analog" + +Required properties if not a sub-node of the PRCM node: +- reg: must contain the registers location and length + +Example: +prcm: prcm@1f01400 { + codec_analog: codec-analog { + compatible = "allwinner,sun8i-a23-codec-analog"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/sunxi,sun4i-spdif.txt b/arch/arm64/boot/dts/vendor/bindings/sound/sunxi,sun4i-spdif.txt new file mode 100644 index 0000000000000000000000000000000000000000..0c64a209c2e9f7b0e8d00815ac2dd1a414c3c689 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/sunxi,sun4i-spdif.txt @@ -0,0 +1,42 @@ +Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller + +The Allwinner S/PDIF audio block is a transceiver that allows the +processor to receive and transmit digital audio via an coaxial cable or +a fibre cable. +For now only playback is supported. + +Required properties: + + - compatible : should be one of the following: + - "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC + - "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC + - "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the spdif interrupt. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Two dmas have to be defined, "tx" and "rx". + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "apb" clock for the spdif bus. + "spdif" clock for spdif controller. + + - resets : reset specifier for the ahb reset (A31 and newer only) + +Example: + +spdif: spdif@1c21000 { + compatible = "allwinner,sun4i-a10-spdif"; + reg = <0x01c21000 0x40>; + interrupts = <13>; + clocks = <&apb0_gates 1>, <&spdif_clk>; + clock-names = "apb", "spdif"; + dmas = <&dma 0 2>, <&dma 0 2>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tas2552.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tas2552.txt new file mode 100644 index 0000000000000000000000000000000000000000..2d71eb05c1d384c72e166d02a46fc2d695cea382 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tas2552.txt @@ -0,0 +1,36 @@ +Texas Instruments - tas2552 Codec module + +The tas2552 serial control bus communicates through I2C protocols + +Required properties: + - compatible - One of: + "ti,tas2552" - TAS2552 + - reg - I2C slave address: it can be 0x40 if ADDR pin is 0 + or 0x41 if ADDR pin is 1. + - supply-*: Required supply regulators are: + "vbat" battery voltage + "iovdd" I/O Voltage + "avdd" Analog DAC Voltage + +Optional properties: + - enable-gpio - gpio pin to enable/disable the device + +tas2552 can receive its reference clock via MCLK, BCLK, IVCLKIN pin or use the +internal 1.8MHz. This CLKIN is used by the PLL. In addition to PLL, the PDM +reference clock is also selectable: PLL, IVCLKIN, BCLK or MCLK. +For system integration the dt-bindings/sound/tas2552.h header file provides +defined values to select and configure the PLL and PDM reference clocks. + +Example: + +tas2552: tas2552@41 { + compatible = "ti,tas2552"; + reg = <0x41>; + vbat-supply = <®_vbat>; + iovdd-supply = <®_iovdd>; + avdd-supply = <®_avdd>; + enable-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; +}; + +For more product information please see the link below: +http://www.ti.com/product/TAS2552 diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tas571x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tas571x.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c8fd37c2f9e9da14740f78ae8801a01d086ec46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tas571x.txt @@ -0,0 +1,48 @@ +Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: should be one of the following: + - "ti,tas5707" + - "ti,tas5711", + - "ti,tas5717", + - "ti,tas5719", + - "ti,tas5721" +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be "mclk" +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) +- DRVDD-supply: regulator phandle for the DRVDD supply (5721) +- PVDD-supply: regulator phandle for the PVDD supply (5721) + +Example: + + tas5717: audio-codec@2a { + compatible = "ti,tas5717"; + reg = <0x2a>; + #sound-dai-cells = <0>; + + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>; + + clocks = <&clk_core CLK_I2S>; + clock-names = "mclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tas5720.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tas5720.txt new file mode 100644 index 0000000000000000000000000000000000000000..7481653fe8e3eba498667dcebe9afb8d97dc3391 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tas5720.txt @@ -0,0 +1,26 @@ +Texas Instruments TAS5720 Mono Audio amplifier + +The TAS5720 serial control bus communicates through the I2C protocol only. The +serial bus is also used for periodic codec fault checking/reporting during +audio playback. For more product information please see the links below: + +http://www.ti.com/product/TAS5720L +http://www.ti.com/product/TAS5720M +http://www.ti.com/product/TAS5722L + +Required properties: + +- compatible : "ti,tas5720", + "ti,tas5722" +- reg : I2C slave address +- dvdd-supply : phandle to a 3.3-V supply for the digital circuitry +- pvdd-supply : phandle to a supply used for the Class-D amp and the analog + +Example: + +tas5720: tas5720@6c { + compatible = "ti,tas5720"; + reg = <0x6c>; + dvdd-supply = <&vdd_3v3_reg>; + pvdd-supply = <&_supply_reg>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tda7419.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tda7419.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b85ec38dd5656f7eb434d5f2cef88c30589f488 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tda7419.txt @@ -0,0 +1,38 @@ +TDA7419 audio processor + +This device supports I2C only. + +Required properties: + +- compatible : "st,tda7419" +- reg : the I2C address of the device. +- vdd-supply : a regulator spec for the common power supply (8-10V) + +Optional properties: + +- st,mute-gpios : a GPIO spec for the MUTE pin. + +Pins on the device (for linking into audio routes): + + * SE3L + * SE3R + * SE2L + * SE2R + * SE1L + * SE1R + * DIFFL + * DIFFR + * MIX + * OUTLF + * OUTRF + * OUTLR + * OUTRR + * OUTSW + +Example: + +ap: tda7419@44 { + compatible = "st,tda7419"; + reg = <0x44>; + vdd-supply = <&vdd_9v0_reg>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tdm-slot.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tdm-slot.txt new file mode 100644 index 0000000000000000000000000000000000000000..34cf70e2cbc4720510cf03e05eba6f3bcb6b2cae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tdm-slot.txt @@ -0,0 +1,29 @@ +TDM slot: + +This specifies audio DAI's TDM slot. + +TDM slot properties: +dai-tdm-slot-num : Number of slots in use. +dai-tdm-slot-width : Width in bits for each slot. +dai-tdm-slot-tx-mask : Transmit direction slot mask, optional +dai-tdm-slot-rx-mask : Receive direction slot mask, optional + +For instance: + dai-tdm-slot-num = <2>; + dai-tdm-slot-width = <8>; + dai-tdm-slot-tx-mask = <0 1>; + dai-tdm-slot-rx-mask = <1 0>; + +And for each spcified driver, there could be one .of_xlate_tdm_slot_mask() +to specify a explicit mapping of the channels and the slots. If it's absent +the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the +tx and rx masks. + +For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit +for an active slot as default, and the default active bits are at the LSB of +the masks. + +The explicit masks are given as array of integers, where the first +number presents bit-0 (LSB), second presents bit-1, etc. Any non zero +number is considered 1 and 0 is 0. snd_soc_of_xlate_tdm_slot_mask() +does not do anything, if either mask is set non zero value. diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tfa9879.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tfa9879.txt new file mode 100644 index 0000000000000000000000000000000000000000..1620e6848436d630aadc5ff17cd028925623b89f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tfa9879.txt @@ -0,0 +1,23 @@ +NXP TFA9879 class-D audio amplifier + +Required properties: + +- compatible : "nxp,tfa9879" + +- reg : the I2C address of the device + +- #sound-dai-cells : must be 0. + +Example: + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + + amp: amp@6c { + #sound-dai-cells = <0>; + compatible = "nxp,tfa9879"; + reg = <0x6c>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ti,ads117x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ti,ads117x.txt new file mode 100644 index 0000000000000000000000000000000000000000..7db19b50865a9878b284d0e1fabf26dbd9081ec9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ti,ads117x.txt @@ -0,0 +1,11 @@ +Texas Intstruments ADS117x ADC + +Required properties: + + - compatible : "ti,ads1174" or "ti,ads1178" + +Example: + +ads1178 { + compatible = "ti,ads1178"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ti,pcm1681.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ti,pcm1681.txt new file mode 100644 index 0000000000000000000000000000000000000000..4df17185ab807c5d2be5843b38cd6c995c74914b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ti,pcm1681.txt @@ -0,0 +1,15 @@ +Texas Instruments PCM1681 8-channel PWM Processor + +Required properties: + + - compatible: Should contain "ti,pcm1681". + - reg: The i2c address. Should contain <0x4c>. + +Examples: + + i2c_bus { + pcm1681@4c { + compatible = "ti,pcm1681"; + reg = <0x4c>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ti,pcm3168a.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ti,pcm3168a.txt new file mode 100644 index 0000000000000000000000000000000000000000..5d9cb84c661d84115da207f4e0301ce503899712 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ti,pcm3168a.txt @@ -0,0 +1,48 @@ +Texas Instruments pcm3168a DT bindings + +This driver supports both SPI and I2C bus access for this codec + +Required properties: + + - compatible: "ti,pcm3168a" + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Includes the following entries: + "scki" The system clock + + - VDD1-supply : Digital power supply regulator 1 (+3.3V) + + - VDD2-supply : Digital power supply regulator 2 (+3.3V) + + - VCCAD1-supply : ADC power supply regulator 1 (+5V) + + - VCCAD2-supply : ADC power supply regulator 2 (+5V) + + - VCCDA1-supply : DAC power supply regulator 1 (+5V) + + - VCCDA2-supply : DAC power supply regulator 2 (+5V) + +For required properties on SPI/I2C, consult SPI/I2C device tree documentation + +Examples: + +i2c0: i2c0@0 { + + ... + + pcm3168a: audio-codec@44 { + compatible = "ti,pcm3168a"; + reg = <0x44>; + clocks = <&clk_core CLK_AUDIO>; + clock-names = "scki"; + VDD1-supply = <&supply3v3>; + VDD2-supply = <&supply3v3>; + VCCAD1-supply = <&supply5v0>; + VCCAD2-supply = <&supply5v0>; + VCCDA1-supply = <&supply5v0>; + VCCDA2-supply = <&supply5v0>; + pinctrl-names = "default"; + pinctrl-0 = <&dac_clk_pin>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ti,tas5086.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ti,tas5086.txt new file mode 100644 index 0000000000000000000000000000000000000000..234dad296da7149ec0a910a3e4410c8871a0cd1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ti,tas5086.txt @@ -0,0 +1,48 @@ +Texas Instruments TAS5086 6-channel PWM Processor + +Required properties: + + - compatible: Should contain "ti,tas5086". + - reg: The i2c address. Should contain <0x1b>. + +Optional properties: + + - reset-gpio: A GPIO spec to define which pin is connected to the + chip's !RESET pin. If specified, the driver will + assert a hardware reset at probe time. + + - ti,charge-period: This property should contain the time in microseconds + that closely matches the external single-ended + split-capacitor charge period. The hardware chip + waits for this period of time before starting the + PWM signals. This helps reduce pops and clicks. + + When not specified, the hardware default of 1300ms + is retained. + + - ti,mid-z-channel-X: Boolean properties, X being a number from 1 to 6. + If given, channel X will start with the Mid-Z start + sequence, otherwise the default Low-Z scheme is used. + + The correct configuration depends on how the power + stages connected to the PWM output pins work. Not all + power stages are compatible to Mid-Z - please refer + to the datasheets for more details. + + Most systems should not set any of these properties. + + - avdd-supply: Power supply for AVDD, providing 3.3V + - dvdd-supply: Power supply for DVDD, providing 3.3V + +Examples: + + i2c_bus { + tas5086@1b { + compatible = "ti,tas5086"; + reg = <0x1b>; + reset-gpio = <&gpio 23 0>; + ti,charge-period = <156000>; + avdd-supply = <&vdd_3v3_reg>; + dvdd-supply = <&vdd_3v3_reg>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ti,tas6424.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ti,tas6424.txt new file mode 100644 index 0000000000000000000000000000000000000000..eacb54f34188fa6cf10f3ad101b1c70bf590a488 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ti,tas6424.txt @@ -0,0 +1,22 @@ +Texas Instruments TAS6424 Quad-Channel Audio amplifier + +The TAS6424 serial control bus communicates through I2C protocols. + +Required properties: + - compatible: "ti,tas6424" - TAS6424 + - reg: I2C slave address + - sound-dai-cells: must be equal to 0 + - standby-gpios: GPIO used to shut the TAS6424 down. + - mute-gpios: GPIO used to mute all the outputs + +Example: + +tas6424: tas6424@6a { + compatible = "ti,tas6424"; + reg = <0x6a>; + + #sound-dai-cells = <0>; +}; + +For more product information please see the link below: +http://www.ti.com/product/TAS6424-Q1 diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic31xx.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic31xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b3c33bb99e57a4d21384aa7c1d36b062f14ab12 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic31xx.txt @@ -0,0 +1,72 @@ +Texas Instruments - tlv320aic31xx Codec module + +The tlv320aic31xx serial control bus communicates through I2C protocols + +Required properties: + +- compatible - "string" - One of: + "ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp + "ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp + "ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP) + "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP) + "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP) + "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP) + "ti,tlv320dac3100" - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP) + "ti,tlv320dac3101" - TLV320DAC3101 (no ADC, stereo speaker amp, no MiniDSP) + +- reg - - I2C slave address +- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply, + DVDD-supply : power supplies for the device as covered in + Documentation/devicetree/bindings/regulator/regulator.txt + + +Optional properties: + +- reset-gpios - GPIO specification for the active low RESET input. +- ai31xx-micbias-vg - MicBias Voltage setting + 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V + 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V + 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD + If this node is not mentioned or if the value is unknown, then + micbias is set to 2.0V. + +Deprecated properties: + +- gpio-reset - gpio pin number used for codec reset + +CODEC output pins: + * HPL + * HPR + * SPL, devices with stereo speaker amp + * SPR, devices with stereo speaker amp + * SPK, devices with mono speaker amp + * MICBIAS + +CODEC input pins: + * MIC1LP, devices with ADC + * MIC1RP, devices with ADC + * MIC1LM, devices with ADC + * AIN1, devices without ADC + * AIN2, devices without ADC + +The pins can be used in referring sound node's audio-routing property. + +Example: +#include +#include + +tlv320aic31xx: tlv320aic31xx@18 { + compatible = "ti,tlv320aic311x"; + reg = <0x18>; + + ai31xx-micbias-vg = ; + + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + + HPVDD-supply = <®ulator>; + SPRVDD-supply = <®ulator>; + SPLVDD-supply = <®ulator>; + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic32x4.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic32x4.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca75890f0d0722b68a581eb660f1ddd3acf69f0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic32x4.txt @@ -0,0 +1,41 @@ +Texas Instruments - tlv320aic32x4 Codec module + +The tlv320aic32x4 serial control bus communicates through I2C protocols + +Required properties: + - compatible - "string" - One of: + "ti,tlv320aic32x4" TLV320AIC3204 + "ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256 + - reg: I2C slave address + - supply-*: Required supply regulators are: + "iov" - digital IO power supply + "ldoin" - LDO power supply + "dv" - Digital core power supply + "av" - Analog core power supply + If you supply ldoin, dv and av are optional. Otherwise they are required + See regulator/regulator.txt for more information about the detailed binding + format. + +Optional properties: + - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt + - clocks/clock-names: Clock named 'mclk' for the master clock of the codec. + See clock/clock-bindings.txt for information about the detailed format. + - aic32x4-gpio-func - + - Types are defined in include/sound/tlv320aic32x4.h + + +Example: + +codec: tlv320aic32x4@18 { + compatible = "ti,tlv320aic32x4"; + reg = <0x18>; + clocks = <&clks 201>; + clock-names = "mclk"; + aic32x4-gpio-func= < + 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ + 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ + 0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */ + 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ + 0x08 /* MFP5 AIC32X4_MFP5_GPIO_INPUT */ + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic3x.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic3x.txt new file mode 100644 index 0000000000000000000000000000000000000000..9796c46392620074c0ee32480e746b529e524b0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tlv320aic3x.txt @@ -0,0 +1,80 @@ +Texas Instruments - tlv320aic3x Codec module + +The tlv320aic3x serial control bus communicates through I2C protocols + +Required properties: + +- compatible - "string" - One of: + "ti,tlv320aic3x" - Generic TLV320AIC3x device + "ti,tlv320aic33" - TLV320AIC33 + "ti,tlv320aic3007" - TLV320AIC3007 + "ti,tlv320aic3106" - TLV320AIC3106 + "ti,tlv320aic3104" - TLV320AIC3104 + + +- reg - - I2C slave address + + +Optional properties: + +- reset-gpios - GPIO specification for the active low RESET input. +- ai3x-gpio-func - - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality + - Not supported on tlv320aic3104 +- ai3x-micbias-vg - MicBias Voltage required. + 1 - MICBIAS output is powered to 2.0V, + 2 - MICBIAS output is powered to 2.5V, + 3 - MICBIAS output is connected to AVDD, + If this node is not mentioned or if the value is incorrect, then MicBias + is powered down. +- ai3x-ocmv - Output Common-Mode Voltage selection: + 0 - 1.35V, + 1 - 1.5V, + 2 - 1.65V, + 3 - 1.8V +- AVDD-supply, IOVDD-supply, DRVDD-supply, DVDD-supply : power supplies for the + device as covered in Documentation/devicetree/bindings/regulator/regulator.txt + +Deprecated properties: + +- gpio-reset - gpio pin number used for codec reset + +CODEC output pins: + * LLOUT + * RLOUT + * MONO_LOUT + * HPLOUT + * HPROUT + * HPLCOM + * HPRCOM + +CODEC input pins for TLV320AIC3104: + * MIC2L + * MIC2R + * LINE1L + * LINE1R + +CODEC input pins for other compatible codecs: + * MIC3L + * MIC3R + * LINE1L + * LINE2L + * LINE1R + * LINE2R + +The pins can be used in referring sound node's audio-routing property. + +Example: + +#include + +tlv320aic3x: tlv320aic3x@1b { + compatible = "ti,tlv320aic3x"; + reg = <0x1b>; + + reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + + AVDD-supply = <®ulator>; + IOVDD-supply = <®ulator>; + DRVDD-supply = <®ulator>; + DVDD-supply = <®ulator>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tpa6130a2.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tpa6130a2.txt new file mode 100644 index 0000000000000000000000000000000000000000..6dfa740e4b2d87665e245a64d4bdc66299d94bc8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tpa6130a2.txt @@ -0,0 +1,27 @@ +Texas Instruments - tpa6130a2 Codec module + +The tpa6130a2 serial control bus communicates through I2C protocols + +Required properties: + +- compatible - "string" - One of: + "ti,tpa6130a2" - TPA6130A2 + "ti,tpa6140a2" - TPA6140A2 + + +- reg - - I2C slave address + +- Vdd-supply - - power supply regulator + +Optional properties: + +- power-gpio - gpio pin to power the device + +Example: + +tpa6130a2: tpa6130a2@60 { + compatible = "ti,tpa6130a2"; + reg = <0x60>; + Vdd-supply = <&vmmc2>; + power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ts3a227e.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ts3a227e.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ed8359144d32bc6eeacae78e6201fb4902c4297 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ts3a227e.txt @@ -0,0 +1,30 @@ +Texas Instruments TS3A227E +Autonomous Audio Accessory Detection and Configuration Switch + +The TS3A227E detect headsets of 3-ring and 4-ring standards and +switches automatically to route the microphone correctly. It also +handles key press detection in accordance with the Android audio +headset specification v1.0. + +Required properties: + + - compatible: Should contain "ti,ts3a227e". + - reg: The i2c address. Should contain <0x3b>. + - interrupts: Interrupt number for /INT pin from the 227e + +Optional properies: + - ti,micbias: Intended MICBIAS voltage (datasheet section 9.6.7). + Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage + 2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V + Default value is "1" (2.2V). + +Examples: + + i2c { + ts3a227e@3b { + compatible = "ti,ts3a227e"; + reg = <0x3b>; + interrupt-parent = <&gpio>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tscs42xx.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tscs42xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..7eea32e9d07838aec8d7f30b4e88b39c69da24d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tscs42xx.txt @@ -0,0 +1,22 @@ +TSCS42XX Audio CODEC + +Required Properties: + + - compatible : "tempo,tscs42A1" for analog mic + "tempo,tscs42A2" for digital mic + + - reg : <0x71> for analog mic + <0x69> for digital mic + + - clock-names: Must one of the following "mclk1", "xtal", "mclk2" + + - clocks: phandle of the clock that provides the codec sysclk + +Example: + +wookie: codec@69 { + compatible = "tempo,tscs42A2"; + reg = <0x69>; + clock-names = "xtal"; + clocks = <&audio_xtal>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/tscs454.txt b/arch/arm64/boot/dts/vendor/bindings/sound/tscs454.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ba3e2d2c20666c5f3cf7651ca117462eac7faf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/tscs454.txt @@ -0,0 +1,23 @@ +TSCS454 Audio CODEC + +Required Properties: + + - compatible : "tempo,tscs454" + + - reg : <0x69> + + - clock-names: Must one of the following "xtal", "mclk1", "mclk2" + + - clocks: phandle of the clock that provides the codec sysclk + + Note: If clock is not provided then bit clock is assumed + +Example: + +redwood: codec@69 { + #sound-dai-cells = <1>; + compatible = "tempo,tscs454"; + reg = <0x69>; + clock-names = "mclk1"; + clocks = <&audio_mclk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/uniphier,aio.txt b/arch/arm64/boot/dts/vendor/bindings/sound/uniphier,aio.txt new file mode 100644 index 0000000000000000000000000000000000000000..4ce68ed6f2f2363f90079a1fef368a4bf9abd90d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/uniphier,aio.txt @@ -0,0 +1,45 @@ +Socionext UniPhier SoC audio driver + +The Socionext UniPhier audio subsystem consists of I2S and S/PDIF blocks in +the same register space. + +Required properties: +- compatible : should be one of the following: + "socionext,uniphier-ld11-aio" + "socionext,uniphier-ld20-aio" + "socionext,uniphier-pxs2-aio" +- reg : offset and length of the register set for the device. +- interrupts : should contain I2S or S/PDIF interrupt. +- pinctrl-names : should be "default". +- pinctrl-0 : defined I2S signal pins for an external codec chip. +- clock-names : should include following entries: + "aio" +- clocks : a list of phandle, should contain an entry for each + entry in clock-names. +- reset-names : should include following entries: + "aio" +- resets : a list of phandle, should contain an entry for each + entry in reset-names. +- #sound-dai-cells: should be 1. + +Optional properties: +- socionext,syscon: a phandle, should contain soc-glue. + The soc-glue is used for changing mode of S/PDIF signal pin + to Output from Hi-Z. This property is optional if you use + I2S signal pins only. + +Example: + audio { + compatible = "socionext,uniphier-ld20-aio"; + reg = <0x56000000 0x80000>; + interrupts = <0 144 4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_aout>; + clock-names = "aio"; + clocks = <&sys_clk 40>; + reset-names = "aio"; + resets = <&sys_rst 40>; + #sound-dai-cells = <1>; + + socionext,syscon = <&sg>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/uniphier,evea.txt b/arch/arm64/boot/dts/vendor/bindings/sound/uniphier,evea.txt new file mode 100644 index 0000000000000000000000000000000000000000..3f31b235f18b9bc0a3a82b0058fbde26c6181d6b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/uniphier,evea.txt @@ -0,0 +1,26 @@ +Socionext EVEA - UniPhier SoC internal codec driver + +Required properties: +- compatible : should be "socionext,uniphier-evea". +- reg : offset and length of the register set for the device. +- clock-names : should include following entries: + "evea", "exiv" +- clocks : a list of phandle, should contain an entry for each + entries in clock-names. +- reset-names : should include following entries: + "evea", "exiv", "adamv" +- resets : a list of phandle, should contain reset entries of + reset-names. +- #sound-dai-cells: should be 1. + +Example: + + codec { + compatible = "socionext,uniphier-evea"; + reg = <0x57900000 0x1000>; + clock-names = "evea", "exiv"; + clocks = <&sys_clk 41>, <&sys_clk 42>; + reset-names = "evea", "exiv", "adamv"; + resets = <&sys_rst 41>, <&sys_rst 42>, <&adamv_rst 0>; + #sound-dai-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ux500-mop500.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ux500-mop500.txt new file mode 100644 index 0000000000000000000000000000000000000000..48e071c96b465ed2bfbe599d7f322557833614af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ux500-mop500.txt @@ -0,0 +1,39 @@ +* MOP500 Audio Machine Driver + +This node is responsible for linking together all ux500 Audio Driver components. + +Required properties: + - compatible : "stericsson,snd-soc-mop500" + +Non-standard properties: + - stericsson,cpu-dai : Phandle to the CPU-side DAI + - stericsson,audio-codec : Phandle to the Audio CODEC + - stericsson,card-name : Over-ride default card name + +Example: + + sound { + compatible = "stericsson,snd-soc-mop500"; + + stericsson,cpu-dai = <&msp1 &msp3>; + stericsson,audio-codec = <&codec>; + }; + + msp1: msp@80124000 { + compatible = "stericsson,ux500-msp-i2s"; + reg = <0x80124000 0x1000>; + interrupts = <0 62 0x4>; + v-ape-supply = <&db8500_vape_reg>; + }; + + msp3: msp@80125000 { + compatible = "stericsson,ux500-msp-i2s"; + reg = <0x80125000 0x1000>; + interrupts = <0 62 0x4>; + v-ape-supply = <&db8500_vape_reg>; + }; + + codec: ab8500-codec { + compatible = "stericsson,ab8500-codec"; + stericsson,earpeice-cmv = <950>; /* Units in mV. */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/ux500-msp.txt b/arch/arm64/boot/dts/vendor/bindings/sound/ux500-msp.txt new file mode 100644 index 0000000000000000000000000000000000000000..7dd1b96160f5973e2ea2c37d7718368779957df1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/ux500-msp.txt @@ -0,0 +1,42 @@ +* ux500 MSP (CPU-side Digital Audio Interface) + +Required properties: + - compatible :"stericsson,ux500-msp-i2s" + - reg : Physical base address and length of the device's registers. + +Optional properties: + - interrupts : The interrupt output from the device. + - -supply : Phandle to the regulator supply + +Example: + + sound { + compatible = "stericsson,snd-soc-mop500"; + + stericsson,platform-pcm-dma = <&pcm>; + stericsson,cpu-dai = <&msp1 &msp3>; + stericsson,audio-codec = <&codec>; + }; + + pcm: ux500-pcm { + compatible = "stericsson,ux500-pcm"; + }; + + msp1: msp@80124000 { + compatible = "stericsson,ux500-msp-i2s"; + reg = <0x80124000 0x1000>; + interrupts = <0 62 0x4>; + v-ape-supply = <&db8500_vape_reg>; + }; + + msp3: msp@80125000 { + compatible = "stericsson,ux500-msp-i2s"; + reg = <0x80125000 0x1000>; + interrupts = <0 62 0x4>; + v-ape-supply = <&db8500_vape_reg>; + }; + + codec: ab8500-codec { + compatible = "stericsson,ab8500-codec"; + stericsson,earpeice-cmv = <950>; /* Units in mV. */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wcd_codec.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wcd_codec.txt new file mode 100644 index 0000000000000000000000000000000000000000..57c4189e52fd041f0f2388ae771baf7e78361ba4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wcd_codec.txt @@ -0,0 +1,561 @@ +Qualcomm Technologies, Inc. WCD audio CODEC + +WSA macro in Bolero codec + +Required properties: + - compatible = "qcom,wsa-macro"; + - reg: Specifies the WSA macro base address for Bolero + soundwire core registers. + - clock-names : clock names defined for WSA macro + - clocks : clock handles defined for WSA macro + - qcom,default-clk-id: Default clk ID used for WSA macro + - qcom,wsa-swr-gpios: phandle for SWR data and clock GPIOs of WSA macro + - qcom,wsa-bcl-pmic-params: u8 array of PMIC ID, SID and PPID in same order + required to be configured to receive interrupts + in BCL block of WSA macro + +WSA slave device as child of Bolero codec + +Required properties: + - compatible = "qcom,wsa881x"; + - reg: Specifies the WSA slave device base address. + - qcom,spkr-sd-n-gpio: speaker reset gpio + +Optional properties: + - bolero-handle: phandle to bolero codec + +Example: + +&bolero { + wsa_macro: wsa-macro { + compatible = "qcom,wsa-macro"; + reg = <0x0C2C0000 0x0>; + clock-names = "wsa_core_clk", "wsa_npl_clk"; + clocks = <&clock_audio_wsa_1 0>, + <&clock_audio_wsa_2 0>; + qcom,wsa-swr-gpios = &wsa_swr_gpios; + qcom,wsa-bcl-pmic-params = /bits/ 8 <0x00 0x00 0x1E>; + qcom,default-clk-id = ; + swr_0: wsa_swr_master { + compatible = "qcom,swr-mstr"; + wsa881x_1: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170212>; + qcom,spkr-sd-n-gpio = <&tlmm 80 0>; + bolero-handle = <&bolero>; + }; + }; + }; +}; + +VA macro in bolero codec + +Required properties: + - compatible = "qcom,va-macro"; + - reg: Specifies the VA macro base address for Bolero + soundwire core registers. + - clock-names : clock names defined for VA macro + - clocks : clock handles defined for VA macro + - qcom,default-clk-id: Default clk ID used for VA macro + - va-vdd-micb-supply: phandle of mic bias supply's regulator device tree node + - qcom,va-vdd-micb-voltage: mic bias supply's voltage level min and max in mV + - qcom,va-vdd-micb-current: mic bias supply's max current in mA + - qcom,va-dmic-sample-rate: Sample rate defined for DMIC connected to VA macro + +Optional properties: + - qcom,va-clk-mux-select: VA macro MCLK MUX selection + - qcom,va-island-mode-muxsel: VA macro island mode MUX selection + This property is required if qcom,va-clk-mux-select is provided + +Example: + +&bolero { + va_macro: va-macro { + compatible = "qcom,va-macro"; + reg = <0x0C490000 0x0>; + clock-names = "va_core_clk"; + clocks = <&clock_audio_va 0>; + qcom,default-clk-id = ; + va-vdd-micb-supply = <&S4A>; + qcom,va-vdd-micb-voltage = <1800000 1800000>; + qcom,va-vdd-micb-current = <11200>; + qcom,va-dmic-sample-rate = <4800000>; + qcom,va-clk-mux-select = <1>; + qcom,va-island-mode-muxsel = <0x033A0000>; + }; +}; + +RX macro in bolero codec + +Required properties: + - compatible = "qcom,rx-macro"; + - reg: Specifies the Rx macro base address for Bolero + soundwire core registers. + - clock-names : clock names defined for RX macro + - clocks : clock handles defined for RX macro + - qcom,default-clk-id: Default clk ID used for RX macro + - qcom,rx-swr-gpios: phandle for SWR data and clock GPIOs of RX macro + - qcom,rx_mclk_mode_muxsel: register address for RX macro MCLK mode mux select + - qcom,rx-bcl-pmic-params: u8 array of PMIC ID, SID and PPID in same order + required to be configured to receive interrupts + in BCL block of WSA macro + +Optional properties: + - qcom,disable-div2-clk-switch: u32 int to disable clock switch for rx master. + +Example: + +&bolero { + rx_macro: rx-macro { + compatible = "qcom,rx-macro"; + reg = <0x62EE0000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x62C25020>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x00 0x1E>; + qcom,default-clk-id = ; + swr_1: rx_swr_master { + compatible = "qcom,swr-mstr"; + wcd938x_rx_slave: wcd938x-rx-slave { + compatible = "qcom,wcd938x-slave"; + }; + }; + }; +}; + +TX macro in bolero codec + +Required properties: + - compatible = "qcom,tx-macro"; + - reg: Specifies the Tx macro base address for Bolero + soundwire core registers. + - clock-names : clock names defined for TX macro + - clocks : clock handles defined for TX macro + - qcom,tx-swr-gpios: phandle for SWR data and clock GPIOs of TX macro + - qcom,tx-dmic-sample-rate: Sample rate defined for DMICs connected to TX macro + +Optional properties: + - compatible = "qcom,swr-mstr"; + - Child of TX macro represent TX SWR master. + - qcom,swrm-hctl-reg: HW_CTL and CLK_ENABLE bits of SWR module. + Need Disable HW_CTL bit(to gate HW control) + for particular Soundwire master version as SW workaround. + +Example: + +&bolero { + tx_macro: tx-macro { + compatible = "qcom,tx-macro"; + reg = <0x62EC0000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0> + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <4800000>; + swr_2: tx_swr_master { + compatible = "qcom,swr-mstr"; + qcom,swrm-hctl-reg = <0xa53a400>; + wcd938x_tx_slave: wcd938x-tx-slave { + compatible = "qcom,wcd938x-slave"; + }; + rouleur_tx_slave: rouleur-tx-slave { + compatible = "qcom,rouleur-slave"; + }; + }; + }; +}; + +&bolero { + rx_macro: rx-macro { + compatible = "qcom,tx-macro"; + reg = <0x62EC0000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0> + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + swr_2: rx_swr_master { + compatible = "qcom,swr-mstr"; + wcd937x_rx_slave: wcd937x-rx-slave { + compatible = "qcom,wcd937x-slave"; + }; + rouleur_rx_slave: rouleur-rx-slave { + compatible = "qcom,rouleur-slave"; + }; + }; + }; +}; + +Tanggu Codec + +Required properties: + - compatible: "qcom,wcd937x-codec"; + - qcom,rx_swr_ch_map: mapping of swr rx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,tx_swr_ch_map: mapping of swr tx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio + configuration. If this property is not defined, it is + expected to atleast define "qcom,cdc-reset-gpio" property. + - qcom,rx-slave: phandle reference of Soundwire Rx slave device. + - qcom,tx-slave: phandle reference of Soundwire Tx slave device. + +Optional properties: + + - cdc-vdd-rxtx-supply: phandle of rxtx supply's regulator device tree node. + - qcom,cdc-vdd-rxtx-voltage: rxtx supply's voltage level min and max in mV. + - qcom,cdc-vdd-rxtx-current: rxtx supply's max current in mA. + - qcom,cdc-vdd-rxtx-lpm-supported: rxtx supply's LPM mode. + + - cdc-vddio-supply: phandle of io supply's regulator device tree node. + - qcom,cdc-vddio-voltage: io supply's voltage level min and max in mV. + - qcom,cdc-vddio-current: io supply's max current in mA. + - qcom,cdc-vddio-lpm-supported: io supply's LPM mode. + + - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node. + - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV. + - qcom,cdc-vdd-buck-current: buck supply's max current in mA. + + - cdc-vdd-mic-bias-supply: phandle of mic bias supply's regulator device tree node. + - qcom,cdc-vdd-mic-bias-voltage: mic bias supply's voltage level min and max in mV. + - qcom,cdc-vdd-mic-bias-current: mic bias supply's max current in mA. + + - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec + hardware probe. Supplies in this list will be + stay enabled. + + - qcom,cdc-on-demand-supplies: List of supplies which can be enabled + dynamically. + Supplies in this list are off by default. + +Example: +wcd937x_codec: wcd937x-codec { + compatible = "qcom,wcd937x-codec"; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x3 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd937x_rst_gpio>; + qcom,rx-slave = <&wcd937x_rx_slave>; + qcom,tx-slave = <&wcd937x_tx_slave>; + + cdc-vdd-buck-supply = <&S4A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-rxtx-supply = <&S4A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + + cdc-vddio-supply = <&S4A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio"; + qcom,cdc-on-demand-supplies = "cdc-vdd-buck", + "cdc-vdd-mic-bias"; +}; + +Traverso Codec + +Required properties: + - compatible: "qcom,wcd938x-codec"; + - qcom,rx_swr_ch_map: mapping of swr rx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,tx_swr_ch_map: mapping of swr tx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,wcd-rst-gpio-node: Phandle reference to the DT node having codec reset gpio + configuration. If this property is not defined, it is + expected to atleast define "qcom,cdc-reset-gpio" property. + - qcom,rx-slave: phandle reference of Soundwire Rx slave device. + - qcom,tx-slave: phandle reference of Soundwire Tx slave device. + +Optional properties: + + - cdc-vdd-rxtx-supply: phandle of rxtx supply's regulator device tree node. + - qcom,cdc-vdd-rxtx-voltage: rxtx supply's voltage level min and max in mV. + - qcom,cdc-vdd-rxtx-current: rxtx supply's max current in mA. + + - cdc-vddio-supply: phandle of io supply's regulator device tree node. + - qcom,cdc-vddio-voltage: io supply's voltage level min and max in mV. + - qcom,cdc-vddio-current: io supply's max current in mA. + + - cdc-vdd-buck-supply: phandle of buck supply's regulator device tree node. + - qcom,cdc-vdd-buck-voltage: buck supply's voltage level min and max in mV. + - qcom,cdc-vdd-buck-current: buck supply's max current in mA. + + - cdc-vdd-mic-bias-supply: phandle of mic bias supply's regulator device tree node. + - qcom,cdc-vdd-mic-bias-voltage: mic bias supply's voltage level min and max in mV. + - qcom,cdc-vdd-mic-bias-current: mic bias supply's max current in mA. + + - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec + hardware probe. Supplies in this list will be + stay enabled. + + - qcom,cdc-on-demand-supplies: List of supplies which can be enabled + dynamically. + Supplies in this list are off by default. + +Example: +wcd938x_codec: wcd938x-codec { + compatible = "qcom,wcd938x-codec"; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x3 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd938x_rst_gpio>; + qcom,rx-slave = <&wcd938x_rx_slave>; + qcom,tx-slave = <&wcd938x_tx_slave>; + + cdc-vdd-buck-supply = <&S4A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-rxtx-supply = <&S4A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + + cdc-vddio-supply = <&S4A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio"; + qcom,cdc-on-demand-supplies = "cdc-vdd-buck", + "cdc-vdd-mic-bias"; +}; + +Bolero Clock Resource Manager + +Required Properties: + - compatible = "qcom,bolero-clk-rsc-mngr"; + - qcom,fs-gen-sequence: Register sequence for fs clock generation + - clock-names : clock names defined for WSA macro + - clocks : clock handles defined for WSA macro + +Optional Properties: + - qcom,rx_mclk_mode_muxsel: register address for RX macro MCLK mode mux select + - qcom,wsa_mclk_mode_muxsel: register address for WSA macro MCLK mux select + - qcom,va_mclk_mode_muxsel: register address for VA macro MCLK mode mux select + +Example: +&bolero { + bolero-clock-rsc-manager { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,wsa_mclk_mode_muxsel = <0x033220D8>; + qcom,va_mclk_mode_muxsel = <0x033A0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", + "rx_npl_clk", "wsa_core_clk", "wsa_npl_clk", + "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_wsa_1 0>, <&clock_audio_wsa_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; +}; + +WSA Analog Codec + +Required Properties: + - compatible = "qcom,wsa881x-i2c-codec"; + - reg: Specifies the I2C chip address. + - clock-names : clock names defined for WSA master clock + - clocks : clock handles defined for WSA master clock + - qcom,wsa-analog-clk-gpio: Specificies WSA_MCLK GPIO handle + - qcom,wsa-analog-reset-gpio: Specifies WSA reset GPIO handle + +Optional Properties: + - qcom,wsa-analog-vi-gpio: Specifies WSA VI sense GPIO handle + +Example: +&qupv3_se1_i2c { + wsa881x_i2c_f: wsa881x-i2c-codec@f { + compatible = "qcom,wsa881x-i2c-codec"; + reg = <0x0f>; + clock-names = "wsa_mclk"; + clocks = <&wsa881x_analog_clk 0>; + qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>; + qcom,wsa-analog-reset-gpio = <&wsa881x_analog_reset_gpio>; + }; + + wsa881x_i2c_45: wsa881x-i2c-codec@45 { + compatible = "qcom,wsa881x-i2c-codec"; + reg = <0x045>; + }; +}; + +WSA883x Soundwire slave device as child of Soundwire master in Bolero codec + +Required properties: + - compatible = "qcom,wsa883x"; + - reg: Specifies the WSA883x soundwire slave unique device address + - qcom,spkr-sd-n-gpio: speaker reset gpio + +Optional properties: + - bolero-handle: phandle to bolero codec + - cdc-vdd-1p8-supply: phandle of VDD 1.8V supply's regulator device tree node. + - qcom,cdc-vdd-1p8-voltage: VDD 1.8V supply's voltage level min and max in mV. + - qcom,cdc-vdd-1p8-current: VDD 1.8V supply's max current in mA. + - qcom,cdc-vdd-qp8-lpm-supported: VDD 1.8V supply's LPM mode. + - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec + hardware probe. Supplies in this list will be + stay enabled. + +Example: +wsa883x_0221: wsa883x@02170221 { + compatible = "qcom,wsa883x"; + reg = <0x02 0x02170221>; + qcom,spkr-sd-n-gpio = <&tlmm 80 0>; + bolero-handle = <&bolero>; + + cdc-vdd-1p8-supply = <&S10B>; + qcom,cdc-vdd-1p8-voltage = <1800000 1800000>; + qcom,cdc-vdd-1p8-current = <20000>; + qcom,cdc-static-supplies = "cdc-vdd-1p8"; +}; + +PM2250 SPMI node + +pm2250_spmi: Child node of SPMI bus required for rouleur codec + in order to access SPMI register to reset the peripheral. + +Required properties: + -compatible: "qcom,pm2250-spmi"; + +&spmi_bus { + pm2250_cdc: qcom,pm2250-cdc { + compatible = "qcom,pm2250-spmi"; + }; +}; + + +Rouleur Codec + +Required properties: + - compatible: "qcom,rouleur-codec"; + - qcom,split-codec: Property to check on split codec support. + - qcom,rx_swr_ch_map: mapping of swr rx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,tx_swr_ch_map: mapping of swr tx slave port configuration to port_type and also + corresponding master port type it need to attach. + format: + same port_id configurations have to be grouped, and in ascending order. + - qcom,pmic-spmi-node: Phandle reference to the PMIC SPMI DT node. + - qcom,wcd-reset-reg: Reset register address in PMIC for rouleur codec. + - qcom,rx-slave: phandle reference of Soundwire Rx slave device. + - qcom,tx-slave: phandle reference of Soundwire Tx slave device. + +Optional properties: + + - cdc-pa-vpos-supply: phandle of pa vpos supply's regulator device tree node. + - qcom,cdc-pa-vpos-voltage: pa vpos supply's voltage level min and max in mV. + - qcom,cdc-pa-vpos-current: pa vpos supply's max current in mA. + + - cdc-vdd-io-supply: phandle of io supply's regulator device tree node. + - qcom,cdc-vdd-io-voltage: io supply's voltage level min and max in mV. + - qcom,cdc-vdd-io-current: io supply's max current in mA. + + - cdc-vdd-cp-supply: phandle of vdd cp supply's regulator device tree node. + - qcom,cdc-vdd-cp-voltage: vdd cp supply's voltage level min and max in mV. + - qcom,cdc-vdd-cp-current: vdd cp supply's max current in mA. + + - cdc-vdd-mic-bias-supply: phandle of mic bias supply's regulator device tree node. + - qcom,cdc-vdd-mic-bias-voltage: mic bias supply's voltage level min and max in mV. + - qcom,cdc-vdd-mic-bias-current: mic bias supply's max current in mA. + - qcom,cdc-vdd-mic-bias-lpm-supported: mic bias supply's LPM mode. + + - qcom,cdc-static-supplies: List of supplies to be enabled prior to codec + hardware probe. Supplies in this list will be + stay enabled. + + - qcom,cdc-on-demand-supplies: List of supplies which can be enabled + dynamically. + Supplies in this list are off by default. + +Example: + + rouleur_codec: rouleur-codec { + compatible = "qcom,rouleur-codec"; + qcom,split-codec = <1>; + qcom,pmic-spmi-node = <&pm2250_cdc>; + qcom,wcd-reset-reg = <0x0000F3DB>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <0 ADC2 0x2 0 ADC2>, <0 DMIC0 0x4 0 ADC3>, + <0 MBHC 0x8 0 ADC4>, <1 DMIC0 0x1 0 DMIC0>, + <1 DMIC1 0x2 0 DMIC1>, <1 ADC1 0x4 0 DMIC2>, + <1 MBHC 0x8 0 DMIC3>; + + qcom,rx-slave = <&rouleur_rx_slave>; + qcom,tx-slave = <&rouleur_tx_slave>; + + cdc-vdd-io-supply = <&L15A>; + qcom,cdc-vdd-io-voltage = <1800000 1800000>; + qcom,cdc-vdd-io-current = <10000>; + + cdc-vdd-cp-supply = <&S4A>; + qcom,cdc-vdd-cp-voltage = <2040000 2040000>; + qcom,cdc-vdd-cp-current = <300000>; + + cdc-pa-vpos-supply = <&S4A>; + qcom,cdc-pa-vpos-voltage = <2040000 2040000>; + qcom,cdc-pa-vpos-current = <2400000>; + + cdc-vdd-mic-bias-supply = <&L22A>; + qcom,cdc-vdd-mic-bias-voltage = <3304000 3304000>; + qcom,cdc-vdd-mic-bias-current = <50000>; + qcom,cdc-vdd-mic-bias-lpm-supported = <1>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-cp", + "cdc-vdd-io"; + qcom,cdc-on-demand-supplies = "cdc-pa-vpos", + "cdc-vdd-mic-bias"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/widgets.txt b/arch/arm64/boot/dts/vendor/bindings/sound/widgets.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6de5ba3b2dec4410f0a104858374026536ede60 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/widgets.txt @@ -0,0 +1,20 @@ +Widgets: + +This mainly specifies audio off-codec DAPM widgets. + +Each entry is a pair of strings in DT: + + "template-wname", "user-supplied-wname" + +The "template-wname" being the template widget name and currently includes: +"Microphone", "Line", "Headphone" and "Speaker". + +The "user-supplied-wname" being the user specified widget name. + +For instance: + simple-audio-widgets = + "Microphone", "Microphone Jack", + "Line", "Line In Jack", + "Line", "Line Out Jack", + "Headphone", "Headphone Jack", + "Speaker", "Speaker External"; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wlf,arizona.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wlf,arizona.txt new file mode 100644 index 0000000000000000000000000000000000000000..e172c62dc2dffd58d64b9810af849ce2f6e863b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wlf,arizona.txt @@ -0,0 +1,53 @@ +Cirrus Logic Arizona class audio SoCs + +These devices are audio SoCs with extensive digital capabilities and a range +of analogue I/O. + +This document lists sound specific bindings, see the primary binding +document: + ../mfd/arizona.txt + +Optional properties: + + - wlf,inmode : A list of INn_MODE register values, where n is the number + of input signals. Valid values are 0 (Differential), 1 (Single-ended) and + 2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default. + If present, values must be specified less than or equal to the number of + input signals. If values less than the number of input signals, elements + that have not been specified are set to 0 by default. Entries are: + (wm5102, wm5110, wm8280, wm8997) + (wm8998, wm1814) + - wlf,out-mono : A list of boolean values indicating whether each output is + mono or stereo. Position within the list indicates the output affected + (eg. First entry in the list corresponds to output 1). A non-zero value + indicates a mono output. If present, the number of values should be less + than or equal to the number of outputs, if less values are supplied the + additional outputs will be treated as stereo. + + - wlf,dmic-ref : DMIC reference voltage source for each input, can be + selected from either MICVDD or one of the MICBIAS's, defines + (ARIZONA_DMIC_xxxx) are provided in . If + present, the number of values should be less than or equal to the + number of inputs, unspecified inputs will use the chip default. + + - wlf,max-channels-clocked : The maximum number of channels to be clocked on + each AIF, useful for I2S systems with multiple data lines being mastered. + Specify one cell for each AIF to be configured, specify zero for AIFs that + should be handled normally. + If present, number of cells must be less than or equal to the number of + AIFs. If less than the number of AIFs, for cells that have not been + specified the corresponding AIFs will be treated as default setting. + + - wlf,spk-fmt : PDM speaker data format, must contain 2 cells (OUT5 and OUT6). + See the datasheet for values. + The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997, + wm8998, wm1814) + + - wlf,spk-mute : PDM speaker mute setting, must contain 2 cells (OUT5 and OUT6). + See the datasheet for values. + The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997, + wm8998, wm1814) + + - wlf,out-volume-limit : The volume limit value that should be applied to each + output channel. See the datasheet for exact values. Channels are specified + in the order OUT1L, OUT1R, OUT2L, OUT2R, etc. diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wlf,wm8974.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wlf,wm8974.txt new file mode 100644 index 0000000000000000000000000000000000000000..01d3a7c83419785a31f395e8795890bbecda6197 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wlf,wm8974.txt @@ -0,0 +1,15 @@ +WM8974 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + - compatible: "wlf,wm8974" + - reg: the I2C address or SPI chip select number of the device + +Examples: + +codec: wm8974@1a { + compatible = "wlf,wm8974"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8510.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8510.txt new file mode 100644 index 0000000000000000000000000000000000000000..e6b6cc041f895b21d22cfc8a7e73277d2716fff1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8510.txt @@ -0,0 +1,18 @@ +WM8510 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8510" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8510: codec@1a { + compatible = "wlf,wm8510"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8523.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8523.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3a6485f4b8abf1b149c944d1f3486936f6529e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8523.txt @@ -0,0 +1,16 @@ +WM8523 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8523" + + - reg : the I2C address of the device. + +Example: + +wm8523: codec@1a { + compatible = "wlf,wm8523"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8524.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8524.txt new file mode 100644 index 0000000000000000000000000000000000000000..f6c0c263b135add1539054bb3beee8414da11c63 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8524.txt @@ -0,0 +1,16 @@ +WM8524 audio CODEC + +This device does not use I2C or SPI but a simple Hardware Control Interface. + +Required properties: + + - compatible : "wlf,wm8524" + + - wlf,mute-gpios: a GPIO spec for the MUTE pin. + +Example: + +wm8524: codec { + compatible = "wlf,wm8524"; + wlf,mute-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8580.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8580.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff3f9f5f2111f7afc832fcf6b280468dad843eb1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8580.txt @@ -0,0 +1,16 @@ +WM8580 and WM8581 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8580", "wlf,wm8581" + + - reg : the I2C address of the device. + +Example: + +wm8580: codec@1a { + compatible = "wlf,wm8580"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8711.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8711.txt new file mode 100644 index 0000000000000000000000000000000000000000..c30a1387c4bff4f08a081d1a711b43d6f8e2a53e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8711.txt @@ -0,0 +1,18 @@ +WM8711 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8711" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8711: codec@1a { + compatible = "wlf,wm8711"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8728.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8728.txt new file mode 100644 index 0000000000000000000000000000000000000000..a3608b4c78b95ce2a3998de2df43e6a3d8fbc4d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8728.txt @@ -0,0 +1,18 @@ +WM8728 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8728" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8728: codec@1a { + compatible = "wlf,wm8728"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8731.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8731.txt new file mode 100644 index 0000000000000000000000000000000000000000..f660d9bb0e698eb0a9d141541709071ff745b418 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8731.txt @@ -0,0 +1,27 @@ +WM8731 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8731" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8731: codec@1a { + compatible = "wlf,wm8731"; + reg = <0x1a>; +}; + +Available audio endpoints for an audio-routing table: + * LOUT: Left Channel Line Output + * ROUT: Right Channel Line Output + * LHPOUT: Left Channel Headphone Output + * RHPOUT: Right Channel Headphone Output + * LLINEIN: Left Channel Line Input + * RLINEIN: Right Channel Line Input + * MICIN: Microphone Input diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8737.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8737.txt new file mode 100644 index 0000000000000000000000000000000000000000..eda1ec6a7563a04a4b83bc3fafea57d91b4ec9a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8737.txt @@ -0,0 +1,18 @@ +WM8737 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8737" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8737: codec@1a { + compatible = "wlf,wm8737"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8741.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8741.txt new file mode 100644 index 0000000000000000000000000000000000000000..b69e196c741c4f8d13b051e16b06c904e64c25f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8741.txt @@ -0,0 +1,29 @@ +WM8741 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8741" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Optional properties: + + - diff-mode: Differential output mode configuration. Default value for field + DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be: + 0 = stereo + 1 = mono left + 2 = stereo reversed + 3 = mono right + +Example: + +wm8741: codec@1a { + compatible = "wlf,wm8741"; + reg = <0x1a>; + + diff-mode = <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8750.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8750.txt new file mode 100644 index 0000000000000000000000000000000000000000..682f221f6f38e3615d043070a26585916e096dc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8750.txt @@ -0,0 +1,18 @@ +WM8750 and WM8987 audio CODECs + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8750" or "wlf,wm8987" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8750: codec@1a { + compatible = "wlf,wm8750"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8753.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8753.txt new file mode 100644 index 0000000000000000000000000000000000000000..eca9e5a825a96e5ff17f682a83ffeef7f33a896b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8753.txt @@ -0,0 +1,40 @@ +WM8753 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8753" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Pins on the device (for linking into audio routes): + + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * MONO1 + * MONO2 + * OUT3 + * OUT4 + * LINE1 + * LINE2 + * RXP + * RXN + * ACIN + * ACOP + * MIC1N + * MIC1 + * MIC2N + * MIC2 + * Mic Bias + +Example: + +wm8753: codec@1a { + compatible = "wlf,wm8753"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8770.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8770.txt new file mode 100644 index 0000000000000000000000000000000000000000..cac762a1105ded99ebe0966d2c4f0c67bbba7dc6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8770.txt @@ -0,0 +1,16 @@ +WM8770 audio CODEC + +This device supports SPI. + +Required properties: + + - compatible : "wlf,wm8770" + + - reg : the chip select number. + +Example: + +wm8770: codec@1 { + compatible = "wlf,wm8770"; + reg = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8776.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8776.txt new file mode 100644 index 0000000000000000000000000000000000000000..01173369c3ed300a89dd86c288757ddfae0e37b7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8776.txt @@ -0,0 +1,18 @@ +WM8776 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8776" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +wm8776: codec@1a { + compatible = "wlf,wm8776"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8804.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8804.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c1641c17a91efc97c0a6194724da559849721cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8804.txt @@ -0,0 +1,25 @@ +WM8804 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8804" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + + - PVDD-supply, DVDD-supply : Power supplies for the device, as covered + in Documentation/devicetree/bindings/regulator/regulator.txt + +Optional properties: + + - wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin + +Example: + +wm8804: codec@1a { + compatible = "wlf,wm8804"; + reg = <0x1a>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8903.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8903.txt new file mode 100644 index 0000000000000000000000000000000000000000..6371c2434afe75f0dbfd7228f1b905879fc0288d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8903.txt @@ -0,0 +1,82 @@ +WM8903 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8903" + + - reg : the I2C address of the device. + + - gpio-controller : Indicates this device is a GPIO controller. + + - #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + +Optional properties: + + - interrupts : The interrupt line the codec is connected to. + + - micdet-cfg : Default register value for R6 (Mic Bias). If absent, the + default is 0. + + - micdet-delay : The debounce delay for microphone detection in mS. If + absent, the default is 100. + + - gpio-cfg : A list of GPIO configuration register values. The list must + be 5 entries long. If absent, no configuration of these registers is + performed. If any entry has the value 0xffffffff, that GPIO's + configuration will not be modified. + + - AVDD-supply : Analog power supply regulator on the AVDD pin. + + - CPVDD-supply : Charge pump supply regulator on the CPVDD pin. + + - DBVDD-supply : Digital buffer supply regulator for the DBVDD pin. + + - DCVDD-supply : Digital core supply regulator for the DCVDD pin. + +Pins on the device (for linking into audio routes): + + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * DMICDAT + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * LOP + * LON + * ROP + * RON + * MICBIAS + +Example: + +wm8903: codec@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupts = < 347 >; + + AVDD-supply = <&fooreg_a>; + CPVDD-supply = <&fooreg_b>; + DBVDD-supply = <&fooreg_c>; + DCVDC-supply = <&fooreg_d>; + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = < + 0x0600 /* DMIC_LR, output */ + 0x0680 /* DMIC_DAT, input */ + 0x0000 /* GPIO, output, low */ + 0x0200 /* Interrupt, output */ + 0x01a0 /* BCLK, input, active high */ + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8904.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8904.txt new file mode 100644 index 0000000000000000000000000000000000000000..66bf261423b92499d54694e46a4fcfd90b23f753 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8904.txt @@ -0,0 +1,33 @@ +WM8904 audio CODEC + +This device supports I2C only. + +Required properties: + - compatible: "wlf,wm8904" or "wlf,wm8912" + - reg: the I2C address of the device. + - clock-names: "mclk" + - clocks: reference to + + +Pins on the device (for linking into audio routes): + + * IN1L + * IN1R + * IN2L + * IN2R + * IN3L + * IN3R + * HPOUTL + * HPOUTR + * LINEOUTL + * LINEOUTR + * MICBIAS + +Examples: + +codec: wm8904@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + clocks = <&pck0>; + clock-names = "mclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8960.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8960.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d29ac3750eeea29da05a361b527580e65d6f76f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8960.txt @@ -0,0 +1,31 @@ +WM8960 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8960" + + - reg : the I2C address of the device. + +Optional properties: + - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of + R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins + will be disabled only when ADC (Left and Right) and DAC (Left and Right) + are disabled. + When wm8960 works on synchronize mode and DACLRC pin is used to supply + frame clock, it will no frame clock for captrue unless enable DAC to enable + DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue. + + - wlf,capless: This is a boolean property. If present, OUT3 pin will be + enabled and disabled together with HP_L and HP_R pins in response to jack + detect events. + +Example: + +wm8960: codec@1a { + compatible = "wlf,wm8960"; + reg = <0x1a>; + + wlf,shared-lrclk; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8962.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8962.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcfa9a3369fde640da518de0f61466a1a54235c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8962.txt @@ -0,0 +1,39 @@ +WM8962 audio CODEC + +This device supports I2C only. + +Required properties: + + - compatible : "wlf,wm8962" + + - reg : the I2C address of the device. + +Optional properties: + - spk-mono: This is a boolean property. If present, the SPK_MONO bit + of R51 (Class D Control 2) gets set, indicating that the speaker is + in mono mode. + + - mic-cfg : Default register value for R48 (Additional Control 4). + If absent, the default should be the register default. + + - gpio-cfg : A list of GPIO configuration register values. The list must + be 6 entries long. If absent, no configuration of these registers is + performed. And note that only the value within [0x0, 0xffff] is valid. + Any other value is regarded as setting the GPIO register by its reset + value 0x0. + +Example: + +wm8962: codec@1a { + compatible = "wlf,wm8962"; + reg = <0x1a>; + + gpio-cfg = < + 0x0000 /* 0:Default */ + 0x0000 /* 1:Default */ + 0x0013 /* 2:FN_DMICCLK */ + 0x0000 /* 3:Default */ + 0x8014 /* 4:FN_DMICCDAT */ + 0x0000 /* 5:Default */ + >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/wm8994.txt b/arch/arm64/boot/dts/vendor/bindings/sound/wm8994.txt new file mode 100644 index 0000000000000000000000000000000000000000..68cccc4653ba390aecaee8e3121ad03a7a4f79e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/wm8994.txt @@ -0,0 +1,83 @@ +WM1811/WM8994/WM8958 audio CODEC + +These devices support both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : One of "wlf,wm1811", "wlf,wm8994" or "wlf,wm8958". + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + + - gpio-controller : Indicates this device is a GPIO controller. + - #gpio-cells : Must be 2. The first cell is the pin number and the + second cell is used to specify optional parameters (currently unused). + + - AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply, + SPKVDD1-supply, SPKVDD2-supply : power supplies for the device, as covered + in Documentation/devicetree/bindings/regulator/regulator.txt + +Optional properties: + + - interrupts : The interrupt line the IRQ signal for the device is + connected to. This is optional, if it is not connected then none + of the interrupt related properties should be specified. + - interrupt-controller : These devices contain interrupt controllers + and may provide interrupt services to other devices if they have an + interrupt line connected. + - #interrupt-cells: the number of cells to describe an IRQ, this should be 2. + The first cell is the IRQ number. + The second cell is the flags, encoded as the trigger masks from + Documentation/devicetree/bindings/interrupt-controller/interrupts.txt + + - clocks : A list of up to two phandle and clock specifier pairs + - clock-names : A list of clock names sorted in the same order as clocks. + Valid clock names are "MCLK1" and "MCLK2". + + - wlf,gpio-cfg : A list of GPIO configuration register values. If absent, + no configuration of these registers is performed. If any value is + over 0xffff then the register will be left as default. If present 11 + values must be supplied. + + - wlf,micbias-cfg : Two MICBIAS register values for WM1811 or + WM8958. If absent the register defaults will be used. + + - wlf,ldo1ena : GPIO specifier for control of LDO1ENA input to device. + - wlf,ldo2ena : GPIO specifier for control of LDO2ENA input to device. + + - wlf,lineout1-se : If present LINEOUT1 is in single ended mode. + - wlf,lineout2-se : If present LINEOUT2 is in single ended mode. + + - wlf,lineout1-feedback : If present LINEOUT1 has common mode feedback + connected. + - wlf,lineout2-feedback : If present LINEOUT2 has common mode feedback + connected. + + - wlf,ldoena-always-driven : If present LDOENA is always driven. + + - wlf,spkmode-pu : If present enable the internal pull-up resistor on + the SPKMODE pin. + + - wlf,csnaddr-pd : If present enable the internal pull-down resistor on + the CS/ADDR pin. + +Example: + +wm8994: codec@1a { + compatible = "wlf,wm8994"; + reg = <0x1a>; + + gpio-controller; + #gpio-cells = <2>; + + lineout1-se; + + AVDD2-supply = <®ulator>; + CPVDD-supply = <®ulator>; + DBVDD1-supply = <®ulator>; + DBVDD2-supply = <®ulator>; + DBVDD3-supply = <®ulator>; + SPKVDD1-supply = <®ulator>; + SPKVDD2-supply = <®ulator>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/zte,tdm.txt b/arch/arm64/boot/dts/vendor/bindings/sound/zte,tdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a07ca655264c377a2d8a658b10f594d6206b34a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/zte,tdm.txt @@ -0,0 +1,30 @@ +ZTE TDM DAI driver + +Required properties: + +- compatible : should be one of the following. + * zte,zx296718-tdm +- reg : physical base address of the controller and length of memory mapped + region. +- clocks : Pairs of phandle and specifier referencing the controller's clocks. +- clock-names: "wclk" for the wclk. + "pclk" for the pclk. +-#clock-cells: should be 1. +- zte,tdm-dma-sysctrl : Reference to the sysctrl controller controlling + the dma. includes: + phandle of sysctrl. + register offset in sysctrl for control dma. + mask of the register that be written to sysctrl. + +Example: + + tdm: tdm@1487000 { + compatible = "zte,zx296718-tdm"; + reg = <0x01487000 0x1000>; + clocks = <&audiocrm AUDIO_TDM_WCLK>, <&audiocrm AUDIO_TDM_PCLK>; + clock-names = "wclk", "pclk"; + #clock-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&tdm_global_pin>; + zte,tdm-dma-sysctrl = <&sysctrl 0x10c 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-aud96p22.txt b/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-aud96p22.txt new file mode 100644 index 0000000000000000000000000000000000000000..41bb1040eb71615558c415fe57a2dbf081715d6f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-aud96p22.txt @@ -0,0 +1,24 @@ +ZTE ZX AUD96P22 Audio Codec + +Required properties: + - compatible: Must be "zte,zx-aud96p22" + - #sound-dai-cells: Should be 0 + - reg: I2C bus slave address of AUD96P22 + +Example: + + i2c0: i2c@1486000 { + compatible = "zte,zx296718-i2c"; + reg = <0x01486000 0x1000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&audiocrm AUDIO_I2C0_WCLK>; + clock-frequency = <1600000>; + + aud96p22: codec@22 { + compatible = "zte,zx-aud96p22"; + #sound-dai-cells = <0>; + reg = <0x22>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-i2s.txt b/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-i2s.txt new file mode 100644 index 0000000000000000000000000000000000000000..3927251464f0619da76a6c43f2f24e978cf97d06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-i2s.txt @@ -0,0 +1,45 @@ +ZTE ZX296702 I2S controller + +Required properties: + - compatible : Must be one of: + "zte,zx296718-i2s", "zte,zx296702-i2s" + "zte,zx296702-i2s" + - reg : Must contain I2S core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's clocks. + - clock-names: "wclk" for the wclk, "pclk" for the pclk to the I2S interface. + - dmas: Pairs of phandle and specifier for the DMA channel that is used by + the core. The core expects two dma channels for transmit. + - dma-names : Must be "tx" and "rx" + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties +please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + i2s0: i2s@b005000 { + #sound-dai-cells = <0>; + compatible = "zte,zx296718-i2s", "zte,zx296702-i2s"; + reg = <0x0b005000 0x1000>; + clocks = <&audiocrm AUDIO_I2S0_WCLK>, <&audiocrm AUDIO_I2S0_PCLK>; + clock-names = "wclk", "pclk"; + interrupts = ; + dmas = <&dma 5>, <&dma 6>; + dma-names = "tx", "rx"; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "zx296702_snd"; + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + sndcpu: simple-audio-card,cpu { + sound-dai = <&i2s0>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&acodec>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-spdif.txt b/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-spdif.txt new file mode 100644 index 0000000000000000000000000000000000000000..09231d7586b2e184dab34353a06d3458499bb69e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sound/zte,zx-spdif.txt @@ -0,0 +1,27 @@ +ZTE ZX296702 SPDIF controller + +Required properties: + - compatible : Must be "zte,zx296702-spdif" + - reg : Must contain SPDIF core's registers location and length + - clocks : Pairs of phandle and specifier referencing the controller's clocks. + - clock-names: "tx" for the clock to the SPDIF interface. + - dmas: Pairs of phandle and specifier for the DMA channel that is used by + the core. The core expects one dma channel for transmit. + - dma-names : Must be "tx" + +For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties +please check: + * resource-names.txt + * clock/clock-bindings.txt + * dma/dma.txt + +Example: + spdif0: spdif0@b004000 { + compatible = "zte,zx296702-spdif"; + reg = <0x0b004000 0x1000>; + clocks = <&lsp0clk ZX296702_SPDIF0_DIV>; + clock-names = "tx"; + interrupts = ; + dmas = <&dma 4>; + dma-names = "tx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/adi,axi-spi-engine.txt b/arch/arm64/boot/dts/vendor/bindings/spi/adi,axi-spi-engine.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a18d71e68791fbf29256716d5c83d31eed0701d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/adi,axi-spi-engine.txt @@ -0,0 +1,31 @@ +Analog Devices AXI SPI Engine controller Device Tree Bindings + +Required properties: +- compatible : Must be "adi,axi-spi-engine-1.00.a"" +- reg : Physical base address and size of the register map. +- interrupts : Property with a value describing the interrupt + number. +- clock-names : List of input clock names - "s_axi_aclk", "spi_clk" +- clocks : Clock phandles and specifiers (See clock bindings for + details on clock-names and clocks). +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Optional subnodes: + Subnodes are use to represent the SPI slave devices connected to the SPI + master. They follow the generic SPI bindings as outlined in spi-bus.txt. + +Example: + + spi@@44a00000 { + compatible = "adi,axi-spi-engine-1.00.a"; + reg = <0x44a00000 0x1000>; + interrupts = <0 56 4>; + clocks = <&clkc 15 &clkc 15>; + clock-names = "s_axi_aclk", "spi_clk"; + + #address-cells = <1>; + #size-cells = <0>; + + /* SPI devices */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/brcm,bcm2835-aux-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/brcm,bcm2835-aux-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..9887b07247590ad92fa107f50311afd81a310a46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/brcm,bcm2835-aux-spi.txt @@ -0,0 +1,38 @@ +Broadcom BCM2835 auxiliar SPI1/2 controller + +The BCM2835 contains two forms of SPI master controller, one known simply as +SPI0, and the other known as the "Universal SPI Master"; part of the +auxiliary block. This binding applies to the SPI1/2 controller. + +Required properties: +- compatible: Should be "brcm,bcm2835-aux-spi". +- reg: Should contain register location and length for the spi block +- interrupts: Should contain shared interrupt of the aux block +- clocks: The clock feeding the SPI controller - needs to + point to the auxiliar clock driver of the bcm2835, + as this clock will enable the output gate for the specific + clock. +- cs-gpios: the cs-gpios (native cs is NOT supported) + see also spi-bus.txt + +Example: + +spi1@7e215080 { + compatible = "brcm,bcm2835-aux-spi"; + reg = <0x7e215080 0x40>; + interrupts = <1 29>; + clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>; + #address-cells = <1>; + #size-cells = <0>; + cs-gpios = <&gpio 18>, <&gpio 17>, <&gpio 16>; +}; + +spi2@7e2150c0 { + compatible = "brcm,bcm2835-aux-spi"; + reg = <0x7e2150c0 0x40>; + interrupts = <1 29>; + clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI2>; + #address-cells = <1>; + #size-cells = <0>; + cs-gpios = <&gpio 43>, <&gpio 44>, <&gpio 45>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/brcm,bcm2835-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/brcm,bcm2835-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..f11f295c845042acb1a84bacb26036d6dba53498 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/brcm,bcm2835-spi.txt @@ -0,0 +1,22 @@ +Broadcom BCM2835 SPI0 controller + +The BCM2835 contains two forms of SPI master controller, one known simply as +SPI0, and the other known as the "Universal SPI Master"; part of the +auxiliary block. This binding applies to the SPI0 controller. + +Required properties: +- compatible: Should be "brcm,bcm2835-spi". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks: The clock feeding the SPI controller. + +Example: + +spi@20204000 { + compatible = "brcm,bcm2835-spi"; + reg = <0x7e204000 0x1000>; + interrupts = <2 22>; + clocks = <&clk_spi>; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/brcm,spi-bcm-qspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/brcm,spi-bcm-qspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..ad7ac80a3841fb06d5b1962d378090a2e24a678a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/brcm,spi-bcm-qspi.txt @@ -0,0 +1,233 @@ +Broadcom SPI controller + +The Broadcom SPI controller is a SPI master found on various SOCs, including +BRCMSTB (BCM7XXX), Cygnus, NSP and NS2. The Broadcom Master SPI hw IP consits +of : + MSPI : SPI master controller can read and write to a SPI slave device + BSPI : Broadcom SPI in combination with the MSPI hw IP provides acceleration + for flash reads and be configured to do single, double, quad lane + io with 3-byte and 4-byte addressing support. + + Supported Broadcom SoCs have one instance of MSPI+BSPI controller IP. + MSPI master can be used wihout BSPI. BRCMSTB SoCs have an additional instance + of a MSPI master without the BSPI to use with non flash slave devices that + use SPI protocol. + +Required properties: + +- #address-cells: + Must be <1>, as required by generic SPI binding. + +- #size-cells: + Must be <0>, also as required by generic SPI binding. + +- compatible: + Must be one of : + "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs + "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI + BRCMSTB SoCs + "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi" : MSPI+BSPI on Cygnus, NSP + "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi" : NS2 SoCs + +- reg: + Define the bases and ranges of the associated I/O address spaces. + The required range is MSPI controller registers. + +- reg-names: + First name does not matter, but must be reserved for the MSPI controller + register range as mentioned in 'reg' above, and will typically contain + - "bspi_regs": BSPI register range, not required with compatible + "spi-brcmstb-mspi" + - "mspi_regs": MSPI register range is required for compatible strings + - "intr_regs", "intr_status_reg" : Interrupt and status register for + NSP, NS2, Cygnus SoC + +- interrupts + The interrupts used by the MSPI and/or BSPI controller. + +- interrupt-names: + Names of interrupts associated with MSPI + - "mspi_halted" : + - "mspi_done": Indicates that the requested SPI operation is complete. + - "spi_lr_fullness_reached" : Linear read BSPI pipe full + - "spi_lr_session_aborted" : Linear read BSPI pipe aborted + - "spi_lr_impatient" : Linear read BSPI requested when pipe empty + - "spi_lr_session_done" : Linear read BSPI session done + +- clocks: + A phandle to the reference clock for this block. + +Optional properties: + + +- native-endian + Defined when using BE SoC and device uses BE register read/write + +Recommended optional m25p80 properties: +- spi-rx-bus-width: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Examples: + +BRCMSTB SoC Example: + + SPI Master (MSPI+BSPI) for SPI-NOR access: + + spi@f03e3400 { + #address-cells = <0x1>; + #size-cells = <0x0>; + compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-qspi"; + reg = <0xf03e0920 0x4 0xf03e3400 0x188 0xf03e3200 0x50>; + reg-names = "cs_reg", "mspi", "bspi"; + interrupts = <0x6 0x5 0x4 0x3 0x2 0x1 0x0>; + interrupt-parent = <0x1c>; + interrupt-names = "mspi_halted", + "mspi_done", + "spi_lr_overread", + "spi_lr_session_done", + "spi_lr_impatient", + "spi_lr_session_aborted", + "spi_lr_fullness_reached"; + + clocks = <&hif_spi>; + clock-names = "sw_spi"; + + m25p80@0 { + #size-cells = <0x2>; + #address-cells = <0x2>; + compatible = "m25p80"; + reg = <0x0>; + spi-max-frequency = <0x2625a00>; + spi-cpol; + spi-cpha; + m25p,fast-read; + + flash0.bolt@0 { + reg = <0x0 0x0 0x0 0x100000>; + }; + + flash0.macadr@100000 { + reg = <0x0 0x100000 0x0 0x10000>; + }; + + flash0.nvram@110000 { + reg = <0x0 0x110000 0x0 0x10000>; + }; + + flash0.kernel@120000 { + reg = <0x0 0x120000 0x0 0x400000>; + }; + + flash0.devtree@520000 { + reg = <0x0 0x520000 0x0 0x10000>; + }; + + flash0.splash@530000 { + reg = <0x0 0x530000 0x0 0x80000>; + }; + + flash0@0 { + reg = <0x0 0x0 0x0 0x4000000>; + }; + }; + }; + + + MSPI master for any SPI device : + + spi@f0416000 { + #address-cells = <1>; + #size-cells = <0>; + clocks = <&upg_fixed>; + compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-mspi"; + reg = <0xf0416000 0x180>; + reg-names = "mspi"; + interrupts = <0x14>; + interrupt-parent = <&irq0_aon_intc>; + interrupt-names = "mspi_done"; + }; + +iProc SoC Example: + + qspi: spi@18027200 { + compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi"; + reg = <0x18027200 0x184>, + <0x18027000 0x124>, + <0x1811c408 0x004>, + <0x180273a0 0x01c>; + reg-names = "mspi_regs", "bspi_regs", "intr_regs", "intr_status_reg"; + interrupts = , + , + , + , + , + , + ; + interrupt-names = + "spi_lr_fullness_reached", + "spi_lr_session_aborted", + "spi_lr_impatient", + "spi_lr_session_done", + "mspi_done", + "mspi_halted"; + clocks = <&iprocmed>; + clock-names = "iprocmed"; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + + NS2 SoC Example: + + qspi: spi@66470200 { + compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi"; + reg = <0x66470200 0x184>, + <0x66470000 0x124>, + <0x67017408 0x004>, + <0x664703a0 0x01c>; + reg-names = "mspi", "bspi", "intr_regs", + "intr_status_reg"; + interrupts = ; + interrupt-names = "spi_l1_intr"; + clocks = <&iprocmed>; + clock-names = "iprocmed"; + num-cs = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + + m25p80 node for NSP, NS2 + + &qspi { + flash: m25p80@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "m25p80"; + reg = <0x0>; + spi-max-frequency = <12500000>; + m25p,fast-read; + spi-cpol; + spi-cpha; + + partition@0 { + label = "boot"; + reg = <0x00000000 0x000a0000>; + }; + + partition@a0000 { + label = "env"; + reg = <0x000a0000 0x00060000>; + }; + + partition@100000 { + label = "system"; + reg = <0x00100000 0x00600000>; + }; + + partition@700000 { + label = "rootfs"; + reg = <0x00700000 0x01900000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/efm32-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/efm32-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e0fa61a1be0c864258574787d8fa496db2118916 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/efm32-spi.txt @@ -0,0 +1,39 @@ +* Energy Micro EFM32 SPI + +Required properties: +- #address-cells: see spi-bus.txt +- #size-cells: see spi-bus.txt +- compatible: should be "energymicro,efm32-spi" +- reg: Offset and length of the register set for the controller +- interrupts: pair specifying rx and tx irq +- clocks: phandle to the spi clock +- cs-gpios: see spi-bus.txt + +Recommended properties : +- energymicro,location: Value to write to the ROUTE register's LOCATION + bitfield to configure the pinmux for the device, see + datasheet for values. + If this property is not provided, keeping what is + already configured in the hardware, so its either the + reset default 0 or whatever the bootloader did. + +Example: + +spi1: spi@4000c400 { /* USART1 */ + #address-cells = <1>; + #size-cells = <0>; + compatible = "energymicro,efm32-spi"; + reg = <0x4000c400 0x400>; + interrupts = <15 16>; + clocks = <&cmu 20>; + cs-gpios = <&gpio 51 1>; // D3 + energymicro,location = <1>; + + ks8851@0 { + compatible = "ks8851"; + spi-max-frequency = <6000000>; + reg = <0>; + interrupt-parent = <&boardfpga>; + interrupts = <4>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/fsl-imx-cspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/fsl-imx-cspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3c48b20b1a691b37d0b425251a257c682a38eca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/fsl-imx-cspi.txt @@ -0,0 +1,52 @@ +* Freescale (Enhanced) Configurable Serial Peripheral Interface + (CSPI/eCSPI) for i.MX + +Required properties: +- compatible : + - "fsl,imx1-cspi" for SPI compatible with the one integrated on i.MX1 + - "fsl,imx21-cspi" for SPI compatible with the one integrated on i.MX21 + - "fsl,imx27-cspi" for SPI compatible with the one integrated on i.MX27 + - "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31 + - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35 + - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51 + - "fsl,imx53-ecspi" for SPI compatible with the one integrated on i.MX53 and later Soc +- reg : Offset and length of the register set for the device +- interrupts : Should contain CSPI/eCSPI interrupt +- clocks : Clock specifiers for both ipg and per clocks. +- clock-names : Clock names should include both "ipg" and "per" +See the clock consumer binding, + Documentation/devicetree/bindings/clock/clock-bindings.txt + +Recommended properties: +- cs-gpios : GPIOs to use as chip selects, see spi-bus.txt. While the native chip +select lines can be used, they appear to always generate a pulse between each +word of a transfer. Most use cases will require GPIO based chip selects to +generate a valid transaction. + +Optional properties: +- num-cs : Number of total chip selects, see spi-bus.txt. +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, +Documentation/devicetree/bindings/dma/dma.txt. +- dma-names: DMA request names, if present, should include "tx" and "rx". +- fsl,spi-rdy-drctl: Integer, representing the value of DRCTL, the register +controlling the SPI_READY handling. Note that to enable the DRCTL consideration, +the SPI_READY mode-flag needs to be set too. +Valid values are: 0 (disabled), 1 (edge-triggered burst) and 2 (level-triggered burst). + +Obsolete properties: +- fsl,spi-num-chipselects : Contains the number of the chipselect + +Example: + +ecspi@70010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx51-ecspi"; + reg = <0x70010000 0x4000>; + interrupts = <36>; + cs-gpios = <&gpio3 24 0>, /* GPIO3_24 */ + <&gpio3 25 0>; /* GPIO3_25 */ + dmas = <&sdma 3 7 1>, <&sdma 4 7 2>; + dma-names = "rx", "tx"; + fsl,spi-rdy-drctl = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/fsl-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/fsl-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..8854004a1d3ae2c38d6e14941e059b74e26ebdea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/fsl-spi.txt @@ -0,0 +1,58 @@ +* SPI (Serial Peripheral Interface) + +Required properties: +- cell-index : QE SPI subblock index. + 0: QE subblock SPI1 + 1: QE subblock SPI2 +- compatible : should be "fsl,spi" or "aeroflexgaisler,spictrl". +- mode : the SPI operation mode, it can be "cpu" or "cpu-qe". +- reg : Offset and length of the register set for the device +- interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. +- clock-frequency : input clock frequency to non FSL_SOC cores + +Optional properties: +- gpios : specifies the gpio pins to be used for chipselects. + The gpios will be referred to as reg = in the SPI child nodes. + If unspecified, a single SPI device without a chip select can be used. + +Example: + spi@4c0 { + cell-index = <0>; + compatible = "fsl,spi"; + reg = <4c0 40>; + interrupts = <82 0>; + interrupt-parent = <700>; + mode = "cpu"; + gpios = <&gpio 18 1 // device reg=<0> + &gpio 19 1>; // device reg=<1> + }; + + +* eSPI (Enhanced Serial Peripheral Interface) + +Required properties: +- compatible : should be "fsl,mpc8536-espi". +- reg : Offset and length of the register set for the device. +- interrupts : should contain eSPI interrupt, the device has one interrupt. +- fsl,espi-num-chipselects : the number of the chipselect signals. + +Optional properties: +- fsl,csbef: chip select assertion time in bits before frame starts +- fsl,csaft: chip select negation time in bits after frame ends + +Example: + spi@110000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc8536-espi"; + reg = <0x110000 0x1000>; + interrupts = <53 0x2>; + interrupt-parent = <&mpic>; + fsl,espi-num-chipselects = <4>; + fsl,csbef = <1>; + fsl,csaft = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/icpdas-lp8841-spi-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/spi/icpdas-lp8841-spi-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..852b651f3bc5b619662232676b082ad9e593d42d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/icpdas-lp8841-spi-rtc.txt @@ -0,0 +1,54 @@ +* ICP DAS LP-8841 SPI Controller for RTC + +ICP DAS LP-8841 contains a DS-1302 RTC. RTC is connected to an IO +memory register, which acts as an SPI master device. + +The device uses the standard MicroWire half-duplex transfer timing. +Master output is set on low clock and sensed by the RTC on the rising +edge. Master input is set by the RTC on the trailing edge and is sensed +by the master on low clock. + +Required properties: + +- #address-cells: should be 1 + +- #size-cells: should be 0 + +- compatible: should be "icpdas,lp8841-spi-rtc" + +- reg: should provide IO memory address + +Requirements to SPI slave nodes: + +- There can be only one slave device. + +- The spi slave node should claim the following flags which are + required by the spi controller. + + - spi-3wire: The master itself has only 3 wire. It cannor work in + full duplex mode. + + - spi-cs-high: DS-1302 has active high chip select line. The master + doesn't support active low. + + - spi-lsb-first: DS-1302 requires least significant bit first + transfers. The master only support this type of bit ordering. + + +Example: + +spi@901c { + #address-cells = <1>; + #size-cells = <0>; + compatible = "icpdas,lp8841-spi-rtc"; + reg = <0x901c 0x1>; + + rtc@0 { + compatible = "maxim,ds1302"; + reg = <0>; + spi-max-frequency = <500000>; + spi-3wire; + spi-lsb-first; + spi-cs-high; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/jcore,spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/jcore,spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..93936d16e1395e2466683c9c1fcad7cebc264fd2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/jcore,spi.txt @@ -0,0 +1,34 @@ +J-Core SPI master + +Required properties: + +- compatible: Must be "jcore,spi2". + +- reg: Memory region for registers. + +- #address-cells: Must be 1. + +- #size-cells: Must be 0. + +Optional properties: + +- clocks: If a phandle named "ref_clk" is present, SPI clock speed + programming is relative to the frequency of the indicated clock. + Necessary only if the input clock rate is something other than a + fixed 50 MHz. + +- clock-names: Clock names, one for each phandle in clocks. + +See spi-bus.txt for additional properties not specific to this device. + +Example: + +spi@40 { + compatible = "jcore,spi2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x40 0x8>; + spi-max-frequency = <25000000>; + clocks = <&bus_clk>; + clock-names = "ref_clk"; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/microchip,spi-pic32.txt b/arch/arm64/boot/dts/vendor/bindings/spi/microchip,spi-pic32.txt new file mode 100644 index 0000000000000000000000000000000000000000..79de379f4dc067ee0c53385eaa344d18cd51cae3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/microchip,spi-pic32.txt @@ -0,0 +1,34 @@ +Microchip PIC32 SPI Master controller + +Required properties: +- compatible: Should be "microchip,pic32mzda-spi". +- reg: Address and length of register space for the device. +- interrupts: Should contain all three spi interrupts in sequence + of , , . +- interrupt-names: Should be "fault", "rx", "tx" in order. +- clocks: Phandle of the clock generating SPI clock on the bus. +- clock-names: Should be "mck0". +- cs-gpios: Specifies the gpio pins to be used for chipselects. + See: Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: +- dmas: Two or more DMA channel specifiers following the convention outlined + in Documentation/devicetree/bindings/dma/dma.txt +- dma-names: Names for the dma channels. There must be at least one channel + named "spi-tx" for transmit and named "spi-rx" for receive. + +Example: + +spi1: spi@1f821000 { + compatible = "microchip,pic32mzda-spi"; + reg = <0x1f821000 0x200>; + interrupts = <109 IRQ_TYPE_LEVEL_HIGH>, + <110 IRQ_TYPE_LEVEL_HIGH>, + <111 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "fault", "rx", "tx"; + clocks = <&PBCLK2>; + clock-names = "mck0"; + cs-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; + dmas = <&dma 134>, <&dma 135>; + dma-names = "spi-rx", "spi-tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/mxs-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/mxs-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..3499b73293c20562b1036215016e37c2265d57ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/mxs-spi.txt @@ -0,0 +1,26 @@ +* Freescale MX233/MX28 SSP/SPI + +Required properties: +- compatible: Should be "fsl,-spi", where soc is "imx23" or "imx28" +- reg: Offset and length of the register set for the device +- interrupts: Should contain SSP ERROR interrupt +- dmas: DMA specifier, consisting of a phandle to DMA controller node + and SSP DMA channel ID. + Refer to dma.txt and fsl-mxs-dma.txt for details. +- dma-names: Must be "rx-tx". + +Optional properties: +- clock-frequency : Input clock frequency to the SPI block in Hz. + Default is 160000000 Hz. + +Example: + +ssp0: ssp@80010000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,imx28-spi"; + reg = <0x80010000 0x2000>; + interrupts = <96>; + dmas = <&dma_apbh 0>; + dma-names = "rx-tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra114-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra114-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ba7c5a273b4f39cfb912ff9df50e41d317f4677 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra114-spi.txt @@ -0,0 +1,41 @@ +NVIDIA Tegra114 SPI controller. + +Required properties: +- compatible : For Tegra114, must contain "nvidia,tegra114-spi". + Otherwise, must contain '"nvidia,-spi", "nvidia,tegra114-spi"' where + is tegra124, tegra132, or tegra210. +- reg: Should contain SPI registers location and length. +- interrupts: Should contain SPI interrupts. +- clock-names : Must include the following entries: + - spi +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + +Recommended properties: +- spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt +Example: + +spi@7000d600 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000d600 0x200>; + interrupts = <0 82 0x04>; + spi-max-frequency = <25000000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&tegra_car 44>; + clock-names = "spi"; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra20-sflash.txt b/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra20-sflash.txt new file mode 100644 index 0000000000000000000000000000000000000000..c212491929b5b84832d7ddc06db6c1a9113fae69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra20-sflash.txt @@ -0,0 +1,37 @@ +NVIDIA Tegra20 SFLASH controller. + +Required properties: +- compatible : should be "nvidia,tegra20-sflash". +- reg: Should contain SFLASH registers location and length. +- interrupts: Should contain SFLASH interrupts. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx + +Recommended properties: +- spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + +spi@7000c380 { + compatible = "nvidia,tegra20-sflash"; + reg = <0x7000c380 0x80>; + interrupts = <0 39 0x04>; + spi-max-frequency = <25000000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&tegra_car 43>; + resets = <&tegra_car 43>; + reset-names = "spi"; + dmas = <&apbdma 11>, <&apbdma 11>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra20-slink.txt b/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra20-slink.txt new file mode 100644 index 0000000000000000000000000000000000000000..40d80b93e32799ee0a3cb14a206ec3232f1973f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/nvidia,tegra20-slink.txt @@ -0,0 +1,37 @@ +NVIDIA Tegra20/Tegra30 SLINK controller. + +Required properties: +- compatible : should be "nvidia,tegra20-slink", "nvidia,tegra30-slink". +- reg: Should contain SLINK registers location and length. +- interrupts: Should contain SLINK interrupts. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx + +Recommended properties: +- spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + +spi@7000d600 { + compatible = "nvidia,tegra20-slink"; + reg = <0x7000d600 0x200>; + interrupts = <0 82 0x04>; + spi-max-frequency = <25000000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&tegra_car 44>; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/omap-spi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/omap-spi.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ba5f9c023acb93be4e8089fd3c817a44cd08bc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/omap-spi.txt @@ -0,0 +1,47 @@ +OMAP2+ McSPI device + +Required properties: +- compatible : + - "ti,omap2-mcspi" for OMAP2 & OMAP3. + - "ti,omap4-mcspi" for OMAP4+. +- ti,spi-num-cs : Number of chipselect supported by the instance. +- ti,hwmods: Name of the hwmod associated to the McSPI +- ti,pindir-d0-out-d1-in: Select the D0 pin as output and D1 as + input. The default is D0 as input and + D1 as output. + +Optional properties: +- dmas: List of DMA specifiers with the controller specific format + as described in the generic DMA client binding. A tx and rx + specifier is required for each chip select. +- dma-names: List of DMA request names. These strings correspond + 1:1 with the DMA specifiers listed in dmas. The string naming + is to be "rxN" and "txN" for RX and TX requests, + respectively, where N equals the chip select number. + +Examples: + +[hwmod populated DMA resources] + +mcspi1: mcspi@1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,omap4-mcspi"; + ti,hwmods = "mcspi1"; + ti,spi-num-cs = <4>; +}; + +[generic DMA request binding] + +mcspi1: mcspi@1 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,omap4-mcspi"; + ti,hwmods = "mcspi1"; + ti,spi-num-cs = <2>; + dmas = <&edma 42 + &edma 43 + &edma 44 + &edma 45>; + dma-names = "tx0", "rx0", "tx1", "rx1"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/qcom,spi-geni-qcom.txt b/arch/arm64/boot/dts/vendor/bindings/spi/qcom,spi-geni-qcom.txt new file mode 100644 index 0000000000000000000000000000000000000000..e63b88df4a367663074c3ed38e83cd86639c43fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/qcom,spi-geni-qcom.txt @@ -0,0 +1,85 @@ +GENI based Qualcomm Technologies Inc Universal Peripheral version 3 (QUPv3) + Serial Peripheral Interface (SPI) + +The QUP v3 core is a GENI based AHB slave that provides a common data path +(an output FIFO and an input FIFO) for serial peripheral interface (SPI) +mini-core. + +SPI in master mode supports up to 50MHz, up to four chip selects, programmable +data path from 4 bits to 32 bits and numerous protocol variants. + +Required properties: +- compatible: Should contain "qcom,spi-geni" +- reg: Should contain base register location and length +- interrupts: Interrupt number used by this controller +- clocks: Should contain the core clock and the AHB clock. +- clock-names: Should be "core" for the core clock and "iface" for the + AHB clock. +- pinctrl-names: Property should contain "default" and "sleep" for the + pin configurations during the usecase and during idle. +- pinctrl-x: phandle to the default/sleep pin configurations. +- #address-cells: Number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: Should be zero. +- spi-max-frequency: Specifies maximum SPI clock frequency, + Units - Hz. Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt +- qcom,wrapper-core: Wrapper QUPv3 core containing this SPI controller. + +Optional properties: +- qcom,rt: Specifies if the framework worker thread for this + controller device should have "real-time" priority. +- qcom,disable-autosuspend: Specifies to disable runtime PM auto suspend. +- qcom,shared_ee: Specifies that this serial engine is shared between + execution environments. +- qcom,set-cs-sb-delay: Specifies the SB PIPE delay value in cycles which can be + used to achieve CS delay in minicore based targets. + Note: Use this property to introduce cs_clk_delay only for minicore QUPs with + inter words delay as 0 and CS toggle as 0. For other cases, use the + conventional method of using spi_cs_clk_dly register. + +SPI slave nodes must be children of the SPI master node and can contain +the following properties. + +Required properties: +- compatible: Should contain: + "qcom,spi-msm-codec-slave" for external codec control + +- reg: Chip select address of device. + +- spi-max-frequency: Maximum SPI clocking speed of device in Hz. + +Optional properties: +- spi-cpha: Empty property indicating device requires + shifted clock phase (CPHA) mode. + +- qcom,slv-ctrl : Set this flag to configure QUPV3 as SPI slave controller. + +Other optional properties described in +Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + + qupv3_spi10: spi@a84000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa84000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qup_1_spi_2_active>; + pinctrl-1 = <&qup_1_spi_2_sleep>; + interrupts = ; + spi-max-frequency = <19200000>; + qcom,wrapper-core = <&qupv3_0>; + + dev@0 { + compatible = "dummy,slave"; + reg = <0>; + spi-max-frequency = <9600000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/qcom,spi-qup.txt b/arch/arm64/boot/dts/vendor/bindings/spi/qcom,spi-qup.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c090771c016cd22f38ebeaa4a4158ee7da20ccf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/qcom,spi-qup.txt @@ -0,0 +1,103 @@ +Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) + +The QUP core is an AHB slave that provides a common data path (an output FIFO +and an input FIFO) for serial peripheral interface (SPI) mini-core. + +SPI in master mode supports up to 50MHz, up to four chip selects, programmable +data path from 4 bits to 32 bits and numerous protocol variants. + +Required properties: +- compatible: Should contain: + "qcom,spi-qup-v1.1.1" for 8660, 8960 and 8064. + "qcom,spi-qup-v2.1.1" for 8974 and later + "qcom,spi-qup-v2.2.1" for 8974 v2 and later. + +- reg: Should contain base register location and length +- interrupts: Interrupt number used by this controller + +- clocks: Should contain the core clock and the AHB clock. +- clock-names: Should be "core" for the core clock and "iface" for the + AHB clock. + +- #address-cells: Number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: Should be zero. + +Optional properties: +- spi-max-frequency: Specifies maximum SPI clock frequency, + Units - Hz. Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt +- num-cs: total number of chipselects +- cs-gpios: should specify GPIOs used for chipselects. + The gpios will be referred to as reg = in the SPI child + nodes. If unspecified, a single SPI device without a chip + select can be used. + +- dmas: Two DMA channel specifiers following the convention outlined + in bindings/dma/dma.txt +- dma-names: Names for the dma channels, if present. There must be at + least one channel named "tx" for transmit and named "rx" for + receive. + +SPI slave nodes must be children of the SPI master node and can contain +properties described in Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + + spi_8: spi@f9964000 { /* BLSP2 QUP2 */ + + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xf9964000 0x1000>; + interrupts = <0 102 0>; + spi-max-frequency = <19200000>; + + clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + + dmas = <&blsp1_bam 13>, <&blsp1_bam 12>; + dma-names = "rx", "tx"; + + pinctrl-names = "default"; + pinctrl-0 = <&spi8_default>; + + device@0 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <19200000>; + spi-cpol; + }; + + device@1 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <1>; /* Chip select 1 */ + spi-max-frequency = <9600000>; + spi-cpha; + }; + + device@2 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <2>; /* Chip select 2 */ + spi-max-frequency = <19200000>; + spi-cpol; + spi-cpha; + }; + + device@3 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <3>; /* Chip select 3 */ + spi-max-frequency = <19200000>; + spi-cpol; + spi-cpha; + spi-cs-high; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/sh-hspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/sh-hspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..b9d1e4d11a7726f2b7e02ba3ed1d25f55fe8f86c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/sh-hspi.txt @@ -0,0 +1,26 @@ +Renesas HSPI. + +Required properties: +- compatible : "renesas,hspi-", "renesas,hspi" as fallback. + Examples with soctypes are: + - "renesas,hspi-r8a7778" (R-Car M1) + - "renesas,hspi-r8a7779" (R-Car H1) +- reg : Offset and length of the register set for the device +- interrupts : Interrupt specifier +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. + +Example: + + hspi0: spi@fffc7000 { + compatible = "renesas,hspi-r8a7778", "renesas,hspi"; + reg = <0xfffc7000 0x18>; + interrupt-parent = <&gic>; + interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/sh-msiof.txt b/arch/arm64/boot/dts/vendor/bindings/spi/sh-msiof.txt new file mode 100644 index 0000000000000000000000000000000000000000..bfbc2035fb6bfaf634948e7218bea80aab359f6a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/sh-msiof.txt @@ -0,0 +1,97 @@ +Renesas MSIOF spi controller + +Required properties: +- compatible : "renesas,msiof-r8a7743" (RZ/G1M) + "renesas,msiof-r8a7745" (RZ/G1E) + "renesas,msiof-r8a7790" (R-Car H2) + "renesas,msiof-r8a7791" (R-Car M2-W) + "renesas,msiof-r8a7792" (R-Car V2H) + "renesas,msiof-r8a7793" (R-Car M2-N) + "renesas,msiof-r8a7794" (R-Car E2) + "renesas,msiof-r8a7795" (R-Car H3) + "renesas,msiof-r8a7796" (R-Car M3-W) + "renesas,msiof-r8a77965" (R-Car M3-N) + "renesas,msiof-sh73a0" (SH-Mobile AG5) + "renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device) + "renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device) + "renesas,rcar-gen3-msiof" (generic R-Car Gen3 compatible device) + "renesas,sh-msiof" (deprecated) + + When compatible with the generic version, nodes + must list the SoC-specific version corresponding + to the platform first followed by the generic + version. + +- reg : A list of offsets and lengths of the register sets for + the device. + If only one register set is present, it is to be used + by both the CPU and the DMA engine. + If two register sets are present, the first is to be + used by the CPU, and the second is to be used by the + DMA engine. +- interrupts : Interrupt specifier +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Optional properties: +- clocks : Must contain a reference to the functional clock. +- num-cs : Total number of chip selects (default is 1). + Up to 3 native chip selects are supported: + 0: MSIOF_SYNC + 1: MSIOF_SS1 + 2: MSIOF_SS2 + Hardware limitations related to chip selects: + - Native chip selects are always deasserted in + between transfers that are part of the same + message. Use cs-gpios to work around this. + - All slaves using native chip selects must use the + same spi-cs-high configuration. Use cs-gpios to + work around this. + - When using GPIO chip selects, at least one native + chip select must be left unused, as it will be + driven anyway. +- dmas : Must contain a list of two references to DMA + specifiers, one for transmission, and one for + reception. +- dma-names : Must contain a list of two DMA names, "tx" and "rx". +- spi-slave : Empty property indicating the SPI controller is used + in slave mode. +- renesas,dtdl : delay sync signal (setup) in transmit mode. + Must contain one of the following values: + 0 (no bit delay) + 50 (0.5-clock-cycle delay) + 100 (1-clock-cycle delay) + 150 (1.5-clock-cycle delay) + 200 (2-clock-cycle delay) + +- renesas,syncdl : delay sync signal (hold) in transmit mode. + Must contain one of the following values: + 0 (no bit delay) + 50 (0.5-clock-cycle delay) + 100 (1-clock-cycle delay) + 150 (1.5-clock-cycle delay) + 200 (2-clock-cycle delay) + 300 (3-clock-cycle delay) + +Optional properties, deprecated for soctype-specific bindings: +- renesas,tx-fifo-size : Overrides the default tx fifo size given in words + (default is 64) +- renesas,rx-fifo-size : Overrides the default rx fifo size given in words + (default is 64) + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. + +Example: + + msiof0: spi@e6e20000 { + compatible = "renesas,msiof-r8a7791", + "renesas,rcar-gen2-msiof"; + reg = <0 0xe6e20000 0 0x0064>; + interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>; + dmas = <&dmac0 0x51>, <&dmac0 0x52>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/snps,dw-apb-ssi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/snps,dw-apb-ssi.txt new file mode 100644 index 0000000000000000000000000000000000000000..642d3fb1ef851b4f588f24730df23b70c79aa161 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/snps,dw-apb-ssi.txt @@ -0,0 +1,32 @@ +Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface. + +Required properties: +- compatible : "snps,dw-apb-ssi" or "mscc,-spi", where soc is "ocelot" or + "jaguar2" +- reg : The register base for the controller. For "mscc,-spi", a second + register set is required (named ICPU_CFG:SPI_MST) +- interrupts : One interrupt, used by the controller. +- #address-cells : <1>, as required by generic SPI binding. +- #size-cells : <0>, also as required by generic SPI binding. + +Optional properties: +- cs-gpios : Specifies the gpio pis to be used for chipselects. +- num-cs : The number of chipselects. If omitted, this will default to 4. +- reg-io-width : The I/O register width (in bytes) implemented by this + device. Supported values are 2 or 4 (the default). + +Child nodes as per the generic SPI binding. + +Example: + + spi@fff00000 { + compatible = "snps,dw-apb-ssi"; + reg = <0xfff00000 0x1000>; + interrupts = <0 154 4>; + #address-cells = <1>; + #size-cells = <0>; + num-cs = <2>; + cs-gpios = <&gpio0 13 0>, + <&gpio0 14 0>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-armada-3700.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-armada-3700.txt new file mode 100644 index 0000000000000000000000000000000000000000..1564aa8c02cdb1dbe1265f5c7ff14ad466acc502 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-armada-3700.txt @@ -0,0 +1,25 @@ +* Marvell Armada 3700 SPI Controller + +Required Properties: + +- compatible: should be "marvell,armada-3700-spi" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number. The interrupt specifier format depends on + the interrupt controller and of its driver. +- clocks: Must contain the clock source, usually from the North Bridge clocks. +- num-cs: The number of chip selects that is supported by this SPI Controller +- #address-cells: should be 1. +- #size-cells: should be 0. + +Example: + + spi0: spi@10600 { + compatible = "marvell,armada-3700-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x10600 0x5d>; + clocks = <&nb_perih_clk 7>; + interrupts = ; + num-cs = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-ath79.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-ath79.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c696fa66f818eb98144c628aa1b7000f96a6695 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-ath79.txt @@ -0,0 +1,24 @@ +Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller + +Required properties: +- compatible: has to be "qca,-spi", "qca,ar7100-spi" as fallback. +- reg: Base address and size of the controllers memory area +- clocks: phandle of the AHB clock. +- clock-names: has to be "ahb". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Child nodes as per the generic SPI binding. + +Example: + + spi@1f000000 { + compatible = "qca,ar9132-spi", "qca,ar7100-spi"; + reg = <0x1f000000 0x10>; + + clocks = <&pll 2>; + clock-names = "ahb"; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-bcm63xx-hsspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-bcm63xx-hsspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..37b29ee138600fe265b4caa1166e209a2714b3fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-bcm63xx-hsspi.txt @@ -0,0 +1,33 @@ +Binding for Broadcom BCM6328 High Speed SPI controller + +Required properties: +- compatible: must contain of "brcm,bcm6328-hsspi". +- reg: Base address and size of the controllers memory area. +- interrupts: Interrupt for the SPI block. +- clocks: phandles of the SPI clock and the PLL clock. +- clock-names: must be "hsspi", "pll". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Optional properties: +- num-cs: some controllers have less than 8 cs signals. Defaults to 8 + if absent. + +Child nodes as per the generic SPI binding. + +Example: + + spi@10001000 { + compatible = "brcm,bcm6328-hsspi"; + reg = <0x10001000 0x600>; + + interrupts = <29>; + + clocks = <&clkctl 9>, <&hsspi_pll>; + clock-names = "hsspi", "pll"; + + num-cs = <2>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-bcm63xx.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-bcm63xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..1c16f66926137eb56817dd58ce360e585fece179 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-bcm63xx.txt @@ -0,0 +1,33 @@ +Binding for Broadcom BCM6348/BCM6358 SPI controller + +Required properties: +- compatible: must contain one of "brcm,bcm6348-spi", "brcm,bcm6358-spi". +- reg: Base address and size of the controllers memory area. +- interrupts: Interrupt for the SPI block. +- clocks: phandle of the SPI clock. +- clock-names: has to be "spi". +- #address-cells: <1>, as required by generic SPI binding. +- #size-cells: <0>, also as required by generic SPI binding. + +Optional properties: +- num-cs: some controllers have less than 8 cs signals. Defaults to 8 + if absent. + +Child nodes as per the generic SPI binding. + +Example: + + spi@10000800 { + compatible = "brcm,bcm6368-spi", "brcm,bcm6358-spi"; + reg = <0x10000800 0x70c>; + + interrupts = <1>; + + clocks = <&clkctl 9>; + clock-names = "spi"; + + num-cs = <5>; + + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-bus.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-bus.txt new file mode 100644 index 0000000000000000000000000000000000000000..1f6e86f787efd229a7e02b1ba78dff1af3d43235 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-bus.txt @@ -0,0 +1,111 @@ +SPI (Serial Peripheral Interface) busses + +SPI busses can be described with a node for the SPI controller device +and a set of child nodes for each SPI slave on the bus. The system's SPI +controller may be described for use in SPI master mode or in SPI slave mode, +but not for both at the same time. + +The SPI controller node requires the following properties: +- compatible - Name of SPI bus controller following generic names + recommended practice. + +In master mode, the SPI controller node requires the following additional +properties: +- #address-cells - number of cells required to define a chip select + address on the SPI bus. +- #size-cells - should be zero. + +In slave mode, the SPI controller node requires one additional property: +- spi-slave - Empty property. + +No other properties are required in the SPI bus node. It is assumed +that a driver for an SPI bus device will understand that it is an SPI bus. +However, the binding does not attempt to define the specific method for +assigning chip select numbers. Since SPI chip select configuration is +flexible and non-standardized, it is left out of this binding with the +assumption that board specific platform code will be used to manage +chip selects. Individual drivers can define additional properties to +support describing the chip select layout. + +Optional properties (master mode only): +- cs-gpios - gpios chip select. +- num-cs - total number of chipselects. + +If cs-gpios is used the number of chip selects will be increased automatically +with max(cs-gpios > hw cs). + +So if for example the controller has 2 CS lines, and the cs-gpios +property looks like this: + +cs-gpios = <&gpio1 0 0>, <0>, <&gpio1 1 0>, <&gpio1 2 0>; + +Then it should be configured so that num_chipselect = 4 with the +following mapping: + +cs0 : &gpio1 0 0 +cs1 : native +cs2 : &gpio1 1 0 +cs3 : &gpio1 2 0 + + +SPI slave nodes must be children of the SPI controller node. + +In master mode, one or more slave nodes (up to the number of chip selects) can +be present. Required properties are: +- compatible - Name of SPI device following generic names recommended + practice. +- reg - Chip select address of device. +- spi-max-frequency - Maximum SPI clocking speed of device in Hz. + +In slave mode, the (single) slave node is optional. +If present, it must be called "slave". Required properties are: +- compatible - Name of SPI device following generic names recommended + practice. + +All slave nodes can contain the following optional properties: +- spi-cpol - Empty property indicating device requires inverse clock + polarity (CPOL) mode. +- spi-cpha - Empty property indicating device requires shifted clock + phase (CPHA) mode. +- spi-cs-high - Empty property indicating device requires chip select + active high. +- spi-3wire - Empty property indicating device requires 3-wire mode. +- spi-lsb-first - Empty property indicating device requires LSB first mode. +- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI. + Defaults to 1 if not present. +- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO. + Defaults to 1 if not present. +- spi-rx-delay-us - Microsecond delay after a read transfer. +- spi-tx-delay-us - Microsecond delay after a write transfer. + +Some SPI controllers and devices support Dual and Quad SPI transfer mode. +It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4 +wires (QUAD). +Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is +only 1 (SINGLE), 2 (DUAL) and 4 (QUAD). +Dual/Quad mode is not allowed when 3-wire mode is used. + +If a gpio chipselect is used for the SPI slave the gpio number will be passed +via the SPI master node cs-gpios property. + +SPI example for an MPC5200 SPI bus: + spi@f00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi"; + reg = <0xf00 0x20>; + interrupts = <2 13 0 2 14 0>; + interrupt-parent = <&mpc5200_pic>; + + ethernet-switch@0 { + compatible = "micrel,ks8995m"; + spi-max-frequency = <1000000>; + reg = <0>; + }; + + codec@1 { + compatible = "ti,tlv320aic26"; + spi-max-frequency = <100000>; + reg = <1>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-cadence.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-cadence.txt new file mode 100644 index 0000000000000000000000000000000000000000..05a2ef945664be2fae40aae229544c3a6b74d31d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-cadence.txt @@ -0,0 +1,30 @@ +Cadence SPI controller Device Tree Bindings +------------------------------------------- + +Required properties: +- compatible : Should be "cdns,spi-r1p6" or "xlnx,zynq-spi-r1p6". +- reg : Physical base address and size of SPI registers map. +- interrupts : Property with a value describing the interrupt + number. +- clock-names : List of input clock names - "ref_clk", "pclk" + (See clock bindings for details). +- clocks : Clock phandles (see clock bindings for details). + +Optional properties: +- num-cs : Number of chip selects used. + If a decoder is used, this will be the number of + chip selects after the decoder. +- is-decoded-cs : Flag to indicate whether decoder is used or not. + +Example: + + spi@e0007000 { + compatible = "xlnx,zynq-spi-r1p6"; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 26>, <&clkc 35>; + interrupt-parent = <&intc>; + interrupts = <0 49 4>; + num-cs = <4>; + is-decoded-cs = <0>; + reg = <0xe0007000 0x1000>; + } ; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-clps711x.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-clps711x.txt new file mode 100644 index 0000000000000000000000000000000000000000..5122dc7860af595a0e9393a22c320aef4b0c4be7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-clps711x.txt @@ -0,0 +1,32 @@ +Serial Peripheral Interface on Cirrus Logic CL-PS71xx, EP72xx, EP73xx + +Required properties +- #address-cells: must be <1> +- #size-cells: must be <0> +- compatible: should include "cirrus,ep7209-spi" +- reg: Address and length of one register range +- interrupts: one interrupt line +- clocks: One entry, refers to the SPI bus clock +- cs-gpios: Specifies the gpio pins to be used for chipselects. + See: Documentation/devicetree/bindings/spi/spi-bus.txt + +An additional register is present in the system controller, +which is assumed to be in the same device tree, with and marked +as compatible with "cirrus,ep7209-syscon3". + +Example: + +spi@80000500 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "cirrus,ep7209-spi"; + reg = <0x80000500 0x4>; + interrupts = <15>; + clocks = <&clks CLPS711X_CLK_SPI>; +}; + +syscon3: syscon@80002200 { + compatible = "cirrus,ep7209-syscon3", "syscon"; + reg = <0x80002200 0x40>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-davinci.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-davinci.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f5b4c7c0c086df37aac599bbaa3df421ac561ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-davinci.txt @@ -0,0 +1,100 @@ +Davinci SPI controller device bindings + +Links on DM: +Keystone 2 - http://www.ti.com/lit/ug/sprugp2a/sprugp2a.pdf +dm644x - http://www.ti.com/lit/ug/sprue32a/sprue32a.pdf +OMAP-L138/da830 - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf + +Required properties: +- #address-cells: number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: should be zero. +- compatible: + - "ti,dm6441-spi" for SPI used similar to that on DM644x SoC family + - "ti,da830-spi" for SPI used similar to that on DA8xx SoC family + - "ti,keystone-spi" for SPI used similar to that on Keystone2 SoC + family +- reg: Offset and length of SPI controller register space +- num-cs: Number of chip selects. This includes internal as well as + GPIO chip selects. +- ti,davinci-spi-intr-line: interrupt line used to connect the SPI + IP to the interrupt controller within the SoC. Possible values + are 0 and 1. Manual says one of the two possible interrupt + lines can be tied to the interrupt controller. Set this + based on a specific SoC configuration. +- interrupts: interrupt number mapped to CPU. +- clocks: spi clk phandle + For 66AK2G this property should be set per binding, + Documentation/devicetree/bindings/clock/ti,sci-clk.txt + +SoC-specific Required Properties: + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the SPI device id + value. This property is as per the binding, + +Optional: +- cs-gpios: gpio chip selects + For example to have 3 internal CS and 2 GPIO CS, user could define + cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>; + where first three are internal CS and last two are GPIO CS. + +Optional properties for slave devices: +SPI slave nodes can contain the following properties. +Not all SPI Peripherals from Texas Instruments support this. +Please check SPI peripheral documentation for a device before using these. + +- ti,spi-wdelay : delay between transmission of words + (SPIFMTn.WDELAY, SPIDAT1.WDEL) must be specified in number of SPI module + clock periods. + + delay = WDELAY * SPI_module_clock_period + 2 * SPI_module_clock_period + +Below is timing diagram which shows functional meaning of +"ti,spi-wdelay" parameter. + + +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +SPI_CLK | | | | | | | | | | | | | | | | + +----------+ +-+ +-+ +-+ +-+ +---------------------------+ +-+ +-+ +- + +SPI_SOMI/SIMO+-----------------+ +----------- + +----------+ word1 +---------------------------+word2 + +-----------------+ +----------- + WDELAY + <--------------------------> + +Example of a NOR flash slave device (n25q032) connected to DaVinci +SPI controller device over the SPI bus. + +spi0:spi@20bf0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,dm6446-spi"; + reg = <0x20BF0000 0x1000>; + num-cs = <4>; + ti,davinci-spi-intr-line = <0>; + interrupts = <338>; + clocks = <&clkspi>; + + flash: n25q032@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,m25p32"; + spi-max-frequency = <25000000>; + reg = <0>; + ti,spi-wdelay = <8>; + + partition@0 { + label = "u-boot-spl"; + reg = <0x0 0x80000>; + read-only; + }; + + partition@1 { + label = "test"; + reg = <0x80000 0x380000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-dw.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-dw.txt new file mode 100644 index 0000000000000000000000000000000000000000..7b63ed6019909bdeb0fcb96d7e0d6ce1649fef3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-dw.txt @@ -0,0 +1,24 @@ +Synopsys DesignWare SPI master + +Required properties: +- compatible: should be "snps,designware-spi" +- #address-cells: see spi-bus.txt +- #size-cells: see spi-bus.txt +- reg: address and length of the spi master registers +- interrupts: should contain one interrupt +- clocks: spi clock phandle +- num-cs: see spi-bus.txt + +Optional properties: +- cs-gpios: see spi-bus.txt + +Example: + +spi: spi@4020a000 { + compatible = "snps,designware-spi"; + interrupts = <11 1>; + reg = <0x4020a000 0x1000>; + clocks = <&pclk>; + num-cs = <2>; + cs-gpios = <&banka 0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-fsl-dspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-fsl-dspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..dcc7eaada5118a5e61c23499d5f46f5f324e5c43 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-fsl-dspi.txt @@ -0,0 +1,59 @@ +ARM Freescale DSPI controller + +Required properties: +- compatible : "fsl,vf610-dspi", "fsl,ls1021a-v1.0-dspi", + "fsl,ls2085a-dspi" + or + "fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi" + "fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi" +- reg : Offset and length of the register set for the device +- interrupts : Should contain SPI controller interrupt +- clocks: from common clock binding: handle to dspi clock. +- clock-names: from common clock binding: Shall be "dspi". +- pinctrl-0: pin control group to be used for this controller. +- pinctrl-names: must contain a "default" entry. +- spi-num-chipselects : the number of the chipselect signals. +- bus-num : the slave chip chipselect signal number. + +Optional property: +- big-endian: If present the dspi device's registers are implemented + in big endian mode. + +Optional SPI slave node properties: +- fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip + select and the start of clock signal, at the start of a transfer. +- fsl,spi-sck-cs-delay: a delay in nanoseconds between stopping the clock + signal and deactivating chip select, at the end of a transfer. + +Example: + +dspi0@4002c000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,vf610-dspi"; + reg = <0x4002c000 0x1000>; + interrupts = <0 67 0x04>; + clocks = <&clks VF610_CLK_DSPI0>; + clock-names = "dspi"; + spi-num-chipselects = <5>; + bus-num = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dspi0_1>; + big-endian; + + sflash: at26df081a@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,at26df081a"; + spi-max-frequency = <16000000>; + spi-cpol; + spi-cpha; + reg = <0>; + linux,modalias = "m25p80"; + modal = "at26df081a"; + fsl,spi-cs-sck-delay = <100>; + fsl,spi-sck-cs-delay = <50>; + }; +}; + + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-fsl-lpspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-fsl-lpspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..4af132606b378d696f3010fea121a30205fd9a5c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-fsl-lpspi.txt @@ -0,0 +1,18 @@ +* Freescale Low Power SPI (LPSPI) for i.MX + +Required properties: +- compatible : + - "fsl,imx7ulp-spi" for LPSPI compatible with the one integrated on i.MX7ULP soc +- reg : address and length of the lpspi master registers +- interrupts : lpspi interrupt +- clocks : lpspi clock specifier + +Examples: + +lpspi2: lpspi@40290000 { + compatible = "fsl,imx7ulp-spi"; + reg = <0x40290000 0x10000>; + interrupt-parent = <&intc>; + interrupts = ; + clocks = <&clks IMX7ULP_CLK_LPSPI2>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..52db562f17a422df5d7db5cc5a3ece060009a657 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-gpio.txt @@ -0,0 +1,43 @@ +SPI-GPIO devicetree bindings + +This represents a group of 3-n GPIO lines used for bit-banged SPI on dedicated +GPIO lines. + +Required properties: + + - compatible: should be set to "spi-gpio" + - #address-cells: should be set to <0x1> + - ranges + - sck-gpios: GPIO spec for the SCK line to use + - miso-gpios: GPIO spec for the MISO line to use + - mosi-gpios: GPIO spec for the MOSI line to use + - cs-gpios: GPIOs to use for chipselect lines. + Not needed if num-chipselects = <0>. + - num-chipselects: Number of chipselect lines. Should be <0> if a single device + with no chip select is connected. + +Deprecated bindings: + +These legacy GPIO line bindings can alternatively be used to define the +GPIO lines used, they should not be used in new device trees. + + - gpio-sck: GPIO spec for the SCK line to use + - gpio-miso: GPIO spec for the MISO line to use + - gpio-mosi: GPIO spec for the MOSI line to use + +Example: + + spi { + compatible = "spi-gpio"; + #address-cells = <0x1>; + ranges; + + sck-gpios = <&gpio 95 0>; + miso-gpios = <&gpio 98 0>; + mosi-gpios = <&gpio 97 0>; + cs-gpios = <&gpio 125 0>; + num-chipselects = <1>; + + /* clients */ + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-img-spfi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-img-spfi.txt new file mode 100644 index 0000000000000000000000000000000000000000..494db6012d02f29b3e17aec0f91f0ea6b0b65a28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-img-spfi.txt @@ -0,0 +1,39 @@ +IMG Synchronous Peripheral Flash Interface (SPFI) controller + +Required properties: +- compatible: Must be "img,spfi". +- reg: Must contain the base address and length of the SPFI registers. +- interrupts: Must contain the SPFI interrupt. +- clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - spfi: SPI operating clock + - sys: SPI system interface clock +- dmas: Must contain an entry for each entry in dma-names. + See ../dma/dma.txt for details. +- dma-names: Must include the following entries: + - rx + - tx +- cs-gpios: Must specify the GPIOs used for chipselect lines. +- #address-cells: Must be 1. +- #size-cells: Must be 0. + +Optional properties: +- img,supports-quad-mode: Should be set if the interface supports quad mode + SPI transfers. +- spfi-max-frequency: Maximum speed supported by the spfi block. + +Example: + +spi@18100f00 { + compatible = "img,spfi"; + reg = <0x18100f00 0x100>; + interrupts = ; + clocks = <&spi_clk>, <&system_clk>; + clock-names = "spfi", "sys"; + dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>; + dma-names = "rx", "tx"; + + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-lantiq-ssc.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-lantiq-ssc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce3230c8e28dc2b733622be276a2378bafcbb3a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-lantiq-ssc.txt @@ -0,0 +1,29 @@ +Lantiq Synchronous Serial Controller (SSC) SPI master driver + +Required properties: +- compatible: "lantiq,ase-spi", "lantiq,falcon-spi", "lantiq,xrx100-spi" +- #address-cells: see spi-bus.txt +- #size-cells: see spi-bus.txt +- reg: address and length of the spi master registers +- interrupts: should contain the "spi_rx", "spi_tx" and "spi_err" interrupt. + + +Optional properties: +- clocks: spi clock phandle +- num-cs: see spi-bus.txt, set to 8 if unset +- base-cs: the number of the first chip select, set to 1 if unset. + +Example: + + +spi: spi@e100800 { + compatible = "lantiq,xrx200-spi", "lantiq,xrx100-spi"; + reg = <0xE100800 0x100>; + interrupt-parent = <&icu0>; + interrupts = <22 23 24>; + interrupt-names = "spi_rx", "spi_tx", "spi_err"; + #address-cells = <1>; + #size-cells = <1>; + num-cs = <6>; + base-cs = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-meson.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-meson.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7f5e86fed225b30a337b330e532804d4830ca51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-meson.txt @@ -0,0 +1,55 @@ +Amlogic Meson SPI controllers + +* SPIFC (SPI Flash Controller) + +The Meson SPIFC is a controller optimized for communication with SPI +NOR memories, without DMA support and a 64-byte unified transmit / +receive buffer. + +Required properties: + - compatible: should be "amlogic,meson6-spifc" or "amlogic,meson-gxbb-spifc" + - reg: physical base address and length of the controller registers + - clocks: phandle of the input clock for the baud rate generator + - #address-cells: should be 1 + - #size-cells: should be 0 + + spi@c1108c80 { + compatible = "amlogic,meson6-spifc"; + reg = <0xc1108c80 0x80>; + clocks = <&clk81>; + #address-cells = <1>; + #size-cells = <0>; + }; + +* SPICC (SPI Communication Controller) + +The Meson SPICC is generic SPI controller for general purpose Full-Duplex +communications with dedicated 16 words RX/TX PIO FIFOs. + +Required properties: + - compatible: should be: + "amlogic,meson-gx-spicc" on Amlogic GX and compatible SoCs. + "amlogic,meson-axg-spicc" on Amlogic AXG and compatible SoCs + - reg: physical base address and length of the controller registers + - interrupts: The interrupt specifier + - clock-names: Must contain "core" + - clocks: phandle of the input clock for the baud rate generator + - #address-cells: should be 1 + - #size-cells: should be 0 + +Optional properties: + - resets: phandle of the internal reset line + +See ../spi/spi-bus.txt for more details on SPI bus master and slave devices +required and optional properties. + +Example : + spi@c1108d80 { + compatible = "amlogic,meson-gx-spicc"; + reg = <0xc1108d80 0x80>; + interrupts = ; + clock-names = "core"; + clocks = <&clk81>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-mt65xx.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-mt65xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..236dcb0faf376238d9fe4452c5bcb5f686b87e37 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-mt65xx.txt @@ -0,0 +1,60 @@ +Binding for MTK SPI controller + +Required properties: +- compatible: should be one of the following. + - mediatek,mt2701-spi: for mt2701 platforms + - mediatek,mt2712-spi: for mt2712 platforms + - mediatek,mt6589-spi: for mt6589 platforms + - mediatek,mt7622-spi: for mt7622 platforms + - mediatek,mt8135-spi: for mt8135 platforms + - mediatek,mt8173-spi: for mt8173 platforms + +- #address-cells: should be 1. + +- #size-cells: should be 0. + +- reg: Address and length of the register set for the device + +- interrupts: Should contain spi interrupt + +- clocks: phandles to input clocks. + The first should be one of the following. It's PLL. + - <&clk26m>: specify parent clock 26MHZ. + - <&topckgen CLK_TOP_SYSPLL3_D2>: specify parent clock 109MHZ. + It's the default one. + - <&topckgen CLK_TOP_SYSPLL4_D2>: specify parent clock 78MHZ. + - <&topckgen CLK_TOP_UNIVPLL2_D4>: specify parent clock 104MHZ. + - <&topckgen CLK_TOP_UNIVPLL1_D8>: specify parent clock 78MHZ. + The second should be <&topckgen CLK_TOP_SPI_SEL>. It's clock mux. + The third is <&pericfg CLK_PERI_SPI0>. It's clock gate. + +- clock-names: shall be "parent-clk" for the parent clock, "sel-clk" for the + muxes clock, and "spi-clk" for the clock gate. + +Optional properties: +-cs-gpios: see spi-bus.txt. + +- mediatek,pad-select: specify which pins group(ck/mi/mo/cs) spi + controller used. This is an array, the element value should be 0~3, + only required for MT8173. + 0: specify GPIO69,70,71,72 for spi pins. + 1: specify GPIO102,103,104,105 for spi pins. + 2: specify GPIO128,129,130,131 for spi pins. + 3: specify GPIO5,6,7,8 for spi pins. + +Example: + +- SoC Specific Portion: +spi: spi@1100a000 { + compatible = "mediatek,mt8173-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x1100a000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_SYSPLL3_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&pericfg CLK_PERI_SPI0>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + cs-gpios = <&pio 105 GPIO_ACTIVE_LOW>, <&pio 72 GPIO_ACTIVE_LOW>; + mediatek,pad-select = <1>, <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-octeon.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-octeon.txt new file mode 100644 index 0000000000000000000000000000000000000000..431add192342ec320b4e0718b22f45aa4f7630c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-octeon.txt @@ -0,0 +1,33 @@ +Cavium, Inc. OCTEON SOC SPI master controller. + +Required properties: +- compatible : "cavium,octeon-3010-spi" +- reg : The register base for the controller. +- interrupts : One interrupt, used by the controller. +- #address-cells : <1>, as required by generic SPI binding. +- #size-cells : <0>, also as required by generic SPI binding. + +Child nodes as per the generic SPI binding. + +Example: + + spi@1070000001000 { + compatible = "cavium,octeon-3010-spi"; + reg = <0x10700 0x00001000 0x0 0x100>; + interrupts = <0 58>; + #address-cells = <1>; + #size-cells = <0>; + + eeprom@0 { + compatible = "st,m95256", "atmel,at25"; + reg = <0>; + spi-max-frequency = <5000000>; + spi-cpha; + spi-cpol; + + pagesize = <64>; + size = <32768>; + address-width = <16>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-orion.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-orion.txt new file mode 100644 index 0000000000000000000000000000000000000000..8434a65fc12a65959fe0b56801bd458d96175d2e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-orion.txt @@ -0,0 +1,79 @@ +Marvell Orion SPI device + +Required properties: +- compatible : should be on of the following: + - "marvell,orion-spi" for the Orion, mv78x00, Kirkwood and Dove SoCs + - "marvell,armada-370-spi", for the Armada 370 SoCs + - "marvell,armada-375-spi", for the Armada 375 SoCs + - "marvell,armada-380-spi", for the Armada 38x SoCs + - "marvell,armada-390-spi", for the Armada 39x SoCs + - "marvell,armada-xp-spi", for the Armada XP SoCs +- reg : offset and length of the register set for the device. + This property can optionally have additional entries to configure + the SPI direct access mode that some of the Marvell SoCs support + additionally to the normal indirect access (PIO) mode. The values + for the MBus "target" and "attribute" are defined in the Marvell + SoC "Functional Specifications" Manual in the chapter "Marvell + Core Processor Address Decoding". + The eight register sets following the control registers refer to + chip-select lines 0 through 7 respectively. +- cell-index : Which of multiple SPI controllers is this. +- clocks : pointers to the reference clocks for this device, the first + one is the one used for the clock on the spi bus, the + second one is optional and is the clock used for the + functional part of the controller + +Optional properties: +- interrupts : Is currently not used. +- clock-names : names of used clocks, mandatory if the second clock is + used, the name must be "core", and "axi" (the latter + is only for Armada 7K/8K). + + +Example: + spi@10600 { + compatible = "marvell,orion-spi"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + reg = <0x10600 0x28>; + interrupts = <23>; + }; + +Example with SPI direct mode support (optionally): + spi0: spi@10600 { + compatible = "marvell,orion-spi"; + #address-cells = <1>; + #size-cells = <0>; + cell-index = <0>; + reg = , /* control */ + , /* CS0 */ + , /* CS1 */ + , /* CS2 */ + , /* CS3 */ + , /* CS4 */ + , /* CS5 */ + , /* CS6 */ + ; /* CS7 */ + interrupts = <23>; + }; + +To enable the direct mode, the board specific 'ranges' property in the +'soc' node needs to add the entries for the desired SPI controllers +and its chip-selects that are used in the direct mode instead of PIO +mode. Here an example for this (SPI controller 0, device 1 and SPI +controller 1, device 2 are used in direct mode. All other SPI device +are used in the default indirect (PIO) mode): + soc { + /* + * Enable the SPI direct access by configuring an entry + * here in the board-specific ranges property + */ + ranges = , /* internal regs */ + , /* BootROM */ + , /* SPI0-DEV1 */ + ; /* SPI1-DEV2 */ + +For further information on the MBus bindings, please see the MBus +DT documentation: +Documentation/devicetree/bindings/bus/mvebu-mbus.txt diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-rockchip.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-rockchip.txt new file mode 100644 index 0000000000000000000000000000000000000000..a0edac12d8df5457e6b1031b2adf1519c3db7bcf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-rockchip.txt @@ -0,0 +1,58 @@ +* Rockchip SPI Controller + +The Rockchip SPI controller is used to interface with various devices such as flash +and display controllers using the SPI communication interface. + +Required Properties: + +- compatible: should be one of the following. + "rockchip,rv1108-spi" for rv1108 SoCs. + "rockchip,px30-spi", "rockchip,rk3066-spi" for px30 SoCs. + "rockchip,rk3036-spi" for rk3036 SoCS. + "rockchip,rk3066-spi" for rk3066 SoCs. + "rockchip,rk3188-spi" for rk3188 SoCs. + "rockchip,rk3228-spi" for rk3228 SoCS. + "rockchip,rk3288-spi" for rk3288 SoCs. + "rockchip,rk3368-spi" for rk3368 SoCs. + "rockchip,rk3399-spi" for rk3399 SoCs. +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Shall be "spiclk" for the transfer-clock, and "apb_pclk" for + the peripheral clock. +- #address-cells: should be 1. +- #size-cells: should be 0. + +Optional Properties: + +- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request names should include "tx" and "rx" if present. +- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling + Rx data (may need to be fine tuned for high capacitance lines). + No delay (0) by default. +- pinctrl-names: Names for the pin configuration(s); may be "default" or + "sleep", where the "sleep" configuration may describe the state + the pins should be in during system suspend. See also + pinctrl/pinctrl-bindings.txt. + + +Example: + + spi0: spi@ff110000 { + compatible = "rockchip,rk3066-spi"; + reg = <0xff110000 0x1000>; + dmas = <&pdma1 11>, <&pdma1 12>; + dma-names = "tx", "rx"; + rx-sample-delay-ns = <10>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>; + clock-names = "spiclk", "apb_pclk"; + pinctrl-0 = <&spi1_pins>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-rspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-rspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..96fd58548f694dd0b2f9b9da9f04aaca9bb41ecb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-rspi.txt @@ -0,0 +1,70 @@ +Device tree configuration for Renesas RSPI/QSPI driver + +Required properties: +- compatible : For Renesas Serial Peripheral Interface on legacy SH: + "renesas,rspi-", "renesas,rspi" as fallback. + For Renesas Serial Peripheral Interface on RZ/A1H: + "renesas,rspi-", "renesas,rspi-rz" as fallback. + For Quad Serial Peripheral Interface on R-Car Gen2 and + RZ/G1 devices: + "renesas,qspi-", "renesas,qspi" as fallback. + Examples with soctypes are: + - "renesas,rspi-sh7757" (SH) + - "renesas,rspi-r7s72100" (RZ/A1H) + - "renesas,qspi-r8a7743" (RZ/G1M) + - "renesas,qspi-r8a7745" (RZ/G1E) + - "renesas,qspi-r8a7790" (R-Car H2) + - "renesas,qspi-r8a7791" (R-Car M2-W) + - "renesas,qspi-r8a7792" (R-Car V2H) + - "renesas,qspi-r8a7793" (R-Car M2-N) + - "renesas,qspi-r8a7794" (R-Car E2) +- reg : Address start and address range size of the device +- interrupts : A list of interrupt-specifiers, one for each entry in + interrupt-names. + If interrupt-names is not present, an interrupt specifier + for a single muxed interrupt. +- interrupt-names : A list of interrupt names. Should contain (if present): + - "error" for SPEI, + - "rx" for SPRI, + - "tx" to SPTI, + - "mux" for a single muxed interrupt. +- num-cs : Number of chip selects. Some RSPI cores have more than 1. +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Optional properties: +- clocks : Must contain a reference to the functional clock. +- dmas : Must contain a list of two references to DMA specifiers, + one for transmission, and one for reception. +- dma-names : Must contain a list of two DMA names, "tx" and "rx". + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. + +Examples: + + spi0: spi@e800c800 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800c800 0x24>; + interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>, + <0 239 IRQ_TYPE_LEVEL_HIGH>, + <0 240 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + interrupt-parent = <&gic>; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi: spi@e6b10000 { + compatible = "renesas,qspi-r8a7791", "renesas,qspi"; + reg = <0 0xe6b10000 0 0x2c>; + interrupt-parent = <&gic>; + interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + dmas = <&dmac0 0x17>, <&dmac0 0x18>; + dma-names = "tx", "rx"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-samsung.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-samsung.txt new file mode 100644 index 0000000000000000000000000000000000000000..49028a4f5df18863181c472c52da7104225ccca4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-samsung.txt @@ -0,0 +1,122 @@ +* Samsung SPI Controller + +The Samsung SPI controller is used to interface with various devices such as flash +and display controllers using the SPI communication interface. + +Required SoC Specific Properties: + +- compatible: should be one of the following. + - samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms + - samsung,s3c6410-spi: for s3c6410 platforms + - samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms + - samsung,exynos5433-spi: for exynos5433 compatible controllers + - samsung,exynos7-spi: for exynos7 platforms + +- reg: physical base address of the controller and length of memory mapped + region. + +- interrupts: The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. + +- dmas : Two or more DMA channel specifiers following the convention outlined + in bindings/dma/dma.txt + +- dma-names: Names for the dma channels. There must be at least one channel + named "tx" for transmit and named "rx" for receive. + +- clocks: specifies the clock IDs provided to the SPI controller; they are + required for interacting with the controller itself, for synchronizing the bus + and as I/O clock (the latter is required by exynos5433 and exynos7). + +- clock-names: string names of the clocks in the 'clocks' property; for all the + the devices the names must be "spi", "spi_busclkN" (where N is determined by + "samsung,spi-src-clk"), while Exynos5433 should specify a third clock + "spi_ioclk" for the I/O clock. + +Required Board Specific Properties: + +- #address-cells: should be 1. +- #size-cells: should be 0. + +Optional Board Specific Properties: + +- samsung,spi-src-clk: If the spi controller includes a internal clock mux to + select the clock source for the spi bus clock, this property can be used to + indicate the clock to be used for driving the spi bus clock. If not specified, + the clock number 0 is used as default. + +- num-cs: Specifies the number of chip select lines supported. If + not specified, the default number of chip select lines is set to 1. + +- cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt) + +- no-cs-readback: the CS line is disconnected, therefore the device should not + operate based on CS signalling. + +SPI Controller specific data in SPI slave nodes: + +- The spi slave nodes should provide the following information which is required + by the spi controller. + + - samsung,spi-feedback-delay: The sampling phase shift to be applied on the + miso line (to account for any lag in the miso line). The following are the + valid values. + + - 0: No phase shift. + - 1: 90 degree phase shift sampling. + - 2: 180 degree phase shift sampling. + - 3: 270 degree phase shift sampling. + +Aliases: + +- All the SPI controller nodes should be represented in the aliases node using + the following format 'spi{n}' where n is a unique number for the alias. + + +Example: + +- SoC Specific Portion: + + spi_0: spi@12d20000 { + compatible = "samsung,exynos4210-spi"; + reg = <0x12d20000 0x100>; + interrupts = <0 66 0>; + dmas = <&pdma0 5 + &pdma0 4>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + }; + +- Board Specific Portion: + + spi_0: spi@12d20000 { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_bus>; + cs-gpios = <&gpa2 5 0>; + + w25q80bw@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "w25x80"; + reg = <0>; + spi-max-frequency = <10000>; + + controller-data { + samsung,spi-feedback-delay = <0>; + }; + + partition@0 { + label = "U-Boot"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "Kernel"; + reg = <0x40000 0xc0000>; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-sc18is602.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sc18is602.txt new file mode 100644 index 0000000000000000000000000000000000000000..02f9033270a2467c13b68a963b292b3353a2f0df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sc18is602.txt @@ -0,0 +1,23 @@ +NXP SC18IS602/SCIS603 + +Required properties: + - compatible : Should be one of + "nxp,sc18is602" + "nxp,sc18is602b" + "nxp,sc18is603" + - reg: I2C bus address + +Optional properties: + - clock-frequency : external oscillator clock frequency. If not + specified, the SC18IS602 default frequency (7372000) will be used. + +The clock-frequency property is relevant and needed only if the chip has an +external oscillator (SC18IS603). + +Example: + + sc18is603@28 { + compatible = "nxp,sc18is603"; + reg = <0x28>; + clock-frequency = <14744000>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-sirf.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sirf.txt new file mode 100644 index 0000000000000000000000000000000000000000..ddd78ff68fae5b741b5125e7b19696b3c847fd8a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sirf.txt @@ -0,0 +1,42 @@ +* CSR SiRFprimaII Serial Peripheral Interface + +Required properties: +- compatible : Should be "sirf,prima2-spi", "sirf,prima2-usp" + or "sirf,atlas7-usp" +- reg : Offset and length of the register set for the device +- interrupts : Should contain SPI interrupt +- resets: phandle to the reset controller asserting this device in + reset + See ../reset/reset.txt for details. +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + +- #address-cells: Number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: Should be zero. + +Optional properties: +- spi-max-frequency: Specifies maximum SPI clock frequency, + Units - Hz. Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt +- cs-gpios: should specify GPIOs used for chipselects. + +Example: + +spi0: spi@b00d0000 { + compatible = "sirf,prima2-spi"; + reg = <0xb00d0000 0x10000>; + interrupts = <15>; + dmas = <&dmac1 9>, + <&dmac1 4>; + dma-names = "rx", "tx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clks 19>; + resets = <&rstc 26>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-sprd-adi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sprd-adi.txt new file mode 100644 index 0000000000000000000000000000000000000000..8de589b376ce1b72a83ab2c088c811ed0af9f360 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sprd-adi.txt @@ -0,0 +1,58 @@ +Spreadtrum ADI controller + +ADI is the abbreviation of Anolog-Digital interface, which is used to access +analog chip (such as PMIC) from digital chip. ADI controller follows the SPI +framework for its hardware implementation is alike to SPI bus and its timing +is compatile to SPI timing. + +ADI controller has 50 channels including 2 software read/write channels and +48 hardware channels to access analog chip. For 2 software read/write channels, +users should set ADI registers to access analog chip. For hardware channels, +we can configure them to allow other hardware components to use it independently, +which means we can just link one analog chip address to one hardware channel, +then users can access the mapped analog chip address by this hardware channel +triggered by hardware components instead of ADI software channels. + +Thus we introduce one property named "sprd,hw-channels" to configure hardware +channels, the first value specifies the hardware channel id which is used to +transfer data triggered by hardware automatically, and the second value specifies +the analog chip address where user want to access by hardware components. + +Since we have multi-subsystems will use unique ADI to access analog chip, when +one system is reading/writing data by ADI software channels, that should be under +one hardware spinlock protection to prevent other systems from reading/writing +data by ADI software channels at the same time, or two parallel routine of setting +ADI registers will make ADI controller registers chaos to lead incorrect results. +Then we need one hardware spinlock to synchronize between the multiple subsystems. + +Required properties: +- compatible: Should be "sprd,sc9860-adi". +- reg: Offset and length of ADI-SPI controller register space. +- hwlocks: Reference to a phandle of a hwlock provider node. +- hwlock-names: Reference to hwlock name strings defined in the same order + as the hwlocks, should be "adi". +- #address-cells: Number of cells required to define a chip select address + on the ADI-SPI bus. Should be set to 1. +- #size-cells: Size of cells required to define a chip select address size + on the ADI-SPI bus. Should be set to 0. + +Optional properties: +- sprd,hw-channels: This is an array of channel values up to 49 channels. + The first value specifies the hardware channel id which is used to + transfer data triggered by hardware automatically, and the second + value specifies the analog chip address where user want to access + by hardware components. + +SPI slave nodes must be children of the SPI controller node and can contain +properties described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + adi_bus: spi@40030000 { + compatible = "sprd,sc9860-adi"; + reg = <0 0x40030000 0 0x10000>; + hwlocks = <&hwlock1 0>; + hwlock-names = "adi"; + #address-cells = <1>; + #size-cells = <0>; + sprd,hw-channels = <30 0x8c20>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-st-ssc.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-st-ssc.txt new file mode 100644 index 0000000000000000000000000000000000000000..1bdc4709e4743c5599d790e09ff68295c05f9fa0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-st-ssc.txt @@ -0,0 +1,40 @@ +STMicroelectronics SSC (SPI) Controller +--------------------------------------- + +Required properties: +- compatible : "st,comms-ssc4-spi" +- reg : Offset and length of the device's register set +- interrupts : The interrupt specifier +- clock-names : Must contain "ssc" +- clocks : Must contain an entry for each name in clock-names + See ../clk/* +- pinctrl-names : Uses "default", can use "sleep" if provided + See ../pinctrl/pinctrl-bindings.txt + +Optional properties: +- cs-gpios : List of GPIO chip selects + See ../spi/spi-bus.txt + +Child nodes represent devices on the SPI bus + See ../spi/spi-bus.txt + +Example: + spi@9840000 { + compatible = "st,comms-ssc4-spi"; + reg = <0x9840000 0x110>; + interrupts = ; + clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>; + clock-names = "ssc"; + pinctrl-0 = <&pinctrl_spi0_default>; + pinctrl-names = "default"; + cs-gpios = <&pio17 5 0>; + #address-cells = <1>; + #size-cells = <0>; + + st95hf@0{ + compatible = "st,st95hf"; + reg = <0>; + spi-max-frequency = <1000000>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-stm32.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-stm32.txt new file mode 100644 index 0000000000000000000000000000000000000000..1b3fa2c119d5123a7023a6eb6f71225d9ed37f1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-stm32.txt @@ -0,0 +1,59 @@ +STMicroelectronics STM32 SPI Controller + +The STM32 SPI controller is used to communicate with external devices using +the Serial Peripheral Interface. It supports full-duplex, half-duplex and +simplex synchronous serial communication with external devices. It supports +from 4 to 32-bit data size. Although it can be configured as master or slave, +only master is supported by the driver. + +Required properties: +- compatible: Must be "st,stm32h7-spi". +- reg: Offset and length of the device's register set. +- interrupts: Must contain the interrupt id. +- clocks: Must contain an entry for spiclk (which feeds the internal clock + generator). +- #address-cells: Number of cells required to define a chip select address. +- #size-cells: Should be zero. + +Optional properties: +- resets: Must contain the phandle to the reset controller. +- A pinctrl state named "default" may be defined to set pins in mode of + operation for SPI transfer. +- dmas: DMA specifiers for tx and rx dma. DMA fifo mode must be used. See the + STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt. +- dma-names: DMA request names should include "tx" and "rx" if present. +- cs-gpios: list of GPIO chip selects. See the SPI bus bindings, + Documentation/devicetree/bindings/spi/spi-bus.txt + + +Child nodes represent devices on the SPI bus + See ../spi/spi-bus.txt + +Optional properties: +- st,spi-midi-ns: (Master Inter-Data Idleness) minimum time delay in + nanoseconds inserted between two consecutive data frames. + + +Example: + spi2: spi@40003800 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32h7-spi"; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = <&rcc SPI2_CK>; + resets = <&rcc 1166>; + dmas = <&dmamux1 0 39 0x400 0x01>, + <&dmamux1 1 40 0x400 0x01>; + dma-names = "rx", "tx"; + pinctrl-0 = <&spi2_pins_b>; + pinctrl-names = "default"; + cs-gpios = <&gpioa 11 0>; + + aardvark@0 { + compatible = "totalphase,aardvark"; + reg = <0>; + spi-max-frequency = <4000000>; + st,spi-midi-ns = <4000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-sun4i.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sun4i.txt new file mode 100644 index 0000000000000000000000000000000000000000..c75d604a82900fe3a05f54e4f52c4f28dafc4cbf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sun4i.txt @@ -0,0 +1,23 @@ +Allwinner A10 SPI controller + +Required properties: +- compatible: Should be "allwinner,sun4-a10-spi". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks: phandle to the clocks feeding the SPI controller. Two are + needed: + - "ahb": the gated AHB parent clock + - "mod": the parent module clock +- clock-names: Must contain the clock names described just above + +Example: + +spi1: spi@1c06000 { + compatible = "allwinner,sun4i-a10-spi"; + reg = <0x01c06000 0x1000>; + interrupts = <11>; + clocks = <&ahb_gates 21>, <&spi1_clk>; + clock-names = "ahb", "mod"; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-sun6i.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sun6i.txt new file mode 100644 index 0000000000000000000000000000000000000000..435a8e0731ac02ce8c9572eb118012a499b11280 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-sun6i.txt @@ -0,0 +1,44 @@ +Allwinner A31/H3 SPI controller + +Required properties: +- compatible: Should be "allwinner,sun6i-a31-spi" or "allwinner,sun8i-h3-spi". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks: phandle to the clocks feeding the SPI controller. Two are + needed: + - "ahb": the gated AHB parent clock + - "mod": the parent module clock +- clock-names: Must contain the clock names described just above +- resets: phandle to the reset controller asserting this device in + reset + +Optional properties: +- dmas: DMA specifiers for rx and tx dma. See the DMA client binding, + Documentation/devicetree/bindings/dma/dma.txt +- dma-names: DMA request names should include "rx" and "tx" if present. + +Example: + +spi1: spi@1c69000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c69000 0x1000>; + interrupts = <0 66 4>; + clocks = <&ahb1_gates 21>, <&spi1_clk>; + clock-names = "ahb", "mod"; + resets = <&ahb1_rst 21>; +}; + +spi0: spi@1c68000 { + compatible = "allwinner,sun8i-h3-spi"; + reg = <0x01c68000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>; + clock-names = "ahb", "mod"; + dmas = <&dma 23>, <&dma 23>; + dma-names = "rx", "tx"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + resets = <&ccu RST_BUS_SPI0>; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-uniphier.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-uniphier.txt new file mode 100644 index 0000000000000000000000000000000000000000..504a4ecfc7b16869192c666e903a9d884d9f052d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-uniphier.txt @@ -0,0 +1,22 @@ +Socionext UniPhier SPI controller driver + +UniPhier SoCs have SCSSI which supports SPI single channel. + +Required properties: + - compatible: should be "socionext,uniphier-scssi" + - reg: address and length of the spi master registers + - #address-cells: must be <1>, see spi-bus.txt + - #size-cells: must be <0>, see spi-bus.txt + - clocks: A phandle to the clock for the device. + - resets: A phandle to the reset control for the device. + +Example: + +spi0: spi@54006000 { + compatible = "socionext,uniphier-scssi"; + reg = <0x54006000 0x100>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&peri_clk 11>; + resets = <&peri_rst 11>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-xilinx.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-xilinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc924a5f71db042c5c702374442c08710a4e5fec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-xilinx.txt @@ -0,0 +1,21 @@ +Xilinx SPI controller Device Tree Bindings +------------------------------------------------- + +Required properties: +- compatible : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a" +- reg : Physical base address and size of SPI registers map. +- interrupts : Property with a value describing the interrupt + number. + +Optional properties: +- xlnx,num-ss-bits : Number of chip selects used. + +Example: + axi_quad_spi@41e00000 { + compatible = "xlnx,xps-spi-2.00.a"; + interrupt-parent = <&intc>; + interrupts = <0 31 1>; + reg = <0x41e00000 0x10000>; + xlnx,num-ss-bits = <0x1>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-xlp.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-xlp.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4925ec0ed331d7a1330eed795b959b79de9b2a2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-xlp.txt @@ -0,0 +1,38 @@ +SPI Master controller for Netlogic XLP MIPS64 SOCs +================================================== + +Currently this SPI controller driver is supported for the following +Netlogic XLP SoCs: + XLP832, XLP316, XLP208, XLP980, XLP532 + +Required properties: +- compatible : Should be "netlogic,xlp832-spi". +- #address-cells : Number of cells required to define a chip select address + on the SPI bus. +- #size-cells : Should be zero. +- reg : Should contain register location and length. +- clocks : Phandle of the spi clock +- interrupts : Interrupt number used by this controller. + +SPI slave nodes must be children of the SPI master node and can contain +properties described in Documentation/devicetree/bindings/spi/spi-bus.txt. + +Example: + + spi: xlp_spi@3a100 { + compatible = "netlogic,xlp832-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x3a100 0x100>; + clocks = <&spi_clk>; + interrupts = <34>; + interrupt-parent = <&pic>; + + spi_nor@1 { + compatible = "spansion,s25sl12801"; + #address-cells = <1>; + #size-cells = <1>; + reg = <1>; /* Chip Select */ + spi-max-frequency = <40000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-xtensa-xtfpga.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-xtensa-xtfpga.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6ebe2bc704104a0cd4872a4d14002d963871b92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-xtensa-xtfpga.txt @@ -0,0 +1,9 @@ +Cadence Xtensa XTFPGA platform SPI controller. + +This simple SPI master controller is built into xtfpga bitstreams and is used +to control daughterboard audio codec. + +Required properties: +- compatible: should be "cdns,xtfpga-spi". +- reg: physical base address of the controller and length of memory mapped + region. diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi-zynqmp-qspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi-zynqmp-qspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f6d37ff541c4b0a9b1923120b18dfb49b0f9115 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi-zynqmp-qspi.txt @@ -0,0 +1,25 @@ +Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings +------------------------------------------------------------------- + +Required properties: +- compatible : Should be "xlnx,zynqmp-qspi-1.0". +- reg : Physical base address and size of GQSPI registers map. +- interrupts : Property with a value describing the interrupt + number. +- clock-names : List of input clock names - "ref_clk", "pclk" + (See clock bindings for details). +- clocks : Clock phandles (see clock bindings for details). + +Optional properties: +- num-cs : Number of chip selects used. + +Example: + qspi: spi@ff0f0000 { + compatible = "xlnx,zynqmp-qspi-1.0"; + clock-names = "ref_clk", "pclk"; + clocks = <&misc_clk &misc_clk>; + interrupts = <0 15 4>; + interrupt-parent = <&gic>; + num-cs = <1>; + reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi_altera.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi_altera.txt new file mode 100644 index 0000000000000000000000000000000000000000..31319dcf30ab78513f7355d1b28d1f439c052cab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi_altera.txt @@ -0,0 +1,5 @@ +Altera SPI + +Required properties: +- compatible : should be "ALTR,spi-1.0". +- compatible : should be "altr,spi-1.0". diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi_atmel.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi_atmel.txt new file mode 100644 index 0000000000000000000000000000000000000000..f99c733d75c12b6d393eb8b48f66c2cbdeaba56b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi_atmel.txt @@ -0,0 +1,36 @@ +Atmel SPI device + +Required properties: +- compatible : should be "atmel,at91rm9200-spi". +- reg: Address and length of the register set for the device +- interrupts: Should contain spi interrupt +- cs-gpios: chipselects (optional for SPI controller version >= 2 with the + Chip Select Active After Transfer feature). +- clock-names: tuple listing input clock names. + Required elements: "spi_clk" +- clocks: phandles to input clocks. + +Optional properties: +- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO + capable SPI controllers. + +Example: + +spi1: spi@fffcc000 { + compatible = "atmel,at91rm9200-spi"; + reg = <0xfffcc000 0x4000>; + interrupts = <13 4 5>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&spi1_clk>; + clock-names = "spi_clk"; + cs-gpios = <&pioB 3 0>; + atmel,fifo-size = <32>; + + mmc-slot@0 { + compatible = "mmc-spi-slot"; + reg = <0>; + gpios = <&pioC 4 0>; /* CD */ + spi-max-frequency = <25000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi_oc_tiny.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi_oc_tiny.txt new file mode 100644 index 0000000000000000000000000000000000000000..d95c0b367a04ea1a3bba91e9082d84c743284078 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi_oc_tiny.txt @@ -0,0 +1,12 @@ +OpenCores tiny SPI + +Required properties: +- compatible : should be "opencores,tiny-spi-rtlsvn2". +- gpios : should specify GPIOs used for chipselect. +Optional properties: +- clock-frequency : input clock frequency to the core. +- baud-width: width, in bits, of the programmable divider used to scale + the input clock to SCLK. + +The clock-frequency and baud-width properties are needed only if the divider +is programmable. They are not needed if the divider is fixed. diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi_pl022.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi_pl022.txt new file mode 100644 index 0000000000000000000000000000000000000000..7638b4968ddb4ad8adabbf36ab540751b6eec343 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi_pl022.txt @@ -0,0 +1,70 @@ +ARM PL022 SPI controller + +Required properties: +- compatible : "arm,pl022", "arm,primecell" +- reg : Offset and length of the register set for the device +- interrupts : Should contain SPI controller interrupt +- num-cs : total number of chipselects + +Optional properties: +- cs-gpios : should specify GPIOs used for chipselects. + The gpios will be referred to as reg = in the SPI child nodes. + If unspecified, a single SPI device without a chip select can be used. +- pl022,autosuspend-delay : delay in ms following transfer completion before + the runtime power management system suspends the + device. A setting of 0 indicates no delay and the + device will be suspended immediately +- pl022,rt : indicates the controller should run the message pump with realtime + priority to minimise the transfer latency on the bus (boolean) +- dmas : Two or more DMA channel specifiers following the convention outlined + in bindings/dma/dma.txt +- dma-names: Names for the dma channels, if present. There must be at + least one channel named "tx" for transmit and named "rx" for + receive. + + +SPI slave nodes must be children of the SPI master node and can +contain the following properties. + +- pl022,interface : interface type: + 0: SPI + 1: Texas Instruments Synchronous Serial Frame Format + 2: Microwire (Half Duplex) +- pl022,com-mode : specifies the transfer mode: + 0: interrupt mode + 1: polling mode (default mode if property not present) + 2: DMA mode +- pl022,rx-level-trig : Rx FIFO watermark level +- pl022,tx-level-trig : Tx FIFO watermark level +- pl022,ctrl-len : Microwire interface: Control length +- pl022,wait-state : Microwire interface: Wait state +- pl022,duplex : Microwire interface: Full/Half duplex + + +Example: + + spi@e0100000 { + compatible = "arm,pl022", "arm,primecell"; + reg = <0xe0100000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0 31 0x4>; + dmas = <&dma-controller 23 1>, + <&dma-controller 24 0>; + dma-names = "rx", "tx"; + + m25p80@1 { + compatible = "st,m25p80"; + reg = <1>; + spi-max-frequency = <12000000>; + spi-cpol; + spi-cpha; + pl022,interface = <0>; + pl022,com-mode = <0x2>; + pl022,rx-level-trig = <0>; + pl022,tx-level-trig = <0>; + pl022,ctrl-len = <0x11>; + pl022,wait-state = <0>; + pl022,duplex = <0>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/spi_qsd.txt b/arch/arm64/boot/dts/vendor/bindings/spi/spi_qsd.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d50dbbc7917729503afff30a8b2f1047319766f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/spi_qsd.txt @@ -0,0 +1,106 @@ +Qualcomm Technologies, Inc. Serial Peripheral Interface (SPI) + +Required properties: +- compatible : Should be "qcom,spi-qup-v2". +- reg : Offset and length of the register regions for the device +- reg-names : Register region names referenced in reg above. + Required register resource entries are: + "spi_physical" : Physical address of controller register blocks. +- interrupts : Interrupt numbers used by this controller +- interrupt-names : Interrupt resource names referenced in interrupts above. + Required interrupt resource entries are: + "spi_irq" : QUP-core interrupt. +- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz. + +Required alias: +- The desired bus-number is specified via an alias with the following format + 'spi{n}' where n is the bus number. + +Optional properties: +- qcom,gpio-mosi : GPIO pin number of the MOSI bus line. +- qcom,gpio-miso : GPIO pin number of the MISO bus line. +- qcom,gpio-clk : GPIO pin number of the CLK bus line. +- qcom,gpio-cs0 : GPIO pin number of the chipselect0 bus line. +- qcom,gpio-cs1 : GPIO pin number of the chipselect1 bus line. +- qcom,gpio-cs2 : GPIO pin number of the chipselect2 bus line. +- qcom,gpio-cs3 : GPIO pin number of the chipselect3 bus line. +- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When + value is non-zero, the value is the number of words in maximum transfer + length. + - qcom,active-only : Vote for core clock when the application processor goes + to active state and remove that vote when it goes to idle state. This flag may + improve service time of first spi request at the expense of power consumption. + When this entry is not present, voting is done by the runtime-pm callbacks. + - qcom,master-id : Master endpoint number used for voting on clocks using the + bus-scaling driver. + - qcom,rt-priority : whether spi message queue is set to run as a realtime task. + With this spi transaction message pump with high (realtime) priority to reduce + the transfer latency on the bus by minimising the delay between a transfer request + - qcom,shared : whether this qup is shared with other ee's + +Optional properties which are required for support of BAM-mode: +- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW + version support latest features (e.g. BAM) and then enable them. Should be + removed for legacy HW. +- qcom,use-bam : Boolean. When present, enables BAM-mode. +- qcom,use-pinctrl : Boolean. When present, enables pinctrl frame work to configure GPIO's + instead of existing gpio mux hence gpio entries are no more required if present. +- pinctrl-names : Property must contain "spi_default" and "spi_sleep" if + pinctrl is to be used. + instead of existing gpio mux hence gpio entries are no more required if present. +- qcom,bam-consumer-pipe-index : BAM consumer-pipe index. +- qcom,bam-producer-pipe-index : BAM producer-pipe index. +- reg-names : register region names referenced in reg. + Required register resource for BAM are: + "spi_bam_physical" : Physical address of BAM for this controller. +- interrupt-names : interrupt resource names referenced in interrupts. + Required interrupt resource from BAM are: + "spi_bam_irq" : BAM interrupt used by the controller. + +Optional SPI slave nodes must be children of the SPI master node and contain +the following properties. +- reg: (required) chip-select address of the device. +- compatible : (required) Name of SPI device following generic names. +- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz +- interrupts : (recommended) Should contain the SPI slave interrupt number + encoded depending on the type of the interrupt controller. +- interrupt-parent : (recommended) The phandle for the interrupt controller + that services interrupts for this device. +- spi-cpol : (optional) Empty property indicating device requires inverse + clock polarity (CPOL) mode +- spi-cpha : (optional) Empty property indicating device requires shifted + clock phase (CPHA) mode +- spi-cs-high : (optional) Empty property indicating device requires + chip select active high + +Example: + aliases { + spi0 = &spi_0; + }; + + spi_0: spi@f9923000 { + compatible = "qcom,spi-qup-v2"; + + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xf9923000 0x1000>, + <0xf9904000 0x10000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 95 0>, <0 238 0>; + + spi-max-frequency = <19200000>; + #address-cells = <1>; + #size-cells = <0>; + qcom,gpio-mosi = <&msmgpio 0 0>; + qcom,gpio-miso = <&msmgpio 1 0>; + qcom,gpio-clk = <&msmgpio 3 0>; + qcom,gpio-cs2 = <&msmgpio 9 0>; + + qcom,infinite-mode = <0>; + qcom,use-bam; + qcom,use-pinctrl; + qcom,bam-consumer-pipe-index = <12>; + qcom,bam-producer-pipe-index = <13>; + qcom,ver-reg-exists; + qcom,master-id = <86>; + qcom,rt-priority; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/sqi-pic32.txt b/arch/arm64/boot/dts/vendor/bindings/spi/sqi-pic32.txt new file mode 100644 index 0000000000000000000000000000000000000000..c82d021bce50c401a172babf4638f340a2114e1b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/sqi-pic32.txt @@ -0,0 +1,18 @@ +Microchip PIC32 Quad SPI controller +----------------------------------- +Required properties: +- compatible: Should be "microchip,pic32mzda-sqi". +- reg: Address and length of SQI controller register space. +- interrupts: Should contain SQI interrupt. +- clocks: Should contain phandle of two clocks in sequence, one that drives + clock on SPI bus and other that drives SQI controller. +- clock-names: Should be "spi_ck" and "reg_ck" in order. + +Example: + sqi1: spi@1f8e2000 { + compatible = "microchip,pic32mzda-sqi"; + reg = <0x1f8e2000 0x200>; + clocks = <&rootclk REF2CLK>, <&rootclk PB5CLK>; + clock-names = "spi_ck", "reg_ck"; + interrupts = <169 IRQ_TYPE_LEVEL_HIGH>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spi/ti_qspi.txt b/arch/arm64/boot/dts/vendor/bindings/spi/ti_qspi.txt new file mode 100644 index 0000000000000000000000000000000000000000..e65fde4a73883f0a9457200a79a4d8e91ffeca44 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spi/ti_qspi.txt @@ -0,0 +1,53 @@ +TI QSPI controller. + +Required properties: +- compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi". +- reg: Should contain QSPI registers location and length. +- reg-names: Should contain the resource reg names. + - qspi_base: Qspi configuration register Address space + - qspi_mmap: Memory mapped Address space + - (optional) qspi_ctrlmod: Control module Address space +- interrupts: should contain the qspi interrupt number. +- #address-cells, #size-cells : Must be present if the device has sub-nodes +- ti,hwmods: Name of the hwmod associated to the QSPI + +Recommended properties: +- spi-max-frequency: Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +Optional properties: +- syscon-chipselects: Handle to system control region contains QSPI + chipselect register and offset of that register. + +NOTE: TI QSPI controller requires different pinmux and IODelay +parameters for Mode-0 and Mode-3 operations, which needs to be set up by +the bootloader (U-Boot). Default configuration only supports Mode-0 +operation. Hence, "spi-cpol" and "spi-cpha" DT properties cannot be +specified in the slave nodes of TI QSPI controller without appropriate +modification to bootloader. + +Example: + +For am4372: +qspi: qspi@4b300000 { + compatible = "ti,am4372-qspi"; + reg = <0x47900000 0x100>, <0x30000000 0x4000000>; + reg-names = "qspi_base", "qspi_mmap"; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <25000000>; + ti,hwmods = "qspi"; +}; + +For dra7xx: +qspi: qspi@4b300000 { + compatible = "ti,dra7xxx-qspi"; + reg = <0x4b300000 0x100>, + <0x5c000000 0x4000000>, + reg-names = "qspi_base", "qspi_mmap"; + syscon-chipselects = <&scm_conf 0x558>; + #address-cells = <1>; + #size-cells = <0>; + spi-max-frequency = <48000000>; + ti,hwmods = "qspi"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spmi/qcom,spmi-pmic-arb-debug.txt b/arch/arm64/boot/dts/vendor/bindings/spmi/qcom,spmi-pmic-arb-debug.txt new file mode 100644 index 0000000000000000000000000000000000000000..0d7985225b98ca72c36df44cf9d490b5f1f95658 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spmi/qcom,spmi-pmic-arb-debug.txt @@ -0,0 +1,78 @@ +Qualcomm Technologies, Inc. SPMI Debug Controller (PMIC Arbiter) + +The SPMI PMIC Arbiter is found on various QTI chips. It is an SPMI controller +with wrapping arbitration logic to allow for multiple on-chip devices to control +a single SPMI master. + +The PMIC Arbiter debug bus is present starting at arbiter version 5. It has +read and write access to all PMIC peripherals regardless of ownership +configurations. It cannot be used on production devices because it is disabled +by an eFuse. + +See spmi.txt for the generic SPMI controller binding requirements for child +nodes. + +Supported Properties: + +- compatible + Usage: required + Value type: + Definition: Must be "qcom,spmi-pmic-arb-debug". + +- reg + Usage: required + Value type: + Definition: List of address and size pairs. The address of the PMIC + arbiter module is required. The address of the debug bus + disabling fuse is optional. + +- reg-names + Usage: required + Value type: + Definition: Address names. Must include "core" for the PMIC arbiter + module and may include "fuse" for the debug bus disabling + fuse. The strings must be specified in the same order as + the corresponding addresses are specified in the reg + property. + +- clocks + Usage: optional + Value type: + Definition: Clock tuple consisting of a phandle to a clock controller + device and the clock ID number for the SPMI debug controller + clock. + +- clock-names + Usage: required if clocks property is specified + Value type: + Definition: Defines the name of the clock defined in the "clocks" + property. This must be "core_clk". + +- #address-cells + Usage: required + Value type: + Definition: Must be 2. + +- #size-cells + Usage: required + Value type: + Definition: Must be 0. + +- qcom,fuse-disable-bit + Usage: required if "fuse" is listed in reg-names property + Value type: + Definition: The bit within the fuse register which is set when the debug + bus is not available. Supported values are 0 to 31. + +Example: + +qcom,spmi-debug@6b22000 { + compatible = "qcom,spmi-pmic-arb-debug"; + reg = <0x6b22000 0x60>, <0x7820a8 4>; + reg-names = "core", "fuse"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + qcom,fuse-disable-bit = <12>; + #address-cells = <2>; + #size-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/spmi/qcom,spmi-pmic-arb.txt b/arch/arm64/boot/dts/vendor/bindings/spmi/qcom,spmi-pmic-arb.txt new file mode 100644 index 0000000000000000000000000000000000000000..e16b9b5afc70a139087dea1ca3a64e9989525112 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spmi/qcom,spmi-pmic-arb.txt @@ -0,0 +1,65 @@ +Qualcomm SPMI Controller (PMIC Arbiter) + +The SPMI PMIC Arbiter is found on Snapdragon chipsets. It is an SPMI +controller with wrapping arbitration logic to allow for multiple on-chip +devices to control a single SPMI master. + +The PMIC Arbiter can also act as an interrupt controller, providing interrupts +to slave devices. + +See spmi.txt for the generic SPMI controller binding requirements for child +nodes. + +See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for +generic interrupt controller binding documentation. + +Required properties: +- compatible : should be "qcom,spmi-pmic-arb". +- reg-names : must contain: + "core" - core registers + "intr" - interrupt controller registers + "cnfg" - configuration registers + Registers used only for V2 PMIC Arbiter: + "chnls" - tx-channel per virtual slave registers. + "obsrvr" - rx-channel (called observer) per virtual slave registers. + +- reg : address + size pairs describing the PMIC arb register sets; order must + correspond with the order of entries in reg-names +- #address-cells : must be set to 2 +- #size-cells : must be set to 0 +- qcom,ee : indicates the active Execution Environment identifier (0-5) +- qcom,channel : which of the PMIC Arb provided channels to use for accesses (0-5) +- interrupts : interrupt list for the PMIC Arb controller, must contain a + single interrupt entry for the peripheral interrupt +- interrupt-names : corresponding interrupt names for the interrupts + listed in the 'interrupts' property, must contain: + "periph_irq" - summary interrupt for PMIC peripherals +- interrupt-controller : boolean indicator that the PMIC arbiter is an interrupt controller +- #interrupt-cells : must be set to 4. Interrupts are specified as a 4-tuple: + cell 1: slave ID for the requested interrupt (0-15) + cell 2: peripheral ID for requested interrupt (0-255) + cell 3: the requested peripheral interrupt (0-7) + cell 4: interrupt flags indicating level-sense information, as defined in + dt-bindings/interrupt-controller/irq.h + +Example: + + spmi { + compatible = "qcom,spmi-pmic-arb"; + reg-names = "core", "intr", "cnfg"; + reg = <0xfc4cf000 0x1000>, + <0xfc4cb000 0x1000>, + <0xfc4ca000 0x1000>; + + interrupt-names = "periph_irq"; + interrupts = <0 190 0>; + + qcom,ee = <0>; + qcom,channel = <0>; + + #address-cells = <2>; + #size-cells = <0>; + + interrupt-controller; + #interrupt-cells = <4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/spmi/spmi.txt b/arch/arm64/boot/dts/vendor/bindings/spmi/spmi.txt new file mode 100644 index 0000000000000000000000000000000000000000..4bb10d161a27d277554821fe6d82a2762c8b81c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/spmi/spmi.txt @@ -0,0 +1,41 @@ +System Power Management Interface (SPMI) Controller + +This document defines a generic set of bindings for use by SPMI controllers. A +controller is modelled in device tree as a node with zero or more child nodes, +each representing a unique slave on the bus. + +Required properties: +- #address-cells : must be set to 2 +- #size-cells : must be set to 0 + +Child nodes: + +An SPMI controller node can contain zero or more child nodes representing slave +devices on the bus. Child 'reg' properties are specified as an address, type +pair. The address must be in the range 0-15 (4 bits). The type must be one of +SPMI_USID (0) or SPMI_GSID (1) for Unique Slave ID or Group Slave ID respectively. +These are the identifiers "statically assigned by the system integrator", as +per the SPMI spec. + +Each child node must have one and only one 'reg' entry of type SPMI_USID. + +#include + + spmi@.. { + compatible = "..."; + reg = <...>; + + #address-cells = <2>; + #size-cells = <0>; + + child@0 { + compatible = "..."; + reg = <0 SPMI_USID>; + }; + + child@7 { + compatible = "..."; + reg = <7 SPMI_USID + 3 SPMI_GSID>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sram/renesas,smp-sram.txt b/arch/arm64/boot/dts/vendor/bindings/sram/renesas,smp-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..712d05e3e15eeb65faaed7de21f6533ab6bcbb47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sram/renesas,smp-sram.txt @@ -0,0 +1,27 @@ +* Renesas SMP SRAM + +Renesas R-Car Gen2 and RZ/G1 SoCs need a small piece of SRAM for the jump stub +for secondary CPU bringup and CPU hotplug. +This memory is reserved by adding a child node to a "mmio-sram" node, cfr. +Documentation/devicetree/bindings/sram/sram.txt. + +Required child node properties: + - compatible: Must be "renesas,smp-sram", + - reg: Address and length of the reserved SRAM. + The full physical (bus) address must be aligned to a 256 KiB boundary. + + +Example: + + icram1: sram@e63c0000 { + compatible = "mmio-sram"; + reg = <0 0xe63c0000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0xe63c0000 0x1000>; + + smp-sram@0 { + compatible = "renesas,smp-sram"; + reg = <0 0x10>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sram/rockchip-pmu-sram.txt b/arch/arm64/boot/dts/vendor/bindings/sram/rockchip-pmu-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b42fda306ff61631f6feeefaa05369adecac7f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sram/rockchip-pmu-sram.txt @@ -0,0 +1,16 @@ +Rockchip SRAM for pmu: +------------------------------ + +The sram of pmu is used to store the function of resume from maskrom(the 1st +level loader). This is a common use of the "pmu-sram" because it keeps power +even in low power states in the system. + +Required node properties: +- compatible : should be "rockchip,rk3288-pmu-sram" +- reg : physical base address and the size of the registers window + +Example: + sram@ff720000 { + compatible = "rockchip,rk3288-pmu-sram", "mmio-sram"; + reg = <0xff720000 0x1000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sram/rockchip-smp-sram.txt b/arch/arm64/boot/dts/vendor/bindings/sram/rockchip-smp-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..800701ecffca34235d46d00f29fd4cbabdaac5bd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sram/rockchip-smp-sram.txt @@ -0,0 +1,30 @@ +Rockchip SRAM for smp bringup: +------------------------------ + +Rockchip's smp-capable SoCs use the first part of the sram for the bringup +of the cores. Once the core gets powered up it executes the code that is +residing at the very beginning of the sram. + +Therefore a reserved section sub-node has to be added to the mmio-sram +declaration. + +Required sub-node properties: +- compatible : should be "rockchip,rk3066-smp-sram" + +The rest of the properties should follow the generic mmio-sram discription +found in Documentation/devicetree/bindings/sram/sram.txt + +Example: + + sram: sram@10080000 { + compatible = "mmio-sram"; + reg = <0x10080000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + smp-sram@10080000 { + compatible = "rockchip,rk3066-smp-sram"; + reg = <0x10080000 0x50>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sram/samsung-sram.txt b/arch/arm64/boot/dts/vendor/bindings/sram/samsung-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..61a9bbed303d7000eafa3d51219c39592f94c869 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sram/samsung-sram.txt @@ -0,0 +1,38 @@ +Samsung Exynos SYSRAM for SMP bringup: +------------------------------------ + +Samsung SMP-capable Exynos SoCs use part of the SYSRAM for the bringup +of the secondary cores. Once the core gets powered up it executes the +code that is residing at some specific location of the SYSRAM. + +Therefore reserved section sub-nodes have to be added to the mmio-sram +declaration. These nodes are of two types depending upon secure or +non-secure execution environment. + +Required sub-node properties: +- compatible : depending upon boot mode, should be + "samsung,exynos4210-sysram" : for Secure SYSRAM + "samsung,exynos4210-sysram-ns" : for Non-secure SYSRAM + +The rest of the properties should follow the generic mmio-sram discription +found in Documentation/devicetree/bindings/sram/sram.txt + +Example: + + sysram@2020000 { + compatible = "mmio-sram"; + reg = <0x02020000 0x54000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x02020000 0x54000>; + + smp-sysram@0 { + compatible = "samsung,exynos4210-sysram"; + reg = <0x0 0x1000>; + }; + + smp-sysram@53000 { + compatible = "samsung,exynos4210-sysram-ns"; + reg = <0x53000 0x1000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/sram/sram.txt b/arch/arm64/boot/dts/vendor/bindings/sram/sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..e98908bd4227fbd780882655cba6dd118787e7a8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sram/sram.txt @@ -0,0 +1,80 @@ +Generic on-chip SRAM + +Simple IO memory regions to be managed by the genalloc API. + +Required properties: + +- compatible : mmio-sram or atmel,sama5d2-securam + +- reg : SRAM iomem address range + +Reserving sram areas: +--------------------- + +Each child of the sram node specifies a region of reserved memory. Each +child node should use a 'reg' property to specify a specific range of +reserved memory. + +Following the generic-names recommended practice, node names should +reflect the purpose of the node. Unit address (@
) should be +appended to the name. + +Required properties in the sram node: + +- #address-cells, #size-cells : should use the same values as the root node +- ranges : standard definition, should translate from local addresses + within the sram to bus addresses + +Optional properties in the sram node: + +- no-memory-wc : the flag indicating, that SRAM memory region has not to + be remapped as write combining. WC is used by default. + +Required properties in the area nodes: + +- reg : iomem address range, relative to the SRAM range + +Optional properties in the area nodes: + +- compatible : standard definition, should contain a vendor specific string + in the form ,[-] +- pool : indicates that the particular reserved SRAM area is addressable + and in use by another device or devices +- export : indicates that the reserved SRAM area may be accessed outside + of the kernel, e.g. by bootloader or userspace +- protect-exec : Same as 'pool' above but with the additional + constraint that code wil be run from the region and + that the memory is maintained as read-only, executable + during code execution. NOTE: This region must be page + aligned on start and end in order to properly allow + manipulation of the page attributes. +- label : the name for the reserved partition, if omitted, the label + is taken from the node name excluding the unit address. +- clocks : a list of phandle and clock specifier pair that controls the + single SRAM clock. + +Example: + +sram: sram@5c000000 { + compatible = "mmio-sram"; + reg = <0x5c000000 0x40000>; /* 256 KiB SRAM at address 0x5c000000 */ + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x5c000000 0x40000>; + + smp-sram@100 { + compatible = "socvendor,smp-sram"; + reg = <0x100 0x50>; + }; + + device-sram@1000 { + reg = <0x1000 0x1000>; + pool; + }; + + exported@20000 { + reg = <0x20000 0x20000>; + export; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/sram/sunxi-sram.txt b/arch/arm64/boot/dts/vendor/bindings/sram/sunxi-sram.txt new file mode 100644 index 0000000000000000000000000000000000000000..c51ade86578c6508bf29c11af8653c68211d2ac3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/sram/sunxi-sram.txt @@ -0,0 +1,99 @@ +Allwinnner SoC SRAM controllers +----------------------------------------------------- + +The SRAM controller found on most Allwinner devices is represented by +a regular node for the SRAM controller itself, with sub-nodes +reprensenting the SRAM handled by the SRAM controller. + +Controller Node +--------------- + +Required properties: +- compatible : should be: + - "allwinner,sun4i-a10-sram-controller" (deprecated) + - "allwinner,sun4i-a10-system-control" + - "allwinner,sun5i-a13-system-control" + - "allwinner,sun7i-a20-system-control", "allwinner,sun4i-a10-system-control" + - "allwinner,sun8i-a23-system-control" + - "allwinner,sun8i-h3-system-control" + - "allwinner,sun50i-a64-sram-controller" (deprecated) + - "allwinner,sun50i-a64-system-control" +- reg : sram controller register offset + length + +SRAM nodes +---------- + +Each SRAM is described using the mmio-sram bindings documented in +Documentation/devicetree/bindings/sram/sram.txt + +Each SRAM will have SRAM sections that are going to be handled by the +SRAM controller as subnodes. These sections are represented following +once again the representation described in the mmio-sram binding. + +The valid sections compatible for A10 are: + - allwinner,sun4i-a10-sram-a3-a4 + - allwinner,sun4i-a10-sram-c1 + - allwinner,sun4i-a10-sram-d + +The valid sections compatible for A13 are: + - allwinner,sun5i-a13-sram-a3-a4, allwinner,sun4i-a10-sram-a3-a4 + - allwinner,sun5i-a13-sram-c1, allwinner,sun4i-a10-sram-c1 + - allwinner,sun5i-a13-sram-d, allwinner,sun4i-a10-sram-d + +The valid sections compatible for A20 are: + - allwinner,sun7i-a20-sram-a3-a4, allwinner,sun4i-a10-sram-a3-a4 + - allwinner,sun7i-a20-sram-c1, allwinner,sun4i-a10-sram-c1 + - allwinner,sun7i-a20-sram-d, allwinner,sun4i-a10-sram-d + +The valid sections compatible for A23/A33 are: + - allwinner,sun8i-a23-sram-c1, allwinner,sun4i-a10-sram-c1 + +The valid sections compatible for H3 are: + - allwinner,sun8i-h3-sram-c1, allwinner,sun4i-a10-sram-c1 + +The valid sections compatible for A64 are: + - allwinner,sun50i-a64-sram-c + +Devices using SRAM sections +--------------------------- + +Some devices need to request to the SRAM controller to map an SRAM for +their exclusive use. + +The relationship between such a device and an SRAM section is +expressed through the allwinner,sram property, that will take a +phandle and an argument. + +This valid values for this argument are: + - 0: CPU + - 1: Device + +Example +------- +system-control@1c00000 { + compatible = "allwinner,sun4i-a10-system-control"; + reg = <0x01c00000 0x30>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram_a: sram@00000000 { + compatible = "mmio-sram"; + reg = <0x00000000 0xc000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x00000000 0xc000>; + + emac_sram: sram-section@8000 { + compatible = "allwinner,sun4i-a10-sram-a3-a4"; + reg = <0x8000 0x4000>; + }; + }; +}; + +emac: ethernet@1c0b000 { + compatible = "allwinner,sun4i-a10-emac"; + ... + + allwinner,sram = <&emac_sram 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/staging/iio/adc/lpc32xx-adc.txt b/arch/arm64/boot/dts/vendor/bindings/staging/iio/adc/lpc32xx-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b3629d3a9adf82e510f504274b175ccfebe06fb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/staging/iio/adc/lpc32xx-adc.txt @@ -0,0 +1,16 @@ +* NXP LPC32xx SoC ADC controller + +Required properties: +- compatible: must be "nxp,lpc3220-adc" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The ADC interrupt + +Example: + + adc@40048000 { + compatible = "nxp,lpc3220-adc"; + reg = <0x40048000 0x1000>; + interrupt-parent = <&mic>; + interrupts = <39 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/staging/iio/adc/spear-adc.txt b/arch/arm64/boot/dts/vendor/bindings/staging/iio/adc/spear-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..88bc94fe1f6dff3def4725dac95841098bc43855 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/staging/iio/adc/spear-adc.txt @@ -0,0 +1,24 @@ +* ST SPEAr ADC device driver + +Required properties: +- compatible: Should be "st,spear600-adc" +- reg: Address and length of the register set for the device +- interrupts: Should contain the ADC interrupt +- sampling-frequency: Default sampling frequency + +Optional properties: +- vref-external: External voltage reference in milli-volts. If omitted + the internal voltage reference will be used. +- average-samples: Number of samples to generate an average value. If + omitted, single data conversion will be used. + +Examples: + + adc: adc@d8200000 { + compatible = "st,spear600-adc"; + reg = <0xd8200000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <6>; + sampling-frequency = <5000000>; + vref-external = <2500>; /* 2.5V VRef */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/submitting-patches.txt b/arch/arm64/boot/dts/vendor/bindings/submitting-patches.txt new file mode 100644 index 0000000000000000000000000000000000000000..de0d6090c0fd200f241aa0c71b5d208c62bde45c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/submitting-patches.txt @@ -0,0 +1,74 @@ + + Submitting devicetree (DT) binding patches + +I. For patch submitters + + 0) Normal patch submission rules from Documentation/process/submitting-patches.rst + applies. + + 1) The Documentation/ and include/dt-bindings/ portion of the patch should + be a separate patch. The preferred subject prefix for binding patches is: + + "dt-bindings: : ..." + + The 80 characters of the subject are precious. It is recommended to not + use "Documentation" or "doc" because that is implied. All bindings are + docs. Repeating "binding" again should also be avoided. + + 2) Submit the entire series to the devicetree mailinglist at + + devicetree@vger.kernel.org + + and Cc: the DT maintainers. Use scripts/get_maintainer.pl to identify + all of the DT maintainers. + + 3) The Documentation/ portion of the patch should come in the series before + the code implementing the binding. + + 4) Any compatible strings used in a chip or board DTS file must be + previously documented in the corresponding DT binding text file + in Documentation/devicetree/bindings. This rule applies even if + the Linux device driver does not yet match on the compatible + string. [ checkpatch will emit warnings if this step is not + followed as of commit bff5da4335256513497cc8c79f9a9d1665e09864 + ("checkpatch: add DT compatible string documentation checks"). ] + + 5) The wildcard "" may be used in compatible strings, as in + the following example: + + - compatible: Must contain '"nvidia,-pcie", + "nvidia,tegra20-pcie"' where is tegra30, tegra132, ... + + As in the above example, the known values of "" should be + documented if it is used. + + 6) If a documented compatible string is not yet matched by the + driver, the documentation should also include a compatible + string that is matched by the driver (as in the "nvidia,tegra20-pcie" + example above). + + +II. For kernel maintainers + + 1) If you aren't comfortable reviewing a given binding, reply to it and ask + the devicetree maintainers for guidance. This will help them prioritize + which ones to review and which ones are ok to let go. + + 2) For driver (not subsystem) bindings: If you are comfortable with the + binding, and it hasn't received an Acked-by from the devicetree + maintainers after a few weeks, go ahead and take it. + + Subsystem bindings (anything affecting more than a single device) + then getting a devicetree maintainer to review it is required. + + 3) For a series going though multiple trees, the binding patch should be + kept with the driver using the binding. + +III. Notes + + 0) Please see ...bindings/ABI.txt for details regarding devicetree ABI. + + 1) This document is intended as a general familiarization with the process as + decided at the 2013 Kernel Summit. When in doubt, the current word of the + devicetree maintainers overrules this document. In that situation, a patch + updating this document would be appreciated. diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/armada-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/armada-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..f3b441100890f493d781689f4c65027ef801be0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/armada-thermal.txt @@ -0,0 +1,41 @@ +* Marvell Armada 370/375/380/XP thermal management + +Required properties: + +- compatible: Should be set to one of the following: + * marvell,armada370-thermal + * marvell,armada375-thermal + * marvell,armada380-thermal + * marvell,armadaxp-thermal + * marvell,armada-ap806-thermal + * marvell,armada-cp110-thermal + +Note: these bindings are deprecated for AP806/CP110 and should instead +follow the rules described in: +Documentation/devicetree/bindings/arm/marvell/ap806-system-controller.txt +Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt + +- reg: Device's register space. + Two entries are expected, see the examples below. The first one points + to the status register (4B). The second one points to the control + registers (8B). + Note: The compatibles marvell,armada370-thermal, + marvell,armada380-thermal, and marvell,armadaxp-thermal must point to + "control MSB/control 1", with size of 4 (deprecated binding), or point + to "control LSB/control 0" with size of 8 (current binding). All other + compatibles must point to "control LSB/control 0" with size of 8. + +Examples: + + /* Legacy bindings */ + thermal@d0018300 { + compatible = "marvell,armada370-thermal"; + reg = <0xd0018300 0x4 + 0xd0018304 0x4>; + }; + + ap_thermal: thermal@6f8084 { + compatible = "marvell,armada-ap806-thermal"; + reg = <0x6f808C 0x4>, + <0x6f8084 0x8>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,avs-tmon.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,avs-tmon.txt new file mode 100644 index 0000000000000000000000000000000000000000..43a9ed5459447c8f7294cc490b044026b1cc16ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,avs-tmon.txt @@ -0,0 +1,19 @@ +* Broadcom STB thermal management + +Thermal management core, provided by the AVS TMON hardware block. + +Required properties: +- compatible: must be "brcm,avs-tmon" and/or "brcm,avs-tmon-bcm7445" +- reg: address range for the AVS TMON registers +- interrupts: temperature monitor interrupt, for high/low threshold triggers +- interrupt-names: should be "tmon" + +Example: + + thermal@f04d1500 { + compatible = "brcm,avs-tmon-bcm7445", "brcm,avs-tmon"; + reg = <0xf04d1500 0x28>; + interrupts = <0x6>; + interrupt-names = "tmon"; + interrupt-parent = <&avs_host_l2_intc>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,bcm2835-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,bcm2835-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..da8c5b73ad105a5fa5bf1510f5ec1f2d1ab462f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,bcm2835-thermal.txt @@ -0,0 +1,41 @@ +Binding for Thermal Sensor driver for BCM2835 SoCs. + +Required parameters: +------------------- + +compatible: should be one of: "brcm,bcm2835-thermal", + "brcm,bcm2836-thermal" or "brcm,bcm2837-thermal" +reg: Address range of the thermal registers. +clocks: Phandle of the clock used by the thermal sensor. +#thermal-sensor-cells: should be 0 (see thermal.txt) + +Example: + +thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <1000>; + + thermal-sensors = <&thermal>; + + trips { + cpu-crit { + temperature = <80000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + coefficients = <(-538) 407000>; + + cooling-maps { + }; + }; +}; + +thermal: thermal@7e212000 { + compatible = "brcm,bcm2835-thermal"; + reg = <0x7e212000 0x8>; + clocks = <&clocks BCM2835_CLOCK_TSENS>; + #thermal-sensor-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,ns-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,ns-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..68e047170039ecc08625fb1902d939aeb32bd58e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/brcm,ns-thermal.txt @@ -0,0 +1,37 @@ +* Broadcom Northstar Thermal + +This binding describes thermal sensor that is part of Northstar's DMU (Device +Management Unit). + +Required properties: +- compatible : Must be "brcm,ns-thermal" +- reg : iomem address range of PVTMON registers +- #thermal-sensor-cells : Should be <0> + +Example: + +thermal: thermal@1800c2c0 { + compatible = "brcm,ns-thermal"; + reg = <0x1800c2c0 0x10>; + #thermal-sensor-cells = <0>; +}; + +thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <1000>; + coefficients = <(-556) 418000>; + thermal-sensors = <&thermal>; + + trips { + cpu-crit { + temperature = <125000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/da9062-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/da9062-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..e241bb5a5584d2c5c0b4ff068926794264920f45 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/da9062-thermal.txt @@ -0,0 +1,36 @@ +* Dialog DA9062/61 TJUNC Thermal Module + +This module is part of the DA9061/DA9062. For more details about entire +DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt + +Junction temperature thermal module uses an interrupt signal to identify +high THERMAL_TRIP_HOT temperatures for the PMIC device. + +Required properties: + +- compatible: should be one of the following valid compatible string lines: + "dlg,da9061-thermal", "dlg,da9062-thermal" + "dlg,da9062-thermal" + +Optional properties: + +- polling-delay-passive : Specify the polling period, measured in + milliseconds, between thermal zone device update checks. + +Example: DA9062 + + pmic0: da9062@58 { + thermal { + compatible = "dlg,da9062-thermal"; + polling-delay-passive = <3000>; + }; + }; + +Example: DA9061 using a fall-back compatible for the DA9062 onkey driver + + pmic0: da9061@58 { + thermal { + compatible = "dlg,da9061-thermal", "dlg,da9062-thermal"; + polling-delay-passive = <3000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/db8500-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/db8500-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..2e1c06fad81fe2340996c91c539c22fd03ae3475 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/db8500-thermal.txt @@ -0,0 +1,44 @@ +* ST-Ericsson DB8500 Thermal + +** Thermal node properties: + +- compatible : "stericsson,db8500-thermal"; +- reg : address range of the thermal sensor registers; +- interrupts : interrupts generated from PRCMU; +- interrupt-names : "IRQ_HOTMON_LOW" and "IRQ_HOTMON_HIGH"; +- num-trips : number of total trip points, this is required, set it 0 if none, + if greater than 0, the following properties must be defined; +- tripN-temp : temperature of trip point N, should be in ascending order; +- tripN-type : type of trip point N, should be one of "active" "passive" "hot" + "critical"; +- tripN-cdev-num : number of the cooling devices which can be bound to trip + point N, this is required if trip point N is defined, set it 0 if none, + otherwise the following cooling device names must be defined; +- tripN-cdev-nameM : name of the No. M cooling device of trip point N; + +Usually the num-trips and tripN-*** are separated in board related dts files. + +Example: +thermal@801573c0 { + compatible = "stericsson,db8500-thermal"; + reg = <0x801573c0 0x40>; + interrupts = <21 0x4>, <22 0x4>; + interrupt-names = "IRQ_HOTMON_LOW", "IRQ_HOTMON_HIGH"; + + num-trips = <3>; + + trip0-temp = <75000>; + trip0-type = "active"; + trip0-cdev-num = <1>; + trip0-cdev-name0 = "thermal-cpufreq-0"; + + trip1-temp = <80000>; + trip1-type = "active"; + trip1-cdev-num = <2>; + trip1-cdev-name0 = "thermal-cpufreq-0"; + trip1-cdev-name1 = "thermal-fan"; + + trip2-temp = <85000>; + trip2-type = "critical"; + trip2-cdev-num = <0>; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/dove-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/dove-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f474677d4727de938e10c7e9132c0fbeaab14d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/dove-thermal.txt @@ -0,0 +1,18 @@ +* Dove Thermal + +This driver is for Dove SoCs which contain a thermal sensor. + +Required properties: +- compatible : "marvell,dove-thermal" +- reg : Address range of the thermal registers + +The reg properties should contain two ranges. The first is for the +three Thermal Manager registers, while the second range contains the +Thermal Diode Control Registers. + +Example: + + thermal@10078 { + compatible = "marvell,dove-thermal"; + reg = <0xd001c 0x0c>, <0xd005c 0x08>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/exynos-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/exynos-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..33004ce7e5dfa3d16a9a37fe3922546e4806f850 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/exynos-thermal.txt @@ -0,0 +1,106 @@ +* Exynos Thermal Management Unit (TMU) + +** Required properties: + +- compatible : One of the following: + "samsung,exynos3250-tmu" + "samsung,exynos4412-tmu" + "samsung,exynos4210-tmu" + "samsung,exynos5250-tmu" + "samsung,exynos5260-tmu" + "samsung,exynos5420-tmu" for TMU channel 0, 1 on Exynos5420 + "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4 + Exynos5420 (Must pass triminfo base and triminfo clock) + "samsung,exynos5433-tmu" + "samsung,exynos7-tmu" +- reg : Address range of the thermal registers. For soc's which has multiple + instances of TMU and some registers are shared across all TMU's like + interrupt related then 2 set of register has to supplied. First set + belongs to register set of TMU instance and second set belongs to + registers shared with the TMU instance. + + NOTE: On Exynos5420, the TRIMINFO register is misplaced for TMU + channels 2, 3 and 4 + Use "samsung,exynos5420-tmu-ext-triminfo" in cases, there is a misplaced + register, also provide clock to access that base. + + TRIMINFO at 0x1006c000 contains data for TMU channel 3 + TRIMINFO at 0x100a0000 contains data for TMU channel 4 + TRIMINFO at 0x10068000 contains data for TMU channel 2 + +- interrupts : Should contain interrupt for thermal system +- clocks : The main clocks for TMU device + -- 1. operational clock for TMU channel + -- 2. optional clock to access the shared registers of TMU channel + -- 3. optional special clock for functional operation +- clock-names : Thermal system clock name + -- "tmu_apbif" operational clock for current TMU channel + -- "tmu_triminfo_apbif" clock to access the shared triminfo register + for current TMU channel + -- "tmu_sclk" clock for functional operation of the current TMU + channel + +The Exynos TMU supports generating interrupts when reaching given +temperature thresholds. Number of supported thermal trip points depends +on the SoC (only first trip points defined in DT will be configured): + - most of SoC: 4 + - samsung,exynos5433-tmu: 8 + - samsung,exynos7-tmu: 8 + +** Optional properties: + +- vtmu-supply: This entry is optional and provides the regulator node supplying + voltage to TMU. If needed this entry can be placed inside + board/platform specific dts file. + +Example 1): + + tmu@100c0000 { + compatible = "samsung,exynos4412-tmu"; + interrupt-parent = <&combiner>; + reg = <0x100C0000 0x100>; + interrupts = <2 4>; + clocks = <&clock 383>; + clock-names = "tmu_apbif"; + vtmu-supply = <&tmu_regulator_node>; + #thermal-sensor-cells = <0>; + }; + +Example 2): (In case of Exynos5420 "with misplaced TRIMINFO register") + tmu_cpu2: tmu@10068000 { + compatible = "samsung,exynos5420-tmu-ext-triminfo"; + reg = <0x10068000 0x100>, <0x1006c000 0x4>; + interrupts = <0 184 0>; + clocks = <&clock 318>, <&clock 318>; + clock-names = "tmu_apbif", "tmu_triminfo_apbif"; + #thermal-sensor-cells = <0>; + }; + + tmu_cpu3: tmu@1006c000 { + compatible = "samsung,exynos5420-tmu-ext-triminfo"; + reg = <0x1006c000 0x100>, <0x100a0000 0x4>; + interrupts = <0 185 0>; + clocks = <&clock 318>, <&clock 319>; + clock-names = "tmu_apbif", "tmu_triminfo_apbif"; + #thermal-sensor-cells = <0>; + }; + + tmu_gpu: tmu@100a0000 { + compatible = "samsung,exynos5420-tmu-ext-triminfo"; + reg = <0x100a0000 0x100>, <0x10068000 0x4>; + interrupts = <0 215 0>; + clocks = <&clock 319>, <&clock 318>; + clock-names = "tmu_apbif", "tmu_triminfo_apbif"; + #thermal-sensor-cells = <0>; + }; + +Note: For multi-instance tmu each instance should have an alias correctly +numbered in "aliases" node. + +Example: + +aliases { + tmuctrl0 = &tmuctrl_0; + tmuctrl1 = &tmuctrl_1; + tmuctrl2 = &tmuctrl_2; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/hisilicon-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/hisilicon-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..cef716a236f1a94179d5c61bde45c79df0890e8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/hisilicon-thermal.txt @@ -0,0 +1,32 @@ +* Temperature Sensor on hisilicon SoCs + +** Required properties : + +- compatible: "hisilicon,tsensor". +- reg: physical base address of thermal sensor and length of memory mapped + region. +- interrupt: The interrupt number to the cpu. Defines the interrupt used + by /SOCTHERM/tsensor. +- clock-names: Input clock name, should be 'thermal_clk'. +- clocks: phandles for clock specified in "clock-names" property. +- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description. + +Example : + +for Hi6220: + tsensor: tsensor@0,f7030700 { + compatible = "hisilicon,tsensor"; + reg = <0x0 0xf7030700 0x0 0x1000>; + interrupts = <0 7 0x4>; + clocks = <&sys_ctrl HI6220_TSENSOR_CLK>; + clock-names = "thermal_clk"; + #thermal-sensor-cells = <1>; + } + +for Hi3660: + tsensor: tsensor@fff30000 { + compatible = "hisilicon,hi3660-tsensor"; + reg = <0x0 0xfff30000 0x0 0x1000>; + interrupts = ; + #thermal-sensor-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/imx-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/imx-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..823e4176eef8f7399eff8e9a8ded841c54bd8d4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/imx-thermal.txt @@ -0,0 +1,61 @@ +* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs + +Required properties: +- compatible : must be one of following: + - "fsl,imx6q-tempmon" for i.MX6Q, + - "fsl,imx6sx-tempmon" for i.MX6SX, + - "fsl,imx7d-tempmon" for i.MX7S/D. +- interrupts : the interrupt output of the controller: + i.MX6Q has one IRQ which will be triggered when temperature is higher than high threshold, + i.MX6SX and i.MX7S/D have two more IRQs than i.MX6Q, one is IRQ_LOW and the other is IRQ_PANIC, + when temperature is below than low threshold, IRQ_LOW will be triggered, when temperature + is higher than panic threshold, system will auto reboot by SRC module. +- fsl,tempmon : phandle pointer to system controller that contains TEMPMON + control registers, e.g. ANATOP on imx6q. +- nvmem-cells: A phandle to the calibration cells provided by ocotp. +- nvmem-cell-names: Should be "calib", "temp_grade". + +Deprecated properties: +- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON + calibration data, e.g. OCOTP on imx6q. The details about calibration data + can be found in SoC Reference Manual. + +Direct access to OCOTP via fsl,tempmon-data is incorrect on some newer chips +because it does not handle OCOTP clock requirements. + +Optional properties: +- clocks : thermal sensor's clock source. + +Example: +ocotp: ocotp@21bc000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,imx6sx-ocotp", "syscon"; + reg = <0x021bc000 0x4000>; + clocks = <&clks IMX6SX_CLK_OCOTP>; + + tempmon_calib: calib@38 { + reg = <0x38 4>; + }; + + tempmon_temp_grade: temp-grade@20 { + reg = <0x20 4>; + }; +}; + +tempmon: tempmon { + compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon"; + interrupts = ; + fsl,tempmon = <&anatop>; + nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>; + nvmem-cell-names = "calib", "temp_grade"; + clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>; +}; + +Legacy method (Deprecated): +tempmon { + compatible = "fsl,imx6q-tempmon"; + fsl,tempmon = <&anatop>; + fsl,tempmon-data = <&ocotp>; + clocks = <&clks 172>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/kirkwood-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/kirkwood-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c0f5eb86da75d75d34e959adf288798e2fa760e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/kirkwood-thermal.txt @@ -0,0 +1,15 @@ +* Kirkwood Thermal + +This version is for Kirkwood 88F8262 & 88F6283 SoCs. Other kirkwoods +don't contain a thermal sensor. + +Required properties: +- compatible : "marvell,kirkwood-thermal" +- reg : Address range of the thermal registers + +Example: + + thermal@10078 { + compatible = "marvell,kirkwood-thermal"; + reg = <0x10078 0x4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/max77620_thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/max77620_thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..323a3b3822aacfb8236222933ab916df1e58d340 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/max77620_thermal.txt @@ -0,0 +1,70 @@ +Thermal driver for MAX77620 Power management IC from Maxim Semiconductor. + +Maxim Semiconductor MAX77620 supports alarm interrupts when its +die temperature crosses 120C and 140C. These threshold temperatures +are not configurable. Device does not provide the real temperature +of die other than just indicating whether temperature is above or +below threshold level. + +Required properties: +------------------- +#thermal-sensor-cells: Please refer + for more details. + The value must be 0. + +For more details, please refer generic thermal DT binding document +. + +Please refer for mfd DT binding +document for the MAX77620. + +Example: +-------- +#include +#include +... + +i2c@7000d000 { + spmic: max77620@3c { + compatible = "maxim,max77620"; + ::::: + #thermal-sensor-cells = <0>; + ::: + }; +}; + +cool_dev: cool-dev { + compatible = "cooling-dev"; + #cooling-cells = <2>; +}; + +thermal-zones { + PMIC-Die { + polling-delay = <0>; + polling-delay-passive = <0>; + thermal-sensors = <&spmic>; + + trips { + pmic_die_warn_temp_thresh: hot-die { + temperature = <120000>; + type = "hot"; + hysteresis = <0>; + }; + + pmic_die_cirt_temp_thresh: cirtical-die { + temperature = <140000>; + type = "critical"; + hysteresis = <0>; + }; + }; + + cooling-maps { + map0 { + trip = <&pmic_die_warn_temp_thresh>; + cooling-device = <&cool_dev THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + contribution = <100>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/mediatek-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/mediatek-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..41d6a443ad660a1e969e765b19ec253e5f04530d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/mediatek-thermal.txt @@ -0,0 +1,47 @@ +* Mediatek Thermal + +This describes the device tree binding for the Mediatek thermal controller +which measures the on-SoC temperatures. This device does not have its own ADC, +instead it directly controls the AUXADC via AHB bus accesses. For this reason +this device needs phandles to the AUXADC. Also it controls a mux in the +apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS +is also needed. + +Required properties: +- compatible: + - "mediatek,mt8173-thermal" : For MT8173 family of SoCs + - "mediatek,mt2701-thermal" : For MT2701 family of SoCs + - "mediatek,mt2712-thermal" : For MT2712 family of SoCs + - "mediatek,mt7622-thermal" : For MT7622 SoC +- reg: Address range of the thermal controller +- interrupts: IRQ for the thermal controller +- clocks, clock-names: Clocks needed for the thermal controller. required + clocks are: + "therm": Main clock needed for register access + "auxadc": The AUXADC clock +- resets: Reference to the reset controller controlling the thermal controller. +- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses +- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller. +- #thermal-sensor-cells : Should be 0. See ./thermal.txt for a description. + +Optional properties: +- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If + unspecified default values shall be used. +- nvmem-cell-names: Should be "calibration-data" + +Example: + + thermal: thermal@1100b000 { + #thermal-sensor-cells = <1>; + compatible = "mediatek,mt8173-thermal"; + reg = <0 0x1100b000 0 0x1000>; + interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>; + clock-names = "therm", "auxadc"; + resets = <&pericfg MT8173_PERI_THERM_SW_RST>; + reset-names = "therm"; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration_data>; + nvmem-cell-names = "calibration-data"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/nvidia,tegra124-soctherm.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/nvidia,tegra124-soctherm.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6c0ae53d4dca345f3b751df5b39217497d075fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/nvidia,tegra124-soctherm.txt @@ -0,0 +1,184 @@ +Tegra124 SOCTHERM thermal management system + +The SOCTHERM IP block contains thermal sensors, support for polled +or interrupt-based thermal monitoring, CPU and GPU throttling based +on temperature trip points, and handling external overcurrent +notifications. It is also used to manage emergency shutdown in an +overheating situation. + +Required properties : +- compatible : For Tegra124, must contain "nvidia,tegra124-soctherm". + For Tegra132, must contain "nvidia,tegra132-soctherm". + For Tegra210, must contain "nvidia,tegra210-soctherm". +- reg : Should contain at least 2 entries for each entry in reg-names: + - SOCTHERM register set + - Tegra CAR register set: Required for Tegra124 and Tegra210. + - CCROC register set: Required for Tegra132. +- reg-names : Should contain at least 2 entries: + - soctherm-reg + - car-reg + - ccroc-reg +- interrupts : Defines the interrupt used by SOCTHERM +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - tsensor + - soctherm +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - soctherm +- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description + of this property. See for a + list of valid values when referring to thermal sensors. +- throttle-cfgs: A sub-node which is a container of configuration for each + hardware throttle events. These events can be set as cooling devices. + * throttle events: Sub-nodes must be named as "light" or "heavy". + Properties: + - nvidia,priority: Each throttles has its own throttle settings, so the + SW need to set priorities for various throttle, the HW arbiter can select + the final throttle settings. + Bigger value indicates higher priority, In general, higher priority + translates to lower target frequency. SW needs to ensure that critical + thermal alarms are given higher priority, and ensure that there is + no race if priority of two vectors is set to the same value. + The range of this value is 1~100. + - nvidia,cpu-throt-percent: This property is for Tegra124 and Tegra210. + It is the throttling depth of pulse skippers, it's the percentage + throttling. + - nvidia,cpu-throt-level: This property is only for Tegra132, it is the + level of pulse skippers, which used to throttle clock frequencies. It + indicates cpu clock throttling depth, and the depth can be programmed. + Must set as following values: + TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED + TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE + - #cooling-cells: Should be 1. This cooling device only support on/off state. + See ./thermal.txt for a description of this property. + +Note: +- the "critical" type trip points will be set to SOC_THERM hardware as the +shut down temperature. Once the temperature of this thermal zone is higher +than it, the system will be shutdown or reset by hardware. +- the "hot" type trip points will be set to SOC_THERM hardware as the throttle +temperature. Once the the temperature of this thermal zone is higher +than it, it will trigger the HW throttle event. + +Example : + + soctherm@700e2000 { + compatible = "nvidia,tegra124-soctherm"; + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */ + 0x0 0x60006000 0x0 0x400 /* CAR reg_base */ + reg-names = "soctherm-reg", "car-reg"; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_TSENSOR>, + <&tegra_car TEGRA124_CLK_SOC_THERM>; + clock-names = "tsensor", "soctherm"; + resets = <&tegra_car 78>; + reset-names = "soctherm"; + + #thermal-sensor-cells = <1>; + + throttle-cfgs { + /* + * When the "heavy" cooling device triggered, + * the HW will skip cpu clock's pulse in 85% depth + */ + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-percent = <85>; + + #cooling-cells = <1>; + }; + + /* + * When the "light" cooling device triggered, + * the HW will skip cpu clock's pulse in 50% depth + */ + throttle_light: light { + nvidia,priority = <80>; + nvidia,cpu-throt-percent = <50>; + + #cooling-cells = <1>; + }; + + /* + * If these two devices are triggered in same time, the HW throttle + * arbiter will select the highest priority as the final throttle + * settings to skip cpu pulse. + */ + }; + }; + +Example: referring to Tegra132's "reg", "reg-names" and "throttle-cfgs" : + + soctherm@700e2000 { + compatible = "nvidia,tegra132-soctherm"; + reg = <0x0 0x700e2000 0x0 0x600 /* SOC_THERM reg_base */ + 0x0 0x70040000 0x0 0x200>; /* CCROC reg_base */; + reg-names = "soctherm-reg", "ccroc-reg"; + + throttle-cfgs { + /* + * When the "heavy" cooling device triggered, + * the HW will skip cpu clock's pulse in HIGH level + */ + throttle_heavy: heavy { + nvidia,priority = <100>; + nvidia,cpu-throt-level = ; + + #cooling-cells = <1>; + }; + + /* + * When the "light" cooling device triggered, + * the HW will skip cpu clock's pulse in MED level + */ + throttle_light: light { + nvidia,priority = <80>; + nvidia,cpu-throt-level = ; + + #cooling-cells = <1>; + }; + + /* + * If these two devices are triggered in same time, the HW throttle + * arbiter will select the highest priority as the final throttle + * settings to skip cpu pulse. + */ + + }; + }; + +Example: referring to thermal sensors : + + thermal-zones { + cpu { + polling-delay-passive = <1000>; + polling-delay = <1000>; + + thermal-sensors = + <&soctherm TEGRA124_SOCTHERM_SENSOR_CPU>; + + trips { + cpu_shutdown_trip: shutdown-trip { + temperature = <102500>; + hysteresis = <1000>; + type = "critical"; + }; + + cpu_throttle_trip: throttle-trip { + temperature = <100000>; + hysteresis = <1000>; + type = "hot"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_throttle_trip>; + cooling-device = <&throttle_heavy 1 1>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..276387dd6815e334ae7d6a9e7d05f1509efd8f5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/nvidia,tegra186-bpmp-thermal.txt @@ -0,0 +1,32 @@ +NVIDIA Tegra186 BPMP thermal sensor + +In Tegra186, the BPMP (Boot and Power Management Processor) implements an +interface that is used to read system temperatures, including CPU cluster +and GPU temperatures. This binding describes the thermal sensor that is +exposed by BPMP. + +The BPMP thermal node must be located directly inside the main BPMP node. See +../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding. + +This node represents a thermal sensor. See thermal.txt for details of the +core thermal binding. + +Required properties: +- compatible: + Array of strings. + One of: + - "nvidia,tegra186-bpmp-thermal". +- #thermal-sensor-cells: Cell for sensor index. + Single-cell integer. + Must be <1>. + +Example: + +bpmp { + ... + + bpmp_thermal: thermal { + compatible = "nvidia,tegra186-bpmp-thermal"; + #thermal-sensor-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/oneplus-shell-temp.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/oneplus-shell-temp.txt new file mode 100644 index 0000000000000000000000000000000000000000..a61aed64c1dca5caf3d79bde573d79c6befba797 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/oneplus-shell-temp.txt @@ -0,0 +1,9 @@ +=============================================================================== +Shell Temperature Fitting driver: +=============================================================================== + +Temperature fitting for the front, frame, and back of devices + +Required Parameters: +- compatible: must be 'oneplus,shell-temp' for shell-temp driver. + diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom,cx-ipeak-cdev.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom,cx-ipeak-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..562cc6e5f5d36ad91fe9ecbdd1e7969731513ab6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom,cx-ipeak-cdev.txt @@ -0,0 +1,53 @@ +Qualcomm Technologies, Inc. CX Peak current cooling device + +The CX IPEAK cooling device, will be used to set thermal client vote to +CX IPEAK LM hardware. When all pre-defined clients on CX rail including +thermal client set their vote, CXIP LM hardware throttles pre-defined +client on the same rail. + +Required Parameters: +- compatible: + Usage: required + Value type: + Definition: should be "qcom,cxip-lm-cooling-device" + +- reg: + Usage: required + Value type: + Definition: Must contain 2 variables where 'a' is the starting + register address of the CX IPEAK LM hardware and 'b' is the + size of the peripheral address space. + +- qcom,thermal-client-offset: + Usage: Optional + Value type: + Definition: This property is required for CX IP LM v1.1 and above + hardware. Must contain offset from CX IPEAK LM reg + base for thermal client voting. If this property is not defined, + then CX IPEAK cooling device will use legacy CXIP LM hardware + offset registers. + +- qcom,bypass-client-list: + Usage: Optional + Value type: + Definition: This property is required for CX IP LM v1.1 and above + hardware. Must contain array of offsets from CX IPEAK LM reg + base for clients those are not participating voting to CXIP LM + hardware. This property makes sense only when thermal-client + is defined. + +- #cooling-cells: + Usage: required + Value type: + Definition: Must be 2. This is required by of-thermal and refer the doc + for more details. + +Example: + + cxip_cdev: cxip-cdev@1fed000 { + compatible = "qcom,cxip-lm-cooling-device"; + reg = <0x1fed000 0x24>; + qcom,thermal-client-offset = <0x8000>; + qcom,bypass-client-list = <0x2004 0x3004>; + #cooling-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-adc-tm.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-adc-tm.txt new file mode 100644 index 0000000000000000000000000000000000000000..46870d830883b30d6134bb3065b1d6620653a1e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-adc-tm.txt @@ -0,0 +1,186 @@ +Qualcomm Technologies, Inc. PMIC thermal monitor ADC driver (ADC_TM) + +PMIC thermal monitoring (TM) provides interface to thermal clients +to set temperature thresholds and receive notification when the thresholds +are crossed. A 16 bit ADC is used for measurements. The driver is part +of the sysfs thermal framework that provides support to read the trip +points, set threshold for the trip points and enable the trip points. + +ADC_TM node + +- compatible: + Usage: required + Value type: + Definition: Should contain "qcom,adc-tm5" or "qcom,adc-tm5-iio" for PMIC5 ADC TM device. + Should contain "qcom,adc-tm7" or "qcom,adc-tm5-iio" for PMIC7 ADC TM device. + Should contain "qcom,adc-tm-rev2" for PMIC refresh ADC_TM device + +- reg: + Usage: required + Value type: + Definition: ADC_TM base address in the SPMI PMIC register map. + +- #address-cells: + Usage: required + Value type: + Definition: Must be one. Child node 'reg' property should define ADC + channel number. + +- #size-cells: + Usage: required + Value type: + Definition: Must be zero. + +- interrupts: + Usage: required + Value type: + Definition: Threshold violation interrupt. + +- interrupt-names: + Usage: required + Value type: + Definition: Should contain "thr-int-en" for PMIC5 ADC TM driver. + +- qcom,decimation: + Usage: optional + Value type: + Definition: This parameter is used to decrease ADC sampling rate. + Quicker measurements can be made by reducing decimation ratio. + For PMIC5 ADC, combined two step decimation values are 250, 420 and 840. + If property is not found, default value of 840 will be used. + +- qcom,avg-samples: + Usage: optional + Value type: + Definition: Number of samples to be used for measurement. + Averaging provides the option to obtain a single measurement + from the ADC that is an average of multiple samples. The value + selected is 2^(value). + Valid values are: 1, 2, 4, 8, 16 + If property is not found, 1 sample will be used. + +- #thermal-sensor-cells: + Usage: optional + Value type: + Definition: Should be 1. See thermal.txt for a description. + +- io-channels: + Usage: Required + Value type: + Definition: The phandle of the iio provider. + +Channel node properties: + +- reg: + Usage: required + Value type: + Definition: For PMIC5, ADC channel number. + See include/dt-bindings/iio/qcom,spmi-vadc.h + For PMIC7, ADC virtual channel number, made by combining SID of + PMIC having the channel and actual ADC channel number. + See files in include/dt-bindings/iio/. + +- qcom,pre-scaling: + Usage: optional + Value type: + Definition: Used for scaling the channel input signal before the signal is + fed to VADC. The configuration for this node is to know the + pre-determined ratio and use it for post scaling. Select one from + the following options. + <1 1>, <1 3>, <1 4>, <1 6>, <1 20>, <1 8>, <10 81>, <1 10> + If property is not found default value depending on chip will be used. + +- qcom,decimation: + Usage: optional, used as channel property only for PMIC7 + Value type: + Definition: This parameter is used to decrease ADC sampling rate. + Quicker measurements can be made by reducing decimation ratio. + For PMIC7 ADC, combined two step decimation values are 85, 340 and 1360. + If property is not found, default value of 1360 will be used. + +- qcom,avg-samples: + Usage: optional, used as channel property only for PMIC7 + Value type: + Definition: Number of samples to be used for measurement. + Averaging provides the option to obtain a single measurement + from the ADC that is an average of multiple samples. + Valid values are: 1, 2, 4, 8, 16 + If property is not found, 1 sample will be used. + +- qcom,kernel-client: + Usage: optional + Value type: + Definition: Used to indicate if the client for this channel is not the + thermal framework. Non-thermal clients use a different set of + APIs to configure their channels. In addition, the reverse scaling function + needs to be specified for them. If property is not found, channel will be + considered as thermal by default. + +- qcom,scale-type: + Usage: optional + Value type: + Definition: Reverse scaling function used to convert raw ADC code to units + specific to a given channel. + Select from the following unsigned int. + 0 : Scaling to convert voltage in uV to raw adc code. + +- qcom,ratiometric: + Usage: optional + Value type: + Definition: Channel calibration type. If this property is specified + VADC will use the VDD reference (1.875V) and GND for channel + calibration. If property is not found, channel will be + calibrated with 0V and 1.25V reference channels, also + known as absolute calibration. + +- qcom,hw-settle-time: + Usage: optional + Value type: + Definition: Time between AMUX getting configured and the ADC starting + conversion. + For PMIC5, delay = 15us for value 0, + 100us * (value) for values 0 < value < 11, and + 2ms * (value - 10) otherwise. + Valid values are: 15, 100, 200, 300, 400, 500, 600, 700, 1, + 2, 4, 8, 16, 32, 64, 128 ms + For PMIC7, valid values are: 15, 100, 200, 300, 400, 500, 600, + 700, 1000, 2000, 4000, 8000, 16000, 32000, 64000, 128000 us. + If property is not found, channel will use 15us. + +Example: + + /* ADC_TM node */ + pmic_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pmic_vadc ADC_AMUX_THM2_PU2>; + + /* Channel node */ + skin_msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + }; + + /* Adding thermal zone to register with of_thermal */ + &thermal_zones { + wp-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pmic_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl-pmic5.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl-pmic5.txt new file mode 100644 index 0000000000000000000000000000000000000000..8e5ba1b7e9140e6f667066d499d5c1b7f11c5168 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl-pmic5.txt @@ -0,0 +1,48 @@ +=============================================================================== +BCL Peripheral driver for PMIC5: +=============================================================================== +Qualcomm Technologies, Inc's PMIC has battery current limiting peripheral, +which can monitor for high battery current and low battery voltage in the +hardware. The BCL peripheral driver interacts with the PMIC peripheral using +the SPMI driver interface. The hardware can take threshold for notifying for +high battery current or low battery voltage events. This driver works only +with PMIC version 5, where the same BCL peripheral can be found in multiple +PMIC's that are used in a device, with limited functionalities. For example, +one PMIC can have only vbat monitoring, while the other PMIC can have both +vbat and ibat monitoring. This is a common driver, that can interact +with the multiple BCL peripherals. + +Required Parameters: +- compatible: must be + 'qcom,bcl-v5' for bcl peripheral in PMIC version 5. +- reg: where 'a' is the starting register address of the PMIC + peripheral and 'b' is the size of the peripheral address space. +- interrupts: Where, + 'a' is the SLAVE ID of the PMIC, + 'b' is the peripheral ID, + 'c' is the interrupt number in PMIC and + 'd' is the interrupt type. +- interrupt-names: user defined names for the interrupts. These + interrupt names will be used by the drivers to identify the + interrupts, instead of specifying the ID's. bcl driver will + accept these standard interrupts. + "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2", + +Optional Parameters: +- qcom,ibat-use-qg-adc-5a: This optional property is used to divide Ibat + scaling factor by two for PMIC QG_ADC with ibat range of 5A. + By default, this Ibat scaling factor will be 1 corresponding + to FG_ADC with 10A range. + +Example: + bcl@4200 { + compatible = "qcom,bcl-v5"; + reg = <0x4200 0x100>; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>, + <0x2 0x42 0x1 IRQ_TYPE_NONE>; + interrupt-names = "bcl-lvl0", + "bcl-lvl1"; + qcom,ibat-use-qg-adc-5a; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl-soc.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl-soc.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ea7d330b2eb2c58c7a68db99f1f7ef46074460c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl-soc.txt @@ -0,0 +1,14 @@ +=============================================================================== +PMIC state of charge driver: +=============================================================================== +Battery state of charge driver can monitor for change in battery charge and +notify thermal framework, when the value goes below a certain threshold. + +Required Parameters: +- compatible: must be 'qcom,msm-bcl-soc' for battery state of charge driver. + +Optional Parameters: + + bcl-soc { + compatible = "qcom,msm-bcl-soc"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl.txt new file mode 100644 index 0000000000000000000000000000000000000000..449cbadcdbe70bb5875d878e41d9ced3c5a89fc8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-bcl.txt @@ -0,0 +1,44 @@ +=============================================================================== +BCL PMIC Peripheral driver: +=============================================================================== +Qualcomm Technologies, Inc's PMIC has battery current limiting peripheral, which can monitor for +high battery current and low battery voltage in the hardware. The BCL +peripheral driver interacts with the PMIC peripheral using the SPMI driver +interface. The hardware can take threshold for notifying for high battery +current or low battery voltage events. + +Required Parameters: +- compatible: must be + 'qcom,msm-bcl-lmh' for bcl peripheral with LMH DCVSh interface. +- reg: where 'a' is the starting register address of the PMIC + peripheral and 'b' is the size of the peripheral address space. + If the BCL inhibit current derating feature is enabled, this must also + have the PON spare registers as well. Example: where + c is the first PON spare register that will be written and d is the + size of the registers space needed to be written. Certain version + of PMIC, can send interrupt to LMH hardware driver directly. In that + case the shadow peripheral address space should be mentioned along + with the bcl peripherals address. +- interrupts: Where 'a' is the SLAVE ID of the PMIC, 'b' is + the peripheral ID and 'c' is the interrupt number in PMIC. +- interrupt-names: user defined names for the interrupts. These + interrupt names will be used by the drivers to identify the + interrupts, instead of specifying the ID's. bcl driver will + accept these five standard interrupts. + "bcl-low-vbat" + "bcl-very-low-vbat" + "bcl-crit-low-vbat" + "bcl-high-ibat" + "bcl-very-high-ibat" + + +Optional Parameters: + + bcl@4200 { + compatible = "qcom,msm-bcl"; + reg = <0x4200 0xFF 0x88e 0x2>; + interrupts = <0x2 0x42 0x0>, + <0x2 0x42 0x1>; + interrupt-names = "bcl-high-ibat-int", + "bcl-low-vbat-int"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-lmh-dcvs.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-lmh-dcvs.txt new file mode 100644 index 0000000000000000000000000000000000000000..07309c14c20fa55dad231d6a4200409072369132 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-lmh-dcvs.txt @@ -0,0 +1,85 @@ +Limits Management Hardware - DCVS + +The LMH-DCVS block is a hardware IP for every CPU cluster, to handle quick +changes in thermal limits. The hardware responds to thermal variation amongst +the CPUs in the cluster by requesting limits on the clock frequency and +voltage on the OSM hardware. + +The LMH DCVS driver exports a virtual sensor that can be used to set the +thermal limits on the hardware. LMH DCVS driver can be a platform CPU Cooling +device, which registers with the CPU cooling device interface. All CPU device +nodes should reference the corresponding LMH DCVS hardware in device tree. +CPUs referencing the same LMH DCVS node will be associated with the +corresponding cooling device as related CPUs. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: shall be "qcom,msm-hw-limits" +- interrupts: + Usage: optional + Value type: + Definition: Should specify interrupt information about the debug + interrupt generated by the LMH DCVSh hardware. LMH + DCVSh hardware will generate this interrupt whenever + it makes a new cpu DCVS decision. +- qcom,affinity: + Usage: optional + Value type: + Definition: Should specify the cluster affinity this hardware + corresponds to. + +- isens_vref_1p8-supply: +- isens_vref_0p8-supply: + Usage: optional + Value type: + Definition: Should specify the phandle of the vref regulator used by + the isens hardware. This active only regulator will be + enabled by LMH DCVSh. Isens hardware needs 1.8v and + 0.8v supply regulators. + +- isens-vref-1p8-settings: +- isens-vref-0p8-settings: + Usage: optional + Value type: + Definition: Should specify the min voltage(uV), max voltage(uV) and + max load(uA) for the isens vref regulator. This + property is valid only if there is valid entry for + isens_vref_1p8-supply and isens_vref_0p8-supply. + +- reg: + Usage: optional + Value type: + Definition: where 'a' is the starting register address of the OSM/LLM + and 'b' is the size of OSM/LLM address space. The + register space in index 0 should be LLM and index 1 + should be OSM. + +- qcom,no-cooling-device-register: + Usage: optional + Value type: + Definition: Should define this property if this driver doesn't need + to register CPU cooling devices with thermal framework. + +Example: + + lmh_dcvs0: qcom,limits-dcvs@18350800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + isens_vref_1p8-supply = <&pm8998_l1_ao>; + isens-vref-1p8-settings = <880000 880000 36000>; + isens_vref_0p8-supply = <&pm8998_l12_ao>; + isens-vref-0p8-settings = <880000 880000 36000>; + reg = <0x18350800 0x1000>, //LLM + <0x18323000 0x1000>; //OSM + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + qcom,lmh-dcvs = <&lmh_dcvs0>;; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-spmi-temp-alarm.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-spmi-temp-alarm.txt new file mode 100644 index 0000000000000000000000000000000000000000..7307aed4e0f048fc4f9673d42d6541be7acd441e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-spmi-temp-alarm.txt @@ -0,0 +1,72 @@ +Qualcomm QPNP PMIC Temperature Alarm + +QPNP temperature alarm peripherals are found inside of Qualcomm PMIC chips +that utilize the Qualcomm SPMI implementation. These peripherals provide an +interrupt signal and status register to identify high PMIC die temperature. + +Required properties: +- compatible: Should contain "qcom,spmi-temp-alarm". +- reg: Specifies the SPMI address and length of the controller's + registers. +- interrupts: PMIC temperature alarm interrupt. +- #thermal-sensor-cells: Should be 0. See thermal.txt for a description. + +Optional properties: +- io-channels: Should contain IIO channel specifier for the ADC channel, + which report chip die temperature. +- io-channel-names: Should contain "thermal". +- qcom,temperature-threshold-set: Defines the temperature threshold set to + configure. Supported values are 0 to 3. Each set defines + the over-temperature stage 1, 2, and 3 temperature + thresholds. If this property is not specified, then set 0 + will be used by default. + Threshold set mapping (TEMP_GEN1, TEMP_GEN2 rev 0): + 0 = {105 C, 125 C, 145 C} + 1 = {110 C, 130 C, 150 C} + 2 = {115 C, 135 C, 155 C} + 3 = {120 C, 140 C, 160 C} + Threshold set mapping (TEMP_GEN2 rev 1 and above): + 0 = { 90 C, 110 C, 140 C} + 1 = { 95 C, 115 C, 145 C} + 2 = {100 C, 120 C, 150 C} + 3 = {105 C, 125 C, 155 C} + +Example: + + pm8941_temp: thermal-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + + io-channels = <&pm8941_vadc VADC_DIE_TEMP>; + io-channel-names = "thermal"; + }; + + thermal-zones { + pm8941 { + polling-delay-passive = <250>; + polling-delay = <1000>; + + thermal-sensors = <&pm8941_temp>; + + trips { + passive { + temperature = <1050000>; + hysteresis = <2000>; + type = "passive"; + }; + alert { + temperature = <125000>; + hysteresis = <2000>; + type = "hot"; + }; + crit { + temperature = <145000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-tsens.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-tsens.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d9e8cf6101819244d2e59ebf79bd6db43d46f8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qcom-tsens.txt @@ -0,0 +1,41 @@ +* QCOM SoC Temperature Sensor (TSENS) + +Required properties: +- compatible: + Must be one of the following: + - "qcom,msm8916-tsens" (MSM8916) + - "qcom,msm8974-tsens" (MSM8974) + - "qcom,msm8996-tsens" (MSM8996) + - "qcom,msm8998-tsens", "qcom,tsens-v2" (MSM8998) + - "qcom,sdm845-tsens", "qcom,tsens-v2" (SDM845) + The generic "qcom,tsens-v2" property must be used as a fallback for any SoC + with version 2 of the TSENS IP. MSM8996 is the only exception because the + generic property did not exist when support was added. + +- reg: Address range of the thermal registers. + New platforms containing v2.x.y of the TSENS IP must specify the SROT and TM + register spaces separately, with order being TM before SROT. + See Example 2, below. + +- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. +- #qcom,sensors: Number of sensors in tsens block +- Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify +nvmem cells + +Example 1 (legacy support before a fallback tsens-v2 property was introduced): +tsens: thermal-sensor@900000 { + compatible = "qcom,msm8916-tsens"; + reg = <0x4a8000 0x2000>; + nvmem-cells = <&tsens_caldata>, <&tsens_calsel>; + nvmem-cell-names = "caldata", "calsel"; + #thermal-sensor-cells = <1>; + }; + +Example 2 (for any platform containing v2 of the TSENS IP): +tsens0: thermal-sensor@c263000 { + compatible = "qcom,sdm845-tsens", "qcom,tsens-v2"; + reg = <0xc263000 0x1ff>, /* TM */ + <0xc222000 0x1ff>; /* SROT */ + #qcom,sensors = <13>; + #thermal-sensor-cells = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qoriq-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qoriq-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..20ca4ef9d77609a0bc0432256c70694e0ac1cbac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qoriq-thermal.txt @@ -0,0 +1,70 @@ +* Thermal Monitoring Unit (TMU) on Freescale QorIQ SoCs + +Required properties: +- compatible : Must include "fsl,qoriq-tmu". The version of the device is + determined by the TMU IP Block Revision Register (IPBRR0) at + offset 0x0BF8. + Table of correspondences between IPBRR0 values and example chips: + Value Device + ---------- ----- + 0x01900102 T1040 +- reg : Address range of TMU registers. +- interrupts : Contains the interrupt for TMU. +- fsl,tmu-range : The values to be programmed into TTRnCR, as specified by + the SoC reference manual. The first cell is TTR0CR, the second is + TTR1CR, etc. +- fsl,tmu-calibration : A list of cell pairs containing temperature + calibration data, as specified by the SoC reference manual. + The first cell of each pair is the value to be written to TTCFGR, + and the second is the value to be written to TSCFGR. +- #thermal-sensor-cells : Must be 1. The sensor specifier is the monitoring + site ID, and represents the "n" in TRITSRn and TRATSRn. + +Optional property: +- little-endian : If present, the TMU registers are little endian. If absent, + the default is big endian. + +Example: + +tmu@f0000 { + compatible = "fsl,qoriq-tmu"; + reg = <0xf0000 0x1000>; + interrupts = <18 2 0 0>; + fsl,tmu-range = <0x000a0000 0x00090026 0x0008004a 0x0001006a>; + fsl,tmu-calibration = <0x00000000 0x00000025 + 0x00000001 0x00000028 + 0x00000002 0x0000002d + 0x00000003 0x00000031 + 0x00000004 0x00000036 + 0x00000005 0x0000003a + 0x00000006 0x00000040 + 0x00000007 0x00000044 + 0x00000008 0x0000004a + 0x00000009 0x0000004f + 0x0000000a 0x00000054 + + 0x00010000 0x0000000d + 0x00010001 0x00000013 + 0x00010002 0x00000019 + 0x00010003 0x0000001f + 0x00010004 0x00000025 + 0x00010005 0x0000002d + 0x00010006 0x00000033 + 0x00010007 0x00000043 + 0x00010008 0x0000004b + 0x00010009 0x00000053 + + 0x00020000 0x00000010 + 0x00020001 0x00000017 + 0x00020002 0x0000001f + 0x00020003 0x00000029 + 0x00020004 0x00000031 + 0x00020005 0x0000003c + 0x00020006 0x00000042 + 0x00020007 0x0000004d + 0x00020008 0x00000056 + + 0x00030000 0x00000012 + 0x00030001 0x0000001d>; + #thermal-sensor-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qti-cpu-isolation-cdev.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-cpu-isolation-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..9d1852620e4050df47603da944320de1c7efb1de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-cpu-isolation-cdev.txt @@ -0,0 +1,50 @@ +QTI CPU isolation cooling devices. + +The CPU isolation cooling device will be used for isolating a CPU on a thermal +condition. This cooling device driver can register one cooling device per CPU, +which can be used by thermal zone to mitigate. + +Each child node will represent a cooling device and the child node should +point to the CPU, which will be mitigated by that cooling device instance. + +Properties: +- compatible: + Usage: required + Value type: + Definition: should be "qcom,cpu-isolate" + +Cooling device node: +- qcom,cpu: + Usage: required + Value type: + Definition: phandle to the CPU device that this cooling device will + mitigate. + +-#cooling-cells: + Usage: required + Value type: + Definition: Must be 2. Needed for of_thermal as cooling device + identifier. Please refer to + for more + details. +Example: + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qti-isense-cdsp.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-isense-cdsp.txt new file mode 100644 index 0000000000000000000000000000000000000000..587c03920cdc9f07f6dffd7751f6f34ed3e8db30 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-isense-cdsp.txt @@ -0,0 +1,14 @@ +=============================================================================== +QTI Limits cdsp isense driver: +=============================================================================== +Limits cdsp isense driver reads cdsp isense calibration data from shared memory +and enables sysfs file support to access the data read from shared memory. + +Required Parameters: +- compatible: must be 'qcom,msm-limits-cdsp' for limits cdsp isense driver. + +Optional Parameters: + + lmh_isense_cdsp { + compatible = "qcom,msm-limits-cdsp"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qti-lmh-cpu-vdd-cdev.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-lmh-cpu-vdd-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..40bf2a14b8be8fd71922907c26ce12934d0bd161 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-lmh-cpu-vdd-cdev.txt @@ -0,0 +1,33 @@ +QTI LMH CPU Voltage cooling devices. + +The LMH CPU voltage cooling device will be used to place voltage restriction +vote on CPU railway during cold thermal condition. This cooling device driver +will register one cooling device per LLM, which can be used by thermal zone to +place voltage restriction vote. + +Properties: +- compatible: + Usage: required + Value type: + Definition: should be "qcom,lmh-cpu-vdd" + +Cooling device node: +- reg: + Usage: Required + Value type: + Definition: where 'a' is the starting register address of the LLM + and 'b' is the size of LLM address space. + +- #cooling-cells: + Usage: required + Value type: + Definition: Must be 2. Needed for of_thermal as cooling device + identifier. Please refer to + for more + details. +Example: + lmh_cpu_vdd0: qcom,lmh-cpu-vdd@18350800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0x18350800 0x1000>; + #cooling-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qti-qmi-cdev.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-qmi-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..aeff953af9a9e486f46a2087928d4a167694cdd6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-qmi-cdev.txt @@ -0,0 +1,137 @@ +QMI thermal mitigation(TMD) cooling devices. + +The QMI TMD cooling device, will be used for various mitigations for remote +subsystem including remote processor mitigation, rail voltage restriction etc. +This cooling device uses kernel qti QMI interface to send the message to +remote subsystem. + +Each child node of the QMI TMD devicetree node represents each remote +subsystem and each child of this subsystem represents separate cooling +devices. It requires minimum one remote subsystem node and each subsystem +node requires minimum one cooling device node. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: should be "qcom,qmi-cooling-devices" + + +Subsystem properties: +- qcom,instance-id: + Usage: required + Value type: + Definition: Remote subsystem QMI server instance id to be used for + communicating with QMI. + + Minimum one child node is required. Child node name and its alias are + used as cooling device name and phandle for that cooling device. + + cooling device node properties: + -qcom,qmi-dev-name: + Usage: required + Value type: + Definition: Remote subsystem device identifier. Below strings + are the only acceptable device names, + "pa" -> for pa cooling device, + "pa_fr1" -> for pa cooling device, + "cpuv_restriction_cold" -> for vdd restriction, + "cx_vdd_limit" -> for vdd limit, + "modem" -> for processor passive cooling device, + "modem_current" -> for current limiting device, + "modem_bw" -> for bus bandwidth limiting device, + "vbatt_low" -> BCL vbat mitigation device, + "mmw0" -> Millimeter wave limiting device 0, + "mmw1" -> Millimeter wave limiting device 1, + "mmw2" -> Millimeter wave limiting device 2, + "mmw3" -> Millimeter wave limiting device 3, + "modem_skin" -> Modem skin mitigation device, + "mmw_skin0" -> MMW skin mitigation device0, + "mmw_skin1" -> MMW skin mitigation device1, + "mmw_skin2" -> MMW skin mitigation device2, + "mmw_skin3" -> MMW skin mitigation device3, + "cpr_cold" -> for cpr restriction. + "wlan" -> for modem wlan mitigation device. + "cdsp_sw" -> for CDSP DCVS mitigation device. + "cdsp_hw" -> for CDSP hardware mitigation device. + + -#cooling-cells: + Usage: required + Value type: + Definition: Must be 2. Needed for of_thermal as cooling device + identifier. Please refer to + for more + details. +Example: + + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_cpr_cold: modem_cpr_cold { + qcom,qmi-dev-name = "cpr_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + + cdsp_sw: cdsp { + qcom,qmi-dev-name = "cdsp_sw"; + #cooling-cells = <2>; + }; + + cdsp_hw: hvx { + qcom,qmi-dev-name = "cdsp_hw"; + #cooling-cells = <2>; + }; + }; + + slpi { + qcom,instance-id = <0x53>; + + slpi_vdd: slpi_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qti-qmi-sensor.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-qmi-sensor.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c45319aa1e5c046ed8c825890b7b2db76145d02 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-qmi-sensor.txt @@ -0,0 +1,77 @@ +QMI thermal mitigation(TS) sensor. + +The QMI TS Sensor driver can list the sensors that are available in the +remote subsystem. This driver can read the temperature, set threshold and +get threshold notification. + +Each child node of the QMI TS devicetree node represents a remote +subsystem and it can have more than one remote sensor names. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: should be "qcom,qmi-sensors" + +- #thermal-sensor-cells: + Usage: required + Value type: + Definition: Must be 1. See thermal.txt for description. + +Subsystem properties: +- qcom,instance-id: + Usage: required + Value type: + Definition: Remote subsystem QMI server instance id to be used for + communicating with QMI. + +- qcom,qmi-sensor-names: + Usage: required + Value type: + Definition: Remote sensor names. Below strings + are the only acceptable sensor names, + 1. pa + 2. pa_1 + 3. pa_2 + 4. qfe_pa0 + 5. qfe_wtr0 + 6. modem_tsens + 7. qfe_mmw0 + 8. qfe_mmw1 + 9. qfe_mmw2 + 10. qfe_mmw3 + 11. xo_therm + 12. qfe_pa_mdm + 13. qfe_pa_wtr + 14. qfe_mmw_streamer0 + 15. qfe_mmw0_mod + 16. qfe_mmw1_mod + 17. qfe_mmw2_mod + 18. qfe_mmw3_mod + 19. qfe_ret_pa0 + 20. qfe_wtr_pa0 + 21. qfe_wtr_pa1 + 22. qfe_wtr_pa2 + 23. qfe_wtr_pa3 + 24. sys_therm1 + 25. sys_therm2 + 26. modem_tsens1 + 27. BEAMER_W_THERM + 28. BEAMER_N_THERM + 29. BEAMER_E_THERM + +Example: + +qmi_sensor: qmi-ts-sensors { + compatible = "qcom,qmi-sensors"; + #thermal-sensor-cells = <1>; + + modem { + qcom,instance-id = <0x0>; + qcom,qmi-sensor-names = "pa", + "pa_1", + "qfe_pa0", + "qfe_wtr0"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/qti-rpmh-reg-cdev.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-rpmh-reg-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..b7734adc508287a5bd8bb41bf183acf50e1cff56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/qti-rpmh-reg-cdev.txt @@ -0,0 +1,44 @@ +RPMh regulator cooling device. + +The RPMh regulator cooling device, will be used to place a voltage floor +restriction on a rail. This cooling device will use a QMP AOP mail box to send +the message to apply and clear voltage floor restriction. + +The cooling device node should be a child of the regulator devicetree node, +which it is trying to place the floor restriction. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: shall be "qcom,rpmh-reg-cdev" + +- qcom,reg-resource-name: + Usage: required + Value type: + Definition: The regulator resource name to be used for communicating + with RPMh. This value should be any of the below + resource name, + cx -> For CX rail, + mx -> For MX rail, + ebi -> For EBI rail. + +- mboxes: + Usage: required + Value type: + Definition: A phandle to the QMP AOP mail box, that needs to be used + for sending the floor restriction message. + +- #cooling-cells: Must be 2. Please refer to + for more + details. + +Example: + + vdd_cx: rpmh-cx-regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/rcar-gen3-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/rcar-gen3-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..cfa154bb0fa7c7ec5977de4c38c92a7ebd596e7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/rcar-gen3-thermal.txt @@ -0,0 +1,56 @@ +* DT bindings for Renesas R-Car Gen3 Thermal Sensor driver + +On R-Car Gen3 SoCs, the thermal sensor controllers (TSC) control the thermal +sensors (THS) which are the analog circuits for measuring temperature (Tj) +inside the LSI. + +Required properties: +- compatible : "renesas,-thermal", + Examples with soctypes are: + - "renesas,r8a7795-thermal" (R-Car H3) + - "renesas,r8a7796-thermal" (R-Car M3-W) + - "renesas,r8a77965-thermal" (R-Car M3-N) +- reg : Address ranges of the thermal registers. Each sensor + needs one address range. Sorting must be done in + increasing order according to datasheet, i.e. + TSC1, TSC2, ... +- clocks : Must contain a reference to the functional clock. +- #thermal-sensor-cells : must be <1>. + +Optional properties: + +- interrupts : interrupts routed to the TSC (3 for H3, M3-W and M3-N) +- power-domain : Must contain a reference to the power domain. This + property is mandatory if the thermal sensor instance + is part of a controllable power domain. + +Example: + + tsc: thermal@e6198000 { + compatible = "renesas,r8a7795-thermal"; + reg = <0 0xe6198000 0 0x100>, + <0 0xe61a0000 0 0x100>, + <0 0xe61a8000 0 0x100>; + interrupts = , + , + ; + clocks = <&cpg CPG_MOD 522>; + power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; + #thermal-sensor-cells = <1>; + }; + + thermal-zones { + sensor_thermal1: sensor-thermal1 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&tsc 0>; + + trips { + sensor1_crit: sensor1-crit { + temperature = <90000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/rcar-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/rcar-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..67c563f1b4c42131157e8428300c5a12d39bbc2f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/rcar-thermal.txt @@ -0,0 +1,74 @@ +* Renesas R-Car Thermal + +Required properties: +- compatible : "renesas,thermal-", + "renesas,rcar-gen2-thermal" (with thermal-zone) or + "renesas,rcar-thermal" (without thermal-zone) as + fallback except R-Car D3. + Examples with soctypes are: + - "renesas,thermal-r8a73a4" (R-Mobile APE6) + - "renesas,thermal-r8a7743" (RZ/G1M) + - "renesas,thermal-r8a7779" (R-Car H1) + - "renesas,thermal-r8a7790" (R-Car H2) + - "renesas,thermal-r8a7791" (R-Car M2-W) + - "renesas,thermal-r8a7792" (R-Car V2H) + - "renesas,thermal-r8a7793" (R-Car M2-N) + - "renesas,thermal-r8a77995" (R-Car D3) +- reg : Address range of the thermal registers. + The 1st reg will be recognized as common register + if it has "interrupts". + +Option properties: + +- interrupts : If present should contain 3 interrupts for + R-Car D3 or 1 interrupt otherwise. + +Example (non interrupt support): + +thermal@ffc48000 { + compatible = "renesas,thermal-r8a7779", "renesas,rcar-thermal"; + reg = <0xffc48000 0x38>; +}; + +Example (interrupt support): + +thermal@e61f0000 { + compatible = "renesas,thermal-r8a73a4", "renesas,rcar-thermal"; + reg = <0xe61f0000 0x14 + 0xe61f0100 0x38 + 0xe61f0200 0x38 + 0xe61f0300 0x38>; + interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; +}; + +Example (with thermal-zone): + +thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <5000>; + + thermal-sensors = <&thermal>; + + trips { + cpu-crit { + temperature = <115000>; + hysteresis = <0>; + type = "critical"; + }; + }; + cooling-maps { + }; + }; +}; + +thermal: thermal@e61f0000 { + compatible = "renesas,thermal-r8a7790", + "renesas,rcar-gen2-thermal", + "renesas,rcar-thermal"; + reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>; + interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp5_clks R8A7790_CLK_THERMAL>; + power-domains = <&cpg_clocks>; + #thermal-sensor-cells = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/regulator-cdev.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/regulator-cdev.txt new file mode 100644 index 0000000000000000000000000000000000000000..7c9abe2053445599958e04fb3819a58f84fc1500 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/regulator-cdev.txt @@ -0,0 +1,38 @@ +Regulator cooling device. + +The regulator cooling device, will be used to place a voltage floor +restriction on a rail. + +Properties: + +- compatible: + Usage: required + Value type: + Definition: shall be "qcom,regulator-cooling-device" + +- cdev-supply: + Usage: required + Value type: + Definition: phandle to the regulator to which the cooling device will + place a floor mitigation. + +- regulator-levels: + Usage: required + Value type: + Definition: Array of regulator voltages the cooling device should + use to place a floor restriction. The voltages should + be specified in descending order. + +- #cooling-cells: Must be 2. Please refer to + for more + details. + +Example: + + mv_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + cdev-supply = <®ulator-cdev-supply>; + regulator-levels = ; + #cooling-cells = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/rockchip-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/rockchip-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..43d744e5305ef3fd4f1577ec69fd8db41dc2be56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/rockchip-thermal.txt @@ -0,0 +1,84 @@ +* Temperature Sensor ADC (TSADC) on rockchip SoCs + +Required properties: +- compatible : should be "rockchip,-tsadc" + "rockchip,rv1108-tsadc": found on RV1108 SoCs + "rockchip,rk3228-tsadc": found on RK3228 SoCs + "rockchip,rk3288-tsadc": found on RK3288 SoCs + "rockchip,rk3328-tsadc": found on RK3328 SoCs + "rockchip,rk3368-tsadc": found on RK3368 SoCs + "rockchip,rk3399-tsadc": found on RK3399 SoCs +- reg : physical base address of the controller and length of memory mapped + region. +- interrupts : The interrupt number to the cpu. The interrupt specifier format + depends on the interrupt controller. +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Shall be "tsadc" for the converter-clock, and "apb_pclk" for + the peripheral clock. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the name "tsadc-apb". +- pinctrl-names : The pin control state names; +- pinctrl-0 : The "init" pinctrl state, it will be set before device probe. +- pinctrl-1 : The "default" pinctrl state, it will be set after reset the + TSADC controller. +- pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend. +- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description. + +Optional properties: +- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value. +- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO. +- rockchip,hw-tshut-polarity : The hardware-controlled active polarity 0:LOW + 1:HIGH. +- rockchip,grf : The phandle of the syscon node for the general register file. + +Exiample: +tsadc: tsadc@ff280000 { + compatible = "rockchip,rk3288-tsadc"; + reg = <0xff280000 0x100>; + interrupts = ; + clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>; + clock-names = "tsadc", "apb_pclk"; + resets = <&cru SRST_TSADC>; + reset-names = "tsadc-apb"; + pinctrl-names = "init", "default", "sleep"; + pinctrl-0 = <&otp_gpio>; + pinctrl-1 = <&otp_out>; + pinctrl-2 = <&otp_gpio>; + #thermal-sensor-cells = <1>; + rockchip,hw-tshut-temp = <95000>; + rockchip,hw-tshut-mode = <0>; + rockchip,hw-tshut-polarity = <0>; +}; + +Example: referring to thermal sensors: +thermal-zones { + cpu_thermal: cpu_thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <5000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&tsadc 1>; + + trips { + cpu_alert0: cpu_alert { + temperature = <70000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu_crit: cpu_crit { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert0>; + cooling-device = + <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/spear-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/spear-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..93e3b67c102d5af108f174c2b82bbae9cb8fc117 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/spear-thermal.txt @@ -0,0 +1,14 @@ +* SPEAr Thermal + +Required properties: +- compatible : "st,thermal-spear1340" +- reg : Address range of the thermal registers +- st,thermal-flags: flags used to enable thermal sensor + +Example: + + thermal@fc000000 { + compatible = "st,thermal-spear1340"; + reg = <0xfc000000 0x1000>; + st,thermal-flags = <0x7000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/st-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/st-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..a2f939137e3541e3b3f3e89627cdbb6d74b69c98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/st-thermal.txt @@ -0,0 +1,32 @@ +Binding for Thermal Sensor driver for STMicroelectronics STi series of SoCs. + +Required parameters: +------------------- + +compatible : Should be "st,stih407-thermal" + +clock-names : Should be "thermal". + See: Documentation/devicetree/bindings/resource-names.txt +clocks : Phandle of the clock used by the thermal sensor. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt + +Optional parameters: +------------------- + +reg : For non-sysconf based sensors, this should be the physical base + address and length of the sensor's registers. +interrupts : Standard way to define interrupt number. + NB: For thermal sensor's for which no interrupt has been + defined, a polling delay of 1000ms will be used to read the + temperature from device. + +Example: + + temp0@91a0000 { + compatible = "st,stih407-thermal"; + reg = <0x91a0000 0x28>; + clock-names = "thermal"; + clocks = <&CLK_SYSIN>; + interrupts = ; + st,passive_cooling_temp = <110>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/tango-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/tango-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..212198d4b9379b70c3ca7572f4619479541bb487 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/tango-thermal.txt @@ -0,0 +1,17 @@ +* Tango Thermal + +The SMP8758 SoC includes 3 instances of this temperature sensor +(in the CPU, video decoder, and PCIe controller). + +Required properties: +- #thermal-sensor-cells: Should be 0 (see thermal.txt) +- compatible: "sigma,smp8758-thermal" +- reg: Address range of the thermal registers + +Example: + + cpu_temp: thermal@920100 { + #thermal-sensor-cells = <0>; + compatible = "sigma,smp8758-thermal"; + reg = <0x920100 12>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/thermal-generic-adc.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/thermal-generic-adc.txt new file mode 100644 index 0000000000000000000000000000000000000000..d72355502b786d02d51c2d8d21e834e2351266b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/thermal-generic-adc.txt @@ -0,0 +1,89 @@ +General Purpose Analog To Digital Converter (ADC) based thermal sensor. + +On some of platforms, thermal sensor like thermistors are connected to +one of ADC channel and sensor resistance is read via voltage across the +sensor resistor. The voltage read across the sensor is mapped to +temperature using voltage-temperature lookup table. + +Required properties: +=================== +- compatible: Must be "generic-adc-thermal". +- temperature-lookup-table: Two dimensional array of Integer; lookup table + to map the relation between ADC value and + temperature. When ADC is read, the value is + looked up on the table to get the equivalent + temperature. + The first value of the each row of array is the + temperature in milliCelsius and second value of + the each row of array is the ADC read value. +- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description + of this property. + +Example : +#include + +i2c@7000c400 { + ads1015: ads1015@4a { + reg = <0x4a>; + compatible = "ads1015"; + sampling-frequency = <3300>; + #io-channel-cells = <1>; + }; +}; + +tboard_thermistor: thermal-sensor { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&ads1015 1>; + io-channel-names = "sensor-channel"; + temperature-lookup-table = < (-40000) 2578 + (-39000) 2577 + (-38000) 2576 + (-37000) 2575 + (-36000) 2574 + (-35000) 2573 + (-34000) 2572 + (-33000) 2571 + (-32000) 2569 + (-31000) 2568 + (-30000) 2567 + :::::::::: + 118000 254 + 119000 247 + 120000 240 + 121000 233 + 122000 226 + 123000 220 + 124000 214 + 125000 208>; +}; + +dummy_cool_dev: dummy-cool-dev { + compatible = "dummy-cooling-dev"; + #cooling-cells = <2>; /* min followed by max */ +}; + +thermal-zones { + Tboard { + polling-delay = <15000>; /* milliseconds */ + polling-delay-passive = <0>; /* milliseconds */ + thermal-sensors = <&tboard_thermistor>; + + trips { + therm_est_trip: therm_est_trip { + temperature = <40000>; + type = "active"; + hysteresis = <1000>; + }; + }; + + cooling-maps { + map0 { + trip = <&therm_est_trip>; + cooling-device = <&dummy_cool_dev THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + contribution = <100>; + }; + + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..089f6d19bb9db24727f1275d52d4fe073576e71f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/thermal.txt @@ -0,0 +1,604 @@ +* Thermal Framework Device Tree descriptor + +This file describes a generic binding to provide a way of +defining hardware thermal structure using device tree. +A thermal structure includes thermal zones and their components, +such as trip points, polling intervals, sensors and cooling devices +binding descriptors. + +The target of device tree thermal descriptors is to describe only +the hardware thermal aspects. The thermal device tree bindings are +not about how the system must control or which algorithm or policy +must be taken in place. + +There are five types of nodes involved to describe thermal bindings: +- thermal sensors: devices which may be used to take temperature + measurements. +- cooling devices: devices which may be used to dissipate heat. +- trip points: describe key temperatures at which cooling is recommended. The + set of points should be chosen based on hardware limits. +- cooling maps: used to describe links between trip points and cooling devices; +- thermal zones: used to describe thermal data within the hardware; + +The following is a description of each of these node types. + +* Thermal sensor devices + +Thermal sensor devices are nodes providing temperature sensing capabilities on +thermal zones. Typical devices are I2C ADC converters and bandgaps. These are +nodes providing temperature data to thermal zones. Thermal sensor devices may +control one or more internal sensors. + +Required property: +- #thermal-sensor-cells: Used to provide sensor device specific information + Type: unsigned while referring to it. Typically 0 on thermal sensor + Size: one cell nodes with only one sensor, and at least 1 on nodes + with several internal sensors, in order + to identify uniquely the sensor instances within + the IC. See thermal zone binding for more details + on how consumers refer to sensor devices. + +* Cooling device nodes + +Cooling devices are nodes providing control on power dissipation. There +are essentially two ways to provide control on power dissipation. First +is by means of regulating device performance, which is known as passive +cooling. A typical passive cooling is a CPU that has dynamic voltage and +frequency scaling (DVFS), and uses lower frequencies as cooling states. +Second is by means of activating devices in order to remove +the dissipated heat, which is known as active cooling, e.g. regulating +fan speeds. In both cases, cooling devices shall have a way to determine +the state of cooling in which the device is. + +Any cooling device has a range of cooling states (i.e. different levels +of heat dissipation). For example a fan's cooling states correspond to +the different fan speeds possible. Cooling states are referred to by +single unsigned integers, where larger numbers mean greater heat +dissipation. The precise set of cooling states associated with a device +(as referred to by the cooling-min-level and cooling-max-level +properties) should be defined in a particular device's binding. +For more examples of cooling devices, refer to the example sections below. + +Required properties: +- #cooling-cells: Used to provide cooling device specific information + Type: unsigned while referring to it. Must be at least 2, in order + Size: one cell to specify minimum and maximum cooling state used + in the reference. The first cell is the minimum + cooling state requested and the second cell is + the maximum cooling state requested in the reference. + See Cooling device maps section below for more details + on how consumers refer to cooling devices. + +Optional properties: +- cooling-min-level: An integer indicating the smallest + Type: unsigned cooling state accepted. Typically 0. + Size: one cell + +- cooling-max-level: An integer indicating the largest + Type: unsigned cooling state accepted. + Size: one cell + +* Trip points + +The trip node is a node to describe a point in the temperature domain +in which the system takes an action. This node describes just the point, +not the action. + +Required properties: +- temperature: An integer indicating the trip temperature level, + Type: signed in millicelsius. + Size: one cell + +- hysteresis: A low hysteresis value on temperature property (above). + Type: unsigned This is a relative value, in millicelsius. + Size: one cell + +- type: a string containing the trip type. Expected values are: + "active": A trip point to enable active cooling + "passive": A trip point to enable passive cooling + "hot": A trip point to notify emergency + "critical": Hardware not reliable. + Type: string + +* Cooling device maps + +The cooling device maps node is a node to describe how cooling devices +get assigned to trip points of the zone. The cooling devices are expected +to be loaded in the target system. + +Required properties: +- cooling-device: A list of phandles of cooling devices with their specifiers, + Type: phandle + referring to which cooling devices are used in this + cooling specifier binding. In the cooling specifier, the first cell + is the minimum cooling state and the second cell + is the maximum cooling state used in this map. +- trip: A phandle of a trip point node within the same thermal + Type: phandle of zone. + trip point node + +Optional property: +- contribution: The cooling contribution to the thermal zone of the + Type: unsigned referred cooling device at the referred trip point. + Size: one cell The contribution is a ratio of the sum + of all cooling contributions within a thermal zone. + +Note: Using the THERMAL_NO_LIMIT (-1UL) constant in the cooling-device phandle +limit specifier means: +(i) - minimum state allowed for minimum cooling state used in the reference. +(ii) - maximum state allowed for maximum cooling state used in the reference. +Refer to include/dt-bindings/thermal/thermal.h for definition of this constant. + +* Thermal zone nodes + +The thermal zone node is the node containing all the required info +for describing a thermal zone, including its cooling device bindings. The +thermal zone node must contain, apart from its own properties, one sub-node +containing trip nodes and one sub-node containing all the zone cooling maps. + +Required properties: +- polling-delay: The maximum number of milliseconds to wait between polls + Type: unsigned when checking this thermal zone. + Size: one cell + +- polling-delay-passive: The maximum number of milliseconds to wait + Type: unsigned between polls when performing passive cooling. + Size: one cell + +- thermal-sensors: A list of thermal sensor phandles and sensor specifier + Type: list of used while monitoring the thermal zone. + phandles + sensor + specifier + +- trips: A sub-node which is a container of only trip point nodes + Type: sub-node required to describe the thermal zone. + +- cooling-maps: A sub-node which is a container of only cooling device + Type: sub-node map nodes, used to describe the relation between trips + and cooling devices. + +Optional property: +- coefficients: An array of integers (one signed cell) containing + Type: array coefficients to compose a linear relation between + Elem size: one cell the sensors listed in the thermal-sensors property. + Elem type: signed Coefficients defaults to 1, in case this property + is not specified. A simple linear polynomial is used: + Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn. + + The coefficients are ordered and they match with sensors + by means of sensor ID. Additional coefficients are + interpreted as constant offset. + +- sustainable-power: An estimate of the sustainable power (in mW) that the + Type: unsigned thermal zone can dissipate at the desired + Size: one cell control temperature. For reference, the + sustainable power of a 4'' phone is typically + 2000mW, while on a 10'' tablet is around + 4500mW. + +- wake-capable-sensor: Set to true if thermal zone sensor is wake up capable + Type: bool and cooling devices binded to this thermal zone are not + Size: none affected during suspend. + +Note: The delay properties are bound to the maximum dT/dt (temperature +derivative over time) in two situations for a thermal zone: +(i) - when passive cooling is activated (polling-delay-passive); and +(ii) - when the zone just needs to be monitored (polling-delay) or +when active cooling is activated. + +The maximum dT/dt is highly bound to hardware power consumption and dissipation +capability. The delays should be chosen to account for said max dT/dt, +such that a device does not cross several trip boundaries unexpectedly +between polls. Choosing the right polling delays shall avoid having the +device in temperature ranges that may damage the silicon structures and +reduce silicon lifetime. + +* The thermal-zones node + +The "thermal-zones" node is a container for all thermal zone nodes. It shall +contain only sub-nodes describing thermal zones as in the section +"Thermal zone nodes". The "thermal-zones" node appears under "/". + +* Examples + +Below are several examples on how to use thermal data descriptors +using device tree bindings: + +(a) - CPU thermal zone + +The CPU thermal zone example below describes how to setup one thermal zone +using one single sensor as temperature source and many cooling devices and +power dissipation control sources. + +#include + +cpus { + /* + * Here is an example of describing a cooling device for a DVFS + * capable CPU. The CPU node describes its four OPPs. + * The cooling states possible are 0..3, and they are + * used as OPP indexes. The minimum cooling state is 0, which means + * all four OPPs can be available to the system. The maximum + * cooling state is 3, which means only the lowest OPPs (198MHz@0.85V) + * can be available in the system. + */ + cpu0: cpu@0 { + ... + operating-points = < + /* kHz uV */ + 970000 1200000 + 792000 1100000 + 396000 950000 + 198000 850000 + >; + cooling-min-level = <0>; + cooling-max-level = <3>; + #cooling-cells = <2>; /* min followed by max */ + }; + ... +}; + +&i2c1 { + ... + /* + * A simple fan controller which supports 10 speeds of operation + * (represented as 0-9). + */ + fan0: fan@48 { + ... + cooling-max-level = <9>; + cooling-min-level = <0>; + #cooling-cells = <2>; /* min followed by max */ + }; +}; + +ocp { + ... + /* + * A simple IC with a single bandgap temperature sensor. + */ + bandgap0: bandgap@0000ed00 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&bandgap0>; + + trips { + cpu_alert0: cpu-alert0 { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "active"; + }; + cpu_alert1: cpu-alert1 { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu_crit: cpu-crit { + temperature = <125000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert0>; + cooling-device = <&fan0 THERMAL_NO_LIMIT 4>; + }; + map1 { + trip = <&cpu_alert1>; + cooling-device = <&fan0 5 THERMAL_NO_LIMIT>, <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; +}; + +In the example above, the ADC sensor (bandgap0) at address 0x0000ED00 is +used to monitor the zone 'cpu-thermal' using its sole sensor. A fan +device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten +different cooling states 0-9. It is used to remove the heat out of +the thermal zone 'cpu-thermal' using its cooling states +from its minimum to 4, when it reaches trip point 'cpu_alert0' +at 90C, as an example of active cooling. The same cooling device is used at +'cpu_alert1', but from 5 to its maximum state. The cpu@0 device is also +linked to the same thermal zone, 'cpu-thermal', as a passive cooling device, +using all its cooling states at trip point 'cpu_alert1', +which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the +temperature of 125C, represented by the trip point 'cpu_crit', the silicon +is not reliable anymore. + +(b) - IC with several internal sensors + +The example below describes how to deploy several thermal zones based off a +single sensor IC, assuming it has several internal sensors. This is a common +case on SoC designs with several internal IPs that may need different thermal +requirements, and thus may have their own sensor to monitor or detect internal +hotspots in their silicon. + +#include + +ocp { + ... + /* + * A simple IC with several bandgap temperature sensors. + */ + bandgap0: bandgap@0000ed00 { + ... + #thermal-sensor-cells = <1>; + }; +}; + +thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 0>; + + trips { + /* each zone within the SoC may have its own trips */ + cpu_alert: cpu-alert { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu_crit: cpu-crit { + temperature = <125000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; + + gpu_thermal: gpu-thermal { + polling-delay-passive = <120>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 1>; + + trips { + /* each zone within the SoC may have its own trips */ + gpu_alert: gpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + gpu_crit: gpu-crit { + temperature = <105000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; + + dsp_thermal: dsp-thermal { + polling-delay-passive = <50>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 2>; + + trips { + /* each zone within the SoC may have its own trips */ + dsp_alert: dsp-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + dsp_crit: gpu-crit { + temperature = <135000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; +}; + +In the example above, there is one bandgap IC which has the capability to +monitor three sensors. The hardware has been designed so that sensors are +placed on different places in the DIE to monitor different temperature +hotspots: one for CPU thermal zone, one for GPU thermal zone and the +other to monitor a DSP thermal zone. + +Thus, there is a need to assign each sensor provided by the bandgap IC +to different thermal zones. This is achieved by means of using the +#thermal-sensor-cells property and using the first cell of the sensor +specifier as sensor ID. In the example, then, is used to +monitor CPU thermal zone, is used to monitor GPU thermal +zone and is used to monitor DSP thermal zone. Each zone +may be uncorrelated, having its own dT/dt requirements, trips +and cooling maps. + + +(c) - Several sensors within one single thermal zone + +The example below illustrates how to use more than one sensor within +one thermal zone. + +#include + +&i2c1 { + ... + /* + * A simple IC with a single temperature sensor. + */ + adc: sensor@49 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +ocp { + ... + /* + * A simple IC with a single bandgap temperature sensor. + */ + bandgap0: bandgap@0000ed00 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&bandgap0>, /* cpu */ + <&adc>; /* pcb north */ + + /* hotspot = 100 * bandgap - 120 * adc + 484 */ + coefficients = <100 -120 484>; + + trips { + ... + }; + + cooling-maps { + ... + }; + }; +}; + +In some cases, there is a need to use more than one sensor to extrapolate +a thermal hotspot in the silicon. The above example illustrates this situation. +For instance, it may be the case that a sensor external to CPU IP may be placed +close to CPU hotspot and together with internal CPU sensor, it is used +to determine the hotspot. Assuming this is the case for the above example, +the hypothetical extrapolation rule would be: + hotspot = 100 * bandgap - 120 * adc + 484 + +In other context, the same idea can be used to add fixed offset. For instance, +consider the hotspot extrapolation rule below: + hotspot = 1 * adc + 6000 + +In the above equation, the hotspot is always 6C higher than what is read +from the ADC sensor. The binding would be then: + thermal-sensors = <&adc>; + + /* hotspot = 1 * adc + 6000 */ + coefficients = <1 6000>; + +(d) - Board thermal + +The board thermal example below illustrates how to setup one thermal zone +with many sensors and many cooling devices. + +#include + +&i2c1 { + ... + /* + * An IC with several temperature sensor. + */ + adc_dummy: sensor@50 { + ... + #thermal-sensor-cells = <1>; /* sensor internal ID */ + }; +}; + +thermal-zones { + batt-thermal { + polling-delay-passive = <500>; /* milliseconds */ + polling-delay = <2500>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&adc_dummy 4>; + + trips { + ... + }; + + cooling-maps { + ... + }; + }; + + board_thermal: board-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <2500>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&adc_dummy 0>, /* pcb top edge */ + <&adc_dummy 1>, /* lcd */ + <&adc_dummy 2>; /* back cover */ + /* + * An array of coefficients describing the sensor + * linear relation. E.g.: + * z = c1*x1 + c2*x2 + c3*x3 + */ + coefficients = <1200 -345 890>; + + sustainable-power = <2500>; + + trips { + /* Trips are based on resulting linear equation */ + cpu_trip: cpu-trip { + temperature = <60000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + gpu_trip: gpu-trip { + temperature = <55000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + } + lcd_trip: lcp-trip { + temperature = <53000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + crit_trip: crit-trip { + temperature = <68000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_trip>; + cooling-device = <&cpu0 0 2>; + contribution = <55>; + }; + map1 { + trip = <&gpu_trip>; + cooling-device = <&gpu0 0 2>; + contribution = <20>; + }; + map2 { + trip = <&lcd_trip>; + cooling-device = <&lcd0 5 10>; + contribution = <15>; + }; + }; + }; +}; + +The above example is a mix of previous examples, a sensor IP with several internal +sensors used to monitor different zones, one of them is composed by several sensors and +with different cooling devices. diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/ti_soc_thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/ti_soc_thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..6299dd8de339aeb1ede83b582e5ce3289213af7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/ti_soc_thermal.txt @@ -0,0 +1,88 @@ +* Texas Instrument OMAP SCM bandgap bindings + +In the System Control Module, OMAP supplies a voltage reference +and a temperature sensor feature that are gathered in the band +gap voltage and temperature sensor (VBGAPTS) module. The band +gap provides current and voltage reference for its internal +circuits and other analog IP blocks. The analog-to-digital +converter (ADC) produces an output value that is proportional +to the silicon temperature. + +Required properties: +- compatible : Should be: + - "ti,omap34xx-bandgap" : for OMAP34xx bandgap + - "ti,omap36xx-bandgap" : for OMAP36xx bandgap + - "ti,omap4430-bandgap" : for OMAP4430 bandgap + - "ti,omap4460-bandgap" : for OMAP4460 bandgap + - "ti,omap4470-bandgap" : for OMAP4470 bandgap + - "ti,omap5430-bandgap" : for OMAP5430 bandgap +- interrupts : this entry should indicate which interrupt line +the talert signal is routed to; +Specific: +- gpios : this entry should be used to inform which GPIO +line the tshut signal is routed to. The informed GPIO will +be treated as an IRQ; +- regs : this entry must also be specified and it is specific +to each bandgap version, because the mapping may change from +soc to soc, apart of depending on available features. + +Example: +OMAP34xx: +bandgap { + reg = <0x48002524 0x4>; + compatible = "ti,omap34xx-bandgap"; +}; + +OMAP36xx: +bandgap { + reg = <0x48002524 0x4>; + compatible = "ti,omap36xx-bandgap"; +}; + +OMAP4430: +bandgap { + reg = <0x4a002260 0x4 0x4a00232C 0x4>; + compatible = "ti,omap4430-bandgap"; +}; + +OMAP4460: +bandgap { + reg = <0x4a002260 0x4 + 0x4a00232C 0x4 + 0x4a002378 0x18>; + compatible = "ti,omap4460-bandgap"; + interrupts = <0 126 4>; /* talert */ + gpios = <&gpio3 22 0>; /* tshut */ +}; + +OMAP4470: +bandgap { + reg = <0x4a002260 0x4 + 0x4a00232C 0x4 + 0x4a002378 0x18>; + compatible = "ti,omap4470-bandgap"; + interrupts = <0 126 4>; /* talert */ + gpios = <&gpio3 22 0>; /* tshut */ +}; + +OMAP5430: +bandgap { + reg = <0x4a0021e0 0xc + 0x4a00232c 0xc + 0x4a002380 0x2c + 0x4a0023C0 0x3c>; + compatible = "ti,omap5430-bandgap"; + interrupts = <0 126 4>; /* talert */ +}; + +DRA752: +bandgap { + reg = <0x4a0021e0 0xc + 0x4a00232c 0xc + 0x4a002380 0x2c + 0x4a0023C0 0x3c + 0x4a002564 0x8 + 0x4a002574 0x50>; + compatible = "ti,dra752-bandgap"; + interrupts = <0 126 4>; /* talert */ +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/tsens.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/tsens.txt new file mode 100644 index 0000000000000000000000000000000000000000..3ea40abbe03515c5a5e06ab159c4aed63ac5e31a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/tsens.txt @@ -0,0 +1,55 @@ +Qualcomm Technologies, Inc. TSENS driver + +Temperature sensor (TSENS) driver supports reading temperature from sensors +across the MSM. The driver defaults to support a 12 bit ADC. + +The driver uses the Thermal sysfs framework to provide thermal +clients the ability to read from supported on-die temperature sensors, +set temperature thresholds for cool/warm thresholds and receive notification +on temperature threshold events. + +TSENS node + +Required properties: +- compatible : should be "qcom,msm8996-tsens" for 8996 TSENS driver. + should be "qcom,msm8953-tsens" for 8953 TSENS driver. + should be "qcom,msm8998-tsens" for 8998 TSENS driver. + should be "qcom,msmhamster-tsens" for hamster TSENS driver. + should be "qcom,sdm660-tsens" for 660 TSENS driver. + should be "qcom,sdm630-tsens" for 630 TSENS driver. + should be "qcom,sdm845-tsens" for SDM845 TSENS driver. + should be "qcom,tsens24xx" for 2.4 TSENS controller. + should be "qcom,msm8937-tsens" for 8937 TSENS driver. + should be "qcom,qcs405-tsens" for QCS405 TSENS driver. + should be "qcom,sm6150-tsens" for 6150 TSENS driver. + should be "qcom,tsens26xx" for 2.6 TSENS controller. + + The compatible property is used to identify the respective controller to use + for the corresponding SoC. +- reg : offset and length of the TSENS registers with associated property in reg-names + as "tsens_srot_physical" for TSENS SROT physical address region. TSENS TM + physical address region as "tsens_tm_physical", and "tsens_eeprom_physical" for the + TSENS calibration fuse register region. +- reg-names : resource names used for the physical address of the TSENS + registers. Should be "tsens_srot_physical" for physical address of the TSENS + SROT region, "tsens_tm_physical" for physical address of the TM region and + "tsens_eeprom_physical" for the TSENS calibration fuse register region. +- interrupts : TSENS interrupt to notify Upper/Lower and Critical temperature threshold. +- interrupt-names: Should be "tsens-upper-lower" for temperature threshold. + Add "tsens-critical" for Critical temperature threshold notification + in addition to "tsens-upper-lower" for 8996 TSENS since + 8996 supports Upper/Lower and Critical temperature threshold. +- tsens-reinit-wa : To support the re-initialization of tsens controller from + trustzone +Example: + +tsens@fc4a8000 { + compatible = "qcom,msm-tsens"; + reg = <0xfc4a8000 0x10>, + <0xfc4b8000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical", + "tsens_eeprom_physical", + interrupts = <0 184 0>; + interrupt-names = "tsens-upper-lower"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/uniphier-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/uniphier-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..ceb92a95727a8aadb79dbfe9e222ced65449d6c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/uniphier-thermal.txt @@ -0,0 +1,65 @@ +* UniPhier Thermal bindings + +This describes the devicetree bindings for thermal monitor supported by +PVT(Process, Voltage and Temperature) monitoring unit implemented on Socionext +UniPhier SoCs. + +Required properties: +- compatible : + - "socionext,uniphier-pxs2-thermal" : For UniPhier PXs2 SoC + - "socionext,uniphier-ld20-thermal" : For UniPhier LD20 SoC + - "socionext,uniphier-pxs3-thermal" : For UniPhier PXs3 SoC +- interrupts : IRQ for the temperature alarm +- #thermal-sensor-cells : Should be 0. See ./thermal.txt for details. + +Optional properties: +- socionext,tmod-calibration: A pair of calibrated values referred from PVT, + in case that the values aren't set on SoC, + like a reference board. + +Example: + + sysctrl@61840000 { + compatible = "socionext,uniphier-ld20-sysctrl", + "simple-mfd", "syscon"; + reg = <0x61840000 0x10000>; + ... + pvtctl: pvtctl { + compatible = "socionext,uniphier-ld20-thermal"; + interrupts = <0 3 1>; + #thermal-sensor-cells = <0>; + }; + ... + }; + + thermal-zones { + cpu_thermal { + polling-delay-passive = <250>; /* 250ms */ + polling-delay = <1000>; /* 1000ms */ + thermal-sensors = <&pvtctl>; + + trips { + cpu_crit: cpu_crit { + temperature = <110000>; /* 110C */ + hysteresis = <2000>; + type = "critical"; + }; + cpu_alert: cpu_alert { + temperature = <100000>; /* 100C */ + hysteresis = <2000>; + type = "passive"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert>; + cooling-device = <&cpu0 (-1) (-1)>; + }; + map1 { + trip = <&cpu_alert>; + cooling-device = <&cpu2 (-1) (-1)>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/thermal/zx2967-thermal.txt b/arch/arm64/boot/dts/vendor/bindings/thermal/zx2967-thermal.txt new file mode 100644 index 0000000000000000000000000000000000000000..3dc1c6bf0478fa6d598654f7def790597c159e1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/thermal/zx2967-thermal.txt @@ -0,0 +1,116 @@ +* ZTE zx2967 family Thermal + +Required Properties: +- compatible: should be one of the following. + * zte,zx296718-thermal +- reg: physical base address of the controller and length of memory mapped + region. +- clocks : Pairs of phandle and specifier referencing the controller's clocks. +- clock-names: "topcrm" for the topcrm clock. + "apb" for the apb clock. +- #thermal-sensor-cells: must be 0. + +Please note: slope coefficient defined in thermal-zones section need to be +multiplied by 1000. + +Example for tempsensor: + + tempsensor: tempsensor@148a000 { + compatible = "zte,zx296718-thermal"; + reg = <0x0148a000 0x20>; + clocks = <&topcrm TEMPSENSOR_GATE>, <&audiocrm AUDIO_TS_PCLK>; + clock-names = "topcrm", "apb"; + #thermal-sensor-cells = <0>; + }; + +Example for cooling device: + + cooling_dev: cooling_dev { + cluster0_cooling_dev: cluster0-cooling-dev { + #cooling-cells = <2>; + cpumask = <0xf>; + capacitance = <1500>; + }; + + cluster1_cooling_dev: cluster1-cooling-dev { + #cooling-cells = <2>; + cpumask = <0x30>; + capacitance = <2000>; + }; + }; + +Example for thermal zones: + + thermal-zones { + zx296718_thermal: zx296718_thermal { + polling-delay-passive = <500>; + polling-delay = <1000>; + sustainable-power = <6500>; + + thermal-sensors = <&tempsensor 0>; + /* + * slope need to be multiplied by 1000. + */ + coefficients = <1951 (-922)>; + + trips { + trip0: switch_on_temperature { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip1: desired_temperature { + temperature = <100000>; + hysteresis = <2000>; + type = "passive"; + }; + + crit: critical_temperature { + temperature = <110000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&gpu 2 5>; + }; + + map1 { + trip = <&trip0>; + cooling-device = <&cluster0_cooling_dev 1 2>; + }; + + map2 { + trip = <&trip1>; + cooling-device = <&cluster0_cooling_dev 1 2>; + }; + + map3 { + trip = <&crit>; + cooling-device = <&cluster0_cooling_dev 1 2>; + }; + + map4 { + trip = <&trip0>; + cooling-device = <&cluster1_cooling_dev 1 2>; + contribution = <9000>; + }; + + map5 { + trip = <&trip1>; + cooling-device = <&cluster1_cooling_dev 1 2>; + contribution = <4096>; + }; + + map6 { + trip = <&crit>; + cooling-device = <&cluster1_cooling_dev 1 2>; + contribution = <4096>; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/actions,owl-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/actions,owl-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..977054f87563ce8e0faa3a5887ce23f24a2c1954 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/actions,owl-timer.txt @@ -0,0 +1,21 @@ +Actions Semi Owl Timer + +Required properties: +- compatible : "actions,s500-timer" for S500 + "actions,s700-timer" for S700 + "actions,s900-timer" for S900 +- reg : Offset and length of the register set for the device. +- interrupts : Should contain the interrupts. +- interrupt-names : Valid names are: "2hz0", "2hz1", + "timer0", "timer1", "timer2", "timer3" + See ../resource-names.txt + +Example: + + timer@b0168000 { + compatible = "actions,s500-timer"; + reg = <0xb0168000 0x100>; + interrupts = , + ; + interrupt-names = "timer0", "timer1"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/allwinner,sun4i-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/allwinner,sun4i-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..5c2e23574ca025aea14151eb4243052c4cf14901 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/allwinner,sun4i-timer.txt @@ -0,0 +1,17 @@ +Allwinner A1X SoCs Timer Controller + +Required properties: + +- compatible : should be "allwinner,sun4i-a10-timer" +- reg : Specifies base physical address and size of the registers. +- interrupts : The interrupt of the first timer +- clocks: phandle to the source clock (usually a 24 MHz fixed clock) + +Example: + +timer { + compatible = "allwinner,sun4i-a10-timer"; + reg = <0x01c20c00 0x400>; + interrupts = <22>; + clocks = <&osc>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/allwinner,sun5i-a13-hstimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c5c1be7836015c9cfc6ef4e653eb5d846d48dad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/allwinner,sun5i-a13-hstimer.txt @@ -0,0 +1,26 @@ +Allwinner SoCs High Speed Timer Controller + +Required properties: + +- compatible : should be "allwinner,sun5i-a13-hstimer" or + "allwinner,sun7i-a20-hstimer" +- reg : Specifies base physical address and size of the registers. +- interrupts : The interrupts of these timers (2 for the sun5i IP, 4 for the sun7i + one) +- clocks: phandle to the source clock (usually the AHB clock) + +Optional properties: +- resets: phandle to a reset controller asserting the timer + +Example: + +timer@1c60000 { + compatible = "allwinner,sun7i-a20-hstimer"; + reg = <0x01c60000 0x1000>; + interrupts = <0 51 1>, + <0 52 1>, + <0 53 1>, + <0 54 1>; + clocks = <&ahb1_gates 19>; + resets = <&ahb1rst 19>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/altr,timer-1.0.txt b/arch/arm64/boot/dts/vendor/bindings/timer/altr,timer-1.0.txt new file mode 100644 index 0000000000000000000000000000000000000000..e698e348873567adf2ab39bd2040a9144347ec68 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/altr,timer-1.0.txt @@ -0,0 +1,18 @@ +Altera Timer + +Required properties: + +- compatible : should be "altr,timer-1.0" +- reg : Specifies base physical address and size of the registers. +- interrupts : Should contain the timer interrupt number +- clock-frequency : The frequency of the clock that drives the counter, in Hz. + +Example: + +timer { + compatible = "altr,timer-1.0"; + reg = <0x00400000 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <11>; + clock-frequency = <125000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/amlogic,meson6-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/amlogic,meson6-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..a092053f7902fdbba2e2d752b5e725ea83506432 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/amlogic,meson6-timer.txt @@ -0,0 +1,15 @@ +Amlogic Meson6 SoCs Timer Controller + +Required properties: + +- compatible : should be "amlogic,meson6-timer" +- reg : Specifies base physical address and size of the registers. +- interrupts : The interrupt of the first timer + +Example: + +timer@c1109940 { + compatible = "amlogic,meson6-timer"; + reg = <0xc1109940 0x14>; + interrupts = <0 10 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/andestech,atcpit100-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/andestech,atcpit100-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c9ea5989e352166e3ccc23b9929f9fa83a746d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/andestech,atcpit100-timer.txt @@ -0,0 +1,33 @@ +Andestech ATCPIT100 timer +------------------------------------------------------------------ +ATCPIT100 is a generic IP block from Andes Technology, embedded in +Andestech AE3XX platforms and other designs. + +This timer is a set of compact multi-function timers, which can be +used as pulse width modulators (PWM) as well as simple timers. + +It supports up to 4 PIT channels. Each PIT channel is a +multi-function timer and provide the following usage scenarios: +One 32-bit timer +Two 16-bit timers +Four 8-bit timers +One 16-bit PWM +One 16-bit timer and one 8-bit PWM +Two 8-bit timer and one 8-bit PWM + +Required properties: +- compatible : Should be "andestech,atcpit100" +- reg : Address and length of the register set +- interrupts : Reference to the timer interrupt +- clocks : a clock to provide the tick rate for "andestech,atcpit100" +- clock-names : should be "PCLK" for the peripheral clock source. + +Examples: + +timer0: timer@f0400000 { + compatible = "andestech,atcpit100"; + reg = <0xf0400000 0x1000>; + interrupts = <2>; + clocks = <&apb>; + clock-names = "PCLK"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/arm,arch_timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/arm,arch_timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..68301b77e854c86abc7d8e63cf67bcedb8b4b174 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/arm,arch_timer.txt @@ -0,0 +1,112 @@ +* ARM architected timer + +ARM cores may have a per-core architected timer, which provides per-cpu timers, +or a memory mapped architected timer, which provides up to 8 frames with a +physical and optional virtual timer per frame. + +The per-core architected timer is attached to a GIC to deliver its +per-processor interrupts via PPIs. The memory mapped timer is attached to a GIC +to deliver its interrupts via SPIs. + +** CP15 Timer node properties: + +- compatible : Should at least contain one of + "arm,armv7-timer" + "arm,armv8-timer" + +- interrupts : Interrupt list for secure, non-secure, virtual and + hypervisor timers, in that order. + +- clock-frequency : The frequency of the main counter, in Hz. Should be present + only where necessary to work around broken firmware which does not configure + CNTFRQ on all CPUs to a uniform correct value. Use of this property is + strongly discouraged; fix your firmware unless absolutely impossible. + +- always-on : a boolean property. If present, the timer is powered through an + always-on power domain, therefore it never loses context. + +- fsl,erratum-a008585 : A boolean property. Indicates the presence of + QorIQ erratum A-008585, which says that reading the counter is + unreliable unless the same value is returned by back-to-back reads. + This also affects writes to the tval register, due to the implicit + counter read. + +- hisilicon,erratum-161010101 : A boolean property. Indicates the + presence of Hisilicon erratum 161010101, which says that reading the + counters is unreliable in some cases, and reads may return a value 32 + beyond the correct value. This also affects writes to the tval + registers, due to the implicit counter read. + +** Optional properties: + +- arm,cpu-registers-not-fw-configured : Firmware does not initialize + any of the generic timer CPU registers, which contain their + architecturally-defined reset values. Only supported for 32-bit + systems which follow the ARMv7 architected reset values. + +- arm,no-tick-in-suspend : The main counter does not tick when the system is in + low-power system suspend on some SoCs. This behavior does not match the + Architecture Reference Manual's specification that the system counter "must + be implemented in an always-on power domain." + + +Example: + + timer { + compatible = "arm,cortex-a15-timer", + "arm,armv7-timer"; + interrupts = <1 13 0xf08>, + <1 14 0xf08>, + <1 11 0xf08>, + <1 10 0xf08>; + clock-frequency = <100000000>; + }; + +** Memory mapped timer node properties: + +- compatible : Should at least contain "arm,armv7-timer-mem". + +- clock-frequency : The frequency of the main counter, in Hz. Should be present + only when firmware has not configured the MMIO CNTFRQ registers. + +- reg : The control frame base address. + +Note that #address-cells, #size-cells, and ranges shall be present to ensure +the CPU can address a frame's registers. + +A timer node has up to 8 frame sub-nodes, each with the following properties: + +- frame-number: 0 to 7. + +- interrupts : Interrupt list for physical and virtual timers in that order. + The virtual timer interrupt is optional. + +- reg : The first and second view base addresses in that order. The second view + base address is optional. + +- status : "disabled" indicates the frame is not available for use. Optional. + +Example: + + timer@f0000000 { + compatible = "arm,armv7-timer-mem"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + reg = <0xf0000000 0x1000>; + clock-frequency = <50000000>; + + frame@f0001000 { + frame-number = <0> + interrupts = <0 13 0x8>, + <0 14 0x8>; + reg = <0xf0001000 0x1000>, + <0xf0002000 0x1000>; + }; + + frame@f0003000 { + frame-number = <1> + interrupts = <0 15 0x8>; + reg = <0xf0003000 0x1000>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/arm,armv7m-systick.txt b/arch/arm64/boot/dts/vendor/bindings/timer/arm,armv7m-systick.txt new file mode 100644 index 0000000000000000000000000000000000000000..7cf4a24601eb2e2365e2bc4893a5ecd026074187 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/arm,armv7m-systick.txt @@ -0,0 +1,26 @@ +* ARMv7M System Timer + +ARMv7-M includes a system timer, known as SysTick. Current driver only +implements the clocksource feature. + +Required properties: +- compatible : Should be "arm,armv7m-systick" +- reg : The address range of the timer + +Required clocking property, have to be one of: +- clocks : The input clock of the timer +- clock-frequency : The rate in HZ in input of the ARM SysTick + +Examples: + +systick: timer@e000e010 { + compatible = "arm,armv7m-systick"; + reg = <0xe000e010 0x10>; + clocks = <&clk_systick>; +}; + +systick: timer@e000e010 { + compatible = "arm,armv7m-systick"; + reg = <0xe000e010 0x10>; + clock-frequency = <90000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/arm,global_timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/arm,global_timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..bdae3a818793cd4c05b6e8e82d5c4c03f9888ea1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/arm,global_timer.txt @@ -0,0 +1,27 @@ + +* ARM Global Timer + Cortex-A9 are often associated with a per-core Global timer. + +** Timer node required properties: + +- compatible : should contain + * "arm,cortex-a5-global-timer" for Cortex-A5 global timers. + * "arm,cortex-a9-global-timer" for Cortex-A9 global + timers or any compatible implementation. Note: driver + supports versions r2p0 and above. + +- interrupts : One interrupt to each core + +- reg : Specify the base address and the size of the GT timer + register window. + +- clocks : Should be phandle to a clock. + +Example: + + timer@2c000600 { + compatible = "arm,cortex-a9-global-timer"; + reg = <0x2c000600 0x20>; + interrupts = <1 13 0xf01>; + clocks = <&arm_periph_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/arm,mps2-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/arm,mps2-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..48f84d74edde628bff45ef18b2d71dc8e729bd2b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/arm,mps2-timer.txt @@ -0,0 +1,28 @@ +ARM MPS2 timer + +The MPS2 platform has simple general-purpose 32 bits timers. + +Required properties: +- compatible : Should be "arm,mps2-timer" +- reg : Address and length of the register set +- interrupts : Reference to the timer interrupt + +Required clocking property, have to be one of: +- clocks : The input clock of the timer +- clock-frequency : The rate in HZ in input of the ARM MPS2 timer + +Examples: + +timer1: mps2-timer@40000000 { + compatible = "arm,mps2-timer"; + reg = <0x40000000 0x1000>; + interrupts = <8>; + clocks = <&sysclk>; +}; + +timer2: mps2-timer@40001000 { + compatible = "arm,mps2-timer"; + reg = <0x40001000 0x1000>; + interrupts = <9>; + clock-frequency = <25000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/arm,sp804.txt b/arch/arm64/boot/dts/vendor/bindings/timer/arm,sp804.txt new file mode 100644 index 0000000000000000000000000000000000000000..5cd8eee74af1c127c7a8b77aeb45680b2b3d9fb0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/arm,sp804.txt @@ -0,0 +1,29 @@ +ARM sp804 Dual Timers +--------------------------------------- + +Required properties: +- compatible: Should be "arm,sp804" & "arm,primecell" +- interrupts: Should contain the list of Dual Timer interrupts. This is the + interrupt for timer 1 and timer 2. In the case of a single entry, it is + the combined interrupt or if "arm,sp804-has-irq" is present that + specifies which timer interrupt is connected. +- reg: Should contain location and length for dual timer register. +- clocks: clocks driving the dual timer hardware. This list should be 1 or 3 + clocks. With 3 clocks, the order is timer0 clock, timer1 clock, + apb_pclk. A single clock can also be specified if the same clock is + used for all clock inputs. + +Optional properties: +- arm,sp804-has-irq = <#>: In the case of only 1 timer irq line connected, this + specifies if the irq connection is for timer 1 or timer 2. A value of 1 + or 2 should be used. + +Example: + + timer0: timer@fc800000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0xfc800000 0x1000>; + interrupts = <0 0 4>, <0 1 4>; + clocks = <&timclk1 &timclk2 &pclk>; + clock-names = "timer1", "timer2", "apb_pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/arm,twd.txt b/arch/arm64/boot/dts/vendor/bindings/timer/arm,twd.txt new file mode 100644 index 0000000000000000000000000000000000000000..383ea19c2bf0073e3a09ec4c254db28f17f28738 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/arm,twd.txt @@ -0,0 +1,53 @@ +* ARM Timer Watchdog + +ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core +Timer-Watchdog (aka TWD), which provides both a per-cpu local timer +and watchdog. + +The TWD is usually attached to a GIC to deliver its two per-processor +interrupts. + +** Timer node required properties: + +- compatible : Should be one of: + "arm,cortex-a9-twd-timer" + "arm,cortex-a5-twd-timer" + "arm,arm11mp-twd-timer" + +- interrupts : One interrupt to each core + +- reg : Specify the base address and the size of the TWD timer + register window. + +Optional + +- always-on : a boolean property. If present, the timer is powered through + an always-on power domain, therefore it never loses context. + +Example: + + twd-timer@2c000600 { + compatible = "arm,arm11mp-twd-timer""; + reg = <0x2c000600 0x20>; + interrupts = <1 13 0xf01>; + }; + +** Watchdog node properties: + +- compatible : Should be one of: + "arm,cortex-a9-twd-wdt" + "arm,cortex-a5-twd-wdt" + "arm,arm11mp-twd-wdt" + +- interrupts : One interrupt to each core + +- reg : Specify the base address and the size of the TWD watchdog + register window. + +Example: + + twd-watchdog@2c000620 { + compatible = "arm,arm11mp-twd-wdt"; + reg = <0x2c000620 0x20>; + interrupts = <1 14 0xf01>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/brcm,bcm2835-system-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/brcm,bcm2835-system-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..844bd5fbd04c13c0d5a511c7a333f19c37699e48 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/brcm,bcm2835-system-timer.txt @@ -0,0 +1,22 @@ +BCM2835 System Timer + +The System Timer peripheral provides four 32-bit timer channels and a +single 64-bit free running counter. Each channel has an output compare +register, which is compared against the 32 least significant bits of the +free running counter values, and generates an interrupt. + +Required properties: + +- compatible : should be "brcm,bcm2835-system-timer" +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 4 interrupt sinks; one per timer channel. +- clock-frequency : The frequency of the clock that drives the counter, in Hz. + +Example: + +timer { + compatible = "brcm,bcm2835-system-timer"; + reg = <0x7e003000 0x1000>; + interrupts = <1 0>, <1 1>, <1 2>, <1 3>; + clock-frequency = <1000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/brcm,kona-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/brcm,kona-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..39adf54b4388b919bc7ed465b93e4200e86000cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/brcm,kona-timer.txt @@ -0,0 +1,25 @@ +Broadcom Kona Family timer +----------------------------------------------------- +This timer is used in the following Broadcom SoCs: + BCM11130, BCM11140, BCM11351, BCM28145, BCM28155 + +Required properties: +- compatible : "brcm,kona-timer" +- DEPRECATED: compatible : "bcm,kona-timer" +- reg : Register range for the timer +- interrupts : interrupt for the timer +- clocks: phandle + clock specifier pair of the external clock +- clock-frequency: frequency that the clock operates + +Only one of clocks or clock-frequency should be specified. + +Refer to clocks/clock-bindings.txt for generic clock consumer properties. + +Example: + timer@35006000 { + compatible = "brcm,kona-timer"; + reg = <0x35006000 0x1000>; + interrupts = <0x0 7 0x4>; + clocks = <&hub_timer_clk>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/cadence,ttc-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/cadence,ttc-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..eeee6cd51e5ce94985653015c08691cc24e5ed07 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/cadence,ttc-timer.txt @@ -0,0 +1,21 @@ +Cadence TTC - Triple Timer Counter + +Required properties: +- compatible : Should be "cdns,ttc". +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 3 interrupts; one per timer channel. +- clocks: phandle to the source clock + +Optional properties: +- timer-width: Bit width of the timer, necessary if not 16. + +Example: + +ttc0: ttc0@f8001000 { + interrupt-parent = <&intc>; + interrupts = < 0 10 4 0 11 4 0 12 4 >; + compatible = "cdns,ttc"; + reg = <0xF8001000 0x1000>; + clocks = <&cpu_clk 3>; + timer-width = <32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/cirrus,clps711x-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/cirrus,clps711x-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4c62e7b1714e96348473443e5896e6196a98015 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/cirrus,clps711x-timer.txt @@ -0,0 +1,29 @@ +* Cirrus Logic CLPS711X Timer Counter + +Required properties: +- compatible: Shall contain "cirrus,ep7209-timer". +- reg : Address and length of the register set. +- interrupts: The interrupt number of the timer. +- clocks : phandle of timer reference clock. + +Note: Each timer should have an alias correctly numbered in "aliases" node. + +Example: + aliases { + timer0 = &timer1; + timer1 = &timer2; + }; + + timer1: timer@80000300 { + compatible = "cirrus,ep7312-timer", "cirrus,ep7209-timer"; + reg = <0x80000300 0x4>; + interrupts = <8>; + clocks = <&clks 5>; + }; + + timer2: timer@80000340 { + compatible = "cirrus,ep7312-timer", "cirrus,ep7209-timer"; + reg = <0x80000340 0x4>; + interrupts = <9>; + clocks = <&clks 6>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/digicolor-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/digicolor-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..d1b659bbc29fcabce5c2e69a3ea8179c8fa85476 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/digicolor-timer.txt @@ -0,0 +1,18 @@ +Conexant Digicolor SoCs Timer Controller + +Required properties: + +- compatible : should be "cnxt,cx92755-timer" +- reg : Specifies base physical address and size of the "Agent Communication" + timer registers +- interrupts : Contains 8 interrupts, one for each timer +- clocks: phandle to the main clock + +Example: + + timer@f0000fc0 { + compatible = "cnxt,cx92755-timer"; + reg = <0xf0000fc0 0x40>; + interrupts = <19>, <31>, <34>, <35>, <52>, <53>, <54>, <55>; + clocks = <&main_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/energymicro,efm32-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/energymicro,efm32-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..e502c11b2211eb23d5e1f9c01216353cb902ecf1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/energymicro,efm32-timer.txt @@ -0,0 +1,23 @@ +* EFM32 timer hardware + +The efm32 Giant Gecko SoCs come with four 16 bit timers. Two counters can be +connected to form a 32 bit counter. Each timer has three Compare/Capture +channels and can be used as PWM or Quadrature Decoder. Available clock sources +are the cpu's HFPERCLK (with a 10-bit prescaler) or an external pin. + +Required properties: +- compatible : Should be "energymicro,efm32-timer" +- reg : Address and length of the register set +- clocks : Should contain a reference to the HFPERCLK + +Optional properties: +- interrupts : Reference to the timer interrupt + +Example: + +timer@40010c00 { + compatible = "energymicro,efm32-timer"; + reg = <0x40010c00 0x400>; + interrupts = <14>; + clocks = <&cmu clk_HFPERCLKTIMER3>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/ezchip,nps400-timer0.txt b/arch/arm64/boot/dts/vendor/bindings/timer/ezchip,nps400-timer0.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3cfce8fecc5d5bd4b3a240daffdd987fd369b20 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/ezchip,nps400-timer0.txt @@ -0,0 +1,17 @@ +NPS Network Processor + +Required properties: + +- compatible : should be "ezchip,nps400-timer0" + +Clocks required for compatible = "ezchip,nps400-timer0": +- interrupts : The interrupt of the first timer +- clocks : Must contain a single entry describing the clock input + +Example: + +timer { + compatible = "ezchip,nps400-timer0"; + interrupts = <3>; + clocks = <&sysclk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/ezchip,nps400-timer1.txt b/arch/arm64/boot/dts/vendor/bindings/timer/ezchip,nps400-timer1.txt new file mode 100644 index 0000000000000000000000000000000000000000..c0ab4190b8fbabadc0213d5af3d30f1b7f33cdc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/ezchip,nps400-timer1.txt @@ -0,0 +1,15 @@ +NPS Network Processor + +Required properties: + +- compatible : should be "ezchip,nps400-timer1" + +Clocks required for compatible = "ezchip,nps400-timer1": +- clocks : Must contain a single entry describing the clock input + +Example: + +timer { + compatible = "ezchip,nps400-timer1"; + clocks = <&sysclk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/faraday,fttmr010.txt b/arch/arm64/boot/dts/vendor/bindings/timer/faraday,fttmr010.txt new file mode 100644 index 0000000000000000000000000000000000000000..195792270414fdc1d8c8b72ab7ed581057db970e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/faraday,fttmr010.txt @@ -0,0 +1,37 @@ +Faraday Technology timer + +This timer is a generic IP block from Faraday Technology, embedded in the +Cortina Systems Gemini SoCs and other designs. + +Required properties: + +- compatible : Must be one of + "faraday,fttmr010" + "cortina,gemini-timer", "faraday,fttmr010" + "moxa,moxart-timer", "faraday,fttmr010" + "aspeed,ast2400-timer" + "aspeed,ast2500-timer" + +- reg : Should contain registers location and length +- interrupts : Should contain the three timer interrupts usually with + flags for falling edge + +Optionally required properties: + +- clocks : a clock to provide the tick rate for "faraday,fttmr010" +- clock-names : should be "EXTCLK" and "PCLK" for the external tick timer + and peripheral clock respectively, for "faraday,fttmr010" +- syscon : a phandle to the global Gemini system controller if the compatible + type is "cortina,gemini-timer" + +Example: + +timer@43000000 { + compatible = "faraday,fttmr010"; + reg = <0x43000000 0x1000>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>, /* Timer 1 */ + <15 IRQ_TYPE_EDGE_FALLING>, /* Timer 2 */ + <16 IRQ_TYPE_EDGE_FALLING>; /* Timer 3 */ + clocks = <&extclk>, <&pclk>; + clock-names = "EXTCLK", "PCLK"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/fsl,ftm-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/fsl,ftm-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa8c40230e5e0896025021279c52824f55a87e52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/fsl,ftm-timer.txt @@ -0,0 +1,31 @@ +Freescale FlexTimer Module (FTM) Timer + +Required properties: + +- compatible : should be "fsl,ftm-timer" +- reg : Specifies base physical address and size of the register sets for the + clock event device and clock source device. +- interrupts : Should be the clock event device interrupt. +- clocks : The clocks provided by the SoC to drive the timer, must contain an + entry for each entry in clock-names. +- clock-names : Must include the following entries: + o "ftm-evt" + o "ftm-src" + o "ftm-evt-counter-en" + o "ftm-src-counter-en" +- big-endian: One boolean property, the big endian mode will be in use if it is + present, or the little endian mode will be in use for all the device registers. + +Example: +ftm: ftm@400b8000 { + compatible = "fsl,ftm-timer"; + reg = <0x400b8000 0x1000 0x400b9000 0x1000>; + interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "ftm-evt", "ftm-src", + "ftm-evt-counter-en", "ftm-src-counter-en"; + clocks = <&clks VF610_CLK_FTM2>, + <&clks VF610_CLK_FTM3>, + <&clks VF610_CLK_FTM2_EXT_FIX_EN>, + <&clks VF610_CLK_FTM3_EXT_FIX_EN>; + big-endian; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/fsl,gtm.txt b/arch/arm64/boot/dts/vendor/bindings/timer/fsl,gtm.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc1c571f74123d2293bf5c3af3197000d46a07ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/fsl,gtm.txt @@ -0,0 +1,30 @@ +* Freescale General-purpose Timers Module + +Required properties: + - compatible : should be + "fsl,-gtm", "fsl,gtm" for SOC GTMs + "fsl,-qe-gtm", "fsl,qe-gtm", "fsl,gtm" for QE GTMs + "fsl,-cpm2-gtm", "fsl,cpm2-gtm", "fsl,gtm" for CPM2 GTMs + - reg : should contain gtm registers location and length (0x40). + - interrupts : should contain four interrupts. + - clock-frequency : specifies the frequency driving the timer. + +Example: + +timer@500 { + compatible = "fsl,mpc8360-gtm", "fsl,gtm"; + reg = <0x500 0x40>; + interrupts = <90 8 78 8 84 8 72 8>; + interrupt-parent = <&ipic>; + /* filled by u-boot */ + clock-frequency = <0>; +}; + +timer@440 { + compatible = "fsl,mpc8360-qe-gtm", "fsl,qe-gtm", "fsl,gtm"; + reg = <0x440 0x40>; + interrupts = <12 13 14 15>; + interrupt-parent = <&qeic>; + /* filled by u-boot */ + clock-frequency = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/fsl,imxgpt.txt b/arch/arm64/boot/dts/vendor/bindings/timer/fsl,imxgpt.txt new file mode 100644 index 0000000000000000000000000000000000000000..9809b11f7180fa427b284d68ba484088025d1a18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/fsl,imxgpt.txt @@ -0,0 +1,18 @@ +Freescale i.MX General Purpose Timer (GPT) + +Required properties: + +- compatible : should be "fsl,-gpt" +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 4 interrupts; one per timer channel. +- clocks : The clocks provided by the SoC to drive the timer. + +Example: + +gpt1: timer@10003000 { + compatible = "fsl,imx27-gpt", "fsl,imx1-gpt"; + reg = <0x10003000 0x1000>; + interrupts = <26>; + clocks = <&clks 46>, <&clks 61>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/img,pistachio-gptimer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/img,pistachio-gptimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..7afce80bf6a0160e1d209d40a38c6172000199dd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/img,pistachio-gptimer.txt @@ -0,0 +1,28 @@ +* Pistachio general-purpose timer based clocksource + +Required properties: + - compatible: "img,pistachio-gptimer". + - reg: Address range of the timer registers. + - interrupts: An interrupt for each of the four timers + - clocks: Should contain a clock specifier for each entry in clock-names + - clock-names: Should contain the following entries: + "sys", interface clock + "slow", slow counter clock + "fast", fast counter clock + - img,cr-periph: Must contain a phandle to the peripheral control + syscon node. + +Example: + timer: timer@18102000 { + compatible = "img,pistachio-gptimer"; + reg = <0x18102000 0x100>; + interrupts = , + , + , + ; + clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>, + <&clk_periph PERIPH_CLK_COUNTER_SLOW>, + <&cr_periph SYS_CLK_TIMER>; + clock-names = "fast", "slow", "sys"; + img,cr-periph = <&cr_periph>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/jcore,pit.txt b/arch/arm64/boot/dts/vendor/bindings/timer/jcore,pit.txt new file mode 100644 index 0000000000000000000000000000000000000000..af5dd35469d73491a6714ec90d99e11bf8fded66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/jcore,pit.txt @@ -0,0 +1,24 @@ +J-Core Programmable Interval Timer and Clocksource + +Required properties: + +- compatible: Must be "jcore,pit". + +- reg: Memory region(s) for timer/clocksource registers. For SMP, + there should be one region per cpu, indexed by the sequential, + zero-based hardware cpu number. + +- interrupts: An interrupt to assign for the timer. The actual pit + core is integrated with the aic and allows the timer interrupt + assignment to be programmed by software, but this property is + required in order to reserve an interrupt number that doesn't + conflict with other devices. + + +Example: + +timer@200 { + compatible = "jcore,pit"; + reg = < 0x200 0x30 0x500 0x30 >; + interrupts = < 0x48 >; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/lsi,zevio-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/lsi,zevio-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2d07ad90e9a91599c899daeef80810d721c6d05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/lsi,zevio-timer.txt @@ -0,0 +1,33 @@ +TI-NSPIRE timer + +Required properties: + +- compatible : should be "lsi,zevio-timer". +- reg : The physical base address and size of the timer (always first). +- clocks: phandle to the source clock. + +Optional properties: + +- interrupts : The interrupt number of the first timer. +- reg : The interrupt acknowledgement registers + (always after timer base address) + +If any of the optional properties are not given, the timer is added as a +clock-source only. + +Example: + +timer { + compatible = "lsi,zevio-timer"; + reg = <0x900D0000 0x1000>, <0x900A0020 0x8>; + interrupts = <19>; + clocks = <&timer_clk>; +}; + +Example (no clock-events): + +timer { + compatible = "lsi,zevio-timer"; + reg = <0x900D0000 0x1000>; + clocks = <&timer_clk>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/marvell,armada-370-xp-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/marvell,armada-370-xp-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9c78ce880e600c3413a4d96f5cc39d72f4d59ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/marvell,armada-370-xp-timer.txt @@ -0,0 +1,44 @@ +Marvell Armada 370 and Armada XP Timers +--------------------------------------- + +Required properties: +- compatible: Should be one of the following + "marvell,armada-370-timer", + "marvell,armada-375-timer", + "marvell,armada-xp-timer". +- interrupts: Should contain the list of Global Timer interrupts and + then local timer interrupts +- reg: Should contain location and length for timers register. First + pair for the Global Timer registers, second pair for the + local/private timers. + +Clocks required for compatible = "marvell,armada-370-timer": +- clocks : Must contain a single entry describing the clock input + +Clocks required for compatibles = "marvell,armada-xp-timer", + "marvell,armada-375-timer": +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Must include the following entries: + "nbclk" (L2/coherency fabric clock), + "fixed" (Reference 25 MHz fixed-clock). + +Examples: + +- Armada 370: + + timer { + compatible = "marvell,armada-370-timer"; + reg = <0x20300 0x30>, <0x21040 0x30>; + interrupts = <37>, <38>, <39>, <40>, <5>, <6>; + clocks = <&coreclk 2>; + }; + +- Armada XP: + + timer { + compatible = "marvell,armada-xp-timer"; + reg = <0x20300 0x30>, <0x21040 0x30>; + interrupts = <37>, <38>, <39>, <40>, <5>, <6>; + clocks = <&coreclk 2>, <&refclk>; + clock-names = "nbclk", "fixed"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/marvell,orion-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/marvell,orion-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd1a0c256f940aee48018030c4a21af8a1bef7cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/marvell,orion-timer.txt @@ -0,0 +1,16 @@ +Marvell Orion SoC timer + +Required properties: +- compatible: shall be "marvell,orion-timer" +- reg: base address of the timer register starting with TIMERS CONTROL register +- interrupts: should contain the interrupts for Timer0 and Timer1 +- clocks: phandle of timer reference clock (tclk) + +Example: + timer: timer { + compatible = "marvell,orion-timer"; + reg = <0x20300 0x20>; + interrupt-parent = <&bridge_intc>; + interrupts = <1>, <2>; + clocks = <&core_clk 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/mediatek,mtk-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/mediatek,mtk-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..18d4d0166c76bff5dc35a3eccdd94781a68ed494 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/mediatek,mtk-timer.txt @@ -0,0 +1,31 @@ +Mediatek Timers +--------------- + +Mediatek SoCs have two different timers on different platforms, +- GPT (General Purpose Timer) +- SYST (System Timer) + +The proper timer will be selected automatically by driver. + +Required properties: +- compatible should contain: + * "mediatek,mt2701-timer" for MT2701 compatible timers (GPT) + * "mediatek,mt6580-timer" for MT6580 compatible timers (GPT) + * "mediatek,mt6589-timer" for MT6589 compatible timers (GPT) + * "mediatek,mt7623-timer" for MT7623 compatible timers (GPT) + * "mediatek,mt8127-timer" for MT8127 compatible timers (GPT) + * "mediatek,mt8135-timer" for MT8135 compatible timers (GPT) + * "mediatek,mt8173-timer" for MT8173 compatible timers (GPT) + * "mediatek,mt6577-timer" for MT6577 and all above compatible timers (GPT) + * "mediatek,mt6765-timer" for MT6765 compatible timers (SYST) +- reg: Should contain location and length for timer register. +- clocks: Should contain system clock. + +Examples: + + timer@10008000 { + compatible = "mediatek,mt6577-timer"; + reg = <0x10008000 0x80>; + interrupts = ; + clocks = <&system_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/mrvl,mmp-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/mrvl,mmp-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a6e251462e72c2b84d81cb22a1cd12a3efb3a28 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/mrvl,mmp-timer.txt @@ -0,0 +1,13 @@ +* Marvell MMP Timer controller + +Required properties: +- compatible : Should be "mrvl,mmp-timer". +- reg : Address and length of the register set of timer controller. +- interrupts : Should be the interrupt number. + +Example: + timer0: timer@d4014000 { + compatible = "mrvl,mmp-timer"; + reg = <0xd4014000 0x100>; + interrupts = <13>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/nuvoton,npcm7xx-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/nuvoton,npcm7xx-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..ea22dfe485beec11253c502c85943faa32593217 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/nuvoton,npcm7xx-timer.txt @@ -0,0 +1,21 @@ +Nuvoton NPCM7xx timer + +Nuvoton NPCM7xx have three timer modules, each timer module provides five 24-bit +timer counters. + +Required properties: +- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750. +- reg : Offset and length of the register set for the device. +- interrupts : Contain the timer interrupt with flags for + falling edge. +- clocks : phandle of timer reference clock (usually a 25 MHz clock). + +Example: + +timer@f0008000 { + compatible = "nuvoton,npcm750-timer"; + interrupts = ; + reg = <0xf0008000 0x50>; + clocks = <&clk NPCM7XX_CLK_TIMER>; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/nvidia,tegra20-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/nvidia,tegra20-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..4a864bd10d3d3cb8a9eb32c95a0e2899dbb97f4c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/nvidia,tegra20-timer.txt @@ -0,0 +1,24 @@ +NVIDIA Tegra20 timer + +The Tegra20 timer provides four 29-bit timer channels and a single 32-bit free +running counter. The first two channels may also trigger a watchdog reset. + +Required properties: + +- compatible : should be "nvidia,tegra20-timer". +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 4 interrupts; one per timer channel. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +Example: + +timer { + compatible = "nvidia,tegra20-timer"; + reg = <0x60005000 0x60>; + interrupts = <0 0 0x04 + 0 1 0x04 + 0 41 0x04 + 0 42 0x04>; + clocks = <&tegra_car 132>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/nvidia,tegra30-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/nvidia,tegra30-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..1761f53ee36f71162082e4040612889d9073d3d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/nvidia,tegra30-timer.txt @@ -0,0 +1,28 @@ +NVIDIA Tegra30 timer + +The Tegra30 timer provides ten 29-bit timer channels, a single 32-bit free +running counter, and 5 watchdog modules. The first two channels may also +trigger a legacy watchdog reset. + +Required properties: + +- compatible : For Tegra30, must contain "nvidia,tegra30-timer". Otherwise, + must contain '"nvidia,-timer", "nvidia,tegra30-timer"' where + is tegra124 or tegra132. +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 6 interrupts; one per each of timer channels 1 + through 5, and one for the shared interrupt for the remaining channels. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + +timer { + compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer"; + reg = <0x60005000 0x400>; + interrupts = <0 0 0x04 + 0 1 0x04 + 0 41 0x04 + 0 42 0x04 + 0 121 0x04 + 0 122 0x04>; + clocks = <&tegra_car 214>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/nxp,lpc3220-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/nxp,lpc3220-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..51b05a0e70d19118184f93bf14707cc678793813 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/nxp,lpc3220-timer.txt @@ -0,0 +1,26 @@ +* NXP LPC3220 timer + +The NXP LPC3220 timer is used on a wide range of NXP SoCs. This +includes LPC32xx, LPC178x, LPC18xx and LPC43xx parts. + +Required properties: +- compatible: + Should be "nxp,lpc3220-timer". +- reg: + Address and length of the register set. +- interrupts: + Reference to the timer interrupt +- clocks: + Should contain a reference to timer clock. +- clock-names: + Should contain "timerclk". + +Example: + +timer1: timer@40085000 { + compatible = "nxp,lpc3220-timer"; + reg = <0x40085000 0x1000>; + interrupts = <13>; + clocks = <&ccu1 CLK_CPU_TIMER1>; + clock-names = "timerclk"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/nxp,tpm-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/nxp,tpm-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..f82087b220f415976754db8b30c9297da8da3303 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/nxp,tpm-timer.txt @@ -0,0 +1,28 @@ +NXP Low Power Timer/Pulse Width Modulation Module (TPM) + +The Timer/PWM Module (TPM) supports input capture, output compare, +and the generation of PWM signals to control electric motor and power +management applications. The counter, compare and capture registers +are clocked by an asynchronous clock that can remain enabled in low +power modes. TPM can support global counter bus where one TPM drives +the counter bus for the others, provided bit width is the same. + +Required properties: + +- compatible : should be "fsl,imx7ulp-tpm" +- reg : Specifies base physical address and size of the register sets + for the clock event device and clock source device. +- interrupts : Should be the clock event device interrupt. +- clocks : The clocks provided by the SoC to drive the timer, must contain + an entry for each entry in clock-names. +- clock-names : Must include the following entries: "ipg" and "per". + +Example: +tpm5: tpm@40260000 { + compatible = "fsl,imx7ulp-tpm"; + reg = <0x40260000 0x1000>; + interrupts = ; + clocks = <&clks IMX7ULP_CLK_NIC1_BUS_DIV>, + <&clks IMX7ULP_CLK_LPTPM5>; + clock-names = "ipg", "per"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/oxsemi,rps-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/oxsemi,rps-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..d191612539e8867129504b569e6c6a82e7514069 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/oxsemi,rps-timer.txt @@ -0,0 +1,17 @@ +Oxford Semiconductor OXNAS SoCs Family RPS Timer +================================================ + +Required properties: +- compatible: Should be "oxsemi,ox810se-rps-timer" or "oxsemi,ox820-rps-timer" +- reg : Specifies base physical address and size of the registers. +- interrupts : The interrupts of the two timers +- clocks : The phandle of the timer clock source + +example: + +timer0: timer@200 { + compatible = "oxsemi,ox810se-rps-timer"; + reg = <0x200 0x40>; + clocks = <&rpsclk>; + interrupts = <4 5>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/qcom,msm-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/qcom,msm-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..5e10c345548f56b18422c9995b6fe0bdaa33d7b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/qcom,msm-timer.txt @@ -0,0 +1,47 @@ +* MSM Timer + +Properties: + +- compatible : Should at least contain "qcom,msm-timer". More specific + properties specify which subsystem the timers are paired with. + + "qcom,kpss-timer" - krait subsystem + "qcom,scss-timer" - scorpion subsystem + +- interrupts : Interrupts for the debug timer, the first general purpose + timer, and optionally a second general purpose timer, and + optionally as well, 2 watchdog interrupts, in that order. + +- reg : Specifies the base address of the timer registers. + +- clocks: Reference to the parent clocks, one per output clock. The parents + must appear in the same order as the clock names. + +- clock-names: The name of the clocks as free-form strings. They should be in + the same order as the clocks. + +- clock-frequency : The frequency of the debug timer and the general purpose + timer(s) in Hz in that order. + +Optional: + +- cpu-offset : per-cpu offset used when the timer is accessed without the + CPU remapping facilities. The offset is + cpu-offset + (0x10000 * cpu-nr). + +Example: + + timer@200a000 { + compatible = "qcom,scss-timer", "qcom,msm-timer"; + interrupts = <1 1 0x301>, + <1 2 0x301>, + <1 3 0x301>, + <1 4 0x301>, + <1 5 0x301>; + reg = <0x0200a000 0x100>; + clock-frequency = <19200000>, + <32768>; + clocks = <&sleep_clk>; + clock-names = "sleep"; + cpu-offset = <0x40000>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,16bit-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,16bit-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8792447a199bdb59ee55790dab79b9476a319f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,16bit-timer.txt @@ -0,0 +1,25 @@ +* Renesas H8/300 16bit timer + +The 16bit timer is a 16bit timer/counter with configurable clock inputs and +programmable compare match. + +Required Properties: + + - compatible: must contain "renesas,16bit-timer" + - reg: base address and length of the registers block for the timer module. + - interrupts: interrupt-specifier for the timer, IMIA + - clocks: a list of phandle, one for each entry in clock-names. + - clock-names: must contain "peripheral_clk" for the functional clock. + - renesas,channel: timer channel number. + +Example: + + timer16: timer@ffff68 { + compatible = "reneas,16bit-timer"; + reg = <0xffff68 8>, <0xffff60 8>; + interrupts = <24>; + renesas,channel = <0>; + clocks = <&pclk>; + clock-names = "peripheral_clk"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,8bit-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,8bit-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..9dca3759a0f024d8187d0669df1abe171517822f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,8bit-timer.txt @@ -0,0 +1,25 @@ +* Renesas H8/300 8bit timer + +The 8bit timer is a 8bit timer/counter with configurable clock inputs and +programmable compare match. + +This implement only supported cascade mode. + +Required Properties: + + - compatible: must contain "renesas,8bit-timer" + - reg: base address and length of the registers block for the timer module. + - interrupts: interrupt-specifier for the timer, CMIA and TOVI + - clocks: a list of phandle, one for each entry in clock-names. + - clock-names: must contain "fck" for the functional clock. + +Example: + + timer8_0: timer@ffff80 { + compatible = "renesas,8bit-timer"; + reg = <0xffff80 10>; + interrupts = <36>; + clocks = <&fclk>; + clock-names = "fck"; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,cmt.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,cmt.txt new file mode 100644 index 0000000000000000000000000000000000000000..b40add2d9bb485ecd3ea395669da1e43e9e31a1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,cmt.txt @@ -0,0 +1,76 @@ +* Renesas R-Car Compare Match Timer (CMT) + +The CMT is a multi-channel 16/32/48-bit timer/counter with configurable clock +inputs and programmable compare match. + +Channels share hardware resources but their counter and compare match value +are independent. A particular CMT instance can implement only a subset of the +channels supported by the CMT model. Channel indices represent the hardware +position of the channel in the CMT and don't match the channel numbers in the +datasheets. + +Required Properties: + + - compatible: must contain one or more of the following: + - "renesas,cmt-48-sh73a0" for the sh73A0 48-bit CMT + (CMT1) + - "renesas,cmt-48-r8a7740" for the r8a7740 48-bit CMT + (CMT1) + - "renesas,cmt-48" for all non-second generation 48-bit CMT + (CMT1 on sh73a0 and r8a7740) + This is a fallback for the above renesas,cmt-48-* entries. + + - "renesas,r8a73a4-cmt0" for the 32-bit CMT0 device included in r8a73a4. + - "renesas,r8a73a4-cmt1" for the 48-bit CMT1 device included in r8a73a4. + - "renesas,r8a7743-cmt0" for the 32-bit CMT0 device included in r8a7743. + - "renesas,r8a7743-cmt1" for the 48-bit CMT1 device included in r8a7743. + - "renesas,r8a7745-cmt0" for the 32-bit CMT0 device included in r8a7745. + - "renesas,r8a7745-cmt1" for the 48-bit CMT1 device included in r8a7745. + - "renesas,r8a7790-cmt0" for the 32-bit CMT0 device included in r8a7790. + - "renesas,r8a7790-cmt1" for the 48-bit CMT1 device included in r8a7790. + - "renesas,r8a7791-cmt0" for the 32-bit CMT0 device included in r8a7791. + - "renesas,r8a7791-cmt1" for the 48-bit CMT1 device included in r8a7791. + - "renesas,r8a7793-cmt0" for the 32-bit CMT0 device included in r8a7793. + - "renesas,r8a7793-cmt1" for the 48-bit CMT1 device included in r8a7793. + - "renesas,r8a7794-cmt0" for the 32-bit CMT0 device included in r8a7794. + - "renesas,r8a7794-cmt1" for the 48-bit CMT1 device included in r8a7794. + + - "renesas,rcar-gen2-cmt0" for 32-bit CMT0 devices included in R-Car Gen2 + and RZ/G1. + - "renesas,rcar-gen2-cmt1" for 48-bit CMT1 devices included in R-Car Gen2 + and RZ/G1. + These are fallbacks for r8a73a4, R-Car Gen2 and RZ/G1 entries + listed above. + + - reg: base address and length of the registers block for the timer module. + - interrupts: interrupt-specifier for the timer, one per channel. + - clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. + - clock-names: must contain "fck" for the functional clock. + + +Example: R8A7790 (R-Car H2) CMT0 and CMT1 nodes + + cmt0: timer@ffca0000 { + compatible = "renesas,r8a7790-cmt0", "renesas,rcar-gen2-cmt0"; + reg = <0 0xffca0000 0 0x1004>; + interrupts = <0 142 IRQ_TYPE_LEVEL_HIGH>, + <0 142 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_CMT0>; + clock-names = "fck"; + }; + + cmt1: timer@e6130000 { + compatible = "renesas,r8a7790-cmt1", "renesas,rcar-gen2-cmt1"; + reg = <0 0xe6130000 0 0x1004>; + interrupts = <0 120 IRQ_TYPE_LEVEL_HIGH>, + <0 121 IRQ_TYPE_LEVEL_HIGH>, + <0 122 IRQ_TYPE_LEVEL_HIGH>, + <0 123 IRQ_TYPE_LEVEL_HIGH>, + <0 124 IRQ_TYPE_LEVEL_HIGH>, + <0 125 IRQ_TYPE_LEVEL_HIGH>, + <0 126 IRQ_TYPE_LEVEL_HIGH>, + <0 127 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_CMT1>; + clock-names = "fck"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,mtu2.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,mtu2.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba0a34d97eb80261b98df15737110c614fbd28c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,mtu2.txt @@ -0,0 +1,42 @@ +* Renesas Multi-Function Timer Pulse Unit 2 (MTU2) + +The MTU2 is a multi-purpose, multi-channel timer/counter with configurable +clock inputs and programmable compare match. + +Channels share hardware resources but their counter and compare match value +are independent. The MTU2 hardware supports five channels indexed from 0 to 4. + +Required Properties: + + - compatible: must be one or more of the following: + - "renesas,mtu2-r7s72100" for the r7s72100 MTU2 + - "renesas,mtu2" for any MTU2 + This is a fallback for the above renesas,mtu2-* entries + + - reg: base address and length of the registers block for the timer module. + + - interrupts: interrupt specifiers for the timer, one for each entry in + interrupt-names. + - interrupt-names: must contain one entry named "tgi?a" for each enabled + channel, where "?" is the channel index expressed as one digit from "0" to + "4". + + - clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. + - clock-names: must contain "fck" for the functional clock. + + +Example: R7S72100 (RZ/A1H) MTU2 node + + mtu2: timer@fcff0000 { + compatible = "renesas,mtu2-r7s72100", "renesas,mtu2"; + reg = <0xfcff0000 0x400>; + interrupts = <0 139 IRQ_TYPE_LEVEL_HIGH>, + <0 146 IRQ_TYPE_LEVEL_HIGH>, + <0 150 IRQ_TYPE_LEVEL_HIGH>, + <0 154 IRQ_TYPE_LEVEL_HIGH>, + <0 159 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tgi0a", "tgi1a", "tgi2a", "tgi3a", "tgi4a"; + clocks = <&mstp3_clks R7S72100_CLK_MTU2>; + clock-names = "fck"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,ostm.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,ostm.txt new file mode 100644 index 0000000000000000000000000000000000000000..be3ae0fdf77502e11ff129c1d1b5b1e6aa924aa7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,ostm.txt @@ -0,0 +1,30 @@ +* Renesas OS Timer (OSTM) + +The OSTM is a multi-channel 32-bit timer/counter with fixed clock +source that can operate in either interval count down timer or free-running +compare match mode. + +Channels are independent from each other. + +Required Properties: + + - compatible: must be one or more of the following: + - "renesas,r7s72100-ostm" for the r7s72100 OSTM + - "renesas,ostm" for any OSTM + This is a fallback for the above renesas,*-ostm entries + + - reg: base address and length of the register block for a timer channel. + + - interrupts: interrupt specifier for the timer channel. + + - clocks: clock specifier for the timer channel. + +Example: R7S72100 (RZ/A1H) OSTM node + + ostm0: timer@fcfec000 { + compatible = "renesas,r7s72100-ostm", "renesas,ostm"; + reg = <0xfcfec000 0x30>; + interrupts = ; + clocks = <&mstp5_clks R7S72100_CLK_OSTM0>; + power-domains = <&cpg_clocks>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,tmu.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,tmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd5f20bf2582e742c426018d91d31c652767d7fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,tmu.txt @@ -0,0 +1,44 @@ +* Renesas R-Mobile/R-Car Timer Unit (TMU) + +The TMU is a 32-bit timer/counter with configurable clock inputs and +programmable compare match. + +Channels share hardware resources but their counter and compare match value +are independent. The TMU hardware supports up to three channels. + +Required Properties: + + - compatible: must contain one or more of the following: + - "renesas,tmu-r8a7740" for the r8a7740 TMU + - "renesas,tmu-r8a7778" for the r8a7778 TMU + - "renesas,tmu-r8a7779" for the r8a7779 TMU + - "renesas,tmu" for any TMU. + This is a fallback for the above renesas,tmu-* entries + + - reg: base address and length of the registers block for the timer module. + + - interrupts: interrupt-specifier for the timer, one per channel. + + - clocks: a list of phandle + clock-specifier pairs, one for each entry + in clock-names. + - clock-names: must contain "fck" for the functional clock. + +Optional Properties: + + - #renesas,channels: number of channels implemented by the timer, must be 2 + or 3 (if not specified the value defaults to 3). + + +Example: R8A7779 (R-Car H1) TMU0 node + + tmu0: timer@ffd80000 { + compatible = "renesas,tmu-r8a7779", "renesas,tmu"; + reg = <0xffd80000 0x30>; + interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>, + <0 33 IRQ_TYPE_LEVEL_HIGH>, + <0 34 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7779_CLK_TMU0>; + clock-names = "fck"; + + #renesas,channels = <3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/renesas,tpu.txt b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,tpu.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d46f9de4feb8a8426411cb9ad997c3e1739ca0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/renesas,tpu.txt @@ -0,0 +1,21 @@ +* Renesas H8/300 Timer Pulse Unit + +The TPU is a 16bit timer/counter with configurable clock inputs and +programmable compare match. +This implementation support only cascade mode. + +Required Properties: + + - compatible: must contain "renesas,tpu" + - reg: base address and length of the registers block in 2 channel. + - clocks: a list of phandle, one for each entry in clock-names. + - clock-names: must contain "peripheral_clk" for the functional clock. + + +Example: + tpu: tpu@ffffe0 { + compatible = "renesas,tpu"; + reg = <0xffffe0 16>, <0xfffff0 12>; + clocks = <&pclk>; + clock-names = "peripheral_clk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/rockchip,rk-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/rockchip,rk-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..16a5f4577a61886be16103aedf1a38539d4248b3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/rockchip,rk-timer.txt @@ -0,0 +1,26 @@ +Rockchip rk timer + +Required properties: +- compatible: should be: + "rockchip,rk3036-timer", "rockchip,rk3288-timer": for Rockchip RK3036 + "rockchip,rk3066-timer", "rockchip,rk3288-timer": for Rockchip RK3066 + "rockchip,rk3188-timer", "rockchip,rk3288-timer": for Rockchip RK3188 + "rockchip,rk3228-timer", "rockchip,rk3288-timer": for Rockchip RK3228 + "rockchip,rk3229-timer", "rockchip,rk3288-timer": for Rockchip RK3229 + "rockchip,rk3288-timer": for Rockchip RK3288 + "rockchip,rk3368-timer", "rockchip,rk3288-timer": for Rockchip RK3368 + "rockchip,rk3399-timer": for Rockchip RK3399 +- reg: base address of the timer register starting with TIMERS CONTROL register +- interrupts: should contain the interrupts for Timer0 +- clocks : must contain an entry for each entry in clock-names +- clock-names : must include the following entries: + "timer", "pclk" + +Example: + timer: timer@ff810000 { + compatible = "rockchip,rk3288-timer"; + reg = <0xff810000 0x20>; + interrupts = ; + clocks = <&xin24m>, <&cru PCLK_TIMER>; + clock-names = "timer", "pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/samsung,exynos4210-mct.txt b/arch/arm64/boot/dts/vendor/bindings/timer/samsung,exynos4210-mct.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f78640ad64c61ec163843585732ddc8fb2d66db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/samsung,exynos4210-mct.txt @@ -0,0 +1,88 @@ +Samsung's Multi Core Timer (MCT) + +The Samsung's Multi Core Timer (MCT) module includes two main blocks, the +global timer and CPU local timers. The global timer is a 64-bit free running +up-counter and can generate 4 interrupts when the counter reaches one of the +four preset counter values. The CPU local timers are 32-bit free running +down-counters and generate an interrupt when the counter expires. There is +one CPU local timer instantiated in MCT for every CPU in the system. + +Required properties: + +- compatible: should be "samsung,exynos4210-mct". + (a) "samsung,exynos4210-mct", for mct compatible with Exynos4210 mct. + (b) "samsung,exynos4412-mct", for mct compatible with Exynos4412 mct. + +- reg: base address of the mct controller and length of the address space + it occupies. + +- interrupts: the list of interrupts generated by the controller. The following + should be the order of the interrupts specified. The local timer interrupts + should be specified after the four global timer interrupts have been + specified. + + 0: Global Timer Interrupt 0 + 1: Global Timer Interrupt 1 + 2: Global Timer Interrupt 2 + 3: Global Timer Interrupt 3 + 4: Local Timer Interrupt 0 + 5: Local Timer Interrupt 1 + 6: .. + 7: .. + i: Local Timer Interrupt n + + For MCT block that uses a per-processor interrupt for local timers, such + as ones compatible with "samsung,exynos4412-mct", only one local timer + interrupt might be specified, meaning that all local timers use the same + per processor interrupt. + +Example 1: In this example, the IP contains two local timers, using separate + interrupts, so two local timer interrupts have been specified, + in addition to four global timer interrupts. + + mct@10050000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x10050000 0x800>; + interrupts = <0 57 0>, <0 69 0>, <0 70 0>, <0 71 0>, + <0 42 0>, <0 48 0>; + }; + +Example 2: In this example, the timer interrupts are connected to two separate + interrupt controllers. Hence, an interrupt-map is created to map + the interrupts to the respective interrupt controllers. + + mct@101c0000 { + compatible = "samsung,exynos4210-mct"; + reg = <0x101C0000 0x800>; + interrupt-parent = <&mct_map>; + interrupts = <0>, <1>, <2>, <3>, <4>, <5>; + + mct_map: mct-map { + #interrupt-cells = <1>; + #address-cells = <0>; + #size-cells = <0>; + interrupt-map = <0 &gic 0 57 0>, + <1 &gic 0 69 0>, + <2 &combiner 12 6>, + <3 &combiner 12 7>, + <4 &gic 0 42 0>, + <5 &gic 0 48 0>; + }; + }; + +Example 3: In this example, the IP contains four local timers, but using + a per-processor interrupt to handle them. Either all the local + timer interrupts can be specified, with the same interrupt specifier + value or just the first one. + + mct@10050000 { + compatible = "samsung,exynos4412-mct"; + reg = <0x10050000 0x800>; + + /* Both ways are possible in this case. Either: */ + interrupts = <0 57 0>, <0 69 0>, <0 70 0>, <0 71 0>, + <0 42 0>; + /* or: */ + interrupts = <0 57 0>, <0 69 0>, <0 70 0>, <0 71 0>, + <0 42 0>, <0 42 0>, <0 42 0>, <0 42 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/snps,arc-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/snps,arc-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..147ef3e7445200055b9618646ad83237c33feadf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/snps,arc-timer.txt @@ -0,0 +1,27 @@ +Synopsys ARC Local Timer with Interrupt Capabilities +- Found on all ARC CPUs (ARC700/ARCHS) +- Can be optionally programmed to interrupt on Limit +- Two idential copies TIMER0 and TIMER1 exist in ARC cores and historically + TIMER0 used as clockevent provider (true for all ARC cores) + TIMER1 used for clocksource (mandatory for ARC700, optional for ARC HS) + +Required properties: + +- compatible : should be "snps,arc-timer" +- interrupts : single Interrupt going into parent intc + (16 for ARCHS cores, 3 for ARC700 cores) +- clocks : phandle to the source clock + +Example: + + timer0 { + compatible = "snps,arc-timer"; + interrupts = <3>; + interrupt-parent = <&core_intc>; + clocks = <&core_clk>; + }; + + timer1 { + compatible = "snps,arc-timer"; + clocks = <&core_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/snps,archs-gfrc.txt b/arch/arm64/boot/dts/vendor/bindings/timer/snps,archs-gfrc.txt new file mode 100644 index 0000000000000000000000000000000000000000..b6cd1b3922ded63ce68d49327ce7844eef533b51 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/snps,archs-gfrc.txt @@ -0,0 +1,14 @@ +Synopsys ARC Free Running 64-bit Global Timer for ARC HS CPUs +- clocksource provider for SMP SoC + +Required properties: + +- compatible : should be "snps,archs-gfrc" +- clocks : phandle to the source clock + +Example: + + gfrc { + compatible = "snps,archs-gfrc"; + clocks = <&core_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/snps,archs-rtc.txt b/arch/arm64/boot/dts/vendor/bindings/timer/snps,archs-rtc.txt new file mode 100644 index 0000000000000000000000000000000000000000..47bd7a702f3f6104aa926d8bf024491581c9f840 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/snps,archs-rtc.txt @@ -0,0 +1,14 @@ +Synopsys ARC Free Running 64-bit Local Timer for ARC HS CPUs +- clocksource provider for UP SoC + +Required properties: + +- compatible : should be "snps,archs-rtc" +- clocks : phandle to the source clock + +Example: + + rtc { + compatible = "snps,arc-rtc"; + clocks = <&core_clk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/spreadtrum,sprd-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/spreadtrum,sprd-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d97e7d0f6e86fdd5995bd41e1d54f5a7cf4843d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/spreadtrum,sprd-timer.txt @@ -0,0 +1,20 @@ +Spreadtrum timers + +The Spreadtrum SC9860 platform provides 3 general-purpose timers. +These timers can support 32bit or 64bit counter, as well as supporting +period mode or one-shot mode, and they are can be wakeup source +during deep sleep. + +Required properties: +- compatible: should be "sprd,sc9860-timer" for SC9860 platform. +- reg: The register address of the timer device. +- interrupts: Should contain the interrupt for the timer device. +- clocks: The phandle to the source clock (usually a 32.768 KHz fixed clock). + +Example: + timer@40050000 { + compatible = "sprd,sc9860-timer"; + reg = <0 0x40050000 0 0x20>; + interrupts = ; + clocks = <&ext_32k>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/st,spear-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/st,spear-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5238a07da1716d31b9291c8e50b3013aef7274c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/st,spear-timer.txt @@ -0,0 +1,16 @@ +* SPEAr ARM Timer + +** Timer node required properties: + +- compatible : Should be: + "st,spear-timer" +- reg: Address range of the timer registers +- interrupt: Should contain the timer interrupt number + +Example: + + timer@f0000000 { + compatible = "st,spear-timer"; + reg = <0xf0000000 0x400>; + interrupts = <2>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/st,stih407-lpc b/arch/arm64/boot/dts/vendor/bindings/timer/st,stih407-lpc new file mode 100644 index 0000000000000000000000000000000000000000..72acb487b856dfc88983396e5ac17dd03f4b2db7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/st,stih407-lpc @@ -0,0 +1,28 @@ +STMicroelectronics Low Power Controller (LPC) - Clocksource +=========================================================== + +LPC currently supports Watchdog OR Real Time Clock OR Clocksource +functionality. + +[See: ../watchdog/st_lpc_wdt.txt for Watchdog options] +[See: ../rtc/rtc-st-lpc.txt for RTC options] + +Required properties + +- compatible : Must be: "st,stih407-lpc" +- reg : LPC registers base address + size +- interrupts : LPC interrupt line number and associated flags +- clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) +- st,lpc-mode : The LPC can run either one of three modes: + ST_LPC_MODE_RTC [0] + ST_LPC_MODE_WDT [1] + ST_LPC_MODE_CLKSRC [2] + One (and only one) mode must be selected. + +Example: + lpc@fde05000 { + compatible = "st,stih407-lpc"; + reg = <0xfde05000 0x1000>; + clocks = <&clk_s_d3_flexgen CLK_LPC_0>; + st,lpc-mode = ; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/st,stm32-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/st,stm32-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ef28e70d6e84ef8f11dff80a34a226d861ff1ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/st,stm32-timer.txt @@ -0,0 +1,22 @@ +. STMicroelectronics STM32 timer + +The STM32 MCUs family has several general-purpose 16 and 32 bits timers. + +Required properties: +- compatible : Should be "st,stm32-timer" +- reg : Address and length of the register set +- clocks : Reference on the timer input clock +- interrupts : Reference to the timer interrupt + +Optional properties: +- resets: Reference to a reset controller asserting the timer + +Example: + +timer5: timer@40000c00 { + compatible = "st,stm32-timer"; + reg = <0x40000c00 0x400>; + interrupts = <50>; + resets = <&rrc 259>; + clocks = <&clk_pmtr1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/stericsson-u300-apptimer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/stericsson-u300-apptimer.txt new file mode 100644 index 0000000000000000000000000000000000000000..9499bc8ee9e33283561ddb1dcb0d8f2497346a94 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/stericsson-u300-apptimer.txt @@ -0,0 +1,18 @@ +ST-Ericsson U300 apptimer + +Required properties: + +- compatible : should be "stericsson,u300-apptimer" +- reg : Specifies base physical address and size of the registers. +- interrupts : A list of 4 interrupts; one for each subtimer. These + are, in order: OS (operating system), DD (device driver) both + adopted for EPOC/Symbian with two specific IRQs for these tasks, + then GP1 and GP2, which are general-purpose timers. + +Example: + +timer { + compatible = "stericsson,u300-apptimer"; + reg = <0xc0014000 0x1000>; + interrupts = <24 25 26 27>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/ti,c64x+timer64.txt b/arch/arm64/boot/dts/vendor/bindings/timer/ti,c64x+timer64.txt new file mode 100644 index 0000000000000000000000000000000000000000..d96c1e283e736c96c778b837efa5d80ee89991f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/ti,c64x+timer64.txt @@ -0,0 +1,25 @@ +Timer64 +------- + +The timer64 node describes C6X event timers. + +Required properties: + +- compatible: must be "ti,c64x+timer64" +- reg: base address and size of register region +- interrupts: interrupt id + +Optional properties: + +- ti,dscr-dev-enable: Device ID used to enable timer IP through DSCR interface. + +- ti,core-mask: on multi-core SoCs, bitmask of cores allowed to use this timer. + +Example: + timer0: timer@25e0000 { + compatible = "ti,c64x+timer64"; + ti,core-mask = < 0x01 >; + reg = <0x25e0000 0x40>; + interrupt-parent = <&megamod_pic>; + interrupts = < 16 >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/ti,davinci-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/ti,davinci-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..29bf91ccf5b754be4008f62053b181317b9f97e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/ti,davinci-timer.txt @@ -0,0 +1,37 @@ +* Device tree bindings for Texas Instruments DaVinci timer + +This document provides bindings for the 64-bit timer in the DaVinci +architecture devices. The timer can be configured as a general-purpose 64-bit +timer, dual general-purpose 32-bit timers. When configured as dual 32-bit +timers, each half can operate in conjunction (chain mode) or independently +(unchained mode) of each other. + +The timer is a free running up-counter and can generate interrupts when the +counter reaches preset counter values. + +Also see ../watchdog/davinci-wdt.txt for timers that are configurable as +watchdog timers. + +Required properties: + +- compatible : should be "ti,da830-timer". +- reg : specifies base physical address and count of the registers. +- interrupts : interrupts generated by the timer. +- interrupt-names: should be "tint12", "tint34", "cmpint0", "cmpint1", + "cmpint2", "cmpint3", "cmpint4", "cmpint5", "cmpint6", + "cmpint7" ("cmpintX" may be omitted if not present in the + hardware). +- clocks : the clock feeding the timer clock. + +Example: + + clocksource: timer@20000 { + compatible = "ti,da830-timer"; + reg = <0x20000 0x1000>; + interrupts = <21>, <22>, <74>, <75>, <76>, <77>, <78>, <79>, + <80>, <81>; + interrupt-names = "tint12", "tint34", "cmpint0", "cmpint1", + "cmpint2", "cmpint3", "cmpint4", "cmpint5", + "cmpint6", "cmpint7"; + clocks = <&pll0_auxclk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/ti,keystone-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/ti,keystone-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..5fbe361252b4dfaa802e7158b1fb801fe741968a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/ti,keystone-timer.txt @@ -0,0 +1,29 @@ +* Device tree bindings for Texas instruments Keystone timer + +This document provides bindings for the 64-bit timer in the KeyStone +architecture devices. The timer can be configured as a general-purpose 64-bit +timer, dual general-purpose 32-bit timers. When configured as dual 32-bit +timers, each half can operate in conjunction (chain mode) or independently +(unchained mode) of each other. + +It is global timer is a free running up-counter and can generate interrupt +when the counter reaches preset counter values. + +Documentation: +http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf + +Required properties: + +- compatible : should be "ti,keystone-timer". +- reg : specifies base physical address and count of the registers. +- interrupts : interrupt generated by the timer. +- clocks : the clock feeding the timer clock. + +Example: + +timer@22f0000 { + compatible = "ti,keystone-timer"; + reg = <0x022f0000 0x80>; + interrupts = ; + clocks = <&clktimer15>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/ti,timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/ti,timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..d02e27c764ecc4facab9bceeffa756693d8c0a98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/ti,timer.txt @@ -0,0 +1,44 @@ +OMAP Timer bindings + +Required properties: +- compatible: Should be set to one of the below. Please note that + OMAP44xx devices have timer instances that are 100% + register compatible with OMAP3xxx devices as well as + newer timers that are not 100% register compatible. + So for OMAP44xx devices timer instances may use + different compatible strings. + + ti,omap2420-timer (applicable to OMAP24xx devices) + ti,omap3430-timer (applicable to OMAP3xxx/44xx devices) + ti,omap4430-timer (applicable to OMAP44xx devices) + ti,omap5430-timer (applicable to OMAP543x devices) + ti,am335x-timer (applicable to AM335x devices) + ti,am335x-timer-1ms (applicable to AM335x devices) + +- reg: Contains timer register address range (base address and + length). +- interrupts: Contains the interrupt information for the timer. The + format is being dependent on which interrupt controller + the OMAP device uses. +- ti,hwmods: Name of the hwmod associated to the timer, "timer", + where is the instance number of the timer from the + HW spec. + +Optional properties: +- ti,timer-alwon: Indicates the timer is in an alway-on power domain. +- ti,timer-dsp: Indicates the timer can interrupt the on-chip DSP in + addition to the ARM CPU. +- ti,timer-pwm: Indicates the timer can generate a PWM output. +- ti,timer-secure: Indicates the timer is reserved on a secure OMAP device + and therefore cannot be used by the kernel. + +Example: + +timer12: timer@48304000 { + compatible = "ti,omap3430-timer"; + reg = <0x48304000 0x400>; + interrupts = <95>; + ti,hwmods = "timer12" + ti,timer-alwon; + ti,timer-secure; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/timer/via,vt8500-timer.txt b/arch/arm64/boot/dts/vendor/bindings/timer/via,vt8500-timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..901c73f0d8ef05fb54d517b807d04f80eef2e736 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/timer/via,vt8500-timer.txt @@ -0,0 +1,15 @@ +VIA/Wondermedia VT8500 Timer +----------------------------------------------------- + +Required properties: +- compatible : "via,vt8500-timer" +- reg : Should contain 1 register ranges(address and length) +- interrupts : interrupt for the timer + +Example: + + timer@d8130100 { + compatible = "via,vt8500-timer"; + reg = <0xd8130100 0x28>; + interrupts = <36>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/trivial-devices.txt b/arch/arm64/boot/dts/vendor/bindings/trivial-devices.txt new file mode 100644 index 0000000000000000000000000000000000000000..763a2808a95c806a278111686cc75227f971f08d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/trivial-devices.txt @@ -0,0 +1,201 @@ +This is a list of trivial i2c devices that have simple device tree +bindings, consisting only of a compatible field, an address and +possibly an interrupt line. + +If a device needs more specific bindings, such as properties to +describe some aspect of it, there needs to be a specific binding +document for it just like any other devices. + + +Compatible Vendor / Chip +========== ============= +abracon,abb5zes3 AB-RTCMC-32.768kHz-B5ZE-S3: Real Time Clock/Calendar Module with I2C Interface +ad,ad7414 SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert and Over Temperature Pin +ad,adm9240 ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems +adi,adt7461 +/-1C TDM Extended Temp Range I.C +adt7461 +/-1C TDM Extended Temp Range I.C +adi,adt7473 +/-1C TDM Extended Temp Range I.C +adi,adt7475 +/-1C TDM Extended Temp Range I.C +adi,adt7476 +/-1C TDM Extended Temp Range I.C +adi,adt7490 +/-1C TDM Extended Temp Range I.C +adi,adxl345 Three-Axis Digital Accelerometer +adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too) +ams,iaq-core AMS iAQ-Core VOC Sensor +amstaos,tsl2571 AMS/TAOS ALS and proximity sensor +amstaos,tsl2671 AMS/TAOS ALS and proximity sensor +amstaos,tmd2671 AMS/TAOS ALS and proximity sensor +amstaos,tsl2771 AMS/TAOS ALS and proximity sensor +amstaos,tmd2771 AMS/TAOS ALS and proximity sensor +amstaos,tsl2572 AMS/TAOS ALS and proximity sensor +amstaos,tsl2672 AMS/TAOS ALS and proximity sensor +amstaos,tmd2672 AMS/TAOS ALS and proximity sensor +amstaos,tsl2772 AMS/TAOS ALS and proximity sensor +amstaos,tmd2772 AMS/TAOS ALS and proximity sensor +at,24c08 i2c serial eeprom (24cxx) +atmel,at97sc3204t i2c trusted platform module (TPM) +capella,cm32181 CM32181: Ambient Light Sensor +capella,cm3232 CM3232: Ambient Light Sensor +cirrus,cs42l51 Cirrus Logic CS42L51 audio codec +dallas,ds1374 I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output +dallas,ds1631 High-Precision Digital Thermometer +dallas,ds1672 Dallas DS1672 Real-time Clock +dallas,ds1682 Total-Elapsed-Time Recorder with Alarm +dallas,ds1775 Tiny Digital Thermometer and Thermostat +dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM +dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O +dallas,ds75 Digital Thermometer and Thermostat +devantech,srf02 Devantech SRF02 ultrasonic ranger in I2C mode +devantech,srf08 Devantech SRF08 ultrasonic ranger +devantech,srf10 Devantech SRF10 ultrasonic ranger +dlg,da9053 DA9053: flexible system level PMIC with multicore support +dlg,da9063 DA9063: system PMIC for quad-core application processors +domintech,dmard09 DMARD09: 3-axis Accelerometer +domintech,dmard10 DMARD10: 3-axis Accelerometer +epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE +epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE +emmicro,em3027 EM Microelectronic EM3027 Real-time Clock +fsl,mag3110 MAG3110: Xtrinsic High Accuracy, 3D Magnetometer +fsl,mma7660 MMA7660FC: 3-Axis Orientation/Motion Detection Sensor +fsl,mma8450 MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer +fsl,mpl3115 MPL3115: Absolute Digital Pressure Sensor +fsl,mpr121 MPR121: Proximity Capacitive Touch Sensor Controller +fsl,sgtl5000 SGTL5000: Ultra Low-Power Audio Codec +gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface +infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) +infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz) +infineon,tlv493d-a1b6 Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor +isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM +isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM +isil,isl12022 Intersil ISL12022 Real-time Clock +isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor +isil,isl29030 Intersil ISL29030 Ambient Light and Proximity Sensor +maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator +maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs +maxim,max6621 PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion +maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface +mcube,mc3230 mCube 3-axis 8-bit digital accelerometer +memsic,mxc6225 MEMSIC 2-axis 8-bit digital accelerometer +microchip,mcp4017-502 Microchip 7-bit Single I2C Digital POT (5k) +microchip,mcp4017-103 Microchip 7-bit Single I2C Digital POT (10k) +microchip,mcp4017-503 Microchip 7-bit Single I2C Digital POT (50k) +microchip,mcp4017-104 Microchip 7-bit Single I2C Digital POT (100k) +microchip,mcp4018-502 Microchip 7-bit Single I2C Digital POT (5k) +microchip,mcp4018-103 Microchip 7-bit Single I2C Digital POT (10k) +microchip,mcp4018-503 Microchip 7-bit Single I2C Digital POT (50k) +microchip,mcp4018-104 Microchip 7-bit Single I2C Digital POT (100k) +microchip,mcp4019-502 Microchip 7-bit Single I2C Digital POT (5k) +microchip,mcp4019-103 Microchip 7-bit Single I2C Digital POT (10k) +microchip,mcp4019-503 Microchip 7-bit Single I2C Digital POT (50k) +microchip,mcp4019-104 Microchip 7-bit Single I2C Digital POT (100k) +microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4531-103 Microchip 7-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4531-503 Microchip 7-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4531-104 Microchip 7-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4532-502 Microchip 7-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4532-103 Microchip 7-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4532-503 Microchip 7-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4532-104 Microchip 7-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4541-502 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4541-103 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4541-503 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4541-104 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4542-502 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4542-103 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4542-503 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4542-104 Microchip 7-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4551-502 Microchip 8-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4551-103 Microchip 8-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4551-503 Microchip 8-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4551-104 Microchip 8-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4552-502 Microchip 8-bit Single I2C Digital Potentiometer (5k) +microchip,mcp4552-103 Microchip 8-bit Single I2C Digital Potentiometer (10k) +microchip,mcp4552-503 Microchip 8-bit Single I2C Digital Potentiometer (50k) +microchip,mcp4552-104 Microchip 8-bit Single I2C Digital Potentiometer (100k) +microchip,mcp4561-502 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4561-103 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4561-503 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4561-104 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4562-502 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4562-103 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4562-503 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4562-104 Microchip 8-bit Single I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4631-502 Microchip 7-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4631-103 Microchip 7-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4631-503 Microchip 7-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4631-104 Microchip 7-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4632-502 Microchip 7-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4632-103 Microchip 7-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4632-503 Microchip 7-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4632-104 Microchip 7-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4641-502 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4641-103 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4641-503 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4641-104 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4642-502 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4642-103 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4642-503 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4642-104 Microchip 7-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4651-502 Microchip 8-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4651-103 Microchip 8-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4651-503 Microchip 8-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4651-104 Microchip 8-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4652-502 Microchip 8-bit Dual I2C Digital Potentiometer (5k) +microchip,mcp4652-103 Microchip 8-bit Dual I2C Digital Potentiometer (10k) +microchip,mcp4652-503 Microchip 8-bit Dual I2C Digital Potentiometer (50k) +microchip,mcp4652-104 Microchip 8-bit Dual I2C Digital Potentiometer (100k) +microchip,mcp4661-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4661-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4661-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4661-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,mcp4662-502 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (5k) +microchip,mcp4662-103 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (10k) +microchip,mcp4662-503 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (50k) +microchip,mcp4662-104 Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k) +microchip,tc654 PWM Fan Speed Controller With Fan Fault Detection +microchip,tc655 PWM Fan Speed Controller With Fan Fault Detection +microcrystal,rv3029 Real Time Clock Module with I2C-Bus +miramems,da226 MiraMEMS DA226 2-axis 14-bit digital accelerometer +miramems,da280 MiraMEMS DA280 3-axis 14-bit digital accelerometer +miramems,da311 MiraMEMS DA311 3-axis 12-bit digital accelerometer +national,lm63 Temperature sensor with integrated fan control +national,lm75 I2C TEMP SENSOR +national,lm80 Serial Interface ACPI-Compatible Microprocessor System Hardware Monitor +national,lm85 Temperature sensor with integrated fan control +national,lm92 ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator with Two-Wire Interface +nuvoton,npct501 i2c trusted platform module (TPM) +nuvoton,npct601 i2c trusted platform module (TPM2) +nuvoton,w83773g Nuvoton Temperature Sensor +nxp,pca9556 Octal SMBus and I2C registered interface +nxp,pca9557 8-bit I2C-bus and SMBus I/O port with reset +nxp,pcf2127 Real-time clock +nxp,pcf2129 Real-time clock +nxp,pcf8523 Real-time Clock +nxp,pcf8563 Real-time clock/calendar +nxp,pcf85063 Tiny Real-Time Clock +oki,ml86v7667 OKI ML86V7667 video decoder +ovti,ov5642 OV5642: Color CMOS QSXGA (5-megapixel) Image Sensor with OmniBSI and Embedded TrueFocus +pericom,pt7c4338 Real-time Clock Module +plx,pex8648 48-Lane, 12-Port PCI Express Gen 2 (5.0 GT/s) Switch +pulsedlight,lidar-lite-v2 Pulsedlight LIDAR range-finding sensor +ricoh,r2025sd I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,r2221tl I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,rs5c372a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC +samsung,24ad0xd1 S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power) +sgx,vz89x SGX Sensortech VZ89X Sensors +sii,s35390a 2-wire CMOS real-time clock +silabs,si7020 Relative Humidity and Temperature Sensors +skyworks,sky81452 Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply +st,24c256 i2c serial eeprom (24cxx) +taos,tsl2550 Ambient Light Sensor with SMBUS/Two Wire Serial Interface +ti,ads7828 8-Channels, 12-bit ADC +ti,ads7830 8-Channels, 8-bit ADC +ti,amc6821 Temperature Monitoring and Fan Control +ti,tsc2003 I2C Touch-Screen Controller +ti,tmp102 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface +ti,tmp103 Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface +ti,tmp275 Digital Temperature Sensor +winbond,w83793 Winbond/Nuvoton H/W Monitor +winbond,wpct301 i2c trusted platform module (TPM) diff --git a/arch/arm64/boot/dts/vendor/bindings/ufs/tc-dwc-g210-pltfrm.txt b/arch/arm64/boot/dts/vendor/bindings/ufs/tc-dwc-g210-pltfrm.txt new file mode 100644 index 0000000000000000000000000000000000000000..71c0777960e9c4c846b33fa985823148bf4df8bf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ufs/tc-dwc-g210-pltfrm.txt @@ -0,0 +1,26 @@ +* Universal Flash Storage (UFS) DesignWare Host Controller + +DWC_UFS nodes are defined to describe on-chip UFS host controllers and MPHY. +Each UFS controller instance should have its own node. + +Required properties: +- compatible : compatible list must contain the PHY type & version: + "snps,g210-tc-6.00-20bit" + "snps,g210-tc-6.00-40bit" + complemented with the Controller IP version: + "snps,dwc-ufshcd-1.40a" + complemented with the JEDEC version: + "jedec,ufs-1.1" + "jedec,ufs-2.0" + +- reg : +- interrupts : + +Example for a setup using a 1.40a DWC Controller with a 6.00 G210 40-bit TC: + dwc-ufs@d0000000 { + compatible = "snps,g210-tc-6.00-40bit", + "snps,dwc-ufshcd-1.40a", + "jedec,ufs-2.0"; + reg = < 0xd0000000 0x10000 >; + interrupts = < 24 >; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-hisi.txt b/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-hisi.txt new file mode 100644 index 0000000000000000000000000000000000000000..a48c4481736722c060f67d1d1067e3f493ebebbe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-hisi.txt @@ -0,0 +1,41 @@ +* Hisilicon Universal Flash Storage (UFS) Host Controller + +UFS nodes are defined to describe on-chip UFS hardware macro. +Each UFS Host Controller should have its own node. + +Required properties: +- compatible : compatible list, contains one of the following - + "hisilicon,hi3660-ufs", "jedec,ufs-1.1" for hisi ufs + host controller present on Hi36xx chipset. +- reg : should contain UFS register address space & UFS SYS CTRL register address, +- interrupt-parent : interrupt device +- interrupts : interrupt number +- clocks : List of phandle and clock specifier pairs +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. "ref_clk", "phy_clk" is optional +- freq-table-hz : Array of operating frequencies stored in the same + order as the clocks property. If this property is not + defined or a value in the array is "0" then it is assumed + that the frequency is set by the parent clock or a + fixed rate clock source. +- resets : describe reset node register +- reset-names : reset node register, the "rst" corresponds to reset the whole UFS IP. + +Example: + + ufs: ufs@ff3b0000 { + compatible = "hisilicon,hi3660-ufs", "jedec,ufs-1.1"; + /* 0: HCI standard */ + /* 1: UFS SYS CTRL */ + reg = <0x0 0xff3b0000 0x0 0x1000>, + <0x0 0xff3b1000 0x0 0x1000>; + interrupt-parent = <&gic>; + interrupts = ; + clocks = <&crg_ctrl HI3660_CLK_GATE_UFSIO_REF>, + <&crg_ctrl HI3660_CLK_GATE_UFSPHY_CFG>; + clock-names = "ref_clk", "phy_clk"; + freq-table-hz = <0 0>, <0 0>; + /* offset: 0x84; bit: 12 */ + resets = <&crg_rst 0x84 12>; + reset-names = "rst"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-msm.txt b/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-msm.txt new file mode 100644 index 0000000000000000000000000000000000000000..5534f93b4c3b2164ddcd5017da3b2995da97428f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-msm.txt @@ -0,0 +1,33 @@ +* MSM Universal Flash Storage (UFS) PHY + +UFSPHY nodes are defined to describe on-chip UFS PHY hardware macro. +Each UFS PHY node should have its own node. + +To bind UFS PHY with UFS host controller, the controller node should +contain a phandle reference to UFS PHY node. + +Required properties: +- compatible : compatible list, contains "qcom,ufsphy" +- reg : +- vdda-phy-supply : phandle to main PHY supply for analog domain +- vdda-pll-supply : phandle to PHY PLL and Power-Gen block power supply + +Optional properties: +- vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply +- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply + +Example: + + ufsphy1: ufsphy@0xfc597000 { + compatible = "qcom,ufsphy"; + reg = <0xfc597000 0x800>; + vdda-phy-supply = <&pma8084_l4>; + vdda-pll-supply = <&pma8084_l12>; + vdda-phy-max-microamp = <50000>; + vdda-pll-max-microamp = <1000>; + }; + + ufshc@0xfc598000 { + ... + ufs-phy = <&ufsphy1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-qcom.txt b/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-qcom.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b5e0de2071e584f71e1b1e86f9d1483845f1914 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ufs/ufs-qcom.txt @@ -0,0 +1,81 @@ +* Qualcomm Technologies Inc Universal Flash Storage (UFS) PHY + +UFSPHY nodes are defined to describe on-chip UFS PHY hardware macro. +Each UFS PHY node should have its own node. + +To bind UFS PHY with UFS host controller, the controller node should +contain a phandle reference to UFS PHY node. + +Required properties: +- compatible : compatible list, contains one of the following - + "qcom,ufs-phy-qmp-14nm" for legacy 14nm ufs phy, + "qcom,ufs-phy-qmp-v3" for V3 ufs phy present + on msmcobalt platform, + "qcom,ufs-phy-qmp-v4" for V4 ufs phy present + on Kona platform, + "qcom,ufs-phy-qmp-v4-card" for V4 ufs card phy present + on Kona platform, + "qcom,ufs-phy-qmp-v4-lito" for V4 ufs phy present + on lito platform, + "qcom,ufs-phy-qrbtc-sdm845" for phy support + for sdm845 emulation, + "qcom,ufs-phy-qmp-v3-falcon" for phy support + for msmfalcon, + "qcom,ufs-phy-qmp-v3-660" for V3 ufs phy present + on SDM660 platform, + "qcom,msm8996-ufs-phy-qmp-14nm" for 14nm ufs phy + present on MSM8996 chipset. +- reg : should contain PHY register address space (mandatory), +- reg-names : indicates various resources passed to driver (via reg proptery) by name. + Required "reg-names" is "phy_mem". +- #phy-cells : This property shall be set to 0 +- vdda-phy-supply : phandle to main PHY supply for analog domain +- vdda-pll-supply : phandle to PHY PLL and Power-Gen block power supply +- clocks : List of phandle and clock specifier pairs +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. "ref_clk_src", + "tx_iface_clk" & "rx_iface_clk" are mandatory but + "ref_clk_parent" and "ref_clk" are optional + +Optional properties: +- vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply +- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply +- vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply +- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply +- vddp-ref-clk-min-uV : specifies min voltage that can be set for reference clock supply +- vddp-ref-clk-max-uV : specifies max voltage that can be set for reference clock supply +- qcom,disable-lpm : disable various LPM mechanisms in UFS for platform compatibility + (limit link to PWM Gear-1, 1-lane slow mode; disable hibernate, and avoid suspend/resume) +- vccq-parent-supply : phandle to UFS device's VCCQ parent power supply +- vccq-parent-max-microamp : specifies max. load that can be drawn from the VCCQ's parent supply +- qcom,rpmh-resource-name : Specifies the RPMH resource name + +Example: + + ufsphy1: ufsphy@fc597000 { + compatible = "qcom,ufs-phy-qmp-14nm"; + reg = <0xfc597000 0x800>; + reg-names = "phy_mem"; + #phy-cells = <0>; + lanes-per-direction = <1>; + vdda-phy-supply = <&pma8084_l4>; + vdda-pll-supply = <&pma8084_l12>; + vdda-phy-max-microamp = <50000>; + vdda-pll-max-microamp = <1000>; + clock-names = "ref_clk_src", + "ref_clk_parent", + "ref_clk", + "tx_iface_clk", + "rx_iface_clk"; + clocks = <&clock_rpm clk_ln_bb_clk>, + <&clock_gcc clk_pcie_1_phy_ldo >, + <&clock_gcc clk_ufs_phy_ldo>, + <&clock_gcc clk_gcc_ufs_tx_cfg_clk>, + <&clock_gcc clk_gcc_ufs_rx_cfg_clk>; + }; + + ufshc@fc598000 { + ... + phys = <&ufsphy1>; + phy-names = "ufsphy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/ufs/ufshcd-pltfrm.txt b/arch/arm64/boot/dts/vendor/bindings/ufs/ufshcd-pltfrm.txt new file mode 100644 index 0000000000000000000000000000000000000000..56cdca7094c0b1319cef731841a325ea5c982621 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/ufs/ufshcd-pltfrm.txt @@ -0,0 +1,234 @@ +* Universal Flash Storage (UFS) Host Controller + +UFSHC nodes are defined to describe on-chip UFS host controllers. +Each UFS controller instance should have its own node. + +Required properties: +- compatible : must contain "jedec,ufs-1.1" or "jedec,ufs-2.0", may + also list one or more of the following: + "qcom,msm8994-ufshc" + "qcom,msm8996-ufshc" + "qcom,ufshc" +- interrupts : +- reg : + first entry should contain UFS host controller register address space (mandatory), + second entry is the device ref. clock control register map (optional). +- reset : reset specifier pair consists of phandle for the reset provider + and reset lines used by this controller. +- reset-names : reset signal name strings sorted in the same order as the resets property. + +Optional properties: +- phys : phandle to UFS PHY node +- phy-names : the string "ufsphy" when is found in a node, along + with "phys" attribute, provides phandle to UFS PHY node +- vdd-hba-supply : phandle to UFS host controller supply regulator node +- vcc-supply : phandle to VCC supply regulator node +- vcc-voltage-level : specifies voltage levels for VCC supply. + Should be specified in pairs (min, max), units uV. +- vccq2-voltage-level : specifies voltage levels for VCCQ2 supply. + Should be specified in pairs (min, max), units uV. +- vcc-low-voltage-sup : If specified, treats min voltage from vcc-voltage-level as + low voltage level different from max voltage. +- vccq-supply : phandle to VCCQ supply regulator node +- vccq2-supply : phandle to VCCQ2 supply regulator node +- vcc-supply-1p8 : For embedded UFS devices, valid VCC range is 1.7-1.95V + or 2.7-3.6V. This boolean property when set, specifies + to use low voltage range of 1.7-1.95V. Note for external + UFS cards this property is invalid and valid VCC range is + always 2.7-3.6V. +- vcc-max-microamp : specifies max. load that can be drawn from vcc supply +- vccq-max-microamp : specifies max. load that can be drawn from vccq supply +- vccq-min-microamp : specifies min. load that can be drawn from vccq supply +- vccq2-max-microamp : specifies max. load that can be drawn from vccq2 supply +- vccq2-min-microamp : specifies min. load that can be drawn from vccq2 supply +- -fixed-regulator : boolean property specifying that -supply is a fixed regulator + +- clocks : List of phandle and clock specifier pairs +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. +- freq-table-hz : Array of operating frequencies stored in the same + order as the clocks property. If this property is not + defined or a value in the array is "0" then it is assumed + that the frequency is set by the parent clock or a + fixed rate clock source. +- rpm-level : UFS Runtime power management level. Following PM levels are supported: + 0 - Both UFS device and Link in active state (Highest power consumption) + 1 - UFS device in active state but Link in Hibern8 state + 2 - UFS device in Sleep state but Link in active state + 3 - UFS device in Sleep state and Link in hibern8 state (default PM level) + 4 - UFS device in Power-down state and Link in Hibern8 state + 5 - UFS device in Power-down state and Link in OFF state (Lowest power consumption) +- spm-level : UFS System power management level. Allowed PM levels are same as rpm-level. +- ufs-qcom-crypto : phandle to UFS-QCOM ICE (Inline Cryptographic Engine) node +-lanes-per-direction : number of lanes available per direction - either 1 or 2. + Note that it is assume same number of lanes is used both + directions at once. If not specified, default is 2 lanes per direction. +- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + for these optional properties +- limit-tx-hs-gear : Specify the max. limit on the TX HS gear. + Valid range: 1-3. 1 => HS-G1, 2 => HS-G2, 3 => HS-G3 +- limit-rx-hs-gear : Specify the max. limit on the RX HS gear. Refer "limit-tx-hs-gear" for expected values. +- limit-tx-pwm-gear : Specify the max. limit on the TX PWM gear + Valid range: 1-4. 1 => PWM-G1, 2 => PWM-G2, 3 => PWM-G3, 4 => PWM-G4 +- limit-rx-pwm-gear : Specify the max. limit on the RX PWM gear. Refer "limit-tx-pwm-gear" for expected values. +- scsi-cmd-timeout : Specify the command timeout (in seconds) for scsi commands +- dev-ref-clk-freq : Specify the device reference clock frequency, must be one of the following: + 0: 19.2 MHz + 1: 26 MHz + 2: 38.4 MHz + 3: 52 MHz + Defaults to 26 MHz if not specified. +- extcon: phandle to external connector (Refer Documentation/devicetree/bindings/extcon/extcon-gpio.txt for more details). +- non-removable : defines if the connected ufs device is not removable +- resets : reset node register +- reset-names : describe reset node register, the "rst" corresponds to reset the whole UFS IP. +- force-g4 : forces UFS Host PHY to be initialized in HS-G4 + +- vccq-pwr-collapse-sup : +- vccq2-pwr-collapse-sup : Support turning off UFS's Vccq/Vccq2 power supply during system suspend events. + The UFS device will be fully reinitialized during system resume events. + The advantage is to save power consumption during system suspend because the + entire UFS device is powered off. + The tradeoffs are: + 1. The System Resume time will increase due to full UFS device re-initializations. + 2. The UFS device life expectancy may be reduced because of the frequent power cycles. + Customers should only enable the feature if the SoC supports turning off the UFS + power supplies during power collapse events. + In addition, customers should evaluate the benefits and tradeoffs of this feature + very carefully before enabling it. + +Note: If above properties are not defined it can be assumed that the supply +regulators or clocks are always on. + +Example: + ufshc@fc598000 { + compatible = "jedec,ufs-1.1"; + reg = <0xfc598000 0x800>, <0xfd512074 0x4>; + interrupts = <0 28 0>; + + ufs-qcom-crypto = <&ufs_ice>; + vdd-hba-supply = <&xxx_reg0>; + vdd-hba-fixed-regulator; + vcc-supply = <&xxx_reg1>; + vcc-supply-1p8; + vcc-low-voltage-sup; + vccq-supply = <&xxx_reg2>; + vccq2-supply = <&xxx_reg3>; + vcc-max-microamp = 500000; + vccq-max-microamp = 200000; + vccq2-max-microamp = 200000; + + clocks = <&core 0>, <&ref 0>, <&phy 0>, <&iface 0>; + clock-names = "core_clk", "ref_clk", "phy_clk", "iface_clk"; + freq-table-hz = <100000000 200000000>, <0 0>, <0 0>, <0 0>; + resets = <&reset 0 1>; + reset-names = "rst"; + phys = <&ufsphy1>; + phy-names = "ufsphy"; + rpm-level = <3>; + spm-level = <5>; + dev-ref-clk-freq = <0>; /* reference clock freq: 19.2 MHz */ + force-g4; + }; + +==== MSM UFS platform driver properties ===== +* For UFS host controller in MSM platform following clocks are required - + Controller clock source - + "core_clk_src", max-clock-frequency-hz = 200MHz + + Controller System clock branch: + "core_clk" - Controller core clock + + AHB/AXI interface clocks: + "iface_clk" - AHB interface clock + "bus_clk" - AXI bus master clock + + PHY to controller symbol synchronization clocks: + "rx_lane0_sync_clk" - RX Lane 0 + "rx_lane1_sync_clk" - RX Lane 1 + "tx_lane0_sync_clk" - TX Lane 0 + "tx_lane1_sync_clk" - TX Lane 1 + + Optional reference clock input to UFS device + "ref_clk", max-clock-frequency-hz = 19.2MHz + +* Following bus parameters are required - +- qcom,msm-bus,name +- qcom,msm-bus,num-cases +- qcom,msm-bus,num-paths +- qcom,msm-bus,vectors-KBps +For the above four properties please refer to +Documentation/devicetree/bindings/arm/msm/msm_bus.txt +Note: The instantaneous bandwidth (IB) value in the vectors-KBps field should + be zero as UFS data transfer path doesn't have latency requirements and + voting for aggregated bandwidth (AB) should take care of providing + optimum throughput requested. + +- qcom,bus-vector-names: specifies string IDs for the corresponding +bus vectors in the same order as qcom,msm-bus,vectors-KBps property. + +* The following parameters are optional, but required in order for PM QoS to be +enabled and functional in the driver: +- qcom,pm-qos-cpu-groups: arrays of unsigned integers representing the cpu groups. + The number of values in the array defines the number of cpu-groups. + Each value is a bit-mask defining the cpus that take part in that cpu group. + i.e. if bit N is set, then cpuN is a part of the cpu group. So basically, + a cpu group corelated to a cpu cluster. + A PM QoS request object is maintained for each cpu-group. +- qcom,pm-qos-cpu-group-latency-us: array of values used for PM QoS voting, one for each cpu-group defined. + the number of values must match the number of values defined in + qcom,pm-qos-cpu-mask property. +- qcom,pm-qos-default-cpu: PM QoS voting is based on the cpu associated with each IO request by the block layer. + This defined the default cpu used for PM QoS voting in case a specific cpu value is not available. + +- qcom,vddp-ref-clk-supply : reference clock to ufs device. Controlled by the host driver. +- qcom,vddp-ref-clk-max-microamp : specifies max. load that can be drawn for + ref-clk supply. +- qcom,vccq-parent-supply : phandle to VCCQ's parent supply regulator. +- qcom,vccq-parent-max-microamp : specifies max. load that can be drawn for + VCCQ's parent supply regulator. + +Example: + ufshc@0xfc598000 { + ... + + qcom,msm-bus,name = "ufs1"; + qcom,msm-bus,num-cases = <22>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <95 512 0 0>, <1 650 0 0>, /* No vote */ + + <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */ + <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */ + <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */ + <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */ + <95 512 1844 0>, <1 650 1000 0>, /* PWM G1 L2 */ + <95 512 3688 0>, <1 650 1000 0>, /* PWM G2 L2 */ + <95 512 7376 0>, <1 650 1000 0>, /* PWM G3 L2 */ + <95 512 14752 0>, <1 650 1000 0>, /* PWM G4 L2 */ + + <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */ + <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */ + <95 512 511181 0>, <1 650 1000 0>, /* HS G3 RA */ + <95 512 255591 0>, <1 650 1000 0>, /* HS G1 RA L2 */ + <95 512 511181 0>, <1 650 1000 0>, /* HS G2 RA L2 */ + <95 512 1022362 0>, <1 650 1000 0>, /* HS G3 RA L2 */ + + <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */ + <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */ + <95 512 596378 0>, <1 650 1000 0>, /* HS G3 RB */ + <95 512 298189 0>, <1 650 1000 0>, /* HS G1 RB L2 */ + <95 512 596378 0>, <1 650 1000 0>, /* HS G2 RB L2 */ + <95 512 1192756 0>, <1 650 1000 0>, /* HS G3 RB L2 */ + + <95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", + "MAX"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/uio/msm_sharedmem.txt b/arch/arm64/boot/dts/vendor/bindings/uio/msm_sharedmem.txt new file mode 100644 index 0000000000000000000000000000000000000000..55bd4cd859c056a7149d968eaf7a806c3ee594c0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/uio/msm_sharedmem.txt @@ -0,0 +1,29 @@ +msm_sharedmem provides the shared memory addresses for various clients in user-space + +Required properties: +- compatible: Must be "qcom,sharedmem-uio" +- reg : The address and size of the shared memory. The address/sizes may vary. + A reg address of Zero indicates that the shared memory is dynamically + allocated using dma_alloc_coherent. A non zero reg address is used + directly. +- reg-names : Indicates various client-names. +- qcom,client-id : The client id for the QMI clients. + +Optional properties: +- qcom,guard-memory: If this dtsi property is set, then the shared memory + region will be guarded by SZ_4K at the start and at the end. + This is needed to overcome the XPU limitation on some MSM HW, + so as to make this memory not contiguous with other allocations + that may possibly happen from other clients. +- qcom,vm-nav-path: If this dtsi property is set, then the shared memory region + will be given access to vm-nav-path also. + +Example: + qcom,msm_sharedmem@0dc80000 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0dc80000 0x00180000>, + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + qcom,vm-nav-path; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/unittest.txt b/arch/arm64/boot/dts/vendor/bindings/unittest.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a5b311f44342079d73ab7b5a4881d2d8c706c59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/unittest.txt @@ -0,0 +1,66 @@ +1) OF unittest platform device + +** unittest + +Required properties: +- compatible: must be "unittest" + +All other properties are optional. + +Example: + unittest { + compatible = "unittest"; + }; + +2) OF unittest i2c adapter platform device + +** platform device unittest adapter + +Required properties: +- compatible: must be unittest-i2c-bus + +Children nodes contain unittest i2c devices. + +Example: + unittest-i2c-bus { + compatible = "unittest-i2c-bus"; + }; + +3) OF unittest i2c device + +** I2C unittest device + +Required properties: +- compatible: must be unittest-i2c-dev + +All other properties are optional + +Example: + unittest-i2c-dev { + compatible = "unittest-i2c-dev"; + }; + +4) OF unittest i2c mux device + +** I2C unittest mux + +Required properties: +- compatible: must be unittest-i2c-mux + +Children nodes contain unittest i2c bus nodes per channel. + +Example: + unittest-i2c-mux { + compatible = "unittest-i2c-mux"; + #address-cells = <1>; + #size-cells = <0>; + channel-0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + i2c-dev { + reg = <8>; + compatible = "unittest-i2c-dev"; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/allwinner,sun4i-a10-musb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/allwinner,sun4i-a10-musb.txt new file mode 100644 index 0000000000000000000000000000000000000000..50abb20fe319435cbc824cb17ba23bf2394e3d87 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -0,0 +1,28 @@ +Allwinner sun4i A10 musb DRC/OTG controller +------------------------------------------- + +Required properties: + - compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb", + "allwinner,sun8i-a33-musb" or "allwinner,sun8i-h3-musb" + - reg : mmio address range of the musb controller + - clocks : clock specifier for the musb controller ahb gate clock + - reset : reset specifier for the ahb reset (A31 and newer only) + - interrupts : interrupt to which the musb controller is connected + - interrupt-names : must be "mc" + - phys : phy specifier for the otg phy + - phy-names : must be "usb" + - dr_mode : Dual-Role mode must be "host" or "otg" + - extcon : extcon specifier for the otg phy + +Example: + + usb_otg: usb@1c13000 { + compatible = "allwinner,sun4i-a10-musb"; + reg = <0x01c13000 0x0400>; + clocks = <&ahb_gates 0>; + interrupts = <38>; + interrupt-names = "mc"; + phys = <&usbphy 0>; + phy-names = "usb"; + extcon = <&usbphy 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/am33xx-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/am33xx-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a198a30408abf3f8a164189d60248f1dfcddc8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/am33xx-usb.txt @@ -0,0 +1,199 @@ + AM33xx MUSB +~~~~~~~~~~~~~~~ +- compatible: ti,am33xx-usb +- reg: offset and length of the usbss register sets +- ti,hwmods : must be "usb_otg_hs" + +The glue layer contains multiple child nodes. It is required to have +at least a control module node, USB node and a PHY node. The second USB +node and its PHY node are optional. The DMA node is also optional. + +Reset module +~~~~~~~~~~~~ +- compatible: ti,am335x-usb-ctrl-module +- reg: offset and length of the "USB control registers" in the "Control + Module" block. A second offset and length for the USB wake up control + in the same memory block. +- reg-names: "phy_ctrl" for the "USB control registers" and "wakeup" for + the USB wake up control register. + +USB PHY +~~~~~~~ +compatible: ti,am335x-usb-phy +reg: offset and length of the "USB PHY" register space +ti,ctrl_mod: reference to the "reset module" node +reg-names: phy +The PHY should have a "phy" alias numbered properly in the alias +node. + +USB +~~~ +- compatible: ti,musb-am33xx +- reg: offset and length of "USB Controller Registers", and offset and + length of "USB Core" register space. +- reg-names: control for the ""USB Controller Registers" and "mc" for + "USB Core" register space +- interrupts: USB interrupt number +- interrupt-names: mc +- dr_mode: Should be one of "host", "peripheral" or "otg". +- mentor,multipoint: Should be "1" indicating the musb controller supports + multipoint. This is a MUSB configuration-specific setting. +- mentor,num-eps: Specifies the number of endpoints. This is also a + MUSB configuration-specific setting. Should be set to "16" +- mentor,ram-bits: Specifies the ram address size. Should be set to "12" +- mentor,power: Should be "500". This signifies the controller can supply up to + 500mA when operating in host mode. +- phys: reference to the USB phy +- dmas: specifies the dma channels +- dma-names: specifies the names of the channels. Use "rxN" for receive + and "txN" for transmit endpoints. N specifies the endpoint number. + +The controller should have an "usb" alias numbered properly in the alias +node. + +DMA +~~~ +- compatible: ti,am3359-cppi41 +- reg: offset and length of the following register spaces: USBSS, USB + CPPI DMA Controller, USB CPPI DMA Scheduler, USB Queue Manager +- reg-names: glue, controller, scheduler, queuemgr +- #dma-cells: should be set to 2. The first number represents the + endpoint number (0 … 14 for endpoints 1 … 15 on instance 0 and 15 … 29 + for endpoints 1 … 15 on instance 1). The second number is 0 for RX and + 1 for TX transfers. +- #dma-channels: should be set to 30 representing the 15 endpoints for + each USB instance. + +Example: +~~~~~~~~ +The following example contains all the nodes as used on am335x-evm: + +aliases { + usb0 = &usb0; + usb1 = &usb1; + phy0 = &usb0_phy; + phy1 = &usb1_phy; +}; + +usb: usb@47400000 { + compatible = "ti,am33xx-usb"; + reg = <0x47400000 0x1000>; + ranges; + #address-cells = <1>; + #size-cells = <1>; + ti,hwmods = "usb_otg_hs"; + + ctrl_mod: control@44e10000 { + compatible = "ti,am335x-usb-ctrl-module"; + reg = <0x44e10620 0x10 + 0x44e10648 0x4>; + reg-names = "phy_ctrl", "wakeup"; + }; + + usb0_phy: usb-phy@47401300 { + compatible = "ti,am335x-usb-phy"; + reg = <0x47401300 0x100>; + reg-names = "phy"; + ti,ctrl_mod = <&ctrl_mod>; + #phy-cells = <0>; + }; + + usb0: usb@47401000 { + compatible = "ti,musb-am33xx"; + reg = <0x47401400 0x400 + 0x47401000 0x200>; + reg-names = "mc", "control"; + + interrupts = <18>; + interrupt-names = "mc"; + dr_mode = "otg" + mentor,multipoint = <1>; + mentor,num-eps = <16>; + mentor,ram-bits = <12>; + mentor,power = <500>; + phys = <&usb0_phy>; + + dmas = <&cppi41dma 0 0 &cppi41dma 1 0 + &cppi41dma 2 0 &cppi41dma 3 0 + &cppi41dma 4 0 &cppi41dma 5 0 + &cppi41dma 6 0 &cppi41dma 7 0 + &cppi41dma 8 0 &cppi41dma 9 0 + &cppi41dma 10 0 &cppi41dma 11 0 + &cppi41dma 12 0 &cppi41dma 13 0 + &cppi41dma 14 0 &cppi41dma 0 1 + &cppi41dma 1 1 &cppi41dma 2 1 + &cppi41dma 3 1 &cppi41dma 4 1 + &cppi41dma 5 1 &cppi41dma 6 1 + &cppi41dma 7 1 &cppi41dma 8 1 + &cppi41dma 9 1 &cppi41dma 10 1 + &cppi41dma 11 1 &cppi41dma 12 1 + &cppi41dma 13 1 &cppi41dma 14 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", + "rx14", "rx15", + "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7", + "tx8", "tx9", "tx10", "tx11", "tx12", "tx13", + "tx14", "tx15"; + }; + + usb1_phy: usb-phy@47401b00 { + compatible = "ti,am335x-usb-phy"; + reg = <0x47401b00 0x100>; + reg-names = "phy"; + ti,ctrl_mod = <&ctrl_mod>; + #phy-cells = <0>; + }; + + usb1: usb@47401800 { + compatible = "ti,musb-am33xx"; + reg = <0x47401c00 0x400 + 0x47401800 0x200>; + reg-names = "mc", "control"; + interrupts = <19>; + interrupt-names = "mc"; + dr_mode = "host" + mentor,multipoint = <1>; + mentor,num-eps = <16>; + mentor,ram-bits = <12>; + mentor,power = <500>; + phys = <&usb1_phy>; + + dmas = <&cppi41dma 15 0 &cppi41dma 16 0 + &cppi41dma 17 0 &cppi41dma 18 0 + &cppi41dma 19 0 &cppi41dma 20 0 + &cppi41dma 21 0 &cppi41dma 22 0 + &cppi41dma 23 0 &cppi41dma 24 0 + &cppi41dma 25 0 &cppi41dma 26 0 + &cppi41dma 27 0 &cppi41dma 28 0 + &cppi41dma 29 0 &cppi41dma 15 1 + &cppi41dma 16 1 &cppi41dma 17 1 + &cppi41dma 18 1 &cppi41dma 19 1 + &cppi41dma 20 1 &cppi41dma 21 1 + &cppi41dma 22 1 &cppi41dma 23 1 + &cppi41dma 24 1 &cppi41dma 25 1 + &cppi41dma 26 1 &cppi41dma 27 1 + &cppi41dma 28 1 &cppi41dma 29 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", "rx5", "rx6", "rx7", + "rx8", "rx9", "rx10", "rx11", "rx12", "rx13", + "rx14", "rx15", + "tx1", "tx2", "tx3", "tx4", "tx5", "tx6", "tx7", + "tx8", "tx9", "tx10", "tx11", "tx12", "tx13", + "tx14", "tx15"; + }; + + cppi41dma: dma-controller@7402000 { + compatible = "ti,am3359-cppi41"; + reg = <0x47400000 0x1000 + 0x47402000 0x1000 + 0x47403000 0x1000 + 0x47404000 0x4000>; + reg-names = "glue", "controller", "scheduler", "queuemgr"; + interrupts = <17>; + interrupt-names = "glue"; + #dma-cells = <2>; + #dma-channels = <30>; + #dma-requests = <256>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/amlogic,dwc3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/amlogic,dwc3.txt new file mode 100644 index 0000000000000000000000000000000000000000..9a8b631904fd6569ab9ddbe8f26ee43d0bce550b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/amlogic,dwc3.txt @@ -0,0 +1,42 @@ +Amlogic Meson GX DWC3 USB SoC controller + +Required properties: +- compatible: depending on the SoC this should contain one of: + * amlogic,meson-axg-dwc3 + * amlogic,meson-gxl-dwc3 +- clocks: a handle for the "USB general" clock +- clock-names: must be "usb_general" +- resets: a handle for the shared "USB OTG" reset line +- reset-names: must be "usb_otg" + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +PHY documentation is provided in the following places: +- Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt +- Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt + +Example device nodes: + usb0: usb@ff500000 { + compatible = "amlogic,meson-axg-dwc3"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&clkc CLKID_USB>; + clock-names = "usb_general"; + resets = <&reset RESET_USB_OTG>; + reset-names = "usb_otg"; + + dwc3: dwc3@ff500000 { + compatible = "snps,dwc3"; + reg = <0x0 0xff500000 0x0 0x100000>; + interrupts = ; + dr_mode = "host"; + maximum-speed = "high-speed"; + snps,dis_u2_susphy_quirk; + phys = <&usb3_phy>, <&usb2_phy0>; + phy-names = "usb2-phy", "usb3-phy"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/atmel-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/atmel-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..44e80153b148f178c61608b5dd8276b1f24e30ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/atmel-usb.txt @@ -0,0 +1,167 @@ +Atmel SOC USB controllers + +OHCI + +Required properties: + - compatible: Should be "atmel,at91rm9200-ohci" for USB controllers + used in host mode. + - reg: Address and length of the register set for the device + - interrupts: Should contain ohci interrupt + - clocks: Should reference the peripheral, host and system clocks + - clock-names: Should contain three strings + "ohci_clk" for the peripheral clock + "hclk" for the host clock + "uhpck" for the system clock + - num-ports: Number of ports. + - atmel,vbus-gpio: If present, specifies a gpio that needs to be + activated for the bus to be powered. + - atmel,oc-gpio: If present, specifies a gpio that needs to be + activated for the overcurrent detection. + +usb0: ohci@500000 { + compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + reg = <0x00500000 0x100000>; + clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>; + clock-names = "ohci_clk", "hclk", "uhpck"; + interrupts = <20 4>; + num-ports = <2>; +}; + +EHCI + +Required properties: + - compatible: Should be "atmel,at91sam9g45-ehci" for USB controllers + used in host mode. + - reg: Address and length of the register set for the device + - interrupts: Should contain ehci interrupt + - clocks: Should reference the peripheral and the UTMI clocks + - clock-names: Should contain two strings + "ehci_clk" for the peripheral clock + "usb_clk" for the UTMI clock + +usb1: ehci@800000 { + compatible = "atmel,at91sam9g45-ehci", "usb-ehci"; + reg = <0x00800000 0x100000>; + interrupts = <22 4>; + clocks = <&utmi>, <&uhphs_clk>; + clock-names = "usb_clk", "ehci_clk"; +}; + +AT91 USB device controller + +Required properties: + - compatible: Should be one of the following + "atmel,at91rm9200-udc" + "atmel,at91sam9260-udc" + "atmel,at91sam9261-udc" + "atmel,at91sam9263-udc" + - reg: Address and length of the register set for the device + - interrupts: Should contain macb interrupt + - clocks: Should reference the peripheral and the AHB clocks + - clock-names: Should contain two strings + "pclk" for the peripheral clock + "hclk" for the AHB clock + +Optional properties: + - atmel,vbus-gpio: If present, specifies a gpio that needs to be + activated for the bus to be powered. + +usb1: gadget@fffa4000 { + compatible = "atmel,at91rm9200-udc"; + reg = <0xfffa4000 0x4000>; + interrupts = <10 4>; + clocks = <&udc_clk>, <&udpck>; + clock-names = "pclk", "hclk"; + atmel,vbus-gpio = <&pioC 5 0>; +}; + +Atmel High-Speed USB device controller + +Required properties: + - compatible: Should be one of the following + "atmel,at91sam9rl-udc" + "atmel,at91sam9g45-udc" + "atmel,sama5d3-udc" + - reg: Address and length of the register set for the device + - interrupts: Should contain usba interrupt + - clocks: Should reference the peripheral and host clocks + - clock-names: Should contain two strings + "pclk" for the peripheral clock + "hclk" for the host clock + - ep childnode: To specify the number of endpoints and their properties. + +Optional properties: + - atmel,vbus-gpio: If present, specifies a gpio that allows to detect whether + vbus is present (USB is connected). + +Required child node properties: + - name: Name of the endpoint. + - reg: Num of the endpoint. + - atmel,fifo-size: Size of the fifo. + - atmel,nb-banks: Number of banks. + - atmel,can-dma: Boolean to specify if the endpoint support DMA. + - atmel,can-isoc: Boolean to specify if the endpoint support ISOC. + +usb2: gadget@fff78000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,at91sam9rl-udc"; + reg = <0x00600000 0x80000 + 0xfff78000 0x400>; + interrupts = <27 4 0>; + clocks = <&utmi>, <&udphs_clk>; + clock-names = "hclk", "pclk"; + atmel,vbus-gpio = <&pioB 19 0>; + + ep@0 { + reg = <0>; + atmel,fifo-size = <64>; + atmel,nb-banks = <1>; + }; + + ep@1 { + reg = <1>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep@2 { + reg = <2>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep@3 { + reg = <3>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + }; + + ep@4 { + reg = <4>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + }; + + ep@5 { + reg = <5>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep@6 { + reg = <6>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + atmel,can-isoc; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/brcm,bcm3384-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/brcm,bcm3384-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..452c45c7bf2929493fa0c9b123351f143de9410a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/brcm,bcm3384-usb.txt @@ -0,0 +1,11 @@ +* Broadcom USB controllers + +Required properties: +- compatible: "brcm,bcm3384-ohci", "brcm,bcm3384-ehci" + + These currently use the generic-ohci and generic-ehci drivers. On some + systems, special handling may be needed in the following cases: + + - Restoring state after systemwide power save modes + - Sharing PHYs with the USBD (UDC) hardware + - Figuring out which controllers are disabled on ASIC bondout variants diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/brcm,bdc.txt b/arch/arm64/boot/dts/vendor/bindings/usb/brcm,bdc.txt new file mode 100644 index 0000000000000000000000000000000000000000..63e63af3bf593926fb908861aad2718f43a77e16 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/brcm,bdc.txt @@ -0,0 +1,29 @@ +Broadcom USB Device Controller (BDC) +==================================== + +Required properties: + +- compatible: must be one of: + "brcm,bdc-v0.16" + "brcm,bdc" +- reg: the base register address and length +- interrupts: the interrupt line for this controller + +Optional properties: + +On Broadcom STB platforms, these properties are required: + +- phys: phandle to one or two USB PHY blocks + NOTE: Some SoC's have a single phy and some have + USB 2.0 and USB 3.0 phys +- clocks: phandle to the functional clock of this block + +Example: + + bdc@f0b02000 { + compatible = "brcm,bdc-v0.16"; + reg = <0xf0b02000 0xfc4>; + interrupts = <0x0 0x60 0x0>; + phys = <&usbphy_0 0x0>; + clocks = <&sw_usbd>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ci-hdrc-usb2.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ci-hdrc-usb2.txt new file mode 100644 index 0000000000000000000000000000000000000000..2e9318151df79712bcfec96de8d9994e9415d66b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ci-hdrc-usb2.txt @@ -0,0 +1,111 @@ +* USB2 ChipIdea USB controller for ci13xxx + +Required properties: +- compatible: should be one of: + "fsl,imx23-usb" + "fsl,imx27-usb" + "fsl,imx28-usb" + "fsl,imx6q-usb" + "fsl,imx6sl-usb" + "fsl,imx6sx-usb" + "fsl,imx6ul-usb" + "fsl,imx7d-usb" + "lsi,zevio-usb" + "qcom,ci-hdrc" + "chipidea,usb2" + "xlnx,zynq-usb-2.20a" +- reg: base address and length of the registers +- interrupts: interrupt for the USB controller + +Recommended properies: +- phy_type: the type of the phy connected to the core. Should be one + of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this + property the PORTSC register won't be touched. +- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" + +Deprecated properties: +- usb-phy: phandle for the PHY device. Use "phys" instead. +- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead. + +Optional properties: +- clocks: reference to the USB clock +- phys: reference to the USB PHY +- phy-names: should be "usb-phy" +- vbus-supply: reference to the VBUS regulator +- maximum-speed: limit the maximum connection speed to "full-speed". +- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts +- itc-setting: interrupt threshold control register control, the setting + should be aligned with ITC bits at register USBCMD. +- ahb-burst-config: it is vendor dependent, the required value should be + aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This + property is used to change AHB burst configuration, check the chipidea + spec for meaning of each value. If this property is not existed, it + will use the reset value. +- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword + (4 bytes), This register represents the maximum length of a the burst + in 32-bit words while moving data from system memory to the USB + bus, the value of this property will only take effect if property + "ahb-burst-config" is set to 0, if this property is missing the reset + default of the hardware implementation will be used. +- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword + (4 bytes), This register represents the maximum length of a the burst + in 32-bit words while moving data from the USB bus to system memory, + the value of this property will only take effect if property + "ahb-burst-config" is set to 0, if this property is missing the reset + default of the hardware implementation will be used. +- extcon: phandles to external connector devices. First phandle should point to + external connector, which provide "USB" cable events, the second should point + to external connector device, which provide "USB-HOST" cable events. If one + of the external connector devices is not required, empty <0> phandle should + be specified. +- phy-clkgate-delay-us: the delay time (us) between putting the PHY into + low power mode and gating the PHY clock. +- non-zero-ttctrl-ttha: after setting this property, the value of register + ttctrl.ttha will be 0x7f; if not, the value will be 0x0, this is the default + value. It needs to be very carefully for setting this property, it is + recommended that consult with your IC engineer before setting this value. + On the most of chipidea platforms, the "usage_tt" flag at RTL is 0, so this + property only affects siTD. + If this property is not set, the max packet size is 1023 bytes, and if + the total of packet size for pervious transactions are more than 256 bytes, + it can't accept any transactions within this frame. The use case is single + transaction, but higher frame rate. + If this property is set, the max packet size is 188 bytes, it can handle + more transactions than above case, it can accept transactions until it + considers the left room size within frame is less than 188 bytes, software + needs to make sure it does not send more than 90% + maximum_periodic_data_per_frame. The use case is multiple transactions, but + less frame rate. +- mux-controls: The mux control for toggling host/device output of this + controller. It's expected that a mux state of 0 indicates device mode and a + mux state of 1 indicates host mode. +- mux-control-names: Shall be "usb_switch" if mux-controls is specified. + +i.mx specific properties +- fsl,usbmisc: phandler of non-core register device, with one + argument that indicate usb controller index +- disable-over-current: disable over current detect +- over-current-active-high: over current signal polarity is high active, + typically over current signal polarity is low active. +- external-vbus-divider: enables off-chip resistor divider for Vbus + +Example: + + usb@f7ed0000 { + compatible = "chipidea,usb2"; + reg = <0xf7ed0000 0x10000>; + interrupts = ; + clocks = <&chip CLKID_USB0>; + phys = <&usb_phy0>; + phy-names = "usb-phy"; + vbus-supply = <®_usb0_vbus>; + itc-setting = <0x4>; /* 4 micro-frames */ + /* Incremental burst of unspecified length */ + ahb-burst-config = <0x0>; + tx-burst-size-dword = <0x10>; /* 64 bytes */ + rx-burst-size-dword = <0x10>; + extcon = <0>, <&usb_id>; + phy-clkgate-delay-us = <400>; + mux-controls = <&usb_switch>; + mux-control-names = "usb_switch"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/da8xx-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/da8xx-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ce22551b2b3ea2aa7dff3d0819093114dc421a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/da8xx-usb.txt @@ -0,0 +1,80 @@ +TI DA8xx MUSB +~~~~~~~~~~~~~ +For DA8xx/OMAP-L1x/AM17xx/AM18xx platforms. + +Required properties: +~~~~~~~~~~~~~~~~~~~~ + - compatible : Should be set to "ti,da830-musb". + + - reg: Offset and length of the USB controller register set. + + - interrupts: The USB interrupt number. + + - interrupt-names: Should be set to "mc". + + - dr_mode: The USB operation mode. Should be one of "host", "peripheral" or "otg". + + - phys: Phandle for the PHY device + + - phy-names: Should be "usb-phy" + + - dmas: specifies the dma channels + + - dma-names: specifies the names of the channels. Use "rxN" for receive + and "txN" for transmit endpoints. N specifies the endpoint number. + +Optional properties: +~~~~~~~~~~~~~~~~~~~~ + - vbus-supply: Phandle to a regulator providing the USB bus power. + +DMA +~~~ +- compatible: ti,da830-cppi41 +- reg: offset and length of the following register spaces: CPPI DMA Controller, + CPPI DMA Scheduler, Queue Manager +- reg-names: "controller", "scheduler", "queuemgr" +- #dma-cells: should be set to 2. The first number represents the + channel number (0 … 3 for endpoints 1 … 4). + The second number is 0 for RX and 1 for TX transfers. +- #dma-channels: should be set to 4 representing the 4 endpoints. + +Example: + usb_phy: usb-phy { + compatible = "ti,da830-usb-phy"; + #phy-cells = <0>; + }; + usb0: usb@200000 { + compatible = "ti,da830-musb"; + reg = <0x00200000 0x1000>; + ranges; + #address-cells = <1>; + #size-cells = <1>; + interrupts = <58>; + interrupt-names = "mc"; + + dr_mode = "host"; + vbus-supply = <&usb_vbus>; + phys = <&usb_phy 0>; + phy-names = "usb-phy"; + + dmas = <&cppi41dma 0 0 &cppi41dma 1 0 + &cppi41dma 2 0 &cppi41dma 3 0 + &cppi41dma 0 1 &cppi41dma 1 1 + &cppi41dma 2 1 &cppi41dma 3 1>; + dma-names = + "rx1", "rx2", "rx3", "rx4", + "tx1", "tx2", "tx3", "tx4"; + + + cppi41dma: dma-controller@201000 { + compatible = "ti,da830-cppi41"; + reg = <0x201000 0x1000 + 0x202000 0x1000 + 0x204000 0x4000>; + reg-names = "controller", "scheduler", "queuemgr"; + interrupts = <58>; + #dma-cells = <2>; + #dma-channels = <4>; + }; + + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/dwc2.txt b/arch/arm64/boot/dts/vendor/bindings/usb/dwc2.txt new file mode 100644 index 0000000000000000000000000000000000000000..46da5f1844608fa85c9a88a947fe50643392a7f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/dwc2.txt @@ -0,0 +1,53 @@ +Platform DesignWare HS OTG USB 2.0 controller +----------------------------------------------------- + +Required properties: +- compatible : One of: + - brcm,bcm2835-usb: The DWC2 USB controller instance in the BCM2835 SoC. + - hisilicon,hi6220-usb: The DWC2 USB controller instance in the hi6220 SoC. + - rockchip,rk3066-usb: The DWC2 USB controller instance in the rk3066 Soc; + - "rockchip,rk3188-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3188 Soc; + - "rockchip,rk3288-usb", "rockchip,rk3066-usb", "snps,dwc2": for rk3288 Soc; + - "lantiq,arx100-usb": The DWC2 USB controller instance in Lantiq ARX SoCs; + - "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq XRX SoCs; + - "amlogic,meson8-usb": The DWC2 USB controller instance in Amlogic Meson8 SoCs; + - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs; + - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; + - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs; + - snps,dwc2: A generic DWC2 USB controller with default parameters. + - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in STM32F4x9 SoCs + configured in FS mode; + - "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs + configured in HS mode; + - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs + configured in HS mode; +- reg : Should contain 1 register range (address and length) +- interrupts : Should contain 1 interrupt +- clocks: clock provider specifier +- clock-names: shall be "otg" +Refer to clk/clock-bindings.txt for generic clock consumer properties + +Optional properties: +- phys: phy provider specifier +- phy-names: shall be "usb2-phy" +Refer to phy/phy-bindings.txt for generic phy consumer properties +- dr_mode: shall be one of "host", "peripheral" and "otg" + Refer to usb/generic.txt +- g-rx-fifo-size: size of rx fifo size in gadget mode. +- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. +- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. + +Deprecated properties: +- g-use-dma: gadget DMA mode is automatically detected + +Example: + + usb@101c0000 { + compatible = "ralink,rt3050-usb, snps,dwc2"; + reg = <0x101c0000 40000>; + interrupts = <18>; + clocks = <&usb_otg_ahb_clk>; + clock-names = "otg"; + phys = <&usbphy>; + phy-names = "usb2-phy"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-cavium.txt b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-cavium.txt new file mode 100644 index 0000000000000000000000000000000000000000..710b782ccf654a443e2e394e24f3e55479a6032d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-cavium.txt @@ -0,0 +1,28 @@ +Cavium SuperSpeed DWC3 USB SoC controller + +Required properties: +- compatible: Should contain "cavium,octeon-7130-usb-uctl" + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +Example device node: + + uctl@1180069000000 { + compatible = "cavium,octeon-7130-usb-uctl"; + reg = <0x00011800 0x69000000 0x00000000 0x00000100>; + ranges; + #address-cells = <0x00000002>; + #size-cells = <0x00000002>; + refclk-frequency = <0x05f5e100>; + refclk-type-ss = "dlmc_ref_clk0"; + refclk-type-hs = "dlmc_ref_clk0"; + power = <0x00000002 0x00000002 0x00000001>; + xhci@1690000000000 { + compatible = "cavium,octeon-7130-xhci", "synopsys,dwc3"; + reg = <0x00016900 0x00000000 0x00000010 0x00000000>; + interrupt-parent = <0x00000010>; + interrupts = <0x00000009 0x00000004>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-st.txt b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..df0e02e1ee43e7b8bf88486d26bea2ed92d8aeef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-st.txt @@ -0,0 +1,66 @@ +ST DWC3 glue logic + +This file documents the parameters for the dwc3-st driver. +This driver controls the glue logic used to configure the dwc3 core on +STiH407 based platforms. + +Required properties: + - compatible : must be "st,stih407-dwc3" + - reg : glue logic base address and USB syscfg ctrl register offset + - reg-names : should be "reg-glue" and "syscfg-reg" + - st,syscon : should be phandle to system configuration node which + encompasses the glue registers + - resets : list of phandle and reset specifier pairs. There should be two entries, one + for the powerdown and softreset lines of the usb3 IP + - reset-names : list of reset signal names. Names should be "powerdown" and "softreset" +See: Documentation/devicetree/bindings/reset/st,sti-powerdown.txt +See: Documentation/devicetree/bindings/reset/reset.txt + + - #address-cells, #size-cells : should be '1' if the device has sub-nodes + with 'reg' property + + - pinctl-names : A pinctrl state named "default" must be defined +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + + - pinctrl-0 : Pin control group +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + + - ranges : allows valid 1:1 translation between child's address space and + parent's address space + +Sub-nodes: +The dwc3 core should be added as subnode to ST DWC3 glue as shown in the +example below. The DT binding details of dwc3 can be found in: +Documentation/devicetree/bindings/usb/dwc3.txt + +NB: The dr_mode property described in [1] is NOT optional for this driver, as the default value +is "otg", which isn't supported by this SoC. Valid dr_mode values for dwc3-st are either "host" +or "device". + +[1] Documentation/devicetree/bindings/usb/generic.txt + +Example: + +st_dwc3: dwc3@8f94000 { + compatible = "st,stih407-dwc3"; + reg = <0x08f94000 0x1000>, <0x110 0x4>; + reg-names = "reg-glue", "syscfg-reg"; + st,syscfg = <&syscfg_core>; + resets = <&powerdown STIH407_USB3_POWERDOWN>, + <&softreset STIH407_MIPHY2_SOFTRESET>; + reset-names = "powerdown", "softreset"; + #address-cells = <1>; + #size-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb3>; + ranges; + + dwc3: dwc3@9900000 { + compatible = "snps,dwc3"; + reg = <0x09900000 0x100000>; + interrupts = ; + dr_mode = "host"; + phy-names = "usb2-phy", "usb3-phy"; + phys = <&usb2_picophy2>, <&phy_port2 PHY_TYPE_USB3>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-xilinx.txt b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-xilinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..4aae5b2cef56e65d1d20f0a5a0960f19488a2001 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3-xilinx.txt @@ -0,0 +1,32 @@ +Xilinx SuperSpeed DWC3 USB SoC controller + +Required properties: +- compatible: Should contain "xlnx,zynqmp-dwc3" +- clocks: A list of phandles for the clocks listed in clock-names +- clock-names: Should contain the following: + "bus_clk" Master/Core clock, have to be >= 125 MHz for SS + operation and >= 60MHz for HS operation + + "ref_clk" Clock source to core during PHY power down + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +Example device node: + + usb@0 { + #address-cells = <0x2>; + #size-cells = <0x1>; + compatible = "xlnx,zynqmp-dwc3"; + clock-names = "bus_clk" "ref_clk"; + clocks = <&clk125>, <&clk125>; + ranges; + + dwc3@fe200000 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe200000 0x40000>; + interrupts = <0x0 0x41 0x4>; + dr_mode = "host"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/dwc3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3.txt new file mode 100644 index 0000000000000000000000000000000000000000..f27ddca0de76095f3ead2aa0aab52a29f37562d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/dwc3.txt @@ -0,0 +1,138 @@ +synopsys DWC3 CORE + +DWC3- USB3 CONTROLLER. Complies to the generic USB binding properties + as described in 'usb/generic.txt' + +Required properties: + - compatible: must be "snps,dwc3" + - reg : Address and length of the register set for the device + - interrupts: Interrupts used by the dwc3 controller. + - clock-names: should contain "ref", "bus_early", "suspend" + - clocks: list of phandle and clock specifier pairs corresponding to + entries in the clock-names property. + +Exception for clocks: + clocks are optional if the parent node (i.e. glue-layer) is compatible to + one of the following: + "amlogic,meson-axg-dwc3" + "amlogic,meson-gxl-dwc3" + "cavium,octeon-7130-usb-uctl" + "qcom,dwc3" + "samsung,exynos5250-dwusb3" + "samsung,exynos7-dwusb3" + "sprd,sc9860-dwc3" + "st,stih407-dwc3" + "ti,am437x-dwc3" + "ti,dwc3" + "ti,keystone-dwc3" + "rockchip,rk3399-dwc3" + "xlnx,zynqmp-dwc3" + +Optional properties: + - usb-phy : array of phandle for the PHY device. The first element + in the array is expected to be a handle to the USB2/HS PHY and + the second element is expected to be a handle to the USB3/SS PHY + - phys: from the *Generic PHY* bindings + - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy" + or "usb3-phy". + - resets: a single pair of phandle and reset specifier + - tx-fifo-resize: determines if the FIFO *has* to be reallocated. + - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable + - snps,disable_scramble_quirk: true when SW should disable data scrambling. + Only really useful for FPGA builds. + - snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled + - snps,lpm-nyet-threshold: LPM NYET threshold + - snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk + - snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk + - snps,req_p1p2p3_quirk: when set, the core will always request for + P1/P2/P3 transition sequence. + - snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain + amount of 8B10B errors occur. + - snps,del_phy_power_chg_quirk: when set core will delay PHY power change + from P0 to P1/P2/P3. + - snps,lfps_filter_quirk: when set core will filter LFPS reception. + - snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start + Polling LFPS after RX.Detect. + - snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value. + - snps,tx_de_emphasis: the value driven to the PHY is controlled by the + LTSSM during USB3 Compliance mode. + - snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy. + - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. + - snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG, + disabling the suspend signal to the PHY. + - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection + in PHY P3 power state. + - snps,dis-u2-freeclk-exists-quirk: when set, clear the u2_freeclk_exists + in GUSB2PHYCFG, specify that USB2 PHY doesn't provide + a free-running PHY clock. + - snps,dis-del-phy-power-chg-quirk: when set core will change PHY power + from P0 to P1/P2/P3 without delay. + - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check + during HS transmit. + - snps,dis_metastability_quirk: when set, disable metastability workaround. + CAUTION: use only if you are absolutely sure of it. + - snps,ssp-u3-u0-quirk: when set, core always changes PHY power state + to P2, before attempting a U3 exit handshake. + - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal + utmi_l1_suspend_n, false when asserts utmi_sleep_n + - snps,hird-threshold: HIRD threshold + - snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for + UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3. + - snps,quirk-frame-length-adjustment: Value for GFLADJ_30MHZ field of GFLADJ + register for post-silicon frame length adjustment when the + fladj_30mhz_sdbnd signal is invalid or incorrect. + - snps,rx-thr-num-pkt-prd: periodic ESS RX packet threshold count - host mode + only. Set this and rx-max-burst-prd to a valid, + non-zero value 1-16 (DWC_usb31 programming guide + section 1.2.4) to enable periodic ESS RX threshold. + - snps,rx-max-burst-prd: max periodic ESS RX burst size - host mode only. Set + this and rx-thr-num-pkt-prd to a valid, non-zero value + 1-16 (DWC_usb31 programming guide section 1.2.4) to + enable periodic ESS RX threshold. + - snps,tx-thr-num-pkt-prd: periodic ESS TX packet threshold count - host mode + only. Set this and tx-max-burst-prd to a valid, + non-zero value 1-16 (DWC_usb31 programming guide + section 1.2.3) to enable periodic ESS TX threshold. + - snps,tx-max-burst-prd: max periodic ESS TX burst size - host mode only. Set + this and tx-thr-num-pkt-prd to a valid, non-zero value + 1-16 (DWC_usb31 programming guide section 1.2.3) to + enable periodic ESS TX threshold. + - snps,xhci-imod-value: Interrupt moderation interval for host mode + (in increments of 250nsec). + - usb-core-id: Differentiates between different controllers present on a device. + - snps,bus-suspend-enable: If present then controller supports low power mode + during bus suspend. + - snps,usb3-u1u2-disable: If present, disable U1U2 low power modes in Superspeed mode + - snps,disable-clk-gating: If present, disable controller's internal clock gating. + Default it is enabled. + + - tx-fifo-resize: determines if the FIFO *has* to be reallocated. + - snps,incr-burst-type-adjustment: Value for INCR burst type of GSBUSCFG0 + register, undefined length INCR burst type enable and INCRx type. + When just one value, which means INCRX burst mode enabled. When + more than one value, which means undefined length INCR burst type + enabled. The values can be 1, 4, 8, 16, 32, 64, 128 and 256. + - snps,gen2-tx-de-emph: This register is for setting TX deemphasis used in + normal operation in gen2. + - snps,gen2-tx-de-emph1: This register is for setting TX deemphasis used in + compliance mode, pattern 13. + - snps,gen2-tx-de-emph2: This register is for setting TX deemphasis used in + compliance mode, pattern 14. + - snps,gen2-tx-de-emph3: This register is for setting TX deemphasis used in + compliance mode, pattern 16. + + - in addition all properties from usb-xhci.txt from the current directory are + supported as well + + +This is usually a subnode to DWC3 glue to which it is connected. + +dwc3@4a030000 { + compatible = "snps,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4> + usb-phy = <&usb2_phy>, <&usb3,phy>; + tx-fifo-resize; + snps,xhci-imod-value = <4000>; + snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ehci-omap.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ehci-omap.txt new file mode 100644 index 0000000000000000000000000000000000000000..d77e11a975a2d0565550ecbcb548264762b66ebc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ehci-omap.txt @@ -0,0 +1,31 @@ +OMAP HS USB EHCI controller + +This device is usually the child of the omap-usb-host +Documentation/devicetree/bindings/mfd/omap-usb-host.txt + +Required properties: + +- compatible: should be "ti,ehci-omap" +- reg: should contain one register range i.e. start and length +- interrupts: description of the interrupt line + +Optional properties: + +- phys: list of phandles to PHY nodes. + This property is required if at least one of the ports are in + PHY mode i.e. OMAP_EHCI_PORT_MODE_PHY + +To specify the port mode, see +Documentation/devicetree/bindings/mfd/omap-usb-host.txt + +Example for OMAP4: + +usbhsehci: ehci@4a064c00 { + compatible = "ti,ehci-omap"; + reg = <0x4a064c00 0x400>; + interrupts = <0 77 0x4>; +}; + +&usbhsehci { + phys = <&hsusb1_phy 0 &hsusb3_phy>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ehci-orion.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ehci-orion.txt new file mode 100644 index 0000000000000000000000000000000000000000..2855bae79fda60b2aa4e2ae7a6a7c54115e6cd60 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ehci-orion.txt @@ -0,0 +1,22 @@ +* EHCI controller, Orion Marvell variants + +Required properties: +- compatible: must be one of the following + "marvell,orion-ehci" + "marvell,armada-3700-ehci" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The EHCI interrupt + +Optional properties: +- clocks: reference to the clock +- phys: reference to the USB PHY +- phy-names: name of the USB PHY, should be "usb" + +Example: + + ehci@50000 { + compatible = "marvell,orion-ehci"; + reg = <0x50000 0x1000>; + interrupts = <19>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ehci-st.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ehci-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..065c91d955ad159a1ff4cbd75d26ff86f0e52c0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ehci-st.txt @@ -0,0 +1,38 @@ +ST USB EHCI controller + +Required properties: + - compatible : must be "st,st-ehci-300x" + - reg : physical base addresses of the controller and length of memory mapped + region + - interrupts : one EHCI interrupt should be described here + - pinctrl-names : a pinctrl state named "default" must be defined + - pinctrl-0 : phandle referencing pin configuration of the USB controller +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + - clocks : phandle list of usb clocks + - clock-names : should be "ic" for interconnect clock and "clk48" +See: Documentation/devicetree/bindings/clock/clock-bindings.txt + + - phys : phandle for the PHY device + - phy-names : should be "usb" + - resets : phandle + reset specifier pairs to the powerdown and softreset lines + of the USB IP + - reset-names : should be "power" and "softreset" +See: Documentation/devicetree/bindings/reset/st,sti-powerdown.txt +See: Documentation/devicetree/bindings/reset/reset.txt + +Example: + + ehci1: usb@fe203e00 { + compatible = "st,st-ehci-300x"; + reg = <0xfe203e00 0x100>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb1>; + clocks = <&clk_s_a1_ls 0>; + phys = <&usb2_phy>; + phy-names = "usb"; + + resets = <&powerdown STIH416_USB1_POWERDOWN>, + <&softreset STIH416_USB1_SOFTRESET>; + reset-names = "power", "softreset"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/exynos-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/exynos-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..c97374315049ae874fd5c9aaa764bb254ca780d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/exynos-usb.txt @@ -0,0 +1,119 @@ +Samsung Exynos SoC USB controller + +The USB devices interface with USB controllers on Exynos SOCs. +The device node has following properties. + +EHCI +Required properties: + - compatible: should be "samsung,exynos4210-ehci" for USB 2.0 + EHCI controller in host mode. + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + - clocks: from common clock binding: handle to usb clock. + - clock-names: from common clock binding: Shall be "usbhost". + - port: if in the SoC there are EHCI phys, they should be listed here. + One phy per port. Each port should have following entries: + - reg: port number on EHCI controller, e.g + On Exynos5250, port 0 is USB2.0 otg phy + port 1 is HSIC phy0 + port 2 is HSIC phy1 + - phys: from the *Generic PHY* bindings; specifying phy used by port. + +Optional properties: + - samsung,vbus-gpio: if present, specifies the GPIO that + needs to be pulled up for the bus to be powered. + +Example: + + usb@12110000 { + compatible = "samsung,exynos4210-ehci"; + reg = <0x12110000 0x100>; + interrupts = <0 71 0>; + samsung,vbus-gpio = <&gpx2 6 1 3 3>; + + clocks = <&clock 285>; + clock-names = "usbhost"; + + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + phys = <&usb2phy 1>; + }; + }; + +OHCI +Required properties: + - compatible: should be "samsung,exynos4210-ohci" for USB 2.0 + OHCI companion controller in host mode. + - reg: physical base address of the controller and length of memory mapped + region. + - interrupts: interrupt number to the cpu. + - clocks: from common clock binding: handle to usb clock. + - clock-names: from common clock binding: Shall be "usbhost". + - port: if in the SoC there are OHCI phys, they should be listed here. + One phy per port. Each port should have following entries: + - reg: port number on OHCI controller, e.g + On Exynos5250, port 0 is USB2.0 otg phy + port 1 is HSIC phy0 + port 2 is HSIC phy1 + - phys: from the *Generic PHY* bindings, specifying phy used by port. + +Example: + usb@12120000 { + compatible = "samsung,exynos4210-ohci"; + reg = <0x12120000 0x100>; + interrupts = <0 71 0>; + + clocks = <&clock 285>; + clock-names = "usbhost"; + + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + phys = <&usb2phy 1>; + }; + + }; + +DWC3 +Required properties: + - compatible: should be one of the following - + "samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on + Exynos5250/5420. + "samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7. + - #address-cells, #size-cells : should be '1' if the device has sub-nodes + with 'reg' property. + - ranges: allows valid 1:1 translation between child's address space and + parent's address space + - clocks: Clock IDs array as required by the controller. + - clock-names: names of clocks correseponding to IDs in the clock property + - vdd10-supply: 1.0V powr supply + - vdd33-supply: 3.0V/3.3V power supply + +Sub-nodes: +The dwc3 core should be added as subnode to Exynos dwc3 glue. +- dwc3 : + The binding details of dwc3 can be found in: + Documentation/devicetree/bindings/usb/dwc3.txt + +Example: + usb@12000000 { + compatible = "samsung,exynos5250-dwusb3"; + clocks = <&clock 286>; + clock-names = "usbdrd30"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + vdd10-supply = <&ldo11_reg>; + vdd33-supply = <&ldo9_reg>; + + dwc3 { + compatible = "synopsys,dwc3"; + reg = <0x12000000 0x10000>; + interrupts = <0 72 0>; + usb-phy = <&usb2_phy &usb3_phy>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/fcs,fusb302.txt b/arch/arm64/boot/dts/vendor/bindings/usb/fcs,fusb302.txt new file mode 100644 index 0000000000000000000000000000000000000000..6087dc7f209e32d4298ce794b9461dd87f71a8df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/fcs,fusb302.txt @@ -0,0 +1,23 @@ +Fairchild FUSB302 Type-C Port controllers + +Required properties : +- compatible : "fcs,fusb302" +- reg : I2C slave address +- interrupts : Interrupt specifier + +Optional properties : +- fcs,operating-sink-microwatt : + Minimum amount of power accepted from a sink + when negotiating + +Example: + +fusb302: typec-portc@54 { + compatible = "fcs,fusb302"; + reg = <0x54>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + fcs,max-sink-microvolt = <12000000>; + fcs,max-sink-microamp = <3000000>; + fcs,max-sink-microwatt = <36000000>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/fsl-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/fsl-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b08b006c5ead36944f9c34263ba456a42bfa166 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/fsl-usb.txt @@ -0,0 +1,81 @@ +Freescale SOC USB controllers + +The device node for a USB controller that is part of a Freescale +SOC is as described in the document "Open Firmware Recommended +Practice : Universal Serial Bus" with the following modifications +and additions : + +Required properties : + - compatible : Should be "fsl-usb2-mph" for multi port host USB + controllers, or "fsl-usb2-dr" for dual role USB controllers + or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121. + Wherever applicable, the IP version of the USB controller should + also be mentioned (for eg. fsl-usb2-dr-v2.2 for bsc9132). + - phy_type : For multi port host USB controllers, should be one of + "ulpi", or "serial". For dual role USB controllers, should be + one of "ulpi", "utmi", "utmi_wide", or "serial". + - reg : Offset and length of the register set for the device + - port0 : boolean; if defined, indicates port0 is connected for + fsl-usb2-mph compatible controllers. Either this property or + "port1" (or both) must be defined for "fsl-usb2-mph" compatible + controllers. + - port1 : boolean; if defined, indicates port1 is connected for + fsl-usb2-mph compatible controllers. Either this property or + "port0" (or both) must be defined for "fsl-usb2-mph" compatible + controllers. + - dr_mode : indicates the working mode for "fsl-usb2-dr" compatible + controllers. Can be "host", "peripheral", or "otg". Default to + "host" if not defined for backward compatibility. + +Recommended properties : + - interrupts : where a is the interrupt number and b is a + field that represents an encoding of the sense and level + information for the interrupt. This should be encoded based on + the information in section 2) depending on the type of interrupt + controller you have. + +Optional properties : + - fsl,invert-drvvbus : boolean; for MPC5121 USB0 only. Indicates the + port power polarity of internal PHY signal DRVVBUS is inverted. + - fsl,invert-pwr-fault : boolean; for MPC5121 USB0 only. Indicates + the PWR_FAULT signal polarity is inverted. + +Example multi port host USB controller device node : + usb@22000 { + compatible = "fsl-usb2-mph"; + reg = <22000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <27 1>; + phy_type = "ulpi"; + port0; + port1; + }; + +Example dual role USB controller device node : + usb@23000 { + compatible = "fsl-usb2-dr"; + reg = <23000 1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <700>; + interrupts = <26 1>; + dr_mode = "otg"; + phy = "ulpi"; + }; + +Example dual role USB controller device node for MPC5121ADS: + + usb@4000 { + compatible = "fsl,mpc5121-usb2-dr"; + reg = <0x4000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = < &ipic >; + interrupts = <44 0x8>; + dr_mode = "otg"; + phy_type = "utmi_wide"; + fsl,invert-drvvbus; + fsl,invert-pwr-fault; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/generic.txt b/arch/arm64/boot/dts/vendor/bindings/usb/generic.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a74ab8dfdc2f369979232e4fc90b4c660cf6b3a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/generic.txt @@ -0,0 +1,46 @@ +Generic USB Properties + +Optional properties: + - maximum-speed: tells USB controllers we want to work up to a certain + speed. Valid arguments are "super-speed", "high-speed", + "full-speed" and "low-speed". In case this isn't passed + via DT, USB controllers should default to their maximum + HW capability. + - dr_mode: tells Dual-Role USB controllers that we want to work on a + particular mode. Valid arguments are "host", + "peripheral" and "otg". In case this attribute isn't + passed via DT, USB DRD controllers should default to + OTG. + - phy_type: tells USB controllers that we want to configure the core to support + a UTMI+ PHY with an 8- or 16-bit interface if UTMI+ is + selected. Valid arguments are "utmi" and "utmi_wide". + In case this isn't passed via DT, USB controllers should + default to HW capability. + - otg-rev: tells usb driver the release number of the OTG and EH supplement + with which the device and its descriptors are compliant, + in binary-coded decimal (i.e. 2.0 is 0200H). This + property is used if any real OTG features(HNP/SRP/ADP) + is enabled, if ADP is required, otg-rev should be + 0x0200 or above. + - companion: phandle of a companion + - hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP + is the basic function of real OTG except you want it + to be a srp-capable only B device. + - srp-disable: tells OTG controllers we want to disable OTG SRP, SRP is + optional for OTG device. + - adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is + optional for OTG device. + +This is an attribute to a USB controller such as: + +dwc3@4a030000 { + compatible = "synopsys,dwc3"; + reg = <0x4a030000 0xcfff>; + interrupts = <0 92 4> + usb-phy = <&usb2_phy>, <&usb3,phy>; + maximum-speed = "super-speed"; + dr_mode = "otg"; + phy_type = "utmi_wide"; + otg-rev = <0x0200>; + adp-disable; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/gr-udc.txt b/arch/arm64/boot/dts/vendor/bindings/usb/gr-udc.txt new file mode 100644 index 0000000000000000000000000000000000000000..e9445224fabd97aa0a7faca780f5398ae72734ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/gr-udc.txt @@ -0,0 +1,34 @@ +USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC. + +The GRUSBDC USB Device Controller core is available in the GRLIB VHDL +IP core library. + +Note: In the ordinary environment for the core, a Leon SPARC system, +these properties are built from information in the AMBA plug&play. + +Required properties: + +- name : Should be "GAISLER_USBDC" or "01_021" + +- reg : Address and length of the register set for the device + +- interrupts : Interrupt numbers for this device. Either one interrupt number + for all interrupts, or one for status related interrupts, one for IN + endpoint related interrupts and one for OUT endpoint related interrupts. + +Optional properties: + +- epobufsizes : Array of buffer sizes for OUT endpoints when they differ + from the default size of 1024. The array is indexed by the OUT endpoint + number. If the property is present it typically contains one entry for + each OUT endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. + +- epibufsizes : Array of buffer sizes for IN endpoints when they differ + from the default size of 1024. The array is indexed by the IN endpoint + number. If the property is present it typically contains one entry for + each IN endpoint of the core. Fewer entries overrides the default sizes + only for as many endpoints as the array contains. + +For further information look in the documentation for the GLIB IP core library: +http://www.gaisler.com/products/grlib/grip.pdf diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/hisilicon,histb-xhci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/hisilicon,histb-xhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..f4633496b1221f21d61b9b87a13b281a1c153e5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/hisilicon,histb-xhci.txt @@ -0,0 +1,45 @@ +HiSilicon STB xHCI + +The device node for HiSilicon STB xHCI host controller + +Required properties: + - compatible: should be "hisilicon,hi3798cv200-xhci" + - reg: specifies physical base address and size of the registers + - interrupts : interrupt used by the controller + - clocks: a list of phandle + clock-specifier pairs, one for each + entry in clock-names + - clock-names: must contain + "bus": for bus clock + "utmi": for utmi clock + "pipe": for pipe clock + "suspend": for suspend clock + - resets: a list of phandle and reset specifier pairs as listed in + reset-names property. + - reset-names: must contain + "soft": for soft reset + - phys: a list of phandle + phy specifier pairs + - phy-names: must contain at least one of following: + "inno": for inno phy + "combo": for combo phy + +Optional properties: + - usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM + - usb3-lpm-capable: determines if platform is USB3 LPM capable + - imod-interval-ns: default interrupt moderation interval is 40000ns + +Example: + +xhci0: xchi@f98a0000 { + compatible = "hisilicon,hi3798cv200-xhci"; + reg = <0xf98a0000 0x10000>; + interrupts = ; + clocks = <&crg HISTB_USB3_BUS_CLK>, + <&crg HISTB_USB3_UTMI_CLK>, + <&crg HISTB_USB3_PIPE_CLK>, + <&crg HISTB_USB3_SUSPEND_CLK>; + clock-names = "bus", "utmi", "pipe", "suspend"; + resets = <&crg 0xb0 12>; + reset-names = "soft"; + phys = <&usb2_phy1_port1 0>, <&combphy0 PHY_TYPE_USB3>; + phy-names = "inno", "combo"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/iproc-udc.txt b/arch/arm64/boot/dts/vendor/bindings/usb/iproc-udc.txt new file mode 100644 index 0000000000000000000000000000000000000000..272d7faf1a971d3d0a99e74af05cb12081a9878b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/iproc-udc.txt @@ -0,0 +1,21 @@ +Broadcom IPROC USB Device controller. + +The device node is used for UDCs integrated into Broadcom's +iProc family (Northstar2, Cygnus) of SoCs'. The UDC is based +on Synopsys Designware Cores AHB Subsystem Device Controller +IP. + +Required properties: + - compatible: Add the compatibility strings for supported platforms. + For Broadcom NS2 platform, add "brcm,ns2-udc","brcm,iproc-udc". + For Broadcom Cygnus platform, add "brcm,cygnus-udc", "brcm,iproc-udc". + - reg: Offset and length of UDC register set + - interrupts: description of interrupt line + - phys: phandle to phy node. + +Example: + udc_dwc: usb@664e0000 { + compatible = "brcm,ns2-udc", "brcm,iproc-udc"; + reg = <0x664e0000 0x2000>; + interrupts = ; + phys = <&usbdrd_phy>; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/isp1301.txt b/arch/arm64/boot/dts/vendor/bindings/usb/isp1301.txt new file mode 100644 index 0000000000000000000000000000000000000000..ecd607dacba553eb664d10681bac8baae47002ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/isp1301.txt @@ -0,0 +1,24 @@ +* NXP ISP1301 USB transceiver + +Required properties: +- compatible: must be "nxp,isp1301" +- reg: I2C address of the ISP1301 device + +Optional properties of devices using ISP1301: +- transceiver: phandle of isp1301 - this helps the ISP1301 driver to find the + ISP1301 instance associated with the respective USB driver + +Example: + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + + usbd@31020000 { + compatible = "nxp,lpc3220-udc"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; + transceiver = <&isp1301>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/keystone-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/keystone-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..f96e09f784cc0c721dea4cb44dfa68debe27afb1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/keystone-usb.txt @@ -0,0 +1,54 @@ +TI Keystone Soc USB Controller + +DWC3 GLUE + +Required properties: + - compatible: should be "ti,keystone-dwc3". + - #address-cells, #size-cells : should be '1' if the device has sub-nodes + with 'reg' property. + - reg : Address and length of the register set for the USB subsystem on + the SOC. + - interrupts : The irq number of this device that is used to interrupt the + MPU. + - ranges: allows valid 1:1 translation between child's address space and + parent's address space. + +SoC-specific Required Properties: +The following are mandatory properties for Keystone 2 66AK2HK, 66AK2L and 66AK2E +SoCs only: + +- clocks: Clock ID for USB functional clock. +- clock-names: Must be "usb". + + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains: Should contain a phandle to a PM domain provider node + and an args specifier containing the USB device id + value. This property is as per the binding, + Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt + +Sub-nodes: +The dwc3 core should be added as subnode to Keystone DWC3 glue. +- dwc3 : + The binding details of dwc3 can be found in: + Documentation/devicetree/bindings/usb/dwc3.txt + +Example: + usb: usb@2680000 { + compatible = "ti,keystone-dwc3"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2680000 0x10000>; + clocks = <&clkusb>; + clock-names = "usb"; + interrupts = ; + ranges; + + dwc3@2690000 { + compatible = "synopsys,dwc3"; + reg = <0x2690000 0x70000>; + interrupts = ; + usb-phy = <&usb_phy>, <&usb_phy>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/lpc32xx-udc.txt b/arch/arm64/boot/dts/vendor/bindings/usb/lpc32xx-udc.txt new file mode 100644 index 0000000000000000000000000000000000000000..29f12a533f666e7242f794127cc4794bd23c7f19 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/lpc32xx-udc.txt @@ -0,0 +1,28 @@ +* NXP LPC32xx SoC USB Device Controller (UDC) + +Required properties: +- compatible: Must be "nxp,lpc3220-udc" +- reg: Physical base address of the controller and length of memory mapped + region. +- interrupts: The USB interrupts: + * USB Device Low Priority Interrupt + * USB Device High Priority Interrupt + * USB Device DMA Interrupt + * External USB Transceiver Interrupt (OTG ATX) +- transceiver: phandle of the associated ISP1301 device - this is necessary for + the UDC controller for connecting to the USB physical layer + +Example: + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + + usbd@31020000 { + compatible = "nxp,lpc3220-udc"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>; + transceiver = <&isp1301>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/maxim,max3421.txt b/arch/arm64/boot/dts/vendor/bindings/usb/maxim,max3421.txt new file mode 100644 index 0000000000000000000000000000000000000000..90495b1aeec2797ef30dcff6c38e0bc796ace6a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/maxim,max3421.txt @@ -0,0 +1,23 @@ +Maxim Integrated SPI-based USB 2.0 host controller MAX3421E + +Required properties: + - compatible: Should be "maxim,max3421" + - spi-max-frequency: maximum frequency for this device must not exceed 26 MHz. + - reg: chip select number to which this device is connected. + - maxim,vbus-en-pin: + GPOUTx is the number (1-8) of the GPOUT pin of MAX3421E to drive Vbus. + ACTIVE_LEVEL is 0 or 1. + - interrupts: the interrupt line description for the interrupt controller. + The driver configures MAX3421E for active low level triggered interrupts, + configure your interrupt line accordingly. + +Example: + + usb@0 { + compatible = "maxim,max3421"; + reg = <0>; + maxim,vbus-en-pin = <3 1>; + spi-max-frequency = <26000000>; + interrupt-parent = <&PIC>; + interrupts = <42>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/mediatek,mtk-xhci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/mediatek,mtk-xhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..266c2d917a2894afe8bccff05e95756d7a5b3a9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/mediatek,mtk-xhci.txt @@ -0,0 +1,120 @@ +MT8173 xHCI + +The device node for Mediatek SOC USB3.0 host controller + +There are two scenarios: the first one only supports xHCI driver; +the second one supports dual-role mode, and the host is based on xHCI +driver. Take account of backward compatibility, we divide bindings +into two parts. + +1st: only supports xHCI driver +------------------------------------------------------------------------ + +Required properties: + - compatible : should be "mediatek,-xhci", "mediatek,mtk-xhci", + soc-model is the name of SoC, such as mt8173, mt2712 etc, when using + "mediatek,mtk-xhci" compatible string, you need SoC specific ones in + addition, one of: + - "mediatek,mt8173-xhci" + - reg : specifies physical base address and size of the registers + - reg-names: should be "mac" for xHCI MAC and "ippc" for IP port control + - interrupts : interrupt used by the controller + - power-domains : a phandle to USB power domain node to control USB's + mtcmos + - vusb33-supply : regulator of USB avdd3.3v + + - clocks : a list of phandle + clock-specifier pairs, one for each + entry in clock-names + - clock-names : must contain + "sys_ck": controller clock used by normal mode, + the following ones are optional: + "ref_ck": reference clock used by low power mode etc, + "mcu_ck": mcu_bus clock for register access, + "dma_ck": dma_bus clock for data transfer by DMA + + - phys : see usb-hcd.txt in the current directory + +Optional properties: + - wakeup-source : enable USB remote wakeup; + - mediatek,syscon-wakeup : phandle to syscon used to access the register + of the USB wakeup glue layer between xHCI and SPM; it depends on + "wakeup-source", and has two arguments: + - the first one : register base address of the glue layer in syscon; + - the second one : hardware version of the glue layer + - 1 : used by mt8173 etc + - 2 : used by mt2712 etc + - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, + bit1 for u3port1, ... etc; + - vbus-supply : reference to the VBUS regulator; + - usb3-lpm-capable : supports USB3.0 LPM + - pinctrl-names : a pinctrl state named "default" must be defined + - pinctrl-0 : pin control group + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + - imod-interval-ns: default interrupt moderation interval is 5000ns + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + +Example: +usb30: usb@11270000 { + compatible = "mediatek,mt8173-xhci"; + reg = <0 0x11270000 0 0x1000>, + <0 0x11280700 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, + <&pericfg CLK_PERI_USB0>, + <&pericfg CLK_PERI_USB1>; + clock-names = "sys_ck", "ref_ck"; + phys = <&phy_port0 PHY_TYPE_USB3>, + <&phy_port1 PHY_TYPE_USB2>; + vusb33-supply = <&mt6397_vusb_reg>; + vbus-supply = <&usb_p1_vbus>; + usb3-lpm-capable; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; + wakeup-source; + imod-interval-ns = <10000>; +}; + +2nd: dual-role mode with xHCI driver +------------------------------------------------------------------------ + +In the case, xhci is added as subnode to mtu3. An example and the DT binding +details of mtu3 can be found in: +Documentation/devicetree/bindings/usb/mediatek,mtu3.txt + +Required properties: + - compatible : should be "mediatek,-xhci", "mediatek,mtk-xhci", + soc-model is the name of SoC, such as mt8173, mt2712 etc, when using + "mediatek,mtk-xhci" compatible string, you need SoC specific ones in + addition, one of: + - "mediatek,mt8173-xhci" + - reg : specifies physical base address and size of the registers + - reg-names: should be "mac" for xHCI MAC + - interrupts : interrupt used by the host controller + - power-domains : a phandle to USB power domain node to control USB's + mtcmos + - vusb33-supply : regulator of USB avdd3.3v + + - clocks : a list of phandle + clock-specifier pairs, one for each + entry in clock-names + - clock-names : must contain "sys_ck", and the following ones are optional: + "ref_ck", "mcu_ck" and "dma_ck" + +Optional properties: + - vbus-supply : reference to the VBUS regulator; + - usb3-lpm-capable : supports USB3.0 LPM + +Example: +usb30: usb@11270000 { + compatible = "mediatek,mt8173-xhci"; + reg = <0 0x11270000 0 0x1000>; + reg-names = "mac"; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; + vusb33-supply = <&mt6397_vusb_reg>; + usb3-lpm-capable; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/mediatek,mtu3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/mediatek,mtu3.txt new file mode 100644 index 0000000000000000000000000000000000000000..3382b5cb471d748dad74c9780dff600e5a384587 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/mediatek,mtu3.txt @@ -0,0 +1,98 @@ +The device node for Mediatek USB3.0 DRD controller + +Required properties: + - compatible : should be "mediatek,-mtu3", "mediatek,mtu3", + soc-model is the name of SoC, such as mt8173, mt2712 etc, + when using "mediatek,mtu3" compatible string, you need SoC specific + ones in addition, one of: + - "mediatek,mt8173-mtu3" + - reg : specifies physical base address and size of the registers + - reg-names: should be "mac" for device IP and "ippc" for IP port control + - interrupts : interrupt used by the device IP + - power-domains : a phandle to USB power domain node to control USB's + mtcmos + - vusb33-supply : regulator of USB avdd3.3v + - clocks : a list of phandle + clock-specifier pairs, one for each + entry in clock-names + - clock-names : must contain "sys_ck" for clock of controller, + the following clocks are optional: + "ref_ck", "mcu_ck" and "dam_ck"; + - phys : see usb-hcd.txt in the current directory + - dr_mode : should be one of "host", "peripheral" or "otg", + refer to usb/generic.txt + +Optional properties: + - #address-cells, #size-cells : should be '2' if the device has sub-nodes + with 'reg' property + - ranges : allows valid 1:1 translation between child's address space and + parent's address space + - extcon : external connector for vbus and idpin changes detection, needed + when supports dual-role mode. + - vbus-supply : reference to the VBUS regulator, needed when supports + dual-role mode. + - pinctrl-names : a pinctrl state named "default" is optional, and need be + defined if auto drd switch is enabled, that means the property dr_mode + is set as "otg", and meanwhile the property "mediatek,enable-manual-drd" + is not set. + - pinctrl-0 : pin control group + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + + - maximum-speed : valid arguments are "super-speed", "high-speed" and + "full-speed"; refer to usb/generic.txt + - enable-manual-drd : supports manual dual-role switch via debugfs; usually + used when receptacle is TYPE-A and also wants to support dual-role + mode. + - wakeup-source: enable USB remote wakeup of host mode. + - mediatek,syscon-wakeup : phandle to syscon used to access the register + of the USB wakeup glue layer between SSUSB and SPM; it depends on + "wakeup-source", and has two arguments: + - the first one : register base address of the glue layer in syscon; + - the second one : hardware version of the glue layer + - 1 : used by mt8173 etc + - 2 : used by mt2712 etc + - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, + bit1 for u3port1, ... etc; + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + +Sub-nodes: +The xhci should be added as subnode to mtu3 as shown in the following example +if host mode is enabled. The DT binding details of xhci can be found in: +Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt + +Example: +ssusb: usb@11271000 { + compatible = "mediatek,mt8173-mtu3"; + reg = <0 0x11271000 0 0x3000>, + <0 0x11280700 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + phys = <&phy_port0 PHY_TYPE_USB3>, + <&phy_port1 PHY_TYPE_USB2>; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, + <&pericfg CLK_PERI_USB0>, + <&pericfg CLK_PERI_USB1>; + clock-names = "sys_ck", "ref_ck"; + vusb33-supply = <&mt6397_vusb_reg>; + vbus-supply = <&usb_p0_vbus>; + extcon = <&extcon_usb>; + dr_mode = "otg"; + wakeup-source; + mediatek,syscon-wakeup = <&pericfg 0x400 1>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + usb_host: xhci@11270000 { + compatible = "mediatek,mt8173-xhci"; + reg = <0 0x11270000 0 0x1000>; + reg-names = "mac"; + interrupts = ; + power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; + vusb33-supply = <&mt6397_vusb_reg>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/msm-hsusb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/msm-hsusb.txt new file mode 100644 index 0000000000000000000000000000000000000000..8654a3ec23e481127260d36706a5611b9b49576a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/msm-hsusb.txt @@ -0,0 +1,110 @@ +MSM SoC HSUSB controllers + +EHCI + +Required properties: +- compatible: Should contain "qcom,ehci-host" +- regs: offset and length of the register set in the memory map +- usb-phy: phandle for the PHY device + +Example EHCI controller device node: + + ehci: ehci@f9a55000 { + compatible = "qcom,ehci-host"; + reg = <0xf9a55000 0x400>; + usb-phy = <&usb_otg>; + }; + +USB PHY with optional OTG: + +Required properties: +- compatible: Should contain: + "qcom,usb-otg-ci" for chipsets with ChipIdea 45nm PHY + "qcom,usb-otg-snps" for chipsets with Synopsys 28nm PHY + +- regs: Offset and length of the register set in the memory map +- interrupts: interrupt-specifier for the OTG interrupt. + +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "phy" USB PHY reference clock + "core" Protocol engine clock + "iface" Interface bus clock + "alt_core" Protocol engine clock for targets with asynchronous + reset methodology. (optional) + +- vdccx-supply: phandle to the regulator for the vdd supply for + digital circuit operation. +- v1p8-supply: phandle to the regulator for the 1.8V supply +- v3p3-supply: phandle to the regulator for the 3.3V supply + +- resets: A list of phandle + reset-specifier pairs for the + resets listed in reset-names +- reset-names: Should contain the following: + "phy" USB PHY controller reset + "link" USB LINK controller reset + +- qcom,otg-control: OTG control (VBUS and ID notifications) can be one of + 1 - PHY control + 2 - PMIC control + +Optional properties: +- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg" + +- switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual + SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex + D+/D- USB lines between connectors. + +- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device + Mode Eye Diagram test. Start address at which these values will be + written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as + "do not overwrite default value at this address". + For example: qcom,phy-init-sequence = < -1 0x63 >; + Will update only value at address ULPI_EXT_VENDOR_SPECIFIC + 1. + +- qcom,phy-num: Select number of pyco-phy to use, can be one of + 0 - PHY one, default + 1 - Second PHY + Some platforms may have configuration to allow USB + controller work with any of the two HSPHYs present. + +- qcom,vdd-levels: This property must be a list of three integer values + (no, min, max) where each value represents either a voltage + in microvolts or a value corresponding to voltage corner. + +- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy + and controller driver therefore enables pull-up explicitly + before starting controller using usbcmd run/stop bit. + +- extcon: phandles to external connector devices. First phandle + should point to external connector, which provide "USB" + cable events, the second should point to external connector + device, which provide "USB-HOST" cable events. If one of + the external connector devices is not required empty <0> + phandle should be specified. + +Example HSUSB OTG controller device node: + + usb@f9a55000 { + compatible = "qcom,usb-otg-snps"; + reg = <0xf9a55000 0x400>; + interrupts = <0 134 0>; + dr_mode = "peripheral"; + + clocks = <&gcc GCC_XO_CLK>, <&gcc GCC_USB_HS_SYSTEM_CLK>, + <&gcc GCC_USB_HS_AHB_CLK>; + + clock-names = "phy", "core", "iface"; + + vddcx-supply = <&pm8841_s2_corner>; + v1p8-supply = <&pm8941_l6>; + v3p3-supply = <&pm8941_l24>; + + resets = <&gcc GCC_USB2A_PHY_BCR>, <&gcc GCC_USB_HS_BCR>; + reset-names = "phy", "link"; + + qcom,otg-control = <1>; + qcom,phy-init-sequence = < -1 0x63 >; + qcom,vdd-levels = <1 5 7>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/msm-ssusb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/msm-ssusb.txt new file mode 100644 index 0000000000000000000000000000000000000000..56af1f8748fea6b488d59d274a3d74e8e71feccc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/msm-ssusb.txt @@ -0,0 +1,151 @@ +MSM SuperSpeed USB3.0 SoC controller + +Required properties : +- compatible : should be "qcom,dwc-usb3-msm" + - reg: Address and length of the register set for the device + Required regs are: + "core_base" : usb controller register set +- interrupts: IRQ lines used by this controller +- interrupt-names : Interrupt resource entries are : + "pwr_event_irq" : Interrupt to controller for asynchronous events in LPM. + Used for SS-USB power events. + - clocks: a list of phandles to the controller clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. Required clocks are "xo", "iface_clk", "core_clk", "sleep_clk" + and "utmi_clk". +- resets: reset specifier pair consists of phandle for the reset provider + and reset lines used by this controller. +- reset-names: reset signal name strings sorted in the same order as the resets + property. + +Optional properties : +- reg: Additional registers + "ahb2phy_base" : top-level register to configure read/write wait cycle with + both QMP and QUSB PHY registers. +- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for + below optional properties: + - qcom,msm_bus,name + - qcom,msm_bus,num_cases + - qcom,msm_bus,num_paths + - qcom,msm_bus,vectors +- qcom,default-bus-vote: To use default bus voting other than NOMINAL. Default is NOMINAL. +- interrupt-names : Optional interrupt resource entries are: + "ss_phy_irq" : Interrupt from super speed phy for wake up notification. + "hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM. + "dp_hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM + going through PDC. (use qcom,use-pdc-interrupts property) + "dm_hs_phy_irq" : Interrupt from HS PHY for asynchronous events in LPM + going through PDC. (use qcom,use-pdc-interrupts property) + + - clocks: a list of phandles to the controller clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. Optional clocks are "bus_aggr_clk", "noc_aggr_clk" and "cfg_ahb_clk". +- qcom,charging-disabled: If present then battery charging using USB + is disabled. +- vbus_dwc3-supply: phandle to the 5V VBUS supply regulator used for host mode. +- USB3_GDSC-supply : phandle to the globally distributed switch controller + regulator node to the USB controller. +- qcom,gdsc-collapse-in-host-suspend: GDSC regulator will not be turned off by + default when USB controller goes into LPM as part of host mode bus suspend. + This property collapses GDSC regulator as part of LPM entry in host mode bus suspend. +- dpdm-supply: phandle to dpdm supply which will be used to drive dp/dm lines + in high-z state. +- qcom,dwc-usb3-msm-tx-fifo-size: If present, represents RAM size available for + TX fifo allocation in bytes +- qcom,lpm-to-suspend-delay-ms: Indicates timeout (in milliseconds) to release wakeup source + after USB is kept into LPM. +- qcom,disable-dev-mode-pm: If present, it disables PM runtime functionality for device mode. +- qcom,core-clk-rate: If present, indicates clock frequency to be set for USB master clock. +- qcom,core-clk-rate-hs: If present, indicates min core clock frequency required to support + hs speed. +- qcom,use-pdc-interrupts: It present, it configures provided PDC IRQ with required + configuration for wakeup functionality. +- extcon: phandles to external connector devices. First phandle should point to + external connector, which provide type-C based "USB" cable events, the + second should point to external connector device, which provide type-C + "USB-HOST" cable events. A single phandle may be specified if a single + connector device provides both "USB" and "USB-HOST" events. An optional + third phandle may be specified for EUD based attach/detach events. A + mandatory fourth phandle has to be specified to provide microUSB based + "USB" cable events. An optional fifth phandle may be specified to provide + microUSB based "USB-HOST" cable events. Only the fourth phandle may be + specified if a single connector device provides both "USB" and "USB-HOST" + events. +- qcom,num-gsi-evt-buffs: If present, specifies number of GSI based hardware accelerated + event buffers. 1 event buffer is needed per h/w accelerated endpoint. +- qcom,gsi-reg-offset: USB GSI wrapper registers offset. It is must to provide this + if qcom,num-gsi-evt-buffs property is specified. Check dwc3-msm driver for order + and name of register offset need to provide. +- qcom,gsi-disable-io-coherency: IO-coherency is enabled by default in usb gsi driver. + This property disables io-coherency in usb gsi driver. +- qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs, + which is used as a vote by driver to get max performance in perf mode. +- qcom,smmu-s1-bypass: If present, configure SMMU to bypass stage 1 translation. +- qcom,dbm-version: If present, specifies DBM version. Currently "1.4" or "1.5" + are supported. If omitted, assume HW supports "1.5". +- qcom,reset-ep-after-lpm-resume: If present, dbm requires ep reset after + going to lpm +- qcom,host-poweroff-in-pm-suspend: If present, allow PM suspend to happen + irrespective of runtimePM state of host and power collapse the core. + This also leads to reset-resume of connected devices on PM resume. +- qcom,default-mode-none: If present, do not start any mode on probe for an OTG + capable DWC3 which does not have extcon handle. +- qcom,default-mode-host: If present, start host mode on probe for an OTG + capable DWC3 which does not have extcon handle. + +Sub nodes: +- Sub node for "DWC3- USB3 controller". + This sub node is required property for device node. The properties of this subnode + are specified in dwc3.txt. + +Example MSM USB3.0 controller device node : + usb@f9200000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0xf9200000 0xfc000>, + <0xf9b3e000 0x3ff>; + reg-names = "core_base", + "ahb2phy_base", + interrupts = <0 133 0>; + interrupt-names = "hs_phy_irq"; + vbus_dwc3-supply = <&pm8941_mvs1>; + USB3_GDSC-supply = <&gdsc_usb30>; + qcom,dwc-usb3-msm-dbm-eps = <4> + qcom,dwc_usb3-adc_tm = <&pm8941_adc_tm>; + qcom,dwc-usb3-msm-tx-fifo-size = <29696>; + qcom,usb-dbm = <&dbm_1p4>; + qcom,lpm-to-suspend-delay-ms = <2>; + qcom,num-gsi-evt-buffs = <0x2>; + qcom,pm-qos-latency = <2>; + + qcom,msm_bus,name = "usb3"; + qcom,msm_bus,num_cases = <2>; + qcom,msm_bus,num_paths = <1>; + qcom,msm_bus,vectors = + <61 512 0 0>, + <61 512 240000000 960000000>; + + clocks = <&clock_gcc clk_gcc_usb30_master_clk>, + <&clock_gcc clk_gcc_cfg_noc_usb3_axi_clk>, + <&clock_gcc clk_gcc_aggre1_usb3_axi_clk>, + <&clock_rpmcc RPM_AGGR2_NOC_CLK>, + <&clock_gcc clk_gcc_usb30_mock_utmi_clk>, + <&clock_gcc clk_gcc_usb30_sleep_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, + <&clock_gcc clk_cxo_dwc3_clk>; + + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", "noc_aggr_clk", + "utmi_clk", "sleep_clk", "cfg_ahb_clk", "xo"; + + resets = <&clock_gcc GCC_USB_30_BCR>; + reset-names = "core_reset"; + + dwc3@f9200000 { + compatible = "synopsys,dwc3"; + reg = <0xf9200000 0xfc000>; + interrupts = <0 131 0>, <0 179 0>; + interrupt-names = "irq", "otg_irq"; + tx-fifo-resize; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/npcm7xx-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/npcm7xx-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..5a0f1f14fbfae1afd809fb0451fd9055e7b0a43a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/npcm7xx-usb.txt @@ -0,0 +1,18 @@ +Nuvoton NPCM7XX SoC USB controllers: +----------------------------- + +EHCI: +----- + +Required properties: +- compatible: "nuvoton,npcm750-ehci" +- interrupts: Should contain the EHCI interrupt +- reg: Physical address and length of the register set for the device + +Example: + + ehci1: usb@f0806000 { + compatible = "nuvoton,npcm750-ehci"; + reg = <0xf0806000 0x1000>; + interrupts = <0 61 4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/nvidia,tegra124-xusb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/nvidia,tegra124-xusb.txt new file mode 100644 index 0000000000000000000000000000000000000000..3eee9e505400e4d62983955c4227aca3d959db5d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/nvidia,tegra124-xusb.txt @@ -0,0 +1,120 @@ +NVIDIA Tegra xHCI controller +============================ + +The Tegra xHCI controller supports both USB2 and USB3 interfaces exposed by +the Tegra XUSB pad controller. + +Required properties: +-------------------- +- compatible: Must be: + - Tegra124: "nvidia,tegra124-xusb" + - Tegra132: "nvidia,tegra132-xusb", "nvidia,tegra124-xusb" + - Tegra210: "nvidia,tegra210-xusb" +- reg: Must contain the base and length of the xHCI host registers, XUSB FPCI + registers and XUSB IPFS registers. +- reg-names: Must contain the following entries: + - "hcd" + - "fpci" + - "ipfs" +- interrupts: Must contain the xHCI host interrupt and the mailbox interrupt. +- clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. +- clock-names: Must include the following entries: + - xusb_host + - xusb_host_src + - xusb_falcon_src + - xusb_ss + - xusb_ss_src + - xusb_ss_div2 + - xusb_hs_src + - xusb_fs_src + - pll_u_480m + - clk_m + - pll_e +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - xusb_host + - xusb_ss + - xusb_src + Note that xusb_src is the shared reset for xusb_{ss,hs,fs,falcon,host}_src. +- nvidia,xusb-padctl: phandle to the XUSB pad controller that is used to + configure the USB pads used by the XHCI controller + +For Tegra124 and Tegra132: +- avddio-pex-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V. +- dvddio-pex-supply: PCIe/USB3 digital logic power supply. Must supply 1.05 V. +- avdd-usb-supply: USB controller power supply. Must supply 3.3 V. +- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V. +- avdd-pll-erefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. +- avdd-usb-ss-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. +- hvdd-usb-ss-supply: High-voltage PCIe/USB3 power supply. Must supply 3.3 V. +- hvdd-usb-ss-pll-e-supply: High-voltage PLLE power supply. Must supply 3.3 V. + +For Tegra210: +- dvddio-pex-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V. +- hvddio-pex-supply: High-voltage PCIe/USB3 power supply. Must supply 1.8 V. +- avdd-usb-supply: USB controller power supply. Must supply 3.3 V. +- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V. +- avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. +- dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. +- hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V. + +Optional properties: +-------------------- +- phys: Must contain an entry for each entry in phy-names. + See ../phy/phy-bindings.txt for details. +- phy-names: Should include an entry for each PHY used by the controller. The + following PHYs are available: + - Tegra124: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1 + - Tegra132: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1 + - Tegra210: usb2-0, usb2-1, usb2-2, usb2-3, hsic-0, usb3-0, usb3-1, usb3-2, + usb3-3 + +Example: +-------- + + usb@0,70090000 { + compatible = "nvidia,tegra124-xusb"; + reg = <0x0 0x70090000 0x0 0x8000>, + <0x0 0x70098000 0x0 0x1000>, + <0x0 0x70099000 0x0 0x1000>; + reg-names = "hcd", "fpci", "ipfs"; + + interrupts = , + ; + + clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>, + <&tegra_car TEGRA124_CLK_XUSB_HOST_SRC>, + <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>, + <&tegra_car TEGRA124_CLK_XUSB_SS>, + <&tegra_car TEGRA124_CLK_XUSB_SS_DIV2>, + <&tegra_car TEGRA124_CLK_XUSB_SS_SRC>, + <&tegra_car TEGRA124_CLK_XUSB_HS_SRC>, + <&tegra_car TEGRA124_CLK_XUSB_FS_SRC>, + <&tegra_car TEGRA124_CLK_PLL_U_480M>, + <&tegra_car TEGRA124_CLK_CLK_M>, + <&tegra_car TEGRA124_CLK_PLL_E>; + clock-names = "xusb_host", "xusb_host_src", "xusb_falcon_src", + "xusb_ss", "xusb_ss_div2", "xusb_ss_src", + "xusb_hs_src", "xusb_fs_src", "pll_u_480m", + "clk_m", "pll_e"; + resets = <&tegra_car 89>, <&tegra_car 156>, <&tegra_car 143>; + reset-names = "xusb_host", "xusb_ss", "xusb_src"; + + nvidia,xusb-padctl = <&padctl>; + + phys = <&{/padctl@0,7009f000/pads/usb2/lanes/usb2-1}>, /* mini-PCIe USB */ + <&{/padctl@0,7009f000/pads/usb2/lanes/usb2-2}>, /* USB A */ + <&{/padctl@0,7009f000/pads/pcie/lanes/pcie-0}>; /* USB A */ + phy-names = "usb2-1", "usb2-2", "usb3-0"; + + avddio-pex-supply = <&vdd_1v05_run>; + dvddio-pex-supply = <&vdd_1v05_run>; + avdd-usb-supply = <&vdd_3v3_lp0>; + avdd-pll-utmip-supply = <&vddio_1v8>; + avdd-pll-erefe-supply = <&avdd_1v05_run>; + avdd-usb-ss-pll-supply = <&vdd_1v05_run>; + hvdd-usb-ss-supply = <&vdd_3v3_lp0>; + hvdd-usb-ss-pll-e-supply = <&vdd_3v3_lp0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/nvidia,tegra20-ehci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/nvidia,tegra20-ehci.txt new file mode 100644 index 0000000000000000000000000000000000000000..f60785f73d3d5623b2cda6ddd4b8ea88fd6524a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/nvidia,tegra20-ehci.txt @@ -0,0 +1,23 @@ +Tegra SOC USB controllers + +The device node for a USB controller that is part of a Tegra +SOC is as described in the document "Open Firmware Recommended +Practice : Universal Serial Bus" with the following modifications +and additions : + +Required properties : + - compatible : For Tegra20, must contain "nvidia,tegra20-ehci". + For Tegra30, must contain "nvidia,tegra30-ehci". Otherwise, must contain + "nvidia,-ehci" plus at least one of the above, where is + tegra114, tegra124, tegra132, or tegra210. + - nvidia,phy : phandle of the PHY that the controller is connected to. + - clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names : Must include the following entries: + - usb + +Optional properties: + - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 + USB ports, which need reset twice due to hardware issues. diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/octeon-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/octeon-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..205c8d24d6e31487f412cc88fe860a4794765197 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/octeon-usb.txt @@ -0,0 +1,62 @@ +OCTEON/OCTEON+ USB BLOCK + +1) Main node + + Required properties: + + - compatible: must be "cavium,octeon-5750-usbn" + + - reg: specifies the physical base address of the USBN block and + the length of the memory mapped region. + + - #address-cells: specifies the number of cells needed to encode an + address. The value must be 2. + + - #size-cells: specifies the number of cells used to represent the size + of an address. The value must be 2. + + - ranges: specifies the translation between child address space and parent + address space. + + - clock-frequency: speed of the USB reference clock. Allowed values are + 12000000, 24000000 or 48000000. + + - cavium,refclk-type: type of the USB reference clock. Allowed values are + "crystal" or "external". + + - refclk-frequency: deprecated, use "clock-frequency". + + - refclk-type: deprecated, use "cavium,refclk-type". + +2) Child node + + The main node must have one child node which describes the built-in + USB controller. + + Required properties: + + - compatible: must be "cavium,octeon-5750-usbc" + + - reg: specifies the physical base address of the USBC block and + the length of the memory mapped region. + + - interrupts: specifies the interrupt number for the USB controller. + +3) Example: + + usbn: usbn@1180068000000 { + compatible = "cavium,octeon-5750-usbn"; + reg = <0x11800 0x68000000 0x0 0x1000>; + ranges; /* Direct mapping */ + #address-cells = <2>; + #size-cells = <2>; + clock-frequency = <12000000>; + cavium,refclk-type = "crystal"; + + usbc@16f0010000000 { + compatible = "cavium,octeon-5750-usbc"; + reg = <0x16f00 0x10000000 0x0 0x80000>; + interrupts = <0 56>; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ohci-da8xx.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-da8xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..24a826d5015ec5823f4c64b10cfbf0c06cb080a7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-da8xx.txt @@ -0,0 +1,23 @@ +DA8XX USB OHCI controller + +Required properties: + + - compatible: Should be "ti,da830-ohci" + - reg: Should contain one register range i.e. start and length + - interrupts: Description of the interrupt line + - phys: Phandle for the PHY device + - phy-names: Should be "usb-phy" + +Optional properties: + - vbus-supply: phandle of regulator that controls vbus power / over-current + +Example: + +ohci: usb@225000 { + compatible = "ti,da830-ohci"; + reg = <0x225000 0x1000>; + interrupts = <59>; + phys = <&usb_phy 1>; + phy-names = "usb-phy"; + vbus-supply = <®_usb_ohci>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ohci-nxp.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-nxp.txt new file mode 100644 index 0000000000000000000000000000000000000000..71e28c1017eddd93421c2b13ff81fdc2f685ce5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-nxp.txt @@ -0,0 +1,24 @@ +* OHCI controller, NXP ohci-nxp variant + +Required properties: +- compatible: must be "nxp,ohci-nxp" +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: The OHCI interrupt +- transceiver: phandle of the associated ISP1301 device - this is necessary for + the UDC controller for connecting to the USB physical layer + +Example (LPC32xx): + + isp1301: usb-transceiver@2c { + compatible = "nxp,isp1301"; + reg = <0x2c>; + }; + + ohci@31020000 { + compatible = "nxp,ohci-nxp"; + reg = <0x31020000 0x300>; + interrupt-parent = <&mic>; + interrupts = <0x3b 0>; + transceiver = <&isp1301>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ohci-omap3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-omap3.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce8c47cff6d0c98b803c9224929315a1efae10e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-omap3.txt @@ -0,0 +1,15 @@ +OMAP HS USB OHCI controller (OMAP3 and later) + +Required properties: + +- compatible: should be "ti,ohci-omap3" +- reg: should contain one register range i.e. start and length +- interrupts: description of the interrupt line + +Example for OMAP4: + +usbhsohci: ohci@4a064800 { + compatible = "ti,ohci-omap3"; + reg = <0x4a064800 0x400>; + interrupts = <0 76 0x4>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ohci-st.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-st.txt new file mode 100644 index 0000000000000000000000000000000000000000..44c998c16f85bfbfa4814fffb8dc3d344c14a3de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ohci-st.txt @@ -0,0 +1,36 @@ +ST USB OHCI controller + +Required properties: + + - compatible : must be "st,st-ohci-300x" + - reg : physical base addresses of the controller and length of memory mapped + region + - interrupts : one OHCI controller interrupt should be described here + - clocks : phandle list of usb clocks + - clock-names : should be "ic" for interconnect clock and "clk48" +See: Documentation/devicetree/bindings/clock/clock-bindings.txt + + - phys : phandle for the PHY device + - phy-names : should be "usb" + + - resets : phandle to the powerdown and reset controller for the USB IP + - reset-names : should be "power" and "softreset". +See: Documentation/devicetree/bindings/reset/st,sti-powerdown.txt +See: Documentation/devicetree/bindings/reset/reset.txt + +Example: + + ohci0: usb@fe1ffc00 { + compatible = "st,st-ohci-300x"; + reg = <0xfe1ffc00 0x100>; + interrupts = ; + clocks = <&clk_s_a1_ls 0>, + <&clockgen_b0 0>; + clock-names = "ic", "clk48"; + phys = <&usb2_phy>; + phy-names = "usb"; + + resets = <&powerdown STIH416_USB0_POWERDOWN>, + <&softreset STIH416_USB0_SOFTRESET>; + reset-names = "power", "softreset"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/omap-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/omap-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..38d9bb8507cf16fd47ef0620b2514587d4ac742f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/omap-usb.txt @@ -0,0 +1,80 @@ +OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS + +OMAP MUSB GLUE + - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" + - ti,hwmods : must be "usb_otg_hs" + - multipoint : Should be "1" indicating the musb controller supports + multipoint. This is a MUSB configuration-specific setting. + - num-eps : Specifies the number of endpoints. This is also a + MUSB configuration-specific setting. Should be set to "16" + - ram-bits : Specifies the ram address size. Should be set to "12" + - interface-type : This is a board specific setting to describe the type of + interface between the controller and the phy. It should be "0" or "1" + specifying ULPI and UTMI respectively. + - mode : Should be "3" to represent OTG. "1" signifies HOST and "2" + represents PERIPHERAL. + - power : Should be "50". This signifies the controller can supply up to + 100mA when operating in host mode. + - usb-phy : the phandle for the PHY device + - phys : the phandle for the PHY device (used by generic PHY framework) + - phy-names : the names of the PHY corresponding to the PHYs present in the + *phy* phandle. + +Optional properties: + - ctrl-module : phandle of the control module this glue uses to write to + mailbox + +SOC specific device node entry +usb_otg_hs: usb_otg_hs@4a0ab000 { + compatible = "ti,omap4-musb"; + ti,hwmods = "usb_otg_hs"; + multipoint = <1>; + num-eps = <16>; + ram-bits = <12>; + ctrl-module = <&omap_control_usb>; + phys = <&usb2_phy>; + phy-names = "usb2-phy"; +}; + +Board specific device node entry +&usb_otg_hs { + interface-type = <1>; + mode = <3>; + power = <50>; +}; + +OMAP DWC3 GLUE + - compatible : Should be + * "ti,dwc3" for OMAP5 and DRA7 + * "ti,am437x-dwc3" for AM437x + - ti,hwmods : Should be "usb_otg_ss" + - reg : Address and length of the register set for the device. + - interrupts : The irq number of this device that is used to interrupt the + MPU + - #address-cells, #size-cells : Must be present if the device has sub-nodes + - utmi-mode : controls the source of UTMI/PIPE status for VBUS and OTG ID. + It should be set to "1" for HW mode and "2" for SW mode. + - ranges: the child address space are mapped 1:1 onto the parent address space + +Optional Properties: + - extcon : phandle for the extcon device omap dwc3 uses to detect + connect/disconnect events. + - vbus-supply : phandle to the regulator device tree node if needed. + +Sub-nodes: +The dwc3 core should be added as subnode to omap dwc3 glue. +- dwc3 : + The binding details of dwc3 can be found in: + Documentation/devicetree/bindings/usb/dwc3.txt + +omap_dwc3 { + compatible = "ti,dwc3"; + ti,hwmods = "usb_otg_ss"; + reg = <0x4a020000 0x1ff>; + interrupts = <0 93 4>; + #address-cells = <1>; + #size-cells = <1>; + utmi-mode = <2>; + ranges; +}; + diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/onsemi_redriver.txt b/arch/arm64/boot/dts/vendor/bindings/usb/onsemi_redriver.txt new file mode 100644 index 0000000000000000000000000000000000000000..4c834a896bd8b4b6ad72310b477e09dea0acbcfe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/onsemi_redriver.txt @@ -0,0 +1,53 @@ +ON Semiconductor USB Type-C and display port 10Gbps Linear Re-Driver + +Required properties: +- compatible: Must be "onnn,redriver". +- reg: I2C address on the selected bus. +- extcon: phandles to external connector devices. The first phandle + should point to the external connector which provides + both "USB" cable events and "USB-HOST" cable events. + An optional second phandle may be specified for DP + lane events. + +Optional properties: +- eq: Equalization value of re-driver channel A/B/C/D, 8 bit. + eq[0] - eq[3]: Channel A-D parameter for USB. + eq[4] - eq[7]: Channel A-D parameter for DP. +- flat-gain: Flat gain control value of re-driver channel A/B/C/D, 8 bit. + flat_gain[0] - flat_gain[3]: Channel A-D parameter for USB. + flat_gain[4] - flat_gain[7]: Channel A-D parameter for DP. +- output-comp: Output compression value of re-driver channel A/B/C/D, +8 bit. + output_comp[0] - output_comp[3]: Channel A-D parameter for USB. + output_comp[4] - output_comp[7]: Channel A-D parameter for DP. +- loss-match: Loss profile matching control value of re-driver channel +A/B/C/D, 8 bit. + loss_match[0] - loss_match[3]: Channel A-D parameter for USB. + loss_match[4] - loss_match[7]: Channel A-D parameter for DP. + +Example: + redriver@19 { + compatible = "onnn,redriver"; + reg = <0x19>; + extcon = <&pm8150b_pdphy>, <&pm8150b_pdphy>; + eq = /bits/ 8 < + /* Parameters for USB */ + 0x4 0x4 0x4 0x4 + /* Parameters for DP */ + 0x6 0x4 0x4 0x6>; + flat-gain = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x1 0x1 0x3 + /* Parameters for DP */ + 0x2 0x1 0x1 0x2>; + output-comp = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x3 0x3 0x3 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + loss-match = /bits/ 8 < + /* Parameters for USB */ + 0x1 0x3 0x3 0x1 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/pxa-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/pxa-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c331799b87c73477d6cd8046fd9b4a5b4dbbd79 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/pxa-usb.txt @@ -0,0 +1,53 @@ +PXA USB controllers + +OHCI + +Required properties: + - compatible: Should be "marvell,pxa-ohci" for USB controllers + used in host mode. + +Optional properties: + - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3" + If present, enables the appropriate USB port of the controller. + - "marvell,port-mode" selects the mode of the ports: + 1 = PMM_NPS_MODE + 2 = PMM_GLOBAL_MODE + 3 = PMM_PERPORT_MODE + - "marvell,power-sense-low" - power sense pin is low-active. + - "marvell,power-control-low" - power control pin is low-active. + - "marvell,no-oc-protection" - disable over-current protection. + - "marvell,oc-mode-perport" - enable per-port over-current protection. + - "marvell,power_on_delay" Power On to Power Good time - in ms. + +Example: + + usb0: ohci@4c000000 { + compatible = "marvell,pxa-ohci", "usb-ohci"; + reg = <0x4c000000 0x100000>; + interrupts = <18>; + marvell,enable-port1; + marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */ + }; + +UDC + +Required properties: + - compatible: Should be "marvell,pxa270-udc" for USB controllers + used in device mode. + - reg: usb device MMIO address space + - interrupts: single interrupt generated by the UDC IP + - clocks: input clock of the UDC IP (see clock-bindings.txt) + +Optional properties: + - gpios: + - gpio activated to control the USB D+ pullup (see gpio.txt) + +Example: + + pxa27x_udc: udc@40600000 { + compatible = "marvell,pxa270-udc"; + reg = <0x40600000 0x10000>; + interrupts = <11>; + clocks = <&pxa2xx_clks 11>; + gpios = <&gpio 22 GPIO_ACTIVE_LOW>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/qcom,dwc3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/qcom,dwc3.txt new file mode 100644 index 0000000000000000000000000000000000000000..56c5b420b415f70b63e120ed40d45b0ff008eff6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/qcom,dwc3.txt @@ -0,0 +1,104 @@ +Qualcomm SuperSpeed DWC3 USB SoC controller + +Required properties: +- compatible: Compatible list, contains + "qcom,dwc3" + "qcom,msm8996-dwc3" for msm8996 SOC. + "qcom,sdm845-dwc3" for sdm845 SOC. +- reg: Offset and length of register set for QSCRATCH wrapper +- power-domains: specifies a phandle to PM domain provider node +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "core" Master/Core clock, have to be >= 125 MHz for SS + operation and >= 60MHz for HS operation + "mock_utmi" Mock utmi clock needed for ITP/SOF generation in + host mode. Its frequency should be 19.2MHz. + "sleep" Sleep clock, used for wakeup when USB3 core goes + into low power mode (U3). + +Optional clocks: + "iface" System bus AXI clock. + Not present on "qcom,msm8996-dwc3" compatible. + "cfg_noc" System Config NOC clock. + Not present on "qcom,msm8996-dwc3" compatible. +- assigned-clocks: Should be: + MOCK_UTMI_CLK + MASTER_CLK +- assigned-clock-rates: Should be: + 19.2Mhz (192000000) for MOCK_UTMI_CLK + >=125Mhz (125000000) for MASTER_CLK in SS mode + >=60Mhz (60000000) for MASTER_CLK in HS mode + +Optional properties: +- resets: Phandle to reset control that resets core and wrapper. +- interrupts: specifies interrupts from controller wrapper used + to wakeup from low power/susepnd state. Must contain + one or more entry for interrupt-names property +- interrupt-names: Must include the following entries: + - "hs_phy_irq": The interrupt that is asserted when a + wakeup event is received on USB2 bus + - "ss_phy_irq": The interrupt that is asserted when a + wakeup event is received on USB3 bus + - "dm_hs_phy_irq" and "dp_hs_phy_irq": Separate + interrupts for any wakeup event on DM and DP lines +- qcom,select-utmi-as-pipe-clk: if present, disable USB3 pipe_clk requirement. + Used when dwc3 operates without SSPHY and only + HS/FS/LS modes are supported. + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +Phy documentation is provided in the following places: +Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt - USB3 QMP PHY +Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt - USB2 QUSB2 PHY + +Example device nodes: + + hs_phy: phy@100f8800 { + compatible = "qcom,qusb2-v2-phy"; + ... + }; + + ss_phy: phy@100f8830 { + compatible = "qcom,qmp-v3-usb3-phy"; + ... + }; + + usb3_0: usb30@a6f8800 { + compatible = "qcom,dwc3"; + reg = <0xa6f8800 0x400>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 131 0>, <0 486 0>, <0 488 0>, <0 489 0>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq"; + + clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>; + clock-names = "core", "mock_utmi", "sleep"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <133000000>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + power-domains = <&gcc USB30_PRIM_GDSC>; + qcom,select-utmi-as-pipe-clk; + + dwc3@10000000 { + compatible = "snps,dwc3"; + reg = <0x10000000 0xcd00>; + interrupts = <0 205 0x4>; + phys = <&hs_phy>, <&ss_phy>; + phy-names = "usb2-phy", "usb3-phy"; + tx-fifo-resize; + dr_mode = "host"; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/qcom,msm-phy.txt b/arch/arm64/boot/dts/vendor/bindings/usb/qcom,msm-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..4935ad92164bf846d473527ea42933f36e0474d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/qcom,msm-phy.txt @@ -0,0 +1,253 @@ +QCOM USB PHY transceivers + +HSUSB PHY + +Required properties: + - compatible: Should be "qcom,usb-hsphy-snps-femto" + - reg: Address and length of the register set for the device + Required regs are: + "hsusb_phy_base" : the base register for the PHY + - -supply: phandle to the regulator device tree node + Required "supply-name" examples are: + "vdd" : vdd supply for HSPHY digital circuit operation + "vdda18" : 1.8v supply for HSPHY + "vdda33" : 3.3v supply for HSPHY + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. "ref_clk_src" is a mandatory clock. + - qcom,vdd-voltage-level: This property must be a list of three integer + values (no, min, max) where each value represents either a voltage in + microvolts or a value corresponding to voltage corner + - resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. + - reset-names: reset signal name strings sorted in the same order as the resets + property. + +Optional properties: + - qcom,param-override-seq: parameter override sequence with value, reg offset + pair. + - qcom,rcal-mask: efuse calibration mask. + - reg: Address and length of the register set for the device + Optional regs are: + "phy_rcal_reg": register address for efuse used for rext calibration + "eud_enable_reg" : register address to read eud enable/disable status. + +Example: + hsphy@f9200000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0xff1000 0x400>; + vdd-supply = <&pm8841_s2_corner>; + vdda18-supply = <&pm8941_l6>; + vdda33-supply = <&pm8941_l24>; + qcom,vdd-voltage-level = <0 872000 872000>; + qcom,param-override-seq = <0x43 0x70>; + }; + +SSUSB-QMP PHY + +Required properties: + - compatible: Should be "qcom,usb-ssphy-qmp", "qcom,usb-ssphy-qmp-v1" or + "qcom,usb-ssphy-qmp-v2" or "qcom,usb-ssphy-qmp-usb3-or-dp" or + "qcom,usb-ssphy-qmp-dp-combo" + - reg: Address and length of the register set for the device + Required reg-names entry must contain: + "qmp_phy_base" : QMP PHY Base register set. + - -supply: phandle to the regulator device tree node + Required "supply-name" examples are: + "vdd" : vdd supply for SSPHY digital circuit operation + "core" : high-voltage analog supply for SSPHY + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. Required clocks are "aux_clk" and "pipe_clk". + - qcom,vdd-voltage-level: This property must be a list of three integer + values (no, min, max) where each value represents either a voltage in + microvolts or a value corresponding to voltage corner + - qcom,qmp-phy-init-seq: QMP PHY initialization sequence with reg offset, its + value, delay after register write. + - qcom,qmp-phy-reg-offset: Provides important phy register offsets in an order + defined in the phy driver. + Provide below mentioned register offsets in order for non USB DP combo PHY: + USB3_PHY_PCS_STATUS, + USB3_PHY_AUTONOMOUS_MODE_CTRL, + USB3_PHY_LFPS_RXTERM_IRQ_CLEAR, + USB3_PHY_POWER_DOWN_CONTROL, + USB3_PHY_SW_RESET, + USB3_PHY_START + + In addion to above following set of registers offset needed for USB DP combo PHY in mentioned order: + USB3_DP_DP_PHY_PD_CTL, + USB3_DP_COM_POWER_DOWN_CTRL, + USB3_DP_COM_SW_RESET, + USB3_DP_COM_RESET_OVRD_CTRL, + USB3_DP_COM_PHY_MODE_CTRL, + USB3_DP_COM_TYPEC_CTRL, + USB3_DP_COM_SWI_CTRL, + + Optional register for enabling/disabling VLS clamp if available: + USB3_PCS_MISC_CLAMP_ENABLE + + Optional register for configuring USB Type-C port select if available: + USB3_PHY_PCS_MISC_TYPEC_CTRL + +- resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. +- reset-names: reset signal name strings sorted in the same order as the resets + property. + +Optional properties: + - reg: Additional register set of address and length to control QMP PHY are: + "tcsr_usb3_dp_phymode" : top-level CSR register to be written to select + super speed usb qmp phy. + "pcs_clamp_enable_reg" : Clamps the phy data inputs and enables USB3 + autonomous mode. + "vls_clamp_reg" : top-level CSR register to be written to enable phy vls + clamp which allows phy to detect autonomous mode. + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. "cfg_ahb_clk" and "com_aux_clk" are an optional clocks. + - qcom,vbus-valid-override: If present, indicates VBUS pin is not connected to + the USB PHY and the controller must rely on external VBUS notification in + order to manually relay the notification to the SSPHY. + - qcom,vdd-max-load-uA: If present, indicates the maximum current (in uA) the + PHY is expected to draw from the vdd power supply. + - qcom,core-voltage-level: This property must be a list of three integer + values (no, min, max) where each value represents either a voltage in + - qcom,core-max-load-uA: If present, indicates the maximum current (in uA) the + PHY is expected to draw from the core power supply. + microvolts or a value corresponding to voltage corner. + - qcom,link-training-reset: This property indicates to start link training + timer to reset the elastic buffer based on rx equalization value. + - extcon : phandle to external connector devices which provide type-C based + "USB-HOST" cable events. This phandle is used for notifying number + of lanes used in case of USB+DP concurrent mode to driver. + +Example: + ssphy0: ssphy@f9b38000 { + compatible = "qcom,usb-ssphy-qmp"; + reg = <0xf9b38000 0x16c>, + <0x01947244 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; + vdd-supply = <&pmd9635_l4>; + vdda18-supply = <&pmd9635_l8>; + qcom,vdd-voltage-level = <0 900000 1050000>; + qcom,vbus-valid-override; + + clocks = <&clock_gcc clk_gcc_usb3_phy_aux_clk>, + <&clock_gcc clk_gcc_usb3_phy_pipe_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>, + <&clock_gcc clk_ln_bb_clk1>, + <&clock_gcc clk_gcc_usb3_clkref_clk>; + + clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", + "ref_clk_src", "ref_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy_reset", + "phy_phy_reset"; + + }; + +QUSB2 High-Speed PHY + +Required properties: + - compatible: Should be "qcom,qusb2phy" or "qcom,qusb2phy-v2" + - reg: Address and length of the QUSB2 PHY register set + - reg-names: Should be "qusb_phy_base". + - -supply: phandle to the regulator device tree node + Required supplies are: + "vdd" : vdd supply for digital circuit operation + "vdda18" : 1.8v high-voltage analog supply + "vdda33" : 3.3v high-voltage analog supply + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. "ref_clk_src" is a mandatory clock. + - qcom,vdd-voltage-level: This property must be a list of three integer + values (no, min, max) where each value represents either a voltage in + microvolts or a value corresponding to voltage corner + - phy_type: Should be one of "ulpi" or "utmi". ChipIdea core uses "ulpi" mode. + - resets: reset specifier pair consists of phandle for the reset controller + and reset lines used by this controller. + - reset-names: reset signal name strings sorted in the same order as the resets + property. + - qcom,qusb-phy-reg-offset: Provides important phy register offsets in an order defined in phy driver. + +Optional properties: + - reg-names: Additional registers corresponding with the following: + "efuse_addr": EFUSE address to read and update analog tune parameter. + "emu_phy_base" : phy base address used for programming emulation target phy. + "ref_clk_addr" : ref_clk bcr address used for on/off ref_clk before reset. + "tcsr_clamp_dig_n" : To enable/disable digital clamp to the phy. When + de-asserted, it will prevent random leakage from qusb2 phy resulting from + out of sequence turn on/off of 1p8, 3p3 and DVDD regulators. + "refgen_north_bg_reg" : address used to read REFGEN status for overriding QUSB PHY register. + "tcsr_conn_box_spare" : To enable/disable USB HS AC/DC coupling feature. When + enabled, DP/DM signals will take path through capacitor when USB HS device is + connected. This is a required property if 'qcom,usb-hs-ac-bitmask' property is present. + - clocks: a list of phandles to the PHY clocks. Use as per + Documentation/devicetree/bindings/clock/clock-bindings.txt + - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" + property. "cfg_ahb_clk" and "ref_clk" are optional clocks. + - qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair. + - qcom,qusb-phy-host-init-seq: QUSB PHY initialization sequence for host mode + with value,reg pair. + - qcom,emu-init-seq : emulation initialization sequence with value,reg pair. + - qcom,phy-pll-reset-seq : emulation PLL reset sequence with value,reg pair. + - qcom,emu-dcm-reset-seq : emulation DCM reset sequence with value,reg pair. + - qcom,tune2-efuse-bit-pos: TUNE2 parameter related start bit position with EFUSE register for "qcom,qusb2phy". + - qcom,tune2-efuse-num-bits: Number of bits based value to use for TUNE2 high nibble for "qcom,qusb2phy". + - qcom,efuse-bit-pos: start bit position within EFUSE register for "qcom,qusb2phy-v2". + - qcom,efuse-num-bits: Number of bits to read from EFUSE register for "qcom,qusb2phy-v2". + - qcom,emulation: Indicates that we are running on emulation platform. + - qcom,hold-reset: Indicates that hold QUSB PHY into reset state. + - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided. + - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0 + - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Allowed names are + "default" and "sleep". + - qcom,tune2-efuse-correction: The value to be adjusted from fused value for + improved rise/fall times. + - qcom,host-chirp-erratum: Indicates host chirp fix is required. + - qcom,override-bias-ctrl2: Indicates override is done from driver for + BIAS_CTRL2 register. + - nvmem-cells: specifies the handle to represent the SoC revision. + usually it is defined by qfprom device node. + - nvmem-cell-names: specifies the given nvmem cell name as defined in + qfprom node. + - qcom,usb-hs-ac-bitmask: Specifies the polarity and enable bitfields in + tcsr_conn_box_spare register so as to enable USB HS AC/DC coupling feature. + - qcom,usb-hs-ac-value: Specifies the value to be written to polarity and + enable bitfields so as to enable USB HS AC/DC coupling feature. This is a + required property if 'qcom,usb-hs-ac-bitmask' property is present. + +Example: + qusb_phy: qusb@f9b39000 { + compatible = "qcom,qusb2phy"; + reg = <0x00079000 0x7000>; + reg-names = "qusb_phy_base"; + vdd-supply = <&pm8994_s2_corner>; + vdda18-supply = <&pm8994_l6>; + vdda33-supply = <&pm8994_l24>; + qcom,vdd-voltage-level = <1 5 7>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198>; /* QUSB2PHY_PLL_BIAS_CONTROL_2 */ + qcom,efuse-bit-pos = <21>; + qcom,efuse-num-bits = <3>; + + clocks = <&clock_rpm clk_ln_bb_clk>, + <&clock_gcc clk_gcc_rx2_usb1_clkref_clk>, + <&clock_gcc clk_gcc_usb_phy_cfg_ahb2phy_clk>; + clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk"; + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/qcom,usb-emu-phy.txt b/arch/arm64/boot/dts/vendor/bindings/usb/qcom,usb-emu-phy.txt new file mode 100644 index 0000000000000000000000000000000000000000..e35e3f5899f625ebecb2f82ab3b5da7ac38f7714 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/qcom,usb-emu-phy.txt @@ -0,0 +1,30 @@ +Qualcomm Technologies, Inc. emulation USB PHY + +Required properties: +- compatible: should contain "qcom,usb-emu-phy" +- reg: offset and length of the register set in the memory map +- qcom,emu-init-seq: emulation initialization sequence of value,reg pairs + +Optional properties: +- reg: Additional register names supported are + "qcratch_base" + +Example PHY device node: + + usb_emu_phy@a720000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x0a720000 0x9500>, + <0x0a6f8800 0x100>; + reg-names = "base", "qcratch_base"; + + qcom,emu-init-seq = <0xfff0 0x4 + 0xfff3 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/qpnp-pdphy.txt b/arch/arm64/boot/dts/vendor/bindings/usb/qpnp-pdphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..ebbb6d5b477075c11ceb80bbd9f6d5e440495909 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/qpnp-pdphy.txt @@ -0,0 +1,71 @@ +Qualcomm Technologies, Inc. QPNP PD PHY - USB Power Delivery Physical layer + +Required properties: +- compatible: Must be "qcom,qpnp-pdphy" +- reg: The base address for this peripheral +- vdd-pdphy-supply: phandle to the VDD supply regulator node +- interrupts: Specifies the interrupt associated with the peripheral. +- interrupt-names: Specifies the interrupt names for the peripheral. Every + available interrupt needs to have an associated name + with it to indentify its purpose. + + The following interrupts are required: + + 0: sig-tx + Triggers when a signal (HardReset or CableReset) + has been sent. + 1: sig-rx + Triggers when a signal has been received. + 2: msg-tx + Triggers when a message has been sent and the + related GoodCRC has been received. + 3: msg-rx + Triggers when a message has been received and + the related GoodCRC was sent successfully. + 4: msg-tx-failed + Triggers when a message failed all its + transmission attempts, either due to a non-idle + bus or missing GoodCRC reply. + 5: msg-tx-discarded + Triggers when a message is received while a + transmission request was in place. The request + itself is discarded. + 6: msg-rx-discarded + Triggers when a message was received but had to + be discarded due to the RX buffer still in use + by SW. + +Optional properties: +- vbus-supply: Regulator that enables VBUS source output +- vconn-supply: Regulator that enables VCONN source output. This will + be supplied on the USB CC line that is not used for + communication when Ra resistance is detected. +- qcom,default-sink-caps: List of 32-bit values representing the nominal sink + capabilities in voltage (millivolts) and current + (milliamps) pairs. + +Example: + qcom,qpnp-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + vdd-pdphy-supply = <&pm8998_l24>; + interrupts = <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>, /* 9V @ 3A */ + <12000 2250>; /* 12V @ 2.25A */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/renesas_usb3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/renesas_usb3.txt new file mode 100644 index 0000000000000000000000000000000000000000..2c071bb5801e7c8af98c44deb0c87d80627269b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/renesas_usb3.txt @@ -0,0 +1,38 @@ +Renesas Electronics USB3.0 Peripheral driver + +Required properties: + - compatible: Must contain one of the following: + - "renesas,r8a7795-usb3-peri" + - "renesas,r8a7796-usb3-peri" + - "renesas,r8a77965-usb3-peri" + - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible + device + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + + - reg: Base address and length of the register for the USB3.0 Peripheral + - interrupts: Interrupt specifier for the USB3.0 Peripheral + - clocks: clock phandle and specifier pair + +Optional properties: + - phys: phandle + phy specifier pair + - phy-names: must be "usb" + +Example of R-Car H3 ES1.x: + usb3_peri0: usb@ee020000 { + compatible = "renesas,r8a7795-usb3-peri", + "renesas,rcar-gen3-usb3-peri"; + reg = <0 0xee020000 0 0x400>; + interrupts = ; + clocks = <&cpg CPG_MOD 328>; + }; + + usb3_peri1: usb@ee060000 { + compatible = "renesas,r8a7795-usb3-peri", + "renesas,rcar-gen3-usb3-peri"; + reg = <0 0xee060000 0 0x400>; + interrupts = ; + clocks = <&cpg CPG_MOD 327>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/renesas_usbhs.txt b/arch/arm64/boot/dts/vendor/bindings/usb/renesas_usbhs.txt new file mode 100644 index 0000000000000000000000000000000000000000..43960faf5a88c6c1c1c3f34e11d9ceef7d5e40cf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/renesas_usbhs.txt @@ -0,0 +1,46 @@ +Renesas Electronics USBHS driver + +Required properties: + - compatible: Must contain one or more of the following: + + - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device + - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device + - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device + - "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device + - "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device + - "renesas,usbhs-r8a7793" for r8a7793 (R-Car M2-N) compatible device + - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device + - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device + - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device + - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device + - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device + - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device + - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices + - "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device + - "renesas,rza1-usbhs" for RZ/A1 compatible device + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first followed + by the generic version. + + - reg: Base address and length of the register for the USBHS + - interrupts: Interrupt specifier for the USBHS + - clocks: A list of phandle + clock specifier pairs + +Optional properties: + - renesas,buswait: Integer to use BUSWAIT register + - renesas,enable-gpio: A gpio specifier to check GPIO determining if USB + function should be enabled + - phys: phandle + phy specifier pair + - phy-names: must be "usb" + - dmas: Must contain a list of references to DMA specifiers. + - dma-names : named "ch%d", where %d is the channel number ranging from zero + to the number of channels (DnFIFOs) minus one. + +Example: + usbhs: usb@e6590000 { + compatible = "renesas,usbhs-r8a7790", "renesas,rcar-gen2-usbhs"; + reg = <0 0xe6590000 0 0x100>; + interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7790_CLK_HSUSB>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/richtek,rt1711h.txt b/arch/arm64/boot/dts/vendor/bindings/usb/richtek,rt1711h.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4cf53c071d94cabf834e450a19ee4a3e49ecab8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/richtek,rt1711h.txt @@ -0,0 +1,15 @@ +Richtek RT1711H TypeC PD Controller. + +Required properties: + - compatible : Must be "richtek,rt1711h". + - reg : Must be 0x4e, it's slave address of RT1711H. + - interrupts : where a is the interrupt number and b represents an + encoding of the sense and level information for the interrupt. + +Example : +rt1711h@4e { + compatible = "richtek,rt1711h"; + reg = <0x4e>; + interrupt-parent = <&gpio26>; + interrupts = <0 IRQ_TYPE_LEVEL_LOW>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/rockchip,dwc3.txt b/arch/arm64/boot/dts/vendor/bindings/usb/rockchip,dwc3.txt new file mode 100644 index 0000000000000000000000000000000000000000..c8c4b00ecb941fe85144fb3efd8c5cfa4ec0e5e4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/rockchip,dwc3.txt @@ -0,0 +1,56 @@ +Rockchip SuperSpeed DWC3 USB SoC controller + +Required properties: +- compatible: should contain "rockchip,rk3399-dwc3" for rk3399 SoC +- clocks: A list of phandle + clock-specifier pairs for the + clocks listed in clock-names +- clock-names: Should contain the following: + "ref_clk" Controller reference clk, have to be 24 MHz + "suspend_clk" Controller suspend clk, have to be 24 MHz or 32 KHz + "bus_clk" Master/Core clock, have to be >= 62.5 MHz for SS + operation and >= 30MHz for HS operation + "grf_clk" Controller grf clk + +Required child node: +A child node must exist to represent the core DWC3 IP block. The name of +the node is not important. The content of the node is defined in dwc3.txt. + +Phy documentation is provided in the following places: +Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt - USB2.0 PHY +Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt - Type-C PHY + +Example device nodes: + + usbdrd3_0: usb@fe800000 { + compatible = "rockchip,rk3399-dwc3"; + clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>, + <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk", "grf_clk"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + usbdrd_dwc3_0: dwc3@fe800000 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe800000 0x0 0x100000>; + interrupts = ; + dr_mode = "otg"; + }; + }; + + usbdrd3_1: usb@fe900000 { + compatible = "rockchip,rk3399-dwc3"; + clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>, + <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_GRF>; + clock-names = "ref_clk", "suspend_clk", + "bus_clk", "grf_clk"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + usbdrd_dwc3_1: dwc3@fe900000 { + compatible = "snps,dwc3"; + reg = <0x0 0xfe900000 0x0 0x100000>; + interrupts = ; + dr_mode = "otg"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/s3c2410-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/s3c2410-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..e45b38ce29865030c090421faa46f1a6b9e36d98 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/s3c2410-usb.txt @@ -0,0 +1,22 @@ +Samsung S3C2410 and compatible SoC USB controller + +OHCI + +Required properties: + - compatible: should be "samsung,s3c2410-ohci" for USB host controller + - reg: address and lenght of the controller memory mapped region + - interrupts: interrupt number for the USB OHCI controller + - clocks: Should reference the bus and host clocks + - clock-names: Should contain two strings + "usb-bus-host" for the USB bus clock + "usb-host" for the USB host clock + +Example: + +usb0: ohci@49000000 { + compatible = "samsung,s3c2410-ohci"; + reg = <0x49000000 0x100>; + interrupts = <0 0 26 3>; + clocks = <&clocks UCLK>, <&clocks HCLK_USBH>; + clock-names = "usb-bus-host", "usb-host"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/samsung-hsotg.txt b/arch/arm64/boot/dts/vendor/bindings/usb/samsung-hsotg.txt new file mode 100644 index 0000000000000000000000000000000000000000..0388634598ce6d3d0273653c75d3dc7f98f9cdf9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/samsung-hsotg.txt @@ -0,0 +1,38 @@ +Samsung High Speed USB OTG controller +----------------------------- + +The Samsung HSOTG IP can be found on Samsung SoCs, from S3C6400 onwards. +It gives functionality of OTG-compliant USB 2.0 host and device with +support for USB 2.0 high-speed (480Mbps) and full-speed (12 Mbps) +operation. + +Currently only device mode is supported. + +Binding details +----- + +Required properties: +- compatible: "samsung,s3c6400-hsotg" should be used for all currently + supported SoC, +- interrupts: specifier of interrupt signal of interrupt controller, + according to bindings of interrupt controller, +- clocks: contains an array of clock specifiers: + - first entry: OTG clock +- clock-names: contains array of clock names: + - first entry: must be "otg" +- vusb_d-supply: phandle to voltage regulator of digital section, +- vusb_a-supply: phandle to voltage regulator of analog section. + +Example +----- + + hsotg@12480000 { + compatible = "samsung,s3c6400-hsotg"; + reg = <0x12480000 0x20000>; + interrupts = <0 71 0>; + clocks = <&clock 305>; + clock-names = "otg"; + vusb_d-supply = <&vusb_reg>; + vusb_a-supply = <&vusbdac_reg>; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/spear-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/spear-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..1dc91cc459c0d62c3c86eadc4b2609fc037c8ab7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/spear-usb.txt @@ -0,0 +1,35 @@ +ST SPEAr SoC USB controllers: +----------------------------- + +EHCI: +----- + +Required properties: +- compatible: "st,spear600-ehci" +- interrupts: Should contain the EHCI interrupt + +Example: + + ehci@e1800000 { + compatible = "st,spear600-ehci", "usb-ehci"; + reg = <0xe1800000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <27>; + }; + + +OHCI: +----- + +Required properties: +- compatible: "st,spear600-ohci" +- interrupts: Should contain the OHCI interrupt + +Example: + + ohci@e1900000 { + compatible = "st,spear600-ohci", "usb-ohci"; + reg = <0xe1800000 0x1000>; + interrupt-parent = <&vic1>; + interrupts = <26>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/twlxxxx-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/twlxxxx-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..17327a296110a49814cc7b725a0fb111a2ae55da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/twlxxxx-usb.txt @@ -0,0 +1,43 @@ +USB COMPARATOR OF TWL CHIPS + +TWL6030 USB COMPARATOR + - compatible : Should be "ti,twl6030-usb" + - interrupts : Two interrupt numbers to the cpu should be specified. First + interrupt number is the otg interrupt number that raises ID interrupts when + the controller has to act as host and the second interrupt number is the + usb interrupt number that raises VBUS interrupts when the controller has to + act as device + - usb-supply : phandle to the regulator device tree node. It should be vusb + if it is twl6030 or ldousb if it is twl6032 subclass. + +twl6030-usb { + compatible = "ti,twl6030-usb"; + interrupts = < 4 10 >; +}; + +Board specific device node entry +&twl6030-usb { + usb-supply = <&vusb>; +}; + +TWL4030 USB PHY AND COMPARATOR + - compatible : Should be "ti,twl4030-usb" + - interrupts : The interrupt numbers to the cpu should be specified. First + interrupt number is the otg interrupt number that raises ID interrupts + and VBUS interrupts. The second interrupt number is optional. + - -supply : phandle to the regulator device tree node. + should be vusb1v5, vusb1v8 and vusb3v1 + - usb_mode : The mode used by the phy to connect to the controller. "1" + specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode. + +If a sibling node is compatible "ti,twl4030-bci", then it will find +this device and query it for USB power status. + +twl4030-usb { + compatible = "ti,twl4030-usb"; + interrupts = < 10 4 >; + usb1v5-supply = <&vusb1v5>; + usb1v8-supply = <&vusb1v8>; + usb3v1-supply = <&vusb3v1>; + usb_mode = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/typec-tcpci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/typec-tcpci.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dd1469e73180810180b81f422dd5a1489dcd35e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/typec-tcpci.txt @@ -0,0 +1,49 @@ +TCPCI(Typec port cotroller interface) binding +--------------------------------------------- + +Required properties: +- compatible: should be set one of following: + - "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110. + +- reg: the i2c slave address of typec port controller device. +- interrupt-parent: the phandle to the interrupt controller which provides + the interrupt. +- interrupts: interrupt specification for tcpci alert. + +Required sub-node: +- connector: The "usb-c-connector" attached to the tcpci chip, the bindings + of connector node are specified in + Documentation/devicetree/bindings/connector/usb-connector.txt + +Example: + +ptn5110@50 { + compatible = "nxp,ptn5110"; + reg = <0x50>; + interrupt-parent = <&gpio3>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + + usb_con: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "dual"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + usb_con_ss: endpoint { + remote-endpoint = <&usb3_data_ss>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/udc-xilinx.txt b/arch/arm64/boot/dts/vendor/bindings/usb/udc-xilinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..47b4e397a08de6d71f93f5526f5a91922f5aef7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/udc-xilinx.txt @@ -0,0 +1,18 @@ +Xilinx USB2 device controller + +Required properties: +- compatible : Should be "xlnx,usb2-device-4.00.a" +- reg : Physical base address and size of the USB2 + device registers map. +- interrupts : Should contain single irq line of USB2 device + controller +- xlnx,has-builtin-dma : if DMA is included + +Example: + axi-usb2-device@42e00000 { + compatible = "xlnx,usb2-device-4.00.a"; + interrupts = <0x0 0x39 0x1>; + reg = <0x42e00000 0x10000>; + xlnx,has-builtin-dma; + }; + diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ulpi.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ulpi.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca179dc4bd50a207ecd817f86a213a7d4a3dfd89 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ulpi.txt @@ -0,0 +1,20 @@ +ULPI bus binding +---------------- + +Phys that are behind a ULPI connection can be described with the following +binding. The host controller shall have a "ulpi" named node as a child, and +that node shall have one enabled node underneath it representing the ulpi +device on the bus. + +EXAMPLE +------- + +usb { + compatible = "vendor,usb-controller"; + + ulpi { + phy { + compatible = "vendor,phy"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-device.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-device.txt new file mode 100644 index 0000000000000000000000000000000000000000..036be172b1ae8cf2ebd4bfde3a1a47898c9b38d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-device.txt @@ -0,0 +1,102 @@ +Generic USB Device Properties + +Usually, we only use device tree for hard wired USB device. +The reference binding doc is from: +http://www.devicetree.org/open-firmware/bindings/usb/usb-1_0.ps + +Four types of device-tree nodes are defined: "host-controller nodes" +representing USB host controllers, "device nodes" representing USB devices, +"interface nodes" representing USB interfaces and "combined nodes" +representing simple USB devices. + +A combined node shall be used instead of a device node and an interface node +for devices of class 0 or 9 (hub) with a single configuration and a single +interface. + +A "hub node" is a combined node or an interface node that represents a USB +hub. + + +Required properties for device nodes: +- compatible: "usbVID,PID", where VID is the vendor id and PID the product id. + The textual representation of VID and PID shall be in lower case hexadecimal + with leading zeroes suppressed. The other compatible strings from the above + standard binding could also be used, but a device adhering to this binding + may leave out all except for "usbVID,PID". +- reg: the number of the USB hub port or the USB host-controller port to which + this device is attached. The range is 1-255. + + +Required properties for device nodes with interface nodes: +- #address-cells: shall be 2 +- #size-cells: shall be 0 + + +Required properties for interface nodes: +- compatible: "usbifVID,PID.configCN.IN", where VID is the vendor id, PID is + the product id, CN is the configuration value and IN is the interface + number. The textual representation of VID, PID, CN and IN shall be in lower + case hexadecimal with leading zeroes suppressed. The other compatible + strings from the above standard binding could also be used, but a device + adhering to this binding may leave out all except for + "usbifVID,PID.configCN.IN". +- reg: the interface number and configuration value + +The configuration component is not included in the textual representation of +an interface-node unit address for configuration 1. + + +Required properties for combined nodes: +- compatible: "usbVID,PID", where VID is the vendor id and PID the product id. + The textual representation of VID and PID shall be in lower case hexadecimal + with leading zeroes suppressed. The other compatible strings from the above + standard binding could also be used, but a device adhering to this binding + may leave out all except for "usbVID,PID". +- reg: the number of the USB hub port or the USB host-controller port to which + this device is attached. The range is 1-255. + + +Required properties for hub nodes with device nodes: +- #address-cells: shall be 1 +- #size-cells: shall be 0 + + +Required properties for host-controller nodes with device nodes: +- #address-cells: shall be 1 +- #size-cells: shall be 0 + + +Example: + +&usb1 { /* host controller */ + #address-cells = <1>; + #size-cells = <0>; + + hub@1 { /* hub connected to port 1 */ + compatible = "usb5e3,608"; + reg = <1>; + }; + + device@2 { /* device connected to port 2 */ + compatible = "usb123,4567"; + reg = <2>; + }; + + device@3 { /* device connected to port 3 */ + compatible = "usb123,abcd"; + reg = <3>; + + #address-cells = <2>; + #size-cells = <0>; + + interface@0 { /* interface 0 of configuration 1 */ + compatible = "usbif123,abcd.config1.0"; + reg = <0 1>; + }; + + interface@0,2 { /* interface 0 of configuration 2 */ + compatible = "usbif123,abcd.config2.0"; + reg = <0 2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-ehci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-ehci.txt new file mode 100644 index 0000000000000000000000000000000000000000..0f1b75386207ffedfb7bfbfc8496c3afd71140c0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-ehci.txt @@ -0,0 +1,42 @@ +USB EHCI controllers + +Required properties: + - compatible : should be "generic-ehci". + - reg : should contain at least address and length of the standard EHCI + register set for the device. Optional platform-dependent registers + (debug-port or other) can be also specified here, but only after + definition of standard EHCI registers. + - interrupts : one EHCI interrupt should be described here. + +Optional properties: + - big-endian-regs : boolean, set this for hcds with big-endian registers + - big-endian-desc : boolean, set this for hcds with big-endian descriptors + - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc + - needs-reset-on-resume : boolean, set this to force EHCI reset after resume + - has-transaction-translator : boolean, set this if EHCI have a Transaction + Translator built into the root hub. + - clocks : a list of phandle + clock specifier pairs + - phys : see usb-hcd.txt in the current directory + - resets : phandle + reset specifier pair + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + +Example (Sequoia 440EPx): + ehci@e0000300 { + compatible = "ibm,usb-ehci-440epx", "usb-ehci"; + interrupt-parent = <&UIC0>; + interrupts = <1a 4>; + reg = <0 e0000300 90 0 e0000390 70>; + big-endian; + }; + +Example (Allwinner sun4i A10 SoC): + ehci0: usb@1c14000 { + compatible = "allwinner,sun4i-a10-ehci", "generic-ehci"; + reg = <0x01c14000 0x100>; + interrupts = <39>; + clocks = <&ahb_gates 1>; + phys = <&usbphy 1>; + phy-names = "usb"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-hcd.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-hcd.txt new file mode 100644 index 0000000000000000000000000000000000000000..50529b838c9c4ee85979ba986131a18b87d5aa21 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-hcd.txt @@ -0,0 +1,9 @@ +Generic USB HCD (Host Controller Device) Properties + +Optional properties: +- phys: a list of all USB PHYs on this HCD + +Example: + &usb1 { + phys = <&usb2_phy1>, <&usb3_phy1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-nop-xceiv.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-nop-xceiv.txt new file mode 100644 index 0000000000000000000000000000000000000000..4dc6a8ee307156ea1f09083900e49536e0a94b6a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-nop-xceiv.txt @@ -0,0 +1,43 @@ +USB NOP PHY + +Required properties: +- compatible: should be usb-nop-xceiv +- #phy-cells: Must be 0 + +Optional properties: +- clocks: phandle to the PHY clock. Use as per Documentation/devicetree + /bindings/clock/clock-bindings.txt + This property is required if clock-frequency is specified. + +- clock-names: Should be "main_clk" + +- clock-frequency: the clock frequency (in Hz) that the PHY clock must + be configured to. + +- vcc-supply: phandle to the regulator that provides power to the PHY. + +- reset-gpios: Should specify the GPIO for reset. + +- vbus-detect-gpio: should specify the GPIO detecting a VBus insertion + (see Documentation/devicetree/bindings/gpio/gpio.txt) +- vbus-regulator : should specifiy the regulator supplying current drawn from + the VBus line (see Documentation/devicetree/bindings/regulator/regulator.txt). + +Example: + + hsusb1_phy { + compatible = "usb-nop-xceiv"; + clock-frequency = <19200000>; + clocks = <&osc 0>; + clock-names = "main_clk"; + vcc-supply = <&hsusb1_vcc_regulator>; + reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>; + vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>; + vbus-regulator = <&vbus_regulator>; + #phy-cells = <0>; + }; + +hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator +and expects that clock to be configured to 19.2MHz by the NOP PHY driver. +hsusb1_vcc_regulator provides power to the PHY and GPIO 7 controls RESET. +GPIO 13 detects VBus insertion, and accordingly notifies the vbus-regulator. diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-ohci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-ohci.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8d2103d1f3df7fb7675012ee6d0eb5617ff2369 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-ohci.txt @@ -0,0 +1,31 @@ +USB OHCI controllers + +Required properties: +- compatible : "generic-ohci" +- reg : ohci controller register range (address and length) +- interrupts : ohci controller interrupt + +Optional properties: +- big-endian-regs : boolean, set this for hcds with big-endian registers +- big-endian-desc : boolean, set this for hcds with big-endian descriptors +- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc +- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA +- remote-wakeup-connected: remote wakeup is wired on the platform +- num-ports : u32, to override the detected port count +- clocks : a list of phandle + clock specifier pairs +- phys : see usb-hcd.txt in the current directory +- resets : a list of phandle + reset specifier pairs + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + +Example: + + ohci0: usb@1c14400 { + compatible = "allwinner,sun4i-a10-ohci", "generic-ohci"; + reg = <0x01c14400 0x100>; + interrupts = <64>; + clocks = <&usb_clk 6>, <&ahb_gates 2>; + phys = <&usbphy 1>; + phy-names = "usb"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-uhci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-uhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..cc2e6f7d602e1f8376233b894538827b4de54632 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-uhci.txt @@ -0,0 +1,18 @@ +Generic Platform UHCI Controller +----------------------------------------------------- + +Required properties: +- compatible : "generic-uhci" (deprecated: "platform-uhci") +- reg : Should contain 1 register ranges(address and length) +- interrupts : UHCI controller interrupt + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + +Example: + + uhci@d8007b00 { + compatible = "generic-uhci"; + reg = <0xd8007b00 0x200>; + interrupts = <43>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb-xhci.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb-xhci.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac4cd0d6195a89f6bf5619f34cd3987c20597aac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb-xhci.txt @@ -0,0 +1,51 @@ +USB xHCI controllers + +Required properties: + - compatible: should be one or more of + + - "generic-xhci" for generic XHCI device + - "marvell,armada3700-xhci" for Armada 37xx SoCs + - "marvell,armada-375-xhci" for Armada 375 SoCs + - "marvell,armada-380-xhci" for Armada 38x SoCs + - "renesas,xhci-r8a7743" for r8a7743 SoC + - "renesas,xhci-r8a7790" for r8a7790 SoC + - "renesas,xhci-r8a7791" for r8a7791 SoC + - "renesas,xhci-r8a7793" for r8a7793 SoC + - "renesas,xhci-r8a7795" for r8a7795 SoC + - "renesas,xhci-r8a7796" for r8a7796 SoC + - "renesas,xhci-r8a77965" for r8a77965 SoC + - "renesas,xhci-r8a77990" for r8a77990 SoC + - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible + device + - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device + - "xhci-platform" (deprecated) + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + + - reg: should contain address and length of the standard XHCI + register set for the device. + - interrupts: one XHCI interrupt should be described here. + +Optional properties: + - clocks: reference to the clocks + - clock-names: mandatory if there is a second clock, in this case + the name must be "core" for the first clock and "reg" for the + second one + - usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM + - usb3-lpm-capable: determines if platform is USB3 LPM capable + - quirk-broken-port-ped: set if the controller has broken port disable mechanism + - imod-interval-ns: default interrupt moderation interval is 5000ns + - phys : see usb-hcd.txt in the current directory + +additionally the properties from usb-hcd.txt (in the current directory) are +supported. + + +Example: + usb@f0931000 { + compatible = "generic-xhci"; + reg = <0xf0931000 0x8c8>; + interrupts = <0x0 0x4e 0x0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb251xb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb251xb.txt new file mode 100644 index 0000000000000000000000000000000000000000..168ff819e8273fc5435552949c67467d69f14e1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb251xb.txt @@ -0,0 +1,84 @@ +Microchip USB 2.0 Hi-Speed Hub Controller + +The device node for the configuration of a Microchip USB251x/xBi USB 2.0 +Hi-Speed Controller. + +Required properties : + - compatible : Should be "microchip,usb251xb" or one of the specific types: + "microchip,usb2512b", "microchip,usb2512bi", "microchip,usb2513b", + "microchip,usb2513bi", "microchip,usb2514b", "microchip,usb2514bi", + "microchip,usb2517", "microchip,usb2517i" + - reg : I2C address on the selected bus (default is <0x2C>) + +Optional properties : + - reset-gpios : Should specify the gpio for hub reset + - skip-config : Skip Hub configuration, but only send the USB-Attach command + - vendor-id : Set USB Vendor ID of the hub (16 bit, default is 0x0424) + - product-id : Set USB Product ID of the hub (16 bit, default depends on type) + - device-id : Set USB Device ID of the hub (16 bit, default is 0x0bb3) + - language-id : Set USB Language ID (16 bit, default is 0x0000) + - manufacturer : Set USB Manufacturer string (max 31 characters long) + - product : Set USB Product string (max 31 characters long) + - serial : Set USB Serial string (max 31 characters long) + - {bus,self}-powered : selects between self- and bus-powered operation + (boolean, default is self-powered) + - disable-hi-speed : disable USB Hi-Speed support (boolean) + - {multi,single}-tt : selects between multi- and single-transaction-translator + (boolean, default is multi-tt) + - disable-eop : disable End of Packet generation in full-speed mode (boolean) + - {ganged,individual}-sensing : select over-current sense type in self-powered + mode (boolean, default is individual) + - {ganged,individual}-port-switching : select port power switching mode + (boolean, default is individual) + - dynamic-power-switching : enable auto-switching from self- to bus-powered + operation if the local power source is removed or unavailable (boolean) + - oc-delay-us : Delay time (in microseconds) for filtering the over-current + sense inputs. Valid values are 100, 4000, 8000 (default) and 16000. If + an invalid value is given, the default is used instead. + - compound-device : indicate the hub is part of a compound device (boolean) + - port-mapping-mode : enable port mapping mode (boolean) + - led-{usb,speed}-mode : led usb/speed indication mode selection + (boolean, default is speed mode) + - string-support : enable string descriptor support (required for manufacturer, + product and serial string configuration) + - non-removable-ports : Should specify the ports which have a non-removable + device connected. + - sp-disabled-ports : Specifies the ports which will be self-power disabled + - bp-disabled-ports : Specifies the ports which will be bus-power disabled + - sp-max-total-current-microamp: Specifies max current consumed by the hub + from VBUS when operating in self-powered hub. It includes the hub + silicon along with all associated circuitry including a permanently + attached peripheral (range: 0 - 100000 uA, default 1000 uA) + - bp-max-total-current-microamp: Specifies max current consumed by the hub + from VBUS when operating in self-powered hub. It includes the hub + silicon along with all associated circuitry including a permanently + attached peripheral (range: 0 - 510000 uA, default 100000 uA) + - sp-max-removable-current-microamp: Specifies max current consumed by the hub + from VBUS when operating in self-powered hub. It includes the hub + silicon along with all associated circuitry excluding a permanently + attached peripheral (range: 0 - 100000 uA, default 1000 uA) + - bp-max-removable-current-microamp: Specifies max current consumed by the hub + from VBUS when operating in self-powered hub. It includes the hub + silicon along with all associated circuitry excluding a permanently + attached peripheral (range: 0 - 510000 uA, default 100000 uA) + - power-on-time-ms : Specifies the time it takes from the time the host + initiates the power-on sequence to a port until the port has adequate + power. The value is given in ms in a 0 - 510 range (default is 100ms). + +Examples: + usb2512b@2c { + compatible = "microchip,usb2512b"; + reg = <0x2c>; + reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + }; + + usb2514b@2c { + compatible = "microchip,usb2514b"; + reg = <0x2c>; + vendor-id = /bits/ 16 <0x0000>; + product-id = /bits/ 16 <0x0000>; + string-support; + manufacturer = "Foo"; + product = "Foo-Bar"; + serial = "1234567890A"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb3503.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb3503.txt new file mode 100644 index 0000000000000000000000000000000000000000..057dd384d4732c76c3412c8a7fbc40b16fbee82a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb3503.txt @@ -0,0 +1,39 @@ +SMSC USB3503 High-Speed Hub Controller + +Required properties: +- compatible: Should be "smsc,usb3503" or "smsc,usb3503a". + +Optional properties: +- reg: Specifies the i2c slave address, it is required and should be 0x08 + if I2C is used. +- connect-gpios: Should specify GPIO for connect. +- disabled-ports: Should specify the ports unused. + '1' or '2' or '3' are available for this property to describe the port + number. 1~3 property values are possible to be described. + Do not describe this property if all ports have to be enabled. +- intn-gpios: Should specify GPIO for interrupt. +- reset-gpios: Should specify GPIO for reset. +- initial-mode: Should specify initial mode. + (1 for HUB mode, 2 for STANDBY mode) +- refclk: Clock used for driving REFCLK signal (optional, if not provided + the driver assumes that clock signal is always available, its + rate is specified by REF_SEL pins and a value from the primary + reference clock frequencies table is used). Use clocks and + clock-names in order to assign it +- refclk-frequency: Frequency of the REFCLK signal as defined by REF_SEL + pins (optional, if not provided, driver will not set rate of the + REFCLK signal and assume that a value from the primary reference + clock frequencies table is used) + +Examples: + usb3503@8 { + compatible = "smsc,usb3503"; + reg = <0x08>; + connect-gpios = <&gpx3 0 1>; + disabled-ports = <2 3>; + intn-gpios = <&gpx3 4 1>; + reset-gpios = <&gpx3 5 1>; + initial-mode = <1>; + clocks = <&clks 80>; + clock-names = "refclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usb4604.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usb4604.txt new file mode 100644 index 0000000000000000000000000000000000000000..82506d17712c509c7539177bcbf91af057fb9ea5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usb4604.txt @@ -0,0 +1,19 @@ +SMSC USB4604 High-Speed Hub Controller + +Required properties: +- compatible: Should be "smsc,usb4604" + +Optional properties: +- reg: Specifies the i2c slave address, it is required and should be 0x2d + if I2C is used. +- reset-gpios: Should specify GPIO for reset. +- initial-mode: Should specify initial mode. + (1 for HUB mode, 2 for STANDBY mode) + +Examples: + usb-hub@2d { + compatible = "smsc,usb4604"; + reg = <0x2d>; + reset-gpios = <&gpx3 5 1>; + initial-mode = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/usbmisc-imx.txt b/arch/arm64/boot/dts/vendor/bindings/usb/usbmisc-imx.txt new file mode 100644 index 0000000000000000000000000000000000000000..a85a631ec434c6f1a6cf47c7e68d608e24734319 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/usbmisc-imx.txt @@ -0,0 +1,17 @@ +* Freescale i.MX non-core registers + +Required properties: +- #index-cells: Cells used to descibe usb controller index. Should be <1> +- compatible: Should be one of below: + "fsl,imx6q-usbmisc" for imx6q + "fsl,vf610-usbmisc" for Vybrid vf610 + "fsl,imx6sx-usbmisc" for imx6sx + "fsl,imx7d-usbmisc" for imx7d +- reg: Should contain registers location and length + +Examples: +usbmisc@2184800 { + #index-cells = <1>; + compatible = "fsl,imx6q-usbmisc"; + reg = <0x02184800 0x200>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/usb/ux500-usb.txt b/arch/arm64/boot/dts/vendor/bindings/usb/ux500-usb.txt new file mode 100644 index 0000000000000000000000000000000000000000..439a41c79afacd680a6c8309935ab37573cd6326 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/usb/ux500-usb.txt @@ -0,0 +1,50 @@ +Ux500 MUSB + +Required properties: + - compatible : Should be "stericsson,db8500-musb" + - reg : Offset and length of registers + - interrupts : Interrupt; mode, number and trigger + - dr_mode : Dual-role; either host mode "host", peripheral mode "peripheral" + or both "otg" + +Optional properties: + - dmas : A list of dma channels; + dma-controller, event-line, fixed-channel, flags + - dma-names : An ordered list of channel names affiliated to the above + +Example: + +usb_per5@a03e0000 { + compatible = "stericsson,db8500-musb"; + reg = <0xa03e0000 0x10000>; + interrupts = <0 23 0x4>; + interrupt-names = "mc"; + + dr_mode = "otg"; + + dmas = <&dma 38 0 0x2>, /* Logical - DevToMem */ + <&dma 38 0 0x0>, /* Logical - MemToDev */ + <&dma 37 0 0x2>, /* Logical - DevToMem */ + <&dma 37 0 0x0>, /* Logical - MemToDev */ + <&dma 36 0 0x2>, /* Logical - DevToMem */ + <&dma 36 0 0x0>, /* Logical - MemToDev */ + <&dma 19 0 0x2>, /* Logical - DevToMem */ + <&dma 19 0 0x0>, /* Logical - MemToDev */ + <&dma 18 0 0x2>, /* Logical - DevToMem */ + <&dma 18 0 0x0>, /* Logical - MemToDev */ + <&dma 17 0 0x2>, /* Logical - DevToMem */ + <&dma 17 0 0x0>, /* Logical - MemToDev */ + <&dma 16 0 0x2>, /* Logical - DevToMem */ + <&dma 16 0 0x0>, /* Logical - MemToDev */ + <&dma 39 0 0x2>, /* Logical - DevToMem */ + <&dma 39 0 0x0>; /* Logical - MemToDev */ + + dma-names = "iep_1_9", "oep_1_9", + "iep_2_10", "oep_2_10", + "iep_3_11", "oep_3_11", + "iep_4_12", "oep_4_12", + "iep_5_13", "oep_5_13", + "iep_6_14", "oep_6_14", + "iep_7_15", "oep_7_15", + "iep_8", "oep_8"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/vendor-prefixes.txt b/arch/arm64/boot/dts/vendor/bindings/vendor-prefixes.txt new file mode 100644 index 0000000000000000000000000000000000000000..3251c45846e0b379e97c44660575d8fdcb926e07 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/vendor-prefixes.txt @@ -0,0 +1,443 @@ +Device tree binding vendor prefix registry. Keep list in alphabetical order. + +This isn't an exhaustive list, but you should add new prefixes to it before +using them to avoid name-space collisions. + +abilis Abilis Systems +abracon Abracon Corporation +actions Actions Semiconductor Co., Ltd. +active-semi Active-Semi International Inc +ad Avionic Design GmbH +adafruit Adafruit Industries, LLC +adapteva Adapteva, Inc. +adaptrum Adaptrum, Inc. +adh AD Holdings Plc. +adi Analog Devices, Inc. +advantech Advantech Corporation +aeroflexgaisler Aeroflex Gaisler AB +al Annapurna Labs +allo Allo.com +allwinner Allwinner Technology Co., Ltd. +alphascale AlphaScale Integrated Circuits Systems, Inc. +altr Altera Corp. +amarula Amarula Solutions +amazon Amazon.com, Inc. +amcc Applied Micro Circuits Corporation (APM, formally AMCC) +amd Advanced Micro Devices (AMD), Inc. +amlogic Amlogic, Inc. +ampire Ampire Co., Ltd. +ams AMS AG +amstaos AMS-Taos Inc. +android Google Inc. +analogix Analogix Semiconductor, Inc. +andestech Andes Technology Corporation +apm Applied Micro Circuits Corporation (APM) +aptina Aptina Imaging +arasan Arasan Chip Systems +archermind ArcherMind Technology (Nanjing) Co., Ltd. +arctic Arctic Sand +aries Aries Embedded GmbH +arm ARM Ltd. +armadeus ARMadeus Systems SARL +arrow Arrow Electronics +artesyn Artesyn Embedded Technologies Inc. +asahi-kasei Asahi Kasei Corp. +aspeed ASPEED Technology Inc. +asus AsusTek Computer Inc. +atlas Atlas Scientific LLC +atmel Atmel Corporation +auo AU Optronics Corporation +auvidea Auvidea GmbH +avago Avago Technologies +avia avia semiconductor +avic Shanghai AVIC Optoelectronics Co., Ltd. +avnet Avnet, Inc. +axentia Axentia Technologies AB +axis Axis Communications AB +bananapi BIPAI KEJI LIMITED +bhf Beckhoff Automation GmbH & Co. KG +bitmain Bitmain Technologies +boe BOE Technology Group Co., Ltd. +bosch Bosch Sensortec GmbH +boundary Boundary Devices Inc. +brcm Broadcom Corporation +buffalo Buffalo, Inc. +bticino Bticino International +calxeda Calxeda +capella Capella Microsystems, Inc +cascoda Cascoda, Ltd. +cavium Cavium, Inc. +cdns Cadence Design Systems Inc. +ceva Ceva, Inc. +chipidea Chipidea, Inc +chipone ChipOne +chipspark ChipSPARK +chrp Common Hardware Reference Platform +chunghwa Chunghwa Picture Tubes Ltd. +ciaa Computadora Industrial Abierta Argentina +cirrus Cirrus Logic, Inc. +cloudengines Cloud Engines, Inc. +cnm Chips&Media, Inc. +cnxt Conexant Systems, Inc. +compulab CompuLab Ltd. +cortina Cortina Systems, Inc. +cosmic Cosmic Circuits +crane Crane Connectivity Solutions +creative Creative Technology Ltd +crystalfontz Crystalfontz America, Inc. +cubietech Cubietech, Ltd. +cypress Cypress Semiconductor Corporation +cznic CZ.NIC, z.s.p.o. +dallas Maxim Integrated Products (formerly Dallas Semiconductor) +dataimage DataImage, Inc. +davicom DAVICOM Semiconductor, Inc. +delta Delta Electronics, Inc. +denx Denx Software Engineering +devantech Devantech, Ltd. +dh DH electronics GmbH +digi Digi International Inc. +digilent Diglent, Inc. +dioo Dioo Microcircuit Co., Ltd +dlc DLC Display Co., Ltd. +dlg Dialog Semiconductor +dlink D-Link Corporation +dmo Data Modul AG +domintech Domintech Co., Ltd. +dongwoon Dongwoon Anatech +dptechnics DPTechnics +dragino Dragino Technology Co., Limited +ea Embedded Artists AB +ebv EBV Elektronik +eckelmann Eckelmann AG +edt Emerging Display Technologies +eeti eGalax_eMPIA Technology Inc +elan Elan Microelectronic Corp. +embest Shenzhen Embest Technology Co., Ltd. +emmicro EM Microelectronic +emtrion emtrion GmbH +energymicro Silicon Laboratories (formerly Energy Micro AS) +engicam Engicam S.r.l. +epcos EPCOS AG +epfl Ecole Polytechnique Fédérale de Lausanne +epson Seiko Epson Corp. +est ESTeem Wireless Modems +ettus NI Ettus Research +eukrea Eukréa Electromatique +everest Everest Semiconductor Co. Ltd. +everspin Everspin Technologies, Inc. +exar Exar Corporation +excito Excito +ezchip EZchip Semiconductor +fairphone Fairphone B.V. +faraday Faraday Technology Corporation +fastrax Fastrax Oy +fcs Fairchild Semiconductor +firefly Firefly +focaltech FocalTech Systems Co.,Ltd +fpc Fingerprint Cards AB. +friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd +fsl Freescale Semiconductor +fujitsu Fujitsu Ltd. +gcw Game Consoles Worldwide +ge General Electric Company +geekbuying GeekBuying +gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. +GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. +geniatech Geniatech, Inc. +giantec Giantec Semiconductor, Inc. +giantplus Giantplus Technology Co., Ltd. +globalscale Globalscale Technologies, Inc. +gmt Global Mixed-mode Technology, Inc. +goodix Shenzhen Huiding Technology Co., Ltd. +google Google, Inc. +grinn Grinn +grmn Garmin Limited +gumstix Gumstix, Inc. +gw Gateworks Corporation +hannstar HannStar Display Corporation +halo Halo Microelectronics Co. Ltd. +haoyu Haoyu Microelectronic Co. Ltd. +hardkernel Hardkernel Co., Ltd +hideep HiDeep Inc. +himax Himax Technologies, Inc. +hisilicon Hisilicon Limited. +hit Hitachi Ltd. +hitex Hitex Development Tools +holt Holt Integrated Circuits, Inc. +honeywell Honeywell +hp Hewlett Packard +holtek Holtek Semiconductor, Inc. +hwacom HwaCom Systems Inc. +i2se I2SE GmbH +ibm International Business Machines (IBM) +idt Integrated Device Technologies, Inc. +ifi Ingenieurburo Fur Ic-Technologie (I/F/I) +ilitek ILI Technology Corporation (ILITEK) +img Imagination Technologies Ltd. +infineon Infineon Technologies +inforce Inforce Computing +ingenic Ingenic Semiconductor +innolux Innolux Corporation +inside-secure INSIDE Secure +intel Intel Corporation +intercontrol Inter Control Group +invensense InvenSense Inc. +inversepath Inverse Path +iom Iomega Corporation +isee ISEE 2007 S.L. +isil Intersil +issi Integrated Silicon Solutions Inc. +itead ITEAD Intelligent Systems Co.Ltd +iwave iWave Systems Technologies Pvt. Ltd. +jdi Japan Display Inc. +jedec JEDEC Solid State Technology Association +jianda Jiandangjing Technology Co., Ltd. +karo Ka-Ro electronics GmbH +keithkoep Keith & Koep GmbH +keymile Keymile GmbH +khadas Khadas +kiebackpeter Kieback & Peter GmbH +kinetic Kinetic Technologies +kingdisplay King & Display Technology Co., Ltd. +kingnovel Kingnovel Technology Co., Ltd. +koe Kaohsiung Opto-Electronics Inc. +kosagi Sutajio Ko-Usagi PTE Ltd. +kyo Kyocera Corporation +lacie LaCie +laird Laird PLC +lantiq Lantiq Semiconductor +lattice Lattice Semiconductor +lego LEGO Systems A/S +lenovo Lenovo Group Ltd. +lg LG Corporation +libretech Shenzhen Libre Technology Co., Ltd +licheepi Lichee Pi +linaro Linaro Limited +linksys Belkin International, Inc. (Linksys) +linux Linux-specific binding +linx Linx Technologies +lltc Linear Technology Corporation +logicpd Logic PD, Inc. +lsi LSI Corp. (LSI Logic) +lwn Liebherr-Werk Nenzing GmbH +lt Lontium Semiconductor Corporation +macnica Macnica Americas +marvell Marvell Technology Group Ltd. +maxim Maxim Integrated Products +mbvl Mobiveil Inc. +mcube mCube +meas Measurement Specialties +mediatek MediaTek Inc. +megachips MegaChips +mele Shenzhen MeLE Digital Technology Ltd. +melexis Melexis N.V. +melfas MELFAS Inc. +mellanox Mellanox Technologies +memsic MEMSIC Inc. +merrii Merrii Technology Co., Ltd. +micrel Micrel Inc. +microchip Microchip Technology Inc. +microcrystal Micro Crystal AG +micron Micron Technology Inc. +minix MINIX Technology Ltd. +miramems MiraMEMS Sensing Technology Co., Ltd. +mitsubishi Mitsubishi Electric Corporation +mosaixtech Mosaix Technologies, Inc. +motorola Motorola, Inc. +moxa Moxa Inc. +mpl MPL AG +mqmaker mqmaker Inc. +mscc Microsemi Corporation +msi Micro-Star International Co. Ltd. +mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.) +multi-inno Multi-Inno Technology Co.,Ltd +mundoreader Mundo Reader S.L. +murata Murata Manufacturing Co., Ltd. +mxicy Macronix International Co., Ltd. +myir MYIR Tech Limited +national National Semiconductor +nec NEC LCD Technologies, Ltd. +neonode Neonode Inc. +netgear NETGEAR +netlogic Broadcom Corporation (formerly NetLogic Microsystems) +netron-dy Netron DY +netxeon Shenzhen Netxeon Technology CO., LTD +nexbox Nexbox +nextthing Next Thing Co. +newhaven Newhaven Display International +ni National Instruments +nintendo Nintendo +nlt NLT Technologies, Ltd. +nokia Nokia +nordic Nordic Semiconductor +novatek Novatek Microelectronics Corporation +nutsboard NutsBoard +nuvoton Nuvoton Technology Corporation +nvd New Vision Display +nvidia NVIDIA +nxp NXP Semiconductors +okaya Okaya Electric America, Inc. +oki Oki Electric Industry Co., Ltd. +olimex OLIMEX Ltd. +onion Onion Corporation +onnn ON Semiconductor Corp. +ontat On Tat Industrial Company +opalkelly Opal Kelly Incorporated +opencores OpenCores.org +openrisc OpenRISC.io +option Option NV +oranth Shenzhen Oranth Technology Co., Ltd. +ORCL Oracle Corporation +orisetech Orise Technology +ortustech Ortus Technology Co., Ltd. +ovti OmniVision Technologies +oxsemi Oxford Semiconductor, Ltd. +panasonic Panasonic Corporation +parade Parade Technologies Inc. +pericom Pericom Technology Inc. +pervasive Pervasive Displays, Inc. +phytec PHYTEC Messtechnik GmbH +picochip Picochip Ltd +pine64 Pine64 +pixcir PIXCIR MICROELECTRONICS Co., Ltd +plathome Plat'Home Co., Ltd. +plda PLDA +portwell Portwell Inc. +poslab Poslab Technology Co., Ltd. +powervr PowerVR (deprecated, use img) +probox2 PROBOX2 (by W2COMP Co., Ltd.) +pulsedlight PulsedLight, Inc +qca Qualcomm Atheros, Inc. +qcom Qualcomm Technologies, Inc +qemu QEMU, a generic and open source machine emulator and virtualizer +qi Qi Hardware +qiaodian QiaoDian XianShi Corporation +qnap QNAP Systems, Inc. +radxa Radxa +raidsonic RaidSonic Technology GmbH +ralink Mediatek/Ralink Technology Corp. +ramtron Ramtron International +raspberrypi Raspberry Pi Foundation +raydium Raydium Semiconductor Corp. +realtek Realtek Semiconductor Corp. +renesas Renesas Electronics Corporation +richtek Richtek Technology Corporation +ricoh Ricoh Co. Ltd. +rikomagic Rikomagic Tech Corp. Ltd +riscv RISC-V Foundation +rockchip Fuzhou Rockchip Electronics Co., Ltd +rohm ROHM Semiconductor Co., Ltd +roofull Shenzhen Roofull Technology Co, Ltd +samsung Samsung Semiconductor +samtec Samtec/Softing company +sancloud Sancloud Ltd +sandisk Sandisk Corporation +sbs Smart Battery System +schindler Schindler +seagate Seagate Technology PLC +semtech Semtech Corporation +sensirion Sensirion AG +sff Small Form Factor Committee +sgd Solomon Goldentek Display Corporation +sgx SGX Sensortech +sharp Sharp Corporation +shimafuji Shimafuji Electric, Inc. +si-en Si-En Technology Ltd. +sifive SiFive, Inc. +sigma Sigma Designs, Inc. +sii Seiko Instruments, Inc. +sil Silicon Image +silabs Silicon Laboratories +silead Silead Inc. +silergy Silergy Corp. +siliconmitus Silicon Mitus, Inc. +simtek +sirf SiRF Technology, Inc. +sis Silicon Integrated Systems Corp. +sitronix Sitronix Technology Corporation +skyworks Skyworks Solutions, Inc. +smsc Standard Microsystems Corporation +snps Synopsys, Inc. +socionext Socionext Inc. +solidrun SolidRun +solomon Solomon Systech Limited +sony Sony Corporation +spansion Spansion Inc. +sprd Spreadtrum Communications Inc. +sst Silicon Storage Technology, Inc. +st STMicroelectronics +starry Starry Electronic Technology (ShenZhen) Co., LTD +startek Startek +ste ST-Ericsson +stericsson ST-Ericsson +summit Summit microelectronics +sunchip Shenzhen Sunchip Technology Co., Ltd +SUNW Sun Microsystems, Inc +swir Sierra Wireless +synaptics Synaptics Inc. +synology Synology, Inc. +tbs TBS Technologies +tbs-biometrics Touchless Biometric Systems AG +tcg Trusted Computing Group +tcl Toby Churchill Ltd. +technexion TechNexion +technologic Technologic Systems +tempo Tempo Semiconductor +terasic Terasic Inc. +thine THine Electronics, Inc. +ti Texas Instruments +tianma Tianma Micro-electronics Co., Ltd. +tlm Trusted Logic Mobility +tmt Tecon Microprocessor Technologies, LLC. +topeet Topeet +toradex Toradex AG +toshiba Toshiba Corporation +toumaz Toumaz +tpk TPK U.S.A. LLC +tplink TP-LINK Technologies Co., Ltd. +tpo TPO +tronfy Tronfy +tronsmart Tronsmart +truly Truly Semiconductors Limited +tsd Theobroma Systems Design und Consulting GmbH +tyan Tyan Computer Corporation +u-blox u-blox +ucrobotics uCRobotics +ubnt Ubiquiti Networks +udoo Udoo +uniwest United Western Technologies Corp (UniWest) +upisemi uPI Semiconductor Corp. +urt United Radiant Technology Corporation +usi Universal Scientific Industrial Co., Ltd. +v3 V3 Semiconductor +vamrs Vamrs Ltd. +variscite Variscite Ltd. +via VIA Technologies, Inc. +virtio Virtual I/O Device Specification, developed by the OASIS consortium +vitesse Vitesse Semiconductor Corporation +vivante Vivante Corporation +vocore VoCore Studio +voipac Voipac Technologies s.r.o. +vot Vision Optical Technology Co., Ltd. +wd Western Digital Corp. +wetek WeTek Electronics, limited. +wexler Wexler +wi2wi Wi2Wi, Inc. +winbond Winbond Electronics corp. +winstar Winstar Display Corp. +wlf Wolfson Microelectronics +wm Wondermedia Technologies, Inc. +x-powers X-Powers +xes Extreme Engineering Solutions (X-ES) +xillybus Xillybus Ltd. +xlnx Xilinx +xunlong Shenzhen Xunlong Software CO.,Limited +ysoft Y Soft Corporation a.s. +zarlink Zarlink Semiconductor +zeitec ZEITEC Semiconductor Co., LTD. +zidoo Shenzhen Zidoo Technology Co., Ltd. +zii Zodiac Inflight Innovations +zte ZTE Corp. +zyxel ZyXEL Communications Corp. +oem,oem_serial_pinctrl oem oem_serial_pinctrl +qcom,msm-geni-console-oem qcom msm-geni-console-oem diff --git a/arch/arm64/boot/dts/vendor/bindings/virtio/mmio.txt b/arch/arm64/boot/dts/vendor/bindings/virtio/mmio.txt new file mode 100644 index 0000000000000000000000000000000000000000..5069c1b8e1931ae2071083714c53e15bedd9e005 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/virtio/mmio.txt @@ -0,0 +1,17 @@ +* virtio memory mapped device + +See http://ozlabs.org/~rusty/virtio-spec/ for more details. + +Required properties: + +- compatible: "virtio,mmio" compatibility string +- reg: control registers base address and size including configuration space +- interrupts: interrupt generated by the device + +Example: + + virtio_block@3000 { + compatible = "virtio,mmio"; + reg = <0x3000 0x100>; + interrupts = <41>; + } diff --git a/arch/arm64/boot/dts/vendor/bindings/w1/fsl-imx-owire.txt b/arch/arm64/boot/dts/vendor/bindings/w1/fsl-imx-owire.txt new file mode 100644 index 0000000000000000000000000000000000000000..cbaa6467ab2cc3f0892d0958cc87fb25739837da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/w1/fsl-imx-owire.txt @@ -0,0 +1,18 @@ +* Freescale i.MX One wire bus master controller + +Required properties: +- compatible : should be "fsl,imx21-owire" +- reg : Address and length of the register set for the device + +Optional properties: +- clocks : phandle of clock that supplies the module (required if platform + clock bindings use device tree) + +Example: + +- From imx53.dtsi: +owire: owire@63fa4000 { + compatible = "fsl,imx53-owire", "fsl,imx21-owire"; + reg = <0x63fa4000 0x4000>; + clocks = <&clks 159>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/w1/omap-hdq.txt b/arch/arm64/boot/dts/vendor/bindings/w1/omap-hdq.txt new file mode 100644 index 0000000000000000000000000000000000000000..913c5f91a0f9f85e7d100f2acda6f9dc210b773f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/w1/omap-hdq.txt @@ -0,0 +1,22 @@ +* OMAP HDQ One wire bus master controller + +Required properties: +- compatible : should be "ti,omap3-1w" or "ti,am4372-hdq" +- reg : Address and length of the register set for the device +- interrupts : interrupt line. +- ti,hwmods : "hdq1w" + +Optional properties: +- ti,mode: should be "hdq": HDQ mode "1w": one-wire mode. + If not specified HDQ mode is implied. + +Example: + +- From omap3.dtsi + hdqw1w: 1w@480b2000 { + compatible = "ti,omap3-1w"; + reg = <0x480b2000 0x1000>; + interrupts = <58>; + ti,hwmods = "hdq1w"; + ti,mode = "hdq"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/w1/w1-gpio.txt b/arch/arm64/boot/dts/vendor/bindings/w1/w1-gpio.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d6554eac240ce174e3d2073fa290a6b15bfd0fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/w1/w1-gpio.txt @@ -0,0 +1,27 @@ +w1-gpio devicetree bindings + +Required properties: + + - compatible: "w1-gpio" + - gpios: one or two GPIO specs: + - the first one is used as data I/O pin + - the second one is optional. If specified, it is used as + enable pin for an external pin pullup. + +Optional properties: + + - linux,open-drain: if specified, the data pin is considered in + open-drain mode. + +Also refer to the generic w1.txt document. + +Examples: + + onewire { + compatible = "w1-gpio"; + gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; + + battery { + // ... + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/w1/w1.txt b/arch/arm64/boot/dts/vendor/bindings/w1/w1.txt new file mode 100644 index 0000000000000000000000000000000000000000..05f26b27d898867823632b4a6cdde50b4b6fce8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/w1/w1.txt @@ -0,0 +1,25 @@ +Generic devicetree bindings for onewire (w1) busses +=================================================== + +Onewire busses are described through nodes of their master bus controller. +Slave devices are listed as sub-nodes of such master devices. For now, only +one slave is allowed per bus master. + + +Example: + + charger: charger { + compatible = "gpio-charger"; + charger-type = "mains"; + gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + }; + + onewire { + compatible = "w1-gpio"; + gpios = <&gpio 100 0>, <&gpio 101 0>; + + battery { + compatible = "maxim,ds2760"; + power-supplies = <&charger>; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/alphascale-asm9260.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/alphascale-asm9260.txt new file mode 100644 index 0000000000000000000000000000000000000000..75b265a04047a1646904f589c6da0514a585c804 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/alphascale-asm9260.txt @@ -0,0 +1,35 @@ +Alphascale asm9260 Watchdog timer + +Required properties: + +- compatible : should be "alphascale,asm9260-wdt". +- reg : Specifies base physical address and size of the registers. +- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt +- clock-names : should be set to + "mod" - source for tick counter. + "ahb" - ahb gate. +- resets : phandle pointing to the system reset controller with + line index for the watchdog. +- reset-names : should be set to "wdt_rst". + +Optional properties: +- timeout-sec : shall contain the default watchdog timeout in seconds, + if unset, the default timeout is 30 seconds. +- alphascale,mode : three modes are supported + "hw" - hw reset (default). + "sw" - sw reset. + "debug" - no action is taken. + +Example: + +watchdog0: watchdog@80048000 { + compatible = "alphascale,asm9260-wdt"; + reg = <0x80048000 0x10>; + clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>; + clock-names = "mod", "ahb"; + interrupts = <55>; + resets = <&rst WDT_RESET>; + reset-names = "wdt_rst"; + timeout-sec = <30>; + alphascale,mode = "hw"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/arm,sp805.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/arm,sp805.txt new file mode 100644 index 0000000000000000000000000000000000000000..bee6f1f0e41b5ad23285bda5e475f02c39653161 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/arm,sp805.txt @@ -0,0 +1,32 @@ +ARM AMBA Primecell SP805 Watchdog + +SP805 WDT is a ARM Primecell Peripheral and has a standard-id register that +can be used to identify the peripheral type, vendor, and revision. +This value can be used for driver matching. + +As SP805 WDT is a primecell IP, it follows the base bindings specified in +'arm/primecell.txt' + +Required properties: +- compatible: Should be "arm,sp805" & "arm,primecell" +- reg: Should contain location and length for watchdog timer register +- clocks: Clocks driving the watchdog timer hardware. This list should be + 2 clocks. With 2 clocks, the order is wdog_clk, apb_pclk + wdog_clk can be equal to or be a sub-multiple of the apb_pclk + frequency +- clock-names: Shall be "wdog_clk" for first clock and "apb_pclk" for the + second one + +Optional properties: +- interrupts: Should specify WDT interrupt number +- timeout-sec: Should specify default WDT timeout in seconds. If unset, the + default timeout is determined by the driver + +Example: + watchdog@66090000 { + compatible = "arm,sp805", "arm,primecell"; + reg = <0x66090000 0x1000>; + interrupts = ; + clocks = <&wdt_clk>, <&apb_pclk>; + clock-names = "wdog_clk", "apb_pclk"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/aspeed-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/aspeed-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..c5077a1f5cb3e4753fbf74bb3c905e8e8fce2c81 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/aspeed-wdt.txt @@ -0,0 +1,56 @@ +Aspeed Watchdog Timer + +Required properties: + - compatible: must be one of: + - "aspeed,ast2400-wdt" + - "aspeed,ast2500-wdt" + + - reg: physical base address of the controller and length of memory mapped + region + +Optional properties: + + - aspeed,reset-type = "cpu|soc|system|none" + + Reset behavior - Whenever a timeout occurs the watchdog can be programmed + to generate one of three different, mutually exclusive, types of resets. + + Type "none" can be specified to indicate that no resets are to be done. + This is useful in situations where another watchdog engine on chip is + to perform the reset. + + If 'aspeed,reset-type=' is not specfied the default is to enable system + reset. + + Reset types: + + - cpu: Reset CPU on watchdog timeout + + - soc: Reset 'System on Chip' on watchdog timeout + + - system: Reset system on watchdog timeout + + - none: No reset is performed on timeout. Assumes another watchdog + engine is responsible for this. + + - aspeed,alt-boot: If property is present then boot from alternate block. + - aspeed,external-signal: If property is present then signal is sent to + external reset counter (only WDT1 and WDT2). If not + specified no external signal is sent. + - aspeed,ext-pulse-duration: External signal pulse duration in microseconds + +Optional properties for AST2500-compatible watchdogs: + - aspeed,ext-push-pull: If aspeed,external-signal is present, set the pin's + drive type to push-pull. The default is open-drain. + - aspeed,ext-active-high: If aspeed,external-signal is present and and the pin + is configured as push-pull, then set the pulse + polarity to active-high. The default is active-low. + +Example: + + wdt1: watchdog@1e785000 { + compatible = "aspeed,ast2400-wdt"; + reg = <0x1e785000 0x1c>; + aspeed,reset-type = "system"; + aspeed,external-signal; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-at91rm9200-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-at91rm9200-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..d4d86cf8f9ebbb2872c739fa93f46190ca99e9f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-at91rm9200-wdt.txt @@ -0,0 +1,9 @@ +Atmel AT91RM9200 System Timer Watchdog + +Required properties: +- compatible: must be "atmel,at91sam9260-wdt". + +Example: + watchdog@fffffd00 { + compatible = "atmel,at91rm9200-wdt"; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-sama5d4-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-sama5d4-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..4fec1e3725b44c1d3e9731a9040e884abe1df5c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-sama5d4-wdt.txt @@ -0,0 +1,34 @@ +* Atmel SAMA5D4 Watchdog Timer (WDT) Controller + +Required properties: +- compatible: "atmel,sama5d4-wdt" +- reg: base physical address and length of memory mapped region. + +Optional properties: +- timeout-sec: watchdog timeout value (in seconds). +- interrupts: interrupt number to the CPU. +- atmel,watchdog-type: should be "hardware" or "software". + "hardware": enable watchdog fault reset. A watchdog fault triggers + watchdog reset. + "software": enable watchdog fault interrupt. A watchdog fault asserts + watchdog interrupt. +- atmel,idle-halt: present if you want to stop the watchdog when the CPU is + in idle state. + CAUTION: This property should be used with care, it actually makes the + watchdog not counting when the CPU is in idle state, therefore the + watchdog reset time depends on mean CPU usage and will not reset at all + if the CPU stop working while it is in idle state, which is probably + not what you want. +- atmel,dbg-halt: present if you want to stop the watchdog when the CPU is + in debug state. + +Example: + watchdog@fc068640 { + compatible = "atmel,sama5d4-wdt"; + reg = <0xfc068640 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; + timeout-sec = <10>; + atmel,watchdog-type = "hardware"; + atmel,dbg-halt; + atmel,idle-halt; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..711a880b3d3bf46ed5b5e67dc98ceed3f10d80b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/atmel-wdt.txt @@ -0,0 +1,51 @@ +* Atmel Watchdog Timers + +** at91sam9-wdt + +Required properties: +- compatible: must be "atmel,at91sam9260-wdt". +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: phandle to input clock. + +Optional properties: +- timeout-sec: contains the watchdog timeout in seconds. +- interrupts : Should contain WDT interrupt. +- atmel,max-heartbeat-sec : Should contain the maximum heartbeat value in + seconds. This value should be less or equal to 16. It is used to + compute the WDV field. +- atmel,min-heartbeat-sec : Should contain the minimum heartbeat value in + seconds. This value must be smaller than the max-heartbeat-sec value. + It is used to compute the WDD field. +- atmel,watchdog-type : Should be "hardware" or "software". Hardware watchdog + use the at91 watchdog reset. Software watchdog use the watchdog + interrupt to trigger a software reset. +- atmel,reset-type : Should be "proc" or "all". + "all" : assert peripherals and processor reset signals + "proc" : assert the processor reset signal + This is valid only when using "hardware" watchdog. +- atmel,disable : Should be present if you want to disable the watchdog. +- atmel,idle-halt : Should be present if you want to stop the watchdog when + entering idle state. + CAUTION: This property should be used with care, it actually makes the + watchdog not counting when the CPU is in idle state, therefore the + watchdog reset time depends on mean CPU usage and will not reset at all + if the CPU stop working while it is in idle state, which is probably + not what you want. +- atmel,dbg-halt : Should be present if you want to stop the watchdog when + entering debug state. + +Example: + watchdog@fffffd40 { + compatible = "atmel,at91sam9260-wdt"; + reg = <0xfffffd40 0x10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; + timeout-sec = <15>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; + atmel,max-heartbeat-sec = <16>; + atmel,min-heartbeat-sec = <0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,bcm2835-pm-wdog.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,bcm2835-pm-wdog.txt new file mode 100644 index 0000000000000000000000000000000000000000..f801d71de1cd42565e44831f25aa04c0d06ca726 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,bcm2835-pm-wdog.txt @@ -0,0 +1,18 @@ +BCM2835 Watchdog timer + +Required properties: + +- compatible : should be "brcm,bcm2835-pm-wdt" +- reg : Specifies base physical address and size of the registers. + +Optional properties: + +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + +watchdog { + compatible = "brcm,bcm2835-pm-wdt"; + reg = <0x7e100000 0x28>; + timeout-sec = <10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,bcm7038-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,bcm7038-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..84122270be8f4b6ea361852f201a80560fedc666 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,bcm7038-wdt.txt @@ -0,0 +1,19 @@ +BCM7038 Watchdog timer + +Required properties: + +- compatible : should be "brcm,bcm7038-wdt" +- reg : Specifies base physical address and size of the registers. + +Optional properties: + +- clocks: The clock running the watchdog. If no clock is found the + driver will default to 27000000 Hz. + +Example: + +watchdog@f040a7e8 { + compatible = "brcm,bcm7038-wdt"; + clocks = <&upg_fixed>; + reg = <0xf040a7e8 0x16>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,kona-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,kona-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b86a00e351d3725c021fd9754deaa393cf99ba6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/brcm,kona-wdt.txt @@ -0,0 +1,15 @@ +Broadcom Kona Family Watchdog Timer +----------------------------------- + +This watchdog timer is used in the following Broadcom SoCs: + BCM11130, BCM11140, BCM11351, BCM28145, BCM28155 + +Required properties: + - compatible = "brcm,bcm11351-wdt", "brcm,kona-wdt"; + - reg: memory address & range + +Example: + watchdog@35002f40 { + compatible = "brcm,bcm11351-wdt", "brcm,kona-wdt"; + reg = <0x35002f40 0x6c>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/cadence-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/cadence-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..750a87657448d67e80d6f04d03333edffdff1f03 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/cadence-wdt.txt @@ -0,0 +1,23 @@ +Zynq Watchdog Device Tree Bindings +------------------------------------------- + +Required properties: +- compatible : Should be "cdns,wdt-r1p2". +- clocks : This is pclk (APB clock). +- interrupts : This is wd_irq - watchdog timeout interrupt. + +Optional properties +- reset-on-timeout : If this property exists, then a reset is done + when watchdog times out. +- timeout-sec : Watchdog timeout value (in seconds). + +Example: + watchdog@f8005000 { + compatible = "cdns,wdt-r1p2"; + clocks = <&clkc 45>; + interrupt-parent = <&intc>; + interrupts = <0 9 1>; + reg = <0xf8005000 0x1000>; + reset-on-timeout; + timeout-sec = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/da9062-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/da9062-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..b935b526d2f37880da3bde38f0ae1cf996cee28d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/da9062-wdt.txt @@ -0,0 +1,23 @@ +* Dialog Semiconductor DA9062/61 Watchdog Timer + +Required properties: + +- compatible: should be one of the following valid compatible string lines: + "dlg,da9061-watchdog", "dlg,da9062-watchdog" + "dlg,da9062-watchdog" + +Example: DA9062 + + pmic0: da9062@58 { + watchdog { + compatible = "dlg,da9062-watchdog"; + }; + }; + +Example: DA9061 using a fall-back compatible for the DA9062 watchdog driver + + pmic0: da9061@58 { + watchdog { + compatible = "dlg,da9061-watchdog", "dlg,da9062-watchdog"; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/davinci-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/davinci-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..e60b9a13bdcbd5887078e110280dffe5e39ba5e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/davinci-wdt.txt @@ -0,0 +1,24 @@ +Texas Instruments DaVinci/Keystone Watchdog Timer (WDT) Controller + +Required properties: +- compatible : Should be "ti,davinci-wdt", "ti,keystone-wdt" +- reg : Should contain WDT registers location and length + +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds +- clocks : the clock feeding the watchdog timer. + Needed if platform uses clocks. + See clock-bindings.txt + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/spruer5b/spruer5b.pdf +Keystone - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf + +Examples: + +wdt: wdt@2320000 { + compatible = "ti,davinci-wdt"; + reg = <0x02320000 0x80>; + timeout-sec = <30>; + clocks = <&clkwdtimer0>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/digicolor-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/digicolor-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..a882967e17d4c37ca1f6b7c96c85abbcd45689c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/digicolor-wdt.txt @@ -0,0 +1,25 @@ +Conexant Digicolor SoCs Watchdog timer + +The watchdog functionality in Conexant Digicolor SoCs relies on the so called +"Agent Communication" block. This block includes the eight programmable system +timer counters. The first timer (called "Timer A") is the only one that can be +used as watchdog. + +Required properties: + +- compatible : Should be "cnxt,cx92755-wdt" +- reg : Specifies base physical address and size of the registers +- clocks : phandle; specifies the clock that drives the timer + +Optional properties: + +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + + watchdog@f0000fc0 { + compatible = "cnxt,cx92755-wdt"; + reg = <0xf0000fc0 0x8>; + clocks = <&main_clk>; + timeout-sec = <15>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/dw_wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/dw_wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb0914420c7cac06c6afcf2d072390c9a1301729 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/dw_wdt.txt @@ -0,0 +1,24 @@ +Synopsys Designware Watchdog Timer + +Required Properties: + +- compatible : Should contain "snps,dw-wdt" +- reg : Base address and size of the watchdog timer registers. +- clocks : phandle + clock-specifier for the clock that drives the + watchdog timer. + +Optional Properties: + +- interrupts : The interrupt used for the watchdog timeout warning. +- resets : phandle pointing to the system reset controller with + line index for the watchdog. + +Example: + + watchdog0: wd@ffd02000 { + compatible = "snps,dw-wdt"; + reg = <0xffd02000 0x1000>; + interrupts = <0 171 4>; + clocks = <&per_base_clk>; + resets = <&rst WDT0_RESET>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/faraday,ftwdt010.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/faraday,ftwdt010.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ecdb502e605949f79b88fa7ab03ff90e98b590a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/faraday,ftwdt010.txt @@ -0,0 +1,22 @@ +Faraday Technology FTWDT010 watchdog + +This is an IP part from Faraday Technology found in the Gemini +SoCs and others. + +Required properties: +- compatible : must be one of + "faraday,ftwdt010" + "cortina,gemini-watchdog", "faraday,ftwdt010" +- reg : shall contain base register location and length +- interrupts : shall contain the interrupt for the watchdog + +Optional properties: +- timeout-sec : the default watchdog timeout in seconds. + +Example: + +watchdog@41000000 { + compatible = "faraday,ftwdt010"; + reg = <0x41000000 0x1000>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/fsl-imx-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/fsl-imx-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..adc6b76fcb3a54d43da5d3e9eef41459a5b87713 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/fsl-imx-wdt.txt @@ -0,0 +1,24 @@ +* Freescale i.MX Watchdog Timer (WDT) Controller + +Required properties: +- compatible : Should be "fsl,-wdt" +- reg : Should contain WDT registers location and length +- interrupts : Should contain WDT interrupt + +Optional properties: +- big-endian: If present the watchdog device's registers are implemented + in big endian mode, otherwise in native mode(same with CPU), for more + detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. +- fsl,ext-reset-output: If present the watchdog device is configured to + assert its external reset (WDOG_B) instead of issuing a software reset. +- timeout-sec : Contains the watchdog timeout in seconds + +Examples: + +wdt@73f98000 { + compatible = "fsl,imx51-wdt", "fsl,imx21-wdt"; + reg = <0x73f98000 0x4000>; + interrupts = <58>; + big-endian; + timeout-sec = <20>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/gpio-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/gpio-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..198794963786bac2d46e4e9af0b39b28828669f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/gpio-wdt.txt @@ -0,0 +1,28 @@ +* GPIO-controlled Watchdog + +Required Properties: +- compatible: Should contain "linux,wdt-gpio". +- gpios: From common gpio binding; gpio connection to WDT reset pin. +- hw_algo: The algorithm used by the driver. Should be one of the + following values: + - toggle: Either a high-to-low or a low-to-high transition clears + the WDT counter. The watchdog timer is disabled when GPIO is + left floating or connected to a three-state buffer. + - level: Low or high level starts counting WDT timeout, + the opposite level disables the WDT. Active level is determined + by the GPIO flags. +- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). + +Optional Properties: +- always-running: If the watchdog timer cannot be disabled, add this flag to + have the driver keep toggling the signal without a client. It will only cease + to toggle the signal when the device is open and the timeout elapsed. + +Example: + watchdog: watchdog { + /* ADM706 */ + compatible = "linux,wdt-gpio"; + gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + hw_margin_ms = <1600>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/imgpdc-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/imgpdc-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..b2fa11fd43dee50157672f69584a47d73cf5636a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/imgpdc-wdt.txt @@ -0,0 +1,19 @@ +*ImgTec PowerDown Controller (PDC) Watchdog Timer (WDT) + +Required properties: +- compatible : Should be "img,pdc-wdt" +- reg : Should contain WDT registers location and length +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Should contain "wdt" and "sys"; the watchdog counter + clock and register interface clock respectively. +- interrupts : Should contain WDT interrupt + +Examples: + +watchdog@18102100 { + compatible = "img,pdc-wdt"; + reg = <0x18102100 0x100>; + clocks = <&pdc_wdt_clk>, <&sys_clk>; + clock-names = "wdt", "sys"; + interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/ingenic,jz4740-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/ingenic,jz4740-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce1cb72d53452df3ab226f3d68daaa5ae91663b2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/ingenic,jz4740-wdt.txt @@ -0,0 +1,17 @@ +Ingenic Watchdog Timer (WDT) Controller for JZ4740 & JZ4780 + +Required properties: +compatible: "ingenic,jz4740-watchdog" or "ingenic,jz4780-watchdog" +reg: Register address and length for watchdog registers +clocks: phandle to the RTC clock +clock-names: should be "rtc" + +Example: + +watchdog: jz4740-watchdog@10002000 { + compatible = "ingenic,jz4740-watchdog"; + reg = <0x10002000 0x10>; + + clocks = <&cgu JZ4740_CLK_RTC>; + clock-names = "rtc"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/lantiq-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/lantiq-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..18d4d83027026dd166b762bc87188fa475a186ac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/lantiq-wdt.txt @@ -0,0 +1,24 @@ +Lantiq WTD watchdog binding +============================ + +This describes the binding of the Lantiq watchdog driver. + +------------------------------------------------------------------------------- +Required properties: +- compatible : Should be one of + "lantiq,wdt" + "lantiq,xrx100-wdt" + "lantiq,xrx200-wdt", "lantiq,xrx100-wdt" + "lantiq,falcon-wdt" +- reg : Address of the watchdog block +- lantiq,rcu : A phandle to the RCU syscon (required for + "lantiq,falcon-wdt" and "lantiq,xrx100-wdt") + +------------------------------------------------------------------------------- +Example for the watchdog on the xRX200 SoCs: + watchdog@803f0 { + compatible = "lantiq,xrx200-wdt", "lantiq,xrx100-wdt"; + reg = <0x803f0 0x10>; + + lantiq,rcu = <&rcu0>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/lpc18xx-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/lpc18xx-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..09f6b24969e0fd48eaaed78594571f7eade9076f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/lpc18xx-wdt.txt @@ -0,0 +1,19 @@ +* NXP LPC18xx Watchdog Timer (WDT) + +Required properties: +- compatible: Should be "nxp,lpc1850-wwdt" +- reg: Should contain WDT registers location and length +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Should contain "wdtclk" and "reg"; the watchdog counter + clock and register interface clock respectively. +- interrupts: Should contain WDT interrupt + +Examples: + +watchdog@40080000 { + compatible = "nxp,lpc1850-wwdt"; + reg = <0x40080000 0x24>; + clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_WWDT>; + clock-names = "wdtclk", "reg"; + interrupts = <49>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/marvel.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/marvel.txt new file mode 100644 index 0000000000000000000000000000000000000000..c1b67a78f00c770109bdf0b80059e401413b80ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/marvel.txt @@ -0,0 +1,45 @@ +* Marvell Orion Watchdog Time + +Required Properties: + +- Compatibility : "marvell,orion-wdt" + "marvell,armada-370-wdt" + "marvell,armada-xp-wdt" + "marvell,armada-375-wdt" + "marvell,armada-380-wdt" + +- reg : Should contain two entries: first one with the + timer control address, second one with the + rstout enable address. + +For "marvell,armada-375-wdt" and "marvell,armada-380-wdt": + +- reg : A third entry is mandatory and should contain the + shared mask/unmask RSTOUT address. + +Clocks required for compatibles = "marvell,orion-wdt", + "marvell,armada-370-wdt": +- clocks : Must contain a single entry describing the clock input + +Clocks required for compatibles = "marvell,armada-xp-wdt" + "marvell,armada-375-wdt" + "marvell,armada-380-wdt": +- clocks : Must contain an entry for each entry in clock-names. +- clock-names : Must include the following entries: + "nbclk" (L2/coherency fabric clock), + "fixed" (Reference 25 MHz fixed-clock). + +Optional properties: + +- interrupts : Contains the IRQ for watchdog expiration +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + + wdt@20300 { + compatible = "marvell,orion-wdt"; + reg = <0x20300 0x28>, <0x20108 0x4>; + interrupts = <3>; + timeout-sec = <10>; + clocks = <&gate_clk 7>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/men-a021-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/men-a021-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..370dee3226d9dc34572304bc425d9e03f8b6804e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/men-a021-wdt.txt @@ -0,0 +1,25 @@ +Bindings for MEN A21 Watchdog device connected to GPIO lines + +Required properties: +- compatible: "men,a021-wdt" +- gpios: Specifies the pins that control the Watchdog, order: + 1: Watchdog enable + 2: Watchdog fast-mode + 3: Watchdog trigger + 4: Watchdog reset cause bit 0 + 5: Watchdog reset cause bit 1 + 6: Watchdog reset cause bit 2 + +Optional properties: +- None + +Example: + watchdog { + compatible ="men,a021-wdt"; + gpios = <&gpio3 9 1 /* WD_EN */ + &gpio3 10 1 /* WD_FAST */ + &gpio3 11 1 /* WD_TRIG */ + &gpio3 6 1 /* RST_CAUSE[0] */ + &gpio3 7 1 /* RST_CAUSE[1] */ + &gpio3 8 1>; /* RST_CAUSE[2] */ + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/meson-gxbb-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/meson-gxbb-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..c7fe36fa739c9a58fb3b1a8224a381abada8649f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/meson-gxbb-wdt.txt @@ -0,0 +1,16 @@ +Meson GXBB SoCs Watchdog timer + +Required properties: + +- compatible : should be "amlogic,meson-gxbb-wdt" +- reg : Specifies base physical address and size of the registers. +- clocks : Should be a phandle to the Watchdog clock source, for GXBB the xtal + is the default clock source. + +Example: + +wdt: watchdog@98d0 { + compatible = "amlogic,meson-gxbb-wdt"; + reg = <0 0x98d0 0x0 0x10>; + clocks = <&xtal>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/meson-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/meson-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..7588cc3971bf6bf7bc229072e1a1ccb2aad73501 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/meson-wdt.txt @@ -0,0 +1,21 @@ +Meson SoCs Watchdog timer + +Required properties: + +- compatible : depending on the SoC this should be one of: + "amlogic,meson6-wdt" on Meson6 SoCs + "amlogic,meson8-wdt" and "amlogic,meson6-wdt" on Meson8 SoCs + "amlogic,meson8b-wdt" on Meson8b SoCs + "amlogic,meson8m2-wdt" and "amlogic,meson8b-wdt" on Meson8m2 SoCs +- reg : Specifies base physical address and size of the registers. + +Optional properties: +- timeout-sec: contains the watchdog timeout in seconds. + +Example: + +wdt: watchdog@c1109900 { + compatible = "amlogic,meson6-wdt"; + reg = <0xc1109900 0x8>; + timeout-sec = <10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/microchip,pic32-dmt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/microchip,pic32-dmt.txt new file mode 100644 index 0000000000000000000000000000000000000000..49485f8313739e71ab0e5f9b56097a7822315383 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/microchip,pic32-dmt.txt @@ -0,0 +1,19 @@ +* Microchip PIC32 Deadman Timer + +The deadman timer is used to reset the processor in the event of a software +malfunction. It is a free-running instruction fetch timer, which is clocked +whenever an instruction fetch occurs until a count match occurs. + +Required properties: +- compatible: must be "microchip,pic32mzda-dmt". +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: phandle of source clk. Should be <&rootclk PB7CLK>. + +Example: + + watchdog@1f800a00 { + compatible = "microchip,pic32mzda-dmt"; + reg = <0x1f800a00 0x80>; + clocks = <&rootclk PB7CLK>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/microchip,pic32-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/microchip,pic32-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..f03a29a1b32394cf585661b163a6f598a91a5f8f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/microchip,pic32-wdt.txt @@ -0,0 +1,18 @@ +* Microchip PIC32 Watchdog Timer + +When enabled, the watchdog peripheral can be used to reset the device if the +WDT is not cleared periodically in software. + +Required properties: +- compatible: must be "microchip,pic32mzda-wdt". +- reg: physical base address of the controller and length of memory mapped + region. +- clocks: phandle of source clk. Should be <&rootclk LPRCCLK>. + +Example: + + watchdog@1f800800 { + compatible = "microchip,pic32mzda-wdt"; + reg = <0x1f800800 0x200>; + clocks = <&rootclk LPRCCLK>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/moxa,moxart-watchdog.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/moxa,moxart-watchdog.txt new file mode 100644 index 0000000000000000000000000000000000000000..1169857d1d12a08e9d0e7d3ff76dcd521e3c88f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/moxa,moxart-watchdog.txt @@ -0,0 +1,15 @@ +MOXA ART Watchdog timer + +Required properties: + +- compatible : Must be "moxa,moxart-watchdog" +- reg : Should contain registers location and length +- clocks : Should contain phandle for the clock that drives the counter + +Example: + + watchdog: watchdog@98500000 { + compatible = "moxa,moxart-watchdog"; + reg = <0x98500000 0x10>; + clocks = <&coreclk>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/mt7621-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/mt7621-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..c15ef0ef609f3f26e6060e91f7c3ff0ca8631466 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/mt7621-wdt.txt @@ -0,0 +1,12 @@ +Ralink Watchdog Timers + +Required properties: +- compatible: must be "mediatek,mt7621-wdt" +- reg: physical base address of the controller and length of the register range + +Example: + + watchdog@100 { + compatible = "mediatek,mt7621-wdt"; + reg = <0x100 0x10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/mtk-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/mtk-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..859dee167b9140970942fe08a5b1fca760f4f96f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/mtk-wdt.txt @@ -0,0 +1,23 @@ +Mediatek SoCs Watchdog timer + +Required properties: + +- compatible should contain: + "mediatek,mt2701-wdt", "mediatek,mt6589-wdt": for MT2701 + "mediatek,mt6589-wdt": for MT6589 + "mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797 + "mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622 + "mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623 + +- reg : Specifies base physical address and size of the registers. + +Optional properties: +- timeout-sec: contains the watchdog timeout in seconds. + +Example: + +wdt: watchdog@10000000 { + compatible = "mediatek,mt6589-wdt"; + reg = <0x10000000 0x18>; + timeout-sec = <10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/nuvoton,npcm-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/nuvoton,npcm-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..6d593003c933bedddafb80ef685eeec8bb7facf0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/nuvoton,npcm-wdt.txt @@ -0,0 +1,28 @@ +Nuvoton NPCM Watchdog + +Nuvoton NPCM timer module provides five 24-bit timer counters, and a watchdog. +The watchdog supports a pre-timeout interrupt that fires 10ms before the +expiry. + +Required properties: +- compatible : "nuvoton,npcm750-wdt" for NPCM750 (Poleg). +- reg : Offset and length of the register set for the device. +- interrupts : Contain the timer interrupt with flags for + falling edge. + +Required clocking property, have to be one of: +- clocks : phandle of timer reference clock. +- clock-frequency : The frequency in Hz of the clock that drives the NPCM7xx + timer (usually 25000000). + +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + +timer@f000801c { + compatible = "nuvoton,npcm750-wdt"; + interrupts = ; + reg = <0xf000801c 0x4>; + clocks = <&clk NPCM7XX_CLK_TIMER>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/of-xilinx-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/of-xilinx-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..c6ae9c9d5e3e2c13a640d48d2af3d79b8aa90388 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/of-xilinx-wdt.txt @@ -0,0 +1,26 @@ +Xilinx AXI/PLB soft-core watchdog Device Tree Bindings +--------------------------------------------------------- + +Required properties: +- compatible : Should be "xlnx,xps-timebase-wdt-1.00.a" or + "xlnx,xps-timebase-wdt-1.01.a". +- reg : Physical base address and size + +Optional properties: +- clocks : Input clock specifier. Refer to common clock + bindings. +- clock-frequency : Frequency of clock in Hz +- xlnx,wdt-enable-once : 0 - Watchdog can be restarted + 1 - Watchdog can be enabled just once +- xlnx,wdt-interval : Watchdog timeout interval in 2^ clock cycles, + is integer from 8 to 31. + +Example: +axi-timebase-wdt@40100000 { + clock-frequency = <50000000>; + compatible = "xlnx,xps-timebase-wdt-1.00.a"; + clocks = <&clkc 15>; + reg = <0x40100000 0x10000>; + xlnx,wdt-enable-once = <0x0>; + xlnx,wdt-interval = <0x1b>; +} ; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/omap-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/omap-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..1fa20e453a2d00207fb72408b3c84db066d3ed9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/omap-wdt.txt @@ -0,0 +1,15 @@ +TI Watchdog Timer (WDT) Controller for OMAP + +Required properties: +- compatible : "ti,omap3-wdt" for OMAP3 or "ti,omap4-wdt" for OMAP4 +- ti,hwmods : Name of the hwmod associated to the WDT + +Optional properties: +- timeout-sec : default watchdog timeout in seconds + +Examples: + +wdt2: wdt@4a314000 { + compatible = "ti,omap4-wdt", "ti,omap3-wdt"; + ti,hwmods = "wd_timer2"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/pnx4008-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/pnx4008-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b76bec62af9d42df8096e5e62fa77bacbbe01b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/pnx4008-wdt.txt @@ -0,0 +1,17 @@ +* NXP PNX watchdog timer + +Required properties: +- compatible: must be "nxp,pnx4008-wdt" +- reg: physical base address of the controller and length of memory mapped + region. + +Optional properties: +- timeout-sec: contains the watchdog timeout in seconds. + +Example: + + watchdog@4003c000 { + compatible = "nxp,pnx4008-wdt"; + reg = <0x4003C000 0x1000>; + timeout-sec = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/qca-ar7130-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/qca-ar7130-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a89e5f854153401ceb88d14633cc6e624ba2ab8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/qca-ar7130-wdt.txt @@ -0,0 +1,13 @@ +* Qualcomm Atheros AR7130 Watchdog Timer (WDT) Controller + +Required properties: +- compatible: must be "qca,ar7130-wdt" +- reg: physical base address of the controller and length of memory mapped + region. + +Example: + +wdt@18060008 { + compatible = "qca,ar9330-wdt", "qca,ar7130-wdt"; + reg = <0x18060008 0x8>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/qcom-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/qcom-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..41aeaa2ff0f89a3d099c1502c7b55161097b466e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/qcom-wdt.txt @@ -0,0 +1,28 @@ +Qualcomm Krait Processor Sub-system (KPSS) Watchdog +--------------------------------------------------- + +Required properties : +- compatible : shall contain only one of the following: + + "qcom,kpss-wdt-msm8960" + "qcom,kpss-wdt-apq8064" + "qcom,kpss-wdt-ipq8064" + "qcom,kpss-wdt-ipq4019" + "qcom,kpss-timer" + "qcom,scss-timer" + "qcom,kpss-wdt" + +- reg : shall contain base register location and length +- clocks : shall contain the input clock + +Optional properties : +- timeout-sec : shall contain the default watchdog timeout in seconds, + if unset, the default timeout is 30 seconds + +Example: + watchdog@208a038 { + compatible = "qcom,kpss-wdt-ipq8064"; + reg = <0x0208a038 0x40>; + clocks = <&sleep_clk>; + timeout-sec = <10>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/realtek,rtd119x.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/realtek,rtd119x.txt new file mode 100644 index 0000000000000000000000000000000000000000..05653054bd5b24909c09fe1412fa6b40bdf1262b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/realtek,rtd119x.txt @@ -0,0 +1,17 @@ +Realtek RTD1295 Watchdog +======================== + +Required properties: + +- compatible : Should be "realtek,rtd1295-watchdog" +- reg : Specifies the physical base address and size of registers +- clocks : Specifies one clock input + + +Example: + + watchdog@98007680 { + compatible = "realtek,rtd1295-watchdog"; + reg = <0x98007680 0x100>; + clocks = <&osc27M>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/renesas-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/renesas-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..9407212a85a8cac6918c56a27380bdb101e7af31 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/renesas-wdt.txt @@ -0,0 +1,44 @@ +Renesas Watchdog Timer (WDT) Controller + +Required properties: + - compatible : Must be "renesas,-wdt", followed by a generic + fallback compatible string when compatible with the generic + version. + Examples with soctypes are: + - "renesas,r8a7743-wdt" (RZ/G1M) + - "renesas,r8a7745-wdt" (RZ/G1E) + - "renesas,r8a774a1-wdt" (RZ/G2M) + - "renesas,r8a7790-wdt" (R-Car H2) + - "renesas,r8a7791-wdt" (R-Car M2-W) + - "renesas,r8a7792-wdt" (R-Car V2H) + - "renesas,r8a7793-wdt" (R-Car M2-N) + - "renesas,r8a7794-wdt" (R-Car E2) + - "renesas,r8a7795-wdt" (R-Car H3) + - "renesas,r8a7796-wdt" (R-Car M3-W) + - "renesas,r8a77965-wdt" (R-Car M3-N) + - "renesas,r8a77970-wdt" (R-Car V3M) + - "renesas,r8a77990-wdt" (R-Car E3) + - "renesas,r8a77995-wdt" (R-Car D3) + - "renesas,r7s72100-wdt" (RZ/A1) + The generic compatible string must be: + - "renesas,rza-wdt" for RZ/A + - "renesas,rcar-gen2-wdt" for R-Car Gen2 and RZ/G1 + - "renesas,rcar-gen3-wdt" for R-Car Gen3 and RZ/G2 + +- reg : Should contain WDT registers location and length +- clocks : the clock feeding the watchdog timer. + +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds +- power-domains : the power domain the WDT belongs to +- interrupts: Some WDTs have an interrupt when used in interval timer mode + +Examples: + + wdt0: watchdog@e6020000 { + compatible = "renesas,r8a7795-wdt", "renesas,rcar-gen3-wdt"; + reg = <0 0xe6020000 0 0x0c>; + clocks = <&cpg CPG_MOD 402>; + power-domains = <&cpg>; + timeout-sec = <60>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/rt2880-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/rt2880-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..05b95bfa2a890b8d3a99943e8d0c6542dd75e0b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/rt2880-wdt.txt @@ -0,0 +1,18 @@ +Ralink Watchdog Timers + +Required properties: +- compatible: must be "ralink,rt2880-wdt" +- reg: physical base address of the controller and length of the register range + +Optional properties: +- interrupts: Specify the INTC interrupt number + +Example: + + watchdog@120 { + compatible = "ralink,rt2880-wdt"; + reg = <0x120 0x10>; + + interrupt-parent = <&intc>; + interrupts = <1>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/samsung-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/samsung-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..46dcb48e75b41d0643647d31eb8af89ca1cf6f95 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/samsung-wdt.txt @@ -0,0 +1,35 @@ +* Samsung's Watchdog Timer Controller + +The Samsung's Watchdog controller is used for resuming system operation +after a preset amount of time during which the WDT reset event has not +occurred. + +Required properties: +- compatible : should be one among the following + - "samsung,s3c2410-wdt" for S3C2410 + - "samsung,s3c6410-wdt" for S3C6410, S5PV210 and Exynos4 + - "samsung,exynos5250-wdt" for Exynos5250 + - "samsung,exynos5420-wdt" for Exynos5420 + - "samsung,exynos7-wdt" for Exynos7 + +- reg : base physical address of the controller and length of memory mapped + region. +- interrupts : interrupt number to the cpu. +- samsung,syscon-phandle : reference to syscon node (This property required only + in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt". + In case of Exynos5250 and 5420 this property points to syscon node holding the PMU + base address) + +Optional properties: +- timeout-sec : contains the watchdog timeout in seconds. + +Example: + +watchdog@101d0000 { + compatible = "samsung,exynos5250-wdt"; + reg = <0x101D0000 0x100>; + interrupts = <0 42 0>; + clocks = <&clock 336>; + clock-names = "watchdog"; + samsung,syscon-phandle = <&pmu_syscon>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/sbsa-gwdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/sbsa-gwdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f2d5f91964d50c029ee8be0cfbdf3e245b74f92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/sbsa-gwdt.txt @@ -0,0 +1,31 @@ +* SBSA (Server Base System Architecture) Generic Watchdog + +The SBSA Generic Watchdog Timer is used to force a reset of the system +after two stages of timeout have elapsed. A detailed definition of the +watchdog timer can be found in the ARM document: ARM-DEN-0029 - Server +Base System Architecture (SBSA) + +Required properties: +- compatible: Should at least contain "arm,sbsa-gwdt". + +- reg: Each entry specifies the base physical address of a register frame + and the length of that frame; currently, two frames must be defined, + in this order: + 1: Watchdog control frame; + 2: Refresh frame. + +- interrupts: Should contain the Watchdog Signal 0 (WS0) SPI (Shared + Peripheral Interrupt) number of SBSA Generic Watchdog. + +Optional properties +- timeout-sec: Watchdog timeout values (in seconds). + +Example for FVP Foundation Model v8: + +watchdog@2a440000 { + compatible = "arm,sbsa-gwdt"; + reg = <0x0 0x2a440000 0 0x1000>, + <0x0 0x2a450000 0 0x1000>; + interrupts = <0 27 4>; + timeout-sec = <30>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/sigma,smp8642-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/sigma,smp8642-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..5b7ec2c707d8bb83432a0726d4117459234090c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/sigma,smp8642-wdt.txt @@ -0,0 +1,18 @@ +Sigma Designs SMP86xx/SMP87xx watchdog + +Required properties: +- compatible: Should be "sigma,smp8642-wdt" +- reg: Specifies the physical address region +- clocks: Should be a phandle to the clock + +Optional properties: +- timeout-sec: watchdog timeout in seconds + +Example: + +watchdog@1fd00 { + compatible = "sigma,smp8642-wdt"; + reg = <0x1fd00 8>; + clocks = <&xtal_in_clk>; + timeout-sec = <30>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/sirfsoc_wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/sirfsoc_wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..0dce5e3100b499e550278052a20b7f7d75c2c5ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/sirfsoc_wdt.txt @@ -0,0 +1,18 @@ +SiRFSoC Timer and Watchdog Timer(WDT) Controller + +Required properties: +- compatible: "sirf,prima2-tick" +- reg: Address range of tick timer/WDT register set +- interrupts: interrupt number to the cpu + +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + +timer@b0020000 { + compatible = "sirf,prima2-tick"; + reg = <0xb0020000 0x1000>; + interrupts = <0>; + timeout-sec = <30>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/sprd-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/sprd-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..aeaf3e0caf47b2695fde0c7d1eb86f89a46108fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/sprd-wdt.txt @@ -0,0 +1,19 @@ +Spreadtrum SoCs Watchdog timer + +Required properties: +- compatible : Should be "sprd,sp9860-wdt". +- reg : Specifies base physical address and size of the registers. +- interrupts : Exactly one interrupt specifier. +- timeout-sec : Contain the default watchdog timeout in seconds. +- clock-names : Contain the input clock names. +- clocks : Phandles to input clocks. + +Example: + watchdog: watchdog@40310000 { + compatible = "sprd,sp9860-wdt"; + reg = <0 0x40310000 0 0x1000>; + interrupts = ; + timeout-sec = <12>; + clock-names = "enable", "rtc_enable"; + clocks = <&clk_aon_apb_gates1 8>, <&clk_aon_apb_rtc_gates 9>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/st,stm32-iwdg.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/st,stm32-iwdg.txt new file mode 100644 index 0000000000000000000000000000000000000000..d8f4430b0a13b8dff44449afe0a3c96d81d8c1a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/st,stm32-iwdg.txt @@ -0,0 +1,26 @@ +STM32 Independent WatchDoG (IWDG) +--------------------------------- + +Required properties: +- compatible: Should be either: + - "st,stm32-iwdg" + - "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "lsi", "pclk" for st,stm32mp1-iwdg + +Optional Properties: +- timeout-sec: Watchdog timeout value in seconds. + +Example: + +iwdg: watchdog@40003000 { + compatible = "st,stm32-iwdg"; + reg = <0x40003000 0x400>; + clocks = <&clk_lsi>; + clock-names = "lsi"; + timeout-sec = <32>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/st_lpc_wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/st_lpc_wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..b949039bc5025741203232852469a57c71dcbd0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/st_lpc_wdt.txt @@ -0,0 +1,41 @@ +STMicroelectronics Low Power Controller (LPC) - Watchdog +======================================================== + +LPC currently supports Watchdog OR Real Time Clock OR Clocksource +functionality. + +[See: ../rtc/rtc-st-lpc.txt for RTC options] +[See: ../timer/st,stih407-lpc for Clocksource options] + +Required properties + +- compatible : Should be: "st,stih407-lpc" +- reg : LPC registers base address + size +- interrupts : LPC interrupt line number and associated flags +- clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) +- st,lpc-mode : The LPC can run either one of three modes: + ST_LPC_MODE_RTC [0] + ST_LPC_MODE_WDT [1] + ST_LPC_MODE_CLKSRC [2] + One (and only one) mode must be selected. + +Required properties [watchdog mode] + +- st,syscfg : Phandle to syscfg node used to enable watchdog and configure + CPU reset type. +- timeout-sec : Watchdog timeout in seconds + +Optional properties [watchdog mode] + +- st,warm-reset : If present reset type will be 'warm' - if not it will be cold + +Example: + lpc@fde05000 { + compatible = "st,stih407-lpc"; + reg = <0xfde05000 0x1000>; + clocks = <&clk_s_d3_flexgen CLK_LPC_0>; + st,syscfg = <&syscfg_core>; + timeout-sec = <120>; + st,lpc-mode = ; + st,warm-reset; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/stericsson-coh901327.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/stericsson-coh901327.txt new file mode 100644 index 0000000000000000000000000000000000000000..8ffb88e39e7652bbb533a1cf70155cb568c3d67d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/stericsson-coh901327.txt @@ -0,0 +1,19 @@ +ST-Ericsson COH 901 327 Watchdog timer + +Required properties: +- compatible: must be "stericsson,coh901327". +- reg: physical base address of the controller and length of memory mapped + region. +- interrupts: the interrupt used for the watchdog timeout warning. + +Optional properties: +- timeout-sec: contains the watchdog timeout in seconds. + +Example: + +watchdog: watchdog@c0012000 { + compatible = "stericsson,coh901327"; + reg = <0xc0012000 0x1000>; + interrupts = <3>; + timeout-sec = <60>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/sunxi-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/sunxi-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed11ce0ac8362d687bdfcc9041194deb5f4ee265 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/sunxi-wdt.txt @@ -0,0 +1,20 @@ +Allwinner SoCs Watchdog timer + +Required properties: + +- compatible : should be one of + "allwinner,sun4i-a10-wdt" + "allwinner,sun6i-a31-wdt" + "allwinner,sun50i-a64-wdt","allwinner,sun6i-a31-wdt" +- reg : Specifies base physical address and size of the registers. + +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + +wdt: watchdog@1c20c90 { + compatible = "allwinner,sun4i-a10-wdt"; + reg = <0x01c20c90 0x10>; + timeout-sec = <10>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/ts4800-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/ts4800-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f6caad4258d15306a610d89f0d5d1aedbd0ad59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/ts4800-wdt.txt @@ -0,0 +1,25 @@ +Technologic Systems Watchdog + +Required properties: +- compatible: must be "technologic,ts4800-wdt" +- syscon: phandle / integer array that points to the syscon node which + describes the FPGA's syscon registers. + - phandle to FPGA's syscon + - offset to the watchdog register + +Optional property: +- timeout-sec: contains the watchdog timeout in seconds. + +Example: + +syscon: syscon@b0010000 { + compatible = "syscon", "simple-mfd"; + reg = <0xb0010000 0x3d>; + reg-io-width = <2>; + + wdt@e { + compatible = "technologic,ts4800-wdt"; + syscon = <&syscon 0xe>; + timeout-sec = <10>; + }; +} diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/twl4030-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/twl4030-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..80a37193c0b86b0e697e5b93ddae7a8b6d602cb0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/twl4030-wdt.txt @@ -0,0 +1,10 @@ +Device tree bindings for twl4030-wdt driver (TWL4030 watchdog) + +Required properties: + compatible = "ti,twl4030-wdt"; + +Example: + +watchdog { + compatible = "ti,twl4030-wdt"; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/uniphier-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/uniphier-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..bf6337546dd18ce3024049424ef79527b8643f6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/uniphier-wdt.txt @@ -0,0 +1,20 @@ +UniPhier watchdog timer controller + +This UniPhier watchdog timer controller must be under sysctrl node. + +Required properties: +- compatible: should be "socionext,uniphier-wdt" + +Example: + + sysctrl@61840000 { + compatible = "socionext,uniphier-ld11-sysctrl", + "simple-mfd", "syscon"; + reg = <0x61840000 0x4000>; + + watchdog { + compatible = "socionext,uniphier-wdt"; + } + + other nodes ... + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/zii,rave-sp-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/zii,rave-sp-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..3de96186e92e6fdd4e09850f194ea5e79027ca14 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/zii,rave-sp-wdt.txt @@ -0,0 +1,39 @@ +Zodiac Inflight Innovations RAVE Supervisory Processor Watchdog Bindings + +RAVE SP watchdog device is a "MFD cell" device corresponding to +watchdog functionality of RAVE Supervisory Processor. It is expected +that its Device Tree node is specified as a child of the node +corresponding to the parent RAVE SP device (as documented in +Documentation/devicetree/bindings/mfd/zii,rave-sp.txt) + +Required properties: + +- compatible: Depending on wire protocol implemented by RAVE SP + firmware, should be one of: + - "zii,rave-sp-watchdog" + - "zii,rave-sp-watchdog-legacy" + +Optional properties: + +- wdt-timeout: Two byte nvmem cell specified as per + Documentation/devicetree/bindings/nvmem/nvmem.txt + +Example: + + rave-sp { + compatible = "zii,rave-sp-rdu1"; + current-speed = <38400>; + + eeprom { + wdt_timeout: wdt-timeout@8E { + reg = <0x8E 2>; + }; + }; + + watchdog { + compatible = "zii,rave-sp-watchdog"; + nvmem-cells = <&wdt_timeout>; + nvmem-cell-names = "wdt-timeout"; + }; + } + diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/ziirave-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/ziirave-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..3d878184ec3ff788462291a125471b392b2c5fe9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/ziirave-wdt.txt @@ -0,0 +1,19 @@ +Zodiac RAVE Watchdog Timer + +Required properties: +- compatible: must be "zii,rave-wdt" +- reg: i2c slave address of device, usually 0x38 + +Optional Properties: +- timeout-sec: Watchdog timeout value in seconds. +- reset-duration-ms: Duration of the pulse generated when the watchdog times + out. Value in milliseconds. + +Example: + + watchdog@38 { + compatible = "zii,rave-wdt"; + reg = <0x38>; + timeout-sec = <30>; + reset-duration-ms = <30>; + }; diff --git a/arch/arm64/boot/dts/vendor/bindings/watchdog/zte,zx2967-wdt.txt b/arch/arm64/boot/dts/vendor/bindings/watchdog/zte,zx2967-wdt.txt new file mode 100644 index 0000000000000000000000000000000000000000..06ce67766756e972e7532ebc8173a674e54776bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/watchdog/zte,zx2967-wdt.txt @@ -0,0 +1,32 @@ +ZTE zx2967 Watchdog timer + +Required properties: + +- compatible : should be one of the following. + * zte,zx296718-wdt +- reg : Specifies base physical address and size of the registers. +- clocks : Pairs of phandle and specifier referencing the controller's clocks. +- resets : Reference to the reset controller controlling the watchdog + controller. + +Optional properties: + +- timeout-sec : Contains the watchdog timeout in seconds. +- zte,wdt-reset-sysctrl : Directs how to reset system by the watchdog. + if we don't want to restart system when watchdog been triggered, + it's not required, vice versa. + It should include following fields. + * phandle of aon-sysctrl. + * offset of register that be written, should be 0xb0. + * configure value that be written to aon-sysctrl. + * bit mask, corresponding bits will be affected. + +Example: + +wdt: watchdog@1465000 { + compatible = "zte,zx296718-wdt"; + reg = <0x1465000 0x1000>; + clocks = <&topcrm WDT_WCLK>; + resets = <&toprst 35>; + zte,wdt-reset-sysctrl = <&aon_sysctrl 0xb0 1 0x115>; +}; diff --git a/arch/arm64/boot/dts/vendor/bindings/x86/ce4100.txt b/arch/arm64/boot/dts/vendor/bindings/x86/ce4100.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd1221bfb53933dec59a2f139d282f96c00d7986 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/x86/ce4100.txt @@ -0,0 +1,57 @@ +CE4100 Device Tree Bindings +--------------------------- + +The CE4100 SoC uses for in core peripherals the following compatible +format: ,-. +Many of the "generic" devices like HPET or IO APIC have the ce4100 +name in their compatible property because they first appeared in this +SoC. + +The CPU nodes +------------- + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "intel,ce4100"; + reg = <0x00>; + }; + + cpu@2 { + device_type = "cpu"; + compatible = "intel,ce4100"; + reg = <0x02>; + }; + }; + +A "cpu" node describes one logical processor (hardware thread). + +Required properties: + +- device_type + Device type, must be "cpu". + +- reg + Local APIC ID, the unique number assigned to each processor by + system hardware. + +The SoC node +------------ + +This node describes the in-core peripherals. Required property: + compatible = "intel,ce4100-cp"; + +The PCI node +------------ +This node describes the PCI bus on the SoC. Its property should be + compatible = "intel,ce4100-pci", "pci"; + +If the OS is using the IO-APIC for interrupt routing then the reported +interrupt numbers for devices is no longer true. In order to obtain the +correct interrupt number, the child node which represents the device has +to contain the interrupt property. Besides the interrupt property it has +to contain at least the reg property containing the PCI bus address and +compatible property according to "PCI Bus Binding Revision 2.1". diff --git a/arch/arm64/boot/dts/vendor/bindings/x86/timer.txt b/arch/arm64/boot/dts/vendor/bindings/x86/timer.txt new file mode 100644 index 0000000000000000000000000000000000000000..c688af58e3bdbe551dddffe3a8f57ec0d705e677 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/x86/timer.txt @@ -0,0 +1,6 @@ +Timers +------ + +* High Precision Event Timer (HPET) + Required property: + compatible = "intel,ce4100-hpet"; diff --git a/arch/arm64/boot/dts/vendor/bindings/xilinx.txt b/arch/arm64/boot/dts/vendor/bindings/xilinx.txt new file mode 100644 index 0000000000000000000000000000000000000000..d058ace29345b3e8622149fb7f19c3471d61d459 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/xilinx.txt @@ -0,0 +1,308 @@ + d) Xilinx IP cores + + The Xilinx EDK toolchain ships with a set of IP cores (devices) for use + in Xilinx Spartan and Virtex FPGAs. The devices cover the whole range + of standard device types (network, serial, etc.) and miscellaneous + devices (gpio, LCD, spi, etc). Also, since these devices are + implemented within the fpga fabric every instance of the device can be + synthesised with different options that change the behaviour. + + Each IP-core has a set of parameters which the FPGA designer can use to + control how the core is synthesized. Historically, the EDK tool would + extract the device parameters relevant to device drivers and copy them + into an 'xparameters.h' in the form of #define symbols. This tells the + device drivers how the IP cores are configured, but it requires the kernel + to be recompiled every time the FPGA bitstream is resynthesized. + + The new approach is to export the parameters into the device tree and + generate a new device tree each time the FPGA bitstream changes. The + parameters which used to be exported as #defines will now become + properties of the device node. In general, device nodes for IP-cores + will take the following form: + + (name): (generic-name)@(base-address) { + compatible = "xlnx,(ip-core-name)-(HW_VER)" + [, (list of compatible devices), ...]; + reg = <(baseaddr) (size)>; + interrupt-parent = <&interrupt-controller-phandle>; + interrupts = < ... >; + xlnx,(parameter1) = "(string-value)"; + xlnx,(parameter2) = <(int-value)>; + }; + + (generic-name): an open firmware-style name that describes the + generic class of device. Preferably, this is one word, such + as 'serial' or 'ethernet'. + (ip-core-name): the name of the ip block (given after the BEGIN + directive in system.mhs). Should be in lowercase + and all underscores '_' converted to dashes '-'. + (name): is derived from the "PARAMETER INSTANCE" value. + (parameter#): C_* parameters from system.mhs. The C_ prefix is + dropped from the parameter name, the name is converted + to lowercase and all underscore '_' characters are + converted to dashes '-'. + (baseaddr): the baseaddr parameter value (often named C_BASEADDR). + (HW_VER): from the HW_VER parameter. + (size): the address range size (often C_HIGHADDR - C_BASEADDR + 1). + + Typically, the compatible list will include the exact IP core version + followed by an older IP core version which implements the same + interface or any other device with the same interface. + + 'reg' and 'interrupts' are all optional properties. + + For example, the following block from system.mhs: + + BEGIN opb_uartlite + PARAMETER INSTANCE = opb_uartlite_0 + PARAMETER HW_VER = 1.00.b + PARAMETER C_BAUDRATE = 115200 + PARAMETER C_DATA_BITS = 8 + PARAMETER C_ODD_PARITY = 0 + PARAMETER C_USE_PARITY = 0 + PARAMETER C_CLK_FREQ = 50000000 + PARAMETER C_BASEADDR = 0xEC100000 + PARAMETER C_HIGHADDR = 0xEC10FFFF + BUS_INTERFACE SOPB = opb_7 + PORT OPB_Clk = CLK_50MHz + PORT Interrupt = opb_uartlite_0_Interrupt + PORT RX = opb_uartlite_0_RX + PORT TX = opb_uartlite_0_TX + PORT OPB_Rst = sys_bus_reset_0 + END + + becomes the following device tree node: + + opb_uartlite_0: serial@ec100000 { + device_type = "serial"; + compatible = "xlnx,opb-uartlite-1.00.b"; + reg = ; + interrupt-parent = <&opb_intc_0>; + interrupts = <1 0>; // got this from the opb_intc parameters + current-speed = ; // standard serial device prop + clock-frequency = ; // standard serial device prop + xlnx,data-bits = <8>; + xlnx,odd-parity = <0>; + xlnx,use-parity = <0>; + }; + + Some IP cores actually implement 2 or more logical devices. In + this case, the device should still describe the whole IP core with + a single node and add a child node for each logical device. The + ranges property can be used to translate from parent IP-core to the + registers of each device. In addition, the parent node should be + compatible with the bus type 'xlnx,compound', and should contain + #address-cells and #size-cells, as with any other bus. (Note: this + makes the assumption that both logical devices have the same bus + binding. If this is not true, then separate nodes should be used + for each logical device). The 'cell-index' property can be used to + enumerate logical devices within an IP core. For example, the + following is the system.mhs entry for the dual ps2 controller found + on the ml403 reference design. + + BEGIN opb_ps2_dual_ref + PARAMETER INSTANCE = opb_ps2_dual_ref_0 + PARAMETER HW_VER = 1.00.a + PARAMETER C_BASEADDR = 0xA9000000 + PARAMETER C_HIGHADDR = 0xA9001FFF + BUS_INTERFACE SOPB = opb_v20_0 + PORT Sys_Intr1 = ps2_1_intr + PORT Sys_Intr2 = ps2_2_intr + PORT Clkin1 = ps2_clk_rx_1 + PORT Clkin2 = ps2_clk_rx_2 + PORT Clkpd1 = ps2_clk_tx_1 + PORT Clkpd2 = ps2_clk_tx_2 + PORT Rx1 = ps2_d_rx_1 + PORT Rx2 = ps2_d_rx_2 + PORT Txpd1 = ps2_d_tx_1 + PORT Txpd2 = ps2_d_tx_2 + END + + It would result in the following device tree nodes: + + opb_ps2_dual_ref_0: opb-ps2-dual-ref@a9000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,compound"; + ranges = <0 a9000000 2000>; + // If this device had extra parameters, then they would + // go here. + ps2@0 { + compatible = "xlnx,opb-ps2-dual-ref-1.00.a"; + reg = <0 40>; + interrupt-parent = <&opb_intc_0>; + interrupts = <3 0>; + cell-index = <0>; + }; + ps2@1000 { + compatible = "xlnx,opb-ps2-dual-ref-1.00.a"; + reg = <1000 40>; + interrupt-parent = <&opb_intc_0>; + interrupts = <3 0>; + cell-index = <0>; + }; + }; + + Also, the system.mhs file defines bus attachments from the processor + to the devices. The device tree structure should reflect the bus + attachments. Again an example; this system.mhs fragment: + + BEGIN ppc405_virtex4 + PARAMETER INSTANCE = ppc405_0 + PARAMETER HW_VER = 1.01.a + BUS_INTERFACE DPLB = plb_v34_0 + BUS_INTERFACE IPLB = plb_v34_0 + END + + BEGIN opb_intc + PARAMETER INSTANCE = opb_intc_0 + PARAMETER HW_VER = 1.00.c + PARAMETER C_BASEADDR = 0xD1000FC0 + PARAMETER C_HIGHADDR = 0xD1000FDF + BUS_INTERFACE SOPB = opb_v20_0 + END + + BEGIN opb_uart16550 + PARAMETER INSTANCE = opb_uart16550_0 + PARAMETER HW_VER = 1.00.d + PARAMETER C_BASEADDR = 0xa0000000 + PARAMETER C_HIGHADDR = 0xa0001FFF + BUS_INTERFACE SOPB = opb_v20_0 + END + + BEGIN plb_v34 + PARAMETER INSTANCE = plb_v34_0 + PARAMETER HW_VER = 1.02.a + END + + BEGIN plb_bram_if_cntlr + PARAMETER INSTANCE = plb_bram_if_cntlr_0 + PARAMETER HW_VER = 1.00.b + PARAMETER C_BASEADDR = 0xFFFF0000 + PARAMETER C_HIGHADDR = 0xFFFFFFFF + BUS_INTERFACE SPLB = plb_v34_0 + END + + BEGIN plb2opb_bridge + PARAMETER INSTANCE = plb2opb_bridge_0 + PARAMETER HW_VER = 1.01.a + PARAMETER C_RNG0_BASEADDR = 0x20000000 + PARAMETER C_RNG0_HIGHADDR = 0x3FFFFFFF + PARAMETER C_RNG1_BASEADDR = 0x60000000 + PARAMETER C_RNG1_HIGHADDR = 0x7FFFFFFF + PARAMETER C_RNG2_BASEADDR = 0x80000000 + PARAMETER C_RNG2_HIGHADDR = 0xBFFFFFFF + PARAMETER C_RNG3_BASEADDR = 0xC0000000 + PARAMETER C_RNG3_HIGHADDR = 0xDFFFFFFF + BUS_INTERFACE SPLB = plb_v34_0 + BUS_INTERFACE MOPB = opb_v20_0 + END + + Gives this device tree (some properties removed for clarity): + + plb@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "xlnx,plb-v34-1.02.a"; + device_type = "ibm,plb"; + ranges; // 1:1 translation + + plb_bram_if_cntrl_0: bram@ffff0000 { + reg = ; + } + + opb@20000000 { + #address-cells = <1>; + #size-cells = <1>; + ranges = <20000000 20000000 20000000 + 60000000 60000000 20000000 + 80000000 80000000 40000000 + c0000000 c0000000 20000000>; + + opb_uart16550_0: serial@a0000000 { + reg = ; + }; + + opb_intc_0: interrupt-controller@d1000fc0 { + reg = ; + }; + }; + }; + + That covers the general approach to binding xilinx IP cores into the + device tree. The following are bindings for specific devices: + + i) Xilinx ML300 Framebuffer + + Simple framebuffer device from the ML300 reference design (also on the + ML403 reference design as well as others). + + Optional properties: + - resolution = : pixel resolution of framebuffer. Some + implementations use a different resolution. + Default is + - virt-resolution = : Size of framebuffer in memory. + Default is . + - rotate-display (empty) : rotate display 180 degrees. + + ii) Xilinx SystemACE + + The Xilinx SystemACE device is used to program FPGAs from an FPGA + bitstream stored on a CF card. It can also be used as a generic CF + interface device. + + Optional properties: + - 8-bit (empty) : Set this property for SystemACE in 8 bit mode + + iii) Xilinx EMAC and Xilinx TEMAC + + Xilinx Ethernet devices. In addition to general xilinx properties + listed above, nodes for these devices should include a phy-handle + property, and may include other common network device properties + like local-mac-address. + + iv) Xilinx Uartlite + + Xilinx uartlite devices are simple fixed speed serial ports. + + Required properties: + - current-speed : Baud rate of uartlite + + v) Xilinx hwicap + + Xilinx hwicap devices provide access to the configuration logic + of the FPGA through the Internal Configuration Access Port + (ICAP). The ICAP enables partial reconfiguration of the FPGA, + readback of the configuration information, and some control over + 'warm boots' of the FPGA fabric. + + Required properties: + - xlnx,family : The family of the FPGA, necessary since the + capabilities of the underlying ICAP hardware + differ between different families. May be + 'virtex2p', 'virtex4', or 'virtex5'. + - compatible : should contain "xlnx,xps-hwicap-1.00.a" or + "xlnx,opb-hwicap-1.00.b". + + vi) Xilinx Uart 16550 + + Xilinx UART 16550 devices are very similar to the NS16550 but with + different register spacing and an offset from the base address. + + Required properties: + - clock-frequency : Frequency of the clock input + - reg-offset : A value of 3 is required + - reg-shift : A value of 2 is required + + vii) Xilinx USB Host controller + + The Xilinx USB host controller is EHCI compatible but with a different + base address for the EHCI registers, and it is always a big-endian + USB Host controller. The hardware can be configured as high speed only, + or high speed/full speed hybrid. + + Required properties: + - xlnx,support-usb-fs: A value 0 means the core is built as high speed + only. A value 1 means the core also supports + full speed devices. + diff --git a/arch/arm64/boot/dts/vendor/bindings/xillybus/xillybus.txt b/arch/arm64/boot/dts/vendor/bindings/xillybus/xillybus.txt new file mode 100644 index 0000000000000000000000000000000000000000..e65d1f94b49c4d73290ebc2ac874810fa8b13a1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/xillybus/xillybus.txt @@ -0,0 +1,18 @@ +* Xillybus driver for generic FPGA interface + +Required properties: +- compatible: Should be "xillybus,xillybus-1.00.a" +- reg: Address and length of the register set for the device +- interrupts: Contains one interrupt node, typically consisting of three cells. + +Optional properties: +- dma-coherent: Present if DMA operations are coherent + +Example: + + xillybus@ff200400 { + compatible = "xillybus,xillybus-1.00.a"; + reg = < 0xff200400 0x00000080 >; + interrupts = < 0 40 1 >; + interrupt-parent = <&intc>; + } ; diff --git a/arch/arm64/boot/dts/vendor/qcom/Makefile b/arch/arm64/boot/dts/vendor/qcom/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..38da283beab760939cc319ec0df91b6d1ffb7138 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/Makefile @@ -0,0 +1,304 @@ +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_KONA) += \ + kona-cdp-overlay.dtbo \ + kona-cdp-lcd-overlay.dtbo \ + kona-mtp-overlay.dtbo \ + kona-mtp-ws-overlay.dtbo \ + kona-sa-mtp-overlay.dtbo \ + kona-xr-overlay.dtbo \ + kona-rumi-overlay.dtbo \ + kona-qrd-overlay.dtbo \ + kona-xrfusion-overlay.dtbo \ + kona-xrfusion-ult-overlay.dtbo \ + kona-hdk-overlay.dtbo + +kona-cdp-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-cdp-lcd-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-mtp-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-mtp-ws-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-sa-mtp-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-xr-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-rumi-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-qrd-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-xrfusion-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-xrfusion-ult-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb +kona-hdk-overlay.dtbo-base := kona.dtb kona-v2.dtb kona-v2.1.dtb + +else +dtb-$(CONFIG_ARCH_KONA) += kona-rumi.dtb \ + kona-mtp.dtb \ + kona-mtp-ws.dtb \ + kona-mtp-sa.dtb \ + kona-xr.dtb \ + kona-xrfusion.dtb \ + kona-xrfusion-ult.dtb \ + kona-cdp.dtb \ + kona-cdp-lcd.dtb \ + kona-qrd.dtb \ + kona-v2-rumi.dtb \ + kona-v2-mtp.dtb \ + kona-v2-mtp-ws.dtb \ + kona-v2-mtp-sa.dtb \ + kona-v2-cdp.dtb \ + kona-v2-qrd.dtb \ + kona-v2-xrfusion.dtb \ + kona-v2-xrfusion-ult.dtb \ + kona-hdk.dtb \ + kona-v2.1-mtp.dtb \ + kona-v2.1-mtp-ws.dtb \ + kona-v2.1-mtp-sa.dtb \ + kona-v2.1-cdp.dtb \ + kona-v2.1-qrd.dtb \ + kona-v2.1-hdk.dtb \ + kona-v2.1-xrfusion.dtb \ + kona-v2.1-xrfusion-ult.dtb \ + qrb5165-iot-rb5.dtb \ + kona-v2.1-iot-rb5.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY_NOT_OEM),y) +dtbo-$(CONFIG_ARCH_LITO) += lito-rumi-overlay.dtbo \ + lito-mtp-overlay.dtbo \ + lito-v2-mtp-overlay.dtbo \ + lito-cdp-overlay.dtbo \ + lito-v2-cdp-overlay.dtbo \ + lito-atp-overlay.dtbo \ + lito-v2-atp-overlay.dtbo \ + lito-v2-atp-lcd-overlay.dtbo \ + lito-qrd-overlay.dtbo \ + lito-v2-qrd-overlay.dtbo \ + orchid-mtp-overlay.dtbo \ + orchid-cdp-overlay.dtbo + +lito-rumi-overlay.dtbo-base := lito.dtb lito-v2.dtb +lito-mtp-overlay.dtbo-base := lito.dtb +lito-v2-mtp-overlay.dtbo-base := lito-v2.dtb +lito-cdp-overlay.dtbo-base := lito.dtb +lito-v2-cdp-overlay.dtbo-base := lito-v2.dtb +lito-atp-overlay.dtbo-base := lito.dtb +lito-v2-atp-overlay.dtbo-base := lito-v2.dtb +lito-v2-atp-lcd-overlay.dtbo-base := lito-v2.dtb +lito-qrd-overlay.dtbo-base := lito.dtb +lito-v2-qrd-overlay.dtbo-base := lito-v2.dtb +orchid-mtp-overlay.dtbo-base := orchid.dtb +orchid-cdp-overlay.dtbo-base := orchid.dtb + +else +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_LITO) += \ + avicii-overlay-dvt.dtbo \ + avicii-overlay-dvt-v2.1.dtbo \ + avicii-overlay-pvt.dtbo \ + avicii-overlay-pvt-v2.1.dtbo + +avicii-overlay-dvt.dtbo-base := lito.dtb +avicii-overlay-dvt-v2.1.dtbo-base := lito.dtb +avicii-overlay-pvt.dtbo-base := lito.dtb +avicii-overlay-pvt-v2.1.dtbo-base := lito.dtb + +else +dtb-$(CONFIG_ARCH_LITO) += lito-rumi.dtb \ + lito-mtp.dtb \ + lito-cdp.dtb \ + lito-atp.dtb \ + lito-qrd.dtb \ + lito-v2-mtp.dtb \ + lito-v2-cdp.dtb \ + lito-v2-atp.dtb \ + lito-v2-atp-lcd.dtb \ + lito-v2-qrd.dtb \ + orchid-mtp.dtb \ + orchid-cdp.dtb +endif +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +dtbo-$(CONFIG_ARCH_LAGOON) += \ + lagoon-rumi-overlay.dtbo \ + lagoon-mtp-overlay.dtbo \ + lagoon-mtp-usbc-overlay.dtbo \ + lagoon-cdp-overlay.dtbo \ + lagoon-atp-overlay.dtbo \ + lagoon-qrd-overlay.dtbo + +lagoon-rumi-overlay.dtbo-base := lagoon.dtb +lagoon-mtp-overlay.dtbo-base := lagoon.dtb +lagoon-mtp-usbc-overlay.dtbo-base := lagoon.dtb +lagoon-cdp-overlay.dtbo-base := lagoon.dtb +lagoon-atp-overlay.dtbo-base := lagoon.dtb +lagoon-qrd-overlay.dtbo-base := lagoon.dtb +else +dtb-$(CONFIG_ARCH_LAGOON) += \ + lagoon-rumi.dtb \ + lagoon-mtp.dtb \ + lagoon-mtp-usbc.dtb \ + lagoon-cdp.dtb \ + lagoon-atp.dtb \ + lagoon-qrd.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_BENGAL) += \ + bengal-rumi-overlay.dtbo \ + bengal-qrd-overlay.dtbo \ + bengal-idp-overlay.dtbo \ + bengal-idp-usbc-overlay.dtbo \ + bengalp-idp-overlay.dtbo \ + bengal-idp-1gb-overlay.dtbo \ + bengal-idp-2gb-overlay.dtbo \ + bengal-idp-usbc-1gb-overlay.dtbo \ + bengal-idp-usbc-2gb-overlay.dtbo \ + bengal-iot-idp-overlay.dtbo \ + bengalp-iot-idp-overlay.dtbo \ + bengal-iot-idp-2gb-overlay.dtbo \ + bengal-iot-idp-usbc-2gb-overlay.dtbo \ + bengal-iot-idp-usbc-overlay.dtbo \ + bengalp-iot-idp-2gb-overlay.dtbo \ + bengalp-iot-idp-usbc-2gb-overlay.dtbo \ + bengalp-iot-idp-usbc-overlay.dtbo + +bengal-rumi-overlay.dtbo-base := bengal.dtb +bengal-qrd-overlay.dtbo-base := bengal.dtb +bengal-idp-overlay.dtbo-base := bengal.dtb +bengal-idp-usbc-overlay.dtbo-base := bengal.dtb +bengalp-idp-overlay.dtbo-base := bengalp.dtb +bengal-idp-1gb-overlay.dtbo-base := bengal-1gb.dtb +bengal-idp-2gb-overlay.dtbo-base := bengal-2gb.dtb +bengal-idp-usbc-1gb-overlay.dtbo-base := bengal-1gb.dtb +bengal-idp-usbc-2gb-overlay.dtbo-base := bengal-2gb.dtb +bengal-iot-idp-overlay.dtbo-base := bengal-iot.dtb +bengalp-iot-idp-overlay.dtbo-base := bengalp-iot.dtb +bengal-iot-idp-2gb-overlay.dtbo-base := bengal-iot-2gb.dtb +bengal-iot-idp-usbc-2gb-overlay.dtbo-base := bengal-iot-2gb.dtb +bengal-iot-idp-usbc-overlay.dtbo-base := bengal-iot.dtb +bengalp-iot-idp-2gb-overlay.dtbo-base := bengalp-iot-2gb.dtb +bengalp-iot-idp-usbc-2gb-overlay.dtbo-base := bengalp-iot-2gb.dtb +bengalp-iot-idp-usbc-overlay.dtbo-base := bengalp-iot.dtb +else +dtb-$(CONFIG_ARCH_BENGAL) += bengal-rumi.dtb \ + bengal-qrd.dtb \ + bengal-idp.dtb \ + bengal-idp-usbc.dtb \ + bengalp-idp.dtb \ + bengal-idp-1gb.dtb \ + bengal-idp-2gb.dtb \ + bengal-idp-usbc-1gb.dtb \ + bengal-idp-usbc-2gb.dtb \ + bengal-iot-idp.dtb \ + bengalp-iot-idp.dtb \ + bengal-iot-idp-2gb.dtb \ + bengal-iot-idp-usbc-2gb.dtb \ + bengal-iot-idp-usbc.dtb \ + bengalp-iot-idp-2gb.dtb \ + bengalp-iot-idp-usbc-2gb.dtb \ + bengalp-iot-idp-usbc.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_SCUBA) += \ + scuba-rumi-overlay.dtbo \ + scuba-idp-overlay.dtbo \ + scuba-idp-usbc-overlay.dtbo \ + scuba-qrd-eldo-overlay.dtbo \ + scuba-qrd-non-eldo-overlay.dtbo \ + scuba-iot-idp-overlay.dtbo \ + scuba-iot-idp-usbc-overlay.dtbo \ + scuba-iot-qrd-eldo-overlay.dtbo \ + scuba-iot-qrd-non-eldo-overlay.dtbo + +scuba-rumi-overlay.dtbo-base := scuba.dtb scubap.dtb scuba-2gb.dtb +scuba-idp-overlay.dtbo-base := scuba.dtb scubap.dtb scuba-2gb.dtb +scuba-qrd-eldo-overlay.dtbo-base := scuba.dtb scubap.dtb scuba-2gb.dtb +scuba-qrd-non-eldo-overlay.dtbo-base := scuba.dtb scubap.dtb scuba-2gb.dtb +scuba-idp-usbc-overlay.dtbo-base := scuba.dtb scubap.dtb scuba-2gb.dtb +scuba-iot-idp-overlay.dtbo-base := scuba-iot.dtb scubap-iot.dtb scuba-iot-2gb.dtb +scuba-iot-qrd-eldo-overlay.dtbo-base := scuba-iot.dtb scubap-iot.dtb scuba-iot-2gb.dtb +scuba-iot-qrd-non-eldo-overlay.dtbo-base := scuba-iot.dtb scubap-iot.dtb scuba-iot-2gb.dtb +scuba-iot-idp-usbc-overlay.dtbo-base := scuba-iot.dtb scubap-iot.dtb scuba-iot-2gb.dtb +else +dtb-$(CONFIG_ARCH_SCUBA) += scuba-rumi.dtb \ + scuba-idp.dtb \ + scuba-idp-usbc.dtb \ + scuba-qrd-eldo.dtb \ + scuba-qrd-non-eldo.dtb \ + scubap-idp.dtb \ + scubap-idp-2gb.dtb \ + scuba-idp-2gb.dtb \ + scuba-idp-usbc-2gb.dtb \ + scuba-iot-idp.dtb \ + scuba-iot-idp-usbc.dtb \ + scubap-iot-idp.dtb \ + scuba-iot-qrd-eldo.dtb \ + scuba-iot-qrd-non-eldo.dtb \ + scubap-iot-idp-2gb.dtb \ + scuba-iot-idp-2gb.dtb \ + scuba-iot-idp-usbc-2gb.dtb +endif + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) + dtbo-$(CONFIG_ARCH_SDM660) += \ + sdm660-mtp-external-codec-overlay.dtbo \ + sdm660-mtp-internal-codec-overlay.dtbo \ + sdm660-cdp-external-codec-overlay.dtbo \ + sdm660-cdp-internal-codec-overlay.dtbo \ + sdm660-qrd-external-codec-overlay.dtbo \ + sdm660-rcm-external-codec-overlay.dtbo \ + sdm660-rcm-internal-codec-overlay.dtbo \ + sda660-mtp-external-codec-overlay.dtbo \ + sda660-cdp-external-codec-overlay.dtbo \ + sda660-rcm-external-codec-overlay.dtbo + +sdm660-mtp-external-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sdm660-mtp-internal-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sdm660-cdp-external-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sdm660-cdp-internal-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sdm660-qrd-external-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sdm660-rcm-external-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sdm660-rcm-internal-codec-overlay.dtbo-base := sdm660-pm660l.dtb + +sda660-mtp-external-codec-overlay.dtbo-base := sda660-pm660l.dtb + +sda660-cdp-external-codec-overlay.dtbo-base := sda660-pm660l.dtb + +sda660-rcm-external-codec-overlay.dtbo-base := sda660-pm660l.dtb +else +dtb-$(CONFIG_ARCH_SDM660) += sdm660-sim.dtb \ +sdm660-internal-codec-cdp.dtb \ + sdm660-internal-codec-mtp.dtb \ + sdm660-internal-codec-rcm.dtb \ + sdm660-cdp.dtb \ + sdm660-mtp.dtb \ + sdm660-qrd.dtb \ + sdm660-rcm.dtb \ + sdm660-pm660a-cdp.dtb \ + sdm660-pm660a-mtp.dtb \ + sdm660-pm660a-qrd.dtb \ + sdm660-pm660a-rcm.dtb \ + sdm660-internal-codec-pm660a-cdp.dtb \ + sdm660-internal-codec-pm660a-mtp.dtb \ + sdm660-internal-codec-pm660a-rcm.dtb \ + sdm660-pm660a-sim.dtb \ + sda660-cdp.dtb \ + sda660-mtp.dtb \ + sda660-rcm.dtb \ + sda660-pm660a-cdp.dtb \ + sda660-pm660a-mtp.dtb \ + sda660-pm660a-rcm.dtb \ + sda660-pm660a-qrd-hdk.dtb \ + sdm660-headset-jacktype-no-cdp.dtb \ + sdm660-headset-jacktype-no-rcm.dtb \ + sdm660-pm660a-headset-jacktype-no-cdp.dtb \ + sdm660-pm660a-headset-jacktype-no-rcm.dtb \ + sdm660-usbc-audio-mtp.dtb \ + sdm660-usbc-audio-rcm.dtb +endif + +always := $(dtb-y) +subdir-y := $(dts-dirs) +clean-files := *.dtb *.dtbo diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-dvt-v2.1.dtsi b/arch/arm64/boot/dts/vendor/qcom/avicii-dvt-v2.1.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..c011785d892ed1c1a0dec156ce8c1c8d984a5063 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-dvt-v2.1.dtsi @@ -0,0 +1 @@ +/*this is for one project different hw version */ diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-dvt.dtsi b/arch/arm64/boot/dts/vendor/qcom/avicii-dvt.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..c011785d892ed1c1a0dec156ce8c1c8d984a5063 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-dvt.dtsi @@ -0,0 +1 @@ +/*this is for one project different hw version */ diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-dvt-v2.1.dts b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-dvt-v2.1.dts new file mode 100755 index 0000000000000000000000000000000000000000..de4f07a0510181246816066ccff15fe7236dd602 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-dvt-v2.1.dts @@ -0,0 +1,24 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-mtp.dtsi" + +#include "avicii.dtsi" +#include "avicii-dvt-v2.1.dtsi" +#include "camera/lito-oem-camera-avicii.dtsi" /* Camera may use same hardware */ + + +/ { + model = "Qualcomm Technologies, Inc. Lito MTP dvt V2.1 20801 53"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,board-id = <8 0>; + /*we can add project id to this array,uefi can auto read it,if new project,we add to this array */ + oem,project-id = <20801>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <53>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-dvt.dts b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-dvt.dts new file mode 100755 index 0000000000000000000000000000000000000000..b310720f1a4d52b139018f621d787ea535743ccf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-dvt.dts @@ -0,0 +1,24 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-mtp.dtsi" + +#include "avicii.dtsi" +#include "avicii-dvt.dtsi" +#include "camera/lito-oem-camera-avicii.dtsi" /* Camera may use same hardware */ + + +/ { + model = "Qualcomm Technologies, Inc. Lito MTP dvt 20801 13"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,board-id = <8 0>; + /*we can add project id to this array,uefi can auto read it,if new project,we add to this array */ + oem,project-id = <20801>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <13>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-pvt-v2.1.dts b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-pvt-v2.1.dts new file mode 100755 index 0000000000000000000000000000000000000000..494e13e59af060b16b9c939fdb17458434d08074 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-pvt-v2.1.dts @@ -0,0 +1,24 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-mtp.dtsi" + +#include "avicii.dtsi" +#include "avicii-pvt-v2.1.dtsi" +#include "camera/lito-oem-camera-avicii.dtsi" /* Camera may use same hardware */ + + +/ { + model = "Qualcomm Technologies, Inc. Lito MTP pvt V2.1 20801 54"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,board-id = <8 0>; + /*we can add project id to this array,uefi can auto read it,if new project,we add to this array */ + oem,project-id = <20801>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <54>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-pvt.dts b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-pvt.dts new file mode 100755 index 0000000000000000000000000000000000000000..40d56a3ae5ae85aaf0be0d2a861c380a4a4d2a95 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-overlay-pvt.dts @@ -0,0 +1,24 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-mtp.dtsi" + +#include "avicii.dtsi" +#include "avicii-pvt.dtsi" +#include "camera/lito-oem-camera-avicii.dtsi" /* Camera may use same hardware */ + + +/ { + model = "Qualcomm Technologies, Inc. Lito MTP pvt 20801 14"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,board-id = <8 0>; + /*we can add project id to this array,uefi can auto read it,if new project,we add to this array */ + oem,project-id = <20801>; + /*we can add hw id to this array,uefi can auto read it,if new hw,we add to this array */ + oem,hw-id = <14>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-pvt-v2.1.dtsi b/arch/arm64/boot/dts/vendor/qcom/avicii-pvt-v2.1.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..c011785d892ed1c1a0dec156ce8c1c8d984a5063 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-pvt-v2.1.dtsi @@ -0,0 +1 @@ +/*this is for one project different hw version */ diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii-pvt.dtsi b/arch/arm64/boot/dts/vendor/qcom/avicii-pvt.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..c011785d892ed1c1a0dec156ce8c1c8d984a5063 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii-pvt.dtsi @@ -0,0 +1 @@ +/*this is for one project different hw version */ diff --git a/arch/arm64/boot/dts/vendor/qcom/avicii.dtsi b/arch/arm64/boot/dts/vendor/qcom/avicii.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ebbe5b5ac1c654d56d0932b4578f5c7a12745881 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/avicii.dtsi @@ -0,0 +1,665 @@ +/*this is for different project dtsi*/ +&thermal_zones { + skin-therm { + trips { + skin_trip0: skin-trip0 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_trip1: skin-trip1 { + temperature = <48000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_trip2: skin-trip2 { + temperature = <50000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_trip3: skin-trip3 { + temperature = <52000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + + cooling-maps { + skin_cpu7_cdev0 { + trip = <&skin_trip0>; + /* throttle from fmax to 1766400KHz */ + cooling-device = + <&CPU7 (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu6_cdev0 { + trip = <&skin_trip0>; + /* throttle from fmax to 1728000KHz */ + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + skin_cpu7_cdev1 { + trip = <&skin_trip1>; + /* throttle from fmax to 1401600KHz */ + cooling-device = <&CPU7 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + + skin_cpu6_cdev1 { + trip = <&skin_trip1>; + /* throttle from fmax to 1478400KHz */ + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_gpu_cdev1 { + trip = <&skin_trip1>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + + skin_cpu0_cdev1 { + trip = <&skin_trip2>; + /* throttle from fmax to 864000KHz */ + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu7_cdev2 { + trip = <&skin_trip2>; + /* throttle to close cpu7 */ + cooling-device = <&cpu7_isolate 1 1>; + }; + + skin_cpu6_cdev2 { + trip = <&skin_trip2>; + /* throttle to close cpu6 */ + cooling-device = <&cpu6_isolate 1 1>; + }; + + skin_cpu5_cdev2 { + trip = <&skin_trip2>; + /* throttle to close cpu5 */ + cooling-device = <&cpu5_isolate 1 1>; + }; + + skin_cpu4_cdev2 { + trip = <&skin_trip2>; + /* throttle to close cpu4 */ + cooling-device = <&cpu4_isolate 1 1>; + }; + + skin_cpu0_cdev3 { + trip = <&skin_trip3>; + /* throttle from fmax to 614400KHz */ + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + }; + }; + + msm-therm { + trips { + msm_trip0: msm-trip0 { + temperature = <55000>; + hysteresis = <2000>; + type = "passive"; + }; + + msm_trip1: msm-trip1 { + temperature = <57000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + + cooling-maps { + msm_cpu7_cdev0 { + trip = <&msm_trip0>; + /* throttle from fmax to 2304000KHz */ + cooling-device = + <&CPU7 (THERMAL_MAX_LIMIT-6) + (THERMAL_MAX_LIMIT-6)>; + }; + + msm_cpu6_cdev0 { + trip = <&msm_trip0>; + /* throttle from fmax to 1900800KHz */ + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-5) + (THERMAL_MAX_LIMIT-5)>; + }; + + msm_cpu7_cdev1 { + trip = <&msm_trip1>; + /* throttle from fmax to 1996800KHz */ + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + msm_cpu6_cdev1 { + trip = <&msm_trip1>; + /* throttle from fmax to 1728000KHz */ + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + msm_gpu_cdev1 { + trip = <&msm_trip1>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; +}; + +&tlmm { + oneplus_fastchg { + usb_sw_active: usb_sw_active { + mux { + pins = "gpio4", "gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio126"; + drive-strength = <16>; + bias-pull-down; + }; + }; + + usb_sw_suspend: usb_sw_suspend { + mux { + pins = "gpio4", "gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio126"; + drive-strength = <2>; + bias-disable; + }; + }; + + fastchg_active: fastchg_active { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + fastchg_suspend: fastchg_suspend { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_clk_active: ap_clk_active { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_clk_suspend: ap_clk_suspend { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_data_active: ap_data_active { + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_data_suspend: ap_data_suspend { + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + ab_id0_active: ab_id0_active { + mux { + pins = "gpio58"; + function = "gpio"; + }; + config { + pins = "gpio58"; + drive-strength = <2>; + bias-pull-up; + }; + }; + ab_id0_sleep: ab_id0_sleep { + mux { + pins = "gpio58"; + function = "gpio"; + }; + config { + pins = "gpio58"; + drive-strength = <2>; + bias-disable; + }; + }; + rf_cable_ant1_active: rf_cable_ant1_active { + mux { + pins = "gpio90"; + function = "gpio"; + }; + config { + pins = "gpio90"; + drive-strength = <2>; + bias-pull-up; + }; + }; + rf_cable_ant2_active: rf_cable_ant2_active { + mux { + pins = "gpio66"; + function = "gpio"; + }; + config { + pins = "gpio66"; + drive-strength = <2>; + bias-pull-up; + }; + }; + rf_cable_ant3_active: rf_cable_ant3_active { + mux { + pins = "gpio67"; + function = "gpio"; + }; + config { + pins = "gpio67"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; +/* @bsp, 2019/07/08 Battery & Charging porting END */ + +&qupv3_se11_i2c { + status = "ok"; + qcom,clk-freq-out = <100000>; + bq27541_battery:bq27541-battery@55 { + status = "ok"; + compatible = "ti,bq27541-battery"; + reg = <0x55>; + qcom,modify-soc-smooth; + qcom,battery-full-param;//only for wite battery full param in guage dirver probe on 7250 platform + op,bat-4p45v; + }; + + oneplus_fastchg@26{ + status = "ok"; + compatible = "microchip,oneplus_fastchg"; + reg = <0x26>; + microchip,mcu-en-gpio = <&tlmm 24 0x00>; + microchip,usb-sw-1-gpio = <&tlmm 4 0x00>; + microchip,usb-sw-2-gpio = <&tlmm 126 0x00>; + microchip,ap-clk = <&tlmm 44 0x00>; + microchip,ap-data = <&tlmm 45 0x00>; + + pinctrl-names = "mux_fastchg_active", + "mux_fastchg_suspend", + "mcu_data_read", + "mcu_data_write"; + pinctrl-0 = <&fastchg_active + &usb_sw_active + &ap_clk_active>; + pinctrl-1 = <&usb_sw_suspend + &fastchg_suspend + &ap_clk_suspend>; + pinctrl-2 =<&ap_data_active>; + pinctrl-3 =<&ap_data_suspend>; + op,fw-erase-count = <384>; + op,fw-addr-low = <0x88>; + op,fw-addr-high = <0>; + op,4115mAh_4p45_support; + op,mcl_verion; + }; +}; + +&pm7250b_gpios { + pm8150b_charger { + ship_mode_default: ship_mode_default { + pins = "gpio4"; + function = "normal"; + power-source = <0>; + bias-disable; + input-disable; + }; + }; +}; + + +&pm7250b_charger { + qcom,dc-icl-ua = <1200000>; + qcom,fcc-max-ua = <2000000>; + qcom,usb-icl-ua = <1800000>; + qcom,fv-max-uv = <4365000>; + /* ibatmax setting for different temp regions */ + ibatmax-little-cold-ma = <350>; + ibatmax-cool-ma = <2000>; + ibatmax-little-cool-ma = <2000>; + ibatmax-pre-normal-ma = <2000>; + ibatmax-normal-ma = <2000>; + ibatmax-warm-ma = <1150>; + ibatmax-little-cool-thr-ma = <1900>; + ibatmax-cool-thr-ma = <1150>; + /* vbatmax setting for different temp regions */ + vbatmax-little-cold-mv = <3975>; + vbatmax-cool-mv = <4435>; + vbatmax-little-cool-mv = <4435>; + vbatmax-pre-normal-mv = <4435>; + vbatmax-normal-mv = <4435>; + vbatmax-warm-mv = <4130>; + little-cool-vbat-thr-mv = <4180>; + cool-vbat-thr-mv = <4180>; + /* vbatdet setting for different temp regions */ + vbatdet-little-cold-mv = <3675>; + vbatdet-cool-mv = <4235>; + vbatdet-little-cool-mv = <4335>; + vbatdet-pre-normal-mv = <4335>; + vbatdet-normal-mv = <4335>; + vbatdet-warm-mv = <4030>; + /* temp region settings */ + cold-bat-decidegc = <20>; + little-cold-bat-decidegc = <0>; + cool-bat-decidegc = <50>; + little-cool-bat-decidegc = <120>; + pre-normal-bat-decidegc = <160>; + warm-bat-decidegc = <450>; + hot-bat-decidegc = <500>; + qcom,otg-cl-ua = <1500000>; + op,sw-iterm-ma = <310>; + op,sw-check-full-enable; + qcom,op-pps-usbpd-detection = <&pm7250b_pdphy>; + /*ffc temp region*/ + ffc-pre-normal-decidegc = <120>; + ffc-normal-decidegc = <350>; + ffc-warm-decidegc = <400>; + ffc-normal-fcc-ma = <1050>; + ffc-warm-fcc-ma = <1100>; + ffc-normal-cutoff-ma = <950>; + ffc-warm-cutoff-ma = <1000>; + ffc-full-vbat-mv = <4480>; + + /* skin thermal temp adjust the dash current */ + op,skin-thermal-high-threshold-disp-off = <42>; + op,skin-thermal-pre-high-threshold-disp-off = <38>; + op,skin-thermal-medium-threshold-disp-off = <39>; + op,skin-thermal-normal-threshold-disp-off = <37>; + + op,skin-thermal-high-threshold-disp-on = <40>; + op,skin-thermal-pre-high-threshold-disp-on = <39>; + op,skin-thermal-little-high-threshold-disp-on = <38>; + op,skin-thermal-pre-little-high-threshold-disp-on = <37>; + op,skin-thermal-medium-threshold-disp-on = <36>; + op,skin-thermal-normal-threshold-disp-on = <35>; + op,enable-dash-current-dynamic-adjust; + + /* skin thermal temp adjust the pd current */ + op,pd-skin-thermal-high-threshold = <40>; + op,pd-skin-thermal-normal-threshold = <38>; + op,pd-skin-thermal-medium-threshold = <39>; + op,pd-skin-thermal-pre-high-threshold = <39>; + op,enable-pd-current-dynamic-adjust; + + /delete-property/ qcom,sw-jeita-enable; + + /*otg low battery current limit*/ + op,otg-icl-ctrl-enable; + otg-low-battery-thr = <15>; + otg-low-bat-icl-thr = <1000000>; + otg-normal-bat-icl-thr = <1500000>; + + /* for usb connecter temperature check */ + op,normal-check-interval-period = <300>; + op,fast-check-interval-period = <50>; + op,fast-check-threshold-temp = <33>; + op,high-temp-short-check-timeout = <1500>; + op,first-protect-connecter-temp = <60>; + op,second-protect-connecter-temp = <45>; + op,second-protect-interval-temp = <14>; + op,third-protect-rise-rate = <3>; + op,third-protect-loop-temp = <40>; + op,third-protect-interval-temp = <8>; + op,third-protect-base-temp = <20>; + + /* for charge current&voltage curve optimize */ + op,fv-offset-voltage-mv = <50>; + + /* for 4p45v not charge full issue add sw full count numb */ + op,full-count-sw-numb = <2>; + + /* other settings */ + /*disable lpd*/ + qcom,lpd-disable; + qcom,cutoff-voltage-with-charger = <3250>; + qcom,msm-bus,name = "dash_clk_vote"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <1 731 0 300000000>, + <1 731 0 0>; + + /*usb connector hw auto detection*/ + op,usb-check = <&tlmm 68 0x00>; + + /* for external ship mode suppot */ + op,stm-ctrl-gpio = <&pm7250b_gpios 4 0x00>; + pinctrl-names = "op_ship_mode_default", + "op_usb_temp_adc_default", + "op_usb_temp_adc_sec"; + + pinctrl-0 = <&ship_mode_default>; + pinctrl-1 = <&usb_tem1_adc_gpio_default>; + pinctrl-2 = <&usb_tem2_adc_gpio_default>; + + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>, + <&pm7250b_vadc ADC_AMUX_THM1_PU2>, + <&pm8150l_vadc ADC_GPIO3_PU2>, + <&pm8150_vadc ADC_GPIO1_PU1>, + <&pm8150l_vadc ADC_GPIO2_PU1>; + + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage", + "skin_temp", + "skin_therm", + "usb_tem1_adc", + "usb_tem2_adc"; + + /* VBUS control config */ + op,vbus-ctrl-gpio = <&pm7250b_gpios 7 GPIO_ACTIVE_LOW>; +}; + + +&spmi_bus { + qcom,pm8150@0 { + qcom,power-on@800 { + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x5 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "kpdpwr", "resin", "kpdpwr-resin-bark"; + qcom,s3-src = "kpdpwr-and-resin"; + + qcom,pon_1 { + qcom,support-reset = <0>; + qcom,s1-timer = <6720>; + qcom,s2-timer = <2000>; + qcom,s2-type = ; + qcom,pull-up; + }; + + qcom,pon_2 { + qcom,support-reset = <0>; + qcom,s1-timer = <6720>; + qcom,s2-timer = <2000>; + qcom,s2-type = ; + qcom,pull-up; + }; + + qcom,pon_3 { + qcom,pon-type = ; + qcom,support-reset = <0>; + qcom,s1-timer = <6720>; + qcom,s2-timer = <2000>; + qcom,s2-type = ; + qcom,pull-up; + }; + }; + }; +}; + +&soc { + fingerprint_detect:fingerprint_detect { + oneplus,20801; + compatible = "oneplus,fpdetect"; + fp-gpio-id0 = <&tlmm 65 0>; + pinctrl-names = "fp_id_init"; + pinctrl-0 = <&fp_id0_init >; + }; + + goodix_fp { + compatible = "goodix,fingerprint"; + interrupt-parent = <&tlmm>; + fp-gpio-irq = <&tlmm 112 0x00>; + fp-gpio-reset = <&tlmm 63 0x00>; + fp-gpio-enable = <&pm8150_gpios 7 0x00>; + fp-gpio-1v8 = <&pm8150_gpios 6 0x00 >; + ldo-supply = <&pm8150a_l9>; // pm660l_l5 for goodix_fp + pinctrl-names = "fp_en_init","fp_dis_init"; + pinctrl-0 = <&fp_vdd_init &fp_1v8_init &fp_irq_init>; /*high*/ + pinctrl-1 = <&fp_vdd_dis_init &fp_1v8_dis_init>; /*low*/ + gpios = <&pm8150_gpios 7 0x00>, + <&pm8150_gpios 6 0x00 >, + <&tlmm 112 0x00>; + status = "okay"; + }; + + oem_aboard_check:oem_aboard_check { + compatible = "oem,aboard"; + interrupt-parent = <&tlmm>; + oem,aboard-gpio-0 = <&tlmm 58 0>; + pinctrl-names = "oem_aboard_active","oem_aboard_sleep"; + pinctrl-0 = <&ab_id0_active>; + pinctrl-1 = <&ab_id0_sleep>; + }; + + bootloader_log { + compatible = "bootloader_log"; + linux,contiguous-region = <&bootloader_log_mem>; + }; + oem_rf_cable:oem_rf_cable { + compatible = "oem,rf_cable"; + interrupt-parent = <&tlmm>; + rf,cable-gpio-0 = <&tlmm 90 0>; + rf,cable-gpio-1 = <&tlmm 66 0>; + rf,cable-gpio-2 = <&tlmm 67 0>; + rf,cable-support-timer = <0>; + oem,rf_uevent_feature_enable; + pinctrl-names = "oem_rf_cable_active"; + pinctrl-0 = <&rf_cable_ant1_active &rf_cable_ant2_active &rf_cable_ant3_active>; + }; +}; + +&reserved_memory { + param_mem: param_mem@0xCC200000 { + reg = <0 0xCC200000 0 0x00100000>; + label = "param_mem"; + }; + + ramoops: ramoops@0xCBE00000 { + compatible = "ramoops"; + reg = <0 0xCBE00000 0 0x00400000>; + record-size = <0x40000>; //256x1024 + console-size = <0x40000>; + ftrace-size = <0x40000>; + pmsg-size= <0x200000>; + devinfo-size= <0x01000>; + ecc-size= <0x0>; + }; + + mtp_mem: mtp_mem@cc300000 { + reg = <0 0xCC300000 0 0x00B00000>; + label = "mtp_mem"; + }; + + bootloader_log_mem: bootloader_log_mem@0x0xB7E00000 { + reg = <0 0xB7E00000 0 0x00008000>; + label = "bootloader_log_mem"; + }; +}; + +&wdog{ + qcom,bark-time = <15000>; +}; + +/* @bsp, 2019/10/08 usb config START*/ +&usb2_phy0 { + qcom,param-override-seq = + <0x47 0x6c /*Disconnection voltage +21.56%*/ + 0x1e 0x70 /*Pre-emphasis:4x DC voltage level:+17.80%*/ + 0x37 0x74>; +}; +/* @bsp, 2019/10/08 usb config END*/ diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-1gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..e21f6863fe8f12584f055ebf6e122e28fdf2ae49 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-1gb.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengal-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal 1Gb DDR HD+ SoC"; + compatible = "qcom,bengal"; + qcom,board-id = <0 0x303>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..b4c7dda1900334a6adb78a0caaa2298994b9bf1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-2gb.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengal-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal 2Gb DDR HD+ SoC"; + compatible = "qcom,bengal"; + qcom,board-id = <0 0x403>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-audio-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..29025c620ed19a51c5477a0d6b77ac4d60d7a8ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-audio-overlay.dtsi @@ -0,0 +1,343 @@ +#include +#include +#include +#include + +&bolero { + qcom,num-macros = <3>; + qcom,bolero-version = <5>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x0a5640d8>; + qcom,va_mclk_mode_muxsel = <0x0a7a0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", "rx_npl_clk", + "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; + + tx_macro: tx-macro@a620000 { + compatible = "qcom,tx-macro"; + reg = <0xa620000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-dmic-sample-rate = <2400000>; + qcom,is-used-swr-gpio = <0>; + }; + + rx_macro: rx-macro@a600000 { + compatible = "qcom,rx-macro"; + reg = <0xa600000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x0a5640d8>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr1: rx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <2>; + qcom,swrm-hctl-reg = <0x0a6a9098>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0xa610000 0x0>; + interrupts = <0 297 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x1>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,disable-div2-clk-switch = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd937x_rx_slave: wcd937x-rx-slave { + compatible = "qcom,wcd937x-slave"; + reg = <0x0A 0x01170224>; + }; + }; + }; + + va_macro: va-macro@a730000 { + compatible = "qcom,va-macro"; + reg = <0xa730000 0x0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,va-dmic-sample-rate = <600000>; + qcom,va-clk-mux-select = <1>; + qcom,va-island-mode-muxsel = <0x0a7a0000>; + qcom,default-clk-id = ; + qcom,is-used-swr-gpio = <1>; + qcom,va-swr-gpios = <&va_swr_gpios>; + swr0: va_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <3>; + qcom,swrm-hctl-reg = <0x0a7ec100>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0xa740000 0x0>; + interrupts = + <0 296 IRQ_TYPE_LEVEL_HIGH>, + <0 79 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-wakeup-required = <1>; + qcom,swr-num-ports = <3>; + qcom,swr-port-mapping = <1 ADC1 0x1>, <1 ADC2 0x2>, + <1 ADC3 0x4>, <1 ADC4 0x8>, + <2 DMIC0 0x1>, <2 DMIC1 0x2>, + <2 DMIC2 0x4>, <2 DMIC3 0x8>, + <3 DMIC4 0x1>, <3 DMIC5 0x2>, + <3 DMIC6 0x4>, <3 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + qcom,swr-mstr-irq-wakeup-capable = <1>; + wcd937x_tx_slave: wcd937x-tx-slave { + compatible = "qcom,wcd937x-slave"; + reg = <0x0A 0x01170223>; + }; + }; + }; + + wcd937x_codec: wcd937x-codec { + compatible = "qcom,wcd937x-codec"; + qcom,split-codec = <1>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 DMIC0>, <1 ADC3 0x2 0 DMIC1>, + <2 DMIC0 0x1 0 DMIC4>, <2 DMIC1 0x2 0 DMIC5>, + <2 MBHC 0x4 0 DMIC6>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd937x_rst_gpio>; + qcom,rx-slave = <&wcd937x_rx_slave>; + qcom,tx-slave = <&wcd937x_tx_slave>; + + cdc-vdd-rxtx-supply = <&L9A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <10000>; + + cdc-vddpx-supply = <&L9A>; + qcom,cdc-vddpx-voltage = <1800000 1800000>; + qcom,cdc-vddpx-current = <20000>; + + cdc-vdd-buck-supply = <&L14A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddpx"; + qcom,cdc-on-demand-supplies = "cdc-vdd-buck"; + }; + +}; + +&bengal_snd { + qcom,model = "bengal-idp-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,va-bolero-codec = <1>; + qcom,rxtx-bolero-codec = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "TX DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "TX DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "TX DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "TX DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "SpkrMono WSA_IN", "AUX", + "TX SWR_MIC0", "ADC1_OUTPUT", + "TX SWR_MIC4", "ADC2_OUTPUT", + "TX SWR_MIC5", "ADC3_OUTPUT", + "TX SWR_MIC8", "DMIC1_OUTPUT", + "TX SWR_MIC9", "DMIC2_OUTPUT", + "TX SWR_MIC8", "DMIC3_OUTPUT", + "TX SWR_MIC9", "DMIC4_OUTPUT", + "TX SWR_MIC10", "DMIC5_OUTPUT", + "TX SWR_MIC11", "DMIC6_OUTPUT", + "TX SWR_MIC0", "VA_TX_SWR_CLK", + "TX SWR_MIC1", "VA_TX_SWR_CLK", + "TX SWR_MIC2", "VA_TX_SWR_CLK", + "TX SWR_MIC3", "VA_TX_SWR_CLK", + "TX SWR_MIC4", "VA_TX_SWR_CLK", + "TX SWR_MIC5", "VA_TX_SWR_CLK", + "TX SWR_MIC6", "VA_TX_SWR_CLK", + "TX SWR_MIC7", "VA_TX_SWR_CLK", + "TX SWR_MIC8", "VA_TX_SWR_CLK", + "TX SWR_MIC9", "VA_TX_SWR_CLK", + "TX SWR_MIC10", "VA_TX_SWR_CLK", + "TX SWR_MIC11", "VA_TX_SWR_CLK", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "TX_AIF1 CAP", "VA_TX_SWR_CLK", + "TX_AIF2 CAP", "VA_TX_SWR_CLK", + "TX_AIF3 CAP", "VA_TX_SWR_CLK", + "VA DMIC0", "VA MIC BIAS1", + "VA DMIC1", "VA MIC BIAS1", + "VA DMIC2", "VA MIC BIAS3", + "VA DMIC3", "VA MIC BIAS3", + "VA MIC BIAS1", "Digital Mic0", + "VA MIC BIAS1", "Digital Mic1", + "VA MIC BIAS3", "Digital Mic2", + "VA MIC BIAS3", "Digital Mic3", + "VA SWR_MIC0", "ADC1_OUTPUT", + "VA SWR_MIC4", "ADC2_OUTPUT", + "VA SWR_MIC5", "ADC3_OUTPUT", + "VA SWR_MIC8", "DMIC1_OUTPUT", + "VA SWR_MIC9", "DMIC2_OUTPUT", + "VA SWR_MIC8", "DMIC3_OUTPUT", + "VA SWR_MIC9", "DMIC4_OUTPUT", + "VA SWR_MIC10", "DMIC5_OUTPUT", + "VA SWR_MIC11", "DMIC6_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + + nvmem-cells = <&adsp_variant>; + nvmem-cell-names = "adsp_variant"; + + asoc-codec = <&stub_codec>, <&bolero>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_i2c_e>; + qcom,wsa-aux-dev-prefix = "SpkrMono"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd937x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&bolero>, + <&lpi_tlmm>; +}; + +&qupv3_se1_i2c { + wsa881x_i2c_e: wsa881x-i2c-codec@e { + compatible = "qcom,wsa881x-i2c-codec"; + reg = <0x0e>; + clock-names = "wsa_mclk"; + clocks = <&wsa881x_analog_clk 0>; + qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>; + qcom,wsa-analog-reset-gpio = <&wsa881x_analog_reset_gpio>; + }; + + wsa881x_i2c_44: wsa881x-i2c-codec@44 { + compatible = "qcom,wsa881x-i2c-codec"; + reg = <0x044>; + }; +}; + +&soc { + wcd937x_rst_gpio: msm_cdc_pinctrl@92 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd937x_reset_active>; + pinctrl-1 = <&wcd937x_reset_sleep>; + }; + + wsa881x_analog_reset_gpio: msm_cdc_pinctrl@106 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa881x_analog_clk: wsa_ana_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <9600000>; + qcom,codec-lpass-clk-id = <0x301>; + #clock-cells = <1>; + }; + + clock_audio_rx_1: rx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30E>; + #clock-cells = <1>; + }; + + clock_audio_rx_2: rx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30F>; + #clock-cells = <1>; + }; + + clock_audio_tx_1: tx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30C>; + #clock-cells = <1>; + }; + + clock_audio_tx_2: tx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30D>; + #clock-cells = <1>; + }; + + clock_audio_va_1: va_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30B>; + #clock-cells = <1>; + }; + + clock_audio_va_2: va_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x310>; + #clock-cells = <1>; + }; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <1>; +}; + +&adsp_loader { + nvmem-cells = <&adsp_variant>; + nvmem-cell-names = "adsp_variant"; + adsp-fw-names = "adsp2"; + adsp-fw-bit-values = <0x1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0bffa0ead7b16871d66267f28765dfaa9b0498d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-audio.dtsi @@ -0,0 +1,185 @@ +#include +#include "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x01c1 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + + lpass_audio_hw_vote: vote_lpass_audio_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + }; +}; + +#include "bengal-lpi.dtsi" + +&q6core { + cdc_dmic01_gpios: cdc_dmic01_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic01_clk_active &cdc_dmic01_data_active>; + pinctrl-1 = <&cdc_dmic01_clk_sleep &cdc_dmic01_data_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic23_gpios: cdc_dmic23_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic23_clk_active &cdc_dmic23_data_active>; + pinctrl-1 = <&cdc_dmic23_clk_sleep &cdc_dmic23_data_sleep>; + qcom,lpi-gpios; + }; + + rx_swr_gpios: rx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&rx_swr_clk_active &rx_swr_data_active + &rx_swr_data1_active>; + pinctrl-1 = <&rx_swr_clk_sleep &rx_swr_data_sleep + &rx_swr_data1_sleep>; + qcom,lpi-gpios; + }; + + va_swr_gpios: va_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tx_swr_clk_active &tx_swr_data1_active + &tx_swr_data2_active>; + pinctrl-1 = <&tx_swr_clk_sleep &tx_swr_data1_sleep + &tx_swr_data2_sleep>; + qcom,lpi-gpios; + qcom,chip-wakeup-reg = <0x003ca04c>; + qcom,chip-wakeup-maskbit = <0>; + qcom,chip-wakeup-default-val = <0x1>; + }; + + wsa881x_analog_clk_gpio: msm_cdc_pinctrl@18 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wsa_mclk_active>; + pinctrl-1 = <&wsa_mclk_sleep>; + qcom,lpi-gpios; + }; +}; + +&q6core { + bolero: bolero-cdc { + compatible = "qcom,bolero-codec"; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + }; + + va_macro: va-macro@a730000 { + swr0: va_swr_master { + }; + }; + + rx_macro: rx-macro@a600000 { + swr1: rx_swr_master { + }; + }; + }; +}; + +&q6core { + bengal_snd: sound { + compatible = "qcom,bengal-asoc-snd"; + qcom,mi2s-audio-intf = <0>; + qcom,auxpcm-audio-intf = <0>; + qcom,tdm-audio-intf = <0>; + qcom,wcn-btfm = <1>; + qcom,afe-rxtx-lb = <0>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&proxy_rx>, <&proxy_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&va_cdc_dma_2_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&rx_cdc_dma_6_rx>, <&rx_cdc_dma_7_rx>, + <&afe_loopback_tx>; + asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16401", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45093", + "msm-dai-cdc-dma-dev.45104", + "msm-dai-cdc-dma-dev.45105", + "msm-dai-cdc-dma-dev.45106", + "msm-dai-cdc-dma-dev.45107", + "msm-dai-cdc-dma-dev.45108", + "msm-dai-cdc-dma-dev.45109", + "msm-dai-cdc-dma-dev.45110", + "msm-dai-cdc-dma-dev.45111", + "msm-dai-cdc-dma-dev.45112", + "msm-dai-cdc-dma-dev.45113", + "msm-dai-cdc-dma-dev.45114", + "msm-dai-cdc-dma-dev.45115", + "msm-dai-cdc-dma-dev.45116", + "msm-dai-cdc-dma-dev.45118", + "msm-dai-q6-dev.24577"; + fsa4480-i2c-handle = <&fsa4480>; + }; +}; + +&qupv3_se1_i2c { + status = "ok"; + fsa4480: fsa4480@42 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x42>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-bus.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1932f9d7d20ba38d650fde20342a7b8dad1b48df --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-bus.dtsi @@ -0,0 +1,1081 @@ +#include +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x1880000 0x60200>, + <0x4480000 0x80000>, + <0x1900000 0x8200>, + <0x1880000 0x60200>, + <0x1880000 0x60200>, + <0x1880000 0x60200>, + <0x1880000 0x60200>; + reg-names = "sys_noc-base", "bimc-base", "config_noc-base", + "qup_virt-base", "fab-gpu_vert-base", + "mmnrt_virt-base", "mmrt_virt-base"; + + /*Buses*/ + + fab_bimc: fab-bimc { + cell-id = ; + label = "fab-bimc"; + qcom,fab-dev; + qcom,base-name = "bimc-base"; + qcom,bus-type = <2>; + qcom,util-fact = <153>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc BIMC_MSMBUS_CLK>, + <&rpmcc BIMC_MSMBUS_A_CLK>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc CNOC_MSMBUS_CLK>, + <&rpmcc CNOC_MSMBUS_A_CLK>; + }; + + fab_qup_virt: fab-qup_virt { + cell-id = ; + label = "fab-qup_virt"; + qcom,fab-dev; + qcom,base-name = "qup_virt-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc RPM_SMD_QUP_CLK>, + <&rpmcc RPM_SMD_QUP_A_CLK>; + }; + + fab_sys_noc: fab-sys_noc { + cell-id = ; + label = "fab-sys_noc"; + qcom,fab-dev; + qcom,base-name = "sys_noc-base"; + qcom,bus-type = <3>; + qcom,base-offset = <0x15000>; + qcom,qos-off = <0x1000>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc SNOC_MSMBUS_CLK>, + <&rpmcc SNOC_MSMBUS_A_CLK>; + }; + + fab_gpu_vert: fab-gpu_vert { + cell-id = ; + label = "fab-gpu_vert"; + qcom,vert-dev; + qcom,base-name = "fab-gpu_vert-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + }; + + fab_mmnrt_virt: fab-mmnrt_virt { + cell-id = ; + label = "fab-mmnrt_virt"; + qcom,fab-dev; + qcom,base-name = "mmnrt_virt-base"; + qcom,bus-type = <3>; + qcom,base-offset = <0x15000>; + qcom,qos-off = <0x1000>; + qcom,util-fact = <142>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc CPP_MMNRT_MSMBUS_CLK>, + <&rpmcc CPP_MMNRT_MSMBUS_A_CLK>; + }; + + fab_mmrt_virt: fab-mmrt_virt { + cell-id = ; + label = "fab-mmrt_virt"; + qcom,fab-dev; + qcom,base-name = "mmrt_virt-base"; + qcom,bus-type = <3>; + qcom,base-offset = <0x15000>; + qcom,qos-off = <0x1000>; + qcom,util-fact = <139>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc MDP_MMRT_MSMBUS_CLK>, + <&rpmcc MDP_MMRT_MSMBUS_A_CLK>; + }; + + /*Masters*/ + + mas_apps_proc: mas-apps-proc { + cell-id = ; + label = "mas-apps-proc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_rt: mas-snoc-bimc-rt { + cell-id = ; + label = "mas-snoc-bimc-rt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_nrt: mas-snoc-bimc-nrt { + cell-id = ; + label = "mas-snoc-bimc-nrt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <3>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc: mas-snoc-bimc { + cell-id = ; + label = "mas-snoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <6>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_gpu_cdsp_bimc: mas-gpu-cdsp-bimc { + cell-id = ; + label = "mas-gpu-cdsp-bimc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <1>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_tcu_0: mas-tcu-0 { + cell-id = ; + label = "mas-tcu-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <6>; + qcom,prio-rd = <6>; + qcom,prio-wr = <6>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_cnoc: mas-snoc-cnoc { + cell-id = ; + label = "mas-snoc-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_qhs_tlmm_south + &slv_qhs_camera_rt_throttle_cfg + &slv_qhs_cdsp_throttle_cfg + &slv_srvc_cnoc &slv_qhs_sdc2 + &slv_qhs_sdc1 + &slv_qhs_qm_cfg &slv_qhs_tlmm_east + &slv_qhs_bimc_cfg &slv_qhs_usb3 + &slv_qhs_qm_mpu_cfg + &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_tlmm_west &slv_qhs_qdss_cfg + &slv_qhs_pdm &slv_qhs_ipa_cfg + &slv_qhs_display_throttle_cfg &slv_qhs_tcsr + &slv_qhs_mesg_ram + &slv_qhs_pmic_arb + &slv_qhs_lpass + &slv_qhs_disp_ss_cfg + &slv_qhs_venus_cfg + &slv_qhs_gpu_cfg + &slv_qhs_imem_cfg &slv_snoc_cfg + &slv_qhs_ufs_mem_cfg + &slv_qhs_venus_throttle_cfg + &slv_qhs_prng + &slv_qhs_vsense_ctrl_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_qup0 + &slv_qhs_camera_ss_cfg &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_dap: mas-xm-dap { + cell-id = ; + label = "mas-xm-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_qhs_tlmm_south + &slv_qhs_camera_rt_throttle_cfg + &slv_qhs_cdsp_throttle_cfg + &slv_srvc_cnoc &slv_qhs_sdc2 + &slv_qhs_sdc1 + &slv_qhs_qm_cfg &slv_qhs_tlmm_east + &slv_qhs_bimc_cfg &slv_qhs_usb3 + &slv_qhs_qm_mpu_cfg + &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_tlmm_west &slv_qhs_qdss_cfg + &slv_qhs_pdm &slv_qhs_ipa_cfg + &slv_qhs_display_throttle_cfg &slv_qhs_tcsr + &slv_qhs_mesg_ram + &slv_qhs_pmic_arb + &slv_qhs_lpass + &slv_qhs_disp_ss_cfg + &slv_qhs_venus_cfg + &slv_qhs_gpu_cfg + &slv_qhs_imem_cfg &slv_snoc_cfg + &slv_qhs_ufs_mem_cfg + &slv_qhs_venus_throttle_cfg + &slv_qhs_prng + &slv_qhs_vsense_ctrl_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_qup0 + &slv_qhs_camera_ss_cfg &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,mas-rpm-id = ; + }; + + mas_crypto_c0: mas-crypto-c0 { + cell-id = ; + label = "mas-crypto-c0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <22>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc CRYPTO_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc CRYPTO_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qup_core_master_0: mas-qup-core-master-0 { + cell-id = ; + label = "mas-qup-core-master-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup_core_slave_0>; + qcom,bus-dev = <&fab_qup_virt>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_cfg: mas-snoc-cfg { + cell-id = ; + label = "mas-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qhm_tic: mas-qhm-tic { + cell-id = ; + label = "mas-qhm-tic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_snoc_bimc &slv_snoc_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_anoc_snoc: mas-anoc-snoc { + cell-id = ; + label = "mas-anoc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_snoc_bimc + &slv_snoc_cnoc &slv_xs_sys_tcu_cfg + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_camera_nrt: mas-qnm-camera-nrt { + cell-id = ; + label = "mas-qnm-camera-nrt"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_snoc_bimc_nrt>; + qcom,prio = <3>; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_camera_rt: mas-qnm-camera-rt { + cell-id = ; + label = "mas-qnm-camera-rt"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <10>; + qcom,qos-mode = "fixed"; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_rt>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_mmrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_bimc_snoc: mas-bimc-snoc { + cell-id = ; + label = "mas-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_snoc_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <5>; + qcom,qos-mode = "fixed"; + qcom,prio = <2>; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_rt>; + qcom,bus-dev = <&fab_mmrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <20>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_qxs_imem &slv_snoc_bimc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_venus0: mas-qxm-venus0 { + cell-id = ; + label = "mas-qxm-venus0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <9>; + qcom,qos-mode = "fixed"; + qcom,prio = <3>; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_nrt>; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_venus_cpu: mas-qxm-venus-cpu { + cell-id = ; + label = "mas-qxm-venus-cpu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <13>; + qcom,qos-mode = "fixed"; + qcom,prio = <4>; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_nrt>; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qhm_qup0: mas-qhm-qup0 { + cell-id = ; + label = "mas-qhm-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc QUP0_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc QUP0_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <3>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <12>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_sdc1: mas-xm-sdc1 { + cell-id = ; + label = "mas-xm-sdc1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <17>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc SDC1_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc SDC1_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <23>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc SDC2_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc SDC2_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <25>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc RPM_SMD_SNOC_LPASS_CLK>, + <&rpmcc RPM_SMD_SNOC_LPASS_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <24>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_gpu_qos: mas-qnm-gpu-qos { + cell-id = ; + label = "mas-qnm-gpu-qos"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <16>; + qcom,qos-mode = "fixed"; + qcom,bus-dev = <&fab_sys_noc>; + qcom,prio = <0>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_gpu: mas-qnm-gpu { + cell-id = ; + label = "mas-qnm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_gpu_cdsp_bimc>; + qcom,bus-dev = <&fab_gpu_vert>; + qcom,mas-rpm-id = ; + }; + + /*Slaves*/ + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_bimc_snoc:slv-bimc-snoc { + cell-id = ; + label = "slv-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,connections = <&mas_bimc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_bimc_cfg:slv-qhs-bimc-cfg { + cell-id = ; + label = "slv-qhs-bimc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_camera_nrt_throttle_cfg:slv-qhs-camera-nrt-throtle-cfg { + cell-id = ; + label = "slv-qhs-camera-nrt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_camera_rt_throttle_cfg:slv-qhs-camera-rt-throttle-cfg { + cell-id = ; + label = "slv-qhs-camera-rt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_camera_ss_cfg:slv-qhs-camera-ss-cfg { + cell-id = ; + label = "slv-qhs-camera-ss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_cdsp_throttle_cfg:slv-qhs-cdsp-throttle-cfg { + cell-id = ; + label = "slv-qhs-cdsp-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_disp_ss_cfg:slv-qhs-disp-ss-cfg { + cell-id = ; + label = "slv-qhs-disp-ss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_display_throttle_cfg:slv-qhs-display-throttle-cfg { + cell-id = ; + label = "slv-qhs-display-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_gpu_cfg:slv-qhs-gpu-cfg { + cell-id = ; + label = "slv-qhs-gpu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_ipa_cfg:slv-qhs-ipa-cfg { + cell-id = ; + label = "slv-qhs-ipa-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_lpass:slv-qhs-lpass { + cell-id = ; + label = "slv-qhs-lpass"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_mesg_ram:slv-qhs-mesg-ram { + cell-id = ; + label = "slv-qhs-mesg-ram"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pmic_arb:slv-qhs-pmic-arb { + cell-id = ; + label = "slv-qhs-pmic-arb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qm_cfg:slv-qhs-qm-cfg { + cell-id = ; + label = "slv-qhs-qm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qm_mpu_cfg:slv-qhs-qm-mpu-cfg { + cell-id = ; + label = "slv-qhs-qm-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qup0:slv-qhs-qup0 { + cell-id = ; + label = "slv-qhs-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_sdc1:slv-qhs-sdc1 { + cell-id = ; + label = "slv-qhs-sdc1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cfg:slv-snoc-cfg { + cell-id = ; + label = "slv-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_snoc_cfg>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_tlmm_east:slv-qhs-tlmm-east { + cell-id = ; + label = "slv-qhs-tlmm-east"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_tlmm_south:slv-qhs-tlmm-south { + cell-id = ; + label = "slv-qhs-tlmm-south"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_tlmm_west:slv-qhs-tlmm-west { + cell-id = ; + label = "slv-qhs-tlmm-west"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg { + cell-id = ; + label = "slv-qhs-ufs-mem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_usb3:slv-qhs-usb3 { + cell-id = ; + label = "slv-qhs-usb3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_venus_throttle_cfg:slv-qhs-venus-throttle-cfg { + cell-id = ; + label = "slv-qhs-venus-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qup_core_slave_0:slv-qup-core-slave-0 { + cell-id = ; + label = "slv-qup-core-slave-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_qup_virt>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_nrt:slv-snoc-bimc-nrt { + cell-id = ; + label = "slv-snoc-bimc-nrt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,connections = <&mas_snoc_bimc_nrt>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_rt:slv-snoc-bimc-rt { + cell-id = ; + label = "slv-snoc-bimc-rt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mmrt_virt>; + qcom,connections = <&mas_snoc_bimc_rt>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cnoc:slv-snoc-cnoc { + cell-id = ; + label = "slv-snoc-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,qos-mode = "fixed"; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,connections = <&mas_snoc_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc:slv-snoc-bimc { + cell-id = ; + label = "slv-snoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,connections = <&mas_snoc_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_anoc_snoc:slv-anoc-snoc { + cell-id = ; + label = "slv-anoc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,connections = <&mas_anoc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_gpu_cdsp_bimc:slv-gpu-cdsp-bimc { + cell-id = ; + label = "slv-gpu-cdsp-bimc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gpu_vert>; + qcom,connections = <&mas_gpu_cdsp_bimc>; + qcom,slv-rpm-id = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-coresight.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c5b6c25a5cc8fb55a5fa36bf6c95ab08dccad20f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-coresight.dtsi @@ -0,0 +1,1765 @@ +&soc { + hwevent { + compatible = "qcom,coresight-hwevent"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + apss_tgu: tgu@9900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x09900000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <8>; + tgu-timer-counters = <8>; + interrupts = <0 53 1>, <0 54 1>, <0 55 1>, <0 56 1>; + coresight-name = "coresight-tgu-apss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + csr: csr@8001000 { + compatible = "qcom,coresight-csr"; + reg = <0x8001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@8a03000 { + compatible = "qcom,coresight-csr"; + reg = <0x8a03000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + + qcom,timestamp-support; + qcom,aodbg-csr-support; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + stm: stm@8002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb962>; + + reg = <0x8002000 0x1000>, + <0xe280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + nvmem-cells = <&stm_debug_fuse>; + nvmem-cell-names = "debug_fuse"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + tpdm_center: tpdm@8b58000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8b58000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dl_ct_out_tpda0: endpoint { + remote-endpoint = + <&tpda0_in_tpdm_dl_ct>; + }; + }; + }; + + tpdm_gpu: tpdm@8940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8940000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gpu"; + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_gpu_out_funnel_gpu: endpoint { + remote-endpoint = + <&funnel_gpu_in_tpdm_gpu>; + }; + }; + }; + + modem_rfxe: modem_rfxe { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-modem-rfxe"; + qcom,dummy-source; + + port { + modem_rxfe_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_rxfe>; + }; + }; + }; + + audio_etm0: audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-audio-etm0"; + + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_audio_etm0>; + }; + }; + }; + + snoc: snoc { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-snoc"; + qcom,dummy-source; + + port { + snoc_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_snoc>; + }; + }; + }; + + tpdm_lpass: tpdm@8a26000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-lpass"; + qcom,dummy-source; + + port { + tpdm_lpass_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpdm_lpass>; + }; + }; + }; + + tpdm_turing: tpdm@8860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + turing_etm0: turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-turing-etm0"; + + qcom,inst-id = <13>; + + port { + turing_etm0_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_turing_etm0>; + }; + }; + }; + + tpdm_vsense: tpdm@8840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_vsense_out_tpda7: endpoint { + remote-endpoint = + <&tpda7_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@8870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + qcom,hw-enable-check; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dcc_out_tpda8: endpoint { + remote-endpoint = + <&tpda8_in_tpdm_dcc>; + }; + }; + }; + + tpdm_prng: tpdm@884c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x884c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_prng_out_tpda10: endpoint { + remote-endpoint = + <&tpda10_in_tpdm_prng>; + }; + }; + }; + + tpdm_qm: tpdm@89d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x89d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_qm_out_tpda12: endpoint { + remote-endpoint = + <&tpda12_in_tpdm_qm>; + }; + }; + }; + + tpdm_west: tpdm@8a58000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8a58000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-west"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_west_out_tpda13: endpoint { + remote-endpoint = + <&tpda13_in_tpdm_west>; + }; + }; + }; + + tpdm_pimem: tpdm@8850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_pimem_out_tpda15: endpoint { + remote-endpoint = + <&tpda15_in_tpdm_pimem>; + }; + }; + }; + + tpdm_mapss: tpdm@8a01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8a01000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mapss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_mapss_out_tpda_mapss: endpoint { + remote-endpoint = + <&tpda_mapss_in_tpdm_mapss>; + }; + }; + }; + + tpdm_wcss: tpdm@899c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_silver_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpdm_wcss_silver>; + }; + }; + }; + + modem_etm0: modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm0"; + + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + etm0: etm@9040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9040000 0x1000>; + cpu = <&CPU0>; + qcom,tupwr-disable; + coresight-name = "coresight-etm0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm0_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm0>; + }; + }; + }; + + etm1: etm@9140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9140000 0x1000>; + cpu = <&CPU1>; + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm1_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm1>; + }; + }; + }; + + etm2: etm@9240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9240000 0x1000>; + cpu = <&CPU2>; + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm2_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm2>; + }; + }; + }; + + etm3: etm@9340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9340000 0x1000>; + cpu = <&CPU3>; + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm3_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm3>; + }; + }; + }; + + etm4: etm@9440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9440000 0x1000>; + cpu = <&CPU4>; + qcom,tupwr-disable; + coresight-name = "coresight-etm4"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm4_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm4>; + }; + }; + }; + + etm5: etm@9540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9540000 0x1000>; + cpu = <&CPU5>; + qcom,tupwr-disable; + coresight-name = "coresight-etm5"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm5_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm5>; + }; + }; + }; + + etm6: etm@9640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9640000 0x1000>; + cpu = <&CPU6>; + qcom,tupwr-disable; + coresight-name = "coresight-etm6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm6_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm6>; + }; + }; + }; + + etm7: etm@9740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9740000 0x1000>; + cpu = <&CPU7>; + qcom,tupwr-disable; + coresight-name = "coresight-etm7"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm7_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm7>; + }; + }; + }; + + tpdm_actpm: tpd@9830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x9830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-actpm"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_actpm_out_tpda_actpm: endpoint { + remote-endpoint = + <&tpda_actpm_in_tpdm_actpm>; + }; + }; + }; + + tpdm_llm_silver: tpdm@98a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x98a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpdm_apss: tpdm@9860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x9860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = + <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + funnel_apss0: funnel@9800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x9800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss0_out_funnel_apss1: endpoint { + remote-endpoint = + <&funnel_apss1_in_funnel_apss0>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss0_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss0>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss0_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss0>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss0_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss0>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss0_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss0>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss0_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss0>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss0_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss0>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss0_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss0>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss0_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss0>; + }; + }; + + }; + }; + + tpda_actpm: tpda@9832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x9832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-actpm"; + + qcom,tpda-atid = <77>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_actpm_out_funnel_apss1: endpoint { + remote-endpoint = + <&funnel_apss1_in_tpda_actpm>; + }; + }; + + port@1 { + reg = <0>; + tpda_actpm_in_tpdm_actpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_actpm_out_tpda_actpm>; + }; + }; + }; + }; + + tpda_apss: tpda@9862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x9862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss1: endpoint { + remote-endpoint = + <&funnel_apss1_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + + tpda_llm_silver: tpda@98c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x98c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss1: endpoint { + remote-endpoint = + <&funnel_apss1_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + + funnel_apss1: funnel@9810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x9810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss1_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss1>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss1_in_funnel_apss0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss0_out_funnel_apss1>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss1_in_tpda_actpm: endpoint { + slave-mode; + remote-endpoint = + <&tpda_actpm_out_funnel_apss1>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss1_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss1>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss1_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss1>; + }; + }; + + }; + }; + + tpda_mapss: tpda@8a04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x8a04000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-mapss"; + + qcom,tpda-atid = <76>; + qcom,cmb-elem-size = <0 32>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_mapss_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpda_mapss>; + }; + }; + + port@1 { + reg = <0>; + tpda_mapss_in_tpdm_mapss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mapss_out_tpda_mapss>; + }; + }; + }; + }; + + funnel_gpu: funnel@8944000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8944000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gpu"; + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_gpu_out_tpda1: endpoint { + remote-endpoint = + <&tpda1_in_funnel_gpu>; + }; + }; + + port@1 { + reg = <0>; + funnel_gpu_in_tpdm_gpu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gpu_out_funnel_gpu>; + }; + }; + + }; + }; + + funnel_turing: funnel@8861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_turing_out_tpda5: endpoint { + remote-endpoint = + <&tpda5_in_funnel_turing>; + source = <&tpdm_turing>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing>; + source = <&turing_etm0>; + }; + }; + + port@2 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + + port@3 { + reg = <1>; + funnel_turing_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing>; + }; + }; + + }; + }; + + tpda: tpda@8004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x8004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,dsb-elem-size = <0 32>, + <1 32>, + <5 32>, + <12 32>, + <13 32>, + <15 32>; + qcom,cmb-elem-size = <7 32>, + <8 32>, + <10 32>, + <15 64>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <0>; + tpda0_in_tpdm_dl_ct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_ct_out_tpda0>; + }; + }; + + port@2 { + reg = <1>; + tpda1_in_funnel_gpu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gpu_out_tpda1>; + }; + }; + + port@3 { + reg = <5>; + tpda5_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda5>; + }; + }; + + port@4 { + reg = <7>; + tpda7_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda7>; + }; + }; + + port@5 { + reg = <8>; + tpda8_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda8>; + }; + }; + + port@6 { + reg = <10>; + tpda10_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda10>; + }; + }; + + port@7 { + reg = <12>; + tpda12_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda12>; + }; + }; + + port@8 { + reg = <13>; + tpda13_in_tpdm_west: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_west_out_tpda13>; + }; + }; + + port@9 { + reg = <15>; + tpda15_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda15>; + }; + }; + + }; + }; + + funnel_qatb: funnel@8005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <6>; + funnel_qatb_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <5>; + funnel_qatb_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_qatb>; + }; + }; + + port@4 { + reg = <5>; + funnel_qatb_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_qatb>; + }; + }; + }; + }; + + funnel_in0: funnel@8041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <5>; + funnel_in0_in_snoc: endpoint { + slave-mode; + remote-endpoint = + <&snoc_out_funnel_in0>; + }; + }; + + port@2 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@3 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = + <&stm_out_funnel_in0>; + }; + }; + + }; + }; + + funnel_in1: funnel@8042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <1>; + funnel_in1_in_tpda_mapss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_mapss_out_funnel_in1>; + }; + }; + + port@2 { + reg = <2>; + funnel_in1_in_modem_rxfe: endpoint { + slave-mode; + remote-endpoint = + <&modem_rxfe_out_funnel_in1>; + }; + }; + + port@3 { + reg = <3>; + funnel_in1_in_tpdm_wcss_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_silver_out_funnel_in1>; + }; + }; + + port@4 { + reg = <4>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + + port@5 { + reg = <6>; + funnel_in1_in_funnel_apss1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss1_out_funnel_in1>; + }; + }; + + }; + }; + + funnel_merg: funnel@8045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + + }; + }; + + tmc_etf: tmc@8047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + reg = <0x8047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etf_out_replicator_qdss: endpoint { + remote-endpoint = + <&replicator_qdss_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + + }; + }; + + replicator_qdss: replicator@8046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + reg = <0x8046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + replicator_qdss_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator_qdss>; + }; + }; + + port@1 { + reg = <0>; + replicator_qdss_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator_qdss>; + }; + }; + + }; + }; + + tmc_etr: tmc@8048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + reg = <0x8048000 0x1000>, + <0x8064000 0x15000>; + reg-names = "tmc-base","bam-base"; + + coresight-name = "coresight-tmc-etr"; + + + iommus = <&apps_smmu 0x0180 0>, + <&apps_smmu 0x0160 0>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + arm,scatter-gather; + + coresight-ctis = <&cti0>; + coresight-csr = <&csr>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etr_in_replicator_qdss: endpoint { + slave-mode; + remote-endpoint = + <&replicator_qdss_out_tmc_etr>; + }; + }; + + }; + }; + + cti_cortex_M3: cti@8B30000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8B30000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cortex_M3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_apss_cti0: cti@98E0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x98E0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_apss_cti1: cti@98F0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x98F0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_wcss_cti0: cti@89A4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x89A4000 0x1000>; + reg-names = "cti-base"; + status = "disabled"; + coresight-name = "coresight-cti-wcss-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_wcss_cti1: cti@89A5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x89A5000 0x1000>; + reg-names = "cti-base"; + status = "disabled"; + coresight-name = "coresight-cti-wcss-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_wcss_cti2: cti@89A6000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x89A6000 0x1000>; + reg-names = "cti-base"; + status = "disabled"; + coresight-name = "coresight-cti-wcss-cti2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_q6: cti@8A21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8A21000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-lpass-q6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_q6: cti@8867000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8867000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing-q6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@8833000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8833000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_isdb_gpu: cti@8941000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8941000 0x1000>; + reg-names = "cti-base"; + status = "disabled"; + coresight-name = "coresight-cti-isdb-gpu"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mapss: cti@8A02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8A02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mapss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti0: cti@8B59000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8B59000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti1: cti@8B5A000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8B5A000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti2: cti@8B5B000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8B5B000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti3: cti@8B5C000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8B5C000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@8010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1: cti@8011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti10: cti@801a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti11: cti@801b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti12: cti@801c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti13: cti@801d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti14: cti@801e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti15: cti@801f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2: cti@8012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3: cti@8013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti4: cti@8014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti5: cti@8015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti6: cti@8016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti7: cti@8017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti8: cti@8018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti9: cti@8019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-gdsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-gdsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..16c1a0a7a34033e6d23497db1ff54c388613d166 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-gdsc.dtsi @@ -0,0 +1,115 @@ +&soc { + /* GDSCs in GCC */ + gcc_camss_top_gdsc: qcom,gdsc@1458004 { + compatible = "qcom,gdsc"; + reg = <0x1458004 0x4>; + regulator-name = "gcc_camss_top_gdsc"; + status = "disabled"; + }; + + gcc_ufs_phy_gdsc: qcom,gdsc@1445004 { + compatible = "qcom,gdsc"; + reg = <0x1445004 0x4>; + regulator-name = "gcc_ufs_phy_gdsc"; + status = "disabled"; + }; + + gcc_usb30_prim_gdsc: qcom,gdsc@141a004 { + compatible = "qcom,gdsc"; + reg = <0x141a004 0x4>; + regulator-name = "gcc_usb30_prim_gdsc"; + status = "disabled"; + }; + + gcc_vcodec0_gdsc: qcom,gdsc@1458098 { + compatible = "qcom,gdsc"; + reg = <0x1458098 0x4>; + regulator-name = "gcc_vcodec0_gdsc"; + status = "disabled"; + }; + + gcc_venus_gdsc: qcom,gdsc@145807c { + compatible = "qcom,gdsc"; + reg = <0x145807c 0x4>; + regulator-name = "gcc_venus_gdsc"; + status = "disabled"; + }; + + hlos1_vote_turing_mmu_tbu1_gdsc: qcom,gdsc@147d060 { + compatible = "qcom,gdsc"; + reg = <0x147d060 0x4>; + regulator-name = "hlos1_vote_turing_mmu_tbu1_gdsc"; + qcom,no-status-check-on-disable; + status = "disabled"; + }; + + hlos1_vote_turing_mmu_tbu0_gdsc: qcom,gdsc@147d07c { + compatible = "qcom,gdsc"; + reg = <0x147d07c 0x4>; + regulator-name = "hlos1_vote_turing_mmu_tbu0_gdsc"; + qcom,no-status-check-on-disable; + status = "disabled"; + }; + + hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc: qcom,gdsc@147d074 { + compatible = "qcom,gdsc"; + reg = <0x147d074 0x4>; + regulator-name = "hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc"; + qcom,no-status-check-on-disable; + status = "disabled"; + }; + + hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc: qcom,gdsc@147d078 { + compatible = "qcom,gdsc"; + reg = <0x147d078 0x4>; + regulator-name = "hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc"; + qcom,no-status-check-on-disable; + status = "disabled"; + }; + + /* GDSCs in DISPCC */ + mdss_core_gdsc: qcom,gdsc@5f03000 { + compatible = "qcom,gdsc"; + reg = <0x5f03000 0x4>; + regulator-name = "mdss_core_gdsc"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + status = "disabled"; + }; + + /* GDSCs in GPUCC */ + gpu_gx_domain_addr: syscon@5991508 { + compatible = "syscon"; + reg = <0x5991508 0x4>; + }; + + gpu_cx_hw_ctrl: syscon@5991540 { + compatible = "syscon"; + reg = <0x5991540 0x4>; + }; + + gpu_gx_sw_reset: syscon@5991008 { + compatible = "syscon"; + reg = <0x5991008 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@599106c { + compatible = "qcom,gdsc"; + reg = <0x599106c 0x4>; + regulator-name = "gpu_cx_gdsc"; + hw-ctrl-addr = <&gpu_cx_hw_ctrl>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + qcom,clk-dis-wait-val = <8>; + status = "disabled"; + }; + + gpu_gx_gdsc: qcom,gdsc@599100c { + compatible = "qcom,gdsc"; + reg = <0x599100c 0x4>; + regulator-name = "gpu_gx_gdsc"; + sw-reset = <&gpu_gx_sw_reset>; + domain-addr = <&gpu_gx_domain_addr>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c751da6e300ed45c2cb075f2fc5c33d26a5b2a7d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-gpu.dtsi @@ -0,0 +1,650 @@ +&soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a610_zap"; + qcom,mas-crypto = <&mas_crypto_c0>; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-980000000 { + opp-hz = /bits/ 64 <980000000>; + opp-microvolt = ; + }; + + opp-950000000 { + opp-hz = /bits/ 64 <950000000>; + opp-microvolt = ; + }; + + opp-900000000 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = ; + }; + + opp-820000000 { + opp-hz = /bits/ 64 <820000000>; + opp-microvolt = ; + }; + + opp-745000000 { + opp-hz = /bits/ 64 <745000000>; + opp-microvolt = ; + }; + + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = ; + }; + + opp-465000000 { + opp-hz = /bits/ 64 <465000000>; + opp-microvolt = ; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + opp-microvolt = ; + }; + }; + + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + operating-points-v2 = <&gpu_opp_table>; + }; + + gpu_bw_tbl: gpu-bw-tbl { + compatible = "operating-points-v2"; + + opp-0 { opp-hz = /bits/ 64 < 0 >; }; /* OFF */ + + opp-100 { opp-hz = /bits/ 64 < 762 >; }; /* 1.100 MHz */ + + opp-200 { opp-hz = /bits/ 64 < 1525 >; }; /* 2.200 MHz */ + + opp-300 { opp-hz = /bits/ 64 < 2288 >; }; /* 3.300 MHz */ + + opp-451 { opp-hz = /bits/ 64 < 3440 >; }; /* 4.451 MHz */ + + opp-547 { opp-hz = /bits/ 64 < 4173 >; }; /* 5.547 MHz */ + + opp-681 { opp-hz = /bits/ 64 < 5195 >; }; /* 6.681 MHz */ + + opp-768 { opp-hz = /bits/ 64 < 5859 >; }; /* 7.768 MHz */ + + opp-1017 { opp-hz = /bits/ 64 < 7759 >; }; /* 8.1017 MHz */ + + opp-1353 { opp-hz = /bits/ 64 < 10322 >; }; /* 9.1353 MHz */ + + opp-1555 { opp-hz = /bits/ 64 < 11863 >; }; /* 10.1555 MHz */ + + opp-1804 { opp-hz = /bits/ 64 < 13763 >; }; /* 11.1804 MHz */ + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + operating-points-v2 = <&gpu_bw_tbl>; + }; + + msm_gpu: qcom,kgsl-3d0@5900000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + + reg = <0x5900000 0x90000>, + <0x5961000 0x800>; + reg-names = "kgsl_3d0_reg_memory", "cx_dbgc"; + + interrupts = <0 177 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_3d0_irq"; + + qcom,id = <0>; + qcom,chipid = <0x06010000>; + + qcom,initial-pwrlevel = <6>; + qcom,idle-timeout = <80>; + + qcom,ubwc-mode = <1>; + qcom,min-access-length = <64>; + qcom,highest-bank-bit = <14>; + + /* size in bytes */ + qcom,snapshot-size = <1048576>; + + /* base addr, size */ + qcom,gpu-qdss-stm = <0xe1c0000 0x40000>; + #cooling-cells = <2>; + + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_BIMC_GPU_AXI_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", + "iface_clk", "mem_iface_clk", "gmu_clk", + "smmu_vote"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 800000>, /* 1 bus=100 (LOW SVS) */ + <26 512 0 1600000>, /* 2 bus=200 (LOW SVS) */ + <26 512 0 2400000>, /* 3 bus=300 (LOW SVS) */ + <26 512 0 3608000>, /* 4 bus=451 (LOW SVS) */ + <26 512 0 4376000>, /* 5 bus=547 (LOW SVS) */ + <26 512 0 5448000>, /* 6 bus=681 (SVS) */ + <26 512 0 6144000>, /* 7 bus=768 (SVS) */ + <26 512 0 8136000>, /* 8 bus=1017 (SVS_L1) */ + <26 512 0 10824000>, /* 9 bus=1353 (NOM) */ + <26 512 0 12440000>, /* 10 bus=1555 (NOM) */ + <26 512 0 14432000>; /* 11 bus=1804 (TURBO) */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <422>; + qcom,pm-qos-wakeup-latency = <422>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <5>; + + nvmem-cells = <&gpu_speed_bin>, <&gpu_gaming_bin>; + nvmem-cell-names = "speed_bin", "gaming_bin"; + + qcom,gpu-cx-ipeak { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-cx-ipeak"; + + qcom,gpu-cx-ipeak@0 { + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 10>; + qcom,gpu-cx-ipeak-freq = <950000000>; + }; + + qcom,gpu-cx-ipeak@1 { + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 1>; + qcom,gpu-cx-ipeak-freq = <900000000>; + }; + }; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* GPU Mempool configuration for low memory SKUs */ + qcom,gpu-mempools-lowmem { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools-lowmem"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-allocate; + qcom,mempool-max-pages = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-allocate; + qcom,mempool-max-pages = <32>; + }; + }; + + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calculated as FMAX/4.8 MHz round up to zero + * decimal places plus two margin to account for + * clock jitters. + */ + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <6>; + qcom,ca-target-pwrlevel = <5>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <980000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <900000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <820000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <600000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <206>; + + qcom,initial-pwrlevel = <6>; + qcom,ca-target-pwrlevel = <5>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <980000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <900000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <820000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <600000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <200>; + + qcom,initial-pwrlevel = <6>; + qcom,ca-target-pwrlevel = <5>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <950000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <900000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <820000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <600000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <157>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <745000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <600000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-4 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <127>; + + qcom,initial-pwrlevel = <2>; + qcom,ca-target-pwrlevel = <1>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <600000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@59a0000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x59a0000 0x10000>; + qcom,protect = <0xa0000 0x10000>; + + clocks = <&gcc GCC_BIMC_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "mem_clk", "mem_iface_clk", "smmu_vote"; + + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0 1>; + qcom,iommu-dma = "disabled"; + qcom,gpu-offset = <0xa8000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_secure"; + iommus = <&kgsl_smmu 2 0>; + qcom,iommu-dma = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-1gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-1gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..f614df1a9f319fd1df31ff81b6287546d3992b62 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-1gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP 1Gb DDR HD+"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + qcom,board-id = <34 0x303>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-1gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..d272c7b4069f7b177a94a786e525893ae087f503 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-1gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal-low-ram.dtsi" +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP 1Gb DDR HD+"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,board-id = <34 0x303>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-2gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..962305e274737694d3cc480f77faf7b38a32aea1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-2gb-overlay.dts @@ -0,0 +1,40 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP 2Gb DDR HD+"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + qcom,board-id = <34 0x403>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..fd12308a97bb837e21a00a858d46815cae156cef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-2gb.dts @@ -0,0 +1,38 @@ +/dts-v1/; + +#include "bengal-low-ram.dtsi" +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP 2Gb DDR HD+"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,board-id = <34 0x403>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eef3e49bcecef848ce55c4e59d33ee8e4a883a5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-low-ram.dtsi @@ -0,0 +1 @@ +#include "bengal-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5b1e7f3b1ddd7164a6be308f2071f9521b71f9cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-1gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-1gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..91c3725f222b1e84e97ebdb39fc802f65c77db4b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-1gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP AATC 1Gb DDR"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + qcom,board-id = <34 0x301>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-1gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-1gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..95ebbd014e8a388dcd413cd0db22f0173299080a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-1gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal-low-ram.dtsi" +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP AATC 1Gb DDR"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,board-id = <34 0x301>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-2gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4b5b228289f286d0b0e0a24c02176a3d074747f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-2gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP AATC 2Gb DDR"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..d35e02cde4a8584b6a0e9c55642a071f486659d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-2gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal-low-ram.dtsi" +#include "bengal-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP AATC 2Gb DDR"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4f2bb4c659a4d345562edf79ee1f873f204be326 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp.dtsi" +#include "bengal-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP USBC Audio"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc.dts new file mode 100644 index 0000000000000000000000000000000000000000..c9e9b2498e0ad0a44dfc5c5b62fcbc09fdbe5825 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "bengal.dtsi" +#include "bengal-idp.dtsi" +#include "bengal-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP USBC Audio"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..704385e62afeaa8e922bcad5ff19702a54ad367a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp-usbc.dtsi @@ -0,0 +1,5 @@ +&bengal_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..5c41c0d3d9a4f6449d264d024bab293032e27db6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal.dtsi" +#include "bengal-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL IDP"; + compatible = "qcom,bengal-idp", "qcom,bengal", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6989918cd64950cfcacb4ff52e0629f36a819ced --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-idp.dtsi @@ -0,0 +1,449 @@ +#include +#include +#include +#include "bengal-audio-overlay.dtsi" +#include "bengal-thermal-overlay.dtsi" +#include "bengal-sde-display.dtsi" +#include "camera/bengal-camera-sensor-idp.dtsi" + +&soc { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + }; +}; + +&qupv3_se1_i2c { + status = "ok"; + #include "smb1355.dtsi" +}; + +&qupv3_se4_2uart { + status = "ok"; +}; + +&pm6125_vadc { + pinctrl-0 = <&camera_therm_default &emmc_therm_default &rf_pa1_therm_default>; + + rf_pa1_therm { + reg = ; + label = "rf_pa1_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm6125_adc_tm { + io-channels = <&pm6125_vadc ADC_AMUX_THM1_PU2>, + <&pm6125_vadc ADC_AMUX_THM2_PU2>, + <&pm6125_vadc ADC_XO_THERM_PU2>, + <&pm6125_vadc ADC_GPIO4_PU2>; + + rf_pa1_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + rf-pa1-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6125_adc_tm ADC_GPIO4_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&pmi632_qg { + qcom,battery-data = <&mtp_batterydata>; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,qg-use-s7-ocv; +}; + +&pmi632_charger { + qcom,battery-data = <&mtp_batterydata>; + qcom,suspend-input-on-debug-batt; + qcom,sw-jeita-enable; + qcom,step-charging-enable; + qcom,hvdcp2-max-icl-ua = <2000000>; + /* SMB1355 only */ + qcom,sec-charger-config = <2>; + dpdm-supply = <&qusb_phy0>; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,auto-recharge-soc = <98>; + qcom,flash-disable-soc = <10>; + qcom,hw-die-temp-mitigation; + qcom,hw-connector-mitigation; + qcom,connector-internal-pull-kohm = <100>; + qcom,float-option = <1>; + qcom,thermal-mitigation = <3000000 2500000 + 2000000 1500000 1000000 500000>; +}; + +&pmi632_gpios { + smb_en { + smb_en_default: smb_en_default { + pins = "gpio2"; + function = "func1"; + output-enable; + }; + }; + + pmi632_sense { + /* GPIO 7 and 8 are external-sense pins for PMI632 */ + pmi632_sense_default: pmi632_sense_default { + pins = "gpio7", "gpio8"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; + + pmi632_ctm { + /* Disable GPIO1 for h/w base mitigation */ + pmi632_ctm_default: pmi632_ctm_default { + pins = "gpio1"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; +}; + +&pm6125_gpios { + + rf_pa1_therm { + rf_pa1_therm_default: rf_pa1_therm_default { + pins = "gpio7"; + bias-high-impedance; + }; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio5"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&usb0 { + extcon = <&pmi632_charger>, <&eud>; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6125_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; +}; + +&qupv3_se1_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 70 0x00>; + qcom,nq-ven = <&tlmm 69 0x00>; + qcom,nq-firm = <&tlmm 31 0x00>; + qcom,nq-clkreq = <&tlmm 86 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <70 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&tlmm { + smb_int_default: smb_int_default { + mux { + pins = "gpio105"; + function = "gpio"; + }; + + config { + pins = "gpio105"; + bias-pull-up; + input-enable; + }; + }; +}; + +&smb1355 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + interrupt-parent = <&tlmm>; + interrupts = <105 IRQ_TYPE_LEVEL_LOW>; + status = "ok"; +}; + +&smb1355_charger { + pinctrl-names = "default"; + pinctrl-0 = <&smb_en_default &pmi632_sense_default &pmi632_ctm_default>; + qcom,parallel-mode = <1>; + qcom,disable-ctm; + qcom,hw-die-temp-mitigation; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&L24A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L11A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L22A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L5A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + vdd-io-bias-supply = <&L7A>; + qcom,vdd-io-bias-voltage-level = <1256000 1256000>; + qcom,vdd-io-bias-current-level = <0 6000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 88 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3-660"; + + vdda-phy-supply = <&L4A>; /* 0.9v */ + vdda-pll-supply = <&L12A>; /* 1.8v */ + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L24A>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&L11A>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + vccq2-pwr-collapse-sup; + + qcom,vddp-ref-clk-supply = <&L18A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1232000>; + qcom,vddp-ref-clk-max-uV = <1232000>; + + status = "ok"; +}; + +&pm6125_pwm { + status = "ok"; +}; + +&dsi_td4330_truly_v2_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm6125_pwm 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-bklight-en-gpio = <&pmi632_gpios 6 0>; +}; + +&dsi_td4330_truly_v2_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm6125_pwm 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-bklight-en-gpio = <&pmi632_gpios 6 0>; +}; + +&dsi_nt36525_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm6125_pwm 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-bklight-en-gpio = <&pmi632_gpios 6 0>; +}; + +&dsi_r66451_amoled_hd_90hz_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-en-gpio = <&tlmm 83 0>; +}; + +&dsi_r66451_amoled_hd_90hz_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-en-gpio = <&tlmm 83 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_td4330_truly_v2_video>; +}; + +&tlmm { + touch_vdd_default: touch_vdd_default { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; +}; + +&soc { + touch_vdd: touch_vdd { + compatible = "regulator-fixed"; + regulator-name = "touch_vdd"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&tlmm 84 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-names = "default"; + pinctrl-0 = <&touch_vdd_default>; + }; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="synaptics,tcm-i2c"; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,irq-gpio = <&tlmm 80 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 71 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware_k.img"; + + panel = <&dsi_td4330_truly_v2_video &dsi_td4330_truly_v2_cmd>; + }; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; + + focaltech@38 { + compatible = "focaltech,fts_ts"; + reg = <0x38>; + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + focaltech,reset-gpio = <&tlmm 71 0x00>; + focaltech,irq-gpio = <&tlmm 80 0x2008>; + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 1080 2340>; + + vdd-supply = <&touch_vdd>; + + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + panel = <&dsi_r66451_amoled_hd_90hz_video + &dsi_r66451_amoled_hd_90hz_cmd>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-ion.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b1e71e3dca0b72446e4efa542ab6942577245171 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-ion.dtsi @@ -0,0 +1,50 @@ +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + system_secure_heap: qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@14 { /* SECURE CARVEOUT HEAP */ + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + cdsp { + memory-region = <&cdsp_sec_mem>; + token = <0x20000000>; + }; + }; + + qcom,ion-heap@26 { /* USER CONTIG HEAP */ + reg = <26>; + memory-region = <&user_contig_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..cc6fe36f89a4588f161e00358800e42e52d6fb66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-2gb.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengal-iot-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT 2Gb DDR HD+ SoC"; + compatible = "qcom,bengal-iot"; + qcom,board-id = <0 0x403>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-2gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..8ba5934b7bb7880cb98f6d7130b519b42ab51613 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-2gb-overlay.dts @@ -0,0 +1,40 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP 2Gb DDR HD+"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0x403>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..50b6b22ad930c99e243220826036e427e9b43f41 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-2gb.dts @@ -0,0 +1,38 @@ +/dts-v1/; + +#include "bengal-iot-low-ram.dtsi" +#include "bengal-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP 2Gb DDR HD+"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,board-id = <34 0x403>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f76fdf04c5ce74d12986eb8e3829e2667c1e2d19 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-low-ram.dtsi @@ -0,0 +1 @@ +#include "bengal-iot-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3afec6e694676889115fab3dd1a2a155e3b8f70a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP Overlay"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-2gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..cde54437765a0477da9dbd3f30313dc2f0e639c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-2gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP AATC 2Gb DDR"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..37ca9398077cc234fb49540597eca120916ae1ff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-2gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal-iot-low-ram.dtsi" +#include "bengal-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP AATC 2Gb DDR"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a57774fae86ae068bc6b95534d01b76e345765ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-iot-idp.dtsi" +#include "bengal-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP USBC Audio"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,msm-id = <469 0x10000>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc.dts new file mode 100644 index 0000000000000000000000000000000000000000..1d9a5633ec9a2d67784d69363b008cdc5d9335b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "bengal-iot.dtsi" +#include "bengal-iot-idp.dtsi" +#include "bengal-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP USBC Audio"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..704385e62afeaa8e922bcad5ff19702a54ad367a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp-usbc.dtsi @@ -0,0 +1,5 @@ +&bengal_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..6457f123654bf707151f01c2255f36998e815b29 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal-iot.dtsi" +#include "bengal-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT IDP"; + compatible = "qcom,bengal-iot-idp", "qcom,bengal-iot", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eef3e49bcecef848ce55c4e59d33ee8e4a883a5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-idp.dtsi @@ -0,0 +1 @@ +#include "bengal-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ab4a6ae57e5b3eff7c7481b19b5c6fa82724441f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot-low-ram.dtsi @@ -0,0 +1,148 @@ +#include "bengal-iot.dtsi" +/ { +}; + +/delete-node/ &hyp_mem; +/delete-node/ &xbl_aop_mem; +/delete-node/ &sec_apps_mem; +/delete-node/ &smem_mem; +/delete-node/ &removed_mem; +/delete-node/ &pil_modem_mem; +/delete-node/ &pil_video_mem; +/delete-node/ &wlan_msa_mem; +/delete-node/ &pil_cdsp_mem; +/delete-node/ &pil_adsp_mem; +/delete-node/ &pil_ipa_fw_mem; +/delete-node/ &pil_ipa_gsi_mem; +/delete-node/ &pil_gpu_mem; +/delete-node/ &cdsp_sec_mem; + +/delete-node/ &user_contig_mem; +/delete-node/ &qseecom_mem; +/delete-node/ &qseecom_ta_mem; + +/delete-node/ &secure_display_memory; + +/delete-node/ &disp_rdump_memory; + +&reserved_memory { + hyp_mem: hyp_region@45700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45700000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_region@45e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45e00000 0x0 0x100000>; + }; + + sec_apps_mem: sec_apps_region@45fff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45fff000 0x0 0x1000>; + }; + + smem_mem: smem_region@46000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x46000000 0x0 0x200000>; + }; + + pil_modem_mem: modem_region@4ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x4ab00000 0x0 0x6900000>; + }; + + pil_video_mem: pil_video_region@51400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51400000 0x0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@51900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51900000 0x0 0x100000>; + }; + + pil_cdsp_mem: cdsp_regions@51a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51a00000 0x0 0x800000>; + }; + + pil_adsp_mem: pil_adsp_region@52200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x52200000 0x0 0x1c00000>; + }; + + pil_ipa_fw_mem: ipa_fw_region@53e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e00000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@53e10000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e10000 0x0 0x5000>; + }; + + pil_gpu_mem: gpu_region@53e15000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e15000 0x0 0x2000>; + }; + + tz_stat_mem: tz_stat_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x100000>; + }; + + removed_mem: removed_region@60100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60100000 0x0 0x2200000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + linux,cma { + size = <0x0 0x1000000>; + }; +}; + +&soc { + qcom,ion { + /delete-node/ qcom,ion-heap@14; + /delete-node/ qcom,ion-heap@10; + /delete-node/ qcom,ion-heap@26; + }; + + qcom_seecom: qseecom@61800000 { + reg = <0x61800000 0xb00000>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + reg = <0x61800000 0xb00000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-iot.dts new file mode 100644 index 0000000000000000000000000000000000000000..2a5be79d97ee89990cfc6e1422fead8ce5eed877 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengal-iot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT SoC"; + compatible = "qcom,bengal-iot"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-iot.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-iot.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6d93a7a8ff9f791a6d429851fcdc689e6e621e6f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-iot.dtsi @@ -0,0 +1,8 @@ +#include "bengal.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGAL-IOT"; + compatible = "qcom,bengal-iot"; + qcom,msm-id = <469 0x0>; + qcom,msm-name = "BENGAL-IOT"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8179bf419f81f89093d176b2a97b5e730eb5afbd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-low-ram.dtsi @@ -0,0 +1,148 @@ +#include "bengal.dtsi" +/ { +}; + +/delete-node/ &hyp_mem; +/delete-node/ &xbl_aop_mem; +/delete-node/ &sec_apps_mem; +/delete-node/ &smem_mem; +/delete-node/ &removed_mem; +/delete-node/ &pil_modem_mem; +/delete-node/ &pil_video_mem; +/delete-node/ &wlan_msa_mem; +/delete-node/ &pil_cdsp_mem; +/delete-node/ &pil_adsp_mem; +/delete-node/ &pil_ipa_fw_mem; +/delete-node/ &pil_ipa_gsi_mem; +/delete-node/ &pil_gpu_mem; +/delete-node/ &cdsp_sec_mem; + +/delete-node/ &user_contig_mem; +/delete-node/ &qseecom_mem; +/delete-node/ &qseecom_ta_mem; + +/delete-node/ &secure_display_memory; + +/delete-node/ &disp_rdump_memory; + +&reserved_memory { + hyp_mem: hyp_region@45700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45700000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_region@45e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45e00000 0x0 0x100000>; + }; + + sec_apps_mem: sec_apps_region@45fff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45fff000 0x0 0x1000>; + }; + + smem_mem: smem_region@46000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x46000000 0x0 0x200000>; + }; + + pil_modem_mem: modem_region@4ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x4ab00000 0x0 0x6900000>; + }; + + pil_video_mem: pil_video_region@51400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51400000 0x0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@51900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51900000 0x0 0x100000>; + }; + + pil_cdsp_mem: cdsp_regions@51a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51a00000 0x0 0x800000>; + }; + + pil_adsp_mem: pil_adsp_region@52200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x52200000 0x0 0x1c00000>; + }; + + pil_ipa_fw_mem: ipa_fw_region@53e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e00000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@53e10000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e10000 0x0 0x5000>; + }; + + pil_gpu_mem: gpu_region@53e15000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e15000 0x0 0x2000>; + }; + + tz_stat_mem: tz_stat_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x100000>; + }; + + removed_mem: removed_region@60100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60100000 0x0 0x2200000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + linux,cma { + size = <0x0 0x1000000>; + }; +}; + +&soc { + qcom,ion { + /delete-node/ qcom,ion-heap@14; + /delete-node/ qcom,ion-heap@10; + /delete-node/ qcom,ion-heap@26; + }; + + qcom_seecom: qseecom@61800000 { + reg = <0x61800000 0xb00000>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + reg = <0x61800000 0xb00000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-lpi.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4bcd1af8b0d0727914528b7292f2e33cce641fc2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-lpi.dtsi @@ -0,0 +1,1957 @@ +&q6core { + lpi_tlmm: lpi_pinctrl@ac40000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0xa7c0000 0x0>; + qcom,slew-reg = <0xa95a000 0x0>; + qcom,num-gpios = <19>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = <0x00000000>, <0x00001000>, + <0x00002000>, <0x00003000>, + <0x00004000>, <0x00005000>, + <0x00006000>, <0x00007000>, + <0x00008000>, <0x00009000>, + <0x0000A000>, <0x0000B000>, + <0x0000C000>, <0x0000D000>, + <0x0000E000>, <0x0000F000>, + <0x00010000>, <0x00011000>, + <0x00012000>; + qcom,lpi-slew-offset-tbl = <0x00000000>, <0x00000002>, + <0x00000004>, <0x00000008>, + <0x0000000A>, <0x0000000C>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000014>; + + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + + quat_mi2s_sck { + quat_mi2s_sck_sleep: quat_mi2s_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sck_active: quat_mi2s_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_ws { + quat_mi2s_ws_sleep: quat_mi2s_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_ws_active: quat_mi2s_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sck { + lpi_i2s1_sck_sleep: lpi_i2s1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sck_active: lpi_i2s1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_ws { + lpi_i2s1_ws_sleep: lpi_i2s1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_ws_active: lpi_i2s1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd0 { + lpi_i2s1_sd0_sleep: lpi_i2s1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd0_active: lpi_i2s1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd1 { + lpi_i2s1_sd1_sleep: lpi_i2s1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd1_active: lpi_i2s1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sck { + lpi_i2s2_sck_sleep: lpi_i2s2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sck_active: lpi_i2s2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_ws { + lpi_i2s2_ws_sleep: lpi_i2s2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_ws_active: lpi_i2s2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd0 { + lpi_i2s2_sd0_sleep: lpi_i2s2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd0_active: lpi_i2s2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd1 { + lpi_i2s2_sd1_sleep: lpi_i2s2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd1_active: lpi_i2s2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_sck { + lpi_i2s3_sck_sleep: lpi_i2s3_sck_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_sck_active: lpi_i2s3_sck_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_ws { + lpi_i2s3_ws_sleep: lpi_i2s3_ws_sleep { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_ws_active: lpi_i2s3_ws_active { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_sd0 { + lpi_i2s3_sd0_sleep: lpi_i2s3_sd0_sleep { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_sd0_active: lpi_i2s3_sd0_active { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_sd1 { + lpi_i2s3_sd1_sleep: lpi_i2s3_sd1_sleep { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_sd1_active: lpi_i2s3_sd1_active { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sck { + quat_tdm_sck_sleep: quat_tdm_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sck_active: quat_tdm_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_ws { + quat_tdm_ws_sleep: quat_tdm_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_ws_active: quat_tdm_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd0 { + quat_tdm_sd0_sleep: quat_tdm_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd0_active: quat_tdm_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd1 { + quat_tdm_sd1_sleep: quat_tdm_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd1_active: quat_tdm_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd2 { + quat_tdm_sd2_sleep: quat_tdm_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd2_active: quat_tdm_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd3 { + quat_tdm_sd3_sleep: quat_tdm_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd3_active: quat_tdm_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sck { + lpi_tdm1_sck_sleep: lpi_tdm1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sck_active: lpi_tdm1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_ws { + lpi_tdm1_ws_sleep: lpi_tdm1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_ws_active: lpi_tdm1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd0 { + lpi_tdm1_sd0_sleep: lpi_tdm1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd0_active: lpi_tdm1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd1 { + lpi_tdm1_sd1_sleep: lpi_tdm1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd1_active: lpi_tdm1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sck { + lpi_tdm2_sck_sleep: lpi_tdm2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sck_active: lpi_tdm2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_ws { + lpi_tdm2_ws_sleep: lpi_tdm2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_ws_active: lpi_tdm2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd0 { + lpi_tdm2_sd0_sleep: lpi_tdm2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd0_active: lpi_tdm2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd1 { + lpi_tdm2_sd1_sleep: lpi_tdm2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd1_active: lpi_tdm2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_sck { + lpi_tdm3_sck_sleep: lpi_tdm3_sck_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_sck_active: lpi_tdm3_sck_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_ws { + lpi_tdm3_ws_sleep: lpi_tdm3_ws_sleep { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_ws_active: lpi_tdm3_ws_active { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_sd0 { + lpi_tdm3_sd0_sleep: lpi_tdm3_sd0_sleep { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_sd0_active: lpi_tdm3_sd0_active { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_sd1 { + lpi_tdm3_sd1_sleep: lpi_tdm3_sd1_sleep { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_sd1_active: lpi_tdm3_sd1_active { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sck { + quat_aux_sck_sleep: quat_aux_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sck_active: quat_aux_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_ws { + quat_aux_ws_sleep: quat_aux_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_ws_active: quat_aux_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd0 { + quat_aux_sd0_sleep: quat_aux_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd0_active: quat_aux_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd1 { + quat_aux_sd1_sleep: quat_aux_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd1_active: quat_aux_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd2 { + quat_aux_sd2_sleep: quat_aux_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd2_active: quat_aux_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd3 { + quat_aux_sd3_sleep: quat_aux_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd3_active: quat_aux_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sck { + lpi_aux1_sck_sleep: lpi_aux1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sck_active: lpi_aux1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_ws { + lpi_aux1_ws_sleep: lpi_aux1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_ws_active: lpi_aux1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd0 { + lpi_aux1_sd0_sleep: lpi_aux1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd0_active: lpi_aux1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd1 { + lpi_aux1_sd1_sleep: lpi_aux1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd1_active: lpi_aux1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sck { + lpi_aux2_sck_sleep: lpi_aux2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sck_active: lpi_aux2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_ws { + lpi_aux2_ws_sleep: lpi_aux2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_ws_active: lpi_aux2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd0 { + lpi_aux2_sd0_sleep: lpi_aux2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd0_active: lpi_aux2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd1 { + lpi_aux2_sd1_sleep: lpi_aux2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd1_active: lpi_aux2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_sck { + lpi_aux3_sck_sleep: lpi_aux3_sck_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_sck_active: lpi_aux3_sck_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_ws { + lpi_aux3_ws_sleep: lpi_aux3_ws_sleep { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_ws_active: lpi_aux3_ws_active { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_sd0 { + lpi_aux3_sd0_sleep: lpi_aux3_sd0_sleep { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_sd0_active: lpi_aux3_sd0_active { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_sd1 { + lpi_aux3_sd1_sleep: lpi_aux3_sd1_sleep { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_sd1_active: lpi_aux3_sd1_active { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tx_swr_clk_sleep: tx_swr_clk_sleep { + mux { + pins = "gpio0"; + function = "func1"; + input-enable; + bias-pull-down; + }; + + config { + pins = "gpio0"; + drive-strength = <10>; + }; + }; + + tx_swr_clk_active: tx_swr_clk_active { + mux { + pins = "gpio0"; + function = "func1"; + }; + + config { + pins = "gpio0"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + + tx_swr_data1_sleep: tx_swr_data1_sleep { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <10>; + input-enable; + bias-bus-hold; + }; + }; + + tx_swr_data1_active: tx_swr_data1_active { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + tx_swr_data2_sleep: tx_swr_data2_sleep { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data2_active: tx_swr_data2_active { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + rx_swr_clk_sleep: rx_swr_clk_sleep { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_clk_active: rx_swr_clk_active { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + + rx_swr_data_sleep: rx_swr_data_sleep { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data_active: rx_swr_data_active { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + rx_swr_data1_sleep: rx_swr_data1_sleep { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data1_active: rx_swr_data1_active { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + cdc_dmic01_clk_active: dmic01_clk_active { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic01_clk_sleep: dmic01_clk_sleep { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic01_data_active: dmic01_data_active { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic01_data_sleep: dmic01_data_sleep { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic23_clk_active: dmic23_clk_active { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic23_clk_sleep: dmic23_clk_sleep { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic23_data_active: dmic23_data_active { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic23_data_sleep: dmic23_data_sleep { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + wsa_mclk_sleep: wsa_mclk_sleep { + mux { + pins = "gpio18"; + function = "func1"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + }; + }; + + wsa_mclk_active: wsa_mclk_active { + mux { + pins = "gpio18"; + function = "func1"; + }; + + config { + pins = "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-pinctrl.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8f3ec92c6891d9f221caf4c5290971c7028ab4f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-pinctrl.dtsi @@ -0,0 +1,1188 @@ +&soc { + tlmm: pinctrl@400000 { + compatible = "qcom,bengal-pinctrl"; + reg = <0x400000 0xc00000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&wakegpio>; + irqdomain-map = <0 0 &wakegpio 84 0>, + <3 0 &wakegpio 75 0>, + <4 0 &wakegpio 16 0>, + <6 0 &wakegpio 59 0>, + <8 0 &wakegpio 63 0>, + <11 0 &wakegpio 17 0>, + <13 0 &wakegpio 18 0>, + <14 0 &wakegpio 51 0>, + <17 0 &wakegpio 20 0>, + <18 0 &wakegpio 52 0>, + <19 0 &wakegpio 53 0>, + <24 0 &wakegpio 6 0>, + <25 0 &wakegpio 71 0>, + <27 0 &wakegpio 73 0>, + <28 0 &wakegpio 41 0>, + <31 0 &wakegpio 27 0>, + <32 0 &wakegpio 54 0>, + <33 0 &wakegpio 55 0>, + <34 0 &wakegpio 56 0>, + <35 0 &wakegpio 57 0>, + <36 0 &wakegpio 58 0>, + <39 0 &wakegpio 28 0>, + <46 0 &wakegpio 29 0>, + <62 0 &wakegpio 60 0>, + <63 0 &wakegpio 61 0>, + <64 0 &wakegpio 62 0>, + <65 0 &wakegpio 30 0>, + <66 0 &wakegpio 31 0>, + <67 0 &wakegpio 32 0>, + <69 0 &wakegpio 33 0>, + <70 0 &wakegpio 34 0>, + <72 0 &wakegpio 72 0>, + <75 0 &wakegpio 35 0>, + <79 0 &wakegpio 36 0>, + <80 0 &wakegpio 21 0>, + <81 0 &wakegpio 38 0>, + <83 0 &wakegpio 9 0>, + <84 0 &wakegpio 39 0>, + <85 0 &wakegpio 40 0>, + <86 0 &wakegpio 19 0>, + <87 0 &wakegpio 42 0>, + <88 0 &wakegpio 43 0>, + <89 0 &wakegpio 45 0>, + <91 0 &wakegpio 74 0>, + <93 0 &wakegpio 46 0>, + <94 0 &wakegpio 47 0>, + <95 0 &wakegpio 48 0>, + <96 0 &wakegpio 49 0>, + <97 0 &wakegpio 50 0>; + irqdomain-map-pass-thru = <0 0xff>; + irqdomain-map-mask = <0xff 0>; + + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-disable; + }; + }; + + tb_trig1_on: tb_trig1_on { + mux { + pins = "gpio19"; + function = "SDC1_TB"; + }; + + config { + pins = "gpio19"; + bias-pull-up; /* PULL UP */ + drive-strength = <8>; /* 8 MA */ + input-enable; + }; + }; + + /* WSA speaker reset pin1 */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio106"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio106"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + wcd937x_reset_active: wcd937x_reset_active { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <16>; + output-high; + }; + }; + + wcd937x_reset_sleep: wcd937x_reset_sleep { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + qupv3_se4_2uart_pins: qupv3_se4_2uart_pins { + qupv3_se4_2uart_active: qupv3_se4_2uart_active { + mux { + pins = "gpio12", "gpio13"; + function = "qup4"; + }; + + config { + pins = "gpio12", "gpio13"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_2uart_sleep: qupv3_se4_2uart_sleep { + mux { + pins = "gpio12", "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio13"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se3_4uart_pins: qupv3_se3_4uart_pins { + qupv3_se3_default_ctsrtsrx: + qupv3_se3_default_ctsrtsrx { + mux { + pins = "gpio8", "gpio9", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9", "gpio11"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se3_default_tx: + qupv3_se3_default_tx { + mux { + pins = "gpio10"; + function = "gpio"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se3_ctsrx: qupv3_se3_ctsrx { + mux { + pins = "gpio8", "gpio11"; + function = "qup3"; + }; + + config { + pins = "gpio8", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_rts: qupv3_se3_rts { + mux { + pins = "gpio9"; + function = "qup3"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se3_tx: qupv3_se3_tx { + mux { + pins = "gpio10"; + function = "qup3"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup1"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 70 NFC Read Interrupt */ + pins = "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio70"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 70 NFC Read Interrupt */ + pins = "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio70"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 69: Enable 31: Firmware */ + pins = "gpio69", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio69", "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 69: Enable 31: Firmware */ + pins = "gpio69", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio69", "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + + nfc_clk_req_active: nfc_clk_req_active { + /* active state */ + mux { + /* GPIO 86: NFC CLOCK REQUEST */ + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_clk_req_suspend: nfc_clk_req_suspend { + /* sleep state */ + mux { + /* GPIO 86: NFC CLOCK REQUEST */ + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + function = "qup1"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + function = "qup5"; + }; + + config { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA*/ + pins = "gpio23", "gpio22"; + function = "cci_i2c"; + }; + + config { + pins = "gpio23", "gpio22"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA*/ + pins = "gpio23", "gpio22"; + function = "cci_i2c"; + }; + + config { + pins = "gpio23", "gpio22"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA*/ + pins = "gpio30", "gpio29"; + function = "cci_i2c"; + }; + + config { + pins = "gpio30", "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA*/ + pins = "gpio30", "gpio29"; + function = "cci_i2c"; + }; + + config { + pins = "gpio30", "gpio29"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK 0*/ + mux { + pins = "gpio20"; + function = "cam_mclk"; + }; + + config { + pins = "gpio20"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK 0*/ + mux { + pins = "gpio20"; + function = "cam_mclk"; + }; + + config { + pins = "gpio20"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK 1*/ + mux { + pins = "gpio21"; + function = "cam_mclk"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK 1*/ + mux { + pins = "gpio21"; + function = "cam_mclk"; + }; + + config { + pins = "gpio21"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK 2*/ + mux { + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK 2*/ + mux { + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK 3*/ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK 3*/ + mux { + pins = "gpio28"; + function = "cam_mclk"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear0_reset_active: cam_sensor_rear0_reset_active { + /* RESET0 */ + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear0_reset_suspend: cam_sensor_rear0_reset_suspend { + /* RESET0 */ + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear1_reset_active: cam_sensor_rear1_reset_active { + /* RESET1 */ + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear1_reset_suspend: cam_sensor_rear1_reset_suspend { + /* RESET1 */ + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear2_reset_active: cam_sensor_rear2_reset_active { + /* RESET2 */ + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_reset_suspend: cam_sensor_rear2_reset_suspend { + /* RESET2 */ + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_front0_reset_active: cam_sensor_front0_reset_active { + /* RESET0 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front0_reset_suspend: cam_sensor_front0_reset_suspend { + /* RESET0 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_csi_mux_oe_active: cam_sensor_csi_mux_oe_active { + /*CSIMUX_OE*/ + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_csi_mux_oe_suspend: cam_sensor_csi_mux_oe_suspend { + /* CSIMUX_OE */ + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_csi_mux_sel_active: cam_sensor_csi_mux_sel_active { + /*CSIMUX_SEL*/ + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_csi_mux_sel_suspend: cam_sensor_csi_mux_sel_suspend { + /* CSIMUX_SEL */ + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <8>; + bias-disable = <0>; + }; + }; + + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio81"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio81"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio81"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio81"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio71"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio71"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio80", "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio80", "gpio71"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pm8008_active: pm8008_active { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-pull-up; + output-high; + drive-strength = <2>; + }; + }; + + pm8008_interrupt: pm8008_interrupt { + mux { + pins = "gpior25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + bias-disable; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-pm.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..059d29f525ca057ded3e5101967a526475e35ccb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-pm.dtsi @@ -0,0 +1,192 @@ +&soc { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + qcom,use-psci; + #address-cells = <1>; + #size-cells = <0>; + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "system"; + qcom,spm-device-names = "cci"; + qcom,psci-mode-shift = <8>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0 { + reg = <0>; + label = "system-wfi"; + qcom,psci-mode = <0x0>; + qcom,entry-latency-us = <640>; + qcom,exit-latency-us = <1654>; + qcom,min-residency-us = <2294>; + }; + + qcom,pm-cluster-level@1 { /* E3 */ + reg = <1>; + label = "system-pc"; + qcom,psci-mode = <0x3>; + qcom,entry-latency-us = <10831>; + qcom,exit-latency-us = <4506>; + qcom,min-residency-us = <15338>; + qcom,min-child-idx = <2>; + qcom,notify-rpm; + qcom,is-reset; + }; + + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "pwr"; + qcom,spm-device-names = "l2"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "pwr-l2-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <38>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <89>; + }; + + qcom,pm-cluster-level@1 { /* D3G */ + reg = <1>; + label = "pwr-l2-gdhs"; + qcom,psci-mode = <0x2>; + qcom,entry-latency-us = <360>; + qcom,exit-latency-us = <421>; + qcom,min-residency-us = <782>; + qcom,min-child-idx = <1>; + }; + + qcom,pm-cluster-level@2 { /* D3 */ + reg = <2>; + label = "pwr-l2-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <800>; + qcom,exit-latency-us = <2118>; + qcom,min-residency-us = <7376>; + qcom,min-child-idx = <1>; + qcom,is-reset; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,disable-ipi-prediction; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <49>; + qcom,exit-latency-us = <42>; + qcom,min-residency-us = <91>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <290>; + qcom,exit-latency-us = <376>; + qcom,min-residency-us = <1182>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + + qcom,pm-cluster@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + label = "perf"; + qcom,spm-device-names = "l2"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "perf-l2-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <38>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <89>; + }; + + qcom,pm-cluster-level@1 { /* D3G*/ + reg = <1>; + label = "perf-l2-gdhs"; + qcom,psci-mode = <2>; + qcom,entry-latency-us = <314>; + qcom,exit-latency-us = <345>; + qcom,min-residency-us = <660>; + qcom,min-child-idx = <1>; + }; + + qcom,pm-cluster-level@2 { /* D3 */ + reg = <2>; + label = "perf-l2-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <640>; + qcom,exit-latency-us = <1654>; + qcom,min-residency-us = <8094>; + qcom,min-child-idx = <1>; + qcom,is-reset; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,disable-ipi-prediction; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <29>; + qcom,exit-latency-us = <39>; + qcom,min-residency-us = <68>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <297>; + qcom,exit-latency-us = <324>; + qcom,min-residency-us = <1110>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + }; + + qcom,rpm-stats@4600000 { + compatible = "qcom,rpm-stats"; + reg = <0x04600000 0x1000>, + <0x04690014 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + qcom,sleep-stats-version = <2>; + }; + + qcom,rpm-master-stats@45f0150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x45f0150 0x5000>; + qcom,masters = "APSS", "MPSS", "ADSP", "CDSP", "TZ"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-qrd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1a4bfdca0386dda13c1441e72b4bb999d9c68cbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-qrd-overlay.dts @@ -0,0 +1,10 @@ +/dts-v1/; +/plugin/; + +#include "bengal-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal QRD"; + compatible = "qcom,bengal-qrd", "qcom,bengal", "qcom,qrd"; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..8d1c093986b2bf38885af60e8be818d0154102d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-qrd.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengal.dtsi" +#include "bengal-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal QRD"; + compatible = "qcom,bengal-qrd", "qcom,bengal", "qcom,qrd"; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..18858d38abfba8ff7ae418f10b64166d99e8fcd2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-qrd.dtsi @@ -0,0 +1,436 @@ +#include +#include +#include +#include "bengal-thermal-overlay.dtsi" +#include "bengal-audio-overlay.dtsi" +#include "bengal-sde-display.dtsi" +#include "camera/bengal-camera-sensor-qrd.dtsi" + +&qupv3_se1_i2c { + status = "ok"; + #include "smb1355.dtsi" +}; + +&soc { + qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; +}; + +&pmi632_qg { + qcom,battery-data = <&qrd_batterydata>; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,qg-use-s7-ocv; +}; + +&pmi632_charger { + qcom,battery-data = <&qrd_batterydata>; + qcom,suspend-input-on-debug-batt; + qcom,sw-jeita-enable; + qcom,step-charging-enable; + /* SMB1355 only */ + qcom,sec-charger-config = <2>; + qcom,hvdcp2-max-icl-ua = <2000000>; + dpdm-supply = <&qusb_phy0>; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,auto-recharge-soc = <98>; + qcom,flash-disable-soc = <10>; + qcom,hw-die-temp-mitigation; + qcom,hw-connector-mitigation; + qcom,connector-internal-pull-kohm = <100>; + qcom,float-option = <1>; + qcom,thermal-mitigation = <4200000 3500000 3000000 + 2500000 2000000 1500000 1000000 500000>; +}; + +&pmi632_gpios { + smb_en { + smb_en_default: smb_en_default { + pins = "gpio2"; + function = "func1"; + output-enable; + }; + }; + + pmi632_sense { + /* GPIO 7 and 8 are external-sense pins for PMI632 */ + pmi632_sense_default: pmi632_sense_default { + pins = "gpio7", "gpio8"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; + + pmi632_ctm { + /* Disable GPIO1 for h/w base mitigation */ + pmi632_ctm_default: pmi632_ctm_default { + pins = "gpio1"; + bias-high-impedance; /* disable the GPIO */ + bias-disable; /* no-pull */ + }; + }; +}; + +&pm6125_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio5"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&usb0 { + extcon = <&pmi632_charger>, <&eud>; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x81 0x88 + 0xc7 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x80 0x04 + 0x9f 0x1c + 0x00 0x18>; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6125_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + linux,can-disable; + debounce-interval = <15>; + gpio-key,wakeup; + }; + }; +}; + +&bengal_snd { + qcom,model = "bengal-qrd-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <0>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "SpkrMono WSA_IN", "AUX", + "TX SWR_MIC0", "ADC1_OUTPUT", + "TX SWR_MIC4", "ADC2_OUTPUT", + "TX SWR_MIC5", "ADC3_OUTPUT", + "TX SWR_MIC0", "VA_TX_SWR_CLK", + "TX SWR_MIC1", "VA_TX_SWR_CLK", + "TX SWR_MIC2", "VA_TX_SWR_CLK", + "TX SWR_MIC3", "VA_TX_SWR_CLK", + "TX SWR_MIC4", "VA_TX_SWR_CLK", + "TX SWR_MIC5", "VA_TX_SWR_CLK", + "TX SWR_MIC6", "VA_TX_SWR_CLK", + "TX SWR_MIC7", "VA_TX_SWR_CLK", + "TX SWR_MIC8", "VA_TX_SWR_CLK", + "TX SWR_MIC9", "VA_TX_SWR_CLK", + "TX SWR_MIC10", "VA_TX_SWR_CLK", + "TX SWR_MIC11", "VA_TX_SWR_CLK", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "TX_AIF1 CAP", "VA_TX_SWR_CLK", + "TX_AIF2 CAP", "VA_TX_SWR_CLK", + "TX_AIF3 CAP", "VA_TX_SWR_CLK", + "VA SWR_MIC0", "ADC1_OUTPUT", + "VA SWR_MIC4", "ADC2_OUTPUT", + "VA SWR_MIC5", "ADC3_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + asoc-codec = <&stub_codec>, <&bolero>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_i2c_e>; + qcom,wsa-aux-dev-prefix = "SpkrMono"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd937x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&bolero>, + <&lpi_tlmm>; +}; + +&qupv3_se1_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 70 0x00>; + qcom,nq-ven = <&tlmm 69 0x00>; + qcom,nq-firm = <&tlmm 31 0x00>; + qcom,nq-clkreq = <&tlmm 86 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <70 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&sdhc_1 { + vdd-supply = <&L24A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L11A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L22A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L5A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + vdd-io-bias-supply = <&L7A>; + qcom,vdd-io-bias-voltage-level = <1256000 1256000>; + qcom,vdd-io-bias-current-level = <0 6000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 88 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&tlmm { + smb_int_default: smb_int_default { + mux { + pins = "gpio105"; + function = "gpio"; + }; + + config { + pins = "gpio105"; + bias-pull-up; + input-enable; + }; + }; +}; + +&smb1355 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + interrupt-parent = <&tlmm>; + interrupts = <105 IRQ_TYPE_LEVEL_LOW>; + status = "ok"; +}; + +&smb1355_charger { + pinctrl-names = "default"; + pinctrl-0 = <&smb_en_default &pmi632_sense_default &pmi632_ctm_default>; + qcom,parallel-mode = <1>; + qcom,disable-ctm; + qcom,hw-die-temp-mitigation; + status = "ok"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3-660"; + + vdda-phy-supply = <&L4A>; /* 0.9v */ + vdda-pll-supply = <&L12A>; /* 1.8v */ + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L24A>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&L11A>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + vccq2-pwr-collapse-sup; + + qcom,vddp-ref-clk-supply = <&L18A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1232000>; + qcom,vddp-ref-clk-max-uV = <1232000>; + + status = "ok"; +}; + +&pm6125_pwm { + status = "ok"; +}; + +&dsi_td4330_truly_v2_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm6125_pwm 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-bklight-en-gpio = <&pmi632_gpios 6 0>; +}; + +&dsi_td4330_truly_v2_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm6125_pwm 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-bklight-en-gpio = <&pmi632_gpios 6 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_td4330_truly_v2_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="synaptics,tcm-i2c"; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,irq-gpio = <&tlmm 80 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 71 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware_k.img"; + + panel = <&dsi_td4330_truly_v2_video &dsi_td4330_truly_v2_cmd>; + }; +}; + +&thermal_zones { + quiet-therm-step { + status = "ok"; + }; +}; + +&tlmm { + fpc_reset_int: fpc_reset_int { + fpc_reset_low: reset_low { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + fpc_reset_high: reset_high { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + fpc_int_low: int_low { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + }; +}; + +&soc { + fingerprint: fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <97 0>; + fpc,gpio_rst = <&tlmm 104 0>; + fpc,gpio_irq = <&tlmm 97 0>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&fpc_reset_low>; + pinctrl-1 = <&fpc_reset_high>; + pinctrl-2 = <&fpc_int_low>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-qupv3.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-qupv3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c050d4bc05a6177e927fdac2422b09a263bff938 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-qupv3.dtsi @@ -0,0 +1,214 @@ +#include + +&soc { + /* QUPv3_0 wrapper instance */ + qupv3_0: qcom,qupv3_0_geni_se@4ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x4ac0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + qcom,vote-for-bw; + iommus = <&apps_smmu 0xe3 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + /* GPI Instance */ + gpi_dma0: qcom,gpi-dma@4a00000 { + compatible = "qcom,gpi-dma"; + #dma-cells = <5>; + reg = <0x4a00000 0x60000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0xf>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0xf6 0x0>; + qcom,gpi-ee-offset = <0x10000>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + /* Debug UART Instance */ + qupv3_se4_2uart: qcom,qup_uart@4a90000 { + compatible = "qcom,msm-geni-console"; + reg = <0x4a90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_2uart_active>; + pinctrl-1 = <&qupv3_se4_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* HS UART Instance */ + qupv3_se3_4uart: qcom,qup_uart@4a8c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x4a8c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "active", "sleep"; + pinctrl-0 = <&qupv3_se3_default_ctsrtsrx>, + <&qupv3_se3_default_tx>; + pinctrl-1 = <&qupv3_se3_ctsrx>, <&qupv3_se3_rts>, + <&qupv3_se3_tx>; + pinctrl-2 = <&qupv3_se3_ctsrx>, <&qupv3_se3_rts>, + <&qupv3_se3_tx>; + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; + qcom,wrapper-core = <&qupv3_0>; + qcom,wakeup-byte = <0xFD>; + status = "disabled"; + }; + + /* I2C Instance */ + qupv3_se0_i2c: i2c@4a80000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a80000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* I2C Instance */ + qupv3_se1_i2c: i2c@4a84000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a84000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* I2C Instance */ + qupv3_se2_i2c: i2c@4a88000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a88000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* SPI Instance */ + qupv3_se0_spi: spi@4a80000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a80000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* SPI Instance */ + qupv3_se1_spi: spi@4a84000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a84000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_spi_active>; + pinctrl-1 = <&qupv3_se1_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* SPI Instance */ + qupv3_se5_spi: spi@4a94000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x4a94000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_spi_active>; + pinctrl-1 = <&qupv3_se5_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ba3ca199be62ca86c84ef7e96faa177012864fe2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-regulator.dtsi @@ -0,0 +1,394 @@ +#include +#include + +&rpm_bus { + /* PM6125 S3/S4 - VDD_CX supply */ + rpm-regulator-smpa3 { + status = "okay"; + VDD_CX_LEVEL: + VDD_GFX_LEVEL: + VDD_MSS_LEVEL: + S3A_LEVEL: pm6125_s3_level: regulator-s3-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s3_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + VDD_CX_FLOOR_LEVEL: + VDD_MSS_FLOOR_LEVEL: + S3A_FLOOR_LEVEL: + pm6125_s3_floor_level: regulator-s3-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s3_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + VDD_CX_LEVEL_AO: + VDD_MSS_LEVEL_AO: + S3A_LEVEL_AO: pm6125_s3_level_ao: regulator-s3-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s3_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + cx_cdev: cx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_CX_FLOOR_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + /* PM6125 S5 - VDD_MX/WCSS_MX supply */ + rpm-regulator-smpa5 { + status = "okay"; + VDD_MX_LEVEL: + S5A_LEVEL: pm6125_s5_level: regulator-s5-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s5_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + VDD_MX_FLOOR_LEVEL: + S5A_FLOOR_LEVEL: + pm6125_s5_floor_level: regulator-s5-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s5_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + VDD_MX_LEVEL_AO: + S5A_LEVEL_AO: pm6125_s5_level_ao: regulator-s5-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s5_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MX_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpm-regulator-smpa6 { + status = "okay"; + S6A: pm6125_s6: regulator-s6 { + regulator-min-microvolt = <304000>; + regulator-max-microvolt = <1456000>; + qcom,init-voltage = <304000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa7 { + status = "okay"; + S7A: pm6125_s7: regulator-s7 { + regulator-min-microvolt = <1280000>; + regulator-max-microvolt = <2080000>; + qcom,init-voltage = <1280000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa8 { + status = "okay"; + S8A: pm6125_s8: regulator-s8 { + regulator-min-microvolt = <1064000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1064000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa1 { + status = "okay"; + L1A: pm6125_l1: regulator-l1 { + regulator-min-microvolt = <952000>; + regulator-max-microvolt = <1152000>; + qcom,init-voltage = <952000>; + status = "okay"; + }; + }; + + /* VDD_LPI_MX supply */ + rpm-regulator-ldoa2 { + status = "okay"; + qcom,resource-name = "rwlm"; + qcom,resource-id = <0>; + L2A_LEVEL: pm6125_l2_level: regulator-l2-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l2_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + }; + + /* VDD_LPI_CX supply */ + rpm-regulator-ldoa3 { + status = "okay"; + qcom,resource-name = "rwlc"; + qcom,resource-id = <0>; + L3A_LEVEL: pm6125_l3_level: regulator-l3-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l3_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + }; + + rpm-regulator-ldoa4 { + status = "okay"; + L4A: pm6125_l4: regulator-l4 { + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <488000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa5 { + status = "okay"; + L5A: pm6125_l5: regulator-l5 { + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <3056000>; + qcom,init-voltage = <1648000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + L6A: pm6125_l6: regulator-l6 { + regulator-min-microvolt = <576000>; + regulator-max-microvolt = <656000>; + qcom,init-voltage = <576000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa7 { + status = "okay"; + L7A: pm6125_l7: regulator-l7 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + /* WCSS_CX */ + rpm-regulator-ldoa8 { + status = "okay"; + L8A: pm6125_l8: regulator-l8 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <728000>; + qcom,init-voltage = <400000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa9 { + status = "okay"; + L9A: pm6125_l9: regulator-l9 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + qcom,init-voltage = <1800000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + L10A: pm6125_l10: regulator-l10 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1704000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + L11A: pm6125_l11: regulator-l11 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1952000>; + qcom,init-voltage = <1704000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + L12A: pm6125_l12: regulator-l12 { + regulator-min-microvolt = <1624000>; + regulator-max-microvolt = <1984000>; + qcom,init-voltage = <1624000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + L13A: pm6125_l13: regulator-l13 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <1952000>; + qcom,init-voltage = <1504000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa14 { + status = "okay"; + L14A: pm6125_l14: regulator-l14 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1704000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa15 { + status = "okay"; + L15A: pm6125_l15: regulator-l15 { + regulator-min-microvolt = <2920000>; + regulator-max-microvolt = <3232000>; + qcom,init-voltage = <2920000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa16 { + status = "okay"; + L16A: pm6125_l16: regulator-l16 { + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1704000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa17 { + status = "okay"; + L17A: pm6125_l17: regulator-l17 { + regulator-min-microvolt = <1152000>; + regulator-max-microvolt = <1384000>; + qcom,init-voltage = <1152000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa18 { + status = "okay"; + L18A: pm6125_l18: regulator-l18 { + regulator-min-microvolt = <1104000>; + regulator-max-microvolt = <1312000>; + qcom,init-voltage = <1104000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa19 { + status = "okay"; + L19A: pm6125_l19: regulator-l19 { + regulator-min-microvolt = <1624000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <1624000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa20 { + status = "okay"; + L20A: pm6125_l20: regulator-l20 { + regulator-min-microvolt = <1624000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <1624000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa21 { + status = "okay"; + L21A: pm6125_l21: regulator-l21 { + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <2400000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa22 { + status = "okay"; + L22A: pm6125_l22: regulator-l22 { + regulator-min-microvolt = <2952000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2952000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa23 { + status = "okay"; + L23A: pm6125_l23: regulator-l23 { + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + qcom,init-voltage = <3200000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa24 { + status = "okay"; + L24A: pm6125_l24: regulator-l24 { + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <2704000>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-rumi-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..87c19bae131d0fd74885bdbf226409694b214249 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-rumi-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal RUMI"; + compatible = "qcom,bengal-rumi", "qcom,bengal", "qcom,rumi"; + qcom,msm-id = <417 0x10000>; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-rumi.dts b/arch/arm64/boot/dts/vendor/qcom/bengal-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..b443a84909011f5e80a4474895ec621cabda0770 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-rumi.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/memreserve/ 0x90000000 0x00000100; + +#include "bengal.dtsi" +#include "bengal-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal RUMI"; + compatible = "qcom,bengal-rumi", "qcom,bengal", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-rumi.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..236d76f18caafdde8e2f37eb8bbb503ccb690c0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-rumi.dtsi @@ -0,0 +1,230 @@ +&soc { + usb_emu_phy: usb_emu_phy@4f20000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x04f20000 0x9500>, + <0x04ef8800 0x100>; + reg-names = "base", "qscratch_base"; + + + qcom,emu-init-seq = <0xffff 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x101f0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; + + timer { + clock-frequency = <500000>; + }; + + timer@f120000 { + clock-frequency = <500000>; + }; + + wdog: qcom,wdt@f017000 { + status = "disabled"; + }; + + bi_tcxo: bi_tcxo { + compatible = "fixed-factor-clock"; + clocks = <&xo_board>; + clock-mult = <1>; + clock-div = <1>; + #clock-cells = <0>; + }; + + bi_tcxo_ao: bi_tcxo_ao { + compatible = "fixed-factor-clock"; + clocks = <&xo_board>; + clock-mult = <1>; + clock-div = <1>; + #clock-cells = <0>; + }; + + qmi-tmd-devices { + status = "disabled"; + }; +}; + +&qupv3_se1_i2c { + status = "disabled"; +}; + +&rpm_bus { + rpm-standalone; + /delete-node/ rpm-regulator-smpa3; + /delete-node/ rpm-regulator-smpa5; + /delete-node/ rpm-regulator-smpa6; + /delete-node/ rpm-regulator-smpa7; + /delete-node/ rpm-regulator-smpa8; + /delete-node/ rpm-regulator-ldoa1; + /delete-node/ rpm-regulator-ldoa2; + /delete-node/ rpm-regulator-ldoa3; + /delete-node/ rpm-regulator-ldoa4; + /delete-node/ rpm-regulator-ldoa5; + /delete-node/ rpm-regulator-ldoa6; + /delete-node/ rpm-regulator-ldoa7; + /delete-node/ rpm-regulator-ldoa8; + /delete-node/ rpm-regulator-ldoa9; + /delete-node/ rpm-regulator-ldoa10; + /delete-node/ rpm-regulator-ldoa11; + /delete-node/ rpm-regulator-ldoa12; + /delete-node/ rpm-regulator-ldoa13; + /delete-node/ rpm-regulator-ldoa14; + /delete-node/ rpm-regulator-ldoa15; + /delete-node/ rpm-regulator-ldoa16; + /delete-node/ rpm-regulator-ldoa17; + /delete-node/ rpm-regulator-ldoa18; + /delete-node/ rpm-regulator-ldoa19; + /delete-node/ rpm-regulator-ldoa20; + /delete-node/ rpm-regulator-ldoa21; + /delete-node/ rpm-regulator-ldoa22; + /delete-node/ rpm-regulator-ldoa23; + /delete-node/ rpm-regulator-ldoa24; +}; + +&tsens0 { + status = "disabled"; +}; + +&bcl_sensor { + status = "disabled"; +}; + +&bcl_soc { + status = "disabled"; +}; + +&lmh_cpu_vdd { + status = "disabled"; +}; + +&cxip_cdev { + status = "disabled"; +}; + +&lmh_dcvs0 { + status = "disabled"; +}; + +&lmh_dcvs1 { + status = "disabled"; +}; + +&thermal_zones { + /delete-node/ mapss-lowf; + /delete-node/ camera-lowf; + /delete-node/ pmi632-ibat-lvl0; + /delete-node/ pmi632-ibat-lvl1; + /delete-node/ pmi632-vbat-lvl0; + /delete-node/ pmi632-vbat-lvl1; + /delete-node/ pmi632-vbat-lvl2; + /delete-node/ pmi632-bcl-lvl0; + /delete-node/ pmi632-bcl-lvl1; + /delete-node/ pmi632-bcl-lvl2; +}; + + #include "bengal-stub-regulator.dtsi" + +&sdhc_1 { + vdd-supply = <&L24A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L11A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L22A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L5A>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qrbtc-sdm845"; + + vdda-phy-supply = <&L4A>; /* 0.9v */ + vdda-pll-supply = <&L12A>; /* 1.8v */ + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + + status = "ok"; +}; + +&ufshc_mem { + limit-tx-hs-gear = <1>; + limit-rx-hs-gear = <1>; + scsi-cmd-timeout = <300000>; + + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L24A>; + vccq2-supply = <&L11A>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&L18A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1232000>; + qcom,vddp-ref-clk-max-uV = <1232000>; + + qcom,disable-lpm; + status = "ok"; +}; + +&usb0 { + dpdm-supply = <&usb_nop_phy>; + dwc3@4e00000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + dr_mode = "peripheral"; + }; +}; + +&rpmcc { + compatible = "qcom,dummycc"; + clock-output-names = "rpmcc_clocks"; + #clock-cells = <1>; + #reset-cells = <1>; +}; + +&debugcc { + compatible = "qcom,dummycc"; + clock-output-names = "debugcc_clocks"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d9fcada497f28dc4929429600c32f7717a66b0ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-sde-display.dtsi @@ -0,0 +1,289 @@ +#include "dsi-panel-td4330-truly-v2-singlemipi-fhd-cmd.dtsi" +#include "dsi-panel-td4330-truly-v2-singlemipi-fhd-vid.dtsi" +#include "dsi-panel-nt36525-truly-hd-plus-vid.dtsi" +#include "dsi-panel-r66451-hd-plus-90hz-video.dtsi" +#include "dsi-panel-r66451-hd-plus-90hz-cmd.dtsi" +#include + +&pmi632_gpios { + disp_pins { + disp_pins_default: disp_pins_default { + pins = "gpio6"; + function = "func1"; + qcom,drive-strength = <2>; + power-source = <0>; + bias-disable; + output-low; + }; + }; +}; + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_labibb_amoled: dsi_panel_pwr_supply_labibb_amoled { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdda-3p3"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <13200>; + qcom,supply-disable-load = <80>; + }; + }; + + sde_dsi: qcom,dsi-display-primary { + compatible = "qcom,dsi-display"; + label = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + + clocks = <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,panel-te-source = <0>; + + vddio-supply = <&L9A>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,mdp = <&mdss_mdp>; + + qcom,dsi-default-panel = + <&dsi_td4330_truly_v2_video>; + }; + + sde_wb: qcom,wb-display@0 { + status = "disabled"; + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + msm_notifier: qcom,msm_notifier@0 { + compatible = "qcom,msm-notifier"; + panel = <&dsi_r66451_amoled_hd_90hz_video + &dsi_r66451_amoled_hd_90hz_cmd>; + }; +}; + +&mdss_mdp { + connectors = <&sde_dsi>; +}; + +&dsi_td4330_truly_v2_cmd { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <944315056 928576464 932511112 936445760 940380400>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 1F 09 0B 06 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <40 40 40 40 40 40>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = + [25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 1F 09 0A 06 03 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_td4330_truly_v2_video { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-supported-dfps-list = <60 55 48>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <976190400 988392784 984325320 980257864>; + qcom,dsi-dyn-clk-type = "constant-fps-adjust-vfp"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 1F 09 0A 06 03 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = + [26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 1F 09 0B 06 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt36525_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0a>; + qcom,mdss-dsi-t-clk-pre = <0x21>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [1F 1B 05 06 03 02 04 a0 + 1F 1B 05 06 03 02 04 a0 + 1F 1B 05 06 03 02 04 a0 + 1F 1B 05 06 03 02 04 a0 + 1F 10 04 06 03 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_hd_90hz_video { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [22 1E 07 08 04 02 04 a0 + 22 1E 07 08 04 02 04 a0 + 22 1E 07 08 04 02 04 a0 + 22 1E 07 08 04 02 04 a0 + 22 17 06 07 04 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_hd_90hz_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [22 1E 07 08 04 02 04 a0 + 22 1E 07 08 04 02 04 a0 + 22 1E 07 08 04 02 04 a0 + 22 1E 07 08 04 02 04 a0 + 22 17 06 07 04 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-sde-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..72e4bc6659e05289c16a6791733b7cf09fb6d0fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-sde-pll.dtsi @@ -0,0 +1,32 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi0_pll { + compatible = "qcom,mdss_dsi_pll_14nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0x5e94400 0x588>, + <0x5f03000 0x8>, + <0x5e94200 0x100>; + reg-names = "pll_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + memory-region = <&dfps_data_memory>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-sde.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e94c58e436a5e97b1a36f05333db33111a498ba4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-sde.dtsi @@ -0,0 +1,417 @@ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp { + compatible = "qcom,sde-kms"; + reg = <0x5e00000 0x8f030>, + <0x5eb0000 0x2008>, + <0x5e8f000 0x02c>, + <0xc125ba4 0x20>; + + reg-names = "mdp_phys", + "vbif_phys", + "sid_phys", + "sde_imem_phys"; + + clocks = + <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_THROTTLE_CORE_CLK>, + <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", "throttle_clk", + "div_clk", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 0 0 256000000 19200000 192000000 192000000>; + clock-max-rate = <0 0 0 0 0 384000000 19200000 384000000 + 307000000>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x494>; + + qcom,sde-ctl-off = <0x2000>; + qcom,sde-ctl-size = <0x1dc>; + qcom,sde-ctl-display-pref = "primary"; + + qcom,sde-mixer-off = <0x45000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000>; + qcom,sde-dspp-size = <0xfe4>; + + qcom,sde-intf-off = <0x0 0x6b800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "none", "dsi"; + + qcom,sde-pp-off = <0x71000>; + qcom,sde-pp-size = <0xd4>; + + qcom,sde-dither-off = <0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "dma"; + + qcom,sde-sspp-off = <0x5000 0x25000>; + qcom,sde-sspp-src-size = <0x1f8>; + + qcom,sde-sspp-xin-id = <0 1>; + qcom,sde-sspp-excl-rect = <1 1>; + qcom,sde-sspp-smart-dma-priority = <2 1>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <0>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-mixer-stage-base-layer; + + qcom,sde-max-per-pipe-bw-kbps = <2600000 2600000>; + + qcom,sde-max-per-pipe-bw-high-kbps = <2600000 2600000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2ac 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2048>; + qcom,sde-sspp-linewidth = <2160>; + qcom,sde-mixer-blendstages = <0x4>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x100>; + qcom,sde-ubwc-swizzle = <0x7>; + qcom,sde-ubwc-static = <0x11F>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + + qcom,sde-max-bw-low-kbps = <3100000>; + qcom,sde-max-bw-high-kbps = <4000000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <1>; + qcom,sde-num-nrt-paths = <0>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x2008>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + + /*Pending macrotile & macrotile-qseed has the same configs */ + + qcom,sde-danger-lut = <0x000000ff 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff0>; + qcom,sde-safe-lut-macrotile = <0 0xff00>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xff00>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22335777>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + qcom,sde-secure-sid-mask = <0x0000421>; + qcom,sde-num-mnoc-ports = <1>; + qcom,sde-axi-bus-width = <16>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0x420 0x2>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-earlymap; /* for cont-splash */ + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x421 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 4800000>, + <22 512 0 4800000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + + qcom,sde-limits { + qcom,sde-linewidth-limits { + qcom,sde-limit-name = "sspp_linewidth_usecases"; + qcom,sde-limit-cases = "vig", "dma", "scale"; + qcom,sde-limit-ids= <0x1 0x2 0x4>; + qcom,sde-limit-values = <0x1 4096>, + <0x5 2560>, + <0x2 2160>; + }; + + qcom,sde-bw-limits { + qcom,sde-limit-name = "sde_bwlimit_usecases"; + qcom,sde-limit-cases = "per_vig_pipe", + "per_dma_pipe", + "total_max_bw", + "camera_concurrency"; + qcom,sde-limit-ids = <0x1 0x2 0x4 0x8>; + qcom,sde-limit-values = <0x1 2600000>, + <0x9 2600000>, + <0x2 2600000>, + <0xa 2600000>, + <0x4 4000000>, + <0xc 3100000>; + }; + }; + }; + + mdss_rotator: qcom,mdss_rotator { + compatible = "qcom,sde_rotator"; + reg = <0x5e00000 0xac000>, + <0x5eb0000 0x2008>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 6400000>, + <22 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + /*Offline rotator RT setting */ + qcom,mdss-rot-parent = <&mdss_mdp 0>; + qcom,mdss-rot-xin-id = <10 11>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x43C 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0x43D 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi0_ctrl { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-0"; + cell-index = <0>; + frame-threshold-time-us = <1000>; + reg = <0x5e94000 0x400>, + <0x5f08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&L18A>; + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1232000>; + qcom,supply-max-voltage = <1232000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0 { + compatible = "qcom,dsi-phy-v2.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0x5e94400 0x588>, + <0x5e01400 0x100>, + <0x5e94200 0x100>; + reg-names = "dsi_phy", "phy_clamp_base", + "dyn_refresh_base"; + vdda-0p9-supply = <&VDD_MX_LEVEL>; + qcom,platform-strength-ctrl = [ff 06 + ff 06 + ff 06 + ff 06 + ff 00]; + qcom,platform-lane-config = [00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 8f]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,panel-allow-phy-poweroff; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = + ; + qcom,supply-max-voltage = + ; + qcom,supply-off-min-voltage = + ; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-stub-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-stub-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f0698e7f96411abdc254c8250b31c98ff7cc4c3b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-stub-regulator.dtsi @@ -0,0 +1,263 @@ +#include + +&soc { + S1A: pm6125_s1: regulator-pm6125-s1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <1155000>; + }; + + VDD_CX_LEVEL: + S3A_LEVEL: pm6125_s3_level: regulator-pm6125-s3-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s3_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + VDD_CX_LEVEL_AO: + S3A_LEVEL_AO: pm6125_s3_level_ao: regulator-pm6125-s3-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s3_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + VDD_MX_LEVEL: + S5A_LEVEL: pm6125_s5_level: regulator-pm6125-s5-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s5_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + VDD_MX_LEVEL_AO: + S5A_LEVEL_AO: pm6125_s5_level_ao: regulator-pm6125-s5-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s5_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + S6A: pm6125_s6: regulator-pm6125-s6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <1450000>; + }; + + S7A: pm6125_s7: regulator-pm6125-s7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1270000>; + regulator-max-microvolt = <3369999>; + }; + + S8A: pm6125_s8: regulator-pm6125-s8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_s8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1060000>; + regulator-max-microvolt = <1300000>; + }; + + L1A: pm6125_l1: regulator-pm6125-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1150000>; + }; + + L2A_LEVEL: pm6125_l2_level: regulator-pm6125-l2-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l2_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + L3A_LEVEL: pm6125_l3_level: regulator-pm6125-l3-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l3_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + L4A: pm6125_l4: regulator-pm6125-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <1000000>; + }; + + L5A: pm6125_l5: regulator-pm6125-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3050000>; + }; + + L6A: pm6125_l6: regulator-pm6125-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <570000>; + regulator-max-microvolt = <650000>; + }; + + L7A: pm6125_l7: regulator-pm6125-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + }; + + L8A: pm6125_l8: regulator-pm6125-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <728000>; + }; + + L9A: pm6125_l9: regulator-pm6125-l9 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l9"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + }; + + L10A: pm6125_l10: regulator-pm6125-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + + L11A: pm6125_l11: regulator-pm6125-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1950000>; + }; + + L12A: pm6125_l12: regulator-pm6125-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l12"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + }; + + L13A: pm6125_l13: regulator-pm6125-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l13"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3100000>; + }; + + L14A: pm6125_l14: regulator-pm6125-l14 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l14"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + + L15A: pm6125_l15: regulator-pm6125-l15 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l15"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2300000>; + regulator-max-microvolt = <3600000>; + }; + + L16A: pm6125_l16: regulator-pm6125-l16 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l16"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + + L17A: pm6125_l17: regulator-pm6125-l17 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l17"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1380000>; + }; + + L18A: pm6125_l18: regulator-pm6125-l18 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l18"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1312500>; + }; + + L19A: pm6125_l19: regulator-pm6125-l19 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l19"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + L20A: pm6125_l20: regulator-pm6125-l20 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l20"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + L21A: pm6125_l21: regulator-pm6125-l21 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l21"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3600000>; + }; + + L22A: pm6125_l22: regulator-pm6125-l22 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l22"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3300000>; + }; + + L23A: pm6125_l23: regulator-pm6125-l23 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l23"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + }; + + L24A: pm6125_l24: regulator-pm6125-l24 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6125_l24"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3600000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-thermal-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-thermal-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bfc70d7808e46322ca2af809c5a144252d93cc0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-thermal-overlay.dtsi @@ -0,0 +1,166 @@ +#include + +&thermal_zones { + pmi632-tz { + cooling-maps { + trip0_bat { + trip = <&pmi632_trip0>; + cooling-device = + <&pmi632_charger (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_bat { + trip = <&pmi632_trip1>; + cooling-device = + <&pmi632_charger THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm6125-tz { + cooling-maps { + trip0_cpu0 { + trip = <&pm6125_trip0>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip0_cpu4 { + trip = <&pm6125_trip0>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu1 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + trip1_cpu2 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + trip1_cpu3 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu3_isolate 1 1>; + }; + + trip1_cpu4 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + trip1_cpu5 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu5_isolate 1 1>; + }; + + trip1_cpu6 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + trip1_cpu7 { + trip = <&pm6125_trip1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pmi632-bcl-lvl0 { + cooling-maps { + cpu0_cdev { + trip = <&bcl_lvl0>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-5) + (THERMAL_MAX_LIMIT-5)>; + }; + + cpu4_cdev { + trip = <&bcl_lvl0>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-5) + (THERMAL_MAX_LIMIT-5)>; + }; + }; + }; + + pmi632-bcl-lvl1 { + cooling-maps { + cpu0_cdev { + trip = <&bcl_lvl1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + cpu4_cdev { + trip = <&bcl_lvl1>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + cpu6_cdev { + trip = <&bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + cpu7_cdev { + trip = <&bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pmi632-bcl-lvl2 { + cooling-maps { + cpu4_cdev { + trip = <&bcl_lvl2>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + cpu5_cdev { + trip = <&bcl_lvl2>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + soc { + cooling-maps { + soc_cpu0 { + trip = <&pmi632_low_soc>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + soc_cpu4 { + trip = <&pmi632_low_soc>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + soc_cpu6 { + trip = <&pmi632_low_soc>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + soc_cpu7 { + trip = <&pmi632_low_soc>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-thermal.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d8a3fd1a2c5b2a9e17ea42bb41adf0ea715f5cb4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-thermal.dtsi @@ -0,0 +1,1248 @@ +#include +#include + +&cpufreq_hw { + #address-cells = <1>; + #size-cells = <1>; + lmh_dcvs0: qcom,limits-dcvs@f521000 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + reg = <0xf550800 0x1000>, + <0xf521000 0x1000>; + qcom,no-cooling-device-register; + #thermal-sensor-cells = <0>; + }; + + lmh_dcvs1: qcom,limits-dcvs@f523000 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + reg = <0xf550800 0x1000>, + <0xf523000 0x1000>; + qcom,no-cooling-device-register; + #thermal-sensor-cells = <0>; + }; + + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + + cpu4_isolate: cpu4-isolate { + qcom,cpu = <&CPU4>; + #cooling-cells = <2>; + }; + + cpu5_isolate: cpu5-isolate { + qcom,cpu = <&CPU5>; + #cooling-cells = <2>; + }; + + cpu6_isolate: cpu6-isolate { + qcom,cpu = <&CPU6>; + #cooling-cells = <2>; + }; + + cpu7_isolate: cpu7-isolate { + qcom,cpu = <&CPU7>; + #cooling-cells = <2>; + }; + }; +}; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = ; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + + modem_wlan: modem_wlan { + qcom,qmi-dev-name = "wlan"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = ; + + cdsp_sw: cdsp { + qcom,qmi-dev-name = "cdsp_sw"; + #cooling-cells = <2>; + }; + + cdsp_hw: hvx { + qcom,qmi-dev-name = "cdsp_hw"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = ; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; + + lmh_cpu_vdd: qcom,lmh-cpu-vdd@f550800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0xf550800 0x1000>; + #cooling-cells = <2>; + }; + + cxip_cdev: cxip-cdev@3ed000 { + compatible = "qcom,cxip-lm-cooling-device"; + reg = <0x3ed000 0xc00c>; + qcom,thermal-client-offset = <0x8000>; + /* 4th and 5th offsets to bypass VICTIM1 */ + qcom,bypass-client-list = <0x1004 0x4004 0x6004 0xc004 0xc008>; + #cooling-cells = <2>; + }; +}; + +&thermal_zones { + mapss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cdsp-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + wlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 11>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 12>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 13>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + display-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 14>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 15>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6125_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6125_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6125_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6125_adc_tm_iio ADC_GPIO1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + emmc-ufs-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6125_adc_tm_iio ADC_GPIO2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + chg-skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pmi632_adc_tm ADC_GPIO2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 15>; + wake-capable-sensor; + trips { + gpu_step_trip: gpu-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + gpu_cx_mon: gpu-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev { + trip = <&gpu_step_trip>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + + gpu-cx-cdev0 { + trip = <&gpu_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + gpu-cx-cdev1 { + trip = <&gpu_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + gpu-cx-cdev2 { + trip = <&gpu_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + + gpu-cx-cdev3 { + trip = <&gpu_cx_mon>; + cooling-device = <&cdsp_sw THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + hepta-cpu-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + silver-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + cpuss-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + + trips { + cpu4_5_config: cpu-4-5-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu4_cdev { + trip = <&cpu4_5_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + cpu5_cdev { + trip = <&cpu4_5_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpuss-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 11>; + wake-capable-sensor; + + trips { + cpu6_7_config: cpu-6-7-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu6_cdev { + trip = <&cpu6_7_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + cpu7_cdev { + trip = <&cpu6_7_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + cpuss-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 12>; + wake-capable-sensor; + + trips { + silv_cpus_config: silv-cpus-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu0_cdev { + trip = <&silv_cpus_config>; + cooling-device = <&cpu0_isolate 1 1>; + }; + + cpu1_cdev { + trip = <&silv_cpus_config>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + cpu2_cdev { + trip = <&silv_cpus_config>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + cpu3_cdev { + trip = <&silv_cpus_config>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + cpu-1-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + + trips { + cpu4_config: cpu4-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu4_cdev { + trip = <&cpu4_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + }; + }; + + cpu-1-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + + trips { + cpu5_config: cpu5-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu5_cdev { + trip = <&cpu5_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpu-1-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + + trips { + cpu6_config: cpu6-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu6_cdev { + trip = <&cpu6_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + + trips { + cpu7_config: cpu7-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu7_cdev { + trip = <&cpu7_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + cdsp-hvx-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens0 1>; + thermal-governor = "step_wise"; + wake-capable-sensor; + + trips { + cdsp_trip0: cdsp-trip0 { + temperature = <95000>; + hysteresis = <20000>; + type = "passive"; + }; + + cdsp_trip1: cdsp-trip1 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + cdsp_cx_mon: cdsp-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cxip-cdev { + trip = <&cdsp_trip0>; + cooling-device = <&cxip_cdev 1 1>; + }; + + cdsp-cdev0 { + trip = <&cdsp_trip1>; + cooling-device = <&cdsp_sw THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + + cdsp-cx-cdev0 { + trip = <&cdsp_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + cdsp-cx-cdev1 { + trip = <&cdsp_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + cdsp-cx-cdev2 { + trip = <&cdsp_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + + cdsp-cx-cdev3 { + trip = <&cdsp_cx_mon>; + cooling-device = <&cdsp_sw THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + mdm-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 13>; + wake-capable-sensor; + trips { + mdm0_cx_mon: mdm0-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm0-cx-cdev0 { + trip = <&mdm0_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + mdm0-cx-cdev1 { + trip = <&mdm0_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + mdm0-cx-cdev2 { + trip = <&mdm0_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + + mdm0-cx-cdev3 { + trip = <&mdm0_cx_mon>; + cooling-device = <&cdsp_sw THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + mdm-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + trips { + mdm1_cx_mon: mdm1-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm1-cx-cdev0 { + trip = <&mdm1_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + mdm1-cx-cdev1 { + trip = <&mdm1_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + mdm1-cx-cdev2 { + trip = <&mdm1_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + + mdm1-cx-cdev3 { + trip = <&mdm1_cx_mon>; + cooling-device = <&cdsp_sw THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + mapss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + + trips { + mapss_trip: mapss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cx_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + + mx_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + + modem_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + + adsp_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + }; + }; + + mapss-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + + trips { + mapss_cap_trip: mapss-cap-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu_cdev { + trip = <&mapss_cap_trip>; + cooling-device = <&lmh_cpu_vdd 1 1>; + }; + }; + }; + + camera-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + tracks-low; + + trips { + camera_trip: camera-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + + mx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + + modem_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + + adsp_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + }; + }; + + camera-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + tracks-low; + + trips { + camera_cap_trip: camera-cap-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu_cdev { + trip = <&camera_cap_trip>; + cooling-device = <&lmh_cpu_vdd 1 1>; + }; + }; + }; + + quiet-therm-step { + polling-delay-passive = <2000>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6125_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + status = "disabled"; + + trips { + skin_batt_trip0: batt-trip0 { + temperature = <39000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_modem_trip0: modem-trip0 { + temperature = <40000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_gold_trip: gold-trip { + temperature = <40000>; + hysteresis = <0>; + type = "passive"; + }; + + skin_batt_trip1: batt-trip1 { + temperature = <41000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_silver_trip: silver-trip { + temperature = <41000>; + hysteresis = <0>; + type = "passive"; + }; + + skin_modem_trip1: modem-trip1 { + temperature = <42000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_modem_trip2: modem-trip2 { + temperature = <43000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_batt_trip2: batt-trip2 { + temperature = <43000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_gpu_trip: gpu-trip { + temperature = <43000>; + hysteresis = <0>; + type = "passive"; + }; + + skin_batt_trip3: batt-trip3 { + temperature = <45000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_modem_trip3: modem-trip3 { + temperature = <50000>; + hysteresis = <5000>; + type = "passive"; + }; + + skin_hvx_trip: hvx-trip { + temperature = <52000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + + cooling-maps { + gold_cdev { + trip = <&skin_gold_trip>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-4)>; + }; + + silver_cdev { + trip = <&skin_silver_trip>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-5)>; + }; + + gpu_cdev { + trip = <&skin_gpu_trip>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + hvx_cdev { + trip = <&skin_hvx_trip>; + cooling-device = <&cdsp_sw THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + mdm_cdev0 { + trip = <&skin_modem_trip0>; + cooling-device = <&modem_proc 1 1>; + }; + + mdm_cdev1 { + trip = <&skin_modem_trip1>; + cooling-device = <&modem_pa 1 1>; + }; + + mdm_cdev2 { + trip = <&skin_modem_trip2>; + cooling-device = <&modem_pa 2 2>; + }; + + mdm_cdev3 { + trip = <&skin_modem_trip3>; + cooling-device = <&modem_pa 3 3>; + }; + + mdm_cdev4 { + trip = <&skin_modem_trip3>; + cooling-device = <&modem_proc 3 3>; + }; + + batt_cdev1 { + trip = <&skin_batt_trip0>; + cooling-device = <&pmi632_charger 2 2>; + }; + + batt_cdev2 { + trip = <&skin_batt_trip1>; + cooling-device = <&pmi632_charger 4 4>; + }; + + batt_cdev3 { + trip = <&skin_batt_trip2>; + cooling-device = <&pmi632_charger 6 6>; + }; + + batt_cdev4 { + trip = <&skin_batt_trip3>; + cooling-device = <&pmi632_charger 7 7>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-usb.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f079a7764bc6068a4ef893d1ba9734517db919bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-usb.dtsi @@ -0,0 +1,321 @@ +#include +#include +#include + +&soc { + /* Primary USB port related controller */ + usb0: ssusb@4e00000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x4e00000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x120 0x0>; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x50000000 0x60000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = , + , + ; + interrupt-names = "pwr_event_irq", "ss_phy_irq", "hs_phy_irq"; + + clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "xo", "sleep_clk", "utmi_clk"; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + USB3_GDSC-supply = <&gcc_usb30_prim_gdsc>; + dpdm-supply = <&qusb_phy0>; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,gsi-disable-io-coherency; + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + , + + /* min vote */ + , + , + ; + + dwc3@4e00000 { + compatible = "snps,dwc3"; + reg = <0x4e00000 0xcd00>; + interrupt-parent = <&intc>; + interrupts = ; + usb-phy = <&qusb_phy0>, <&usb_qmp_phy>; + tx-fifo-resize; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <0>; + maximum-speed = "super-speed"; + dr_mode = "otg"; + }; + + qcom,usbbam@0x04f04000 { + compatible = "qcom,usb-bam-msm"; + reg = <0x04f04000 0x17000>; + interrupts = ; + + qcom,usb-bam-fifo-baseaddr = <0xc121000>; + qcom,usb-bam-num-pipes = <4>; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x08064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + }; + + /* Primary USB port related High Speed PHY */ + qusb_phy0: qusb@1613000 { + compatible = "qcom,qusb2phy"; + reg = <0x01613000 0x180>, + <0x003cb250 0x4>, + <0x01b40258 0x4>, + <0x01612000 0x4>; + reg-names = "qusb_phy_base", + "tcsr_clamp_dig_n_1p8", + "tune2_efuse_addr", + "eud_enable_reg"; + + vdd-supply = <&pm6125_l4>; + vdda18-supply = <&pm6125_l12>; + vdda33-supply = <&pm6125_l15>; + qcom,vdd-voltage-level = <0 925000 970000>; + qcom,tune2-efuse-bit-pos = <25>; + qcom,tune2-efuse-num-bits = <4>; + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x81 0x88 + 0xc0 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x80 0x04 + 0x9f 0x1c + 0x00 0x18>; + phy_type = "utmi"; + qcom,phy-clk-scheme = "cmos"; + qcom,major-rev = <1>; + + clocks = <&rpmcc CXO_SMD_OTG_CLK>, + <&gcc GCC_AHB2PHY_USB_CLK>; + clock-names = "ref_clk_src", "cfg_ahb_clk"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + /* Primary USB port related QMP USB PHY */ + usb_qmp_phy: ssphy@1615000 { + compatible = "qcom,usb-ssphy-qmp-usb3-or-dp"; + reg = <0x01615000 0x1000>, + <0x03cb244 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; + + vdd-supply = <&pm6125_l4>; + core-supply = <&pm6125_l12>; + qcom,vdd-voltage-level = <0 925000 970000>; + qcom,core-voltage-level = <0 1800000 1800000>; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + <0xd74 /* USB3_PHY_PCS_STATUS */ + 0xcd8 /* USB3_PHY_AUTONOMOUS_MODE_CTRL */ + 0xcdc /* USB3_PHY_LFPS_RXTERM_IRQ_CLEAR */ + 0xc04 /* USB3_PHY_POWER_DOWN_CONTROL */ + 0xc00 /* USB3_PHY_SW_RESET */ + 0xc08 /* USB3_PHY_START */ + 0xa00>; /* USB3PHY_PCS_MISC_TYPEC_CTRL */ + + clocks = <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&rpmcc CXO_SMD_OTG_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_AHB2PHY_USB_CLK>; + + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "cfg_ahb_clk"; + + resets = <&gcc GCC_USB3_PHY_PRIM_SP0_BCR>, + <&gcc GCC_USB3PHY_PHY_PRIM_SP0_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x1cf 0x0>; + qcom,iommu-dma = "disabled"; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal-vidc.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2e00ba31b410ea299f1ebd92c4881383e6bbcf17 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal-vidc.dtsi @@ -0,0 +1,110 @@ +#include +#include + +&soc { + msm_vidc: qcom,vidc@5a00000 { + compatible = "qcom,msm-vidc", "qcom,bengal-vidc"; + status = "ok"; + reg = <0x5a00000 0x200000>; + interrupts = ; + + /* Supply */ + venus-supply = <&gcc_venus_gdsc>; + venus-core0-supply = <&gcc_vcodec0_gdsc>; + + /* Clocks */ + clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk", "throttle_clk"; + clocks = <&gcc GCC_VIDEO_VENUS_CTL_CLK>, + <&gcc GCC_VIDEO_AHB_CLK>, + <&gcc GCC_VENUS_CTL_AXI_CLK>, + <&gcc GCC_VIDEO_VCODEC0_SYS_CLK>, + <&gcc GCC_VCODEC0_AXI_CLK>, + <&gcc GCC_VIDEO_THROTTLE_CORE_CLK>; + qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk", "throttle_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x0>; + qcom,allowed-clock-rates = <133330000 240000000 300000000 + 384000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "vidc-ar50-ddr"; + qcom,bus-range-kbps = <1000 2128000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&apps_smmu 0x860 0x00>, + <&apps_smmu 0x880 0x00>; + qcom,iommu-dma-addr-pool = <0x70800000 0x6f800000>; + qcom,iommu-faults = "non-fatal"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x6f800000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = + <&apps_smmu 0x861 0x04>; + qcom,iommu-dma-addr-pool = <0x4b000000 0x25800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = + <&apps_smmu 0x863 0x0>; + qcom,iommu-dma-addr-pool = <0x25800000 0x25800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = + <&apps_smmu 0x804 0xE0>; + qcom,iommu-dma-addr-pool = <0x1000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal.dts b/arch/arm64/boot/dts/vendor/qcom/bengal.dts new file mode 100644 index 0000000000000000000000000000000000000000..9ae48674aa9ef43bdcdccaa24aa5605f5d73e845 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengal.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengal SoC"; + compatible = "qcom,bengal"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengal.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..57c71b8e33827cfa958de0c2da85220d6a07d5d7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengal.dtsi @@ -0,0 +1,2948 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + +#define BW_OPP_ENTRY_DDR(mhz, w, ddrtype) opp-mhz {\ + opp-hz = /bits/ 64 ;\ + opp-supported-hw = ;} + +#define DDR_TYPE_LPDDR3 5 +#define DDR_TYPE_LPDDR4X 7 + +/ { + model = "Qualcomm Technologies, Inc. BENGAL"; + compatible = "qcom,bengal"; + qcom,msm-id = <417 0x10000>, <444 0x10000>; + interrupt-parent = <&wakegic>; + + #address-cells = <2>; + #size-cells = <2>; + memory { device_type = "memory"; reg = <0 0 0 0>; }; + + mem-offline { + compatible = "qcom,mem-offline"; + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>, + <0x2 0xc0000000 0x1 0x40000000>; + granule = <512>; + }; + + aliases { + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + swr0 = &swr0; + swr1 = &swr1; + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 7>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 7>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + + L1_I_1: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_1: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 7>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + + L1_I_2: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_2: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 7>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + + L1_I_3: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_3: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + capacity-dmips-mhz = <1638>; + dynamic-power-coefficient = <282>; + next-level-cache = <&L2_1>; + qcom,freq-domain = <&cpufreq_hw 1 7>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + L2_1: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x101>; + capacity-dmips-mhz = <1638>; + dynamic-power-coefficient = <282>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + qcom,freq-domain = <&cpufreq_hw 1 7>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + + L1_I_101: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_101: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x102>; + capacity-dmips-mhz = <1638>; + dynamic-power-coefficient = <282>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + qcom,freq-domain = <&cpufreq_hw 1 7>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + + L1_I_102: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_102: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x103>; + capacity-dmips-mhz = <1638>; + dynamic-power-coefficient = <282>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + qcom,freq-domain = <&cpufreq_hw 1 7>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + + L1_I_103: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_103: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible="android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo,recovery"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/4744000.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_mem: hyp_region@45700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45700000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_region@45e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45e00000 0x0 0x140000>; + }; + + sec_apps_mem: sec_apps_region@45fff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45fff000 0x0 0x1000>; + }; + + smem_mem: smem_region@46000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x46000000 0x0 0x200000>; + }; + + removed_mem: removed_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x3900000>; + }; + + pil_modem_mem: modem_region@4ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x4ab00000 0x0 0x6900000>; + }; + + pil_video_mem: pil_video_region@51400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51400000 0x0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@51900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51900000 0x0 0x100000>; + }; + + pil_cdsp_mem: cdsp_regions@51a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51a00000 0x0 0x1e00000>; + }; + + pil_adsp_mem: pil_adsp_region@53800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53800000 0x0 0x1e00000>; + }; + + pil_ipa_fw_mem: ipa_fw_region@55600000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x55600000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@55610000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x55610000 0x0 0x5000>; + }; + + pil_gpu_mem: gpu_region@55615000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x55615000 0x0 0x2000>; + }; + + user_contig_mem: user_contig_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + cdsp_sec_mem: cdsp_sec_regions@46200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x46200000 0x0 0x1e00000>; + }; + + secure_display_memory: secure_display_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x5c00000>; + }; + + cont_splash_memory: cont_splash_region@5c000000 { + reg = <0x0 0x5c000000 0x0 0x00f00000>; + label = "cont_splash_region"; + }; + + disp_rdump_memory: disp_rdump_region@5c000000 { + reg = <0x0 0x5c000000 0x0 0x00f00000>; + label = "disp_rdump_region"; + }; + + dfps_data_memory: dfps_data_region@5cf00000 { + reg = <0x0 0x5cf00000 0x0 0x0100000>; + label = "dfps_data_region"; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + size = <0 0x800000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x2000000>; + linux,cma-default; + }; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + }; + + soc: soc { }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + intc: interrupt-controller@f200000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + interrupt-parent = <&intc>; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0xf200000 0x10000>, /* GICD */ + <0xf300000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + }; + + jtag_mm0: jtagmm@9040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@9140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@9240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@9340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@9440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@9540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@9640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@9740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; + }; + + slim_aud: slim@a5c0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0xa5c0000 0x2c000>, + <0xa584000 0x20000>, <0xa66e000 0x2000>; + reg-names = "slimbus_physical", + "slimbus_bam_physical", "slimbus_lpass_mem"; + interrupts = , + ; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x0>; + qcom,ea-pc = <0x360>; + status = "ok"; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + wakegic: wake-gic { + compatible = "qcom,mpm-gic-bengal", "qcom,mpm-gic"; + interrupts-extended = <&wakegic GIC_SPI 197 + IRQ_TYPE_EDGE_RISING>; + reg = <0x45f01b8 0x1000>, + <0xf011008 0x4>; /* MSM_APCS_GCC_BASE 4K */ + reg-names = "vmpm", "ipc"; + qcom,num-mpm-irqs = <96>; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <3>; + }; + + wakegpio: wake-gpio { + compatible = "qcom,mpm-gpio"; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <2>; + }; + + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&L9A>; /* IO */ + qca,bt-vdd-core-supply = <&L17A>; /* RFA */ + qca,bt-vdd-pa-supply = <&L23A>; /* CH0 */ + qca,bt-vdd-xtal-supply = <&L16A>; /* XO */ + + qca,bt-vdd-io-voltage-level = <1700000 1900000>; + qca,bt-vdd-core-voltage-level = <1304000 1304000>; + qca,bt-vdd-pa-voltage-level = <3000000 3312000>; + qca,bt-vdd-xtal-voltage-level = <1700000 1900000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + dcc: dcc_v2@1be2000 { + compatible = "qcom,dcc-v2"; + reg = <0x1be2000 0x1000>, + <0x1bee000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + dcc-ram-offset = <0x2000>; + }; + + timer@f120000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0xf120000 0x1000>; + clock-frequency = <19200000>; + + frame@f121000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0xf121000 0x1000>, + <0xf122000 0x1000>; + }; + + frame@f123000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0xf123000 0x1000>; + status = "disabled"; + }; + + frame@f124000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0xf124000 0x1000>; + status = "disabled"; + }; + + frame@f125000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0xf125000 0x1000>; + status = "disabled"; + }; + + frame@f126000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0xf126000 0x1000>; + status = "disabled"; + }; + + frame@f127000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0xf127000 0x1000>; + status = "disabled"; + }; + + frame@f128000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0xf128000 0x1000>; + status = "disabled"; + }; + }; + + arm64_cpu_erp { + compatible = "arm,arm64-cpu-erp"; + interrupt-names = "pri-dbe-irq", + "sec-dbe-irq", + "pri-ext-irq", + "sec-ext-irq"; + interrupts = <0 43 4>, + <0 44 4>, + <0 41 4>, + <0 42 4>; + poll-delay-ms = <5000>; + }; + + l2cache_pmu { + #address-cells = <1>; + #size-cells = <1>; + compatible = "qcom,l2cache-pmu"; + ranges; + + cluster0@f111000 { + cluster-id = <0>; + interrupts = ; + reg = <0xf111000 0x1000>; + }; + + cluster1@f011000 { + cluster-id = <1>; + interrupts = ; + reg = <0xf011000 0x1000>; + }; + }; + + qcom,msm-imem@c125000 { + compatible = "qcom,msm-imem"; + reg = <0xc125000 0x1000>; + ranges = <0x0 0xc125000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 0x8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 0x4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 0x20>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 0xc>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 0xc8>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 0xc8>; + }; + }; + + restart@440b000 { + compatible = "qcom,pshold"; + reg = <0x440b000 0x4>, + <0x03d3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom_seecom: qseecom@61800000 { + compatible = "qcom,qseecom"; + reg = <0x61800000 0x2100000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,fde-key-size; + qcom,appsbl-qseecom-support; + qcom,commonlib64-loaded-by-uefi; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + clock-names = + "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = + <&rpmcc QSEECOM_CE1_CLK>, + <&rpmcc QSEECOM_CE1_CLK>, + <&rpmcc QSEECOM_CE1_CLK>, + <&rpmcc QSEECOM_CE1_CLK>; + qcom,ce-opp-freq = <192000000>; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + compatible = "qcom,smcinvoke"; + reg = <0x61800000 0x2100000>; + reg-names = "secapp-region"; + }; + + qcom_rng: qrng@1b53000 { + compatible = "qcom,msm-rng"; + reg = <0x1b53000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , /* No vote */ + ; /* 75 MHz */ + clocks = <&gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + + qcom_tzlog: tz-log@c125720 { + compatible = "qcom,tz-log"; + reg = <0xc125720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_cedev: qcedev@1b20000 { + compatible = "qcom,qcedev"; + reg = <0x1b20000 0x20000>, + <0x1b04000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + clock-names = + "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = + <&rpmcc QCEDEV_CE1_CLK>, + <&rpmcc QCEDEV_CE1_CLK>, + <&rpmcc QCEDEV_CE1_CLK>, + <&rpmcc QCEDEV_CE1_CLK>; + qcom,ce-opp-freq = <192000000>; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x0086 0x0011>, + <&apps_smmu 0x0096 0x0011>; + qcom,iommu-dma = "atomic"; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&apps_smmu 0x92 0>, + <&apps_smmu 0x98 0x1>, + <&apps_smmu 0x9F 0>; + qcom,iommu-dma-addr-pool = <0x70000000 0X10000000>; + }; + + qcom_cedev_s_cb { + compatible = "qcom,qcedev,context-bank"; + label = "secure_context"; + iommus = <&apps_smmu 0x93 0>, + <&apps_smmu 0x9C 0x1>, + <&apps_smmu 0x9E 0>; + qcom,iommu-dma-addr-pool = <0x70000000 0X10000000>; + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ + qcom,secure-context-bank; + }; + }; + + qcom_crypto: qcrypto@1b20000 { + compatible = "qcom,qcrypto"; + reg = <0x1b20000 0x20000>, + <0x1b04000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + clock-names = + "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = + <&rpmcc QCRYPTO_CE1_CLK>, + <&rpmcc QCRYPTO_CE1_CLK>, + <&rpmcc QCRYPTO_CE1_CLK>, + <&rpmcc QCRYPTO_CE1_CLK>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x0084 0x0011>, + <&apps_smmu 0x0094 0x0011>; + qcom,iommu-dma = "atomic"; + }; + + qcom,mpm2-sleep-counter@4403000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x4403000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 6 4>; + }; + + eud: qcom,msm-eud@1610000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x1610000 0x2000>, + <0x1612000 0x1000>, + <0x3E5018 0x4>; + reg-names = "eud_base", "eud_mode_mgr2", + "eud_tcsr_check_reg"; + qcom,secure-eud-en; + qcom,eud-tcsr-check-enable; + qcom,eud-clock-vote-req; + clocks = <&gcc GCC_AHB2PHY_USB_CLK>; + clock-names = "eud_ahb2phy_clk"; + status = "ok"; + }; + + qcom,msm-gladiator-v2@f100000 { + compatible = "qcom,msm-gladiator-v2"; + reg = <0xf100000 0xdc00>; + reg-names = "gladiator_base"; + interrupts = ; + clock-names = "atb_clk"; + clocks = <&rpmcc RPM_QDSS_CLK>; + }; + + wdog: qcom,wdt@f017000 { + compatible = "qcom,msm-watchdog"; + reg = <0xf017000 0x1000>; + reg-names = "wdt-base"; + interrupts = , + ; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; + + rpm_bus: qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + rpm-channel-name = "rpm_requests"; + interrupts = ; + rpm-channel-type = <15>; /* SMD_APPS_RPM */ + }; + + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x0f1880b0 0x0f1980b0 + 0x0f1a80b0 0x0f1b80b0>; + qcom,config-arr = <0x0f1880b8 0x0f1980b8 + 0x0f1a80b8 0x0f1b80b8>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x0f0880b0 0x0f0980b0 + 0x0f0a80b0 0x0f0b80b0>; + qcom,config-arr = <0x0f0880b8 0x0f0980b8 + 0x0f0a80b8 0x0f0b80b8>; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect"; + qcom,threshold-arr = <0x0f1d141c 0x0f1d1420 + 0x0f1d1424 0x0f1d1428 + 0x0f1d142c 0x0f1d1430>; + qcom,config-reg = <0x0f1d1434>; + }; + + qcom,lpass@ab00000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xab00000 0x00100>; + + vdd_lpi_cx-supply = <&L3A_LEVEL>; + qcom,proxy-reg-names = "vdd_lpi_cx", "vdd_lpi_mx"; + qcom,vdd_lpi_cx-uV-uA = ; + vdd_lpi_mx-supply = <&L2A_LEVEL>; + qcom,vdd_lpi_mx-uV-uA = ; + + clocks = <&rpmcc CXO_SMD_PIL_LPASS_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + qcom,mas-crypto = <&mas_crypto_c0>; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,minidump-id = <5>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + qcom,complete-ramdump; + qcom,minidump-as-elf32; + + /* Inputs from lpass */ + interrupts-extended = <&intc 0 282 1>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + qcom,turing@b300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xb300000 0x100000>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&rpmcc CXO_SMD_PIL_CDSP_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + qcom,mas-crypto = <&mas_crypto_c0>; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,minidump-id = <7>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&pil_cdsp_mem>; + qcom,complete-ramdump; + qcom,minidump-as-elf32; + + /* Inputs from turing */ + interrupts-extended = <&intc 0 265 1>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + c0_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x0>; + }; + + c1_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x1>; + }; + + c2_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x2>; + }; + + c3_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x3>; + }; + + c100_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x4>; + }; + + c101_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x5>; + }; + + c102_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x6>; + }; + + c103_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x7>; + }; + + c_scandump { + qcom,dump-size = <0x40000>; + qcom,dump-id = <0xeb>; + }; + + l1_icache0 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x60>; + }; + + l1_icache1 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x61>; + }; + + l1_icache2 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x62>; + }; + + l1_icache3 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x63>; + }; + + l1_icache100 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x64>; + }; + + l1_icache101 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x65>; + }; + + l1_icache102 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x66>; + }; + + l1_icache103 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x67>; + }; + + l1_dcache0 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x80>; + }; + + l1_dcache1 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x81>; + }; + + l1_dcache2 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x82>; + }; + + l1_dcache3 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x83>; + }; + + l1_dcache100 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x84>; + }; + + l1_dcache101 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x85>; + }; + + l1_dcache102 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x86>; + }; + + l1_dcache103 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x87>; + }; + + l2_tlb0 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x120>; + }; + + l2_tlb1 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x121>; + }; + + l2_tlb2 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x122>; + }; + + l2_tlb3 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x123>; + }; + + l2_tlb100 { + qcom,dump-size = <0x4800>; + qcom,dump-id = <0x124>; + }; + + l2_tlb101 { + qcom,dump-size = <0x4800>; + qcom,dump-id = <0x125>; + }; + + l2_tlb102 { + qcom,dump-size = <0x4800>; + qcom,dump-id = <0x126>; + }; + + l2_tlb103 { + qcom,dump-size = <0x4800>; + qcom,dump-id = <0x127>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xe4>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + tmc_etf { + qcom,dump-size = <0x8000>; + qcom,dump-id = <0xf0>; + }; + + etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + etf_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x101>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + }; + + sdhc_1: sdhci@4744000 { + compatible = "qcom,sdhci-msm-v5", "qcom,sdhci-msm-cqe"; + reg = <0x4744000 0x1000>, <0x4745000 0x1000>, + <0x4748000 0x8000>; + reg-names = "hc_mem", "cqhci_mem", "cqhci_ice"; + + interrupts-extended = <&intc GIC_SPI 348 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 19 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "hc_irq", "pwr_irq", "tb_trig_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <78 512 0 0>, <1 606 0 0>, + /* 400 KB/s*/ + <78 512 1046 1600>, + <1 606 1600 1600>, + /* 20 MB/s */ + <78 512 20480 80000>, + <1 606 80000 80000>, + /* 25 MB/s */ + <78 512 25600 250000>, + <1 606 50000 133320>, + /* 50 MB/s */ + <78 512 51200 250000>, + <1 606 65000 133320>, + /* 100 MB/s */ + <78 512 102400 250000>, + <1 606 65000 133320>, + /* 200 MB/s */ + <78 512 204800 800000>, + <1 606 200000 300000>, + /* 400 MB/s */ + <78 512 204800 800000>, + <1 606 200000 300000>, + /* Max. bandwidth */ + <78 512 1338562 4096000>, + <1 606 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 400000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <26 26>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cmdq-latency-us = <26 26>, <26 26>; + qcom,pm-qos-legacy-latency-us = <26 26>, <26 26>; + + clocks = <&gcc GCC_SDCC1_AHB_CLK>, + <&gcc GCC_SDCC1_APPS_CLK>, + <&gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,ice-clk-rates = <300000000 100000000>; + + /* Add support for gcc hw reset */ + resets = <&gcc GCC_SDCC1_BCR>; + reset-names = "core_reset"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x000f642c 0x0 0x0 0x00010800 0x80040850>; + + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@4784000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x4784000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 202000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 202000000>; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 3200>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 250000>, + <1 608 80000 133320>, + /* 25 MB/s */ + <81 512 65360 250000>, + <1 608 100000 133320>, + /* 50 MB/s */ + <81 512 130718 250000>, + <1 608 133320 133320>, + /* 100 MB/s */ + <81 512 261438 250000>, + <1 608 150000 133320>, + /* 200 MB/s */ + <81 512 261438 800000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <26 26>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-legacy-latency-us = <26 26>, <26 26>; + + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642c 0x0 0x0 0x00010800 0x80040868>; + + status = "disabled"; + }; + + ufsphy_mem: ufsphy_mem@4807000 { + reg = <0x4807000 0xdb8>; /* PHY regs */ + reg-names = "phy_mem"; + #phy-cells = <0>; + + lanes-per-direction = <1>; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, + <&gcc GCC_UFS_CLKREF_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + + status = "disabled"; + }; + + ufshc_mem: ufshc@4804000 { + compatible = "qcom,ufshc"; + reg = <0x4804000 0x3000>, <0x4810000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; + interrupts = ; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + + lanes-per-direction = <1>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + spm-level = <5>; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk"; + clocks = + <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_SYS_NOC_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&rpmcc RPM_SMD_XO_CLK_SRC>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cpu-group-latency-us = <26 26>; + qcom,pm-qos-default-cpu = <0>; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + non-removable; + + status = "disabled"; + }; + + thermal_zones: thermal-zones {}; + + tsens0:tsens@c222000 { + compatible = "qcom,tsens24xx"; + reg = <0x04410000 0x8>, + <0x04411000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 275 0>, <0 190 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + clocks { + xo_board: xo_board { + compatible = "fixed-clock"; + clock-frequency = <19200000>; + clock-output-names = "xo_board"; + #clock-cells = <0>; + }; + + sleep_clk: sleep_clk { + compatible = "fixed-clock"; + clock-frequency = <32764>; + clock-output-names = "sleep_clk"; + #clock-cells = <0>; + }; + }; + + rpmcc: qcom,rpmcc { + compatible = "qcom,rpmcc-bengal"; + #clock-cells = <1>; + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + qcom,vm-nav-path; + }; + + gcc: qcom,gcc@1400000 { + compatible = "qcom,bengal-gcc", "syscon"; + reg = <0x1400000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + dispcc: qcom,dispcc@5f00000 { + compatible = "qcom,bengal-dispcc", "syscon"; + reg = <0x05f00000 0x20000>; + reg-names = "cc_base"; + clock-names = "cfg_ahb_clk"; + clocks = <&gcc GCC_DISP_AHB_CLK>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + gpucc: qcom,gpucc@5990000 { + compatible = "qcom,bengal-gpucc", "syscon"; + reg = <0x5990000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + mccc_debug: syscon@447d200 { + compatible = "syscon"; + reg = <0x447d200 0x100>; + }; + + cpucc_debug: syscon@f11101c { + compatible = "syscon"; + reg = <0xf11101c 0x4>; + }; + + debugcc: qcom,cc-debug { + compatible = "qcom,bengal-debugcc"; + qcom,gcc = <&gcc>; + qcom,dispcc = <&dispcc>; + qcom,gpucc = <&gpucc>; + qcom,mccc = <&mccc_debug>; + qcom,cpucc = <&cpucc_debug>; + clock-names = "xo_clk_src"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + #clock-cells = <1>; + }; + + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw"; + reg = <0xf521000 0x1000>, <0xf523000 0x1000>; + reg-names = "freq-domain0", "freq-domain1"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&gcc GPLL0>; + clock-names = "xo", "alternate"; + qcom,no-accumulative-counter; + qcom,max-lut-entries = <12>; + #freq-domain-cells = <2>; + }; + + tcsr_mutex_block: syscon@00340000 { + compatible = "syscon"; + reg = <0x340000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; + }; + + rpm_msg_ram: memory@045f0000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0x45f0000 0x7000>; + }; + + apcs_glb: mailbox@0f111000 { + compatible = "qcom,bengal-apcs-hmss-global"; + reg = <0xF111000 0x1000>; + + #mbox-cells = <1>; + }; + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,rpc-latency-us = <611>; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x0C01 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x0C02 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x0C03 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x0C04 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x0C05 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x0C06 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x0C09 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C3 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C4 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C5 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb13 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C6 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb14 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C7 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + + qcom,rpm_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; + + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "mpss_smem"; + interrupts = ; + + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 8>; + mbox-names = "adsp_smem"; + interrupts = ; + + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apcs_glb 28>; + mbox-names = "cdsp_smem"; + interrupts = ; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x20 12>; + + msm_cdsp_rm: qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <100>; + qcom,qos-maxhold-ms = <20>; + }; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + mboxes = <&apcs_glb 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_wlan_1_in: qcom,smp2p-wlan-1-in { + qcom,entry-name = "wlan"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + mboxes = <&apcs_glb 10>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + mboxes = <&apcs_glb 30>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg5_out: qcom,smp2p-rdbg5-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_in: qcom,smp2p-rdbg5-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + + qfprom: qfprom@1b40000 { + compatible = "qcom,qfprom"; + reg = <0x1b40000 0x7000>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + ranges; + + stm_debug_fuse: stm@20f0 { + reg = <0x20f0 0x4>; + }; + + feat_conf5: feat_conf5@6018 { + reg = <0x6018 0x4>; + }; + + feat_conf10: feat_conf10@602c { + reg = <0x602c 0x4>; + }; + + adsp_variant: adsp_variant@6011 { + reg = <0x6011 0x1>; + bits = <3 1>; + }; + + gpu_speed_bin: gpu_speed_bin@6006 { + reg = <0x6006 0x2>; + bits = <5 8>; + }; + + gpu_gaming_bin: gpu_gaming_bin@602d { + reg = <0x602d 0x1>; + bits = <5 1>; + }; + }; + + spmi_bus: qcom,spmi@1c40000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x1c40000 0x1100>, + <0x1e00000 0x2000000>, + <0x3e00000 0x100000>, + <0x3f00000 0xa0000>, + <0x1c0a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + icnss: qcom,icnss@C800000 { + compatible = "qcom,icnss"; + reg = <0xC800000 0x800000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x1A0 0x1>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-faults = "stall-disable", "HUPCF"; + qcom,iommu-geometry = <0xa0000000 0x10010000>; + vdd-cx-mx-supply = <&L8A>; + vdd-1.8-xo-supply = <&L16A>; + vdd-1.3-rfa-supply = <&L17A>; + vdd-3.3-ch0-supply = <&L23A>; + qcom,vdd-cx-mx-config = <640000 640000>; + qcom,vdd-3.3-ch0-config = <3000000 3312000>; + qcom,smp2p_map_wlan_1_in { + interrupts-extended = <&smp2p_wlan_1_in 0 0>, + <&smp2p_wlan_1_in 1 0>; + interrupt-names = "qcom,smp2p-force-fatal-error", + "qcom,smp2p-early-crash-ind"; + }; + }; + + qcom,venus@5ab0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x5ab0000 0x20000>; + + vdd-supply = <&gcc_venus_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&gcc GCC_VIDEO_VENUS_CTL_CLK>, + <&gcc GCC_VENUS_CTL_AXI_CLK>, + <&gcc GCC_VIDEO_AHB_CLK>, + <&gcc GCC_VIDEO_THROTTLE_CORE_CLK>; + clock-names = "core_clk", "bus_clk", "iface_clk", "throttle_clk"; + qcom,proxy-clock-names = "core_clk", "bus_clk", "iface_clk", "throttle_clk"; + qcom,mas-crypto = <&mas_crypto_c0>; + + qcom,core-freq = <240000000>; + qcom,ahb-freq = <240000000>; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + }; + + cx_ipeak_lm: cx_ipeak@3ed000 { + compatible = "qcom,cx-ipeak-v2"; + reg = <0x3ed000 0xe008>; + }; + + pil_modem: qcom,mss@6080000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x6080000 0x100>; + + clocks = <&rpmcc CXO_SMD_PIL_MSS_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + qcom,mas-crypto = <&mas_crypto_c0>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,vdd_cx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx"; + + qcom,firmware-name = "modem"; + memory-region = <&pil_modem_mem>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,pas-id = <4>; + qcom,smem-id = <421>; + qcom,minidump-id = <3>; + qcom,aux-minidump-ids = <4>; + qcom,complete-ramdump; + qcom,sequential-fw-load; + + qcom,msm-bus,name = "pil-modem"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + + /* Inputs from mss */ + interrupts-extended = <&intc 0 307 1>, + <&modem_smp2p_in 0 0>, + <&modem_smp2p_in 2 0>, + <&modem_smp2p_in 1 0>, + <&modem_smp2p_in 3 0>, + <&modem_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* Outputs to mss */ + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY_DDR( 200, 8, 0xA0); /* 1525 MB/s */ + BW_OPP_ENTRY_DDR( 300, 8, 0xA0); /* 2288 MB/s */ + BW_OPP_ENTRY_DDR( 451, 8, 0xA0); /* 3440 MB/s */ + BW_OPP_ENTRY_DDR( 547, 8, 0xA0); /* 4173 MB/s */ + BW_OPP_ENTRY_DDR( 681, 8, 0xA0); /* 5195 MB/s */ + BW_OPP_ENTRY_DDR( 768, 8, 0xA0); /* 5859 MB/s */ + BW_OPP_ENTRY_DDR( 931, 8, 0x20); /* 7102 MB/s */ + BW_OPP_ENTRY_DDR(1017, 8, 0x80); /* 7759 MB/s */ + BW_OPP_ENTRY_DDR(1353, 8, 0x80); /*10322 MB/s */ + BW_OPP_ENTRY_DDR(1555, 8, 0x80); /*11863 MB/s */ + BW_OPP_ENTRY_DDR(1804, 8, 0x80); /*13763 MB/s */ + }; + + suspendable_ddr4_bw_opp_table: suspendable-ddr4-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY_DDR( 0, 8, 0xA0); /* 0 MB/s */ + BW_OPP_ENTRY_DDR( 200, 8, 0xA0); /* 1525 MB/s */ + BW_OPP_ENTRY_DDR( 300, 8, 0xA0); /* 2288 MB/s */ + BW_OPP_ENTRY_DDR( 451, 8, 0xA0); /* 3440 MB/s */ + BW_OPP_ENTRY_DDR( 547, 8, 0xA0); /* 4173 MB/s */ + BW_OPP_ENTRY_DDR( 681, 8, 0xA0); /* 5195 MB/s */ + BW_OPP_ENTRY_DDR( 768, 8, 0xA0); /* 5859 MB/s */ + BW_OPP_ENTRY_DDR( 931, 8, 0x20); /* 7102 MB/s */ + BW_OPP_ENTRY_DDR(1017, 8, 0x80); /* 7759 MB/s */ + BW_OPP_ENTRY_DDR(1353, 8, 0x80); /*10322 MB/s */ + BW_OPP_ENTRY_DDR(1555, 8, 0x80); /*11863 MB/s */ + BW_OPP_ENTRY_DDR(1804, 8, 0x80); /*13763 MB/s */ + }; + + cpu_cpu_ddr_bw: qcom,cpu-cpu-ddr-bw { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_cpu_ddr_bwmon: qcom,cpu-cpu-ddr-bwmon@01b8e200 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x01b8e300 0x100>, <0x01b8e200 0x100>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_cpu_ddr_lat: qcom,cpu0-cpu-ddr-lat { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_memlat_cpugrp: qcom,cpu0-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + + cpu0_cpu_ddr_latmon: qcom,cpu0-cpu-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,stall-cycle-ev = <0xE7>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 864000 MHZ_TO_MBPS(200, 8) >, + < 1305600 MHZ_TO_MBPS(451, 8) >, + < 1804800 MHZ_TO_MBPS(768, 8) >; + }; + + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 864000 MHZ_TO_MBPS( 300, 8) >, + < 1305600 MHZ_TO_MBPS( 547, 8) >, + < 1420000 MHZ_TO_MBPS( 768, 8) >, + < 1804800 MHZ_TO_MBPS(1017, 8) >; + }; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 614400 MHZ_TO_MBPS( 200, 8) >, + < 1305600 MHZ_TO_MBPS( 451, 8) >, + < 1804800 MHZ_TO_MBPS( 768, 8) >; + }; + + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 614400 MHZ_TO_MBPS( 300, 8) >, + < 1017600 MHZ_TO_MBPS( 451, 8) >, + < 1420000 MHZ_TO_MBPS( 547, 8) >, + < 1804800 MHZ_TO_MBPS( 768, 8) >; + }; + }; + }; + + cpu4_cpu_ddr_lat: qcom,cpu4-cpu-ddr-lat { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu4_cpu_ddr_latfloor: qcom,cpu4-cpu-ddr-latfloor { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu4_memlat_cpugrp: qcom,cpu4-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + + cpu4_cpu_ddr_latmon: qcom,cpu4-cpu-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_cpu_ddr_lat>; + qcom,cachemiss-ev = <0x17>; + qcom,stall-cycle-ev = <0x24>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 1056000 MHZ_TO_MBPS(200, 8) >, + < 1401600 MHZ_TO_MBPS(451, 8) >, + < 1804800 MHZ_TO_MBPS(768, 8) >, + < 2016000 MHZ_TO_MBPS(931, 8) >; + }; + + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 902400 MHZ_TO_MBPS( 451, 8) >, + < 1401600 MHZ_TO_MBPS(1017, 8) >, + < 1804800 MHZ_TO_MBPS(1555, 8) >, + < 2016000 MHZ_TO_MBPS(1804, 8) >; + }; + }; + + cpu4_computemon: qcom,cpu4-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_cpu_ddr_latfloor>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 652800 MHZ_TO_MBPS( 200, 8) >, + < 1056000 MHZ_TO_MBPS( 451, 8) >, + < 1401600 MHZ_TO_MBPS( 547, 8) >, + < 1536000 MHZ_TO_MBPS( 768, 8) >, + < 2016000 MHZ_TO_MBPS( 931, 8) >; + }; + + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 902400 MHZ_TO_MBPS( 300, 8) >, + < 1056000 MHZ_TO_MBPS( 547, 8) >, + < 1401680 MHZ_TO_MBPS( 768, 8) >, + < 1804800 MHZ_TO_MBPS(1017, 8) >, + < 2016000 MHZ_TO_MBPS(1804, 8) >; + }; + }; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-platform-type-msm; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + ipa_hw: qcom,ipa@0x5800000 { + compatible = "qcom,ipa"; + reg = <0x5800000 0x34000>, + <0x5804000 0x28000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = <0 257 0>, <0 259 0>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <16>; /* IPA core version = IPAv4.2 */ + qcom,ipa-hw-mode = <0>; + qcom,platform-type = <1>; /* MSM platform */ + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,ipa-wdi2_over_gsi; + qcom,ipa-endp-delay-wa; + qcom,ipa-fltrt-not-hashable; + qcom,use-64-bit-dma-mask; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,use-ipa-pm; + qcom,skip-ieob-mask-wa; + clocks = <&rpmcc RPM_SMD_IPA_CLK>; + clock-names = "core_clk"; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + , + , + , + /* SVS2 */ + , + , + , + /* SVS */ + , + , + , + /* NOMINAL */ + , + , + , + /* TURBO */ + , + , + ; + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x0140 0x0>; + qcom,iommu-dma-addr-pool = <0x10000000 0x30000000>; + /* modem tables in IMEM */ + qcom,iommu-dma = "fastmap"; + qcom,additional-mapping = <0x0c123000 0x0c123000 0x2000>; + qcom,iommu-geometry = <0 0xB0000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x0141 0x0>; + /* ipa-uc ram */ + qcom,iommu-dma = "atomic"; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x0142 0x0>; + qcom,iommu-dma-addr-pool = <0x40400000 0x1fc00000>; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; + }; + + qcom,demux { + compatible = "qcom,demux"; + }; +}; + +#include "bengal-gdsc.dtsi" +#include "bengal-usb.dtsi" +#include "bengal-ion.dtsi" +#include "bengal-coresight.dtsi" +#include "bengal-bus.dtsi" +#include "bengal-vidc.dtsi" +#include "pmi632.dtsi" +#include "pm6125.dtsi" + +&gcc_camss_top_gdsc { + status = "ok"; +}; + +&gcc_ufs_phy_gdsc { + status = "ok"; +}; + +&gcc_usb30_prim_gdsc { + status = "ok"; +}; + +&gcc_vcodec0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&gcc_venus_gdsc { + status = "ok"; +}; + +&hlos1_vote_turing_mmu_tbu1_gdsc { + status = "ok"; +}; + +&hlos1_vote_turing_mmu_tbu0_gdsc { + status = "ok"; +}; + +&hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc { + status = "ok"; +}; + +&hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc { + status = "ok"; +}; + +&mdss_core_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&gpu_cx_gdsc { + parent-supply = <&VDD_CX_LEVEL>; + status = "ok"; +}; + +&gpu_gx_gdsc { + parent-supply = <&VDD_CX_LEVEL>; + status = "ok"; +}; + +#include "msm-arm-smmu-bengal.dtsi" +#include "pm6125-rpm-regulator.dtsi" +#include "bengal-regulator.dtsi" +#include "bengal-pm.dtsi" +#include "bengal-pinctrl.dtsi" +#include "bengal-qupv3.dtsi" +#include "bengal-gpu.dtsi" +#include "bengal-audio.dtsi" +#include "bengal-sde-pll.dtsi" +#include "bengal-sde.dtsi" + +&qupv3_se1_i2c { + status = "ok"; + #include "pm8008.dtsi" +}; + +&pm8008_8 { + /* PM8008 IRQ STAT */ + interrupt-parent = <&tlmm>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_active &pm8008_interrupt>; +}; + +&pm8008_regulators { + vdd_l1_l2-supply = <&S6A>; +}; + +&L1P { + regulator-max-microvolt = <1200000>; + qcom,min-dropout-voltage = <100000>; +}; + +&L2P { + regulator-max-microvolt = <1056000>; + qcom,min-dropout-voltage = <100000>; +}; + +&L3P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + +&L4P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + +&L5P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + +&L6P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; +}; + +&L7P { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; + +&qupv3_se4_2uart { + status = "ok"; +}; + +&qupv3_se3_4uart { + status = "ok"; +}; + +&pm6125_vadc { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_therm_default &emmc_therm_default>; + + pa_therm0 { + reg = ; + label = "pa_therm0"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + quiet_therm { + reg = ; + label = "quiet_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + camera_flash_therm { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + emmc_ufs_therm { + reg = ; + label = "emmc_ufs_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm6125_gpios { + camera_therm { + camera_therm_default: camera_therm_default { + pins = "gpio3"; + bias-high-impedance; + }; + }; + + emmc_therm { + emmc_therm_default: emmc_therm_default { + pins = "gpio4"; + bias-high-impedance; + }; + }; + +}; + +&spmi_bus { + qcom,pm6125@0 { + pm6125_adc_tm_iio: adc_tm@3400 { + compatible = "qcom,adc-tm5-iio"; + reg = <0x3400 0x100>; + #thermal-sensor-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm6125_vadc ADC_GPIO1_PU2>, + <&pm6125_vadc ADC_GPIO2_PU2>; + + camera_flash_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + emmc_ufs_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + }; + }; +}; + +&pm6125_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm6125_vadc ADC_AMUX_THM1_PU2>, + <&pm6125_vadc ADC_AMUX_THM2_PU2>, + <&pm6125_vadc ADC_XO_THERM_PU2>; + + /* Channel nodes */ + pa_therm0 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + quiet_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pmi632_vadc { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&conn_therm_default &skin_therm_default>; + + conn_therm { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pmi632_gpios { + conn_therm { + conn_therm_default: conn_therm_default { + pins = "gpio1"; + bias-high-impedance; + }; + }; + + skin_therm { + skin_therm_default: skin_therm_default { + pins = "gpio3"; + bias-high-impedance; + }; + }; + +}; + +&pmi632_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pmi632_vadc ADC_GPIO2_PU2>; + + /* Channel nodes */ + skin_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&msm_vidc { + qcom,cx-ipeak-data = <&cx_ipeak_lm 6>; + qcom,clock-freq-threshold = <300000000>; +}; + +#include "bengal-thermal.dtsi" +#include "camera/bengal-camera.dtsi" +#include "msm-rdbg.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d8ba915bd6d4a1799fe9d5ddf3f2237a090ca05a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengal-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP IDP"; + compatible = "qcom,bengalp-idp", "qcom,bengalp", "qcom,idp"; + qcom,msm-id = <445 0x10000>, <420 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-idp.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..578d7158addcb045ce2f67807de30645c22b4581 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengalp.dtsi" +#include "bengal-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP IDP"; + compatible = "qcom,bengalp-idp", "qcom,bengalp", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..26bd558d06518462e7c1deb6cb442b80976d9136 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-2gb.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengalp-iot-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT 2Gb DDR HD+ SoC"; + compatible = "qcom,bengalp-iot"; + qcom,board-id = <0 0x403>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-2gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..37610143f910b7011b17fbcbc5c4dfbbe3a8709a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-2gb-overlay.dts @@ -0,0 +1,40 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengalp-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP 2Gb DDR HD+"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,msm-id = <470 0x10000>; + qcom,board-id = <34 0x403>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..966ca966d0001da61ba7c283fb3f330ae1815458 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-2gb.dts @@ -0,0 +1,38 @@ +/dts-v1/; + +#include "bengalp-iot-low-ram.dtsi" +#include "bengalp-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP 2Gb DDR HD+"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,board-id = <34 0x403>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9a3cdc7e5af96a0e0fc336358896e6f055cbeb3f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-low-ram.dtsi @@ -0,0 +1 @@ +#include "bengalp-iot-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..dc0e38238408067ff2c68a980c635de0451ad1e0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengalp-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP Overlay"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,msm-id = <470 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-2gb-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-2gb-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..0bd85a2ba76ac5d4c798070919c7c1fbc5f3de0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-2gb-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengalp-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP AATC 2Gb DDR"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,msm-id = <470 0x10000>; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..217daa818acb278bdc1e0dbd38be0d04622a413b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-2gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengalp-iot-low-ram.dtsi" +#include "bengalp-iot-idp-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP AATC 2Gb DDR"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ecec206b7030c13b6954293c9442a727784b4841 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "bengalp-iot-idp.dtsi" +#include "bengalp-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP USBC Audio"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,msm-id = <470 0x10000>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc.dts new file mode 100644 index 0000000000000000000000000000000000000000..091a668e1222e2717aac1f96d1a52f9ac22cadec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "bengalp-iot.dtsi" +#include "bengalp-iot-idp.dtsi" +#include "bengalp-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP USBC Audio"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..704385e62afeaa8e922bcad5ff19702a54ad367a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp-usbc.dtsi @@ -0,0 +1,5 @@ +&bengal_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..4299025cd29d977ea684bea79a9611c559c50add --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "bengalp-iot.dtsi" +#include "bengalp-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT IDP"; + compatible = "qcom,bengalp-iot-idp", "qcom,bengalp-iot", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..eef3e49bcecef848ce55c4e59d33ee8e4a883a5b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-idp.dtsi @@ -0,0 +1 @@ +#include "bengal-idp.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7451dc1c66ece2115d185a7b6ca27d09931c45f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot-low-ram.dtsi @@ -0,0 +1,148 @@ +#include "bengalp-iot.dtsi" +/ { +}; + +/delete-node/ &hyp_mem; +/delete-node/ &xbl_aop_mem; +/delete-node/ &sec_apps_mem; +/delete-node/ &smem_mem; +/delete-node/ &removed_mem; +/delete-node/ &pil_modem_mem; +/delete-node/ &pil_video_mem; +/delete-node/ &wlan_msa_mem; +/delete-node/ &pil_cdsp_mem; +/delete-node/ &pil_adsp_mem; +/delete-node/ &pil_ipa_fw_mem; +/delete-node/ &pil_ipa_gsi_mem; +/delete-node/ &pil_gpu_mem; +/delete-node/ &cdsp_sec_mem; + +/delete-node/ &user_contig_mem; +/delete-node/ &qseecom_mem; +/delete-node/ &qseecom_ta_mem; + +/delete-node/ &secure_display_memory; + +/delete-node/ &disp_rdump_memory; + +&reserved_memory { + hyp_mem: hyp_region@45700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45700000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_region@45e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45e00000 0x0 0x100000>; + }; + + sec_apps_mem: sec_apps_region@45fff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45fff000 0x0 0x1000>; + }; + + smem_mem: smem_region@46000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x46000000 0x0 0x200000>; + }; + + pil_modem_mem: modem_region@4ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x4ab00000 0x0 0x6900000>; + }; + + pil_video_mem: pil_video_region@51400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51400000 0x0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@51900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51900000 0x0 0x100000>; + }; + + pil_cdsp_mem: cdsp_regions@51a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51a00000 0x0 0x800000>; + }; + + pil_adsp_mem: pil_adsp_region@52200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x52200000 0x0 0x1c00000>; + }; + + pil_ipa_fw_mem: ipa_fw_region@53e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e00000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@53e10000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e10000 0x0 0x5000>; + }; + + pil_gpu_mem: gpu_region@53e15000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53e15000 0x0 0x2000>; + }; + + tz_stat_mem: tz_stat_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x100000>; + }; + + removed_mem: removed_region@60100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60100000 0x0 0x2200000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + linux,cma { + size = <0x0 0x1000000>; + }; +}; + +&soc { + qcom,ion { + /delete-node/ qcom,ion-heap@14; + /delete-node/ qcom,ion-heap@10; + /delete-node/ qcom,ion-heap@26; + }; + + qcom_seecom: qseecom@61800000 { + reg = <0x61800000 0xb00000>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + reg = <0x61800000 0xb00000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot.dts new file mode 100644 index 0000000000000000000000000000000000000000..b035dd2d7dd347adf91292b7e9c7b4084c7b5011 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengalp-iot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT SoC"; + compatible = "qcom,bengalp-iot"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp-iot.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..165af6ac1c46fcabdb48c57d0182d061c65f1cf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp-iot.dtsi @@ -0,0 +1,18 @@ +#include "bengal.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. BENGALP-IOT"; + compatible = "qcom,bengalp-iot"; + qcom,msm-id = <470 0x0>; + qcom,msm-name = "BENGALP-IOT"; +}; + +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp.dts b/arch/arm64/boot/dts/vendor/qcom/bengalp.dts new file mode 100644 index 0000000000000000000000000000000000000000..a4bc2aca4c87e1ee92bbf60f7019f2cbd6559120 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "bengalp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengalp SoC"; + compatible = "qcom,bengalp"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/bengalp.dtsi b/arch/arm64/boot/dts/vendor/qcom/bengalp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f9a2c1166b9b6c80e94f8837d66d7dd434ea4fd2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/bengalp.dtsi @@ -0,0 +1,19 @@ +/dts-v1/; + +#include "bengal.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Bengalp SoC"; + compatible = "qcom,bengalp"; + qcom,msm-id = <445 0x10000>, <420 0x10000>; +}; + +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera-sensor-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..65ac19946f1e44233b97d5e273958a58a6522bf6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera-sensor-idp.dtsi @@ -0,0 +1,393 @@ +#include +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi632_flash0 &pmi632_flash1>; + torch-source = <&pmi632_torch0 &pmi632_torch1>; + switch-source = <&pmi632_switch0 &pmi632_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi632_flash0 &pmi632_flash1>; + torch-source = <&pmi632_torch0 &pmi632_torch1>; + switch-source = <&pmi632_switch0 &pmi632_switch0>; + status = "ok"; + }; + + led_flash_rear_aux2: qcom,camera-flash@2 { + cell-index = <2>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi632_flash0 &pmi632_flash1>; + torch-source = <&pmi632_torch0 &pmi632_torch1>; + switch-source = <&pmi632_switch0 &pmi632_switch0>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear0_reset_suspend>; + gpios = <&tlmm 20 0>, + <&tlmm 18 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear1_reset_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear1_reset_suspend>; + gpios = <&tlmm 19 0>, + <&tlmm 21 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front0_reset_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 24 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux2: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0>; + rgltr-max-voltage = <1800000 2800000 1200000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_rear2_reset_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_rear2_reset_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 65 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /* Rear*/ + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1050000 0>; + rgltr-max-voltage = <1800000 2800000 1050000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear0_reset_suspend>; + gpios = <&tlmm 20 0>, + <&tlmm 18 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Rear Aux*/ + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0>; + rgltr-max-voltage = <1800000 2800000 1200000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear1_reset_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear1_reset_suspend>; + gpios = <&tlmm 19 0>, + <&tlmm 21 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Front*/ + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front0_reset_active + &cam_sensor_csi_mux_oe_active + &cam_sensor_csi_mux_sel_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front0_reset_suspend + &cam_sensor_csi_mux_oe_suspend + &cam_sensor_csi_mux_sel_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 24 0>, + <&tlmm 66 0>, + <&tlmm 67 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /*Rear Aux2*/ + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux2>; + eeprom-src = <&eeprom_rear_aux2>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0>; + rgltr-max-voltage = <1800000 2800000 1200000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_rear2_reset_active + &cam_sensor_csi_mux_oe_active + &cam_sensor_csi_mux_sel_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_rear2_reset_suspend + &cam_sensor_csi_mux_oe_suspend + &cam_sensor_csi_mux_sel_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 65 0>, + <&tlmm 66 0>, + <&tlmm 67 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera-sensor-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a4c93476024f8d72a3834bd9686b1311248268d1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera-sensor-qrd.dtsi @@ -0,0 +1,403 @@ +#include +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi632_flash0 &pmi632_flash1>; + torch-source = <&pmi632_torch0 &pmi632_torch1>; + switch-source = <&pmi632_switch0 &pmi632_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi632_flash0 &pmi632_flash1>; + torch-source = <&pmi632_torch0 &pmi632_torch1>; + switch-source = <&pmi632_switch0 &pmi632_switch0>; + status = "ok"; + }; + + led_flash_rear_aux2: qcom,camera-flash@2 { + cell-index = <2>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi632_flash0 &pmi632_flash1>; + torch-source = <&pmi632_torch0 &pmi632_torch1>; + switch-source = <&pmi632_switch0 &pmi632_switch0>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear0_reset_suspend>; + gpios = <&tlmm 20 0>, + <&tlmm 18 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear1_reset_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear1_reset_suspend>; + gpios = <&tlmm 21 0>, + <&tlmm 19 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front0_reset_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 24 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux2: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0>; + rgltr-max-voltage = <1800000 2800000 1200000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_rear2_reset_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_rear2_reset_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 65 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /* Rear*/ + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear0_reset_suspend>; + gpios = <&tlmm 20 0>, + <&tlmm 18 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Rear Aux*/ + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear1_reset_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear1_reset_suspend>; + gpios = <&tlmm 21 0>, + <&tlmm 19 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Front*/ + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front0_reset_active + &cam_sensor_csi_mux_oe_active + &cam_sensor_csi_mux_sel_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front0_reset_suspend + &cam_sensor_csi_mux_oe_suspend + &cam_sensor_csi_mux_sel_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 24 0>, + <&tlmm 66 0>, + <&tlmm 67 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-custom2 = <3>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_CSIMUX_OE0", + "CAM_CSIMUX_SEL0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /*Rear Aux2*/ + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux2>; + eeprom-src = <&eeprom_rear_aux2>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0>; + rgltr-max-voltage = <1800000 2800000 1200000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_rear2_reset_active + &cam_sensor_csi_mux_oe_active + &cam_sensor_csi_mux_sel_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_rear2_reset_suspend + &cam_sensor_csi_mux_oe_suspend + &cam_sensor_csi_mux_sel_suspend>; + gpios = <&tlmm 28 0>, + <&tlmm 65 0>, + <&tlmm 66 0>, + <&tlmm 67 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-custom2 = <3>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_CSIMUX_OE1", + "CAM_CSIMUX_SEL1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..23c6041547f962bdd991b606404d5831b4dd6fa9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bengal-camera.dtsi @@ -0,0 +1,870 @@ +#include + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy0 { + cell-index = <0>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x05C52000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x52000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&gcc_camss_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&L18A>; + clocks = <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_CPHY_0_CLK>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK_SRC>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + clock-rates = + <19200000 0 19200000 0>, + <341330000 0 200000000 0>, + <341330000 0 200000000 0>, + <384000000 0 268800000 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy1 { + cell-index = <1>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x05C53000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x53000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&gcc_camss_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&L18A>; + clocks = <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_CPHY_1_CLK>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK_SRC>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + clock-rates = + <19200000 0 19200000 0>, + <341330000 0 200000000 0>, + <341330000 0 200000000 0>, + <384000000 0 268800000 0>; + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy2 { + cell-index = <2>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x05C54000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x54000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&gcc_camss_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&L18A>; + clocks = <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_CPHY_2_CLK>, + <&gcc GCC_CAMSS_CSI2PHYTIMER_CLK_SRC>, + <&gcc GCC_CAMSS_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + clock-rates = + <19200000 0 19200000 0>, + <341330000 0 200000000 0>, + <341330000 0 200000000 0>, + <384000000 0 268800000 0>; + status = "ok"; + }; + + cam_cci0: qcom,cci0 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x05C1B000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x1B000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&gcc_camss_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&gcc GCC_CAMSS_CCI_0_CLK>, + <&gcc GCC_CAMSS_CCI_CLK_SRC>; + clock-names = "cci_0_clk", + "cci_0_clk_src"; + src-clock-name = "cci_0_clk_src"; + clock-cntl-level = "svs"; + clock-rates = <0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 22 0>, + <&tlmm 23 0>, + <&tlmm 29 0>, + <&tlmm 30 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz_cci0: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci0: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_tfe { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x400 0x000>, + <&apps_smmu 0x401 0x000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "tfe"; + tfe_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_ope { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x820 0x000>, + <&apps_smmu 0x821 0x020>, + <&apps_smmu 0x840 0x000>, + <&apps_smmu 0x841 0x000>; + qcom,iommu-faults = "non-fatal"; + multiple-client-devices; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "ope", "ope-cdm0"; + ope_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x800 0x000>, + <&apps_smmu 0x801 0x020>; + label = "cpas-cdm0"; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + }; + + qcom,cam-cpas@5c11000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x11000 0x13000>; + interrupt-names = "cpas_camnoc"; + interrupts = ; + camnoc-axi-min-ib-bw = <3000000000>; /*Need to be verified*/ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&gcc_camss_top_gdsc>; + clock-names = + "gcc_camss_ahb_clk", + "gcc_camss_top_ahb_clk", + "gcc_camss_top_ahb_clk_src", + "gcc_camss_axi_clk", + "gcc_camss_axi_clk_src"; + clocks = + <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK_SRC>, + <&gcc GCC_CAMSS_AXI_CLK>, + <&gcc GCC_CAMSS_AXI_CLK_SRC>; + src-clock-name = "gcc_camss_axi_clk_src"; + clock-rates = + <0 0 0 0 0>, + <0 80000000 80000000 19200000 19200000>, + <0 80000000 80000000 150000000 150000000>, + <0 80000000 80000000 200000000 200000000>, + <0 80000000 80000000 300000000 300000000>, + <0 80000000 80000000 300000000 300000000>, + <0 80000000 80000000 300000000 300000000>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + qcom,msm-bus,name = "cam_ahb"; /*Need to verify*/ + qcom,msm-bus,num-cases = <7>; /*Need to verify*/ + qcom,msm-bus,num-paths = <1>; /*Need to verify*/ + qcom,msm-bus,vectors-KBps = /*Need to verify*/ + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "minsvs", + "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", "tfe0", + "tfe1", "tfe2", "ope0", "cam-cdm-intf0", + "cpas-cdm0", "ope-cdm0", "tpg0", "tpg1"; + + camera-bus-nodes { + level2-nodes { + level-index = <2>; + level2_rt0_rd_wr_sum: level2-rt0-rd-wr-sum { + cell-index = <0>; + node-name = "level2-rt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_0"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level2_nrt0_rd_wr_sum: level2-nrt0-rd-wr-sum { + cell-index = <1>; + node-name = "level2-nrt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_0"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + level1_rt0_wr: level1-rt0-wr { + cell-index = <2>; + node-name = "level1-rt0-wr"; + parent-node = <&level2_rt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level1_nrt0_rd_wr: level1-nrt0-rd-wr { + cell-index = <3>; + node-name = "level1-nrt0-rd-wr"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + }; + + level0-nodes { + level-index = <0>; + ope0_all_wr: ope0-all-wr { + cell-index = <4>; + node-name = "ope0-all-wr"; + client-name = "ope0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + + ope0_all_rd: ope0-all-rd { + cell-index = <5>; + node-name = "ope0-all-rd"; + client-name = "ope0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + + tfe0_all_wr: tfe0-all-wr { + cell-index = <6>; + node-name = "tfe0-all-wr"; + client-name = "tfe0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + tfe1_all_wr: tfe1-all-wr { + cell-index = <7>; + node-name = "tfe1-all-wr"; + client-name = "tfe1"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + tfe2_all_wr: tfe2-all-wr { + cell-index = <8>; + node-name = "tfe2-all-wr"; + client-name = "tfe2"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <9>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + + ope_cdm0_all_rd: ope-cdm0-all-rd { + cell-index = <10>; + node-name = "ope-cdm0-all-rd"; + client-name = "ope-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <2>; + cdm-client-names = "vfe"; + status = "ok"; + }; + + cam_cpas_cdm: qcom,cpas-cdm0@5c23000 { + cell-index = <0>; + compatible = "qcom,cam-cpas-cdm2_0"; + label = "cpas-cdm"; + reg = <0x5c23000 0x400>; + reg-names = "cpas-cdm0"; + reg-cam-base = <0x23000>; + interrupts = ; + interrupt-names = "cpas-cdm0"; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = "cam_cc_cpas_top_ahb_clk"; + clocks = <&gcc GCC_CAMSS_TOP_AHB_CLK>; + clock-rates = <0>; + clock-cntl-level = "svs"; + cdm-client-names = "tfe0", "tfe1", "tfe2"; + config-fifo; + fifo-depths = <64 64 64 64>; + status = "ok"; + }; + + cam_ope_cdm: qcom,ope-cdm0@5c42000 { + cell-index = <0>; + compatible = "qcom,cam-ope-cdm2_0"; + label = "ope-cdm"; + reg = <0x5c42000 0x400>; + reg-names = "ope-cdm0"; + reg-cam-base = <0x42000>; + interrupts = ; + interrupt-names = "ope-cdm0"; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "ope_ahb_clk", + "ope_clk_src", + "ope_clk"; + clocks = + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_OPE_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_CLK>; + clock-rates = <0 0 0>, + <0 0 0>, + <0 0 0>, + <0 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + cdm-client-names = "ope"; + config-fifo; + fifo-depths = <64 64 64 64>; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "tfe"; + status = "ok"; + }; + + cam_tfe_csid0: qcom,tfe_csid0@5c6e000 { + cell-index = <0>; + compatible = "qcom,csid530"; + reg-names = "csid", "top", "camnoc"; + reg = <0x5c6e000 0x5000>, + <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x6e000 0x11000 0x13000>; + interrupt-names = "csid0"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_csid_clk_src", + "tfe_csid_clk", + "cphy_rx_clk_src", + "tfe_cphy_rx_clk", + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_0_CSID_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CSID_CLK>, + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_TFE_0_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <240000000 240000000 0 240000000 256000000 256000000 150000000>, + <384000000 384000000 0 341333333 460800000 460800000 200000000>, + <426400000 426400000 0 384000000 576000000 576000000 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe0: qcom,tfe0@5c6e000 { + cell-index = <0>; + compatible = "qcom,tfe530"; + reg-names = "tfe0"; + reg = <0x5c6e000 0x5000>; + reg-cam-base = <0x6e000>; + interrupt-names = "tfe0"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_0_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <256000000 256000000 150000000>, + <460800000 460800000 200000000>, + <576000000 576000000 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe_csid1: qcom,tfe_csid1@5c75000 { + cell-index = <1>; + compatible = "qcom,csid530"; + reg-names = "csid", "top", "camnoc"; + reg = <0x5c75000 0x5000>, + <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x75000 0x11000 0x13000>; + interrupt-names = "csid1"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_csid_clk_src", + "tfe_csid_clk", + "cphy_rx_clk_src", + "tfe_cphy_rx_clk", + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_1_CSID_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CSID_CLK>, + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_TFE_1_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <240000000 240000000 0 240000000 256000000 256000000 150000000>, + <384000000 384000000 0 341333333 460800000 460800000 200000000>, + <426400000 426400000 0 384000000 576000000 576000000 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe1: qcom,tfe1@5c75000 { + cell-index = <1>; + compatible = "qcom,tfe530"; + reg-names = "tfe1"; + reg = <0x5c75000 0x5000>; + reg-cam-base = <0x75000>; + interrupt-names = "tfe1"; + interrupts = <0 213 0>; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_1_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <256000000 256000000 150000000>, + <460800000 460800000 200000000>, + <576000000 576000000 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe_csid2: qcom,tfe_csid2@5c7c000 { + cell-index = <2>; + compatible = "qcom,csid530"; + reg-names = "csid", "top", "camnoc"; + reg = <0x5c7c000 0x5000>, + <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x7c000 0x11000 0x13000>; + interrupt-names = "csid2"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_csid_clk_src", + "tfe_csid_clk", + "cphy_rx_clk_src", + "tfe_cphy_rx_clk", + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_2_CSID_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_2_CSID_CLK>, + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_2_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_TFE_2_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_2_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <240000000 240000000 0 240000000 256000000 256000000 150000000>, + <384000000 384000000 0 341333333 460800000 460800000 200000000>, + <426400000 426400000 0 384000000 576000000 576000000 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe2: qcom,tfe2@5c7c000 { + cell-index = <2>; + compatible = "qcom,tfe530"; + reg-names = "tfe2"; + reg = <0x5c7c000 0x5000>; + reg-cam-base = <0x7c000>; + interrupt-names = "tfe2"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_2_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_2_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <256000000 256000000 150000000>, + <460800000 460800000 200000000>, + <576000000 576000000 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe_tpg0: qcom,tpg0@5c66000 { + cell-index = <0>; + compatible = "qcom,tpgv1"; + reg-names = "tpg0", "top"; + reg = <0x5c66000 0x400>, + <0x5c11000 0x1000>; + reg-cam-base = <0x66000 0x11000>; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "cphy_rx_clk_src", + "tfe_0_cphy_rx_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CPHY_RX_CLK>; + clock-rates = + <240000000 240000000>, + <341333333 341333333>, + <384000000 384000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "cphy_rx_clk_src"; + clock-control-debugfs = "false"; + status = "ok"; + }; + + cam_tfe_tpg1: qcom,tpg0@5c68000 { + cell-index = <1>; + compatible = "qcom,tpgv1"; + reg-names = "tpg0", "top"; + reg = <0x5c68000 0x400>, + <0x5c11000 0x1000>; + reg-cam-base = <0x68000 0x11000>; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "cphy_rx_clk_src", + "tfe_1_cphy_rx_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CPHY_RX_CLK>; + clock-rates = + <240000000 240000000>, + <341333333 341333333>, + <384000000 384000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "cphy_rx_clk_src"; + clock-control-debugfs = "false"; + status = "ok"; + }; + + qcom,cam-ope { + compatible = "qcom,cam-ope"; + compat-hw-name = "qcom,ope"; + num-ope = <1>; + status = "ok"; + }; + + ope: qcom,ope@0x5c42000 { + cell-index = <0>; + compatible = "qcom,ope"; + reg = + <0x5c42000 0x400>, + <0x5c42400 0x200>, + <0x5c42600 0x200>, + <0x5c42800 0x4400>, + <0x5c46c00 0x190>, + <0x5c46d90 0x1270>; + reg-names = + "ope_cdm", + "ope_top", + "ope_qos", + "ope_pp", + "ope_bus_rd", + "ope_bus_wr"; + reg-cam-base = <0x42000 0x42400 0x42600 0x42800 0x46c00 0x46d90>; + interrupts = ; + interrupt-names = "ope"; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "ope_ahb_clk", + "ope_clk_src", + "ope_clk"; + clocks = + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_OPE_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_CLK>; + clock-rates = + <171428571 200000000 200000000>, + <171428571 266600000 266600000>, + <240000000 465000000 465000000>, + <240000000 580000000 580000000>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ope_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cci.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cci.txt new file mode 100644 index 0000000000000000000000000000000000000000..59651a3541570c9b076f43ad31db629e8c504494 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cci.txt @@ -0,0 +1,817 @@ +* Qualcomm Technologies, Inc. MSM CCI + +CCI (Camera Control Interface) is module that is use for camera sensor module +I2C communication. + +======================= +Required Node Structure +======================= +The camera CCI node must be described in two levels of device nodes. The +first level describe the overall CCI node structure. Second level nodes +describe camera sensor submodule nodes which is using CCI for +i2c communication. + +====================================== +First Level Node - CCI device +====================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cci". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- reg-names + Usage: required + Value type: + Definition: Should specify relevant names to each + reg property defined. + +- interrupts + Usage: required + Value type: + Definition: Interrupt associated with CCI HW. + +- interrupt-names + Usage: required + Value type: + Definition: Name of the interrupt. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the CCI. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels in + gpio-req-tbl-num property (in the same order) + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CCI HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clock rates in Hz for CCI HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- src-clock-name + Usage: required + Value type: + Definition: name for the source clock. + +- regulator-names + Usage: required + Value type: + Definition: name of the voltage regulators required for the device. + +- gdscr-supply + Usage: required + Value type: + Definition: should contain gdsr regulator used for cci clocks. + +- mmagic-supply + Usage: optional + Value type: + Definition: should contain mmagic regulator used for mmagic clocks. + +========================= +CCI clock settings +========================= +- I2c speed settings (*) + Usage: required + Definition: List of i2c rates for CCI HW. + - i2c_freq_100Khz + Definition: qcom,i2c_standard_mode - node should contain clock settings for + 100Khz + - i2c_freq_400Khz + Definition: qcom,i2c_fast_mode - node should contain clock settings for + 400Khz + - i2c_freq_custom + Definition: qcom,i2c_custom_mode - node can contain clock settings for + frequencies other than 100Khz and 400Khz which is specific to usecase. + Currently it has settings for 375Khz. + - i2c_freq_1Mhz + Definition: qcom,i2c_fast_plus_mode - node should contain clock + settings for 1Mhz +* if speed settings is not defined the low level driver can use "i2c_freq_custom" +like default + + - hw-thigh + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tlow + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tsu-sto + Definition: should contain setup time for STOP condition + - hw-tsu-sta + Definition: should contain setup time for Repeated START condition + - hw-thd-dat + Definition: should contain hold time for the data + - hw-thd-sta + Definition: should contain hold time for START condition + - hw-tbuf + Definition: should contain free time between a STOP and a START condition + - hw-scl-stretch-en + Definition: should contain enable or disable clock stretching + - hw-trdhld + Definition: should contain internal hold time for SDA + - hw-tsp + Definition: should contain filtering of glitches + +Example: + + qcom,cci@0xfda0c000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xfda0c000 0x300>; + reg-names = "cci"; + interrupts = <0 50 0>; + interrupt-names = "cci"; + clock-names = "camnoc_axi_clk", "soc_ahb_clk", + "slow_ahb_src_clk", "cpas_ahb_clk", + "cci_clk", "cci_clk_src"; + clock-rates = <0 0 80000000 0 0 37500000>; + clock-cntl-level = "turbo"; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-tbl-num = <0 1 2 3>; + gpio-tbl-flags = <1 1 1 1>; + gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <78>; + hw-tlow = <114>; + hw-tsu-sto = <28>; + hw-tsu-sta = <28>; + hw-thd-dat = <10>; + hw-thd-sta = <77>; + hw-tbuf = <118>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <1>; + status = "ok"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <20>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <15>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <19>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + +======================================= +Second Level Node - CAM SENSOR MODULES +======================================= + +======================================= +CAM SENSOR RESOURCE MANAGER +======================================= +Camera Sensor Resource manager node contains properties of shared camera +sensor resource. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-res-mgr". + +- shared-gpios + Usage: optional + Value type: + Definition: should contain the gpios which are used by two or more + cameras, and these cameras may be opened together. + +- pinctrl-names + Usage: optional + Value type: + Definition: List of names to assign the shared pin state defined in pinctrl device node + +- pinctrl-<0..n> + Usage: optional + Value type: + Definition: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl device node. + + +============================= +CAMERA IMAGE SENSOR MODULE +============================= +Image sensor node contains properties of camera image sensor + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-sensor". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- csiphy-sd-index + Usage: required + Value type: + Definition: should contain csiphy instance that will used to + receive sensor data (0, 1, 2, 3). + +- cam_vdig-supply + Usage: required + Value type: + Definition: should contain regulator from which digital voltage is + supplied + +- cam_vana-supply + Usage: required + Value type: + Definition: should contain regulator from which analog voltage is + supplied + +- cam_vio-supply + Usage: required + Value type: + Definition: should contain regulator from which IO voltage is supplied + +- cam_bob-supply + Usage: optional + Value type: + Definition: should contain regulator from which BoB voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + sensor + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property is required if the sw control regulator parameters + e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain optimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- sensor-position-roll + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-pitch + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-yaw + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- qcom,secure + Usage: optional + Value type: + Definition: should be enabled to operate the camera in secure mode + +- gpio-no-mux + Usage: optional + Value type: + Definition: should contain field to indicate whether gpio mux table is + available. i.e. 1 if gpio mux is not available, 0 otherwise + +- cam_vaf-supply + Usage: optional + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- pwm-switch + Usage: optional + Value type: + Definition: This property is required for regulator to switch into PWM mode. + +- gpios + Usage: required + Value type: + Definition: should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) + +- gpio-reset + Usage: required + Value type: + Definition: should contain index to gpio used by sensors reset_n + +- gpio-standby + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors standby_n + +- gpio-vio + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors io vreg enable + +- gpio-vana + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors analog vreg enable + +- gpio-vdig + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors digital vreg enable + +- gpio-vaf + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af vreg enable + +- gpio-af-pwdm + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af pwdm_n + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should contain index to gpios specific to this sensor + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should contain direction of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should contain name of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-set-tbl-num + Usage: optional + Value type: + Definition: should contain index of gpios that need to be + configured by msm + +- gpio-set-tbl-flags + Usage: optional + Value type: + Definition: should contain value to be configured for the gpios + present in gpio-set-tbl-num property (in the same order) + +- gpio-set-tbl-delay + Usage: optional + Value type: + Definition: should contain amount of delay after configuring + gpios as specified in gpio_set_tbl_flags property (in the same order) + +- actuator-src + Usage: optional + Value type: + Definition: if auto focus is supported by this sensor, this + property should contain phandle of respective actuator node + +- led-flash-src + Usage: optional + Value type: + Definition: if LED flash is supported by this sensor, this + property should contain phandle of respective LED flash node + +- qcom,vdd-cx-supply + Usage: optional + Value type: + Definition: should contain regulator from which cx voltage is supplied + +- qcom,vdd-cx-name + Usage: optional + Value type: + Definition: should contain names of cx regulator + +- eeprom-src + Usage: optional + Value type: + Definition: if eeprom memory is supported by this sensor, this + property should contain phandle of respective eeprom nodes + +- ois-src + Usage: optional + Value type: + Definition: if optical image stabilization is supported by this sensor, + this property should contain phandle of respective ois node + +- ir-led-src + Usage: optional + Value type: + Definition: if ir led is supported by this sensor, this property + should contain phandle of respective ir-led node + +- qcom,ir-cut-src + Usage: optional + Value type: + Definition: if ir cut is supported by this sensor, this property + should contain phandle of respective ir-cut node + +- qcom,special-support-sensors + Usage: required + Value type: + Definition: if only some special sensors are supported + on this board, add sensor name in this property. + +- use-shared-clk + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the clk is shared clk between different sensor and ois, if this + device need to be opened together. + +- clock-rates + Usage: required + Value type: + Definition: clock rate in Hz. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clock-cntl-support + Usage: optional + Value type: + Definition: Says whether clock control support is present or not + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- clock-control + Usage: optional + Value type: + Definition: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property clock-rates. + +============================= +ACTUATOR MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,actuator". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +============================= +OIS MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,ois". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +- use-shared-clk + Usage: optional + Value type: + Definition: This property is required if the clk is shared clk between different + sensor and ois, if this device need to be opened together. + +Example: +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8994_flash0 &pmi8994_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch>; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&pmi8998_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&pmi8998_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <18 19>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_shared_clk_active &cam_res_mgr_active>; + pinctrl-1 = <&cam_shared_clk_suspend &cam_res_mgr_suspend>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + secure = <1>; + led-flash-src = <&led_flash0>; + actuator-src = <&actuator0>; + ois-src = <&ois0>; + eeprom-src = <&eeprom0>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009l_l1>; + cam_vana-supply = <&pm8009l_l5>; + cam_bob-supply = <&pm8150l_bob>; + cam_clk-supply = <&tital_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <0 2800000 1200000 0 3008000>; + rgltr-max-voltage = <0 2800000 1200000 0 4000000>; + rgltr-load-current = <0 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 80 0>, + <&tlmm 79 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + use-shared-clk; + clocks = <&clock_mmss clk_mclk0_clk_src>, + <&clock_mmss clk_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + clock-cntl-leveli = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cdm.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cdm.txt new file mode 100644 index 0000000000000000000000000000000000000000..a407bd656a0b312fc82b0ec08b43c8bf30f007e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cdm.txt @@ -0,0 +1,157 @@ +* Qualcomm Technologies, Inc. MSM Camera CDM + +CDM (Camera Data Mover) is module intended to provide means for fast programming +camera registers and lookup tables. + +======================= +Required Node Structure +======================= +CDM Interface node takes care of the handling has HW nodes and provide interface +for camera clients. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-cdm-intf". + +- label + Usage: required + Value type: + Definition: Should be "cam-cdm-intf". + +- num-hw-cdm + Usage: required + Value type: + Definition: Number of supported HW blocks. + +- cdm-client-names + Usage: required + Value type: + Definition: List of Clients supported by CDM interface. + +Example: + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpeg-dma", + "jpeg", + "fd"; + }; + +======================= +Required Node Structure +======================= +CDM HW node provides interface for camera clients through +to CDM interface node. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam170-cpas-cdm0", "qcom,cam480-cpas-cdm0", + "qcom,cam480-cpas-cdm1", "qcom,cam480-cpas-cdm2", "qcom,cam-cpas-cdm1_0", + "qcom,cam-cpas-cdm1_1", "qcom,cam-cpas-cdm1_2", "qcom,cam-ife-cdm1_2", + "qcom,cam-cpas-cdm2_0" or "qcom,cam-ope-cdm2_0" + +- label + Usage: required + Value type: + Definition: Should be "cpas-cdm". + +- reg-names + Usage: required + Value type: + Definition: Name of the register resources. + +- reg + Usage: required + Value type: + Definition: Register values. + +- reg-cam-base + Usage: required + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with CDM HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for CDM HW. + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CDM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CDM HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- cdm-client-names + Usage: required + Value type: + Definition: List of Clients supported by CDM HW node. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Example: + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm0"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "soc_ahb_clk", + "titan_top_ahb_clk", + "cam_axi_clk", + "camcc_slow_ahb_clk_src", + "cpas_top_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + qcom,clock-rates = <0 80000000 80000000 80000000 80000000 80000000>; + cdm-client-names = "ife"; + clock-cntl-level = "turbo"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cpas.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cpas.txt new file mode 100644 index 0000000000000000000000000000000000000000..c18b74391c18d1532d0f744edf388cf93456f038 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-cpas.txt @@ -0,0 +1,406 @@ +* Qualcomm Technologies, Inc. MSM Camera CPAS + +The MSM camera CPAS device provides dependency definitions for +enabling Camera CPAS HW and provides the Client definitions +for all HW blocks that use CPAS driver for BW voting. These +definitions consist of various properties that define the list +of clients supported, AHB, AXI master-slave IDs used for BW +voting. + +======================= +Required Node Structure +======================= +The camera CPAS device must be described in five levels. The first level has +general description of cpas including compatibility, interrupts, power info +etc. +The second level deals with information related to CPAS clients and how +the BW should be calculated. For simplicity in BW vote consolidation, the +grouping of granular votes pertaining to CPAS clients is represented as nodes +at four CAMNOC levels. The nodes at a particular level have some common +properties such as traffic merge type which indicates whether the votes at a +node have to be summed up, sum divided by two or taken max of all. CAMNOC Level +zero node usually represents granular vote info for clients. CAMNOC Level one +represents nodes which are clubbed together by arbiter in CAMNOC diagram. CAMNOC +Level two represents consolidated read and write nodes for RT and NRT paths. +CAMNOC Level three provides axi port information and these have nodes where all +paths from clients eventually converge according to their properties. This +includes master-slave IDs, ab, ib values for mnoc, camnoc bus interface + +================================== +First Level Node - CAM CPAS device +================================== +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-cpas". + +- label + Usage: required + Value type: + Definition: Should be "cpas". + +- arch-compat + Usage: required + Value type: + Definition: Should be "cpas_top" or "camss_top". + +- reg-names + Usage: required + Value type: + Definition: Name of the register resources. + +- reg + Usage: required + Value type: + Definition: Register values. + +- reg-cam-base + Usage: required + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- cam_hw_fuse + Usage: optional + Value type: + Definition: List of fuse based features and respective + fuse info. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with CAMNOC HW. + +- qcom,cpas-hw-ver + Usage: required + Value type: + Definition: CAM HW Version information. + +- camnoc-axi-min-ib-bw + Usage: optional + Value type: + Definition: Min camnoc axi bw for the given target. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for CPAS HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CPAS HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CPAS HW. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +- control-camnoc-axi-clk + Usage: optional + Value type: + Definition: Bool property specifying whether to control camnoc axi + clock from cpas driver. + +- camnoc-bus-width + Usage: required if control-camnoc-axi-clk is enabled + Value type: + Definition: camnoc bus width. + +- camnoc-axi-clk-bw-margin-perc + Usage: optional + Value type: + Definition: Percentage value to be added to camnoc bw while calculating + camnoc axi clock frequency. + +- qcom,msm-bus,name +- qcom,msm-bus,num-cases +- qcom,msm-bus,num-paths +- qcom,msm-bus,vectors-KBps + Please refer Documentation/devicetree/bindings/arm/msm/msm_bus.txt + for the properties above. + +- vdd-corners + Usage: required + Value type: + Definition: List of vdd corners to map for ahb level. + +- vdd-corner-ahb-mapping + Usage: required + Value type: + Definition: List of ahb level strings corresponds to vdd-corners. + Supported strings: suspend, svs, nominal, turbo + +- client-id-based + Usage: required + Value type: + Definition: Bool property specifying whether CPAS clients are ID based. + +- client-names + Usage: required + Value type: + Definition: List of Clients supported by CPAS. + +- client-bus-camnoc-based + Usage: optional + Value type: + Definition: Bool property specifying whether Clients are connected + through CAMNOC for AXI access. + +=================================================================== +Third Level Node - CAMNOC Level nodes +=================================================================== +- level-index + Usage: required + Value type: + Definition: Number representing level index for ndoes at current CAMNOC level + +- camnoc-max-needed + Usage: optional + Value type: + Definition: Bool property for all votes at current level to be taken maximum + for CAMNOC BW calculation. + +=================================================================== +Fourth Level Node - Generic CAMNOC node properties +=================================================================== +- cell-index + Usage: required + Value type: + Definition: Unique index of node to be used by CPAS driver. + +- node-name + Usage: required + Value type: + Definition: Unique name representing this node. + +- path-data-type + Usage: required if a CAMNOC Level 0 Node + Value type: + Definition: Type of path data for a specific client. + Supported : CAM_CPAS_PATH_DATA_IFE_LINEAR, CAM_CPAS_PATH_DATA_ALL, etc. + Please refer dt-bindings/msm/msm-camera.h for all supported + definitions. + +- path-transaction-type + Usage: required if a CAMNOC Level 0 Node + Value type: + Definition: Type of path transaction for a specific client. + Supported : CAM_CPAS_TRANSACTION_READ, CAM_CPAS_TRANSACTION_WRITE + +- client-name + Usage: required if a CAMNOC Level 0 Node + Value type: + Definition: Name of the client with above properties. + Supported : From "client-names" property in CPAS node + +- constituent-paths + Usage: optional, applicable only to CAMNOC Level 0 Nodes + Value type: + Definition: List of constituents of path data type of current node. + Supported : CAM_CPAS_PATH_DATA_IFE_VID, CAM_CPAS_PATH_DATA_IFE_DISP, etc. + Please refer dt-bindings/msm/msm-camera.h for all supported + definitions. + +- traffic-merge-type + Usage: required if NOT a CAMNOC Level 0 Node + Value type: + Definition: Type of traffic merge for that node. + Supported : CAM_CPAS_TRAFFIC_MERGE_SUM, CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE. + +- parent-node + Usage: required for all except CAMNOC Level 3 Nodes + Value type: + Definition: Parent node of this node. Parent node must be at least + one level above the current level. + +- bus-width-factor + Usage: optional + Value type: + Definition: For bus width factor consideration in CAMNOC BW calculation + +- qcom,axi-port-name + Usage: required at CAMNOC Level 3 + Value type: + Definition: Name of the AXI Port. + +- ib-bw-voting-needed + Usage: optional + Value type: + Definition: Bool property indicating axi port requires instantaneous bandwidth + +=================================================================== +Fifth Level Node - CAM AXI Bus Properties +=================================================================== +- qcom,msm-bus,name +- qcom,msm-bus,num-cases +- qcom,msm-bus,num-paths +- qcom,msm-bus,vectors-KBps + Please refer Documentation/devicetree/bindings/arm/msm/msm_bus.txt + for the properties above. + +- qcom,msm-bus-vector-dyn-vote + Usage: optional + Value type: + Definition: Bool property specifying whether this bus client + is dynamic vote based. + +Example: + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x5000>; + reg-cam-base = <0x40000 0x42000>; + cam_hw_fuse = , + ; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170100>; /* Titan v170 v1.0.0 */ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 80000000 0>; + clock-cntl-level = "turbo"; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <10>; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "csiphy3", + "csiphy4", "csiphy5", "cci0", "cci1", + "csid0", "csid1", "csid2", "csid3", + "csid4", "csid5", "csid6", + "ife0", "ife1", "ife2", "ife3", "custom0", + "ipe0", "cam-cdm-intf0", "cpas-cdm0", "cpas-cdm1", + "cpas-cdm2", + "bps0", "icp0", "jpeg-dma0", "jpeg-enc0", + "fd0"; + + camera-bus-nodes { + level3-nodes { + level-index = <3>; + level3_rt0_rd_wr_sum: level3-rt0-rd-wr-sum { + cell-index = <0>; + node-name = "level3-rt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_0"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + level2-nodes { + level-index = <2>; + camnoc-max-needed; + level2_rt0_wr: level2-rt0-wr { + cell-index = <3>; + node-name = "level2-rt0-wr"; + parent-node = <&level3_rt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + }; + level1-nodes { + level-index = <1>; + camnoc-max-needed; + level1_rt0_wr0: level1-rt0-wr0 { + cell-index = <8>; + node-name = "level1-rt0-wr0"; + parent-node = <&level2_rt0_wr>; + traffic-merge-type = + ; + }; + }; + level0-nodes { + level-index = <0>; + ife0_ubwc_stats_wr: ife0-ubwc-stats-wr { + cell-index = <16>; + node-name = "ife0-ubwc-stats-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr0>; + }; + }; + }; + }; + diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-csiphy.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-csiphy.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f5be32843e117de9abd6f69b34adbab7feac599 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-csiphy.txt @@ -0,0 +1,118 @@ +* Qualcomm Technologies, Inc. MSM CSI Phy + +======================= +Required Node Structure +======================= +The camera CSIPHY node must be described in First level of device nodes. The +first level describe the overall CSIPHY node structure. + +====================================== +First Level Node - CSIPHY device +====================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,csiphy-v1.0", + "qcom,csiphy-v1.1", "qcom,csiphy-v1.2", "qcom,csiphy-v1.2.1", + "qcom,csiphy-v1.2.2", "qcom,csiphy-v2.0", "qcom,csiphy-v1.2.2.2", + "qcom,csiphy-v1.2.3", "qcom,csiphy". + +- cell-index: csiphy hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the csiphy operating in + compatible mode. + +- reg-names + Usage: required + Value type: + Definition: Should specify relevant names to each + reg property defined. + +- reg-cam-base + Usage: required + Value type: + Definition: offset of CSIPHY in camera hw block + +- interrupts + Usage: required + Value type: + Definition: Interrupt associated with CCI HW. + +- interrupt-names + Usage: required + Value type: + Definition: Name of the interrupt. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CSIPHY HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clock rates in Hz for CSIPHY HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- regulator-names + Usage: required + Value type: + Definition: name of the voltage regulators required for the device. + +- gdscr-supply + Usage: required + Value type: + Definition: should contain gdsr regulator used for CSIPHY clocks. + +- mipi-csi-vdd-supply + Usage: required + Value type: + Definition: should contain phandle for mipi-csi-vdd regulator used for + CSIPHY device. + +- csi-vdd-voltage + Usage: required + Value type: + Definition: should contain required voltage for csi-vdd supply for CSIPHY. + +Example: + +qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac65000 0x200>; + reg-cam-base = <0x65000>; + reg-names = "csiphy"; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + mipi-csi-vdd-supply = <&pm8998_l1>; + csi-vdd-voltage = <1200000>; + gdscr-supply = <&titan_top_gdsc>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", "csiphy0_clk", + "csi0phytimer_clk_src", "csi0phytimer_clk"; + clock-rates = <400000000 0 300000000 0>; + clock-cntl-level = "turbo"; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-custom-hw.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-custom-hw.txt new file mode 100644 index 0000000000000000000000000000000000000000..61125d0c8087d2ffa7541cc159feba379e856e93 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-custom-hw.txt @@ -0,0 +1,28 @@ +* Qualcomm Technologies, Inc. MSM Camera Custom HW + +Camera Custom device provides the definitions for enabling +the custom hardware. It also provides the functions for the client +to control the Custom hardware. + +======================= +Required Node Structure +======================= +The Custom device is described in one level of the device node. + +====================================== +First Level Node - CAM Custom device +====================================== +Required properties: +- compatible + Usage: required + Value type: + Definition: Should specify the compatibility string for matching the + driver. e.g. "qcom,cam_custom_hw_sub_mod". + +Example: + + qcom,cam-custom-hw { + compatible = "qcom,cam_custom_hw_sub_mod"; + arch-compat = "custom"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-custom.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-custom.txt new file mode 100644 index 0000000000000000000000000000000000000000..8c5cc6148c5b0c5ea7b0e08c09e04301e8df7b34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-custom.txt @@ -0,0 +1,31 @@ +* Qualcomm Technologies, Inc. MSM Camera Custom + +The MSM camera Custom driver provides the definitions for enabling +the Camera custom hadware. It provides the functions for the Client to +control the custom hardware. + +======================= +Required Node Structure +======================= +The camera Custom device is described in one level of device node. + +================================== +First Level Node - CAM CUSTOM device +================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-custom". + +- arch-compat + Usage: required + Value type: + Definition: Should be "custom". + +Example: + + qcom,cam-custom { + compatible = "qcom,cam-custom"; + arch-compat = "custom"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-eeprom.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-eeprom.txt new file mode 100644 index 0000000000000000000000000000000000000000..d77f337a9e3c0659db6966ee77025a9b7a8bb857 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-eeprom.txt @@ -0,0 +1,503 @@ +* Qualcomm Technologies, Inc. MSM EEPROM + +EEPROM is a one time programmed(OTP) device that stores the calibration data +use for camera sensor. It may either be integrated in the sensor module or in +the sensor itself. As a result, the power, clock and GPIOs may be the same as +the camera sensor. The following describes the page block map, power supply, +clock, GPIO and power on sequence properties of the EEPROM device. + +======================================================= +Required Node Structure if probe happens from userspace +======================================================= +The EEPROM device is described in one level of the device node. + +====================================== +First Level Node - CAM EEPROM device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,eeprom". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for EEPROM HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property specifies if the regulator control is supported + e.g. rgltr-min-voltage. + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain the maximum current in microamps required for + the regulators mentioned in regulator-names property. + +- gpio-no-mux + Usage: required + Value type: + Definition: should specify the gpio mux type. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the eeprom. + +- gpio-reset + Usage: required + Value type: + Definition: should specify the reset gpio index. + +- gpio-standby + Usage: required + Value type: + Definition: should specify the standby gpio index. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels. + +- sensor-position + Usage: required + Value type: + Definition: should contain the mount angle of the camera sensor. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor. + +- sensor-mode + Usage: required + Value type: + Definition: should contain sensor mode supported. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for EEPROM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for EEPROM HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: says what all different clock levels eeprom node has. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Example: + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8998_l5>; + cam_vio-supply = <&pm8998_lvs1>; + regulator-names = "cam_vdig", "cam_vio"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 0>; + rgltr-max-voltage = <1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + +======================================================= +Required Node Structure if probe happens from kernel +======================================================= +The EEPROM device is described in one level of the device node. + +====================================== +First Level Node - CAM EEPROM device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,eeprom". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- qcom,eeprom-name + Usage: required + Value type: + Definition: Name of the EEPROM HW. + +- qcom,slave-addr + Usage: required + Value type: + Definition: Slave address of the EEPROM HW. + +- qcom,num-blocks + Usage: required + Value type: + Definition: Total block number that eeprom contains. + +- qcom,pageX + Usage: required + Value type: + Definition: List of values specifying page size, start address, + address type, data, data type, delay in ms. + size 0 stand for non-paged. + +- qcom,pollX + Usage: required + Value type: + Definition: List of values specifying poll size, poll reg address, + address type, data, data type, delay in ms. + size 0 stand for not used. + +- qcom,memX + Usage: required + Value type: + Definition: List of values specifying memory size, start address, + address type, data, data type, delay in ms. + size 0 stand for not used. + +- qcom,saddrX + Usage: required + Value type: + Definition: property should specify the slave address for block (%d). + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for EEPROM HW. + +- qcom,cmm-data-support + Usage: required + Value type: + Definition: Camera MultiModule data capability flag.. + +- qcom,cmm-data-compressed + Usage: required + Value type: + Definition: Camera MultiModule data compression flag. + +- qcom,cmm-data-offset + Usage: required + Value type: + Definition: Camera MultiModule data start offset. + +- qcom,cmm-data-size + Usage: required + Value type: + Definition: Camera MultiModule data size. + +- qcom,cam-power-seq-type + Usage: required + Value type: + Definition: should specify the power on sequence types. + +- qcom,cam-power-seq-val + Usage: required + Value type: + Definition: should specify the power on sequence values. + +- qcom,cam-power-seq-cfg-val + Usage: required + Value type: + Definition: should specify the power on sequence config values. + +- qcom,cam-power-seq-delay + Usage: required + Value type: + Definition: should specify the power on sequence delay time in ms. + +- spiop-read + Usage: required + Value type: + Definition: this array provides SPI read operation related data. + +- spiop-readseq + Usage: required + Value type: + Definition: this array provides SPI read sequence operation realted data. + +- spiop-queryid + Usage: required + Value type: + Definition: this array provides SPI query eeprom id operation related data. + +- spiop-pprog: + Usage: required + Value type: + Definition: this array provides SPI page program operation related data. + +- spiop-wenable + Usage: required + Value type: + Definition: this array provides SPI write enable operation related data. + +- spiop-readst + Usage: required + Value type: + Definition: this array provides SPI read destination operation related data. + +- spiop-erase + Usage: required + Value type: + Definition: this array provides SPI erase operation related data. + +- eeprom-idx + Usage: required + Value type: + Definition: this array provides eeprom id realted data. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property specifies if the regulator control is supported + e.g. rgltr-min-voltage. + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators + mentioned in regulator-names property. + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain the maximum current in microamps required for + the regulators mentioned in regulator-names property. + +- gpio-no-mux + Usage: required + Value type: + Definition: should specify the gpio mux type. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the eeprom. + +- gpio-reset + Usage: required + Value type: + Definition: should specify the reset gpio index. + +- gpio-standby + Usage: required + Value type: + Definition: should specify the standby gpio index. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels. + +- sensor-position + Usage: required + Value type: + Definition: should contain the mount angle of the camera sensor. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor. + +- sensor-mode + Usage: required + Value type: + Definition: should contain sensor mode supported. + +- clock-cntl-level + Usage: required + Value type: + Definition: says what all different clock levels eeprom node has. + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for EEPROM HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for EEPROM HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Example: + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0x0>; + qcom,eeprom-name = "msm_eeprom"; + eeprom-id0 = <0xF8 0x15>; + eeprom-id1 = <0xEF 0x15>; + eeprom-id2 = <0xC2 0x36>; + eeprom-id3 = <0xC8 0x15>; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x60>; + qcom,num-blocks = <2>; + qcom,page0 = <1 0x100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0 1 1>; + qcom,mem0 = <0 0x0 2 0 1 0>; + qcom,page1 = <1 0x0200 2 0x8 1 1>; + qcom,pageen1 = <1 0x0202 2 0x01 1 10>; + qcom,poll1 = <0 0x0 2 0 1 1>; + qcom,mem1 = <32 0x3000 2 0 1 0>; + qcom,saddr1 = <0x62>; + qcom,cmm-data-support; + qcom,cmm-data-compressed; + qcom,cmm-data-offset = <0>; + qcom,cmm-data-size = <0>; + spiop-read = <0x03 3 0 0 0>; + spiop-readseq = <0x03 3 0 0 0>; + spiop-queryid = <0x90 3 0 0 0>; + spiop-pprog = <0x02 3 0 3 100>; + spiop-wenable = <0x06 0 0 0 0>; + spiop-readst = <0x05 0 0 0 0>; + spiop-erase = <0x20 3 0 10 100>; + qcom,cam-power-seq-type = "sensor_vreg", + "sensor_vreg", "sensor_clk", + "sensor_gpio", "sensor_gpio"; + qcom,cam-power-seq-val = "cam_vdig", + "cam_vio", "sensor_cam_mclk", + "sensor_gpio_reset", + "sensor_gpio_standby"; + qcom,cam-power-seq-cfg-val = <1 1 24000000 1 1>; + qcom,cam-power-seq-delay = <1 1 5 5 10>; + cam_vdig-supply = <&pm8998_l5>; + cam_vio-supply = <&pm8998_lvs1>; + regulator-names = "cam_vdig", "cam_vio"; + rgltr-cntrl-support; + rgltr-min-voltage = <1200000 0>; + rgltr-max-voltage = <1200000 0>; + rgltr-load-current = <0 80000 105000 0>; + qcom,gpio-no-mux = <0>; + gpios = <&msmgpio 26 0>, + <&msmgpio 37 0>, + <&msmgpio 36 0>; + gpio-reset = <1>; + gpio-standby = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET1", + "CAM_STANDBY"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-cntl-level = "turbo"; + clock-names = "cam_clk"; + clock-rates = <24000000>; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-fd.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-fd.txt new file mode 100644 index 0000000000000000000000000000000000000000..51b0babaa709d5524dd94604c41933b41176a4cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-fd.txt @@ -0,0 +1,154 @@ +* Qualcomm Technologies, Inc. MSM Camera FD + +The MSM camera Face Detection device provides dependency definitions +for enabling Camera FD HW. MSM camera FD is implemented in multiple +device nodes. The root FD device node has properties defined to hint +the driver about the FD HW nodes available during the probe sequence. +Each node has multiple properties defined for interrupts, clocks and +regulators. + +======================= +Required Node Structure +======================= +FD root interface node takes care of the handling Face Detection high level +driver handling and controls underlying FD hardware present. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-fd". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,fd". + +- num-fd + Usage: required + Value type: + Definition: Number of supported FD HW blocks. + +Example: + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + }; + +======================= +Required Node Structure +======================= +FD Node provides interface for Face Detection hardware driver +about the device register map, interrupt map, clocks, regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be one of "qcom,fd41", "qcom,fd501", + "qcom,fd600". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt line associated with FD HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for FD HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for FD HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks required for FD HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Examples: + cam_fd: qcom,fd@ac5a000 { + cell-index = <0>; + compatible = "qcom,fd600"; + reg-names = "fd_core", "fd_wrapper"; + reg = <0xac5a000 0x1000>, + <0xac5b000 0x400>; + reg-cam-base = <0x5a000 0x5b000>; + interrupt-names = "fd"; + interrupts = <0 462 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "fd_core_clk_src", + "fd_core_clk", + "fd_core_uar_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_FD_CORE_CLK_SRC>, + <&clock_camcc CAM_CC_FD_CORE_CLK>, + <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; + src-clock-name = "fd_core_clk_src"; + clock-cntl-level = "svs"; + clock-rates = <0 0 0 0 0 400000000 0 0>; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-icp.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-icp.txt new file mode 100644 index 0000000000000000000000000000000000000000..e22e1f99f670dad052f7a57f2de737a362806b66 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-icp.txt @@ -0,0 +1,287 @@ +* Qualcomm Technologies, Inc. MSM Camera ICP + +The MSM camera ICP devices are implemented multiple device nodes. +The root icp device node has properties defined to hint the driver +about the number of A5,IPE and BPS nodes available during the +probe sequence. Each node has multiple properties defined +for interrupts, clocks and regulators. + +======================= +Required Node Structure +======================= +ICP root interface node takes care of the handling account for number +of A5, IPE and BPS devices present on the hardware. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-icp". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,a5" or "qcom,ipe0" or "qcom,ipe1" or "qcom,bps". + +- num-a5 + Usage: required + Value type: + Definition: Number of supported A5 processors. + +- num-ipe + Usage: required + Value type: + Definition: Number of supported IPE HW blocks. + +- num-bps + Usage: required + Value type: + Definition: Number of supported BPS HW blocks. + +Example: + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", "qcom,ipe0", "qcom,ipe1", "qcom,bps"; + num-a5 = <1>; + num-ipe = <2>; + num-bps = <1>; + status = "ok"; + }; + +======================= +Required Node Structure +======================= +A5/IPE/BPS Node's provides interface for Image Control Processor driver +about the A5 register map, interrupt map, clocks, regulators +and name of firmware image. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-a5" or "qcom,cam-ipe" or "qcom,cam-bps". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Register values. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with CDM HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for CDM HW. + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CDM HW. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CDM HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: lowsvs, svs, svs_l1, nominal, turbo. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- fw_name + Usage: optional + Value type: + Definition: Name of firmware image. + +- ubwc-ipe-fetch-cfg + Usage: required + Value type: + Definition: UBWC IPE fetch configuration based on DDR device type. + +- ubwc-ipe-write-cfg + Usage: required + Value type: + Definition: UBWC IPE write configuration based on DDR device type. + +- ubwc-bps-fetch-cfg + Usage: required + Value type: + Definition: UBWC BPS fetch configuration based on DDR device type. + +- ubwc-bps-write-cfg + Usage: required + Value type: + Definition: UBWC BPS write configuration based on DDR device type. + +- ubwc-cfg + Usage: optional + Value type: + Definition: UBWC configuration, this is mandatory if above + ipe/bps ubwc properties are not used. + +Examples: +a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + interrupts = <0 463 0>; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_cam_ahb_clk", + "gcc_cam_axi_clk", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_apb_clk", + "icp_atb_clk", + "icp_clk", + "icp_clk_src", + "icp_cti_clk", + "icp_ts_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_ICP_APB_CLK>, + <&clock_camcc CAM_CC_ICP_ATB_CLK>, + <&clock_camcc CAM_CC_ICP_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>, + <&clock_camcc CAM_CC_ICP_CTI_CLK>, + <&clock_camcc CAM_CC_ICP_TS_CLK>; + + clock-rates = <0 0 0 80000000 0 0 0 0 600000000 0 0>; + clock-cntl-level = "turbo"; + fw_name = "CAMERA_ICP.elf"; + /* "ubwc-cfg" is not used, even if defined the new property + tags will be priortized. If the new properties are not used + please specify "ubwc-cfg" in that case */ + ubwc-ipe-fetch-cfg = <0x707b 0x7083>; + ubwc-ipe-write-cfg = <0x161ef 0x1620f>; + ubwc-bps-fetch-cfg = <0x707b 0x7083> + ubwc-bps-write-cfg = <0x161ef 0x1620f>; + +qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; +}; + +qcom,ipe1 { + cell-index = <1>; + compatible = "qcom,cam-ipe"; + regulator-names = "ipe1-vdd"; + ipe1-vdd-supply = <&ipe_1_gdsc>; + clock-names = "ipe_1_ahb_clk", + "ipe_1_areg_clk", + "ipe_1_axi_clk", + "ipe_1_clk", + "ipe_1_clk_src"; + src-clock-name = "ipe_1_clk_src"; + clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_1_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_1_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK>, + <&clock_camcc CAM_CC_IPE_1_CLK_SRC>; + + clock-rates = <0 0 0 0 240000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; +}; + +bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = <0 0 0 0 200000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 600000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-ife-csid.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-ife-csid.txt new file mode 100644 index 0000000000000000000000000000000000000000..0a11bea1fba7a931e19853c15b28d56270f96993 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-ife-csid.txt @@ -0,0 +1,122 @@ +* Qualcomm Technologies, Inc. MSM Camera IFE CSID + +Camera IFE CSID device provides the definitions for enabling +the IFE CSID hardware. It also provides the functions for the client +to control the IFE CSID hardware. + +======================= +Required Node Structure +======================= +The IFE CSID device is described in one level of the device node. + +====================================== +First Level Node - CAM IFE CSID device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,csid170", "qcom,csid170_200", "qcom,csid175", + "qcom,csid175_200", "qcom,csid480", "qcom,csid-lite170", + "qcom,csid-lite175", "qcom,csid-lite480" or + "qcom,csid-custom480". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should be "csid". + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with IFE CSID HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for IFE CSID HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for IFE CSID HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for IFE CSID HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +Example: + + qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid480"; + reg = <0xacb3000 0x1000>; + reg-names = "csid"; + interrupts = <0 464 0>; + interrupt-names = "csid"; + vdd-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src"; + clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>; + clock-rates = <0 0 80000000 0 320000000 0 384000000 0 384000000>; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-isp.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-isp.txt new file mode 100644 index 0000000000000000000000000000000000000000..801c3feae3d7d72ec76fea508188733f4c149451 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-isp.txt @@ -0,0 +1,36 @@ +* Qualcomm Technologies, Inc. MSM Camera ISP + +The MSM camera ISP driver provides the definitions for enabling +the Camera ISP hadware. It provides the functions for the Client to +control the ISP hardware. + +======================= +Required Node Structure +======================= +The camera ISP device is described in one level of device node. + +================================== +First Level Node - CAM ISP device +================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-isp". + +- arch-compat + Usage: required + Value type: + Definition: Should be "vfe", "ife" or "tfe". + +- ubwc-static-cfg + Usage: optional + Value type: + Definition: IFE UBWC static configuration based on DDR device type. + +Example: + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-jpeg.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-jpeg.txt new file mode 100644 index 0000000000000000000000000000000000000000..73e99b25cd8f370e62059b5dd8e49396f8ef2ac7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-jpeg.txt @@ -0,0 +1,186 @@ +* Qualcomm Technologies, Inc. MSM Camera JPEG + +The MSM camera JPEG devices are implemented multiple device nodes. +The root JPEG device node has properties defined to hint the driver +about the number of Encoder and DMA nodes available during the +probe sequence. Each node has multiple properties defined +for interrupts, clocks and regulators. + +======================= +Required Node Structure +======================= +JPEG root interface node takes care of the handling account for number +of Encoder and DMA devices present on the hardware. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-jpeg". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,jpegenc" or "qcom,jpegdma". + +- num-jpeg-enc + Usage: required + Value type: + Definition: Number of supported Encoder HW blocks. + +- num-jpeg-dma + Usage: required + Value type: + Definition: Number of supported DMA HW blocks. + +Example: + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + +======================= +Required Node Structure +======================= +Encoder/DMA Nodes provide interface for JPEG driver about +the device register map, interrupt map, clocks and regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam_jpeg_enc". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with JPEG HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for JPEG HW. + +- camss-vdd-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for JPEG HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for JPEG HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo. + +Examples: + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <0 474 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000{ + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = <0 475 0>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <0 0 0 0 0 600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-lrme.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-lrme.txt new file mode 100644 index 0000000000000000000000000000000000000000..409be3f08de42b2f1e3b592e4037caaa2edb126c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-lrme.txt @@ -0,0 +1,148 @@ +* Qualcomm Technologies, Inc. MSM Camera LRME + +The MSM camera Low Resolution Motion Estimation device provides dependency +definitions for enabling Camera LRME HW. MSM camera LRME is implemented in +multiple device nodes. The root LRME device node has properties defined to +hint the driver about the LRME HW nodes available during the probe sequence. +Each node has multiple properties defined for interrupts, clocks and +regulators. + +======================= +Required Node Structure +======================= +LRME root interface node takes care of the handling LRME high level +driver handling and controls underlying LRME hardware present. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-lrme" + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,lrme" + +- num-lrme + Usage: required + Value type: + Definition: Number of supported LRME HW blocks + +Example: + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + compat-hw-name = "qcom,lrme"; + num-lrme = <1>; + }; + +======================= +Required Node Structure +======================= +LRME Node provides interface for Low Resolution Motion Estimation hardware +driver about the device register map, interrupt map, clocks, regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,lrme" + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources + +- reg + Usage: optional + Value type: + Definition: Register values + +- reg-cam-base + Usage: optional + Value type: + Definition: Offset of the register space compared to + to Camera base register space + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt + +- interrupts + Usage: optional + Value type: + Definition: Interrupt line associated with LRME HW + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for LRME HW + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names" + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for LRME HW + +- clocks + Usage: required + Value type: + Definition: List of clocks required for LRME HW + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels + Supported strings: minsvs, lowsvs, svs, svs_l1, nominal, turbo + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name + +Examples: + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <0 476 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "lrme_clk_src", + "lrme_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_LRME_CLK_SRC>, + <&clock_camcc CAM_CC_LRME_CLK>; + clock-rates = <0 0 0 0 0 0 0>, + <0 0 0 0 0 19200000 19200000>, + <0 0 0 0 0 19200000 19200000>, + <0 0 0 0 0 19200000 19200000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "lrme_core_clk_src"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-ope.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-ope.txt new file mode 100644 index 0000000000000000000000000000000000000000..fdd6c5e980f1929f11c4928ba14dbb5184a887d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-ope.txt @@ -0,0 +1,168 @@ +* Qualcomm Technologies, Inc. MSM Camera OPE + +The ope device node has properties defined to hint the driver +about the number of OPE nodes available during the +probe sequence. Each node has multiple properties defined +for interrupts, clocks and regulators. + +======================= +Required Node Structure +======================= +OPE root interface node takes care of the handling account for number +of OPE devices present on the hardware. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-ope". + +- compat-hw-name + Usage: required + Value type: + Definition: Should be "qcom,ope". + +- num-ope + Usage: required + Value type: + Definition: Number of supported OPE HW blocks. + +Example: + qcom,cam-ope { + compatible = "qcom,cam-ope"; + compat-hw-name = "qcom,ope"; + num-ope = <2>; + status = "ok"; + }; + +======================= +Required Node Structure +======================= +OPE Node provides interface for Image Control Processor driver +about the OPE register map, interrupt map, clocks, regulators. + +- cell-index + Usage: required + Value type: + Definition: Node instance number. + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,ope". + +- reg-names + Usage: optional + Value type: + Definition: Name of the register resources. + +- reg + Usage: optional + Value type: + Definition: Register values. + +- reg-cam-base + Usage: optional + Value type: + Definition: Register values. + +- interrupt-names + Usage: optional + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: optional + Value type: + Definition: Interrupt associated with OPE HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for OPE HW. + +- camss-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed + in "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CDM HW. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for CDM HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: List of strings corresponds clock-rates levels. + Supported strings: lowsvs, svs, svs_l1, nominal, turbo. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +Examples: +qcom,cam-ope { + compatible = "qcom,cam-ope"; + compat-hw-name = "qcom,ope"; + num-ope = <1>; + status = "ok"; +}; + +ope: qcom,ope@ac00000 { + cell-index = <0>; + compatible = "qcom,ope"; + reg = + <0x42000 0x400>, + <0x42400 0x200>, + <0x42600 0x200>, + <0x42800 0x4400>, + <0x46c00 0x190>, + <0x46d90 0x1270>; + reg-names = + "ope_cdm", + "ope_top", + "ope_qos", + "ope_pp", + "ope_bus_rd", + "ope_bus_wr"; + reg-cam-base = <0x42000 0x42400 0x42600 0x42800 0x46c00 0x46d90>; + interrupts = ; + interrupt-names = "ope"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&gcc_camss_top_gdsc>; + clock-names = + "ope_ahb_clk_src", + "ope_ahb_clk", + "ope_clk_src", + "ope_clk"; + clocks = + <&gcc GCC_CAMSS_OPE_AHB_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_OPE_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_CLK>; + + clock-rates = + <200000000 0 480000000 0>, + <400000000 0 600000000 0>; + + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ope_clk_src"; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-smmu.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-smmu.txt new file mode 100644 index 0000000000000000000000000000000000000000..eca2bd82ec79c278fb0edde771141e3648f84db6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-smmu.txt @@ -0,0 +1,142 @@ +* Qualcomm Technologies, Inc. MSM Camera SMMU + +The MSM camera SMMU device provides SMMU context bank definitions +for all HW blocks that need to map IOVA to physical memory. These +definitions consist of various properties that define how the +IOVA address space is laid out for each HW block in the camera +subsystem. + +======================= +Required Node Structure +======================= +The camera SMMU device must be described in three levels of device nodes. The +first level describes the overall SMMU device. Within it, second level nodes +describe individual context banks that map different stream ids. There can +also be second level nodes describing firmware device nodes. Each HW block +such as IFE, ICP maps into these second level device nodes. All context bank +specific properties that define how the IOVA is laid out is contained within +third level device nodes within the second level device nodes. + +During the kernel initialization all the devices are probed recursively and +a device pointer is created for each context bank keeping track of the IOVA +mapping information. + +Duplicate regions of the same type are not allowed within the same +context bank. All context banks must contain an IO region at the very least. + +================================== +First Level Node - CAM SMMU device +================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,msm-cam-smmu". + +=================================================================== +Second Level Node - CAM SMMU context bank device or firmware device +=================================================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,msm-cam-smmu-cb" or "qcom,msm-cam-smmu-fw-dev". + +- memory-region + Usage: optional + Value type: + Definition: Should specify the phandle of the memory region for firmware. + allocation + +- iommus + Usage: required + Value type: + Definition: first cell is phandle of the iommu, second cell is stream id + and third cell is SMR mask. + +- label + Usage: required + Value type: + Definition: Should specify a string label to identify the context bank. + +- qcom,secure-cb + Usage: optional + Value type: boolean + Definition: Specifies if the context bank is a secure context bank. + +============================================= +Third Level Node - CAM SMMU memory map device +============================================= +- iova-region-name + Usage: required + Value type: + Definition: Should specify a string label to identify the IOVA region. + +- iova-region-start + Usage: required + Value type: + Definition: Should specify start IOVA for region. + +- iova-region-len + Usage: required + Value type: + Definition: Should specify length for IOVA region. + +- iova-region-id + Usage: required + Value type: + Definition: Should specify the numerical identifier for IOVA region. + Allowed values are: 0x00 to 0x03 + - Firmware region: 0x00 + - Shared region: 0x01 + - Scratch region: 0x02 + - IO region: 0x03 + +- iova-granularity + Usage: optional + Value type: + Definition: Should specify IOVA granularity for shared memory region. + +Example: + qcom,cam_smmu@0 { + compatible = "qcom,msm-cam-smmu"; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1078>, + <&apps_smmu 0x1020>, + <&apps_smmu 0x1028>, + <&apps_smmu 0x1040>, + <&apps_smmu 0x1048>, + <&apps_smmu 0x1030>, + <&apps_smmu 0x1050>; + label = "icp"; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.5 GB */ + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tfe-csid.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tfe-csid.txt new file mode 100644 index 0000000000000000000000000000000000000000..73a4b7bc069be77a729de574c12985c53a9805fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tfe-csid.txt @@ -0,0 +1,123 @@ +* Qualcomm Technologies, Inc. MSM Camera TFE CSID + +Camera TFE CSID device provides the definitions for enabling +the TFE CSID hardware. It also provides the functions for the client +to control the TFE CSID hardware. + +======================= +Required Node Structure +======================= +The TFE CSID device is described in one level of the device node. + +====================================== +First Level Node - CAM TFE CSID device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,csid530" + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should be "csid". + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with TFE CSID HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for TFE CSID HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for TFE CSID HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for TFE CSID HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +Example: + + qcom,tfe_csid0@5c6e000 { + cell-index = <0>; + compatible = "qcom,csid530"; + reg-names = reg-names = "csid", "top", "camnoc"; + reg = <0x5c6e000 0x5000>, + <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + interrupt-names = "csid0"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_csid_clk_src", + "tfe_csid_clk", + "cphy_rx_clk_src", + "tfe_cphy_rx_clk", + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_0_CSID_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CSID_CLK>, + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_TFE_0_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <240000000 0 0 0 256000000 0 0>, + <384000000 0 0 0 460800000 0 0>, + <426400000 0 0 0 576000000 0 0>, + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tfe.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tfe.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f7c21b977650bbd49e3332c304ae79b9fc9d0cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tfe.txt @@ -0,0 +1,142 @@ +* Qualcomm Technologies, Inc. MSM Camera TFE + +Camera TFE device provides the definitions for enabling +the TFE hardware. It also provides the functions for the client +to control the TFE hardware. + +======================= +Required Node Structure +======================= +The TFE device is described in one level of the device node. + +====================================== +First Level Node - CAM TFE device +====================================== +Required properties: +- compatible + Usage: required + Value type: + Definition: Should specify the compatibility string for matching the + driver. e.g. "qcom,tfe530" + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should specify the name of the register block. + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with TFE HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for TFE HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for TFE HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for TFE HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +Optional properties: +- clock-names-option + Usage: optional + Value type: + Definition: Optional clock names. + +- clocks-option + Usage: required if clock-names-option defined + Value type: + Definition: List of optinal clocks used for TFE HW. + +- clock-rates-option + Usage: required if clock-names-option defined + Value type: + Definition: List of clocks rates for optional clocks. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +- qcom,cam-cx-ipeak: + Usage: optional + Value type: + phandle - phandle of CX Ipeak device node + bit - Every bit corresponds to a client of CX Ipeak + Definition: CX Ipeak is a mitigation scheme which throttles camera frequency + if all the clients are running at their respective threshold + frequencies to limit CX peak current. + driver in the relevant register. + +- scl-clk-names: + Usage: optional + Value type: + Definition: Scalable clock names to identify which clocks needs to update + along with source clock. + +Example: + cam_tfe0: qcom,tfe0@5c6e000{ + cell-index = <0>; + compatible = "qcom,tfe530"; + reg-names = "tfe0"; + reg = <0x5c6e000 0x5000>; + reg-cam-base = <0x6e000>; + interrupt-names = "tfe0"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_clk_src", + "tfe_clk", + "tfe_axi_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_0_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CLK>, + <&gcc GCC_CAMSS_AXI_CLK>; + clock-rates = + <256000000 0 150000000>, + <460800000 0 200000000>, + <576000000 0 300000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tpg.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tpg.txt new file mode 100644 index 0000000000000000000000000000000000000000..0e34d93ad5765f55f3715b1b5003517492503a06 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-tpg.txt @@ -0,0 +1,113 @@ +* Qualcomm Technologies, Inc. MSM Camera TPG + +Camera TPG device provides the definitions for enabling +the TPG hardware. It also provides the functions for the client +to control the TPG hardware. + +======================= +Required Node Structure +======================= +The TPG device is described in one level of the device node. + +====================================== +First Level Node - CAM TPG device +====================================== +Required properties: +- compatible + Usage: required + Value type: + Definition: Should specify the compatibility string for matching the + driver. e.g. "qcom,tpgv1" + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should specify the name of the register block. + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with TFE HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for TFE HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for TFE HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for TFE HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +- scl-clk-names: + Usage: optional + Value type: + Definition: Scalable clock names to identify which clocks needs to update + along with source clock. + +Example: + cam_tfe_tpg0: qcom,tpg0@5c66000 { + cell-index = <0>; + compatible = "qcom,tpgv1"; + reg-names = "tpg0", "top"; + reg = <0x5c66000 0x400>, + <0x5c11000 0x1000>; + reg-cam-base = <0x66000 0x11000>; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "cphy_rx_clk_src", + "tfe_0_cphy_rx_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CPHY_RX_CLK>; + clock-rates = + <240000000 240000000>, + <341333333 341333333>, + <384000000 384000000>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "cphy_rx_clk_src"; + clock-control-debugfs = "false"; + status = "ok"; + }; \ No newline at end of file diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-vfe.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-vfe.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8df9d4388a43413066f27e4059189caece09e4e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-cam-vfe.txt @@ -0,0 +1,155 @@ +* Qualcomm Technologies, Inc. MSM Camera VFE + +Camera VFE device provides the definitions for enabling +the VFE hardware. It also provides the functions for the client +to control the VFE hardware. + +======================= +Required Node Structure +======================= +The VFE device is described in one level of the device node. + +====================================== +First Level Node - CAM VFE device +====================================== +Required properties: +- compatible + Usage: required + Value type: + Definition: Should specify the compatibility string for matching the + driver. e.g. "qcom,vfe480", "qcom,vfe175", "qcom,vfe170", "qcom,vfe175_130", + "qcom,vfe170_150", "qcom,vfe-lite480", "qcom,vfe-lite175", "qcom,vfe-lite175_130", + "qcom,vfe-lite170". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg-names + Usage: required + Value type: + Definition: Should specify the name of the register block. + +- reg + Usage: required + Value type: + Definition: Register values. + +- interrupt-names + Usage: Required + Value type: + Definition: Name of the interrupt. + +- interrupts + Usage: Required + Value type: + Definition: Interrupt associated with VFE HW. + +- regulator-names + Usage: required + Value type: + Definition: Name of the regulator resources for VFE HW. + +- xxxx-supply + Usage: required + Value type: + Definition: Regulator reference corresponding to the names listed in + "regulator-names". + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for VFE HW. + +- clocks + Usage: required + Value type: + Definition: List of clocks used for VFE HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clocks rates. + +- src-clock-name + Usage: required + Value type: + Definition: Source clock name. + +Optional properties: +- clock-names-option + Usage: optional + Value type: + Definition: Optional clock names. + +- clocks-option + Usage: required if clock-names-option defined + Value type: + Definition: List of optinal clocks used for VFE HW. + +- clock-rates-option + Usage: required if clock-names-option defined + Value type: + Definition: List of clocks rates for optional clocks. + +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + +- qcom,cam-cx-ipeak: + Usage: optional + Value type: + phandle - phandle of CX Ipeak device node + bit - Every bit corresponds to a client of CX Ipeak + Definition: CX Ipeak is a mitigation scheme which throttles camera frequency + if all the clients are running at their respective threshold + frequencies to limit CX peak current. + driver in the relevant register. + +- scl-clk-names: + Usage: optional + Value type: + Definition: Scalable clock names to identify which clocks needs to update + along with source clock. + +Example: + qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe480"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + interrupts = <0 465 0>; + interrupt-names = "ife"; + vdd-names = "camss-vdd", "ife0-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + ife0-vdd-supply = <&ife_0_gdsc>; + clock-names = "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "camnoc_axi_clk", + "ife_axi_clk", + clocks = <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>, + clock-rates = <0 0 80000000 0 320000000 0 384000000 0 0 0>; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + scl-clk-en; + scl-clk-names = "ife_axi_clk"; + qcom,cam-cx-ipeak = <&cx_ipeak_lm 2>; + status = "ok"; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-camera-flash.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-camera-flash.txt new file mode 100644 index 0000000000000000000000000000000000000000..ab81329df08ed7601fa9bdb42db67bc28dcccd4a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-camera-flash.txt @@ -0,0 +1,132 @@ +* Qualcomm Technologies, Inc. MSM FLASH + +The MSM camera Flash driver provides the definitions for +enabling and disabling LED Torch/Flash by requesting it to +PMIC/I2C/GPIO based hardware. It provides the functions for +the Client to control the Flash hardware. + +======================================================= +Required Node Structure +======================================================= +The Flash device is described in one level of the device node. + +====================================== +First Level Node - CAM FLASH device +====================================== +- compatible + Usage: required + Value type: + Definition: Should be "qcom,camera-flash". + +- cell-index + Usage: required + Value type: + Definition: Should specify the hardware index id. + +- reg + Usage: required + Value type: + Definition: Register values. + +- flash-source + Usage: required + Value type: + Definition: Should contain array of phandles to Flash source nodes. + +- torch-source + Usage: required + Value type: + Definition: Should contain array of phandles to torch source nodes. + +- switch-source + Usage: Optional + Value type: + Definition: Should contain phandle to switch source nodes. + +- slave-id + Usage: optional + Value type: + Definition: should contain i2c slave address, device id address + and expected id read value. + +- cci-master + Usage: optional + Value type: + Definition: should contain i2c master id to be used for this camera + flash. + +- max-current + Usage: optional + Value type: + Definition: Max current in mA supported by flash + +- max-duration + Usage: optional + Value type: + Definition: Max duration in ms flash can glow. + +- wled-flash-support + Usage: optional + Value type: + Definition: To identity wled flash hardware support. + +- gpios + Usage: optional + Value type: + Definition: should specify the gpios to be used for the flash. + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should specify the gpio labels. + +- gpio-flash-reset + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash reset" pin. + +- gpio-flash-en + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash enable" pin. + +- gpio-flash-now + Usage: optional + Value type: + Definition: should contain index to gpio used by flash's "flash now" pin. + +Example: + +led_flash_rear: qcom,camera-flash@0 { + reg = <0x00 0x00>; + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + wled-flash-support; + qcom,slave-id = <0x00 0x00 0x0011>; + qcom,cci-master = <0>; + gpios = <&msmgpio 23 0>, + <&msmgpio 24 0>; + <&msmgpio 25 0>; + qcom,gpio-flash-reset = <0>; + qcom,gpio-flash-en = <0>; + qcom,gpio-flash-now = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <0 0>; + qcom,gpio-req-tbl-label = "FLASH_EN", + "FLASH_NOW"; + qcom,max-current = <1500>; + qcom,max-duration = <1200>; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-camera.txt b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-camera.txt new file mode 100644 index 0000000000000000000000000000000000000000..04548caa330b92ba7e02a65b360423bab2a18573 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/bindings/msm-camera.txt @@ -0,0 +1,13 @@ +* Qualcomm Technologies, Inc. MSM Camera + +Required properties: +- compatible : + - "qcom,cam-req-mgr" +- qcom,sensor-manual-probe : specify if sensor probes at kernel boot time or user driven + +Example: + + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + qcom,sensor-manual-probe; + }; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..38cf6a0e990959e5659aee8db51f492e5e5a15ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-cdp.dtsi @@ -0,0 +1,674 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_wide: qcom,actuator4 { + cell-index = <4>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_tele: qcom,actuator5 { + cell-index = <5>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_wide: qcom,eeprom4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_tele: qcom,eeprom5 { + cell-index = <5>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_triple_wide>; + led-flash-src = <&led_flash_triple_rear>; + eeprom-src = <&eeprom_triple_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_triple_tele>; + actuator-src = <&actuator_triple_tele>; + led-flash-src = <&led_flash_triple_rear_aux>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_uw: qcom,actuator6 { + cell-index = <6>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 2800000 1056000 0 2856000>; + rgltr-max-voltage = <0 3000000 1056000 0 3104000>; + rgltr-load-current = <0 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_tof: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3600000 0>; + rgltr-max-voltage = <0 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_uw: qcom,eeprom6 { + cell-index = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + eeprom-src = <&eeprom_tof>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3600000 0>; + rgltr-max-voltage = <1800000 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_triple_uw>; + actuator-src = <&actuator_triple_uw>; + led-flash-src = <&led_flash_triple_rear_aux2>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a1dab4718adf17ae25fd4182df10121ab42e4fd6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-mtp.dtsi @@ -0,0 +1,676 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_wide: qcom,actuator4 { + cell-index = <4>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_tele: qcom,actuator5 { + cell-index = <5>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_wide: qcom,eeprom4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_tele: qcom,eeprom5 { + cell-index = <5>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + actuator-src = <&actuator_rear_aux>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_triple_wide>; + led-flash-src = <&led_flash_triple_rear>; + eeprom-src = <&eeprom_triple_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_triple_tele>; + actuator-src = <&actuator_triple_tele>; + led-flash-src = <&led_flash_triple_rear_aux>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_uw: qcom,actuator6 { + cell-index = <6>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_uw: qcom,eeprom6 { + cell-index = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_tof: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3600000 0>; + rgltr-max-voltage = <0 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + eeprom-src = <&eeprom_tof>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3600000 0>; + rgltr-max-voltage = <1800000 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_triple_uw>; + actuator-src = <&actuator_triple_uw>; + led-flash-src = <&led_flash_triple_rear_aux2>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9e69a98cf38db9e64ae69947262888015146d9ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-qrd.dtsi @@ -0,0 +1,674 @@ +&soc { + led_flash_rear: qcom,camera-flash0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_wide: qcom,actuator4 { + cell-index = <4>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_tele: qcom,actuator5 { + cell-index = <5>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_uw: qcom,actuator6 { + cell-index = <6>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_wide: qcom,eeprom4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_tele: qcom,eeprom5 { + cell-index = <5>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_uw: qcom,eeprom6 { + cell-index = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + actuator-src = <&actuator_rear_aux>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_triple_wide>; + led-flash-src = <&led_flash_triple_rear>; + eeprom-src = <&eeprom_triple_wide>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_triple_tele>; + actuator-src = <&actuator_triple_tele>; + led-flash-src = <&led_flash_triple_rear_aux>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_triple_uw>; + actuator-src = <&actuator_triple_uw>; + led-flash-src = <&led_flash_triple_rear_aux2>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_tof: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3600000 0>; + rgltr-max-voltage = <0 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + eeprom-src = <&eeprom_tof>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3600000 0>; + rgltr-max-voltage = <1800000 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-rb5.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-rb5.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..261a7fe65f111c53fbbd297a68ea5cea504fe7fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-rb5.dtsi @@ -0,0 +1,278 @@ +&soc { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&tlmm { + cam_sensor_active_gmsl: cam_sensor_active_gmsl { + /* RESET */ + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + bias-pull-up; + drive-strength = <2>; /* 2 MA */ + output-high; + }; + }; + + cam_sensor_suspend_gmsl: cam_sensor_suspend_gmsl { + /* RESET */ + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; +}; + +&cam_cci0 { + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <120000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor4 { + cell-index = <4>; + status = "disable"; + }; + + qcom,cam-sensor5 { + cell-index = <5>; + status = "disable"; + }; +}; + +&cam_cci1 { + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <4>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_gmsl>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_gmsl>; + gpios = <&tlmm 94 0>, + <&tlmm 99 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET4"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <4>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 0>; + rgltr-max-voltage = <1800000 0>; + rgltr-load-current = <120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_gmsl>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_gmsl>; + gpios = <&tlmm 94 0>, + <&tlmm 99 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET4"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xr.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xr.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a9c7c216375f67558199e4e14c17b53361c671ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xr.dtsi @@ -0,0 +1,693 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <1184 1183 1182 1214 1245 1217 1216 1215>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_sensor_6dof_vana_active + &cam_sensor_6dof_vdig_active + &cam_sensor_6dof_vio_active + &cam_sensor_et_vana_active + &cam_sensor_et_vio_active + &cam_sensor_rgb_vana_active + &cam_sensor_rgb_vio_active + &cam_sensor_rgb_vdig_active>; + pinctrl-1 = <&cam_sensor_6dof_vana_suspend + &cam_sensor_6dof_vdig_suspend + &cam_sensor_6dof_vio_suspend + &cam_sensor_et_vana_suspend + &cam_sensor_et_vio_suspend + &cam_sensor_rgb_vana_suspend + &cam_sensor_rgb_vio_suspend + &cam_sensor_rgb_vdig_suspend>; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_wide: qcom,actuator4 { + cell-index = <4>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_tele: qcom,actuator5 { + cell-index = <5>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_wide: qcom,eeprom4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_tele: qcom,eeprom5 { + cell-index = <5>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + /* RGB Left (Master) */ + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rgbleft>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rgbleft>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>, + <&tlmm 117 0>, + <&tlmm 116 0>, + <&tlmm 115 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA2", + "CAM_VIO2", + "CAM_VDIG2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + /* RGB Right (Slave) */ + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rgbright>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rgbright>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>, + <&tlmm 117 0>, + <&tlmm 116 0>, + <&tlmm 115 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_VANA3", + "CAM_VIO3", + "CAM_VDIG3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + /* 6DOF Left (Slave) */ + qcom,cam-sensor4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <4>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <6000000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk4_active + &cam_sensor_active_6dofright>; + pinctrl-1 = <&cam_sensor_mclk4_suspend + &cam_sensor_suspend_6dofright>; + gpios = <&tlmm 98 0>, + <&tlmm 131 0>, + <&tlmm 84 0>, + <&tlmm 83 0>, + <&tlmm 82 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4", + "CAM_VIO4", + "CAM_VDIG4"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + /* 6DOF Right (Master) */ + qcom,cam-sensor5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <5>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <6000000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk5_active + &cam_sensor_active_6dofleft>; + pinctrl-1 = <&cam_sensor_mclk5_suspend + &cam_sensor_suspend_6dofleft>; + gpios = <&tlmm 99 0>, + <&tlmm 130 0>, + <&tlmm 84 0>, + <&tlmm 83 0>, + <&tlmm 82 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5", + "CAM_VANA5", + "CAM_VIO5", + "CAM_VDIG5"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK5_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + +}; + +&cam_cci1 { + actuator_triple_uw: qcom,actuator6 { + cell-index = <6>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_uw: qcom,eeprom6 { + cell-index = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_tof: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3600000 0>; + rgltr-max-voltage = <0 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* ET Left (Master) */ + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_etleft>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_etleft>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>, + <&tlmm 114 0>, + <&tlmm 145 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA0", + "CAM_VIO0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* ET Right (Slave) */ + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_etright>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_etright>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>, + <&tlmm 114 0>, + <&tlmm 145 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1", + "CAM_VIO1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xrfusion.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xrfusion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..996277c3af62946f9f9cfbad84d52946de1e692d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera-sensor-xrfusion.dtsi @@ -0,0 +1,746 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "disabled"; + }; + + led_flash_rear_aux: qcom,camera-flash1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "disabled"; + }; + + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "disabled"; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "disabled"; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "disabled"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + shared-gpios = <1143 1142 1141 1214 1245 1217 1216 1215>; + pinctrl-names = "cam_res_mgr_default", "cam_res_mgr_suspend"; + pinctrl-0 = <&cam_sensor_6dof_vana_active + &cam_sensor_6dof_vdig_active + &cam_sensor_6dof_vio_active + &cam_sensor_et_vana_active + &cam_sensor_et_vio_active + &cam_sensor_rgb_vana_active + &cam_sensor_rgb_vio_active + &cam_sensor_rgb_vdig_active>; + + pinctrl-1 = <&cam_sensor_6dof_vana_suspend + &cam_sensor_6dof_vdig_suspend + &cam_sensor_6dof_vio_suspend + &cam_sensor_et_vana_suspend + &cam_sensor_et_vio_suspend + &cam_sensor_rgb_vana_suspend + &cam_sensor_rgb_vio_suspend + &cam_sensor_rgb_vdig_suspend>; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_wide: qcom,actuator4 { + cell-index = <4>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + actuator_triple_tele: qcom,actuator5 { + cell-index = <5>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_wide: qcom,eeprom4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l5>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_tele: qcom,eeprom5 { + cell-index = <5>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1200000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* RGB Left (Master) */ + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rgbleft>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rgbleft>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>, + <&tlmm 117 0>, + <&tlmm 116 0>, + <&tlmm 115 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA2", + "CAM_VIO2", + "CAM_VDIG2"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* RGB Right(Slave) */ + qcom,cam-sensor3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rgbright>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rgbright>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>, + <&tlmm 117 0>, + <&tlmm 116 0>, + <&tlmm 115 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_VANA3", + "CAM_VIO3", + "CAM_VDIG3"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* 6DOF Left (Slave) */ + qcom,cam-sensor4 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <4>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l2>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <6000000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk4_active + &cam_sensor_active_6dofright>; + pinctrl-1 = <&cam_sensor_mclk4_suspend + &cam_sensor_suspend_6dofright>; + gpios = <&tlmm 98 0>, + <&tlmm 131 0>, + <&tlmm 43 0>, + <&tlmm 41 0>, + <&tlmm 42 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4", + "CAM_VIO4", + "CAM_VDIG4"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* 6DOF Left (Master) */ + qcom,cam-sensor5 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <5>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <6000000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk5_active + &cam_sensor_active_6dofleft>; + pinctrl-1 = <&cam_sensor_mclk5_suspend + &cam_sensor_suspend_6dofleft>; + gpios = <&tlmm 99 0>, + <&tlmm 130 0>, + <&tlmm 43 0>, + <&tlmm 41 0>, + <&tlmm 42 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5", + "CAM_VANA5", + "CAM_VIO5", + "CAM_VDIG5"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK5_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_uw: qcom,actuator6 { + cell-index = <6>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2856000>; + rgltr-max-voltage = <3104000>; + rgltr-load-current = <100000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_uw: qcom,eeprom6 { + cell-index = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l3>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&pm8150a_l7>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2856000>; + rgltr-max-voltage = <1800000 3000000 1056000 0 3104000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rst2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rst2>; + gpios = <&tlmm 96 0>, + <&tlmm 78 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <0>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_tof: qcom,eeprom3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8009_l7>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3600000 0>; + rgltr-max-voltage = <0 3600000 0>; + rgltr-load-current = <180000 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 97 0>, + <&tlmm 109 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-master = <1>; + status = "disabled"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* ET LEFT (Master) */ + qcom,cam-sensor0 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8009_l7>; + cam_bob-supply = <&pm8150a_bob>; + cam_vana-supply = <&pm8009_l6>; + cam_vdig-supply = <&pm8009_l1>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1104000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_etleft>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_etleft>; + gpios = <&tlmm 94 0>, + <&tlmm 93 0>, + <&tlmm 114 0>, + <&tlmm 145 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA0", + "CAM_VIO0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* ET RIGHT (Slave) Combo mode */ + qcom,cam-sensor1 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <600000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_etright>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_etright>; + gpios = <&tlmm 95 0>, + <&tlmm 92 0>, + <&tlmm 114 0>, + <&tlmm 145 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1", + "CAM_VIO1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* Face Tracking */ + qcom,cam-sensor6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_bob-supply = <&pm8150a_bob>; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009_l7>; + cam_vana-supply = <&pm8009_l6>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 3008000>; + rgltr-max-voltage = <1800000 3000000 1200000 0 3960000>; + rgltr-load-current = <6000000 80000 1200000 0 2000000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk6_active + &cam_sensor_active_etright>; + pinctrl-1 = <&cam_sensor_mclk6_suspend + &cam_sensor_active_etright>; + gpios = <&tlmm 100 0>, + <&tlmm 113 0>, + <&tlmm 51 0>, + <&tlmm 50 0>, + <&tlmm 49 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-vio = <3>; + gpio-vdig = <4>; + gpio-req-tbl-num = <0 1 2 3 4>; + gpio-req-tbl-flags = <1 0 0 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK6", + "CAM_RESET6", + "CAM_VANA6", + "CAM_VIO6", + "CAM_VDIG6"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK6_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11dc66d57e63713c21e93d5c88a52479c3734ecf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/kona-camera.dtsi @@ -0,0 +1,1707 @@ +#include + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy@ac6a000 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0x0ac6a000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0x6a000>; + interrupts = ; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + regulator-names = "gdscr", "refgen"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8150_l9>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY0_CLK>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac6c000 { + cell-index = <1>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0xac6c000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0x6c000>; + interrupts = ; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + regulator-names = "gdscr", "refgen"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8150_l9>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY1_CLK>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <400000000 0 300000000 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac6e000 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0xac6e000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0x6e000>; + interrupts = ; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + regulator-names = "gdscr", "refgen"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8150_l9>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY2_CLK>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy3: qcom,csiphy@ac70000 { + cell-index = <3>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0xac70000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0x70000>; + interrupts = ; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + regulator-names = "gdscr", "refgen"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8150_l9>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY3_CLK>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI3PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + src-clock-name = "csi3phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy4: qcom,csiphy@ac72000 { + cell-index = <4>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0xac72000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0x72000>; + interrupts = ; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + regulator-names = "gdscr", "refgen"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8150_l9>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY4_CLK>, + <&clock_camcc CAM_CC_CSI4PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI4PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy4_clk", + "csi4phytimer_clk_src", + "csi4phytimer_clk"; + src-clock-name = "csi4phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy5: qcom,csiphy@ac74000 { + cell-index = <5>; + compatible = "qcom,csiphy-v1.2.1", "qcom,csiphy"; + reg = <0xac74000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0x74000>; + interrupts = ; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + regulator-names = "gdscr", "refgen"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8150_l9>; + clocks = <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_CSIPHY5_CLK>, + <&clock_camcc CAM_CC_CSI5PHYTIMER_CLK_SRC>, + <&clock_camcc CAM_CC_CSI5PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy5_clk", + "csi5phytimer_clk_src", + "csi5phytimer_clk"; + src-clock-name = "csi5phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_cci0: qcom,cci@ac4f000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xac4f000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4f000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CCI_0_CLK_SRC>, + <&clock_camcc CAM_CC_CCI_0_CLK>; + clock-names = "cci_0_clk_src", + "cci_0_clk"; + src-clock-name = "cci_0_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <37500000 0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 101 0>, + <&tlmm 102 0>, + <&tlmm 103 0>, + <&tlmm 104 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz_cci0: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci0: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci1: qcom,cci@ac50000 { + cell-index = <1>; + compatible = "qcom,cci"; + reg = <0xac50000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x50000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CCI_1_CLK_SRC>, + <&clock_camcc CAM_CC_CCI_1_CLK>; + clock-names = "cci_1_clk_src", + "cci_1_clk"; + src-clock-name = "cci_1_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <37500000 0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci2_active &cci3_active>; + pinctrl-1 = <&cci2_suspend &cci3_suspend>; + gpios = <&tlmm 105 0>, + <&tlmm 106 0>, + <&tlmm 107 0>, + <&tlmm 108 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA2", + "CCI_I2C_CLK2", + "CCI_I2C_DATA3", + "CCI_I2C_CLK3"; + + i2c_freq_100Khz_cci1: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci1: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci1: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci1: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x800 0x400>, + <&apps_smmu 0x801 0x400>, + <&apps_smmu 0x840 0x400>, + <&apps_smmu 0x841 0x400>, + <&apps_smmu 0xC00 0x400>, + <&apps_smmu 0xC01 0x400>, + <&apps_smmu 0xC40 0x400>, + <&apps_smmu 0xC41 0x400>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x2040 0x400>, + <&apps_smmu 0x2440 0x400>; + label = "jpeg"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x20E2 0x400>, + <&apps_smmu 0x24E2 0x400>, + <&apps_smmu 0x2000 0x400>, + <&apps_smmu 0x2001 0x400>, + <&apps_smmu 0x2400 0x400>, + <&apps_smmu 0x2401 0x400>, + <&apps_smmu 0x2060 0x400>, + <&apps_smmu 0x2061 0x400>, + <&apps_smmu 0x2460 0x400>, + <&apps_smmu 0x2461 0x400>, + <&apps_smmu 0x2020 0x400>, + <&apps_smmu 0x2021 0x400>, + <&apps_smmu 0x2420 0x400>, + <&apps_smmu 0x2421 0x400>; + label = "icp"; + qcom,iommu-dma-addr-pool = <0x10c00000 0xee300000>; + iova-region-discard = <0xdff00000 0x300000>; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + iova-region-id = <0x1>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0x10a00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.7 GB */ + iova-region-name = "io"; + iova-region-start = <0x10c00000>; + iova-region-len = <0xee300000>; + iova-region-id = <0x3>; + iova-region-discard = <0xdff00000 0x300000>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* QDSS region is appropriate 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10b00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x20C0 0x400>, + <&apps_smmu 0x24C0 0x400>; + label = "cpas-cdm0"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + msm_cam_smmu_fd { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x2080 0x400>, + <&apps_smmu 0x2480 0x400>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "fd"; + fd_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x8000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = ; + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "gcc_ahb_clk", + "gcc_axi_hf_clk", + "gcc_axi_sf_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "cpas_core_ahb_clk", + "camnoc_axi_clk_src", + "camnoc_axi_clk"; + clocks = + <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_HF_AXI_CLK>, + <&clock_gcc GCC_CAMERA_SF_AXI_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CORE_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "camnoc_axi_clk_src"; + clock-rates = + <0 0 0 0 0 0 0 0>, + <0 0 0 19200000 0 0 19200000 0>, + <0 0 0 80000000 0 0 300000000 0>, + <0 0 0 80000000 0 0 400000000 0>, + <0 0 0 80000000 0 0 400000000 0>, + <0 0 0 80000000 0 0 400000000 0>, + <0 0 0 80000000 0 0 400000000 0>, + <0 0 0 80000000 0 0 480000000 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "minsvs", + "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "csiphy3", + "csiphy4", "csiphy5", "cci0", "cci1", + "csid0", "csid1", "csid2", "csid3", + "csid4", "csid5", "csid6", "ife0", + "ife1", "ife2", "ife3", "custom0", + "ipe0", "cam-cdm-intf0", "cpas-cdm0", + "bps0", "icp0", "jpeg-dma0", "jpeg-enc0", + "fd0"; + + camera-bus-nodes { + level3-nodes { + level-index = <3>; + level3_rt0_rd_wr_sum: level3-rt0-rd-wr-sum { + cell-index = <0>; + node-name = "level3-rt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_0"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { + cell-index = <1>; + node-name = "level3-nrt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_0"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_nrt1_rd_wr_sum: level3-nrt1-rd-wr-sum { + cell-index = <2>; + node-name = "level3-nrt1-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_icp"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_icp_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + + level2-nodes { + level-index = <2>; + camnoc-max-needed; + level2_rt0_wr: level2-rt0-wr { + cell-index = <3>; + node-name = "level2-rt0-wr"; + parent-node = <&level3_rt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_rt0_rd: level2-rt0-rd { + cell-index = <4>; + node-name = "level2-rt0-rd"; + parent-node = <&level3_rt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt0_wr: level2-nrt0-wr { + cell-index = <5>; + node-name = "level2-nrt0-wr"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt0_rd: level2-nrt0-rd { + cell-index = <6>; + node-name = "level2-nrt0-rd"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt1_rd: level2-nrt1-rd { + cell-index = <7>; + node-name = "level2-nrt1-rd"; + parent-node = <&level3_nrt1_rd_wr_sum>; + traffic-merge-type = + ; + bus-width-factor = <4>; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + level1_rt0_wr0: level1-rt0-wr0 { + cell-index = <8>; + node-name = "level1-rt0-wr0"; + parent-node = <&level2_rt0_wr>; + traffic-merge-type = + ; + }; + + level1_rt0_wr1: level1-rt0-wr1 { + cell-index = <9>; + node-name = "level1-rt0-wr1"; + parent-node = <&level2_rt0_wr>; + traffic-merge-type = + ; + }; + + level1_rt0_rd0: level1-rt0-rd0 { + cell-index = <10>; + node-name = "level1-rt0-rd0"; + parent-node = <&level2_rt0_rd>; + traffic-merge-type = + ; + }; + + level1_rt0_wr2: level1-rt0-wr2 { + cell-index = <11>; + node-name = "level1-rt0-wr2"; + parent-node = <&level2_rt0_wr>; + traffic-merge-type = + ; + }; + + level1_nrt0_wr0: level1-nrt0-wr0 { + cell-index = <12>; + node-name = "level1-nrt0-wr0"; + parent-node = <&level2_nrt0_wr>; + traffic-merge-type = + ; + }; + + level1_nrt0_rd0: level1-nrt0-rd0 { + cell-index = <13>; + node-name = "level1-nrt0-rd0"; + parent-node = <&level2_nrt0_rd>; + traffic-merge-type = + ; + }; + + level1_nrt0_wr1: level1-nrt0-wr1 { + cell-index = <14>; + node-name = "level1-nrt0-wr1"; + parent-node = <&level2_nrt0_wr>; + traffic-merge-type = + ; + }; + + level1_nrt0_rd2: level1-nrt0-rd2 { + cell-index = <15>; + node-name = "level1-nrt0-rd2"; + parent-node = <&level2_nrt0_rd>; + traffic-merge-type = + ; + }; + }; + + level0-nodes { + level-index = <0>; + ife0_ubwc_stats_wr: ife0-ubwc-stats-wr { + cell-index = <16>; + node-name = "ife0-ubwc-stats-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr0>; + }; + + ife1_ubwc_stats_wr: ife1-ubwc-stats-wr { + cell-index = <17>; + node-name = "ife1-ubwc-stats-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr0>; + }; + + ife0_linear_pdaf_wr: ife0-linear-pdaf-wr { + cell-index = <18>; + node-name = "ife0-linear-pdaf-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr1>; + }; + + ife1_linear_pdaf_wr: ife1-linear-pdaf-wr { + cell-index = <19>; + node-name = "ife1-linear-pdaf-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr1>; + }; + + ife2_rdi_all_wr: ife2-rdi-all-wr { + cell-index = <20>; + node-name = "ife2-rdi-all-wr"; + client-name = "ife2"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr1>; + }; + + ife3_rdi_all_wr: ife3-rdi-all-wr { + cell-index = <21>; + node-name = "ife3-rdi-all-wr"; + client-name = "ife3"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr1>; + }; + + ife0_rdi_all_rd: ife0-rdi-all-rd { + cell-index = <22>; + node-name = "ife0-rdi-all-rd"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_rd0>; + }; + + ife1_rdi_all_rd: ife1-rdi-all-rd { + cell-index = <23>; + node-name = "ife1-rdi-all-rd"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_rd0>; + }; + + custom0_all_rd: custom0-all-rd { + cell-index = <24>; + node-name = "custom0-all-rd"; + client-name = "custom0"; + traffic-data = + ; + traffic-transaction-type = + ; + parent-node = <&level1_rt0_rd0>; + }; + + ife0_rdi_pixel_raw_wr: ife0-rdi-pixel-raw-wr { + cell-index = <25>; + node-name = "ife0-rdi-pixel-raw-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr2>; + }; + + ife1_rdi_pixel_raw_wr: ife1-rdi-pixel-raw-wr { + cell-index = <26>; + node-name = "ife1-rdi-pixel-raw-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr2>; + }; + + custom0_all_wr: custom0-all-wr { + cell-index = <27>; + node-name = "custom0-all-wr"; + client-name = "custom0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_rt0_wr2>; + }; + + ipe0_all_wr: ipe0-all-wr { + cell-index = <28>; + node-name = "ipe0-all-wr"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_wr0>; + }; + + bps0_all_wr: bps0-all-wr { + cell-index = <29>; + node-name = "bps0-all-wr"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_wr0>; + }; + + ipe0_ref_rd: ipe0-ref-rd { + cell-index = <30>; + node-name = "ipe0-ref-rd"; + client-name = "ipe0"; + traffic-data = + ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd0>; + }; + + bps0_all_rd: bps0-all-rd { + cell-index = <31>; + node-name = "bps0-all-rd"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd0>; + }; + + ipe0_in_rd: ipe0-in-rd { + cell-index = <32>; + node-name = "ipe0-in-rd"; + client-name = "ipe0"; + traffic-data = + ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_rd>; + }; + + jpeg_enc0_all_wr: jpeg-enc0-all-wr { + cell-index = <33>; + node-name = "jpeg-enc0-all-wr"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_wr1>; + }; + + jpeg_dma0_all_wr: jpeg-dma0-all-wr { + cell-index = <34>; + node-name = "jpeg-dma0-all-wr"; + client-name = "jpeg-dma0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_wr1>; + }; + + jpeg_enc0_all_rd: jpeg-enc0-all-rd { + cell-index = <35>; + node-name = "jpeg-enc0-all-rd"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd2>; + }; + + jpeg_dma0_all_rd: jpeg-dma0-all-rd { + cell-index = <36>; + node-name = "jpeg-dma0-all-rd"; + client-name = "jpeg-dma0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd2>; + }; + + fd0_all_wr: fd0-all-wr { + cell-index = <37>; + node-name = "fd0-all-wr"; + client-name = "fd0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_wr>; + }; + + fd0_all_rd: fd0-all-rd { + cell-index = <38>; + node-name = "fd0-all-rd"; + client-name = "fd0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_rd>; + }; + + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <39>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_rd>; + }; + + icp0_all_rd: icp0-all-rd { + cell-index = <40>; + node-name = "icp0-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt1_rd>; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <3>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "fd"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac4d000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac4d000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x4d000>; + interrupts = ; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "cam_cc_cpas_slow_ahb_clk", + "cam_cc_cpas_ahb_clk"; + clocks = <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>; + clock-rates = <0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cpas-cdm1@acb4200 { + cell-index = <1>; + compatible = "qcom,cam480-cpas-cdm1"; + label = "cpas-cdm"; + reg = <0xacb4200 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0xb4200>; + interrupts = ; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "cam_cc_cpas_slow_ahb_clk", + "cam_cc_cpas_ahb_clk"; + clocks = <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>; + clock-rates = <0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife0"; + status = "disabled"; + }; + + qcom,cpas-cdm2@acc3200 { + cell-index = <2>; + compatible = "qcom,cam480-cpas-cdm2"; + label = "cpas-cdm"; + reg = <0xacc3200 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0xc3200>; + interrupts = ; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "cam_cc_cpas_slow_ahb_clk", + "cam_cc_cpas_ahb_clk"; + clocks = <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>; + clock-rates = <0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife1"; + status = "disabled"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb5200 { + cell-index = <0>; + compatible = "qcom,csid480"; + reg-names = "csid"; + reg = <0xacb5200 0x1000>; + reg-cam-base = <0xb5200>; + interrupt-names = "csid"; + interrupts = ; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_0_areg", + "ife_0_ahb", + "ife_axi_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CSID_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IFE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <400000000 0 400000000 0 350000000 0 100000000 0 0>, + <400000000 0 400000000 0 475000000 0 200000000 0 0>, + <400000000 0 400000000 0 576000000 0 300000000 0 0>, + <400000000 0 400000000 0 720000000 0 400000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe0: qcom,ife0@acb4000 { + cell-index = <0>; + compatible = "qcom,vfe480"; + reg-names = "ife", "cam_camnoc"; + reg = <0xacb4000 0xd000>, + <0xac42000 0x8000>; + reg-cam-base = <0xb4000 0x42000>; + interrupt-names = "ife"; + interrupts = ; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = + "ife_0_ahb", + "ife_0_areg", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 100000000 350000000 0 0>, + <0 200000000 475000000 0 0>, + <0 300000000 576000000 0 0>, + <0 400000000 720000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + scl-clk-names = "ife_0_areg"; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <720000000>; + ubwc-static-cfg = <0x1026 0x1036>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acc4200 { + cell-index = <1>; + compatible = "qcom,csid480"; + reg-names = "csid"; + reg = <0xacc4200 0x1000>; + reg-cam-base = <0xc4200>; + interrupt-names = "csid"; + interrupts = ; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_1_areg", + "ife_1_ahb", + "ife_axi_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_AREG_CLK>, + <&clock_camcc CAM_CC_IFE_1_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <400000000 0 400000000 0 350000000 0 100000000 0 0>, + <400000000 0 400000000 0 475000000 0 200000000 0 0>, + <400000000 0 400000000 0 576000000 0 300000000 0 0>, + <400000000 0 400000000 0 720000000 0 400000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe1: qcom,ife1@acc3000 { + cell-index = <1>; + compatible = "qcom,vfe480"; + reg-names = "ife", "cam_camnoc"; + reg = <0xacc3000 0xd000>, + <0xac42000 0x8000>; + reg-cam-base = <0xc3000 0x42000>; + interrupt-names = "ife"; + interrupts = ; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = + "ife_1_ahb", + "ife_1_areg", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_1_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_1_AREG_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 100000000 350000000 0 0>, + <0 200000000 475000000 0 0>, + <0 300000000 576000000 0 0>, + <0 400000000 720000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + scl-clk-names = "ife_1_areg"; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <720000000>; + ubwc-static-cfg = <0x1026 0x1036>; + status = "ok"; + }; + + cam_csid_lite0: qcom,csid-lite0@acd9200 { + cell-index = <2>; + compatible = "qcom,csid-lite480"; + reg-names = "csid-lite"; + reg = <0xacd9200 0x1000>; + reg-cam-base = <0xd9200>; + interrupt-names = "csid-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_lite_ahb", + "ife_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <400000000 0 0 0 400000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 480000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe_lite0: qcom,ife-lite0@acd9000 { + cell-index = <2>; + compatible = "qcom,vfe-lite480"; + reg-names = "ife-lite"; + reg = <0xacd9000 0x2200>; + reg-cam-base = <0xd9000>; + interrupt-names = "ife-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = + "ife_lite_ahb", + "ife_lite_axi", + "ife_clk_src", + "ife_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <0 0 400000000 0>, + <0 0 480000000 0>, + <0 0 480000000 0>, + <0 0 480000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_csid_lite1: qcom,csid-lite1@acdb400 { + cell-index = <3>; + compatible = "qcom,csid-lite480"; + reg-names = "csid-lite"; + reg = <0xacdb400 0x1000>; + reg-cam-base = <0xdb400>; + interrupt-names = "csid-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_lite_ahb", + "ife_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <400000000 0 0 0 400000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 480000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe_lite1: qcom,ife-lite1@acdb200 { + cell-index = <3>; + compatible = "qcom,vfe-lite480"; + reg-names = "ife-lite"; + reg = <0xacdb200 0x2200>; + reg-cam-base = <0xdb200>; + interrupt-names = "ife-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = + "ife_lite_ahb", + "ife_lite_axi", + "ife_clk_src", + "ife_clk"; + clocks = + <&clock_camcc CAM_CC_IFE_LITE_AHB_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <0 0 400000000 0>, + <0 0 480000000 0>, + <0 0 480000000 0>, + <0 0 480000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + status = "ok"; + icp_pc_en; + ipe_bps_pc_en; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = ; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "soc_fast_ahb", + "icp_ahb_clk", + "icp_clk_src", + "icp_clk"; + src-clock-name = "icp_clk_src"; + clocks = + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_ICP_AHB_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>, + <&clock_camcc CAM_CC_ICP_CLK>; + + clock-rates = + <100000000 0 400000000 0>, + <200000000 0 480000000 0>, + <300000000 0 600000000 0>, + <400000000 0 600000000 0>, + <400000000 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-ipe-fetch-cfg = <0x707b 0x7083>; + ubwc-ipe-write-cfg = <0x161ef 0x1620f>; + ubwc-bps-fetch-cfg = <0x707b 0x7083>; + ubwc-bps-write-cfg = <0x161ef 0x1620f>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + reg = <0xac9a000 0xc000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x9a000>; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = + "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk_src", + "ipe_0_clk"; + src-clock-name = "ipe_0_clk_src"; + clock-control-debugfs = "true"; + clocks = + <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, + <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, + <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>, + <&clock_camcc CAM_CC_IPE_0_CLK>; + + clock-rates = + <0 0 0 300000000 0>, + <0 0 0 475000000 0>, + <0 0 0 525000000 0>, + <0 0 0 700000000 0>, + <0 0 0 700000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + reg = <0xac7a000 0x8000>; + reg-names = "bps_top"; + reg-cam-base = <0x7a000>; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = + "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk_src", + "bps_clk"; + src-clock-name = "bps_clk_src"; + clock-control-debugfs = "true"; + clocks = + <&clock_camcc CAM_CC_BPS_AHB_CLK>, + <&clock_camcc CAM_CC_BPS_AREG_CLK>, + <&clock_camcc CAM_CC_BPS_AXI_CLK>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>, + <&clock_camcc CAM_CC_BPS_CLK>; + + clock-rates = + <0 0 0 200000000 0>, + <0 0 0 400000000 0>, + <0 0 0 480000000 0>, + <0 0 0 600000000 0>, + <0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac53000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac53000 0x4000>; + reg-cam-base = <0x53000>; + interrupt-names = "jpeg"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@ac57000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac57000 0x4000>; + reg-cam-base = <0x57000>; + interrupt-names = "jpegdma"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = + <&clock_camcc CAM_CC_JPEG_CLK_SRC>, + <&clock_camcc CAM_CC_JPEG_CLK>; + + clock-rates = <600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + status = "ok"; + }; + + cam_fd: qcom,fd@ac5f000 { + cell-index = <0>; + compatible = "qcom,fd600"; + reg-names = "fd_core", "fd_wrapper"; + reg = <0xac5f000 0x1000>, + <0xac60000 0x400>; + reg-cam-base = <0x5f000 0x60000>; + interrupt-names = "fd"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "fd_core_clk_src", + "fd_core_clk", + "fd_core_uar_clk"; + clocks = + <&clock_camcc CAM_CC_FD_CORE_CLK_SRC>, + <&clock_camcc CAM_CC_FD_CORE_CLK>, + <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; + src-clock-name = "fd_core_clk_src"; + clock-control-debugfs = "true"; + clock-cntl-level = "svs", "svs_l1", "turbo"; + clock-rates = + <400000000 0 0>, + <480000000 0 0>, + <600000000 0 0>; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f98331463beb6d8bc37c3ee67e138a0f7f56d6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-cdp.dtsi @@ -0,0 +1,421 @@ +#include + +&soc { + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + reg = <0x04 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + reg = <0x05 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + reg = <0x06 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_triple_rear: qcom,actuator@4 { + cell-index = <4>; + reg = <0x4>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_triple_rear_aux: qcom,actuator@5 { + cell-index = <5>; + reg = <0x5>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_triple_rear: qcom,eeprom@4 { + cell-index = <4>; + reg = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2904000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2904000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 29 0>, + <&tlmm 34 0>, + <&tlmm 50 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux: qcom,eeprom@5 { + cell-index = <5>; + reg = <5>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 2000000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 30 0>, + <&tlmm 35 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear>; + actuator-src = <&actuator_triple_rear>; + eeprom-src = <&eeprom_triple_rear>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_v_custom1-supply = <&S2A>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_v_custom1"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2904000 1104000 0 1856000>; + rgltr-max-voltage = <1800000 2904000 1104000 0 2048000>; + rgltr-load-current = <0 80000 105000 0 80000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 29 0>, + <&tlmm 34 0>, + <&tlmm 50 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + reg = <0x5>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux>; + actuator-src = <&actuator_triple_rear_aux>; + eeprom-src = <&eeprom_triple_rear_aux>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 2000000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 30 0>, + <&tlmm 35 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_rear_aux2: qcom,actuator@6 { + cell-index = <6>; + reg = <0x6>; + compatible = "qcom,actuator"; + cci-device = <1>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 32 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux2: qcom,eeprom@6 { + cell-index = <6>; + reg = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L7P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 31 0>, + <&tlmm 36 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 32 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + reg = <0x06>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux2>; + actuator-src = <&actuator_triple_rear_aux2>; + eeprom-src = <&eeprom_triple_rear_aux2>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L7P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 31 0>, + <&tlmm 36 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK6", + "CAM_RESET6"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f98331463beb6d8bc37c3ee67e138a0f7f56d6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-mtp.dtsi @@ -0,0 +1,421 @@ +#include + +&soc { + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + reg = <0x04 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + reg = <0x05 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + reg = <0x06 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_triple_rear: qcom,actuator@4 { + cell-index = <4>; + reg = <0x4>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_triple_rear_aux: qcom,actuator@5 { + cell-index = <5>; + reg = <0x5>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_triple_rear: qcom,eeprom@4 { + cell-index = <4>; + reg = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2904000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2904000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 29 0>, + <&tlmm 34 0>, + <&tlmm 50 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux: qcom,eeprom@5 { + cell-index = <5>; + reg = <5>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 2000000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 30 0>, + <&tlmm 35 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear>; + actuator-src = <&actuator_triple_rear>; + eeprom-src = <&eeprom_triple_rear>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_v_custom1-supply = <&S2A>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_v_custom1"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2904000 1104000 0 1856000>; + rgltr-max-voltage = <1800000 2904000 1104000 0 2048000>; + rgltr-load-current = <0 80000 105000 0 80000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 29 0>, + <&tlmm 34 0>, + <&tlmm 50 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + reg = <0x5>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux>; + actuator-src = <&actuator_triple_rear_aux>; + eeprom-src = <&eeprom_triple_rear_aux>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 2000000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 30 0>, + <&tlmm 35 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_rear_aux2: qcom,actuator@6 { + cell-index = <6>; + reg = <0x6>; + compatible = "qcom,actuator"; + cci-device = <1>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 32 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux2: qcom,eeprom@6 { + cell-index = <6>; + reg = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L7P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 31 0>, + <&tlmm 36 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 32 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + reg = <0x06>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux2>; + actuator-src = <&actuator_triple_rear_aux2>; + eeprom-src = <&eeprom_triple_rear_aux2>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L7P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 31 0>, + <&tlmm 36 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK6", + "CAM_RESET6"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1bb08daa1d83dfeea933f3632705f4aef7dd73b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera-sensor-qrd.dtsi @@ -0,0 +1,421 @@ +#include + +&soc { + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + reg = <0x04 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + reg = <0x05 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + reg = <0x06 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm6150l_flash0 &pm6150l_flash1>; + torch-source = <&pm6150l_torch0 &pm6150l_torch1>; + switch-source = <&pm6150l_switch2>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_triple_rear: qcom,actuator@4 { + cell-index = <4>; + reg = <0x4>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_triple_rear_aux: qcom,actuator@5 { + cell-index = <5>; + reg = <0x5>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_triple_rear: qcom,eeprom@4 { + cell-index = <4>; + reg = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2904000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2904000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 29 0>, + <&tlmm 34 0>, + <&tlmm 50 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux: qcom,eeprom@5 { + cell-index = <5>; + reg = <5>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 2000000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 30 0>, + <&tlmm 35 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear>; + actuator-src = <&actuator_triple_rear>; + eeprom-src = <&eeprom_triple_rear>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_v_custom1-supply = <&S2A>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_v_custom1"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2904000 1104000 0 2096000>; + rgltr-max-voltage = <1800000 2904000 1104000 0 2096000>; + rgltr-load-current = <0 80000 105000 0 80000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 29 0>, + <&tlmm 34 0>, + <&tlmm 50 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4", + "CAM_VANA4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + reg = <0x5>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux>; + actuator-src = <&actuator_triple_rear_aux>; + eeprom-src = <&eeprom_triple_rear_aux>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 2000000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 30 0>, + <&tlmm 35 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_rear_aux2: qcom,actuator@6 { + cell-index = <6>; + reg = <0x6>; + compatible = "qcom,actuator"; + cci-device = <1>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 32 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux2: qcom,eeprom@6 { + cell-index = <6>; + reg = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L7P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 31 0>, + <&tlmm 36 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 32 0>, + <&tlmm 37 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + reg = <0x06>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux2>; + actuator-src = <&actuator_triple_rear_aux2>; + eeprom-src = <&eeprom_triple_rear_aux2>; + cam_vio-supply = <&L6P>; + cam_vana-supply = <&L7P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 31 0>, + <&tlmm 36 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK6", + "CAM_RESET6"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..09dbb368c50cd207e949fabcad4a55b7b07684ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lagoon-camera.dtsi @@ -0,0 +1,1488 @@ +#include + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy0 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.2.3", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen", "mipi-csi-vdd1", + "mipi-csi-vdd2"; + gdscr-supply = <&cam_cc_titan_top_gdsc>; + refgen-supply = <&refgen>; + mipi-csi-vdd1-supply = <&L18A>; + mipi-csi-vdd2-supply = <&L22A>; + rgltr-cntrl-support; + rgltr-min-voltage = <0 0 880000 1200000>; + rgltr-max-voltage = <0 0 1049000 1305000>; + rgltr-load-current = <0 0 80000 80000>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy1 { + cell-index = <1>; + compatible = "qcom,csiphy-v1.2.3", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen", "mipi-csi-vdd1", + "mipi-csi-vdd2"; + gdscr-supply = <&cam_cc_titan_top_gdsc>; + refgen-supply = <&refgen>; + mipi-csi-vdd1-supply = <&L18A>; + mipi-csi-vdd2-supply = <&L22A>; + rgltr-cntrl-support; + rgltr-min-voltage = <0 0 880000 1200000>; + rgltr-max-voltage = <0 0 1049000 1305000>; + rgltr-load-current = <0 0 80000 80000>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy2 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.2.3", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen", "mipi-csi-vdd1", + "mipi-csi-vdd2"; + gdscr-supply = <&cam_cc_titan_top_gdsc>; + refgen-supply = <&refgen>; + mipi-csi-vdd1-supply = <&L18A>; + mipi-csi-vdd2-supply = <&L22A>; + rgltr-cntrl-support; + rgltr-min-voltage = <0 0 880000 1200000>; + rgltr-max-voltage = <0 0 1049000 1305000>; + rgltr-load-current = <0 0 80000 80000>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy3: qcom,csiphy3 { + cell-index = <3>; + compatible = "qcom,csiphy-v1.2.3", "qcom,csiphy"; + reg = <0xac68000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x68000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen", "mipi-csi-vdd1", + "mipi-csi-vdd2"; + gdscr-supply = <&cam_cc_titan_top_gdsc>; + refgen-supply = <&refgen>; + mipi-csi-vdd1-supply = <&L18A>; + mipi-csi-vdd2-supply = <&L22A>; + rgltr-cntrl-support; + rgltr-min-voltage = <0 0 880000 1200000>; + rgltr-max-voltage = <0 0 1049000 1305000>; + rgltr-load-current = <0 0 80000 80000>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY3_CLK>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + src-clock-name = "csi3phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_cci0: qcom,cci0 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&camcc CAM_CC_CCI_0_CLK>, + <&camcc CAM_CC_CCI_0_CLK_SRC>; + clock-names = "cci_0_clk", + "cci_0_clk_src"; + src-clock-name = "cci_0_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 39 0>, + <&tlmm 40 0>, + <&tlmm 41 0>, + <&tlmm 42 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz_cci0: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci0: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci1: qcom,cci1 { + cell-index = <1>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4b000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4b000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&cam_cc_titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&camcc CAM_CC_CCI_1_CLK>, + <&camcc CAM_CC_CCI_1_CLK_SRC>; + clock-names = "cci_clk", + "cci_1_clk_src"; + src-clock-name = "cci_1_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci2_active>; + pinctrl-1 = <&cci2_suspend>; + gpios = <&tlmm 43 0>, + <&tlmm 44 0>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA2", + "CCI_I2C_CLK2"; + + i2c_freq_100Khz_cci1: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci1: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci1: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci1: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + non-fatal-fault-disabled; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0xD40 0x20>, + <&apps_smmu 0xD60 0x20>; + label = "lrme"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x820 0xc0>, + <&apps_smmu 0x840 0x0>, + <&apps_smmu 0x860 0xc0>, + <&apps_smmu 0x880 0x0>; + label = "ife"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0xD00 0x20>, + <&apps_smmu 0xD20 0x20>; + label = "jpeg"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0xCA2 0x0>, + <&apps_smmu 0xC40 0x20>, + <&apps_smmu 0xC60 0x20>, + <&apps_smmu 0xCC0 0x20>, + <&apps_smmu 0xCE0 0x20>; + label = "icp"; + qcom,iommu-dma-addr-pool = <0x10c00000 0xee300000>; + iova-region-discard = <0xdff00000 0x300000>; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0x10A00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.7 GB */ + iova-region-name = "io"; + iova-region-start = <0x10C00000>; + iova-region-len = <0xee300000>; + iova-region-id = <0x3>; + iova-region-discard = <0xdff00000 0x300000>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10B00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0xC80 0x0>; + label = "cpas-cdm0"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = ; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_camnoc_axi_clk"; + clocks = + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170_200"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid0"; + interrupts = ; + regulator-names = "camss", "ife0"; + camss-supply = <&cam_cc_titan_top_gdsc>; + ife0-supply = <&cam_cc_ife_0_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <300000000 0 0 0 320000000 0 0>, + <384000000 0 0 0 404000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170_150"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife0"; + interrupts = ; + regulator-names = "camss", "ife0"; + camss-supply = <&cam_cc_titan_top_gdsc>; + ife0-supply = <&cam_cc_ife_0_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <320000000 0 0>, + <404000000 0 0>, + <480000000 0 0>, + <600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170_200"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid1"; + interrupts = ; + regulator-names = "camss", "ife1"; + camss-supply = <&cam_cc_titan_top_gdsc>; + ife1-supply = <&cam_cc_ife_1_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <300000000 0 0 0 320000000 0 0>, + <384000000 0 0 0 404000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170_150"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife1"; + interrupts = ; + regulator-names = "camss", "ife1"; + camss-supply = <&cam_cc_titan_top_gdsc>; + ife1-supply = <&cam_cc_ife_1_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <320000000 0 0>, + <404000000 0 0>, + <480000000 0 0>, + <600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid2: qcom,csid2@acc1000 { + cell-index = <2>; + compatible = "qcom,csid170_200"; + reg-names = "csid2"; + reg = <0xacc1000 0x1000>; + reg-cam-base = <0xc1000>; + interrupt-names = "csid"; + interrupts = ; + regulator-names = "camss", "ife2"; + camss-supply = <&cam_cc_titan_top_gdsc>; + ife2-supply = <&cam_cc_ife_2_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_2_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_2_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CLK>, + <&camcc CAM_CC_IFE_2_AXI_CLK>; + clock-rates = + <300000000 0 0 0 320000000 0 0>, + <384000000 0 0 0 404000000 0 0>, + <400000000 0 0 0 480000000 0 0>, + <400000000 0 0 0 600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe2: qcom,vfe2@acbd000 { + cell-index = <2>; + compatible = "qcom,vfe170_150"; + reg-names = "ife2"; + reg = <0xacbd000 0x4000>; + reg-cam-base = <0xbd000>; + interrupt-names = "ife"; + interrupts = ; + regulator-names = "camss", "ife2"; + camss-supply = <&cam_cc_titan_top_gdsc>; + ife2-supply = <&cam_cc_ife_2_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_2_CLK_SRC>, + <&camcc CAM_CC_IFE_2_CLK>, + <&camcc CAM_CC_IFE_2_AXI_CLK>; + clock-rates = + <320000000 0 0>, + <404000000 0 0>, + <480000000 0 0>, + <600000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_2_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <3>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk"; + clocks = + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <300000000 0 0 0 320000000 0>, + <384000000 0 0 0 400000000 0>, + <400000000 0 0 0 480000000 0>, + <400000000 0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <3>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk"; + clocks = + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <320000000 0>, + <400000000 0>, + <480000000 0>, + <600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <1>; + num-bps = <1>; + icp_pc_en; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = ; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "soc_fast_ahb", + "soc_ahb_clk", + "icp_clk", + "icp_clk_src"; + src-clock-name = "icp_clk_src"; + clocks = + <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_ICP_CLK>, + <&camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <100000000 0 0 384000000>, + <200000000 0 0 404000000>, + <300000000 0 0 600000000>, + <404000000 0 0 600000000>, + <404000000 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x73 0x1CF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + reg = <0xac87000 0xa000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&cam_cc_ipe_0_gdsc>; + clock-names = + "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + src-clock-name = "ipe_0_clk_src"; + clocks = <&camcc CAM_CC_IPE_0_AHB_CLK>, + <&camcc CAM_CC_IPE_0_AREG_CLK>, + <&camcc CAM_CC_IPE_0_AXI_CLK>, + <&camcc CAM_CC_IPE_0_CLK>, + <&camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = + <0 0 0 0 240000000>, + <0 0 0 0 320000000>, + <0 0 0 0 404000000>, + <0 0 0 0 538666666>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x8000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&cam_cc_bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + src-clock-name = "bps_clk_src"; + clocks = + <&camcc CAM_CC_BPS_AHB_CLK>, + <&camcc CAM_CC_BPS_AREG_CLK>, + <&camcc CAM_CC_BPS_AXI_CLK>, + <&camcc CAM_CC_BPS_CLK>, + <&camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = + <0 0 0 0 200000000>, + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 600000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = + <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + + clock-rates = + <600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma@0xac52000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = + <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + + clock-rates = + <600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "lrme_clk_src", + "lrme_clk"; + clocks = + <&camcc CAM_CC_LRME_CLK_SRC>, + <&camcc CAM_CC_LRME_CLK>; + clock-rates = + <200000000 0>, + <269333333 0>, + <323200000 0>, + <404000000 0>, + <404000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", + "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; + + qcom,cam-cpas@ac40000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc", "core_top_csr_tcsr"; + reg = <0xac40000 0x1000>, + <0xac42000 0x4600>, + <0x01fc0000 0x40000>; + reg-cam-base = <0x40000 0x42000 0x0>; + interrupt-names = "cpas_camnoc"; + interrupts = ; + qcom,cpas-hw-ver = <0x170200>; /* Titan v170 v2.0.0 */ + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&cam_cc_titan_top_gdsc>; + clock-names = + "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = + <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_AXI_CLK>, + <&camcc CAM_CC_SOC_AHB_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = + <0 0 0 0 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "csiphy3", "cci0", + "cci1", "csid0", "csid1", "csid2", "csid3", + "ife0", "ife1", "ife2", "ife3", "ipe0", + "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "lrmecpas0"; + + camera-bus-nodes { + level3-nodes { + level-index = <3>; + level3_rt0_wr_sum: level3-rt0-wr-sum { + cell-index = <0>; + node-name = "level3-rt0-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_0"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + + qcom,axi-port-camnoc { + qcom,msm-bus,name = + "cam_hf_0_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { + cell-index = <1>; + node-name = "level3-nrt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_0"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + + qcom,axi-port-camnoc { + qcom,msm-bus,name = + "cam_sf_0_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_nrt1_rd_wr_sum: level3-nrt1-rd-wr-sum { + cell-index = <2>; + node-name = "level3-nrt1-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_icp"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_icp_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + + qcom,axi-port-camnoc { + qcom,msm-bus,name = + "cam_sf_icp_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + + level2-nodes { + level-index = <2>; + level2_rt0_wr: level2-rt0-wr { + cell-index = <3>; + node-name = "level2-rt0-wr"; + parent-node = <&level3_rt0_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt0_rd_wr: level2-nrt0-rd-wr { + cell-index = <4>; + node-name = "level2-nrt0-rd-wr"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt1_rd: level2-nrt1-rd { + cell-index = <5>; + node-name = "level2-nrt1-rd"; + parent-node = <&level3_nrt1_rd_wr_sum>; + traffic-merge-type = + ; + bus-width-factor = <4>; + }; + }; + + level1-nodes { + level-index = <1>; + level1_rt0_wr: level1-rt0-wr { + cell-index = <6>; + node-name = "level1-rt0-wr"; + parent-node = <&level2_rt0_wr>; + traffic-merge-type = + ; + }; + + level1_rt1_wr: level1-rt1-wr { + cell-index = <7>; + node-name = "level1-rt1-wr"; + parent-node = <&level2_rt0_wr>; + traffic-merge-type = + ; + }; + + level1_nrt0_wr: level1-nrt0-wr { + cell-index = <8>; + node-name = "level1-nrt0-wr"; + parent-node = <&level2_nrt0_rd_wr>; + traffic-merge-type = + ; + }; + + level1_nrt0_rd: level1-nrt0-rd { + cell-index = <9>; + node-name = "level1-nrt0-rd"; + parent-node = <&level2_nrt0_rd_wr>; + traffic-merge-type = + ; + }; + }; + + level0-nodes { + level-index = <0>; + + ife0_rdi_all_wr: ife0-rdi-all-wr { + cell-index = <10>; + node-name = "ife0-rdi-all-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + ife1_rdi_all_wr: ife1-rdi-all-wr { + cell-index = <11>; + node-name = "ife1-rdi-all-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + ife2_rdi_all_wr: ife2-rdi-all-wr { + cell-index = <12>; + node-name = "ife2-rdi-all-wr"; + client-name = "ife2"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_wr>; + }; + + ife3_rdi_all_wr: ife3-rdi-all-wr { + cell-index = <13>; + node-name = "ife3-rdi-all-wr"; + client-name = "ife3"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_wr>; + }; + + ife0_pixelall_wr: ife0-pixelall-wr { + cell-index = <14>; + node-name = "ife0-pixelall-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + ife1_pixelall_wr: ife1-pixelall-wr { + cell-index = <15>; + node-name = "ife1-pixelall-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + ife2_pixelall_wr: ife2-pixelall-wr { + cell-index = <16>; + node-name = "ife2-pixelall-wr"; + client-name = "ife2"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_wr>; + }; + + bps0_all_wr: bps0-all-wr { + cell-index = <17>; + node-name = "bps0-all-wr"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_wr>; + }; + + bps0_all_rd: bps0-all-rd { + cell-index = <18>; + node-name = "bps0-all-rd"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd>; + }; + + ipe0_all_rd: ipe0-all-rd { + cell-index = <19>; + node-name = "ipe0-all-rd"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_rd>; + }; + + ipe0_all_wr: ipe0-all-wr { + cell-index = <20>; + node-name = "ipe0-all-wr"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_wr>; + }; + + lrme0_all_rd: lrme0-all-rd { + cell-index = <21>; + node-name = "lrme0-all-rd"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd>; + }; + + lrme0_all_wr: lrme0-all-wr { + cell-index = <22>; + node-name = "lrme0-all-wr"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_wr>; + }; + + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <23>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_rd_wr>; + }; + + jpeg0_all_wr: jpeg0-all-wr { + cell-index = <24>; + node-name = "jpeg0-all-wr"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_rd_wr>; + }; + + jpeg0_all_rd: jpeg0-all-rd { + cell-index = <25>; + node-name = "jpeg0-all-rd"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_rd_wr>; + }; + + icp0_all_rd: icp0-all-rd { + cell-index = <26>; + node-name = "icp0-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt1_rd>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c3467e225a080d521211a55fc68347bffe6318b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-cdp.dtsi @@ -0,0 +1,293 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&S8C>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1350000 0>; + rgltr-max-voltage = <1800000 2800000 1350000 0>; + rgltr-load-current = <0 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 71 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VDIG1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + status="ok"; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0>; + rgltr-max-voltage = <1800000 2800000 1104000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&S8C>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1350000 0>; + rgltr-max-voltage = <1800000 2800000 1350000 0>; + rgltr-load-current = <0 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 71 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VDIG1"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + status = "ok"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>, + <&tlmm 32 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>, + <&tlmm 32 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c3467e225a080d521211a55fc68347bffe6318b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-mtp.dtsi @@ -0,0 +1,293 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&S8C>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1350000 0>; + rgltr-max-voltage = <1800000 2800000 1350000 0>; + rgltr-load-current = <0 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 71 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VDIG1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + status="ok"; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0>; + rgltr-max-voltage = <1800000 2800000 1104000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&S8C>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1350000 0>; + rgltr-max-voltage = <1800000 2800000 1350000 0>; + rgltr-load-current = <0 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 71 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VDIG1"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + status = "ok"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>, + <&tlmm 32 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>, + <&tlmm 32 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..08cdafb240a1fba99092702df994a73b9cfe2117 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera-sensor-qrd.dtsi @@ -0,0 +1,672 @@ +#include + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + led_flash_triple_rear: qcom,camera-flash@4 { + cell-index = <4>; + reg = <0x04 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + led_flash_triple_rear_aux: qcom,camera-flash@5 { + cell-index = <5>; + reg = <0x05 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + led_flash_triple_rear_aux2: qcom,camera-flash@6 { + cell-index = <6>; + reg = <0x06 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + }; + + vreg_tof: regulator-dbb1 { + compatible = "regulator-fixed"; + regulator-name = "vdd_tof"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + gpio = <&pm8150l_gpios 2 GPIO_ACTIVE_HIGH>; + startup-delay-us = <1000>; + enable-active-high; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_triple_rear: qcom,actuator@4 { + cell-index = <4>; + reg = <0x4>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_triple_rear_aux2: qcom,actuator@6 { + cell-index = <6>; + reg = <0x6>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&S8C>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1350000 0>; + rgltr-max-voltage = <1800000 2800000 1350000 0>; + rgltr-load-current = <0 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 71 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VDIG1"; + sensor-position = <0>; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + status="ok"; + }; + + eeprom_triple_rear: qcom,eeprom@4 { + cell-index = <4>; + reg = <4>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1104000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux2: qcom,eeprom@6 { + cell-index = <6>; + reg = <6>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1056000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk4_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk4_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 25 0>, + <&tlmm 21 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK6", + "CAM_RESET6"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0>; + rgltr-max-voltage = <1800000 2800000 1104000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&S8C>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1350000 0>; + rgltr-max-voltage = <1800000 2800000 1350000 0>; + rgltr-load-current = <0 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 71 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VDIG1"; + sensor-mode = <0>; + cci-master = <1>; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + status = "ok"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear>; + actuator-src = <&actuator_triple_rear>; + eeprom-src = <&eeprom_triple_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_v_custom1-supply = <&L6P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_v_custom1"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1104000 0 1800000>; + rgltr-max-voltage = <1800000 2800000 1104000 0 1800000>; + rgltr-load-current = <0 80000 105000 0 80000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 13 0>, + <&tlmm 30 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK4", + "CAM_RESET4"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@6 { + cell-index = <6>; + compatible = "qcom,cam-sensor"; + reg = <0x06>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux2>; + actuator-src = <&actuator_triple_rear_aux2>; + eeprom-src = <&eeprom_triple_rear_aux2>; + cam_vdig-supply = <&L1P>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk4_active + &cam_sensor_active_rear_aux2>; + pinctrl-1 = <&cam_sensor_mclk4_suspend + &cam_sensor_suspend_rear_aux2>; + gpios = <&tlmm 25 0>, + <&tlmm 21 0>, + <&tlmm 51 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK6", + "CAM_RESET6", + "CAM_VANA6"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; + +&cam_cci1 { + actuator_triple_rear_aux: qcom,actuator@5 { + cell-index = <5>; + reg = <0x5>; + compatible = "qcom,actuator"; + cci-device = <1>; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>, + <&tlmm 32 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + eeprom_triple_rear_aux: qcom,eeprom@5 { + cell-index = <5>; + reg = <5>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&BOB>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3008000 1056000 0 2800000>; + rgltr-max-voltage = <1800000 4000000 1056000 0 2800000>; + rgltr-load-current = <0 2000000 105000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_triple_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_triple_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 70 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5", + "CAM_VANA5"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>, + <&tlmm 32 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + cam_vio-supply = <&L7P>; + cam_vdig-supply = <&vreg_tof>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3600000 0>; + rgltr-max-voltage = <1800000 3600000 0>; + rgltr-load-current = <0 120000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_3>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_3>; + gpios = <&tlmm 16 0>, + <&tlmm 23 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + reg = <0x5>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_triple_rear_aux>; + actuator-src = <&actuator_triple_rear_aux>; + eeprom-src = <&eeprom_triple_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&BOB>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 3008000 1056000 0>; + rgltr-max-voltage = <1800000 4000000 1056000 0>; + rgltr-load-current = <0 2000000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_triple_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_triple_rear_aux>; + gpios = <&tlmm 14 0>, + <&tlmm 29 0>, + <&tlmm 70 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK5", + "CAM_RESET5", + "CAM_VANA5"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c3c75bf1fda69700090418aa139a250c14f49d55 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lito-camera.dtsi @@ -0,0 +1,1617 @@ +#include + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy0 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.2.2", "qcom,csiphy"; + reg = <0x0ace0000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe0000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <880000>; + mipi-csi-vdd-supply = <&L5A>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY0_CLK>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy1 { + cell-index = <1>; + compatible = "qcom,csiphy-v1.2.2", "qcom,csiphy"; + reg = <0xace2000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe2000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <880000>; + mipi-csi-vdd-supply = <&L5A>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY1_CLK>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy2 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.2.2", "qcom,csiphy"; + reg = <0xace4000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe4000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <880000>; + mipi-csi-vdd-supply = <&L5A>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY2_CLK>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI2PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_csiphy3: qcom,csiphy3 { + cell-index = <3>; + compatible = "qcom,csiphy-v1.2.2", "qcom,csiphy"; + reg = <0xace6000 0x2000>; + reg-names = "csiphy"; + reg-cam-base = <0xe6000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <880000>; + mipi-csi-vdd-supply = <&L5A>; + clocks = <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_CSIPHY3_CLK>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK_SRC>, + <&camcc CAM_CC_CSI3PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + src-clock-name = "csi3phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1"; + clock-rates = + <300000000 0 300000000 0>, + <384000000 0 300000000 0>, + <400000000 0 300000000 0>; + status = "ok"; + }; + + cam_cci0: qcom,cci0 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&camcc CAM_CC_CCI_0_CLK>, + <&camcc CAM_CC_CCI_0_CLK_SRC>; + clock-names = "cci_0_clk", + "cci_0_clk_src"; + src-clock-name = "cci_0_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz_cci0: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci0: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + cam_cci1: qcom,cci1 { + cell-index = <1>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4b000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x4b000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&camcc CAM_CC_CCI_1_CLK>, + <&camcc CAM_CC_CCI_1_CLK_SRC>; + clock-names = "cci_clk", + "cci_1_clk_src"; + src-clock-name = "cci_1_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci2_active>; + pinctrl-1 = <&cci2_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 28 0>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA2", + "CCI_I2C_CLK2"; + + i2c_freq_100Khz_cci1: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci1: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci1: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci1: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x900 0x5E0>, + <&apps_smmu 0x880 0x5E0>, + <&apps_smmu 0x820 0x5E0>, + <&apps_smmu 0x920 0x5E0>, + <&apps_smmu 0x8A0 0x5E0>, + <&apps_smmu 0x940 0x5E0>, + <&apps_smmu 0x8C0 0x5E0>, + <&apps_smmu 0xD00 0x5E0>, + <&apps_smmu 0xC80 0x5E0>, + <&apps_smmu 0xC20 0x5E0>, + <&apps_smmu 0xD20 0x5E0>, + <&apps_smmu 0xCA0 0x5E0>, + <&apps_smmu 0xD40 0x5E0>, + <&apps_smmu 0xCC0 0x5E0>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "ife"; + ife_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_jpeg { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1280 0x20>, + <&apps_smmu 0x12A0 0x20>; + label = "jpeg"; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + jpeg_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_icp_fw { + compatible = "qcom,msm-cam-smmu-fw-dev"; + label="icp"; + memory-region = <&pil_camera_mem>; + }; + + msm_cam_smmu_icp { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1042 0x0>, + <&apps_smmu 0x11A0 0x0>, + <&apps_smmu 0x1220 0x0>, + <&apps_smmu 0x1300 0x20>, + <&apps_smmu 0x1320 0x20>, + <&apps_smmu 0x1180 0x0>, + <&apps_smmu 0x1200 0x0>, + <&apps_smmu 0x11E0 0x0>, + <&apps_smmu 0x1260 0x0>; + label = "icp"; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x10c00000 0xee300000>; + iova-region-discard = <0xdff00000 0x300000>; + icp_iova_mem_map: iova-mem-map { + iova-mem-region-firmware { + /* Firmware region is 5MB */ + iova-region-name = "firmware"; + iova-region-start = <0x0>; + iova-region-len = <0x500000>; + iova-region-id = <0x0>; + status = "ok"; + }; + + iova-mem-region-shared { + /* Shared region is 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + iova-region-id = <0x1>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0x10a00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3.7 GB */ + iova-region-name = "io"; + iova-region-start = <0x10c00000>; + iova-region-len = <0xee300000>; + iova-region-id = <0x3>; + iova-region-discard = <0xdff00000 0x300000>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* QDSS region is appropriate 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10b00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1000 0x0>; + label = "cpas-cdm0"; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + msm_cam_smmu_fd { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x12C0 0x20>, + <&apps_smmu 0x12E0 0x20>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "fd"; + fd_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x11C0 0x0>, + <&apps_smmu 0x1240 0x0>; + label = "lrme"; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "fd", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = ; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "cam_cc_cpas_slow_ahb_clk", + "cam_cc_cpas_ahb_clk"; + clocks = <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>; + clock-rates = <0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0 { + cell-index = <0>; + compatible = "qcom,csid175_200"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = ; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_0_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <300000000 0 0 0 380000000 0 0>, + <384000000 0 0 0 510000000 0 0>, + <400000000 0 0 0 637000000 0 0>, + <400000000 0 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0 { + cell-index = <0>; + compatible = "qcom,vfe175_130"; + reg-names = "ife"; + reg = <0xacaf000 0x5200>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = ; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_0_CLK_SRC>, + <&camcc CAM_CC_IFE_0_CLK>, + <&camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <380000000 0 0>, + <510000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <760000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1 { + cell-index = <1>; + compatible = "qcom,csid175_200"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = ; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <300000000 0 0 0 380000000 0 0>, + <384000000 0 0 0 510000000 0 0>, + <400000000 0 0 0 637000000 0 0>, + <400000000 0 0 0 760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1 { + cell-index = <1>; + compatible = "qcom,vfe175_130"; + reg-names = "ife"; + reg = <0xacb6000 0x5200>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = ; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk", + "ife_axi_clk"; + clocks = + <&camcc CAM_CC_IFE_1_CLK_SRC>, + <&camcc CAM_CC_IFE_1_CLK>, + <&camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <380000000 0 0>, + <510000000 0 0>, + <637000000 0 0>, + <760000000 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <760000000>; + status = "ok"; + }; + + cam_csid_lite0: qcom,csid-lite0 { + cell-index = <2>; + compatible = "qcom,csid-lite175"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = + "ife_csid_clk_src", + "ife_csid_clk", + "cphy_rx_clk_src", + "ife_cphy_rx_clk", + "ife_clk_src", + "ife_clk"; + clocks = + <&camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CSID_CLK>, + <&camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <300000000 0 0 0 320000000 0>, + <384000000 0 0 0 400000000 0>, + <400000000 0 0 0 480000000 0>, + <400000000 0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe_lite0: qcom,vfe-lite0 { + cell-index = <2>; + compatible = "qcom,vfe-lite175"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = + "ife_clk_src", + "ife_clk"; + clocks = + <&camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&camcc CAM_CC_IFE_LITE_CLK>; + clock-rates = + <320000000 0>, + <400000000 0>, + <480000000 0>, + <600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,ipe1", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <2>; + num-bps = <1>; + icp_pc_en; + status = "ok"; + }; + + cam_a5: qcom,a5 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = ; + interrupt-names = "a5"; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "soc_fast_ahb", + "icp_ahb_clk", + "icp_clk_src", + "icp_clk"; + src-clock-name = "icp_clk_src"; + clocks = + <&camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&camcc CAM_CC_ICP_AHB_CLK>, + <&camcc CAM_CC_ICP_CLK_SRC>, + <&camcc CAM_CC_ICP_CLK>; + + clock-rates = + <100000000 0 400000000 0>, + <200000000 0 480000000 0>, + <300000000 0 600000000 0>, + <400000000 0 600000000 0>, + <400000000 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x1073 0x101CF>; + qos-val = <0x00000A0A>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = + "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk_src", + "ipe_0_clk"; + src-clock-name = "ipe_0_clk_src"; + clock-control-debugfs = "true"; + clocks = + <&camcc CAM_CC_IPE_0_AHB_CLK>, + <&camcc CAM_CC_IPE_0_AREG_CLK>, + <&camcc CAM_CC_IPE_0_AXI_CLK>, + <&camcc CAM_CC_IPE_0_CLK_SRC>, + <&camcc CAM_CC_IPE_0_CLK>; + + clock-rates = + <0 0 0 300000000 0>, + <0 0 0 430000000 0>, + <0 0 0 520000000 0>, + <0 0 0 600000000 0>, + <0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + status = "ok"; + }; + + cam_ipe1: qcom,ipe1 { + cell-index = <1>; + compatible = "qcom,cam-ipe"; + reg = <0xac91000 0x3000>; + reg-names = "ipe1_top"; + reg-cam-base = <0x91000>; + regulator-names = "ipe1-vdd"; + ipe1-vdd-supply = <&ipe_1_gdsc>; + clock-names = + "ipe_1_ahb_clk", + "ipe_1_areg_clk", + "ipe_1_axi_clk", + "ipe_1_clk_src", + "ipe_1_clk"; + src-clock-name = "ipe_1_clk_src"; + clock-control-debugfs = "true"; + clocks = + <&camcc CAM_CC_IPE_1_AHB_CLK>, + <&camcc CAM_CC_IPE_1_AREG_CLK>, + <&camcc CAM_CC_IPE_1_AXI_CLK>, + <&camcc CAM_CC_IPE_0_CLK_SRC>, + <&camcc CAM_CC_IPE_1_CLK>; + + clock-rates = + <0 0 0 300000000 0>, + <0 0 0 430000000 0>, + <0 0 0 520000000 0>, + <0 0 0 600000000 0>, + <0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = + "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk_src", + "bps_clk"; + src-clock-name = "bps_clk_src"; + clock-control-debugfs = "true"; + clocks = + <&camcc CAM_CC_BPS_AHB_CLK>, + <&camcc CAM_CC_BPS_AREG_CLK>, + <&camcc CAM_CC_BPS_AXI_CLK>, + <&camcc CAM_CC_BPS_CLK_SRC>, + <&camcc CAM_CC_BPS_CLK>; + + clock-rates = + <0 0 0 200000000 0>, + <0 0 0 400000000 0>, + <0 0 0 480000000 0>, + <0 0 0 600000000 0>, + <0 0 0 600000000 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", + "nominal", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "jpegenc_clk_src", + "jpegenc_clk"; + clocks = + <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + + clock-rates = <600000000 0>; + src-clock-name = "jpegenc_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + cam_jpeg_dma: qcom,jpegdma { + cell-index = <0>; + compatible = "qcom,cam_jpeg_dma"; + reg-names = "jpegdma_hw"; + reg = <0xac52000 0x4000>; + reg-cam-base = <0x52000>; + interrupt-names = "jpegdma"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "jpegdma_clk_src", + "jpegdma_clk"; + clocks = + <&camcc CAM_CC_JPEG_CLK_SRC>, + <&camcc CAM_CC_JPEG_CLK>; + + clock-rates = <600000000 0>; + src-clock-name = "jpegdma_clk_src"; + clock-cntl-level = "nominal"; + status = "ok"; + }; + + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + status = "ok"; + }; + + cam_fd: qcom,fd { + cell-index = <0>; + compatible = "qcom,fd501"; + reg-names = "fd_core", "fd_wrapper"; + reg = <0xac5a000 0x1000>, + <0xac5b000 0x400>; + reg-cam-base = <0x5a000 0x5b000>; + interrupt-names = "fd"; + interrupts = ; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "fd_core_clk_src", + "fd_core_clk", + "fd_core_uar_clk"; + clocks = + <&camcc CAM_CC_FD_CORE_CLK_SRC>, + <&camcc CAM_CC_FD_CORE_CLK>, + <&camcc CAM_CC_FD_CORE_UAR_CLK>; + src-clock-name = "fd_core_clk_src"; + clock-control-debugfs = "true"; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal"; + clock-rates = + <380000000 0 0>, + <384000000 0 0>, + <480000000 0 0>, + <600000000 0 0>; + status = "ok"; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "lrme_clk_src", + "lrme_clk"; + clocks = <&camcc CAM_CC_LRME_CLK_SRC>, + <&camcc CAM_CC_LRME_CLK>; + clock-rates = <240000000 240000000>, + <300000000 300000000>, + <320000000 320000000>, + <400000000 400000000>, + <400000000 400000000>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "nominal", + "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; + + qcom,cam-cpas { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0xac40000 0x1000>, + <0xac42000 0x6000>; + reg-cam-base = <0x40000 0x42000>; + cam_hw_fuse = , + ; + interrupt-names = "cpas_camnoc"; + interrupts = ; + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = + "gcc_ahb_clk", + "gcc_axi_hf_clk", + "gcc_axi_sf_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk_src", + "camnoc_axi_clk"; + clocks = + <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMERA_HF_AXI_CLK>, + <&gcc GCC_CAMERA_SF_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CAMNOC_AXI_CLK_SRC>, + <&camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "camnoc_axi_clk_src"; + clock-rates = + <0 0 0 0 0 0 0>, + <0 0 0 80000000 0 150000000 0>, + <0 0 0 80000000 0 240000000 0>, + <0 0 0 80000000 0 320000000 0>, + <0 0 0 80000000 0 400000000 0>, + <0 0 0 80000000 0 400000000 0>, + <0 0 0 80000000 0 480000000 0>; + clock-cntl-level = "suspend", "lowsvs", "svs", + "svs_l1", "nominal", "nominal_l1", "turbo"; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "csiphy3", + "cci0", "cci1", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", + "ipe0", "ipe1", "cam-cdm-intf0", "cpas-cdm0", + "bps0", "icp0", "jpeg-dma0", "jpeg-enc0", + "fd0", "lrmecpas0"; + camera-bus-nodes { + level3-nodes { + level-index = <3>; + level3_rt0_wr_sum: level3-rt0-wr-sum { + cell-index = <0>; + node-name = "level3-rt0-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_3"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_3_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_rt1_rd_wr_sum: level3-rt1-rd-wr-sum { + cell-index = <1>; + node-name = "level3-rt1-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_1"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_nrt0_rd_wr_sum: level3-nrt0-rd-wr-sum { + cell-index = <2>; + node-name = "level3-nrt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_0"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level3_nrt1_rd_sum: level3-nrt1-rd-sum { + cell-index = <3>; + node-name = "level3-nrt1-rd-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_icp"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_4_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + + level2-nodes { + level-index = <2>; + camnoc-max-needed; + level2_rt0_write0: level2-rt0-write0 { + cell-index = <4>; + node-name = "level2-rt0-write0"; + parent-node = <&level3_rt0_wr_sum>; + traffic-merge-type = + ; + }; + + level2_rt1_read0: level2-rt1-read0 { + cell-index = <5>; + node-name = "level2-rt1-read0"; + parent-node = <&level3_rt1_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_rt1_write0: level2-rt1-write0 { + cell-index = <6>; + node-name = "level2-rt1-write0"; + parent-node = <&level3_rt1_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt0_write0: level2-nrt0-write0 { + cell-index = <7>; + node-name = "level2-nrt0-write0"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt0_read0: level2-nrt0-read0 { + cell-index = <8>; + node-name = "level2-nrt0-read0"; + parent-node = <&level3_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level2_nrt1_read0: level2-nrt1-read0 { + cell-index = <9>; + node-name = "level2-nrt1-read0"; + parent-node = <&level3_nrt1_rd_sum>; + traffic-merge-type = + ; + bus-width-factor = <4>; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + level1_rt0_write0: level1-rt0-write0 { + cell-index = <10>; + node-name = "level1-rt0-write0"; + parent-node = <&level2_rt0_write0>; + traffic-merge-type = + ; + }; + + level1_rt1_write0: level1-rt1-write0 { + cell-index = <11>; + node-name = "level1-rt1-write0"; + parent-node = <&level2_rt1_write0>; + traffic-merge-type = + ; + }; + + level1_rt1_read0: level1-rt1-read0 { + cell-index = <12>; + node-name = "level1-rt1-read0"; + parent-node = <&level2_rt1_read0>; + traffic-merge-type = + ; + }; + + level1_rt1_write1: level1-rt1-write1 { + cell-index = <13>; + node-name = "level1-rt1-write1"; + parent-node = <&level2_rt1_write0>; + traffic-merge-type = + ; + }; + + level1_nrt0_write0: level1-nrt0-write0 { + cell-index = <14>; + node-name = "level1-nrt0-write0"; + parent-node = <&level2_nrt0_write0>; + traffic-merge-type = + ; + }; + + level1_nrt0_write1: level1-nrt0-write1 { + cell-index = <15>; + node-name = "level1-nrt0-write1"; + parent-node = <&level2_nrt0_write0>; + traffic-merge-type = + ; + }; + + level1_nrt0_read0: level1-nrt0-read0 { + cell-index = <16>; + node-name = "level1-nrt0-read0"; + parent-node = <&level2_nrt0_read0>; + traffic-merge-type = + ; + }; + }; + + level0-nodes { + level-index = <0>; + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <17>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_read0>; + }; + + fd0_all_wr: fd0-all-wr { + cell-index = <18>; + node-name = "fd0-all-wr"; + client-name = "fd0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_write0>; + }; + + fd0_all_rd: fd0-all-rd { + cell-index = <19>; + node-name = "fd0-all-rd"; + client-name = "fd0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_read0>; + }; + + ife0_pixelall_wr: ife0-pixelall-wr { + cell-index = <20>; + node-name = "ife0-pixelall-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_write0>; + }; + + ife1_rdi_wr: ife1-rdi-wr { + cell-index = <21>; + node-name = "ife1-rdi-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_write0>; + }; + + ife0_rdi_wr: ife0-rdi-wr { + cell-index = <22>; + node-name = "ife0-rdi-wr"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_write0>; + }; + + ife2_rdi_wr: ife2-rdi-wr { + cell-index = <23>; + node-name = "ife2-rdi-wr"; + client-name = "ife2"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_write0>; + }; + + ife1_rdi_rd: ife1-rdi-rd { + cell-index = <24>; + node-name = "ife1-rdi-rd"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_read0>; + }; + + ife0_rdi_rd: ife0-rdi-rd { + cell-index = <25>; + node-name = "ife0-rdi-rd"; + client-name = "ife0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_read0>; + }; + + ife1_pixelall_wr: ife1-pixelall-wr { + cell-index = <26>; + node-name = "ife1-pixelall-wr"; + client-name = "ife1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt1_write1>; + }; + + bps0_all_rd: bps0-all-rd { + cell-index = <27>; + node-name = "bps0-all-rd"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_read0>; + }; + + ipe0_all_rd: ipe0-all-rd { + cell-index = <28>; + node-name = "ipe0-all-rd"; + client-name = "ipe0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_read0>; + }; + + ipe1_all_rd: ipe1-all-rd { + cell-index = <29>; + node-name = "ipe1-all-rd"; + client-name = "ipe1"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_read0>; + }; + + lrme0_all_rd: lrme0-all-rd { + cell-index = <30>; + node-name = "lrme0-all-rd"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_read0>; + }; + + bps0_all_wr: bps0-all-wr { + cell-index = <31>; + node-name = "bps0-all-wr"; + client-name = "bps0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_write0>; + }; + + ipe0_ref_wr: ipe0-ref-wr { + cell-index = <32>; + node-name = "ipe0-ref-wr"; + client-name = "ipe0"; + traffic-data = + ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_write0>; + }; + + ipe1_ref_wr: ipe1-ref-wr { + cell-index = <33>; + node-name = "ipe1-ref-wr"; + client-name = "ipe1"; + traffic-data = + ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_write0>; + }; + + lrme0_all_wr: lrme0-all-wr { + cell-index = <34>; + node-name = "lrme0-all-wr"; + client-name = "lrmecpas0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_write0>; + }; + + ipe1_viddisp_wr: ipe1-viddisp-wr { + cell-index = <35>; + node-name = "ipe1-viddisp-wr"; + client-name = "ipe1"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_write1>; + }; + + ipe0_viddisp_wr: ipe0-viddisp-wr { + cell-index = <36>; + node-name = "ipe0-viddisp-wr"; + client-name = "ipe0"; + traffic-data = + ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_write1>; + }; + + jpeg0_all_wr: jpeg0-all-wr { + cell-index = <37>; + node-name = "jpeg0-all-wr"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_write0>; + }; + + jpeg0_all_rd: jpeg0-all-rd { + cell-index = <38>; + node-name = "jpeg0-all-rd"; + client-name = "jpeg-enc0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt0_read0>; + }; + + icp0_all_rd: icp0-all-rd { + cell-index = <39>; + node-name = "icp0-all-rd"; + client-name = "icp0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level2_nrt1_read0>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lito-oem-camera-avicii.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lito-oem-camera-avicii.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..6eea473d2fbb80f7321a32870a95c5652a481bc5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lito-oem-camera-avicii.dtsi @@ -0,0 +1,1141 @@ +#include + +&pm8150l_gpios{ //pm7150a + + cam_sensor_pmi_gpio { + + cam_sensor_front_0_vana_active: cam_sensor_front_0_vana_active { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_front_0_vana_suspend: cam_sensor_front_0_vana_suspend { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + bias-pull-down; + input-disable; + }; + }; +}; + +&pm7250b_gpios{ + + cam_sensor_pmi_gpio { + + cam_sensor_rear_0_avdd_active: cam_sensor_rear_0_avdd_active { + pins = "gpio12"; + function = "normal"; + power-source = <0>; + output-low; + input-disable; + }; + + cam_sensor_rear_0_avdd_suspend: cam_sensor_rear_0_avdd_suspend { + pins = "gpio12"; + function = "normal"; + power-source = <0>; + bias-pull-down; + input-disable; + }; + }; +}; + +&soc { + led_flash_rear: qcom,camera-flash0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>;//pm8150a_bob + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_micro: qcom,camera-flash2 { + cell-index = <2>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + camera_vdig_ldo: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "camera_vdig_ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&tlmm 72 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vdig>; + vin-supply = <&pm8150a_s8>; + }; + +}; + +&pm8008_regulators { + vdd_l6-supply = <&BOB>; + vdd_l7-supply = <&BOB>; +}; + +&L6P { + regulator-max-microvolt = <2800000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <184000>; +}; + +&L7P { + regulator-max-microvolt = <2900000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <200000>; +}; + +&pm8150_s5 { + regulator-min-microvolt = <2024000>; + regulator-max-microvolt = <2024000>; +}; + +&cam_cci0 { + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L6P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <300000>; + }; + + + ois_rear_0: qcom,ois@0{ + cell-index = <0>; + reg = <0>; + compatible = "qcom,ois"; + cam_vio-supply = <&pm8150_l17>; + cam_vdig-supply = <&camera_vdig_ldo>; + cam_vaf-supply = <&L3P>; + regulator-names ="cam_vio","cam_vdig","cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 696000 2800000>; + rgltr-max-voltage = <0 1416000 2800000>; + rgltr-load-current = <0 1000000 300000>; + cci-master = <0>; + status = "ok"; + ois_gyro,position=<3>; + ois,type=<0>; + ois_gyro,type=<3>; + ois,name="LC898124"; + ois_module,vendor=<0>; + ois_actuator,vednor=<0>; + ois,fw=<1>; + }; + + eeprom_rear_0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + reg = <0x0>; + cam_vio-supply = <&pm8150_l17>; //pm7250_l17 + cam_vdig-supply = <&camera_vdig_ldo>; + cam_vana-supply = <&L7P>; //pm8008_l7 + cam_v_custom1-supply = <&pm8150_s5>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 696000 2900000 2024000 0>; + rgltr-max-voltage = <0 1416000 2900000 2024000 0>; + rgltr-load-current = <0 1000000 300000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_clock_active + &cam_sensor_rear_0_reset_active + &cam_sensor_rear_0_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 30 0>, + <&pm7250b_gpios 12 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAM_RESET0", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x01>; + cam_vio-supply = <&pm8150_l17>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <0 2800000 1056000 0>; + rgltr-max-voltage = <0 2800000 1056000 0>; + rgltr-load-current = <300000 300000 600000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_2_clock_active + &cam_sensor_rear_2_reset_active>; + + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend>; + + gpios = <&tlmm 14 0>, + <&tlmm 21 0>; + + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_front_0: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x02>; + cam_vio-supply = <&pm8150_l17>; //pm7250_l17 + cam_vdig-supply = <&camera_vdig_ldo>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 696000 3008000 0>; + rgltr-max-voltage = <0 1416000 3960000 0>; + rgltr-load-current = <0 1000000 250000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_0_clock_active + &cam_sensor_front_0_reset_active + &cam_sensor_front_0_vana_active>; + pinctrl-1 = <&cam_sensor_front_0_clock_suspend + &cam_sensor_front_0_reset_suspend + &cam_sensor_front_0_vana_suspend>; + gpios = <&tlmm 25 0>, + <&tlmm 29 0>, + <&pm8150l_gpios 9 GPIO_ACTIVE_HIGH>; //pm7150a + use-shared-clk; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_front_MCLK", + "CAM_front_RESET", + "CAM_front_VANA"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*wide camera*/ + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_0>; + eeprom-src = <&eeprom_rear_0>; + ois-src = <&ois_rear_0>; + led-flash-src = <&led_flash_rear>; + cam_vio-supply = <&pm8150_l17>; //pm7250_l17 + cam_vdig-supply = <&camera_vdig_ldo>; + cam_vana-supply = <&L7P>; //pm8008_l7 + cam_v_custom1-supply = <&pm8150_s5>; + //cam_v_custom2-supply = <&pm8009_l2>; + cam_vaf-supply = <&L6P>; //pm8008_l6 + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana","cam_v_custom1","cam_vaf", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 696000 2900000 2024000 2800000 0>; + rgltr-max-voltage = <0 1416000 2900000 2024000 2800000 0>; + rgltr-load-current = <0 1000000 300000 300000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_clock_active + &cam_sensor_rear_0_reset_active + &cam_sensor_rear_0_avdd_active>; + pinctrl-1 = <&cam_sensor_rear_0_clock_suspend + &cam_sensor_rear_0_reset_suspend + &cam_sensor_rear_0_avdd_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 30 0>, + <&pm7250b_gpios 12 GPIO_ACTIVE_HIGH>; + use-shared-clk; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_MCLK0", + "CAM_RESET0", + "CAM_CUSTOM1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*ultra wide-rear-hi846-8M*/ + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x01>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_1>; + led-flash-src = <&led_flash_rear_aux>; + cam_vio-supply = <&pm8150_l17>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <0 2800000 1056000 0>; + rgltr-max-voltage = <0 2800000 1056000 0>; + rgltr-load-current = <300000 300000 600000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_2_clock_active + &cam_sensor_rear_2_reset_active>; + + pinctrl-1 = <&cam_sensor_rear_2_clock_suspend + &cam_sensor_rear_2_reset_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 21 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Front Main-IMX616-32M*/ + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front_0>; + cam_vio-supply = <&pm8150_l17>; //pm7250_l17 + cam_vdig-supply = <&camera_vdig_ldo>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 696000 3008000 0>; + rgltr-max-voltage = <0 1416000 3960000 0>; + rgltr-load-current = <0 1000000 250000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_0_clock_active + &cam_sensor_front_0_reset_active + &cam_sensor_front_0_vana_active>; + pinctrl-1 = <&cam_sensor_front_0_clock_suspend + &cam_sensor_front_0_reset_suspend + &cam_sensor_front_0_vana_suspend>; + gpios = <&tlmm 25 0>, + <&tlmm 29 0>, + <&pm8150l_gpios 9 GPIO_ACTIVE_HIGH>; //pm7150a + use-shared-clk; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAM_front_MCLK", + "CAM_front_RESET", + "CAM_front_VANA"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK4_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + +}; + +&cam_cci1 { + + eeprom_rear_3: qcom,eeprom@3 { + cell-index = <3>; + compatible = "qcom,eeprom"; + reg = <0x3>; + cam_vio-supply = <&pm8150_l17>; + cam_vana-supply = <&L5P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <0 2800000 0>; + rgltr-max-voltage = <0 2800000 0>; + rgltr-load-current = <300000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_clock_active + &cam_sensor_rear_1_reset_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 23 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_4: qcom,eeprom@4 { + cell-index = <4>; + compatible = "qcom,eeprom"; + reg = <0x4>; + cam_vio-supply = <&pm8150_l17>; + cam_vdig-supply = <&L2P>; + cam_vana-supply = <&L5P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000 0>; + rgltr-max-voltage = <0 1104000 2800000 0>; + rgltr-load-current = <0 1056000 800000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_3_clock_active + &cam_sensor_rear_3_reset_active>; + pinctrl-1 = <&cam_sensor_rear_3_clock_suspend + &cam_sensor_rear_3_reset_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 32 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*macro_camera*/ + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x3>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_3>; + led-flash-src = <&led_flash_rear_micro>; + cam_vio-supply = <&pm8150_l17>; + cam_vana-supply = <&L5P>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <0 2800000 0>; + rgltr-max-voltage = <0 2800000 0>; + rgltr-load-current = <300000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_clock_active + &cam_sensor_rear_1_reset_active>; + pinctrl-1 = <&cam_sensor_rear_1_clock_suspend + &cam_sensor_rear_1_reset_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 23 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /* IR Rear camera: gc5035*/ + qcom,cam-sensor@4 { + cell-index = <4>; + compatible = "qcom,cam-sensor"; + reg = <0x4>; + csiphy-sd-index = <2>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + cam_vio-supply = <&pm8150_l17>; + cam_vdig-supply = <&L2P>; + cam_vana-supply = <&L5P>; + cam_clk-supply = <&titan_top_gdsc>; + eeprom-src = <&eeprom_rear_4>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 2800000 0>; + rgltr-max-voltage = <0 1104000 2800000 0>; + rgltr-load-current = <0 1056000 800000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_3_clock_active + &cam_sensor_rear_3_reset_active>; + pinctrl-1 = <&cam_sensor_rear_3_clock_suspend + &cam_sensor_rear_3_reset_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 32 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAM_MCLK3", + "CAM_RESET3"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + //front camera-gc8054-8M + qcom,cam-sensor@5 { + cell-index = <5>; + compatible = "qcom,cam-sensor"; + reg = <0x05>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_rear_4>; + cam_vio-supply = <&pm8150_l17>; + cam_vdig-supply = <&L2P>; + cam_vana-supply = <&pm8150a_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio","cam_vdig","cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 1104000 3008000 0>; + rgltr-max-voltage = <0 1104000 3960000 0>; + rgltr-load-current = <300000 600000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_clock_active + &cam_sensor_front_reset_active + &cam_sensor_front_avdd_active + &cam_sensor_front_switch_active>; + pinctrl-1 = <&cam_sensor_front_clock_suspend + &cam_sensor_front_reset_suspend + &cam_sensor_front_avdd_suspend + &cam_sensor_front_switch_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 21 0>, + <&tlmm 22 0>, + <&tlmm 56 0>; + use-shared-clk; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-custom1 = <3>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 0 0 0>; + gpio-req-tbl-label = "CAM_front_MCLK", + "CAM_front_RESET", + "CAM_front_VANA", + "CAM_custom1"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + +}; + +&tlmm { + cam_sensor_front_0_clock_active: cam_sensor_front_0_clock_active { + /* MCLK3 */ + mux { + pins = "gpio25"; + function = "cam_mclk"; + }; + + config { + pins = "gpio25"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_clock_suspend: cam_sensor_front_0_clock_suspend { + /* MCLK3 */ + mux { + pins = "gpio25"; + function = "cam_mclk"; + }; + + config { + pins = "gpio25"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_active: cam_sensor_rear_0_clock_active { + /* MCLK0 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_clock_suspend: cam_sensor_rear_0_clock_suspend { + /* MCLK0 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_active: cam_sensor_rear_1_clock_active { + /* MCLK1 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_clock_suspend: cam_sensor_rear_1_clock_suspend { + /* MCLK1 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_clock_active: cam_sensor_rear_3_clock_active { + /* MCLK4 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_clock_suspend: cam_sensor_rear_3_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_active: cam_sensor_front_clock_active { + /* MCLK2 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_clock_suspend: cam_sensor_front_clock_suspend { + /* MCLK2 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_active: cam_sensor_rear_2_clock_active { + /* MCLK4 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_clock_suspend: cam_sensor_rear_2_clock_suspend { + /* MCLK4 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_reset_active: cam_sensor_front_0_reset_active { + /* RESET 2 */ + mux { + pins = "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_reset_suspend: cam_sensor_front_0_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio29"; + function = "gpio"; + }; + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear_0_reset_active: cam_sensor_rear_0_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_reset_suspend: cam_sensor_rear_0_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_reset_active: cam_sensor_rear_1_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_reset_suspend: cam_sensor_rear_1_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_vdig: cam_sensor_rear_vdig { + pins = "gpio72"; + function = "normal"; + power-source = <0>; + drive-push-pull; + output-low; + }; + cam_sensor_rear_1_avdd_active: cam_sensor_rear_1_avdd_active { + /* RESET, STANDBY */ + mux { + pins = "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio139"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_avdd_suspend: cam_sensor_rear_1_avdd_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio139"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_active: cam_sensor_front_reset_active { + /* RESET 2 */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_reset_suspend: cam_sensor_front_reset_suspend { + /* RESET 2 */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_front_switch_active: cam_sensor_front_switch_active { + /* switch */ + mux { + pins = "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio56"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_switch_suspend: cam_sensor_front_switch_suspend { + /* switch */ + mux { + pins = "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio56"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_front_avdd_active: cam_sensor_front_avdd_active { + /* RESET 2 */ + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_avdd_suspend: cam_sensor_front_avdd_suspend { + /* RESET 2 */ + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear_2_reset_active: cam_sensor_rear_2_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_reset_suspend: cam_sensor_rear_2_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_vaf_active: cam_sensor_rear_2_vaf_active { + /* RESET, STANDBY */ + mux { + pins = "gpio159"; + function = "gpio"; + }; + + config { + pins = "gpio159"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_2_vaf_suspend: cam_sensor_rear_2_vaf_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio159"; + function = "gpio"; + }; + + config { + pins = "gpio159"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_active: cam_sensor_rear_3_reset_active { + /* RESET, STANDBY */ + mux { + pins = "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio32"; + bias-pull-down; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_3_reset_suspend: cam_sensor_rear_3_reset_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio32"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_avdd2_active: cam_sensor_rear_0_avdd2_active { + /* RESET, STANDBY */ + mux { + pins = "gpio156"; + function = "gpio"; + }; + + config { + pins = "gpio156"; + drive-strength = <16>; /* 2 MA */ + output-high; + bias-pull-up; + }; + }; + + cam_sensor_rear_0_avdd2_suspend: cam_sensor_rear_0_avdd2_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio156"; + function = "gpio"; + }; + + config { + pins = "gpio156"; + output-low; /* active low reset */ + bias-pull-down; + drive-strength = <2>; /* 2 MA */ + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/lito-v2-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/lito-v2-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9b292b1bc692ff9682baa684a413f6dfa4119f9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/lito-v2-camera.dtsi @@ -0,0 +1,16 @@ +/* Override CSIPHY version */ +&cam_csiphy0 { + compatible = "qcom,csiphy-v1.2.2.2", "qcom,csiphy"; +}; + +&cam_csiphy1 { + compatible = "qcom,csiphy-v1.2.2.2", "qcom,csiphy"; +}; + +&cam_csiphy2 { + compatible = "qcom,csiphy-v1.2.2.2", "qcom,csiphy"; +}; + +&cam_csiphy3 { + compatible = "qcom,csiphy-v1.2.2.2", "qcom,csiphy"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/scuba-camera-sensor-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/scuba-camera-sensor-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6c7655b20cd8eb9aff54121c0113ff59fcce89ed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/scuba-camera-sensor-idp.dtsi @@ -0,0 +1,313 @@ +#include +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pm2250_flash0>; + torch-source = <&pm2250_torch0>; + switch-source = <&pm2250_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + flash-source = <&pm2250_flash0>; + torch-source = <&pm2250_torch0>; + switch-source = <&pm2250_switch0>; + status = "ok"; + }; + + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; +}; + +&cam_cci0 { + actuator_rear: qcom,actuator0 { + cell-index = <0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + actuator_rear_aux: qcom,actuator1 { + cell-index = <1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&L5P>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1050000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear0_reset_suspend>; + gpios = <&tlmm 20 0>, + <&tlmm 18 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_aux: qcom,eeprom1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_vaf-supply = <&L5P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-max-voltage = <1800000 2800000 1200000 0 2800000>; + rgltr-load-current = <120000 80000 1200000 0 100000>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear1_reset_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear1_reset_suspend>; + gpios = <&tlmm 21 0>, + <&tlmm 19 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_front: qcom,eeprom2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front0_reset_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 24 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + /* Rear*/ + qcom,cam-sensor0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear>; + led-flash-src = <&led_flash_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L4P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1050000 0>; + rgltr-max-voltage = <1800000 2800000 1050000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear0_reset_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear0_reset_suspend>; + gpios = <&tlmm 20 0>, + <&tlmm 18 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + sensor-mode = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Rear Aux*/ + qcom,cam-sensor1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L3P>; + cam_vdig-supply = <&L1P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1200000 0>; + rgltr-max-voltage = <1800000 2800000 1200000 0>; + rgltr-load-current = <120000 80000 1200000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_rear1_reset_active + &cam_sensor_csi_mux_oe_active + &cam_sensor_csi_mux_sel_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_rear1_reset_suspend + &cam_sensor_csi_mux_oe_suspend + &cam_sensor_csi_mux_sel_suspend>; + gpios = <&tlmm 21 0>, + <&tlmm 19 0>, + <&tlmm 113 0>, + <&tlmm 114 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-custom2 = <3>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_CSIMUX_OE0", + "CAM_CSIMUX_SEL0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + /*Front*/ + qcom,cam-sensor2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + csiphy-sd-index = <1>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + cam_vio-supply = <&L7P>; + cam_vana-supply = <&L6P>; + cam_vdig-supply = <&L2P>; + cam_clk-supply = <&gcc_camss_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 2800000 1056000 0>; + rgltr-max-voltage = <1800000 2800000 1056000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_front0_reset_active + &cam_sensor_csi_mux_oe_active + &cam_sensor_csi_mux_sel_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_front0_reset_suspend + &cam_sensor_csi_mux_oe_suspend + &cam_sensor_csi_mux_sel_suspend>; + gpios = <&tlmm 27 0>, + <&tlmm 24 0>, + <&tlmm 113 0>, + <&tlmm 114 0>; + gpio-reset = <1>; + gpio-custom1 = <2>; + gpio-custom2 = <3>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_CSIMUX_OE0", + "CAM_CSIMUX_SEL0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&gcc GCC_CAMSS_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/camera/scuba-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/camera/scuba-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..beff5884daf87d2e31d7f22af4e7cfe1331a3322 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/camera/scuba-camera.dtsi @@ -0,0 +1,762 @@ +#include + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy0 { + cell-index = <0>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x05C52000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x52000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&gcc_camss_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&L5A>; + clocks = <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_CPHY_0_CLK>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK_SRC>, + <&gcc GCC_CAMSS_CSI0PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + clock-rates = + <19200000 0 19200000 0>, + <341330000 0 200000000 0>, + <341330000 0 200000000 0>, + <384000000 0 268800000 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy1 { + cell-index = <1>; + compatible = "qcom,csiphy-v2.0", "qcom,csiphy"; + reg = <0x05C53000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x53000>; + interrupts = ; + interrupt-names = "csiphy"; + regulator-names = "gdscr"; + gdscr-supply = <&gcc_camss_top_gdsc>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&L5A>; + clocks = <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_CPHY_1_CLK>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK_SRC>, + <&gcc GCC_CAMSS_CSI1PHYTIMER_CLK>; + clock-names = "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + clock-rates = + <19200000 0 19200000 0>, + <341330000 0 200000000 0>, + <341330000 0 200000000 0>, + <384000000 0 268800000 0>; + status = "ok"; + }; + + cam_cci0: qcom,cci0 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x05C1B000 0x1000>; + reg-names = "cci"; + reg-cam-base = <0x1B000>; + interrupt-names = "cci"; + interrupts = ; + status = "ok"; + gdscr-supply = <&gcc_camss_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&gcc GCC_CAMSS_CCI_0_CLK>, + <&gcc GCC_CAMSS_CCI_CLK_SRC>; + clock-names = "cci_0_clk", + "cci_0_clk_src"; + src-clock-name = "cci_0_clk_src"; + clock-cntl-level = "svs"; + clock-rates = <0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 22 0>, + <&tlmm 23 0>, + <&tlmm 29 0>, + <&tlmm 30 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz_cci0: qcom,i2c_standard_mode { + hw-thigh = <201>; + hw-tlow = <174>; + hw-tsu-sto = <204>; + hw-tsu-sta = <231>; + hw-thd-dat = <22>; + hw-thd-sta = <162>; + hw-tbuf = <227>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_400Khz_cci0: qcom,i2c_fast_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_custom_cci0: qcom,i2c_custom_mode { + hw-thigh = <38>; + hw-tlow = <56>; + hw-tsu-sto = <40>; + hw-tsu-sta = <40>; + hw-thd-dat = <22>; + hw-thd-sta = <35>; + hw-tbuf = <62>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + + i2c_freq_1Mhz_cci0: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <24>; + hw-scl-stretch-en = <0>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + + msm_cam_smmu_tfe { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x400 0x000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "tfe"; + tfe_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_ope { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x820 0x000>, + <&apps_smmu 0x840 0x000>; + qcom,iommu-faults = "non-fatal"; + multiple-client-devices; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + label = "ope", "ope-cdm0"; + ope_iova_mem_map: iova-mem-map { + /* IO region is approximately 3.4 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x800 0x000>; + label = "cpas-cdm0"; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; + cpas_cdm_iova_mem_map: iova-mem-map { + iova-mem-region-io { + /* IO region is approximately 3.4 GB */ + iova-region-name = "io"; + iova-region-start = <0x7400000>; + iova-region-len = <0xd8c00000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_secure { + compatible = "qcom,msm-cam-smmu-cb"; + label = "cam-secure"; + qcom,secure-cb; + }; + + }; + + qcom,cam-cpas@5c11000 { + cell-index = <0>; + compatible = "qcom,cam-cpas"; + label = "cpas"; + arch-compat = "cpas_top"; + status = "ok"; + reg-names = "cam_cpas_top", "cam_camnoc"; + reg = <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x11000 0x13000>; + cam_hw_fuse = ; + interrupt-names = "cpas_camnoc"; + interrupts = ; + camnoc-axi-min-ib-bw = <3000000000>; /*Need to be verified*/ + regulator-names = "camss-vdd"; + camss-vdd-supply = <&gcc_camss_top_gdsc>; + clock-names = + "gcc_camss_ahb_clk", + "gcc_camss_top_ahb_clk", + "gcc_camss_top_ahb_clk_src", + "gcc_camss_axi_clk", + "gcc_camss_axi_clk_src", + "gcc_camss_nrt_axi_clk", + "gcc_camss_rt_axi_clk"; + clocks = + <&gcc GCC_CAMERA_AHB_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK>, + <&gcc GCC_CAMSS_TOP_AHB_CLK_SRC>, + <&gcc GCC_CAMSS_AXI_CLK>, + <&gcc GCC_CAMSS_AXI_CLK_SRC>, + <&gcc GCC_CAMSS_NRT_AXI_CLK>, + <&gcc GCC_CAMSS_RT_AXI_CLK>; + src-clock-name = "gcc_camss_axi_clk_src"; + clock-rates = + <0 0 0 0 0 0 0>, + <0 0 80000000 0 19200000 0 0>, + <0 0 80000000 0 150000000 0 0>, + <0 0 80000000 0 200000000 0 0>, + <0 0 80000000 0 300000000 0 0>, + <0 0 80000000 0 300000000 0 0>, + <0 0 80000000 0 300000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + control-camnoc-axi-clk; + camnoc-bus-width = <32>; + camnoc-axi-clk-bw-margin-perc = <20>; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "minsvs", + "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "cci0", + "csid0", "csid1", "tfe0", + "tfe1", "ope0", "cam-cdm-intf0", + "cpas-cdm0", "ope-cdm0", "tpg0", "tpg1"; + + camera-bus-nodes { + level2-nodes { + level-index = <2>; + level2_rt0_rd_wr_sum: level2-rt0-rd-wr-sum { + cell-index = <0>; + node-name = "level2-rt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_hf_0"; + ib-bw-voting-needed; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_hf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + + level2_nrt0_rd_wr_sum: level2-nrt0-rd-wr-sum { + cell-index = <1>; + node-name = "level2-nrt0-rd-wr-sum"; + traffic-merge-type = + ; + qcom,axi-port-name = "cam_sf_0"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = + "cam_sf_0_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + + level1-nodes { + level-index = <1>; + camnoc-max-needed; + level1_rt0_wr: level1-rt0-wr { + cell-index = <2>; + node-name = "level1-rt0-wr"; + parent-node = <&level2_rt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + + level1_nrt0_rd_wr: level1-nrt0-rd-wr { + cell-index = <3>; + node-name = "level1-nrt0-rd-wr"; + parent-node = <&level2_nrt0_rd_wr_sum>; + traffic-merge-type = + ; + }; + }; + + level0-nodes { + level-index = <0>; + ope0_all_wr: ope0-all-wr { + cell-index = <4>; + node-name = "ope0-all-wr"; + client-name = "ope0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + + ope0_all_rd: ope0-all-rd { + cell-index = <5>; + node-name = "ope0-all-rd"; + client-name = "ope0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + + tfe0_all_wr: tfe0-all-wr { + cell-index = <6>; + node-name = "tfe0-all-wr"; + client-name = "tfe0"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + tfe1_all_wr: tfe1-all-wr { + cell-index = <7>; + node-name = "tfe1-all-wr"; + client-name = "tfe1"; + traffic-data = ; + traffic-transaction-type = + ; + constituent-paths = + ; + parent-node = <&level1_rt0_wr>; + }; + + cpas_cdm0_all_rd: cpas-cdm0-all-rd { + cell-index = <9>; + node-name = "cpas-cdm0-all-rd"; + client-name = "cpas-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + + ope_cdm0_all_rd: ope-cdm0-all-rd { + cell-index = <10>; + node-name = "ope-cdm0-all-rd"; + client-name = "ope-cdm0"; + traffic-data = ; + traffic-transaction-type = + ; + parent-node = <&level1_nrt0_rd_wr>; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <2>; + cdm-client-names = "vfe"; + status = "ok"; + }; + + cam_cpas_cdm: qcom,cpas-cdm0@5c23000 { + cell-index = <0>; + compatible = "qcom,cam-cpas-cdm2_0"; + label = "cpas-cdm"; + reg = <0x5c23000 0x400>; + reg-names = "cpas-cdm0"; + reg-cam-base = <0x23000>; + interrupts = ; + interrupt-names = "cpas-cdm0"; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = "cam_cc_cpas_top_ahb_clk"; + clocks = <&gcc GCC_CAMSS_TOP_AHB_CLK>; + clock-rates = <0>; + clock-cntl-level = "svs"; + cdm-client-names = "tfe0", "tfe1"; + config-fifo; + fifo-depths = <64 64 64 64>; + status = "ok"; + }; + + cam_ope_cdm: qcom,ope-cdm0@5c42000 { + cell-index = <0>; + compatible = "qcom,cam-ope-cdm2_0"; + label = "ope-cdm"; + reg = <0x5c42000 0x400>; + reg-names = "ope-cdm0"; + reg-cam-base = <0x42000>; + interrupts = ; + interrupt-names = "ope-cdm0"; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "ope_ahb_clk", + "ope_clk_src", + "ope_clk"; + clocks = + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_OPE_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_CLK>; + clock-rates = <0 0 0>, + <0 0 0>, + <0 0 0>, + <0 0 0>; + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + cdm-client-names = "ope"; + config-fifo; + fifo-depths = <64 64 64 64>; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "tfe"; + status = "ok"; + }; + + cam_tfe_csid0: qcom,tfe_csid0@5c6e000 { + cell-index = <0>; + compatible = "qcom,csid530"; + reg-names = "csid", "top", "camnoc"; + reg = <0x5c6e000 0x1000>, + <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x6e000 0x11000 0x13000>; + interrupt-names = "csid0"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_csid_clk_src", + "tfe_csid_clk", + "cphy_rx_clk_src", + "tfe_cphy_rx_clk", + "tfe_clk_src", + "tfe_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_0_CSID_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CSID_CLK>, + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_TFE_0_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CLK>; + clock-rates = + <240000000 0 240000000 0 256000000 0>, + <384000000 0 341333333 0 460800000 0>, + <426400000 0 384000000 0 576000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe0: qcom,tfe0@5c6e000 { + cell-index = <0>; + compatible = "qcom,tfe530"; + reg-names = "tfe0"; + reg = <0x5c6e000 0x5000>; + reg-cam-base = <0x6e000>; + interrupt-names = "tfe0"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_clk_src", + "tfe_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_0_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CLK>; + clock-rates = + <256000000 0>, + <460800000 0>, + <576000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe_csid1: qcom,tfe_csid1@5c75000 { + cell-index = <1>; + compatible = "qcom,csid530"; + reg-names = "csid", "top", "camnoc"; + reg = <0x5c75000 0x1000>, + <0x5c11000 0x1000>, + <0x5c13000 0x4000>; + reg-cam-base = <0x75000 0x11000 0x13000>; + interrupt-names = "csid1"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_csid_clk_src", + "tfe_csid_clk", + "cphy_rx_clk_src", + "tfe_cphy_rx_clk", + "tfe_clk_src", + "tfe_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_1_CSID_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CSID_CLK>, + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_TFE_1_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CLK>; + clock-rates = + <240000000 0 240000000 0 256000000 0>, + <384000000 0 341333333 0 460800000 0>, + <426400000 0 384000000 0 576000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe1: qcom,tfe1@5c75000 { + cell-index = <1>; + compatible = "qcom,tfe530"; + reg-names = "tfe1"; + reg = <0x5c75000 0x5000>; + reg-cam-base = <0x75000>; + interrupt-names = "tfe1"; + interrupts = ; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "tfe_clk_src", + "tfe_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_1_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CLK>; + clock-rates = + <256000000 0>, + <460800000 0>, + <576000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "tfe_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_tfe_tpg0: qcom,tpg0@5c66000 { + cell-index = <0>; + compatible = "qcom,tpgv1"; + reg-names = "tpg0", "top"; + reg = <0x5c66000 0x400>, + <0x5c11000 0x1000>; + reg-cam-base = <0x66000 0x11000>; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "cphy_rx_clk_src", + "tfe_0_cphy_rx_clk", + "gcc_camss_cphy_0_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_0_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_CPHY_0_CLK>; + clock-rates = + <240000000 0 0>, + <341333333 0 0>, + <384000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "cphy_rx_clk_src"; + clock-control-debugfs = "false"; + status = "ok"; + }; + + cam_tfe_tpg1: qcom,tpg0@5c68000 { + cell-index = <1>; + compatible = "qcom,tpgv1"; + reg-names = "tpg0", "top"; + reg = <0x5c68000 0x400>, + <0x5c11000 0x1000>; + reg-cam-base = <0x68000 0x11000>; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "cphy_rx_clk_src", + "tfe_1_cphy_rx_clk", + "gcc_camss_cphy_1_clk"; + clocks = + <&gcc GCC_CAMSS_TFE_CPHY_RX_CLK_SRC>, + <&gcc GCC_CAMSS_TFE_1_CPHY_RX_CLK>, + <&gcc GCC_CAMSS_CPHY_1_CLK>; + clock-rates = + <240000000 0 0>, + <341333333 0 0>, + <384000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "cphy_rx_clk_src"; + clock-control-debugfs = "false"; + status = "ok"; + }; + + qcom,cam-ope { + compatible = "qcom,cam-ope"; + compat-hw-name = "qcom,ope"; + num-ope = <1>; + status = "ok"; + }; + + ope: qcom,ope@0x5c42000 { + cell-index = <0>; + compatible = "qcom,ope"; + reg = + <0x5c42000 0x400>, + <0x5c42400 0x200>, + <0x5c42600 0x200>, + <0x5c42800 0x4400>, + <0x5c46c00 0x190>, + <0x5c46d90 0xA00>; + reg-names = + "ope_cdm", + "ope_top", + "ope_qos", + "ope_pp", + "ope_bus_rd", + "ope_bus_wr"; + reg-cam-base = <0x42000 0x42400 0x42600 0x42800 0x46c00 0x46d90>; + interrupts = ; + interrupt-names = "ope"; + regulator-names = "camss"; + camss-supply = <&gcc_camss_top_gdsc>; + clock-names = + "ope_ahb_clk_src", + "ope_ahb_clk", + "ope_clk_src", + "ope_clk"; + clocks = + <&gcc GCC_CAMSS_OPE_AHB_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_AHB_CLK>, + <&gcc GCC_CAMSS_OPE_CLK_SRC>, + <&gcc GCC_CAMSS_OPE_CLK>; + clock-rates = + <171428571 0 200000000 0>, + <171428571 0 266600000 0>, + <240000000 0 465000000 0>, + <240000000 0 580000000 0>; + clock-cntl-level = "svs", "svs_l1", "nominal", "turbo"; + src-clock-name = "ope_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-ext-bridge-1080p.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-ext-bridge-1080p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..07d398e9e16c70c6ec384a7788357e078e16053a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-ext-bridge-1080p.dtsi @@ -0,0 +1,46 @@ +&mdss_mdp { + dsi_ext_bridge_1080p: qcom,mdss_dsi_ext_bridge_1080p { + qcom,mdss-dsi-panel-name = "ext video mode dsi bridge"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x24>; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-ext-bridge-mode; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1920>; + qcom,mdss-dsi-panel-height = <1080>; + qcom,mdss-dsi-h-front-porch = <88>; + qcom,mdss-dsi-h-back-porch = <148>; + qcom,mdss-dsi-h-pulse-width = <44>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <36>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <5>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9dc1a26207f3bef449561b31f98e56f6b70d99cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi @@ -0,0 +1,151 @@ +&mdss_mdp { + dsi_hx83112a_truly_video: qcom,mdss_dsi_hx83112a_truly_video { + qcom,mdss-dsi-panel-name = + "hx83112a video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <42>; + qcom,mdss-dsi-h-back-porch = <42>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <15>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <3>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 83 11 2A + 39 01 00 00 00 00 09 B1 08 29 29 00 00 4F 54 + 33 + 39 01 00 00 00 00 11 B2 00 02 00 80 70 00 08 + 26 FC 01 00 03 15 A3 87 09 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 03 D2 2C 2C + 39 01 00 00 00 00 1C B4 01 CE 01 CE 01 CE 0A + CE 0A CE 0A CE 00 FF 00 FF 00 00 22 23 00 + 28 0A 13 14 00 8A + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0A B4 00 92 12 22 88 12 12 + 00 53 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 04 B6 82 82 E3 + 39 01 00 00 00 00 02 CC 08 + 39 01 00 00 00 00 2B D3 40 00 00 00 00 01 01 + 0A 0A 07 07 00 08 09 09 09 09 32 10 09 00 + 09 32 21 0A 00 0A 32 10 08 00 00 00 00 00 + 00 00 00 00 0B 08 82 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 09 D3 00 00 19 00 00 0A 00 + 81 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 31 D5 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 01 00 07 06 05 04 03 02 21 20 18 + 18 19 19 18 18 03 03 18 18 18 18 18 18 + 39 01 00 00 00 00 31 D6 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 02 03 04 05 06 07 00 01 20 21 18 + 18 18 18 19 19 20 20 18 18 18 18 18 18 + 39 01 00 00 00 00 19 D8 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0D D8 AF FF FA AA BA AA AA + FF FA AA BA AA + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 18 E7 0E 0E 1E 6A 1D 6A 00 + 32 02 02 00 00 02 02 02 05 14 14 32 B9 23 + B9 08 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 0A E7 02 00 98 01 9A 0D A8 + 0E 01 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 1E E7 00 00 08 00 01 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 04 00 00 00 00 02 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 C1 01 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 E9 C3 + 39 01 00 00 00 00 03 CB 92 01 + 39 01 00 00 00 00 02 E9 3F + 39 01 00 00 00 00 07 C7 70 00 04 E0 33 00 + 39 01 00 00 00 00 03 51 0F FF + 39 01 00 00 00 00 02 53 24 + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-hx8394d-720p-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-hx8394d-720p-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6de6c6c4c8599cf14f3f7e5e139499fb03f3a368 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-hx8394d-720p-video.dtsi @@ -0,0 +1,87 @@ +&mdss_mdp { + dsi_hx8394d_720_vid: qcom,mdss_dsi_hx8394d_720p_video { + qcom,mdss-dsi-panel-name = "hx8394d 720p video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 b9 ff 83 94 + 39 01 00 00 00 00 03 ba 33 83 + 39 01 00 00 00 00 10 b1 6c 12 12 + 37 04 11 f1 80 ec 94 23 80 c0 + d2 18 + 39 01 00 00 00 00 0c b2 00 64 0e + 0d 32 23 08 08 1c 4d 00 + 39 01 00 00 00 00 0d b4 00 ff 03 + 50 03 50 03 50 01 6a 01 6a + 39 01 00 00 00 00 02 bc 07 + 39 01 00 00 00 00 04 bf 41 0e 01 + 39 01 00 00 00 00 1f d3 00 07 00 + 00 00 10 00 32 10 05 00 00 32 + 10 00 00 00 32 10 00 00 00 36 + 03 09 09 37 00 00 37 + 39 01 00 00 00 00 2d d5 02 03 00 + 01 06 07 04 05 20 21 22 23 18 + 18 18 18 18 18 18 18 18 18 18 + 18 18 18 18 18 18 18 18 18 18 + 18 18 18 18 18 24 25 18 18 19 + 19 + 39 01 00 00 00 00 2d d6 05 04 07 + 06 01 00 03 02 23 22 21 20 18 + 18 18 18 18 18 58 58 18 18 18 + 18 18 18 18 18 18 18 18 18 18 + 18 18 18 18 18 25 24 19 19 18 + 18 + 39 01 00 00 00 00 02 cc 09 + 39 01 00 00 00 00 03 c0 30 14 + 39 01 00 00 00 00 05 c7 00 c0 40 c0 + 39 01 00 00 00 00 03 b6 43 43 + 05 01 00 00 c8 00 02 11 00 + 05 01 00 00 0a 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [ + 79 1a 12 00 3e 42 + 16 1e 15 03 04 00 + ]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1b>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>; + qcom,mdss-pan-physical-width-dimension = <59>; + qcom,mdss-pan-physical-height-dimension = <104>; + + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8a05258d0e43b5e78b85425b01ebe334b768e5ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi @@ -0,0 +1,240 @@ +&mdss_mdp { + dsi_nt35597_truly_dsc_cmd: qcom,mdss_dsi_nt35597_dsc_cmd_truly { + qcom,mdss-dsi-panel-name = + "nt35597 cmd mode dsi truly panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x1 0x1>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f ae + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6D + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c D8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 C0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2d888cbce876ceb317e52d517ebdd7db5782fcf1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -0,0 +1,226 @@ +&mdss_mdp { + dsi_nt35597_truly_dsc_video: qcom,mdss_dsi_nt35597_dsc_video_truly { + qcom,mdss-dsi-panel-name = + "nt35597 video mode dsi truly panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-dma-schedule-line = <5>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x00(2 Port SDC); + * 0x01(1 PortA FBC); + * 0x02(MTK); 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 39 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 03 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cddf9165ff1fb05ea90fcd8c996e398563b5b6d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,219 @@ +&mdss_mdp { + dsi_dual_nt35597_truly_cmd: qcom,mdss_dsi_nt35597_truly_wqxga_cmd { + qcom,mdss-dsi-panel-name = + "Dual nt35597 cmd mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-jitter = <0x1 0x1>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..aff695014114bdeb9b0c918fb398c2bbcecfb134 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -0,0 +1,206 @@ +&mdss_mdp { + dsi_dual_nt35597_truly_video: qcom,mdss_dsi_nt35597_wqxga_video_truly { + qcom,mdss-dsi-panel-name = + "Dual nt35597 video mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-underflow-color = <0x3ff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-bpp = <24>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 FF 24 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 FF 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 03 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35695b-truly-fhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35695b-truly-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ffefa6a671d62d5e9cb996ec2315aa8eb8c0a9de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35695b-truly-fhd-cmd.dtsi @@ -0,0 +1,185 @@ +&mdss_mdp { + dsi_nt35695b_truly_fhd_cmd: qcom,mdss_dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd command mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + qcom,dsi-select-sec-clocks = "src_byte_clk1", "src_pixel_clk1"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 + 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35695b-truly-fhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35695b-truly-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fe84525de19741f4c19eee4b481b57e5e562a72d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt35695b-truly-fhd-video.dtsi @@ -0,0 +1,177 @@ +&mdss_mdp { + dsi_nt35695b_truly_fhd_video: qcom,mdss_dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 03 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 14 00 02 28 00 05 01 00 00 78 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d066925a86f2fe9488a49da09ad15f68c87f879b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,80 @@ +&mdss_mdp { + dsi_dual_nt36850_truly_cmd: qcom,mdss_dsi_nt36850_truly_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual nt36850 cmd mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 50>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <140>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 44 03 e8 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 2c + 15 01 00 00 00 00 02 55 01 + 05 01 00 00 0a 00 02 20 00 + 15 01 00 00 00 00 02 bb 10 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11eb3a30d232cffdb3225a895e4775083239968c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,129 @@ +&mdss_mdp { + dsi_dual_s6e3ha3_amoled_cmd: qcom,mdss_dsi_s6e3ha3_amoled_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual s6e3ha3 amoled cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <31>; + qcom,mdss-dsi-v-front-porch = <30>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-on-command = [05 01 00 00 05 00 02 11 00 + 39 01 00 00 00 00 05 2a 00 00 05 9f + 39 01 00 00 00 00 05 2b 00 00 09 ff + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 02 b0 10 + 39 01 00 00 00 00 02 b5 a0 + 39 01 00 00 00 00 02 c4 03 + 39 01 00 00 00 00 0a + f6 42 57 37 00 aa cc d0 00 00 + 39 01 00 00 00 00 02 f9 03 + 39 01 00 00 00 00 14 + c2 00 00 d8 d8 00 80 2b 05 08 + 0e 07 0b 05 0d 0a 15 13 20 1e + 39 01 00 00 78 00 03 f0 a5 a5 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 02 51 60 + 05 01 00 00 05 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 3c 00 02 28 00 + 05 01 00 00 b4 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp-mode-on = [39 00 00 00 05 00 03 f0 5a 5a + 39 00 00 00 05 00 03 f1 5a 5a + 39 00 00 00 05 00 03 fc 5a 5a + 39 00 00 00 05 00 02 b0 17 + 39 00 00 00 05 00 02 cb 10 + 39 00 00 00 05 00 02 b0 2d + 39 00 00 00 05 00 02 cb cd + 39 00 00 00 05 00 02 b0 0e + 39 00 00 00 05 00 02 cb 02 + 39 00 00 00 05 00 02 b0 0f + 39 00 00 00 05 00 02 cb 09 + 39 00 00 00 05 00 02 b0 02 + 39 00 00 00 05 00 02 f2 c9 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f2 c0 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f4 aa + 39 00 00 00 05 00 02 b0 08 + 39 00 00 00 05 00 02 b1 30 + 39 00 00 00 05 00 02 b0 09 + 39 00 00 00 05 00 02 b1 0a + 39 00 00 00 05 00 02 b0 0d + 39 00 00 00 05 00 02 b1 10 + 39 00 00 00 05 00 02 b0 00 + 39 00 00 00 05 00 02 f7 03 + 39 00 00 00 05 00 02 fe 30 + 39 01 00 00 05 00 02 fe b0]; + qcom,mdss-dsi-lp-mode-off = [39 00 00 00 05 00 03 f0 5a 5a + 39 00 00 00 05 00 03 f1 5a 5a + 39 00 00 00 05 00 03 fc 5a 5a + 39 00 00 00 05 00 02 b0 2d + 39 00 00 00 05 00 02 cb 4d + 39 00 00 00 05 00 02 b0 17 + 39 00 00 00 05 00 02 cb 04 + 39 00 00 00 05 00 02 b0 0e + 39 00 00 00 05 00 02 cb 06 + 39 00 00 00 05 00 02 b0 0f + 39 00 00 00 05 00 02 cb 05 + 39 00 00 00 05 00 02 b0 02 + 39 00 00 00 05 00 02 f2 b8 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f2 80 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f4 8a + 39 00 00 00 05 00 02 b0 08 + 39 00 00 00 05 00 02 b1 10 + 39 00 00 00 05 00 02 b0 09 + 39 00 00 00 05 00 02 b1 0a + 39 00 00 00 05 00 02 b0 0d + 39 00 00 00 05 00 02 b1 80 + 39 00 00 00 05 00 02 b0 00 + 39 00 00 00 05 00 02 f7 03 + 39 00 00 00 05 00 02 fe 30 + 39 01 00 00 05 00 02 fe b0]; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <122>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-1080p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8ffa0eb7749d2f7d051768a1c7eeddd1ce99994e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-1080p-cmd.dtsi @@ -0,0 +1,79 @@ +&mdss_mdp { + dsi_sharp_1080_cmd: qcom,mdss_dsi_sharp_1080p_cmd { + qcom,mdss-dsi-panel-name = "sharp 1080p cmd mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-clockrate = <850000000>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <64>; + qcom,mdss-pan-physical-height-dimension = <117>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dsc-4k-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..89df5ffd4029c1b89d9843a48a38f03662661c1a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -0,0 +1,96 @@ +&mdss_mdp { + dsi_sharp_4k_dsc_cmd: qcom,mdss_dsi_sharp_4k_dsc_cmd { + qcom,mdss-dsi-panel-name = "Sharp 4k cmd mode dsc dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <129>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-tx-eot-append; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x8 0xa>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dsc-4k-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..feb55406288c6cacb35dcbe25e31a653afa8a1c2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dsc-4k-video.dtsi @@ -0,0 +1,89 @@ +&mdss_mdp { + dsi_sharp_4k_dsc_video: qcom,mdss_dsi_sharp_4k_dsc_video { + qcom,mdss-dsi-panel-name = "Sharp 4k video mode dsc dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <129>; + qcom,mdss-dsi-tx-eot-append; + + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 10 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c909864db377892dee53422882549ac1c0641982 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi @@ -0,0 +1,86 @@ +&mdss_mdp { + dsi_dual_sharp_wqhd_cmd: qcom,mdss_dsi_sharp_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual Sharp WQHD cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <121>; + + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 + 20 00 20 02 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + 15 01 00 00 00 00 02 90 01 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c0 15 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualdsi-wqhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualdsi-wqhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..37330078b1ff25015c72e7163863ad3a4f7444c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualdsi-wqhd-video.dtsi @@ -0,0 +1,82 @@ +&mdss_mdp { + dsi_dual_sharp_wqhd_video: qcom,mdss_dsi_sharp_wqhd_video { + qcom,mdss-dsi-panel-name = + "Dual Sharp wqhd video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <121>; + + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 + 20 00 20 02 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 10 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + 15 01 00 00 00 00 02 90 01 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c0 15 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + }; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..06a95cadbd586c0f6091c1881d5e5e0670f5e4e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi @@ -0,0 +1,626 @@ +&mdss_mdp { + dsi_dual_sharp_1080_120hz_cmd: qcom,mdss_dual_sharp_1080p_120hz_cmd { + qcom,mdss-dsi-panel-name = + "sharp 1080p 120hz dual dsi cmd mode panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 10>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,cmd-sync-wait-trigger; + qcom,mdss-tear-check-frame-rate = <12000>; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 ba 07 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 d9 00 + 15 01 00 00 00 00 02 ef 70 + 15 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 06 3b 03 0e 0c 08 1c + 15 01 00 00 00 00 02 e9 0e + 15 01 00 00 00 00 02 ea 0c + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 59 6a + 15 01 00 00 00 00 02 0b 1b + 15 01 00 00 00 00 02 61 f7 + 15 01 00 00 00 00 02 62 6c + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 04 c8 + 15 01 00 00 00 00 02 05 1a + 15 01 00 00 00 00 02 0d 93 + 15 01 00 00 00 00 02 0e 93 + 15 01 00 00 00 00 02 0f 7e + 15 01 00 00 00 00 02 06 69 + 15 01 00 00 00 00 02 07 bc + 15 01 00 00 00 00 02 10 03 + 15 01 00 00 00 00 02 11 64 + 15 01 00 00 00 00 02 12 5a + 15 01 00 00 00 00 02 13 40 + 15 01 00 00 00 00 02 14 40 + 15 01 00 00 00 00 02 15 00 + 15 01 00 00 00 00 02 33 13 + 15 01 00 00 00 00 02 5a 40 + 15 01 00 00 00 00 02 5b 40 + 15 01 00 00 00 00 02 5e 80 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 80 + 15 01 00 00 00 00 02 14 80 + 15 01 00 00 00 00 02 01 80 + 15 01 00 00 00 00 02 15 80 + 15 01 00 00 00 00 02 02 80 + 15 01 00 00 00 00 02 16 80 + 15 01 00 00 00 00 02 03 0a + 15 01 00 00 00 00 02 17 0c + 15 01 00 00 00 00 02 04 06 + 15 01 00 00 00 00 02 18 08 + 15 01 00 00 00 00 02 05 80 + 15 01 00 00 00 00 02 19 80 + 15 01 00 00 00 00 02 06 80 + 15 01 00 00 00 00 02 1a 80 + 15 01 00 00 00 00 02 07 80 + 15 01 00 00 00 00 02 1b 80 + 15 01 00 00 00 00 02 08 80 + 15 01 00 00 00 00 02 1c 80 + 15 01 00 00 00 00 02 09 80 + 15 01 00 00 00 00 02 1d 80 + 15 01 00 00 00 00 02 0a 80 + 15 01 00 00 00 00 02 1e 80 + 15 01 00 00 00 00 02 0b 1a + 15 01 00 00 00 00 02 1f 1b + 15 01 00 00 00 00 02 0c 16 + 15 01 00 00 00 00 02 20 17 + 15 01 00 00 00 00 02 0d 1c + 15 01 00 00 00 00 02 21 1d + 15 01 00 00 00 00 02 0e 18 + 15 01 00 00 00 00 02 22 19 + 15 01 00 00 00 00 02 0f 0e + 15 01 00 00 00 00 02 23 10 + 15 01 00 00 00 00 02 10 80 + 15 01 00 00 00 00 02 24 80 + 15 01 00 00 00 00 02 11 80 + 15 01 00 00 00 00 02 25 80 + 15 01 00 00 00 00 02 12 80 + 15 01 00 00 00 00 02 26 80 + 15 01 00 00 00 00 02 13 80 + 15 01 00 00 00 00 02 27 80 + 15 01 00 00 00 00 02 74 ff + 15 01 00 00 00 00 02 75 ff + 15 01 00 00 00 00 02 8d 00 + 15 01 00 00 00 00 02 8e 00 + 15 01 00 00 00 00 02 8f 9c + 15 01 00 00 00 00 02 90 0c + 15 01 00 00 00 00 02 91 0e + 15 01 00 00 00 00 02 d6 00 + 15 01 00 00 00 00 02 d7 20 + 15 01 00 00 00 00 02 d8 00 + 15 01 00 00 00 00 02 d9 88 + 15 01 00 00 00 00 02 e5 05 + 15 01 00 00 00 00 02 e6 10 + 15 01 00 00 00 00 02 54 06 + 15 01 00 00 00 00 02 55 05 + 15 01 00 00 00 00 02 56 04 + 15 01 00 00 00 00 02 58 03 + 15 01 00 00 00 00 02 59 33 + 15 01 00 00 00 00 02 5a 33 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5d 01 + 15 01 00 00 00 00 02 5e 0a + 15 01 00 00 00 00 02 5f 0a + 15 01 00 00 00 00 02 60 0a + 15 01 00 00 00 00 02 61 0a + 15 01 00 00 00 00 02 62 10 + 15 01 00 00 00 00 02 63 01 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 65 00 + 15 01 00 00 00 00 02 ef 00 + 15 01 00 00 00 00 02 f0 00 + 15 01 00 00 00 00 02 6d 20 + 15 01 00 00 00 00 02 66 44 + 15 01 00 00 00 00 02 68 01 + 15 01 00 00 00 00 02 69 00 + 15 01 00 00 00 00 02 67 11 + 15 01 00 00 00 00 02 6a 06 + 15 01 00 00 00 00 02 6b 31 + 15 01 00 00 00 00 02 6c 90 + 15 01 00 00 00 00 02 ab c3 + 15 01 00 00 00 00 02 b1 49 + 15 01 00 00 00 00 02 aa 80 + 15 01 00 00 00 00 02 b0 90 + 15 01 00 00 00 00 02 b2 a4 + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 23 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 00 + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 00 + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba 00 + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc 00 + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be 00 + 15 01 00 00 00 00 02 bf 00 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 c7 40 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c1 2a + 15 01 00 00 00 00 02 c2 2a + 15 01 00 00 00 00 02 c3 00 + 15 01 00 00 00 00 02 c4 00 + 15 01 00 00 00 00 02 c5 00 + 15 01 00 00 00 00 02 c6 00 + 15 01 00 00 00 00 02 c8 ab + 15 01 00 00 00 00 02 ca 00 + 15 01 00 00 00 00 02 cb 00 + 15 01 00 00 00 00 02 cc 20 + 15 01 00 00 00 00 02 cd 40 + 15 01 00 00 00 00 02 ce a8 + 15 01 00 00 00 00 02 cf a8 + 15 01 00 00 00 00 02 d0 00 + 15 01 00 00 00 00 02 d1 00 + 15 01 00 00 00 00 02 d2 00 + 15 01 00 00 00 00 02 d3 00 + 15 01 00 00 00 00 02 af 01 + 15 01 00 00 00 00 02 a4 1e + 15 01 00 00 00 00 02 95 41 + 15 01 00 00 00 00 02 96 03 + 15 01 00 00 00 00 02 98 00 + 15 01 00 00 00 00 02 9a 9a + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9d 80 + 15 01 00 00 00 00 02 ff 26 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 fa d0 + 15 01 00 00 00 00 02 6b 80 + 15 01 00 00 00 00 02 6c 5c + 15 01 00 00 00 00 02 6d 0c + 15 01 00 00 00 00 02 6e 0e + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 59 15 + 15 01 00 00 00 00 02 5a 01 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 01 + 15 01 00 00 00 00 02 5d 2b + 15 01 00 00 00 00 02 74 00 + 15 01 00 00 00 00 02 75 ba + 15 01 00 00 00 00 02 81 0a + 15 01 00 00 00 00 02 4e 81 + 15 01 00 00 00 00 02 4f 83 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 53 4d + 15 01 00 00 00 00 02 54 03 + 15 01 00 00 00 00 02 ff e0 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 b2 81 + 15 01 00 00 00 00 02 62 28 + 15 01 00 00 00 00 02 a2 09 + 15 01 00 00 00 00 02 b3 01 + 15 01 00 00 00 00 02 ed 00 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 75 00 + 15 01 00 00 00 00 02 76 71 + 15 01 00 00 00 00 02 77 00 + 15 01 00 00 00 00 02 78 84 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 7a a5 + 15 01 00 00 00 00 02 7b 00 + 15 01 00 00 00 00 02 7c bb + 15 01 00 00 00 00 02 7d 00 + 15 01 00 00 00 00 02 7e ce + 15 01 00 00 00 00 02 7f 00 + 15 01 00 00 00 00 02 80 e0 + 15 01 00 00 00 00 02 81 00 + 15 01 00 00 00 00 02 82 ef + 15 01 00 00 00 00 02 83 00 + 15 01 00 00 00 00 02 84 ff + 15 01 00 00 00 00 02 85 01 + 15 01 00 00 00 00 02 86 0b + 15 01 00 00 00 00 02 87 01 + 15 01 00 00 00 00 02 88 38 + 15 01 00 00 00 00 02 89 01 + 15 01 00 00 00 00 02 8a 5b + 15 01 00 00 00 00 02 8b 01 + 15 01 00 00 00 00 02 8c 95 + 15 01 00 00 00 00 02 8d 01 + 15 01 00 00 00 00 02 8e c4 + 15 01 00 00 00 00 02 8f 02 + 15 01 00 00 00 00 02 90 0d + 15 01 00 00 00 00 02 91 02 + 15 01 00 00 00 00 02 92 4a + 15 01 00 00 00 00 02 93 02 + 15 01 00 00 00 00 02 94 4c + 15 01 00 00 00 00 02 95 02 + 15 01 00 00 00 00 02 96 85 + 15 01 00 00 00 00 02 97 02 + 15 01 00 00 00 00 02 98 c3 + 15 01 00 00 00 00 02 99 02 + 15 01 00 00 00 00 02 9a e9 + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9c 16 + 15 01 00 00 00 00 02 9d 03 + 15 01 00 00 00 00 02 9e 34 + 15 01 00 00 00 00 02 9f 03 + 15 01 00 00 00 00 02 a0 56 + 15 01 00 00 00 00 02 a2 03 + 15 01 00 00 00 00 02 a3 62 + 15 01 00 00 00 00 02 a4 03 + 15 01 00 00 00 00 02 a5 6c + 15 01 00 00 00 00 02 a6 03 + 15 01 00 00 00 00 02 a7 74 + 15 01 00 00 00 00 02 a9 03 + 15 01 00 00 00 00 02 aa 80 + 15 01 00 00 00 00 02 ab 03 + 15 01 00 00 00 00 02 ac 89 + 15 01 00 00 00 00 02 ad 03 + 15 01 00 00 00 00 02 ae 8b + 15 01 00 00 00 00 02 af 03 + 15 01 00 00 00 00 02 b0 8d + 15 01 00 00 00 00 02 b1 03 + 15 01 00 00 00 00 02 b2 8e + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 71 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 84 + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 a5 + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba bb + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc ce + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be e0 + 15 01 00 00 00 00 02 bf 00 + 15 01 00 00 00 00 02 c0 ef + 15 01 00 00 00 00 02 c1 00 + 15 01 00 00 00 00 02 c2 ff + 15 01 00 00 00 00 02 c3 01 + 15 01 00 00 00 00 02 c4 0b + 15 01 00 00 00 00 02 c5 01 + 15 01 00 00 00 00 02 c6 38 + 15 01 00 00 00 00 02 c7 01 + 15 01 00 00 00 00 02 c8 5b + 15 01 00 00 00 00 02 c9 01 + 15 01 00 00 00 00 02 ca 95 + 15 01 00 00 00 00 02 cb 01 + 15 01 00 00 00 00 02 cc c4 + 15 01 00 00 00 00 02 cd 02 + 15 01 00 00 00 00 02 ce 0d + 15 01 00 00 00 00 02 cf 02 + 15 01 00 00 00 00 02 d0 4a + 15 01 00 00 00 00 02 d1 02 + 15 01 00 00 00 00 02 d2 4c + 15 01 00 00 00 00 02 d3 02 + 15 01 00 00 00 00 02 d4 85 + 15 01 00 00 00 00 02 d5 02 + 15 01 00 00 00 00 02 d6 c3 + 15 01 00 00 00 00 02 d7 02 + 15 01 00 00 00 00 02 d8 e9 + 15 01 00 00 00 00 02 d9 03 + 15 01 00 00 00 00 02 da 16 + 15 01 00 00 00 00 02 db 03 + 15 01 00 00 00 00 02 dc 34 + 15 01 00 00 00 00 02 dd 03 + 15 01 00 00 00 00 02 de 56 + 15 01 00 00 00 00 02 df 03 + 15 01 00 00 00 00 02 e0 62 + 15 01 00 00 00 00 02 e1 03 + 15 01 00 00 00 00 02 e2 6c + 15 01 00 00 00 00 02 e3 03 + 15 01 00 00 00 00 02 e4 74 + 15 01 00 00 00 00 02 e5 03 + 15 01 00 00 00 00 02 e6 80 + 15 01 00 00 00 00 02 e7 03 + 15 01 00 00 00 00 02 e8 89 + 15 01 00 00 00 00 02 e9 03 + 15 01 00 00 00 00 02 ea 8b + 15 01 00 00 00 00 02 eb 03 + 15 01 00 00 00 00 02 ec 8d + 15 01 00 00 00 00 02 ed 03 + 15 01 00 00 00 00 02 ee 8e + 15 01 00 00 00 00 02 ef 00 + 15 01 00 00 00 00 02 f0 71 + 15 01 00 00 00 00 02 f1 00 + 15 01 00 00 00 00 02 f2 84 + 15 01 00 00 00 00 02 f3 00 + 15 01 00 00 00 00 02 f4 a5 + 15 01 00 00 00 00 02 f5 00 + 15 01 00 00 00 00 02 f6 bb + 15 01 00 00 00 00 02 f7 00 + 15 01 00 00 00 00 02 f8 ce + 15 01 00 00 00 00 02 f9 00 + 15 01 00 00 00 00 02 fa e0 + 15 01 00 00 00 00 02 ff 21 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 00 + 15 01 00 00 00 00 02 01 ef + 15 01 00 00 00 00 02 02 00 + 15 01 00 00 00 00 02 03 ff + 15 01 00 00 00 00 02 04 01 + 15 01 00 00 00 00 02 05 0b + 15 01 00 00 00 00 02 06 01 + 15 01 00 00 00 00 02 07 38 + 15 01 00 00 00 00 02 08 01 + 15 01 00 00 00 00 02 09 5b + 15 01 00 00 00 00 02 0a 01 + 15 01 00 00 00 00 02 0b 95 + 15 01 00 00 00 00 02 0c 01 + 15 01 00 00 00 00 02 0d c4 + 15 01 00 00 00 00 02 0e 02 + 15 01 00 00 00 00 02 0f 0d + 15 01 00 00 00 00 02 10 02 + 15 01 00 00 00 00 02 11 4a + 15 01 00 00 00 00 02 12 02 + 15 01 00 00 00 00 02 13 4c + 15 01 00 00 00 00 02 14 02 + 15 01 00 00 00 00 02 15 85 + 15 01 00 00 00 00 02 16 02 + 15 01 00 00 00 00 02 17 c3 + 15 01 00 00 00 00 02 18 02 + 15 01 00 00 00 00 02 19 e9 + 15 01 00 00 00 00 02 1a 03 + 15 01 00 00 00 00 02 1b 16 + 15 01 00 00 00 00 02 1c 03 + 15 01 00 00 00 00 02 1d 34 + 15 01 00 00 00 00 02 1e 03 + 15 01 00 00 00 00 02 1f 56 + 15 01 00 00 00 00 02 20 03 + 15 01 00 00 00 00 02 21 62 + 15 01 00 00 00 00 02 22 03 + 15 01 00 00 00 00 02 23 6c + 15 01 00 00 00 00 02 24 03 + 15 01 00 00 00 00 02 25 74 + 15 01 00 00 00 00 02 26 03 + 15 01 00 00 00 00 02 27 80 + 15 01 00 00 00 00 02 28 03 + 15 01 00 00 00 00 02 29 89 + 15 01 00 00 00 00 02 2a 03 + 15 01 00 00 00 00 02 2b 8b + 15 01 00 00 00 00 02 2d 03 + 15 01 00 00 00 00 02 2f 8d + 15 01 00 00 00 00 02 30 03 + 15 01 00 00 00 00 02 31 8e + 15 01 00 00 00 00 02 32 00 + 15 01 00 00 00 00 02 33 71 + 15 01 00 00 00 00 02 34 00 + 15 01 00 00 00 00 02 35 84 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 37 a5 + 15 01 00 00 00 00 02 38 00 + 15 01 00 00 00 00 02 39 bb + 15 01 00 00 00 00 02 3a 00 + 15 01 00 00 00 00 02 3b ce + 15 01 00 00 00 00 02 3d 00 + 15 01 00 00 00 00 02 3f e0 + 15 01 00 00 00 00 02 40 00 + 15 01 00 00 00 00 02 41 ef + 15 01 00 00 00 00 02 42 00 + 15 01 00 00 00 00 02 43 ff + 15 01 00 00 00 00 02 44 01 + 15 01 00 00 00 00 02 45 0b + 15 01 00 00 00 00 02 46 01 + 15 01 00 00 00 00 02 47 38 + 15 01 00 00 00 00 02 48 01 + 15 01 00 00 00 00 02 49 5b + 15 01 00 00 00 00 02 4a 01 + 15 01 00 00 00 00 02 4b 95 + 15 01 00 00 00 00 02 4c 01 + 15 01 00 00 00 00 02 4d c4 + 15 01 00 00 00 00 02 4e 02 + 15 01 00 00 00 00 02 4f 0d + 15 01 00 00 00 00 02 50 02 + 15 01 00 00 00 00 02 51 4a + 15 01 00 00 00 00 02 52 02 + 15 01 00 00 00 00 02 53 4c + 15 01 00 00 00 00 02 54 02 + 15 01 00 00 00 00 02 55 85 + 15 01 00 00 00 00 02 56 02 + 15 01 00 00 00 00 02 58 c3 + 15 01 00 00 00 00 02 59 02 + 15 01 00 00 00 00 02 5a e9 + 15 01 00 00 00 00 02 5b 03 + 15 01 00 00 00 00 02 5c 16 + 15 01 00 00 00 00 02 5d 03 + 15 01 00 00 00 00 02 5e 34 + 15 01 00 00 00 00 02 5f 03 + 15 01 00 00 00 00 02 60 56 + 15 01 00 00 00 00 02 61 03 + 15 01 00 00 00 00 02 62 62 + 15 01 00 00 00 00 02 63 03 + 15 01 00 00 00 00 02 64 6c + 15 01 00 00 00 00 02 65 03 + 15 01 00 00 00 00 02 66 74 + 15 01 00 00 00 00 02 67 03 + 15 01 00 00 00 00 02 68 80 + 15 01 00 00 00 00 02 69 03 + 15 01 00 00 00 00 02 6a 89 + 15 01 00 00 00 00 02 6b 03 + 15 01 00 00 00 00 02 6c 8b + 15 01 00 00 00 00 02 6d 03 + 15 01 00 00 00 00 02 6e 8d + 15 01 00 00 00 00 02 6f 03 + 15 01 00 00 00 00 02 70 8e + 15 01 00 00 00 00 02 71 00 + 15 01 00 00 00 00 02 72 71 + 15 01 00 00 00 00 02 73 00 + 15 01 00 00 00 00 02 74 84 + 15 01 00 00 00 00 02 75 00 + 15 01 00 00 00 00 02 76 a5 + 15 01 00 00 00 00 02 77 00 + 15 01 00 00 00 00 02 78 bb + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 7a ce + 15 01 00 00 00 00 02 7b 00 + 15 01 00 00 00 00 02 7c e0 + 15 01 00 00 00 00 02 7d 00 + 15 01 00 00 00 00 02 7e ef + 15 01 00 00 00 00 02 7f 00 + 15 01 00 00 00 00 02 80 ff + 15 01 00 00 00 00 02 81 01 + 15 01 00 00 00 00 02 82 0b + 15 01 00 00 00 00 02 83 01 + 15 01 00 00 00 00 02 84 38 + 15 01 00 00 00 00 02 85 01 + 15 01 00 00 00 00 02 86 5b + 15 01 00 00 00 00 02 87 01 + 15 01 00 00 00 00 02 88 95 + 15 01 00 00 00 00 02 89 01 + 15 01 00 00 00 00 02 8a c4 + 15 01 00 00 00 00 02 8b 02 + 15 01 00 00 00 00 02 8c 0d + 15 01 00 00 00 00 02 8d 02 + 15 01 00 00 00 00 02 8e 4a + 15 01 00 00 00 00 02 8f 02 + 15 01 00 00 00 00 02 90 4c + 15 01 00 00 00 00 02 91 02 + 15 01 00 00 00 00 02 92 85 + 15 01 00 00 00 00 02 93 02 + 15 01 00 00 00 00 02 94 c3 + 15 01 00 00 00 00 02 95 02 + 15 01 00 00 00 00 02 96 e9 + 15 01 00 00 00 00 02 97 03 + 15 01 00 00 00 00 02 98 16 + 15 01 00 00 00 00 02 99 03 + 15 01 00 00 00 00 02 9a 34 + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9c 56 + 15 01 00 00 00 00 02 9d 03 + 15 01 00 00 00 00 02 9e 62 + 15 01 00 00 00 00 02 9f 03 + 15 01 00 00 00 00 02 a0 6c + 15 01 00 00 00 00 02 a2 03 + 15 01 00 00 00 00 02 a3 74 + 15 01 00 00 00 00 02 a4 03 + 15 01 00 00 00 00 02 a5 80 + 15 01 00 00 00 00 02 a6 03 + 15 01 00 00 00 00 02 a7 89 + 15 01 00 00 00 00 02 a9 03 + 15 01 00 00 00 00 02 aa 8b + 15 01 00 00 00 00 02 ab 03 + 15 01 00 00 00 00 02 ac 8d + 15 01 00 00 00 00 02 ad 03 + 15 01 00 00 00 00 02 ae 8e + 15 01 00 00 00 00 02 af 00 + 15 01 00 00 00 00 02 b0 71 + 15 01 00 00 00 00 02 b1 00 + 15 01 00 00 00 00 02 b2 84 + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 a5 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 bb + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 ce + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba e0 + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc ef + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be ff + 15 01 00 00 00 00 02 bf 01 + 15 01 00 00 00 00 02 c0 0b + 15 01 00 00 00 00 02 c1 01 + 15 01 00 00 00 00 02 c2 38 + 15 01 00 00 00 00 02 c3 01 + 15 01 00 00 00 00 02 c4 5b + 15 01 00 00 00 00 02 c5 01 + 15 01 00 00 00 00 02 c6 95 + 15 01 00 00 00 00 02 c7 01 + 15 01 00 00 00 00 02 c8 c4 + 15 01 00 00 00 00 02 c9 02 + 15 01 00 00 00 00 02 ca 0d + 15 01 00 00 00 00 02 cb 02 + 15 01 00 00 00 00 02 cc 4a + 15 01 00 00 00 00 02 cd 02 + 15 01 00 00 00 00 02 ce 4c + 15 01 00 00 00 00 02 cf 02 + 15 01 00 00 00 00 02 d0 85 + 15 01 00 00 00 00 02 d1 02 + 15 01 00 00 00 00 02 d2 c3 + 15 01 00 00 00 00 02 d3 02 + 15 01 00 00 00 00 02 d4 e9 + 15 01 00 00 00 00 02 d5 03 + 15 01 00 00 00 00 02 d6 16 + 15 01 00 00 00 00 02 d7 03 + 15 01 00 00 00 00 02 d8 34 + 15 01 00 00 00 00 02 d9 03 + 15 01 00 00 00 00 02 da 56 + 15 01 00 00 00 00 02 db 03 + 15 01 00 00 00 00 02 dc 62 + 15 01 00 00 00 00 02 dd 03 + 15 01 00 00 00 00 02 de 6c + 15 01 00 00 00 00 02 df 03 + 15 01 00 00 00 00 02 e0 74 + 15 01 00 00 00 00 02 e1 03 + 15 01 00 00 00 00 02 e2 80 + 15 01 00 00 00 00 02 e3 03 + 15 01 00 00 00 00 02 e4 89 + 15 01 00 00 00 00 02 e5 03 + 15 01 00 00 00 00 02 e6 8b + 15 01 00 00 00 00 02 e7 03 + 15 01 00 00 00 00 02 e8 8d + 15 01 00 00 00 00 02 e9 03 + 15 01 00 00 00 00 02 ea 8e + 15 01 00 00 00 00 02 FF 10 + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = + [15 01 00 00 00 00 02 ff 10 + 05 01 00 00 10 00 01 28 + 15 01 00 00 00 00 02 b0 00 + 05 01 00 00 40 00 01 10 + 15 01 00 00 00 00 02 4f 01]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f62ce3b9d7b5ff646dec8970fc59e382a013afdd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-cmd.dtsi @@ -0,0 +1,347 @@ +&mdss_mdp { + dsi_sim_cmd: qcom,mdss_dsi_sim_cmd { + qcom,mdss-dsi-panel-name = "Simulator cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,cmd-to-video-mode-switch-commands = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 39 01 00 00 00 00 06 b2 00 5d 04 80 49 + 15 01 00 00 00 00 02 3d 10 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 55 0c + ]; + qcom,cmd-to-video-mode-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,video-to-cmd-mode-switch-commands = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 39 01 00 00 00 00 06 b2 00 5d 04 80 49 + 15 01 00 00 00 00 02 3d 11 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 55 0b + ]; + qcom,video-to-cmd-mode-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@3 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <460>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <740>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@4 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <840>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <1380>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dsc-10bit-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dsc-10bit-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..310ce40cd9021916e25eb51919b8533a4ae507ee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dsc-10bit-cmd.dtsi @@ -0,0 +1,474 @@ +&mdss_mdp { + dsi_sim_dsc_10b_cmd: qcom,mdss_dsi_sim_dsc_10b_cmd { + qcom,mdss-dsi-panel-name = + "Simulator cmd mode DSC3:1 10bit dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <30>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <10>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <10>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <10>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dsc375-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ef40a2e7b3e65f9f9faa3c37d579bfd70c337aa3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dsc375-cmd.dtsi @@ -0,0 +1,280 @@ +&mdss_mdp { + dsi_sim_dsc_375_cmd: qcom,mdss_dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-panel-name = + "Simulator cmd mode DSC 3.75:1 dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f4be88fb88fbc289366c3d45d20ae2e3a148d8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-cmd.dtsi @@ -0,0 +1,141 @@ +&mdss_mdp { + dsi_dual_sim_cmd: qcom,mdss_dsi_dual_sim_cmd { + qcom,mdss-dsi-panel-name = "Sim dual cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-hor-line-idle = <0 40 256>, + <40 120 128>, + <120 240 64>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + qcom,mdss-dsi-qsync-min-refresh-rate = <45>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <40>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..87b4a76a3a962d990897962b78f98a6879af88cc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi @@ -0,0 +1,327 @@ +&mdss_mdp { + dsi_dual_sim_dsc_375_cmd: qcom,mdss_dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-panel-name = + "Sim dual cmd mode DSC 3.75:1 dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-hor-line-idle = <0 40 256>, + <40 120 128>, + <120 240 64>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <2520>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <1080>; + qcom,mdss-dsc-slice-width = <1260>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3bee9f6f104d319c74b9491169a17a2d9bd3a208 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-dualmipi-video.dtsi @@ -0,0 +1,63 @@ +&mdss_mdp { + dsi_dual_sim_vid: qcom,mdss_dsi_dual_sim_video { + qcom,mdss-dsi-panel-name = "Sim dual video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-panel-broadcast-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>; + qcom,panel-ack-disabled; + qcom,mdss-dsi-qsync-min-refresh-rate = <45>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-sec-hd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-sec-hd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e9d31359ed5b1349cc5e1fc34029a1cb0b192737 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-sec-hd-cmd.dtsi @@ -0,0 +1,68 @@ +&mdss_mdp { + dsi_sim_sec_hd_cmd: qcom,mdss_dsi_sim_sec_hd_cmd { + qcom,mdss-dsi-panel-name = + "sim hd command mode secondary dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + qcom,dsi-select-sec-clocks = "src_byte_clk1", "src_pixel_clk1"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,panel-ack-disabled; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5a2ac01716d3b385aba386437ece5a0079c8496e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sim-video.dtsi @@ -0,0 +1,62 @@ +&mdss_mdp { + dsi_sim_vid: qcom,mdss_dsi_sim_video { + qcom,mdss-dsi-panel-name = "Simulator video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1b>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 0>, <0 0>, <1 0>; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <640>; + qcom,mdss-dsi-panel-height = <480>; + qcom,mdss-dsi-h-front-porch = <8>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <6>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 00 00 00 00 00 00 00 00 00 00 00]; + qcom,mdss-dsi-on-command = + [32 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-off-command = + [22 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6195f8c82a53ab5f7045852766f3053913e829f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi @@ -0,0 +1,103 @@ +&mdss_mdp { + dsi_sw43404_amoled_fhd_plus_cmd: qcom,mdss_dsi_sw43404_fhd_plus_cmd { + qcom,mdss-dsi-panel-name = + "sw43404 amoled boe fhd+ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <138>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <160>; + qcom,mdss-dsi-h-back-porch = <72>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 08 70 04 38 02 1c 02 1c 02 1c 02 00 + 02 0e 00 20 34 29 00 07 00 0C 00 2e + 00 31 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 5e 10 + 39 01 00 00 00 00 06 b9 bf 11 40 00 30 + 39 01 00 00 00 00 09 F8 00 08 10 08 2D + 00 00 2D + 15 01 00 00 00 00 02 55 08 + 05 01 00 00 1e 00 02 11 00 + 15 01 00 00 78 00 02 3d 01 + 39 01 00 00 00 00 03 b0 a5 00 + 05 01 00 00 78 00 02 35 00 + 05 01 00 00 3c 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <270>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..032fc39b91bf492f0ea14f0c6f05516da892b5db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi @@ -0,0 +1,121 @@ +&mdss_mdp { + dsi_sw43404_amoled_cmd: qcom,mdss_dsi_sw43404_amoled_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "sw43404 amoled cmd mode dsi boe panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-qsync-min-refresh-rate = <55>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2880>; + qcom,mdss-dsi-h-front-porch = <60>; + qcom,mdss-dsi-h-back-porch = <30>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 03 5c 42 00 + 07 01 00 00 00 00 02 01 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 0B 40 05 A0 05 A0 02 D0 02 D0 02 00 + 02 68 00 20 9A DB 00 0A 00 0C 00 12 + 00 0E 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 09 F8 00 08 10 08 2D + 00 00 2D + 15 01 00 00 00 00 02 55 08 + 05 01 00 00 1e 00 02 11 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 + 05 01 00 00 78 00 02 35 00 + 05 01 00 00 3c 00 02 29 00 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 5a 01]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 5a 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <180>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..37c0dfcd7d75703842bf34afcfc141c26bfcd03b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi @@ -0,0 +1,101 @@ +&mdss_mdp { + dsi_sw43404_amoled_video: qcom,mdss_dsi_sw43404_amoled_wqhd_video { + qcom,mdss-dsi-panel-name = + "sw43404 amoled video mode dsi boe panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2880>; + qcom,mdss-dsi-h-front-porch = <10>; + qcom,mdss-dsi-h-back-porch = <10>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 39 01 00 00 00 00 06 b2 00 5d 04 80 49 + 15 01 00 00 00 00 02 3d 10 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 55 08 + 39 01 00 00 00 00 09 f8 00 08 10 08 2d + 00 00 2d + 39 01 00 00 3c 00 03 51 00 00 + 05 01 00 00 50 00 02 11 00 + 39 01 00 00 00 00 03 b0 34 04 + 39 01 00 00 00 00 05 c1 00 00 00 46 + 39 01 00 00 00 00 03 b0 a5 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 0B 40 05 A0 02 d0 02 D0 02 D0 02 00 + 02 68 00 20 4e a8 00 0A 00 0C 00 23 + 00 1c 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <180>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-td4328-1080p-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-td4328-1080p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..476c34c01d34f0ffac8d21f66071ae5d2ea62a8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-td4328-1080p-cmd.dtsi @@ -0,0 +1,169 @@ +&mdss_mdp { + dsi_td4328_truly_cmd: qcom,mdss_dsi_td4328_truly_cmd { + qcom,mdss-dsi-panel-name = + "td4328 cmd mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 00 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E C7 C7 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 2B + 02 2B + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 50 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 29 01 00 00 00 00 02 B0 00 + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-td4328-1080p-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-td4328-1080p-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e9b7bac3450458b20c1148acee6cf9b443a9c86b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/dsi-panel-td4328-1080p-video.dtsi @@ -0,0 +1,164 @@ +&mdss_mdp { + dsi_td4328_truly_video: qcom,mdss_dsi_td4328_truly_video { + qcom,mdss-dsi-panel-name = + "td4328 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 31 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E DB DB 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 40 + 02 40 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 90 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-cdp-lcd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-cdp-lcd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a7d85dfd9194dd77918b3cba1a375d44047443e6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-cdp-lcd.dtsi @@ -0,0 +1,36 @@ +&dsi_sharp_4k_dsc_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + /delete-property/ qcom,platform-en-gpio; +}; + +&dsi_sharp_4k_dsc_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + /delete-property/ qcom,platform-en-gpio; +}; + +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&sde_dsi { + /delete-property/ avdd-supply; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,dsi-default-panel = <&dsi_sharp_4k_dsc_cmd>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fadbce641428800ba39a6ca9ad0ec88e654d6e05 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-cdp.dtsi @@ -0,0 +1,152 @@ +#include "kona-sde-display.dtsi" + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-en-gpio = <&tlmm 60 0>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-en-gpio = <&tlmm 60 0>; +}; + +&dsi_sharp_1080_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_sec_hd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b81aad8801d0be545ead634120060ca4fc091073 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-mtp.dtsi @@ -0,0 +1,87 @@ +#include "kona-sde-display.dtsi" + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_sec_hd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1f6e32ac60f87059eaa83c8bfcd91437f9ab5a4d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-qrd.dtsi @@ -0,0 +1,76 @@ +#include "kona-sde-display.dtsi" + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-rumi.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3eb83e40a9c031554bcf834aa5b7bfdacf423710 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display-rumi.dtsi @@ -0,0 +1 @@ +#include "kona-sde-display.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6257b55c4e1dcad364d8ddf041ae622dc3667659 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-display.dtsi @@ -0,0 +1,528 @@ +#include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-video.dtsi" +#include "dsi-panel-sharp-1080p-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dsc-10bit-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-sim-sec-hd-cmd.dtsi" +#include + +&tlmm { + display_panel_avdd_default: display_panel_avdd_default { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; +}; + +&soc { + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + }; + + dsi_panel_pwr_supply_avdd: dsi_panel_pwr_supply_avdd { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + + display_panel_avdd: display_gpio_regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "display_panel_avdd"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 61 0>; + enable-active-high; + regulator-boot-on; + pinctrl-names = "default"; + pinctrl-0 = <&display_panel_avdd_default>; + }; + + sde_dsi: qcom,dsi-display-primary { + compatible = "qcom,dsi-display"; + label = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0", + "src_byte_clk1", "src_pixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,panel-te-source = <0>; + + vddio-supply = <&pm8150_l14>; + vdd-supply = <&pm8150a_l11>; + avdd-supply = <&display_panel_avdd>; + + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; + }; + + sde_dsi1: qcom,dsi-display-secondary { + compatible = "qcom,dsi-display"; + label = "secondary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "src_byte_clk0", "src_pixel_clk0", + "src_byte_clk1", "src_pixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi1_active &sde_te1_active>; + pinctrl-1 = <&sde_dsi1_suspend &sde_te1_suspend>; + + qcom,platform-te-gpio = <&tlmm 67 0>; + qcom,panel-te-source = <1>; + + vddio-supply = <&pm8150_l14>; + vdd-supply = <&pm8150a_l11>; + avdd-supply = <&display_panel_avdd>; + + qcom,mdp = <&mdss_mdp>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pm8150b_pdphy>; + qcom,ext-disp = <&ext_disp>; + qcom,dp-aux-switch = <&fsa4480>; + + qcom,usbplug-cc-gpio = <&tlmm 65 0>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_usbplug_cc_suspend>; +}; + +&mdss_mdp { + connectors = <&sde_dp &sde_wb &sde_dsi &sde_dsi1 &sde_rscc>; +}; + +/* PHY TIMINGS REVISION W */ +&dsi_sw43404_amoled_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1e 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + }; +}; + +&dsi_sw43404_amoled_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-supported-dfps-list = <60 57 55>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_hfp"; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1e 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 12 04 04 1e 1e 04 + 05 02 03 04 00 11 14]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 270 270 270 1080 270>; + }; + }; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_4k_dsc_video { + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_1080_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,mdss-dsi-panel-clockrate = <900000000>; + }; + }; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@3 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@4 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { /* QHD 60fps */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* 1080 60fps */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + + timing@2 { /* QHD 90fps */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 02 04 00 18 17]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { /* 5k */ + qcom,mdss-dsi-panel-phy-timings = [00 46 13 14 33 30 12 + 14 0e 02 04 00 37 22]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_sec_hd_cmd { + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e6bda66f50ac7abcc64f7fba73ff8d2bdbc180d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde-pll.dtsi @@ -0,0 +1,82 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94900 { + compatible = "qcom,mdss_dsi_pll_7nm_v4_1"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94900 0x260>, + <0xae94400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96900 { + compatible = "qcom,mdss_dsi_pll_7nm_v4_1"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96900 0x260>, + <0xae96400 0x800>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + compatible = "qcom,mdss_dp_pll_7nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", + "gcc_iface", "pipe_clk"; + clock-rate = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/display/kona-sde.dtsi b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d6a849eb49254edb95245d38d2f2e7ae6891a399 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/display/kona-sde.dtsi @@ -0,0 +1,688 @@ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x84208>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0x214>, + <0x0ae8f000 0x02c>, + <0x0af50000 0x038>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys", + "sid_phys", + "swfuse_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_HF_AXI_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", "gcc_nrt_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 0 300000000 19200000 300000000 19200000>; + clock-max-rate = <0 0 0 0 460000000 19200000 460000000 + 460000000>; + + mmcx-supply = <&VDD_MMCX_LEVEL>; + + /* interrupt config */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x494>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800 0x2a00>; + qcom,sde-ctl-size = <0x1dc>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 + 0x48000 0x49000 0x4a000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-mixer-cwb-pref = "none", "none", "cwb", + "cwb", "cwb", "cwb"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>; + qcom,sde-dspp-size = <0x1800>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0x1c>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0x800>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x2bc 16>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000 0x72800 0x73000 0x73800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + qcom,sde-pp-merge-3d-id = <0x0 0x0 0x1 0x1 0x2 0x2>; + + qcom,sde-merge-3d-off = <0x84000 0x84100 0x84200>; + qcom,sde-merge-3d-size = <0x100>; + + qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0 0x0 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000 0x81400 0x81800 0x81c00>; + qcom,sde-dsc-size = <0x140>; + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 + 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "vig", "vig", "vig", + "dma", "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x7000 0x9000 0xb000 + 0x25000 0x27000 0x29000 0x2b000>; + qcom,sde-sspp-src-size = <0x1f8>; + + qcom,sde-sspp-xin-id = <0 4 8 12 + 1 5 9 13>; + qcom,sde-sspp-excl-rect = <1 1 1 1 + 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <5 6 7 8 1 2 3 4>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <2 1 4 3 6 5>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-max-per-pipe-bw-kbps = <4400000 4400000 + 4400000 4400000 + 4400000 4400000 + 4400000 4400000>; + + qcom,sde-max-per-pipe-bw-high-kbps = <5300000 5300000 + 5300000 5300000 + 5300000 5300000 + 5300000 5300000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, <0x2c4 0>, + <0x2ac 8>, <0x2b4 8>, <0x2bc 8>, <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <4096>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x3>; + qcom,sde-ubwc-version = <0x400>; + qcom,sde-ubwc-swizzle = <0x6>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-ubwc-static = <0x1>; + qcom,sde-macrotile-mode = <0x1>; + qcom,sde-smart-panel-align-mode = <0xc>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-has-dest-scaler; + qcom,sde-has-idle-pc; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <13700000>; + qcom,sde-max-bw-high-kbps = <16600000>; + qcom,sde-min-core-ib-kbps = <2400000>; + qcom,sde-min-llcc-ib-kbps = <800000>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ltm-version = <0x00010000>; + /* offsets are based off dspp 0 and dspp 1 */ + qcom,sde-dspp-ltm-off = <0x2a000 0x28100>; + + qcom,sde-uidle-off = <0x80000>; + qcom,sde-uidle-size = <0x70>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-qos-cwb-remap = <3 3 4 4 5 5 6 3>; + qcom,sde-vbif-qos-lutdma-remap = <3 3 3 3 4 4 4 4>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x000000ff 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff0>; + qcom,sde-safe-lut-macrotile = <0 0xff00>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xff00>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0x3ff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22335777>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x66666541 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010002>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + qcom,sde-reg-dma-xin-id = <7>; + qcom,sde-reg-dma-clk-ctrl = <0x2bc 20>; + + qcom,sde-secure-sid-mask = <0x4000821>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-gamut = <0x1d00 0x00060000>; + qcom,sde-vig-igc = <0x1d00 0x00060000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + }; + + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + }; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040001>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "mmcx"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0x820 0x402>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-earlymap; /* for cont-splash */ + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x821 0x400>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_dp: qcom,dp_display@ae90000 { + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&pm8150_l9>; + vdda-0p9-supply = <&pm8150_l18>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae91000 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>, + <0xae91400 0x094>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_pipe_clk", "link_clk", "link_iface_clk", + "pixel_clk_rcg", "pixel_parent", + "pixel1_clk_rcg", "pixel1_parent", + "strm0_pixel_clk", "strm1_pixel_clk"; + + qcom,phy-version = <0x420>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13]; + qcom,aux-cfg2-settings = [28 A4]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,mst-enable; + qcom,widebus-enable; + qcom,dsc-feature-enable; + qcom,fec-feature-enable; + qcom,max-dp-dsc-blks = <2>; + qcom,max-dp-dsc-input-width-pixs = <2048>; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <33000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <912000>; + qcom,supply-max-voltage = <912000>; + qcom,supply-enable-load = <126000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x3c50>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <3>; + + qcom,sde-dram-channels = <2>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20513 0 0>, <20004 20513 0 0>, + <20003 20513 0 6400000>, <20004 20513 0 6400000>, + <20003 20513 0 6400000>, <20004 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator@aea8800 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + status = "disabled"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x3>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x215C 0x0400>; + qcom,iommu-dma = "disabled"; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm8150_l9>; + refgen-supply = <&refgen>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <26700>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-1"; + cell-index = <1>; + reg = <0xae96000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <5 0>; + vdda-1p2-supply = <&pm8150_l9>; + refgen-supply = <&refgen>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <26700>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v4.1"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x760>; + reg-names = "dsi_phy"; + vdda-0p9-supply = <&pm8150_l5>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <46000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy1@ae96400 { + compatible = "qcom,dsi-phy-v4.1"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x760>; + reg-names = "dsi_phy"; + vdda-0p9-supply = <&pm8150_l5>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <46000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-ext-bridge-1080p.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-ext-bridge-1080p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..07d398e9e16c70c6ec384a7788357e078e16053a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-ext-bridge-1080p.dtsi @@ -0,0 +1,46 @@ +&mdss_mdp { + dsi_ext_bridge_1080p: qcom,mdss_dsi_ext_bridge_1080p { + qcom,mdss-dsi-panel-name = "ext video mode dsi bridge"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x24>; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-ext-bridge-mode; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1920>; + qcom,mdss-dsi-panel-height = <1080>; + qcom,mdss-dsi-h-front-porch = <88>; + qcom,mdss-dsi-h-back-porch = <148>; + qcom,mdss-dsi-h-pulse-width = <44>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <36>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <5>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-ext-bridge-4k-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-ext-bridge-4k-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8e9a04ae0a3ff3a9ea8fb4a04a33172eeb9c1aa6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-ext-bridge-4k-video.dtsi @@ -0,0 +1,45 @@ +&mdss_mdp { + dsi_ext_bridge_4k_vid: qcom,mdss_dsi_ext_bridge_4k_video { + qcom,mdss-dsi-panel-name = "ext 4k video mode dsi bridge"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-t-clk-post = <0x1e>; + qcom,mdss-dsi-t-clk-pre = <0x2e>; + qcom,mdss-dsi-force-clock-lane-hs; + qcom,mdss-dsi-ext-bridge-mode; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1920>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <88>; + qcom,mdss-dsi-h-back-porch = <200>; + qcom,mdss-dsi-h-pulse-width = <44>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <72>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <10>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9dc1a26207f3bef449561b31f98e56f6b70d99cb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi @@ -0,0 +1,151 @@ +&mdss_mdp { + dsi_hx83112a_truly_video: qcom,mdss_dsi_hx83112a_truly_video { + qcom,mdss-dsi-panel-name = + "hx83112a video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <42>; + qcom,mdss-dsi-h-back-porch = <42>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <15>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <3>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 83 11 2A + 39 01 00 00 00 00 09 B1 08 29 29 00 00 4F 54 + 33 + 39 01 00 00 00 00 11 B2 00 02 00 80 70 00 08 + 26 FC 01 00 03 15 A3 87 09 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 03 D2 2C 2C + 39 01 00 00 00 00 1C B4 01 CE 01 CE 01 CE 0A + CE 0A CE 0A CE 00 FF 00 FF 00 00 22 23 00 + 28 0A 13 14 00 8A + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0A B4 00 92 12 22 88 12 12 + 00 53 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 04 B6 82 82 E3 + 39 01 00 00 00 00 02 CC 08 + 39 01 00 00 00 00 2B D3 40 00 00 00 00 01 01 + 0A 0A 07 07 00 08 09 09 09 09 32 10 09 00 + 09 32 21 0A 00 0A 32 10 08 00 00 00 00 00 + 00 00 00 00 0B 08 82 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 09 D3 00 00 19 00 00 0A 00 + 81 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 31 D5 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 01 00 07 06 05 04 03 02 21 20 18 + 18 19 19 18 18 03 03 18 18 18 18 18 18 + 39 01 00 00 00 00 31 D6 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 02 03 04 05 06 07 00 01 20 21 18 + 18 18 18 19 19 20 20 18 18 18 18 18 18 + 39 01 00 00 00 00 19 D8 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0D D8 AF FF FA AA BA AA AA + FF FA AA BA AA + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 18 E7 0E 0E 1E 6A 1D 6A 00 + 32 02 02 00 00 02 02 02 05 14 14 32 B9 23 + B9 08 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 0A E7 02 00 98 01 9A 0D A8 + 0E 01 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 1E E7 00 00 08 00 01 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 04 00 00 00 00 02 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 C1 01 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 E9 C3 + 39 01 00 00 00 00 03 CB 92 01 + 39 01 00 00 00 00 02 E9 3F + 39 01 00 00 00 00 07 C7 70 00 04 E0 33 00 + 39 01 00 00 00 00 03 51 0F FF + 39 01 00 00 00 00 02 53 24 + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx8394d-720p-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx8394d-720p-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6de6c6c4c8599cf14f3f7e5e139499fb03f3a368 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx8394d-720p-video.dtsi @@ -0,0 +1,87 @@ +&mdss_mdp { + dsi_hx8394d_720_vid: qcom,mdss_dsi_hx8394d_720p_video { + qcom,mdss-dsi-panel-name = "hx8394d 720p video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 b9 ff 83 94 + 39 01 00 00 00 00 03 ba 33 83 + 39 01 00 00 00 00 10 b1 6c 12 12 + 37 04 11 f1 80 ec 94 23 80 c0 + d2 18 + 39 01 00 00 00 00 0c b2 00 64 0e + 0d 32 23 08 08 1c 4d 00 + 39 01 00 00 00 00 0d b4 00 ff 03 + 50 03 50 03 50 01 6a 01 6a + 39 01 00 00 00 00 02 bc 07 + 39 01 00 00 00 00 04 bf 41 0e 01 + 39 01 00 00 00 00 1f d3 00 07 00 + 00 00 10 00 32 10 05 00 00 32 + 10 00 00 00 32 10 00 00 00 36 + 03 09 09 37 00 00 37 + 39 01 00 00 00 00 2d d5 02 03 00 + 01 06 07 04 05 20 21 22 23 18 + 18 18 18 18 18 18 18 18 18 18 + 18 18 18 18 18 18 18 18 18 18 + 18 18 18 18 18 24 25 18 18 19 + 19 + 39 01 00 00 00 00 2d d6 05 04 07 + 06 01 00 03 02 23 22 21 20 18 + 18 18 18 18 18 58 58 18 18 18 + 18 18 18 18 18 18 18 18 18 18 + 18 18 18 18 18 25 24 19 19 18 + 18 + 39 01 00 00 00 00 02 cc 09 + 39 01 00 00 00 00 03 c0 30 14 + 39 01 00 00 00 00 05 c7 00 c0 40 c0 + 39 01 00 00 00 00 03 b6 43 43 + 05 01 00 00 c8 00 02 11 00 + 05 01 00 00 0a 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <1>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [ + 79 1a 12 00 3e 42 + 16 1e 15 03 04 00 + ]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1b>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 20>; + qcom,mdss-pan-physical-width-dimension = <59>; + qcom,mdss-pan-physical-height-dimension = <104>; + + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1a3f5981b66bdead79bcb34dd1f390fdad89cc12 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-hx8399c-fhd-plus-video.dtsi @@ -0,0 +1,120 @@ +&mdss_mdp { + dsi_hx8399c_truly_vid: qcom,mdss_dsi_hx8399_truly_fhd_video { + qcom,mdss-dsi-panel-name = + "hx8399c video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <42>; + qcom,mdss-dsi-h-back-porch = <42>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <15>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <3>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 + b9 ff 83 99 + 39 01 00 00 00 00 02 + d2 88 + 39 01 00 00 00 00 0c + b1 02 04 72 92 01 + 32 aa 11 11 52 57 + 39 01 00 00 00 00 10 + b2 00 80 80 cc 05 07 5a + 11 10 10 00 1e 70 03 d4 + 39 01 00 00 00 00 2d + b4 00 ff 59 59 01 ab 00 + 00 09 00 03 05 00 28 03 + 0b 0d 21 03 02 00 0c a3 + 80 59 59 02 ab 00 00 09 + 00 03 05 00 28 03 0b 0d + 02 00 0c a3 01 + 39 01 00 00 05 00 22 + d3 00 0c 03 03 00 00 10 + 10 00 00 03 00 03 00 08 + 78 08 78 00 00 00 00 00 + 24 02 05 05 03 00 00 00 + 05 40 + 39 01 00 00 05 00 21 + d5 20 20 19 19 18 18 02 + 03 00 01 24 24 18 18 18 + 18 24 24 00 00 00 00 00 + 00 00 00 2f 2f 30 30 31 + 31 + 39 01 00 00 05 00 21 + d6 24 24 18 18 19 19 01 + 00 03 02 24 24 18 18 18 + 18 20 20 40 40 40 40 40 + 40 40 40 2f 2f 30 30 31 + 31 + 39 01 00 00 00 00 02 + bd 00 + 39 01 00 00 00 00 11 + d8 aa aa aa aa aa aa aa + aa aa ba aa aa aa ba aa + aa + 39 01 00 00 00 00 02 + bd 01 + 39 01 00 00 00 00 11 + d8 00 00 00 00 00 00 00 + 00 82 ea aa aa 82 ea aa + aa + 39 01 00 00 00 00 02 + bd 02 + 39 01 00 00 00 00 09 + d8 ff ff c0 3f ff ff c0 + 3f + 39 01 00 00 00 00 02 + bd 00 + 39 01 00 00 05 00 37 + e0 01 21 31 2d 66 6f 7b + 75 7a 81 86 89 8c 90 95 + 97 9a a1 a2 aa 9e ad b0 + 5b 57 63 7a 01 21 31 2d + 66 6f 7b 75 7a 81 86 89 + 8c 90 95 97 9a a1 a2 aa + 9e ad b0 5b 57 63 7a + 39 01 00 00 00 00 03 + b6 7e 7e + 39 01 00 00 00 00 02 + cc 08 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1184a2e41bae8009afccd1835bbd2b6dcc19a4d6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-lgd-incell-sw49106-fhd-video.dtsi @@ -0,0 +1,103 @@ +&mdss_mdp { + dsi_lgd_incell_sw49106_fhd_video: + qcom,mdss_dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-panel-name = + "lgd incell sw49106 fhd video"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <8>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <92>; + qcom,mdss-dsi-v-front-porch = <170>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [F8 3C 28 00 6E 72 2E + 40 30 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-on-command = [05 01 00 00 0B 00 02 35 00 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 51 FF + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 55 80 + 39 01 00 00 00 00 02 B0 AC + 39 01 00 00 00 00 06 B1 46 00 80 14 85 + 39 01 00 00 00 00 08 B3 05 08 14 00 1C 00 02 + 39 01 00 00 00 00 10 B4 83 08 00 04 04 04 04 00 + 00 00 00 00 00 00 00 + 39 01 00 00 00 00 13 B5 03 1E 0B 02 29 00 00 00 + 00 04 00 24 00 10 10 10 10 00 + 39 01 00 00 00 00 0A B6 00 72 39 13 08 67 00 60 46 + 39 01 00 00 00 00 05 B7 00 50 37 04 + 39 01 00 00 00 00 0C B8 70 38 14 ED 08 04 00 01 + 0A A0 00 + 39 01 00 00 00 00 06 C0 8A 8F 18 C1 12 + 39 01 00 00 00 00 07 C1 01 00 30 C2 C7 0F + 39 01 00 00 00 00 03 C2 2A 00 + 39 01 00 00 00 00 07 C3 05 0E 0E 50 88 09 + 39 01 00 00 00 00 04 C4 A2 E8 F4 + 39 01 00 00 00 00 05 C5 C2 2A 4E 08 + 39 01 00 00 00 00 03 C6 15 01 + 39 01 00 00 00 00 07 CA 00 00 03 84 55 F5 + 39 01 00 00 00 00 03 CB 3F A0 + 39 01 00 00 00 00 09 CC F0 03 10 55 11 FC 34 34 + 39 01 00 00 00 00 07 CD 11 50 50 90 00 F3 + 39 01 00 00 00 00 07 CE A0 28 28 34 00 AB + 39 01 00 00 00 00 10 D0 10 1B 22 2A 35 42 4A 53 4D + 44 34 23 10 03 81 + 39 01 00 00 00 00 10 D1 09 15 1C 25 31 3F 47 52 4F + 45 34 22 0E 01 83 + 39 01 00 00 00 00 10 D2 10 1B 22 29 34 41 49 52 4E + 44 34 23 10 03 81 + 39 01 00 00 00 00 10 D3 09 15 1C 24 30 3E 46 51 50 + 45 34 22 0E 01 83 + 39 01 00 00 00 00 10 D4 10 1B 22 2A 35 42 4A 53 4D + 44 34 23 10 03 81 + 39 01 00 00 00 00 10 D5 09 15 1C 25 31 3F 47 52 4F + 45 34 22 0E 01 83 + 39 01 00 00 00 00 0D E5 24 23 11 10 00 0A 08 06 04 + 11 0E 23 + 39 01 00 00 00 00 0D E6 24 23 11 10 01 0B 09 07 05 + 11 0E 23 + 39 01 00 00 00 00 07 E7 15 16 17 18 19 1A + 39 01 00 00 00 00 07 E8 1B 1C 1D 1E 1F 20 + 39 01 00 00 00 00 05 ED 00 01 53 0C + 39 01 00 00 00 00 03 F0 B2 00 + 39 01 00 00 00 00 05 F2 01 00 17 00 + 39 01 00 00 64 00 07 F3 00 50 90 C9 00 01 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 05 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 32 00 02 28 00 + 05 01 00 00 64 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 400>, <0 400>, <1 400>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f05fc5fc782764495960656d7330fa13ff4224da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,93 @@ +&mdss_mdp { + dsi_dual_nt35597_cmd: qcom,mdss_dsi_nt35597_wqxga_cmd{ + qcom,mdss-dsi-panel-name = + "Dual nt35597 cmd mode dsi panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03 + 04 00]; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,ulps-enabled; + qcom,mdss-dsi-on-command = [15 01 00 00 10 00 02 ff 10 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 ba 03 + 15 01 00 00 10 00 02 e5 01 + 15 01 00 00 10 00 02 35 00 + 15 01 00 00 10 00 02 bb 10 + 15 01 00 00 10 00 02 b0 03 + 15 01 00 00 10 00 02 ff e0 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 6b 3d + 15 01 00 00 10 00 02 6c 3d + 15 01 00 00 10 00 02 6d 3d + 15 01 00 00 10 00 02 6e 3d + 15 01 00 00 10 00 02 6f 3d + 15 01 00 00 10 00 02 35 02 + 15 01 00 00 10 00 02 36 72 + 15 01 00 00 10 00 02 37 10 + 15 01 00 00 10 00 02 08 c0 + 15 01 00 00 10 00 02 ff 24 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 c6 06 + 15 01 00 00 10 00 02 ff 10 + 05 01 00 00 a0 00 02 11 00 + 05 01 00 00 a0 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 02 28 00 + 05 01 00 00 3c 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,config-select = <&dsi_dual_nt35597_cmd_config0>; + + dsi_dual_nt35597_cmd_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + dsi_dual_nt35597_cmd_config1: config1 { + qcom,split-mode = "pingpong-split"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4059d721eb886485334d0433fdbb4c3252b0b745 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -0,0 +1,84 @@ +&mdss_mdp { + dsi_dual_nt35597_video: qcom,mdss_dsi_nt35597_wqxga_video { + qcom,mdss-dsi-panel-name = "Dual nt35597 video mode dsi + panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0x3ff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 ba 03 + 15 01 00 00 00 00 02 e5 01 + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 bb 03 + 15 01 00 00 00 00 02 b0 03 + 39 01 00 00 00 00 06 3b 03 08 08 64 9a + 15 01 00 00 00 00 02 ff e0 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 6b 3d + 15 01 00 00 00 00 02 6c 3d + 15 01 00 00 00 00 02 6d 3d + 15 01 00 00 00 00 02 6e 3d + 15 01 00 00 00 00 02 6f 3d + 15 01 00 00 00 00 02 35 02 + 15 01 00 00 00 00 02 36 72 + 15 01 00 00 00 00 02 37 10 + 15 01 00 00 00 00 02 08 c0 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 02 28 00 + 05 01 00 00 3c 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 6a 28 38 2a + 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + + qcom,config-select = <&dsi_dual_nt35597_video_config0>; + + dsi_dual_nt35597_video_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + dsi_dual_nt35597_video_config1: config1 { + qcom,split-mode = "pingpong-split"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8a05258d0e43b5e78b85425b01ebe334b768e5ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi @@ -0,0 +1,240 @@ +&mdss_mdp { + dsi_nt35597_truly_dsc_cmd: qcom,mdss_dsi_nt35597_dsc_cmd_truly { + qcom,mdss-dsi-panel-name = + "nt35597 cmd mode dsi truly panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x1 0x1>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f ae + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6D + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c D8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 C0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2d888cbce876ceb317e52d517ebdd7db5782fcf1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -0,0 +1,226 @@ +&mdss_mdp { + dsi_nt35597_truly_dsc_video: qcom,mdss_dsi_nt35597_dsc_video_truly { + qcom,mdss-dsi-panel-name = + "nt35597 video mode dsi truly panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <1>; + qcom,dsi-phy-num = <1>; + qcom,dsi-select-clocks = "src_byte_clk1", "src_pixel_clk1"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-dma-schedule-line = <5>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x00(2 Port SDC); + * 0x01(1 PortA FBC); + * 0x02(MTK); 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 39 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 03 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6c24158d20a718863bc156829bb5800997ca22eb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,230 @@ +&mdss_mdp { + dsi_dual_nt35597_truly_cmd: qcom,mdss_dsi_nt35597_truly_wqxga_cmd { + qcom,mdss-dsi-panel-name = + "Dual nt35597 cmd mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,config-select = <&dsi_dual_nt35597_truly_cmd_config0>; + dsi_dual_nt35597_truly_cmd_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-jitter = <0x1 0x1>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 + 64 26 34 29 03 04 00]; + qcom,mdss-dsi-panel-timings-phy-v2 = + [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e0602a18ac99deaa3a7c11acaa35b8cdb8597fb4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -0,0 +1,217 @@ +&mdss_mdp { + dsi_dual_nt35597_truly_video: qcom,mdss_dsi_nt35597_wqxga_video_truly { + qcom,mdss-dsi-panel-name = + "Dual nt35597 video mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-underflow-color = <0x3ff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,config-select = <&dsi_dual_nt35597_truly_video_config0>; + dsi_dual_nt35597_truly_video_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 FF 24 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 FF 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 03 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 + 6a 28 38 2a 03 04 00]; + qcom,mdss-dsi-panel-timings-phy-v2 = + [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..698c466b2ffd305134f5fe42ce8a7d19b98f1587 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35695b-truly-fhd-cmd.dtsi @@ -0,0 +1,183 @@ +&mdss_mdp { + dsi_nt35695b_truly_fhd_cmd: qcom,mdss_dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd command mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 + 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..78ae48b0ff8652bef8e3c7eadf2d9cd3379fb731 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35695b-truly-fhd-video.dtsi @@ -0,0 +1,179 @@ +&mdss_mdp { + dsi_nt35695b_truly_fhd_video: qcom,mdss_dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-name = + "nt35695b truly fhd video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 03 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 14 00 02 28 00 05 01 00 00 78 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt36525-truly-hd-plus-vid.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt36525-truly-hd-plus-vid.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..366a916b033707ce00f47a0501624dbe5e2f978d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt36525-truly-hd-plus-vid.dtsi @@ -0,0 +1,304 @@ +&mdss_mdp { + dsi_nt36525_truly_video: qcom,mdss_dsi_nt36525_truly_video { + qcom,mdss-dsi-panel-name = + "nt36525 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1520>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <88>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 05 A9 + 15 01 00 00 00 00 02 07 73 + 15 01 00 00 00 00 02 08 C1 + 15 01 00 00 00 00 02 0E 87 + 15 01 00 00 00 00 02 0F 55 + 15 01 00 00 00 00 02 1F 00 + 15 01 00 00 00 00 02 69 A9 + 15 01 00 00 00 00 02 6D 33 + 15 01 00 00 00 00 02 89 64 + 15 01 00 00 00 00 02 8A 64 + 15 01 00 00 00 00 02 8B 64 + 15 01 00 00 00 00 02 8C 64 + 15 01 00 00 00 00 02 95 EB + 15 01 00 00 00 00 02 96 EB + 15 01 00 00 00 00 02 FF 23 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 12 AB + 15 01 00 00 00 00 02 15 F5 + 15 01 00 00 00 00 02 16 0B + 15 01 00 00 00 00 02 FF 24 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 02 05 + 15 01 00 00 00 00 02 03 05 + 15 01 00 00 00 00 02 04 9F + 15 01 00 00 00 00 02 05 9F + 15 01 00 00 00 00 02 06 9E + 15 01 00 00 00 00 02 07 9E + 15 01 00 00 00 00 02 08 0C + 15 01 00 00 00 00 02 09 03 + 15 01 00 00 00 00 02 0A 0D + 15 01 00 00 00 00 02 0B 0E + 15 01 00 00 00 00 02 0C 0F + 15 01 00 00 00 00 02 0D 10 + 15 01 00 00 00 00 02 0E 11 + 15 01 00 00 00 00 02 0F 12 + 15 01 00 00 00 00 02 10 13 + 15 01 00 00 00 00 02 11 04 + 15 01 00 00 00 00 02 12 04 + 15 01 00 00 00 00 02 18 05 + 15 01 00 00 00 00 02 19 05 + 15 01 00 00 00 00 02 1A 9F + 15 01 00 00 00 00 02 1B 9F + 15 01 00 00 00 00 02 1C 9E + 15 01 00 00 00 00 02 1D 9E + 15 01 00 00 00 00 02 1E 0C + 15 01 00 00 00 00 02 1F 03 + 15 01 00 00 00 00 02 20 0D + 15 01 00 00 00 00 02 21 0E + 15 01 00 00 00 00 02 22 0F + 15 01 00 00 00 00 02 23 10 + 15 01 00 00 00 00 02 24 11 + 15 01 00 00 00 00 02 25 12 + 15 01 00 00 00 00 02 26 13 + 15 01 00 00 00 00 02 27 04 + 15 01 00 00 00 00 02 28 04 + 15 01 00 00 00 00 02 2F 0C + 15 01 00 00 00 00 02 30 40 + 15 01 00 00 00 00 02 33 40 + 15 01 00 00 00 00 02 34 0C + 15 01 00 00 00 00 02 37 77 + 15 01 00 00 00 00 02 3A 9A + 15 01 00 00 00 00 02 3B 95 + 15 01 00 00 00 00 02 3D 92 + 15 01 00 00 00 00 02 4D 15 + 15 01 00 00 00 00 02 4E 26 + 15 01 00 00 00 00 02 4F 37 + 15 01 00 00 00 00 02 50 48 + 15 01 00 00 00 00 02 51 84 + 15 01 00 00 00 00 02 52 73 + 15 01 00 00 00 00 02 53 62 + 15 01 00 00 00 00 02 54 51 + 15 01 00 00 00 00 02 55 86 + 15 01 00 00 00 00 02 56 78 + 15 01 00 00 00 00 02 5A 9A + 15 01 00 00 00 00 02 5B 95 + 15 01 00 00 00 00 02 5C 8F + 15 01 00 00 00 00 02 5D 0A + 15 01 00 00 00 00 02 5E 10 + 15 01 00 00 00 00 02 60 80 + 15 01 00 00 00 00 02 61 7C + 15 01 00 00 00 00 02 64 11 + 15 01 00 00 00 00 02 85 11 + 15 01 00 00 00 00 02 92 AD + 15 01 00 00 00 00 02 93 08 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 AB 00 + 15 01 00 00 00 00 02 AD 00 + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 B1 A9 + 15 01 00 00 00 00 02 FF 25 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 0A 82 + 15 01 00 00 00 00 02 0B 9C + 15 01 00 00 00 00 02 0C 01 + 15 01 00 00 00 00 02 17 82 + 15 01 00 00 00 00 02 18 06 + 15 01 00 00 00 00 02 19 0F + 15 01 00 00 00 00 02 1F 9A + 15 01 00 00 00 00 02 20 95 + 15 01 00 00 00 00 02 23 05 + 15 01 00 00 00 00 02 24 A9 + 15 01 00 00 00 00 02 26 9A + 15 01 00 00 00 00 02 27 95 + 15 01 00 00 00 00 02 2A 05 + 15 01 00 00 00 00 02 2B A9 + 15 01 00 00 00 00 02 2F 80 + 15 01 00 00 00 00 02 40 10 + 15 01 00 00 00 00 02 41 80 + 15 01 00 00 00 00 02 42 A6 + 15 01 00 00 00 00 02 43 95 + 15 01 00 00 00 00 02 46 05 + 15 01 00 00 00 00 02 47 A9 + 15 01 00 00 00 00 02 4C 95 + 15 01 00 00 00 00 02 4E 95 + 15 01 00 00 00 00 02 4F A6 + 15 01 00 00 00 00 02 50 95 + 15 01 00 00 00 00 02 53 05 + 15 01 00 00 00 00 02 54 A9 + 15 01 00 00 00 00 02 55 05 + 15 01 00 00 00 00 02 56 A9 + 15 01 00 00 00 00 02 5A 80 + 15 01 00 00 00 00 02 5B 80 + 15 01 00 00 00 00 02 5D 9A + 15 01 00 00 00 00 02 5E 95 + 15 01 00 00 00 00 02 5F 9A + 15 01 00 00 00 00 02 60 95 + 15 01 00 00 00 00 02 61 9A + 15 01 00 00 00 00 02 62 95 + 15 01 00 00 00 00 02 65 05 + 15 01 00 00 00 00 02 66 A9 + 15 01 00 00 00 00 02 FF 26 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 04 42 + 15 01 00 00 00 00 02 06 FF + 15 01 00 00 00 00 02 0C 0B + 15 01 00 00 00 00 02 0D 01 + 15 01 00 00 00 00 02 0E 02 + 15 01 00 00 00 00 02 0F 06 + 15 01 00 00 00 00 02 10 07 + 15 01 00 00 00 00 02 13 24 + 15 01 00 00 00 00 02 14 88 + 15 01 00 00 00 00 02 16 81 + 15 01 00 00 00 00 02 19 15 + 15 01 00 00 00 00 02 1A 0D + 15 01 00 00 00 00 02 1B 12 + 15 01 00 00 00 00 02 1C 82 + 15 01 00 00 00 00 02 1E AD + 15 01 00 00 00 00 02 1F AD + 15 01 00 00 00 00 02 24 00 + 15 01 00 00 00 00 02 2F 04 + 15 01 00 00 00 00 02 30 AD + 15 01 00 00 00 00 02 31 11 + 15 01 00 00 00 00 02 32 11 + 15 01 00 00 00 00 02 34 04 + 15 01 00 00 00 00 02 35 AD + 15 01 00 00 00 00 02 36 81 + 15 01 00 00 00 00 02 37 67 + 15 01 00 00 00 00 02 38 11 + 15 01 00 00 00 00 02 3F 10 + 15 01 00 00 00 00 02 40 AD + 15 01 00 00 00 00 02 58 D6 + 15 01 00 00 00 00 02 59 D6 + 15 01 00 00 00 00 02 5A D6 + 15 01 00 00 00 00 02 5B AD + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5D 26 + 15 01 00 00 00 00 02 5E 10 + 15 01 00 00 00 00 02 63 9A + 15 01 00 00 00 00 02 64 95 + 15 01 00 00 00 00 02 65 9A + 15 01 00 00 00 00 02 66 95 + 15 01 00 00 00 00 02 67 9A + 15 01 00 00 00 00 02 68 95 + 15 01 00 00 00 00 02 6B 00 + 15 01 00 00 00 00 02 6D 00 + 15 01 00 00 00 00 02 70 05 + 15 01 00 00 00 00 02 71 D2 + 15 01 00 00 00 00 02 73 9A + 15 01 00 00 00 00 02 74 95 + 15 01 00 00 00 00 02 77 05 + 15 01 00 00 00 00 02 78 D2 + 15 01 00 00 00 00 02 7A 9A + 15 01 00 00 00 00 02 7B 95 + 15 01 00 00 00 00 02 7E 05 + 15 01 00 00 00 00 02 7F D2 + 15 01 00 00 00 00 02 82 9A + 15 01 00 00 00 00 02 83 95 + 15 01 00 00 00 00 02 84 9A + 15 01 00 00 00 00 02 85 95 + 15 01 00 00 00 00 02 86 9A + 15 01 00 00 00 00 02 87 95 + 15 01 00 00 00 00 02 8A 05 + 15 01 00 00 00 00 02 8B A9 + 15 01 00 00 00 00 02 8F 00 + 15 01 00 00 00 00 02 90 00 + 15 01 00 00 00 00 02 92 05 + 15 01 00 00 00 00 02 93 F0 + 15 01 00 00 00 00 02 99 0D + 15 01 00 00 00 00 02 9A 36 + 15 01 00 00 00 00 02 9B 0C + 15 01 00 00 00 00 02 9C 9E + 15 01 00 00 00 00 02 FF 27 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 14 55 + 15 01 00 00 00 00 02 FF 27 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 9E 00 + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 FB 01 + 29 01 00 00 00 00 11 B0 00 00 00 2E 00 65 00 8C 00 AA 00 C4 00 DA 00 ED + 29 01 00 00 00 00 11 B1 00 FE 01 36 01 5C 01 99 01 C3 02 03 02 33 02 34 + 29 01 00 00 00 00 11 B2 02 64 02 98 02 C0 02 F1 03 10 03 47 03 53 03 64 + 29 01 00 00 00 00 0D B3 03 76 03 8C 03 A6 03 C3 03 D9 03 FF + 29 01 00 00 00 00 11 B4 00 00 00 2E 00 65 00 8C 00 AA 00 C4 00 DA 00 ED + 29 01 00 00 00 00 11 B5 00 FE 01 36 01 5C 01 99 01 C3 02 03 02 33 02 34 + 29 01 00 00 00 00 11 B6 02 64 02 98 02 C0 02 F1 03 10 03 47 03 53 03 64 + 29 01 00 00 00 00 0D B7 03 76 03 8C 03 A6 03 C3 03 D9 03 FF + 29 01 00 00 00 00 11 B8 00 00 00 2E 00 65 00 8C 00 AA 00 C4 00 DA 00 ED + 29 01 00 00 00 00 11 B9 00 FE 01 36 01 5C 01 99 01 C3 02 03 02 33 02 34 + 29 01 00 00 00 00 11 BA 02 64 02 98 02 C0 02 F1 03 10 03 47 03 53 03 64 + 29 01 00 00 00 00 0D BB 03 76 03 8C 03 A6 03 C3 03 D9 03 FF + 15 01 00 00 00 00 02 FF 21 + 15 01 00 00 00 00 02 FB 01 + 29 01 00 00 00 00 11 B0 00 00 00 2E 00 65 00 8C 00 AA 00 C4 00 DA 00 ED + 29 01 00 00 00 00 11 B1 00 FE 01 36 01 5C 01 99 01 C3 02 03 02 33 02 34 + 29 01 00 00 00 00 11 B2 02 64 02 98 02 C0 02 F1 03 10 03 47 03 53 03 64 + 29 01 00 00 00 00 0D B3 03 76 03 8C 03 A6 03 C3 03 D9 03 FF + 29 01 00 00 00 00 11 B4 00 00 00 2E 00 65 00 8C 00 AA 00 C4 00 DA 00 ED + 29 01 00 00 00 00 11 B5 00 FE 01 36 01 5C 01 99 01 C3 02 03 02 33 02 34 + 29 01 00 00 00 00 11 B6 02 64 02 98 02 C0 02 F1 03 10 03 47 03 53 03 64 + 29 01 00 00 00 00 0D B7 03 76 03 8C 03 A6 03 C3 03 D9 03 FF + 29 01 00 00 00 00 11 B8 00 00 00 2E 00 65 00 8C 00 AA 00 C4 00 DA 00 ED + 29 01 00 00 00 00 11 B9 00 FE 01 36 01 5C 01 99 01 C3 02 03 02 33 02 34 + 29 01 00 00 00 00 11 BA 02 64 02 98 02 C0 02 F1 03 10 03 47 03 53 03 64 + 29 01 00 00 00 00 0D BB 03 76 03 8C 03 A6 03 C3 03 D9 03 FF + 15 01 00 00 00 00 02 FF 10 + 15 01 00 00 00 00 02 FB 01 + 15 01 00 00 00 00 02 BA 03 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d066925a86f2fe9488a49da09ad15f68c87f879b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,80 @@ +&mdss_mdp { + dsi_dual_nt36850_truly_cmd: qcom,mdss_dsi_nt36850_truly_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual nt36850 cmd mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 50>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <140>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 44 03 e8 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 2c + 15 01 00 00 00 00 02 55 01 + 05 01 00 00 0a 00 02 20 00 + 15 01 00 00 00 00 02 bb 10 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f28d7f6df9bfd602940736f0dbb9b297e3def196 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-cmd.dtsi @@ -0,0 +1,334 @@ +&mdss_mdp { + dsi_r66451_amoled_120hz_cmd: qcom,mdss_dsi_r66451_fhd_plus_120hz_cmd { + qcom,mdss-dsi-panel-name = + "r66451 amoled cmd mode dsi visionox 120HZ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-pan-physical-width-dimension = <72>; + qcom,mdss-pan-physical-height-dimension = <157>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 1a c2 09 24 0c 00 00 + 0c 00 00 00 09 3c 00 00 00 00 00 00 + 00 00 00 00 00 30 00 6c + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 0c c2 09 24 0c 00 00 + 0c 00 00 00 09 3c + 39 01 00 00 00 00 1a d7 00 b9 3c 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 3c 00 40 04 00 a0 0a + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 14 de 40 00 18 00 18 + 00 18 00 18 10 00 18 00 18 00 18 02 + 00 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 e8 00 02 + 39 01 00 00 00 00 03 e4 00 08 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 11 c4 00 00 00 00 + 00 00 00 00 00 00 00 02 00 00 00 32 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 02 02 02 02 02 03 + 39 01 00 00 00 00 15 d3 45 00 00 01 13 + 15 00 15 07 0f 77 77 77 37 b2 11 00 + a0 3c 9c + 39 01 00 00 00 00 1a d7 00 b9 34 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 34 00 40 04 00 a0 0a + 39 01 00 00 00 00 34 d8 00 00 00 00 00 + 00 00 00 00 3a 00 3a 00 3a 00 3a 00 + 3a 05 00 00 00 00 00 00 00 00 00 0a + 00 0a 00 00 00 00 00 00 00 00 00 00 + 00 00 00 0a 00 32 00 0a 00 22 + 39 01 00 00 00 00 2b df 50 42 58 81 2d + 00 00 00 00 00 00 6b 00 00 00 00 00 + 00 00 00 01 0f ff d4 0e 00 00 00 00 + 00 00 0f 53 f1 00 00 00 00 00 00 00 + 00 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 0a e4 34 b4 00 00 00 + 39 04 09 34 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 14 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-timing-switch-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 1a c2 09 24 0c 00 00 + 0c 03 14 00 09 3c 00 00 00 00 00 00 + 00 00 00 00 00 30 00 6c + ]; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 0c c2 09 24 0c 00 00 + 0c 00 00 00 09 3c + 39 01 00 00 00 00 1a d7 00 b9 3c 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 3c 00 40 04 00 a0 0a + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 14 de 40 00 18 00 18 + 00 18 00 18 10 00 18 00 18 00 18 02 + 00 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 e8 00 02 + 39 01 00 00 00 00 03 e4 00 08 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 11 c4 00 00 00 00 + 00 00 00 00 00 00 00 02 00 00 00 32 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 02 02 02 02 02 03 + 39 01 00 00 00 00 15 d3 45 00 00 01 13 + 15 00 15 07 0f 77 77 77 37 b2 11 00 + a0 3c 9c + 39 01 00 00 00 00 1a d7 00 b9 34 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 34 00 40 04 00 a0 0a + 39 01 00 00 00 00 34 d8 00 00 00 00 00 + 00 00 00 00 3a 00 3a 00 3a 00 3a 00 + 3a 05 00 00 00 00 00 00 00 00 00 0a + 00 0a 00 00 00 00 00 00 00 00 00 00 + 00 00 00 0a 00 32 00 0a 00 22 + 39 01 00 00 00 00 2b df 50 42 58 81 2d + 00 00 00 00 00 00 6b 00 00 00 00 00 + 00 00 00 01 0f ff d4 0e 00 00 00 00 + 00 00 0f 53 f1 00 00 00 00 00 00 00 + 00 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 0a e4 34 b4 00 00 00 + 39 04 09 34 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 14 00 01 29 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 1a c2 09 24 0c 00 00 + 0c 03 14 00 09 3c 00 00 00 00 00 00 + 00 00 00 00 00 30 00 6c + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-timing-switch-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 1a c2 09 24 0c 00 00 + 0c 09 3c 00 09 3c 00 00 00 00 00 00 + 00 00 00 00 00 30 00 6c + ]; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 0c c2 09 24 0c 00 00 + 0c 00 00 00 09 3c + 39 01 00 00 00 00 1a d7 00 b9 3c 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 3c 00 40 04 00 a0 0a + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 14 de 40 00 18 00 18 + 00 18 00 18 10 00 18 00 18 00 18 02 + 00 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 e8 00 02 + 39 01 00 00 00 00 03 e4 00 08 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 11 c4 00 00 00 00 + 00 00 00 00 00 00 00 02 00 00 00 32 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 02 02 02 02 02 03 + 39 01 00 00 00 00 15 d3 45 00 00 01 13 + 15 00 15 07 0f 77 77 77 37 b2 11 00 + a0 3c 9c + 39 01 00 00 00 00 1a d7 00 b9 34 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 34 00 40 04 00 a0 0a + 39 01 00 00 00 00 34 d8 00 00 00 00 00 + 00 00 00 00 3a 00 3a 00 3a 00 3a 00 + 3a 05 00 00 00 00 00 00 00 00 00 0a + 00 0a 00 00 00 00 00 00 00 00 00 00 + 00 00 00 0a 00 32 00 0a 00 22 + 39 01 00 00 00 00 2b df 50 42 58 81 2d + 00 00 00 00 00 00 6b 00 00 00 00 00 + 00 00 00 01 0f ff d4 0e 00 00 00 00 + 00 00 0f 53 f1 00 00 00 00 00 00 00 + 00 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 0a e4 34 b4 00 00 00 + 39 04 09 34 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 14 00 01 29 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 1a c2 09 24 0c 00 00 + 0c 09 3c 00 09 3c 00 00 00 00 00 00 + 00 00 00 00 00 30 00 6c + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-timing-switch-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b312662069b2fddf6cd7ea92bf1376bf7af3105c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-120hz-video.dtsi @@ -0,0 +1,107 @@ +&mdss_mdp { + dsi_r66451_amoled_120hz_video: qcom,mdss_dsi_r66451_fhd_plus_120hz_video { + qcom,mdss-dsi-panel-name = + "r66451 amoled video mode dsi visionox 120HZ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-pan-physical-width-dimension = <72>; + qcom,mdss-pan-physical-height-dimension = <157>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <96>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <32>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 02 b3 01 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 e8 00 02 + 39 01 00 00 00 00 03 e4 00 08 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 11 c4 00 00 00 00 + 00 00 00 00 00 00 00 02 00 00 00 32 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 02 02 02 02 02 03 + 39 01 00 00 00 00 15 d3 45 00 00 01 13 + 15 00 15 07 0f 77 77 77 37 b2 11 00 + a0 3c 9c + 39 01 00 00 00 00 1a d7 00 b9 34 00 40 + 04 00 a0 0a 00 40 00 00 00 00 00 00 + 19 34 00 40 04 00 a0 0a + 39 01 00 00 00 00 34 d8 00 00 00 00 00 + 00 00 00 00 3a 00 3a 00 3a 00 3a 00 + 3a 05 00 00 00 00 00 00 00 00 00 0a + 00 0a 00 00 00 00 00 00 00 00 00 00 + 00 00 00 0a 00 32 00 0a 00 22 + 39 01 00 00 00 00 2b df 50 42 58 81 2d + 00 00 00 00 00 00 6b 00 00 00 00 00 + 00 00 00 01 0f ff d4 0e 00 00 00 00 + 00 00 0f 53 f1 00 00 00 00 00 00 00 + 00 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 0a e4 34 b4 00 00 00 + 39 04 09 34 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-144hz-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-144hz-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a959920b50ca9f6af7ff80db0c5f196a7889a1c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-144hz-cmd.dtsi @@ -0,0 +1,134 @@ +&mdss_mdp { + dsi_r66451_amoled_144hz_cmd: qcom,mdss_dsi_r66451_fhd_plus_144hz_cmd { + qcom,mdss-dsi-panel-name = + "r66451 amoled cmd mode dsi visionox panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <144>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 03 E8 00 02 + 39 01 00 00 00 00 03 E4 00 08 + 39 01 00 00 00 00 02 B0 00 + 39 01 00 00 00 00 32 C4 00 00 00 00 00 + 00 00 00 10 00 00 02 00 00 00 29 00 + 01 00 00 00 00 00 00 00 00 00 00 00 + 22 00 00 00 00 11 00 00 0C 00 00 00 + 00 30 00 00 00 00 00 00 + 39 01 00 00 00 00 86 CF 64 0B 00 00 00 + 00 00 00 08 00 0B 77 01 01 01 01 01 + 01 02 02 02 02 02 03 00 00 00 00 00 + 00 00 00 00 00 00 00 02 C9 02 C9 02 + C9 03 FF 03 FF 03 FF 00 00 00 00 00 + 00 00 00 00 00 00 00 02 C9 02 C9 02 + C9 03 FF 03 FF 03 FF 01 62 01 62 01 + 62 01 62 01 62 01 62 01 62 01 62 01 + 62 01 62 01 62 01 62 19 19 19 19 19 + 19 19 19 19 19 19 19 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 0F F6 0F + F6 0F F6 0F F6 0F F6 19 + 39 01 00 00 00 00 0D D0 44 44 B2 28 00 + 28 5A 00 5A 0D 17 01 + 39 01 00 00 00 00 15 D3 49 00 00 01 1A + 15 00 15 07 0F 77 77 77 37 B2 11 00 + A0 3C 9A + 39 01 00 00 00 00 1A D7 00 B9 40 00 40 + 04 00 F0 0F 00 40 00 00 00 00 00 00 + 19 40 00 40 04 00 F0 0F + 39 01 00 00 00 00 34 D8 00 00 00 00 00 + 00 00 00 00 30 00 30 00 30 00 30 00 + 30 05 00 00 00 00 00 00 00 00 00 0F + 00 0F 00 00 00 00 00 00 00 00 00 00 + 00 00 00 0F 00 2F 00 0F 00 20 + 39 01 00 00 00 00 2B DF 50 42 58 81 2D + 00 00 00 00 00 00 6B 00 00 00 00 00 + 00 00 00 01 0F FF D4 0E 00 00 00 00 + 00 00 0F 53 18 00 0F 00 00 00 00 00 + 00 + 39 01 00 00 00 00 02 F7 01 + 39 01 00 00 00 00 02 B0 80 + 39 01 00 00 00 00 0a E4 34 B4 00 00 00 + 30 04 0C E2 + 39 01 00 00 00 00 02 E6 00 + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 03 DF 50 40 + 39 01 00 00 00 00 06 F3 50 00 00 00 00 + 39 01 00 00 00 00 02 F2 11 + 39 01 00 00 00 00 06 F3 01 00 00 00 01 + 39 01 00 00 00 00 03 F4 00 02 + 39 01 00 00 00 00 02 F2 19 + 39 01 00 00 00 00 03 DF 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-timing-switch-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1303acb4a2c349cfb8ef42704a7110cb2ed857da --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-cmd.dtsi @@ -0,0 +1,95 @@ +&mdss_mdp { + dsi_r66451_amoled_60hz_cmd: qcom,mdss_dsi_r66451_fhd_plus_60hz_cmd { + qcom,mdss-dsi-panel-name = + "r66451 amoled cmd mode dsi visionox 60HZ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 13 d8 00 00 00 00 00 + 00 00 00 00 5b 00 5b 00 5b 00 5b 00 + 5b + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 04 04 04 04 04 05 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cfda350675adc89bcc06b987e01c57a61dbc0764 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-60hz-video.dtsi @@ -0,0 +1,86 @@ +&mdss_mdp { + dsi_r66451_amoled_60hz_video: qcom,mdss_dsi_r66451_fhd_plus_60hz_video { + qcom,mdss-dsi-panel-name = + "r66451 amoled video mode dsi visionox 60HZ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 02 b3 01 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 13 d8 00 00 00 00 00 + 00 00 00 00 5b 00 5b 00 5b 00 5b 00 + 5b + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 04 04 04 04 04 05 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-90hz-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-90hz-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3b1a851a055a2d7397c4badec2386d87d03c5928 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-90hz-cmd.dtsi @@ -0,0 +1,91 @@ +&mdss_mdp { + dsi_r66451_amoled_90hz_cmd: qcom,mdss_dsi_r66451_fhd_plus_90hz_cmd { + qcom,mdss-dsi-panel-name = + "r66451 amoled cmd mode dsi visionox 90HZ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 04 04 04 04 04 05 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-90hz-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-90hz-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..dd76a024b17b5732b7d46acd0b46405cdcf74d55 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-dsc-fhd-plus-90hz-video.dtsi @@ -0,0 +1,82 @@ +&mdss_mdp { + dsi_r66451_amoled_90hz_video: qcom,mdss_dsi_r66451_fhd_plus_90hz_video { + qcom,mdss-dsi-panel-name = + "r66451 amoled video mode dsi visionox 90HZ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 02 b3 01 + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 04 04 04 04 04 05 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 02 f7 01 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 04 37 + 39 01 00 00 00 00 05 2b 00 00 09 23 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <20>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-hd-plus-90hz-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-hd-plus-90hz-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c5b9f65b7c8e2d3bec9d243de0b85b6ad09a26fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-hd-plus-90hz-cmd.dtsi @@ -0,0 +1,86 @@ +&mdss_mdp { + dsi_r66451_amoled_hd_90hz_cmd: qcom,mdss_dsi_r66451_hd_plus_90hz_cmd { + qcom,mdss-dsi-panel-name = + "r66451 amoled cmd mode dsi visionox 90HZ panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1560>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 d9 09 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 04 04 04 04 04 05 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 eb 00 00 + 39 01 00 00 00 00 02 f7 00 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 05 2a 00 00 02 cf + 39 01 00 00 00 00 05 2b 00 00 06 17 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-hd-plus-90hz-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-hd-plus-90hz-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..abb12bd2ac2ab9b8c85202883c44b6d2e8be2343 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-r66451-hd-plus-90hz-video.dtsi @@ -0,0 +1,76 @@ +&mdss_mdp { + dsi_r66451_amoled_hd_90hz_video: qcom,mdss_dsi_r66451_hd_plus_90hz_video { + qcom,mdss-dsi-panel-name = + "r66451 amoled video mode dsi visionox 90HZ panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 10>, <1 20>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1560>; + qcom,mdss-dsi-h-front-porch = <95>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <1>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <25>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 02 b3 01 + 39 01 00 00 00 00 02 b0 80 + 39 01 00 00 00 00 02 e6 00 + 39 01 00 00 00 00 02 d9 09 + 39 01 00 00 00 00 02 b0 00 + 39 01 00 00 00 00 19 cf 64 0b 00 00 00 + 00 00 00 08 00 0b 77 01 01 01 01 01 + 01 04 04 04 04 04 05 + 39 01 00 00 00 00 02 b0 04 + 39 01 00 00 00 00 03 eb 00 00 + 39 01 00 00 00 00 02 f7 00 + 39 01 00 00 00 00 03 df 50 40 + 39 01 00 00 00 00 06 f3 50 00 00 00 00 + 39 01 00 00 00 00 02 f2 11 + 39 01 00 00 00 00 06 f3 01 00 00 00 01 + 39 01 00 00 00 00 03 f4 00 02 + 39 01 00 00 00 00 02 f2 19 + 39 01 00 00 00 00 03 df 50 42 + 39 01 00 00 00 00 05 2a 00 00 02 cf + 39 01 00 00 00 00 05 2b 00 00 06 17 + 05 01 00 00 78 00 01 11 + 05 01 00 00 00 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9cdfd590806f7438b79d78d4abe0a8dd3e183d9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm67195-amoled-fhd-cmd.dtsi @@ -0,0 +1,119 @@ +&mdss_mdp { + dsi_rm67195_amoled_fhd_cmd: qcom,mdss_dsi_rm67195_amoled_fhd_cmd{ + qcom,mdss-dsi-panel-name = + "rm67195 amoled fhd cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 fe 0d + 15 01 00 00 00 00 02 0b c0 + 15 01 00 00 00 00 02 42 00 + 15 01 00 00 00 00 02 18 08 + 15 01 00 00 00 00 02 08 41 + 15 01 00 00 00 00 02 46 02 + 15 01 00 00 00 00 02 1e 04 + 15 01 00 00 02 00 02 1e 00 + 15 01 00 00 00 00 02 fe 0a + 15 01 00 00 00 00 02 24 17 + 15 01 00 00 00 00 02 04 07 + 15 01 00 00 00 00 02 1a 0c + 15 01 00 00 02 00 02 0f 44 + 15 01 00 00 00 00 02 fe 0b + 15 01 00 00 00 00 02 28 40 + 15 01 00 00 02 00 02 29 4f + 15 01 00 00 00 00 02 fe 04 + 15 01 00 00 00 00 02 0a d8 + 15 01 00 00 00 00 02 0c e6 + 15 01 00 00 00 00 02 4e 20 + 15 01 00 00 00 00 02 4f 1b + 15 01 00 00 00 00 02 50 2f + 15 01 00 00 02 00 02 51 08 + 15 01 00 00 00 00 02 fe 09 + 15 01 00 00 00 00 02 00 08 + 15 01 00 00 00 00 02 01 08 + 15 01 00 00 00 00 02 02 00 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 04 10 + 15 01 00 00 00 00 02 05 00 + 15 01 00 00 00 00 02 06 08 + 15 01 00 00 00 00 02 07 08 + 15 01 00 00 00 00 02 08 00 + 15 01 00 00 00 00 02 12 24 + 15 01 00 00 00 00 02 13 49 + 15 01 00 00 00 00 02 14 92 + 15 01 00 00 00 00 02 15 49 + 15 01 00 00 00 00 02 16 92 + 15 01 00 00 00 00 02 17 24 + 15 01 00 00 00 00 02 18 24 + 15 01 00 00 00 00 02 19 49 + 15 01 00 00 00 00 02 1a 92 + 15 01 00 00 00 00 02 1b 49 + 15 01 00 00 00 00 02 1c 92 + 15 01 00 00 00 00 02 1d 24 + 15 01 00 00 00 00 02 1e 24 + 15 01 00 00 00 00 02 1f 49 + 15 01 00 00 00 00 02 20 92 + 15 01 00 00 00 00 02 21 49 + 15 01 00 00 00 00 02 22 92 + 15 01 00 00 00 00 02 23 24 + 15 01 00 00 00 00 02 9b 07 + 15 01 00 00 02 00 02 9c a5 + 15 01 00 00 00 00 02 fe 00 + 15 01 00 00 00 00 02 c2 08 + 15 01 00 00 02 00 02 35 00 + 39 01 00 00 00 00 03 44 03 e8 + 05 01 00 00 82 00 02 11 00 + 05 01 00 00 14 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 82 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_pulse"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-pan-physical-width-dimension = <70>; + qcom,mdss-pan-physical-height-dimension = <125>; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-panel-orientation = "180"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm69299-visionox-fhd-plus-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm69299-visionox-fhd-plus-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3137cb65e3e4e75d3258c50413d38f8a9c77048d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm69299-visionox-fhd-plus-cmd.dtsi @@ -0,0 +1,72 @@ +&mdss_mdp { + dsi_rm69299_visionox_amoled_cmd: + qcom,mdss_dsi_rm69299_visionox_amoled_cmd { + qcom,mdss-dsi-panel-name = + "rm69299 amoled fhd+ cmd mode dsi visionox panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2248>; + qcom,mdss-dsi-h-front-porch = <26>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <2>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <56>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 FE 00 + 39 01 00 00 00 00 02 C2 08 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 51 FF + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp1-command = + [05 01 00 00 00 00 02 39 00]; + qcom,mdss-dsi-lp1-command-state ="dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = + [05 01 00 00 00 00 02 38 00]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm69299-visionox-fhd-plus-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm69299-visionox-fhd-plus-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5cd896fcd21337e073686c231616a02a0090c450 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-rm69299-visionox-fhd-plus-video.dtsi @@ -0,0 +1,72 @@ +&mdss_mdp { + dsi_rm69299_visionox_amoled_video: + qcom,mdss_dsi_rm69299_visionox_amoled_video { + qcom,mdss-dsi-panel-name = + "rm69299 amoled fhd+ video mode dsi visionox panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2248>; + qcom,mdss-dsi-h-front-porch = <26>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <2>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <56>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 FE 00 + 39 01 00 00 00 00 02 C2 08 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 51 FF + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp1-command = + [05 01 00 00 00 00 02 39 00]; + qcom,mdss-dsi-lp1-command-state ="dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = + [05 01 00 00 00 00 02 38 00]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11eb3a30d232cffdb3225a895e4775083239968c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,129 @@ +&mdss_mdp { + dsi_dual_s6e3ha3_amoled_cmd: qcom,mdss_dsi_s6e3ha3_amoled_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual s6e3ha3 amoled cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <31>; + qcom,mdss-dsi-v-front-porch = <30>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-on-command = [05 01 00 00 05 00 02 11 00 + 39 01 00 00 00 00 05 2a 00 00 05 9f + 39 01 00 00 00 00 05 2b 00 00 09 ff + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 02 b0 10 + 39 01 00 00 00 00 02 b5 a0 + 39 01 00 00 00 00 02 c4 03 + 39 01 00 00 00 00 0a + f6 42 57 37 00 aa cc d0 00 00 + 39 01 00 00 00 00 02 f9 03 + 39 01 00 00 00 00 14 + c2 00 00 d8 d8 00 80 2b 05 08 + 0e 07 0b 05 0d 0a 15 13 20 1e + 39 01 00 00 78 00 03 f0 a5 a5 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 02 51 60 + 05 01 00 00 05 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 3c 00 02 28 00 + 05 01 00 00 b4 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp-mode-on = [39 00 00 00 05 00 03 f0 5a 5a + 39 00 00 00 05 00 03 f1 5a 5a + 39 00 00 00 05 00 03 fc 5a 5a + 39 00 00 00 05 00 02 b0 17 + 39 00 00 00 05 00 02 cb 10 + 39 00 00 00 05 00 02 b0 2d + 39 00 00 00 05 00 02 cb cd + 39 00 00 00 05 00 02 b0 0e + 39 00 00 00 05 00 02 cb 02 + 39 00 00 00 05 00 02 b0 0f + 39 00 00 00 05 00 02 cb 09 + 39 00 00 00 05 00 02 b0 02 + 39 00 00 00 05 00 02 f2 c9 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f2 c0 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f4 aa + 39 00 00 00 05 00 02 b0 08 + 39 00 00 00 05 00 02 b1 30 + 39 00 00 00 05 00 02 b0 09 + 39 00 00 00 05 00 02 b1 0a + 39 00 00 00 05 00 02 b0 0d + 39 00 00 00 05 00 02 b1 10 + 39 00 00 00 05 00 02 b0 00 + 39 00 00 00 05 00 02 f7 03 + 39 00 00 00 05 00 02 fe 30 + 39 01 00 00 05 00 02 fe b0]; + qcom,mdss-dsi-lp-mode-off = [39 00 00 00 05 00 03 f0 5a 5a + 39 00 00 00 05 00 03 f1 5a 5a + 39 00 00 00 05 00 03 fc 5a 5a + 39 00 00 00 05 00 02 b0 2d + 39 00 00 00 05 00 02 cb 4d + 39 00 00 00 05 00 02 b0 17 + 39 00 00 00 05 00 02 cb 04 + 39 00 00 00 05 00 02 b0 0e + 39 00 00 00 05 00 02 cb 06 + 39 00 00 00 05 00 02 b0 0f + 39 00 00 00 05 00 02 cb 05 + 39 00 00 00 05 00 02 b0 02 + 39 00 00 00 05 00 02 f2 b8 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f2 80 + 39 00 00 00 05 00 02 b0 03 + 39 00 00 00 05 00 02 f4 8a + 39 00 00 00 05 00 02 b0 08 + 39 00 00 00 05 00 02 b1 10 + 39 00 00 00 05 00 02 b0 09 + 39 00 00 00 05 00 02 b1 0a + 39 00 00 00 05 00 02 b0 0d + 39 00 00 00 05 00 02 b1 80 + 39 00 00 00 05 00 02 b0 00 + 39 00 00 00 05 00 02 f7 03 + 39 00 00 00 05 00 02 fe 30 + 39 01 00 00 05 00 02 fe b0]; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <122>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ams644vk04_ana6705_fhd_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ams644vk04_ana6705_fhd_dsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c8b404d55a1d63bf63bce310a9c3cd692e30b848 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ams644vk04_ana6705_fhd_dsc.dtsi @@ -0,0 +1,651 @@ +/*This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +&mdss_mdp { + dsi_samsung_ams644vk04_ana6705_dsc_cmd: qcom,mdss_dsi_samsung_ams644vk04_ana6705_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel"; + qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-version = "DSC"; + qcom,mdss-dsi-backlight-version = "SAMSUNG"; + qcom,mdss-dsi-backlight-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-default-val = <200>; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-pan-physical-width-dimension = <70>; + qcom,mdss-pan-physical-height-dimension = <151>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-loading-effect; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-bl-high2bit; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + /* HDR Setting */ + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15635 16450 34000 16000 13250 34500 7500 3000>; + qcom,mdss-dsi-panel-peak-brightness = <5400000>; + qcom,mdss-dsi-panel-average-brightness = <2000000>; + qcom,mdss-dsi-panel-blackness-level = <2000>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + qcom,mdss-dsi-panel-seria-num-year-index = <11>; + qcom,mdss-dsi-panel-seria-num-mon-index = <11>; + qcom,mdss-dsi-panel-seria-num-day-index = <12>; + qcom,mdss-dsi-panel-seria-num-hour-index = <13>; + qcom,mdss-dsi-panel-seria-num-min-index = <14>; + qcom,mdss-dsi-panel-seria-num-sec-index = <15>; + qcom,mdss-dsi-panel-seria-num-msec-high-index = <16>; + qcom,mdss-dsi-panel-seria-num-msec-low-index = <17>; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 00]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9C>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-id1-command = [06 01 00 00 00 00 02 0A 00]; + qcom,mdss-dsi-panel-id1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,display-topology = <1 1 1>, <2 2 1>; + qcom,default-topology-index = <1>; + qcom,mdss-mdp-transfer-time-us = <8000>; //for 60fps + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <830000000>; + qcom,mdss-dsi-panel-phy-timings = [00 1D 07 07 23 22 07 07 05 02 04 00 18 17]; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2400>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <24>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <1208>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + /* 60hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 9D 01 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 60 + 04 38 00 30 02 1C 02 1C + 02 00 02 52 00 20 04 23 + 00 07 00 0F 02 8E 02 1F + 18 00 10 F0 03 0C 20 00 + 06 0B 0B 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 01 02 01 00 09 40 + 09 BE 19 FC 19 FA 19 F8 + 1A 38 1A 78 1A B6 2A B6 + 2A F4 2A F4 4B 34 63 74 + 05 01 00 00 14 00 01 11 + /* TE ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 5F + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 04 D7 07 02 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FFC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 C4 + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 06 F8 41 47 11 B8 B8 + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 CC + 39 01 00 00 00 00 03 F0 A5 A5 + /* FB DELAY */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 3B + 39 01 00 00 00 00 02 F5 25 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 06 + 39 01 00 00 00 00 02 B7 01 + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /* 60hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* ACL Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 55 00 + 39 01 00 00 6E 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-off-command=[ + 05 01 00 00 14 00 01 28 + 05 01 00 00 96 00 01 10 + ]; + qcom,mdss-dsi-panel-hbm-on-command-1 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 05 21 /* fod correction 697nit */ + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 04 AE /* fod correction 697nit*/ + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + /* ELVSS Dim Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 /* 0x13 : ELVSS DIM OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 1B /* 0x1B : DLY OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 08 00 03 51 05 CB /* 800nit */ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + 15 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + ]; + qcom,mdss-dsi-panel-serial-num-pre-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 37 01 00 00 05 00 02 10 00 + ]; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 00 + ]; + qcom,mdss-dsi-panel-code-info-command = [ + 06 01 00 00 00 00 01 DA 00 + ]; + qcom,mdss-dsi-panel-stage-info-command = [ + 06 01 00 00 00 00 01 DB 00 + ]; + qcom,mdss-dsi-panel-production-info-command = [ + 06 01 00 00 00 00 01 DC 00 + ]; + qcom,mdss-dsi-panel-serial-num-post-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 83 56 37 /* 0x83 : OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 A3 56 37 /* 0xA3 : ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-on-command-1 = [ + ]; + qcom,mdss-dsi-panel-aod-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* ELVSS Dim Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 /* 0x13 : ELVSS DIM OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 1B /* 0x1B : DLY OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 08 00 03 51 05 CB /* 800nit */ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 03 81 31 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B1 B2 05 00 06 CC 01 09 00 A8 15 E7 D5 CB 07 B5 E0 DD 01 FF FF FF + 39 01 00 00 00 00 02 B1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-id1-command = [ + 06 01 00 00 00 00 02 0A 00 + ]; + qcom,mdss-dsi-panel-id2-command = [ + 06 01 00 00 00 00 02 EE 00 + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-5-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-serial-num-pre-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-code-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-state-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-production-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-post-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-aod-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-aod-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<540 48 540 48 540 48>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <48>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + timing@1{ + qcom,display-topology = <1 1 1>, <2 2 1>; + qcom,default-topology-index = <1>; + qcom,mdss-mdp-transfer-time-us = <8000>; //for 90fps + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-clockrate = <830000000>; + qcom,mdss-dsi-panel-phy-timings = [00 1D 07 07 23 22 07 07 05 02 04 00 18 17]; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2400>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <24>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-panel-command = [ + ]; + qcom,mdss-dsi-timing-switch-command = [ + /* 90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 9D 01 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 60 + 04 38 00 30 02 1C 02 1C + 02 00 02 52 00 20 04 23 + 00 07 00 0F 02 8E 02 1F + 18 00 10 F0 03 0C 20 00 + 06 0B 0B 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 01 02 01 00 09 40 + 09 BE 19 FC 19 FA 19 F8 + 1A 38 1A 78 1A B6 2A B6 + 2A F4 2A F4 4B 34 63 74 + 05 01 00 00 14 00 01 11 + /* TE ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 5F + /* TSP SYNC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 04 D7 07 02 40 + 39 01 00 00 00 00 03 F0 A5 A5 + /* FFC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 C4 + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 06 F8 41 47 11 B8 B8 + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 CC + 39 01 00 00 00 00 03 F0 A5 A5 + /* FB DELAY */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 3B + 39 01 00 00 00 00 02 F5 25 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 06 + 39 01 00 00 00 00 02 B7 01 + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /* 90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + /* ACL Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 55 00 + 39 01 00 00 6E 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-off-command=[ + 05 01 00 00 14 00 01 28 + 05 01 00 00 96 00 01 10 + ]; + qcom,mdss-dsi-panel-hbm-on-command-1 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 05 21 /* fod correction 697nit */ + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 04 AE /* fod correction 697nit*/ + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + /* ELVSS Dim Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 /* 0x13 : ELVSS DIM OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 1B /* 0x1B : DLY OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 08 00 03 51 05 CB /* 800nit */ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + 15 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + ]; + qcom,mdss-dsi-panel-serial-num-pre-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 37 01 00 00 05 00 02 10 00 + ]; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 00 + ]; + qcom,mdss-dsi-panel-code-info-command = [ + 06 01 00 00 00 00 01 DA 00 + ]; + qcom,mdss-dsi-panel-stage-info-command = [ + 06 01 00 00 00 00 01 DB 00 + ]; + qcom,mdss-dsi-panel-production-info-command = [ + 06 01 00 00 00 00 01 DC 00 + ]; + qcom,mdss-dsi-panel-serial-num-post-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 83 56 37 /* 0x83 : OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 A3 56 37 /* 0xA3 : ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-on-command-1 = [ + ]; + qcom,mdss-dsi-panel-aod-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* ELVSS Dim Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 /* 0x13 : ELVSS DIM OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 1B /* 0x1B : DLY OFF */ + 39 01 00 00 06 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 08 00 03 51 05 CB /* 800nit */ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 03 81 31 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B1 B2 05 00 06 CC 01 09 00 A8 15 E7 D5 CB 07 B5 E0 DD 01 FF FF FF + 39 01 00 00 00 00 02 B1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-id1-command = [ + 06 01 00 00 00 00 02 0A 00 + ]; + qcom,mdss-dsi-panel-id2-command = [ + 06 01 00 00 00 00 02 EE 00 + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-5-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-serial-num-pre-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-code-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-state-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-production-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-post-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-aod-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-aod-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<540 48 540 48 540 48>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <48>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; +&dsi_samsung_ams644vk04_ana6705_dsc_cmd { + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + //qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_samsung>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; +&soc { + dsi_samsung_ams644vk04_ana6705_dsc_cmd { + qcom,dsi-display-active; + }; +}; +&dsi_samsung_ams644vk04_ana6705_dsc_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* wqhd 60hz */ + qcom,mdss-dsi-panel-phy-timings = [00 1D 07 07 23 22 07 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + }; + timing@1 { /* fhd 90hz */ + qcom,mdss-dsi-panel-phy-timings = [00 1D 07 07 23 22 07 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ams644vk04_fhd_dsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ams644vk04_fhd_dsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bcebcd097cce6a684deedace0ffca1461221bf1d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_ams644vk04_fhd_dsc.dtsi @@ -0,0 +1,1065 @@ +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +&mdss_mdp { + dsi_samsung_ams644vk04_dsc_cmd: qcom,mdss_dsi_samsung_ams644vk04_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung ams644vk04 fhd cmd mode dsc dsi panel"; + qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-version = "DSC"; + qcom,mdss-dsi-backlight-version = "SAMSUNG"; + qcom,mdss-dsi-backlight-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-brightness-default-val = <320>; + qcom,mdss-brightness-max-level = <2047>; + qcom,mdss-pan-physical-width-dimension = <67>; + qcom,mdss-pan-physical-height-dimension = <149>; + //qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-loading-effect; + qcom,mdss-dsi-te-using-te-pin; + //qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-bl-high2bit; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + /* HDR Setting */ + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15635 16450 34000 16000 13250 34500 7500 3000>; + qcom,mdss-dsi-panel-peak-brightness = <5400000>; + qcom,mdss-dsi-panel-average-brightness = <2000000>; + qcom,mdss-dsi-panel-blackness-level = <2000>; + qcom,dynamic-mode-switch-enabled; + qcom,dynamic-mode-switch-type = "dynamic-switch-immediate"; + qcom,mdss-dsi-panel-seria-num-year-index = <5>; + qcom,mdss-dsi-panel-seria-num-mon-index = <5>; + qcom,mdss-dsi-panel-seria-num-day-index = <6>; + qcom,mdss-dsi-panel-seria-num-hour-index = <7>; + qcom,mdss-dsi-panel-seria-num-min-index = <8>; + qcom,mdss-dsi-panel-seria-num-sec-index = <9>; + qcom,mdss-dsi-panel-seria-num-msec-high-index = <10>; + qcom,mdss-dsi-panel-seria-num-msec-low-index = <11>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 00]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9C>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-mdp-transfer-time-us = <12000>; //for 60fps + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <832000000>; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2400>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <24>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <1208>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + /* 60hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OPEC Control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 E6 02 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 69 + 39 01 00 00 00 00 02 E6 02 + 39 01 00 00 00 00 02 B0 77 + 39 01 00 00 00 00 02 E6 B3 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 9D 01 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 60 + 04 38 00 30 02 1C 02 1C + 02 00 02 52 00 20 04 23 + 00 07 00 0F 02 8E 02 1F + 18 00 10 F0 03 0C 20 00 + 06 0B 0B 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 01 02 01 00 09 40 + 09 BE 19 FC 19 FA 19 F8 + 1A 38 1A 78 1A B6 2A B6 + 2A F4 2A F4 4B 34 63 74 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Sleep Out(11h) */ + 05 01 00 00 14 00 01 11 + /* TE ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 5F + /* FFC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 F5 85 + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 C4 + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 06 F8 41 47 11 B8 B8 + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 CC + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 F2 82 + 39 01 00 00 00 00 02 F5 87 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Fast Discharge */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 DD 40 + 39 01 00 00 6E 00 03 F0 A5 A5 + /* Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 06 + 39 01 00 00 00 00 02 B7 01 + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /* 60hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* ACL Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 55 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* SEED LP */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OPEC Control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 E6 02 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 69 + 39 01 00 00 00 00 02 E6 02 + 39 01 00 00 00 00 02 B0 77 + 39 01 00 00 00 00 02 E6 B3 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-off-command=[ + 05 01 00 00 0A 00 01 28 + 05 01 00 00 78 00 01 10 + ]; + qcom,mdss-dsi-panel-hbm-on-command-1 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 0C 7C + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 0A AA + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 14 00 03 51 01 D3 /* 800nit */ + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + 15 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* ELVSS Dim Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 /* 0x13 : ELVSS DIM OFF */ + 39 01 00 00 01 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 3F /* DLY OFF */ + 39 01 00 00 01 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 09 00 03 51 07 FF + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-serial-num-pre-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 37 01 00 00 05 00 02 10 00 + ]; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 00 + ]; + qcom,mdss-dsi-panel-code-info-command = [ + 06 01 00 00 00 00 01 DA 00 + ]; + qcom,mdss-dsi-panel-stage-info-command = [ + 06 01 00 00 00 00 01 DB 00 + ]; + qcom,mdss-dsi-panel-production-info-command = [ + 06 01 00 00 00 00 01 DC 00 + ]; + qcom,mdss-dsi-panel-serial-num-post-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 83 56 37 /* 0x83 : OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 A3 56 37 /* 0xA3 : ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-on-command-1 = [ + /* 10nit */ + 15 01 00 00 00 00 02 53 23 + ]; + qcom,mdss-dsi-panel-aod-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-aod-on-command-3 = [ + /* 50nit */ + 15 01 00 00 00 00 02 53 22 + ]; + qcom,mdss-dsi-panel-aod-on-command-4 = [ + ]; + qcom,mdss-dsi-panel-aod-on-command-5 = [ + /* 50nit */ + 15 01 00 00 21 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 07 + 39 01 00 00 00 00 02 F4 5B + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 53 22 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + /* 60hz Transition */ + 15 01 00 00 21 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + /* 60hz Transition */ + 15 01 00 00 21 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + /* 60hz Transition */ + 15 01 00 00 21 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 14 00 03 51 01 D3 /* 800nit */ + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + /* Aod Mode Off */ + 15 01 00 00 21 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 20 00 03 51 01 D3 /* 800nit */ + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 03 81 31 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B1 B2 09 02 36 D8 10 09 04 C6 40 E6 CD BC 0E C0 F0 EE 16 F6 FB F0 + 39 01 00 00 00 00 02 B1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF FD F6 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 03 36 D8 0D 09 04 C6 40 E6 CD BC 0E C0 F4 EE 12 FF F8 E3 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 DF EC FF + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 04 36 D8 12 09 04 C6 40 E6 D8 BC 0E D4 F0 EE 16 FF FD F5 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF FD F6 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-low-backlight-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF F6 F1 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-low-backlight-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 03 36 D8 0D 09 04 C6 40 E6 CD BC 0E C0 F4 EE 12 FF F0 DD + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-low-backlight-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 DF E3 FF + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-low-backlight-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 04 36 D8 12 09 04 C6 40 E6 D8 BC 0E D4 F0 EE 16 FF F4 F2 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-low-backlight-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF F6 F1 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-ed-command = [ + 39 01 00 00 00 00 02 ED 97 + ]; + qcom,mdss-dsi-panel-id1-command = [ + 06 01 00 00 00 00 02 0A 00 + ]; + qcom,mdss-dsi-panel-id2-command = [ + 06 01 00 00 00 00 02 EE 00 + ]; + qcom,mdss-dsi-panel-id3-command = [ + 06 01 00 00 00 00 02 E5 00 + ]; + qcom,mdss-dsi-panel-id4-command = [ + 06 01 00 00 00 00 02 ED 00 + ]; + qcom,mdss-dsi-panel-check-info-command = [ + 06 01 00 00 00 00 02 D6 00 + ]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-5-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-serial-num-pre-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-code-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-state-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-production-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-post-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-aod-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-aod-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-4-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-5-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-p3-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-srgb-low-backlight-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-low-backlight-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-srgb-color-mode-low-backlight-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-p3-mode-low-backlight-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-wide-color-mode-low-backlight-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-ed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id4-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-check-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<540 48 540 48 540 48>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <48>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1{ + qcom,mdss-mdp-transfer-time-us = <8000>; //for 90fps + qcom,mdss-dsi-timing-default; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-clockrate = <832000000>; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,mdss-dsi-t-clk-post = <0x17>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2400>; + qcom,mdss-dsi-h-front-porch = <52>; + qcom,mdss-dsi-h-back-porch = <24>; + qcom,mdss-dsi-h-pulse-width = <24>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + /* 90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OPEC Control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 E6 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-on-command = [ + /* DSC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 9D 01 + 39 01 00 00 00 00 59 9E + 11 00 00 89 30 80 09 60 + 04 38 00 30 02 1C 02 1C + 02 00 02 52 00 20 04 23 + 00 07 00 0F 02 8E 02 1F + 18 00 10 F0 03 0C 20 00 + 06 0B 0B 33 0E 1C 2A 38 + 46 54 62 69 70 77 79 7B + 7D 7E 01 02 01 00 09 40 + 09 BE 19 FC 19 FA 19 F8 + 1A 38 1A 78 1A B6 2A B6 + 2A F4 2A F4 4B 34 63 74 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Sleep Out(11h) */ + 05 01 00 00 14 00 01 11 + /* TE ON */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* CASET/PASET Setting */ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 5F + /* FFC Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 F5 85 + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 C4 + 39 01 00 00 00 00 02 B0 04 + 39 01 00 00 00 00 06 F8 41 47 11 B8 B8 + 39 01 00 00 00 00 02 B0 02 + 39 01 00 00 00 00 02 F8 CC + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 F2 82 + 39 01 00 00 00 00 02 F5 87 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Fast Discharge */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 03 + 39 01 00 00 00 00 02 DD 40 + 39 01 00 00 6E 00 03 F0 A5 A5 + /* Dimming Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 06 + 39 01 00 00 00 00 02 B7 01 + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /* 90hz Transition */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + /* ACL Mode */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 55 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* SEED LP */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 03 F0 A5 A5 + /* OPEC Control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 E6 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Display On */ + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-off-command=[ + 05 01 00 00 0A 00 01 28 + 05 01 00 00 78 00 01 10 + ]; + qcom,mdss-dsi-panel-hbm-on-command-1 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 0C 7C + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 00 00 03 51 0A AA + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 14 00 03 51 01 D3 /* 800nit */ + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-brightness-on-command = [ + 15 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-brightness-off-command = [ + /* ELVSS Dim Setting */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 05 + 39 01 00 00 00 00 02 B7 13 /* 0x13 : ELVSS DIM OFF */ + 39 01 00 00 01 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 3F /* DLY OFF */ + 39 01 00 00 01 00 03 F0 A5 A5 + /* HBM Mode OFF */ + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 09 00 03 51 07 FF + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 09 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-serial-num-pre-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 37 01 00 00 05 00 02 10 00 + ]; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 00 + ]; + qcom,mdss-dsi-panel-code-info-command = [ + 06 01 00 00 00 00 01 DA 00 + ]; + qcom,mdss-dsi-panel-stage-info-command = [ + 06 01 00 00 00 00 01 DB 00 + ]; + qcom,mdss-dsi-panel-production-info-command = [ + 06 01 00 00 00 00 01 DC 00 + ]; + qcom,mdss-dsi-panel-serial-num-post-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-command = [ + ]; + qcom,mdss-dsi-loading-effect-enable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 83 56 37 /* 0x83 : OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-loading-effect-disable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 04 C8 A3 56 37 /* 0xA3 : ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-on-command-1 = [ + /* 10nit */ + 15 01 00 00 00 00 02 53 23 + ]; + qcom,mdss-dsi-panel-aod-on-command-2 = [ + ]; + qcom,mdss-dsi-panel-aod-on-command-3 = [ + /* 50nit */ + 15 01 00 00 00 00 02 53 22 + ]; + qcom,mdss-dsi-panel-aod-on-command-4 = [ + ]; + qcom,mdss-dsi-panel-aod-on-command-5 = [ + /* 50nit */ + 15 01 00 00 16 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 07 + 39 01 00 00 00 00 02 F4 5B + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 53 22 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + /* 90hz Transition */ + 15 01 00 00 16 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + /* 90hz Transition */ + 15 01 00 00 16 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + /* 90hz Transition */ + 15 01 00 00 16 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command = [ + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 13 /* 0x13 : DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 14 00 03 51 01 D3 /* 800nit */ + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + /* Aod Mode Off */ + 15 01 00 00 16 00 01 28 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 02 B0 32 + 39 01 00 00 00 00 02 D1 04 + 15 01 00 00 00 00 02 60 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 01 13 + 15 01 00 00 00 00 01 29 + /* HBM Mode ON */ + 39 01 00 00 00 00 02 53 E0 /* 0xE0 Normal transition */ + 39 01 00 00 16 00 03 51 01 D3 /* 800nit */ + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command = [ + /* HBM Mode OFF */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 53 20 /* 0x20 Normal transition */ + 39 01 00 00 00 00 03 F0 A5 A5 + /* Dimming Delay control */ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B7 01 37 /* DLY ON */ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-seed-command = [ + 39 01 00 00 00 00 03 81 31 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 16 B1 B2 09 02 36 D8 10 09 04 C6 40 E6 CD BC 0E C0 F0 EE 16 F6 FB F0 + 39 01 00 00 00 00 02 B1 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF FD F6 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 03 36 D8 0D 09 04 C6 40 E6 CD BC 0E C0 F4 EE 12 FF F8 E3 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 DF EC FF + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 04 36 D8 12 09 04 C6 40 E6 D8 BC 0E D4 F0 EE 16 FF FD F5 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF FD F6 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-low-backlight-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF F6 F1 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-srgb-color-mode-low-backlight-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 03 36 D8 0D 09 04 C6 40 E6 CD BC 0E C0 F4 EE 12 FF F0 DD + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-low-backlight-on-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 DF E3 FF + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-low-backlight-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 B2 09 04 36 D8 12 09 04 C6 40 E6 D8 BC 0E D4 F0 EE 16 FF F4 F2 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-low-backlight-enable-command = [ + 39 01 00 0A 00 00 03 81 31 00 + 39 01 00 0A 00 00 03 F0 5A 5A + 39 01 00 0A 00 00 02 B0 01 + 39 01 00 0A 00 00 16 B1 C2 00 00 0F D2 01 09 05 DB 1C F2 E7 EB 06 EB F2 E0 00 FF F6 F1 + 39 01 00 0A 00 00 02 B1 00 + 39 01 00 0A 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-read-register-ed-command = [ + 39 01 00 00 00 00 02 ED 97 + ]; + qcom,mdss-dsi-panel-id1-command = [ + 06 01 00 00 00 00 02 0A 00 + ]; + qcom,mdss-dsi-panel-id2-command = [ + 06 01 00 00 00 00 02 EE 00 + ]; + qcom,mdss-dsi-panel-id3-command = [ + 06 01 00 00 00 00 02 E5 00 + ]; + qcom,mdss-dsi-panel-id4-command = [ + 06 01 00 00 00 00 02 ED 00 + ]; + qcom,mdss-dsi-panel-check-info-command = [ + 06 01 00 00 00 00 02 D6 00 + ]; + + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-level2-key-enable-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + ]; + qcom,mdss-dsi-panel-level2-key-disable-command = [ + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-timing-switch-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-on-command-1-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-2-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-3-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-4-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-5-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-brightness-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-serial-num-pre-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-code-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-state-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-production-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-post-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-loading-effect-disable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-new-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-samsung-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-off-aod-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-aod-on-command-1-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-2-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-3-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-4-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-5-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-seed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-p3-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-srgb-low-backlight-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-p3-low-backlight-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-srgb-color-mode-low-backlight-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-p3-mode-low-backlight-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-wide-color-mode-low-backlight-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-ed-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id4-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-check-info-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-level2-key-disable-command-state = "dsi_lp_mode"; + qcom,panel-roi-alignment=<540 48 540 48 540 48>; + qcom,compression-mode = "dsc"; + qcom,lm-split = <540 540>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <48>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + }; + }; +}; + +&soc { + dsi_samsung_ams644vk04_dsc_cmd { + qcom,dsi-display-active; + }; +}; +&dsi_samsung_ams644vk04_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_samsung>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1D 07 07 23 22 07 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + }; + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 1D 07 07 23 22 07 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>,<2 2 1>; + qcom,default-topology-index = <1>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_sofef00_m_video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_sofef00_m_video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b31ab6cc07cb2d7e31974f711e4f1cf063ed2345 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-samsung_sofef00_m_video.dtsi @@ -0,0 +1,118 @@ +/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +&mdss_mdp { + dsi_samsung_sofef00_m_video: qcom,mdss_dsi_samsung_sofef00_m_video { + qcom,mdss-dsi-panel-name = + "samsung sofef00_m video mode dsi panel"; + qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-version = "SOFEF00_M"; + qcom,mdss-dsi-backlight-version = "SAMSUNG"; + qcom,mdss-dsi-backlight-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1b>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 0>, <0 0>, <1 0>; + qcom,panel-ack-disabled; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-default-val = <200>; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + qcom,mdss-dsi-init-delay-us = <1000>; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-bl-high2bit; + /* HDR Setting */ + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15635 16450 34000 16000 13250 34500 7500 3000>; + qcom,mdss-dsi-panel-average-brightness = <2000000>; + qcom,mdss-dsi-panel-blackness-level = <2000>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <640>; + qcom,mdss-dsi-panel-height = <480>; + qcom,mdss-dsi-h-front-porch = <8>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <6>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 00 00 00 00 00 00 00 00 00 00 00]; + qcom,mdss-dsi-on-command = + [32 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-off-command = + [22 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; +&dsi_samsung_sofef00_m_video { + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + //qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_samsung>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; +&soc { + dsi_samsung_sofef00_m_video { + qcom,dsi-display-active; + }; +}; +&dsi_samsung_sofef00_m_video { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-1080p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c78aa1c268ff97e5ce8222234ecf9463cb6113a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-1080p-cmd.dtsi @@ -0,0 +1,78 @@ +&mdss_mdp { + dsi_sharp_1080_cmd: qcom,mdss_dsi_sharp_1080p_cmd { + qcom,mdss-dsi-panel-name = "sharp 1080p cmd mode dsi panel"; + qcom,mdss-dsi-panel-controller = <&mdss_dsi0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-panel-destination = "display_1"; + qcom,mdss-dsi-panel-clockrate = <850000000>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <64>; + qcom,mdss-pan-physical-height-dimension = <117>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..08c6a928b60ad0f4044e80625b742e6572695050 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -0,0 +1,95 @@ +&mdss_mdp { + dsi_sharp_4k_dsc_cmd: qcom,mdss_dsi_sharp_4k_dsc_cmd { + qcom,mdss-dsi-panel-name = "Sharp 4k cmd mode dsc dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <129>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-tx-eot-append; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x8 0xa>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dsc-4k-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..54894686a0faf34ef33f778ddb76cc9790d8c7db --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dsc-4k-video.dtsi @@ -0,0 +1,88 @@ +&mdss_mdp { + dsi_sharp_4k_dsc_video: qcom,mdss_dsi_sharp_4k_dsc_video { + qcom,mdss-dsi-panel-name = "Sharp 4k video mode dsc dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 100>, <0 100>, <1 100>; + qcom,mdss-pan-physical-width-dimension = <71>; + qcom,mdss-pan-physical-height-dimension = <129>; + qcom,mdss-dsi-tx-eot-append; + + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 10 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c909864db377892dee53422882549ac1c0641982 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi @@ -0,0 +1,86 @@ +&mdss_mdp { + dsi_dual_sharp_wqhd_cmd: qcom,mdss_dsi_sharp_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "Dual Sharp WQHD cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,dcs-cmd-by-left; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <121>; + + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 + 20 00 20 02 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + 15 01 00 00 00 00 02 90 01 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c0 15 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualdsi-wqhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualdsi-wqhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..37330078b1ff25015c72e7163863ad3a4f7444c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualdsi-wqhd-video.dtsi @@ -0,0 +1,82 @@ +&mdss_mdp { + dsi_dual_sharp_wqhd_video: qcom,mdss_dsi_sharp_wqhd_video { + qcom,mdss-dsi-panel-name = + "Dual Sharp wqhd video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <121>; + + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 + 20 00 20 02 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 10 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + 15 01 00 00 00 00 02 90 01 + 15 01 00 00 00 00 02 03 00 + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c0 15 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + }; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..06a95cadbd586c0f6091c1881d5e5e0670f5e4e5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi @@ -0,0 +1,626 @@ +&mdss_mdp { + dsi_dual_sharp_1080_120hz_cmd: qcom,mdss_dual_sharp_1080p_120hz_cmd { + qcom,mdss-dsi-panel-name = + "sharp 1080p 120hz dual dsi cmd mode panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 1>, <1 10>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,cmd-sync-wait-trigger; + qcom,mdss-tear-check-frame-rate = <12000>; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 ba 07 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 d9 00 + 15 01 00 00 00 00 02 ef 70 + 15 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 06 3b 03 0e 0c 08 1c + 15 01 00 00 00 00 02 e9 0e + 15 01 00 00 00 00 02 ea 0c + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 59 6a + 15 01 00 00 00 00 02 0b 1b + 15 01 00 00 00 00 02 61 f7 + 15 01 00 00 00 00 02 62 6c + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 04 c8 + 15 01 00 00 00 00 02 05 1a + 15 01 00 00 00 00 02 0d 93 + 15 01 00 00 00 00 02 0e 93 + 15 01 00 00 00 00 02 0f 7e + 15 01 00 00 00 00 02 06 69 + 15 01 00 00 00 00 02 07 bc + 15 01 00 00 00 00 02 10 03 + 15 01 00 00 00 00 02 11 64 + 15 01 00 00 00 00 02 12 5a + 15 01 00 00 00 00 02 13 40 + 15 01 00 00 00 00 02 14 40 + 15 01 00 00 00 00 02 15 00 + 15 01 00 00 00 00 02 33 13 + 15 01 00 00 00 00 02 5a 40 + 15 01 00 00 00 00 02 5b 40 + 15 01 00 00 00 00 02 5e 80 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 80 + 15 01 00 00 00 00 02 14 80 + 15 01 00 00 00 00 02 01 80 + 15 01 00 00 00 00 02 15 80 + 15 01 00 00 00 00 02 02 80 + 15 01 00 00 00 00 02 16 80 + 15 01 00 00 00 00 02 03 0a + 15 01 00 00 00 00 02 17 0c + 15 01 00 00 00 00 02 04 06 + 15 01 00 00 00 00 02 18 08 + 15 01 00 00 00 00 02 05 80 + 15 01 00 00 00 00 02 19 80 + 15 01 00 00 00 00 02 06 80 + 15 01 00 00 00 00 02 1a 80 + 15 01 00 00 00 00 02 07 80 + 15 01 00 00 00 00 02 1b 80 + 15 01 00 00 00 00 02 08 80 + 15 01 00 00 00 00 02 1c 80 + 15 01 00 00 00 00 02 09 80 + 15 01 00 00 00 00 02 1d 80 + 15 01 00 00 00 00 02 0a 80 + 15 01 00 00 00 00 02 1e 80 + 15 01 00 00 00 00 02 0b 1a + 15 01 00 00 00 00 02 1f 1b + 15 01 00 00 00 00 02 0c 16 + 15 01 00 00 00 00 02 20 17 + 15 01 00 00 00 00 02 0d 1c + 15 01 00 00 00 00 02 21 1d + 15 01 00 00 00 00 02 0e 18 + 15 01 00 00 00 00 02 22 19 + 15 01 00 00 00 00 02 0f 0e + 15 01 00 00 00 00 02 23 10 + 15 01 00 00 00 00 02 10 80 + 15 01 00 00 00 00 02 24 80 + 15 01 00 00 00 00 02 11 80 + 15 01 00 00 00 00 02 25 80 + 15 01 00 00 00 00 02 12 80 + 15 01 00 00 00 00 02 26 80 + 15 01 00 00 00 00 02 13 80 + 15 01 00 00 00 00 02 27 80 + 15 01 00 00 00 00 02 74 ff + 15 01 00 00 00 00 02 75 ff + 15 01 00 00 00 00 02 8d 00 + 15 01 00 00 00 00 02 8e 00 + 15 01 00 00 00 00 02 8f 9c + 15 01 00 00 00 00 02 90 0c + 15 01 00 00 00 00 02 91 0e + 15 01 00 00 00 00 02 d6 00 + 15 01 00 00 00 00 02 d7 20 + 15 01 00 00 00 00 02 d8 00 + 15 01 00 00 00 00 02 d9 88 + 15 01 00 00 00 00 02 e5 05 + 15 01 00 00 00 00 02 e6 10 + 15 01 00 00 00 00 02 54 06 + 15 01 00 00 00 00 02 55 05 + 15 01 00 00 00 00 02 56 04 + 15 01 00 00 00 00 02 58 03 + 15 01 00 00 00 00 02 59 33 + 15 01 00 00 00 00 02 5a 33 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5d 01 + 15 01 00 00 00 00 02 5e 0a + 15 01 00 00 00 00 02 5f 0a + 15 01 00 00 00 00 02 60 0a + 15 01 00 00 00 00 02 61 0a + 15 01 00 00 00 00 02 62 10 + 15 01 00 00 00 00 02 63 01 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 65 00 + 15 01 00 00 00 00 02 ef 00 + 15 01 00 00 00 00 02 f0 00 + 15 01 00 00 00 00 02 6d 20 + 15 01 00 00 00 00 02 66 44 + 15 01 00 00 00 00 02 68 01 + 15 01 00 00 00 00 02 69 00 + 15 01 00 00 00 00 02 67 11 + 15 01 00 00 00 00 02 6a 06 + 15 01 00 00 00 00 02 6b 31 + 15 01 00 00 00 00 02 6c 90 + 15 01 00 00 00 00 02 ab c3 + 15 01 00 00 00 00 02 b1 49 + 15 01 00 00 00 00 02 aa 80 + 15 01 00 00 00 00 02 b0 90 + 15 01 00 00 00 00 02 b2 a4 + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 23 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 00 + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 00 + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba 00 + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc 00 + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be 00 + 15 01 00 00 00 00 02 bf 00 + 15 01 00 00 00 00 02 c0 00 + 15 01 00 00 00 00 02 c7 40 + 15 01 00 00 00 00 02 c9 00 + 15 01 00 00 00 00 02 c1 2a + 15 01 00 00 00 00 02 c2 2a + 15 01 00 00 00 00 02 c3 00 + 15 01 00 00 00 00 02 c4 00 + 15 01 00 00 00 00 02 c5 00 + 15 01 00 00 00 00 02 c6 00 + 15 01 00 00 00 00 02 c8 ab + 15 01 00 00 00 00 02 ca 00 + 15 01 00 00 00 00 02 cb 00 + 15 01 00 00 00 00 02 cc 20 + 15 01 00 00 00 00 02 cd 40 + 15 01 00 00 00 00 02 ce a8 + 15 01 00 00 00 00 02 cf a8 + 15 01 00 00 00 00 02 d0 00 + 15 01 00 00 00 00 02 d1 00 + 15 01 00 00 00 00 02 d2 00 + 15 01 00 00 00 00 02 d3 00 + 15 01 00 00 00 00 02 af 01 + 15 01 00 00 00 00 02 a4 1e + 15 01 00 00 00 00 02 95 41 + 15 01 00 00 00 00 02 96 03 + 15 01 00 00 00 00 02 98 00 + 15 01 00 00 00 00 02 9a 9a + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9d 80 + 15 01 00 00 00 00 02 ff 26 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 fa d0 + 15 01 00 00 00 00 02 6b 80 + 15 01 00 00 00 00 02 6c 5c + 15 01 00 00 00 00 02 6d 0c + 15 01 00 00 00 00 02 6e 0e + 15 01 00 00 00 00 02 58 01 + 15 01 00 00 00 00 02 59 15 + 15 01 00 00 00 00 02 5a 01 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 01 + 15 01 00 00 00 00 02 5d 2b + 15 01 00 00 00 00 02 74 00 + 15 01 00 00 00 00 02 75 ba + 15 01 00 00 00 00 02 81 0a + 15 01 00 00 00 00 02 4e 81 + 15 01 00 00 00 00 02 4f 83 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 53 4d + 15 01 00 00 00 00 02 54 03 + 15 01 00 00 00 00 02 ff e0 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 b2 81 + 15 01 00 00 00 00 02 62 28 + 15 01 00 00 00 00 02 a2 09 + 15 01 00 00 00 00 02 b3 01 + 15 01 00 00 00 00 02 ed 00 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 75 00 + 15 01 00 00 00 00 02 76 71 + 15 01 00 00 00 00 02 77 00 + 15 01 00 00 00 00 02 78 84 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 7a a5 + 15 01 00 00 00 00 02 7b 00 + 15 01 00 00 00 00 02 7c bb + 15 01 00 00 00 00 02 7d 00 + 15 01 00 00 00 00 02 7e ce + 15 01 00 00 00 00 02 7f 00 + 15 01 00 00 00 00 02 80 e0 + 15 01 00 00 00 00 02 81 00 + 15 01 00 00 00 00 02 82 ef + 15 01 00 00 00 00 02 83 00 + 15 01 00 00 00 00 02 84 ff + 15 01 00 00 00 00 02 85 01 + 15 01 00 00 00 00 02 86 0b + 15 01 00 00 00 00 02 87 01 + 15 01 00 00 00 00 02 88 38 + 15 01 00 00 00 00 02 89 01 + 15 01 00 00 00 00 02 8a 5b + 15 01 00 00 00 00 02 8b 01 + 15 01 00 00 00 00 02 8c 95 + 15 01 00 00 00 00 02 8d 01 + 15 01 00 00 00 00 02 8e c4 + 15 01 00 00 00 00 02 8f 02 + 15 01 00 00 00 00 02 90 0d + 15 01 00 00 00 00 02 91 02 + 15 01 00 00 00 00 02 92 4a + 15 01 00 00 00 00 02 93 02 + 15 01 00 00 00 00 02 94 4c + 15 01 00 00 00 00 02 95 02 + 15 01 00 00 00 00 02 96 85 + 15 01 00 00 00 00 02 97 02 + 15 01 00 00 00 00 02 98 c3 + 15 01 00 00 00 00 02 99 02 + 15 01 00 00 00 00 02 9a e9 + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9c 16 + 15 01 00 00 00 00 02 9d 03 + 15 01 00 00 00 00 02 9e 34 + 15 01 00 00 00 00 02 9f 03 + 15 01 00 00 00 00 02 a0 56 + 15 01 00 00 00 00 02 a2 03 + 15 01 00 00 00 00 02 a3 62 + 15 01 00 00 00 00 02 a4 03 + 15 01 00 00 00 00 02 a5 6c + 15 01 00 00 00 00 02 a6 03 + 15 01 00 00 00 00 02 a7 74 + 15 01 00 00 00 00 02 a9 03 + 15 01 00 00 00 00 02 aa 80 + 15 01 00 00 00 00 02 ab 03 + 15 01 00 00 00 00 02 ac 89 + 15 01 00 00 00 00 02 ad 03 + 15 01 00 00 00 00 02 ae 8b + 15 01 00 00 00 00 02 af 03 + 15 01 00 00 00 00 02 b0 8d + 15 01 00 00 00 00 02 b1 03 + 15 01 00 00 00 00 02 b2 8e + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 71 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 84 + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 a5 + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba bb + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc ce + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be e0 + 15 01 00 00 00 00 02 bf 00 + 15 01 00 00 00 00 02 c0 ef + 15 01 00 00 00 00 02 c1 00 + 15 01 00 00 00 00 02 c2 ff + 15 01 00 00 00 00 02 c3 01 + 15 01 00 00 00 00 02 c4 0b + 15 01 00 00 00 00 02 c5 01 + 15 01 00 00 00 00 02 c6 38 + 15 01 00 00 00 00 02 c7 01 + 15 01 00 00 00 00 02 c8 5b + 15 01 00 00 00 00 02 c9 01 + 15 01 00 00 00 00 02 ca 95 + 15 01 00 00 00 00 02 cb 01 + 15 01 00 00 00 00 02 cc c4 + 15 01 00 00 00 00 02 cd 02 + 15 01 00 00 00 00 02 ce 0d + 15 01 00 00 00 00 02 cf 02 + 15 01 00 00 00 00 02 d0 4a + 15 01 00 00 00 00 02 d1 02 + 15 01 00 00 00 00 02 d2 4c + 15 01 00 00 00 00 02 d3 02 + 15 01 00 00 00 00 02 d4 85 + 15 01 00 00 00 00 02 d5 02 + 15 01 00 00 00 00 02 d6 c3 + 15 01 00 00 00 00 02 d7 02 + 15 01 00 00 00 00 02 d8 e9 + 15 01 00 00 00 00 02 d9 03 + 15 01 00 00 00 00 02 da 16 + 15 01 00 00 00 00 02 db 03 + 15 01 00 00 00 00 02 dc 34 + 15 01 00 00 00 00 02 dd 03 + 15 01 00 00 00 00 02 de 56 + 15 01 00 00 00 00 02 df 03 + 15 01 00 00 00 00 02 e0 62 + 15 01 00 00 00 00 02 e1 03 + 15 01 00 00 00 00 02 e2 6c + 15 01 00 00 00 00 02 e3 03 + 15 01 00 00 00 00 02 e4 74 + 15 01 00 00 00 00 02 e5 03 + 15 01 00 00 00 00 02 e6 80 + 15 01 00 00 00 00 02 e7 03 + 15 01 00 00 00 00 02 e8 89 + 15 01 00 00 00 00 02 e9 03 + 15 01 00 00 00 00 02 ea 8b + 15 01 00 00 00 00 02 eb 03 + 15 01 00 00 00 00 02 ec 8d + 15 01 00 00 00 00 02 ed 03 + 15 01 00 00 00 00 02 ee 8e + 15 01 00 00 00 00 02 ef 00 + 15 01 00 00 00 00 02 f0 71 + 15 01 00 00 00 00 02 f1 00 + 15 01 00 00 00 00 02 f2 84 + 15 01 00 00 00 00 02 f3 00 + 15 01 00 00 00 00 02 f4 a5 + 15 01 00 00 00 00 02 f5 00 + 15 01 00 00 00 00 02 f6 bb + 15 01 00 00 00 00 02 f7 00 + 15 01 00 00 00 00 02 f8 ce + 15 01 00 00 00 00 02 f9 00 + 15 01 00 00 00 00 02 fa e0 + 15 01 00 00 00 00 02 ff 21 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 00 + 15 01 00 00 00 00 02 01 ef + 15 01 00 00 00 00 02 02 00 + 15 01 00 00 00 00 02 03 ff + 15 01 00 00 00 00 02 04 01 + 15 01 00 00 00 00 02 05 0b + 15 01 00 00 00 00 02 06 01 + 15 01 00 00 00 00 02 07 38 + 15 01 00 00 00 00 02 08 01 + 15 01 00 00 00 00 02 09 5b + 15 01 00 00 00 00 02 0a 01 + 15 01 00 00 00 00 02 0b 95 + 15 01 00 00 00 00 02 0c 01 + 15 01 00 00 00 00 02 0d c4 + 15 01 00 00 00 00 02 0e 02 + 15 01 00 00 00 00 02 0f 0d + 15 01 00 00 00 00 02 10 02 + 15 01 00 00 00 00 02 11 4a + 15 01 00 00 00 00 02 12 02 + 15 01 00 00 00 00 02 13 4c + 15 01 00 00 00 00 02 14 02 + 15 01 00 00 00 00 02 15 85 + 15 01 00 00 00 00 02 16 02 + 15 01 00 00 00 00 02 17 c3 + 15 01 00 00 00 00 02 18 02 + 15 01 00 00 00 00 02 19 e9 + 15 01 00 00 00 00 02 1a 03 + 15 01 00 00 00 00 02 1b 16 + 15 01 00 00 00 00 02 1c 03 + 15 01 00 00 00 00 02 1d 34 + 15 01 00 00 00 00 02 1e 03 + 15 01 00 00 00 00 02 1f 56 + 15 01 00 00 00 00 02 20 03 + 15 01 00 00 00 00 02 21 62 + 15 01 00 00 00 00 02 22 03 + 15 01 00 00 00 00 02 23 6c + 15 01 00 00 00 00 02 24 03 + 15 01 00 00 00 00 02 25 74 + 15 01 00 00 00 00 02 26 03 + 15 01 00 00 00 00 02 27 80 + 15 01 00 00 00 00 02 28 03 + 15 01 00 00 00 00 02 29 89 + 15 01 00 00 00 00 02 2a 03 + 15 01 00 00 00 00 02 2b 8b + 15 01 00 00 00 00 02 2d 03 + 15 01 00 00 00 00 02 2f 8d + 15 01 00 00 00 00 02 30 03 + 15 01 00 00 00 00 02 31 8e + 15 01 00 00 00 00 02 32 00 + 15 01 00 00 00 00 02 33 71 + 15 01 00 00 00 00 02 34 00 + 15 01 00 00 00 00 02 35 84 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 37 a5 + 15 01 00 00 00 00 02 38 00 + 15 01 00 00 00 00 02 39 bb + 15 01 00 00 00 00 02 3a 00 + 15 01 00 00 00 00 02 3b ce + 15 01 00 00 00 00 02 3d 00 + 15 01 00 00 00 00 02 3f e0 + 15 01 00 00 00 00 02 40 00 + 15 01 00 00 00 00 02 41 ef + 15 01 00 00 00 00 02 42 00 + 15 01 00 00 00 00 02 43 ff + 15 01 00 00 00 00 02 44 01 + 15 01 00 00 00 00 02 45 0b + 15 01 00 00 00 00 02 46 01 + 15 01 00 00 00 00 02 47 38 + 15 01 00 00 00 00 02 48 01 + 15 01 00 00 00 00 02 49 5b + 15 01 00 00 00 00 02 4a 01 + 15 01 00 00 00 00 02 4b 95 + 15 01 00 00 00 00 02 4c 01 + 15 01 00 00 00 00 02 4d c4 + 15 01 00 00 00 00 02 4e 02 + 15 01 00 00 00 00 02 4f 0d + 15 01 00 00 00 00 02 50 02 + 15 01 00 00 00 00 02 51 4a + 15 01 00 00 00 00 02 52 02 + 15 01 00 00 00 00 02 53 4c + 15 01 00 00 00 00 02 54 02 + 15 01 00 00 00 00 02 55 85 + 15 01 00 00 00 00 02 56 02 + 15 01 00 00 00 00 02 58 c3 + 15 01 00 00 00 00 02 59 02 + 15 01 00 00 00 00 02 5a e9 + 15 01 00 00 00 00 02 5b 03 + 15 01 00 00 00 00 02 5c 16 + 15 01 00 00 00 00 02 5d 03 + 15 01 00 00 00 00 02 5e 34 + 15 01 00 00 00 00 02 5f 03 + 15 01 00 00 00 00 02 60 56 + 15 01 00 00 00 00 02 61 03 + 15 01 00 00 00 00 02 62 62 + 15 01 00 00 00 00 02 63 03 + 15 01 00 00 00 00 02 64 6c + 15 01 00 00 00 00 02 65 03 + 15 01 00 00 00 00 02 66 74 + 15 01 00 00 00 00 02 67 03 + 15 01 00 00 00 00 02 68 80 + 15 01 00 00 00 00 02 69 03 + 15 01 00 00 00 00 02 6a 89 + 15 01 00 00 00 00 02 6b 03 + 15 01 00 00 00 00 02 6c 8b + 15 01 00 00 00 00 02 6d 03 + 15 01 00 00 00 00 02 6e 8d + 15 01 00 00 00 00 02 6f 03 + 15 01 00 00 00 00 02 70 8e + 15 01 00 00 00 00 02 71 00 + 15 01 00 00 00 00 02 72 71 + 15 01 00 00 00 00 02 73 00 + 15 01 00 00 00 00 02 74 84 + 15 01 00 00 00 00 02 75 00 + 15 01 00 00 00 00 02 76 a5 + 15 01 00 00 00 00 02 77 00 + 15 01 00 00 00 00 02 78 bb + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 7a ce + 15 01 00 00 00 00 02 7b 00 + 15 01 00 00 00 00 02 7c e0 + 15 01 00 00 00 00 02 7d 00 + 15 01 00 00 00 00 02 7e ef + 15 01 00 00 00 00 02 7f 00 + 15 01 00 00 00 00 02 80 ff + 15 01 00 00 00 00 02 81 01 + 15 01 00 00 00 00 02 82 0b + 15 01 00 00 00 00 02 83 01 + 15 01 00 00 00 00 02 84 38 + 15 01 00 00 00 00 02 85 01 + 15 01 00 00 00 00 02 86 5b + 15 01 00 00 00 00 02 87 01 + 15 01 00 00 00 00 02 88 95 + 15 01 00 00 00 00 02 89 01 + 15 01 00 00 00 00 02 8a c4 + 15 01 00 00 00 00 02 8b 02 + 15 01 00 00 00 00 02 8c 0d + 15 01 00 00 00 00 02 8d 02 + 15 01 00 00 00 00 02 8e 4a + 15 01 00 00 00 00 02 8f 02 + 15 01 00 00 00 00 02 90 4c + 15 01 00 00 00 00 02 91 02 + 15 01 00 00 00 00 02 92 85 + 15 01 00 00 00 00 02 93 02 + 15 01 00 00 00 00 02 94 c3 + 15 01 00 00 00 00 02 95 02 + 15 01 00 00 00 00 02 96 e9 + 15 01 00 00 00 00 02 97 03 + 15 01 00 00 00 00 02 98 16 + 15 01 00 00 00 00 02 99 03 + 15 01 00 00 00 00 02 9a 34 + 15 01 00 00 00 00 02 9b 03 + 15 01 00 00 00 00 02 9c 56 + 15 01 00 00 00 00 02 9d 03 + 15 01 00 00 00 00 02 9e 62 + 15 01 00 00 00 00 02 9f 03 + 15 01 00 00 00 00 02 a0 6c + 15 01 00 00 00 00 02 a2 03 + 15 01 00 00 00 00 02 a3 74 + 15 01 00 00 00 00 02 a4 03 + 15 01 00 00 00 00 02 a5 80 + 15 01 00 00 00 00 02 a6 03 + 15 01 00 00 00 00 02 a7 89 + 15 01 00 00 00 00 02 a9 03 + 15 01 00 00 00 00 02 aa 8b + 15 01 00 00 00 00 02 ab 03 + 15 01 00 00 00 00 02 ac 8d + 15 01 00 00 00 00 02 ad 03 + 15 01 00 00 00 00 02 ae 8e + 15 01 00 00 00 00 02 af 00 + 15 01 00 00 00 00 02 b0 71 + 15 01 00 00 00 00 02 b1 00 + 15 01 00 00 00 00 02 b2 84 + 15 01 00 00 00 00 02 b3 00 + 15 01 00 00 00 00 02 b4 a5 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 bb + 15 01 00 00 00 00 02 b7 00 + 15 01 00 00 00 00 02 b8 ce + 15 01 00 00 00 00 02 b9 00 + 15 01 00 00 00 00 02 ba e0 + 15 01 00 00 00 00 02 bb 00 + 15 01 00 00 00 00 02 bc ef + 15 01 00 00 00 00 02 bd 00 + 15 01 00 00 00 00 02 be ff + 15 01 00 00 00 00 02 bf 01 + 15 01 00 00 00 00 02 c0 0b + 15 01 00 00 00 00 02 c1 01 + 15 01 00 00 00 00 02 c2 38 + 15 01 00 00 00 00 02 c3 01 + 15 01 00 00 00 00 02 c4 5b + 15 01 00 00 00 00 02 c5 01 + 15 01 00 00 00 00 02 c6 95 + 15 01 00 00 00 00 02 c7 01 + 15 01 00 00 00 00 02 c8 c4 + 15 01 00 00 00 00 02 c9 02 + 15 01 00 00 00 00 02 ca 0d + 15 01 00 00 00 00 02 cb 02 + 15 01 00 00 00 00 02 cc 4a + 15 01 00 00 00 00 02 cd 02 + 15 01 00 00 00 00 02 ce 4c + 15 01 00 00 00 00 02 cf 02 + 15 01 00 00 00 00 02 d0 85 + 15 01 00 00 00 00 02 d1 02 + 15 01 00 00 00 00 02 d2 c3 + 15 01 00 00 00 00 02 d3 02 + 15 01 00 00 00 00 02 d4 e9 + 15 01 00 00 00 00 02 d5 03 + 15 01 00 00 00 00 02 d6 16 + 15 01 00 00 00 00 02 d7 03 + 15 01 00 00 00 00 02 d8 34 + 15 01 00 00 00 00 02 d9 03 + 15 01 00 00 00 00 02 da 56 + 15 01 00 00 00 00 02 db 03 + 15 01 00 00 00 00 02 dc 62 + 15 01 00 00 00 00 02 dd 03 + 15 01 00 00 00 00 02 de 6c + 15 01 00 00 00 00 02 df 03 + 15 01 00 00 00 00 02 e0 74 + 15 01 00 00 00 00 02 e1 03 + 15 01 00 00 00 00 02 e2 80 + 15 01 00 00 00 00 02 e3 03 + 15 01 00 00 00 00 02 e4 89 + 15 01 00 00 00 00 02 e5 03 + 15 01 00 00 00 00 02 e6 8b + 15 01 00 00 00 00 02 e7 03 + 15 01 00 00 00 00 02 e8 8d + 15 01 00 00 00 00 02 e9 03 + 15 01 00 00 00 00 02 ea 8e + 15 01 00 00 00 00 02 FF 10 + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-off-command = + [15 01 00 00 00 00 02 ff 10 + 05 01 00 00 10 00 01 28 + 15 01 00 00 00 00 02 b0 00 + 05 01 00 00 40 00 01 10 + 15 01 00 00 00 00 02 4f 01]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualmipi-wqxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d0fafd5e638325b432e5174dc43d3e4efa99108e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-dualmipi-wqxga-video.dtsi @@ -0,0 +1,71 @@ +&mdss_mdp { + dsi_dual_sharp_video: qcom,mdss_dsi_sharp_wqxga_video { + qcom,mdss-dsi-panel-name = "Dual SHARP video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <800>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <76>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <11>; + qcom,mdss-dsi-v-front-porch = <2>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [05 01 00 00 a0 00 02 11 00 + 05 01 00 00 02 00 02 29 00]; + qcom,mdss-dsi-pre-off-command = [05 01 00 00 02 00 02 28 00 + 05 01 00 00 a0 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 6a 28 38 2a 03 + 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2a>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <50>; + qcom,mdss-dsi-bl-pmic-bank-select = <2>; + qcom,mdss-dsi-reset-sequence = <1 2>, <0 5>, <1 120>; + qcom,mdss-pan-physical-width-dimension = <83>; + qcom,mdss-pan-physical-height-dimension = <133>; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-panel-status-check-mode = "bta_check"; + qcom,mdss-dsi-tx-eot-append; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14880 15935 32435 + 16555 14945 30910 7790 3415>; + qcom,mdss-dsi-panel-peak-brightness = <5643000>; + qcom,mdss-dsi-panel-blackness-level = <6134>; + qcom,config-select = <&dsi_dual_sharp_video_config0>; + + dsi_dual_sharp_video_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + dsi_dual_sharp_video_config1: config1 { + qcom,split-mode = "pingpong-split"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fae031cdfaa14a5a7bc3dcb66494f23603975185 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-cmd.dtsi @@ -0,0 +1,361 @@ +&mdss_mdp { + dsi_sharp_qsync_fhd_cmd: qcom,mdss_dsi_sharp_qsync_fhd_cmd { + qcom,mdss-dsi-panel-name = "Sharp fhd cmd mode qsync dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-panel-mode-switch; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <134>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-schedule-line = <5>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15000 16000 33750 + 15800 13250 34450 7500 3000>; + qcom,mdss-dsi-panel-peak-brightness = <6450000>; + qcom,mdss-dsi-panel-blackness-level = <4961>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 02 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..185f32603582b9a2f9057c33cbe9ffc8647e30a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-fhd-video.dtsi @@ -0,0 +1,119 @@ +&mdss_mdp { + dsi_sharp_qsync_fhd_video: qcom,mdss_dsi_sharp_qsync_fhd_video { + qcom,mdss-dsi-panel-name = + "Sharp fhd video mode qsync dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <134>; + qcom,mdss-dsi-tx-eot-append; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15000 16000 33750 + 15800 13250 34450 7500 3000>; + qcom,mdss-dsi-panel-peak-brightness = <6450000>; + qcom,mdss-dsi-panel-blackness-level = <4961>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <124>; + qcom,mdss-dsi-h-back-porch = <20>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <1968>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 03 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 05 be 00 10 00 10 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..215b3ab46dded259df1a3e7a252b21ebb50cb478 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-wqhd-cmd.dtsi @@ -0,0 +1,921 @@ +&mdss_mdp { + dsi_sharp_qsync_wqhd_cmd: qcom,mdss_dsi_sharp_qsync_wqhd_cmd { + qcom,mdss-dsi-panel-name = "Sharp 2k cmd mode qsync dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-panel-mode-switch; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <134>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-dma-schedule-line = <5>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15000 16000 33750 + 15800 13250 34450 7500 3000>; + qcom,mdss-dsi-panel-peak-brightness = <6450000>; + qcom,mdss-dsi-panel-blackness-level = <4961>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 00 00 01 28 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,cmd-to-video-mode-post-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 bb 13 + 39 00 00 00 00 00 02 ff 26 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 06 + ]; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <2608>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 03 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 05 be 00 10 00 10 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,video-to-cmd-mode-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 bb 10 + ]; + qcom,video-to-cmd-mode-post-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 bb 10 + 39 00 00 00 00 00 02 ff 26 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + ]; + qcom,video-to-cmd-mode-switch-commands-state = + "dsi_lp_mode"; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 00 00 01 28 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@3 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 02 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 00 00 01 28 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@4 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 03 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 00 00 01 28 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,cmd-to-video-mode-post-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 bb 13 + 39 00 00 00 00 00 02 ff 26 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 06 + ]; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@5 { + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 03 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 05 be 00 10 00 10 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,video-to-cmd-mode-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 bb 10 + ]; + qcom,video-to-cmd-mode-post-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 bb 10 + 39 00 00 00 00 00 02 ff 26 + 39 00 00 00 00 00 02 fb 01 + 39 00 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + ]; + qcom,video-to-cmd-mode-switch-commands-state = + "dsi_lp_mode"; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@6 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 00 00 01 28 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@7 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 02 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 00 00 01 28 + 05 01 00 00 00 00 01 29 + ]; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-wqhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-wqhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0268ded1a74ccc1d575e0988ef369fd87c7a2054 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sharp-qsync-wqhd-video.dtsi @@ -0,0 +1,120 @@ +&mdss_mdp { + dsi_sharp_qsync_wqhd_video: qcom,mdss_dsi_sharp_qsync_wqhd_video { + qcom,mdss-dsi-panel-name = + "Sharp 2k video mode qsync dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <74>; + qcom,mdss-pan-physical-height-dimension = <134>; + qcom,mdss-dsi-tx-eot-append; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <15000 16000 33750 + 15800 13250 34450 7500 3000>; + qcom,mdss-dsi-panel-peak-brightness = <6450000>; + qcom,mdss-dsi-panel-blackness-level = <4961>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <2608>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 03 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 83 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 68 00 d5 00 0a 0d b7 09 89 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 03 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 05 be 00 10 00 10 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b0748f8d04a19d3717ed9c39b2f701ac57b5efc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-cmd.dtsi @@ -0,0 +1,346 @@ +&mdss_mdp { + dsi_sim_cmd: qcom,mdss_dsi_sim_cmd { + qcom,mdss-dsi-panel-name = "Simulator cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-t-clk-post = <0x03>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,cmd-to-video-mode-switch-commands = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 39 01 00 00 00 00 06 b2 00 5d 04 80 49 + 15 01 00 00 00 00 02 3d 10 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 55 0c + ]; + qcom,cmd-to-video-mode-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,video-to-cmd-mode-switch-commands = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 39 01 00 00 00 00 06 b2 00 5d 04 80 49 + 15 01 00 00 00 00 02 3d 11 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 55 0b + ]; + qcom,video-to-cmd-mode-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <100>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@3 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <460>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <740>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@4 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <840>; + qcom,mdss-dsi-h-pulse-width = <40>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <100>; + qcom,mdss-dsi-v-front-porch = <1380>; + qcom,mdss-dsi-v-pulse-width = <40>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 21 09 09 24 23 08 08 08 03 04 00]; + qcom,mdss-dsi-on-command = + [29 01 00 00 00 00 02 b0 03 + 05 01 00 00 0a 00 01 00 + /* Soft reset, wait 10ms */ + 15 01 00 00 0a 00 02 3a 77 + /* Set Pixel format (24 bpp) */ + 39 01 00 00 0a 00 05 2a 00 00 04 ff + /* Set Column address */ + 39 01 00 00 0a 00 05 2b 00 00 05 9f + /* Set page address */ + 15 01 00 00 0a 00 02 35 00 + /* Set tear on */ + 39 01 00 00 0a 00 03 44 00 00 + /* Set tear scan line */ + 15 01 00 00 0a 00 02 51 ff + /* write display brightness */ + 15 01 00 00 0a 00 02 53 24 + /* write control brightness */ + 15 01 00 00 0a 00 02 55 00 + /* CABC brightness */ + 05 01 00 00 78 00 01 11 + /* exit sleep mode, wait 120ms */ + 05 01 00 00 10 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <40>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dsc-10bit-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dsc-10bit-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..edb09ed0db4e3fa76fa830693e3155d7eecd8f15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dsc-10bit-cmd.dtsi @@ -0,0 +1,473 @@ +&mdss_mdp { + dsi_sim_dsc_10b_cmd: qcom,mdss_dsi_sim_dsc_10b_cmd { + qcom,mdss-dsi-panel-name = + "Simulator cmd mode DSC3:1 10bit dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <30>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <10>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <10>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <10>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dsc375-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ce0faca6452a5bb90c44f2987201e9c407c33120 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dsc375-cmd.dtsi @@ -0,0 +1,325 @@ +&mdss_mdp { + dsi_sim_dsc_375_cmd: qcom,mdss_dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-panel-name = + "Simulator cmd mode DSC 3.75:1 dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1e + 15 01 00 00 00 00 02 0b 73 + 15 01 00 00 00 00 02 0c 73 + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f aE + 15 01 00 00 00 00 02 11 b8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5a 00 + 15 01 00 00 00 00 02 5b 01 + 15 01 00 00 00 00 02 5c 80 + 15 01 00 00 00 00 02 5d 81 + 15 01 00 00 00 00 02 5e 00 + 15 01 00 00 00 00 02 5f 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1c + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0f + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8a + 15 01 00 00 00 00 02 0a 13 + 15 01 00 00 00 00 02 0b 13 + 15 01 00 00 00 00 02 0c 15 + 15 01 00 00 00 00 02 0d 15 + 15 01 00 00 00 00 02 0e 17 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 1c + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0f + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8a + 15 01 00 00 00 00 02 1a 13 + 15 01 00 00 00 00 02 1b 13 + 15 01 00 00 00 00 02 1c 15 + 15 01 00 00 00 00 02 1d 15 + 15 01 00 00 00 00 02 1e 17 + 15 01 00 00 00 00 02 1f 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 e0 00 + 15 01 00 00 00 00 02 dc 21 + 15 01 00 00 00 00 02 dd 22 + 15 01 00 00 00 00 02 de 07 + 15 01 00 00 00 00 02 df 07 + 15 01 00 00 00 00 02 e3 6d + 15 01 00 00 00 00 02 e1 07 + 15 01 00 00 00 00 02 e2 07 + /* UD */ + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + /* CLK */ + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 7f 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0a + 15 01 00 00 00 00 02 94 0a + /* Inversion Type */ + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b ff + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9d b0 + 15 01 00 00 00 00 02 9f 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 ec 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VESA DSC PPS settings + * (1440x2560 slide 16H) + */ + 39 01 00 00 00 00 11 c1 09 + 20 00 10 02 00 02 68 01 bb + 00 0a 06 67 04 c5 + + 39 01 00 00 00 00 03 c2 10 f0 + /* C0h = 0x0(2 Port SDC) + * 0x01(1 PortA FBC) + * 0x02(MTK) 0x03(1 PortA VESA) + */ + 15 01 00 00 00 00 02 c0 03 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3b 03 0a 0a + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 e5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 bb 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 fb 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <0>; + qcom,mdss-dsi-h-back-porch = <0>; + qcom,mdss-dsi-h-pulse-width = <0>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <0>; + qcom,mdss-dsi-v-front-porch = <0>; + qcom,mdss-dsi-v-pulse-width = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <144>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 b0 03 + 05 01 00 00 78 00 01 11 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 24 + 15 01 00 00 00 00 02 ff 23 + 15 01 00 00 00 00 02 08 05 + 15 01 00 00 00 00 02 46 90 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 ff f0 + 15 01 00 00 00 00 02 92 01 + 15 01 00 00 00 00 02 ff 10 + /* enable TE generation */ + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 28 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 10 00 01 28 + 05 01 00 00 40 00 01 10]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6407ef2d75b2172a8001cd04831ba27c043ef83c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-cmd.dtsi @@ -0,0 +1,140 @@ +&mdss_mdp { + dsi_dual_sim_cmd: qcom,mdss_dsi_dual_sim_cmd { + qcom,mdss-dsi-panel-name = "Sim dual cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-hor-line-idle = <0 40 256>, + <40 120 128>, + <120 240 64>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + qcom,mdss-dsi-qsync-min-refresh-rate = <45>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <28>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + /* Set display on, wait 16ms */ + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <40>; + qcom,mdss-dsi-on-command = + [/* exit sleep mode, wait 0ms */ + 05 01 00 00 00 00 01 29]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 00 00 02 28 00 + 05 01 00 00 00 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ef10fbdcec1206da760e1a686f01b309d6e66e65 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi @@ -0,0 +1,1490 @@ +&mdss_mdp { + dsi_dual_sim_dsc_375_cmd: qcom,mdss_dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-panel-name = + "Sim dual cmd mode DSC 3.75:1 dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-hor-line-idle = <0 40 256>, + <40 120 128>, + <120 240 64>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-using-te-pin; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <30>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <90>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@3 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <3840>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <1080>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@4 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <30>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@5 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@6 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <90>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@7 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@8 { + qcom,mdss-dsi-panel-framerate = <30>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@9 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@10 { + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@11 { + qcom,mdss-dsi-panel-framerate = <120>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 00 00 02 FF 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 05 40 + 15 01 00 00 00 00 02 06 19 + 15 01 00 00 00 00 02 07 1E + 15 01 00 00 00 00 02 0B 73 + 15 01 00 00 00 00 02 0C 73 + 15 01 00 00 00 00 02 0E B0 + 15 01 00 00 00 00 02 0F AE + 15 01 00 00 00 00 02 11 B8 + 15 01 00 00 00 00 02 13 00 + 15 01 00 00 00 00 02 58 80 + 15 01 00 00 00 00 02 59 01 + 15 01 00 00 00 00 02 5A 00 + 15 01 00 00 00 00 02 5B 01 + 15 01 00 00 00 00 02 5C 80 + 15 01 00 00 00 00 02 5D 81 + 15 01 00 00 00 00 02 5E 00 + 15 01 00 00 00 00 02 5F 01 + 15 01 00 00 00 00 02 72 31 + 15 01 00 00 00 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 1C + 15 01 00 00 00 00 02 01 0B + 15 01 00 00 00 00 02 02 0C + 15 01 00 00 00 00 02 03 01 + 15 01 00 00 00 00 02 04 0F + 15 01 00 00 00 00 02 05 10 + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 89 + 15 01 00 00 00 00 02 09 8A + 15 01 00 00 00 00 02 0A 13 + 15 01 00 00 00 00 02 0B 13 + 15 01 00 00 00 00 02 0C 15 + 15 01 00 00 00 00 02 0D 15 + 15 01 00 00 00 00 02 0E 17 + 15 01 00 00 00 00 02 0F 17 + 15 01 00 00 00 00 02 10 1C + 15 01 00 00 00 00 02 11 0B + 15 01 00 00 00 00 02 12 0C + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 0F + 15 01 00 00 00 00 02 15 10 + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 89 + 15 01 00 00 00 00 02 19 8A + 15 01 00 00 00 00 02 1A 13 + 15 01 00 00 00 00 02 1B 13 + 15 01 00 00 00 00 02 1C 15 + 15 01 00 00 00 00 02 1D 15 + 15 01 00 00 00 00 02 1E 17 + 15 01 00 00 00 00 02 1F 17 + /* STV */ + 15 01 00 00 00 00 02 20 40 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6D + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + /* Vend */ + 15 01 00 00 00 00 02 E0 00 + 15 01 00 00 00 00 02 DC 21 + 15 01 00 00 00 00 02 DD 22 + 15 01 00 00 00 00 02 DE 07 + 15 01 00 00 00 00 02 DF 07 + 15 01 00 00 00 00 02 E3 6D + 15 01 00 00 00 00 02 E1 07 + 15 01 00 00 00 00 02 E2 07 + /* UD */ + 15 01 00 00 00 00 02 29 D8 + 15 01 00 00 00 00 02 2A 2A + /* CLK */ + 15 01 00 00 00 00 02 4B 03 + 15 01 00 00 00 00 02 4C 11 + 15 01 00 00 00 00 02 4D 10 + 15 01 00 00 00 00 02 4E 01 + 15 01 00 00 00 00 02 4F 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 00 00 02 5B 43 + 15 01 00 00 00 00 02 5C 00 + 15 01 00 00 00 00 02 5F 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 00 00 02 72 02 + /* mux */ + 15 01 00 00 00 00 02 7A 80 + 15 01 00 00 00 00 02 7B 91 + 15 01 00 00 00 00 02 7C D8 + 15 01 00 00 00 00 02 7D 60 + 15 01 00 00 00 00 02 7F 15 + 15 01 00 00 00 00 02 75 15 + /* ABOFF */ + 15 01 00 00 00 00 02 B3 C0 + 15 01 00 00 00 00 02 B4 00 + 15 01 00 00 00 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 00 00 02 78 00 + 15 01 00 00 00 00 02 79 00 + 15 01 00 00 00 00 02 80 00 + 15 01 00 00 00 00 02 83 00 + /* FP BP */ + 15 01 00 00 00 00 02 93 0A + 15 01 00 00 00 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 00 00 02 8A 00 + 15 01 00 00 00 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 00 00 02 9D B0 + 15 01 00 00 00 00 02 9F 63 + 15 01 00 00 00 00 02 98 10 + /* FRM */ + 15 01 00 00 00 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 00 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 00 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 00 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 00 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 00 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 00 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@12 { + qcom,mdss-dsi-panel-width = <2520>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <1080>; + qcom,mdss-dsc-slice-width = <1260>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@13 { + qcom,mdss-dsi-panel-width = <360>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <30>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@14 { + qcom,mdss-dsi-panel-width = <360>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@15 { + qcom,mdss-dsi-panel-width = <360>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <90>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@16 { + qcom,mdss-dsi-panel-width = <360>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <120>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <10>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@17 { + qcom,mdss-dsi-panel-width = <540>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <30>; + qcom,mdss-dsi-h-back-porch = <100>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <144>; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 11 91 09 20 00 20 02 + 00 03 1c 04 21 00 + 0f 03 19 01 97 + 39 01 00 00 00 00 03 92 10 f0 + 15 01 00 00 00 00 02 90 03 + 15 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 04 + 15 01 00 00 00 00 02 c0 03 + 39 01 00 00 00 00 06 f0 55 aa 52 08 07 + 15 01 00 00 00 00 02 ef 01 + 39 01 00 00 00 00 06 f0 55 aa 52 08 00 + 15 01 00 00 00 00 02 b4 01 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 05 ff aa 55 a5 80 + 15 01 00 00 00 00 02 6f 01 + 15 01 00 00 00 00 02 f3 10 + 39 01 00 00 00 00 05 ff aa 55 a5 00 + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <32>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9121f2cb87507497f7e33ef17dd5b1ecd6d76fa1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-dualmipi-video.dtsi @@ -0,0 +1,62 @@ +&mdss_mdp { + dsi_dual_sim_vid: qcom,mdss_dsi_dual_sim_video { + qcom,mdss-dsi-panel-name = "Sim dual video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-panel-broadcast-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 200>, <1 20>; + qcom,panel-ack-disabled; + qcom,mdss-dsi-qsync-min-refresh-rate = <45>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1280>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <44>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = + [05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_hs_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 51 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-sec-hd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-sec-hd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..973dc517711c88ee1d2d3c30b587b14125a2aa0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-sec-hd-cmd.dtsi @@ -0,0 +1,67 @@ +&mdss_mdp { + dsi_sim_sec_hd_cmd: qcom,mdss_dsi_sim_sec_hd_cmd { + qcom,mdss-dsi-panel-name = + "sim hd command mode secondary dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-sec-ctrl-num = <1>; + qcom,dsi-sec-phy-num = <1>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,panel-ack-disabled; + qcom,mdss-dsi-te-using-wd; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + + qcom,mdss-dsi-on-command = [ + /* sleep out + delay 120ms */ + 05 01 00 00 78 00 01 11 + /* display on + delay 120ms */ + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f5a522b0748ef20f0689deb3431eee74b86d9a34 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sim-video.dtsi @@ -0,0 +1,61 @@ +&mdss_mdp { + dsi_sim_vid: qcom,mdss_dsi_sim_video { + qcom,mdss-dsi-panel-name = "Simulator video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1b>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 0>, <0 0>, <1 0>; + qcom,panel-ack-disabled; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <640>; + qcom,mdss-dsi-panel-height = <480>; + qcom,mdss-dsi-h-front-porch = <8>; + qcom,mdss-dsi-h-back-porch = <8>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <6>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-timings = + [00 00 00 00 00 00 00 00 00 00 00 00]; + qcom,mdss-dsi-on-command = + [32 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-off-command = + [22 01 00 00 00 00 02 00 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4d77525decb679c45d3f8845cd83adb109dd9eef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi @@ -0,0 +1,102 @@ +&mdss_mdp { + dsi_sw43404_amoled_fhd_plus_cmd: qcom,mdss_dsi_sw43404_fhd_plus_cmd { + qcom,mdss-dsi-panel-name = + "sw43404 amoled boe fhd+ panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <138>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <160>; + qcom,mdss-dsi-h-back-porch = <72>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 08 70 04 38 02 1c 02 1c 02 1c 02 00 + 02 0e 00 20 34 29 00 07 00 0C 00 2e + 00 31 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 5e 10 + 39 01 00 00 00 00 06 b9 bf 11 40 00 30 + 39 01 00 00 00 00 09 F8 00 08 10 08 2D + 00 00 2D + 15 01 00 00 00 00 02 55 08 + 05 01 00 00 1e 00 02 11 00 + 15 01 00 00 78 00 02 3d 01 + 39 01 00 00 00 00 03 b0 a5 00 + 05 01 00 00 78 00 02 35 00 + 05 01 00 00 3c 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <270>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1c08e1931f81d5b6f063db4b2ff657b8a728e815 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi @@ -0,0 +1,311 @@ +&mdss_mdp { + dsi_sw43404_amoled_cmd: qcom,mdss_dsi_sw43404_amoled_wqhd_cmd { + qcom,mdss-dsi-panel-name = + "sw43404 amoled cmd mode dsi boe panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-qsync-min-refresh-rate = <55>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2880>; + qcom,mdss-dsi-h-front-porch = <60>; + qcom,mdss-dsi-h-back-porch = <30>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x6 0x1>; + qcom,mdss-mdp-transfer-time-us = <15300>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 42 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + ]; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 03 5c 42 00 + 07 01 00 00 00 00 02 01 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 0B 40 05 A0 05 A0 02 D0 02 D0 02 00 + 02 68 00 20 9A DB 00 0A 00 0C 00 12 + 00 0E 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 09 F8 00 08 10 08 2D + 00 00 2D + 15 01 00 00 00 00 02 55 08 + 05 01 00 00 1e 00 02 11 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 + 05 01 00 00 78 00 02 35 00 + 05 01 00 00 3c 00 02 29 00 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 5a 01]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 5a 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <180>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@1 { + qcom,mdss-dsi-panel-framerate = <50>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2880>; + qcom,mdss-dsi-h-front-porch = <60>; + qcom,mdss-dsi-h-back-porch = <30>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 4f 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + ]; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 03 5c 42 00 + 07 01 00 00 00 00 02 01 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 0B 40 05 A0 05 A0 02 D0 02 D0 02 00 + 02 68 00 20 9A DB 00 0A 00 0C 00 12 + 00 0E 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 09 F8 00 08 10 08 2D + 00 00 2D + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 1e 00 02 11 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 + 05 01 00 00 78 00 02 35 00 + 05 01 00 00 3c 00 02 29 00 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 4f 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 4f 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 5a 01]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 5a 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <180>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + + timing@2 { + qcom,mdss-dsi-panel-framerate = <40>; + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2880>; + qcom,mdss-dsi-h-front-porch = <60>; + qcom,mdss-dsi-h-back-porch = <30>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + + qcom,mdss-dsi-timing-switch-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 63 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + ]; + + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 03 5c 42 00 + 07 01 00 00 00 00 02 01 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 0B 40 05 A0 05 A0 02 D0 02 D0 02 00 + 02 68 00 20 9A DB 00 0A 00 0C 00 12 + 00 0E 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 09 F8 00 08 10 08 2D + 00 00 2D + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 1e 00 02 11 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 + 05 01 00 00 78 00 02 35 00 + 05 01 00 00 3c 00 02 29 00 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 4f 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + 39 01 00 00 00 00 03 b0 a5 00 + 39 01 00 00 00 00 0c b1 a0 9f 63 4f 63 0e 0a 10 0e 0a 10 + 39 01 00 00 00 00 07 e4 30 06 00 40 34 03 + ]; + + qcom,mdss-dsi-off-command = [ + 05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-qsync-on-commands = + [15 01 00 00 00 00 02 5a 01]; + qcom,mdss-dsi-qsync-on-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-qsync-off-commands = + [15 01 00 00 00 00 02 5a 00]; + qcom,mdss-dsi-qsync-off-commands-state = + "dsi_lp_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <180>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ecac0d4bfc655cf028370fedc2502ffc5e5ca739 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi @@ -0,0 +1,100 @@ +&mdss_mdp { + dsi_sw43404_amoled_video: qcom,mdss_dsi_sw43404_amoled_wqhd_video { + qcom,mdss-dsi-panel-name = + "sw43404 amoled video mode dsi boe panel with DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-physical-type = "oled"; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <2880>; + qcom,mdss-dsi-h-front-porch = <10>; + qcom,mdss-dsi-h-back-porch = <10>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 b0 a5 00 + 07 01 00 00 00 00 02 01 00 + 39 01 00 00 00 00 06 b2 00 5d 04 80 49 + 15 01 00 00 00 00 02 3d 10 + 15 01 00 00 00 00 02 36 00 + 15 01 00 00 00 00 02 55 08 + 39 01 00 00 00 00 09 f8 00 08 10 08 2d + 00 00 2d + 39 01 00 00 3c 00 03 51 00 00 + 05 01 00 00 50 00 02 11 00 + 39 01 00 00 00 00 03 b0 34 04 + 39 01 00 00 00 00 05 c1 00 00 00 46 + 39 01 00 00 00 00 03 b0 a5 00 + 0a 01 00 00 00 00 80 11 00 00 89 30 80 + 0B 40 05 A0 02 d0 02 D0 02 D0 02 00 + 02 68 00 20 4e a8 00 0A 00 0C 00 23 + 00 1c 18 00 10 F0 03 0C 20 00 06 0B + 0B 33 0E 1C 2A 38 46 54 62 69 70 77 + 79 7B 7D 7E 01 02 01 00 09 40 09 BE + 19 FC 19 FA 19 F8 1A 38 1A 78 1A B6 + 2A F6 2B 34 2B 74 3B 74 6B F4 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 39 01 00 00 00 00 03 b0 a5 00 + 15 01 00 00 00 00 02 e0 18 + 39 01 00 00 00 00 0c c0 00 53 6f 51 50 + 51 34 4f 5a 33 19 + 05 01 00 00 78 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 + 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-lp1-command = [ + 05 01 00 00 00 00 02 39 00 + ]; + qcom,mdss-dsi-lp1-command-state = + "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 00 00 02 38 00 + ]; + qcom,mdss-dsi-nolp-command-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <180>; + qcom,mdss-dsc-slice-width = <720>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4328-1080p-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4328-1080p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..476c34c01d34f0ffac8d21f66071ae5d2ea62a8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4328-1080p-cmd.dtsi @@ -0,0 +1,169 @@ +&mdss_mdp { + dsi_td4328_truly_cmd: qcom,mdss_dsi_td4328_truly_cmd { + qcom,mdss-dsi-panel-name = + "td4328 cmd mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 00 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E C7 C7 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 2B + 02 2B + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 50 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 29 01 00 00 00 00 02 B0 00 + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4328-1080p-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4328-1080p-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e9b7bac3450458b20c1148acee6cf9b443a9c86b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4328-1080p-video.dtsi @@ -0,0 +1,164 @@ +&mdss_mdp { + dsi_td4328_truly_video: qcom,mdss_dsi_td4328_truly_video { + qcom,mdss-dsi-panel-name = + "td4328 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "src_byte_clk0", "src_pixel_clk0"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <70>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <10>; + qcom,mdss-dsi-v-front-porch = <5>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 04 B3 31 00 06 + 29 01 00 00 00 00 02 B4 00 + 29 01 00 00 00 00 06 B6 33 DB 80 12 00 + 29 01 00 00 00 00 08 B8 57 3D 19 1E 0A + 50 50 + 29 01 00 00 00 00 08 B9 6F 3D 28 3C 14 + C8 C8 + 29 01 00 00 00 00 08 BA B5 33 41 64 23 + A0 A0 + 29 01 00 00 00 00 03 BB 14 14 + 29 01 00 00 00 00 03 BC 37 32 + 29 01 00 00 00 00 03 BD 64 32 + 29 01 00 00 00 00 02 BE 04 + 29 01 00 00 00 00 02 C0 00 + 29 01 00 00 00 00 2E C1 04 48 00 00 26 + 15 19 0B 63 D2 D9 9A 73 EF BD E7 5C + 6B 93 4D 22 18 8B 2A 41 00 00 00 00 + 00 00 00 00 00 40 02 22 1B 06 03 00 + 07 FF 00 01 + 29 01 00 00 00 00 18 C2 01 F8 70 08 68 + 08 0C 10 00 08 30 00 00 00 00 00 00 + 20 02 43 00 00 00 + 29 01 00 00 00 00 3F C3 87 D8 7D 87 D0 + 00 00 00 00 00 00 04 3A 00 00 00 04 + 44 00 00 01 01 03 28 00 01 00 01 00 + 00 19 00 0C 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 32 00 19 00 5A + 02 32 00 19 00 5A 02 40 00 + 29 01 00 00 00 00 15 C4 70 00 00 00 11 + 11 00 00 00 02 02 31 01 00 00 00 02 + 01 01 01 + 29 01 00 00 00 00 08 C5 08 00 00 00 00 + 70 00 + 29 01 00 00 00 00 40 C6 5B 2D 2D 07 54 + 07 54 01 02 01 02 07 07 00 00 07 07 + 0F 11 07 5B 00 5B 5B C2 C2 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 27 C7 01 1D 2E 41 4F + 5A 71 80 8B 95 45 4F 5C 71 7B 88 98 + A6 BE 01 1D 2E 41 4F 5A 71 80 8B 95 + 45 4F 5C 71 7B 88 98 A6 BE + 29 01 00 00 00 00 38 C8 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 14 C9 00 00 00 00 00 + FC 00 00 00 00 00 FC 00 00 00 00 00 + FC 00 + 29 01 00 00 00 00 2C CA 1C FC FC FC 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 1C CB FF FF FF FF 0F + 00 08 00 01 00 31 F0 40 08 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CC 02 + 29 01 00 00 00 00 27 CD 10 80 37 C0 1A + 00 5C 02 19 90 11 88 D8 6C D8 6C 01 + 00 00 00 32 00 32 00 5D 02 32 32 01 + 33 00 33 00 5E 02 32 32 AF + 29 01 00 00 00 00 1A CE 5D 40 49 53 59 + 5E 63 68 6E 74 7E 8A 98 A8 BB D0 FF + 04 00 04 04 42 00 69 5A + 29 01 00 00 00 00 03 CF 4A 1D + 29 01 00 00 00 00 12 D0 33 57 D4 31 01 + 10 10 10 19 19 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 D1 00 + 29 01 00 00 00 00 20 D2 10 00 00 10 75 + 0F 03 25 20 00 00 00 00 00 00 00 00 + 04 00 00 00 00 00 00 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 17 D3 1B 3B BB 77 77 + 77 BB B3 33 00 00 6D 6E DB DB 33 BB + F2 FD C6 0B 07 + 29 01 00 00 00 00 08 D4 00 00 00 00 00 + 00 00 + 29 01 00 00 00 00 08 D5 03 00 00 02 40 + 02 40 + 29 01 00 00 00 00 02 D6 01 + 29 01 00 00 00 00 22 D7 F6 FF 03 05 41 + 24 80 1F C7 1F 1B 00 0C 07 20 00 00 + 00 00 00 0C 00 1F 00 FC 00 00 AA 67 + 7E 5D 06 00 + 29 01 00 00 00 00 03 D9 20 14 + 29 01 00 00 00 00 05 DD 30 06 23 65 + 29 01 00 00 00 00 05 DE 00 3F FF 90 + 29 01 00 00 00 00 06 E7 00 00 00 46 61 + 29 01 00 00 00 00 02 EA 1F + 29 01 00 00 00 00 04 EE 41 51 00 + 29 01 00 00 00 00 03 F1 00 00 + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 08 6F + 39 01 00 00 00 00 01 2C + 39 01 00 00 00 00 02 51 FF + 39 01 00 00 00 00 02 53 0C + 39 01 00 00 00 00 02 55 00 + 05 01 00 00 96 00 01 11 + 05 01 00 00 32 00 01 29]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4330-truly-v2-singlemipi-fhd-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4330-truly-v2-singlemipi-fhd-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..49fdd7440a62b0dbff55136aff76dc2f7391a2dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4330-truly-v2-singlemipi-fhd-cmd.dtsi @@ -0,0 +1,562 @@ +&mdss_mdp { + dsi_td4330_truly_v2_cmd: qcom,mdss_dsi_td4330_truly_v2_cmd { + qcom,mdss-dsi-panel-name = + "td4330 v2 cmd mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <80>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <13>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 + B0 00 + 29 01 00 00 00 00 0D + B6 30 6B 00 06 03 0A 13 1A 6C + 18 19 02 + 29 01 00 00 00 00 05 + B7 40 00 00 00 + 29 01 00 00 00 00 08 + B8 57 3D 19 BE 1E 0A 0A + 29 01 00 00 00 00 08 + B9 6F 3D 28 BE 3C 14 0A + 29 01 00 00 00 00 08 + BA B5 33 41 BE 64 23 0A + 29 01 00 00 00 00 0C + BB 44 26 C3 1F 19 06 03 C0 00 + 00 10 + 29 01 00 00 00 00 0C + BC 32 4C C3 52 32 1F 03 F2 00 + 00 13 + 29 01 00 00 00 00 0C + BD 24 68 C3 AA 3F 32 03 FF 00 + 00 25 + 29 01 00 00 00 00 0D + BE 00 00 00 00 00 00 00 00 00 + 00 00 00 + 29 01 00 00 00 00 0D + C0 00 DC 00 DC 04 08 E8 00 04 + 00 03 78 + 29 01 00 00 00 00 24 + C1 30 00 00 11 11 00 00 00 22 + 00 05 20 FA 00 08 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 79 + C2 06 E0 6E 01 03 00 02 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 11 00 00 00 00 04 A0 C9 + 00 00 00 00 00 00 48 EB 00 00 + 01 00 00 00 11 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 11 00 00 00 00 + 00 00 DC 00 00 00 00 04 00 08 + EF 00 00 00 00 00 11 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 6D + C3 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 AA AA AA 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 62 + C4 00 4C 00 3F 00 83 00 00 87 + 86 85 84 00 00 00 00 00 61 5D + 5F 00 5E 60 62 00 00 00 02 00 + 83 00 00 87 86 85 84 00 00 00 + 00 00 61 5D 5F 00 5E 60 62 FF + FF FF FF FF FF 00 0F 0E 00 0F + 0E 00 00 00 00 00 00 00 0F EE + 00 0F EE 00 00 E0 00 00 E0 0E + 00 00 00 0E 00 00 00 00 00 FF + 57 00 00 00 00 00 00 00 + 29 01 00 00 00 00 06 + C5 08 00 00 00 00 + 29 01 00 00 00 00 3A + C6 02 0A 08 FC FF FF FF 00 00 + 13 01 F0 0C 06 01 43 43 43 00 + 00 00 01 77 09 28 28 06 01 43 + 43 43 00 00 00 01 61 00 00 00 + 1C 01 00 00 00 00 00 00 00 00 + 00 00 00 00 20 20 00 00 + 29 01 00 00 00 00 4D + C7 00 00 00 E0 01 E9 02 7E 02 + 05 02 90 02 F6 02 40 02 5C 02 + 77 02 C8 02 1B 02 5B 02 BD 02 + 27 02 C3 03 54 03 D8 03 FF 00 + 00 00 E0 01 E9 02 7E 02 05 02 + 90 02 F6 02 40 02 5C 02 77 02 + C8 02 1B 02 5B 02 BD 02 27 02 + C3 03 54 03 D8 03 FF + 29 01 00 00 00 00 42 + C8 41 00 FF FA 00 FF 00 00 FE + F6 FE E9 00 00 FF F7 FB E1 00 + 00 00 00 00 FF 00 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF + 29 01 00 00 00 00 19 + C9 00 FF FA 00 FF 00 00 FE F6 + FE E9 00 00 FF F7 FB E1 00 00 + 00 00 00 FF 00 + 29 01 00 00 00 00 42 + CA 1C FC FC FC 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + CC 00 00 4D 8B 55 4D 8B AA 4D + 8B + 29 01 00 00 00 00 02 + CD 00 + 29 01 00 00 00 00 24 + CE 5D 40 49 53 59 5E 63 68 6E + 74 7E 8A 98 A8 BB D0 E7 FF 04 + 00 04 04 42 04 69 5A 40 11 F4 + 00 00 84 FA 00 00 + 29 01 00 00 00 00 07 + CF 00 00 80 46 61 00 + 29 01 00 00 00 00 12 + D0 F6 95 11 B1 55 CF 00 F6 D3 + 11 F0 01 12 CF 02 20 11 + 29 01 00 00 00 00 23 + D1 D3 D3 33 33 07 03 3B 33 77 + 37 77 37 35 77 07 77 F7 33 73 + 07 33 33 03 33 1B 03 32 3D 0A + 30 13 13 20 00 + 29 01 00 00 00 00 05 + D2 00 00 07 00 + 29 01 00 00 00 00 9A + D3 03 00 00 00 00 00 00 0F 00 + 57 00 00 32 00 00 1A 70 01 19 + 80 01 01 F0 02 00 E0 06 FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF + 29 01 00 00 00 00 05 + E5 03 00 00 00 + 29 01 00 00 00 00 09 + D5 02 42 02 42 02 DC 02 DC + 29 01 00 00 00 00 02 + D6 C0 + 29 01 00 00 00 00 32 + D7 21 10 52 52 00 B6 04 FD 00 + B6 04 FD 00 82 80 83 84 85 83 + 80 84 45 85 85 85 87 04 06 02 + 04 04 07 10 0C 0B 0A 0A 07 06 + 00 08 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 05 + DD 30 06 23 65 + 29 01 00 00 00 00 0D + DE 00 00 00 0F FF 00 00 00 00 + 00 00 10 + 29 01 00 00 00 00 02 + E3 FF + 29 01 00 00 00 00 07 + E6 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + E7 50 04 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 05 + E8 00 01 23 00 + 29 01 00 00 00 00 1E + EA 01 02 47 80 47 00 00 00 05 + 00 13 60 02 47 80 47 00 00 00 + 00 13 60 00 11 00 30 10 21 02 + 29 01 00 00 00 00 08 + EB 00 00 00 00 01 00 11 + 29 01 00 00 00 00 04 + EC 00 00 00 + 29 01 00 00 00 00 21 + ED 01 01 02 02 02 02 00 00 00 + 00 00 00 0A 00 00 00 00 10 00 + 18 00 18 00 B0 00 00 00 00 00 + DA 10 00 + 29 01 00 00 00 00 61 + EE 03 0F 00 00 00 00 40 1F 00 + 00 0F F2 3F 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 10 + 01 00 09 01 8C D8 EF 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 50 1F 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 + 29 01 00 00 00 00 8C + EF 00 70 4A 08 D0 00 00 00 00 + 3C 3C 3C 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 70 + 4A 08 D0 00 00 00 00 3C 3C 3C + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 03 08 EC 50 10 00 10 + 00 0A 0A 00 00 00 00 10 0F 00 + 03 51 00 50 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 03 08 EC + 29 01 00 00 00 00 02 + B0 03 + 29 01 00 00 00 00 02 + B0 04 + 29 01 00 00 00 00 02 + D6 00 + 39 01 00 00 00 00 03 + 51 FF F0 + 39 01 00 00 00 00 02 + 53 0C + 39 01 00 00 00 00 02 + 55 00 + 39 01 00 00 00 00 02 + 35 00 + 39 01 00 00 00 00 05 + 2A 00 00 04 37 + 39 01 00 00 00 00 05 + 2B 00 00 08 E7 + 05 01 00 00 FF 00 02 + 29 00 + 05 01 00 00 FF 00 02 + 11 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,video-to-cmd-mode-post-switch-commands = [ + 15 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 05 B7 40 00 00 00]; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + }; + + timing@1 { + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <40>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 + B0 00 + 29 01 00 00 00 00 0D + B6 30 6B 00 06 03 0A 13 1A 6C + 18 19 02 + 29 01 00 00 00 00 05 + B7 51 00 00 00 + 29 01 00 00 00 00 08 + B8 57 3D 19 BE 1E 0A 0A + 29 01 00 00 00 00 08 + B9 6F 3D 28 BE 3C 14 0A + 29 01 00 00 00 00 08 + BA B5 33 41 BE 64 23 0A + 29 01 00 00 00 00 0C + BB 44 26 C3 1F 19 06 03 C0 00 + 00 10 + 29 01 00 00 00 00 0C + BC 32 4C C3 52 32 1F 03 F2 00 + 00 13 + 29 01 00 00 00 00 0C + BD 24 68 C3 AA 3F 32 03 FF 00 + 00 25 + 29 01 00 00 00 00 0D + BE 00 00 00 00 00 00 00 00 00 + 00 00 00 + 29 01 00 00 00 00 0D + C0 00 DC 00 DC 04 08 E8 00 04 + 00 03 78 + 29 01 00 00 00 00 24 + C1 30 00 00 11 11 00 00 00 22 + 00 05 20 FA 00 08 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 79 + C2 06 E0 6E 01 03 00 02 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 11 00 00 00 00 04 A0 C9 + 00 00 00 00 00 00 48 EB 00 00 + 01 00 00 00 11 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 11 00 00 00 00 + 00 00 DC 00 00 00 00 04 00 08 + EF 00 00 00 00 00 11 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 6D + C3 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 AA AA AA 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 62 + C4 00 4C 00 3F 00 83 00 00 87 + 86 85 84 00 00 00 00 00 61 5D + 5F 00 5E 60 62 00 00 00 02 00 + 83 00 00 87 86 85 84 00 00 00 + 00 00 61 5D 5F 00 5E 60 62 FF + FF FF FF FF FF 00 0F 0E 00 0F + 0E 00 00 00 00 00 00 00 0F EE + 00 0F EE 00 00 E0 00 00 E0 0E + 00 00 00 0E 00 00 00 00 00 FF + 57 00 00 00 00 00 00 00 + 29 01 00 00 00 00 06 + C5 08 00 00 00 00 + 29 01 00 00 00 00 3A + C6 02 0A 08 FC FF FF FF 00 00 + 13 01 F0 0C 06 01 43 43 43 00 + 00 00 01 77 09 28 28 06 01 43 + 43 43 00 00 00 01 61 00 00 00 + 1C 01 00 00 00 00 00 00 00 00 + 00 00 00 00 20 20 00 00 + 29 01 00 00 00 00 4D + C7 00 00 00 E0 01 E9 02 7E 02 + 05 02 90 02 F6 02 40 02 5C 02 + 77 02 C8 02 1B 02 5B 02 BD 02 + 27 02 C3 03 54 03 D8 03 FF 00 + 00 00 E0 01 E9 02 7E 02 05 02 + 90 02 F6 02 40 02 5C 02 77 02 + C8 02 1B 02 5B 02 BD 02 27 02 + C3 03 54 03 D8 03 FF + 29 01 00 00 00 00 42 + C8 41 00 FF FA 00 FF 00 00 FE + F6 FE E9 00 00 FF F7 FB E1 00 + 00 00 00 00 FF 00 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF + 29 01 00 00 00 00 19 + C9 00 FF FA 00 FF 00 00 FE F6 + FE E9 00 00 FF F7 FB E1 00 00 + 00 00 00 FF 00 + 29 01 00 00 00 00 42 + CA 1C FC FC FC 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + CC 00 00 4D 8B 55 4D 8B AA 4D + 8B + 29 01 00 00 00 00 02 + CD 00 + 29 01 00 00 00 00 24 + CE 5D 40 49 53 59 5E 63 68 6E + 74 7E 8A 98 A8 BB D0 E7 FF 04 + 00 04 04 42 04 69 5A 40 11 F4 + 00 00 84 FA 00 00 + 29 01 00 00 00 00 07 + CF 00 00 80 46 61 00 + 29 01 00 00 00 00 12 + D0 F6 95 11 B1 55 CF 00 F6 D3 + 11 F0 01 12 CF 02 20 11 + 29 01 00 00 00 00 23 + D1 D3 D3 33 33 07 03 3B 33 77 + 37 77 37 35 77 07 77 F7 33 73 + 07 33 33 03 33 1B 03 32 3D 0A + 30 13 13 20 00 + 29 01 00 00 00 00 05 + D2 00 00 07 00 + 29 01 00 00 00 00 9A + D3 03 00 00 00 00 00 00 0F 00 + 57 00 00 32 00 00 1A 70 01 19 + 80 01 01 F0 02 00 E0 06 FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF + 29 01 00 00 00 00 05 + E5 03 00 00 00 + 29 01 00 00 00 00 09 + D5 02 42 02 42 02 DC 02 DC + 29 01 00 00 00 00 02 + D6 C0 + 29 01 00 00 00 00 32 + D7 21 10 52 52 00 B6 04 FD 00 + B6 04 FD 00 82 80 83 84 85 83 + 80 84 45 85 85 85 87 04 06 02 + 04 04 07 10 0C 0B 0A 0A 07 06 + 00 08 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 05 + DD 30 06 23 65 + 29 01 00 00 00 00 0D + DE 00 00 00 0F FF 00 00 00 00 + 00 00 10 + 29 01 00 00 00 00 02 + E3 FF + 29 01 00 00 00 00 07 + E6 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + E7 50 04 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 05 + E8 00 01 23 00 + 29 01 00 00 00 00 1E + EA 01 02 47 80 47 00 00 00 05 + 00 12 60 02 47 80 47 00 00 00 + 00 13 60 00 11 00 30 10 21 02 + 29 01 00 00 00 00 08 + EB 00 00 00 00 01 00 11 + 29 01 00 00 00 00 04 + EC 00 00 00 + 29 01 00 00 00 00 21 + ED 01 01 02 02 02 02 00 00 00 + 00 00 00 0A 00 00 00 00 10 00 + 18 00 18 00 B0 00 00 00 00 00 + DA 10 00 + 29 01 00 00 00 00 61 + EE 03 0F 00 00 00 00 40 1F 00 + 00 0F F2 3F 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 10 + 01 00 09 01 8C D8 EF 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 50 1F 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 + 29 01 00 00 00 00 8C + EF 00 70 4A 08 D0 00 00 00 00 + 3C 3C 3C 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 70 + 4A 08 D0 00 00 00 00 3C 3C 3C + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 03 08 EC 50 10 00 10 + 00 0A 0A 00 00 00 00 10 0F 00 + 03 51 00 50 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 03 08 EC + 29 01 00 00 00 00 02 + B0 03 + 29 01 00 00 00 00 02 + B0 04 + 29 01 00 00 00 00 02 + D6 00 + 39 01 00 00 00 00 03 + 51 FF F0 + 39 01 00 00 00 00 02 + 53 0C + 39 01 00 00 00 00 02 + 55 00 + 39 01 00 00 00 00 02 + 35 00 + 39 01 00 00 00 00 05 + 2A 00 00 04 37 + 39 01 00 00 00 00 05 + 2B 00 00 08 E7 + 05 01 00 00 FF 00 02 + 29 00 + 05 01 00 00 FF 00 02 + 11 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,cmd-to-video-mode-post-switch-commands = [ + 15 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 05 B7 51 00 00 00]; + qcom,cmd-to-video-mode-post-switch-commands-state = + "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4330-truly-v2-singlemipi-fhd-vid.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4330-truly-v2-singlemipi-fhd-vid.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b3500c424d6801cd66070a641291b7937dc002ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-td4330-truly-v2-singlemipi-fhd-vid.dtsi @@ -0,0 +1,567 @@ +&mdss_mdp { + dsi_td4330_truly_v2_video: qcom,mdss_dsi_td4330_truly_v2_video { + qcom,mdss-dsi-panel-name = + "td4330 v2 video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <65>; + qcom,mdss-pan-physical-height-dimension = <129>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <40>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <6>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 + B0 00 + 29 01 00 00 00 00 0D + B6 30 6B 00 06 03 0A 13 1A 6C + 18 19 02 + 29 01 00 00 00 00 05 + B7 51 00 00 00 + 29 01 00 00 00 00 08 + B8 57 3D 19 BE 1E 0A 0A + 29 01 00 00 00 00 08 + B9 6F 3D 28 BE 3C 14 0A + 29 01 00 00 00 00 08 + BA B5 33 41 BE 64 23 0A + 29 01 00 00 00 00 0C + BB 44 26 C3 1F 19 06 03 C0 00 + 00 10 + 29 01 00 00 00 00 0C + BC 32 4C C3 52 32 1F 03 F2 00 + 00 13 + 29 01 00 00 00 00 0C + BD 24 68 C3 AA 3F 32 03 FF 00 + 00 25 + 29 01 00 00 00 00 0D + BE 00 00 00 00 00 00 00 00 00 + 00 00 00 + 29 01 00 00 00 00 0D + C0 00 DC 00 DC 04 08 E8 00 04 + 00 03 78 + 29 01 00 00 00 00 24 + C1 30 00 00 11 11 00 00 00 22 + 00 05 20 FA 00 08 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 79 + C2 06 E0 6E 01 03 00 02 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 11 00 00 00 00 04 A0 C9 + 00 00 00 00 00 00 48 EB 00 00 + 01 00 00 00 11 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 11 00 00 00 00 + 00 00 DC 00 00 00 00 04 00 08 + EF 00 00 00 00 00 11 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 6D + C3 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 AA AA AA 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 62 + C4 00 4C 00 3F 00 83 00 00 87 + 86 85 84 00 00 00 00 00 61 5D + 5F 00 5E 60 62 00 00 00 02 00 + 83 00 00 87 86 85 84 00 00 00 + 00 00 61 5D 5F 00 5E 60 62 FF + FF FF FF FF FF 00 0F 0E 00 0F + 0E 00 00 00 00 00 00 00 0F EE + 00 0F EE 00 00 E0 00 00 E0 0E + 00 00 00 0E 00 00 00 00 00 FF + 57 00 00 00 00 00 00 00 + 29 01 00 00 00 00 06 + C5 08 00 00 00 00 + 29 01 00 00 00 00 3A + C6 02 0A 08 FC FF FF FF 00 00 + 13 01 F0 0C 06 01 43 43 43 00 + 00 00 01 77 09 28 28 06 01 43 + 43 43 00 00 00 01 61 00 00 00 + 1C 01 00 00 00 00 00 00 00 00 + 00 00 00 00 20 20 00 00 + 29 01 00 00 00 00 4D + C7 00 00 00 E0 01 E9 02 7E 02 + 05 02 90 02 F6 02 40 02 5C 02 + 77 02 C8 02 1B 02 5B 02 BD 02 + 27 02 C3 03 54 03 D8 03 FF 00 + 00 00 E0 01 E9 02 7E 02 05 02 + 90 02 F6 02 40 02 5C 02 77 02 + C8 02 1B 02 5B 02 BD 02 27 02 + C3 03 54 03 D8 03 FF + 29 01 00 00 00 00 42 + C8 41 00 FF FA 00 FF 00 00 FE + F6 FE E9 00 00 FF F7 FB E1 00 + 00 00 00 00 FF 00 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF + 29 01 00 00 00 00 19 + C9 00 FF FA 00 FF 00 00 FE F6 + FE E9 00 00 FF F7 FB E1 00 00 + 00 00 00 FF 00 + 29 01 00 00 00 00 42 + CA 1C FC FC FC 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + CC 00 00 4D 8B 55 4D 8B AA 4D + 8B + 29 01 00 00 00 00 02 + CD 00 + 29 01 00 00 00 00 24 + CE 5D 40 49 53 59 5E 63 68 6E + 74 7E 8A 98 A8 BB D0 E7 FF 04 + 00 04 04 42 04 69 5A 40 11 F4 + 00 00 84 FA 00 00 + 29 01 00 00 00 00 07 + CF 00 00 80 46 61 00 + 29 01 00 00 00 00 12 + D0 F6 95 11 B1 55 CF 00 F6 D3 + 11 F0 01 12 CF 02 20 11 + 29 01 00 00 00 00 23 + D1 D3 D3 33 33 07 03 3B 33 77 + 37 77 37 35 77 07 77 F7 33 73 + 07 33 33 03 33 1B 03 32 3D 0A + 30 13 13 20 00 + 29 01 00 00 00 00 05 + D2 00 00 07 00 + 29 01 00 00 00 00 9A + D3 03 00 00 00 00 00 00 0F 00 + 57 00 00 32 00 00 1A 70 01 19 + 80 01 01 F0 02 00 E0 06 FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF + 29 01 00 00 00 00 05 + E5 03 00 00 00 + 29 01 00 00 00 00 09 + D5 02 42 02 42 02 DC 02 DC + 29 01 00 00 00 00 02 + D6 C0 + 29 01 00 00 00 00 32 + D7 21 10 52 52 00 B6 04 FD 00 + B6 04 FD 00 82 80 83 84 85 83 + 80 84 45 85 85 85 87 04 06 02 + 04 04 07 10 0C 0B 0A 0A 07 06 + 00 08 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 05 + DD 30 06 23 65 + 29 01 00 00 00 00 0D + DE 00 00 00 0F FF 00 00 00 00 + 00 00 10 + 29 01 00 00 00 00 02 + E3 FF + 29 01 00 00 00 00 07 + E6 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + E7 50 04 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 05 + E8 00 01 23 00 + 29 01 00 00 00 00 1E + EA 01 02 47 80 47 00 00 00 05 + 00 12 60 02 47 80 47 00 00 00 + 00 13 60 00 11 00 30 10 21 02 + 29 01 00 00 00 00 08 + EB 00 00 00 00 01 00 11 + 29 01 00 00 00 00 04 + EC 00 00 00 + 29 01 00 00 00 00 21 + ED 01 01 02 02 02 02 00 00 00 + 00 00 00 0A 00 00 00 00 10 00 + 18 00 18 00 B0 00 00 00 00 00 + DA 10 00 + 29 01 00 00 00 00 61 + EE 03 0F 00 00 00 00 40 1F 00 + 00 0F F2 3F 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 10 + 01 00 09 01 8C D8 EF 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 50 1F 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 + 29 01 00 00 00 00 8C + EF 00 70 4A 08 D0 00 00 00 00 + 3C 3C 3C 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 70 + 4A 08 D0 00 00 00 00 3C 3C 3C + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 03 08 EC 50 10 00 10 + 00 0A 0A 00 00 00 00 10 0F 00 + 03 51 00 50 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 03 08 EC + 29 01 00 00 00 00 02 + B0 03 + 29 01 00 00 00 00 02 + B0 04 + 29 01 00 00 00 00 02 + D6 00 + 39 01 00 00 00 00 03 + 51 FF F0 + 39 01 00 00 00 00 02 + 53 0C + 39 01 00 00 00 00 02 + 55 00 + 39 01 00 00 00 00 02 + 35 00 + 39 01 00 00 00 00 05 + 2A 00 00 04 37 + 39 01 00 00 00 00 05 + 2B 00 00 08 E7 + 05 01 00 00 FF 00 02 + 29 00 + 05 01 00 00 FF 00 02 + 11 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,cmd-to-video-mode-post-switch-commands = [ + 15 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 05 B7 51 00 00 00]; + qcom,cmd-to-video-mode-post-switch-commands-state = + "dsi_lp_mode"; + }; + + timing@1 { + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <80>; + qcom,mdss-dsi-h-back-porch = <80>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <13>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x4 0x1>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 + B0 00 + 29 01 00 00 00 00 0D + B6 30 6B 00 06 03 0A 13 1A 6C + 18 19 02 + 29 01 00 00 00 00 05 + B7 40 00 00 00 + 29 01 00 00 00 00 08 + B8 57 3D 19 BE 1E 0A 0A + 29 01 00 00 00 00 08 + B9 6F 3D 28 BE 3C 14 0A + 29 01 00 00 00 00 08 + BA B5 33 41 BE 64 23 0A + 29 01 00 00 00 00 0C + BB 44 26 C3 1F 19 06 03 C0 00 + 00 10 + 29 01 00 00 00 00 0C + BC 32 4C C3 52 32 1F 03 F2 00 + 00 13 + 29 01 00 00 00 00 0C + BD 24 68 C3 AA 3F 32 03 FF 00 + 00 25 + 29 01 00 00 00 00 0D + BE 00 00 00 00 00 00 00 00 00 + 00 00 00 + 29 01 00 00 00 00 0D + C0 00 DC 00 DC 04 08 E8 00 04 + 00 03 78 + 29 01 00 00 00 00 24 + C1 30 00 00 11 11 00 00 00 22 + 00 05 20 FA 00 08 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 79 + C2 06 E0 6E 01 03 00 02 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 11 00 00 00 00 04 A0 C9 + 00 00 00 00 00 00 48 EB 00 00 + 01 00 00 00 11 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 11 00 00 00 00 + 00 00 DC 00 00 00 00 04 00 08 + EF 00 00 00 00 00 11 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 6D + C3 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 AA AA AA 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 62 + C4 00 4C 00 3F 00 83 00 00 87 + 86 85 84 00 00 00 00 00 61 5D + 5F 00 5E 60 62 00 00 00 02 00 + 83 00 00 87 86 85 84 00 00 00 + 00 00 61 5D 5F 00 5E 60 62 FF + FF FF FF FF FF 00 0F 0E 00 0F + 0E 00 00 00 00 00 00 00 0F EE + 00 0F EE 00 00 E0 00 00 E0 0E + 00 00 00 0E 00 00 00 00 00 FF + 57 00 00 00 00 00 00 00 + 29 01 00 00 00 00 06 + C5 08 00 00 00 00 + 29 01 00 00 00 00 3A + C6 02 0A 08 FC FF FF FF 00 00 + 13 01 F0 0C 06 01 43 43 43 00 + 00 00 01 77 09 28 28 06 01 43 + 43 43 00 00 00 01 61 00 00 00 + 1C 01 00 00 00 00 00 00 00 00 + 00 00 00 00 20 20 00 00 + 29 01 00 00 00 00 4D + C7 00 00 00 E0 01 E9 02 7E 02 + 05 02 90 02 F6 02 40 02 5C 02 + 77 02 C8 02 1B 02 5B 02 BD 02 + 27 02 C3 03 54 03 D8 03 FF 00 + 00 00 E0 01 E9 02 7E 02 05 02 + 90 02 F6 02 40 02 5C 02 77 02 + C8 02 1B 02 5B 02 BD 02 27 02 + C3 03 54 03 D8 03 FF + 29 01 00 00 00 00 42 + C8 41 00 FF FA 00 FF 00 00 FE + F6 FE E9 00 00 FF F7 FB E1 00 + 00 00 00 00 FF 00 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF 00 FF FA 00 + FF 00 FE F6 FE E9 00 FF F7 FB + E1 00 00 00 00 FF + 29 01 00 00 00 00 19 + C9 00 FF FA 00 FF 00 00 FE F6 + FE E9 00 00 FF F7 FB E1 00 00 + 00 00 00 FF 00 + 29 01 00 00 00 00 42 + CA 1C FC FC FC 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + CC 00 00 4D 8B 55 4D 8B AA 4D + 8B + 29 01 00 00 00 00 02 + CD 00 + 29 01 00 00 00 00 24 + CE 5D 40 49 53 59 5E 63 68 6E + 74 7E 8A 98 A8 BB D0 E7 FF 04 + 00 04 04 42 04 69 5A 40 11 F4 + 00 00 84 FA 00 00 + 29 01 00 00 00 00 07 + CF 00 00 80 46 61 00 + 29 01 00 00 00 00 12 + D0 F6 95 11 B1 55 CF 00 F6 D3 + 11 F0 01 12 CF 02 20 11 + 29 01 00 00 00 00 23 + D1 D3 D3 33 33 07 03 3B 33 77 + 37 77 37 35 77 07 77 F7 33 73 + 07 33 33 03 33 1B 03 32 3D 0A + 30 13 13 20 00 + 29 01 00 00 00 00 05 + D2 00 00 07 00 + 29 01 00 00 00 00 9A + D3 03 00 00 00 00 00 00 0F 00 + 57 00 00 32 00 00 1A 70 01 19 + 80 01 01 F0 02 00 E0 06 FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF FF F7 FF FF F7 FF + FF F7 FF FF F7 FF FF F7 FF FF + F7 FF FF F7 FF FF F7 FF FF F7 + FF FF F7 FF + 29 01 00 00 00 00 05 + E5 03 00 00 00 + 29 01 00 00 00 00 09 + D5 02 42 02 42 02 DC 02 DC + 29 01 00 00 00 00 02 + D6 C0 + 29 01 00 00 00 00 32 + D7 21 10 52 52 00 B6 04 FD 00 + B6 04 FD 00 82 80 83 84 85 83 + 80 84 45 85 85 85 87 04 06 02 + 04 04 07 10 0C 0B 0A 0A 07 06 + 00 08 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 05 + DD 30 06 23 65 + 29 01 00 00 00 00 0D + DE 00 00 00 0F FF 00 00 00 00 + 00 00 10 + 29 01 00 00 00 00 02 + E3 FF + 29 01 00 00 00 00 07 + E6 00 00 00 00 00 00 + 29 01 00 00 00 00 0B + E7 50 04 00 00 00 00 00 00 00 + 00 + 29 01 00 00 00 00 05 + E8 00 01 23 00 + 29 01 00 00 00 00 1E + EA 01 02 47 80 47 00 00 00 05 + 00 13 60 02 47 80 47 00 00 00 + 00 13 60 00 11 00 30 10 21 02 + 29 01 00 00 00 00 08 + EB 00 00 00 00 01 00 11 + 29 01 00 00 00 00 04 + EC 00 00 00 + 29 01 00 00 00 00 21 + ED 01 01 02 02 02 02 00 00 00 + 00 00 00 0A 00 00 00 00 10 00 + 18 00 18 00 B0 00 00 00 00 00 + DA 10 00 + 29 01 00 00 00 00 61 + EE 03 0F 00 00 00 00 40 1F 00 + 00 0F F2 3F 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 10 + 01 00 09 01 8C D8 EF 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 50 1F 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 + 29 01 00 00 00 00 8C + EF 00 70 4A 08 D0 00 00 00 00 + 3C 3C 3C 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 70 + 4A 08 D0 00 00 00 00 3C 3C 3C + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 03 08 EC 50 10 00 10 + 00 0A 0A 00 00 00 00 10 0F 00 + 03 51 00 50 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 03 08 EC + 29 01 00 00 00 00 02 + B0 03 + 29 01 00 00 00 00 02 + B0 04 + 29 01 00 00 00 00 02 + D6 00 + 39 01 00 00 00 00 03 + 51 FF F0 + 39 01 00 00 00 00 02 + 53 0C + 39 01 00 00 00 00 02 + 55 00 + 39 01 00 00 00 00 02 + 35 00 + 39 01 00 00 00 00 05 + 2A 00 00 04 37 + 39 01 00 00 00 00 05 + 2B 00 00 08 E7 + 05 01 00 00 FF 00 02 + 29 00 + 05 01 00 00 FF 00 02 + 11 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,video-to-cmd-mode-post-switch-commands = [ + 15 01 00 00 00 00 02 B0 00 + 29 01 00 00 00 00 05 B7 40 00 00 00]; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-truly-1080p-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-truly-1080p-cmd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..af3576a97c7443e69b8e88be270244ecdd9b7d61 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-truly-1080p-cmd.dtsi @@ -0,0 +1,84 @@ +&mdss_mdp { + dsi_truly_1080_cmd: qcom,mdss_dsi_truly_1080p_cmd { + qcom,mdss-dsi-panel-name = "truly 1080p cmd mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <96>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6e 2a 3c 44 03 + 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-on-command = [23 01 00 00 00 00 02 d6 01 + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 2c + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 78 00 02 11 00 + 23 01 00 00 00 00 02 b0 04 + 29 01 00 00 00 00 07 b3 04 00 00 00 00 00 + 29 01 00 00 00 00 03 b6 3a d3 + 29 01 00 00 00 00 03 c0 00 00 + 29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02 + 58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10 00 02 01 + 22 22 00 01 + 29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00 + 29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06 + 00 00 00 00 00 04 00 00 00 0c 06 + 29 01 00 00 00 00 29 c6 78 69 00 69 00 69 00 00 00 00 00 + 69 00 69 00 69 10 19 07 00 78 00 69 00 69 00 69 00 00 00 + 00 00 69 00 69 00 69 10 19 07 + 29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0 + 23 01 00 00 00 00 02 cc 0b + 29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00 + 29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00 + a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33 + 29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32 + 29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52 + 60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60 67 6e 77 + 29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00 + 00 fc 00 00 00 00 00 fc 00 + 05 01 00 00 14 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,ulps-enabled; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-truly-1080p-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-truly-1080p-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f081ef9b76884b839acde0c0ae9ad64f6a0ded83 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-truly-1080p-video.dtsi @@ -0,0 +1,78 @@ +&mdss_mdp { + dsi_truly_1080_vid: qcom,mdss_dsi_truly_1080p_video { + qcom,mdss-dsi-panel-name = "truly 1080p video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <96>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [e6 38 26 00 68 6e 2a 3c 44 03 + 04 00]; + qcom,mdss-dsi-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-on-command = [15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 2c + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 78 00 02 11 00 + 23 01 00 00 00 00 02 b0 00 + 29 01 00 00 00 00 07 b3 14 00 00 00 00 00 + 29 01 00 00 00 00 03 b6 3a d3 + 29 01 00 00 00 00 03 c0 00 00 + 29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02 + 58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10 00 02 01 + 22 22 00 01 + 29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00 + 29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06 + 00 00 00 00 00 04 00 00 00 0c 06 + 29 01 00 00 00 00 29 c6 00 69 00 69 00 69 00 00 00 00 00 + 69 00 69 00 69 10 19 07 00 01 00 69 00 69 00 69 00 00 00 + 00 00 69 00 69 00 69 10 19 07 + 29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0 + 23 01 00 00 00 00 02 cc 0b + 29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00 + 29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00 + a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33 + 29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32 + 29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52 + 60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60 67 6e 77 + 29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00 + 00 fc 00 00 00 00 00 fc 00 + 05 01 00 00 14 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-post-init-delay = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-xrsmrtvwr-jdi-dual-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-xrsmrtvwr-jdi-dual-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e6ce614d032b5ef12e07ac3046b89ad0ce0038b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-xrsmrtvwr-jdi-dual-video.dtsi @@ -0,0 +1,87 @@ +&mdss_mdp { + dsi_dual_xrsmrtvwr_jdi_video: qcom,mdss_dsi_xrsmrtvwr_video_jdi { + qcom,mdss-dsi-panel-name = + "Dual Smart XR Viewer LPM029M483A R63455 jdi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dsi-ctrl-num = <0 1>; + qcom,dsi-phy-num = <0 1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; + qcom,mdss-pan-physical-width-dimension = <52>; + qcom,mdss-pan-physical-height-dimension = <52>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-bpp = <24>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1440>; + qcom,mdss-dsi-panel-height = <1440>; + qcom,mdss-dsi-h-front-porch = <40>; + qcom,mdss-dsi-h-back-porch = <40>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <322>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <75>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 00 + 29 01 00 00 00 00 0A B6 30 6B 80 06 33 + 8A 00 1A 7A + 29 01 00 00 00 00 05 B7 54 00 00 00 + 29 01 00 00 00 00 0D B9 00 85 01 BF 00 + 00 00 00 00 85 01 BF + 29 01 00 00 00 00 09 C0 61 86 58 02 08 + 70 04 EC + 29 01 00 00 00 00 02 F1 1E + 29 01 00 00 00 00 09 C6 A0 05 A0 05 43 + 9F 05 43 + 29 01 00 00 00 00 02 CD 11 + 29 01 00 00 00 00 08 CF 00 00 80 46 61 + 00 00 + 29 01 00 00 00 00 07 EC 01 8E 00 00 00 + 00 + 39 01 00 00 00 00 02 03 00 + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 05 01 00 00 02 00 02 29 00 + 05 01 00 00 80 00 02 11 00 + 29 01 00 00 00 00 02 D6 80 + 29 01 00 00 00 00 02 B0 03 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 32 00 02 34 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c8aab9400bac29e6f115a19bc783f2f80f0badd4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi @@ -0,0 +1,78 @@ +qcom,ascent_3450mah { + /* Ascent_wConn_Aging_3450mAh_averaged_MasterSlave_Jul11th2017 */ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <3450>; + qcom,batt-id-kohm = <60>; + qcom,jeita-fcc-ranges = <0 100 1725000 + 101 400 3450000 + 401 450 2760000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 101 400 4350000 + 401 450 4250000>; + qcom,step-chg-ranges = <3600000 4200000 3450000 + 4201000 4300000 2760000 + 4301000 4350000 2070000>; + qcom,battery-beta = <3435>; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_oct30th2017"; + qcom,checksum = <0xAAE2>; + qcom,gui-version = "PMI8998GUI - 2.0.0.58"; + qcom,fg-profile-data = [ + 8F 1F 94 05 + 73 0A 4A 06 + 27 1D 21 EA + 16 0A 3A 0C + 07 18 97 22 + A5 3C EC 4A + 5C 00 00 00 + 10 00 00 00 + 00 00 43 C5 + 92 BC 89 BB + 11 00 08 00 + 69 DA AD 07 + 4B FD 19 FA + 7E 01 49 13 + EB F3 78 3B + 24 06 09 20 + 27 00 14 00 + 7E 1F F2 05 + 19 0A AB 06 + 6C 1D B9 07 + 1A 12 FF 1D + 6F 18 EB 22 + B9 45 6F 52 + 55 00 00 00 + 0E 00 00 00 + 00 00 33 CC + 72 CA B3 C4 + 0F 00 00 00 + 93 00 AD 07 + 8D FD F6 00 + 6F E3 44 0B + AB FC F9 1B + C3 33 CC FF + 07 10 00 00 + A4 0D 99 45 + 0F 00 40 00 + A4 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-itech-3000mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5a3d5ac92499f11c4b28c29240e8744d4caf6814 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-itech-3000mah.dtsi @@ -0,0 +1,69 @@ +qcom,itech_3000mah { + /* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jan10th2017*/ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <2000>; + qcom,batt-id-kohm = <100>; + qcom,battery-beta = <3435>; + qcom,battery-type = "itech_b00826lf_3000mah_ver1660_jan10th2017"; + qcom,checksum = <0xFB8F>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,fg-profile-data = [ + A4 1F 6E 05 + 9C 0A 2B FC + 32 1D 23 E5 + 60 0B 1B 15 + AD 17 8C 22 + EA 3C 89 4A + 5B 00 00 00 + 12 00 00 00 + 00 00 62 C2 + 0C CD D8 C2 + 19 00 08 00 + 85 EA C7 EC + E2 05 2F 01 + 9B F5 12 12 + 5E 05 88 3B + 22 06 09 20 + 27 00 14 00 + 7D 1F DD 05 + 3F 0A E5 FC + 72 1D E3 F5 + 6F 12 C0 1D + 88 18 FB 22 + 8D 45 C6 52 + 54 00 00 00 + 0F 00 00 00 + 00 00 BD CD + 55 C2 5D C5 + 14 00 00 00 + 7E 00 C7 EC + 60 06 BB 00 + 59 06 61 03 + D9 FC 75 1B + B3 33 CC FF + 07 10 00 00 + 3E 0B 99 45 + 14 00 40 00 + AE 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8c157e40c0a2479ba5d9983aba47268bd12f98fc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi @@ -0,0 +1,69 @@ +qcom,qrd_msm8998_skuk_3000mah { + /* QRD8997_ST1031GA_3000mAh_averaged_MasterSlave_Jan10th2017 */ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <3000>; + qcom,batt-id-kohm = <68>; + qcom,battery-beta = <3380>; + qcom,battery-type = "qrd8997_st1031ga_3000mah"; + qcom,checksum = <0xD299>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,fg-profile-data = [ + 70 1F B1 05 + 6F 0A A1 FC + 8C 1D D7 FD + C4 12 AC 1D + 7E 18 01 23 + 8C 45 B6 52 + 55 00 00 00 + 0F 00 00 00 + 00 00 92 C5 + 95 CD A0 CA + 1F 00 08 00 + 9F E3 C3 EC + F7 FC 25 F3 + 02 01 FF 12 + 29 DC 1D 3A + 1C 06 09 20 + 27 00 14 00 + AC 1F B4 05 + 57 0A EF FC + 6A 1D E9 E2 + 11 0B BB 14 + 40 19 DC 22 + 79 45 03 53 + 53 00 00 00 + 0E 00 00 00 + 00 00 05 CC + 3A BB 24 CA + 1C 00 00 00 + 56 F2 C3 EC + A6 06 A2 F2 + 9A 06 CC 01 + 8C EA CF 1A + BA 33 CC FF + 07 10 00 00 + 3A 0C 66 46 + 1C 00 40 00 + 98 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-alium-3600mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0be77e5406b67b835c9114d8c2972a16ef2dfe52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-alium-3600mah.dtsi @@ -0,0 +1,141 @@ +qcom,alium_860_89032_0000_3600mah_averaged_masterslave_sep24th2018 { + /* #Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Sept24th2018*/ + qcom,max-voltage-uv = <4350000>; + qcom,fastchg-current-ma = <5400>; + qcom,jeita-fcc-ranges = <0 100 2500000 + 101 400 3600000 + 401 450 2500000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 101 400 4350000 + 401 450 4250000>; + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3800001 4300000 3600000 + 4300001 4350000 2500000>; + /* COLD = 0 DegC, HOT = 45 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x20b8>; + /* COOL = 10 DegC, WARM = 40 DegC */ + qcom,jeita-soft-thresholds = <0x4ccc 0x25e3>; + /* COLD hys = 13 DegC, WARM hys = 37 DegC */ + qcom,jeita-soft-hys-thresholds = <0x48d4 0x2943>; + qcom,jeita-soft-fcc-ua = <2500000 2500000>; + qcom,jeita-soft-fv-uv = <4250000 4250000>; + qcom,ocv-based-step-chg; + qcom,batt-id-kohm = <107>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,battery-type = "alium_860_89032_0000_3600mah_sept24th2018"; + qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; + qcom,therm-center-offset = <0x70>; + qcom,therm-pull-up = <100>; + qcom,rslow-normal-coeffs = <0xdf 0x02 0x77 0x1a>; + qcom,rslow-low-coeffs = <0x51 0x04 0xd0 0x13>; + qcom,checksum = <0x1538>; + qcom,gui-version = "PM855GUI - 1.0.0.10"; + qcom,fg-profile-data = [ + 09 00 C7 EA + C4 DC 8E E2 + 3A DD 00 00 + 15 BC A5 8A + 02 80 D1 92 + AB 9D 47 80 + 10 00 DF 02 + 77 1A 85 EC + E1 FD CE 07 + 32 00 75 EB + AA ED F3 CD + 0C 0A 7A E4 + ED C5 40 1B + D0 02 1F CA + FF 00 52 00 + 4D 00 4A 00 + 3C 00 35 00 + 38 00 39 00 + 48 00 43 00 + 3F 00 FF 00 + 38 00 40 00 + 46 00 50 00 + 45 00 5C 00 + 7E 64 60 00 + 50 08 50 10 + FF 00 6A 00 + 5F 00 63 00 + 6E 00 60 00 + 7D 20 96 40 + 75 50 6B 13 + 63 00 D8 00 + 14 22 7E 0D + 21 02 AA 04 + ED 1C D4 09 + 64 0C D3 23 + A4 18 D3 42 + B5 55 91 02 + 90 12 2A 1F + 02 06 1F 0A + A3 06 AE 1C + 8D 02 96 04 + D2 03 D1 17 + 51 23 3F 45 + 28 53 69 14 + 93 20 8E EC + 18 CB C8 C5 + DB 1C 7B C9 + 7C 05 E6 C2 + B9 17 2C 93 + 87 85 A2 92 + 91 A8 09 80 + 92 F2 1A 0D + F4 FC 5E EB + 00 F8 FB ED + 15 E2 F6 0F + 75 02 72 05 + 49 01 10 00 + FA E5 E2 03 + 8D 05 85 02 + CE 07 32 00 + 23 03 46 02 + 9C 04 03 02 + 48 07 0A 00 + BA 03 97 02 + 65 05 50 00 + 3A 00 41 00 + 43 64 45 00 + 45 10 45 18 + 46 08 44 00 + 47 00 3A 08 + 4B 08 37 00 + 47 20 4E 40 + 54 58 60 10 + 57 00 5F 00 + 57 08 55 00 + 4B 00 50 00 + 3E 08 52 08 + 52 00 5C 20 + 6F 40 7D 58 + 67 10 63 00 + 69 08 4F 10 + D8 00 8C 2A + DB 04 28 02 + AD 04 0B 1D + 50 22 A7 45 + 0D 52 A2 18 + 74 03 AD 04 + 35 02 AE 13 + 3F 0A 5A 20 + DD 04 F1 02 + D8 05 C7 1C + DD 02 3D 04 + EB 03 97 18 + 52 03 D5 04 + 19 02 72 00 + 14 22 7E 05 + 21 02 AA 04 + ED 1C D4 01 + 64 04 D3 03 + A4 18 D3 02 + B5 05 91 02 + 90 00 7C 01 + C0 00 FA 00 + 04 0E 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-ascent-3450mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5c8618c9dc9c1a2a1f2849730affb446b564675b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-ascent-3450mah.dtsi @@ -0,0 +1,139 @@ +qcom,ascent_wconn_3450mah_fresh_averaged_masterslave_feb28th2019 { + qcom,profile-revision = <24>; + /* #Ascent_wConn_3450mAh_Fresh_averaged_MasterSlave_Feb28th2019*/ + qcom,max-voltage-uv = <4350000>; + qcom,fastchg-current-ma = <3450>; + qcom,jeita-fcc-ranges = <0 100 1725000 + 101 400 3450000 + 401 450 2760000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 101 400 4350000 + 401 450 4250000>; + /* COLD = 0 DegC, HOT = 45 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x20b8>; + /* COOL = 10 DegC, WARM = 40 DegC */ + qcom,jeita-soft-thresholds = <0x4ccc 0x25e3>; + /* COLD hys = 13 DegC, WARM hys = 37 DegC */ + qcom,jeita-soft-hys-thresholds = <0x48d4 0x2943>; + qcom,jeita-soft-fcc-ua = <1725000 2760000>; + qcom,jeita-soft-fv-uv = <4250000 4250000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,nom-batt-capacity-mah = <3450>; + qcom,batt-id-kohm = <60>; + qcom,battery-beta = <3435>; + qcom,therm-room-temp = <68000>; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_feb28th2019"; + qcom,therm-coefficients = <0x2313 0xc42 0xea62 0xcc3d 0x8313>; + qcom,therm-center-offset = <0x5b>; + qcom,therm-pull-up = <100>; + qcom,rslow-normal-coeffs = <0x43 0x0a 0x7b 0x1a>; + qcom,rslow-low-coeffs = <0xd0 0x13 0x18 0x22>; + qcom,checksum = <0xC0ED>; + qcom,gui-version = "PM855GUI - 1.0.0.13"; + qcom,fg-profile-data = [ + 09 00 63 EA + 65 DD F5 DB + 02 D4 00 00 + A5 BD 62 8A + FA 87 3A A4 + 16 9A D5 80 + 0E 00 43 0A + 7B 1A 3B F4 + 4D F2 CE 07 + 32 00 1F F3 + 18 D4 81 DA + D4 02 0B E4 + F3 C4 F6 1B + AB F3 AF C4 + 60 00 4A 00 + 42 00 43 00 + 42 00 3A 00 + 3C 00 49 00 + 3D 00 39 00 + 3A 00 60 00 + 26 00 24 00 + 33 00 3D 00 + 36 00 94 00 + 58 64 41 00 + 3A 00 35 08 + 60 F8 18 00 + 25 00 3B 08 + 3C 08 3D 00 + 83 20 4E 40 + 44 50 42 12 + 3E 00 D8 00 + 6D 20 B5 0C + E5 FA 2B 04 + 7C 1C F0 0A + 55 0C A7 23 + 95 17 74 43 + 11 55 74 03 + 79 14 A1 1F + 9B 05 5A 02 + EF F4 AE 1C + 34 02 90 05 + 8E 0A 1D 17 + 66 23 70 45 + A8 52 7B 14 + DE 1E 75 EE + 7D D3 02 C4 + AA 1C F8 C1 + 06 04 25 BA + 33 18 BD 8A + F2 85 21 A2 + 78 98 09 80 + 3D FA AD 0D + 2F 02 61 03 + 00 F8 DF D5 + 6D EA F9 0F + E8 F5 6A D5 + 0F 11 0C 18 + 03 F5 6A 03 + B0 05 D8 01 + CE 07 32 00 + 9F 03 19 04 + 0B 05 5D 02 + 79 03 E4 05 + 4A 03 FB 05 + AB 02 55 00 + 3F 00 41 00 + 40 64 40 00 + 44 F8 37 00 + 3B F0 41 00 + 43 00 36 10 + 60 10 3E 00 + 4A 20 4E 40 + 52 58 5D 0F + 45 00 46 00 + 4B 08 5E F8 + 43 00 5E 00 + 42 08 52 10 + 50 00 65 20 + 78 40 59 50 + 65 12 66 00 + 5E 00 47 08 + D8 00 A8 1F + 53 04 7D 0B + 52 0C A9 1C + 7D 23 B8 45 + 44 52 5E 18 + A8 03 4D 04 + 9D 02 6C 13 + 3F 0A 85 1F + F5 05 11 02 + 6D 05 A7 1C + 0E 03 06 04 + 11 02 47 18 + 1C 03 61 05 + 15 03 6C 00 + 6C 20 DD 04 + E4 02 EF 05 + C4 1C 1F 02 + D9 05 31 02 + 7B 18 C5 02 + D2 05 60 02 + 85 00 A4 01 + C0 00 FA 00 + A4 0D 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-atl466274-3650mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-atl466274-3650mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f5e78e3a31d34ba2e695a3c753f70486fb21ed1e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-atl466274-3650mah.dtsi @@ -0,0 +1,138 @@ + +qcom,atl466274_3650mah_averaged_masterslave_may14th2019 { + /* #ATL466274_3650mAh_averaged_MasterSlave_May14th2019*/ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <5325>; + qcom,batt-id-kohm = <31>; + /* COLD = 0 DegC, HOT = 55 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x181d>; + /* COOL = 10 DegC, WARM = 45 DegC */ + qcom,jeita-soft-thresholds = <0x4ccc 0x20b8>; + /* COOL hys = 13 DegC, WARM hys = 42 DegC */ + qcom,jeita-soft-hys-thresholds = <0x48d4 0x23c0>; + qcom,jeita-fcc-ranges = <0 100 1065000 + 101 200 1775000 + 201 450 5325000 + 451 550 1775000>; + qcom,jeita-fv-ranges = <0 100 4400000 + 101 200 4400000 + 201 450 4400000 + 451 550 4050000>; + qcom,jeita-soft-fcc-ua = <1065000 1775000>; + qcom,jeita-soft-fv-uv = <4400000 4050000>; + qcom,battery-beta = <4250>; + qcom,battery-type = "ATL466274_3650mah_masterslave_may14th2019"; + qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; + qcom,therm-center-offset = <0x70>; + qcom,rslow-normal-coeffs = <0xb1 0xfa 0x99 0x13>; + qcom,rslow-low-coeffs = <0x79 0x15 0x21 0xfa>; + qcom,checksum = <0xCC95>; + qcom,gui-version = "PM855GUI - 1.0.0.13"; + qcom,fg-profile-data = [ + 09 00 CB E3 + B1 DD D0 DB + 31 D4 00 00 + 9F BD BE 83 + FE 87 38 9C + 6C 87 9B 80 + 1A 00 B1 FA + 99 13 B9 06 + 13 FA CE 07 + 32 00 3D EB + F9 ED BF D5 + 38 0A 45 DB + BD 9C 6F 12 + 8B E3 55 C4 + 60 00 4A 00 + 47 00 43 00 + 34 00 31 00 + 34 00 43 00 + 40 00 42 00 + 44 00 60 00 + 33 00 3D 00 + 47 00 3F 00 + 37 00 75 00 + 5D 64 49 00 + 40 00 40 08 + 60 00 50 00 + 4C 00 58 08 + 4C 10 45 00 + 84 28 5D 48 + 4F 58 48 0E + 45 00 D8 08 + 6F 20 6F 14 + 61 03 7F FD + A0 1C E7 02 + 0D 04 24 22 + 9B 17 2C 42 + B2 55 61 03 + 71 13 44 22 + 57 05 4B 0A + 5F 04 06 1D + D3 02 A2 05 + F5 02 30 18 + 25 23 6C 45 + E4 52 95 12 + D5 1F 3F E5 + D9 CA DF BD + E0 1C 8B C9 + 5B 05 43 BB + 55 17 B2 8B + E2 84 97 93 + 84 98 09 80 + A3 03 CD 05 + 66 05 3D F2 + 00 F8 58 D5 + E3 E2 F7 07 + D5 EB 0A C5 + 37 18 17 00 + 33 E7 CB 02 + 36 07 5E 03 + CE 07 32 00 + 2B 03 07 04 + 3D 05 D6 02 + EB 05 73 03 + 9F 03 33 03 + 02 05 4C 00 + 3D 00 42 00 + 42 64 46 00 + 4A 00 3E 08 + 44 F8 46 00 + 46 00 3B 10 + 3E 10 3B 00 + 49 28 4A 48 + 52 60 64 0D + 40 00 48 00 + 50 08 4C 00 + 39 00 3E 00 + 3D 10 48 10 + 42 00 51 20 + 65 40 43 58 + 4D 0E 48 00 + 38 00 20 08 + D8 00 2D 20 + 39 05 B1 0A + 33 0C BD 1C + 71 23 97 45 + 8D 52 5C 18 + 22 02 7F 05 + 0C 02 6A 11 + 3F 0A 36 20 + E5 04 25 03 + 8D 05 C5 1C + FD 02 FA 05 + 37 02 88 18 + B2 03 1A 04 + DA 02 6C 00 + 78 20 8C 04 + 75 03 37 05 + D7 1C 3B 02 + 84 05 BF 02 + 93 18 11 03 + 4E 05 45 03 + 7A 00 1D 01 + C0 00 FA 00 + 47 0E 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-goertek-6100mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-goertek-6100mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6b3aee7ec471cba21ca616413f982ea5bc3bd9d3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-goertek-6100mah.dtsi @@ -0,0 +1,69 @@ +qcom,4295629_goertek_vdl_6100mah_pm660_jan9th2020 { + /* #4295629_Goertek_VDL_6100mAH_PM660_averaged_MasterSlave_Jan9th2020*/ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,nom-batt-capacity-mah = <6100>; + qcom,batt-id-kohm = <35>; + qcom,battery-beta = <4250>; + qcom,battery-type = "4295629_goertek_vdl_6100mah_pm660_jan9th2020"; + qcom,checksum = <0xFBA6>; + qcom,gui-version = "PM660GUI - 0.0.0.45"; + qcom,fg-profile-data = [ + 6B 1E 62 F4 + 65 02 85 EC + D2 1C 12 02 + 82 0D D8 0A + F8 17 76 23 + F1 44 B7 53 + 67 00 00 00 + 11 00 00 00 + 00 00 50 C5 + 02 C5 02 00 + 25 00 08 00 + C6 DB F3 E4 + B7 05 9F FB + D7 EA F1 12 + F7 06 2C 32 + 25 06 09 20 + 27 00 14 00 + 5B 1F 5D FC + D2 03 A9 FD + D0 1C D6 02 + 3E 0C 04 12 + A7 18 67 23 + A6 44 4B 5A + 69 00 00 00 + 0F 00 00 00 + 00 00 76 D5 + 6C CA 06 BB + 1C 00 00 00 + 1D EA F3 E4 + BF 06 0B FA + 71 FD 12 01 + FB FD 5F 13 + 99 33 CC FF + 07 10 00 00 + 59 19 99 45 + 1C 00 40 00 + DF 00 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-mlp466274-3650mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-mlp466274-3650mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5c82394242a1813c821b1feea512b16bdf741e8b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/fg-gen4-batterydata-mlp466274-3650mah.dtsi @@ -0,0 +1,135 @@ +qcom,mlp466274_3650mah_averaged_masterslave_jan21st2019 { + /* #mlp466274_3650mAh_averaged_MasterSlave_Jan21st2019*/ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,fastchg-current-ma = <5325>; + qcom,batt-id-kohm = <44>; + /* COLD = 0 DegC, HOT = 55 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x181d>; + /* COOL = 15 DegC, WARM = 45 DegC */ + qcom,jeita-soft-thresholds = <0x4621 0x20b8>; + /* COOL hys = 18 DegC, WARM hys = 42 DegC */ + qcom,jeita-soft-hys-thresholds = <0x4206 0x23c0>; + qcom,jeita-fcc-ranges = <0 150 710000 + 151 450 5325000 + 451 550 1775000>; + qcom,jeita-fv-ranges = <0 150 4150000 + 151 450 4400000 + 451 550 4150000>; + qcom,jeita-soft-fcc-ua = <710000 1775000>; + qcom,jeita-soft-fv-uv = <4150000 4150000>; + qcom,battery-beta = <4250>; + qcom,battery-type = "mlp466274_3650mah_masterslave_jan21st2019"; + qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; + qcom,therm-center-offset = <0x70>; + qcom,rslow-normal-coeffs = <0xa9 0x15 0x87 0x0d>; + qcom,rslow-low-coeffs = <0xae 0x0c 0x65 0xfc>; + qcom,checksum = <0x393C>; + qcom,gui-version = "PM855GUI - 1.0.0.13"; + qcom,fg-profile-data = [ + 09 00 15 EA + CA DC 05 E3 + 99 DC 00 00 + A6 BD 4F 8A + F9 87 88 9D + 79 9A E7 87 + 48 00 A9 15 + 87 0D 7C 04 + 30 02 CE 07 + 32 00 BF EB + 95 ED 67 D5 + 16 0A 1A EB + 5C B2 FE 0D + A9 06 23 BB + 60 00 3E 00 + 3D 00 3E 00 + 38 00 32 00 + 33 00 38 00 + 40 00 4A 00 + 5A 00 60 00 + 51 00 41 00 + 36 00 31 00 + 2E 00 3C 00 + 45 64 43 00 + 47 00 40 00 + 60 00 54 00 + 45 00 50 08 + 53 08 3F 00 + 66 28 61 48 + 51 58 4A 0E + 47 00 D8 00 + F6 1F 7F 0D + FA 03 53 07 + 73 1C DE 0A + 82 0C 64 23 + 1A 17 4E 42 + 8C 55 99 03 + 7D 13 79 1F + 98 05 91 0A + 2B 06 BE 1C + 32 02 67 05 + F4 02 F9 17 + 27 23 72 45 + DB 52 72 13 + FE 1F 14 ED + F1 CA CA 85 + D3 1C 8C C1 + 78 05 11 BB + 4C 17 80 8B + 33 85 0F 9B + 88 80 09 80 + 01 F2 F2 05 + FE 03 AC FB + 00 F8 51 DD + 44 EB F4 07 + 89 F5 8C CA + 33 18 2A 00 + 11 DD AB 01 + 86 05 2F 03 + CE 07 32 00 + 3D 03 D9 03 + 45 05 01 07 + 23 02 17 05 + C8 03 9F 07 + 33 03 50 00 + 3F 00 3F 00 + 41 64 43 00 + 42 F8 3F 00 + 45 00 44 00 + 42 00 3B 10 + 45 10 3D 00 + 44 20 43 40 + 45 58 4B 0F + 39 00 3A 00 + 44 08 56 00 + 4B 00 3E 00 + 3A 10 48 10 + 45 00 4D 20 + 5F 40 40 58 + 42 10 4E 00 + 4B 08 2C 10 + D8 08 B3 1F + 41 FC B9 03 + EF 06 C5 1C + 57 23 D8 45 + 2D 52 7D 18 + 86 03 8C 04 + 5C 02 6C 12 + 3F 0A 68 20 + D1 04 1D 03 + A0 05 B9 1C + 1B 03 FB 05 + 1F 02 94 18 + 4E 03 DD 04 + 14 02 70 00 + 9D 23 A2 04 + D6 02 A4 05 + E6 1C D7 03 + 78 04 CB 03 + 84 18 F7 02 + 88 05 D7 02 + 95 00 58 01 + C0 00 FA 00 + 29 0E 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/ipcc-test-lagoon.dtsi b/arch/arm64/boot/dts/vendor/qcom/ipcc-test-lagoon.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b4bfb42ce4cad5755e071599396867f900e7bbf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/ipcc-test-lagoon.dtsi @@ -0,0 +1,9 @@ +#include "ipcc-test.dtsi" + +&soc { + /delete-node/ ipcc-self-ping-slpi; +}; + +&ipcc_self_ping_npu { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/ipcc-test-lito.dtsi b/arch/arm64/boot/dts/vendor/qcom/ipcc-test-lito.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b4bfb42ce4cad5755e071599396867f900e7bbf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/ipcc-test-lito.dtsi @@ -0,0 +1,9 @@ +#include "ipcc-test.dtsi" + +&soc { + /delete-node/ ipcc-self-ping-slpi; +}; + +&ipcc_self_ping_npu { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/ipcc-test.dtsi b/arch/arm64/boot/dts/vendor/qcom/ipcc-test.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e442628c74b62960b2b24539d1354f54b51b91a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/ipcc-test.dtsi @@ -0,0 +1,38 @@ +#include + +&soc { + ipcc_self_ping_apss: ipcc-self-ping-apss { + compatible = "qcom,ipcc-self-ping"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_APSS + IPCC_MPROC_SIGNAL_SMP2P IRQ_TYPE_LEVEL_HIGH>; + mboxes = <&ipcc_mproc IPCC_CLIENT_APSS IPCC_MPROC_SIGNAL_SMP2P>; + }; + + ipcc_self_ping_cdsp: ipcc-self-ping-cdsp { + compatible = "qcom,ipcc-self-ping"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_PING IRQ_TYPE_LEVEL_HIGH>; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP IPCC_MPROC_SIGNAL_PING>; + }; + + ipcc_self_ping_adsp: ipcc-self-ping-adsp { + compatible = "qcom,ipcc-self-ping"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_PING IRQ_TYPE_LEVEL_HIGH>; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS IPCC_MPROC_SIGNAL_PING>; + }; + + ipcc_self_ping_slpi: ipcc-self-ping-slpi { + compatible = "qcom,ipcc-self-ping"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_SLPI + IPCC_MPROC_SIGNAL_PING IRQ_TYPE_LEVEL_HIGH>; + mboxes = <&ipcc_mproc IPCC_CLIENT_SLPI IPCC_MPROC_SIGNAL_PING>; + }; + + ipcc_self_ping_npu: ipcc-self-ping-npu { + compatible = "qcom,ipcc-self-ping"; + interrupts-extended = <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_PING IRQ_TYPE_LEVEL_HIGH>; + mboxes = <&msm_npu IPCC_CLIENT_NPU IPCC_MPROC_SIGNAL_PING>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-audio-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..602cc3a5facc6efa94f5f1efaff7b8893c37727c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-audio-overlay.dtsi @@ -0,0 +1,466 @@ +#include +#include +#include +#include +#include "kona-lpi.dtsi" +#include "kona-va-bolero.dtsi" + +&bolero { + qcom,num-macros = <4>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,wsa_mclk_mode_muxsel = <0x033220D8>; + qcom,va_mclk_mode_muxsel = <0x033A0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", "rx_npl_clk", + "wsa_core_clk", "wsa_npl_clk", "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_wsa_1 0>, <&clock_audio_wsa_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; + + tx_macro: tx-macro@3220000 { + compatible = "qcom,tx-macro"; + reg = <0x3220000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <2400000>; + swr2: tx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <3>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3230000 0x0>; + interrupts-extended = + <&intc GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 109 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-wakeup-required = <1>; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 PCM_OUT1 0xF>, + <2 ADC1 0x1>, <2 ADC2 0x2>, + <3 ADC3 0x1>, <3 ADC4 0x2>, + <4 DMIC0 0x1>, <4 DMIC1 0x2>, + <4 DMIC2 0x4>, <4 DMIC3 0x8>, + <5 DMIC4 0x1>, <5 DMIC5 0x2>, + <5 DMIC6 0x4>, <5 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + qcom,swr-mstr-irq-wakeup-capable = <1>; + wcd938x_tx_slave: wcd938x-tx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170223>; + }; + }; + }; + + rx_macro: rx-macro@3200000 { + compatible = "qcom,rx-macro"; + reg = <0x3200000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr1: rx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <2>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3210000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,disable-div2-clk-switch = <1>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x1>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd938x_rx_slave: wcd938x-rx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170224>; + }; + }; + }; + + wsa_macro: wsa-macro@3240000 { + compatible = "qcom,wsa-macro"; + reg = <0x3240000 0x0>; + clock-names = "wsa_core_clk", "wsa_npl_clk"; + clocks = <&clock_audio_wsa_1 0>, + <&clock_audio_wsa_2 0>; + qcom,wsa-swr-gpios = <&wsa_swr_gpios>; + qcom,wsa-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr0: wsa_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <1>; + qcom,mipi-sdw-block-packing-mode = <0>; + swrm-io-base = <0x3250000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr-num-dev = <2>; + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + qcom,bolero-handle = <&bolero>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + qcom,bolero-handle = <&bolero>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + }; + }; + + }; + + wcd938x_codec: wcd938x-codec { + compatible = "qcom,wcd938x-codec"; + qcom,split-codec = <1>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <0 ADC2 0x2 0 ADC2>, <1 ADC3 0x1 0 ADC3>, + <1 ADC4 0x2 0 ADC4>, <2 DMIC0 0x1 0 DMIC0>, + <2 DMIC1 0x2 0 DMIC1>, <2 MBHC 0x4 0 DMIC2>, + <2 DMIC2 0x4 0 DMIC2>, <2 DMIC3 0x8 0 DMIC3>, + <3 DMIC4 0x1 0 DMIC4>, <3 DMIC5 0x2 0 DMIC5>, + <3 DMIC6 0x4 0 DMIC6>, <3 DMIC7 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd938x_rst_gpio>; + qcom,rx-slave = <&wcd938x_rx_slave>; + qcom,tx-slave = <&wcd938x_tx_slave>; + + cdc-vdd-rxtx-supply = <&S4A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + + cdc-vddio-supply = <&S4A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + + cdc-vdd-buck-supply = <&S4A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio", + "cdc-vdd-buck", + "cdc-vdd-mic-bias"; + }; + +}; + +&kona_snd { + qcom,model = "kona-mtp-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>, <1>; + qcom,wcn-bt = <1>; + qcom,ext-disp-audio-rx = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&lpi_tlmm>, + <&bolero>; +}; + +&q6core { + cdc_dmic01_gpios: cdc_dmic01_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic01_clk_active &cdc_dmic01_data_active>; + pinctrl-1 = <&cdc_dmic01_clk_sleep &cdc_dmic01_data_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic23_gpios: cdc_dmic23_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic23_clk_active &cdc_dmic23_data_active>; + pinctrl-1 = <&cdc_dmic23_clk_sleep &cdc_dmic23_data_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic45_gpios: cdc_dmic45_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic45_clk_active &cdc_dmic45_data_active>; + pinctrl-1 = <&cdc_dmic45_clk_sleep &cdc_dmic45_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <158>; + }; + + wsa_swr_gpios: wsa_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wsa_swr_clk_active &wsa_swr_data_active>; + pinctrl-1 = <&wsa_swr_clk_sleep &wsa_swr_data_sleep>; + qcom,lpi-gpios; + }; + + rx_swr_gpios: rx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&rx_swr_clk_active &rx_swr_data_active + &rx_swr_data1_active>; + pinctrl-1 = <&rx_swr_clk_sleep &rx_swr_data_sleep + &rx_swr_data1_sleep>; + qcom,lpi-gpios; + }; + + tx_swr_gpios: tx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tx_swr_clk_active &tx_swr_data1_active + &tx_swr_data2_active>; + pinctrl-1 = <&tx_swr_clk_sleep &tx_swr_data1_sleep + &tx_swr_data2_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <147>; + }; +}; + +&soc { + wsa_spkr_en1: wsa_spkr_en1_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_en2: wsa_spkr_en2_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + wcd938x_rst_gpio: msm_cdc_pinctrl@32 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd938x_reset_active>; + pinctrl-1 = <&wcd938x_reset_sleep>; + }; + + clock_audio_wsa_1: wsa_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x309>; + #clock-cells = <1>; + }; + + clock_audio_wsa_2: wsa_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30A>; + #clock-cells = <1>; + }; + + clock_audio_rx_1: rx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30E>; + #clock-cells = <1>; + }; + + clock_audio_rx_2: rx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30F>; + #clock-cells = <1>; + }; + + clock_audio_tx_1: tx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30C>; + #clock-cells = <1>; + }; + + clock_audio_tx_2: tx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30D>; + #clock-cells = <1>; + }; + + clock_audio_va_1: va_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30B>; + #clock-cells = <1>; + }; + + clock_audio_va_2: va_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x310>; + #clock-cells = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ae746f1b00a5e9d525f8e22a8341f40df48bc851 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-audio.dtsi @@ -0,0 +1,181 @@ +#include +#include "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x1801 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&soc { + qcom,avtimer@39f0000 { + compatible = "qcom,avtimer"; + reg = <0x039f000c 0x4>, + <0x039f0010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <192>; + qcom,clk-mult = <10>; + }; +}; + +&audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + + lpass_core_hw_vote: vote_lpass_core_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + lpass_audio_hw_vote: vote_lpass_audio_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + bolero: bolero-cdc { + compatible = "qcom,bolero-codec"; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + }; + + tx_macro: tx-macro@3220000 { + swr2: tx_swr_master { + }; + }; + + rx_macro: rx-macro@3200000 { + swr1: rx_swr_master { + }; + }; + + wsa_macro: wsa-macro@3240000 { + swr0: wsa_swr_master { + }; + }; + }; + }; + + voice_mhi_audio: qcom,voice-mhi-audio { + compatible = "qcom,voice-mhi-audio"; + memory-region = <&mailbox_mem>; + voice_mhi_voting; + }; +}; + +&q6core { + kona_snd: sound { + compatible = "qcom,kona-asoc-snd"; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + qcom,tdm-audio-intf = <1>; + qcom,wcn-bt = <0>; + qcom,ext-disp-audio-rx = <0>; + qcom,afe-rxtx-lb = <0>; + + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, <&dai_dp1>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_mi2s5>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&dai_sen_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&proxy_rx>, <&proxy_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&sb_7_rx>, <&sb_7_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&dai_sen_tdm_rx_0>, <&dai_sen_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&va_cdc_dma_2_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&rx_cdc_dma_6_rx>, <&rx_cdc_dma_7_rx>, + <&afe_loopback_tx>; + asoc-cpu-names = "msm-dai-q6-dp.0", "msm-dai-q6-dp.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.5", + "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-auxpcm.6", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36944", "msm-dai-q6-tdm.36945", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45093", + "msm-dai-cdc-dma-dev.45104", + "msm-dai-cdc-dma-dev.45105", + "msm-dai-cdc-dma-dev.45106", + "msm-dai-cdc-dma-dev.45107", + "msm-dai-cdc-dma-dev.45108", + "msm-dai-cdc-dma-dev.45109", + "msm-dai-cdc-dma-dev.45110", + "msm-dai-cdc-dma-dev.45111", + "msm-dai-cdc-dma-dev.45112", + "msm-dai-cdc-dma-dev.45113", + "msm-dai-cdc-dma-dev.45114", + "msm-dai-cdc-dma-dev.45115", + "msm-dai-cdc-dma-dev.45116", + "msm-dai-cdc-dma-dev.45118", + "msm-dai-q6-dev.24577"; + fsa4480-i2c-handle = <&fsa4480>; + }; +}; + +&qupv3_se15_i2c { + status = "ok"; + fsa4480: fsa4480@43 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x43>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-bus.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a7306484d3c74cc590524f47241f1f05a526ed99 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-bus.dtsi @@ -0,0 +1,2250 @@ +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x016E0000 0x1f180>, + <0x1700000 0x3d180>, + <0x1500000 0x28000>, + <0x90C0000 0x4200>, + <0x9100000 0xae200>, + <0x9100000 0xae200>, + <0x1740000 0x1f080>, + <0x1620000 0x1c200>, + <0x1620000 0x40000>, + <0x1700000 0x3d180>, + <0x9990000 0x1600>; + + reg-names = "aggre1_noc-base", "aggre2_noc-base", + "config_noc-base", "dc_noc-base", + "mc_virt-base", "gem_noc-base", + "mmss_noc-base", "system_noc-base", + "ipa_virt-base", "compute_noc-base", "npu_noc-base"; + + /*RSCs*/ + rsc_apps: rsc-apps { + cell-id = ; + label = "apps_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + rsc_disp: rsc-disp { + cell-id = ; + label = "disp_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + /*BCMs*/ + bcm_acv: bcm-acv { + cell-id = ; + label = "ACV"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_alc: bcm-alc { + cell-id = ; + label = "ALC"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mc0: bcm-mc0 { + cell-id = ; + label = "MC0"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh0: bcm-sh0 { + cell-id = ; + label = "SH0"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm0: bcm-mm0 { + cell-id = ; + label = "MM0"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ce0: bcm-ce0 { + cell-id = ; + label = "CE0"; + qcom,bcm-name = "CE0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm1: bcm-mm1 { + cell-id = ; + label = "MM1"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh2: bcm-sh2 { + cell-id = ; + label = "SH2"; + qcom,bcm-name = "SH2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm2: bcm-mm2 { + cell-id = ; + label = "MM2"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_qup0: bcm-qup0 { + cell-id = ; + label = "QUP0"; + qcom,bcm-name = "QUP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh3: bcm-sh3 { + cell-id = ; + label = "SH3"; + qcom,bcm-name = "SH3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm3: bcm-mm3 { + cell-id = ; + label = "MM3"; + qcom,bcm-name = "MM3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh4: bcm-sh4 { + cell-id = ; + label = "SH4"; + qcom,bcm-name = "SH4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn0: bcm-sn0 { + cell-id = ; + label = "SN0"; + qcom,bcm-name = "SN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co0: bcm-co0 { + cell-id = ; + label = "CO0"; + qcom,bcm-name = "CO0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn0: bcm-cn0 { + cell-id = ; + label = "CN0"; + qcom,bcm-name = "CN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn2: bcm-sn2 { + cell-id = ; + label = "SN2"; + qcom,bcm-name = "SN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co2: bcm-co2 { + cell-id = ; + label = "CO2"; + qcom,bcm-name = "CO2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn4: bcm-sn4 { + cell-id = ; + label = "SN4"; + qcom,bcm-name = "SN4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn5: bcm-sn5 { + cell-id = ; + label = "SN5"; + qcom,bcm-name = "SN5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn6: bcm-sn6 { + cell-id = ; + label = "SN6"; + qcom,bcm-name = "SN6"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn7: bcm-sn7 { + cell-id = ; + label = "SN7"; + qcom,bcm-name = "SN7"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn8: bcm-sn8 { + cell-id = ; + label = "SN8"; + qcom,bcm-name = "SN8"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn9: bcm-sn9 { + cell-id = ; + label = "SN9"; + qcom,bcm-name = "SN9"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn11: bcm-sn11 { + cell-id = ; + label = "SN11"; + qcom,bcm-name = "SN11"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn12: bcm-sn12 { + cell-id = ; + label = "SN12"; + qcom,bcm-name = "SN12"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_acv_display: bcm-acv_display { + cell-id = ; + label = "ACV_DISPLAY"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_alc_display: bcm-alc_display { + cell-id = ; + label = "ALC_DISPLAY"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mc0_display: bcm-mc0_display { + cell-id = ; + label = "MC0_DISPLAY"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_sh0_display: bcm-sh0_display { + cell-id = ; + label = "SH0_DISPLAY"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm0_display: bcm-mm0_display { + cell-id = ; + label = "MM0_DISPLAY"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm1_display: bcm-mm1_display { + cell-id = ; + label = "MM1_DISPLAY"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm2_display: bcm-mm2_display { + cell-id = ; + label = "MM2_DISPLAY"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + + /*Buses*/ + fab_aggre1_noc: fab-aggre1_noc { + cell-id = ; + label = "fab-aggre1_noc"; + qcom,fab-dev; + qcom,base-name = "aggre1_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <8192>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_aggre2_noc: fab-aggre2_noc { + cell-id = ; + label = "fab-aggre2_noc"; + qcom,fab-dev; + qcom,base-name = "aggre2_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <12288>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_compute_noc: fab-compute_noc { + cell-id = ; + label = "fab-compute_noc"; + qcom,fab-dev; + qcom,base-name = "compute_noc-base"; + qcom,qos-off = <2048>; + qcom,base-offset = <208896>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <24576>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_dc_noc: fab-dc_noc { + cell-id = ; + label = "fab-dc_noc"; + qcom,fab-dev; + qcom,base-name = "dc_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc: fab-gem_noc { + cell-id = ; + label = "fab-gem_noc"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <135168>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_ipa_virt: fab-ipa_virt { + cell-id = ; + label = "fab-ipa_virt"; + qcom,fab-dev; + qcom,base-name = "ipa_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mc_virt: fab-mc_virt { + cell-id = ; + label = "fab-mc_virt"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mmss_noc: fab-mmss_noc { + cell-id = ; + label = "fab-mmss_noc"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <2048>; + qcom,base-offset = <40960>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_npu_noc: fab-npu_noc { + cell-id = ; + label = "fab-npu_noc"; + qcom,fab-dev; + qcom,base-name = "npu_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_system_noc: fab-system_noc { + cell-id = ; + label = "fab-system_noc"; + qcom,fab-dev; + qcom,base-name = "system_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <73728>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc_display: fab-gem_noc_display { + cell-id = ; + label = "fab-gem_noc_display"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <135168>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mc_virt_display: fab-mc_virt_display { + cell-id = ; + label = "fab-mc_virt_display"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mmss_noc_display: fab-mmss_noc_display { + cell-id = ; + label = "fab-mmss_noc_display"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <2048>; + qcom,base-offset = <40960>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + + /*Masters*/ + + mas_qhm_a1noc_cfg: mas-qhm-a1noc-cfg { + cell-id = ; + label = "mas-qhm-a1noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre1_noc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_qhm_qspi: mas-qhm-qspi { + cell-id = ; + label = "mas-qhm-qspi"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup1: mas-qhm-qup1 { + cell-id = ; + label = "mas-qhm-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_qup0>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup2: mas-qhm-qup2 { + cell-id = ; + label = "mas-qhm-qup2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_qup0>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_tsif: mas-qhm-tsif { + cell-id = ; + label = "mas-qhm-tsif"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_pcie3_modem: mas-xm-pcie3-modem { + cell-id = ; + label = "mas-xm-pcie3-modem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_pcie_modem_mem_noc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_sdc4: mas-xm-sdc4 { + cell-id = ; + label = "mas-xm-sdc4"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + clock-names = + "clk-aggre-ufs-phy-axi-no-rate"; + }; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-usb3-prim-axi-no-rate"; + }; + }; + + mas_xm_usb3_1: mas-xm-usb3-1 { + cell-id = ; + label = "mas-xm-usb3-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&clock_gcc GCC_AGGRE_USB3_SEC_AXI_CLK>; + clock-names = + "clk-usb3-sec-axi-no-rate"; + }; + }; + + mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg { + cell-id = ; + label = "mas-qhm-a2noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre2_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <11>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup0: mas-qhm-qup0 { + cell-id = ; + label = "mas-qhm-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <12>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_qup0>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qnm_cnoc: mas-qnm-cnoc { + cell-id = ; + label = "mas-qnm-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_ce0>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; + }; + + mas_xm_pcie3_0: mas-xm-pcie3-0 { + cell-id = ; + label = "mas-xm-pcie3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_pcie_mem_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_pcie3_1: mas-xm-pcie3-1 { + cell-id = ; + label = "mas-xm-pcie3-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <9>; + qcom,connections = <&slv_qns_pcie_mem_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_ufs_card: mas-xm-ufs-card { + cell-id = ; + label = "mas-xm-ufs-card"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,blacklist = <&slv_qns_cnoc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qnm_npu: mas-qnm-npu { + cell-id = ; + label = "mas-qnm-npu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <6 7>; + qcom,connections = <&slv_qns_cdsp_mem_noc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co2>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc: mas-qnm-snoc { + cell-id = ; + label = "mas-qnm-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_compute_dsp + &slv_qhs_camera_cfg &slv_qhs_tlmm1 + &slv_qhs_tlmm0 &slv_qhs_sdc4 + &slv_qhs_tlmm2 &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_snoc_cfg &slv_qhs_pdm + &slv_qhs_cx_rdpm &slv_qhs_pcie1_cfg + &slv_qhs_a2_noc_cfg &slv_qhs_qdss_cfg + &slv_qhs_display_cfg &slv_qhs_pcie_modem_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qhs_ipc_router + &slv_qhs_pcie0_cfg &slv_qhs_cpr_mmcx + &slv_qhs_npu_cfg &slv_qhs_ahb2phy0 + &slv_qhs_ahb2phy1 &slv_qhs_gpuss_cfg + &slv_qhs_venus_cfg &slv_qhs_tsif + &slv_qhs_ipa &slv_qhs_imem_cfg + &slv_qhs_usb3_0 &slv_srvc_cnoc + &slv_qhs_ufs_card_cfg &slv_qhs_usb3_1 + &slv_qhs_lpass_cfg &slv_qhs_cpr_cx + &slv_qhs_a1_noc_cfg &slv_qhs_aoss + &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg + &slv_qhs_qspi &slv_qhs_crypto0_cfg + &slv_qhs_pimem_cfg &slv_qhs_cpr_mx + &slv_qhs_qup0 &slv_qhs_qup1 + &slv_qhs_qup2 &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_xm_qdss_dap: mas-xm-qdss-dap { + cell-id = ; + label = "mas-xm-qdss-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_compute_dsp + &slv_qhs_camera_cfg &slv_qhs_tlmm1 + &slv_qhs_tlmm0 &slv_qhs_sdc4 + &slv_qhs_tlmm2 &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_snoc_cfg &slv_qhs_pdm + &slv_qhs_cx_rdpm &slv_qhs_pcie1_cfg + &slv_qhs_a2_noc_cfg &slv_qhs_qdss_cfg + &slv_qhs_display_cfg &slv_qhs_pcie_modem_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qhs_ipc_router + &slv_qns_cnoc_a2noc &slv_qhs_pcie0_cfg + &slv_qhs_cpr_mmcx &slv_qhs_npu_cfg + &slv_qhs_ahb2phy0 &slv_qhs_ahb2phy1 + &slv_qhs_gpuss_cfg &slv_qhs_venus_cfg + &slv_qhs_tsif &slv_qhs_ipa + &slv_qhs_imem_cfg &slv_qhs_usb3_0 + &slv_srvc_cnoc &slv_qhs_ufs_card_cfg + &slv_qhs_usb3_1 &slv_qhs_lpass_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_vsense_ctrl_cfg &slv_qhs_qspi + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_cpr_mx &slv_qhs_qup0 + &slv_qhs_qup1 &slv_qhs_qup2 + &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + qcom,blacklist = <&slv_qns_gem_noc_snoc>; + }; + + mas_qhm_cnoc_dc_noc: mas-qhm-cnoc-dc-noc { + cell-id = ; + label = "mas-qhm-cnoc-dc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_memnoc &slv_qhs_llcc>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + mas_alm_gpu_tcu: mas-alm-gpu-tcu { + cell-id = ; + label = "mas-alm-gpu-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <127>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh2>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_alm_sys_tcu: mas-alm-sys-tcu { + cell-id = ; + label = "mas-alm-sys-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <128>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh2>; + qcom,ap-owned; + qcom,prio = <6>; + }; + + mas_chm_apps: mas-chm-apps { + cell-id = ; + label = "mas-chm-apps"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc &slv_qns_sys_pcie>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh4>; + }; + + mas_qhm_gemnoc_cfg: mas-qhm-gemnoc-cfg { + cell-id = ; + label = "mas-qhm-gemnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_odd_gemnoc + &slv_srvc_even_gemnoc &slv_srvc_sys_gemnoc>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + mas_qnm_cmpnoc: mas-qnm-cmpnoc { + cell-id = ; + label = "mas-qnm-cmpnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <0 64>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_gpu: mas-qnm-gpu { + cell-id = ; + label = "mas-qnm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <1 65>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { + cell-id = ; + label = "mas-qnm-mnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <2 66>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { + cell-id = ; + label = "mas-qnm-mnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <3 67>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_pcie: mas-qnm-pcie { + cell-id = ; + label = "mas-qnm-pcie"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <129>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <130>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc_sf: mas-qnm-snoc-sf { + cell-id = ; + label = "mas-qnm-snoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <131>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc &slv_qns_sys_pcie>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_ipa_core_master: mas-ipa-core-master { + cell-id = ; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ipa_core_slave>; + qcom,bus-dev = <&fab_ipa_virt>; + }; + + mas_llcc_mc: mas-llcc-mc { + cell-id = ; + label = "mas-llcc-mc"; + qcom,buswidth = <4>; + qcom,agg-ports = <4>; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_mc_virt>; + }; + + mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { + cell-id = ; + label = "mas-qhm-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + mas_qnm_camnoc_hf: mas-qnm-camnoc-hf { + cell-id = ; + label = "mas-qnm-camnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <4 5>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_camnoc_icp: mas-qnm-camnoc-icp { + cell-id = ; + label = "mas-qnm-camnoc-icp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <5>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_camnoc_sf: mas-qnm-camnoc-sf { + cell-id = ; + label = "mas-qnm-camnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <0 1>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_video0: mas-qnm-video0 { + cell-id = ; + label = "mas-qnm-video0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <12>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_video1: mas-qnm-video1 { + cell-id = ; + label = "mas-qnm-video1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <13>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_video_cvp: mas-qnm-video-cvp { + cell-id = ; + label = "mas-qnm-video-cvp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <14>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp1: mas-qxm-mdp1 { + cell-id = ; + label = "mas-qxm-mdp1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_rot: mas-qxm-rot { + cell-id = ; + label = "mas-qxm-rot"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <10>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_amm_npu_sys: mas-amm-npu-sys { + cell-id = ; + label = "mas-amm-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <4>; + qcom,connections = <&slv_qns_npu_sys>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_amm_npu_sys_cdp_w: mas-amm-npu-sys-cdp-w { + cell-id = ; + label = "mas-amm-npu-sys-cdp-w"; + qcom,buswidth = <16>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_npu_sys>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qhm_cfg: mas-qhm-cfg { + cell-id = ; + label = "mas-qhm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_noc + &slv_qhs_isense &slv_qhs_llm + &slv_qhs_dma_bwmon &slv_qhs_cp + &slv_qhs_tcm &slv_qhs_cal_dp0 + &slv_qhs_cal_dp1 &slv_qhs_dpm>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { + cell-id = ; + label = "mas-qhm-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qnm_aggre1_noc: mas-qnm-aggre1-noc { + cell-id = ; + label = "mas-qnm-aggre1-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn7>; + }; + + mas_qnm_aggre2_noc: mas-qnm-aggre2-noc { + cell-id = ; + label = "mas-qnm-aggre2-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn8>; + }; + + mas_qnm_gemnoc: mas-qnm-gemnoc { + cell-id = ; + label = "mas-qnm-gemnoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss + &slv_qns_cnoc &slv_xs_sys_tcu_cfg + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn11>; + }; + + mas_qnm_gemnoc_pcie: mas-qnm-gemnoc-pcie { + cell-id = ; + label = "mas-qnm-gemnoc-pcie"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_xs_pcie_modem + &slv_xs_pcie_0 &slv_xs_pcie_1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn9>; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_gemnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_xm_gic: mas-xm-gic { + cell-id = ; + label = "mas-xm-gic"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_gemnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_alc: mas-alc { + cell-id = ; + label = "mas-alc"; + qcom,buswidth = <1>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_alc>; + }; + + mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display { + cell-id = ; + label = "mas-qnm-mnoc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <2 66>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display { + cell-id = ; + label = "mas-qnm-mnoc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <3 67>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_llcc_mc_display: mas-llcc-mc_display { + cell-id = ; + label = "mas-llcc-mc_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <4>; + qcom,connections = <&slv_ebi_display>; + qcom,bus-dev = <&fab_mc_virt_display>; + }; + + mas_qxm_mdp0_display: mas-qxm-mdp0_display { + cell-id = ; + label = "mas-qxm-mdp0_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_mdp1_display: mas-qxm-mdp1_display { + cell-id = ; + label = "mas-qxm-mdp1_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_rot_display: mas-qxm-rot_display { + cell-id = ; + label = "mas-qxm-rot_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <10>; + qcom,connections = <&slv_qns_mem_noc_sf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + }; + + /*Internal nodes*/ + + /*Slaves*/ + + slv_qns_a1noc_snoc:slv-qns-a1noc-snoc { + cell-id = ; + label = "slv-qns-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_aggre1_noc>; + }; + + slv_qns_pcie_modem_mem_noc:slv-qns-pcie-modem-mem-noc { + cell-id = ; + label = "slv-qns-pcie-modem-mem-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_pcie>; + qcom,bcms = <&bcm_sn12>; + }; + + slv_srvc_aggre1_noc:slv-srvc-aggre1-noc { + cell-id = ; + label = "slv-srvc-aggre1-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + slv_qns_a2noc_snoc:slv-qns-a2noc-snoc { + cell-id = ; + label = "slv-qns-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_aggre2_noc>; + }; + + slv_qns_pcie_mem_noc:slv-qns-pcie-mem-noc { + cell-id = ; + label = "slv-qns-pcie-mem-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_pcie>; + qcom,bcms = <&bcm_sn12>; + }; + + slv_srvc_aggre2_noc:slv-srvc-aggre2-noc { + cell-id = ; + label = "slv-srvc-aggre2-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + slv_qns_cdsp_mem_noc:slv-qns-cdsp-mem-noc { + cell-id = ; + label = "slv-qns-cdsp-mem-noc"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,connections = <&mas_qnm_cmpnoc>; + qcom,bcms = <&bcm_co0>; + }; + + slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg { + cell-id = ; + label = "slv-qhs-a1-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a1noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_a2_noc_cfg:slv-qhs-a2-noc-cfg { + cell-id = ; + label = "slv-qhs-a2-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a2noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy0:slv-qhs-ahb2phy0 { + cell-id = ; + label = "slv-qhs-ahb2phy0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy1:slv-qhs-ahb2phy1 { + cell-id = ; + label = "slv-qhs-ahb2phy1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_aoss:slv-qhs-aoss { + cell-id = ; + label = "slv-qhs-aoss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_cfg:slv-qhs-camera-cfg { + cell-id = ; + label = "slv-qhs-camera-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + qcom,disable-ports = <0 1 2>; + mmcx-supply = <&VDD_MMCX_LEVEL>; + node-reg-names = "mmcx"; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_compute_dsp:slv-qhs-compute-dsp { + cell-id = ; + label = "slv-qhs-compute-dsp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_cx:slv-qhs-cpr-cx { + cell-id = ; + label = "slv-qhs-cpr-cx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_mmcx:slv-qhs-cpr-mmcx { + cell-id = ; + label = "slv-qhs-cpr-mmcx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_mx:slv-qhs-cpr-mx { + cell-id = ; + label = "slv-qhs-cpr-mx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cx_rdpm:slv-qhs-cx-rdpm { + cell-id = ; + label = "slv-qhs-cx-rdpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_dcc_cfg:slv-qhs-dcc-cfg { + cell-id = ; + label = "slv-qhs-dcc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ddrss_cfg:slv-qhs-ddrss-cfg { + cell-id = ; + label = "slv-qhs-ddrss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cnoc_dc_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_cfg:slv-qhs-display-cfg { + cell-id = ; + label = "slv-qhs-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + qcom,disable-ports = <3 4>; + mmcx-supply = <&VDD_MMCX_LEVEL>; + node-reg-names = "mmcx"; + }; + + slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg { + cell-id = ; + label = "slv-qhs-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipc_router:slv-qhs-ipc-router { + cell-id = ; + label = "slv-qhs-ipc-router"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_lpass_cfg:slv-qhs-lpass-cfg { + cell-id = ; + label = "slv-qhs-lpass-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg { + cell-id = ; + label = "slv-qhs-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_mnoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_npu_cfg:slv-qhs-npu-cfg { + cell-id = ; + label = "slv-qhs-npu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pcie0_cfg:slv-qhs-pcie0-cfg { + cell-id = ; + label = "slv-qhs-pcie0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pcie1_cfg:slv-qhs-pcie1-cfg { + cell-id = ; + label = "slv-qhs-pcie1-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pcie_modem_cfg:slv-qhs-pcie-modem-cfg { + cell-id = ; + label = "slv-qhs-pcie-modem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qspi:slv-qhs-qspi { + cell-id = ; + label = "slv-qhs-qspi"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup0:slv-qhs-qup0 { + cell-id = ; + label = "slv-qhs-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup1:slv-qhs-qup1 { + cell-id = ; + label = "slv-qhs-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup2:slv-qhs-qup2 { + cell-id = ; + label = "slv-qhs-qup2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc4:slv-qhs-sdc4 { + cell-id = ; + label = "slv-qhs-sdc4"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_snoc_cfg:slv-qhs-snoc-cfg { + cell-id = ; + label = "slv-qhs-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_snoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm0:slv-qhs-tlmm0 { + cell-id = ; + label = "slv-qhs-tlmm0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm1:slv-qhs-tlmm1 { + cell-id = ; + label = "slv-qhs-tlmm1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm2:slv-qhs-tlmm2 { + cell-id = ; + label = "slv-qhs-tlmm2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tsif:slv-qhs-tsif { + cell-id = ; + label = "slv-qhs-tsif"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ufs_card_cfg:slv-qhs-ufs-card-cfg { + cell-id = ; + label = "slv-qhs-ufs-card-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg { + cell-id = ; + label = "slv-qhs-ufs-mem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_usb3_0:slv-qhs-usb3-0 { + cell-id = ; + label = "slv-qhs-usb3-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_usb3_1:slv-qhs-usb3-1 { + cell-id = ; + label = "slv-qhs-usb3-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + qcom,disable-ports = <5 6 7>; + mmcx-supply = <&VDD_MMCX_LEVEL>; + node-reg-names = "mmcx"; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qns_cnoc_a2noc:slv-qns-cnoc-a2noc { + cell-id = ; + label = "slv-qns-cnoc-a2noc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qnm_cnoc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_llcc:slv-qhs-llcc { + cell-id = ; + label = "slv-qhs-llcc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + slv_qhs_memnoc:slv-qhs-memnoc { + cell-id = ; + label = "slv-qhs-memnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + qcom,connections = <&mas_qhm_gemnoc_cfg>; + }; + + slv_qns_gem_noc_snoc:slv-qns-gem-noc-snoc { + cell-id = ; + label = "slv-qns-gem-noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_qnm_gemnoc>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <4>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_qns_sys_pcie:slv-qns-sys-pcie { + cell-id = ; + label = "slv-qns-sys-pcie"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_qnm_gemnoc_pcie>; + }; + + slv_srvc_even_gemnoc:slv-srvc-even-gemnoc { + cell-id = ; + label = "slv-srvc-even-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_srvc_odd_gemnoc:slv-srvc-odd-gemnoc { + cell-id = ; + label = "slv-srvc-odd-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_srvc_sys_gemnoc:slv-srvc-sys-gemnoc { + cell-id = ; + label = "slv-srvc-sys-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_ipa_virt>; + qcom,bcms = <&bcm_ip0>; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <4>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_mc0>, <&bcm_acv>; + }; + + slv_qns_mem_noc_hf:slv-qns-mem-noc-hf { + cell-id = ; + label = "slv-qns-mem-noc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_hf>; + qcom,bcms = <&bcm_mm0>; + }; + + slv_qns_mem_noc_sf:slv-qns-mem-noc-sf { + cell-id = ; + label = "slv-qns-mem-noc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_sf>; + qcom,bcms = <&bcm_mm2>; + }; + + slv_srvc_mnoc:slv-srvc-mnoc { + cell-id = ; + label = "slv-srvc-mnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + slv_qhs_cal_dp0:slv-qhs-cal-dp0 { + cell-id = ; + label = "slv-qhs-cal-dp0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_cal_dp1:slv-qhs-cal-dp1 { + cell-id = ; + label = "slv-qhs-cal-dp1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_cp:slv-qhs-cp { + cell-id = ; + label = "slv-qhs-cp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dma_bwmon:slv-qhs-dma-bwmon { + cell-id = ; + label = "slv-qhs-dma-bwmon"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dpm:slv-qhs-dpm { + cell-id = ; + label = "slv-qhs-dpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_isense:slv-qhs-isense { + cell-id = ; + label = "slv-qhs-isense"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_llm:slv-qhs-llm { + cell-id = ; + label = "slv-qhs-llm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_tcm:slv-qhs-tcm { + cell-id = ; + label = "slv-qhs-tcm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qns_npu_sys:slv-qns-npu-sys { + cell-id = ; + label = "slv-qns-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_srvc_noc:slv-srvc-noc { + cell-id = ; + label = "slv-srvc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_cnoc:slv-qns-cnoc { + cell-id = ; + label = "slv-qns-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc>; + }; + + slv_qns_gemnoc_gc:slv-qns-gemnoc-gc { + cell-id = ; + label = "slv-qns-gemnoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_gc>; + qcom,bcms = <&bcm_sn2>; + }; + + slv_qns_gemnoc_sf:slv-qns-gemnoc-sf { + cell-id = ; + label = "slv-qns-gemnoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_sf>; + qcom,bcms = <&bcm_sn0>; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn1>; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_xs_pcie_0:slv-xs-pcie-0 { + cell-id = ; + label = "slv-xs-pcie-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn6>; + }; + + slv_xs_pcie_1:slv-xs-pcie-1 { + cell-id = ; + label = "slv-xs-pcie-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn6>; + }; + + slv_xs_pcie_modem:slv-xs-pcie-modem { + cell-id = ; + label = "slv-xs-pcie-modem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn5>; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_llcc_display:slv-qns-llcc_display { + cell-id = ; + label = "slv-qns-llcc_display"; + qcom,buswidth = <16>; + qcom,agg-ports = <4>; + qcom,bus-dev = <&fab_gem_noc_display>; + qcom,connections = <&mas_llcc_mc_display>; + qcom,bcms = <&bcm_sh0_display>; + }; + + slv_ebi_display:slv-ebi_display { + cell-id = ; + label = "slv-ebi_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <4>; + qcom,bus-dev = <&fab_mc_virt_display>; + qcom,bcms = <&bcm_mc0_display>, <&bcm_acv_display>; + }; + + slv_qns_mem_noc_hf_display:slv-qns-mem-noc-hf_display { + cell-id = ; + label = "slv-qns-mem-noc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_hf_display>; + qcom,bcms = <&bcm_mm0_display>; + }; + + slv_qns_mem_noc_sf_display:slv-qns-mem-noc-sf_display { + cell-id = ; + label = "slv-qns-mem-noc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_sf_display>; + qcom,bcms = <&bcm_mm2_display>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5e4e20cb37d667f0601c1107b196ad0bb1a35afb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd-overlay.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/plugin/; + +#include "kona-cdp-lcd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona CDP (LCD)"; + compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp"; + qcom,board-id = <0x10101 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd.dts b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd.dts new file mode 100644 index 0000000000000000000000000000000000000000..d1e2288d4441a822ffb30564021225b82790e3be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-cdp-lcd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona CDP (LCD)"; + compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp"; + qcom,board-id = <0x10101 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a73e6a220bf6959d125f2ae238eb70f7afb6e84f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-lcd.dtsi @@ -0,0 +1,170 @@ +#include "kona-cdp.dtsi" + +&pm8150a_amoled { + status = "disabled"; +}; + +&pm8150l_lcdb { + status = "ok"; +}; + +&pm8150l_wled { + qcom,string-cfg = <7>; + status = "ok"; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0c]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x77>; + qcom,mdss-dsi-panel-on-check-value = <0x77>; + qcom,mdss-dsi-panel-status-read-length = <1>; + /delete-property/ qcom,platform-en-gpio; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0c]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x77>; + qcom,mdss-dsi-panel-on-check-value = <0x77>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-qsync-min-refresh-rate = <55>; + /delete-property/ qcom,platform-en-gpio; +}; + +&dsi_sharp_qsync_wqhd_cmd { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + /delete-property/ qcom,platform-en-gpio; +}; + +&dsi_sharp_qsync_wqhd_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + /delete-property/ qcom,platform-en-gpio; +}; + +&dsi_sharp_1080_cmd { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_dual_nt35597_truly_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; +}; + +&dsi_sim_sec_hd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply_avdd>; +}; + +&sde_dsi { + /delete-property/ avdd-supply; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,dsi-default-panel = <&dsi_sharp_4k_dsc_cmd>; +}; + +&sde_dsi1 { + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cdp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ad04489c9e11ac90cd6de98628657542d866cbb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp-overlay.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona CDP"; + compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp"; + qcom,board-id = <0x10001 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..d593aec82a71cae774bce71ce42d144bc1850e20 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona CDP"; + compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp"; + qcom,board-id = <0x10001 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..19e30f64227681f5bc05556fdc2beb9bd67292f4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cdp.dtsi @@ -0,0 +1,864 @@ +#include +#include + +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "camera/kona-camera-sensor-cdp.dtsi" +#include "kona-audio-overlay.dtsi" +#include "kona-thermal-overlay.dtsi" + +&qupv3_se12_2uart { + status = "ok"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&dai_mi2s2 { + qcom,msm-mi2s-tx-lines = <1>; +}; + +&q6core { + cdc_tert_mi2s_gpios: msm_cdc_pinctrl_tert { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep>; + }; +}; + +&kona_snd { + qcom,tert-mi2s-gpios = <&cdc_tert_mi2s_gpios>; +}; + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 111 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 110 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <111 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18800>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vcc-voltage-level = <2504000 2950000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8150_l6>; + vccq2-supply = <&pm8150_s4>; + vccq-max-microamp = <800000>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vccq-parent-supply = <&pm8150a_s8>; + qcom,vccq-parent-max-microamp = <210000>; + + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_home_default + &key_vol_up_default>; + + home { + label = "home"; + gpios = <&pm8150_gpios 1 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qcom,qbt_handler { + compatible = "qcom,qbt-handler"; + qcom,ipc-gpio = <&tlmm 23 0>; + qcom,finger-detect-gpio = <&pm8150_gpios 1 0>; + status = "disabled"; + }; +}; + +&qupv3_se13_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + vdd-supply = <&pm8150a_l1>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 39 0x2008>; + st,reset-gpio = <&tlmm 38 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + panel = <&dsi_sw43404_amoled_cmd &dsi_sw43404_amoled_video + &dsi_sw43404_amoled_fhd_plus_cmd>; + }; + + synaptics_dsx@22 { + compatible = "synaptics,dsx-i2c"; + reg = <0x22>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + vdd-supply = <&pm8150a_l1>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,ub-i2c-addr = <0x22>; + synaptics,max-y-for-2d = <1859>; + synaptics,irq-gpio = <&tlmm 39 0x2008>; + synaptics,reset-gpio = <&tlmm 38 0x0>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + + panel = <&dsi_sharp_qsync_wqhd_cmd &dsi_sharp_qsync_wqhd_video>; + }; + + focaltech@38 { + compatible = "focaltech,fts_ts"; + reg = <0x38>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + focaltech,reset-gpio = <&tlmm 38 0x00>; + focaltech,irq-gpio = <&tlmm 39 0x2008>; + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 1080 2340>; + + vdd-supply = <&pm8150_l13>; + + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend","pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + + panel = <&dsi_r66451_amoled_144hz_cmd>; + }; +}; + +&vendor { + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-sw-ctrl-gpio = <&tlmm 124 0>; /* SW_CTRL */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + }; + + extcon_usb1: extcon_usb1 { + compatible = "linux,extcon-usb-gpio"; + vbus-gpio = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; + id-gpio = <&tlmm 91 GPIO_ACTIVE_HIGH>; + vbus-out-gpio = <&pm8150_gpios 9 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_det_default + &usb2_id_det_default + &usb2_vbus_boost_default>; + }; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-en-gpio = <&tlmm 60 0>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-en-gpio = <&tlmm 60 0>; +}; + +&dsi_sharp_qsync_wqhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-en-gpio = <&tlmm 60 0>; +}; + +&dsi_sharp_qsync_wqhd_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-en-gpio = <&tlmm 60 0>; +}; + +&dsi_sharp_1080_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_nt35597_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_avdd>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_sec_hd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&dsi_r66451_amoled_144hz_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <255>; + qcom,mdss-dsi-bl-inverted-dbv; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; +}; + +&pm8150b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&pm8150b_charger { + status = "ok"; + qcom,batteryless-platform; + io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; +}; + +&pm8150b_fg { + status = "ok"; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@4d { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4e { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + camera_flash_therm@4d { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_msm_therm@4e { + reg = ; + label = "skin_msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm2@4f { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM3_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + camera_flash_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_debug_bus { + status = "ok"; +}; + +&kona_snd { + qcom,model = "kona-cdp-snd-card"; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "DMIC4", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC6", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "DMIC7", "MIC BIAS3", + "MIC BIAS3", "Digital Mic6", + "DMIC8", "MIC BIAS3", + "MIC BIAS3", "Digital Mic7", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&usb1 { + extcon = <&extcon_usb1>; +}; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-coresight.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b5c7e56251875a51428457dc9da728e7d07723d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-coresight.dtsi @@ -0,0 +1,3520 @@ +&soc { + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + replicator0_out_tmc_etr: endpoint { + remote-endpoint= + <&tmc_etr_in_replicator0>; + }; + }; + + port@1 { + reg = <0>; + replicator_cx_in_swao_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator_swao_out_cx_in>; + }; + }; + }; + }; + + replicator_swao: replicator@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + + reg = <0x6b06000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@0 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&eud_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_cx_in: endpoint { + remote-endpoint = + <&replicator_cx_in_swao_out>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator_swao>; + }; + }; + }; + }; + + dummy_eud: dummy_sink { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-eud"; + + qcom,dummy-sink; + port { + eud_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_eud>; + }; + }; + }; + + tmc_etf_swao: tmc@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + + reg = <0x6b05000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0_swao &cti3_swao>; + coresight-csr = <&swao_csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator_swao: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + }; + + funnel_swao: funnel@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6b04000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <3>; + funnel_swao_in_ssc_etm0: endpoint { + slave-mode; + remote-endpoint= + <&ssc_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <5>; + funnel_swao_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint= + <&audio_etm0_out_funnel_swao>; + }; + }; + + port@3 { + reg = <6>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + + port@4 { + reg = <7>; + funnel_swao_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint= + <&funnel_merg_out_funnel_swao>; + }; + }; + + port@5 { + reg = <5>; + funnel_swao_in_lpass_lpi: endpoint { + slave-mode; + remote-endpoint= + <&lpass_lpi_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x6b08000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + }; + }; + }; + + tpdm_swao0: tpdm@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + + reg = <0x6b09000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6b0a000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + iommus = <&apps_smmu 0x0480 0>, + <&apps_smmu 0x0520 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + arm,scatter-gather; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti3_swao>; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator0: endpoint { + slave-mode; + remote-endpoint = <&replicator0_out_tmc_etr>; + }; + }; + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_merg_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>, + <0x7820f0 0x4>; + reg-names = "stm-base", "stm-stimulus-base", "stm-debug-status"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@6b0c000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0c000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <1>; + funnel_in1_in_funnel_dl_north: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_north_out_funnel_in1>; + }; + }; + + port@2 { + reg = <4>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + }; + }; + + funnel_gpu: funnel@6902000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6902000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gpu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>, + <&clock_cpucc L3_GPU_VOTE_CLK>; + + clock-names = "apb_pclk", + "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + qcom,proxy-clks = "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + regulator-names = "vddcx", "vdd"; + qcom,proxy-regs = "vddcx", "vdd"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_gpu_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_gpu>; + }; + }; + + port@1 { + reg = <0>; + funnel_gpu_in_tpdm_gpu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gpu_out_funnel_gpu>; + }; + }; + }; + }; + + tpdm_gpu: tpdm@6900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6900000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gpu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>, + <&clock_cpucc L3_GPU_VOTE_CLK>; + clock-names = "apb_pclk", + "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + qcom,proxy-clks = "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + regulator-names = "vddcx", "vdd"; + qcom,proxy-regs = "vddcx", "vdd"; + + port { + tpdm_gpu_out_funnel_gpu: endpoint { + remote-endpoint = <&funnel_gpu_in_tpdm_gpu>; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <16 32>, + <24 32>, + <25 32>; + qcom,tc-elem-size = <16 32>, + <25 32>; + qcom,dsb-elem-size = <1 32>, + <6 32>, + <7 32>, + <10 32>, + <11 32>, + <12 32>, + <13 32>, + <14 32>, + <16 32>, + <19 32>, + <24 32>, + <25 32>; + qcom,cmb-elem-size = <7 64>, + <13 32>, + <15 32>, + <16 32>, + <17 32>, + <18 64>, + <20 64>, + <21 64>, + <22 32>, + <23 32>, + <25 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <1>; + tpda_in_funnel_gpu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gpu_out_tpda>; + }; + }; + + port@2 { + reg = <6>; + tpda_6_in_tpdm_venus: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_venus_out_tpda6>; + }; + }; + + port@3 { + reg = <7>; + tpda_7_in_tpdm_mdss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mdss_out_tpda7>; + }; + }; + + port@4 { + reg = <9>; + tpda_9_in_tpdm_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mm_out_tpda9>; + }; + }; + + port@5 { + reg = <10>; + tpda_10_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda_10>; + }; + }; + + port@6 { + reg = <11>; + tpda_11_in_tpdm_ddr_ch02: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_ch02_out_tpda11>; + }; + }; + + port@7 { + reg = <12>; + tpda_12_in_tpdm_ddr_ch13: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_ch13_out_tpda12>; + }; + }; + + port@8 { + reg = <13>; + tpda_13_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_tpda13>; + }; + }; + + port@9 { + reg = <14>; + tpda_14_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_tpda14>; + }; + }; + + port@10 { + reg = <15>; + tpda_15_in_tpdm_llm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_turing_out_tpda15>; + }; + }; + + port@11 { + reg = <16>; + tpda_16_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_tpda16>; + }; + }; + + port@12 { + reg = <17>; + tpda_17_in_tpdm_npu_llm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_llm_out_tpda17>; + }; + }; + + port@13 { + reg = <18>; + tpda_18_in_tpdm_npu_dpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_dpm_out_tpda18>; + }; + }; + + port@14 { + reg = <19>; + tpda_19_in_tpdm_dlct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct_out_tpda19>; + }; + }; + + port@15 { + reg = <20>; + tpda_20_in_tpdm_ipcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ipcc_out_tpda20>; + }; + }; + + port@16 { + reg = <21>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@17 { + reg = <22>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + + port@18 { + reg = <23>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@19 { + reg = <24>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + + port@20 { + reg = <25>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + }; + }; + + tpdm_dcc: tpdm@6870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + qcom,hw-enable-check; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + status = "disabled"; + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + funnel_lpass: funnel@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6846000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_lpass_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_lpass_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_lpass>; + }; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6844000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_lpass_out_funnel_lpass: endpoint { + remote-endpoint = <&funnel_lpass_in_tpdm_lpass>; + }; + }; + }; + + tpdm_dl_north: tpdm@6ac0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6ac0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_dl_north_out_tpda_dl_north: endpoint { + remote-endpoint = + <&tpda_dl_north_in_tpdm_dl_north>; + }; + }; + }; + + tpdm_lpass_lpi: tpdm@6b26000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-lpass-lpi"; + qcom,dummy-source; + + port { + lpass_lpi_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_lpass_lpi>; + }; + }; + }; + + tpda_dl_north: tpda@6ac1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x06ac1000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-dl-north"; + qcom,tpda-atid = <97>; + + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_dl_north_out_funnel_dl_north: endpoint { + remote-endpoint = + <&funnel_dl_north_in_tpda_dl_north>; + }; + }; + + port@1 { + reg = <0>; + tpda_dl_north_in_tpdm_dl_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_north_out_tpda_dl_north>; + }; + }; + }; + }; + + funnel_dl_south: funnel@69c2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x69c2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_south_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_dl_compute_in_funnel_dl_south>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_south_in_tpda_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpda_dl_south_out_funnel_dl_south>; + }; + }; + }; + }; + + tpda_dl_south: tpda@69c1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x69c1000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-dl-south"; + + qcom,tpda-atid = <75>; + qcom,dsb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_dl_south_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_tpda_dl_south>; + }; + + }; + + port@1 { + reg = <0>; + tpda_dl_south_in_tpdm_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_south_out_tpda_dl_south>; + }; + }; + }; + }; + + tpdm_dl_south: tpdm@69c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x69c0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_south_out_tpda_dl_south: endpoint { + remote-endpoint = + <&tpda_dl_south_in_tpdm_dl_south>; + }; + }; + }; + + funnel_dl_north: funnel@6ac2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6ac2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_north_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_dl_north>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_north_in_tpda_dl_north: endpoint { + slave-mode; + remote-endpoint = + <&tpda_dl_north_out_funnel_dl_north>; + }; + }; + }; + }; + + funnel_dl_compute: funnel@6c39000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c39000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-compute"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_compute_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_compute>; + }; + }; + + port@1 { + reg = <0>; + funnel_compute_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_funnel_dl_compute>; + }; + }; + + port@2 { + reg = <1>; + funnel_compute_in_funnel_npu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_npu_out_funnel_dl_compute>; + }; + }; + + port@3 { + reg = <3>; + funnel_dl_compute_in_funnel_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&funnel_south_out_funnel_dl_compute>; + }; + }; + }; + }; + + tpdm_npu: tpdm@6c47000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c47000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gcc GCC_NPU_AXI_CLK>, + <&clock_gcc GCC_NPU_CFG_AHB_CLK>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_CORE_CLK>, + <&clock_npucc NPU_CC_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_ATB_CLK>; + + clock-names = "apb_pclk", + "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk"; + + qcom,proxy-clks = "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-regs ="vdd", "vdd_cx"; + + port { + tpdm_npu_out_funnel_npu: endpoint { + remote-endpoint = <&funnel_npu_in_tpdm_npu>; + }; + }; + }; + + tpdm_npu_llm: tpdm@6c40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c40000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu-llm"; + clocks = <&clock_aop QDSS_CLK>, + <&clock_gcc GCC_NPU_AXI_CLK>, + <&clock_gcc GCC_NPU_CFG_AHB_CLK>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_CORE_CLK>, + <&clock_npucc NPU_CC_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_ATB_CLK>, + <&clock_npucc NPU_CC_LLM_CLK>, + <&clock_npucc NPU_CC_LLM_XO_CLK>, + <&clock_npucc NPU_CC_LLM_TEMP_CLK>, + <&clock_npucc NPU_CC_LLM_CURR_CLK>, + <&clock_npucc NPU_CC_DL_LLM_CLK>; + + clock-names = "apb_pclk", + "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk", + "npu_cc_llm_clk", + "npu_cc_llm_xo_clk", + "npu_cc_llm_temp_clk", + "npu_cc_llm_curr_clk", + "npu_cc_dl_llm_clk"; + + qcom,proxy-clks = "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk", + "npu_cc_llm_clk", + "npu_cc_llm_xo_clk", + "npu_cc_llm_temp_clk", + "npu_cc_llm_curr_clk", + "npu_cc_dl_llm_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-regs ="vdd", "vdd_cx"; + + port { + tpdm_npu_llm_out_funnel_npu: endpoint { + remote-endpoint = <&funnel_npu_in_tpdm_npu_llm>; + }; + }; + }; + + tpdm_npu_dpm: tpdm@6c41000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c41000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu-dpm"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gcc GCC_NPU_AXI_CLK>, + <&clock_gcc GCC_NPU_CFG_AHB_CLK>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_CORE_CLK>, + <&clock_npucc NPU_CC_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_ATB_CLK>, + <&clock_npucc NPU_CC_DPM_CLK>, + <&clock_npucc NPU_CC_DPM_XO_CLK>, + <&clock_npucc NPU_CC_DL_DPM_CLK>; + + clock-names = "apb_pclk", + "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk", + "npu_cc_dpm_clk", + "npu_cc_dpm_xo_clk", + "npu_cc_dl_dpm_clk"; + + qcom,proxy-clks = "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk", + "npu_cc_dpm_clk", + "npu_cc_dpm_xo_clk", + "npu_cc_dl_dpm_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-regs ="vdd", "vdd_cx"; + + port { + tpdm_npu_dpm_out_funnel_npu: endpoint { + remote-endpoint = <&funnel_npu_in_tpdm_npu_dpm>; + }; + }; + }; + + funnel_dl_center: funnel@6c2d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c2d000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-center"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpdm_venus_out_tpda6: endpoint { + remote-endpoint = + <&tpda_6_in_tpdm_venus>; + source = <&tpdm_venus>; + }; + }; + + port@1 { + reg = <1>; + tpdm_mdss_out_tpda7: endpoint { + remote-endpoint = + <&tpda_7_in_tpdm_mdss>; + source = <&tpdm_mdss>; + }; + }; + + port@2 { + reg = <2>; + tpdm_mm_out_tpda9: endpoint { + remote-endpoint = + <&tpda_9_in_tpdm_mm>; + source = <&tpdm_mm>; + }; + }; + + port@3 { + reg = <3>; + funnel_dl_center_out_tpda_10: endpoint { + remote-endpoint = + <&tpda_10_in_funnel_dl_center>; + source = <&tpdm_lpass>; + }; + }; + + port@4 { + reg = <4>; + tpdm_ddr_ch02_out_tpda11: endpoint { + remote-endpoint = + <&tpda_11_in_tpdm_ddr_ch02>; + source = <&tpdm_ddr_ch02>; + }; + }; + + port@5 { + reg = <5>; + tpdm_ddr_ch13_out_tpda12: endpoint { + remote-endpoint = + <&tpda_12_in_tpdm_ddr_ch13>; + source = <&tpdm_ddr_ch13>; + }; + }; + + port@6 { + reg = <6>; + tpdm_ddr_out_tpda13: endpoint { + remote-endpoint = + <&tpda_13_in_tpdm_ddr>; + source = <&tpdm_ddr>; + }; + }; + + port@7 { + reg = <7>; + tpdm_turing_out_tpda14: endpoint { + remote-endpoint = + <&tpda_14_in_tpdm_turing>; + source = <&tpdm_turing>; + }; + }; + + port@8 { + reg = <8>; + tpdm_llm_turing_out_tpda15: endpoint { + remote-endpoint = + <&tpda_15_in_tpdm_llm_turing>; + source = <&tpdm_llm_turing>; + }; + }; + + port@9 { + reg = <9>; + tpdm_npu_out_tpda16: endpoint { + remote-endpoint = + <&tpda_16_in_tpdm_npu>; + source = <&tpdm_npu>; + }; + }; + + port@10 { + reg = <10>; + tpdm_npu_llm_out_tpda17: endpoint { + remote-endpoint = + <&tpda_17_in_tpdm_npu_llm>; + source = <&tpdm_npu_llm>; + }; + }; + + port@11 { + reg = <11>; + tpdm_npu_dpm_out_tpda18: endpoint { + remote-endpoint = + <&tpda_18_in_tpdm_npu_dpm>; + source = <&tpdm_npu_dpm>; + }; + }; + + port@12 { + reg = <12>; + tpdm_dlct_out_tpda19: endpoint { + remote-endpoint = + <&tpda_19_in_tpdm_dlct>; + source = <&tpdm_dlct>; + }; + }; + + port@13 { + reg = <13>; + tpdm_ipcc_out_tpda20: endpoint { + remote-endpoint = + <&tpda_20_in_tpdm_ipcc>; + source = <&tpdm_ipcc>; + }; + }; + + port@14 { + reg = <14>; + funnel_dl_center_out_qatb3: endpoint { + remote-endpoint = + <&qatb3_in_funnel_dl_center>; + }; + }; + + port@15 { + reg = <2>; + funnel_dl_center_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_funnel_dl_center>; + }; + }; + + port@16 { + reg = <3>; + funnel_dl_center_in_funnel_lpass: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_out_funnel_dl_center>; + }; + }; + + port@17 { + reg = <4>; + funnel_dl_center_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_funnel_dl_center>; + }; + }; + + port@18 { + reg = <5>; + funnel_dl_center_in_funnel_compute: endpoint { + slave-mode; + remote-endpoint = + <&funnel_compute_out_funnel_dl_center>; + }; + }; + + port@19 { + reg = <6>; + funnel_center_in_tpdm_dlct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct_out_funnel_center>; + }; + }; + + port@20 { + reg = <7>; + funnel_center_in_tpdm_ipcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ipcc_out_funnel_center>; + }; + }; + }; + }; + + tpdm_dlct: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dlct"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dlct_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_tpdm_dlct>; + }; + }; + }; + + tpdm_ipcc: tpdm@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c29000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ipcc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_ipcc_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_tpdm_ipcc>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_qm>; + }; + }; + }; + + tpda_apss: tpda@7863000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x7863000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <3 32>; + qcom,cmb-elem-size = <0 32>, + <1 32>, + <2 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_apss>; + }; + }; + + port@2 { + reg = <1>; + tpda_apss_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_apss>; + }; + }; + + port@3 { + reg = <2>; + tpda_apss_in_tpdm_actpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_actpm_out_tpda_apss>; + }; + }; + + port@4 { + reg = <3>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_apss: endpoint { + remote-endpoint = + <&tpda_apss_in_tpdm_llm_silver>; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_apss: endpoint { + remote-endpoint = + <&tpda_apss_in_tpdm_llm_gold>; + }; + }; + }; + + tpdm_actpm: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-actpm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_actpm_out_tpda_apss: endpoint { + remote-endpoint = + <&tpda_apss_in_tpdm_actpm>; + }; + }; + }; + + tpdm_apss: tpdm@7861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x7861000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = + <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + funnel_dl_mm: funnel@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c0b000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_mm_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_mm_in_funnel_venus: endpoint { + slave-mode; + remote-endpoint = + <&funnel_venus_out_funnel_dl_mm>; + }; + }; + + port@2 { + reg = <1>; + funnel_dl_mm_in_tpdm_mdss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mdss_out_funnel_dl_mm>; + }; + }; + + port@3 { + reg = <3>; + funnel_dl_mm_in_tpdm_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mm_out_funnel_dl_mm>; + }; + }; + }; + }; + + funnel_venus: funnel@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6832000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-venus"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_venus_out_funnel_dl_mm: endpoint { + remote-endpoint = + <&funnel_dl_mm_in_funnel_venus>; + }; + }; + + port@1 { + reg = <0>; + funnel_venus_in_tpdm_venus: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_venus_out_funnel_venus>; + }; + }; + + }; + }; + + tpdm_venus: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-venus"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_venus_out_funnel_venus: endpoint { + remote-endpoint = + <&funnel_venus_in_tpdm_venus>; + }; + }; + }; + + tpdm_mdss: tpdm@6c60000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c60000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mdss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_mdss_out_funnel_dl_mm: endpoint { + remote-endpoint = + <&funnel_dl_mm_in_tpdm_mdss>; + }; + }; + }; + + tpdm_mm: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c08000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_mm_out_funnel_dl_mm: endpoint { + remote-endpoint = + <&funnel_dl_mm_in_tpdm_mm>; + }; + }; + }; + + funnel_npu: funnel@6c44000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c44000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-npu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gcc GCC_NPU_AXI_CLK>, + <&clock_gcc GCC_NPU_CFG_AHB_CLK>, + <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_CORE_CLK>, + <&clock_npucc NPU_CC_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_ATB_CLK>; + + clock-names = "apb_pclk", + "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk"; + + qcom,proxy-clks = "gcc_npu_axi_clk", + "gcc_npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_cc_atb_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + regulator-names = "vdd", "vdd_cx"; + qcom,proxy-regs ="vdd", "vdd_cx"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_npu_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_compute_in_funnel_npu>; + }; + }; + + port@1 { + reg = <0>; + funnel_npu_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_funnel_npu>; + }; + }; + + port@2 { + reg = <1>; + funnel_npu_in_tpdm_npu_llm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_llm_out_funnel_npu>; + }; + }; + + port@3 { + reg = <2>; + funnel_npu_in_tpdm_npu_dpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_dpm_out_funnel_npu>; + }; + }; + + port@4 { + reg = <3>; + funnel_npu_in_npu_etm0: endpoint { + slave-mode; + remote-endpoint = + <&npu_etm0_out_funnel_npu>; + }; + }; + }; + }; + + funnel_turing: funnel@6983000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6983000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_turing_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_compute_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + + port@2 { + reg = <1>; + funnel_turing_in_tpdm_llm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_turing_out_funnel_turing>; + }; + }; + + port@3 { + reg = <2>; + funnel_turing_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6980000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + tpdm_llm_turing: tpdm@69810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6981000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing-llm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + status = "disabled"; + + port { + tpdm_llm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_llm_turing>; + }; + }; + }; + + funnel_ddr_0: funnel@6e04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6e04000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_ddr_0_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_funnel_ddr_ch02: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_ch02_out_funnel_ddr_0>; + }; + }; + + port@2 { + reg = <1>; + funnel_ddr_0_in_funnel_ddr_ch13: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_ch13_out_funnel_ddr_0>; + }; + }; + + port@3 { + reg = <2>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + funnel_ddr_ch02: funnel@6e12000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6e12000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-ch02"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_ddr_ch02_out_funnel_ddr_0: endpoint { + remote-endpoint = + <&funnel_ddr_0_in_funnel_ddr_ch02>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_ch02_in_tpdm_ddr_ch02: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_ch02_out_funnel_ddr_ch02>; + }; + }; + }; + }; + + funnel_ddr_ch13: funnel@6e22000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6e22000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-ch13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_ddr_ch13_out_funnel_ddr_0: endpoint { + remote-endpoint = + <&funnel_ddr_0_in_funnel_ddr_ch13>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_ch13_in_tpdm_ddr_ch13: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_ch13_out_funnel_ddr_ch13>; + }; + }; + }; + }; + + tpdm_ddr_ch02: tpdm@6e10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x06e10000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr-ch02"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_ch02_out_funnel_ddr_ch02: endpoint { + remote-endpoint = + <&funnel_ddr_ch02_in_tpdm_ddr_ch02>; + }; + }; + }; + + tpdm_ddr_ch13: tpdm@6e20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x06e20000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr-ch13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_ch13_out_funnel_ddr_ch13: endpoint { + remote-endpoint = + <&funnel_ddr_ch13_in_tpdm_ddr_ch13>; + }; + }; + }; + + tpdm_ddr: tpdm@6e00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x06e00000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + status = "disabled"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <3>; + qatb3_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_qatb3>; + }; + }; + }; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6e01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e01000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6e02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ddr0: cti@6e03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6e0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e0c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6e0d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e0d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ddr1: cti@6e0e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e0e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_ch02: cti@6e11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_ch02_dl_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_ch13: cti@6e21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_ch13_dl_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_dlct: cti@6c2c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,cti-gpio-trigout = <4>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti_cpu0: cti@7020000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7020000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti_cpu1: cti@7120000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7120000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@7220000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7220000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@7320000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7320000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu4: cti@7420000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7420000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@7520000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7520000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@7620000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7620000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@7720000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7720000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_m3: cti@6962000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6962000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-gpu_cortex_m3"; + status = "disabled"; + clocks = <&clock_aop QDSS_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>, + <&clock_cpucc L3_GPU_VOTE_CLK>; + + clock-names = "apb_pclk", + "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + qcom,proxy-clks = "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + regulator-names = "vddcx", "vdd"; + qcom,proxy-regs = "vddcx", "vdd"; + }; + + cti_gpu_isdb: cti@6961000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6961000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-gpu_isdb_cti"; + status = "disabled"; + clocks = <&clock_aop QDSS_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>, + <&clock_cpucc L3_GPU_VOTE_CLK>; + + clock-names = "apb_pclk", + "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + qcom,proxy-clks = "rbbmtimer_clk", + "mem_clk", + "mem_iface_clk", + "gmu_clk", + "gpu_cc_ahb", + "l3_vote"; + + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + regulator-names = "vddcx", "vdd"; + qcom,proxy-regs = "vddcx", "vdd"; + }; + + cti_iris: cti@6831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6831000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-iris_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass: cti@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6845000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_lpi: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass_lpi_cti"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_q6: cti@6b2b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b2b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass_q6_cti"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mdss: cti@6c61000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c61000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mdss_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl0: cti@6c42000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c42000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl1: cti@6c43000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c43000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu: cti@6c4b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c4b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_q6_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_titan: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-sierra_a6_cti"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_sdc: cti@6b40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b40000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_cortex_m3"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ssc0: cti@6b4b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b4b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_cti0_q6"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ssc1: cti@6b41000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b41000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_cti1"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ssc4: cti@6b4e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b4e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ssc_cti_noc"; + status = "disabled"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao:cti@6b00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b00000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao:cti@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b01000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao:cti@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao:cti@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing:cti@6982000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6982000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_q6:cti@698b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x698b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_q6_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_compute:cti@6c38000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c38000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-compute_dl_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + ipcb_tgu: tgu@6b0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb999>; + reg = <0x06b0b000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + etm_turing: turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port { + turing_etm0_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_turing_etm0>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_audio_etm0>; + }; + }; + }; + + ssc_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-ssc-etm0"; + qcom,inst-id = <8>; + + port { + ssc_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_ssc_etm0>; + }; + }; + }; + + npu_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-npu-etm0"; + qcom,inst-id = <14>; + + port { + npu_etm0_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_npu_etm0>; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <3>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + hwevent { + compatible = "qcom,coresight-hwevent"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-cvp.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-cvp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..460cd4ac47ffce278ca67b7e83d8758c3e5c2fc9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-cvp.dtsi @@ -0,0 +1,93 @@ +#include +#include +#include + +&soc { + msm_cvp: qcom,cvp@ab00000 { + compatible = "qcom,msm-cvp", "qcom,kona-cvp"; + status = "ok"; + reg = <0xab00000 0x100000>; + interrupts = ; + + /* LLCC Cache */ + cache-slice-names = "cvp"; + + /* Supply */ + cvp-supply = <&mvs1c_gdsc>; + cvp-core-supply = <&mvs1_gdsc>; + + /* Clocks */ + clock-names = "gcc_video_axi1", "cvp_clk", "core_clk"; + clocks = <&clock_gcc GCC_VIDEO_AXI1_CLK>, + <&clock_videocc VIDEO_CC_MVS1C_CLK>, + <&clock_videocc VIDEO_CC_MVS1_CLK>; + qcom,proxy-clock-names = "gcc_video_axi1", + "cvp_clk", "core_clk"; + + /* V2 clock frequency plan */ + qcom,clock-configs = <0x0 0x1 0x1>; + qcom,allowed-clock-rates = <280000000 366000000 444000000>; + + resets = <&clock_gcc GCC_VIDEO_AXI1_CLK_ARES>, + <&clock_videocc VIDEO_CC_MVS1C_CLK_ARES>; + reset-names = "cvp_axi_reset", "cvp_core_reset"; + + qcom,reg-presets = <0xB0088 0x0>; + + /* Buses */ + cvp_cnoc { + compatible = "qcom,msm-cvp,bus"; + label = "cvp-cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + cvp_bus_ddr { + compatible = "qcom,msm-cvp,bus"; + label = "cvp-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 6533000>; + }; + + /* MMUs */ + cvp_non_secure_cb { + compatible = "qcom,msm-cvp,context-bank"; + label = "cvp_hlos"; + iommus = + <&apps_smmu 0x2120 0x400>; + buffer-types = <0xfff>; + qcom,iommu-dma-addr-pool = <0x4b000000 0x90000000>; + }; + + + cvp_secure_nonpixel_cb { + compatible = "qcom,msm-cvp,context-bank"; + label = "cvp_sec_nonpixel"; + iommus = + <&apps_smmu 0x2124 0x400>; + buffer-types = <0x741>; + qcom,iommu-dma-addr-pool = <0x01000000 0x25800000>; + qcom,iommu-vmid = <0xB>; + }; + + cvp_secure_pixel_cb { + compatible = "qcom,msm-cvp,context-bank"; + label = "cvp_sec_pixel"; + iommus = + <&apps_smmu 0x2123 0x400>; + buffer-types = <0x106>; + qcom,iommu-dma-addr-pool = <0x26800000 0x24800000>; + qcom,iommu-vmid = <0xA>; + }; + + /* Memory Heaps */ + qcom,msm-cvp,mem_cdsp { + compatible = "qcom,msm-cvp,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..12af820076ee13ccf8f66e14979c835838eddd54 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-gpu.dtsi @@ -0,0 +1,349 @@ + +#define MHZ_TO_KBPS(mhz, w) ((mhz * 1000000 * w) / (1024)) + +&soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a650_zap"; + }; + + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + operating-points-v2 = <&gpu_opp_table>; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw-ddr"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = ; + }; + + opp-381000000 { + opp-hz = /bits/ 64 <381000000>; + opp-microvolt = ; + }; + + opp-290000000 { + opp-hz = /bits/ 64 <290000000>; + opp-microvolt = ; + }; + }; + + msm_gpu: qcom,kgsl-3d0@3d00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x3d00000 0x40000>, <0x3d61000 0x800>, + <0x3de0000 0x10000>, <0x3d8b000 0x2000>, + <0x06900000 0x80000>; + reg-names = "kgsl_3d0_reg_memory", "cx_dbgc", "rscc", + "isense_cntl", "qdss_gfx"; + interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x06050000>; + + qcom,initial-pwrlevel = <2>; + + qcom,idle-timeout = <80>; /* msecs */ + + qcom,no-nap; + + qcom,highest-bank-bit = <16>; + + qcom,min-access-length = <32>; + + qcom,ubwc-mode = <4>; + + qcom,snapshot-size = <0x200000>; /* bytes */ + + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; /* base addr, size */ + + #cooling-cells = <2>; + + qcom,tzone-name = "gpuss-max-step"; + + qcom,pm-qos-active-latency = <44>; + + clocks = <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>, + <&clock_cpucc L3_GPU_VOTE_CLK>; + + clock-names = "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk", + "gpu_cc_ahb", "l3_vote"; + + qcom,isense-clk-on-level = <1>; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* GPU OPP data */ + operating-points-v2 = <&gpu_opp_table>; + + nvmem-cells = <&gpu_lm_efuse>, <&gpu_speed_bin>; + nvmem-cell-names = "isense_slope", "speed_bin"; + + qcom,bus-accesses-ddr7 = <970>; + qcom,bus-accesses-ddr8 = <1162>; + + /* bus table */ + qcom,gpu-bus-table-0 { + compatible = "qcom,gpu-bus-table", + "qcom,gpu-bus-table-ddr7"; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 MHZ_TO_KBPS(0, 4)>, /* index=0 */ + <26 512 0 MHZ_TO_KBPS(200, 4)>, /* index=1 */ + <26 512 0 MHZ_TO_KBPS(300, 4)>, /* index=2 */ + <26 512 0 MHZ_TO_KBPS(451, 4)>, /* index=3 */ + <26 512 0 MHZ_TO_KBPS(547, 4)>, /* index=4 */ + <26 512 0 MHZ_TO_KBPS(681, 4)>, /* index=5 */ + <26 512 0 MHZ_TO_KBPS(768, 4)>, /* index=6 */ + <26 512 0 MHZ_TO_KBPS(1017, 4)>, /* index=7 */ + <26 512 0 MHZ_TO_KBPS(1353, 4)>, /* index=8 */ + <26 512 0 MHZ_TO_KBPS(1555, 4)>, /* index=9 */ + <26 512 0 MHZ_TO_KBPS(1804, 4)>, /* index=10 */ + <26 512 0 MHZ_TO_KBPS(2092, 4)>; /* index=11 */ + }; + + qcom,gpu-bus-table-1 { + compatible = "qcom,gpu-bus-table", + "qcom,gpu-bus-table-ddr8"; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 MHZ_TO_KBPS(0, 4)>, /* index=0 */ + <26 512 0 MHZ_TO_KBPS(200, 4)>, /* index=1 */ + <26 512 0 MHZ_TO_KBPS(300, 4)>, /* index=2 */ + <26 512 0 MHZ_TO_KBPS(451, 4)>, /* index=3 */ + <26 512 0 MHZ_TO_KBPS(547, 4)>, /* index=4 */ + <26 512 0 MHZ_TO_KBPS(681, 4)>, /* index=5 */ + <26 512 0 MHZ_TO_KBPS(768, 4)>, /* index=6 */ + <26 512 0 MHZ_TO_KBPS(1017, 4)>, /* index=7 */ + <26 512 0 MHZ_TO_KBPS(1555, 4)>, /* index=8 */ + <26 512 0 MHZ_TO_KBPS(1804, 4)>, /* index=9 */ + <26 512 0 MHZ_TO_KBPS(2092, 4)>, /* index=10 */ + <26 512 0 MHZ_TO_KBPS(2736, 4)>; /* index=11 */ + }; + + qcom,l3-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,l3-pwrlevels"; + + qcom,l3-pwrlevel@0 { + reg = <0>; + qcom,l3-freq = <0>; + }; + + qcom,l3-pwrlevel@1 { + reg = <1>; + qcom,l3-freq = <864000000>; + }; + + qcom,l3-pwrlevel@2 { + reg = <2>; + qcom,l3-freq = <1344000000>; + }; + }; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-reserved = <2048>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-reserved = <1024>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* Power levels */ + qcom,gpu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <480000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <11>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <11>; + qcom,bus-max-ddr8 = <11>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <381000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <7>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <11>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <290000000>; + qcom,bus-freq-ddr7 = <2>; + qcom,bus-min-ddr7 = <1>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <2>; + qcom,bus-min-ddr8 = <1>; + qcom,bus-max-ddr8 = <8>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@3da0000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x03da0000 0x10000>; + /* CB5(ATOS) & CB5/6/7 are protected by HYP */ + qcom,protect = <0xa0000 0xc000>; + + clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>; + clock-names = "gcc_gpu_memnoc_gfx", + "gcc_gpu_snoc_dvm_gfx", + "gpu_cc_ahb"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0x0 0x401>; + qcom,iommu-dma = "disabled"; + qcom,gpu-offset = <0xa8000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_secure"; + iommus = <&kgsl_smmu 0x2 0x400>; + qcom,iommu-dma = "disabled"; + }; + }; + + gmu: qcom,gmu@3d6a000 { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = <0x3d6a000 0x30000>, + <0xb290000 0x10000>, + <0xb490000 0x10000>; + reg-names = "kgsl_gmu_reg", + "kgsl_gmu_pdc_cfg", + "kgsl_gmu_pdc_seq"; + + interrupts = <0 304 IRQ_TYPE_LEVEL_HIGH>, + <0 305 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq"; + + qcom,msm-bus,name = "cnoc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 10036 0 0>, /* CNOC off */ + <26 10036 0 100>; /* CNOC on */ + + regulator-names = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>, + <&clock_gpucc GPU_CC_CXO_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>; + + clock-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk", "gpu_cc_ahb"; + + /* AOP mailbox for sending ACD enable and disable messages */ + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 0x4 0x400>; + qcom,iommu-dma = "disabled"; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 0x5 0x400>; + qcom,iommu-dma = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-hdk-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-hdk-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4368a5fa14246e051835a0e3377c667c19371dc0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-hdk-overlay.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona HDK"; + compatible = "qcom,kona-hdk", "qcom,kona", "qcom,hdk"; + qcom,board-id = <0x01001F 0x01>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-hdk.dts b/arch/arm64/boot/dts/vendor/qcom/kona-hdk.dts new file mode 100644 index 0000000000000000000000000000000000000000..0c62e71330e26f90bf2dc51c44eb7923c16b1983 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-hdk.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona HDK"; + compatible = "qcom,kona-hdk", "qcom,kona", "qcom,hdk"; + qcom,board-id = <0x01001F 0x01>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-hdk.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-hdk.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cc56bb53076f565bbcc33c970036ecc4cba9eebb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-hdk.dtsi @@ -0,0 +1,128 @@ +#include "kona-qrd.dtsi" + +&qupv3_se13_i2c { + status = "ok"; + qcom,i2c-touch-active = ""; + + st_fts@49 { + st,x-flip; + st,y-flip; + }; +}; + +&kona_snd { + qcom,msm-mbhc-usbc-audio-supported = <0>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; + +&redriver { + status = "disabled"; +}; + +&dwc1 { + dr_mode = "host"; +}; + +&usb2_phy0 { + qcom,param-override-seq = + <0xc7 0x6c + 0x03 0x70 + 0x03 0x74>; +}; + +&mdm0 { + status = "disabled"; +}; + +&qupv3_se1_i2c { + status = "ok"; + lt9611: lt,lt9611@2b { + compatible = "lt,lt9611uxc"; + reg = <0x2b>; + interrupt-parent = <&tlmm>; + interrupts = <1 0>; + interrupt-names = "lt_irq"; + lt,irq-gpio = <&tlmm 1 0x0>; + lt,reset-gpio = <&tlmm 2 0x0>; + instance_id = <0>; + lt,non-pluggable; + + pinctrl-names = "default"; + pinctrl-0 = <<9611_pins>; + + lt,preferred-mode = "1920x1080"; + + lt,customize-modes { + lt,customize-mode-id@0 { + lt,mode-h-active = <1920>; + lt,mode-h-front-porch = <88>; + lt,mode-h-pulse-width = <44>; + lt,mode-h-back-porch = <148>; + lt,mode-h-active-high; + lt,mode-v-active = <1080>; + lt,mode-v-front-porch = <4>; + lt,mode-v-pulse-width = <5>; + lt,mode-v-back-porch = <36>; + lt,mode-v-active-high; + lt,mode-refresh-rate = <60>; + lt,mode-clock-in-khz = <148500>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt9611_in: endpoint { + remote-endpoint = <&ext_dsi_out>; + }; + }; + + }; + }; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_ext_bridge_1080p>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ext_dsi_out: endpoint { + remote-endpoint = <<9611_in>; + }; + }; + }; +}; + +&pcie2 { + qcom,boot-option = <0x0>; +}; + +&mhi_0 { + reg = <0x100 0x0 0x0 0x0 0x0>; +}; + +&pcie2_rp { + #address-cells = <5>; + #size-cells = <0>; + + nvme: nvme { + reg = <0 0 0 0 0>; + qcom,iommu-group = <&nvme_pci_iommu_group>; + + #address-cells = <1>; + #size-cells = <1>; + + nvme_pci_iommu_group: nvme_pci_iommu_group { + qcom,iommu-dma-addr-pool = <0x20000000 0x40000000>; + qcom,iommu-dma = "fastmap"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-ion.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..610d9f31741485e7d9c71bb1cd73134e38ee03a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-ion.dtsi @@ -0,0 +1,62 @@ +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + adsp_heap: qcom,ion-heap@22 { + reg = <22>; + memory-region = <&sdsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + system_secure_heap: qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + + qcom,ion-heap@26 { /* USER CONTIG HEAP */ + reg = <26>; + memory-region = <&user_contig_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@13 { /* SPSS HEAP */ + reg = <13>; + memory-region = <&sp_mem>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@14 { /* SECURE CARVEOUT HEAP */ + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + cdsp { + memory-region = <&cdsp_secure_heap>; + token = <0x20000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-iot-rb5-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-iot-rb5-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7d658cf4cb11ce0c3e7b4608114cf0329dd6a5e2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-iot-rb5-audio.dtsi @@ -0,0 +1,300 @@ + +&spkr_2_sd_n_sleep { + mux { + pins = "gpio130"; + }; + + config { + pins = "gpio130"; + }; +}; + +&spkr_2_sd_n_active { + mux { + pins = "gpio130"; + }; + + config { + pins = "gpio130"; + }; +}; + + +&bolero { + qcom,num-macros = <4>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,wsa_mclk_mode_muxsel = <0x033220D8>; + qcom,va_mclk_mode_muxsel = <0x033A0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", "rx_npl_clk", + "wsa_core_clk", "wsa_npl_clk", "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_wsa_1 0>, <&clock_audio_wsa_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; + + tx_macro: tx-macro@3220000 { + compatible = "qcom,tx-macro"; + reg = <0x3220000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <2400000>; + swr2: tx_swr_master { + status = "disabled"; + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <3>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3230000 0x0>; + interrupts-extended = + <&intc GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 109 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-wakeup-required = <1>; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 PCM_OUT1 0xF>, + <2 ADC1 0x1>, <2 ADC2 0x2>, + <3 ADC3 0x1>, <3 ADC4 0x2>, + <4 DMIC0 0x1>, <4 DMIC1 0x2>, + <4 DMIC2 0x4>, <4 DMIC3 0x8>, + <5 DMIC4 0x1>, <5 DMIC5 0x2>, + <5 DMIC6 0x4>, <5 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + qcom,swr-mstr-irq-wakeup-capable = <1>; + wcd938x_tx_slave: wcd938x-tx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170223>; + }; + }; + }; + + rx_macro: rx-macro@3200000 { + compatible = "qcom,rx-macro"; + reg = <0x3200000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr1: rx_swr_master { + status = "disabled"; + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <2>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3210000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x1>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd938x_rx_slave: wcd938x-rx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170224>; + }; + }; + }; + + wsa_macro: wsa-macro@3240000 { + compatible = "qcom,wsa-macro"; + reg = <0x3240000 0x0>; + clock-names = "wsa_core_clk", "wsa_npl_clk"; + clocks = <&clock_audio_wsa_1 0>, + <&clock_audio_wsa_2 0>; + qcom,wsa-swr-gpios = <&wsa_swr_gpios>; + qcom,wsa-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr0: wsa_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <1>; + qcom,mipi-sdw-block-packing-mode = <0>; + swrm-io-base = <0x3250000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr-num-dev = <2>; + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x10 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + }; + }; + + }; + + wcd938x_codec: wcd938x-codec { + status = "disabled"; + compatible = "qcom,wcd938x-codec"; + qcom,split-codec = <1>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <0 ADC2 0x2 0 ADC2>, <1 ADC3 0x1 0 ADC3>, + <1 ADC4 0x2 0 ADC4>, <2 DMIC0 0x1 0 DMIC0>, + <2 DMIC1 0x2 0 DMIC1>, <2 MBHC 0x4 0 DMIC2>, + <2 DMIC2 0x4 0 DMIC2>, <2 DMIC3 0x8 0 DMIC3>, + <3 DMIC4 0x1 0 DMIC4>, <3 DMIC5 0x2 0 DMIC5>, + <3 DMIC6 0x4 0 DMIC6>, <3 DMIC7 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd938x_rst_gpio>; + qcom,rx-slave = <&wcd938x_rx_slave>; + qcom,tx-slave = <&wcd938x_tx_slave>; + + cdc-vdd-rxtx-supply = <&S4A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + + cdc-vddio-supply = <&S4A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + + cdc-vdd-buck-supply = <&S4A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio", + "cdc-vdd-buck", + "cdc-vdd-mic-bias"; + }; + +}; + +&kona_snd { + qcom,model = "kona-iot-snd-card"; + qcom,audio-routing = + "TX DMIC0", "Digital Mic0", + "TX DMIC1", "Digital Mic1", + "TX DMIC2", "Digital Mic2", + "TX DMIC3", "Digital Mic3", + "TX DMIC4", "Digital Mic4", + "TX DMIC5", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA DMIC0", "Digital Mic0", + "VA DMIC1", "Digital Mic1", + "VA DMIC2", "Digital Mic2", + "VA DMIC3", "Digital Mic3", + "VA DMIC4", "Digital Mic4", + "VA DMIC5", "Digital Mic5", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT"; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-lpi.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..66c579d91546448a196dd90d4c83b46ea3e1a59d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-lpi.dtsi @@ -0,0 +1,1679 @@ +&q6core { + lpi_tlmm: lpi_pinctrl@33c0000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0x33c0000 0x0>; + qcom,slew-reg = <0x355a000 0x0>; + qcom,num-gpios = <14>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = <0x00000000>, <0x00001000>, + <0x00002000>, <0x00003000>, + <0x00004000>, <0x00005000>, + <0x00006000>, <0x00007000>, + <0x00008000>, <0x00009000>, + <0x0000A000>, <0x0000B000>, + <0x0000C000>, <0x0000D000>; + qcom,lpi-slew-offset-tbl = <0x00000000>, <0x00000002>, + <0x00000004>, <0x00000008>, + <0x0000000A>, <0x0000000C>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000010>, <0x00000012>, + <0x00000000>, <0x00000000>; + + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + + quat_mi2s_sck { + quat_mi2s_sck_sleep: quat_mi2s_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sck_active: quat_mi2s_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_ws { + quat_mi2s_ws_sleep: quat_mi2s_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_ws_active: quat_mi2s_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio5"; + function = "func4"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio5"; + function = "func4"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sck { + lpi_i2s1_sck_sleep: lpi_i2s1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sck_active: lpi_i2s1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_ws { + lpi_i2s1_ws_sleep: lpi_i2s1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_ws_active: lpi_i2s1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd0 { + lpi_i2s1_sd0_sleep: lpi_i2s1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd0_active: lpi_i2s1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd1 { + lpi_i2s1_sd1_sleep: lpi_i2s1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd1_active: lpi_i2s1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sck { + lpi_i2s2_sck_sleep: lpi_i2s2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sck_active: lpi_i2s2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_ws { + lpi_i2s2_ws_sleep: lpi_i2s2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_ws_active: lpi_i2s2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd0 { + lpi_i2s2_sd0_sleep: lpi_i2s2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd0_active: lpi_i2s2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd1 { + lpi_i2s2_sd1_sleep: lpi_i2s2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd1_active: lpi_i2s2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sck { + quat_tdm_sck_sleep: quat_tdm_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sck_active: quat_tdm_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_ws { + quat_tdm_ws_sleep: quat_tdm_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_ws_active: quat_tdm_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd0 { + quat_tdm_sd0_sleep: quat_tdm_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd0_active: quat_tdm_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd1 { + quat_tdm_sd1_sleep: quat_tdm_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd1_active: quat_tdm_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd2 { + quat_tdm_sd2_sleep: quat_tdm_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd2_active: quat_tdm_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd3 { + quat_tdm_sd3_sleep: quat_tdm_sd3_sleep { + mux { + pins = "gpio5"; + function = "func4"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd3_active: quat_tdm_sd3_active { + mux { + pins = "gpio5"; + function = "func4"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sck { + lpi_tdm1_sck_sleep: lpi_tdm1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sck_active: lpi_tdm1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_ws { + lpi_tdm1_ws_sleep: lpi_tdm1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_ws_active: lpi_tdm1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd0 { + lpi_tdm1_sd0_sleep: lpi_tdm1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd0_active: lpi_tdm1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd1 { + lpi_tdm1_sd1_sleep: lpi_tdm1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd1_active: lpi_tdm1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sck { + lpi_tdm2_sck_sleep: lpi_tdm2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sck_active: lpi_tdm2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_ws { + lpi_tdm2_ws_sleep: lpi_tdm2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_ws_active: lpi_tdm2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd0 { + lpi_tdm2_sd0_sleep: lpi_tdm2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd0_active: lpi_tdm2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd1 { + lpi_tdm2_sd1_sleep: lpi_tdm2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd1_active: lpi_tdm2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sck { + quat_aux_sck_sleep: quat_aux_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sck_active: quat_aux_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_ws { + quat_aux_ws_sleep: quat_aux_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_ws_active: quat_aux_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd0 { + quat_aux_sd0_sleep: quat_aux_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd0_active: quat_aux_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd1 { + quat_aux_sd1_sleep: quat_aux_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd1_active: quat_aux_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd2 { + quat_aux_sd2_sleep: quat_aux_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd2_active: quat_aux_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd3 { + quat_aux_sd3_sleep: quat_aux_sd3_sleep { + mux { + pins = "gpio5"; + function = "func4"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd3_active: quat_aux_sd3_active { + mux { + pins = "gpio5"; + function = "func4"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sck { + lpi_aux1_sck_sleep: lpi_aux1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sck_active: lpi_aux1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_ws { + lpi_aux1_ws_sleep: lpi_aux1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_ws_active: lpi_aux1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd0 { + lpi_aux1_sd0_sleep: lpi_aux1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd0_active: lpi_aux1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd1 { + lpi_aux1_sd1_sleep: lpi_aux1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd1_active: lpi_aux1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sck { + lpi_aux2_sck_sleep: lpi_aux2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sck_active: lpi_aux2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_ws { + lpi_aux2_ws_sleep: lpi_aux2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_ws_active: lpi_aux2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd0 { + lpi_aux2_sd0_sleep: lpi_aux2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd0_active: lpi_aux2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd1 { + lpi_aux2_sd1_sleep: lpi_aux2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd1_active: lpi_aux2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + wsa_swr_clk_pin { + wsa_swr_clk_sleep: wsa_swr_clk_sleep { + mux { + pins = "gpio10"; + function = "func2"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + wsa_swr_clk_active: wsa_swr_clk_active { + mux { + pins = "gpio10"; + function = "func2"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + }; + }; + + wsa_swr_data_pin { + wsa_swr_data_sleep: wsa_swr_data_sleep { + mux { + pins = "gpio11"; + function = "func2"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + wsa_swr_data_active: wsa_swr_data_active { + mux { + pins = "gpio11"; + function = "func2"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + }; + + tx_swr_clk_sleep: tx_swr_clk_sleep { + mux { + pins = "gpio0"; + function = "func1"; + input-enable; + bias-pull-down; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + }; + }; + + tx_swr_clk_active: tx_swr_clk_active { + mux { + pins = "gpio0"; + function = "func1"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + }; + + tx_swr_data1_sleep: tx_swr_data1_sleep { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; + input-enable; + bias-bus-hold; + }; + }; + + tx_swr_data1_active: tx_swr_data1_active { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + tx_swr_data2_sleep: tx_swr_data2_sleep { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data2_active: tx_swr_data2_active { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + rx_swr_clk_sleep: rx_swr_clk_sleep { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_clk_active: rx_swr_clk_active { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + }; + + rx_swr_data_sleep: rx_swr_data_sleep { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data_active: rx_swr_data_active { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + rx_swr_data1_sleep: rx_swr_data1_sleep { + mux { + pins = "gpio5"; + function = "func2"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data1_active: rx_swr_data1_active { + mux { + pins = "gpio5"; + function = "func2"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + cdc_dmic01_clk_active: dmic01_clk_active { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic01_clk_sleep: dmic01_clk_sleep { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic01_data_active: dmic01_data_active { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic01_data_sleep: dmic01_data_sleep { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic23_clk_active: dmic23_clk_active { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic23_clk_sleep: dmic23_clk_sleep { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic23_data_active: dmic23_data_active { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic23_data_sleep: dmic23_data_sleep { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic45_clk_active: dmic45_clk_active { + mux { + pins = "gpio12"; + function = "func1"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic45_clk_sleep: dmic45_clk_sleep { + mux { + pins = "gpio12"; + function = "func1"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic45_data_active: dmic45_data_active { + mux { + pins = "gpio13"; + function = "func1"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic45_data_sleep: dmic45_data_sleep { + mux { + pins = "gpio13"; + function = "func1"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mhi.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-mhi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..31fb61c4050a427d502900191439d88c38c07f56 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mhi.dtsi @@ -0,0 +1,774 @@ +&pcie2_rp { + #address-cells = <5>; + #size-cells = <0>; + + mhi_0: qcom,mhi@0 { + reg = <0 0 0 0 0 >; + + /* controller specific configuration */ + qcom,iommu-group = <&mhi_0_iommu_group>; + + /* controller ddr frequency scaling configuration */ + qcom,msm-bus,name = "mhi0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , /* 4 Gbps */ + ; /* 8 Gbps */ + + esoc-names = "mdm"; + esoc-0 = <&mdm0>; + + /* mhi bus specific settings */ + mhi,max-channels = <111>; + mhi,timeout = <2000>; + mhi,buffer-len = <0x8000>; + mhi,sfr-support; + mhi,name = "esoc0"; + + #address-cells = <1>; + #size-cells = <1>; + + mhi_0_iommu_group: mhi_0_iommu_group { + qcom,iommu-dma-addr-pool = <0x20000000 0x1fffffff>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-pagetable = "coherent"; + }; + + mhi_channels: mhi_channels { + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@2 { + reg = <2>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@3 { + reg = <3>; + label = "SAHARA"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@8 { + reg = <8>; + label = "QDSS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@9 { + reg = <9>; + label = "QDSS"; + mhi,num-elements = <128>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@10 { + reg = <10>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@11 { + reg = <11>; + label = "EFS"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,wake-capable; + }; + + mhi_chan@14 { + reg = <14>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@15 { + reg = <15>; + label = "QMI0"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@16 { + reg = <16>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@17 { + reg = <17>; + label = "QMI1"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@18 { + reg = <18>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@19 { + reg = <19>; + label = "IP_CTRL"; + mhi,num-elements = <64>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@22 { + reg = <22>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@23 { + reg = <23>; + label = "TF"; + mhi,num-elements = <64>; + mhi,event-ring = <2>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@25 { + reg = <25>; + label = "BL"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x2>; + mhi,auto-queue; + mhi,auto-start; + }; + + mhi_chan@26 { + reg = <26>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@27 { + reg = <27>; + label = "DCI"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@32 { + reg = <32>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@33 { + reg = <33>; + label = "DUN"; + mhi,num-elements = <64>; + mhi,event-ring = <3>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@50 { + reg = <50>; + label = "ADSP_0"; + mhi,event-ring = <4>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@51 { + reg = <51>; + label = "ADSP_1"; + mhi,event-ring = <4>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@52 { + reg = <52>; + label = "SLPI_0"; + mhi,event-ring = <5>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@53 { + reg = <53>; + label = "SLPI_1"; + mhi,event-ring = <5>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@70 { + reg = <70>; + label = "ADSP_2"; + mhi,event-ring = <4>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@71 { + reg = <71>; + label = "ADSP_3"; + mhi,event-ring = <4>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@72 { + reg = <72>; + label = "SLPI_2"; + mhi,event-ring = <5>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@73 { + reg = <73>; + label = "SLPI_3"; + mhi,event-ring = <5>; + mhi,chan-dir = <0>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@80 { + reg = <80>; + label = "AUDIO_VOICE_0"; + mhi,event-ring = <0>; + mhi,chan-dir = <0>; + mhi,ee = <0x4>; + mhi,data-type = <3>; + mhi,offload-chan; + status = "ok"; + }; + + mhi_chan@100 { + reg = <100>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <7>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + mhi,db-mode-switch; + }; + + mhi_chan@101 { + reg = <101>; + label = "IP_HW0"; + mhi,num-elements = <512>; + mhi,event-ring = <8>; + mhi,chan-dir = <2>; + mhi,data-type = <4>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + }; + + mhi_chan@102 { + reg = <102>; + label = "IP_HW_ADPL"; + mhi,event-ring = <9>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_chan@103 { + reg = <103>; + label = "IP_HW_QDSS"; + mhi,num-elements = <128>; + mhi,event-ring = <10>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@104 { + reg = <104>; + label = "IP_HW0_RSC"; + mhi,num-elements = <512>; + mhi,local-elements = <3078>; + mhi,event-ring = <8>; + mhi,chan-dir = <2>; + mhi,data-type = <5>; + mhi,doorbell-mode = <3>; + mhi,ee = <0x4>; + mhi,chan-type = <3>; + }; + + mhi_chan@105 { + reg = <105>; + label = "IP_HW_MHIP_0"; + mhi,event-ring = <11>; + mhi,chan-dir = <1>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@106 { + reg = <106>; + label = "IP_HW_MHIP_0"; + mhi,event-ring = <12>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_chan@107 { + reg = <107>; + label = "IP_HW_MHIP_1"; + mhi,event-ring = <13>; + mhi,chan-dir = <1>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + }; + + mhi_chan@108 { + reg = <108>; + label = "IP_HW_MHIP_1"; + mhi,event-ring = <14>; + mhi,chan-dir = <2>; + mhi,data-type = <3>; + mhi,ee = <0x4>; + mhi,offload-chan; + mhi,lpm-notify; + }; + + mhi_chan@109 { + reg = <109>; + label = "RMNET_CTL"; + mhi,num-elements = <128>; + mhi,event-ring = <15>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + + mhi_chan@110 { + reg = <110>; + label = "RMNET_CTL"; + mhi,num-elements = <128>; + mhi,event-ring = <16>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x4>; + }; + }; + + mhi_events: mhi_events { + #address-cells = <1>; + #size-cells = <0>; + + mhi_event@0 { + reg = <0>; + mhi,num-elements = <32>; + mhi,intmod = <0>; + mhi,msi = <1>; + mhi,priority = <0>; + mhi,brstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <0>; + mhi,msi = <2>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@2 { + mhi,num-elements = <256>; + mhi,intmod = <0>; + mhi,msi = <3>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@3 { + mhi,num-elements = <256>; + mhi,intmod = <0>; + mhi,msi = <4>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@4 { + mhi,num-elements = <512>; + mhi,intmod = <5>; + mhi,msi = <0>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@5 { + mhi,num-elements = <512>; + mhi,intmod = <5>; + mhi,msi = <0>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@6 { + mhi,num-elements = <64>; + mhi,intmod = <0>; + mhi,msi = <0>; + mhi,priority = <2>; + mhi,brstmode = <2>; + mhi,data-type = <3>; + }; + + mhi_event@7 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <5>; + mhi,chan = <100>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + }; + + mhi_event@8 { + mhi,num-elements = <2048>; + mhi,intmod = <5>; + mhi,msi = <6>; + mhi,chan = <101>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + mhi,force-uncached; + }; + + mhi_event@9 { + mhi,num-elements = <0>; + mhi,intmod = <0>; + mhi,msi = <0>; + mhi,chan = <102>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@10 { + mhi,num-elements = <1024>; + mhi,intmod = <5>; + mhi,msi = <7>; + mhi,chan = <103>; + mhi,priority = <1>; + mhi,brstmode = <2>; + mhi,hw-ev; + }; + + mhi_event@11 { + mhi,num-elements = <0>; + mhi,intmod = <0>; + mhi,msi = <0>; + mhi,chan = <105>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@12 { + mhi,num-elements = <0>; + mhi,intmod = <0>; + mhi,msi = <0>; + mhi,chan = <106>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@13 { + mhi,num-elements = <0>; + mhi,intmod = <0>; + mhi,msi = <0>; + mhi,chan = <107>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@14 { + mhi,num-elements = <0>; + mhi,intmod = <0>; + mhi,msi = <0>; + mhi,chan = <108>; + mhi,priority = <1>; + mhi,brstmode = <3>; + mhi,hw-ev; + mhi,client-manage; + mhi,offload; + }; + + mhi_event@15 { + mhi,num-elements = <1024>; + mhi,intmod = <1>; + mhi,msi = <8>; + mhi,chan = <109>; + mhi,priority = <0>; + mhi,brstmode = <2>; + mhi,hw-ev; + }; + + mhi_event@16 { + mhi,num-elements = <1024>; + mhi,intmod = <0>; + mhi,msi = <9>; + mhi,chan = <110>; + mhi,priority = <0>; + mhi,brstmode = <2>; + mhi,hw-ev; + }; + }; + + mhi_devices: mhi_devices { + #address-cells = <1>; + #size-cells = <0>; + + mhi_netdev_0: mhi_rmnet@0 { + reg = <0x0>; + mhi,chan = "IP_HW0"; + mhi,interface-name = "rmnet_mhi"; + mhi,mru = <0x8000>; + mhi,chain-skb; + mhi,rsc-child = <&mhi_netdev_0_rsc>; + }; + + mhi_netdev_0_rsc: mhi_rmnet@1 { + reg = <0x1>; + mhi,chan = "IP_HW0_RSC"; + mhi,mru = <0x8000>; + mhi,rsc-parent = <&mhi_netdev_0>; + }; + + mhi_qdss_dev_0 { + mhi,chan = "QDSS"; + mhi,default-channel; + }; + + mhi_qdss_dev_1 { + mhi,chan = "IP_HW_QDSS"; + }; + + mhi_qrtr { + mhi,chan = "IPCR"; + qcom,net-id = <3>; + mhi,early-notify; + }; + + mhi_subsys_adsp_0: mhi_dev@2 { + reg = <0x2>; + mhi,chan = "ADSP_0"; + mhi,max-devices = <4>; + mhi,early-notify; + }; + + mhi_subsys_slpi_0: mhi_dev@3 { + reg = <0x3>; + mhi,chan = "SLPI_0"; + mhi,max-devices = <4>; + mhi,early-notify; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1928b89ca8082fd6cdceaaeb62c5e91afdea49d7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-overlay.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x10008 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp-sa.dts b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-sa.dts new file mode 100644 index 0000000000000000000000000000000000000000..8eb1117ec1c0115cf13e28346afb9e0a463b8ce2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-sa.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona standalone MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x02010008 0>; +}; + +&mdm0 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..778ed9b64c04f8eb98d89fd039a1fcb2488d61a0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws-overlay.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/plugin/; + +#include "kona-mtp-ws.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona MTP (WS)"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x03010008 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws.dts b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws.dts new file mode 100644 index 0000000000000000000000000000000000000000..bffdb81d86722a8b7846cb262bde515e8e645e73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-mtp-ws.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona MTP (WS)"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x03010008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..362c9fd2e674ee55c271673aed48f26a19eec3d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp-ws.dtsi @@ -0,0 +1,28 @@ +#include "kona-mtp.dtsi" + +&wlan { + vdd-wlan-dig-supply = <&pm8150_s6>; + qcom,vdd-wlan-dig-config = <950000 950000 0 0 1>; + qcom,cmd_db_name = "smpa6"; +}; + +&bluetooth { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-sw-ctrl-gpio = <&tlmm 124 0>; /* SW_CTRL */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8150_s6>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 950000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..2b12870bcee773e257a4271057aae4d4ad5bd242 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x10008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d5505e7ea5193ee81e8864cc02ab909afe574ab7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-mtp.dtsi @@ -0,0 +1,682 @@ +#include +#include + +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "camera/kona-camera-sensor-mtp.dtsi" +#include "kona-audio-overlay.dtsi" +#include "kona-thermal-overlay.dtsi" + +&qupv3_se12_2uart { + status = "ok"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&dai_mi2s2 { + qcom,msm-mi2s-tx-lines = <1>; +}; + +&q6core { + cdc_tert_mi2s_gpios: msm_cdc_pinctrl_tert { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep>; + }; +}; + +&kona_snd { + qcom,tert-mi2s-gpios = <&cdc_tert_mi2s_gpios>; +}; + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 111 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 110 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <111 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18800>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vcc-voltage-level = <2504000 2950000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8150_l6>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vccq-parent-supply = <&pm8150a_s8>; + qcom,vccq-parent-max-microamp = <210000>; + + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qcom,qbt_handler { + compatible = "qcom,qbt-handler"; + qcom,ipc-gpio = <&tlmm 23 0>; + pinctrl-names = "default"; + pinctrl-0 = <&key_home_default>; + qcom,finger-detect-gpio = <&pm8150_gpios 1 0>; + }; +}; + +&qupv3_se13_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + vdd-supply = <&pm8150a_l1>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 39 0x2008>; + st,reset-gpio = <&tlmm 38 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + st,x-flip = <1>; + st,y-flip = <1>; + panel = <&dsi_sw43404_amoled_cmd &dsi_sw43404_amoled_video + &dsi_sw43404_amoled_fhd_plus_cmd>; + }; +}; + +&vendor { + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-sw-ctrl-gpio = <&tlmm 124 0>; /* SW_CTRL */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + }; + + kona_mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen4-batterydata-alium-3600mah.dtsi" + #include "fg-gen4-batterydata-ascent-3450mah.dtsi" + }; + + extcon_usb1: extcon_usb1 { + compatible = "linux,extcon-usb-gpio"; + vbus-gpio = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; + id-gpio = <&tlmm 91 GPIO_ACTIVE_HIGH>; + vbus-out-gpio = <&pm8150_gpios 9 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_det_default + &usb2_id_det_default + &usb2_vbus_boost_default>; + }; +}; + +&vreg_hap_boost { + status = "ok"; +}; + +&pm8150b_haptics { + vdd-supply = <&vreg_hap_boost>; +}; + +&pm8150b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&pm8150b_charger { + status = "ok"; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "mid_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp"; + qcom,battery-data = <&kona_mtp_batterydata>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,wd-bark-time-secs = <16>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; + qcom,smb-internal-pull-kohm = <0>; +}; + +&pm8150b_fg { + status = "ok"; + qcom,battery-data = <&kona_mtp_batterydata>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,five-pin-battery; + qcom,cl-wt-enable; + qcom,soc-scale-mode-en; + qcom,force-calib-level = <130>; + /* ESR fast calibration */ + qcom,fg-esr-timer-chg-fast = <0 7>; + qcom,fg-esr-timer-dischg-fast = <0 7>; + qcom,fg-esr-timer-chg-slow = <0 96>; + qcom,fg-esr-timer-dischg-slow = <0 96>; + qcom,fg-esr-cal-soc-thresh = <26 230>; + qcom,fg-esr-cal-temp-thresh = <10 40>; +}; + +&qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; +#include "smb1390.dtsi" + + halo,hl6111r@25 { + compatible = "halo,hl6111r"; + reg = <0x25>; + status = "ok"; + }; +}; + +&smb1390 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + qcom,parallel-output-mode = <2>; + qcom,min-ilim-ua = <750000>; + status = "ok"; +}; + +&smb1390_slave { + status = "ok"; +}; + +&smb1390_slave_charger { + status = "ok"; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@4d { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4e { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + camera_flash_therm@4d { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_msm_therm@4e { + reg = ; + label = "skin_msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm2@4f { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM3_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + camera_flash_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_debug_bus { + status = "ok"; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_sec_hd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&usb1 { + extcon = <&extcon_usb1>; +}; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-npu.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-npu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..17d6e025cfdbb9592e2c4fec1e2f07f181bbe0ab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-npu.dtsi @@ -0,0 +1,272 @@ +&soc { + msm_npu: qcom,msm_npu@9800000 { + compatible = "qcom,msm-npu"; + status = "ok"; + reg = <0x9900000 0x20000>, + <0x99F0000 0x10000>, + <0x9980000 0x10000>, + <0x17c00000 0x10000>, + <0x01F40000 0x40000>; + reg-names = "tcm", "core", "cc", "apss_shared", "tcsr"; + interrupts = , + , + , + ; + interrupt-names = "error_irq", "wdg_bite_irq", "ipc_irq", + "general_irq"; + iommus = <&apps_smmu 0x1081 0x400>, <&apps_smmu 0x1082 0x400>, + <&apps_smmu 0x10A1 0x400>, <&apps_smmu 0x10A2 0x400>, + <&apps_smmu 0x10C1 0x400>, <&apps_smmu 0x10C2 0x400>; + qcom,npu-dsp-sid-mapped; + + clocks = <&clock_npucc NPU_CC_XO_CLK>, + <&clock_npucc NPU_CC_CORE_CLK>, + <&clock_npucc NPU_CC_CAL_HM0_CLK>, + <&clock_npucc NPU_CC_CAL_HM1_CLK>, + <&clock_npucc NPU_CC_CAL_HM0_CDC_CLK>, + <&clock_npucc NPU_CC_CAL_HM1_CDC_CLK>, + <&clock_npucc NPU_CC_NOC_AXI_CLK>, + <&clock_npucc NPU_CC_NOC_AHB_CLK>, + <&clock_npucc NPU_CC_NOC_DMA_CLK>, + <&clock_npucc NPU_CC_LLM_CLK>, + <&clock_npucc NPU_CC_LLM_XO_CLK>, + <&clock_npucc NPU_CC_LLM_TEMP_CLK>, + <&clock_npucc NPU_CC_LLM_CURR_CLK>, + <&clock_npucc NPU_CC_DL_LLM_CLK>, + <&clock_npucc NPU_CC_ISENSE_CLK>, + <&clock_npucc NPU_CC_DPM_CLK>, + <&clock_npucc NPU_CC_DPM_XO_CLK>, + <&clock_npucc NPU_CC_DL_DPM_CLK>, + <&clock_npucc NPU_CC_RSC_XO_CLK>, + <&clock_npucc NPU_CC_DPM_TEMP_CLK>, + <&clock_npucc NPU_CC_CAL_HM0_DPM_IP_CLK>, + <&clock_npucc NPU_CC_CAL_HM1_DPM_IP_CLK>, + <&clock_npucc NPU_CC_S2P_CLK>, + <&clock_npucc NPU_CC_BWMON_CLK>, + <&clock_npucc NPU_CC_CAL_HM0_PERF_CNT_CLK>, + <&clock_npucc NPU_CC_CAL_HM1_PERF_CNT_CLK>, + <&clock_npucc NPU_CC_BTO_CORE_CLK>, + <&clock_npucc NPU_DSP_CORE_CLK_SRC>; + clock-names = "xo_clk", + "npu_core_clk", + "cal_hm0_clk", + "cal_hm1_clk", + "cal_hm0_cdc_clk", + "cal_hm1_cdc_clk", + "axi_clk", + "ahb_clk", + "dma_clk", + "llm_clk", + "llm_xo_clk", + "llm_temp_clk", + "llm_curr_clk", + "dl_llm_clk", + "isense_clk", + "dpm_clk", + "dpm_xo_clk", + "dl_dpm_clk", + "rsc_xo_clk", + "dpm_temp_clk", + "cal_hm0_dpm_ip_clk", + "cal_hm1_dpm_ip_clk", + "s2p_clk", + "bwmon_clk", + "cal_hm0_perf_cnt_clk", + "cal_hm1_perf_cnt_clk", + "bto_core_clk", + "dsp_core_clk_src"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names ="vdd", "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + resets = <&clock_npucc NPU_CC_DPM_TEMP_CLK_ARES>, + <&clock_npucc NPU_CC_LLM_CURR_CLK_ARES>, + <&clock_npucc NPU_CC_LLM_TEMP_CLK_ARES>; + reset-names = "dpm_temp_clk", "llm_curr_clk", "llm_temp_clk"; + #cooling-cells = <2>; + mboxes = <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_GLINK_QMP>, + <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_SMP2P>, + <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_PING>; + mbox-names = "ipcc-glink", "ipcc-smp2p", "ipcc-ping"; + #mbox-cells = <2>; + qcom,npubw-devs = <&npu_npu_llcc_bw>, <&npu_llcc_ddr_bw>, + <&npudsp_npu_ddr_bw>; + qcom,npubw-dev-names = "llcc_bw", "llcc_ddr_bw", "dsp_ddr_bw"; + qcom,src-dst-ports = , + ; + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + vreg = <1>; + clk-freq = <19200000 + 100000000 + 300000000 + 300000000 + 300000000 + 300000000 + 200000000 + 40000000 + 300000000 + 100000000 + 19200000 + 50000000 + 50000000 + 100000000 + 100000000 + 100000000 + 19200000 + 100000000 + 19200000 + 50000000 + 200000000 + 200000000 + 50000000 + 19200000 + 300000000 + 300000000 + 19200000 + 300000000>; + }; + + qcom,npu-pwrlevel@1 { + reg = <1>; + vreg = <2>; + clk-freq = <19200000 + 200000000 + 466000000 + 466000000 + 466000000 + 466000000 + 267000000 + 40000000 + 403000000 + 200000000 + 19200000 + 50000000 + 50000000 + 200000000 + 200000000 + 200000000 + 19200000 + 200000000 + 19200000 + 50000000 + 466000000 + 466000000 + 50000000 + 19200000 + 466000000 + 466000000 + 19200000 + 400000000>; + }; + + qcom,npu-pwrlevel@2 { + reg = <2>; + vreg = <3>; + clk-freq = <19200000 + 333000000 + 533000000 + 533000000 + 533000000 + 533000000 + 403000000 + 75000000 + 533000000 + 214000000 + 19200000 + 50000000 + 100000000 + 214000000 + 214000000 + 214000000 + 19200000 + 214000000 + 19200000 + 50000000 + 533000000 + 533000000 + 50000000 + 19200000 + 533000000 + 533000000 + 19200000 + 500000000>; + }; + + qcom,npu-pwrlevel@3 { + reg = <3>; + vreg = <4>; + clk-freq = <19200000 + 428000000 + 850000000 + 850000000 + 850000000 + 850000000 + 533000000 + 75000000 + 700000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 850000000 + 850000000 + 100000000 + 19200000 + 850000000 + 850000000 + 19200000 + 660000000>; + }; + + qcom,npu-pwrlevel@4 { + reg = <4>; + vreg = <6>; + clk-freq = <19200000 + 500000000 + 1000000000 + 1000000000 + 1000000000 + 1000000000 + 700000000 + 75000000 + 806000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 1000000000 + 1000000000 + 100000000 + 19200000 + 1000000000 + 1000000000 + 19200000 + 800000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-pcie.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-pcie.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..58a7cea6930a5fcefdf687526014b09238cd8b9a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-pcie.dtsi @@ -0,0 +1,812 @@ +#include + +&soc { + pcie0: qcom,pcie@1c00000 { + compatible = "qcom,pci-msm"; + + reg = <0x01c00000 0x3000>, + <0x01c06000 0x1000>, + <0x60000000 0xf1d>, + <0x60000f20 0xa8>, + <0x60001000 0x1000>, + <0x60100000 0x100000>; + reg-names = "parf", "phy", "dm_core", "elbi", "iatu", "conf"; + + cell-index = <0>; + linux,pci-domain = <0>; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x60200000 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x60300000 0x0 0x3d00000>; + + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4>; + interrupt-names = "int_global_int", "int_a", "int_b", "int_c", + "int_d"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH + 0 0 0 1 &intc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH + 0 0 0 2 &intc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH + 0 0 0 3 &intc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH + 0 0 0 4 &intc GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>; + msi-parent = <&pcie0_msi>; + + perst-gpio = <&tlmm 79 0>; + wake-gpio = <&tlmm 81 0>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + pinctrl-1 = <&pcie0_clkreq_sleep + &pcie0_perst_default + &pcie0_wake_default>; + + gdsc-vdd-supply = <&pcie_0_gdsc>; + vreg-1p8-supply = <&pm8150_l9>; + vreg-0p9-supply = <&pm8150_l5>; + vreg-cx-supply = <&VDD_CX_LEVEL>; + qcom,vreg-1p8-voltage-level = <1200000 1200000 16000>; + qcom,vreg-0p9-voltage-level = <880000 880000 73500>; + qcom,vreg-cx-voltage-level = ; + qcom,bw-scale = ; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_0_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_0_AUX_CLK>, + <&clock_gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_WIFI_CLKREF_EN>, + <&clock_gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE0_PHY_REFGEN_CLK>, + <&clock_gcc GCC_DDRSS_PCIE_SF_TBU_CLK>; + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_ddrss_sf_tbu_clk"; + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + + dma-coherent; + qcom,smmu-sid-base = <0x1c00>; + iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, + <0x100 &apps_smmu 0x1c01 0x1>; + + qcom,boot-option = <0x1>; + qcom,drv-supported; + qcom,drv-l1ss-timeout-us = <10000>; /* 10ms */ + qcom,use-19p2mhz-aux-clk; + qcom,no-l0s-supported; + qcom,l1-2-th-scale = <2>; /* 1us */ + qcom,l1-2-th-value = <70>; + qcom,slv-addr-space-size = <0x4000000>; + qcom,ep-latency = <10>; + + qcom,pcie-phy-ver = <1102>; + qcom,phy-status-offset = <0x814>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0x840>; + qcom,phy-sequence = <0x0840 0x03 0x0 + 0x0094 0x08 0x0 + 0x0154 0x34 0x0 + 0x016c 0x08 0x0 + 0x0058 0x0f 0x0 + 0x00a4 0x42 0x0 + 0x0110 0x24 0x0 + 0x011c 0x03 0x0 + 0x0118 0xb4 0x0 + 0x010c 0x02 0x0 + 0x01bc 0x11 0x0 + 0x00bc 0x82 0x0 + 0x00d4 0x03 0x0 + 0x00d0 0x55 0x0 + 0x00cc 0x55 0x0 + 0x00b0 0x1a 0x0 + 0x00ac 0x0a 0x0 + 0x00c4 0x68 0x0 + 0x00e0 0x02 0x0 + 0x00dc 0xaa 0x0 + 0x00d8 0xab 0x0 + 0x00b8 0x34 0x0 + 0x00b4 0x14 0x0 + 0x0158 0x01 0x0 + 0x0074 0x06 0x0 + 0x007c 0x16 0x0 + 0x0084 0x36 0x0 + 0x0078 0x06 0x0 + 0x0080 0x16 0x0 + 0x0088 0x36 0x0 + 0x01b0 0x1e 0x0 + 0x01ac 0xca 0x0 + 0x01b8 0x18 0x0 + 0x01b4 0xa2 0x0 + 0x0050 0x07 0x0 + 0x0010 0x01 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0024 0xde 0x0 + 0x0028 0x07 0x0 + 0x0030 0x4c 0x0 + 0x0034 0x06 0x0 + 0x029c 0x12 0x0 + 0x0284 0x35 0x0 + 0x023c 0x11 0x0 + 0x051c 0x03 0x0 + 0x0518 0x1c 0x0 + 0x0524 0x1e 0x0 + 0x04e8 0x00 0x0 + 0x04ec 0x0e 0x0 + 0x04f0 0x4a 0x0 + 0x04f4 0x0f 0x0 + 0x05b4 0x04 0x0 + 0x0434 0x7f 0x0 + 0x0444 0x70 0x0 + 0x0510 0x17 0x0 + 0x04d4 0x04 0x0 + 0x04d8 0x07 0x0 + 0x0598 0xd4 0x0 + 0x059c 0x54 0x0 + 0x05a0 0xdb 0x0 + 0x05a4 0x3b 0x0 + 0x05a8 0x31 0x0 + 0x0584 0x24 0x0 + 0x0588 0xe4 0x0 + 0x058c 0xec 0x0 + 0x0590 0x3b 0x0 + 0x0594 0x36 0x0 + 0x0570 0x3f 0x0 + 0x0574 0x3f 0x0 + 0x0578 0xff 0x0 + 0x057c 0x7f 0x0 + 0x0580 0x14 0x0 + 0x04fc 0x00 0x0 + 0x04f8 0xc0 0x0 + 0x0460 0x30 0x0 + 0x0464 0x00 0x0 + 0x05bc 0x0c 0x0 + 0x04dc 0x1b 0x0 + 0x0408 0x0c 0x0 + 0x0414 0x03 0x0 + 0x05b8 0x30 0x0 + 0x09a4 0x01 0x0 + 0x0c90 0x00 0x0 + 0x0c40 0x01 0x0 + 0x0c48 0x01 0x0 + 0x0c50 0x00 0x0 + 0x0cb4 0x33 0x0 + 0x0cbc 0x00 0x0 + 0x0ce0 0x58 0x0 + 0x0ca4 0x0f 0x0 + 0x0048 0x90 0x0 + 0x0c1c 0xc1 0x0 + 0x0988 0x77 0x0 + 0x0998 0x0b 0x0 + 0x08dc 0x0d 0x0 + 0x09ec 0x12 0x0 + 0x0800 0x00 0x0 + 0x0844 0x03 0x0>; + + pcie0_rp: pcie0_rp { + reg = <0 0 0 0 0>; + }; + }; + + pcie0_msi: qcom,pcie0_msi@17a10040 { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a10040 0x0>; + interrupt-parent = <&intc>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + pcie1: qcom,pcie@1c08000 { + compatible = "qcom,pci-msm"; + + reg = <0x01c08000 0x3000>, + <0x01c0e000 0x2000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40001000 0x1000>, + <0x40100000 0x100000>; + reg-names = "parf", "phy", "dm_core", "elbi", "iatu", "conf"; + + cell-index = <1>; + linux,pci-domain = <1>; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1fd00000>; + + interrupt-parent = <&pcie1>; + interrupts = <0 1 2 3 4>; + interrupt-names = "int_global_int", "int_a", "int_b", "int_c", + "int_d"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH + 0 0 0 1 &intc GIC_SPI 434 IRQ_TYPE_LEVEL_HIGH + 0 0 0 2 &intc GIC_SPI 435 IRQ_TYPE_LEVEL_HIGH + 0 0 0 3 &intc GIC_SPI 438 IRQ_TYPE_LEVEL_HIGH + 0 0 0 4 &intc GIC_SPI 439 IRQ_TYPE_LEVEL_HIGH>; + msi-parent = <&pcie1_msi>; + + perst-gpio = <&tlmm 82 0>; + wake-gpio = <&tlmm 84 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_clkreq_default + &pcie1_perst_default + &pcie1_wake_default>; + + gdsc-vdd-supply = <&pcie_1_gdsc>; + vreg-1p8-supply = <&pm8150_l9>; + vreg-0p9-supply = <&pm8150_l5>; + vreg-cx-supply = <&VDD_CX_LEVEL>; + qcom,vreg-1p8-voltage-level = <1200000 1200000 25000>; + qcom,vreg-0p9-voltage-level = <880000 880000 98800>; + qcom,vreg-cx-voltage-level = ; + qcom,bw-scale = ; + + qcom,msm-bus,name = "pcie1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_1_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_1_AUX_CLK>, + <&clock_gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_1_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_1_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_WIGIG_CLKREF_EN>, + <&clock_gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE1_PHY_REFGEN_CLK>, + <&clock_gcc GCC_DDRSS_PCIE_SF_TBU_CLK>; + clock-names = "pcie_1_pipe_clk", "pcie_1_ref_clk_src", + "pcie_1_aux_clk", "pcie_1_cfg_ahb_clk", + "pcie_1_mstr_axi_clk", "pcie_1_slv_axi_clk", + "pcie_1_ldo", "pcie_1_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_ddrss_sf_tbu_clk"; + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_1_BCR>, + <&clock_gcc GCC_PCIE_1_PHY_BCR>; + reset-names = "pcie_1_core_reset", + "pcie_1_phy_reset"; + + dma-coherent; + qcom,smmu-sid-base = <0x1c80>; + iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, + <0x100 &apps_smmu 0x1c81 0x1>; + + qcom,boot-option = <0x1>; + qcom,drv-supported; + qcom,use-19p2mhz-aux-clk; + qcom,no-l0s-supported; + qcom,slv-addr-space-size = <0x20000000>; + qcom,ep-latency = <10>; + + qcom,pcie-phy-ver = <1102>; + qcom,phy-status-offset = <0xa14>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0xa40>; + qcom,phy-sequence = <0x0a40 0x03 0x0 + 0x0010 0x01 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0024 0xde 0x0 + 0x0028 0x07 0x0 + 0x0030 0x4c 0x0 + 0x0034 0x06 0x0 + 0x0048 0x90 0x0 + 0x0058 0x0f 0x0 + 0x0074 0x06 0x0 + 0x0078 0x06 0x0 + 0x007c 0x16 0x0 + 0x0080 0x16 0x0 + 0x0084 0x36 0x0 + 0x0088 0x36 0x0 + 0x0094 0x08 0x0 + 0x00a4 0x42 0x0 + 0x00ac 0x0a 0x0 + 0x00b0 0x1a 0x0 + 0x00b4 0x14 0x0 + 0x00b8 0x34 0x0 + 0x00bc 0x82 0x0 + 0x00c4 0x68 0x0 + 0x00cc 0x55 0x0 + 0x00d0 0x55 0x0 + 0x00d4 0x03 0x0 + 0x00d8 0xab 0x0 + 0x00dc 0xaa 0x0 + 0x00e0 0x02 0x0 + 0x010c 0x02 0x0 + 0x0110 0x24 0x0 + 0x0118 0xb4 0x0 + 0x011c 0x03 0x0 + 0x0154 0x34 0x0 + 0x0158 0x01 0x0 + 0x016c 0x08 0x0 + 0x01ac 0xca 0x0 + 0x01b0 0x1e 0x0 + 0x01b4 0xa2 0x0 + 0x01b8 0x18 0x0 + 0x01bc 0x11 0x0 + 0x023c 0x11 0x0 + 0x0284 0x75 0x0 + 0x029c 0x12 0x0 + 0x0304 0x02 0x0 + 0x0408 0x0c 0x0 + 0x0414 0x03 0x0 + 0x0434 0x7f 0x0 + 0x0444 0x70 0x0 + 0x0460 0x30 0x0 + 0x04d4 0x04 0x0 + 0x04d8 0x07 0x0 + 0x04dc 0x1b 0x0 + 0x04e8 0x04 0x0 + 0x04ec 0x0e 0x0 + 0x04f0 0x4a 0x0 + 0x04f4 0x0f 0x0 + 0x04f8 0xc0 0x0 + 0x04fc 0x00 0x0 + 0x0510 0x17 0x0 + 0x0518 0x1c 0x0 + 0x051c 0x03 0x0 + 0x0524 0x1e 0x0 + 0x0570 0xbf 0x0 + 0x0574 0x3f 0x0 + 0x0578 0xff 0x0 + 0x057c 0x7f 0x0 + 0x0580 0x15 0x0 + 0x0584 0x24 0x0 + 0x0588 0xe4 0x0 + 0x058c 0xec 0x0 + 0x0590 0x3b 0x0 + 0x0594 0x36 0x0 + 0x0598 0xd4 0x0 + 0x059c 0x54 0x0 + 0x05a0 0xdb 0x0 + 0x05a4 0x3b 0x0 + 0x05a8 0x31 0x0 + 0x05bc 0x0c 0x0 + 0x05b8 0x38 0x0 + 0x063c 0x11 0x0 + 0x0684 0x75 0x0 + 0x069c 0x12 0x0 + 0x0704 0x20 0x0 + 0x0808 0x0c 0x0 + 0x0814 0x03 0x0 + 0x0834 0x7f 0x0 + 0x0844 0x70 0x0 + 0x0860 0x30 0x0 + 0x08d4 0x04 0x0 + 0x08d8 0x07 0x0 + 0x08dc 0x1b 0x0 + 0x08e8 0x04 0x0 + 0x08ec 0x0e 0x0 + 0x08f0 0x4a 0x0 + 0x08f4 0x0f 0x0 + 0x08f8 0xc0 0x0 + 0x08fc 0x00 0x0 + 0x0910 0x17 0x0 + 0x0918 0x1c 0x0 + 0x091c 0x03 0x0 + 0x0924 0x1e 0x0 + 0x0970 0xbf 0x0 + 0x0974 0x3f 0x0 + 0x0978 0xff 0x0 + 0x097c 0x7f 0x0 + 0x0980 0x15 0x0 + 0x0984 0x24 0x0 + 0x0988 0xe4 0x0 + 0x098c 0xec 0x0 + 0x0990 0x3b 0x0 + 0x0994 0x36 0x0 + 0x0998 0xd4 0x0 + 0x099c 0x54 0x0 + 0x09a0 0xdb 0x0 + 0x09a4 0x3b 0x0 + 0x09a8 0x31 0x0 + 0x09bc 0x0c 0x0 + 0x09b8 0x38 0x0 + 0x0adc 0x05 0x0 + 0x0b88 0x77 0x0 + 0x0b98 0x0b 0x0 + 0x0ba4 0x01 0x0 + 0x0be0 0x0f 0x0 + 0x0e0c 0x0d 0x0 + 0x0e14 0x07 0x0 + 0x0e1c 0xc1 0x0 + 0x0e40 0x01 0x0 + 0x0e48 0x01 0x0 + 0x0e90 0x00 0x0 + 0x0eb4 0x33 0x0 + 0x0ebc 0x00 0x0 + 0x0ee0 0x58 0x0 + 0x0a00 0x00 0x0 + 0x0a44 0x03 0x0>; + + pcie1_rp: pcie1_rp { + reg = <0 0 0 0 0>; + }; + }; + + pcie1_msi: qcom,pcie1_msi@17a10040 { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a10040 0x0>; + interrupt-parent = <&intc>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + pcie2: qcom,pcie@1c10000 { + compatible = "qcom,pci-msm"; + + reg = <0x01c10000 0x3000>, + <0x01c16000 0x2000>, + <0x64000000 0xf1d>, + <0x64000f20 0xa8>, + <0x64001000 0x1000>, + <0x64100000 0x100000>; + reg-names = "parf", "phy", "dm_core", "elbi", "iatu", "conf"; + + cell-index = <2>; + linux,pci-domain = <2>; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x64200000 0x64200000 0x0 0x100000>, + <0x02000000 0x0 0x64300000 0x64300000 0x0 0x3d00000>; + + interrupt-parent = <&pcie2>; + interrupts = <0 1 2 3 4>; + interrupt-names = "int_global_int", "int_a", "int_b", "int_c", + "int_d"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 236 IRQ_TYPE_LEVEL_HIGH + 0 0 0 1 &intc GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH + 0 0 0 2 &intc GIC_SPI 415 IRQ_TYPE_LEVEL_HIGH + 0 0 0 3 &intc GIC_SPI 416 IRQ_TYPE_LEVEL_HIGH + 0 0 0 4 &intc GIC_SPI 417 IRQ_TYPE_LEVEL_HIGH>; + msi-parent = <&pcie2_msi>; + + perst-gpio = <&tlmm 85 0>; + wake-gpio = <&tlmm 87 0>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_clkreq_default + &pcie2_perst_default + &pcie2_wake_default>; + + gdsc-vdd-supply = <&pcie_2_gdsc>; + vreg-1p8-supply = <&pm8150_l9>; + vreg-0p9-supply = <&pm8150_l5>; + vreg-cx-supply = <&VDD_CX_LEVEL>; + qcom,vreg-1p8-voltage-level = <1200000 1200000 25500>; + qcom,vreg-0p9-voltage-level = <880000 880000 98800>; + qcom,vreg-cx-voltage-level = ; + qcom,bw-scale = ; + + qcom,msm-bus,name = "pcie2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <108 512 0 0>, + <108 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_2_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_2_AUX_CLK>, + <&clock_gcc GCC_PCIE_2_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_2_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_2_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_MDM_CLKREF_EN>, + <&clock_gcc GCC_PCIE_2_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE2_PHY_REFGEN_CLK>, + <&clock_gcc GCC_DDRSS_PCIE_SF_TBU_CLK>; + clock-names = "pcie_2_pipe_clk", "pcie_2_ref_clk_src", + "pcie_2_aux_clk", "pcie_2_cfg_ahb_clk", + "pcie_2_mstr_axi_clk", "pcie_2_slv_axi_clk", + "pcie_2_ldo", "pcie_2_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_ddrss_sf_tbu_clk"; + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_2_BCR>, + <&clock_gcc GCC_PCIE_2_PHY_BCR>; + reset-names = "pcie_2_core_reset", + "pcie_2_phy_reset"; + + dma-coherent; + qcom,smmu-sid-base = <0x1d00>; + iommu-map = <0x0 &apps_smmu 0x1d00 0x1>, + <0x100 &apps_smmu 0x1d01 0x1>; + + qcom,boot-option = <0x1>; + qcom,drv-supported; + qcom,use-19p2mhz-aux-clk; + qcom,no-l0s-supported; + qcom,slv-addr-space-size = <0x4000000>; + qcom,ep-latency = <10>; + + qcom,pcie-phy-ver = <1102>; + qcom,phy-status-offset = <0xa14>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0xa40>; + qcom,phy-sequence = <0x0a40 0x03 0x0 + 0x0010 0x01 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0024 0xde 0x0 + 0x0028 0x07 0x0 + 0x0030 0x4c 0x0 + 0x0034 0x06 0x0 + 0x0048 0x90 0x0 + 0x0058 0x0f 0x0 + 0x0074 0x06 0x0 + 0x0078 0x06 0x0 + 0x007c 0x16 0x0 + 0x0080 0x16 0x0 + 0x0084 0x36 0x0 + 0x0088 0x36 0x0 + 0x0094 0x08 0x0 + 0x00a4 0x42 0x0 + 0x00ac 0x0a 0x0 + 0x00b0 0x1a 0x0 + 0x00b4 0x14 0x0 + 0x00b8 0x34 0x0 + 0x00bc 0x82 0x0 + 0x00c4 0x68 0x0 + 0x00cc 0x55 0x0 + 0x00d0 0x55 0x0 + 0x00d4 0x03 0x0 + 0x00d8 0xab 0x0 + 0x00dc 0xaa 0x0 + 0x00e0 0x02 0x0 + 0x010c 0x02 0x0 + 0x0110 0x24 0x0 + 0x0118 0xb4 0x0 + 0x011c 0x03 0x0 + 0x0154 0x34 0x0 + 0x0158 0x01 0x0 + 0x016c 0x08 0x0 + 0x01ac 0xca 0x0 + 0x01b0 0x1e 0x0 + 0x01b4 0xa2 0x0 + 0x01b8 0x18 0x0 + 0x01bc 0x11 0x0 + 0x023c 0x11 0x0 + 0x0284 0x75 0x0 + 0x029c 0x12 0x0 + 0x0304 0x02 0x0 + 0x0408 0x0c 0x0 + 0x0414 0x03 0x0 + 0x0434 0x7f 0x0 + 0x0444 0x70 0x0 + 0x0460 0x30 0x0 + 0x04d4 0x04 0x0 + 0x04d8 0x07 0x0 + 0x04dc 0x1b 0x0 + 0x04e8 0x04 0x0 + 0x04ec 0x0e 0x0 + 0x04f0 0x4a 0x0 + 0x04f4 0x0f 0x0 + 0x04f8 0xc0 0x0 + 0x04fc 0x00 0x0 + 0x0510 0x17 0x0 + 0x0518 0x1c 0x0 + 0x051c 0x03 0x0 + 0x0524 0x1e 0x0 + 0x0570 0xbf 0x0 + 0x0574 0x3f 0x0 + 0x0578 0xff 0x0 + 0x057c 0x7f 0x0 + 0x0580 0x15 0x0 + 0x0584 0x24 0x0 + 0x0588 0xe4 0x0 + 0x058c 0xec 0x0 + 0x0590 0x3b 0x0 + 0x0594 0x36 0x0 + 0x0598 0xd4 0x0 + 0x059c 0x54 0x0 + 0x05a0 0xdb 0x0 + 0x05a4 0x3b 0x0 + 0x05a8 0x31 0x0 + 0x05bc 0x0c 0x0 + 0x05b8 0x38 0x0 + 0x063c 0x11 0x0 + 0x0684 0x75 0x0 + 0x069c 0x12 0x0 + 0x0704 0x20 0x0 + 0x0808 0x0c 0x0 + 0x0814 0x03 0x0 + 0x0834 0x7f 0x0 + 0x0844 0x70 0x0 + 0x0860 0x30 0x0 + 0x08d4 0x04 0x0 + 0x08d8 0x07 0x0 + 0x08dc 0x1b 0x0 + 0x08e8 0x04 0x0 + 0x08ec 0x0e 0x0 + 0x08f0 0x4a 0x0 + 0x08f4 0x0f 0x0 + 0x08f8 0xc0 0x0 + 0x08fc 0x00 0x0 + 0x0910 0x17 0x0 + 0x0918 0x1c 0x0 + 0x091c 0x03 0x0 + 0x0924 0x1e 0x0 + 0x0970 0xbf 0x0 + 0x0974 0x3f 0x0 + 0x0978 0xff 0x0 + 0x097c 0x7f 0x0 + 0x0980 0x15 0x0 + 0x0984 0x24 0x0 + 0x0988 0xe4 0x0 + 0x098c 0xec 0x0 + 0x0990 0x3b 0x0 + 0x0994 0x36 0x0 + 0x0998 0xd4 0x0 + 0x099c 0x54 0x0 + 0x09a0 0xdb 0x0 + 0x09a4 0x3b 0x0 + 0x09a8 0x31 0x0 + 0x09bc 0x0c 0x0 + 0x09b8 0x38 0x0 + 0x0adc 0x05 0x0 + 0x0b88 0x77 0x0 + 0x0b98 0x0b 0x0 + 0x0ba4 0x01 0x0 + 0x0be0 0x0f 0x0 + 0x0e0c 0x0d 0x0 + 0x0e14 0x07 0x0 + 0x0e1c 0xc1 0x0 + 0x0e40 0x01 0x0 + 0x0e48 0x01 0x0 + 0x0e90 0x00 0x0 + 0x0eb4 0x33 0x0 + 0x0ebc 0x00 0x0 + 0x0ee0 0x58 0x0 + 0x0a00 0x00 0x0 + 0x0a44 0x03 0x0>; + + pcie2_rp: pcie2_rp { + reg = <0 0 0 0 0>; + }; + }; + + pcie2_msi: qcom,pcie2_msi@17a10040 { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a10040 0x0>; + interrupt-parent = <&intc>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-pinctrl.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d2d94defbcd10d61f7dc66ca9e9c418de5606c01 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-pinctrl.dtsi @@ -0,0 +1,4614 @@ +&soc { + tlmm: pinctrl@f000000 { + compatible = "qcom,kona-pinctrl"; + reg = <0x0F000000 0x1000000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + irqdomain-map = <0 0 &pdc 79 0>, + <1 0 &pdc 84 0>, + <2 0 &pdc 80 0>, + <3 0 &pdc 82 0>, + <4 0 &pdc 107 0>, + <7 0 &pdc 43 0>, + <11 0 &pdc 42 0>, + <14 0 &pdc 44 0>, + <15 0 &pdc 52 0>, + <19 0 &pdc 67 0>, + <23 0 &pdc 68 0>, + <24 0 &pdc 105 0>, + <27 0 &pdc 92 0>, + <28 0 &pdc 106 0>, + <31 0 &pdc 69 0>, + <35 0 &pdc 70 0>, + <39 0 &pdc 73 0>, + <40 0 &pdc 108 0>, + <43 0 &pdc 71 0>, + <45 0 &pdc 72 0>, + <47 0 &pdc 83 0>, + <51 0 &pdc 74 0>, + <55 0 &pdc 77 0>, + <59 0 &pdc 78 0>, + <63 0 &pdc 75 0>, + <64 0 &pdc 81 0>, + <65 0 &pdc 87 0>, + <66 0 &pdc 88 0>, + <67 0 &pdc 89 0>, + <68 0 &pdc 54 0>, + <70 0 &pdc 85 0>, + <77 0 &pdc 46 0>, + <80 0 &pdc 90 0>, + <81 0 &pdc 91 0>, + <83 0 &pdc 97 0>, + <84 0 &pdc 98 0>, + <86 0 &pdc 99 0>, + <88 0 &pdc 101 0>, + <89 0 &pdc 102 0>, + <92 0 &pdc 103 0>, + <93 0 &pdc 104 0>, + <100 0 &pdc 53 0>, + <103 0 &pdc 47 0>, + <104 0 &pdc 48 0>, + <108 0 &pdc 49 0>, + <109 0 &pdc 94 0>, + <110 0 &pdc 95 0>, + <111 0 &pdc 96 0>, + <112 0 &pdc 55 0>, + <113 0 &pdc 56 0>, + <118 0 &pdc 50 0>, + <121 0 &pdc 51 0>, + <122 0 &pdc 57 0>, + <123 0 &pdc 58 0>, + <124 0 &pdc 45 0>, + <126 0 &pdc 59 0>, + <128 0 &pdc 76 0>, + <129 0 &pdc 86 0>, + <132 0 &pdc 93 0>, + <133 0 &pdc 65 0>, + <134 0 &pdc 66 0>, + <136 0 &pdc 62 0>, + <137 0 &pdc 63 0>, + <138 0 &pdc 64 0>, + <142 0 &pdc 60 0>, + <143 0 &pdc 61 0>, + <147 0 &pdc 109 0>, /* bi_mx_lpass_1_aoss_mx */ + <150 0 &pdc 110 0>, + <157 0 &pdc 111 0>, + <158 0 &pdc 112 0>, + <160 0 &pdc 113 0>, + <162 0 &pdc 114 0>, + <164 0 &pdc 115 0>, + <166 0 &pdc 116 0>, + <167 0 &pdc 117 0>, + <175 0 &pdc 118 0>, + <177 0 &pdc 119 0>, + <179 0 &pdc 120 0>; + irqdomain-map-mask = <0xff 0>; + irqdomain-map-pass-thru = <0 0xff>; + + trigout_a: trigout_a { + mux { + pins = "gpio2"; + function = "qdss_cti"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_2uart_pins: qupv3_se2_2uart_pins { + qupv3_se2_2uart_active: qupv3_se2_2uart_active { + mux { + pins = "gpio117", "gpio118"; + function = "qup2"; + }; + + config { + pins = "gpio117", "gpio118"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_2uart_sleep: qupv3_se2_2uart_sleep { + mux { + pins = "gpio117", "gpio118"; + function = "gpio"; + }; + + config { + pins = "gpio117", "gpio118"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se6_4uart_pins: qupv3_se6_4uart_pins { + qupv3_se6_default_cts: + qupv3_se6_default_cts { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_default_rtsrx: + qupv3_se6_default_rtsrx { + mux { + pins = "gpio17", "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio19"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se6_default_tx: + qupv3_se6_default_tx { + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se6_ctsrx: qupv3_se6_ctsrx { + mux { + pins = "gpio16", "gpio19"; + function = "qup6"; + }; + + config { + pins = "gpio16", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_rts: qupv3_se6_rts { + mux { + pins = "gpio17"; + function = "qup6"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se6_tx: qupv3_se6_tx { + mux { + pins = "gpio18"; + function = "qup6"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se12_2uart_pins: qupv3_se12_2uart_pins { + qupv3_se12_2uart_active: qupv3_se12_2uart_active { + mux { + pins = "gpio34", "gpio35"; + function = "qup12"; + }; + + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + }; + }; + + qupv3_se12_2uart_sleep: qupv3_se12_2uart_sleep { + mux { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-pull-down; + }; + + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se17_4uart_pins: qupv3_se17_4uart_pins { + qupv3_se17_ctsrx: qupv3_se17_ctsrx { + mux { + pins = "gpio52", "gpio55"; + function = "qup17"; + }; + + config { + pins = "gpio52", "gpio55"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + qupv3_se17_rts: qupv3_se17_rts { + mux { + pins = "gpio53"; + function = "qup17"; + }; + + config { + pins = "gpio53"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se17_tx: qupv3_se17_tx { + mux { + pins = "gpio54"; + function = "qup17"; + }; + + config { + pins = "gpio54"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se18_2uart_pins: qupv3_se18_2uart_pins { + qupv3_se18_rx: qupv3_se18_rx { + mux { + pins = "gpio59"; + function = "qup18"; + }; + + config { + pins = "gpio59"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + qupv3_se18_tx: qupv3_se18_tx { + mux { + pins = "gpio58"; + function = "qup18"; + }; + + config { + pins = "gpio58"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio38", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio39"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + pmx_ts_release: pmx_ts_release { + mux { + pins = "gpio38", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + + storage_cd: storage_cd { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_clk_ds_400KHz: sdc2_clk_ds_400KHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_ds_50MHz: sdc2_clk_ds_50MHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_ds_100MHz: sdc2_clk_ds_100MHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_ds_200MHz: sdc2_clk_ds_200MHz { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_ds_400KHz: sdc2_cmd_ds_400KHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_cmd_ds_50MHz: sdc2_cmd_ds_50MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_cmd_ds_100MHz: sdc2_cmd_ds_100MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_cmd_ds_200MHz: sdc2_cmd_ds_200MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_ds_400KHz: sdc2_data_ds_400KHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_data_ds_50MHz: sdc2_data_ds_50MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_data_ds_100MHz: sdc2_data_ds_100MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_data_ds_200MHz: sdc2_data_ds_200MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + /* add pins for DisplayPort */ + sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + bias-disable; + drive-strength = <16>; + }; + }; + + sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_suspend { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + ap2mdm { + ap2mdm_active: ap2mdm_active { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio56", "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio56", "gpio57"; + drive-strength = <16>; + bias-disable; + }; + }; + + ap2mdm_sleep: ap2mdm_sleep { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio56", "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio56", "gpio57"; + drive-strength = <8>; + bias-disable; + }; + + }; + }; + + mdm2ap { + mdm2ap_active: mdm2ap_active { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio1", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio1", "gpio3"; + drive-strength = <8>; + bias-disable; + }; + }; + + mdm2ap_sleep: mdm2ap_sleep { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio1", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio1", "gpio3"; + drive-strength = <8>; + bias-disable; + }; + }; + }; + + pcie0 { + pcie0_perst_default: pcie0_perst_default { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie0_clkreq_default: pcie0_clkreq_default { + mux { + pins = "gpio80"; + function = "pci_e0"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_wake_default: pcie0_wake_default { + mux { + pins = "gpio81"; + function = "gpio"; + }; + + config { + pins = "gpio81"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_clkreq_sleep: pcie0_clkreq_sleep { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + pcie1 { + pcie1_perst_default: pcie1_perst_default { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie1_clkreq_default: pcie1_clkreq_default { + mux { + pins = "gpio83"; + function = "pci_e1"; + }; + + config { + pins = "gpio83"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie1_wake_default: pcie1_wake_default { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + pcie2 { + pcie2_perst_default: pcie2_perst_default { + mux { + pins = "gpio85"; + function = "gpio"; + }; + + config { + pins = "gpio85"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie2_clkreq_default: pcie2_clkreq_default { + mux { + pins = "gpio86"; + function = "pci_e2"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie2_wake_default: pcie2_wake_default { + mux { + pins = "gpio87"; + function = "gpio"; + }; + + config { + pins = "gpio87"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + cnss_pins { + cnss_wlan_en_active: cnss_wlan_en_active { + mux { + pins = "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio20"; + drive-strength = <16>; + output-high; + bias-pull-up; + }; + }; + + cnss_wlan_en_sleep: cnss_wlan_en_sleep { + mux { + pins = "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + output-low; + bias-pull-down; + }; + }; + }; + + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio75", "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio60"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio75", "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_dsi1_active: sde_dsi1_active { + mux { + pins = "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio128"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + + sde_dsi1_suspend: sde_dsi1_suspend { + mux { + pins = "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio128"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio66"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio66"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te1_active: sde_te1_active { + mux { + pins = "gpio67"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te1_suspend: sde_te1_suspend { + mux { + pins = "gpio67"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pri_aux_pcm_clk { + pri_aux_pcm_clk_sleep: pri_aux_pcm_clk_sleep { + mux { + pins = "gpio138"; + function = "gpio"; + }; + + config { + pins = "gpio138"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_clk_active: pri_aux_pcm_clk_active { + mux { + pins = "gpio138"; + function = "mi2s0_sck"; + }; + + config { + pins = "gpio138"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_aux_pcm_sync { + pri_aux_pcm_sync_sleep: pri_aux_pcm_sync_sleep { + mux { + pins = "gpio141"; + function = "gpio"; + }; + + config { + pins = "gpio141"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_sync_active: pri_aux_pcm_sync_active { + mux { + pins = "gpio141"; + function = "mi2s0_ws"; + }; + + config { + pins = "gpio141"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_aux_pcm_din { + pri_aux_pcm_din_sleep: pri_aux_pcm_din_sleep { + mux { + pins = "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio139"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_din_active: pri_aux_pcm_din_active { + mux { + pins = "gpio139"; + function = "mi2s0_data0"; + }; + + config { + pins = "gpio139"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_aux_pcm_dout { + pri_aux_pcm_dout_sleep: pri_aux_pcm_dout_sleep { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_dout_active: pri_aux_pcm_dout_active { + mux { + pins = "gpio140"; + function = "mi2s0_data1"; + }; + + config { + pins = "gpio140"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm { + sec_aux_pcm_clk_sleep: sec_aux_pcm_clk_sleep { + mux { + pins = "gpio142"; + function = "gpio"; + }; + + config { + pins = "gpio142"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_clk_active: sec_aux_pcm_clk_active { + mux { + pins = "gpio142"; + function = "mi2s1_sck"; + }; + + config { + pins = "gpio142"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + + sec_aux_pcm_ws_sleep: sec_aux_pcm_ws_sleep { + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_ws_active: sec_aux_pcm_ws_active { + mux { + pins = "gpio145"; + function = "mi2s1_ws"; + }; + + config { + pins = "gpio145"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm_din { + sec_aux_pcm_din_sleep: sec_aux_pcm_din_sleep { + mux { + pins = "gpio143"; + function = "gpio"; + }; + + config { + pins = "gpio143"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_din_active: sec_aux_pcm_din_active { + mux { + pins = "gpio143"; + function = "mi2s1_data0"; + }; + + config { + pins = "gpio143"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm_dout { + sec_aux_pcm_dout_sleep: sec_aux_pcm_dout_sleep { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_dout_active: sec_aux_pcm_dout_active { + mux { + pins = "gpio144"; + function = "mi2s1_data1"; + }; + + config { + pins = "gpio144"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_aux_pcm { + tert_aux_pcm_clk_sleep: tert_aux_pcm_clk_sleep { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_clk_active: tert_aux_pcm_clk_active { + mux { + pins = "gpio133"; + function = "mi2s2_sck"; + }; + + config { + pins = "gpio133"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + + tert_aux_pcm_ws_sleep: tert_aux_pcm_ws_sleep { + mux { + pins = "gpio135"; + function = "gpio"; + }; + + config { + pins = "gpio135"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_ws_active: tert_aux_pcm_ws_active { + mux { + pins = "gpio135"; + function = "mi2s2_ws"; + }; + + config { + pins = "gpio135"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_aux_pcm_din { + tert_aux_pcm_din_sleep: tert_aux_pcm_din_sleep { + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_din_active: tert_aux_pcm_din_active { + mux { + pins = "gpio134"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio134"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_aux_pcm_dout { + tert_aux_pcm_dout_sleep: tert_aux_pcm_dout_sleep { + mux { + pins = "gpio137"; + function = "gpio"; + }; + + config { + pins = "gpio137"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_dout_active: tert_aux_pcm_dout_active { + mux { + pins = "gpio137"; + function = "mi2s2_data1"; + }; + + config { + pins = "gpio137"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_tdm_clk { + pri_tdm_clk_sleep: pri_tdm_clk_sleep { + mux { + pins = "gpio138"; + function = "gpio"; + }; + + config { + pins = "gpio138"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_tdm_clk_active: pri_tdm_clk_active { + mux { + pins = "gpio138"; + function = "mi2s0_sck"; + }; + + config { + pins = "gpio138"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_tdm_sync { + pri_tdm_sync_sleep: pri_tdm_sync_sleep { + mux { + pins = "gpio141"; + function = "gpio"; + }; + + config { + pins = "gpio141"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_tdm_sync_active: pri_tdm_sync_active { + mux { + pins = "gpio141"; + function = "mi2s0_ws"; + }; + + config { + pins = "gpio141"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_tdm_din { + pri_tdm_din_sleep: pri_tdm_din_sleep { + mux { + pins = "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio139"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_tdm_din_active: pri_tdm_din_active { + mux { + pins = "gpio139"; + function = "mi2s0_data0"; + }; + + config { + pins = "gpio139"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_tdm_dout { + pri_tdm_dout_sleep: pri_tdm_dout_sleep { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_tdm_dout_active: pri_tdm_dout_active { + mux { + pins = "gpio140"; + function = "mi2s0_data1"; + }; + + config { + pins = "gpio140"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_tdm { + sec_tdm_sck_sleep: sec_tdm_sck_sleep { + mux { + pins = "gpio142"; + function = "gpio"; + }; + + config { + pins = "gpio142"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_tdm_sck_active: sec_tdm_sck_active { + mux { + pins = "gpio142"; + function = "mi2s1_sck"; + }; + + config { + pins = "gpio142"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + + sec_tdm_ws_sleep: sec_tdm_ws_sleep { + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_tdm_ws_active: sec_tdm_ws_active { + mux { + pins = "gpio145"; + function = "mi2s1_ws"; + }; + + config { + pins = "gpio145"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_tdm_din { + sec_tdm_din_sleep: sec_tdm_din_sleep { + mux { + pins = "gpio143"; + function = "gpio"; + }; + + config { + pins = "gpio143"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_tdm_din_active: sec_tdm_din_active { + mux { + pins = "gpio143"; + function = "mi2s1_data0"; + }; + + config { + pins = "gpio143"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_tdm_dout { + sec_tdm_dout_sleep: sec_tdm_dout_sleep { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_tdm_dout_active: sec_tdm_dout_active { + mux { + pins = "gpio144"; + function = "mi2s1_data1"; + }; + + config { + pins = "gpio144"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_tdm { + tert_tdm_clk_sleep: tert_tdm_clk_sleep { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_tdm_clk_active: tert_tdm_clk_active { + mux { + pins = "gpio133"; + function = "mi2s2_sck"; + }; + + config { + pins = "gpio133"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + + tert_tdm_ws_sleep: tert_tdm_ws_sleep { + mux { + pins = "gpio135"; + function = "gpio"; + }; + + config { + pins = "gpio135"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_tdm_ws_active: tert_tdm_ws_active { + mux { + pins = "gpio135"; + function = "mi2s2_ws"; + }; + + config { + pins = "gpio135"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_tdm_din { + tert_tdm_din_sleep: tert_tdm_din_sleep { + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_tdm_din_active: tert_tdm_din_active { + mux { + pins = "gpio134"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio134"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_tdm_dout { + tert_tdm_dout_sleep: tert_tdm_dout_sleep { + mux { + pins = "gpio137"; + function = "gpio"; + }; + + config { + pins = "gpio137"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_tdm_dout_active: tert_tdm_dout_active { + mux { + pins = "gpio137"; + function = "mi2s2_data1"; + }; + + config { + pins = "gpio137"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_mi2s_mclk { + pri_mi2s_mclk_sleep: pri_mi2s_mclk_sleep { + mux { + pins = "gpio136"; + function = "gpio"; + }; + + config { + pins = "gpio136"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_mclk_active: pri_mi2s_mclk_active { + mux { + pins = "gpio136"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio136"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sck { + pri_mi2s_sck_sleep: pri_mi2s_sck_sleep { + mux { + pins = "gpio138"; + function = "gpio"; + }; + + config { + pins = "gpio138"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sck_active: pri_mi2s_sck_active { + mux { + pins = "gpio138"; + function = "mi2s0_sck"; + }; + + config { + pins = "gpio138"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_ws { + pri_mi2s_ws_sleep: pri_mi2s_ws_sleep { + mux { + pins = "gpio141"; + function = "gpio"; + }; + + config { + pins = "gpio141"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_ws_active: pri_mi2s_ws_active { + mux { + pins = "gpio141"; + function = "mi2s0_ws"; + }; + + config { + pins = "gpio141"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sd0 { + pri_mi2s_sd0_sleep: pri_mi2s_sd0_sleep { + mux { + pins = "gpio139"; + function = "gpio"; + }; + + config { + pins = "gpio139"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd0_active: pri_mi2s_sd0_active { + mux { + pins = "gpio139"; + function = "mi2s0_data0"; + }; + + config { + pins = "gpio139"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sd1 { + pri_mi2s_sd1_sleep: pri_mi2s_sd1_sleep { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd1_active: pri_mi2s_sd1_active { + mux { + pins = "gpio140"; + function = "mi2s0_data1"; + }; + + config { + pins = "gpio140"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + sec_mi2s_mclk { + sec_mi2s_mclk_sleep: sec_mi2s_mclk_sleep { + mux { + pins = "gpio137"; + function = "gpio"; + }; + + config { + pins = "gpio137"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_mclk_active: sec_mi2s_mclk_active { + mux { + pins = "gpio137"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio137"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + sec_mi2s_sck { + sec_mi2s_sck_sleep: sec_mi2s_sck_sleep { + mux { + pins = "gpio142"; + function = "gpio"; + }; + + config { + pins = "gpio142"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sck_active: sec_mi2s_sck_active { + mux { + pins = "gpio142"; + function = "mi2s1_sck"; + }; + + config { + pins = "gpio142"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_ws { + sec_mi2s_ws_sleep: sec_mi2s_ws_sleep { + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_ws_active: sec_mi2s_ws_active { + mux { + pins = "gpio145"; + function = "mi2s1_ws"; + }; + + config { + pins = "gpio145"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_sd0 { + sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep { + mux { + pins = "gpio143"; + function = "gpio"; + }; + + config { + pins = "gpio143"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd0_active: sec_mi2s_sd0_active { + mux { + pins = "gpio143"; + function = "mi2s1_data0"; + }; + + config { + pins = "gpio143"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_sd1 { + sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd1_active: sec_mi2s_sd1_active { + mux { + pins = "gpio144"; + function = "mi2s1_data1"; + }; + + config { + pins = "gpio144"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sck { + tert_mi2s_sck_sleep: tert_mi2s_sck_sleep { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sck_active: tert_mi2s_sck_active { + mux { + pins = "gpio133"; + function = "mi2s2_sck"; + }; + + config { + pins = "gpio133"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_ws { + tert_mi2s_ws_sleep: tert_mi2s_ws_sleep { + mux { + pins = "gpio135"; + function = "gpio"; + }; + + config { + pins = "gpio135"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_ws_active: tert_mi2s_ws_active { + mux { + pins = "gpio135"; + function = "mi2s2_ws"; + }; + + config { + pins = "gpio135"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sd0 { + tert_mi2s_sd0_sleep: tert_mi2s_sd0_sleep { + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd0_active: tert_mi2s_sd0_active { + mux { + pins = "gpio134"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio134"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sd1 { + tert_mi2s_sd1_sleep: tert_mi2s_sd1_sleep { + mux { + pins = "gpio137"; + function = "gpio"; + }; + + config { + pins = "gpio137"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd1_active: tert_mi2s_sd1_active { + mux { + pins = "gpio137"; + function = "mi2s2_data1"; + }; + + config { + pins = "gpio137"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + /* WSA speaker reset pins */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + wcd938x_reset_active: wcd938x_reset_active { + mux { + pins = "gpio32"; + function = "func2"; + }; + + config { + pins = "gpio32"; + drive-strength = <16>; + output-high; + }; + }; + + wcd938x_reset_sleep: wcd938x_reset_sleep { + mux { + pins = "gpio32"; + function = "func2"; + }; + + config { + pins = "gpio32"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_active: cam_sensor_mclk4_active { + /* MCLK4 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_suspend: cam_sensor_mclk4_suspend { + /* MCLK4 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk5_active: cam_sensor_mclk5_active { + /* MCLK5 */ + mux { + pins = "gpio99"; + function = "cam_mclk"; + }; + + config { + pins = "gpio99"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk5_suspend: cam_sensor_mclk5_suspend { + /* MCLK5 */ + mux { + pins = "gpio99"; + function = "cam_mclk"; + }; + + config { + pins = "gpio99"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk6_active: cam_sensor_mclk6_active { + /* MCLK6 */ + mux { + pins = "gpio100"; + function = "cam_mclk"; + }; + + config { + pins = "gpio100"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk6_suspend: cam_sensor_mclk6_suspend { + /* MCLK6 */ + mux { + pins = "gpio100"; + function = "cam_mclk"; + }; + + config { + pins = "gpio100"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rear: cam_sensor_active_rear { + /* RESET REAR */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear: cam_sensor_suspend_rear { + /* RESET REAR */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rear_aux: cam_sensor_active_rear_aux { + /* RESET REARAUX */ + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear_aux: cam_sensor_suspend_rear_aux { + /* RESET REARAUX */ + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rst2: cam_sensor_active_rst2 { + /* RESET 2 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rst2: cam_sensor_suspend_rst2 { + /* RESET 2 */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_3: cam_sensor_active_3 { + /* RESET 3 */ + mux { + pins = "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio109"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_3: cam_sensor_suspend_3 { + /* RESET 3 */ + mux { + pins = "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio109"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_4: cam_sensor_active_4 { + /* RESET 4 */ + mux { + pins = "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio130"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_4: cam_sensor_suspend_4 { + /* RESET 4 */ + mux { + pins = "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio130"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_5: cam_sensor_active_5 { + /* RESET 5 */ + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_5: cam_sensor_suspend_5 { + /* RESET 5 */ + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_6: cam_sensor_active_6 { + /* RESET 6 */ + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_6: cam_sensor_suspend_6 { + /* RESET 6 */ + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio101","gpio102"; // Only 2 + function = "cci_i2c"; + }; + + config { + pins = "gpio101","gpio102"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio101","gpio102"; + function = "cci_i2c"; + }; + + config { + pins = "gpio101","gpio102"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio103","gpio104"; + function = "cci_i2c"; + }; + + config { + pins = "gpio103","gpio104"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio103","gpio104"; + function = "cci_i2c"; + }; + + config { + pins = "gpio103","gpio104"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_active: cci2_active { + mux { + /* CLK, DATA */ + pins = "gpio105","gpio106"; + function = "cci_i2c"; + }; + + config { + pins = "gpio105","gpio106"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_suspend: cci2_suspend { + mux { + /* CLK, DATA */ + pins = "gpio105","gpio106"; + function = "cci_i2c"; + }; + + config { + pins = "gpio105","gpio106"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_active: cci3_active { + mux { + /* CLK, DATA */ + pins = "gpio107","gpio108"; + function = "cci_i2c"; + }; + + config { + pins = "gpio107","gpio108"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_suspend: cci3_suspend { + mux { + /* CLK, DATA */ + pins = "gpio107","gpio108"; + function = "cci_i2c"; + }; + + config { + pins = "gpio107","gpio108"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + tsif0_signals_active: tsif0_signals_active { + tsif1_clk { + pins = "gpio69"; /* TSIF0 CLK */ + function = "tsif0_clk"; + }; + + tsif1_en { + pins = "gpio70"; /* TSIF0 Enable */ + function = "tsif0_en"; + }; + + tsif1_data { + pins = "gpio71"; /* TSIF0 DATA */ + function = "tsif0_data"; + }; + + signals_cfg { + pins = "gpio69", "gpio70", "gpio71"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif0_sync_active: tsif0_sync_active { + tsif1_sync { + pins = "gpio72"; /* TSIF0 SYNC */ + function = "tsif0_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + tsif1_signals_active: tsif1_signals_active { + tsif2_clk { + pins = "gpio73"; /* TSIF1 CLK */ + function = "tsif1_clk"; + }; + + tsif2_en { + pins = "gpio74"; /* TSIF1 Enable */ + function = "tsif1_en"; + }; + + tsif2_data { + pins = "gpio75"; /* TSIF1 DATA */ + function = "tsif1_data"; + }; + + signals_cfg { + pins = "gpio73", "gpio74", "gpio75"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + /* sync signal is only used if configured to mode-2 */ + tsif1_sync_active: tsif1_sync_active { + tsif2_sync { + pins = "gpio76"; /* TSIF1 SYNC */ + function = "tsif1_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + sde_led_driver_en1_gpio: sde_led_driver_en1_gpio { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + bias-pull-down; + drive-strength = <16>; + }; + }; + + sde_led_driver_en2_gpio: sde_led_driver_en2_gpio { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + bias-pull-down; + drive-strength = <16>; + }; + }; + + sde_led_5v_en_gpio: sde_led_5v_en_gpio { + mux { + pins = "gpio134"; + function = "gpio"; + }; + + config { + pins = "gpio134"; + bias-pull-down; + drive-strength = <16>; + }; + }; + + sde_display_1p8_en_gpio: sde_display_1p8_en_gpio { + mux { + pins = "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio133"; + bias-pull-down; + drive-strength = <16>; + }; + }; + + cam_sensor_6dof_vana_active: cam_sensor_6dof_vana_active { + /* AVDD LDO */ + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vana_suspend: cam_sensor_6dof_vana_suspend { + /* AVDD LDO */ + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vdig_active: cam_sensor_6dof_vdig_active { + /* VDIG LDO */ + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vdig_suspend: cam_sensor_6dof_vdig_suspend { + /* VDIG LDO */ + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vio_active: cam_sensor_6dof_vio_active { + /* VIO LDO */ + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vio_suspend: cam_sensor_6dof_vio_suspend { + /* VIO LDO */ + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_et_vana_active: cam_sensor_et_vana_active { + /* AVDD LDO */ + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_et_vana_suspend: cam_sensor_et_vana_suspend { + /* AVDD LDO */ + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_et_vio_active: cam_sensor_et_vio_active { + /* VIO LDO */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_et_vio_suspend: cam_sensor_et_vio_suspend { + /* VIO LDO */ + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rgb_vana_active: cam_sensor_rgb_vana_active { + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rgb_vana_suspend: cam_sensor_rgb_vana_suspend { + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rgb_vio_active: cam_sensor_rgb_vio_active { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rgb_vio_suspend: cam_sensor_rgb_vio_suspend { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rgb_vdig_active: cam_sensor_rgb_vdig_active { + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rgb_vdig_suspend: cam_sensor_rgb_vdig_suspend { + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_etleft: cam_sensor_active_etleft { + /* RESET REAR */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_etleft: cam_sensor_suspend_etleft { + /* RESET REAR */ + mux { + pins = "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio93"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_etright: cam_sensor_active_etright { + /* RESET REAR */ + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_etright: cam_sensor_suspend_etright { + /* RESET REAR */ + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_6dofleft: cam_sensor_active_6dofleft { + /* RESET REAR */ + mux { + pins = "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio130"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_6dofleft: cam_sensor_suspend_6dofleft { + /* RESET REAR */ + mux { + pins = "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio130"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_6dofright: cam_sensor_active_6dofright { + /* RESET REAR */ + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_6dofright: cam_sensor_suspend_6dofright { + /* RESET REAR */ + mux { + pins = "gpio131"; + function = "gpio"; + }; + + config { + pins = "gpio131"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rgbright: cam_sensor_active_rgbright { + /* RESET REAR */ + mux { + pins = "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio109"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rgbright: cam_sensor_suspend_rgbright { + /* RESET REAR */ + mux { + pins = "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio109"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rgbleft: cam_sensor_active_rgbleft { + /* RESET REAR */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rgbleft: cam_sensor_suspend_rgbleft { + /* RESET REAR */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + bt_en_sleep: bt_en_sleep { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + output-low; + bias-pull-down; + }; + }; + + /* QUPv3_0 North SE0 mappings */ + qupv3_se0_i3c_pins: qupv3_se0_i3c_pins { + qupv3_se0_i3c_active: qupv3_se0_i3c_active { + mux { + pins = "gpio28", "gpio29"; + function = "ibi_i3c"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + qupv3_se0_i3c_sleep: qupv3_se0_i3c_sleep { + mux { + pins = "gpio28", "gpio29"; + function = "ibi_i3c"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + qupv3_se0_i3c_disable: qupv3_se0_i3c_disable { + mux { + pins = "gpio28", "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + /* QUPv3_0 North SE1 mappings */ + qupv3_se1_i3c_pins: qupv3_se1_i3c_pins { + qupv3_se1_i3c_active: qupv3_se1_i3c_active { + mux { + pins = "gpio4", "gpio5"; + function = "ibi_i3c"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + qupv3_se1_i3c_sleep: qupv3_se1_i3c_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "ibi_i3c"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + qupv3_se1_i3c_disable: qupv3_se1_i3c_disable { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + /* SE 0 pin mappings */ + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio28", "gpio29"; + function = "qup0"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio28", "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio28", "gpio29"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 1 pin mappings */ + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup1"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + lt9611_pins: lt9611_pins { + mux { + pins = "gpio2", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio2", "gpio1"; + drive-strength = <8>; + bias-disable = <0>; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 111 NFC Read Interrupt */ + pins = "gpio111"; + function = "gpio"; + }; + + config { + pins = "gpio111"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 111 NFC Read Interrupt */ + pins = "gpio111"; + function = "gpio"; + }; + + config { + pins = "gpio111"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 6: Enable 110: Firmware */ + pins = "gpio6", "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio110"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 6: Enable 110: Firmware */ + pins = "gpio6", "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio110"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + + nfc_clk_req_active: nfc_clk_req_active { + /* active state */ + mux { + /* GPIO 7: NFC CLOCK REQUEST */ + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_clk_req_suspend: nfc_clk_req_suspend { + /* sleep state */ + mux { + /* GPIO 7: NFC CLOCK REQUEST */ + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + /* SE 2 pin mappings */ + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio115", "gpio116"; + function = "qup2"; + }; + + config { + pins = "gpio115", "gpio116"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio115", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio115", "gpio116"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 3 pin mappings */ + qupv3_se3_i2c_pins: qupv3_se3_i2c_pins { + qupv3_se3_i2c_active: qupv3_se3_i2c_active { + mux { + pins = "gpio119", "gpio120"; + function = "qup3"; + }; + + config { + pins = "gpio119", "gpio120"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep { + mux { + pins = "gpio119", "gpio120"; + function = "gpio"; + }; + + config { + pins = "gpio119", "gpio120"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 4 pin mappings */ + qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { + qupv3_se4_i2c_active: qupv3_se4_i2c_active { + mux { + pins = "gpio8", "gpio9"; + function = "qup4"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 5 pin mappings */ + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio12", "gpio13"; + function = "qup5"; + }; + + config { + pins = "gpio12", "gpio13"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio12", "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio13"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 6 pin mappings */ + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio16", "gpio17"; + function = "qup6"; + }; + + config { + pins = "gpio16", "gpio17"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio16", "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio17"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 7 pin mappings */ + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio20", "gpio21"; + function = "qup7"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio20", "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio20", "gpio21"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio28", "gpio29", "gpio30", + "gpio31"; + function = "qup0"; + }; + + config { + pins = "gpio28", "gpio29", "gpio30", + "gpio31"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio28", "gpio29", "gpio30", + "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio28", "gpio29", "gpio30", + "gpio31"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + function = "qup1"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio115", "gpio116", "gpio117", + "gpio118"; + function = "qup2"; + }; + + config { + pins = "gpio115", "gpio116", "gpio117", + "gpio118"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio115", "gpio116", "gpio117", + "gpio118"; + function = "gpio"; + }; + + config { + pins = "gpio115", "gpio116", "gpio117", + "gpio118"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se3_spi_pins: qupv3_se3_spi_pins { + qupv3_se3_spi_active: qupv3_se3_spi_active { + mux { + pins = "gpio119", "gpio120", "gpio121", + "gpio122"; + function = "qup3"; + }; + + config { + pins = "gpio119", "gpio120", "gpio121", + "gpio122"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se3_spi_sleep: qupv3_se3_spi_sleep { + mux { + pins = "gpio119", "gpio120", "gpio121", + "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio119", "gpio120", "gpio121", + "gpio122"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se4_spi_pins: qupv3_se4_spi_pins { + qupv3_se4_spi_active: qupv3_se4_spi_active { + mux { + pins = "gpio8", "gpio9", "gpio10", + "gpio11"; + function = "qup4"; + }; + + config { + pins = "gpio8", "gpio9", "gpio10", + "gpio11"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se4_spi_sleep: qupv3_se4_spi_sleep { + mux { + pins = "gpio8", "gpio9", "gpio10", + "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9", "gpio10", + "gpio11"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio12", "gpio13", "gpio14", + "gpio15"; + function = "qup5"; + }; + + config { + pins = "gpio12", "gpio13", "gpio14", + "gpio15"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio12", "gpio13", "gpio14", + "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio12", "13", "gpio14", + "gpio15"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio16", "gpio17", "gpio18", + "gpio19"; + function = "qup6"; + }; + + config { + pins = "gpio16", "gpio17", "gpio18", + "gpio19"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio16", "gpio17", "gpio18", + "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio17", "gpio18", + "gpio19"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se7_spi_pins: qupv3_se7_spi_pins { + qupv3_se7_spi_active: qupv3_se7_spi_active { + mux { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + function = "qup7"; + }; + + config { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se7_spi_sleep: qupv3_se7_spi_sleep { + mux { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio20", "gpio21", "gpio22", + "gpio23"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* QUPv3_1 South_1 SE mappings */ + /* SE 8 pin mappings */ + qupv3_se8_i2c_pins: qupv3_se8_i2c_pins { + qupv3_se8_i2c_active: qupv3_se8_i2c_active { + mux { + pins = "gpio24", "gpio25"; + function = "qup8"; + }; + + config { + pins = "gpio24", "gpio25"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep { + mux { + pins = "gpio24", "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio24", "gpio25"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 9 pin mappings */ + qupv3_se9_i2c_pins: qupv3_se9_i2c_pins { + qupv3_se9_i2c_active: qupv3_se9_i2c_active { + mux { + pins = "gpio125", "gpio126"; + function = "qup9"; + }; + + config { + pins = "gpio125", "gpio126"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep { + mux { + pins = "gpio125", "gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio125", "gpio126"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 10 pin mappings */ + qupv3_se10_i2c_pins: qupv3_se10_i2c_pins { + qupv3_se10_i2c_active: qupv3_se10_i2c_active { + mux { + pins = "gpio129", "gpio130"; + function = "qup10"; + }; + + config { + pins = "gpio129", "gpio130"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep { + mux { + pins = "gpio129", "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio129", "gpio130"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 11 pin mappings */ + qupv3_se11_i2c_pins: qupv3_se11_i2c_pins { + qupv3_se11_i2c_active: qupv3_se11_i2c_active { + mux { + pins = "gpio60", "gpio61"; + function = "qup11"; + }; + + config { + pins = "gpio60", "gpio61"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep { + mux { + pins = "gpio60", "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio60", "gpio61"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 12 pin mappings */ + qupv3_se12_i2c_pins: qupv3_se12_i2c_pins { + qupv3_se12_i2c_active: qupv3_se12_i2c_active { + mux { + pins = "gpio32", "gpio33"; + function = "qup12"; + }; + + config { + pins = "gpio32", "gpio33"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se12_i2c_sleep: qupv3_se12_i2c_sleep { + mux { + pins = "gpio32", "gpio33"; + function = "gpio"; + }; + + config { + pins = "gpio32", "gpio33"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 13 pin mappings */ + qupv3_se13_i2c_pins: qupv3_se13_i2c_pins { + qupv3_se13_i2c_active: qupv3_se13_i2c_active { + mux { + pins = "gpio36", "gpio37"; + function = "qup13"; + }; + + config { + pins = "gpio36", "gpio37"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se13_i2c_sleep: qupv3_se13_i2c_sleep { + mux { + pins = "gpio36", "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio36", "gpio37"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + qupv3_se8_spi_pins: qupv3_se8_spi_pins { + qupv3_se8_spi_active: qupv3_se8_spi_active { + mux { + pins = "gpio24", "gpio25", "gpio26", + "gpio27"; + function = "qup8"; + }; + + config { + pins = "gpio24", "gpio25", "gpio26", + "gpio27"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se8_spi_sleep: qupv3_se8_spi_sleep { + mux { + pins = "gpio24", "gpio25", "gpio26", + "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio24", "gpio25", "gpio26", + "gpio27"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se9_spi_pins: qupv3_se9_spi_pins { + qupv3_se9_spi_active: qupv3_se9_spi_active { + mux { + pins = "gpio125", "gpio126", "gpio127", + "gpio128"; + function = "qup9"; + }; + + config { + pins = "gpio125", "gpio126", "gpio127", + "gpio128"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se9_spi_sleep: qupv3_se9_spi_sleep { + mux { + pins = "gpio125", "gpio126", "gpio127", + "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio125", "gpio126", "gpio127", + "gpio128"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se10_spi_pins: qupv3_se10_spi_pins { + qupv3_se10_spi_active: qupv3_se10_spi_active { + mux { + pins = "gpio129", "gpio130", "gpio131", + "gpio132"; + function = "qup10"; + }; + + config { + pins = "gpio129", "gpio130", "gpio131", + "gpio132"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se10_spi_sleep: qupv3_se10_spi_sleep { + mux { + pins = "gpio129", "gpio130", "gpio131", + "gpio132"; + function = "gpio"; + }; + + config { + pins = "gpio129", "gpio130", "gpio131", + "gpio132"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se11_spi_pins: qupv3_se11_spi_pins { + qupv3_se11_spi_active: qupv3_se11_spi_active { + mux { + pins = "gpio60", "gpio61", "gpio62", + "gpio63"; + function = "qup11"; + }; + + config { + pins = "gpio60", "gpio61", "gpio62", + "gpio63"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se11_spi_sleep: qupv3_se11_spi_sleep { + mux { + pins = "gpio60", "gpio61", "gpio62", + "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio60", "gpio61", "gpio62", + "gpio63"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se12_spi_pins: qupv3_se12_spi_pins { + qupv3_se12_spi_active: qupv3_se12_spi_active { + mux { + pins = "gpio32", "gpio33", "gpio34", + "gpio35"; + function = "qup12"; + }; + + config { + pins = "gpio32", "gpio33", "gpio34", + "gpio35"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se12_spi_sleep: qupv3_se12_spi_sleep { + mux { + pins = "gpio32", "gpio33", "gpio34", + "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio32", "gpio33", "gpio34", + "gpio35"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se13_spi_pins: qupv3_se13_spi_pins { + qupv3_se13_spi_active: qupv3_se13_spi_active { + mux { + pins = "gpio36", "gpio37", "gpio38", + "gpio39"; + function = "qup13"; + }; + + config { + pins = "gpio36", "gpio37", "gpio38", + "gpio39"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se13_spi_sleep: qupv3_se13_spi_sleep { + mux { + pins = "gpio36", "gpio37", "gpio38", + "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio36", "gpio37", "gpio38", + "gpio39"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* QUPv3_2 South_2 SE mappings */ + /* SE 14 pin mappings */ + qupv3_se14_i2c_pins: qupv3_se14_i2c_pins { + qupv3_se14_i2c_active: qupv3_se14_i2c_active { + mux { + pins = "gpio40", "gpio41"; + function = "qup14"; + }; + + config { + pins = "gpio40", "gpio41"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se14_i2c_sleep: qupv3_se14_i2c_sleep { + mux { + pins = "gpio40", "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio40", "gpio41"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 15 pin mappings */ + qupv3_se15_i2c_pins: qupv3_se15_i2c_pins { + qupv3_se15_i2c_active: qupv3_se15_i2c_active { + mux { + pins = "gpio44", "gpio45"; + function = "qup15"; + }; + + config { + pins = "gpio44", "gpio45"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se15_i2c_sleep: qupv3_se15_i2c_sleep { + mux { + pins = "gpio44", "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio44", "gpio45"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 16 pin mappings */ + qupv3_se16_i2c_pins: qupv3_se16_i2c_pins { + qupv3_se16_i2c_active: qupv3_se16_i2c_active { + mux { + pins = "gpio48", "gpio49"; + function = "qup16"; + }; + + config { + pins = "gpio48", "gpio49"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se16_i2c_sleep: qupv3_se16_i2c_sleep { + mux { + pins = "gpio48", "gpio49"; + function = "gpio"; + }; + + config { + pins = "gpio48", "gpio49"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 17 pin mappings */ + qupv3_se17_i2c_pins: qupv3_se17_i2c_pins { + qupv3_se17_i2c_active: qupv3_se17_i2c_active { + mux { + pins = "gpio52", "gpio53"; + function = "qup17"; + }; + + config { + pins = "gpio52", "gpio53"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se17_i2c_sleep: qupv3_se17_i2c_sleep { + mux { + pins = "gpio52", "gpio53"; + function = "gpio"; + }; + + config { + pins = "gpio52", "gpio53"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 18 pin mappings */ + qupv3_se18_i2c_pins: qupv3_se18_i2c_pins { + qupv3_se18_i2c_active: qupv3_se18_i2c_active { + mux { + pins = "gpio56", "gpio57"; + function = "qup18"; + }; + + config { + pins = "gpio56", "gpio57"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se18_i2c_sleep: qupv3_se18_i2c_sleep { + mux { + pins = "gpio56", "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio56", "gpio57"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 19 pin mappings */ + qupv3_se19_i2c_pins: qupv3_se19_i2c_pins { + qupv3_se19_i2c_active: qupv3_se19_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup19"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se19_i2c_sleep: qupv3_se19_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + qupv3_se14_spi_pins: qupv3_se14_spi_pins { + qupv3_se14_spi_active: qupv3_se14_spi_active { + mux { + pins = "gpio40", "gpio41", "gpio42", + "gpio43"; + function = "qup14"; + }; + + config { + pins = "gpio40", "gpio41", "gpio42", + "gpio43"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se14_spi_sleep: qupv3_se14_spi_sleep { + mux { + pins = "gpio40", "gpio41", "gpio42", + "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio40", "gpio41", "gpio42", + "gpio43"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se15_spi_pins: qupv3_se15_spi_pins { + qupv3_se15_spi_active: qupv3_se15_spi_active { + mux { + pins = "gpio44", "gpio45", "gpio46", + "gpio47"; + function = "qup15"; + }; + + config { + pins = "gpio44", "gpio45", "gpio46", + "gpio47"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se15_spi_sleep: qupv3_se15_spi_sleep { + mux { + pins = "gpio44", "gpio45", "gpio46", + "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio44", "gpio45", "gpio46", + "gpio47"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se16_spi_pins: qupv3_se16_spi_pins { + qupv3_se16_spi_active: qupv3_se16_spi_active { + mux { + pins = "gpio48", "gpio49", "gpio50", + "gpio51"; + function = "qup16"; + }; + + config { + pins = "gpio48", "gpio49", "gpio50", + "gpio51"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se16_spi_sleep: qupv3_se16_spi_sleep { + mux { + pins = "gpio48", "gpio49", "gpio50", + "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio48", "gpio49", "gpio50", + "gpio51"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se17_spi_pins: qupv3_se17_spi_pins { + qupv3_se17_spi_active: qupv3_se17_spi_active { + mux { + pins = "gpio52", "gpio53", "gpio54", + "gpio55"; + function = "qup17"; + }; + + config { + pins = "gpio52", "gpio53", "gpio54", + "gpio55"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se17_spi_sleep: qupv3_se17_spi_sleep { + mux { + pins = "gpio52", "gpio53", "gpio54", + "gpio55"; + function = "gpio"; + }; + + config { + pins = "gpio52", "gpio53", "gpio54", + "gpio55"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se18_spi_pins: qupv3_se18_spi_pins { + qupv3_se18_spi_active: qupv3_se18_spi_active { + mux { + pins = "gpio56", "gpio57", "gpio58", + "gpio59"; + function = "qup18"; + }; + + config { + pins = "gpio56", "gpio57", "gpio58", + "gpio59"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se18_spi_sleep: qupv3_se18_spi_sleep { + mux { + pins = "gpio56", "gpio57", "gpio58", + "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio56", "gpio57", "gpio58", + "gpio59"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se19_spi_pins: qupv3_se19_spi_pins { + qupv3_se19_spi_active: qupv3_se19_spi_active { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "qup19"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se19_spi_sleep: qupv3_se19_spi_sleep { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + usb2_id_det_default: usb2_id_det_default { + config { + pins = "gpio91"; + function = "gpio"; + input-enable; + bias-pull-up; + }; + }; + + wil6210_refclk_en_pin: wil6210_refclk_en_pin { + mux { + pins = "gpio14"; + function = "gpio"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-pm.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a5eba34468ee25209d8f07baf5efe9c53462ec2a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-pm.dtsi @@ -0,0 +1,118 @@ +&soc { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "L3"; + qcom,clstr-tmr-add = <1000>; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xfff>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "l3-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <48>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <99>; + }; + + qcom,pm-cluster-level@1 { /* LLCC off, AOSS sleep */ + reg = <1>; + label = "llcc-off"; + qcom,psci-mode = <0xC24>; + qcom,entry-latency-us = <3263>; + qcom,exit-latency-us = <6562>; + qcom,min-residency-us = <9987>; + qcom,min-child-idx = <1>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,ref-stddev = <500>; + qcom,tmr-add = <1000>; + qcom,ref-premature-cnt = <1>; + qcom,disable-ipi-prediction; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <57>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <100>; + }; + + qcom,pm-cpu-level@1 { /* C4 */ + reg = <1>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <360>; + qcom,exit-latency-us = <531>; + qcom,min-residency-us = <3934>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + + qcom,pm-cpu@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,disable-ipi-prediction; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@2 { /* C1 */ + reg = <2>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <57>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <83>; + }; + + qcom,pm-cpu-level@3 { /* C4 */ + reg = <3>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <702>; + qcom,exit-latency-us = <1061>; + qcom,min-residency-us = <4488>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + + qcom,rpm-stats@c3f0004 { + compatible = "qcom,rpm-stats"; + reg = <0xc300000 0x1000>, <0xc3f0004 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + qcom,num-records = <3>; + }; + + qcom,ddr-stats@c3f0000 { + compatible = "qcom,ddr-stats"; + reg = <0xc300000 0x1000>, <0xc3f001c 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; + + qcom,rpmh-master-stats@b221200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb221200 0x60>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-pmic-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-pmic-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..37658de92d4524ce9d3873225c1b70a259996ccf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-pmic-overlay.dtsi @@ -0,0 +1,217 @@ +#include +#include + +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" +#include "pm8009.dtsi" + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pmxprairie@8 { + compatible = "qcom,spmi-pmic"; + reg = <0x8 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,modem-reset; + }; + }; + + qcom,pmxprairie@9 { + compatible ="qcom,spmi-pmic"; + reg = <0x9 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + }; +}; + +&pm8150_gpios { + key_home { + key_home_default: key_home_default { + pins = "gpio1"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + imu_clkin { + imu_clkin_default: imu_clkin_default { + pins = "gpio3"; + function = "func1"; + output-low; + power-source = <0>; + bias-disable; + qcom,dtest-buffer = <1>; + qcom,drive-strength = <1>; + }; + + imu_clkin_sleep: imu_clkin_sleep { + pins = "gpio3"; + function = "func1"; + input-enable; + bias-pull-down; + power-source = <0>; + qcom,dtest-buffer = <1>; + qcom,drive-strength = <1>; + }; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <1>; + }; + }; + + key_confirm { + key_confirm_default: key_confirm_default { + pins = "gpio7"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + usb2_vbus_boost { + usb2_vbus_boost_default: usb2_vbus_boost_default { + pins = "gpio9"; + function = "normal"; + output-low; + power-source = <1>; /* 1.8V input supply */ + }; + }; + + usb2_vbus_det { + usb2_vbus_det_default: usb2_vbus_det_default { + pins = "gpio10"; + function = "normal"; + input-enable; + bias-pull-down; + power-source = <1>; /* 1.8V input supply */ + }; + }; +}; + +&pm8150b_gpios { + qnovo_fet_ctrl { + qnovo_fet_ctrl_state1: qnovo_fet_ctrl_state1 { + pins = "gpio8"; + function = "normal"; + input-enable; + output-disable; + bias-disable; + power-source = <0>; + }; + + qnovo_fet_ctrl_state2: qnovo_fet_ctrl_state2 { + pins = "gpio8"; + function = "normal"; + input-enable; + output-disable; + bias-pull-down; + power-source = <0>; + }; + }; + + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&pm8150b_qnovo { + pinctrl-names = "q_state1", "q_state2"; + pinctrl-0 = <&qnovo_fet_ctrl_state1>; + pinctrl-1 = <&qnovo_fet_ctrl_state2>; +}; + +&pm8150b_fg { + nvmem-names = "fg_sdam"; + nvmem = <&pm8150_sdam_2>; +}; + +&pm8150b_charger { + dpdm-supply = <&usb2_phy0>; + smb5_vconn: qcom,smb5-vconn { + regulator-name = "smb5-vconn"; + }; + + smb5_vbus: qcom,smb5-vbus { + regulator-name = "smb5-vbus"; + }; +}; + +&pm8150b_pdphy { + vdd-pdphy-supply = <&pm8150_l2>; + vbus-supply = <&smb5_vbus>; + vconn-supply = <&smb5_vconn>; +}; + +&pm8150b_gpios { + haptics_boost { + haptics_boost_default: haptics_boost_default { + pins = "gpio5"; + function = "normal"; + output-enable; + input-disable; + bias-disable; + qcom,drive-strength = <3>; /* high */ + power-source = <1>; /* 1.8 V */ + }; + }; +}; + +&soc { + vreg_tof: regulator-dbb1 { + compatible = "regulator-fixed"; + regulator-name = "vdd_tof"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + gpio = <&pm8009_gpios 1 GPIO_ACTIVE_HIGH>; + startup-delay-us = <1000>; + enable-active-high; + }; + + vreg_hap_boost: regulator-haptics-boost { + compatible = "regulator-fixed"; + regulator-name = "vdd_hap_boost"; + gpio = <&pm8150b_gpios 5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&haptics_boost_default>; + startup-delay-us = <1000>; + enable-active-high; + status = "disabled"; + }; +}; + +&usb0 { + extcon = <&pm8150b_pdphy>, <&eud>; +}; + +&usb_qmp_dp_phy { + extcon = <&pm8150b_pdphy>; +}; + +&sde_dp { + extcon = <&pm8150b_pdphy>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-qrd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..68b9dca92256997e79a0ec4c48a5a6828d89ebc3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-qrd-overlay.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona QRD"; + compatible = "qcom,kona-qrd", "qcom,kona", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/kona-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..cc9a4a61ee36f4b1e38429b0974c2c1c7a33ea74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-qrd.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona QRD"; + compatible = "qcom,kona-qrd", "qcom,kona", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4e663f5f1e68694dd57c4a2ce8edab76a65eb0fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-qrd.dtsi @@ -0,0 +1,1010 @@ +#include +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "camera/kona-camera-sensor-qrd.dtsi" +#include "kona-audio-overlay.dtsi" +#include "kona-thermal-overlay.dtsi" + +&vendor { + kona_qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen4-batterydata-mlp466274-3650mah.dtsi" + #include "fg-gen4-batterydata-atl466274-3650mah.dtsi" + }; +}; + +&qupv3_se12_2uart { + status = "okay"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&dai_mi2s2 { + qcom,msm-mi2s-tx-lines = <1>; +}; + +&q6core { + cdc_tert_mi2s_gpios: msm_cdc_pinctrl_tert { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep>; + }; +}; + +&kona_snd { + qcom,model = "kona-qrd-snd-card"; + qcom,audio-routing = + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0212>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; + + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + + qcom,tert-mi2s-gpios = <&cdc_tert_mi2s_gpios>; +}; + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 111 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 110 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <111 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&qupv3_se13_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + vdd-supply = <&pm8150a_l1>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 39 0x2008>; + st,reset-gpio = <&tlmm 38 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + panel = <&dsi_sw43404_amoled_cmd &dsi_sw43404_amoled_video + &dsi_sw43404_amoled_fhd_plus_cmd>; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18800>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vcc-voltage-level = <2504000 2950000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8150_l6>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vccq-parent-supply = <&pm8150a_s8>; + qcom,vccq-parent-max-microamp = <210000>; + + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qcom,qbt_handler { + compatible = "qcom,qbt-handler"; + qcom,ipc-gpio = <&tlmm 23 0>; + pinctrl-names = "default"; + pinctrl-0 = <&key_home_default>; + qcom,finger-detect-gpio = <&pm8150_gpios 1 0>; + }; +}; + +&vreg_hap_boost { + status = "ok"; +}; + +&pm8150b_haptics { + qcom,vmax-mv = <1697>; + qcom,play-rate-us = <5882>; + vdd-supply = <&vreg_hap_boost>; + + wf_0 { + /* CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_1 { + /* DOUBLE CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_2 { + /* TICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_3 { + /* THUD */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_4 { + /* POP */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_5 { + /* HEAVY CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; +}; + +&pm8150b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; + redriver: redriver@1c { + compatible = "onnn,redriver"; + reg = <0x1c>; + extcon = <&pm8150b_pdphy>, <&pm8150b_pdphy>; + eq = /bits/ 8 < + /* Parameters for USB */ + 0x4 0x4 0x4 0x4 + /* Parameters for DP */ + 0x6 0x4 0x4 0x6>; + flat-gain = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x1 0x1 0x3 + /* Parameters for DP */ + 0x2 0x1 0x1 0x2>; + output-comp = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x3 0x3 0x3 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + loss-match = /bits/ 8 < + /* Parameters for USB */ + 0x1 0x3 0x3 0x1 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + }; + + + #include "smb1390.dtsi" +}; + +&smb1390 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + qcom,parallel-output-mode = <2>; + qcom,min-ilim-ua = <750000>; + qcom,parallel-input-mode = <1>; + status = "ok"; +}; + +&smb1390_slave { + status = "ok"; +}; + +&smb1390_slave_charger { + status = "ok"; +}; + +&pm8150b_charger { + status = "ok"; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "mid_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp"; + qcom,battery-data = <&kona_qrd_batterydata>; + qcom,sw-jeita-enable; + qcom,wd-bark-time-secs = <16>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; + qcom,smb-internal-pull-kohm = <0>; + qcom,thermal-mitigation = <5325000 4500000 4000000 3500000 3000000 + 2500000 2000000 1500000 1000000 500000>; +}; + +&pm8150b_fg { + status = "ok"; + qcom,battery-data = <&kona_qrd_batterydata>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,five-pin-battery; + qcom,cl-wt-enable; + qcom,soc-scale-mode-en; + /* ESR fast calibration */ + qcom,fg-esr-timer-chg-fast = <0 7>; + qcom,fg-esr-timer-dischg-fast = <0 7>; + qcom,fg-esr-timer-chg-slow = <0 96>; + qcom,fg-esr-timer-dischg-slow = <0 96>; + qcom,fg-esr-cal-soc-thresh = <26 230>; + qcom,fg-esr-cal-temp-thresh = <10 40>; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@4d { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4e { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + camera_flash_therm@4d { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_msm_therm@4e { + reg = ; + label = "skin_msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm2@4f { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM3_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + camera_flash_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_debug_bus { + status = "ok"; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-skin-avg-step { + polling-delay-passive = <1000>; + polling-delay = <5000>; + thermal-governor = "step_wise"; + trips { + virt_trip: virt-trip { + temperature = <64600>; + hysteresis = <2000>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev { + trip = <&virt_trip>; + cooling-device = <&msm_gpu 0 1>; + }; + }; + }; + + skin-msm-therm-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + skin_trip: skin-config0 { + temperature = <46000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + lcd_cdev { + trip = <&skin_trip>; + cooling-device = <&mdss_mdp 153 153>; + }; + }; + }; + + xo-therm-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + + trips { + xo_lvl0: active-config0 { + temperature = <42000>; + hysteresis = <2000>; + type = "passive"; + }; + + xo_lvl1: active-config1 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + + xo_lvl2: active-config2 { + temperature = <56000>; + hysteresis = <6000>; + type = "passive"; + }; + }; + + cooling-maps { + xo_skin_lvl0 { + trip = <&xo_lvl0>; + cooling-device = <&modem_mmw_skin2 1 1>; + }; + + xo_skin_lvl1 { + trip = <&xo_lvl1>; + cooling-device = <&modem_mmw_skin2 2 2>; + }; + + xo_skin_lvl2 { + trip = <&xo_lvl2>; + cooling-device = <&modem_mmw_skin2 3 3>; + }; + }; + }; + + mmw-pa1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + + trips { + pa1_lvl0: active-config0 { + temperature = <44000>; + hysteresis = <5000>; + type = "passive"; + }; + + pa1_lvl1: active-config1 { + temperature = <48000>; + hysteresis = <2000>; + type = "passive"; + }; + + pa1_lvl2: active-config2 { + temperature = <56000>; + hysteresis = <6000>; + type = "passive"; + }; + }; + + cooling-maps { + pa1_skin_lvl0 { + trip = <&pa1_lvl0>; + cooling-device = <&modem_mmw_skin0 1 1>; + }; + + pa1_skin_lvl1 { + trip = <&pa1_lvl1>; + cooling-device = <&modem_mmw_skin0 2 2>; + }; + + pa1_skin_lvl2 { + trip = <&pa1_lvl2>; + cooling-device = <&modem_mmw_skin0 3 3>; + }; + }; + }; + + mmw-pa2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + + trips { + pa2_lvl0: active-config0 { + temperature = <42000>; + hysteresis = <4000>; + type = "passive"; + }; + + pa2_lvl1: active-config1 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + + pa2_lvl2: active-config2 { + temperature = <56000>; + hysteresis = <6000>; + type = "passive"; + }; + }; + + cooling-maps { + pa2_skin_lvl0 { + trip = <&pa2_lvl0>; + cooling-device = <&modem_mmw_skin1 1 1>; + }; + + pa2_skin_lvl1 { + trip = <&pa2_lvl1>; + cooling-device = <&modem_mmw_skin1 2 2>; + }; + + pa2_skin_lvl2 { + trip = <&pa2_lvl2>; + cooling-device = <&modem_mmw_skin1 3 3>; + }; + }; + }; + + skin-therm-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + disable-thermal-zone; + + trips { + skin_therm0: active-config0 { + temperature = <62000>; + hysteresis = <5000>; + type = "passive"; + }; + + skin_therm1: active-config1 { + temperature = <65000>; + hysteresis = <5000>; + type = "passive"; + }; + + skin_therm2: active-config2 { + temperature = <72000>; + hysteresis = <2000>; + type = "passive"; + }; + }; + + cooling-maps { + skin_lvl0 { + trip = <&skin_therm0>; + cooling-device = <&modem_skin 1 1>; + }; + + skin_lvl1 { + trip = <&skin_therm1>; + cooling-device = <&modem_skin 2 2>; + }; + + skin_lvl2 { + trip = <&skin_therm2>; + cooling-device = <&modem_skin 3 3>; + }; + }; + + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&vendor { + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-sw-ctrl-gpio = <&tlmm 124 0>; /* SW_CTRL */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + }; +}; + +&usb0 { + dwc3@a600000 { + maximum-speed = "super-speed-plus"; + }; +}; + +&usb1 { + qcom,default-mode-none; +}; + +&wil6210 { + status = "ok"; +}; + +&usb2_phy0 { + qcom,param-override-seq = + <0xc7 0x6c + 0x0f 0x70 + 0x03 0x74>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-qupv3.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-qupv3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8c1f34eba8be07c949b90e46ae31156555236f0c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-qupv3.dtsi @@ -0,0 +1,1052 @@ +#include + +&soc { + /* QUPv3_0 wrapper instance : North QUP*/ + qupv3_0: qcom,qupv3_0_geni_se@9c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x9c0000 0x2000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + iommus = <&apps_smmu 0x5a3 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + /* QUPV3_0_SE0 */ + i3c0: i3c-master@980000 { + compatible = "qcom,geni-i3c"; + reg = <0x980000 0x4000>, + <0x0EC30000 0x10000>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep", "disable"; + pinctrl-0 = <&qupv3_se0_i3c_active>; + pinctrl-1 = <&qupv3_se0_i3c_sleep>; + pinctrl-2 = <&qupv3_se0_i3c_disable>; + interrupts-extended = <&intc GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 31 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 30 IRQ_TYPE_LEVEL_HIGH>; + + #address-cells = <3>; + #size-cells = <0>; + qcom,wrapper-core = <&qupv3_0>; + qcom,ibi-ctrl-id = <0>; + status = "disabled"; + }; + + /* QUPV3_0_SE1 */ + i3c1: i3c-master@984000 { + compatible = "qcom,geni-i3c"; + reg = <0x984000 0x4000>, + <0xEC40000 0x10000>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep", "disable"; + pinctrl-0 = <&qupv3_se1_i3c_active>; + pinctrl-1 = <&qupv3_se1_i3c_sleep>; + pinctrl-2 = <&qupv3_se1_i3c_disable>; + interrupts-extended = <&intc GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 33 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 32 IRQ_TYPE_LEVEL_HIGH>; + + #address-cells = <3>; + #size-cells = <0>; + qcom,wrapper-core = <&qupv3_0>; + qcom,ibi-ctrl-id = <1>; + status = "disabled"; + }; + + /* Debug UART Instance for RUMI platform */ + qupv3_se2_2uart: qcom,qup_uart@988000 { + compatible = "qcom,msm-geni-console"; + reg = <0x988000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_2uart_active>; + pinctrl-1 = <&qupv3_se2_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_0>; + qcom,change-sampling-rate; + status = "disabled"; + }; + + /* + * HS UART instances. HS UART usecases can be supported on these + * instances only. + */ + qupv3_se6_4uart: qcom,qup_uart@998000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x998000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "active", "sleep"; + pinctrl-0 = <&qupv3_se6_default_cts>, + <&qupv3_se6_default_rtsrx>, <&qupv3_se6_default_tx>; + pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, + <&qupv3_se6_tx>; + pinctrl-2 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, + <&qupv3_se6_tx>; + interrupts-extended = <&intc GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 19 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; + }; + + /* I2C */ + qupv3_se0_i2c: i2c@980000 { + compatible = "qcom,i2c-geni"; + reg = <0x980000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se1_i2c: i2c@984000 { + compatible = "qcom,i2c-geni"; + reg = <0x984000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@988000 { + compatible = "qcom,i2c-geni"; + reg = <0x988000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se3_i2c: i2c@98c000 { + compatible = "qcom,i2c-geni"; + reg = <0x98c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 3 3 64 0>, + <&gpi_dma0 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_i2c_active>; + pinctrl-1 = <&qupv3_se3_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se4_i2c: i2c@990000 { + compatible = "qcom,i2c-geni"; + reg = <0x990000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 4 3 64 0>, + <&gpi_dma0 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_i2c_active>; + pinctrl-1 = <&qupv3_se4_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se5_i2c: i2c@994000 { + compatible = "qcom,i2c-geni"; + reg = <0x994000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 5 3 64 0>, + <&gpi_dma0 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_i2c_active>; + pinctrl-1 = <&qupv3_se5_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se6_i2c: i2c@998000 { + compatible = "qcom,i2c-geni"; + reg = <0x998000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 6 3 64 0>, + <&gpi_dma0 1 6 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i2c_active>; + pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se7_i2c: i2c@99c000 { + compatible = "qcom,i2c-geni"; + reg = <0x99c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 7 3 64 0>, + <&gpi_dma0 1 7 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_i2c_active>; + pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se0_spi: spi@980000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x980000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se1_spi: spi@984000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x984000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_spi_active>; + pinctrl-1 = <&qupv3_se1_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se2_spi: spi@988000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x988000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_spi_active>; + pinctrl-1 = <&qupv3_se2_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se3_spi: spi@98c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x98c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se3_spi_active>; + pinctrl-1 = <&qupv3_se3_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 3 1 64 0>, + <&gpi_dma0 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se4_spi: spi@990000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x990000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_spi_active>; + pinctrl-1 = <&qupv3_se4_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 4 1 64 0>, + <&gpi_dma0 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se5_spi: spi@994000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x994000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_spi_active>; + pinctrl-1 = <&qupv3_se5_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se6_spi: spi@998000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x998000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_spi_active>; + pinctrl-1 = <&qupv3_se6_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 6 1 64 0>, + <&gpi_dma0 1 6 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se7_spi: spi@99c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x99c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_spi_active>; + pinctrl-1 = <&qupv3_se7_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 7 1 64 0>, + <&gpi_dma0 1 7 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* QUPv3 South_1 & South_2 Instances + * South_1 0 : SE 8 + * South_1 1 : SE 9 + * South_1 2 : SE 10 + * South_1 3 : SE 11 + * South_1 4 : SE 12 + * South_1 5 : SE 13 + * South_2 0 : SE 14 + * South_2 1 : SE 15 + * South_2 2 : SE 16 + * South_2 3 : SE 17 + * South_2 4 : SE 18 + * South_2 5 : SE 19 + */ + + /* QUPv3_1 wrapper instance : South_1 QUP */ + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x2000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + iommus = <&apps_smmu 0x43 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + /* Debug UART Instance for CDP/MTP platform */ + qupv3_se12_2uart: qcom,qup_uart@a90000 { + compatible = "qcom,msm-geni-console"; + reg = <0xa90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_2uart_active>; + pinctrl-1 = <&qupv3_se12_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + qcom,change-sampling-rate; + status = "disabled"; + }; + + /* I2C */ + qupv3_se8_i2c: i2c@a80000 { + compatible = "qcom,i2c-geni"; + reg = <0xa80000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_i2c_active>; + pinctrl-1 = <&qupv3_se8_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se9_i2c: i2c@a84000 { + compatible = "qcom,i2c-geni"; + reg = <0xa84000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_i2c_active>; + pinctrl-1 = <&qupv3_se9_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se10_i2c: i2c@a88000 { + compatible = "qcom,i2c-geni"; + reg = <0xa88000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_i2c_active>; + pinctrl-1 = <&qupv3_se10_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se11_i2c: i2c@a8c000 { + compatible = "qcom,i2c-geni"; + reg = <0xa8c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 3 3 64 0>, + <&gpi_dma1 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_i2c_active>; + pinctrl-1 = <&qupv3_se11_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se12_i2c: i2c@a90000 { + compatible = "qcom,i2c-geni"; + reg = <0xa90000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 4 3 64 0>, + <&gpi_dma1 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_i2c_active>; + pinctrl-1 = <&qupv3_se12_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se13_i2c: i2c@a94000 { + compatible = "qcom,i2c-geni"; + reg = <0xa94000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 5 3 64 0>, + <&gpi_dma1 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se13_i2c_active>; + pinctrl-1 = <&qupv3_se13_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se8_spi: spi@a80000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa80000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_spi_active>; + pinctrl-1 = <&qupv3_se8_spi_active>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se9_spi: spi@a84000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa84000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_spi_active>; + pinctrl-1 = <&qupv3_se9_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 1 1 64 0>, + <&gpi_dma1 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se10_spi: spi@a88000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa88000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_spi_active>; + pinctrl-1 = <&qupv3_se10_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 2 1 64 0>, + <&gpi_dma1 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se11_spi: spi@a8c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa8c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_spi_active>; + pinctrl-1 = <&qupv3_se11_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 3 1 64 0>, + <&gpi_dma1 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se12_spi: spi@a90000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa90000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se12_spi_active>; + pinctrl-1 = <&qupv3_se12_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 4 1 64 0>, + <&gpi_dma1 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se13_spi: spi@a94000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa94000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se13_spi_active>; + pinctrl-1 = <&qupv3_se13_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 5 1 64 0>, + <&gpi_dma1 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* QUPv3_2 wrapper instance : South_2 QUP */ + qupv3_2: qcom,qupv3_2_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x2000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + iommus = <&apps_smmu 0x63 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + /* + * HS UART : Modem/Audio backup + */ + qupv3_se17_4uart: qcom,qup_uart@88c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x88c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se17_ctsrx>, <&qupv3_se17_rts>, + <&qupv3_se17_tx>; + pinctrl-1 = <&qupv3_se17_ctsrx>, <&qupv3_se17_rts>, + <&qupv3_se17_tx>; + interrupts-extended = <&intc GIC_SPI 585 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 55 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_2>; + }; + + /* + * HS UART : 2-wire Modem + */ + qupv3_se18_2uart: qcom,qup_uart@890000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x890000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se18_rx>, <&qupv3_se18_tx>; + pinctrl-1 = <&qupv3_se18_rx>, <&qupv3_se18_tx>; + interrupts-extended = <&intc GIC_SPI 586 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 59 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_2>; + }; + + /* I2C */ + qupv3_se14_i2c: i2c@880000 { + compatible = "qcom,i2c-geni"; + reg = <0x880000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + dmas = <&gpi_dma2 0 0 3 64 0>, + <&gpi_dma2 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se14_i2c_active>; + pinctrl-1 = <&qupv3_se14_i2c_sleep>; + qcom,wrapper-core = <&qupv3_2>; + status = "disabled"; + }; + + qupv3_se15_i2c: i2c@884000 { + compatible = "qcom,i2c-geni"; + reg = <0x884000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + dmas = <&gpi_dma2 0 1 3 64 0>, + <&gpi_dma2 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se15_i2c_active>; + pinctrl-1 = <&qupv3_se15_i2c_sleep>; + qcom,wrapper-core = <&qupv3_2>; + status = "ok"; + }; + + qupv3_se16_i2c: i2c@888000 { + compatible = "qcom,i2c-geni"; + reg = <0x888000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + dmas = <&gpi_dma2 0 2 3 64 0>, + <&gpi_dma2 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se16_i2c_active>; + pinctrl-1 = <&qupv3_se16_i2c_sleep>; + qcom,wrapper-core = <&qupv3_2>; + status = "disabled"; + }; + + qupv3_se17_i2c: i2c@88c000 { + compatible = "qcom,i2c-geni"; + reg = <0x88c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + dmas = <&gpi_dma2 0 3 3 64 0>, + <&gpi_dma2 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se17_i2c_active>; + pinctrl-1 = <&qupv3_se17_i2c_sleep>; + qcom,wrapper-core = <&qupv3_2>; + status = "disabled"; + }; + + qupv3_se18_i2c: i2c@890000 { + compatible = "qcom,i2c-geni"; + reg = <0x890000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + dmas = <&gpi_dma2 0 4 3 64 0>, + <&gpi_dma2 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se18_i2c_active>; + pinctrl-1 = <&qupv3_se18_i2c_sleep>; + qcom,wrapper-core = <&qupv3_2>; + status = "disabled"; + }; + + qupv3_se19_i2c: i2c@894000 { + compatible = "qcom,i2c-geni"; + reg = <0x894000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + dmas = <&gpi_dma2 0 5 3 64 0>, + <&gpi_dma2 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se19_i2c_active>; + pinctrl-1 = <&qupv3_se19_i2c_sleep>; + qcom,wrapper-core = <&qupv3_2>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se14_spi: spi@880000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x880000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S0_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se14_spi_active>; + pinctrl-1 = <&qupv3_se14_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_2>; + dmas = <&gpi_dma2 0 0 1 64 0>, + <&gpi_dma2 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se15_spi: spi@884000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x884000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S1_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se15_spi_active>; + pinctrl-1 = <&qupv3_se15_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_2>; + dmas = <&gpi_dma2 0 1 1 64 0>, + <&gpi_dma2 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se16_spi: spi@888000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x888000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S2_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se16_spi_active>; + pinctrl-1 = <&qupv3_se16_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_2>; + dmas = <&gpi_dma2 0 2 1 64 0>, + <&gpi_dma2 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se17_spi: spi@88c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x88c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S3_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se17_spi_active>; + pinctrl-1 = <&qupv3_se17_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_2>; + dmas = <&gpi_dma2 0 3 1 64 0>, + <&gpi_dma2 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se18_spi: spi@890000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x890000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S4_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se18_spi_active>; + pinctrl-1 = <&qupv3_se18_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_2>; + dmas = <&gpi_dma2 0 4 1 64 0>, + <&gpi_dma2 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se19_spi: spi@894000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x894000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP2_S5_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se19_spi_active>; + pinctrl-1 = <&qupv3_se19_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_2>; + dmas = <&gpi_dma2 0 5 1 64 0>, + <&gpi_dma2 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-regulators.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-regulators.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..528403c6c5dadc6a7da2a60664f411462ab36d26 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-regulators.dtsi @@ -0,0 +1,936 @@ +#include + +/* RPMh regulators */ +&apps_rsc { + /* PM8150A S3 = VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "mx.lvl"; + pm8150a_s3_mmcx_sup_level-parent-supply = + <&VDD_CX_MMCX_SUPPLY_LEVEL>; + + VDD_MX_LEVEL: S3C_LEVEL: + pm8150a_s3_level: regulator-pm8150a-s3-level { + regulator-name = "pm8150a_s3_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + + VDD_MX_LEVEL_AO: S3C_LEVEL_AO: + pm8150a_s3_level_ao: regulator-pm8150a-s3-level-ao { + regulator-name = "pm8150a_s3_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + + VDD_MX_MMCX_SUPPLY_LEVEL: regulator-pm8150a-s3-mmcx-sup-level { + regulator-name = "pm8150a_s3_mmcx_sup_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + }; + }; + + /* PM8150 S3 + S2 + S1 = VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "cx.lvl"; + pm8150_s3_level-parent-supply = <&VDD_MX_LEVEL>; + pm8150_s3_level_ao-parent-supply = <&VDD_MX_LEVEL_AO>; + proxy-supply = <&VDD_CX_MMCX_SUPPLY_LEVEL>; + + VDD_CX_LEVEL: S3A_LEVEL: + pm8150_s3_level: regulator-pm8150-s3-level { + regulator-name = "pm8150_s3_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_LEVEL_AO: S3A_LEVEL_AO: + pm8150_s3_level_ao: regulator-pm8150-s3-level-ao { + regulator-name = "pm8150_s3_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_MMCX_SUPPLY_LEVEL: regulator-pm8150-s3-mmcx-sup-level { + regulator-name = "pm8150_s3_mmcx_sup_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level = + ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-voltage + = ; + }; + }; + + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa4"; + S4A: pm8150_s4: regulator-pm8150-s4 { + regulator-name = "pm8150_s4"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1920000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpmh-regulator-smpa5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa5"; + S5A: pm8150_s5: regulator-pm8150-s5 { + regulator-name = "pm8150_s5"; + qcom,set = ; + regulator-min-microvolt = <1824000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1824000>; + }; + }; + + rpmh-regulator-smpa6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa6"; + S6A: pm8150_s6: regulator-pm8150-s6 { + regulator-name = "pm8150_s6"; + qcom,set = ; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <600000>; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L2A: pm8150_l2: regulator-pm8150-l2 { + regulator-name = "pm8150_l2"; + qcom,set = ; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + qcom,init-voltage = <3072000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L3A: pm8150_l3: regulator-pm8150-l3 { + regulator-name = "pm8150_l3"; + qcom,set = ; + regulator-min-microvolt = <928000>; + regulator-max-microvolt = <932000>; + qcom,init-voltage = <928000>; + qcom,init-mode = ; + }; + }; + + /* PM8150 L4 = VDD_SSC_MX supply */ + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "lmx.lvl"; + L4A_LEVEL: pm8150_l4_level: regulator-pm8150-l4-level { + regulator-name = "pm8150_l4_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + proxy-supply = <&pm8150_l5>; + L5A: pm8150_l5: regulator-pm8150-l5 { + regulator-name = "pm8150_l5"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <100000>; + }; + + L5A_AO: pm8150_l5_ao: regulator-pm8150-l5-ao { + regulator-name = "pm8150_l5_ao"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + + regulator-pm8150-l5-so { + regulator-name = "pm8150_l5_so"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L6A: pm8150_l6: regulator-pm8150-l6 { + regulator-name = "pm8150_l6"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L7A: pm8150_l7: regulator-pm8150-l7 { + regulator-name = "pm8150_l7"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + proxy-supply = <&pm8150_l9>; + L9A: pm8150_l9: regulator-pm8150-l9 { + regulator-name = "pm8150_l9"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <100000>; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L10A: pm8150_l10: regulator-pm8150-l10 { + regulator-name = "pm8150_l10"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + /* PM8150 L11 = VDD_SSC_CX supply */ + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "lcx.lvl"; + L11A_LEVEL: pm8150_l11_level: regulator-pm8150-l11-level { + regulator-name = "pm8150_l11_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L12A: pm8150_l12: regulator-pm8150-l12 { + regulator-name = "pm8150_l12"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + + L12A_AO: pm8150_l12_ao: regulator-pm8150-l12-ao { + regulator-name = "pm8150_l12_ao"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + + regulator-pm8150-l12-so { + regulator-name = "pm8150_l12_so"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L13A: pm8150_l13: regulator-pm8150-l13 { + regulator-name = "pm8150_l13"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + proxy-supply = <&pm8150_l14>; + L14A: pm8150_l14: regulator-pm8150-l14 { + regulator-name = "pm8150_l14"; + qcom,set = ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <62000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1880000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L15A: pm8150_l15: regulator-pm8150-l15 { + regulator-name = "pm8150_l15"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L16A: pm8150_l16: regulator-pm8150-l16 { + regulator-name = "pm8150_l16"; + qcom,set = ; + regulator-min-microvolt = <3024000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <3024000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L17A: pm8150_l17: regulator-pm8150-l17 { + regulator-name = "pm8150_l17"; + qcom,set = ; + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3008000>; + qcom,init-voltage = <2496000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa18 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L18A: pm8150_l18: regulator-pm8150-l18 { + regulator-name = "pm8150_l18"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <920000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + /* PM8150A S1 + S2 = VDD_GFX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "gfx.lvl"; + VDD_GFX_LEVEL: S1C_LEVEL: + pm8150a_s1_level: regulator-pm8150a-s1-level { + regulator-name = "pm8150a_s1_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* PM8150A S4 + S5 = VDD_MMCX supply */ + rpmh-regulator-mmcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "mmcx.lvl"; + pm8150a_s4_level-parent-supply = <&VDD_MX_MMCX_SUPPLY_LEVEL>; + pm8150a_s4_level_ao-parent-supply = <&VDD_MX_LEVEL_AO>; + proxy-supply = <&VDD_MMCX_LEVEL>; + + VDD_MMCX_LEVEL: S4C_LEVEL: + pm8150a_s4_level: regulator-pm8150a-s4-level { + regulator-name = "pm8150a_s4_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-voltage + = ; + }; + + VDD_MMCX_LEVEL_AO: S4C_LEVEL_AO: + pm8150a_s4_level_ao: regulator-pm8150a-s4-level-ao { + regulator-name = "pm8150a_s4_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + regulator-pm8150a-s4-level-so { + regulator-name = "pm8150a_s4_level_so"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* PM8150A S6 = VDD_EBI supply */ + rpmh-regulator-ebilvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "ebi.lvl"; + S6C_LEVEL: pm8150a_s6_level: regulator-pm8150a-s6-level { + regulator-name = "pm8150a_s6_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-smpc7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpc7"; + S7C: pm8150a_s7: regulator-pm8150a-s7 { + regulator-name = "pm8150a_s7"; + qcom,set = ; + regulator-min-microvolt = <348000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <348000>; + }; + }; + + rpmh-regulator-smpc8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpc8"; + qcom,regulator-type = "pmic5-hfsmps"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 200000>; + S8C: pm8150a_s8: regulator-pm8150a-s8 { + regulator-name = "pm8150a_s8"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc1"; + qcom,regulator-type = "pmic5-ldo"; + L1C: pm8150a_l1: regulator-pm8150a-l1 { + regulator-name = "pm8150a_l1"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpmh-regulator-ldoc2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L2C: pm8150a_l2: regulator-pm8150a-l2 { + regulator-name = "pm8150a_l2"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L3C: pm8150a_l3: regulator-pm8150a-l3 { + regulator-name = "pm8150a_l3"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L4C: pm8150a_l4: regulator-pm8150a-l4 { + regulator-name = "pm8150a_l4"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L5C: pm8150a_l5: regulator-pm8150a-l5 { + regulator-name = "pm8150a_l5"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L6C: pm8150a_l6: regulator-pm8150a-l6 { + regulator-name = "pm8150a_l6"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L7C: pm8150a_l7: regulator-pm8150a-l7 { + regulator-name = "pm8150a_l7"; + qcom,set = ; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + qcom,init-voltage = <2856000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc8"; + qcom,regulator-type = "pmic5-ldo"; + L8C: pm8150a_l8: regulator-pm8150a-l8 { + regulator-name = "pm8150a_l8"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpmh-regulator-ldoc9 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L9C: pm8150a_l9: regulator-pm8150a-l9 { + regulator-name = "pm8150a_l9"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc10 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L10C: pm8150a_l10: regulator-pm8150a-l10 { + regulator-name = "pm8150a_l10"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc11 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + proxy-supply = <&pm8150a_l11>; + L11C: pm8150a_l11: regulator-pm8150a-l11 { + regulator-name = "pm8150a_l11"; + qcom,set = ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <857000>; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <3104000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-bobc1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "bobc1"; + qcom,regulator-type = "pmic5-bob"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1000000 2000000>; + qcom,send-defaults; + + BOB: pm8150a_bob: regulator-pm8150a-bob { + regulator-name = "pm8150a_bob"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + qcom,init-voltage = <3312000>; + qcom,init-mode = ; + }; + + BOB_AO: pm8150a_bob_ao: regulator-pm8150a-bob-ao { + regulator-name = "pm8150a_bob_ao"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-smpf1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpf1"; + S1F: pm8009_s1: regulator-pm8009-s1 { + regulator-name = "pm8009_s1"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + }; + }; + + rpmh-regulator-smpf2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpf2"; + S2F: pm8009_s2: regulator-pm8009-s2 { + regulator-name = "pm8009_s2"; + qcom,set = ; + regulator-min-microvolt = <512000>; + regulator-max-microvolt = <1100000>; + qcom,init-voltage = <512000>; + }; + }; + + rpmh-regulator-ldof1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L1F: pm8009_l1: regulator-pm8009-l1 { + regulator-name = "pm8009_l1"; + qcom,set = ; + regulator-min-microvolt = <1104000>; + regulator-max-microvolt = <1104000>; + qcom,init-voltage = <1104000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldof2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L2F: pm8009_l2: regulator-pm8009-l2 { + regulator-name = "pm8009_l2"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldof3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + L3F: pm8009_l3: regulator-pm8009-l3 { + regulator-name = "pm8009_l3"; + qcom,set = ; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1056000>; + qcom,init-voltage = <1056000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldof5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L5F: pm8009_l5: regulator-pm8009-l5 { + regulator-name = "pm8009_l5"; + qcom,set = ; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <2800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldof6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L6F: pm8009_l6: regulator-pm8009-l6 { + regulator-name = "pm8009_l6"; + qcom,set = ; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <2800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldof7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldof7"; + qcom,regulator-type = "pmic5-ldo"; + L7F: pm8009_l7: regulator-pm8009-l7 { + regulator-name = "pm8009_l7"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; +}; + +&soc { + refgen: refgen-regulator@88e7000 { + compatible = "qcom,refgen-kona-regulator"; + reg = <0x88e7000 0x84>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + proxy-supply = <&refgen>; + qcom,proxy-consumer-enable; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-rumi-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1c118048c6de241ea0c0013db7f9f2426f7a736c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-rumi-overlay.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona RUMI"; + compatible = "qcom,kona-rumi", "qcom,kona", "qcom,rumi"; + qcom,board-id = <0x1000F 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-rumi.dts b/arch/arm64/boot/dts/vendor/qcom/kona-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..8eb98745d6181fd37648f0801b9b472967e877e1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-rumi.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/memreserve/ 0x90000000 0x00000100; + +#include "kona.dtsi" +#include "kona-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona RUMI"; + compatible = "qcom,kona-rumi", "qcom,kona", "qcom,rumi"; + qcom,board-id = <0x1000F 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-rumi.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..87b03007174c1033d8f54d35ed86e5d530f7c531 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-rumi.dtsi @@ -0,0 +1,155 @@ +#include +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "msm-audio-lpass.dtsi" + +&arch_timer { + clock-frequency = <500000>; +}; + +&memtimer { + clock-frequency = <500000>; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qrbtc-sdm845"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + limit-tx-hs-gear = <1>; + limit-rx-hs-gear = <1>; + + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <750000>; + vccq2-max-microamp = <750000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + + qcom,disable-lpm; + rpm-level = <0>; + spm-level = <0>; + status = "ok"; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + + pcie2: qcom,pcie@1c10000 { + reg = <0x01c10000 0x4000>, + <0x01c16000 0x2000>, + <0x64000000 0xf1d>, + <0x64000f20 0xa8>, + <0x64001000 0x1000>, + <0x64100000 0x100000>, + <0x64200000 0x100000>, + <0x64300000 0x4000000>, + <0x01c15000 0x1000>; + reg-names = "parf", "phy", "dm_core", "elbi", "iatu", "conf", + "io", "bars", "rumi"; + + qcom,target-link-speed = <0x1>; + qcom,link-check-max-count = <200>; /* 1 sec */ + qcom,no-l1-supported; + qcom,no-l1ss-supported; + qcom,no-aux-clk-sync; + }; + + usb_emu_phy: usb_emu_phy@a720000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x0a720000 0x9500>, + <0x0a6f8800 0x100>; + reg-names = "base", "qscratch_base"; + + qcom,emu-init-seq = <0xffff 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x101f0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; +}; + +&usb0 { + /delete-property/ extcon; + dwc3@a600000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&qupv3_se12_2uart { + status = "disabled"; +}; + +/* RUMI UART console */ +&qupv3_se2_2uart { + status = "ok"; +}; + +&audio_apr { + sound-stub { + compatible = "qcom,kona-asoc-snd-stub"; + qcom,model = "kona-stub-snd-card"; + + qcom,audio-routing = + "AIF4 VI", "MCLK"; + + asoc-platform = <&pcm0>, <&routing>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-routing"; + asoc-cpu = <&dai_pri_auxpcm>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; +}; + +&ipa_hw { + qcom,ipa-hw-mode = <1>; /* IPA hw type = Virtual */ +}; + +&mhi_0 { + mhi,timeout = <10000>; + + mhi_channels { + mhi_chan@25 { + status = "disabled"; + }; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + + status = "disabled"; +}; + +&wdog { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-sa-mtp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-sa-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..8ef8c7881a1bcc7c5dd49174643cdfab4d47df6b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-sa-mtp-overlay.dts @@ -0,0 +1,20 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona standalone MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x02010008 0>; +}; + +&mdm0 { + status = "disabled"; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..89ce8c875cc4fdc62b7a1289de9ec7ced99b7ea0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-sde-display.dtsi @@ -0,0 +1,944 @@ +#include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-video.dtsi" +#include "dsi-panel-sharp-qsync-wqhd-cmd.dtsi" +#include "dsi-panel-sharp-qsync-wqhd-video.dtsi" +#include "dsi-panel-sharp-1080p-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-ext-bridge-1080p.dtsi" +#include "dsi-panel-ext-bridge-4k-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dsc-10bit-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-sim-sec-hd-cmd.dtsi" +#include "dsi-panel-xrsmrtvwr-jdi-dual-video.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-144hz-cmd.dtsi" +#include + +&tlmm { + display_panel_avdd_default: display_panel_avdd_default { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; +}; + +&soc { + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_lab_ibb: dsi_panel_pwr_supply_lab_ibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_avdd: dsi_panel_pwr_supply_avdd { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + + display_panel_avdd: display_gpio_regulator@1 { + compatible = "regulator-fixed"; + regulator-name = "display_panel_avdd"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 61 0>; + enable-active-high; + regulator-boot-on; + pinctrl-names = "default"; + pinctrl-0 = <&display_panel_avdd_default>; + }; + + sde_dsi: qcom,dsi-display-primary { + compatible = "qcom,dsi-display"; + label = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi0_pll BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll PCLK_SRC_0_CLK>, + <&mdss_dsi0_pll CPHY_BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll CPHY_PCLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_PCLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_CPHY_BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_CPHY_PCLK_SRC_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>, + <&mdss_dsi1_pll BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll PCLK_SRC_1_CLK>, + <&mdss_dsi1_pll CPHY_BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll CPHY_PCLK_SRC_1_CLK>, + <&mdss_dsi1_pll SHADOW_BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll SHADOW_PCLK_SRC_1_CLK>, + <&mdss_dsi1_pll SHADOW_CPHY_BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll SHADOW_CPHY_PCLK_SRC_1_CLK>; + + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "cphy_byte_clk0", "cphy_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0", + "shadow_cphybyte_clk0", "shadow_cphypixel_clk0", + "mux_byte_clk1", "mux_pixel_clk1", + "src_byte_clk1", "src_pixel_clk1", + "cphy_byte_clk1", "cphy_pixel_clk1", + "shadow_byte_clk1", "shadow_pixel_clk1", + "shadow_cphybyte_clk1", "shadow_cphypixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,panel-te-source = <0>; + + vddio-supply = <&pm8150_l14>; + vdd-supply = <&pm8150a_l11>; + avdd-supply = <&display_panel_avdd>; + lab-supply = <&ab_vreg>; + ibb-supply = <&ibb_vreg>; + + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_sw43404_amoled_cmd>; + }; + + sde_dsi1: qcom,dsi-display-secondary { + compatible = "qcom,dsi-display"; + label = "secondary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi0_pll CPHY_BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll CPHY_PCLK_SRC_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>, + <&mdss_dsi1_pll CPHY_BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll CPHY_PCLK_SRC_1_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "cphy_byte_clk0", "cphy_pixel_clk0", + "mux_byte_clk1", "mux_pixel_clk1", + "cphy_byte_clk1", "cphy_pixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi1_active &sde_te1_active>; + pinctrl-1 = <&sde_dsi1_suspend &sde_te1_suspend>; + + qcom,platform-te-gpio = <&tlmm 67 0>; + qcom,panel-te-source = <1>; + + vddio-supply = <&pm8150_l14>; + vdd-supply = <&pm8150a_l11>; + avdd-supply = <&display_panel_avdd>; + + qcom,mdp = <&mdss_mdp>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + msm_notifier: qcom,msm_notifier@0 { + compatible = "qcom,msm-notifier"; + panel = <&dsi_sw43404_amoled_cmd &dsi_sharp_qsync_wqhd_cmd + &dsi_dual_sim_dsc_375_cmd>; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pm8150b_pdphy>; + qcom,ext-disp = <&ext_disp>; + qcom,dp-aux-switch = <&fsa4480>; + + qcom,usbplug-cc-gpio = <&tlmm 65 0>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_usbplug_cc_suspend>; +}; + +&mdss_mdp { + connectors = <&sde_dp &sde_wb &sde_dsi &sde_dsi1 &sde_rscc>; +}; + +/* PHY TIMINGS REVISION W */ +&dsi_ext_bridge_1080p { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_ext_bridge_4k_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 3a 0f 0f 2e 2b 0f + 10 0b 02 04 00 2e 1e]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_xrsmrtvwr_jdi_video { + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <80>; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 17 05 05 20 1F + 06 06 03 02 04 00 13 15]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sw43404_amoled_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = <552424501 549895420 547366339>; + + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1e 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 13 04 04 1f 1e 05 + 05 03 02 04 00 12 14]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 11 03 04 1e 1e 04 + 04 02 02 04 00 10 14]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + }; +}; + +&dsi_sw43404_amoled_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-supported-dfps-list = <60 57 55>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_hfp"; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <534712320 532484352 530256384>; + + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1e 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 12 04 04 1e 1e 04 + 05 02 03 04 00 11 14]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 270 270 270 1080 270>; + qcom,mdss-dsi-panel-clockrate = <400000000>; + }; + }; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_4k_dsc_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_qsync_wqhd_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* WQHD 60FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0b 03 02 1d 1c 03 + 03 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 8 8 8 1440 8>; + }; + + timing@1 { /* WQHD 60FPS VID */ + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1f 06 + 06 03 02 04 00 13 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { /* FHD 60FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0a 01 02 1b 1c 02 + 02 00 02 04 00 0a 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + + timing@3 { /* WQHD 90FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 10 03 03 1e 1e 04 + 04 02 02 04 00 0f 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 8 8 8 1440 8>; + }; + + timing@4 { /* WQHD 120FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 13 05 04 1f 1e 05 + 05 03 02 04 00 12 14]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 8 8 8 1440 8>; + }; + + timing@5 { /* WQHD 120FPS VID */ + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1f 06 + 06 03 02 04 00 13 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@6 { /* FHD 120FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0e 03 03 1e 1d 04 + 04 02 02 04 00 0e 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + + timing@7 { /* FHD 90FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0b 02 02 1c 1c 03 + 02 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + }; +}; + +&dsi_sharp_qsync_wqhd_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1f 06 + 06 03 02 04 00 13 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_1080_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,mdss-dsi-panel-clockrate = <900000000>; + }; + }; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_truly_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@3 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@4 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 06 04 02 04 00 16 16]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* QHD 60fps */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* 1080 60fps */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + + timing@2 { /* QHD 90fps */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 02 04 00 18 17]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* 4k 30 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 0e 03 03 1e 1d 04 + 04 02 02 04 00 0e 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* 4k 60 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 02 04 00 15 16]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { /* 4k 90 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 22 09 09 25 23 09 + 09 06 02 04 00 1c 19]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@3 { /* 4k 120 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 2c 0c 0c 29 27 0c + 0c 08 02 04 00 24 1b]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@4 { /* 1080 30 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [01 09 01 01 1b 1b 01 + 01 01 02 04 00 0a 11]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@5 { /* 1080 60 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 0b 02 02 1c 1c 03 + 02 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@6 { /* 1080 90 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 0e 03 03 1e 1d 04 + 03 02 02 04 00 0e 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@7 { /* 1080 120 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 11 04 04 1e 1e 04 + 04 02 02 04 00 10 14]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@8 { /* qhd 30 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 0a 02 02 1c 1c 02 + 02 01 02 04 00 0b 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@9 { /* qhd 60 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 0f 03 03 1e 1d 04 + 04 02 02 04 00 0f 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@10 { /* qhd 90 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1f 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@11 { /* qhd 120 FPS*/ + qcom,mdss-dsi-panel-phy-timings = [00 19 06 06 21 20 07 + 06 04 02 04 00 15 16]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@12 { /* 5k */ + qcom,mdss-dsi-panel-phy-timings = [00 1a 07 06 22 21 07 + 07 04 02 04 00 16 16]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@13 { /* 720p 30 FPS */ + qcom,mdss-dsi-panel-phy-timings = [03 07 00 01 1a 1a 01 + 01 00 02 04 00 08 11]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@14 { /* 720p 60 FPS */ + qcom,mdss-dsi-panel-phy-timings = [01 09 01 01 1b 1b 01 + 01 01 02 04 00 0a 11]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@15 { /* 720p 90 FPS */ + qcom,mdss-dsi-panel-phy-timings = [00 0a 02 02 1c 1c 02 + 02 01 02 04 00 0b 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@16 { /* 720 120 FPS */ + qcom,mdss-dsi-panel-phy-timings = [00 0b 02 02 1c 1c 03 + 03 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@17 { /* 1080 144 FPS */ + qcom,mdss-dsi-panel-phy-timings = [00 13 05 04 1f 1e 05 + 05 03 02 04 00 12 14]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_sec_hd_cmd { + qcom,ulps-enabled; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_r66451_amoled_144hz_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 22 09 09 19 17 09 + 09 09 02 04 00 1d 0e]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-sde-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0484c59cba20580ef888628c23552e81f707e2c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-sde-pll.dtsi @@ -0,0 +1,67 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94900 { + compatible = "qcom,mdss_dsi_pll_7nm_v4_1"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94900 0x260>, + <0xae94400 0x800>, + <0xaf03000 0x8>, + <0xae94200 0x100>; + reg-names = "pll_base", "phy_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + memory-region = <&dfps_data_memory>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + }; + + mdss_dsi1_pll: qcom,mdss_dsi_pll@ae96900 { + compatible = "qcom,mdss_dsi_pll_7nm_v4_1"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96900 0x260>, + <0xae96400 0x800>, + <0xaf03000 0x8>, + <0xae96200 0x100>; + reg-names = "pll_base", "phy_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + compatible = "qcom,mdss_dp_pll_7nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea2b8 0x8>, + <0x088ea2e8 0x4>, + <0x088ea600 0x200>, + <0x088ea6b8 0x8>, + <0x088ea6e8 0x4>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", + "ln_tx0_base", "ln_tx0_tran_base", "ln_tx0_vmode_base", + "ln_tx1_base", "ln_tx1_tran_base", "ln_tx1_vmode_base", + "gdsc_base"; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", + "gcc_iface", "pipe_clk"; + clock-rate = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-sde.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c280379826df5a895997f09cd5356ee9509e5ba0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-sde.dtsi @@ -0,0 +1,705 @@ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x84208>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0x214>, + <0x0ae8f000 0x02c>, + <0x0af50000 0x038>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys", + "sid_phys", + "swfuse_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_HF_AXI_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", "gcc_nrt_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 0 300000000 19200000 300000000 19200000>; + clock-max-rate = <0 0 0 0 460000000 19200000 460000000 + 460000000>; + + mmcx-supply = <&VDD_MMCX_LEVEL>; + + /* interrupt config */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x494>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800 0x2a00>; + qcom,sde-ctl-size = <0x1dc>; + qcom,sde-ctl-display-pref = "primary", "none", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 + 0x48000 0x49000 0x4a000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-mixer-cwb-pref = "none", "none", "cwb", + "cwb", "cwb", "cwb"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>; + qcom,sde-dspp-size = <0x1800>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0x1c>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0x800>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x2bc 16>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000 0x72800 0x73000 0x73800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + qcom,sde-pp-merge-3d-id = <0x0 0x0 0x1 0x1 0x2 0x2>; + + qcom,sde-merge-3d-off = <0x84000 0x84100 0x84200>; + qcom,sde-merge-3d-size = <0x100>; + + qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0 0x0 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000 0x81400 0x81800 0x81c00>; + qcom,sde-dsc-size = <0x140>; + qcom,sde-dsc-pair-mask = <2 1 4 3>; + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 + 0x30e0 0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "vig", "vig", "vig", + "dma", "dma", "dma", "dma"; + + qcom,sde-sspp-off = <0x5000 0x7000 0x9000 0xb000 + 0x25000 0x27000 0x29000 0x2b000>; + qcom,sde-sspp-src-size = <0x1f8>; + + qcom,sde-sspp-xin-id = <0 4 8 12 + 1 5 9 13>; + qcom,sde-sspp-excl-rect = <1 1 1 1 + 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <5 6 7 8 1 2 3 4>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <2 1 4 3 6 5>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-max-per-pipe-bw-kbps = <4400000 4400000 + 4400000 4400000 + 4400000 4400000 + 4400000 4400000>; + + qcom,sde-max-per-pipe-bw-high-kbps = <5300000 5300000 + 5300000 5300000 + 5300000 5300000 + 5300000 5300000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2b4 0>, <0x2bc 0>, <0x2c4 0>, + <0x2ac 8>, <0x2b4 8>, <0x2bc 8>, <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <4096>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x3>; + qcom,sde-ubwc-version = <0x400>; + qcom,sde-ubwc-swizzle = <0x6>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-ubwc-static = <0x1>; + qcom,sde-macrotile-mode = <0x1>; + qcom,sde-smart-panel-align-mode = <0xc>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-has-dest-scaler; + qcom,sde-has-idle-pc; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <13700000>; + qcom,sde-max-bw-high-kbps = <16600000>; + qcom,sde-min-core-ib-kbps = <4800000>; + qcom,sde-min-llcc-ib-kbps = <0>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ltm-version = <0x00010000>; + /* offsets are based off dspp 0 and dspp 1 */ + qcom,sde-dspp-ltm-off = <0x2a000 0x28100>; + + qcom,sde-uidle-off = <0x80000>; + qcom,sde-uidle-size = <0x70>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-qos-cwb-remap = <3 3 4 4 5 5 6 3>; + qcom,sde-vbif-qos-lutdma-remap = <3 3 3 3 4 4 4 4>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x000000ff 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfff0>; + qcom,sde-safe-lut-macrotile = <0 0xff00>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xff00>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0x3ff>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22335777>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x66666541 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + qcom,sde-qos-cpu-irq-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010002>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + qcom,sde-reg-dma-xin-id = <7>; + qcom,sde-reg-dma-clk-ctrl = <0x2bc 20>; + + qcom,sde-secure-sid-mask = <0x4000821>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-gamut = <0x1d00 0x00060000>; + qcom,sde-vig-igc = <0x1d00 0x00060000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + }; + + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + }; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040002>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "mmcx"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0x820 0x402>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-earlymap; /* for cont-splash */ + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x821 0x400>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_dp: qcom,dp_display@ae90000 { + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&pm8150_l9>; + vdda-0p9-supply = <&pm8150_l18>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae91000 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>, + <0xae91400 0x094>; + /* dp_ctrl: dp_ahb, dp_aux, dp_link, dp_p0 */ + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_pipe_clk", "link_clk", "link_iface_clk", + "pixel_clk_rcg", "pixel_parent", + "pixel1_clk_rcg", "pixel1_parent", + "strm0_pixel_clk", "strm1_pixel_clk"; + + qcom,phy-version = <0x420>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13]; + qcom,aux-cfg2-settings = [28 A4]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,mst-enable; + qcom,widebus-enable; + qcom,dsc-feature-enable; + qcom,fec-feature-enable; + qcom,max-dp-dsc-blks = <2>; + qcom,max-dp-dsc-input-width-pixs = <2048>; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <33000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <912000>; + qcom,supply-max-voltage = <912000>; + qcom,supply-enable-load = <126000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x3c50>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <3>; + + qcom,sde-dram-channels = <2>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20513 0 0>, <20004 20513 0 0>, + <20003 20513 0 6400000>, <20004 20513 0 6400000>, + <20003 20513 0 6400000>, <20004 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "disp_rsc_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator@aea8800 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + status = "disabled"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x3>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_SF_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x215C 0x0400>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-0"; + cell-index = <0>; + frame-threshold-time-us = <800>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&pm8150_l9>; + refgen-supply = <&refgen>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <26700>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-1"; + cell-index = <1>; + frame-threshold-time-us = <800>; + reg = <0xae96000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <5 0>; + vdda-1p2-supply = <&pm8150_l9>; + refgen-supply = <&refgen>; + clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&clock_dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>, + <&clock_dispcc DISP_CC_MDSS_ESC1_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <26700>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v4.1"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x7c0>, + <0xae94200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; + vdda-0p9-supply = <&pm8150_l5>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <46000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy1@ae96400 { + compatible = "qcom,dsi-phy-v4.1"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x7c0>, + <0xae96200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; + vdda-0p9-supply = <&pm8150_l5>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <46000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-smp2p.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-smp2p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11b8f950b3759b7888170f3690cc1638ee2f1435 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-smp2p.dtsi @@ -0,0 +1,133 @@ +#include +#include + +&soc { + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-dsps { + compatible = "qcom,smp2p"; + qcom,smem = <481>, <430>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_SLPI IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <3>; + + dsps_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + dsps_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_qvrexternal5_out: qcom,smp2p-qvrexternal5-out { + qcom,entry-name = "qvrexternal"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_out: qcom,smp2p-rdbg5-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_in: qcom,smp2p-rdbg5-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-npu { + compatible = "qcom,smp2p"; + qcom,smem = <617>, <616>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&msm_npu IPCC_CLIENT_NPU IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <10>; + + npu_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + npu_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-thermal-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-thermal-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4d8cb9aa6987b22034611f40a2a94529757ea2fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-thermal-overlay.dtsi @@ -0,0 +1,130 @@ +#include + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&thermal_zones { + soc { + cooling-maps { + soc_cpu4 { + trip = <&soc_trip>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + soc_cpu5 { + trip = <&soc_trip>; + cooling-device = <&cpu5_isolate 1 1>; + }; + + soc_cpu6 { + trip = <&soc_trip>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + soc_cpu7 { + trip = <&soc_trip>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm8150b-bcl-lvl0 { + cooling-maps { + vbat_cpu4 { + trip = <&b_bcl_lvl0>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + vbat_cpu5 { + trip = <&b_bcl_lvl0>; + cooling-device = <&cpu5_isolate 1 1>; + }; + + vbat_gpu0 { + trip = <&b_bcl_lvl0>; + cooling-device = <&msm_gpu 2 2>; + }; + }; + }; + + pm8150b-bcl-lvl1 { + cooling-maps { + vbat_cpu6 { + trip = <&b_bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vbat_cpu7 { + trip = <&b_bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + + vbat_gpu1 { + trip = <&b_bcl_lvl1>; + cooling-device = <&msm_gpu 4 4>; + }; + }; + }; + + pm8150b-bcl-lvl2 { + cooling-maps { + vbat_gpu2 { + trip = <&b_bcl_lvl2>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm8150l-bcl-lvl0 { + disable-thermal-zone; + cooling-maps { + vph_cpu4 { + trip = <&l_bcl_lvl0>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + vph_cpu5 { + trip = <&l_bcl_lvl0>; + cooling-device = <&cpu5_isolate 1 1>; + }; + + vph_gpu0 { + trip = <&l_bcl_lvl0>; + cooling-device = <&msm_gpu 2 2>; + }; + }; + }; + + pm8150l-bcl-lvl1 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + + vph_gpu1 { + trip = <&l_bcl_lvl1>; + cooling-device = <&msm_gpu 4 4>; + }; + }; + }; + + pm8150l-bcl-lvl2 { + disable-thermal-zone; + cooling-maps { + vph_gpu2 { + trip = <&l_bcl_lvl2>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-thermal.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..318d2a32b83bf97865f2a6cf367672ab943e8aa1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-thermal.dtsi @@ -0,0 +1,1674 @@ +#include +#include + +&cpufreq_hw { + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + + cpu4_isolate: cpu4-isolate { + qcom,cpu = <&CPU4>; + #cooling-cells = <2>; + }; + + cpu5_isolate: cpu5-isolate { + qcom,cpu = <&CPU5>; + #cooling-cells = <2>; + }; + + cpu6_isolate: cpu6-isolate { + qcom,cpu = <&CPU6>; + #cooling-cells = <2>; + }; + + cpu7_isolate: cpu7-isolate { + qcom,cpu = <&CPU7>; + #cooling-cells = <2>; + }; + }; + + qcom,limits-dcvs { + compatible = "qcom,msm-hw-limits"; + isens_vref_0p8-supply = <&pm8150_l5_ao>; + isens-vref-0p8-settings = <880000 880000 20000>; + isens_vref_1p8-supply = <&pm8150_l12_ao>; + isens-vref-1p8-settings = <1800000 1800000 20000>; + }; +}; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = ; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_pa_fr1: modem_pa_fr1 { + qcom,qmi-dev-name = "pa_fr1"; + #cooling-cells = <2>; + }; + + modem_tj: modem_tj { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_mmw_skin0: modem_mmw_skin0 { + qcom,qmi-dev-name = "mmw_skin0"; + #cooling-cells = <2>; + }; + + modem_mmw_skin1: modem_mmw_skin1 { + qcom,qmi-dev-name = "mmw_skin1"; + #cooling-cells = <2>; + }; + + modem_mmw_skin2: modem_mmw_skin2 { + qcom,qmi-dev-name = "mmw_skin2"; + #cooling-cells = <2>; + }; + + modem_mmw_skin3: modem_mmw_skin3 { + qcom,qmi-dev-name = "mmw_skin3"; + #cooling-cells = <2>; + }; + + modem_mmw0: modem_mmw0 { + qcom,qmi-dev-name = "mmw0"; + #cooling-cells = <2>; + }; + + modem_mmw1: modem_mmw1 { + qcom,qmi-dev-name = "mmw1"; + #cooling-cells = <2>; + }; + + modem_mmw2: modem_mmw2 { + qcom,qmi-dev-name = "mmw2"; + #cooling-cells = <2>; + }; + + modem_mmw3: modem_mmw3 { + qcom,qmi-dev-name = "mmw3"; + #cooling-cells = <2>; + }; + + modem_bcl: modem_bcl { + qcom,qmi-dev-name = "vbatt_low"; + #cooling-cells = <2>; + }; + + modem_charge_state: modem_charge_state { + qcom,qmi-dev-name = "charge_state"; + #cooling-cells = <2>; + }; + }; + }; + + qmi_sensor: qmi-ts-sensors { + compatible = "qcom,qmi-sensors"; + #thermal-sensor-cells = <1>; + + modem { + qcom,instance-id = ; + qcom,qmi-sensor-names = "pa", + "pa_1", + "qfe_wtr0", + "modem_tsens", + "qfe_mmw0", + "qfe_mmw1", + "qfe_mmw2", + "qfe_mmw3", + "xo_therm", + "qfe_mmw_streamer0", + "qfe_mmw0_mod", + "qfe_mmw1_mod", + "qfe_mmw2_mod", + "qfe_mmw3_mod", + "qfe_ret_pa0", + "qfe_wtr_pa0", + "qfe_wtr_pa1", + "qfe_wtr_pa2", + "qfe_wtr_pa3", + "sys_therm1", + "sys_therm2", + "modem_tsens1"; + }; + }; + + lmh_isense_cdsp { + compatible = "qcom,msm-limits-cdsp"; + }; +}; + +&thermal_zones { + aoss0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-4-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-5-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-6-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-7-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 15>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + aoss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cwlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + ddr-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + q6-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cmpss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + npu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 8>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + active-config1 { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-max-step { + polling-delay-passive = <10>; + polling-delay = <100>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gpu_trip0: gpu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev { + trip = <&gpu_trip0>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + apc-0-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + silver-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + apc-1-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gold-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pop-mem-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + pop_trip: pop-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + pop_cdev4 { + trip = <&pop_trip>; + cooling-device = + <&CPU4 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + + pop_cdev7 { + trip = <&pop_trip>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu-0-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + cpu00_config: cpu00-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu00_cdev { + trip = <&cpu00_config>; + cooling-device = <&cpu0_isolate 1 1>; + }; + }; + }; + + cpu-0-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + cpu01_config: cpu01-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu01_cdev { + trip = <&cpu01_config>; + cooling-device = <&cpu1_isolate 1 1>; + }; + }; + }; + + cpu-0-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + cpu02_config: cpu02-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu02_cdev { + trip = <&cpu02_config>; + cooling-device = <&cpu2_isolate 1 1>; + }; + }; + }; + + cpu-0-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu03_config: cpu03-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu03_cdev { + trip = <&cpu03_config>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + cpu-1-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_10_config: cpufreq-10-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu10_config: cpu10-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_10_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu10_cdev { + trip = <&cpu10_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + }; + }; + + cpu-1-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_11_config: cpufreq-11-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu11_config: cpu11-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_11_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu11_cdev { + trip = <&cpu11_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpu-1-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_12_config: cpufreq-12-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu12_config: cpu12-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_12_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu12_cdev { + trip = <&cpu12_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_13_config: cpufreq-13-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu13_config: cpu13-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_13_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu13_cdev { + trip = <&cpu13_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + cpu-1-4-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_14_config: cpufreq-14-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu14_config: cpu14-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_14_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu14_cdev { + trip = <&cpu14_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + }; + }; + + cpu-1-5-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_15_config: cpufreq-15-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu15_config: cpu15-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_15_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu15_cdev { + trip = <&cpu15_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpu-1-6-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_16_config: cpufreq-16-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu16_config: cpu16-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_16_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu16_cdev { + trip = <&cpu16_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-7-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpufreq_17_config: cpufreq-17-config { + temperature = <75000>; + hysteresis = <5000>; + type = "passive"; + }; + + cpu17_config: cpu17-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpufreq_cdev { + trip = <&cpufreq_17_config>; + cooling-device = <&cpu7_notify 1 1>; + }; + + cpu17_cdev { + trip = <&cpu17_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + cwlan-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cwlan_trip0: cwlan-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&cwlan_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&cwlan_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&cwlan_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&cwlan_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&cwlan_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + video-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + video_trip0: video-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&video_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&video_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&video_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&video_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&video_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + ddr-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + ddr_trip0: ddr-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&ddr_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&ddr_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&ddr_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&ddr_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&ddr_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + q6-hvx-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + q6_hvx_trip0: q6-hvx-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&q6_hvx_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&q6_hvx_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&q6_hvx_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&q6_hvx_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&q6_hvx_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + camera-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + camera_trip0: camera-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&camera_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&camera_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&camera_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&camera_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&camera_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + cmpss-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cmpss_trip0: cmpss-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&cmpss_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&cmpss_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&cmpss_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&cmpss_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&cmpss_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + npu-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 7>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + npu_trip0: npu-trip0 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev { + trip = <&npu_trip0>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&npu_trip0>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&npu_trip0>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&npu_trip0>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&npu_trip0>; + cooling-device = <&msm_npu (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + }; + }; + + modem-lte-sub6-pa1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_PA)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-lte-sub6-pa2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_PA_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_0)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_2)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_3)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-skin-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_XO_THERM)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-wifi-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_SYS_THERM_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-ambient-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_SYS_THERM_2)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_MODEM_TSENS)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_MODEM_TSENS_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-streamer-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_STREAMER_0)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw0-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_0_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw1-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_1_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw2-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_2_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw3-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_NR_INST_ID+QMI_QFE_MMW_3_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-usb.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f4026b3fcef8894d86db9e2be818a70fac7de3fa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-usb.dtsi @@ -0,0 +1,595 @@ +#include +#include + +&soc { + /* Primary USB port related controller */ + usb0: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x0 0x0>; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x90000000 0x60000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts-extended = <&pdc 14 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 15 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + qcom,use-pdc-interrupts; + + USB3_GDSC-supply = <&usb30_prim_gdsc>; + dpdm-supply = <&usb2_phy0>; + clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&clock_gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_PRIM_SLEEP_CLK>, + /* + * GCC_USB3_SEC_CLKREF_EN provides ref_clk for both + * USB instances. + */ + <&clock_gcc GCC_USB3_SEC_CLKREF_EN>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + , + + /* min vote */ + , + , + ; + + dwc0: dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xd93c>; + interrupts = ; + usb-phy = <&usb2_phy0>, <&usb_qmp_dp_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3-u1u2-disable; + usb-core-id = <0>; + tx-fifo-resize; + maximum-speed = "super-speed-plus"; + dr_mode = "drd"; + }; + + qcom,usbbam@a704000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xa704000 0x17000>; + interrupts = ; + + qcom,usb-bam-fifo-baseaddr = <0x146bb000>; + qcom,usb-bam-num-pipes = <4>; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x6064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + }; + + /* Primary USB port related High Speed PHY */ + usb2_phy0: hsphy@88e3000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e3000 0x110>, + <0x088e2000 0x4>; + reg-names = "hsusb_phy_base", + "eud_enable_reg"; + + vdd-supply = <&pm8150_l5>; + vdda18-supply = <&pm8150_l12>; + vdda33-supply = <&pm8150_l2>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + }; + + /* Primary USB port related QMP USB DP Combo PHY */ + usb_qmp_dp_phy: ssphy@88e8000 { + compatible = "qcom,usb-ssphy-qmp-dp-combo"; + reg = <0x88e8000 0x3000>; + reg-names = "qmp_phy_base"; + + vdd-supply = <&pm8150_l18>; + qcom,vdd-voltage-level = <0 912000 912000>; + qcom,vdd-max-load-uA = <47000>; + core-supply = <&pm8150_l9>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK_SRC>, + <&clock_gcc USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "pipe_clk_mux", + "pipe_clk_ext_src", "ref_clk_src", + "com_aux_clk"; + + resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&clock_gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "global_phy_reset", "phy_reset"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x180f 0x0>; + qcom,iommu-dma = "disabled"; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + /* Secondary USB port related controller */ + usb1: ssusb@a800000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0xa800000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x20 0x0>; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x90000000 0x60000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts-extended = <&pdc 12 IRQ_TYPE_EDGE_BOTH>, + <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 16 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 13 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + qcom,use-pdc-interrupts; + + USB3_GDSC-supply = <&usb30_sec_gdsc>; + clocks = <&clock_gcc GCC_USB30_SEC_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_SEC_AXI_CLK>, + <&clock_gcc GCC_AGGRE_USB3_SEC_AXI_CLK>, + <&clock_gcc GCC_USB30_SEC_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_SEC_SLEEP_CLK>, + <&clock_gcc GCC_USB3_SEC_CLKREF_EN>; + + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_gcc GCC_USB30_SEC_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,charging-disabled; + + qcom,msm-bus,name = "usb1"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + ; + + dwc1: dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0xa800000 0xd93c>; + interrupts = ; + usb-phy = <&usb2_phy1>, <&usb_qmp_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <1>; + tx-fifo-resize; + maximum-speed = "super-speed"; + dr_mode = "drd"; + }; + }; + + /* Primary USB port related High Speed PHY */ + usb2_phy1: hsphy@88e4000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e4000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8150_l5>; + vdda18-supply = <&pm8150_l12>; + vdda33-supply = <&pm8150_l2>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + }; + + /* Secondary USB port related QMP PHY */ + usb_qmp_phy: ssphy@88eb000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0x88eb000 0x1000>, + <0x088eb88c 0x4>; + reg-names = "qmp_phy_base", + "pcs_clamp_enable_reg"; + + vdd-supply = <&pm8150_l18>; + qcom,vdd-voltage-level = <0 912000 912000>; + qcom,vdd-max-load-uA = <47000>; + core-supply = <&pm8150_l9>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_SEC_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_SEC_PHY_PIPE_CLK>, + <&clock_gcc GCC_USB3_SEC_PHY_PIPE_CLK_SRC>, + <&clock_gcc USB3_UNI_PHY_SEC_GCC_USB30_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_SEC_CLKREF_EN>, + <&clock_gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "pipe_clk_mux", + "pipe_clk_ext_src", "ref_clk_src", + "ref_clk", "com_aux_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_SEC_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..06e939b0913a5db7c8fe753512be0688f904950c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-cdp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona CDP"; + compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp"; + qcom,board-id = <0x10001 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-v2-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3565dfdd803e00b1eac0556ef199da313ffddd8e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-gpu.dtsi @@ -0,0 +1,477 @@ +&soc { + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + operating-points-v2 = <&gpu_opp_table_v2>; + }; + + gpu_opp_table_v2: gpu-opp-table_v2 { + compatible = "operating-points-v2"; + + opp-670000000 { + opp-hz = /bits/ 64 <670000000>; + opp-microvolt = ; + }; + + opp-587000000 { + opp-hz = /bits/ 64 <587000000>; + opp-microvolt = ; + }; + + opp-525000000 { + opp-hz = /bits/ 64 <525000000>; + opp-microvolt = ; + }; + + opp-490000000 { + opp-hz = /bits/ 64 <490000000>; + opp-microvolt = ; + }; + + opp-441600000 { + opp-hz = /bits/ 64 <441600000>; + opp-microvolt = ; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = ; + }; + + opp-305000000 { + opp-hz = /bits/ 64 <305000000>; + opp-microvolt = ; + }; + }; +}; + +&msm_gpu { + qcom,chipid = <0x06050001>; + + /* GPU OPP data */ + operating-points-v2 = <&gpu_opp_table_v2>; + + /delete-property/qcom,initial-pwrlevel; + /delete-node/qcom,gpu-pwrlevels; + + /* Power levels bins */ + qcom,gpu-pwrlevel-bins { + compatible="qcom,gpu-pwrlevel-bins"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <0>; + qcom,initial-pwrlevel = <5>; + qcom,throttle-pwrlevel = <0>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <587000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <11>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <11>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <525000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <9>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <8>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <490000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <441600000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq-ddr7 = <7>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <6>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <305000000>; + qcom,bus-freq-ddr7 = <3>; + qcom,bus-min-ddr7 = <2>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <3>; + qcom,bus-min-ddr8 = <2>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <1>; + qcom,initial-pwrlevel = <6>; + qcom,throttle-pwrlevel = <1>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <670000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <11>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <11>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <587000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <11>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <11>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <525000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <9>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <8>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <490000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <441600000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq-ddr7 = <7>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <6>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <305000000>; + qcom,bus-freq-ddr7 = <3>; + qcom,bus-min-ddr7 = <2>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <3>; + qcom,bus-min-ddr8 = <2>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <3>; + qcom,initial-pwrlevel = <4>; + qcom,throttle-pwrlevel = <0>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <525000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <10>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <10>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <490000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <441600000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq-ddr7 = <7>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <6>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <305000000>; + qcom,bus-freq-ddr7 = <3>; + qcom,bus-min-ddr7 = <2>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <3>; + qcom,bus-min-ddr8 = <2>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <2>; + qcom,initial-pwrlevel = <6>; + qcom,throttle-pwrlevel = <1>; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <670000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <11>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <11>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <587000000>; + qcom,bus-freq-ddr7 = <11>; + qcom,bus-min-ddr7 = <11>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <11>; + qcom,bus-min-ddr8 = <11>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <525000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <9>; + qcom,bus-max-ddr7 = <11>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <8>; + qcom,bus-max-ddr8 = <11>; + + qcom,acd-level = <0x802b5ffd>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <490000000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <441600000>; + qcom,bus-freq-ddr7 = <9>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <7>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq-ddr7 = <7>; + qcom,bus-min-ddr7 = <6>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <8>; + qcom,bus-min-ddr8 = <6>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <305000000>; + qcom,bus-freq-ddr7 = <3>; + qcom,bus-min-ddr7 = <2>; + qcom,bus-max-ddr7 = <9>; + + qcom,bus-freq-ddr8 = <3>; + qcom,bus-min-ddr8 = <2>; + qcom,bus-max-ddr8 = <9>; + + qcom,acd-level = <0xa02b5ffd>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp-sa.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp-sa.dts new file mode 100644 index 0000000000000000000000000000000000000000..413f5b0bd5cbeeb397870de2606de1fa15218a58 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp-sa.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona standalone MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x02010008 0>; +}; + +&mdm0 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp-ws.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp-ws.dts new file mode 100644 index 0000000000000000000000000000000000000000..dd76c7741bb4a75de48736daef4e5669d8f0f040 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp-ws.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-mtp-ws.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona V2 MTP (WS)"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x03010008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..792a32b4899eef39e212f26e61fc4d199214399c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-mtp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x10008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..6581125bf32f5a8bf8e18b9fc51657cb432f527f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-qrd.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona QRD"; + compatible = "qcom,kona-qrd", "qcom,kona", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-rumi.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..77006e3c06aa8a26d879dc49cdf160193fdeecf8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-rumi.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona RUMI"; + compatible = "qcom,kona-rumi", "qcom,kona", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion-ult.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion-ult.dts new file mode 100644 index 0000000000000000000000000000000000000000..9ce91f0f0cc55152fc435e2dbb977af0ad1d37d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion-ult.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-xrfusion-ult.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR 5G UltraSound"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x30008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion.dts new file mode 100644 index 0000000000000000000000000000000000000000..aaf83c850ad736323a5f9ce584a6f7b770859d77 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2-xrfusion.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.dtsi" +#include "kona-xrfusion.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR 5G Fusion"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x20008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..94599adb179e4abfec694df9d9010fd15edcc6ae --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-cdp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 CDP"; + compatible = "qcom,kona-cdp", "qcom,kona", "qcom,cdp"; + qcom,board-id = <0x10001 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bc5204681693e83877682daec0d9ceee86759988 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-gpu.dtsi @@ -0,0 +1,3 @@ +&msm_gpu { + qcom,chipid = <0x06050002>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-hdk.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-hdk.dts new file mode 100644 index 0000000000000000000000000000000000000000..965f4023f21deb4ca0bf96499845e7415d5dea70 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-hdk.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-hdk.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 HDK"; + compatible = "qcom,kona-hdk", "qcom,kona", "qcom,hdk"; + qcom,board-id = <0x01001F 0x01>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dts new file mode 100644 index 0000000000000000000000000000000000000000..0e445285402af295921f62dfa0fcbcd8b94703ba --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-v2.1-iot-rb5.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 IOT RB5"; + compatible = "qcom,kona-iot", "qcom,kona", "qcom,iot"; + qcom,board-id = <11 3>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..271c757fb636cd830bbc6dd69aae0c09abd8b3a6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-iot-rb5.dtsi @@ -0,0 +1,315 @@ +#include "kona-qrd.dtsi" +#include "kona-iot-rb5-audio.dtsi" +#include "camera/kona-camera-sensor-rb5.dtsi" + +&qupv3_se12_2uart { + status = "okay"; +}; + +&qupv3_se1_i2c { + status = "disabled"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&pm8150l_gpios { + lt9611_rst_pin_out { + lt9611_rst_pin_out_default: lt9611_rst_pin_out_default { + pins = "gpio5"; + function = "normal"; + output-enable; + input-disable; + bias-pull-down; + power-source = <0>; + }; + }; +}; + +&mdss_mdp { + connectors = <&sde_dp &sde_dsi &sde_dsi1 &sde_rscc>; +}; + +&mdss_dsi0_pll { + /delete-property/ qcom,dsi-pll-ssc-en; +}; + +&mdss_dsi1_pll { + /delete-property/ qcom,dsi-pll-ssc-en; +}; + +<9611_pins { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <8>; + bias-disable = <0>; + }; +}; + +&qupv3_se5_i2c { + status = "ok"; + lt9611: lt,lt9611@2b { + compatible = "lt,lt9611uxc"; + reg = <0x2b>; + interrupt-parent = <&tlmm>; + interrupts = <63 0>; + interrupt-names = "lt_irq"; + lt,irq-gpio = <&tlmm 63 0x0>; + lt,reset-gpio = <&pm8150l_gpios 5 0x0>; + instance_id = <0>; + lt,non-pluggable; + + pinctrl-names = "default"; + pinctrl-0 = <<9611_pins <9611_rst_pin_out_default>; + + lt,preferred-mode = "1920x1080"; + + totalVoltage-supply = <&pm8150a_l11>; + lt,supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + lt,supply-entry@0 { + reg = <0>; + lt,supply-name = "totalVoltage"; + lt,supply-min-voltage = <3300000>; + lt,supply-max-voltage = <3300000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + }; + + lt,customize-modes { + lt,customize-mode-id@0 { + lt,mode-h-active = <1920>; + lt,mode-h-front-porch = <88>; + lt,mode-h-pulse-width = <44>; + lt,mode-h-back-porch = <148>; + lt,mode-h-active-high; + lt,mode-v-active = <1080>; + lt,mode-v-front-porch = <4>; + lt,mode-v-pulse-width = <5>; + lt,mode-v-back-porch = <36>; + lt,mode-v-active-high; + lt,mode-refresh-rate = <60>; + lt,mode-clock-in-khz = <148500>; + }; + + lt,customize-mode-id@1 { + lt,mode-h-active = <3840>; + lt,mode-h-front-porch = <176>; + lt,mode-h-pulse-width = <88>; + lt,mode-h-back-porch = <400>; + lt,mode-h-active-high; + lt,mode-v-active = <2160>; + lt,mode-v-front-porch = <8>; + lt,mode-v-pulse-width = <10>; + lt,mode-v-back-porch = <72>; + lt,mode-v-active-high; + lt,mode-refresh-rate = <60>; + lt,mode-clock-in-khz = <608040>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt9611_in_0: endpoint { + remote-endpoint = <&ext_dsi_0_out>; + }; + }; + + port@1 { + reg = <1>; + lt9611_in_1: endpoint { + remote-endpoint = <&ext_dsi_1_out>; + }; + }; + + }; + }; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_ext_bridge_1080p>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ext_dsi_0_out: endpoint { + remote-endpoint = <<9611_in_0>; + }; + }; + }; +}; + +&sde_dsi1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + ext_dsi_1_out: endpoint { + remote-endpoint = <<9611_in_1>; + }; + }; + }; +}; + +&usb1 { + /delete-property/ qcom,default-mode-none; + dwc3@a800000 { + dr_mode = "host"; + }; +}; + +&soc { + clk40M: can_clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <40000000>; + }; +}; + +&usb0 { + qcom,charging-disabled; +}; + +&usb2_phy0 { + qcom,param-override-seq = <0x43 0x70>; +}; + +&pm8150b_charger { + qcom,batteryless-platform; +}; + +&qupv3_se0_spi { + status = "okay"; + can@0 { + compatible = "microchip,mcp2517fd"; + reg = <0>; + clocks = <&clk40M>; + interrupt-parent = <&tlmm>; + interrupts = <15 0>; + interrupt-names = "can_irq"; + spi-max-frequency = <10000000>; + gpio-controller; + status = "okay"; + }; +}; + +&pcie1 { + status = "disabled"; +}; + +&thermal_zones { + /delete-node/ modem-lte-sub6-pa1; + /delete-node/ modem-lte-sub6-pa2; + /delete-node/ modem-mmw0-usr; + /delete-node/ modem-mmw1-usr; + /delete-node/ modem-mmw2-usr; + /delete-node/ modem-mmw3-usr; + /delete-node/ modem-skin-usr; + /delete-node/ modem-wifi-usr; + /delete-node/ modem-ambient-usr; + /delete-node/ modem-0-usr; + /delete-node/ modem-1-usr; + /delete-node/ modem-streamer-usr; + /delete-node/ modem-mmw0-mod-usr; + /delete-node/ modem-mmw1-mod-usr; + /delete-node/ modem-mmw2-mod-usr; + /delete-node/ modem-mmw3-mod-usr; + + /delete-node/ skin-therm-usr; + /delete-node/ skin-therm-step; + /delete-node/ camera-therm-usr; + + /delete-node/ mmw-pa1-usr; + /delete-node/ mmw-pa1-step; + /delete-node/ mmw-pa2-usr; + /delete-node/ mmw-pa2-step; + /delete-node/ xo-therm-step; + /delete-node/ xo-therm-usr; + /delete-node/ skin-msm-therm-step; + + pm8250-wifi-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <52000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + }; + + pm8150l-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <50000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + }; + + pm8250-xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <50000>; + hysteresis = <4000>; + type = "passive"; + }; + + }; + }; + + pm8150l-skin-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + skin_trip: skin-config0 { + temperature = <50000>; + hysteresis = <48000>; + type = "passive"; + }; + }; + + cooling-maps { + lcd_cdev { + trip = <&skin_trip>; + cooling-device = <&mdss_mdp 153 153>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-sa.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-sa.dts new file mode 100644 index 0000000000000000000000000000000000000000..daaf65a9e5cecdfd82f09f849197beff6725fc32 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-sa.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 standalone MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x02010008 0>; +}; + +&mdm0 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-ws.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-ws.dts new file mode 100644 index 0000000000000000000000000000000000000000..5619b98f13bf5fa32237ae1727f3592f3b3b8cd8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp-ws.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-mtp-ws.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 MTP (WS)"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x03010008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ec73498aab130128b100eafcec87b96349004159 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-mtp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 MTP"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x10008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..29824a87812d29cdd4a1334087683d4740f7e641 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-qrd.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 QRD"; + compatible = "qcom,kona-qrd", "qcom,kona", "qcom,qrd"; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion-ult.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion-ult.dts new file mode 100644 index 0000000000000000000000000000000000000000..cf616a6d7898bcd6f69590a5d93f6ca9090638bc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion-ult.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-xrfusion-ult.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 XR 5G UltraSound"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x30008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion.dts new file mode 100644 index 0000000000000000000000000000000000000000..616943e7a8832701f3fe52db61cbe17b5c4d963b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1-xrfusion.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" +#include "kona-xrfusion.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 XR 5G Fusion"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x20008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dts new file mode 100644 index 0000000000000000000000000000000000000000..e2b673c42492bfa73502224d655ea5df14d879d7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "kona-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1 SoC"; + compatible = "qcom,kona"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..76658bfa29dd4884a634986eda9a2e571f5b1741 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.1.dtsi @@ -0,0 +1,10 @@ + +#include "kona-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2.1"; + compatible = "qcom,kona"; + qcom,msm-id = <356 0x20001>; +}; + +#include "kona-v2.1-gpu.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.dts b/arch/arm64/boot/dts/vendor/qcom/kona-v2.dts new file mode 100644 index 0000000000000000000000000000000000000000..65a8d498dd4f7e0d4d785d0b8cda2766706d232b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "kona-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2 SoC"; + compatible = "qcom,kona"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-v2.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-v2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8ca5010a1ab7bc68189d14ecfd34442b37711167 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-v2.dtsi @@ -0,0 +1,393 @@ +#include "kona.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v2"; + compatible = "qcom,kona"; + qcom,msm-id = <356 0x20000>; +}; + +&CPU4 { + dynamic-power-coefficient = <533>; +}; + +&CPU5 { + dynamic-power-coefficient = <533>; +}; + +&CPU6 { + dynamic-power-coefficient = <533>; +}; + +&CPU7 { + dynamic-power-coefficient = <642>; +}; + +&clock_camcc { + compatible = "qcom,camcc-kona-v2", "syscon"; +}; + +&clock_videocc { + compatible = "qcom,videocc-kona-v2", "syscon"; +}; + +&clock_npucc { + compatible = "qcom,npucc-kona-v2", "syscon"; +}; + +&spss_utils { + qcom,spss-dev-firmware-name = "spss2d"; /* 8 chars max */ + qcom,spss-test-firmware-name = "spss2t"; /* 8 chars max */ + qcom,spss-prod-firmware-name = "spss2p"; /* 8 chars max */ +}; + +#include "kona-v2-gpu.dtsi" + +&cpu0_cpu_l3_latmon { + qcom,core-dev-table = + < 300000 300000000 >, + < 403200 403200000 >, + < 518400 518400000 >, + < 691200 614400000 >, + < 883200 825600000 >, + < 1075200 921600000 >, + < 1171200 1017600000 >, + < 1344000 1132800000 >, + < 1420800 1228800000 >, + < 1516800 1324800000 >, + < 1612800 1516800000 >, + < 1804800 1612800000 >; +}; + +&cpu4_cpu_l3_latmon { + qcom,core-dev-table = + < 300000 300000000 >, + < 825600 614400000 >, + < 1171200 825600000 >, + < 1478400 1017600000 >, + < 1670400 1228800000 >, + < 2054400 1324800000 >, + < 2419200 1516800000 >, + < 2841600 1612800000 >; +}; + +&cpu7_cpu_l3_latmon { + qcom,core-dev-table = + < 300000 300000000 >, + < 825600 614400000 >, + < 1171200 825600000 >, + < 1478400 1017600000 >, + < 1670400 1228800000 >, + < 2054400 1324800000 >, + < 2419200 1516800000 >, + < 2841600 1612800000 >; +}; + +&cpu0_cpu_llcc_latmon { + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 150, 16) >, + < 787200 MHZ_TO_MBPS( 300, 16) >, + < 1516800 MHZ_TO_MBPS( 466, 16) >, + < 1804800 MHZ_TO_MBPS( 600, 16) >; +}; + +&cpu4_cpu_llcc_latmon { + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 150, 16) >, + < 710400 MHZ_TO_MBPS( 300, 16) >, + < 1056000 MHZ_TO_MBPS( 466, 16) >, + < 1286400 MHZ_TO_MBPS( 600, 16) >, + < 1862400 MHZ_TO_MBPS( 806, 16) >, + < 2419200 MHZ_TO_MBPS( 933, 16) >, + < 2841600 MHZ_TO_MBPS( 1000, 16) >; +}; + +&cpu0_llcc_ddr_latmon { + qcom,cachemiss-ev = <0x1000>; + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 787200 MHZ_TO_MBPS( 451, 4) >, + < 1171200 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS( 1017, 4) >; + }; + + ddr5-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 787200 MHZ_TO_MBPS( 451, 4) >, + < 1171200 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS( 1017, 4) >; + }; +}; + +&cpu4_llcc_ddr_latmon { + qcom,cachemiss-ev = <0x1000>; + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 710400 MHZ_TO_MBPS( 451, 4) >, + < 825600 MHZ_TO_MBPS( 547, 4) >, + < 1056000 MHZ_TO_MBPS( 768, 4) >, + < 1286400 MHZ_TO_MBPS(1017, 4) >, + < 1574400 MHZ_TO_MBPS(1353, 4) >, + < 1862400 MHZ_TO_MBPS(1555, 4) >, + < 2419200 MHZ_TO_MBPS(1804, 4) >, + < 2745600 MHZ_TO_MBPS(2092, 4) >, + < 2841600 MHZ_TO_MBPS(2736, 4) >; + }; + + ddr5-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 710400 MHZ_TO_MBPS( 451, 4) >, + < 825600 MHZ_TO_MBPS( 547, 4) >, + < 1056000 MHZ_TO_MBPS( 768, 4) >, + < 1286400 MHZ_TO_MBPS(1017, 4) >, + < 1862400 MHZ_TO_MBPS(1555, 4) >, + < 2419200 MHZ_TO_MBPS(1804, 4) >, + < 2745600 MHZ_TO_MBPS(2092, 4) >, + < 2841600 MHZ_TO_MBPS(2736, 4) >; + }; +}; + +&cpu4_computemon { + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 1862400 MHZ_TO_MBPS( 200, 4) >, + < 2745600 MHZ_TO_MBPS(1017, 4) >, + < 2841600 MHZ_TO_MBPS(2092, 4) >; + }; + + ddr5-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 1862400 MHZ_TO_MBPS( 200, 4) >, + < 2745600 MHZ_TO_MBPS(1017, 4) >, + < 2841600 MHZ_TO_MBPS(2736, 4) >; + }; +}; + +&cpu4_qoslatmon { + qcom,cachemiss-ev = <0x1000>; +}; + +/* NPU overrides */ +&msm_npu { + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <5>; + qcom,npu-pwrlevel@0 { + reg = <0>; + vreg = <1>; + clk-freq = <19200000 + 100000000 + 300000000 + 300000000 + 300000000 + 300000000 + 200000000 + 40000000 + 300000000 + 100000000 + 19200000 + 50000000 + 50000000 + 100000000 + 100000000 + 100000000 + 19200000 + 100000000 + 19200000 + 50000000 + 200000000 + 200000000 + 50000000 + 19200000 + 300000000 + 300000000 + 19200000 + 300000000>; + }; + + qcom,npu-pwrlevel@1 { + reg = <1>; + vreg = <2>; + clk-freq = <19200000 + 200000000 + 406000000 + 406000000 + 406000000 + 406000000 + 267000000 + 40000000 + 403000000 + 200000000 + 19200000 + 50000000 + 50000000 + 200000000 + 200000000 + 200000000 + 19200000 + 200000000 + 19200000 + 50000000 + 406000000 + 406000000 + 50000000 + 19200000 + 406000000 + 406000000 + 19200000 + 400000000>; + }; + + qcom,npu-pwrlevel@2 { + reg = <2>; + vreg = <3>; + clk-freq = <19200000 + 333000000 + 533000000 + 533000000 + 533000000 + 533000000 + 403000000 + 75000000 + 533000000 + 214000000 + 19200000 + 50000000 + 100000000 + 214000000 + 214000000 + 214000000 + 19200000 + 214000000 + 19200000 + 50000000 + 533000000 + 533000000 + 50000000 + 19200000 + 533000000 + 533000000 + 19200000 + 500000000>; + }; + + qcom,npu-pwrlevel@3 { + reg = <3>; + vreg = <4>; + clk-freq = <19200000 + 428000000 + 730000000 + 730000000 + 730000000 + 730000000 + 533000000 + 75000000 + 700000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 730000000 + 730000000 + 100000000 + 19200000 + 730000000 + 730000000 + 19200000 + 660000000>; + }; + + qcom,npu-pwrlevel@4 { + reg = <4>; + vreg = <6>; + clk-freq = <19200000 + 500000000 + 920000000 + 920000000 + 920000000 + 920000000 + 700000000 + 75000000 + 806000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 920000000 + 920000000 + 100000000 + 19200000 + 920000000 + 920000000 + 19200000 + 800000000>; + }; + + qcom,npu-pwrlevel@5 { + reg = <5>; + vreg = <7>; + clk-freq = <19200000 + 500000000 + 1000000000 + 1000000000 + 1000000000 + 1000000000 + 700000000 + 75000000 + 806000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 1000000000 + 1000000000 + 100000000 + 19200000 + 1000000000 + 1000000000 + 19200000 + 800000000>; + }; + }; +}; + +&cpufreq_hw { + interrupts = , + , + ; + interrupt-names = "dcvsh0_int", "dcvsh1_int", "dcvsh2_int"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-va-bolero.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-va-bolero.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fc56b3172b42065a2c25c71f3a0951e866eafdad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-va-bolero.dtsi @@ -0,0 +1,19 @@ +&bolero { + va_macro: va-macro@3370000 { + compatible = "qcom,va-macro"; + reg = <0x3370000 0x0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + va-vdd-micb-supply = <&S4A>; + qcom,va-vdd-micb-voltage = <1800000 1800000>; + qcom,va-vdd-micb-current = <11200>; + qcom,va-dmic-sample-rate = <600000>; + qcom,va-clk-mux-select = <1>; + qcom,va-island-mode-muxsel = <0x033A0000>; + qcom,default-clk-id = ; + }; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-vidc.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a0b09cab75170f5f9debde5ad54372c1de3d76d8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-vidc.dtsi @@ -0,0 +1,121 @@ +#include +#include +#include + +&soc { + msm_vidc: qcom,vidc@aa00000 { + compatible = "qcom,msm-vidc", "qcom,kona-vidc"; + status = "ok"; + sku-index = <0>; + reg = <0x0aa00000 0x00100000>; + interrupts = ; + + /* IOMMU Config */ + #address-cells = <1>; + #size-cells = <1>; + + /* LLCC Cache */ + cache-slice-names = "vidsc0"; + + /* Supply */ + iris-ctl-supply = <&mvs0c_gdsc>; + vcodec-supply = <&mvs0_gdsc>; + + /* Clocks */ + clock-names = "gcc_video_axi0", + "core_clk", "vcodec_clk"; + clocks = <&clock_gcc GCC_VIDEO_AXI0_CLK>, + <&clock_videocc VIDEO_CC_MVS0C_CLK>, + <&clock_videocc VIDEO_CC_MVS0_CLK>; + qcom,proxy-clock-names = "gcc_video_axi0", + "core_clk", "vcodec_clk"; + /* Mask: Bit0: Clock Scaling, Bit1: Mem Retention*/ + qcom,clock-configs = <0x0 0x1 0x1>; + qcom,allowed-clock-rates = <239999999 338000000 + 366000000 444000000>; + resets = <&clock_gcc GCC_VIDEO_AXI0_CLK_ARES>, + <&clock_videocc VIDEO_CC_MVS0C_CLK_ARES>; + reset-names = "video_axi_reset", "video_core_reset"; + + qcom,reg-presets = <0xB0088 0x0>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <762 762>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venus-ddr"; + qcom,bus-range-kbps = <762 15000000>; + }; + + venus_bus_llcc { + compatible = "qcom,msm-vidc,bus"; + label = "venus-llcc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venuc-llcc"; + qcom,bus-range-kbps = <2288 15000000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0x2100 0x0400>; + qcom,iommu-dma-addr-pool = <0x25800000 0xba800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0x2104 0x0400>; + qcom,iommu-dma-addr-pool = <0x01000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x01000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0x2101 0x0404>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x00500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0x2103 0x0400>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x00500000 0xdfb00000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xr-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xr-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..76f19e6aee30f8664acbfa63ebfaabd772e68283 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xr-overlay.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-xr.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. XR kona Standalone"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x1010008 0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xr-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-xr-pinctrl-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bc6d7f0d51cce458ce1fe1acba767953d73bb04a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xr-pinctrl-overlay.dtsi @@ -0,0 +1,195 @@ +&cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio94"; + function = "cam_mclk"; + }; + + config { + pins = "gpio94"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio95"; + function = "cam_mclk"; + }; + + config { + pins = "gpio95"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio96"; + function = "cam_mclk"; + }; + + config { + pins = "gpio96"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio97"; + function = "cam_mclk"; + }; + + config { + pins = "gpio97"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk4_active { + /* MCLK4 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk4_suspend { + /* MCLK4 */ + mux { + pins = "gpio98"; + function = "cam_mclk"; + }; + + config { + pins = "gpio98"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk5_active { + /* MCLK5 */ + mux { + pins = "gpio99"; + function = "cam_mclk"; + }; + + config { + pins = "gpio99"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk5_suspend { + /* MCLK5 */ + mux { + pins = "gpio99"; + function = "cam_mclk"; + }; + + config { + pins = "gpio99"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk6_active { + /* MCLK6 */ + mux { + pins = "gpio100"; + function = "cam_mclk"; + }; + + config { + pins = "gpio100"; + bias-disable; /* No PULL */ + drive-strength = <16>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk6_suspend { + /* MCLK6 */ + mux { + pins = "gpio100"; + function = "cam_mclk"; + }; + + config { + pins = "gpio100"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <16>; /* 2 MA */ + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xr.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xr.dts new file mode 100644 index 0000000000000000000000000000000000000000..eba0487d327cff26b92093f3c98b6d0e14675f5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xr.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-xr.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR Standalone"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x10108 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xr.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-xr.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ce4bbf54c17178f31c397b665a80c998cec3d3ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xr.dtsi @@ -0,0 +1,1210 @@ +#include +#include + + +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "kona-audio-overlay.dtsi" +#include "kona-thermal-overlay.dtsi" +#include "kona-xr-pinctrl-overlay.dtsi" +#include "camera/kona-camera-sensor-xr.dtsi" + +&tlmm { + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + pri_aux_pcm_dout { + pri_aux_pcm_dout_sleep: pri_aux_pcm_dout_sleep { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_dout_active: pri_aux_pcm_dout_active { + mux { + pins = "gpio7"; + function = "mi2s0_data1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm_dout { + sec_aux_pcm_dout_sleep: sec_aux_pcm_dout_sleep { + mux { + pins = "gpio6"; + function = "gpio"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_dout_active: sec_aux_pcm_dout_active { + mux { + pins = "gpio6"; + function = "mi2s0_data1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_aux_pcm { + tert_aux_pcm_clk_sleep: tert_aux_pcm_clk_sleep { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_clk_active: tert_aux_pcm_clk_active { + mux { + pins = "gpio9"; + function = "mi2s2_sck"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_aux_pcm_din { + tert_aux_pcm_din_sleep: tert_aux_pcm_din_sleep { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_din_active: tert_aux_pcm_din_active { + mux { + pins = "gpio8"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_tdm_dout { + pri_tdm_dout_sleep: pri_tdm_dout_sleep { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_tdm_dout_active: pri_tdm_dout_active { + mux { + pins = "gpio7"; + function = "mi2s0_data1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_tdm_dout { + sec_tdm_dout_sleep: sec_tdm_dout_sleep { + mux { + pins = "gpio6"; + function = "gpio"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_tdm_dout_active: sec_tdm_dout_active { + mux { + pins = "gpio6"; + function = "mi2s1_data1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_tdm { + tert_tdm_clk_sleep: tert_tdm_clk_sleep { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_tdm_clk_active: tert_tdm_clk_active { + mux { + pins = "gpio9"; + function = "mi2s2_sck"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_tdm_din { + tert_tdm_din_sleep: tert_tdm_din_sleep { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_tdm_din_active: tert_tdm_din_active { + mux { + pins = "gpio8"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_mi2s_sd1 { + pri_mi2s_sd1_sleep: pri_mi2s_sd1_sleep { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd1_active: pri_mi2s_sd1_active { + mux { + pins = "gpio7"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + sec_mi2s_sd1 { + sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep { + mux { + pins = "gpio6"; + function = "gpio"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd1_active: sec_mi2s_sd1_active { + mux { + pins = "gpio6"; + function = "mi2s1_data1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sck { + tert_mi2s_sck_sleep: tert_mi2s_sck_sleep { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sck_active: tert_mi2s_sck_active { + mux { + pins = "gpio9"; + function = "mi2s2_sck"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sd0 { + tert_mi2s_sd0_sleep: tert_mi2s_sd0_sleep { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd0_active: tert_mi2s_sd0_active { + mux { + pins = "gpio8"; + function = "mi2s2_data0"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + display_panel_led1_default: display_panel_led1_default { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; + + display_panel_led2_default: display_panel_led2_default { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; + +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&dai_mi2s2 { + status = "ok"; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep>; +}; + +&kona_snd { + qcom,model = "kona-xr-standalone-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>, <1>; + qcom,wcn-bt = <1>; + qcom,ext-disp-audio-rx = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "DMIC6", "MIC BIAS3", + "MIC BIAS3", "Digital Mic6", + "DMIC7", "MIC BIAS3", + "MIC BIAS3", "Digital Mic7", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&lpi_tlmm>, + <&bolero>; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18800>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vcc-voltage-level = <2504000 2950000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8150_l6>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&pm8150a_l11 { + qcom,init-voltage = <3304000>; +}; + + +&vendor { + kona_xr_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen4-batterydata-mlp466274-3650mah.dtsi" + #include "fg-gen4-batterydata-atl466274-3650mah.dtsi" + }; +}; + + +&pm8150a_amoled { + status = "disabled"; +}; + +&qupv3_se1_i2c { + status = "disabled"; +}; + +&pcie1 { + status = "disabled"; +}; + +&pcie2 { + status = "disabled"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_home_default + &key_vol_up_default>; + + home { + label = "home"; + gpios = <&pm8150_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qcom,qbt_handler { + status = "disabled"; + }; + + qcom,xr-stdalonevwr-misc { + compatible = "qcom,xr-stdalonevwr-misc"; + }; +}; + +&qupv3_se13_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + st_fts@49 { + status = "disabled"; + }; +}; + +&qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; + + halo,hl6111r@25 { + compatible = "halo,hl6111r"; + reg = <0x25>; + status = "disabled"; + }; +}; + +&vendor { + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + }; + + extcon_usb1: extcon_usb1 { + compatible = "linux,extcon-usb-gpio"; + vbus-gpio = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; + id-gpio = <&tlmm 91 GPIO_ACTIVE_HIGH>; + vbus-out-gpio = <&pm8150_gpios 9 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_det_default + &usb2_id_det_default + &usb2_vbus_boost_default>; + }; +}; + +&vreg_hap_boost { + status = "ok"; +}; + +&pm8150b_haptics { + vdd-supply = <&vreg_hap_boost>; +}; + +&pm8150b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&pm8150b_charger { + status = "ok"; + qcom,sec-charger-config = <0>; + qcom,auto-recharge-soc = <98>; + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "mid_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp"; + qcom,battery-data = <&kona_xr_batterydata>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,wd-bark-time-secs = <16>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; +}; + +&pm8150b_fg { + status = "ok"; + qcom,battery-data = <&kona_xr_batterydata>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,five-pin-battery; + qcom,cl-wt-enable; + qcom,soc-scale-mode-en; + /* ESR fast calibration */ + qcom,fg-esr-timer-chg-fast = <0 7>; + qcom,fg-esr-timer-dischg-fast = <0 7>; + qcom,fg-esr-timer-chg-slow = <0 96>; + qcom,fg-esr-timer-dischg-slow = <0 96>; + qcom,fg-esr-cal-soc-thresh = <26 230>; + qcom,fg-esr-cal-temp-thresh = <10 40>; +}; + +&qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; +#include "smb1390.dtsi" + + halo,hl6111r@25 { + compatible = "halo,hl6111r"; + reg = <0x25>; + status = "ok"; + }; +}; + +&smb1390 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@4d { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4e { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + camera_flash_therm@4d { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_msm_therm@4e { + reg = ; + label = "skin_msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm2@4f { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM3_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + camera_flash_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_debug_bus { + status = "ok"; +}; + +&dsi_dual_xrsmrtvwr_jdi_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 66 0>; + + qcom,platform-bklight-en-gpio = <&tlmm 133 0>; + qcom,5v-boost-gpio = <&tlmm 134 0>; + /delete-property/ qcom,platform-en-gpio; +}; + +&sde_dsi { + avdd-supply = <&display_panel_avdd>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,dsi-default-panel = <&dsi_dual_xrsmrtvwr_jdi_video>; +}; + +&display_panel_avdd { + display_panel_led1_gpio = <&tlmm 144 0>; + display_panel_led2_gpio = <&tlmm 140 0>; + enable-active-high; + regulator-boot-on; + pinctrl-names = "default"; + pinctrl-0 = <&display_panel_led1_default + &display_panel_led2_default>; +}; + +&dsi_panel_pwr_supply_lab_ibb { + qcom,panel-supply-entry@3 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&pm8150l_lcdb { + status = "ok"; +}; + +&pm8150l_wled { + status = "ok"; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150_s4>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&usb1 { + extcon = <&extcon_usb1>; +}; + +&flash_led { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&pm8150l_flash0 { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&pm8150l_flash1 { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&pm8150l_flash2 { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&pm8150l_torch0 { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&pm8150l_torch1 { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&pm8150l_torch2 { + qcom,hw-strobe-option = <0>; + qcom,strobe-sel = <1>; +}; + +&wil6210 { + status = "disabled"; +}; + +&key_home_default { + pins = "gpio7"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..589db276254d2767b618ffb6bd79fb15135f101a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-overlay.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-xrfusion.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR 5G Fusion"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x1020008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..004cd8a7a17992ad41da7474465cd46fb636c36c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult-overlay.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "kona-xrfusion-ult.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR 5G UltraSound"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x1030008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult.dts new file mode 100644 index 0000000000000000000000000000000000000000..69e681074f3f7eee25a4877ff3fd9c50976246ad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-xrfusion-ult.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR 5G UltraSound"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x30008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..65d61aa87f8459ae5eef366ee9982826349af2c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion-ult.dtsi @@ -0,0 +1,1114 @@ +#include +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "kona-audio-overlay.dtsi" +#include "kona-thermal-overlay.dtsi" +#include "kona-xr-pinctrl-overlay.dtsi" +#include "camera/kona-camera-sensor-xrfusion.dtsi" + +&tlmm { + display_panel_led1_default: display_panel_led1_default { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; + + display_panel_led2_default: display_panel_led2_default { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; + + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + cam_sensor_6dof_vana_active: cam_sensor_6dof_vana_active { + /* AVDD LDO */ + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vana_suspend: cam_sensor_6dof_vana_suspend { + /* AVDD LDO */ + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vdig_active: cam_sensor_6dof_vdig_active { + /* VDIG LDO */ + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vdig_suspend: cam_sensor_6dof_vdig_suspend { + /* VDIG LDO */ + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vio_active: cam_sensor_6dof_vio_active { + /* VIO LDO */ + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vio_suspend: cam_sensor_6dof_vio_suspend { + /* VIO LDO */ + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&vendor { + kona_xrfusion_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen4-batterydata-goertek-6100mah.dtsi" + }; +}; + +&qupv3_se12_2uart { + status = "okay"; +}; + +&pm8150a_amoled { + status = "disabled"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&dai_mi2s2 { + status = "disabled"; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep>; +}; + +&kona_snd { + qcom,model = "kona-xrfusion-ult-snd-card"; + qcom,mi2s-audio-intf = <0>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS4", + "MIC BIAS4", "Analog Mic4", + "AMIC5", "MIC BIAS5", + "MIC BIAS5", "Analog Mic5", + "AMIC6", "MIC BIAS6", + "MIC BIAS6", "Analog Mic6", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "DMIC4", "MIC BIAS3", + "MIC BIAS3", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "DMIC6", "MIC BIAS3", + "MIC BIAS3", "Digital Mic6", + "DMIC7", "MIC BIAS3", + "MIC BIAS3", "Digital Mic7", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&lpi_tlmm>, + <&bolero>; +}; + +&pm8150_l10 { + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <3304000>; +}; + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + xrfancontroller: xrfancontroller@50 { + compatible = "maxim,xrfancontroller"; + reg = <0x50>; + qcom,fan-pwr-en = <&tlmm 38 0x00>; + qcom,fan-pwr-bp = <&tlmm 39 0x00>; + }; +}; + +&qupv3_se13_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18800>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vcc-voltage-level = <2504000 2950000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8150_l6>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vccq-parent-supply = <&pm8150a_s8>; + qcom,vccq-parent-max-microamp = <210000>; + + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default + &key_confirm_default + &key_vol_up_default>; + + home { + label = "home"; + gpios = <&pm8150_gpios 1 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + confirm { + label = "confirm"; + gpios = <&pm8150_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qcom,qbt_handler { + status = "disabled"; + }; + + qcom,xr-stdalonevwr-misc { + compatible = "qcom,xr-stdalonevwr-misc"; + /* IMU CLK Enable PM8150 GPIO 3 */ + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&imu_clkin_default>; + pinctrl-1 = <&imu_clkin_sleep>; + }; +}; + +&vreg_hap_boost { + status = "ok"; +}; + +&pm8150b_haptics { + qcom,vmax-mv = <1697>; + qcom,play-rate-us = <5882>; + vdd-supply = <&vreg_hap_boost>; + + wf_0 { + /* CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_1 { + /* DOUBLE CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_2 { + /* TICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_3 { + /* THUD */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_4 { + /* POP */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_5 { + /* HEAVY CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; +}; + +&pm8150b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; + redriver: redriver@1c { + compatible = "onnn,redriver"; + reg = <0x1c>; + extcon = <&pm8150b_pdphy>, <&pm8150b_pdphy>; + eq = /bits/ 8 < + /* Parameters for USB */ + 0x4 0x4 0x4 0x4 + /* Parameters for DP */ + 0x6 0x4 0x4 0x6>; + flat-gain = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x1 0x1 0x3 + /* Parameters for DP */ + 0x2 0x1 0x1 0x2>; + output-comp = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x3 0x3 0x3 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + loss-match = /bits/ 8 < + /* Parameters for USB */ + 0x1 0x3 0x3 0x1 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + }; + + #include "smb1390.dtsi" +}; + +&smb1390 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + qcom,parallel-output-mode = <2>; + status = "ok"; +}; + +&smb1390_slave { + status = "ok"; +}; + +&smb1390_slave_charger { + status = "ok"; +}; + +&pm8150b_charger { + status = "ok"; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "mid_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp"; + qcom,battery-data = <&kona_xrfusion_batterydata>; + qcom,sw-jeita-enable; + qcom,wd-bark-time-secs = <16>; + qcom,suspend-input-on-debug-batt; + qcom,thermal-mitigation = <5325000 4500000 4000000 3500000 3000000 + 2500000 2000000 1500000 1000000 500000>; +}; + +&pm8150b_fg { + status = "ok"; + qcom,battery-data = <&kona_xrfusion_batterydata>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,five-pin-battery; + qcom,cl-wt-enable; + qcom,soc-scale-mode-en; + /* ESR fast calibration */ + qcom,fg-esr-timer-chg-fast = <0 7>; + qcom,fg-esr-timer-dischg-fast = <0 7>; + qcom,fg-esr-timer-chg-slow = <0 96>; + qcom,fg-esr-timer-dischg-slow = <0 96>; + qcom,fg-esr-cal-soc-thresh = <26 230>; + qcom,fg-esr-cal-temp-thresh = <10 40>; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@4d { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4e { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + camera_flash_therm@4d { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_msm_therm@4e { + reg = ; + label = "skin_msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm2@4f { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM3_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + camera_flash_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_debug_bus { + status = "ok"; +}; + +&sde_dsi { + avdd-supply = <&display_panel_avdd>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,dsi-default-panel = <&dsi_dual_xrsmrtvwr_jdi_video>; +}; + +&display_panel_avdd { + display_panel_led1_gpio = <&tlmm 144 0>; + display_panel_led2_gpio = <&tlmm 140 0>; + enable-active-high; + regulator-boot-on; + pinctrl-names = "default"; + pinctrl-0 = <&display_panel_led1_default + &display_panel_led2_default>; +}; + +&dsi_panel_pwr_supply_lab_ibb { + qcom,panel-supply-entry@3 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&pm8150l_lcdb { + status = "ok"; +}; + +&pm8150l_wled { + status = "ok"; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_HIGH>; /* Morpheus has to be HIGH */ + + status = "ok"; +}; + +&vendor { + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + }; +}; + +&usb0 { + dwc3@a600000 { + maximum-speed = "super-speed-plus"; + }; +}; + +&usb1 { + qcom,default-mode-none; +}; + +&wil6210 { + status = "ok"; +}; + +&usb2_phy0 { + qcom,param-override-seq = + <0xc7 0x6c + 0x0f 0x70 + 0x03 0x74>; +}; + +&mdss_mdp { + qcom,sde-mixer-display-pref = "primary", "primary", "primary", + "primary", "none", "none"; +}; + +&dsi_dual_xrsmrtvwr_jdi_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 66 0>; + + qcom,platform-bklight-en-gpio = <&tlmm 133 0>; + qcom,5v-boost-gpio = <&tlmm 134 0>; + /delete-property/ qcom,platform-en-gpio; + + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-supported-dfps-list = <90 75 60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-min-refresh-rate = <60>; + qcom,mdss-dsi-max-refresh-rate = <90>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <2160>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <20>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <936>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 00 + 29 01 00 00 00 00 0A B6 30 6B 80 06 33 + 8A 00 1A 7A + 29 01 00 00 00 00 05 B7 54 00 00 00 + 29 01 00 00 00 00 05 B9 10 00 01 38 + 29 01 00 00 00 00 09 C0 51 86 64 00 08 + 70 07 00 + 29 01 00 00 00 00 02 F1 1E + 29 01 00 00 00 00 11 C6 70 08 D0 02 21 + 6F 08 5A 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CD 00 + 29 01 00 00 00 00 08 CF 8B 00 80 46 61 + 00 8B + 29 01 00 00 00 00 06 EC 02 96 00 00 00 + 39 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 05 01 00 00 02 00 02 29 00 + 05 01 00 00 80 00 02 11 00 + 29 01 00 00 00 00 02 D6 80 + 29 01 00 00 00 00 02 B0 03 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 32 00 02 34 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsi-panel-phy-timings = [00 17 05 05 20 1F + 06 06 03 02 04 00 13 15]; + qcom,display-topology = <4 4 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dts b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dts new file mode 100644 index 0000000000000000000000000000000000000000..ed5fde6e8c7ef807931bbaa055345c43ee9a4328 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "kona.dtsi" +#include "kona-xrfusion.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona XR 5G Fusion"; + compatible = "qcom,kona-mtp", "qcom,kona", "qcom,mtp"; + qcom,board-id = <0x20008 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bdddd4b533b3707a821ac7532c3aa405dc98a2b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona-xrfusion.dtsi @@ -0,0 +1,1091 @@ +#include +#include "kona-pmic-overlay.dtsi" +#include "kona-sde-display.dtsi" +#include "kona-audio-overlay.dtsi" +#include "kona-thermal-overlay.dtsi" +#include "kona-xr-pinctrl-overlay.dtsi" +#include "camera/kona-camera-sensor-xrfusion.dtsi" + +&tlmm { + display_panel_led1_default: display_panel_led1_default { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; + + display_panel_led2_default: display_panel_led2_default { + mux { + pins = "gpio140"; + function = "gpio"; + }; + + config { + pins = "gpio140"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; + + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio127"; + function = "gpio"; + }; + + config { + pins = "gpio127"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio129"; + function = "gpio"; + }; + + config { + pins = "gpio129"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + cam_sensor_6dof_vana_active: cam_sensor_6dof_vana_active { + /* AVDD LDO */ + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vana_suspend: cam_sensor_6dof_vana_suspend { + /* AVDD LDO */ + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vdig_active: cam_sensor_6dof_vdig_active { + /* VDIG LDO */ + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vdig_suspend: cam_sensor_6dof_vdig_suspend { + /* VDIG LDO */ + mux { + pins = "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio42"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vio_active: cam_sensor_6dof_vio_active { + /* VIO LDO */ + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_6dof_vio_suspend: cam_sensor_6dof_vio_suspend { + /* VIO LDO */ + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&vendor { + kona_xrfusion_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen4-batterydata-goertek-6100mah.dtsi" + }; +}; + +&qupv3_se12_2uart { + status = "okay"; +}; + +&pm8150a_amoled { + status = "disabled"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&dai_mi2s2 { + status = "disabled"; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&tert_mi2s_sck_active &tert_mi2s_ws_active + &tert_mi2s_sd0_active>; + pinctrl-1 = <&tert_mi2s_sck_sleep &tert_mi2s_ws_sleep + &tert_mi2s_sd0_sleep>; +}; + +&kona_snd { + qcom,model = "kona-xrfusion-snd-card"; + qcom,mi2s-audio-intf = <0>; + qcom,audio-routing = + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "TX DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "TX DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "TX DMIC2", "MIC BIAS4", + "MIC BIAS4", "Digital Mic2", + "TX DMIC3", "MIC BIAS4", + "MIC BIAS4", "Digital Mic3", + "TX DMIC5", "MIC BIAS3", + "MIC BIAS3", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&lpi_tlmm>, + <&bolero>; +}; + +&pm8150_l10 { + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <3304000>; +}; + +&qupv3_se1_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + xrfancontroller: xrfancontroller@50 { + compatible = "maxim,xrfancontroller"; + reg = <0x50>; + qcom,fan-pwr-en = <&tlmm 38 0x00>; + qcom,fan-pwr-bp = <&tlmm 39 0x00>; + }; +}; + +&qupv3_se13_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <89900>; + vdda-pll-max-microamp = <18800>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l17>; + vcc-voltage-level = <2504000 2950000>; + vcc-low-voltage-sup; + vccq-supply = <&pm8150_l6>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vccq-parent-supply = <&pm8150a_s8>; + qcom,vccq-parent-max-microamp = <210000>; + + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default + &key_confirm_default + &key_vol_up_default>; + + home { + label = "home"; + gpios = <&pm8150_gpios 1 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + confirm { + label = "confirm"; + gpios = <&pm8150_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qcom,qbt_handler { + status = "disabled"; + }; + + qcom,xr-stdalonevwr-misc { + compatible = "qcom,xr-stdalonevwr-misc"; + }; +}; + +&vreg_hap_boost { + status = "ok"; +}; + +&pm8150b_haptics { + qcom,vmax-mv = <1697>; + qcom,play-rate-us = <5882>; + vdd-supply = <&vreg_hap_boost>; + + wf_0 { + /* CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_1 { + /* DOUBLE CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_2 { + /* TICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_3 { + /* THUD */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_4 { + /* POP */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; + + wf_5 { + /* HEAVY CLICK */ + qcom,wf-play-rate-us = <5882>; + qcom,wf-vmax-mv = <1697>; + }; +}; + +&pm8150b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&qupv3_se15_i2c { + #address-cells = <1>; + #size-cells = <0>; + status = "ok"; + redriver: redriver@1c { + compatible = "onnn,redriver"; + reg = <0x1c>; + extcon = <&pm8150b_pdphy>, <&pm8150b_pdphy>; + eq = /bits/ 8 < + /* Parameters for USB */ + 0x4 0x4 0x4 0x4 + /* Parameters for DP */ + 0x6 0x4 0x4 0x6>; + flat-gain = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x1 0x1 0x3 + /* Parameters for DP */ + 0x2 0x1 0x1 0x2>; + output-comp = /bits/ 8 < + /* Parameters for USB */ + 0x3 0x3 0x3 0x3 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + loss-match = /bits/ 8 < + /* Parameters for USB */ + 0x1 0x3 0x3 0x1 + /* Parameters for DP */ + 0x3 0x3 0x3 0x3>; + }; + + #include "smb1390.dtsi" +}; + +&smb1390 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + qcom,parallel-output-mode = <2>; + status = "ok"; +}; + +&smb1390_slave { + status = "ok"; +}; + +&smb1390_slave_charger { + status = "ok"; +}; + +&pm8150b_charger { + status = "ok"; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "mid_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp"; + qcom,battery-data = <&kona_xrfusion_batterydata>; + qcom,sw-jeita-enable; + qcom,wd-bark-time-secs = <16>; + qcom,suspend-input-on-debug-batt; + qcom,thermal-mitigation = <5325000 4500000 4000000 3500000 3000000 + 2500000 2000000 1500000 1000000 500000>; +}; + +&pm8150b_fg { + status = "ok"; + qcom,battery-data = <&kona_xrfusion_batterydata>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,five-pin-battery; + qcom,cl-wt-enable; + qcom,soc-scale-mode-en; + /* ESR fast calibration */ + qcom,fg-esr-timer-chg-fast = <0 7>; + qcom,fg-esr-timer-dischg-fast = <0 7>; + qcom,fg-esr-timer-chg-slow = <0 96>; + qcom,fg-esr-timer-dischg-slow = <0 96>; + qcom,fg-esr-cal-soc-thresh = <26 230>; + qcom,fg-esr-cal-temp-thresh = <10 40>; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@4d { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4e { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + camera_flash_therm@4d { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_msm_therm@4e { + reg = ; + label = "skin_msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm2@4f { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150b_vadc ADC_AMUX_THM3_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + + camera_flash_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_msm_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm2@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_debug_bus { + status = "ok"; +}; + +&sde_dsi { + avdd-supply = <&display_panel_avdd>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,dsi-default-panel = <&dsi_dual_xrsmrtvwr_jdi_video>; +}; + +&display_panel_avdd { + display_panel_led1_gpio = <&tlmm 144 0>; + display_panel_led2_gpio = <&tlmm 140 0>; + enable-active-high; + regulator-boot-on; + pinctrl-names = "default"; + pinctrl-0 = <&display_panel_led1_default + &display_panel_led2_default>; +}; + +&dsi_panel_pwr_supply_lab_ibb { + qcom,panel-supply-entry@3 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; +}; + +&pm8150l_lcdb { + status = "ok"; +}; + +&pm8150l_wled { + status = "ok"; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 66 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,mdss-dsi-panel-test-pin = <&tlmm 46 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_sim_dsc_10b_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&tlmm 75 0>; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + skin-msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &storage_cd>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &storage_cd>; + + cd-gpios = <&tlmm 77 GPIO_ACTIVE_HIGH>; /* Morpheus has to be HIGH */ + + status = "ok"; +}; + +&vendor { + bluetooth: bt_qca6390 { + compatible = "qca,qca6390"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_sleep>; + qca,bt-reset-gpio = <&tlmm 21 0>; /* BT_EN */ + qca,bt-vdd-aon-supply = <&pm8150_s6>; + qca,bt-vdd-dig-supply = <&pm8009_s2>; + qca,bt-vdd-rfa1-supply = <&pm8150_s5>; + qca,bt-vdd-rfa2-supply = <&pm8150a_s8>; + qca,bt-vdd-asd-supply = <&pm8150_l16>; + + qca,bt-vdd-aon-voltage-level = <950000 950000>; + qca,bt-vdd-dig-voltage-level = <950000 952000>; + qca,bt-vdd-rfa1-voltage-level = <1900000 1900000>; + qca,bt-vdd-rfa2-voltage-level = <1350000 1350000>; + qca,bt-vdd-asd-voltage-level = <3024000 3304000>; + + qca,bt-vdd-asd-current-level = <10000>; + }; +}; + +&usb0 { + dwc3@a600000 { + maximum-speed = "super-speed-plus"; + }; +}; + +&usb1 { + qcom,default-mode-none; +}; + +&wil6210 { + status = "ok"; +}; + +&usb2_phy0 { + qcom,param-override-seq = + <0xc7 0x6c + 0x0f 0x70 + 0x03 0x74>; +}; + +&mdss_mdp { + qcom,sde-mixer-display-pref = "primary", "primary", "primary", + "primary", "none", "none"; +}; + +&dsi_dual_xrsmrtvwr_jdi_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_lab_ibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + qcom,platform-te-gpio = <&tlmm 66 0>; + + qcom,platform-bklight-en-gpio = <&tlmm 133 0>; + qcom,5v-boost-gpio = <&tlmm 134 0>; + /delete-property/ qcom,platform-en-gpio; + + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-min-refresh-rate = <60>; + qcom,mdss-dsi-max-refresh-rate = <90>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <2160>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <20>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <20>; + qcom,mdss-dsi-v-front-porch = <936>; + qcom,mdss-dsi-v-pulse-width = <4>; + qcom,mdss-dsi-panel-framerate = <90>; + qcom,mdss-dsi-on-command = [ + 29 01 00 00 00 00 02 B0 04 + 29 01 00 00 00 00 02 D6 00 + 29 01 00 00 00 00 0A B6 30 6B 80 06 33 + 8A 00 1A 7A + 29 01 00 00 00 00 05 B7 54 00 00 00 + 29 01 00 00 00 00 05 B9 10 00 01 38 + 29 01 00 00 00 00 09 C0 51 86 64 00 08 + 70 07 00 + 29 01 00 00 00 00 02 F1 1E + 29 01 00 00 00 00 11 C6 70 08 D0 02 21 + 6F 08 5A 00 00 00 00 00 00 00 00 + 29 01 00 00 00 00 02 CD 00 + 29 01 00 00 00 00 08 CF 8B 00 80 46 61 + 00 8B + 29 01 00 00 00 00 06 EC 02 96 00 00 00 + 39 01 00 00 00 00 02 03 01 + 39 01 00 00 00 00 03 44 00 00 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 36 00 + 39 01 00 00 00 00 02 3A 77 + 05 01 00 00 02 00 02 29 00 + 05 01 00 00 80 00 02 11 00 + 29 01 00 00 00 00 02 D6 80 + 29 01 00 00 00 00 02 B0 03 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 32 00 02 34 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsi-panel-phy-timings = [00 17 05 05 20 1F + 06 06 03 02 04 00 13 15]; + qcom,display-topology = <4 4 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona.dts b/arch/arm64/boot/dts/vendor/qcom/kona.dts new file mode 100644 index 0000000000000000000000000000000000000000..5fbda62473fd8e753548090eb8ff28385ec159b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "kona.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. kona v1 SoC"; + compatible = "qcom,kona"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/kona.dtsi b/arch/arm64/boot/dts/vendor/qcom/kona.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..06c2c496466dcfc9f1ba3862b6438c739b96f7c9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/kona.dtsi @@ -0,0 +1,5042 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + +#define BW_OPP_ENTRY_DDR(mhz, w, ddrtype) opp-mhz {\ + opp-hz = /bits/ 64 ;\ + opp-supported-hw = ;} + +#define DDR_TYPE_LPDDR4X 7 +#define DDR_TYPE_LPDDR5 8 + +/ { + model = "Qualcomm Technologies, Inc. kona"; + compatible = "qcom,kona"; + qcom,msm-id = <356 0x10000>; + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + memory { device_type = "memory"; reg = <0 0 0 0>; }; + + mem-offline { + compatible = "qcom,mem-offline"; + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>, + <0x2 0xc0000000 0x1 0x40000000>; + granule = <512>; + mboxes = <&qmp_aop 0>; + }; + + aliases { + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + sdhc2 = &sdhc_2; /* SDC2 SD card slot */ + pci-domain0 = &pcie0; /* PCIe0 domain */ + pci-domain1 = &pcie1; /* PCIe1 domain */ + pci-domain2 = &pcie2; /* PCIe2 domain */ + serial0 = &qupv3_se2_2uart; /* RUMI */ + swr0 = &swr0; + swr1 = &swr1; + swr2 = &swr2; + mhi-netdev0 = &mhi_netdev_0; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x0>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + + L3_0: l3-cache { + compatible = "arm,arch-cache"; + cache-level = <3>; + }; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x100>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_1>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + L2_1: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x200>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_2>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + L2_2: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_200: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_200: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x300>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_3>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + L2_3: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_300: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_300: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x400>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_4>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <514>; + #cooling-cells = <2>; + L2_4: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_400: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_400: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x500>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_5>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <514>; + L2_5: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_500: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_500: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x600>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_6>; + qcom,freq-domain = <&cpufreq_hw 1 4>; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <514>; + L2_6: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_600: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_600: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "qcom,kryo"; + reg = <0x0 0x700>; + enable-method = "psci"; + cpu-release-addr = <0x0 0x90000000>; + next-level-cache = <&L2_7>; + qcom,freq-domain = <&cpufreq_hw 2 4>; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <598>; + #cooling-cells = <2>; + L2_7: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_700: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_700: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU7>; + }; + }; + }; + }; + + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = ; + }; + + soc: soc { + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw-epss"; + reg = <0x18591000 0x1000>, <0x18592000 0x1000>, + <0x18593000 0x1000>; + reg-names = "freq-domain0", "freq-domain1", + "freq-domain2"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GPLL0>; + clock-names = "xo", "alternate"; + + qcom,lut-row-size = <4>; + qcom,skip-enable-check; + + #freq-domain-cells = <2>; + + cpu7_notify: cpu7-notify { + qcom,cooling-cpu = <&CPU7>; + #cooling-cells = <2>; + }; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_mem: hyp_region@80000000 { + no-map; + reg = <0x0 0x80000000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_region@80700000 { + no-map; + reg = <0x0 0x80700000 0x0 0x160000>; + }; + + cmd_db: reserved-memory@80860000 { + reg = <0x0 0x80860000 0x0 0x20000>; + compatible = "qcom,cmd-db"; + no-map; + }; + + smem_mem: smem_region@80900000 { + no-map; + reg = <0x0 0x80900000 0x0 0x200000>; + }; + + removed_mem: removed_region@80b00000 { + no-map; + reg = <0x0 0x80b00000 0x0 0x5300000>; + }; + + pil_camera_mem: pil_camera_region@86200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86200000 0x0 0x500000>; + }; + + pil_wlan_fw_mem: pil_wlan_fw_region@86700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86700000 0x0 0x100000>; + }; + + pil_ipa_fw_mem: pil_ipa_fw_region@86800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86800000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: pil_ipa_gsi_region@86810000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86810000 0x0 0xa000>; + }; + + pil_gpu_mem: pil_gpu_region@8681a000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8681a000 0x0 0x2000>; + }; + + pil_npu_mem: pil_npu_region@86900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86900000 0x0 0x500000>; + }; + + pil_video_mem: pil_video_region@86e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86e00000 0x0 0x500000>; + }; + + pil_cvp_mem: pil_cvp_region@87300000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x87300000 0x0 0x500000>; + }; + + pil_cdsp_mem: pil_cdsp_region@87800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x87800000 0x0 0x1400000>; + }; + + pil_slpi_mem: pil_slpi_region@88c00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x88c00000 0x0 0x1500000>; + }; + + pil_adsp_mem: pil_adsp_region@8a100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8a100000 0x0 0x1d00000>; + }; + + pil_spss_mem: pil_spss_region@8be00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8be00000 0x0 0x100000>; + }; + + cdsp_secure_heap: cdsp_secure_heap@8bf00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8bf00000 0x0 0x4600000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0xC00000>; + }; + + sdsp_mem: sdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x800000>; + }; + + cdsp_mem: cdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + cont_splash_memory: cont_splash_region@9c000000 { + reg = <0x0 0x9c000000 0x0 0x02300000>; + label = "cont_splash_region"; + }; + + disp_rdump_memory: disp_rdump_region@9c000000 { + reg = <0x0 0x9c000000 0x0 0x00800000>; + label = "disp_rdump_region"; + }; + + dfps_data_memory: dfps_data_region@9e300000 { + reg = <0x0 0x9e300000 0x0 0x0100000>; + label = "dfps_data_region"; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + size = <0 0x2800000>; + }; + sp_mem: sp_region { /* SPSS-HLOS ION shared mem */ + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + user_contig_mem: user_contig_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + secure_display_memory: secure_display_region { /* Secure UI */ + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0xA400000>; + }; + + cnss_wlan_mem: cnss_wlan_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x2000000>; + linux,cma-default; + }; + + mailbox_mem: mailbox_region { + compatible = "shared-dma-pool"; + no-map; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + alignment = <0x0 0x400000>; + size = <0x0 0x20000>; + }; + }; + + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + thermal_zones: thermal-zones { + }; + + slim_aud: slim@3ac0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x3ac0000 0x2c000>, + <0x3a84000 0x2c000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = , + ; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x700000>; + qcom,ea-pc = <0x2d0>; + iommus = <&apps_smmu 0x1826 0x0>, + <&apps_smmu 0x182f 0x0>, + <&apps_smmu 0x1830 0x1>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "atomic"; + status = "ok"; + + /* Slimbus Slave DT for QCA6390 */ + btfmslim_codec: qca6390 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = ; + }; + + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x18000058 0x18010058 + 0x18020058 0x18030058>; + qcom,config-arr = <0x18000060 0x18010060 + 0x18020060 0x18030060>; + }; + + dsu_pmu@0 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&CPU0>, <&CPU1>, <&CPU2>, <&CPU3>, + <&CPU4>, <&CPU5>, <&CPU6>, <&CPU7>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x18040058 0x18050058 + 0x18060058 0x18070058>; + qcom,config-arr = <0x18040060 0x18050060 + 0x18060060 0x18070060>; + }; + + cache-controller@9200000 { + compatible = "qcom,llcc-v2"; + reg = <0x9200000 0x1d0000> , <0x9600000 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + cap-based-alloc-and-pwr-collapse; + }; + + wdog: qcom,wdt@17c10000 { + compatible = "qcom,msm-watchdog"; + reg = <0x17c10000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>, + <0 1 IRQ_TYPE_LEVEL_HIGH>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,wakeup-enable; + qcom,ipi-ping; + }; + + arch_timer: timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + clock-frequency = <19200000>; + }; + + memtimer: timer@17c20000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c20000 0x1000>; + clock-frequency = <19200000>; + + frame@17c21000 { + frame-number = <0>; + interrupts = , + ; + reg = <0x17c21000 0x1000>, + <0x17c22000 0x1000>; + }; + + frame@17c23000 { + frame-number = <1>; + interrupts = ; + reg = <0x17c23000 0x1000>; + status = "disabled"; + }; + + frame@17c25000 { + frame-number = <2>; + interrupts = ; + reg = <0x17c25000 0x1000>; + status = "disabled"; + }; + + frame@17c27000 { + frame-number = <3>; + interrupts = ; + reg = <0x17c27000 0x1000>; + status = "disabled"; + }; + + frame@17c29000 { + frame-number = <4>; + interrupts = ; + reg = <0x17c29000 0x1000>; + status = "disabled"; + }; + + frame@17c2b000 { + frame-number = <5>; + interrupts = ; + reg = <0x17c2b000 0x1000>; + status = "disabled"; + }; + + frame@17c2d000 { + frame-number = <6>; + interrupts = ; + reg = <0x17c2d000 0x1000>; + status = "disabled"; + }; + }; + + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + + qcom,devfreq-l3 { + compatible = "qcom,devfreq-fw"; + reg = <0x18590000 0x4>, <0x18590100 0xa0>, <0x18590320 0x4>; + reg-names = "en-base", "ftbl-base", "perf-base"; + + cpu0_l3: qcom,cpu0-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cpu4_l3: qcom,cpu4-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cpu7_l3: qcom,cpu7-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cdsp_l3: qcom,cdsp-cdsp-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + }; + + bus_proxy_client: qcom,bus_proxy_client { + compatible = "qcom,bus-proxy-client"; + qcom,msm-bus,name = "bus-proxy-client"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 1500000 1500000>, <23 512 1500000 1500000>; + qcom,msm-bus,active-only; + status = "ok"; + }; + + keepalive_opp_table: keepalive-opp-table { + compatible = "operating-points-v2"; + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = ; + qcom,active-only; + status = "ok"; + operating-points-v2 = <&keepalive_opp_table>; + }; + + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + BW_OPP_ENTRY( 1000, 16); /* 15258 MB/s */ + }; + + suspendable_llcc_bw_opp_table: suspendable-llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 16); /* 0 MB/s */ + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + BW_OPP_ENTRY( 1000, 16); /* 15258 MB/s */ + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY_DDR( 200, 4, 0x180); /* 762 MB/s */ + BW_OPP_ENTRY_DDR( 300, 4, 0x180); /* 1144 MB/s */ + BW_OPP_ENTRY_DDR( 451, 4, 0x180); /* 1720 MB/s */ + BW_OPP_ENTRY_DDR( 547, 4, 0x180); /* 2086 MB/s */ + BW_OPP_ENTRY_DDR( 681, 4, 0x180); /* 2597 MB/s */ + BW_OPP_ENTRY_DDR( 768, 4, 0x180); /* 2929 MB/s */ + BW_OPP_ENTRY_DDR( 1017, 4, 0x180); /* 3879 MB/s */ + BW_OPP_ENTRY_DDR( 1353, 4, 0x80); /* 5161 MB/s */ + BW_OPP_ENTRY_DDR( 1555, 4, 0x180); /* 5931 MB/s */ + BW_OPP_ENTRY_DDR( 1804, 4, 0x180); /* 6881 MB/s */ + BW_OPP_ENTRY_DDR( 2092, 4, 0x180); /* 7980 MB/s */ + BW_OPP_ENTRY_DDR( 2736, 4, 0x100); /* 10437 MB/s */ + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY_DDR( 0, 4, 0x180); /* 0 MB/s */ + BW_OPP_ENTRY_DDR( 200, 4, 0x180); /* 762 MB/s */ + BW_OPP_ENTRY_DDR( 300, 4, 0x180); /* 1144 MB/s */ + BW_OPP_ENTRY_DDR( 451, 4, 0x180); /* 1720 MB/s */ + BW_OPP_ENTRY_DDR( 547, 4, 0x180); /* 2086 MB/s */ + BW_OPP_ENTRY_DDR( 681, 4, 0x180); /* 2597 MB/s */ + BW_OPP_ENTRY_DDR( 768, 4, 0x180); /* 2929 MB/s */ + BW_OPP_ENTRY_DDR( 1017, 4, 0x180); /* 3879 MB/s */ + BW_OPP_ENTRY_DDR( 1353, 4, 0x80); /* 5161 MB/s */ + BW_OPP_ENTRY_DDR( 1555, 4, 0x180); /* 5931 MB/s */ + BW_OPP_ENTRY_DDR( 1804, 4, 0x180); /* 6881 MB/s */ + BW_OPP_ENTRY_DDR( 2092, 4, 0x180); /* 7980 MB/s */ + BW_OPP_ENTRY_DDR( 2736, 4, 0x100); /* 10437 MB/s */ + }; + + llcc_pmu: llcc-pmu@9095000 { + compatible = "qcom,llcc-pmu-ver2"; + reg = <0x09095000 0x300>; + reg-names = "lagg-base"; + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x90b6400 0x300>, <0x90b6300 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@9091000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x9091000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + npu_npu_llcc_bw: qcom,npu-npu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_llcc_bw_opp_table>; + }; + + npu_npu_llcc_bwmon: qcom,npu-npu-llcc-bwmon@60300 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x00060400 0x300>, <0x00060300 0x200>; + reg-names = "base", "global_base"; + qcom,msm_bus = <154 10070>; + qcom,msm_bus_name = "npu_bwmon_cdsp"; + clocks = <&clock_gcc GCC_NPU_BWMON_CFG_AHB_CLK>, + <&clock_gcc GCC_NPU_BWMON_AXI_CLK>; + clock-names = "npu_bwmon_ahb", "npu_bwmon_axi"; + qcom,bwmon_clks = "npu_bwmon_ahb", "npu_bwmon_axi"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_npu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + npu_llcc_ddr_bw: qcom,npu-llcc-ddr-bw { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npu_llcc_ddr_bwmon: qcom,npu-llcc-ddr-bwmon@0x9093000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x9093000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + npudsp_npu_ddr_bw: qcom,npudsp-npu-ddr-bw { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npudsp_npu_ddr_bwmon: qcom,npudsp-npu-ddr-bwmon@70200 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x00070300 0x300>, <0x00070200 0x200>; + reg-names = "base", "global_base"; + qcom,msm_bus = <154 10070>; + qcom,msm_bus_name = "npudsp_bwmon_cdsp"; + clocks = <&clock_gcc GCC_NPU_BWMON_CFG_AHB_CLK>, + <&clock_gcc GCC_NPU_BWMON_AXI_CLK>; + clock-names = "npu_bwmon_ahb", "npu_bwmon_axi"; + qcom,bwmon_clks = "npu_bwmon_ahb", "npu_bwmon_axi"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npudsp_npu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + npu_npu_ddr_latfloor: qcom,npu-npu-ddr-latfloor { + compatible = "qcom,devbw-ddr"; + governor = "powersave"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npu_staticmap_mon: qcom,npu-staticmap-mon { + compatible = "qcom,static-map"; + qcom,target-dev = <&npu_npu_ddr_latfloor>; + clocks = <&clock_npucc NPU_CC_CAL_HM0_CLK>; + clock-names = "cal_hm0_clk"; + qcom,dev_clk = "cal_hm0_clk"; + qcom,core-dev-table = + < 0 MHZ_TO_MBPS( 0, 4) >, + < 300000 MHZ_TO_MBPS( 451, 4) >, + < 406000 MHZ_TO_MBPS( 768, 4) >, + < 533000 MHZ_TO_MBPS( 1555, 4) >, + < 730000 MHZ_TO_MBPS( 1804, 4) >, + < 920000 MHZ_TO_MBPS( 2092, 4) >, + < 1000000 MHZ_TO_MBPS( 2736, 4) >; + }; + + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu4_cpu_llcc_lat: qcom,cpu4-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu4_llcc_ddr_lat: qcom,cpu4-llcc-ddr-lat { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu4_cpu_ddr_latfloor: qcom,cpu4-cpu-ddr-latfloor { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + qoslat_opp_table: qoslat-opp-table { + compatible = "operating-points-v2"; + opp-0 { + opp-hz = /bits/ 64 < 1 >; + }; + + opp-1 { + opp-hz = /bits/ 64 < 2 >; + }; + }; + + cpu4_cpu_ddr_qoslat: qcom,cpu4-cpu-ddr-qoslat { + compatible = "qcom,devfreq-qoslat"; + governor = "powersave"; + operating-points-v2 = <&qoslat_opp_table>; + mboxes = <&qmp_aop 0>; + }; + + cpu0_memlat_cpugrp: qcom,cpu0-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + + cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,target-dev = <&cpu0_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 403200 403200000 >, + < 518400 518400000 >, + < 633600 614400000 >, + < 825600 729600000 >, + < 921600 825600000 >, + < 1036800 921600000 >, + < 1132800 1036800000 >, + < 1228800 1132800000 >, + < 1401600 1228800000 >, + < 1497600 1305600000 >, + < 1670400 1382400000 >; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 150, 16) >, + < 729600 MHZ_TO_MBPS( 300, 16) >, + < 1497600 MHZ_TO_MBPS( 466, 16) >, + < 1670400 MHZ_TO_MBPS( 600, 16) >; + }; + + cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x2A>; + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 729600 MHZ_TO_MBPS( 451, 4) >, + < 1132800 MHZ_TO_MBPS( 547, 4) >, + < 1497600 MHZ_TO_MBPS( 768, 4) >, + < 1670400 MHZ_TO_MBPS( 1017, 4) >; + }; + + ddr5-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 729600 MHZ_TO_MBPS( 451, 4) >, + < 1132800 MHZ_TO_MBPS( 547, 4) >, + < 1497600 MHZ_TO_MBPS( 768, 4) >, + < 1670400 MHZ_TO_MBPS( 1017, 4) >; + }; + }; + + }; + + cpu4_memlat_cpugrp: qcom,cpu4-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + + cpu4_cpu_l3_latmon: qcom,cpu4-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6>; + qcom,target-dev = <&cpu4_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 806400 614400000 >, + < 1017600 729600000 >, + < 1228800 921600000 >, + < 1689600 1228800000 >, + < 1804800 1305600000 >, + < 2227200 1382400000 >; + }; + + cpu7_cpu_l3_latmon: qcom,cpu7-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU7>; + qcom,target-dev = <&cpu7_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 806400 614400000 >, + < 1017600 729600000 >, + < 1228800 921600000 >, + < 1689600 1228800000 >, + < 1804800 1305600000 >, + < 2227200 1382400000 >; + }; + + cpu4_cpu_llcc_latmon: qcom,cpu4-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,target-dev = <&cpu4_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 150, 16) >, + < 691200 MHZ_TO_MBPS( 300, 16) >, + < 1017600 MHZ_TO_MBPS( 466, 16) >, + < 1228800 MHZ_TO_MBPS( 600, 16) >, + < 1804800 MHZ_TO_MBPS( 806, 16) >, + < 2227200 MHZ_TO_MBPS( 933, 16) >, + < 2476800 MHZ_TO_MBPS( 1000, 16) >; + }; + + cpu4_llcc_ddr_latmon: qcom,cpu4-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x2A>; + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 691200 MHZ_TO_MBPS( 451, 4) >, + < 806400 MHZ_TO_MBPS( 547, 4) >, + < 1017600 MHZ_TO_MBPS( 768, 4) >, + < 1228800 MHZ_TO_MBPS(1017, 4) >, + < 1574400 MHZ_TO_MBPS(1353, 4) >, + < 1804800 MHZ_TO_MBPS(1555, 4) >, + < 2227200 MHZ_TO_MBPS(1804, 4) >, + < 2380800 MHZ_TO_MBPS(2092, 4) >; + }; + + ddr5-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 691200 MHZ_TO_MBPS( 451, 4) >, + < 806400 MHZ_TO_MBPS( 547, 4) >, + < 1017600 MHZ_TO_MBPS( 768, 4) >, + < 1228800 MHZ_TO_MBPS(1017, 4) >, + < 1804800 MHZ_TO_MBPS(1555, 4) >, + < 2227200 MHZ_TO_MBPS(1804, 4) >, + < 2380800 MHZ_TO_MBPS(2092, 4) >, + < 2476800 MHZ_TO_MBPS(2736, 4) >; + }; + }; + + cpu4_computemon: qcom,cpu4-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,target-dev = <&cpu4_cpu_ddr_latfloor>; + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 1804800 MHZ_TO_MBPS( 200, 4) >, + < 2380800 MHZ_TO_MBPS(1017, 4) >, + < 2500000 MHZ_TO_MBPS(2092, 4) >; + }; + + ddr5-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 1804800 MHZ_TO_MBPS( 200, 4) >, + < 2380800 MHZ_TO_MBPS(1017, 4) >, + < 2500000 MHZ_TO_MBPS(2736, 4) >; + }; + }; + + cpu4_qoslatmon: qcom,cpu4-qoslatmon { + compatible = "qcom,arm-memlat-mon"; + qcom,target-dev = <&cpu4_cpu_ddr_qoslat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 1 >, + < 3000000 2 >; + }; + }; + + keepalive_opp_table: keepalive-opp-table { + compatible = "operating-points-v2"; + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 627>; + qcom,active-only; + status = "ok"; + operating-points-v2 = <&keepalive_opp_table>; + }; + + qcom,msm-imem@146bf000 { + compatible = "qcom,msm-imem"; + reg = <0x146bf000 0x1000>; + ranges = <0x0 0x146bf000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 0x8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 0x4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 0x20>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 0xc>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 0xc8>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 0xc8>; + }; + }; + + restart@c264000 { + compatible = "qcom,pshold"; + reg = <0xc264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + dcc: dcc_v2@1023000 { + compatible = "qcom,dcc-v2"; + reg = <0x1023000 0x1000>, + <0x103a000 0x6000>; + reg-names = "dcc-base", "dcc-ram-base"; + + dcc-ram-offset = <0x1a000>; + + link_list1 { + qcom,curr-link-list = <3>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + link_list2 { + qcom,curr-link-list = <6>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + link_list3 { + qcom,curr-link-list = <7>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + }; + + qcom_seecom: qseecom@82400000 { + compatible = "qcom,qseecom"; + reg = <0x82400000 0x3A00000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + qcom,appsbl-qseecom-support; + qcom,commonlib64-loaded-by-uefi; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 300000>; /* 75 MHz */ + clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + + mdm0: qcom,mdm0 { + compatible = "qcom,ext-sdx55m"; + cell-index = <0>; + #address-cells = <0>; + interrupt-parent = <&mdm0>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-names = + "err_fatal_irq", + "status_irq", + "mdm2ap_vddmin_irq"; + /* modem attributes */ + qcom,ramdump-delay-ms = <3000>; + qcom,ramdump-timeout-ms = <120000>; + qcom,vddmin-modes = "normal"; + qcom,vddmin-drive-strength = <8>; + qcom,sfr-query; + qcom,sysmon-id = <20>; + qcom,ssctl-instance-id = <0x10>; + qcom,support-shutdown; + qcom,pil-force-shutdown; + qcom,esoc-skip-restart-for-mdm-crash; + pinctrl-names = "mdm_active", "mdm_suspend"; + pinctrl-0 = <&ap2mdm_active &mdm2ap_active>; + pinctrl-1 = <&ap2mdm_sleep &mdm2ap_sleep>; + interrupt-map = <0 &tlmm 1 0x3 + 1 &tlmm 3 0x3>; + qcom,mdm2ap-errfatal-gpio = <&tlmm 1 0x00>; + qcom,ap2mdm-errfatal-gpio = <&tlmm 57 0x00>; + qcom,mdm2ap-status-gpio = <&tlmm 3 0x00>; + qcom,ap2mdm-status-gpio = <&tlmm 56 0x00>; + qcom,mdm-link-info = "0306_02.01.00"; + status = "ok"; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,kona-pdc"; + reg = <0xb220000 0x30000>, <0x17c000f0 0x60>; + qcom,pdc-ranges = <0 480 94>, <94 609 31>, <125 63 1>, <126 716 12>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <38400000>; + clock-output-names = "xo_board"; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + clock-output-names = "chip_sleep_clk"; + #clock-cells = <1>; + }; + }; + + clock_aop: qcom,aopclk { + compatible = "qcom,aop-qmp-clk"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + }; + + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-kona", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_npucc: qcom,npucc@9980000 { + compatible = "qcom,npucc-kona", "syscon"; + reg = <0x9980000 0x10000>, + <0x9800000 0x10000>, + <0x9810000 0x10000>; + reg-names = "cc", "qdsp6ss", "qdsp6ss_pll"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_videocc: qcom,videocc@abf0000 { + compatible = "qcom,videocc-kona", "syscon"; + reg = <0xabf0000 0x10000>; + reg-names = "cc_base"; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_camcc: qcom,camcc@ad00000 { + compatible = "qcom,camcc-kona", "syscon"; + reg = <0xad00000 0x10000>; + reg-names = "cc_base"; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_dispcc: qcom,dispcc@af00000 { + compatible = "qcom,kona-dispcc", "syscon"; + reg = <0xaf00000 0x20000>; + reg-names = "cc_base"; + vdd_mm-supply = <&VDD_MMCX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&clock_gcc GCC_DISP_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gpucc: qcom,gpucc@3d90000 { + compatible = "qcom,gpucc-kona", "syscon"; + reg = <0x3d90000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_cpucc: qcom,cpucc { + compatible = "qcom,dummycc"; + clock-output-names = "cpucc_clocks"; + #clock-cells = <1>; + }; + + clock_apsscc: syscon@182a0000 { + compatible = "syscon"; + reg = <0x182a0000 0x1c>; + }; + + clock_mccc: syscon@90ba000 { + compatible = "syscon"; + reg = <0x90ba000 0x54>; + }; + + clock_debugcc: qcom,cc-debug { + compatible = "qcom,kona-debugcc"; + qcom,gcc = <&clock_gcc>; + qcom,videocc = <&clock_videocc>; + qcom,dispcc = <&clock_dispcc>; + qcom,camcc = <&clock_camcc>; + qcom,gpucc = <&clock_gpucc>; + qcom,npucc = <&clock_npucc>; + qcom,apsscc = <&clock_apsscc>; + qcom,mccc = <&clock_mccc>; + clock-names = "xo_clk_src"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + #clock-cells = <1>; + }; + + /* GCC GDSCs */ + pcie_0_gdsc: qcom,gdsc@16b004 { + compatible = "qcom,gdsc"; + reg = <0x16b004 0x4>; + regulator-name = "pcie_0_gdsc"; + qcom,retain-regs; + }; + + pcie_1_gdsc: qcom,gdsc@18d004 { + compatible = "qcom,gdsc"; + reg = <0x18d004 0x4>; + regulator-name = "pcie_1_gdsc"; + qcom,retain-regs; + }; + + pcie_2_gdsc: qcom,gdsc@106004 { + compatible = "qcom,gdsc"; + reg = <0x106004 0x4>; + regulator-name = "pcie_2_gdsc"; + qcom,retain-regs; + }; + + ufs_phy_gdsc: qcom,gdsc@177004 { + compatible = "qcom,gdsc"; + reg = <0x177004 0x4>; + regulator-name = "ufs_phy_gdsc"; + qcom,retain-regs; + }; + + usb30_prim_gdsc: qcom,gdsc@10f004 { + compatible = "qcom,gdsc"; + reg = <0x10f004 0x4>; + regulator-name = "usb30_prim_gdsc"; + qcom,retain-regs; + }; + + usb30_sec_gdsc: qcom,gdsc@110004 { + compatible = "qcom,gdsc"; + reg = <0x110004 0x4>; + regulator-name = "usb30_sec_gdsc"; + qcom,retain-regs; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc: qcom,gdsc@17d050 { + compatible = "qcom,gdsc"; + reg = <0x17d050 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc: qcom,gdsc@17d058 { + compatible = "qcom,gdsc"; + reg = <0x17d058 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + }; + + hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc: qcom,gdsc@17d054 { + compatible = "qcom,gdsc"; + reg = <0x17d054 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + }; + + hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc: qcom,gdsc@17d06c { + compatible = "qcom,gdsc"; + reg = <0x17d06c 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + }; + + /* CAM_CC GDSCs */ + bps_gdsc: qcom,gdsc@ad07004 { + compatible = "qcom,gdsc"; + reg = <0xad07004 0x4>; + regulator-name = "bps_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "bps_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,support-hw-trigger; + qcom,retain-regs; + }; + + ife_0_gdsc: qcom,gdsc@ad0a004 { + compatible = "qcom,gdsc"; + reg = <0xad0a004 0x4>; + regulator-name = "ife_0_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ife_0_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,retain-regs; + }; + + ife_1_gdsc: qcom,gdsc@ad0b004 { + compatible = "qcom,gdsc"; + reg = <0xad0b004 0x4>; + regulator-name = "ife_1_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ife_1_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,retain-regs; + }; + + ipe_0_gdsc: qcom,gdsc@ad08004 { + compatible = "qcom,gdsc"; + reg = <0xad08004 0x4>; + regulator-name = "ipe_0_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "ipe_0_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,support-hw-trigger; + qcom,retain-regs; + }; + + sbi_gdsc: qcom,gdsc@ad09004 { + compatible = "qcom,gdsc"; + reg = <0xad09004 0x4>; + regulator-name = "sbi_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "sbi_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,retain-regs; + }; + + titan_top_gdsc: qcom,gdsc@ad0c144 { + compatible = "qcom,gdsc"; + reg = <0xad0c144 0x4>; + regulator-name = "titan_top_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "titan_top_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,retain-regs; + qcom,gds-timeout = <500>; + }; + + /* DISP_CC GDSC */ + mdss_core_gdsc: qcom,gdsc@af03000 { + compatible = "qcom,gdsc"; + reg = <0xaf03000 0x4>; + regulator-name = "mdss_core_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_DISP_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mdss_core_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,support-hw-trigger; + qcom,retain-regs; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + }; + + /* GPU_CC GDSCs */ + gpu_cx_hw_ctrl: syscon@3d91540 { + compatible = "syscon"; + reg = <0x3d91540 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@3d9106c { + compatible = "qcom,gdsc"; + reg = <0x3d9106c 0x4>; + regulator-name = "gpu_cx_gdsc"; + hw-ctrl-addr = <&gpu_cx_hw_ctrl>; + parent-supply = <&VDD_CX_LEVEL>; + vdd_parent-supply = <&VDD_CX_LEVEL>; + qcom,no-status-check-on-disable; + qcom,clk-dis-wait-val = <8>; + qcom,gds-timeout = <500>; + qcom,retain-regs; + }; + + gpu_gx_domain_addr: syscon@3d91508 { + compatible = "syscon"; + reg = <0x3d91508 0x4>; + }; + + gpu_gx_sw_reset: syscon@3d91008 { + compatible = "syscon"; + reg = <0x3d91008 0x4>; + }; + + gpu_gx_gdsc: qcom,gdsc@3d9100c { + compatible = "qcom,gdsc"; + reg = <0x3d9100c 0x4>; + regulator-name = "gpu_gx_gdsc"; + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; + parent-supply = <&VDD_GFX_LEVEL>; + vdd_parent-supply = <&VDD_GFX_LEVEL>; + qcom,skip-disable-before-sw-enable; + qcom,reset-aon-logic; + qcom,retain-regs; + }; + + /* NPU GDSC */ + npu_core_gdsc: qcom,gdsc@9981004 { + compatible = "qcom,gdsc"; + reg = <0x9981004 0x4>; + regulator-name = "npu_core_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_NPU_CFG_AHB_CLK>; + qcom,retain-regs; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + + /* VIDEO_CC GDSCs */ + mvs0_gdsc: qcom,gdsc@abf0d18 { + compatible = "qcom,gdsc"; + reg = <0xabf0d18 0x4>; + regulator-name = "mvs0_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvs0_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,support-hw-trigger; + qcom,retain-regs; + }; + + mvs0c_gdsc: qcom,gdsc@abf0bf8 { + compatible = "qcom,gdsc"; + reg = <0xabf0bf8 0x4>; + regulator-name = "mvs0c_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvs0c_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,retain-regs; + }; + + mvs1_gdsc: qcom,gdsc@abf0d98 { + compatible = "qcom,gdsc"; + reg = <0xabf0d98 0x4>; + regulator-name = "mvs1_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvs1_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,support-hw-trigger; + qcom,retain-regs; + }; + + mvs1c_gdsc: qcom,gdsc@abf0c98 { + compatible = "qcom,gdsc"; + reg = <0xabf0c98 0x4>; + regulator-name = "mvs1c_gdsc"; + clock-names = "ahb_clk"; + clocks = <&clock_gcc GCC_VIDEO_AHB_CLK>; + parent-supply = <&VDD_MMCX_LEVEL>; + vdd_parent-supply = <&VDD_MMCX_LEVEL>; + qcom,msm-bus,name = "mvs1c_gdsc_ahb"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,retain-regs; + }; + + spmi_bus: qcom,spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0x1100>, + <0xc600000 0x2000000>, + <0xe600000 0x100000>, + <0xe700000 0xa0000>, + <0xc40a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + spmi_debug_bus: qcom,spmi-debug@6b0f000 { + compatible = "qcom,spmi-pmic-arb-debug"; + reg = <0x6b0f000 0x60>, <0x7820a8 0x4>; + reg-names = "core", "fuse"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + qcom,fuse-disable-bit = <24>; + #address-cells = <2>; + #size-cells = <0>; + status = "disabled"; + + qcom,pm8150-debug@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8150-debug@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8150b-debug@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8150b-debug@3 { + compatible = "qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8150l-debug@4 { + compatible = "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8150l-debug@5 { + compatible = "qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pmk8002-debug@6 { + compatible = "qcom,spmi-pmic"; + reg = <0x6 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pmk8002-debug@7 { + compatible = "qcom,spmi-pmic"; + reg = <0x7 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pmxprairie-debug@8 { + compatible = "qcom,spmi-pmic"; + reg = <0x8 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pmxprairie-debug@9 { + compatible ="qcom,spmi-pmic"; + reg = <0x9 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8009-debug@a { + compatible = "qcom,spmi-pmic"; + reg = <0xa SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8009-debug@b { + compatible = "qcom,spmi-pmic"; + reg = <0xb SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + reg = <0x1d87000 0xe00>, <0x1d90000 0x8000>; /* PHY regs */ + reg-names = "phy_mem", "ufs_ice"; + #phy-cells = <0>; + + lanes-per-direction = <2>; + + clock-names = "ref_clk_src", + "ref_aux_clk"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_PHY_PHY_AUX_CLK>; + + status = "disabled"; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x3000>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; + interrupts = ; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + + lanes-per-direction = <2>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + clocks = + <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + freq-table-hz = + <37500000 300000000>, + <0 0>, + <0 0>, + <37500000 300000000>, + <37500000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <26>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G1 L2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G2 L2 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G3 L2 */ + <123 512 14752 0>, <1 757 1000 0>, /* PWM G4 L2 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G4 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G1 RA L2 */ + <123 512 511181 0>, <1 757 1000 0>, /* HS G2 RA L2 */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */ + <123 512 8388608 0>, <1 757 409600 0>, /* HS G4 RA L2 */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G4 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */ + <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */ + /* As UFS working in HS G3 RB L2 mode, aggregated + * bandwidth (AB) should take care of providing + * optimum throughput requested. However, as tested, + * in order to scale up CNOC clock, instantaneous + * bindwidth (IB) needs to be given a proper value too. + */ + <123 512 4194304 0>, <1 757 204800 409600>, /* HS G3 RB L2 */ + <123 512 8388608 0>, <1 757 409600 409600>, /* HS G4 RB L2 */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", "HS_RA_G4_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", "HS_RA_G4_L2", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", "HS_RB_G4_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", "HS_RB_G4_L2", + + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cpu-group-latency-us = <44 44>; + qcom,pm-qos-default-cpu = <0>; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&clock_gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + + status = "disabled"; + }; + + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 1600>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 80000>, + <1 608 80000 80000>, + /* 25 MB/s */ + <81 512 65360 100000>, + <1 608 100000 100000>, + /* 50 MB/s */ + <81 512 130718 200000>, + <1 608 133320 133320>, + /* 100 MB/s */ + <81 512 261438 200000>, + <1 608 150000 150000>, + /* 200 MB/s */ + <81 512 261438 400000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 4294967295>; + + qcom,restore-after-cx-collapse; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 201500000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 201500000>; + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <44 44>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <44 44>, <44 44>; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642C 0xA800 0x10 + 0x2C010800 0x80040868>; + + status = "disabled"; + }; + + ipcc_mproc: qcom,ipcc@408000 { + compatible = "qcom,ipcc"; + reg = <0x408000 0x1000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + }; + + apps_rsc: rsc@18200000 { + label = "apps_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0x18200000 0x10000>, + <0x18210000 0x10000>, + <0x18220000 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + + msm_bus_apps_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; + + system_pm { + compatible = "qcom,system-pm"; + }; + + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,kona-rpmh-clk"; + #clock-cells = <1>; + }; + }; + + disp_rsc: rsc@af20000 { + label = "disp_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0xaf20000 0x10000>; + reg-names = "drv-0"; + interrupts = ; + qcom,tcs-offset = <0x1c00>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + + msm_bus_disp_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; + + sde_rsc_rpmh { + compatible = "qcom,sde-rsc-rpmh"; + cell-index = <0>; + }; + }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; + }; + + kryo-erp { + compatible = "arm,arm64-kryo-cpu-erp"; + interrupts = , + ; + interrupt-names = "l1-l2-faultirq", + "l3-scu-faultirq"; + }; + + sp_scsr: mailbox@188501c { + compatible = "qcom,kona-spcs-global"; + reg = <0x188501c 0x4>; + + #mbox-cells = <1>; + }; + + sp_scsr_block: syscon@1880000 { + compatible = "syscon"; + reg = <0x1880000 0x10000>; + }; + + intsp: qcom,qsee_irq { + compatible = "qcom,kona-qsee-irq"; + + syscon = <&sp_scsr_block>; + interrupts = <0 348 IRQ_TYPE_LEVEL_HIGH>, + <0 349 IRQ_TYPE_LEVEL_HIGH>; + + interrupt-names = "sp_ipc0", + "sp_ipc1"; + + interrupt-controller; + #interrupt-cells = <3>; + }; + + qcom,qsee_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,dev-name = "qsee_ipc_irq_spss"; + label = "spss"; + interrupt-parent = <&intsp>; + interrupts = <1 0 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + spss_utils: qcom,spss_utils { + compatible = "qcom,spss-utils"; + /* spss fuses physical address */ + qcom,spss-fuse1-addr = <0x00780234>; + qcom,spss-fuse1-bit = <27>; + qcom,spss-fuse2-addr = <0x00780234>; + qcom,spss-fuse2-bit = <26>; + qcom,spss-fuse3-addr = <0x007801E8>; // IAR_FEATURE_ENABLED fuse + qcom,spss-fuse3-bit = <10>; + qcom,spss-fuse4-addr = <0x00780218>; // IAR_STATE fuse + qcom,spss-fuse4-bit = <1>; // 0x00780214 bits 33-35 + qcom,spss-dev-firmware-name = "spss1d"; /* 8 chars max */ + qcom,spss-test-firmware-name = "spss1t"; /* 8 chars max */ + qcom,spss-prod-firmware-name = "spss1p"; /* 8 chars max */ + qcom,spss-debug-reg-addr = <0x01886020>; + qcom,spss-emul-type-reg-addr = <0x01fc8004>; + pil-mem = <&pil_spss_mem>; + qcom,pil-addr = <0x8BE00000>; // backward compatible + qcom,pil-size = <0x0F0000>; // padding to 960 KB + status = "ok"; + }; + + qcom,spcom { + compatible = "qcom,spcom"; + + /* predefined channels, remote side is server */ + qcom,spcom-ch-names = "sp_kernel", "sp_ssr"; + /* rmb_err shared register physical address */ + qcom,spcom-rmb-err-reg-addr = <0x188103c>; + /* sp2soc rmb shared register physical address and bmsk */ + qcom,spcom-sp2soc-rmb-reg-addr = <0x01881020>; + qcom,spcom-sp2soc-rmb-initdone-bit = <24>; + qcom,spcom-sp2soc-rmb-pbldone-bit = <25>; + /* soc2sp rmb shared register physical address */ + qcom,spcom-soc2sp-rmb-reg-addr = <0x01881030>; + qcom,spcom-soc2sp-rmb-sp-ssr-bit = <0>; + status = "ok"; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_gsi_mem>; + }; + + qcom,ipa_uc { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0x1B>; + qcom,firmware-name = "ipa_uc"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; + }; + + qcom,ipa-mpm { + compatible = "qcom,ipa-mpm"; + qcom,mhi-chdb-base = <0x64300300>; + qcom,mhi-erdb-base = <0x64300700>; + qcom,iova-mapping = <0x10000000 0x0FFFFFFF>; + }; + + ipa_hw: qcom,ipa@1e00000 { + compatible = "qcom,ipa"; + mboxes = <&qmp_aop 0>; + reg = + <0x1e00000 0x84000>, + <0x1e04000 0x23000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = + <0 311 IRQ_TYPE_LEVEL_HIGH>, + <0 432 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <17>; /* IPA core version = IPAv4.5 */ + qcom,ipa-hw-mode = <0>; + qcom,platform-type = <2>; /* APQ platform */ + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,mhi-event-ring-id-limits = <9 11>; /* start and end */ + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi3-over-gsi; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,bandwidth-vote-for-ipa; + qcom,use-64-bit-dma-mask; + qcom,ipa-endp-delay-wa; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <5>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + , + , + , + , + , + + /* SVS2 */ + , + , + , + , + , + + /* SVS */ + , + , + , + , + , + + /* NOMINAL */ + , + , + , + , + , + + /* TURBO */ + , + , + , + , + ; + + qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", + "TURBO"; + qcom,throughput-threshold = <600 2500 5000>; + qcom,scaling-exceptions = "wdi", "0", "600", "1200", + "USB DPL", "0", "2500", "5000", "ODL", "0", + "2500", "5000"; + + qcom,entire-ipa-block-size = <0x100000>; + qcom,register-collection-on-crash; + qcom,testbus-collection-on-crash; + qcom,non-tn-collection-on-crash; + qcom,ram-collection-on-crash; + qcom,secure-debug-check-action = <0>; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x5C0 0x0>; + qcom,iommu-dma-addr-pool = <0x20000000 0x20000000>; + qcom,additional-mapping = + /* modem tables in IMEM */ + <0x146BD000 0x146BD000 0x2000>; + dma-coherent; + qcom,iommu-dma = "fastmap"; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x5C1 0x0>; + qcom,iommu-dma = "fastmap"; + dma-coherent; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x5C2 0x0>; + qcom,iommu-dma-addr-pool = <0x20000000 0x20000000>; + qcom,iommu-dma = "fastmap"; + }; + + ipa_smmu_11ad: ipa_smmu_11ad { + compatible = "qcom,ipa-smmu-11ad-cb"; + iommus = <&apps_smmu 0x5C3 0x0>; + dma-coherent; + qcom,shared-cb; + qcom,iommu-group = <&wil6210_pci_iommu_group>; + }; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_npu: npu { + qcom,remote-pid = <10>; + transport = "smem"; + mboxes = <&msm_npu IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "npu_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + + label = "npu"; + qcom,glink-label = "npu"; + + qcom,npu_qrtr { + qcom,net-id = <1>; + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,npu_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_cdsp>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "adsp_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,net-id = <2>; + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_slpi>, + <&glink_cdsp>; + }; + }; + + glink_slpi: dsps { + qcom,remote-pid = <3>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_SLPI + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "dsps_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + + label = "slpi"; + qcom,glink-label = "dsps"; + + qcom,slpi_qrtr { + qcom,net-id = <2>; + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,slpi_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "dsps_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,net-id = <1>; + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x20 12>; + + qcom,cdsp-cdsp-l3-gov { + compatible = "qcom,cdsp-l3"; + qcom,target-dev = <&cdsp_l3>; + }; + + msm_cdsp_rm: qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <44>; + qcom,qos-maxhold-ms = <20>; + qcom,compute-cx-limit-en; + qcom,compute-priority-mode = <2>; + #cooling-cells = <2>; + }; + + msm_hvx_rm: qcom,msm_hvx_rm { + compatible = "qcom,msm-hvx-rm"; + #cooling-cells = <2>; + }; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_slpi>, + <&glink_npu>; + }; + }; + + glink_spss: spss { + qcom,remote-pid = <8>; + transport = "spss"; + mboxes = <&sp_scsr 0>; + mbox-names = "spss_spss"; + interrupt-parent = <&intsp>; + interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>; + + reg = <0x1885008 0x8>, + <0x1885010 0x4>; + reg-names = "qcom,spss-addr", + "qcom,spss-size"; + + label = "spss"; + qcom,glink-label = "spss"; + }; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + mboxes = <&ipcc_mproc IPCC_CLIENT_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "aop_qmp"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + reg = <0xc300000 0x1000>; + reg-names = "msgram"; + + label = "aop"; + qcom,early-boot; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + + eud: qcom,msm-eud@ff0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupt-parent = <&pdc>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x088E0000 0x2000>, + <0x088E2000 0x1000>; + reg-names = "eud_base", "eud_mode_mgr2"; + qcom,secure-eud-en; + qcom,eud-clock-vote-req; + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_BCR>; + clock-names = "eud_ahb2phy_clk"; + status = "ok"; + }; + + qcom,lpass@17300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x17300000 0x00100>; + + vdd_cx-supply = <&L11A_LEVEL>; + qcom,vdd_cx-uV-uA = ; + vdd_mx-supply = <&L4A_LEVEL>; + qcom,vdd_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx","vdd_mx"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + + /* Inputs from lpass */ + interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; + }; + + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&pil_cdsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + + qcom,msm-bus,name = "pil-cdsp"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <154 10070 0 0>, + <154 10070 0 1>; + + /* Inputs from turing */ + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; + }; + + qcom,venus@aab0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xaab0000 0x2000>; + + vdd-supply = <&mvs0c_gdsc>; + qcom,proxy-reg-names = "vdd"; + qcom,complete-ramdump; + + clocks = <&clock_videocc VIDEO_CC_XO_CLK>, + <&clock_videocc VIDEO_CC_MVS0C_CLK>, + <&clock_videocc VIDEO_CC_AHB_CLK>; + clock-names = "xo", "core", "ahb"; + qcom,proxy-clock-names = "xo", "core", "ahb"; + + qcom,core-freq = <200000000>; + qcom,ahb-freq = <200000000>; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + }; + + /* PIL spss node - for loading Secure Processor */ + qcom,spss@1880000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x188101c 0x4>, + <0x1881024 0x4>, + <0x1881028 0x4>, + <0x188103c 0x4>, + <0x1882014 0x4>; + reg-names = "sp2soc_irq_status", "sp2soc_irq_clr", + "sp2soc_irq_mask", "rmb_err", "rmb_err_spare2"; + interrupts = <0 352 1>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_mx-uV = ; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + qcom,pil-generic-irq-handler; + status = "ok"; + + qcom,signal-aop; + qcom,complete-ramdump; + + qcom,pas-id = <14>; + qcom,proxy-timeout-ms = <10000>; + qcom,firmware-name = "spss"; + memory-region = <&pil_spss_mem>; + qcom,spss-scsr-bits = <24 25>; + /* use extra size for IAR memory */ + qcom,extra-size = <4096>; + + mboxes = <&qmp_aop 0>; + mbox-names = "spss-pil"; + }; + + qcom,cvpss@abb0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xabb0000 0x2000>; + status = "ok"; + qcom,pas-id = <26>; + qcom,firmware-name = "cvpss"; + + memory-region = <&pil_cvp_mem>; + }; + + qcom,npu@9800000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x9800000 0x800000>; + + status = "ok"; + qcom,pas-id = <23>; + qcom,firmware-name = "npu"; + memory-region = <&pil_npu_mem>; + + /* Outputs to npu */ + qcom,smem-states = <&npu_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + msm_fastrpc: qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + qcom,rpc-latency-us = <235>; + qcom,qos-cores = <0 1 2 3>; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1001 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1002 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1003 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1004 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1005 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1006 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1007 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1008 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1009 0x0460>; + qcom,iommu-dma-addr-pool = <0x60000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + qcom,iommu-vmid = <0xA>; /* VMID_CP_PIXEL */ + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1803 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1804 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1805 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb13 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x0541 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb14 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x0542 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb15 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "sdsprpc-smd"; + iommus = <&apps_smmu 0x0543 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + shared-cb = <4>; + dma-coherent; + }; + }; + + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0586 0x0011>, + <&apps_smmu 0x0596 0x0011>; + qcom,iommu-dma = "atomic"; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&apps_smmu 0x592 0>, + <&apps_smmu 0x598 0>, + <&apps_smmu 0x599 0>, + <&apps_smmu 0x59F 0>; + }; + + qcom_cedev_s_cb { + compatible = "qcom,qcedev,context-bank"; + label = "secure_context"; + iommus = <&apps_smmu 0x593 0>, + <&apps_smmu 0x59C 0>, + <&apps_smmu 0x59D 0>, + <&apps_smmu 0x59E 0>; + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ + qcom,secure-context-bank; + }; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <125 512 0 0>, + <125 512 393600 393600>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0584 0x0011>, + <&apps_smmu 0x0594 0x0011>; + qcom,iommu-dma = "atomic"; + }; + + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + c0_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x0>; + }; + + c100_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x1>; + }; + + c200_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x2>; + }; + + c300_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x3>; + }; + + c400_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x4>; + }; + + c500_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x5>; + }; + + c600_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x6>; + }; + + c700_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x7>; + }; + + c0_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x130>; + }; + + c100_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x131>; + }; + + c200_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x132>; + }; + + c300_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x133>; + }; + + c400_scandump { + qcom,dump-size = <0x1a4c0>; + qcom,dump-id = <0x134>; + }; + + c500_scandump { + qcom,dump-size = <0x1a4c0>; + qcom,dump-id = <0x135>; + }; + + c600_scandump { + qcom,dump-size = <0x1a4c0>; + qcom,dump-id = <0x136>; + }; + + c700_scandump { + qcom,dump-size = <0x1a4c0>; + qcom,dump-id = <0x137>; + }; + + cpuss_reg { + qcom,dump-size = <0x30000>; + qcom,dump-id = <0xef>; + }; + + l1_icache0 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x60>; + }; + + l1_icache100 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x61>; + }; + + l1_icache200 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x62>; + }; + + l1_icache300 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x63>; + }; + + l1_icache400 { + qcom,dump-size = <0x26000>; + qcom,dump-id = <0x64>; + }; + + l1_icache500 { + qcom,dump-size = <0x26000>; + qcom,dump-id = <0x65>; + }; + + l1_icache600 { + qcom,dump-size = <0x26000>; + qcom,dump-id = <0x66>; + }; + + l1_icache700 { + qcom,dump-size = <0x26000>; + qcom,dump-id = <0x67>; + }; + + l1_dcache0 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x80>; + }; + + l1_dcache100 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x81>; + }; + + l1_dcache200 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x82>; + }; + + l1_dcache300 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x83>; + }; + + l1_dcache400 { + qcom,dump-size = <0x1A000>; + qcom,dump-id = <0x84>; + }; + + l1_dcache500 { + qcom,dump-size = <0x1A000>; + qcom,dump-id = <0x85>; + }; + + l1_dcache600 { + qcom,dump-size = <0x1A000>; + qcom,dump-id = <0x86>; + }; + + l1_dcache700 { + qcom,dump-size = <0x1A000>; + qcom,dump-id = <0x87>; + }; + + l1_itlb400 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x24>; + }; + + l1_itlb500 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x25>; + }; + + l1_itlb600 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x26>; + }; + + l1_itlb700 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x27>; + }; + + l1_dtlb400 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x44>; + }; + + l1_dtlb500 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x45>; + }; + + l1_dtlb600 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x46>; + }; + + l1_dtlb700 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x47>; + }; + + l2_cache400 { + qcom,dump-size = <0x68000>; + qcom,dump-id = <0xc4>; + }; + + l2_cache500 { + qcom,dump-size = <0x68000>; + qcom,dump-id = <0xc5>; + }; + + l2_cache600 { + qcom,dump-size = <0x68000>; + qcom,dump-id = <0xc6>; + }; + + l2_cache700 { + qcom,dump-size = <0xD0000>; + qcom,dump-id = <0xc7>; + }; + + l2_tlb0 { + qcom,dump-size = <0x6000>; + qcom,dump-id = <0x120>; + }; + + l2_tlb100 { + qcom,dump-size = <0x6000>; + qcom,dump-id = <0x121>; + }; + + l2_tlb200 { + qcom,dump-size = <0x6000>; + qcom,dump-id = <0x122>; + }; + + l2_tlb300 { + qcom,dump-size = <0x6000>; + qcom,dump-id = <0x123>; + }; + + l2_tlb400 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x124>; + }; + + l2_tlb500 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x125>; + }; + + l2_tlb600 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x126>; + }; + + l2_tlb700 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x127>; + }; + + gemnoc { + qcom,dump-size = <0x100000>; + qcom,dump-id = <0x162>; + }; + + mhm_scan { + qcom,dump-size = <0x20000>; + qcom,dump-id = <0x161>; + }; + + rpmh { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x80000>; + qcom,dump-id = <0xe4>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + etf_swao { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf1>; + }; + + etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + etfswao_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + + etf_slpi { + qcom,dump-size = <0x4000>; + qcom,dump-id = <0xf3>; + }; + + etfslpi_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x103>; + }; + + etf_lpass { + qcom,dump-size = <0x4000>; + qcom,dump-id = <0xf4>; + }; + + etflpass_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x104>; + }; + }; + + qcom_tzlog: tz-log@146bf720 { + compatible = "qcom,tz-log"; + reg = <0x146bf720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom,ssc@5c00000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x5c00000 0x4000>; + + vdd_cx-supply = <&L11A_LEVEL>; + qcom,vdd_cx-uV-uA = ; + vdd_mx-supply = <&L4A_LEVEL>; + qcom,vdd_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx", "vdd_mx"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <12>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <424>; + qcom,sysmon-id = <3>; + qcom,ssctl-instance-id = <0x16>; + qcom,firmware-name = "slpi"; + status = "ok"; + memory-region = <&pil_slpi_mem>; + qcom,complete-ramdump; + qcom,signal-aop; + + /* Inputs from ssc */ + interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + <&dsps_smp2p_in 0 0>, + <&dsps_smp2p_in 2 0>, + <&dsps_smp2p_in 1 0>, + <&dsps_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to ssc */ + qcom,smem-states = <&dsps_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "slpi-pil"; + }; + + ssc_sensors: qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + status = "ok"; + qcom,firmware-name = "slpi"; + }; + + qcom_smcinvoke: smcinvoke@87900000 { + compatible = "qcom,smcinvoke"; + reg = <0x87900000 0x2200000>; + reg-names = "secapp-region"; + }; + + tsens0: tsens@c222000 { + compatible = "qcom,tsens24xx"; + reg = <0xc222000 0x4>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = , + ; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + tsens1: tsens@c223000 { + compatible = "qcom,tsens24xx"; + reg = <0xc223000 0x4>, + <0xc265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = , + ; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,mpm2-sleep-counter@c221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; + }; + + gpi_dma0: qcom,gpi-dma@900000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x900000 0x70000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <15>; + qcom,gpii-mask = <0x7ff>; + qcom,ev-factor = <2>; + qcom,gpi-ee-offset = <0x1000>; + iommus = <&apps_smmu 0x5b6 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + gpi_dma1: qcom,gpi-dma@a00000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0xa00000 0x70000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x3f>; + qcom,ev-factor = <2>; + qcom,gpi-ee-offset = <0x6000>; + iommus = <&apps_smmu 0x56 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + gpi_dma2: qcom,gpi-dma@800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x70000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x3f>; + qcom,ev-factor = <2>; + qcom,gpi-ee-offset = <0x6000>; + iommus = <&apps_smmu 0x76 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + wlan: qcom,cnss-qca6390@b0000000 { + compatible = "qcom,cnss-qca6390"; + reg = <0xb0000000 0x10000>, + <0xb2e5510 0x5c0>; + reg-names = "smmu_iova_ipa", "tcs_cmd"; + wlan-en-gpio = <&tlmm 20 0>; + pinctrl-names = "wlan_en_active", "wlan_en_sleep"; + pinctrl-0 = <&cnss_wlan_en_active>; + pinctrl-1 = <&cnss_wlan_en_sleep>; + qcom,wlan-rc-num = <0>; + qcom,wlan-ramdump-dynamic = <0x420000>; + qcom,smmu-s1-enable; + qcom,converged-dt; + cnss-daemon-support; + qcom,cmd_db_name = "smpf2"; + qcom,set-wlaon-pwr-ctrl; + + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + /* no vote */ + , + /* idle: 0-18 Mbps, ddr freq: 451.2 MHz */ + , + /* low: 18-60 Mbps, ddr freq: 451.2 MHz*/ + , + /* medium: 60-240 Mbps, ddr freq: 451.2 MHz */ + , + /* high: 240 - 800 Mbps, ddr freq: 451.2 MHz */ + , + /* very high: 800 - 1400 Mbps, ddr freq: 1555.2 MHz */ + , + /* low (latency critical): 18 - 60 Mbps, ddr freq: 547.2 MHz */ + ; + + vdd-wlan-aon-supply = <&pm8150_s6>; + qcom,vdd-wlan-aon-config = <950000 950000 0 0 1>; + vdd-wlan-dig-supply = <&pm8009_s2>; + qcom,vdd-wlan-dig-config = <950000 952000 0 0 1>; + vdd-wlan-io-supply = <&pm8150_s4>; + qcom,vdd-wlan-io-config = <1800000 1800000 0 0 1>; + vdd-wlan-rfa1-supply = <&pm8150_s5>; + qcom,vdd-wlan-rfa1-config = <1900000 1900000 0 0 1>; + vdd-wlan-rfa2-supply = <&pm8150a_s8>; + qcom,vdd-wlan-rfa2-config = <1350000 1350000 0 0 1>; + wlan-ant-switch-supply = <&pm8150a_l5>; + qcom,wlan-ant-switch-config = <1800000 1800000 0 0 0>; + + mhi,max-channels = <30>; + mhi,timeout = <10000>; + mhi,buffer-len = <0x8000>; + mhi,m2-no-db-access; + + mhi_channels { + #address-cells = <1>; + #size-cells = <0>; + + mhi_chan@0 { + reg = <0>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@1 { + reg = <1>; + label = "LOOPBACK"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@4 { + reg = <4>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@5 { + reg = <5>; + label = "DIAG"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + }; + + mhi_chan@20 { + reg = <20>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <1>; + mhi,data-type = <1>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-start; + }; + + mhi_chan@21 { + reg = <21>; + label = "IPCR"; + mhi,num-elements = <32>; + mhi,event-ring = <1>; + mhi,chan-dir = <2>; + mhi,data-type = <0>; + mhi,doorbell-mode = <2>; + mhi,ee = <0x14>; + mhi,auto-queue; + mhi,auto-start; + }; + }; + + mhi_events { + mhi_event@0 { + mhi,num-elements = <32>; + mhi,intmod = <0>; + mhi,msi = <1>; + mhi,priority = <1>; + mhi,brstmode = <2>; + mhi,data-type = <1>; + }; + + mhi_event@1 { + mhi,num-elements = <256>; + mhi,intmod = <0>; + mhi,msi = <2>; + mhi,priority = <1>; + mhi,brstmode = <2>; + }; + + mhi_event@2 { + mhi,num-elements = <32>; + mhi,intmod = <1>; + mhi,msi = <0>; + mhi,priority = <2>; + mhi,brstmode = <2>; + mhi,data-type = <3>; + }; + }; + + mhi_devices { + mhi_qrtr { + mhi,chan = "IPCR"; + qcom,net-id = <0>; + qcom,low-latency; + mhi,early-notify; + }; + }; + }; + + wil6210: qcom,wil6210 { + compatible = "qcom,wil6210"; + qcom,pcie-parent = <&pcie1>; + pinctrl-names = "default"; + pinctrl-0 = <&wil6210_refclk_en_pin>; + qcom,msm-bus,name = "wil6210"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 600000 800000>, /* ~4.6Gbps (MCS12) */ + <100 512 1300000 1300000>; /* ~10.1Gbps */ + qcom,use-ext-supply; + vdd-ldo-supply = <&pm8150_l15>; + vddio-supply = <&pm8150_s5>; + qcom,use-ext-clocks; + clocks = <&clock_rpmh RPMH_RF_CLK1>; + clock-names = "rf_clk"; + qcom,keep-radio-on-during-sleep; + qcom,use-ap-power-save; + status = "disabled"; + }; + + tspp: msm_tspp@8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = ,/*TSIF_TSPP_IRQ*/ + , /* TSIF0_IRQ */ + , /* TSIF1_IRQ */ + ; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + memory-region = <&qseecom_mem>; + iommus = <&apps_smmu 0xA0 0x00>; + qcom,iommu-dma-addr-pool = <0x10000000 0x40000000>; + qcom,smmu-s1-enable; + }; + + demux { + compatible = "qcom,demux"; + }; + + qfprom: qfprom@780000 { + compatible = "qcom,qfprom"; + reg = <0x00784000 0x3000>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + ranges; + + gpu_lm_efuse: gpu_lm_efuse@5c8 { + reg = <0x5c8 0x4>; + }; + + gpu_speed_bin: gpu_speed_bin@19b { + reg = <0x19b 0x1>; + bits = <5 3>; + }; + }; +}; + +#include "kona-regulators.dtsi" +#include "kona-bus.dtsi" +#include "kona-ion.dtsi" +#include "kona-pcie.dtsi" +#include "kona-mhi.dtsi" + +&pcie0_rp { + #address-cells = <5>; + #size-cells = <0>; + + cnss_pci: cnss_pci { + reg = <0 0 0 0 0>; + qcom,iommu-group = <&cnss_pci_iommu_group>; + memory-region = <&cnss_wlan_mem>; + + #address-cells = <1>; + #size-cells = <1>; + + cnss_pci_iommu_group: cnss_pci_iommu_group { + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-pagetable = "coherent"; + qcom,iommu-faults = "stall-disable", "HUPCF", "no-CFRE", + "non-fatal"; + }; + }; +}; + +&pcie1_rp { + #address-cells = <5>; + #size-cells = <0>; + + wil6210_pci: wil6210_pci { + reg = <0 0 0 0 0>; + qcom,iommu-group = <&wil6210_pci_iommu_group>; + + #address-cells = <1>; + #size-cells = <1>; + + wil6210_pci_iommu_group: wil6210_pci_iommu_group { + reg = <0 0>; + qcom,iommu-dma-addr-pool = <0x60000000 0xa0000000>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-pagetable = "coherent"; + }; + }; +}; + +#include "msm-arm-smmu-kona.dtsi" +#include "kona-pinctrl.dtsi" +#include "kona-smp2p.dtsi" +#include "kona-usb.dtsi" +#include "kona-coresight.dtsi" +#include "kona-sde.dtsi" +#include "kona-sde-pll.dtsi" +#include "msm-rdbg.dtsi" + +#include "kona-pm.dtsi" +#include "camera/kona-camera.dtsi" +#include "kona-qupv3.dtsi" +#include "kona-audio.dtsi" +#include "kona-thermal.dtsi" +#include "kona-vidc.dtsi" +#include "kona-cvp.dtsi" +#include "kona-npu.dtsi" +#include "kona-gpu.dtsi" +#include "msm-qvr-external.dtsi" +#include "ipcc-test.dtsi" + +&qupv3_se15_i2c { + status = "ok"; + nq@64 { + compatible = "rtc6226"; + reg = <0x64>; + fmint-gpio = <&tlmm 51 0>; + vdd-supply = <&pm8150a_bob>; + rtc6226,vdd-supply-voltage = <3296000 3296000>; + vio-supply = <&pm8150_s4>; + rtc6226,vio-supply-voltage = <1800000 1800000 >; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-atp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-atp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..f12a2d5cb56cf8dbcb94ef33c9534574018ce656 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-atp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "lagoon-atp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon ATP"; + compatible = "qcom,lagoon-atp", "qcom,lagoon", "qcom,atp"; + qcom,msm-id = <434 0x10000>, <459 0x10000>; + qcom,board-id = <33 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-atp.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-atp.dts new file mode 100644 index 0000000000000000000000000000000000000000..6dfe8f32c65d97677ba6ec17263766e16eaa9124 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-atp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "lagoon.dtsi" +#include "lagoon-atp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon ATP"; + compatible = "qcom,lagoon-atp", "qcom,lagoon", "qcom,atp"; + qcom,board-id = <33 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-atp.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-atp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ad03c03160dac144711d6386d17aa761ebd00ec5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-atp.dtsi @@ -0,0 +1,261 @@ +#include "lagoon-audio-overlay.dtsi" +#include +#include +#include +#include "lagoon-sde-display.dtsi" +#include "lagoon-thermal-overlay.dtsi" + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&pm6350_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&qupv3_se10_i2c { + status = "disabled"; +}; + +&pm8008_8 { + status = "disabled"; +}; + +&pm8008_9 { + status = "disabled"; +}; + +&pm6150a_amoled { + status = "ok"; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage"; + qcom,batteryless-platform; + qcom,sec-charger-config = <0>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&L18A>; + vdda-pll-supply = <&L22A>; + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L7E>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&L12A>; + vccq2-voltage-level = <1800000 1800000>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + vccq2-pwr-collapse-sup; + + qcom,vddp-ref-clk-supply = <&L22A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&L7E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L12A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L9E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L6E>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&dsi_rm69299_visionox_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_rm69299_visionox_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_rm69299_visionox_amoled_video>; +}; + +&qupv3_se0_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 9 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 8 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <9 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&qupv3_se8_i2c { + status = "okay"; + qcom,i2c-touch-active="synaptics,tcm-i2c"; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <22 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + vdd-supply = <&L11A>; + avdd-supply = <&L6A>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,irq-gpio = <&tlmm 22 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 21 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware.img"; + + panel = <&dsi_rm69299_visionox_amoled_video + &dsi_rm69299_visionox_amoled_cmd>; + }; +}; + +&sde_dp { + status = "disabled"; +}; + +&mdss_dp_pll { + status = "disabled"; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_rscc>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-audio-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..50db37cc4819764326bcb034b4e8501e58181194 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-audio-overlay.dtsi @@ -0,0 +1,537 @@ +#include +#include +#include +#include +#include "lagoon-lpi.dtsi" + +&bolero { + qcom,num-macros = <4>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,wsa_mclk_mode_muxsel = <0x033220D8>; + qcom,va_mclk_mode_muxsel = <0x033A0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", "rx_npl_clk", + "wsa_core_clk", "wsa_npl_clk", "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_wsa_1 0>, <&clock_audio_wsa_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; + + tx_macro: tx-macro@3220000 { + compatible = "qcom,tx-macro"; + reg = <0x3220000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <2400000>; + swr2: tx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <3>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3230000 0x0>; + interrupts-extended = + <&intc GIC_SPI 296 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 144 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-wakeup-required = <1>; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 PCM_OUT1 0xF>, + <2 ADC1 0x1>, <2 ADC2 0x2>, + <3 ADC3 0x1>, <3 ADC4 0x2>, + <4 DMIC0 0x1>, <4 DMIC1 0x2>, + <4 DMIC2 0x4>, <4 DMIC3 0x8>, + <5 DMIC4 0x1>, <5 DMIC5 0x2>, + <5 DMIC6 0x4>, <5 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + qcom,swr-mstr-irq-wakeup-capable = <1>; + wcd938x_tx_slave: wcd938x-tx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170223>; + }; + wcd937x_tx_slave: wcd937x-tx-slave { + status = "disabled"; + compatible = "qcom,wcd937x-slave"; + reg = <0x0A 0x01170223>; + }; + }; + }; + + rx_macro: rx-macro@3200000 { + compatible = "qcom,rx-macro"; + reg = <0x3200000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x02 0x1E>; + qcom,default-clk-id = ; + swr1: rx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <2>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3210000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,disable-div2-clk-switch = <1>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x1>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd938x_rx_slave: wcd938x-rx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170224>; + }; + wcd937x_rx_slave: wcd937x_rx_slave { + status = "disabled"; + compatible = "qcom,wcd937x-slave"; + reg = <0x0A 0x01170224>; + }; + }; + }; + + wsa_macro: wsa-macro@3240000 { + compatible = "qcom,wsa-macro"; + reg = <0x3240000 0x0>; + clock-names = "wsa_core_clk", "wsa_npl_clk"; + clocks = <&clock_audio_wsa_1 0>, + <&clock_audio_wsa_2 0>; + qcom,wsa-swr-gpios = <&wsa_swr_gpios>; + qcom,wsa-bcl-pmic-params = /bits/ 8 <0x00 0x02 0x1E>; + qcom,default-clk-id = ; + swr0: wsa_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <1>; + qcom,mipi-sdw-block-packing-mode = <0>; + swrm-io-base = <0x3250000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <8>; + qcom,swr-port-mapping = <1 SPKR_L 0x1>, + <2 SPKR_L_COMP 0xF>, <3 SPKR_L_BOOST 0x3>, + <4 SPKR_R 0x1>, <5 SPKR_R_COMP 0xF>, + <6 SPKR_R_BOOST 0x3>, <7 SPKR_L_VI 0x3>, + <8 SPKR_R_VI 0x3>; + qcom,swr-num-dev = <2>; + wsa883x_0221: wsa883x@02170221 { + compatible = "qcom,wsa883x"; + reg = <0x02 0x02170221>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + qcom,bolero-handle = <&bolero>; + + cdc-vdd-1p8-supply = <&L11A>; + qcom,cdc-vdd-1p8-voltage = <1800000 1800000>; + qcom,cdc-vdd-1p8-current = <20000>; + qcom,cdc-vdd-1p8-lpm-supported = <1>; + qcom,cdc-static-supplies = "cdc-vdd-1p8"; + }; + + wsa883x_0222: wsa883x@02170222 { + compatible = "qcom,wsa883x"; + reg = <0x02 0x02170222>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + qcom,bolero-handle = <&bolero>; + + cdc-vdd-1p8-supply = <&L11A>; + qcom,cdc-vdd-1p8-voltage = <1800000 1800000>; + qcom,cdc-vdd-1p8-current = <20000>; + qcom,cdc-vdd-1p8-lpm-supported = <1>; + qcom,cdc-static-supplies = "cdc-vdd-1p8"; + }; + }; + + }; + + va_macro: va-macro@3370000 { + compatible = "qcom,va-macro"; + reg = <0x3370000 0x0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,va-dmic-sample-rate = <600000>; + qcom,va-clk-mux-select = <1>; + qcom,va-island-mode-muxsel = <0x033A0000>; + qcom,default-clk-id = ; + }; + + wcd938x_codec: wcd938x-codec { + compatible = "qcom,wcd938x-codec"; + qcom,split-codec = <1>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <0 ADC2 0x2 0 ADC2>, <1 ADC3 0x1 0 ADC3>, + <1 ADC4 0x2 0 ADC4>, <2 DMIC0 0x1 0 DMIC0>, + <2 DMIC1 0x2 0 DMIC1>, <2 MBHC 0x4 0 DMIC2>, + <2 DMIC2 0x4 0 DMIC2>, <2 DMIC3 0x8 0 DMIC3>, + <3 DMIC4 0x1 0 DMIC4>, <3 DMIC5 0x2 0 DMIC5>, + <3 DMIC6 0x4 0 DMIC6>, <3 DMIC7 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd938x_rst_gpio>; + qcom,rx-slave = <&wcd938x_rx_slave>; + qcom,tx-slave = <&wcd938x_tx_slave>; + + cdc-vdd-rxtx-supply = <&L11A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + qcom,cdc-vdd-rxtx-lpm-supported = <1>; + + cdc-vddio-supply = <&L11A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + qcom,cdc-vddio-lpm-supported = <1>; + + cdc-vdd-buck-supply = <&L14A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio", + "cdc-vdd-mic-bias"; + qcom,cdc-on-demand-supplies = "cdc-vdd-buck"; + }; + + wcd937x_codec: wcd937x-codec { + status = "disabled"; + compatible = "qcom,wcd937x-codec"; + qcom,split-codec = <1>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <1 ADC2 0x1 0 ADC3>, <1 ADC3 0x2 0 ADC4>, + <2 DMIC0 0x1 0 DMIC0>, <2 DMIC1 0x2 0 DMIC1>, + <2 MBHC 0x4 0 DMIC2>, <3 DMIC2 0x1 0 DMIC4>, + <3 DMIC3 0x2 0 DMIC5>, <3 DMIC4 0x4 0 DMIC6>, + <3 DMIC5 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd938x_rst_gpio>; + qcom,rx-slave = <&wcd937x_rx_slave>; + qcom,tx-slave = <&wcd937x_tx_slave>; + + cdc-vdd-rxtx-supply = <&L11A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + + cdc-vddio-supply = <&L11A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + + cdc-vdd-buck-supply = <&L14A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio", + "cdc-vdd-mic-bias"; + qcom,cdc-on-demand-supplies = "cdc-vdd-buck"; + }; + +}; + +&lagoon_snd { + qcom,model = "lito-lagoonmtp-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "TX DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "TX DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "TX DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "TX DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS1", "Digital Mic0", + "VA MIC BIAS1", "Digital Mic1", + "VA MIC BIAS3", "Digital Mic2", + "VA MIC BIAS3", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS1", + "VA DMIC1", "VA MIC BIAS1", + "VA DMIC2", "VA MIC BIAS3", + "VA DMIC3", "VA MIC BIAS3", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa883x_0221>, <&wsa883x_0222>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, + <&lpi_tlmm>, <&bolero>; +}; + +&q6core { + cdc_dmic01_gpios: cdc_dmic01_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic01_clk_active &cdc_dmic01_data_active>; + pinctrl-1 = <&cdc_dmic01_clk_sleep &cdc_dmic01_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <133 134>; + }; + + cdc_dmic23_gpios: cdc_dmic23_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic23_clk_active &cdc_dmic23_data_active>; + pinctrl-1 = <&cdc_dmic23_clk_sleep &cdc_dmic23_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <136>; + }; + + cdc_dmic45_gpios: cdc_dmic45_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic45_clk_active &cdc_dmic45_data_active>; + pinctrl-1 = <&cdc_dmic45_clk_sleep &cdc_dmic45_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <139 140>; + }; + + wsa_swr_gpios: wsa_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wsa_swr_clk_active &wsa_swr_data_active>; + pinctrl-1 = <&wsa_swr_clk_sleep &wsa_swr_data_sleep>; + qcom,lpi-gpios; + }; + + rx_swr_gpios: rx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&rx_swr_clk_active &rx_swr_data_active + &rx_swr_data1_active>; + pinctrl-1 = <&rx_swr_clk_sleep &rx_swr_data_sleep + &rx_swr_data1_sleep>; + qcom,lpi-gpios; + }; + + tx_swr_gpios: tx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tx_swr_clk_active &tx_swr_data1_active + &tx_swr_data2_active &tx_swr_data3_active>; + pinctrl-1 = <&tx_swr_clk_sleep &tx_swr_data1_sleep + &tx_swr_data2_sleep &tx_swr_data3_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <128 129>; + }; +}; + +&soc { + wsa_spkr_en1: wsa_spkr_en1_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_en2: wsa_spkr_en2_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + wcd938x_rst_gpio: msm_cdc_pinctrl@83 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd938x_reset_active>; + pinctrl-1 = <&wcd938x_reset_sleep>; + }; + + clock_audio_wsa_1: wsa_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x309>; + #clock-cells = <1>; + }; + + clock_audio_wsa_2: wsa_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30A>; + #clock-cells = <1>; + }; + + clock_audio_rx_1: rx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30E>; + #clock-cells = <1>; + }; + + clock_audio_rx_2: rx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30F>; + #clock-cells = <1>; + }; + + clock_audio_tx_1: tx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30C>; + #clock-cells = <1>; + }; + + clock_audio_tx_2: tx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30D>; + #clock-cells = <1>; + }; + + clock_audio_va_1: va_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30B>; + #clock-cells = <1>; + }; + + clock_audio_va_2: va_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x310>; + #clock-cells = <1>; + }; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7402fb50932da7f6bd3cdb9e573888c99f15ff1b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-audio.dtsi @@ -0,0 +1,177 @@ +#include +#include "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x1001 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&soc { + qcom,avtimer@39ef000 { + compatible = "qcom,avtimer"; + reg = <0x039f000c 0x4>, + <0x039f0010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <192>; + qcom,clk-mult = <10>; + }; +}; + +&audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + + lpass_core_hw_vote: vote_lpass_core_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + lpass_audio_hw_vote: vote_lpass_audio_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + bolero: bolero-cdc { + compatible = "qcom,bolero-codec"; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + }; + + tx_macro: tx-macro@3220000 { + swr2: tx_swr_master { + }; + }; + + rx_macro: rx-macro@3200000 { + swr1: rx_swr_master { + }; + }; + + wsa_macro: wsa-macro@3240000 { + swr0: wsa_swr_master { + }; + }; + }; + }; +}; + +&q6core { + lagoon_snd: sound { + compatible = "qcom,kona-asoc-snd"; + qcom,mi2s-audio-intf = <1>; + qcom,auxpcm-audio-intf = <1>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <0>; + qcom,afe-rxtx-lb = <0>; + + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, <&dai_dp1>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_mi2s5>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&dai_sen_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&proxy_rx>, <&proxy_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&dai_sen_tdm_rx_0>, <&dai_sen_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&va_cdc_dma_2_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&rx_cdc_dma_6_rx>, <&rx_cdc_dma_7_rx>, + <&afe_loopback_tx>; + asoc-cpu-names = "msm-dai-q6-dp.0", "msm-dai-q6-dp.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.5", + "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-auxpcm.6", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16401", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36944", "msm-dai-q6-tdm.36945", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45093", + "msm-dai-cdc-dma-dev.45104", + "msm-dai-cdc-dma-dev.45105", + "msm-dai-cdc-dma-dev.45106", + "msm-dai-cdc-dma-dev.45107", + "msm-dai-cdc-dma-dev.45108", + "msm-dai-cdc-dma-dev.45109", + "msm-dai-cdc-dma-dev.45110", + "msm-dai-cdc-dma-dev.45111", + "msm-dai-cdc-dma-dev.45112", + "msm-dai-cdc-dma-dev.45113", + "msm-dai-cdc-dma-dev.45114", + "msm-dai-cdc-dma-dev.45115", + "msm-dai-cdc-dma-dev.45116", + "msm-dai-cdc-dma-dev.45118", + "msm-dai-q6-dev.24577"; + fsa4480-i2c-handle = <&fsa4480>; + }; +}; + +&qupv3_se10_i2c { + status = "ok"; + fsa4480: fsa4480@42 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x42>; + pinctrl-names = "default"; + pinctrl-0 = <&fsa_usbc_ana_en>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-bus.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8a7fb87fcb2675441705c144ee2d60dde85e6b78 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-bus.dtsi @@ -0,0 +1,1880 @@ +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x16E0000 0x15080>, + <0x1700000 0x1F880>, + <0x1500000 0x28000>, + <0x9160000 0x03200>, + <0x9680000 0x3E200>, + <0x1740000 0x1C100>, + <0x1620000 0x17080>, + <0x1700000 0x1F880>, + <0x9990000 0x1600>, + <0x1620000 0x4000>; + + reg-names = "aggre1_noc-base", "aggre2_noc-base", + "config_noc-base", "dc_noc-base", + "gem_noc-base", "mmss_noc-base", + "system_noc-base", "compute_noc-base", + "npu_noc-base", "clk_virt-base"; + + /*RSCs*/ + rsc_apps: rsc-apps { + cell-id = ; + label = "apps_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + rsc_disp: rsc-disp { + cell-id = ; + label = "disp_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + /*BCMs*/ + bcm_acv: bcm-acv { + cell-id = ; + label = "ACV"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_alc: bcm-alc { + cell-id = ; + label = "ALC"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ce0: bcm-ce0 { + cell-id = ; + label = "CE0"; + qcom,bcm-name = "CE0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn0: bcm-cn0 { + cell-id = ; + label = "CN0"; + qcom,bcm-name = "CN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn1: bcm-cn1 { + cell-id = ; + label = "CN1"; + qcom,bcm-name = "CN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co0: bcm-co0 { + cell-id = ; + label = "CO0"; + qcom,bcm-name = "CO0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co2: bcm-co2 { + cell-id = ; + label = "CO2"; + qcom,bcm-name = "CO2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co3: bcm-co3 { + cell-id = ; + label = "CO3"; + qcom,bcm-name = "CO3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mc0: bcm-mc0 { + cell-id = ; + label = "MC0"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm0: bcm-mm0 { + cell-id = ; + label = "MM0"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm1: bcm-mm1 { + cell-id = ; + label = "MM1"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm2: bcm-mm2 { + cell-id = ; + label = "MM2"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm3: bcm-mm3 { + cell-id = ; + label = "MM3"; + qcom,bcm-name = "MM3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_qup0: bcm-qup0 { + cell-id = ; + label = "QUP0"; + qcom,bcm-name = "QUP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh0: bcm-sh0 { + cell-id = ; + label = "SH0"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh2: bcm-sh2 { + cell-id = ; + label = "SH2"; + qcom,bcm-name = "SH2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh3: bcm-sh3 { + cell-id = ; + label = "SH3"; + qcom,bcm-name = "SH3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh4: bcm-sh4 { + cell-id = ; + label = "SH4"; + qcom,bcm-name = "SH4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn0: bcm-sn0 { + cell-id = ; + label = "SN0"; + qcom,bcm-name = "SN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn2: bcm-sn2 { + cell-id = ; + label = "SN2"; + qcom,bcm-name = "SN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn4: bcm-sn4 { + cell-id = ; + label = "SN4"; + qcom,bcm-name = "SN4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn5: bcm-sn5 { + cell-id = ; + label = "SN5"; + qcom,bcm-name = "SN5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn6: bcm-sn6 { + cell-id = ; + label = "SN6"; + qcom,bcm-name = "SN6"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn10: bcm-sn10 { + cell-id = ; + label = "SN10"; + qcom,bcm-name = "SN10"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_acv_display: bcm-acv_display { + cell-id = ; + label = "ACV_DISPLAY"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_alc_display: bcm-alc_display { + cell-id = ; + label = "ALC_DISPLAY"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mc0_display: bcm-mc0_display { + cell-id = ; + label = "MC0_DISPLAY"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm0_display: bcm-mm0_display { + cell-id = ; + label = "MM0_DISPLAY"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm1_display: bcm-mm1_display { + cell-id = ; + label = "MM1_DISPLAY"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_sh0_display: bcm-sh0_display { + cell-id = ; + label = "SH0_DISPLAY"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + /*Buses*/ + fab_aggre1_noc: fab-aggre1_noc { + cell-id = ; + label = "fab-aggre1_noc"; + qcom,fab-dev; + qcom,base-name = "aggre1_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_aggre2_noc: fab-aggre2_noc { + cell-id = ; + label = "fab-aggre2_noc"; + qcom,fab-dev; + qcom,base-name = "aggre2_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <20480>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_clk_virt: fab-clk_virt { + cell-id = ; + label = "fab-clk_virt"; + qcom,fab-dev; + qcom,base-name = "clk_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_compute_noc: fab-compute_noc { + cell-id = ; + label = "fab-compute_noc"; + qcom,fab-dev; + qcom,base-name = "compute_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <57344>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_dc_noc: fab-dc_noc { + cell-id = ; + label = "fab-dc_noc"; + qcom,fab-dev; + qcom,base-name = "dc_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc: fab-gem_noc { + cell-id = ; + label = "fab-gem_noc"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <188416>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mmss_noc: fab-mmss_noc { + cell-id = ; + label = "fab-mmss_noc"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_npu_noc: fab-npu_noc { + cell-id = ; + label = "fab-npu_noc"; + qcom,fab-dev; + qcom,base-name = "npu_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_system_noc: fab-system_noc { + cell-id = ; + label = "fab-system_noc"; + qcom,fab-dev; + qcom,base-name = "system_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <45056>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc_display: fab-gem_noc_display { + cell-id = ; + label = "fab-gem_noc_display"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <188416>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + + fab_mmss_noc_display: fab-mmss_noc_display { + cell-id = ; + label = "fab-mmss_noc_display"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + + /*Masters*/ + mas_qhm_a1noc_cfg: mas-qhm-a1noc-cfg { + cell-id = ; + label = "mas-qhm-a1noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre1_noc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_qhm_qup_0: mas-qhm-qup-0 { + cell-id = ; + label = "mas-qhm-qup-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_emmc: mas-xm-emmc { + cell-id = ; + label = "mas-xm-emmc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + clock-names = + "clk-aggre-ufs-phy-axi-no-rate"; + }; + }; + + mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg { + cell-id = ; + label = "mas-qhm-a2noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre2_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup_1: mas-qhm-qup-1 { + cell-id = ; + label = "mas-qhm-qup-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_ce0>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <19>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-aggre-usb3-prim-axi-no-rate"; + }; + }; + + mas_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf0-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_icp_uncomp: mas-qxm-camnoc-icp-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-icp-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_sf_uncomp: mas-qxm-camnoc-sf-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-sf-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_ipa_core_master: mas-ipa-core-master { + cell-id = ; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ipa_core_slave>; + qcom,bus-dev = <&fab_clk_virt>; + }; + + mas_qup0_core_master: mas-qup0-core-master { + cell-id = ; + label = "mas-qup0-core-master"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup0_core_slave>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qup1_core_master: mas-qup1-core-master { + cell-id = ; + label = "mas-qup1-core-master"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup1_core_slave>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qnm_npu: mas-qnm-npu { + cell-id = ; + label = "mas-qnm-npu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <1 3>; + qcom,connections = <&slv_qns_cdsp_gemnoc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co2>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_npu_dsp: mas-qxm-npu-dsp { + cell-id = ; + label = "mas-qxm-npu-dsp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_cdsp_gemnoc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc: mas-qnm-snoc { + cell-id = ; + label = "mas-qnm-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_camera_cfg &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_qm_cfg &slv_qhs_snoc_cfg + &slv_qhs_qm_mpu_cfg &slv_qhs_glm + &slv_qhs_pdm &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_a2_noc_cfg &slv_qhs_qdss_cfg + &slv_qhs_vsense_ctrl_cfg + &slv_qhs_camera_rt_throttle_cfg + &slv_qhs_display_cfg &slv_qhs_tcsr + &slv_qhs_dcc_cfg &slv_qhs_ddrss_cfg + &slv_qhs_display_throttle_cfg + &slv_qhs_npu_cfg &slv_qhs_ahb2phy0 + &slv_qhs_gpuss_cfg &slv_qhs_boot_rom + &slv_qhs_venus_cfg &slv_qhs_ipa + &slv_qhs_security &slv_qhs_imem_cfg + &slv_qhs_mss_cfg &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_venus_throttle_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_emmc_cfg &slv_qhs_crypto0_cfg + &slv_qhs_pimem_cfg &slv_qhs_cpr_mx + &slv_qhs_qup0 &slv_qhs_qup1 + &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_xm_qdss_dap: mas-xm-qdss-dap { + cell-id = ; + label = "mas-xm-qdss-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_camera_cfg &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_qm_cfg &slv_qhs_snoc_cfg + &slv_qhs_qm_mpu_cfg &slv_qhs_glm + &slv_qhs_pdm &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_a2_noc_cfg &slv_qhs_qdss_cfg + &slv_qhs_vsense_ctrl_cfg + &slv_qhs_camera_rt_throttle_cfg + &slv_qhs_display_cfg &slv_qhs_tcsr + &slv_qhs_dcc_cfg &slv_qhs_ddrss_cfg + &slv_qhs_display_throttle_cfg + &slv_qhs_npu_cfg &slv_qhs_ahb2phy0 + &slv_qhs_gpuss_cfg &slv_qhs_boot_rom + &slv_qhs_venus_cfg &slv_qhs_ipa + &slv_qhs_security &slv_qhs_imem_cfg + &slv_qhs_mss_cfg &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_venus_throttle_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_emmc_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_cpr_mx &slv_qhs_qup0 + &slv_qhs_qup1 &slv_qhs_clk_ctl>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qhm_cnoc_dc_noc: mas-qhm-cnoc-dc-noc { + cell-id = ; + label = "mas-qhm-cnoc-dc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_llcc &slv_qhs_gemnoc>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + mas_acm_apps: mas-acm-apps { + cell-id = ; + label = "mas-acm-apps"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <34 32>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh4>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_acm_sys_tcu: mas-acm-sys-tcu { + cell-id = ; + label = "mas-acm-sys-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <224>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh2>; + qcom,ap-owned; + qcom,prio = <6>; + }; + + mas_qhm_gemnoc_cfg: mas-qhm-gemnoc-cfg { + cell-id = ; + label = "mas-qhm-gemnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_mcdma_ms_mpu_cfg + &slv_srvc_gemnoc &slv_qhs_mdsp_ms_mpu_cfg>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + mas_qnm_cmpnoc: mas-qnm-cmpnoc { + cell-id = ; + label = "mas-qnm-cmpnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { + cell-id = ; + label = "mas-qnm-mnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <64>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { + cell-id = ; + label = "mas-qnm-mnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <192>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <128>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc_sf: mas-qnm-snoc-sf { + cell-id = ; + label = "mas-qnm-snoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <96>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_gpu: mas-qxm-gpu { + cell-id = ; + label = "mas-qxm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <160 161>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_llcc_mc: mas-llcc-mc { + cell-id = ; + label = "mas-llcc-mc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_clk_virt>; + }; + + mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { + cell-id = ; + label = "mas-qhm-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + }; + + mas_qnm_video0: mas-qnm-video0 { + cell-id = ; + label = "mas-qnm-video0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_video_cvp: mas-qnm-video-cvp { + cell-id = ; + label = "mas-qnm-video-cvp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <5>; + qcom,forwarding; + }; + + mas_qxm_camnoc_hf: mas-qxm-camnoc-hf { + cell-id = ; + label = "mas-qxm-camnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <1 2>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <3>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_icp: mas-qxm-camnoc-icp { + cell-id = ; + label = "mas-qxm-camnoc-icp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,ap-owned; + qcom,prio = <5>; + }; + + mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { + cell-id = ; + label = "mas-qxm-camnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <3>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <3>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_amm_npu_sys: mas-amm-npu-sys { + cell-id = ; + label = "mas-amm-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_npu_sys>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qhm_npu_cfg: mas-qhm-npu-cfg { + cell-id = ; + label = "mas-qhm-npu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_noc &slv_qhs_isense + &slv_qhs_llm &slv_qhs_dma_bwmon &slv_qhs_cp + &slv_qhs_tcm &slv_qhs_cal_dp0 &slv_qhs_dpm>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { + cell-id = ; + label = "mas-qhm-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qnm_aggre1_noc: mas-qnm-aggre1-noc { + cell-id = ; + label = "mas-qnm-aggre1-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf &slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss &slv_qns_cnoc + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn5>; + }; + + mas_qnm_aggre2_noc: mas-qnm-aggre2-noc { + cell-id = ; + label = "mas-qnm-aggre2-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf &slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn6>; + }; + + mas_qnm_gemnoc: mas-qnm-gemnoc { + cell-id = ; + label = "mas-qnm-gemnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn10>; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_gemnoc_gc &slv_qxs_imem>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_gic: mas-xm-gic { + cell-id = ; + label = "mas-xm-gic"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_gemnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <3>; + }; + + mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display { + cell-id = ; + label = "mas-qnm-mnoc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <64>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display { + cell-id = ; + label = "mas-qnm-mnoc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <192>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_llcc_mc_display: mas-llcc-mc_display { + cell-id = ; + label = "mas-llcc-mc_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi_display>; + qcom,bus-dev = <&fab_clk_virt>; + }; + + mas_qxm_mdp0_display: mas-qxm-mdp0_display { + cell-id = ; + label = "mas-qxm-mdp0_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + /*Internal nodes*/ + + /*Slaves*/ + slv_qns_a1noc_snoc:slv-qns-a1noc-snoc { + cell-id = ; + label = "slv-qns-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_aggre1_noc>; + }; + + slv_srvc_aggre1_noc:slv-srvc-aggre1-noc { + cell-id = ; + label = "slv-srvc-aggre1-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + slv_qns_a2noc_snoc:slv-qns-a2noc-snoc { + cell-id = ; + label = "slv-qns-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_aggre2_noc>; + }; + + slv_srvc_aggre2_noc:slv-srvc-aggre2-noc { + cell-id = ; + label = "slv-srvc-aggre2-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + slv_qns_camnoc_uncomp:slv-qns-camnoc-uncomp { + cell-id = ; + label = "slv-qns-camnoc-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_clk_virt>; + }; + + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_ip0>; + }; + + slv_qup0_core_slave:slv-qup0-core-slave { + cell-id = ; + label = "slv-qup0-core-slave"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + slv_qup1_core_slave:slv-qup1-core-slave { + cell-id = ; + label = "slv-qup1-core-slave"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + slv_qns_cdsp_gemnoc:slv-qns-cdsp-gemnoc { + cell-id = ; + label = "slv-qns-cdsp-gemnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,connections = <&mas_qnm_cmpnoc>; + qcom,bcms = <&bcm_co0>; + }; + + slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg { + cell-id = ; + label = "slv-qhs-a1-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a1noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_a2_noc_cfg:slv-qhs-a2-noc-cfg { + cell-id = ; + label = "slv-qhs-a2-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a2noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy0:slv-qhs-ahb2phy0 { + cell-id = ; + label = "slv-qhs-ahb2phy0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy2:slv-qhs-ahb2phy2 { + cell-id = ; + label = "slv-qhs-ahb2phy2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_aoss:slv-qhs-aoss { + cell-id = ; + label = "slv-qhs-aoss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_boot_rom:slv-qhs-boot-rom { + cell-id = ; + label = "slv-qhs-boot-rom"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_cfg:slv-qhs-camera-cfg { + cell-id = ; + label = "slv-qhs-camera-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_nrt_throttle_cfg:slv-qhs-camera-nrt-thrott-cfg { + cell-id = ; + label = "slv-qhs-camera-nrt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_rt_throttle_cfg:slv-qhs-camera-rt-throttle-cfg { + cell-id = ; + label = "slv-qhs-camera-rt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_cx:slv-qhs-cpr-cx { + cell-id = ; + label = "slv-qhs-cpr-cx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_mx:slv-qhs-cpr-mx { + cell-id = ; + label = "slv-qhs-cpr-mx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_dcc_cfg:slv-qhs-dcc-cfg { + cell-id = ; + label = "slv-qhs-dcc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ddrss_cfg:slv-qhs-ddrss-cfg { + cell-id = ; + label = "slv-qhs-ddrss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cnoc_dc_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_cfg:slv-qhs-display-cfg { + cell-id = ; + label = "slv-qhs-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_throttle_cfg:slv-qhs-display-throttle-cfg { + cell-id = ; + label = "slv-qhs-display-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_emmc_cfg:slv-qhs-emmc-cfg { + cell-id = ; + label = "slv-qhs-emmc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_glm:slv-qhs-glm { + cell-id = ; + label = "slv-qhs-glm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg { + cell-id = ; + label = "slv-qhs-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg { + cell-id = ; + label = "slv-qhs-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_mnoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mss_cfg:slv-qhs-mss-cfg { + cell-id = ; + label = "slv-qhs-mss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_npu_cfg:slv-qhs-npu-cfg { + cell-id = ; + label = "slv-qhs-npu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_npu_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qm_cfg:slv-qhs-qm-cfg { + cell-id = ; + label = "slv-qhs-qm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qm_mpu_cfg:slv-qhs-qm-mpu-cfg { + cell-id = ; + label = "slv-qhs-qm-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup0:slv-qhs-qup0 { + cell-id = ; + label = "slv-qhs-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup1:slv-qhs-qup1 { + cell-id = ; + label = "slv-qhs-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_security:slv-qhs-security { + cell-id = ; + label = "slv-qhs-security"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_snoc_cfg:slv-qhs-snoc-cfg { + cell-id = ; + label = "slv-qhs-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_snoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg { + cell-id = ; + label = "slv-qhs-ufs-mem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_usb3_0:slv-qhs-usb3-0 { + cell-id = ; + label = "slv-qhs-usb3-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_throttle_cfg:slv-qhs-venus-throttle-cfg { + cell-id = ; + label = "slv-qhs-venus-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gemnoc:slv-qhs-gemnoc { + cell-id = ; + label = "slv-qhs-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + qcom,connections = <&mas_qhm_gemnoc_cfg>; + }; + + slv_qhs_llcc:slv-qhs-llcc { + cell-id = ; + label = "slv-qhs-llcc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + slv_qhs_mcdma_ms_mpu_cfg:slv-qhs-mcdma-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mcdma-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mdsp-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_qns_gem_noc_snoc:slv-qns-gem-noc-snoc { + cell-id = ; + label = "slv-qns-gem-noc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_qnm_gemnoc>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_srvc_gemnoc:slv-srvc-gemnoc { + cell-id = ; + label = "slv-srvc-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_mc0>, <&bcm_acv>; + }; + + slv_qns_mem_noc_hf:slv-qns-mem-noc-hf { + cell-id = ; + label = "slv-qns-mem-noc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_hf>; + qcom,bcms = <&bcm_mm0>; + }; + + slv_qns_mem_noc_sf:slv-qns-mem-noc-sf { + cell-id = ; + label = "slv-qns-mem-noc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_sf>; + qcom,bcms = <&bcm_mm2>; + }; + + slv_srvc_mnoc:slv-srvc-mnoc { + cell-id = ; + label = "slv-srvc-mnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + slv_qhs_cal_dp0:slv-qhs-cal-dp0 { + cell-id = ; + label = "slv-qhs-cal-dp0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_cp:slv-qhs-cp { + cell-id = ; + label = "slv-qhs-cp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dma_bwmon:slv-qhs-dma-bwmon { + cell-id = ; + label = "slv-qhs-dma-bwmon"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dpm:slv-qhs-dpm { + cell-id = ; + label = "slv-qhs-dpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_isense:slv-qhs-isense { + cell-id = ; + label = "slv-qhs-isense"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_llm:slv-qhs-llm { + cell-id = ; + label = "slv-qhs-llm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_tcm:slv-qhs-tcm { + cell-id = ; + label = "slv-qhs-tcm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qns_npu_sys:slv-qns-npu-sys { + cell-id = ; + label = "slv-qns-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_srvc_noc:slv-srvc-noc { + cell-id = ; + label = "slv-srvc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_cnoc:slv-qns-cnoc { + cell-id = ; + label = "slv-qns-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc>; + }; + + slv_qns_gemnoc_gc:slv-qns-gemnoc-gc { + cell-id = ; + label = "slv-qns-gemnoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_gc>; + qcom,bcms = <&bcm_sn2>; + }; + + slv_qns_gemnoc_sf:slv-qns-gemnoc-sf { + cell-id = ; + label = "slv-qns-gemnoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_sf>; + qcom,bcms = <&bcm_sn0>; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn1>; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_llcc_display:slv-qns-llcc_display { + cell-id = ; + label = "slv-qns-llcc_display"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc_display>; + qcom,connections = <&mas_llcc_mc_display>; + qcom,bcms = <&bcm_sh0_display>; + }; + + slv_ebi_display:slv-ebi_display { + cell-id = ; + label = "slv-ebi_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_clk_virt>; + qcom,bcms = <&bcm_mc0_display>, <&bcm_acv_display>; + }; + + slv_qns_mem_noc_hf_display:slv-qns-mem-noc-hf_display { + cell-id = ; + label = "slv-qns-mem-noc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_hf_display>; + qcom,bcms = <&bcm_mm0_display>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..0b36c97bcf16187dd6e72472d2ffdff43d70ef9e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp-overlay.dts @@ -0,0 +1,13 @@ + +/dts-v1/; +/plugin/; + +#include +#include "lagoon-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon CDP"; + compatible = "qcom,lagoon-cdp", "qcom,lagoon", "qcom,cdp"; + qcom,msm-id = <434 0x10000>, <459 0x10000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ef8a9a74c780f009aa97fdc2c847e6f5eaaee3fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "lagoon.dtsi" +#include "lagoon-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon CDP"; + compatible = "qcom,lagoon-cdp", "qcom,lagoon", "qcom,cdp"; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6637a13e2f56580cbf9accbbeb0cb47e08f51df9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-cdp.dtsi @@ -0,0 +1,421 @@ +#include "lagoon-audio-overlay.dtsi" +#include +#include "lagoon-sde-display.dtsi" +#include "camera/lagoon-camera-sensor-cdp.dtsi" +#include "lagoon-thermal-overlay.dtsi" + +&soc { +}; + +&lagoon_snd { + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&L18A>; + vdda-pll-supply = <&L22A>; + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L7E>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&L12A>; + vccq2-voltage-level = <1800000 1800000>; + vcc-max-microamp = <800000>; + vccq2-min-microamp = <0>; + vccq2-max-microamp = <800000>; + vccq2-pwr-collapse-sup; + + qcom,vddp-ref-clk-supply = <&L22A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&L7E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L12A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L9E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L6E>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +#include +#include +#include + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&pm6350_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&pm6150a_amoled { + status = "ok"; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage"; + qcom,batteryless-platform; + qcom,sec-charger-config = <0>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; +}; + +&dsi_rm69299_visionox_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_rm69299_visionox_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sharp_qsync_fhd_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm6350_gpios 6 0>; +}; + +&dsi_sharp_qsync_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm6350_gpios 6 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_r66451_amoled_144hz_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_144>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-bl-inverted-dbv; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_rm69299_visionox_amoled_video>; +}; + +&qupv3_se0_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 9 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 8 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + qcom,nq-vdd-1p8-supply = <&L11A>; + qcom,nq-vdd-1p8-voltage = <1800000 1800000>; + qcom,nq-vdd-1p8-current = <157000>; + interrupt-parent = <&tlmm>; + interrupts = <9 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&qupv3_se8_i2c { + status = "okay"; + qcom,i2c-touch-active="synaptics,tcm-i2c"; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <22 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + vdd-supply = <&L11A>; + avdd-supply = <&L6A>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,irq-gpio = <&tlmm 22 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 21 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware.img"; + + panel = <&dsi_rm69299_visionox_amoled_video + &dsi_rm69299_visionox_amoled_cmd>; + }; + + synaptics_dsx@22 { + compatible = "synaptics,dsx-i2c"; + reg = <0x22>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + vdd-supply = <&L11A>; + avdd-supply = <&L6A>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,ub-i2c-addr = <0x22>; + synaptics,max-y-for-2d = <1859>; + synaptics,irq-gpio = <&tlmm 22 0x2008>; + synaptics,reset-gpio = <&tlmm 21 0x0>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + + panel = <&dsi_sharp_qsync_fhd_video + &dsi_sharp_qsync_fhd_cmd>; + }; + + focaltech@38 { + compatible = "focaltech,fts_ts"; + reg = <0x38>; + interrupt-parent = <&tlmm>; + interrupts = <22 0x2008>; + focaltech,reset-gpio = <&tlmm 21 0x00>; + focaltech,irq-gpio = <&tlmm 22 0x2008>; + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 1080 2340>; + + vdd-supply = <&L6A>; + + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + + panel = <&dsi_r66451_amoled_144hz_cmd>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-coresight.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3a4f2f6cb9279facba8dcc59bf760da7ff1649c4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-coresight.dtsi @@ -0,0 +1,3042 @@ +&soc { + hwevent { + compatible = "qcom,coresight-hwevent"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + audio_etm0: audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-audio-etm0"; + + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_audio_etm0>; + }; + }; + }; + + tpdm_swao_0: tpdm@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b09000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_swao_0_out_tpda_swao0: endpoint { + remote-endpoint = <&tpda_swao0_in_tpdm_swao_0>; + }; + }; + }; + + tpdm_swao_1: tpdm@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b0a000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao_1_out_tpda_swao1: endpoint { + remote-endpoint = <&tpda_swao1_in_tpdm_swao_1>; + }; + }; + }; + + tpdm_vsense: tpdm@6834000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6834000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_vsense_out_tpda_dl_center11: endpoint { + remote-endpoint = + <&tpda_dl_center11_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@6870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + qcom,hw-enable-check; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dcc_out_tpda24: endpoint { + remote-endpoint = + <&tpda24_in_tpdm_dcc>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_prng_out_tpda25: endpoint { + remote-endpoint = + <&tpda25_in_tpdm_prng>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_pimem_out_tpda27: endpoint { + remote-endpoint = + <&tpda27_in_tpdm_pimem>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_qm_out_tpda_dl_center13: endpoint { + remote-endpoint = + <&tpda_dl_center13_in_tpdm_qm>; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6844000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-lpass"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_lpass_out_tpda0: endpoint { + remote-endpoint = + <&tpda0_in_tpdm_lpass>; + }; + }; + }; + + tpdm_lpass_lpi: tpdm@6b26000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-lpass-lpi"; + qcom,dummy-source; + + port { + tpdm_lpass_lpi_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpdm_lpass_lpi>; + }; + }; + }; + + tpdm_npu: tpdm@6c47000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c47000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_npu_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_tpdm_npu>; + }; + }; + }; + + npu_etm0: npu_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-npu-etm0"; + + qcom,inst-id = <14>; + + port { + npu_etm0_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_npu_etm0>; + }; + }; + }; + + tpdm_mdss: tpdm@6c60000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c60000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mdss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_mdss_out_funnel_dl_north: endpoint { + remote-endpoint = + <&funnel_dl_north_in_tpdm_mdss>; + }; + }; + }; + + tpdm_dl_north: tpdm@6ac0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6ac0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-north"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dl_north_out_funnel_dl_north: endpoint { + remote-endpoint = + <&funnel_dl_north_in_tpdm_dl_north>; + }; + }; + }; + + tpdm_dlct: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dlct"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dlct0_0_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_tpdm_dlct0_0>; + }; + }; + }; + + tpdm_ipcc: tpdm@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c29000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ipcc"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dlct0_1_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_tpdm_dlct0_1>; + }; + }; + }; + + tpdm_dlct2: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c08000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dlct2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dlct2_out_funnel_dlct2: endpoint { + remote-endpoint = + <&funnel_dlct2_in_tpdm_dlct2>; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + tpdm_gpu: tpdm@6940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6940000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gpu"; + status = "disabled"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_gpu_out_funnel_gpu: endpoint { + remote-endpoint = + <&funnel_gpu_in_tpdm_gpu>; + }; + }; + }; + + tpdm_ddr: tpdm@6f80000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6f80000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + status = "disabled"; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr0: endpoint { + remote-endpoint = + <&funnel_ddr0_in_tpdm_ddr>; + }; + }; + }; + + tpdm_turing: tpdm@6980000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + tpdm_turing_llm: tpdm@6981000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6981000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing-llm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_turing_llm_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing_llm>; + }; + }; + }; + + turing_etm0: turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-turing-etm0"; + + qcom,inst-id = <13>; + + port { + turing_etm0_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_turing_etm0>; + }; + }; + }; + + tpdm_wcss: tpdm@69a4000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpdm_wcss>; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm4"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm5"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm6"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm7"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = + <&funnel_apss_in_etm7>; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_olc_out_tpda_olc0: endpoint { + remote-endpoint = + <&tpda_olc0_in_tpdm_olc>; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_llm_silver_out_tpda_llm_silver0: endpoint { + remote-endpoint = + <&tpda_llm_silver0_in_tpdm_llm_silver>; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_llm_gold_out_tpda_llm_gold0: endpoint { + remote-endpoint = + <&tpda_llm_gold0_in_tpdm_llm_gold>; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_apss_out_tpda_apss0: endpoint { + remote-endpoint = + <&tpda_apss0_in_tpdm_apss>; + }; + }; + }; + + tpdm_modem0: tpdm@6800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6800000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem-0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_modem0_out_tpda_modem0: endpoint { + remote-endpoint = + <&tpda_modem0_in_tpdm_modem0>; + }; + }; + }; + + tpdm_modem1: tpdm@6801000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6801000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem1"; + + status = "disabled"; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_modem1_out_tpda_modem1: endpoint { + remote-endpoint = + <&tpda_modem1_in_tpdm_modem1>; + }; + }; + }; + + funnel_modem_q6: funnel@680c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x680c000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem-q6"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_q6_out_funnel_mq6_dup: endpoint { + remote-endpoint = + <&funnel_mq6_dup_in_funnel_modem_q6>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_q6_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_modem_q6>; + }; + }; + }; + }; + + funnel_mq6_dup: funnel_1@680c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x680b000 0x1000>, + <0x680c000 0x1000>; + + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-modem-q6_dup"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_mq6_dup_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_funnel_mq6_dup>; + }; + }; + + port@1 { + reg = <1>; + funnel_mq6_dup_in_funnel_modem_q6: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_q6_out_funnel_mq6_dup>; + }; + }; + + port@2 { + reg = <2>; + funnel_mq6_dup_in_modem_diag: endpoint { + slave-mode; + remote-endpoint = + <&modem_diag_out_funnel_mq6_dup>; + }; + }; + }; + }; + + modem_diag: dummy_source { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-modem-diag"; + qcom,dummy-source; + + port { + modem_diag_out_funnel_mq6_dup: endpoint { + remote-endpoint = + <&funnel_mq6_dup_in_modem_diag>; + }; + }; + }; + + modem_etm0: modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm0"; + + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_modem_q6: endpoint { + remote-endpoint = + <&funnel_modem_q6_in_modem_etm0>; + }; + }; + }; + + modem2_etm0: modem2_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem2-etm0"; + + qcom,inst-id = <11>; + + port { + modem2_etm0_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_modem2_etm0>; + }; + }; + }; + + funnel_npu: funnel@6c44000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6c44000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-npu"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_npu_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_funnel_npu>; + }; + }; + + port@1 { + reg = <0>; + funnel_npu_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_funnel_npu>; + }; + }; + + port@2 { + reg = <3>; + funnel_npu_in_npu_etm0: endpoint { + slave-mode; + remote-endpoint = + <&npu_etm0_out_funnel_npu>; + }; + }; + + }; + }; + + tpda_modem: tpda@6803000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6803000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_modem_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem0_in_tpdm_modem0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem0_out_tpda_modem0>; + }; + }; + + port@2 { + reg = <1>; + tpda_modem1_in_tpdm_modem1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem1_out_tpda_modem1>; + }; + }; + + }; + }; + + funnel_modem: funnel@6804000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6804000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_modem_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_out_funnel_modem>; + }; + }; + + port@2 { + reg = <1>; + funnel_modem_in_modem2_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem2_etm0_out_funnel_modem>; + }; + }; + + port@3 { + reg = <3>; + funnel_modem_in_funnel_mq6_dup: endpoint { + slave-mode; + remote-endpoint = + <&funnel_mq6_dup_out_funnel_modem>; + }; + }; + + }; + }; + + funnel_dl_north: funnel@6ac5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6ac5000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-north"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_north_out_funnel_dlct0: endpoint { + remote-endpoint = + <&funnel_dlct0_in_funnel_dl_north>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_north_in_tpdm_mdss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mdss_out_funnel_dl_north>; + }; + }; + + port@2 { + reg = <1>; + funnel_dl_north_in_tpdm_dl_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_north_out_funnel_dl_north>; + }; + }; + + }; + }; + + funnel_dlct0: funnel@6c2d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6c2d000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlct0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dlct0_out_tpda13: endpoint { + remote-endpoint = + <&tpda13_in_funnel_dlct0>; + source = <&tpdm_npu>; + }; + + }; + + port@1 { + reg = <1>; + funnel_dlct0_out_funnel_qatb4: endpoint { + remote-endpoint = + <&funnel_qatb4_in_funnel_dlct0>; + source = <&npu_etm0>; + }; + + }; + + port@2 { + reg = <2>; + funnel_dlct0_out_tpda16: endpoint { + remote-endpoint = + <&tpda16_in_funnel_dlct0>; + source = <&tpdm_mdss>; + }; + + }; + + port@3 { + reg = <3>; + funnel_dlct0_out_tpda17: endpoint { + remote-endpoint = + <&tpda17_in_funnel_dlct0>; + source = <&tpdm_dl_north>; + }; + + }; + + port@4 { + reg = <4>; + funnel_dlct0_out_tpda21: endpoint { + remote-endpoint = + <&tpda21_in_funnel_dlct0>; + source = <&tpdm_dlct>; + }; + + }; + + port@5 { + reg = <5>; + funnel_dlct0_out_tpda22: endpoint { + remote-endpoint = + <&tpda22_in_funnel_dlct0>; + source = <&tpdm_ipcc>; + }; + + }; + + port@6 { + reg = <4>; + funnel_dlct0_in_funnel_npu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_npu_out_funnel_dlct0>; + }; + }; + + port@7 { + reg = <5>; + funnel_dlct0_in_funnel_dl_north: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_north_out_funnel_dlct0>; + }; + }; + + port@8 { + reg = <6>; + funnel_dlct0_in_tpdm_dlct0_0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct0_0_out_funnel_dlct0>; + }; + }; + + port@9 { + reg = <7>; + funnel_dlct0_in_tpdm_dlct0_1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct0_1_out_funnel_dlct0>; + }; + }; + + }; + }; + + funnel_gpu: funnel@6944000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6944000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gpu"; + status = "disabled"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_gpu_out_tpda_dl_center0: endpoint { + remote-endpoint = + <&tpda_dl_center0_in_funnel_gpu>; + }; + }; + + port@1 { + reg = <0>; + funnel_gpu_in_tpdm_gpu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gpu_out_funnel_gpu>; + }; + }; + + }; + }; + + funnel_ddr0: funnel@6f85000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6f85000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_ddr0_out_tpda_dl_center3: endpoint { + remote-endpoint = + <&tpda_dl_center3_in_funnel_ddr0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr0>; + }; + }; + + }; + }; + + funnel_turing: funnel@6983000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6983000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_turing_out_tpda_dl_center5: endpoint { + remote-endpoint = + <&tpda_dl_center5_in_funnel_turing>; + source = <&tpdm_turing>; + }; + + }; + + port@1 { + reg = <1>; + funnel_turing_out_tpda_dl_center6: endpoint { + remote-endpoint = + <&tpda_dl_center6_in_funnel_turing>; + source = <&tpdm_turing_llm>; + }; + + }; + + port@2 { + reg = <2>; + funnel_turing_out_funnel_dlct1: endpoint { + remote-endpoint = + <&funnel_dlct1_in_funnel_turing>; + source = <&turing_etm0>; + }; + + }; + + port@3 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + + port@4 { + reg = <1>; + funnel_turing_in_tpdm_turing_llm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_llm_out_funnel_turing>; + }; + }; + + port@5 { + reg = <2>; + funnel_turing_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing>; + }; + }; + + }; + }; + + tpda_dl_center: tpda@6c38000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6c38000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-dl-center"; + + qcom,tpda-atid = <78>; + qcom,dsb-elem-size = <0 32>, + <3 32>, + <5 32>, + <16 32>; + qcom,cmb-elem-size = <3 32>, + <6 32>, + <16 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_dl_center_out_funnel_dlct1: endpoint { + remote-endpoint = + <&funnel_dlct1_in_tpda_dl_center>; + }; + }; + + port@1 { + reg = <11>; + tpda_dl_center11_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda_dl_center11>; + }; + }; + + port@2 { + reg = <13>; + tpda_dl_center13_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda_dl_center13>; + }; + }; + + port@3 { + reg = <0>; + tpda_dl_center0_in_funnel_gpu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gpu_out_tpda_dl_center0>; + }; + }; + + port@4 { + reg = <3>; + tpda_dl_center3_in_funnel_ddr0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr0_out_tpda_dl_center3>; + }; + }; + + port@5 { + reg = <5>; + tpda_dl_center5_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda_dl_center5>; + }; + }; + + port@6 { + reg = <6>; + tpda_dl_center6_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda_dl_center6>; + }; + }; + + }; + }; + + funnel_dlct1: funnel@6c39000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6c39000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlct1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dlct1_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_dlct1>; + }; + }; + + port@1 { + reg = <0>; + funnel_dlct1_in_tpda_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&tpda_dl_center_out_funnel_dlct1>; + }; + }; + + port@2 { + reg = <4>; + funnel_dlct1_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_funnel_dlct1>; + }; + }; + + }; + }; + + funnel_dlct2: funnel@6c0d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6c0d000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlct2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dlct2_out_tpda2: endpoint { + remote-endpoint = + <&tpda2_in_funnel_dlct2>; + }; + }; + + port@1 { + reg = <1>; + funnel_dlct2_in_tpdm_dlct2: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct2_out_funnel_dlct2>; + }; + }; + + }; + }; + + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_funnel_apss>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_olc>; + }; + }; + + port@1 { + reg = <0>; + tpda_olc0_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc0>; + }; + }; + + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver0_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver0>; + }; + }; + + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold0_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold0>; + }; + }; + + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <3 32>; + qcom,cmb-elem-size = <0 32>, + <1 32>, + <2 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merge: endpoint { + remote-endpoint = + <&funnel_apss_merge_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss0_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss0>; + }; + }; + + }; + }; + + funnel_apss_merge: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merge"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss_merge_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merge>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merge_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merge>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merge_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merge>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merge_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merge>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merge_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merge>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merge_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merge>; + }; + }; + + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <16 32>, + <24 32>, + <25 32>; + qcom,tc-elem-size = <16 32>, + <25 32>; + qcom,dsb-elem-size = <1 32>, + <6 32>, + <7 32>, + <10 32>, + <11 32>, + <12 32>, + <13 32>, + <14 32>, + <16 32>, + <19 32>, + <24 32>, + <25 32>; + qcom,cmb-elem-size = <7 64>, + <13 32>, + <15 32>, + <16 32>, + <17 32>, + <18 64>, + <20 64>, + <21 64>, + <22 32>, + <23 32>, + <25 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <24>; + tpda24_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda24>; + }; + }; + + port@2 { + reg = <25>; + tpda25_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda25>; + }; + }; + + port@3 { + reg = <27>; + tpda27_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda27>; + }; + }; + + port@4 { + reg = <0>; + tpda0_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_tpda0>; + }; + }; + + port@5 { + reg = <13>; + tpda13_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda13>; + }; + }; + + port@6 { + reg = <16>; + tpda16_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda16>; + }; + }; + + port@7 { + reg = <17>; + tpda17_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda17>; + }; + }; + + port@8 { + reg = <21>; + tpda21_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda21>; + }; + }; + + port@9 { + reg = <22>; + tpda22_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_tpda22>; + }; + }; + + port@10 { + reg = <2>; + tpda2_in_funnel_dlct2: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct2_out_tpda2>; + }; + }; + + }; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <4>; + funnel_qatb4_in_funnel_dlct0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct0_out_funnel_qatb4>; + }; + }; + + }; + }; + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,perflsheot-set-support; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@6b0c000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0c000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in0_out_funnel_merge: endpoint { + remote-endpoint = + <&funnel_merge_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = + <&stm_out_funnel_in0>; + }; + }; + + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in1_out_funnel_merge: endpoint { + remote-endpoint = + <&funnel_merge_in_funnel_in1>; + }; + }; + + port@1 { + reg = <2>; + funnel_in1_in_funnel_dlct1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct1_out_funnel_in1>; + }; + }; + + port@2 { + reg = <3>; + funnel_in1_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_in1>; + }; + }; + + port@3 { + reg = <4>; + funnel_in1_in_funnel_apss_merge: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merge_out_funnel_in1>; + }; + }; + + port@4 { + reg = <6>; + funnel_in1_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_in1>; + }; + }; + + }; + }; + + funnel_merge: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merge"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_merge_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_funnel_merge>; + }; + }; + + port@1 { + reg = <1>; + funnel_merge_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merge>; + }; + }; + + port@2 { + reg = <0>; + funnel_merge_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merge>; + }; + }; + + }; + }; + + tpda_swao: tpda@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b08000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + }; + + port@1 { + reg = <0>; + tpda_swao0_in_tpdm_swao_0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao_0_out_tpda_swao0>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao1_in_tpdm_swao_1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao_1_out_tpda_swao1>; + }; + }; + + }; + }; + + funnel_swao: funnel@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x6b04000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_swao>; + }; + }; + + port@1 { + reg = <5>; + funnel_swao_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <5>; + funnel_swao_in_tpdm_lpass_lpi: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_lpi_out_funnel_swao>; + }; + }; + + port@3 { + reg = <6>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint = + <&tpda_swao_out_funnel_swao>; + }; + }; + + port@4 { + reg = <7>; + funnel_swao_in_funnel_merge: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merge_out_funnel_swao>; + }; + }; + + }; + }; + + tmc_etf: tmc@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + reg = <0x6b05000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti_swao_cti0 &cti_swao_cti3>; + coresight-csr = <&swao_csr>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etf_out_replicator_swao: endpoint { + remote-endpoint = + <&replicator_swao_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint = + <&funnel_swao_out_tmc_etf>; + }; + }; + + }; + }; + + replicator_swao: replicator@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + reg = <0x6b06000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + replicator_swao_out_replicator_qdss: endpoint { + remote-endpoint = + <&replicator_qdss_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator_swao>; + }; + }; + + }; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + replicator_qdss_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator_qdss>; + }; + }; + + port@1 { + reg = <0>; + replicator_qdss_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_replicator_qdss>; + }; + }; + + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + qcom,iommu-dma = "bypass"; + iommus = <&apps_smmu 0x0480 0x20>, + <&apps_smmu 0x04a0 0x20>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + arm,scatter-gather; + + qcom,sw-usb; + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti_swao_cti3>; + coresight-csr = <&csr>; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etr_in_replicator_qdss: endpoint { + slave-mode; + remote-endpoint = + <&replicator_qdss_out_tmc_etr>; + }; + }; + + }; + }; + + cti_apss_cti0: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_apss_cti1: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_apss_cti2: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,cti-gpio-trigout = <0>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss: cti@680b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x680b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_dl_cti: cti@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6845000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass_dl_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_isdb_cti: cti@6941000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6941000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-gpu_isdb_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_cortex_m3: cti@6942000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6942000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-gpu_cortex_m3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_dl_cti: cti@6982000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6982000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_dl_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_q6_cti: cti@698b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x698b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_q6_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti0: cti@6ac1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6ac1000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dl-north_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti1: cti@6ac2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6ac2000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dl-north_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti2: cti@6ac3000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6ac3000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dl-north_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_north_cti3: cti@6ac4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6ac4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dl-north_cti3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti0: cti@6b00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b00000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti1: cti@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b01000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti2: cti@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_swao_cti3: cti@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b0e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b0e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-aop-m3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_lpi_cti: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-lpass_lpi_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_q6_cti: cti@6b2B000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b2B000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-lpass_q6_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct2_cti0: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct2_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct2_cti1: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct2_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct2_cti2: cti@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c0b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct2_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct2_cti3: cti@6c0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c0c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct2_cti3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct0_cti0: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct0_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct0_cti1: cti@6c2b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct0_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct0_cti2: cti@6c2c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct0_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl_cti_0: cti@6c42000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c42000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl_cti_1: cti@6c43000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c43000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_q6_cti: cti@6c4b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c4b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_q6_cti"; + status = "disabled"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_sierra_a6_cti: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-sierra_a6_cti"; + status = "disabled"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mdss_dl_cti: cti@6c61000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c61000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mdss_dl_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_0_cti_0: cti@6f82000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6f82000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_0_cti_1: cti@6f83000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6f83000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_0_cti_2: cti@6f84000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6f84000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_1_cti_0: cti@6f90000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6f90000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_1_cti_1: cti@6f91000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6f91000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_ddr_dl_1_cti_2: cti@6f92000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6f92000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_olc: cti@7831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7831000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-olc"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dl_apss: cti@7861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7861000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dl-apss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + ipcb_tgu: tgu@6b0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb999>; + reg = <0x06b0b000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-gdsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-gdsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..622945e955c80fcf7bc2c431eb871232181fa9e8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-gdsc.dtsi @@ -0,0 +1,148 @@ +&soc { + /* GDSCs in GCC */ + gcc_ufs_phy_gdsc: qcom,gdsc@13a004 { + compatible = "qcom,gdsc"; + reg = <0x13a004 0x4>; + regulator-name = "gcc_ufs_phy_gdsc"; + status = "disabled"; + }; + + gcc_usb30_prim_gdsc: qcom,gdsc@11a004 { + compatible = "qcom,gdsc"; + reg = <0x11a004 0x4>; + regulator-name = "gcc_usb30_prim_gdsc"; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc: qcom,gdsc@1b7040 { + compatible = "qcom,gdsc"; + reg = <0x1b7040 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_sf_gdsc: qcom,gdsc@1b7044 { + compatible = "qcom,gdsc"; + reg = <0x1b7044 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + /* GDSCs in CAMCC */ + cam_cc_bps_gdsc: qcom,gdsc@ad06004 { + compatible = "qcom,gdsc"; + reg = <0xad06004 0x4>; + regulator-name = "cam_cc_bps_gdsc"; + status = "disabled"; + }; + + cam_cc_ife_0_gdsc: qcom,gdsc@ad09004 { + compatible = "qcom,gdsc"; + reg = <0xad09004 0x4>; + regulator-name = "cam_cc_ife_0_gdsc"; + status = "disabled"; + }; + + cam_cc_ife_1_gdsc: qcom,gdsc@ad0a004 { + compatible = "qcom,gdsc"; + reg = <0xad0a004 0x4>; + regulator-name = "cam_cc_ife_1_gdsc"; + status = "disabled"; + }; + + cam_cc_ife_2_gdsc: qcom,gdsc@ad0b004 { + compatible = "qcom,gdsc"; + reg = <0xad0b004 0x4>; + regulator-name = "cam_cc_ife_2_gdsc"; + status = "disabled"; + }; + + cam_cc_ipe_0_gdsc: qcom,gdsc@ad07004 { + compatible = "qcom,gdsc"; + reg = <0xad07004 0x4>; + regulator-name = "cam_cc_ipe_0_gdsc"; + status = "disabled"; + }; + + cam_cc_titan_top_gdsc: qcom,gdsc@ad14004 { + compatible = "qcom,gdsc"; + reg = <0xad14004 0x4>; + regulator-name = "cam_cc_titan_top_gdsc"; + status = "disabled"; + }; + + /* GDSCs in DISPCC */ + mdss_core_gdsc: qcom,gdsc@af01004 { + compatible = "qcom,gdsc"; + reg = <0xaf01004 0x4>; + regulator-name = "mdss_core_gdsc"; + qcom,support-hw-trigger; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + status = "disabled"; + }; + + /* GDSCs in GPUCC */ + gpu_gx_domain_addr: syscon@3d91508 { + compatible = "syscon"; + reg = <0x3d91508 0x4>; + }; + + gpu_gx_sw_reset: syscon@3d91008 { + compatible = "syscon"; + reg = <0x3d91008 0x4>; + }; + + gpu_cx_hw_ctrl: syscon@3d91540 { + compatible = "syscon"; + reg = <0x3d91540 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@3d9106c { + compatible = "qcom,gdsc"; + reg = <0x3d9106c 0x4>; + regulator-name = "gpu_cx_gdsc"; + hw-ctl-addr = <&gpu_cx_hw_ctrl>; + qcom,no-status-check-on-disable; + qcom,clk-dis-wait-val = <8>; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + gpu_gx_gdsc: qcom,gdsc@3d9100c { + compatible = "qcom,gdsc"; + reg = <0x3d9100c 0x4>; + regulator-name = "gpu_gx_gdsc"; + sw-reset = <&gpu_gx_sw_reset>; + domain-addr = <&gpu_gx_domain_addr>; + qcom,skip-disable-before-sw-enable; + status = "disabled"; + }; + + /* GDSCs in NPUCC */ + npu_cc_core_gdsc: qcom,gdsc@9981004 { + compatible = "qcom,gdsc"; + reg = <0x9981004 0x4>; + regulator-name = "npu_cc_core_gdsc"; + status = "disabled"; + }; + + /* GDSCs in VIDEOCC */ + video_cc_mvs0_gdsc: qcom,gdsc@aaf3004 { + compatible = "qcom,gdsc"; + reg = <0xaaf3004 0x4>; + regulator-name = "video_cc_mvs0_gdsc"; + status = "disabled"; + }; + + video_cc_mvsc_gdsc: qcom,gdsc@aaf2004 { + compatible = "qcom,gdsc"; + reg = <0xaaf2004 0x4>; + regulator-name = "video_cc_mvsc_gdsc"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5b96770028f1023c37a061da67cfc604c5485c84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-gpu.dtsi @@ -0,0 +1,629 @@ +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + +&soc { + + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a615_zap"; + }; + + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + operating-points-v2 = <&gpu_opp_table>; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-850000000 { + opp-hz = /bits/ 64 <850000000>; + opp-microvolt = ; + }; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = ; + }; + + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + opp-microvolt = ; + }; + + opp-565000000 { + opp-hz = /bits/ 64 <565000000>; + opp-microvolt = ; + }; + + opp-430000000 { + opp-hz = /bits/ 64 <430000000>; + opp-microvolt = ; + }; + + opp-355000000 { + opp-hz = /bits/ 64 <355000000>; + opp-microvolt = ; + }; + + opp-253000000 { + opp-hz = /bits/ 64 <253000000>; + opp-microvolt = ; + }; + }; + + msm_gpu: qcom,kgsl-3d0@3d00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x3d00000 0x40000>, + <0x3d61000 0x800>, + <0x3d9e000 0x1000>; + reg-names = "kgsl_3d0_reg_memory", + "cx_dbgc", "cx_misc"; + interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x06010900>; + + qcom,gpu-quirk-hfi-use-reg; + qcom,gpu-quirk-secvid-set-once; + + /* */ + qcom,idle-timeout = <80>; + qcom,no-nap; + + qcom,highest-bank-bit = <14>; + qcom,min-access-length = <32>; + qcom,ubwc-mode = <2>; + + /* size in bytes */ + qcom,snapshot-size = <0x200000>; + + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_CX_GMU_CLK>; + + clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk"; + + /* QDSS_STM base addr, size */ + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; + + #cooling-cells = <2>; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <13>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 800000>, /* 2 bus=200 */ + <26 512 0 1200000>, /* 3 bus=300 */ + <26 512 0 1804800>, /* 4 bus=451 */ + <26 512 0 2188000>, /* 5 bus=547 */ + <26 512 0 2724000>, /* 6 bus=681 */ + <26 512 0 3072000>, /* 7 bus=768 */ + <26 512 0 4068000>, /* 8 bus=1017 */ + <26 512 0 5412000>, /* 9 bus=1353 */ + <26 512 0 6220000>, /* 10 bus=1555 */ + <26 512 0 7216000>, /* 11 bus=1804 */ + <26 512 0 8371200>; /* 12 bus=2092 */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + nvmem-cells = <&gpu_speed_bin>, <&gpu_gaming_bin>; + nvmem-cell-names = "speed_bin", "gaming_bin"; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <67>; + qcom,pm-qos-wakeup-latency = <67>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* GPU OPP data */ + operating-points-v2 = <&gpu_opp_table>; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calulated as FMAX/4.8 MHz (round up to zero + * decimal places) + 2. + */ + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <0>; + qcom,ca-target-pwrlevel = <5>; + qcom,initial-pwrlevel = <6>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <850000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <800000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <253000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <180>; + qcom,ca-target-pwrlevel = <5>; + qcom,initial-pwrlevel = <6>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <850000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <800000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <253000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <169>; + qcom,ca-target-pwrlevel = <4>; + qcom,initial-pwrlevel = <5>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <800000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <253000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <120>; + qcom,ca-target-pwrlevel = <2>; + qcom,initial-pwrlevel = <3>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <253000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-4 { + #address-cells = <1>; + #size-cells = <0>; + qcom,speed-bin = <138>; + qcom,ca-target-pwrlevel = <3>; + qcom,initial-pwrlevel = <4>; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <8>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <565000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <355000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <253000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + qcom,cpu-to-gpu-cfg-path { + qcom,msm-bus,name = "gpu_cfg"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 598 0 0>, // off + <1 598 0 100>, // min freq + <1 598 0 9999999>; // max freq + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@3d40000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x3d40000 0x10000>; + qcom,protect = <0x40000 0x10000>; + qcom,micro-mmu-control = <0x6000>; + + clocks = <&gcc GCC_GPU_CFG_AHB_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>; + + clock-names = "iface_clk", "mem_clk", "mem_iface_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,iommu-dma = "disabled"; + qcom,gpu-offset = <0x48000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + qcom,iommu-dma = "disabled"; + iommus = <&kgsl_smmu 2>; + }; + }; + + gmu: qcom,gmu@3d6a000 { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = <0x3d6a000 0x31000>, + <0xb290000 0x10000>, + <0xb490000 0x10000>; + reg-names = "kgsl_gmu_reg", + "kgsl_gmu_pdc_cfg", + "kgsl_gmu_pdc_seq"; + + interrupts = <0 304 IRQ_TYPE_LEVEL_HIGH>, + <0 305 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq"; + + qcom,msm-bus,name = "cnoc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 10036 0 0>, /* CNOC off */ + <26 10036 0 100>; /* CNOC on */ + + regulator-names = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>; + + clock-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk"; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 4>; + qcom,iommu-dma = "disabled"; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 5>; + qcom,iommu-dma = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-ion.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9942c82775abf46f7d54096f23f58267b9674e84 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-ion.dtsi @@ -0,0 +1,44 @@ +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + system_secure_heap: qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@14 { /* SECURE CARVEOUT HEAP */ + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + cdsp { + memory-region = <&cdsp_sec_mem>; + token = <0x20000000>; + }; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-lpi.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d7b1af6b044d82b4539e76a9c14ee3d48e64b910 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-lpi.dtsi @@ -0,0 +1,1717 @@ +&q6core { + lpi_tlmm: lpi_pinctrl@33c0000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0x33c0000 0x0>; + qcom,slew-reg = <0x355a000 0x0>; + qcom,num-gpios = <15>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = <0x00000000>, <0x00001000>, + <0x00002000>, <0x00003000>, + <0x00004000>, <0x00005000>, + <0x00006000>, <0x00007000>, + <0x00008000>, <0x00009000>, + <0x0000A000>, <0x0000B000>, + <0x0000C000>, <0x0000D000>, + <0x0000E000>; + qcom,lpi-slew-offset-tbl = <0x00000000>, <0x00000002>, + <0x00000004>, <0x00000008>, + <0x0000000A>, <0x0000000C>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000010>, <0x00000012>, + <0x00000000>, <0x00000000>, + <0x00000000>; + qcom,lpi-slew-base-tbl = <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x0355C000>; + + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + + quat_mi2s_sck { + quat_mi2s_sck_sleep: quat_mi2s_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sck_active: quat_mi2s_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_ws { + quat_mi2s_ws_sleep: quat_mi2s_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_ws_active: quat_mi2s_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sck { + lpi_i2s1_sck_sleep: lpi_i2s1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sck_active: lpi_i2s1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_ws { + lpi_i2s1_ws_sleep: lpi_i2s1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_ws_active: lpi_i2s1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd0 { + lpi_i2s1_sd0_sleep: lpi_i2s1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd0_active: lpi_i2s1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd1 { + lpi_i2s1_sd1_sleep: lpi_i2s1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd1_active: lpi_i2s1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sck { + lpi_i2s2_sck_sleep: lpi_i2s2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sck_active: lpi_i2s2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_ws { + lpi_i2s2_ws_sleep: lpi_i2s2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_ws_active: lpi_i2s2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd0 { + lpi_i2s2_sd0_sleep: lpi_i2s2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd0_active: lpi_i2s2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd1 { + lpi_i2s2_sd1_sleep: lpi_i2s2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd1_active: lpi_i2s2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sck { + quat_tdm_sck_sleep: quat_tdm_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sck_active: quat_tdm_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_ws { + quat_tdm_ws_sleep: quat_tdm_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_ws_active: quat_tdm_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd0 { + quat_tdm_sd0_sleep: quat_tdm_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd0_active: quat_tdm_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd1 { + quat_tdm_sd1_sleep: quat_tdm_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd1_active: quat_tdm_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd2 { + quat_tdm_sd2_sleep: quat_tdm_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd2_active: quat_tdm_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd3 { + quat_tdm_sd3_sleep: quat_tdm_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd3_active: quat_tdm_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sck { + lpi_tdm1_sck_sleep: lpi_tdm1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sck_active: lpi_tdm1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_ws { + lpi_tdm1_ws_sleep: lpi_tdm1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_ws_active: lpi_tdm1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd0 { + lpi_tdm1_sd0_sleep: lpi_tdm1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd0_active: lpi_tdm1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd1 { + lpi_tdm1_sd1_sleep: lpi_tdm1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd1_active: lpi_tdm1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sck { + lpi_tdm2_sck_sleep: lpi_tdm2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sck_active: lpi_tdm2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_ws { + lpi_tdm2_ws_sleep: lpi_tdm2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_ws_active: lpi_tdm2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd0 { + lpi_tdm2_sd0_sleep: lpi_tdm2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd0_active: lpi_tdm2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd1 { + lpi_tdm2_sd1_sleep: lpi_tdm2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd1_active: lpi_tdm2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sck { + quat_aux_sck_sleep: quat_aux_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sck_active: quat_aux_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_ws { + quat_aux_ws_sleep: quat_aux_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_ws_active: quat_aux_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd0 { + quat_aux_sd0_sleep: quat_aux_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd0_active: quat_aux_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd1 { + quat_aux_sd1_sleep: quat_aux_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd1_active: quat_aux_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd2 { + quat_aux_sd2_sleep: quat_aux_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd2_active: quat_aux_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd3 { + quat_aux_sd3_sleep: quat_aux_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd3_active: quat_aux_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sck { + lpi_aux1_sck_sleep: lpi_aux1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sck_active: lpi_aux1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_ws { + lpi_aux1_ws_sleep: lpi_aux1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_ws_active: lpi_aux1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd0 { + lpi_aux1_sd0_sleep: lpi_aux1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd0_active: lpi_aux1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd1 { + lpi_aux1_sd1_sleep: lpi_aux1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd1_active: lpi_aux1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sck { + lpi_aux2_sck_sleep: lpi_aux2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sck_active: lpi_aux2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_ws { + lpi_aux2_ws_sleep: lpi_aux2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_ws_active: lpi_aux2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd0 { + lpi_aux2_sd0_sleep: lpi_aux2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd0_active: lpi_aux2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd1 { + lpi_aux2_sd1_sleep: lpi_aux2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd1_active: lpi_aux2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + wsa_swr_clk_pin { + wsa_swr_clk_sleep: wsa_swr_clk_sleep { + mux { + pins = "gpio10"; + function = "func2"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + wsa_swr_clk_active: wsa_swr_clk_active { + mux { + pins = "gpio10"; + function = "func2"; + }; + + config { + pins = "gpio10"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + }; + + wsa_swr_data_pin { + wsa_swr_data_sleep: wsa_swr_data_sleep { + mux { + pins = "gpio11"; + function = "func2"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + wsa_swr_data_active: wsa_swr_data_active { + mux { + pins = "gpio11"; + function = "func2"; + }; + + config { + pins = "gpio11"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + }; + + tx_swr_clk_sleep: tx_swr_clk_sleep { + mux { + pins = "gpio0"; + function = "func1"; + input-enable; + bias-pull-down; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + }; + }; + + tx_swr_clk_active: tx_swr_clk_active { + mux { + pins = "gpio0"; + function = "func1"; + }; + + config { + pins = "gpio0"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + + tx_swr_data1_sleep: tx_swr_data1_sleep { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; + input-enable; + bias-bus-hold; + }; + }; + + tx_swr_data1_active: tx_swr_data1_active { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + tx_swr_data2_sleep: tx_swr_data2_sleep { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data2_active: tx_swr_data2_active { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + tx_swr_data3_sleep: tx_swr_data3_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data3_active: tx_swr_data3_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + rx_swr_clk_sleep: rx_swr_clk_sleep { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_clk_active: rx_swr_clk_active { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + + rx_swr_data_sleep: rx_swr_data_sleep { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data_active: rx_swr_data_active { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + rx_swr_data1_sleep: rx_swr_data1_sleep { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data1_active: rx_swr_data1_active { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + cdc_dmic01_clk_active: dmic01_clk_active { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic01_clk_sleep: dmic01_clk_sleep { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic01_data_active: dmic01_data_active { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic01_data_sleep: dmic01_data_sleep { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic23_clk_active: dmic23_clk_active { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic23_clk_sleep: dmic23_clk_sleep { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic23_data_active: dmic23_data_active { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic23_data_sleep: dmic23_data_sleep { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic45_clk_active: dmic45_clk_active { + mux { + pins = "gpio12"; + function = "func1"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic45_clk_sleep: dmic45_clk_sleep { + mux { + pins = "gpio12"; + function = "func1"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic45_data_active: dmic45_data_active { + mux { + pins = "gpio13"; + function = "func1"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic45_data_sleep: dmic45_data_sleep { + mux { + pins = "gpio13"; + function = "func1"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..51c01cf65b0113c10557a54bb3ff1c8865b86fa0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "lagoon-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon MTP"; + compatible = "qcom,lagoon-mtp", "qcom,lagoon", "qcom,mtp"; + qcom,msm-id = <434 0x10000>, <459 0x10000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7eb0528cfe2419f9718beb936b7263228e93d981 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "lagoon-mtp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon MTP USBC audio"; + compatible = "qcom,lagoon-mtp", "qcom,lagoon", "qcom,mtp"; + qcom,msm-id = <434 0x10000>, <459 0x10000>; + qcom,board-id = <8 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc.dts new file mode 100644 index 0000000000000000000000000000000000000000..bd8339282b8635c60f1ccc1b005fc6e65d44f7b9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "lagoon.dtsi" +#include "lagoon-mtp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon MTP USBC audio"; + compatible = "qcom,lagoon-mtp", "qcom,lagoon", "qcom,mtp"; + qcom,board-id = <8 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..464143a99bcfb10d37902f1a3cf0c6e93bd60e26 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp-usbc.dtsi @@ -0,0 +1,11 @@ +#include "lagoon-mtp.dtsi" + +&soc { + +}; + +&lagoon_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..1f288e81befd40fb0e82293859f2941b940d4477 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "lagoon.dtsi" +#include "lagoon-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon MTP"; + compatible = "qcom,lagoon-mtp", "qcom,lagoon", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..00da3bba5a90e0aab52964a6a737d3b9b7288ecb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-mtp.dtsi @@ -0,0 +1,321 @@ +#include "lagoon-audio-overlay.dtsi" +#include +#include +#include +#include "lagoon-sde-display.dtsi" +#include "camera/lagoon-camera-sensor-mtp.dtsi" +#include +#include "lagoon-thermal-overlay.dtsi" + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + #include "qg-batterydata-atl436186020H_3780mAh.dtsi" + }; +}; + +&pm6350_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&L18A>; + vdda-pll-supply = <&L22A>; + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L7E>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&L12A>; + vccq2-voltage-level = <1800000 1800000>; + vcc-max-microamp = <800000>; + vccq2-min-microamp = <0>; + vccq2-max-microamp = <800000>; + vccq2-pwr-collapse-sup; + + qcom,vddp-ref-clk-supply = <&L22A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&L7E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L12A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L9E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L6E>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pm6150a_amoled { + status = "ok"; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>, + <&pm7250b_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage", + "skin_temp"; + qcom,battery-data = <&mtp_batterydata>; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; + qcom,fcc-step-delay-ms = <100>; + qcom,fcc-step-size-ua = <100000>; + qcom,smb-internal-pull-kohm = <0>; + qcom,en-skin-therm-mitigation; + qcom,hvdcp3-standalone-config; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,battery-data = <&mtp_batterydata>; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3300>; + qcom,bass-enable; + qcom,use-cp-iin-sns; +}; + +&dsi_rm69299_visionox_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_rm69299_visionox_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_rm69299_visionox_amoled_video>; +}; + +&qupv3_se0_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 9 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 8 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + qcom,nq-vdd-1p8-supply = <&L11A>; + qcom,nq-vdd-1p8-voltage = <1800000 1800000>; + qcom,nq-vdd-1p8-current = <157000>; + interrupt-parent = <&tlmm>; + interrupts = <9 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&qupv3_se8_i2c { + status = "okay"; + qcom,i2c-touch-active="synaptics,tcm-i2c"; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <22 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + vdd-supply = <&L11A>; + avdd-supply = <&L6A>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,irq-gpio = <&tlmm 22 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 21 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware.img"; + + panel = <&dsi_rm69299_visionox_amoled_video + &dsi_rm69299_visionox_amoled_cmd>; + }; +}; + +&pm7250b_vadc { + smb1390_therm@e { + qcom,scale-fn-type = ; + }; +}; + +&pm7250b_gpios { + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&thermal_zones { + quiet-therm-step { + status = "disabled"; + }; +}; + +&qupv3_se10_i2c { + qcom,clk-freq-out = <100000>; + status = "ok"; + #include "smb1398.dtsi" +}; + +&smb1396 { + interrupts = <0x2 0xc5 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&spmi_bus>; + interrupt-names = "smb1396"; + pinctrl-names = "default"; + qcom,enable-toggle-stat; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1396_div2_cp_master { + io-channels = <&pm7250b_vadc ADC_AMUX_THM2>; + qcom,parallel-input-mode = <1>; /* USBIN */ + qcom,parallel-output-mode = <2>; /* VBAT */ + qcom,div2-cp-min-ilim-ua = <750000>; + status = "ok"; +}; + +&smb1396_slave { + status = "ok"; +}; + +&smb1396_div2_cp_slave { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-npu.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-npu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e4586666f00630a12e324d27cb05cbf405f5b20b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-npu.dtsi @@ -0,0 +1,165 @@ +&soc { + msm_npu: qcom,msm_npu@9800000 { + compatible = "qcom,msm-npu"; + status = "ok"; + reg = <0x9900000 0x20000>, + <0x99F0000 0x10000>, + <0x9980000 0x10000>, + <0x17c00000 0x10000>, + <0x01F40000 0x40000>, + <0x780000 0x7000>; + reg-names = "tcm", "core", "cc", "apss_shared", "tcsr", + "qfprom_physical"; + interrupts = , + , + , + ; + interrupt-names = "error_irq", "wdg_bite_irq", "ipc_irq", + "general_irq"; + iommus = <&apps_smmu 0x1441 0x00>, <&apps_smmu 0x1442 0x00>, + <&apps_smmu 0x1461 0x00>, <&apps_smmu 0x1462 0x00>, + <&apps_smmu 0x1481 0x00>, <&apps_smmu 0x1482 0x00>; + qcom,npu-dsp-sid-mapped; + + clocks = <&npucc NPU_CC_XO_CLK>, + <&npucc NPU_CC_CORE_CLK>, + <&npucc NPU_CC_CAL_HM0_CLK>, + <&npucc NPU_CC_CAL_HM0_CDC_CLK>, + <&npucc NPU_CC_NOC_AXI_CLK>, + <&npucc NPU_CC_NOC_AHB_CLK>, + <&npucc NPU_CC_NOC_DMA_CLK>, + <&npucc NPU_CC_RSC_XO_CLK>, + <&npucc NPU_CC_S2P_CLK>, + <&npucc NPU_CC_BWMON_CLK>, + <&npucc NPU_CC_CAL_HM0_PERF_CNT_CLK>, + <&npucc NPU_CC_BTO_CORE_CLK>, + <&npucc NPU_DSP_CORE_CLK_SRC>; + clock-names = "xo_clk", + "npu_core_clk", + "cal_hm0_clk", + "cal_hm0_cdc_clk", + "axi_clk", + "ahb_clk", + "dma_clk", + "rsc_xo_clk", + "s2p_clk", + "bwmon_clk", + "cal_hm0_perf_cnt_clk", + "bto_core_clk", + "dsp_core_clk_src"; + + vdd-supply = <&npu_cc_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names ="vdd", "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + #cooling-cells = <2>; + mboxes = <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_GLINK_QMP>, + <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_SMP2P>, + <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_PING>; + mbox-names = "ipcc-glink", "ipcc-smp2p", "ipcc-ping"; + #mbox-cells = <2>; + qcom,npubw-devs = <&npu_npu_llcc_bw &npu_llcc_ddr_bw &npudsp_npu_ddr_bw>; + qcom,npubw-dev-names = "npu_llcc_bw", "llcc_ddr_bw", "dsp_ddr_bw"; + qcom,src-dst-ports = , + ; + qcom,npu-cxlimit-enable; + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <4>; + qcom,npu-pwrlevel@0 { + reg = <0>; + vreg = <1>; + clk-freq = <19200000 + 100000000 + 192000000 + 192000000 + 150000000 + 30000000 + 200000000 + 19200000 + 50000000 + 19200000 + 192000000 + 19200000 + 300000000>; + }; + + qcom,npu-pwrlevel@1 { + reg = <1>; + vreg = <2>; + clk-freq = <19200000 + 200000000 + 268800000 + 268800000 + 200000000 + 37500000 + 300000000 + 19200000 + 50000000 + 19200000 + 268800000 + 19200000 + 400000000>; + }; + + qcom,npu-pwrlevel@2 { + reg = <2>; + vreg = <3>; + clk-freq = <19200000 + 333000000 + 403200000 + 403200000 + 300000000 + 37500000 + 403000000 + 19200000 + 50000000 + 19200000 + 403200000 + 19200000 + 500000000>; + }; + + qcom,npu-pwrlevel@3 { + reg = <3>; + vreg = <4>; + clk-freq = <19200000 + 428000000 + 515000000 + 515000000 + 403000000 + 75000000 + 600000000 + 19200000 + 100000000 + 19200000 + 515000000 + 19200000 + 660000000>; + }; + + qcom,npu-pwrlevel@4 { + reg = <4>; + vreg = <6>; + clk-freq = <19200000 + 500000000 + 748800000 + 748800000 + 533000000 + 75000000 + 710000000 + 19200000 + 100000000 + 19200000 + 748800000 + 19200000 + 800000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-pinctrl.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bc95634b8700739329116ed2ddd7731b0b7f6f7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-pinctrl.dtsi @@ -0,0 +1,1373 @@ +&soc { + tlmm: pinctrl@f100000 { + compatible = "qcom,lagoon-pinctrl"; + reg = <0x0f100000 0x300000>; + interrupts = , + , + , + , + , + , + , + , + ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + irqdomain-map = <3 0 &pdc 126 0>, + <4 0 &pdc 151 0>, + <7 0 &pdc 58 0>, + <8 0 &pdc 113 0>, + <9 0 &pdc 66 0>, + <11 0 &pdc 106 0>, + <12 0 &pdc 59 0>, + <13 0 &pdc 112 0>, + <16 0 &pdc 73 0>, + <17 0 &pdc 74 0>, + <18 0 &pdc 75 0>, + <19 0 &pdc 76 0>, + <21 0 &pdc 130 0>, + <22 0 &pdc 96 0>, + <23 0 &pdc 146 0>, + <24 0 &pdc 114 0>, + <25 0 &pdc 83 0>, + <27 0 &pdc 84 0>, + <28 0 &pdc 85 0>, + <34 0 &pdc 147 0>, + <35 0 &pdc 92 0>, + <36 0 &pdc 93 0>, + <37 0 &pdc 94 0>, + <38 0 &pdc 68 0>, + <48 0 &pdc 100 0>, + <50 0 &pdc 57 0>, + <51 0 &pdc 81 0>, + <52 0 &pdc 80 0>, + <53 0 &pdc 69 0>, + <54 0 &pdc 71 0>, + <55 0 &pdc 70 0>, + <57 0 &pdc 152 0>, + <58 0 &pdc 115 0>, + <59 0 &pdc 116 0>, + <60 0 &pdc 117 0>, + <61 0 &pdc 118 0>, + <62 0 &pdc 119 0>, + <64 0 &pdc 121 0>, + <66 0 &pdc 127 0>, + <67 0 &pdc 128 0>, + <69 0 &pdc 60 0>, + <73 0 &pdc 78 0>, + <78 0 &pdc 135 0>, + <82 0 &pdc 138 0>, + <83 0 &pdc 140 0>, + <84 0 &pdc 141 0>, + <85 0 &pdc 98 0>, + <87 0 &pdc 88 0>, + <88 0 &pdc 107 0>, + <89 0 &pdc 109 0>, + <90 0 &pdc 110 0>, + <91 0 &pdc 111 0>, + <92 0 &pdc 149 0>, + <93 0 &pdc 101 0>, + <94 0 &pdc 61 0>, + <95 0 &pdc 65 0>, + <96 0 &pdc 95 0>, + <97 0 &pdc 72 0>, + <98 0 &pdc 145 0>, + <99 0 &pdc 150 0>, + <100 0 &pdc 108 0>, + <104 0 &pdc 129 0>, + <107 0 &pdc 131 0>, + <110 0 &pdc 132 0>, + <112 0 &pdc 133 0>, + <114 0 &pdc 134 0>, + <116 0 &pdc 136 0>, + <118 0 &pdc 137 0>, + <122 0 &pdc 97 0>, + <123 0 &pdc 99 0>, + <124 0 &pdc 148 0>, + <125 0 &pdc 82 0>, + <128 0 &pdc 144 0>, + <129 0 &pdc 86 0>, + <131 0 &pdc 87 0>, + <133 0 &pdc 142 0>, + <134 0 &pdc 143 0>, + <136 0 &pdc 102 0>, + <137 0 &pdc 91 0>, + <138 0 &pdc 77 0>, + <139 0 &pdc 79 0>, + <140 0 &pdc 90 0>, + <142 0 &pdc 103 0>, + <144 0 &pdc 105 0>, + <147 0 &pdc 104 0>, + <153 0 &pdc 120 0>, + <155 0 &pdc 67 0>; + irqdomain-map-mask = <0xff 0>; + irqdomain-map-pass-thru = <0 0xff>; + + trigout_a: trigout_a { + mux { + pins = "gpio87"; + function = "qdss_cti"; + }; + + config { + pins = "gpio87"; + drive-strength = <2>; + bias-disable; + }; + }; + + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + + qupv3_se7_2uart_pins: qupv3_se7_2uart_pins { + qupv3_se7_2uart_active: qupv3_se7_2uart_active { + mux { + pins = "gpio27", "gpio28"; + function = "qup11"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_2uart_sleep: qupv3_se7_2uart_sleep { + mux { + pins = "gpio27", "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se9_2uart_pins: qupv3_se9_2uart_pins { + qupv3_se9_2uart_active: qupv3_se9_2uart_active { + mux { + pins = "gpio25", "gpio26"; + function = "qup13_f2"; + }; + + config { + pins = "gpio25", "gpio26"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_2uart_sleep: qupv3_se9_2uart_sleep { + mux { + pins = "gpio25", "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio25", "gpio26"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se1_4uart_pins: qupv3_se1_4uart_pins { + qupv3_se1_default_ctsrtsrx: qupv3_se1_default_ctsrtsrx { + mux { + pins = "gpio61", "gpio62", "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio61", "gpio62", "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se1_default_tx: qupv3_se1_default_tx { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se1_ctsrx: qupv3_se1_ctsrx { + mux { + pins = "gpio61", "gpio64"; + function = "qup01"; + }; + + config { + pins = "gpio61", "gpio64"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_rts: qupv3_se1_rts { + mux { + pins = "gpio62"; + function = "qup01"; + }; + + config { + pins = "gpio62"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se1_tx: qupv3_se1_tx { + mux { + pins = "gpio63"; + function = "qup01"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup00"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 9 NFC Read Interrupt */ + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 9 NFC Read Interrupt */ + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 6: Enable 8: Firmware */ + pins = "gpio6", "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio8"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 6: Enable 8: Firmware */ + pins = "gpio6", "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio8"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + + nfc_clk_req_active: nfc_clk_req_active { + /* active state */ + mux { + /* GPIO 7: NFC CLOCK REQUEST */ + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_clk_req_suspend: nfc_clk_req_suspend { + /* sleep state */ + mux { + /* GPIO 7: NFC CLOCK REQUEST */ + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio45", "gpio46"; + function = "qup02"; + }; + + config { + pins = "gpio45", "gpio46"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio45", "gpio46"; + function = "gpio"; + }; + + config { + pins = "gpio45", "gpio46"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio13", "gpio14"; + function = "qup10"; + }; + + config { + pins = "gpio13", "gpio14"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio13", "gpio14"; + function = "gpio"; + }; + + config { + pins = "gpio13", "gpio14"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio27", "gpio28"; + function = "qup11"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio27", "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se8_i2c_pins: qupv3_se8_i2c_pins { + qupv3_se8_i2c_active: qupv3_se8_i2c_active { + mux { + pins = "gpio19", "gpio20"; + function = "qup12"; + }; + + config { + pins = "gpio19", "gpio20"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep { + mux { + pins = "gpio19", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio19", "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se10_i2c_pins: qupv3_se10_i2c_pins { + qupv3_se10_i2c_active: qupv3_se10_i2c_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup14"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "qup00"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio45", "gpio46", + "gpio56", "gpio57"; + function = "qup02"; + }; + + config { + pins = "gpio45", "gpio46", + "gpio56", "gpio57"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio45", "gpio46", + "gpio56", "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio45", "gpio46", + "gpio56", "gpio57"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio13", "gpio14", + "gpio15", "gpio16"; + function = "qup10"; + }; + + config { + pins = "gpio13", "gpio14", + "gpio15", "gpio16"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio13", "gpio14", + "gpio15", "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio13", "gpio14", + "gpio15", "gpio16"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* WSA speaker reset pins */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio11"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + wcd938x_reset_active: wcd938x_reset_active { + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <16>; + output-high; + }; + }; + + wcd938x_reset_sleep: wcd938x_reset_sleep { + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + fsa_usbc_ana_en_n@84 { + fsa_usbc_ana_en: fsa_usbc_ana_en { + mux { + pins = "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio84"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* No pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* No Pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* Pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* Pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* Pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* Pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* Pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* Pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* No pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* No pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* Pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* Pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* Pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* Pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio94"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio94"; + drive-strength = <2>; + bias-disable; + }; + }; + + pm8008_interrupt: pm8008_interrupt { + mux { + pins = "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio59"; + bias-disable; + input-enable; + }; + }; + + pm8008_active: pm8008_active { + mux { + pins = "gpio58"; + function = "gpio"; + }; + + config { + pins = "gpio58"; + bias-pull-up; + output-high; + drive-strength = <2>; + }; + }; + + /* Camera GPIOs CCI*/ + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio39", "gpio40"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio39", "gpio40"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio39", "gpio40"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio39", "gpio40"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio41", "gpio42"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio41", "gpio42"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio41", "gpio42"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio41", "gpio42"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_active: cci2_active { + mux { + /* CLK, DATA */ + pins = "gpio43", "gpio44"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio43", "gpio44"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_suspend: cci2_suspend { + mux { + /* CLK, DATA */ + pins = "gpio43", "gpio44"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio43", "gpio44"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_active: cci3_active { + mux { + /* CLK, DATA */ + pins = "gpio2", "gpio3"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio2", "gpio3"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci3_suspend: cci3_suspend { + mux { + /* CLK, DATA */ + pins = "gpio2", "gpio3"; + function = "CCI_I2C"; + }; + + config { + pins = "gpio2", "gpio3"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + /* Camera GPIOs CCI*/ + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio29"; + function = "CAM_MCLK0"; + }; + + config { + pins = "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio29"; + function = "CAM_MCLK0"; + }; + + config { + pins = "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio30"; + function = "CAM_MCLK1"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio30"; + function = "CAM_MCLK1"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio31"; + function = "CAM_MCLK2"; + }; + + config { + pins = "gpio31"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio31"; + function = "CAM_MCLK2"; + }; + + config { + pins = "gpio31"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio32"; + function = "CAM_MCLK3"; + }; + + config { + pins = "gpio32"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio32"; + function = "CAM_MCLK3"; + }; + + config { + pins = "gpio32"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_active: cam_sensor_mclk4_active { + /* MCLK4 */ + mux { + pins = "gpio33"; + function = "CAM_MCLK4"; + }; + + config { + pins = "gpio33"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_suspend: cam_sensor_mclk4_suspend { + /* MCLK4 */ + mux { + pins = "gpio33"; + function = "CAM_MCLK4"; + }; + + config { + pins = "gpio33"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rear: cam_sensor_active_rear { + /* RESET REAR, AVDD eLDO */ + mux { + pins = "gpio34", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio34", "gpio50"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear: cam_sensor_suspend_rear { + /* RESET REAR, AVDD eLDO */ + mux { + pins = "gpio34", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio34", "gpio50"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rear_aux: cam_sensor_active_rear_aux { + /* RESET REARAUX */ + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear_aux: cam_sensor_suspend_rear_aux { + /* RESET REARAUX */ + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rear_aux2: cam_sensor_active_rear_aux2 { + /* RESET REARAUX2 */ + mux { + pins = "gpio36"; + function = "gpio"; + }; + + config { + pins = "gpio36"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear_aux2: cam_sensor_suspend_rear_aux2 { + /* RESET REARAUX2 */ + mux { + pins = "gpio36"; + function = "gpio"; + }; + + config { + pins = "gpio36"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_front: cam_sensor_active_front { + /* RESET FRONT */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_front: cam_sensor_suspend_front { + /* RESET FRONT */ + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio23"; + function = "MDP_VSYNC"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio23"; + function = "MDP_VSYNC"; + }; + + config { + pins = "gpio23"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio21", "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio22"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + pmx_ts_release: pmx_ts_release { + mux { + pins = "gpio21", "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio22"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-pm.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2db850cc3a0636d000435e161f7aad483708d647 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-pm.dtsi @@ -0,0 +1,167 @@ +&soc { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "L3"; + qcom,clstr-tmr-add = <1000>; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xfff>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "l3-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <660>; + qcom,exit-latency-us = <600>; + qcom,min-residency-us = <1260>; + }; + + qcom,pm-cluster-level@1 { /* D4 */ + reg = <1>; + label = "l3-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <2752>; + qcom,exit-latency-us = <3048>; + qcom,min-residency-us = <6118>; + qcom,min-child-idx = <2>; + qcom,is-reset; + }; + + qcom,pm-cluster-level@2 { /* Cx Off */ + reg = <2>; + label = "cx-ret"; + qcom,psci-mode = <0x124>; + qcom,entry-latency-us = <3638>; + qcom,exit-latency-us = <4562>; + qcom,min-residency-us = <8467>; + qcom,min-child-idx = <2>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cluster-level@3 { /* LLCC off, AOSS sleep */ + reg = <3>; + label = "llcc-off"; + qcom,psci-mode = <0xB24>; + qcom,entry-latency-us = <3263>; + qcom,exit-latency-us = <6562>; + qcom,min-residency-us = <9826>; + qcom,min-child-idx = <2>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,ref-stddev = <500>; + qcom,tmr-add = <1000>; + qcom,ref-premature-cnt = <1>; + qcom,disable-ipi-prediction; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 + &CPU5>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <61>; + qcom,exit-latency-us = <60>; + qcom,min-residency-us = <121>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <549>; + qcom,exit-latency-us = <901>; + qcom,min-residency-us = <1774>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <702>; + qcom,exit-latency-us = <915>; + qcom,min-residency-us = <4001>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + + qcom,pm-cpu@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,ref-stddev = <100>; + qcom,tmr-add = <100>; + qcom,ref-premature-cnt = <3>; + qcom,cpu = <&CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <55>; + qcom,exit-latency-us = <66>; + qcom,min-residency-us = <121>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <523>; + qcom,exit-latency-us = <1244>; + qcom,min-residency-us = <2207>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <526>; + qcom,exit-latency-us = <1854>; + qcom,min-residency-us = <5555>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + + qcom,rpm-stats@c300000 { + compatible = "qcom,rpm-stats"; + reg = <0xc300000 0x1000>, <0xc3f0004 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + qcom,num-records = <3>; + }; + + qcom,rpmh-master-stats@b221200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb221200 0x60>; + }; + + qcom,ddr-stats@c3f001c { + compatible = "qcom,ddr-stats"; + reg = <0xc300000 0x1000>, <0xc3f001c 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..94b7538049c4cec7dd33c61bc446258064c6599b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "lagoon-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon QRD"; + compatible = "qcom,lagoon-qrd", "qcom,lagoon", "qcom,qrd"; + qcom,msm-id = <434 0x10000>, <459 0x10000>; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..a920fda11d8d6b622308ac2358643b685fdbf53b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "lagoon.dtsi" +#include "lagoon-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon QRD"; + compatible = "qcom,lagoon-qrd", "qcom,lagoon", "qcom,qrd"; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..42092ae04079cf6917d81583b45370f2a8f5b980 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-qrd.dtsi @@ -0,0 +1,576 @@ +#include +#include +#include +#include "lagoon-audio-overlay.dtsi" +#include "lagoon-sde-display.dtsi" +#include "camera/lagoon-camera-sensor-mtp.dtsi" +#include +#include "lagoon-thermal-overlay.dtsi" + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm6350_gpios 2 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-atl436186020H_3780mAh.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; +}; + +&pm6150a_l1 { + qcom,init-voltage = <1800000>; +}; + +&pm6350_gpios { + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio2"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&L18A>; + vdda-pll-supply = <&L22A>; + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L7E>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&L12A>; + vccq2-voltage-level = <1800000 1800000>; + vcc-max-microamp = <800000>; + vccq2-min-microamp = <0>; + vccq2-max-microamp = <800000>; + vccq2-pwr-collapse-sup; + + qcom,vddp-ref-clk-supply = <&L22A>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&L7E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L12A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L9E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L6E>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pm6150a_amoled { + status = "ok"; +}; + +&dsi_r66451_amoled_60hz_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_r66451_amoled_90hz_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_r66451_amoled_120hz_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-inverted-dbv; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_r66451_amoled_60hz_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_r66451_amoled_90hz_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&dsi_r66451_amoled_120hz_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-bl-inverted-dbv; + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,platform-reset-gpio = <&pm6150l_gpios 9 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_r66451_amoled_120hz_video>; +}; + +&qupv3_se0_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 9 0x00>; + qcom,nq-ven = <&tlmm 6 0x00>; + qcom,nq-firm = <&tlmm 8 0x00>; + qcom,nq-clkreq = <&tlmm 7 0x00>; + qcom,nq-vdd-1p8-supply = <&L11A>; + qcom,nq-vdd-1p8-voltage = <1800000 1800000>; + qcom,nq-vdd-1p8-current = <157000>; + interrupt-parent = <&tlmm>; + interrupts = <9 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>, + <&pm7250b_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage", + "skin_temp"; + qcom,battery-data = <&qrd_batterydata>; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; + qcom,fcc-step-delay-ms = <100>; + qcom,fcc-step-size-ua = <100000>; + qcom,smb-internal-pull-kohm = <0>; + qcom,en-skin-therm-mitigation; + qcom,thermal-mitigation = <10000000 9500000 9000000 8500000 8000000 + 7500000 7000000 6500000 6000000 5500000 5000000 4500000 + 4000000 3500000 3000000 2500000 2000000 1500000 1000000 + 500000>; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3300>; + qcom,bass-enable; + qcom,use-cp-iin-sns; +}; + +&wcd937x_codec { + status = "ok"; +}; + +&wcd938x_codec { + status = "disabled"; +}; + +&wcd937x_rx_slave { + status = "ok"; +}; + +&wcd937x_tx_slave { + status = "ok"; +}; + +&wcd938x_tx_slave { + status = "disabled"; +}; + +&wcd938x_rx_slave { + status = "disabled"; +}; + +&lagoon_snd { + qcom,model = "lito-lagoonqrd-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS1", + "MIC BIAS1", "Analog Mic4", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC2", "ADC2_OUTPUT", + "TX SWR_ADC3", "ADC3_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC2", "ADC2_OUTPUT", + "VA SWR_ADC3", "ADC3_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa883x_0221>; + qcom,wsa-aux-dev-prefix = "SpkrLeft"; + qcom,codec-max-aux-devs = <1>; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,codec-aux-devs = <&wcd937x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, + <&lpi_tlmm>, <&bolero>; +}; + +&qupv3_se8_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "focaltech,fts_ts"; + + focaltech@38 { + compatible = "focaltech,fts_ts"; + reg = <0x38>; + interrupt-parent = <&tlmm>; + interrupts = <22 0x2008>; + focaltech,reset-gpio = <&tlmm 21 0x00>; + focaltech,irq-gpio = <&tlmm 22 0x2008>; + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 1080 2340>; + + vdd-supply = <&L6A>; + + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend","pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + + panel = <&dsi_r66451_amoled_60hz_cmd + &dsi_r66451_amoled_90hz_cmd + &dsi_r66451_amoled_120hz_cmd + &dsi_r66451_amoled_60hz_video + &dsi_r66451_amoled_90hz_video + &dsi_r66451_amoled_120hz_video>; + }; +}; + +&pm7250b_vadc { + smb1390_therm@e { + qcom,scale-fn-type = ; + }; +}; + +&pm7250b_gpios { + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&qupv3_se10_i2c { + qcom,clk-freq-out = <100000>; + status = "ok"; + #include "smb1398.dtsi" +}; + +&smb1396 { + interrupts = <0x2 0xc5 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&spmi_bus>; + interrupt-names = "smb1396"; + pinctrl-names = "default"; + qcom,enable-toggle-stat; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1396_div2_cp_master { + io-channels = <&pm7250b_vadc ADC_AMUX_THM2>; + qcom,parallel-input-mode = <1>; /* USBIN */ + qcom,parallel-output-mode = <2>; /* VBAT */ + qcom,div2-cp-min-ilim-ua = <750000>; + status = "ok"; +}; + +&smb1396_slave { + status = "ok"; +}; + +&smb1396_div2_cp_slave { + status = "ok"; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x16 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x47 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x30 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + qcom,qusb-phy-host-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x16 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x47 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x30 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; + +&tlmm { + fpc_reset_int: fpc_reset_int { + fpc_reset_low: reset_low { + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + fpc_reset_high: reset_high { + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + fpc_int_low: int_low { + mux { + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + }; +}; + +&soc { + fingerprint: fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <17 0>; + fpc,gpio_rst = <&tlmm 18 0>; + fpc,gpio_irq = <&tlmm 17 0>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&fpc_reset_low>; + pinctrl-1 = <&fpc_reset_high>; + pinctrl-2 = <&fpc_int_low>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-qupv3.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-qupv3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f620248c4672a6671b5f58d93b98c790362f06b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-qupv3.dtsi @@ -0,0 +1,329 @@ +#include + +&soc { + /* QUPv3 SE Instances + * North 0 : SE 0 + * North 1 : SE 1 + * North 2 : SE 2 + * South 0 : SE 6 + * South 1 : SE 7 + * South 2 : SE 8 + * South 3 : SE 9 + * South 4 : SE 10 + */ + + /* QUPv3_0 wrapper instance : North QUP */ + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + iommus = <&apps_smmu 0x43 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + gpi_dma0: qcom,gpi-dma@800000 { + compatible = "qcom,gpi-dma"; + #dma-cells = <5>; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x1f>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x56 0x0>; + qcom,gpi-ee-offset = <0x10000>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + qupv3_se0_i2c: i2c@880000 { + compatible = "qcom,i2c-geni"; + reg = <0x880000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se0_spi: spi@880000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x880000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se1_4uart: qcom,qup_uart@884000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x884000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "active", "sleep"; + pinctrl-0 = <&qupv3_se1_default_ctsrtsrx>, + <&qupv3_se1_default_tx>; + pinctrl-1 = <&qupv3_se1_ctsrx>, <&qupv3_se1_rts>, + <&qupv3_se1_tx>; + pinctrl-2 = <&qupv3_se1_ctsrx>, <&qupv3_se1_rts>, + <&qupv3_se1_tx>; + interrupts-extended = <&intc GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 64 IRQ_TYPE_LEVEL_HIGH>; + qcom,wrapper-core = <&qupv3_0>; + qcom,wakeup-byte = <0xFD>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@888000 { + compatible = "qcom,i2c-geni"; + reg = <0x888000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_spi: spi@888000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x888000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_spi_active>; + pinctrl-1 = <&qupv3_se2_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* QUPv3_1 wrapper instance : South QUP */ + qupv3_1: qcom,qupv3_1_geni_se@9c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x9c0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + iommus = <&apps_smmu 0x4c3 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + gpi_dma1: qcom,gpi-dma@900000 { + compatible = "qcom,gpi-dma"; + #dma-cells = <5>; + reg = <0x900000 0x60000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x3f>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x4d6 0x0>; + qcom,gpi-ee-offset = <0x10000>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + qupv3_se6_i2c: i2c@980000 { + compatible = "qcom,i2c-geni"; + reg = <0x980000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i2c_active>; + pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se6_spi: spi@980000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x980000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_spi_active>; + pinctrl-1 = <&qupv3_se6_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se7_2uart: qcom,qup_uart@984000 { + compatible = "qcom,msm-geni-console"; + reg = <0x984000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_2uart_active>; + pinctrl-1 = <&qupv3_se7_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se7_i2c: i2c@984000 { + compatible = "qcom,i2c-geni"; + reg = <0x984000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_i2c_active>; + pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se8_i2c: i2c@988000 { + compatible = "qcom,i2c-geni"; + reg = <0x988000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_i2c_active>; + pinctrl-1 = <&qupv3_se8_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se9_2uart: qcom,qup_uart@98c000 { + compatible = "qcom,msm-geni-console"; + reg = <0x98c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_2uart_active>; + pinctrl-1 = <&qupv3_se9_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "ok"; + }; + + qupv3_se10_i2c: i2c@990000 { + compatible = "qcom,i2c-geni"; + reg = <0x990000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 4 3 64 0>, + <&gpi_dma1 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_i2c_active>; + pinctrl-1 = <&qupv3_se10_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + qcom,shared; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-regulators.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-regulators.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bf29d2a1f4164d755ba16fe14d38c7239a2e5b6e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-regulators.dtsi @@ -0,0 +1,779 @@ +#include + +&apps_rsc { + rpmh-regulator-smpa1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa1"; + S1A: + pm6350_s1: regulator-pm6350-s1 { + regulator-name = "pm6350_s1"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1000000>; + }; + }; + + rpmh-regulator-smpa2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa2"; + S2A: + pm6350_s2: regulator-pm6350-s2 { + regulator-name = "pm6350_s2"; + qcom,set = ; + regulator-min-microvolt = <1503000>; + regulator-max-microvolt = <2048000>; + qcom,init-voltage = <1503000>; + }; + }; + + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "gfx.lvl"; + VDD_GFX_LEVEL: + S3A_LEVEL: + pm6350_s3_level: regulator-pm6350-s3-level { + regulator-name = "pm6350_s3_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "mx.lvl"; + VDD_MX_LEVEL: + S5A_LEVEL: + pm6350_s5_level: regulator-pm6350-s5-level { + regulator-name = "pm6350_s5_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + }; + + VDD_MX_LEVEL_AO: + S5A_LEVEL_AO: + pm6350_s5_level_ao: regulator-pm6350-s5-level-ao { + regulator-name = "pm6350_s5_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "lcx.lvl"; + L1A_LEVEL: + pm6350_l1_level: regulator-pm6350-l1-level { + regulator-name = "pm6350_l1_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2A: + pm6350_l2: regulator-pm6350-l2 { + regulator-name = "pm6350_l2"; + qcom,set = ; + regulator-min-microvolt = <1503000>; + regulator-max-microvolt = <1980000>; + qcom,init-voltage = <1503000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3A: + pm6350_l3: regulator-pm6350-l3 { + regulator-name = "pm6350_l3"; + qcom,set = ; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L4A: + pm6350_l4: regulator-pm6350-l4 { + regulator-name = "pm6350_l4"; + qcom,set = ; + regulator-min-microvolt = <352000>; + regulator-max-microvolt = <801000>; + qcom,init-voltage = <352000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5A: + pm6350_l5: regulator-pm6350-l5 { + regulator-name = "pm6350_l5"; + qcom,set = ; + regulator-min-microvolt = <1503000>; + regulator-max-microvolt = <1980000>; + qcom,init-voltage = <1503000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L6A: + pm6350_l6: regulator-pm6350-l6 { + regulator-name = "pm6350_l6"; + qcom,set = ; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <1710000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7A: + pm6350_l7: regulator-pm6350-l7 { + regulator-name = "pm6350_l7"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L8A: + pm6350_l8: regulator-pm6350-l8 { + regulator-name = "pm6350_l8"; + qcom,set = ; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <2500000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L9A: + pm6350_l9: regulator-pm6350-l9 { + regulator-name = "pm6350_l9"; + qcom,set = ; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3401000>; + qcom,init-voltage = <1650000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11A: + pm6350_l11: regulator-pm6350-l11 { + regulator-name = "pm6350_l11"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12A: + pm6350_l12: regulator-pm6350-l12 { + regulator-name = "pm6350_l12"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L13A: + pm6350_l13: regulator-pm6350-l13 { + regulator-name = "pm6350_l13"; + qcom,set = ; + regulator-min-microvolt = <570000>; + regulator-max-microvolt = <650000>; + qcom,init-voltage = <570000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L14A: + pm6350_l14: regulator-pm6350-l14 { + regulator-name = "pm6350_l14"; + qcom,set = ; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + qcom,init-voltage = <1700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L15A: + pm6350_l15: regulator-pm6350-l15 { + regulator-name = "pm6350_l15"; + qcom,set = ; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1305000>; + qcom,init-voltage = <1100000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L16A: + pm6350_l16: regulator-pm6350-l16 { + regulator-name = "pm6350_l16"; + qcom,set = ; + regulator-min-microvolt = <830000>; + regulator-max-microvolt = <921000>; + qcom,init-voltage = <830000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "lmx.lvl"; + L17A_LEVEL: + pm6350_l17_level: regulator-pm6350-l17-level { + regulator-name = "pm6350_l17_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-ldoa18 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L18A: + pm6350_l18: regulator-pm6350-l18 { + regulator-name = "pm6350_l18"; + qcom,set = ; + regulator-min-microvolt = <788000>; + regulator-max-microvolt = <1049000>; + qcom,init-voltage = <788000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa19 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa19"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L19A: + pm6350_l19: regulator-pm6350-l19 { + regulator-name = "pm6350_l19"; + qcom,set = ; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1305000>; + qcom,init-voltage = <1080000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa20 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa20"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L20A: + pm6350_l20: regulator-pm6350-l20 { + regulator-name = "pm6350_l20"; + qcom,set = ; + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <801000>; + qcom,init-voltage = <530000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa21 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa21"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L21A: + pm6350_l21: regulator-pm6350-l21 { + regulator-name = "pm6350_l21"; + qcom,set = ; + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <825000>; + qcom,init-voltage = <751000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa22 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa22"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L22A: + pm6350_l22: regulator-pm6350-l22 { + regulator-name = "pm6350_l22"; + qcom,set = ; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1305000>; + qcom,init-voltage = <1080000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "cx.lvl"; + VDD_CX_LEVEL: + S1E_LEVEL: + pm6150a_s1_level: regulator-pm6150a-s1-level { + regulator-name = "pm6150a_s1_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_LEVEL_AO: + S1E_LEVEL_AO: + pm6150a_s1_level_ao: regulator-pm6150a-s1-level-ao { + regulator-name = "pm6150a_s1_level_ao"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-msslvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "mss.lvl"; + VDD_MSS_LEVEL: + S6E_LEVEL: + pm6150a_s6_level: regulator-pm6150a-s6-level { + regulator-name = "pm6150a_s6_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = ; + qcom,init-voltage-level = + ; + }; + }; + + rpmh-regulator-smpe8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpe8"; + S8E: + pm6150a_s8: regulator-pm6150a-s8 { + regulator-name = "pm6150a_s8"; + qcom,set = ; + regulator-min-microvolt = <313000>; + regulator-max-microvolt = <1395000>; + qcom,init-voltage = <313000>; + }; + }; + + rpmh-regulator-ldoe1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L1E: + pm6150a_l1: regulator-pm6150a-l1 { + regulator-name = "pm6150a_l1"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2E: + pm6150a_l2: regulator-pm6150a-l2 { + regulator-name = "pm6150a_l2"; + qcom,set = ; + regulator-min-microvolt = <1170000>; + regulator-max-microvolt = <1305000>; + qcom,init-voltage = <1170000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3E: + pm6150a_l3: regulator-pm6150a-l3 { + regulator-name = "pm6150a_l3"; + qcom,set = ; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1299000>; + qcom,init-voltage = <1100000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L4E: + pm6150a_l4: regulator-pm6150a-l4 { + regulator-name = "pm6150a_l4"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5E: + pm6150a_l5: regulator-pm6150a-l5 { + regulator-name = "pm6150a_l5"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L6E: + pm6150a_l6: regulator-pm6150a-l6 { + regulator-name = "pm6150a_l6"; + qcom,set = ; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <1700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7E: + pm6150a_l7: regulator-pm6150a-l7 { + regulator-name = "pm6150a_l7"; + qcom,set = ; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <2700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L8E: + pm6150a_l8: regulator-pm6150a-l8 { + regulator-name = "pm6150a_l8"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe9 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L9E: + pm6150a_l9: regulator-pm6150a-l9 { + regulator-name = "pm6150a_l9"; + qcom,set = ; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + qcom,init-voltage = <2700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe10 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10E: + pm6150a_l10: regulator-pm6150a-l10 { + regulator-name = "pm6150a_l10"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3401000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoe11 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoe11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11E: + pm6150a_l11: regulator-pm6150a-l11 { + regulator-name = "pm6150a_l11"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3401000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-bobe1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "bobe1"; + qcom,regulator-type = "pmic5-bob"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1000000 2000000>; + qcom,send-defaults; + BOB: + pm6150a_bob: regulator-pm6150a-bob { + regulator-name = "pm6150a_bob"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <5492000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + + BOB_AO: + pm6150a_bob_ao: regulator-pm6150a-bob-ao { + regulator-name = "pm6150a_bob_ao"; + qcom,set = ; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <5492000>; + qcom,init-voltage = <1620000>; + qcom,init-mode = ; + }; + }; +}; + +&soc { + refgen: refgen-regulator@88e7000 { + compatible = "qcom,refgen-kona-regulator"; + reg = <0x88e7000 0x60>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d6c83f5cb2e53f3bf3251ab7e4574a78722042f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "lagoon-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon RUMI"; + compatible = "qcom,lagoon-rumi", "qcom,lagoon", "qcom,rumi"; + qcom,msm-id = <434 0x10000>; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..45b21fdaf5097a2065e062c97b8b9117233d01c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/memreserve/ 0xc0000000 0x00000100; + +#include "lagoon.dtsi" +#include "lagoon-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon RUMI"; + compatible = "qcom,lagoon-rumi", "qcom,lagoon", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..96fe4a5d5a7cd1a95c243590299c4b55cfa567c0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-rumi.dtsi @@ -0,0 +1,153 @@ +&soc { + timer { + clock-frequency = <500000>; + }; + + timer@17c20000 { + clock-frequency = <500000>; + }; + + usb_emu_phy: usb_emu_phy@a720000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x0a720000 0x9500>, + <0x0a6f8800 0x100>; + reg-names = "base", "qscratch_base"; + + qcom,emu-init-seq = <0xfff0 0x4 + 0xfff3 0x4 + 0x40 0x4 + 0xfff3 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; + + bi_tcxo: bi_tcxo { + compatible = "fixed-factor-clock"; + clock-mult = <1>; + clock-div = <4>; + clocks = <&xo_board>; + #clock-cells = <0>; + }; + + bi_tcxo_ao: bi_tcxo_ao { + compatible = "fixed-factor-clock"; + clock-mult = <1>; + clock-div = <4>; + clocks = <&xo_board>; + #clock-cells = <0>; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qrbtc-sdm845"; + + vdda-phy-supply = <&L18A>; + vdda-pll-supply = <&L22A>; + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + limit-tx-hs-gear = <1>; + limit-rx-hs-gear = <1>; + scsi-cmd-timeout = <300000>; + + vdd-hba-supply = <&gcc_ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&L7E>; + vccq2-supply = <&L12A>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&L22A>; + qcom,vddp-ref-clk-max-microamp = <100>; + + qcom,disable-lpm; + status = "ok"; +}; + +&wdog { + status = "disabled"; +}; + +&usb0 { + /delete-property/ extcon; + + dwc3@a600000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&rpmhcc { + compatible = "qcom,dummycc"; + clock-output-names = "rpmh_clocks"; +}; + +&aopcc { + compatible = "qcom,dummycc"; + clock-output-names = "qdss_clocks"; +}; + +&sdhc_1 { + vdd-supply = <&L7E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L12A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + qcom,clk-rates = <400000 25000000 50000000>; + qcom,bus-speed-mode = "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L9E>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L6E>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&qupv3_se10_i2c { + status = "disabled"; +}; + +/* Debug UART Console */ +&qupv3_se9_2uart { + qcom,rumi_platform; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..66f4482af6a69d6bba4bb67f47675a17c0efee9d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-sde-display.dtsi @@ -0,0 +1,907 @@ +#include "dsi-panel-rm69299-visionox-fhd-plus-video.dtsi" +#include "dsi-panel-rm69299-visionox-fhd-plus-cmd.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-60hz-cmd.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-90hz-cmd.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-120hz-cmd.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-60hz-video.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-90hz-video.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-120hz-video.dtsi" +#include "dsi-panel-sharp-qsync-fhd-video.dtsi" +#include "dsi-panel-sharp-qsync-fhd-cmd.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-144hz-cmd.dtsi" + +#include + +&pm6150l_gpios { + disp_pins { + disp_pins_default: disp_pins_default { + pins = "gpio9"; + function = "func1"; + qcom,drive-strength = <2>; + power-source = <1>; + bias-disable; + output-low; + }; + }; +}; + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <363000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <363000>; + qcom,supply-disable-load = <20>; + }; + }; + + dsi_panel_pwr_supply_144: dsi_panel_pwr_supply_144 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1980000>; + qcom,supply-max-voltage = <1980000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <363000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <363000>; + qcom,supply-disable-load = <20>; + }; + }; + + dsi_panel_pwr_supply_avdd: dsi_panel_pwr_supply_avdd { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <363000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <363000>; + qcom,supply-disable-load = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + sde_dsi: qcom,dsi-display-primary { + compatible = "qcom,dsi-display"; + label = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi0_pll BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll PCLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_PCLK_SRC_0_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_te_active &disp_pins_default>; + pinctrl-1 = <&sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 23 0>; + qcom,panel-te-source = <0>; + + vddio-supply = <&L1E>; + vdd-supply = <&L8A>; + lab-supply = <&ab_vreg>; + ibb-supply = <&ibb_vreg>; + + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_rm69299_visionox_amoled_video>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + msm_notifier: qcom,msm_notifier@0 { + compatible = "qcom,msm-notifier"; + panel = <&dsi_rm69299_visionox_amoled_video + &dsi_rm69299_visionox_amoled_cmd + &dsi_r66451_amoled_120hz_video + &dsi_r66451_amoled_120hz_cmd>; + }; + + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pm7250b_pdphy>; + qcom,ext-disp = <&ext_disp>; + qcom,dp-aux-switch = <&fsa4480>; + + extcon = <&pm7250b_pdphy>; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_rscc &sde_dp>; +}; + +&dsi_rm69299_visionox_amoled_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-supported-dfps-list = <60 55 48>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <952174080 948206688 956141472>; + qcom,dsi-dyn-clk-type = "constant-fps-adjust-vfp"; + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 20 08 08 24 23 08 + 08 05 02 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_rm69299_visionox_amoled_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <929813440 925939216 922064992>; + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x31>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 20 08 08 24 23 08 + 08 05 02 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_144hz_cmd { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x1d>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 22 09 09 19 17 09 + 09 09 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_60hz_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0A>; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 10 04 04 1E 1E 04 + 04 03 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_90hz_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0B>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1F 06 + 06 06 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_120hz_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x32>; + qcom,dsi-supported-dfps-list = <120 90 60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-min-refresh-rate = <60>; + qcom,mdss-dsi-max-refresh-rate = <120>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 08 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_60hz_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0A>; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 10 04 04 1E 1E 04 + 04 03 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_90hz_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0B>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1F 06 + 06 06 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r66451_amoled_120hz_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1C 08 07 23 22 07 + 07 08 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1F 06 + 06 06 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 10 04 04 1E 1E 04 + 04 03 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_qsync_fhd_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x2c>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-panel-mode-switch; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-video-mode; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 07 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 07 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 03 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 05 be 00 10 00 10 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,cmd-to-video-mode-post-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 bb 03 + ]; + qcom,cmd-to-video-mode-post-switch-commands-state = + "dsi_lp_mode"; + }; + + timing@1 { + qcom,mdss-dsi-cmd-mode; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <20>; + qcom,mdss-dsi-h-back-porch = <12>; + qcom,mdss-dsi-h-pulse-width = <8>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <14>; + qcom,mdss-dsi-v-front-porch = <16>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-jitter = <0x3 0x1>; + qcom,mdss-dsi-panel-phy-timings = [00 0c 03 03 1d 1d 03 + 03 02 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 07 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 05 be 00 10 00 10 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command = [ + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bc 00 + 05 01 00 00 10 00 01 28 + 05 01 00 00 32 00 01 10 + ]; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,video-to-cmd-mode-post-switch-commands = [ + 39 00 00 00 00 00 02 ff 10 + 39 00 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 bb 10 + ]; + qcom,video-to-cmd-mode-post-switch-commands-state = + "dsi_lp_mode"; + qcom,compression-mode = "dsc"; + qcom,mdss-dsc-slice-height = <8>; + qcom,mdss-dsc-slice-width = <540>; + qcom,mdss-dsc-slice-per-pkt = <1>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + }; + }; +}; + +&dsi_sharp_qsync_fhd_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x09>; + qcom,mdss-dsi-t-clk-pre = <0x18>; + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-phy-timings = [00 0c 03 03 1d 1d 03 + 03 02 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 07 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 0a + 39 01 00 00 00 00 02 17 30 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + }; + + timing@1 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 06 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 07 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 00 + 39 01 00 00 00 00 02 17 10 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 00 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + }; + + timing@2 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-phy-timings = [00 10 04 04 1e 1e 04 + 04 03 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 40 + 39 01 00 00 10 00 02 f1 40 + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 10 00 06 2c 01 02 04 08 10 + 39 01 00 00 00 00 02 ff d0 + 39 01 00 00 00 00 02 75 00 + 39 01 00 00 10 00 02 f1 00 + /* Initial Setting */ + 39 01 00 00 00 00 02 ff 10 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 ba 07 + 39 01 00 00 00 00 02 bc 08 + 39 01 00 00 00 00 02 c0 85 + 39 01 00 00 00 00 11 c1 89 28 00 08 02 + 00 02 0e 00 bb 00 07 0d b7 0c b7 + 39 01 00 00 00 00 03 c2 10 f0 + 39 01 00 00 00 00 02 d5 00 + 39 01 00 00 00 00 02 d6 00 + 39 01 00 00 00 00 02 de 00 + 39 01 00 00 00 00 02 e1 00 + 39 01 00 00 00 00 02 e5 01 + 39 01 00 00 00 00 02 bb 10 + 39 01 00 00 00 00 02 f6 70 + 39 01 00 00 00 00 02 f7 80 + 39 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 02 44 00 + 39 01 00 00 00 00 02 ff 20 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 87 02 + 39 01 00 00 00 00 02 5d 00 + 39 01 00 00 00 00 02 5e 14 + 39 01 00 00 00 00 02 5f eb + 39 01 00 00 00 00 02 ff 24 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 14 00 + 39 01 00 00 00 00 02 15 10 + 39 01 00 00 00 00 02 16 03 + 39 01 00 00 00 00 02 17 70 + 39 01 00 00 00 00 02 ff 26 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 60 00 + 39 01 00 00 00 00 02 62 01 + 39 01 00 00 00 00 02 40 00 + 39 01 00 00 00 00 02 ff 28 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 91 02 + 39 01 00 00 00 00 02 ff e0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 48 81 + 39 01 00 00 00 00 02 8e 09 + 39 01 00 00 00 00 02 ff f0 + 39 01 00 00 00 00 02 fb 01 + 39 01 00 00 00 00 02 33 20 + 39 01 00 00 00 00 02 34 35 + 39 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 01 11 + 05 01 00 00 78 00 01 29 + ]; + }; + }; +}; + +&dsi_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 02 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@3 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@4 { + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 02 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-sde-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..98454ad33362c572d37c8fcd1bd54aaeb0642863 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-sde-pll.dtsi @@ -0,0 +1,44 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi0_pll { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94a00 0x1e0>, + <0xae94400 0x800>, + <0xaf03000 0x8>, + <0xae94200 0x100>; + reg-names = "pll_base", "phy_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + memory-region = <&dfps_data_memory>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@ae90000 { + compatible = "qcom,mdss_dp_pll_10nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_QLINK_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk", + "pipe_clk"; + clock-rate = <0>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-sde.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..75ded597b40db4910652ae98074d5b0529a6523e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-sde.dtsi @@ -0,0 +1,536 @@ +#include +&soc { + mdss_mdp: qcom,mdss_mdp { + compatible = "qcom,sde-kms"; + reg = <0xae00000 0x84208>, + <0xaeb0000 0x2008>, + <0xaeac000 0x214>, + <0xae8f000 0x030>, + <0xaf50000 0x054>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys", + "sid_phys", + "swfuse_phys"; + + clocks = + <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk"; + clock-rate = <0 0 0 373333333 19200000 373333333>; + clock-max-rate = <0 0 0 560000000 19200000 560000000>; + qcom,dss-cx-ipeak = <&cx_ipeak_lm 4>; + + /* interrupt config */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x494>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 0x2600>; + qcom,sde-ctl-size = <0x1dc>; + qcom,sde-ctl-display-pref = "primary", "none", "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "none"; + qcom,sde-mixer-cwb-pref = "none", "cwb"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000>; + qcom,sde-dspp-size = <0x1800>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x2bc 16>; + + qcom,sde-intf-off = <0x6b000 0x6b800>; + qcom,sde-intf-size = <0x2c0>; + qcom,sde-intf-type = "dp", "dsi"; + + qcom,sde-pp-off = <0x71000 0x71800>; + qcom,sde-pp-slave = <0x0 0x0>; + qcom,sde-pp-size = <0xd4>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000>; + qcom,sde-dsc-size = <0x140>; + qcom,sde-dsc-pair-mask = <0>; + + qcom,sde-dither-off = <0x30e0 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "dma", "dma", "dma"; + qcom,sde-sspp-off = <0x5000 0x25000 0x27000 0x29000>; + qcom,sde-sspp-src-size = <0x1f8>; + qcom,sde-sspp-xin-id = <0 1 5 9>; + qcom,sde-sspp-excl-rect = <1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <4 1 2 3>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <2 1>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-max-per-pipe-bw-kbps = <2700000 2700000 + 2700000 2700000>; + + qcom,sde-max-per-pipe-bw-high-kbps = <2700000 2700000 + 2700000 2700000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = <0x2ac 0>, + <0x2ac 8>, <0x2b4 8>, <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-wb-linewidth = <1920>; + qcom,sde-mixer-blendstages = <0x7>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-ubwc-swizzle = <0x6>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-ubwc-static = <0x1e>; + qcom,sde-macrotile-mode = <0x0>; + qcom,sde-smart-panel-align-mode = <0xc>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + qcom,sde-max-bw-low-kbps = <4200000>; + qcom,sde-max-bw-high-kbps = <5100000>; + qcom,sde-min-core-ib-kbps = <2500000>; + qcom,sde-min-llcc-ib-kbps = <0>; + qcom,sde-min-dram-ib-kbps = <1600000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ltm-version = <0x00010000>; + /* offsets are based off dspp 0 */ + qcom,sde-dspp-ltm-off = <0x2a000>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1044>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-qos-cwb-remap = <3 3 4 4 5 5 6 3>; + qcom,sde-vbif-qos-lutdma-remap = <3 3 3 3 4 4 4 4>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x0000ffff 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>, <0x0003ffff + 0x0003ffff 0x00000000 0x00000000 0x0003ffff>; + + qcom,sde-safe-lut-linear = <0 0xff00>, <0 0xfe00>; + qcom,sde-safe-lut-macrotile = <0 0xff00>, <0 0xfe00>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xff00>, <0 0xfe00>; + qcom,sde-safe-lut-nrt = <0 0xffff>, <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0x3ff>, <0x3ff>; + + /* creq LUTs */ + qcom,sde-qos-lut-linear = <0 0x00112233 0x44556677>, + <0 0x00112234 0x45566777>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>, + <0 0x00112234 0x45566777>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>, + <0 0x00112236 0x67777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>, + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x66666541 0x00000000>, + <0 0x66666541 0x00000000>; + qcom,sde-qos-refresh-rates = <60 120>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + qcom,sde-qos-cpu-irq-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010002>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + qcom,sde-reg-dma-xin-id = <7>; + qcom,sde-reg-dma-clk-ctrl = <0x2bc 20>; + + qcom,sde-secure-sid-mask = <0x801>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-gamut = <0x1d00 0x00060000>; + qcom,sde-vig-igc = <0x1d00 0x00060000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + }; + + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + }; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040002>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0x800 0x2>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-earlymap; /* for cont-splash */ + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x801 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 6400000>, + <22 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + + qcom,sde-limits { + qcom,sde-linewidth-limits { + qcom,sde-limit-name = "sspp_linewidth_usecases"; + qcom,sde-limit-cases = "vig", "dma", + "scale", "inline_rot"; + qcom,sde-limit-ids= <0x1 0x2 0x4 0x8>; + qcom,sde-limit-values = <0x1 4096>, + <0x5 2560>, + <0x2 2160>, + <0x9 1088>; + }; + + qcom,sde-bw-limits { + qcom,sde-limit-name = "sde_bwlimit_usecases"; + qcom,sde-limit-cases = "per_vig_pipe", + "per_dma_pipe", + "total_max_bw", + "camera_concurrency", + "cwb_concurrency"; + qcom,sde-limit-ids = <0x1 0x2 0x4 0x8 0x10>; + qcom,sde-limit-values = <0x1 2700000>, + <0x11 2700000>, + <0x9 2700000>, + <0x19 2700000>, + <0x2 2700000>, + <0x12 2700000>, + <0xa 2700000>, + <0x1a 2700000>, + <0x4 5100000>, + <0x14 5100000>, + <0xc 4400000>, + <0x1c 4200000>; + }; + }; + }; + + sde_rscc: qcom,sde_rscc { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x3c50>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <3>; + + qcom,sde-dram-channels = <2>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20003 20513 0 0>, + <20003 20513 0 6400000>, + <20003 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "disp_rsc_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi0_ctrl { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-0"; + cell-index = <0>; + frame-threshold-time-us = <1000>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&L22A>; + refgen-supply = <&refgen>; + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x800>, + <0xae94200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; + vdda-0p9-supply = <&S5A_LEVEL>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,panel-allow-phy-poweroff; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = + ; + qcom,supply-max-voltage = + ; + qcom,supply-off-min-voltage = + ; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + sde_dp: qcom,dp_display@ae90000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&L22A>; + vdda-0p9-supply = <&L16A>; + + reg = <0xae90000 0x200>, + <0xae90200 0x200>, + <0xae90400 0xc00>, + <0xae91000 0x400>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf01000 0x2d0>, + <0x780000 0x6228>, + <0x88ea030 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x2a>, + <0xae91400 0x400>; + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "qfprom_physical", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13 23 1d]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 bb]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <337500>; + qcom,no-mst-encoder; + + clocks = <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&rpmhcc RPMH_QLINK_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_PHY_PLL_VCO_DIV_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; + + clock-names = "core_aux_clk", "core_usb_pipe_clk", + "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_pipe_clk", + "link_clk", "link_iface_clk", + "pixel_clk_rcg", "pixel_parent", + "strm0_pixel_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <928000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-stub-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-stub-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d0ed0ea2589811711e26876f2beaf6239018b1de --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-stub-regulator.dtsi @@ -0,0 +1,433 @@ +#include + +/ { + S1A: + pm6350_s1: regulator-pm6350-s1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_s1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + }; + + S2A: + pm6350_s2: regulator-pm6350-s2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_s2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <100000>; + regulator-max-microvolt = <3900000>; + }; + + VDD_GFX_LEVEL: + S3A_LEVEL: + pm6350_s3_level: regulator-pm6350-s3-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_s3_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + VDD_MX_LEVEL: + S5A_LEVEL: + pm6350_s5_level: regulator-pm6350-s5-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_s5_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + VDD_MX_LEVEL_AO: + S5A_LEVEL_AO: + pm6350_s5_level_ao: regulator-pm6350-s5-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_s5_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + S6A: + pm6350_s6: regulator-pm6350-s6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_s6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <647000>; + regulator-max-microvolt = <1290000>; + }; + + L1A_LEVEL: + pm6350_l1_level: regulator-pm6350-l1-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l1_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + L2A: + pm6350_l2: regulator-pm6350-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + }; + + L3A: + pm6350_l3: regulator-pm6350-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3400000>; + }; + + L4A: + pm6350_l4: regulator-pm6350-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <950000>; + }; + + L5A: + pm6350_l5: regulator-pm6350-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <0>; + regulator-max-microvolt = <3600000>; + }; + + L6A: + pm6350_l6: regulator-pm6350-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3600000>; + }; + + L7A: + pm6350_l7: regulator-pm6350-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + }; + + L8A: + pm6350_l8: regulator-pm6350-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <4400000>; + }; + + L9A: + pm6350_l9: regulator-pm6350-l9 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l9"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <0>; + regulator-max-microvolt = <0>; + }; + + L10A: + pm6350_l10: regulator-pm6350-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <0>; + regulator-max-microvolt = <3300000>; + }; + + L11A: + pm6350_l11: regulator-pm6350-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <0>; + regulator-max-microvolt = <3600000>; + }; + + L12A: + pm6350_l12: regulator-pm6350-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l12"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + }; + + L13A: + pm6350_l13: regulator-pm6350-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l13"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <650000>; + }; + + L14A: + pm6350_l14: regulator-pm6350-l14 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l14"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + }; + + L15A: + pm6350_l15: regulator-pm6350-l15 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l15"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1400000>; + }; + + L16A: + pm6350_l16: regulator-pm6350-l16 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l16"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <830000>; + regulator-max-microvolt = <920000>; + }; + + L17A_LEVEL: + pm6350_l17_level: regulator-pm6350-l17-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l17_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + L18A: + pm6350_l18: regulator-pm6350-l18 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l18"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <348000>; + regulator-max-microvolt = <990000>; + }; + + L19A: + pm6350_l19: regulator-pm6350-l19 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l19"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <0>; + regulator-max-microvolt = <1236000>; + }; + + L20A: + pm6350_l20: regulator-pm6350-l20 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l20"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <800000>; + }; + + L21A: + pm6350_l21: regulator-pm6350-l21 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l21"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + }; + + L22A: + pm6350_l22: regulator-pm6350-l22 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6350_l22"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1980000>; + }; + + BOB: pm6150a_bob: regulator-pm6150a-bob { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_bob"; + regulator-min-microvolt = <100000>; + regulator-max-microvolt = <5500000>; + }; + + BOB_AO: pm6150a_bob_ao: regulator-pm6150a-bob-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_bob_ao"; + regulator-min-microvolt = <100000>; + regulator-max-microvolt = <5500000>; + }; + + VDD_CX_LEVEL: + S1E_LEVEL: + pm6150a_s1_level: regulator-pm6150a-s1-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_s1_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + VDD_CX_LEVEL_AO: + S1E_LEVEL_AO: + pm6150a_s1_level_ao: regulator-pm6150a-s1-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_s1_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + + VDD_MSS_LEVEL: + S6E_LEVEL: + pm6150a_s6_level: regulator-pm6150a-s6-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_s6_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + }; + + S8E: + pm6150a_s8: regulator-pm6150a-s8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_s8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <300000>; + regulator-max-microvolt = <2050000>; + }; + + L1E: + pm6150a_l1: regulator-pm6150a-l1 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l1"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; + }; + + L2E: + pm6150a_l2: regulator-pm6150a-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1170000>; + regulator-max-microvolt = <1430000>; + }; + + L3E: + pm6150a_l3: regulator-pm6150a-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + L4E: + pm6150a_l4: regulator-pm6150a-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + L5E: + pm6150a_l5: regulator-pm6150a-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + L6E: + pm6150a_l6: regulator-pm6150a-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3600000>; + }; + + L7E: + pm6150a_l7: regulator-pm6150a-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3599000>; + }; + + L8E: + pm6150a_l8: regulator-pm6150a-l8 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l8"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <3600000>; + }; + + L9E: + pm6150a_l9: regulator-pm6150a-l9 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l9"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <3300000>; + }; + + L10E: + pm6150a_l10: regulator-pm6150a-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3600000>; + }; + + L11E: + pm6150a_l11: regulator-pm6150a-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm6150a_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3600000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-thermal-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-thermal-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..11cc3484695281d0f8306d5f2b7bf636b51beb52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-thermal-overlay.dtsi @@ -0,0 +1,179 @@ +#include + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&thermal_zones { + pm7250b-tz { + cooling-maps { + trip0_bat { + trip = <&pm7250b_trip0>; + cooling-device = + <&pm7250b_charger (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_bat { + trip = <&pm7250b_trip1>; + cooling-device = + <&pm7250b_charger THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm6150l-tz { + cooling-maps { + trip0_cpu0 { + trip = <&pm6150l_trip0>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip0_cpu6 { + trip = <&pm6150l_trip0>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu1 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + trip1_cpu2 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + trip1_cpu3 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu3_isolate 1 1>; + }; + + trip1_cpu4 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + trip1_cpu5 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu5_isolate 1 1>; + }; + + trip1_cpu6 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + trip1_cpu7 { + trip = <&pm6150l_trip1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + soc { + cooling-maps { + soc_cpu6 { + trip = <&soc_trip>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + soc_cpu7 { + trip = <&soc_trip>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm7250b-bcl-lvl0 { + cooling-maps { + lbat0_cpu6 { + trip = <&b_bcl_lvl0>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + lbat0_cpu7 { + trip = <&b_bcl_lvl0>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm7250b-bcl-lvl1 { + cooling-maps { + lbat1_cpu6 { + trip = <&b_bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + lbat1_cpu7 { + trip = <&b_bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm7250b-bcl-lvl2 { + cooling-maps { + lbat2_cpu6 { + trip = <&b_bcl_lvl2>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + lbat2_cpu7 { + trip = <&b_bcl_lvl2>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm6150l-bcl-lvl0 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl0>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl0>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm6150l-bcl-lvl1 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm6150l-bcl-lvl2 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl2>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl2>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-thermal.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bd473a9700200e2fa4b22735d6fa25506e32dfb2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-thermal.dtsi @@ -0,0 +1,1439 @@ +#include +#include "sdxprairie-thermal-integrated.dtsi" + +&cpufreq_hw { + #address-cells = <1>; + #size-cells = <1>; + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + + cpu4_isolate: cpu4-isolate { + qcom,cpu = <&CPU4>; + #cooling-cells = <2>; + }; + + cpu5_isolate: cpu5-isolate { + qcom,cpu = <&CPU5>; + #cooling-cells = <2>; + }; + + cpu6_isolate: cpu6-isolate { + qcom,cpu = <&CPU6>; + #cooling-cells = <2>; + }; + + cpu7_isolate: cpu7-isolate { + qcom,cpu = <&CPU7>; + #cooling-cells = <2>; + }; + }; + + lmh_dcvs0: qcom,limits-dcvs@18358800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + reg = <0x18358800 0x1000>, + <0x18323000 0x1000>; + qcom,no-cooling-device-register; + }; + + lmh_dcvs1: qcom,limits-dcvs@18350800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + reg = <0x18350800 0x1000>, + <0x18325800 0x1000>; + qcom,no-cooling-device-register; + }; +}; + +&soc { + lmh_cpu_vdd0: qcom,lmh-cpu-vdd@18358800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0x18358800 0x1000>; + #cooling-cells = <2>; + }; + + lmh_cpu_vdd1: qcom,lmh-cpu-vdd@18350800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0x18350800 0x1000>; + #cooling-cells = <2>; + }; + + qmi-tmd-devices { + cdsp { + qcom,instance-id = ; + + cdsp_sw: cdsp { + qcom,qmi-dev-name = "cdsp_sw"; + #cooling-cells = <2>; + }; + + cdsp_hw: hvx { + qcom,qmi-dev-name = "cdsp_hw"; + #cooling-cells = <2>; + }; + }; + }; + + cxip_cdev: cxip-cdev@1fed000 { + status = "disabled"; + + compatible = "qcom,cxip-lm-cooling-device"; + reg = <0x1fed000 0x10060>; + qcom,thermal-client-offset = <0x8000>; + qcom,bypass-client-list = <0xe00c 0xf00c 0x1000c 0x1001c + 0x1002c 0x1003c 0x1004c 0x1005c>; + #cooling-cells = <2>; + }; +}; + +&thermal_zones { + aoss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-4-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-5-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 11>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 12>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 13>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 14>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cwlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + audio-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + ddr-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + q6-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 4>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 5>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-core-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 6>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-core-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 7>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-vec-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 8>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-scl-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 9>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + npu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 10>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 11>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-max-step { + polling-delay-passive = <10>; + polling-delay = <100>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gpu_trip0: gpu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev { + trip = <&gpu_trip0>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu-0-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + cpu00_config: cpu00-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu00_cdev { + trip = <&cpu00_config>; + cooling-device = <&cpu0_isolate 1 1>; + }; + }; + }; + + cpu-0-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + cpu01_config: cpu01-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu01_cdev { + trip = <&cpu01_config>; + cooling-device = <&cpu1_isolate 1 1>; + }; + }; + }; + + cpu-0-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + cpu02_config: cpu02-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu02_cdev { + trip = <&cpu02_config>; + cooling-device = <&cpu2_isolate 1 1>; + }; + }; + }; + + cpu-0-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu03_config: cpu03-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu03_cdev { + trip = <&cpu03_config>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + cpu-0-4-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu04_config: cpu04-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu04_cdev { + trip = <&cpu04_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + }; + }; + + cpu-0-5-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu05_config: cpu05-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu05_cdev { + trip = <&cpu05_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpu-1-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu10_config: cpu10-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu10_cdev { + trip = <&cpu10_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu11_config: cpu11-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu11_cdev { + trip = <&cpu11_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu12_config: cpu12-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu12_cdev { + trip = <&cpu12_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + cpu-1-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu13_config: cpu13-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu13_cdev { + trip = <&cpu13_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + q6-hvx-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cxip_trip: cxip-trip { + temperature = <95000>; + hysteresis = <20000>; + type = "passive"; + }; + + q6_hvx_trip0: q6-hvx-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + q6_hvx_trip1: q6-hvx-trip1 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cxip-cdev { + trip = <&cxip_trip>; + cooling-device = <&cxip_cdev 1 1>; + }; + + cdsp-cdev0 { + trip = <&q6_hvx_trip0>; + cooling-device = <&cdsp_sw THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + + cdsp-cdev1 { + trip = <&q6_hvx_trip1>; + cooling-device = <&cdsp_sw 4 4>; + }; + + modem-pa-cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&msm_npu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + gpu-cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + }; + }; + + chg-skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + sdm-skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm_iio ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + rfc-cam-pa3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm_iio ADC_GPIO2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_GPIO3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_GPIO4_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm6150l_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pmk8350_adc_tm PMK8350_ADC7_AMUX_THM1_100K_PU>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + npu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 10>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + npu_trip0: npu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + npu_cdev { + trip = <&npu_trip0>; + cooling-device = + <&msm_npu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + min-temp-0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 16>; + thermal-governor = "low_limits_floor"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_0_lowf: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + wcss_cx_vdd_cdev { + trip = <&min_temp_0_lowf>; + cooling-device = <&cx_cdev 0 0>; + }; + }; + }; + + min-temp-0-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 16>; + thermal-governor = "low_limits_cap"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_0_lowc: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu0_cdev { + trip = <&min_temp_0_lowc>; + cooling-device = <&lmh_cpu_vdd0 1 1>; + }; + + lmh_cpu6_cdev { + trip = <&min_temp_0_lowc>; + cooling-device = <&lmh_cpu_vdd1 1 1>; + }; + }; + }; + + min-temp-1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 16>; + thermal-governor = "low_limits_floor"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_1_lowf: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + wcss_cx_vdd_cdev { + trip = <&min_temp_1_lowf>; + cooling-device = <&cx_cdev 0 0>; + }; + }; + }; + + min-temp-1-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 16>; + thermal-governor = "low_limits_cap"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_1_lowc: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu0_cdev { + trip = <&min_temp_1_lowc>; + cooling-device = <&lmh_cpu_vdd0 1 1>; + }; + + lmh_cpu6_cdev { + trip = <&min_temp_1_lowc>; + cooling-device = <&lmh_cpu_vdd1 1 1>; + }; + }; + }; + + quiet-therm-step { + polling-delay-passive = <2000>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_adc_tm ADC_GPIO4_PU2>; + wake-capable-sensor; + + trips { + modem_skin_trip0: modem-skin-trip0 { + temperature = <40000>; + hysteresis = <4000>; + type = "passive"; + }; + + modem_skin_trip1: modem-skin-trip1 { + temperature = <41000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_batt_trip0: batt-skin-trip0 { + temperature = <41000>; + hysteresis = <2000>; + type = "passive"; + }; + + modem_skin_trip2: modem-skin-trip2 { + temperature = <42000>; + hysteresis = <4000>; + type = "passive"; + }; + + gold_trip: gold-trip { + temperature = <43000>; + hysteresis = <0>; + type = "passive"; + }; + + skin_batt_modem_trip: batt-modem-skin-trip { + temperature = <43000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_batt_trip2: batt-skin-trip2 { + temperature = <45000>; + hysteresis = <2000>; + type = "passive"; + }; + + gpu_skin_trip: gpu-skin-trip { + temperature = <45000>; + hysteresis = <3000>; + type = "passive"; + }; + + skin_batt_trip3: batt-skin-trip3 { + temperature = <47000>; + hysteresis = <2000>; + type = "passive"; + }; + + silver_trip: silver-trip { + temperature = <48000>; + hysteresis = <0>; + type = "passive"; + }; + + skin_batt_trip4: batt-skin-trip4 { + temperature = <48000>; + hysteresis = <1000>; + type = "passive"; + }; + + cx_emer_trip: cx-emer-trip { + temperature = <50000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + + cooling-maps { + skin_cpu6 { + trip = <&gold_trip>; + /* throttle from fmax to 1555200KHz */ + cooling-device = <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-6)>; + }; + + skin_cpu0 { + trip = <&silver_trip>; + /* throttle from fmax to 1516800KHz */ + cooling-device = <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-6)>; + }; + + skin_gpu { + trip = <&gpu_skin_trip>; + /* throttle to 650000000Hz */ + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + skin_gpu_emrg { + trip = <&cx_emer_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-2) + (THERMAL_MAX_LIMIT-2)>; + }; + + skin_cdsp { + trip = <&cx_emer_trip>; + cooling-device = <&cdsp_sw 4 4>; + }; + + skin_npu { + trip = <&cx_emer_trip>; + cooling-device = <&msm_npu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + skin_modem_skin_cdev0 { + trip = <&modem_skin_trip0>; + cooling-device = <&modem_skin 1 1>; + }; + + skin_modem_skin_cdev1 { + trip = <&modem_skin_trip1>; + cooling-device = <&modem_skin 2 2>; + }; + + skin_modem_skin_cdev2 { + trip = <&cx_emer_trip>; + cooling-device = <&modem_skin 3 3>; + }; + + skin_modem_cdev0 { + trip = <&modem_skin_trip2>; + cooling-device = <&modem_pa 1 1>; + }; + + skin_modem_cdev1 { + trip = <&skin_batt_modem_trip>; + cooling-device = <&modem_pa 2 2>; + }; + + skin_modem_cdev2 { + trip = <&cx_emer_trip>; + cooling-device = <&modem_pa 3 3>; + }; + + modem_pa_fr1_cdev0 { + trip = <&modem_skin_trip2>; + cooling-device = <&modem_pa_fr1 1 1>; + }; + + modem_pa_fr1_cdev1 { + trip = <&skin_batt_modem_trip>; + cooling-device = <&modem_pa_fr1 2 2>; + }; + + modem_pa_fr1_cdev2 { + trip = <&cx_emer_trip>; + cooling-device = <&modem_pa_fr1 3 3>; + }; + + batt_cdev0 { + trip = <&skin_batt_trip0>; + cooling-device = <&pm7250b_charger 8 8>; + }; + + batt_cdev1 { + trip = <&skin_batt_modem_trip>; + cooling-device = <&pm7250b_charger 12 12>; + }; + + batt_cdev2 { + trip = <&skin_batt_trip2>; + cooling-device = <&pm7250b_charger 14 14>; + }; + + batt_cdev3 { + trip = <&skin_batt_trip3>; + cooling-device = <&pm7250b_charger 16 16>; + }; + + batt_cdev4 { + trip = <&skin_batt_trip4>; + cooling-device = <&pm7250b_charger 18 18>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-usb.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..72056871df7f7133767e7eacc1f3faf11d418b0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-usb.dtsi @@ -0,0 +1,376 @@ +#include +#include +#include + +&soc { + usb0: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0x200000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x540 0x0>; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x90000000 0x60000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts-extended = <&pdc 14 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 15 IRQ_TYPE_LEVEL_HIGH>; + + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + qcom,use-pdc-interrupts; + + USB3_GDSC-supply = <&gcc_usb30_prim_gdsc>; + dpdm-supply = <&qusb_phy0>; + + clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,pm-qos-latency = <61>; /* CPU0-WFI-LVL latency +1 */ + + qcom,gsi-disable-io-coherency; + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + , + + /* min vote */ + , + , + ; + + dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xe000>; + interrupts = ; + usb-phy = <&qusb_phy0>, <&usb_qmp_dp_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3-u1u2-disable; + usb-core-id = <0>; + tx-fifo-resize; + maximum-speed = "super-speed"; + dr_mode = "drd"; + }; + qcom,usbbam@a704000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xa704000 0x17000>; + interrupts = ; + qcom,usb-bam-fifo-baseaddr = <0x146a6000>; + qcom,usb-bam-num-pipes = <4>; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x6064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + /* Primary USB port related QUSB2 PHY */ + qusb_phy0: qusb@88e3000 { + compatible = "qcom,qusb2phy-v2"; + reg = <0x088e3000 0x400>, + <0x00780268 0x4>, + <0x088e7014 0x4>, + <0x088e2000 0x4>; + reg-names = "qusb_phy_base", "efuse_addr", + "refgen_north_bg_reg_addr", + "eud_enable_reg"; + + qcom,efuse-bit-pos = <25>; + qcom,efuse-num-bits = <3>; + vdd-supply = <&L18A>; + vdda18-supply = <&L2A>; + vdda33-supply = <&L3A>; + refgen-supply = <&L22A>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x27c /* QUSB2PHY_DEBUG_CTRL1 */ + 0x280 /* QUSB2PHY_DEBUG_CTRL2 */ + 0x284 /* QUSB2PHY_DEBUG_CTRL3 */ + 0x288 /* QUSB2PHY_DEBUG_CTRL4 */ + 0x2a0>; /* QUSB2PHY_STAT5 */ + + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x22 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x30 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + qcom,qusb-phy-host-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x22 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x30 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + phy_type= "utmi"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + /* Primary USB port related QMP USB DP Combo PHY */ + usb_qmp_dp_phy: ssphy@88e8000 { + compatible = "qcom,usb-ssphy-qmp-dp-combo"; + reg = <0x88e8000 0x3000>; + reg-names = "qmp_phy_base"; + vdd-supply = <&L16A>; + qcom,vdd-voltage-level = <0 880000 880000>; + core-supply = <&L22A>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&rpmhcc RPMH_QLINK_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk"; + + resets = <&gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "global_phy_reset", "phy_reset"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x100f 0x0>; + qcom,iommu-dma = "disabled"; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon-vidc.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a70fec6804dc0fcae70e6b23833b856e61e71072 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon-vidc.dtsi @@ -0,0 +1,221 @@ +#include +#include +#include + +&soc { + msm_vidc0: qcom,vidc0 { + compatible = "qcom,msm-vidc", "qcom,lagoon-vidc"; + status = "ok"; + sku-index = <0>; + reg = <0xaa00000 0x0100000>; + interrupts = ; + + /* Supply */ + iris-ctl-supply = <&video_cc_mvsc_gdsc>; + vcodec-supply = <&video_cc_mvs0_gdsc>; + + /* Clocks */ + clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "core_clk", + "vcodec_clk", "iface_clk"; + clocks = <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&videocc VIDEO_CC_MVS0_AXI_CLK>, + <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_MVS0_CORE_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>; + + qcom,proxy-clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "core_clk", + "vcodec_clk", "iface_clk"; + + qcom,clock-configs = <0x0 0x0 0x1 0x1 0x0>; + qcom,allowed-clock-rates = <133250000 240000000 + 300000000 380000000 460000000>; + + qcom,reg-presets = <0xB0084 0x0>, + <0xB0088 0x0>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <762 762>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venus-ddr"; + qcom,bus-range-kbps = <762 15000000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0xc00 0x20>; + qcom,iommu-dma-addr-pool = <0x25800000 0xba800000>; + qcom,iommu-faults = "non-fatal"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0xc04 0x20>; + qcom,iommu-dma-addr-pool = <0x01000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0xc01 0x04>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0xc03 0x00>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x500000 0xdfb00000>; + qcom,secure-context-bank; + }; + }; + + msm_vidc1: qcom,vidc1 { + compatible = "qcom,msm-vidc", "qcom,lagoon-vidc"; + status = "ok"; + sku-index = <1>; + reg = <0xaa00000 0x0100000>; + interrupts = ; + + /* Supply */ + iris-ctl-supply = <&video_cc_mvsc_gdsc>; + vcodec-supply = <&video_cc_mvs0_gdsc>; + + /* Clocks */ + clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "core_clk", + "vcodec_clk", "iface_clk"; + clocks = <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&videocc VIDEO_CC_MVS0_AXI_CLK>, + <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_MVS0_CORE_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>; + + qcom,proxy-clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "core_clk", + "vcodec_clk", "iface_clk"; + + qcom,clock-configs = <0x0 0x0 0x1 0x1 0x0>; + qcom,allowed-clock-rates = <133250000 240000000 + 300000000 380000000>; + + qcom,reg-presets = <0xB0084 0x0>, + <0xB0088 0x0>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <762 762>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venus-ddr"; + qcom,bus-range-kbps = <762 15000000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0xc00 0x20>; + qcom,iommu-dma-addr-pool = <0x25800000 0xba800000>; + qcom,iommu-faults = "non-fatal"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0xc04 0x20>; + qcom,iommu-dma-addr-pool = <0x01000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0xc01 0x04>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x00500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0xc03 0x00>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x00500000 0xdfb00000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon.dts b/arch/arm64/boot/dts/vendor/qcom/lagoon.dts new file mode 100644 index 0000000000000000000000000000000000000000..72a3de3e7eac843031976ae0e5f6d4cc8de73ac0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "lagoon.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lagoon SoC"; + compatible = "qcom,lagoon"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lagoon.dtsi b/arch/arm64/boot/dts/vendor/qcom/lagoon.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b59baf1311f13dfda76abaf778e674d42e059549 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lagoon.dtsi @@ -0,0 +1,4096 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + +/ { + model = "Qualcomm Technologies, Inc. Lagoon"; + compatible = "qcom,lagoon"; + qcom,msm-id = <434 0x10000>, <459 0x10000>; + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + memory { device_type = "memory"; reg = <0 0 0 0>; }; + + mem-offline { + compatible = "qcom,mem-offline"; + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>, + <0x2 0xc0000000 0x1 0x40000000>; + granule = <512>; + mboxes = <&qmp_aop 0>; + }; + + aliases { + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + serial0 = &qupv3_se9_2uart; /* Debug Console */ + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + swr0 = &swr0; + swr1 = &swr1; + swr2 = &swr2; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + + L3_0: l3-cache { + compatible = "arm,arch-cache"; + cache-level = <3>; + }; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_100>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_100: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x200>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_200>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_200: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_200: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_200: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x300>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_300>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_300: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_300: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_300: l1-dcache { + compatible = "arm,arch-cache"; + }; + + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x400>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_400>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_400: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_400: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_400: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x500>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_500>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_500: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_500: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_500: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x600>; + enable-method = "psci"; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <703>; + qcom,freq-domain = <&cpufreq_hw 1 2>; + next-level-cache = <&L2_600>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + L2_600: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_600: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_600: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x700>; + enable-method = "psci"; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <703>; + qcom,freq-domain = <&cpufreq_hw 1 2>; + next-level-cache = <&L2_700>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + L2_700: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_700: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_700: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + + core4 { + cpu = <&CPU4>; + }; + + core5 { + cpu = <&CPU5>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU6>; + }; + + core1 { + cpu = <&CPU7>; + }; + }; + + }; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 earlycon=msm_geni_serial,0x98c000"; + }; + + soc: soc { }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_region: hyp_region@80000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x80000000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_mem@80700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x80700000 0x0 0x160000>; + }; + + sec_apps_mem: sec_apps_region@808ff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x808ff000 0x0 0x1000>; + }; + + smem_region: smem@80900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x80900000 0x0 0x200000>; + }; + + cdsp_sec_mem: cdsp_sec_regions@80b00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x80b00000 0x0 0x1e00000>; + }; + + pil_camera_mem: camera_region@86000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86000000 0x0 0x500000>; + }; + + pil_npu_mem: pil_npu_region@86500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86500000 0x0 0x500000>; + }; + + pil_video_mem: pil_video_region@86a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86a00000 0x0 0x500000>; + }; + + pil_cdsp_mem: cdsp_regions@86f00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86f00000 0x0 0x1e00000>; + }; + + pil_adsp_mem: pil_adsp_region@88d00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x88d00000 0x0 0x2800000>; + }; + + wlan_fw_mem: wlan_fw_region@8b500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8b500000 0x0 0x200000>; + }; + + pil_ipa_fw_mem: ipa_fw_region@8b700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8b700000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@8b710000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8b710000 0x0 0x5400>; + }; + + pil_gpu_mem: gpu_region@8b715400 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8b715400 0x0 0x2000>; + }; + + pil_modem_mem: modem_region@8b800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8b800000 0x0 0xf800000>; + }; + + removed_region: removed_region@c0000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0xc0000000 0x0 0x3900000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + secure_display_memory: secure_display_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x8c00000>; + }; + + cont_splash_memory: cont_splash_region { + reg = <0x0 0xA0000000 0x0 0x02300000>; + label = "cont_splash_region"; + }; + + disp_rdump_memory: disp_rdump_region@0xa0000000 { + reg = <0x0 0xA0000000 0x0 0x02300000>; + label = "disp_rdump_region"; + }; + + dfps_data_memory: dfps_data_region { + reg = <0x0 0xA2300000 0x0 0x0100000>; + label = "dfps_data_region"; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + size = <0 0x2800000>; + }; + + cmd_db: reserved-memory@80860000 { + reg = <0x0 0x80860000 0x0 0x20000>; + compatible = "qcom,cmd-db"; + no-map; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x2000000>; + linux,cma-default; + }; + }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + slim_aud: slim@3ac0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x3ac0000 0x2c000>, + <0x3a84000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = , + ; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x0>; + qcom,ea-pc = <0x380>; + iommus = <&apps_smmu 0x1026 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + status = "ok"; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&L11A>; /* IO */ + qca,bt-vdd-core-supply = <&L2E>; /* RFA */ + qca,bt-vdd-pa-supply = <&L10E>; /* CH0 */ + qca,bt-vdd-xtal-supply = <&L7A>; /* XO */ + + qca,bt-vdd-io-voltage-level = <1700000 1900000>; + qca,bt-vdd-core-voltage-level = <1304000 1304000>; + qca,bt-vdd-pa-voltage-level = <3000000 3312000>; + qca,bt-vdd-xtal-voltage-level = <1700000 1900000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + }; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = ; + interrupt-parent = <&intc>; + }; + + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + reg = <0x1d87000 0xe00>; /* PHY regs */ + reg-names = "phy_mem"; + #phy-cells = <0>; + + lanes-per-direction = <2>; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&rpmhcc RPMH_QLINK_CLK>, + <&gcc GCC_UFS_MEM_CLKREF_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + + status = "disabled"; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x3000>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; + interrupts = ; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + + lanes-per-direction = <2>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + spm-level = <5>; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + clocks = + <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&rpmhcc RPMH_QLINK_CLK>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <22>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G1 L2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G2 L2 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G3 L2 */ + <123 512 14752 0>, <1 757 1000 0>, /* PWM G4 L2 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G1 RA L2 */ + <123 512 511181 0>, <1 757 1000 0>, /* HS G2 RA L2 */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */ + <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */ + /* As UFS working in HS G3 RB L2 mode, aggregated + * bandwidth (AB) should take care of providing + * optimum throughput requested. However, as tested, + * in order to scale up CNOC clock, instantaneous + * bindwidth (IB) needs to be given a proper value too. + */ + <123 512 4194304 0>, <1 757 204800 409600>, /* HS G3 RB L2 */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-cpu-group-latency-us = <67 67>; + qcom,pm-qos-default-cpu = <0>; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + non-removable; + + status = "disabled"; + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x280000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + clock-frequency = <19200000>; + }; + + timer@17c20000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c20000 0x1000>; + clock-frequency = <19200000>; + + frame@17c21000 { + frame-number = <0>; + interrupts = , + ; + reg = <0x17c21000 0x1000>, + <0x17c22000 0x1000>; + }; + + frame@17c23000 { + frame-number = <1>; + interrupts = ; + reg = <0x17c23000 0x1000>; + status = "disabled"; + }; + + frame@17c25000 { + frame-number = <2>; + interrupts = ; + reg = <0x17c25000 0x1000>; + status = "disabled"; + }; + + frame@17c27000 { + frame-number = <3>; + interrupts = ; + reg = <0x17c27000 0x1000>; + status = "disabled"; + }; + + frame@17c29000 { + frame-number = <4>; + interrupts = ; + reg = <0x17c29000 0x1000>; + status = "disabled"; + }; + + frame@17c2b000 { + frame-number = <5>; + interrupts = ; + reg = <0x17c2b000 0x1000>; + status = "disabled"; + }; + + frame@17c2d000 { + frame-number = <6>; + interrupts = ; + reg = <0x17c2d000 0x1000>; + status = "disabled"; + }; + }; + + ipcc_mproc: qcom,ipcc@408000 { + compatible = "qcom,ipcc"; + reg = <0x408000 0x1000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,lagoon-pdc"; + reg = <0xb220000 0x30000>, <0x17c000f0 0x64>; + qcom,pdc-ranges = <0 480 94>, <94 609 31>, <125 63 1>, + <126 655 12>, <138 139 15>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + apps_rsc: rsc@18200000 { + label = "apps_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0x18200000 0x10000>, + <0x18210000 0x10000>, + <0x18220000 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + + system_pm { + compatible = "qcom,system-pm"; + }; + + msm_bus_apps_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; + + rpmhcc: qcom,rpmhclk { + compatible = "qcom,lagoon-rpmh-clk"; + #clock-cells = <1>; + }; + }; + + disp_rsc: rsc@af20000 { + label = "disp_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0xaf20000 0x10000>; + reg-names = "drv-0"; + interrupts = ; + qcom,tcs-offset = <0x1c00>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + + msm_bus_disp_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; + + sde_rsc_rpmh { + compatible = "qcom,sde-rsc-rpmh"; + cell-index = <0>; + }; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = ; + }; + + cache-controller@9200000 { + compatible = "lagoon-llcc-v1"; + reg = <0x9200000 0x50000> , <0x9600000 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + cap-based-alloc-and-pwr-collapse; + }; + + qcom,msm-imem@146aa000 { + compatible = "qcom,msm-imem"; + reg = <0x146aa000 0x1000>; + ranges = <0x0 0x146aa000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 0x8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 0x4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 0x20>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 0xc>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 0xc8>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 0xc8>; + }; + }; + + dcc: dcc_v2@109f000 { + compatible = "qcom,dcc-v2"; + reg = <0x109f000 0x1000>, + <0x1026000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + dcc-ram-offset = <0x6000>; + + qcom,curr-link-list = <4>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + restart@c264000 { + compatible = "qcom,pshold"; + reg = <0xc264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom_seecom: qseecom@c1700000 { + compatible = "qcom,qseecom"; + reg = <0xc1700000 0x2200000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + qcom,commonlib64-loaded-by-uefi; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_smcinvoke: smcinvoke@c1700000 { + compatible = "qcom,smcinvoke"; + reg = <0xc1700000 0x2200000>; + reg-names = "secapp-region"; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , /* No vote */ + ; /* 75 MHz */ + clocks = <&gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + + qcom_tzlog: tz-log@146aa720 { + compatible = "qcom,tz-log"; + reg = <0x146aa720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0424 0x0011>, + <&apps_smmu 0x0434 0x0011>; + qcom,iommu-dma = "atomic"; + }; + + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0426 0x0011>, + <&apps_smmu 0x0436 0x0011>; + qcom,iommu-dma = "atomic"; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&apps_smmu 0x432 0>, + <&apps_smmu 0x438 0x1>, + <&apps_smmu 0x43F 0>; + }; + + qcom_cedev_s_cb { + compatible = "qcom,qcedev,context-bank"; + label = "secure_context"; + iommus = <&apps_smmu 0x433 0>, + <&apps_smmu 0x43C 0x1>, + <&apps_smmu 0x43E 0>; + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ + qcom,secure-context-bank; + }; + }; + + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + + qcom,mpm2-sleep-counter@0xc221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + wdog: qcom,wdt@17c10000 { + compatible = "qcom,msm-watchdog"; + reg = <0x17c10000 0x1000>; + reg-names = "wdt-base"; + interrupts = , + ; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + qcom,scandump-sizes = <0x10100 0x10100 0x10100 0x10100 + 0x10100 0x10100 0x25900 0x25900>; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + + qcom,chd_sliver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x18000058 0x18010058 + 0x18020058 0x18030058 + 0x18040058 0x18050058>; + qcom,config-arr = <0x18000060 0x18010060 + 0x18020060 0x18030060 + 0x18040060 0x18050060>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x18060058 0x18070058>; + qcom,config-arr = <0x18060060 0x18070060>; + }; + + kryo-erp { + compatible = "arm,arm64-kryo-cpu-erp"; + interrupts = , + ; + interrupt-names = "l1-l2-faultirq", + "l3-scu-faultirq"; + }; + + qcom,lpass@3000000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x03000000 0x00100>; + + vdd_lpi_cx-supply = <&L1A_LEVEL>; + qcom,vdd_lpi_cx-uV-uA = ; + vdd_lpi_mx-supply = <&L17A_LEVEL>; + qcom,vdd_lpi_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_lpi_cx", "vdd_lpi_mx"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,minidump-id = <5>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + qcom,minidump-as-elf32; + + /* Inputs from lpass */ + interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack"; + + /* Outputs to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; + }; + + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,vdd_cx-uV-uA = ; + vdd_mx-supply = <&VDD_MX_LEVEL>; + qcom,vdd_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx", "vdd_mx"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,minidump-id = <7>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&pil_cdsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + qcom,minidump-as-elf32; + + qcom,msm-bus,name = "pil-cdsp"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + + /* Inputs from turing */ + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x4080000 0x100>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,vdd_cx-uV-uA = ; + vdd_mss-supply = <&VDD_MSS_LEVEL>; + qcom,vdd_mss-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx", "vdd_mss"; + + qcom,firmware-name = "modem"; + memory-region = <&pil_modem_mem>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,pas-id = <4>; + qcom,smem-id = <421>; + qcom,signal-aop; + qcom,minidump-id = <3>; + qcom,aux-minidump-ids = <4>; + qcom,complete-ramdump; + + /* Inputs from mss */ + interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_EDGE_RISING>, + <&mpss_smp2p_in 0 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 1 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 2 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 3 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 7 IRQ_TYPE_NONE>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + qcom,msm-bus,name = "pil-modem"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 8171520>; + + /* Outputs to mss */ + qcom,smem-states = <&mpss_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "mss-pil"; + }; + + thermal_zones: thermal-zones {}; + + tsens0:tsens@c222000 { + compatible = "qcom,tsens24xx"; + reg = <0x0C222000 0x8>, + <0x0C263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts-extended = <&pdc 26 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 28 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 20 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tsens-upper-lower", "tsens-critical", + "tsens-0C"; + 0C-sensor-num = <16>; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + tsens1:tsens@c223000 { + compatible = "qcom,tsens24xx"; + reg = <0x0C223000 0x8>, + <0x0C265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts-extended = <&pdc 27 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 29 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 21 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tsens-upper-lower", "tsens-critical", + "tsens-0C"; + 0C-sensor-num = <16>; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + spmi_bus: qcom,spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0x1100>, + <0xc600000 0x2000000>, + <0xe600000 0x100000>, + <0xe700000 0xa0000>, + <0xc40a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect-v3"; + qcom,threshold-arr = <0x17e0041c>; + qcom,config-reg = <0x17e00434>; + }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <76800000>; + clock-output-names = "xo_board"; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32764>; + clock-output-names = "chip_sleep_clk"; + #clock-cells = <0>; + }; + }; + + aopcc: qcom,aopcc { + compatible = "qcom,aop-qmp-clk"; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + #clock-cells = <1>; + }; + + gcc: qcom,gcc@100000 { + compatible = "qcom,lagoon-gcc", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + camcc: qcom,camcc@ad00000 { + compatible = "qcom,lagoon-camcc", "syscon"; + reg = <0xad00000 0x16000>; + reg-names = "cc_base"; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + dispcc: qcom,dispcc@af00000 { + compatible = "qcom,lagoon-dispcc", "syscon"; + reg = <0xaf00000 0x20000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + gpucc: qcom,gpucc@3d90000 { + compatible = "qcom,lagoon-gpucc", "syscon"; + reg = <0x3d90000 0x9000>; + reg-names = "cc_base"; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_gx-supply = <&VDD_GFX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + npucc: qcom,npucc@9980000 { + compatible = "qcom,lagoon-npucc", "syscon"; + reg = <0x9980000 0x10000>, + <0x9800000 0x10000>, + <0x9810000 0x10000>, + <0x007841e0 0x8>; + reg-names = "cc", "qdsp6ss", "qdsp6ss_pll", "efuse"; + npu_gdsc-supply = <&npu_cc_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + + videocc: qcom,videocc@aaf0000 { + compatible = "qcom,lagoon-videocc", "syscon"; + reg = <0x0aaf0000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cpucc: syscon@182a0018 { + compatible = "syscon"; + reg = <0x182a0000 0x1000>; + }; + + mccc: syscon@90b0000 { + compatible = "syscon"; + reg = <0x90b0000 0x1000>; + }; + + debugcc: qcom,cc-debug { + compatible = "qcom,lagoon-debugcc"; + qcom,gcc = <&gcc>; + qcom,videocc = <&videocc>; + qcom,camcc = <&camcc>; + qcom,dispcc = <&dispcc>; + qcom,gpucc = <&gpucc>; + qcom,npucc = <&npucc>; + qcom,cpucc = <&cpucc>; + qcom,mccc = <&mccc>; + clock-names = "xo_clk_src"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + #clock-cells = <1>; + }; + + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw"; + reg = <0x18323000 0x1000>, <0x18325800 0x1000>; + reg-names = "freq-domain0", "freq-domain1"; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>; + clock-names = "xo", "alternate"; + qcom,no-accumulative-counter; + #freq-domain-cells = <2>; + }; + + qcom,cpufreq-hw-debug@18320000 { + compatible = "qcom,cpufreq-hw-debug"; + reg = <0x18320000 0x800>; + reg-names = "domain-top"; + qcom,freq-hw-domain = <&cpufreq_hw 0>, <&cpufreq_hw 1>; + }; + + qcom,devfreq-l3 { + compatible = "qcom,devfreq-fw"; + reg = <0x18321000 0x4>, <0x18321110 0x500>, <0x18321920 0x4>; + reg-names = "en-base", "ftbl-base", "perf-base"; + + qcom,ftbl-row-size = <32>; + + cpu0_l3: qcom,cpu0-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cpu6_l3: qcom,cpu6-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cdsp_l3: qcom,cdsp-cdsp-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + }; + + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + qcom,rpc-latency-us = <235>; + qcom,qos-cores = <0 1 2 3 4 5>; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1401 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1402 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1403 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1404 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1405 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1406 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1407 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1408 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1409 0x0020>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + qcom,iommu-vmid = <0xA>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1003 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1004 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1005 0x0>; + shared-cb = <5>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "modem_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 0x2>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "adsp_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "dsps_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x20 12>; + + qcom,cdsp-cdsp-l3-gov { + compatible = "qcom,cdsp-l3"; + qcom,target-dev = <&cdsp_l3>; + }; + + msm_cdsp_rm: qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <70>; + qcom,qos-maxhold-ms = <20>; + qcom,compute-cx-limit-en; + qcom,compute-priority-mode = <2>; + }; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_npu>; + }; + }; + + glink_npu: npu { + qcom,remote-pid = <10>; + transport = "smem"; + mboxes = <&msm_npu IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "npu_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "npu"; + qcom,glink-label = "npu"; + + qcom,npu_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,npu_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,smp2p-mpss { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + mpss_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + mpss_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_wlan_1_in: qcom,smp2p-wlan-1-in { + qcom,entry-name = "wlan"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg5_out: qcom,smp2p-rdbg5-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_in: qcom,smp2p-rdbg5-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-npu { + compatible = "qcom,smp2p"; + qcom,smem = <617>, <616>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&msm_npu IPCC_CLIENT_NPU IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <10>; + + npu_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + npu_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + reg = <0xc300000 0x1000>; + reg-names = "msgram"; + mboxes = <&ipcc_mproc IPCC_CLIENT_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "aop_qmp"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + + label = "aop"; + qcom,early-boot; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + qcom,venus@aab0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xaab0000 0x2000>; + + vdd-supply = <&video_cc_mvsc_gdsc>; + qcom,proxy-reg-names = "vdd"; + qcom,complete-ramdump; + + clocks = <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>; + clock-names = "core", "ahb"; + qcom,proxy-clock-names = "core", "ahb"; + + qcom,core-freq = <200000000>; + qcom,ahb-freq = <200000000>; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + }; + + cx_ipeak_lm: cx_ipeak@1fed000 { + compatible = "qcom,cx-ipeak-v2"; + reg = <0x1fed000 0x9000>; + }; + + qcom,npu@9800000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x9800000 0x800000>; + status = "ok"; + qcom,pas-id = <23>; + qcom,firmware-name = "npu"; + memory-region = <&pil_npu_mem>; + + /* Outputs to npu */ + qcom,smem-states = <&npu_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupt-parent = <&pdc>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x088e0000 0x2000>, + <0x088e2000 0x1000>; + reg-names = "eud_base", "eud_mode_mgr2"; + qcom,secure-eud-en; + status = "ok"; + }; + + llcc_pmu: llcc-pmu@90cc000 { + compatible = "qcom,llcc-pmu-ver1"; + reg = <0x090cc000 0x300>; + reg-names = "lagg-base"; + }; + + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + }; + + suspendable_llcc_bw_opp_table: suspendable-llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 16); /* 0 MB/s */ + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x90B6300 0x300>, <0x090B6200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; + + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90cd000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + BW_OPP_ENTRY(2092, 4); /* 8136 MB/s */ + }; + + npu_npu_llcc_bw: qcom,npu-npu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_llcc_bw_opp_table>; + }; + + npu_npu_llcc_bwmon: qcom,npu-npu-llcc-bwmon@9960300 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x00060400 0x300>, <0x00060300 0x200>; + reg-names = "base", "global_base"; + clocks = <&gcc RPMH_CXO_CLK>, + <&gcc GCC_NPU_BWMON_DMA_CFG_AHB_CLK>, + <&gcc GCC_NPU_BWMON_AXI_CLK>; + clock-names = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,bwmon_clks = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,msm_bus = <154 512>; + qcom,msm_bus_name = "npu_bwmon_cdsp"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_npu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + npu_llcc_ddr_bw: qcom,npu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npu_llcc_ddr_bwmon: qcom,npu-llcc-ddr-bwmon@90CE000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90CE000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + npudsp_npu_ddr_bw: qcom,npudsp-npu-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npudsp_npu_ddr_bwmon: qcom,npudsp-npu-ddr-bwmon@70200 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x00070300 0x300>, <0x00070200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + clocks = <&gcc RPMH_CXO_CLK>, + <&gcc GCC_NPU_BWMON_DSP_CFG_AHB_CLK>, + <&gcc GCC_NPU_BWMON_AXI_CLK>; + clock-names = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,bwmon_clks = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,msm_bus = <154 512>; + qcom,msm_bus_name = "npu_bwmon_cdsp"; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npudsp_npu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_memlat_cpugrp: qcom,cpu0-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + + cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 768000 300000000 >, + < 1017600 556800000 >, + < 1248000 806400000 >, + < 1516800 940800000 >, + < 1612800 1209600000 >, + < 1804800 1459000000 >; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 1248000 MHZ_TO_MBPS(300, 16) >, + < 1516800 MHZ_TO_MBPS(466, 16) >, + < 1804800 MHZ_TO_MBPS(600, 16) >; + }; + + cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS( 300, 4) >, + < 1017600 MHZ_TO_MBPS( 451, 4) >, + < 1248000 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 768000 MHZ_TO_MBPS( 300, 4) >, + < 1248000 MHZ_TO_MBPS( 451, 4) >, + < 1516800 MHZ_TO_MBPS( 547, 4) >, + < 1804800 MHZ_TO_MBPS( 768, 4) >; + }; + }; + + cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_memlat_cpugrp: qcom,cpu6-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU6 &CPU7>; + + cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,access-ev = <0x2B>; + qcom,wb-ev = <0x18>; + qcom,core-dev-table = + < 1036800 556800000 >, + < 1248000 806400000 >, + < 1555400 940800000 >, + < 1766400 1209600000 >, + < 1900800 1401600000 >, + < 2246000 1459000000 >; + }; + + cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 787200 MHZ_TO_MBPS(300, 16) >, + < 1036800 MHZ_TO_MBPS(466, 16) >, + < 1248000 MHZ_TO_MBPS(600, 16) >, + < 1555200 MHZ_TO_MBPS(806, 16) >, + < 2246000 MHZ_TO_MBPS(933, 16) >; + }; + + cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 1036800 MHZ_TO_MBPS( 547, 4) >, + < 1248000 MHZ_TO_MBPS(1017, 4) >, + < 1555200 MHZ_TO_MBPS(1555, 4) >, + < 1900800 MHZ_TO_MBPS(1804, 4) >, + < 2246000 MHZ_TO_MBPS(2092, 4) >; + }; + + cpu6_computemon: qcom,cpu6-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1248800 MHZ_TO_MBPS( 547, 4) >, + < 1401600 MHZ_TO_MBPS( 768, 4) >, + < 1555200 MHZ_TO_MBPS(1017, 4) >, + < 1766400 MHZ_TO_MBPS(1555, 4) >, + < 1900800 MHZ_TO_MBPS(1804, 4) >, + < 2246000 MHZ_TO_MBPS(2092, 4) >; + }; + }; + + keepalive_opp_table: keepalive-opp-table { + compatible = "operating-points-v2"; + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = ; + qcom,active-only; + status = "ok"; + operating-points-v2 = <&keepalive_opp_table>; + }; + + bus_proxy_client: qcom,bus_proxy_client { + compatible = "qcom,bus-proxy-client"; + qcom,msm-bus,name = "bus-proxy-client"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,msm-bus,active-only; + status = "ok"; + }; + + sdhc_1: sdhci@7c4000 { + compatible = "qcom,sdhci-msm-v5", "qcom,sdhci-msm-cqe"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>, <0x7c8000 0x8000>; + reg-names = "hc_mem", "cqhci_mem", "cqhci_ice"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + clocks = <&gcc GCC_SDCC1_AHB_CLK>, + <&gcc GCC_SDCC1_APPS_CLK>, + <&gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,ice-clk-rates = <300000000 100000000>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <150 10073 0 0>, + <135 512 0 0>, + <1 825 0 0>, + /* 400 KB/s */ + <150 10073 1000 790000>, + <135 512 1000 1800000>, + <1 825 2000 131000>, + /* 25 MB/s */ + <150 10073 50000 790000>, + <135 512 50000 1800000>, + <1 825 30000 131000>, + /* 50 MB/s */ + <150 10073 50000 790000>, + <135 512 80000 1800000>, + <1 825 40000 131000>, + /* 100 MB/s */ + <150 10073 50000 790000>, + <135 512 100000 1800000>, + <1 825 50000 131000>, + /* 200 MB/s */ + <150 10073 50000 790000>, + <135 512 150000 1800000>, + <1 825 80000 131000>, + /* 400 MB/s */ + <150 10073 261438 3190000>, + <135 512 261438 4000000>, + <1 825 300000 294000>, + /* Max. bandwidth */ + <150 10073 1338562 4290000>, + <135 512 1338562 7200000>, + <1 825 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <59 59>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-cmdq-latency-us = <65 65>, <65 65>; + qcom,pm-qos-legacy-latency-us = <65 65>, <65 65>; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x000f642c 0x0 0x0 0x00010800 0x80040868>; + + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 25000000 + 50000000 100000000 202000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 202000000>; + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 10073 0 0>, + <135 512 0 0>, + <1 608 0 0>, + /* 400 KB/s*/ + <81 10073 1000 790000>, + <135 512 1000 1800000>, + <1 608 2000 131000>, + /* 25 MB/s */ + <81 10073 50000 790000>, + <135 512 50000 1800000>, + <1 608 30000 131000>, + /* 50 MB/s */ + <81 10073 50000 790000>, + <135 512 80000 1800000>, + <1 608 40000 131000>, + /* 100 MB/s */ + <81 10073 50000 790000>, + <135 512 100000 1800000>, + <1 608 50000 131000>, + /* 200 MB/s */ + <81 10073 261438 3190000>, + <135 512 261438 4000000>, + <1 608 300000 294000>, + /* Max. bandwidth */ + <81 10073 1338562 4290000>, + <135 512 1338562 7200000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 25000000 50000000 + 100000000 200000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <59 59>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <65 65>, <65 65>; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642c 0x0 0x0 0x00010800 0x80040868>; + + status = "disabled"; + }; + + icnss: qcom,icnss@18800000 { + compatible = "qcom,icnss"; + reg = <0x18800000 0x800000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x20 0x1>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + qcom,iommu-dma = "fastmap"; + qcom,iommu-faults = "stall-disable", "non-fatal"; + qcom,wlan-msa-fixed-region = <&wlan_fw_mem>; + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; + vdd-cx-mx-supply = <&L4A>; + vdd-1.8-xo-supply = <&L7A>; + vdd-1.3-rfa-supply = <&L2E>; + vdd-3.3-ch1-supply = <&L11E>; + vdd-3.3-ch0-supply = <&L10E>; + qcom,vdd-cx-mx-config = <0 0>; + qcom,vdd-1.3-rfa-config = <1224000 1304000>; + qcom,vdd-3.3-ch1-config = <3000000 3312000>; + qcom,vdd-3.3-ch0-config = <3000000 3312000>; + qcom,smp2p_map_wlan_1_in { + interrupts-extended = <&smp2p_wlan_1_in 0 0>, + <&smp2p_wlan_1_in 1 0>; + interrupt-names = "qcom,smp2p-force-fatal-error", + "qcom,smp2p-early-crash-ind"; + }; + }; + + qfprom: qfprom@780000 { + compatible = "qcom,qfprom"; + reg = <0x00780000 0x7000>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + ranges; + + gpu_speed_bin: gpu_speed_bin@6015 { + reg = <0x6015 0x1>; + bits = <0 8>; + }; + + feat_conf8: feat_conf8@6024 { + reg = <0x6024 0x4>; + }; + + gpu_gaming_bin: gpu_gaming_bin@6026 { + reg = <0x6026 0x1>; + bits = <5 1>; + }; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x80000>; + qcom,dump-id = <0xe4>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + etf_swao { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf1>; + }; + + etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + etfswao_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + + ipa { + qcom,dump-size = <0x11000>; + qcom,dump-id = <0x150>; + }; + + etf_lpass { + qcom,dump-size = <0x4000>; + qcom,dump-id = <0xf4>; + }; + + etflpass_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x104>; + }; + + c0_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x0>; + }; + + c100_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x1>; + }; + + c200_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x2>; + }; + + c300_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x3>; + }; + + c400_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x4>; + }; + + c500_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x5>; + }; + + c600_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x6>; + }; + + c700_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x7>; + }; + + c0_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x130>; + }; + + c100_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x131>; + }; + + c200_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x132>; + }; + + c300_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x133>; + }; + + c400_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x134>; + }; + + c500_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x135>; + }; + + c600_scandump { + qcom,dump-size = <0x25900>; + qcom,dump-id = <0x136>; + }; + + c700_scandump { + qcom,dump-size = <0x25900>; + qcom,dump-id = <0x137>; + }; + + l1_i_cache0 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x60>; + }; + + l1_icache100 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x61>; + }; + + l1_icache200 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x62>; + }; + + l1_icache300 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x63>; + }; + + l1_icache400 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x64>; + }; + + l1_icache500 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x65>; + }; + + l1_icache600 { + qcom,dump-size = <0x21000>; + qcom,dump-id = <0x66>; + }; + + l1_icache700 { + qcom,dump-size = <0x21000>; + qcom,dump-id = <0x67>; + }; + + l1_dcache0 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x80>; + }; + + l1_dcache100 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x81>; + }; + + l1_dcache200 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x82>; + }; + + l1_dcache300 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x83>; + }; + + l1_dcache400 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x84>; + }; + + l1_dcache500 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x85>; + }; + + l1_dcache600 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x86>; + }; + + l1_dcache700 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x87>; + }; + + l1_itlb600 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x26>; + }; + + l1_itlb700 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x27>; + }; + + l1_dtlb600 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x46>; + }; + + l1_dtlb700 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x47>; + }; + + l2_cache600 { + qcom,dump-size = <0x48000>; + qcom,dump-id = <0xc6>; + }; + + l2_cache700 { + qcom,dump-size = <0x48000>; + qcom,dump-id = <0xc7>; + }; + + l2_tlb0 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x120>; + }; + + l2_tlb100 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x121>; + }; + + l2_tlb200 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x122>; + }; + + l2_tlb300 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x123>; + }; + + l2_tlb400 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x124>; + }; + + l2_tlb500 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x125>; + }; + + l2_tlb600 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x126>; + }; + + l2_tlb700 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x127>; + }; + + llcc1_d_cache { + qcom,dump-size = <0x1141c0>; + qcom,dump-id = <0x140>; + }; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-platform-type-msm; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "lagoon_ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; + }; + + ipa_hw: qcom,ipa@1e00000 { + compatible = "qcom,ipa"; + reg = <0x1e00000 0x84000>, + <0x1e04000 0x23000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = , + ; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <18>; /* IPA core version = IPAv4.7 */ + qcom,ipa-hw-mode = <0>; + qcom,platform-type = <1>; /* MSM platform */ + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,ipa-wdi2_over_gsi; + qcom,use-ipa-pm; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,bandwidth-vote-for-ipa; + qcom,ipa-endp-delay-wa; + qcom,use-64-bit-dma-mask; + qcom,msm-bus,name = "ipa"; + qcom,use-gsi-ipa-fw = "lagoon_ipa_fws"; + qcom,wan-use-skb-page; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <5>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + , + , + , + , + , + + /* SVS2 */ + , + , + , + , + , + + /* SVS */ + , + , + , + , + , + + /* NOMINAL */ + , + , + , + , + , + + /* TURBO */ + , + , + , + , + ; + + + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x0440 0x0>; + qcom,iommu-dma-addr-pool = <0x20000000 0x40000000>; + /* modem tables in IMEM */ + qcom,additional-mapping = <0x146a8000 0x146a8000 0x2000>; + qcom,iommu-dma = "fastmap"; + qcom,ipa-q6-smem-size = <26624>; + qcom,geometry-mapping = <0x0 0xF0000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x0441 0x0>; + /* ipa-uc ram */ + qcom,additional-mapping = <0x1ea0000 0x1ea0000 0x80000>; + qcom,iommu-dma = "atomic"; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x0442 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0x20000000>; + }; +}; + +#include "lagoon-gdsc.dtsi" +#include "lagoon-usb.dtsi" +#include "lagoon-gpu.dtsi" +#include "lagoon-npu.dtsi" +#include "camera/lagoon-camera.dtsi" + +&gcc_ufs_phy_gdsc { + status = "ok"; +}; + +&gcc_usb30_prim_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc { + status = "ok"; +}; + +&cam_cc_bps_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&cam_cc_ife_0_gdsc { + status = "ok"; +}; + +&cam_cc_ife_1_gdsc { + status = "ok"; +}; + +&cam_cc_ife_2_gdsc { + status = "ok"; +}; + +&cam_cc_ipe_0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&cam_cc_titan_top_gdsc { + status = "ok"; +}; + +&mdss_core_gdsc { + status = "ok"; +}; + +&gpu_gx_gdsc { + parent-supply = <&VDD_GFX_LEVEL>; + status = "ok"; +}; + +&gpu_cx_gdsc { + parent-supply = <&VDD_CX_LEVEL>; + vdd_parent-supply = <&VDD_CX_LEVEL>; + status = "ok"; +}; + +&npu_cc_core_gdsc { + status = "ok"; +}; + +&video_cc_mvs0_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&video_cc_mvsc_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + status = "ok"; +}; + +#include "msm-arm-smmu-lagoon.dtsi" +#include "lagoon-pinctrl.dtsi" +#include "lagoon-pm.dtsi" +#include "lagoon-regulators.dtsi" +#include "lagoon-coresight.dtsi" +#include "pm6350.dtsi" +#include "pm7250b.dtsi" +#include "pm6150l.dtsi" +#include "pmk8350.dtsi" +#include "lagoon-ion.dtsi" +#include "lagoon-qupv3.dtsi" +#include "lagoon-audio.dtsi" +#include "ipcc-test-lagoon.dtsi" +#include "lagoon-vidc.dtsi" + +&qupv3_se10_i2c { + status = "ok"; + #include "pm8008.dtsi" +}; + +&pm8008_8 { + /* PM8008 IRQ STAT */ + interrupt-parent = <&tlmm>; + interrupts = <59 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_active &pm8008_interrupt>; +}; + +&pm8008_regulators { + vdd_l1_l2-supply = <&S8E>; + vdd_l3_l4-supply = <&BOB>; + vdd_l5-supply = <&BOB>; + vdd_l6-supply = <&S2A>; + vdd_l7-supply = <&BOB>; +}; + +&L1P { + regulator-max-microvolt = <1056000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <209000>; +}; + +&L2P { + regulator-max-microvolt = <1104000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <209000>; +}; + +&L3P { + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <128000>; +}; + +&L4P { + regulator-max-microvolt = <2904000>; + qcom,min-dropout-voltage = <96000>; +}; + +&L5P { + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <300000>; +}; + +&L6P { + regulator-max-microvolt = <1800000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <56000>; +}; + +&L7P { + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <120000>; +}; + +&pm7250b_charger { + dpdm-supply = <&qusb_phy0>; + + smb5_vbus: qcom,smb5-vbus { + regulator-name = "smb5-vbus"; + }; + + smb5_vconn: qcom,smb5-vconn { + regulator-name = "smb5-vconn"; + }; +}; + +/*Debug UART*/ +&qupv3_se9_2uart { + status = "ok"; +}; + +/* HS UART */ +&qupv3_se1_4uart { + status = "ok"; +}; + +#include "lagoon-bus.dtsi" +#include "lagoon-thermal.dtsi" + +&pm7250b_vadc { + #address-cells = <1>; + #size-cells = <0>; + + charger_skin_therm { + reg = ; + label = "charger_skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + conn_therm { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm7250b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm7250b_vadc ADC_AMUX_THM1_PU2>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>; + + /* Channel nodes */ + charger_skin_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + conn_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm6150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = < + &rfc_cam_therm_default + &rear_cam_flash_therm_default + &quiet_therm_default + >; + + pa_therm2 { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + msm_therm { + reg = ; + label = "msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1 { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + rfc_cam_therm { + reg = ; + label = "rfc_cam_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + rear_cam_flash_therm { + reg = ; + label = "rear_cam_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + quiet_therm { + reg = ; + label = "quiet_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm6150l_gpios { + rfc_cam_therm { + rfc_cam_therm_default: rfc_cam_therm_default { + pins = "gpio6"; + bias-high-impedance; + }; + }; + + rear_cam_flash_therm { + rear_cam_flash_therm_default: rear_cam_flash_therm_default { + pins = "gpio7"; + bias-high-impedance; + }; + }; + + quiet_therm { + quiet_therm_default: quiet_therm_default { + pins = "gpio10"; + bias-high-impedance; + }; + }; +}; + +&pm6150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm6150l_vadc ADC_AMUX_THM1_PU2>, + <&pm6150l_vadc ADC_AMUX_THM3_PU2>, + <&pm6150l_vadc ADC_GPIO3_PU2>, + <&pm6150l_vadc ADC_GPIO4_PU2>; + + /* Channel nodes */ + + pa_therm1 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm0 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + rear_cam_flash_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + quiet_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pmk8350_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pmk8350_vadc PMK8350_ADC7_AMUX_THM1_100K_PU>; + + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&spmi_bus { + qcom,pm6150l@4 { + pm6150l_adc_tm_iio: adc_tm@3400 { + compatible = "qcom,adc-tm5-iio"; + reg = <0x3400 0x100>; + #thermal-sensor-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm6150l_vadc ADC_AMUX_THM2_PU2>, + <&pm6150l_vadc ADC_GPIO2_PU2>; + + msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + rfc_cam_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + }; + }; +}; + +&pm7250b_pdphy { + vdd-pdphy-supply = <&L3A>; + vbus-supply = <&smb5_vbus>; + vconn-supply = <&smb5_vconn>; +}; + +&usb0 { + extcon = <&pm7250b_pdphy>, <&pm7250b_charger>, <&eud>; +}; + +&usb_qmp_dp_phy { + extcon = <&pm7250b_pdphy>; +}; + +&msm_vidc0 { + qcom,cx-ipeak-data = <&cx_ipeak_lm 5>; + qcom,clock-freq-threshold = <460000000>; +}; + +&msm_vidc1 { + qcom,cx-ipeak-data = <&cx_ipeak_lm 5>; + qcom,clock-freq-threshold = <380000000>; +}; + +#include "lagoon-sde.dtsi" +#include "lagoon-sde-pll.dtsi" +#include "msm-rdbg.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-atp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-atp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..99e6f63e68648b4039b3ac3eca040d786ae7b4a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-atp-overlay.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-atp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito ATP"; + compatible = "qcom,lito-atp", "qcom,lito", "qcom,atp"; + qcom,msm-id = <400 0x10000>, <440 0x10000>; + qcom,board-id = <33 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-atp.dts b/arch/arm64/boot/dts/vendor/qcom/lito-atp.dts new file mode 100644 index 0000000000000000000000000000000000000000..8828a848714c49f15cfee6ae65a05cd3752cc6e7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-atp.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "lito.dtsi" +#include "lito-atp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito ATP"; + compatible = "qcom,lito-atp", "qcom,lito", "qcom,atp"; + qcom,board-id = <33 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-atp.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-atp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e2e73cba92411512f7374485f5adb99c8d00604d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-atp.dtsi @@ -0,0 +1,276 @@ +#include +#include "lito-audio-overlay.dtsi" +#include "lito-pmic-overlay.dtsi" +#include "lito-sde-display.dtsi" +#include "lito-thermal-overlay.dtsi" + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150l_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + vdda_usb_ss_dp_core: vdda_usb_ss_dp_core { + compatible = "regulator-fixed"; + regulator-name = "vdd_supply"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + enable-active-high; + gpio = <&pm8150l_gpios 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_eldo13>; + }; + +}; + +&usb_qmp_dp_phy { + vdd-supply = <&vdda_usb_ss_dp_core>; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4-lito"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <90200>; + vdda-pll-max-microamp = <19000>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150a_l7>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l9>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm8150a_l7>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm8150_s4>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage"; + qcom,batteryless-platform; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; +}; + +&qupv3_se7_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <9 0x2008>; + vdd-supply = <&pm8150_s4>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 9 0x2008>; + st,reset-gpio = <&tlmm 8 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + }; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sim_sec_hd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-sec-reset-gpio = <&tlmm 128 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_video>; +}; + +&qupv3_se0_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 34 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 35 0x00>; + qcom,nq-clkreq = <&tlmm 31 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <34 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-audio-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-audio-overlay.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..9f946ac7beba35c595e3ec84a6bcc6ae0343cf74 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-audio-overlay.dtsi @@ -0,0 +1,504 @@ +#include +#include +#include +#include +#include "lito-lpi.dtsi" + +&bolero { + qcom,num-macros = <3>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,wsa_mclk_mode_muxsel = <0x033220D8>; + qcom,va_mclk_mode_muxsel = <0x033A0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", "rx_npl_clk", + "wsa_core_clk", "wsa_npl_clk", "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_wsa_1 0>, <&clock_audio_wsa_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; + + tx_macro: tx-macro@3220000 { + compatible = "qcom,tx-macro"; + reg = <0x3220000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-swr-gpios = <&tx_swr_gpios>; + qcom,tx-dmic-sample-rate = <2400000>; + swr2: tx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <3>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3230000 0x0>; + interrupts-extended = + <&intc GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 109 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-wakeup-required = <1>; + qcom,swr-num-ports = <5>; + qcom,swr-port-mapping = <1 PCM_OUT1 0xF>, + <2 ADC1 0x1>, <2 ADC2 0x2>, + <3 ADC3 0x1>, <3 ADC4 0x2>, + <4 DMIC0 0x1>, <4 DMIC1 0x2>, + <4 DMIC2 0x4>, <4 DMIC3 0x8>, + <5 DMIC4 0x1>, <5 DMIC5 0x2>, + <5 DMIC6 0x4>, <5 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + qcom,swr-mstr-irq-wakeup-capable = <1>; + wcd938x_tx_slave: wcd938x-tx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170223>; + }; + }; + }; + + rx_macro: rx-macro@3200000 { + compatible = "qcom,rx-macro"; + reg = <0x3200000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x033240D8>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr1: rx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <2>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x3210000 0x0>; + interrupts = ; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,disable-div2-clk-switch = <1>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x1>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + wcd938x_rx_slave: wcd938x-rx-slave { + compatible = "qcom,wcd938x-slave"; + reg = <0x0D 0x01170224>; + }; + }; + }; + + va_macro: va-macro@3370000 { + compatible = "qcom,va-macro"; + reg = <0x3370000 0x0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,va-dmic-sample-rate = <600000>; + qcom,va-clk-mux-select = <1>; + qcom,va-island-mode-muxsel = <0x033A0000>; + qcom,default-clk-id = ; + }; + + wcd938x_codec: wcd938x-codec { + compatible = "qcom,wcd938x-codec"; + qcom,split-codec = <1>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, <1 CLSH 0x1 0 CLSH>, + <2 COMP_L 0x1 0 COMP_L>, <2 COMP_R 0x2 0 COMP_R>, + <3 LO 0x1 0 LO>, <4 DSD_L 0x1 0 DSD_L>, + <4 DSD_R 0x2 0 DSD_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <0 ADC2 0x2 0 ADC2>, <1 ADC3 0x1 0 ADC3>, + <1 ADC4 0x2 0 ADC4>, <2 DMIC0 0x1 0 DMIC0>, + <2 DMIC1 0x2 0 DMIC1>, <2 MBHC 0x4 0 DMIC2>, + <2 DMIC2 0x4 0 DMIC2>, <2 DMIC3 0x8 0 DMIC3>, + <3 DMIC4 0x1 0 DMIC4>, <3 DMIC5 0x2 0 DMIC5>, + <3 DMIC6 0x4 0 DMIC6>, <3 DMIC7 0x8 0 DMIC7>; + + qcom,wcd-rst-gpio-node = <&wcd938x_rst_gpio>; + qcom,rx-slave = <&wcd938x_rx_slave>; + qcom,tx-slave = <&wcd938x_tx_slave>; + + cdc-vdd-rxtx-supply = <&S4A>; + qcom,cdc-vdd-rxtx-voltage = <1800000 1800000>; + qcom,cdc-vdd-rxtx-current = <30000>; + + cdc-vddio-supply = <&S4A>; + qcom,cdc-vddio-voltage = <1800000 1800000>; + qcom,cdc-vddio-current = <30000>; + + cdc-vdd-buck-supply = <&S4A>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-vdd-mic-bias-supply = <&BOB>; + qcom,cdc-vdd-mic-bias-voltage = <3296000 3296000>; + qcom,cdc-vdd-mic-bias-current = <30000>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <2700>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-rxtx", + "cdc-vddio", + "cdc-vdd-buck", + "cdc-vdd-mic-bias"; + }; + +}; + +&lito_snd { + qcom,model = "lito-mtp-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <1>; + qcom,mi2s-audio-intf = <1>; + qcom,afe-rxtx-lb = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "TX DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "TX DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "TX DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "TX DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS1", "Digital Mic0", + "VA MIC BIAS1", "Digital Mic1", + "VA MIC BIAS3", "Digital Mic2", + "VA MIC BIAS3", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS1", + "VA DMIC1", "VA MIC BIAS1", + "VA DMIC2", "VA MIC BIAS3", + "VA DMIC3", "VA MIC BIAS3", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + qcom,cdc-dmic45-gpios = <&cdc_dmic45_gpios>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + asoc-codec = <&stub_codec>, <&bolero>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <0>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&wcd938x_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, + <&lpi_tlmm>, <&bolero>; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-use-usbc-detect = <1>; + qcom,msm-mbhc-hs-mic-max-threshold-mv = <2550>; + fsa4480-i2c-handle = <&fsa4480>; +}; + +&tlmm { + aw_reset_active: aw_reset_active { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + aw_reset_suspend: aw_reset_suspend { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + +}; + +&qupv3_se9_i2c { + status = "okay"; +/* + aw882xx_smartpa@34 { + compatible = "awinic,aw882xx_smartpa"; + reg = <0x34>; + reset-gpio = <&tlmm 125 0>; + monitor-flag = <1>; + monitor-timer-val = <3000>; + pinctrl-names = "aw_pinctrl_active","aw_pinctrl_suspend"; + pinctrl-0 = <&aw_reset_active>; + pinctrl-1 = <&aw_reset_suspend>; + status = "okay"; + }; +*/ + tfa98xx@34 { + compatible = "nxp,tfa98xx"; + reg = <0x34>; + reset-gpio = <&tlmm 125 0>; + tfa9874_vdd-supply = <&pm8150_s4>; + tfa98xx_fw_name = "tfa98xx.cnt"; + tfa_min_range = <5000>; + tfa_max_range = <8000>; + //aw882xx smart PA config + monitor-flag = <1>; + monitor-timer-val = <3000>; + cali-ra-val = <500>; + pinctrl-names = "aw_pinctrl_active","aw_pinctrl_suspend"; + pinctrl-0 = <&aw_reset_active>; + pinctrl-1 = <&aw_reset_suspend>; + status = "okay"; + }; + +}; + +&dai_mi2s0 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; +}; + +&q6core { + cdc_dmic01_gpios: cdc_dmic01_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic01_clk_active &cdc_dmic01_data_active>; + pinctrl-1 = <&cdc_dmic01_clk_sleep &cdc_dmic01_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <121 122>; + }; + + cdc_dmic23_gpios: cdc_dmic23_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic23_clk_active &cdc_dmic23_data_active>; + pinctrl-1 = <&cdc_dmic23_clk_sleep &cdc_dmic23_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <124>; + }; + + cdc_dmic45_gpios: cdc_dmic45_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic45_clk_active &cdc_dmic45_data_active>; + pinctrl-1 = <&cdc_dmic45_clk_sleep &cdc_dmic45_data_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <127 128>; + }; + + rx_swr_gpios: rx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&rx_swr_clk_active &rx_swr_data_active + &rx_swr_data1_active>; + pinctrl-1 = <&rx_swr_clk_sleep &rx_swr_data_sleep + &rx_swr_data1_sleep>; + qcom,lpi-gpios; + }; + + tx_swr_gpios: tx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tx_swr_clk_active &tx_swr_data1_active + &tx_swr_data2_active &tx_swr_data3_active>; + pinctrl-1 = <&tx_swr_clk_sleep &tx_swr_data1_sleep + &tx_swr_data2_sleep &tx_swr_data3_sleep>; + qcom,lpi-gpios; + qcom,tlmm-gpio = <115 116 117>; + }; +}; + +&soc { + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_i2s_sck_active &pri_i2s_ws_active + &pri_i2s_data0_active &pri_i2s_data1_active>; + pinctrl-1 = <&pri_i2s_sck_sleep &pri_i2s_ws_sleep + &pri_i2s_data0_sleep &pri_i2s_data1_sleep>; + }; + + wcd938x_rst_gpio: msm_cdc_pinctrl@57 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd938x_reset_active>; + pinctrl-1 = <&wcd938x_reset_sleep>; + }; + + clock_audio_wsa_1: wsa_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x309>; + #clock-cells = <1>; + }; + + clock_audio_wsa_2: wsa_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30A>; + #clock-cells = <1>; + }; + + clock_audio_rx_1: rx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30E>; + #clock-cells = <1>; + }; + + clock_audio_rx_2: rx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30F>; + #clock-cells = <1>; + }; + + clock_audio_tx_1: tx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30C>; + #clock-cells = <1>; + }; + + clock_audio_tx_2: tx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30D>; + #clock-cells = <1>; + }; + + clock_audio_va_1: va_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30B>; + #clock-cells = <1>; + }; + + clock_audio_va_2: va_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x310>; + #clock-cells = <1>; + }; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <1>; +}; + +&adsp_loader { + nvmem-cells = <&adsp_variant>; + nvmem-cell-names = "adsp_variant"; + adsp-fw-names = "adsp2"; + adsp-fw-bit-values = <0x2>; +}; + +&qupv3_se9_i2c { + status = "okay"; + + fsa4480: fsa4480@42 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x42>; + }; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ebe3aa99bc535bd6bf12bffeac08108703cc2a52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-audio.dtsi @@ -0,0 +1,176 @@ +#include +#include "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x1401 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&soc { + qcom,avtimer@39f0000 { + compatible = "qcom,avtimer"; + reg = <0x039f000c 0x4>, + <0x039f0010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <192>; + qcom,clk-mult = <10>; + }; +}; + +&audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + + lpass_core_hw_vote: vote_lpass_core_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + lpass_audio_hw_vote: vote_lpass_audio_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + bolero: bolero-cdc { + compatible = "qcom,bolero-codec"; + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + }; + + tx_macro: tx-macro@3220000 { + swr2: tx_swr_master { + }; + }; + + rx_macro: rx-macro@3200000 { + swr1: rx_swr_master { + }; + }; + + wsa_macro: wsa-macro@3240000 { + swr0: wsa_swr_master { + }; + }; + }; + }; +}; + +&q6core { + lito_snd: sound { + compatible = "qcom,kona-asoc-snd"; + qcom,mi2s-audio-intf = <0>; + qcom,auxpcm-audio-intf = <0>; + qcom,tdm-audio-intf = <0>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <0>; + qcom,afe-rxtx-lb = <0>; + + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, <&dai_dp1>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_mi2s5>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&dai_sen_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&proxy_rx>, <&proxy_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>, + <&dai_sen_tdm_rx_0>, <&dai_sen_tdm_tx_0>, + <&wsa_cdc_dma_0_rx>, <&wsa_cdc_dma_0_tx>, + <&wsa_cdc_dma_1_rx>, <&wsa_cdc_dma_1_tx>, + <&wsa_cdc_dma_2_tx>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&va_cdc_dma_2_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&rx_cdc_dma_6_rx>, <&rx_cdc_dma_7_rx>, + <&afe_loopback_tx>; + asoc-cpu-names = "msm-dai-q6-dp.0", "msm-dai-q6-dp.1", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.5", + "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-auxpcm.6", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16401", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36944", "msm-dai-q6-tdm.36945", + "msm-dai-cdc-dma-dev.45056", + "msm-dai-cdc-dma-dev.45057", + "msm-dai-cdc-dma-dev.45058", + "msm-dai-cdc-dma-dev.45059", + "msm-dai-cdc-dma-dev.45061", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45093", + "msm-dai-cdc-dma-dev.45104", + "msm-dai-cdc-dma-dev.45105", + "msm-dai-cdc-dma-dev.45106", + "msm-dai-cdc-dma-dev.45107", + "msm-dai-cdc-dma-dev.45108", + "msm-dai-cdc-dma-dev.45109", + "msm-dai-cdc-dma-dev.45110", + "msm-dai-cdc-dma-dev.45111", + "msm-dai-cdc-dma-dev.45112", + "msm-dai-cdc-dma-dev.45113", + "msm-dai-cdc-dma-dev.45114", + "msm-dai-cdc-dma-dev.45115", + "msm-dai-cdc-dma-dev.45116", + "msm-dai-cdc-dma-dev.45118", + "msm-dai-q6-dev.24577"; + //fsa4480-i2c-handle = <&fsa4480>; + }; +}; + +&qupv3_se9_i2c { + status = "ok"; + fsa4480: fsa4480@43 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x43>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-bus.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b361373b10dba4f1c0e50abd8dbb4500cdc13c21 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-bus.dtsi @@ -0,0 +1,1968 @@ +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x016E0000 0x15080>, + <0x1700000 0x23080>, + <0x1500000 0x28000>, + <0x9160000 0x3200>, + <0x9680000 0x3e200>, + <0x9680000 0x3e200>, + <0x1740000 0x1c100>, + <0x1620000 0x19200>, + <0x1620000 0x19200>, + <0x1700000 0x3d180>, + <0x9990000 0x1600>, + <0x1620000 0x19200>, + <0x1620000 0x19200>; + + reg-names = "aggre1_noc-base", "aggre2_noc-base", + "config_noc-base", "dc_noc-base", + "mc_virt-base", "gem_noc-base", + "mmss_noc-base", "system_noc-base", + "ipa_virt-base", "compute_noc-base", + "npu_noc-base", "camnoc_virt-base", + "qup_virt-base"; + + /*RSCs*/ + rsc_apps: rsc-apps { + cell-id = ; + label = "apps_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + rsc_disp: rsc-disp { + cell-id = ; + label = "disp_rsc"; + qcom,rsc-dev; + qcom,req_state = <2>; + }; + + /*BCMs*/ + bcm_mc0: bcm-mc0 { + cell-id = ; + label = "MC0"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh0: bcm-sh0 { + cell-id = ; + label = "SH0"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_acv: bcm-acv { + cell-id = ; + label = "ACV"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_alc: bcm-alc { + cell-id = ; + label = "ALC"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm0: bcm-mm0 { + cell-id = ; + label = "MM0"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co0: bcm-co0 { + cell-id = ; + label = "CO0"; + qcom,bcm-name = "CO0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ce0: bcm-ce0 { + cell-id = ; + label = "CE0"; + qcom,bcm-name = "CE0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn0: bcm-cn0 { + cell-id = ; + label = "CN0"; + qcom,bcm-name = "CN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm1: bcm-mm1 { + cell-id = ; + label = "MM1"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn1: bcm-cn1 { + cell-id = ; + label = "CN1"; + qcom,bcm-name = "CN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh2: bcm-sh2 { + cell-id = ; + label = "SH2"; + qcom,bcm-name = "SH2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm2: bcm-mm2 { + cell-id = ; + label = "MM2"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co2: bcm-co2 { + cell-id = ; + label = "CO2"; + qcom,bcm-name = "CO2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh3: bcm-sh3 { + cell-id = ; + label = "SH3"; + qcom,bcm-name = "SH3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_mm3: bcm-mm3 { + cell-id = ; + label = "MM3"; + qcom,bcm-name = "MM3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_co3: bcm-co3 { + cell-id = ; + label = "CO3"; + qcom,bcm-name = "CO3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_qup0: bcm-qup0 { + cell-id = ; + label = "QUP0"; + qcom,bcm-name = "QUP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sh4: bcm-sh4 { + cell-id = ; + label = "SH4"; + qcom,bcm-name = "SH4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn0: bcm-sn0 { + cell-id = ; + label = "SN0"; + qcom,bcm-name = "SN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn2: bcm-sn2 { + cell-id = ; + label = "SN2"; + qcom,bcm-name = "SN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn4: bcm-sn4 { + cell-id = ; + label = "SN4"; + qcom,bcm-name = "SN4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn5: bcm-sn5 { + cell-id = ; + label = "SN5"; + qcom,bcm-name = "SN5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn6: bcm-sn6 { + cell-id = ; + label = "SN6"; + qcom,bcm-name = "SN6"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn10: bcm-sn10 { + cell-id = ; + label = "SN10"; + qcom,bcm-name = "SN10"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_acv_display: bcm-acv_display { + cell-id = ; + label = "ACV_DISPLAY"; + qcom,bcm-name = "ACV"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_alc_display: bcm-alc_display { + cell-id = ; + label = "ALC_DISPLAY"; + qcom,bcm-name = "ALC"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mc0_display: bcm-mc0_display { + cell-id = ; + label = "MC0_DISPLAY"; + qcom,bcm-name = "MC0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_sh0_display: bcm-sh0_display { + cell-id = ; + label = "SH0_DISPLAY"; + qcom,bcm-name = "SH0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm0_display: bcm-mm0_display { + cell-id = ; + label = "MM0_DISPLAY"; + qcom,bcm-name = "MM0"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm1_display: bcm-mm1_display { + cell-id = ; + label = "MM1_DISPLAY"; + qcom,bcm-name = "MM1"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + bcm_mm2_display: bcm-mm2_display { + cell-id = ; + label = "MM2_DISPLAY"; + qcom,bcm-name = "MM2"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + /*Buses*/ + fab_aggre1_noc: fab-aggre1_noc { + cell-id = ; + label = "fab-aggre1_noc"; + qcom,fab-dev; + qcom,base-name = "aggre1_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <12288>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_aggre2_noc: fab-aggre2_noc { + cell-id = ; + label = "fab-aggre2_noc"; + qcom,fab-dev; + qcom,base-name = "aggre2_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <20480>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_compute_noc: fab-compute_noc { + cell-id = ; + label = "fab-compute_noc"; + qcom,fab-dev; + qcom,base-name = "compute_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_dc_noc: fab-dc_noc { + cell-id = ; + label = "fab-dc_noc"; + qcom,fab-dev; + qcom,base-name = "dc_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc: fab-gem_noc { + cell-id = ; + label = "fab-gem_noc"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <184320>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_ipa_virt: fab-ipa_virt { + cell-id = ; + label = "fab-ipa_virt"; + qcom,fab-dev; + qcom,base-name = "ipa_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mc_virt: fab-mc_virt { + cell-id = ; + label = "fab-mc_virt"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mmss_noc: fab-mmss_noc { + cell-id = ; + label = "fab-mmss_noc"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_npu_noc: fab-npu_noc { + cell-id = ; + label = "fab-npu_noc"; + qcom,fab-dev; + qcom,base-name = "npu_noc-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_qup_virt: fab-qup_virt { + cell-id = ; + label = "fab-qup_virt"; + qcom,fab-dev; + qcom,base-name = "qup_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_system_noc: fab-system_noc { + cell-id = ; + label = "fab-system_noc"; + qcom,fab-dev; + qcom,base-name = "system_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <49152>; + qcom,sbm-offset = <0>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gem_noc_display: fab-gem_noc_display { + cell-id = ; + label = "fab-gem_noc_display"; + qcom,fab-dev; + qcom,base-name = "gem_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <184320>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mc_virt_display: fab-mc_virt_display { + cell-id = ; + label = "fab-mc_virt_display"; + qcom,fab-dev; + qcom,base-name = "mc_virt-base"; + qcom,qos-off = <0>; + qcom,base-offset = <0>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + clocks = <>; + }; + + fab_mmss_noc_display: fab-mmss_noc_display { + cell-id = ; + label = "fab-mmss_noc_display"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <128>; + qcom,base-offset = <36864>; + qcom,sbm-offset = <0>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + /*Masters*/ + + mas_qhm_a1noc_cfg: mas-qhm-a1noc-cfg { + cell-id = ; + label = "mas-qhm-a1noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre1_noc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_qhm_qup_1: mas-qhm-qup-1 { + cell-id = ; + label = "mas-qhm-qup-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_sdc4: mas-xm-sdc4 { + cell-id = ; + label = "mas-xm-sdc4"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_emmc: mas-xm-emmc { + cell-id = ; + label = "mas-xm-emmc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_cn1>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>; + clock-names = + "clk-aggre-ufs-phy-axi-no-rate"; + }; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,node-qos-clks { + clocks = + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + clock-names = + "clk-usb3-prim-axi-no-rate"; + }; + }; + + mas_qhm_a2noc_cfg: mas-qhm-a2noc-cfg { + cell-id = ; + label = "mas-qhm-a2noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_aggre2_noc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qhm_qup_0: mas-qhm-qup-0 { + cell-id = ; + label = "mas-qhm-qup-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_ce0>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,forwarding; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <9>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qnm_npu: mas-qnm-npu { + cell-id = ; + label = "mas-qnm-npu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <6 8>; + qcom,connections = <&slv_qns_cdsp_gem_noc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co2>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_npu_dsp: mas-qxm-npu-dsp { + cell-id = ; + label = "mas-qxm-npu-dsp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_cdsp_gem_noc>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,bcms = <&bcm_co3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc: mas-qnm-snoc { + cell-id = ; + label = "mas-qnm-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_compute_dsp + &slv_qhs_tlmm_2 &slv_qhs_camera_cfg + &slv_qhs_tlmm_0 &slv_qhs_sdc4 + &slv_qhs_sdc2 &slv_qhs_mnoc_cfg + &slv_qhs_ufs_mem_cfg &slv_qhs_snoc_cfg + &slv_qhs_pdm &slv_qhs_cx_rdpm + &slv_qhs_tlmm_1 &slv_qhs_a2_noc_cfg + &slv_qhs_qdss_cfg &slv_qhs_display_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qhs_ipc_router + &slv_qhs_ahb2phy2 &slv_qhs_npu_cfg + &slv_qhs_ahb2phy0 &slv_qhs_gpuss_cfg + &slv_qhs_venus_cfg &slv_qhs_ipa + &slv_qhs_imem_cfg &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_lpass_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_vsense_ctrl_cfg &slv_qhs_crypto0_cfg + &slv_qhs_pimem_cfg &slv_qhs_cpr_mx + &slv_qhs_qup0 &slv_qhs_qup1 + &slv_qhs_clk_ctl &slv_qhs_emmc_cfg>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_xm_qdss_dap: mas-xm-qdss-dap { + cell-id = ; + label = "mas-xm-qdss-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_compute_dsp + &slv_qhs_tlmm_2 &slv_qhs_camera_cfg + &slv_qhs_tlmm_0 &slv_qhs_sdc4 + &slv_qhs_sdc2 &slv_qhs_mnoc_cfg + &slv_qhs_ufs_mem_cfg &slv_qhs_snoc_cfg + &slv_qhs_pdm &slv_qhs_cx_rdpm + &slv_qhs_tlmm_1 &slv_qhs_a2_noc_cfg + &slv_qhs_qdss_cfg &slv_qhs_display_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qhs_ipc_router + &slv_qhs_ahb2phy2 &slv_qhs_npu_cfg + &slv_qhs_ahb2phy0 &slv_qhs_gpuss_cfg + &slv_qhs_venus_cfg &slv_qhs_ipa + &slv_qhs_imem_cfg &slv_srvc_cnoc + &slv_qhs_usb3_0 &slv_qhs_lpass_cfg + &slv_qhs_cpr_cx &slv_qhs_a1_noc_cfg + &slv_qhs_aoss &slv_qhs_prng + &slv_qhs_vsense_ctrl_cfg &slv_qhs_crypto0_cfg + &slv_qhs_pimem_cfg &slv_qhs_cpr_mx + &slv_qhs_qup0 &slv_qhs_qup1 + &slv_qhs_clk_ctl &slv_qhs_emmc_cfg>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qhm_cnoc_dc_noc: mas-qhm-cnoc-dc-noc { + cell-id = ; + label = "mas-qhm-cnoc-dc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_llcc &slv_qhs_gemnoc>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + mas_acm_apps0: mas-acm-apps0 { + cell-id = ; + label = "mas-acm-apps0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh4>; + }; + + mas_acm_sys_tcu: mas-acm-sys-tcu { + cell-id = ; + label = "mas-acm-sys-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <224>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh2>; + qcom,ap-owned; + qcom,prio = <6>; + }; + + mas_alm_gpu_tcu: mas-alm-gpu-tcu { + cell-id = ; + label = "mas-alm-gpu-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh2>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + mas_qhm_gemnoc_cfg: mas-qhm-gemnoc-cfg { + cell-id = ; + label = "mas-qhm-gemnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_mcdma_ms_mpu_cfg + &slv_srvc_gemnoc &slv_qhs_mdsp_ms_mpu_cfg>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + mas_qnm_cmpnoc: mas-qnm-cmpnoc { + cell-id = ; + label = "mas-qnm-cmpnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + }; + + mas_qnm_gpu: mas-qnm-gpu { + cell-id = ; + label = "mas-qnm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <256 257>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { + cell-id = ; + label = "mas-qnm-mnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <128 129>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { + cell-id = ; + label = "mas-qnm-mnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <288>; + qcom,connections = <&slv_qns_llcc + &slv_qns_gem_noc_snoc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <192>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qnm_snoc_sf: mas-qnm-snoc-sf { + cell-id = ; + label = "mas-qnm-snoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,qport = <160>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_ipa_core_master: mas-ipa-core-master { + cell-id = ; + label = "mas-ipa-core-master"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_ipa_core_slave>; + qcom,bus-dev = <&fab_ipa_virt>; + }; + + mas_llcc_mc: mas-llcc-mc { + cell-id = ; + label = "mas-llcc-mc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_mc_virt>; + }; + + mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { + cell-id = ; + label = "mas-qhm-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + mas_qxm_camnoc_icp: mas-qxm-camnoc-icp { + cell-id = ; + label = "mas-qxm-camnoc-icp"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <258>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <5>; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_hf0: mas-qxm-camnoc-hf0 { + cell-id = ; + label = "mas-qxm-camnoc-hf0"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <32 64>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 { + cell-id = ; + label = "mas-qxm-camnoc-hf1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <257>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { + cell-id = ; + label = "mas-qxm-camnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <96>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_mdp1: mas-qxm-mdp1 { + cell-id = ; + label = "mas-qxm-mdp1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <128>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_rot: mas-qxm-rot { + cell-id = ; + label = "mas-qxm-rot"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <160>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus0: mas-qxm-venus0 { + cell-id = ; + label = "mas-qxm-venus0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <192>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus1: mas-qxm-venus1 { + cell-id = ; + label = "mas-qxm-venus1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <224>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus_arm9: mas-qxm-venus-arm9 { + cell-id = ; + label = "mas-qxm-venus-arm9"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <256>; + qcom,connections = <&slv_qns_mem_noc_sf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <5>; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_amm_npu_sys: mas-amm-npu-sys { + cell-id = ; + label = "mas-amm-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_qns_npu_sys>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qhm_cfg: mas-qhm-cfg { + cell-id = ; + label = "mas-qhm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_noc &slv_qhs_isense + &slv_qhs_llm &slv_qhs_dma_bwmon &slv_qhs_cp + &slv_qhs_tcm &slv_qhs_cal_dp0 &slv_qhs_dpm>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + mas_qup_core_master_1: mas-qup-core-master-1 { + cell-id = ; + label = "mas-qup-core-master-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup_core_slave_1>; + qcom,bus-dev = <&fab_qup_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qup_core_master_2: mas-qup-core-master-2 { + cell-id = ; + label = "mas-qup-core-master-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup_core_slave_2>; + qcom,bus-dev = <&fab_qup_virt>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qhm_snoc_cfg: mas-qhm-snoc-cfg { + cell-id = ; + label = "mas-qhm-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_system_noc>; + }; + + mas_qnm_aggre1_noc: mas-qnm-aggre1-noc { + cell-id = ; + label = "mas-qnm-aggre1-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf &slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss + &slv_qns_cnoc &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn5>; + }; + + mas_qnm_aggre2_noc: mas-qnm-aggre2-noc { + cell-id = ; + label = "mas-qnm-aggre2-noc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_gemnoc_sf &slv_qxs_pimem + &slv_qxs_imem &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn6>; + }; + + mas_qnm_gemnoc: mas-qnm-gemnoc { + cell-id = ; + label = "mas-qnm-gemnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn10>; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_gemnoc_gc &slv_qxs_imem>; + qcom,bus-dev = <&fab_system_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qnm_mnoc_hf_display: mas-qnm-mnoc-hf_display { + cell-id = ; + label = "mas-qnm-mnoc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <128 129>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display { + cell-id = ; + label = "mas-qnm-mnoc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <288>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_gem_noc_display>; + }; + + mas_llcc_mc_display: mas-llcc-mc_display { + cell-id = ; + label = "mas-llcc-mc_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_ebi_display>; + qcom,bus-dev = <&fab_mc_virt_display>; + }; + + mas_qxm_mdp0_display: mas-qxm-mdp0_display { + cell-id = ; + label = "mas-qxm-mdp0_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <96>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_mdp1_display: mas-qxm-mdp1_display { + cell-id = ; + label = "mas-qxm-mdp1_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <128>; + qcom,connections = <&slv_qns_mem_noc_hf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm1_display>; + }; + + mas_qxm_rot_display: mas-qxm-rot_display { + cell-id = ; + label = "mas-qxm-rot_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <160>; + qcom,connections = <&slv_qns_mem_noc_sf_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + }; + + /*Slaves*/ + + slv_qns_a1noc_snoc:slv-qns-a1noc-snoc { + cell-id = ; + label = "slv-qns-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_aggre1_noc>; + }; + + slv_srvc_aggre1_noc:slv-srvc-aggre1-noc { + cell-id = ; + label = "slv-srvc-aggre1-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + slv_qns_a2noc_snoc:slv-qns-a2noc-snoc { + cell-id = ; + label = "slv-qns-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_aggre2_noc>; + }; + + slv_srvc_aggre2_noc:slv-srvc-aggre2-noc { + cell-id = ; + label = "slv-srvc-aggre2-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + slv_qns_cdsp_gem_noc:slv-qns-cdsp-gem-noc { + cell-id = ; + label = "slv-qns-cdsp-gem-noc"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_compute_noc>; + qcom,connections = <&mas_qnm_cmpnoc>; + qcom,bcms = <&bcm_co0>; + }; + + slv_qhs_a1_noc_cfg:slv-qhs-a1-noc-cfg { + cell-id = ; + label = "slv-qhs-a1-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a1noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_a2_noc_cfg:slv-qhs-a2-noc-cfg { + cell-id = ; + label = "slv-qhs-a2-noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_a2noc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy0:slv-qhs-ahb2phy0 { + cell-id = ; + label = "slv-qhs-ahb2phy0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ahb2phy2:slv-qhs-ahb2phy2 { + cell-id = ; + label = "slv-qhs-ahb2phy2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_aoss:slv-qhs-aoss { + cell-id = ; + label = "slv-qhs-aoss"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_camera_cfg:slv-qhs-camera-cfg { + cell-id = ; + label = "slv-qhs-camera-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_compute_dsp:slv-qhs-compute-dsp { + cell-id = ; + label = "slv-qhs-compute-dsp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_cx:slv-qhs-cpr-cx { + cell-id = ; + label = "slv-qhs-cpr-cx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cpr_mx:slv-qhs-cpr-mx { + cell-id = ; + label = "slv-qhs-cpr-mx"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_cx_rdpm:slv-qhs-cx-rdpm { + cell-id = ; + label = "slv-qhs-cx-rdpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_dcc_cfg:slv-qhs-dcc-cfg { + cell-id = ; + label = "slv-qhs-dcc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ddrss_cfg:slv-qhs-ddrss-cfg { + cell-id = ; + label = "slv-qhs-ddrss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cnoc_dc_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_cfg:slv-qhs-display-cfg { + cell-id = ; + label = "slv-qhs-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg { + cell-id = ; + label = "slv-qhs-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipc_router:slv-qhs-ipc-router { + cell-id = ; + label = "slv-qhs-ipc-router"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_lpass_cfg:slv-qhs-lpass-cfg { + cell-id = ; + label = "slv-qhs-lpass-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg { + cell-id = ; + label = "slv-qhs-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_mnoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_npu_cfg:slv-qhs-npu-cfg { + cell-id = ; + label = "slv-qhs-npu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup0:slv-qhs-qup0 { + cell-id = ; + label = "slv-qhs-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qup1:slv-qhs-qup1 { + cell-id = ; + label = "slv-qhs-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_sdc4:slv-qhs-sdc4 { + cell-id = ; + label = "slv-qhs-sdc4"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_snoc_cfg:slv-qhs-snoc-cfg { + cell-id = ; + label = "slv-qhs-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_snoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_0:slv-qhs-tlmm-0 { + cell-id = ; + label = "slv-qhs-tlmm-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_1:slv-qhs-tlmm-1 { + cell-id = ; + label = "slv-qhs-tlmm-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_2:slv-qhs-tlmm-2 { + cell-id = ; + label = "slv-qhs-tlmm-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ufs_mem_cfg:slv-qhs-ufs-mem-cfg { + cell-id = ; + label = "slv-qhs-ufs-mem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_emmc_cfg:slv-qhs-emmc-cfg { + cell-id = ; + label = "slv-qhs-emmc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn1>; + }; + + slv_qhs_usb3_0:slv-qhs-usb3-0 { + cell-id = ; + label = "slv-qhs-usb3-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gemnoc:slv-qhs-gemnoc { + cell-id = ; + label = "slv-qhs-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + qcom,connections = <&mas_qhm_gemnoc_cfg>; + }; + + slv_qhs_llcc:slv-qhs-llcc { + cell-id = ; + label = "slv-qhs-llcc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + slv_qhs_mcdma_ms_mpu_cfg:slv-qhs-mcdma-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mcdma-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mdsp-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_qns_gem_noc_snoc:slv-qns-gem-noc-snoc { + cell-id = ; + label = "slv-qns-gem-noc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_qnm_gemnoc>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_gem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_srvc_gemnoc:slv-srvc-gemnoc { + cell-id = ; + label = "slv-srvc-gemnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gem_noc>; + }; + + slv_ipa_core_slave:slv-ipa-core-slave { + cell-id = ; + label = "slv-ipa-core-slave"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_ipa_virt>; + qcom,bcms = <&bcm_ip0>; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mc_virt>; + qcom,bcms = <&bcm_mc0>, <&bcm_acv>; + }; + + slv_qns_mem_noc_hf:slv-qns-mem-noc-hf { + cell-id = ; + label = "slv-qns-mem-noc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_hf>; + qcom,bcms = <&bcm_mm0>; + }; + + slv_qns_mem_noc_sf:slv-qns-mem-noc-sf { + cell-id = ; + label = "slv-qns-mem-noc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_sf>; + qcom,bcms = <&bcm_mm2>; + }; + + slv_srvc_mnoc:slv-srvc-mnoc { + cell-id = ; + label = "slv-srvc-mnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + slv_qhs_cal_dp0:slv-qhs-cal-dp0 { + cell-id = ; + label = "slv-qhs-cal-dp0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_cp:slv-qhs-cp { + cell-id = ; + label = "slv-qhs-cp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dma_bwmon:slv-qhs-dma-bwmon { + cell-id = ; + label = "slv-qhs-dma-bwmon"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_dpm:slv-qhs-dpm { + cell-id = ; + label = "slv-qhs-dpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_isense:slv-qhs-isense { + cell-id = ; + label = "slv-qhs-isense"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_llm:slv-qhs-llm { + cell-id = ; + label = "slv-qhs-llm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qhs_tcm:slv-qhs-tcm { + cell-id = ; + label = "slv-qhs-tcm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qns_npu_sys:slv-qns-npu-sys { + cell-id = ; + label = "slv-qns-npu-sys"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_srvc_noc:slv-srvc-noc { + cell-id = ; + label = "slv-srvc-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_npu_noc>; + }; + + slv_qup_core_slave_1:slv-qup-core-slave-1 { + cell-id = ; + label = "slv-qup-core-slave-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_qup_virt>; + }; + + slv_qup_core_slave_2:slv-qup-core-slave-2 { + cell-id = ; + label = "slv-qup-core-slave-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_qup_virt>; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_cnoc:slv-qns-cnoc { + cell-id = ; + label = "slv-qns-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc>; + }; + + slv_qns_gemnoc_gc:slv-qns-gemnoc-gc { + cell-id = ; + label = "slv-qns-gemnoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_gc>; + qcom,bcms = <&bcm_sn2>; + }; + + slv_qns_gemnoc_sf:slv-qns-gemnoc-sf { + cell-id = ; + label = "slv-qns-gemnoc-sf"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,connections = <&mas_qnm_snoc_sf>; + qcom,bcms = <&bcm_sn0>; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn1>; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + }; + + slv_qns_llcc_display:slv-qns-llcc_display { + cell-id = ; + label = "slv-qns-llcc_display"; + qcom,buswidth = <16>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_gem_noc_display>; + qcom,connections = <&mas_llcc_mc_display>; + qcom,bcms = <&bcm_sh0_display>; + }; + + slv_ebi_display:slv-ebi_display { + cell-id = ; + label = "slv-ebi_display"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mc_virt_display>; + qcom,bcms = <&bcm_mc0_display>, <&bcm_acv_display>; + }; + + slv_qns_mem_noc_hf_display:slv-qns-mem-noc-hf_display { + cell-id = ; + label = "slv-qns-mem-noc-hf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_hf_display>; + qcom,bcms = <&bcm_mm0_display>; + }; + + slv_qns_mem_noc_sf_display:slv-qns-mem-noc-sf_display { + cell-id = ; + label = "slv-qns-mem-noc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_sf_display>; + qcom,bcms = <&bcm_mm2_display>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-cdp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..eefff2d258c03ce64b4e1bb795f03ebaab7e69f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-cdp-overlay.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito CDP"; + compatible = "qcom,lito-cdp", "qcom,lito", "qcom,cdp"; + qcom,msm-id = <400 0x10000>, <440 0x10000>; + qcom,board-id = <1 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/lito-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..22526f0c5c46785417d73ff598a4e6e74e377dab --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-cdp.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "lito.dtsi" +#include "lito-cdp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito CDP"; + compatible = "qcom,lito-cdp", "qcom,lito", "qcom,cdp"; + qcom,board-id = <1 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c29c9085f71d0a3ed8f95d8997ec5328616b9cd3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-cdp.dtsi @@ -0,0 +1,589 @@ +#include +#include "lito-audio-overlay.dtsi" +#include "lito-pmic-overlay.dtsi" +#include "camera/lito-camera-sensor-cdp.dtsi" +#include "lito-sde-display.dtsi" +#include "lito-thermal-overlay.dtsi" + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150l_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + vdda_usb_ss_dp_core: vdda_usb_ss_dp_core { + compatible = "regulator-fixed"; + regulator-name = "vdd_supply"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + enable-active-high; + gpio = <&pm8150l_gpios 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_eldo13>; + }; +}; + +&usb_qmp_dp_phy { + vdd-supply = <&vdda_usb_ss_dp_core>; +}; + +&sde_dp { + vdda-0p9-supply = <&vdda_usb_ss_dp_core>; +}; + +&pm7250b_vadc { + pinctrl-0 = < + &bmr_w_therm_default + &camera_therm_default + &bmr_s_therm_default + >; + + bmr_s_therm { + reg = ; + label = "bmr_s_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm7250b_gpios { + bmr_s_therm { + bmr_s_therm_default: bmr_s_therm_default { + pins = "gpio5"; + bias-high-impedance; + }; + }; +}; + +&pm7250b_adc_tm { + io-channels = <&pm7250b_vadc ADC_AMUX_THM1_PU2>, + <&pm7250b_vadc ADC_GPIO2_PU2>, + <&pm7250b_vadc ADC_GPIO3_PU2>, + <&pm7250b_vadc ADC_GPIO4_PU2>; + + bmr_s_therm@54 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + mmw-pa4-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_GPIO3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&qupv3_se0_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 34 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 35 0x00>; + qcom,nq-clkreq = <&tlmm 31 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <34 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&lito_snd { + qcom,model = "lito-cdp-snd-card"; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "DMIC4", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC6", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "DMIC7", "MIC BIAS3", + "MIC BIAS3", "Digital Mic6", + "DMIC8", "MIC BIAS3", + "MIC BIAS3", "Digital Mic7", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC0", "ADC1_OUTPUT", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_ADC2", "ADC3_OUTPUT", + "VA SWR_ADC3", "ADC4_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4-lito"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <90200>; + vdda-pll-max-microamp = <19000>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150a_l7>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l9>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm8150a_l7>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm8150_s4>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage"; + qcom,batteryless-platform; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; +}; + +&qupv3_se7_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <9 0x2008>; + vdd-supply = <&pm8150_s4>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 9 0x2008>; + st,reset-gpio = <&tlmm 8 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + panel = <&dsi_sw43404_amoled_cmd &dsi_sw43404_amoled_video + &dsi_sw43404_amoled_fhd_plus_cmd>; + }; + + synaptics_dsx@22 { + compatible = "synaptics,dsx-i2c"; + reg = <0x22>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + vdd-supply = <&pm8150_s4>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + synaptics,pwr-reg-name = "avdd"; + synaptics,bus-reg-name = "vdd"; + synaptics,ub-i2c-addr = <0x22>; + synaptics,max-y-for-2d = <1859>; + synaptics,irq-gpio = <&tlmm 9 0x2008>; + synaptics,reset-gpio = <&tlmm 8 0x0>; + synaptics,irq-on-state = <0>; + synaptics,power-delay-ms = <200>; + synaptics,reset-delay-ms = <200>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + + panel = <&dsi_sharp_qsync_wqhd_cmd &dsi_sharp_qsync_wqhd_video + &dsi_sharp_qsync_fhd_video &dsi_sharp_qsync_fhd_cmd>; + }; + + focaltech@38 { + compatible = "focaltech,fts_ts"; + reg = <0x38>; + interrupt-parent = <&tlmm>; + interrupts = <39 0x2008>; + focaltech,irq-gpio = <&tlmm 9 0x2008>; + focaltech,reset-gpio = <&tlmm 8 0x00>; + focaltech,max-touch-number = <5>; + focaltech,display-coords = <0 0 1080 2340>; + + vdd-supply = <&pm8150_l13>; + + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&pmx_ts_release>; + + panel = <&dsi_r66451_amoled_144hz_cmd>; + }; + +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sharp_wqhd_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_dual_sharp_wqhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_sharp_4k_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-sec-reset-gpio = <&pm8150l_gpios 11 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,panel-sec-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-sec-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-sec-reset-gpio = <&pm8150l_gpios 11 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_sharp_qsync_wqhd_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_sharp_qsync_wqhd_cmd { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_sharp_qsync_fhd_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; +}; + +&dsi_sharp_qsync_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_external"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; + qcom,platform-en-gpio = <&pm8150l_gpios 9 0>; + qcom,platform-bklight-en-gpio = <&pm8150l_gpios 10 0>; + +}; + +&dsi_rm69299_visionox_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_r66451_amoled_144hz_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-brightness-max-level = <255>; + qcom,mdss-dsi-bl-inverted-dbv; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_video>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-coresight.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8edd526707307b88b538ae3ecda4947e69e0982e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-coresight.dtsi @@ -0,0 +1,3363 @@ +&soc { + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator0_out_tmc_etr: endpoint { + remote-endpoint= + <&tmc_etr_in_replicator0>; + }; + }; + + port@1 { + reg = <0>; + replicator_cx_in_swao_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator_swao_out_cx_in>; + }; + }; + }; + }; + + replicator_swao: replicator@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + + reg = <0x6b06000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@0 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&eud_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_cx_in: endpoint { + remote-endpoint = + <&replicator_cx_in_swao_out>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator_swao>; + }; + }; + }; + }; + + dummy_eud: dummy_sink { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-eud"; + + qcom,dummy-sink; + port { + eud_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_eud>; + }; + }; + }; + + tmc_etf_swao: tmc@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + + reg = <0x6b05000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0_swao &cti3_swao>; + coresight-csr = <&swao_csr>; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator_swao: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + }; + + funnel_swao: funnel@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6b04000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <5>; + funnel_swao_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint= + <&audio_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <5>; + funnel_swao_in_lpass_lpi: endpoint { + slave-mode; + remote-endpoint= + <&lpass_lpi_out_funnel_swao>; + }; + }; + + port@3 { + reg = <6>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + + port@4 { + reg = <7>; + funnel_swao_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint= + <&funnel_merg_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x6b08000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + }; + }; + }; + + tpdm_swao0: tpdm@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + + reg = <0x6b09000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6b0a000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + qcom,iommu-dma = "bypass"; + iommus = <&apps_smmu 0x04c0 0>, + <&apps_smmu 0x04a0 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + arm,scatter-gather; + + qcom,sw-usb; + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti3_swao>; + coresight-csr = <&csr>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator0: endpoint { + slave-mode; + remote-endpoint = <&replicator0_out_tmc_etr>; + }; + }; + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + nvmem-cells = <&stm_debug_fuse>; + nvmem-cell-names = "debug_fuse"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@6b0c000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0c000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <3>; + qatb3_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_qatb3>; + }; + }; + + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 64>, + <24 32>, + <25 64>; + qcom,tc-elem-size = <10 64>, + <25 64>; + qcom,dsb-elem-size = <1 32>, + <2 32>, + <4 32>, + <6 32>, + <9 32>, + <10 32>, + <13 32>, + <14 32>, + <15 32>, + <19 32>, + <24 32>, + <25 32>; + qcom,cmb-elem-size = <4 32>, + <6 32>, + <10 32>, + <11 32>, + <12 64>, + <14 64>, + <16 32>, + <20 64>, + <21 32>, + <22 32>, + <23 32>, + <25 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <1>; + tpda_in_funnel_gpu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gpu_out_tpda>; + }; + }; + + port@2 { + reg = <2>; + tpda2_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda2>; + }; + }; + + port@3 { + reg = <4>; + tpda4_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda4>; + }; + }; + + port@4 { + reg = <6>; + tpda6_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda6>; + }; + }; + + port@5 { + reg = <9>; + tpda9_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda9>; + }; + }; + + port@6 { + reg = <10>; + tpda10_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda10>; + }; + }; + + port@7 { + reg = <11>; + tpda11_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda11>; + }; + }; + + port@8 { + reg = <12>; + tpda12_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda12>; + }; + }; + + port@9 { + reg = <13>; + tpda13_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda13>; + }; + }; + + port@10 { + reg = <14>; + tpda14_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda14>; + }; + }; + + port@11 { + reg = <15>; + tpda15_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda15>; + }; + }; + + port@12 { + reg = <16>; + tpda16_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda16>; + }; + }; + + port@13 { + reg = <19>; + tpda19_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda19>; + }; + }; + + port@14 { + reg = <20>; + tpda20_in_funnel_dl_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_center_out_tpda20>; + }; + }; + + port@15 { + reg = <21>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@16 { + reg = <22>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + + port@17 { + reg = <23>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@18 { + reg = <24>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + + port@19 { + reg = <25>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + }; + }; + + tpdm_dcc: tpdm@6870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + qcom,hw-enable-check; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_qm>; + }; + }; + }; + + funnel_dl_center: funnel@6c2d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c2d000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-center"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_center_out_tpda2: endpoint { + remote-endpoint = + <&tpda2_in_funnel_dl_center>; + source = <&tpdm_dl_mm>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_center_out_tpda4: endpoint { + remote-endpoint = + <&tpda4_in_funnel_dl_center>; + source = <&tpdm_mdss>; + }; + }; + + port@2 { + reg = <2>; + funnel_dl_center_out_tpda6: endpoint { + remote-endpoint = + <&tpda6_in_funnel_dl_center>; + source = <&tpdm_ddr>; + }; + }; + + port@3 { + reg = <3>; + funnel_dl_center_out_tpda9: endpoint { + remote-endpoint = + <&tpda9_in_funnel_dl_center>; + source = <&tpdm_lpass>; + }; + }; + + port@4 { + reg = <4>; + funnel_dl_center_out_tpda10: endpoint { + remote-endpoint = + <&tpda10_in_funnel_dl_center>; + source = <&tpdm_npu>; + }; + }; + + port@5 { + reg = <5>; + funnel_dl_center_out_tpda11: endpoint { + remote-endpoint = + <&tpda11_in_funnel_dl_center>; + source = <&tpdm_npu_llm>; + }; + }; + + port@6 { + reg = <6>; + funnel_dl_center_out_tpda12: endpoint { + remote-endpoint = + <&tpda12_in_funnel_dl_center>; + source = <&tpdm_npu_dpm>; + }; + }; + + port@7 { + reg = <7>; + funnel_dl_center_out_tpda13: endpoint { + remote-endpoint = + <&tpda13_in_funnel_dl_center>; + source = <&tpdm_compute0>; + }; + }; + + port@8 { + reg = <8>; + funnel_dl_center_out_tpda14: endpoint { + remote-endpoint = + <&tpda14_in_funnel_dl_center>; + source = <&tpdm_compute1>; + }; + }; + + port@9 { + reg = <9>; + funnel_dl_center_out_tpda15: endpoint { + remote-endpoint = + <&tpda15_in_funnel_dl_center>; + source = <&tpdm_turing>; + }; + }; + + port@10 { + reg = <10>; + funnel_dl_center_out_tpda16: endpoint { + remote-endpoint = + <&tpda16_in_funnel_dl_center>; + source = <&tpdm_llm_turing>; + }; + }; + + port@11 { + reg = <11>; + funnel_dl_center_out_tpda19: endpoint { + remote-endpoint = + <&tpda19_in_funnel_dl_center>; + source = <&tpdm_dlct>; + }; + }; + + port@12 { + reg = <12>; + funnel_dl_center_out_tpda20: endpoint { + remote-endpoint = + <&tpda20_in_funnel_dl_center>; + source = <&tpdm_ipcc>; + }; + }; + + port@13 { + reg = <13>; + funnel_dl_center_out_qatb3: endpoint { + remote-endpoint = + <&qatb3_in_funnel_dl_center>; + }; + }; + + port@14 { + reg = <0>; + funnel_dl_center_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_funnel_dl_center>; + }; + }; + + port@15 { + reg = <1>; + funnel_dl_center_in_tpdm_mdss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mdss_out_funnel_dl_center>; + }; + }; + + port@16 { + reg = <2>; + funnel_dl_center_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_funnel_dl_center>; + }; + }; + + port@17 { + reg = <3>; + funnel_center_in_funnel_compute: endpoint { + slave-mode; + remote-endpoint = + <&funnel_compute_out_funnel_center>; + }; + }; + + port@18 { + reg = <4>; + funnel_dl_center_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_funnel_dl_center>; + }; + }; + + port@19 { + reg = <5>; + funnel_dl_center_in_tpdm_dlct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct_out_funnel_dl_center>; + }; + }; + + port@20 { + reg = <6>; + funnel_dl_center_in_tpdm_ipcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ipcc_out_funnel_dl_center>; + }; + }; + }; + }; + + tpdm_dlct: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dlct"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dlct_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_tpdm_dlct>; + }; + }; + }; + + tpdm_ipcc: tpdm@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c29000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ipcc"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_ipcc_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_tpdm_ipcc>; + }; + }; + }; + + tpda_nav: tpda@6843000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x6843000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-nav"; + qcom,tpda-atid = <68>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_nav_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_dl_compute_in_tpda_nav>; + }; + }; + + port@1 { + reg = <0>; + tpda_nav0_in_tpdm_nav: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_nav_out_tpda_nav0>; + }; + }; + + }; + }; + + tpdm_nav: tpdm@6842000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6842000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-nav"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_nav_out_tpda_nav0: endpoint { + remote-endpoint = + <&tpda_nav0_in_tpdm_nav>; + }; + }; + }; + + funnel_turing: funnel@6983000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6983000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + + port@2 { + reg = <1>; + funnel_turing_in_tpdm_llm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_turing_out_funnel_turing>; + }; + }; + + port@3 { + reg = <2>; + funnel_turing_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6980000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; + }; + }; + }; + + tpdm_llm_turing: tpdm@69810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6981000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing-llm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_llm_turing>; + }; + }; + }; + + etm_turing: turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port { + turing_etm0_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_turing_etm0>; + }; + }; + }; + + funnel_dl_compute: funnel@6c3b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c3b000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-compute"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_compute_out_funnel_center: endpoint { + remote-endpoint = + <&funnel_center_in_funnel_compute>; + }; + }; + + port@1 { + reg = <2>; + funnel_dl_compute_in_funnel_lpass: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_out_funnel_dl_compute>; + }; + }; + + port@2 { + reg = <4>; + funnel_dl_compute_in_funnel_npu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_npu_out_funnel_dl_compute>; + }; + }; + + port@3 { + reg = <5>; + funnel_dl_compute_in_tpdm_compute0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_compute0_out_funnel_dl_compute>; + }; + }; + + port@4 { + reg = <6>; + funnel_dl_compute_in_tpdm_compute1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_compute1_out_funnel_dl_compute>; + }; + }; + + port@5 { + reg = <7>; + funnel_dl_compute_in_tpda_nav: endpoint { + slave-mode; + remote-endpoint = + <&tpda_nav_out_funnel_dl_compute>; + }; + }; + }; + }; + + tpdm_compute0: tpdm@6c38000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c38000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-compute0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_compute0_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_dl_compute_in_tpdm_compute0>; + }; + }; + }; + + tpdm_compute1: tpdm@6c39000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c39000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-compute1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_compute1_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_dl_compute_in_tpdm_compute1>; + }; + }; + }; + + tpdm_npu: tpdm@6c47000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c47000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&aopcc QDSS_CLK>; + + clock-names = "apb_pclk"; + + port { + tpdm_npu_out_funnel_npu: endpoint { + remote-endpoint = <&funnel_npu_in_tpdm_npu>; + }; + }; + }; + + tpdm_npu_llm: tpdm@6c40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c40000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu-llm"; + + clocks = <&aopcc QDSS_CLK>, + <&gcc GCC_NPU_AXI_CLK>, + <&gcc GCC_NPU_CFG_AHB_CLK>, + <&npucc NPU_CC_XO_CLK>, + <&npucc NPU_CC_CORE_CLK>, + <&npucc NPU_CC_CORE_CLK_SRC>, + <&npucc NPU_CC_DL_LLM_CLK>, + <&npucc NPU_CC_LLM_CLK>, + <&npucc NPU_CC_LLM_CURR_CLK>, + <&npucc NPU_CC_LLM_TEMP_CLK>, + <&npucc NPU_CC_LLM_XO_CLK>; + + clock-names = "apb_pclk", + "npu_axi_clk", + "npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "dl_llm_clk", + "llm_clk", + "llm_curr_clk", + "llm_temp_clk", + "llm_xo_clk"; + + qcom,proxy-clks = "npu_axi_clk", + "npu_cfg_ahb_clk", + "npu_cc_xo_clk", + "npu_core_clk", + "npu_core_clk_src", + "dl_llm_clk", + "llm_clk", + "llm_curr_clk", + "llm_temp_clk", + "llm_xo_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-regs ="vdd", "vdd_cx"; + + port { + tpdm_npu_llm_out_funnel_npu: endpoint { + remote-endpoint = <&funnel_npu_in_tpdm_npu_llm>; + }; + }; + }; + + tpdm_npu_dpm: tpdm@6c41000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c41000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu-dpm"; + + clocks = <&aopcc QDSS_CLK>, + <&npucc NPU_CC_DL_DPM_CLK>, + <&npucc NPU_CC_DPM_CLK>, + <&npucc NPU_CC_DPM_TEMP_CLK>, + <&npucc NPU_CC_DPM_XO_CLK>; + + clock-names = "apb_pclk", + "dl_dpm_clk", + "dpm_clk", + "dpm_temp_clk", + "dpm_xo_clk"; + + qcom,proxy-clks = "dl_dpm_clk", + "dpm_clk", + "dpm_temp_clk", + "dpm_xo_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-regs ="vdd", "vdd_cx"; + + + port { + tpdm_npu_dpm_out_funnel_npu: endpoint { + remote-endpoint = <&funnel_npu_in_tpdm_npu_dpm>; + }; + }; + }; + + funnel_npu: funnel@6c44000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c44000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-npu"; + + clocks = <&aopcc QDSS_CLK>; + + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_npu_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_dl_compute_in_funnel_npu>; + }; + }; + + port@1 { + reg = <0>; + funnel_npu_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_funnel_npu>; + }; + }; + + port@2 { + reg = <1>; + funnel_npu_in_tpdm_npu_llm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_llm_out_funnel_npu>; + }; + }; + + port@3 { + reg = <2>; + funnel_npu_in_tpdm_npu_dpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_dpm_out_funnel_npu>; + }; + }; + + port@4 { + reg = <3>; + funnel_npu_in_npu_etm0: endpoint { + slave-mode; + remote-endpoint = + <&npu_etm0_out_funnel_npu>; + }; + }; + }; + }; + + etm_npu: npu_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-npu-etm0"; + qcom,inst-id = <14>; + + port { + npu_etm0_out_funnel_npu: endpoint { + remote-endpoint = + <&funnel_npu_in_npu_etm0>; + }; + }; + }; + + funnel_lpass: funnel@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6846000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-lpass"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_out_funnel_dl_compute: endpoint { + remote-endpoint = + <&funnel_dl_compute_in_funnel_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_lpass_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_lpass>; + }; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6844000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-lpass"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_lpass_out_funnel_lpass: endpoint { + remote-endpoint = <&funnel_lpass_in_tpdm_lpass>; + }; + }; + }; + + funnel_ddr_0: funnel@6e05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6e05000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ddr_0_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@6e00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x06e00000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + status = "disabled"; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + tpdm_mdss: tpdm@6c60000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c60000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mdss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_mdss_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_tpdm_mdss>; + }; + }; + }; + + funnel_dl_mm: funnel@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6c0b000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm_out_funnel_dl_center: endpoint { + remote-endpoint = + <&funnel_dl_center_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_mm_in_tpdm_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_mm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_dl_mm: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6c08000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mm"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_mm_out_funnel_dl_mm: endpoint { + remote-endpoint = + <&funnel_dl_mm_in_tpdm_dl_mm>; + }; + }; + }; + + funnel_gpu: funnel@6902000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6902000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gpu"; + + status = "disabled"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gpu_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_gpu>; + }; + }; + + port@1 { + reg = <0>; + funnel_gpu_in_tpdm_gpu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gpu_out_funnel_gpu>; + }; + }; + }; + }; + + tpdm_gpu: tpdm@6900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6900000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gpu"; + status = "disabled"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_gpu_out_funnel_gpu: endpoint { + remote-endpoint = <&funnel_gpu_in_tpdm_gpu>; + }; + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <1>; + funnel_in1_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_in1>; + }; + }; + + port@2 { + reg = <4>; + funnel_in1_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_in1>; + }; + }; + + port@3 { + reg = <5>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + }; + }; + + funnel_modem: funnel@6804000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x6804000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_out_funnel_modem>; + }; + }; + + port@2 { + reg = <1>; + funnel_modem_in_modem2_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem2_etm0_out_funnel_modem>; + }; + }; + + port@3 { + reg = <3>; + funnel_modem_in_funnel_mq6_dup: endpoint { + slave-mode; + remote-endpoint = + <&funnel_mq6_dup_out_funnel_modem>; + }; + }; + }; + }; + + modem2_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem2-etm0"; + qcom,inst-id = <11>; + + port { + modem2_etm0_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_modem2_etm0>; + }; + }; + }; + + funnel_modem_q6: funnel@680c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x680c000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem-q6"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_q6_out_funnel_mq6_dup: endpoint { + remote-endpoint = + <&funnel_mq6_dup_in_funnel_modem_q6>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_q6_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_modem_q6>; + }; + }; + }; + }; + + funnel_mq6_dup: funnel_1@680c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x680b000 0x1000>, + <0x680c000 0x1000>; + + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-modem-q6_dup"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_mq6_dup_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_funnel_mq6_dup>; + }; + }; + + port@1 { + reg = <1>; + funnel_mq6_dup_in_funnel_modem_q6: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_q6_out_funnel_mq6_dup>; + }; + }; + + port@2 { + reg = <2>; + funnel_mq6_dup_in_modem_diag: endpoint { + slave-mode; + remote-endpoint = + <&modem_diag_out_funnel_mq6_dup>; + }; + }; + }; + }; + + modem_diag: dummy_source { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-modem-diag"; + qcom,dummy-source; + + port { + modem_diag_out_funnel_mq6_dup: endpoint { + remote-endpoint = + <&funnel_mq6_dup_in_modem_diag>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_modem_q6: endpoint { + remote-endpoint = + <&funnel_modem_q6_in_modem_etm0>; + }; + }; + }; + + tpda_modem: tpda@6803000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x6803000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_modem_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem_0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_0_out_tpda_modem>; + }; + }; + + port@2 { + reg = <1>; + tpda_modem_in_tpdm_modem_1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_1_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem_0: tpdm@6800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6800000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-modem-0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_modem_0_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem_0>; + }; + }; + }; + + tpdm_modem_1: tpdm@6801000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6801000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-modem-1"; + + status = "disabled"; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_modem_1_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem_1>; + }; + }; + }; + + tpdm_swao1: tpdm@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x6b0a000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm4"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm5"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm6"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm7"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_iris: cti@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6830000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-iris_dl_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,cti-gpio-trigout = <4>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti_cpu0: cti@7020000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7020000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + + }; + + cti_cpu1: cti@7120000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7120000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@7220000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7220000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@7320000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7320000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu4: cti@7420000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7420000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@7520000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7520000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@7620000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7620000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@7720000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x7720000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao:cti@6b00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b00000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao:cti@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b01000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao:cti@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao:cti@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6b03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_dlct: cti@6c2c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c2c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlcompute: cti@6c3a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c3a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlcompute_cti0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6e02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6e03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ddr0: cti@6e04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti_2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6e10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6e11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_ddr1: cti@6e12000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6e12000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti_2"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_m3: cti@6962000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6962000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-gpu_cortex_m3"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_gpu_isdb: cti@6961000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6961000 0x1000>; + reg-names = "cti-base"; + + status = "disabled"; + coresight-name = "coresight-cti-gpu_isdb_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass: cti@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6845000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass_dl_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl0: cti@6c42000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c42000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_0"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu_dl1: cti@6c43000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c43000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_dl_cti_1"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_npu: cti@6c4b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6c4b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-npu_q6_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing:cti@6982000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x6982000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_dl_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing_q6:cti@698b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x698b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing_q6_cti"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + tpdm_lpass_lpi: tpdm@6b26000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-lpass-lpi"; + qcom,dummy-source; + + port { + lpass_lpi_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_lpass_lpi>; + }; + }; + }; + + tpdm_wcss: tpdm@069a4000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_in1: endpoint { + remote-endpoint = <&funnel_in1_in_tpdm_wcss>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_audio_etm0>; + }; + }; + }; + + ipcb_tgu: tgu@6b0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb999>; + reg = <0x06b0b000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + hwevent { + compatible = "qcom,coresight-hwevent"; + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&aopcc QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-gdsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-gdsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fff09af074f84302cabb3b4d1fd9740aae95136a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-gdsc.dtsi @@ -0,0 +1,165 @@ +&soc { + /* GCC GDSCs */ + ufs_phy_gdsc: qcom,gdsc@177004 { + compatible = "qcom,gdsc"; + reg = <0x177004 0x4>; + regulator-name = "ufs_phy_gdsc"; + status = "disabled"; + }; + + usb30_prim_gdsc: qcom,gdsc@10f004 { + compatible = "qcom,gdsc"; + reg = <0x10f004 0x4>; + regulator-name = "usb30_prim_gdsc"; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc: qcom,gdsc@17d050 { + compatible = "qcom,gdsc"; + reg = <0x17d050 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc: qcom,gdsc@17d058 { + compatible = "qcom,gdsc"; + reg = <0x17d058 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc: qcom,gdsc@17d054 { + compatible = "qcom,gdsc"; + reg = <0x17d054 0x4>; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + /* CAM_CC GDSCs */ + bps_gdsc: qcom,gdsc@ad07004 { + compatible = "qcom,gdsc"; + reg = <0xad07004 0x4>; + regulator-name = "bps_gdsc"; + status = "disabled"; + }; + + ipe_0_gdsc: qcom,gdsc@ad08004 { + compatible = "qcom,gdsc"; + reg = <0xad08004 0x4>; + regulator-name = "ipe_0_gdsc"; + status = "disabled"; + }; + + ipe_1_gdsc: qcom,gdsc@ad09004 { + compatible = "qcom,gdsc"; + reg = <0xad09004 0x4>; + regulator-name = "ipe_1_gdsc"; + status = "disabled"; + }; + + ife_0_gdsc: qcom,gdsc@ad0a004 { + compatible = "qcom,gdsc"; + reg = <0xad0a004 0x4>; + regulator-name = "ife_0_gdsc"; + status = "disabled"; + }; + + ife_1_gdsc: qcom,gdsc@ad0b004 { + compatible = "qcom,gdsc"; + reg = <0xad0b004 0x4>; + regulator-name = "ife_1_gdsc"; + status = "disabled"; + }; + + titan_top_gdsc: qcom,gdsc@ad0c1c4 { + compatible = "qcom,gdsc"; + reg = <0xad0c1c4 0x4>; + regulator-name = "titan_top_gdsc"; + status = "disabled"; + }; + + /* DISP_CC GDSC */ + mdss_core_gdsc: qcom,gdsc@af03000 { + compatible = "qcom,gdsc"; + reg = <0xaf03000 0x4>; + regulator-name = "mdss_core_gdsc"; + qcom,support-hw-trigger; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + status = "disabled"; + }; + + /* GPU_CC GDSCs */ + gpu_cx_hw_ctrl: syscon@3d91540 { + compatible = "syscon"; + reg = <0x3d91540 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@3d9106c { + compatible = "qcom,gdsc"; + reg = <0x3d9106c 0x4>; + regulator-name = "gpu_cx_gdsc"; + hw-ctrl-addr = <&gpu_cx_hw_ctrl>; + qcom,no-status-check-on-disable; + qcom,clk-dis-wait-val = <8>; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + gpu_gx_domain_addr: syscon@3d91508 { + compatible = "syscon"; + reg = <0x3d91508 0x4>; + }; + + gpu_gx_sw_reset: syscon@3d91008 { + compatible = "syscon"; + reg = <0x3d91008 0x4>; + }; + + gpu_gx_gdsc: qcom,gdsc@3d9100c { + compatible = "qcom,gdsc"; + reg = <0x3d9100c 0x4>; + regulator-name = "gpu_gx_gdsc"; + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; + qcom,skip-disable-before-sw-enable; + qcom,reset-aon-logic; + status = "disabled"; + }; + + /* NPU GDSC */ + npu_core_gdsc: qcom,gdsc@9981004 { + compatible = "qcom,gdsc"; + reg = <0x9981004 0x4>; + regulator-name = "npu_core_gdsc"; + status = "disabled"; + }; + + /* VIDEO_CC GDSCs */ + mvsc_gdsc: qcom,gdsc@ab00814 { + compatible = "qcom,gdsc"; + reg = <0xab00814 0x4>; + regulator-name = "mvsc_gdsc"; + status = "disabled"; + }; + + mvs0_gdsc: qcom,gdsc@ab00874 { + compatible = "qcom,gdsc"; + reg = <0xab00874 0x4>; + regulator-name = "mvs0_gdsc"; + status = "disabled"; + }; + + mvs1_gdsc: qcom,gdsc@ab008b4 { + compatible = "qcom,gdsc"; + reg = <0xab008b4 0x4>; + regulator-name = "mvs1_gdsc"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ecfcd0aecf5b58f17310b92da62fa9957670b449 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-gpu.dtsi @@ -0,0 +1,455 @@ +&soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a620_zap"; + }; + + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + operating-points-v2 = <&gpu_opp_table>; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-750000000 { + opp-hz = /bits/ 64 <750000000>; + opp-microvolt = ; + }; + + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = ; + }; + + opp-670000000 { + opp-hz = /bits/ 64 <670000000>; + opp-microvolt = ; + }; + + opp-625000000 { + opp-hz = /bits/ 64 <625000000>; + opp-microvolt = ; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + opp-microvolt = ; + }; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = ; + }; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = ; + }; + + opp-275000000 { + opp-hz = /bits/ 64 <275000000>; + opp-microvolt = ; + }; + }; + + msm_gpu: qcom,kgsl-3d0@3d00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x3d00000 0x40000>, <0x3d61000 0x800>, + <0x3de0000 0x1000>, <0x3d8b000 0x2000>; + reg-names = "kgsl_3d0_reg_memory", "cx_dbgc", "rscc", + "isense_cntl"; + interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x06020000>; + + qcom,initial-pwrlevel = <3>; + + qcom,idle-timeout = <80>; /* msecs */ + + qcom,highest-bank-bit = <14>; + + qcom,min-access-length = <32>; + + qcom,ubwc-mode = <3>; + qcom,no-nap; + qcom,snapshot-size = <2048576>; /* bytes */ + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; /* base addr, size */ + + #cooling-cells = <2>; + qcom,tzone-name = "gpuss-max-step"; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <67>; + qcom,pm-qos-wakeup-latency = <67>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + clocks = <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk", + "gpu_cc_ahb", "smmu_vote"; + + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <13>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 800000>, /* 2 bus=200 */ + <26 512 0 1200000>, /* 3 bus=300 */ + <26 512 0 1804800>, /* 4 bus=451 */ + <26 512 0 2188000>, /* 5 bus=547 */ + <26 512 0 2724000>, /* 6 bus=681 */ + <26 512 0 3072000>, /* 7 bus=768 */ + <26 512 0 4068000>, /* 8 bus=1017 */ + <26 512 0 5412000>, /* 9 bus=1353 */ + <26 512 0 6220000>, /* 10 bus=1555 */ + <26 512 0 7216000>, /* 11 bus=1804 */ + <26 512 0 8371200>; /* 12 bus=2092 */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + nvmem-cells = <&gpu_speed_bin>, <&gpu_gaming_bin>, <&gpu_lm_efuse>; + nvmem-cell-names = "speed_bin", "gaming_bin", "isense_slope"; + + /* GPU OPP data */ + operating-points-v2 = <&gpu_opp_table>; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-reserved = <2048>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-reserved = <1024>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calulated as FMAX/4.8 MHz round up to zero + * decimal places. + */ + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + qcom,ca-target-pwrlevel = <2>; + qcom,initial-pwrlevel = <3>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <625000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802C5FFD>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <132>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <625000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802C5FFD>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <115>; + qcom,initial-pwrlevel = <2>; + qcom,ca-target-pwrlevel = <1>; + + /* SVS L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <540000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802C5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + qcom,cpu-to-gpu-cfg-path { + qcom,msm-bus,name = "gpu_cfg"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 598 0 0>, // off + <1 598 0 100>, // min freq + <1 598 0 9999999>; // max freq + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@3da0000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x03da0000 0x10000>; + /* CB5(ATOS) & CB5/6/7 are protected by HYP */ + qcom,protect = <0xa0000 0xc000>; + + clocks =<&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "gcc_gpu_memnoc_gfx", + "gcc_gpu_snoc_dvm_gfx", + "gpu_cc_ahb", "smmu_vote"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0x0 0x401>; + qcom,iommu-dma = "disabled"; + qcom,gpu-offset = <0xa8000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_secure"; + iommus = <&kgsl_smmu 0x2 0x400>; + qcom,iommu-dma = "disabled"; + }; + }; + + gmu: qcom,gmu@3d6a000 { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = <0x3d6a000 0x30000>, + <0xb290000 0x10000>, + <0xb490000 0x10000>; + reg-names = "kgsl_gmu_reg", + "kgsl_gmu_pdc_cfg", + "kgsl_gmu_pdc_seq"; + + interrupts = <0 304 IRQ_TYPE_LEVEL_HIGH>, + <0 305 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq"; + + qcom,msm-bus,name = "cnoc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 10036 0 0>, /* CNOC off */ + <26 10036 0 100>; /* CNOC on */ + + regulator-names = "vddcx", "vdd"; + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk", "gpu_cc_ahb", "smmu_vote"; + + /* AOP mailbox for sending ACD enable and disable messages */ + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 0x4 0x400>; + qcom,iommu-dma = "disabled"; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 0x5 0x400>; + qcom,iommu-dma = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-ion.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6a4835bb591a12d3807c26b6f38b87a2056a45a9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-ion.dtsi @@ -0,0 +1,50 @@ +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + system_secure_heap: qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&sdsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@14 { /* SECURE CARVEOUT HEAP */ + reg = <14>; + qcom,ion-heap-type = "SECURE_CARVEOUT"; + cdsp { + memory-region = <&cdsp_sec_mem>; + token = <0x20000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-lpi.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..53e07b7f1918abb2d86cc925553bae586d96bc9d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-lpi.dtsi @@ -0,0 +1,1650 @@ +&q6core { + lpi_tlmm: lpi_pinctrl@33c0000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0x33c0000 0x0>; + qcom,slew-reg = <0x355a000 0x0>; + qcom,num-gpios = <15>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = <0x00000000>, <0x00001000>, + <0x00002000>, <0x00003000>, + <0x00004000>, <0x00005000>, + <0x00006000>, <0x00007000>, + <0x00008000>, <0x00009000>, + <0x0000A000>, <0x0000B000>, + <0x0000C000>, <0x0000D000>, + <0x0000E000>; + qcom,lpi-slew-offset-tbl = <0x00000000>, <0x00000002>, + <0x00000004>, <0x00000008>, + <0x0000000A>, <0x0000000C>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000010>, <0x00000012>, + <0x00000000>, <0x00000000>, + <0x00000000>; + + clock-names = "lpass_core_hw_vote", + "lpass_audio_hw_vote"; + clocks = <&lpass_core_hw_vote 0>, + <&lpass_audio_hw_vote 0>; + + quat_mi2s_sck { + quat_mi2s_sck_sleep: quat_mi2s_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sck_active: quat_mi2s_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_ws { + quat_mi2s_ws_sleep: quat_mi2s_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_ws_active: quat_mi2s_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sck { + lpi_i2s1_sck_sleep: lpi_i2s1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sck_active: lpi_i2s1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_ws { + lpi_i2s1_ws_sleep: lpi_i2s1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_ws_active: lpi_i2s1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd0 { + lpi_i2s1_sd0_sleep: lpi_i2s1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd0_active: lpi_i2s1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd1 { + lpi_i2s1_sd1_sleep: lpi_i2s1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd1_active: lpi_i2s1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sck { + lpi_i2s2_sck_sleep: lpi_i2s2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sck_active: lpi_i2s2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_ws { + lpi_i2s2_ws_sleep: lpi_i2s2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_ws_active: lpi_i2s2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd0 { + lpi_i2s2_sd0_sleep: lpi_i2s2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd0_active: lpi_i2s2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd1 { + lpi_i2s2_sd1_sleep: lpi_i2s2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd1_active: lpi_i2s2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sck { + quat_tdm_sck_sleep: quat_tdm_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sck_active: quat_tdm_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_ws { + quat_tdm_ws_sleep: quat_tdm_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_ws_active: quat_tdm_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd0 { + quat_tdm_sd0_sleep: quat_tdm_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd0_active: quat_tdm_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd1 { + quat_tdm_sd1_sleep: quat_tdm_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd1_active: quat_tdm_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd2 { + quat_tdm_sd2_sleep: quat_tdm_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd2_active: quat_tdm_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd3 { + quat_tdm_sd3_sleep: quat_tdm_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd3_active: quat_tdm_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sck { + lpi_tdm1_sck_sleep: lpi_tdm1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sck_active: lpi_tdm1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_ws { + lpi_tdm1_ws_sleep: lpi_tdm1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_ws_active: lpi_tdm1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd0 { + lpi_tdm1_sd0_sleep: lpi_tdm1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd0_active: lpi_tdm1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd1 { + lpi_tdm1_sd1_sleep: lpi_tdm1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd1_active: lpi_tdm1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sck { + lpi_tdm2_sck_sleep: lpi_tdm2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sck_active: lpi_tdm2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_ws { + lpi_tdm2_ws_sleep: lpi_tdm2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_ws_active: lpi_tdm2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd0 { + lpi_tdm2_sd0_sleep: lpi_tdm2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd0_active: lpi_tdm2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd1 { + lpi_tdm2_sd1_sleep: lpi_tdm2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd1_active: lpi_tdm2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sck { + quat_aux_sck_sleep: quat_aux_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sck_active: quat_aux_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_ws { + quat_aux_ws_sleep: quat_aux_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_ws_active: quat_aux_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd0 { + quat_aux_sd0_sleep: quat_aux_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd0_active: quat_aux_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd1 { + quat_aux_sd1_sleep: quat_aux_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd1_active: quat_aux_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd2 { + quat_aux_sd2_sleep: quat_aux_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd2_active: quat_aux_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd3 { + quat_aux_sd3_sleep: quat_aux_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd3_active: quat_aux_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sck { + lpi_aux1_sck_sleep: lpi_aux1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sck_active: lpi_aux1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_ws { + lpi_aux1_ws_sleep: lpi_aux1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_ws_active: lpi_aux1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd0 { + lpi_aux1_sd0_sleep: lpi_aux1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd0_active: lpi_aux1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd1 { + lpi_aux1_sd1_sleep: lpi_aux1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd1_active: lpi_aux1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sck { + lpi_aux2_sck_sleep: lpi_aux2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sck_active: lpi_aux2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_ws { + lpi_aux2_ws_sleep: lpi_aux2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_ws_active: lpi_aux2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd0 { + lpi_aux2_sd0_sleep: lpi_aux2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd0_active: lpi_aux2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd1 { + lpi_aux2_sd1_sleep: lpi_aux2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd1_active: lpi_aux2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + + tx_swr_clk_sleep: tx_swr_clk_sleep { + mux { + pins = "gpio0"; + function = "func1"; + input-enable; + bias-pull-down; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + }; + }; + + tx_swr_clk_active: tx_swr_clk_active { + mux { + pins = "gpio0"; + function = "func1"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + }; + + tx_swr_data1_sleep: tx_swr_data1_sleep { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; + input-enable; + bias-bus-hold; + }; + }; + + tx_swr_data1_active: tx_swr_data1_active { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + tx_swr_data2_sleep: tx_swr_data2_sleep { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data2_active: tx_swr_data2_active { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + tx_swr_data3_sleep: tx_swr_data3_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data3_active: tx_swr_data3_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + rx_swr_clk_sleep: rx_swr_clk_sleep { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_clk_active: rx_swr_clk_active { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + }; + + rx_swr_data_sleep: rx_swr_data_sleep { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data_active: rx_swr_data_active { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + rx_swr_data1_sleep: rx_swr_data1_sleep { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data1_active: rx_swr_data1_active { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + cdc_dmic01_clk_active: dmic01_clk_active { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic01_clk_sleep: dmic01_clk_sleep { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic01_data_active: dmic01_data_active { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic01_data_sleep: dmic01_data_sleep { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic23_clk_active: dmic23_clk_active { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic23_clk_sleep: dmic23_clk_sleep { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic23_data_active: dmic23_data_active { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic23_data_sleep: dmic23_data_sleep { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic45_clk_active: dmic45_clk_active { + mux { + pins = "gpio12"; + function = "func1"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic45_clk_sleep: dmic45_clk_sleep { + mux { + pins = "gpio12"; + function = "func1"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic45_data_active: dmic45_data_active { + mux { + pins = "gpio13"; + function = "func1"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic45_data_sleep: dmic45_data_sleep { + mux { + pins = "gpio13"; + function = "func1"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-mtp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..249ab6f927dfe8b616521f71115a4b87973ddc83 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-mtp-overlay.dts @@ -0,0 +1,16 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito MTP"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,msm-id = <400 0x10000>, <440 0x10000>; + qcom,board-id = <8 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/lito-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..f62ee55d9d455652dfe85d4d9af97b9e5354d6f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-mtp.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "lito.dtsi" +#include "lito-mtp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito MTP"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,board-id = <8 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-mtp.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..ff35b2145f7a49e5e627130279f46d9616e22f9b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-mtp.dtsi @@ -0,0 +1,567 @@ +#include +#include "lito-audio-overlay.dtsi" +#include "lito-pmic-overlay.dtsi" +#include "lito-sde-display.dtsi" +#include "lito-thermal-overlay.dtsi" + +&soc { + oem_serial_pinctrl { + compatible = "oem,oem_serial_pinctrl"; + pinctrl-names = "uart_pinctrl_active","uart_pinctrl_deactive"; + pinctrl-0 = <&qupv3_se2_2uart_active>; + pinctrl-1 = <&qupv3_se2_2uart_sleep>; + }; + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150l_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + vol_down { + label = "volume_down"; + gpios = <&pm7250b_gpios 3 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + }; + + vdda_usb_ss_dp_core: vdda_usb_ss_dp_core { + compatible = "regulator-fixed"; + regulator-name = "vdd_supply"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + enable-active-high; + gpio = <&pm8150l_gpios 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_eldo13>; + }; + + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; + + tri_state_key:tri_state_key { + compatible = "oneplus,tri-state-key"; + status = "ok"; + interrupt-parent = <&tlmm>; + tristate,gpio_key1 = <&pm7250b_gpios 10 0x00>; + tristate,gpio_key2 = <&tlmm 83 0x00>; + tristate,gpio_key3 = <&tlmm 69 0x00>; + pinctrl-names = + "pmx_tri_state_key_active", + "pmx_tri_state_key_suspend"; + pinctrl-0 = <&tri_state_key_active &tri_state_key_pmic>; + pinctrl-1 = <&tri_state_key_suspend &tri_state_key_pmic>; + }; +}; + + +&tlmm{ + tri_state_key_active: tri_state_key_active { + mux { + pins = "gpio69", "gpio83"; + function = "gpio"; + }; + config { + pins = "gpio69", "gpio83"; + drive-strength = <2>; + bias-disable; + }; + }; + + tri_state_key_suspend: tri_state_key_suspend { + mux { + pins = "gpio69", "gpio83"; + function = "gpio"; + }; + config { + pins = "gpio69", "gpio83"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +&pm7250b_gpios { + tri_state_key_pmic { + tri_state_key_pmic: tri_state_key_pmic { + pins = "gpio10"; + function = "normal"; + input-enable; + output-disable; + power-source = <0>; + }; + }; +}; + + +/*for aw haptic start*/ + +&tlmm { + aw_irq: aw_irq { + mux { + pins = "gpio70"; + function = "gpio"; + }; + config { + pins = "gpio70"; + drive-strength = <2>; + bias-pull-up; + }; + }; + aw_reset: aw_reset { + mux { + pins = "gpio71"; + function = "gpio"; + }; + config { + pins = "gpio71"; + drive-strength = <2>; + bias-disable; + }; + }; +}; +&qupv3_se0_i2c { + status = "ok"; + aw8697_haptic@5A { + compatible = "awinic,aw8697_haptic"; + reg = <0x5A>; + reset-gpio = <&tlmm 71 0x00>; + irq-gpio = <&tlmm 70 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&aw_irq &aw_reset>; + status = "okay"; + }; +}; + +&qupv3_se2_2uart { + compatible = "qcom,msm-geni-console-oem"; +}; + +&usb_qmp_dp_phy { + vdd-supply = <&vdda_usb_ss_dp_core>; +}; + +&sde_dp { + vdda-0p9-supply = <&vdda_usb_ss_dp_core>; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4-lito"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <90200>; + vdda-pll-max-microamp = <19000>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150a_l7>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l9>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm8150a_l7>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm8150_s4>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + + status = "disabled"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&pm7250b_vadc { + pinctrl-0 = < + &bmr_w_therm_default + &camera_therm_default + &bmr_s_therm_default + >; + + bmr_s_therm { + reg = ; + label = "bmr_s_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm7250b_gpios { + bmr_s_therm { + bmr_s_therm_default: bmr_s_therm_default { + pins = "gpio5"; + bias-high-impedance; + }; + }; +}; + +&pm7250b_adc_tm { + io-channels = <&pm7250b_vadc ADC_AMUX_THM1_PU2>, + <&pm7250b_vadc ADC_GPIO2_PU2>, + <&pm7250b_vadc ADC_GPIO3_PU2>, + <&pm7250b_vadc ADC_GPIO4_PU2>; + + bmr_s_therm@54 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + mmw-pa4-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_GPIO3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>, + <&pm7250b_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage", + "skin_temp"; + qcom,battery-data = <&mtp_batterydata>; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; + qcom,fcc-step-delay-ms = <100>; + qcom,fcc-step-size-ua = <100000>; + qcom,smb-internal-pull-kohm = <0>; + qcom,en-skin-therm-mitigation; + qcom,hvdcp3-standalone-config; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,battery-data = <&mtp_batterydata>; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3300>; + qcom,bass-enable; +}; + +&qupv3_se7_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <9 0x2008>; + vdd-supply = <&pm8150_s4>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 9 0x2008>; + st,reset-gpio = <&tlmm 8 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + st,x-flip = <1>; + st,y-flip = <1>; + st,power_on_suspend; + panel = <&dsi_sw43404_amoled_cmd &dsi_sw43404_amoled_video + &dsi_sw43404_amoled_fhd_plus_cmd>; + }; +}; + +&qupv3_se7_i2c { + status = "ok"; + Goodix-gt9886@5D { + compatible = "Goodix-gt9886"; + reg = <0x5D>; + project-name = "20801"; + chip-name = "GT885"; + module_id = <7>; + /* Interrupt && Irq-gpio */ + interrupt-parent = <&tlmm>; + interrupts = <9 0x2002>; + + /* Power Config */ + vdd_2v8-supply = <&pm8150_l13>; + //vcc_1v8-supply = <&pm8150a_l1>; + vdd_2v8_volt = <3008000>; + enable1v8_gpio = <&pm8150l_gpios 1 GPIO_ACTIVE_LOW>; + + /* Other HW Resource */ + irq-gpio = <&tlmm 9 0x2002>; + reset-gpio = <&tlmm 8 0x1>; + pinctrl-names = "pin_set_high", "pin_set_low"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_reset_suspend>; + + touchpanel,max-num-support = <10>; + touchpanel,tx-rx-num = <15 34>; + touchpanel,panel-coords = <1080 2400>; + touchpanel,display-coords = <1080 2400>; + + /* SW Support Feature Control */ + black_gesture_support = <1>; + //fw_edge_limit_support; + //charger_pump_support; + //spurious_fingerprint_support; + //fw_update_app_support; + //smart_gesture_support; + game_switch_support = <1>; + face_detect_support = <1>; + lcd_refresh_rate_switch = <1>; + touch_hold_support = <1>; + charge_detect_support = <1>; + register-is-16bit = <1>; + // module_id_support = <1>; + //kernel_grip_support; + //health_monitor_support; + //fingerprint_underscreen_support; + //headset_pump_support; + //pressure_report_support; + panel =<&dsi_samsung_ams644vk04_dsc_cmd>; + }; +}; +&tlmm { + ts_int_active: ts_int_active { + mux { + pins = "gpio9"; + function = "gpio"; + }; + config { + pins = "gpio9"; + drive-strength = <8>; + bias-disable; + }; + }; + ts_reset_active: ts_reset_active { + mux { + pins = "gpio8"; + function = "gpio"; + }; + config { + pins = "gpio8"; + drive-strength = <8>; + bias-pull-up; + }; + }; + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio8"; + function = "gpio"; + }; + config { + pins = "gpio8"; + drive-strength = <8>; + bias-pull-down; + }; + }; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_video>; +}; + +/* Add for NXP NFCC */ +&qupv3_se0_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + nq@28 { + status = "disabled"; + }; + + pn5xx@28 { + compatible = "nxp,pn544"; + reg = <0x28>; + nxp,pn544-irq = <&tlmm 34 0x00>; + nxp,pn544-ven = <&tlmm 12 0x00>; + nxp,pn544-fw-dwnld = <&tlmm 35 0x00>; + nxp,pn544-clk-gpio = <&tlmm 31 0x00>; + nxp,pn544-ese-pwr = <&tlmm 26 0x00>; + //nfc_voltage_s4-supply = <&pm8150_s4>; + interrupt-parent = <&tlmm>; + //qcom,clk-src = "BBCLK3"; + interrupts = <34 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + }; +}; + +/* Add for NXP eSE */ +&qupv3_se1_spi { + status = "ok"; + qcom,disable-autosuspend; + + ese@0 { + compatible = "nxp,p61"; + reg = <0>; + spi-max-frequency = <8000000>; + nxp,nfcc = "5-0028"; + }; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + + +&L6P { + regulator-max-microvolt = <2800000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <184000>; +}; + +&L7P { + regulator-max-microvolt = <2900000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <200000>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-npu.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-npu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4ff1ec37cd03e78ffc6be0edf68efaf5b9c4abcf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-npu.dtsi @@ -0,0 +1,273 @@ +&soc { + msm_npu: qcom,msm_npu@9800000 { + compatible = "qcom,msm-npu"; + status = "ok"; + reg = <0x9900000 0x20000>, + <0x99F0000 0x10000>, + <0x9980000 0x10000>, + <0x17c00000 0x10000>, + <0x01F40000 0x40000>, + <0x780000 0x7000>; + reg-names = "tcm", "core", "cc", "apss_shared", "tcsr", + "qfprom_physical"; + interrupts = , + , + , + ; + interrupt-names = "error_irq", "wdg_bite_irq", "ipc_irq", + "general_irq"; + iommus = <&apps_smmu 0x1861 0x400>, <&apps_smmu 0x1862 0x400>, + <&apps_smmu 0x1881 0x400>, <&apps_smmu 0x1882 0x400>; + qcom,npu-dsp-sid-mapped; + + clocks = <&npucc NPU_CC_XO_CLK>, + <&npucc NPU_CC_CORE_CLK>, + <&npucc NPU_CC_CAL_HM0_CLK>, + <&npucc NPU_CC_CAL_HM0_CDC_CLK>, + <&npucc NPU_CC_NOC_AXI_CLK>, + <&npucc NPU_CC_NOC_AHB_CLK>, + <&npucc NPU_CC_NOC_DMA_CLK>, + <&npucc NPU_CC_LLM_CLK>, + <&npucc NPU_CC_LLM_XO_CLK>, + <&npucc NPU_CC_LLM_TEMP_CLK>, + <&npucc NPU_CC_LLM_CURR_CLK>, + <&npucc NPU_CC_DL_LLM_CLK>, + <&npucc NPU_CC_ISENSE_CLK>, + <&npucc NPU_CC_DPM_CLK>, + <&npucc NPU_CC_DPM_XO_CLK>, + <&npucc NPU_CC_DL_DPM_CLK>, + <&npucc NPU_CC_RSC_XO_CLK>, + <&npucc NPU_CC_DPM_TEMP_CLK>, + <&npucc NPU_CC_CAL_HM0_DPM_IP_CLK>, + <&npucc NPU_CC_S2P_CLK>, + <&npucc NPU_CC_BWMON_CLK>, + <&npucc NPU_CC_CAL_HM0_PERF_CNT_CLK>, + <&npucc NPU_CC_BTO_CORE_CLK>, + <&npucc NPU_DSP_CORE_CLK_SRC>; + clock-names = "xo_clk", + "npu_core_clk", + "cal_hm0_clk", + "cal_hm0_cdc_clk", + "axi_clk", + "ahb_clk", + "dma_clk", + "llm_clk", + "llm_xo_clk", + "llm_temp_clk", + "llm_curr_clk", + "dl_llm_clk", + "isense_clk", + "dpm_clk", + "dpm_xo_clk", + "dl_dpm_clk", + "rsc_xo_clk", + "dpm_temp_clk", + "cal_hm0_dpm_ip_clk", + "s2p_clk", + "bwmon_clk", + "cal_hm0_perf_cnt_clk", + "bto_core_clk", + "dsp_core_clk_src"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names ="vdd", "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + resets = <&npucc NPU_CC_DPM_TEMP_CLK_ARES>, + <&npucc NPU_CC_LLM_CURR_CLK_ARES>, + <&npucc NPU_CC_LLM_TEMP_CLK_ARES>; + reset-names = "dpm_temp_clk", "llm_curr_clk", "llm_temp_clk"; + #cooling-cells = <2>; + mboxes = <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_GLINK_QMP>, + <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_SMP2P>, + <&ipcc_mproc IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_PING>; + mbox-names = "ipcc-glink", "ipcc-smp2p", "ipcc-ping"; + #mbox-cells = <2>; + qcom,npubw-devs = <&npu_npu_llcc_bw &npu_llcc_ddr_bw &npudsp_npu_ddr_bw>; + qcom,npubw-dev-names = "npu_llcc_bw", "llcc_ddr_bw", "dsp_ddr_bw"; + qcom,src-dst-ports = , + ; + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <5>; + qcom,npu-pwrlevel@0 { + reg = <0>; + vreg = <1>; + clk-freq = <19200000 + 100000000 + 230000000 + 230000000 + 150000000 + 40000000 + 300000000 + 100000000 + 19200000 + 50000000 + 50000000 + 100000000 + 100000000 + 100000000 + 19200000 + 100000000 + 19200000 + 50000000 + 230000000 + 50000000 + 19200000 + 230000000 + 19200000 + 300000000>; + }; + + qcom,npu-pwrlevel@1 { + reg = <1>; + vreg = <2>; + clk-freq = <19200000 + 200000000 + 422000000 + 422000000 + 207000000 + 40000000 + 403000000 + 200000000 + 19200000 + 50000000 + 50000000 + 200000000 + 200000000 + 200000000 + 19200000 + 200000000 + 19200000 + 50000000 + 422000000 + 50000000 + 19200000 + 422000000 + 19200000 + 400000000>; + }; + + qcom,npu-pwrlevel@2 { + reg = <2>; + vreg = <3>; + clk-freq = <19200000 + 333000000 + 557000000 + 557000000 + 300000000 + 75000000 + 533000000 + 214000000 + 19200000 + 50000000 + 100000000 + 214000000 + 214000000 + 214000000 + 19200000 + 214000000 + 19200000 + 50000000 + 557000000 + 50000000 + 19200000 + 557000000 + 19200000 + 500000000>; + }; + + qcom,npu-pwrlevel@3 { + reg = <3>; + vreg = <4>; + clk-freq = <19200000 + 428000000 + 729000000 + 729000000 + 403000000 + 75000000 + 700000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 729000000 + 100000000 + 19200000 + 729000000 + 19200000 + 660000000>; + }; + + qcom,npu-pwrlevel@4 { + reg = <4>; + vreg = <6>; + clk-freq = <19200000 + 500000000 + 844000000 + 844000000 + 533000000 + 75000000 + 806000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 844000000 + 100000000 + 19200000 + 844000000 + 19200000 + 800000000>; + }; + + qcom,npu-pwrlevel@5 { + reg = <5>; + vreg = <7>; + clk-freq = <19200000 + 500000000 + 1000000000 + 1000000000 + 533000000 + 75000000 + 806000000 + 300000000 + 19200000 + 100000000 + 200000000 + 300000000 + 300000000 + 300000000 + 19200000 + 300000000 + 19200000 + 100000000 + 1000000000 + 100000000 + 19200000 + 1000000000 + 19200000 + 800000000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-pinctrl.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..35e5b2bc5ac283a315f236b9cf737b4c16f52cda --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-pinctrl.dtsi @@ -0,0 +1,1990 @@ +&soc { + tlmm: pinctrl@f000000 { + compatible = "qcom,lito-pinctrl"; + reg = <0x0f000000 0x1000000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + irqdomain-map = <0 0 &pdc 58 0>, + <3 0 &pdc 44 0>, + <4 0 &pdc 80 0>, + <5 0 &pdc 89 0>, + <6 0 &pdc 52 0>, + <9 0 &pdc 104 0>, + <10 0 &pdc 54 0>, + <11 0 &pdc 62 0>, + <22 0 &pdc 64 0>, + <24 0 &pdc 82 0>, + <26 0 &pdc 56 0>, + <30 0 &pdc 84 0>, + <31 0 &pdc 43 0>, + <32 0 &pdc 79 0>, + <33 0 &pdc 66 0>, + <34 0 &pdc 53 0>, + <36 0 &pdc 92 0>, + <37 0 &pdc 63 0>, + <38 0 &pdc 73 0>, + <39 0 &pdc 76 0>, + <41 0 &pdc 81 0>, + <42 0 &pdc 94 0>, + <43 0 &pdc 55 0>, + <45 0 &pdc 83 0>, + <46 0 &pdc 57 0>, + <47 0 &pdc 86 0>, + <48 0 &pdc 121 0>, + <49 0 &pdc 87 0>, + <50 0 &pdc 90 0>, + <52 0 &pdc 72 0>, + <53 0 &pdc 96 0>, + <55 0 &pdc 91 0>, + <56 0 &pdc 135 0>, + <57 0 &pdc 137 0>, + <58 0 &pdc 93 0>, + <59 0 &pdc 136 0>, + <62 0 &pdc 97 0>, + <64 0 &pdc 65 0>, + <65 0 &pdc 75 0>, + <66 0 &pdc 98 0>, + <67 0 &pdc 99 0>, + <68 0 &pdc 100 0>, + <69 0 &pdc 46 0>, + <70 0 &pdc 85 0>, + <72 0 &pdc 50 0>, + <73 0 &pdc 45 0>, + <74 0 &pdc 101 0>, + <78 0 &pdc 42 0>, + <82 0 &pdc 88 0>, + <83 0 &pdc 51 0>, + <84 0 &pdc 102 0>, + <85 0 &pdc 113 0>, + <86 0 &pdc 95 0>, + <87 0 &pdc 103 0>, + <88 0 &pdc 114 0>, + <90 0 &pdc 105 0>, + <97 0 &pdc 70 0>, + <98 0 &pdc 106 0>, + <100 0 &pdc 59 0>, + <103 0 &pdc 60 0>, + <105 0 &pdc 71 0>, + <107 0 &pdc 78 0>, + <108 0 &pdc 61 0>, + <109 0 &pdc 134 0>, + <110 0 &pdc 48 0>, + <111 0 &pdc 67 0>, + <112 0 &pdc 68 0>, + <113 0 &pdc 77 0>, + <114 0 &pdc 69 0>, + <115 0 &pdc 133 0>, + <116 0 &pdc 109 0>, + <117 0 &pdc 120 0>, + <119 0 &pdc 110 0>, + <121 0 &pdc 119 0>, + <122 0 &pdc 112 0>, + <124 0 &pdc 107 0>, + <126 0 &pdc 111 0>, + <127 0 &pdc 116 0>, + <128 0 &pdc 132 0>, + <133 0 &pdc 131 0>, + <135 0 &pdc 130 0>, + <138 0 &pdc 129 0>, + <139 0 &pdc 128 0>, + <140 0 &pdc 127 0>, + <141 0 &pdc 126 0>, + <142 0 &pdc 125 0>, + <144 0 &pdc 122 0>; + irqdomain-map-mask = <0xff 0>; + irqdomain-map-pass-thru = <0 0xff>; + + goodix_fp{ + fp_irq_init: fp_irq_init { + /*mux { + pins = "gpio112"; + function = "gpio"; + };*/ + config { + pins = "gpio112"; + function = "gpio"; + //drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + fp_reset_init: fp_reset_init { + mux { + pins = "gpio63"; + function = "gpio"; + }; + config { + pins = "gpio63"; + drive-strength = <8>; + bias-pull-up; + }; + }; + fp_id0_init: fp_id0_init { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-strength = <2>; + bias-disable; /* No Pull */ + input-enable; + }; + }; + }; + + trigout_a: trigout_a { + mux { + pins = "gpio63"; + function = "qdss_cti"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_2uart_pins: qupv3_se2_2uart_pins { + qupv3_se2_2uart_active: qupv3_se2_2uart_active { + mux { + pins = "gpio36", "gpio37"; + function = "qup02"; + }; + + config { + pins = "gpio36", "gpio37"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_2uart_sleep: qupv3_se2_2uart_sleep { + mux { + pins = "gpio36", "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio36", "gpio37"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se5_4uart_pins: qupv3_se5_4uart_pins { + qupv3_se5_ctsrx: qupv3_se5_ctsrx { + mux { + pins = "gpio38", "gpio41"; + function = "qup05"; + }; + + config { + pins = "gpio38", "gpio41"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_rts: qupv3_se5_rts { + mux { + pins = "gpio39"; + function = "qup05"; + }; + + config { + pins = "gpio39"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se5_tx: qupv3_se5_tx { + mux { + pins = "gpio40"; + function = "qup05"; + }; + + config { + pins = "gpio40"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se8_2uart_pins: qupv3_se8_2uart_pins { + qupv3_se8_2uart_active: qupv3_se8_2uart_active { + mux { + pins = "gpio51", "gpio52"; + function = "qup12"; + }; + + config { + pins = "gpio51", "gpio52"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_2uart_sleep: qupv3_se8_2uart_sleep { + mux { + pins = "gpio51", "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio51", "gpio52"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + qupv3_se0_i3c_pins: qupv3_se0_i3c_pins { + qupv3_se0_i3c_active: qupv3_se0_i3c_active { + mux { + pins = "gpio42", "gpio43"; + function = "ibi_i3c"; + }; + + config { + pins = "gpio42", "gpio43"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + qupv3_se0_i3c_sleep: qupv3_se0_i3c_sleep { + mux { + pins = "gpio42", "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio42", "gpio43"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se6_i3c_pins: qupv3_se6_i3c_pins { + qupv3_se6_i3c_active: qupv3_se6_i3c_active { + mux { + pins = "gpio59", "gpio60"; + function = "ibi_i3c"; + }; + + config { + pins = "gpio59", "gpio60"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + qupv3_se6_i3c_sleep: qupv3_se6_i3c_sleep { + mux { + pins = "gpio59", "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio59", "gpio60"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pri_i2s_sck_ws { + pri_i2s_sck_sleep: pri_i2s_sck_sleep { + mux { + pins = "gpio49"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio49"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + pri_i2s_sck_active: pri_i2s_sck_active { + mux { + pins = "gpio49"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio49"; + drive-strength = <4>; /* 4 mA */ + bias-disable; + output-high; + }; + }; + + pri_i2s_ws_sleep: pri_i2s_ws_sleep { + mux { + pins = "gpio50"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio50"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + pri_i2s_ws_active: pri_i2s_ws_active { + mux { + pins = "gpio50"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio50"; + drive-strength = <4>; /* 4 mA */ + bias-disable; + output-high; + }; + }; + }; + + pri_i2s_data0 { + pri_i2s_data0_sleep: pri_i2s_data0_sleep { + mux { + pins = "gpio51"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio51"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + pri_i2s_data0_active: pri_i2s_data0_active { + mux { + pins = "gpio51"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio51"; + drive-strength = <4>; /* 4 mA */ + bias-disable; + output-high; + }; + }; + }; + + pri_i2s_data1 { + pri_i2s_data1_sleep: pri_i2s_data1_sleep { + mux { + pins = "gpio52"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio52"; + drive-strength = <2>; /* 2 mA */ + }; + }; + + pri_i2s_data1_active: pri_i2s_data1_active { + mux { + pins = "gpio52"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio52"; + drive-strength = <4>; /* 4 mA */ + bias-disable; + output-high; + }; + }; + }; + + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio69"; + function = "gpio"; + }; + + config { + pins = "gpio69"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio69"; + function = "gpio"; + }; + + config { + pins = "gpio69"; + drive-strength = <2>; + bias-disable; + }; + }; + + + wcd938x_reset_active: wcd938x_reset_active { + mux { + pins = "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio57"; + drive-strength = <16>; + output-high; + }; + }; + + wcd938x_reset_sleep: wcd938x_reset_sleep { + mux { + pins = "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio57"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + /* Camera GPIOs CCI*/ + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio17", "gpio18"; + function = "cci_i2c"; + }; + + config { + pins = "gpio17", "gpio18"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio17", "gpio18"; + function = "cci_i2c"; + }; + + config { + pins = "gpio17", "gpio18"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio19", "gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19", "gpio20"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio19", "gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19", "gpio20"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_active: cci2_active { + mux { + /* CLK, DATA */ + pins = "gpio27", "gpio28"; + function = "cci_i2c"; + }; + + config { + pins = "gpio27", "gpio28"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci2_suspend: cci2_suspend { + mux { + /* CLK, DATA */ + pins = "gpio27", "gpio28"; + function = "cci_i2c"; + }; + + config { + pins = "gpio27", "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + /* Camera GPIOs CCI*/ + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_active: cam_sensor_mclk4_active { + /* MCLK4 */ + mux { + pins = "gpio25"; + function = "cam_mclk"; + }; + + config { + pins = "gpio25"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk4_suspend: cam_sensor_mclk4_suspend { + /* MCLK4 */ + mux { + pins = "gpio25"; + function = "cam_mclk"; + }; + + config { + pins = "gpio25"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_active_rear: cam_sensor_active_rear { + /* RESET REAR2 */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear: cam_sensor_suspend_rear { + /* RESET REAR2 */ + mux { + pins = "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio30"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rear_aux: cam_sensor_active_rear_aux { + /* RESET REARAUX,DVDD ELDO */ + mux { + pins = "gpio29", "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio29", "gpio71"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear_aux: cam_sensor_suspend_rear_aux { + /* RESET REARAUX,DVDD ELDO */ + mux { + pins = "gpio29", "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio29", "gpio71"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_triple_rear_aux: + cam_sensor_active_triple_rear_aux { + /* RESET REARAUX,AVDD ELDO */ + mux { + pins = "gpio29", "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio29", "gpio70"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_triple_rear_aux: + cam_sensor_suspend_triple_rear_aux { + /* RESET REARAUX,AVDD ELDO */ + mux { + pins = "gpio29", "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio29", "gpio70"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_rear_aux2: cam_sensor_active_rear_aux2 { + /* RESET REARAUX2,CSI MUX Sel */ + mux { + pins = "gpio21", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio51"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_rear_aux2: cam_sensor_suspend_rear_aux2 { + /* RESET REARAUX2, CSI MUX Sel */ + mux { + pins = "gpio21", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio51"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_3: cam_sensor_active_3 { + /* RESET TOF */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_3: cam_sensor_suspend_3 { + /* RESET TOF */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_active_front: cam_sensor_active_front { + /* RESET FRONT */ + mux { + pins = "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio32"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_suspend_front: cam_sensor_suspend_front { + /* RESET FRONT */ + mux { + pins = "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio32"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + /* QUPv3_0 North SE mappings */ + /* SE 0 pin mappings */ + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio42", "gpio43"; + function = "qup00"; + }; + + config { + pins = "gpio42", "gpio43"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio42", "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio42", "gpio43"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 34 NFC Read Interrupt */ + pins = "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio34"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 34 NFC Read Interrupt */ + pins = "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio34"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 12: Enable 35: Firmware */ + pins = "gpio12", "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio35"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 12: Enable 35: Firmware */ + pins = "gpio12", "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio35"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + + nfc_clk_req_active: nfc_clk_req_active { + /* active state */ + mux { + /* GPIO 31: NFC CLOCK REQUEST */ + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_clk_req_suspend: nfc_clk_req_suspend { + /* sleep state */ + mux { + /* GPIO 31: NFC CLOCK REQUEST */ + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + /* SE 1 pin mappings */ + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup01"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 2 pin mappings */ + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio34", "gpio35"; + function = "qup02"; + }; + + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio34", "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio34", "gpio35"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 4 pin mappings */ + qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { + qupv3_se4_i2c_active: qupv3_se4_i2c_active { + mux { + pins = "gpio31", "gpio32"; + function = "qup04"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep { + mux { + pins = "gpio31", "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 5 pin mappings */ + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio38", "gpio39"; + function = "qup05"; + }; + + config { + pins = "gpio38", "gpio39"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio38", "gpio39"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* QUPv3_1 South_1 SE mappings */ + /* SE 6 pin mappings */ + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio59", "gpio60"; + function = "qup10"; + }; + + config { + pins = "gpio59", "gpio60"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio59", "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio59", "gpio60"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 7 pin mappings */ + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup11"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 8 pin mappings */ + qupv3_se8_i2c_pins: qupv3_se8_i2c_pins { + qupv3_se8_i2c_active: qupv3_se8_i2c_active { + mux { + pins = "gpio49", "gpio50"; + function = "qup12"; + }; + + config { + pins = "gpio49", "gpio50"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep { + mux { + pins = "gpio49", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio49", "gpio50"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 9 pin mappings */ + qupv3_se9_i2c_pins: qupv3_se9_i2c_pins { + qupv3_se9_i2c_active: qupv3_se9_i2c_active { + mux { + pins = "gpio46", "gpio47"; + function = "qup13"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep { + mux { + pins = "gpio46", "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 10 pin mappings */ + qupv3_se10_i2c_pins: qupv3_se10_i2c_pins { + qupv3_se10_i2c_active: qupv3_se10_i2c_active { + mux { + pins = "gpio53", "gpio54"; + function = "qup14"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep { + mux { + pins = "gpio53", "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + /* SE 11 pin mappings */ + qupv3_se11_i2c_pins: qupv3_se11_i2c_pins { + qupv3_se11_i2c_active: qupv3_se11_i2c_active { + mux { + pins = "gpio108", "gpio109"; + function = "qup15"; + }; + + config { + pins = "gpio108", "gpio109"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep { + mux { + pins = "gpio108", "gpio109"; + function = "gpio"; + }; + + config { + pins = "gpio108", "gpio109"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio42", "gpio43", "gpio44", + "gpio45"; + function = "qup00"; + }; + + config { + pins = "gpio42", "gpio43", "gpio44", + "gpio45"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio42", "gpio43", "gpio44", + "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio42", "gpio43", "gpio44", + "gpio45"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "qup01"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", + "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37"; + function = "qup02"; + }; + + config { + pins = "gpio34", "gpio35", "gpio36", + "gpio37"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio34", "gpio35", "gpio36", + "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio34", "gpio35", "gpio36", + "gpio37"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se4_spi_pins: qupv3_se4_spi_pins { + qupv3_se4_spi_active: qupv3_se4_spi_active { + mux { + pins = "gpio31", "gpio32", "gpio29", + "gpio30"; + function = "qup04"; + }; + + config { + pins = "gpio31", "gpio32", "gpio29", + "gpio30"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se4_spi_sleep: qupv3_se4_spi_sleep { + mux { + pins = "gpio31", "gpio32", "gpio29", + "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32", "gpio29", + "gpio30"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio38", "gpio39", "gpio40", + "gpio41"; + function = "qup05"; + }; + + config { + pins = "gpio38", "gpio39", "gpio40", + "gpio41"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio38", "gpio39", "gpio40", + "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio38", "gpio39", "gpio40", + "gpio41"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio59", "gpio60", "gpio61", + "gpio62"; + function = "qup10"; + }; + + config { + pins = "gpio59", "gpio60", "gpio61", + "gpio62"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio59", "gpio60", "gpio61", + "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio59", "gpio60", "gpio61", + "gpio62"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se7_spi_pins: qupv3_se7_spi_pins { + qupv3_se7_spi_active: qupv3_se7_spi_active { + mux { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + function = "qup11"; + }; + + config { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se7_spi_sleep: qupv3_se7_spi_sleep { + mux { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7", "gpio8", + "gpio9"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se8_spi_pins: qupv3_se8_spi_pins { + qupv3_se8_spi_active: qupv3_se8_spi_active { + mux { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + function = "qup12"; + }; + + config { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se8_spi_sleep: qupv3_se8_spi_sleep { + mux { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se9_spi_pins: qupv3_se9_spi_pins { + qupv3_se9_spi_active: qupv3_se9_spi_active { + mux { + pins = "gpio46", "gpio47", "gpio48", + "gpio63"; + function = "qup13"; + }; + + config { + pins = "gpio46", "gpio47", "gpio48", + "gpio63"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se9_spi_sleep: qupv3_se9_spi_sleep { + mux { + pins = "gpio46", "gpio47", "gpio48", + "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio46", "gpio47", "gpio48", + "gpio63"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se10_spi_pins: qupv3_se10_spi_pins { + qupv3_se10_spi_active: qupv3_se10_spi_active { + mux { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + function = "qup14"; + }; + + config { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se10_spi_sleep: qupv3_se10_spi_sleep { + mux { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se11_spi_pins: qupv3_se11_spi_pins { + qupv3_se11_spi_active: qupv3_se11_spi_active { + mux { + pins = "gpio108", "gpio109", "gpio112", + "gpio113"; + function = "qup15"; + }; + + config { + pins = "gpio108", "gpio109", "gpio112", + "gpio113"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se11_spi_sleep: qupv3_se11_spi_sleep { + mux { + pins = "gpio108", "gpio109", "gpio112", + "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio108", "gpio109", "gpio112", + "gpio113"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + pmx_ts_release: pmx_ts_release { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te1_active: sde_te1_active { + mux { + pins = "gpio11"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te1_suspend: sde_te1_suspend { + mux { + pins = "gpio11"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_susppend { + mux { + pins = "gpio114"; + function = ""; + }; + + config { + pins = "gpio114"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active { + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-disable; + drive-strenght = <16>; + }; + }; + + pm8008_interrupt: pm8008_interrupt { + mux { + pins = "gpio145"; + function = "gpio"; + }; + + config { + pins = "gpio145"; + bias-disable; + input-enable; + }; + }; + + pm8008_active: pm8008_active { + mux { + pins = "gpio144"; + function = "gpio"; + }; + + config { + pins = "gpio144"; + bias-pull-up; + output-high; + drive-strength = <2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-pm.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a7d72b4ef6ef8c3db7e112f9c67a30f9500a2a12 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-pm.dtsi @@ -0,0 +1,164 @@ +&soc { + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + #address-cells = <1>; + #size-cells = <0>; + + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "L3"; + qcom,clstr-tmr-add = <1000>; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xfff>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "l3-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <660>; + qcom,exit-latency-us = <600>; + qcom,min-residency-us = <1260>; + }; + + qcom,pm-cluster-level@1 { /* D4 */ + reg = <1>; + label = "l3-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <2752>; + qcom,exit-latency-us = <3048>; + qcom,min-residency-us = <6118>; + qcom,min-child-idx = <2>; + qcom,is-reset; + }; + + qcom,pm-cluster-level@2 { /* Cx Off */ + reg = <2>; + label = "cx-off"; + qcom,psci-mode = <0x224>; + qcom,entry-latency-us = <3638>; + qcom,exit-latency-us = <4562>; + qcom,min-residency-us = <8467>; + qcom,min-child-idx = <2>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cluster-level@3 { /* LLCC off, AOSS sleep */ + reg = <3>; + label = "llcc-off"; + qcom,psci-mode = <0xC24>; + qcom,entry-latency-us = <3263>; + qcom,exit-latency-us = <6562>; + qcom,min-residency-us = <9826>; + qcom,min-child-idx = <2>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,ref-stddev = <500>; + qcom,tmr-add = <1000>; + qcom,ref-premature-cnt = <1>; + qcom,disable-ipi-prediction; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 + &CPU5>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <61>; + qcom,exit-latency-us = <60>; + qcom,min-residency-us = <121>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <549>; + qcom,exit-latency-us = <901>; + qcom,min-residency-us = <1774>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <702>; + qcom,exit-latency-us = <915>; + qcom,min-residency-us = <4001>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + + qcom,pm-cpu@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <55>; + qcom,exit-latency-us = <66>; + qcom,min-residency-us = <121>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <523>; + qcom,exit-latency-us = <1244>; + qcom,min-residency-us = <2207>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,entry-latency-us = <526>; + qcom,exit-latency-us = <1854>; + qcom,min-residency-us = <5555>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + + qcom,rpm-stats@c300000 { + compatible = "qcom,rpm-stats"; + reg = <0xc300000 0x1000>, <0xc3f0004 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + qcom,num-records = <3>; + }; + + qcom,ddr-stats@c3f001c { + compatible = "qcom,ddr-stats"; + reg = <0xc300000 0x1000>, <0xc3f001c 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; + + qcom,rpmh-master-stats@b221200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb221200 0x60>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-pmic-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-pmic-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..765e4c2dc0d82ee38eb3fa5d2609721613b21aeb --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-pmic-overlay.dtsi @@ -0,0 +1,583 @@ +#include "pm8150.dtsi" +#include "pm7250b.dtsi" +#include "pm8150l.dtsi" +#include + +&pm8150_clkdiv { + /delete-property/ clocks; + clocks = <&rpmhcc RPMH_CXO_CLK>; +}; + +&pm8150_gpios { + /*interrupts = <0x0 0xc3 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150_gpio4"; + qcom,gpios-disallowed = <1 2 3 5 8 9 10>;*/ + interrupts = <0x0 0xc0 0x0 IRQ_TYPE_NONE>, + <0x0 0xc2 0x0 IRQ_TYPE_NONE>, + <0x0 0xc5 0x0 IRQ_TYPE_NONE>, + <0x0 0xc6 0x0 IRQ_TYPE_NONE>, + <0x0 0xc8 0x0 IRQ_TYPE_NONE>, + <0x0 0xc9 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150_gpio1", "pm8150_gpio3", + "pm8150_gpio6", "pm8150_gpio7", + "pm8150_gpio9", "pm8150_gpio10"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <2 4 5 8>; + goodix_fp{ + fp_vdd_init: fp_vdd_init { + pins = "gpio7"; + function = "normal"; + power-source = <1>; + bias-pull-up; + output-high; + }; + + fp_vdd_dis_init: fp_vdd_dis_init { + pins = "gpio7"; + function = "normal"; + power-source = <1>; + bias-pull-down; + output-low; + }; + + fp_1v8_init: fp_1v8_init { + pins = "gpio6"; + function = "normal"; + power-source = <1>; + bias-pull-up; + output-high; + }; + fp_1v8_dis_init: fp_1v8_dis_init { + pins = "gpio6"; + function = "normal"; + power-source = <1>; + bias-pull-down; + output-low; + }; + }; + + usb_tem1_adc_gpio { + usb_tem1_adc_gpio_default: usb_tem1_adc_gpio_default { + pins = "gpio3"; /* GPIO3 */ + function = "normal"; /* normal */ + bias-high-impedance; /* DISABLE GPIO03 for ADC*/ + bias-disable; + }; + }; +}; + +&pm8150l_gpios { + /delete-property/ qcom,gpios-disallowed; + interrupts = <0x4 0xc0 0x0 IRQ_TYPE_NONE>, + <0x4 0xc1 0x0 IRQ_TYPE_NONE>, + <0x4 0xc2 0x0 IRQ_TYPE_NONE>, + <0x4 0xc3 0x0 IRQ_TYPE_NONE>, + <0x4 0xc4 0x0 IRQ_TYPE_NONE>, + <0x4 0xc5 0x0 IRQ_TYPE_NONE>, + <0x4 0xc6 0x0 IRQ_TYPE_NONE>, + <0x4 0xc7 0x0 IRQ_TYPE_NONE>, + <0x4 0xc8 0x0 IRQ_TYPE_NONE>, + <0x4 0xc9 0x0 IRQ_TYPE_NONE>, + <0x4 0xca 0x0 IRQ_TYPE_NONE>, + <0x4 0xcb 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150l_gpio1", "pm8150l_gpio2", + "pm8150l_gpio3", "pm8150l_gpio4", + "pm8150l_gpio5", "pm8150l_gpio6", + "pm8150l_gpio7", "pm8150l_gpio8", + "pm8150l_gpio9", "pm8150l_gpio10", + "pm8150l_gpio11", "pm8150l_gpio12"; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio5"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&pm8150l_clkdiv { + /delete-property/ clocks; + clocks = <&rpmhcc RPMH_CXO_CLK>; +}; + +&pm7250b_vadc { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&bmr_w_therm_default &camera_therm_default>; + + charger_skin_therm@4d { + reg = ; + label = "charger_skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + conn_therm@4f { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bmr_w_therm@53 { + reg = ; + label = "bmr_w_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + camera_flash_therm@55 { + reg = ; + label = "camera_flash_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm7250b_gpios { + bmr_w_therm { + bmr_w_therm_default: bmr_w_therm_default { + pins = "gpio12"; + bias-high-impedance; + }; + }; + + camera_therm { + camera_therm_default: camera_therm_default { + pins = "gpio8"; + bias-high-impedance; + }; + }; + + usb2_vbus_boost { + usb2_vbus_boost_default: usb2_vbus_boost_default { + pins = "gpio7"; + function = "normal"; + output-low; + power-source = <1>; /* 1.8V input supply */ + }; + }; +}; + +&pm8150_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin@85 { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm@4c { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm1@4d { + reg = ; + label = "pa_therm1"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bmr_e_therm@4e { + reg = ; + label = "bmr_e_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + usb_tem1_adc_v { + reg = ; + label = "usb_tem1_adc_v"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm8150l_vadc { + #address-cells = <1>; + #size-cells = <0>; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + pa_therm2@4d { + reg = ; + label = "pa_therm2"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + msm_skin_therm@4e { + reg = ; + label = "msm_skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm@54 { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + usb_tem2_adc_v { + reg = ; + label = "usb_tem2_adc_v"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm7250b_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm7250b_vadc ADC_AMUX_THM1_PU2>, + <&pm7250b_vadc ADC_GPIO2_PU2>, + <&pm7250b_vadc ADC_GPIO4_PU2>; + + /* Channel nodes */ + charger_skin_therm@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + bmr_w_therm@53 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + camera_flash_therm@55 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm8150_vadc ADC_XO_THERM_PU2>, + <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>, + <&pm8150_vadc ADC_GPIO1_PU1>; + + /* Channel nodes */ + xo_therm@4c { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + bmr_e_therm@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + usb_tem1_adc@32 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&gpio7C_adc_default>; + io-channels = <&pm8150l_vadc ADC_AMUX_THM1_PU2>, + <&pm8150l_vadc ADC_AMUX_THM2_PU2>, + <&pm8150l_vadc ADC_GPIO3_PU2>, + <&pm8150l_vadc ADC_GPIO2_PU1>; + + /* Channel nodes */ + pa_therm2@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + msm_skin_therm1@4e { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm@54 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + usb_tem2_adc@33 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + skin-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_GPIO3_PU2>; + wake-capable-sensor; + }; + + charger-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + usb-tem2-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_GPIO2_PU1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + usb-tem1-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_GPIO1_PU1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_GPIO2_PU1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_GPIO4_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmw-pa3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + msm-therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + }; + + mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&pm7250b_charger { + dpdm-supply = <&usb2_phy0>; + + smb5_vbus: qcom,smb5-vbus { + regulator-name = "smb5-vbus"; + }; + + smb5_vconn: qcom,smb5-vconn { + regulator-name = "smb5-vconn"; + }; +}; + +&pm8150l_gpios { + eldo13_pin { + usb_eldo13:gpio@cb00 { + pins = "gpio12"; + function = "normal"; + qcom,drive-strength = <2>; + power-source = <0>; + bias-disable; + output-high; + }; + }; + + gpio7C_adc { + gpio7C_adc_default: gpio7C_adc_default { + pins = "gpio7"; /* GPIO07 */ + function = "normal"; /* normal */ + bias-high-impedance; /* DISABLE GPIO07 for ADC*/ + bias-disable; + }; + }; + + usb_tem2_adc_gpio { + usb_tem2_adc_gpio_default: usb_tem2_adc_gpio_default { + pins = "gpio6"; /* GPIO06 */ + function = "normal"; /* normal */ + bias-high-impedance; /* DISABLE GPIO06 for ADC*/ + bias-disable; + }; + }; +}; + +&pm7250b_pdphy { + vdd-pdphy-supply = <&pm8150_l2>; + vbus-supply = <&smb5_vbus>; + vconn-supply = <&smb5_vconn>; +}; + +&usb0 { + extcon = <&pm7250b_pdphy>, <&pm7250b_charger>, <&eud>; +}; + +&usb_qmp_dp_phy { + extcon = <&pm7250b_pdphy>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-qrd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4d994c3d044e199078969f37733695a6e6abb618 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-qrd-overlay.dts @@ -0,0 +1,15 @@ +/dts-v1/; +/plugin/; + +#include "lito-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito QRD"; + compatible = "qcom,lito-qrd", "qcom,lito", "qcom,qrd"; + qcom,msm-id = <400 0x10000>, <440 0x10000>; + qcom,board-id = <11 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/lito-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..b1c94194836394db5697a2da4c5354556e82333f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-qrd.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "lito.dtsi" +#include "lito-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito QRD"; + compatible = "qcom,lito-qrd", "qcom,lito", "qcom,qrd"; + qcom,board-id = <11 0>; +}; + +&ufsphy_mem { + vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3d9d53c4fc698b7db24ca9ac1c3f36b6b609d8f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-qrd.dtsi @@ -0,0 +1,840 @@ +#include "lito-pmic-overlay.dtsi" +#include +#include "lito-audio-overlay.dtsi" +#include "lito-thermal-overlay.dtsi" +#include "camera/lito-camera-sensor-qrd.dtsi" +#include "lito-sde-display.dtsi" + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150l_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; + + qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; + vdda_usb_ss_dp_core: vdda_usb_ss_dp_core { + compatible = "regulator-fixed"; + regulator-name = "vdd_supply"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + enable-active-high; + gpio = <&pm8150l_gpios 12 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_eldo13>; + }; +}; + +&usb_qmp_dp_phy { + vdd-supply = <&vdda_usb_ss_dp_core>; +}; + +&usb2_phy0 { + qcom,param-override-seq = <0x63 0x6c>, + <0xc8 0x70>, + <0x17 0x74>; +}; + +&sde_dp { + vdda-0p9-supply = <&vdda_usb_ss_dp_core>; +}; + +&qupv3_se7_i2c { + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + qcom,i2c-touch-active = "st,fts"; + + st_fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <9 0x2008>; + vdd-supply = <&pm8150_s4>; + avdd-supply = <&pm8150_l13>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + st,irq-gpio = <&tlmm 9 0x2008>; + st,reset-gpio = <&tlmm 8 0x00>; + st,regulator_dvdd = "vdd"; + st,regulator_avdd = "avdd"; + st,x-flip; + st,y-flip; + st,power_on_suspend; + panel = <&dsi_sw43404_amoled_cmd &dsi_sw43404_amoled_video + &dsi_sw43404_amoled_fhd_plus_cmd>; + }; +}; + +&tlmm { + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio8", "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4-lito"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-pll-supply = <&pm8150_l9>; + vdda-phy-max-microamp = <90200>; + vdda-pll-max-microamp = <19000>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150a_l7>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l9>; + qcom,vddp-ref-clk-max-microamp = <100>; + qcom,vddp-ref-clk-min-uV = <1152000>; + qcom,vddp-ref-clk-max-uV = <1200000>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm8150a_l7>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm8150_s4>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 69 GPIO_ACTIVE_HIGH>; + + status = "ok"; +}; + +&pm8150a_amoled { + status = "ok"; +}; + +&pm7250b_adc_tm { + io-channels = <&pm7250b_vadc ADC_AMUX_THM1_PU2>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_GPIO2_PU2>, + <&pm7250b_vadc ADC_GPIO4_PU2>; + + conn_therm@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm7250b_charger { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_USB_IN_V_16>, + <&pm7250b_vadc ADC_USB_IN_I>, + <&pm7250b_vadc ADC_CHG_TEMP>, + <&pm7250b_vadc ADC_DIE_TEMP>, + <&pm7250b_vadc ADC_AMUX_THM3_PU2>, + <&pm7250b_vadc ADC_SBUx>, + <&pm7250b_vadc ADC_VPH_PWR>, + <&pm7250b_vadc ADC_AMUX_THM1_PU2>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp", + "conn_temp", + "sbux_res", + "vph_voltage", + "skin_temp"; + qcom,battery-data = <&qrd_batterydata>; + qcom,sec-charger-config = <1>; + qcom,auto-recharge-soc = <98>; + qcom,step-charging-enable; + qcom,sw-jeita-enable; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + qcom,suspend-input-on-debug-batt; + qcom,fcc-stepping-enable; + qcom,fcc-step-delay-ms = <100>; + qcom,fcc-step-size-ua = <100000>; + qcom,smb-internal-pull-kohm = <0>; + qcom,en-skin-therm-mitigation; + qcom,thermal-mitigation = <8000000 7500000 7000000 6500000 6000000 + 5500000 4500000 4000000 3500000 3000000 2500000 + 2000000 1500000 1000000 500000>; +}; + +&pm7250b_qg { + status = "ok"; + io-channels = <&pm7250b_vadc ADC_BAT_THERM_PU2>, + <&pm7250b_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + qcom,qg-iterm-ma = <100>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3300>; + qcom,bass-enable; +}; + +&thermal_zones { + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm7250b_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-therm-step { + polling-delay-passive = <2000>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + skin_batt_trip0: skin-batt-trip0 { + temperature = <42000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_batt_trip1: skin-batt-trip1 { + temperature = <44000>; + hysteresis = <2000>; + type = "passive"; + }; + + skin_batt_trip2: skin-batt-trip2 { + temperature = <48000>; + hysteresis = <4000>; + type = "passive"; + }; + + modem0_skin_trip: modem0-skin-trip { + temperature = <50000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_batt_trip3: skin-batt-trip3 { + temperature = <50000>; + hysteresis = <2000>; + type = "passive"; + }; + + gold_plus_trip: gold-plus-trip { + temperature = <50000>; + hysteresis = <0>; + type = "passive"; + }; + + modem1_skin_trip: modem1-skin-trip { + temperature = <52000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_batt_trip4: skin-batt-trip4 { + temperature = <52000>; + hysteresis = <2000>; + type = "passive"; + }; + + gold_trip: gold-trip { + temperature = <52000>; + hysteresis = <0>; + type = "passive"; + }; + + cx_emer_trip: cx-emer-trip { + temperature = <54000>; + hysteresis = <6000>; + type = "passive"; + }; + + silver_trip: silver-trip { + temperature = <54000>; + hysteresis = <0>; + type = "passive"; + }; + + gpu_modem2_skin_trip: gpu-modem-skin-trip { + temperature = <56000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + + cooling-maps { + skin_cpu7 { + trip = <&gold_plus_trip>; + /* throttle from fmax to 1516800KHz */ + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu6 { + trip = <&gold_trip>; + /* throttle from fmax to 1478400KHz */ + cooling-device = + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-3)>; + }; + + skin_cpu0 { + trip = <&silver_trip>; + /* throttle from fmax to 1459200KHz */ + cooling-device = <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-5)>; + }; + + skin_gpu { + trip = <&gpu_modem2_skin_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + skin_modem_pa1 { + trip = <&modem0_skin_trip>; + cooling-device = <&modem_pa 1 1>; + }; + + skin_modem_pa2 { + trip = <&modem1_skin_trip>; + cooling-device = <&modem_pa 2 2>; + }; + + skin_modem_pa3 { + trip = <&gpu_modem2_skin_trip>; + cooling-device = <&modem_pa 3 3>; + }; + + skin_modem_pa_fr1_1 { + trip = <&modem0_skin_trip>; + cooling-device = <&modem_pa_fr1 1 1>; + }; + + skin_modem_pa_fr1_2 { + trip = <&modem1_skin_trip>; + cooling-device = <&modem_pa_fr1 2 2>; + }; + + skin_modem_pa_fr1_3 { + trip = <&gpu_modem2_skin_trip>; + cooling-device = <&modem_pa_fr1 3 3>; + }; + + skin_cdsp { + trip = <&cx_emer_trip>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + skin_npu { + trip = <&cx_emer_trip>; + cooling-device = <&msm_npu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + skin_batt_cdev0 { + trip = <&skin_batt_trip0>; + cooling-device = <&pm7250b_charger 1 1>; + }; + + skin_batt_cdev1 { + trip = <&skin_batt_trip1>; + cooling-device = <&pm7250b_charger 5 5>; + }; + + skin_batt_cdev2 { + trip = <&skin_batt_trip2>; + cooling-device = <&pm7250b_charger 7 7>; + }; + + skin_batt_cdev3 { + trip = <&skin_batt_trip3>; + cooling-device = <&pm7250b_charger 9 9>; + }; + + skin_batt_cdev4 { + trip = <&skin_batt_trip4>; + cooling-device = <&pm7250b_charger 11 11>; + }; + }; + }; + + mmw-pa1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + + trips { + mmw_pa1_trip0: mmw-pa1-trip0 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + + mmw_pa1_trip1: mmw-pa1-trip1 { + temperature = <49000>; + hysteresis = <2000>; + type = "passive"; + }; + + mmw_pa1_trip2: mmw-pa1-trip2 { + temperature = <56000>; + hysteresis = <6000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm_mmw_skin1_cdev0 { + trip = <&mmw_pa1_trip0>; + cooling-device = <&modem_mmw_skin1 1 1>; + }; + + mdm_mmw_skin1_cdev1 { + trip = <&mmw_pa1_trip1>; + cooling-device = <&modem_mmw_skin1 2 2>; + }; + + mdm_mmw_skin1_cdev2 { + trip = <&mmw_pa1_trip2>; + cooling-device = <&modem_mmw_skin1 3 3>; + }; + }; + }; + + mmw-pa3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + + trips { + mmw_pa3_trip0: mmw-pa3-trip0 { + temperature = <43000>; + hysteresis = <3000>; + type = "passive"; + }; + + mmw_pa3_trip1: mmw-pa3-trip1 { + temperature = <45000>; + hysteresis = <1000>; + type = "passive"; + }; + + mmw_pa3_trip2: mmw-pa3-trip2 { + temperature = <56000>; + hysteresis = <6000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm_mmw_skin0_cdev0 { + trip = <&mmw_pa3_trip0>; + cooling-device = <&modem_mmw_skin0 1 1>; + }; + + mdm_mmw_skin0_cdev1 { + trip = <&mmw_pa3_trip1>; + cooling-device = <&modem_mmw_skin0 2 2>; + }; + + mdm_mmw_skin0_cdev2 { + trip = <&mmw_pa3_trip2>; + cooling-device = <&modem_mmw_skin0 3 3>; + }; + }; + }; + + mmw-pa2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_adc_tm ADC_GPIO2_PU2>; + wake-capable-sensor; + + trips { + mmw_pa2_trip0: mmw-pa2-trip0 { + temperature = <43000>; + hysteresis = <3000>; + type = "passive"; + }; + + mmw_pa2_trip1: mmw-pa2-trip1 { + temperature = <46000>; + hysteresis = <2000>; + type = "passive"; + }; + + mmw_pa2_trip2: mmw-pa2-trip2 { + temperature = <56000>; + hysteresis = <6000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm_mmw_skin2_cdev0 { + trip = <&mmw_pa2_trip0>; + cooling-device = <&modem_mmw_skin2 1 1>; + }; + + mdm_mmw_skin2_cdev1 { + trip = <&mmw_pa2_trip1>; + cooling-device = <&modem_mmw_skin2 2 2>; + }; + + mdm_mmw_skin2_cdev2 { + trip = <&mmw_pa2_trip2>; + cooling-device = <&modem_mmw_skin2 3 3>; + }; + }; + }; + + msm-s-therm-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + + trips { + skin_msm_trip0: skin-msm-trip0 { + temperature = <50000>; + hysteresis = <4000>; + type = "passive"; + }; + + skin_msm_trip1: skin-msm-trip1 { + temperature = <56000>; + hysteresis = <4000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm_skin_cdev0 { + trip = <&skin_msm_trip0>; + cooling-device = <&modem_tj 1 1>; + }; + + mdm_skin_cdev1 { + trip = <&skin_msm_trip1>; + cooling-device = <&modem_tj 3 3>; + }; + }; + }; +}; + +&lito_snd { + qcom,model = "lito-qrd-snd-card"; + qcom,audio-routing = + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "TX DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "TX DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "TX SWR_ADC0", "ADC1_OUTPUT", + "TX SWR_ADC1", "ADC2_OUTPUT", + "TX SWR_ADC2", "ADC3_OUTPUT", + "TX SWR_ADC3", "ADC4_OUTPUT", + "TX SWR_DMIC0", "DMIC1_OUTPUT", + "TX SWR_DMIC1", "DMIC2_OUTPUT", + "TX SWR_DMIC2", "DMIC3_OUTPUT", + "TX SWR_DMIC3", "DMIC4_OUTPUT", + "TX SWR_DMIC4", "DMIC5_OUTPUT", + "TX SWR_DMIC5", "DMIC6_OUTPUT", + "TX SWR_DMIC6", "DMIC7_OUTPUT", + "TX SWR_DMIC7", "DMIC8_OUTPUT", + "WSA SRC0_INP", "SRC0", + "WSA_TX DEC0_INP", "TX DEC0 MUX", + "WSA_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "SpkrRight IN", "WSA_SPK2 OUT", + "VA_AIF1 CAP", "VA_SWR_CLK", + "VA_AIF2 CAP", "VA_SWR_CLK", + "VA_AIF3 CAP", "VA_SWR_CLK", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA MIC BIAS4", "Digital Mic4", + "VA MIC BIAS4", "Digital Mic5", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA DMIC4", "VA MIC BIAS4", + "VA DMIC5", "VA MIC BIAS4", + "VA SWR_ADC0", "VA_SWR_CLK", + "VA SWR_ADC1", "VA_SWR_CLK", + "VA SWR_ADC2", "VA_SWR_CLK", + "VA SWR_ADC3", "VA_SWR_CLK", + "VA SWR_MIC0", "VA_SWR_CLK", + "VA SWR_MIC1", "VA_SWR_CLK", + "VA SWR_MIC2", "VA_SWR_CLK", + "VA SWR_MIC3", "VA_SWR_CLK", + "VA SWR_MIC4", "VA_SWR_CLK", + "VA SWR_MIC5", "VA_SWR_CLK", + "VA SWR_MIC6", "VA_SWR_CLK", + "VA SWR_MIC7", "VA_SWR_CLK", + "VA SWR_ADC1", "ADC2_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC0", "DMIC1_OUTPUT", + "VA SWR_MIC1", "DMIC2_OUTPUT", + "VA SWR_MIC2", "DMIC3_OUTPUT", + "VA SWR_MIC3", "DMIC4_OUTPUT", + "VA SWR_MIC4", "DMIC5_OUTPUT", + "VA SWR_MIC5", "DMIC6_OUTPUT", + "VA SWR_MIC6", "DMIC7_OUTPUT", + "VA SWR_MIC7", "DMIC8_OUTPUT"; + qcom,wsa-max-devs = <0>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&dsi_sw43404_amoled_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,mdss-brightness-max-level = <255>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_sw43404_amoled_video>; +}; + +&qupv3_se0_i2c { + status = "ok"; + qcom,clk-freq-out = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 34 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 35 0x00>; + qcom,nq-clkreq = <&tlmm 31 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <34 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,platform-reset-gpio = <&pm8150l_gpios 3 0>; +}; + +&pm7250b_gpios { + smb_stat { + smb_stat_default: smb_stat_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + qcom,pull-up-strength = ; + power-source = <0>; + }; + }; +}; + +&qupv3_se9_i2c { + status = "ok"; + #include "smb1390.dtsi" +}; + +&smb1390 { + /delete-property/ interrupts; + interrupts = <0x2 0xc5 0x0 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + compatible = "qcom,smb1390-charger-psy"; + io-channels = <&pm7250b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + qcom,parallel-input-mode = <1>; /* USBIN */ + qcom,parallel-output-mode = <2>; /* VBAT */ + qcom,min-ilim-ua = <750000>; + status = "ok"; +}; + +&smb1390_slave { + status = "ok"; +}; + +&smb1390_slave_charger { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-qupv3.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-qupv3.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..3fac774259a576bf81663723368ebf199c2311a1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-qupv3.dtsi @@ -0,0 +1,603 @@ +#include + +&soc { + /* QUPv3 North Instances + * North 0 : SE 0 + * North 1 : SE 1 + * North 2 : SE 2 + * North 4 : SE 4 + * North 5 : SE 5 + */ + + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + iommus = <&apps_smmu 0x4e3 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "atomic"; + }; + + /* Debug UART Instance for RUMI platform */ + qupv3_se2_2uart: qcom,qup_uart@888000 { + compatible = "qcom,msm-geni-console"; + reg = <0x888000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_2uart_active>; + pinctrl-1 = <&qupv3_se2_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* 4-wire UART */ + qupv3_se5_4uart: qcom,qup_uart@894000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x894000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_ctsrx>, <&qupv3_se5_rts>, + <&qupv3_se5_tx>; + pinctrl-1 = <&qupv3_se5_ctsrx>, <&qupv3_se5_rts>, + <&qupv3_se5_tx>; + interrupts-extended = <&intc GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 41 IRQ_TYPE_LEVEL_HIGH>; + qcom,wrapper-core = <&qupv3_0>; + qcom,wakeup-byte = <0xFD>; + status = "disabled"; + }; + + /* QUPV3_0_SE0 */ + i3c0: i3c-master@880000 { + compatible = "qcom,geni-i3c"; + reg = <0x880000 0x4000>, + <0xec30000 0x10000>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i3c_active>; + pinctrl-1 = <&qupv3_se0_i3c_sleep>; + interrupts = ; + #address-cells = <3>; + #size-cells = <0>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* I2C */ + qupv3_se0_i2c: i2c@880000 { + compatible = "qcom,i2c-geni"; + reg = <0x880000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se1_i2c: i2c@884000 { + compatible = "qcom,i2c-geni"; + reg = <0x884000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@888000 { + compatible = "qcom,i2c-geni"; + reg = <0x888000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se4_i2c: i2c@890000 { + compatible = "qcom,i2c-geni"; + reg = <0x890000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 4 3 64 0>, + <&gpi_dma0 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_i2c_active>; + pinctrl-1 = <&qupv3_se4_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se5_i2c: i2c@894000 { + compatible = "qcom,i2c-geni"; + reg = <0x894000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + dmas = <&gpi_dma0 0 5 3 64 0>, + <&gpi_dma0 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_i2c_active>; + pinctrl-1 = <&qupv3_se5_i2c_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se0_spi: spi@880000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x880000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se1_spi: spi@884000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x884000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_spi_active>; + pinctrl-1 = <&qupv3_se1_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se2_spi: spi@888000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x888000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_spi_active>; + pinctrl-1 = <&qupv3_se2_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se4_spi: spi@890000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x890000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_spi_active>; + pinctrl-1 = <&qupv3_se4_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 4 1 64 0>, + <&gpi_dma0 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se5_spi: spi@894000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x894000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_spi_active>; + pinctrl-1 = <&qupv3_se5_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + /* QUPv3 South_1 Instances + * South_1 0 : SE 6 + * South_1 1 : SE 7 + * South_1 2 : SE 8 + * South_1 3 : SE 9 + * South_1 4 : SE 10 + * South_1 5 : SE 11 + */ + qupv3_1: qcom,qupv3_1_geni_se@9c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x9c0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + iommus = <&apps_smmu 0x023 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "atomic"; + }; + + /* 2-wire UART */ + qupv3_se8_2uart: qcom,qup_uart@988000 { + compatible = "qcom,msm-geni-console"; + reg = <0x988000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_2uart_active>; + pinctrl-1 = <&qupv3_se8_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* QUPV3_1_SE0 */ + i3c1: i3c-master@980000 { + compatible = "qcom,geni-i3c"; + reg = <0x980000 0x4000>, + <0xec40000 0x10000>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i3c_active>; + pinctrl-1 = <&qupv3_se6_i3c_sleep>; + interrupts = ; + #address-cells = <3>; + #size-cells = <0>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* I2C */ + qupv3_se6_i2c: i2c@980000 { + compatible = "qcom,i2c-geni"; + reg = <0x980000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 0 3 64 0>, + <&gpi_dma1 1 0 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_i2c_active>; + pinctrl-1 = <&qupv3_se6_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se7_i2c: i2c@984000 { + compatible = "qcom,i2c-geni"; + reg = <0x984000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 1 3 64 0>, + <&gpi_dma1 1 1 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_i2c_active>; + pinctrl-1 = <&qupv3_se7_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se8_i2c: i2c@988000 { + compatible = "qcom,i2c-geni"; + reg = <0x988000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 2 3 64 0>, + <&gpi_dma1 1 2 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_i2c_active>; + pinctrl-1 = <&qupv3_se8_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se9_i2c: i2c@98c000 { + compatible = "qcom,i2c-geni"; + reg = <0x98c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 3 3 64 0>, + <&gpi_dma1 1 3 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_i2c_active>; + pinctrl-1 = <&qupv3_se9_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + qcom,shared; + status = "disabled"; + }; + + qupv3_se10_i2c: i2c@990000 { + compatible = "qcom,i2c-geni"; + reg = <0x990000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 4 3 64 0>, + <&gpi_dma1 1 4 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_i2c_active>; + pinctrl-1 = <&qupv3_se10_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + qupv3_se11_i2c: i2c@994000 { + compatible = "qcom,i2c-geni"; + reg = <0x994000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 5 3 64 0>, + <&gpi_dma1 1 5 3 64 0>; + dma-names = "tx", "rx"; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_i2c_active>; + pinctrl-1 = <&qupv3_se11_i2c_sleep>; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* SPI */ + qupv3_se6_spi: spi@980000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x980000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se6_spi_active>; + pinctrl-1 = <&qupv3_se6_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 0 1 64 0>, + <&gpi_dma1 1 0 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se7_spi: spi@984000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x984000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se7_spi_active>; + pinctrl-1 = <&qupv3_se7_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 1 1 64 0>, + <&gpi_dma1 1 1 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se8_spi: spi@988000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x988000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se8_spi_active>; + pinctrl-1 = <&qupv3_se8_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 2 1 64 0>, + <&gpi_dma1 1 2 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se9_spi: spi@98c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x98c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se9_spi_active>; + pinctrl-1 = <&qupv3_se9_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 3 1 64 0>, + <&gpi_dma1 1 3 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se10_spi: spi@990000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x990000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se10_spi_active>; + pinctrl-1 = <&qupv3_se10_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 4 1 64 0>, + <&gpi_dma1 1 4 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se11_spi: spi@994000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x994000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se11_spi_active>; + pinctrl-1 = <&qupv3_se11_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 5 1 64 0>, + <&gpi_dma1 1 5 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-regulators.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-regulators.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ed597ddc6575cf2991fda1027aad8d235787b2b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-regulators.dtsi @@ -0,0 +1,807 @@ +#include + +&apps_rsc { + /* PM8150 S1 + S9 + s10 = VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "cx.lvl"; + VDD_CX_LEVEL: S1A_LEVEL: + pm8150_s1_level: regulator-pm8150-s1-level { + regulator-name = "pm8150_s1_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + VDD_CX_LEVEL_AO: S1A_LEVEL_AO: + pm8150_s1_level_ao: regulator-pm8150-s1-level-ao { + regulator-name = "pm8150_s1_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + }; + + rpmh-regulator-smpa4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa4"; + qcom,regulator-type = "pmic5-hfsmps"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + S4A: pm8150_s4: regulator-pm8150-s4 { + regulator-name = "pm8150_s4"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + }; + }; + + rpmh-regulator-smpa5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa5"; + S5A: pm8150_s5: regulator-pm8150-s5 { + regulator-name = "pm8150_s5"; + qcom,set = ; + regulator-min-microvolt = <1664000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1664000>; + }; + }; + + rpmh-regulator-smpa6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpa6"; + S6A: pm8150_s6: regulator-pm8150-s6 { + regulator-name = "pm8150_s6"; + qcom,set = ; + regulator-min-microvolt = <408000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <408000>; + }; + }; + + /* PM8150 S8 + S7 = VDD_MODEM supply */ + rpmh-regulator-msslvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "mss.lvl"; + VDD_MSS_LEVEL: S8A_LEVEL: + pm8150_s8_level: regulator-pm8150-s8 { + regulator-name = "pm8150_s8_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L1A: pm8150_l1: regulator-pm8150-l1 { + regulator-name = "pm8150_l1"; + qcom,set = ; + regulator-min-microvolt = <352000>; + regulator-max-microvolt = <952000>; + qcom,init-voltage = <352000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L2A: pm8150_l2: regulator-pm8150-l2 { + regulator-name = "pm8150_l2"; + qcom,set = ; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2700000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3A: pm8150_l3: regulator-pm8150-l3 { + regulator-name = "pm8150_l3"; + qcom,set = ; + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <824000>; + qcom,init-voltage = <312000>; + qcom,init-mode = ; + }; + }; + + /* PM8150 L4 = VDD_LPI_MX supply */ + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "lmx.lvl"; + L4A_LEVEL: pm8150_l4_level: regulator-pm8150-l4-level { + regulator-name = "pm8150_l4_level"; + qcom,set = ; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8150_l5>; + L5A: pm8150_l5: regulator-pm8150-l5 { + regulator-name = "pm8150_l5"; + qcom,set = ; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1056000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <23800>; + qcom,init-voltage = <720000>; + qcom,init-mode = ; + }; + + L5A_AO: pm8150_l5_ao: regulator-pm8150-l5-ao { + regulator-name = "pm8150_l5_ao"; + qcom,set = ; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1056000>; + qcom,init-voltage = <720000>; + qcom,init-mode = ; + }; + + regulator-pm8150-l5-so { + regulator-name = "pm8150_l5_so"; + qcom,set = ; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1056000>; + qcom,init-voltage = <720000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L6A: pm8150_l6: regulator-pm8150-l6 { + regulator-name = "pm8150_l6"; + qcom,set = ; + regulator-min-microvolt = <1096000>; + regulator-max-microvolt = <1248000>; + qcom,init-voltage = <1096000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7A: pm8150_l7: regulator-pm8150-l7 { + regulator-name = "pm8150_l7"; + qcom,set = ; + regulator-min-microvolt = <1648000>; + regulator-max-microvolt = <1904000>; + qcom,init-voltage = <1648000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L8A: pm8150_l8: regulator-pm8150-l8 { + regulator-name = "pm8150_l8"; + qcom,set = ; + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <824000>; + qcom,init-voltage = <720000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8150_l9>; + L9A: pm8150_l9: regulator-pm8150-l9 { + regulator-name = "pm8150_l9"; + qcom,set = ; + regulator-min-microvolt = <1152000>; + regulator-max-microvolt = <1320000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <51800>; + qcom,init-voltage = <1152000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L10A: pm8150_l10: regulator-pm8150-l10 { + regulator-name = "pm8150_l10"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11A: pm8150_l11: regulator-pm8150-l11 { + regulator-name = "pm8150_l11"; + qcom,set = ; + regulator-min-microvolt = <696000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <696000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L12A: pm8150_l12: regulator-pm8150-l12 { + regulator-name = "pm8150_l12"; + qcom,set = ; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1890000>; + qcom,init-voltage = <1710000>; + qcom,init-mode = ; + }; + + L12A_AO: pm8150_l12_ao: regulator-pm8150-l12-ao { + regulator-name = "pm8150_l12_ao"; + qcom,set = ; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1890000>; + qcom,init-voltage = <1710000>; + qcom,init-mode = ; + }; + + L12A_SO: pm8150_l12_so: regulator-pm8150-l12-so { + regulator-name = "pm8150_l12_so"; + qcom,set = ; + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1890000>; + qcom,init-voltage = <1710000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L13A: pm8150_l13: regulator-pm8150-l13 { + regulator-name = "pm8150_l13"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L14A: pm8150_l14: regulator-pm8150-l14 { + regulator-name = "pm8150_l14"; + qcom,set = ; + regulator-min-microvolt = <1616000>; + regulator-max-microvolt = <1984000>; + qcom,init-voltage = <1616000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L15A: pm8150_l15: regulator-pm8150-l15 { + regulator-name = "pm8150_l15"; + qcom,set = ; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <1900000>; + qcom,init-voltage = <1600000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa16 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8150_l16>; + L16A: pm8150_l16: regulator-pm8150-l16 { + regulator-name = "pm8150_l16"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3304000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <857000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L17A: pm8150_l17: regulator-pm8150-l17 { + regulator-name = "pm8150_l17"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + /* PM8150 L18 = VDD_LPI_CX supply */ + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "lcx.lvl"; + L18A_LEVEL: pm8150_l18_level: regulator-pm8150-l18-level { + regulator-name = "pm8150_l18_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + lpi_cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpc2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpc2"; + S2C: pm8150a_s2: regulator-pm8150a-s2 { + regulator-name = "pm8150a_s2"; + qcom,set = ; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <600000>; + }; + }; + + /* PM8150A S3 = VDD_EBI supply */ + rpmh-regulator-ebilvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "ebi.lvl"; + S3C_LEVEL: pm8150a_s3_level: regulator-pm8150a-s3 { + regulator-name = "pm8150a_s3_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* PM8150A S4 + S5 = VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "mx.lvl"; + VDD_MX_LEVEL: S4C_LEVEL: + pm8150a_s4_level: regulator-pm8150a-s4-level { + regulator-name = "pm8150a_s4_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + + VDD_MX_LEVEL_AO: S4C_LEVEL_AO: + pm8150a_s4_level_ao: regulator-pm8150a-s4-level-ao { + regulator-name = "pm8150a_s4_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* PM8150A S6 = VDD_GX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + qcom,resource-name = "gfx.lvl"; + VDD_GFX_LEVEL: S6C_LEVEL: + pm8150a_s6_level: regulator-pm8150a-s6-level { + regulator-name = "pm8150a_s6_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + rpmh-regulator-smpc7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpc7"; + S7C: pm8150a_s7: regulator-pm8150a-s7 { + regulator-name = "pm8150a_s7"; + qcom,set = ; + regulator-min-microvolt = <1128000>; + regulator-max-microvolt = <1128000>; + qcom,init-voltage = <1128000>; + }; + }; + + rpmh-regulator-smpc8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "smpc8"; + S8C: pm8150a_s8: regulator-pm8150a-s8 { + regulator-name = "pm8150a_s8"; + qcom,set = ; + regulator-min-microvolt = <696000>; + regulator-max-microvolt = <1416000>; + qcom,init-voltage = <696000>; + }; + }; + + rpmh-regulator-ldoc1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc1"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8150a_l1>; + L1C: pm8150a_l1: regulator-pm8150a-l1 { + regulator-name = "pm8150a_l1"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1896000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <62000>; + qcom,init-voltage = <1800000>; + //qcom,init-mode = ; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc2 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc2"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L2C: pm8150a_l2: regulator-pm8150a-l2 { + regulator-name = "pm8150a_l2"; + qcom,set = ; + regulator-min-microvolt = <1144000>; + regulator-max-microvolt = <1328000>; + qcom,init-voltage = <1144000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc3 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc3"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L3C: pm8150a_l3: regulator-pm8150a-l3 { + regulator-name = "pm8150a_l3"; + qcom,set = ; + regulator-min-microvolt = <1136000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1136000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc4 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc4"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L4C: pm8150a_l4: regulator-pm8150a-l4 { + regulator-name = "pm8150a_l4"; + qcom,set = ; + regulator-min-microvolt = <1712000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <1712000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc5 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc5"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L5C: pm8150a_l5: regulator-pm8150a-l5 { + regulator-name = "pm8150a_l5"; + qcom,set = ; + regulator-min-microvolt = <1712000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <1712000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc6 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc6"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L6C: pm8150a_l6: regulator-pm8150a-l6 { + regulator-name = "pm8150a_l6"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc7 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc7"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L7C: pm8150a_l7: regulator-pm8150a-l7 { + regulator-name = "pm8150a_l7"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc8 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc8"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L8C: pm8150a_l8: regulator-pm8150a-l8 { + regulator-name = "pm8150a_l8"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <1952000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc9 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc9"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + L9C: pm8150a_l9: regulator-pm8150a-l9 { + regulator-name = "pm8150a_l9"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <3304000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc10 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc10"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L10C: pm8150a_l10: regulator-pm8150a-l10 { + regulator-name = "pm8150a_l10"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoc11 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "ldoc11"; + qcom,regulator-type = "pmic5-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + L11C: pm8150a_l11: regulator-pm8150a-l11 { + regulator-name = "pm8150a_l11"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-bobc1 { + compatible = "qcom,rpmh-vrm-regulator"; + qcom,resource-name = "bobc1"; + qcom,regulator-type = "pmic5-bob"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1000000 2000000>; + qcom,send-defaults; + + BOB: pm8150a_bob: regulator-pm8150a-bob { + regulator-name = "pm8150a_bob"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = ; + }; + + BOB_AO: pm8150a_bob_ao: regulator-pm8150a-bob-ao { + regulator-name = "pm8150a_bob_ao"; + qcom,set = ; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + qcom,init-voltage = <3008000>; + qcom,init-mode = ; + }; + }; +}; + +&soc { + refgen: refgen-regulator@ff1000 { + compatible = "qcom,refgen-kona-regulator"; + reg = <0xff1000 0x84>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + proxy-supply = <&refgen>; + qcom,proxy-consumer-enable; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-rumi-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..6e4bbd4851e68f79af69a7ad1c8e6c0fa16ce0c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-rumi-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito RUMI"; + compatible = "qcom,lito-rumi", "qcom,lito", "qcom,rumi"; + qcom,msm-id = <400 0x10000>; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-rumi.dts b/arch/arm64/boot/dts/vendor/qcom/lito-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..bc3b6b1d1817a755b1f0f646e977650b7ae7cd6e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-rumi.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/memreserve/ 0x90000000 0x00000100; + +#include "lito.dtsi" +#include "lito-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito RUMI"; + compatible = "qcom,lito-rumi", "qcom,lito", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-rumi.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a9934b1bb0fced9399ee7cf3dd8340df48299a59 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-rumi.dtsi @@ -0,0 +1,162 @@ +&soc { + timer { + clock-frequency = <500000>; + }; + + timer@17c20000 { + clock-frequency = <500000>; + }; + + usb_emu_phy: usb_emu_phy@a720000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x0a720000 0x9500>, + <0x0a6f8800 0x100>; + reg-names = "base", "qscratch_base"; + + qcom,emu-init-seq = <0xfff0 0x4 + 0xfff3 0x4 + 0x40 0x4 + 0xfff3 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x1a0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; + + cxo: bi_tcxo { + compatible = "fixed-factor-clock"; + clocks = <&xo_board>; + clock-mult = <1>; + clock-div = <2>; + #clock-cells = <0>; + }; + + cxo_a: bi_tcxo_ao { + compatible = "fixed-factor-clock"; + clocks = <&xo_board>; + clock-mult = <1>; + clock-div = <2>; + #clock-cells = <0>; + }; +}; + +&rpmhcc { + compatible = "qcom,dummycc"; + clock-output-names = "rpmh_clocks"; +}; + +&aopcc { + compatible = "qcom,dummycc"; + clock-output-names = "qdss_clocks"; +}; + +&usb0 { + dwc3@a600000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&usb2_phy0 { + hsphy@88e3000 { + status = "disabled"; + }; +}; + +&qupv3_se8_2uart { + status = "disabled"; +}; + +/*RUMI UART console*/ +&qupv3_se2_2uart { + status = "ok"; +}; + +&wdog { + status = "disabled"; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qrbtc-sdm845"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-pll-supply = <&pm8150_l6>; + vdda-phy-max-microamp = <90200>; + vdda-pll-max-microamp = <19000>; + + status = "ok"; +}; + +&ufshc_mem { + limit-tx-hs-gear = <1>; + limit-rx-hs-gear = <1>; + + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150a_l7>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <800000>; + vccq2-max-microamp = <800000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l6>; + qcom,vddp-ref-clk-max-microamp = <100>; + + qcom,disable-lpm; + rpm-level = <0>; + spm-level = <0>; + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm8150a_l7>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm8150_s4>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8150a_l9>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&pm8150a_l6>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&qupv3_se9_i2c { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..758e30c2c4b197ecf41e8a3abcf5240ecdc1e6a5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-sde-display.dtsi @@ -0,0 +1,811 @@ +#include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi" +#include "dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi" +#include "dsi-panel-sharp-dualdsi-wqhd-video.dtsi" +#include "dsi-panel-sharp-dualdsi-wqhd-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-sharp-qsync-wqhd-cmd.dtsi" +#include "dsi-panel-sharp-qsync-wqhd-video.dtsi" +#include "dsi-panel-sharp-qsync-fhd-cmd.dtsi" +#include "dsi-panel-sharp-qsync-fhd-video.dtsi" +#include "dsi-panel-sharp-dsc-4k-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-sim-sec-hd-cmd.dtsi" +#include "dsi-panel-rm69299-visionox-fhd-plus-video.dtsi" +#include "dsi-panel-samsung_ams644vk04_fhd_dsc.dtsi" +#include "dsi-panel-samsung_ams644vk04_ana6705_fhd_dsc.dtsi" +#include "dsi-panel-samsung_sofef00_m_video.dtsi" +#include "dsi-panel-r66451-dsc-fhd-plus-144hz-cmd.dtsi" +#include + +&pm8150l_gpios { + disp_pins { + disp_pins_default: disp_pins_default { + pins = "gpio3"; + function = "func1"; + qcom,drive-strength = <2>; + power-source = <0>; + bias-disable; + output-low; + }; + }; +}; + +&soc { + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; + + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + + }; + + dsi_panel_pwr_supply_samsung: dsi_panel_pwr_supply_samsung { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vout"; + qcom,supply-min-voltage = <1280000>; + qcom,supply-max-voltage = <1280000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <20>; + }; + + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + + }; + + + dsi_panel_pwr_supply_avdd: dsi_panel_pwr_supply_avdd { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "avdd"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + sde_dsi: qcom,dsi-display-primary { + compatible = "qcom,dsi-display"; + label = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi0_pll BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll PCLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_BYTECLK_SRC_0_CLK>, + <&mdss_dsi0_pll SHADOW_PCLK_SRC_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>, + <&mdss_dsi1_pll BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll PCLK_SRC_1_CLK>, + <&mdss_dsi1_pll SHADOW_BYTECLK_SRC_1_CLK>, + <&mdss_dsi1_pll SHADOW_PCLK_SRC_1_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0", + "mux_byte_clk1", "mux_pixel_clk1", + "src_byte_clk1", "src_pixel_clk1", + "shadow_byte_clk1", "shadow_pixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_te_active &disp_pins_default>; + pinctrl-1 = <&sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,panel-te-source = <0>; + + + vddio-supply = <&L1C>; + vdd-supply = <&L16A>; + vout-supply = <&L3C>; + + lab-supply = <&ab_vreg>; + ibb-supply = <&ibb_vreg>; + + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_samsung_ams644vk04_ana6705_dsc_cmd>; + }; + + sde_dsi1: qcom,dsi-display-secondary { + compatible = "qcom,dsi-display"; + label = "secondary"; + + qcom,dsi-ctrl = <&mdss_dsi0 &mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy0 &mdss_dsi_phy1>; + + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "mux_byte_clk1", "mux_pixel_clk1"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_te1_active>; + pinctrl-1 = <&sde_te1_suspend>; + + qcom,platform-te-gpio = <&tlmm 11 0>; + qcom,panel-te-source = <1>; + + + //vddio-supply = <&L1C>; + //vdd-supply = <&L16A>; + + + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_samsung_ams644vk04_ana6705_dsc_cmd>; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + msm_notifier: qcom,msm_notifier@0 { + compatible = "qcom,msm-notifier"; + panel = <&dsi_sw43404_amoled_cmd &dsi_sharp_qsync_wqhd_cmd + &dsi_dual_sim_dsc_375_cmd &dsi_sw43404_amoled_video + &dsi_sharp_qsync_wqhd_video &dsi_sharp_qsync_fhd_cmd + &dsi_sharp_qsync_fhd_video>; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pm7250b_pdphy>; + qcom,ext-disp = <&ext_disp>; + qcom,dp-aux-switch = <&fsa4480>; + extcon = <&pm7250b_pdphy>; + + qcom,usbplug-cc-gpio = <&tlmm 114 0>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_usbplug_cc_suspend>; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dsi1 &sde_dp &sde_rscc>; +}; + +&dsi_rm69299_visionox_amoled_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 20 08 08 24 23 08 + 08 05 02 04 00 1a 18]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +/* PHY TIMINGS REVISION W */ +&dsi_sw43404_amoled_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = <552424501 549895420 547366339>; + + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1e 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 13 04 04 1f 1e 05 + 05 03 02 04 00 12 14]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 11 03 04 1e 1e 04 + 04 02 02 04 00 10 14]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 180 180 180 1440 180>; + }; + }; +}; + +&dsi_sw43404_amoled_video { + qcom,dsi-supported-dfps-list = <60 57 55>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_hfp"; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <534712320 536940288 539168256>; + qcom,dsi-dyn-clk-type = "constant-fps-adjust-hfp"; + + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1f 1e 05 + 05 03 02 04 00 12 15]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sw43404_amoled_fhd_plus_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 12 04 04 1e 1e 04 + 05 02 03 04 00 11 14]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 270 270 270 1080 270>; + qcom,mdss-dsi-panel-clockrate = <380000000>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@3 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <540 40 540 40 540 40>; + qcom,partial-update-enabled = "single_roi"; + }; + + timing@4 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>, + <2 2 1>; + qcom,default-topology-index = <1>; + qcom,panel-roi-alignment = <360 40 360 40 360 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 02 04 00 18 17]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 07 + 07 05 02 04 00 18 17]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { /* 5k */ + qcom,mdss-dsi-panel-phy-timings = [00 46 13 14 33 30 12 + 14 0e 02 04 00 37 22]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_sec_hd_cmd { + qcom,ulps-enabled; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,panel-roi-alignment = <720 40 720 40 720 40>; + qcom,partial-update-enabled = "single_roi"; + }; + }; +}; + +&dsi_dual_sharp_wqhd_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1b 07 06 22 21 + 07 07 04 02 04 00 17 16]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sharp_wqhd_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1b 07 06 22 21 + 07 07 04 02 04 00 17 16]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,ulps-enabled; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_4k_dsc_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 08 + 08 05 02 04 00 19 18]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-supported-dfps-list = <60 55 48>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-select-sec-clocks = "mux_byte_clk1", "mux_pixel_clk1"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1e 08 07 24 22 + 08 08 05 02 04 00 19 17]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_qsync_wqhd_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { /* WQHD 60FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0b 03 02 1d 1c 03 + 03 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 8 8 8 1440 8>; + }; + + timing@1 { /* WQHD 60FPS VID */ + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1f 06 + 06 03 02 04 00 13 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@2 { /* FHD 60FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0a 01 02 1b 1c 02 + 02 00 02 04 00 0a 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + + timing@3 { /* WQHD 90FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 10 03 03 1e 1e 04 + 04 02 02 04 00 0f 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 8 8 8 1440 8>; + }; + + timing@4 { /* WQHD 120FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 13 05 04 1f 1e 05 + 05 03 02 04 00 12 14]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 8 8 8 1440 8>; + }; + + timing@5 { /* WQHD 120FPS VID */ + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1f 06 + 06 03 02 04 00 13 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + + timing@6 { /* FHD 120FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0e 03 03 1e 1d 04 + 04 02 02 04 00 0e 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + + timing@7 { /* FHD 90FPS CMD */ + qcom,mdss-dsi-panel-phy-timings = [00 0b 02 02 1c 1c 03 + 02 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + }; +}; + + +&dsi_sharp_qsync_wqhd_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-supported-dfps-list = <120 90 60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-min-refresh-rate = <60>; + qcom,mdss-dsi-max-refresh-rate = <120>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 16 06 05 20 1f 06 + 06 03 02 04 00 13 15]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_qsync_fhd_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-supported-dfps-list = <120 90 60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-min-refresh-rate = <60>; + qcom,mdss-dsi-max-refresh-rate = <120>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 13 04 04 1f 1f 04 + 05 03 02 04 00 12 14]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_qsync_fhd_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 0a 01 02 1b 1c 02 + 02 00 02 04 00 0a 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = [00 0e 03 03 1e 1d 04 + 04 02 02 04 00 0e 13]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + + timing@2 { + qcom,mdss-dsi-panel-phy-timings = [00 0b 02 02 1c 1c 03 + 02 01 02 04 00 0c 12]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <540 8 8 8 1080 8>; + }; + }; +}; + +&dsi_r66451_amoled_144hz_cmd { + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 22 09 09 19 17 09 + 09 09 02 04 00 1d 0e]; + qcom,display-topology = <2 2 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-sde-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9bbeb998eb9f6545e07ee2c1aaea6624e4d85ac1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-sde-pll.dtsi @@ -0,0 +1,67 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi0_pll { + compatible = "qcom,mdss_dsi_pll_7nm_v4_1"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94900 0x280>, + <0xae94400 0x800>, + <0xaf03000 0x8>, + <0xae94200 0x100>; + reg-names = "pll_base", "phy_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + memory-region = <&dfps_data_memory>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + }; + + mdss_dsi1_pll: qcom,mdss_dsi1_pll { + compatible = "qcom,mdss_dsi_pll_7nm_v4_1"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96900 0x280>, + <0xae96400 0x800>, + <0xaf03000 0x8>, + <0xae96200 0x100>; + reg-names = "pll_base", "phy_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + }; + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + compatible = "qcom,mdss_dp_pll_7nm_v2"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea2c0 0x8>, + <0x088ea2c8 0x4>, + <0x088ea600 0x200>, + <0x088ea6c0 0x8>, + <0x088ea6c8 0x4>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", + "ln_tx0_base", "ln_tx0_tran_base", "ln_tx0_vmode_base", + "ln_tx1_base", "ln_tx1_tran_base", "ln_tx1_vmode_base", + "gdsc_base"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", + "gcc_iface", "pipe_clk"; + clock-rate = <0>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-sde.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..34bb7ddb065626491ca40769f41a17068005555b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-sde.dtsi @@ -0,0 +1,706 @@ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp { + compatible = "qcom,sde-kms"; + reg = <0xae00000 0x84208>, + <0xaeb0000 0x2008>, + <0xaeac000 0x214>, + <0xae8f000 0x02c>, + <0xaf50000 0x038>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys", + "sid_phys", + "swfuse_phys"; + + clocks = + <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", "gcc_nrt_bus", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 0 460000000 19200000 460000000 + 200000000>; + clock-max-rate = <0 0 0 0 460000000 19200000 460000000 + 460000000>; + + /* interrupt config */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x494>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 0x2600>; + qcom,sde-ctl-size = <0x1dc>; + qcom,sde-ctl-display-pref = "primary", "none", "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 0x48000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none"; + qcom,sde-mixer-cwb-pref = "none", "none", "cwb", "cwb"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000 0x57000>; + qcom,sde-dspp-size = <0x1800>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0x1c>; + qcom,sde-dest-scaler-off = <0x800 0x1000>; + qcom,sde-dest-scaler-size = <0x800>; + + qcom,sde-wb-off = <0x66000>; + qcom,sde-wb-size = <0x2c8>; + qcom,sde-wb-xin-id = <6>; + qcom,sde-wb-id = <2>; + qcom,sde-wb-clk-ctrl = <0x2bc 16>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + + qcom,sde-pp-off = <0x71000 0x71800 0x72000 0x72800>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x1>; + qcom,sde-pp-size = <0xd4>; + qcom,sde-pp-merge-3d-id = <0x0 0x0 0x1 0x1>; + + qcom,sde-merge-3d-off = <0x84000 0x84100>; + qcom,sde-merge-3d-size = <0x100>; + + qcom,sde-te2-off = <0x2000 0x2000 0x0 0x0>; + + qcom,sde-cdm-off = <0x7a200>; + qcom,sde-cdm-size = <0x224>; + + qcom,sde-dsc-off = <0x81000 0x81400>; + qcom,sde-dsc-size = <0x140>; + qcom,sde-dsc-pair-mask = <2 1>; + + qcom,sde-dither-off = <0x30e0 0x30e0 0x30e0 + 0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "vig", + "dma", "dma", "dma"; + qcom,sde-sspp-off = <0x5000 0x7000 0x25000 0x27000 0x29000>; + qcom,sde-sspp-src-size = <0x1f8>; + qcom,sde-sspp-xin-id = <0 4 1 5 9>; + qcom,sde-sspp-excl-rect = <1 1 1 1 1>; + qcom,sde-sspp-smart-dma-priority = <4 5 1 2 3>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <2 1 4 3>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0>; + + qcom,sde-max-per-pipe-bw-kbps = <4700000 4700000 + 4700000 4700000 + 4700000>; + + qcom,sde-max-per-pipe-bw-high-kbps = <4700000 4700000 + 4700000 4700000 + 4700000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = <0x2ac 0>, <0x2b4 0>, + <0x2ac 8>, <0x2b4 8>, <0x2c4 8>; + qcom,sde-sspp-csc-off = <0x1a00>; + qcom,sde-csc-type = "csc-10bit"; + qcom,sde-qseed-type = "qseedv3lite"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2880>; + qcom,sde-vig-sspp-linewidth = <4096>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0x9>; + qcom,sde-highest-bank-bit = <0x1>; + qcom,sde-ubwc-version = <0x300>; + qcom,sde-ubwc-swizzle = <0x6>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-ubwc-static = <0x1>; + qcom,sde-macrotile-mode = <0x1>; + qcom,sde-smart-panel-align-mode = <0xc>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-pipe-order-version = <0x1>; + qcom,sde-has-dim-layer; + qcom,sde-has-dest-scaler; + qcom,sde-has-idle-pc; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <5800000>; + qcom,sde-max-bw-high-kbps = <8600000>; + qcom,sde-min-core-ib-kbps = <4800000>; + qcom,sde-min-llcc-ib-kbps = <0>; + qcom,sde-min-dram-ib-kbps = <800000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + qcom,sde-dspp-ltm-version = <0x00010000>; + /* offsets are based off dspp 0 and dspp 1 */ + qcom,sde-dspp-ltm-off = <0x2a000 0x28100>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x1040>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-nrt-remap = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-qos-cwb-remap = <3 3 4 4 5 5 6 6>; + qcom,sde-vbif-qos-lutdma-remap = <3 3 3 3 4 4 4 4>; + + /* macrotile & macrotile-qseed has the same configs */ + qcom,sde-danger-lut = <0x000000ff 0x0000ffff + 0x00000000 0x00000000 0x0000ffff>; + + qcom,sde-safe-lut-linear = <0 0xfffc>; + qcom,sde-safe-lut-macrotile = <0 0xff00>; + /* same as safe-lut-macrotile */ + qcom,sde-safe-lut-macrotile-qseed = <0 0xff00>; + qcom,sde-safe-lut-nrt = <0 0xffff>; + qcom,sde-safe-lut-cwb = <0 0x3ff>; + + /* creq LUTs */ + qcom,sde-qos-lut-linear = <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = <0 0x00112233 0x66777777>; + qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = <0 0x66666541 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + qcom,sde-qos-cpu-irq-latency = <300>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x00010002>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + qcom,sde-reg-dma-xin-id = <7>; + qcom,sde-reg-dma-clk-ctrl = <0x2bc 20>; + + qcom,sde-secure-sid-mask = <0xb41>; + + qcom,sde-sspp-vig-blocks { + qcom,sde-vig-csc-off = <0x1a00>; + qcom,sde-vig-qseed-off = <0xa00>; + qcom,sde-vig-qseed-size = <0xa0>; + qcom,sde-vig-gamut = <0x1d00 0x00060000>; + qcom,sde-vig-igc = <0x1d00 0x00060000>; + qcom,sde-vig-inverse-pma; + }; + + qcom,sde-sspp-dma-blocks { + dgm@0 { + qcom,sde-dma-igc = <0x400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x200>; + }; + + dgm@1 { + qcom,sde-dma-igc = <0x1400 0x00050000>; + qcom,sde-dma-gc = <0x600 0x00050000>; + qcom,sde-dma-inverse-pma; + qcom,sde-dma-csc-off = <0x1200>; + }; + }; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040002>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0xb40 0x402>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-earlymap; /* for cont-splash */ + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0xb41 0x0>, + <&apps_smmu 0xf41 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + + qcom,sde-limits { + qcom,sde-linewidth-limits { + qcom,sde-limit-name = "sspp_linewidth_usecases"; + qcom,sde-limit-cases = "vig", "dma", "scale", "inline_rot"; + qcom,sde-limit-ids= <0x1 0x2 0x4 0x8>; + qcom,sde-limit-values = <0x1 4096>, + <0x5 2560>, + <0x2 2880>, + <0x9 1088>; + }; + + qcom,sde-bw-limits { + qcom,sde-limit-name = "sde_bwlimit_usecases"; + qcom,sde-limit-cases = "per_vig_pipe", + "per_dma_pipe", + "total_max_bw", + "camera_concurrency", + "cwb_concurrency"; + qcom,sde-limit-ids = <0x1 0x2 0x4 0x8 0x10>; + qcom,sde-limit-values = <0x1 4700000>, + <0x11 4700000>, + <0x9 4700000>, + <0x19 4700000>, + <0x2 4700000>, + <0x12 4700000>, + <0xa 4700000>, + <0x1a 4700000>, + <0x4 8600000>, + <0x14 8600000>, + <0xc 5800000>, + <0x1c 5800000>; + }; + }; + }; + + sde_rscc: qcom,sde_rscc { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x3c50>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <3>; + + qcom,sde-dram-channels = <2>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_NON_GDSC_AHB_CLK>, + <&dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "gdsc_clk", "iface_clk"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20513 0 0>, <20004 20513 0 0>, + <20003 20513 0 6400000>, <20004 20513 0 6400000>, + <20003 20513 0 6400000>, <20004 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "disp_rsc_ebi"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20000 20512 0 0>, + <20000 20512 0 6400000>, + <20000 20512 0 6400000>; + }; + qcom,sde-reg-bus { + qcom,msm-bus,name = "disp_rsc_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + mdss_rotator: qcom,mdss_rotator { + status = "disabled"; + compatible = "qcom,sde_rotator"; + reg = <0xae00000 0xac000>, + <0xaeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x3>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <25 512 0 0>, + <25 512 0 6400000>, + <25 512 0 6400000>; + + rot-vdd-supply = <&mdss_core_gdsc>; + qcom,supply-names = "rot-vdd"; + + clocks = + <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_SF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + power-domains = <&mdss_mdp>; + + /* Offline rotator QoS setting */ + qcom,mdss-rot-vbif-qos-setting = <3 3 3 3 3 3 3 3>; + qcom,mdss-rot-vbif-memtype = <3 3>; + qcom,mdss-rot-cdp-setting = <1 1>; + qcom,mdss-rot-qos-lut = <0x0 0x0 0x0 0x0>; + qcom,mdss-rot-danger-lut = <0x0 0x0>; + qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + /* reg bus scale settings */ + rot_reg: qcom,rot-reg-bus { + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x135C 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0x135d 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi0_ctrl { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-0"; + cell-index = <0>; + frame-threshold-time-us = <1000>; + reg = <0xae94000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&L9A>; + refgen-supply = <&refgen>; + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1152000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi1_ctrl { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-1"; + frame-threshold-time-us = <1000>; + cell-index = <1>; + reg = <0xae96000 0x400>, + <0xaf08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <5 0>; + vdda-1p2-supply = <&L9A>; + refgen-supply = <&refgen>; + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", "esc_clk"; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1152000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + sde_dp: qcom,dp_display@ae90000 { + cell-index = <0>; + compatible = "qcom,dp-display"; + + vdda-1p2-supply = <&L9A>; + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae91000 0x094>, + <0x88eaa00 0x198>, + <0x88ea200 0x150>, + <0x88ea600 0x150>, + <0xaf02000 0x2c4>, + <0x88ea040 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x2a>, + <0xae91400 0x095>; + reg-names = "dp_ahb", "dp_aux", "dp_link", + "dp_p0", "dp_phy", "dp_ln_tx0", "dp_ln_tx1", + "dp_mmss_cc", "dp_pll", + "usb3_dp_com", "hdcp_physical", "dp_p1"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + clock-names = "core_aux_clk", "core_usb_pipe_clk", + "core_usb_ref_clk_src", + "link_clk", "link_iface_clk", + "pixel_clk_rcg", "pixel_parent", + "pixel1_clk_rcg", "pixel1_parent", + "strm0_pixel_clk", "strm1_pixel_clk"; + + qcom,phy-version = <0x420>; + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13]; + qcom,aux-cfg2-settings = [28 A4]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,mst-enable; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1152000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + + mdss_dsi_phy0: qcom,mdss_dsi_phy0 { + compatible = "qcom,dsi-phy-v4.1"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x800>, + <0xae94200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; + vdda-0p9-supply = <&L5A>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy1 { + compatible = "qcom,dsi-phy-v4.1"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x800>, + <0xae96200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; + vdda-0p9-supply = <&L5A>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 0a 0a + 00 00 8a 8a]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <0>; + }; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-smp2p.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-smp2p.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9a7ba151bed5dbec01bf8013e4de3f9fafc52f11 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-smp2p.dtsi @@ -0,0 +1,145 @@ +#include +#include + +&soc { + + qcom,smp2p-mpss { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + mpss_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + mpss_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_wlan_1_in: qcom,smp2p-wlan-1-in { + qcom,entry-name = "wlan"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg5_out: qcom,smp2p-rdbg5-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_in: qcom,smp2p-rdbg5-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-npu { + compatible = "qcom,smp2p"; + qcom,smem = <617>, <616>; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + mboxes = <&msm_npu IPCC_CLIENT_NPU IPCC_MPROC_SIGNAL_SMP2P>; + qcom,local-pid = <0>; + qcom,remote-pid = <10>; + + npu_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + npu_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-thermal-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-thermal-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..299d4b60946597f642a753defe4e79cdb2ca16af --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-thermal-overlay.dtsi @@ -0,0 +1,186 @@ +#include + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&thermal_zones { + pm7250b-tz { + cooling-maps { + trip0_bat { + trip = <&pm7250b_trip0>; + cooling-device = + <&pm7250b_charger (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_bat { + trip = <&pm7250b_trip1>; + cooling-device = + <&pm7250b_charger THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm8150_tz { + cooling-maps { + trip0_cpu0 { + trip = <&pm8150_trip0>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip0_cpu6 { + trip = <&pm8150_trip0>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip0_cpu7 { + trip = <&pm8150_trip0>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu1 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + trip1_cpu2 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + trip1_cpu3 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu3_isolate 1 1>; + }; + + trip1_cpu4 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu4_isolate 1 1>; + }; + + trip1_cpu5 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu5_isolate 1 1>; + }; + + trip1_cpu6 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + trip1_cpu7 { + trip = <&pm8150_trip1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + soc { + cooling-maps { + soc_cpu6 { + trip = <&soc_trip>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + soc_cpu7 { + trip = <&soc_trip>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm7250b-bcl-lvl0 { + cooling-maps { + lbat0_cpu6 { + trip = <&b_bcl_lvl0>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + lbat0_cpu7 { + trip = <&b_bcl_lvl0>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm7250b-bcl-lvl1 { + cooling-maps { + lbat1_cpu6 { + trip = <&b_bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + lbat1_cpu7 { + trip = <&b_bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm7250b-bcl-lvl2 { + cooling-maps { + lbat2_cpu6 { + trip = <&b_bcl_lvl2>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + lbat2_cpu7 { + trip = <&b_bcl_lvl2>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm8150l-bcl-lvl0 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl0>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl0>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm8150l-bcl-lvl1 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl1>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl1>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + pm8150l-bcl-lvl2 { + disable-thermal-zone; + cooling-maps { + vph_cpu6 { + trip = <&l_bcl_lvl2>; + cooling-device = <&cpu6_isolate 1 1>; + }; + + vph_cpu7 { + trip = <&l_bcl_lvl2>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-thermal.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..21b95c76275d44038f83322d7e0a8ecfa1303f50 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-thermal.dtsi @@ -0,0 +1,1307 @@ +#include +#include "sdxprairie-thermal-integrated.dtsi" + +&cpufreq_hw { + #address-cells = <1>; + #size-cells = <1>; + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + + cpu4_isolate: cpu4-isolate { + qcom,cpu = <&CPU4>; + #cooling-cells = <2>; + }; + + cpu5_isolate: cpu5-isolate { + qcom,cpu = <&CPU5>; + #cooling-cells = <2>; + }; + + cpu6_isolate: cpu6-isolate { + qcom,cpu = <&CPU6>; + #cooling-cells = <2>; + }; + + cpu7_isolate: cpu7-isolate { + qcom,cpu = <&CPU7>; + #cooling-cells = <2>; + }; + }; + + lmh_dcvs0: qcom,limits-dcvs@18358800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + reg = <0x18358800 0x1000>, + <0x18323000 0x1000>; + qcom,no-cooling-device-register; + #thermal-sensor-cells = <0>; + }; + + lmh_dcvs1: qcom,limits-dcvs@18350800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + reg = <0x18350800 0x1000>, + <0x18325800 0x1000>; + qcom,no-cooling-device-register; + #thermal-sensor-cells = <0>; + }; + + lmh_dcvs2: qcom,limits-dcvs@18327800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + reg = <0x18350800 0x1000>, + <0x18327800 0x1000>; + qcom,no-cooling-device-register; + #thermal-sensor-cells = <0>; + }; +}; + +&soc { + lmh_cpu_vdd0: qcom,lmh-cpu-vdd@18358800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0x18358800 0x1000>; + #cooling-cells = <2>; + }; + + lmh_cpu_vdd1: qcom,lmh-cpu-vdd@18350800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0x18350800 0x1000>; + #cooling-cells = <2>; + }; + + lmh_isense_cdsp { + compatible = "qcom,msm-limits-cdsp"; + }; +}; + +/{ + shell_front { + polling-delay-passive = <0>; + polling-delay = <0>; + compatible = "oneplus,shell-temp"; + }; + + shell_frame { + polling-delay-passive = <0>; + polling-delay = <0>; + compatible = "oneplus,shell-temp"; + }; + + shell_back { + polling-delay-passive = <0>; + polling-delay = <0>; + compatible = "oneplus,shell-temp"; + }; +}; + +&thermal_zones { + aoss0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-4-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-0-5-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + min-temp-0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 16>; + thermal-governor = "low_limits_floor"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_0_lowf: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lpi_cx_vdd_cdev { + trip = <&min_temp_0_lowf>; + cooling-device = <&lpi_cx_cdev 0 0>; + }; + }; + + }; + + min-temp-0-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 16>; + thermal-governor = "low_limits_cap"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_0_lowc: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu0_cdev { + trip = <&min_temp_0_lowc>; + cooling-device = <&lmh_cpu_vdd0 1 1>; + }; + + lmh_cpu6_cdev { + trip = <&min_temp_0_lowc>; + cooling-device = <&lmh_cpu_vdd1 1 1>; + }; + }; + }; + + aoss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cwlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + ddr-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + q6-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cmpss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + npu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 7>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-vec-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 8>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-scl-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 9>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-core-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 10>; + thermal-governor = "user_space"; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-core-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens1 11>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-config { + temperature = <115000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpuss-max-step { + polling-delay-passive = <10>; + polling-delay = <100>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gpu_trip0: gpu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev { + trip = <&gpu_trip0>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu-0-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + silver-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + cpu-1-max-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + gold-trip { + temperature = <120000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + cpu-0-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + cpu00_config: cpu00-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu00_cdev { + trip = <&cpu00_config>; + cooling-device = <&cpu0_isolate 1 1>; + }; + }; + }; + + cpu-0-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + cpu01_config: cpu01-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu01_cdev { + trip = <&cpu01_config>; + cooling-device = <&cpu1_isolate 1 1>; + }; + }; + }; + + cpu-0-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + cpu02_config: cpu02-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu02_cdev { + trip = <&cpu02_config>; + cooling-device = <&cpu2_isolate 1 1>; + }; + }; + }; + + cpu-0-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu03_config: cpu03-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu03_cdev { + trip = <&cpu03_config>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + cpu-0-4-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu04_config: cpu04-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu04_cdev { + trip = <&cpu04_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + }; + }; + + cpu-0-5-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu05_config: cpu05-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu05_cdev { + trip = <&cpu05_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpu-1-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu10_config: cpu10-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu10_cdev { + trip = <&cpu10_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu11_config: cpu11-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu11_cdev { + trip = <&cpu11_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + cpu-1-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu12_config: cpu12-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu12_cdev { + trip = <&cpu12_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu13_config: cpu13-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu13_cdev { + trip = <&cpu13_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + q6-hvx-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + q6_hvx_trip1: q6-hvx-trip1 { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cdsp-cdev1 { + trip = <&q6_hvx_trip1>; + cooling-device = <&msm_cdsp_rm 3 3>; + }; + + gpu-cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + modem-pa-cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&modem_pa 3 3>; + }; + + modem-tj-cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&modem_tj 3 3>; + }; + + npu_cdev { + trip = <&q6_hvx_trip1>; + cooling-device = <&msm_npu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + min-temp-1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 16>; + thermal-governor = "low_limits_floor"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_1_lowf: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lpi_cx_vdd_cdev { + trip = <&min_temp_1_lowf>; + cooling-device = <&lpi_cx_cdev 0 0>; + }; + }; + }; + + min-temp-1-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 16>; + thermal-governor = "low_limits_cap"; + wake-capable-sensor; + tracks-low; + trips { + min_temp_1_lowc: active-config0 { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu0_cdev { + trip = <&min_temp_1_lowc>; + cooling-device = <&lmh_cpu_vdd0 1 1>; + }; + + lmh_cpu6_cdev { + trip = <&min_temp_1_lowc>; + cooling-device = <&lmh_cpu_vdd1 1 1>; + }; + }; + }; + + npu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + npu_trip0: npu-trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + npu_cdev { + trip = <&npu_trip0>; + cooling-device = + <&msm_npu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + mdm-vec-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 8>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + modem_vec_trip0: modem-vec-trip0 { + temperature = <95000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_vec_trip1: modem-vec-trip1 { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_vec_trip2: modem-vec-trip2 { + temperature = <115000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj1_cdev { + trip = <&modem_vec_trip0>; + cooling-device = <&modem_tj 1 1>; + }; + + modem_tj2_cdev { + trip = <&modem_vec_trip1>; + cooling-device = <&modem_tj 2 2>; + }; + + modem_tj3_cdev { + trip = <&modem_vec_trip2>; + cooling-device = <&modem_tj 3 3>; + }; + }; + }; + + mdm-scl-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 9>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + modem_scl_trip0: modem-scl-trip0 { + temperature = <95000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_scl_trip1: modem-scl-trip1 { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_scl_trip2: modem-scl-trip2 { + temperature = <115000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj1_cdev { + trip = <&modem_scl_trip0>; + cooling-device = <&modem_tj 1 1>; + }; + + modem_tj2_cdev { + trip = <&modem_scl_trip1>; + cooling-device = <&modem_tj 2 2>; + }; + + modem_tj3_cdev { + trip = <&modem_scl_trip2>; + cooling-device = <&modem_tj 3 3>; + }; + }; + }; + + mdm-core-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 10>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + modem_core_0_trip0: modem-core-0-trip0 { + temperature = <95000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_core_0_trip1: modem-core-0-trip1 { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_core_0_trip2: modem-core-0-trip2 { + temperature = <115000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj1_cdev { + trip = <&modem_core_0_trip0>; + cooling-device = <&modem_tj 1 1>; + }; + + modem_tj2_cdev { + trip = <&modem_core_0_trip1>; + cooling-device = <&modem_tj 2 2>; + }; + + modem_tj3_cdev { + trip = <&modem_core_0_trip2>; + cooling-device = <&modem_tj 3 3>; + }; + }; + }; + + mdm-core-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 11>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + modem_core_1_trip0: modem-core-1-trip0 { + temperature = <95000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_core_1_trip1: modem-core-1-trip1 { + temperature = <105000>; + hysteresis = <15000>; + type = "passive"; + }; + + modem_core_1_trip2: modem-core-1-trip2 { + temperature = <115000>; + hysteresis = <15000>; + type = "passive"; + }; + }; + + cooling-maps { + modem_tj1_cdev { + trip = <&modem_core_1_trip0>; + cooling-device = <&modem_tj 1 1>; + }; + + modem_tj2_cdev { + trip = <&modem_core_1_trip1>; + cooling-device = <&modem_tj 2 2>; + }; + + modem_tj3_cdev { + trip = <&modem_core_1_trip2>; + cooling-device = <&modem_tj 3 3>; + }; + }; + }; + + /delete-node/ modem-mmw-pa1-usr; + /delete-node/ modem-mmw-pa2-usr; + /delete-node/ modem-mmw-pa3-usr; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-usb.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b124a58c9a88379017ba09db02eeb8d5449387c8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-usb.dtsi @@ -0,0 +1,329 @@ +#include +#include + +&soc { + /* Primary USB port related controller */ + usb0: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0xE0 0x0>; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x90000000 0x60000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts-extended = <&pdc 14 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 15 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + qcom,use-pdc-interrupts; + + USB3_GDSC-supply = <&usb30_prim_gdsc>; + qcom,gdsc-collapse-in-host-suspend; + dpdm-supply = <&usb2_phy0>; + clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,gsi-disable-io-coherency; + qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,pm-qos-latency = <61>; /* CPU0-WFI-LVL latency +1 */ + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + , + + /* min vote */ + , + , + ; + + qcom,default-bus-vote = <1>; /* use nominal bus voting */ + dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xcd00>; + interrupts = ; + usb-phy = <&usb2_phy0>, <&usb_qmp_dp_phy>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3-u1u2-disable; + xhci-imod-value = <160>; + usb-core-id = <0>; + tx-fifo-resize; + qcom,pm-qos-latency= <62>; + maximum-speed = "super-speed"; + dr_mode = "drd"; + }; + }; + + /* Primary USB port related High Speed PHY */ + usb2_phy0: hsphy@88e3000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e3000 0x110>, + <0x088e2000 0x4>; + reg-names = "hsusb_phy_base", + "eud_enable_reg"; + + vdd-supply = <&pm8150_l5>; + vdda18-supply = <&pm8150_l12>; + vdda33-supply = <&pm8150_l2>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x63 0x6c>, + <0x85 0x70>, + <0x17 0x74>; + }; + + /* Primary USB port related QMP USB DP Combo PHY */ + usb_qmp_dp_phy: ssphy@88e8000 { + compatible = "qcom,usb-ssphy-qmp-dp-combo"; + reg = <0x88e8000 0x3000>; + reg-names = "qmp_phy_base"; + + core-supply = <&pm8150_l9>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vdd-max-load-uA = <47000>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "com_aux_clk"; + + resets = <&gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "global_phy_reset", "phy_reset"; + + status = "ok"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x140f 0x0>; + qcom,iommu-dma = "disabled"; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-lcd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-lcd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..54567e93bee21b7a958322a8496f0d2c1928d769 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-lcd-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-atp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 LCD ATP"; + compatible = "qcom,lito-atp", "qcom,lito", "qcom,atp"; + qcom,msm-id = <440 0x20000>; + qcom,board-id = <33 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-lcd.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-lcd.dts new file mode 100644 index 0000000000000000000000000000000000000000..10eabb7e9b2e842aadf64cee9592a97146470aa3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-lcd.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "lito-v2.dtsi" +#include "lito-atp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 LCD ATP"; + compatible = "qcom,lito-atp", "qcom,lito", "qcom,atp"; + qcom,board-id = <33 1>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..28a384546e95bd5c00d4aeb5f097813b27f97f12 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-atp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 ATP"; + compatible = "qcom,lito-atp", "qcom,lito", "qcom,atp"; + qcom,msm-id = <400 0x20000>, <440 0x20000>; + qcom,board-id = <33 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp.dts new file mode 100644 index 0000000000000000000000000000000000000000..56fdad34842210f14941a48478b7a7cb904bd18e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-atp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "lito-v2.dtsi" +#include "lito-atp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 ATP"; + compatible = "qcom,lito-atp", "qcom,lito", "qcom,atp"; + qcom,board-id = <33 0>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-v2-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ee0dbd53a8059ef88939d126502a2e74b06b35ea --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-audio.dtsi @@ -0,0 +1,11 @@ + +&lpi_tlmm { + qcom,lpi-slew-base-tbl = <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x0355C000>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-cdp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..33c9f881521a848e22edc66009ea3852deab1e63 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-cdp-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-cdp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 CDP"; + compatible = "qcom,lito-cdp", "qcom,lito", "qcom,cdp"; + qcom,msm-id = <400 0x20000>, <440 0x20000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..09c92fd887543265c0c7ea36ac8025e0dec03daf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-cdp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "lito-v2.dtsi" +#include "lito-cdp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 CDP"; + compatible = "qcom,lito-cdp", "qcom,lito", "qcom,cdp"; + qcom,board-id = <1 0>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-mtp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d60d0667063f7a679969a846de30f557513915c1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-mtp-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "lito-mtp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 MTP"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,msm-id = <400 0x20000>, <440 0x20000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..888adca5cf363dc92c45be0b3651324b73892798 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-mtp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "lito-v2.dtsi" +#include "lito-mtp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 MTP"; + compatible = "qcom,lito-mtp", "qcom,lito", "qcom,mtp"; + qcom,board-id = <8 0>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-qrd-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-qrd-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a9cbb2b56afe5bc6224739ba33cd66e0aa2ac032 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-qrd-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include "lito-qrd.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 QRD"; + compatible = "qcom,lito-qrd", "qcom,lito", "qcom,qrd"; + qcom,msm-id = <400 0x20000>, <440 0x20000>; + qcom,board-id = <11 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..281ad0f6735e94e8368dd522264274fd6afb7c18 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2-qrd.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "lito-v2.dtsi" +#include "lito-qrd.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 QRD"; + compatible = "qcom,lito-qrd", "qcom,lito", "qcom,qrd"; + qcom,board-id = <11 0>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2.dts b/arch/arm64/boot/dts/vendor/qcom/lito-v2.dts new file mode 100644 index 0000000000000000000000000000000000000000..a3da016a653d65cb310deb32aa2895615fb8b7f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "lito-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2 SoC"; + compatible = "qcom,lito"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-v2.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-v2.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b6045c7ffd17bc99baa321eddc61012183ebc901 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-v2.dtsi @@ -0,0 +1,630 @@ +#include "lito.dtsi" +#include "camera/lito-v2-camera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito v2"; + compatible = "qcom,lito"; + qcom,msm-id = <400 0x20000>, <440 0x20000>; +}; + +&lito_snd { + qcom,lito-is-v2-enabled = <1>; +}; + +&camcc { + compatible = "qcom,lito-camcc-v2", "syscon"; +}; + +&npucc { + compatible = "qcom,lito-npucc-v2", "syscon"; +}; + +&pm8008_regulators { + vdd_l7-supply = <&BOB>; +}; + +&msm_gpu { + /delete-property/qcom,chipid; + qcom,chipid = <0x06020001>; + + /delete-node/qcom,gpu-pwrlevel-bins; + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + qcom,ca-target-pwrlevel = <4>; + qcom,initial-pwrlevel = <5>; + qcom,throttle-pwrlevel = <0>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <750000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <670000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <625000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802D5FFD>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + qcom,acd-level = <0xA02D5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0x802E5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <132>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <625000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802D5FFD>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + qcom,acd-level = <0xA02D5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0x802E5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <115>; + qcom,initial-pwrlevel = <2>; + qcom,ca-target-pwrlevel = <1>; + + /* SVS L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <540000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802D5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0x802E5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-4 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <158>; + qcom,ca-target-pwrlevel = <4>; + qcom,initial-pwrlevel = <5>; + qcom,throttle-pwrlevel = <0>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <750000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <670000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0xA02C5FFD>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <625000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802D5FFD>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + qcom,acd-level = <0xA02D5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0x802E5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-5 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <165>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <2>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <625000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + qcom,acd-level = <0x802D5FFD>; + }; + + /* SVS L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <500000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <10>; + qcom,acd-level = <0xA02D5FFD>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + qcom,acd-level = <0x802E5FFD>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <275000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + qcom,acd-level = <0x802F5FFD>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; +}; + +&cpu0_cpu_l3_latmon { + qcom,core-dev-table = + < 614400 300000000 >, + < 864000 556800000 >, + < 1075200 787200000 >, + < 1363200 940800000 >, + < 1804800 1516800000 >; +}; + +&cpu0_cpu_llcc_latmon { + qcom,core-dev-table = + < 1075200 MHZ_TO_MBPS(300, 16) >, + < 1363200 MHZ_TO_MBPS(466, 16) >, + < 1804800 MHZ_TO_MBPS(600, 16) >; +}; + +&cpu0_llcc_ddr_latmon { + qcom,core-dev-table = + < 614400 MHZ_TO_MBPS( 300, 4) >, + < 864000 MHZ_TO_MBPS( 451, 4) >, + < 1075200 MHZ_TO_MBPS( 547, 4) >, + < 1363200 MHZ_TO_MBPS( 768, 4) >, + < 1804800 MHZ_TO_MBPS(1017, 4) >; +}; + +&cpu0_computemon { + qcom,core-dev-table = + < 614400 MHZ_TO_MBPS( 300, 4) >, + < 1075200 MHZ_TO_MBPS( 451, 4) >, + < 1363200 MHZ_TO_MBPS( 547, 4) >, + < 1804800 MHZ_TO_MBPS( 768, 4) >; +}; + +&cpu6_cpu_l3_latmon { + qcom,core-dev-table = + < 940800 556800000 >, + < 1152000 787200000 >, + < 1728000 1209600000 >, + < 1900800 1382400000 >, + < 2342400 1516800000 >; +}; + +&cpu7_cpu_l3_latmon { + qcom,core-dev-table = + < 1094400 556800000 >, + < 1401600 787200000 >, + < 1996800 1209600000 >, + < 2188800 1324800000 >, + < 2707200 1516800000 >; +}; + +&cpu6_cpu_llcc_latmon { + qcom,core-dev-table = + < 652800 MHZ_TO_MBPS( 300, 16) >, + < 940800 MHZ_TO_MBPS( 466, 16) >, + < 1152000 MHZ_TO_MBPS( 600, 16) >, + < 1728000 MHZ_TO_MBPS( 806, 16) >, + < 2342400 MHZ_TO_MBPS( 933, 16) >, + < 3000000 MHZ_TO_MBPS(1066, 16) >; +}; + +&cpu6_llcc_ddr_latmon { + qcom,core-dev-table = + < 652800 MHZ_TO_MBPS( 451, 4) >, + < 940800 MHZ_TO_MBPS( 547, 4) >, + < 1152000 MHZ_TO_MBPS(1017, 4) >, + < 1728000 MHZ_TO_MBPS(1555, 4) >, + < 2342400 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; +}; + +&cpu6_computemon { + qcom,core-dev-table = + < 652800 MHZ_TO_MBPS( 300, 4) >, + < 1152000 MHZ_TO_MBPS( 547, 4) >, + < 1478400 MHZ_TO_MBPS( 768, 4) >, + < 1728000 MHZ_TO_MBPS(1017, 4) >, + < 2342400 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; +}; + +&cpu7_computemon { + qcom,core-dev-table = + < 806400 MHZ_TO_MBPS( 300, 4) >, + < 1401600 MHZ_TO_MBPS( 547, 4) >, + < 1766400 MHZ_TO_MBPS( 768, 4) >, + < 1996800 MHZ_TO_MBPS(1017, 4) >, + < 2707200 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; +}; + +/* NPU overrides */ +&msm_npu { + qcom,npu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,npu-pwrlevels"; + initial-pwrlevel = <5>; + qcom,npu-pwrlevel@0 { + reg = <0>; + vreg = <1>; + clk-freq = <19200000 + 100000000 + 230000000 + 230000000 + 150000000 + 40000000 + 300000000 + 100000000 + 19200000 + 50000000 + 50000000 + 100000000 + 100000000 + 100000000 + 19200000 + 100000000 + 19200000 + 50000000 + 230000000 + 50000000 + 19200000 + 230000000 + 19200000 + 300000000>; + }; + + qcom,npu-pwrlevel@1 { + reg = <1>; + vreg = <2>; + clk-freq = <19200000 + 200000000 + 422000000 + 422000000 + 207000000 + 40000000 + 403000000 + 200000000 + 19200000 + 50000000 + 50000000 + 200000000 + 200000000 + 200000000 + 19200000 + 200000000 + 19200000 + 50000000 + 422000000 + 50000000 + 19200000 + 422000000 + 19200000 + 400000000>; + }; + + qcom,npu-pwrlevel@2 { + reg = <2>; + vreg = <3>; + clk-freq = <19200000 + 333000000 + 557000000 + 557000000 + 300000000 + 75000000 + 533000000 + 214000000 + 19200000 + 50000000 + 100000000 + 214000000 + 214000000 + 214000000 + 19200000 + 214000000 + 19200000 + 50000000 + 557000000 + 50000000 + 19200000 + 557000000 + 19200000 + 500000000>; + }; + + qcom,npu-pwrlevel@3 { + reg = <3>; + vreg = <4>; + clk-freq = <19200000 + 400000000 + 729000000 + 729000000 + 403000000 + 75000000 + 700000000 + 285714286 + 19200000 + 100000000 + 200000000 + 285714286 + 285714286 + 285714286 + 19200000 + 285714286 + 19200000 + 100000000 + 729000000 + 100000000 + 19200000 + 729000000 + 19200000 + 660000000>; + }; + + qcom,npu-pwrlevel@4 { + reg = <4>; + vreg = <6>; + clk-freq = <19200000 + 500000000 + 844000000 + 844000000 + 533000000 + 75000000 + 806000000 + 285714286 + 19200000 + 100000000 + 200000000 + 285714286 + 285714286 + 285714286 + 19200000 + 285714286 + 19200000 + 100000000 + 844000000 + 100000000 + 19200000 + 844000000 + 19200000 + 800000000>; + }; + + qcom,npu-pwrlevel@5 { + reg = <5>; + vreg = <7>; + clk-freq = <19200000 + 500000000 + 1000000000 + 1000000000 + 533000000 + 75000000 + 806000000 + 285714286 + 19200000 + 100000000 + 200000000 + 285714286 + 285714286 + 285714286 + 19200000 + 285714286 + 19200000 + 100000000 + 1000000000 + 100000000 + 19200000 + 1000000000 + 19200000 + 800000000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito-vidc.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..40007b8fcd939893896e450293f73af993a2652e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito-vidc.dtsi @@ -0,0 +1,233 @@ +#include +#include +#include + +&soc { + msm_vidc0: qcom,vidc0 { + compatible = "qcom,msm-vidc", "qcom,lito-vidc"; + status = "ok"; + sku-index = <0>; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + iris-ctl-supply = <&mvsc_gdsc>; + vcodec-supply = <&mvs0_gdsc>; + cvp-supply = <&mvs1_gdsc>; + + /* Clocks */ + clock-names = "video_cc_mvsc_ctl_axi", "video_cc_mvs0_ctl_axi", + "video_cc_mvs1_ctl_axi", "core_clk", "vcodec_clk", + "cvp_clk", "iface_clk"; + clocks = <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&videocc VIDEO_CC_MVS0_AXI_CLK>, + <&videocc VIDEO_CC_MVS1_AXI_CLK>, + <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_MVS0_CORE_CLK>, + <&videocc VIDEO_CC_MVS1_CORE_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>; + + qcom,proxy-clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "video_cc_mvs1_ctl_axi", + "core_clk", "vcodec_clk", "cvp_clk", "iface_clk"; + + qcom,clock-configs = <0x0 0x0 0x0 0x1 0x1 0x1 0x0>; + qcom,allowed-clock-rates = <240000000 338000000 365000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venus-ddr"; + qcom,bus-range-kbps = <1000 6533000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0x1380 0x60>, + <&apps_smmu 0x1360 0x0>; + qcom,iommu-dma-addr-pool = <0x25800000 0xba800000>; + qcom,iommu-faults = "non-fatal"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0x1304 0xe0>; + qcom,iommu-dma-addr-pool = <0x01000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0x1361 0x4>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0x1303 0xe0>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + /* Memory Heaps */ + qcom,msm-vidc,mem_cdsp { + compatible = "qcom,msm-vidc,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; + }; + + msm_vidc1: qcom,vidc1 { + compatible = "qcom,msm-vidc", "qcom,lito-vidc"; + status = "ok"; + sku-index = <1>; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* Supply */ + iris-ctl-supply = <&mvsc_gdsc>; + vcodec-supply = <&mvs0_gdsc>; + cvp-supply = <&mvs1_gdsc>; + + /* Clocks */ + clock-names = "video_cc_mvsc_ctl_axi", "video_cc_mvs0_ctl_axi", + "video_cc_mvs1_ctl_axi", "core_clk", "vcodec_clk", + "cvp_clk", "iface_clk"; + clocks = <&videocc VIDEO_CC_MVSC_CTL_AXI_CLK>, + <&videocc VIDEO_CC_MVS0_AXI_CLK>, + <&videocc VIDEO_CC_MVS1_AXI_CLK>, + <&videocc VIDEO_CC_MVSC_CORE_CLK>, + <&videocc VIDEO_CC_MVS0_CORE_CLK>, + <&videocc VIDEO_CC_MVS1_CORE_CLK>, + <&videocc VIDEO_CC_VENUS_AHB_CLK>; + + qcom,proxy-clock-names = "video_cc_mvsc_ctl_axi", + "video_cc_mvs0_ctl_axi", "video_cc_mvs1_ctl_axi", + "core_clk", "vcodec_clk", "cvp_clk", "iface_clk"; + + qcom,clock-configs = <0x0 0x0 0x0 0x1 0x1 0x1 0x0>; + qcom,allowed-clock-rates = <200000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venus-ddr"; + qcom,bus-range-kbps = <1000 6533000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_smmu 0x1380 0x60>, + <&apps_smmu 0x1360 0x0>; + qcom,iommu-dma-addr-pool = <0x25800000 0xba800000>; + qcom,iommu-faults = "non-fatal"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x25800000 0xba800000>; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_smmu 0x1304 0xe0>; + qcom,iommu-dma-addr-pool = <0x01000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_smmu 0x1361 0x4>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x00500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_smmu 0x1303 0xe0>; + qcom,iommu-dma-addr-pool = <0x00500000 0xdfb00000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x00500000 0xdfb00000>; + qcom,secure-context-bank; + }; + + /* Memory Heaps */ + qcom,msm-vidc,mem_cdsp { + compatible = "qcom,msm-vidc,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito.dts b/arch/arm64/boot/dts/vendor/qcom/lito.dts new file mode 100644 index 0000000000000000000000000000000000000000..24ed52b8ea20b5da9e8939121afce44d25b28af4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "lito.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Lito SoC"; + compatible = "qcom,lito"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/lito.dtsi b/arch/arm64/boot/dts/vendor/qcom/lito.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d1d22134998fb4450ce430c0a703dea9ad452366 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/lito.dtsi @@ -0,0 +1,4056 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + +/ { + model = "Qualcomm Technologies, Inc. Lito"; + compatible = "qcom,lito"; + qcom,msm-id = <400 0x10000>, <440 0x10000>; + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + memory { device_type = "memory"; reg = <0 0 0 0>; }; + + mem-offline { + compatible = "qcom,mem-offline"; + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>, + <0x2 0xc0000000 0x1 0x40000000>; + granule = <512>; + mboxes = <&qmp_aop 0>; + }; + + aliases { + serial0 = &qupv3_se2_2uart; /*RUMI*/ + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + swr0 = &swr0; + swr1 = &swr1; + swr2 = &swr2; + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + i2c2 = &qupv3_se9_i2c; + i2c4 = &qupv3_se7_i2c; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + + L3_0: l3-cache { + compatible = "arm,arch-cache"; + cache-level = <3>; + }; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + }; + + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_100>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_100: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + }; + + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x200>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_200>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_200: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_200: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_200: l1-dcache { + compatible = "arm,arch-cache"; + }; + + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x300>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_300>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_300: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_300: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_300: l1-dcache { + compatible = "arm,arch-cache"; + }; + + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x400>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_400>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_400: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_400: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_400: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x500>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + qcom,freq-domain = <&cpufreq_hw 0 6>; + next-level-cache = <&L2_500>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + L2_500: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_500: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_500: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x600>; + enable-method = "psci"; + capacity-dmips-mhz = <1740>; + dynamic-power-coefficient = <341>; + qcom,freq-domain = <&cpufreq_hw 1 2>; + next-level-cache = <&L2_600>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + L2_600: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_600: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_600: l1-dcache { + compatible = "arm,arch-cache"; + }; + + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x700>; + enable-method = "psci"; + capacity-dmips-mhz = <1740>; + dynamic-power-coefficient = <375>; + qcom,freq-domain = <&cpufreq_hw 2 2>; + next-level-cache = <&L2_700>; + qcom,lmh-dcvs = <&lmh_dcvs2>; + #cooling-cells = <2>; + L2_700: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + + L1_I_700: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_700: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + + core4 { + cpu = <&CPU4>; + }; + + core5 { + cpu = <&CPU5>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU6>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU7>; + }; + }; + }; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/1d84000.ufshc/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect"; + status = "ok"; + }; + }; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + reserved_memory:reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_mem: hyp_region@80000000 { + no-map; + reg = <0x0 0x80000000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_region@80700000 { + no-map; + reg = <0x0 0x80700000 0x0 0x160000>; + }; + + cmd_db: reserved-memory@80860000 { + reg = <0x0 0x80860000 0x0 0x20000>; + compatible = "qcom,cmd-db"; + no-map; + }; + + sec_apps_mem: sec_apps_region@808ff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x808ff000 0x0 0x1000>; + }; + + smem_mem: smem_region@80900000 { + no-map; + reg = <0x0 0x80900000 0x0 0x200000>; + }; + + removed_mem: removed_region@80b00000 { + no-map; + reg = <0x0 0x80b00000 0x0 0x1300000>; + }; + + qtee_apps_mem: qtee_apps_region@81e00000 { + no-map; + reg = <0x0 0x81e00000 0x0 0x4200000>; + }; + + pil_camera_mem: pil_camera_region@86000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86000000 0x0 0x500000>; + }; + + pil_npu_mem: pil_npu_region@86500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86500000 0x0 0x500000>; + }; + + pil_video_mem: pil_video_region@86a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86a00000 0x0 0x500000>; + }; + + pil_cdsp_mem: pil_cdsp_region@87400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x87400000 0x0 0x1e00000>; + }; + + pil_adsp_mem: pil_adsp_region@89200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x89200000 0x0 0x2800000>; + }; + + pil_wlan_fw_mem: pil_wlan_fw_region@8ba00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8ba00000 0x0 0x200000>; + }; + + pil_ipa_fw_mem: pil_ipa_fw_region@8bc00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8bc00000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: pil_ipa_gsi_region@8bc10000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8bc10000 0x0 0x5400>; + }; + + pil_gpu_mem: pil_gpu_region@8bc15400 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8bc15400 0x0 0x2000>; + }; + + reserved_pil: reserved_pil_mem_region@8bc17400 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8bc17400 0x0 0x3e8c00>; + }; + + modem_wlan_mem: modem_wlan_region@8c000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8c000000 0x0 0xf800000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + cdsp_sec_mem: cdsp_sec_regions@9f400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x9f400000 0x0 0xc00000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0xC00000>; + }; + + sdsp_mem: sdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + cdsp_mem: cdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + secure_display_memory: secure_display_region { /* Secure UI */ + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0xA000000>; + }; + + cont_splash_memory: cont_splash_region { + reg = <0x0 0xA0000000 0x0 0x02300000>; + label = "cont_splash_region"; + }; + + dfps_data_memory: dfps_data_region@a2300000 { + reg = <0x0 0xa2300000 0x0 0x0100000>; + label = "dfps_data_region"; + }; + + disp_rdump_memory: disp_rdump_region@0xa0000000 { + reg = <0x0 0xA0000000 0x0 0x02300000>; + label = "disp_rdump_region"; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + size = <0 0x2800000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x2000000>; + linux,cma-default; + }; + + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + }; + + soc: soc { }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + slim_aud: slim@3ac0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x3ac0000 0x2c000>, + <0x3a84000 0x2c000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = , + ; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x700000>; + qcom,ea-pc = <0x330>; + iommus = <&apps_smmu 0x1426 0x0>, + <&apps_smmu 0x142f 0x0>, + <&apps_smmu 0x1430 0x1>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "atomic"; + status = "ok"; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-sw-ctrl-gpio = <&tlmm 73 0>; /* SW_CTRL */ + qca,bt-vdd-io-supply = <&pm8150_s4>; + qca,bt-vdd-core-supply = <&pm8150a_l2>; + qca,bt-vdd-pa-supply = <&pm8150a_l10>; + qca,bt-vdd-xtal-supply = <&pm8150_l14>; + + qca,bt-vdd-io-voltage-level = <1800000 1800000>; /* IO */ + qca,bt-vdd-core-voltage-level = <1304000 1304000>; /* RFA */ + qca,bt-vdd-pa-voltage-level = <3000000 3312000>; /*chain0 */ + qca,bt-vdd-xtal-voltage-level = <1800000 1800000>; /* XO */ + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + }; + + thermal_zones: thermal-zones { + }; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17a60000 0x100000>; /* GICR * 8 */ + interrupts = ; + interrupt-parent = <&intc>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,lito-pdc"; + reg = <0xb220000 0x30000>, <0x17c000f0 0x60>; + qcom,pdc-ranges = <0 480 42>, <42 612 28>, <70 63 1>, + <71 640 15>, <86 522 52>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + clock-frequency = <19200000>; + }; + + timer@17c20000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17c20000 0x1000>; + clock-frequency = <19200000>; + + frame@17c21000 { + frame-number = <0>; + interrupts = , + ; + reg = <0x17c21000 0x1000>, + <0x17c22000 0x1000>; + }; + + frame@17c23000 { + frame-number = <1>; + interrupts = ; + reg = <0x17c23000 0x1000>; + status = "disabled"; + }; + + frame@17c25000 { + frame-number = <2>; + interrupts = ; + reg = <0x17c25000 0x1000>; + status = "disabled"; + }; + + frame@17c27000 { + frame-number = <3>; + interrupts = ; + reg = <0x17c27000 0x1000>; + status = "disabled"; + }; + + frame@17c29000 { + frame-number = <4>; + interrupts = ; + reg = <0x17c29000 0x1000>; + status = "disabled"; + }; + + frame@17c2b000 { + frame-number = <5>; + interrupts = ; + reg = <0x17c2b000 0x1000>; + status = "disabled"; + }; + + frame@17c2d000 { + frame-number = <6>; + interrupts = ; + reg = <0x17c2d000 0x1000>; + status = "disabled"; + }; + }; + + qcom,msm-imem@146ab000 { + compatible = "qcom,msm-imem"; + reg = <0x146ab000 0x1000>; + ranges = <0x0 0x146ab000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 0x8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 0x4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 0x20>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 0xc>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 0xc8>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 0xc8>; + }; + }; + + dcc: dcc_v2@1022000 { + compatible = "qcom,dcc-v2"; + reg = <0x1022000 0x1000>, + <0x103b000 0x5000>; + reg-names = "dcc-base", "dcc-ram-base"; + + dcc-ram-offset = <0xb000>; + + qcom,curr-link-list = <6>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + restart@c264000 { + compatible = "qcom,pshold"; + reg = <0xc264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom_seecom: qseecom@82200000 { + compatible = "qcom,qseecom"; + reg = <0x82200000 0x3e00000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + qcom,commonlib64-loaded-by-uefi; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_smcinvoke: smcinvoke@82200000 { + compatible = "qcom,smcinvoke"; + reg = <0x82200000 0x3e00000>; + reg-names = "secapp-region"; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , /* No vote */ + ; /* 75 MHz */ + clocks = <&gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + + qcom_tzlog: tz-log@146ab720 { + compatible = "qcom,tz-log"; + reg = <0x146ab720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0506 0x0011>, + <&apps_smmu 0x0516 0x0011>; + qcom,iommu-dma = "atomic"; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&apps_smmu 0x512 0>, + <&apps_smmu 0x518 0x1>, + <&apps_smmu 0x51F 0>; + }; + + qcom_cedev_s_cb { + compatible = "qcom,qcedev,context-bank"; + label = "secure_context"; + iommus = <&apps_smmu 0x513 0>, + <&apps_smmu 0x51C 0x1>, + <&apps_smmu 0x51E 0>; + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ + qcom,secure-context-bank; + }; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + qcom,no-clock-support; + iommus = <&apps_smmu 0x0504 0x0011>, + <&apps_smmu 0x0514 0x0011>; + qcom,iommu-dma = "atomic"; + }; + + qcom,mpm2-sleep-counter@0xc221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0xc221000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + wdog: qcom,wdt@17c10000 { + compatible = "qcom,msm-watchdog"; + reg = <0x17c10000 0x1000>; + reg-names = "wdt-base"; + interrupts = , + ; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; + + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7440000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7440000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7540000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7540000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7640000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7640000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7740000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7740000 0x1000>; + reg-names = "etm-base"; + + clocks = <&aopcc QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; + + keepalive_opp_table: keepalive-opp-table { + compatible = "operating-points-v2"; + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = ; + qcom,active-only; + status = "ok"; + operating-points-v2 = <&keepalive_opp_table>; + }; + + bus_proxy_client: qcom,bus_proxy_client { + compatible = "qcom,bus-proxy-client"; + qcom,msm-bus,name = "bus-proxy-client"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 5000000>, <23 512 0 5000000>; + qcom,msm-bus,active-only; + status = "ok"; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + + tsens0: tsens@c222000 { + compatible = "qcom,tsens26xx"; + reg = <0xc222000 0x8>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + + interrupts-extended = <&pdc 26 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 28 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 20 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tsens-upper-lower", + "tsens-critical", "tsens-0C"; + 0C-sensor-num = <16>; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + tsens1: tsens@c223000 { + compatible = "qcom,tsens26xx"; + reg = <0xc223000 0x8>, + <0xc265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + + interrupts-extended = <&pdc 27 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 29 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 21 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tsens-upper-lower", + "tsens-critical", "tsens-0C"; + 0C-sensor-num = <16>; + tsens-reinit-wa; + #thermal-sensor-cells = <1>; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect-v3"; + qcom,threshold-arr = <0x17e0041c>; + qcom,config-reg = <0x17e00434>; + }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <38400000>; + clock-output-names = "xo_board"; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-output-names = "chip_sleep_clk"; + clock-frequency = <32000>; + #clock-cells = <0>; + }; + }; + + aopcc: qcom,aopclk { + compatible = "qcom,aop-qmp-clk"; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + #clock-cells = <1>; + }; + + gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-lito", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + camcc: qcom,camcc@ad00000 { + compatible = "qcom,lito-camcc", "syscon"; + reg = <0xad00000 0x10000>; + reg-names = "cc_base"; + vdd_mx-supply = <&VDD_MX_LEVEL>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + videocc: qcom,videocc@ab00000 { + compatible = "qcom,lito-videocc", "syscon"; + reg = <0x0ab00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + clock-names = "cfg_ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + nvmem-cells = <&iris_efuse>; + nvmem-cell-names = "iris-bin"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + dispcc: qcom,dispcc@af00000 { + compatible = "qcom,lito-dispcc", "syscon"; + reg = <0xaf00000 0x20000>; + reg-names = "cc_base"; + clock-names = "cfg_ahb_clk"; + clocks = <&gcc GCC_DISP_AHB_CLK>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + gpucc: qcom,gpucc@3d90000 { + compatible = "qcom,lito-gpucc", "syscon"; + reg = <0x3d90000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + npucc: qcom,npucc@9980000 { + compatible = "qcom,lito-npucc", "syscon"; + reg = <0x9980000 0x10000>, + <0x9800000 0x10000>, + <0x9810000 0x10000>; + reg-names = "cc", "qdsp6ss", "qdsp6ss_pll"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + nvmem-cells = <&npu_efuse>; + nvmem-cell-names = "npu-bin"; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cpucc: syscon@182a0018 { + compatible = "syscon"; + reg = <0x182a0000 0x4>; + }; + + mccc: syscon@90b0000 { + compatible = "syscon"; + reg = <0x90b0000 0x1000>; + }; + + debugcc: qcom,cc-debug { + compatible = "qcom,lito-debugcc"; + qcom,gcc = <&gcc>; + qcom,videocc = <&videocc>; + qcom,dispcc = <&dispcc>; + qcom,camcc = <&camcc>; + qcom,gpucc = <&gpucc>; + qcom,npucc = <&npucc>; + qcom,cpucc = <&cpucc>; + qcom,mccc = <&mccc>; + clock-names = "xo_clk_src"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + #clock-cells = <1>; + }; + + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw"; + reg = <0x18323000 0x1000>, <0x18325800 0x1000>, + <0x18327800 0x1000>; + reg-names = "freq-domain0", "freq-domain1", + "freq-domain2"; + clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GPLL0>; + clock-names = "xo", "alternate"; + qcom,no-accumulative-counter; + #freq-domain-cells = <2>; + }; + + qcom,cpufreq-hw-debug@18320000 { + compatible = "qcom,cpufreq-hw-debug-trace"; + reg = <0x18320000 0x800>; + reg-names = "domain-top"; + qcom,freq-hw-domain = <&cpufreq_hw 0>, <&cpufreq_hw 1>, + <&cpufreq_hw 2>; + }; + + qcom,devfreq-l3 { + compatible = "qcom,devfreq-fw"; + reg = <0x18321000 0x4>, <0x18321110 0x500>, <0x18321920 0x4>, + <0x18321700 0x4>; + reg-names = "en-base", "ftbl-base", "perf-base", "pstate-base"; + + qcom,ftbl-row-size = <32>; + qcom,support-panic-notifier; + + cpu0_l3: qcom,cpu0-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cpu6_l3: qcom,cpu6-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cpu7_l3: qcom,cpu7-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cdsp_l3: qcom,cdsp-cdsp-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + }; + + spmi_bus: qcom,spmi@c440000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0xc440000 0x1100>, + <0xc600000 0x2000000>, + <0xe600000 0x100000>, + <0xe700000 0xa0000>, + <0xc40a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x3000>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; + interrupts = ; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + + lanes-per-direction = <2>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + spm-level = <3>; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "core_clk_ice_hw_ctl", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + clocks = + <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_CLK>, + <&gcc GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <22>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G1 L2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G2 L2 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G3 L2 */ + <123 512 14752 0>, <1 757 1000 0>, /* PWM G4 L2 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G1 RA L2 */ + <123 512 511181 0>, <1 757 1000 0>, /* HS G2 RA L2 */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */ + <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */ + /* As UFS working in HS G3 RB L2 mode, aggregated + * bandwidth (AB) should take care of providing + * optimum throughput requested. However, as tested, + * in order to scale up CNOC clock, instantaneous + * bindwidth (IB) needs to be given a proper value too. + */ + <123 512 4194304 0>, <1 757 204800 409600>, /* HS G3 RB L2 */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-cpu-group-latency-us = <67 67>; + qcom,pm-qos-default-cpu = <0>; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "core_reset"; + non-removable; + + status = "disabled"; + }; + + sdhc_1: sdhci@7c4000 { + compatible = "qcom,sdhci-msm-v5", "qcom,sdhci-msm-cqe"; + reg = <0x7c4000 0x1000>, <0x7c5000 0x1000>, <0x7c8000 0x8000>; + reg-names = "hc_mem", "cqhci_mem", "cqhci_ice"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <150 10073 0 0>, + <135 512 0 0>, + <1 825 0 0>, + /* 400 KB/s*/ + <150 10073 1000 7600>, + <135 512 1000 90000>, + <1 825 2000 6600>, + /* 20 MB/s */ + <150 10073 25000 76000>, + <135 512 25000 900000>, + <1 825 20000 66000>, + /* 25 MB/s */ + <150 10073 50000 76000>, + <135 512 50000 900000>, + <1 825 30000 66000>, + /* 50 MB/s */ + <150 10073 50000 76000>, + <135 512 80000 900000>, + <1 825 40000 66000>, + /* 100 MB/s */ + <150 10073 50000 76000>, + <135 512 100000 900000>, + <1 825 50000 66000>, + /* 200 MB/s */ + <150 10073 50000 76000>, + <150 512 150000 900000>, + <1 825 80000 76000>, + /* 400 MB/s */ + <150 10073 261438 2300000>, + <135 512 261438 4700000>, + <1 825 300000 300000>, + /* Max. bandwidth */ + <150 10073 1338562 4096000>, + <135 512 1338562 4096000>, + <1 825 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 400000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <67 67>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-cmdq-latency-us = <67 67>, <67 67>; + qcom,pm-qos-legacy-latency-us = <67 67>, <67 67>; + + clocks = <&gcc GCC_SDCC1_AHB_CLK>, + <&gcc GCC_SDCC1_APPS_CLK>, + <&gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,ice-clk-rates = <300000000 100000000>; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x000f642c 0x0 0x0 0x2c010800 0x80040868>; + + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@8804000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x8804000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 202000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 202000000>; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 10073 0 0>, + <135 512 0 0>, + <1 825 0 0>, + /* 400 KB/s*/ + <81 10073 1000 7600>, + <135 512 1000 90000>, + <1 825 2000 6600>, + /* 20 MB/s */ + <81 10073 25000 76000>, + <135 512 25000 900000>, + <1 825 20000 66000>, + /* 25 MB/s */ + <81 10073 50000 76000>, + <135 512 50000 900000>, + <1 825 30000 66000>, + /* 50 MB/s */ + <81 10073 50000 76000>, + <135 512 80000 900000>, + <1 825 40000 66000>, + /* 100 MB/s */ + <81 10073 50000 76000>, + <135 512 100000 900000>, + <1 825 50000 66000>, + /* 200 MB/s */ + <81 10073 261438 2300000>, + <135 512 261438 4700000>, + <1 825 300000 300000>, + /* Max. bandwidth */ + <81 10073 1338562 4096000>, + <135 512 1338562 4096000>, + <1 825 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 400000000 4294967295>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <67 67>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <67 67>, <67 67>; + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642c 0x0 0x10 0x2c010800 0x80040868>; + + status = "disabled"; + }; + + apps_rsc: rsc@18200000 { + label = "apps_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0x18200000 0x10000>, + <0x18210000 0x10000>, + <0x18220000 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + system_pm { + compatible = "qcom,system-pm"; + }; + + rpmhcc: qcom,rpmhclk { + compatible = "qcom,lito-rpmh-clk"; + #clock-cells = <1>; + }; + + msm_bus_apps_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + reg = <0x1d87000 0xe00>, <0x1d90000 0x8000>; + reg-names = "phy_mem", "ufs_ice"; + #phy-cells = <0>; + + lanes-per-direction = <2>; + qcom,rpmh-resource-name = "qphy.lvl"; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_1X_CLKREF_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + }; + }; + + disp_rsc: rsc@af20000 { + label = "disp_rsc"; + compatible = "qcom,rpmh-rsc"; + reg = <0xaf20000 0x10000>; + reg-names = "drv-0"; + interrupts = ; + qcom,tcs-offset = <0x1c00>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + + msm_bus_disp_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; + + sde_rsc_rpmh { + compatible = "qcom,sde-rsc-rpmh"; + cell-index = <0>; + }; + + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x280000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + }; + + ipcc_mproc: qcom,ipcc@408000 { + compatible = "qcom,ipcc"; + reg = <0x408000 0x1000>; + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + #mbox-cells = <2>; + }; + + cache-controller@9200000 { + compatible = "qcom,llcc-v1"; + reg = <0x9200000 0xd0000> , <0x9600000 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + cap-based-alloc-and-pwr-collapse; + + LLCC_1: llcc_1_dcache { + qcom,dump-size = <0x1141c0>; + }; + + LLCC_2: llcc_2_dcache { + qcom,dump-size = <0x1141c0>; + }; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = ; + }; + + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + c0_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x0>; + }; + + c100_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x1>; + }; + + c200_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x2>; + }; + + c300_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x3>; + }; + + c400_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x4>; + }; + + c500_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x5>; + }; + + c600_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x6>; + }; + + c700_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x7>; + }; + + c0_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x130>; + }; + + c100_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x131>; + }; + + c200_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x132>; + }; + + c300_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x133>; + }; + + c400_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x134>; + }; + + c500_scandump { + qcom,dump-size = <0x10100>; + qcom,dump-id = <0x135>; + }; + + c600_scandump { + qcom,dump-size = <0x25900>; + qcom,dump-id = <0x136>; + }; + + c700_scandump { + qcom,dump-size = <0x25900>; + qcom,dump-id = <0x137>; + }; + + l1_i_cache0 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x60>; + }; + + l1_icache100 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x61>; + }; + + l1_icache200 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x62>; + }; + + l1_icache300 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x63>; + }; + + l1_icache400 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x64>; + }; + + l1_icache500 { + qcom,dump-size = <0x10800>; + qcom,dump-id = <0x65>; + }; + + l1_icache600 { + qcom,dump-size = <0x21000>; + qcom,dump-id = <0x66>; + }; + + l1_icache700 { + qcom,dump-size = <0x21000>; + qcom,dump-id = <0x67>; + }; + + l1_dcache0 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x80>; + }; + + l1_dcache100 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x81>; + }; + + l1_dcache200 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x82>; + }; + + l1_dcache300 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x83>; + }; + + l1_dcache400 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x84>; + }; + + l1_dcache500 { + qcom,dump-size = <0x9000>; + qcom,dump-id = <0x85>; + }; + + l1_dcache600 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x86>; + }; + + l1_dcache700 { + qcom,dump-size = <0x12000>; + qcom,dump-id = <0x87>; + }; + + l1_itlb600 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x26>; + }; + + l1_itlb700 { + qcom,dump-size = <0x300>; + qcom,dump-id = <0x27>; + }; + + l1_dtlb600 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x46>; + }; + + l1_dtlb700 { + qcom,dump-size = <0x480>; + qcom,dump-id = <0x47>; + }; + + l2_cache600 { + qcom,dump-size = <0x48000>; + qcom,dump-id = <0xc6>; + }; + + l2_cache700 { + qcom,dump-size = <0x48000>; + qcom,dump-id = <0xc7>; + }; + + l2_tlb0 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x120>; + }; + + l2_tlb100 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x121>; + }; + + l2_tlb200 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x122>; + }; + + l2_tlb300 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x123>; + }; + + l2_tlb400 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x124>; + }; + + l2_tlb500 { + qcom,dump-size = <0x5a00>; + qcom,dump-id = <0x125>; + }; + + l2_tlb600 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x126>; + }; + + l2_tlb700 { + qcom,dump-size = <0x7800>; + qcom,dump-id = <0x127>; + }; + + llcc1_d_cache { + qcom,dump-size = <0x1141c0>; + qcom,dump-id = <0x140>; + }; + + llcc2_d_cache { + qcom,dump-size = <0x1141c0>; + qcom,dump-id = <0x141>; + }; + + rpmh { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x80000>; + qcom,dump-id = <0xe4>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + etf_swao { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf1>; + }; + + etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + etfswao_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + + ipa { + qcom,dump-size = <0x11000>; + qcom,dump-id = <0x150>; + }; + + etf_slpi { + qcom,dump-size = <0x4000>; + qcom,dump-id = <0xf3>; + }; + + etfslpi_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x103>; + }; + + etf_lpass { + qcom,dump-size = <0x4000>; + qcom,dump-id = <0xf4>; + }; + + etflpass_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x104>; + }; + + clk_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x163>; + }; + }; + + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x18000058 0x18010058 + 0x18020058 0x18030058 + 0x18040058 0x18050058>; + qcom,config-arr = <0x18000060 0x18010060 + 0x18020060 0x18030060 + 0x18040060 0x18050060>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x18060058 0x18070058>; + qcom,config-arr = <0x18060060 0x18070060>; + }; + + kryo-erp { + compatible = "arm,arm64-kryo-cpu-erp"; + interrupts = , + ; + interrupt-names = "l1-l2-faultirq", + "l3-scu-faultirq"; + }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "modem_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 0x2>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "adsp_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&ipcc_mproc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "dsps_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x20 12>; + + qcom,cdsp-cdsp-l3-gov { + compatible = "qcom,cdsp-l3"; + qcom,target-dev = <&cdsp_l3>; + }; + + msm_cdsp_rm: qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <44>; + qcom,qos-maxhold-ms = <20>; + qcom,compute-cx-limit-en; + qcom,compute-priority-mode = <2>; + #cooling-cells = <2>; + }; + + msm_hvx_rm: qcom,msm_hvx_rm { + compatible = "qcom,msm-hvx-rm"; + #cooling-cells = <2>; + }; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_npu>; + }; + }; + + glink_npu: npu { + qcom,remote-pid = <10>; + transport = "smem"; + mboxes = <&msm_npu IPCC_CLIENT_NPU + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "npu_smem"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + label = "npu"; + qcom,glink-label = "npu"; + + qcom,npu_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,npu_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + reg = <0xc300000 0x1000>; + reg-names = "msgram"; + mboxes = <&ipcc_mproc IPCC_CLIENT_AOP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + mbox-names = "aop_qmp"; + interrupt-parent = <&ipcc_mproc>; + interrupts = ; + + label = "aop"; + qcom,early-boot; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x4080000 0x100>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,vdd_cx-uV-uA = ; + vdd_mss-supply = <&VDD_MSS_LEVEL>; + qcom,vdd_mss-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx", "vdd_mss"; + + qcom,firmware-name = "modem"; + memory-region = <&modem_wlan_mem>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,pas-id = <4>; + qcom,smem-id = <421>; + qcom,minidump-id = <3>; + qcom,aux-minidump-ids = <4>; + qcom,signal-aop; + qcom,complete-ramdump; + + qcom,msm-bus,name = "pil-modem"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <129 512 0 0>, + <129 512 0 8171520>; + + /* Inputs from mss */ + interrupts-extended = <&intc GIC_SPI 266 IRQ_TYPE_EDGE_RISING>, + <&mpss_smp2p_in 0 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 1 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 2 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 3 IRQ_TYPE_NONE>, + <&mpss_smp2p_in 7 IRQ_TYPE_NONE>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* Outputs to mss */ + qcom,smem-states = <&mpss_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "mss-pil"; + }; + + qcom,lpass@3000000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x3000000 0x00100>; + + vdd_lpi_cx-supply = <&L18A_LEVEL>; + qcom,vdd_lpi_cx-uV-uA = ; + vdd_lpi_mx-supply = <&L4A_LEVEL>; + qcom,vdd_lpi_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_lpi_cx", "vdd_lpi_mx"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,minidump-id = <5>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + qcom,signal-aop; + qcom,complete-ramdump; + qcom,minidump-as-elf32; + + /* Inputs from lpass */ + interrupts-extended = <&pdc 16 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,err-ready", + "qcom,proxy-unvote", + "qcom,stop-ack"; + + /* Outputs to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; + }; + + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <18>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,minidump-id = <7>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&pil_cdsp_mem>; + qcom,complete-ramdump; + qcom,signal-aop; + qcom,minidump-as-elf32; + + qcom,msm-bus,name = "pil-cdsp"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <154 821 0 0>, + <154 821 0 1>; + + /* Inputs from turing */ + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + status = "ok"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + msm_fastrpc: qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + status = "ok"; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + qcom,rpc-latency-us = <235>; + qcom,qos-cores = <0 1 2 3 4 5>; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1801 0x0440>, + <&apps_smmu 0x1821 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1802 0x0440>, + <&apps_smmu 0x1822 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1803 0x0440>, + <&apps_smmu 0x1823 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1804 0x0440>, + <&apps_smmu 0x1824 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1805 0x0440>, + <&apps_smmu 0x1825 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1806 0x0460>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1807 0x0440>, + <&apps_smmu 0x1827 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1808 0x0440>, + <&apps_smmu 0x1828 0x0400>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1809 0x0460>; + qcom,iommu-dma-addr-pool = <0x60000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + qcom,iommu-vmid = <0xA>; /* VMID_CP_PIXEL */ + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1403 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1404 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1405 0x0>; + shared-cb = <5>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + dma-coherent; + }; + }; + + qcom,venus@aae0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xaae0000 0x4000>; + + vdd-supply = <&mvsc_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&videocc VIDEO_CC_XO_CLK>, + <&videocc VIDEO_CC_MVSC_CORE_CLK>; + clock-names = "xo", "core"; + qcom,proxy-clock-names = "xo", "core"; + + qcom,core-freq = <240000000>; + qcom,ahb-freq = <240000000>; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + }; + + gpi_dma0: qcom,gpi-dma@800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x1f>; + qcom,ev-factor = <2>; + qcom,gpi-ee-offset = <0x10000>; + iommus = <&apps_smmu 0x4f6 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + gpi_dma1: qcom,gpi-dma@900000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x900000 0x60000>; + reg-names = "gpi-top"; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,max-num-gpii = <10>; + qcom,gpii-mask = <0x3f>; + qcom,ev-factor = <2>; + qcom,gpi-ee-offset = <0x10000>; + iommus = <&apps_smmu 0x36 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + status = "ok"; + }; + + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupt-parent = <&pdc>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + reg = <0x088e0000 0x2000>, + <0x088e2000 0x1000>; + reg-names = "eud_base", "eud_mode_mgr2"; + qcom,secure-eud-en; + qcom,eud-clock-vote-req; + clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_BCR>; + clock-names = "eud_ahb2phy_clk"; + status = "ok"; + }; + + llcc_pmu: llcc-pmu@90cc000 { + compatible = "qcom,llcc-pmu-ver1"; + reg = <0x090cc000 0x300>; + reg-names = "lagg-base"; + }; + + llcc_bw_opp_table: llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + BW_OPP_ENTRY(1066, 16); /* 16265 MB/s */ + }; + + suspendable_llcc_bw_opp_table: suspendable-llcc-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 16); /* 0 MB/s */ + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 466, 16); /* 7110 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 806, 16); /* 12298 MB/s */ + BW_OPP_ENTRY( 933, 16); /* 14236 MB/s */ + BW_OPP_ENTRY(1066, 16); /* 16265 MB/s */ + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon@90b6400 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x90B6300 0x300>, <0x090B6200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; + + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon@90cd000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90cd000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5161 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + BW_OPP_ENTRY(2092, 4); /* 7980 MB/s */ + }; + + npu_npu_llcc_bw: qcom,npu-npu-llcc-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_llcc_bw_opp_table>; + }; + + npu_npu_llcc_bwmon: qcom,npu-npu-llcc-bwmon@9960300 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x00060400 0x300>, <0x00060300 0x200>; + reg-names = "base", "global_base"; + clocks = <&gcc GCC_NPU_BWMON_CFG_AHB_CLK>, + <&gcc GCC_NPU_BWMON_AXI_CLK>, + <&gcc GCC_NPU_BWMON2_AXI_CLK>; + clock-names = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,bwmon_clks = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,msm_bus = <154 512>; + qcom,msm_bus_name = "npu_bwmon_cdsp"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_npu_llcc_bw>; + qcom,count-unit = <0x10000>; + }; + + npu_llcc_ddr_bw: qcom,npu-llcc-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npu_llcc_ddr_bwmon: qcom,npu-llcc-ddr-bwmon@90CE000 { + compatible = "qcom,bimc-bwmon5"; + reg = <0x90CE000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npu_llcc_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + npudsp_npu_ddr_bw: qcom,npudsp-npu-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = ; + operating-points-v2 = <&suspendable_ddr_bw_opp_table>; + }; + + npudsp_npu_ddr_bwmon: qcom,npudsp-npu-ddr-bwmon@70200 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x00070300 0x300>, <0x00070200 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + clocks = <&gcc GCC_NPU_BWMON_CFG_AHB_CLK>, + <&gcc GCC_NPU_BWMON_AXI_CLK>, + <&gcc GCC_NPU_BWMON2_AXI_CLK>; + clock-names = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,bwmon_clks = "npu_bwmon_ahb", "npu_bwmon_axi", + "npu_bwmon2_axi"; + qcom,msm_bus = <154 512>; + qcom,msm_bus_name = "npu_bwmon_cdsp"; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&npudsp_npu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu0_llcc_ddr_lat: qcom,cpu0-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_memlat_cpugrp: qcom,cpu0-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + + cpu0_cpu_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 672000 300000000 >, + < 940800 556800000 >, + < 1228800 806400000 >, + < 1459200 940800000 >, + < 1728000 1420000000 >; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 1228800 MHZ_TO_MBPS(300, 16) >, + < 1459200 MHZ_TO_MBPS(466, 16) >, + < 1728000 MHZ_TO_MBPS(600, 16) >; + }; + + cpu0_llcc_ddr_latmon: qcom,cpu0-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 672000 MHZ_TO_MBPS( 300, 4) >, + < 940800 MHZ_TO_MBPS( 451, 4) >, + < 1228800 MHZ_TO_MBPS( 547, 4) >, + < 1459200 MHZ_TO_MBPS( 768, 4) >, + < 1728000 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3 &CPU4 &CPU5>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 672000 MHZ_TO_MBPS( 300, 4) >, + < 1228800 MHZ_TO_MBPS( 451, 4) >, + < 1459200 MHZ_TO_MBPS( 547, 4) >, + < 1728000 MHZ_TO_MBPS( 768, 4) >; + }; + }; + + cpu6_cpu_llcc_lat: qcom,cpu6-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&llcc_bw_opp_table>; + }; + + cpu6_llcc_ddr_lat: qcom,cpu6-llcc-ddr-lat { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu6_cpu_ddr_latfloor: qcom,cpu6-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu7_cpu_ddr_latfloor: qcom,cpu7-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu4_memlat_cpugrp: qcom,cpu4-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU6 &CPU7>; + + cpu6_cpu_l3_latmon: qcom,cpu6-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6>; + qcom,target-dev = <&cpu6_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 940800 556800000 >, + < 1228800 806400000 >, + < 1708800 1190400000 >, + < 1900800 1382400000 >, + < 2323200 1420000000 >; + }; + + cpu7_cpu_l3_latmon: qcom,cpu7-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU7>; + qcom,target-dev = <&cpu7_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 940800 556800000 >, + < 1228800 806400000 >, + < 1708800 1190400000 >, + < 1900800 1382400000 >, + < 2323200 1420000000 >; + }; + + cpu6_cpu_llcc_latmon: qcom,cpu6-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 672000 MHZ_TO_MBPS( 300, 16) >, + < 940800 MHZ_TO_MBPS( 466, 16) >, + < 1228000 MHZ_TO_MBPS( 600, 16) >, + < 1708800 MHZ_TO_MBPS( 806, 16) >, + < 2350000 MHZ_TO_MBPS( 933, 16) >, + < 3000000 MHZ_TO_MBPS(1066, 16) >; + }; + + cpu6_llcc_ddr_latmon: qcom,cpu6-llcc-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU6 &CPU7>; + qcom,target-dev = <&cpu6_llcc_ddr_lat>; + qcom,cachemiss-ev = <0x1000>; + qcom,core-dev-table = + < 672000 MHZ_TO_MBPS( 451, 4) >, + < 940800 MHZ_TO_MBPS( 547, 4) >, + < 1228000 MHZ_TO_MBPS(1017, 4) >, + < 1708800 MHZ_TO_MBPS(1555, 4) >, + < 2350000 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; + }; + + cpu6_computemon: qcom,cpu6-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU6>; + qcom,target-dev = <&cpu6_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 672000 MHZ_TO_MBPS( 300, 4) >, + < 1228800 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1708800 MHZ_TO_MBPS(1017, 4) >, + < 2350000 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; + }; + + cpu7_computemon: qcom,cpu7-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU7>; + qcom,target-dev = <&cpu7_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 672000 MHZ_TO_MBPS( 300, 4) >, + < 1228800 MHZ_TO_MBPS( 547, 4) >, + < 1516800 MHZ_TO_MBPS( 768, 4) >, + < 1708800 MHZ_TO_MBPS(1017, 4) >, + < 2350000 MHZ_TO_MBPS(1804, 4) >, + < 3000000 MHZ_TO_MBPS(2092, 4) >; + }; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-platform-type-msm; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; + }; + + ipa_hw: qcom,ipa@1e00000 { + compatible = "qcom,ipa"; + reg = <0x1e00000 0x84000>, + <0x1e04000 0x23000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = , + ; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <18>; /* IPA core version = IPAv4.7 */ + qcom,ipa-hw-mode = <0>; + qcom,platform-type = <1>; /* MSM platform */ + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,ipa-wdi2_over_gsi; + qcom,use-ipa-pm; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,bandwidth-vote-for-ipa; + qcom,ipa-endp-delay-wa; + qcom,use-64-bit-dma-mask; + qcom,msm-bus,name = "ipa"; + qcom,wan-use-skb-page; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <5>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + , + , + , + , + , + + /* SVS2 */ + , + , + , + , + , + + /* SVS */ + , + , + , + , + , + + /* NOMINAL */ + , + , + , + , + , + + /* TURBO */ + , + , + , + , + ; + + + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x0520 0x0>; + qcom,iommu-dma-addr-pool = <0x20000000 0x40000000>; + /* modem tables in IMEM */ + qcom,additional-mapping = <0x146a9000 0x146a9000 0x2000>; + qcom,iommu-dma = "fastmap"; + qcom,ipa-q6-smem-size = <26624>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x0521 0x0>; + /* ipa-uc ram */ + qcom,additional-mapping = <0x1ea0000 0x1ea0000 0x80000>; + qcom,iommu-dma = "fastmap"; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x0522 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0x20000000>; + qcom,iommu-dma = "fastmap"; + }; + + icnss: qcom,icnss@18800000 { + compatible = "qcom,icnss"; + reg = <0x18800000 0x800000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_ipa"; + iommus = <&apps_smmu 0xC0 0x1>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + qcom,wlan-msa-fixed-region = <&pil_wlan_fw_mem>; + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-faults = "stall-disable", "HUPCF", "non-fatal"; + vdd-cx-mx-supply = <&L1A>; + vdd-1.8-xo-supply = <&L14A>; + vdd-1.3-rfa-supply = <&L2C>; + vdd-3.3-ch1-supply = <&L11C>; + vdd-3.3-ch0-supply = <&L10C>; + qcom,vdd-cx-mx-config = <0 0>; + qcom,vdd-3.3-ch1-config = <3000000 3312000>; + qcom,vdd-3.3-ch0-config = <3000000 3312000>; + qcom,smp2p_map_wlan_1_in { + interrupts-extended = <&smp2p_wlan_1_in 0 0>, + <&smp2p_wlan_1_in 1 0>; + interrupt-names = "qcom,smp2p-force-fatal-error", + "qcom,smp2p-early-crash-ind"; + }; + }; + + qcom,npu@9800000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x9800000 0x800000>; + status = "ok"; + qcom,pas-id = <23>; + qcom,firmware-name = "npu"; + memory-region = <&pil_npu_mem>; + + /* Outputs to npu */ + qcom,smem-states = <&npu_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + qfprom: qfprom@780000 { + compatible = "qcom,qfprom"; + reg = <0x00780000 0x7000>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + ranges; + + gpu_speed_bin: gpu_speed_bin@1ea { + reg = <0x1ea 0x2>; + bits = <5 8>; + }; + + gpu_gaming_bin: gpu_gaming_bin@212 { + reg = <0x212 0x1>; + bits = <0 1>; + }; + + gpu_lm_efuse: gpu_lm_efuse@45c8 { + reg = <0x45c8 0x4>; + }; + + adsp_variant: adsp_variant@210 { + reg = <0x213 0x1>; + bits = <1 2>; + }; + + iris_efuse: iris@6008 { + reg = <0x6008 0x4>; + }; + + npu_efuse: npu@6010 { + reg = <0x6010 0x4>; + }; + + feat_conf10: feat_conf10@602c { + reg = <0x602c 0x4>; + }; + + stm_debug_fuse: stm@20f0 { + reg = <0x20f0 0x4>; + }; + }; + + qcom,demux { + compatible = "qcom,demux"; + }; +}; + +#include "lito-pinctrl.dtsi" +#include "lito-pm.dtsi" +#include "lito-gdsc.dtsi" +#include "msm-arm-smmu-lito.dtsi" +#include "lito-regulators.dtsi" +#include "lito-smp2p.dtsi" +#include "lito-usb.dtsi" +#include "lito-ion.dtsi" +#include "lito-vidc.dtsi" +#include "lito-bus.dtsi" +#include "lito-gpu.dtsi" +#include "lito-thermal.dtsi" +#include "lito-npu.dtsi" +#include "msm-rdbg.dtsi" +#include "ipcc-test-lito.dtsi" + +&ufs_phy_gdsc { + status = "ok"; +}; + +&usb30_prim_gdsc { + status = "ok"; + qcom,retain-regs; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc { + status = "ok"; +}; + +&bps_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&ipe_0_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&ipe_1_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&ife_0_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + status = "ok"; +}; + +&ife_1_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + status = "ok"; +}; + +&titan_top_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_CAMERA_AHB_CLK>; + status = "ok"; +}; + +&mdss_core_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_DISP_AHB_CLK>; + status = "ok"; +}; + +&gpu_cx_gdsc { + parent-supply = <&VDD_CX_LEVEL>; + vdd_parent-supply = <&VDD_CX_LEVEL>; + status = "ok"; +}; + +&gpu_gx_gdsc { + parent-supply = <&VDD_GFX_LEVEL>; + vdd_parent-supply = <&VDD_GFX_LEVEL>; + status = "ok"; +}; + +&npu_core_gdsc { + status = "ok"; + qcom,retain-regs; +}; + +&mvsc_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + status = "ok"; +}; + +&mvs0_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&mvs1_gdsc { + clock-names = "ahb_clk"; + clocks = <&gcc GCC_VIDEO_AHB_CLK>; + qcom,support-hw-trigger; + status = "ok"; +}; + +#include "lito-qupv3.dtsi" +#include "lito-coresight.dtsi" +#include "camera/lito-camera.dtsi" +#include "lito-audio.dtsi" + +&qupv3_se9_i2c { + status = "ok"; + #include "pm8008.dtsi" +}; + +&qupv3_se7_i2c { + status = "ok"; + Goodix-gt9886@5D { + compatible = "Goodix-gt9886"; + reg = <0x5D>; + project-name = "20801"; + chip-name = "GT885"; + module_id = <7>; + /* Interrupt && Irq-gpio */ + interrupt-parent = <&tlmm>; + interrupts = <9 0x2002>; + + /* Power Config */ + vdd_2v8-supply = <&pm8150_l13>; + //vcc_1v8-supply = <&pm8150a_l1>; + vdd_2v8_volt = <3008000>; + + /* Other HW Resource */ + irq-gpio = <&tlmm 9 0x2002>; + reset-gpio = <&tlmm 8 0x1>; + pinctrl-names = "pin_set_high", "pin_set_low"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_reset_suspend>; + + touchpanel,max-num-support = <10>; + touchpanel,tx-rx-num = <15 34>; + touchpanel,panel-coords = <1080 2400>; + touchpanel,display-coords = <1080 2400>; + + /* SW Support Feature Control */ + black_gesture_support = <1>; + //fw_edge_limit_support; + //charger_pump_support; + //spurious_fingerprint_support; + //fw_update_app_support; + //smart_gesture_support; + //game_switch_support = <1>; + face_detect_support = <1>; + lcd_refresh_rate_switch = <1>; + touch_hold_support = <1>; + charge_detect_support = <1>; + register-is-16bit = <1>; + //module_id_support = <1>; + //kernel_grip_support; + //health_monitor_support; + //fingerprint_underscreen_support; + //headset_pump_support; + //pressure_report_support; + + /* + *Virtual Key Config: + *1:touchpanel,button-type: + *virtualkey_type: + *Type 1: using board_properties + *Type 2: using same IC (button zone&& touch zone are seprate) + *Type 3: using diffrent IC (button zone&& touch zone are seprate) + *Type 4: No need of virtual key process + *supportted_button-map:select|menu|home|back + * + *2:touchpanel,button-map + *type (X1,Y1)(X2,Y2)(X3,Y3)(Width_X,Hight_Y)--Only when button-type is 0 + */ + touchpanel,button-type = <4>; + touchpanel.button-TRx = <0 0>; + }; +}; +&qupv3_se2_2uart { + status = "ok"; +}; + +&qupv3_se5_4uart { + status = "ok"; +}; + +&pm8008_8 { + /* PM8008 IRQ STAT */ + interrupt-parent = <&tlmm>; + interrupts = <145 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_active &pm8008_interrupt>; +}; + +&pm8008_regulators { + vdd_l1_l2-supply = <&S8C>; + vdd_l3_l4-supply = <&BOB>; + vdd_l5-supply = <&BOB>; + vdd_l6-supply = <&S5A>; + vdd_l7-supply = <&S5A>; +}; + +&L1P { + regulator-max-microvolt = <1056000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <209000>; +}; + +&L2P { + regulator-max-microvolt = <1104000>; + /* Reduced the headroom by 16mV for AHC */ + qcom,min-dropout-voltage = <209000>; +}; + +&L3P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <136000>; +}; + +&L4P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2904000>; + qcom,min-dropout-voltage = <160000>; +}; + +&L5P { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + qcom,min-dropout-voltage = <300000>; +}; + +&L6P { + regulator-max-microvolt = <1800000>; + qcom,min-dropout-voltage = <184000>; +}; + +&L7P { + regulator-max-microvolt = <1800000>; + qcom,min-dropout-voltage = <200000>; +}; +#include "lito-sde.dtsi" +#include "lito-sde-pll.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-660.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7bdd448d45fa95cebeb9e69a73d7b7168ecfd5f9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-660.dtsi @@ -0,0 +1,205 @@ +#include +#include +#include +#include +#include + +&soc { + anoc2_smmu: arm,smmu-anoc2@16c0000 { + compatible = "qcom,smmu-v2"; + reg = <0x16c0000 0x40000>; + #iommu-cells = <1>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,regulator-names = "vdd"; + #global-interrupts = <2>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&clock_rpmcc AGGR2_NOC_SMMU_CLK>; + clock-names = "smmu_aggr2_noc_clk"; + #clock-cells = <1>; + }; + + lpass_q6_smmu: arm,smmu-lpass_q6@5100000 { + compatible = "qcom,smmu-v2"; + reg = <0x5100000 0x40000>; + #iommu-cells = <1>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,regulator-names = "vdd"; + #global-interrupts = <2>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + vdd-supply = <&gdsc_hlos1_vote_lpass_adsp>; + clocks = <&clock_gcc HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>; + clock-names = "lpass_q6_smmu_clk"; + #clock-cells = <1>; + }; + + mmss_bimc_smmu: arm,smmu-mmss@cd00000 { + compatible = "qcom,smmu-v2"; + reg = <0xcd00000 0x40000>; + #iommu-cells = <1>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,regulator-names = "vdd"; + #global-interrupts = <2>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + vdd-supply = <&gdsc_bimc_smmu>; + clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>; + clock-names = "mmss_mnoc_ahb_clk", + "mmssnoc_axi_clk", + "mmss_bimc_smmu_ahb_clk", + "mmss_bimc_smmu_axi_clk"; + #clock-cells = <1>; + qcom,bus-master-id = ; + }; + + kgsl_smmu: arm,smmu-kgsl@5040000 { + compatible = "qcom,smmu-v2"; + reg = <0x5040000 0x10000>; + #iommu-cells = <1>; + qcom,dynamic; + qcom,use-3-lvl-tables; + qcom,disable-atos; + qcom,regulator-names = "vdd"; + #global-interrupts = <2>; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,deferred-regulator-disable-delay = <80>; + vdd-supply = <&gdsc_gpu_cx>; + clocks = <&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gcc GCC_BIMC_GFX_CLK>, + <&clock_gcc GCC_GPU_BIMC_GFX_CLK>; + clock-names = "gcc_gpu_cfg_ahb_clk", + "gcc_bimc_gfx_clk", + "gcc_gpu_bimc_gfx_clk"; + #clock-cells = <1>; + }; + + turing_q6_smmu: arm,smmu-turing_q6@5180000 { + compatible = "qcom,smmu-v2"; + reg = <0x5180000 0x40000>; + #iommu-cells = <1>; + qcom,register-save; + qcom,skip-init; + qcom,regulator-names = "vdd"; + #global-interrupts = <2>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + vdd-supply = <&gdsc_hlos1_vote_turing_adsp>; + clocks = <&clock_gcc HLOS1_VOTE_TURING_ADSP_SMMU_CLK>; + clock-names = "turing_q6_smmu_clk"; + #clock-cells = <1>; + }; + + iommu_test_device { + compatible = "iommu-debug-test"; + /* + * 42 shouldn't be used by anyone on the mmss_smmu. We just + * need _something_ here to get this node recognized by the + * SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&mmss_bimc_smmu 42>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-bengal.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-bengal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4e352f8f4bf9f3d8a7bf1fea0dabc2a71eb47792 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-bengal.dtsi @@ -0,0 +1,241 @@ +#include +#include + +&soc { + kgsl_smmu: kgsl-smmu@0x59a0000 { + status = "okay"; + compatible = "qcom,qsmmu-v500"; + reg = <0x59a0000 0x10000>, + <0x59c2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,dynamic; + qcom,skip-init; + qcom,testbus-version = <1>; + qcom,no-dynamic-asid; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + + clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gcc_gpu_memnoc_gfx", + "gcc_gpu_snoc_dvm_gfx", + "gpu_cc_ahb", + "gpu_cc_hlos1_vote_gpu_smmu_clk"; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + ; + qcom,actlr = + /* All CBs of GFX: +15 deep PF */ + <0x0 0x3ff 0x30B>; + + gfx_0_tbu: gfx_0_tbu@0x59c5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x59c5000 0x1000>, + <0x59c2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + }; + }; + + apps_smmu: apps-smmu@0xc600000 { + status = "okay"; + compatible = "qcom,qsmmu-v500"; + reg = <0xc600000 0x80000>, + <0xc782000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + + qcom,actlr = + /* For rt TBU +3 deep PF */ + <0x400 0x3ff 0x103>, + /* For nrt TBU +3 deep PF */ + <0x800 0x3ff 0x103>; + + anoc_1_tbu: anoc_1_tbu@0xc785000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc785000 0x1000>, + <0xc782200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + + }; + + mm_rt_tbu: mm_rt_tbu@0xc789000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc789000 0x1000>, + <0xc782208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + }; + + mm_nrt_tbu: mm_nrt_tbu@0xc78d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc78d000 0x1000>, + <0xc782210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + + }; + + cdsp_tbu: cdsp_tbu@0xc791000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc791000 0x1000>, + <0xc782218 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0xc00 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_turing_mmu_tbu0_gdsc>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + }; + }; + + kgsl_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&kgsl_smmu 0x7 0x0>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x1e0 0>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x1e1 0>; + dma-coherent; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-impl-defs-660.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-impl-defs-660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..532632b1b3256c3d7680fd25e6eb0f6a7208a504 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-impl-defs-660.dtsi @@ -0,0 +1,397 @@ +&kgsl_smmu { + attach-impl-defs = <0x6000 0x2378>, + <0x6060 0x1055>, + <0x678c 0x8>, + <0x6794 0x28>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x11000>, + <0x6930 0x800>, + <0x6960 0xffffffff>, + <0x6b64 0x1a5551>, + <0x6b68 0x9a82a382>; +}; + +&lpass_q6_smmu { + attach-impl-defs = <0x6000 0x2378>, + <0x6060 0x1055>, + <0x6070 0xe0>, + <0x6074 0xe0>, + <0x6078 0xe0>, + <0x607c 0xe0>, + <0x60f0 0xc0>, + <0x60f4 0xc8>, + <0x60f8 0xd0>, + <0x60fc 0xd8>, + <0x6170 0x0>, + <0x6174 0x30>, + <0x6178 0x60>, + <0x617c 0x90>, + <0x6270 0x0>, + <0x6274 0x2>, + <0x6278 0x4>, + <0x627c 0x6>, + <0x62f0 0x8>, + <0x62f4 0xe>, + <0x62f8 0x14>, + <0x62fc 0x1a>, + <0x6370 0x20>, + <0x6374 0x40>, + <0x6378 0x60>, + <0x637c 0x80>, + <0x6784 0x0>, + <0x678c 0x10>, + <0x67a0 0x0>, + <0x67a4 0x0>, + <0x67a8 0x20>, + <0x67b0 0x0>, + <0x67b4 0x8>, + <0x67b8 0xc8>, + <0x67d0 0x4>, + <0x67dc 0x8>, + <0x67e0 0x8>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x202>, + <0x6928 0x10a00>, + <0x6930 0x500>, + <0x6960 0xffffffff>, + <0x6b64 0x121151>, + <0x6b68 0xea800080>, + <0x6c00 0x0>, + <0x6c04 0x0>, + <0x6c08 0x0>, + <0x6c0c 0x0>, + <0x6c10 0x1>, + <0x6c14 0x1>, + <0x6c18 0x1>, + <0x6c1c 0x1>, + <0x6c20 0x2>, + <0x6c24 0x2>, + <0x6c28 0x2>, + <0x6c2c 0x2>, + <0x6c30 0x3>, + <0x6c34 0x3>, + <0x6c38 0x3>, + <0x6c3c 0x3>; +}; + +&turing_q6_smmu { + attach-impl-defs = <0x6000 0x2378>, + <0x6060 0x1055>, + <0x6070 0xe0>, + <0x6074 0xe0>, + <0x6078 0xe0>, + <0x607c 0xe0>, + <0x60f0 0xc0>, + <0x60f4 0xc8>, + <0x60f8 0xd0>, + <0x60fc 0xd8>, + <0x6170 0x0>, + <0x6174 0x30>, + <0x6178 0x60>, + <0x617c 0x90>, + <0x6270 0x0>, + <0x6274 0x2>, + <0x6278 0x4>, + <0x627c 0x6>, + <0x62f0 0x8>, + <0x62f4 0xe>, + <0x62f8 0x14>, + <0x62fc 0x1a>, + <0x6370 0x20>, + <0x6374 0x40>, + <0x6378 0x60>, + <0x637c 0x80>, + <0x6784 0x0>, + <0x678c 0x10>, + <0x67a0 0x0>, + <0x67a4 0x0>, + <0x67a8 0x20>, + <0x67b0 0x0>, + <0x67b4 0x8>, + <0x67b8 0xc8>, + <0x67d0 0x4>, + <0x67dc 0x8>, + <0x67e0 0x8>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x202>, + <0x6928 0x10a00>, + <0x6930 0x500>, + <0x6960 0xffffffff>, + <0x6b64 0x121151>, + <0x6b68 0xea800080>, + <0x6c00 0x0>, + <0x6c04 0x0>, + <0x6c08 0x0>, + <0x6c0c 0x0>, + <0x6c10 0x1>, + <0x6c14 0x1>, + <0x6c18 0x1>, + <0x6c1c 0x1>, + <0x6c20 0x2>, + <0x6c24 0x2>, + <0x6c28 0x2>, + <0x6c2c 0x2>, + <0x6c30 0x3>, + <0x6c34 0x3>, + <0x6c38 0x3>, + <0x6c3c 0x3>; +}; + +&mmss_bimc_smmu { + attach-impl-defs = <0x6000 0x2378>, + <0x6060 0x1055>, + <0x678c 0x28>, + <0x6794 0xe0>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x11002>, + <0x6930 0x800>, + <0x6960 0xffffffff>, + <0x6964 0xffffffff>, + <0x6968 0xffffffff>, + <0x696c 0xffffffff>, + <0x6b48 0x330330>, + <0x6b4c 0x81>, + <0x6b50 0x3333>, + <0x6b54 0x3333>, + <0x6b64 0x1a5555>, + <0x6b68 0xbaaa892a>, + <0x6b70 0x10100202>, + <0x6b74 0x10100202>, + <0x6b78 0x10100000>, + <0x6b80 0x20042004>, + <0x6b84 0x20042004>; +}; + +&anoc2_smmu { + attach-impl-defs = <0x6000 0x2378>, + <0x6060 0x1055>, + <0x6070 0xf>, + <0x6074 0x23>, + <0x6078 0x37>, + <0x607c 0x39>, + <0x6080 0x3f>, + <0x6084 0x6f>, + <0x6088 0x74>, + <0x608c 0x92>, + <0x6090 0xb0>, + <0x6094 0xf0>, + <0x6098 0xf0>, + <0x609c 0xf0>, + <0x60f0 0x0>, + <0x60f4 0x1>, + <0x60f8 0x3>, + <0x60fc 0x4>, + <0x6100 0x6>, + <0x6104 0x8>, + <0x6108 0x9>, + <0x610c 0xb>, + <0x6110 0xd>, + <0x6114 0xf>, + <0x6118 0xf>, + <0x611c 0xf>, + <0x6170 0x0>, + <0x6174 0x0>, + <0x6178 0x0>, + <0x617c 0x0>, + <0x6180 0x0>, + <0x6184 0x0>, + <0x6188 0x0>, + <0x618c 0x0>, + <0x6190 0x0>, + <0x6194 0x0>, + <0x6198 0x0>, + <0x619c 0x0>, + <0x6270 0x0>, + <0x6274 0x1>, + <0x6278 0x2>, + <0x627c 0x4>, + <0x6280 0x4>, + <0x6284 0x6>, + <0x6288 0x6>, + <0x628c 0xa>, + <0x6290 0xc>, + <0x6294 0xc>, + <0x6298 0xc>, + <0x629c 0xc>, + <0x62f0 0xc>, + <0x62f4 0x12>, + <0x62f8 0x18>, + <0x62fc 0x1a>, + <0x6300 0x1d>, + <0x6304 0x23>, + <0x6308 0x24>, + <0x630c 0x28>, + <0x6310 0x2c>, + <0x6314 0x30>, + <0x6318 0x30>, + <0x631c 0x30>, + <0x6370 0x30>, + <0x6374 0x35>, + <0x6378 0x3a>, + <0x637c 0x3e>, + <0x6380 0x46>, + <0x6384 0x50>, + <0x6388 0x55>, + <0x638c 0x5d>, + <0x6390 0x67>, + <0x6394 0x80>, + <0x6398 0x80>, + <0x639c 0x80>, + <0x678c 0x12>, + <0x6794 0x32>, + <0x67a0 0x0>, + <0x67a4 0xe1>, + <0x67a8 0xf0>, + <0x67b0 0x0>, + <0x67b4 0xc>, + <0x67b8 0x9c>, + <0x67d0 0x0>, + <0x67dc 0x4>, + <0x67e0 0x8>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6b48 0x330330>, + <0x6b4c 0x81>, + <0x6b50 0x1313>, + <0x6b64 0x121155>, + <0x6b68 0xcaa84920>, + <0x6b70 0xc0c0000>, + <0x6b74 0x8080000>, + <0x6b78 0x8080000>, + <0x6b80 0x20002000>, + <0x6b84 0x20002000>, + <0x6c00 0x5>, + <0x6c04 0x0>, + <0x6c08 0x5>, + <0x6c0c 0x0>, + <0x6c10 0x5>, + <0x6c14 0x0>, + <0x6c18 0x5>, + <0x6c1c 0x0>, + <0x6c20 0x5>, + <0x6c24 0x0>, + <0x6c28 0x0>, + <0x6c2c 0x0>, + <0x6c30 0x0>, + <0x6c34 0x0>, + <0x6c38 0x0>, + <0x6c3c 0x0>, + <0x6c40 0x0>, + <0x6c44 0x0>, + <0x6c48 0x0>, + <0x6c4c 0x0>, + <0x6c50 0x0>, + <0x6c54 0x0>, + <0x6c58 0x0>, + <0x6c5c 0x0>, + <0x6c60 0x0>, + <0x6c64 0x0>, + <0x6c68 0x0>, + <0x6c6c 0x0>, + <0x6c70 0x0>, + <0x6c74 0x0>, + <0x6c78 0x0>, + <0x6c7c 0x0>, + <0x6c80 0x0>, + <0x6c84 0x0>, + <0x6c88 0x0>, + <0x6c8c 0x0>, + <0x6c90 0x0>, + <0x6c94 0x0>, + <0x6c98 0x0>, + <0x6c9c 0x0>, + <0x6ca0 0x0>, + <0x6ca4 0x0>, + <0x6ca8 0x0>, + <0x6cac 0x0>, + <0x6cb0 0x0>, + <0x6cb4 0x0>, + <0x6cb8 0x0>, + <0x6cbc 0x0>, + <0x6cc0 0x0>, + <0x6cc4 0x0>, + <0x6cc8 0x0>, + <0x6ccc 0x0>, + <0x6cd0 0x0>, + <0x6cd4 0x0>, + <0x6cd8 0x0>, + <0x6cdc 0x0>, + <0x6ce0 0x0>, + <0x6ce4 0x0>, + <0x6ce8 0x0>, + <0x6cec 0x0>, + <0x6cf0 0x0>, + <0x6cf4 0x0>, + <0x6cf8 0x0>, + <0x6cfc 0x0>, + <0x6d00 0x3>, + <0x6d04 0x4>, + <0x6d08 0x4>, + <0x6d0c 0x0>, + <0x6d10 0x8>, + <0x6d14 0x8>, + <0x6d18 0x3>, + <0x6d1c 0x2>, + <0x6d20 0x4>, + <0x6d24 0x0>, + <0x6d28 0x4>, + <0x6d2c 0x0>, + <0x6d30 0x7>, + <0x6d34 0x0>, + <0x6d38 0x6>, + <0x6d3c 0x0>, + <0x6d40 0x0>, + <0x6d44 0x1>, + <0x6d48 0x4>, + <0x6d4c 0x0>, + <0x6d50 0x4>, + <0x6d54 0x0>, + <0x6d58 0x4>, + <0x6d5c 0x0>, + <0x6d60 0x0>, + <0x6d64 0x0>, + <0x6d68 0x0>, + <0x6d6c 0x0>, + <0x6d70 0x0>, + <0x6d74 0x0>, + <0x6d78 0x0>, + <0x6d7c 0x0>, + <0x6d80 0x0>, + <0x6d84 0x0>, + <0x6d88 0x0>, + <0x6d8c 0x0>, + <0x6d90 0x0>, + <0x6d94 0x0>, + <0x6d98 0x0>, + <0x6d9c 0x0>, + <0x6da0 0x0>, + <0x6da4 0x0>, + <0x6da8 0x0>, + <0x6dac 0x0>, + <0x6db0 0x0>, + <0x6db4 0x0>, + <0x6db8 0x0>, + <0x6dbc 0x0>, + <0x6dc0 0x0>, + <0x6dc4 0x0>, + <0x6dc8 0x0>, + <0x6dcc 0x0>, + <0x6dd0 0x0>, + <0x6dd4 0x0>, + <0x6dd8 0x0>, + <0x6ddc 0x0>, + <0x6de0 0x0>, + <0x6de4 0x0>, + <0x6de8 0x0>, + <0x6dec 0x0>, + <0x6df0 0x0>, + <0x6df4 0x0>, + <0x6df8 0x0>, + <0x6dfc 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-kona.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-kona.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5ce2401e0fedb39dcfce788b17ef41d9e36590a3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-kona.dtsi @@ -0,0 +1,439 @@ +#include + +&soc { + kgsl_smmu: kgsl-smmu@3da0000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x3DA0000 0x10000>, + <0x3DC2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,no-dynamic-asid; + #global-interrupts = <2>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + + clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&clock_gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&clock_gpucc GPU_CC_AHB_CLK>; + clock-names = "gcc_gpu_memnoc_gfx", + "gcc_gpu_snoc_dvm_gfx", + "gpu_cc_ahb"; + + interrupts = , + , + , + , + , + , + , + , + , + ; + + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + qcom,actlr = + /* All CBs of GFX: +15 deep PF */ + <0x2 0x400 0x32B>, + <0x4 0x400 0x32B>, + <0x5 0x400 0x32B>, + <0x7 0x400 0x32B>, + <0x0 0x401 0x32B>; + + gfx_0_tbu: gfx_0_tbu@3dc5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x3DC5000 0x1000>, + <0x3DC2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + }; + + gfx_1_tbu: gfx_1_tbu@3dc9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x3DC9000 0x1000>, + <0x3DC2208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + }; + }; + + apps_smmu: apps-smmu@15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x100000>, + <0x15182000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <2>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + qcom,actlr = + /* For HF-0 TBU +3 deep PF */ + <0x800 0x3ff 0x103>, + /* For HF-1 TBU +3 deep PF */ + <0xC00 0x3ff 0x103>, + /* For SF-0 TBU +3 deep PF */ + <0x2000 0x3ff 0x103>, + /* For SF-1 TBU +3 deep PF */ + <0x2400 0x3ff 0x103>, + /* For NPU +3 deep PF */ + <0x1081 0x400 0x103>, + <0x1082 0x400 0x103>, + <0x1085 0x400 0x103>, + <0x10a1 0x400 0x103>, + <0x10a2 0x400 0x103>, + <0x10a5 0x400 0x103>; + + anoc_1_tbu: anoc_1_tbu@15185000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15185000 0x1000>, + <0x15182200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + anoc_2_tbu: anoc_2_tbu@15189000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15189000 0x1000>, + <0x15182208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_0_tbu: mnoc_hf_0_tbu@1518d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x1518D000 0x1000>, + <0x15182210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>; + qcom,msm-bus,name = "mnoc_hf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_1_tbu: mnoc_hf_1_tbu@15191000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15191000 0x1000>, + <0x15182218 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0xc00 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc>; + qcom,msm-bus,name = "mnoc_hf_1_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + compute_dsp_1_tbu: compute_dsp_1_tbu@15195000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15195000 0x1000>, + <0x15182220 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1000 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + compute_dsp_0_tbu: compute_dsp_0_tbu@15199000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15199000 0x1000>, + <0x15182228 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1400 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + }; + + adsp_tbu: adsp_tbu@1519d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x1519D000 0x1000>, + <0x15182230 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1800 0x400>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + anoc_1_pcie_tbu: anoc_1_pcie_tbu@151a1000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x151A1000 0x1000>, + <0x15182238 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1c00 0x400>; + clock-names = "gcc_aggre_noc_pcie_tbu_clk"; + clocks = <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + }; + + mnoc_sf_0_tbu: mnoc_sf_0_tbu@151a5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x151A5000 0x1000>, + <0x15182240 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x2000 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc>; + qcom,msm-bus,name = "mnoc_sf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_sf_1_tbu: mnoc_sf_1_tbu@151a9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x151A9000 0x1000>, + <0x15182248 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x2400 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf1_gdsc>; + qcom,msm-bus,name = "mnoc_sf_1_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + }; + + kgsl_iommu_test_device { + compatible = "iommu-debug-test"; + iommus = <&kgsl_smmu 0x7 0>; + qcom,iommu-dma = "disabled"; + }; + + kgsl_iommu_coherent_test_device { + status = "disabled"; + compatible = "iommu-debug-test"; + iommus = <&kgsl_smmu 0x9 0>; + qcom,iommu-dma = "disabled"; + dma-coherent; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + iommus = <&apps_smmu 0x21 0>; + qcom,iommu-dma = "disabled"; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + iommus = <&apps_smmu 0x23 0>; + qcom,iommu-dma = "disabled"; + dma-coherent; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-lagoon.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-lagoon.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6d7eabccec025e0b52ba410d36d8fff61e6f9c16 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-lagoon.dtsi @@ -0,0 +1,318 @@ +#include + +&soc { + kgsl_smmu: arm,smmu-kgsl@3d40000 { + status = "ok"; + compatible = "qcom,smmu-v2"; + reg = <0x3d40000 0x10000>; + #iommu-cells = <1>; + qcom,use-3-lvl-tables; + #global-interrupts = <2>; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + clock-names = "gcc_gpu_memnoc_gfx_clk"; + clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>; + interrupts = , + , + , + , + , + , + , + , + , + ; + attach-impl-defs = + <0x6000 0x2378>, + <0x6060 0x1055>, + <0x678c 0x8>, + <0x6794 0x28>, + <0x6800 0x6>, + <0x6900 0x3ff>, + <0x6924 0x204>, + <0x6928 0x11000>, + <0x6930 0x800>, + <0x6960 0xffffffff>, + <0x6b64 0x1a5551>, + <0x6b68 0x9a82a382>; + }; + + apps_smmu: apps-smmu@15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x100000>, + <0x15182000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + qcom,actlr = + /* For HF-0 TBU +3 deep PF */ + <0x800 0x3ff 0x103>, + /* For SF-0 TBU +3 deep PF */ + <0xC00 0x3ff 0x103>, + /* For NPU +3 deep PF */ + <0x1440 0x2f 0x103>, + <0x1480 0xf 0x103>; + + anoc_1_tbu: anoc_1_tbu@15185000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15185000 0x1000>, + <0x15182200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + anoc_2_tbu: anoc_2_tbu@15189000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15189000 0x1000>, + <0x15182208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_0_tbu: mnoc_hf_0_tbu@1518d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x1518d000 0x1000>, + <0x15182210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + interrupts = ; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>; + qcom,msm-bus,name = "mnoc_hf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_sf_0_tbu: mnoc_sf_0_tbu@15191000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15191000 0x1000>, + <0x15182218 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0xc00 0x400>; + interrupts = ; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>; + qcom,msm-bus,name = "mnoc_sf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + adsp_tbu: adsp_tbu@15195000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15195000 0x1000>, + <0x15182220 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1000 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + compute_dsp_0_tbu: compute_dsp_0_tbu@15199000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15199000 0x1000>, + <0x15182228 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1400 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + pcie_tbu: pcie_tbu@1519d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x1519d000 0x1000>, + <0x15182230 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1800 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + }; + + kgsl_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&kgsl_smmu 0x7>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x1 0>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x3 0>; + dma-coherent; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-lito.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-lito.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..7b0cc7d30414586a107f5579692853cc1e777cc7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-lito.dtsi @@ -0,0 +1,384 @@ +#include + +&soc { + kgsl_smmu: kgsl-smmu@3da0000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x3da0000 0x10000>, + <0x3dc2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,no-dynamic-asid; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + + clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gcc_gpu_memnoc_gfx", + "gcc_gpu_snoc_dvm_gfx", + "gpu_cc_ahb", + "gpu_cc_hlos1_vote_gpu_smmu_clk"; + + interrupts = , + , + , + , + , + , + , + , + ; + + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + qcom,actlr = + /* All CBs of GFX: +15 deep PF */ + <0x0 0x3ff 0x32B>, + <0x400 0x3ff 0x32B>; + + gfx_0_tbu: gfx_0_tbu@3dc5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x3dc5000 0x1000>, + <0x3dc2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + interrupts = ; + }; + + gfx_1_tbu: gfx_1_tbu@3dc9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x3dc9000 0x1000>, + <0x3dc2208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + interrupts = ; + }; + }; + + apps_smmu: apps-smmu@15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x100000>, + <0x15182000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + + qcom,actlr = + /* For HF-0 TBU +3 deep PF */ + <0x800 0x3ff 0x103>, + /* For HF-1 TBU +3 deep PF */ + <0xd00 0x5e0 0x103>, + <0xc80 0x5e0 0x103>, + <0xc20 0x5e0 0x103>, + <0xd20 0x5e0 0x103>, + <0xca0 0x5e0 0x103>, + <0xd40 0x5e0 0x103>, + <0xcc0 0x5e0 0x103>, + <0xf40 0x402 0x103>, + <0xf42 0x402 0x103>, + /* For SF-0 TBU +3 deep PF */ + <0x1000 0x3ff 0x103>, + /* For NPU +3 deep PF */ + <0x1861 0x400 0x103>, + <0x1862 0x400 0x103>, + <0x1863 0x404 0x103>, + <0x1864 0x400 0x103>, + <0x1865 0x400 0x103>, + <0x1868 0x400 0x103>; + + anoc_1_tbu: anoc_1_tbu@15185000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15185000 0x1000>, + <0x15182200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + anoc_2_tbu: anoc_2_tbu@15189000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15189000 0x1000>, + <0x15182208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_0_tbu: mnoc_hf_0_tbu@1518d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x1518D000 0x1000>, + <0x15182210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + interrupts = ; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>; + qcom,msm-bus,name = "mnoc_hf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_hf_1_tbu: mnoc_hf_1_tbu@15191000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15191000 0x1000>, + <0x15182218 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0xc00 0x400>; + interrupts = ; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc>; + qcom,msm-bus,name = "mnoc_hf_1_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + mnoc_sf_0_tbu: mnoc_sf_0_tbu@15195000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15195000 0x1000>, + <0x15182220 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1000 0x400>; + interrupts = ; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf0_gdsc>; + qcom,msm-bus,name = "mnoc_sf_0_tbu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + adsp_tbu: adsp_tbu@15199000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x15199000 0x1000>, + <0x15182228 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1400 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + compute_dsp_0_tbu: compute_dsp_0_tbu@1519d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x1519D000 0x1000>, + <0x15182230 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1800 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + + compute_dsp_1_tbu: compute_dsp_1_tbu@151a1000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x151A1000 0x1000>, + <0x15182238 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1c00 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + <0 0>, + , + , + <0 1000>; + }; + }; + + kgsl_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&kgsl_smmu 0x7 0x400>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x1 0>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x3 0>; + dma-coherent; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-scuba.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-scuba.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1d4df9efeffee562977a8b0689f69abeda1af297 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-arm-smmu-scuba.dtsi @@ -0,0 +1,221 @@ +#include +#include + +&soc { + kgsl_smmu: kgsl-smmu@0x59a0000 { + status = "okay"; + compatible = "qcom,qsmmu-v500"; + reg = <0x59a0000 0x10000>, + <0x59c2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,no-dynamic-asid; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + clocks = <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + clock-names = "gcc_gpu_memnoc_gfx", + "gcc_gpu_snoc_dvm_gfx", + "gpu_cc_ahb", + "gpu_cc_hlos1_vote_gpu_smmu_clk"; + #size-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + ; + + qcom,actlr = + /* ALL CBs of GFX: +15 deep PF */ + <0x0 0x3ff 0x30B>; + + gfx_0_tbu: gfx_0_tbu@0x59c5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x59c5000 0x1000>, + <0x59c2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + interrupts = ; + }; + }; + + apps_smmu: apps-smmu@0xc600000 { + status = "okay"; + compatible = "qcom,qsmmu-v500"; + reg = <0xc600000 0x80000>, + <0xc782000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + #global-interrupts = <1>; + #size-cells = <1>; + #address-cells = <1>; + ranges; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + + qcom,actlr = + /* For rt TBU +3 deep PF */ + <0x400 0x3ff 0x103>, + /* For nrt TBU +3 deep PF */ + <0x800 0x3ff 0x103>; + + anoc_1_tbu: anoc_1_tbu@0xc785000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc785000 0x1000>, + <0xc782200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + + }; + + mm_rt_tbu: mm_rt_tbu@0xc789000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc789000 0x1000>, + <0xc782208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + + }; + + mm_nrt_tbu: mm_nrt_tbu@0xc78d000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0xc78d000 0x1000>, + <0xc782210 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x800 0x400>; + interrupts = ; + qcom,msm-bus,name = "apps_smmu"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,active-only; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + + }; + + }; + + kgsl_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&kgsl_smmu 0x7 0x0>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x1E0 0x0>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + qcom,iommu-dma = "disabled"; + iommus = <&apps_smmu 0x1E1 0x0>; + dma-coherent; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-audio-lpass.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..360e984ab5d525fa1061aa08a94eeaffa753faf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-audio-lpass.dtsi @@ -0,0 +1,719 @@ +&soc { + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + compr: qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "regular"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + pcm_noirq: qcom,msm-pcm-dsp-noirq { + compatible = "qcom,msm-pcm-dsp-noirq"; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + trans_loopback: qcom,msm-transcode-loopback { + compatible = "qcom,msm-transcode-loopback"; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + dai_hdmi: qcom,msm-dai-q6-hdmi { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <8>; + }; + + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <0>; + }; + + dai_dp1: qcom,msm-dai-q6-dp1 { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <1>; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + loopback1: qcom,msm-pcm-loopback-low-latency { + compatible = "qcom,msm-pcm-loopback"; + qcom,msm-pcm-loopback-low-latency; + }; + + pcm_dtmf: qcom,msm-pcm-dtmf { + compatible = "qcom,msm-pcm-dtmf"; + }; + + msm_dai_mi2s: qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + dai_mi2s0: qcom,msm-dai-q6-mi2s-prim { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s1: qcom,msm-dai-q6-mi2s-sec { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <1>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s2: qcom,msm-dai-q6-mi2s-tert { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <2>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_mi2s3: qcom,msm-dai-q6-mi2s-quat { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <3>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s4: qcom,msm-dai-q6-mi2s-quin { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <4>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s5: qcom,msm-dai-q6-mi2s-senary { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <5>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + }; + + msm_dai_cdc_dma: qcom,msm-dai-cdc-dma { + compatible = "qcom,msm-dai-cdc-dma"; + wsa_cdc_dma_0_rx: qcom,msm-dai-wsa-cdc-dma-0-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45056>; + }; + + wsa_cdc_dma_0_tx: qcom,msm-dai-wsa-cdc-dma-0-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45057>; + }; + + wsa_cdc_dma_1_rx: qcom,msm-dai-wsa-cdc-dma-1-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45058>; + }; + + wsa_cdc_dma_1_tx: qcom,msm-dai-wsa-cdc-dma-1-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45059>; + }; + + wsa_cdc_dma_2_tx: qcom,msm-dai-wsa-cdc-dma-2-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45061>; + }; + + va_cdc_dma_0_tx: qcom,msm-dai-va-cdc-dma-0-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45089>; + }; + + va_cdc_dma_1_tx: qcom,msm-dai-va-cdc-dma-1-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45091>; + }; + + va_cdc_dma_2_tx: qcom,msm-dai-va-cdc-dma-2-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45093>; + }; + + rx_cdc_dma_0_rx: qcom,msm-dai-rx-cdc-dma-0-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45104>; + }; + + rx_cdc_dma_1_rx: qcom,msm-dai-rx-cdc-dma-1-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45106>; + }; + + rx_cdc_dma_2_rx: qcom,msm-dai-rx-cdc-dma-2-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45108>; + }; + + rx_cdc_dma_3_rx: qcom,msm-dai-rx-cdc-dma-3-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45110>; + }; + + rx_cdc_dma_4_rx: qcom,msm-dai-rx-cdc-dma-4-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45112>; + }; + + rx_cdc_dma_5_rx: qcom,msm-dai-rx-cdc-dma-5-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45114>; + }; + + rx_cdc_dma_6_rx: qcom,msm-dai-rx-cdc-dma-6-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45116>; + }; + + rx_cdc_dma_7_rx: qcom,msm-dai-rx-cdc-dma-7-rx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45118>; + }; + + tx_cdc_dma_0_tx: qcom,msm-dai-tx-cdc-dma-0-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45105>; + }; + + tx_cdc_dma_1_tx: qcom,msm-dai-tx-cdc-dma-1-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45107>; + }; + + tx_cdc_dma_2_tx: qcom,msm-dai-tx-cdc-dma-2-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45109>; + }; + + tx_cdc_dma_3_tx: qcom,msm-dai-tx-cdc-dma-3-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45111>; + }; + + tx_cdc_dma_4_tx: qcom,msm-dai-tx-cdc-dma-4-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45113>; + }; + + tx_cdc_dma_5_tx: qcom,msm-dai-tx-cdc-dma-5-tx { + compatible = "qcom,msm-dai-cdc-dma-dev"; + qcom,msm-dai-cdc-dma-dev-id = <45115>; + }; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + sb_7_rx: qcom,msm-dai-q6-sb-7-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16398>; + qcom,msm-dai-q6-slim-dev-id = <0>; + }; + + sb_7_tx: qcom,msm-dai-q6-sb-7-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16399>; + qcom,msm-dai-q6-slim-dev-id = <0>; + }; + + sb_8_tx: qcom,msm-dai-q6-sb-8-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16401>; + qcom,msm-dai-q6-slim-dev-id = <0>; + }; + + bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12288>; + }; + + bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12289>; + }; + + int_fm_rx: qcom,msm-dai-q6-int-fm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12292>; + }; + + int_fm_tx: qcom,msm-dai-q6-int-fm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12293>; + }; + + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + + proxy_rx: qcom,msm-dai-q6-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <8194>; + }; + + proxy_tx: qcom,msm-dai-q6-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <8195>; + }; + + usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28672>; + }; + + usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28673>; + }; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + + audio_apr: qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + qcom,subsys-name = "apr_adsp"; + + msm_audio_ion: qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <2>; + qcom,smmu-enabled; + iommus = <&apps_smmu 0x1801 0x0>; + qcom,iommu-dma-addr-pool = <0x10000000 0x10000000>; + }; + }; + + dai_pri_auxpcm: qcom,msm-pri-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_sec_auxpcm: qcom,msm-sec-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "secondary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_tert_auxpcm: qcom,msm-tert-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "tertiary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_quat_auxpcm: qcom,msm-quat-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "quaternary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_quin_auxpcm: qcom,msm-quin-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "quinary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_sen_auxpcm: qcom,msm-sen-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "senary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + hdmi_dba: qcom,msm-hdmi-dba-codec-rx { + compatible = "qcom,msm-hdmi-dba-codec-rx"; + qcom,dba-bridge-chip = "adv7533"; + }; + + adsp_loader: qcom,msm-adsp-loader { + status = "ok"; + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; + + tdm_pri_rx: qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_pri_tx: qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_sec_rx: qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_sec_tx: qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_tert_rx: qcom,msm-dai-tdm-tert-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37152>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36896>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36896>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_tert_tx: qcom,msm-dai-tdm-tert-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37153>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36897 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36897 >; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_quat_rx: qcom,msm-dai-tdm-quat-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37168>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36912>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36912>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_quat_tx: qcom,msm-dai-tdm-quat-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37169>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36913 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36913 >; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_quin_rx: qcom,msm-dai-tdm-quin-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37184>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36928>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36928>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_quin_tx: qcom,msm-dai-tdm-quin-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37185>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36929>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36929>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_sen_rx: qcom,msm-dai-tdm-sen-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37200>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36944>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sen_tdm_rx_0: qcom,msm-dai-q6-tdm-sen-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36944>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_sen_tx: qcom,msm-dai-tdm-sen-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37201>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36945>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sen_tdm_tx_0: qcom,msm-dai-q6-tdm-sen-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36945>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + dai_pri_spdif_rx: qcom,msm-dai-q6-spdif-pri-rx { + compatible = "qcom,msm-dai-q6-spdif"; + qcom,msm-dai-q6-dev-id = <20480>; + }; + + dai_pri_spdif_tx: qcom,msm-dai-q6-spdif-pri-tx { + compatible = "qcom,msm-dai-q6-spdif"; + qcom,msm-dai-q6-dev-id = <20481>; + }; + + dai_sec_spdif_rx: qcom,msm-dai-q6-spdif-sec-rx { + compatible = "qcom,msm-dai-q6-spdif"; + qcom,msm-dai-q6-dev-id = <20482>; + }; + + dai_sec_spdif_tx: qcom,msm-dai-q6-spdif-sec-tx { + compatible = "qcom,msm-dai-q6-spdif"; + qcom,msm-dai-q6-dev-id = <20483>; + }; + + afe_loopback_tx: qcom,msm-dai-q6-afe-loopback-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <24577>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..048993be6adecfa3090f3d78cce5ba0a04b36317 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-audio.dtsi @@ -0,0 +1,805 @@ +&spi_7 { + status = "okay"; +}; + +&soc { + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + compr: qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "regular"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + pcm_noirq: qcom,msm-pcm-dsp-noirq { + compatible = "qcom,msm-pcm-dsp-noirq"; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + cpe: qcom,msm-cpe-lsm { + compatible = "qcom,msm-cpe-lsm"; + }; + + cpe3: qcom,msm-cpe-lsm@3 { + compatible = "qcom,msm-cpe-lsm"; + qcom,msm-cpe-lsm-id = <3>; + }; + + wdsp_mgr: qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi_xprt_wdsp 2>; + qcom,img-filename = "cpe_9340"; + }; + + wdsp_glink: qcom,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + qcom,wdsp-channels = "g_glink_ctrl", + "g_glink_persistent_data_nild", + "g_glink_persistent_data_ild", + "g_glink_audio_data"; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + dai_dp: qcom,msm-dai-q6-dp { + compatible = "qcom,msm-dai-q6-hdmi"; + qcom,msm-dai-q6-dev-id = <24608>; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + qcom,msm-dai-mi2s { + compatible = "qcom,msm-dai-mi2s"; + dai_mi2s0: qcom,msm-dai-q6-mi2s-prim { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <0>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s1: qcom,msm-dai-q6-mi2s-sec { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <1>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_mi2s3: qcom,msm-dai-q6-mi2s-quat { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <3>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s2: qcom,msm-dai-q6-mi2s-tert { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <2>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_mi2s4: qcom,msm-dai-q6-mi2s-quin { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <4>; + qcom,msm-mi2s-rx-lines = <1>; + qcom,msm-mi2s-tx-lines = <2>; + }; + + dai_mi2s6: qcom,msm-dai-q6-mi2s-senary { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <6>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s0: qcom,msm-dai-q6-int-mi2s0 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <7>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s1: qcom,msm-dai-q6-int-mi2s1 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <8>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s2: qcom,msm-dai-q6-int-mi2s2 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <9>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s3: qcom,msm-dai-q6-int-mi2s3 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <10>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s4: qcom,msm-dai-q6-int-mi2s4 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <11>; + qcom,msm-mi2s-rx-lines = <3>; + qcom,msm-mi2s-tx-lines = <0>; + }; + + dai_int_mi2s5: qcom,msm-dai-q6-int-mi2s5 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <12>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + + dai_int_mi2s6: qcom,msm-dai-q6-int-mi2s6 { + compatible = "qcom,msm-dai-q6-mi2s"; + qcom,msm-dai-q6-mi2s-dev-id = <13>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + sb_0_rx: qcom,msm-dai-q6-sb-0-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16384>; + }; + + sb_0_tx: qcom,msm-dai-q6-sb-0-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16385>; + }; + + sb_1_rx: qcom,msm-dai-q6-sb-1-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16386>; + }; + + sb_1_tx: qcom,msm-dai-q6-sb-1-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16387>; + }; + + sb_2_rx: qcom,msm-dai-q6-sb-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16388>; + }; + + sb_2_tx: qcom,msm-dai-q6-sb-2-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16389>; + }; + + + sb_3_rx: qcom,msm-dai-q6-sb-3-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16390>; + }; + + sb_3_tx: qcom,msm-dai-q6-sb-3-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16391>; + }; + + sb_4_rx: qcom,msm-dai-q6-sb-4-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16392>; + }; + + sb_4_tx: qcom,msm-dai-q6-sb-4-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16393>; + }; + + sb_5_tx: qcom,msm-dai-q6-sb-5-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16395>; + }; + + sb_5_rx: qcom,msm-dai-q6-sb-5-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16394>; + }; + + sb_6_rx: qcom,msm-dai-q6-sb-6-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16396>; + }; + + sb_7_tx: qcom,msm-dai-q6-sb-7-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16399>; + qcom,msm-dai-q6-slim-dev-id = <1>; + }; + + sb_7_rx: qcom,msm-dai-q6-sb-7-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16398>; + qcom,msm-dai-q6-slim-dev-id = <1>; + }; + + sb_8_tx: qcom,msm-dai-q6-sb-8-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16401>; + qcom,msm-dai-q6-slim-dev-id = <1>; + }; + + sb_8_rx: qcom,msm-dai-q6-sb-8-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16400>; + qcom,msm-dai-q6-slim-dev-id = <1>; + }; + + bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12288>; + }; + + bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12289>; + }; + + int_fm_rx: qcom,msm-dai-q6-int-fm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12292>; + }; + + int_fm_tx: qcom,msm-dai-q6-int-fm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12293>; + }; + + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + + usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28672>; + }; + + usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28673>; + }; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + + dai_pri_auxpcm: qcom,msm-pri-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "primary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_sec_auxpcm: qcom,msm-sec-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "secondary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_tert_auxpcm: qcom,msm-tert-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "tertiary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + dai_quat_auxpcm: qcom,msm-quat-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "quaternary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + dai_quin_auxpcm: qcom,msm-quin-auxpcm { + compatible = "qcom,msm-auxpcm-dev"; + qcom,msm-cpudai-auxpcm-mode = <0>, <0>; + qcom,msm-cpudai-auxpcm-sync = <1>, <1>; + qcom,msm-cpudai-auxpcm-frame = <5>, <4>; + qcom,msm-cpudai-auxpcm-quant = <2>, <2>; + qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>; + qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>; + qcom,msm-cpudai-auxpcm-data = <0>, <0>; + qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>; + qcom,msm-auxpcm-interface = "quinary"; + qcom,msm-cpudai-afe-clk-ver = <2>; + }; + + qcom,msm-adsp-loader { + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; + + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37152>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36896>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36896>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37153>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36897 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36897 >; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quat-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37168>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36912>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quat_tdm_rx_0: qcom,msm-dai-q6-tdm-quat-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36912>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-quat-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37169>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36913 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quat_tdm_tx_0: qcom,msm-dai-q6-tdm-quat-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36913 >; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_quin_rx: qcom,msm-dai-tdm-quin-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37184>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36928>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quin_tdm_rx_0: qcom,msm-dai-q6-tdm-quin-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36928>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + tdm_quin_tx: qcom,msm-dai-tdm-quin-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37185>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36929>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_quin_tdm_tx_0: qcom,msm-dai-q6-tdm-quin-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36929>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,avtimer@150f700c { + compatible = "qcom,avtimer"; + reg = <0x150f700c 0x4>, + <0x150f7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <27>; + }; + + audio_apr: qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + qcom,subsys-name = "apr_adsp"; + msm_audio_ion: qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <2>; + qcom,smmu-enabled; + iommus = <&lpass_q6_smmu 1>; + }; + }; + + tasha_snd: sound-9335 { + compatible = "qcom,sdm660-asoc-snd-tasha"; + qcom,model = "sdm660-tasha-snd-card"; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,ext-disp-audio-rx; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "AMIC6", "MIC BIAS4", + "MIC BIAS4", "Analog Mic6", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,us-euro-gpios = <&us_euro_gpio>; + qcom,hph-en0-gpio = <&tasha_hph_en0>; + qcom,hph-en1-gpio = <&tasha_hph_en1>; + qcom,msm-mclk-freq = <9600000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>, <&cpe3>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq", + "msm-cpe-lsm.3"; + asoc-cpu = <&dai_dp>, <&dai_mi2s0>, + <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", + "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672", + "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36913"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + us_euro_gpio: msm_cdc_pinctrl@75 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_gnd_mic_swap_active>; + pinctrl-1 = <&wcd_gnd_mic_swap_idle>; + }; + + wcd9xxx_intc: wcd9xxx-irq { + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupts = <0 177 0>; + interrupt-names = "wcd_irq"; + }; + + clock_audio: audio_ext_clk { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + qcom,audio-ref-clk-gpio = <&pm660_gpios 3 0>; + clock-names = "osr_clk"; + clocks = <&clock_rpmcc RPM_SMD_DIV_CLK1>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + qcom,codec-mclk-clk-freq = <11289600>; + qcom,mclk-clk-reg = <0x15020018 0x0>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&lpi_mclk0_sleep>; + pinctrl-1 = <&lpi_mclk0_active>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = <1>; + clock-names = "osr_clk"; + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&lpi_cdc_reset_active>; + pinctrl-1 = <&lpi_cdc_reset_sleep>; + qcom,lpi-gpios; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-gdsc-660.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-gdsc-660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a61f037a67d4ab27747d206b51bcada20cd29315 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-gdsc-660.dtsi @@ -0,0 +1,146 @@ +&soc { + /* GCC GDSCs */ + gdsc_usb30: qcom,gdsc@10f004 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_usb30"; + reg = <0x10f004 0x4>; + status = "disabled"; + }; + + gdsc_ufs: qcom,gdsc@175004 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_ufs"; + reg = <0x175004 0x4>; + status = "disabled"; + }; + + gdsc_hlos1_vote_lpass_adsp: qcom,gdsc@17d034 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_hlos1_vote_lpass_adsp"; + reg = <0x17d034 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + gdsc_hlos1_vote_turing_adsp: qcom,gdsc@17d04c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_hlos1_vote_turing_adsp"; + reg = <0x17d04c 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + gdsc_hlos2_vote_turing_adsp: qcom,gdsc@17e04c { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_hlos2_vote_turing_adsp"; + reg = <0x17e04c 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + /* MMSS GDSCs */ + bimc_smmu_hw_ctrl: syscon@c8ce024 { + compatible = "syscon"; + reg = <0xc8ce024 0x4>; + }; + + gdsc_bimc_smmu: qcom,gdsc@c8ce020 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_bimc_smmu"; + reg = <0xc8ce020 0x4>; + hw-ctrl-addr = <&bimc_smmu_hw_ctrl>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + gdsc_venus: qcom,gdsc@c8c1024 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus"; + reg = <0xc8c1024 0x4>; + status = "disabled"; + }; + + gdsc_venus_core0: qcom,gdsc@c8c1040 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_venus_core0"; + reg = <0xc8c1040 0x4>; + status = "disabled"; + }; + + gdsc_camss_top: qcom,gdsc@c8c34a0 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_camss_top"; + reg = <0xc8c34a0 0x4>; + status = "disabled"; + }; + + gdsc_vfe0: qcom,gdsc@c8c3664 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vfe0"; + reg = <0xc8c3664 0x4>; + status = "disabled"; + }; + + gdsc_vfe1: qcom,gdsc@c8c3674 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_vfe1"; + reg = <0xc8c3674 0x4>; + status = "disabled"; + }; + + gdsc_cpp: qcom,gdsc@c8c36d4 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_cpp"; + reg = <0xc8c36d4 0x4>; + status = "disabled"; + }; + + gdsc_mdss: qcom,gdsc@c8c2304 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_mdss"; + reg = <0xc8c2304 0x4>; + status = "disabled"; + }; + + /* GPU GDSCs */ + gpu_cx_hw_ctrl: syscon@5066008 { + compatible = "syscon"; + reg = <0x5066008 0x4>; + }; + + gdsc_gpu_cx: qcom,gdsc@5066004 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_gpu_cx"; + reg = <0x5066004 0x4>; + hw-ctrl-addr = <&gpu_cx_hw_ctrl>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <2000>; + status = "disabled"; + }; + + /* GPU GX GDSCs */ + gpu_gx_domain_addr: syscon@5065130 { + compatible = "syscon"; + reg = <0x5065130 0x4>; + }; + + gpu_gx_sw_reset: syscon@5066090 { + compatible = "syscon"; + reg = <0x5066090 0x4>; + }; + + gdsc_gpu_gx: qcom,gdsc@5066094 { + compatible = "qcom,gdsc"; + regulator-name = "gdsc_gpu_gx"; + reg = <0x5066094 0x4>; + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; + qcom,retain-periph; + qcom,reset-aon-logic; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-pm660a.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-pm660a.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ace6e9186633ec4cbb00b22329d8951fe6a03bf4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-pm660a.dtsi @@ -0,0 +1,17 @@ +/* Disable WLED */ +&pm660l_wled { + status = "disabled"; +}; + +/* disable LCDB */ +&pm660l_lcdb { + status = "disabled"; +}; + +&pm660a_oledb { + status = "okay"; +}; + +&pm660a_labibb { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-qvr-external.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-qvr-external.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e5056b65ef7e2221319e35f6cc24666732f01a47 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-qvr-external.dtsi @@ -0,0 +1,9 @@ +&soc { + + qcom,smp2p_interrupt_qvrexternal_5_out { + compatible = "qcom,smp2p-interrupt-qvrexternal-5-out"; + qcom,smem-states = <&smp2p_qvrexternal5_out 0>; + qcom,smem-state-names = "qvrexternal-smp2p-out"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-rdbg-scuba.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-rdbg-scuba.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..758dda2c87002db3b860a8d1d270dddd705972d9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-rdbg-scuba.dtsi @@ -0,0 +1,15 @@ +&soc { + /* smp2p information */ + qcom,smp2p_interrupt_rdbg_2_out { + compatible = "qcom,smp2p-interrupt-rdbg-2-out"; + qcom,smem-states = <&smp2p_rdbg2_out 0>; + qcom,smem-state-names = "rdbg-smp2p-out"; + }; + + qcom,smp2p_interrupt_rdbg_2_in { + compatible = "qcom,smp2p-interrupt-rdbg-2-in"; + interrupts-extended = <&smp2p_rdbg2_in 0 0>; + interrupt-names = "rdbg-smp2p-in"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/msm-rdbg.dtsi b/arch/arm64/boot/dts/vendor/qcom/msm-rdbg.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bb2adf8d09917c097717f9ba58f76eaf83cc0e2e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/msm-rdbg.dtsi @@ -0,0 +1,26 @@ +&soc { + /* smp2p information */ + qcom,smp2p_interrupt_rdbg_2_out { + compatible = "qcom,smp2p-interrupt-rdbg-2-out"; + qcom,smem-states = <&smp2p_rdbg2_out 0>; + qcom,smem-state-names = "rdbg-smp2p-out"; + }; + + qcom,smp2p_interrupt_rdbg_2_in { + compatible = "qcom,smp2p-interrupt-rdbg-2-in"; + interrupts-extended = <&smp2p_rdbg2_in 0 0>; + interrupt-names = "rdbg-smp2p-in"; + }; + + qcom,smp2p_interrupt_rdbg_5_out { + compatible = "qcom,smp2p-interrupt-rdbg-5-out"; + qcom,smem-states = <&smp2p_rdbg5_out 0>; + qcom,smem-state-names = "rdbg-smp2p-out"; + }; + + qcom,smp2p_interrupt_rdbg_5_in { + compatible = "qcom,smp2p-interrupt-rdbg-5-in"; + interrupts-extended = <&smp2p_rdbg5_in 0 0>; + interrupt-names = "rdbg-smp2p-in"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid-cdp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/orchid-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..eb5983514c1affad9d628a08f212a544306461c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid-cdp-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "orchid-cdp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Orchid CDP"; + compatible = "qcom,orchid-cdp", "qcom,orchid", "qcom,cdp"; + qcom,msm-id = <476 0x10000>; + qcom,board-id = <1 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/orchid-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..4f8a3fbb54945bc3a78161b6eeb1e91006ce5996 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid-cdp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "orchid.dtsi" +#include "orchid-cdp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Orchid CDP"; + compatible = "qcom,orchid-cdp", "qcom,orchid", "qcom,cdp"; + qcom,board-id = <1 0>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/orchid-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f8657a3de8c706f8cebaf07882f0d685afcc776b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid-cdp.dtsi @@ -0,0 +1,5 @@ +#include "lito-cdp.dtsi" + +&soc { + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid-mtp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/orchid-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4f3d0c84b46a26142bdb3426165ccd22cd826b7f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid-mtp-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "orchid-mtp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Orchid MTP"; + compatible = "qcom,orchid-mtp", "qcom,orchid", "qcom,mtp"; + qcom,msm-id = <476 0x10000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/orchid-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..89a3a48ef1e137613eb2d68106fbd7cce3473750 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid-mtp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "orchid.dtsi" +#include "orchid-mtp.dtsi" +#include "lito-v2-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Orchid MTP"; + compatible = "qcom,orchid-mtp", "qcom,orchid", "qcom,mtp"; + qcom,board-id = <8 0>; +}; + +&ufsphy_mem { + /delete-property/ vdda-phy-always-on; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/orchid-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..17bffaf7b93ce29bf2e84bb93e4b2a1725005b5f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid-mtp.dtsi @@ -0,0 +1,5 @@ +#include "lito-mtp.dtsi" + +&soc { + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid.dts b/arch/arm64/boot/dts/vendor/qcom/orchid.dts new file mode 100644 index 0000000000000000000000000000000000000000..1fcf2cc2de50f3098ae0a4eb1c583a6d04b4175b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "orchid.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Orchid SoC"; + compatible = "qcom,orchid"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/orchid.dtsi b/arch/arm64/boot/dts/vendor/qcom/orchid.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d0d72d332c930f03b4e706976c735b6ca0d0e257 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/orchid.dtsi @@ -0,0 +1,7 @@ +#include "lito-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Orchid"; + compatible = "qcom,orchid"; + qcom,msm-id = <476 0x10000>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm2250-rpm-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm2250-rpm-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ed8a655d621f0acfe2a95917aad511eeedd81c6d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm2250-rpm-regulator.dtsi @@ -0,0 +1,439 @@ +&rpm_bus { + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <4>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <4>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <9>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa14 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <14>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l14 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l14"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa15 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <15>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l15 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l15"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa16 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <16>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l16 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l16"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa17 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <17>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l17 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l17"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa18 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <18>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l18 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l18"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa19 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <19>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l19 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l19"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa20 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <20>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l20 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l20"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa21 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <21>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l21 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l21"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa22 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <22>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l22 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l22"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm2250.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm2250.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..27310ed9dc12688439d755c14be5573d98558d1b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm2250.dtsi @@ -0,0 +1,492 @@ +#include +#include +#include +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm2250@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm2250_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + + qcom,pon_2 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + }; + + pm2250_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pm2250_vadc ADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm2250_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5-lite"; + reg = <0x3100 0x100>; + reg-names = "adc5-usr-base"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel nodes */ + ref_gnd { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vbat_sns { + reg = ; + label = "vbat_sns"; + qcom,pre-scaling = <1 3>; + }; + + usb_in_v_div_16 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; + + chg_temp { + reg = ; + label = "chg_temp"; + qcom,pre-scaling = <1 1>; + }; + + bat_therm { + reg = ; + label = "bat_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_therm_30k { + reg = ; + label = "bat_therm_30k"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_therm_400k { + reg = ; + label = "bat_therm_400k"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_id { + reg = ; + label = "bat_id"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + die_temp_s3 { + reg = ; + label = "die_temp_s3"; + qcom,pre-scaling = <1 3>; + qcom,scale-fn-type = ; + }; + }; + + + pm2250_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>; + + interrupt-names = "pm2250_gpio1", "pm2250_gpio2", + "pm2250_gpio3", "pm2250_gpio4", + "pm2250_gpio5", "pm2250_gpio6", + "pm2250_gpio7", "pm2250_gpio8", + "pm2250_gpio9", "pm2250_gpio10"; + + gpio-controller; + #gpio-cells = <2>; + }; + + pm2250_rtc: qcom,pm2250_rtc { + compatible = "qcom,pm8941-rtc"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + + pm2250_cdc: qcom,pm2250-cdc { + compatible = "qcom,pm2250-spmi"; + }; + + pm2250_qg: qpnp,qg { + compatible = "qcom,qpnp-qg-lite"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,vbatt-cutoff-mv = <3400>; + qcom,vbatt-low-mv = <3500>; + qcom,vbatt-low-cold-mv = <3800>; + qcom,vbatt-empty-mv = <3200>; + qcom,vbatt-empty-cold-mv = <3000>; + qcom,s3-entry-fifo-length = <2>; + + qcom,pmic-revid = <&pm2250_revid>; + io-channels = <&pm2250_vadc ADC_BAT_THERM_PU2>, + <&pm2250_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", "batt-id"; + + qcom,qgauge@4800 { + status = "okay"; + reg = <0x4800 0x100>; + interrupts = + <0x0 0x48 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x48 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x48 0x5 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "qg-vbat-empty", + "qg-fifo-done", + "qg-good-ocv"; + }; + + qcom,qg-sdam@b600 { + status = "okay"; + reg = <0xb600 0x100>; + }; + }; + + pm2250_charger: qcom,qpnp-smblite { + compatible = "qcom,qpnp-smblite"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,pmic-revid = <&pm2250_revid>; + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "chgr-error", + "chg-state-change", + "buck-oc", + "vph-ov"; + }; + + qcom,dcdc@1100 { + reg = <0x1100 0x100>; + interrupts = + <0x0 0x11 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x11 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-fault", + "skip-mode", + "input-current-limiting", + "switcher-power-ok"; + }; + + qcom,batif@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x0 0x12 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x4 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "bat-temp", + "bat-therm-or-id-missing", + "bat-low", + "bat-ov", + "bsm-active"; + }; + + qcom,usb@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-plugin", + "usbin-collapse", + "usbin-uv", + "usbin-ov", + "usbin-gtvt", + "usbin-icl-change"; + }; + + qcom,typec@1500 { + reg = <0x1500 0x100>; + interrupts = + <0x0 0x15 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x15 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x15 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x15 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x15 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x15 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x15 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "typec-or-rid-detect-change", + "typec-vpd-detect", + "typec-cc-state-change", + "typec-vbus-change", + "typec-attach-detach", + "typec-legacy-cable-detect", + "typec-try-snk-src-detect"; + }; + + qcom,misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x6 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "imp-trigger", + "all-chnl-cond-done", + "temp-change"; + }; + + qcom,schgm-flashlite@a600 { + reg = <0xa600 0x100>; + interrupts = + <0x0 0xa6 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0xa6 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0xa6 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0xa6 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "flash-state-change", + "ilim1-s1", + "ilim2-s2", + "vreg-ok"; + }; + }; + }; + + pm2250_1: qcom,pm2250@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm2250_vib: qcom,vibrator@5600 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5600 0x100>; + qcom,vib-ldo-volt-uv = <3000000>; + qcom,disable-overdrive; + }; + + pm2250_pwm1: qcom,pwms@bc00 { + compatible = "qcom,pwm-lpg"; + reg = <0xbc00 0x100>; + reg-names = "lpg-base"; + qcom,num-lpg-channels = <1>; + #pwm-cells = <2>; + }; + + pm2250_pwm2: qcom,pwms@bd00 { + compatible = "qcom,pwm-lpg"; + reg = <0xbd00 0x100>; + reg-names = "lpg-base"; + qcom,num-lpg-channels = <1>; + #pwm-cells = <2>; + }; + + pm2250_pwm3: qcom,pwms@be00 { + compatible = "qcom,pwm-lpg"; + reg = <0xbe00 0x100>; + reg-names = "lpg-base"; + qcom,num-lpg-channels = <1>; + #pwm-cells = <2>; + }; + + pm2250_rg_leds: qcom,rg_leds { + compatible = "pwm-leds"; + + red { + label = "red"; + pwms = <&pm2250_pwm1 0 1000000>; + max-brightness = <255>; + linux,default-trigger = "timer"; + }; + + green { + label = "green"; + pwms = <&pm2250_pwm2 0 1000000>; + max-brightness = <255>; + linux,default-trigger = "timer"; + }; + }; + + pm2250_flash: qcom,flash_led@d300 { + compatible = "qcom,pm2250-flash-led"; + reg = <0xd300>; + interrupts = <0x1 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x1 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x1 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + + pm2250_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current-ma = <1000>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + }; + + pm2250_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current-ma = <200>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,ires-ua = <12500>; + }; + + pm2250_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <1>; + qcom,default-led-trigger = "switch0_trigger"; + }; + }; + + bcl_soc: bcl-soc { + compatible = "qcom,msm-bcl-soc"; + #thermal-sensor-cells = <0>; + }; + }; +}; + +&thermal_zones { + pm2250-tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm2250_tz>; + wake-capable-sensor; + + trips { + pm2250_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm2250_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + soc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_soc>; + wake-capable-sensor; + tracks-low; + + trips { + pm2250_low_soc: low-soc { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm6125-rpm-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm6125-rpm-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..b699d861d455fb8a225cff6709a9c297f5a86746 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm6125-rpm-regulator.dtsi @@ -0,0 +1,509 @@ +&rpm_bus { + /* VDD_APC supply */ + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwmx"; + qcom,resource-id = <0>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + /* VDD_CX */ + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwcx"; + qcom,resource-id = <0>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + /* VDD_MX */ + rpm-regulator-smpa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwmx"; + qcom,resource-id = <0>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <6>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <7>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <8>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_s8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <4>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + /* VDD_WCSS_CX */ + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <9>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa14 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <14>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l14 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l14"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa15 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <15>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l15 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l15"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa16 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <16>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l16 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l16"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa17 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <17>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l17 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l17"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa18 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <18>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l18 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l18"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa19 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <19>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l19 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l19"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa20 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <20>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l20 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l20"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa21 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <21>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l21 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l21"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa22 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <22>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l22 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l22"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa23 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <23>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l23 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l23"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa24 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <24>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic5-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l24 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm6125_l24"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm6125.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm6125.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a79905c65daafa64d5b16eb75d1555f79113bf73 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm6125.dtsi @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include + +&spmi_bus { + qcom,pm6125@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 0x0>; + #address-cells = <2>; + #size-cells = <0>; + + pm6125_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + + qcom,pon_2 { + qcom,pon-type = ; + qcom,pull-up = <1>; + linux,code = ; + }; + }; + + pm6125_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel nodes */ + ref_gnd { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + }; + + pm6125_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + }; + + pm6125_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm6125_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm6125_div_clk1"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo"; + assigned-clocks = <&pm6125_clkdiv 1>; + assigned-clock-rates = <9600000>; + }; + + pm6125_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x900>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>; + interrupt-names = "pm6125_gpio1", "pm6125_gpio2", + "pm6125_gpio3", "pm6125_gpio4", + "pm6125_gpio5", "pm6125_gpio6", + "pm6125_gpio7", "pm6125_gpio8", + "pm6125_gpio9"; + gpio-controller; + #gpio-cells = <2>; + }; + + pm6125_rtc: qcom,pm6125_rtc { + compatible = "qcom,pm8941-rtc"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + }; + + qcom,pm6125@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 0x0>; + #address-cells = <2>; + #size-cells = <0>; + + pm6125_pwm: qcom,pwms@b300 { + status = "disabled"; + compatible = "qcom,pwm-lpg"; + reg = <0xb300 0x100>; + reg-names = "lpg-base"; + qcom,num-lpg-channels = <1>; + #pwm-cells = <2>; + }; + }; +}; + +&thermal_zones { + pm6125-tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6125_tz>; + wake-capable-sensor; + + trips { + pm6125_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6125_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm6150l.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm6150l.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4cc62d4f4911ffc5dc0763b25c361abaadd3a33a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm6150l.dtsi @@ -0,0 +1,552 @@ +#include +#include +#include + +&spmi_bus { + qcom,pm6150l@4 { + compatible = "qcom,spmi-pmic"; + reg = <4 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm6150l_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm6150l_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm6150l_bcl: bcl@3d00 { + compatible = "qcom,bcl-v5"; + reg = <0x3d00 0x100>; + interrupts = <0x4 0x3d 0x0 IRQ_TYPE_NONE>, + <0x4 0x3d 0x1 IRQ_TYPE_NONE>, + <0x4 0x3d 0x2 IRQ_TYPE_NONE>; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; + #thermal-sensor-cells = <1>; + }; + + pm6150l_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x4 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + ref_gnd { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + }; + + pm6150l_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x4 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + }; + + pm6150l_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm6150l_div_clk1"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + status = "disabled"; + }; + + pm6150l_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>, + <0x4 0xc1 0 IRQ_TYPE_NONE>, + <0x4 0xc2 0 IRQ_TYPE_NONE>, + <0x4 0xc3 0 IRQ_TYPE_NONE>, + <0x4 0xc4 0 IRQ_TYPE_NONE>, + <0x4 0xc5 0 IRQ_TYPE_NONE>, + <0x4 0xc6 0 IRQ_TYPE_NONE>, + <0x4 0xc7 0 IRQ_TYPE_NONE>, + <0x4 0xc8 0 IRQ_TYPE_NONE>, + <0x4 0xc9 0 IRQ_TYPE_NONE>, + <0x4 0xca 0 IRQ_TYPE_NONE>, + <0x4 0xcb 0 IRQ_TYPE_NONE>; + interrupt-names = "pm6150l_gpio1", "pm6150l_gpio2", + "pm6150l_gpio3", "pm6150l_gpio4", + "pm6150l_gpio5", "pm6150l_gpio6", + "pm6150l_gpio7", "pm6150l_gpio8", + "pm6150l_gpio9", "pm6150l_gpio10", + "pm6150l_gpio11", "pm6150l_gpio12"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + qcom,pm6150l@5 { + compatible ="qcom,spmi-pmic"; + reg = <5 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm6150l_pwm_1: qcom,pwms@bc00 { + status = "disabled"; + compatible = "qcom,pwm-lpg"; + reg = <0xbc00 0x100>; + reg-names = "lpg-base"; + qcom,num-lpg-channels = <1>; + #pwm-cells = <2>; + }; + + pm6150l_lcdb: qcom,lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + interrupts = <0x5 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + qcom,pmic-revid = <&pm6150l_revid>; + qcom,voltage-step-ramp; + status = "disabled"; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_bst_vreg: bst { + label = "bst"; + regulator-name = "lcdb_bst"; + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <6275000>; + }; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x5 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,hdrm-auto-mode; + qcom,short-circuit-det; + qcom,open-circuit-det; + qcom,vph-droop-det; + qcom,thermal-derate-en; + qcom,thermal-derate-current = <200 500 1000>; + qcom,isc-delay = <192>; + qcom,pmic-revid = <&pm6150l_revid>; + + pm6150l_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm6150l_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm6150l_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + status = "disabled"; + }; + + pm6150l_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm6150l_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm6150l_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + status = "disabled"; + }; + + pm6150l_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <1>; + qcom,default-led-trigger = "switch0_trigger"; + }; + + pm6150l_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <2>; + qcom,default-led-trigger = "switch1_trigger"; + }; + + pm6150l_switch2: qcom,led_switch_2 { + label = "switch"; + qcom,led-name = "led:switch_2"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch2_trigger"; + }; + }; + + pm6150l_wled: qcom,wled@d800 { + compatible = "qcom,pm6150l-spmi-wled"; + reg = <0xd800 0x100>, <0xd900 0x100>; + reg-names = "wled-ctrl-base", "wled-sink-base"; + label = "backlight"; + interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd8 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x5 0xd8 0x5 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "ovp-irq", "pre-flash-irq", + "flash-irq"; + qcom,pmic-revid = <&pm6150l_revid>; + qcom,auto-calibration; + status = "disabled"; + + wled_flash: qcom,wled-flash { + label = "flash"; + qcom,default-led-trigger = "wled_flash"; + }; + + wled_torch: qcom,wled-torch { + label = "torch"; + qcom,default-led-trigger = "wled_torch"; + qcom,wled-torch-timer = <1200>; + }; + + wled_switch: qcom,wled-switch { + label = "switch"; + qcom,default-led-trigger = "wled_switch"; + }; + }; + + pm6150l_lpg: qcom,pwms@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x300>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <3>; + qcom,lut-patterns = <0 10 20 30 40 50 60 70 80 90 100 + 90 80 70 60 50 40 30 20 10 0>; + lpg1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + }; + + pm6150l_rgb_led: qcom,leds@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + red { + label = "red"; + pwms = <&pm6150l_lpg 0 1000000>; + led-sources = <0>; + linux,default-trigger = "timer"; + }; + + green { + label = "green"; + pwms = <&pm6150l_lpg 1 1000000>; + led-sources = <1>; + linux,default-trigger = "timer"; + }; + + blue { + label = "blue"; + pwms = <&pm6150l_lpg 2 1000000>; + led-sources = <2>; + linux,default-trigger = "timer"; + }; + }; + + pm6150a_amoled: qcom,amoled { + compatible = "qcom,qpnp-amoled-regulator"; + status = "disabled"; + + oledb_vreg: oledb@e000 { + reg = <0xe000 0x100>; + reg-names = "oledb_base"; + regulator-name = "oledb"; + regulator-min-microvolt = <4925000>; + regulator-max-microvolt = <8100000>; + qcom,swire-control; + }; + + ab_vreg: ab@de00 { + reg = <0xde00 0x100>; + reg-names = "ab_base"; + regulator-name = "ab"; + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6100000>; + qcom,swire-control; + }; + + ibb_vreg: ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_base"; + regulator-name = "ibb"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <5400000>; + qcom,swire-control; + }; + }; + }; +}; + +&thermal_zones { + pm6150l_temp_alarm: pm6150l-tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_tz>; + wake-capable-sensor; + + trips { + pm6150l_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6150l_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pm6150l-vph-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm6150l_bcl 2>; + wake-capable-sensor; + tracks-low; + + trips { + vph_lvl0: vph-lvl0 { + temperature = <3000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm6150l-vph-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm6150l_bcl 3>; + wake-capable-sensor; + tracks-low; + + trips { + vph_lvl1:vph-lvl1 { + temperature = <2750>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm6150l-vph-lvl2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm6150l_bcl 4>; + wake-capable-sensor; + tracks-low; + + trips { + vph_lvl2:vph-lvl2 { + temperature = <2500>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm6150l-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_bcl 5>; + wake-capable-sensor; + + trips { + l_bcl_lvl0: l-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm6150l-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_bcl 6>; + wake-capable-sensor; + + trips { + l_bcl_lvl1: l-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm6150l-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6150l_bcl 7>; + wake-capable-sensor; + + trips { + l_bcl_lvl2: l-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm6350.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm6350.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d74f35b4e9d9cc4782c5b1afbd417ab51bbf212f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm6350.dtsi @@ -0,0 +1,132 @@ +#include +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm6350@0 { + compatible = "qcom,spmi-pmic"; + reg = <0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm6350_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + qcom,pull-up; + linux,code = ; + }; + + qcom,pon_2 { + qcom,pon-type = ; + qcom,pull-up; + linux,code = ; + }; + }; + + pm6350_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm6350_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm6350_div_clk1"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + status = "disabled"; + }; + + pm6350_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x900>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>; + interrupt-names = "pm6350_gpio1", "pm6350_gpio2", + "pm6350_gpio3", "pm6350_gpio4", + "pm6350_gpio5", "pm6350_gpio6", + "pm6350_gpio7", "pm6350_gpio8", + "pm6350_gpio9"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + qcom,pm6350@1 { + compatible ="qcom,spmi-pmic"; + reg = <1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm6350_pwm: qcom,pwms@6000 { + status = "disabled"; + compatible = "qcom,pwm-lpg"; + reg = <0x6000 0x100>; + reg-names = "lpg-base"; + qcom,num-lpg-channels = <1>; + #pwm-cells = <2>; + }; + }; +}; + +&thermal_zones { + pm6350_tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6350_tz>; + wake-capable-sensor; + + trips { + pm6350_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6350_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6350_trip2: trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm660-rpm-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm660-rpm-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a02607244a5ad1d3ed89ce8a1a469a7afc3a8fb3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm660-rpm-regulator.dtsi @@ -0,0 +1,403 @@ +&rpm_bus { + rpm-regulator-smpa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <3>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <4>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_s4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <5>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_s5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpa"; + qcom,resource-id = <6>; + qcom,regulator-type = <1>; + qcom,hpm-min-load = <100000>; + status = "disabled"; + + regulator-s6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_s6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <9>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <10>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa11 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <11>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l11 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l11"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa12 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <12>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l12 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l12"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa13 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <13>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l13 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l13"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa14 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <14>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l14 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l14"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa15 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <15>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l15 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l15"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa16 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <16>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l16 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l16"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa17 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <17>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l17 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l17"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa18 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <18>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l18 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l18"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldoa19 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldoa"; + qcom,resource-id = <19>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + qcom,hpm-min-load = <10000>; + status = "disabled"; + + regulator-l19 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l19"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm660.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4d744af9ca3cd3a991913f7483ebe6d6ef369978 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm660.dtsi @@ -0,0 +1,555 @@ +#include +#include +#include + +&spmi_bus { + qcom,pm660@0 { + compatible ="qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + qcom,fab-id-valid; + qcom,tp-rev-valid; + }; + + pm660_misc: qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + }; + + pm660_pon: qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + }; + + pm660_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm660_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xd00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc2 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>, + <0x0 0xca 0 IRQ_TYPE_NONE>, + <0x0 0xcb 0 IRQ_TYPE_NONE>, + <0x0 0xcc 0 IRQ_TYPE_NONE>; + interrupt-names = "pm660_gpio1", "pm660_gpio2", + "pm660_gpio3", "pm660_gpio4", + "pm660_gpio5", "pm660_gpio6", + "pm660_gpio7", "pm660_gpio8", + "pm660_gpio9", "pm660_gpio10", + "pm660_gpio11", "pm660_gpio12", + "pm660_gpio13"; + gpio-controller; + #gpio-cells = <2>; + }; + + pm660_rtc: qcom,pm660_rtc { + compatible = "qcom,pm8941-rtc"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + + pm660_pbs: qcom,pbs@7400 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7400 0x100>; + status = "disabled"; + }; + + pm660_vadc: vadc@3100 { + compatible = "qcom,spmi-adc-rev2"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel nodes */ + die_temp { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + ref_gnd { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + xo_therm { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + msm_therm{ + reg = ; + label = "msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + quiet_therm{ + reg = ; + label = "quiet_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + emmc_therm{ + reg = ; + label = "emmc_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm0{ + reg = ; + label = "pa_therm0"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + drax_temp{ + reg = ; + label = "drax_temp"; + qcom,pre-scaling = <1 1>; + }; + }; + + pm660_charger: qcom,qpnp-smb2 { + compatible = "qcom,qpnp-smb2"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,pmic-revid = <&pm660_revid>; + + io-channels = <&pm660_rradc 8>, + <&pm660_rradc 10>, + <&pm660_rradc 3>, + <&pm660_rradc 4>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v"; + + qcom,wipower-max-uw = <5000000>; + dpdm-supply = <&qusb_phy0>; + + qcom,thermal-mitigation + = <3000000 2500000 2000000 1500000 + 1000000 500000>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x0 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x4 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x0 0x11 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x11 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x11 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x11 0x3 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x0 0x12 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x5 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x0 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x13 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = + <0x0 0x14 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x0 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x16 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x16 0x6 IRQ_TYPE_EDGE_FALLING>, + <0x0 0x16 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; + }; + + pm660_pdphy: qcom,usb-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + vdd-pdphy-supply = <&pm660l_l7>; + vbus-supply = <&smb2_vbus>; + vconn-supply = <&smb2_vconn>; + interrupts = <0x0 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x0 0x17 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>; /* 9V @ 3A */ + }; + + pm660_adc_tm: vadc@3400 { + compatible = "qcom,adc-tm-rev2"; + reg = <0x3400 0x100>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + qcom,pmic-revid = <&pm660_revid>; + }; + + pm660_rradc: rradc@4500 { + compatible = "qcom,rradc"; + reg = <0x4500 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + qcom,pmic-revid = <&pm660_revid>; + }; + + pm660_fg: qpnp,fg { + compatible = "qcom,fg-gen3"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660_revid>; + io-channels = <&pm660_rradc 0>, + <&pm660_rradc 7>; + io-channel-names = "rradc_batt_id", + "rradc_die_temp"; + qcom,rradc-base = <0x4500>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; + qcom,cycle-counter-en; + status = "okay"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x0 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x2 + IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 0x3 + IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x5 + IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x40 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta", + "msoc-low", + "msoc-empty", + "msoc-high", + "msoc-full"; + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x0 0x41 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x41 0x6 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbatt-pred-delta", + "vbatt-low", + "esr-delta", + "batt-missing", + "batt-temp-delta"; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x0 0x44 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x44 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x44 0x2 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "ima-rdy", + "mem-xcp", + "dma-grant"; + }; + }; + + bcl_sensor:bcl@4200 { + compatible = "qcom,msm-bcl-lmh"; + reg = <0x4200 0xff>, + <0x4300 0xff>; + reg-names = "fg_user_adc", + "fg_lmh"; + interrupts = <0x0 0x42 0x0 IRQ_TYPE_NONE>, + <0x0 0x42 0x1 IRQ_TYPE_NONE>, + <0x0 0x42 0x2 IRQ_TYPE_NONE>, + <0x0 0x42 0x3 IRQ_TYPE_NONE>, + <0x0 0x42 0x4 IRQ_TYPE_NONE>; + interrupt-names = "bcl-high-ibat", + "bcl-very-high-ibat", + "bcl-low-vbat", + "bcl-very-low-vbat", + "bcl-crit-low-vbat"; + #thermal-sensor-cells = <1>; + }; + }; + + qcom,pm660@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660_haptics: qcom,haptic@c000 { + compatible = "qcom,pm660-haptics"; + reg = <0xc000 0x100>; + interrupts = <0x1 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x1 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hap-sc-irq", "hap-play-irq"; + qcom,actuator-type = "lra"; + qcom,vmax-mv = <3200>; + qcom,play-rate-us = <6667>; + qcom,lra-resonance-sig-shape = "sine"; + qcom,lra-auto-resonance-mode = "qwd"; + qcom,lra-allow-variable-play-rate; + + wf_0 { + /* CLICK */ + qcom,effect-id = <0>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [01 00 00 00]; + qcom,lra-auto-resonance-disable; + }; + wf_1 { + /* DOUBLE CLICK */ + qcom,effect-id = <1>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e 02 02 02 02 02 02]; + qcom,wf-play-rate-us = <7143>; + qcom,wf-repeat-count = <2>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + wf_2 { + /* TICK */ + qcom,effect-id = <2>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e]; + qcom,wf-play-rate-us = <4000>; + qcom,lra-auto-resonance-disable; + }; + wf_3 { + /* THUD */ + qcom,effect-id = <3>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e 7e]; + qcom,wf-play-rate-us = <6667>; + qcom,lra-auto-resonance-disable; + }; + wf_4 { + /* POP */ + qcom,effect-id = <4>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e]; + qcom,wf-play-rate-us = <5000>; + qcom,lra-auto-resonance-disable; + }; + wf_5 { + /* HEAVY CLICK */ + qcom,effect-id = <5>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e 7e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [03 00 00 00]; + qcom,lra-auto-resonance-disable; + }; + }; + }; +}; + +&thermal_zones { + pm660_temp_alarm: pm660-tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm660_tz>; + wake-capable-sensor; + + trips { + pm660_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + pm660_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + pm660_trip2: trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm660l-rpm-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm660l-rpm-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..fcb1d959f2eea658aa910e509828e51893362512 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm660l-rpm-regulator.dtsi @@ -0,0 +1,237 @@ +&rpm_bus { + rpm-regulator-smpb1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpb"; + qcom,resource-id = <1>; + qcom,regulator-type = <1>; + status = "disabled"; + + regulator-s1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpb2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "smpb"; + qcom,resource-id = <2>; + qcom,regulator-type = <1>; + status = "disabled"; + + regulator-s2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpb3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwcx"; + qcom,resource-id = <0>; + qcom,regulator-type = <1>; + status = "disabled"; + + regulator-s3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-smpb5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwmx"; + qcom,resource-id = <0>; + qcom,regulator-type = <1>; + status = "disabled"; + + regulator-s5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob1 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <1>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l1"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob2 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <2>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l2"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob3 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <3>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l3"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob4 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <4>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l4 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l4"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob5 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <5>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l5 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l5"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob6 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <6>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l6 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l6"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob7 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <7>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l7 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l7"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob8 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "ldob"; + qcom,resource-id = <8>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l8 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l8"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob9 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwlc"; + qcom,resource-id = <0>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l9 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l9"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-ldob10 { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "rwlm"; + qcom,resource-id = <0>; + qcom,regulator-type = <0>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-l10 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l10"; + qcom,set = <3>; + status = "disabled"; + }; + }; + + rpm-regulator-bobb { + compatible = "qcom,rpm-smd-regulator-resource"; + qcom,resource-name = "bobb"; + qcom,resource-id = <1>; + qcom,regulator-type = <4>; + qcom,regulator-hw-type = "pmic4-ldo"; + status = "disabled"; + + regulator-bob { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_bob"; + qcom,set = <3>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm660l.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm660l.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4d6b47113ff8dcb22220afab31cc48c1573dbf6b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm660l.dtsi @@ -0,0 +1,378 @@ +#include +#include +#include + +&spmi_bus { + qcom,pm660l@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660l_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pm660l_pbs: qcom,pbs@7300 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7300 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + qcom,secondary-pon-reset; + qcom,hard-reset-poweroff-type = + ; + }; + + pm660l_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm660l_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x2 0xc0 0 IRQ_TYPE_NONE>, + <0x2 0xc1 0 IRQ_TYPE_NONE>, + <0x2 0xc2 0 IRQ_TYPE_NONE>, + <0x2 0xc3 0 IRQ_TYPE_NONE>, + <0x2 0xc4 0 IRQ_TYPE_NONE>, + <0x2 0xc5 0 IRQ_TYPE_NONE>, + <0x2 0xc6 0 IRQ_TYPE_NONE>, + <0x2 0xc7 0 IRQ_TYPE_NONE>, + <0x2 0xc8 0 IRQ_TYPE_NONE>, + <0x2 0xc9 0 IRQ_TYPE_NONE>, + <0x2 0xca 0 IRQ_TYPE_NONE>, + <0x2 0xcb 0 IRQ_TYPE_NONE>; + interrupt-names = "pm660l_gpio1", "pm660l_gpio2", + "pm660l_gpio3", "pm660l_gpio4", + "pm660l_gpio5", "pm660l_gpio6", + "pm660l_gpio7", "pm660l_gpio8", + "pm660l_gpio9", "pm660l_gpio10", + "pm660l_gpio11", "pm660l_gpio12"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + pm660l_3: qcom,pm660l@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm660l_lpg: qcom,pwms@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x300>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <3>; + qcom,lut-patterns = <0 10 20 30 40 50 60 70 80 90 100 + 90 80 70 60 50 40 30 20 10 0>; + + lpg1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + lpg2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + }; + + pm660l_pwm: qcom,pwms@b400 { + compatible = "qcom,pwm-lpg"; + reg = <0xb400 0x100>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <1>; + }; + + pm660l_rgb_led: qcom,leds@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + red { + label = "red"; + pwms = <&pm660l_lpg 2 1000000>; + led-sources = <0>; + linux,default-trigger = "timer"; + }; + green { + label = "green"; + pwms = <&pm660l_lpg 1 1000000>; + led-sources = <1>; + linux,default-trigger = "timer"; + }; + blue { + label = "blue"; + pwms = <&pm660l_lpg 0 1000000>; + led-sources = <2>; + linux,default-trigger = "timer"; + }; + }; + + pm660l_wled: qcom,leds@d800 { + compatible = "qcom,pm660l-spmi-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>; + reg-names = "wled-ctrl-base", + "wled-sink-base"; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq"; + label = "backlight"; + qcom,pmic-revid = <&pm660l_revid>; + qcom,auto-calibration; + status = "ok"; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,hdrm-auto-mode; + qcom,short-circuit-det; + qcom,open-circuit-det; + qcom,vph-droop-det; + qcom,thermal-derate-en; + qcom,thermal-derate-current = <200 500 1000>; + qcom,isc-delay = <192>; + qcom,pmic-revid = <&pm660l_revid>; + + pm660l_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm660l_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch0_trigger"; + }; + + pm660l_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <4>; + qcom,default-led-trigger = "switch1_trigger"; + }; + }; + + pm660l_lcdb: qpnp-lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + + qcom,pmic-revid = <&pm660l_revid>; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + }; + + pm660a_oledb: qpnp-oledb@e000 { + compatible = "qcom,qpnp-oledb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; + reg = <0xe000 0x100>; + qcom,pbs-client = <&pm660l_pbs>; + + label = "oledb"; + regulator-name = "regulator-oledb"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <8100000>; + + qcom,swire-control; + qcom,ext-pin-control; + status = "disabled"; + }; + + pm660a_labibb: qpnp-labibb-regulator { + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm660l_revid>; + qcom,swire-control; + status = "disabled"; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6300000>; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-init-voltage = <4000000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6100000>; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-init-voltage = <4600000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + + qcom,notify-lab-vreg-ok-sts; + }; + }; + }; +}; + +&thermal_zones { + pm660l_temp_alarm: pm660l-tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm660l_tz>; + wake-capable-sensor; + + trips { + pm660l_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + pm660l_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm7250b.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm7250b.dtsi new file mode 100755 index 0000000000000000000000000000000000000000..cf3ee72b56679b379ae41c92c39721606a3fa301 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm7250b.dtsi @@ -0,0 +1,646 @@ +#include +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm7250b@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm7250b_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm7250b_charger: qcom,qpnp-smb5 { + compatible = "qcom,qpnp-smb5"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,thermal-mitigation = <5400000 4500000 4000000 + 3500000 3000000 2500000 2000000 1500000 + 1000000 500000>; + qcom,pmic-revid = <&pm7250b_revid>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chgr-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-req", + "fg-fvcal-qualified", + "vph-alarm", + "vph-drop-prechg"; + }; + + qcom,dcdc@1100 { + reg = <0x1100 0x100>; + interrupts = + <0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "otg-fail", + "otg-oc-disable-sw", + "otg-oc-hiccup", + "bsm-active", + "high-duty-cycle", + "input-current-limiting", + "concurrent-mode-disable", + "switcher-power-ok"; + }; + + qcom,batif@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "bat-temp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing", + "buck-oc", + "vph-ov"; + }; + + qcom,usb@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "usbin-collapse", + "usbin-vashdn", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-revi-change", + "usbin-src-change", + "usbin-icl-change"; + }; + + qcom,dc@1400 { + reg = <0x1400 0x100>; + interrupts = + <0x2 0x14 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x14 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "dcin-vashdn", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "dcin-revi", + "dcin-pon", + "dcin-en"; + }; + + qcom,typec@1500 { + reg = <0x1500 0x100>; + interrupts = + <0x2 0x15 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "typec-or-rid-detect-change", + "typec-vpd-detect", + "typec-cc-state-change", + "typec-vconn-oc", + "typec-vbus-change", + "typec-attach-detach", + "typec-legacy-cable-detect", + "typec-try-snk-src-detect"; + }; + + qcom,misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "smb-en", + "imp-trigger", + "temp-change", + "temp-change-smb"; + }; + + qcom,chg-sdam@b000 { + reg = <0xb000 0x100>; + }; + }; + + pm7250b_pdphy: qcom,usb-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + interrupts = <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded", + "fr-swap"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>, /* 9V @ 3A */ + <12000 2250>; /* 12V @ 2.25A */ + }; + + pm7250b_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pm7250b_vadc ADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm7250b_qg: qpnp,qg { + compatible = "qcom,qpnp-qg"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,vbatt-cutoff-mv = <3200>; + qcom,vbatt-low-mv = <3300>; + qcom,vbatt-low-cold-mv = <3700>; + qcom,vbatt-empty-mv = <3000>; + qcom,vbatt-empty-cold-mv = <3000>; + qcom,s3-entry-fifo-length = <2>; + qcom,s3-entry-ibat-ua = <25000>; + qcom,s3-exit-ibat-ua = <35000>; + + qcom,pmic-revid = <&pm7250b_revid>; + + qcom,qgauge@4800 { + status = "okay"; + reg = <0x4800 0x100>; + interrupts = + <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x48 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x48 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "qg-batt-missing", + "qg-vbat-low", + "qg-vbat-empty", + "qg-fifo-done", + "qg-good-ocv"; + }; + + qcom,qg-sdam@b100 { + status = "okay"; + reg = <0xb100 0x100>; + }; + }; + + pm7250b_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm7250b_div_clk1"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + assigned-clocks = <&pm7250b_clkdiv 1>; + assigned-clock-rates = <19200000>; + }; + + pm7250b_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x2 0xc0 0x0 IRQ_TYPE_NONE>, + <0x2 0xc1 0x0 IRQ_TYPE_NONE>, + <0x2 0xc2 0x0 IRQ_TYPE_NONE>, + <0x2 0xc3 0x0 IRQ_TYPE_NONE>, + <0x2 0xc4 0x0 IRQ_TYPE_NONE>, + <0x2 0xc5 0x0 IRQ_TYPE_NONE>, + <0x2 0xc6 0x0 IRQ_TYPE_NONE>, + <0x2 0xc7 0x0 IRQ_TYPE_NONE>, + <0x2 0xc8 0x0 IRQ_TYPE_NONE>, + <0x2 0xc9 0x0 IRQ_TYPE_NONE>, + <0x2 0xca 0x0 IRQ_TYPE_NONE>, + <0x2 0xcb 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm7250b_gpio1", "pm7250b_gpio2", + "pm7250b_gpio3", "pm7250b_gpio4", + "pm7250b_gpio5", "pm7250b_gpio6", + "pm7250b_gpio7", "pm7250b_gpio8", + "pm7250b_gpio9", "pm7250b_gpio10", + "pm7250b_gpio11", "pm7250b_gpio12"; + gpio-controller; + #gpio-cells = <2>; + }; + + pm7250b_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>; + reg-names = "adc5-usr-base"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + ref_gnd@0 { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25@1 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp@2 { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + vph_pwr@83 { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vbat_sns@84 { + reg = ; + label = "vbat_sns"; + qcom,pre-scaling = <1 3>; + }; + + usb_in_i_uv@7 { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16@8 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; + + chg_temp@9 { + reg = ; + label = "chg_temp"; + qcom,pre-scaling = <1 1>; + }; + + bat_therm@4a { + reg = ; + label = "bat_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_therm_30k@2a { + reg = ; + label = "bat_therm_30k"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_therm_400k@6a { + reg = ; + label = "bat_therm_400k"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_id@4b { + reg = ; + label = "bat_id"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + smb1390_therm@e { + reg = ; + label = "smb1390_therm"; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux@99 { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6@1e { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + v_i_int_ext@b0 { + reg = ; + label = "v_i_int_vbat_vdata"; + qcom,pre-scaling = <1 1>; + }; + + v_i_parallel@b0 { + reg = ; + label = "v_i_parallel_vbat_vdata"; + qcom,pre-scaling = <1 1>; + }; + }; + + pm7250b_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + }; + + pm7250b_bcl: bcl@1d00 { + compatible = "qcom,bcl-v5"; + reg = <0x1d00 0x100>; + interrupts = <0x2 0x1d 0x0 IRQ_TYPE_NONE>, + <0x2 0x1d 0x1 IRQ_TYPE_NONE>, + <0x2 0x1d 0x2 IRQ_TYPE_NONE>; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; + #thermal-sensor-cells = <1>; + }; + + bcl_soc:bcl-soc { + compatible = "qcom,msm-bcl-soc"; + #thermal-sensor-cells = <0>; + }; + }; + + //qcom,pm7250b@3 { + // compatible = "qcom,spmi-pmic"; + // reg = <0x3 SPMI_USID>; + // #address-cells = <2>; + // #size-cells = <0>; + // + // pm7250b_vib: qcom,vibrator@5300 { + // compatible = "qcom,qpnp-vibrator-ldo"; + // reg = <0x5300 0x100>; + // qcom,vib-ldo-volt-uv = <3000000>; + // qcom,disable-overdrive; + // }; + //}; +}; + +&thermal_zones { + pm7250b_temp_alarm: pm7250b-tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_tz>; + wake-capable-sensor; + + trips { + pm7250b_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm7250b_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pm7250b-ibat-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_bcl 0>; + wake-capable-sensor; + + trips { + ibat_lvl0:ibat-lvl0 { + temperature = <5500>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm7250b-ibat-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_bcl 1>; + wake-capable-sensor; + + trips { + ibat_lvl1:ibat-lvl1 { + temperature = <6000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm7250b-vbat-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm7250b_bcl 2>; + wake-capable-sensor; + tracks-low; + + trips { + vbat_lvl0: vbat-lvl0 { + temperature = <3000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm7250b-vbat-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm7250b_bcl 3>; + wake-capable-sensor; + tracks-low; + + trips { + vbat_lvl1:vbat-lvl1 { + temperature = <2800>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm7250b-vbat-lvl2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm7250b_bcl 4>; + wake-capable-sensor; + tracks-low; + + trips { + vbat_lvl2:vbat-lvl2 { + temperature = <2600>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm7250b-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_bcl 5>; + wake-capable-sensor; + + trips { + b_bcl_lvl0: b-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm7250b-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_bcl 6>; + wake-capable-sensor; + + trips { + b_bcl_lvl1: b-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm7250b-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm7250b_bcl 7>; + wake-capable-sensor; + + trips { + b_bcl_lvl2: b-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + soc { + polling-delay-passive = <5000>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_soc>; + wake-capable-sensor; + tracks-low; + + trips { + soc_trip:soc-trip { + temperature = <5>; + hysteresis = <0>; + type = "passive"; + }; + soc_trip2:soc-trip2 { + temperature = <15>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm8008.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm8008.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..07c8824e2c70db9ef5aaadb47233e9053ea709d5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm8008.dtsi @@ -0,0 +1,127 @@ +#include + +pm8008_8: qcom,pm8008@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <3>; + + interrupt-names = "pm8008"; + qcom,periph-map = <0x09 0x24 0xc0 0xc1>; + + pm8008_chip: qcom,pm8008-chip@900 { + compatible = "qcom,pm8008-chip"; + reg = <0x900>; + interrupts = <0x09 4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ocp"; + + PM8008_EN: qcom,pm8008-chip-en { + regulator-name = "pm8008-chip-en"; + }; + }; + + qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100>; + }; + + pm8008_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x200>; + interrupts = <0xc0 0 IRQ_TYPE_EDGE_RISING>, + <0xc1 0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "pm8008_gpio1", "pm8008_gpio2"; + gpio-controller; + #gpio-cells = <2>; + + pm8008_gpio1_active: pm8008_gpio1_active { + pins = "gpio1"; + function = "func1"; + power-source = <1>; + output-enable; + input-disable; + bias-disable; + }; + }; +}; + +pm8008_9: qcom,pm8008@9 { + compatible = "qcom,i2c-pmic"; + reg = <0x9>; + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_gpio1_active>; + + pm8008_regulators: qcom,pm8008-regulator { + compatible = "qcom,pm8008-regulator"; + pm8008_en-supply = <&PM8008_EN>; + qcom,enable-ocp-broadcast; + + L1P: qcom,pm8008-l1@4000 { + reg = <0x4000>; + regulator-name = "pm8008_l1"; + regulator-min-microvolt = <528000>; + regulator-max-microvolt = <1504000>; + qcom,min-dropout-voltage = <225000>; + qcom,hpm-min-load = <10000>; + }; + + L2P: qcom,pm8008-l2@4100 { + reg = <0x4100>; + regulator-name = "pm8008_l2"; + regulator-min-microvolt = <528000>; + regulator-max-microvolt = <1504000>; + qcom,min-dropout-voltage = <225000>; + qcom,hpm-min-load = <10000>; + }; + + L3P: qcom,pm8008-l3@4200 { + reg = <0x4200>; + regulator-name = "pm8008_l3"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3400000>; + qcom,min-dropout-voltage = <200000>; + qcom,hpm-min-load = <10000>; + }; + + L4P: qcom,pm8008-l4@4300 { + reg = <0x4300>; + regulator-name = "pm8008_l4"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3400000>; + qcom,min-dropout-voltage = <200000>; + qcom,hpm-min-load = <10000>; + }; + + L5P: qcom,pm8008-l5@4400 { + reg = <0x4400>; + regulator-name = "pm8008_l5"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3400000>; + qcom,min-dropout-voltage = <300000>; + qcom,hpm-min-load = <10000>; + }; + + L6P: qcom,pm8008-l6@4400 { + reg = <0x4500>; + regulator-name = "pm8008_l6"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3400000>; + qcom,min-dropout-voltage = <300000>; + qcom,hpm-min-load = <10000>; + }; + + L7P: qcom,pm8008-l7@4400 { + reg = <0x4600>; + regulator-name = "pm8008_l7"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <3400000>; + qcom,min-dropout-voltage = <300000>; + qcom,hpm-min-load = <10000>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm8009.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm8009.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..dd1cea294e04a428219bfea30e19a79420a7a7ca --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm8009.dtsi @@ -0,0 +1,46 @@ +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm8009@a { + compatible ="qcom,spmi-pmic"; + reg = <0xa SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm8009_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x400>; + interrupts = <0xa 0xc0 0 IRQ_TYPE_NONE>, + <0xa 0xc1 0 IRQ_TYPE_NONE>, + <0xa 0xc2 0 IRQ_TYPE_NONE>, + <0xa 0xc3 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8009_gpio1", "pm8009_gpio2", + "pm8009_gpio3", "pm8009_gpio4"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + qcom,pm8009@b { + compatible = "qcom,spmi-pmic"; + reg = <0xb SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm8150.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm8150.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3bbba490d07cefbc4846e2274de6765260197f82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm8150.dtsi @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm8150@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + interrupts = <0x0 0x8 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x8 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "kpdpwr", "resin"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = ; + linux,code = ; + qcom,pull-up; + }; + + qcom,pon_2 { + qcom,pon-type = ; + linux,code = ; + qcom,pull-up; + }; + }; + + pm8150_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pm8150_vadc ADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm8150_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x200>; + #clock-cells = <1>; + qcom,num-clkdivs = <2>; + clock-output-names = "pm8150_div_clk1", + "pm8150_div_clk2"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm8150_sdam_2: sdam@b100 { + compatible = "qcom,spmi-sdam"; + reg = <0xb100 0x100>; + }; + + pm8150_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xa00>; + interrupts = <0x0 0xc0 0x0 IRQ_TYPE_NONE>, + <0x0 0xc2 0x0 IRQ_TYPE_NONE>, + <0x0 0xc5 0x0 IRQ_TYPE_NONE>, + <0x0 0xc6 0x0 IRQ_TYPE_NONE>, + <0x0 0xc8 0x0 IRQ_TYPE_NONE>, + <0x0 0xc9 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150_gpio1", "pm8150_gpio3", + "pm8150_gpio6", "pm8150_gpio7", + "pm8150_gpio9", "pm8150_gpio10"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <2 4 5 8>; + }; + + pm8150_rtc: qcom,pm8150_rtc { + compatible = "qcom,pm8941-rtc"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; + + pm8150_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + ref_gnd@0 { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25@1 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp@2 { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + }; + + pm8150_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pm8150_vadc ADC_AMUX_THM1_PU2>, + <&pm8150_vadc ADC_AMUX_THM2_PU2>; + }; + }; + + qcom,pm8150@1 { + compatible ="qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + }; +}; + +&thermal_zones { + pm8150_temp_alarm: pm8150_tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150_tz>; + wake-capable-sensor; + + trips { + pm8150_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm8150_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm8150b.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9d4633389a45effc37043cb80e12f4ea97de2a69 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm8150b.dtsi @@ -0,0 +1,731 @@ +#include +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm8150b@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8150b_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm8150b_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pm8150b_vadc ADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm8150b_clkdiv: clock-controller@6000 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x6000 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm8150b_div_clk1"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm8150b_pbs1: qcom,pbs@7200 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7200 0x100>; + }; + + pm8150b_qnovo: qcom,sdam-qnovo@b000 { + compatible = "qcom,qpnp-qnovo5"; + reg = <0xb000 0x100>; + interrupts = <0x2 0xb0 1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ptrain-done"; + }; + + pm8150b_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x2 0xc0 0x0 IRQ_TYPE_NONE>, + <0x2 0xc1 0x0 IRQ_TYPE_NONE>, + <0x2 0xc4 0x0 IRQ_TYPE_NONE>, + <0x2 0xc5 0x0 IRQ_TYPE_NONE>, + <0x2 0xc6 0x0 IRQ_TYPE_NONE>, + <0x2 0xc7 0x0 IRQ_TYPE_NONE>, + <0x2 0xc8 0x0 IRQ_TYPE_NONE>, + <0x2 0xc9 0x0 IRQ_TYPE_NONE>, + <0x2 0xcb 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150b_gpio1", "pm8150b_gpio2", + "pm8150b_gpio5", "pm8150b_gpio6", + "pm8150b_gpio7", "pm8150b_gpio8", + "pm8150b_gpio9", "pm8150b_gpio10", + "pm8150b_gpio12"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <3 4 11>; + }; + + pm8150b_charger: qcom,qpnp-smb5 { + compatible = "qcom,qpnp-smb5"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,pmic-revid = <&pm8150b_revid>; + + qcom,thermal-mitigation + = <3000000 1500000 1000000 500000>; + + qcom,chg-term-src = <1>; + qcom,charger-temp-max = <800>; + qcom,smb-temp-max = <800>; + status = "disabled"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x10 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "chgr-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-req", + "vph-alarm", + "vph-drop-prechg"; + }; + + qcom,dcdc@1100 { + reg = <0x1100 0x100>; + interrupts = + <0x2 0x11 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-oc-disable-sw", + "otg-oc-hiccup", + "high-duty-cycle", + "input-current-limiting", + "concurrent-mode-disable", + "switcher-power-ok"; + }; + + qcom,batif@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "bat-temp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing", + "buck-oc", + "vph-ov"; + }; + + qcom,usb@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-collapse", + "usbin-vashdn", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-revi-change", + "usbin-src-change", + "usbin-icl-change"; + }; + + qcom,dc@1400 { + reg = <0x1400 0x100>; + interrupts = + <0x2 0x14 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x14 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "dcin-vashdn", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "dcin-revi", + "dcin-pon", + "dcin-en"; + }; + + qcom,typec@1500 { + reg = <0x1500 0x100>; + interrupts = + <0x2 0x15 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x15 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "typec-or-rid-detect-change", + "typec-vpd-detect", + "typec-cc-state-change", + "typec-vconn-oc", + "typec-vbus-change", + "typec-attach-detach", + "typec-legacy-cable-detect", + "typec-try-snk-src-detect"; + }; + + qcom,misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "smb-en", + "temp-change", + "temp-change-smb"; + }; + }; + + pm8150b_pdphy: qcom,usb-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + interrupts = <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded", + "fr-swap"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>, /* 9V @ 3A */ + <12000 2250>; /* 12V @ 2.25A */ + }; + + pm8150b_bcl: bcl@1d00 { + compatible = "qcom,bcl-v5"; + reg = <0x1d00 0x100>; + interrupts = <0x2 0x1d 0x0 IRQ_TYPE_NONE>, + <0x2 0x1d 0x1 IRQ_TYPE_NONE>, + <0x2 0x1d 0x2 IRQ_TYPE_NONE>; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; + #thermal-sensor-cells = <1>; + }; + + bcl_soc:bcl-soc { + compatible = "qcom,msm-bcl-soc"; + #thermal-sensor-cells = <0>; + }; + + pm8150b_fg: qpnp,fg { + compatible = "qcom,fg-gen4"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pm8150b_revid>; + qcom,pmic-pbs = <&pm8150b_pbs1>; + status = "disabled"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x2 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x3 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x5 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta", + "msoc-low", + "msoc-empty", + "msoc-high", + "msoc-full"; + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x3 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "vbatt-low", + "vbatt-pred-delta", + "esr-delta"; + }; + + qcom,fg-rradc@4200 { + status = "okay"; + reg = <0x4200 0x100>; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x42 0x4 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "batt-missing", + "batt-id", + "batt-temp-delta", + "batt-temp-hot", + "batt-temp-cold"; + }; + + qcom,fg-memif@4300 { + status = "okay"; + reg = <0x4300 0x100>; + interrupts = <0x2 0x43 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x43 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x43 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x43 0x3 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x43 0x4 + IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "ima-rdy", + "ima-xcp", + "dma-xcp", + "dma-grant", + "mem-attn"; + }; + }; + + pm8150b_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>, <0x3700 0x100>; + reg-names = "adc5-usr-base", "adc5-cal-base"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + ref_gnd@0 { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25@1 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp@2 { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + chg_temp@9 { + reg = ; + label = "chg_temp"; + qcom,pre-scaling = <1 1>; + }; + + bat_id@4b { + reg = ; + label = "bat_id"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + smb1390_therm@e { + reg = ; + label = "smb1390_therm"; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + smb1355_therm@4e { + reg = ; + label = "smb1355_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + }; + + pm8150b_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + qcom,pmic-revid = <&pm8150b_revid>; + }; + }; + + qcom,pm8150b@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8150b_pwm: qcom,pwms@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x200>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <2>; + }; + + pm8150b_hr_led: qcom,leds@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + nvmem-names = "pbs_sdam"; + nvmem = <&pm8150_sdam_2>; + hr_led1 { + label = "hr_led1"; + pwms = <&pm8150b_pwm 0 1000000>; + led-sources = <0>; + }; + + hr_led2 { + label = "hr_led2"; + pwms = <&pm8150b_pwm 1 1000000>; + led-sources = <1>; + }; + }; + + pm8150b_haptics: qcom,haptics@c000 { + compatible = "qcom,haptics"; + reg = <0xc000 0x100>; + interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "hap-sc-irq", "hap-play-irq"; + qcom,actuator-type = "lra"; + qcom,vmax-mv = <3600>; + qcom,play-rate-us = <6667>; + qcom,lra-resonance-sig-shape = "sine"; + qcom,lra-auto-resonance-mode = "qwd"; + qcom,lra-allow-variable-play-rate; + + wf_0 { + /* CLICK */ + qcom,effect-id = <0>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [00 00 00 00]; + qcom,wf-repeat-count = <1>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + + wf_1 { + /* DOUBLE CLICK */ + qcom,effect-id = <1>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [00 00 00 00]; + qcom,wf-repeat-count = <1>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + + wf_2 { + /* TICK */ + qcom,effect-id = <2>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [00 00 00 00]; + qcom,wf-repeat-count = <1>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + + wf_3 { + /* THUD */ + qcom,effect-id = <3>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [00 00 00 00]; + qcom,wf-repeat-count = <1>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + + wf_4 { + /* POP */ + qcom,effect-id = <4>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [00 00 00 00]; + qcom,wf-repeat-count = <1>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + + wf_5 { + /* HEAVY CLICK */ + qcom,effect-id = <5>; + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-play-rate-us = <6667>; + qcom,wf-brake-pattern = [00 00 00 00]; + qcom,wf-repeat-count = <1>; + qcom,wf-s-repeat-count = <1>; + qcom,lra-auto-resonance-disable; + }; + }; + }; +}; + +&thermal_zones { + pm8150b_temp_alarm: pm8150b_tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_tz>; + wake-capable-sensor; + + trips { + pm8150b_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm8150b_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pm8150b-ibat-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 0>; + wake-capable-sensor; + + trips { + ibat_lvl0:ibat-lvl0 { + temperature = <4500>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150b-ibat-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 1>; + wake-capable-sensor; + + trips { + ibat_lvl1:ibat-lvl1 { + temperature = <5000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150b-vbat-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm8150b_bcl 2>; + tracks-low; + wake-capable-sensor; + + trips { + vbat_lvl0: vbat-lvl0 { + temperature = <3000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150b-vbat-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm8150b_bcl 3>; + tracks-low; + wake-capable-sensor; + + trips { + vbat_lvl1:vbat-lvl1 { + temperature = <2800>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150b-vbat-lvl2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm8150b_bcl 4>; + tracks-low; + wake-capable-sensor; + + trips { + vbat_lvl2:vbat-lvl2 { + temperature = <2600>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150b-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 5>; + wake-capable-sensor; + + trips { + b_bcl_lvl0: b-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150b-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 6>; + wake-capable-sensor; + + trips { + b_bcl_lvl1: b-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150b-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150b_bcl 7>; + wake-capable-sensor; + + trips { + b_bcl_lvl2: b-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + soc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_soc>; + tracks-low; + wake-capable-sensor; + + trips { + soc_trip:soc-trip { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pm8150l.dtsi b/arch/arm64/boot/dts/vendor/qcom/pm8150l.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d89288b61785c3323c587260d714ef1f725f1f15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pm8150l.dtsi @@ -0,0 +1,558 @@ +#include +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pm8150l@4 { + compatible = "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8150l_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pm8150l_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pm8150l_vadc ADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pm8150l_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,num-clkdivs = <1>; + clock-output-names = "pm8150l_div_clk1"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; + }; + + pm8150l_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xc00>; + interrupts = <0x4 0xc0 0x0 IRQ_TYPE_NONE>, + <0x4 0xc2 0x0 IRQ_TYPE_NONE>, + <0x4 0xc3 0x0 IRQ_TYPE_NONE>, + <0x4 0xc4 0x0 IRQ_TYPE_NONE>, + <0x4 0xc5 0x0 IRQ_TYPE_NONE>, + <0x4 0xc6 0x0 IRQ_TYPE_NONE>, + <0x4 0xc7 0x0 IRQ_TYPE_NONE>, + <0x4 0xc9 0x0 IRQ_TYPE_NONE>, + <0x4 0xca 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pm8150l_gpio1", "pm8150l_gpio3", + "pm8150l_gpio4", "pm8150l_gpio5", + "pm8150l_gpio6", "pm8150l_gpio7", + "pm8150l_gpio8", "pm8150l_gpio10", + "pm8150l_gpio11"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <2 9 12>; + }; + + pm8150l_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x4 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel node */ + ref_gnd@0 { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25@1 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp@2 { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + }; + + pm8150l_bcl: bcl@3d00 { + compatible = "qcom,bcl-v5"; + reg = <0x3d00 0x100>; + interrupts = <0x4 0x3d 0x0 IRQ_TYPE_NONE>, + <0x4 0x3d 0x1 IRQ_TYPE_NONE>, + <0x4 0x3d 0x2 IRQ_TYPE_NONE>; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; + #thermal-sensor-cells = <1>; + }; + + pm8150l_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x4 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + io-channels = <&pm8150l_vadc ADC_AMUX_THM1_PU2>, + <&pm8150l_vadc ADC_AMUX_THM2_PU2>, + <&pm8150l_vadc ADC_AMUX_THM3_PU2>; + }; + }; + + qcom,pm8150l@5 { + compatible ="qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pm8150l_lcdb: qcom,lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + reg = <0xec00 0x100>; + interrupts = <0x5 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + qcom,pmic-revid = <&pm8150l_revid>; + qcom,voltage-step-ramp; + status = "disabled"; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_bst_vreg: bst { + label = "bst"; + regulator-name = "lcdb_bst"; + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <6275000>; + }; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x5 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,hdrm-auto-mode; + qcom,short-circuit-det; + qcom,open-circuit-det; + qcom,vph-droop-det; + qcom,thermal-derate-en; + qcom,thermal-derate-current = <200 500 1000>; + qcom,isc-delay = <192>; + qcom,pmic-revid = <&pm8150l_revid>; + + pm8150l_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm8150l_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm8150l_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + status = "disabled"; + }; + + pm8150l_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm8150l_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pm8150l_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + status = "disabled"; + }; + + pm8150l_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <1>; /* Channel 1 */ + qcom,default-led-trigger = "switch0_trigger"; + }; + + pm8150l_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <2>; /* Channel 2 */ + qcom,default-led-trigger = "switch1_trigger"; + }; + + pm8150l_switch2: qcom,led_switch_2 { + label = "switch"; + qcom,led-name = "led:switch_2"; + qcom,led-mask = <3>; /* Channels 1 and 2 */ + qcom,default-led-trigger = "switch2_trigger"; + }; + + pm8150l_switch3: qcom,led_switch_3 { + label = "switch"; + qcom,led-name = "led:switch_3"; + qcom,led-mask = <4>; /* Channel 3 */ + qcom,default-led-trigger = "switch3_trigger"; + }; + }; + + pm8150l_wled: qcom,wled@d800 { + compatible = "qcom,pm8150l-spmi-wled"; + reg = <0xd800 0x100>, <0xd900 0x100>; + reg-names = "wled-ctrl-base", "wled-sink-base"; + label = "backlight"; + interrupts = <0x5 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x5 0xd8 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x5 0xd8 0x5 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "ovp-irq", "pre-flash-irq", + "flash-irq"; + qcom,pmic-revid = <&pm8150l_revid>; + qcom,auto-calibration; + status = "disabled"; + + wled_flash: qcom,wled-flash { + label = "flash"; + qcom,default-led-trigger = "wled_flash"; + }; + + wled_torch: qcom,wled-torch { + label = "torch"; + qcom,default-led-trigger = "wled_torch"; + qcom,wled-torch-timer = <1200>; + }; + + wled_switch: qcom,wled-switch { + label = "switch"; + qcom,default-led-trigger = "wled_switch"; + }; + }; + + pm8150l_lpg: qcom,pwms@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x300>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <3>; + qcom,lut-patterns = <0 10 20 30 40 50 60 70 80 90 100 + 90 80 70 60 50 40 30 20 10 0>; + lpg1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + + lpg3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <100>; + qcom,ramp-pause-hi-count = <2>; + qcom,ramp-pause-lo-count = <2>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <20>; + qcom,ramp-from-low-to-high; + qcom,ramp-pattern-repeat; + }; + }; + + pm8150l_pwm: qcom,pwms@bc00 { + compatible = "qcom,pwm-lpg"; + reg = <0xbc00 0x200>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <2>; + }; + + pm8150l_rgb_led: qcom,leds@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + red { + label = "red"; + pwms = <&pm8150l_lpg 0 1000000>; + led-sources = <0>; + linux,default-trigger = "timer"; + }; + + green { + label = "green"; + pwms = <&pm8150l_lpg 1 1000000>; + led-sources = <1>; + linux,default-trigger = "timer"; + }; + + blue { + label = "blue"; + pwms = <&pm8150l_lpg 2 1000000>; + led-sources = <2>; + linux,default-trigger = "timer"; + }; + }; + + pm8150a_amoled: qcom,amoled { + compatible = "qcom,qpnp-amoled-regulator"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + oledb_vreg: oledb@e000 { + reg = <0xe000 0x100>; + reg-names = "oledb_base"; + regulator-name = "oledb"; + regulator-min-microvolt = <4925000>; + regulator-max-microvolt = <8100000>; + qcom,swire-control; + }; + + ab_vreg: ab@de00 { + reg = <0xde00 0x100>; + reg-names = "ab_base"; + regulator-name = "ab"; + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6100000>; + qcom,swire-control; + }; + + ibb_vreg: ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_base"; + regulator-name = "ibb"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <5400000>; + qcom,swire-control; + }; + }; + }; +}; + +&thermal_zones { + pm8150l_temp_alarm: pm8150l_tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_tz>; + wake-capable-sensor; + + trips { + trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pm8150l-vph-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm8150l_bcl 2>; + tracks-low; + wake-capable-sensor; + + trips { + vph_lvl0: vph-lvl0 { + temperature = <3000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150l-vph-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm8150l_bcl 3>; + tracks-low; + wake-capable-sensor; + + trips { + vph_lvl1:vph-lvl1 { + temperature = <2750>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150l-vph-lvl2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&pm8150l_bcl 4>; + tracks-low; + wake-capable-sensor; + + trips { + vph_lvl2:vph-lvl2 { + temperature = <2500>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pm8150l-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_bcl 5>; + wake-capable-sensor; + + trips { + l_bcl_lvl0: l-bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150l-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_bcl 6>; + wake-capable-sensor; + + trips { + l_bcl_lvl1: l-bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pm8150l-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8150l_bcl 7>; + wake-capable-sensor; + + trips { + l_bcl_lvl2: l-bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pmi632.dtsi b/arch/arm64/boot/dts/vendor/qcom/pmi632.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..26464cc7f5b460113e2ea03b0be3132dd96d1e0d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pmi632.dtsi @@ -0,0 +1,773 @@ +#include +#include +#include + +&spmi_bus { + qcom,pmi632@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 0x0>; + #address-cells = <2>; + #size-cells = <0>; + + pmi632_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pmi632_pon: qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pmi632_vadc: vadc@3100 { + compatible = "qcom,spmi-adc5-lite"; + reg = <0x3100 0x100>, <0x3700 0x100>; + reg-names = "adc5-usr-base", "adc5-cal-base"; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x2 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; + qcom,pmic-revid = <&pmi632_revid>; + + /* Channel nodes */ + ref_gnd { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vbat_sns { + reg = ; + label = "vbat_sns"; + qcom,pre-scaling = <1 3>; + }; + + usb_in_i_uv { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; + + chg_temp { + reg = ; + label = "chg_temp"; + qcom,pre-scaling = <1 1>; + }; + + bat_therm { + reg = ; + label = "bat_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_therm_30k { + reg = ; + label = "bat_therm_30k"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_therm_400k { + reg = ; + label = "bat_therm_400k"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + bat_id { + reg = ; + label = "bat_id"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + i_parallel { + reg = ; + label = "i_parallel"; + qcom,pre-scaling = <1 1>; + }; + + v_i_int_ext { + reg = ; + label = "v_i_int_vbat_vdata"; + qcom,pre-scaling = <1 1>; + }; + + v_i_parallel { + reg = ; + label = "v_i_parallel_vbat_vdata"; + qcom,pre-scaling = <1 1>; + }; + + }; + + pmi632_adc_tm: adc_tm@3500 { + compatible = "qcom,adc-tm5"; + reg = <0x3500 0x100>; + interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + }; + + pmi632_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pmi632_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x800>; + interrupts = <0x2 0xc0 0 IRQ_TYPE_NONE>, + <0x2 0xc1 0 IRQ_TYPE_NONE>, + <0x2 0xc2 0 IRQ_TYPE_NONE>, + <0x2 0xc3 0 IRQ_TYPE_NONE>, + <0x2 0xc4 0 IRQ_TYPE_NONE>, + <0x2 0xc5 0 IRQ_TYPE_NONE>, + <0x2 0xc6 0 IRQ_TYPE_NONE>, + <0x2 0xc7 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi632_gpio1", "pmi632_gpio2", + "pmi632_gpio3", "pmi632_gpio4", + "pmi632_gpio5", "pmi632_gpio6", + "pmi632_gpio7", "pmi632_gpio8"; + gpio-controller; + #gpio-cells = <2>; + }; + + pmi632_charger: qcom,qpnp-smb5 { + compatible = "qcom,qpnp-smb5"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,pmic-revid = <&pmi632_revid>; + io-channels = <&pmi632_vadc ADC_USB_IN_V_16>, + <&pmi632_vadc ADC_USB_IN_I>, + <&pmi632_vadc ADC_CHG_TEMP>, + <&pmi632_vadc ADC_DIE_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp", + "die_temp"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x2 0x10 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x10 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "chgr-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-req", + "fg-fvcal-qualified", + "vph-alarm", + "vph-drop-prechg"; + }; + + qcom,dcdc@1100 { + reg = <0x1100 0x100>; + interrupts = + <0x2 0x11 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x11 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-oc-disable-sw", + "otg-oc-hiccup", + "bsm-active", + "high-duty-cycle", + "input-current-limiting", + "concurrent-mode-disable", + "switcher-power-ok"; + }; + + qcom,batif@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x12 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x12 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "bat-temp", + "all-chnl-conv-done", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing", + "buck-oc", + "vph-ov"; + }; + + qcom,usb@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x2 0x13 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x13 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-collapse", + "usbin-vashdn", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-revi-change", + "usbin-src-change", + "usbin-icl-change"; + }; + + qcom,typec@1500 { + reg = <0x1500 0x100>; + interrupts = + <0x2 0x15 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x15 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x15 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x15 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x15 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "typec-or-rid-detect-change", + "typec-vpd-detect", + "typec-cc-state-change", + "typec-vconn-oc", + "typec-vbus-change", + "typec-attach-detach", + "typec-legacy-cable-detect", + "typec-try-snk-src-detect"; + }; + + qcom,misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x2 0x16 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x16 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "smb-en", + "imp-trigger", + "temp-change", + "temp-change-smb"; + }; + + qcom,schgm-flash@a600 { + reg = <0xa600 0x100>; + interrupts = + <0x2 0xa6 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0xa6 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0xa6 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0xa6 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "flash-state-change", + "ilim1-s1", + "ilim2-s2", + "vreg-ok"; + }; + }; + + pmi632_qg: qpnp,qg { + compatible = "qcom,qpnp-qg"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,pmic-revid = <&pmi632_revid>; + io-channels = <&pmi632_vadc ADC_BAT_THERM_PU2>, + <&pmi632_vadc ADC_BAT_ID_PU2>; + io-channel-names = "batt-therm", + "batt-id"; + + qcom,qgauge@4800 { + status = "okay"; + reg = <0x4800 0x100>; + interrupts = + <0x2 0x48 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x48 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x48 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x48 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "qg-batt-missing", + "qg-vbat-low", + "qg-vbat-empty", + "qg-fifo-done", + "qg-good-ocv"; + }; + + qcom,qg-sdam@b100 { + status = "okay"; + reg = <0xb100 0x100>; + }; + }; + + pmi632_pbs_client3: qcom,pbs@7400 { + compatible = "qcom,qpnp-pbs"; + reg = <0x7400 0x100>; + }; + + pmi632_sdam7: qcom,sdam@b600 { + compatible = "qcom,spmi-sdam"; + reg = <0xb600 0x100>; + }; + + bcl_sensor: bcl@3d00 { + compatible = "qcom,bcl-v5"; + reg = <0x3d00 0x100>; + interrupts = <0x2 0x3d 0x0 IRQ_TYPE_NONE>, + <0x2 0x3d 0x1 IRQ_TYPE_NONE>, + <0x2 0x3d 0x2 IRQ_TYPE_NONE>; + interrupt-names = "bcl-lvl0", + "bcl-lvl1", + "bcl-lvl2"; + qcom,ibat-use-qg-adc-5a; + #thermal-sensor-cells = <1>; + }; + + bcl_soc: bcl-soc { + compatible = "qcom,msm-bcl-soc"; + #thermal-sensor-cells = <0>; + }; + }; + + pmi632_3: qcom,pmi632@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 0x0>; + #address-cells = <2>; + #size-cells = <0>; + + pmi632_vib: qcom,vibrator@5700 { + compatible = "qcom,qpnp-vibrator-ldo"; + reg = <0x5700 0x100>; + qcom,vib-ldo-volt-uv = <3000000>; + qcom,disable-overdrive; + }; + + pmi632_pwm: qcom,pwms@b300 { + compatible = "qcom,pwm-lpg"; + reg = <0xb300 0x500>; + reg-names = "lpg-base"; + #pwm-cells = <2>; + qcom,num-lpg-channels = <5>; + nvmem-names = "ppg_sdam"; + nvmem = <&pmi632_sdam7>; + qcom,pbs-client = <&pmi632_pbs_client3>; + qcom,lut-sdam-base = <0x80>; + qcom,lut-patterns = <0 0 0 14 28 42 56 70 84 100 + 100 84 70 56 42 28 14 0 0 0>; + lpg@1 { + qcom,lpg-chan-id = <1>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <19>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x48>; + }; + + lpg@2 { + qcom,lpg-chan-id = <2>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <19>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x56>; + }; + + lpg@3 { + qcom,lpg-chan-id = <3>; + qcom,ramp-step-ms = <200>; + qcom,ramp-low-index = <0>; + qcom,ramp-high-index = <19>; + qcom,ramp-pattern-repeat; + qcom,lpg-sdam-base = <0x64>; + }; + }; + + pmi632_rgb: qcom,leds@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; + red { + label = "red"; + pwms = <&pmi632_pwm 0 1000000>; + led-sources = <0>; + linux,default-trigger = "timer"; + }; + + green { + label = "green"; + pwms = <&pmi632_pwm 1 1000000>; + led-sources = <1>; + linux,default-trigger = "timer"; + }; + + blue { + label = "blue"; + pwms = <&pmi632_pwm 2 1000000>; + led-sources = <2>; + linux,default-trigger = "timer"; + }; + }; + + pmi632_lcdb: qpnp-lcdb@ec00 { + compatible = "qcom,qpnp-lcdb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0xec00 0x100>; + interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "sc-irq"; + + qcom,pmic-revid = <&pmi632_revid>; + qcom,voltage-step-ramp; + + lcdb_ldo_vreg: ldo { + label = "ldo"; + regulator-name = "lcdb_ldo"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_ncp_vreg: ncp { + label = "ncp"; + regulator-name = "lcdb_ncp"; + regulator-min-microvolt = <4000000>; + regulator-max-microvolt = <6000000>; + }; + + lcdb_bst_vreg: bst { + label = "bst"; + regulator-name = "lcdb_bst"; + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <6275000>; + }; + }; + + flash_led: qcom,leds@d300 { + compatible = "qcom,qpnp-flash-led-v2"; + status = "okay"; + reg = <0xd300 0x100>; + label = "flash"; + interrupts = <0x3 0xd3 0x0 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd3 0x3 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd3 0x4 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "led-fault-irq", + "all-ramp-down-done-irq", + "all-ramp-up-done-irq"; + qcom,short-circuit-det; + qcom,open-circuit-det; + qcom,vph-droop-det; + qcom,thermal-derate-en; + qcom,thermal-derate-current = <200 500 1000>; + qcom,isc-delay = <192>; + qcom,pmic-revid = <&pmi632_revid>; + + pmi632_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <400>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi632_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <400>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi632_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <400>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi632_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <400>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi632_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch0_trigger"; + }; + + pmi632_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <2>; + qcom,default-led-trigger = "switch1_trigger"; + }; + + }; + + }; +}; + +&thermal_zones { + pmi632-tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pmi632_tz>; + wake-capable-sensor; + + trips { + pmi632_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pmi632_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + pmi632-ibat-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 0>; + wake-capable-sensor; + + trips { + pmi632_ibat_lvl0: ibat-lvl0 { + temperature = <4000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pmi632-ibat-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 1>; + wake-capable-sensor; + + trips { + pmi632_ibat_lvl1: ibat-lvl1 { + temperature = <4200>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + + pmi632-vbat-lvl0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 2>; + wake-capable-sensor; + tracks-low; + + trips { + pmi632_vbat_lvl0: vbat-lvl0 { + temperature = <3000>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + pmi632-vbat-lvl1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 3>; + wake-capable-sensor; + tracks-low; + + trips { + pmi632_vbat_lvl1: vbat-lvl1 { + temperature = <2800>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + pmi632-vbat-lvl2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 4>; + wake-capable-sensor; + tracks-low; + + trips { + pmi632_vbat_lvl2: vbat-lvl1 { + temperature = <2600>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + pmi632-bcl-lvl0 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 5>; + wake-capable-sensor; + + trips { + bcl_lvl0: bcl-lvl0 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pmi632-bcl-lvl1 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 6>; + wake-capable-sensor; + + trips { + bcl_lvl1: bcl-lvl1 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + pmi632-bcl-lvl2 { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 7>; + wake-capable-sensor; + + trips { + bcl_lvl2: bcl-lvl2 { + temperature = <1>; + hysteresis = <1>; + type = "passive"; + }; + }; + }; + + soc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_soc>; + wake-capable-sensor; + tracks-low; + + trips { + pmi632_low_soc: low-soc { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/vendor/qcom/pmk8350.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c7261d51c8b2abb1e70e7b86ed6a289de3100dee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pmk8350.dtsi @@ -0,0 +1,93 @@ +#include +#include + +#define PMK8350_SID 6 + +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pmk8350@6 { + compatible = "qcom,spmi-pmic"; + reg = <6 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmk8350_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pmk8350_vadc: vadc@3100 { + compatible = "qcom,spmi-adc7"; + reg = <0x3100 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x6 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + #io-channel-cells = <1>; + io-channel-ranges; + + /* Channel nodes */ + ref_gnd { + reg = ; + label = "ref_gnd"; + qcom,pre-scaling = <1 1>; + }; + + vref_1p25 { + reg = ; + label = "vref_1p25"; + qcom,pre-scaling = <1 1>; + }; + + die_temp { + reg = ; + label = "die_temp"; + qcom,pre-scaling = <1 1>; + }; + + xo_therm { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + }; + + pmk8350_adc_tm: adc_tm@3400 { + compatible = "qcom,adc-tm7"; + reg = <0x3400>; + interrupts = <0x6 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; + #address-cells = <1>; + #size-cells = <0>; + #thermal-sensor-cells = <1>; + }; + + pmk8350_rtc: rtc@6100 { + compatible = "qcom,pmk8350-rtc"; + reg = <0x6100>, <0x6200>; + reg-names = "rtc", "alarm"; + interrupts = <0x6 0x62 0x1 IRQ_TYPE_EDGE_RISING>; + }; + + pmk8350_gpios: pinctrl@b000 { + compatible = "qcom,spmi-gpio"; + reg = <0xb000 0x400>; + interrupts = <0x6 0xb0 0x0 IRQ_TYPE_NONE>, + <0x6 0xb1 0x0 IRQ_TYPE_NONE>, + <0x6 0xb2 0x0 IRQ_TYPE_NONE>, + <0x6 0xb3 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pmk8350_gpio1", "pmk8350_gpio2", + "pmk8350_gpio3", "pmk8350_gpio4"; + gpio-controller; + #gpio-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/pmr735b.dtsi b/arch/arm64/boot/dts/vendor/qcom/pmr735b.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2d085abf63787c37772f1654f1278ab1af4d88ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/pmr735b.dtsi @@ -0,0 +1,42 @@ +#include +#include + +&spmi_bus { + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + + qcom,pmr735b@a { + compatible = "qcom,spmi-pmic"; + reg = <10 SPMI_USID>; + #address-cells = <1>; + #size-cells = <1>; + + pmr735b_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pmr735b_tz: qcom,temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00 0x100>; + interrupts = <0xa 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; + }; + + pmr735b_gpios: pinctrl@8800 { + compatible = "qcom,spmi-gpio"; + reg = <0x8800 0x400>; + interrupts = <0xa 0x88 0x0 IRQ_TYPE_NONE>, + <0xa 0x89 0x0 IRQ_TYPE_NONE>, + <0xa 0x8a 0x0 IRQ_TYPE_NONE>, + <0xa 0x8b 0x0 IRQ_TYPE_NONE>; + interrupt-names = "pmr735b_gpio1", "pmr735b_gpio2", + "pmr735b_gpio3", "pmr735b_gpio4"; + gpio-controller; + #gpio-cells = <2>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-alium-3600mah.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..051f64164fb2a31c01dfc23febc9a5c1ecf2c5f7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-alium-3600mah.dtsi @@ -0,0 +1,1035 @@ +qcom,alium_860_89032_0000_3600mAh { + /* Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Jun15th2018 */ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-uv = <4340000>; + qcom,fastchg-current-ma = <5400>; + qcom,batt-id-kohm = <107>; + qcom,battery-beta = <4250>; + qcom,battery-therm-kohm = <100>; + qcom,battery-type = "Alium_860_89032_0000_3600mAh_Jun15th2018"; + qcom,qg-batt-profile-ver = <100>; + + qcom,jeita-fcc-ranges = <0 50 2500000 + 51 400 5400000 + 401 450 2500000>; + qcom,jeita-fv-ranges = <0 50 4250000 + 51 400 4350000 + 401 450 4250000>; + qcom,step-chg-ranges = <3600000 3800000 5400000 + 3800001 4300000 3600000 + 4300001 4350000 2500000>; + qcom,ocv-based-step-chg; + + /* COOL = 5 DegC, WARM = 40 DegC */ + qcom,jeita-soft-thresholds = <0x5314 0x25e3>; + /* COLD = 0 DegC, HOT = 45 DegC */ + qcom,jeita-hard-thresholds = <0x58cd 0x20b8>; + /* COOL hys = 8 DegC, WARM hys = 37 DegC */ + qcom,jeita-soft-hys-thresholds = <0x4f5e 0x2943>; + qcom,jeita-soft-fcc-ua = <2500000 2500000>; + qcom,jeita-soft-fv-uv = <4250000 4250000>; + + qcom,fcc1-temp-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-data = <3426 3519 3581 3613 3630>; + }; + + qcom,fcc2-temp-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-data = <3546 3576 3586 3588 3583 3583>; + }; + + qcom,pc-temp-v1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <43078 43267 43365 43394 43399>, + <42839 43052 43147 43186 43196>, + <42609 42823 42920 42964 42981>, + <42392 42591 42693 42738 42759>, + <42186 42370 42469 42513 42535>, + <41983 42159 42248 42289 42310>, + <41776 41953 42032 42066 42085>, + <41565 41745 41820 41847 41863>, + <41376 41534 41607 41630 41645>, + <41226 41338 41393 41412 41426>, + <41086 41189 41206 41205 41212>, + <40873 41057 41063 41032 41014>, + <40523 40858 40918 40878 40833>, + <40155 40509 40680 40678 40639>, + <39917 40145 40325 40390 40407>, + <39757 39925 40039 40116 40180>, + <39638 39781 39894 39960 40010>, + <39541 39669 39779 39850 39877>, + <39455 39579 39646 39699 39715>, + <39364 39489 39487 39469 39489>, + <39266 39366 39306 39235 39257>, + <39165 39210 39096 39058 39072>, + <39060 39042 38900 38912 38919>, + <38955 38854 38767 38784 38785>, + <38859 38675 38671 38668 38668>, + <38773 38551 38581 38562 38562>, + <38692 38462 38490 38466 38462>, + <38619 38394 38403 38377 38369>, + <38552 38343 38327 38296 38283>, + <38491 38301 38257 38222 38203>, + <38439 38261 38195 38156 38132>, + <38392 38224 38142 38097 38067>, + <38348 38190 38095 38043 38010>, + <38306 38161 38052 37989 37952>, + <38265 38135 38015 37938 37895>, + <38223 38102 37976 37886 37836>, + <38181 38066 37935 37830 37771>, + <38128 38020 37890 37771 37701>, + <38054 37950 37823 37699 37623>, + <37964 37850 37727 37613 37538>, + <37862 37740 37617 37512 37439>, + <37739 37617 37494 37390 37318>, + <37601 37487 37361 37256 37185>, + <37448 37354 37221 37119 37052>, + <37327 37238 37120 37019 36955>, + <37241 37161 37057 36960 36898>, + <37209 37134 37035 36943 36881>, + <37182 37113 37018 36927 36865>, + <37146 37086 36991 36896 36829>, + <37036 36976 36855 36724 36634>, + <36712 36636 36510 36372 36278>, + <36253 36181 36056 35916 35819>, + <35673 35600 35476 35330 35231>, + <34889 34811 34685 34533 34429>, + <33644 33573 33450 33289 33175>, + <30000 30000 30000 30000 30000>; + }; + + qcom,pc-temp-v2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <43405 43390 43380 43360 43310 43280>, + <43003 43066 43092 43094 43055 43033>, + <42659 42770 42823 42839 42808 42792>, + <42388 42505 42573 42597 42570 42556>, + <42183 42269 42342 42369 42341 42328>, + <41972 42046 42121 42146 42116 42104>, + <41647 41828 41907 41928 41893 41879>, + <41314 41618 41700 41715 41674 41657>, + <41242 41409 41488 41499 41455 41438>, + <41295 41194 41265 41273 41232 41219>, + <41338 41020 41073 41079 41031 41013>, + <41030 40918 40949 40949 40883 40839>, + <40301 40831 40837 40833 40747 40674>, + <39816 40619 40617 40621 40542 40474>, + <39553 40056 40158 40222 40214 40226>, + <39352 39574 39750 39893 39934 39999>, + <39187 39400 39544 39757 39792 39836>, + <39047 39287 39391 39659 39684 39694>, + <38903 39154 39240 39507 39524 39512>, + <38748 38998 39093 39269 39281 39271>, + <38600 38840 38951 39039 39045 39043>, + <38473 38688 38809 38867 38872 38870>, + <38360 38541 38673 38723 38728 38725>, + <38269 38408 38551 38598 38603 38600>, + <38195 38289 38441 38488 38492 38488>, + <38132 38186 38339 38387 38390 38385>, + <38076 38102 38245 38293 38296 38290>, + <38026 38033 38158 38206 38208 38200>, + <37976 37977 38077 38128 38127 38118>, + <37929 37931 38001 38058 38053 38043>, + <37882 37891 37932 37991 37985 37974>, + <37835 37852 37869 37926 37922 37912>, + <37786 37815 37814 37863 37863 37853>, + <37734 37776 37764 37798 37793 37778>, + <37680 37735 37722 37732 37704 37675>, + <37621 37692 37680 37666 37610 37565>, + <37558 37641 37633 37602 37526 37469>, + <37492 37582 37583 37538 37448 37384>, + <37421 37513 37524 37470 37374 37308>, + <37348 37429 37450 37396 37302 37235>, + <37274 37332 37362 37312 37222 37156>, + <37201 37229 37261 37208 37121 37056>, + <37130 37124 37145 37082 36997 36933>, + <37054 37029 37028 36964 36881 36820>, + <36966 36949 36952 36902 36830 36771>, + <36849 36873 36903 36875 36801 36743>, + <36768 36823 36880 36854 36784 36726>, + <36666 36763 36850 36823 36756 36699>, + <36509 36668 36775 36740 36671 36604>, + <36284 36467 36557 36486 36422 36338>, + <35954 36107 36161 36071 36005 35919>, + <35477 35597 35626 35539 35482 35397>, + <34808 34917 34941 34844 34796 34717>, + <33818 33942 34003 33928 33918 33830>, + <32458 32548 32795 32808 32663 32496>, + <28619 28270 28017 28020 27984 27930>; + }; + + qcom,pc-temp-z1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <14545 13238 12041 11680 11593>, + <14523 13183 12045 11678 11602>, + <14531 13174 12043 11685 11612>, + <14535 13182 12039 11687 11616>, + <14547 13186 12035 11688 11618>, + <14571 13181 12033 11688 11620>, + <14591 13164 12034 11689 11623>, + <14582 13150 12035 11692 11626>, + <14551 13149 12037 11694 11629>, + <14518 13154 12041 11697 11631>, + <14486 13152 12045 11701 11634>, + <14452 13134 12047 11704 11639>, + <14403 13116 12047 11707 11643>, + <14352 13102 12043 11707 11644>, + <14318 13096 12036 11705 11644>, + <14291 13097 12033 11703 11644>, + <14262 13097 12036 11707 11647>, + <14226 13100 12042 11714 11653>, + <14194 13111 12052 11721 11659>, + <14181 13129 12065 11726 11663>, + <14179 13150 12076 11731 11667>, + <14186 13172 12085 11736 11672>, + <14195 13188 12093 11741 11676>, + <14207 13195 12101 11745 11681>, + <14215 13201 12109 11751 11686>, + <14220 13210 12116 11756 11690>, + <14223 13222 12123 11760 11695>, + <14228 13229 12130 11764 11699>, + <14239 13234 12137 11768 11703>, + <14255 13242 12143 11772 11707>, + <14279 13250 12149 11776 11711>, + <14302 13257 12154 11780 11716>, + <14310 13265 12160 11784 11720>, + <14314 13278 12166 11789 11725>, + <14320 13297 12174 11794 11729>, + <14343 13315 12181 11799 11733>, + <14395 13333 12189 11802 11736>, + <14443 13346 12197 11804 11738>, + <14481 13351 12202 11807 11740>, + <14512 13353 12205 11809 11741>, + <14514 13357 12209 11811 11742>, + <14472 13369 12217 11813 11744>, + <14451 13384 12223 11815 11745>, + <14446 13399 12224 11816 11746>, + <14433 13385 12228 11817 11746>, + <14447 13396 12231 11819 11746>, + <14441 13396 12232 11819 11745>, + <14440 13403 12233 11819 11746>, + <14431 13399 12239 11820 11747>, + <14460 13394 12241 11824 11750>, + <14470 13423 12251 11830 11755>, + <14506 13430 12275 11839 11760>, + <14485 13470 12295 11850 11770>, + <14544 13512 12338 11868 11782>, + <14544 13512 12338 11868 11782>, + <14544 13512 12338 11868 11782>; + }; + + qcom,pc-temp-z2-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <11192 9778 10257 10603 10910>, + <10253 10813 10276 10490 10558>, + <9726 10534 10287 10428 10436>, + <9734 10061 10282 10413 10412>, + <9760 9938 10269 10392 10406>, + <9775 9923 10261 10380 10404>, + <9777 9909 10257 10375 10408>, + <9772 9898 10258 10370 10412>, + <9765 9890 10262 10368 10412>, + <9755 9884 10265 10372 10421>, + <9746 9880 10259 10375 10444>, + <9750 9878 10227 10382 10452>, + <9766 9881 10199 10414 10451>, + <9772 9895 10216 10429 10452>, + <9752 9907 10260 10399 10450>, + <9717 9910 10282 10371 10439>, + <9701 9914 10279 10383 10449>, + <9697 9923 10269 10418 10506>, + <9693 9949 10295 10465 10551>, + <9686 9981 10388 10545 10559>, + <9673 10014 10446 10602 10559>, + <9662 10050 10419 10553 10531>, + <9655 10080 10371 10429 10478>, + <9649 10101 10339 10379 10444>, + <9631 10116 10316 10398 10420>, + <9588 10124 10303 10422 10405>, + <9554 10131 10300 10409 10406>, + <9540 10135 10301 10384 10415>, + <9483 10134 10309 10376 10426>, + <9426 10131 10329 10376 10445>, + <9408 10130 10351 10380 10472>, + <9395 10131 10373 10399 10506>, + <9386 10133 10396 10437 10548>, + <9378 10137 10420 10474 10594>, + <9372 10146 10446 10506 10651>, + <9368 10154 10463 10533 10695>, + <9374 10162 10468 10556 10712>, + <9380 10167 10471 10580 10722>, + <9389 10171 10479 10593 10733>, + <9398 10176 10491 10596 10745>, + <9397 10178 10497 10597 10753>, + <9384 10169 10490 10609 10755>, + <9380 10140 10483 10625 10759>, + <9386 9964 10481 10631 10781>, + <9324 9926 10454 10642 10811>, + <9305 9932 10438 10669 10808>, + <9287 9948 10463 10697 10858>, + <9289 9933 10557 10698 10889>, + <9274 9965 10622 10758 10917>, + <9278 9923 10533 10711 10837>, + <9316 9884 10462 10634 10693>, + <9326 9807 10425 10609 10671>, + <9285 9724 10395 10535 10591>, + <9245 9615 10285 10458 10500>, + <9245 9615 10285 10458 10500>, + <9245 9615 10285 10458 10500>; + }; + + qcom,pc-temp-z3-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <19525 19431 19373 19383 19355>, + <19784 19494 19408 19370 19350>, + <19920 19574 19438 19372 19351>, + <19937 19651 19450 19380 19356>, + <19918 19673 19455 19382 19359>, + <19895 19676 19456 19383 19362>, + <19884 19677 19454 19381 19362>, + <19879 19677 19451 19376 19359>, + <19877 19680 19448 19372 19355>, + <19874 19682 19446 19372 19353>, + <19872 19668 19440 19372 19352>, + <19877 19628 19423 19367 19352>, + <19894 19610 19400 19355 19349>, + <19909 19638 19406 19350 19345>, + <19892 19671 19439 19363 19347>, + <19843 19665 19457 19379 19351>, + <19796 19628 19436 19373 19348>, + <19760 19594 19408 19356 19338>, + <19726 19567 19407 19352 19335>, + <19697 19550 19425 19366 19342>, + <19672 19554 19438 19379 19351>, + <19654 19573 19439 19379 19357>, + <19644 19591 19439 19374 19361>, + <19636 19603 19437 19373 19362>, + <19628 19612 19434 19380 19360>, + <19619 19613 19433 19386 19358>, + <19607 19611 19439 19383 19356>, + <19596 19607 19445 19378 19354>, + <19583 19601 19446 19374 19352>, + <19567 19594 19444 19369 19350>, + <19549 19588 19442 19365 19348>, + <19530 19583 19439 19362 19345>, + <19514 19578 19434 19360 19342>, + <19499 19571 19431 19359 19338>, + <19486 19563 19429 19358 19334>, + <19479 19557 19426 19358 19332>, + <19483 19551 19422 19358 19332>, + <19491 19546 19418 19357 19334>, + <19513 19542 19415 19356 19334>, + <19535 19539 19414 19351 19331>, + <19526 19535 19412 19347 19329>, + <19496 19530 19410 19347 19330>, + <19483 19519 19408 19347 19330>, + <19481 19451 19404 19347 19331>, + <19372 19379 19382 19344 19327>, + <19345 19348 19360 19337 19320>, + <19337 19340 19358 19328 19312>, + <19339 19335 19342 19326 19312>, + <19316 19318 19331 19324 19309>, + <19320 19317 19352 19335 19324>, + <19371 19345 19355 19339 19331>, + <19418 19350 19357 19342 19332>, + <19442 19348 19353 19346 19335>, + <19464 19360 19359 19349 19340>, + <19464 19360 19359 19349 19340>, + <19464 19360 19359 19349 19340>; + }; + + qcom,pc-temp-z4-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <16385 15501 14962 14712 14715>, + <16621 15491 14959 14790 14777>, + <16602 15456 14922 14802 14786>, + <16518 15370 14881 14784 14773>, + <16384 15265 14843 14759 14750>, + <16241 15178 14812 14736 14726>, + <16119 15106 14786 14721 14710>, + <16009 15051 14764 14710 14700>, + <15894 15008 14752 14704 14694>, + <15746 14969 14746 14701 14689>, + <15604 14928 14744 14698 14685>, + <15557 14895 14744 14693 14681>, + <15579 14889 14745 14687 14673>, + <15600 14901 14749 14689 14670>, + <15554 14908 14754 14704 14683>, + <15436 14889 14752 14715 14696>, + <15339 14846 14732 14699 14686>, + <15282 14813 14713 14669 14663>, + <15245 14793 14712 14671 14662>, + <15230 14781 14722 14728 14708>, + <15221 14780 14742 14778 14758>, + <15217 14783 14794 14782 14763>, + <15221 14793 14846 14777 14751>, + <15227 14842 14846 14766 14737>, + <15232 14904 14815 14739 14722>, + <15237 14918 14783 14717 14709>, + <15244 14915 14759 14707 14700>, + <15250 14910 14740 14702 14693>, + <15262 14895 14729 14697 14687>, + <15275 14872 14722 14693 14682>, + <15283 14853 14717 14690 14677>, + <15290 14837 14715 14686 14673>, + <15294 14821 14714 14682 14670>, + <15292 14806 14713 14682 14669>, + <15285 14792 14713 14684 14672>, + <15265 14778 14712 14686 14677>, + <15218 14764 14710 14689 14683>, + <15171 14753 14707 14691 14689>, + <15100 14750 14704 14691 14691>, + <15036 14748 14701 14691 14688>, + <15028 14745 14698 14690 14685>, + <15035 14740 14695 14688 14684>, + <15033 14741 14690 14685 14683>, + <15011 14800 14682 14681 14680>, + <15037 14827 14679 14667 14668>, + <15046 14838 14675 14645 14644>, + <15051 14840 14669 14641 14637>, + <15043 14842 14681 14633 14624>, + <15056 14851 14689 14629 14622>, + <15040 14847 14670 14638 14636>, + <15003 14839 14678 14645 14640>, + <14990 14846 14681 14646 14645>, + <14996 14862 14691 14647 14646>, + <15017 14877 14695 14650 14646>, + <15017 14877 14695 14650 14646>, + <15017 14877 14695 14650 14646>; + }; + + qcom,pc-temp-z5-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <11068 11690 13464 19085 17868>, + <12016 12370 14843 18209 18510>, + <12567 13373 16287 18434 19041>, + <12767 14431 17166 19331 19871>, + <12906 14953 17644 19970 20772>, + <13043 15275 18035 20553 21985>, + <13254 15589 18448 20812 22838>, + <13520 16021 18878 20763 23075>, + <13787 16665 19253 20832 23069>, + <14074 17170 19532 21287 23403>, + <14425 17078 19373 21540 24108>, + <14893 16220 17894 20839 24888>, + <15428 16083 16100 18925 24832>, + <15715 18342 16976 18223 24189>, + <15770 20589 20553 20659 24472>, + <15797 20502 22513 23616 25498>, + <15834 19565 21295 23828 25788>, + <15830 19061 19385 22969 25708>, + <15750 18918 21990 23440 25684>, + <15580 18870 30436 27428 25707>, + <15309 20532 34653 30469 25746>, + <15057 25755 30884 27232 24220>, + <14852 31080 25218 20500 20766>, + <14649 35866 22212 18547 19399>, + <14406 39481 20440 20518 19854>, + <14102 39590 19963 22400 20596>, + <13801 37343 21441 23200 21434>, + <13549 34779 23939 23840 22513>, + <13290 32437 26091 24203 23750>, + <13021 30286 28345 24605 25226>, + <12746 29196 30150 25017 26620>, + <12479 28629 31211 25585 27804>, + <12282 28181 32038 26640 28805>, + <12126 27688 32872 28101 29029>, + <11990 27267 33745 30291 28636>, + <11896 27207 34089 31579 28289>, + <11945 27442 32771 31455 28513>, + <12049 27808 30864 31087 28942>, + <12350 28315 30537 30322 28828>, + <12671 28953 30633 27821 27284>, + <12642 29117 30687 26060 26101>, + <12299 27717 30577 26308 26287>, + <12208 24781 30313 26635 26505>, + <12309 16408 28848 26643 26112>, + <11428 13096 22891 26468 25271>, + <11198 12322 18301 26248 25109>, + <11112 12144 18213 22490 22887>, + <11116 12041 15832 22757 25790>, + <10935 11705 14733 23506 25696>, + <10976 11757 17791 27597 30144>, + <11440 12275 17295 25361 28944>, + <11648 12197 17311 24873 26253>, + <11657 11966 16067 25059 25290>, + <11600 11884 16052 23410 24581>, + <11600 11884 16052 23410 24581>, + <11600 11884 16052 23410 24581>; + }; + + qcom,pc-temp-z6-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <16538 15406 14813 14639 14611>, + <16749 15432 14830 14667 14637>, + <16795 15447 14830 14674 14643>, + <16769 15440 14820 14671 14641>, + <16699 15411 14805 14663 14634>, + <16612 15372 14791 14653 14625>, + <16540 15333 14779 14645 14619>, + <16482 15307 14768 14638 14613>, + <16423 15289 14762 14634 14608>, + <16352 15271 14759 14633 14606>, + <16282 15242 14755 14632 14604>, + <16243 15204 14746 14628 14603>, + <16229 15190 14734 14620 14598>, + <16213 15202 14738 14617 14595>, + <16158 15216 14756 14631 14602>, + <16064 15204 14764 14643 14610>, + <15984 15167 14745 14634 14604>, + <15930 15138 14722 14613 14590>, + <15887 15120 14722 14612 14588>, + <15858 15110 14737 14646 14613>, + <15836 15113 14757 14675 14640>, + <15826 15129 14785 14678 14644>, + <15826 15150 14807 14675 14644>, + <15831 15182 14806 14671 14642>, + <15836 15213 14793 14664 14635>, + <15841 15221 14782 14658 14628>, + <15846 15221 14776 14653 14623>, + <15850 15220 14772 14648 14620>, + <15854 15214 14769 14645 14617>, + <15856 15204 14766 14641 14614>, + <15856 15196 14763 14638 14611>, + <15856 15188 14761 14635 14608>, + <15855 15180 14760 14632 14605>, + <15853 15174 14759 14632 14604>, + <15851 15168 14759 14633 14604>, + <15851 15164 14758 14634 14604>, + <15853 15160 14756 14636 14607>, + <15855 15157 14754 14637 14611>, + <15855 15157 14752 14637 14612>, + <15854 15158 14751 14634 14610>, + <15851 15158 14750 14632 14608>, + <15842 15157 14749 14631 14608>, + <15832 15156 14747 14631 14607>, + <15821 15148 14743 14630 14607>, + <15777 15126 14731 14621 14600>, + <15764 15120 14719 14609 14585>, + <15763 15114 14716 14602 14578>, + <15759 15116 14713 14598 14572>, + <15757 15111 14711 14595 14570>, + <15765 15116 14716 14605 14584>, + <15777 15136 14723 14612 14591>, + <15805 15152 14732 14616 14594>, + <15840 15173 14739 14621 14598>, + <15893 15213 14754 14628 14605>, + <15893 15213 14754 14628 14605>, + <15893 15213 14754 14628 14605>; + }; + + qcom,pc-temp-y1-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <7598 6764 6071 5440 5223 5179>, + <7604 6767 6083 5439 5222 5181>, + <7616 6772 6090 5438 5222 5182>, + <7629 6778 6094 5436 5222 5184>, + <7640 6782 6096 5435 5223 5185>, + <7645 6784 6096 5434 5223 5187>, + <7644 6784 6092 5434 5224 5187>, + <7642 6784 6086 5434 5226 5188>, + <7635 6781 6085 5435 5228 5189>, + <7612 6774 6088 5436 5229 5190>, + <7594 6768 6090 5437 5231 5192>, + <7603 6766 6086 5437 5232 5193>, + <7624 6767 6080 5437 5234 5195>, + <7644 6772 6081 5438 5236 5197>, + <7668 6789 6096 5445 5241 5202>, + <7683 6807 6107 5453 5244 5204>, + <7674 6820 6111 5455 5244 5205>, + <7655 6831 6115 5458 5245 5205>, + <7640 6832 6116 5460 5246 5206>, + <7626 6817 6114 5461 5248 5209>, + <7619 6805 6114 5464 5251 5212>, + <7638 6807 6125 5468 5255 5216>, + <7673 6815 6139 5472 5259 5219>, + <7681 6821 6141 5477 5262 5223>, + <7680 6824 6136 5481 5265 5226>, + <7684 6828 6135 5485 5267 5230>, + <7689 6840 6144 5489 5270 5234>, + <7692 6860 6155 5494 5274 5237>, + <7690 6871 6158 5499 5277 5240>, + <7672 6876 6162 5505 5280 5242>, + <7648 6878 6167 5510 5283 5245>, + <7641 6875 6171 5515 5287 5248>, + <7643 6871 6175 5520 5290 5252>, + <7645 6871 6176 5523 5293 5255>, + <7649 6869 6177 5526 5296 5257>, + <7656 6867 6179 5529 5298 5259>, + <7671 6879 6183 5531 5300 5260>, + <7690 6895 6188 5533 5301 5261>, + <7693 6895 6193 5534 5301 5262>, + <7679 6883 6197 5535 5302 5262>, + <7669 6879 6202 5537 5303 5263>, + <7670 6885 6209 5541 5305 5265>, + <7670 6891 6220 5544 5306 5266>, + <7670 6898 6217 5546 5307 5267>, + <7674 6904 6224 5551 5310 5269>, + <7684 6923 6224 5553 5310 5270>, + <7689 6920 6233 5556 5310 5270>, + <7718 6926 6243 5556 5310 5270>, + <7735 6923 6251 5558 5311 5270>, + <7724 6942 6247 5561 5314 5272>, + <7721 6975 6265 5570 5317 5275>, + <7736 7003 6293 5585 5324 5280>, + <7777 7007 6312 5604 5331 5286>, + <7862 7038 6346 5623 5340 5292>, + <7862 7038 6346 5623 5340 5292>, + <7862 7038 6346 5623 5340 5292>; + }; + + qcom,pc-temp-y2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <9686 10401 10680 11050 11104 11401>, + <9784 10367 10651 11029 11106 11345>, + <9844 10346 10618 11003 11105 11260>, + <9875 10335 10585 10974 11102 11170>, + <9887 10331 10557 10941 11096 11098>, + <9890 10330 10539 10906 11089 11068>, + <9836 10343 10530 10861 11080 11075>, + <9739 10365 10523 10815 11067 11086>, + <9714 10360 10518 10793 11048 11085>, + <9726 10302 10514 10780 11017 11066>, + <9749 10260 10512 10771 10981 11044>, + <9880 10338 10522 10756 10934 11003>, + <10116 10474 10547 10736 10885 10947>, + <10170 10505 10586 10738 10874 10940>, + <9944 10486 10664 10781 10896 10992>, + <9729 10473 10720 10835 10928 11033>, + <9701 10495 10746 10897 10988 11035>, + <9694 10532 10766 10960 11059 11032>, + <9688 10541 10781 10991 11079 11043>, + <9682 10540 10795 11004 11080 11097>, + <9677 10537 10806 11018 11082 11163>, + <9674 10483 10815 11049 11128 11225>, + <9672 10313 10824 11092 11200 11283>, + <9670 10193 10827 11124 11234 11325>, + <9667 10079 10832 11151 11254 11356>, + <9664 10012 10836 11169 11271 11377>, + <9663 9998 10834 11180 11289 11395>, + <9662 9984 10826 11184 11309 11414>, + <9661 9965 10822 11175 11317 11445>, + <9660 9940 10820 11150 11329 11500>, + <9659 9913 10815 11136 11341 11537>, + <9659 9889 10729 11139 11328 11522>, + <9658 9867 10574 11151 11311 11482>, + <9657 9842 10507 11164 11315 11466>, + <9656 9813 10490 11161 11321 11473>, + <9656 9786 10478 11140 11317 11478>, + <9655 9762 10470 11112 11316 11484>, + <9655 9732 10507 11097 11321 11496>, + <9654 9708 10556 11103 11323 11495>, + <9654 9694 10525 11104 11318 11473>, + <9654 9684 10426 11103 11314 11461>, + <9654 9675 10396 11106 11316 11468>, + <9654 9668 10406 11101 11314 11471>, + <9653 9662 10267 11078 11283 11464>, + <9653 9659 10199 11060 11283 11440>, + <9653 9659 10180 11025 11296 11394>, + <9653 9658 10256 11021 11274 11345>, + <9653 9657 10321 11043 11240 11336>, + <9653 9656 10323 11048 11247 11344>, + <9652 9656 10295 10982 11294 11322>, + <9652 9654 10240 10956 11255 11261>, + <9652 9653 10172 10913 11134 11175>, + <9652 9652 10118 10825 11023 11061>, + <9650 9652 10099 10780 10831 10826>, + <9650 9652 10099 10780 10831 10826>, + <9650 9652 10099 10780 10831 10826>; + }; + + qcom,pc-temp-y3-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <13434 13398 13345 13285 13280 13272>, + <13675 13407 13338 13284 13280 13274>, + <13823 13420 13334 13283 13280 13275>, + <13901 13433 13334 13283 13280 13277>, + <13931 13444 13336 13283 13280 13278>, + <13936 13449 13340 13285 13280 13278>, + <13804 13449 13347 13288 13280 13278>, + <13564 13448 13355 13293 13281 13278>, + <13499 13451 13358 13295 13281 13278>, + <13498 13470 13359 13296 13281 13277>, + <13499 13484 13360 13296 13281 13277>, + <13523 13470 13373 13303 13284 13279>, + <13572 13441 13392 13313 13289 13282>, + <13584 13425 13393 13314 13290 13283>, + <13548 13416 13371 13310 13288 13282>, + <13516 13410 13351 13307 13286 13282>, + <13520 13407 13346 13309 13288 13282>, + <13536 13405 13343 13313 13292 13283>, + <13543 13402 13339 13313 13292 13283>, + <13545 13397 13334 13305 13287 13280>, + <13546 13391 13329 13296 13283 13277>, + <13548 13381 13324 13288 13281 13276>, + <13552 13365 13319 13283 13280 13275>, + <13557 13351 13318 13282 13279 13275>, + <13568 13340 13317 13283 13278 13275>, + <13586 13335 13317 13284 13278 13274>, + <13605 13336 13317 13283 13278 13274>, + <13625 13339 13317 13283 13277 13274>, + <13647 13343 13317 13285 13277 13274>, + <13675 13347 13317 13289 13277 13273>, + <13709 13352 13317 13292 13277 13273>, + <13746 13357 13312 13293 13278 13273>, + <13786 13364 13305 13292 13278 13274>, + <13834 13372 13302 13292 13279 13274>, + <13889 13385 13303 13290 13278 13274>, + <13952 13400 13304 13288 13278 13273>, + <14017 13416 13307 13286 13278 13273>, + <14082 13434 13314 13284 13277 13273>, + <14146 13456 13320 13283 13277 13273>, + <14209 13488 13324 13283 13277 13273>, + <14273 13532 13327 13283 13277 13273>, + <14339 13585 13333 13283 13278 13274>, + <14405 13648 13342 13283 13278 13274>, + <14482 13731 13345 13284 13278 13274>, + <14570 13843 13353 13283 13278 13274>, + <14605 13890 13360 13291 13279 13276>, + <14655 13886 13365 13292 13281 13277>, + <14684 13912 13378 13296 13283 13280>, + <14733 14009 13393 13298 13282 13280>, + <14859 14104 13394 13294 13281 13277>, + <14999 14246 13402 13296 13280 13277>, + <15153 14472 13423 13301 13283 13281>, + <15376 14712 13458 13305 13286 13284>, + <16172 14971 13514 13315 13290 13286>, + <16172 14971 13514 13315 13290 13286>, + <16172 14971 13514 13315 13290 13286>; + }; + + qcom,pc-temp-y4-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <17845 16850 16626 16493 16453 16452>, + <17707 16859 16623 16499 16453 16450>, + <17643 16875 16623 16504 16455 16449>, + <17641 16896 16626 16507 16456 16448>, + <17685 16923 16631 16509 16458 16448>, + <17761 16953 16638 16510 16459 16448>, + <17959 16995 16646 16508 16461 16449>, + <18315 17038 16657 16506 16462 16452>, + <18708 17060 16668 16506 16465 16454>, + <19236 17069 16679 16513 16469 16457>, + <19572 17084 16696 16524 16475 16461>, + <19006 17415 16799 16542 16489 16473>, + <17760 17958 16951 16564 16509 16488>, + <17274 17986 16977 16573 16513 16492>, + <17223 17320 16899 16575 16509 16491>, + <17197 16817 16810 16579 16507 16490>, + <17184 16821 16750 16620 16529 16506>, + <17165 16866 16699 16681 16570 16536>, + <17135 16877 16663 16682 16576 16541>, + <17076 16837 16634 16593 16532 16509>, + <17012 16792 16611 16517 16486 16475>, + <16969 16768 16596 16504 16468 16461>, + <16936 16750 16584 16498 16457 16451>, + <16927 16747 16578 16495 16456 16450>, + <16931 16735 16574 16491 16456 16450>, + <16939 16719 16571 16489 16457 16451>, + <16945 16707 16570 16491 16459 16453>, + <16955 16695 16570 16493 16462 16456>, + <16966 16694 16569 16494 16465 16460>, + <16978 16706 16564 16496 16471 16465>, + <16990 16724 16560 16498 16478 16472>, + <17002 16743 16564 16500 16488 16483>, + <17014 16767 16573 16502 16499 16496>, + <17027 16792 16580 16500 16501 16498>, + <17040 16818 16585 16489 16484 16481>, + <17052 16845 16589 16478 16463 16460>, + <17064 16879 16594 16475 16452 16451>, + <17077 16927 16600 16473 16446 16447>, + <17095 16964 16604 16474 16446 16448>, + <17121 16978 16617 16477 16450 16453>, + <17160 16988 16637 16480 16455 16458>, + <17211 16994 16652 16483 16456 16459>, + <17278 17008 16664 16484 16454 16456>, + <17363 17031 16681 16481 16445 16443>, + <17450 17090 16711 16491 16449 16446>, + <17435 17135 16736 16501 16471 16474>, + <17438 17159 16742 16516 16496 16504>, + <17389 17194 16787 16546 16537 16546>, + <17360 17262 16870 16574 16540 16536>, + <17381 17283 16862 16542 16494 16484>, + <17398 17284 16856 16542 16480 16473>, + <17425 17312 16891 16573 16496 16487>, + <17507 17393 16998 16635 16528 16517>, + <18186 17570 17197 16862 16705 16664>, + <18186 17570 17197 16862 16705 16664>, + <18186 17570 17197 16862 16705 16664>; + }; + + qcom,pc-temp-y5-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <8712 13450 15024 13637 17779 13876>, + <8712 13482 14393 13094 17299 16002>, + <9887 13538 13920 12763 16795 17370>, + <12171 13602 13593 12592 16319 18144>, + <13352 13655 13402 12528 15924 18488>, + <13712 13682 13338 12519 15663 18564>, + <12526 13686 13491 13011 15524 18119>, + <10345 13688 13732 13797 15423 17285>, + <9855 13494 13762 13896 15233 16665>, + <10836 12338 13637 13520 14742 16018>, + <12278 11512 13460 13263 14463 15589>, + <14305 12246 13117 13605 14692 15613>, + <16658 13838 12700 14184 15051 15805>, + <17024 14948 12908 14300 15117 15807>, + <14139 15828 14686 14149 14970 15538>, + <11513 16242 16074 14033 14913 15280>, + <11523 16069 16259 14411 15080 15197>, + <11996 15810 16323 15261 15416 15147>, + <12172 15770 16274 15815 15959 15251>, + <12062 15859 16079 16180 16933 16031>, + <11868 15956 15846 16328 17499 16947>, + <11620 15469 15368 15383 17703 17632>, + <11312 13975 14705 13688 17924 18203>, + <11115 12872 14496 13266 17959 18431>, + <11014 12058 14552 13626 17682 18509>, + <10964 11631 14629 13920 17362 18511>, + <10973 11596 14709 13944 17173 18320>, + <10988 11605 14796 13932 17044 17852>, + <10995 11588 14900 14573 17019 17407>, + <11030 11538 15113 16622 17008 17007>, + <11086 11527 15270 18010 17024 16810>, + <11136 11527 14539 18405 17391 17083>, + <11177 11500 13186 18651 18220 17910>, + <11216 11497 12702 18616 19096 18783>, + <11256 11585 12708 17851 20108 19561>, + <11296 11690 12725 16773 20954 20137>, + <11333 11737 12833 15892 21243 20622>, + <11364 11658 13487 15086 21079 21066>, + <11372 11570 14099 14616 20668 21138>, + <11354 11602 14046 14527 20112 20711>, + <11333 11673 13559 14611 19900 20367>, + <11347 11689 13647 14598 20136 20790>, + <11447 11633 14091 14488 20830 22215>, + <11628 11564 13261 14690 21851 23634>, + <11886 11464 12890 13840 19650 20132>, + <12228 11536 12810 15945 17300 17267>, + <12464 11547 13361 15880 17100 16566>, + <12844 11910 14094 16530 16574 16161>, + <12886 12441 14613 16353 15911 15963>, + <12844 12583 14513 15967 17037 16654>, + <12567 12345 14561 17027 17428 17457>, + <12151 12056 14328 17704 18241 18950>, + <11887 11870 14282 17302 18299 19121>, + <11109 11677 14642 17219 17830 18283>, + <11109 11677 14642 17219 17830 18283>, + <11109 11677 14642 17219 17830 18283>; + }; + + qcom,pc-temp-y6-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <6900 5639 5266 5065 5021 5010>, + <6907 5646 5261 5064 5021 5011>, + <6911 5654 5258 5063 5021 5012>, + <6911 5662 5258 5064 5021 5013>, + <6908 5670 5260 5065 5022 5013>, + <6903 5678 5262 5066 5023 5014>, + <6855 5686 5268 5068 5023 5015>, + <6776 5694 5276 5071 5025 5015>, + <6772 5702 5281 5074 5026 5016>, + <6911 5708 5283 5076 5027 5017>, + <7024 5719 5288 5079 5029 5018>, + <6900 5804 5324 5090 5036 5023>, + <6611 5932 5379 5103 5045 5030>, + <6465 5932 5387 5106 5047 5032>, + <6414 5744 5349 5105 5045 5031>, + <6390 5602 5310 5104 5043 5031>, + <6395 5604 5291 5117 5051 5036>, + <6409 5621 5276 5138 5065 5045>, + <6413 5625 5263 5138 5067 5047>, + <6412 5613 5251 5107 5051 5035>, + <6410 5600 5242 5078 5035 5023>, + <6413 5590 5235 5069 5028 5018>, + <6426 5582 5230 5064 5025 5015>, + <6444 5577 5229 5063 5024 5015>, + <6469 5575 5230 5063 5024 5015>, + <6500 5574 5231 5064 5024 5016>, + <6530 5579 5232 5065 5025 5016>, + <6560 5589 5235 5066 5026 5017>, + <6592 5602 5237 5068 5027 5018>, + <6630 5619 5238 5072 5029 5020>, + <6673 5639 5239 5076 5031 5022>, + <6719 5661 5240 5078 5035 5026>, + <6770 5688 5241 5079 5039 5030>, + <6823 5717 5243 5078 5040 5031>, + <6880 5750 5247 5074 5035 5026>, + <6940 5787 5251 5070 5029 5020>, + <7001 5830 5256 5068 5026 5018>, + <7062 5880 5264 5067 5024 5016>, + <7124 5938 5274 5066 5024 5017>, + <7187 6002 5285 5067 5025 5018>, + <7249 6076 5296 5069 5027 5020>, + <7312 6161 5311 5070 5028 5021>, + <7379 6261 5328 5071 5027 5020>, + <7458 6383 5344 5072 5025 5017>, + <7552 6532 5369 5074 5027 5018>, + <7589 6585 5388 5083 5033 5027>, + <7631 6596 5395 5089 5042 5037>, + <7646 6631 5423 5100 5055 5051>, + <7684 6743 5466 5110 5056 5048>, + <7789 6847 5472 5099 5042 5031>, + <7903 6977 5491 5102 5038 5029>, + <8038 7181 5547 5117 5046 5036>, + <8244 7391 5646 5141 5058 5047>, + <9160 7653 5795 5217 5112 5092>, + <9160 7653 5795 5217 5112 5092>, + <9160 7653 5795 5217 5112 5092>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl436186020H_3780mAh.dtsi b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl436186020H_3780mAh.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e9a359822f576636af09e913cf3734ae97fd7345 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl436186020H_3780mAh.dtsi @@ -0,0 +1,1046 @@ +qcom,ATL436186_020H_3780mAh { + /* ATL436186_020H_3780mAh_Averaged_MasterSlave_Feb25th2020 */ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-uv = <4400000>; + qcom,fastchg-current-ma = <10000>; + qcom,batt-id-kohm = <39>; + qcom,battery-beta = <4250>; + qcom,battery-therm-kohm = <100>; + qcom,battery-type = + "ATL436186_020H_3780mAh_Averaged_MasterSlave_Feb25th2020"; + qcom,qg-batt-profile-ver = <100>; + + qcom,jeita-fcc-ranges = <0 100 1890000 + 101 200 3780000 + 201 420 10000000 + 421 434 8000000 + 435 450 7000000 + 451 550 1890000>; + + qcom,jeita-fv-ranges = <0 100 4400000 + 101 200 4400000 + 201 420 4400000 + 421 434 4400000 + 435 450 4400000 + 451 550 4050000>; + + qcom,step-chg-ranges = <3500000 4000000 10000000 + 4000001 4200000 8000000 + 4200001 4400000 6000000>; + qcom,ocv-based-step-chg; + + /* Rise-Hys = 1 DeciDegC, Fall-Hys=10 deciDegC */ + qcom,qcom,step-jeita-hysteresis = <1 10>; + /* COOL = 10 degc, WARM = 45 degC */ + qcom,jeita-soft-thresholds = <0x4ccc 0x20b8>; + /* COLD = 0 degC, HOT = 55 degC*/ + qcom,jeita-hard-thresholds = <0x58cd 0x181d>; + /* COOL hys = 13 degC, WARM hys = 42 degC */ + qcom,jeita-soft-hys-thresholds = <0x48d4 0x23c0>; + qcom,jeita-soft-fcc-ua = <1890000 1890000>; + qcom,jeita-soft-fv-uv = <4400000 4050000>; + + qcom,fcc1-temp-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-data = <3697 3755 3812 3835 3845>; + }; + + qcom,fcc2-temp-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-data = <3792 3795 3802 3819 3809 3801>; + }; + + qcom,pc-temp-v1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <43837 43914 43961 43974 43979>, + <43618 43702 43752 43762 43768>, + <43394 43485 43537 43549 43556>, + <43166 43264 43318 43332 43342>, + <42938 43039 43095 43113 43125>, + <42710 42810 42869 42890 42903>, + <42481 42578 42639 42662 42677>, + <42256 42346 42406 42431 42450>, + <42034 42119 42176 42201 42223>, + <41817 41896 41949 41975 41997>, + <41609 41677 41725 41751 41771>, + <41407 41462 41506 41531 41550>, + <41207 41252 41291 41313 41332>, + <41011 41053 41083 41103 41121>, + <40819 40863 40881 40898 40917>, + <40625 40675 40686 40700 40720>, + <40431 40487 40499 40510 40529>, + <40258 40304 40321 40329 40345>, + <40119 40139 40148 40153 40167>, + <39977 39988 39986 39986 39997>, + <39774 39809 39817 39819 39828>, + <39506 39562 39607 39622 39634>, + <39289 39314 39366 39391 39406>, + <39151 39148 39169 39185 39199>, + <39041 39021 39021 39027 39039>, + <38943 38908 38896 38893 38903>, + <38856 38802 38783 38774 38781>, + <38774 38706 38682 38669 38673>, + <38695 38620 38590 38572 38573>, + <38621 38542 38505 38481 38478>, + <38554 38471 38429 38398 38392>, + <38493 38405 38359 38322 38312>, + <38438 38346 38296 38252 38238>, + <38387 38291 38238 38189 38170>, + <38341 38243 38188 38137 38109>, + <38300 38198 38138 38084 38049>, + <38266 38162 38090 38022 37975>, + <38227 38123 38040 37953 37891>, + <38155 38058 37972 37872 37800>, + <38045 37951 37874 37776 37702>, + <37922 37829 37759 37666 37594>, + <37785 37699 37633 37539 37465>, + <37631 37552 37490 37396 37318>, + <37448 37375 37320 37231 37158>, + <37301 37226 37175 37102 37032>, + <37200 37139 37097 37033 36972>, + <37176 37110 37072 37016 36954>, + <37175 37095 37054 37001 36939>, + <37137 37069 37036 36980 36914>, + <37063 36993 36930 36851 36764>, + <36758 36680 36593 36504 36417>, + <36291 36221 36130 36040 35954>, + <35695 35625 35535 35440 35357>, + <34884 34815 34721 34626 34546>, + <33616 33554 33462 33363 33302>, + <30000 30000 30000 30000 30000>; + }; + + qcom,pc-temp-v2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <44010 43990 43980 43955 43910 43895>, + <43674 43710 43723 43710 43669 43653>, + <43367 43445 43475 43472 43433 43418>, + <43093 43196 43238 43240 43203 43189>, + <42851 42966 43012 43017 42980 42968>, + <42613 42737 42786 42792 42757 42746>, + <42365 42504 42555 42562 42527 42517>, + <42121 42270 42323 42330 42297 42288>, + <41898 42038 42094 42100 42070 42062>, + <41692 41806 41864 41873 41844 41837>, + <41486 41578 41638 41648 41621 41615>, + <41265 41355 41418 41427 41403 41397>, + <41047 41138 41202 41209 41188 41182>, + <40862 40936 40996 41001 40980 40975>, + <40707 40746 40796 40798 40776 40772>, + <40521 40559 40598 40601 40580 40577>, + <40232 40377 40403 40410 40392 40389>, + <39909 40189 40207 40224 40211 40207>, + <39657 39968 40007 40045 40036 40032>, + <39447 39713 39804 39870 39866 39866>, + <39247 39471 39594 39674 39679 39682>, + <39047 39253 39364 39429 39442 39449>, + <38856 39052 39141 39188 39206 39213>, + <38674 38878 38961 39005 39025 39033>, + <38496 38724 38807 38848 38871 38882>, + <38358 38586 38671 38714 38738 38751>, + <38264 38460 38551 38597 38623 38636>, + <38190 38345 38443 38492 38520 38532>, + <38129 38232 38342 38395 38426 38435>, + <38078 38123 38247 38304 38337 38344>, + <38030 38040 38160 38220 38255 38261>, + <37982 37980 38078 38142 38179 38186>, + <37935 37931 38002 38068 38106 38114>, + <37884 37893 37933 38000 38035 38038>, + <37832 37863 37868 37935 37964 37959>, + <37777 37829 37812 37862 37879 37865>, + <37715 37789 37766 37778 37771 37744>, + <37646 37742 37719 37690 37659 37617>, + <37568 37678 37654 37600 37560 37514>, + <37480 37592 37571 37507 37468 37423>, + <37378 37484 37472 37409 37367 37324>, + <37250 37342 37350 37301 37256 37212>, + <37117 37183 37208 37173 37128 37083>, + <36996 37011 37048 37022 36979 36931>, + <36898 36881 36926 36922 36889 36842>, + <36814 36811 36868 36890 36863 36817>, + <36773 36779 36838 36869 36848 36802>, + <36727 36738 36803 36842 36825 36779>, + <36660 36680 36748 36790 36781 36737>, + <36517 36561 36624 36620 36609 36535>, + <36231 36271 36298 36228 36203 36133>, + <35764 35780 35781 35692 35681 35615>, + <35118 35133 35110 35007 35009 34946>, + <34216 34250 34193 34048 34114 34057>, + <32787 32833 32800 32877 32759 32761>, + <29558 29605 29729 29539 29540 29544>; + }; + + qcom,pc-temp-z1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <10270 9660 9205 8982 8932>, + <10729 10185 9985 9894 9870>, + <10961 10522 10161 10008 9971>, + <11078 10616 10231 10065 10021>, + <11137 10656 10248 10073 10030>, + <11151 10675 10258 10073 10030>, + <11155 10683 10258 10073 10029>, + <11157 10687 10253 10071 10028>, + <11160 10685 10249 10068 10027>, + <11164 10677 10247 10067 10027>, + <11163 10670 10245 10066 10026>, + <11158 10666 10244 10066 10026>, + <11155 10663 10242 10066 10026>, + <11156 10660 10241 10066 10026>, + <11157 10657 10242 10066 10026>, + <11156 10656 10243 10066 10026>, + <11151 10657 10244 10066 10027>, + <11148 10661 10245 10067 10028>, + <11149 10661 10246 10069 10029>, + <11150 10662 10249 10070 10030>, + <11154 10662 10251 10071 10030>, + <11163 10665 10253 10073 10031>, + <11167 10668 10256 10075 10032>, + <11169 10672 10259 10077 10033>, + <11173 10677 10263 10079 10035>, + <11179 10682 10268 10081 10037>, + <11187 10688 10272 10083 10039>, + <11191 10694 10276 10084 10040>, + <11188 10695 10280 10086 10041>, + <11182 10696 10284 10089 10042>, + <11180 10697 10287 10091 10044>, + <11182 10699 10290 10093 10046>, + <11186 10703 10294 10095 10047>, + <11195 10707 10298 10098 10048>, + <11210 10711 10302 10101 10050>, + <11214 10715 10307 10104 10052>, + <11209 10725 10311 10107 10054>, + <11204 10735 10316 10109 10057>, + <11209 10736 10321 10112 10059>, + <11224 10733 10326 10114 10060>, + <11232 10731 10331 10116 10062>, + <11233 10740 10335 10119 10063>, + <11234 10751 10340 10121 10065>, + <11236 10753 10345 10123 10065>, + <11250 10761 10351 10125 10066>, + <11246 10766 10354 10126 10067>, + <11246 10761 10358 10127 10067>, + <11257 10768 10360 10127 10067>, + <11246 10764 10362 10128 10068>, + <11264 10770 10369 10131 10069>, + <11271 10785 10373 10132 10072>, + <11301 10793 10379 10137 10073>, + <11283 10797 10389 10144 10076>, + <11343 10815 10399 10147 10080>, + <11343 10815 10399 10147 10080>, + <11343 10815 10399 10147 10080>; + }; + + qcom,pc-temp-z2-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <9998 10274 10794 10844 10945>, + <10167 10355 10550 10730 10846>, + <10239 10399 10603 10678 10871>, + <10266 10395 10627 10658 10860>, + <10276 10383 10590 10661 10840>, + <10258 10382 10530 10681 10820>, + <10229 10393 10504 10694 10818>, + <10222 10402 10503 10691 10838>, + <10225 10403 10506 10686 10861>, + <10230 10402 10495 10698 10866>, + <10468 10399 10479 10712 10863>, + <10817 10392 10478 10717 10858>, + <10830 10389 10490 10720 10866>, + <10488 10389 10497 10723 10887>, + <10237 10383 10489 10733 10919>, + <10238 10380 10479 10753 10955>, + <10250 10394 10485 10763 10976>, + <10293 10409 10508 10767 10990>, + <10590 10407 10522 10769 10998>, + <10856 10392 10525 10764 10996>, + <10737 10386 10523 10757 10989>, + <10407 10410 10531 10746 10961>, + <10271 10437 10570 10711 10841>, + <10271 10447 10592 10670 10746>, + <10273 10453 10576 10628 10731>, + <10283 10454 10553 10595 10727>, + <10306 10441 10542 10604 10733>, + <10322 10425 10536 10639 10758>, + <10324 10424 10535 10657 10785>, + <10323 10434 10540 10663 10803>, + <10323 10447 10549 10671 10824>, + <10329 10467 10557 10698 10870>, + <10336 10487 10569 10749 10948>, + <10345 10497 10586 10795 11004>, + <10355 10502 10622 10833 11059>, + <10358 10503 10654 10871 11110>, + <10355 10506 10670 10914 11142>, + <10351 10511 10681 10958 11183>, + <10348 10514 10696 10979 11193>, + <10344 10522 10730 10992 11177>, + <10338 10526 10756 11000 11154>, + <10307 10496 10725 10996 11137>, + <10278 10462 10682 10987 11119>, + <10264 10453 10689 10977 11087>, + <10246 10428 10699 10978 11047>, + <10229 10374 10720 11010 11096>, + <10188 10355 10691 11025 11117>, + <10121 10306 10709 11029 11193>, + <10243 10335 10714 11081 11268>, + <10479 10337 10724 10961 10999>, + <10405 10348 10693 10847 10883>, + <10327 10360 10632 10748 10808>, + <9992 10290 10623 10696 10740>, + <10016 10209 10570 10627 10634>, + <10016 10209 10570 10627 10634>, + <10016 10209 10570 10627 10634>; + }; + + qcom,pc-temp-z3-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <19393 19347 19322 19314 19304>, + <19481 19407 19348 19323 19310>, + <19528 19444 19374 19334 19318>, + <19557 19459 19384 19340 19321>, + <19571 19467 19381 19338 19320>, + <19574 19469 19375 19332 19319>, + <19576 19464 19371 19330 19317>, + <19574 19458 19367 19329 19315>, + <19563 19453 19365 19329 19313>, + <19554 19448 19361 19327 19312>, + <19555 19445 19358 19323 19311>, + <19558 19444 19356 19321 19310>, + <19555 19442 19354 19320 19310>, + <19544 19439 19353 19319 19309>, + <19533 19433 19353 19318 19306>, + <19526 19431 19353 19318 19302>, + <19521 19432 19352 19317 19300>, + <19520 19434 19351 19315 19300>, + <19527 19434 19350 19314 19299>, + <19535 19434 19349 19312 19299>, + <19537 19434 19349 19311 19299>, + <19543 19435 19353 19313 19303>, + <19546 19436 19361 19324 19317>, + <19536 19440 19369 19333 19326>, + <19524 19451 19377 19336 19325>, + <19524 19456 19381 19338 19323>, + <19532 19456 19380 19338 19321>, + <19538 19454 19377 19335 19319>, + <19538 19451 19374 19332 19317>, + <19537 19445 19369 19330 19315>, + <19535 19440 19365 19327 19312>, + <19531 19436 19361 19324 19309>, + <19527 19434 19358 19321 19306>, + <19524 19432 19356 19318 19303>, + <19521 19430 19355 19315 19301>, + <19519 19429 19354 19313 19300>, + <19515 19426 19353 19312 19300>, + <19511 19424 19352 19312 19301>, + <19506 19420 19350 19312 19301>, + <19499 19415 19347 19313 19303>, + <19494 19410 19343 19314 19304>, + <19492 19407 19342 19315 19306>, + <19489 19404 19341 19316 19307>, + <19483 19400 19338 19319 19308>, + <19461 19390 19335 19317 19308>, + <19456 19383 19327 19309 19299>, + <19436 19385 19328 19304 19295>, + <19263 19371 19326 19300 19292>, + <19262 19374 19319 19296 19290>, + <19261 19369 19326 19308 19301>, + <19261 19365 19335 19313 19303>, + <19261 19355 19338 19313 19303>, + <19264 19362 19329 19315 19304>, + <19263 19368 19332 19316 19306>, + <19263 19368 19332 19316 19306>, + <19263 19368 19332 19316 19306>; + }; + + qcom,pc-temp-z4-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <15411 15118 14858 14791 14756>, + <15540 15131 14945 14798 14741>, + <15522 15130 14892 14768 14727>, + <15372 15081 14836 14731 14698>, + <15215 14972 14795 14714 14687>, + <15110 14894 14763 14705 14683>, + <15022 14847 14748 14697 14679>, + <14959 14816 14739 14690 14675>, + <14908 14802 14731 14684 14670>, + <14869 14794 14723 14679 14665>, + <14839 14788 14717 14674 14661>, + <14817 14781 14710 14669 14656>, + <14812 14775 14704 14663 14651>, + <14820 14769 14698 14658 14647>, + <14832 14763 14693 14652 14643>, + <14850 14762 14688 14647 14640>, + <14880 14770 14686 14643 14636>, + <14889 14779 14685 14640 14631>, + <14846 14773 14684 14639 14628>, + <14800 14754 14688 14641 14629>, + <14825 14750 14695 14648 14632>, + <14928 14825 14724 14663 14641>, + <14993 14913 14779 14695 14664>, + <15001 14914 14799 14712 14678>, + <14998 14879 14781 14707 14677>, + <14983 14850 14758 14697 14673>, + <14949 14834 14746 14689 14669>, + <14924 14823 14738 14683 14664>, + <14914 14821 14734 14678 14660>, + <14908 14820 14732 14673 14656>, + <14907 14819 14731 14670 14652>, + <14908 14821 14731 14669 14650>, + <14909 14823 14731 14668 14648>, + <14909 14826 14732 14668 14647>, + <14909 14829 14734 14669 14646>, + <14909 14831 14738 14670 14646>, + <14902 14827 14742 14676 14650>, + <14892 14820 14745 14686 14661>, + <14881 14812 14746 14689 14665>, + <14868 14804 14742 14686 14662>, + <14851 14792 14736 14681 14659>, + <14827 14773 14724 14676 14657>, + <14801 14751 14709 14671 14655>, + <14776 14733 14701 14668 14655>, + <14722 14697 14683 14659 14649>, + <14692 14666 14659 14644 14634>, + <14706 14660 14649 14639 14629>, + <14871 14659 14641 14630 14620>, + <14866 14650 14633 14626 14617>, + <14863 14655 14638 14628 14623>, + <14867 14664 14635 14630 14625>, + <14872 14672 14633 14629 14625>, + <14872 14667 14638 14627 14624>, + <14877 14663 14636 14625 14622>, + <14877 14663 14636 14625 14622>, + <14877 14663 14636 14625 14622>; + }; + + qcom,pc-temp-z5-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <12262 12657 13731 16808 17854>, + <13952 14497 15898 18081 19486>, + <15214 16021 17443 19818 21650>, + <16162 17186 18570 21296 23275>, + <17097 18170 19329 21536 24003>, + <18157 19258 19745 21509 24358>, + <19290 20662 19830 21628 24381>, + <20511 21771 20008 22343 23971>, + <21891 22042 20173 22938 23666>, + <23153 22138 20134 22808 23885>, + <24239 22299 20112 22359 24494>, + <25122 22870 20235 22259 25170>, + <25283 23518 20612 22732 26113>, + <24901 23610 21090 23419 26820>, + <24579 23449 21852 24318 26214>, + <24560 23299 22739 25492 24698>, + <24597 23117 23372 26450 24419>, + <24657 22978 23855 27282 26292>, + <24758 24230 24222 27692 27840>, + <24963 27807 24600 27046 27691>, + <27120 29427 24875 25350 27235>, + <33501 27662 23857 23361 26672>, + <36732 25045 20915 20755 24954>, + <32079 23961 19681 19621 23155>, + <25894 23427 20225 19990 22122>, + <25017 23670 21187 20786 21421>, + <26081 25610 22464 21686 21497>, + <27398 27942 24124 22802 22457>, + <28893 29059 25372 23931 23556>, + <30402 29771 26311 25076 24526>, + <31214 30415 27177 26252 25453>, + <31859 31149 28012 27490 26246>, + <32223 31779 28804 28771 27082>, + <32238 32053 29691 29417 27978>, + <32222 32216 30909 29665 29280>, + <32171 32224 31681 29773 30219>, + <31897 31917 31314 28697 28966>, + <31589 31417 30242 26131 25565>, + <31432 30966 29114 25294 24387>, + <31306 30513 27668 25736 25464>, + <31237 30105 26683 26472 27140>, + <31178 29635 26578 27651 29292>, + <31252 29276 26516 29015 31174>, + <31626 29252 25441 29682 30555>, + <31440 30295 26157 28469 30177>, + <32621 30638 26358 26578 24593>, + <28667 32814 29500 26931 25216>, + <11283 24894 31532 29489 30335>, + <11256 26655 27253 28994 33457>, + <11252 24276 28331 30163 34171>, + <11253 21078 30650 32037 33143>, + <11197 17749 31712 30278 31282>, + <11126 18743 23249 30719 30746>, + <11019 19676 23476 30978 30980>, + <11019 19676 23476 30978 30980>, + <11019 19676 23476 30978 30980>; + }; + + qcom,pc-temp-z6-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <14990 14531 14250 14172 14140>, + <15156 14653 14425 14331 14298>, + <15177 14719 14443 14341 14309>, + <15121 14708 14447 14344 14312>, + <15058 14667 14434 14340 14311>, + <15003 14634 14414 14332 14308>, + <14950 14608 14404 14326 14304>, + <14907 14588 14397 14323 14301>, + <14868 14577 14391 14319 14297>, + <14840 14569 14386 14316 14295>, + <14826 14563 14381 14312 14292>, + <14817 14558 14377 14308 14290>, + <14813 14553 14373 14305 14287>, + <14809 14548 14370 14302 14285>, + <14806 14542 14367 14299 14282>, + <14809 14540 14365 14297 14278>, + <14818 14544 14364 14294 14275>, + <14821 14549 14363 14292 14273>, + <14809 14546 14362 14291 14272>, + <14796 14539 14364 14292 14272>, + <14808 14538 14368 14294 14274>, + <14856 14573 14383 14302 14280>, + <14885 14613 14414 14324 14298>, + <14885 14616 14425 14335 14309>, + <14882 14609 14421 14334 14309>, + <14877 14602 14416 14332 14306>, + <14871 14596 14412 14329 14304>, + <14866 14592 14407 14325 14301>, + <14864 14589 14404 14321 14298>, + <14862 14587 14401 14318 14295>, + <14861 14586 14399 14316 14292>, + <14863 14587 14397 14314 14289>, + <14864 14589 14396 14312 14287>, + <14865 14591 14396 14311 14285>, + <14867 14593 14398 14310 14284>, + <14867 14594 14400 14310 14283>, + <14867 14594 14402 14312 14285>, + <14866 14593 14405 14317 14291>, + <14865 14591 14405 14318 14293>, + <14863 14588 14403 14318 14292>, + <14861 14584 14400 14317 14292>, + <14859 14579 14395 14315 14292>, + <14858 14574 14389 14314 14292>, + <14856 14569 14386 14314 14293>, + <14840 14557 14379 14311 14291>, + <14835 14546 14366 14300 14280>, + <14833 14546 14362 14295 14275>, + <14822 14541 14359 14289 14270>, + <14825 14541 14353 14285 14267>, + <14833 14546 14359 14292 14276>, + <14843 14554 14364 14297 14279>, + <14856 14555 14367 14297 14280>, + <14867 14566 14367 14299 14281>, + <14891 14579 14371 14300 14282>, + <14891 14579 14371 14300 14282>, + <14891 14579 14371 14300 14282>; + }; + + qcom,pc-temp-y1-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <5613 5139 4854 4609 4486 4453>, + <5582 5142 4858 4605 4484 4452>, + <5561 5141 4859 4600 4482 4452>, + <5548 5138 4858 4596 4480 4451>, + <5541 5134 4856 4592 4478 4450>, + <5539 5133 4853 4590 4477 4450>, + <5549 5131 4848 4587 4476 4450>, + <5563 5129 4842 4585 4475 4450>, + <5562 5129 4838 4583 4474 4449>, + <5545 5126 4835 4580 4474 4447>, + <5535 5124 4832 4578 4473 4446>, + <5536 5124 4827 4577 4472 4447>, + <5537 5122 4823 4575 4470 4447>, + <5539 5121 4821 4574 4470 4447>, + <5550 5118 4820 4572 4470 4447>, + <5558 5117 4820 4571 4470 4447>, + <5560 5127 4820 4572 4470 4447>, + <5560 5138 4822 4572 4470 4447>, + <5556 5137 4822 4573 4470 4447>, + <5550 5127 4821 4574 4471 4448>, + <5547 5124 4821 4576 4472 4448>, + <5548 5124 4824 4576 4472 4448>, + <5549 5126 4826 4577 4472 4449>, + <5552 5130 4827 4579 4473 4449>, + <5561 5136 4829 4581 4473 4450>, + <5570 5140 4831 4583 4474 4451>, + <5579 5139 4834 4585 4476 4451>, + <5585 5137 4837 4588 4477 4452>, + <5579 5139 4841 4591 4478 4452>, + <5566 5146 4848 4594 4479 4453>, + <5563 5150 4851 4597 4480 4453>, + <5559 5154 4853 4600 4482 4454>, + <5551 5159 4854 4604 4484 4455>, + <5550 5161 4854 4607 4486 4456>, + <5556 5162 4855 4611 4488 4458>, + <5561 5162 4856 4615 4489 4458>, + <5559 5157 4859 4619 4490 4459>, + <5555 5152 4862 4623 4491 4460>, + <5560 5155 4871 4624 4492 4461>, + <5575 5164 4883 4625 4493 4462>, + <5582 5167 4888 4627 4495 4463>, + <5567 5164 4886 4631 4496 4463>, + <5558 5165 4888 4634 4497 4464>, + <5581 5178 4892 4640 4499 4465>, + <5588 5163 4895 4644 4500 4466>, + <5579 5172 4907 4646 4501 4466>, + <5597 5165 4900 4650 4502 4466>, + <5597 5165 4903 4654 4502 4468>, + <5638 5175 4904 4656 4503 4467>, + <5637 5176 4909 4658 4503 4468>, + <5722 5182 4909 4660 4503 4468>, + <5802 5199 4918 4665 4506 4469>, + <5999 5220 4916 4671 4508 4470>, + <6440 5346 4923 4681 4510 4473>, + <6440 5346 4923 4681 4510 4473>, + <6440 5346 4923 4681 4510 4473>; + }; + + qcom,pc-temp-y2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <10579 10898 11101 11195 11534 11808>, + <10587 10890 11091 11188 11513 11753>, + <10595 10879 11070 11175 11481 11696>, + <10604 10868 11044 11157 11444 11639>, + <10612 10857 11017 11136 11403 11584>, + <10621 10848 10996 11113 11363 11533>, + <10630 10840 10976 11081 11311 11480>, + <10639 10830 10955 11051 11264 11433>, + <10650 10820 10936 11044 11251 11410>, + <10673 10808 10914 11046 11247 11392>, + <10698 10802 10904 11044 11242 11376>, + <10744 10811 10908 11020 11234 11359>, + <10793 10832 10916 10994 11227 11343>, + <10791 10866 10931 11000 11228 11330>, + <10754 10934 10967 11040 11240 11314>, + <10733 10997 11008 11088 11247 11303>, + <10770 11068 11064 11140 11246 11302>, + <10824 11133 11128 11204 11248 11309>, + <10829 11137 11183 11298 11292 11337>, + <10812 11095 11236 11421 11410 11407>, + <10788 11055 11257 11462 11470 11467>, + <10757 11032 11230 11408 11472 11558>, + <10716 11010 11191 11350 11476 11666>, + <10655 10989 11177 11340 11522 11710>, + <10520 10968 11170 11336 11595 11730>, + <10362 10946 11169 11335 11630 11752>, + <10105 10916 11177 11364 11639 11784>, + <9860 10890 11186 11400 11646 11820>, + <9786 10887 11191 11417 11670 11856>, + <9751 10889 11190 11437 11713 11899>, + <9729 10890 11180 11443 11749 11939>, + <9712 10843 11139 11445 11777 11976>, + <9699 10771 11103 11445 11803 12006>, + <9691 10761 11101 11445 11829 12028>, + <9685 10796 11105 11451 11852 12052>, + <9680 10818 11107 11445 11855 12059>, + <9676 10793 11098 11416 11825 12028>, + <9673 10743 11080 11393 11794 11998>, + <9671 10658 11045 11390 11782 12004>, + <9669 10468 10976 11389 11776 12021>, + <9667 10230 10887 11379 11772 12015>, + <9666 9913 10756 11355 11767 11932>, + <9664 9749 10615 11333 11749 11876>, + <9663 9708 10495 11285 11708 11873>, + <9662 9691 10413 11193 11663 11846>, + <9660 9683 10344 11207 11610 11670>, + <9659 9678 10297 11200 11562 11627>, + <9658 9673 10226 11178 11454 11533>, + <9657 9669 10160 11156 11417 11523>, + <9654 9666 10110 11116 11448 11504>, + <9651 9663 10039 11055 11432 11472>, + <9650 9659 9904 10988 11333 11399>, + <9648 9654 9774 10991 11236 11296>, + <9648 9651 9700 11020 11107 11175>, + <9648 9651 9700 11020 11107 11175>, + <9648 9651 9700 11020 11107 11175>; + }; + + qcom,pc-temp-y3-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <13401 13334 13305 13279 13270 13266>, + <13404 13336 13305 13280 13270 13266>, + <13407 13339 13306 13281 13271 13267>, + <13409 13341 13307 13281 13271 13268>, + <13412 13343 13308 13282 13272 13269>, + <13414 13345 13309 13282 13272 13270>, + <13415 13347 13310 13283 13273 13270>, + <13416 13349 13312 13283 13273 13270>, + <13421 13351 13312 13284 13274 13270>, + <13434 13352 13313 13284 13274 13271>, + <13442 13353 13314 13285 13275 13271>, + <13422 13356 13315 13285 13275 13272>, + <13394 13359 13316 13285 13275 13272>, + <13389 13356 13316 13286 13275 13273>, + <13391 13345 13316 13288 13276 13273>, + <13393 13339 13316 13289 13276 13273>, + <13388 13342 13313 13290 13277 13274>, + <13379 13346 13310 13291 13279 13275>, + <13373 13345 13309 13291 13279 13275>, + <13369 13337 13308 13290 13280 13276>, + <13364 13329 13308 13289 13280 13277>, + <13360 13325 13305 13286 13277 13274>, + <13356 13322 13300 13282 13274 13270>, + <13351 13319 13298 13280 13272 13269>, + <13343 13318 13297 13279 13270 13268>, + <13338 13316 13296 13278 13270 13268>, + <13339 13315 13296 13278 13270 13268>, + <13342 13314 13295 13278 13270 13268>, + <13347 13312 13295 13278 13270 13268>, + <13356 13310 13295 13278 13271 13268>, + <13365 13309 13294 13278 13271 13268>, + <13373 13306 13293 13278 13271 13268>, + <13381 13304 13293 13278 13270 13269>, + <13391 13305 13293 13278 13270 13269>, + <13406 13311 13292 13278 13271 13269>, + <13425 13316 13293 13278 13271 13268>, + <13451 13318 13293 13277 13270 13268>, + <13484 13321 13294 13277 13269 13267>, + <13520 13323 13295 13276 13269 13267>, + <13561 13327 13295 13274 13269 13267>, + <13608 13332 13296 13275 13269 13268>, + <13660 13343 13298 13276 13269 13268>, + <13722 13357 13299 13277 13270 13268>, + <13798 13368 13301 13277 13270 13268>, + <13898 13385 13305 13278 13269 13267>, + <13981 13408 13307 13278 13270 13270>, + <14066 13433 13309 13279 13272 13271>, + <14173 13468 13312 13281 13273 13271>, + <14311 13522 13319 13285 13275 13271>, + <14673 13589 13329 13285 13273 13270>, + <15387 13676 13335 13285 13273 13270>, + <16730 13847 13348 13287 13274 13271>, + <19422 14291 13383 13291 13275 13271>, + <24674 15433 13481 13297 13276 13273>, + <24674 15433 13481 13297 13276 13273>, + <24674 15433 13481 13297 13276 13273>; + }; + + qcom,pc-temp-y4-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <16694 16620 16544 16472 16435 16430>, + <16722 16640 16554 16470 16434 16428>, + <16772 16662 16560 16467 16433 16426>, + <16827 16684 16563 16465 16431 16424>, + <16872 16700 16565 16463 16430 16422>, + <16890 16706 16565 16462 16429 16422>, + <16887 16703 16562 16462 16429 16422>, + <16884 16698 16557 16461 16429 16422>, + <16883 16695 16555 16462 16430 16423>, + <16885 16692 16555 16463 16431 16424>, + <16889 16691 16555 16465 16432 16424>, + <16942 16691 16558 16469 16434 16426>, + <17027 16693 16566 16474 16438 16427>, + <17070 16714 16578 16479 16441 16429>, + <17099 16795 16599 16484 16446 16433>, + <17108 16843 16624 16491 16451 16436>, + <17016 16843 16657 16503 16456 16441>, + <16874 16835 16685 16519 16463 16446>, + <16813 16813 16685 16543 16477 16457>, + <16782 16754 16670 16575 16501 16474>, + <16750 16699 16650 16585 16510 16481>, + <16705 16656 16605 16546 16490 16467>, + <16657 16619 16553 16498 16463 16447>, + <16613 16593 16528 16477 16449 16437>, + <16568 16574 16513 16462 16439 16430>, + <16550 16558 16506 16458 16436 16428>, + <16559 16545 16503 16459 16436 16429>, + <16570 16532 16502 16460 16438 16430>, + <16576 16512 16501 16463 16440 16431>, + <16581 16488 16500 16468 16444 16435>, + <16587 16478 16500 16474 16449 16439>, + <16596 16484 16498 16479 16456 16444>, + <16606 16495 16495 16485 16463 16450>, + <16615 16506 16490 16490 16469 16454>, + <16625 16517 16481 16494 16473 16457>, + <16632 16529 16479 16494 16473 16457>, + <16639 16549 16486 16481 16460 16447>, + <16644 16569 16497 16466 16445 16436>, + <16647 16580 16503 16453 16440 16434>, + <16650 16587 16507 16443 16437 16433>, + <16650 16588 16511 16442 16435 16433>, + <16636 16578 16517 16445 16432 16432>, + <16620 16568 16522 16450 16430 16431>, + <16614 16563 16525 16453 16428 16427>, + <16615 16562 16523 16451 16422 16420>, + <16613 16564 16518 16456 16427 16422>, + <16627 16574 16527 16464 16431 16427>, + <16649 16594 16545 16476 16440 16441>, + <16680 16626 16576 16495 16462 16472>, + <16773 16666 16611 16492 16462 16446>, + <16928 16677 16605 16482 16430 16426>, + <17295 16696 16613 16495 16436 16431>, + <18563 16866 16657 16525 16454 16445>, + <24332 17928 16752 16586 16506 16498>, + <24332 17928 16752 16586 16506 16498>, + <24332 17928 16752 16586 16506 16498>; + }; + + qcom,pc-temp-y5-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <17385 18969 19820 18348 20163 15959>, + <17747 18838 19450 18890 20657 19132>, + <18103 18812 19205 19190 21127 22137>, + <18411 18852 19060 19305 21522 24662>, + <18626 18918 18991 19291 21795 26391>, + <18705 18971 18974 19205 21896 27007>, + <18629 19094 19073 18964 21813 26331>, + <18510 19255 19222 18609 21627 25304>, + <18766 19163 19149 18291 21388 24842>, + <20163 18555 18614 17964 21017 24218>, + <21032 18009 18042 17605 20541 23551>, + <19032 17765 17592 16853 19821 22949>, + <16117 17560 17120 16095 18943 22277>, + <16345 17065 16488 16048 18051 21384>, + <19627 15838 15525 16241 17057 20196>, + <21566 15288 15054 16327 16646 19365>, + <21325 17934 15379 15963 16689 18762>, + <20982 21635 16106 15532 16771 18242>, + <21191 22355 17495 15688 16847 18058>, + <22316 22435 20149 16465 16869 17992>, + <23224 22550 21963 17525 17119 18301>, + <23686 22921 22848 19857 19274 19217>, + <23988 23459 23408 22065 21698 20457>, + <23290 23862 23498 22361 21910 21812>, + <19618 24215 23492 22200 21660 23372>, + <16438 24526 23534 22071 21408 23966>, + <14775 24905 23990 22050 21155 23476>, + <13666 25190 24552 22075 21047 22545>, + <13635 24764 24798 22051 21119 21378>, + <13849 22890 24942 21876 21068 19896>, + <13996 20838 25126 21761 20694 19265>, + <14033 18639 25610 21706 19522 19158>, + <14060 16889 26149 21672 18549 19111>, + <14124 17260 26121 21984 18968 19337>, + <14308 19696 25472 22832 20290 20169>, + <14508 21521 24816 23852 21110 20787>, + <14746 22141 24379 25326 21478 20975>, + <14986 22550 23907 26231 21632 21128>, + <15179 22752 23025 24735 21694 21438>, + <15372 22757 21838 22015 22081 22256>, + <15402 22360 21056 21454 22681 23441>, + <14907 20259 20513 22055 23749 25248>, + <14397 17852 19989 21633 24797 27697>, + <14093 15614 19667 21203 26044 30188>, + <13935 14761 20276 22289 27496 29447>, + <13951 14682 20221 21232 22757 27736>, + <13926 14690 18886 19253 22810 27775>, + <14234 14424 17632 18735 22875 24541>, + <14603 14818 17328 19657 22999 21351>, + <13616 15527 17751 21342 20705 20460>, + <12552 15663 18495 22607 27375 29585>, + <11145 14831 17455 22804 28646 29386>, + <9957 13010 16230 23779 29324 28727>, + <9195 10486 14924 24477 27339 28153>, + <9195 10486 14924 24477 27339 28153>, + <9195 10486 14924 24477 27339 28153>; + }; + + qcom,pc-temp-y6-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <5494 5203 5060 4960 4929 4921>, + <5509 5209 5061 4960 4929 4921>, + <5520 5213 5060 4959 4928 4921>, + <5526 5215 5059 4959 4928 4921>, + <5530 5216 5058 4958 4928 4921>, + <5531 5216 5057 4958 4928 4921>, + <5527 5214 5055 4958 4928 4921>, + <5521 5210 5053 4958 4929 4922>, + <5521 5207 5051 4958 4929 4922>, + <5525 5205 5050 4959 4930 4923>, + <5530 5204 5049 4959 4931 4923>, + <5532 5203 5050 4960 4931 4924>, + <5535 5204 5052 4962 4932 4925>, + <5541 5208 5055 4963 4934 4926>, + <5556 5221 5060 4966 4935 4927>, + <5563 5231 5066 4969 4937 4928>, + <5536 5233 5073 4973 4939 4930>, + <5494 5234 5079 4978 4942 4932>, + <5478 5229 5079 4985 4947 4935>, + <5470 5207 5074 4993 4954 4941>, + <5463 5187 5068 4996 4956 4943>, + <5453 5173 5053 4982 4948 4937>, + <5444 5162 5036 4966 4938 4928>, + <5437 5156 5028 4959 4933 4925>, + <5431 5152 5023 4954 4929 4922>, + <5429 5150 5021 4953 4928 4922>, + <5436 5149 5021 4953 4928 4922>, + <5449 5148 5022 4954 4928 4922>, + <5463 5146 5023 4955 4929 4923>, + <5480 5145 5024 4957 4931 4923>, + <5500 5145 5025 4959 4933 4925>, + <5522 5150 5026 4961 4934 4927>, + <5546 5159 5026 4963 4936 4929>, + <5573 5171 5027 4965 4938 4930>, + <5604 5188 5027 4967 4940 4931>, + <5637 5207 5028 4967 4940 4931>, + <5673 5229 5032 4964 4936 4927>, + <5711 5253 5039 4959 4931 4924>, + <5753 5277 5046 4956 4930 4923>, + <5798 5302 5053 4953 4929 4924>, + <5845 5328 5061 4953 4929 4924>, + <5892 5353 5072 4955 4928 4924>, + <5947 5381 5086 4959 4928 4924>, + <6021 5417 5102 4961 4927 4922>, + <6115 5463 5120 4962 4926 4920>, + <6200 5508 5125 4964 4928 4922>, + <6283 5549 5138 4968 4931 4925>, + <6392 5602 5160 4974 4934 4929>, + <6541 5672 5190 4983 4941 4939>, + <6922 5760 5227 4983 4941 4930>, + <7615 5860 5251 4980 4931 4924>, + <8825 6039 5300 4988 4934 4926>, + <11227 6535 5388 5002 4940 4931>, + <16611 7839 5546 5027 4956 4948>, + <16611 7839 5546 5027 4956 4948>, + <16611 7839 5546 5027 4956 4948>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl466271_3300mAh.dtsi b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl466271_3300mAh.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..456c17bc725c08d788dbdf6c849b89a4b9c08695 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qg-batterydata-atl466271_3300mAh.dtsi @@ -0,0 +1,1041 @@ +qcom,ATL466271_3300mAh { + /* ATL466271_3300mAh_averaged_MasterSlave_Jun12th2019 */ + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-uv = <4390000>; + qcom,fastchg-current-ma = <8000>; + qcom,batt-id-kohm = <24>; + qcom,battery-beta = <4250>; + qcom,battery-therm-kohm = <100>; + qcom,battery-type = + "ATL466271_3300mAh_averaged_MasterSlave_Jun12th2019"; + qcom,qg-batt-profile-ver = <100>; + + qcom,jeita-fcc-ranges = <0 100 1600000 + 101 200 3200000 + 201 450 8000000 + 451 550 1600000>; + + qcom,jeita-fv-ranges = <0 100 4400000 + 101 200 4400000 + 201 450 4400000 + 451 550 4050000>; + + qcom,step-chg-ranges = <3500000 4000000 8000000 + 4000001 4200000 6000000 + 4200001 4400000 4000000>; + qcom,ocv-based-step-chg; + + /* COOL = 10 degc, WARM = 45 degC */ + qcom,jeita-soft-thresholds = <0x4ccc 0x20b8>; + /* COLD = 0 degC, HOT = 55 degC*/ + qcom,jeita-hard-thresholds = <0x58cd 0x181d>; + /* COOL hys = 13 degC, WARM hys = 42 degC */ + qcom,jeita-soft-hys-thresholds = <0x48d4 0x23c0>; + qcom,jeita-soft-fcc-ua = <1600000 1600000>; + qcom,jeita-soft-fv-uv = <4400000 4050000>; + + qcom,fcc1-temp-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-data = <3191 3260 3320 3354 3366>; + }; + + qcom,fcc2-temp-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-data = <3307 3309 3324 3332 3330 3326>; + }; + + qcom,pc-temp-v1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <43710 43825 43909 43937 43942>, + <43473 43605 43706 43721 43723>, + <43237 43380 43489 43509 43510>, + <43003 43150 43267 43294 43299>, + <42775 42918 43038 43070 43079>, + <42550 42687 42804 42837 42850>, + <42328 42457 42573 42606 42620>, + <42109 42230 42341 42375 42390>, + <41894 42008 42113 42145 42161>, + <41684 41789 41886 41917 41933>, + <41476 41574 41663 41690 41705>, + <41278 41360 41446 41467 41481>, + <41103 41159 41232 41247 41261>, + <40943 40987 41027 41035 41047>, + <40756 40823 40831 40833 40840>, + <40499 40625 40638 40639 40642>, + <40235 40371 40434 40442 40448>, + <40047 40136 40224 40241 40259>, + <39905 39978 40039 40053 40076>, + <39770 39845 39893 39894 39909>, + <39637 39668 39742 39742 39748>, + <39498 39402 39527 39546 39554>, + <39319 39159 39260 39286 39299>, + <39057 39018 39056 39062 39070>, + <38841 38914 38916 38909 38913>, + <38748 38814 38798 38783 38786>, + <38688 38714 38686 38668 38667>, + <38628 38621 38584 38566 38559>, + <38566 38536 38491 38471 38460>, + <38504 38459 38406 38380 38367>, + <38445 38391 38330 38297 38282>, + <38388 38330 38261 38223 38205>, + <38337 38276 38199 38156 38134>, + <38292 38228 38143 38095 38068>, + <38251 38187 38095 38043 38009>, + <38214 38146 38049 37992 37951>, + <38182 38111 38004 37933 37881>, + <38143 38071 37958 37869 37800>, + <38074 38006 37895 37793 37711>, + <37974 37903 37802 37697 37614>, + <37864 37788 37692 37587 37506>, + <37736 37663 37571 37457 37376>, + <37592 37522 37433 37310 37228>, + <37427 37351 37270 37152 37071>, + <37293 37218 37135 37037 36964>, + <37218 37148 37061 36976 36918>, + <37197 37127 37043 36958 36899>, + <37176 37114 37027 36945 36884>, + <37152 37086 37005 36915 36845>, + <37053 36954 36879 36723 36623>, + <36674 36578 36526 36347 36242>, + <36195 36086 36041 35859 35751>, + <35574 35449 35427 35229 35116>, + <34729 34574 34574 34362 34242>, + <33401 33172 33225 32989 32851>, + <30000 30000 30000 30000 30000>; + }; + + qcom,pc-temp-v2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <43975 43950 43930 43905 43855 43835>, + <43614 43647 43667 43663 43617 43596>, + <43279 43361 43410 43424 43383 43362>, + <42972 43092 43162 43188 43150 43130>, + <42688 42841 42921 42956 42921 42903>, + <42432 42596 42682 42724 42691 42675>, + <42220 42350 42446 42490 42458 42443>, + <42020 42110 42212 42257 42225 42210>, + <41772 41881 41982 42027 41995 41980>, + <41458 41662 41755 41799 41766 41751>, + <41235 41448 41531 41574 41541 41526>, + <41153 41235 41310 41352 41318 41305>, + <41088 41026 41094 41134 41100 41087>, + <40904 40832 40899 40930 40893 40877>, + <40447 40653 40720 40736 40694 40672>, + <40034 40458 40525 40537 40495 40472>, + <39788 40221 40292 40319 40288 40277>, + <39585 39967 40050 40106 40087 40088>, + <39406 39734 39841 39926 39912 39913>, + <39248 39515 39652 39767 39754 39750>, + <39074 39305 39456 39583 39572 39566>, + <38832 39100 39232 39336 39328 39323>, + <38584 38908 39017 39089 39082 39080>, + <38426 38747 38845 38906 38903 38901>, + <38310 38609 38699 38752 38755 38754>, + <38226 38477 38570 38621 38627 38625>, + <38164 38335 38453 38506 38513 38511>, + <38113 38204 38348 38403 38410 38407>, + <38062 38112 38253 38308 38314 38311>, + <38014 38043 38166 38221 38224 38220>, + <37968 37988 38082 38140 38142 38137>, + <37925 37942 37996 38064 38067 38062>, + <37882 37901 37921 37993 37995 37989>, + <37836 37861 37870 37925 37926 37914>, + <37789 37823 37831 37859 37858 37837>, + <37739 37781 37790 37789 37775 37745>, + <37688 37735 37747 37715 37668 37625>, + <37631 37682 37698 37637 37559 37505>, + <37562 37619 37632 37559 37469 37410>, + <37480 37542 37547 37477 37386 37325>, + <37385 37449 37447 37382 37290 37228>, + <37268 37321 37322 37269 37178 37113>, + <37144 37177 37181 37135 37045 36979>, + <37027 37026 37025 36987 36895 36830>, + <36932 36918 36939 36908 36841 36784>, + <36855 36857 36899 36885 36818 36762>, + <36812 36827 36875 36867 36801 36749>, + <36761 36786 36846 36843 36779 36722>, + <36679 36721 36775 36779 36692 36597>, + <36475 36551 36546 36552 36390 36264>, + <36066 36173 36127 36133 35937 35797>, + <35499 35647 35579 35596 35370 35211>, + <34766 34968 34863 34909 34633 34453>, + <33784 34024 33935 33996 33658 33408>, + <32412 32711 32567 32650 31840 31311>, + <28215 28831 27522 28579 27814 27518>; + }; + + qcom,pc-temp-z1-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <11770 11167 10508 10200 10123>, + <11802 11193 10579 10273 10190>, + <11806 11200 10581 10275 10191>, + <11805 11183 10570 10275 10191>, + <11792 11170 10557 10270 10189>, + <11777 11154 10545 10264 10185>, + <11765 11131 10537 10259 10182>, + <11755 11116 10530 10255 10180>, + <11743 11111 10524 10251 10178>, + <11735 11108 10520 10250 10177>, + <11730 11108 10517 10249 10175>, + <11726 11108 10514 10248 10174>, + <11721 11108 10512 10248 10173>, + <11717 11105 10511 10247 10173>, + <11714 11099 10510 10247 10172>, + <11704 11097 10508 10245 10172>, + <11693 11095 10507 10245 10172>, + <11693 11095 10506 10245 10172>, + <11704 11097 10506 10246 10174>, + <11714 11101 10509 10248 10175>, + <11726 11106 10513 10252 10177>, + <11741 11114 10517 10254 10179>, + <11744 11122 10522 10256 10181>, + <11737 11128 10527 10258 10183>, + <11732 11133 10532 10260 10185>, + <11733 11134 10537 10264 10187>, + <11737 11132 10542 10267 10190>, + <11740 11131 10548 10272 10194>, + <11743 11133 10553 10276 10197>, + <11747 11137 10558 10280 10200>, + <11750 11142 10564 10285 10203>, + <11754 11154 10571 10288 10206>, + <11758 11165 10579 10292 10209>, + <11769 11165 10584 10296 10213>, + <11781 11161 10589 10301 10217>, + <11789 11159 10594 10306 10221>, + <11796 11169 10600 10312 10225>, + <11803 11182 10606 10317 10229>, + <11809 11185 10612 10322 10233>, + <11816 11186 10619 10326 10236>, + <11819 11188 10625 10330 10239>, + <11821 11199 10630 10335 10243>, + <11823 11208 10636 10340 10246>, + <11826 11206 10642 10342 10248>, + <11820 11215 10648 10344 10249>, + <11820 11220 10655 10347 10250>, + <11830 11225 10660 10348 10252>, + <11816 11232 10658 10350 10253>, + <11831 11224 10662 10354 10257>, + <11856 11221 10671 10358 10261>, + <11833 11233 10673 10362 10265>, + <11848 11251 10678 10368 10270>, + <11885 11257 10688 10374 10275>, + <11898 11288 10702 10382 10282>, + <11898 11288 10702 10382 10282>, + <11898 11288 10702 10382 10282>; + }; + + qcom,pc-temp-z2-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <9894 9757 10034 10106 10345>, + <9913 9932 10014 10164 10226>, + <9939 10003 10052 10124 10214>, + <9961 9993 10069 10079 10205>, + <9956 9975 10063 10081 10205>, + <9932 9968 10050 10100 10208>, + <9909 9964 10028 10116 10214>, + <9894 9962 9988 10127 10224>, + <9882 9965 9971 10137 10239>, + <9879 9971 9979 10146 10256>, + <9887 9975 9990 10155 10278>, + <9899 9978 9996 10160 10293>, + <9908 9983 10003 10160 10302>, + <9915 10111 10010 10159 10307>, + <9923 10305 10017 10164 10303>, + <9937 10319 10021 10171 10296>, + <9949 10152 10020 10170 10294>, + <9950 10028 10015 10163 10294>, + <9944 10019 10013 10158 10295>, + <9940 10013 10022 10178 10307>, + <9940 10015 10039 10212 10331>, + <9943 10049 10081 10217 10334>, + <9948 10079 10155 10205 10297>, + <9962 10074 10180 10185 10246>, + <9973 10059 10141 10123 10180>, + <9974 10052 10094 10050 10113>, + <9972 10052 10070 10041 10102>, + <9972 10053 10053 10046 10113>, + <9973 10046 10049 10054 10127>, + <9975 10033 10060 10064 10141>, + <9976 10029 10075 10077 10158>, + <9978 10038 10091 10098 10180>, + <9980 10052 10108 10129 10208>, + <9983 10064 10127 10163 10243>, + <9988 10077 10148 10206 10293>, + <9992 10087 10168 10244 10345>, + <9997 10095 10183 10263 10380>, + <10003 10102 10195 10276 10409>, + <10012 10114 10208 10287 10417>, + <10023 10130 10226 10298 10403>, + <10024 10137 10237 10306 10390>, + <10014 10120 10220 10308 10389>, + <10008 10106 10192 10307 10384>, + <10006 10106 10186 10298 10361>, + <10058 10124 10199 10299 10329>, + <10061 10124 10204 10309 10360>, + <10054 10113 10214 10301 10359>, + <10052 10093 10207 10352 10392>, + <10039 10104 10227 10397 10452>, + <9972 10155 10228 10268 10254>, + <10081 10129 10171 10193 10218>, + <10034 10095 10128 10161 10175>, + <9993 10043 10103 10128 10146>, + <9836 9993 10057 10083 10063>, + <9836 9993 10057 10083 10063>, + <9836 9993 10057 10083 10063>; + }; + + qcom,pc-temp-z3-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <19500 19444 19370 19351 19313>, + <19626 19520 19402 19353 19340>, + <19677 19560 19426 19362 19348>, + <19706 19570 19435 19369 19353>, + <19708 19575 19432 19369 19353>, + <19704 19574 19427 19367 19351>, + <19701 19566 19421 19364 19348>, + <19699 19557 19414 19360 19345>, + <19697 19549 19409 19355 19341>, + <19692 19541 19406 19353 19340>, + <19680 19535 19404 19352 19339>, + <19665 19529 19401 19351 19338>, + <19649 19525 19397 19351 19337>, + <19632 19526 19395 19351 19336>, + <19625 19529 19394 19350 19335>, + <19632 19529 19394 19349 19331>, + <19639 19523 19394 19348 19329>, + <19638 19517 19394 19347 19327>, + <19628 19510 19394 19345 19325>, + <19621 19502 19390 19341 19323>, + <19618 19501 19385 19335 19320>, + <19616 19515 19389 19337 19322>, + <19618 19527 19402 19355 19339>, + <19632 19520 19415 19369 19354>, + <19643 19503 19428 19376 19357>, + <19638 19499 19437 19380 19359>, + <19626 19519 19437 19380 19359>, + <19619 19539 19434 19373 19356>, + <19618 19539 19430 19368 19353>, + <19618 19535 19425 19366 19350>, + <19619 19530 19418 19364 19347>, + <19621 19524 19413 19362 19343>, + <19622 19517 19409 19358 19340>, + <19621 19512 19405 19354 19336>, + <19618 19508 19401 19349 19331>, + <19615 19505 19398 19346 19328>, + <19611 19503 19397 19346 19330>, + <19607 19500 19396 19347 19336>, + <19603 19497 19395 19348 19339>, + <19597 19494 19393 19350 19339>, + <19593 19490 19390 19351 19339>, + <19592 19487 19386 19352 19339>, + <19588 19483 19383 19353 19339>, + <19579 19481 19385 19354 19341>, + <19543 19466 19382 19350 19341>, + <19529 19450 19368 19337 19321>, + <19525 19448 19365 19331 19318>, + <19523 19438 19363 19324 19312>, + <19489 19434 19359 19320 19312>, + <19401 19438 19363 19342 19330>, + <19514 19442 19376 19345 19331>, + <19508 19444 19378 19345 19332>, + <19506 19447 19381 19346 19334>, + <19479 19451 19379 19353 19342>, + <19479 19451 19379 19353 19342>, + <19479 19451 19379 19353 19342>; + }; + + qcom,pc-temp-z4-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <15847 15406 14998 14784 14808>, + <15949 15355 15044 14878 14825>, + <15794 15280 14959 14838 14798>, + <15524 15160 14880 14782 14745>, + <15335 15024 14821 14755 14725>, + <15199 14932 14776 14735 14717>, + <15092 14862 14760 14724 14712>, + <15007 14818 14752 14719 14708>, + <14938 14795 14745 14715 14704>, + <14892 14781 14736 14710 14700>, + <14861 14774 14728 14704 14696>, + <14839 14771 14722 14699 14691>, + <14823 14768 14716 14693 14687>, + <14809 14746 14714 14688 14682>, + <14805 14717 14714 14683 14677>, + <14837 14717 14714 14679 14672>, + <14877 14763 14713 14676 14669>, + <14877 14798 14707 14672 14666>, + <14845 14782 14700 14669 14663>, + <14819 14748 14691 14667 14660>, + <14809 14748 14684 14665 14657>, + <14802 14849 14717 14676 14662>, + <14817 14940 14810 14736 14713>, + <14926 14941 14844 14773 14752>, + <15018 14932 14810 14755 14738>, + <15011 14916 14769 14725 14711>, + <14979 14870 14751 14712 14699>, + <14949 14826 14739 14706 14693>, + <14922 14811 14733 14701 14688>, + <14898 14803 14730 14696 14684>, + <14881 14800 14728 14693 14681>, + <14867 14800 14728 14691 14678>, + <14859 14800 14727 14689 14675>, + <14855 14800 14728 14689 14674>, + <14853 14801 14730 14689 14673>, + <14850 14801 14732 14690 14672>, + <14845 14800 14733 14694 14676>, + <14843 14799 14734 14701 14687>, + <14846 14800 14735 14703 14692>, + <14851 14805 14736 14701 14691>, + <14852 14807 14737 14699 14691>, + <14843 14799 14733 14696 14691>, + <14831 14786 14724 14692 14690>, + <14819 14776 14719 14690 14690>, + <14767 14740 14703 14678 14676>, + <14740 14710 14680 14653 14645>, + <14731 14703 14668 14647 14637>, + <14725 14696 14656 14637 14627>, + <14741 14692 14651 14632 14622>, + <14832 14699 14662 14641 14641>, + <14739 14707 14661 14645 14646>, + <14748 14705 14661 14648 14648>, + <14752 14704 14661 14650 14649>, + <14789 14699 14665 14647 14645>, + <14789 14699 14665 14647 14645>, + <14789 14699 14665 14647 14645>; + }; + + qcom,pc-temp-z5-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <11792 12279 13535 15414 14204>, + <13001 13808 15235 16383 17416>, + <13841 15100 16456 17237 19077>, + <14514 16104 17533 18315 20517>, + <15113 17028 18754 19244 21245>, + <15689 18181 19650 20146 21743>, + <16375 19593 19683 20412 21915>, + <17353 20752 19475 20064 21544>, + <18570 21607 19385 19726 21069>, + <19714 22312 19837 19833 21119>, + <20922 22624 20368 20227 21592>, + <21654 22649 20366 20704 22135>, + <21494 22792 20190 21409 22819>, + <21073 24392 20127 22129 23478>, + <21017 26764 20584 22757 23767>, + <22555 26941 21094 23386 23725>, + <24349 24455 21214 23801 23655>, + <24216 22548 21439 24313 23878>, + <22900 22853 21828 24599 24211>, + <22166 23930 23250 24474 24553>, + <23067 25813 24579 24129 24960>, + <25218 31144 24161 23371 24839>, + <27733 35337 22682 21648 23111>, + <31628 31478 21716 20674 21705>, + <34089 22242 21182 20941 21493>, + <31865 19114 20879 21395 21408>, + <26536 20884 21549 21643 21618>, + <23985 23280 23503 21875 22646>, + <23503 25063 24966 22255 23786>, + <23364 26728 25863 23569 24665>, + <23874 27767 26627 25316 25537>, + <25339 28404 27366 26549 26565>, + <26580 28812 28051 27647 27783>, + <27299 28952 28637 28369 28438>, + <27859 29013 29244 28922 28605>, + <28127 28980 29596 29269 28749>, + <28121 28632 29354 28928 29008>, + <28035 28071 28613 27970 29397>, + <28032 27480 27672 27629 29838>, + <28024 26731 26146 27677 30769>, + <27889 25936 24626 27779 31609>, + <27436 24934 23369 28434 31801>, + <26929 24388 22499 29368 31887>, + <26421 24450 22608 28936 31937>, + <27988 25663 22852 26365 31185>, + <27430 25453 21972 22626 21099>, + <26554 25602 22352 22600 22211>, + <26806 23914 24361 22775 24450>, + <23478 23641 24736 23227 28936>, + <18946 23905 22228 28971 29716>, + <23561 21707 23990 27451 26335>, + <20333 21474 23601 25150 24619>, + <18967 20996 23606 23367 22997>, + <16796 21104 21653 24495 23716>, + <16796 21104 21653 24495 23716>, + <16796 21104 21653 24495 23716>; + }; + + qcom,pc-temp-z6-lut { + qcom,lut-col-legend = <0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200>, + <9000 8800 8600 8400 8200>, + <8000 7800 7600 7400 7200>, + <7000 6800 6600 6400 6200>, + <6000 5800 5600 5400 5200>, + <5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200>, + <3000 2800 2600 2400 2200>, + <2000 1800 1600 1400 1200>, + <1000 900 800 700 600>, + <500 400 300 200 100>, + <0>; + qcom,lut-data = <15776 15081 14574 14403 14378>, + <15822 15066 14611 14457 14412>, + <15728 15042 14587 14444 14404>, + <15561 14985 14560 14425 14386>, + <15434 14901 14531 14412 14376>, + <15332 14840 14504 14402 14371>, + <15250 14790 14491 14394 14367>, + <15184 14755 14482 14389 14362>, + <15130 14736 14475 14384 14359>, + <15088 14723 14469 14380 14356>, + <15057 14715 14464 14377 14353>, + <15033 14710 14459 14374 14350>, + <15014 14704 14454 14371 14348>, + <14997 14693 14451 14368 14345>, + <14991 14680 14450 14366 14342>, + <15002 14679 14449 14363 14338>, + <15017 14691 14448 14361 14335>, + <15016 14701 14446 14359 14333>, + <14999 14693 14443 14357 14331>, + <14987 14676 14438 14354 14328>, + <14985 14676 14433 14350 14326>, + <14985 14729 14451 14357 14329>, + <14996 14777 14500 14394 14362>, + <15054 14775 14519 14417 14387>, + <15101 14767 14512 14412 14383>, + <15097 14759 14503 14404 14374>, + <15080 14752 14497 14398 14368>, + <15067 14746 14492 14393 14365>, + <15057 14742 14488 14389 14362>, + <15050 14739 14484 14386 14358>, + <15047 14737 14482 14384 14356>, + <15045 14735 14480 14382 14353>, + <15045 14734 14478 14379 14350>, + <15046 14734 14478 14378 14347>, + <15047 14735 14478 14376 14345>, + <15049 14736 14479 14375 14343>, + <15050 14738 14480 14377 14345>, + <15052 14740 14481 14381 14354>, + <15055 14743 14482 14384 14358>, + <15061 14747 14484 14384 14358>, + <15065 14749 14485 14385 14359>, + <15066 14747 14482 14385 14359>, + <15067 14746 14478 14385 14360>, + <15067 14745 14478 14385 14361>, + <15047 14732 14473 14378 14356>, + <15035 14716 14457 14362 14333>, + <15030 14712 14451 14356 14327>, + <15027 14706 14445 14348 14320>, + <15020 14704 14442 14344 14318>, + <15023 14714 14450 14360 14336>, + <15046 14724 14459 14366 14341>, + <15055 14730 14462 14368 14344>, + <15068 14739 14467 14371 14347>, + <15088 14751 14472 14376 14351>, + <15088 14751 14472 14376 14351>, + <15088 14751 14472 14376 14351>; + }; + + qcom,pc-temp-y1-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <5821 5347 5037 4674 4481 4427>, + <5843 5351 5036 4672 4484 4429>, + <5865 5355 5035 4670 4485 4430>, + <5883 5361 5033 4667 4485 4430>, + <5897 5365 5031 4664 4484 4431>, + <5903 5367 5030 4660 4482 4431>, + <5900 5367 5025 4656 4477 4430>, + <5895 5365 5019 4650 4473 4429>, + <5896 5364 5014 4646 4472 4427>, + <5901 5359 5010 4643 4472 4425>, + <5903 5356 5008 4640 4472 4423>, + <5904 5358 5011 4637 4470 4422>, + <5908 5361 5015 4634 4468 4422>, + <5911 5361 5013 4632 4467 4421>, + <5920 5359 5004 4630 4465 4419>, + <5925 5358 5000 4629 4464 4419>, + <5922 5365 5003 4629 4464 4419>, + <5917 5374 5007 4629 4464 4419>, + <5917 5376 5008 4629 4464 4419>, + <5916 5373 5005 4630 4465 4419>, + <5914 5372 5003 4631 4465 4419>, + <5914 5377 5004 4633 4467 4420>, + <5916 5382 5005 4635 4469 4422>, + <5917 5383 5005 4638 4469 4422>, + <5917 5382 5006 4640 4469 4422>, + <5917 5382 5008 4643 4470 4423>, + <5915 5390 5013 4646 4472 4423>, + <5911 5400 5019 4650 4474 4424>, + <5907 5401 5024 4654 4476 4426>, + <5900 5398 5029 4659 4479 4428>, + <5896 5395 5032 4664 4481 4430>, + <5906 5395 5032 4669 4484 4431>, + <5922 5398 5032 4675 4487 4432>, + <5932 5401 5035 4679 4490 4434>, + <5943 5403 5043 4682 4493 4437>, + <5946 5405 5047 4686 4496 4440>, + <5933 5401 5047 4691 4499 4442>, + <5912 5395 5048 4695 4501 4444>, + <5901 5393 5053 4701 4504 4445>, + <5892 5393 5061 4707 4506 4446>, + <5887 5393 5065 4710 4509 4448>, + <5896 5394 5064 4713 4511 4451>, + <5900 5398 5066 4715 4513 4451>, + <5883 5418 5079 4717 4515 4451>, + <5915 5410 5075 4725 4518 4454>, + <5906 5399 5089 4726 4521 4456>, + <5899 5402 5088 4727 4519 4457>, + <5893 5400 5081 4734 4522 4457>, + <5894 5416 5082 4737 4521 4457>, + <5893 5422 5089 4735 4523 4458>, + <5951 5403 5099 4738 4525 4460>, + <5978 5411 5100 4752 4529 4462>, + <5943 5406 5107 4748 4534 4464>, + <5955 5420 5108 4757 4536 4469>, + <5955 5420 5108 4757 4536 4469>, + <5955 5420 5108 4757 4536 4469>; + }; + + qcom,pc-temp-y2-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <10091 10247 10509 10767 10785 10927>, + <10085 10259 10500 10740 10807 10958>, + <10082 10274 10489 10711 10818 10974>, + <10082 10288 10479 10684 10821 10978>, + <10084 10301 10470 10661 10818 10974>, + <10088 10309 10463 10643 10813 10967>, + <10129 10314 10458 10630 10787 10948>, + <10196 10318 10454 10619 10754 10920>, + <10242 10317 10452 10606 10748 10891>, + <10309 10310 10448 10589 10749 10854>, + <10343 10306 10446 10578 10750 10833>, + <10348 10349 10451 10581 10744 10834>, + <10361 10433 10462 10588 10735 10837>, + <10354 10516 10482 10588 10734 10833>, + <10267 10617 10525 10585 10733 10822>, + <10196 10671 10577 10591 10733 10816>, + <9993 10677 10646 10622 10733 10824>, + <9724 10679 10709 10670 10734 10837>, + <9677 10682 10732 10741 10732 10847>, + <9671 10689 10745 10841 10729 10857>, + <9668 10692 10750 10877 10736 10873>, + <9666 10695 10747 10828 10833 10914>, + <9664 10701 10743 10775 10940 10965>, + <9663 10698 10754 10784 10956 10999>, + <9661 10676 10777 10824 10960 11030>, + <9660 10640 10792 10857 10965 11054>, + <9659 10551 10798 10880 10972 11078>, + <9658 10416 10805 10900 10980 11102>, + <9657 10287 10820 10916 10994 11121>, + <9656 10134 10847 10930 11021 11137>, + <9656 10010 10858 10948 11048 11156>, + <9655 9913 10844 10989 11077 11185>, + <9655 9833 10824 11022 11105 11210>, + <9654 9791 10807 11021 11137 11220>, + <9654 9761 10786 11011 11170 11226>, + <9654 9737 10768 11005 11177 11228>, + <9654 9716 10753 11011 11139 11200>, + <9654 9699 10737 11017 11102 11170>, + <9653 9689 10712 11012 11096 11161>, + <9653 9681 10675 10996 11093 11144>, + <9653 9675 10616 10980 11081 11118>, + <9653 9671 10491 10961 11032 11066>, + <9653 9667 10377 10936 11009 11056>, + <9653 9664 10284 10902 11002 11096>, + <9653 9661 10205 10867 11000 10997>, + <9652 9659 10189 10820 10935 10941>, + <9652 9659 10170 10842 10880 10907>, + <9652 9658 10266 10786 10907 10898>, + <9652 9657 10342 10819 10926 10908>, + <9652 9656 10250 10823 10875 10851>, + <9652 9655 10037 10750 10829 10802>, + <9652 9654 9972 10651 10750 10766>, + <9651 9653 9891 10735 10690 10675>, + <9650 9653 10171 10679 10569 10544>, + <9650 9653 10171 10679 10569 10544>, + <9650 9653 10171 10679 10569 10544>; + }; + + qcom,pc-temp-y3-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <14020 13485 13348 13290 13276 13269>, + <13912 13484 13350 13290 13276 13270>, + <13847 13482 13351 13290 13277 13271>, + <13814 13481 13352 13290 13277 13272>, + <13802 13479 13353 13290 13278 13274>, + <13800 13477 13353 13290 13278 13274>, + <13846 13474 13353 13290 13278 13275>, + <13915 13471 13353 13289 13279 13275>, + <13881 13472 13353 13290 13279 13275>, + <13646 13477 13352 13291 13279 13275>, + <13499 13480 13351 13292 13280 13275>, + <13535 13470 13351 13294 13280 13276>, + <13592 13454 13351 13296 13280 13277>, + <13605 13449 13352 13297 13281 13277>, + <13589 13442 13356 13297 13282 13277>, + <13574 13436 13358 13298 13282 13277>, + <13544 13434 13352 13298 13282 13277>, + <13507 13429 13343 13300 13283 13277>, + <13503 13421 13341 13301 13284 13278>, + <13510 13403 13340 13302 13285 13280>, + <13517 13385 13338 13303 13286 13281>, + <13521 13372 13331 13298 13282 13278>, + <13523 13361 13323 13291 13278 13275>, + <13523 13352 13319 13288 13277 13274>, + <13533 13345 13316 13286 13277 13273>, + <13553 13338 13314 13285 13276 13272>, + <13593 13320 13311 13285 13277 13273>, + <13646 13299 13309 13285 13277 13273>, + <13696 13288 13308 13285 13276 13273>, + <13750 13271 13307 13286 13276 13273>, + <13806 13266 13305 13286 13275 13273>, + <13866 13268 13303 13285 13275 13273>, + <13929 13271 13301 13285 13275 13272>, + <13994 13274 13301 13285 13275 13272>, + <14060 13278 13303 13284 13276 13272>, + <14134 13284 13305 13284 13277 13272>, + <14220 13295 13307 13283 13276 13273>, + <14312 13311 13309 13282 13275 13273>, + <14405 13332 13311 13282 13275 13273>, + <14501 13362 13312 13282 13276 13274>, + <14596 13393 13313 13282 13276 13274>, + <14687 13416 13313 13282 13277 13274>, + <14781 13443 13314 13283 13277 13274>, + <14884 13488 13317 13284 13276 13273>, + <14998 13565 13322 13285 13276 13274>, + <14988 13596 13326 13288 13278 13276>, + <15059 13649 13330 13289 13279 13277>, + <15152 13712 13339 13294 13283 13279>, + <15247 13784 13351 13296 13282 13277>, + <15340 13847 13352 13295 13280 13276>, + <15443 13922 13355 13295 13281 13277>, + <15627 14060 13367 13298 13284 13279>, + <15865 14258 13384 13304 13286 13283>, + <16661 14530 13427 13312 13291 13287>, + <16661 14530 13427 13312 13291 13287>, + <16661 14530 13427 13312 13291 13287>; + }; + + qcom,pc-temp-y4-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <18008 16999 16718 16500 16460 16456>, + <18072 17065 16719 16497 16459 16454>, + <18111 17109 16717 16493 16457 16452>, + <18131 17135 16714 16489 16455 16451>, + <18138 17148 16709 16486 16453 16449>, + <18139 17152 16703 16485 16453 16448>, + <18029 17137 16693 16486 16452 16448>, + <17863 17112 16683 16486 16452 16447>, + <17896 17097 16681 16488 16452 16448>, + <18235 17083 16680 16490 16454 16449>, + <18508 17077 16680 16492 16455 16450>, + <18619 17111 16683 16496 16457 16451>, + <18700 17180 16689 16501 16461 16452>, + <18607 17260 16712 16509 16466 16453>, + <18107 17384 16786 16522 16473 16457>, + <17766 17446 16846 16538 16481 16462>, + <17718 17379 16883 16554 16487 16468>, + <17687 17259 16908 16574 16496 16475>, + <17629 17174 16905 16613 16516 16490>, + <17534 17108 16880 16675 16554 16516>, + <17407 17042 16841 16697 16568 16526>, + <17159 16963 16746 16628 16535 16505>, + <16891 16889 16644 16542 16492 16476>, + <16806 16845 16607 16507 16473 16463>, + <16770 16818 16587 16484 16461 16454>, + <16755 16786 16580 16478 16457 16452>, + <16753 16727 16578 16479 16457 16452>, + <16753 16673 16578 16480 16457 16452>, + <16756 16669 16579 16483 16459 16453>, + <16763 16685 16581 16490 16462 16455>, + <16771 16697 16581 16497 16467 16458>, + <16783 16705 16558 16506 16473 16464>, + <16797 16717 16535 16512 16481 16470>, + <16813 16732 16538 16515 16488 16475>, + <16831 16753 16552 16517 16495 16479>, + <16846 16769 16568 16515 16495 16479>, + <16858 16781 16587 16493 16474 16465>, + <16869 16791 16601 16473 16454 16451>, + <16877 16794 16600 16470 16450 16451>, + <16883 16792 16599 16468 16449 16452>, + <16885 16788 16599 16469 16448 16452>, + <16876 16770 16608 16474 16449 16451>, + <16865 16757 16618 16479 16448 16448>, + <16860 16757 16628 16481 16442 16435>, + <16879 16761 16645 16484 16444 16435>, + <16891 16789 16652 16498 16455 16453>, + <16943 16827 16682 16511 16475 16497>, + <17014 16881 16733 16537 16536 16562>, + <17081 16976 16802 16590 16557 16530>, + <17089 17020 16800 16563 16478 16467>, + <17047 16991 16801 16554 16477 16469>, + <17042 17006 16834 16584 16500 16488>, + <17105 17082 16903 16649 16553 16544>, + <17555 17233 17100 16828 16767 16718>, + <17555 17233 17100 16828 16767 16718>, + <17555 17233 17100 16828 16767 16718>; + }; + + qcom,pc-temp-y5-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <11727 11942 13506 16264 17485 13743>, + <11187 12181 13834 16304 17713 15443>, + <10948 12440 14154 16154 17943 16969>, + <10946 12689 14439 15889 18142 18238>, + <11119 12897 14661 15580 18277 19164>, + <11403 13035 14792 15300 18315 19661>, + <12465 13100 14855 14911 18249 19739>, + <13822 13150 14864 14518 18113 19553>, + <13670 13301 14746 14395 17867 19106>, + <11695 13714 14420 14341 17361 18217>, + <10462 13958 14096 14326 16853 17639>, + <11501 13114 13863 14506 16406 17596>, + <13219 11865 13624 14722 15945 17611>, + <13884 11823 13278 14498 15435 17295>, + <13848 12774 12797 13693 14834 16535>, + <13691 13748 12589 13309 14470 15845>, + <13167 14554 12751 13334 14271 15143>, + <12586 15195 13107 13390 14142 14574>, + <13020 15258 13900 13564 14152 14504>, + <14413 15027 15523 14068 14254 14631>, + <15535 14881 16342 14723 14446 14876>, + <15575 14923 16444 15913 15152 15787>, + <15061 15014 16478 16911 16165 16899>, + <14339 15197 16434 16931 17201 17475>, + <12334 15627 16343 16746 18331 17902>, + <11314 15978 16268 16667 18791 18109>, + <11399 15505 16100 16581 18776 18180>, + <11512 14520 15934 16533 18615 18169>, + <11525 13737 16028 16730 18175 18053>, + <11550 12045 16380 17082 17340 17858>, + <11588 11352 16565 17187 16713 17565>, + <11718 11445 16382 17060 16198 16814>, + <11865 11550 16160 16944 15883 16183>, + <11908 11637 16198 17254 16375 16323>, + <11980 11737 16327 17954 17689 16949>, + <12075 11818 16423 18152 18505 17767>, + <12422 11915 16495 17982 18987 19240>, + <12794 12071 16540 17734 19303 20755>, + <12843 12334 16444 17425 19669 21829>, + <12812 12824 16116 17020 20264 22723>, + <12740 13086 15663 16654 20463 22879>, + <12356 12741 14862 16171 20541 22449>, + <11882 12264 14369 16034 20626 22711>, + <11570 11949 14152 16151 21020 24835>, + <11487 11951 14006 15816 18734 20674>, + <11662 11903 13943 16003 17805 20181>, + <11655 12101 13682 15426 17094 17583>, + <11840 12432 13801 16015 16324 15006>, + <12476 12948 14155 15430 14898 14594>, + <12752 13151 14323 16256 17791 17272>, + <12081 13073 14285 16869 17629 17625>, + <11734 12858 14199 16707 19166 17889>, + <11770 12567 13945 17145 18317 18429>, + <11976 12244 15223 16959 17784 17367>, + <11976 12244 15223 16959 17784 17367>, + <11976 12244 15223 16959 17784 17367>; + }; + + qcom,pc-temp-y6-lut { + qcom,lut-col-legend = <(-10) 0 10 25 40 50>; + qcom,lut-row-legend = <10000 9800 9600 9400 9200 9000>, + <8800 8600 8400 8200 8000 7800>, + <7600 7400 7200 7000 6800 6600>, + <6400 6200 6000 5800 5600 5400>, + <5200 5000 4800 4600 4400 4200>, + <4000 3800 3600 3400 3200 3000>, + <2800 2600 2400 2200 2000 1800>, + <1600 1400 1200 1000 900 800>, + <700 600 500 400 300 200>, + <100 0>; + qcom,lut-data = <6551 5600 5220 4990 4943 4930>, + <6534 5605 5216 4988 4942 4931>, + <6511 5605 5211 4986 4942 4931>, + <6488 5601 5205 4984 4942 4931>, + <6470 5594 5199 4983 4942 4932>, + <6461 5584 5193 4982 4942 4932>, + <6460 5570 5186 4981 4942 4932>, + <6461 5554 5179 4980 4942 4932>, + <6450 5545 5174 4981 4942 4932>, + <6403 5538 5169 4981 4942 4933>, + <6375 5535 5166 4982 4943 4933>, + <6433 5536 5165 4984 4943 4933>, + <6517 5539 5164 4987 4945 4934>, + <6504 5548 5169 4989 4946 4935>, + <6362 5577 5191 4993 4949 4936>, + <6258 5593 5206 4998 4951 4938>, + <6231 5576 5210 5003 4954 4939>, + <6212 5543 5212 5009 4956 4942>, + <6209 5514 5211 5021 4962 4946>, + <6205 5486 5203 5040 4974 4955>, + <6199 5459 5190 5046 4978 4958>, + <6156 5431 5159 5023 4966 4950>, + <6101 5407 5125 4994 4951 4939>, + <6096 5397 5113 4982 4945 4934>, + <6119 5393 5107 4974 4941 4931>, + <6146 5387 5105 4972 4940 4930>, + <6186 5373 5105 4973 4940 4930>, + <6237 5359 5106 4974 4940 4931>, + <6285 5359 5108 4975 4940 4931>, + <6335 5374 5112 4978 4941 4932>, + <6386 5394 5113 4981 4942 4933>, + <6438 5418 5109 4984 4944 4934>, + <6491 5448 5106 4986 4946 4936>, + <6546 5478 5109 4988 4949 4938>, + <6603 5512 5120 4989 4952 4939>, + <6665 5547 5133 4989 4952 4939>, + <6732 5583 5145 4983 4946 4936>, + <6803 5621 5158 4978 4940 4932>, + <6876 5662 5167 4978 4940 4932>, + <6950 5708 5176 4978 4940 4933>, + <7022 5754 5186 4979 4940 4933>, + <7089 5799 5201 4982 4942 4934>, + <7157 5850 5219 4985 4942 4933>, + <7235 5915 5240 4987 4939 4929>, + <7330 6003 5272 4991 4941 4930>, + <7326 6045 5279 4998 4946 4937>, + <7395 6104 5304 5003 4952 4950>, + <7483 6173 5341 5014 4973 4970>, + <7577 6261 5385 5032 4978 4960>, + <7656 6331 5397 5024 4954 4941>, + <7727 6392 5417 5023 4955 4943>, + <7873 6517 5468 5035 4965 4950>, + <8078 6702 5539 5060 4982 4970>, + <8853 6954 5681 5120 5047 5023>, + <8853 6954 5681 5120 5047 5023>, + <8853 6954 5681 5120 5047 5023>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qrb5165-iot-rb5.dts b/arch/arm64/boot/dts/vendor/qcom/qrb5165-iot-rb5.dts new file mode 100644 index 0000000000000000000000000000000000000000..2acccf6465477802e115eabb63efdc038f7028ec --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qrb5165-iot-rb5.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "qrb5165.dtsi" +#include "kona-v2.1-iot-rb5.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. qrb5165 IOT RB5"; + compatible = "qcom,kona-iot", "qcom,kona", "qcom,iot"; + qcom,board-id = <11 3>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/qrb5165.dtsi b/arch/arm64/boot/dts/vendor/qcom/qrb5165.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3cfa38c0c168fa437dd3119e74377b801513fdd6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/qrb5165.dtsi @@ -0,0 +1,10 @@ + +#include "kona-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. qrb5165"; + compatible = "qcom,kona"; + qcom,msm-id = <455 0x20001>; +}; + +#include "kona-v2.1-gpu.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..a5ae2732a3ae1723565c8ea0f724ecbb4beaf472 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-2gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba 2GB DDR SoC"; + compatible = "qcom,scuba"; + qcom,msm-id = <441 0x10000>, <471 0x10000>; + qcom,board-id = <0 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-audio-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-audio-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9ed32c7800228b5f5a541ac2015bffb42dae1c71 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-audio-overlay.dtsi @@ -0,0 +1,319 @@ +#include +#include +#include +#include + +&bolero { + qcom,num-macros = <3>; + qcom,bolero-version = <5>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + qcom,fs-gen-sequence = <0x3000 0x1>, + <0x3004 0x1>, <0x3080 0x2>; + qcom,rx_mclk_mode_muxsel = <0x0a5640d8>; + qcom,va_mclk_mode_muxsel = <0x0a7a0000>; + clock-names = "tx_core_clk", "tx_npl_clk", "rx_core_clk", "rx_npl_clk", + "va_core_clk", "va_npl_clk"; + clocks = <&clock_audio_tx_1 0>, <&clock_audio_tx_2 0>, + <&clock_audio_rx_1 0>, <&clock_audio_rx_2 0>, + <&clock_audio_va_1 0>, <&clock_audio_va_2 0>; + }; + + tx_macro: tx-macro@0a620000 { + compatible = "qcom,tx-macro"; + reg = <0x0a620000 0x0>; + clock-names = "tx_core_clk", "tx_npl_clk"; + clocks = <&clock_audio_tx_1 0>, + <&clock_audio_tx_2 0>; + qcom,tx-dmic-sample-rate = <2400000>; + qcom,is-used-swr-gpio = <0>; + }; + + rx_macro: rx-macro@0a600000 { + compatible = "qcom,rx-macro"; + reg = <0x0a600000 0x0>; + clock-names = "rx_core_clk", "rx_npl_clk"; + clocks = <&clock_audio_rx_1 0>, + <&clock_audio_rx_2 0>; + qcom,rx-swr-gpios = <&rx_swr_gpios>; + qcom,rx_mclk_mode_muxsel = <0x0a5640d8>; + qcom,rx-bcl-pmic-params = /bits/ 8 <0x00 0x04 0x3E>; + qcom,default-clk-id = ; + swr1: rx_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <2>; + qcom,swrm-hctl-reg = <0x0a6a9098>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x0a610000 0x0>; + interrupts = <0 297 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq"; + qcom,swr-num-ports = <5>; + qcom,disable-div2-clk-switch = <1>; + qcom,swr-port-mapping = <1 HPH_L 0x1>, + <1 HPH_R 0x2>, <2 CLSH 0x1>, + <3 COMP_L 0x1>, <3 COMP_R 0x2>, + <4 LO 0x1>, <5 DSD_L 0x1>, + <5 DSD_R 0x2>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + rouleur_rx_slave: rouleur-rx-slave { + compatible = "qcom,rouleur-slave"; + reg = <0x0C 0x01170224>; + }; + }; + }; + + va_macro: va-macro@0a730000 { + compatible = "qcom,va-macro"; + reg = <0x0a730000 0x0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,va-dmic-sample-rate = <600000>; + qcom,va-clk-mux-select = <1>; + qcom,va-island-mode-muxsel = <0x0a7a0000>; + qcom,default-clk-id = ; + qcom,is-used-swr-gpio = <1>; + qcom,va-swr-gpios = <&va_swr_gpios>; + swr0: va_swr_master { + compatible = "qcom,swr-mstr"; + #address-cells = <2>; + #size-cells = <0>; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + qcom,swr_master_id = <3>; + qcom,swrm-hctl-reg = <0x0a7ec100>; + qcom,mipi-sdw-block-packing-mode = <1>; + swrm-io-base = <0x0a740000 0x0>; + interrupts = + <0 296 IRQ_TYPE_LEVEL_HIGH>, + <0 79 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq", "swr_wake_irq"; + qcom,swr-wakeup-required = <1>; + qcom,swr-num-ports = <3>; + qcom,swr-port-mapping = <1 ADC1 0x1>, <1 ADC2 0x2>, + <1 ADC3 0x4>, <1 ADC4 0x8>, + <2 DMIC0 0x1>, <2 DMIC1 0x2>, + <2 DMIC2 0x4>, <2 DMIC3 0x8>, + <3 DMIC4 0x1>, <3 DMIC5 0x2>, + <3 DMIC6 0x4>, <3 DMIC7 0x8>; + qcom,swr-num-dev = <1>; + qcom,swr-clock-stop-mode0 = <1>; + qcom,swr-mstr-irq-wakeup-capable = <1>; + rouleur_tx_slave: rouleur-tx-slave { + compatible = "qcom,rouleur-slave"; + reg = <0x0C 0x01170223>; + }; + }; + }; + + rouleur_codec: rouleur-codec { + compatible = "qcom,rouleur-codec"; + qcom,split-codec = <1>; + qcom,pmic-spmi-node = <&pm2250_cdc>; + qcom,wcd-reset-reg = <0x0000F3DB>; + qcom,foundry-id-reg = <0x0000704D>; + qcom,rx_swr_ch_map = <0 HPH_L 0x1 0 HPH_L>, + <0 HPH_R 0x2 0 HPH_R>, + <1 COMP_L 0x1 0 COMP_L>, <1 COMP_R 0x2 0 COMP_R>; + qcom,tx_swr_ch_map = <0 ADC1 0x1 0 ADC1>, + <0 ADC2 0x2 0 ADC2>, <0 DMIC0 0x4 0 ADC3>, + <0 MBHC 0x8 0 ADC4>, <1 DMIC0 0x1 0 DMIC0>, + <1 DMIC1 0x2 0 DMIC1>, <1 ADC1 0x4 0 DMIC2>, + <1 MBHC 0x8 0 DMIC3>; + + qcom,rx-slave = <&rouleur_rx_slave>; + qcom,tx-slave = <&rouleur_tx_slave>; + + cdc-vdd-io-supply = <&L15A>; + qcom,cdc-vdd-io-voltage = <1800000 1800000>; + qcom,cdc-vdd-io-current = <10000>; + + cdc-vdd-cp-supply = <&S4A>; + qcom,cdc-vdd-cp-voltage = <2040000 2040000>; + qcom,cdc-vdd-cp-current = <300000>; + + cdc-pa-vpos-supply = <&S4A>; + qcom,cdc-pa-vpos-voltage = <2040000 2040000>; + qcom,cdc-pa-vpos-current = <2400000>; + + cdc-vdd-mic-bias-supply = <&L22A>; + qcom,cdc-vdd-mic-bias-voltage = <3000000 3304000>; + qcom,cdc-vdd-mic-bias-current = <50000>; + qcom,cdc-vdd-mic-bias-lpm-supported = <1>; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + + qcom,cdc-static-supplies = "cdc-vdd-cp", + "cdc-vdd-io", + "cdc-vdd-mic-bias"; + qcom,cdc-on-demand-supplies = "cdc-pa-vpos"; + }; +}; + +&scuba_snd { + qcom,model = "bengal-scubaidp-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,va-bolero-codec = <1>; + qcom,rxtx-bolero-codec = <1>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "TX DMIC0", "MIC BIAS3", + "MIC BIAS3", "Digital Mic0", + "TX DMIC1", "MIC BIAS3", + "MIC BIAS3", "Digital Mic1", + "TX DMIC2", "MIC BIAS1", + "MIC BIAS1", "Digital Mic2", + "TX DMIC3", "MIC BIAS1", + "MIC BIAS1", "Digital Mic3", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "SpkrMono WSA_IN", "LO", + "TX SWR_MIC0", "ADC1_OUTPUT", + "TX SWR_MIC1", "ADC2_OUTPUT", + "TX SWR_MIC2", "DMIC1_OUTPUT", + "TX SWR_MIC5", "DMIC2_OUTPUT", + "TX SWR_MIC0", "VA_TX_SWR_CLK", + "TX SWR_MIC1", "VA_TX_SWR_CLK", + "TX SWR_MIC2", "VA_TX_SWR_CLK", + "TX SWR_MIC3", "VA_TX_SWR_CLK", + "TX SWR_MIC4", "VA_TX_SWR_CLK", + "TX SWR_MIC5", "VA_TX_SWR_CLK", + "TX SWR_MIC6", "VA_TX_SWR_CLK", + "TX SWR_MIC7", "VA_TX_SWR_CLK", + "TX SWR_MIC8", "VA_TX_SWR_CLK", + "TX SWR_MIC9", "VA_TX_SWR_CLK", + "TX SWR_MIC10", "VA_TX_SWR_CLK", + "TX SWR_MIC11", "VA_TX_SWR_CLK", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "TX_AIF1 CAP", "VA_TX_SWR_CLK", + "TX_AIF2 CAP", "VA_TX_SWR_CLK", + "TX_AIF3 CAP", "VA_TX_SWR_CLK", + "VA DMIC0", "VA MIC BIAS3", + "VA DMIC1", "VA MIC BIAS3", + "VA DMIC2", "VA MIC BIAS1", + "VA DMIC3", "VA MIC BIAS1", + "VA MIC BIAS3", "Digital Mic0", + "VA MIC BIAS3", "Digital Mic1", + "VA MIC BIAS1", "Digital Mic2", + "VA MIC BIAS1", "Digital Mic3", + "VA SWR_MIC0", "ADC1_OUTPUT", + "VA SWR_MIC1", "ADC2_OUTPUT", + "VA SWR_MIC2", "DMIC1_OUTPUT", + "VA SWR_MIC5", "DMIC2_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,cdc-dmic01-gpios = <&cdc_dmic01_gpios>; + qcom,cdc-dmic23-gpios = <&cdc_dmic23_gpios>; + + nvmem-cells = <&adsp_variant>; + nvmem-cell-names = "adsp_variant"; + asoc-codec = <&stub_codec>, <&bolero>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_i2c_e>; + qcom,wsa-aux-dev-prefix = "SpkrMono"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&rouleur_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&bolero>, + <&lpi_tlmm>; +}; + +&qupv3_se1_i2c { + wsa881x_i2c_e: wsa881x-i2c-codec@e { + compatible = "qcom,wsa881x-i2c-codec"; + reg = <0x0e>; + clock-names = "wsa_mclk"; + clocks = <&wsa881x_analog_clk 0>; + qcom,wsa-analog-clk-gpio = <&wsa881x_analog_clk_gpio>; + qcom,wsa-analog-reset-gpio = <&wsa881x_analog_reset_gpio>; + }; + + wsa881x_i2c_44: wsa881x-i2c-codec@44 { + compatible = "qcom,wsa881x-i2c-codec"; + reg = <0x044>; + }; +}; + +&soc { + wsa881x_analog_reset_gpio: msm_cdc_pinctrl@106 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa881x_analog_clk: wsa_ana_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <9600000>; + qcom,codec-lpass-clk-id = <0x301>; + #clock-cells = <1>; + }; + + clock_audio_rx_1: rx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30E>; + #clock-cells = <1>; + }; + + clock_audio_rx_2: rx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <22579200>; + qcom,codec-lpass-clk-id = <0x30F>; + #clock-cells = <1>; + }; + + clock_audio_tx_1: tx_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30C>; + #clock-cells = <1>; + }; + + clock_audio_tx_2: tx_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30D>; + #clock-cells = <1>; + }; + + clock_audio_va_1: va_core_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x30B>; + #clock-cells = <1>; + }; + + clock_audio_va_2: va_npl_clk { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + qcom,codec-lpass-ext-clk-freq = <19200000>; + qcom,codec-lpass-clk-id = <0x310>; + #clock-cells = <1>; + }; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bc1bbc6335a329b0f109e102e4baca94f068bab8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-audio.dtsi @@ -0,0 +1,185 @@ +#include +#include "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x01c1 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + + lpass_audio_hw_vote: vote_lpass_audio_hw { + compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = ; + #clock-cells = <1>; + }; + + }; +}; + +#include "scuba-lpi.dtsi" + +&q6core { + cdc_dmic01_gpios: cdc_dmic01_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic01_clk_active &cdc_dmic01_data_active>; + pinctrl-1 = <&cdc_dmic01_clk_sleep &cdc_dmic01_data_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic23_gpios: cdc_dmic23_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic23_clk_active &cdc_dmic23_data_active>; + pinctrl-1 = <&cdc_dmic23_clk_sleep &cdc_dmic23_data_sleep>; + qcom,lpi-gpios; + }; + + rx_swr_gpios: rx_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&rx_swr_clk_active &rx_swr_data_active + &rx_swr_data1_active>; + pinctrl-1 = <&rx_swr_clk_sleep &rx_swr_data_sleep + &rx_swr_data1_sleep>; + qcom,lpi-gpios; + }; + + va_swr_gpios: va_swr_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&tx_swr_clk_active &tx_swr_data1_active + &tx_swr_data2_active>; + pinctrl-1 = <&tx_swr_clk_sleep &tx_swr_data1_sleep + &tx_swr_data2_sleep>; + qcom,lpi-gpios; + qcom,chip-wakeup-reg = <0x003ca064>; + qcom,chip-wakeup-maskbit = <0>; + qcom,chip-wakeup-default-val = <0x1>; + }; + + wsa881x_analog_clk_gpio: msm_cdc_pinctrl@18 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wsa_mclk_active>; + pinctrl-1 = <&wsa_mclk_sleep>; + qcom,lpi-gpios; + }; +}; + +&q6core { + bolero: bolero-cdc { + compatible = "qcom,bolero-codec"; + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + bolero-clk-rsc-mngr { + compatible = "qcom,bolero-clk-rsc-mngr"; + }; + + va_macro: va-macro@0a730000 { + swr0: va_swr_master { + }; + }; + + rx_macro: rx-macro@0a600000 { + swr1: rx_swr_master { + }; + }; + }; +}; + +&q6core { + scuba_snd: sound { + compatible = "qcom,bengal-asoc-snd"; + qcom,mi2s-audio-intf = <0>; + qcom,auxpcm-audio-intf = <0>; + qcom,tdm-audio-intf = <0>; + qcom,wcn-btfm = <0>; + qcom,afe-rxtx-lb = <0>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&proxy_rx>, <&proxy_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&va_cdc_dma_0_tx>, <&va_cdc_dma_1_tx>, + <&va_cdc_dma_2_tx>, + <&rx_cdc_dma_0_rx>, <&tx_cdc_dma_0_tx>, + <&rx_cdc_dma_1_rx>, <&tx_cdc_dma_1_tx>, + <&rx_cdc_dma_2_rx>, <&tx_cdc_dma_2_tx>, + <&rx_cdc_dma_3_rx>, <&tx_cdc_dma_3_tx>, + <&rx_cdc_dma_4_rx>, <&tx_cdc_dma_4_tx>, + <&rx_cdc_dma_5_rx>, <&tx_cdc_dma_5_tx>, + <&rx_cdc_dma_6_rx>, <&rx_cdc_dma_7_rx>, + <&afe_loopback_tx>; + asoc-cpu-names = "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", + "msm-dai-q6-dev.16401", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-cdc-dma-dev.45089", + "msm-dai-cdc-dma-dev.45091", + "msm-dai-cdc-dma-dev.45093", + "msm-dai-cdc-dma-dev.45104", + "msm-dai-cdc-dma-dev.45105", + "msm-dai-cdc-dma-dev.45106", + "msm-dai-cdc-dma-dev.45107", + "msm-dai-cdc-dma-dev.45108", + "msm-dai-cdc-dma-dev.45109", + "msm-dai-cdc-dma-dev.45110", + "msm-dai-cdc-dma-dev.45111", + "msm-dai-cdc-dma-dev.45112", + "msm-dai-cdc-dma-dev.45113", + "msm-dai-cdc-dma-dev.45114", + "msm-dai-cdc-dma-dev.45115", + "msm-dai-cdc-dma-dev.45116", + "msm-dai-cdc-dma-dev.45118", + "msm-dai-q6-dev.24577"; + fsa4480-i2c-handle = <&fsa4480>; + }; +}; + +&qupv3_se1_i2c { + status = "ok"; + fsa4480: fsa4480@42 { + compatible = "qcom,fsa4480-i2c"; + reg = <0x42>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-bus.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..81217bae444e707e3d4cfd11450439a97ca25cff --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-bus.dtsi @@ -0,0 +1,1007 @@ +#include +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x1880000 0x60200>, + <0x4480000 0x80000>, + <0x1900000 0x8200>, + <0x1880000 0x600>, + <0x1880000 0x60200>, + <0x1880000 0x60200>; + reg-names = "sys_noc-base", "bimc-base", + "config_noc-base", "qup_virt-base", + "mmnrt_virt-base", "mmrt_virt-base"; + + /*Buses*/ + + fab_bimc: fab-bimc { + cell-id = ; + label = "fab-bimc"; + qcom,fab-dev; + qcom,base-name = "bimc-base"; + qcom,bus-type = <2>; + qcom,util-fact = <153>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc BIMC_MSMBUS_CLK>, + <&rpmcc BIMC_MSMBUS_A_CLK>; + }; + + fab_config_noc: fab-config_noc { + cell-id = ; + label = "fab-config_noc"; + qcom,fab-dev; + qcom,base-name = "config_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc CNOC_MSMBUS_CLK>, + <&rpmcc CNOC_MSMBUS_A_CLK>; + }; + + fab_qup_virt: fab-qup_virt { + cell-id = ; + label = "fab-qup_virt"; + qcom,fab-dev; + qcom,base-name = "qup_virt-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc RPM_SMD_QUP_CLK>, + <&rpmcc RPM_SMD_QUP_A_CLK>; + }; + + fab_sys_noc: fab-sys_noc { + cell-id = ; + label = "fab-sys_noc"; + qcom,fab-dev; + qcom,base-name = "sys_noc-base"; + qcom,bus-type = <3>; + qcom,base-offset = <0x15000>; + qcom,qos-off = <0x1000>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc SNOC_MSMBUS_CLK>, + <&rpmcc SNOC_MSMBUS_A_CLK>; + }; + + fab_mmnrt_virt: fab-mmnrt_virt { + cell-id = ; + label = "fab-mmnrt_virt"; + qcom,fab-dev; + qcom,base-name = "mmnrt_virt-base"; + qcom,bus-type = <3>; + qcom,base-offset = <0x15000>; + qcom,qos-off = <0x1000>; + qcom,util-fact = <142>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc CPP_MMNRT_MSMBUS_CLK>, + <&rpmcc CPP_MMNRT_MSMBUS_A_CLK>; + }; + + fab_mmrt_virt: fab-mmrt_virt { + cell-id = ; + label = "fab-mmrt_virt"; + qcom,fab-dev; + qcom,base-name = "mmrt_virt-base"; + qcom,bus-type = <3>; + qcom,base-offset = <0x15000>; + qcom,qos-off = <0x1000>; + qcom,util-fact = <139>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&rpmcc MDP_MMRT_MSMBUS_CLK>, + <&rpmcc MDP_MMRT_MSMBUS_A_CLK>; + }; + + /*Masters*/ + + mas_apps_proc: mas-apps-proc { + cell-id = ; + label = "mas-apps-proc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,util-fact = <159>; + qcom,vrail-comp = <96>; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc RPM_SMD_CPUSS_GNOC_CLK>, + <&rpmcc RPM_SMD_CPUSS_GNOC_A_CLK>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_rt: mas-snoc-bimc-rt { + cell-id = ; + label = "mas-snoc-bimc-rt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc_nrt: mas-snoc-bimc-nrt { + cell-id = ; + label = "mas-snoc-bimc-nrt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <3>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc: mas-snoc-bimc { + cell-id = ; + label = "mas-snoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <6>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_tcu_0: mas-tcu-0 { + cell-id = ; + label = "mas-tcu-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi &slv_bimc_snoc>; + qcom,prio-lvl = <6>; + qcom,prio-rd = <6>; + qcom,prio-wr = <6>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_cnoc: mas-snoc-cnoc { + cell-id = ; + label = "mas-snoc-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_qhs_camera_rt_throttle_cfg + &slv_qhs_sdc2 &slv_qhs_sdc1 + &slv_qhs_qm_cfg &slv_qhs_bimc_cfg + &slv_qhs_usb3 &slv_qhs_qm_mpu_cfg + &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_qdss_cfg &slv_qhs_pdm + &slv_qhs_ipa_cfg &slv_qhs_display_throttle_cfg + &slv_qhs_tcsr &slv_qhs_mesg_ram + &slv_qhs_pmic_arb &slv_qhs_lpass + &slv_qhs_disp_ss_cfg &slv_qhs_venus_cfg + &slv_qhs_gpu_cfg &slv_qhs_imem_cfg + &slv_snoc_cfg &slv_srvc_cnoc + &slv_qhs_venus_throttle_cfg + &slv_qhs_pka_wrapper &slv_qhs_hwkm + &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_qup0 &slv_qhs_camera_ss_cfg + &slv_qhs_clk_ctl &slv_qhs_qpic>; + qcom,bus-dev = <&fab_config_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_dap: mas-xm-dap { + cell-id = ; + label = "mas-xm-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_qhs_camera_rt_throttle_cfg + &slv_qhs_sdc2 &slv_qhs_sdc1 + &slv_qhs_qm_cfg &slv_qhs_bimc_cfg + &slv_qhs_usb3 &slv_qhs_qm_mpu_cfg + &slv_qhs_camera_nrt_throttle_cfg + &slv_qhs_qdss_cfg &slv_qhs_pdm + &slv_qhs_ipa_cfg &slv_qhs_display_throttle_cfg + &slv_qhs_tcsr &slv_qhs_mesg_ram + &slv_qhs_pmic_arb &slv_qhs_lpass + &slv_qhs_disp_ss_cfg &slv_qhs_venus_cfg + &slv_qhs_gpu_cfg &slv_qhs_imem_cfg + &slv_snoc_cfg &slv_srvc_cnoc + &slv_qhs_venus_throttle_cfg + &slv_qhs_pka_wrapper &slv_qhs_hwkm + &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_qup0 &slv_qhs_camera_ss_cfg + &slv_qhs_clk_ctl &slv_qhs_qpic>; + qcom,bus-dev = <&fab_config_noc>; + qcom,mas-rpm-id = ; + }; + + mas_crypto_c0: mas-crypto-c0 { + cell-id = ; + label = "mas-crypto-c0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <22>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc CRYPTO_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc CRYPTO_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qup_core_master_0: mas-qup-core-master-0 { + cell-id = ; + label = "mas-qup-core-master-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qup_core_slave_0>; + qcom,bus-dev = <&fab_qup_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_camera_nrt: mas-qnm-camera-nrt { + cell-id = ; + label = "mas-qnm-camera-nrt"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_snoc_bimc_nrt>; + qcom,prio = <3>; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_camera_rt: mas-qnm-camera-rt { + cell-id = ; + label = "mas-qnm-camera-rt"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <10>; + qcom,qos-mode = "fixed"; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_rt>; + qcom,prio = <3>; + qcom,bus-dev = <&fab_mmrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_mdp0: mas-qxm-mdp0 { + cell-id = ; + label = "mas-qxm-mdp0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <5>; + qcom,qos-mode = "fixed"; + qcom,prio = <3>; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_rt>; + qcom,bus-dev = <&fab_mmrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_venus0: mas-qxm-venus0 { + cell-id = ; + label = "mas-qxm-venus0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <9>; + qcom,qos-mode = "fixed"; + qcom,prio = <3>; + qcom,forwarding; + qcom,connections = <&slv_snoc_bimc_nrt>; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_venus_cpu: mas-qxm-venus-cpu { + cell-id = ; + label = "mas-qxm-venus-cpu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <13>; + qcom,qos-mode = "fixed"; + qcom,prio = <4>; + qcom,connections = <&slv_snoc_bimc_nrt>; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_cfg: mas-snoc-cfg { + cell-id = ; + label = "mas-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qhm_tic: mas-qhm-tic { + cell-id = ; + label = "mas-qhm-tic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + /* QoS priority for snoc_cnoc master */ + qcom,prio = <2>; + qcom,qport = <8>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_snoc_bimc &slv_snoc_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_anoc_snoc: mas-anoc-snoc { + cell-id = ; + label = "mas-anoc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_snoc_bimc + &slv_snoc_cnoc &slv_xs_sys_tcu_cfg + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_bimc_snoc: mas-bimc-snoc { + cell-id = ; + label = "mas-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem &slv_qxs_imem + &slv_qhs_apss &slv_snoc_cnoc + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <20>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_qxs_imem &slv_snoc_bimc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + + mas_qhm_qdss_bam: mas-qhm-qdss-bam { + cell-id = ; + label = "mas-qhm-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qhm_qup0: mas-qhm-qup0 { + cell-id = ; + label = "mas-qhm-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc QUP0_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc QUP0_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <3>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_qdss_etr: mas-xm-qdss-etr { + cell-id = ; + label = "mas-xm-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <12>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_sdc1: mas-xm-sdc1 { + cell-id = ; + label = "mas-xm-sdc1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <17>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc SDC1_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc SDC1_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <23>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + clock-names = "node_clk", "node_a_clk"; + clocks = <&rpmcc SDC2_MSMBUS_SNOC_PERIPH_CLK>, + <&rpmcc SDC2_MSMBUS_SNOC_PERIPH_A_CLK>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qhm_qpic: mas-qhm-qpic { + cell-id = ; + label = "mas-qhm-qpic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,qport = <1>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <24>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_anoc_snoc>; + qcom,prio = <2>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,mas-rpm-id = ; + }; + + mas_qnm_gpu: mas-qnm-gpu { + cell-id = ; + label = "mas-qnm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <1>; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + /*Slaves*/ + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_bimc_snoc:slv-bimc-snoc { + cell-id = ; + label = "slv-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,connections = <&mas_bimc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_bimc_cfg:slv-qhs-bimc-cfg { + cell-id = ; + label = "slv-qhs-bimc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_camera_nrt_throttle_cfg:slv-qhs-camera-nrt-throtle-cfg { + cell-id = ; + label = "slv-qhs-camera-nrt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_camera_rt_throttle_cfg:slv-qhs-camera-rt-throttle-cfg { + cell-id = ; + label = "slv-qhs-camera-rt-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_camera_ss_cfg:slv-qhs-camera-ss-cfg { + cell-id = ; + label = "slv-qhs-camera-ss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_clk_ctl:slv-qhs-clk-ctl { + cell-id = ; + label = "slv-qhs-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_disp_ss_cfg:slv-qhs-disp-ss-cfg { + cell-id = ; + label = "slv-qhs-disp-ss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_display_throttle_cfg:slv-qhs-display-throttle-cfg { + cell-id = ; + label = "slv-qhs-display-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_gpu_cfg:slv-qhs-gpu-cfg { + cell-id = ; + label = "slv-qhs-gpu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_hwkm:slv-qhs-hwkm { + cell-id = ; + label = "slv-qhs-hwkm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_ipa_cfg:slv-qhs-ipa-cfg { + cell-id = ; + label = "slv-qhs-ipa-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_lpass:slv-qhs-lpass { + cell-id = ; + label = "slv-qhs-lpass"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_mesg_ram:slv-qhs-mesg-ram { + cell-id = ; + label = "slv-qhs-mesg-ram"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pdm:slv-qhs-pdm { + cell-id = ; + label = "slv-qhs-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pimem_cfg:slv-qhs-pimem-cfg { + cell-id = ; + label = "slv-qhs-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pka_wrapper:slv-qhs-pka-wrapper { + cell-id = ; + label = "slv-qhs-pka-wrapper"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_pmic_arb:slv-qhs-pmic-arb { + cell-id = ; + label = "slv-qhs-pmic-arb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_prng:slv-qhs-prng { + cell-id = ; + label = "slv-qhs-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qdss_cfg:slv-qhs-qdss-cfg { + cell-id = ; + label = "slv-qhs-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qm_cfg:slv-qhs-qm-cfg { + cell-id = ; + label = "slv-qhs-qm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qm_mpu_cfg:slv-qhs-qm-mpu-cfg { + cell-id = ; + label = "slv-qhs-qm-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qpic:slv-qhs-qpic { + cell-id = ; + label = "slv-qhs-qpic"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_qup0:slv-qhs-qup0 { + cell-id = ; + label = "slv-qhs-qup0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_sdc1:slv-qhs-sdc1 { + cell-id = ; + label = "slv-qhs-sdc1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_sdc2:slv-qhs-sdc2 { + cell-id = ; + label = "slv-qhs-sdc2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cfg:slv-snoc-cfg { + cell-id = ; + label = "slv-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_snoc_cfg>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_usb3:slv-qhs-usb3 { + cell-id = ; + label = "slv-qhs-usb3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_venus_cfg:slv-qhs-venus-cfg { + cell-id = ; + label = "slv-qhs-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_venus_throttle_cfg:slv-qhs-venus-throttle-cfg { + cell-id = ; + label = "slv-qhs-venus-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_vsense_ctrl_cfg:slv-qhs-vsense-ctrl-cfg { + cell-id = ; + label = "slv-qhs-vsense-ctrl-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_config_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qup_core_slave_0:slv-qup-core-slave-0 { + cell-id = ; + label = "slv-qup-core-slave-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_qup_virt>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_nrt:slv-snoc-bimc-nrt { + cell-id = ; + label = "slv-snoc-bimc-nrt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mmnrt_virt>; + qcom,connections = <&mas_snoc_bimc_nrt>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc_rt:slv-snoc-bimc-rt { + cell-id = ; + label = "slv-snoc-bimc-rt"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mmrt_virt>; + qcom,connections = <&mas_snoc_bimc_rt>; + qcom,slv-rpm-id = ; + }; + + slv_qhs_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cnoc:slv-snoc-cnoc { + cell-id = ; + label = "slv-snoc-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,connections = <&mas_snoc_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_qxs_imem:slv-qxs-imem { + cell-id = ; + label = "slv-qxs-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_qxs_pimem:slv-qxs-pimem { + cell-id = ; + label = "slv-qxs-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc:slv-snoc-bimc { + cell-id = ; + label = "slv-snoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,connections = <&mas_snoc_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_xs_qdss_stm:slv-xs-qdss-stm { + cell-id = ; + label = "slv-xs-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_xs_sys_tcu_cfg:slv-xs-sys-tcu-cfg { + cell-id = ; + label = "slv-xs-sys-tcu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_sys_noc>; + qcom,slv-rpm-id = ; + }; + + slv_anoc_snoc:slv-anoc-snoc { + cell-id = ; + label = "slv-anoc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_sys_noc>; + qcom,connections = <&mas_anoc_snoc>; + qcom,slv-rpm-id = ; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-coresight.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bbcb275babfd417839b4d1234d34b3c11d7d93b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-coresight.dtsi @@ -0,0 +1,1497 @@ +&soc { + hwevent { + compatible = "qcom,coresight-hwevent"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + apss_tgu: tgu@9900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x09900000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <8>; + tgu-timer-counters = <8>; + interrupts = <0 53 1>, <0 54 1>, <0 55 1>, <0 56 1>; + coresight-name = "coresight-tgu-apss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + csr: csr@8001000 { + compatible = "qcom,coresight-csr"; + reg = <0x8001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@8a03000 { + compatible = "qcom,coresight-csr"; + reg = <0x8a03000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + + qcom,timestamp-support; + qcom,aodbg-csr-support; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + + stm: stm@8002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb962>; + + reg = <0x8002000 0x1000>, + <0xe280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + tpdm_center: tpdm@8b58000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8b58000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dl_ct_out_tpda0: endpoint { + remote-endpoint = + <&tpda0_in_tpdm_dl_ct>; + }; + }; + }; + + tpdm_gpu: tpdm@8940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8940000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-gpu"; + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_gpu_out_funnel_gpu: endpoint { + remote-endpoint = + <&funnel_gpu_in_tpdm_gpu>; + }; + }; + }; + + modem_rfxe: modem_rfxe { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-modem-rfxe"; + qcom,dummy-source; + + port { + modem_rxfe_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_rxfe>; + }; + }; + }; + + audio_etm0: audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-audio-etm0"; + + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_audio_etm0>; + }; + }; + }; + + tpdm_lpass_lpi: tpdm@8a26000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-lpass-lpi"; + qcom,dummy-source; + + port { + tpdm_lpass_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpdm_lpass>; + }; + }; + }; + + tpdm_vsense: tpdm@8840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_vsense_out_tpda7: endpoint { + remote-endpoint = + <&tpda7_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@8870000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8870000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + qcom,hw-enable-check; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_dcc_out_tpda8: endpoint { + remote-endpoint = + <&tpda8_in_tpdm_dcc>; + }; + }; + }; + + tpdm_prng: tpdm@884c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x884c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_prng_out_tpda10: endpoint { + remote-endpoint = + <&tpda10_in_tpdm_prng>; + }; + }; + }; + + tpdm_qm: tpdm@89d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x89d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_qm_out_tpda12: endpoint { + remote-endpoint = + <&tpda12_in_tpdm_qm>; + }; + }; + }; + + tpdm_west: tpdm@8a58000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8a58000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-west"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_west_out_tpda13: endpoint { + remote-endpoint = + <&tpda13_in_tpdm_west>; + }; + }; + }; + + tpdm_pimem: tpdm@8850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_pimem_out_tpda15: endpoint { + remote-endpoint = + <&tpda15_in_tpdm_pimem>; + }; + }; + }; + + tpdm_mapss: tpdm@8a01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x8a01000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mapss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_mapss_out_tpda_mapss: endpoint { + remote-endpoint = + <&tpda_mapss_in_tpdm_mapss>; + }; + }; + }; + + tpdm_wcss: tpdm@899c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_silver_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpdm_wcss_silver>; + }; + }; + }; + + modem_etm0: modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm0"; + + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + etm0: etm@9040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9040000 0x1000>; + cpu = <&CPU0>; + qcom,tupwr-disable; + coresight-name = "coresight-etm0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm0_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm0>; + }; + }; + }; + + etm1: etm@9140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9140000 0x1000>; + cpu = <&CPU1>; + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm1_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm1>; + }; + }; + }; + + etm2: etm@9240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9240000 0x1000>; + cpu = <&CPU2>; + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm2_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm2>; + }; + }; + }; + + etm3: etm@9340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + reg = <0x9340000 0x1000>; + cpu = <&CPU3>; + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + etm3_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_etm3>; + }; + }; + }; + + tpdm_actpm: tpd@9830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x9830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-actpm"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_actpm_out_tpda_actpm: endpoint { + remote-endpoint = + <&tpda_actpm_in_tpdm_actpm>; + }; + }; + }; + + tpdm_llm_silver: tpdm@98a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x98a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpdm_apss: tpdm@9860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb968>; + reg = <0x9860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = + <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + funnel_apss0: funnel@9800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x9800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_apss0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss0>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss0_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss0>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss0_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss0>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss0_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss0>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss0_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss0>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss0_in_tpda_actpm: endpoint { + slave-mode; + remote-endpoint = + <&tpda_actpm_out_funnel_apss0>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss0_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss0>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss0_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss0>; + }; + }; + + }; + }; + + tpda_actpm: tpda@9832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x9832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-actpm"; + + qcom,tpda-atid = <77>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_actpm_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_tpda_actpm>; + }; + }; + + port@1 { + reg = <0>; + tpda_actpm_in_tpdm_actpm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_actpm_out_tpda_actpm>; + }; + }; + }; + }; + + tpda_apss: tpda@9862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x9862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + + tpda_llm_silver: tpda@98c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x98c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss0: endpoint { + remote-endpoint = + <&funnel_apss0_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpda_mapss: tpda@8a04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x8a04000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-mapss"; + + qcom,tpda-atid = <76>; + qcom,cmb-elem-size = <0 32>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_mapss_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpda_mapss>; + }; + }; + + port@1 { + reg = <0>; + tpda_mapss_in_tpdm_mapss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mapss_out_tpda_mapss>; + }; + }; + }; + }; + + funnel_gpu: funnel@8944000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8944000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gpu"; + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_gpu_out_tpda1: endpoint { + remote-endpoint = + <&tpda1_in_funnel_gpu>; + }; + }; + + port@1 { + reg = <0>; + funnel_gpu_in_tpdm_gpu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_gpu_out_funnel_gpu>; + }; + }; + + }; + }; + + tpda: tpda@8004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb969>; + reg = <0x8004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,dsb-elem-size = <0 32>, + <1 32>, + <5 32>, + <12 32>, + <13 32>, + <15 32>; + qcom,cmb-elem-size = <7 32>, + <8 32>, + <10 32>, + <15 64>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + + port@1 { + reg = <0>; + tpda0_in_tpdm_dl_ct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_ct_out_tpda0>; + }; + }; + + port@2 { + reg = <1>; + tpda1_in_funnel_gpu: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gpu_out_tpda1>; + }; + }; + + port@3 { + reg = <7>; + tpda7_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda7>; + }; + }; + + port@4 { + reg = <8>; + tpda8_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda8>; + }; + }; + + port@5 { + reg = <10>; + tpda10_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda10>; + }; + }; + + port@6 { + reg = <12>; + tpda12_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda12>; + }; + }; + + port@7 { + reg = <13>; + tpda13_in_tpdm_west: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_west_out_tpda13>; + }; + }; + + port@8 { + reg = <15>; + tpda15_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda15>; + }; + }; + + }; + }; + + funnel_qatb: funnel@8005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + + port@2 { + reg = <5>; + funnel_qatb_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <5>; + funnel_qatb_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_qatb>; + }; + }; + }; + }; + + funnel_in0: funnel@8041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = + <&stm_out_funnel_in0>; + }; + }; + + }; + }; + + funnel_in1: funnel@8042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <1>; + funnel_in1_in_tpda_mapss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_mapss_out_funnel_in1>; + }; + }; + + port@2 { + reg = <2>; + funnel_in1_in_modem_rxfe: endpoint { + slave-mode; + remote-endpoint = + <&modem_rxfe_out_funnel_in1>; + }; + }; + + port@3 { + reg = <3>; + funnel_in1_in_tpdm_wcss_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_silver_out_funnel_in1>; + }; + }; + + port@4 { + reg = <4>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + + port@5 { + reg = <6>; + funnel_in1_in_funnel_apss0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss0_out_funnel_in1>; + }; + }; + + }; + }; + + funnel_merg: funnel@8045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb908>; + reg = <0x8045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + + }; + }; + + tmc_etf: tmc@8047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + reg = <0x8047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etf_out_replicator_qdss: endpoint { + remote-endpoint = + <&replicator_qdss_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + + }; + }; + + replicator_qdss: replicator@8046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb909>; + reg = <0x8046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + replicator_qdss_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator_qdss>; + }; + }; + + port@1 { + reg = <0>; + replicator_qdss_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator_qdss>; + }; + }; + + }; + }; + + tmc_etr: tmc@8048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb961>; + reg = <0x8048000 0x1000>, + <0x8064000 0x15000>; + reg-names = "tmc-base","bam-base"; + + coresight-name = "coresight-tmc-etr"; + + iommus = <&apps_smmu 0x0180 0>, + <&apps_smmu 0x0160 0>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + arm,scatter-gather; + + coresight-ctis = <&cti0>; + coresight-csr = <&csr>; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tmc_etr_in_replicator_qdss: endpoint { + slave-mode; + remote-endpoint = + <&replicator_qdss_out_tmc_etr>; + }; + }; + + }; + }; + + cti_cortex_m3: cti@8b30000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8b30000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cortex_m3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_apss_cti0: cti@98e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x98e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_apss_cti1: cti@98f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x98f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_wcss_cti0: cti@89a4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x89a4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss-cti0"; + + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_wcss_cti1: cti@89a5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x89a5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss-cti1"; + + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_wcss_cti2: cti@89a6000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x89a6000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss-cti2"; + + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_lpi: cti@8a21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8a21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass-lpi"; + + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_lpass_q6: cti@8a2b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8a2b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-lpass-q6"; + + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@8833000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8833000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_isdb_gpu: cti@8941000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8941000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-isdb-gpu"; + + status = "disabled"; + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mapss: cti@8a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mapss"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti0: cti@8b59000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8b59000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti1: cti@8b5a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8b5a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti2: cti@8b5b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8b5b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_dlct_cti3: cti@8b5c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8b5c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct-cti3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@8010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1: cti@8011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2: cti@8012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3: cti@8013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti4: cti@8014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti5: cti@8015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti6: cti@8016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti7: cti@8017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti8: cti@8018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti9: cti@8019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x8019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti10: cti@801a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti11: cti@801b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti12: cti@801c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti13: cti@801d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti14: cti@801e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti15: cti@801f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb966>; + reg = <0x801f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-gdsc.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-gdsc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..34a178aaf97722b72c240c0633b1f57934750b96 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-gdsc.dtsi @@ -0,0 +1,111 @@ +&soc { + /* GDSCs in GCC */ + gcc_camss_top_gdsc: qcom,gdsc@1458004 { + compatible = "qcom,gdsc"; + reg = <0x1458004 0x4>; + regulator-name = "gcc_camss_top_gdsc"; + status = "disabled"; + }; + + gcc_usb30_prim_gdsc: qcom,gdsc@141a004 { + compatible = "qcom,gdsc"; + reg = <0x141a004 0x4>; + regulator-name = "gcc_usb30_prim_gdsc"; + status = "disabled"; + }; + + gcc_vcodec0_gdsc: qcom,gdsc@1458098 { + compatible = "qcom,gdsc"; + reg = <0x1458098 0x4>; + regulator-name = "gcc_vcodec0_gdsc"; + status = "disabled"; + }; + + gcc_venus_gdsc: qcom,gdsc@145807c { + compatible = "qcom,gdsc"; + reg = <0x145807c 0x4>; + regulator-name = "gcc_venus_gdsc"; + status = "disabled"; + }; + + hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc: qcom,gdsc@147d074 { + compatible = "qcom,gdsc"; + reg = <0x147d074 0x4>; + regulator-name = "hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc: qcom,gdsc@147d078 { + compatible = "qcom,gdsc"; + reg = <0x147d078 0x4>; + regulator-name = "hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_turing_mmu_tbu1_gdsc: qcom,gdsc@147d060 { + compatible = "qcom,gdsc"; + reg = <0x147d060 0x4>; + regulator-name = "hlos1_vote_turing_mmu_tbu1_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_turing_mmu_tbu0_gdsc: qcom,gdsc@147d07c { + compatible = "qcom,gdsc"; + reg = <0x147d07c 0x4>; + regulator-name = "hlos1_vote_turing_mmu_tbu0_gdsc"; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + /* GDSCs in DISPCC */ + mdss_core_gdsc: qcom,gdsc@5f03000 { + compatible = "qcom,gdsc"; + reg = <0x5f03000 0x4>; + regulator-name = "mdss_core_gdsc"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + status = "disabled"; + }; + + /* GDSCs in GPUCC */ + gpu_cx_hw_ctrl: syscon@5991540 { + compatible = "syscon"; + reg = <0x5991540 0x4>; + }; + + gpu_gx_sw_reset: syscon@5991008 { + compatible = "syscon"; + reg = <0x5991008 0x4>; + }; + + gpu_gx_domain_addr: syscon@5991508 { + compatible = "syscon"; + reg = <0x5991508 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@599106c { + compatible = "qcom,gdsc"; + reg = <0x599106c 0x4>; + regulator-name = "gpu_cx_gdsc"; + hw-ctl-addr = <&gpu_cx_hw_ctrl>; + qcom,no-status-check-on-disable; + status = "disabled"; + }; + + gpu_gx_gdsc: qcom,gdsc@599100c { + compatible = "qcom,gdsc"; + reg = <0x599100c 0x4>; + regulator-name = "gpu_gx_gdsc"; + sw-reset = <&gpu_gx_sw_reset>; + domain-addr = <&gpu_gx_domain_addr>; + qcom,reset-aon-logic; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a6f606c9b111f04ec869199bde6504dc36e127f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-gpu.dtsi @@ -0,0 +1,560 @@ +&soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a702_zap"; + qcom,mas-crypto = <&mas_crypto_c0>; + }; + + gpu_opp_table: gpu-opp-table { + compatible = "operating-points-v2"; + + opp-1123200000 { + opp-hz = /bits/ 64 <1123200000>; + opp-microvolt = ; + }; + + opp-1017600000 { + opp-hz = /bits/ 64 <1017600000>; + opp-microvolt = ; + }; + + opp-921600000 { + opp-hz = /bits/ 64 <921600000>; + opp-microvolt = ; + }; + + opp-844800000 { + opp-hz = /bits/ 64 <844800000>; + opp-microvolt = ; + }; + + opp-672000000 { + opp-hz = /bits/ 64 <672000000>; + opp-microvolt = ; + }; + + opp-537600000 { + opp-hz = /bits/ 64 <537600000>; + opp-microvolt = ; + }; + + opp-355200000 { + opp-hz = /bits/ 64 <355200000>; + opp-microvolt = ; + }; + }; + + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + operating-points-v2 = <&gpu_opp_table>; + }; + + gpu_bw_tbl: gpu-bw-tbl { + compatible = "operating-points-v2"; + + opp-0 { opp-hz = /bits/ 64 < 0 >; }; /* OFF */ + + opp-100 { opp-hz = /bits/ 64 < 762 >; }; /* 1.100 MHz */ + + opp-200 { opp-hz = /bits/ 64 < 1525 >; }; /* 2.200 MHz */ + + opp-300 { opp-hz = /bits/ 64 < 2288 >; }; /* 3.300 MHz */ + + opp-451 { opp-hz = /bits/ 64 < 3440 >; }; /* 4.451 MHz */ + + opp-547 { opp-hz = /bits/ 64 < 4173 >; }; /* 5.547 MHz */ + + opp-681 { opp-hz = /bits/ 64 < 5195 >; }; /* 6.681 MHz */ + + opp-768 { opp-hz = /bits/ 64 < 5859 >; }; /* 7.768 MHz */ + + opp-1017 { opp-hz = /bits/ 64 < 7759 >; }; /* 8.1017 MHz */ + + opp-1353 { opp-hz = /bits/ 64 < 10322 >; }; /* 9.1353 MHz */ + + opp-1555 { opp-hz = /bits/ 64 < 11863 >; }; /* 10.1555 MHz */ + + opp-1804 { opp-hz = /bits/ 64 < 13763 >; }; /* 11.1804 MHz */ + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + operating-points-v2 = <&gpu_bw_tbl>; + }; + + msm_gpu: qcom,kgsl-3d0@5900000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + + reg = <0x5900000 0x90000>, + <0x5961000 0x800>; + reg-names = "kgsl_3d0_reg_memory", "cx_dbgc"; + + interrupts = <0 177 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_3d0_irq"; + + qcom,id = <0>; + qcom,chipid = <0x07000200>; + + qcom,initial-pwrlevel = <6>; + qcom,idle-timeout = <80>; + + qcom,ubwc-mode = <2>; + qcom,min-access-length = <64>; + qcom,highest-bank-bit = <14>; + + /* size in bytes */ + qcom,snapshot-size = <1048576>; + + /* base addr, size */ + qcom,gpu-qdss-stm = <0xe1c0000 0x40000>; + #cooling-cells = <2>; + + clocks = <&gpucc GPU_CC_GX_GFX3D_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_BIMC_GPU_AXI_CLK>, + <&gpucc GPU_CC_AHB_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", + "iface_clk", "mem_iface_clk", "gmu_clk", + "smmu_vote"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + <26 512 0 800000>, /* 1 bus=100 (LOW SVS) */ + <26 512 0 1600000>, /* 2 bus=200 (LOW SVS) */ + <26 512 0 2400000>, /* 3 bus=300 (LOW SVS) */ + <26 512 0 3608000>, /* 4 bus=451 (LOW SVS) */ + <26 512 0 4376000>, /* 5 bus=547 (LOW SVS) */ + <26 512 0 5448000>, /* 6 bus=681 (SVS) */ + <26 512 0 6144000>, /* 7 bus=768 (SVS) */ + <26 512 0 8136000>, /* 8 bus=1017 (SVS_L1) */ + <26 512 0 10824000>, /* 9 bus=1353 (NOM) */ + <26 512 0 12440000>, /* 10 bus=1555 (NOM) */ + <26 512 0 14432000>; /* 11 bus=1804 (TURBO) */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <422>; + qcom,pm-qos-wakeup-latency = <422>; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <5>; + + nvmem-cells = <&gpu_speed_bin>; + nvmem-cell-names = "speed_bin"; + + qcom,gpu-cx-ipeak { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-cx-ipeak"; + + qcom,gpu-cx-ipeak@0 { + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 4>; + qcom,gpu-cx-ipeak-freq = <1017600000>; + }; + }; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-reserved = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-reserved = <32>; + }; + }; + + /* GPU Mempool configuration for low memory SKUs */ + qcom,gpu-mempools-lowmem { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools-lowmem"; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + qcom,mempool-allocate; + }; + /* 8K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <8192>; + qcom,mempool-allocate; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@2 { + reg = <2>; + qcom,mempool-page-size = <65536>; + qcom,mempool-allocate; + qcom,mempool-max-pages = <256>; + }; + /* 1M Page Pool configuration */ + qcom,gpu-mempool@3 { + reg = <3>; + qcom,mempool-page-size = <1048576>; + qcom,mempool-allocate; + qcom,mempool-max-pages = <32>; + }; + }; + + + /* Power Levels + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calculated as FMAX/4.8 MHz round up to zero + * decimal places plus two margin to account for + * clock jitters. + */ + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <6>; + qcom,ca-target-pwrlevel = <5>; + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <1123200000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <1017600000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <921600000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <844800000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <672000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <537600000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <355200000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <236>; + + qcom,initial-pwrlevel = <6>; + qcom,ca-target-pwrlevel = <5>; + + /* TURBO_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <1123200000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <1017600000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <921600000>; + qcom,bus-freq = <10>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <844800000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <672000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <9>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <537600000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <355200000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <178>; + + qcom,initial-pwrlevel = <3>; + qcom,ca-target-pwrlevel = <2>; + + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <844800000>; + qcom,bus-freq = <11>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <672000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <537600000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <8>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <355200000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <142>; + + qcom,initial-pwrlevel = <2>; + qcom,ca-target-pwrlevel = <1>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <672000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <537600000>; + qcom,bus-freq = <7>; + qcom,bus-min = <5>; + qcom,bus-max = <9>; + }; + + /* LOW SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <355200000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@59a0000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x59a0000 0x10000>; + qcom,protect = <0xa0000 0x10000>; + + clocks = <&gcc GCC_BIMC_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>; + + clock-names = "mem_clk", "mem_iface_clk", "smmu_vote"; + + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0 1>; + qcom,iommu-dma = "disabled"; + qcom,gpu-offset = <0xa8000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_secure"; + iommus = <&kgsl_smmu 2 0>; + qcom,iommu-dma = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..6f364904b7aa7544b3d72b1693887058fc839dee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-2gb.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba-low-ram.dtsi" +#include "scuba-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IDP 2GB DDR"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,msm-id = <441 0x10000>; + qcom,board-id = <34 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3aea4f03e6da0d84c23f49a58c56869052dd3727 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IDP"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,msm-id = <441 0x10000>, <471 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..986c783d6ef5157ddb0b7047a328d26df937138c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc-2gb.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +#include "scuba-low-ram.dtsi" +#include "scuba-idp.dtsi" +#include "scuba-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IDP USBC Audio 2GB DDR"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,msm-id = <441 0x10000>; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..6cfc22fc8455c7e33ed06c8fc73101a2aba48f00 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-idp.dtsi" +#include "scuba-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IDP USBC Audio"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,msm-id = <441 0x10000>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc.dts new file mode 100644 index 0000000000000000000000000000000000000000..dc18e1f0c56df49e47aae776a8034e504a7b44a4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba.dtsi" +#include "scuba-idp.dtsi" +#include "scuba-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IDP USBC Audio"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f3495c6da47c469aa524115d4b4c31efadf5c15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp-usbc.dtsi @@ -0,0 +1,14 @@ +&scuba_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; + +&adsp_loader { + adsp-fuse-not-supported = <1>; + adsp-fw-name = "adsp2"; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..c9983ebaad5a180c7e36493b2bb4706ffde2e007 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba.dtsi" +#include "scuba-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IDP"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5b4e4579c821178ad05f50a048137611b9e09b89 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-idp.dtsi @@ -0,0 +1,207 @@ +#include "scuba-audio-overlay.dtsi" +#include "scuba-thermal-overlay.dtsi" +#include +#include +#include "scuba-sde-display.dtsi" +#include "camera/scuba-camera-sensor-idp.dtsi" + +&soc { + scuba_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; +}; + +&pm2250_rg_leds { + status = "ok"; +}; + +&pm2250_qg { + qcom,battery-data = <&scuba_batterydata>; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3500>; + qcom,bass-enable; +}; + +&sdhc_1 { + vdd-supply = <&L20A>; + qcom,vdd-voltage-level = <2856000 2856000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L14A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L21A>; + qcom,vdd-voltage-level = <2960000 3300000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L4A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 88 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pm2250_charger { + interrupts-extended = <&tlmm 89 0>; + interrupt-names = "usb_id_irq"; + qcom,usb-id-gpio = <&tlmm 89 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_interrupt>; + + qcom,auto-recharge-soc = <98>; + qcom,suspend-input-on-debug-batt; + qcom,battery-data = <&scuba_batterydata>; + io-channels = <&pm2250_vadc ADC_USB_IN_V_16>, + <&pm2250_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "chg_temp"; + qcom,thermal-mitigation = <2000000 1500000 1000000 500000>; +}; + +&pm2250_pwm3 { + status = "ok"; +}; + +&dsi_nt36525_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-reset-gpio-always-on; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&dsi_td4330_truly_v2_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&dsi_td4330_truly_v2_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,irq-gpio = <&tlmm 80 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 71 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware_k.img"; + + panel = <&dsi_td4330_truly_v2_video &dsi_td4330_truly_v2_cmd>; + }; +}; + +&qusb_phy0 { + extcon = <&pm2250_charger>; +}; + +&usb0 { + extcon = <&qusb_phy0>, <&eud>; +}; + +&qupv3_se1_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 70 0x00>; + qcom,nq-ven = <&tlmm 69 0x00>; + qcom,nq-firm = <&tlmm 31 0x00>; + qcom,nq-clkreq = <&tlmm 86 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <70 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-ion.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..cba6f834d9d90901c358f7fc689937cc7855cc4b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-ion.dtsi @@ -0,0 +1,35 @@ +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + system_secure_heap: qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..c55d917cbe1ae79b2093d7254cab28466f64ae42 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-2gb.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba-iot-low-ram.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT 2GB DDR SoC"; + compatible = "qcom,scuba-iot"; + qcom,msm-id = <473 0x10000>, <474 0x10000>; + qcom,board-id = <0 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..d4d31bc1209269ee384146b971050ddcd7fe2994 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-2gb.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba-iot-low-ram.dtsi" +#include "scuba-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT IDP 2GB DDR"; + compatible = "qcom,scuba-idp", "qcom,scuba-iot", "qcom,idp"; + qcom,msm-id = <473 0x10000>; + qcom,board-id = <34 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..96adfa675a1c82ce2b12709fb642c9c57cbfc41e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT IDP"; + compatible = "qcom,scuba-idp", "qcom,scuba-iot", "qcom,idp"; + qcom,msm-id = <473 0x10000>, <474 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..e8f6b0e9f8259678a121e20aa00590b20ade1f7e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc-2gb.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +#include "scuba-iot-low-ram.dtsi" +#include "scuba-iot-idp.dtsi" +#include "scuba-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT IDP USBC Audio 2GB DDR"; + compatible = "qcom,scuba-idp", "qcom,scuba-iot", "qcom,idp"; + qcom,msm-id = <473 0x10000>; + qcom,board-id = <34 0x401>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..89f92232e96bc1953851af498ec0f128391d0341 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc-overlay.dts @@ -0,0 +1,13 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-iot-idp.dtsi" +#include "scuba-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT IDP USBC Audio"; + compatible = "qcom,scuba-idp", "qcom,scuba-iot", "qcom,idp"; + qcom,msm-id = <473 0x10000>; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc.dts new file mode 100644 index 0000000000000000000000000000000000000000..7e325044f5d4a0f96e9cc9b50d1c928923dd2b85 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" +#include "scuba-iot-idp.dtsi" +#include "scuba-iot-idp-usbc.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT IDP USBC Audio"; + compatible = "qcom,scuba-idp", "qcom,scuba-iot", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5f3495c6da47c469aa524115d4b4c31efadf5c15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp-usbc.dtsi @@ -0,0 +1,14 @@ +&scuba_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; + +&adsp_loader { + adsp-fuse-not-supported = <1>; + adsp-fw-name = "adsp2"; +}; + +&va_cdc_dma_0_tx { + qcom,msm-dai-is-island-supported = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..0ca687eda35aee5f44c6bb16a44b82f7327c0ff5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" +#include "scuba-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT IDP"; + compatible = "qcom,scuba-idp", "qcom,scuba-iot", "qcom,idp"; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..dc25aa50ac069233b9c60be5becad71933657640 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-idp.dtsi @@ -0,0 +1,208 @@ +#include "scuba-audio-overlay.dtsi" +#include +#include +#include "scuba-thermal-overlay.dtsi" +#include "scuba-sde-display.dtsi" +#include "camera/scuba-camera-sensor-idp.dtsi" + +&soc { + scuba_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; +}; + +&pm2250_rg_leds { + status = "ok"; +}; + + +&pm2250_qg { + qcom,battery-data = <&scuba_batterydata>; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3500>; + qcom,bass-enable; +}; + +&sdhc_1 { + vdd-supply = <&L20A>; + qcom,vdd-voltage-level = <2856000 2856000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L14A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L21A>; + qcom,vdd-voltage-level = <2960000 3300000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L4A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 88 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pm2250_charger { + interrupts-extended = <&tlmm 89 0>; + interrupt-names = "usb_id_irq"; + qcom,usb-id-gpio = <&tlmm 89 0>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb_id_interrupt>; + + qcom,auto-recharge-soc = <98>; + qcom,suspend-input-on-debug-batt; + qcom,battery-data = <&scuba_batterydata>; + io-channels = <&pm2250_vadc ADC_USB_IN_V_16>, + <&pm2250_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "chg_temp"; + qcom,thermal-mitigation = <2000000 1500000 1000000 500000>; +}; + +&pm2250_pwm3 { + status = "ok"; +}; + +&dsi_nt36525_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-reset-gpio-always-on; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&dsi_td4330_truly_v2_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&dsi_td4330_truly_v2_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "okay"; + qcom,i2c-touch-active="novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + status = "ok"; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; + + synaptics_tcm@20 { + compatible = "synaptics,tcm-i2c"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + synaptics,irq-gpio = <&tlmm 80 0x2008>; + synaptics,irq-on-state = <0>; + synaptics,reset-gpio = <&tlmm 71 0x00>; + synaptics,reset-on-state = <0>; + synaptics,reset-active-ms = <20>; + synaptics,reset-delay-ms = <200>; + synaptics,power-delay-ms = <200>; + synaptics,ubl-i2c-addr = <0x20>; + synaptics,extend_report; + synaptics,firmware-name = "synaptics_firmware_k.img"; + + panel = <&dsi_td4330_truly_v2_video &dsi_td4330_truly_v2_cmd>; + }; +}; + +&qusb_phy0 { + extcon = <&pm2250_charger>; +}; + +&usb0 { + extcon = <&qusb_phy0>, <&eud>; +}; + +&qupv3_se1_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 70 0x00>; + qcom,nq-ven = <&tlmm 69 0x00>; + qcom,nq-firm = <&tlmm 31 0x00>; + qcom,nq-clkreq = <&tlmm 86 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <70 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ece705c592fc9d67648147875d27d0e698772361 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-low-ram.dtsi @@ -0,0 +1,47 @@ +#include "scuba-iot.dtsi" +/ { + reserved-memory { + /delete-node/ removed_region@60000000; + /delete-node/ qseecom_region; + /delete-node/ qseecom_ta_region; + /delete-node/ disp_rdump_region@5c000000; + + tz_removed_region: tz_removed_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x100000>; + }; + + pimem_removed_region: pimem_removed_region@60100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60100000 0x0 0x1e00000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + }; +}; + +&soc { + qcom_seecom: qseecom@61800000 { + reg = <0x61800000 0x700000>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + reg = <0x61800000 0x700000>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..67881c44b97b86767ab2ad36ebbbbd4ca3b147f8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-iot-qrd-eldo.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba QRD IOT ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba-iot", "qcom,qrd"; + qcom,msm-id = <473 0x10000>, <474 0x10000>; + qcom,board-id = <0x2000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo.dts new file mode 100644 index 0000000000000000000000000000000000000000..b71ee09e6cc18e03f7f4af11c68e97971f40bd23 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" +#include "scuba-iot-qrd-eldo.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT QRD ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba-iot", "qcom,qrd"; + qcom,board-id = <0x2000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..14431ecca0fac8bb11844788a1c135e86bbf2dee --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-eldo.dtsi @@ -0,0 +1,34 @@ +#include "scuba-iot-qrd.dtsi" +#include +#include + +&pm2250_gpios { + vdd_3p1_en { + vdd_3p1_en_default: vdd_3p1_en_default { + pins = "gpio9"; + function = "normal"; + output-enable; + input-disable; + bias-disable; + qcom,drive-strength = ; + }; + }; +}; + +&soc { + vreg_usb_3p1: vreg_usb_3p1 { + compatible = "regulator-fixed"; + regulator-name = "vreg_usb_3p1"; + regulator-min-microvolt = <3100000>; + regulator-max-microvolt = <3100000>; + pinctrl-names = "default"; + pinctrl-0 = <&vdd_3p1_en_default>; + gpio = <&pm2250_gpios 9 GPIO_ACTIVE_HIGH>; + startup-delay-us = <100>; + enable-active-high; + }; +}; + +&qusb_phy0 { + vdda33-supply = <&vreg_usb_3p1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-non-eldo-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-non-eldo-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..e2025780775927e1126f6389a7108f14afc791fe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-non-eldo-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-iot-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT QRD NON ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba-iot", "qcom,qrd"; + qcom,msm-id = <473 0x10000>, <474 0x10000>; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-non-eldo.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-non-eldo.dts new file mode 100644 index 0000000000000000000000000000000000000000..196801d3be9134856d69425d9714d9a130b96488 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd-non-eldo.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" +#include "scuba-iot-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT QRD NON ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba-iot", "qcom,qrd"; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..446f0d730487435be80fbd9edbb4dee033f1b04c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot-qrd.dtsi @@ -0,0 +1,369 @@ +#include "scuba-audio-overlay.dtsi" +#include +#include +#include "scuba-thermal-overlay.dtsi" +#include "scuba-sde-display.dtsi" +#include "camera/scuba-camera-sensor-idp.dtsi" + +&soc { + scuba_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; +}; + +&pm2250_qg { + qcom,battery-data = <&scuba_batterydata>; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3500>; + qcom,bass-enable; +}; + +&sdhc_1 { + vdd-supply = <&L20A>; + qcom,vdd-voltage-level = <2856000 2856000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L14A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&scuba_snd { + qcom,model = "bengal-scubaqrd-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <0>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "SpkrMono WSA_IN", "AUX", + "TX SWR_MIC0", "ADC1_OUTPUT", + "TX SWR_MIC1", "ADC2_OUTPUT", + "TX SWR_MIC5", "ADC3_OUTPUT", + "TX SWR_MIC0", "VA_TX_SWR_CLK", + "TX SWR_MIC1", "VA_TX_SWR_CLK", + "TX SWR_MIC2", "VA_TX_SWR_CLK", + "TX SWR_MIC3", "VA_TX_SWR_CLK", + "TX SWR_MIC4", "VA_TX_SWR_CLK", + "TX SWR_MIC5", "VA_TX_SWR_CLK", + "TX SWR_MIC6", "VA_TX_SWR_CLK", + "TX SWR_MIC7", "VA_TX_SWR_CLK", + "TX SWR_MIC8", "VA_TX_SWR_CLK", + "TX SWR_MIC9", "VA_TX_SWR_CLK", + "TX SWR_MIC10", "VA_TX_SWR_CLK", + "TX SWR_MIC11", "VA_TX_SWR_CLK", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "TX_AIF1 CAP", "VA_TX_SWR_CLK", + "TX_AIF2 CAP", "VA_TX_SWR_CLK", + "TX_AIF3 CAP", "VA_TX_SWR_CLK", + "VA SWR_MIC0", "ADC1_OUTPUT", + "VA SWR_MIC1", "ADC2_OUTPUT", + "VA SWR_MIC5", "ADC3_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + asoc-codec = <&stub_codec>, <&bolero>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_i2c_e>; + qcom,wsa-aux-dev-prefix = "SpkrMono"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&rouleur_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&bolero>, + <&lpi_tlmm>; +}; + +&sdhc_2 { + vdd-supply = <&L21A>; + qcom,vdd-voltage-level = <2960000 3300000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L4A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 88 GPIO_ACTIVE_HIGH>; + + status = "ok"; +}; + +&pm2250_charger { + qcom,auto-recharge-soc = <98>; + qcom,suspend-input-on-debug-batt; + qcom,battery-data = <&scuba_batterydata>; + io-channels = <&pm2250_vadc ADC_USB_IN_V_16>, + <&pm2250_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "chg_temp"; + qcom,thermal-mitigation = <2000000 1500000 1000000 500000>; +}; + +&pm2250_pwm3 { + status = "ok"; +}; + +&thermal_zones { + quiet-therm-usr { + polling-delay = <5000>; + }; + + quiet-therm-step { + polling-delay-passive = <2000>; + polling-delay = <5000>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + quiet_cpu0_trip: quiet-cpu0-trip { + temperature = <40000>; + hysteresis = <0>; + type = "passive"; + }; + + quiet_modem_trip0: quiet-modem-trip0 { + temperature = <40000>; + hysteresis = <5000>; + type = "passive"; + }; + + quiet_modem_trip1: quiet-modem-trip1 { + temperature = <42000>; + hysteresis = <5000>; + type = "passive"; + }; + + quiet_gpu_trip: quiet-gpu-trip { + temperature = <43000>; + hysteresis = <0>; + type = "passive"; + }; + + quiet_modem_trip2: quiet-modem-trip2 { + temperature = <43000>; + hysteresis = <5000>; + type = "passive"; + }; + + quiet_modem_trip3: quiet-modem-trip3 { + temperature = <50000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + gpu-cdev { + trip = <&quiet_gpu_trip>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT - 3)>; + }; + + cpu0-cdev { + trip = <&quiet_cpu0_trip>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT - 3)>; + }; + + modem-proc-cdev0 { + trip = <&quiet_modem_trip0>; + cooling-device = <&modem_proc 1 1>; + }; + + modem-proc-cdev1 { + trip = <&quiet_modem_trip3>; + cooling-device = <&modem_proc 3 3>; + }; + + modem-pa-cdev0 { + trip = <&quiet_modem_trip1>; + cooling-device = <&modem_pa 1 1>; + }; + + modem-pa-cdev1 { + trip = <&quiet_modem_trip2>; + cooling-device = <&modem_pa 2 2>; + }; + + modem-pa-cdev3 { + trip = <&quiet_modem_trip3>; + cooling-device = <&modem_pa 3 3>; + }; + }; + }; +}; + +&dsi_nt36525_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-reset-gpio-always-on; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "ok"; + qcom,i2c-touch-active = "novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; + +&qusb_phy0 { + extcon = <&pm2250_charger>; + + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc5 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x80 0x04 + 0x9f 0x1c + 0x00 0x18>; +}; + +&usb0 { + extcon = <&qusb_phy0>, <&eud>; +}; + +&qupv3_se1_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 70 0x00>; + qcom,nq-ven = <&tlmm 69 0x00>; + qcom,nq-firm = <&tlmm 31 0x00>; + qcom,nq-clkreq = <&tlmm 86 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <70 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&tlmm { + fpc_reset_int: fpc_reset_int { + fpc_reset_low: reset_low { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + fpc_reset_high: reset_high { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + fpc_int_low: int_low { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + }; +}; + +&soc { + fingerprint: fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <97 0>; + fpc,gpio_rst = <&tlmm 104 0>; + fpc,gpio_irq = <&tlmm 97 0>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&fpc_reset_low>; + pinctrl-1 = <&fpc_reset_high>; + pinctrl-2 = <&fpc_int_low>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-iot.dts new file mode 100644 index 0000000000000000000000000000000000000000..804c12bd9c93d87357444a4450622f246511cd86 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba IOT SoC"; + compatible = "qcom,scuba-iot"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-iot.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-iot.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ae5e6fbad212e9e006119fb32da8badb1d8ad31d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-iot.dtsi @@ -0,0 +1,7 @@ +#include "scuba.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. IOT SCUBA"; + compatible = "qcom,scuba-iot"; + qcom,msm-id = <473 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-low-ram.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-low-ram.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8a6b97e58792b24f1f66927d36618624f8ebd761 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-low-ram.dtsi @@ -0,0 +1,52 @@ +#include "scuba.dtsi" +/ { + reserved-memory { + /delete-node/ secure_display_region; + /delete-node/ removed_region@60000000; + /delete-node/ qseecom_region; + /delete-node/ qseecom_ta_region; + /delete-node/ disp_rdump_region@5c000000; + + tz_removed_region: tz_removed_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x100000>; + }; + + pimem_removed_region: pimem_removed_region@60100000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60100000 0x0 0x1e00000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + }; +}; + +&soc { + qcom_seecom: qseecom@61800000 { + reg = <0x61800000 0x700000>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + reg = <0x61800000 0x700000>; + }; + + qcom,ion { + /delete-node/ qcom,ion-heap@10; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-lpi.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c38cae697d47a197c9ca29c5d59a8f87151d15dc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-lpi.dtsi @@ -0,0 +1,1957 @@ +&q6core { + lpi_tlmm: lpi_pinctrl@0a7c0000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0x0a7c0000 0x0>; + qcom,slew-reg = <0x0a95a000 0x0>; + qcom,num-gpios = <19>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = <0x00000000>, <0x00001000>, + <0x00002000>, <0x00003000>, + <0x00004000>, <0x00005000>, + <0x00006000>, <0x00007000>, + <0x00008000>, <0x00009000>, + <0x0000A000>, <0x0000B000>, + <0x0000C000>, <0x0000D000>, + <0x0000E000>, <0x0000F000>, + <0x00010000>, <0x00011000>, + <0x00012000>; + qcom,lpi-slew-offset-tbl = <0x00000000>, <0x00000002>, + <0x00000004>, <0x00000008>, + <0x0000000A>, <0x0000000C>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000000>, <0x00000000>, + <0x00000014>; + + clock-names = "lpass_audio_hw_vote"; + clocks = <&lpass_audio_hw_vote 0>; + + quat_mi2s_sck { + quat_mi2s_sck_sleep: quat_mi2s_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sck_active: quat_mi2s_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_ws { + quat_mi2s_ws_sleep: quat_mi2s_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_ws_active: quat_mi2s_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sck { + lpi_i2s1_sck_sleep: lpi_i2s1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sck_active: lpi_i2s1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_ws { + lpi_i2s1_ws_sleep: lpi_i2s1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_ws_active: lpi_i2s1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd0 { + lpi_i2s1_sd0_sleep: lpi_i2s1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd0_active: lpi_i2s1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s1_sd1 { + lpi_i2s1_sd1_sleep: lpi_i2s1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s1_sd1_active: lpi_i2s1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sck { + lpi_i2s2_sck_sleep: lpi_i2s2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sck_active: lpi_i2s2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_ws { + lpi_i2s2_ws_sleep: lpi_i2s2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_ws_active: lpi_i2s2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd0 { + lpi_i2s2_sd0_sleep: lpi_i2s2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd0_active: lpi_i2s2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s2_sd1 { + lpi_i2s2_sd1_sleep: lpi_i2s2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s2_sd1_active: lpi_i2s2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_sck { + lpi_i2s3_sck_sleep: lpi_i2s3_sck_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_sck_active: lpi_i2s3_sck_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_ws { + lpi_i2s3_ws_sleep: lpi_i2s3_ws_sleep { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_ws_active: lpi_i2s3_ws_active { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_sd0 { + lpi_i2s3_sd0_sleep: lpi_i2s3_sd0_sleep { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_sd0_active: lpi_i2s3_sd0_active { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_i2s3_sd1 { + lpi_i2s3_sd1_sleep: lpi_i2s3_sd1_sleep { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_i2s3_sd1_active: lpi_i2s3_sd1_active { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sck { + quat_tdm_sck_sleep: quat_tdm_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sck_active: quat_tdm_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_ws { + quat_tdm_ws_sleep: quat_tdm_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_ws_active: quat_tdm_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd0 { + quat_tdm_sd0_sleep: quat_tdm_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd0_active: quat_tdm_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd1 { + quat_tdm_sd1_sleep: quat_tdm_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd1_active: quat_tdm_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd2 { + quat_tdm_sd2_sleep: quat_tdm_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd2_active: quat_tdm_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_tdm_sd3 { + quat_tdm_sd3_sleep: quat_tdm_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_tdm_sd3_active: quat_tdm_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sck { + lpi_tdm1_sck_sleep: lpi_tdm1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sck_active: lpi_tdm1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_ws { + lpi_tdm1_ws_sleep: lpi_tdm1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_ws_active: lpi_tdm1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd0 { + lpi_tdm1_sd0_sleep: lpi_tdm1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd0_active: lpi_tdm1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm1_sd1 { + lpi_tdm1_sd1_sleep: lpi_tdm1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm1_sd1_active: lpi_tdm1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sck { + lpi_tdm2_sck_sleep: lpi_tdm2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sck_active: lpi_tdm2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_ws { + lpi_tdm2_ws_sleep: lpi_tdm2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_ws_active: lpi_tdm2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd0 { + lpi_tdm2_sd0_sleep: lpi_tdm2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd0_active: lpi_tdm2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm2_sd1 { + lpi_tdm2_sd1_sleep: lpi_tdm2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm2_sd1_active: lpi_tdm2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_sck { + lpi_tdm3_sck_sleep: lpi_tdm3_sck_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_sck_active: lpi_tdm3_sck_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_ws { + lpi_tdm3_ws_sleep: lpi_tdm3_ws_sleep { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_ws_active: lpi_tdm3_ws_active { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_sd0 { + lpi_tdm3_sd0_sleep: lpi_tdm3_sd0_sleep { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_sd0_active: lpi_tdm3_sd0_active { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_tdm3_sd1 { + lpi_tdm3_sd1_sleep: lpi_tdm3_sd1_sleep { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_tdm3_sd1_active: lpi_tdm3_sd1_active { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sck { + quat_aux_sck_sleep: quat_aux_sck_sleep { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sck_active: quat_aux_sck_active { + mux { + pins = "gpio0"; + function = "func2"; + }; + + config { + pins = "gpio0"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_ws { + quat_aux_ws_sleep: quat_aux_ws_sleep { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_ws_active: quat_aux_ws_active { + mux { + pins = "gpio1"; + function = "func2"; + }; + + config { + pins = "gpio1"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd0 { + quat_aux_sd0_sleep: quat_aux_sd0_sleep { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd0_active: quat_aux_sd0_active { + mux { + pins = "gpio2"; + function = "func2"; + }; + + config { + pins = "gpio2"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd1 { + quat_aux_sd1_sleep: quat_aux_sd1_sleep { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd1_active: quat_aux_sd1_active { + mux { + pins = "gpio3"; + function = "func2"; + }; + + config { + pins = "gpio3"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd2 { + quat_aux_sd2_sleep: quat_aux_sd2_sleep { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd2_active: quat_aux_sd2_active { + mux { + pins = "gpio4"; + function = "func2"; + }; + + config { + pins = "gpio4"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_sd3 { + quat_aux_sd3_sleep: quat_aux_sd3_sleep { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_sd3_active: quat_aux_sd3_active { + mux { + pins = "gpio5"; + function = "func3"; + }; + + config { + pins = "gpio5"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sck { + lpi_aux1_sck_sleep: lpi_aux1_sck_sleep { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sck_active: lpi_aux1_sck_active { + mux { + pins = "gpio6"; + function = "func2"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_ws { + lpi_aux1_ws_sleep: lpi_aux1_ws_sleep { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_ws_active: lpi_aux1_ws_active { + mux { + pins = "gpio7"; + function = "func2"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd0 { + lpi_aux1_sd0_sleep: lpi_aux1_sd0_sleep { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd0_active: lpi_aux1_sd0_active { + mux { + pins = "gpio8"; + function = "func2"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux1_sd1 { + lpi_aux1_sd1_sleep: lpi_aux1_sd1_sleep { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux1_sd1_active: lpi_aux1_sd1_active { + mux { + pins = "gpio9"; + function = "func2"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sck { + lpi_aux2_sck_sleep: lpi_aux2_sck_sleep { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sck_active: lpi_aux2_sck_active { + mux { + pins = "gpio10"; + function = "func1"; + }; + + config { + pins = "gpio10"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_ws { + lpi_aux2_ws_sleep: lpi_aux2_ws_sleep { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_ws_active: lpi_aux2_ws_active { + mux { + pins = "gpio11"; + function = "func1"; + }; + + config { + pins = "gpio11"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd0 { + lpi_aux2_sd0_sleep: lpi_aux2_sd0_sleep { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd0_active: lpi_aux2_sd0_active { + mux { + pins = "gpio12"; + function = "func2"; + }; + + config { + pins = "gpio12"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux2_sd1 { + lpi_aux2_sd1_sleep: lpi_aux2_sd1_sleep { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux2_sd1_active: lpi_aux2_sd1_active { + mux { + pins = "gpio13"; + function = "func2"; + }; + + config { + pins = "gpio13"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_sck { + lpi_aux3_sck_sleep: lpi_aux3_sck_sleep { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_sck_active: lpi_aux3_sck_active { + mux { + pins = "gpio14"; + function = "func1"; + }; + + config { + pins = "gpio14"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_ws { + lpi_aux3_ws_sleep: lpi_aux3_ws_sleep { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_ws_active: lpi_aux3_ws_active { + mux { + pins = "gpio15"; + function = "func1"; + }; + + config { + pins = "gpio15"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_sd0 { + lpi_aux3_sd0_sleep: lpi_aux3_sd0_sleep { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_sd0_active: lpi_aux3_sd0_active { + mux { + pins = "gpio16"; + function = "func1"; + }; + + config { + pins = "gpio16"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + lpi_aux3_sd1 { + lpi_aux3_sd1_sleep: lpi_aux3_sd1_sleep { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + lpi_aux3_sd1_active: lpi_aux3_sd1_active { + mux { + pins = "gpio17"; + function = "func1"; + }; + + config { + pins = "gpio17"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tx_swr_clk_sleep: tx_swr_clk_sleep { + mux { + pins = "gpio0"; + function = "func1"; + input-enable; + bias-pull-down; + }; + + config { + pins = "gpio0"; + drive-strength = <10>; + }; + }; + + tx_swr_clk_active: tx_swr_clk_active { + mux { + pins = "gpio0"; + function = "func1"; + }; + + config { + pins = "gpio0"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + + tx_swr_data1_sleep: tx_swr_data1_sleep { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <10>; + input-enable; + bias-bus-hold; + }; + }; + + tx_swr_data1_active: tx_swr_data1_active { + mux { + pins = "gpio1"; + function = "func1"; + }; + + config { + pins = "gpio1"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + tx_swr_data2_sleep: tx_swr_data2_sleep { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + tx_swr_data2_active: tx_swr_data2_active { + mux { + pins = "gpio2"; + function = "func1"; + }; + + config { + pins = "gpio2"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + rx_swr_clk_sleep: rx_swr_clk_sleep { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_clk_active: rx_swr_clk_active { + mux { + pins = "gpio3"; + function = "func1"; + }; + + config { + pins = "gpio3"; + drive-strength = <10>; + slew-rate = <3>; + bias-disable; + }; + }; + + rx_swr_data_sleep: rx_swr_data_sleep { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data_active: rx_swr_data_active { + mux { + pins = "gpio4"; + function = "func1"; + }; + + config { + pins = "gpio4"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + rx_swr_data1_sleep: rx_swr_data1_sleep { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <10>; + input-enable; + bias-pull-down; + }; + }; + + rx_swr_data1_active: rx_swr_data1_active { + mux { + pins = "gpio5"; + function = "func1"; + }; + + config { + pins = "gpio5"; + drive-strength = <10>; + slew-rate = <3>; + bias-bus-hold; + }; + }; + + cdc_dmic01_clk_active: dmic01_clk_active { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic01_clk_sleep: dmic01_clk_sleep { + mux { + pins = "gpio6"; + function = "func1"; + }; + + config { + pins = "gpio6"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic01_data_active: dmic01_data_active { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic01_data_sleep: dmic01_data_sleep { + mux { + pins = "gpio7"; + function = "func1"; + }; + + config { + pins = "gpio7"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + cdc_dmic23_clk_active: dmic23_clk_active { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic23_clk_sleep: dmic23_clk_sleep { + mux { + pins = "gpio8"; + function = "func1"; + }; + + config { + pins = "gpio8"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic23_data_active: dmic23_data_active { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic23_data_sleep: dmic23_data_sleep { + mux { + pins = "gpio9"; + function = "func1"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + + wsa_mclk_sleep: wsa_mclk_sleep { + mux { + pins = "gpio18"; + function = "func1"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + }; + }; + + wsa_mclk_active: wsa_mclk_active { + mux { + pins = "gpio18"; + function = "func1"; + }; + + config { + pins = "gpio18"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-pinctrl.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ee398146356cbf1a4a01127889a090af06511ebe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-pinctrl.dtsi @@ -0,0 +1,1138 @@ +&soc { + tlmm: pinctrl@500000 { + compatible = "qcom,scuba-pinctrl"; + reg = <0x500000 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + wakeup-parent = <&wakegpio>; + irqdomain-map = <0 0 &wakegpio 84 0>, + <3 0 &wakegpio 75 0>, + <4 0 &wakegpio 16 0>, + <6 0 &wakegpio 59 0>, + <8 0 &wakegpio 63 0>, + <11 0 &wakegpio 17 0>, + <13 0 &wakegpio 18 0>, + <14 0 &wakegpio 51 0>, + <17 0 &wakegpio 20 0>, + <18 0 &wakegpio 52 0>, + <19 0 &wakegpio 53 0>, + <24 0 &wakegpio 6 0>, + <25 0 &wakegpio 71 0>, + <27 0 &wakegpio 73 0>, + <28 0 &wakegpio 41 0>, + <31 0 &wakegpio 27 0>, + <32 0 &wakegpio 54 0>, + <33 0 &wakegpio 55 0>, + <34 0 &wakegpio 56 0>, + <35 0 &wakegpio 57 0>, + <36 0 &wakegpio 58 0>, + <39 0 &wakegpio 28 0>, + <46 0 &wakegpio 29 0>, + <62 0 &wakegpio 60 0>, + <63 0 &wakegpio 61 0>, + <64 0 &wakegpio 62 0>, + <69 0 &wakegpio 33 0>, + <70 0 &wakegpio 34 0>, + <72 0 &wakegpio 72 0>, + <75 0 &wakegpio 35 0>, + <79 0 &wakegpio 36 0>, + <80 0 &wakegpio 21 0>, + <81 0 &wakegpio 38 0>, + <86 0 &wakegpio 19 0>, + <87 0 &wakegpio 42 0>, + <88 0 &wakegpio 43 0>, + <89 0 &wakegpio 45 0>, + <91 0 &wakegpio 74 0>, + <94 0 &wakegpio 47 0>, + <95 0 &wakegpio 48 0>, + <96 0 &wakegpio 49 0>, + <97 0 &wakegpio 50 0>; + irqdomain-map-pass-thru = <0 0xff>; + irqdomain-map-mask = <0xff 0>; + + qupv3_se4_2uart_pins: qupv3_se4_2uart_pins { + qupv3_se4_2uart_active: qupv3_se4_2uart_active { + mux { + pins = "gpio12", "gpio13"; + function = "qup4"; + }; + + config { + pins = "gpio12", "gpio13"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_2uart_sleep: qupv3_se4_2uart_sleep { + mux { + pins = "gpio12", "gpio13"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio13"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio88"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* WSA speaker reset pin1 */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio106"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio106"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + fsa_usbc_ana_en_n@102 { + fsa_usbc_ana_en: fsa_usbc_ana_en { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + }; + + qupv3_se0_i2c_pins: qupv3_se0_i2c_pins { + qupv3_se0_i2c_active: qupv3_se0_i2c_active { + mux { + pins = "gpio0", "gpio1"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se0_spi_pins: qupv3_se0_spi_pins { + qupv3_se0_spi_active: qupv3_se0_spi_active { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "qup0"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se0_spi_sleep: qupv3_se0_spi_sleep { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup1"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 70 NFC Read Interrupt */ + pins = "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio70"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 70 NFC Read Interrupt */ + pins = "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio70"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 69: Enable 31: Firmware */ + pins = "gpio69", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio69", "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 69: Enable 31: Firmware */ + pins = "gpio69", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio69", "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + + nfc_clk_req_active: nfc_clk_req_active { + /* active state */ + mux { + /* GPIO 86: NFC CLOCK REQUEST */ + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_clk_req_suspend: nfc_clk_req_suspend { + /* sleep state */ + mux { + /* GPIO 86: NFC CLOCK REQUEST */ + pins = "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio86"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + function = "qup1"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio69", "gpio70"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio6", "gpio7", + "gpio71", "gpio80"; + function = "qup2"; + }; + + config { + pins = "gpio6", "gpio7", + "gpio71", "gpio80"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio6", "gpio7", + "gpio71", "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7", + "gpio71", "gpio80"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + qupv3_se3_4uart_pins: qupv3_se3_4uart_pins { + qupv3_se3_default_ctsrtsrx: + qupv3_se3_default_ctsrtsrx { + mux { + pins = "gpio8", "gpio9", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio8", "gpio9", "gpio11"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se3_default_tx: + qupv3_se3_default_tx { + mux { + pins = "gpio10"; + function = "gpio"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se3_ctsrx: qupv3_se3_ctsrx { + mux { + pins = "gpio8", "gpio11"; + function = "qup3"; + }; + + config { + pins = "gpio8", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_rts: qupv3_se3_rts { + mux { + pins = "gpio9"; + function = "qup3"; + }; + + config { + pins = "gpio9"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + qupv3_se3_tx: qupv3_se3_tx { + mux { + pins = "gpio10"; + function = "qup3"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio14", "gpio15"; + function = "qup5"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio14", "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + function = "qup5"; + }; + + config { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio14", "gpio15", + "gpio16", "gpio17"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio82", "gpio105"; + function = "gpio"; + }; + + config { + pins = "gpio82", "gpio105"; + drive-strength = <8>; + bias-disable = <0>; + }; + }; + + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio82", "gpio105"; + function = "gpio"; + }; + + config { + pins = "gpio82", "gpio105"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio81"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio81"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio81"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio81"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio71"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio71"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio80", "gpio71"; + function = "gpio"; + }; + + config { + pins = "gpio80", "gpio71"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pm8008_interrupt: pm8008_interrupt { + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + bias-disable; + input-enable; + }; + }; + + pm8008_active: pm8008_active { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + bias-pull-up; + output-high; + drive-strength = <2>; + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA*/ + pins = "gpio23", "gpio22"; + function = "cci_i2c"; + }; + + config { + pins = "gpio23", "gpio22"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA*/ + pins = "gpio23", "gpio22"; + function = "cci_i2c"; + }; + + config { + pins = "gpio23", "gpio22"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA*/ + pins = "gpio30", "gpio29"; + function = "cci_i2c"; + }; + + config { + pins = "gpio30", "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA*/ + pins = "gpio30", "gpio29"; + function = "cci_i2c"; + }; + + config { + pins = "gpio30", "gpio29"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK 0*/ + mux { + pins = "gpio20"; + function = "cam_mclk"; + }; + + config { + pins = "gpio20"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK 0*/ + mux { + pins = "gpio20"; + function = "cam_mclk"; + }; + + config { + pins = "gpio20"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK 1*/ + mux { + pins = "gpio21"; + function = "cam_mclk"; + }; + + config { + pins = "gpio21"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK 1*/ + mux { + pins = "gpio21"; + function = "cam_mclk"; + }; + + config { + pins = "gpio21"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK 2*/ + mux { + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK 2*/ + mux { + pins = "gpio27"; + function = "cam_mclk"; + }; + + config { + pins = "gpio27"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear0_reset_active: cam_sensor_rear0_reset_active { + /* RESET0 */ + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear0_reset_suspend: cam_sensor_rear0_reset_suspend { + /* RESET0 */ + mux { + pins = "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio18"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear1_reset_active: cam_sensor_rear1_reset_active { + /* RESET1 */ + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear1_reset_suspend: cam_sensor_rear1_reset_suspend { + /* RESET1 */ + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + + cam_sensor_front0_reset_active: cam_sensor_front0_reset_active { + /* RESET0 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front0_reset_suspend: cam_sensor_front0_reset_suspend { + /* RESET0 */ + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_csi_mux_oe_active: cam_sensor_csi_mux_oe_active { + /*CSIMUX_OE*/ + mux { + pins = "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio113"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_csi_mux_oe_suspend: cam_sensor_csi_mux_oe_suspend { + /* CSIMUX_OE */ + mux { + pins = "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio113"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_csi_mux_sel_active: cam_sensor_csi_mux_sel_active { + /*CSIMUX_SEL*/ + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_csi_mux_sel_suspend: cam_sensor_csi_mux_sel_suspend { + /* CSIMUX_SEL */ + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + gpio_vol_up: gpio_vol_up { + mux { + pins = "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio96"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + usb_id_interrupt: usb_id_interrupt { + mux { + pins = "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio89"; + bias-pull-up; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-pm.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..61c13bd3f61e95a9749719e1613325364b51df92 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-pm.dtsi @@ -0,0 +1,85 @@ +&soc { + + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + qcom,use-psci; + #address-cells = <1>; + #size-cells = <0>; + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "l2"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0 { /* D1 */ + reg = <0>; + label = "l2-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <38>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <89>; + }; + + qcom,pm-cluster-level@1 { /* D4 */ + reg = <1>; + label = "l2-rail-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <800>; + qcom,exit-latency-us = <2118>; + qcom,min-residency-us = <7376>; + qcom,min-child-idx = <1>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <49>; + qcom,exit-latency-us = <42>; + qcom,min-residency-us = <91>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <290>; + qcom,exit-latency-us = <376>; + qcom,min-residency-us = <1182>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + + }; + + qcom,rpm-stats@4600000 { + compatible = "qcom,rpm-stats"; + reg = <0x04600000 0x1000>, + <0x04690014 0x4>, + <0x0469001c 0x4>; + reg-names = "phys_addr_base", "offset_addr", + "heap_phys_addrbase"; + qcom,sleep-stats-version = <2>; + }; + + qcom,rpm-master-stats@45f0150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x45f0150 0x5000>; + qcom,masters = "APSS", "MPSS", "ADSP", "CDSP", "TZ"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a9ae201cf6c1ad0ad606569a98b234fbf56c7d13 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-qrd-eldo.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba QRD ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba", "qcom,qrd"; + qcom,msm-id = <441 0x10000>, <471 0x10000>; + qcom,board-id = <0x2000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo.dts new file mode 100644 index 0000000000000000000000000000000000000000..95fdb5c200d7caad2e0aa56c878df52fbfab2cbc --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba.dtsi" +#include "scuba-qrd-eldo.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba QRD ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba", "qcom,qrd"; + qcom,board-id = <0x2000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d3aed547800ef8f5725a6e767abcfae47f8ad5ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-eldo.dtsi @@ -0,0 +1,34 @@ +#include "scuba-qrd.dtsi" +#include +#include + +&pm2250_gpios { + vdd_3p1_en { + vdd_3p1_en_default: vdd_3p1_en_default { + pins = "gpio9"; + function = "normal"; + output-enable; + input-disable; + bias-disable; + qcom,drive-strength = ; + }; + }; +}; + +&soc { + vreg_usb_3p1: vreg_usb_3p1 { + compatible = "regulator-fixed"; + regulator-name = "vreg_usb_3p1"; + regulator-min-microvolt = <3100000>; + regulator-max-microvolt = <3100000>; + pinctrl-names = "default"; + pinctrl-0 = <&vdd_3p1_en_default>; + gpio = <&pm2250_gpios 9 GPIO_ACTIVE_HIGH>; + startup-delay-us = <100>; + enable-active-high; + }; +}; + +&qusb_phy0 { + vdda33-supply = <&vreg_usb_3p1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-non-eldo-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-non-eldo-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..ecb03db1025d44277d337bea93267c9f43fc1438 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-non-eldo-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba QRD NON ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba", "qcom,qrd"; + qcom,msm-id = <441 0x10000>, <471 0x10000>; + qcom,board-id = <0x1000B 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-non-eldo.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-non-eldo.dts new file mode 100644 index 0000000000000000000000000000000000000000..f6df8604a5e061b34620a166df1d01257705b7d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd-non-eldo.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +#include "scuba.dtsi" +#include "scuba-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba QRD NON ELDO"; + compatible = "qcom,scuba-qrd", "qcom,scuba", "qcom,qrd"; + qcom,board-id = <0x1000B 0>; +}; + +&qusb_phy0 { + notifier = <&tlmm 88 GPIO_ACTIVE_HIGH>; + interrupts-extended = <&tlmm 88 GPIO_ACTIVE_HIGH>; + interrupt-names = "notifier_irq"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..317c6ccf9ba1c39763452ebb96ba251eeb9899d0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qrd.dtsi @@ -0,0 +1,369 @@ +#include "scuba-audio-overlay.dtsi" +#include "scuba-thermal-overlay.dtsi" +#include +#include +#include "scuba-sde-display.dtsi" +#include "camera/scuba-camera-sensor-idp.dtsi" + +&soc { + scuba_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "qg-batterydata-alium-3600mah.dtsi" + #include "qg-batterydata-atl466271_3300mAh.dtsi" + }; +}; + +&pm2250_qg { + qcom,battery-data = <&scuba_batterydata>; + qcom,qg-iterm-ma = <150>; + qcom,hold-soc-while-full; + qcom,linearize-soc; + qcom,cl-feedback-on; + qcom,tcss-enable; + qcom,fvss-enable; + qcom,fvss-vbatt-mv = <3500>; + qcom,bass-enable; +}; + +&sdhc_1 { + vdd-supply = <&L20A>; + qcom,vdd-voltage-level = <2856000 2856000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L14A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + status = "ok"; +}; + +&scuba_snd { + qcom,model = "bengal-scubaqrd-snd-card"; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,wcn-btfm = <1>; + qcom,ext-disp-audio-rx = <0>; + qcom,audio-routing = + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "Analog Mic1", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Analog Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Analog Mic3", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "IN1_HPHL", "HPHL_OUT", + "IN2_HPHR", "HPHR_OUT", + "IN3_AUX", "AUX_OUT", + "SpkrMono WSA_IN", "AUX", + "TX SWR_MIC0", "ADC1_OUTPUT", + "TX SWR_MIC1", "ADC2_OUTPUT", + "TX SWR_MIC5", "ADC3_OUTPUT", + "TX SWR_MIC0", "VA_TX_SWR_CLK", + "TX SWR_MIC1", "VA_TX_SWR_CLK", + "TX SWR_MIC2", "VA_TX_SWR_CLK", + "TX SWR_MIC3", "VA_TX_SWR_CLK", + "TX SWR_MIC4", "VA_TX_SWR_CLK", + "TX SWR_MIC5", "VA_TX_SWR_CLK", + "TX SWR_MIC6", "VA_TX_SWR_CLK", + "TX SWR_MIC7", "VA_TX_SWR_CLK", + "TX SWR_MIC8", "VA_TX_SWR_CLK", + "TX SWR_MIC9", "VA_TX_SWR_CLK", + "TX SWR_MIC10", "VA_TX_SWR_CLK", + "TX SWR_MIC11", "VA_TX_SWR_CLK", + "RX_TX DEC0_INP", "TX DEC0 MUX", + "RX_TX DEC1_INP", "TX DEC1 MUX", + "RX_TX DEC2_INP", "TX DEC2 MUX", + "RX_TX DEC3_INP", "TX DEC3 MUX", + "TX_AIF1 CAP", "VA_TX_SWR_CLK", + "TX_AIF2 CAP", "VA_TX_SWR_CLK", + "TX_AIF3 CAP", "VA_TX_SWR_CLK", + "VA SWR_MIC0", "ADC1_OUTPUT", + "VA SWR_MIC1", "ADC2_OUTPUT", + "VA SWR_MIC5", "ADC3_OUTPUT"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + asoc-codec = <&stub_codec>, <&bolero>; + asoc-codec-names = "msm-stub-codec.1", "bolero_codec"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_i2c_e>; + qcom,wsa-aux-dev-prefix = "SpkrMono"; + qcom,codec-max-aux-devs = <1>; + qcom,codec-aux-devs = <&rouleur_codec>; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>, <&bolero>, + <&lpi_tlmm>; +}; + +&sdhc_2 { + vdd-supply = <&L21A>; + qcom,vdd-voltage-level = <2960000 3300000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L4A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 88 GPIO_ACTIVE_HIGH>; + + status = "ok"; +}; + +&pm2250_charger { + qcom,auto-recharge-soc = <98>; + qcom,suspend-input-on-debug-batt; + qcom,battery-data = <&scuba_batterydata>; + io-channels = <&pm2250_vadc ADC_USB_IN_V_16>, + <&pm2250_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "chg_temp"; + qcom,thermal-mitigation = <2000000 1500000 1000000 500000>; +}; + +&pm2250_pwm3 { + status = "ok"; +}; + +&thermal_zones { + quiet-therm-usr { + polling-delay = <5000>; + }; + + quiet-therm-step { + polling-delay-passive = <2000>; + polling-delay = <5000>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + quiet_cpu0_trip: quiet-cpu0-trip { + temperature = <40000>; + hysteresis = <0>; + type = "passive"; + }; + + quiet_modem_trip0: quiet-modem-trip0 { + temperature = <40000>; + hysteresis = <5000>; + type = "passive"; + }; + + quiet_modem_trip1: quiet-modem-trip1 { + temperature = <42000>; + hysteresis = <5000>; + type = "passive"; + }; + + quiet_gpu_trip: quiet-gpu-trip { + temperature = <43000>; + hysteresis = <0>; + type = "passive"; + }; + + quiet_modem_trip2: quiet-modem-trip2 { + temperature = <43000>; + hysteresis = <5000>; + type = "passive"; + }; + + quiet_modem_trip3: quiet-modem-trip3 { + temperature = <50000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + gpu-cdev { + trip = <&quiet_gpu_trip>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT - 3)>; + }; + + cpu0-cdev { + trip = <&quiet_cpu0_trip>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT - 3)>; + }; + + modem-proc-cdev0 { + trip = <&quiet_modem_trip0>; + cooling-device = <&modem_proc 1 1>; + }; + + modem-proc-cdev1 { + trip = <&quiet_modem_trip3>; + cooling-device = <&modem_proc 3 3>; + }; + + modem-pa-cdev0 { + trip = <&quiet_modem_trip1>; + cooling-device = <&modem_pa 1 1>; + }; + + modem-pa-cdev1 { + trip = <&quiet_modem_trip2>; + cooling-device = <&modem_pa 2 2>; + }; + + modem-pa-cdev3 { + trip = <&quiet_modem_trip3>; + cooling-device = <&modem_pa 3 3>; + }; + }; + }; +}; + +&dsi_nt36525_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + pwms = <&pm2250_pwm3 0 0>; + qcom,bl-pmic-pwm-period-usecs = <100>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,platform-reset-gpio = <&tlmm 82 0>; + qcom,platform-reset-gpio-always-on; + qcom,platform-en-gpio = <&tlmm 105 0>; +}; + +&sde_dsi { + qcom,dsi-default-panel = <&dsi_nt36525_truly_video>; +}; + +&qupv3_se2_i2c { + status = "ok"; + qcom,i2c-touch-active = "novatek,NVT-ts"; + + novatek@62 { + compatible = "novatek,NVT-ts"; + reg = <0x62>; + + interrupt-parent = <&tlmm>; + interrupts = <80 0x2008>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + + novatek,reset-gpio = <&tlmm 71 0x00>; + novatek,irq-gpio = <&tlmm 80 0x2008>; + + panel = <&dsi_nt36525_truly_video>; + }; +}; + +&qusb_phy0 { + extcon = <&pm2250_charger>; + + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc5 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x80 0x04 + 0x9f 0x1c + 0x00 0x18>; +}; + +&usb0 { + extcon = <&qusb_phy0>, <&eud>; +}; + +&qupv3_se1_i2c { + status = "ok"; + #address-cells = <1>; + #size-cells = <0>; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 70 0x00>; + qcom,nq-ven = <&tlmm 69 0x00>; + qcom,nq-firm = <&tlmm 31 0x00>; + qcom,nq-clkreq = <&tlmm 86 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <70 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&tlmm { + fpc_reset_int: fpc_reset_int { + fpc_reset_low: reset_low { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + fpc_reset_high: reset_high { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + fpc_int_low: int_low { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + }; +}; + +&soc { + fingerprint: fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + interrupts = <97 0>; + fpc,gpio_rst = <&tlmm 104 0>; + fpc,gpio_irq = <&tlmm 97 0>; + fpc,enable-on-boot; + pinctrl-names = "fpc1020_reset_reset", + "fpc1020_reset_active", + "fpc1020_irq_active"; + pinctrl-0 = <&fpc_reset_low>; + pinctrl-1 = <&fpc_reset_high>; + pinctrl-2 = <&fpc_int_low>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-qupv3.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-qupv3.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3c08b7908772073e1e58c5c45b68b7761c6c9886 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-qupv3.dtsi @@ -0,0 +1,260 @@ +#include + +&soc { + /* QUPv3 SE Instances + * Qup0 0: SE 0 + * Qup0 1: SE 1 + * Qup0 2: SE 2 + * Qup0 3: SE 3 + * Qup0 4: SE 4 + * Qup0 5: SE 5 + */ + + /* QUPv3_0 wrapper instance */ + qupv3_0: qcom,qupv3_0_geni_se@4ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x4ac0000 0x2000>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-bus-ids = + , + ; + qcom,vote-for-bw; + iommus = <&apps_smmu 0xe3 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; + }; + + /* GPI Instance */ + gpi_dma0: qcom,gpi-dma@4a00000 { + compatible = "qcom,gpi-dma"; + #dma-cells = <5>; + reg = <0x4a00000 0x60000>; + reg-names = "gpi-top"; + iommus = <&apps_smmu 0xf6 0x0>; + qcom,max-num-gpii = <10>; + interrupts = , + , + , + , + , + , + , + , + , + ; + qcom,gpii-mask = <0x1f>; + qcom,ev-factor = <2>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; + qcom,gpi-ee-offset = <0x10000>; + status = "ok"; + }; + + /* Debug UART Instance */ + qupv3_se4_2uart: qcom,qup_uart@4a90000 { + compatible = "qcom,msm-geni-console"; + reg = <0x4a90000 0x4000>; + reg-names = "se_phys"; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se4_2uart_active>; + pinctrl-1 = <&qupv3_se4_2uart_sleep>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se0_i2c: i2c@4a80000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a80000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_i2c_active>; + pinctrl-1 = <&qupv3_se0_i2c_sleep>; + dmas = <&gpi_dma0 0 0 3 64 0>, + <&gpi_dma0 1 0 3 64 0>; + dma-names = "tx", "rx"; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se0_spi: spi@4a80000 { + compatible = "qcom,spi-geni"; + reg = <0x4a80000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "se_phys"; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se0_spi_active>; + pinctrl-1 = <&qupv3_se0_spi_sleep>; + dmas = <&gpi_dma0 0 0 1 64 0>, + <&gpi_dma0 1 0 1 64 0>; + dma-names = "tx", "rx"; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se1_i2c: i2c@4a84000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a84000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_i2c_active>; + pinctrl-1 = <&qupv3_se1_i2c_sleep>; + dmas = <&gpi_dma0 0 1 3 64 0>, + <&gpi_dma0 1 1 3 64 0>; + dma-names = "tx", "rx"; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se1_spi: spi@4a84000 { + compatible = "qcom,spi-geni"; + reg = <0x4a84000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "se_phys"; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se1_spi_active>; + pinctrl-1 = <&qupv3_se1_spi_sleep>; + dmas = <&gpi_dma0 0 1 1 64 0>, + <&gpi_dma0 1 1 1 64 0>; + dma-names = "tx", "rx"; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_i2c: i2c@4a88000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a88000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_i2c_active>; + pinctrl-1 = <&qupv3_se2_i2c_sleep>; + dmas = <&gpi_dma0 0 2 3 64 0>, + <&gpi_dma0 1 2 3 64 0>; + dma-names = "tx", "rx"; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se2_spi: spi@4a88000 { + compatible = "qcom,spi-geni"; + reg = <0x4a88000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "se_phys"; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se2_spi_active>; + pinctrl-1 = <&qupv3_se2_spi_sleep>; + dmas = <&gpi_dma0 0 2 1 64 0>, + <&gpi_dma0 1 2 1 64 0>; + dma-names = "tx", "rx"; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + /* HS UART Instance */ + qupv3_se3_4uart: qcom,qup_uart@4a8c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x4a8c000 0x4000>; + reg-names = "se_phys"; + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "active", "sleep"; + pinctrl-0 = <&qupv3_se3_default_ctsrtsrx>, + <&qupv3_se3_default_tx>; + pinctrl-1 = <&qupv3_se3_ctsrx>, <&qupv3_se3_rts>, + <&qupv3_se3_tx>; + pinctrl-2 = <&qupv3_se3_ctsrx>, <&qupv3_se3_rts>, + <&qupv3_se3_tx>; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se5_i2c: i2c@4a94000 { + compatible = "qcom,i2c-geni"; + reg = <0x4a94000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_i2c_active>; + pinctrl-1 = <&qupv3_se5_i2c_sleep>; + dmas = <&gpi_dma0 0 5 3 64 0>, + <&gpi_dma0 1 5 3 64 0>; + dma-names = "tx", "rx"; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + + qupv3_se5_spi: spi@4a94000 { + compatible = "qcom,spi-geni"; + reg = <0x4a94000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "se_phys"; + interrupts = ; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>, + <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&qupv3_se5_spi_active>; + pinctrl-1 = <&qupv3_se5_spi_sleep>; + dmas = <&gpi_dma0 0 5 1 64 0>, + <&gpi_dma0 1 5 1 64 0>; + dma-names = "tx", "rx"; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_0>; + status = "disabled"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3a0319159bbf6abe12021883b8325149d1bd8baa --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-regulator.dtsi @@ -0,0 +1,365 @@ +#include +#include + +&rpm_bus { + /* PM2250 S2 - VDD_CX supply */ + rpm-regulator-smpa2 { + status = "okay"; + qcom,resource-name = "rwcx"; + qcom,resource-id = <0>; + + VDD_CX_LEVEL: + VDD_GFX_LEVEL: + VDD_MSS_LEVEL: + S2A_LEVEL: pm2250_s2_level: regulator-s2-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s2_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + VDD_CX_FLOOR_LEVEL: + VDD_MSS_FLOOR_LEVEL: + S2A_FLOOR_LEVEL: + pm2250_s2_floor_level: regulator-s2-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s2_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + VDD_CX_LEVEL_AO: + VDD_MSS_LEVEL_AO: + S2A_LEVEL_AO: pm2250_s2_level_ao: regulator-s2-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_s2_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + cx_cdev: cx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_CX_FLOOR_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + /* PM2250 L1 - VDD_MX/WCSS_MX supply */ + rpm-regulator-ldoa1 { + status = "okay"; + qcom,resource-name = "rwmx"; + qcom,resource-id = <0>; + + VDD_MX_LEVEL: + L1A_LEVEL: pm2250_l1_level: regulator-l1-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l1_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + VDD_MX_FLOOR_LEVEL: + L1A_FLOOR_LEVEL: + pm2250_l1_floor_level: regulator-l1-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l1_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + VDD_MX_LEVEL_AO: + L1A_LEVEL_AO: pm2250_l1_level_ao: regulator-l1-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l1_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MX_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpm-regulator-smpa3 { + status = "okay"; + S3A: pm2250_s3: regulator-s3 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1662500>; + qcom,init-voltage = <400000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa4 { + status = "okay"; + S4A: pm2250_s4: regulator-s4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2350000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + /* VDD_LPI_CX supply */ + rpm-regulator-ldoa8 { + status = "okay"; + qcom,resource-name = "rwlc"; + qcom,resource-id = <0>; + + VDD_LPI_CX_LEVEL: + L8A_LEVEL: pm2250_l8_level: regulator-l8-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l8_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + }; + + /* VDD_LPI_MX supply */ + rpm-regulator-ldoa9 { + status = "okay"; + qcom,resource-name = "rwlm"; + qcom,resource-id = <0>; + + VDD_LPI_MX_LEVEL: + L9A_LEVEL: pm2250_l9_level: regulator-l9-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm2250_l9_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + }; + + rpm-regulator-ldoa2 { + status = "okay"; + L2A: pm2250_l2: regulator-l2 { + regulator-min-microvolt = <1060000>; + regulator-max-microvolt = <1300000>; + qcom,init-voltage = <1060000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa3 { + status = "okay"; + L3A: pm2250_l3: regulator-l3 { + regulator-min-microvolt = <570000>; + regulator-max-microvolt = <650000>; + qcom,init-voltage = <570000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa4 { + status = "okay"; + L4A: pm2250_l4: regulator-l4 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3050000>; + qcom,init-voltage = <1650000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa5 { + status = "okay"; + L5A: pm2250_l5: regulator-l5 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1312000>; + qcom,init-voltage = <1100000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + L6A: pm2250_l6: regulator-l6 { + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <488000>; + status = "okay"; + }; + }; + + /* WCSS_CX */ + rpm-regulator-ldoa7 { + status = "okay"; + WCSS_CX: + L7A: pm2250_l7: regulator-l7 { + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <728000>; + qcom,init-voltage = <400000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + L10A: pm2250_l10: regulator-l10 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1380000>; + qcom,init-voltage = <1150000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + L11A: pm2250_l11: regulator-l11 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1150000>; + qcom,init-voltage = <950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + L12A: pm2250_l12: regulator-l12 { + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <488000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + L13A: pm2250_l13: regulator-l13 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; + qcom,init-voltage = <1650000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa14 { + status = "okay"; + L14A: pm2250_l14: regulator-l14 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1950000>; + qcom,init-voltage = <1700000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa15 { + status = "okay"; + L15A: pm2250_l15: regulator-l15 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2000000>; + qcom,init-voltage = <1200000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa16 { + status = "okay"; + L16A: pm2250_l16: regulator-l16 { + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1950000>; + qcom,init-voltage = <1500000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa17 { + status = "okay"; + L17A: pm2250_l17: regulator-l17 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <3000000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa18 { + status = "okay"; + L18A: pm2250_l18: regulator-l18 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1620000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa19 { + status = "okay"; + L19A: pm2250_l19: regulator-l19 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <1620000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa20 { + status = "okay"; + L20A: pm2250_l20: regulator-l20 { + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <2400000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa21 { + status = "okay"; + L21A: pm2250_l21: regulator-l21 { + regulator-min-microvolt = <2921000>; + regulator-max-microvolt = <3300000>; + qcom,init-voltage = <2921000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa22 { + status = "okay"; + L22A: pm2250_l22: regulator-l22 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <3400000>; + qcom,init-voltage = <2850000>; + status = "okay"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-rumi-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-rumi-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..9b225cfaca0b9fc7de22703724436f06aec587ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-rumi-overlay.dts @@ -0,0 +1,12 @@ +/dts-v1/; +/plugin/; + +#include +#include "scuba-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba RUMI"; + compatible = "qcom,scuba-rumi", "qcom,scuba", "qcom,rumi"; + qcom,msm-id = <441 0x10000>; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-rumi.dts b/arch/arm64/boot/dts/vendor/qcom/scuba-rumi.dts new file mode 100644 index 0000000000000000000000000000000000000000..0562b208e012218e696085388fd300a0392f15f1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-rumi.dts @@ -0,0 +1,11 @@ +/dts-v1/; +/memreserve/ 0x90000000 0x00000100; + +#include "scuba.dtsi" +#include "scuba-rumi.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba RUMI"; + compatible = "qcom,scuba-rumi", "qcom,scuba", "qcom,rumi"; + qcom,board-id = <15 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-rumi.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-rumi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8ccef09607192267948b29e4e7d4401ee16fb9b4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-rumi.dtsi @@ -0,0 +1,111 @@ +&soc { + timer { + clock-frequency = <500000>; + }; + + timer@f120000 { + clock-frequency = <500000>; + }; + + wdog: qcom,wdt@f017000 { + status = "disabled"; + }; + + usb_emu_phy: usb_emu_phy@4f20000 { + compatible = "qcom,usb-emu-phy"; + reg = <0x04f20000 0x9500>, + <0x04ef8800 0x100>; + reg-names = "base", "qscratch_base"; + + qcom,emu-init-seq = <0xffff 0x4 + 0xfff0 0x4 + 0x100000 0x20 + 0x0 0x20 + 0x101f0 0x20 + 0x100000 0x3c + 0x0 0x3c + 0x10060 0x3c + 0x0 0x4>; + }; + + bi_tcxo: bi_tcxo { + compatible = "fixed-factor-clock"; + clock-mult = <1>; + clock-div = <2>; + clocks = <&xo_board>; + #clock-cells = <0>; + }; + + bi_tcxo_ao: bi_tcxo_ao { + compatible = "fixed-factor-clock"; + clock-mult = <1>; + clock-div = <2>; + clocks = <&xo_board>; + #clock-cells = <0>; + }; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&usb_emu_phy>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + dr_mode = "peripheral"; + }; +}; + +&sdhc_1 { + vdd-supply = <&L19A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&L14A>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on + &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off + &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "DDR_1p8v"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&L21A>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 800000>; + + vdd-io-supply = <&L4A>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50"; + + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; +}; + +&rpmcc { + compatible = "qcom,dummycc"; + clock-output-names = "rpmcc_clocks"; + #clock-cells = <1>; + #reset-cells = <1>; +}; + +&qupv3_se1_i2c { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-sde-display.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-sde-display.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f6135d2aa43f0144917431b2be89a237bc7cfd5a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-sde-display.dtsi @@ -0,0 +1,209 @@ +#include +#include "dsi-panel-nt36525-truly-hd-plus-vid.dtsi" +#include "dsi-panel-td4330-truly-v2-singlemipi-fhd-vid.dtsi" +#include "dsi-panel-td4330-truly-v2-singlemipi-fhd-cmd.dtsi" + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <2000000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <2000000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + }; + + dsi_panel_pwr_supply_labibb_amoled: dsi_panel_pwr_supply_labibb_amoled { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <2000000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdda-3p3"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <13200>; + qcom,supply-disable-load = <80>; + }; + }; + + sde_dsi: qcom,dsi-display-primary { + compatible = "qcom,dsi-display"; + label = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + + clocks = <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 81 0>; + qcom,panel-te-source = <0>; + vddio-supply = <&L15A>; + qcom,mdp = <&mdss_mdp>; + + qcom,dsi-default-panel = + <&dsi_nt36525_truly_video>; + }; +}; + +&mdss_mdp { + connectors = <&sde_dsi>; +}; + +&dsi_nt36525_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0a>; + qcom,mdss-dsi-t-clk-pre = <0x21>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,dsi-supported-dfps-list = <60 55 48>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,dsi-dyn-clk-enable; + qcom,dsi-dyn-clk-list = + <502087680 504179712 506271744 508363776>; + qcom,dsi-dyn-clk-type = "constant-fps-adjust-vfp"; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [1F 1B 05 06 03 02 04 a0 + 1F 1B 05 06 03 02 04 a0 + 1F 1B 05 06 03 02 04 a0 + 1F 1B 05 06 03 02 04 a0 + 1F 10 04 06 03 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_td4330_truly_v2_video { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0", + "src_byte_clk0", "src_pixel_clk0", + "shadow_byte_clk0", "shadow_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 1F 09 0A 06 03 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = + [26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 1F 09 0B 06 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_td4330_truly_v2_cmd { + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = + [26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 20 09 0B 06 02 04 a0 + 26 1F 09 0B 06 02 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <40 40 40 40 40 40>; + }; + + timing@1 { + qcom,mdss-dsi-panel-phy-timings = + [25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 20 09 0A 06 03 04 a0 + 25 1F 09 0A 06 03 04 a0]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-sde-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-sde-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..72e4bc6659e05289c16a6791733b7cf09fb6d0fd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-sde-pll.dtsi @@ -0,0 +1,32 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi0_pll { + compatible = "qcom,mdss_dsi_pll_14nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0x5e94400 0x588>, + <0x5f03000 0x8>, + <0x5e94200 0x100>; + reg-names = "pll_base", "gdsc_base", + "dynamic_pll_base"; + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + memory-region = <&dfps_data_memory>; + gdsc-supply = <&mdss_core_gdsc>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-sde.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-sde.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..957b9bdb22a0638349496b3cb293b62deacfb840 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-sde.dtsi @@ -0,0 +1,312 @@ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp { + compatible = "qcom,sde-kms"; + reg = <0x5e00000 0x8f030>, + <0x5eb0000 0x2008>, + <0x5e8f000 0x02c>, + <0xc125ba4 0x20>; + reg-names = "mdp_phys", + "vbif_phys", + "sid_phys", + "sde_imem_phys"; + + clocks = + <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&gcc GCC_DISP_THROTTLE_CORE_CLK>, + <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>; + clock-names = "gcc_iface", "gcc_bus", "throttle_clk", + "div_clk", + "iface_clk", "core_clk", "vsync_clk", + "lut_clk"; + clock-rate = <0 0 0 0 0 256000000 19200000 192000000>; + clock-max-rate = <0 0 0 0 0 384000000 19200000 384000000>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x494>; + + qcom,sde-ctl-off = <0x2000>; + qcom,sde-ctl-size = <0x1dc>; + qcom,sde-ctl-display-pref = "primary"; + + qcom,sde-mixer-off = <0x45000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0x80>; + qcom,sde-dspp-off = <0x55000>; + qcom,sde-dspp-size = <0xfe4>; + + qcom,sde-intf-off = <0x0 0x6b800>; + qcom,sde-intf-size = <0x2b8>; + qcom,sde-intf-type = "none", "dsi"; + + qcom,sde-pp-off = <0x71000>; + qcom,sde-pp-size = <0xd4>; + + qcom,sde-dither-off = <0x30e0>; + qcom,sde-dither-version = <0x00010000>; + qcom,sde-dither-size = <0x20>; + + qcom,sde-sspp-type = "vig", "dma"; + + qcom,sde-sspp-off = <0x5000 0x25000>; + qcom,sde-sspp-src-size = <0x1f8>; + + qcom,sde-sspp-xin-id = <0 1>; + qcom,sde-sspp-excl-rect = <1 1>; + qcom,sde-sspp-smart-dma-priority = <2 1>; + qcom,sde-smart-dma-rev = "smart_dma_v2p5"; + + qcom,sde-mixer-pair-mask = <0>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + qcom,sde-mixer-stage-base-layer; + + qcom,sde-max-per-pipe-bw-kbps = <2700000 2700000>; + + qcom,sde-max-per-pipe-bw-high-kbps = <2700000 2700000>; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-sspp-clk-ctrl = + <0x2ac 0>, <0x2ac 8>; + qcom,sde-mixer-linewidth = <2048>; + qcom,sde-mixer-blendstages = <0x4>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + + qcom,sde-max-bw-low-kbps = <2700000>; + qcom,sde-max-bw-high-kbps = <2700000>; + qcom,sde-min-core-ib-kbps = <1300000>; + qcom,sde-min-llcc-ib-kbps = <0>; + qcom,sde-min-dram-ib-kbps = <1600000>; + qcom,sde-dram-channels = <2>; + qcom,sde-num-nrt-paths = <0>; + + qcom,sde-vbif-off = <0>; + qcom,sde-vbif-size = <0x2008>; + qcom,sde-vbif-id = <0>; + qcom,sde-vbif-memtype-0 = <3 3 3 3 3 3 3 3>; + qcom,sde-vbif-memtype-1 = <3 3 3 3 3 3>; + + qcom,sde-vbif-qos-rt-remap = <3 3 4 4 5 5 6 6>; + + /*Pending macrotile & macrotile-qseed has the same configs */ + + qcom,sde-danger-lut = <0x000000ff 0x00000000 + 0x00000000 0x00000000 0x00000000>; + + qcom,sde-safe-lut-linear = <0 0xfff0>; + + qcom,sde-qos-lut-linear = <0 0x00112222 0x22335777>; + + qcom,sde-cdp-setting = <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + qcom,sde-secure-sid-mask = <0x0000421>; + qcom,sde-num-mnoc-ports = <1>; + qcom,sde-axi-bus-width = <16>; + + qcom,sde-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-dither = <0x82c 0x00010007>; + }; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "sde-vdd"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0x420 0x2>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-earlymap; /* for cont-splash */ + }; + + smmu_sde_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x421 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; + }; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "mdss_sde"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 4800000>, + <22 512 0 4800000>; + }; + + qcom,sde-reg-bus { + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + + qcom,sde-limits { + qcom,sde-linewidth-limits { + qcom,sde-limit-name = "sspp_linewidth_usecases"; + qcom,sde-limit-cases = "vig", "dma"; + qcom,sde-limit-ids= <0x1 0x2>; + qcom,sde-limit-values = <0x1 2160>, + <0x2 2160>; + }; + + qcom,sde-bw-limits { + qcom,sde-limit-name = "sde_bwlimit_usecases"; + qcom,sde-limit-cases = "per_vig_pipe", + "per_dma_pipe", + "total_max_bw", + "camera_concurrency"; + qcom,sde-limit-ids = <0x1 0x2 0x4 0x8>; + qcom,sde-limit-values = <0x1 2700000>, + <0x9 2700000>, + <0x2 2700000>, + <0xa 2700000>, + <0x4 2700000>, + <0xc 2700000>; + }; + }; + }; + + mdss_dsi0: qcom,mdss_dsi0_ctrl { + compatible = "qcom,dsi-ctrl-hw-v2.4"; + label = "dsi-ctrl-0"; + cell-index = <0>; + reg = <0x5e94000 0x400>, + <0x5f08000 0x4>; + reg-names = "dsi_ctrl", "disp_cc_base"; + interrupt-parent = <&mdss_mdp>; + interrupts = <4 0>; + vdda-1p2-supply = <&L5A>; + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>; + clock-names = "byte_clk", "byte_clk_rcg", "byte_intf_clk", + "pixel_clk", "pixel_clk_rcg", + "esc_clk"; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1232000>; + qcom,supply-max-voltage = <1312000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0 { + compatible = "qcom,dsi-phy-v2.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0x5e94400 0x588>, + <0x5e01400 0x100>, + <0x5e94200 0x100>; + reg-names = "dsi_phy", "phy_clamp_base", + "dyn_refresh_base"; + vdda-0p9-supply = <&VDD_MX_LEVEL>; + qcom,platform-strength-ctrl = [ff 06 + ff 06 + ff 06 + ff 06 + ff 00]; + qcom,platform-lane-config = [00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 8f]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,panel-allow-phy-poweroff; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = + ; + qcom,supply-max-voltage = + ; + qcom,supply-off-min-voltage = + ; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-stub-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-stub-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a17cdda965115d804ab8dfa7deac5cb425cac82b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-stub-regulator.dtsi @@ -0,0 +1,235 @@ +#include + +&soc { + VDD_CX_LEVEL: + S2A_LEVEL: pm2250_s2_level: regulator-pm2250-s2-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_s2_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + VDD_CX_LEVEL_AO: + S2A_LEVEL_AO: pm2250_s2_level_ao: regulator-pm2250-s2-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_s2_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + cx_cdev: cx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_CX_LEVEL_AO>; + regulator-levels = ; + #cooling-cells = <2>; + }; + + VDD_MX_LEVEL: + L1A_LEVEL: pm2250_l1_level: regulator-pm2250-l1-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l1_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + VDD_MX_LEVEL_AO: + L1A_LEVEL_AO: pm2250_l1_level_ao: regulator-pm2250-l1-level-ao { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l1_level_ao"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&VDD_MX_LEVEL>; + regulator-levels = ; + #cooling-cells = <2>; + }; + + S4A: pm2250_s4: regulator-pm2250-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_s4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <110000>; + regulator-max-microvolt = <2350000>; + }; + + VDD_LPI_CX_LEVEL: + L8A_LEVEL: pm2250_l8_level: regulator-pm2250-l8-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l8_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + VDD_LPI_MX_LEVEL: + L9A_LEVEL: pm2250_l9_level: regulator-pm2250-l9-level { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l9_level"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + L2A: pm2250_l2: regulator-pm2250-l2 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l2"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1060000>; + regulator-max-microvolt = <1300000>; + }; + + L3A: pm2250_l3: regulator-pm2250-l3 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l3"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <570000>; + regulator-max-microvolt = <650000>; + }; + + L4A: pm2250_l4: regulator-pm2250-l4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l4"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3050000>; + }; + + L5A: pm2250_l5: regulator-pm2250-l5 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l5"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1312000>; + }; + + L6A: pm2250_l6: regulator-pm2250-l6 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l6"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <1000000>; + }; + + /* WCSS_CX */ + L7A: pm2250_l7: regulator-pm2250-l7 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l7"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <728000>; + }; + + L10A: pm2250_l10: regulator-pm2250-l10 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l10"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1380000>; + }; + + L11A: pm2250_l11: regulator-pm2250-l11 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l11"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1150000>; + }; + + L12A: pm2250_l12: regulator-pm2250-l12 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l12"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <488000>; + regulator-max-microvolt = <1000000>; + }; + + L13A: pm2250_l13: regulator-pm2250-l13 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l13"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1950000>; + }; + + L14A: pm2250_l14: regulator-pm2250-l14 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l14"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1950000>; + }; + + L15A: pm2250_l15: regulator-pm2250-l15 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l15"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2000000>; + }; + + L16A: pm2250_l16: regulator-pm2250-l16 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l16"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1950000>; + }; + + L17A: pm2250_l17: regulator-pm2250-l17 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l17"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3600000>; + }; + + L18A: pm2250_l18: regulator-pm2250-l18 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l18"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + L19A: pm2250_l19: regulator-pm2250-l19 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l19"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + }; + + L20A: pm2250_l20: regulator-pm2250-l20 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l20"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3600000>; + }; + + L21A: pm2250_l21: regulator-pm2250-l21 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l21"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <2921000>; + regulator-max-microvolt = <3300000>; + }; + + L22A: pm2250_l22: regulator-pm2250-l22 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm2250_l22"; + qcom,hpm-min-load = <10000>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-thermal-overlay.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-thermal-overlay.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a2039b5bcb7e01b5db15b8853d6dc62c78952111 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-thermal-overlay.dtsi @@ -0,0 +1,54 @@ +#include + +&thermal_zones { + pm2250-tz { + cooling-maps { + trip0_cpu0 { + trip = <&pm2250_trip0>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu1 { + trip = <&pm2250_trip1>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + trip1_cpu2 { + trip = <&pm2250_trip1>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + trip1_cpu3 { + trip = <&pm2250_trip1>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + soc { + cooling-maps { + soc_cpu0 { + trip = <&pm2250_low_soc>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + soc_cpu2 { + trip = <&pm2250_low_soc>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + soc_cpu3 { + trip = <&pm2250_low_soc>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-thermal.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6123f3ced7e4bc930bdd5d2b62b2c594e710b14e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-thermal.dtsi @@ -0,0 +1,661 @@ +#include +#include + +&cpufreq_hw { + #address-cells = <1>; + #size-cells = <1>; + lmh_dcvs0: qcom,limits-dcvs@f550800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + reg = <0xf550800 0x1000>, + <0xf521000 0x1000>; + qcom,no-cooling-device-register; + }; + + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + }; +}; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = ; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + + modem_wlan: modem_wlan { + qcom,qmi-dev-name = "wlan"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = ; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; + + lmh_cpu_vdd: qcom,lmh-cpu-vdd@f550800 { + compatible = "qcom,lmh-cpu-vdd"; + reg = <0xf550800 0x1000>; + #cooling-cells = <2>; + }; + + cxip_cdev: cxip-cdev@3ed000 { + compatible = "qcom,cxip-lm-cooling-device"; + reg = <0x3ed000 0xc008>; + qcom,thermal-client-offset = <0x8000>; + /* 4th offset to bypass VICTIM1 */ + qcom,bypass-client-list = <0x3004 0x4004 0x6004 0xc004>; + #cooling-cells = <2>; + }; +}; + +&thermal_zones { + mapss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + wlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + hm-center-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + xo-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_AMUX_THM2_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + msm-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_AMUX_THM3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + chg-skin-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_GPIO3_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + conn-therm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_GPIO4_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + s3-die-temp-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm2250_adc_tm_iio ADC_SBUx>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + trips { + gpu_cxip_trip: gpu-cxip-trip { + temperature = <95000>; + hysteresis = <20000>; + type = "passive"; + }; + + gpu_step_trip: gpu-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + gpu_cx_mon: gpu-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + + }; + + cooling-maps { + cxip-cdev { + trip = <&gpu_cxip_trip>; + cooling-device = <&cxip_cdev 1 1>; + }; + + gpu_cdev { + trip = <&gpu_step_trip>; + cooling-device = <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + + gpu-cx-cdev0 { + trip = <&gpu_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + gpu-cx-cdev1 { + trip = <&gpu_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + gpu-cx-cdev2 { + trip = <&gpu_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + }; + }; + + cpuss-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + + trips { + cpu0_2_config: cpu-0-2-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu0_cdev { + trip = <&cpu0_2_config>; + cooling-device = <&cpu0_isolate 1 1>; + }; + + cpu2_cdev { + trip = <&cpu0_2_config>; + cooling-device = <&cpu2_isolate 1 1>; + }; + }; + }; + + cpuss-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + + trips { + cpu1_3_config: cpu-1-3-config { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu1_cdev { + trip = <&cpu1_3_config>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + cpu3_cdev { + trip = <&cpu1_3_config>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + mdm-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + trips { + mdm0_cx_mon: mdm0-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm0-cx-cdev0 { + trip = <&mdm0_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + mdm0-cx-cdev1 { + trip = <&mdm0_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + mdm0-cx-cdev2 { + trip = <&mdm0_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + }; + }; + + mdm-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + trips { + mdm1_cx_mon: mdm1-cx-mon { + temperature = <100000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + mdm1-cx-cdev0 { + trip = <&mdm1_cx_mon>; + cooling-device = <&msm_gpu THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + mdm1-cx-cdev1 { + trip = <&mdm1_cx_mon>; + cooling-device = <&modem_proc 3 3>; + }; + + mdm1-cx-cdev2 { + trip = <&mdm1_cx_mon>; + cooling-device = <&modem_pa 3 3>; + }; + }; + }; + + mapss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + + trips { + mapss_trip: mapss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cx_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + + mx_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + + modem_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + + adsp_vdd_cdev { + trip = <&mapss_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + }; + }; + + mapss-lowc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + + trips { + mapss_cap_trip: mapss-cap-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + lmh_cpu_cdev { + trip = <&mapss_cap_trip>; + cooling-device = <&lmh_cpu_vdd 1 1>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-usb.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-usb.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..819e7442f9546948de4c4cb5265c98879b9d1cf7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-usb.dtsi @@ -0,0 +1,321 @@ +#include +#include +#include + +&soc { + /* Primary USB port related controller */ + usb0: ssusb@4e00000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x4e00000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x0120 0x0>; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x50000000 0x60000000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = , + , + ; + interrupt-names = "pwr_event_irq", "ss_phy_irq", "hs_phy_irq"; + + clocks = <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "xo", "sleep_clk", "utmi_clk"; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + USB3_GDSC-supply = <&gcc_usb30_prim_gdsc>; + dpdm-supply = <&qusb_phy0>; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,gsi-reg-offset = + <0x0fc /* GSI_GENERAL_CFG */ + 0x110 /* GSI_DBL_ADDR_L */ + 0x120 /* GSI_DBL_ADDR_H */ + 0x130 /* GSI_RING_BASE_ADDR_L */ + 0x144 /* GSI_RING_BASE_ADDR_H */ + 0x1a4>; /* GSI_IF_STS */ + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,gsi-disable-io-coherency; + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + , + , + + /* nominal vote */ + , + , + , + + /* svs vote */ + , + , + , + + /* min vote */ + , + , + ; + + dwc3@4e00000 { + compatible = "snps,dwc3"; + reg = <0x4e00000 0xcd00>; + interrupt-parent = <&intc>; + interrupts = ; + usb-phy = <&qusb_phy0>, <&usb_qmp_phy>; + tx-fifo-resize; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,usb3_lpm_capable; + usb-core-id = <0>; + maximum-speed = "super-speed"; + dr_mode = "otg"; + }; + + qcom,usbbam@0x04f04000 { + compatible = "qcom,usb-bam-msm"; + reg = <0x04f04000 0x17000>; + interrupts = ; + + qcom,usb-bam-fifo-baseaddr = <0xc121000>; + qcom,usb-bam-num-pipes = <4>; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x08064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + }; + }; + + /* Primary USB port related High Speed PHY */ + qusb_phy0: qusb@1613000 { + compatible = "qcom,qusb2phy"; + reg = <0x01613000 0x180>, + <0x003cb250 0x4>, + <0x01b40258 0x4>, + <0x01612000 0x4>; + reg-names = "qusb_phy_base", + "tcsr_clamp_dig_n_1p8", + "tune2_efuse_addr", + "eud_enable_reg"; + + vdd-supply = <&pm2250_l12>; + vdda18-supply = <&pm2250_l13>; + vdda33-supply = <&pm2250_l21>; + qcom,vdd-voltage-level = <0 925000 970000>; + qcom,tune2-efuse-bit-pos = <25>; + qcom,tune2-efuse-num-bits = <4>; + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc0 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x80 0x04 + 0x9f 0x1c + 0x00 0x18>; + phy_type = "utmi"; + qcom,phy-clk-scheme = "cmos"; + qcom,major-rev = <1>; + + clocks = <&rpmcc CXO_SMD_OTG_CLK>, + <&gcc GCC_AHB2PHY_USB_CLK>; + clock-names = "ref_clk_src", "cfg_ahb_clk"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + /* Primary USB port related QMP USB PHY */ + usb_qmp_phy: ssphy@1615000 { + compatible = "qcom,usb-ssphy-qmp-usb3-or-dp"; + reg = <0x01615000 0x1000>, + <0x03cb244 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; + + vdd-supply = <&pm2250_l12>; + core-supply = <&pm2250_l13>; + qcom,vdd-voltage-level = <0 925000 970000>; + qcom,core-voltage-level = <0 1800000 1800000>; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + <0xd74 /* USB3_PHY_PCS_STATUS */ + 0xcd8 /* USB3_PHY_AUTONOMOUS_MODE_CTRL */ + 0xcdc /* USB3_PHY_LFPS_RXTERM_IRQ_CLEAR */ + 0xc04 /* USB3_PHY_POWER_DOWN_CONTROL */ + 0xc00 /* USB3_PHY_SW_RESET */ + 0xc08 /* USB3_PHY_START */ + 0xa00>; /* USB3PHY_PCS_MISC_TYPEC_CTRL */ + + clocks = <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&rpmcc CXO_SMD_OTG_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&gcc GCC_AHB2PHY_USB_CLK>; + + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "cfg_ahb_clk"; + + resets = <&gcc GCC_USB3_PHY_PRIM_SP0_BCR>, + <&gcc GCC_USB3PHY_PHY_PRIM_SP0_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x1cf 0x0>; + qcom,iommu-dma = "disabled"; + qcom,usb-audio-stream-id = <0xf>; + qcom,usb-audio-intr-num = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba-vidc.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3e57fbbeec40cea76ae4fe1a1278ff585ee84f88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba-vidc.dtsi @@ -0,0 +1,109 @@ +#include +#include + +&soc { + msm_vidc: qcom,vidc@5a00000 { + compatible = "qcom,msm-vidc", "qcom,scuba-vidc"; + status = "ok"; + reg = <0x5a00000 0x200000>; + interrupts = ; + + /* Supply */ + venus-supply = <&gcc_venus_gdsc>; + venus-core0-supply = <&gcc_vcodec0_gdsc>; + + /* Clocks */ + clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk", "throttle_clk"; + clocks = <&gcc GCC_VIDEO_VENUS_CTL_CLK>, + <&gcc GCC_VIDEO_AHB_CLK>, + <&gcc GCC_VENUS_CTL_AXI_CLK>, + <&gcc GCC_VIDEO_VCODEC0_SYS_CLK>, + <&gcc GCC_VCODEC0_AXI_CLK>, + <&gcc GCC_VIDEO_THROTTLE_CORE_CLK>; + qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk", "throttle_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x0>; + qcom,allowed-clock-rates = <133330000 240000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "vidc-ar50-ddr"; + qcom,bus-range-kbps = <1000 2128000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&apps_smmu 0x860 0x00>, + <&apps_smmu 0x880 0x00>; + qcom,iommu-dma-addr-pool = <0x70800000 0x6f800000>; + qcom,iommu-faults = "non-fatal"; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x6f800000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = + <&apps_smmu 0x861 0x04>; + qcom,iommu-dma-addr-pool = <0x4b000000 0x25800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0x9>; /*VMID_CP_BITSTREAM*/ + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = + <&apps_smmu 0x863 0x0>; + qcom,iommu-dma-addr-pool = <0x25800000 0x25800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xA>; /*VMID_CP_PIXEL*/ + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = + <&apps_smmu 0x804 0xE0>; + qcom,iommu-dma-addr-pool = <0x1000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xB>; /*VMID_CP_NON_PIXEL*/ + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba.dts b/arch/arm64/boot/dts/vendor/qcom/scuba.dts new file mode 100644 index 0000000000000000000000000000000000000000..79e68912468f0f8b18bdd1cf0ea12dff6ebcea0e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +#include "scuba.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scuba SoC"; + compatible = "qcom,scuba"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scuba.dtsi b/arch/arm64/boot/dts/vendor/qcom/scuba.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e2bd59da09ec7bbb4c9f68579902ce85652aa045 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scuba.dtsi @@ -0,0 +1,2674 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} + +#define BW_OPP_ENTRY_DDR(mhz, w, ddrtype) opp-mhz {\ + opp-hz = /bits/ 64 ;\ + opp-supported-hw = ;} + +#define DDR_TYPE_LPDDR3 5 +#define DDR_TYPE_LPDDR4X 7 + +/ { + model = "Qualcomm Technologies, Inc. SCUBA"; + compatible = "qcom,scuba"; + qcom,msm-id = <441 0x10000>; + interrupt-parent = <&wakegic>; + + #address-cells = <2>; + #size-cells = <2>; + memory { device_type = "memory"; reg = <0 0 0 0>; }; + + mem-offline { + compatible = "qcom,mem-offline"; + offline-sizes = <0x1 0x40000000 0x0 0x40000000>, + <0x1 0xc0000000 0x0 0x80000000>, + <0x2 0xc0000000 0x1 0x40000000>; + granule = <512>; + }; + + aliases { + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ + swr0 = &swr0; + swr1 = &swr1; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + + L1_I_1: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_1: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + + L1_I_2: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_2: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + next-level-cache = <&L2_0>; + qcom,freq-domain = <&cpufreq_hw 0 4>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + + L1_I_3: l1-icache { + compatible = "arm,arch-cache"; + }; + + L1_D_3: l1-dcache { + compatible = "arm,arch-cache"; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible="android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo,recovery"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/4744000.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_region: hyp_region@45700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45700000 0x0 0x600000>; + }; + + xbl_aop_mem: xbl_aop_mem@45e00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45e00000 0x0 0x100000>; + }; + + sec_apps_mem: sec_apps_region@45fff000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x45fff000 0x0 0x1000>; + }; + + smem_region: smem@46000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x46000000 0x0 0x200000>; + }; + + pil_modem_mem: modem_region@4ab00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x4ab00000 0x0 0x6900000>; + }; + + pil_video_mem: pil_video_region@51400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51400000 0x0 0x500000>; + }; + + wlan_msa_mem: wlan_msa_region@51900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51900000 0x0 0x100000>; + }; + + pil_adsp_mem: adsp_regions@51a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x51a00000 0x0 0x1c00000>; + }; + + pil_ipa_fw_mem: ips_fw_region@53600000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53600000 0x0 0x10000>; + }; + + pil_ipa_gsi_mem: ipa_gsi_region@53610000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53610000 0x0 0x5000>; + }; + + pil_gpu_mem: gpu_region@53615000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x53615000 0x0 0x2000>; + }; + + removed_region: removed_region@60000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x60000000 0x0 0x3900000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; + + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + size = <0 0x800000>; + }; + + secure_display_memory: secure_display_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x5c00000>; + }; + + cont_splash_memory: cont_splash_region@5c000000 { + reg = <0x0 0x5c000000 0x0 0x00f00000>; + label = "cont_splash_region"; + }; + + dfps_data_memory: dfps_data_region@5cf00000 { + reg = <0x0 0x5cf00000 0x0 0x0100000>; + label = "dfps_data_region"; + }; + + disp_rdump_memory: disp_rdump_region@5c000000 { + reg = <0x0 0x5c000000 0x0 0x00f00000>; + label = "disp_rdump_region"; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1000000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x2000000>; + linux,cma-default; + }; + }; + + chosen { + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + }; + + soc: soc { }; +}; + +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + slim_aud: slim@a5c0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0xa5c0000 0x2c000>, + <0xa584000 0x20000>, <0xa66e000 0x2000>; + reg-names = "slimbus_physical", + "slimbus_bam_physical","slimbus_lpass_mem"; + interrupts = , + ; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x0>; + qcom,ea-pc = <0x360>; + status = "ok"; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + intc: interrupt-controller@f200000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-controller; + interrupt-parent = <&intc>; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + reg = <0xf200000 0x10000>, /* GICD */ + <0xf300000 0x100000>; /* GICR * 8 */ + interrupts = <1 9 4>; + }; + + wakegic: wake-gic { + compatible = "qcom,mpm-gic-scuba", "qcom,mpm-gic"; + interrupts-extended = <&wakegic GIC_SPI 197 + IRQ_TYPE_EDGE_RISING>; + reg = <0x45f01b8 0x1000>, + <0xf111008 0x4>; /* MSM_APCS_GCC_BASE 4K */ + reg-names = "vmpm", "ipc"; + qcom,num-mpm-irqs = <96>; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <3>; + }; + + wakegpio: wake-gpio { + compatible = "qcom,mpm-gpio"; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <2>; + }; + + jtag_mm0: jtagmm@9040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9040000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@9140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9140000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@9240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9240000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@9340000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x9340000 0x1000>; + reg-names = "etm-base"; + + clocks = <&rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "core_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + dcc: dcc_v2@1be2000 { + compatible = "qcom,dcc-v2"; + reg = <0x1be2000 0x1000>, + <0x1bee000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + dcc-ram-offset = <0x2000>; + + link_list1 { + qcom,curr-link-list = <3>; + qcom,data-sink = "sram"; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + }; + + timer@f120000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0xf120000 0x1000>; + clock-frequency = <19200000>; + + frame@f121000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0xf121000 0x1000>, + <0xf122000 0x1000>; + }; + + frame@f123000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0xf123000 0x1000>; + status = "disabled"; + }; + + frame@f124000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0xf124000 0x1000>; + status = "disabled"; + }; + + frame@f125000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0xf125000 0x1000>; + status = "disabled"; + }; + + frame@f126000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0xf126000 0x1000>; + status = "disabled"; + }; + + frame@f127000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0xf127000 0x1000>; + status = "disabled"; + }; + + frame@f128000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0xf128000 0x1000>; + status = "disabled"; + }; + }; + + arm64_cpu_erp { + compatible = "arm,arm64-cpu-erp"; + interrupt-names = "pri-dbe-irq", + "pri-ext-irq"; + interrupts = <0 43 4>, + <0 41 4>; + poll-delay-ms = <5000>; + }; + + qcom,msm-imem@c125000 { + compatible = "qcom,msm-imem"; + reg = <0xc125000 0x1000>; + ranges = <0x0 0xc125000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 0x8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 0x4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 0x20>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 0xc>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 0xc8>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 0xc8>; + }; + }; + + restart@440b000 { + compatible = "qcom,pshold"; + reg = <0x440b000 0x4>, + <0x03d3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + qcom_hwkm: hwkm@4440000 { + compatible = "qcom,hwkm"; + reg = <0x4440000 0x9000>, <0x4750000 0x9000>; + reg-names = "km_master", "ice_slave"; + qcom,enable-hwkm-clk; + clock-names = "km_clk_src"; + clocks = <&rpmcc RPM_SMD_HWKM_CLK>; + qcom,op-freq-hz = <75000000>; + }; + + qcom_seecom: qseecom@61800000 { + compatible = "qcom,qseecom"; + reg = <0x61800000 0x2100000>; + reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,fde-key-size; + qcom,appsbl-qseecom-support; + qcom,commonlib64-loaded-by-uefi; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + clock-names = + "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = + <&rpmcc QSEECOM_CE1_CLK>, + <&rpmcc QSEECOM_CE1_CLK>, + <&rpmcc QSEECOM_CE1_CLK>, + <&rpmcc QSEECOM_CE1_CLK>; + qcom,ce-opp-freq = <192000000>; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_smcinvoke: smcinvoke@61800000 { + compatible = "qcom,smcinvoke"; + reg = <0x61800000 0x2100000>; + reg-names = "secapp-region"; + }; + + qcom_tzlog: tz-log@c125720 { + compatible = "qcom,tz-log"; + reg = <0xc125720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_rng: qrng@4453000 { + compatible = "qcom,msm-rng"; + reg = <0x4453000 0x1000>; + qcom,msm-rng-hwkm-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , /* No vote */ + ; /* 75 MHz */ + clock-names = "km_clk_src"; + clocks = <&rpmcc RPM_SMD_HWKM_CLK>; + }; + + qcom_cedev: qcedev@1b20000 { + compatible = "qcom,qcedev"; + reg = <0x1b20000 0x20000>, + <0x1b04000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <3>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + clock-names = + "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = + <&rpmcc QCEDEV_CE1_CLK>, + <&rpmcc QCEDEV_CE1_CLK>, + <&rpmcc QCEDEV_CE1_CLK>, + <&rpmcc QCEDEV_CE1_CLK>; + qcom,ce-opp-freq = <192000000>; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x0086 0x0011>, + <&apps_smmu 0x0096 0x0011>; + qcom,iommu-dma = "atomic"; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&apps_smmu 0x92 0>, + <&apps_smmu 0x98 0x1>, + <&apps_smmu 0x9F 0>; + }; + + qcom_cedev_s_cb { + compatible = "qcom,qcedev,context-bank"; + label = "secure_context"; + iommus = <&apps_smmu 0x93 0>, + <&apps_smmu 0x9C 0x1>, + <&apps_smmu 0x9E 0>; + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ + qcom,secure-context-bank; + }; + }; + + qcom_crypto: qcrypto@1b20000 { + compatible = "qcom,qcrypto"; + reg = <0x1b20000 0x20000>, + <0x1b04000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = ; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + clock-names = + "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = + <&rpmcc QCRYPTO_CE1_CLK>, + <&rpmcc QCRYPTO_CE1_CLK>, + <&rpmcc QCRYPTO_CE1_CLK>, + <&rpmcc QCRYPTO_CE1_CLK>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x0084 0x0011>, + <&apps_smmu 0x0094 0x0011>; + qcom,iommu-dma = "atomic"; + }; + + qcom,mpm2-sleep-counter@4403000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x4403000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x500000>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 6 4>; + }; + + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x0f1880b0 0x0f1980b0 + 0x0f1a80b0 0x0f1b80b0>; + qcom,config-arr = <0x0f1880b8 0x0f1980b8 + 0x0f1a80b8 0x0f1b80b8>; + }; + + eud: qcom,msm-eud@1610000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x1610000 0x2000>, + <0x1612000 0x1000>, + <0x3E5018 0x4>; + reg-names = "eud_base", "eud_mode_mgr2", + "eud_tcsr_check_reg"; + qcom,secure-eud-en; + qcom,eud-tcsr-check-enable; + qcom,eud-clock-vote-req; + clocks = <&gcc GCC_AHB2PHY_USB_CLK>; + clock-names = "eud_ahb2phy_clk"; + status = "ok"; + }; + + wdog: qcom,wdt@f017000 { + compatible = "qcom,msm-watchdog"; + reg = <0xf017000 0x1000>; + reg-names = "wdt-base"; + interrupts = , + ; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; + + qfprom: qfprom@1b40000 { + compatible = "qcom,qfprom"; + reg = <0x1b40000 0x7000>; + #address-cells = <1>; + #size-cells = <1>; + read-only; + ranges; + + feat_conf5: feat_conf5@6018 { + reg = <0x6018 0x4>; + }; + + gpu_speed_bin: gpu_speed_bin@6006 { + reg = <0x6006 0x2>; + bits = <5 8>; + }; + + adsp_variant: adsp_variant@6011 { + reg = <0x6011 0x1>; + bits = <3 1>; + }; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + + qcom,lpass@ab00000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xab00000 0x00100>; + + clocks = <&rpmcc CXO_SMD_PIL_LPASS_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + qcom,mas-crypto = <&mas_crypto_c0>; + + vdd_lpi_cx-supply = <&VDD_LPI_CX_LEVEL>; + qcom,vdd_lpi_cx-uV-uA = ; + vdd_lpi_mx-supply = <&VDD_LPI_MX_LEVEL>; + qcom,vdd_lpi_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_lpi_cx", "vdd_lpi_mx"; + + qcom,firmware-name = "adsp"; + memory-region = <&pil_adsp_mem>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <1>; + qcom,minidump-id = <5>; + qcom,ssctl-instance-id = <0x14>; + qcom,pas-id = <1>; + qcom,smem-id = <423>; + qcom,complete-ramdump; + qcom,minidump-as-elf32; + + /* Inputs from lpass */ + interrupts-extended = <&intc 0 282 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + qcom,venus@5ab0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x5ab0000 0x20000>; + + vdd-supply = <&gcc_venus_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&gcc GCC_VIDEO_VENUS_CTL_CLK>, + <&gcc GCC_VENUS_CTL_AXI_CLK>, + <&gcc GCC_VIDEO_AHB_CLK>, + <&gcc GCC_VIDEO_THROTTLE_CORE_CLK>; + clock-names = "core_clk", "bus_clk", "iface_clk", "throttle_clk"; + qcom,proxy-clock-names = "core_clk", "bus_clk", "iface_clk", "throttle_clk"; + qcom,mas-crypto = <&mas_crypto_c0>; + + qcom,core-freq = <240000000>; + qcom,ahb-freq = <240000000>; + + qcom,pas-id = <9>; + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&pil_video_mem>; + }; + + cx_ipeak_lm: cx_ipeak@3ed000 { + compatible = "qcom,cx-ipeak-v2"; + reg = <0x3ed000 0xe008>; + interrupts = <0 415 IRQ_TYPE_EDGE_RISING>, + <0 416 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "cx_ipeak_danger", "cx_ipeak_safe"; + victims_table = <4 0 844800000>; + }; + + pil_modem: qcom,mss@6080000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x6080000 0x100>; + + clocks = <&rpmcc CXO_SMD_PIL_MSS_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + qcom,mas-crypto = <&mas_crypto_c0>; + + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,vdd_cx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx"; + + qcom,firmware-name = "modem"; + memory-region = <&pil_modem_mem>; + qcom,proxy-timeout-ms = <10000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,pas-id = <4>; + qcom,smem-id = <421>; + qcom,minidump-id = <3>; + qcom,aux-minidump-ids = <4>; + qcom,complete-ramdump; + qcom,sequential-fw-load; + + /* Inputs from mss */ + interrupts-extended = <&intc 0 307 1>, + <&modem_smp2p_in 0 0>, + <&modem_smp2p_in 2 0>, + <&modem_smp2p_in 1 0>, + <&modem_smp2p_in 3 0>, + <&modem_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* Outputs to mss */ + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + }; + + thermal_zones: thermal-zones { }; + + tsens0:tsens@04410000 { + compatible = "qcom,tsens24xx"; + reg = <0x04410000 0x8>, + <0x04411000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 275 0>, <0 190 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + rpm_bus: qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + rpm-channel-name = "rpm_requests"; + interrupts = ; + rpm-channel-type = <15>; /* SMD_APPS_RPM */ + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + c0_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x0>; + }; + + c1_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x1>; + }; + + c2_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x2>; + }; + + c3_context { + qcom,dump-size = <0x800>; + qcom,dump-id = <0x3>; + }; + + l1_icache0 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x60>; + }; + + l1_icache1 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x61>; + }; + + l1_icache2 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x62>; + }; + + l1_icache3 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x63>; + }; + + l1_dcache0 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x80>; + }; + + l1_dcache1 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x81>; + }; + + l1_dcache2 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x82>; + }; + + l1_dcache3 { + qcom,dump-size = <0x9040>; + qcom,dump-id = <0x83>; + }; + + l2_tlb0 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x120>; + }; + + l2_tlb1 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x121>; + }; + + l2_tlb2 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x122>; + }; + + l2_tlb3 { + qcom,dump-size = <0x2000>; + qcom,dump-id = <0x123>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x40000>; + qcom,dump-id = <0xe4>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + tmc_etf { + qcom,dump-size = <0x8000>; + qcom,dump-id = <0xf0>; + }; + + etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + etf_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x101>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + }; + + sdhc_1: sdhci@4744000 { + compatible = "qcom,sdhci-msm-v5", "qcom,sdhci-msm-cqe"; + reg = <0x4744000 0x1000>, <0x4745000 0x1000>, <0x4748000 0x8000>; + reg-names = "hc_mem", "cqhci_mem", "cqhci_ice"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <43 43>; + qcom,pm-qos-cpu-groups = <0x0f>; + qcom,pm-qos-cmdq-latency-us = <43 43>; + qcom,pm-qos-legacy-latency-us = <43 43>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <78 512 0 0>, <1 606 0 0>, + /* 400 KB/s*/ + <78 512 1046 1600>, + <1 606 1600 1600>, + /* 20 MB/s */ + <78 512 20480 80000>, + <1 606 80000 80000>, + /* 25 MB/s */ + <78 512 25600 250000>, + <1 606 50000 133320>, + /* 50 MB/s */ + <78 512 51200 250000>, + <1 606 65000 133320>, + /* 100 MB/s */ + <78 512 102400 250000>, + <1 606 65000 133320>, + /* 200 MB/s */ + <78 512 204800 800000>, + <1 606 200000 300000>, + /* 400 MB/s */ + <78 512 204800 800000>, + <1 606 200000 300000>, + /* Max. bandwidth */ + <78 512 1338562 4096000>, + <1 606 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 400000000 4294967295>; + + clocks = <&gcc GCC_SDCC1_AHB_CLK>, + <&gcc GCC_SDCC1_APPS_CLK>, + <&gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,ice-clk-rates = <300000000 100000000>; + + /* Add support for gcc hw reset */ + resets = <&gcc GCC_SDCC1_BCR>; + reset-names = "core_reset"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x000f642c 0x0 0x0 0x00010800 0x80040868>; + qcom,nonremovable; + status = "disabled"; + }; + + sdhc_2: sdhci@4784000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0x4784000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 + 50000000 100000000 202000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + qcom,devfreq,freq-table = <50000000 202000000>; + + /* PM QoS */ + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <43 43>; + qcom,pm-qos-cpu-groups = <0x0f>; + qcom,pm-qos-legacy-latency-us = <43 43>; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 3200>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 250000>, + <1 608 80000 133320>, + /* 25 MB/s */ + <81 512 65360 250000>, + <1 608 100000 133320>, + /* 50 MB/s */ + <81 512 130718 250000>, + <1 608 133320 133320>, + /* 100 MB/s */ + <81 512 261438 250000>, + <1 608 150000 133320>, + /* 200 MB/s */ + <81 512 261438 800000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100750000 200000000 4294967295>; + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + /* DLL HSR settings. Refer go/hsr - DLL settings */ + qcom,dll-hsr-list = <0x0007642c 0x0 0x0 0x00010800 0x80040868>; + + status = "disabled"; + }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <38400000>; + clock-output-names = "xo_board"; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32764>; + clock-output-names = "chip_sleep_clk"; + #clock-cells = <0>; + }; + }; + + rpmcc: qcom,rpmcc { + compatible = "qcom,rpmcc-scuba"; + #clock-cells = <1>; + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + qcom,vm-nav-path; + }; + + gcc: qcom,gcc@1400000 { + compatible = "qcom,scuba-gcc", "syscon"; + reg = <0x1400000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + vdd_cx_ao-supply = <&VDD_CX_LEVEL_AO>; + vdd_mx-supply = <&VDD_MX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + dispcc: qcom,dispcc@5f00000 { + compatible = "qcom,scuba-dispcc", "syscon"; + reg = <0x5f00000 0x20000>; + reg-names = "cc_base"; + clock-names = "cfg_ahb_clk"; + clocks = <&gcc GCC_DISP_AHB_CLK>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + gpucc: qcom,gpucc@5990000 { + compatible = "qcom,scuba-gpucc", "syscon"; + reg = <0x5990000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + mccc_debug: syscon@447d200 { + compatible = "syscon"; + reg = <0x447d200 0x100>; + }; + + cpucc_debug: syscon@f11101c { + compatible = "syscon"; + reg = <0xf11101c 0x4>; + }; + + debugcc: qcom,cc-debug { + compatible = "qcom,scuba-debugcc"; + qcom,gcc = <&gcc>; + qcom,dispcc = <&dispcc>; + qcom,gpucc = <&gpucc>; + qcom,mccc = <&mccc_debug>; + qcom,cpucc = <&cpucc_debug>; + clock-names = "xo_clk_src"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + #clock-cells = <1>; + }; + + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw"; + reg = <0xf521000 0x1400>; + reg-names = "freq-domain0"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, <&gcc GPLL0>; + clock-names = "xo", "alternate"; + qcom,no-accumulative-counter; + qcom,max-lut-entries = <12>; + #freq-domain-cells = <2>; + }; + + qcom,cpufreq-hw-debug@f521000 { + compatible = "qcom,cpufreq-hw-debug"; + reg = <0xf521000 0x1400>; + reg-names = "domain-top"; + qcom,freq-hw-domain = <&cpufreq_hw 0>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY_DDR( 200, 8, 0xA0); /* 1525 MB/s */ + BW_OPP_ENTRY_DDR( 300, 8, 0xA0); /* 2288 MB/s */ + BW_OPP_ENTRY_DDR( 451, 8, 0xA0); /* 3440 MB/s */ + BW_OPP_ENTRY_DDR( 547, 8, 0xA0); /* 4173 MB/s */ + BW_OPP_ENTRY_DDR( 681, 8, 0xA0); /* 5195 MB/s */ + BW_OPP_ENTRY_DDR( 768, 8, 0xA0); /* 5859 MB/s */ + BW_OPP_ENTRY_DDR( 931, 8, 0x20); /* 7102 MB/s */ + BW_OPP_ENTRY_DDR(1017, 8, 0x80); /* 7759 MB/s */ + BW_OPP_ENTRY_DDR(1353, 8, 0x80); /*10322 MB/s */ + BW_OPP_ENTRY_DDR(1555, 8, 0x80); /*11863 MB/s */ + BW_OPP_ENTRY_DDR(1804, 8, 0x80); /*13763 MB/s */ + }; + + suspendable_ddr_bw_opp_table: suspendable-ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY_DDR( 0, 8, 0xA0); /* 0 MB/s */ + BW_OPP_ENTRY_DDR( 200, 8, 0xA0); /* 1525 MB/s */ + BW_OPP_ENTRY_DDR( 300, 8, 0xA0); /* 2288 MB/s */ + BW_OPP_ENTRY_DDR( 451, 8, 0xA0); /* 3440 MB/s */ + BW_OPP_ENTRY_DDR( 547, 8, 0xA0); /* 4173 MB/s */ + BW_OPP_ENTRY_DDR( 681, 8, 0xA0); /* 5195 MB/s */ + BW_OPP_ENTRY_DDR( 768, 8, 0xA0); /* 5859 MB/s */ + BW_OPP_ENTRY_DDR( 931, 8, 0x20); /* 7102 MB/s */ + BW_OPP_ENTRY_DDR(1017, 8, 0x80); /* 7759 MB/s */ + BW_OPP_ENTRY_DDR(1353, 8, 0x80); /*10322 MB/s */ + BW_OPP_ENTRY_DDR(1555, 8, 0x80); /*11863 MB/s */ + BW_OPP_ENTRY_DDR(1804, 8, 0x80); /*13763 MB/s */ + }; + + cpu_cpu_ddr_bw: qcom,cpu-cpu-ddr-bw { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_cpu_ddr_bwmon: qcom,cpu-cpu-ddr-bwmon@01b8e200 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x01b8e300 0x100>, <0x01b8e200 0x100>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_cpu_ddr_lat: qcom,cpu0-cpu-ddr-lat { + compatible = "qcom,devbw-ddr"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_memlat_cpugrp: qcom,cpu0-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + + cpu0_cpu_ddr_latmon: qcom,cpu0-cpu-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_lat>; + qcom,cachemiss-ev = <0x17>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 614400 MHZ_TO_MBPS( 200, 8) >, + < 1017600 MHZ_TO_MBPS( 451, 8) >, + < 1420000 MHZ_TO_MBPS( 547, 8) >, + < 1612800 MHZ_TO_MBPS( 768, 8) >, + < 2000000 MHZ_TO_MBPS( 931, 8) >; + }; + + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 614400 MHZ_TO_MBPS( 451, 8) >, + < 1017600 MHZ_TO_MBPS( 768, 8) >, + < 1420000 MHZ_TO_MBPS(1017, 8) >, + < 1612800 MHZ_TO_MBPS(1555, 8) >, + < 2000000 MHZ_TO_MBPS(1804, 8) >; + }; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + ddr3-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 864000 MHZ_TO_MBPS( 200, 8) >, + < 1017600 MHZ_TO_MBPS( 300, 8) >, + < 1420000 MHZ_TO_MBPS( 451, 8) >, + < 1804800 MHZ_TO_MBPS( 547, 8) >, + < 2000000 MHZ_TO_MBPS( 931, 8) >; + }; + + ddr4-map { + qcom,ddr-type = ; + qcom,core-dev-table = + < 864000 MHZ_TO_MBPS( 300, 8) >, + < 1017600 MHZ_TO_MBPS( 547, 8) >, + < 1420000 MHZ_TO_MBPS( 768, 8) >, + < 1804800 MHZ_TO_MBPS(1017, 8) >, + < 2000000 MHZ_TO_MBPS(1804, 8) >; + }; + }; + }; + + tcsr_mutex_block: syscon@00340000 { + compatible = "syscon"; + reg = <0x340000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem: qcom,smem { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + }; + + rpm_msg_ram: memory@045f0000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0x45f0000 0x7000>; + }; + + apcs_glb: mailbox@0f111000 { + compatible = "qcom,scuba-apcs-hmss-global"; + reg = <0xF111000 0x1000>; + + #mbox-cells = <1>; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,rpc-latency-us = <611>; + qcom,adsp-remoteheap-vmid = <22 37>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C3 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C4 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C5 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C6 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x01C7 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; + }; + + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + + qcom,rpm_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>; + }; + + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 12>; + mbox-names = "mpss_smem"; + interrupts = ; + + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 8>; + mbox-names = "adsp_smem"; + interrupts = ; + + label = "adsp"; + qcom,glink-label = "lpass"; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>; + }; + }; + }; + + qcom,glinkpkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + mboxes = <&apcs_glb 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_wlan_1_in: qcom,smp2p-wlan-1-in { + qcom,entry-name = "wlan"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + mboxes = <&apcs_glb 10>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + spmi_bus: qcom,spmi@1c40000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x1c40000 0x1100>, + <0x1e00000 0x2000000>, + <0x3e00000 0x100000>, + <0x3f00000 0xa0000>, + <0x1c0a000 0x26000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + }; + + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&L15A>; /* IO */ + qca,bt-vdd-core-supply = <&L10A>; /* RFA */ + qca,bt-vdd-pa-supply = <&L22A>; /* CH0 */ + qca,bt-vdd-xtal-supply = <&L13A>; /* XO */ + + qca,bt-vdd-io-voltage-level = <1700000 1900000>; + qca,bt-vdd-core-voltage-level = <1304000 1304000>; + /*To support 2.85V level for LDO22 at lower SOC level*/ + qca,bt-vdd-pa-voltage-level = <2850000 3312000>; + qca,bt-vdd-xtal-voltage-level = <1700000 1900000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + }; + + icnss: qcom,icnss@C800000 { + compatible = "qcom,icnss"; + reg = <0xC800000 0x800000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x1A0 0x1>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + qcom,iommu-dma = "fastmap"; + qcom,psf-supported; + qcom,iommu-faults = "stall-disable", "HUPCF", "non-fatal"; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; + vdd-cx-mx-supply = <&L7A>; + vdd-1.8-xo-supply = <&L13A>; + vdd-1.3-rfa-supply = <&L10A>; + vdd-3.3-ch0-supply = <&L22A>; + qcom,vdd-cx-mx-config = <640000 640000>; + /*To support 2.85V level for LDO22 at lower SOC level*/ + qcom,vdd-3.3-ch0-config = <2850000 3312000>; + qcom,smp2p_map_wlan_1_in { + interrupts-extended = <&smp2p_wlan_1_in 0 0>, + <&smp2p_wlan_1_in 1 0>; + interrupt-names = "qcom,smp2p-force-fatal-error", + "qcom,smp2p-early-crash-ind"; + }; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-platform-type-msm; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + qcom,ipa_fws { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <0xf>; + qcom,firmware-name = "scuba_ipa_fws"; + qcom,pil-force-shutdown; + memory-region = <&pil_ipa_fw_mem>; + }; + + ipa_hw: qcom,ipa@0x5800000 { + compatible = "qcom,ipa"; + reg = <0x5800000 0x34000>, + <0x5804000 0x28000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = <0 257 0>, <0 259 0>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <16>; /* IPA core version = IPAv4.2 */ + qcom,ipa-hw-mode = <0>; + qcom,platform-type = <1>; /* MSM platform */ + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,ipa-wdi2_over_gsi; + qcom,ipa-endp-delay-wa; + qcom,use-ipa-pm; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,use-64-bit-dma-mask; + qcom,ipa-fltrt-not-hashable; + qcom,skip-ieob-mask-wa; + qcom,msm-bus,name = "ipa"; + qcom,use-gsi-ipa-fw = "scuba_ipa_fws"; + clocks = <&rpmcc RPM_SMD_IPA_CLK>; + clock-names = "core_clk"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + , + , + , + /* SVS2 */ + , + , + , + /* SVS */ + , + , + , + /* NOMINAL */ + , + , + , + /* TURBO */ + , + , + ; + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; + qcom,scaling-exceptions = <>; + + /* smp2p information */ + qcom,smp2p_map_ipa_1_out { + compatible = "qcom,smp2p-map-ipa-1-out"; + qcom,smem-states = <&smp2p_ipa_1_out 0>; + qcom,smem-state-names = "ipa-smp2p-out"; + }; + + qcom,smp2p_map_ipa_1_in { + compatible = "qcom,smp2p-map-ipa-1-in"; + interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupt-names = "ipa-smp2p-in"; + }; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x0140 0x0>; + qcom,iommu-dma-addr-pool = <0x10000000 0x30000000>; + /* modem tables in IMEM */ + qcom,additional-mapping = <0x0c123000 0x0c123000 0x2000>; + qcom,iommu-dma = "fastmap"; + qcom,iommu-geometry = <0 0xB0000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x141 0x0>; + /* ipa-uc ram */ + qcom,iommu-dma = "atomic"; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x0142 0x0>; + qcom,iommu-dma-addr-pool = <0x40400000 0x1fc00000>; + }; + +}; + +#include "pm2250.dtsi" +#include "scuba-thermal.dtsi" +#include "scuba-coresight.dtsi" +#include "scuba-pinctrl.dtsi" +#include "scuba-ion.dtsi" +#include "pm2250-rpm-regulator.dtsi" +#include "scuba-regulator.dtsi" +#include "scuba-gdsc.dtsi" +#include "scuba-qupv3.dtsi" +#include "scuba-audio.dtsi" +#include "scuba-usb.dtsi" +#include "msm-arm-smmu-scuba.dtsi" +#include "scuba-bus.dtsi" +#include "scuba-gpu.dtsi" +#include "scuba-vidc.dtsi" + +&qupv3_se1_i2c { + status = "ok"; + #include "pm8008.dtsi" +}; + +&pm8008_8 { + /* PM8008 IRQ STAT */ + interrupt-parent = <&tlmm>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8008_active &pm8008_interrupt>; +}; + +&pm8008_regulators { + vdd_l1_l2-supply = <&S3A>; +}; + +&L1P { + regulator-max-microvolt = <1260000>; + qcom,min-dropout-voltage = <75000>; +}; + +&L2P { + regulator-max-microvolt = <1150000>; + qcom,min-dropout-voltage = <187500>; +}; + +&L3P { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2900000>; +}; + +&L4P { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2900000>; +}; + +&L5P { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2900000>; +}; + +&L6P { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <2900000>; +}; + +&L7P { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <1900000>; +}; + +&pm2250_vadc { + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&conn_therm_default &skin_therm_default>; + + xo_therm { + reg = ; + label = "xo_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + pa_therm { + reg = ; + label = "pa_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + quiet_therm { + reg = ; + label = "quiet_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + msm_therm { + reg = ; + label = "msm_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + skin_therm { + reg = ; + label = "skin_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + conn_therm { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; +}; + +&pm2250_gpios { + skin_therm { + skin_therm_default: skin_therm_default { + pins = "gpio5"; + bias-high-impedance; + }; + }; + + conn_therm { + conn_therm_default: conn_therm_default { + pins = "gpio6"; + bias-high-impedance; + }; + }; +}; + +&spmi_bus { + qcom,pm2250@0 { + pm2250_adc_tm_iio: adc_tm@3400 { + compatible = "qcom,adc-tm5-iio"; + reg = <0x3400 0x100>; + #thermal-sensor-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + io-channels = <&pm2250_vadc ADC_XO_THERM_PU2>, + <&pm2250_vadc ADC_AMUX_THM1_PU2>, + <&pm2250_vadc ADC_AMUX_THM2_PU2>, + <&pm2250_vadc ADC_AMUX_THM3_PU2>, + <&pm2250_vadc ADC_GPIO3_PU2>, + <&pm2250_vadc ADC_GPIO4_PU2>, + <&pm2250_vadc ADC_SBUx>; + + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + quiet_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + msm_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + skin_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + conn_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + s3_die_temp { + reg = ; + }; + }; + }; +}; + +&gcc_camss_top_gdsc { + status = "ok"; +}; + +&gcc_usb30_prim_gdsc { + status = "ok"; +}; + +&gcc_vcodec0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&gcc_venus_gdsc { + status = "ok"; +}; + +&hlos1_vote_mm_snoc_mmu_tbu_rt_gdsc { + status = "ok"; +}; + +&hlos1_vote_mm_snoc_mmu_tbu_nrt_gdsc { + status = "ok"; +}; + +&hlos1_vote_turing_mmu_tbu1_gdsc { + status = "ok"; +}; + +&hlos1_vote_turing_mmu_tbu0_gdsc { + status = "ok"; +}; + +&mdss_core_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&gpu_cx_gdsc { + status = "ok"; +}; + +&gpu_gx_gdsc { + status = "ok"; +}; + +&qupv3_se4_2uart { + status = "ok"; +}; + +&qupv3_se3_4uart { + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_vol_up>; + + vol_up { + label = "vol_up"; + gpios = <&tlmm 96 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +#include "scuba-pm.dtsi" +#include "scuba-sde.dtsi" +#include "scuba-sde-pll.dtsi" +#include "camera/scuba-camera.dtsi" + +&msm_vidc { + qcom,cx-ipeak-data = <&cx_ipeak_lm 6>; + qcom,clock-freq-threshold = <240000000>; +}; + +#include "msm-rdbg-scuba.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/scubap-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scubap-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..83bec4b37f1273c9e91962d45eed08b325c3ae16 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scubap-idp-2gb.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba-low-ram.dtsi" +#include "scuba-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scubap IDP 2GB DDR"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,msm-id = <471 0x10000>; + qcom,board-id = <34 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scubap-idp.dts b/arch/arm64/boot/dts/vendor/qcom/scubap-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..98f61ac7c30f1d98c2f67b022b8ccf8a0f22594c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scubap-idp.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba.dtsi" +#include "scuba-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scubap IDP"; + compatible = "qcom,scuba-idp", "qcom,scuba", "qcom,idp"; + qcom,msm-id = <471 0x10000>; + qcom,board-id = <34 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scubap-iot-idp-2gb.dts b/arch/arm64/boot/dts/vendor/qcom/scubap-iot-idp-2gb.dts new file mode 100644 index 0000000000000000000000000000000000000000..cc075e9b54ec9017820e80412ad93ce995fb0583 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scubap-iot-idp-2gb.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "scuba-iot-low-ram.dtsi" +#include "scuba-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scubap IOT IDP 2GB DDR"; + compatible = "qcom,scuba-idp", "qcom,scubap-iot", "qcom,idp"; + qcom,msm-id = <474 0x10000>; + qcom,board-id = <34 0x400>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scubap-iot-idp.dts b/arch/arm64/boot/dts/vendor/qcom/scubap-iot-idp.dts new file mode 100644 index 0000000000000000000000000000000000000000..f894d85f4ff96adabec3f3dc05688d9232d2470e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scubap-iot-idp.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" +#include "scuba-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scubap IOT IDP"; + compatible = "qcom,scuba-idp", "qcom,scubap-iot", "qcom,idp"; + qcom,msm-id = <474 0x10000>; + qcom,board-id = <34 0>; +}; + +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scubap-iot.dts b/arch/arm64/boot/dts/vendor/qcom/scubap-iot.dts new file mode 100644 index 0000000000000000000000000000000000000000..6294cb5f70bda1275c21e2ce410ddac490b0e475 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scubap-iot.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +#include "scuba-iot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scubap IOT SoC"; + compatible = "qcom,scubap-iot"; + qcom,msm-id = <474 0x10000>; + qcom,board-id = <0 0>; +}; + +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/scubap.dts b/arch/arm64/boot/dts/vendor/qcom/scubap.dts new file mode 100644 index 0000000000000000000000000000000000000000..16ebe7928265a892c87725e973abffe3a815848c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/scubap.dts @@ -0,0 +1,10 @@ +/dts-v1/; + +#include "scuba.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. Scubap SoC"; + compatible = "qcom,scuba"; + qcom,msm-id = <471 0x10000>; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-cdp-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-cdp-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4eda6280e155f4d4b7f3e0a18cafdb1c0bf7076b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-cdp-external-codec-overlay.dts @@ -0,0 +1,28 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 Ext. Audio Codec CDP"; + compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; + qcom,msm-id = <324 0x0>; + qcom,board-id = <1 0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..a95258de23026330a2ae0106575d45c82a0150ef --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-cdp.dts @@ -0,0 +1,24 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660L CDP"; + compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-mtp-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-mtp-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..aef887a7c04d272019b8388049bcd06def3691c5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-mtp-external-codec-overlay.dts @@ -0,0 +1,22 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-mtp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 Ext. Audio Codec MTP"; + compatible = "qcom,sda660-mtp", "qcom,sda660", "qcom,mtp"; + qcom,msm-id = <324 0x0>; + qcom,board-id = <8 0>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..81f0b03fc7b1e0a4d41574d99f97b8595b411ffe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-mtp.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-mtp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660L MTP"; + compatible = "qcom,sda660-mtp", "qcom,sda660", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..d6b0e1238d4e006b325a4e0d54f1e5d090f12e7a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-cdp.dts @@ -0,0 +1,25 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A CDP"; + compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..f0f85e41208e965586142900fb4d3875717615c7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-mtp.dts @@ -0,0 +1,19 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-mtp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A MTP"; + compatible = "qcom,sda660-mtp", "qcom,sda660", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-qrd-hdk.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-qrd-hdk.dts new file mode 100644 index 0000000000000000000000000000000000000000..8037e6db93a2f5b0c1bbc2b590ddde9b8d90595d --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-qrd-hdk.dts @@ -0,0 +1,229 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-qrd.dtsi" +#include "msm-pm660a.dtsi" + +&smb1351_charger { + status = "disabled"; +}; + +&i2c_2 { + smb138x: qcom,smb138x@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&tlmm>; + interrupts = <21 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb138x"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x11 0x12 0x13 0x14 0x16 0x36>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + + smb138x_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb138x_tadc: qcom,tadc@3600 { + compatible = "qcom,tadc"; + reg = <0x3600 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupt-parent = <&smb138x>; + interrupts = <0x36 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "eoc"; + + batt_temp@0 { + reg = <0>; + qcom,rbias = <68100>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + skin_temp@1 { + reg = <1>; + qcom,rbias = <33000>; + qcom,rtherm-at-25degc = <68000>; + qcom,beta-coefficient = <3450>; + }; + + die_temp@2 { + reg = <2>; + qcom,scale = <(-1306)>; + qcom,offset = <397904>; + }; + + batt_i@3 { + reg = <3>; + qcom,channel = <3>; + qcom,scale = <(-20000000)>; + }; + + batt_v@4 { + reg = <4>; + qcom,scale = <5000000>; + }; + + input_i@5 { + reg = <5>; + qcom,scale = <14285714>; + }; + + input_v@6 { + reg = <6>; + qcom,scale = <25000000>; + }; + + otg_i@7 { + reg = <7>; + qcom,scale = <5714286>; + }; + }; + + smb1381_charger: qcom,smb1381-charger@1000 { + compatible = "qcom,smb138x-parallel-slave"; + qcom,pmic-revid = <&smb138x_revid>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb138x>; + io-channels = + <&smb138x_tadc 1>, + <&smb138x_tadc 2>, + <&smb138x_tadc 3>, + <&smb138x_tadc 14>, + <&smb138x_tadc 15>, + <&smb138x_tadc 16>, + <&smb138x_tadc 17>; + io-channel-names = + "connector_temp", + "charger_temp", + "batt_i", + "connector_temp_thr1", + "connector_temp_thr2", + "connector_temp_thr3", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; + }; +}; + +&tlmm { + smb_int_default: smb_int_default { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A QRD HDK660"; + compatible = "qcom,sda660-qrd", "qcom,sda660", "qcom,qrd"; + qcom,board-id = <0x0016000b 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&pm660a_oledb { + status = "okay"; + qcom,oledb-default-voltage-mv = <6400>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 55 0>; + qcom,aux-sel-gpio = <&tlmm 56 0>; + qcom,usbplug-cc-gpio = <&tlmm 58 0>; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; +}; + +&tasha_snd { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT"; + qcom,msm-mbhc-hphl-swh = <0>; +}; + +&usb2s { + status = "okay"; +}; + +&qusb_phy0 { + reg = <0x0c012000 0x180>, + <0x00188018 0x4>; + reg-names = "qusb_phy_base", + "ref_clk_addr"; + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc7 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..12508fa624245244ea2fea7b6fe2eb7b6298755a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660a-rcm.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660A RCM"; + compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; + qcom,board-id = <21 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-pm660l.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660l.dts new file mode 100644 index 0000000000000000000000000000000000000000..3f7ec20385ba716bdf3862f8b4b96f84345bd207 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-pm660l.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "sda660.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660L SoC"; + compatible = "qcom,sda660"; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-rcm-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-rcm-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..2919fbfc8a44a458aafc79a3fbb3903eae4e7940 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-rcm-external-codec-overlay.dts @@ -0,0 +1,29 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 Ext. Audio Codec RCM"; + compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; + qcom,msm-id = <324 0x0>; + qcom,board-id = <21 0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sda660-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..43e307ee3afe46479a336c8f06025b77afe397ed --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660-rcm.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +#include "sda660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660 PM660 + PM660L RCM"; + compatible = "qcom,sda660-cdp", "qcom,sda660", "qcom,cdp"; + qcom,board-id = <21 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sda660.dtsi b/arch/arm64/boot/dts/vendor/qcom/sda660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a61d75809b48d317e663b05599dd895f96725a52 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sda660.dtsi @@ -0,0 +1,17 @@ +#include "sdm660.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA 660"; + compatible = "qcom,sda660"; + qcom,msm-id = <324 0x0>; +}; + +&soc { + qcom,rmnet-ipa { + status = "disabled"; + }; +}; + +&ipa_hw { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-audio.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..729d1ae234f4dbc86eb9422e970c2d4395d46ab6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-audio.dtsi @@ -0,0 +1,497 @@ +#include "sdm660-wsa881x.dtsi" +#include "sdm660-lpi.dtsi" + +&audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + }; +}; + +&q6core { + int_codec: sound { + status = "disabled"; + compatible = "qcom,sdm660-asoc-snd"; + qcom,model = "sdm660-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,wcn-btfm; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-micbias2-ext-cap; + qcom,msm-hs-micbias-type = "external"; + qcom,us-euro-gpios = <&us_euro_gpio>; + qcom,cdc-pdm-gpios = <&cdc_pdm_gpios>; + qcom,cdc-comp-gpios = <&cdc_comp_gpios>; + qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>; + qcom,audio-routing = "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "INT_LDO_H", "INT_MCLK0", + "RX_I2S_CLK", "INT_MCLK0", + "TX_I2S_CLK", "INT_MCLK0", + "MIC BIAS External", "Handset Mic", + "MIC BIAS External2", "Headset Mic", + "MIC BIAS External", "Secondary Mic", + "AMIC1", "MIC BIAS External", + "AMIC2", "MIC BIAS External2", + "AMIC3", "MIC BIAS External", + "DMIC1", "MIC BIAS External", + "MIC BIAS External", "Digital Mic1", + "DMIC2", "MIC BIAS External", + "MIC BIAS External", "Digital Mic2", + "DMIC3", "MIC BIAS External", + "MIC BIAS External", "Digital Mic3", + "DMIC4", "MIC BIAS External", + "MIC BIAS External", "Digital Mic4", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT", + "PDM_IN_RX1", "PDM_OUT_RX1", + "PDM_IN_RX2", "PDM_OUT_RX2", + "PDM_IN_RX3", "PDM_OUT_RX3", + "ADC1_IN", "ADC1_OUT", + "ADC2_IN", "ADC2_OUT", + "ADC3_IN", "ADC3_OUT"; + asoc-platform = <&pcm0>, <&pcm1>, + <&pcm2>, <&voip>, + <&voice>, <&loopback>, + <&compress>, <&hostless>, + <&afe>, <&lsm>, + <&routing>, <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, + <&dai_int_mi2s0>, <&dai_int_mi2s1>, + <&dai_int_mi2s2>, <&dai_int_mi2s3>, + <&dai_int_mi2s4>, <&dai_int_mi2s5>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>, + <&sb_7_rx>, <&sb_7_tx>, + <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-mi2s.7", + "msm-dai-q6-mi2s.8", + "msm-dai-q6-mi2s.9", "msm-dai-q6-mi2s.10", + "msm-dai-q6-mi2s.11", "msm-dai-q6-mi2s.12", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-auxpcm.5", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672", + "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36929"; + asoc-codec = <&stub_codec>, <&msm_digital_codec>, + <&pmic_analog_codec>, <&msm_sdw_codec>, + <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec", + "analog-codec", "msm_sdw_codec", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>, + <&wsa881x_213_en>, <&wsa881x_214_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + tavil_snd: sound-tavil { + compatible = "qcom,sdm660-asoc-snd-tavil"; + qcom,model = "sdm660-tavil-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,wcn-btfm; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,us-euro-gpios = <&tavil_us_euro_sw>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,msm-mclk-freq = <9600000>; + qcom,usbc-analog-en1_gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2_n_gpio = <&wcd_usbc_analog_en2n_gpio>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, + <&pcm_noirq>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-cpe-lsm", + "msm-compr-dsp", "msm-pcm-dsp-noirq"; + asoc-cpu = <&dai_dp>, <&dai_mi2s0>, + <&dai_mi2s1>, <&dai_mi2s2>, + <&dai_mi2s3>, <&dai_mi2s4>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&dai_quin_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, <&sb_8_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quin_tdm_rx_0>, <&dai_quin_tdm_tx_0>; + asoc-cpu-names = "msm-dai-q6-dp.24608", "msm-dai-q6-mi2s.0", + "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", + "msm-dai-q6-mi2s.3", "msm-dai-q6-mi2s.4", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.16400", "msm-dai-q6-dev.28672", + "msm-dai-q6-dev.28673", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36929"; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + +}; + +&slim_aud { + status = "okay"; + dai_slim: msm_dai_slim { + compatible = "qcom,msm-dai-slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; + + wcd9335: tasha_codec { + compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 a0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk", "wcd_native_clk"; + clocks = <&clock_audio AUDIO_PMI_CLK>, + <&clock_audio AUDIO_LPASS_MCLK_2>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; + + wcd934x_cdc: tavil_codec { + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb 0>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <7>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; + + wcd_usbc_analog_en2n_gpio: msm_cdc_pinctrl_usbc_audio_en2 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en2n_active>; + pinctrl-1 = <&wcd_usbc_analog_en2n_idle>; + }; + }; +}; + +&pm660l_3 { + pmic_analog_codec: anlg-cdc@f000 { + status = "disabled"; + compatible = "qcom,pmic-analog-codec"; + reg = <0xf000 0x200>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x3 0xf0 0x0 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x1 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x2 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x3 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x4 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x5 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x6 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf0 0x7 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf1 0x0 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf1 0x1 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf1 0x2 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf1 0x3 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf1 0x4 IRQ_TYPE_LEVEL_HIGH>, + <0x3 0xf1 0x5 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "spk_cnp_int", + "spk_clip_int", + "spk_ocp_int", + "ins_rem_det1", + "but_rel_det", + "but_press_det", + "ins_rem_det", + "mbhc_int", + "ear_ocp_int", + "hphr_ocp_int", + "hphl_ocp_det", + "ear_cnp_int", + "hphr_cnp_int", + "hphl_cnp_int"; + + + cdc-vdda-cp-supply = <&pm660_s4>; + qcom,cdc-vdda-cp-voltage = <1900000 2050000>; + qcom,cdc-vdda-cp-current = <50000>; + + cdc-vdd-pa-supply = <&pm660_s4>; + qcom,cdc-vdd-pa-voltage = <2040000 2040000>; + qcom,cdc-vdd-pa-current = <260000>; + + cdc-vdd-mic-bias-supply = <&pm660l_l7>; + qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>; + qcom,cdc-vdd-mic-bias-current = <5000>; + + qcom,cdc-mclk-clk-rate = <9600000>; + + qcom,cdc-static-supplies = "cdc-vdda-cp", + "cdc-vdd-pa"; + + qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias"; + + /* + * Not marking address @ as driver searches this child + * with name msm-dig-codec + */ + msm_digital_codec: msm-dig-codec { + compatible = "qcom,msm-digital-codec"; + reg = <0x152c0000 0x0>; + }; + }; +}; + +&soc { + cdc_pdm_gpios: cdc_pdm_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_pdm_gpios_active &cdc_pdm_2_gpios_active>; + pinctrl-1 = <&cdc_pdm_gpios_sleep &cdc_pdm_2_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_comp_gpios: cdc_comp_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_comp_gpios_active>; + pinctrl-1 = <&cdc_comp_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic_gpios: cdc_dmic_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic12_gpios_active + &cdc_dmic34_gpios_active>; + pinctrl-1 = <&cdc_dmic12_gpios_sleep + &cdc_dmic34_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_sdw_gpios: sdw_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sdw_clk_active &sdw_data_active>; + pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>; + }; + + wsa_spkr_en1: wsa_spkr_en1_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_en2: wsa_spkr_en2_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + msm_sdw_codec: msm-sdw-codec@152c1000 { + status = "disabled"; + compatible = "qcom,msm-sdw-codec"; + reg = <0x152c1000 0x0>; + interrupts = <0 161 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "swr_master_irq"; + qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>; + + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211_en: wsa881x_en@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_212_en: wsa881x_en@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + + wsa881x_213_en: wsa881x_en@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_214_en: wsa881x_en@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + }; + }; +}; + +&pm660_gpios { + gpio@c200 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <4>; + qcom,vin-sel = <0>; + qcom,src-sel = <2>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-blsp.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-blsp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a838d5f315bd1dae7d7116af68e7959dee8c66cd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-blsp.dtsi @@ -0,0 +1,582 @@ +#include "sdm660-pinctrl.dtsi" + +/ { + aliases { + spi1 = &spi_1; + spi2 = &spi_2; + spi3 = &spi_3; + spi4 = &spi_4; + spi5 = &spi_5; + spi6 = &spi_6; + spi7 = &spi_7; + spi8 = &spi_8; + i2c1 = &i2c_1; + i2c2 = &i2c_2; + i2c3 = &i2c_3; + i2c4 = &i2c_4; + i2c5 = &i2c_5; + i2c6 = &i2c_6; + i2c7 = &i2c_7; + i2c8 = &i2c_8; + }; +}; + + +&soc { + i2c_1: i2c@c175000 { /* BLSP1 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc175000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 95 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp1 4 64 0x20000020 0x20>, + <&dma_blsp1 5 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 2 0x00>; + qcom,i2c-clk = <&tlmm 3 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_1_active>; + pinctrl-1 = <&i2c_1_sleep>; + pinctrl-2 = <&i2c_1_bitbang>; + status = "disabled"; + }; + + i2c_2: i2c@c176000 { /* BLSP1 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc176000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 96 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp1 6 64 0x20000020 0x20>, + <&dma_blsp1 7 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 6 0x00>; + qcom,i2c-clk = <&tlmm 7 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_2_active>; + pinctrl-1 = <&i2c_2_sleep>; + pinctrl-2 = <&i2c_2_bitbang>; + status = "disabled"; + }; + + i2c_3: i2c@c177000 { /* BLSP1 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc177000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp1 8 64 0x20000020 0x20>, + <&dma_blsp1 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 10 0x00>; + qcom,i2c-clk = <&tlmm 11 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_3_active>; + pinctrl-1 = <&i2c_3_sleep>; + pinctrl-2 = <&i2c_3_bitbang>; + status = "disabled"; + }; + + i2c_4: i2c@c178000 { /* BLSP1 QUP4 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc178000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp1 10 64 0x20000020 0x20>, + <&dma_blsp1 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <86>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 14 0x00>; + qcom,i2c-clk = <&tlmm 15 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_4_active>; + pinctrl-1 = <&i2c_4_sleep>; + pinctrl-2 = <&i2c_4_bitbang>; + status = "disabled"; + }; + + i2c_5: i2c@c1b5000 { /* BLSP2 QUP1 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b5000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 101 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp2 4 64 0x20000020 0x20>, + <&dma_blsp2 5 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP1_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 18 0x00>; + qcom,i2c-clk = <&tlmm 19 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_5_active>; + pinctrl-1 = <&i2c_5_sleep>; + pinctrl-2 = <&i2c_5_bitbang>; + status = "disabled"; + }; + + i2c_6: i2c@c1b6000 { /* BLSP2 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b6000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp2 6 64 0x20000020 0x20>, + <&dma_blsp2 7 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 22 0x00>; + qcom,i2c-clk = <&tlmm 23 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_6_active>; + pinctrl-1 = <&i2c_6_sleep>; + pinctrl-2 = <&i2c_6_bitbang>; + status = "disabled"; + }; + + i2c_7: i2c@c1b7000 { /* BLSP2 QUP3 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b7000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 103 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp2 8 64 0x20000020 0x20>, + <&dma_blsp2 9 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP3_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 26 0x00>; + qcom,i2c-clk = <&tlmm 27 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_7_active>; + pinctrl-1 = <&i2c_7_sleep>; + pinctrl-2 = <&i2c_7_bitbang>; + status = "disabled"; + }; + + i2c_8: i2c@c1b8000 { /* BLSP2 QUP4 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xc1b8000 0x600>; + reg-names = "qup_phys_addr"; + interrupt-names = "qup_irq"; + interrupts = <0 104 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&dma_blsp2 10 64 0x20000020 0x20>, + <&dma_blsp2 11 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + qcom,master-id = <84>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP4_I2C_APPS_CLK>; + qcom,i2c-dat = <&tlmm 30 0x00>; + qcom,i2c-clk = <&tlmm 31 0x00>; + pinctrl-names = "i2c_active", "i2c_sleep", "i2c_bitbang"; + pinctrl-0 = <&i2c_8_active>; + pinctrl-1 = <&i2c_8_sleep>; + pinctrl-2 = <&i2c_8_bitbang>; + status = "disabled"; + }; + + spi_1: spi@c175000 { /* BLSP1 QUP1 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc175000 0x600>, + <0xc144000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 95 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <4>; + qcom,bam-producer-pipe-index = <5>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_1_active>; + pinctrl-1 = <&spi_1_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_2: spi@c176000 { /* BLSP1 QUP2 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc176000 0x600>, + <0xc144000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 96 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <6>; + qcom,bam-producer-pipe-index = <7>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_2_active>; + pinctrl-1 = <&spi_2_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP2_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_3: spi@c177000 { /* BLSP1 QUP3 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc177000 0x600>, + <0xc144000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <8>; + qcom,bam-producer-pipe-index = <9>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_3_active>; + pinctrl-1 = <&spi_3_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP3_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_4: spi@c178000 { /* BLSP1 QUP4 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc178000 0x600>, + <0xc144000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <10>; + qcom,bam-producer-pipe-index = <11>; + qcom,master-id = <86>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_4_active>; + pinctrl-1 = <&spi_4_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP1_AHB_CLK>, + <&clock_gcc GCC_BLSP1_QUP4_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_5: spi@c1b5000 { /* BLSP2 QUP1 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc1b5000 0x600>, + <0xc184000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 101 IRQ_TYPE_LEVEL_HIGH>, <0 239 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <4>; + qcom,bam-producer-pipe-index = <5>; + qcom,master-id = <84>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_5_active>; + pinctrl-1 = <&spi_5_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP1_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_6: spi@c1b6000 { /* BLSP2 QUP2 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc1b6000 0x600>, + <0xc184000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>, <0 239 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <6>; + qcom,bam-producer-pipe-index = <7>; + qcom,master-id = <84>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_6_active>; + pinctrl-1 = <&spi_6_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_7: spi@c1b7000 { /* BLSP2 QUP3 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc1b7000 0x600>, + <0xc184000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 103 IRQ_TYPE_LEVEL_HIGH>, <0 239 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <8>; + qcom,bam-producer-pipe-index = <9>; + qcom,master-id = <84>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_7_active>; + pinctrl-1 = <&spi_7_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP3_SPI_APPS_CLK>; + status = "disabled"; + }; + + spi_8: spi@c1b8000 { /* BLSP2 QUP4 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0xc1b8000 0x600>, + <0xc184000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 104 IRQ_TYPE_LEVEL_HIGH>, <0 239 IRQ_TYPE_LEVEL_HIGH>; + spi-max-frequency = <50000000>; + qcom,use-bam; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <10>; + qcom,bam-producer-pipe-index = <11>; + qcom,master-id = <84>; + qcom,use-pinctrl; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi_8_active>; + pinctrl-1 = <&spi_8_sleep>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc GCC_BLSP2_AHB_CLK>, + <&clock_gcc GCC_BLSP2_QUP4_SPI_APPS_CLK>; + status = "disabled"; + }; + + blsp1_uart1_hs: uart@c16f000 { /* BLSP1 UART1 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc16f000 0x200>, + <0xc144000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart1_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 107 0 + 1 &intc 0 0 238 0 + 2 &tlmm 1 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart1_sleep>; + pinctrl-1 = <&blsp1_uart1_active>; + + qcom,msm-bus,name = "buart1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp1_uart2_hs: uart@c170000 { /* BLSP1 UART2 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc170000 0x200>, + <0xc144000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 108 0 + 1 &intc 0 0 238 0 + 2 &tlmm 5 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp1_uart2_sleep>; + pinctrl-1 = <&blsp1_uart2_active>; + + qcom,msm-bus,name = "buart2"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "disabled"; + }; + + blsp2_uart1_hs: uart@c1af000 { /* BLSP2 UART1 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc1af000 0x200>, + <0xc184000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp2_uart1_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 113 0 + 1 &intc 0 0 239 0 + 2 &tlmm 17 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <0>; + qcom,bam-rx-ep-pipe-index = <1>; + qcom,master-id = <84>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP2_UART1_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp2_uart1_tx_sleep>, + <&blsp2_uart1_rxcts_sleep>, <&blsp2_uart1_rfr_sleep>; + pinctrl-1 = <&blsp2_uart1_tx_active>, + <&blsp2_uart1_rxcts_active>, <&blsp2_uart1_rfr_active>; + qcom,msm-bus,name = "buart3"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + status = "disabled"; + }; + + blsp2_uart2_hs: uart@c1b0000 { /* BLSP2 UART2 */ + compatible = "qcom,msm-hsuart-v14"; + reg = <0xc1b0000 0x200>, + <0xc184000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp2_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 114 0 + 1 &intc 0 0 239 0 + 2 &tlmm 25 0>; + + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,master-id = <84>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc GCC_BLSP2_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&blsp2_uart2_sleep>; + pinctrl-1 = <&blsp2_uart2_active>; + + qcom,msm-bus,name = "buart4"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <84 512 0 0>, + <84 512 500 800>; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-bus.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-bus.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..77b36ba0f349516f9e5c38eb74b811b907f788f3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-bus.dtsi @@ -0,0 +1,1281 @@ +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + /*Version = 14 */ + compatible = "qcom,msm-bus-device"; + reg = <0x1620000 0x20000>, + <0x1000000 0x80000>, + <0x1500000 0x10000>, + <0x1700000 0x20000>, + <0x17900000 0xE000>, + <0x1740000 0x10000>, + <0x1740000 0x10000>; + + reg-names = "snoc-base", "bimc-base", "cnoc-base", + "a2noc-base", "gnoc-base", "mmnoc-ahb-base", "mnoc-base"; + + /*Buses*/ + + fab_a2noc: fab-a2noc { + cell-id = ; + label = "fab-a2noc"; + qcom,fab-dev; + qcom,base-name = "a2noc-base"; + qcom,bus-type = <1>; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpmcc AGGR2_NOC_MSMBUS_CLK>, + <&clock_rpmcc AGGR2_NOC_MSMBUS_A_CLK>; + qcom,node-qos-clks { + clock-names = + "clk-ipa-clk", + "clk-ufs-axi-clk", + "clk-aggre2-ufs-axi-no-rate", + "clk-aggre2-usb3-axi-cfg-no-rate", + "clk-cfg-noc-usb2-axi-no-rate"; + clocks = + <&clock_rpmcc RPM_SMD_IPA_CLK>, + <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&clock_gcc GCC_CFG_NOC_USB2_AXI_CLK>; + }; + }; + + fab_bimc: fab-bimc { + cell-id = ; + label = "fab-bimc"; + qcom,fab-dev; + qcom,base-name = "bimc-base"; + qcom,bus-type = <2>; + qcom,util-fact = <153>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpmcc BIMC_MSMBUS_CLK>, + <&clock_rpmcc BIMC_MSMBUS_A_CLK>; + }; + + fab_cnoc: fab-cnoc { + cell-id = ; + label = "fab-cnoc"; + qcom,fab-dev; + qcom,base-name = "cnoc-base"; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpmcc CNOC_MSMBUS_CLK>, + <&clock_rpmcc CNOC_MSMBUS_A_CLK>; + }; + + fab_gnoc: fab-gnoc { + cell-id = ; + label = "fab-gnoc"; + qcom,virt-dev; + qcom,base-name = "gnoc-base"; + }; + + fab_mnoc: fab-mnoc { + cell-id = ; + label = "fab-mnoc"; + qcom,fab-dev; + qcom,base-name = "mnoc-base"; + qcom,bus-type = <1>; + qcom,qos-off = <4096>; + qcom,base-offset = <20480>; + qcom,util-fact = <153>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_A_CLK>; + qcom,node-qos-clks { + clock-names = + "clk-mmssnoc-axi-no-rate", + "clk-mmss-noc-cfg-ahb-no-rate"; + clocks = + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_gcc GCC_MMSS_NOC_CFG_AHB_CLK>; + }; + }; + + fab_snoc: fab-snoc { + cell-id = ; + label = "fab-snoc"; + qcom,fab-dev; + qcom,base-name = "snoc-base"; + qcom,bus-type = <1>; + qcom,qos-off = <4096>; + qcom,base-offset = <24576>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_rpmcc SNOC_MSMBUS_CLK>, + <&clock_rpmcc SNOC_MSMBUS_A_CLK>; + }; + + fab_mnoc_ahb: fab-mnoc-ahb { + cell-id = ; + label = "fab-mnoc-ahb"; + qcom,fab-dev; + qcom,base-name = "mmnoc-ahb-base"; + qcom,setrate-only-clk; + qcom,bus-type = <1>; + clock-names = "bus_clk", "bus_a_clk"; + clocks = <&clock_mmss AHB_CLK_SRC >, + <&clock_mmss AHB_CLK_SRC>; + }; + + /*Masters*/ + + mas_ipa: mas-ipa { + cell-id = ; + label = "mas-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <3>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_a2noc_snoc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_cnoc_a2noc: mas-cnoc-a2noc { + cell-id = ; + label = "mas-cnoc-a2noc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_a2noc_snoc>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + qcom,blacklist = <&slv_snoc_cnoc>; + }; + + mas_sdcc_1: mas-sdcc-1 { + cell-id = ; + label = "mas-sdcc-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_a2noc_snoc>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_sdcc_2: mas-sdcc-2 { + cell-id = ; + label = "mas-sdcc-2"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_a2noc_snoc>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_blsp_1: mas-blsp-1 { + cell-id = ; + label = "mas-blsp-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_a2noc_snoc>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_blsp_2: mas-blsp-2 { + cell-id = ; + label = "mas-blsp-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_a2noc_snoc>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_ufs: mas-ufs { + cell-id = ; + label = "mas-ufs"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_a2noc_snoc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_usb_hs: mas-usb-hs { + cell-id = ; + label = "mas-usb-hs"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <1>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_a2noc_snoc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_usb3: mas-usb3 { + cell-id = ; + label = "mas-usb3"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_a2noc_snoc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_crypto_c0: mas-crypto-c0 { + cell-id = ; + label = "mas-crypto-c0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <11>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_a2noc_snoc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_a2noc>; + qcom,mas-rpm-id = ; + }; + + mas_gnoc_bimc: mas-gnoc-bimc { + cell-id = ; + label = "mas-gnoc-bimc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_ebi>; + qcom,prio-lvl = <0>; + qcom,prio-rd = <0>; + qcom,prio-wr = <0>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_oxili: mas-oxili { + cell-id = ; + label = "mas-oxili"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,ap-owned; + qcom,qport = <1>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_hmss_l3 + &slv_ebi &slv_bimc_snoc>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_mnoc_bimc: mas-mnoc-bimc { + cell-id = ; + label = "mas-mnoc-bimc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_hmss_l3 + &slv_ebi &slv_bimc_snoc>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_bimc: mas-snoc-bimc { + cell-id = ; + label = "mas-snoc-bimc"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,connections = <&slv_hmss_l3 &slv_ebi>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_pimem: mas-pimem { + cell-id = ; + label = "mas-pimem"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_hmss_l3 &slv_ebi>; + qcom,prio-lvl = <1>; + qcom,prio-rd = <1>; + qcom,prio-wr = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_cnoc: mas-snoc-cnoc { + cell-id = ; + label = "mas-snoc-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_clk_ctl + &slv_qdss_cfg &slv_qm_cfg + &slv_srvc_cnoc &slv_ufs_cfg + &slv_tcsr &slv_a2noc_smmu_cfg + &slv_snoc_cfg &slv_tlmm_south + &slv_mpm &slv_cnoc_mnoc_mmss_cfg + &slv_sdcc_2 &slv_sdcc_1 + &slv_spdm &slv_pmic_arb + &slv_prng &slv_mss_cfg + &slv_gpuss_cfg &slv_imem_cfg + &slv_usb3_0 &slv_a2noc_cfg + &slv_tlmm_north &slv_usb_hs + &slv_pdm &slv_tlmm_center + &slv_ahb2phy &slv_blsp_2 + &slv_blsp_1 &slv_pimem_cfg + &slv_glm &slv_message_ram + &slv_bimc_cfg &slv_cnoc_mnoc_cfg>; + qcom,bus-dev = <&fab_cnoc>; + qcom,mas-rpm-id = ; + }; + + mas_qdss_dap: mas-qdss-dap { + cell-id = ; + label = "mas-qdss-dap"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_clk_ctl + &slv_qdss_cfg &slv_qm_cfg + &slv_srvc_cnoc &slv_ufs_cfg + &slv_tcsr &slv_a2noc_smmu_cfg + &slv_snoc_cfg &slv_tlmm_south + &slv_mpm &slv_cnoc_mnoc_mmss_cfg + &slv_sdcc_2 &slv_sdcc_1 + &slv_spdm &slv_pmic_arb + &slv_prng &slv_mss_cfg + &slv_gpuss_cfg &slv_imem_cfg + &slv_usb3_0 &slv_a2noc_cfg + &slv_tlmm_north &slv_usb_hs + &slv_pdm &slv_tlmm_center + &slv_ahb2phy &slv_blsp_2 + &slv_blsp_1 &slv_pimem_cfg + &slv_glm &slv_message_ram + &slv_cnoc_a2noc &slv_bimc_cfg + &slv_cnoc_mnoc_cfg>; + qcom,bus-dev = <&fab_cnoc>; + qcom,mas-rpm-id = ; + }; + + mas_apps_proc: mas-apps-proc { + cell-id = ; + label = "mas-apps-proc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_gnoc_snoc &slv_gnoc_bimc>; + qcom,bus-dev = <&fab_gnoc>; + qcom,mas-rpm-id = ; + }; + + mas_cnoc_mnoc_mmss_cfg: mas-cnoc-mnoc-mmss-cfg { + cell-id = ; + label = "mas-cnoc-mnoc-mmss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_venus_throttle_cfg + &slv_venus_cfg &slv_camera_throttle_cfg + &slv_smmu_cfg &slv_camera_cfg &slv_csi_phy_cfg + &slv_display_throttle_cfg &slv_display_cfg + &slv_mmss_clk_cfg &slv_mnoc_mpu_cfg + &slv_misc_cfg &slv_mmss_clk_xpu_cfg>; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,mas-rpm-id = ; + }; + + mas_cnoc_mnoc_cfg: mas-cnoc-mnoc-cfg { + cell-id = ; + label = "mas-cnoc-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,mas-rpm-id = ; + }; + + mas_cpp: mas-cpp { + cell-id = ; + label = "mas-cpp"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <4>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_mnoc_bimc>; + qcom,bus-dev = <&fab_mnoc>; + qcom,mas-rpm-id = ; + }; + + mas_jpeg: mas-jpeg { + cell-id = ; + label = "mas-jpeg"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <6>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_mnoc_bimc>; + qcom,bus-dev = <&fab_mnoc>; + qcom,mas-rpm-id = ; + }; + + mas_mdp_p0: mas-mdp-p0 { + cell-id = ; + label = "mas-mdp-p0"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_mnoc_bimc>; + qcom,bus-dev = <&fab_mnoc>; + qcom,vrail-comp = <50>; + qcom,mas-rpm-id = ; + }; + + mas_mdp_p1: mas-mdp-p1 { + cell-id = ; + label = "mas-mdp-p1"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <1>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_mnoc_bimc>; + qcom,bus-dev = <&fab_mnoc>; + qcom,vrail-comp = <50>; + qcom,mas-rpm-id = ; + }; + + mas_venus: mas-venus { + cell-id = ; + label = "mas-venus"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <2>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_mnoc_bimc>; + qcom,bus-dev = <&fab_mnoc>; + qcom,mas-rpm-id = ; + }; + + mas_vfe: mas-vfe { + cell-id = ; + label = "mas-vfe"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <5>; + qcom,qos-mode = "bypass"; + qcom,connections = <&slv_mnoc_bimc>; + qcom,bus-dev = <&fab_mnoc>; + qcom,mas-rpm-id = ; + }; + + mas_qdss_etr: mas-qdss-etr { + cell-id = ; + label = "mas-qdss-etr"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <1>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_pimem + &slv_imem &slv_snoc_cnoc + &slv_snoc_bimc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_qdss_bam: mas-qdss-bam { + cell-id = ; + label = "mas-qdss-bam"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,qport = <0>; + qcom,qos-mode = "fixed"; + qcom,connections = <&slv_pimem + &slv_imem &slv_snoc_cnoc + &slv_snoc_bimc>; + qcom,prio1 = <1>; + qcom,prio0 = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_snoc_cfg: mas-snoc-cfg { + cell-id = ; + label = "mas-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_snoc>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_bimc_snoc: mas-bimc-snoc { + cell-id = ; + label = "mas-bimc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_pimem + &slv_ipa &slv_qdss_stm + &slv_lpass &slv_hmss + &slv_cdsp &slv_snoc_cnoc + &slv_wlan &slv_imem>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + mas_a2noc_snoc: mas-a2noc-snoc { + cell-id = ; + label = "mas-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_pimem + &slv_ipa &slv_qdss_stm + &slv_lpass &slv_hmss + &slv_snoc_bimc &slv_cdsp + &slv_snoc_cnoc &slv_wlan + &slv_imem>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + /*Internal nodes*/ + + /*Slaves*/ + + slv_a2noc_snoc:slv-a2noc-snoc { + cell-id = ; + label = "slv-a2noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_a2noc>; + qcom,connections = <&mas_a2noc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_ebi:slv-ebi { + cell-id = ; + label = "slv-ebi"; + qcom,buswidth = <4>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_hmss_l3:slv-hmss-l3 { + cell-id = ; + label = "slv-hmss-l3"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_bimc_snoc:slv-bimc-snoc { + cell-id = ; + label = "slv-bimc-snoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_bimc>; + qcom,connections = <&mas_bimc_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_cnoc_a2noc:slv-cnoc-a2noc { + cell-id = ; + label = "slv-cnoc-a2noc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,connections = <&mas_cnoc_a2noc>; + qcom,slv-rpm-id = ; + }; + + slv_mpm:slv-mpm { + cell-id = ; + label = "slv-mpm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_pmic_arb:slv-pmic-arb { + cell-id = ; + label = "slv-pmic-arb"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tlmm_north:slv-tlmm-north { + cell-id = ; + label = "slv-tlmm-north"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tcsr:slv-tcsr { + cell-id = ; + label = "slv-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_pimem_cfg:slv-pimem-cfg { + cell-id = ; + label = "slv-pimem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_imem_cfg:slv-imem-cfg { + cell-id = ; + label = "slv-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_message_ram:slv-message-ram { + cell-id = ; + label = "slv-message-ram"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_glm:slv-glm { + cell-id = ; + label = "slv-glm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_bimc_cfg:slv-bimc-cfg { + cell-id = ; + label = "slv-bimc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_prng:slv-prng { + cell-id = ; + label = "slv-prng"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_spdm:slv-spdm { + cell-id = ; + label = "slv-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_qdss_cfg:slv-qdss-cfg { + cell-id = ; + label = "slv-qdss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_cnoc_mnoc_cfg:slv-cnoc-mnoc-cfg { + cell-id = ; + label = "slv-cnoc-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,connections = <&mas_cnoc_mnoc_cfg>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cfg:slv-snoc-cfg { + cell-id = ; + label = "slv-snoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_qm_cfg:slv-qm-cfg { + cell-id = ; + label = "slv-qm-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_clk_ctl:slv-clk-ctl { + cell-id = ; + label = "slv-clk-ctl"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_mss_cfg:slv-mss-cfg { + cell-id = ; + label = "slv-mss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tlmm_south:slv-tlmm-south { + cell-id = ; + label = "slv-tlmm-south"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_ufs_cfg:slv-ufs-cfg { + cell-id = ; + label = "slv-ufs-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_a2noc_cfg:slv-a2noc-cfg { + cell-id = ; + label = "slv-a2noc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_a2noc_smmu_cfg:slv-a2noc-smmu-cfg { + cell-id = ; + label = "slv-a2noc-smmu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_gpuss_cfg:slv-gpuss-cfg { + cell-id = ; + label = "slv-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_ahb2phy:slv-ahb2phy { + cell-id = ; + label = "slv-ahb2phy"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_blsp_1:slv-blsp-1 { + cell-id = ; + label = "slv-blsp-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_sdcc_1:slv-sdcc-1 { + cell-id = ; + label = "slv-sdcc-1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_sdcc_2:slv-sdcc-2 { + cell-id = ; + label = "slv-sdcc-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_tlmm_center:slv-tlmm-center { + cell-id = ; + label = "slv-tlmm-center"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_blsp_2:slv-blsp-2 { + cell-id = ; + label = "slv-blsp-2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_pdm:slv-pdm { + cell-id = ; + label = "slv-pdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_cnoc_mnoc_mmss_cfg:slv-cnoc-mnoc-mmss-cfg { + cell-id = ; + label = "slv-cnoc-mnoc-mmss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,connections = <&mas_cnoc_mnoc_mmss_cfg>; + qcom,slv-rpm-id = ; + }; + + slv_usb_hs:slv-usb-hs { + cell-id = ; + label = "slv-usb-hs"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_usb3_0:slv-usb3-0 { + cell-id = ; + label = "slv-usb3-0"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_srvc_cnoc:slv-srvc-cnoc { + cell-id = ; + label = "slv-srvc-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_cnoc>; + qcom,slv-rpm-id = ; + }; + + + slv_gnoc_bimc:slv-gnoc-bimc { + cell-id = ; + label = "slv-gnoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_gnoc>; + qcom,connections = <&mas_gnoc_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_gnoc_snoc:slv-gnoc-snoc { + cell-id = ; + label = "slv-gnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_gnoc>; + qcom,connections = <&mas_gnoc_snoc>; + qcom,slv-rpm-id = ; + }; + + mas_gnoc_snoc: mas-gnoc-snoc { + cell-id = ; + label = "mas-gnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_pimem + &slv_ipa &slv_qdss_stm + &slv_lpass &slv_hmss + &slv_cdsp &slv_snoc_cnoc + &slv_wlan &slv_imem>; + qcom,bus-dev = <&fab_snoc>; + qcom,mas-rpm-id = ; + }; + + slv_camera_cfg:slv-camera-cfg { + cell-id = ; + label = "slv-camera-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_camera_throttle_cfg:slv-camera-throttle-cfg { + cell-id = ; + label = "slv-camera-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_misc_cfg:slv-misc-cfg { + cell-id = ; + label = "slv-misc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_venus_throttle_cfg:slv-venus-throttle-cfg { + cell-id = ; + label = "slv-venus-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_venus_cfg:slv-venus-cfg { + cell-id = ; + label = "slv-venus-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_mmss_clk_xpu_cfg:slv-mmss-clk-xpu-cfg { + cell-id = ; + label = "slv-mmss-clk-xpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_mmss_clk_cfg:slv-mmss-clk-cfg { + cell-id = ; + label = "slv-mmss-clk-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_mnoc_mpu_cfg:slv-mnoc-mpu-cfg { + cell-id = ; + label = "slv-mnoc-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_display_cfg:slv-display-cfg { + cell-id = ; + label = "slv-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_csi_phy_cfg:slv-csi-phy-cfg { + cell-id = ; + label = "slv-csi-phy-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_display_throttle_cfg:slv-display-throttle-cfg { + cell-id = ; + label = "slv-display-throttle-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_smmu_cfg:slv-smmu-cfg { + cell-id = ; + label = "slv-smmu-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_mnoc_bimc:slv-mnoc-bimc { + cell-id = ; + label = "slv-mnoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <2>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc>; + qcom,connections = <&mas_mnoc_bimc>; + qcom,slv-rpm-id = ; + qcom,enable-only-clk; + clock-names = "node_clk"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>; + }; + + slv_srvc_mnoc:slv-srvc-mnoc { + cell-id = ; + label = "slv-srvc-mnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_mnoc_ahb>; + qcom,slv-rpm-id = ; + }; + + slv_hmss:slv-hmss { + cell-id = ; + label = "slv-hmss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_lpass:slv-lpass { + cell-id = ; + label = "slv-lpass"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_wlan:slv-wlan { + cell-id = ; + label = "slv-wlan"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_cdsp:slv-cdsp { + cell-id = ; + label = "slv-cdsp"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_ipa:slv-ipa { + cell-id = ; + label = "slv-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,ap-owned; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_bimc:slv-snoc-bimc { + cell-id = ; + label = "slv-snoc-bimc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,connections = <&mas_snoc_bimc>; + qcom,slv-rpm-id = ; + }; + + slv_snoc_cnoc:slv-snoc-cnoc { + cell-id = ; + label = "slv-snoc-cnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,connections = <&mas_snoc_cnoc>; + qcom,slv-rpm-id = ; + }; + + slv_imem:slv-imem { + cell-id = ; + label = "slv-imem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_pimem:slv-pimem { + cell-id = ; + label = "slv-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_qdss_stm:slv-qdss-stm { + cell-id = ; + label = "slv-qdss-stm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + + slv_srvc_snoc:slv-srvc-snoc { + cell-id = ; + label = "slv-srvc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_snoc>; + qcom,slv-rpm-id = ; + }; + }; + + devfreq_spdm_cpu { + compatible = "qcom,devfreq_spdm"; + qcom,msm-bus,name = "devfreq_spdm"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 512 0 0>, + <1 512 0 0>; + qcom,msm-bus,active-only; + qcom,spdm-client = <0>; + + qcom,bw-upstep = <450>; + qcom,bw-dwnstep = <8200>; + qcom,max-vote = <8200>; + qcom,up-step-multp = <2>; + qcom,spdm-interval = <30>; + + qcom,ports = <24>; + qcom,alpha-up = <8>; + qcom,alpha-down = <15>; + qcom,bucket-size = <8>; + + /*max pl1 freq, max pl2 freq*/ + qcom,pl-freqs = <210000 610000>; + + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,reject-rate = <5000 5000 5000 5000 5000 5000>; + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,response-time-us = <5000 5000 5000 5000 5000 5000>; + + /* pl1 low, pl1 high, pl2 low, pl2 high, pl3 low, pl3 high */ + qcom,cci-response-time-us = <10000 10000 10000 + 10000 10000 10000>; + qcom,max-cci-freq = <1036800>; + }; + + devfreq_spdm_gov { + compatible = "qcom,gov_spdm_hyp"; + interrupt-names = "spdm-irq"; + interrupts = <0 192 IRQ_TYPE_EDGE_RISING>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..72b71daa9e8d7423018c730d063fe454e2e1adad --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-cdp.dtsi @@ -0,0 +1,391 @@ +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-source = <&pm660l_flash0 &pm660l_flash1>; + qcom,torch-source = <&pm660l_torch0 &pm660l_torch1>; + qcom,switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + led_flash1: qcom,camera-flash@1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + qcom,flash-source = <&pm660l_flash2>; + qcom,torch-source = <&pm660l_torch2>; + qcom,switch-source = <&pm660l_switch1>; + status = "ok"; + }; + + cam_actuator_regulator: cam_actuator_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_actuator_regulator"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + enable-active-high; + gpio = <&tlmm 50 0>; + vin-supply = <&pm660l_bob>; + }; +}; + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + }; + + actuator2: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + qcom,cci-master = <0>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + status = "disabled"; + }; + + tof0: qcom,tof@29{ + cell-index = <0>; + reg = <0x29>; + compatible = "st,stmvl53l0"; + qcom,cci-master = <0>; + cam_laser-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_laser"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_tof_active>; + pinctrl-1 = <&cam_tof_suspend>; + stm,irq-gpio = <&tlmm 45 0x2008>; + gpios = <&tlmm 42 0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "RNG_EN"; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; + qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; + qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active + &cam_sensor_eldo4_default + &cam_actuator_vaf_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend + &cam_actuator_vaf_suspend>; + gpios = <&tlmm 32 0>, + <&tlmm 46 0>, + <&pm660l_gpios 4 0>, + <&tlmm 51 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-vaf = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA", + "CAM_VAF"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss MCLK0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK0_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; + qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; + qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active + &cam_sensor_eldo3_default>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 34 0>, + <&tlmm 48 0>, + <&pm660l_gpios 3 0>, + <&tlmm 51 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_VDIG", + "CAM_VANA"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + eeprom2: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; + qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; + qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active + &cam_actuator_vaf_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend + &cam_actuator_vaf_suspend>; + gpios = <&tlmm 33 0>, + <&tlmm 47 0>, + <&pm660_gpios 3 0>, + <&tlmm 44 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-vaf = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VDIG", + "CAM_VANA", + "CAM_VAF"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK1_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator0>; + qcom,ois-src = <&ois0>; + qcom,eeprom-src = <&eeprom0>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; + qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; + qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active + &cam_sensor_eldo4_default>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 32 0>, + <&tlmm 46 0>, + <&pm660l_gpios 4 0>, + <&tlmm 51 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss MCLK0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK0_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <2>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator1>; + qcom,eeprom-src = <&eeprom1>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; + qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; + qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active + &cam_sensor_eldo3_default>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 34 0>, + <&tlmm 48 0>, + <&pm660l_gpios 3 0>, + <&tlmm 51 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET", + "CAM_VDIG", + "CAM_VANA"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <2>; + qcom,csid-sd-index = <2>; + qcom,mount-angle = <90>; + qcom,actuator-src = <&actuator2>; + qcom,eeprom-src = <&eeprom2>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 1350000>; + qcom,cam-vreg-max-voltage = <1950000 3600000 1350000>; + qcom,cam-vreg-op-mode = <105000 80000 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active + &cam_sensor_eldo3_default>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 33 0>, + <&tlmm 47 0>, + <&pm660l_gpios 3 0>, + <&tlmm 51 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-vana = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VDIG", + "CAM_VANA"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK1_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; + +&pm660l_gpios { + cam_sensor_eldo3 { + cam_sensor_eldo3_default: cam_sensor_eldo3_default { + pins = "gpio3"; + function = "normal"; + output-enable; + bias-disable; + }; + }; + cam_sensor_eldo4 { + cam_sensor_eldo4_default: cam_sensor_eldo4_default { + pins = "gpio4"; + function = "normal"; + output-enable; + bias-disable; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4902dcde2bf58fe50bb59bea3870eda220b90bdd --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-mtp.dtsi @@ -0,0 +1,426 @@ +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-source = <&pm660l_flash0 &pm660l_flash1>; + qcom,torch-source = <&pm660l_torch0 &pm660l_torch1>; + qcom,switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + led_flash1: qcom,camera-flash@1 { + cell-index = <1>; + compatible = "qcom,camera-flash"; + qcom,flash-source = <&pm660l_flash2>; + qcom,torch-source = <&pm660l_torch2>; + qcom,switch-source = <&pm660l_switch1>; + status = "ok"; + }; + + cam_avdd_gpio_regulator: cam_avdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_avdd_gpio_regulator"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + enable-active-high; + gpio = <&tlmm 51 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_actuator_regulator: cam_actuator_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_actuator_regulator"; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + enable-active-high; + gpio = <&tlmm 50 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_dvdd_gpio_regulator: cam_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 3 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_eldo3_default>; + vin-supply = <&pm660_s5>; + }; + + cam_rear_dvdd_gpio_regulator: cam_rear_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_rear_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_eldo4_default>; + vin-supply = <&pm660_s5>; + }; +}; + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + }; + + actuator2: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + qcom,cci-master = <0>; + cam_vaf-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + qcom,cam-vreg-op-mode = <0>; + status = "disabled"; + }; + + tof0: qcom,tof@29{ + cell-index = <0>; + reg = <0x29>; + compatible = "st,stmvl53l0"; + qcom,cci-master = <0>; + cam_laser-supply = <&cam_actuator_regulator>; + qcom,cam-vreg-name = "cam_laser"; + qcom,cam-vreg-min-voltage = <3600000>; + qcom,cam-vreg-max-voltage = <3600000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_tof_active>; + pinctrl-1 = <&cam_tof_suspend>; + stm,irq-gpio = <&tlmm 45 0x2008>; + gpios = <&tlmm 42 0>; + qcom,gpio-req-tbl-num = <0>; + qcom,gpio-req-tbl-flags = <0>; + qcom,gpio-req-tbl-label = "RNG_EN"; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active + &cam_actuator_vaf_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend + &cam_actuator_vaf_suspend>; + gpios = <&tlmm 32 0>, + <&tlmm 46 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vaf = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VAF"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss MCLK0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK0_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 34 0>, + <&tlmm 48 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + eeprom2: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&pm660l_bob>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 3300000 0>; + qcom,cam-vreg-max-voltage = <1950000 3600000 0>; + qcom,cam-vreg-op-mode = <105000 80000 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active + &cam_actuator_vaf_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend + &cam_actuator_vaf_suspend>; + gpios = <&tlmm 33 0>, + <&tlmm 47 0>, + <&tlmm 44 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vana = <2>; + qcom,gpio-vaf = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA", + "CAM_VAF"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK1_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator0>; + qcom,ois-src = <&ois0>; + qcom,eeprom-src = <&eeprom0>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 32 0>, + <&tlmm 46 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss MCLK0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK0_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <2>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator1>; + qcom,eeprom-src = <&eeprom1>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 34 0>, + <&tlmm 48 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK", + "CAM_RESET"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <2>; + qcom,csid-sd-index = <2>; + qcom,mount-angle = <90>; + qcom,actuator-src = <&actuator2>; + qcom,eeprom-src = <&eeprom2>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 33 0>, + <&tlmm 47 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK1_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@3 { + cell-index = <3>; + compatible = "qcom,camera"; + reg = <0x03>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + qcom,led-flash-src = <&led_flash1>; + qcom,actuator-src = <&actuator2>; + qcom,eeprom-src = <&eeprom2>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_front_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_front_iris_suspend>; + gpios = <&tlmm 35 0>, + <&tlmm 52 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + clocks = <&clock_mmss MCLK3_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK3_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; + +&pm660l_gpios { + cam_sensor_eldo3 { + cam_sensor_eldo3_default: cam_sensor_eldo3_default { + pins = "gpio3"; + function = "normal"; + output-high; + bias-disable; + }; + }; + cam_sensor_eldo4 { + cam_sensor_eldo4_default: cam_sensor_eldo4_default { + pins = "gpio4"; + function = "normal"; + output-low; + bias-disable; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..5c79eaf176d61f2a561ba5b6478914e4da35f1b8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera-sensor-qrd.dtsi @@ -0,0 +1,415 @@ +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-source = <&pm660l_flash0 &pm660l_flash1>; + qcom,torch-source = <&pm660l_torch0 &pm660l_torch1>; + qcom,switch-source = <&pm660l_switch0>; + status = "ok"; + }; + + cam_avdd_gpio_regulator:cam_avdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_vadd_gpio_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + enable-active-high; + gpio = <&tlmm 51 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_vaf_gpio_regulator:cam_vaf_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_vaf_gpio_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + enable-active-high; + gpio = <&tlmm 50 0>; + vin-supply = <&pm660l_bob>; + }; + + cam_rear_dvdd_gpio_regulator: cam_rear_dvdd_fixed_regulator { + compatible = "regulator-fixed"; + regulator-name = "cam_rear_dvdd_gpio_regulator"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + enable-active-high; + gpio = <&pm660l_gpios 4 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_eldo4_default>; + vin-supply = <&pm660_s5>; + }; +}; + +&tlmm { + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET */ + mux { + pins = "gpio46"; + function = "gpio"; + }; + + config { + pins = "gpio46"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET */ + mux { + pins = "gpio46"; + function = "gpio"; + }; + + config { + pins = "gpio46"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET */ + mux { + pins = "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio48"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET */ + mux { + pins = "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio48"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&cam_vaf_gpio_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <1>; + cam_vaf-supply = <&cam_vaf_gpio_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + qcom,cci-master = <0>; + cam_vaf-supply = <&cam_vaf_gpio_regulator>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2800000>; + qcom,cam-vreg-max-voltage = <2800000>; + qcom,cam-vreg-op-mode = <0>; + status = "disabled"; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 32 0>, + <&tlmm 46 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET0"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss MCLK0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK0_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 34 0>, + <&tlmm 48 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + eeprom2: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 1352000>; + qcom,cam-vreg-max-voltage = <1950000 0 1352000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active + &cam_sensor_eldo3_default>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 33 0>, + <&tlmm 47 0>, + <&pm660l_gpios 3 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VDIG"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK1_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator0>; + qcom,ois-src = <&ois0>; + qcom,eeprom-src = <&eeprom0>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear_suspend>; + gpios = <&tlmm 32 0>, + <&tlmm 46 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET0"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_mmss MCLK0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK0_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash0>; + qcom,actuator-src = <&actuator1>; + qcom,eeprom-src = <&eeprom1>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&cam_rear_dvdd_gpio_regulator>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 0>; + qcom,cam-vreg-max-voltage = <1950000 0 0>; + qcom,cam-vreg-op-mode = <105000 0 0>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 34 0>, + <&tlmm 48 0>; + qcom,gpio-reset = <1>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK2_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <2>; + qcom,csid-sd-index = <2>; + qcom,mount-angle = <270>; + qcom,eeprom-src = <&eeprom2>; + cam_vio-supply = <&pm660_l11>; + cam_vana-supply = <&cam_avdd_gpio_regulator>; + cam_vdig-supply = <&pm660_s5>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vdig"; + qcom,cam-vreg-min-voltage = <1780000 0 1350000>; + qcom,cam-vreg-max-voltage = <1950000 0 1350000>; + qcom,cam-vreg-op-mode = <105000 0 105000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active + &cam_sensor_eldo3_default>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 33 0>, + <&tlmm 47 0>, + <&pm660l_gpios 3 0>; + qcom,gpio-reset = <1>; + qcom,gpio-vdig = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VDIG"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <1>; + status = "ok"; + clocks = <&clock_mmss MCLK1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_MCLK1_CLK>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; + +&pm660l_gpios { + cam_sensor_eldo3 { + cam_sensor_eldo3_default: cam_sensor_eldo3_default { + pins = "gpio3"; + function = "normal"; + output-high; + bias-disable; + }; + }; + cam_sensor_eldo4 { + cam_sensor_eldo4_default: cam_sensor_eldo4_default { + pins = "gpio4"; + function = "normal"; + output-low; + bias-disable; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-camera.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bd3827a97ce50846db042dd24e497150ef40255f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-camera.dtsi @@ -0,0 +1,864 @@ +&soc { + qcom,msm-cam@ca00000 { + compatible = "qcom,msm-cam"; + reg = <0xca00000 0x4000>; + reg-names = "msm-cam"; + status = "ok"; + bus-vectors = "suspend", "svs", "nominal", "turbo"; + qcom,bus-votes = <0 150000000 320000000 320000000>; + qcom,gpu-limit = <700000000>; + }; + + qcom,csiphy@c824000 { + cell-index = <0>; + compatible = "qcom,csiphy-v3.5", "qcom,csiphy"; + reg = <0xc824000 0x1000>, + <0xca00120 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 78 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csiphy"; + gdscr-supply = <&gdsc_camss_top>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "gdscr", "bimc_smmu"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss CSI0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI0_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID0_CLK>, + <&clock_mmss CSI0PHYTIMER_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI0PHYTIMER_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSIPHY0_CLK>, + <&clock_mmss MMSS_CSIPHY_AHB2CRIF_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "csi_src_clk", "csi_clk", "cphy_csid_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk", + "csiphy_ahb2crif"; + qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0 + 0 200000000 0 0>; + status = "ok"; + }; + + qcom,csiphy@c825000 { + cell-index = <1>; + compatible = "qcom,csiphy-v3.5", "qcom,csiphy"; + reg = <0xc825000 0x1000>, + <0xca00124 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 79 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csiphy"; + gdscr-supply = <&gdsc_camss_top>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "gdscr", "bimc_smmu"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss CSI1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI1_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID1_CLK>, + <&clock_mmss CSI1PHYTIMER_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI1PHYTIMER_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSIPHY1_CLK>, + <&clock_mmss MMSS_CSIPHY_AHB2CRIF_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "csi_src_clk", "csi_clk", "cphy_csid_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk", + "csiphy_ahb2crif"; + qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0 + 0 200000000 0 0>; + status = "ok"; + }; + + qcom,csiphy@c826000 { + cell-index = <2>; + compatible = "qcom,csiphy-v3.5", "qcom,csiphy"; + reg = <0xc826000 0x1000>, + <0xca00128 0x4>; + reg-names = "csiphy", "csiphy_clk_mux"; + interrupts = <0 80 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csiphy"; + gdscr-supply = <&gdsc_camss_top>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "gdscr", "bimc_smmu"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss CSI2_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI2_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID2_CLK>, + <&clock_mmss CSI2PHYTIMER_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI2PHYTIMER_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSIPHY2_CLK>, + <&clock_mmss MMSS_CSIPHY_AHB2CRIF_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "csi_src_clk", "csi_clk", "cphy_csid_clk", + "csiphy_timer_src_clk", "csiphy_timer_clk", + "camss_ispif_ahb_clk", "csiphy_clk_src", "csiphy_clk", + "csiphy_ahb2crif"; + qcom,clock-rates = <0 0 0 0 0 0 310000000 0 0 269333333 0 + 0 200000000 0 0>; + status = "ok"; + }; + + qcom,csid@ca30000 { + cell-index = <0>; + compatible = "qcom,csid-v5.0", "qcom,csid"; + reg = <0xca30000 0x400>; + reg-names = "csid"; + interrupts = <0 296 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm660_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm660l_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,cam-vreg-min-voltage = <925000 0 0>; + qcom,cam-vreg-max-voltage = <925000 0 0>; + qcom,cam-vreg-op-mode = <0 0 0>; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSI0_CLK_SRC>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI0_CLK>, + <&clock_mmss MMSS_CAMSS_CSI0_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_CSI0RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI0PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID0_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", + "csi_clk", "csi_ahb_clk", "csi_rdi_clk", + "csi_pix_clk", "cphy_csid_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 + 0 0 0 0 0>; + status = "ok"; + }; + + qcom,csid@ca30400 { + cell-index = <1>; + compatible = "qcom,csid-v5.0", "qcom,csid"; + reg = <0xca30400 0x400>; + reg-names = "csid"; + interrupts = <0 297 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm660_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm660l_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,cam-vreg-min-voltage = <925000 0 0>; + qcom,cam-vreg-max-voltage = <925000 0 0>; + qcom,cam-vreg-op-mode = <0 0 0>; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSI1_CLK_SRC>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI1_CLK>, + <&clock_mmss MMSS_CAMSS_CSI1_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_CSI1RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI1PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID1_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", + "csi_clk", "csi_ahb_clk", "csi_rdi_clk", + "csi_pix_clk", "cphy_csid_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 + 0 0 0 0 0>; + status = "ok"; + }; + + qcom,csid@ca30800 { + cell-index = <2>; + compatible = "qcom,csid-v5.0", "qcom,csid"; + reg = <0xca30800 0x400>; + reg-names = "csid"; + interrupts = <0 298 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm660_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm660l_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,cam-vreg-min-voltage = <925000 0 0>; + qcom,cam-vreg-max-voltage = <925000 0 0>; + qcom,cam-vreg-op-mode = <0 0 0>; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSI2_CLK_SRC>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI2_CLK>, + <&clock_mmss MMSS_CAMSS_CSI2_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_CSI2RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI2PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID2_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", + "csi_clk", "csi_ahb_clk", "csi_rdi_clk", + "csi_pix_clk", "cphy_csid_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 + 0 0 0 0 0>; + status = "ok"; + }; + + qcom,csid@ca30c00 { + cell-index = <3>; + compatible = "qcom,csid-v5.0", "qcom,csid"; + reg = <0xca30c00 0x400>; + reg-names = "csid"; + interrupts = <0 299 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "csid"; + qcom,csi-vdd-voltage = <1200000>; + qcom,mipi-csi-vdd-supply = <&pm660_l1>; + gdscr-supply = <&gdsc_camss_top>; + vdd_sec-supply = <&pm660l_l1>; + bimc_smmu-supply = <&gdsc_bimc_smmu>; + qcom,cam-vreg-name = "vdd_sec", "gdscr", "bimc_smmu"; + qcom,cam-vreg-min-voltage = <925000 0 0>; + qcom,cam-vreg-max-voltage = <925000 0 0>; + qcom,cam-vreg-op-mode = <0 0 0>; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSI3_CLK_SRC>, + <&clock_mmss CSIPHY_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI3_CLK>, + <&clock_mmss MMSS_CAMSS_CSI3_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_CSI3RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI3PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CPHY_CSID3_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", + "bmic_smmu_ahb", "bmic_smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "ispif_ahb_clk", "csi_src_clk", "csiphy_clk_src", + "csi_clk", "csi_ahb_clk", "csi_rdi_clk", + "csi_pix_clk", "cphy_csid_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 310000000 200000000 + 0 0 0 0 0>; + status = "ok"; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + qcom,iommu-dma-addr-pool = <0x00020000 0x78000000>; + status = "ok"; + + msm_cam_smmu_cb1 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&mmss_bimc_smmu 0xc00>, + <&mmss_bimc_smmu 0xc01>, + <&mmss_bimc_smmu 0xc02>, + <&mmss_bimc_smmu 0xc03>; + label = "vfe"; + qcom,scratch-buf-support; + }; + + msm_cam_smmu_cb2 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&mmss_bimc_smmu 0xa00>; + label = "cpp"; + }; + + msm_cam_smmu_cb4 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&mmss_bimc_smmu 0x800>; + label = "jpeg_enc0"; + }; + + msm_cam_smmu_cb5 { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&mmss_bimc_smmu 0x801>; + label = "jpeg_dma"; + }; + }; + + qcom,cpp@ca04000 { + cell-index = <0>; + compatible = "qcom,cpp"; + reg = <0xca04000 0x100>, + <0xca80000 0x3000>, + <0xca18000 0x3000>, + <0xc8c36D4 0x4>; + reg-names = "cpp", "cpp_vbif", "cpp_hw", "camss_cpp"; + interrupts = <0 294 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cpp"; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + camss-vdd-supply = <&gdsc_camss_top>; + vdd-supply = <&gdsc_cpp>; + qcom,vdd-names = "smmu-vdd", "camss-vdd", "vdd"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss CPP_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CPP_CLK>, + <&clock_mmss MMSS_CAMSS_CPP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_CPP_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_MICRO_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_CPP_VBIF_AHB_CLK>; + clock-names = "mmssnoc_axi_clk", + "mnoc_ahb_clk", + "camss_ahb_clk", "camss_top_ahb_clk", + "cpp_src_clk", + "cpp_core_clk", "camss_cpp_ahb_clk", + "camss_cpp_axi_clk", "micro_iface_clk", + "mmss_smmu_axi_clk", "cpp_vbif_ahb_clk"; + qcom,clock-rates = <0 0 0 0 200000000 200000000 0 0 0 0 0>; + qcom,min-clock-rate = <200000000>; + qcom,bus-master = <1>; + qcom,vbif-qos-setting = <0x550 0x55555555>, + <0x554 0x55555555>, + <0x558 0x55555555>, + <0x55c 0x55555555>, + <0x560 0x55555555>, + <0x564 0x55555555>, + <0x568 0x55555555>, + <0x56c 0x55555555>, + <0x570 0x55555555>, + <0x574 0x55555555>, + <0x578 0x55555555>, + <0x57c 0x55555555>, + <0x580 0x55555555>, + <0x584 0x55555555>, + <0x588 0x55555555>, + <0x58c 0x55555555>; + status = "ok"; + qcom,msm-bus,name = "msm_camera_cpp"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <106 512 0 0>, + <106 512 0 0>; + qcom,msm-bus-vector-dyn-vote; + qcom,cpp-cx-ipeak = <&cx_ipeak_lm 2>; + resets = <&clock_mmss CAMSS_MICRO_BCR>; + reset-names = "micro_iface_reset"; + qcom,src-clock-rates = <120000000 256000000 384000000 + 480000000 540000000 576000000>; + qcom,micro-reset; + qcom,cpp-fw-payload-info { + qcom,stripe-base = <790>; + qcom,plane-base = <715>; + qcom,stripe-size = <63>; + qcom,plane-size = <25>; + qcom,fe-ptr-off = <11>; + qcom,we-ptr-off = <23>; + qcom,ref-fe-ptr-off = <17>; + qcom,ref-we-ptr-off = <36>; + qcom,we-meta-ptr-off = <42>; + qcom,fe-mmu-pf-ptr-off = <7>; + qcom,ref-fe-mmu-pf-ptr-off = <10>; + qcom,we-mmu-pf-ptr-off = <13>; + qcom,dup-we-mmu-pf-ptr-off = <18>; + qcom,ref-we-mmu-pf-ptr-off = <23>; + qcom,set-group-buffer-len = <135>; + qcom,dup-frame-indicator-off = <70>; + }; + }; + + qcom,ispif@ca31000 { + cell-index = <0>; + compatible = "qcom,ispif-v3.0", "qcom,ispif"; + reg = <0xca31000 0xc00>, + <0xca00020 0x4>; + reg-names = "ispif", "csi_clk_mux"; + interrupts = <0 309 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ispif"; + qcom,num-isps = <0x2>; + camss-vdd-supply = <&gdsc_camss_top>; + vfe0-vdd-supply = <&gdsc_vfe0>; + vfe1-vdd-supply = <&gdsc_vfe1>; + qcom,vdd-names = "camss-vdd", "vfe0-vdd", + "vfe1-vdd"; + qcom,clock-cntl-support; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_ISPIF_AHB_CLK>, + <&clock_mmss CSI0_CLK_SRC>, + <&clock_mmss CSI1_CLK_SRC>, + <&clock_mmss CSI2_CLK_SRC>, + <&clock_mmss CSI3_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CSI0RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI1RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI2RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI3RDI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI0PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CSI1PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CSI2PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CSI3PIX_CLK>, + <&clock_mmss MMSS_CAMSS_CSI0_CLK>, + <&clock_mmss MMSS_CAMSS_CSI1_CLK>, + <&clock_mmss MMSS_CAMSS_CSI2_CLK>, + <&clock_mmss MMSS_CAMSS_CSI3_CLK>, + <&clock_mmss VFE0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE0_CLK>, + <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>, + <&clock_mmss VFE1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE1_CLK>, + <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb_clk", + "camss_ahb_clk", + "camss_top_ahb_clk", "ispif_ahb_clk", + "csi0_src_clk", "csi1_src_clk", + "csi2_src_clk", "csi3_src_clk", + "csi0_rdi_clk", "csi1_rdi_clk", + "csi2_rdi_clk", "csi3_rdi_clk", + "csi0_pix_clk", "csi1_pix_clk", + "csi2_pix_clk", "csi3_pix_clk", + "camss_csi0_clk", "camss_csi1_clk", + "camss_csi2_clk", "camss_csi3_clk", + "vfe0_clk_src", + "camss_vfe_vfe0_clk", + "camss_csi_vfe0_clk", + "vfe1_clk_src", + "camss_vfe_vfe1_clk", + "camss_csi_vfe1_clk"; + qcom,clock-rates = <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>; + qcom,clock-control = "INIT_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", + "INIT_RATE", "INIT_RATE", + "INIT_RATE", "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE", + "INIT_RATE", + "NO_SET_RATE", "NO_SET_RATE"; + status = "ok"; + }; + + vfe0: qcom,vfe0@ca10000 { + cell-index = <0>; + compatible = "qcom,vfe48"; + reg = <0xca10000 0x4000>, + <0xca40000 0x3000>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 314 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe0>; + camss-vdd-supply = <&gdsc_camss_top>; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + qcom,vdd-names = "vdd", "camss-vdd", "smmu-vdd"; + clocks = <&clock_mmss MMSS_THROTTLE_CAMSS_AXI_CLK>, + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss VFE0_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE0_CLK>, + <&clock_mmss MMSS_CAMSS_VFE0_STREAM_CLK>, + <&clock_mmss MMSS_CAMSS_VFE0_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>; + clock-names = "mmss_throttle_camss_axi_clk", "mmssnoc_axi", + "mnoc_ahb_clk", "bimc_smmu_ahb_clk", + "bimc_smmu_axi_clk", "camss_ahb_clk", + "camss_top_ahb_clk", "vfe_clk_src", + "camss_vfe_clk", "camss_vfe_stream_clk", + "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", + "camss_vfe_vbif_axi_clk", + "camss_csi_vfe_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; + status = "ok"; + qos-entries = <8>; + qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 + 0x41c 0x420>; + qos-settings = <0xaaa5aaa5 + 0xaaa5aaa5 + 0xaaa5aaa5 + 0xaa55aaa5 + 0xaa55aa55 + 0xaa55aa55 + 0xaa55aa55 + 0x0005aa55>; + vbif-entries = <3>; + vbif-regs = <0x124 0xac 0xd0>; + vbif-settings = <0x3 0x40 0x1010>; + ds-entries = <17>; + ds-regs = <0x424 0x428 0x42c 0x430 0x434 + 0x438 0x43c 0x440 0x444 0x448 0x44c + 0x450 0x454 0x458 0x45c 0x460 0x464>; + ds-settings = <0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0x110>; + qcom,msm-bus,name = "msm_camera_vfe"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <29 512 0 0>, + <29 512 100000000 100000000>; + qcom,msm-bus-vector-dyn-vote; + qcom,vfe-cx-ipeak = <&cx_ipeak_lm 2>; + }; + + vfe1: qcom,vfe1@ca14000 { + cell-index = <1>; + compatible = "qcom,vfe48"; + reg = <0xca14000 0x4000>, + <0xca40000 0x3000>; + reg-names = "vfe", "vfe_vbif"; + interrupts = <0 315 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "vfe"; + vdd-supply = <&gdsc_vfe1>; + camss-vdd-supply = <&gdsc_camss_top>; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + qcom,vdd-names = "vdd", "camss-vdd", "smmu-vdd"; + clocks = <&clock_mmss MMSS_THROTTLE_CAMSS_AXI_CLK>, + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss VFE1_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_VFE1_CLK>, + <&clock_mmss MMSS_CAMSS_VFE1_STREAM_CLK>, + <&clock_mmss MMSS_CAMSS_VFE1_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>; + clock-names = "mmss_throttle_camss_axi_clk", "mmssnoc_axi", + "mnoc_ahb_clk", "bimc_smmu_ahb_clk", + "bimc_smmu_axi_clk", "camss_ahb_clk", + "camss_top_ahb_clk", "vfe_clk_src", + "camss_vfe_clk", "camss_vfe_stream_clk", + "camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk", + "camss_vfe_vbif_axi_clk", + "camss_csi_vfe_clk"; + qcom,clock-rates = <0 0 0 0 0 0 0 404000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 480000000 0 0 0 0 0 0 + 0 0 0 0 0 0 0 576000000 0 0 0 0 0 0>; + status = "ok"; + qos-entries = <8>; + qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418 + 0x41c 0x420>; + qos-settings = <0xaaa5aaa5 + 0xaaa5aaa5 + 0xaaa5aaa5 + 0xaa55aaa5 + 0xaa55aa55 + 0xaa55aa55 + 0xaa55aa55 + 0x0005aa55>; + vbif-entries = <3>; + vbif-regs = <0x124 0xac 0xd0>; + vbif-settings = <0x3 0x40 0x1010>; + ds-entries = <17>; + ds-regs = <0x424 0x428 0x42c 0x430 0x434 + 0x438 0x43c 0x440 0x444 0x448 0x44c + 0x450 0x454 0x458 0x45c 0x460 0x464>; + ds-settings = <0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0xcccc1111 + 0x110>; + qcom,msm-bus,name = "msm_camera_vfe"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <29 512 0 0>, + <29 512 100000000 100000000>; + qcom,msm-bus-vector-dyn-vote; + qcom,vfe-cx-ipeak = <&cx_ipeak_lm 2>; + }; + + qcom,vfe { + compatible = "qcom,vfe"; + num_child = <2>; + }; + + cci: qcom,cci@ca0c000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xca0c000 0x4000>; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "cci"; + interrupts = <0 295 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "cci"; + status = "ok"; + mmagic-supply = <&gdsc_bimc_smmu>; + gdscr-supply = <&gdsc_camss_top>; + qcom,cam-vreg-name = "mmagic", "gdscr"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss CCI_CLK_SRC>, + <&clock_mmss MMSS_CAMSS_CCI_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_CCI_CLK>; + clock-names = "mmssnoc_axi", "mnoc_ahb", "smmu_ahb", "smmu_axi", + "camss_ahb_clk", "camss_top_ahb_clk", + "cci_src_clk", "cci_ahb_clk", "camss_cci_clk"; + qcom,clock-rates = <0 0 0 0 0 0 19200000 0 0>, + <0 0 0 0 0 0 37500000 0 0>; + pinctrl-names = "cci_default", "cci_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 36 0>, + <&tlmm 37 0>, + <&tlmm 38 0>, + <&tlmm 39 0>; + qcom,gpio-tbl-num = <0 1 2 3>; + qcom,gpio-tbl-flags = <1 1 1 1>; + qcom,gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + status = "disabled"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + status = "disabled"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + status = "disabled"; + }; + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + status = "disabled"; + }; + }; + + qcom,jpeg@ca1c000 { + cell-index = <0>; + compatible = "qcom,jpeg"; + reg = <0xca1c000 0x4000>, + <0xca60000 0x3000>; + reg-names = "jpeg_hw", "jpeg_vbif"; + interrupts = <0 316 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "jpeg"; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + camss-vdd-supply = <&gdsc_camss_top>; + qcom,vdd-names = "smmu-vdd", "camss-vdd"; + clock-names = "mmssnoc_axi", + "mmss_mnoc_ahb_clk", + "mmss_bimc_smmu_ahb_clk", + "mmss_bimc_smmu_axi_clk", + "mmss_camss_ahb_clk", + "mmss_camss_top_ahb_clk", + "core_clk", + "mmss_camss_jpeg_ahb_clk", + "mmss_camss_jpeg_axi_clk"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_JPEG0_VOTE_CLK>, + <&clock_mmss MMSS_CAMSS_JPEG_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_JPEG_AXI_CLK >; + qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0>; + qcom,vbif-reg-settings = <0x4 0x1>; + qcom,prefetch-reg-settings = <0x30c 0x1111>, + <0x318 0x31>, + <0x324 0x31>, + <0x330 0x31>, + <0x33c 0x0>; + qcom,msm-bus,name = "msm_camera_jpeg0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <62 512 0 0>, + <62 512 1200000 1200000>; + status = "ok"; + }; + + qcom,jpeg@caa0000 { + cell-index = <3>; + compatible = "qcom,jpegdma"; + reg = <0xcaa0000 0x4000>, + <0xca60000 0x3000>; + reg-names = "jpeg_hw", "jpeg_vbif"; + interrupts = <0 304 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "jpeg"; + smmu-vdd-supply = <&gdsc_bimc_smmu>; + camss-vdd-supply = <&gdsc_camss_top>; + qcom,vdd-names = "smmu-vdd", "camss-vdd"; + clock-names = "mmssnoc_axi", + "mmss_mnoc_ahb_clk", + "mmss_bimc_smmu_ahb_clk", + "mmss_bimc_smmu_axi_clk", + "mmss_camss_ahb_clk", + "mmss_camss_top_ahb_clk", + "core_clk", + "mmss_camss_jpeg_ahb_clk", + "mmss_camss_jpeg_axi_clk"; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_CAMSS_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_JPEG0_DMA_VOTE_CLK>, + <&clock_mmss MMSS_CAMSS_JPEG_AHB_CLK>, + <&clock_mmss MMSS_CAMSS_JPEG_AXI_CLK>; + qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0>; + qcom,vbif-reg-settings = <0x4 0x1>; + qcom,prefetch-reg-settings = <0x18c 0x11>, + <0x1a0 0x31>, + <0x1b0 0x31>; + qcom,msm-bus,name = "msm_camera_jpeg_dma"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <62 512 0 0>, + <62 512 1200000 1200000>; + qcom,max-ds-factor = <128>; + status = "ok"; + }; +}; + +&i2c_freq_100Khz { + qcom,hw-thigh = <201>; + qcom,hw-tlow = <174>; + qcom,hw-tsu-sto = <204>; + qcom,hw-tsu-sta = <231>; + qcom,hw-thd-dat = <22>; + qcom,hw-thd-sta = <162>; + qcom,hw-tbuf = <227>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; +}; + +&i2c_freq_400Khz { + qcom,hw-thigh = <38>; + qcom,hw-tlow = <56>; + qcom,hw-tsu-sto = <40>; + qcom,hw-tsu-sta = <40>; + qcom,hw-thd-dat = <22>; + qcom,hw-thd-sta = <35>; + qcom,hw-tbuf = <62>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; +}; + +&i2c_freq_custom { + qcom,hw-thigh = <38>; + qcom,hw-tlow = <56>; + qcom,hw-tsu-sto = <40>; + qcom,hw-tsu-sta = <40>; + qcom,hw-thd-dat = <22>; + qcom,hw-thd-sta = <35>; + qcom,hw-tbuf = <62>; + qcom,hw-scl-stretch-en = <1>; + qcom,hw-trdhld = <6>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; +}; + +&i2c_freq_1Mhz { + qcom,hw-thigh = <16>; + qcom,hw-tlow = <22>; + qcom,hw-tsu-sto = <17>; + qcom,hw-tsu-sta = <18>; + qcom,hw-thd-dat = <16>; + qcom,hw-thd-sta = <15>; + qcom,hw-tbuf = <24>; + qcom,hw-scl-stretch-en = <0>; + qcom,hw-trdhld = <3>; + qcom,hw-tsp = <3>; + qcom,cci-clk-src = <37500000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7d8eed8f4926d805f36b49247d3eeb28aff988b5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp-external-codec-overlay.dts @@ -0,0 +1,27 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Ext. Audio Codec CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp-internal-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp-internal-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..9b0ca33167a3152d2fc198042c3b096d3a2fcbb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp-internal-codec-overlay.dts @@ -0,0 +1,17 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-cdp.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Int. Audio Codec CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..078b778a8de4e08d5194895e74d812d1a308dca1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp.dts @@ -0,0 +1,24 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..6669065df39a2264d0b750c8f30fec9eee9de7d2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-cdp.dtsi @@ -0,0 +1,261 @@ +#include "sdm660-camera-sensor-cdp.dtsi" +/ { +}; + +&uartblsp1dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&ufsphy1 { + vdda-phy-supply = <&pm660l_l1>; + vdda-pll-supply = <&pm660_l10>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + qcom,vddp-ref-clk-supply = <&pm660_l1>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&pm660_gpios { + /* GPIO 4 (NFC_CLK_REQ) */ + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_6 { /* BLSP1 QUP6 (NFC) */ + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 28 0x00>; + qcom,nq-ven = <&tlmm 29 0x00>; + qcom,nq-firm = <&tlmm 30 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 31 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <28 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK3_PIN>; + clock-names = "ref_clk"; + }; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&pm660l_wled { + qcom,string-cfg= <6>; + status = "ok"; +}; + +&pm660l_lcdb { + status = "ok"; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_sharp_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 128 720 128 1440 128>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_truly_1080_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_truly_1080_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <2 2 4 2 1080 2>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; +}; + +&dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_hx8399c_truly_vid { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 55 0>; + qcom,aux-sel-gpio = <&tlmm 56 0>; + qcom,usbplug-cc-gpio = <&tlmm 58 0>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; + +&soc { + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; +}; + +&pm660_charger { + qcom,batteryless-platform; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-common.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1353983581db9376e3a845c381d40573332b6c0f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-common.dtsi @@ -0,0 +1,645 @@ +&soc { + ufsphy1: ufsphy@1da7000 { + compatible = "qcom,ufs-phy-qmp-v3-660"; + reg = <0x1da7000 0xdb8>; + reg-names = "phy_mem"; + #phy-cells = <0>; + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_UFS_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AUX_CLK>; + status = "disabled"; + }; + + ufs_ice: ufsice@1db0000 { + compatible = "qcom,ice"; + reg = <0x1db0000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_UFS_CLKREF_CLK>, + <&clock_gcc GCC_UFS_AHB_CLK>, + <&clock_gcc GCC_UFS_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&gdsc_ufs>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + + ufs1: ufshc@1da4000 { + compatible = "qcom,ufshc"; + reg = <0x1da4000 0x3000>; + interrupts = <0 265 IRQ_TYPE_LEVEL_HIGH>; + phys = <&ufsphy1>; + phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk"; + clocks = + <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&clock_gcc GCC_UFS_AHB_CLK>, + <&clock_gcc GCC_UFS_UNIPRO_CORE_CLK>, + <&clock_gcc GCC_UFS_ICE_CORE_CLK>, + <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_UFS_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_RX_SYMBOL_0_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + + lanes-per-direction = <1>; + + non-removable; + qcom,msm-bus,name = "ufs1"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <95 512 0 0>, <1 650 0 0>, /* No vote */ + <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */ + <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */ + <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */ + <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */ + <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */ + <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */ + <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RA */ + <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */ + <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */ + <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RB */ + <95 512 7643136 0>, <1 650 307200 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "MAX"; + + qcom,pm-qos-cpu-groups = <0x0F 0xF0>; + qcom,pm-qos-cpu-group-latency-us = <26 26>; + qcom,pm-qos-default-cpu = <0>; + + resets = <&clock_gcc GCC_UFS_BCR>; + reset-names = "core_reset"; + + status = "disabled"; + }; + + usb3: ssusb@a800000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a800000 0xfc100>, + <0x0c016000 0x400>; + reg-names = "core_base", + "ahb2phy_base"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 347 IRQ_TYPE_LEVEL_HIGH>, <0 243 IRQ_TYPE_LEVEL_HIGH>, <0 180 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", "ss_phy_irq", "pwr_event_irq"; + + USB3_GDSC-supply = <&gdsc_usb30>; + dpdm-supply = <&qusb_phy0>; + + qcom,msm-bus,name = "usb3"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <61 512 0 0>, + <61 512 240000 800000>; + + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + extcon = <&pm660_pdphy>; + qcom,pm-qos-latency = <41>; /* CPU-CLUSTER-WFI-LVL latency +1 */ + + clocks = <&clock_gcc GCC_USB30_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_USB3_AXI_CLK>, + <&clock_rpmcc AGGR2_NOC_USB_CLK>, + <&clock_gcc GCC_USB30_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_SLEEP_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_rpmcc CXO_DWC3_CLK>; + + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "noc_aggr_clk", "utmi_clk", "sleep_clk", + "cfg_ahb_clk", "xo"; + + qcom,core-clk-rate = <133330000>; + qcom,core-clk-rate-hs = <66666667>; + + resets = <&clock_gcc GCC_USB_30_BCR>; + reset-names = "core_reset"; + + dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0x0a800000 0xc8d0>; + interrupt-parent = <&intc>; + interrupts = <0 131 IRQ_TYPE_LEVEL_HIGH>; + usb-phy = <&qusb_phy0>, <&ssphy>; + tx-fifo-resize; + snps,usb3-u1u2-disable; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + dr_mode = "otg"; + linux,sysdev_is_parent; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,usb3_lpm_capable; + usb-core-id = <0>; + maximum-speed = "super-speed"; + }; + + qcom,usbbam@a904000 { + compatible = "qcom,usb-bam-msm"; + reg = <0x0a904000 0x17000>; + interrupt-parent = <&intc>; + interrupts = <0 132 IRQ_TYPE_LEVEL_HIGH>; + + qcom,bam-type = <0>; + qcom,usb-bam-fifo-baseaddr = <0x146bb000>; + qcom,usb-bam-num-pipes = <8>; + qcom,ignore-core-reset-ack; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-ipa-out-0"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <0>; + qcom,pipe-num = <0>; + qcom,peer-bam = <1>; + qcom,src-bam-pipe-index = <1>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + qcom,pipe1 { + label = "ssusb-ipa-in-0"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <1>; + qcom,dst-bam-pipe-index = <0>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + qcom,pipe2 { + label = "ssusb-qdss-in-0"; + qcom,usb-bam-mem-type = <2>; + qcom,dir = <1>; + qcom,pipe-num = <0>; + qcom,peer-bam = <0>; + qcom,peer-bam-physical-address = <0x06064000>; + qcom,src-bam-pipe-index = <0>; + qcom,dst-bam-pipe-index = <3>; + qcom,data-fifo-offset = <0x0>; + qcom,data-fifo-size = <0x1800>; + qcom,descriptor-fifo-offset = <0x1800>; + qcom,descriptor-fifo-size = <0x800>; + }; + qcom,pipe3 { + label = "ssusb-dpl-ipa-in-1"; + qcom,usb-bam-mem-type = <1>; + qcom,dir = <1>; + qcom,pipe-num = <1>; + qcom,peer-bam = <1>; + qcom,dst-bam-pipe-index = <2>; + qcom,data-fifo-size = <0x8000>; + qcom,descriptor-fifo-size = <0x2000>; + }; + }; + }; + + qusb_phy0: qusb@c012000 { + compatible = "qcom,qusb2phy"; + reg = <0x0c012000 0x180>, + <0x01fcb24c 0x4>, + <0x00780240 0x4>, + <0x00188018 0x4>; + reg-names = "qusb_phy_base", + "tcsr_clamp_dig_n_1p8", + "tune2_efuse_addr", + "ref_clk_addr"; + vdd-supply = <&pm660l_l1>; + vdda18-supply = <&pm660_l10>; + vdda33-supply = <&pm660l_l7>; + qcom,vdd-voltage-level = <0 925000 925000>; + qcom,tune2-efuse-bit-pos = <25>; + qcom,tune2-efuse-num-bits = <4>; + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0xb3 0x84 + 0x83 0x88 + 0xc0 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; + phy_type= "utmi"; + qcom,phy-clk-scheme = "cml"; + qcom,major-rev = <1>; + + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_RX0_USB2_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + + clock-names = "ref_clk_src", "ref_clk", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + ssphy: ssphy@c010000 { + compatible = "qcom,usb-ssphy-qmp-usb3-or-dp"; + reg = <0xc010000 0xe18>, + <0x01fcb244 0x4>, + <0x01fcb248 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg", + "tcsr_usb3_dp_phymode"; + vdd-supply = <&pm660l_l1>; + core-supply = <&pm660_l10>; + qcom,vdd-voltage-level = <0 925000 925000>; + qcom,core-voltage-level = <0 1800000 1800000>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + <0xac 0x14 0x00 + 0x34 0x08 0x00 + 0x174 0x30 0x00 + 0x3c 0x06 0x00 + 0xb4 0x00 0x00 + 0xb8 0x08 0x00 + 0x70 0x0f 0x00 + 0x19c 0x01 0x00 + 0x178 0x00 0x00 + 0xd0 0x82 0x00 + 0xdc 0x55 0x00 + 0xe0 0x55 0x00 + 0xe4 0x03 0x00 + 0x78 0x0b 0x00 + 0x84 0x16 0x00 + 0x90 0x28 0x00 + 0x108 0x80 0x00 + 0x10c 0x00 0x00 + 0x184 0x0a 0x00 + 0x4c 0x15 0x00 + 0x50 0x34 0x00 + 0x54 0x00 0x00 + 0xc8 0x00 0x00 + 0x18c 0x00 0x00 + 0xcc 0x00 0x00 + 0x128 0x00 0x00 + 0x0c 0x0a 0x00 + 0x10 0x01 0x00 + 0x1c 0x31 0x00 + 0x20 0x01 0x00 + 0x14 0x00 0x00 + 0x18 0x00 0x00 + 0x24 0xde 0x00 + 0x28 0x07 0x00 + 0x48 0x0f 0x00 + 0x194 0x06 0x00 + 0x100 0x80 0x00 + 0xa8 0x01 0x00 + 0x430 0x0b 0x00 + 0x830 0x0b 0x00 + 0x444 0x00 0x00 + 0x844 0x00 0x00 + 0x43c 0x00 0x00 + 0x83c 0x00 0x00 + 0x440 0x00 0x00 + 0x840 0x00 0x00 + 0x408 0x0a 0x00 + 0x808 0x0a 0x00 + 0x414 0x06 0x00 + 0x814 0x06 0x00 + 0x434 0x75 0x00 + 0x834 0x75 0x00 + 0x4d4 0x02 0x00 + 0x8d4 0x02 0x00 + 0x4d8 0x4e 0x00 + 0x8d8 0x4e 0x00 + 0x4dc 0x18 0x00 + 0x8dc 0x18 0x00 + 0x4f8 0x77 0x00 + 0x8f8 0x77 0x00 + 0x4fc 0x80 0x00 + 0x8fc 0x80 0x00 + 0x4c0 0x0a 0x00 + 0x8c0 0x0a 0x00 + 0x504 0x03 0x00 + 0x904 0x03 0x00 + 0x50c 0x16 0x00 + 0x90c 0x16 0x00 + 0x500 0x00 0x00 + 0x900 0x00 0x00 + 0x564 0x00 0x00 + 0x964 0x00 0x00 + 0x260 0x10 0x00 + 0x660 0x10 0x00 + 0x2a4 0x12 0x00 + 0x6a4 0x12 0x00 + 0x28c 0xc6 0x00 + 0x68c 0xc6 0x00 + 0x244 0x00 0x00 + 0x644 0x00 0x00 + 0x248 0x00 0x00 + 0x648 0x00 0x00 + 0xc0c 0x9f 0x00 + 0xc24 0x17 0x00 + 0xc28 0x0f 0x00 + 0xcc8 0x83 0x00 + 0xcc4 0x02 0x00 + 0xccc 0x09 0x00 + 0xcd0 0xa2 0x00 + 0xcd4 0x85 0x00 + 0xc80 0xd1 0x00 + 0xc84 0x1f 0x00 + 0xc88 0x47 0x00 + 0xcb8 0x75 0x00 + 0xcbc 0x13 0x00 + 0xcb0 0x86 0x00 + 0xca0 0x04 0x00 + 0xc8c 0x44 0x00 + 0xc70 0xe7 0x00 + 0xc74 0x03 0x00 + 0xc78 0x40 0x00 + 0xc7c 0x00 0x00 + 0xdd8 0x88 0x00 + 0xffffffff 0xffffffff 0x00>; + + qcom,qmp-phy-reg-offset = + <0xd74 /* USB3_PHY_PCS_STATUS */ + 0xcd8 /* USB3_PHY_AUTONOMOUS_MODE_CTRL */ + 0xcdc /* USB3_PHY_LFPS_RXTERM_IRQ_CLEAR */ + 0xc04 /* USB3_PHY_POWER_DOWN_CONTROL */ + 0xc00 /* USB3_PHY_SW_RESET */ + 0xc08 /* USB3_PHY_START */ + 0xa00>; /* USB3PHY_PCS_MISC_TYPEC_CTRL */ + + clocks = <&clock_gcc GCC_USB3_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_PHY_PIPE_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_USB3_CLKREF_CLK>; + + clock-names = "aux_clk", "pipe_clk", "cfg_ahb_clk", + "ref_clk_src", "ref_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&lpass_q6_smmu 6>; + qcom,usb-audio-stream-id = <6>; + qcom,usb-audio-intr-num = <2>; + }; + + usb2s: hsusb@c200000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0c200000 0xfc000>, + <0x0c016000 0x400>; + reg-names = "core_base", + "ahb2phy_base"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 348 IRQ_TYPE_LEVEL_HIGH>, <0 144 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", "pwr_event_irq"; + + qcom,msm-bus,name = "usb-hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <87 512 0 0>, + <87 512 60000 800000>; + + qcom,pm-qos-latency = <52>; /* CPU-CLUSTER-WFI-LVL latency +1 */ + clocks = <&clock_gcc GCC_USB20_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB2_AXI_CLK>, + <&clock_gcc GCC_USB20_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB20_SLEEP_CLK>, + <&clock_rpmcc CXO_DWC3_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "core_clk", "iface_clk", "utmi_clk", "sleep_clk", + "xo", "cfg_ahb_clk"; + qcom,core-clk-rate = <60000000>; + resets = <&clock_gcc GCC_USB_20_BCR>; + reset-names = "core_reset"; + + status = "disabled"; + dwc3@c200000 { + compatible = "snps,dwc3"; + reg = <0x0c200000 0xc8d0>; + interrupt-parent = <&intc>; + interrupts = <0 143 IRQ_TYPE_LEVEL_HIGH>; + usb-phy = <&qusb_phy1>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + dr_mode = "host"; + }; + }; + + qusb_phy1: qusb@c014000 { + compatible = "qcom,qusb2phy"; + reg = <0x0c014000 0x180>, + <0x00188014 0x4>; + reg-names = "qusb_phy_base", + "ref_clk_addr"; + vdd-supply = <&pm660l_l1>; + vdda18-supply = <&pm660_l10>; + vdda33-supply = <&pm660l_l7>; + qcom,vdd-voltage-level = <0 925000 925000>; + qcom,qusb-phy-init-seq = <0xF8 0x80 + 0xB3 0x84 + 0x83 0x88 + 0xC0 0x8C + 0x30 0x08 + 0x79 0x0C + 0x21 0x10 + 0x14 0x9C + 0x9F 0x1C + 0x00 0x18>; + phy_type = "utmi"; + qcom,phy-clk-scheme = "cml"; + qcom,major-rev = <1>; + qcom,hold-reset; + + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_RX1_USB2_CLKREF_CLK>, + <&clock_rpmcc RPM_SMD_LN_BB_CLK1>; + clock-names = "cfg_ahb_clk", "ref_clk", "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + sdhc_1: sdhci@c0c4000 { + compatible = "qcom,sdhci-msm-v5", "qcom,sdhci-msm-cqe"; + reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>, + <0xc0c8000 0x8000>; + reg-names = "hc_mem", "cqhci_mem", "cqhci_ice"; + + interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>, <0 112 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <43 518>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cmdq-latency-us = <43 518>, <40 518>; + qcom,pm-qos-legacy-latency-us = <43 518>, <40 518>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <78 512 0 0>, <1 606 0 0>, + /* 400 KB/s*/ + <78 512 1046 1600>, + <1 606 1600 1600>, + /* 20 MB/s */ + <78 512 52286 80000>, + <1 606 80000 80000>, + /* 25 MB/s */ + <78 512 65360 100000>, + <1 606 100000 100000>, + /* 50 MB/s */ + <78 512 130718 200000>, + <1 606 133320 133320>, + /* 100 MB/s */ + <78 512 130718 200000>, + <1 606 150000 150000>, + /* 200 MB/s */ + <78 512 261438 400000>, + <1 606 300000 300000>, + /* 400 MB/s */ + <78 512 261438 400000>, + <1 606 300000 300000>, + /* Max. bandwidth */ + <78 512 1338562 4096000>, + <1 606 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 192000000 384000000>; + + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + qcom,ice-clk-rates = <300000000 75000000>; + + qcom,scaling-lower-bus-speed-mode = "DDR52"; + + status = "disabled"; + }; + + sdhc_2: sdhci@c084000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0xc084000 0x1000>; + reg-names = "hc_mem"; + + interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>, <0 221 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 1600>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 80000>, + <1 608 80000 80000>, + /* 25 MB/s */ + <81 512 65360 100000>, + <1 608 100000 100000>, + /* 50 MB/s */ + <81 512 130718 200000>, + <1 608 133320 133320>, + /* 100 MB/s */ + <81 512 261438 200000>, + <1 608 150000 150000>, + /* 200 MB/s */ + <81 512 261438 400000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,pm-qos-irq-type = "affine_irq"; + qcom,pm-qos-irq-latency = <43 518>; + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-legacy-latency-us = <43 518>, <40 518>; + + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", + "SDR104"; + + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-coresight.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-coresight.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..041e8a4dd5f2a810dde963e72d7606f63e9df711 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-coresight.dtsi @@ -0,0 +1,1687 @@ +#include +#include +#include + +&soc { + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + qcom,blk-size = <1>; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + arm,buffer-size = <0x400000>; + arm,sg-enable; + arm,default-sink; + coresight-csr = <&csr>; + + coresight-ctis = <&cti0 &cti8>; + + coresight-name = "coresight-tmc-etr"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports{ + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr:endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + port@1 { + reg = <0>; + replicator_in_tmc_etf:endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + + coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; + arm,default-sink; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports{ + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator:endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg:endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf:endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0:endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1:endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + }; + }; + + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + port@2 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + port@3 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + port@4 { + reg = <0>; + funnel_in0_in_rpm_etm0: endpoint { + slave-mode; + remote-endpoint = + <&rpm_etm0_out_funnel_in0>; + }; + }; + }; + }; + + funnel_in1: funnel@6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + port@1 { + reg = <2>; + funnel_in1_in_tpda_nav: endpoint { + slave-mode; + remote-endpoint = + <&tpda_nav_out_funnel_in1>; + }; + }; + port@2 { + reg = <5>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + port@3 { + reg = <6>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + port@4 { + reg = <4>; + funnel_in1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_in1>; + }; + }; + }; + }; + + funnel_apss_merg: funnel@7b70000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7b70000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + port@2 { + reg = <1>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + port@3 { + reg = <3>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + funnel_apss: funnel@7b60000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7b60000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + etm0: etm@7840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7840000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7940000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7940000 0x1000>; + cpu = <&CPU1>; + + coresight-name = "coresight-etm1"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7a40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7a40000 0x1000>; + cpu = <&CPU2>; + + coresight-name = "coresight-etm2"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7b40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7b40000 0x1000>; + cpu = <&CPU3>; + + coresight-name = "coresight-etm3"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7c40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7c40000 0x1000>; + cpu = <&CPU4>; + + coresight-name = "coresight-etm4"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7d40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7d40000 0x1000>; + cpu = <&CPU5>; + + coresight-name = "coresight-etm5"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7e40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7e40000 0x1000>; + cpu = <&CPU6>; + + coresight-name = "coresight-etm6"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7f40000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7f40000 0x1000>; + cpu = <&CPU7>; + + coresight-name = "coresight-etm7"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + port{ + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + reg = <0x6010000 0x1000>; + arm,primecell-periphid = <0x0003b966>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + qcom,cti-gpio-trigout = <4>; + pinctrl-names = "cti-trigout-pctrl"; + pinctrl-0 = <&trigout_a>; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu0: cti@7820000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x7820000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu1: cti@7920000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7920000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu2: cti@7a20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7a20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu3: cti@7b20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7b20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu4: cti@7c20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu5: cti@7d20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7d20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu6: cti@7e20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7e20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_cpu7: cti@7f20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7f20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_apss: cti@7b80000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7b80000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_apss_dl: cti@7bc1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7bc1000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss-dl"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_olc: cti@7b91000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7b91000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-olc"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_turing: cti@7068000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7068000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_wcss0: cti@71a4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x71a4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss0"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + status = "disabled"; + }; + + cti_wcss1: cti@71a5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x71a5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss1"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + status = "disabled"; + }; + + cti_wcss2: cti@71a6000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x71a6000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcss2"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + status = "disabled"; + }; + + cti_mmss: cti@7188000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7188000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mmss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_isdb: cti@7121000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7121000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-isdb"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + status = "disabled"; + }; + + cti_rpm: cti@7048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7048000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-rpm"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + cti_mss: cti@7041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7041000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + port@2 { + reg = <3>; + funnel_qatb_in_funnel_dlct: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct_out_funnel_qatb>; + }; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "qcom,coresight-tpda"; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <8 32>, + <10 32>; + qcom,tc-elem-size = <4 32>, + <7 32>, + <10 32>; + qcom,dsb-elem-size = <2 32>, + <8 32>, + <10 32>, + <11 32>; + qcom,cmb-elem-size = <4 32>, + <5 32>, + <6 32>, + <10 64>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + }; + port@2 { + reg = <2>; + tpda_in_funnel_dlct: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dlct_out_tpda>; + }; + }; + port@3 { + reg = <4>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + port@4 { + reg = <5>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + port@5 { + reg = <6>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + port@6 { + reg = <8>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + port@7 { + reg = <10>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + port@8 { + reg = <11>; + tpda_in_tpdm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_out_tpda>; + }; + }; + }; + }; + + tpdm_vsense: tpdm@7038000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7038000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_dcc: tpdm@7054000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7054000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + tpdm_prng: tpdm@704c000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x704c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_qm: tpdm@71d0000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x71d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_qm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_qm>; + }; + }; + }; + + tpdm_pimem: tpdm@7050000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7050000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + + tpdm: tpdm@6006000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x6006000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm"; + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm>; + }; + }; + }; + + tpda_nav: tpda@7191000 { + compatible = "qcom,coresight-tpda"; + reg = <0x7191000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-nav"; + + qcom,tpda-atid = <68>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_nav_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpda_nav>; + }; + }; + port@1 { + reg = <0>; + tpda_nav_in_tpdm_nav: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_nav_out_tpda_nav>; + }; + }; + }; + }; + + tpda_apss: tpda@7bc2000 { + compatible = "qcom,coresight-tpda"; + reg = <0x7bc2000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7bc0000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7bc0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_mss: tpda@7043000 { + compatible = "qcom,coresight-tpda"; + reg = <0x7043000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-mss"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_mss_out_funnel_dlct: endpoint { + remote-endpoint = + <&funnel_dlct_in_tpda_mss>; + }; + }; + port@1 { + reg = <0>; + tpda_mss_in_tpdm_mss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mss_out_tpda_mss>; + }; + }; + }; + }; + + tpdm_mss: tpdm@7042000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7042000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mss"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_mss_out_tpda_mss: endpoint { + remote-endpoint = <&tpda_mss_in_tpdm_mss>; + }; + }; + }; + + tpdm_nav: tpdm@7190000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7190000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-nav"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_nav_out_tpda_nav: endpoint { + remote-endpoint = <&tpda_nav_in_tpdm_nav>; + }; + }; + }; + + tpda_olc: tpda@7b92000 { + compatible = "qcom,coresight-tpda"; + reg = <0x7b92000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7b90000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x7b90000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + funnel_dlct: funnel@71c3000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x71c3000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dlct"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "apb_pclk", "core_a_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dlct_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dlct>; + }; + }; + port@1 { + reg = <1>; + funnel_dlct_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_dlct>; + }; + }; + port@2 { + reg = <0>; + funnel_dlct_in_tpdm_dlct: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dlct_out_funnel_dlct>; + }; + }; + port@4 { + reg = <1>; + funnel_dlct_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_dlct>; + }; + }; + port@5 { + reg = <2>; + funnel_dlct_in_tpda_mss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_mss_out_funnel_dlct>; + }; + }; + }; + }; + + tpdm_dlct: tpdm@71c2000 { + compatible = "qcom,coresight-tpdm"; + reg = <0x71c2000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dlct"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + port{ + tpdm_dlct_out_funnel_dlct: endpoint { + remote-endpoint = <&funnel_dlct_in_tpdm_dlct>; + }; + }; + }; + + hwevent: hwevent@158000 { + compatible = "qcom,coresight-hwevent"; + reg = <0x158000 0x80>, + <0x17091000 0x80>, + <0x1730200c 0x4>, + <0xc90137c 0x4>, + <0xc828018 0x80>, + <0x1c00058 0x80>, + <0x5e02038 0x4>, + <0x5e02028 0x10>, + <0x1fcb360 0x80>, + <0x1fcb760 0x80>, + <0x1fcbf60 0x80>, + <0xa8f8860 0x4>, + <0x500c260 0x4>, + <0x500d040 0x4>, + <0x1da6400 0x80>; + reg-names = "gcc-ctrl", "lpass-stm", "lpass-qdsp", "mdss-mdp", + "mdss-misc", "pcie0-hwev", "ssc-en", "ssc-hwev", + "tcsr-qdss", "tcsr-mss0", "tcsr-mss1", "usb-ctrl", + "vbif-stm", "vbif-stm-en", "ufs-mux"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>, + <&clock_mmss MMSS_MISC_AHB_CLK>; + clock-names = "apb_pclk", "core_a_clk", "core_mmss_clk"; + + qcom,hwevent-clks = "core_mmss_clk"; + }; + + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port{ + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port{ + audio_etm0_out_funnel_dlct: endpoint { + remote-endpoint = <&funnel_dlct_in_audio_etm0>; + }; + }; + }; + + rpm_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-rpm-etm0"; + qcom,inst-id = <4>; + + port{ + rpm_etm0_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_rpm_etm0>; + }; + }; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_in1: endpoint { + remote-endpoint = <&funnel_in1_in_turing_etm0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-external-codec.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-external-codec.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..3830da906c13e6f9ab4b7a2e7e83c8e75f52cb46 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-external-codec.dtsi @@ -0,0 +1,23 @@ +&cdc_pdm_gpios { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&cdc_dmic_gpios { + status = "disabled"; +}; + +&cdc_sdw_gpios { + status = "disabled"; +}; + +&wsa_spkr_en1 { + status = "disabled"; +}; + +&wsa_spkr_en2 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-gpu.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-gpu.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c8346e510c92ad88a23de0e73f41268cf111fb0a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-gpu.dtsi @@ -0,0 +1,692 @@ +&soc { + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a512_zap"; + }; + + msm_bus: qcom,kgsl-busmon{ + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpu_bw_tbl: gpu-bw-tbl { + compatible = "operating-points-v2"; + opp-0 { opp-hz = /bits/ 64 < 0 >; }; /* OFF */ + opp-100 { opp-hz = /bits/ 64 < 381 >; }; /* 1.100 MHz */ + opp-150 { opp-hz = /bits/ 64 < 572 >; }; /* 2.150 MHz */ + opp-200 { opp-hz = /bits/ 64 < 762 >; }; /* 3.200 MHz */ + opp-300 { opp-hz = /bits/ 64 < 1144 >; }; /* 4.300 MHz */ + opp-412 { opp-hz = /bits/ 64 < 1571 >; }; /* 5.412 MHz */ + opp-547 { opp-hz = /bits/ 64 < 2086 >; }; /* 6.547 MHz */ + opp-681 { opp-hz = /bits/ 64 < 2597 >; }; /* 7.681 MHz */ + opp-768 { opp-hz = /bits/ 64 < 2929 >; }; /* 8.768 MHz */ + opp-1017 { opp-hz = /bits/ 64 < 3879 >; }; /* 9.1017 MHz */ + opp-1296 { opp-hz = /bits/ 64 < 4943 >; }; /* 10.1296 MHz */ + opp-1353 { opp-hz = /bits/ 64 < 5161 >; }; /* 11.1353 MHz */ + opp-1555 { opp-hz = /bits/ 64 < 5931 >; }; /* 12.1555 MHz */ + opp-1804 { opp-hz = /bits/ 64 < 6881 >; }; /* 13.1804 MHz */ + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + operating-points-v2 = <&gpu_bw_tbl>; + /* + * active-only flag is used while registering the bus + * governor. It helps release the bus vote when the CPU + * subsystem is inactive + */ + qcom,active-only; + }; + + msm_gpu: qcom,kgsl-3d0@5000000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x5000000 0x40000 + 0x780000 0x6220>; + reg-names = "kgsl_3d0_reg_memory", "qfprom_memory"; + interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x05010200>; + + qcom,initial-pwrlevel = <6>; + + /* */ + qcom,idle-timeout = <80>; + + qcom,highest-bank-bit = <14>; + + /* size in bytes */ + qcom,snapshot-size = <1048576>; + #cooling-cells = <2>; + + clocks = <&clock_gfx GPUCC_GFX3D_CLK>, + <&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gfx GPUCC_RBBMTIMER_CLK>, + <&clock_gcc GCC_GPU_BIMC_GFX_CLK>, + <&clock_gcc GCC_BIMC_GFX_CLK>, + <&clock_gpu GPUCC_RBCPR_CLK>; + + clock-names = "core_clk", "iface_clk", "rbbmtimer_clk", + "mem_clk", "alt_mem_iface_clk", "rbcpr_clk"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + /* GPU to BIMC bus width, VBIF data transfer in 1 cycle */ + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <14>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + + <26 512 0 400000>, /* 1 bus=100 */ + <26 512 0 600000>, /* 2 bus=150 */ + <26 512 0 800000>, /* 3 bus=200 */ + <26 512 0 1200000>, /* 4 bus=300 */ + <26 512 0 1648000>, /* 5 bus=412 */ + <26 512 0 2188000>, /* 6 bus=547 */ + <26 512 0 2724000>, /* 7 bus=681 */ + <26 512 0 3072000>, /* 8 bus=768 */ + <26 512 0 4068000>, /* 9 bus=1017 */ + <26 512 0 5184000>, /* 10 bus=1296 */ + <26 512 0 5412000>, /* 11 bus=1353 */ + <26 512 0 6220000>, /* 12 bus=1555 */ + <26 512 0 7216000>; /* 13 bus=1804 */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gdsc_gpu_cx>; + vdd-supply = <&gdsc_gpu_gx>; + + /* Cx ipeak limit supprt */ + qcom,gpu-cx-ipeak = <&cx_ipeak_lm 1>; + qcom,gpu-cx-ipeak-clk = <700000000>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <518>; + qcom,pm-qos-wakeup-latency = <518>; + + /* Quirks */ + qcom,gpu-quirk-dp2clockgating-disable; + qcom,gpu-quirk-lmloadkill-disable; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <4>; + + qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>; + + /* GPU Mempools */ + qcom,gpu-mempools { + #address-cells= <1>; + #size-cells = <0>; + compatible = "qcom,gpu-mempools"; + + qcom,mempool-max-pages = <32768>; + + /* 4K Page Pool configuration */ + qcom,gpu-mempool@0 { + reg = <0>; + qcom,mempool-page-size = <4096>; + }; + /* 64K Page Pool configuration */ + qcom,gpu-mempool@1 { + reg = <1>; + qcom,mempool-page-size = <65536>; + qcom,mempool-allocate; + }; + }; + + /* + * Speed-bin zero is default speed bin. + * For rest of the speed bins, speed-bin value + * is calulated as FMAX/4.8 MHz round up to zero + * decimal places. + */ + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <6>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <750000000>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; + qcom,bus-max = <13>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <11>; + qcom,bus-max = <13>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <647000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <588000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <9>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@8 { + reg = <8>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <157>; + + qcom,initial-pwrlevel = <6>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <750000000>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; + qcom,bus-max = <13>; + }; + + /* TURBO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <11>; + qcom,bus-max = <13>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <647000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <588000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <9>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@8 { + reg = <8>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <146>; + + qcom,initial-pwrlevel = <5>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <700000000>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; + qcom,bus-max = <13>; + }; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <647000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <588000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <9>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <135>; + + qcom,initial-pwrlevel = <4>; + + /* NOM_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <647000000>; + qcom,bus-freq = <13>; + qcom,bus-min = <12>; + qcom,bus-max = <13>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <588000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <9>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-4 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <78>; + + qcom,initial-pwrlevel = <1>; + + /* SVS */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <11>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-5 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <90>; + + qcom,initial-pwrlevel = <2>; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <430000000>; + qcom,bus-freq = <11>; + qcom,bus-min = <10>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <11>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-6 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <122>; + + qcom,initial-pwrlevel = <3>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <585000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <11>; + qcom,bus-max = <12>; + }; + + /* SVS_L1 */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <465000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <370000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <6>; + qcom,bus-max = <9>; + }; + + /* Low SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <266000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <6>; + }; + + /* Min SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <160000000>; + qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x05040000 0x10000>; + qcom,protect = <0x40000 0x10000>; + qcom,micro-mmu-control = <0x6000>; + + clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gcc GCC_GPU_BIMC_GFX_CLK>, + <&clock_gcc GCC_BIMC_GFX_CLK>; + + clock-names = "iface_clk", "mem_clk", "alt_mem_iface_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,iommu-dma = "disabled"; + qcom,gpu-offset = <0x48000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 2>; + qcom,iommu-dma = "disabled"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-headset-jacktype-no-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-headset-jacktype-no-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..68c7a25710ebd4eb150c31d41f2773b4269eaaaf --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-headset-jacktype-no-cdp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, Headset + Jacktype NO, CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-headset-jacktype-no-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-headset-jacktype-no-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..19f1311575ba97fa27704f07bb366abb961092b0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-headset-jacktype-no-rcm.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, Headset + Jacktype NO, RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..334f46bd442fea7a38d7e802d4b0f47812316731 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-cdp.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L Int. Audio + Codec CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..d71a98e4bf7d7947fd19159dda4389055e42dee5 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-mtp.dts @@ -0,0 +1,19 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-mtp.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L Int. Audio + Codec MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&int_codec { + qcom,model = "sdm660-snd-card-mtp"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..e6fc46c24ce2d41ea5cde6c4df5911f9220a5211 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-cdp.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A Int. Audio + Codec CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ac850e72ba5ee2886b29a6e6073211511799618f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-mtp.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-mtp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A Int. Audio + Codec MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&int_codec { + qcom,model = "sdm660-snd-card-mtp"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..516fb5c753768830f0c48b4fb9d07fe28644a4b1 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-pm660a-rcm.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A Int. Audio + Codec RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..60628b2b3b83e20adbb2b99b5955d9eba2e59067 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec-rcm.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L Int. Audio + Codec RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9c899be7e14151c8498dc0eb243a3de8e0679fe7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-internal-codec.dtsi @@ -0,0 +1,63 @@ +&slim_aud { + status = "disabled"; +}; + +&dai_slim { + status = "disabled"; +}; + +&wcd9335 { + status = "disabled"; +}; + +&wcd934x_cdc { + status = "disabled"; +}; + +&clock_audio { + status = "disabled"; +}; + +&wcd_rst_gpio { + status = "disabled"; +}; + +&wcd9xxx_intc { + status = "disabled"; +}; + +&tasha_snd { + status = "disabled"; +}; + +&tavil_snd { + status = "disabled"; +}; + +&spi_7 { + status = "disabled"; +}; + +&wdsp_mgr { + status = "disabled"; +}; + +&wdsp_glink { + status = "disabled"; +}; + +&glink_spi_xprt_wdsp { + status = "disabled"; +}; + +&int_codec { + status = "okay"; +}; + +&pmic_analog_codec { + status = "okay"; +}; + +&msm_sdw_codec { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-ion.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-ion.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e7d0cb0d13618dd4b2beb25b789417479dd557d4 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-ion.dtsi @@ -0,0 +1,35 @@ +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&adsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-lpi.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-lpi.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..418b4201014f213f892396a9a687204ccc376c88 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-lpi.dtsi @@ -0,0 +1,217 @@ +&soc { + lpi_tlmm: lpi_pinctrl@15070000 { + compatible = "qcom,lpi-pinctrl"; + reg = <0x15070000 0x0>; + qcom,num-gpios = <32>; + gpio-controller; + #gpio-cells = <2>; + qcom,lpi-offset-tbl = + <0x00000000>, <0x00001000>, + <0x00002000>, <0x00002010>, + <0x00003000>, <0x00003010>, + <0x00004000>, <0x00004010>, + <0x00005000>, <0x00005010>, + <0x00005020>, <0x00005030>, + <0x00006000>, <0x00006010>, + <0x00007000>, <0x00007010>, + <0x00005040>, <0x00005050>, + <0x00008000>, <0x00008010>, + <0x00008020>, <0x00008030>, + <0x00008040>, <0x00008050>, + <0x00008060>, <0x00008070>, + <0x00009000>, <0x00009010>, + <0x0000A000>, <0x0000A010>, + <0x0000B000>, <0x0000B010>; + + lpi_mclk0_active: lpi_mclk0_active { + mux { + pins = "gpio18"; + function = "func2"; + }; + + config { + pins = "gpio18"; + drive-strength = <8>; + bias-disable; + }; + }; + + lpi_mclk0_sleep: lpi_mclk0_sleep { + mux { + pins = "gpio18"; + function = "func2"; + }; + + config { + pins = "gpio18"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + cdc_pdm_gpios_active: cdc_pdm_gpios_active { + mux { + pins = "gpio18", "gpio19", + "gpio21", "gpio23", + "gpio25"; + function = "func1"; + }; + + config { + pins = "gpio18", "gpio19", + "gpio21", "gpio23", + "gpio25"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_pdm_gpios_sleep: cdc_pdm_gpios_sleep { + mux { + pins = "gpio18", "gpio19", + "gpio21", "gpio23", + "gpio25"; + function = "func1"; + }; + + config { + pins = "gpio18", "gpio19", + "gpio21", "gpio23", + "gpio25"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_pdm_2_gpios_active: cdc_pdm_2_gpios_active { + mux { + pins = "gpio20"; + function = "func1"; + }; + + config { + pins = "gpio20"; + drive-strength = <8>; + }; + }; + + cdc_pdm_2_gpios_sleep: cdc_pdm_2_gpios_sleep { + mux { + pins = "gpio20"; + function = "func1"; + }; + + config { + pins = "gpio20"; + drive-strength = <2>; + bias-disable; + }; + }; + + cdc_comp_gpios_active: cdc_pdm_comp_gpios_active { + mux { + pins = "gpio22", "gpio24"; + function = "func1"; + }; + + config { + pins = "gpio22", "gpio24"; + drive-strength = <8>; + }; + }; + + cdc_comp_gpios_sleep: cdc_pdm_comp_gpios_sleep { + mux { + pins = "gpio22", "gpio24"; + function = "func1"; + }; + + config { + pins = "gpio22", "gpio24"; + drive-strength = <2>; + bias-disable; + }; + }; + + lpi_cdc_reset_active: lpi_cdc_reset_active { + mux { + pins = "gpio24"; + function = "gpio"; + }; + config { + pins = "gpio24"; + drive-strength = <16>; + output-high; + }; + }; + + lpi_cdc_reset_sleep: lpi_cdc_reset_sleep { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + cdc_dmic12_gpios_active: dmic12_gpios_active { + mux { + pins = "gpio26", "gpio28"; + function = "func1"; + }; + + config { + pins = "gpio26", "gpio28"; + drive-strength = <8>; + output-high; + }; + }; + + cdc_dmic12_gpios_sleep: dmic12_gpios_sleep { + mux { + pins = "gpio26", "gpio28"; + function = "func1"; + }; + + config { + pins = "gpio26", "gpio28"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_dmic34_gpios_active: dmic34_gpios_active { + mux { + pins = "gpio27", "gpio29"; + function = "func1"; + }; + + config { + pins = "gpio27", "gpio29"; + drive-strength = <8>; + input-enable; + }; + }; + + cdc_dmic34_gpios_sleep: dmic34_gpios_sleep { + mux { + pins = "gpio27", "gpio29"; + function = "func1"; + }; + + config { + pins = "gpio27", "gpio29"; + drive-strength = <2>; + pull-down; + input-enable; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss-panels.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss-panels.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0b8d3ffa94521416cf819216f0ccc3e6a41c9704 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss-panels.dtsi @@ -0,0 +1,357 @@ +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-sharp-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" +#include "dsi-panel-truly-1080p-cmd.dtsi" +#include "dsi-panel-truly-1080p-video.dtsi" +#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" +#include "dsi-panel-lgd-incell-sw49106-fhd-video.dtsi" +#include "dsi-panel-hx8399c-fhd-plus-video.dtsi" + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "wqhd-vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1950000>; + qcom,supply-enable-load = <32000>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <10>; + }; + }; + + dsi_panel_pwr_supply_labibb_amoled: + dsi_panel_pwr_supply_labibb_amoled { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "wqhd-vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1950000>; + qcom,supply-enable-load = <32000>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdda-3p3"; + qcom,supply-min-voltage = <3300000>; + qcom,supply-max-voltage = <3300000>; + qcom,supply-enable-load = <13200>; + qcom,supply-disable-load = <80>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4000000>; + qcom,supply-max-voltage = <6300000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@4 { + reg = <4>; + qcom,supply-name = "oledb"; + qcom,supply-min-voltage = <5000000>; + qcom,supply-max-voltage = <8100000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + + dsi_panel_pwr_supply_no_labibb: dsi_panel_pwr_supply_no_labibb { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "wqhd-vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1950000>; + qcom,supply-enable-load = <32000>; + qcom,supply-disable-load = <80>; + }; + }; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-bitclk; + qcom,mdss-dsi-dynamic-bitclk_freq = <798240576 801594528 804948480 + 808302432 811656384>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,ulps-enabled; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1c 08 09 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0e>; + qcom,mdss-dsi-t-clk-pre = <0x31>; +}; + +&dsi_dual_sharp_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 20 06 09 05 03 04 a0 + 23 2e 06 08 05 03 04 a0]; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [20 1d 05 07 03 03 04 a0 + 20 1d 05 07 03 03 04 a0 + 20 1d 05 07 03 03 04 a0 + 20 1d 05 07 03 03 04 a0 + 20 12 05 06 03 13 04 a0]; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [20 1d 05 07 03 03 04 a0 + 20 1d 05 07 03 03 04 a0 + 20 1d 05 07 03 03 04 a0 + 20 1d 05 07 03 03 04 a0 + 20 12 05 06 03 13 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; +}; + +&dsi_dual_nt35597_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; + qcom,mdss-dsi-min-refresh-rate = <53>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; +}; + +&dsi_dual_nt35597_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 1e 07 08 05 03 04 a0 + 23 18 07 08 04 03 04 a0]; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1e 08 09 05 03 04 a0 + 24 1e 08 09 05 03 04 a0 + 24 1e 08 09 05 03 04 a0 + 24 1e 08 09 05 03 04 a0 + 24 1a 08 09 05 03 04 a0]; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1e 08 09 05 03 04 a0 + 24 1e 08 09 05 03 04 a0 + 24 1e 08 09 05 03 04 a0 + 24 1e 08 09 05 03 04 a0 + 24 1a 08 09 05 03 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; +}; + +&dsi_truly_1080_vid { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 08 09 05 03 04 a0 + 23 1e 08 09 05 03 04 a0 + 23 1e 08 09 05 03 04 a0 + 23 1e 08 09 05 03 04 a0 + 23 1a 08 09 05 03 04 a0]; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; + +}; + +&dsi_truly_1080_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 08 09 05 03 04 a0 + 23 1e 08 09 05 03 04 a0 + 23 1e 08 09 05 03 04 a0 + 23 1e 08 09 05 03 04 a0 + 23 1a 08 09 05 03 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; + +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1a 08 09 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2f>; +}; + + +&dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1b 08 09 05 03 04 a0]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x30>; +}; + +&dsi_hx8399c_truly_vid { + qcom,mdss-dsi-panel-timings-phy-v2 = [24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1f 08 09 05 03 04 a0 + 24 1c 08 09 05 03 04 a0]; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss-pll.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss-pll.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..8b68cc1764c812a98492c1a7a9635e1564088eac --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss-pll.dtsi @@ -0,0 +1,108 @@ +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@c994400 { + compatible = "qcom,mdss_dsi_pll_sdm660"; + status = "ok"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0xc994400 0x588>, + <0xc8c2300 0x8>, + <0xc994200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; + + gdsc-supply = <&gdsc_mdss>; + + clocks = <&clock_mmss MMSS_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + memory-region = <&dfps_data_mem>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + + }; + }; + + mdss_dsi1_pll: qcom,mdss_dsi_pll@c996400 { + compatible = "qcom,mdss_dsi_pll_sdm660"; + status = "ok"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + + reg = <0xc996400 0x588>, + <0xc8c2300 0x8>, + <0xc996200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; + + gdsc-supply = <&gdsc_mdss>; + + clocks = <&clock_mmss MMSS_MDSS_AHB_CLK>; + clock-names = "iface_clk"; + clock-rate = <0>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; + + mdss_dp_pll: qcom,mdss_dp_pll@c011000 { + compatible = "qcom,mdss_dp_pll_14nm"; + status = "ok"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0xc011c00 0x190>, + <0xc011000 0x910>, + <0x0c8c2300 0x8>; + reg-names = "pll_base", "phy_base", "gdsc_base"; + + gdsc-supply = <&gdsc_mdss>; + + clocks = <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_USB3_CLKREF_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..931619fdb3f748529f71590648ca63890988d676 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mdss.dtsi @@ -0,0 +1,633 @@ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp@c900000 { + compatible = "qcom,mdss_mdp"; + status = "ok"; + reg = <0x0c900000 0x90000>, + <0x0c9b0000 0x1040>; + reg-names = "mdp_phys", "vbif_phys"; + interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; + interrupt-controller; + #interrupt-cells = <1>; + vdd-supply = <&gdsc_mdss>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_mdp"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; + + /* Fudge factors */ + qcom,mdss-ab-factor = <1 1>; /* 1 time */ + qcom,mdss-ib-factor = <1 1>; /* 1 time */ + qcom,mdss-clk-factor = <105 100>; /* 1.05 times */ + + qcom,max-mixer-width = <2560>; + qcom,max-pipe-width = <2560>; + + qcom,max-dest-scaler-input-width = <2048>; + qcom,max-dest-scaler-output-width = <2560>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-vbif-qos-rt-setting = <1 2 2 2>; + qcom,mdss-vbif-qos-nrt-setting = <1 1 1 1>; + qcom,vbif-settings = <0x00ac 0x00008040>, + <0x00d0 0x00002828>; + + qcom,mdss-cx-ipeak = <&cx_ipeak_lm 3>; + qcom,mdss-has-panic-ctrl; + qcom,mdss-per-pipe-panic-luts = <0x000f>, + <0xffff>, + <0xfffc>, + <0xff00>; + + qcom,mdss-mdp-reg-offset = <0x00001000>; + qcom,max-bandwidth-low-kbps = <6600000>; + qcom,max-bandwidth-high-kbps = <6600000>; + qcom,max-bandwidth-per-pipe-kbps = <3100000>; + qcom,max-clk-rate = <412500000>; + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + qcom,mdss-dram-channels = <2>; + + /* Bandwidth limit settings */ + qcom,max-bw-settings = <1 6600000>, /* Default */ + <2 4500000>; /* Camera */ + + qcom,mdss-pipe-vig-off = <0x00005000 0x00007000>; + qcom,mdss-pipe-dma-off = <0x00025000 0x00027000 + 0x00029000>; + qcom,mdss-pipe-cursor-off = <0x00035000>; + + qcom,mdss-pipe-vig-xin-id = <0 4>; + qcom,mdss-pipe-dma-xin-id = <1 5 9>; + qcom,mdss-pipe-cursor-xin-id = <2>; + + /* These Offsets are relative to */ + /* "mdp_phys + mdp-reg-offset" address */ + + qcom,mdss-pipe-vig-clk-ctrl-offsets = <0x2ac 0 0>, + <0x2b4 0 0>; + qcom,mdss-pipe-dma-clk-ctrl-offsets = <0x2ac 8 12>, + <0x2b4 8 12>, + <0x2c4 8 12>; + qcom,mdss-pipe-cursor-clk-ctrl-offsets = <0x3a8 16 15>; + + qcom,mdss-ctl-off = <0x00002000 0x00002200 0x00002400 + 0x00002600 0x00002800>; + qcom,mdss-mixer-intf-off = <0x00045000 0x00046000 + 0x00047000 0x0004a000>; + qcom,mdss-dspp-off = <0x00055000 0x00057000>; + qcom,mdss-wb-off = <0x00066000>; + qcom,mdss-intf-off = <0x0006b000 0x0006b800 + 0x0006c000 0x0006c800>; + qcom,mdss-pingpong-off = <0x00071000 0x00071800 + 0x00072000 0x00072800>; + qcom,mdss-slave-pingpong-off = <0x00073000>; + qcom,mdss-ppb-ctl-off = <0x00000330 0x00000338 0x00000370 + 0x00000374> ; + qcom,mdss-ppb-cfg-off = <0x00000334 0x0000033C>; + qcom,mdss-has-pingpong-split; + qcom,mdss-has-separate-rotator; + + qcom,mdss-ad-off = <0x0079000 0x00079800>; + qcom,mdss-cdm-off = <0x0007a200>; + qcom,mdss-dsc-off = <0x00081000 0x00081400>; + qcom,mdss-wfd-mode = "intf"; + qcom,mdss-has-source-split; + qcom,mdss-highest-bank-bit = <0x1>; + qcom,mdss-has-decimation; + qcom,mdss-idle-power-collapse-enabled; + clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_THROTTLE_MDSS_AXI_CLK>, + <&clock_mmss MDP_CLK_SRC>, + <&clock_mmss MMSS_MDSS_MDP_CLK>, + <&clock_mmss MMSS_MDSS_VSYNC_CLK>, + <&clock_mmss MDP_CLK_SRC>; + clock-names = "mnoc_clk", "iface_clk", "bus_clk", + "throttle_bus_clk", "core_clk_src", + "core_clk", "vsync_clk", "lut_clk"; + + qcom,mdp-settings = <0x01190 0x00000000>, + <0x012ac 0xc0000ccc>, + <0x012b4 0xc0000ccc>, + <0x012bc 0x00cccccc>, + <0x012c4 0x0000cccc>, + <0x013a8 0x0cccc0c0>, + <0x013b0 0xccccc0c0>, + <0x013b8 0xcccc0000>, + <0x013d0 0x00cc0000>, + <0x0506c 0x00000000>, + <0x0706c 0x00000000>, + <0x0906c 0x00000000>, + <0x0b06c 0x00000000>, + <0x1506c 0x00000000>, + <0x1706c 0x00000000>, + <0x1906c 0x00000000>, + <0x1b06c 0x00000000>, + <0x2506c 0x00000000>, + <0x2706c 0x00000000>; + + qcom,regs-dump-mdp = <0x01000 0x01458>, + <0x02000 0x02094>, + <0x02200 0x02294>, + <0x02400 0x02494>, + <0x02600 0x02694>, + <0x02800 0x02894>, + <0x05000 0x05154>, + <0x05a00 0x05b00>, + <0x07000 0x07154>, + <0x07a00 0x07b00>, + <0x25000 0x25184>, + <0x27000 0x27184>, + <0x29000 0x29184>, + <0x35000 0x35150>, + <0x45000 0x452bc>, + <0x46000 0x462bc>, + <0x47000 0x472bc>, + <0x4a000 0x4a2bc>, + <0x55000 0x5522c>, + <0x57000 0x5722c>, + <0x66000 0x662c0>, + <0x6b000 0x6b268>, + <0x6b800 0x6ba68>, + <0x6c000 0x6c268>, + <0x71000 0x710d4>, + <0x71800 0x718d4>, + <0x73000 0x730d4>, + <0x81000 0x81140>, + <0x81400 0x81540>; + + qcom,regs-dump-names-mdp = "MDP", + "CTL_0", "CTL_1", "CTL_2", "CTL_3", "CTL_4", + "VIG0_SSPP", "VIG0", "VIG1_SSPP", "VIG1", + "DMA0_SSPP", "DMA1_SSPP","DMA2_SSPP", + "CURSOR0_SSPP", + "LAYER_0", "LAYER_1", "LAYER_2", + "LAYER_5", + "DSPP_0", "DSPP_1", + "WB_2", + "INTF_0", "INTF_1", "INTF_2", + "PP_0", "PP_1", "PP_4", + "DSC_0", "DSC_1"; + + /* buffer parameters to calculate prefill bandwidth */ + qcom,mdss-prefill-outstanding-buffer-bytes = <0>; + qcom,mdss-prefill-y-buffer-bytes = <0>; + qcom,mdss-prefill-scaler-buffer-lines-bilinear = <2>; + qcom,mdss-prefill-scaler-buffer-lines-caf = <4>; + qcom,mdss-prefill-post-scaler-buffer-pixels = <2560>; + qcom,mdss-prefill-pingpong-buffer-pixels = <5120>; + + qcom,mdss-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + + qcom,mdss-pp-offsets { + qcom,mdss-sspp-mdss-igc-lut-off = <0x2000>; + qcom,mdss-sspp-vig-pcc-off = <0x1b00>; + qcom,mdss-sspp-rgb-pcc-off = <0x380>; + qcom,mdss-sspp-dma-pcc-off = <0x380>; + qcom,mdss-lm-pgc-off = <0x3c0>; + qcom,mdss-dspp-gamut-off = <0x1600>; + qcom,mdss-dspp-pcc-off = <0x1700>; + qcom,mdss-dspp-pgc-off = <0x17c0>; + }; + + qcom,mdss-scaler-offsets { + qcom,mdss-vig-scaler-off = <0xa00>; + qcom,mdss-vig-scaler-lut-off = <0xb00>; + qcom,mdss-has-dest-scaler; + qcom,mdss-dest-block-off = <0x00061000>; + qcom,mdss-dest-scaler-off = <0x800 0x1000>; + qcom,mdss-dest-scaler-lut-off = <0x900 0x1100>; + }; + + smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb { + compatible = "qcom,smmu_mdp_unsec"; + iommus = <&mmss_bimc_smmu 0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-earlymap; /* for cont-splash */ + gdsc-mmagic-mdss-supply = <&gdsc_bimc_smmu>; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>; + clock-names = "mmss_noc_axi_clk", + "mmss_noc_ahb_clk", + "mmss_smmu_ahb_clk", + "mmss_smmu_axi_clk"; + }; + + smmu_mdp_sec: qcom,smmu_mdp_sec_cb { + compatible = "qcom,smmu_mdp_sec"; + iommus = <&mmss_bimc_smmu 1>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-vmid = <0xa>; + gdsc-mmagic-mdss-supply = <&gdsc_bimc_smmu>; + clocks = <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>; + clock-names = "mmss_noc_axi_clk", + "mmss_noc_ahb_clk", + "mmss_smmu_ahb_clk", + "mmss_smmu_axi_clk"; + }; + + mdss_fb0: qcom,mdss_fb_primary { + cell-index = <0>; + compatible = "qcom,mdss-fb"; + qcom,cont-splash-memory { + linux,contiguous-region = <&cont_splash_mem>; + }; + }; + + mdss_fb1: qcom,mdss_fb_wfd { + cell-index = <1>; + compatible = "qcom,mdss-fb"; + }; + + mdss_fb2: qcom,mdss_fb_dp { + cell-index = <2>; + compatible = "qcom,mdss-fb"; + qcom,mdss-intf = <&mdss_dp_ctrl>; + }; + + }; + + mdss_dsi: qcom,mdss_dsi@0 { + compatible = "qcom,mdss-dsi"; + #address-cells = <1>; + #size-cells = <1>; + gdsc-supply = <&gdsc_mdss>; + vdda-1p2-supply = <&pm660_l1>; + vdda-0p9-supply = <&pm660l_l1>; + ranges = <0xc994000 0xc994000 0x400 + 0xc994400 0xc994400 0x588 + 0xc828000 0xc828000 0xac + 0xc996000 0xc996000 0x400 + 0xc996400 0xc996400 0x588 + 0xc828000 0xc828000 0xac>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_dsi"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 1000>; + + qcom,mmss-ulp-clamp-ctrl-offset = <0x14>; + + clocks = <&clock_mmss MMSS_MDSS_MDP_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_MISC_AHB_CLK>, + <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi1_pll BYTE1_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi1_pll PIX1_MUX_CLK>; + clock-names = "mdp_core_clk", + "mnoc_clk", "iface_clk", + "bus_clk", "core_mmss_clk", + "ext_byte0_clk", "ext_byte1_clk", + "ext_pixel0_clk", "ext_pixel1_clk"; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1250000>; + qcom,supply-enable-load = <12560>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <925000>; + qcom,supply-enable-load = <73400>; + qcom,supply-disable-load = <32>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@c994000 { + compatible = "qcom,mdss-dsi-ctrl"; + label = "MDSS DSI CTRL->0"; + cell-index = <0>; + reg = <0xc994000 0x400>, + <0xc994400 0x588>, + <0xc828000 0xac>; + reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys"; + + qcom,timing-db-mode; + wqhd-vddio-supply = <&pm660_l11>; + vdda-3p3-supply = <&pm660l_l6>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,mdss-mdp = <&mdss_mdp>; + qcom,mdss-fb-map = <&mdss_fb0>; + + clocks = <&clock_mmss MMSS_MDSS_BYTE0_CLK>, + <&clock_mmss MMSS_MDSS_PCLK0_CLK>, + <&clock_mmss MMSS_MDSS_ESC0_CLK>, + <&clock_mmss BYTE0_CLK_SRC>, + <&clock_mmss PCLK0_CLK_SRC>, + <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>, + <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; + clock-names = "byte_clk", "pixel_clk", "core_clk", + "byte_clk_rcg", "pixel_clk_rcg", + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; + + qcom,null-insertion-enabled; + qcom,platform-strength-ctrl = [ff 06 + ff 06 + ff 06 + ff 06 + ff 00]; + qcom,platform-regulator-settings = [1d + 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 8f]; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@c996000 { + compatible = "qcom,mdss-dsi-ctrl"; + label = "MDSS DSI CTRL->1"; + cell-index = <1>; + reg = <0xc996000 0x400>, + <0xc996400 0x588>, + <0xc828000 0xac>; + reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys"; + + qcom,timing-db-mode; + wqhd-vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + qcom,mdss-mdp = <&mdss_mdp>; + qcom,mdss-fb-map = <&mdss_fb0>; + + clocks = <&clock_mmss MMSS_MDSS_BYTE1_CLK>, + <&clock_mmss MMSS_MDSS_PCLK1_CLK>, + <&clock_mmss MMSS_MDSS_ESC1_CLK>, + <&clock_mmss BYTE1_CLK_SRC>, + <&clock_mmss PCLK1_CLK_SRC>, + <&clock_mmss MMSS_MDSS_BYTE1_INTF_CLK>, + <&mdss_dsi1_pll BYTE1_MUX_CLK>, + <&mdss_dsi1_pll PIX1_MUX_CLK>, + <&mdss_dsi1_pll BYTE1_SRC_CLK>, + <&mdss_dsi1_pll PIX1_SRC_CLK>, + <&mdss_dsi1_pll SHADOW_BYTE1_SRC_CLK>, + <&mdss_dsi1_pll SHADOW_PIX1_SRC_CLK>; + clock-names = "byte_clk", "pixel_clk", "core_clk", + "byte_clk_rcg", "pixel_clk_rcg", + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; + + qcom,null-insertion-enabled; + qcom,platform-strength-ctrl = [ff 06 + ff 06 + ff 06 + ff 06 + ff 00]; + qcom,platform-regulator-settings = [1d + 1d 1d 1d 1d]; + qcom,platform-lane-config = [00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 0f + 00 00 10 8f]; + }; + }; + + qcom,mdss_wb_panel { + compatible = "qcom,mdss_wb"; + qcom,mdss_pan_res = <640 480>; + qcom,mdss_pan_bpp = <24>; + qcom,mdss-fb-map = <&mdss_fb1>; + }; + + msm_ext_disp: qcom,msm-ext-disp { + status = "ok"; + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + qcom,msm-ext-disp = <&msm_ext_disp>; + }; + }; + + mdss_dp_ctrl: qcom,dp_ctrl@c990000 { + status = "ok"; + cell-index = <0>; + compatible = "qcom,mdss-dp"; + qcom,mdss-fb-map = <&mdss_fb2>; + + gdsc-supply = <&gdsc_mdss>; + vdda-1p8-supply = <&pm660_l10>; + vdda-0p9-supply = <&pm660l_l1>; + + reg = <0xc990000 0xa8c>, + <0xc011000 0x910>, + <0x1fcb200 0x050>, + <0xc8c2200 0x1a0>, + <0x780000 0x621c>, + <0xc9e1000 0x02c>; + reg-names = "dp_ctrl", "dp_phy", "tcsr_regs", "dp_mmss_cc", + "qfprom_physical","hdcp_physical"; + + clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AXI_CLK>, + <&clock_mmss MMSS_MDSS_MDP_CLK>, + <&clock_mmss MMSS_MDSS_HDMI_DP_AHB_CLK>, + <&clock_mmss MMSS_MDSS_DP_AUX_CLK>, + <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_USB3_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_mmss MMSS_MDSS_DP_LINK_CLK>, + <&clock_mmss MMSS_MDSS_DP_LINK_INTF_CLK>, + <&clock_mmss MMSS_MDSS_DP_CRYPTO_CLK>, + <&clock_mmss MMSS_MDSS_DP_PIXEL_CLK>, + <&clock_mmss DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_PHY_PLL_VCO_DIV_CLK>; + clock-names = "core_mnoc_clk", "core_iface_clk", "core_bus_clk", + "core_mdp_core_clk", "core_alt_iface_clk", + "core_aux_clk", "core_ref_clk_src", "core_ref_clk", + "core_ahb_phy_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_crypto_clk", + "ctrl_pixel_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,dp-usbpd-detection = <&pm660_pdphy>; + + qcom,msm_ext_disp = <&msm_ext_disp>; + + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13 23 1d]; + qcom,aux-cfg2-settings = [28 00]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 28]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 b7]; + qcom,aux-cfg9-settings = [44 03]; + qcom,logical2physical-lane-map = [00 01 02 03]; + qcom,phy-register-offset = <0x4>; + qcom,max-pclk-frequency-khz = <300000>; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p8"; + qcom,supply-min-voltage = <1780000>; + qcom,supply-max-voltage = <1950000>; + qcom,supply-enable-load = <12560>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <925000>; + qcom,supply-enable-load = <73400>; + qcom,supply-disable-load = <32>; + }; + }; + }; + + mdss_rotator: qcom,mdss_rotator { + compatible = "qcom,sde_rotator"; + reg = <0x0c900000 0xab100>, + <0x0c9b0000 0x1040>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x1>; + + /* Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rotator"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <22 512 0 0>, + <22 512 0 6400000>, + <22 512 0 6400000>; + + rot-vdd-supply = <&gdsc_mdss>; + qcom,supply-names = "rot-vdd"; + + clocks = <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_MDSS_AHB_CLK>, + <&clock_mmss ROT_CLK_SRC>, + <&clock_mmss MMSS_MDSS_ROT_CLK>, + <&clock_mmss MMSS_MDSS_AXI_CLK>; + clock-names = "mnoc_clk", + "iface_clk", "rot_core_clk", + "rot_clk", "axi_clk"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <2 0>; + + /* VBIF QoS remapper settings*/ + qcom,mdss-rot-vbif-qos-setting = <1 1 1 1>; + qcom,mdss-rot-xin-id = <14 15>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,sde-reg-bus { + /* Reg Bus Scale Settings */ + qcom,msm-bus,name = "mdss_rot_reg"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 160000>, + <1 590 0 320000>; + }; + }; + +}; + +#include "sdm660-mdss-panels.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a65ec9d068c14c7cd5d6c6ab055b219bff062264 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp-external-codec-overlay.dts @@ -0,0 +1,30 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-mtp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Ext. Audio Codec MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 0>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; + +&slim_aud { + /delete-node/tasha_codec; +}; + +&soc { + /delete-node/sound-9335; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp-internal-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp-internal-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..0996310da919ab74fbb47c0786d16595295a8dc0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp-internal-codec-overlay.dts @@ -0,0 +1,21 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-mtp.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Int. Audio Codec MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 1>; +}; + +&int_codec { + qcom,model = "sdm660-snd-card-mtp"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..7ac88a87ad2338fa60decba964042c128e53f086 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp.dts @@ -0,0 +1,26 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-mtp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; + +&slim_aud { + /delete-node/tasha_codec; +}; + +&soc { + /delete-node/sound-9335; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e3421e3328b36bd905eb3b9c052af4c0b8df8e0b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-mtp.dtsi @@ -0,0 +1,262 @@ +#include "sdm660-camera-sensor-mtp.dtsi" + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen3-batterydata-itech-3000mah.dtsi" + #include "fg-gen3-batterydata-ascent-3450mah.dtsi" + }; +}; + +&uartblsp1dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&ufsphy1 { + vdda-phy-supply = <&pm660l_l1>; + vdda-pll-supply = <&pm660_l10>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + qcom,vddp-ref-clk-supply = <&pm660_l1>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&pm660_gpios { + /* GPIO 4 (NFC_CLK_REQ) */ + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; + + /* GPIO 11 for Home Key */ + home_key { + home_key_default: home_key_default { + pins = "gpio11"; + function = "normal"; + input-enable; + bias-pull-up; + }; + }; +}; + +&i2c_6 { /* BLSP1 QUP6 (NFC) */ + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 28 0x00>; + qcom,nq-ven = <&tlmm 29 0x00>; + qcom,nq-firm = <&tlmm 30 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 31 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <28 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK3_PIN>; + clock-names = "ref_clk"; + }; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt35597_truly_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&mdss_dp_ctrl { + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&mdss_dp_aux_active &mdss_dp_usbplug_cc_active>; + pinctrl-1 = <&mdss_dp_aux_suspend &mdss_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 55 0>; + qcom,aux-sel-gpio = <&tlmm 56 0>; + qcom,usbplug-cc-gpio = <&tlmm 58 0>; +}; + +&pm660l_wled { + qcom,string-cfg= <6>; + status = "ok"; +}; + +&pm660l_lcdb { + status = "ok"; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_sharp_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; +}; + +&dsi_lgd_incell_sw49106_fhd_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; + +&soc { + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; +}; + +&mem_client_3_size { + qcom,peripheral-size = <0xf00000>; +}; + +&pm660_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&i2c_2 { + status = "ok"; + smb1351-charger@1d { + compatible = "qcom,smb1351-charger"; + reg = <0x1d>; + qcom,parallel-charger; + qcom,float-voltage-mv = <4400>; + qcom,recharge-mv = <100>; + qcom,parallel-en-pin-polarity = <1>; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pinctrl.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-pinctrl.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..f3b764071051f0f4590d4832c2f46f293e14f64f --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pinctrl.dtsi @@ -0,0 +1,1895 @@ +&soc { + tlmm: pinctrl@03000000 { + compatible = "qcom,sdm660-pinctrl"; + reg = <0x03000000 0xc00000>; + reg-names = "pinctrl", "spi_cfg"; + interrupts-extended = <&wakegic GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + wakeup-parent = <&wakegpio>; + #interrupt-cells = <2>; + irqdomain-map = <1 0 &wakegpio 3 0>, + <5 0 &wakegpio 4 0>, + <9 0 &wakegpio 5 0>, + <10 0 &wakegpio 6 0>, + <66 0 &wakegpio 7 0>, + <22 0 &wakegpio 8 0>, + <25 0 &wakegpio 9 0>, + <28 0 &wakegpio 10 0>, + <58 0 &wakegpio 11 0>, + <41 0 &wakegpio 13 0>, + <43 0 &wakegpio 14 0>, + <40 0 &wakegpio 15 0>, + <42 0 &wakegpio 16 0>, + <46 0 &wakegpio 17 0>, + <50 0 &wakegpio 18 0>, + <44 0 &wakegpio 19 0>, + <56 0 &wakegpio 21 0>, + <45 0 &wakegpio 22 0>, + <68 0 &wakegpio 23 0>, + <69 0 &wakegpio 24 0>, + <70 0 &wakegpio 25 0>, + <71 0 &wakegpio 26 0>, + <72 0 &wakegpio 27 0>, + <73 0 &wakegpio 28 0>, + <64 0 &wakegpio 29 0>, + <2 0 &wakegpio 30 0>, + <13 0 &wakegpio 31 0>, + <111 0 &wakegpio 32 0>, + <74 0 &wakegpio 33 0>, + <75 0 &wakegpio 34 0>, + <76 0 &wakegpio 35 0>, + <82 0 &wakegpio 36 0>, + <17 0 &wakegpio 37 0>, + <77 0 &wakegpio 38 0>, + <47 0 &wakegpio 39 0>, + <54 0 &wakegpio 40 0>, + <48 0 &wakegpio 41 0>, + <101 0 &wakegpio 42 0>, + <49 0 &wakegpio 43 0>, + <51 0 &wakegpio 44 0>, + <86 0 &wakegpio 45 0>, + <90 0 &wakegpio 46 0>, + <91 0 &wakegpio 47 0>, + <52 0 &wakegpio 48 0>, + <55 0 &wakegpio 50 0>, + <6 0 &wakegpio 51 0>, + <65 0 &wakegpio 53 0>, + <67 0 &wakegpio 55 0>, + <83 0 &wakegpio 56 0>, + <84 0 &wakegpio 57 0>, + <85 0 &wakegpio 58 0>, + <87 0 &wakegpio 59 0>, + <21 0 &wakegpio 63 0>, + <78 0 &wakegpio 64 0>, + <113 0 &wakegpio 65 0>, + <60 0 &wakegpio 66 0>, + <98 0 &wakegpio 67 0>, + <30 0 &wakegpio 68 0>, + <31 0 &wakegpio 70 0>, + <29 0 &wakegpio 71 0>, + <107 0 &wakegpio 76 0>, + <109 0 &wakegpio 83 0>, + <103 0 &wakegpio 84 0>, + <105 0 &wakegpio 85 0>; + irqdomain-map-pass-thru = <0 0xff>; + irqdomain-map-mask = <0xff 0>; + + + uart_console_active: uart_console_active { + mux { + pins = "gpio4", "gpio5"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + led_enable: led_enable { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + led_disable: led_disable { + mux { + pins = "gpio40"; + function = "gpio"; + }; + + config { + pins = "gpio40"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + + trigout_a: trigout_a { + mux { + pins = "gpio49"; + function = "qdss_cti0_a"; + }; + + config { + pins = "gpio49"; + drive-strength = <16>; + bias-disable; + output-low; + }; + }; + + ufs_dev_reset_assert: ufs_dev_reset_assert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * UFS_RESET driver strengths are having + * different values/steps compared to typical + * GPIO drive strengths. + * + * Following table clarifies: + * + * HDRV value | UFS_RESET | Typical GPIO + * (dec) | (mA) | (mA) + * 0 | 0.8 | 2 + * 1 | 1.55 | 4 + * 2 | 2.35 | 6 + * 3 | 3.1 | 8 + * 4 | 3.9 | 10 + * 5 | 4.65 | 12 + * 6 | 5.4 | 14 + * 7 | 6.15 | 16 + * + * POR value for UFS_RESET HDRV is 3 which means + * 3.1mA and we want to use that. Hence just + * specify 8mA to "drive-strength" binding and + * that should result into writing 3 to HDRV + * field. + */ + drive-strength = <8>; /* default: 3.1 mA */ + output-low; /* active low reset */ + }; + }; + + ufs_dev_reset_deassert: ufs_dev_reset_deassert { + config { + pins = "ufs_reset"; + bias-pull-down; /* default: pull down */ + /* + * default: 3.1 mA + * check comments under ufs_dev_reset_assert + */ + drive-strength = <8>; + output-high; /* active low reset */ + }; + }; + + /* SDC pin type */ + sdc1_clk_on: sdc1_clk_on { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <16>; /* 16 MA */ + }; + }; + + sdc1_clk_off: sdc1_clk_off { + config { + pins = "sdc1_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_cmd_on: sdc1_cmd_on { + config { + pins = "sdc1_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_cmd_off: sdc1_cmd_off { + config { + pins = "sdc1_cmd"; + num-grp-pins = <1>; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_data_on: sdc1_data_on { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc1_data_off: sdc1_data_off { + config { + pins = "sdc1_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc1_rclk_on: sdc1_rclk_on { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc1_rclk_off: sdc1_rclk_off { + config { + pins = "sdc1_rclk"; + bias-pull-down; /* pull down */ + }; + }; + + sdc2_clk_on: sdc2_clk_on { + config { + pins = "sdc2_clk"; + drive-strength = <16>; /* 16 MA */ + bias-disable; /* NO pull */ + }; + }; + + sdc2_clk_off: sdc2_clk_off { + config { + pins = "sdc2_clk"; + bias-disable; /* NO pull */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cmd_on: sdc2_cmd_on { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_off: sdc2_cmd_off { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_data_on: sdc2_data_on { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_off: sdc2_data_off { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + sdc2_cd_on: cd_on { + mux { + pins = "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio54"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + + /* I2C CONFIGURATION */ + i2c_1 { + i2c_1_active: i2c_1_active { + mux { + pins = "gpio2", "gpio3"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_1_sleep: i2c_1_sleep { + mux { + pins = "gpio2", "gpio3"; + function = "blsp_i2c1"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_1_bitbang: i2c_1_bitbang { + mux { + pins = "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_2 { + i2c_2_active: i2c_2_active { + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_2_sleep: i2c_2_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "blsp_i2c2"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_2_bitbang: i2c_2_bitbang { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_3 { + i2c_3_active: i2c_3_active { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_3_sleep: i2c_3_sleep { + mux { + pins = "gpio10", "gpio11"; + function = "blsp_i2c3"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_3_bitbang: i2c_3_bitbang { + mux { + pins = "gpio10", "gpio11"; + function = "gpio"; + }; + + config { + pins = "gpio10", "gpio11"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_4 { + i2c_4_active: i2c_4_active { + mux { + pins = "gpio14", "gpio15"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_4_sleep: i2c_4_sleep { + mux { + pins = "gpio14", "gpio15"; + function = "blsp_i2c4"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_4_bitbang: i2c_4_bitbang { + mux { + pins = "gpio14", "gpio15"; + function = "gpio"; + }; + + config { + pins = "gpio14", "gpio15"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_5 { + i2c_5_active: i2c_5_active { + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_5_sleep: i2c_5_sleep { + mux { + pins = "gpio18", "gpio19"; + function = "blsp_i2c5"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_5_bitbang: i2c_5_bitbang { + mux { + pins = "gpio18", "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio18", "gpio19"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_6 { + i2c_6_active: i2c_6_active { + mux { + pins = "gpio22", "gpio23"; + function = "blsp_i2c6"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_6_sleep: i2c_6_sleep { + mux { + pins = "gpio22", "gpio23"; + function = "blsp_i2c6"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_6_bitbang: i2c_6_bitbang { + mux { + pins = "gpio22", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio23"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 28 NFC Read Interrupt */ + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 28 NFC Read Interrupt */ + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 29: NFC ENABLE 30:FW DNLD */ + /* 31:ESE Enable */ + pins = "gpio29", "gpio30", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio29", "gpio30", "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 29: NFC ENABLE 30:FW DNLD */ + /* 31:ESE Enable */ + pins = "gpio29", "gpio30", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio29", "gpio30", "gpio31"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + i2c_7 { + i2c_7_active: i2c_7_active { + mux { + pins = "gpio26", "gpio27"; + function = "blsp_i2c7"; + }; + + config { + pins = "gpio26", "gpio27"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_7_sleep: i2c_7_sleep { + mux { + pins = "gpio26", "gpio27"; + function = "blsp_i2c7"; + }; + + config { + pins = "gpio26", "gpio27"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_7_bitbang: i2c_7_bitbang { + mux { + pins = "gpio26", "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio26", "gpio27"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + i2c_8 { + i2c_8_active: i2c_8_active { + mux { + pins = "gpio30", "gpio31"; + function = "blsp_i2c8_a"; + }; + + config { + pins = "gpio30", "gpio31"; + drive-strength = <2>; + bias-disable; + }; + }; + + i2c_8_sleep: i2c_8_sleep { + mux { + pins = "gpio30", "gpio31"; + function = "blsp_i2c8_a"; + }; + + config { + pins = "gpio30", "gpio31"; + drive-strength = <2>; + bias-pull-up; + }; + }; + i2c_8_bitbang: i2c_8_bitbang { + mux { + pins = "gpio30", "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio30", "gpio31"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + /* SPI CONFIGURATION */ + spi_1 { + spi_1_active: spi_1_active { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "blsp_spi1"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_1_sleep: spi_1_sleep { + mux { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + function = "blsp_spi1"; + }; + + config { + pins = "gpio0", "gpio1", + "gpio2", "gpio3"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_2 { + spi_2_active: spi_2_active { + mux { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + function = "blsp_spi2"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_2_sleep: spi_2_sleep { + mux { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + function = "blsp_spi2"; + }; + + config { + pins = "gpio4", "gpio5", + "gpio6", "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_3 { + spi_3_active: spi_3_active { + mux { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_3_sleep: spi_3_sleep { + mux { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + function = "blsp_spi3"; + }; + + config { + pins = "gpio8", "gpio9", + "gpio10", "gpio11"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_4 { + spi_4_active: spi_4_active { + mux { + pins = "gpio12", "gpio13", + "gpio14", "gpio15"; + function = "blsp_spi4"; + }; + + config { + pins = "gpio12", "gpio13", + "gpio14", "gpio15"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_4_sleep: spi_4_sleep { + mux { + pins = "gpio12", "gpio13", + "gpio14", "gpio15"; + function = "blsp_spi4"; + }; + + config { + pins = "gpio12", "gpio13", + "gpio14", "gpio15"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_5 { + spi_5_active: spi_5_active { + mux { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + function = "blsp_spi5"; + }; + + config { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_5_sleep: spi_5_sleep { + mux { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + function = "blsp_spi5"; + }; + + config { + pins = "gpio16", "gpio17", + "gpio18", "gpio19"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_6 { + spi_6_active: spi_6_active { + mux { + pins = "gpio49", "gpio52", + "gpio22", "gpio23"; + function = "blsp_spi6"; + }; + + config { + pins = "gpio49", "gpio52", + "gpio22", "gpio23"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_6_sleep: spi_6_sleep { + mux { + pins = "gpio49", "gpio52", + "gpio22", "gpio23"; + function = "blsp_spi6"; + }; + + config { + pins = "gpio49", "gpio52", + "gpio22", "gpio23"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_7 { + spi_7_active: spi_7_active { + mux { + pins = "gpio24", "gpio25", + "gpio26", "gpio27"; + function = "blsp_spi7"; + }; + + config { + pins = "gpio24", "gpio25", + "gpio26", "gpio27"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_7_sleep: spi_7_sleep { + mux { + pins = "gpio24", "gpio25", + "gpio26", "gpio27"; + function = "blsp_spi7"; + }; + + config { + pins = "gpio24", "gpio25", + "gpio26", "gpio27"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + spi_8 { + spi_8_active: spi_8_active { + mux { + pins = "gpio28", "gpio29", + "gpio30", "gpio31"; + function = "blsp_spi8_a"; + }; + + config { + pins = "gpio28", "gpio29", + "gpio30", "gpio31"; + drive-strength = <6>; + bias-disable; + }; + }; + + spi_8_sleep: spi_8_sleep { + mux { + pins = "gpio28", "gpio29", + "gpio30", "gpio31"; + function = "blsp_spi8_a"; + }; + + config { + pins = "gpio28", "gpio29", + "gpio30", "gpio31"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + /* USB C analog configuration */ + wcd_usbc_analog_en1 { + wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + wcd_usbc_analog_en2n { + wcd_usbc_analog_en2n_idle: wcd_usbc_ana_en2n_idle { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + wcd_usbc_analog_en2n_active: wcd_usbc_ana_en2n_active { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + }; + + sdw_clk_pin { + sdw_clk_sleep: sdw_clk_sleep { + mux { + pins = "gpio24"; + function = "sndwire_clk"; + }; + + config { + pins = "gpio24"; + drive-strength = <2>; + bias-bus-hold; + }; + }; + + sdw_clk_active: sdw_clk_active { + mux { + pins = "gpio24"; + function = "sndwire_clk"; + }; + + config { + pins = "gpio24"; + drive-strength = <2>; + bias-bus-hold; + }; + }; + }; + + sdw_clk_data { + sdw_data_sleep: sdw_data_sleep { + mux { + pins = "gpio25"; + function = "sndwire_data"; + }; + + config { + pins = "gpio25"; + drive-strength = <4>; + bias-bus-hold; + }; + }; + + sdw_data_active: sdw_data_active { + mux { + pins = "gpio25"; + function = "sndwire_data"; + }; + + config { + pins = "gpio25"; + drive-strength = <4>; + bias-bus-hold; + }; + }; + }; + + /* WSA speaker reset pins */ + spkr_1_sd_n { + spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_1_sd_n_active: spkr_1_sd_n_active { + mux { + pins = "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio26"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + spkr_2_sd_n { + spkr_2_sd_n_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; + input-enable; + }; + }; + + spkr_2_sd_n_active: spkr_2_sd_n_active { + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + drive-strength = <16>; /* 16 mA */ + bias-disable; + output-high; + }; + }; + }; + + wcd_gnd_mic_swap { + wcd_gnd_mic_swap_idle: wcd_gnd_mic_swap_idle { + mux { + pins = "gpio63"; + function = "gpio"; + }; + config { + pins = "gpio63"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_gnd_mic_swap_active: wcd_gnd_mic_swap_active { + mux { + pins = "gpio63"; + function = "gpio"; + }; + config { + pins = "gpio63"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + msm_hph_en0 { + hph_en0_sleep: hph_en0_sleep { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + output-low; + }; + }; + + hph_en0_active: hph_en0_active { + mux { + pins = "gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio24"; + output-high; + }; + }; + }; + + msm_hph_en1 { + hph_en1_sleep: hph_en1_sleep { + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + output-low; + }; + }; + + hph_en1_active: hph_en1_active { + mux { + pins = "gpio25"; + function = "gpio"; + }; + + config { + pins = "gpio25"; + output-high; + }; + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio36","gpio37"; // Only 2 + function = "cci_i2c"; + }; + + config { + pins = "gpio36","gpio37"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio36","gpio37"; + function = "cci_i2c"; + }; + + config { + pins = "gpio36","gpio37"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio38","gpio39"; + function = "cci_i2c"; + }; + + config { + pins = "gpio38","gpio39"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio38","gpio39"; + function = "cci_i2c"; + }; + + + config { + pins = "gpio38","gpio39"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_actuator_vaf_active: cam_actuator_vaf_active { + /* ACTUATOR POWER */ + mux { + pins = "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio50"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_actuator_vaf_suspend: cam_actuator_vaf_suspend { + /* ACTUATOR POWER */ + mux { + pins = "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio50"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_tof_active: cam_tof_active { + /* LASER */ + mux { + pins = "gpio50", "gpio42", "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio50", "gpio42", "gpio45"; + bias-pull-up; + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_tof_suspend: cam_tof_suspend { + /* LASER */ + mux { + pins = "gpio50", "gpio42", "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio50", "gpio42", "gpio45"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + /* CLK */ + pins = "gpio32"; + function = "cam_mclk"; + }; + + config { + pins = "gpio32"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + /* CLK */ + pins = "gpio32"; + function = "cam_mclk"; + }; + + config { + pins = "gpio32"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET, STANDBY */ + mux { + pins = "gpio46","gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio46","gpio44"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio46","gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio46","gpio44"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + /* CLK */ + pins = "gpio33"; + function = "cam_mclk"; + }; + + config { + pins = "gpio33"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + /* CLK */ + pins = "gpio33"; + function = "cam_mclk"; + }; + + config { + pins = "gpio33"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET, STANDBY */ + mux { + pins = "gpio48","gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio48","gpio51"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio48","gpio51"; + function = "gpio"; + }; + config { + pins = "gpio48","gpio51"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK1 */ + mux { + /* CLK */ + pins = "gpio34"; + function = "cam_mclk"; + }; + + config { + pins = "gpio34"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK1 */ + mux { + /* CLK */ + pins = "gpio34"; + function = "cam_mclk"; + }; + + config { + pins = "gpio34"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET VANA*/ + mux { + pins = "gpio47", "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio47", "gpio44"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio35"; + function = "cam_mclk"; + }; + + config { + pins = "gpio35"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + /* CLK */ + pins = "gpio35"; + function = "cam_mclk"; + }; + + config { + pins = "gpio35"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_iris_active: cam_sensor_front_iris_active { + /* RESET */ + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_iris_suspend: cam_sensor_front_iris_suspend { + /* RESET */ + mux { + pins = "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio52"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + /* HS UART CONFIGURATION */ + blsp1_uart1_active: blsp1_uart1_active { + mux { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + function = "blsp_uart1"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart1_sleep: blsp1_uart1_sleep { + mux { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + function = "gpio"; + }; + + config { + pins = "gpio0", "gpio1", "gpio2", "gpio3"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2_active: blsp1_uart2_active { + mux { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + function = "blsp_uart2 "; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart2_sleep: blsp1_uart2_sleep { + mux { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1: blsp2_uart1 { + blsp2_uart1_tx_active: blsp2_uart1_tx_active { + mux { + pins = "gpio16"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_tx_sleep: blsp2_uart1_tx_sleep { + mux { + pins = "gpio16"; + function = "gpio"; + }; + + config { + pins = "gpio16"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + blsp2_uart1_rxcts_active: blsp2_uart1_rxcts_active { + mux { + pins = "gpio17", "gpio18"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_rxcts_sleep: blsp2_uart1_rxcts_sleep { + mux { + pins = "gpio17", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp2_uart1_rfr_active: blsp2_uart1_rfr_active { + mux { + pins = "gpio19"; + function = "blsp_uart5"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart1_rfr_sleep: blsp2_uart1_rfr_sleep { + mux { + pins = "gpio19"; + function = "gpio"; + }; + + config { + pins = "gpio19"; + drive-strength = <2>; + bias-no-pull; + }; + }; + }; + + blsp2_uart2_active: blsp2_uart2_active { + mux { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + function = "blsp_uart6_a"; + }; + + config { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp2_uart2_sleep: blsp2_uart2_sleep { + mux { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio24", "gpio25", "gpio26", "gpio27"; + drive-strength = <2>; + bias-disable; + }; + }; + + tlmm_gpio_key { + gpio_key_active: gpio_key_active { + mux { + pins = "gpio64", "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio64", "gpio113"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + gpio_key_suspend: gpio_key_suspend { + mux { + pins = "gpio64", "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio64", "gpio113"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + pmx_mdss: pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio53"; + function = "gpio"; + }; + + config { + pins = "gpio53"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio53"; + function = "gpio"; + }; + + config { + pins = "gpio53"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + }; + + pmx_mdss_te { + mdss_te_active: mdss_te_active { + mux { + pins = "gpio59"; + function = "mdp_vsync"; + }; + config { + pins = "gpio59"; + drive-strength = <2>; /* 8 mA */ + bias-pull-down; /* pull down*/ + }; + }; + + mdss_te_suspend: mdss_te_suspend { + mux { + pins = "gpio59"; + function = "mdp_vsync"; + }; + config { + pins = "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + }; + + mdss_dp_aux_active: mdss_dp_aux_active { + mux { + pins = "gpio55", "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio55", "gpio56"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; + }; + + mdss_dp_aux_suspend: mdss_dp_aux_suspend { + mux { + pins = "gpio55", "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio55", "gpio56"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + mdss_dp_usbplug_cc_active: mdss_dp_usbplug_cc_active { + mux { + pins = "gpio58"; + function = "gpio"; + }; + + config { + pins = "gpio58"; + bias-disable; + drive-strength = <16>; + }; + }; + + mdss_dp_usbplug_cc_suspend: mdss_dp_usbplug_cc_suspend { + mux { + pins = "gpio58"; + function = "gpio"; + }; + + config { + pins = "gpio58"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + ts_mux { + ts_active: ts_active { + mux { + pins = "gpio66", "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio66", "gpio67"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..c689d129213f81c93c12d1f64e7c7daaeed2dc15 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm.dtsi @@ -0,0 +1,284 @@ +#include + +&soc { + qcom,spm@178120000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x17812000 0x1000>; + qcom,name = "gold-l2"; /* Gold L2 SAW */ + qcom,saw2-ver-reg = <0xfd0>; + qcom,cpu-vctl-list = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,vctl-timeout-us = <500>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,saw2-avs-ctl = <0x1010031>; + qcom,saw2-avs-limit = <0x4580458>; + qcom,pfm-port = <0x2>; + }; + + qcom,spm@179120000 { + compatible = "qcom,spm-v2"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x17912000 0x1000>; + qcom,name = "silver-l2"; /* Silver L2 SAW */ + qcom,saw2-ver-reg = <0xfd0>; + qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,vctl-timeout-us = <500>; + qcom,vctl-port = <0x0>; + qcom,phase-port = <0x1>; + qcom,saw2-avs-ctl = <0x1010031>; + qcom,saw2-avs-limit = <0x4580458>; + qcom,pfm-port = <0x2>; + }; + + qcom,lpm-levels { + compatible = "qcom,lpm-levels"; + qcom,use-psci; + #address-cells = <1>; + #size-cells = <0>; + qcom,pm-cluster@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "system"; + qcom,spm-device-names = "cci"; + qcom,psci-mode-shift = <8>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0{ + reg = <0>; + label = "system-wfi"; + qcom,psci-mode = <0x0>; + qcom,entry-latency-us = <640>; + qcom,exit-latency-us = <1654>; + qcom,min-residency-us = <2294>; + }; + + qcom,pm-cluster-level@1{ /* E3 */ + reg = <1>; + label = "system-pc"; + qcom,psci-mode = <0x3>; + qcom,entry-latency-us = <10831>; + qcom,exit-latency-us = <4506>; + qcom,min-residency-us = <15337>; + qcom,min-child-idx = <3>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cluster@0{ + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + label = "pwr"; + qcom,spm-device-names = "l2"; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0{ /* D1 */ + reg = <0>; + label = "pwr-l2-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <38>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <89>; + }; + qcom,pm-cluster-level@1{ /* D2D */ + reg = <1>; + label = "pwr-l2-dynret"; + qcom,psci-mode = <0x2>; + qcom,entry-latency-us = <360>; + qcom,exit-latency-us = <421>; + qcom,min-residency-us = <781>; + qcom,min-child-idx = <1>; + }; + + qcom,pm-cluster-level@2{ /* D2E */ + reg = <2>; + label = "pwr-l2-ret"; + qcom,psci-mode = <0x3>; + qcom,entry-latency-us = <800>; + qcom,exit-latency-us = <517>; + qcom,min-residency-us = <922>; + qcom,min-child-idx = <2>; + }; + + qcom,pm-cluster-level@3{ /* D4 */ + reg = <3>; + label = "pwr-l2-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <800>; + qcom,exit-latency-us = <2118>; + qcom,min-residency-us = <2918>; + qcom,min-child-idx = <2>; + qcom,is-reset; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <49>; + qcom,exit-latency-us = <42>; + qcom,min-residency-us = <91>; + }; + + qcom,pm-cpu-level@1 { /* C2D */ + reg = <1>; + qcom,psci-cpu-mode = <2>; + label = "ret"; + qcom,entry-latency-us = <70>; + qcom,exit-latency-us = <63>; + qcom,min-residency-us = <172>; + }; + + qcom,pm-cpu-level@2 { /* C3 */ + reg = <2>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <290>; + qcom,exit-latency-us = <376>; + qcom,min-residency-us = <666>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + + qcom,pm-cluster@1{ + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + label = "perf"; + qcom,spm-device-names = "l2"; + qcom,psci-mode-shift = <4>; + qcom,psci-mode-mask = <0xf>; + + qcom,pm-cluster-level@0{ /* D1 */ + reg = <0>; + label = "perf-l2-wfi"; + qcom,psci-mode = <0x1>; + qcom,entry-latency-us = <38>; + qcom,exit-latency-us = <51>; + qcom,min-residency-us = <89>; + }; + + qcom,pm-cluster-level@1{ /* D2D */ + reg = <1>; + label = "perf-l2-dynret"; + qcom,psci-mode = <2>; + qcom,entry-latency-us = <314>; + qcom,exit-latency-us = <345>; + qcom,min-residency-us = <659>; + qcom,min-child-idx = <1>; + }; + + qcom,pm-cluster-level@2{ /* D2E */ + reg = <2>; + label = "perf-l2-ret"; + qcom,psci-mode = <3>; + qcom,entry-latency-us = <375>; + qcom,exit-latency-us = <419>; + qcom,min-residency-us = <737>; + qcom,min-child-idx = <2>; + }; + + qcom,pm-cluster-level@3{ /* D4 */ + reg = <3>; + label = "perf-l2-pc"; + qcom,psci-mode = <0x4>; + qcom,entry-latency-us = <640>; + qcom,exit-latency-us = <1654>; + qcom,min-residency-us = <2294>; + qcom,min-child-idx = <2>; + qcom,is-reset; + }; + + qcom,pm-cpu { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,entry-latency-us = <29>; + qcom,exit-latency-us = <39>; + qcom,min-residency-us = <68>; + }; + + qcom,pm-cpu-level@1 { /* C2D */ + reg = <1>; + qcom,psci-cpu-mode = <2>; + label = "ret"; + qcom,entry-latency-us = <50>; + qcom,exit-latency-us = <60>; + qcom,min-residency-us = <181>; + }; + + qcom,pm-cpu-level@2 { /* C3 */ + reg = <2>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,entry-latency-us = <297>; + qcom,exit-latency-us = <324>; + qcom,min-residency-us = <621>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + }; + + qcom,rpm-stats@200000 { + compatible = "qcom,rpm-stats"; + reg = <0x200000 0x1000>, + <0x290014 0x4>, + <0x29001c 0x4>; + reg-names = "phys_addr_base", + "offset_addr", + "heap_phys_addrbase"; + qcom,sleep-stats-version = <2>; + }; + + qcom,rpm-master-stats@778150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x778150 0x5000>; + qcom,masters = "APSS", "MPSS", "ADSP", "CDSP", "TZ"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; + +/* TODO review changed values */ + rpm_msg_ram: memory@0x778000 { + compatible = "qcom,rpm-msg-ram"; + reg = <0x778000 0x7000>; + }; + + rpm_code_ram: rpm-memory@0x778000 { + compatible = "qcom,rpm-code-ram"; + reg = <0x778000 0x5000>; + }; + + qcom,system-stats { + compatible = "qcom,system-stats"; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + qcom,rpm-code-ram = <&rpm_code_ram>; + qcom,masters = "APSS", "MPSS", "ADSP", "CDSP", "TZ"; + }; + +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..e65a5d17bfc227aa77008da6dfa6db68d4467a01 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-cdp.dts @@ -0,0 +1,43 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>; + oledb-supply = <&pm660a_oledb>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; + +&mdss_dsi1 { + status = "disabled"; + oledb-supply = <&pm660a_oledb>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..fba7a22612e189fbc93d45934ffa2ead6797d3b6 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-headset-jacktype-no-cdp.dts @@ -0,0 +1,28 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A, Headset + Jacktype NO, CDP"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <1 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&mdss_dsi0 { + oledb-supply = <&pm660a_oledb>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; + +&mdss_dsi1 { + oledb-supply = <&pm660a_oledb>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..fd7347b9ca181ffa42f922086e9d7e8f0da33296 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-headset-jacktype-no-rcm.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A, Headset + Jacktype NO, RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..971e8d167aec8d27f0f04746f3adce1ec600dfd7 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-mtp.dts @@ -0,0 +1,37 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-mtp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>; + oledb-supply = <&pm660a_oledb>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; + +&mdss_dsi1 { + status = "disabled"; + oledb-supply = <&pm660a_oledb>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..a58021168994b38f2754de702b8932e684d57957 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-qrd.dts @@ -0,0 +1,45 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-qrd.dtsi" +#include "msm-pm660a.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A QRD"; + compatible = "qcom,sdm660-qrd", "qcom,sdm660", "qcom,qrd"; + qcom,board-id = <0x0012000b 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; + +&pm660a_oledb { + status = "okay"; + qcom,oledb-default-voltage-mv = <6400>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_rm67195_amoled_fhd_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..86df1b8abb1f6094dfe630134137e2a7f6da9d7c --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-rcm.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "msm-pm660a.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-sim.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-sim.dts new file mode 100644 index 0000000000000000000000000000000000000000..0690856ec069b04738c9470adb6f7d1ae5a5506e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660a-sim.dts @@ -0,0 +1,98 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-pinctrl.dtsi" +#include "msm-pm660a.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660A SIM"; + compatible = "qcom,sdm660-sim", "qcom,sdm660", "qcom,sim"; + qcom,board-id = <16 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>; + + chosen { + bootargs = "lpm_levels.sleep_disabled=1"; + }; +}; + +&usb3 { + reg = <0xa800000 0xfc000>; + reg-names = "core_base"; + /delete-property/ extcon; + dwc3@a800000 { + maximum-speed = "high-speed"; + }; +}; + +&ssphy { + compatible = "usb-nop-xceiv"; +}; + +&qusb_phy0 { + compatible = "usb-nop-xceiv"; +}; + +&uartblsp1dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 192000000 + 384000000>; + + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&pm660_charger { + status = "disabled"; +}; + +&pm660_fg { + status = "disabled"; +}; + +&pm660_pdphy { + status = "disabled"; +}; + +&ufsphy1 { + vdda-phy-supply = <&pm660l_l1>; + vdda-pll-supply = <&pm660_l10>; + vddp-ref-clk-supply = <&pm660_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660l.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660l.dts new file mode 100644 index 0000000000000000000000000000000000000000..9f398857af699687d8a7f930ce1307d339fd0456 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-pm660l.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +#include "sdm660.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660L SoC"; + compatible = "qcom,sdm660"; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..bb16e6c491f26f984f598c1345fd03eb60df52be --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd-external-codec-overlay.dts @@ -0,0 +1,84 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-wcd.dtsi" +#include "sdm660-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Ext. Audio Codec QRD"; + compatible = "qcom,sdm660-qrd", "qcom,sdm660", "qcom,qrd"; + qcom,board-id = <0x1000b 0>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_fb0 { + qcom,mdss-mixer-swap; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&soc { + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm660l_l3>; + vcc_dig-supply = <&pm660_l13>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3008000>; + qcom,afe-vtg-max = <3008000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1808000>; + qcom,dig-vtg-max = <1808000>; + qcom,fb-resume-delay-us = <10000>; + qcom,afe-force-power-on; + qcom,afe-power-on-delay-us = <1000>; + qcom,afe-power-off-delay-us = <6>; + }; +}; + +&slim_aud { + /delete-node/wcd934x_cdc; +}; + +&soc { + /delete-node/sound-tavil; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd.dts new file mode 100644 index 0000000000000000000000000000000000000000..2504c6b03a397b92ee7054786c037e9875ea8fb8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd.dts @@ -0,0 +1,89 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-qrd.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L QRD"; + compatible = "qcom,sdm660-qrd", "qcom,sdm660", "qcom,qrd"; + qcom,board-id = <0x1000b 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_fb0 { + qcom,mdss-mixer-swap; +}; + +&mdss_dsi { + hw-config = "split_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&mdss_dsi1 { + qcom,dsi-pref-prim-pan = <&dsi_dual_nt36850_truly_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 53 0>; + qcom,platform-te-gpio = <&tlmm 59 0>; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&pm660l_wled { + qcom,string-cfg= <6>; + status = "ok"; +}; + +&pm660l_lcdb { + status = "ok"; +}; + +&soc { + hbtp { + compatible = "qcom,hbtp-input"; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_rst_active>; + pinctrl-1 = <&ts_rst_suspend>; + vcc_ana-supply = <&pm660l_l3>; + vcc_dig-supply = <&pm660_l13>; + qcom,afe-load = <20000>; + qcom,afe-vtg-min = <3008000>; + qcom,afe-vtg-max = <3008000>; + qcom,dig-load = <40000>; + qcom,dig-vtg-min = <1808000>; + qcom,dig-vtg-max = <1808000>; + qcom,fb-resume-delay-us = <10000>; + qcom,afe-force-power-on; + qcom,afe-power-on-delay-us = <1000>; + qcom,afe-power-off-delay-us = <6>; + }; +}; + +&slim_aud { + /delete-node/wcd934x_cdc; +}; + +&soc { + /delete-node/sound-tavil; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d81bff357ae6f8569643d4510112b8a9805ed0c3 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-qrd.dtsi @@ -0,0 +1,274 @@ +#include +#include +#include "sdm660-camera-sensor-qrd.dtsi" +#include "sdm660-external-codec.dtsi" +/ { +}; + +&blsp2_uart1_hs { + status = "ok"; +}; + +&uartblsp1dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdc2_cd_on { + config { + /delete-property/ bias-pull-up; + bias-disable; + }; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x0>; + + status = "ok"; +}; + +&ufsphy1 { + vdda-phy-supply = <&pm660l_l1>; + vdda-pll-supply = <&pm660_l10>; + vddp-ref-clk-supply = <&pm660_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + status = "ok"; +}; + +&soc { + qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + }; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = <0xf8 0x80 + 0x83 0x84 + 0x83 0x88 + 0xc3 0x8c + 0x30 0x08 + 0x79 0x0c + 0x21 0x10 + 0x14 0x9c + 0x9f 0x1c + 0x00 0x18>; +}; + +&pm660_gpios { + /* GPIO 4 (NFC_CLK_REQ) */ + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_6 { /* BLSP1 QUP6 (NFC) */ + status = "okay"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 28 0x00>; + qcom,nq-ven = <&tlmm 29 0x00>; + qcom,nq-firm = <&tlmm 30 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 31 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <28 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK3_PIN>; + clock-names = "ref_clk"; + }; +}; + +&pm660l_gpios { + /* GPIO 7 for VOL_UP */ + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio7"; + function = "normal"; + input-enable; + bias-pull-up; + }; + }; +}; + +&tlmm { + pmx_ts_rst_active { + ts_rst_active: ts_rst_active { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + + pmx_ts_rst_suspend { + ts_rst_suspend: ts_rst_suspend { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; +}; + +&ssphy { + fpc-redrive-supply = <&pm660_l11>; + qcom,redrive-voltage-level = <0 1800000 1950000>; + qcom,redrive-load = <105000>; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + status = "ok"; + + vol_up { + label = "volume_up"; + gpios = <&pm660l_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; +}; + +/ { + qrd_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + + #include "fg-gen3-batterydata-qrd-skuk-4v4-3000mah.dtsi" + }; +}; + +&pm660_fg { + qcom,battery-data = <&qrd_batterydata>; + qcom,fg-jeita-thresholds = <0 5 55 55>; + qcom,battery-thermal-coefficients = [9d 50 ff]; +}; + +&pm660_haptics { + qcom,vmax-mv = <1800>; +}; + +&i2c_2 { + status = "ok"; + smb1351_charger: smb1351-charger@1d { + compatible = "qcom,smb1351-charger"; + reg = <0x1d>; + qcom,parallel-charger; + qcom,float-voltage-mv = <4400>; + qcom,recharge-mv = <100>; + qcom,parallel-en-pin-polarity = <1>; + }; +}; + +/delete-node/ &tasha_hph_en0; +/delete-node/ &tasha_hph_en1; + +&tasha_snd { + qcom,model = "sdm660-tasha-skus-snd-card"; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC5", "MIC BIAS3", + "MIC BIAS3", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT"; + qcom,msm-mbhc-hphl-swh = <1>; + /delete-property/ qcom,us-euro-gpios; + /delete-property/ qcom,hph-en0-gpio; + /delete-property/ qcom,hph-en1-gpio; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; + diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm-external-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm-external-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..1f4d02f029fcaee59dbdd54e30291c7d9e01fd7b --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm-external-codec-overlay.dts @@ -0,0 +1,28 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Ext. Audio Codec RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 0>; +}; + + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm-internal-codec-overlay.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm-internal-codec-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..21381839e0d7b49793535d17bad861698320f56e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm-internal-codec-overlay.dts @@ -0,0 +1,17 @@ +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm660-cdp.dtsi" +#include "sdm660-internal-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 Int. Audio Codec RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..73a81662cc748c9e6338b3a5e7ec4bc704111585 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-rcm.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; + +&tasha_snd { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-regulator.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-regulator.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..bc317a391b8c1622ab35d3fef1fa6a668e94d5f0 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-regulator.dtsi @@ -0,0 +1,949 @@ +#include +#include +#include +#include + +&rpm_bus { + rpm-regulator-smpa4 { + status = "okay"; + pm660_s4: regulator-s4 { + regulator-min-microvolt = <1805000>; + regulator-max-microvolt = <2040000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa5 { + status = "okay"; + pm660_s5: regulator-s5 { + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1350000>; + status = "okay"; + }; + }; + + rpm-regulator-smpa6 { + status = "okay"; + pm660_s6: regulator-s6 { + regulator-min-microvolt = <504000>; + regulator-max-microvolt = <992000>; + status = "okay"; + }; + }; + + rpm-regulator-smpb1 { + status = "okay"; + pm660l_s1: regulator-s1 { + regulator-min-microvolt = <1125000>; + regulator-max-microvolt = <1125000>; + status = "okay"; + }; + }; + + rpm-regulator-smpb2 { + status = "okay"; + pm660l_s2: regulator-s2 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + status = "okay"; + }; + }; + + /* PM660L S3 + S4 - VDD_CX supply */ + rpm-regulator-smpb3 { + status = "okay"; + pm660l_s3_level: regulator-s3-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s3_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pm660l_s3_floor_level: regulator-s3-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s3_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + pm660l_s3_level_ao: regulator-s3-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s3_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + cx_cdev: cx-cdev { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pm660l_s3_floor_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; + + }; + + /* PM660L S5 - VDD_MX supply */ + rpm-regulator-smpb5 { + status = "okay"; + pm660l_s5_level: regulator-s5-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s5_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pm660l_s5_floor_level: regulator-s5-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s5_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + + pm660l_s5_level_ao: regulator-s5-level-ao { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_s5_level_ao"; + qcom,set = <1>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + }; + + rpm-regulator-ldoa1 { + status = "okay"; + pm660_l1: regulator-l1 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1250000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa2 { + status = "okay"; + pm660_l2: regulator-l2 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa3 { + status = "okay"; + pm660_l3: regulator-l3 { + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1010000>; + status = "okay"; + }; + }; + + /* TODO: remove if ADRASTEA CX/MX not voted from APPS */ + rpm-regulator-ldoa5 { + status = "okay"; + pm660_l5: regulator-l5 { + regulator-min-microvolt = <525000>; + regulator-max-microvolt = <950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa6 { + status = "okay"; + pm660_l6: regulator-l6 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1370000>; + status = "okay"; + }; + + pm660_l6_pin_ctrl: regulator-l6-pin-ctrl { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l6_pin_ctrl"; + qcom,set = <3>; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1370000>; + /* Force NPM follows HW_EN1 */ + qcom,init-pin-ctrl-mode = <2>; + /* Enable follows HW_EN1 */ + qcom,enable-with-pin-ctrl = <0 2>; + }; + }; + + rpm-regulator-ldoa7 { + status = "okay"; + pm660_l7: regulator-l7 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa8 { + status = "okay"; + pm660_l8: regulator-l8 { + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa9 { + status = "okay"; + pm660_l9: regulator-l9 { + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + status = "okay"; + }; + + pm660_l9_pin_ctrl: regulator-l9-pin-ctrl { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l9_pin_ctrl"; + qcom,set = <3>; + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <1900000>; + /* Force NPM follows HW_EN1 */ + qcom,init-pin-ctrl-mode = <2>; + /* Enable follows HW_EN1 */ + qcom,enable-with-pin-ctrl = <0 2>; + }; + }; + + rpm-regulator-ldoa10 { + status = "okay"; + pm660_l10: regulator-l10 { + proxy-supply = <&pm660_l10>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <14000>; + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa11 { + status = "okay"; + pm660_l11: regulator-l11 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa12 { + status = "okay"; + pm660_l12: regulator-l12 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa13 { + status = "okay"; + pm660_l13: regulator-l13 { + regulator-min-microvolt = <1780000>; + regulator-max-microvolt = <1950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa14 { + status = "okay"; + pm660_l14: regulator-l14 { + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <1900000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa15 { + status = "okay"; + pm660_l15: regulator-l15 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa17 { + status = "okay"; + pm660_l17: regulator-l17 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldoa19 { + status = "okay"; + pm660_l19: regulator-l19 { + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + status = "okay"; + }; + + pm660_l19_pin_ctrl: regulator-l19-pin-ctrl { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660_l19_pin_ctrl"; + qcom,set = <3>; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + /* Force NPM follows HW_EN1 */ + qcom,init-pin-ctrl-mode = <2>; + /* Enable follows HW_EN1 */ + qcom,enable-with-pin-ctrl = <0 2>; + }; + }; + + rpm-regulator-ldob1 { + status = "okay"; + pm660l_l1: regulator-l1 { + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <925000>; + status = "okay"; + }; + }; + + rpm-regulator-ldob2 { + status = "okay"; + pm660l_l2: regulator-l2 { + regulator-min-microvolt = <350000>; + regulator-max-microvolt = <3100000>; + status = "okay"; + }; + }; + + rpm-regulator-ldob3 { + status = "okay"; + pm660l_l3: regulator-l3 { + regulator-min-microvolt = <1710000>; + regulator-max-microvolt = <3600000>; + status = "okay"; + }; + }; + + rpm-regulator-ldob4 { + status = "okay"; + pm660l_l4: regulator-l4 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <2950000>; + status = "okay"; + }; + }; + + rpm-regulator-ldob5 { + status = "okay"; + pm660l_l5: regulator-l5 { + regulator-min-microvolt = <1721000>; + regulator-max-microvolt = <3600000>; + status = "okay"; + }; + }; + + rpm-regulator-ldob6 { + status = "okay"; + pm660l_l6: regulator-l6 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; + }; + + rpm-regulator-ldob7 { + status = "okay"; + pm660l_l7: regulator-l7 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3125000>; + parent-supply = <&pm660_l10>; + status = "okay"; + }; + }; + + rpm-regulator-ldob8 { + status = "okay"; + pm660l_l8: regulator-l8 { + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3400000>; + status = "okay"; + }; + }; + + /* PM660L L9 = VDD_SSC_CX supply */ + rpm-regulator-ldob9 { + status = "okay"; + pm660l_l9_level: regulator-l9-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l9_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pm660l_l9_floor_level: regulator-l9-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l9_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + }; + + /* PM660L L10 = VDD_SSC_MX supply */ + rpm-regulator-ldob10 { + status = "okay"; + pm660l_l10_level: regulator-l10-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l10_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-level; + }; + + pm660l_l10_floor_level: regulator-l10-floor-level { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_l10_floor_level"; + qcom,set = <3>; + regulator-min-microvolt = + ; + regulator-max-microvolt = + ; + qcom,use-voltage-floor-level; + qcom,always-send-voltage; + }; + }; + + rpm-regulator-bobb { + status = "okay"; + pm660l_bob: regulator-bob { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + qcom,pwm-threshold-current = <2000000>; + qcom,init-bob-mode = <2>; + status = "okay"; + }; + + pm660l_bob_pin1: regulator-bob-pin1 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_bob_pin1"; + qcom,set = <3>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + qcom,pwm-threshold-current = <2000000>; + qcom,init-bob-mode = <2>; + qcom,use-pin-ctrl-voltage1; + }; + + pm660l_bob_pin2: regulator-bob-pin2 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_bob_pin2"; + qcom,set = <3>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + qcom,pwm-threshold-current = <2000000>; + qcom,init-bob-mode = <2>; + qcom,use-pin-ctrl-voltage2; + }; + + pm660l_bob_pin3: regulator-bob-pin3 { + compatible = "qcom,rpm-smd-regulator"; + regulator-name = "pm660l_bob_pin3"; + qcom,set = <3>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3600000>; + qcom,pwm-threshold-current = <2000000>; + qcom,init-bob-mode = <2>; + qcom,use-pin-ctrl-voltage3; + }; + }; +}; + +&pm660_charger { + smb2_vbus: qcom,smb2-vbus { + regulator-name = "smb2-vbus"; + }; + + smb2_vconn: qcom,smb2-vconn { + regulator-name = "smb2-vconn"; + }; +}; + +/* Stub regulators */ +/ { + /* GFX Supply */ + gfx_stub_vreg: regulator-gfx-stub { + compatible = "qcom,stub-regulator"; + regulator-name = "gfx_stub_corner"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <1070000>; + }; +}; + +&soc { + /* MEM ACC regulators */ + gfx_mem_acc_vreg: regulator@01fcf004 { + compatible = "qcom,mem-acc-regulator"; + reg = <0x01fcf004 0x4>; + reg-names = "acc-sel-l1"; + regulator-name = "gfx_mem_acc_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <2>; + + qcom,corner-acc-map = <0x1 0x0>; + qcom,acc-sel-l1-bit-pos = <0>; + qcom,acc-sel-l1-bit-size = <1>; + }; + + gfx_ldo_vreg: ldo@0506e000 { + compatible = "qcom,sdm660-gfx-ldo"; + reg = <0x0506e000 0x34>; + reg-names = "ldo_addr"; + regulator-name = "msm_gfx_ldo"; + regulator-min-microvolt = <400000>; + regulator-max-microvolt = <925000>; + }; + +/* CPR controller regulators */ + /* MMSS CPR Controller node */ + gfx_cpr: cpr4-ctrl@05061000 { + compatible = "qcom,cpr4-sdm660-mmss-ldo-regulator"; + reg = <0x05061000 0x4000>, <0x00784000 0x1000>; + reg-names = "cpr_ctrl", "fuse_base"; + clocks = <&clock_gpu GPUCC_RBCPR_CLK>, + <&clock_rpmcc RPM_SMD_CNOC_CLK>; + clock-names = "core_clk", "bus_clk"; + interrupts = ; + interrupt-names = "cpr"; + qcom,cpr-ctrl-name = "gfx"; + + + qcom,cpr-sensor-time = <1000>; + qcom,cpr-loop-time = <5000000>; + qcom,cpr-idle-cycles = <15>; + qcom,cpr-step-quot-init-min = <12>; + qcom,cpr-step-quot-init-max = <14>; + qcom,cpr-count-mode = <0>; /* All at once */ + qcom,cpr-count-repeat = <14>; + qcom,cpr-reset-step-quot-loop-en; + + vdd-supply = <&gfx_stub_vreg>; + mem-acc-supply = <&gfx_mem_acc_vreg>; + system-supply = <&pm660l_s3_level>; /* vdd_cx */ + qcom,voltage-step = <5000>; + vdd-thread0-ldo-supply = <&gfx_ldo_vreg>; + + thread@0 { + qcom,cpr-thread-id = <0>; + qcom,cpr-consecutive-up = <0>; + qcom,cpr-consecutive-down = <2>; + qcom,cpr-up-threshold = <2>; + qcom,cpr-down-threshold = <2>; + + gfx_vreg_corner: regulator { + regulator-name = "gfx_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,cpr-fuse-corners = <6>; + qcom,cpr-fuse-combos = <8>; + qcom,cpr-corners = <7>; + + qcom,cpr-corner-fmax-map = <1 2 3 4 5 6>; + + qcom,cpr-voltage-ceiling = + <585000 645000 725000 790000 + 870000 925000 1070000>; + qcom,cpr-voltage-floor = + <504000 504000 596000 652000 + 712000 744000 1070000>; + + qcom,mem-acc-voltage = <1 1 1 2 2 2 2>; + qcom,system-voltage = + , + , + , + , + , + , + ; + + qcom,corner-frequencies = + <160000000 266000000 370000000 + 465000000 588000000 647000000 + 750000000>; + + qcom,cpr-target-quotients = + <0 0 0 0 0 0 174 167 + 294 292 303 313 0 0 0 0>, + <0 0 0 0 0 0 263 247 + 413 397 415 412 0 0 0 0>, + <0 0 0 0 0 0 375 354 + 554 519 573 554 0 0 0 0>, + <0 0 0 0 0 0 412 380 + 597 562 612 591 0 0 0 0>, + <0 0 0 0 0 0 513 476 + 722 680 738 718 0 0 0 0>, + <0 0 0 0 0 0 595 553 + 811 768 837 811 0 0 0 0>, + <0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0>; + + qcom,cpr-ro-scaling-factor = + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>, + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>, + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>, + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>, + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>, + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>, + < 0 0 0 0 0 0 1790 1760 + 1990 1900 2140 2020 0 0 0 0>; + + qcom,cpr-scaled-open-loop-voltage-as-ceiling; + qcom,cpr-corner-allow-ldo-mode = + <0 0 0 0 0 0 0>; + qcom,cpr-corner-allow-closed-loop = + <0 0 0 0 0 0 0>; + }; + }; + }; + + /* APC0 CPR Controller node for Silver cluster */ + apc0_cpr: cprh-ctrl@179c8000 { + compatible = "qcom,cprh-sdm660-kbss-regulator"; + reg = <0x179c8000 0x4000>, <0x00784000 0x1000>; + reg-names = "cpr_ctrl", "fuse_base"; + clocks = <&clock_gcc GCC_HMSS_RBCPR_CLK>; + clock-names = "core_clk"; + qcom,cpr-ctrl-name = "apc0"; + qcom,cpr-controller-id = <0>; + + qcom,cpr-sensor-time = <1000>; + qcom,cpr-loop-time = <5000000>; + qcom,cpr-idle-cycles = <15>; + qcom,cpr-up-down-delay-time = <3000>; + qcom,cpr-step-quot-init-min = <12>; + qcom,cpr-step-quot-init-max = <14>; + qcom,cpr-count-mode = <0>; /* All at once */ + qcom,cpr-count-repeat = <14>; + qcom,cpr-down-error-step-limit = <1>; + qcom,cpr-up-error-step-limit = <1>; + qcom,cpr-corner-switch-delay-time = <1042>; + qcom,cpr-voltage-settling-time = <1760>; + + qcom,apm-threshold-voltage = <872000>; + qcom,apm-crossover-voltage = <872000>; + qcom,apm-hysteresis-voltage = <20000>; + qcom,voltage-step = <4000>; + qcom,voltage-base = <400000>; + qcom,cpr-saw-use-unit-mV; + qcom,cpr-reset-step-quot-loop-en; + + qcom,cpr-panic-reg-addr-list = + <0x179cbaa4 0x17912c18>; + qcom,cpr-panic-reg-name-list = + "PWR_CPRH_STATUS", "APCLUS0_L2_SAW4_PMIC_STS"; + + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + + thread@0 { + qcom,cpr-thread-id = <0>; + qcom,cpr-consecutive-up = <0>; + qcom,cpr-consecutive-down = <2>; + qcom,cpr-up-threshold = <2>; + qcom,cpr-down-threshold = <2>; + + apc0_pwrcl_vreg: regulator { + regulator-name = "apc0_pwrcl_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <8>; + + qcom,cpr-fuse-corners = <5>; + qcom,cpr-fuse-combos = <40>; + qcom,cpr-speed-bins = <5>; + qcom,cpr-speed-bin-corners = <8 8 0 8 8>; + qcom,cpr-corners = + /* Speed bin 0 */ + <8 8 8 8 8 8 8 8>, + + /* Speed bin 1 */ + <8 8 8 8 8 8 8 8>, + + /* Speed bin 2 */ + <0 0 0 0 0 0 0 0>, + + /* Speed bin 3 */ + <8 8 8 8 8 8 8 8>, + + /* Speed bin 4 */ + <8 8 8 8 8 8 8 8>; + + qcom,cpr-corner-fmax-map = + /* Speed bin 0 */ + <2 3 4 5 8>, + + /* Speed bin 1 */ + <2 3 4 5 8>, + + /* Speed bin 2 */ + <0 0 0 0 0>, + + /* Speed bin 3 */ + <2 3 4 5 8>, + + /* Speed bin 4 */ + <2 3 4 5 8>; + + qcom,cpr-voltage-ceiling = + < 724000 724000 724000 788000 868000 + 1068000 1068000 1068000>; + + qcom,cpr-voltage-floor = + <588000 588000 596000 652000 712000 + 744000 784000 844000>; + + qcom,corner-frequencies = + /* Speed bin 0 */ + <300000000 633600000 902400000 + 1113600000 1401600000 1536000000 + 1747200000 1843200000>, + + /* Speed bin 1 */ + <300000000 633600000 902400000 + 1113600000 1401600000 1536000000 + 1747200000 1843200000>, + + /* Speed bin 3 */ + <300000000 633600000 902400000 + 1113600000 1401600000 1536000000 + 1612800000 1843200000>, + + /* Speed bin 4 */ + <300000000 633600000 902400000 + 1113600000 1401600000 1536000000 + 1747200000 1843200000>; + + qcom,allow-voltage-interpolation; + qcom,allow-quotient-interpolation; + qcom,cpr-scaled-open-loop-voltage-as-ceiling; + + qcom,cpr-ro-scaling-factor = + <3600 3600 3830 2430 2520 2700 1790 + 1760 1970 1880 2110 2010 2510 4900 + 4370 4780>, + <3600 3600 3830 2430 2520 2700 1790 + 1760 1970 1880 2110 2010 2510 4900 + 4370 4780>, + <3600 3600 3830 2430 2520 2700 1790 + 1760 1970 1880 2110 2010 2510 4900 + 4370 4780>, + <3600 3600 3830 2430 2520 2700 1790 + 1760 1970 1880 2110 2010 2510 4900 + 4370 4780>, + <3600 3600 3830 2430 2520 2700 1790 + 1760 1970 1880 2110 2010 2510 4900 + 4370 4780>; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + < (-4000) 4000 7000 19000 (-8000)>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + <(-32000) (-30000) (-29000) (-23000) + (-21000)>; + + qcom,cpr-floor-to-ceiling-max-range = + <32000 32000 32000 40000 44000 + 40000 40000 40000>; + }; + }; + }; + + /* APC1 CPR Controller node for Gold cluster */ + apc1_cpr: cprh-ctrl@179c4000 { + compatible = "qcom,cprh-sdm660-kbss-regulator"; + reg = <0x179c4000 0x4000>, <0x00784000 0x1000>; + reg-names = "cpr_ctrl", "fuse_base"; + clocks = <&clock_gcc GCC_HMSS_RBCPR_CLK>; + clock-names = "core_clk"; + qcom,cpr-ctrl-name = "apc1"; + qcom,cpr-controller-id = <1>; + + qcom,cpr-sensor-time = <1000>; + qcom,cpr-loop-time = <5000000>; + qcom,cpr-idle-cycles = <15>; + qcom,cpr-up-down-delay-time = <3000>; + qcom,cpr-step-quot-init-min = <12>; + qcom,cpr-step-quot-init-max = <14>; + qcom,cpr-count-mode = <0>; /* All at once */ + qcom,cpr-count-repeat = <14>; + qcom,cpr-down-error-step-limit = <1>; + qcom,cpr-up-error-step-limit = <1>; + qcom,cpr-corner-switch-delay-time = <1042>; + qcom,cpr-voltage-settling-time = <1760>; + + qcom,apm-threshold-voltage = <872000>; + qcom,apm-crossover-voltage = <872000>; + qcom,apm-hysteresis-voltage = <20000>; + qcom,voltage-step = <4000>; + qcom,voltage-base = <400000>; + qcom,cpr-saw-use-unit-mV; + qcom,cpr-reset-step-quot-loop-en; + + qcom,cpr-panic-reg-addr-list = + <0x179c7aa4 0x17812c18>; + qcom,cpr-panic-reg-name-list = + "PERF_CPRH_STATUS", "APCLUS1_L2_SAW4_PMIC_STS"; + + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + + thread@0 { + qcom,cpr-thread-id = <0>; + qcom,cpr-consecutive-up = <0>; + qcom,cpr-consecutive-down = <2>; + qcom,cpr-up-threshold = <2>; + qcom,cpr-down-threshold = <2>; + + apc1_perfcl_vreg: regulator { + regulator-name = "apc1_perfcl_corner"; + regulator-min-microvolt = <1>; + regulator-max-microvolt = <7>; + + qcom,cpr-fuse-corners = <5>; + qcom,cpr-fuse-combos = <40>; + qcom,cpr-speed-bins = <5>; + qcom,cpr-speed-bin-corners = <7 7 0 7 7>; + qcom,cpr-corners = + /* Speed-bin 0 */ + <7 7 7 7 7 7 7 7>, + + /* Speed-bin 1 */ + <7 7 7 7 7 7 7 7>, + + /* Speed-bin 1 */ + <0 0 0 0 0 0 0 0>, + + /* Speed-bin 3 */ + <7 7 7 7 7 7 7 7>, + + /* Speed-bin 4 */ + <7 7 7 7 7 7 7 7>; + + qcom,cpr-corner-fmax-map = + /* Speed-bin 0 */ + <2 3 4 6 7>, + + /* Speed-bin 1 */ + <2 3 4 6 7>, + + /* Speed-bin 2 */ + <0 0 0 0 0>, + + /* Speed-bin 3 */ + <2 3 4 6 7>, + + /* Speed-bin 4 */ + <2 3 4 6 7>; + + qcom,cpr-voltage-ceiling = + <724000 724000 788000 868000 + 988000 988000 1068000>; + + qcom,cpr-voltage-floor = + <588000 596000 652000 712000 + 744000 784000 844000>; + + qcom,corner-frequencies = + /* Speed bin 0 */ + <300000000 1113600000 1401600000 + 1747200000 1958400000 2150400000 + 2457600000>, + + /* Speed bin 1 */ + <300000000 1113600000 1401600000 + 1747200000 1958400000 2150400000 + 2208000000>, + + /* Speed bin 3 */ + <300000000 1113600000 1401600000 + 1747200000 1804800000 2150400000 + 2208000000>, + + /* Speed bin 4 */ + <300000000 1113600000 1401600000 + 1747200000 1958400000 2150400000 + 2208000000>; + + qcom,allow-voltage-interpolation; + qcom,allow-quotient-interpolation; + qcom,cpr-scaled-open-loop-voltage-as-ceiling; + + qcom,cpr-ro-scaling-factor = + <4040 4230 0000 2210 2560 2450 2230 + 2220 2410 2300 2560 2470 1600 3120 + 2620 2280>, + <4040 4230 0000 2210 2560 2450 2230 + 2220 2410 2300 2560 2470 1600 3120 + 2620 2280>, + <4040 4230 0000 2210 2560 2450 2230 + 2220 2410 2300 2560 2470 1600 3120 + 2620 2280>, + <4040 4230 0000 2210 2560 2450 2230 + 2220 2410 2300 2560 2470 1600 3120 + 2620 2280>, + <4040 4230 0000 2210 2560 2450 2230 + 2220 2410 2300 2560 2470 1600 3120 + 2620 2280>; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + <16000 27000 39000 39000 20000>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + <(-22000) (-9000) (-7000) (-2000) + 11000>; + + qcom,cpr-floor-to-ceiling-max-range = + <40000 40000 40000 40000 + 66000 66000 40000>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-sim.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-sim.dts new file mode 100644 index 0000000000000000000000000000000000000000..01658e98a151c672fd17f96873eb4bca22454c82 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-sim.dts @@ -0,0 +1,121 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-pinctrl.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L SIM"; + compatible = "qcom,sdm660-sim", "qcom,sdm660", "qcom,sim"; + qcom,board-id = <16 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; + + chosen { + bootargs = "lpm_levels.sleep_disabled=1"; + }; +}; + +&usb3 { + reg = <0xa800000 0xfc000>; + reg-names = "core_base"; + /delete-property/ extcon; + dwc3@a800000 { + maximum-speed = "high-speed"; + }; +}; + +&ssphy { + compatible = "usb-nop-xceiv"; +}; + +&qusb_phy0 { + compatible = "usb-nop-xceiv"; +}; + +&uartblsp1dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm660l_l4>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm660l_l5>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm660l_l2>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 0 125 0 + 1 &intc 0 0 221 0 + 2 &tlmm 54 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 54 0x1>; + + status = "ok"; +}; + +&pm660_charger { + status = "disabled"; +}; + +&pm660_fg { + status = "disabled"; +}; + +&pm660_pdphy { + status = "disabled"; +}; + +&ufsphy1 { + vdda-phy-supply = <&pm660l_l1>; + vdda-pll-supply = <&pm660_l10>; + vddp-ref-clk-supply = <&pm660_l1>; + vdda-phy-max-microamp = <51400>; + vdda-pll-max-microamp = <14200>; + vddp-ref-clk-max-microamp = <100>; + vddp-ref-clk-always-on; + status = "ok"; +}; + +&ufs1 { + vdd-hba-supply = <&gdsc_ufs>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm660l_l4>; + vccq2-supply = <&pm660_l8>; + vcc-max-microamp = <500000>; + vccq2-max-microamp = <600000>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-thermal.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-thermal.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..813a8e61d589e427f4a473289a684e337cb93839 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-thermal.dtsi @@ -0,0 +1,915 @@ +#include + +&clock_cpu { + #address-cells = <1>; + #size-cells = <1>; + lmh_dcvs0: qcom,limits-dcvs@179ce800 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + reg = <0x179ce800 0x1000>, + <0x179c1400 0x1000>; + qcom,legacy-lmh-enable; + qcom,no-cooling-device-register; + }; + + lmh_dcvs1: qcom,limits-dcvs@0x179cc808 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + reg = <0x179cc800 0x1000>, + <0x179c3400 0x1000>; + qcom,legacy-lmh-enable; + qcom,no-cooling-device-register; + }; + + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + + cpu4_isolate: cpu4-isolate { + qcom,cpu = <&CPU4>; + #cooling-cells = <2>; + }; + + cpu5_isolate: cpu5-isolate { + qcom,cpu = <&CPU5>; + #cooling-cells = <2>; + }; + + cpu6_isolate: cpu6-isolate { + qcom,cpu = <&CPU6>; + #cooling-cells = <2>; + }; + + cpu7_isolate: cpu7-isolate { + qcom,cpu = <&CPU7>; + #cooling-cells = <2>; + }; + }; +}; + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + xo-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm660_adc_tm ADC_XO_THERM_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + msm-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm660_adc_tm ADC_AMUX_THM1_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm660_adc_tm ADC_AMUX_THM5_PU2>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + ibat-high { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 0>; + + trips { + pm660_ibat_high: ibat-high { + temperature = <4200>; + hysteresis = <200>; + type = "passive"; + }; + }; + + cooling-maps { + ibat_map6 { + trip = <&pm660_ibat_high>; + cooling-device = + <&cpu6_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + ibat_map7 { + trip = <&pm660_ibat_high>; + cooling-device = + <&cpu7_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + ibat-vhigh { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 1>; + + trips { + pm660_ibat_vhigh: ibat-vhigh { + temperature = <4300>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + + vbat_adc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 2>; + tracks-low; + + trips { + pm660_vbat_adc: vbat-adc { + temperature = <3500>; + hysteresis = <100>; + type = "passive"; + }; + }; + + cooling-maps { + vbat_map4 { + trip = <&pm660_vbat_adc>; + cooling-device = + <&cpu4_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + vbat_map5 { + trip = <&pm660_vbat_adc>; + cooling-device = + <&cpu5_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + vbat_map6 { + trip = <&pm660_vbat_adc>; + cooling-device = + <&cpu6_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + vbat_map7 { + trip = <&pm660_vbat_adc>; + cooling-device = + <&cpu7_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + vbat_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 3>; + tracks-low; + + trips { + pm660_vbat_low: vbat-low { + temperature = <2800>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + vbat_too_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 4>; + tracks-low; + + trips { + pm660_vbat_too_low: vbat-too-low { + temperature = <2600>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + + mpm-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 0>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 1>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 2>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 3>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 4>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 5>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 6>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 7>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpu-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 8>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 9>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 10>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 11>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 12>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cdsp-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&tsens 13>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + reset-mon-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpu-step { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens 8>; + wake-capable-sensor; + trips { + gpu_trip: gpu-trip { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + gpu_cdev0 { + trip = <&gpu_trip>; + cooling-device = + <&msm_gpu THERMAL_NO_LIMIT + THERMAL_NO_LIMIT>; + }; + }; + }; + + quiet-therm-step { + polling-delay-passive = <2000>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm660_adc_tm ADC_AMUX_THM5_PU2>; + wake-capable-sensor; + trips { + gold_trip: gold-trip { + temperature = <50000>; + hysteresis = <0>; + type = "passive"; + }; + + silver_trip: silver-trip { + temperature = <53000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + /* throttle from fmax to 1536000KHz */ + skin_cpu0 { + trip = <&silver_trip>; + cooling-device = <&CPU0 THERMAL_NO_LIMIT 3>; + }; + + skin_cpu4 { + trip = <&gold_trip>; + /* throttle from fmax to 1747200KHz */ + cooling-device = <&CPU4 THERMAL_NO_LIMIT 5>; + }; + }; + }; + + cpuss-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&tsens 1>; + wake-capable-sensor; + trips { + cpu_03_config: cpu_03-config { + temperature = <105000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu0_cdev { + trip = <&cpu_03_config>; + cooling-device = <&cpu0_isolate 1 1>; + }; + + cpu1_cdev { + trip = <&cpu_03_config>; + cooling-device = <&cpu1_isolate 1 1>; + }; + + cpu2_cdev { + trip = <&cpu_03_config>; + cooling-device = <&cpu2_isolate 1 1>; + }; + + cpu3_cdev { + trip = <&cpu_03_config>; + cooling-device = <&cpu3_isolate 1 1>; + }; + }; + }; + + cpu-1-0-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 3>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu4_0_config: cpu4-0-config { + temperature = <105000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu4_cdev { + trip = <&cpu4_0_config>; + cooling-device = <&cpu4_isolate 1 1>; + }; + }; + }; + + cpu-1-1-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 4>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu5_0_config: cpu5-0-config { + temperature = <105000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu5_cdev { + trip = <&cpu5_0_config>; + cooling-device = <&cpu5_isolate 1 1>; + }; + }; + }; + + cpu-1-2-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 5>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu6_0_config: cpu6-0-config { + temperature = <105000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu6_cdev { + trip = <&cpu6_0_config>; + cooling-device = <&cpu6_isolate 1 1>; + }; + }; + }; + + cpu-1-3-step { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens 6>; + thermal-governor = "step_wise"; + wake-capable-sensor; + trips { + cpu7_1_config: cpu7-1-config { + temperature = <105000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu7_cdev { + trip = <&cpu7_1_config>; + cooling-device = <&cpu7_isolate 1 1>; + }; + }; + }; + + mpm-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens 0>; + wake-capable-sensor; + tracks-low; + trips { + mpm_trip: mpm-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu0_cdev { + trip = <&mpm_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + cpu4_cdev { + trip = <&mpm_trip>; + cooling-device = <&CPU4 (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + + gpu_vdd_cdev { + trip = <&mpm_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + cx_vdd_cdev { + trip = <&mpm_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + + modem_vdd_cdev { + trip = <&mpm_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + }; + }; + + camera-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens 11>; + tracks-low; + trips { + camera_trip: camera-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + + cooling-maps { + cpu0_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU0 (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + cpu4_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU4 (THERMAL_MAX_LIMIT-3) + (THERMAL_MAX_LIMIT-3)>; + }; + + gpu_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&msm_gpu (THERMAL_MAX_LIMIT-4) + (THERMAL_MAX_LIMIT-4)>; + }; + + cx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + }; + }; + + soc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 5>; + tracks-low; + + trips { + pm660_low_soc: low-soc { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + soc_map4 { + trip = <&pm660_low_soc>; + cooling-device = + <&cpu4_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + soc_map5 { + trip = <&pm660_low_soc>; + cooling-device = + <&cpu5_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + soc_map6 { + trip = <&pm660_low_soc>; + cooling-device = + <&cpu6_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + soc_map7 { + trip = <&pm660_low_soc>; + cooling-device = + <&cpu7_isolate THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-usbc-audio-mtp.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-usbc-audio-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..22d231575fce1431e8a86c3b2c300aa83dee171a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-usbc-audio-mtp.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-mtp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, USBC + Audio MTP"; + compatible = "qcom,sdm660-mtp", "qcom,sdm660", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; + qcom,msm-mbhc-usbc-audio-supported = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-usbc-audio-rcm.dts b/arch/arm64/boot/dts/vendor/qcom/sdm660-usbc-audio-rcm.dts new file mode 100644 index 0000000000000000000000000000000000000000..05363318cbe03008dc242b4e93f65c4c387a2405 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-usbc-audio-rcm.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +#include "sdm660.dtsi" +#include "sdm660-cdp.dtsi" +#include "sdm660-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM 660 PM660 + PM660L, USBC + Audio, RCM"; + compatible = "qcom,sdm660-cdp", "qcom,sdm660", "qcom,cdp"; + qcom,board-id = <21 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&tavil_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-vidc.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-vidc.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a4958a95ca127ed2ff5b7916b525d584a3fd782a --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-vidc.dtsi @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include + + +&soc { + msm_vidc: qcom,vidc@cc00000 { + compatible = "qcom,msm-vidc"; + status = "ok"; + reg = <0xcc00000 0x100000>; + interrupts = ; + qcom,hfi = "venus"; + qcom,hfi-version = "3xx"; + qcom,firmware-name = "venus"; + qcom,never-unload-fw; + qcom,sw-power-collapse; + qcom,max-secure-instances = <5>; + qcom,reg-presets = + <0x80010 0x001f001f>, + <0x80018 0x00000156>, + <0x8001c 0x00000156>; + + qcom,max-hw-load = <1036800>; /* Full 4k @ 30 */ + qcom,allowed-clock-rates = + /* TURBO NOM+ NOM + * SVS+ SVS SVS- + */ + <518400000 441600000 404000000 + 320000000 269330000 133330000>; + + qcom,dcvs-tbl = + /* Dec UHD@30 All decoder - NOM to SVS+ */ + <897600 783360 979200 0x3f00000c>, + + /* Dec DCI@24 HEVC - NOM to SVS+ */ + <816000 734400 829440 0x0c000000>, + + /* Enc UHD@30 H264/HEVC - TURBO to NOM+ */ + <897600 897600 979200 0x4000004>; + qcom,dcvs-limit = + <32400 30>, /* Encoder UHD */ + <32400 24>; /* Decoder UHD */ + + /* Regulators */ + smmu-vdd-supply = <&gdsc_bimc_smmu>; + venus-supply = <&gdsc_venus>; + venus-core0-supply = <&gdsc_venus_core0>; + + /* Clocks */ + clock-names = "gcc_mmss_sys_noc_axi_clk", + "mmssnoc_axi_clk", "mmss_throttle_video_axi_clk", + "mmss_mnoc_ahb_clk", "mmss_bimc_smmu_ahb_clk", + "mmss_bimc_smmu_axi_clk", "mmss_video_core_clk", + "mmss_video_ahb_clk", "mmss_video_axi_clk", + "mmss_video_core0_clk"; + clocks = <&clock_gcc GCC_MMSS_SYS_NOC_AXI_CLK>, + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_THROTTLE_VIDEO_AXI_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AHB_CLK>, + <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>, + <&clock_mmss MMSS_VIDEO_CORE_CLK>, + <&clock_mmss MMSS_VIDEO_AHB_CLK>, + <&clock_mmss MMSS_VIDEO_AXI_CLK>, + <&clock_mmss MMSS_VIDEO_SUBCORE0_CLK>; + qcom,clock-configs = <0x0 0x0 0x0 0x0 0x0 0x0 + 0x3 0x0 0x2 0x3>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "venus-ddr"; + qcom,bus-range-kbps = <1000 2365000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,mode = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + + qcom,clock-freq-tbl { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,cycles-per-mb = <931>; + qcom,low-power-mode-factor = <33286>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xf3ffffff>; + qcom,cycles-per-mb = <355>; + }; + qcom,profile-hevcdec { + qcom,codec-mask = <0x0c000000>; + qcom,cycles-per-mb = <400>; + }; + }; + + venus-ddr-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "venus-ddr-gov"; + status = "ok"; + qcom,bus-freq-table { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,load-busfreq-tbl = + <979200 1044000>, /* UHD30E */ + <864000 887000>, /* 720p240LPE */ + <489600 666000>, /* 1080p60E */ + <432000 578000>, /* 720p120E */ + <244800 346000>, /* 1080p30E */ + <216000 293000>, /* 720p60E */ + <108000 151000>, /* 720p30E */ + <0 0>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,load-busfreq-tbl = + <979200 2365000>, /* UHD30D */ + <864000 1978000>, /* 720p240D */ + <489600 1133000>, /* 1080p60D */ + <432000 994000>, /* 720p120D */ + <244800 580000>, /* 1080p30D */ + <216000 501000>, /* 720p60E */ + <108000 255000>, /* 720p30D */ + <0 0>; + }; + qcom,profile-dec-ubwc { + qcom,codec-mask = <0xffffffff>; + qcom,ubwc-mode; + qcom,load-busfreq-tbl = + <979200 1892000>, /* UHD30D */ + <864000 1554000>, /* 720p240D */ + <489600 895000>, /* 1080p60D */ + <432000 781000>, /* 720p120D */ + <244800 460000>, /* 1080p30D */ + <216000 301000>, /* 720p60E */ + <108000 202000>, /* 720p30D */ + <0 0>; + }; + qcom,profile-dec-ubwc-10bit { + qcom,codec-mask = <0xffffffff>; + qcom,ubwc-10bit; + qcom,load-busfreq-tbl = + <979200 2446336>, /* UHD30D */ + <864000 2108416>, /* 720p240D */ + <489600 1207296>, /* 1080p60D */ + <432000 1058816>, /* 720p120D */ + <244800 616448>, /* 1080p30D */ + <216000 534528>, /* 720p60D */ + <108000 271360>, /* 720p30D */ + <0 0>; + }; + }; + }; + + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&mmss_bimc_smmu 0x400>, + <&mmss_bimc_smmu 0x401>, + <&mmss_bimc_smmu 0x40a>, + <&mmss_bimc_smmu 0x407>, + <&mmss_bimc_smmu 0x40e>, + <&mmss_bimc_smmu 0x40f>, + <&mmss_bimc_smmu 0x408>, + <&mmss_bimc_smmu 0x409>, + <&mmss_bimc_smmu 0x40b>, + <&mmss_bimc_smmu 0x40c>, + <&mmss_bimc_smmu 0x40d>, + <&mmss_bimc_smmu 0x410>, + <&mmss_bimc_smmu 0x421>, + <&mmss_bimc_smmu 0x428>, + <&mmss_bimc_smmu 0x429>, + <&mmss_bimc_smmu 0x42b>, + <&mmss_bimc_smmu 0x42c>, + <&mmss_bimc_smmu 0x42d>, + <&mmss_bimc_smmu 0x411>, + <&mmss_bimc_smmu 0x431>; + qcom,iommu-dma-addr-pool = <0x79000000 0x60000000>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x79000000 0x60000000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&mmss_bimc_smmu 0x500>, + <&mmss_bimc_smmu 0x502>, + <&mmss_bimc_smmu 0x509>, + <&mmss_bimc_smmu 0x50a>, + <&mmss_bimc_smmu 0x50b>, + <&mmss_bimc_smmu 0x50e>, + <&mmss_bimc_smmu 0x526>, + <&mmss_bimc_smmu 0x529>, + <&mmss_bimc_smmu 0x52b>; + qcom,iommu-dma-addr-pool = <0x51000000 0x28000000>; + buffer-types = <0x241>; + virtual-addr-pool = <0x51000000 0x28000000>; + qcom,secure-context-bank; + }; + + venus_secure_pixel_cb: secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&mmss_bimc_smmu 0x504>, + <&mmss_bimc_smmu 0x50c>, + <&mmss_bimc_smmu 0x510>, + <&mmss_bimc_smmu 0x52c>; + qcom,iommu-dma-addr-pool = <0x29000000 0x28000000>; + buffer-types = <0x106>; + virtual-addr-pool = <0x29000000 0x28000000>; + qcom,secure-context-bank; + }; + + venus_secure_non_pixel_cb: secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&mmss_bimc_smmu 0x505>, + <&mmss_bimc_smmu 0x507>, + <&mmss_bimc_smmu 0x508>, + <&mmss_bimc_smmu 0x50d>, + <&mmss_bimc_smmu 0x50f>, + <&mmss_bimc_smmu 0x525>, + <&mmss_bimc_smmu 0x528>, + <&mmss_bimc_smmu 0x52d>, + <&mmss_bimc_smmu 0x540>; + qcom,iommu-dma-addr-pool = <0x1000000 0x28000000>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x28000000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-wcd.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-wcd.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ce5025bf4ae1604602ce4830c6f7be130d4ee26e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-wcd.dtsi @@ -0,0 +1,185 @@ +&slim_aud { + tasha_codec { + wsa_spkr_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + tasha_hph_en0: msm_cdc_pinctrl_hph_en0 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en0_active>; + pinctrl-1 = <&hph_en0_sleep>; + }; + + tasha_hph_en1: msm_cdc_pinctrl_hph_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en1_active>; + pinctrl-1 = <&hph_en1_sleep>; + }; + }; + + tavil_codec { + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctrl"; + qcom,num-gpios = <5>; + gpio-controller; + #gpio-cells = <2>; + + us_euro_sw_wcd_active: us_euro_sw_wcd_active { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-high; + }; + }; + + us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-low; + }; + }; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + + spkr_2_wcd_en_active: spkr_2_sd_n_active { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + output-high; + }; + }; + + spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + input-enable; + }; + }; + + hph_en0_wcd_active: hph_en0_wcd_active { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-high; + }; + }; + + hph_en0_wcd_sleep: hph_en0_wcd_sleep { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-low; + }; + }; + + hph_en1_wcd_active: hph_en1_wcd_active { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-high; + }; + }; + + hph_en1_wcd_sleep: hph_en1_wcd_sleep { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-low; + }; + }; + }; + + wsa_spkr_wcd_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_wcd_en_active>; + pinctrl-1 = <&spkr_1_wcd_en_sleep>; + }; + + wsa_spkr_wcd_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_wcd_en_active>; + pinctrl-1 = <&spkr_2_wcd_en_sleep>; + }; + + tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&us_euro_sw_wcd_active>; + pinctrl-1 = <&us_euro_sw_wcd_sleep>; + }; + + tavil_hph_en0: msm_cdc_pinctrl_hph_en0 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en0_wcd_active>; + pinctrl-1 = <&hph_en0_wcd_sleep>; + }; + + tavil_hph_en1: msm_cdc_pinctrl_hph_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en1_wcd_active>; + pinctrl-1 = <&hph_en1_wcd_sleep>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660-wsa881x.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660-wsa881x.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..9259ccc4e03bfa8cf526e81f19c75f0ea0d227f2 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660-wsa881x.dtsi @@ -0,0 +1,67 @@ +#include "sdm660-wcd.dtsi" + +&slim_aud { + tasha_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd1>; + }; + + wsa881x_212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd2>; + }; + + wsa881x_213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd1>; + }; + + wsa881x_214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_sd2>; + }; + }; + }; + + tavil_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/sdm660.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdm660.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..4deeb1605318ebb4afd6618b9d037e6d2b1f9333 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdm660.dtsi @@ -0,0 +1,2825 @@ +#include "skeleton64.dtsi" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} +#define DDR_TYPE_LPDDR3 5 +#define DDR_TYPE_LPDDR4X 7 + +/ { + model = "Qualcomm Technologies, Inc. SDM 660"; + compatible = "qcom,sdm660"; + qcom,msm-id = <317 0x0>; + interrupt-parent = <&wakegic>; + + aliases { + serial0 = &uartblsp1dm1; + sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ + sdhc2 = &sdhc_2; /* SDC2 for SD card */ + }; + + chosen { + stdout-path = "serial0"; + bootargs = "rcupdate.rcu_expedited=1"; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + efficiency = <1024>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L2_0: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + /* A53 L2 dump not supported */ + qcom,dump-size = <0x0>; + }; + + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; + efficiency = <1024>; + next-level-cache = <&L2_0>; + L1_I_1: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_1: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_1: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + efficiency = <1024>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L1_I_2: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_2: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_2: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + enable-method = "psci"; + capacity-dmips-mhz = <1024>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + efficiency = <1024>; + next-level-cache = <&L2_0>; + #cooling-cells = <2>; + L1_I_3: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_D_3: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x9040>; + }; + L1_TLB_3: l1-tlb { + qcom,dump-size = <0x2800>; + }; + }; + + CPU4: cpu@100 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x100>; + enable-method = "psci"; + capacity-dmips-mhz = <1638>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + efficiency = <1638>; + next-level-cache = <&L2_1>; + #cooling-cells = <2>; + L2_1: l2-cache { + compatible = "arm,arch-cache"; + cache-level = <2>; + }; + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU5: cpu@101 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x101>; + enable-method = "psci"; + capacity-dmips-mhz = <1638>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + efficiency = <1638>; + next-level-cache = <&L2_1>; + L1_I_101: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_101: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_TLB_101: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU6: cpu@102 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x102>; + enable-method = "psci"; + capacity-dmips-mhz = <1638>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + efficiency = <1638>; + next-level-cache = <&L2_1>; + L1_I_102: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_102: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_TLB_102: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + CPU7: cpu@103 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x103>; + enable-method = "psci"; + capacity-dmips-mhz = <1638>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; + efficiency = <1638>; + next-level-cache = <&L2_1>; + L1_I_103: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_103: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_TLB_103: l1-tlb { + qcom,dump-size = <0x4800>; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + + energy_costs: energy-costs { + compatible = "sched-energy"; + + CPU_COST_0: core-cost0 { + busy-cost-data = < + 633600 41 + 902400 70 + 1113600 83 + 1401600 146 + 1536000 158 + 1747200 228 + 1843200 285 + >; + idle-cost-data = < + 20 16 10 8 + >; + }; + + CPU_COST_1: core-cost1 { + busy-cost-data = < + 1113600 307 + 1401600 485 + 1747200 857 + 1804800 883 + 1958400 1222 + 2150400 1592 + 2208000 1632 + 2457600 2080 + >; + idle-cost-data = < + 100 80 60 40 + >; + }; + + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 633600 4 + 902400 5 + 1113600 7 + 1401600 9 + 1536000 9 + 1747200 11 + 1843200 13 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 1113600 14 + 1401600 17 + 1747200 25 + 1804800 31 + 1958400 31 + 2150400 37 + 2208000 44 + 2457600 45 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + }; + + clocks { + xo_board { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <19200000>; + clock-output-names = "xo_board"; + }; + + sleep_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32764>; + clock-output-names = "sleep_clk"; + }; + }; + + soc: soc { }; + + vendor: vendor { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + }; + + firmware: firmware { + android { + compatible = "android,firmware"; + + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; + }; + + fstab { + compatible = "android,fstab"; + vendor { + compatible = "android,vendor"; + dev = "/dev/block/platform/soc/c0c4000.sdhci/by-name/vendor"; + type = "ext4"; + mnt_flags = "ro,barrier=1,discard"; + fsmgr_flags = "wait,slotselect,avb"; + status = "ok"; + }; + }; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + wlan_msa_guard: wlan_msa_guard@85600000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x85600000 0x0 0x100000>; + }; + + wlan_msa_mem: wlan_msa_mem@85700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x85700000 0x0 0x100000>; + }; + + smem_mem: smem-mem@86000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86000000 0x0 0x200000>; + }; + + removed_regions: removed_regions@85800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x85800000 0x0 0x800000>; + }; + + removed_regions1: removed_regions@86200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x86200000 0x0 0x2d00000>; + }; + + modem_fw_mem: modem_fw_region@8ac00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8ac00000 0x0 0x7e00000>; + }; + + adsp_fw_mem: adsp_fw_region@92a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x92a00000 0x0 0x1e00000>; + }; + + pil_mba_mem: pil_mba_region@94800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x94800000 0x0 0x200000>; + }; + + cdsp_fw_mem: cdsp_fw_region@94a00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x94a00000 0x0 0x600000>; + }; + + venus_fw_mem: venus_fw_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x80000000 0x0 0x20000000>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x800000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x800000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + secure_display_memory: secure_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x5c00000>; + }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x2c00000>; + linux,cma-default; + }; + + cont_splash_mem: splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x23ff000>; + label = "cont_splash_mem"; + }; + + dfps_data_mem: dfps_data_mem@0x9f7ff000 { + reg = <0 0x9f7ff000 0 0x00001000>; + label = "dfps_data_mem"; + }; + }; + + + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-core-supply = <&pm660_l9>; + qca,bt-vdd-pa-supply = <&pm660_l6>; + qca,bt-vdd-ldo-supply = <&pm660_l19>; + qca,bt-chip-pwd-supply = <&pm660l_bob_pin1>; + clocks = <&clock_rpmcc RPM_SMD_RF_CLK1_PIN>; + clock-names = "rf_clk1"; + + qca,bt-vdd-core-voltage-level = <1800000 1900000>; + qca,bt-vdd-pa-voltage-level = <1304000 1370000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3400000>; + qca,bt-chip-pwd-voltage-level = <3600000 3600000>; + + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */ + }; +}; + +#include "sdm660-coresight.dtsi" +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; + + intc: interrupt-controller@17a00000 { + compatible = "arm,gic-v3"; + reg = <0x17a00000 0x10000>, /* GICD */ + <0x17b00000 0x100000>; /* GICR * 8 */ + #interrupt-cells = <3>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + interrupt-controller; + interrupt-parent = <&intc>; + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x20000>; + interrupts = <1 9 4>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + dma_blsp1: qcom,sps-dma@0xc144000{ /* BLSP1 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0xc144000 0x1F000>; + interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>; + qcom,summing-threshold = <0x10>; + }; + + dma_blsp2: qcom,sps-dma@0xc184000{ /* BLSP2 */ + #dma-cells = <4>; + compatible = "qcom,sps-dma"; + reg = <0xc184000 0x1F000>; + interrupts = <0 239 IRQ_TYPE_LEVEL_HIGH>; + qcom,summing-threshold = <0x10>; + }; + + restart@10ac000 { + compatible = "qcom,pshold"; + reg = <0x10ac000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + spmi_bus: qcom,spmi@800f000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0x800f000 0x1000>, + <0x8400000 0x1000000>, + <0x9400000 0x1000000>, + <0xa400000 0x220000>, + <0x800a000 0x3000>; + reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; + interrupt-names = "periph_irq"; + interrupts = ; + qcom,ee = <0>; + qcom,channel = <0>; + qcom,reserved-chan = <511>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + status = "ok"; + }; + + cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,l1_i_cache0 { + qcom,dump-node = <&L1_I_0>; + qcom,dump-id = <0x60>; + }; + qcom,l1_i_cache1 { + qcom,dump-node = <&L1_I_1>; + qcom,dump-id = <0x61>; + }; + qcom,l1_i_cache2 { + qcom,dump-node = <&L1_I_2>; + qcom,dump-id = <0x62>; + }; + qcom,l1_i_cache3 { + qcom,dump-node = <&L1_I_3>; + qcom,dump-id = <0x63>; + }; + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x64>; + }; + qcom,l1_i_cache101 { + qcom,dump-node = <&L1_I_101>; + qcom,dump-id = <0x65>; + }; + qcom,l1_i_cache102 { + qcom,dump-node = <&L1_I_102>; + qcom,dump-id = <0x66>; + }; + qcom,l1_i_cache103 { + qcom,dump-node = <&L1_I_103>; + qcom,dump-id = <0x67>; + }; + qcom,l1_d_cache0 { + qcom,dump-node = <&L1_D_0>; + qcom,dump-id = <0x80>; + }; + qcom,l1_d_cache1 { + qcom,dump-node = <&L1_D_1>; + qcom,dump-id = <0x81>; + }; + qcom,l1_d_cache2 { + qcom,dump-node = <&L1_D_2>; + qcom,dump-id = <0x82>; + }; + qcom,l1_d_cache3 { + qcom,dump-node = <&L1_D_3>; + qcom,dump-id = <0x83>; + }; + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x84>; + }; + qcom,l1_d_cache101 { + qcom,dump-node = <&L1_D_101>; + qcom,dump-id = <0x85>; + }; + qcom,l1_d_cache102 { + qcom,dump-node = <&L1_D_102>; + qcom,dump-id = <0x86>; + }; + qcom,l1_d_cache103 { + qcom,dump-node = <&L1_D_103>; + qcom,dump-id = <0x87>; + }; + qcom,l1_tlb_dump0 { + qcom,dump-node = <&L1_TLB_0>; + qcom,dump-id = <0x20>; + }; + qcom,l1_tlb_dump1 { + qcom,dump-node = <&L1_TLB_1>; + qcom,dump-id = <0x21>; + }; + qcom,l1_tlb_dump2 { + qcom,dump-node = <&L1_TLB_2>; + qcom,dump-id = <0x22>; + }; + qcom,l1_tlb_dump3 { + qcom,dump-node = <&L1_TLB_3>; + qcom,dump-id = <0x23>; + }; + qcom,l1_tlb_dump100 { + qcom,dump-node = <&L1_TLB_100>; + qcom,dump-id = <0x24>; + }; + qcom,l1_tlb_dump101 { + qcom,dump-node = <&L1_TLB_101>; + qcom,dump-id = <0x25>; + }; + qcom,l1_tlb_dump102 { + qcom,dump-node = <&L1_TLB_102>; + qcom,dump-id = <0x26>; + }; + qcom,l1_tlb_dump103 { + qcom,dump-node = <&L1_TLB_103>; + qcom,dump-id = <0x27>; + }; + }; + + wdog: qcom,wdt@17817000 { + compatible = "qcom,msm-watchdog"; + reg = <0x17817000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 3 IRQ_TYPE_EDGE_RISING>, + <0 4 IRQ_TYPE_LEVEL_HIGH>; + qcom,bark-time = <11000>; + qcom,pet-time = <10000>; + qcom,ipi-ping; + qcom,wakeup-enable; + qcom,scandump-sizes = <0x40000>; + }; + + qcom,sps { + compatible = "qcom,msm-sps-4k"; + qcom,pipe-attr-ee; + }; + + wakegic: wake-gic { + compatible = "qcom,mpm-gic-sdm660", "qcom,mpm-gic"; + interrupts-extended = <&wakegic GIC_SPI 171 + IRQ_TYPE_EDGE_RISING>; + reg = <0x7781b8 0x1000>, /* MSM_RPM_MPM_BASE 4K */ + <0x17911008 0x4>; /* MSM_APCS_GCC_BASE 4K */ + reg-names = "vmpm", "ipc"; + qcom,num-mpm-irqs = <96>; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <3>; + }; + + wakegpio: wake-gpio { + compatible = "qcom,mpm-gpio"; + interrupt-controller; + interrupt-parent = <&intc>; + #interrupt-cells = <2>; + }; + + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x200000>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x300000>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <1>; + qcom,allocate-on-request; + label = "modem"; + }; + }; + + tsens: tsens@10ad000 { + compatible = "qcom,sdm660-tsens"; + reg = <0x10ad000 0x8>, + <0x10ae000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>, + <0 430 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + qcom,client-id = <0 1 2 3 4 5 6 7 8 9 10 11 12 13>; + qcom,sensor-id = <0 10 11 4 5 6 7 8 13 2 3 12 9 1>; + qcom,sensors = <14>; + qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 + 3200 3200 3200 3200 3200 3200>; + }; + + thermal_zones: thermal-zones { }; + + uartblsp1dm1: serial@0c170000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xc170000 0x1000>; + interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + clocks = <&clock_gcc GCC_BLSP1_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + }; + + qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clocks = <&clock_gcc GCC_BLSP1_QUP3_SPI_APPS_CLK>, + <&clock_gcc GCC_BLSP1_AHB_CLK>; + clock-frequency = <15000000>; + qcom,ipc-gpio = <&tlmm 72 0>; + qcom,finger-detect-gpio = <&pm660_gpios 11 0>; + }; + + cx_ipeak_lm: cx_ipeak@1fe5040 { + compatible = "qcom,cx-ipeak-v1"; + reg = <0x1fe5040 0x28>; + }; + + uartblsp2dm1: serial@0c1b0000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0xc1b0000 0x1000>; + interrupts = <0 114 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + clocks = <&clock_gcc GCC_BLSP2_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + }; + + slim_aud: slim@151c0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x151c0000 0x2c000>, + <0x15184000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>, + <0 164 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x7e0000>; + qcom,ea-pc = <0x260>; + qcom,arm-smmu; + iommus = <&anoc2_smmu 0x188b 0x0>, + <&anoc2_smmu 0x188c 0x0>, + <&anoc2_smmu 0x1892 0x0>, + <&anoc2_smmu 0x1893 0x0>, + <&anoc2_smmu 0x1894 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xC0000000>; + qcom,use-64-bit-dma-mask; + qcom,iommu-dma = "bypass"; + qcom,iommu-s1-bypass; + status = "disabled"; + }; + + slim_qca: slim@15240000 { + cell-index = <3>; + compatible = "qcom,slim-ngd"; + reg = <0x15240000 0x2c000>, + <0x15204000 0x20000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 291 IRQ_TYPE_LEVEL_HIGH>, + <0 292 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x1800>; + + /* Slimbus Slave DT for WCN3990 */ + btfmslim_codec: wcn3990 { + compatible = "qcom,btfmslim_slave"; + elemental-addr = [00 01 20 02 17 02]; + qcom,btfm-slim-ifd = "btfmslim_slave_ifd"; + qcom,btfm-slim-ifd-elemental-addr = [00 00 20 02 17 02]; + }; + }; + + timer@17920000 { + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17920000 0x1000>; + clock-frequency = <19200000>; + + frame@17921000 { + frame-number = <0>; + interrupts = <0 8 0x4>, + <0 7 0x4>; + reg = <0x17921000 0x1000>, + <0x17922000 0x1000>; + }; + + frame@17923000 { + frame-number = <1>; + interrupts = <0 9 0x4>; + reg = <0x17923000 0x1000>; + status = "disabled"; + }; + + frame@17924000 { + frame-number = <2>; + interrupts = <0 10 0x4>; + reg = <0x17924000 0x1000>; + status = "disabled"; + }; + + frame@17925000 { + frame-number = <3>; + interrupts = <0 11 0x4>; + reg = <0x17925000 0x1000>; + status = "disabled"; + }; + + frame@17926000 { + frame-number = <4>; + interrupts = <0 12 0x4>; + reg = <0x17926000 0x1000>; + status = "disabled"; + }; + + frame@17927000 { + frame-number = <5>; + interrupts = <0 13 0x4>; + reg = <0x17927000 0x1000>; + status = "disabled"; + }; + + frame@17928000 { + frame-number = <6>; + interrupts = <0 14 0x4>; + reg = <0x17928000 0x1000>; + status = "disabled"; + }; + }; + + arm64-cpu-erp { + compatible = "arm,arm64-cpu-erp"; + interrupts = <0 43 4>, + <0 44 4>, + <0 41 4>, + <0 42 4>; + + interrupt-names = "pri-dbe-irq", + "sec-dbe-irq", + "pri-ext-irq", + "sec-ext-irq"; + + poll-delay-ms = <5000>; + }; + + clock_rpmcc: qcom,rpmcc { + compatible = "qcom,rpmcc-sdm660", "qcom,rpmcc"; + #clock-cells = <1>; + }; + + clock_gcc: clock-controller@100000 { + compatible = "qcom,gcc-sdm660", "syscon"; + reg = <0x100000 0x94000>; + vdd_dig-supply = <&pm660l_s3_level>; + vdd_dig_ao-supply = <&pm660l_s3_level_ao>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_mmss: clock-controller@c8c0000 { + compatible = "qcom,mmcc-sdm660", "syscon"; + reg = <0xc8c0000 0x40000>; + vdd_mx_mmss-supply = <&pm660l_s5_level>; + vdd_dig_mmss-supply = <&pm660l_s3_level>; + vdda-supply = <&pm660_l10>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gpu: clock-controller@5065000 { + compatible = "qcom,gpu-sdm660", "syscon"; + reg = <0x5065000 0x10000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gfx: gfx@5065000 { + compatible = "qcom,gpucc-sdm660", "syscon"; + reg = <0x5065000 0x10000>; + vdd_dig_gfx-supply = <&pm660l_s3_level>; + vdd_mx_gfx-supply = <&pm660l_s5_level>; + vdd_gfx-supply = <&gfx_vreg_corner>; + qcom,gpucc_gfx3d_clk-opp-handle = <&msm_gpu>; + qcom,gfxfreq-corner = + < 0 0>, + < 160000000 1>, /* MinSVS */ + < 266000000 2>, /* LowSVS */ + < 370000000 3>, /* SVS */ + < 465000000 4>, /* SVS_L1 */ + < 588000000 5>, /* NOM */ + < 647000000 6>, /* NOM_L1 */ + < 700000000 7>, /* TURBO */ + < 750000000 7>; /* TURBO */ + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cpu_debug: syscon@1791101c { + compatible = "syscon"; + reg = <0x1791101c 0x4>; + }; + + gpu_debug: syscon@05065120 { + compatible = "syscon"; + reg = <0x05065120 0x4>; + }; + + mmss_debug: syscon@c8c0900 { + compatible = "syscon"; + reg = <0xc8c0900 0x4>; + }; + + clock_debug: qcom,cc-debug@62000 { + compatible = "qcom,sdm660-debugcc"; + qcom,gcc = <&clock_gcc>; + qcom,cpu = <&cpu_debug>; + qcom,mmss = <&clock_mmss>; + qcom,gpu = <&clock_gfx>; + clock-names = "xo_clk_src"; + clocks = <&clock_rpmcc RPM_SMD_XO_CLK_SRC>; + #clock-cells = <1>; + }; + + generic_bw_opp_table: generic-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 100, 4); /* 381 MB/s */ + BW_OPP_ENTRY( 150, 4); /* 572 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 412, 4); /* 1571 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1296, 4); /* 4943 MB/s */ + BW_OPP_ENTRY(1353, 4); /* 5163 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + + cpu_cpu_ddr_bw: qcom,cpu-cpu-ddr-bw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&generic_bw_opp_table>; + }; + + cpu_cpu_ddr_bwmon: qcom,cpu-cpu-ddr-bwmon@01008000 { + compatible = "qcom,bimc-bwmon4"; + reg = <0x01008000 0x300>, <0x01001000 0x200>; + reg-names = "base", "global_base"; + interrupts = ; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpu_cpu_ddr_bw>; + qcom,count-unit = <0x10000>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&generic_bw_opp_table>; + }; + + cpu4_cpu_ddr_latfloor: qcom,cpu4-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&generic_bw_opp_table>; + }; + + cpu0_cpu_ddr_lat: qcom,cpu0-cpu-ddr-lat { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&generic_bw_opp_table>; + }; + + cpu4_cpu_ddr_lat: qcom,cpu4-cpu-ddr-lat { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = + ; + qcom,active-only; + operating-points-v2 = <&generic_bw_opp_table>; + }; + + cpu0_memlat_cpugrp: qcom,cpu0-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + + cpu0_cpu_ddr_latmon: qcom,cpu0-cpu-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_lat>; + qcom,core-dev-table = + < 902400 MHZ_TO_MBPS(200, 4) >, + < 1401600 MHZ_TO_MBPS(547, 4) >, + < 1881600 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 633600 MHZ_TO_MBPS(200, 4) >, + < 1401600 MHZ_TO_MBPS(412, 4) >, + < 1881600 MHZ_TO_MBPS(768, 4) >; + }; + }; + + cpu4_memlat_cpugrp: qcom,cpu4-cpugrp { + compatible = "qcom,arm-memlat-cpugrp"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + + cpu4_cpu_ddr_latmon: qcom,cpu4-cpu-ddr-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_cpu_ddr_lat>; + qcom,core-dev-table = + < 1113600 MHZ_TO_MBPS(200, 4) >, + < 1401600 MHZ_TO_MBPS(1017, 4) >, + < 2150400 MHZ_TO_MBPS(1555, 4) >, + < 2457600 MHZ_TO_MBPS(1804, 4) >; + }; + + cpu4_computemon: qcom,cpu4-computemon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1113600 MHZ_TO_MBPS(200, 4) >, + < 1401600 MHZ_TO_MBPS(547, 4) >, + < 1747200 MHZ_TO_MBPS(768, 4) >, + < 2150400 MHZ_TO_MBPS(1017, 4) >, + < 2457600 MHZ_TO_MBPS(1804, 4) >; + }; + }; + + + clock_cpu: qcom,clk-cpu-660@179c0000 { + compatible = "qcom,clk-cpu-osm"; + reg = <0x179c0000 0x4000>, <0x17916000 0x1000>, + <0x17816000 0x1000>, <0x179d1000 0x1000>, + <0x00784130 0x8>, <0x00784130 0x8>; + reg-names = "osm", "pwrcl_pll", "perfcl_pll", + "apcs_common", "pwrcl_efuse", + "perfcl_efuse"; + + vdd-pwrcl-supply = <&apc0_pwrcl_vreg>; + vdd-perfcl-supply = <&apc1_perfcl_vreg>; + + interrupts = , + ; + interrupt-names = "pwrcl-irq", "perfcl-irq"; + + qcom,pwrcl-speedbin0-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1747200000 0x0404005b 0x09480048 0x2 7 >, + < 1843200000 0x04040060 0x094c004c 0x3 8 >; + + qcom,pwrcl-speedbin1-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1747200000 0x0404005b 0x09480048 0x2 7 >, + < 1843200000 0x04040060 0x094c004c 0x3 8 >; + + qcom,pwrcl-speedbin3-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1612800000 0x04040054 0x09430043 0x2 7 >; + + qcom,pwrcl-speedbin4-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 633600000 0x05040021 0x03200020 0x1 2 >, + < 902400000 0x0404002f 0x04260026 0x1 3 >, + < 1113600000 0x0404003a 0x052e002e 0x2 4 >, + < 1401600000 0x04040049 0x073a003a 0x2 5 >, + < 1536000000 0x04040050 0x08400040 0x2 6 >, + < 1747200000 0x0404005b 0x09480048 0x2 7 >, + < 1843200000 0x04040060 0x094c004c 0x3 8 >; + + qcom,perfcl-speedbin0-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1958400000 0x04040066 0x0a510051 0x2 5 >, + < 2150400000 0x04040070 0x0b590059 0x2 6 >, + < 2457600000 0x04040080 0x0c660066 0x3 7 >; + + qcom,perfcl-speedbin1-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1958400000 0x04040066 0x0a510051 0x2 5 >, + < 2150400000 0x04040070 0x0b590059 0x2 6 >, + < 2208000000 0x04040073 0x0b5c005c 0x3 7 >; + + qcom,perfcl-speedbin3-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1804800000 0x0404005e 0x094b004b 0x2 5 >; + + qcom,perfcl-speedbin4-v0 = + < 300000000 0x0004000f 0x01200020 0x1 1 >, + < 1113600000 0x0404003a 0x052e002e 0x1 2 >, + < 1401600000 0x04040049 0x073a003a 0x2 3 >, + < 1747200000 0x0404005b 0x09480048 0x2 4 >, + < 1958400000 0x04040066 0x0a510051 0x2 5 >; + + qcom,up-timer = <1000 1000>; + qcom,down-timer = <1000 1000>; + qcom,set-ret-inactive; + qcom,enable-llm-freq-vote; + qcom,llm-freq-up-timer = <327675 327675>; + qcom,llm-freq-down-timer = <327675 327675>; + qcom,enable-llm-volt-vote; + qcom,llm-volt-up-timer = <327675 327675>; + qcom,llm-volt-down-timer = <327675 327675>; + qcom,cc-reads = <10>; + qcom,cc-delay = <5>; + qcom,cc-factor = <100>; + qcom,osm-clk-rate = <200000000>; + qcom,xo-clk-rate = <19200000>; + + qcom,l-val-base = <0x17916004 0x17816004>; + qcom,apcs-itm-present = <0x179d143c 0x179d143c>; + qcom,apcs-pll-user-ctl = <0x1791600c 0x1781600c>; + qcom,apcs-cfg-rcgr = <0x17911054 0x17811054>; + qcom,apcs-cmd-rcgr = <0x17911050 0x17811050>; + qcom,apm-mode-ctl = <0x179d0004 0x179d0010>; + qcom,apm-ctrl-status = <0x179d000c 0x179d0018>; + + qcom,apm-threshold-voltage = <872000>; + qcom,boost-fsm-en; + qcom,safe-fsm-en; + qcom,ps-fsm-en; + qcom,droop-fsm-en; + qcom,wfx-fsm-en; + qcom,pc-fsm-en; + + clock-names = "aux_clk", "xo_a"; + clocks = <&clock_gcc HMSS_GPLL0_CLK_SRC>, + <&clock_rpmcc RPM_SMD_XO_A_CLK_SRC>; + + #clock-cells = <1>; + }; + + msm_cpufreq: qcom,msm-cpufreq { + compatible = "qcom,msm-cpufreq"; + clock-names = "cpu0_clk", "cpu4_clk"; + clocks = <&clock_cpu PWRCL_CLK>, + <&clock_cpu PERFCL_CLK>; + + qcom,governor-per-policy; + + qcom,cpufreq-table-0 = + < 633600 >, + < 902400 >, + < 1113600 >, + < 1401600 >, + < 1536000 >, + < 1612800 >, + < 1747200 >, + < 1843200 >; + + qcom,cpufreq-table-4 = + < 1113600 >, + < 1401600 >, + < 1747200 >, + < 1804800 >, + < 1958400 >, + < 2150400 >, + < 2208000 >, + < 2457600 >; + }; + + sdhc_1: sdhci@c0c4000 { + compatible = "qcom,sdhci-msm-v5", "qcom,sdhci-msm-cqe"; + reg = <0xc0c4000 0x1000>, <0xc0c5000 0x1000>, + <0xc0c8000 0x8000>; + reg-names = "hc_mem", "cqhci_mem", "cqhci_ice"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <8>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 + 384000000>; + + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + qcom,devfreq,freq-table = <50000000 200000000>; + + qcom,msm-bus,name = "sdhc1"; + qcom,msm-bus,num-cases = <9>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <78 512 0 0>, <1 606 0 0>, + /* 400 KB/s*/ + <78 512 1046 1600>, + <1 606 1600 1600>, + /* 20 MB/s */ + <78 512 52286 80000>, + <1 606 80000 80000>, + /* 25 MB/s */ + <78 512 65360 100000>, + <1 606 100000 100000>, + /* 50 MB/s */ + <78 512 130718 200000>, + <1 606 133320 133320>, + /* 100 MB/s */ + <78 512 130718 200000>, + <1 606 150000 150000>, + /* 200 MB/s */ + <78 512 261438 400000>, + <1 606 300000 300000>, + /* 400 MB/s */ + <78 512 261438 400000>, + <1 606 300000 300000>, + /* Max. bandwidth */ + <78 512 1338562 4096000>, + <1 606 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 400000000 4294967295>; + + clocks = <&clock_gcc GCC_SDCC1_AHB_CLK>, + <&clock_gcc GCC_SDCC1_APPS_CLK>, + <&clock_gcc GCC_SDCC1_ICE_CORE_CLK>; + clock-names = "iface_clk", "core_clk", "ice_core_clk"; + qcom,ice-clk-rates = <300000000 75000000>; + + status = "disabled"; + }; + + sdhc_2: sdhci@c084000 { + compatible = "qcom,sdhci-msm-v5"; + reg = <0xc084000 0x1000>; + reg-names = "hc_mem"; + + interrupts = , + ; + interrupt-names = "hc_irq", "pwr_irq"; + + qcom,bus-width = <4>; + qcom,large-address-bus; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + qcom,msm-bus,name = "sdhc2"; + qcom,msm-bus,num-cases = <8>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <81 512 0 0>, <1 608 0 0>, + /* 400 KB/s*/ + <81 512 1046 1600>, + <1 608 1600 1600>, + /* 20 MB/s */ + <81 512 52286 80000>, + <1 608 80000 80000>, + /* 25 MB/s */ + <81 512 65360 100000>, + <1 608 100000 100000>, + /* 50 MB/s */ + <81 512 130718 200000>, + <1 608 133320 133320>, + /* 100 MB/s */ + <81 512 261438 200000>, + <1 608 150000 150000>, + /* 200 MB/s */ + <81 512 261438 400000>, + <1 608 300000 300000>, + /* Max. bandwidth */ + <81 512 1338562 4096000>, + <1 608 1338562 4096000>; + qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000 + 100000000 200000000 4294967295>; + + qcom,devfreq,freq-table = <50000000 200000000>; + clocks = <&clock_gcc GCC_SDCC2_AHB_CLK>, + <&clock_gcc GCC_SDCC2_APPS_CLK>; + clock-names = "iface_clk", "core_clk"; + + status = "disabled"; + }; + + ipa_hw: qcom,ipa@14780000 { + compatible = "qcom,ipa"; + reg = <0x14780000 0x4effc>, <0x14784000 0x26934>; + reg-names = "ipa-base", "bam-base"; + interrupts = <0 333 IRQ_TYPE_LEVEL_HIGH>, + <0 432 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ipa-irq", "bam-irq"; + qcom,ipa-hw-ver = <6>; /* IPA core version = IPAv2.6L */ + qcom,ipa-hw-mode = <0>; /* IPA hw type = Normal */ + qcom,wan-rx-ring-size = <192>; /* IPA WAN-rx-ring-size*/ + qcom,lan-rx-ring-size = <192>; /* IPA LAN-rx-ring-size*/ + clocks = <&clock_rpmcc RPM_SMD_IPA_CLK>, + <&clock_rpmcc AGGR2_NOC_SMMU_CLK>; + clock-names = "core_clk", "smmu_clk"; + qcom,arm-smmu; + qcom,smmu-disable-htw; + qcom,smmu-s1-bypass; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,use-dma-zone; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <90 512 0 0>, + <1 676 0 0>, + /* SVS */ + <90 512 80000 640000>, + <1 676 80000 80000>, + /* NOMINAL */ + <90 512 206000 960000>, + <1 676 206000 160000>, + /* TURBO */ + <90 512 206000 960000>, + <1 676 206000 160000>; + qcom,bus-vector-names = "MIN", "SVS", "PERF", "TURBO"; + qcom,rx-polling-sleep-ms = <1>; /* Polling sleep interval */ + qcom,ipa-polling-iteration = <40>; /* Polling Iteration */ + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&anoc2_smmu 0x19C0>; + qcom,iova-mapping = <0x10000000 0x40000000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + status = "disabled"; + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&anoc2_smmu 0x19C1>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&anoc2_smmu 0x19C2>; + qcom,iova-mapping = <0x40000000 0x20000000>; + }; + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa"; + qcom,rmnet-ipa-ssr; + qcom,ipa-platform-type-msm; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + qcom,ipc-spinlock@1f40000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1f40000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,msm-cdsp-loader { + compatible = "qcom,cdsp-loader"; + qcom,proc-img-to-load = "cdsp"; + }; + + qcom,msm-adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,adsp-remoteheap-vmid = <33>; + qcom,rpc-latency-us = <611>; + qcom,fastrpc-adsp-audio-pdr; + qcom,fastrpc-adsp-sensors-pdr; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&lpass_q6_smmu 3>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&lpass_q6_smmu 7>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&lpass_q6_smmu 8>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&lpass_q6_smmu 9>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 3>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 4>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 5>; + dma-coherent; + }; + + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 6>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 7>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 8>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 9>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 10>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb13 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&turing_q6_smmu 11>; + dma-coherent; + }; + }; + + + dcc: dcc@10b3000 { + compatible = "qcom,dcc"; + reg = <0x10b3000 0x1000>, + <0x10b4000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + + clocks = <&clock_gcc GCC_DCC_AHB_CLK>; + clock-names = "dcc_clk"; + }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + }; + + smem { + compatible = "qcom,smem"; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; + }; + + apcs_glb: mailbox@17911000 { + compatible = "qcom,sdm660-apcs-hmss-global"; + reg = <0x17911000 0x1000>; + #mbox-cells = <1>; + }; + + rpm-glink { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + + qcom,rpm_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; + + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apcs_glb 15>; + mbox-names = "mpss_smem"; + interrupts = ; + + label = "modem"; + qcom,glink-label = "mpss"; + + qcom,modem_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,low-latency; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,modem_ds { + qcom,glink-channels = "DS"; + qcom,intents = <0x4000 0x2>; + }; + + qcom,modem_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_adsp>, + <&glink_cdsp>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apcs_glb 9>; + mbox-names = "adsp_smem"; + interrupts = ; + + label = "adsp"; + qcom,glink-label = "lpass"; + cpu-affinity = <1 2>; + + qcom,adsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,apr_tal_rpmsg { + qcom,glink-channels = "apr_audio_svc"; + qcom,intents = <0x200 20>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,adsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_cdsp>; + }; + }; + + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apcs_glb 29>; + mbox-names = "cdsp_smem"; + interrupts = ; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + + qcom,msm_fastrpc_rpmsg { + compatible = "qcom,msm-fastrpc-rpmsg"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + qcom,intents = <0x64 64>; + }; + + qcom,msm_cdsprm_rpmsg { + compatible = "qcom,msm-cdsprm-rpmsg"; + qcom,glink-channels = "cdsprmglink-apps-dsp"; + qcom,intents = <0x20 12>; + + msm_cdsp_rm: qcom,msm_cdsp_rm { + compatible = "qcom,msm-cdsp-rm"; + qcom,qos-latency-us = <44>; + qcom,qos-maxhold-ms = <20>; + #cooling-cells = <2>; + }; + + msm_hvx_rm: qcom,msm_hvx_rm { + compatible = "qcom,msm-hvx-rm"; + #cooling-cells = <2>; + }; + }; + + qcom,cdsp_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>; + }; + }; + + glink_spi_xprt_wdsp: wdsp { + transport = "spi"; + tx-descriptors = <0x12000 0x12004>; + rx-descriptors = <0x1200c 0x12010>; + + label = "wdsp"; + qcom,glink-label = "wdsp"; + + qcom,wdsp_ctrl { + qcom,glink-channels = "g_glink_ctrl"; + qcom,intents = <0x400 1>; + }; + + qcom,wdsp_ild { + qcom,glink-channels = + "g_glink_persistent_data_ild"; + }; + + qcom,wdsp_nild { + qcom,glink-channels = + "g_glink_persistent_data_nild"; + }; + + qcom,wdsp_data { + qcom,glink-channels = "g_glink_audio_data"; + qcom,intents = <0x1000 2>; + }; + + qcom,diag_data { + qcom,glink-channels = "DIAG_DATA"; + qcom,intents = <0x4000 2>; + }; + + qcom,diag_ctrl { + qcom,glink-channels = "DIAG_CTRL"; + qcom,intents = <0x4000 1>; + }; + + qcom,diag_cmd { + qcom,glink-channels = "DIAG_CMD"; + qcom,intents = <0x4000 1 >; + }; + }; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-loopback_cntl { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl"; + }; + + qcom,glinkpkt-loopback_data { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,smp2p_sleepstate { + compatible = "qcom,smp2p-sleepstate"; + qcom,smem-states = <&sleepstate_smp2p_out 0>; + interrupt-parent = <&sleepstate_smp2p_in>; + interrupts = <0 0>; + interrupt-names = "smp2p-sleepstate-in"; + }; + + qcom,smp2p-modem { + compatible = "qcom,smp2p"; + qcom,smem = <435>, <428>; + interrupts = ; + mboxes = <&apcs_glb 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + modem_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + modem_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_ipa_1_out: qcom,smp2p-ipa-1-out { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + /* ipa - inbound entry from mss */ + smp2p_ipa_1_in: qcom,smp2p-ipa-1-in { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_wlan_1_in: qcom,smp2p-wlan-1-in { + qcom,entry-name = "wlan"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-adsp { + compatible = "qcom,smp2p"; + qcom,smem = <443>, <429>; + interrupts = ; + mboxes = <&apcs_glb 10>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + mboxes = <&apcs_glb 30>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + cdsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_rdbg5_out: qcom,smp2p-rdbg5-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_in: qcom,smp2p-rdbg5-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + rpm_bus: qcom,rpm-smd { + compatible = "qcom,rpm-smd"; + rpm-channel-name = "rpm_requests"; + interrupts = ; + rpm-channel-type = <15>; /* SMD_APPS_RPM */ + }; + + qcom,venus@cce0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xcce0000 0x4000>; + + vdd-supply = <&gdsc_venus>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&clock_mmss MMSS_VIDEO_CORE_CLK>, + <&clock_mmss MMSS_MNOC_AHB_CLK>, + <&clock_mmss MMSS_VIDEO_AHB_CLK>, + <&clock_rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, + <&clock_mmss MMSS_VIDEO_AXI_CLK>; + clock-names = "core_clk", "mnoc_ahb_clk", "iface_clk", + "noc_axi_clk", "bus_clk"; + qcom,proxy-clock-names = "core_clk", "mnoc_ahb_clk", + "iface_clk", "noc_axi_clk", "bus_clk"; + + qcom,msm-bus,name = "pil-venus"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <63 512 0 0>, + <63 512 0 304000>; + + qcom,pas-id = <9>; + qcom,mas-crypto = <&mas_crypto_c0>; + qcom,proxy-timeout-ms = <100>; + qcom,firmware-name = "venus"; + memory-region = <&venus_fw_mem>; + status = "ok"; + }; + + qcom,icnss@18800000 { + compatible = "qcom,icnss"; + reg = <0x18800000 0x800000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_ipa"; + iommus = <&anoc2_smmu 0x1a00>, + <&anoc2_smmu 0x1a01>; + clocks = <&clock_rpmcc RPM_SMD_RF_CLK1_PIN>; + clock-names = "cxo_ref_clk_pin"; + interrupts = <0 413 IRQ_TYPE_LEVEL_HIGH>, /* CE0 */ + <0 414 IRQ_TYPE_LEVEL_HIGH>, /* CE1 */ + <0 415 IRQ_TYPE_LEVEL_HIGH>, /* CE2 */ + <0 416 IRQ_TYPE_LEVEL_HIGH>, /* CE3 */ + <0 417 IRQ_TYPE_LEVEL_HIGH>, /* CE4 */ + <0 418 IRQ_TYPE_LEVEL_HIGH>, /* CE5 */ + <0 420 IRQ_TYPE_LEVEL_HIGH>, /* CE6 */ + <0 421 IRQ_TYPE_LEVEL_HIGH>, /* CE7 */ + <0 422 IRQ_TYPE_LEVEL_HIGH>, /* CE8 */ + <0 423 IRQ_TYPE_LEVEL_HIGH>, /* CE9 */ + <0 424 IRQ_TYPE_LEVEL_HIGH>, /* CE10 */ + <0 425 IRQ_TYPE_LEVEL_HIGH>; /* CE11 */ + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; + qcom,iommu-dma = "bypass"; + qcom,iommu-faults = "stall-disable"; + qcom,hyp_enabled; + vdd-cx-mx-supply = <&pm660_l5>; + vdd-1.8-xo-supply = <&pm660_l9_pin_ctrl>; + vdd-1.3-rfa-supply = <&pm660_l6_pin_ctrl>; + vdd-3.3-ch0-supply = <&pm660_l19_pin_ctrl>; + qcom,vdd-cx-mx-config = <848000 848000>; + qcom,vdd-1.8-xo-config = <1750000 1900000>; + qcom,vdd-1.3-rfa-config = <1200000 1370000>; + qcom,vdd-3.3-ch0-config = <3200000 3400000>; + qcom,wlan-msa-memory = <0x100000>; + qcom,wlan-msa-fixed-region = <&wlan_msa_mem>; + qcom,smp2p_map_wlan_1_in { + interrupts-extended = <&smp2p_wlan_1_in 0 0>, + <&smp2p_wlan_1_in 1 0>; + interrupt-names = "qcom,smp2p-force-fatal-error", + "qcom,smp2p-early-crash-ind"; + }; + }; + + qcom,lpass@15700000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x15700000 0x00100>; + reg-names = "base_reg"; + + vdd_cx-supply = <&pm660l_l9_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&clock_rpmcc CXO_SMD_PIL_LPASS_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <1>; + qcom,mas-crypto = <&mas_crypto_c0>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + memory-region = <&adsp_fw_mem>; + + /* GPIO inputs from lpass */ + interrupts-extended = <&wakegic 0 162 1>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* GPIO output to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + status = "ok"; + }; + + qcom,turing@1a300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x1a300000 0x00100>; + reg-names = "base_reg"; + + vdd_cx-supply = <&pm660l_s3_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&clock_rpmcc CXO_SMD_PIL_CDSP_CLK>; + clock-names = "xo"; + qcom,proxy-clock-names = "xo"; + + qcom,pas-id = <18>; + qcom,mas-crypto = <&mas_crypto_c0>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <601>; + qcom,sysmon-id = <7>; + qcom,ssctl-instance-id = <0x17>; + qcom,firmware-name = "cdsp"; + memory-region = <&cdsp_fw_mem>; + + /* Inputs from turing */ + interrupts-extended = <&wakegic 0 518 1>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + + /* Outputs to turing */ + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + status = "ok"; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-q6v55-mss"; + reg = <0x4080000 0x100>, + <0x1f63000 0x008>, + <0x1f65000 0x008>, + <0x1f64000 0x008>, + <0x4180000 0x040>, + <0x00179000 0x004>, + <0x01fe5048 0x004>; + reg-names = "qdsp6_base", "halt_q6", "halt_modem", + "halt_nc", "rmb_base", "restart_reg", + "cxip_lm_vote_clear"; + + clocks = <&clock_rpmcc RPM_SMD_XO_CLK_SRC>, + <&clock_gcc GCC_MSS_CFG_AHB_CLK>, + <&clock_gcc GCC_BIMC_MSS_Q6_AXI_CLK>, + <&clock_gcc GCC_BOOT_ROM_AHB_CLK>, + <&clock_gcc GPLL0_OUT_MSSCC>, + <&clock_gcc GCC_MSS_SNOC_AXI_CLK>, + <&clock_gcc GCC_MSS_MNOC_BIMC_AXI_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_CLK>; + clock-names = "xo", "iface_clk", "bus_clk", + "mem_clk", "gpll0_mss_clk", "snoc_axi_clk", + "mnoc_axi_clk", "qdss_clk"; + qcom,proxy-clock-names = "xo", "qdss_clk"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk", + "gpll0_mss_clk", "snoc_axi_clk", + "mnoc_axi_clk"; + + qcom,sequential-fw-load; + vdd_cx-supply = <&pm660l_s3_level>; + vdd_cx-voltage = ; + vdd_mx-supply = <&pm660l_s5_level>; + vdd_mx-uV = ; + qcom,firmware-name = "modem"; + qcom,pil-self-auth; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + qcom,qdsp6v62-1-5; + memory-region = <&modem_fw_mem>; + qcom,mem-protect-id = <0xF>; + qcom,complete-ramdump; + qcom,cx-ipeak-vote; + + /* Inputs from mss */ + interrupts-extended = <&wakegic 0 448 1>, + <&modem_smp2p_in 0 0>, + <&modem_smp2p_in 2 0>, + <&modem_smp2p_in 1 0>, + <&modem_smp2p_in 3 0>, + <&modem_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* Outputs to mss */ + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + status = "ok"; + qcom,mba-mem@0 { + compatible = "qcom,pil-mba-mem"; + memory-region = <&pil_mba_mem>; + }; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,mpm2-sleep-counter@10a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x10a3000 0x1000>; + clock-frequency = <32768>; + }; + + qcom,msm-imem@146bf000 { + compatible = "qcom,msm-imem"; + reg = <0x146bf000 0x1000>; + ranges = <0x0 0x146bf000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 4>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; + + ss_mdump@b88 { + compatible = "qcom,msm-imem-minidump"; + reg = <0xb88 28>; + }; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect"; + qcom,threshold-arr = <0x179d141c 0x179d1420 + 0x179d1424 0x179d1428 + 0x179d142c 0x179d1430>; + qcom,config-reg = <0x179d1434>; + }; + + qcom,msm-gladiator-v2@17900000 { + compatible = "qcom,msm-gladiator-v2"; + reg = <0x17900000 0xe000>; + reg-names = "gladiator_base"; + interrupts = <0 22 IRQ_TYPE_LEVEL_HIGH>; + clock-names = "atb_clk"; + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 6 4>; + }; + + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 0x2200000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,fde-key-size; + qcom,no-clock-support; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 200000 400000>, + <55 512 300000 800000>, + <55 512 400000 1000000>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_rpmcc QSEECOM_CE1_CLK>, + <&clock_rpmcc QSEECOM_CE1_CLK>, + <&clock_rpmcc QSEECOM_CE1_CLK>, + <&clock_rpmcc QSEECOM_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,qsee-reentrancy-support = <2>; + }; + + qcom_cedev: qcedev@1de0000{ + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 206 IRQ_TYPE_LEVEL_HIGH>; + qcom,bam-pipe-pair = <1>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,ce-hw-shared; + qcom,bam-ee = <0>; + qcom,msm-bus,name = "qcedev-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_rpmcc QCEDEV_CE1_CLK>, + <&clock_rpmcc QCEDEV_CE1_CLK>, + <&clock_rpmcc QCEDEV_CE1_CLK>, + <&clock_rpmcc QCEDEV_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 206 IRQ_TYPE_LEVEL_HIGH>; + qcom,bam-pipe-pair = <2>; + qcom,ce-hw-instance = <0>; + qcom,ce-device = <0>; + qcom,bam-ee = <0>; + qcom,ce-hw-shared; + qcom,clk-mgmt-sus-res; + qcom,msm-bus,name = "qcrypto-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 393600 393600>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_rpmcc QCRYPTO_CE1_CLK>, + <&clock_rpmcc QCRYPTO_CE1_CLK>, + <&clock_rpmcc QCRYPTO_CE1_CLK>, + <&clock_rpmcc QCRYPTO_CE1_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,use-sw-aes-cbc-ecb-ctr-algo; + qcom,use-sw-aes-xts-algo; + qcom,use-sw-aes-ccm-algo; + qcom,use-sw-ahash-algo; + qcom,use-sw-aead-algo; + qcom,use-sw-hmac-algo; + }; + + qcom_tzlog: tz-log@146bf720 { + compatible = "qcom,tz-log"; + reg = <0x146bf720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_rng: qrng@793000 { + compatible = "qcom,msm-rng"; + reg = <0x793000 0x1000>; + qcom,msm-rng-iface-clk; + qcom,no-qrng-config; + qcom,msm-bus,name = "msm-rng-noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 618 0 0>, /* No vote */ + <1 618 0 800>; /* 100 KHz */ + clocks = <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "iface_clk"; + }; + + qcom,chd_silver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x179880b0 0x179980b0 + 0x179a80b0 0x179b80b0>; + qcom,config-arr = <0x179880b8 0x179980b8 + 0x179a80b8 0x179b80b8>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x178880b0 0x178980b0 + 0x178a80b0 0x178b80b0>; + qcom,config-arr = <0x178880b8 0x178980b8 + 0x178a80b8 0x178b80b8>; + }; + + ufsphy1: ufsphy@1da7000 { + compatible = "qcom,ufs-phy-qmp-v3-660"; + reg = <0x1da7000 0xdb8>; + reg-names = "phy_mem"; + #phy-cells = <0>; + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_UFS_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AUX_CLK>; + status = "disabled"; + }; + + ufs1: ufshc@1da4000 { + compatible = "qcom,ufshc"; + reg = <0x1da4000 0x3000>; + interrupts = <0 265 IRQ_TYPE_LEVEL_HIGH>; + phys = <&ufsphy1>; + phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; + + clock-names = + "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "core_clk_ice", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk"; + clocks = + <&clock_gcc GCC_UFS_AXI_CLK>, + <&clock_gcc GCC_AGGRE2_UFS_AXI_CLK>, + <&clock_gcc GCC_UFS_AHB_CLK>, + <&clock_gcc GCC_UFS_UNIPRO_CORE_CLK>, + <&clock_gcc GCC_UFS_ICE_CORE_CLK>, + <&clock_rpmcc RPM_SMD_LN_BB_CLK1>, + <&clock_gcc GCC_UFS_TX_SYMBOL_0_CLK>, + <&clock_gcc GCC_UFS_RX_SYMBOL_0_CLK>; + freq-table-hz = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>; + + lanes-per-direction = <1>; + spm-level = <5>; + dev-ref-clk-freq = <0>; /* 19.2 MHz */ + + non-removable; + qcom,msm-bus,name = "ufs1"; + qcom,msm-bus,num-cases = <12>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <95 512 0 0>, <1 650 0 0>, /* No vote */ + <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */ + <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */ + <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */ + <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */ + <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */ + <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */ + <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RA */ + <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */ + <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */ + <95 512 2097152 0>, <1 650 102400 0>, /* HS G3 RB */ + <95 512 7643136 0>, <1 650 307200 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "MAX"; + + pinctrl-names = "dev-reset-assert", "dev-reset-deassert"; + pinctrl-0 = <&ufs_dev_reset_assert>; + pinctrl-1 = <&ufs_dev_reset_deassert>; + + resets = <&clock_gcc GCC_UFS_BCR>; + reset-names = "core_reset"; + + status = "disabled"; + }; + + jtag_fuse: jtagfuse@786040 { + compatible = "qcom,jtag-fuse-v4"; + reg = <0x786040 0x8>; + reg-names = "fuse-base"; + }; + + jtag_mm0: jtagmm@7840000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7840000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; + + jtag_mm1: jtagmm@7940000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7940000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; + + jtag_mm2: jtagmm@7a40000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7a40000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; + + jtag_mm3: jtagmm@7b40000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7b40000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + }; + + jtag_mm4: jtagmm@7c40000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7c40000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + }; + + jtag_mm5: jtagmm@7d40000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7d40000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + }; + + jtag_mm6: jtagmm@7e40000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7e40000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + }; + + jtag_mm7: jtagmm@7f40000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7f40000 0x1000>; + reg-names = "etm-base"; + + clocks = <&clock_rpmcc RPM_SMD_QDSS_CLK>, + <&clock_rpmcc RPM_SMD_QDSS_A_CLK>; + clock-names = "core_clk", "core_a_clk"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + }; +}; + +#include "sdm660-ion.dtsi" +#include "sdm660-bus.dtsi" +#include "pm660.dtsi" +#include "pm660l.dtsi" +#include "pm660-rpm-regulator.dtsi" +#include "pm660l-rpm-regulator.dtsi" +#include "sdm660-regulator.dtsi" +#include "msm-gdsc-660.dtsi" +#include "sdm660-gpu.dtsi" +#include "sdm660-pm.dtsi" +#include "sdm660-thermal.dtsi" + +&gdsc_usb30 { + status = "ok"; +}; + +&gdsc_ufs { + status = "ok"; +}; + +&gdsc_bimc_smmu { + clock-names = "bus_clk"; + clocks = <&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>; + proxy-supply = <&gdsc_bimc_smmu>; + qcom,proxy-consumer-enable; + status = "ok"; +}; + +&gdsc_hlos1_vote_lpass_adsp { + status = "ok"; +}; + +&gdsc_hlos1_vote_turing_adsp { + status = "ok"; +}; + +&gdsc_hlos2_vote_turing_adsp { + status = "ok"; +}; + +&gdsc_venus { + status = "ok"; +}; + +&gdsc_venus_core0 { + qcom,support-hw-trigger; + status = "ok"; +}; + +&gdsc_camss_top { + status = "ok"; +}; + +&gdsc_vfe0 { + parent-supply = <&gdsc_camss_top>; + status = "ok"; +}; + +&gdsc_vfe1 { + parent-supply = <&gdsc_camss_top>; + status = "ok"; +}; + +&gdsc_cpp { + parent-supply = <&gdsc_camss_top>; + qcom,support-hw-trigger; + status = "ok"; +}; + +&gdsc_mdss { + proxy-supply = <&gdsc_mdss>; + qcom,proxy-consumer-enable; + status = "ok"; +}; + +&gdsc_gpu_gx { + clock-names = "core_root_clk"; + clocks = <&clock_gfx GFX3D_CLK_SRC>; + qcom,force-enable-root-clk; + parent-supply = <&gfx_vreg_corner>; + status = "ok"; +}; + +&gdsc_gpu_cx { + status = "ok"; +}; + + +#include "msm-arm-smmu-660.dtsi" +#include "msm-arm-smmu-impl-defs-660.dtsi" +#include "sdm660-common.dtsi" +#include "sdm660-blsp.dtsi" +#include "msm-rdbg.dtsi" +#include "sdm660-camera.dtsi" +#include "sdm660-vidc.dtsi" +#include "msm-audio.dtsi" +#include "sdm660-audio.dtsi" + +&pm660l_gpios { + /* GPIO 7 for VOL_UP */ + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio7"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&msm_vidc { + qcom,cx-ipeak-data = <&cx_ipeak_lm 4>; + qcom,clock-freq-threshold = <518400000>; +}; + +&soc { + gpio_keys { + status = "okay"; + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend", + "default"; + pinctrl-0 = <&gpio_key_active &key_vol_up_default>; + pinctrl-1 = <&gpio_key_suspend>; + + camera_focus { + label = "camera_focus"; + gpios = <&tlmm 64 0x1>; + linux,input-type = <1>; + linux,code = <0x210>; + debounce-interval = <15>; + }; + + camera_snapshot { + label = "camera_snapshot"; + gpios = <&tlmm 113 0x1>; + linux,input-type = <1>; + linux,code = <0x2fe>; + debounce-interval = <15>; + }; + + vol_up { + label = "volume_up"; + gpios = <&pm660l_gpios 7 0x1>; + linux,input-type = <1>; + linux,code = <115>; + linux,can-disable; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; +}; + +&blsp2_uart1_hs { + status = "ok"; +}; + +&pm660_adc_tm { + io-channels = <&pm660_vadc ADC_XO_THERM_PU2>, + <&pm660_vadc ADC_AMUX_THM1_PU2>, + <&pm660_vadc ADC_AMUX_THM5_PU2>; + + /* Channel nodes */ + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + msm_therm{ + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + quiet_therm{ + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +#include "sdm660-mdss.dtsi" +#include "sdm660-mdss-pll.dtsi" diff --git a/arch/arm64/boot/dts/vendor/qcom/sdxprairie-thermal-integrated.dtsi b/arch/arm64/boot/dts/vendor/qcom/sdxprairie-thermal-integrated.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..45518cfb0877b633c5faaa2e8d6891e08596cec8 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/sdxprairie-thermal-integrated.dtsi @@ -0,0 +1,440 @@ +#include + +&soc { + qmi-tmd-devices { + compatible = "qcom,qmi-cooling-devices"; + + modem { + qcom,instance-id = ; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_pa_fr1: modem_pa_fr1 { + qcom,qmi-dev-name = "pa_fr1"; + #cooling-cells = <2>; + }; + + modem_tj: modem_tj { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_mmw_skin0: modem_mmw_skin0 { + qcom,qmi-dev-name = "mmw_skin0"; + #cooling-cells = <2>; + }; + + modem_mmw_skin1: modem_mmw_skin1 { + qcom,qmi-dev-name = "mmw_skin1"; + #cooling-cells = <2>; + }; + + modem_mmw_skin2: modem_mmw_skin2 { + qcom,qmi-dev-name = "mmw_skin2"; + #cooling-cells = <2>; + }; + + modem_mmw_skin3: modem_mmw_skin3 { + qcom,qmi-dev-name = "mmw_skin3"; + #cooling-cells = <2>; + }; + + modem_mmw0: modem_mmw0 { + qcom,qmi-dev-name = "mmw0"; + #cooling-cells = <2>; + }; + + modem_mmw1: modem_mmw1 { + qcom,qmi-dev-name = "mmw1"; + #cooling-cells = <2>; + }; + + modem_mmw2: modem_mmw2 { + qcom,qmi-dev-name = "mmw2"; + #cooling-cells = <2>; + }; + + modem_mmw3: modem_mmw3 { + qcom,qmi-dev-name = "mmw3"; + #cooling-cells = <2>; + }; + + modem_bcl: modem_bcl { + qcom,qmi-dev-name = "vbatt_low"; + #cooling-cells = <2>; + }; + + modem_charge_state: modem_charge_state { + qcom,qmi-dev-name = "charge_state"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + + modem_wlan: modem_wlan { + qcom,qmi-dev-name = "wlan"; + #cooling-cells = <2>; + }; + }; + }; + + qmi_sensor: qmi-ts-sensors { + compatible = "qcom,qmi-sensors"; + #thermal-sensor-cells = <1>; + + modem { + qcom,instance-id = ; + qcom,qmi-sensor-names = "pa", + "pa_1", + "qfe_wtr0", + "modem_tsens", + "qfe_mmw0", + "qfe_mmw1", + "qfe_mmw2", + "qfe_mmw3", + "xo_therm", + "qfe_mmw_streamer0", + "qfe_mmw0_mod", + "qfe_mmw1_mod", + "qfe_mmw2_mod", + "qfe_mmw3_mod", + "qfe_ret_pa0", + "qfe_wtr_pa0", + "qfe_wtr_pa1", + "qfe_wtr_pa2", + "qfe_wtr_pa3", + "sys_therm1", + "sys_therm2", + "modem_tsens1", + "BEAMER_W_THERM", + "BEAMER_N_THERM", + "BEAMER_E_THERM"; + }; + }; +}; + +&thermal_zones { + modem-lte-sub6-pa1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_PA)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-lte-sub6-pa2 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_PA_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_0)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_2)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_3)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-skin-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_XO_THERM)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-wifi-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_SYS_THERM_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-ambient-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_SYS_THERM_2)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_MODEM_TSENS)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_MODEM_TSENS_1)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-streamer-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_STREAMER_0)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw0-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_0_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw1-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_1_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw2-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_2_MOD)>; + wake-capable-sensor; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw3-mod-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_QFE_MMW_3_MOD)>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw-pa1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_BEAMER_W_THERM)>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw-pa2-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_BEAMER_N_THERM)>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + modem-mmw-pa3-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&qmi_sensor + (QMI_MODEM_INST_ID+QMI_BEAMER_E_THERM)>; + wake-capable-sensor; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/skeleton64.dtsi b/arch/arm64/boot/dts/vendor/qcom/skeleton64.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..1f8ba28132c4a196b6351f99b16fe92593732717 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/skeleton64.dtsi @@ -0,0 +1,15 @@ +/* + * Skeleton device tree in the 64 bits version; the bare minimum + * needed to boot; just include and add a compatible value. The + * bootloader will typically populate the memory node. + */ + +/ { + #address-cells = <2>; + #size-cells = <2>; + cpus { }; + soc { }; + chosen { }; + aliases { }; + memory { device_type = "memory"; reg = <0 0 0 0>; }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/smb1355.dtsi b/arch/arm64/boot/dts/vendor/qcom/smb1355.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..a75e19fc6607562d181be69cb5eaa4b6b1f89082 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/smb1355.dtsi @@ -0,0 +1,44 @@ +#include + +smb1355: qcom,smb1355@c { + compatible = "qcom,i2c-pmic"; + reg = <0xc>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x2 0xC5 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1355"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x12 0x13 0x16>; + status = "disabled"; + + smb1355_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb1355_charger: qcom,smb1355-charger@1000 { + compatible = "qcom,smb1355"; + qcom,pmic-revid = <&smb1355_revid>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb1355>; + status = "disabled"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/smb1390.dtsi b/arch/arm64/boot/dts/vendor/qcom/smb1390.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0996782681de51254c1731e94bec720e94e84ea9 --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/smb1390.dtsi @@ -0,0 +1,60 @@ +#include + +smb1390: qcom,smb1390@10 { + compatible = "qcom,i2c-pmic"; + reg = <0x10>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x2 0xC5 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1390"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10>; + status = "disabled"; + + smb1390_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100>; + }; + + smb1390_charger: qcom,charge_pump { + compatible = "qcom,smb1390-charger-psy"; + qcom,pmic-revid = <&smb1390_revid>; + interrupt-parent = <&smb1390>; + status = "disabled"; + + qcom,core { + interrupts = <0x10 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x10 0x5 IRQ_TYPE_EDGE_RISING>, + <0x10 0x6 IRQ_TYPE_EDGE_RISING>, + <0x10 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "switcher-off-window", + "switcher-off-fault", + "tsd-fault", + "irev-fault", + "vph-ov-hard", + "vph-ov-soft", + "ilim", + "temp-alarm"; + }; + }; +}; + +smb1390_slave: qcom,smb1390_slave@18 { + compatible = "qcom,i2c-pmic"; + reg = <0x18>; + #address-cells = <1>; + #size-cells = <0>; + qcom,periph-map = <0x10>; + status = "disabled"; + + smb1390_slave_charger: qcom,charge_pump_slave { + compatible = "qcom,smb1390-slave"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/vendor/qcom/smb1398.dtsi b/arch/arm64/boot/dts/vendor/qcom/smb1398.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..91d172c35c35085b6a033eaf97bd05405468982e --- /dev/null +++ b/arch/arm64/boot/dts/vendor/qcom/smb1398.dtsi @@ -0,0 +1,63 @@ +#include + +smb1396: qcom,smb1396@34 { + compatible = "qcom,i2c-pmic"; + reg = <0x34>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x6 0x26 0x27>; + status = "disabled"; + + smb1396_revid: qcom,revid { + compatible = "qcom,qpnp-revid"; + reg = <0x100>; + }; + + smb1396_div2_cp_master: qcom,div2_cp { + compatible = "qcom,smb1396-div2-cp-master"; + qcom,pmic-revid = <&smb1396_revid>; + io-channels = <&pm7250b_vadc ADC_AMUX_THM2>; + io-channel-names = "die_temp"; + interrupts = <0x26 0x1 IRQ_TYPE_EDGE_RISING>, + <0x26 0x3 IRQ_TYPE_EDGE_RISING>, + <0x26 0x5 IRQ_TYPE_EDGE_RISING>, + <0x26 0x7 IRQ_TYPE_EDGE_RISING>, + <0x27 0x5 IRQ_TYPE_EDGE_RISING>, + <0x27 0x6 IRQ_TYPE_EDGE_RISING>, + <0x27 0x7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "temp-shdwn", + "div2-irev", + "usbin-uv", + "usbin-ov", + "div2-ilim", + "div2-win-uv", + "div2-win-ov"; + status = "disabled"; + }; +}; + +smb1396_slave: qcom,smb1396@35 { + compatible = "qcom,i2c-pmic"; + reg = <0x35>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + smb1396_div2_cp_slave: qcom,div2_cp_slave { + compatible = "qcom,smb1396-div2-cp-slave"; + status = "disabled"; + }; +}; + +smb1398: qcom,smb1398@36 { + compatible = "qcom,i2c-pmic"; + reg = <0x36>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + smb1398_pre_regulator: qcom,pre_regulator { + compatible = "qcom,smb1398-pre-regulator"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/configs/vendor/bengal-perf_defconfig b/arch/arm64/configs/vendor/bengal-perf_defconfig index cbf4c9ae219e2b0ce530425c2cc764325ae9132e..b44708fc854f6130280321a83e26b2f7301d8d53 100644 --- a/arch/arm64/configs/vendor/bengal-perf_defconfig +++ b/arch/arm64/configs/vendor/bengal-perf_defconfig @@ -65,7 +65,6 @@ CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -297,6 +296,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -637,7 +637,6 @@ CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCE=y diff --git a/arch/arm64/configs/vendor/bengal_defconfig b/arch/arm64/configs/vendor/bengal_defconfig index 037762878a90bf5da3ac17d898ca3889701950fe..796d7e8bef9f170ad0c1594767ad6992a87cb3c3 100644 --- a/arch/arm64/configs/vendor/bengal_defconfig +++ b/arch/arm64/configs/vendor/bengal_defconfig @@ -67,7 +67,6 @@ CONFIG_ARM64_SW_TTBR0_PAN=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y CONFIG_COMPAT=y -CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y CONFIG_PM_WAKELOCKS_LIMIT=0 # CONFIG_PM_WAKELOCKS_GC is not set @@ -309,6 +308,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y @@ -666,7 +666,6 @@ CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y -CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCE=y diff --git a/arch/arm64/configs/vendor/kona-perf_defconfig b/arch/arm64/configs/vendor/kona-perf_defconfig index 89991ead14b2dbd483e57cf7c74686763cfb240c..c418de453454d1796b252199447a7bef6ac5e457 100644 --- a/arch/arm64/configs/vendor/kona-perf_defconfig +++ b/arch/arm64/configs/vendor/kona-perf_defconfig @@ -3,6 +3,10 @@ CONFIG_LOCALVERSION="-perf" CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y +#2020-06-20 [OSP-5970] add for performace data proc/healthinfo/ start +CONFIG_PREEMPT_TRACER=y +CONFIG_IRQSOFF_TRACER=y +#2020-06-20 [OSP-5970] add for performace data proc/healthinfo/ end CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y CONFIG_TASKSTATS=y @@ -351,6 +355,12 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_PROJECT_INFO=y +CONFIG_OEM_BOOT_MODE=y +CONFIG_TOUCHSCREEN_PROPERTIES=y +CONFIG_TOUCHPANEL_ONEPLUS=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY761=y +CONFIG_TOUCHPANEL_SAMSUNG=y CONFIG_TOUCHSCREEN_FTS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y @@ -359,6 +369,8 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set +CONFIG_FINGERPRINT_DETECT=y +CONFIG_FINGERPRINT_GOODIX=y CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y CONFIG_HW_RANDOM=y diff --git a/arch/arm64/configs/vendor/kona_defconfig b/arch/arm64/configs/vendor/kona_defconfig index c693a5f616c25b85ddf215257d728c9662cc769c..3aa4e3b3a082cc60810ebe945c4f63e104700389 100644 --- a/arch/arm64/configs/vendor/kona_defconfig +++ b/arch/arm64/configs/vendor/kona_defconfig @@ -2,6 +2,10 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y +#2020-06-20 [OSP-5970] add for performace data proc/healthinfo/ start +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +#2020-06-20 [OSP-5970] add for performace data proc/healthinfo/ end CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y CONFIG_TASKSTATS=y @@ -365,6 +369,18 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_PROJECT_INFO=y +CONFIG_OEM_BOOT_MODE=y +CONFIG_PARAM_READ_WRITE=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE_DEVICE_INFO=y +CONFIG_PSTORE_PMSG=y +CONFIG_TOUCHSCREEN_PROPERTIES=y +CONFIG_TOUCHPANEL_ONEPLUS=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY761=y +CONFIG_TOUCHPANEL_SAMSUNG=y CONFIG_TOUCHSCREEN_FTS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y @@ -373,6 +389,8 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set +CONFIG_FINGERPRINT_DETECT=y +CONFIG_FINGERPRINT_GOODIX=y CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y diff --git a/arch/arm64/configs/vendor/lito-perf_defconfig b/arch/arm64/configs/vendor/lito-perf_defconfig index 3e38e6cf1ce9931400e0fdf92706d6775c4e955c..48ead50d4ced2f518397c5ab68543ae476291571 100644 --- a/arch/arm64/configs/vendor/lito-perf_defconfig +++ b/arch/arm64/configs/vendor/lito-perf_defconfig @@ -38,13 +38,17 @@ CONFIG_KALLSYMS_ALL=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y +CONFIG_CGROUP_IOLIMIT=y #[OPTIMIZATION][R]:[OSP-8064][KERNEL] IOLimit +#[OPTIMIZATION][SM8250_R]:[stability][OPBRITN-38388] trigger panic when detect key process in D state over 60s(1/4) +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_HUNG_TASK_ENHANCE=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y # CONFIG_ZONE_DMA32 is not set -CONFIG_HOTPLUG_SIZE_BITS=29 CONFIG_ARCH_QCOM=y CONFIG_ARCH_LITO=y CONFIG_ARCH_LAGOON=y @@ -52,6 +56,7 @@ CONFIG_PCI=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_SECCOMP=y +CONFIG_CONTROL_CENTER=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_ARM64_SSBD=y CONFIG_ARMV8_DEPRECATED=y @@ -71,6 +76,7 @@ CONFIG_ENERGY_MODEL=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y @@ -78,6 +84,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_HOUSTON=y CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y CONFIG_MSM_TZ_LOG=y @@ -104,10 +111,6 @@ CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y -CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y -CONFIG_MEMORY_HOTREMOVE=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y @@ -116,6 +119,11 @@ CONFIG_HAVE_USERSPACE_LOW_MEMORY_KILLER=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_ONEPLUS_MEM_MONITOR=y +CONFIG_ONEPLUS_FG_OPT=y +CONFIG_ONEPLUS_HEALTHINFO=y +CONFIG_DEFRAG=y +CONFIG_OPCHAIN=y CONFIG_XFRM_USER=y CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y @@ -267,7 +275,10 @@ CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y -CONFIG_NFC_NQ=y +#CONFIG_NFC_NQ=y +CONFIG_NXP_ESE_PN8XT=y +CONFIG_NXP_NFC_PN8XT=y +CONFIG_NXP_NFC_ESE_DEVICE=y CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set @@ -341,6 +352,24 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TRI_STATE_KEY=y +CONFIG_RF_CABLE_DETECT=y +CONFIG_PROJECT_INFO=y +CONFIG_OEM_BOOT_MODE=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE_DEVICE_INFO=y +CONFIG_PSTORE_PMSG=y +CONFIG_OEM_FORCE_DUMP=y +CONFIG_PARAM_READ_WRITE=y +CONFIG_BOOTLOADER_LOG=y +CONFIG_WB_KERNEL_LOG=y +CONFIG_TOUCHSCREEN_PROPERTIES=y +CONFIG_TOUCHPANEL_ONEPLUS=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY761=y +CONFIG_TOUCHPANEL_GOODIX_GT9886=y +CONFIG_TOUCHPANEL_SAMSUNG=y CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y @@ -352,8 +381,11 @@ CONFIG_INPUT_UINPUT=y # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set +CONFIG_FINGERPRINT_DETECT=y +CONFIG_FINGERPRINT_GOODIX=y CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y +CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_TTY_PRINTK=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y @@ -376,12 +408,13 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y -CONFIG_SMB1355_SLAVE_CHARGER=y +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_QG=y CONFIG_SMB1398_CHARGER=y +CONFIG_FG_BQ27541=y +CONFIG_ONEPLUS_FASTCHG=y CONFIG_THERMAL=y -CONFIG_THERMAL_STATISTICS=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y @@ -473,6 +506,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_ACC=y @@ -552,14 +586,10 @@ CONFIG_MSM_QMP=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y -CONFIG_IOMMU_DEBUG=y -CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_GLINK_SPSS=y CONFIG_QCOM_COMMAND_DB=y -CONFIG_QCOM_MEM_OFFLINE=y -CONFIG_OVERRIDE_MEMORY_LIMIT=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_IPCC=y @@ -649,6 +679,8 @@ CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_BD_STAT=y +CONFIG_F2FS_OF2FS=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y @@ -661,11 +693,14 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_EXFAT_FS=y +CONFIG_NTFS_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y +CONFIG_FSC=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y @@ -698,6 +733,7 @@ CONFIG_DEBUG_LIST=y CONFIG_IPC_LOGGING=y CONFIG_DEBUG_ALIGN_RODATA=y CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_SMART_BOOST=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_DYNAMIC_REPLICATOR=y @@ -710,3 +746,27 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +# Oneplus specific configs +CONFIG_AW8697_HAPTIC=y +CONFIG_ONEPLUS_WIRELESSCHG=n +CONFIG_OP_FREEZER=n +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=n +CONFIG_OP_POWER_SUPPLY=y +CONFIG_OP_TOUCHSCREEN=y +CONFIG_INPUT_FINGERPRINT=y +CONFIG_VM_FRAGMENT_MONITOR=y +CONFIG_DIRECT_SWAPPINESS=y +CONFIG_UFSFEATURE=y +CONFIG_UFSHPB=y +CONFIG_UFSTW=y +CONFIG_OP_FREEZER=y +CONFIG_UFSTW_IGNORE_GUARANTEE_BIT=y +CONFIG_IM=y +CONFIG_PCCORE=y +CONFIG_TPD=y +CONFIG_UXCHAIN=y +CONFIG_MEMEX_STANDALONE=y +#SLM feature configs +CONFIG_SLA=y +CONFIG_SLA_ALGO=y +CONFIG_RATP=y diff --git a/arch/arm64/configs/vendor/lito_defconfig b/arch/arm64/configs/vendor/lito_defconfig index d1fa789baad96f4d16952d527186e230e5b220ca..64df3cd220b531c5909e5d53ed7c46bf65e5dbf0 100644 --- a/arch/arm64/configs/vendor/lito_defconfig +++ b/arch/arm64/configs/vendor/lito_defconfig @@ -39,12 +39,16 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT_ALWAYS_ON=y CONFIG_EMBEDDED=y +CONFIG_CGROUP_IOLIMIT=y #[OPTIMIZATION][R]:[OSP-8064][KERNEL] IOLimit +#[OPTIMIZATION][SM8250_R]:[stability][OPBRITN-38388] trigger panic when detect key process in D state over 60s(1/4) +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=60 +CONFIG_HUNG_TASK_ENHANCE=y # CONFIG_COMPAT_BRK is not set CONFIG_SLAB_FREELIST_RANDOM=y CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y # CONFIG_ZONE_DMA32 is not set -CONFIG_HOTPLUG_SIZE_BITS=29 CONFIG_ARCH_QCOM=y CONFIG_ARCH_LITO=y CONFIG_ARCH_LAGOON=y @@ -52,6 +56,7 @@ CONFIG_PCI=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_SECCOMP=y +CONFIG_CONTROL_CENTER=y # CONFIG_UNMAP_KERNEL_AT_EL0 is not set CONFIG_ARM64_SSBD=y CONFIG_PRINT_VMEMLAYOUT=y @@ -72,12 +77,14 @@ CONFIG_ENERGY_MODEL=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_BOOST=y +CONFIG_HOUSTON=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_ARM_QCOM_CPUFREQ_HW_DEBUG=y @@ -106,10 +113,6 @@ CONFIG_CFQ_GROUP_IOSCHED=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_MEMORY_HOTPLUG=y -CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y -CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y -CONFIG_MEMORY_HOTREMOVE=y CONFIG_CLEANCACHE=y CONFIG_CMA=y CONFIG_CMA_DEBUG=y @@ -121,6 +124,11 @@ CONFIG_HAVE_USERSPACE_LOW_MEMORY_KILLER=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y +CONFIG_ONEPLUS_MEM_MONITOR=y +CONFIG_ONEPLUS_FG_OPT=y +CONFIG_ONEPLUS_HEALTHINFO=y +CONFIG_DEFRAG=y +CONFIG_OPCHAIN=y CONFIG_XFRM_USER=y CONFIG_XFRM_INTERFACE=y CONFIG_XFRM_STATISTICS=y @@ -273,7 +281,10 @@ CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y -CONFIG_NFC_NQ=y +#CONFIG_NFC_NQ=y +CONFIG_NXP_ESE_PN8XT=y +CONFIG_NXP_NFC_PN8XT=y +CONFIG_NXP_NFC_ESE_DEVICE=y CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set @@ -348,6 +359,24 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TRI_STATE_KEY=y +CONFIG_RF_CABLE_DETECT=y +CONFIG_PROJECT_INFO=y +CONFIG_OEM_BOOT_MODE=y +CONFIG_PARAM_READ_WRITE=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE_DEVICE_INFO=y +CONFIG_PSTORE_PMSG=y +CONFIG_BOOTLOADER_LOG=y +CONFIG_OEM_FORCE_DUMP=y +CONFIG_WB_KERNEL_LOG=y +CONFIG_TOUCHSCREEN_PROPERTIES=y +CONFIG_TOUCHPANEL_ONEPLUS=y +CONFIG_TOUCHPANEL_SAMSUNG_S6SY761=y +CONFIG_TOUCHPANEL_GOODIX_GT9886=y +CONFIG_TOUCHPANEL_SAMSUNG=y CONFIG_SECURE_TOUCH_SYNAPTICS_DSX=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_REFLASH=y CONFIG_TOUCHSCREEN_SYNAPTICS_TCM_RECOVERY=y @@ -359,6 +388,8 @@ CONFIG_INPUT_UINPUT=y # CONFIG_VT is not set # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set +CONFIG_FINGERPRINT_DETECT=y +CONFIG_FINGERPRINT_GOODIX=y CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y @@ -384,12 +415,13 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB5=y -CONFIG_SMB1390_CHARGE_PUMP_PSY=y -CONFIG_SMB1355_SLAVE_CHARGER=y +#CONFIG_SMB1390_CHARGE_PUMP_PSY=y +#CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_QG=y CONFIG_SMB1398_CHARGER=y +CONFIG_FG_BQ27541=y +CONFIG_ONEPLUS_FASTCHG=y CONFIG_THERMAL=y -CONFIG_THERMAL_STATISTICS=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y CONFIG_THERMAL_GOV_LOW_LIMITS=y @@ -481,6 +513,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y CONFIG_USB_CONFIGFS_F_ACC=y @@ -575,8 +608,6 @@ CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_GLINK_SPSS=y CONFIG_QCOM_COMMAND_DB=y -CONFIG_QCOM_MEM_OFFLINE=y -CONFIG_BUG_ON_HW_MEM_ONLINE_FAIL=y CONFIG_OVERRIDE_MEMORY_LIMIT=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y @@ -670,6 +701,8 @@ CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_F2FS_FS=y CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_BD_STAT=y +CONFIG_F2FS_OF2FS=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y CONFIG_FS_VERITY=y @@ -682,12 +715,15 @@ CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_EXFAT_FS=y +CONFIG_NTFS_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_EFIVAR_FS=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y +CONFIG_FSC=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y @@ -710,7 +746,6 @@ CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_XZ_DEC=y CONFIG_PRINTK_TIME=y CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS=y CONFIG_DEBUG_MODULE_LOAD_INFO=y CONFIG_DEBUG_INFO=y CONFIG_PAGE_OWNER=y @@ -726,7 +761,7 @@ CONFIG_PAGE_POISONING=y CONFIG_PAGE_POISONING_ENABLE_DEFAULT=y CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y -CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=8192 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y @@ -748,14 +783,13 @@ CONFIG_RCU_TORTURE_TEST=m CONFIG_FAULT_INJECTION=y CONFIG_FAIL_PAGE_ALLOC=y CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_UFS_FAULT_INJECTION=y CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y CONFIG_IPC_LOGGING=y CONFIG_QCOM_RTB=y CONFIG_QCOM_RTB_SEPARATE_CPUS=y CONFIG_FUNCTION_TRACER=y CONFIG_PREEMPTIRQ_EVENTS=y -CONFIG_IRQSOFF_TRACER=y -CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_LKDTM=m CONFIG_ATOMIC64_SELFTEST=m @@ -764,6 +798,7 @@ CONFIG_MEMTEST=y CONFIG_BUG_ON_DATA_CORRUPTION=y CONFIG_PANIC_ON_DATA_CORRUPTION=y CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE=y +CONFIG_SMART_BOOST=y CONFIG_CORESIGHT=y CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y CONFIG_CORESIGHT_SOURCE_ETM4X=y @@ -776,3 +811,27 @@ CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_TGU=y +# Oneplus specific configs +CONFIG_AW8697_HAPTIC=y +CONFIG_ONEPLUS_WIRELESSCHG=n +CONFIG_OP_FREEZER=n +CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL=n +CONFIG_OP_POWER_SUPPLY=y +CONFIG_OP_TOUCHSCREEN=y +CONFIG_INPUT_FINGERPRINT=y +CONFIG_VM_FRAGMENT_MONITOR=y +CONFIG_DIRECT_SWAPPINESS=y +CONFIG_UFSFEATURE=y +CONFIG_UFSHPB=y +CONFIG_UFSTW=y +CONFIG_OP_FREEZER=y +CONFIG_UFSTW_IGNORE_GUARANTEE_BIT=y +CONFIG_IM=y +CONFIG_PCCORE=y +CONFIG_TPD=y +CONFIG_UXCHAIN=y +CONFIG_MEMEX_STANDALONE=y +#SLM feature configs +CONFIG_SLA=y +CONFIG_SLA_ALGO=y +CONFIG_RATP=y diff --git a/arch/arm64/include/uapi/asm/setup.h b/arch/arm64/include/uapi/asm/setup.h index 5d703888f35110d2a7a15ec1836bffcffae3c8bb..9f583cb9e76ecf4ce937fc93f41d0d4dcff8927a 100644 --- a/arch/arm64/include/uapi/asm/setup.h +++ b/arch/arm64/include/uapi/asm/setup.h @@ -22,6 +22,6 @@ #include -#define COMMAND_LINE_SIZE 2048 +#define COMMAND_LINE_SIZE 3072 #endif diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index f3e92f23c2a4c9e0a9edad7691dea31db99554e9..1548874a8890d3b1951f3798a2a4497e8fcc7d1b 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -333,7 +333,7 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) set_bit(ICACHEF_ALIASING, &__icache_flags); } - pr_info("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); + pr_debug("Detected %s I-cache on CPU%d\n", icache_policy_str[l1ip], cpu); } static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index c1bb288abcd6a5ea93b435a7fe68f93fdb70d9fe..606ebcd89ffdb64450861b03a102092d26b959d6 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -1145,7 +1145,7 @@ static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) struct perf_event *event; int idx; - if (!cpu_pmu) + if (!cpu_pmu || !(cpu_pmu->hw_events)) return; if (__this_cpu_read(perf_event_is_hotplugging)) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 73d5ac36803dc12d2dc9e72865031694761d6d3e..ffa33496cfb27aa929353f7bbbd9bb8ab02f3d16 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -101,7 +101,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu) do { err = psci_ops.affinity_info(cpu_logical_map(cpu), 0); if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) { - pr_info("CPU%d killed (polled %d ms)\n", cpu, + pr_debug("CPU%d killed (polled %d ms)\n", cpu, jiffies_to_msecs(jiffies - start)); return 0; } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index ece9ee623a88adc698102da16b937407463ff446..bb75f63f105edeccf7044b191615970fae950f45 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -450,6 +450,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, tsk = current; mm = tsk->mm; +#ifdef CONFIG_CGROUP_IOLIMIT + task_set_in_pagefault(tsk); +#endif /* * If we're in an interrupt or have no user context, we must not take * the fault. @@ -530,6 +533,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, if (fatal_signal_pending(current)) { if (!user_mode(regs)) goto no_context; +#ifdef CONFIG_CGROUP_IOLIMIT + task_clear_in_pagefault(tsk); +#endif return 0; } @@ -592,6 +598,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, * oom-killed). */ pagefault_out_of_memory(); +#ifdef CONFIG_CGROUP_IOLIMIT + task_clear_in_pagefault(tsk); +#endif return 0; } @@ -626,10 +635,16 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, } __do_user_fault(&si, esr); +#ifdef CONFIG_CGROUP_IOLIMIT + task_clear_in_pagefault(tsk); +#endif return 0; no_context: __do_kernel_fault(addr, esr, regs); +#ifdef CONFIG_CGROUP_IOLIMIT + task_clear_in_pagefault(tsk); +#endif return 0; } diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index 157f2caa13516b66db0538a67a148036912dd57c..4b2dde7d6d3be065ab5a3f43bc3b279f4658b055 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -83,6 +83,21 @@ static unsigned long mmap_base(unsigned long rnd, struct rlimit *rlim_stack) return PAGE_ALIGN(STACK_TOP - gap - rnd); } +void special_arch_pick_mmap_layout(struct mm_struct *mm) +{ + unsigned long random_factor = 0UL; + unsigned long old_mmap_base = mm->mmap_base; + unsigned long new_mmap_base; + struct rlimit *rlim_stack = ¤t->signal->rlim[RLIMIT_STACK]; + + if ((current->flags & PF_RANDOMIZE) + && !mmap_is_legacy(rlim_stack)) { + random_factor = arch_mmap_rnd() % (dbg_pm[7]); + new_mmap_base = mmap_base(random_factor, rlim_stack); + mm->mmap_base = max_t(unsigned long, new_mmap_base, old_mmap_base); + } +} + /* * This function, called very early during the creation of a new process VM * image, sets up which VM layout function to use: diff --git a/block/blk-core.c b/block/blk-core.c index f61a9f139cf8d5d7476ac920a927c59f1bb04fb3..7e50d91c3661692a42684e598a936b0524197081 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -50,6 +50,18 @@ struct dentry *blk_debugfs_root; #endif +/* io information */ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +extern void ohm_iolatency_record(struct request *req, unsigned int nr_bytes, int fg, u64 delta_us); +static u64 latency_count; +static u32 io_print_count; +bool io_print_flag; +static int io_print_on; +#define PRINT_LATENCY 500000 /* 500*1000 */ +#define COUNT_TIME 86400000 /* 24*60*60*1000 */ +#endif + + EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); @@ -2921,6 +2933,12 @@ struct request *blk_peek_request(struct request_queue *q) * not be passed by new incoming requests */ rq->rq_flags |= RQF_STARTED; + + /* request start ktime */ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + rq->block_io_start = ktime_get(); +#endif + trace_block_rq_issue(q, rq); } @@ -3110,8 +3128,48 @@ bool blk_update_request(struct request *req, blk_status_t error, { int total_bytes; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*request complete ktime*/ + ktime_t now; + u64 delta_us; + char rwbs[RWBS_LEN]; +#endif + trace_block_rq_complete(req, blk_status_to_errno(error), nr_bytes); +/*request complete ktime*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (req->tag >= 0 && req->block_io_start > 0) { + io_print_flag = false; + now = ktime_get(); + delta_us = ktime_us_delta(now, req->block_io_start); + ohm_iolatency_record(req, nr_bytes, current_is_fg(), ktime_us_delta(now, req->block_io_start)); + trace_block_time(req->q, req, delta_us, nr_bytes); + + if (delta_us > PRINT_LATENCY && io_print_on) { + if ((ktime_to_ms(now)) < COUNT_TIME) + latency_count++; + else + latency_count = 0; + + io_print_flag = true; + blk_fill_rwbs(rwbs, req->cmd_flags, nr_bytes); + + /*if log is continuous, printk the first log.*/ + if (!io_print_count) + pr_info("[IO Latency]UID:%u,slot:%d,outstanding=0x%lx,IO_Type:%s,Block IO/Flash Latency:(%llu/%llu)LBA:%llu,length:%d size:%d,count=%lld\n", + (from_kuid_munged(current_user_ns(), current_uid())), + req->tag, ufs_outstanding, rwbs, delta_us, req->flash_io_latency, + (unsigned long long)blk_rq_pos(req), + nr_bytes >> 9, blk_rq_bytes(req), latency_count); + io_print_count++; + } + + if (!io_print_flag && io_print_count) + io_print_count = 0; + } +#endif + if (!req->bio) return false; diff --git a/block/blk-flush.c b/block/blk-flush.c index 256fa1ccc2bd6e1bc5be35ed992350fd7fec28d8..5fa1d2f6b757b6c07005ac219fa2cb07c8d9517f 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -556,6 +556,10 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, if (!q->make_request_fn) return -ENXIO; +#ifdef CONFIG_PANIC_FLUSH + sysctl_blkdev_issue_flush_count++; +#endif + bio = bio_alloc(gfp_mask, 0); bio_set_dev(bio, bdev); bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH; diff --git a/block/blk.h b/block/blk.h index 1a5b67b57e6b247c12a64476b722d8dd72c685de..0a1cc09723b818cf29c54cb3063fbb539b7ab37e 100644 --- a/block/blk.h +++ b/block/blk.h @@ -19,6 +19,10 @@ extern struct dentry *blk_debugfs_root; #endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +extern unsigned long ufs_outstanding; +#endif + struct blk_flush_queue { unsigned int flush_queue_delayed:1; unsigned int flush_pending_idx:1; @@ -42,6 +46,10 @@ extern struct kmem_cache *request_cachep; extern struct kobj_type blk_queue_ktype; extern struct ida blk_queue_ida; +#ifdef CONFIG_PANIC_FLUSH +extern unsigned long sysctl_blkdev_issue_flush_count; +#endif + /* * @q->queue_lock is set while a queue is being initialized. Since we know * that no other threads access the queue object before @q->queue_lock has diff --git a/block/genhd.c b/block/genhd.c index 2b2a936cf8480c57e2fa4525ec6b540817ac5af6..e10af20eb90c50ed8d911c9116f11954284f98d1 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -957,6 +957,55 @@ void __init printk_all_partitions(void) class_dev_iter_exit(&iter); } +#ifdef CONFIG_WB_KERNEL_LOG +struct block_device *find_reserve_partition(void) +{ + struct class_dev_iter iter; + struct device *dev; + struct block_device *bdev = NULL; + + pr_info("Op_kernel_log: finding reserve partition\n"); + class_dev_iter_init(&iter, &block_class, NULL, &disk_type); + while ((dev = class_dev_iter_next(&iter))) { + struct gendisk *disk = dev_to_disk(dev); + struct disk_part_iter piter; + struct hd_struct *part; + int target_partno; + char name_buf[BDEVNAME_SIZE]; + char devt_buf[BDEVT_SIZE]; + /* + * Don't show empty devices or things that have been + * suppressed + */ + if (get_capacity(disk) == 0 || + (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) + continue; + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); + while ((part = disk_part_iter_next(&piter))) { + bool is_part0 = part == &disk->part0; + + if (part->info && strcmp(((char *)part->info->volname), "kernel_log") == 0) { + pr_info("Op_kernel_log: find reserve partition: %s%s %10llu %s %s %s\n", + is_part0 ? "" : " ", bdevt_str(part_devt(part), devt_buf), + (unsigned long long)part_nr_sects_read(part) >> 1 + , disk_name(disk, part->partno, name_buf), + part->info->uuid, ((char *)part->info->volname)); + + bdev = bdget_disk(disk, part->partno); + + if (bdev != NULL) + get_gendisk(bdev->bd_dev, &target_partno); + else + pr_err("Op_kernel_log: get dev NULL\n"); + } + } + disk_part_iter_exit(&piter); + } + class_dev_iter_exit(&iter); + return bdev; +} +#endif + #ifdef CONFIG_PROC_FS /* iterator */ static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) diff --git a/drivers/Kconfig b/drivers/Kconfig index b37e4b5566cbef23cb88506cd113e793ed424606..b74d0499cc37360721ae0f054982fa816fd00070 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -230,4 +230,5 @@ source "drivers/sensors/Kconfig" source "drivers/gpu/msm/Kconfig" source "drivers/energy_model/Kconfig" +source "drivers/oneplus/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 9a258f18ec6fc55a71929ed15b8983d90b13d17e..c092df7419c55c0716f2e772809f89e42510903d 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -192,3 +192,4 @@ obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/ obj-$(CONFIG_SIOX) += siox/ obj-$(CONFIG_GNSS) += gnss/ obj-$(CONFIG_SENSORS_SSC) += sensors/ +obj-y += oneplus/ diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e9407d3aadf8f6e87fcbaeb228587b3e54ec7fd8..7c2420a4fa32c65a635f07f777692e48a923db1e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -75,12 +75,19 @@ #include #include +#include + #include #include "binder_alloc.h" #include "binder_internal.h" #include "binder_trace.h" +#ifdef CONFIG_OP_FREEZER +// add for op freeze manager +#include +#endif + static HLIST_HEAD(binder_deferred_list); static DEFINE_MUTEX(binder_deferred_lock); @@ -237,7 +244,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( struct binder_work { struct list_head entry; - enum { + enum binder_work_type { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, BINDER_WORK_RETURN_ERROR, @@ -897,27 +904,6 @@ static struct binder_work *binder_dequeue_work_head_ilocked( return w; } -/** - * binder_dequeue_work_head() - Dequeues the item at head of list - * @proc: binder_proc associated with list - * @list: list to dequeue head - * - * Removes the head of the list if there are items on the list - * - * Return: pointer dequeued binder_work, NULL if list was empty - */ -static struct binder_work *binder_dequeue_work_head( - struct binder_proc *proc, - struct list_head *list) -{ - struct binder_work *w; - - binder_inner_proc_lock(proc); - w = binder_dequeue_work_head_ilocked(list); - binder_inner_proc_unlock(proc); - return w; -} - static void binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); static void binder_free_thread(struct binder_thread *thread); @@ -1161,6 +1147,9 @@ static void binder_do_set_priority(struct task_struct *task, bool has_cap_nice; unsigned int policy = desired.sched_policy; + if (im_hwc(task) || task->prio < MAX_RT_PRIO) + return; + if (task->policy == policy && task->normal_prio == desired.prio) return; @@ -2892,6 +2881,19 @@ static bool binder_proc_transaction(struct binder_transaction *t, binder_transaction_priority(thread->task, t, node_prio, node->inherit_rt); binder_enqueue_thread_work_ilocked(thread, &t->work); +#ifdef CONFIG_UXCHAIN + if (!oneway && sysctl_uxchain_enabled && t->from && t->from->task + && t->from->task->static_ux) { + thread->task->dynamic_ux = 1; + thread->task->ux_depth = t->from->task->ux_depth + 1; + } + if (!oneway && sysctl_uxchain_enabled && + t->from && t->from->task && + t->from->task->dynamic_ux /*&& t->from->task->ux_depth < 2*/) { + thread->task->dynamic_ux = 1; + thread->task->ux_depth = t->from->task->ux_depth + 1; + } +#endif } else if (!pending_async) { binder_enqueue_work_ilocked(&t->work, &proc->todo); } else { @@ -2976,6 +2978,14 @@ static void binder_transaction(struct binder_proc *proc, int t_debug_id = atomic_inc_return(&binder_last_id); char *secctx = NULL; u32 secctx_sz = 0; +#ifdef CONFIG_OP_FREEZER + // add for op freeze manager + char buf_data[INTERFACETOKEN_BUFF_SIZE]; + size_t buf_data_size; + char buf[INTERFACETOKEN_BUFF_SIZE] = {0}; + int i = 0; + int j = 0; +#endif e = binder_transaction_log_add(&binder_transaction_log); e->debug_id = t_debug_id; @@ -3091,6 +3101,20 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_dead_binder; } + +#ifdef CONFIG_OP_FREEZER + // add for op freeze manager + if (!(tr->flags & TF_ONE_WAY) //report sync binder call + && target_proc + && (task_uid(target_proc->tsk).val > MIN_USERAPP_UID) + && (proc->pid != target_proc->pid) + && is_frozen_tg(target_proc->tsk)) { + op_freezer_report(SYNC_BINDER, + task_tgid_nr(proc->tsk), task_uid(target_proc->tsk).val, + "SYNC_BINDER", -1); + } +#endif + e->to_node = target_node->debug_id; if (security_binder_transaction(proc->tsk, target_proc->tsk) < 0) { @@ -3323,6 +3347,39 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_bad_offset; } + +#ifdef CONFIG_OP_FREEZER + // add for op freeze manager + if ((tr->flags & TF_ONE_WAY) //report async binder call + && target_proc + && (task_uid(target_proc->tsk).val > MIN_USERAPP_UID) + && (proc->pid != target_proc->pid) + && is_frozen_tg(target_proc->tsk)) { + buf_data_size = tr->data_size > INTERFACETOKEN_BUFF_SIZE ? + INTERFACETOKEN_BUFF_SIZE : tr->data_size; + if (!copy_from_user(buf_data, (char *)tr->data.ptr.buffer, buf_data_size)) { + //1.skip first PARCEL_OFFSET bytes (useless data) + //2.make sure the invalid address issue is not occurring(j =PARCEL_OFFSET+1, j+=2) + //3.java layer uses 2 bytes char. And only the first bytes has the data.(p+=2) + if (buf_data_size > PARCEL_OFFSET) { + char *p = (char *)(buf_data) + PARCEL_OFFSET; + + j = PARCEL_OFFSET + 1; + while (i < INTERFACETOKEN_BUFF_SIZE && j < buf_data_size && *p != '\0') { + buf[i++] = *p; + j += 2; + p += 2; + } + if (i == INTERFACETOKEN_BUFF_SIZE) + buf[i-1] = '\0'; + } + op_freezer_report(ASYNC_BINDER, + task_tgid_nr(proc->tsk), task_uid(target_proc->tsk).val, + buf, tr->code); + } + } +#endif + off_start_offset = ALIGN(tr->data_size, sizeof(void *)); buffer_offset = off_start_offset; off_end_offset = off_start_offset + tr->offsets_size; @@ -3330,6 +3387,11 @@ static void binder_transaction(struct binder_proc *proc, sg_buf_end_offset = sg_buf_offset + extra_buffers_size - ALIGN(secctx_sz, sizeof(u64)); off_min = 0; +#ifdef CONFIG_OPCHAIN + // morison.yan@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + binder_alloc_pass_binder_buffer(&target_proc->alloc, + t->buffer, tr->data_size); +#endif for (buffer_offset = off_start_offset; buffer_offset < off_end_offset; buffer_offset += sizeof(binder_size_t)) { struct binder_object_header *hdr; @@ -3519,6 +3581,12 @@ static void binder_transaction(struct binder_proc *proc, tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; t->work.type = BINDER_WORK_TRANSACTION; +#ifdef CONFIG_UXCHAIN + if (sysctl_uxchain_enabled && thread->task->dynamic_ux) { + thread->task->dynamic_ux = 0; + thread->task->ux_depth = 0; + } +#endif if (reply) { binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); @@ -4183,7 +4251,15 @@ static int binder_wait_for_work(struct binder_thread *thread, list_add(&thread->waiting_thread_node, &proc->waiting_threads); binder_inner_proc_unlock(proc); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17 add for stuck monitor */ + current->in_binder = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17 add for stuck monitor */ + current->in_binder = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ binder_inner_proc_lock(proc); list_del_init(&thread->waiting_thread_node); if (signal_pending(current)) { @@ -4476,6 +4552,18 @@ static int binder_thread_read(struct binder_proc *proc, trd->sender_pid = task_tgid_nr_ns(sender, task_active_pid_ns(current)); +#ifdef CONFIG_UXCHAIN + if (sysctl_uxchain_enabled && t_from && t_from->task && + t_from->task->static_ux) { + thread->task->dynamic_ux = 1; + thread->task->ux_depth = t_from->task->ux_depth + 1; + } + if (sysctl_uxchain_enabled && t_from && t_from->task && + t_from->task->dynamic_ux /*&& t->from->task->ux_depth < 2*/) { + thread->task->dynamic_ux = 1; + thread->task->ux_depth = t_from->task->ux_depth + 1; + } +#endif } else { trd->sender_pid = 0; } @@ -4573,13 +4661,17 @@ static void binder_release_work(struct binder_proc *proc, struct list_head *list) { struct binder_work *w; + enum binder_work_type wtype; while (1) { - w = binder_dequeue_work_head(proc, list); + binder_inner_proc_lock(proc); + w = binder_dequeue_work_head_ilocked(list); + wtype = w ? w->type : 0; + binder_inner_proc_unlock(proc); if (!w) return; - switch (w->type) { + switch (wtype) { case BINDER_WORK_TRANSACTION: { struct binder_transaction *t; @@ -4613,9 +4705,11 @@ static void binder_release_work(struct binder_proc *proc, kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; + case BINDER_WORK_NODE: + break; default: pr_err("unexpected work type, %d, not freed\n", - w->type); + wtype); break; } } @@ -5993,6 +6087,70 @@ int binder_state_show(struct seq_file *m, void *unused) return 0; } +#ifdef CONFIG_OP_FREEZER +// add for op freeze manager +static void op_freezer_check_uid_proc_status(struct binder_proc *proc) +{ + struct rb_node *n = NULL; + struct binder_thread *thread = NULL; + int uid = -1; + struct binder_transaction *btrans = NULL; + bool empty = true; + + //check binder_thread/transaction_stack/binder_proc ongoing transaction + binder_inner_proc_lock(proc); + for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { + thread = rb_entry(n, struct binder_thread, rb_node); + empty = binder_worklist_empty_ilocked(&thread->todo); + + if (thread->task != NULL) { + // has "todo" binder thread in worklist? + uid = task_uid(thread->task).val; + if (!empty) { + binder_inner_proc_unlock(proc); + op_freezer_report(FROZEN_TRANS, -1, uid, "FROZEN_TRANS_THREAD", -1); + return; + } + + // has transcation in transaction_stack? + btrans = thread->transaction_stack; + if (btrans) { + spin_lock(&btrans->lock); + if (btrans->to_thread == thread) { + // only report incoming binder call + spin_unlock(&btrans->lock); + binder_inner_proc_unlock(proc); + op_freezer_report(FROZEN_TRANS, -1, uid, "FROZEN_TRANS_STACK", -1); + return; + } + spin_unlock(&btrans->lock); + } + } + } + + // has "todo" binder proc in worklist + empty = binder_worklist_empty_ilocked(&proc->todo); + if (proc->tsk != NULL && !empty) { + uid = task_uid(proc->tsk).val; + binder_inner_proc_unlock(proc); + op_freezer_report(FROZEN_TRANS, -1, uid, "FROZEN_TRANS_PROC", -1); + return; + } + binder_inner_proc_unlock(proc); +} + +void op_freezer_check_frozen_transcation(uid_t uid) +{ + struct binder_proc *proc; + + mutex_lock(&binder_procs_lock); + hlist_for_each_entry(proc, &binder_procs, proc_node) { + if (proc != NULL && (task_uid(proc->tsk).val == uid)) + op_freezer_check_uid_proc_status(proc); + } + mutex_unlock(&binder_procs_lock); +} +#endif int binder_stats_show(struct seq_file *m, void *unused) { struct binder_proc *proc; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index deb37977cab9c12210e1afcced3768c843fed9fe..b7e69a543130e6249eb87b0deff4d08a34fb14fc 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -33,6 +33,14 @@ #include #include "binder_alloc.h" #include "binder_trace.h" +#ifdef CONFIG_OPCHAIN +// morison.yan@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +#include +#endif +#ifdef CONFIG_OP_FREEZER +// add for op freeze manager +#include +#endif struct list_lru binder_alloc_lru; @@ -362,6 +370,10 @@ static struct binder_buffer *binder_alloc_new_buf_locked( void __user *end_page_addr; size_t size, data_offsets_size; int ret; +#ifdef CONFIG_OP_FREEZER + // add for op freeze manager + struct task_struct *p = NULL; +#endif if (!binder_alloc_get_vma(alloc)) { binder_alloc_debug(BINDER_DEBUG_USER_ERROR, @@ -386,6 +398,23 @@ static struct binder_buffer *binder_alloc_new_buf_locked( alloc->pid, extra_buffers_size); return ERR_PTR(-EINVAL); } + +#ifdef CONFIG_OP_FREEZER + // add for op freeze manager + if (is_async + && (alloc->free_async_space < 3 * (size + sizeof(struct binder_buffer)) + || (alloc->free_async_space < ((alloc->buffer_size / 2) * 9 / 10)))) { + rcu_read_lock(); + p = find_task_by_vpid(alloc->pid); + rcu_read_unlock(); + if (p != NULL && is_frozen_tg(p)) { + op_freezer_report(ASYNC_BINDER, + task_tgid_nr(current), task_uid(p).val, + "free_buffer_full", -1); + } + } +#endif + if (is_async && alloc->free_async_space < size + sizeof(struct binder_buffer)) { binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, @@ -1134,7 +1163,23 @@ binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, } return 0; } - +#ifdef CONFIG_OPCHAIN +// morison.yan@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +void binder_alloc_pass_binder_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t buffer_size) +{ + struct page *page; + pgoff_t pgoff; + void *kptr; + + page = binder_alloc_get_page(alloc, buffer, + 0, &pgoff); + kptr = kmap_atomic(page) + pgoff; + opc_binder_pass(buffer_size, kptr, 1); + kunmap_atomic(kptr); +} +#endif static void binder_alloc_do_buffer_copy(struct binder_alloc *alloc, bool to_buffer, struct binder_buffer *buffer, diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index b60d161b7a7ae98c412ca9c075af530da4d67ee9..39fa6ad27d1a8c071413e64a823f4254dc8444e9 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -160,6 +160,12 @@ binder_alloc_get_free_async_space(struct binder_alloc *alloc) mutex_unlock(&alloc->mutex); return free_async_space; } +#ifdef CONFIG_OPCHAIN +// morison.yan@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +void binder_alloc_pass_binder_buffer(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t buffer_size); +#endif unsigned long binder_alloc_copy_user_to_buffer(struct binder_alloc *alloc, diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 5ad1ebf794b2796c6b25d813535c75de87691c33..3da830b0b81f913360d4341fd981078c61c9bc4f 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "power.h" @@ -78,6 +80,10 @@ static struct wakeup_source deleted_ws = { static DEFINE_IDA(wakeup_ida); +#define WORK_TIMEOUT (10*1000) +static void ws_printk(struct work_struct *work); +static DECLARE_DELAYED_WORK(ws_printk_work, ws_printk); + /** * wakeup_source_create - Create a struct wakeup_source object. * @name: Name of the new wakeup source. @@ -859,7 +865,7 @@ void pm_print_active_wakeup_sources(void) srcuidx = srcu_read_lock(&wakeup_srcu); list_for_each_entry_rcu(ws, &wakeup_sources, entry) { if (ws->active) { - pr_debug("active wakeup source: %s\n", ws->name); + pr_info("active wakeup source: %s\n", ws->name); active = 1; } else if (!active && (!last_activity_ws || @@ -870,12 +876,30 @@ void pm_print_active_wakeup_sources(void) } if (!active && last_activity_ws) - pr_debug("last active wakeup source: %s\n", + pr_info("last active wakeup source: %s\n", last_activity_ws->name); srcu_read_unlock(&wakeup_srcu, srcuidx); } EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources); +static void ws_printk(struct work_struct *work) +{ + pm_print_active_wakeup_sources(); + queue_delayed_work(system_freezable_wq, + &ws_printk_work, msecs_to_jiffies(WORK_TIMEOUT)); +} + +void pm_print_active_wakeup_sources_queue(bool on) +{ + if (on) { + queue_delayed_work(system_freezable_wq, &ws_printk_work, + msecs_to_jiffies(WORK_TIMEOUT)); + } else { + cancel_delayed_work(&ws_printk_work); + } +} +EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources_queue); + /** * pm_wakeup_pending - Check if power transition in progress should be aborted. * @@ -939,6 +963,7 @@ void pm_system_irq_wakeup(unsigned int irq_number) else if (desc->action && desc->action->name) name = desc->action->name; + log_wakeup_reason(irq_number); pr_warn("%s: %d triggered %s\n", __func__, irq_number, name); diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 3053aca7cd8070fc5dbf59d590b008b610e49495..7a1a8f67b2933cf2c8109386bf1bc17044254a86 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -216,6 +216,9 @@ void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd) db = ring->iommu_base + (ring->wp - ring->base); *ring->ctxt_wp = db; mhi_write_db(mhi_cntrl, ring->db_addr, db); + + /* smp update */ + smp_wmb(); } void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/devices/mhi_satellite.c b/drivers/bus/mhi/devices/mhi_satellite.c index 24621475a26867ea68a6e04c369740a050bbae94..b32e1b2ad04162ce04925ac627c66e011a73df37 100644 --- a/drivers/bus/mhi/devices/mhi_satellite.c +++ b/drivers/bus/mhi/devices/mhi_satellite.c @@ -979,7 +979,7 @@ static void mhi_sat_dev_remove(struct mhi_device *mhi_dev) sat_cntrl->state = SAT_ERROR; spin_unlock_irq(&sat_cntrl->state_lock); - if (send_sys_err) + if (send_sys_err && !!subsys->rpdev) mhi_sat_send_sys_err(sat_cntrl); /* exit if some devices are still present */ diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index d234c4238cbf08b3b853794fde344526923357d9..87ac06fb4669937c68c17bf85d8e3cb97cf59f41 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -1815,7 +1815,7 @@ static int diag_switch_logging_proc(struct diag_logging_mode_param_t *param, DIAG_LOG(DIAG_DEBUG_USERSPACE, "not switching modes c: %d n: %d\n", curr_mode, new_mode); - return 0; + continue; } diag_ws_reset(DIAG_WS_MUX); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 53cfe574d8d4b647f378e602c44e663e401b772e..a94f290cec082e24489b6b76c76bbff11a7adb54 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -60,7 +60,7 @@ static DEFINE_MUTEX(misc_mtx); /* * Assigned numbers, used for dynamic minors */ -#define DYNAMIC_MINORS 64 /* like dynamic majors */ +#define DYNAMIC_MINORS 128 /* like dynamic majors */ static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS); #ifdef CONFIG_PROC_FS diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 5b463b486ec00b8952792ae32571db877fbfc484..c84a30f21c6acf75da5b60d53b667f0a75ffa05b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -28,8 +28,12 @@ #include #include #include +#include +#include +#include #include "clk.h" +#include "../soc/qcom/rpmh_master_stat.h" static DEFINE_SPINLOCK(enable_lock); static DEFINE_MUTEX(prepare_lock); @@ -40,6 +44,8 @@ static struct task_struct *enable_owner; static int prepare_refcnt; static int enable_refcnt; +static unsigned int debug_suspend_flag; + static HLIST_HEAD(clk_root_list); static HLIST_HEAD(clk_orphan_list); static LIST_HEAD(clk_notifier_list); @@ -99,10 +105,8 @@ struct clk_core { struct hlist_node child_node; struct hlist_head clks; unsigned int notifier_count; -#ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct hlist_node debug_node; -#endif struct kref ref; struct clk_vdd_class *vdd_class; int vdd_class_vote; @@ -3213,10 +3217,10 @@ EXPORT_SYMBOL_GPL(clk_set_flags); /*** debugfs support ***/ -#ifdef CONFIG_DEBUG_FS #include static struct dentry *rootdir; +static struct proc_dir_entry *procdir; static int inited = 0; static u32 debug_suspend; static DEFINE_MUTEX(clk_debug_lock); @@ -3940,13 +3944,48 @@ static void clk_debug_unregister(struct clk_core *core) */ void clock_debug_print_enabled(void) { - if (likely(!debug_suspend)) - return; - - clock_debug_print_enabled_clocks(NULL); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + if (likely(!debug_suspend)) + return; + clock_debug_print_enabled_clocks(NULL); + rpmhstats_statistics(); + } else { + if (debug_suspend_flag == 1) { + pr_info("Enable debug_suspend mode: clk list."); + clock_debug_print_enabled_clocks(NULL); + } else if (debug_suspend_flag == 2) { + pr_info("Enable debug_suspend mode: RPMh."); + rpmhstats_statistics(); + } else if (debug_suspend_flag == 3) { + pr_info("Enable debug_suspend mode: Both clk and RPMh."); + clock_debug_print_enabled_clocks(NULL); + rpmhstats_statistics(); + } else + return; + } } + EXPORT_SYMBOL_GPL(clock_debug_print_enabled); +static ssize_t debug_suspend_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, sizeof(buf), "%d\n", debug_suspend_flag); +} + +static ssize_t debug_suspend_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + if (kstrtouint(buf, 10, &debug_suspend_flag)) + return -EINVAL; + + pr_info("debug_suspend flag: %d", debug_suspend_flag); + return count; +} + +static struct kobj_attribute debug_suspend_attribute = +__ATTR(debug_suspend, 0644, debug_suspend_show, debug_suspend_store); + /** * clk_debug_init - lazily populate the debugfs clk directory * @@ -3960,74 +3999,171 @@ static int __init clk_debug_init(void) { struct clk_core *core; struct dentry *d; + int ret; - rootdir = debugfs_create_dir("clk", NULL); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + rootdir = debugfs_create_dir("clk", NULL); - if (!rootdir) - return -ENOMEM; + if (!rootdir) + return -ENOMEM; - d = debugfs_create_file("clk_summary", 0444, rootdir, &all_lists, - &clk_summary_fops); - if (!d) - return -ENOMEM; + d = debugfs_create_file("clk_summary", 0444, rootdir, &all_lists, + &clk_summary_fops); + if (!d) + return -ENOMEM; - d = debugfs_create_file("clk_dump", 0444, rootdir, &all_lists, - &clk_dump_fops); - if (!d) - return -ENOMEM; + d = debugfs_create_file("clk_dump", 0444, rootdir, &all_lists, + &clk_dump_fops); + if (!d) + return -ENOMEM; - d = debugfs_create_file("clk_orphan_summary", 0444, rootdir, - &orphan_list, &clk_summary_fops); - if (!d) - return -ENOMEM; + d = debugfs_create_file("clk_orphan_summary", 0444, rootdir, + &orphan_list, &clk_summary_fops); + if (!d) + return -ENOMEM; - d = debugfs_create_file("clk_orphan_dump", 0444, rootdir, - &orphan_list, &clk_dump_fops); - if (!d) - return -ENOMEM; + d = debugfs_create_file("clk_orphan_dump", 0444, rootdir, + &orphan_list, &clk_dump_fops); + if (!d) + return -ENOMEM; - d = debugfs_create_file("clk_enabled_list", 0444, rootdir, - &clk_debug_list, &clk_enabled_list_fops); - if (!d) - return -ENOMEM; + d = debugfs_create_file("clk_enabled_list", 0444, rootdir, + &clk_debug_list, &clk_enabled_list_fops); + if (!d) + return -ENOMEM; - d = debugfs_create_u32("debug_suspend", 0644, rootdir, &debug_suspend); - if (!d) - return -ENOMEM; + d = debugfs_create_u32("debug_suspend", 0644, rootdir, &debug_suspend); + if (!d) + return -ENOMEM; - d = debugfs_create_file("trace_clocks", 0444, rootdir, &all_lists, - &clk_state_fops); - if (!d) - return -ENOMEM; + d = debugfs_create_file("trace_clocks", 0444, rootdir, &all_lists, + &clk_state_fops); + if (!d) + return -ENOMEM; - mutex_lock(&clk_debug_lock); - hlist_for_each_entry(core, &clk_debug_list, debug_node) - clk_debug_create_one(core, rootdir); + mutex_lock(&clk_debug_lock); + hlist_for_each_entry(core, &clk_debug_list, debug_node) + clk_debug_create_one(core, rootdir); - inited = 1; - mutex_unlock(&clk_debug_lock); + inited = 1; + mutex_unlock(&clk_debug_lock); + } + + ret = sysfs_create_file(power_kobj, &debug_suspend_attribute.attr); + if (ret < 0) + pr_err("Failed to create debug_suspend sysfs."); + + procdir = proc_mkdir("power", NULL); + proc_create("clk_enabled_list", 0444, procdir, &clk_enabled_list_fops); return 0; } late_initcall(clk_debug_init); -#else -static inline void clk_debug_register(struct clk_core *core) { } -static inline void clk_debug_reparent(struct clk_core *core, - struct clk_core *new_parent) + +static struct proc_dir_entry *proc_clkdir; + +static int proc_clock_rate_show(struct seq_file *file, void *data) { + struct clk_core *core = PDE_DATA(file_inode(file->file)); + u64 val; + + clk_prepare_lock(); + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, true); + + val = clk_get_rate(core->hw->clk); + + seq_printf(file, "%d\n", val); + + if (core->ops->bus_vote) + core->ops->bus_vote(core->hw, false); + clk_prepare_unlock(); + + return 0; } -static inline void clk_debug_unregister(struct clk_core *core) + +DEFINE_SHOW_ATTRIBUTE(proc_clock_rate); + +static int proc_clk_enable_count_show(struct seq_file *file, void *data) { + struct clk_core *core = PDE_DATA(file_inode(file->file)); + + seq_printf(file, "%d\n", core->enable_count); + + return 0; } -void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f) +DEFINE_SHOW_ATTRIBUTE(proc_clk_enable_count); + +static int proc_list_rates_show(struct seq_file *s, void *unused) { + struct clk_core *core = PDE_DATA(file_inode(s->file)); + int level = 0, i = 0; + unsigned long rate, rate_max = 0; + + /* Find max frequency supported within voltage constraints. */ + if (!core->vdd_class) { + rate_max = ULONG_MAX; + } else { + for (level = 0; level < core->num_rate_max; level++) + if (core->rate_max[level]) + rate_max = core->rate_max[level]; + } + + /* + * List supported frequencies <= rate_max. Higher frequencies may + * appear in the frequency table, but are not valid and should not + * be listed. + */ + while (!IS_ERR_VALUE(rate = + core->ops->list_rate(core->hw, i++, rate_max))) { + if (rate <= 0) + break; + if (rate <= rate_max) + seq_printf(s, "%lu\n", rate); + } + + return 0; } -void clock_debug_print_enabled(void) +static int proc_list_rates_open(struct inode *inode, struct file *file) { + return single_open(file, proc_list_rates_show, inode->i_private); +} + +static const struct file_operations proc_list_rates_fops = { + .open = proc_list_rates_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int proc_add_clk(struct clk_core *core) +{ + struct proc_dir_entry *dentry; + + if (!proc_clkdir) { + proc_clkdir = proc_mkdir("clk", NULL); + if (!proc_clkdir) + return -ENOMEM; + } + + dentry = proc_mkdir(core->name, proc_clkdir); + if (!dentry) + goto out; + + proc_create_data("clk_rate", 0444, dentry, &proc_clock_rate_fops, core); + + if (core->ops->list_rate) { + proc_create_data("clk_list_rates", + 0444, dentry, &proc_list_rates_fops, core); + } + + proc_create_data("clk_enable_count", 0444, dentry, + &proc_clk_enable_count_fops, core); +out: + return 0; } -#endif /** * __clk_core_init - initialize the data structures in a struct clk_core @@ -4284,6 +4420,9 @@ static int __clk_core_init(struct clk_core *core) unlock: clk_prepare_unlock(); + if (!strncmp("gcc_ufs_phy_axi_clk_src", core->name, 23)) + proc_add_clk(core); + if (!ret) clk_debug_register(core); diff --git a/drivers/clk/qcom/camcc-lagoon.c b/drivers/clk/qcom/camcc-lagoon.c index 7ec55d0a8d5e519e0bfc74e7bb77c57a6dfdb510..4f0c84ef942492ebcbccfb6371e0e8b8866a87b7 100644 --- a/drivers/clk/qcom/camcc-lagoon.c +++ b/drivers/clk/qcom/camcc-lagoon.c @@ -184,7 +184,7 @@ static const struct alpha_pll_config cam_cc_pll0_config = { .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00002067, .test_ctl_val = 0x40000000, - .test_ctl_hi_val = 0x00000000, + .test_ctl_hi_val = 0x00000002, .user_ctl_val = 0x00000101, .user_ctl_hi_val = 0x00004805, }; @@ -364,9 +364,9 @@ static const struct alpha_pll_config cam_cc_pll3_config = { .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00002067, .test_ctl_val = 0x40000000, - .test_ctl_hi_val = 0x00000000, + .test_ctl_hi_val = 0x00000002, .user_ctl_val = 0x00000001, - .user_ctl_hi_val = 0x00004805, + .user_ctl_hi_val = 0x00014805, }; static struct clk_alpha_pll cam_cc_pll3 = { diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c index e7af0538dc0422c3613c874e4db035e3a326e6fc..f2413c59f1411e132f5c8c5819c35bfbe1aeaf0e 100644 --- a/drivers/clk/qcom/clk-debug.c +++ b/drivers/clk/qcom/clk-debug.c @@ -282,6 +282,50 @@ static int clk_debug_measure_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get, NULL, "%lld\n"); +#if defined(CONFIG_CONTROL_CENTER) || defined(CONFIG_HOUSTON) +extern int get_only_mccc_hw(struct clk_hw **hwptr); + +void clk_get_ddr_freq(u64 *val) +{ + struct clk_hw *hw = NULL; + struct clk_hw *parent; + struct clk_debug_mux *mux; + int ret = 0; + u32 regval; + + ret = get_only_mccc_hw(&hw); + if (ret) { + pr_err("Error finding mccc clk_hw.\n"); + return; + } + + mutex_lock(&clk_debug_lock); + + ret = clk_find_and_set_parent(measure, hw); + if (!ret) { + parent = clk_hw_get_parent(measure); + if (!parent) { + mutex_unlock(&clk_debug_lock); + return; + } + mux = to_clk_measure(parent); + regmap_read(mux->regmap, mux->period_offset, ®val); + if (!regval) { + pr_err("Error reading mccc period register, ret = %d\n", + ret); + mutex_unlock(&clk_debug_lock); + return; + } + *val = 1000000000000UL; + do_div(*val, regval); + } else { + pr_err("Failed to set the debug mux's parent.\n"); + } + + mutex_unlock(&clk_debug_lock); +} +#endif + static int clk_debug_read_period(void *data, u64 *val) { struct clk_hw *hw = data; diff --git a/drivers/clk/qcom/debugcc-lito.c b/drivers/clk/qcom/debugcc-lito.c index 2502d2001d43118e21461538bef4b492371a5510..4b3d0fbaca207d273322c6870c21321bae0eefae 100644 --- a/drivers/clk/qcom/debugcc-lito.c +++ b/drivers/clk/qcom/debugcc-lito.c @@ -713,6 +713,18 @@ static struct clk_dummy measure_only_mccc_clk = { }, }; +#if defined(CONFIG_CONTROL_CENTER) || defined(CONFIG_HOUSTON) +int get_only_mccc_hw(struct clk_hw **hwptr) +{ + if (unlikely(!&(measure_only_mccc_clk.hw))) { + *hwptr = NULL; + return -EINVAL; + } + *hwptr = &(measure_only_mccc_clk.hw); + return 0; +} +#endif + static struct clk_dummy measure_only_cnoc_clk = { .rrate = 1000, .hw.init = &(struct clk_init_data){ @@ -830,7 +842,9 @@ static int clk_debug_lito_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to get xo clock\n"); return PTR_ERR(clk); } - +#if defined(CONFIG_CONTROL_CENTER) || defined(CONFIG_HOUSTON) + dev_err(&pdev->dev, "houston or control center\n"); +#endif debug_mux_priv.cxo = clk; for (i = 0; i < ARRAY_SIZE(mux_list); i++) { diff --git a/drivers/clk/qcom/npucc-lagoon.c b/drivers/clk/qcom/npucc-lagoon.c index bfef188865d3f7bf2e030a7c32ab318c9b5e20a1..60d9af5e928050597a388a1bc289c34e34a28b98 100644 --- a/drivers/clk/qcom/npucc-lagoon.c +++ b/drivers/clk/qcom/npucc-lagoon.c @@ -145,11 +145,11 @@ static struct clk_alpha_pll npu_cc_pll0 = { }, }; -/* 300MHz Configuration */ +/* 1500MHz Configuration */ static struct alpha_pll_config npu_cc_pll1_config = { - .l = 0xF, + .l = 0x4E, .cal_l = 0x33, - .alpha = 0xA000, + .alpha = 0x2000, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00002067, .test_ctl_val = 0x40000000, @@ -181,11 +181,11 @@ static struct clk_alpha_pll npu_cc_pll1 = { }, }; -/* 250MHz Configuration */ +/* 600MHz Configuration */ static struct alpha_pll_config npu_q6ss_pll_config = { - .l = 0xD, - .cal_l = 0x3F, - .alpha = 0x555, + .l = 0x1F, + .cal_l = 0x1E, + .alpha = 0x4000, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00002067, .test_ctl_val = 0x40000000, diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index ebc5c13d8ad0e36d1abda3009e9e011e6d2ae954..36c3da72de50dfd2541bbcc207662c16e9ad121a 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -895,7 +895,7 @@ static void arch_counter_set_user_access(void) */ if (arch_timer_this_cpu_has_cntvct_wa() || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER_VCT_ACCESS)) - pr_info("CPU%d: Trapping CNTVCT access\n", smp_processor_id()); + pr_debug("CPU%d: Trapping CNTVCT access\n", smp_processor_id()); else cntkctl |= ARCH_TIMER_USR_VCT_ACCESS_EN; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b050316480fc4fd814bb44f275ca3dde202d77c7..06cc1d06971d5645c5ade91aa77ed4112a418438 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -33,7 +33,13 @@ #include #include +#include #include +// 2020/04/01, add for pccore CONFIG_PCCORE +#include +#include +#define GOLD_CPU_NUMBER 6 +#define GOLD_PLUS_CPU_NUMBER 7 static LIST_HEAD(cpufreq_policy_list); @@ -60,6 +66,29 @@ static LIST_HEAD(cpufreq_governor_list); #define for_each_governor(__governor) \ list_for_each_entry(__governor, &cpufreq_governor_list, governor_list) +struct qos_request_value { + bool flag; + unsigned int max_cpufreq; + unsigned int min_cpufreq; +}; +static struct qos_request_value c0_qos_request_value = { + .flag = false, + .max_cpufreq = INT_MAX, + .min_cpufreq = MIN_CPUFREQ, +}; +static struct qos_request_value c1_qos_request_value = { + .flag = false, + .max_cpufreq = INT_MAX, + .min_cpufreq = MIN_CPUFREQ, +}; +static struct qos_request_value c2_qos_request_value = { + .flag = false, + .max_cpufreq = INT_MAX, + .min_cpufreq = MIN_CPUFREQ, +}; +unsigned int cluster1_first_cpu = GOLD_CPU_NUMBER; +unsigned int cluster2_first_cpu = GOLD_PLUS_CPU_NUMBER; + /** * The "cpufreq driver" - the arch- or hardware-dependent low * level driver of CPUFreq support, and its spinlock. This lock @@ -357,8 +386,8 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy, srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); } - - cpufreq_stats_record_transition(policy, freqs->new); + if (freqs->new != policy->cur) + cpufreq_stats_record_transition(policy, freqs->new); cpufreq_times_record_transition(policy, freqs->new); policy->cur = freqs->new; } @@ -507,15 +536,41 @@ EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch); unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy, unsigned int target_freq) { + struct qos_request_value *qos; +// 2020/04/01, add for pccore CONFIG_PCCORE +#ifdef CONFIG_PCCORE + unsigned int min_target; +#endif +#ifdef CONFIG_CONTROL_CENTER + if (likely(policy->cc_enable)) + target_freq = clamp_val(target_freq, policy->cc_min, policy->cc_max); +#endif + target_freq = clamp_val(target_freq, policy->min, policy->max); +// 2020/04/01, add for pccore CONFIG_PCCORE +#ifdef CONFIG_PCCORE + min_target = clamp_val(policy->min, policy->min, policy->max); + policy->min_idx = cpufreq_frequency_table_target(policy, min_target, CPUFREQ_RELATION_L); +#endif + if (policy->cpu >= cluster2_first_cpu) + qos = &c2_qos_request_value; + else { + qos = policy->cpu >= cluster1_first_cpu ? + &c1_qos_request_value : &c0_qos_request_value; + } + target_freq = clamp_val(target_freq, qos->min_cpufreq, + qos->max_cpufreq); policy->cached_target_freq = target_freq; if (cpufreq_driver->target_index) { int idx; - +//2020/03/27, add for pccore CONFIG_PCCORE idx = cpufreq_frequency_table_target(policy, target_freq, - CPUFREQ_RELATION_L); + (get_op_select_freq_enable() && + (ht_pcc_alwayson() || !ccdm_any_hint())) ? CPUFREQ_RELATION_OP : CPUFREQ_RELATION_L); policy->cached_resolved_idx = idx; +//2020/03/27, add for pccore CONFIG_PCCORE + trace_cpu_frequency_select(target_freq, policy->freq_table[idx].frequency, idx, policy->cpu, 1); return policy->freq_table[idx].frequency; } @@ -905,6 +960,18 @@ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) return sprintf(buf, "%u\n", policy->cpuinfo.max_freq); } +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ +static ssize_t show_freq_change_info(struct cpufreq_policy *policy, char *buf) +{ + ssize_t i = 0; + + i += snprintf(buf, 100, "policy->org_max = %u,policy->change_comm = %s\n", + policy->org_max, policy->change_comm); + return i; +} +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400); cpufreq_freq_attr_ro(cpuinfo_min_freq); cpufreq_freq_attr_ro(cpuinfo_max_freq); @@ -915,6 +982,10 @@ cpufreq_freq_attr_ro(scaling_cur_freq); cpufreq_freq_attr_ro(bios_limit); cpufreq_freq_attr_ro(related_cpus); cpufreq_freq_attr_ro(affected_cpus); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ +cpufreq_freq_attr_ro(freq_change_info); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ cpufreq_freq_attr_rw(scaling_min_freq); cpufreq_freq_attr_rw(scaling_max_freq); cpufreq_freq_attr_rw(scaling_governor); @@ -932,6 +1003,10 @@ static struct attribute *default_attrs[] = { &scaling_driver.attr, &scaling_available_governors.attr, &scaling_setspeed.attr, +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-05-31, add for stuck monitor*/ + &freq_change_info.attr, +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ NULL }; @@ -1152,6 +1227,9 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) INIT_LIST_HEAD(&policy->policy_list); init_rwsem(&policy->rwsem); spin_lock_init(&policy->transition_lock); +#ifdef CONFIG_CONTROL_CENTER + spin_lock_init(&policy->cc_lock); +#endif init_waitqueue_head(&policy->transition_wait); init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); @@ -1282,6 +1360,12 @@ static int cpufreq_online(unsigned int cpu) } else { policy->min = policy->user_policy.min; policy->max = policy->user_policy.max; +#ifdef CONFIG_CONTROL_CENTER + spin_lock(&policy->cc_lock); + policy->cc_min = policy->min; + policy->cc_max = policy->max; + spin_unlock(&policy->cc_lock); +#endif } if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { @@ -1906,6 +1990,8 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, target_freq = clamp_val(target_freq, policy->min, policy->max); ret = cpufreq_driver->fast_switch(policy, target_freq); +//2020/03/27, add for pccore CONFIG_PCCORE + trace_cpu_frequency_select(target_freq, ret, -2, policy->cpu, 2); if (ret) { cpufreq_times_record_transition(policy, ret); cpufreq_stats_record_transition(policy, ret); @@ -2008,6 +2094,10 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, if (cpufreq_disabled()) return -ENODEV; +#ifdef CONFIG_CONTROL_CENTER + if (likely(policy->cc_enable)) + target_freq = clamp_val(target_freq, policy->cc_min, policy->cc_max); +#endif /* Make sure that target_freq is within supported range */ target_freq = clamp_val(target_freq, policy->min, policy->max); @@ -2248,6 +2338,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, pr_debug("setting new policy for CPU %u: %u - %u kHz\n", new_policy->cpu, new_policy->min, new_policy->max); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-06-23, add for stuck monitor*/ + policy->org_max = new_policy->max; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo)); /* @@ -2284,8 +2379,18 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, policy->min = new_policy->min; policy->max = new_policy->max; +#ifdef CONFIG_CONTROL_CENTER + spin_lock(&policy->cc_lock); + policy->cc_min = policy->min; + policy->cc_max = policy->max; + spin_unlock(&policy->cc_lock); +#endif trace_cpu_frequency_limits(policy); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-06-23, add for stuck monitor*/ + strlcpy(policy->change_comm, current->comm, TASK_COMM_LEN); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ arch_set_max_freq_scale(policy->cpus, policy->max); policy->cached_target_freq = UINT_MAX; @@ -2648,3 +2753,294 @@ static int __init cpufreq_core_init(void) } module_param(off, int, 0444); core_initcall(cpufreq_core_init); + +static int get_c0_available_cpufreq(struct cpufreq_policy *policy) +{ + int max_cpufreq_index = -1, min_cpufreq_index = -1; + int max_index = -1; + int index_max = 0, index_min = 0; + struct cpufreq_frequency_table *table, *pos; + + table = policy->freq_table; + if (!table) { + pr_err("cpufreq:Failed to get frequency table for CPU%u\n", 0); + return -EINVAL; + } + + max_cpufreq_index = (unsigned int)pm_qos_request(PM_QOS_C0_CPUFREQ_MAX); + min_cpufreq_index = (unsigned int)pm_qos_request(PM_QOS_C0_CPUFREQ_MIN); + + /* you can limit the min cpufreq*/ + if (min_cpufreq_index > max_cpufreq_index) + max_cpufreq_index = min_cpufreq_index; + + /* get the available cpufreq + * lock for the max available cpufreq + */ + cpufreq_for_each_valid_entry(pos, table) { + max_index = pos - table; + } + if (max_cpufreq_index & MASK_CPUFREQ) { + index_max = MAX_CPUFREQ - max_cpufreq_index; + if (index_max > max_index) + index_max = 0; + index_max = max_index - index_max; + } else { + if (max_cpufreq_index > max_index) + index_max = max_index; + } + if (min_cpufreq_index & MASK_CPUFREQ) { + index_min = MAX_CPUFREQ - min_cpufreq_index; + if (index_min > max_index) + index_min = 0; + index_min = max_index - index_min; + } else { + if (min_cpufreq_index > max_index) + index_min = max_index; + } + c0_qos_request_value.max_cpufreq = table[index_max].frequency; + c0_qos_request_value.min_cpufreq = table[index_min].frequency; + pr_debug("c0::: m:%d, ii:%d-, mm:%d-", max_index, index_min, index_max); + + return 0; +} + +static int get_c1_available_cpufreq(struct cpufreq_policy *policy) +{ + int max_cpufreq_index = -1, min_cpufreq_index = -1; + int max_index = -1; + int index_max = 0, index_min = 0; + struct cpufreq_frequency_table *table, *pos; + + table = policy->freq_table; + if (!table) { + pr_err("cpufreq: Failed to get frequency table for CPU\n"); + return -EINVAL; + } + + max_cpufreq_index = (unsigned int)pm_qos_request(PM_QOS_C1_CPUFREQ_MAX); + min_cpufreq_index = (unsigned int)pm_qos_request(PM_QOS_C1_CPUFREQ_MIN); + + /* you can limit the min cpufreq*/ + if (min_cpufreq_index > max_cpufreq_index) + max_cpufreq_index = min_cpufreq_index; + + /* get the available cpufreq + * lock for the max available cpufreq + */ + cpufreq_for_each_valid_entry(pos, table) { + max_index = pos - table; + } + + /* add limits */ + if (max_cpufreq_index & MASK_CPUFREQ) { + index_max = MAX_CPUFREQ - max_cpufreq_index; + if (index_max > max_index) + index_max = 0; + index_max = max_index - index_max; + } else { + if (max_cpufreq_index > max_index) + index_max = max_index; + } + if (min_cpufreq_index & MASK_CPUFREQ) { + index_min = MAX_CPUFREQ - min_cpufreq_index; + if (index_min > max_index) + index_min = 0; + index_min = max_index - index_min; + } else { + if (min_cpufreq_index > max_index) + index_min = max_index; + } + c1_qos_request_value.max_cpufreq = table[index_max].frequency; + c1_qos_request_value.min_cpufreq = table[index_min].frequency; + pr_debug("c1::: m:%d, ii:%d-, mm:%d-", max_index, index_min, index_max); + + return 0; +} + +static int get_c2_available_cpufreq(struct cpufreq_policy *policy) +{ + int max_cpufreq_index = -1, min_cpufreq_index = -1; + int max_index = -1; + int index_max = 0, index_min = 0; + struct cpufreq_frequency_table *table, *pos; + + table = policy->freq_table; + if (!table) { + pr_err("cpufreq: Failed to get frequency table for CPU\n"); + return -EINVAL; + } + + max_cpufreq_index = (unsigned int)pm_qos_request(PM_QOS_C2_CPUFREQ_MAX); + min_cpufreq_index = (unsigned int)pm_qos_request(PM_QOS_C2_CPUFREQ_MIN); + + /* you can limit the min cpufreq*/ + if (min_cpufreq_index > max_cpufreq_index) + max_cpufreq_index = min_cpufreq_index; + + /* get the available cpufreq + * lock for the max available cpufreq + */ + cpufreq_for_each_valid_entry(pos, table) { + max_index = pos - table; + } + + /* add limits */ + if (max_cpufreq_index & MASK_CPUFREQ) { + index_max = MAX_CPUFREQ - max_cpufreq_index; + if (index_max > max_index) + index_max = 0; + index_max = max_index - index_max; + } else { + if (max_cpufreq_index > max_index) + index_max = max_index; + } + if (min_cpufreq_index & MASK_CPUFREQ) { + index_min = MAX_CPUFREQ - min_cpufreq_index; + if (index_min > max_index) + index_min = 0; + index_min = max_index - index_min; + } else { + if (min_cpufreq_index > max_index) + index_min = max_index; + } + c2_qos_request_value.max_cpufreq = table[index_max].frequency; + c2_qos_request_value.min_cpufreq = table[index_min].frequency; + pr_debug("c2::: m:%d, ii:%d-, mm:%d-", max_index, index_min, index_max); + + return 0; +} + +static int c0_cpufreq_qos_handler(struct notifier_block *b, + unsigned long val, void *v) +{ + struct cpufreq_policy *policy; + int ret = -1; + unsigned int freq; + + policy = cpufreq_cpu_get(0); + + if (!policy) + return NOTIFY_BAD; + + if (!policy->governor) { + cpufreq_cpu_put(policy); + return NOTIFY_BAD; + } + + if (strcmp(policy->governor->name, "schedutil")) { + cpufreq_cpu_put(policy); + return NOTIFY_OK; + } + + ret = get_c0_available_cpufreq(policy); + if (ret) { + cpufreq_cpu_put(policy); + return NOTIFY_BAD; + } + freq = cpufreq_driver_resolve_freq(policy, + c0_qos_request_value.min_cpufreq); + cpufreq_driver_fast_switch(policy, freq); + + cpufreq_cpu_put(policy); + return NOTIFY_OK; +} + +static struct notifier_block c0_cpufreq_qos_notifier = { + .notifier_call = c0_cpufreq_qos_handler, +}; + +static int c1_cpufreq_qos_handler(struct notifier_block *b, + unsigned long val, void *v) +{ + struct cpufreq_policy *policy; + int ret = -1; + unsigned int freq; + + policy = cpufreq_cpu_get(cluster1_first_cpu); + + if (!policy) + return NOTIFY_BAD; + + if (!policy->governor) { + cpufreq_cpu_put(policy); + return NOTIFY_BAD; + } + + if (strcmp(policy->governor->name, "schedutil")) { + cpufreq_cpu_put(policy); + return NOTIFY_OK; + } + + ret = get_c1_available_cpufreq(policy); + if (ret) { + cpufreq_cpu_put(policy); + return NOTIFY_BAD; + } + + freq = cpufreq_driver_resolve_freq(policy, + c1_qos_request_value.min_cpufreq); + cpufreq_driver_fast_switch(policy, freq); + + cpufreq_cpu_put(policy); + + return NOTIFY_OK; +} + +static struct notifier_block c1_cpufreq_qos_notifier = { + .notifier_call = c1_cpufreq_qos_handler, +}; + +static int c2_cpufreq_qos_handler(struct notifier_block *b, + unsigned long val, void *v) +{ + struct cpufreq_policy *policy; + int ret = -1; + unsigned int freq; + + policy = cpufreq_cpu_get(cluster2_first_cpu); + + if (!policy) + return NOTIFY_BAD; + + if (!policy->governor) { + cpufreq_cpu_put(policy); + return NOTIFY_BAD; + } + + if (strcmp(policy->governor->name, "schedutil")) { + cpufreq_cpu_put(policy); + return NOTIFY_OK; + } + + ret = get_c2_available_cpufreq(policy); + if (ret) { + cpufreq_cpu_put(policy); + return NOTIFY_BAD; + } + + freq = cpufreq_driver_resolve_freq(policy, + c2_qos_request_value.min_cpufreq); + cpufreq_driver_fast_switch(policy, freq); + + cpufreq_cpu_put(policy); + + return NOTIFY_OK; +} + +static struct notifier_block c2_cpufreq_qos_notifier = { + .notifier_call = c2_cpufreq_qos_handler, +}; + +static int __init pm_qos_notifier_init(void) +{ + /* add cpufreq qos notify */ + pm_qos_add_notifier(PM_QOS_C0_CPUFREQ_MAX, &c0_cpufreq_qos_notifier); + pm_qos_add_notifier(PM_QOS_C0_CPUFREQ_MIN, &c0_cpufreq_qos_notifier); + pm_qos_add_notifier(PM_QOS_C1_CPUFREQ_MAX, &c1_cpufreq_qos_notifier); + pm_qos_add_notifier(PM_QOS_C1_CPUFREQ_MIN, &c1_cpufreq_qos_notifier); + pm_qos_add_notifier(PM_QOS_C2_CPUFREQ_MAX, &c2_cpufreq_qos_notifier); + pm_qos_add_notifier(PM_QOS_C2_CPUFREQ_MIN, &c2_cpufreq_qos_notifier); + return 0; +} +subsys_initcall(pm_qos_notifier_init); diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index dafb679adc589ed533ef6dd02c186fb5ed03f4cc..d1346cf52241b7d50b97f26134a7593009a8d226 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -15,11 +15,45 @@ #include #include #include +#include + +#define CPUFREQ_INDEX 8 static void cpufreq_gov_performance_limits(struct cpufreq_policy *policy) { + unsigned int index = 0; + unsigned int valid_freq; + struct cpufreq_frequency_table *table, *pos; + static unsigned int first_cpu = 1010; pr_debug("setting to %u kHz\n", policy->max); - __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); + if (get_boot_mode() == MSM_BOOT_MODE_RF + || (get_boot_mode() == MSM_BOOT_MODE_FACTORY)) { + if (first_cpu != cpumask_first(policy->related_cpus)) { + first_cpu = cpumask_first(policy->related_cpus); + table = policy->freq_table; + if (!table) { + pr_err("Failed to get freqtable\n"); + } else { + for (pos = table; pos->frequency + != CPUFREQ_TABLE_END; pos++) + index++; + if (index > CPUFREQ_INDEX) + index = index - CPUFREQ_INDEX; + valid_freq = table[index].frequency; + pr_info("setting to %u kHz\n", valid_freq); + if (valid_freq) + __cpufreq_driver_target(policy, + valid_freq, + CPUFREQ_RELATION_H); + else + __cpufreq_driver_target(policy, + policy->max, + CPUFREQ_RELATION_H); + } + } + } else + __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); } static struct cpufreq_governor cpufreq_gov_performance = { diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 21b919bfaeccf7f32e11ca523008afe434802e2f..4d4782a4ac4ce172cb7c360dfed34394a2b1e049 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -232,7 +232,7 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy, new_index = freq_table_get_index(stats, new_freq); /* We can't do stats->time_in_state[-1]= .. */ - if (old_index == -1 || new_index == -1 || old_index == new_index) + if (new_index == -1) return; cpufreq_stats_update(stats); diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c index e1f1331fb7634487c9a13c86b1cd0546a520bf07..d9ccf92fb04e5f94376edd352e97f63aa408a786 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw.c +++ b/drivers/cpufreq/qcom-cpufreq-hw.c @@ -16,6 +16,12 @@ #include #include +//2020/03/25, add for pccore CONFIG_PCCORE +#include +#include +#include +#include + #define CREATE_TRACE_POINTS #include @@ -325,11 +331,55 @@ qcom_cpufreq_hw_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { int index; +//2020/03/25, add for pccore CONFIG_PCCORE + int dp_level = get_op_level(); + bool op_enable = get_op_select_freq_enable(); + int dp_level_mode = get_op_fd_mode(); + int idx_cache; index = policy->cached_resolved_idx; if (index < 0) return 0; +//2020/03/25, add for pccore CONFIG_PCCORE + idx_cache = index; + + if (op_enable) { + + if (!ht_pcc_alwayson() && ccdm_any_hint()) + goto done; + if (dp_level_mode == 2) { + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) + index = find_prefer_pd(policy->cpu, index, true, dp_level); + else + index = find_prefer_pd(policy->cpu, index, false, dp_level); + + } else if (dp_level_mode == 1) { + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) { + if (index - dp_level >= 0) + index -= dp_level; + else + index = 0; + } else { + int max = cpufreq_table_count_valid_entries(policy); + + if (index + dp_level > max) + index = max; + else + index += dp_level; + } + } +#ifdef CONFIG_PCCORE + /* limited by policy->min */ + if (policy->freq_table[index].frequency < policy->min) + index = policy->min_idx; +#endif + } +done: + trace_find_freq(idx_cache, target_freq, index, policy->freq_table[index].frequency, + policy->cpu, op_enable, dp_level_mode, dp_level); if (qcom_cpufreq_hw_target_index(policy, index)) return 0; diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 30ba39d667726f171f35276e8b05be4bdd856d30..1cdc40cc6b2375381be0653e1a863a8a0c37ef34 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -44,6 +44,10 @@ #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + #define SCLK_HZ (32768) #define PSCI_POWER_STATE(reset) (reset << 30) #define PSCI_AFFINITY_LEVEL(lvl) ((lvl & 0x3) << 24) @@ -125,6 +129,12 @@ module_param_named(print_parsed_dt, print_parsed_dt, bool, 0664); static bool sleep_disabled; module_param_named(sleep_disabled, sleep_disabled, bool, 0664); +void msm_cpuidle_set_sleep_disable(bool disable) +{ + sleep_disabled = disable; + pr_info("%s:sleep_disabled=%d\n", __func__, disable); +} + /** * msm_cpuidle_get_deep_idle_latency - Get deep idle latency value * @@ -652,6 +662,11 @@ static inline bool lpm_disallowed(s64 sleep_us, int cpu, struct lpm_cpu *pm_cpu) { uint64_t bias_time = 0; +#ifdef CONFIG_CONTROL_CENTER + uint64_t tb_block_ts; + int tb_ccdm_idx = cpu + CCDM_TB_CPU_0_IDLE_BLOCK; +#endif + if (cpu_isolated(cpu)) goto out; @@ -664,7 +679,16 @@ static inline bool lpm_disallowed(s64 sleep_us, int cpu, struct lpm_cpu *pm_cpu) return true; } +#ifdef CONFIG_CONTROL_CENTER + tb_block_ts = ccdm_get_hint(tb_ccdm_idx); + if (!time_after64(get_jiffies_64(), tb_block_ts)) + return true; +#endif + out: +#ifdef CONFIG_CONTROL_CENTER + ccdm_update_hint_1(tb_ccdm_idx, ULLONG_MAX); +#endif if (sleep_us < 0) return true; diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 234c14b8ec8d5293d2390eeb57ca33aba001981c..7edd69089582255fa1c9886ed4ffa0a8307a2c1c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -29,6 +29,10 @@ #include #include "governor.h" +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + #define MAX(a,b) ((a > b) ? a : b) #define MIN(a,b) ((a < b) ? a : b) @@ -337,6 +341,23 @@ int update_devfreq(struct devfreq *devfreq) flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */ } + +#ifdef CONFIG_CONTROL_CENTER + /* treat marked device with different vote result */ + if (cc_ddr_boost_enabled()) { + if (devfreq->dev.cc_marked) { + unsigned long val; + + /* update parent status */ + devfreq->dev.parent->cc_marked = devfreq->dev.cc_marked; + + val = cc_get_expect_ddrfreq(); + if (val) + freq = val; + } + } +#endif + if (devfreq->profile->get_cur_freq) devfreq->profile->get_cur_freq(devfreq->dev.parent, &cur_freq); else @@ -516,7 +537,8 @@ void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay) mutex_unlock(&devfreq->lock); cancel_delayed_work_sync(&devfreq->work); mutex_lock(&devfreq->lock); - if (!devfreq->stop_polling) + if (!devfreq->stop_polling + && !delayed_work_pending(&devfreq->work)) queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms)); } @@ -665,6 +687,12 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->max_freq = devfreq->scaling_max_freq = freq; dev_set_name(&devfreq->dev, "%s", dev_name(dev)); + +#ifdef CONFIG_CONTROL_CENTER + if (dev_name(dev)) + devfreq->dev.cc_marked = cc_is_ddrfreq_related(dev_name(dev)); +#endif + err = device_register(&devfreq->dev); if (err) { mutex_unlock(&devfreq->lock); diff --git a/drivers/devfreq/devfreq_devbw.c b/drivers/devfreq/devfreq_devbw.c index af8440bc0ba81dd4d65f867d21598f944f836aec..6af11a3c1f5d56af77c6d52d68cb7ab2c7412871 100644 --- a/drivers/devfreq/devfreq_devbw.c +++ b/drivers/devfreq/devfreq_devbw.c @@ -29,6 +29,19 @@ #define MAX_PATHS 2 #define DBL_BUF 2 +#include +struct qos_request_v { + int max_state; + int max_devfreq; + int min_devfreq; +}; + +static bool cpubw_flag; +static struct qos_request_v qos_request_value = { + .max_state = 0, + .max_devfreq = INT_MAX, + .min_devfreq = 0, +}; struct dev_data { struct msm_bus_vectors vectors[MAX_PATHS * DBL_BUF]; struct msm_bus_paths bw_levels[DBL_BUF]; @@ -72,6 +85,50 @@ static int set_bw(struct device *dev, int new_ib, int new_ab) return ret; } +static void find_freq_cpubw(struct devfreq_dev_profile *p, unsigned long *freq, + u32 flags) +{ + int i; + unsigned long atmost, atleast, f; + int min_index, max_index; + + min_index = qos_request_value.min_devfreq; + if (p->max_state > qos_request_value.max_devfreq) + max_index = qos_request_value.max_devfreq; + else + max_index = p->max_state; + + atmost = p->freq_table[min_index]; + atleast = p->freq_table[max_index-1]; + + for (i = min_index; i < max_index; i++) { + f = p->freq_table[i]; + if (f <= *freq) + atmost = max(f, atmost); + if (f >= *freq) + atleast = min(f, atleast); + } + + if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) + *freq = atmost; + else + *freq = atleast; +} + +static int devbw_target_cpubw(struct device *dev, unsigned long *freq, + u32 flags) +{ + struct dev_data *d = dev_get_drvdata(dev); + struct dev_pm_opp *opp; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (!IS_ERR(opp)) + dev_pm_opp_put(opp); + find_freq_cpubw(&d->dp, freq, flags); + + return set_bw(dev, *freq, d->gov_ab); +} + static int devbw_target(struct device *dev, unsigned long *freq, u32 flags) { struct dev_data *d = dev_get_drvdata(dev); @@ -93,6 +150,44 @@ static int devbw_get_dev_status(struct device *dev, return 0; } +static int devfreq_qos_handler(struct notifier_block *b, unsigned long val, + void *v) +{ + unsigned int max_devfreq_index, min_devfreq_index; + unsigned int index_max = 0, index_min = 0; + + max_devfreq_index = (unsigned int)pm_qos_request(PM_QOS_DEVFREQ_MAX); + min_devfreq_index = (unsigned int)pm_qos_request(PM_QOS_DEVFREQ_MIN); + + /* add limit */ + if (max_devfreq_index & MASK_CPUFREQ) { + index_max = MAX_CPUFREQ - max_devfreq_index; + if (index_max > qos_request_value.max_state) + index_max = 0; + index_max = qos_request_value.max_state - index_max; + } else { + if (max_devfreq_index > qos_request_value.max_state) + index_max = qos_request_value.max_state; + } + if (min_devfreq_index & MASK_CPUFREQ) { + index_min = MAX_CPUFREQ - min_devfreq_index; + if (index_min > (qos_request_value.max_state-1)) + index_min = 0; + index_min = qos_request_value.max_state - 1 - index_min; + } else { + if (min_devfreq_index > qos_request_value.max_state) + index_min = qos_request_value.max_state - 1; + } + + qos_request_value.min_devfreq = index_min; + qos_request_value.max_devfreq = index_max; + + return NOTIFY_OK; +} +static struct notifier_block devfreq_qos_notifier = { + .notifier_call = devfreq_qos_handler, +}; + #define PROP_PORTS "qcom,src-dst-ports" #define PROP_ACTIVE "qcom,active-only" @@ -148,7 +243,13 @@ int devfreq_add_devbw(struct device *dev) p = &d->dp; p->polling_ms = 50; - p->target = devbw_target; + + if (strnstr(d->bw_data.name, "soc:qcom,cpu-cpu-llcc-bw", + strlen(d->bw_data.name)) != NULL) { + p->target = devbw_target_cpubw; + cpubw_flag = true; + } else + p->target = devbw_target; p->get_dev_status = devbw_get_dev_status; if (of_device_is_compatible(dev->of_node, "qcom,devbw-ddr")) { @@ -179,6 +280,12 @@ int devfreq_add_devbw(struct device *dev) return PTR_ERR(d->df); } + if (cpubw_flag) { + cpubw_flag = false; + qos_request_value.max_state = p->max_state; + qos_request_value.min_devfreq = 0; + qos_request_value.max_devfreq = p->max_state; + } return 0; } @@ -228,10 +335,20 @@ static struct platform_driver devbw_driver = { .driver = { .name = "devbw", .of_match_table = devbw_match_table, + .owner = THIS_MODULE, .suppress_bind_attrs = true, }, }; -module_platform_driver(devbw_driver); +static int __init devbw_init(void) +{ + /* add cpufreq qos notify */ + cpubw_flag = false; + pm_qos_add_notifier(PM_QOS_DEVFREQ_MAX, &devfreq_qos_notifier); + pm_qos_add_notifier(PM_QOS_DEVFREQ_MIN, &devfreq_qos_notifier); + platform_driver_register(&devbw_driver); + return 0; +} +device_initcall(devbw_init); MODULE_DESCRIPTION("Device DDR bandwidth voting driver MSM SoCs"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index 7ab2b74ed52880106bcc19190752d8f4de0d5c8e..7c13102cb35e1c37ffad7bbd94e315998682f485 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config MSM_TZ_LOG - tristate "MSM Trust Zone (TZ) Log Driver" - depends on DEBUG_FS - help - This option enables a driver with a debugfs interface for messages - produced by the Secure code (Trust zone). These messages provide - diagnostic information about TZ operation. + tristate "MSM Trust Zone (TZ) Log Driver" + help + This option enables a driver with a debugfs interface for messages + produced by the Secure code (Trust zone). These messages provide + diagnostic information about TZ operation. diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index 9dcd24b25d65686eb39625a39e5b82bf2346bd13..48a8c020b87d44f1396aaf592c5e72fdc71e9452 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ -#include #include #include #include @@ -17,6 +16,7 @@ #include #include #include +#include #include #include @@ -781,7 +781,10 @@ static ssize_t tzdbgfs_read(struct file *file, char __user *buf, size_t count, loff_t *offp) { int len = 0; - int *tz_id = file->private_data; + int *tz_id = PDE_DATA(file_inode(file)); + + //pr_info("%s: private_data file name %s\n", __func__, file->f_path.dentry->d_name.name); + //pr_info("%s: data address: %p, data: %d\n", __func__, tz_id, *tz_id); if (*tz_id == TZDBG_BOOT || *tz_id == TZDBG_RESET || *tz_id == TZDBG_INTERRUPT || *tz_id == TZDBG_GENERAL || @@ -899,10 +902,10 @@ static int tzdbgfs_init(struct platform_device *pdev) { int rc = 0; int i; - struct dentry *dent_dir; - struct dentry *dent; + struct proc_dir_entry *dent_dir = NULL; + struct proc_dir_entry *dent = NULL; - dent_dir = debugfs_create_dir("tzdbg", NULL); + dent_dir = proc_mkdir("tzdbg", NULL); if (dent_dir == NULL) { dev_err(&pdev->dev, "tzdbg debugfs_create_dir failed\n"); return -ENOMEM; @@ -910,9 +913,9 @@ static int tzdbgfs_init(struct platform_device *pdev) for (i = 0; i < TZDBG_STATS_MAX; i++) { tzdbg.debug_tz[i] = i; - dent = debugfs_create_file_unsafe(tzdbg.stat[i].name, - 0444, dent_dir, - &tzdbg.debug_tz[i], &tzdbg_fops); + dent = proc_create_data(tzdbg.stat[i].name, + 0444, dent_dir + , &tzdbg_fops, &tzdbg.debug_tz[i]); if (dent == NULL) { dev_err(&pdev->dev, "TZ debugfs_create_file failed\n"); rc = -ENOMEM; @@ -926,14 +929,14 @@ static int tzdbgfs_init(struct platform_device *pdev) platform_set_drvdata(pdev, dent_dir); return 0; err: - debugfs_remove_recursive(dent_dir); + proc_remove(dent_dir); return rc; } static void tzdbgfs_exit(struct platform_device *pdev) { - struct dentry *dent_dir; + struct proc_dir_entry *dent_dir; if (g_qsee_log) { qtee_shmbridge_deregister(qseelog_shmbridge_handle); @@ -942,7 +945,7 @@ static void tzdbgfs_exit(struct platform_device *pdev) } kzfree(tzdbg.disp_buf); dent_dir = platform_get_drvdata(pdev); - debugfs_remove_recursive(dent_dir); + proc_remove(dent_dir); } static int __update_hypdbg_base(struct platform_device *pdev, @@ -1089,9 +1092,13 @@ static int tz_log_probe(struct platform_device *pdev) tzdbg.diag_buf = (struct tzdbg_t *)ptr; + //pr_info("%s: Start init tz procfs\n", __func__); + if (tzdbgfs_init(pdev)) goto err; + //pr_info("%s: End init tz procfs\n", __func__); + tzdbg_register_qsee_log_buf(pdev); tzdbg_get_tz_version(); diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8750f3f02b3fe4b5841b1121bc3c2ee96497a17d..ba8711529b01f90df0f478acb1e3fe97378eb5ca 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -117,6 +117,105 @@ void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); void drm_gem_print_info(struct drm_printer *p, unsigned int indent, const struct drm_gem_object *obj); +extern char gamma_para[2][413]; +extern char dsi_panel_name; +extern int reg_read_len; +extern int oneplus_get_panel_brightness_to_alpha(void); +extern ssize_t notify_fppress_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +extern ssize_t notify_dim_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +extern ssize_t notify_aod_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +int dsi_display_set_hbm_mode(struct drm_connector *connector, int level); +int dsi_display_get_hbm_mode(struct drm_connector *connector); +int dsi_display_get_serial_number(struct drm_connector *connector); +int dsi_display_get_serial_number_year(struct drm_connector *connector); +int dsi_display_get_serial_number_mon(struct drm_connector *connector); +int dsi_display_get_serial_number_day(struct drm_connector *connector); +int dsi_display_get_serial_number_hour(struct drm_connector *connector); +int dsi_display_get_serial_number_min(struct drm_connector *connector); +int dsi_display_set_acl_mode(struct drm_connector *connector, int level); +int dsi_display_get_acl_mode(struct drm_connector *connector); +int dsi_display_set_hbm_mode(struct drm_connector *connector, int level); +int dsi_display_get_hbm_mode(struct drm_connector *connector); +int dsi_display_set_hbm_brightness(struct drm_connector *connector, int level); +int dsi_display_get_hbm_brightness(struct drm_connector *connector); +int dsi_display_set_aod_mode(struct drm_connector *connector, int level); +int dsi_display_get_aod_mode(struct drm_connector *connector); +int dsi_display_set_dci_p3_mode(struct drm_connector *connector, int level); +int dsi_display_get_dci_p3_mode(struct drm_connector *connector); +int dsi_display_set_night_mode(struct drm_connector *connector, int level); +int dsi_display_get_night_mode(struct drm_connector *connector); +int dsi_display_update_gamma_para(struct drm_connector *connector); +int dsi_display_get_serial_number(struct drm_connector *connector); +int dsi_display_get_serial_number_year(struct drm_connector *connector); +int dsi_display_get_serial_number_mon(struct drm_connector *connector); +int dsi_display_get_serial_number_day(struct drm_connector *connector); +int dsi_display_get_serial_number_hour(struct drm_connector *connector); +int dsi_display_get_serial_number_min(struct drm_connector *connector); +int dsi_display_get_serial_number_sec(struct drm_connector *connector); +int dsi_display_get_serial_number_msec_int(struct drm_connector *connector); +int dsi_display_get_serial_number_msec_rem(struct drm_connector *connector); +uint64_t dsi_display_get_serial_number_id(uint64_t serial_number); +int dsi_display_get_code_info(struct drm_connector *connector); +int dsi_display_get_stage_info(struct drm_connector *connector); +int dsi_display_get_production_info(struct drm_connector *connector); +int dsi_display_panel_mismatch_check(struct drm_connector *connector); +int dsi_display_panel_mismatch(struct drm_connector *connector); +int dsi_display_set_aod_disable(struct drm_connector *connector, int disable); +int dsi_display_get_aod_disable(struct drm_connector *connector); +int dsi_display_set_fp_hbm_mode(struct drm_connector *connector, int level); +int dsi_display_get_fp_hbm_mode(struct drm_connector *connector); +int dsi_display_update_dsi_on_command(struct drm_connector *connector, + const char *buf, size_t count); +int dsi_display_get_dsi_on_command(struct drm_connector *connector, + char *buf); +int dsi_display_update_dsi_panel_command(struct drm_connector *connector, + const char *buf, size_t count); +int dsi_display_get_dsi_panel_command(struct drm_connector *connector, + char *buf); +int dsi_display_update_dsi_seed_command(struct drm_connector *connector, + const char *buf, size_t count); +int dsi_display_get_dsi_seed_command(struct drm_connector *connector, + char *buf); +int dsi_display_get_reg_read_command_and_value( + struct drm_connector *connector, char *buf); +int dsi_display_reg_read(struct drm_connector *connector, + const char *buf, size_t count); +int dsi_display_set_native_display_p3_mode(struct drm_connector *connector, + int level); +int dsi_display_get_native_display_p3_mode(struct drm_connector *connector); +int dsi_display_set_native_display_wide_color_mode( + struct drm_connector *connector, int level); +int dsi_display_get_native_display_wide_color_mode( + struct drm_connector *connector); +int dsi_display_set_native_display_srgb_color_mode( + struct drm_connector *connector, int level); +int dsi_display_get_native_display_srgb_color_mode( + struct drm_connector *connector); +int dsi_display_set_native_loading_effect_mode( + struct drm_connector *connector, int level); +int dsi_display_get_native_display_loading_effect_mode( + struct drm_connector *connector); +int dsi_display_set_customer_srgb_mode( + struct drm_connector *connector, int level); +int dsi_display_set_customer_p3_mode( + struct drm_connector *connector, int level); +int dsi_display_get_customer_srgb_mode(struct drm_connector *connector); +int dsi_display_get_customer_p3_mode(struct drm_connector *connector); +int dsi_display_get_panel_ic_v_info(struct drm_connector *connector); +int dsi_display_set_seed_lp_mode( + struct drm_connector *connector, int seed_lp_level); +int dsi_display_get_seed_lp_mode(struct drm_connector *connector); +int dsi_display_get_ddic_check_info(struct drm_connector *connector); +int dsi_display_get_ToolsType_ANA6706(struct drm_connector *connector); +int dsi_display_get_ddic_coords_X(struct drm_connector *connector); +int dsi_display_get_ddic_coords_Y(struct drm_connector *connector); +char *dsi_display_get_ic_reg_buf(struct drm_connector *connector); /* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 3eb8b2a52d585503fe228768c5609b5b80a939ad..47e397dc0178d584d82433693e8683b49108de6c 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -1096,6 +1096,34 @@ int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, } EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness); +int mipi_dsi_dcs_set_display_brightness_samsung(struct mipi_dsi_device *dsi, + u16 brightness) +{ + u8 payload[2] = {brightness >> 8, brightness & 0xff}; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_samsung); + +int mipi_dsi_dcs_write_c1(struct mipi_dsi_device *dsi, + u16 read_number) +{ + u8 payload[3] = {0x0A, read_number >> 8, read_number & 0xff}; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, 0xC1, payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_dcs_write_c1); static int mipi_dsi_drv_probe(struct device *dev) { struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index ecb7b33002bb27de0af599702a354e7c241cd6ed..815d651d58dcb1ccf76f4e6bddf82ce62379bc0e 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -21,9 +21,23 @@ #include #include #include "drm_internal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #define to_drm_minor(d) dev_get_drvdata(d) #define to_drm_connector(d) dev_get_drvdata(d) +#define DSI_PANEL_SAMSUNG_ANA6705 0 +#define DSI_PANEL_SAMSUNG_AMSS644_VK04 1 +#define DSI_PANEL_SAMSUNG_SOFEF00_M 2 +int dsi_cmd_log_enable; +EXPORT_SYMBOL(dsi_cmd_log_enable); /** * DOC: overview @@ -228,17 +242,1130 @@ static ssize_t modes_show(struct device *device, return written; } +static ssize_t acl_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int acl_mode = 0; + + acl_mode = dsi_display_get_acl_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "acl mode = %d\n" + "0--acl mode(off)\n 1--acl mode(5)\n" + "2--acl mode(10)\n 3--acl mode(15)\n", + acl_mode); + return ret; +} + +static ssize_t acl_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int acl_mode = 0; + + ret = kstrtoint(buf, 10, &acl_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_acl_mode(connector, acl_mode); + if (ret) + pr_err("set acl mode(%d) fail\n", acl_mode); + + return count; +} +static ssize_t hbm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int hbm_mode = 0; + + hbm_mode = dsi_display_get_hbm_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "hbm mode = %d\n" + "0--hbm mode(off)\n 1--hbm mode(XX)\n" + "2--hbm mode(XX)\n 3--hbm mode(XX)\n" + "4--hbm mode(XX)\n 5--hbm mode(670)\n", + hbm_mode); + return ret; +} + +static ssize_t hbm_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int hbm_mode = 0; + int panel_stage_info = 0; + + ret = kstrtoint(buf, 10, &hbm_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + if ((dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6705) || (dsi_panel_name == DSI_PANEL_SAMSUNG_AMSS644_VK04)) { + panel_stage_info = dsi_display_get_stage_info(connector); + if (((panel_stage_info == 0x02) || (panel_stage_info == 0x03) + || (panel_stage_info == 0x04)) && (hbm_mode == 4)) { + hbm_mode = hbm_mode - 1; + } else { + pr_err("20801 panel stage version is T0/DVT2/PVT&MP"); + } + } + ret = dsi_display_set_hbm_mode(connector, hbm_mode); + if (ret) + pr_err("set hbm mode(%d) fail\n", hbm_mode); + + return count; +} + +static ssize_t seed_lp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int seed_lp_mode = 0; + + ret = kstrtoint(buf, 10, &seed_lp_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + if (dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6705) { + ret = dsi_display_set_seed_lp_mode(connector, seed_lp_mode); + if (ret) + pr_err("set seed lp (%d) fail\n", seed_lp_mode); + } + + return count; +} +static ssize_t seed_lp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int seed_lp_mode = 0; + + if (dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6705) + seed_lp_mode = dsi_display_get_seed_lp_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "seed lp mode = %d\n" + "4--seed lp mode(off)\n" + "0--seed lp mode(mode0)\n" + "1--seed lp mode(mode1)\n" + "2--seed lp mode(mode2)\n", + seed_lp_mode); + return ret; +} +static ssize_t hbm_brightness_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int hbm_brightness = 0; + + hbm_brightness = dsi_display_get_hbm_brightness(connector); + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", hbm_brightness); + return ret; +} + +static ssize_t hbm_brightness_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int hbm_brightness = 0; + + ret = kstrtoint(buf, 10, &hbm_brightness); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_hbm_brightness(connector, hbm_brightness); + if (ret) + pr_err("set hbm brightness (%d) failed\n", hbm_brightness); + return count; +} + +static ssize_t op_friginer_print_hbm_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int op_hbm_mode = 0; + + op_hbm_mode = dsi_display_get_fp_hbm_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "OP_FP mode = %d\n" + "0--finger-hbm mode(off)\n" + "1--finger-hbm mode(600)\n", + op_hbm_mode); + return ret; +} + +static ssize_t op_friginer_print_hbm_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int op_hbm_mode = 0; + + ret = kstrtoint(buf, 10, &op_hbm_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_fp_hbm_mode(connector, op_hbm_mode); + if (ret) + pr_err("set hbm mode(%d) fail\n", op_hbm_mode); + + return count; +} + +static ssize_t aod_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int aod_mode = 0; + + aod_mode = dsi_display_get_aod_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "AOD mode = %d\n" + "0--AOD MODE(OFF)\n" + "1--ALPM AOD MODE ON(10nit)\n" + "2--ALPM AOD MODE ON(20nit)\n" + "3--ALPM AOD MODE ON(30nit)\n" + "4--ALPM AOD MODE ON(40nit)\n" + "5--HLPM AOD MODE ON(50nit)\n", + aod_mode); + return ret; +} + +static ssize_t aod_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int aod_mode = 0; + + ret = kstrtoint(buf, 10, &aod_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + ret = dsi_display_set_aod_mode(connector, aod_mode); + if (ret) + pr_err("set AOD mode(%d) fail\n", aod_mode); + return count; +} + +static ssize_t aod_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int aod_disable = 0; + + aod_disable = dsi_display_get_aod_disable(connector); + + ret = scnprintf(buf, PAGE_SIZE, "AOD disable = %d\n" + "0--AOD enable\n" + "1--AOD disable\n", + aod_disable); + return ret; +} + +static ssize_t aod_disable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int aod_disable = 0; + + ret = kstrtoint(buf, 10, &aod_disable); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_aod_disable(connector, aod_disable); + if (ret) + pr_err("set AOD disable(%d) fail\n", aod_disable); + + return count; +} + +static ssize_t DCI_P3_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int dci_p3_mode = 0; + + dci_p3_mode = dsi_display_get_dci_p3_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "dci-p3 mode = %d\n" + "0--dci-p3 mode Off\n" + "1--dci-p3 mode On\n", + dci_p3_mode); + return ret; +} + +static ssize_t DCI_P3_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int dci_p3_mode = 0; + + ret = kstrtoint(buf, 10, &dci_p3_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_dci_p3_mode(connector, dci_p3_mode); + if (ret) + pr_err("set dci-p3 mode(%d) fail\n", dci_p3_mode); + + return count; +} + +static ssize_t night_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int night_mode = 0; + + night_mode = dsi_display_get_night_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "night mode = %d\n" + "0--night mode Off\n" + "1--night mode On\n", + night_mode); + return ret; +} + +static ssize_t night_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int night_mode = 0; + + ret = kstrtoint(buf, 10, &night_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_night_mode(connector, night_mode); + if (ret) + pr_err("set night mode(%d) fail\n", night_mode); + + return count; +} + +static ssize_t native_display_p3_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_p3_mode = 0; + + native_display_p3_mode = + dsi_display_get_native_display_p3_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "native display p3 mode = %d\n" + "0--native display p3 mode Off\n" + "1--native display p3 mode On\n", + native_display_p3_mode); + return ret; +} + +static ssize_t native_display_p3_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_p3_mode = 0; + + ret = kstrtoint(buf, 10, &native_display_p3_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_native_display_p3_mode(connector, + native_display_p3_mode); + if (ret) + pr_err("set native_display_p3 mode(%d) fail\n", + native_display_p3_mode); + + return count; +} +static ssize_t native_display_wide_color_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_wide_color_mode = 0; + + native_display_wide_color_mode = + dsi_display_get_native_display_wide_color_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "native display wide color mode = %d\n" + "0--native display wide color mode Off\n" + "1--native display wide color mode On\n", + native_display_wide_color_mode); + return ret; +} + +static ssize_t native_display_loading_effect_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_loading_effect_mode = 0; + + ret = kstrtoint(buf, 10, &native_display_loading_effect_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_native_loading_effect_mode(connector, + native_display_loading_effect_mode); + if (ret) + pr_err("set loading effect mode(%d) fail\n", + native_display_loading_effect_mode); + + return count; +} + +static ssize_t native_display_loading_effect_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_loading_effect_mode = 0; + + native_display_loading_effect_mode = + dsi_display_get_native_display_loading_effect_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, + "native display loading effect mode = %d\n" + "0--native display loading effect mode Off\n" + "1--native display loading effect mode On\n", + native_display_loading_effect_mode); + return ret; +} + +static ssize_t native_display_customer_p3_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_customer_p3_mode = 0; + + ret = kstrtoint(buf, 10, &native_display_customer_p3_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_customer_p3_mode(connector, + native_display_customer_p3_mode); + if (ret) + pr_err("set customer p3 mode(%d) fail\n", + native_display_customer_p3_mode); + + return count; +} + +static ssize_t native_display_customer_p3_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_customer_p3_mode = 0; + + native_display_customer_p3_mode = + dsi_display_get_customer_p3_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, + "native display customer p3 mode = %d\n" + "0--native display customer p3 mode Off\n" + "1--native display customer p3 mode On\n", + native_display_customer_p3_mode); + return ret; +} +static ssize_t native_display_customer_srgb_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_customer_srgb_mode = 0; + + ret = kstrtoint(buf, 10, &native_display_customer_srgb_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_customer_srgb_mode(connector, + native_display_customer_srgb_mode); + if (ret) + pr_err("set customer srgb mode(%d) fail\n", + native_display_customer_srgb_mode); + + return count; +} + +static ssize_t native_display_customer_srgb_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_customer_srgb_mode = 0; + + native_display_customer_srgb_mode = + dsi_display_get_customer_srgb_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, + "native display customer srgb mode = %d\n" + "0--native display customer srgb mode Off\n" + "1--native display customer srgb mode On\n", + native_display_customer_srgb_mode); + return ret; +} + + +static ssize_t native_display_wide_color_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_wide_color_mode = 0; + + ret = kstrtoint(buf, 10, &native_display_wide_color_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_native_display_wide_color_mode(connector, + native_display_wide_color_mode); + if (ret) + pr_err("set native_display_p3 mode(%d) fail\n", + native_display_wide_color_mode); + + return count; +} + +static ssize_t native_display_srgb_color_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_srgb_color_mode = 0; + + native_display_srgb_color_mode = + dsi_display_get_native_display_srgb_color_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, "native display srgb color mode = %d\n" + "0--native display srgb color mode Off\n" + "1--native display srgb color mode On\n", + native_display_srgb_color_mode); + return ret; +} + +static ssize_t native_display_srgb_color_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int native_display_srgb_color_mode = 0; + + ret = kstrtoint(buf, 10, &native_display_srgb_color_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_native_display_srgb_color_mode(connector, + native_display_srgb_color_mode); + if (ret) + pr_err("set native_display_srgb mode(%d) fail\n", + native_display_srgb_color_mode); + + return count; +} + +static ssize_t gamma_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int gamma_test_flag = 0; + int panel_stage_info = 0; + int pvt_mp_panel_flag = 0; + + if (dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6705) { + ret = dsi_display_update_gamma_para(connector); + if (ret) + pr_err("Failed to update gamma para!\n"); + + if ((gamma_para[0][18] == 0xFF) && + (gamma_para[0][19] == 0xFF) && + (gamma_para[0][20] == 0xFF)) + gamma_test_flag = 0; + else + gamma_test_flag = 1; + + dsi_display_get_serial_number(connector); + panel_stage_info = dsi_display_get_stage_info(connector); + + if ((panel_stage_info == 0x07) || + (panel_stage_info == 0x10) || + (panel_stage_info == 0x11) || + (panel_stage_info == 0x16)) + pvt_mp_panel_flag = 1; + else + pvt_mp_panel_flag = 0; + + ret = scnprintf(buf, PAGE_SIZE, + "%d\n", (gamma_test_flag << 1) + pvt_mp_panel_flag); + } else { + ret = scnprintf(buf, PAGE_SIZE, "%d\n", 3); + pr_err("Gamma test is not supported!\n"); + } + + return ret; +} + +extern char buf_Lotid[6]; +static ssize_t panel_serial_number_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int panel_year = 0; + int panel_mon = 0; + int panel_day = 0; + int panel_hour = 0; + int panel_min = 0; + int panel_sec = 0; + int panel_msec_int = 0; + int panel_msec_rem = 0; + int panel_code_info = 0; + int panel_stage_info = 0; + int panel_production_info = 0; + int panel_ic_v_info = 0; + int ddic_check_info = 0; + int ddic_x = 0; + int ddic_y = 0; + int panel_tool = 0; + char *stage_string_info = NULL; + char *ddic_check_result = NULL; + int ret = 0; + + dsi_display_get_serial_number(connector); + + panel_year = dsi_display_get_serial_number_year(connector); + panel_mon = dsi_display_get_serial_number_mon(connector); + panel_day = dsi_display_get_serial_number_day(connector); + panel_hour = dsi_display_get_serial_number_hour(connector); + panel_min = dsi_display_get_serial_number_min(connector); + panel_sec = dsi_display_get_serial_number_sec(connector); + panel_msec_int = dsi_display_get_serial_number_msec_int(connector); + panel_msec_rem = dsi_display_get_serial_number_msec_rem(connector); + panel_code_info = dsi_display_get_code_info(connector); + panel_stage_info = dsi_display_get_stage_info(connector); + panel_production_info = dsi_display_get_production_info(connector); + panel_ic_v_info = dsi_display_get_panel_ic_v_info(connector); + ddic_check_info = dsi_display_get_ddic_check_info(connector); + panel_tool = dsi_display_get_ToolsType_ANA6706(connector); + ddic_x = dsi_display_get_ddic_coords_X(connector); + ddic_y = dsi_display_get_ddic_coords_Y(connector); + + if (ddic_check_info == 1) + ddic_check_result = "OK"; + else if (ddic_check_info == 0) + ddic_check_result = "NG"; + + if ((dsi_panel_name == DSI_PANEL_SAMSUNG_AMSS644_VK04) || (dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6705)) { + if (panel_stage_info == 0x01) + stage_string_info = "STAGE: T0"; + else if (panel_stage_info == 0x02) + stage_string_info = "STAGE: EVT1"; + else if (panel_stage_info == 0x03) + stage_string_info = "STAGE: EVT2"; + else if (panel_stage_info == 0x04) + stage_string_info = "STAGE: DVT1"; + else if (panel_stage_info == 0x05) + stage_string_info = "STAGE: DVT2"; + else if (panel_stage_info == 0x06) + stage_string_info = "STAGE: PVT/MP"; + + ret = scnprintf(buf, PAGE_SIZE, + "%04d/%02d/%02d\n%02d:%02d:%02d:%03d.%01d\n%s\n" + "ID: %02X %02X %02X\n DDIC_Check_Result: %s\n", + panel_year, panel_mon, panel_day, + panel_hour, panel_min, panel_sec, + panel_msec_int, panel_msec_rem, + stage_string_info, panel_code_info, + panel_stage_info, panel_production_info, + ddic_check_result); + } else { + ret = scnprintf(buf, PAGE_SIZE, + "%04d/%02d/%02d %02d:%02d:%02d\n", + panel_year, panel_mon, panel_day, + panel_hour, panel_min, panel_sec); + } + + pr_err("panel year = %d, mon = %d, day = %d, hour = %d, min = %d, msec = %d.%d , ddic_x = %d , ddic_y = %d\n", + panel_year, panel_mon, panel_day, + panel_hour, panel_min, panel_msec_int, + panel_msec_rem, ddic_x, ddic_y); + + return ret; +} + +static ssize_t panel_serial_number_AT_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int ret = 0; + uint64_t serial_number = 0; + + ret = scnprintf(buf, PAGE_SIZE, "%llu\n", + dsi_display_get_serial_number_id(serial_number)); + + return ret; +} + + +static ssize_t dsi_on_command_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_get_dsi_on_command(connector, buf); + + return ret; +} + +static ssize_t dsi_on_command_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_update_dsi_on_command(connector, buf, count); + if (ret) + pr_err("Failed to update dsi on command, ret=%d\n", ret); + + return count; +} + +static ssize_t dsi_panel_command_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_get_dsi_panel_command(connector, buf); + + return ret; +} + +static ssize_t dsi_panel_command_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_update_dsi_panel_command(connector, buf, count); + if (ret) + pr_err("Failed to update dsi panel command, ret=%d\n", ret); + + return count; +} + +static ssize_t dsi_seed_command_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_get_dsi_seed_command(connector, buf); + + return ret; +} + +static ssize_t dsi_seed_command_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_update_dsi_seed_command(connector, buf, count); + if (ret) + pr_err("Failed to update dsi seed command, ret=%d\n", ret); + + return count; +} + +static ssize_t dsi_panel_reg_len_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", reg_read_len); + + return ret; +} + +static ssize_t dsi_panel_reg_len_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + int num = 0; + + ret = kstrtoint(buf, 10, &num); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + if (num <= 0) + pr_err("Invalid length!\n"); + else + reg_read_len = num; + + return count; +} + +static ssize_t dsi_panel_reg_read_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_get_reg_read_command_and_value(connector, buf); + + return ret; +} + +static ssize_t dsi_panel_reg_read_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = dsi_display_reg_read(connector, buf, count); + if (ret) + pr_err("Failed to update reg read command, ret=%d\n", ret); + + return count; +} + +static ssize_t dsi_cmd_log_switch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + + ret = scnprintf(buf, PAGE_SIZE, "dsi cmd log switch = %d\n" + "0 -- dsi cmd log switch off\n" + "other -- dsi cmd log switch on\n", + dsi_cmd_log_enable); + + return ret; +} + +static ssize_t dsi_cmd_log_switch_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + ret = kstrtoint(buf, 10, &dsi_cmd_log_enable); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + return count; +} + +int current_freq; +static ssize_t dynamic_dsitiming_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + + ret = scnprintf(buf, PAGE_SIZE, "current_freq = %d\n", + current_freq); + return ret; +} + +static ssize_t dynamic_dsitiming_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + int freq_value = 0; + + ret = kstrtoint(buf, 10, &freq_value); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + current_freq = freq_value; + + pr_err("freq setting=%d\n", current_freq); + + if (ret) + pr_err("set dsi freq (%d) fail\n", current_freq); + + return count; +} + +extern u32 mode_fps; +static ssize_t dynamic_fps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + + ret = scnprintf(buf, PAGE_SIZE, "%d\n", mode_fps); + + return ret; +} + +static ssize_t panel_mismatch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + int wrong_panel = 0; + + dsi_display_panel_mismatch_check(connector); + + wrong_panel = dsi_display_panel_mismatch(connector); + ret = scnprintf(buf, PAGE_SIZE, + "panel mismatch = %d\n 0--(panel match)\n" + "1--(panel mismatch)\n", + wrong_panel); + return ret; +} + +int oneplus_panel_alpha; +int oneplus_force_screenfp; +int op_dimlayer_bl_enable; +int op_dp_enable; +int op_dither_enable; + +static ssize_t dim_alpha_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + oneplus_get_panel_brightness_to_alpha()); +} + +static ssize_t dim_alpha_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + ret = kstrtoint(buf, 10, &oneplus_panel_alpha); + if (ret) + pr_err("kstrtoint failed. ret=%d\n", ret); + + return count; +} + +static ssize_t force_screenfp_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + oneplus_force_screenfp = dsi_display_get_fp_hbm_mode(connector); + + ret = scnprintf(buf, PAGE_SIZE, + "OP_FP mode = %d\n 0--finger-hbm mode(off)\n" + "1--finger-hbm mode(600)\n", + oneplus_force_screenfp); + return snprintf(buf, PAGE_SIZE, "%d\n", oneplus_force_screenfp); +} + +static ssize_t force_screenfp_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + //sscanf(buf, "%x", &oneplus_force_screenfp); + struct drm_connector *connector = to_drm_connector(dev); + int ret = 0; + + ret = kstrtoint(buf, 10, &oneplus_force_screenfp); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + ret = dsi_display_set_fp_hbm_mode(connector, oneplus_force_screenfp); + if (ret) + pr_err("set hbm mode(%d) fail\n", oneplus_force_screenfp); + return count; +} + +static ssize_t dimlayer_bl_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", op_dimlayer_bl_enable); +} + +static ssize_t dimlayer_bl_en_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + ret = kstrtoint(buf, 10, &op_dimlayer_bl_enable); + if (ret) + pr_err("kstrtoint failed. ret=%d\n", ret); + + pr_err("op_dimlayer_bl_enable : %d\n", op_dimlayer_bl_enable); + + return count; +} + +static ssize_t dither_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", op_dither_enable); +} + +static ssize_t dither_en_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + ret = kstrtoint(buf, 10, &op_dither_enable); + if (ret) + pr_err("kstrtoint failed. ret=%d\n", ret); + + return count; +} + +static ssize_t dp_en_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", op_dp_enable); +} + +static ssize_t dp_en_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + ret = kstrtoint(buf, 10, &op_dp_enable); + if (ret) + pr_err("kstrtoint failed. ret=%d\n", ret); + + return count; +} static DEVICE_ATTR_RW(status); static DEVICE_ATTR_RO(enabled); static DEVICE_ATTR_RO(dpms); static DEVICE_ATTR_RO(modes); - +static DEVICE_ATTR_RW(acl); +static DEVICE_ATTR_RW(hbm); +static DEVICE_ATTR_RW(hbm_brightness); +static DEVICE_ATTR_RW(op_friginer_print_hbm); +static DEVICE_ATTR_RW(aod); +static DEVICE_ATTR_RW(aod_disable); +static DEVICE_ATTR_RW(DCI_P3); +static DEVICE_ATTR_RW(night_mode); +static DEVICE_ATTR_RW(native_display_p3_mode); +static DEVICE_ATTR_RW(native_display_wide_color_mode); +static DEVICE_ATTR_RW(native_display_loading_effect_mode); +static DEVICE_ATTR_RW(native_display_srgb_color_mode); +static DEVICE_ATTR_RW(native_display_customer_p3_mode); +static DEVICE_ATTR_RW(native_display_customer_srgb_mode); +static DEVICE_ATTR_RO(gamma_test); +static DEVICE_ATTR_RO(panel_serial_number); +static DEVICE_ATTR_RO(panel_serial_number_AT); + +static DEVICE_ATTR_RW(dsi_on_command); +static DEVICE_ATTR_RW(dsi_panel_command); +static DEVICE_ATTR_RW(dsi_seed_command); +static DEVICE_ATTR_RW(dsi_panel_reg_len); +static DEVICE_ATTR_RW(dsi_panel_reg_read); +static DEVICE_ATTR_RW(dsi_cmd_log_switch); +static DEVICE_ATTR_RW(dynamic_dsitiming); +static DEVICE_ATTR_RO(panel_mismatch); +static DEVICE_ATTR_RO(dynamic_fps); +static DEVICE_ATTR_RW(dim_alpha); +static DEVICE_ATTR_RW(force_screenfp); +static DEVICE_ATTR_WO(notify_fppress); +static DEVICE_ATTR_WO(notify_dim); +static DEVICE_ATTR_WO(notify_aod); +static DEVICE_ATTR_RW(dimlayer_bl_en); +static DEVICE_ATTR_RW(dp_en); +static DEVICE_ATTR_RW(dither_en); +static DEVICE_ATTR_RW(seed_lp); static struct attribute *connector_dev_attrs[] = { &dev_attr_status.attr, &dev_attr_enabled.attr, &dev_attr_dpms.attr, &dev_attr_modes.attr, + &dev_attr_acl.attr, + &dev_attr_hbm.attr, + &dev_attr_hbm_brightness.attr, + &dev_attr_op_friginer_print_hbm.attr, + &dev_attr_aod.attr, + &dev_attr_aod_disable.attr, + &dev_attr_DCI_P3.attr, + &dev_attr_night_mode.attr, + &dev_attr_native_display_p3_mode.attr, + &dev_attr_native_display_wide_color_mode.attr, + &dev_attr_native_display_loading_effect_mode.attr, + &dev_attr_native_display_srgb_color_mode.attr, + &dev_attr_native_display_customer_p3_mode.attr, + &dev_attr_native_display_customer_srgb_mode.attr, + &dev_attr_gamma_test.attr, + &dev_attr_panel_serial_number.attr, + &dev_attr_panel_serial_number_AT.attr, + &dev_attr_dsi_on_command.attr, + &dev_attr_dsi_panel_command.attr, + &dev_attr_dsi_seed_command.attr, + &dev_attr_dsi_panel_reg_len.attr, + &dev_attr_dsi_panel_reg_read.attr, + &dev_attr_dsi_cmd_log_switch.attr, + &dev_attr_dynamic_dsitiming.attr, + &dev_attr_panel_mismatch.attr, + &dev_attr_force_screenfp.attr, + &dev_attr_dim_alpha.attr, + &dev_attr_dynamic_fps.attr, + &dev_attr_notify_fppress.attr, + &dev_attr_notify_dim.attr, + &dev_attr_notify_aod.attr, + &dev_attr_dimlayer_bl_en.attr, + &dev_attr_dp_en.attr, + &dev_attr_dither_en.attr, + &dev_attr_seed_lp.attr, NULL }; diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 9f1eaa28f3c0911ab8bebde6a263797518e45725..40c20e0736ce769bce0ddd919754cce8373bb31d 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -27,6 +27,7 @@ #include "kgsl_reclaim.h" #include "kgsl_sync.h" #include "kgsl_trace.h" +#include #ifndef arch_mmap_check #define arch_mmap_check(addr, len, flags) (0) @@ -4733,6 +4734,7 @@ static unsigned long _get_svm_area(struct kgsl_process_private *private, uint64_t align; unsigned long result; unsigned long addr; + uint64_t svm_start, svm_end; if (align_shift >= ilog2(SZ_2M)) align = SZ_2M; @@ -4750,6 +4752,9 @@ static unsigned long _get_svm_area(struct kgsl_process_private *private, entry->memdesc.flags)) return -ERANGE; + svm_start = start; + svm_end = end; + /* now clamp the range based on the CPU's requirements */ start = max_t(uint64_t, start, mmap_min_addr); end = min_t(uint64_t, end, current->mm->mmap_base); @@ -4791,6 +4796,24 @@ static unsigned long _get_svm_area(struct kgsl_process_private *private, * Search downwards from the hint first. If that fails we * must try to search above it. */ + if (current->mm->va_feature & 0x2) { + uint64_t lstart, lend; + unsigned long lresult; + + switch (len) { + case 4096: case 8192: case 16384: case 32768: + case 65536: case 131072: case 262144: + lend = current->mm->va_feature_rnd - (dbg_pm[2] * (ilog2(len) - dbg_pm[1])); + lstart = current->mm->va_feature_rnd - (dbg_pm[2] * dbg_pm[3]); + if (lend <= svm_end && lstart >= svm_start) { + lresult = _search_range(private, entry, lstart, lend, len, align); + if (!IS_ERR_VALUE(lresult)) + return lresult; + } + default: + break; + } + } result = _search_range(private, entry, start, addr, len, align); if (IS_ERR_VALUE(result) && hint != 0) result = _search_range(private, entry, addr, end, len, align); @@ -4798,6 +4821,31 @@ static unsigned long _get_svm_area(struct kgsl_process_private *private, return result; } +static void kgsl_send_uevent_notify(struct kgsl_device *desc, char *comm, + unsigned long len, unsigned long total_vm, + unsigned long largest_gap_cpu, unsigned long largest_gap_gpu) +{ + char *envp[6]; + + if (!desc) + return; + + envp[0] = kasprintf(GFP_KERNEL, "COMM=%s", comm); + envp[1] = kasprintf(GFP_KERNEL, "LEN=%lu", len); + envp[2] = kasprintf(GFP_KERNEL, "TOTAL_VM=%lu", total_vm); + envp[3] = kasprintf(GFP_KERNEL, "LARGEST_GAP_CPU=%lu", largest_gap_cpu); + envp[4] = kasprintf(GFP_KERNEL, "LARGEST_GAP_GPU=%lu", largest_gap_gpu); + envp[5] = NULL; + kobject_uevent_env(&desc->dev->kobj, KOBJ_CHANGE, envp); + kfree(envp[4]); + kfree(envp[3]); + kfree(envp[2]); + kfree(envp[1]); + kfree(envp[0]); +} + +static int current_pid = -1; + static unsigned long kgsl_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, @@ -4832,12 +4880,35 @@ kgsl_get_unmapped_area(struct file *file, unsigned long addr, (int) val); } else { val = _get_svm_area(private, entry, addr, len, flags); - if (IS_ERR_VALUE(val)) + if (IS_ERR_VALUE(val)) { + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long largest_gap_cpu = UINT_MAX; + unsigned long largest_gap_gpu = UINT_MAX; + dev_err_ratelimited(device->dev, "_get_svm_area: pid %d mmap_base %lx addr %lx pgoff %lx len %ld failed error %d\n", private->pid, current->mm->mmap_base, addr, pgoff, len, (int) val); + + if (!RB_EMPTY_ROOT(&mm->mm_rb)) { + vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb); + largest_gap_cpu = vma->rb_subtree_gap; + largest_gap_gpu = vma->rb_glfragment_gap; + } + + if (private->pid != current_pid) { + current_pid = private->pid; + kgsl_send_uevent_notify(device, current->group_leader->comm, + len, mm->total_vm, largest_gap_cpu, largest_gap_gpu); + } + + dev_err_ratelimited(device->dev, + "kgsl additional info: %s VmSize %lu MaxGapCpu %lu MaxGapGpu %lu VA_rnd 0x%llx\n" + , current->group_leader->comm, mm->total_vm, largest_gap_cpu + , largest_gap_gpu, mm->va_feature_rnd); + } } put: diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 4eaeadedc479378e0b296be4c3dba0c55a3ded1d..c5360a76a32ba524f1be0fa99469eb4b33947d76 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -17,6 +17,10 @@ #include "kgsl_trace.h" #include "kgsl_trace_power.h" +#ifdef CONFIG_HOUSTON +#include +#endif + #define KGSL_PWRFLAGS_POWER_ON 0 #define KGSL_PWRFLAGS_CLK_ON 1 #define KGSL_PWRFLAGS_AXI_ON 2 @@ -2437,6 +2441,10 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) of_property_read_string(pdev->dev.of_node, "qcom,tzone-name", &pwr->tzone_name); +#ifdef CONFIG_HOUSTON + ht_register_kgsl_pwrctrl(pwr); +#endif + return result; error_cleanup_bus_ib: diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2c85d075daee13186ad079eea20aba37eefb7ad0..05122167d9d850c862dba09a80c476a1788b464f 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1425,6 +1425,17 @@ static void hid_output_field(const struct hid_device *hid, } } +/* + * Compute the size of a report. + */ +static size_t hid_compute_report_size(struct hid_report *report) +{ + if (report->size) + return ((report->size - 1) >> 3) + 1; + + return 0; +} + /* * Create a report. 'data' has to be allocated using * hid_alloc_report_buf() so that it has proper size. @@ -1437,7 +1448,7 @@ void hid_output_report(struct hid_report *report, __u8 *data) if (report->id > 0) *data++ = report->id; - memset(data, 0, ((report->size - 1) >> 3) + 1); + memset(data, 0, hid_compute_report_size(report)); for (n = 0; n < report->maxfield; n++) hid_output_field(report->device, report->field[n], data); } @@ -1564,7 +1575,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, csize--; } - rsize = ((report->size - 1) >> 3) + 1; + rsize = hid_compute_report_size(report); if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE) rsize = HID_MAX_BUFFER_SIZE - 1; diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index dbb0cbe65fc98a9ada4bc1bce7ed940ae5577f99..0062b37ef98fd38df26a21280cab8a6f848fc1b2 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1125,6 +1125,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } mapped: + /* Mapping failed, bail out */ + if (!bit) + return; + if (device->driver->input_mapped && device->driver->input_mapped(device, hidinput, field, usage, &bit, &max) < 0) { diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 19dfd8acd0dab5f01f23f0c2a04d9cc5b53d17fd..515963a5211b3a4310aacc42f81e59ba8a970f02 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -841,6 +841,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, code = BTN_0 + ((usage->hid - 1) & HID_USAGE); hid_map_usage(hi, usage, bit, max, EV_KEY, code); + if (!*bit) + return -1; input_set_capability(hi->input, EV_KEY, code); return 1; diff --git a/drivers/hwtracing/coresight/coresight-byte-cntr.c b/drivers/hwtracing/coresight/coresight-byte-cntr.c index 41ad3c412f4d1bf92e5a3e6936d59b0217d55dac..48756a8607aa8c599ebdd6769a64a9897e3a22ba 100644 --- a/drivers/hwtracing/coresight/coresight-byte-cntr.c +++ b/drivers/hwtracing/coresight/coresight-byte-cntr.c @@ -189,6 +189,8 @@ static int tmc_etr_byte_cntr_release(struct inode *in, struct file *fp) int usb_bypass_start(struct byte_cntr *byte_cntr_data) { + long offset; + if (!byte_cntr_data) return -ENOMEM; @@ -200,7 +202,16 @@ int usb_bypass_start(struct byte_cntr *byte_cntr_data) } atomic_set(&byte_cntr_data->usb_free_buf, USB_BUF_NUM); - byte_cntr_data->offset = tmc_sg_get_rwp_offset(tmcdrvdata); + + offset = tmc_sg_get_rwp_offset(tmcdrvdata); + if (offset < 0) { + dev_err(&tmcdrvdata->csdev->dev, + "%s: invalid rwp offset value\n", __func__); + mutex_unlock(&byte_cntr_data->usb_bypass_lock); + return offset; + } + byte_cntr_data->offset = offset; + byte_cntr_data->read_active = true; /* * IRQ is a '8- byte' counter and to observe interrupt at @@ -326,6 +337,13 @@ static int usb_transfer_small_packet(struct qdss_request *usb_req, long w_offset; w_offset = tmc_sg_get_rwp_offset(tmcdrvdata); + if (w_offset < 0) { + ret = w_offset; + dev_err_ratelimited(&tmcdrvdata->csdev->dev, + "%s: RWP offset is invalid\n", __func__); + goto out; + } + req_size = ((w_offset < drvdata->offset) ? etr_buf->size : 0) + w_offset - drvdata->offset; req_size = ((req_size + *small_size) < USB_BLK_SIZE) ? req_size : @@ -333,8 +351,7 @@ static int usb_transfer_small_packet(struct qdss_request *usb_req, while (req_size > 0) { - usb_req = devm_kzalloc(tmcdrvdata->dev, sizeof(*usb_req), - GFP_KERNEL); + usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL); if (!usb_req) { ret = -EFAULT; goto out; @@ -342,6 +359,16 @@ static int usb_transfer_small_packet(struct qdss_request *usb_req, actual = tmc_etr_buf_get_data(etr_buf, drvdata->offset, req_size, &usb_req->buf); + + if (actual <= 0 || actual > req_size) { + kfree(usb_req); + usb_req = NULL; + dev_err_ratelimited(&tmcdrvdata->csdev->dev, + "%s: Invalid data in ETR\n", __func__); + ret = -EINVAL; + goto out; + } + usb_req->length = actual; drvdata->usb_req = usb_req; req_size -= actual; @@ -358,7 +385,7 @@ static int usb_transfer_small_packet(struct qdss_request *usb_req, ret = usb_qdss_write(tmcdrvdata->usbch, usb_req); if (ret) { - devm_kfree(tmcdrvdata->dev, usb_req); + kfree(usb_req); usb_req = NULL; drvdata->usb_req = NULL; dev_err_ratelimited(tmcdrvdata->dev, @@ -371,7 +398,7 @@ static int usb_transfer_small_packet(struct qdss_request *usb_req, dev_dbg(tmcdrvdata->dev, "Drop data, offset = %d, len = %d\n", drvdata->offset, req_size); - devm_kfree(tmcdrvdata->dev, usb_req); + kfree(usb_req); drvdata->usb_req = NULL; } } @@ -422,15 +449,13 @@ static void usb_read_work_fn(struct work_struct *work) if (req_size > 0) { seq++; req_sg_num = (req_size - 1) / PAGE_SIZE + 1; - usb_req = devm_kzalloc(tmcdrvdata->dev, - sizeof(*usb_req), GFP_KERNEL); + usb_req = kzalloc(sizeof(*usb_req), GFP_KERNEL); if (!usb_req) return; - usb_req->sg = devm_kzalloc(tmcdrvdata->dev, - sizeof(*(usb_req->sg)) * req_sg_num, - GFP_KERNEL); + usb_req->sg = kcalloc(req_sg_num, + sizeof(*(usb_req->sg)), GFP_KERNEL); if (!usb_req->sg) { - devm_kfree(tmcdrvdata->dev, usb_req); + kfree(usb_req); usb_req = NULL; return; } @@ -440,13 +465,13 @@ static void usb_read_work_fn(struct work_struct *work) drvdata->offset, PAGE_SIZE, &buf); - if (actual <= 0) { - devm_kfree(tmcdrvdata->dev, - usb_req->sg); - devm_kfree(tmcdrvdata->dev, usb_req); + if (actual <= 0 || actual > PAGE_SIZE) { + kfree(usb_req->sg); + kfree(usb_req); usb_req = NULL; - dev_err_ratelimited(tmcdrvdata->dev, - "No data in ETR\n"); + dev_err_ratelimited( + &tmcdrvdata->csdev->dev, + "Invalid data in ETR\n"); return; } @@ -473,9 +498,8 @@ static void usb_read_work_fn(struct work_struct *work) ret = usb_qdss_write(tmcdrvdata->usbch, drvdata->usb_req); if (ret) { - devm_kfree(tmcdrvdata->dev, - usb_req->sg); - devm_kfree(tmcdrvdata->dev, usb_req); + kfree(usb_req->sg); + kfree(usb_req); usb_req = NULL; drvdata->usb_req = NULL; dev_err_ratelimited(tmcdrvdata->dev, @@ -491,8 +515,8 @@ static void usb_read_work_fn(struct work_struct *work) "Drop data, offset = %d, seq = %d, irq = %d\n", drvdata->offset, seq, atomic_read(&drvdata->irq_cnt)); - devm_kfree(tmcdrvdata->dev, usb_req->sg); - devm_kfree(tmcdrvdata->dev, usb_req); + kfree(usb_req->sg); + kfree(usb_req); drvdata->usb_req = NULL; } } @@ -509,15 +533,15 @@ static void usb_write_done(struct byte_cntr *drvdata, atomic_inc(&drvdata->usb_free_buf); if (d_req->status) pr_err_ratelimited("USB write failed err:%d\n", d_req->status); - if (d_req->sg) - devm_kfree(tmcdrvdata->dev, d_req->sg); - devm_kfree(tmcdrvdata->dev, d_req); + kfree(d_req->sg); + kfree(d_req); } void usb_bypass_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch) { struct byte_cntr *drvdata = priv; + int ret; if (!drvdata) return; @@ -531,8 +555,11 @@ void usb_bypass_notifier(void *priv, unsigned int event, switch (event) { case USB_QDSS_CONNECT: + ret = usb_bypass_start(drvdata); + if (ret < 0) + return; + usb_qdss_alloc_req(ch, USB_BUF_NUM); - usb_bypass_start(drvdata); queue_work(drvdata->usb_wq, &(drvdata->read_work)); break; diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 9bc1c8adaaedb80ec992b0eedfd045b75b2b3da7..da0ddb5de0c43f301d9e5c2bb787bdf39b0a0db0 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -23,6 +23,11 @@ #include #include +// Added for ESD issue AVICII-556 +#include +#define AP_BAT_SCL 109 +#define AP_BAT_SDA 108 +// Added for ESD issue AVICII-556 #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) #define SE_I2C_SCL_COUNTERS (0x278) @@ -128,6 +133,7 @@ struct geni_i2c_dev { bool is_shared; u32 dbg_num; struct dbg_buf_ctxt *dbg_buf_ptr; + int reset_support; // Added for ESD issue AVICII-556 }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; @@ -903,6 +909,27 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, ret = gi2c->err; if (gi2c->err) { +// Added for ESD issue AVICII-556 + if (gi2c->err == -ETIMEDOUT && gi2c->reset_support) { + pinctrl_select_state(gi2c->i2c_rsc.geni_pinctrl, + gi2c->i2c_rsc.geni_gpio_reset); + gpio_direction_output(AP_BAT_SDA, 0); + gpio_direction_output(AP_BAT_SCL, 0); + msleep(3000); + dev_info(gi2c->dev, "b clk:%d,data:%d\n", + gpio_get_value(AP_BAT_SCL), + gpio_get_value(AP_BAT_SDA)); + gpio_direction_output(AP_BAT_SDA, 1); + gpio_direction_output(AP_BAT_SCL, 1); + dev_info(gi2c->dev, "c clk:%d,data:%d\n", + gpio_get_value(AP_BAT_SCL), + gpio_get_value(AP_BAT_SDA)); + gpio_direction_input(AP_BAT_SDA); + gpio_direction_input(AP_BAT_SCL); + pinctrl_select_state(gi2c->i2c_rsc.geni_pinctrl, + gi2c->i2c_rsc.geni_gpio_active); + } +// Added for ESD issue AVICII-556 GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "i2c error :%d\n", gi2c->err); break; @@ -1022,7 +1049,29 @@ static int geni_i2c_probe(struct platform_device *pdev) ret = PTR_ERR(gi2c->i2c_rsc.geni_gpio_sleep); return ret; } - +// Added for ESD issue AVICII-556 + gi2c->i2c_rsc.geni_gpio_reset = + pinctrl_lookup_state(gi2c->i2c_rsc.geni_pinctrl, + PINCTRL_RESET); + if (IS_ERR_OR_NULL(gi2c->i2c_rsc.geni_gpio_reset)) { + dev_err(&pdev->dev, "No reset config specified\n"); + ret = PTR_ERR(gi2c->i2c_rsc.geni_gpio_reset); + } else { + if (gpio_is_valid(AP_BAT_SCL) + && gpio_is_valid(AP_BAT_SDA)) { + ret = gpio_request(AP_BAT_SCL, "bat_scl"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + AP_BAT_SCL, ret); + ret = gpio_request(AP_BAT_SDA, "bat_sda"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + AP_BAT_SDA, ret); + } + gi2c->reset_support = true; + dev_err(&pdev->dev, "reset config specified\n"); + } +// Added for ESD issue AVICII-556 if (of_property_read_bool(pdev->dev.of_node, "qcom,shared")) { gi2c->is_shared = true; dev_info(&pdev->dev, "Multi-EE usecase\n"); @@ -1030,10 +1079,10 @@ static int geni_i2c_probe(struct platform_device *pdev) if (of_property_read_u32(pdev->dev.of_node, "qcom,clk-freq-out", &gi2c->i2c_rsc.clk_freq_out)) { - dev_info(&pdev->dev, - "Bus frequency not specified, default to 400KHz.\n"); gi2c->i2c_rsc.clk_freq_out = KHz(400); } + dev_info(&pdev->dev, "Bus frequency is set to %dHz\n", + gi2c->i2c_rsc.clk_freq_out); gi2c->irq = platform_get_irq(pdev, 0); if (gi2c->irq < 0) { diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index d5f06dffb7de5f87f4090aea94007bcc8bc0ead1..2514fa25ba16ff765026036412e0cc4f4c815d79 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -656,8 +656,11 @@ static int adc7_do_conversion(struct adc_chip *adc, } /* No support for polling mode at present*/ - wait_for_completion_timeout(&adc->complete, - ADC7_CONV_TIMEOUT); + if (!wait_for_completion_timeout(&adc->complete, + ADC7_CONV_TIMEOUT)) { + pr_err("ADC conversion TIMEDOUT.\n"); + /* TODO: Confirm whether the adc_read could still be valid */ + } ret = adc_read(adc, ADC_USR_STATUS1, &status, 1); if (ret < 0) @@ -923,10 +926,10 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_PM5_SMB_TEMP) [ADC_AMUX_THM3] = ADC_CHAN_TEMP("amux_thm3", 1, SCALE_HW_CALIB_PM5_SMB_TEMP) - [ADC_GPIO1_PU2] = ADC_CHAN_TEMP("gpio1_pu2", 1, - SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC_GPIO2_PU2] = ADC_CHAN_TEMP("gpio2_pu2", 1, - SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO1_PU1] = ADC_CHAN_VOLT("usb_tem1_adc_v", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_GPIO2_PU1] = ADC_CHAN_VOLT("usb_tem2_adc_v", 1, + SCALE_HW_CALIB_DEFAULT) [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 492a971b95b56728c84dac932432c12a56bc737b..b571dc10dc37582a450a22a74d10fbc1f5d19d8d 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -31,6 +31,7 @@ #include #include #include +#include struct gpio_button_data { const struct gpio_keys_button *button; @@ -373,6 +374,8 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) return; } + oem_check_force_dump_key(button->code, state); + if (type == EV_ABS) { if (state) input_event(input, type, button->code, button->value); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 3d7ca037962d8af617ea88a9c0e8d15e03ea8802..72c60fed40eeaa11c143d552f07608a6c71e7b0c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -184,6 +184,18 @@ config INPUT_QPNP_POWER_ON reporting the change in status of the KPDPWR_N line (connected to the power-key) as well as reset features. +config KEY_FLUSH + bool "Key trigger flush" + depends on PANIC_FLUSH + default y + help + This option enables device driver support for flush blk devices using + panic_flush module triggered by qpnp power key. + + panic_flush.o must be compiled. + + If unsure, say Y. + config INPUT_QTI_HAPTICS tristate "Haptics support for QTI PMIC" depends on MFD_SPMI_PMIC diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 0fd3003490a526cf8bbaec77cbcb7ae04f4e8ffc..f894407ced8054a3cfba3491fe36f899bb9ff217 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -26,6 +26,20 @@ #include #include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + #define PMIC_VER_8941 0x01 #define PMIC_VERSION_REG 0x0105 #define PMIC_VERSION_REV4_REG 0x0103 @@ -190,42 +204,6 @@ struct pon_regulator { bool enabled; }; -struct qpnp_pon { - struct device *dev; - struct regmap *regmap; - struct input_dev *pon_input; - struct qpnp_pon_config *pon_cfg; - struct pon_regulator *pon_reg_cfg; - struct list_head list; - struct delayed_work bark_work; - struct dentry *debugfs; - u16 base; - u8 subtype; - u8 pon_ver; - u8 warm_reset_reason1; - u8 warm_reset_reason2; - int num_pon_config; - int num_pon_reg; - int pon_trigger_reason; - int pon_power_off_reason; - u32 dbc_time_us; - u32 uvlo; - int warm_reset_poff_type; - int hard_reset_poff_type; - int shutdown_poff_type; - int resin_warm_reset_type; - int resin_hard_reset_type; - int resin_shutdown_type; - bool is_spon; - bool store_hard_reset_reason; - bool resin_hard_reset_disable; - bool resin_shutdown_disable; - bool ps_hold_hard_reset_disable; - bool ps_hold_shutdown_disable; - bool kpdpwr_dbc_enable; - bool resin_pon_reset; - ktime_t kpdpwr_last_release_time; -}; static int pon_ship_mode_en; module_param_named( @@ -243,66 +221,107 @@ static u32 s1_delay[PON_S1_COUNT_MAX + 1] = { }; static const char * const qpnp_pon_reason[] = { - [0] = "Triggered from Hard Reset", + /*PON_PON_REASON1 | 0x000008C0*/ + [0] = "Triggered from Hard Reset(check POFF reason for the trigger)", [1] = "Triggered from SMPL (Sudden Momentary Power Loss)", [2] = "Triggered from RTC (RTC Alarm Expiry)", [3] = "Triggered from DC (DC Charger Insertion)", [4] = "Triggered from USB (USB Charger Insertion)", - [5] = "Triggered from PON1 (Secondary PMIC)", - [6] = "Triggered from CBL (External Power Supply)", + [5] = "Triggered from PON1 (Secondary PMIC pm8150 same as CBL)", + [6] = "Triggered from CBL (External Power Supply/USB Charger Insertion)", [7] = "Triggered from KPD (Power Key Press)", + /*0x08c1*/ + [8] = "N/A", + [9] = "N/A", + [10] = "N/A", + [11] = "N/A", + [12] = "N/A", + [13] = "N/A", + [14] = "N/A", + [15] = "N/A", + /*PPON_WARM_RESET_REASON1 | 0x000008C2*/ + [16] = "SOFT Triggered by Software(Register write to PMIC to perform a reset)", + [17] = "Triggered by PS_HOLD", + [18] = "Triggered by PMIC Watchdog", + [19] = "Triggered by Keypad_Reset1 (Routed internally from keypad combo)", + [20] = "Triggered by Keypad_Reset2 (Routed internally from keypad combo)", + [21] = "Triggered by simultaneous KPDPWR_N + RESIN_N", + [22] = "Triggred by RESIN_N", + [23] = "Triggered by KPDPWR_N", + /* 0x000008C3*/ + [24] = "N/A", + [25] = "N/A", + [26] = "N/A", + [27] = "N/A", + [28] = "N/A", + [29] = "N/A", + [30] = "N/A", + [31] = "N/A", + /*PON_ON_REASON | 0x000008C4*/ + [32] = "N/A", + [33] = "N/A", + [34] = "N/A", + [35] = "N/A", + [36] = "N/A", + [37] = "N/A", + [38] = "PON_SEQ PMIC entered ON state because of a normal powering-on sequence", + [39] = "WARM_SEQ PMIC entered ON state because of a warm-reset sequence", }; #define POFF_REASON_FAULT_OFFSET 16 #define POFF_REASON_S3_RESET_OFFSET 32 static const char * const qpnp_poff_reason[] = { + /*PON_POFF_REASON1 | 0x000008C5*/ /* QPNP_PON_GEN1 POFF reasons */ - [0] = "Triggered from SOFT (Software)", + [0] = "Triggered from SOFT (Software Register write to PMIC to perform a reset)", [1] = "Triggered from PS_HOLD (PS_HOLD/MSM Controlled Shutdown)", [2] = "Triggered from PMIC_WD (PMIC Watchdog)", - [3] = "Triggered from GP1 (Keypad_Reset1)", - [4] = "Triggered from GP2 (Keypad_Reset2)", + [3] = "Triggered from GP1 (Keypad_Reset1 Routed internally from keypad combo)", + [4] = "Triggered from GP2 (Keypad_Reset2 Routed internally from keypad combo)", [5] = "Triggered from KPDPWR_AND_RESIN (Power Key and Reset Line)", [6] = "Triggered from RESIN_N (Reset Line/Volume Down Key)", [7] = "Triggered from KPDPWR_N (Long Power Key Hold)", + /*0x08c6*/ [8] = "N/A", [9] = "N/A", [10] = "N/A", - [11] = "Triggered from CHARGER (Charger ENUM_TIMER, BOOT_DONE)", - [12] = "Triggered from TFT (Thermal Fault Tolerance)", - [13] = "Triggered from UVLO (Under Voltage Lock Out)", - [14] = "Triggered from OTST3 (Over Temperature)", - [15] = "Triggered from STAGE3 (Stage 3 Reset)", - - /* QPNP_PON_GEN2 FAULT reasons */ - [16] = "Triggered from GP_FAULT0", - [17] = "Triggered from GP_FAULT1", - [18] = "Triggered from GP_FAULT2", - [19] = "Triggered from GP_FAULT3", - [20] = "Triggered from MBG_FAULT", - [21] = "Triggered from OVLO (Over Voltage Lock Out)", - [22] = "Triggered from UVLO (Under Voltage Lock Out)", - [23] = "Triggered from AVDD_RB", - [24] = "N/A", - [25] = "N/A", - [26] = "N/A", - [27] = "Triggered from FAULT_FAULT_N", - [28] = "Triggered from FAULT_PBS_WATCHDOG_TO", - [29] = "Triggered from FAULT_PBS_NACK", - [30] = "Triggered from FAULT_RESTART_PON", - [31] = "Triggered from OTST3 (Over Temperature)", - + [11] = "N/A", + [12] = "N/A", + [13] = "N/A", + [14] = "N/A", + [15] = "N/A", + /*PON_OFF_REASON | 0x000008C7*/ + [16] = "N/A", + [17] = "N/A", + [18] = "RAW_XVDD_SHD both battery and coin-cell absent", + [19] = "RAW_DVDD_SHD battery remove but coin-cell present", + [20] = "IMMEDIATE_XVDD_SHUTDOWN S2 Reset", + [21] = "PMIC entered OFF state because of a S3 Reset", + [22] = "PMIC entered OFF state because of a fault-handling sequence", + [23] = "PMIC entered OFF state because of a normal powering-off sequence", + /*PON_FAULT_REASON1 | 0x000008C8*/ + /*kba-190509012910*/ + [24] = "GP_FAULT0 VREG_FAULT_Broadcast or XO_HALT", + [25] = "GP_FAULT1 Asserts upon PBS fault", + [26] = "GP_FAULT2 Asserted upon PBS watchdog bite", + [27] = "GP_FAULT3 Asserts upon SPMI watchdog bite", + [28] = "MGB_FAULT (Master bandgap (voltage reference))", + [29] = "Triggered by OVLO event (overvoltage Lockout)", + [30] = "Triggered by UVLO event (Under-voltage Lockout)", + [31] = "Triggered by AVDD_RB event",// + /*PON_FAULT_REASON2 | 0x000008C9*/ /* QPNP_PON_GEN2 S3_RESET reasons */ [32] = "N/A", [33] = "N/A", [34] = "N/A", - [35] = "N/A", - [36] = "Triggered from S3_RESET_FAULT_N", - [37] = "Triggered from S3_RESET_PBS_WATCHDOG_TO", - [38] = "Triggered from S3_RESET_PBS_NACK", - [39] = "Triggered from S3_RESET_KPDPWR_ANDOR_RESIN", + [35] = "Triggered by FAULT_N bus", + [36] = "Triggered by PBS WATCHDOG", + [37] = "PBS_NACK Triggered by PBS NACK event",// + [38] = "RESTART_PON Triggered by RESTART PON", + [39] = "Triggered by (OTST3 Over-temperature Stage 3)", }; +static bool is_black_screen; static int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { @@ -941,6 +960,24 @@ static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) switch (cfg->pon_type) { case PON_KPDPWR: pon_rt_bit = QPNP_PON_KPDPWR_N_SET; + if ((pon_rt_sts & pon_rt_bit) == 0) { + pr_info("Power-Key UP\n"); + schedule_work(&pon->up_work); + cancel_delayed_work(&pon->press_work); +#ifdef CONFIG_KEY_FLUSH + cancel_delayed_work(&pon->press_work_flush); + panic_flush_device_cache_circled_off(); +#endif + } else { + pr_info("Power-Key DOWN\n"); + // Check if it is black screen at the time of Power key press + is_black_screen = dsi_panel_backlight_get() != 0 ? + false : true; + schedule_delayed_work(&pon->press_work, msecs_to_jiffies(4000)); +#ifdef CONFIG_KEY_FLUSH + schedule_delayed_work(&pon->press_work_flush, msecs_to_jiffies(7000)); +#endif + } break; case PON_RESIN: pon_rt_bit = QPNP_PON_RESIN_N_SET; @@ -978,6 +1015,8 @@ static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) cfg->old_state = !!key_status; + oem_check_force_dump_key(cfg->key_code, key_status); + return 0; } @@ -1126,6 +1165,133 @@ static void bark_work_func(struct work_struct *work) } } +int check_powerkey_count(int press) +{ + int ret = 0; + int param_poweroff_count = 0; + + ret = get_param_by_index_and_offset(13, 0x30, ¶m_poweroff_count, + sizeof(param_poweroff_count)); + + if (press) + param_poweroff_count++; + else + param_poweroff_count--; + + ret = set_param_by_index_and_offset(13, 0x30, ¶m_poweroff_count, + sizeof(param_poweroff_count)); + pr_info("param_poweroff_count=%d\n", param_poweroff_count); + return 0; +} + +int qpnp_powerkey_state_check(struct qpnp_pon *pon, int up) +{ + int rc = 0; + + if (get_boot_mode() != MSM_BOOT_MODE_NORMAL) + return 0; + + if (up) { + rc = atomic_read(&pon->press_count); + if (rc < 1) { + atomic_inc(&pon->press_count); + check_powerkey_count(1); + } + } else { + rc = atomic_read(&pon->press_count); + if (rc > 0) { + atomic_dec(&pon->press_count); + check_powerkey_count(0); + } + } + return 0; +} + +static void up_work_func(struct work_struct *work) +{ + struct qpnp_pon *pon = + container_of(work, struct qpnp_pon, up_work); + + qpnp_powerkey_state_check(pon, 0); +} + +static void press_work_func(struct work_struct *work) +{ + int boot_mode; + bool is_black_screen_now; + bool black_screen_detected = false; + int rc; + uint pon_rt_sts = 0; + struct qpnp_pon_config *cfg; + struct qpnp_pon *pon = + container_of(work, struct qpnp_pon, press_work.work); + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (!cfg) { + dev_err(pon->dev, "Invalid config pointer\n"); + goto err_return; + } + /* check the RT status to get the current status of the line */ + rc = regmap_read(pon->regmap, QPNP_PON_RT_STS(pon), &pon_rt_sts); + if (rc) { + dev_err(pon->dev, "Unable to read PON RT status\n"); + goto err_return; + } + if ((pon_rt_sts & QPNP_PON_KPDPWR_N_SET) == 1) { + qpnp_powerkey_state_check(pon, 1); + dev_err(pon->dev, "after 4s Power-Key is still DOWN\n"); + is_black_screen_now = dsi_panel_backlight_get() != 0 ? false : true; + // Mark as black screen only when backlight is off at the time of + // power key press and also after 4s of power key press then only + // black screen detect is valid to handle + if (is_black_screen == true && is_black_screen_now == true) + black_screen_detected = true; + pr_info("bl_screen=%d bl_screen_now=%d, bl_screen_det=%d\n", + is_black_screen, is_black_screen_now, black_screen_detected); + boot_mode = get_boot_mode(); + if (black_screen_detected == true && boot_mode == MSM_BOOT_MODE_NORMAL) { + pr_info(" ============== BLACK SCREEN DETECTED =========="); + oem_force_minidump_mode(); + show_state_filter(TASK_UNINTERRUPTIBLE); + panic("power key still pressed\n"); + } + } + msleep(20); + ksys_sync(); +err_return: + return; +} + +#ifdef CONFIG_KEY_FLUSH +static void press_work_flush_func(struct work_struct *work) +{ + int rc; + uint pon_rt_sts = 0; + struct qpnp_pon_config *cfg; + struct qpnp_pon *pon = + container_of(work, struct qpnp_pon, press_work_flush.work); + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (!cfg) { + dev_err(pon->dev, "Invalid config pointer\n"); + goto err_return; + } + /* check the RT status to get the current status of the line */ + rc = regmap_read(pon->regmap, QPNP_PON_RT_STS(pon), &pon_rt_sts); + if (rc) { + dev_err(pon->dev, "Unable to read PON RT status\n"); + goto err_return; + } + if ((pon_rt_sts & QPNP_PON_KPDPWR_N_SET) == 1) { + qpnp_powerkey_state_check(pon, 1); + panic_flush_device_cache_circled_on(); + dev_err(pon->dev, "after 7s Pwr-Key is still DOWN, circle flush\n"); + } +err_return: + return; +} +#endif + static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon) { struct qpnp_pon *pon = _pon; @@ -1156,6 +1322,85 @@ static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon) return IRQ_HANDLED; } +static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg); + +static unsigned int pwr_dump_enabled = -1; +static unsigned int long_pwr_dump_enabled = -1; + +static int param_set_pwr_dump_enabled(const char *val, const struct kernel_param *kp) +{ + unsigned long enable; + struct qpnp_pon *pon = sys_reset_dev; + struct qpnp_pon_config *cfg = NULL; + int rc; + + if (!val || kstrtoul(val, 0, &enable) || enable > 1) + return -EINVAL; + + cfg = qpnp_get_cfg(pon, 0); /*0 means pwr key */ + if (!cfg) + return -EINVAL; + pr_info("pwr_dump_enabled = %d and request enable = %d\n", + pwr_dump_enabled, (unsigned int)enable); + if (pwr_dump_enabled != enable) { + cfg->s1_timer = 1352; /*reduce this time */ + cfg->s2_timer = 2000; + cfg->s2_type = 1;/*change s2 type to warm reset*/ + rc = qpnp_config_reset(pon, cfg); + + /*if we need enable this feature, */ + /*we should disable wakeup capability */ + if (enable) + disable_irq_wake(cfg->state_irq); + else + enable_irq_wake(cfg->state_irq); + pwr_dump_enabled = enable; + } + return 0; +} + +static int param_set_long_press_pwr_dump_enabled +(const char *val, const struct kernel_param *kp) +{ + unsigned long enable; + struct qpnp_pon *pon = sys_reset_dev; + struct qpnp_pon_config *cfg = NULL; + int rc; + + if (!val || kstrtoul(val, 0, &enable) || enable > 1) + return -EINVAL; + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); /*0 means pwr key*/ + if (!cfg) + return -EINVAL; + + pr_info("long_pwr_dump_enabled = %d enable = %d s1_timer =%d\n", + long_pwr_dump_enabled, + (unsigned int)enable, cfg->s1_timer); + + if (long_pwr_dump_enabled != enable) { + + if (enable) { + cfg->s1_timer = 10256; /*reduce this time */ + cfg->s2_timer = 2000; + cfg->s2_type = PON_POWER_OFF_TYPE_WARM_RESET; /*change s2 type warm reset*/ + rc = qpnp_config_reset(pon, cfg); + + } else { + /* Disable S2 reset */ + rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); + } + long_pwr_dump_enabled = enable; + } + return 0; +} + +module_param_call(pwr_dump_enabled, +param_set_pwr_dump_enabled, param_get_uint, &pwr_dump_enabled, 0644); + +module_param_call(long_pwr_dump_enabled, +param_set_long_press_pwr_dump_enabled, +param_get_uint, &long_pwr_dump_enabled, 0644); static int qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) { @@ -2069,6 +2314,266 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) return 0; } +static bool created_pwr_on_off_obj; + +#define PMIC_SID_NUM 2 +#define QPNP_PON_POFF_BUFFER_SIZE 128 + +static struct qpnp_pon *g_pon[PMIC_SID_NUM]; +static bool g_is_cold_boot[PMIC_SID_NUM]; + + +#define PON_ON_LEN 8 +#define PON_OFF_LEN 8 +#define PON_DUMP_LEN 0xd0 + +static int qpnp_get_pon_on_info(struct qpnp_pon *pon, char *buffer, int enable) +{ + struct device *dev = pon->dev; + unsigned char pon_buf[PON_ON_LEN]; + unsigned long pon_sts = 0; + int rc, index; + int i = 0; + int len = 0; + + /* PON reason */ + rc = regmap_bulk_read(pon->regmap, QPNP_PON_REASON1(pon), pon_buf, PON_ON_LEN); + + for (i = 0; i < PON_ON_LEN; i++) { + + pon_sts = pon_sts | ((unsigned long)pon_buf[PON_ON_LEN-i-1] << (PON_ON_LEN-i-1)*8); + pr_debug("SID %d i=%d regs :[0x%x=0x%02x]\n", + to_spmi_device(dev->parent)->usid, i, QPNP_PON_REASON1(pon)+i, pon_buf[i]); + } + + pr_err("SID %d PON_REASON pon_sts=0x%016lx\n", + to_spmi_device(dev->parent)->usid, pon_sts); + if (enable) { + snprintf(buffer, QPNP_PON_POFF_BUFFER_SIZE, + "SID %d PON_REASON pon_sts=0x%016lx\n", + to_spmi_device(dev->parent)->usid, pon_sts); + len += strlen(buffer); + buffer += strlen(buffer); + } + + index = ffs(pon_sts) - 1; + + for_each_set_bit(index, (unsigned long *)&pon_sts, + ARRAY_SIZE(qpnp_pon_reason)) { + if (index >= ARRAY_SIZE(qpnp_pon_reason) || index < 0) { + pr_err("SID %d index=%d on error\n", + to_spmi_device(dev->parent)->usid, index); + } else { + pr_err("SID %d index=%02d on reason: %s\n", + to_spmi_device(dev->parent)->usid, + index, qpnp_pon_reason[index]); + + if (enable) { + snprintf(buffer, QPNP_PON_POFF_BUFFER_SIZE, + "SID %d index=%02d on reason: %s\n", + to_spmi_device(dev->parent)->usid, + index, qpnp_pon_reason[index]); + len += strlen(buffer); + buffer += strlen(buffer); + } + } + } + return 0; +} +static int qpnp_get_pon_off_info(struct qpnp_pon *pon, char *buffer, int enable) +{ + struct device *dev = pon->dev; + unsigned char poff_buf[PON_OFF_LEN]; + unsigned long poff_sts = 0; + int rc, index; + int i = 0; + int len = 0; + /* POFF reason */ + rc = regmap_bulk_read(pon->regmap, QPNP_POFF_REASON1(pon), poff_buf, PON_OFF_LEN); + + for (i = 0; i < PON_OFF_LEN; i++) { + + poff_sts = poff_sts | ((unsigned long)poff_buf[PON_OFF_LEN-i-1] << (PON_OFF_LEN-i-1)*8); + pr_debug("SID %d i=%d regs :[0x%x=0x%02x]\n", + to_spmi_device(dev->parent)->usid, i, QPNP_POFF_REASON1(pon)+i, poff_buf[i]); + } + + pr_err("SID %d POFF_REASON poff_sts=0x%016lx\n", + to_spmi_device(pon->dev->parent)->usid, poff_sts); + if (enable) { + snprintf(buffer, QPNP_PON_POFF_BUFFER_SIZE, + "SID %d POFF_REASON poff_sts=0x%016lx\n", + to_spmi_device(pon->dev->parent)->usid, poff_sts); + len += strlen(buffer); + buffer += strlen(buffer); + } + + index = ffs(poff_sts) - 1; + + for_each_set_bit(index, (unsigned long *)&poff_sts, + ARRAY_SIZE(qpnp_poff_reason)) { + if (index >= ARRAY_SIZE(qpnp_poff_reason) || index < 0) { + pr_err("SID %d index=%02d off error\n", + to_spmi_device(dev->parent)->usid, index); + } else { + pr_err("SID %d index=%02d off reason: %s\n", + to_spmi_device(dev->parent)->usid, index, qpnp_poff_reason[index]); + if (enable) { + snprintf(buffer, QPNP_PON_POFF_BUFFER_SIZE, + "SID %d index=%02d on reason: %s\n", + to_spmi_device(dev->parent)->usid, + index, qpnp_poff_reason[index]); + len += strlen(buffer); + buffer += strlen(buffer); + } + } + } + return 0; +} +static int qpnp_dump_info(struct qpnp_pon *pon) +{ + struct device *dev = pon->dev; + unsigned char dump_buf[PON_DUMP_LEN]; + int rc; + int i = 0; + + /* dump */ + rc = regmap_bulk_read(pon->regmap, 0x0800, dump_buf, PON_DUMP_LEN); + + for (i = 0; i < PON_DUMP_LEN; i++) { + pr_debug("SID %d i=%d regs :[0x%x=0x%02x]\n", + to_spmi_device(dev->parent)->usid, i, 0x0800+i, dump_buf[i]); + } + + return 0; +} + +static ssize_t pwron_reason_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int i; + char *pbuf = buf; + int ret = 0; + + snprintf(pbuf, QPNP_PON_POFF_BUFFER_SIZE, "qpnp_pon_reason :\n"); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + + for (i = 0 ; i < ARRAY_SIZE(qpnp_pon_reason) ; i++) { + snprintf(pbuf, QPNP_PON_POFF_BUFFER_SIZE, + "[%d] : %s\n", i, qpnp_pon_reason[i]); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + } + + for (i = 0 ; i < PMIC_SID_NUM ; i++) { + + /* PON reason */ + if (g_pon[i] == NULL || g_pon[i]->regmap == NULL) + continue; + + qpnp_get_pon_on_info(g_pon[i], pbuf, 1); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + snprintf(pbuf, QPNP_PON_POFF_BUFFER_SIZE, + "SID %d %s boot\n", + to_spmi_device(g_pon[i]->dev->parent)->usid, + g_is_cold_boot[i] ? "cold" : "warm"); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + + } + if (ret) + *(buf+ret-1) = '\n'; + + return ret; +} + +static ssize_t pwroff_reason_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int i; + char *pbuf = buf; + int ret = 0; + + snprintf(pbuf, QPNP_PON_POFF_BUFFER_SIZE, "qpnp_poff_reason :\n"); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + + for (i = 0; i < ARRAY_SIZE(qpnp_poff_reason); i++) { + snprintf(pbuf, QPNP_PON_POFF_BUFFER_SIZE, + "[%d] : %s\n", i, qpnp_poff_reason[i]); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + } + + for (i = 0; i < PMIC_SID_NUM; i++) { + + /* POFF reason */ + if (g_pon[i] == NULL || g_pon[i]->regmap == NULL) + continue; + + qpnp_get_pon_off_info(g_pon[i], pbuf, 1); + ret += strlen(pbuf); + pbuf += strlen(pbuf); + } + if (ret) + *(buf+ret-1) = '\n'; + + return ret; +} + +static struct kobj_attribute pwron_reason_attribute = + __ATTR(pwron_reason, 0444, pwron_reason_show, NULL); +static struct kobj_attribute pwroff_reason_attribute = + __ATTR(pwroff_reason, 0444, pwroff_reason_show, NULL); + +static struct attribute *pwr_on_off_attrs[] = { + &pwron_reason_attribute.attr, + &pwroff_reason_attribute.attr, + NULL, +}; + +static struct attribute_group pwr_on_off_attrs_group = { + .attrs = pwr_on_off_attrs, +}; +static struct kobject *pwr_on_off_kobj; + +static int qpnp_get_pon_on_off_info(struct qpnp_pon *pon, bool cold_boot) +{ + struct device *dev = pon->dev; + unsigned char buf[16]; + + dev_err(dev, "PON@SID%d: %s boot\n\n", + to_spmi_device(dev->parent)->usid, cold_boot ? "cold" : "warm"); + + qpnp_get_pon_on_info(pon, buf, 0); + qpnp_get_pon_off_info(pon, buf, 0); + qpnp_dump_info(pon); + + if (!created_pwr_on_off_obj) { + pwr_on_off_kobj = kobject_create_and_add("pwr_on_off_reason", + NULL); + if (!pwr_on_off_kobj) + dev_err(dev, "kobject_create_and_add for pwr_on_off_reason failed.\n"); + else if (sysfs_create_group(pwr_on_off_kobj, + &pwr_on_off_attrs_group)) { + dev_err(dev, "sysfs_create_group for pwr_on_off_reason failed.\n"); + kobject_put(pwr_on_off_kobj); + } + created_pwr_on_off_obj = true; + } + + if ((to_spmi_device(dev->parent)->usid) < PMIC_SID_NUM) { + g_pon[to_spmi_device(dev->parent)->usid] = pon; + g_is_cold_boot[to_spmi_device(dev->parent)->usid] = cold_boot; + } + + return 0; +} + static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) { struct device *dev = pon->dev; @@ -2129,10 +2634,12 @@ static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) cold_boot ? "cold" : "warm"); } else { pon->pon_trigger_reason = index; + /* dev_info(dev, "PMIC@SID%d Power-on reason: %s and '%s' boot\n", to_spmi_device(dev->parent)->usid, qpnp_pon_reason[index], cold_boot ? "cold" : "warm"); + */ } /* POFF reason */ @@ -2158,9 +2665,11 @@ static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) to_spmi_device(dev->parent)->usid); } else { pon->pon_power_off_reason = index; + /* dev_info(dev, "PMIC@SID%d: Power-off reason: %s\n", to_spmi_device(dev->parent)->usid, qpnp_poff_reason[index]); + */ } if ((pon->pon_trigger_reason == PON_SMPL || @@ -2168,6 +2677,7 @@ static int qpnp_pon_read_hardware_info(struct qpnp_pon *pon, bool sys_reset) of_property_read_bool(dev->of_node, "qcom,uvlo-panic")) { panic("UVLO occurred"); } + qpnp_get_pon_on_off_info(pon, cold_boot); return 0; } @@ -2306,6 +2816,10 @@ static int qpnp_pon_probe(struct platform_device *pdev) to_spmi_device(dev->parent)->usid, pon->num_pon_config, pon->num_pon_reg); + // Save PON register map of PM7250B whose slave id is 2 + if (to_spmi_device(dev->parent)->usid == 2) + op_pm8998_regmap_register(pon->regmap); + rc = qpnp_pon_read_hardware_info(pon, sys_reset); if (rc) return rc; @@ -2321,6 +2835,11 @@ static int qpnp_pon_probe(struct platform_device *pdev) dev_set_drvdata(dev, pon); INIT_DELAYED_WORK(&pon->bark_work, bark_work_func); + INIT_DELAYED_WORK(&pon->press_work, press_work_func); +#ifdef CONFIG_KEY_FLUSH + INIT_DELAYED_WORK(&pon->press_work_flush, press_work_flush_func); +#endif + INIT_WORK(&pon->up_work, up_work_func); rc = qpnp_pon_parse_dt_power_off_config(pon); if (rc) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 3d0ae38d550a98dbecf8582db0c12c486a198023..390baa90bad7e7f6673c2500f29a96c9c7e7c0ad 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -41,9 +41,12 @@ #include #include - +/* Add for battery historian */ +#include #include "irq-gic-common.h" +unsigned int qrtr_first_msg = 1; + struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; @@ -371,7 +374,12 @@ static void gic_show_resume_irq(struct gic_chip_data *gic) else if (desc->action && desc->action->name) name = desc->action->name; + /* Add for battery historian */ + if (name != NULL) + log_wakeup_reason(irq); + pr_warn("%s: %d triggered %s\n", __func__, irq, name); + qrtr_first_msg = 0; } } diff --git a/drivers/irqchip/msm_show_resume_irq.c b/drivers/irqchip/msm_show_resume_irq.c index 1bf7040249ff45d9d0333240d5e309c4ae2fc88c..40497a872211b6f411e2c46d1745b8eecef1d953 100644 --- a/drivers/irqchip/msm_show_resume_irq.c +++ b/drivers/irqchip/msm_show_resume_irq.c @@ -7,7 +7,7 @@ #include #include -int msm_show_resume_irq_mask; +int msm_show_resume_irq_mask = 1; module_param_named( debug_mask, msm_show_resume_irq_mask, int, 0664); diff --git a/drivers/media/platform/msm/broadcast/tspp.c b/drivers/media/platform/msm/broadcast/tspp.c index 7b7f28f2b44df9ea5990c1c9426ed4c314664f6a..1615751120abaae7056eca8138a196b3a6cf355d 100644 --- a/drivers/media/platform/msm/broadcast/tspp.c +++ b/drivers/media/platform/msm/broadcast/tspp.c @@ -3080,7 +3080,7 @@ static int msm_tspp_probe(struct platform_device *pdev) for (i = 0; i < TSPP_TSIF_INSTANCES; i++) tsif_debugfs_init(&device->tsif[i], i); - wakeup_source_init(&device->ws, dev_name(&pdev->dev)); + wakeup_source_register(&(pdev->dev), dev_name(&pdev->dev)); /* set up pointers to ram-based 'registers' */ device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0; diff --git a/drivers/media/platform/msm/cvp/msm_cvp_core.c b/drivers/media/platform/msm/cvp/msm_cvp_core.c index a4a86def16161552000928407988e59712337c39..f970d1df4b988ebf3b0841c7df3142915f34d6e0 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_core.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include @@ -367,14 +367,39 @@ EXPORT_SYMBOL(msm_cvp_open); static void msm_cvp_cleanup_instance(struct msm_cvp_inst *inst) { + bool empty; + int max_retries; + if (!inst) { dprintk(CVP_ERR, "%s: invalid params\n", __func__); return; } + max_retries = inst->core->resources.msm_cvp_hw_rsp_timeout >> 1; + +wait: + mutex_lock(&inst->cvpdspbufs.lock); + empty = list_empty(&inst->cvpdspbufs.list); + if (!empty && max_retries > 0) { + mutex_unlock(&inst->cvpdspbufs.lock); + usleep_range(1000, 2000); + max_retries--; + goto wait; + } + mutex_unlock(&inst->cvpdspbufs.lock); + + dprintk(CVP_DBG, "empty %d, retry %d\n", (int)empty, + (inst->core->resources.msm_cvp_hw_rsp_timeout >> 1) - max_retries); + if (!empty) { + dprintk(CVP_WARN, + "Failed to process frames before session close\n"); + } + if (cvp_comm_release_persist_buffers(inst)) dprintk(CVP_ERR, "Failed to release persist buffers\n"); + + dprintk(CVP_DBG, "Done cvp cleanup instance\n"); } int msm_cvp_destroy(struct msm_cvp_inst *inst) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index cb027ed1f8c35ca5415dbd60f0e4b4c8792c48a1..73c7da07221fa77a34a0740e09aeec61e42aee60 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -373,7 +373,10 @@ static int uid_cputime_show(struct seq_file *m, void *v) u64 total_stime = uid_entry->stime + uid_entry->active_stime; seq_printf(m, "%d: %llu %llu\n", uid_entry->uid, - ktime_to_us(total_utime), ktime_to_us(total_stime)); + (unsigned long long)ktime_to_ms( + total_utime) * USEC_PER_MSEC, + (unsigned long long)ktime_to_ms( + total_stime) * USEC_PER_MSEC); } rt_mutex_unlock(&uid_lock); diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index ecbe47ecd716b78eb39885284a7839f4002fea7a..ac5d97a7b049c3c108e4b15e45885b898d164d96 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -662,7 +662,8 @@ static int cnss_set_pci_link(struct cnss_pci_data *pci_priv, bool link_up) if (pci_priv->drv_connected_last) { cnss_pr_vdbg("Use PCIe DRV suspend\n"); pm_ops = MSM_PCIE_DRV_SUSPEND; - cnss_set_pci_link_status(pci_priv, PCI_GEN1); + if (pci_priv->device_id != QCA6390_DEVICE_ID) + cnss_set_pci_link_status(pci_priv, PCI_GEN1); } else { pm_ops = MSM_PCIE_SUSPEND; } diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 26e114f6c2e41b05dd2b759816e6c0896374fca8..44f8ee872ff1c1827134d95ea42157699bd42eb8 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -60,6 +60,12 @@ source "drivers/nfc/s3fwrn5/Kconfig" source "drivers/nfc/st95hf/Kconfig" endmenu +config NXP_NFC_ESE_DEVICE + tristate "NXP NFC ESE Driver Controller" + +source "drivers/nfc/nxp/ese/Kconfig" +source "drivers/nfc/nxp/nfc/Kconfig" + config NFC_NQ tristate "QTI NCI based NFC Controller Driver for NQx" depends on I2C diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 5661fd6adf96b95ee07a2258b26f9da91762d430..006274afc80b46824391df2e86ed14c0783e9c13 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/ obj-$(CONFIG_NFC_ST95HF) += st95hf/ obj-$(CONFIG_NFC_NQ) += nq-nci.o +obj-$(CONFIG_NXP_NFC_ESE_DEVICE) += nxp/ diff --git a/drivers/nfc/nq-nci.h b/drivers/nfc/nq-nci.h index dee13be8ffb7dcbc1691071f30c41130823786be..6ff879dc7a7ea04fb4559774670acf10cdffe403 100644 --- a/drivers/nfc/nq-nci.h +++ b/drivers/nfc/nq-nci.h @@ -27,7 +27,12 @@ #define DEV_COUNT 1 #define DEVICE_NAME "nq-nci" #define CLASS_NAME "nqx" -#define MAX_BUFFER_SIZE (320) +/* + * From MW 11.04 buffer size increased to support + * frame size of 554 in FW download mode + * Frame len(2) + Frame Header(6) + DATA(512) + HASH(32) + CRC(2) + RFU(4) + */ +#define MAX_BUFFER_SIZE (558) #define WAKEUP_SRC_TIMEOUT (2000) #define NCI_HEADER_LEN 3 #define NCI_PAYLOAD_IDX 3 diff --git a/drivers/nfc/nxp/Makefile b/drivers/nfc/nxp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4b2a2c77f11e744a12de1a8e8d0774bc10690e47 --- /dev/null +++ b/drivers/nfc/nxp/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_NXP_NFC_ESE_DEVICE) += ese/ +obj-$(CONFIG_NXP_NFC_ESE_DEVICE) += nfc/ \ No newline at end of file diff --git a/drivers/nfc/nxp/ese/Kconfig b/drivers/nfc/nxp/ese/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..b751dd949000758db07dd8df756b000201d92eef --- /dev/null +++ b/drivers/nfc/nxp/ese/Kconfig @@ -0,0 +1,15 @@ +config NXP_ESE_SN1XX + bool "Nxp ESE sn1xx Controller" + ---help--- + You'll have to say Y if your computer contains an sn1xx SPI device that + you want to use under Linux. + + You can say N here if you don't have any sn1xx SPI connected to your computer. + +config NXP_ESE_PN8XT + bool "Nxp ESE pn8xt Controller" + ---help--- + You'll have to say Y if your computer contains an pn8xt SPI device that + you want to use under Linux. + + You can say N here if you don't have any pn8xt SPI connected to your computer. diff --git a/drivers/nfc/nxp/ese/Makefile b/drivers/nfc/nxp/ese/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a0ce82eab5374d50d09ffef89c757c618a79cffd --- /dev/null +++ b/drivers/nfc/nxp/ese/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for ese devices +# +p73-objs = ese.o sn1xx.o pn8xt.o +obj-$(CONFIG_NXP_NFC_ESE_DEVICE) += p73.o +ccflags-$(CONFIG_NXP_ESE_SN1XX) := -DNFC_PLATFORM=sn1xx +ccflags-$(CONFIG_NXP_ESE_PN8XT) := -DNFC_PLATFORM=pn8xt + +# obj-y += p73.o +# ccflags-y := -DNFC_PLATFORM=pn8xt \ No newline at end of file diff --git a/drivers/nfc/nxp/ese/ese.c b/drivers/nfc/nxp/ese/ese.c new file mode 100644 index 0000000000000000000000000000000000000000..c17f9ff24142cfd3abe20e566937cf7a994f2479 --- /dev/null +++ b/drivers/nfc/nxp/ese/ese.c @@ -0,0 +1,346 @@ +/* + * The original Work has been changed by NXP Semiconductors. + * Copyright 2013-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +/* + * Copyright 2017 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../nfc/nfc.h" + +#include "ese.h" +#include "sn1xx.h" +#include "pn8xt.h" + +/*Compile time function calls based on the platform selection*/ +#define platform_func(prefix, postfix) prefix##postfix +#define func(prefix, postfix) platform_func(prefix, postfix) + +#define MAX_BUFFER_SIZE func(NFC_PLATFORM, _max_buffer_size) + + +static ssize_t ese_dev_read(struct file *filp, char __user *ubuf, + size_t len, loff_t *offset) +{ + ssize_t ret = -EFAULT; + struct ese_dev *ese_dev = filp->private_data; + // char rx_buf[MAX_BUFFER_SIZE]; + unsigned char *rx_buf = NULL; + mutex_lock(&ese_dev->mutex); + if (len > MAX_BUFFER_SIZE) { + len = MAX_BUFFER_SIZE; + } + + rx_buf = ese_dev->kbuf; + if (!rx_buf) { + pr_info("%s: device doesn't exist anymore.\n", __func__); + ret = -ENODEV; + return ret; + } + memset(rx_buf, 0, len); + ret = spi_read(ese_dev->spi, rx_buf, len); + if (0 > ret) { + pr_err("%s failed to read from SPI\n", __func__); + mutex_unlock(&ese_dev->mutex); + return -EIO; + } + if (copy_to_user(ubuf, rx_buf, len)) { + pr_err("%s failed to copy from user\n", __func__); + mutex_unlock(&ese_dev->mutex); + return -EFAULT; + } + mutex_unlock(&ese_dev->mutex); + return ret; +} + +static ssize_t ese_dev_write(struct file *filp, const char __user *ubuf, + size_t len, loff_t *offset) +{ + ssize_t ret = -EFAULT; + struct ese_dev *ese_dev = filp->private_data; + // char tx_buf[MAX_BUFFER_SIZE]; + char *tx_buf = NULL; + + mutex_lock(&ese_dev->write_mutex); + if (len > MAX_BUFFER_SIZE) + len = MAX_BUFFER_SIZE; + +#if 1 + tx_buf = memdup_user(ubuf, len); + if (IS_ERR(tx_buf)) { + pr_info("%s: memdup_user failed\n", __func__); + ret = PTR_ERR(tx_buf); + return ret; + } +#else + memset(tx_buf, 0, sizeof(tx_buf)); + if (copy_from_user(tx_buf, ubuf, len)) { + pr_err("%s: failed to copy from user\n", __func__); + mutex_unlock(&ese_dev->write_mutex); + return -EFAULT; + } +#endif + ret = spi_write(ese_dev->spi, tx_buf, len); + if (ret < 0) { + pr_err("%s: failed to write to SPI\n", __func__); + mutex_unlock(&ese_dev->write_mutex); + return -EIO; + } + kfree(tx_buf); + mutex_unlock(&ese_dev->write_mutex); + return len; +} + +static long ese_dev_ioctl(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + long ret = 0; + struct ese_dev *ese_dev = filep->private_data; + ret = func(NFC_PLATFORM, _ese_dev_ioctl)(ese_dev, cmd, arg); + if (ret != 0) + pr_err("%s: ioctl: cmd = %u, arg = %lu\n", __func__, cmd, arg); + return ret; +} + +static int ese_dev_open(struct inode *inode, struct file *filp) +{ + struct ese_dev *ese_dev = container_of(filp->private_data, + struct ese_dev, device); + mutex_lock(&ese_dev->mutex); + /* Find the NFC parent device if it exists. */ + if (ese_dev->nfcc_data == NULL) { + struct device *nfc_dev = bus_find_device_by_name( + &i2c_bus_type, + NULL, + ese_dev->nfcc_name); + if (!nfc_dev) { + pr_err("%s: cannot find NFC controller '%s'\n", + __func__, ese_dev->nfcc_name); + mutex_unlock(&ese_dev->mutex); + return -ENODEV; + } + ese_dev->nfcc_data = dev_get_drvdata(nfc_dev); + if (!ese_dev->nfcc_data) { + pr_err("%s: cannot find NFC controller device data\n", + __func__); + put_device(nfc_dev); + mutex_unlock(&ese_dev->mutex); + return -ENODEV; + } + pr_info("%s: NFC controller found\n", __func__); + ese_dev->nfcc_device = nfc_dev; + } + mutex_unlock(&ese_dev->mutex); + func(NFC_PLATFORM, _ese_dev_open)(ese_dev); + filp->private_data = ese_dev; + pr_info("%s: major,minor: %d,%d\n", + __func__, imajor(inode), iminor(inode)); + return 0; +} + +static int ese_dev_release(struct inode *inode, struct file *filp) +{ + struct ese_dev *ese_dev = filp->private_data; + func(NFC_PLATFORM, _ese_dev_release)(ese_dev); + pr_info("%s: released\n", __func__); + return 0; +} + +/* possible fops on the ese device */ +static const struct file_operations ese_dev_fops = { + .owner = THIS_MODULE, + .read = ese_dev_read, + .write = ese_dev_write, + .open = ese_dev_open, + .release = ese_dev_release, + .unlocked_ioctl = ese_dev_ioctl, +}; + +static int ese_probe(struct spi_device *spi) +{ + int ret; + unsigned int rst_gpio; + unsigned int max_speed_hz; + struct ese_dev *ese_dev; + struct device_node *np = dev_of_node(&spi->dev); + + /*if (get_second_board_absent() == 1) { + pr_err("%s second board absent, don't probe p73",__func__); + return -EINVAL; + }*/ + + pr_debug("%s: called\n", __func__); + if (!np) { + pr_err("%s: device tree data missing\n", __func__); + return -EINVAL; + } + ese_dev = kzalloc(sizeof(*ese_dev), GFP_KERNEL); + if (ese_dev == NULL) { + pr_err("%s: No memory\n", __func__); + return -ENOMEM; + } + + ese_dev->kbuflen = MAX_BUFFER_SIZE; + ese_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL); + if (!ese_dev->kbuf) { + pr_err("failed to allocate memory for ese_dev->kbuf"); + ret = -ENOMEM; + goto err_free_dev; + } + + ese_dev->spi = spi; + ese_dev->device.minor = MISC_DYNAMIC_MINOR; + ese_dev->device.name = "p73"; + ese_dev->device.fops = &ese_dev_fops; + ese_dev->device.parent = &spi->dev; + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + ret = of_property_read_u32(np, "spi-max-frequency", + &max_speed_hz); + if (ret < 0) { + pr_err("%s: There's no spi-max-frequency property\n", + __func__); + goto err; + } + spi->max_speed_hz = max_speed_hz; + pr_info("%s: device tree set SPI clock Frequency %u\n", + __func__, spi->max_speed_hz); + ret = spi_setup(spi); + if (ret < 0) { + pr_err("%s: failed to do spi_setup()\n", __func__); + goto err; + } + rst_gpio = of_get_named_gpio(np, "nxp,p61-rst", 0); + if (gpio_is_valid(rst_gpio)) { + ret = gpio_request(rst_gpio, "p61 reset"); + if (ret) { + pr_err("%s: unable to request rst gpio [%d]\n", + __func__, rst_gpio); + goto err; + } + /*soft reset gpio is set to default high*/ + ret = gpio_direction_output(rst_gpio, 1); + if (ret) { + pr_err("%s: cannot set direction for rst gpio [%d]\n", + __func__, rst_gpio); + goto err; + } + } else { + /* rst gpio not required for latest platform*/ + pr_info("%s: rst gpio not provided\n", __func__); + } + + ret = of_property_read_string(np, "nxp,nfcc", &ese_dev->nfcc_name); + if (ret < 0) { + pr_err("%s: nxp,nfcc invalid or missing in device tree (%d)\n", + __func__, ret); + goto err; + } + pr_info("%s: device tree set '%s' as eSE power controller\n", + __func__, ese_dev->nfcc_name); + + ret = misc_register(&ese_dev->device); + if (ret) { + pr_err("%s: misc_register failed\n", __func__); + goto err; + } + pr_info("%s: eSE is configured\n", __func__); + spi_set_drvdata(spi, ese_dev); + + mutex_init(&ese_dev->mutex); + mutex_init(&ese_dev->write_mutex); + return 0; +err: + kfree(ese_dev->kbuf); +err_free_dev: + kfree(ese_dev); + return ret; +} + + +static int ese_remove(struct spi_device *spi) +{ + struct ese_dev *ese_dev = spi_get_drvdata(spi); + int ret = 0; + if (!ese_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + return -ENODEV; + } + /* If we have a NFC device, release it. */ + if (ese_dev->nfcc_device) { + put_device(ese_dev->nfcc_device); + ese_dev->nfcc_data = NULL; + ese_dev->nfcc_device = NULL; + } + misc_deregister(&ese_dev->device); + mutex_destroy(&ese_dev->mutex); + mutex_destroy(&ese_dev->write_mutex); + kfree(ese_dev); + return ret; +} + +static struct of_device_id ese_match_table[] = { + { .compatible = "nxp,p61", }, + { } +}; +MODULE_DEVICE_TABLE(of, ese_match_table); +static struct spi_driver ese_driver = { + .driver = { + .name = "p61", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + .of_match_table = ese_match_table, + }, + .probe = ese_probe, + .remove = ese_remove, +}; + +/* + * module load/unload record keeping + */ + +static int __init ese_dev_init(void) +{ + pr_info("Loading NXP ESE driver\n"); + return spi_register_driver(&ese_driver); +} +module_init(ese_dev_init); + +static void __exit ese_dev_exit(void) +{ + pr_info("Unloading NXP ESE driver\n"); + spi_unregister_driver(&ese_driver); +} + +module_exit(ese_dev_exit); +MODULE_DESCRIPTION("NXP ESE SPI driver"); +MODULE_AUTHOR("Google Inc"); +MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/nxp/ese/ese.h b/drivers/nfc/nxp/ese/ese.h new file mode 100644 index 0000000000000000000000000000000000000000..bce4327d02a6e5dbb8c7e1f35ec43a11b11235fe --- /dev/null +++ b/drivers/nfc/nxp/ese/ese.h @@ -0,0 +1,38 @@ +/* + * The original Work has been changed by NXP Semiconductors. + * Copyright 2013-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +/* + * Copyright 2017 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _NXP_ESE_H_ +#define _NXP_ESE_H_ +#define NXP_ESE_MAGIC 0xEA + +/* Device specific structure */ +struct ese_dev { + struct spi_device *spi; + struct device *nfcc_device; + struct nfc_dev *nfcc_data; + struct mutex mutex; + struct mutex write_mutex; /* write mutex */ + struct miscdevice device; + const char *nfcc_name; + size_t kbuflen; + u8 *kbuf; +}; + +#endif //_NXP_ESE_H_ \ No newline at end of file diff --git a/drivers/nfc/nxp/ese/pn8xt.c b/drivers/nfc/nxp/ese/pn8xt.c new file mode 100644 index 0000000000000000000000000000000000000000..e0811813866f85be5af2a68d4b1146db9af2d552 --- /dev/null +++ b/drivers/nfc/nxp/ese/pn8xt.c @@ -0,0 +1,76 @@ +/* + * Copyright 2013-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../nfc/nfc.h" +#include "../nfc/pn8xt.h" + +#include "ese.h" +#include "pn8xt.h" + +extern long pn8xt_nfc_ese_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg); + +long pn8xt_ese_dev_ioctl(struct ese_dev *ese_dev, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + pr_debug("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + switch (cmd) { + case PN8XT_ESE_SET_SPI_PWR: + ret = pn8xt_nfc_ese_ioctl(ese_dev->nfcc_data, PN8XT_SET_SPI_PWR, arg); + break; + case PN8XT_ESE_GET_SPI_STATUS: + ret = pn8xt_nfc_ese_ioctl(ese_dev->nfcc_data, PN8XT_GET_PWR_STATUS, arg); + break; + case PN8XT_ESE_GET_ACCESS: + ret = pn8xt_nfc_ese_ioctl(ese_dev->nfcc_data, PN8XT_GET_ESE_ACCESS, arg); + break; + case PN8XT_ESE_SET_PWR_SCM: + ret = pn8xt_nfc_ese_ioctl(ese_dev->nfcc_data, PN8XT_SET_POWER_SCM, arg); + break; + case PN8XT_ESE_SET_DN_STATUS: + ret = pn8xt_nfc_ese_ioctl(ese_dev->nfcc_data, PN8XT_SET_DN_STATUS, arg); + break; + case PN8XT_ESE_INHIBIT_PWR_CNTRL: + ret = pn8xt_nfc_ese_ioctl(ese_dev->nfcc_data, PN8XT_SECURE_TIMER_SESSION, arg); + break; + default: + ret = -ENOIOCTLCMD; + pr_err("%s: bad ioctl: cmd = %u, arg = %lu\n", __func__, cmd, arg); + } + pr_debug("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return ret; +} + +void pn8xt_ese_dev_open(struct ese_dev *ese_dev) +{ + pr_info("%s: called\n", __func__); +} + +void pn8xt_ese_dev_release(struct ese_dev *ese_dev) +{ + pr_info("%s: called\n", __func__); +} \ No newline at end of file diff --git a/drivers/nfc/nxp/ese/pn8xt.h b/drivers/nfc/nxp/ese/pn8xt.h new file mode 100644 index 0000000000000000000000000000000000000000..4ec66e51b1677568c03d3c9510579dfb85d23660 --- /dev/null +++ b/drivers/nfc/nxp/ese/pn8xt.h @@ -0,0 +1,36 @@ +/* + * Copyright 2013-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +#ifndef _NXP_ESE_PN8XT_H_ +#define _NXP_ESE_PN8XT_H_ + +#define pn8xt_max_buffer_size 258U + +/* SPI Request NFCC to enable pn8xt ese power, + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define PN8XT_ESE_SET_SPI_PWR _IOW(NXP_ESE_MAGIC, 0x04, unsigned int) +/* SPI or DWP can call this ioctl to get the current + * power state of P61 +*/ +#define PN8XT_ESE_GET_SPI_STATUS _IOR(NXP_ESE_MAGIC, 0x05, unsigned int) +#define PN8XT_ESE_GET_ACCESS _IOW(NXP_ESE_MAGIC, 0x07, unsigned int) +#define PN8XT_ESE_SET_PWR_SCM _IOW(NXP_ESE_MAGIC, 0x08, unsigned int) +#define PN8XT_ESE_SET_DN_STATUS _IOW(NXP_ESE_MAGIC, 0x09, unsigned int) +#define PN8XT_ESE_INHIBIT_PWR_CNTRL _IOW(NXP_ESE_MAGIC, 0x0A, unsigned int) + +long pn8xt_ese_dev_ioctl(struct ese_dev *ese_dev, unsigned int cmd, unsigned long arg); +void pn8xt_ese_dev_open(struct ese_dev *ese_dev); +void pn8xt_ese_dev_release(struct ese_dev *ese_dev); +#endif //_NXP_ESE_PN8XT_H_ \ No newline at end of file diff --git a/drivers/nfc/nxp/ese/sn1xx.c b/drivers/nfc/nxp/ese/sn1xx.c new file mode 100644 index 0000000000000000000000000000000000000000..ba8d0c710150b5ea97ea4f258129bf52e5784fb6 --- /dev/null +++ b/drivers/nfc/nxp/ese/sn1xx.c @@ -0,0 +1,62 @@ +/* + * Copyright 2013-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../nfc/nfc.h" +#include "../nfc/sn1xx.h" + +#include "ese.h" +#include "sn1xx.h" + +extern long sn1xx_nfc_ese_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg); + +long sn1xx_ese_dev_ioctl(struct ese_dev *ese_dev, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + mutex_lock(&ese_dev->mutex); + switch (cmd) { + case SN1XX_ESE_PERFORM_COLD_RESET: + ret = sn1xx_nfc_ese_ioctl(ese_dev->nfcc_data, cmd, arg); + break; + default: + ret = -ENOIOCTLCMD; + pr_err("%s: bad ioctl: cmd = %u, arg = %lu\n", __func__, cmd, arg); + } + mutex_unlock(&ese_dev->mutex); + return ret; +} + +void sn1xx_ese_dev_open(struct ese_dev *ese_dev) +{ + nfc_ese_acquire(ese_dev->nfcc_data); + pr_info("%s: acquired\n", __func__); +} + +void sn1xx_ese_dev_release(struct ese_dev *ese_dev) +{ + nfc_ese_release(ese_dev->nfcc_data); + pr_info("%s: released\n", __func__); +} \ No newline at end of file diff --git a/drivers/nfc/nxp/ese/sn1xx.h b/drivers/nfc/nxp/ese/sn1xx.h new file mode 100644 index 0000000000000000000000000000000000000000..5e656a61fed722b20fa20b2371835a2303e34234 --- /dev/null +++ b/drivers/nfc/nxp/ese/sn1xx.h @@ -0,0 +1,23 @@ +/* + * Copyright 2013-2019 NXP + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +#ifndef _NXP_ESE_SN1XX_H_ +#define _NXP_ESE_SN1XX_H_ + +#define sn1xx_max_buffer_size 780U + +#define SN1XX_ESE_PERFORM_COLD_RESET _IOW(NXP_ESE_MAGIC, 0x0C, long) + +long sn1xx_ese_dev_ioctl(struct ese_dev *ese_dev, unsigned int cmd, unsigned long arg); +void sn1xx_ese_dev_open(struct ese_dev *ese_dev); +void sn1xx_ese_dev_release(struct ese_dev *ese_dev); +#endif //_NXP_ESE_SN1XX_H_ \ No newline at end of file diff --git a/drivers/nfc/nxp/nfc/Kconfig b/drivers/nfc/nxp/nfc/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..64ad7d21505ba9631af01c42a748d681ab785e9e --- /dev/null +++ b/drivers/nfc/nxp/nfc/Kconfig @@ -0,0 +1,15 @@ +config NXP_NFC_SN1XX + bool "Nxp NFC sn1xx Controller" + ---help--- + You'll have to say Y if your computer contains an sn1xx I2C device that + you want to use under Linux. + + You can say N here if you don't have any sn1xx I2C connected to your computer. + +config NXP_NFC_PN8XT + bool "Nxp NFC pn8xt Controller" + ---help--- + You'll have to say Y if your computer contains an pn8xt I2C device that + you want to use under Linux. + + You can say N here if you don't have any pn8xt I2C connected to your computer. \ No newline at end of file diff --git a/drivers/nfc/nxp/nfc/Makefile b/drivers/nfc/nxp/nfc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0424d50b43f7e4bcecfeb7b0c4075b42955d0b5c --- /dev/null +++ b/drivers/nfc/nxp/nfc/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for nfc devices +# +pn553-objs = nfc.o sn1xx.o pn8xt.o +obj-$(CONFIG_NXP_NFC_ESE_DEVICE) += pn553.o +ccflags-$(CONFIG_NXP_NFC_SN1XX) := -DNFC_PLATFORM=sn1xx +ccflags-$(CONFIG_NXP_NFC_PN8XT) := -DNFC_PLATFORM=pn8xt + +# obj-y += pn553.o +# ccflags-y := -DNFC_PLATFORM=pn8xt \ No newline at end of file diff --git a/drivers/nfc/nxp/nfc/nfc.c b/drivers/nfc/nxp/nfc/nfc.c new file mode 100644 index 0000000000000000000000000000000000000000..790a2db25eab32534f60b2c3fcb5ea7aeb758b80 --- /dev/null +++ b/drivers/nfc/nxp/nfc/nfc.c @@ -0,0 +1,729 @@ +/* + * The original Work has been changed by NXP Semiconductors. + * Copyright 2013-2019 NXP + * + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "nfc.h" +#include "sn1xx.h" +#include "pn8xt.h" + +#include + +#define MAX_BUFFER_SIZE (512) +#define WAKEUP_SRC_TIMEOUT (5000) +#define MAX_RETRY_COUNT 3 +#define MAX_SECURE_SESSIONS 1 + +#define HWINFO 1 + +/*Compile time function calls based on the platform selection*/ +#define platform_func(prefix, postfix) prefix##postfix +#define func(prefix, postfix) platform_func(prefix, postfix) + +#if HWINFO +struct hw_type_info hw_info; +#endif + +#if HWINFO +static void check_hw_info(struct nfc_dev *nfc_dev); +#endif + +void nfc_disable_irq(struct nfc_dev *nfc_dev) +{ + unsigned long flags; + spin_lock_irqsave(&nfc_dev->irq_enabled_lock, flags); + if (nfc_dev->irq_enabled) { + disable_irq_nosync(nfc_dev->client->irq); + nfc_dev->irq_enabled = false; + } + spin_unlock_irqrestore(&nfc_dev->irq_enabled_lock, flags); +} + +void nfc_enable_irq(struct nfc_dev *nfc_dev) +{ + unsigned long flags; + spin_lock_irqsave(&nfc_dev->irq_enabled_lock, flags); + if (!nfc_dev->irq_enabled) { + nfc_dev->irq_enabled = true; + enable_irq(nfc_dev->client->irq); + } + spin_unlock_irqrestore(&nfc_dev->irq_enabled_lock, flags); +} + +static irqreturn_t nfc_dev_irq_handler(int irq, void *dev_id) +{ + struct nfc_dev *nfc_dev = dev_id; + unsigned long flags; +if (device_may_wakeup(&nfc_dev->client->dev)) + pm_wakeup_event(&nfc_dev->client->dev, WAKEUP_SRC_TIMEOUT); + + nfc_disable_irq(nfc_dev); + spin_lock_irqsave(&nfc_dev->irq_enabled_lock, flags); + nfc_dev->count_irq++; + spin_unlock_irqrestore(&nfc_dev->irq_enabled_lock, flags); + wake_up(&nfc_dev->read_wq); + return IRQ_HANDLED; +} + +static ssize_t nfc_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct nfc_dev *nfc_dev = filp->private_data; + // char tmp[MAX_BUFFER_SIZE]; + unsigned char *tmp = NULL; + int ret; + int irq_gpio_val = 0; + if (!nfc_dev) { + return -ENODEV; + } + + if (count > MAX_BUFFER_SIZE) + count = MAX_BUFFER_SIZE; + + mutex_lock(&nfc_dev->read_mutex); + irq_gpio_val = gpio_get_value(nfc_dev->irq_gpio); + if (irq_gpio_val == 0) { + if (filp->f_flags & O_NONBLOCK) { + dev_err(&nfc_dev->client->dev, + ":f_flags has O_NONBLOCK. EAGAIN\n"); + ret = -EAGAIN; + goto err; + } + while (1) { + ret = 0; + nfc_enable_irq(nfc_dev); + if (!gpio_get_value(nfc_dev->irq_gpio)) { + ret = wait_event_interruptible(nfc_dev->read_wq, + !nfc_dev->irq_enabled); + } + if (ret) + goto err; + nfc_disable_irq(nfc_dev); + if (gpio_get_value(nfc_dev->irq_gpio)) + break; + pr_warning("%s: spurious interrupt detected\n", __func__); + } + } + tmp = nfc_dev->kbuf; + if (!tmp) { + pr_info("%s: device doesn't exist anymore\n", __func__); + ret = -ENODEV; + goto err; + } + memset(tmp, 0x00, count); + /* Read data */ + ret = i2c_master_recv(nfc_dev->client, tmp, count); + mutex_unlock(&nfc_dev->read_mutex); + /* delay of 1ms for slow devices*/ + udelay(1000); + if (ret < 0) { + pr_err("%s: i2c_master_recv returned %d\n", __func__, ret); + goto err; + } + if (ret > count) { + pr_err("%s: received too many bytes from i2c (%d)\n", + __func__, ret); + ret = -EIO; + goto err; + } + if (copy_to_user(buf, tmp, ret)) { + pr_warning("%s : failed to copy to user space\n", __func__); + ret = -EFAULT; + goto err; + } + return ret; +err: + mutex_unlock(&nfc_dev->read_mutex); + return ret; +} + +static ssize_t nfc_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct nfc_dev *nfc_dev = filp->private_data; + // char tmp[MAX_BUFFER_SIZE]; + char *tmp = NULL; + int ret = 0; + if (!nfc_dev) { + return -ENODEV; + } + if (count > MAX_BUFFER_SIZE) { + count = MAX_BUFFER_SIZE; + } + +#if 1 + tmp = memdup_user(buf, count); + if (IS_ERR(tmp)) { + pr_info("%s: memdup_user failed\n", __func__); + ret = PTR_ERR(tmp); + return ret; + } +#else + if (copy_from_user(tmp, buf, count)) { + pr_err("%s : failed to copy from user space\n", __func__); + return -EFAULT; + } +#endif + ret = i2c_master_send(nfc_dev->client, tmp, count); + if (ret != count) { + pr_err("%s: i2c_master_send returned %d\n", __func__, ret); + ret = -EIO; + } + /* delay of 1ms for slow devices*/ + udelay(1000); + kfree(tmp); + return ret; +} + +/* Callback to claim the embedded secure element + * It is a blocking call, in order to protect the ese + * from being reset from outside when it is in use. + */ +void nfc_ese_acquire(struct nfc_dev *nfc_dev) +{ + mutex_lock(&nfc_dev->ese_status_mutex); + pr_debug("%s: ese acquired\n", __func__); +} + +/* Callback to release the embedded secure element + * it should be released, after completion of any + * operation (usage or reset) of ese. + */ +void nfc_ese_release(struct nfc_dev *nfc_dev) +{ + mutex_unlock(&nfc_dev->ese_status_mutex); + pr_debug("%s: ese released\n", __func__); +} + +static int nfc_dev_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + struct nfc_dev *nfc_dev = container_of(filp->private_data, + struct nfc_dev, nfc_device); + + filp->private_data = nfc_dev; + pr_info("%s: %d,%d\n", __func__, imajor(inode), iminor(inode)); + return ret; +} + +long nfc_dev_ioctl(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + long ret = 0; + struct nfc_dev *nfc_dev = filep->private_data; + ret = func(NFC_PLATFORM, _nfc_ioctl)(nfc_dev, cmd, arg); + if (ret != 0) + pr_err("%s: ioctl: cmd = %u, arg = %lu\n", __func__, cmd, arg); + return ret; +} + +static const struct file_operations nfc_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = nfc_dev_read, + .write = nfc_dev_write, + .open = nfc_dev_open, + .unlocked_ioctl = nfc_dev_ioctl, +}; + +struct nfc_platform_data { + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int ese_pwr_gpio; +}; + +static int nfc_parse_dt(struct device *dev, + struct nfc_platform_data *data) +{ + int ret = 0; + struct device_node *np = dev->of_node; + + data->irq_gpio = of_get_named_gpio(np, "nxp,pn544-irq", 0); + if ((!gpio_is_valid(data->irq_gpio))) + return -EINVAL; + + data->ven_gpio = of_get_named_gpio(np, "nxp,pn544-ven", 0); + if ((!gpio_is_valid(data->ven_gpio))) + return -EINVAL; + + data->firm_gpio = of_get_named_gpio(np, "nxp,pn544-fw-dwnld", 0); + if ((!gpio_is_valid(data->firm_gpio))) + return -EINVAL; + + //required for old platform only + data->ese_pwr_gpio = of_get_named_gpio(np, "nxp,pn544-ese-pwr", 0); + if ((!gpio_is_valid(data->ese_pwr_gpio))) + data->ese_pwr_gpio = -EINVAL; + + pr_info("%s: %d, %d, %d, %d, error:%d\n", __func__, + data->irq_gpio, data->ven_gpio, data->firm_gpio, + data->ese_pwr_gpio, ret); + return ret; +} + +static int nfc_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + int irqn = 0; + struct nfc_platform_data platform_data; + struct nfc_dev *nfc_dev; + pr_debug("%s: enter\n", __func__); + + /*if (get_second_board_absent() == 1) { + pr_err("second board absent, don't probe pn5xx\n", __func__); + ret = -ENODEV; + goto err; + }*/ + + ret = nfc_parse_dt(&client->dev, &platform_data); + if (ret) { + pr_err("%s : failed to parse\n", __func__); + goto err; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("%s : need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err; + } + nfc_dev = kzalloc(sizeof(*nfc_dev), GFP_KERNEL); + if (nfc_dev == NULL) { + ret = -ENOMEM; + goto err; + } + nfc_dev->client = client; + if (gpio_is_valid(platform_data.ven_gpio)) { + ret = gpio_request(platform_data.ven_gpio, "nfc_reset_gpio"); + if (ret) { + pr_err("%s: unable to request nfc reset gpio [%d]\n", + __func__, platform_data.ven_gpio); + goto err_mem; + } + ret = gpio_direction_output(platform_data.ven_gpio, 0); + if (ret) { + pr_err("%s: unable to set direction for nfc reset gpio [%d]\n", + __func__, platform_data.ven_gpio); + goto err_en_gpio; + } + } else { + pr_err("%s: nfc reset gpio not provided\n", __func__); + goto err_mem; + } + if (gpio_is_valid(platform_data.irq_gpio)) { + ret = gpio_request(platform_data.irq_gpio, "nfc_irq_gpio"); + if (ret) { + pr_err("%s: unable to request nfc irq gpio [%d]\n", + __func__, platform_data.irq_gpio); + goto err_en_gpio; + } + ret = gpio_direction_input(platform_data.irq_gpio); + if (ret) { + pr_err("%s: unable to set direction for nfc irq gpio [%d]\n", + __func__, platform_data.irq_gpio); + goto err_irq_gpio; + } + irqn = gpio_to_irq(platform_data.irq_gpio); + if (irqn < 0) { + ret = irqn; + goto err_irq_gpio; + } + client->irq = irqn; + } else { + pr_err("%s: irq gpio not provided\n", __func__); + goto err_en_gpio; + } + if (gpio_is_valid(platform_data.firm_gpio)) { + ret = gpio_request(platform_data.firm_gpio, "nfc_firm_gpio"); + if (ret) { + pr_err("%s: unable to request nfc firmware gpio [%d]\n", + __func__, platform_data.firm_gpio); + goto err_irq_gpio; + } + ret = gpio_direction_output(platform_data.firm_gpio, 0); + if (ret) { + pr_err("%s: cannot set direction for nfc firmware gpio [%d]\n", + __func__, platform_data.firm_gpio); + goto err_firm_gpio; + } + } else { + pr_err("%s: firm gpio not provided\n", __func__); + goto err_irq_gpio; + } + if (gpio_is_valid(platform_data.ese_pwr_gpio)) { + ret = gpio_request(platform_data.ese_pwr_gpio, "nfc-ese_pwr"); + if (ret) { + pr_err("%s: unable to request nfc ese gpio [%d]\n", + __func__, platform_data.ese_pwr_gpio); + goto err_firm_gpio; + } + ret = gpio_direction_output(platform_data.ese_pwr_gpio, 0); + if (ret) { + pr_err("%s: cannot set direction for nfc ese gpio [%d]\n", + __func__, platform_data.ese_pwr_gpio); + goto err_ese_pwr_gpio; + } + } else { + /* ese gpio not required for latest platform*/ + pr_info("%s: ese pwr gpio not provided\n", __func__); + } + + nfc_dev->kbuflen = MAX_BUFFER_SIZE; + nfc_dev->kbuf = kzalloc(MAX_BUFFER_SIZE, GFP_KERNEL); + if (!nfc_dev->kbuf) { + pr_err("failed to allocate memory for pn544_dev->kbuf\n"); + ret = -ENOMEM; + goto err_ese_pwr_gpio; + } + + nfc_dev->ven_gpio = platform_data.ven_gpio; + nfc_dev->irq_gpio = platform_data.irq_gpio; + nfc_dev->firm_gpio = platform_data.firm_gpio; + nfc_dev->ese_pwr_gpio = platform_data.ese_pwr_gpio; + /* init mutex and queues */ + init_waitqueue_head(&nfc_dev->read_wq); + mutex_init(&nfc_dev->read_mutex); + mutex_init(&nfc_dev->ese_status_mutex); + spin_lock_init(&nfc_dev->irq_enabled_lock); + + nfc_dev->nfc_device.minor = MISC_DYNAMIC_MINOR; + nfc_dev->nfc_device.name = "pn553"; + nfc_dev->nfc_device.fops = &nfc_dev_fops; + + ret = misc_register(&nfc_dev->nfc_device); + if (ret) { + pr_err("%s: misc_register failed\n", __func__); + goto err_misc_register; + } + /* NFC_INT IRQ */ + nfc_dev->irq_enabled = true; + ret = request_irq(client->irq, nfc_dev_irq_handler, + IRQF_TRIGGER_HIGH, client->name, nfc_dev); + if (ret) { + pr_err("request_irq failed\n"); + goto err_request_irq_failed; + } + device_init_wakeup(&client->dev, true); + device_set_wakeup_capable(&client->dev, true); + enable_irq_wake(nfc_dev->client->irq); + i2c_set_clientdata(client, nfc_dev); + /*Enable IRQ and VEN*/ + nfc_enable_irq(nfc_dev); + /*call to platform specific probe*/ + ret = func(NFC_PLATFORM, _nfc_probe)(nfc_dev); + if (ret != 0) { + pr_err("%s: probing platform failed\n", __func__); + goto err_request_irq_failed; + }; + pr_info("%s: probing NXP NFC exited successfully\n", __func__); + pr_info("%s: Name of nfcc: %s.\n", __func__, dev_name(&client->dev)); + +#if HWINFO + /* + * This function is used only if + * hardware info is required during probe*/ + check_hw_info(nfc_dev); +#endif + return 0; + +err_request_irq_failed: + misc_deregister(&nfc_dev->nfc_device); +err_misc_register: + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->ese_status_mutex); + kfree(nfc_dev->kbuf); +err_ese_pwr_gpio: + gpio_free(platform_data.ese_pwr_gpio); +err_firm_gpio: + gpio_free(platform_data.firm_gpio); +err_irq_gpio: + gpio_free(platform_data.irq_gpio); +err_en_gpio: + gpio_free(platform_data.ven_gpio); +err_mem: + kfree(nfc_dev); +err: + pr_err("%s: probing NXP NFC driver failed, check hardware\n", __func__); + return ret; +} + +static int nfc_remove(struct i2c_client *client) +{ + int ret = 0; + struct nfc_dev *nfc_dev; + pr_info("%s: remove device\n", __func__); + nfc_dev = i2c_get_clientdata(client); + if (!nfc_dev) { + pr_err("%s: device doesn't exist anymore\n", __func__); + ret = -ENODEV; + goto err; + } + /*call to platform specific remove*/ + ret = func(NFC_PLATFORM, _nfc_remove)(nfc_dev); + if (ret != 0) { + pr_err("%s: platform failed\n", __func__); + goto err; + } + free_irq(client->irq, nfc_dev); + misc_deregister(&nfc_dev->nfc_device); + mutex_destroy(&nfc_dev->read_mutex); + mutex_destroy(&nfc_dev->ese_status_mutex); + gpio_free(nfc_dev->ese_pwr_gpio); + gpio_free(nfc_dev->firm_gpio); + gpio_free(nfc_dev->irq_gpio); + gpio_free(nfc_dev->ven_gpio); + kfree(nfc_dev->kbuf); + kfree(nfc_dev); +err: + return ret; +} + +static int nfc_suspend(struct device *device) +{ + struct i2c_client *client = to_i2c_client(device); + struct nfc_dev *nfc_dev; + bool ven_enabled = false; + int err = -1; + nfc_dev = i2c_get_clientdata(client); + ven_enabled = func(NFC_PLATFORM, _nfc_ven_enabled)(nfc_dev); + if (ven_enabled && gpio_get_value(nfc_dev->irq_gpio)) { + pm_wakeup_event(&nfc_dev->client->dev, WAKEUP_SRC_TIMEOUT); + return err; + } + nfc_enable_irq(nfc_dev); + return 0; +} + +static int nfc_resume(struct device *device) +{ + return 0; +} + +static const struct dev_pm_ops nfc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(nfc_suspend, nfc_resume) +}; + +static const struct i2c_device_id nfc_id[] = { + { "pn544", 0 }, + { } +}; + +static struct of_device_id nfc_match_table[] = { + {.compatible = "nxp,pn544",}, + {} +}; +MODULE_DEVICE_TABLE(of, nfc_match_table); + +static struct i2c_driver nfc_driver = { + .id_table = nfc_id, + .probe = nfc_probe, + .remove = nfc_remove, + .driver = { + .owner = THIS_MODULE, + .name = "pn544", + .of_match_table = nfc_match_table, + .pm = &nfc_pm_ops, + }, +}; + +#if HWINFO +/****************************************************************************** + * Function check_hw_info + * + * Description This function is called during pn544_probe to retrieve + * HW info. + * Useful get HW information in case of previous FW download is + * interrupted and core reset is not allowed. + * This function checks if core reset is allowed, if not + * sets DWNLD_REQ(firm_gpio) , ven reset and sends firmware + * get version command. + * In response HW information will be received. + * + * Returns None + * + ******************************************************************************/ +static void check_hw_info(struct nfc_dev *nfc_dev) { + //char read_data[20]; + int ret, get_version_len = 8, retry_count = 0; + // static uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00}; + char get_version_cmd[] = + {0x00, 0x04, 0xF1, 0x00, 0x00, 0x00, 0x6E, 0xEF}; + + char *tmp = kzalloc(MAX_BUFFER_SIZE,GFP_KERNEL); + if (tmp == NULL) { + pr_err("%s: failed to allocate memory for transfer data\n", __func__); + return; + } + + memcpy(tmp, get_version_cmd, get_version_len); + + + pr_info("%s :Enter\n", __func__); + + /* + * Ven Reset before sending core Reset + * This is to check core reset is allowed or not. + * If not allowed then previous FW download is interrupted in between + * */ + + /* + * Core reset failed. + * set the DWNLD_REQ , do ven reset + * send firmware download info command + * */ + // pr_err("%s : write failed\n", __func__); + pr_info("%s power on with firmware\n", __func__); + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + if (nfc_dev->firm_gpio) { + func(NFC_PLATFORM, _update_state_out)(nfc_dev, ST_DN, true); + gpio_set_value(nfc_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(nfc_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + ret = i2c_master_send(nfc_dev->client, tmp, get_version_len); + if (ret != get_version_len) { + pr_err("%s : write_failed ret=%d\n", __func__,ret); + kfree(tmp); + return ; + } else { + pr_info("%s :data sent\n", __func__); + } + + ret = 0; + + while (retry_count < 10) { + + /* + * Wait for read interrupt + * If spurious interrupt is received retry again + * */ + nfc_enable_irq(nfc_dev); + ret = wait_event_interruptible( + nfc_dev->read_wq, + !nfc_dev->irq_enabled); + + nfc_disable_irq(nfc_dev); + + if (gpio_get_value(nfc_dev->irq_gpio)) + break; + + pr_warning("%s: spurious interrupt detected\n", __func__); + retry_count ++; + } + + if(ret) { + return; + } + + memset(tmp, 0x00, MAX_BUFFER_SIZE); + /* + * Read response data and copy into hw_type_info + * */ + ret = i2c_master_recv(nfc_dev->client, tmp, 14); + + if(ret > 0) { + memcpy(hw_info.data, tmp, ret); + hw_info.len = ret; + pr_info("%s :Hardware Version : %d\n", __func__,hw_info.data[3]); + + switch (hw_info.data[3]) { + case NFCC_NQ_210: + push_component_info(NFC, "NQ210", "NXP"); + break; + case NFCC_NQ_220: + push_component_info(NFC, "NQ220", "NXP"); + break; + case NFCC_NQ_310: + push_component_info(NFC, "NQ310", "NXP"); + break; + case NFCC_NQ_310_V2: + push_component_info(NFC, "NQ310", "NXP"); + break; + case NFCC_NQ_330: + push_component_info(NFC, "NQ330", "NXP"); + break; + case NFCC_PN66T: + push_component_info(NFC, "PN66T", "NXP"); + break; + default: + pr_err("%s: spurious interrupt detected\n", __func__); + break; + } + + } else { + pr_err("%s :Read Failed\n", __func__); + } + func(NFC_PLATFORM, _update_state_out)(nfc_dev, ST_DN, true); + gpio_set_value(nfc_dev->firm_gpio, 0); + msleep(10); + gpio_set_value(nfc_dev->ven_gpio, 0); + udelay(1000); + kfree(tmp); +} +#endif + +static int __init nfc_dev_init(void) +{ + pr_info("Loading NXP NFC driver\n"); + return i2c_add_driver(&nfc_driver); +} +module_init(nfc_dev_init); + +static void __exit nfc_dev_exit(void) +{ + pr_info("Unloading NXP NFC driver\n"); + i2c_del_driver(&nfc_driver); +} +module_exit(nfc_dev_exit); + +MODULE_DESCRIPTION("NXP NFC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/nfc/nxp/nfc/nfc.h b/drivers/nfc/nxp/nfc/nfc.h new file mode 100644 index 0000000000000000000000000000000000000000..e7e1bb91ecf5b015d8c955155f84edc4ef4f6492 --- /dev/null +++ b/drivers/nfc/nxp/nfc/nfc.h @@ -0,0 +1,92 @@ +/* + * The original Work has been changed by NXP Semiconductors. + * Copyright 2013-2019 NXP + * + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _NXP_NFC_H_ +#define _NXP_NFC_H_ +#define NXP_NFC_MAGIC 0xE9 + +/* Device specific structure */ +struct nfc_dev { + wait_queue_head_t read_wq; + struct mutex read_mutex; + struct mutex ese_status_mutex; + struct i2c_client *client; + struct miscdevice nfc_device; + /* NFC GPIO variables */ + unsigned int irq_gpio; + unsigned int ven_gpio; + unsigned int firm_gpio; + unsigned int ese_pwr_gpio; + /* NFC_IRQ state */ + bool irq_enabled; + spinlock_t irq_enabled_lock; + unsigned int count_irq; + /* read buffer*/ + size_t kbuflen; + u8 *kbuf; + /* NFC additional parameters for old platforms */ + void *pdata_op; +}; + +void nfc_disable_irq(struct nfc_dev *nfc_dev); +void nfc_enable_irq(struct nfc_dev *nfc_dev); +void nfc_ese_acquire(struct nfc_dev *nfc_dev); +void nfc_ese_release(struct nfc_dev *nfc_dev); + +struct hw_type_info { + /* + * Response of get_version_cmd will be stored in data + * byte structure : + * byte 0-1 : Header + * byte 2 : Status + * byte 3 : Hardware Version + * byte 4 : ROM code + * byte 5 : 0x00 constant + * byte 6-7 : Protected data version + * byte 8-9 : Trim data version + * byte 10-11 : FW version + * byte 12-13 : CRC + * */ + char data[20]; + int len; +}; + +enum nfcc_chip_variant { + NFCC_NQ_210 = 0x48, /**< NFCC NQ210 */ + NFCC_NQ_220 = 0x58, /**< NFCC NQ220 */ + NFCC_NQ_310 = 0x40, /**< NFCC NQ310 */ + NFCC_NQ_310_V2 = 0x41, /**< NFCC NQ310 */ + NFCC_NQ_330 = 0x51, /**< NFCC NQ330 */ + NFCC_PN66T = 0x18, /**< NFCC PN66T */ + NFCC_NOT_SUPPORTED = 0xFF /**< NFCC is not supported */ +}; +#endif //_NXP_NFC_H_ \ No newline at end of file diff --git a/drivers/nfc/nxp/nfc/pn8xt.c b/drivers/nfc/nxp/nfc/pn8xt.c new file mode 100644 index 0000000000000000000000000000000000000000..fe09a9be762acf38c2b15697315a7314ad88e590 --- /dev/null +++ b/drivers/nfc/nxp/nfc/pn8xt.c @@ -0,0 +1,814 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * 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. + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2019 NXP Semiconductors + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfc.h" +#include "pn8xt.h" + +#define SIG_NFC 44 + +struct pn8xt_dev { + pn8xt_access_st_t cur_state; + pn8xt_pwr_scm_t pwr_scheme; + bool nfc_ven_enabled; + bool spi_ven_enabled; + long service_pid; + struct semaphore ese_access_sema; + struct semaphore svdd_onoff_sema; + struct semaphore dwp_onoff_sema; + struct semaphore dwp_complete_sema; + unsigned long dwpLinkUpdateStat; + unsigned int secure_timer_cnt; + struct timer_list secure_timer; + struct workqueue_struct *pSecureTimerCbWq; + struct nfc_dev *nfc_dev; + struct work_struct wq_task; +}; +static struct pn8xt_dev *pn8xt_dev; +static pn8xt_access_st_t *pn8xt_get_state(struct pn8xt_dev *pn8xt_dev) +{ + return &pn8xt_dev->cur_state; +} + +static void pn8xt_update_state(struct pn8xt_dev *pn8xt_dev, pn8xt_access_st_t state, bool set) +{ + if (state) { + if(set) { + if(pn8xt_dev->cur_state == ST_IDLE) + pn8xt_dev->cur_state = ST_INVALID; + pn8xt_dev->cur_state |= state; + } else { + pn8xt_dev->cur_state ^= state; + if(!pn8xt_dev->cur_state) + pn8xt_dev->cur_state = ST_IDLE; + } + } +} + +void pn8xt_update_state_out(struct nfc_dev *nfc_dev, pn8xt_access_st_t state, bool set) +{ + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + pn8xt_update_state(pn8xt_dev, state, set); +} + +int get_ese_lock(struct pn8xt_dev *pn8xt_dev, int timeout) +{ + unsigned long tempJ = msecs_to_jiffies(timeout); + if(down_timeout(&pn8xt_dev->ese_access_sema, tempJ) != 0) { + printk("get_ese_lock: timeout cur_state = %d\n", pn8xt_dev->cur_state); + return -EBUSY; + } + return 0; +} + +static int signal_handler(pn8xt_access_st_t state, long nfc_pid) +{ + int sigret = 0; + pid_t pid; + struct siginfo sinfo; + struct task_struct *task; + + if(nfc_pid <= 0) { + pr_err("%s: invalid nfc service pid %ld\n", __func__, nfc_pid); + return 0; + } + memset(&sinfo, 0, sizeof(struct siginfo)); + sinfo.si_signo = SIG_NFC; + sinfo.si_code = SI_QUEUE; + sinfo.si_int = state; + pid = nfc_pid; + + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if(task) { + pr_info("%s: %s\n", __func__, task->comm); + sigret = force_sig_info(SIG_NFC, &sinfo, task); + if(sigret < 0) { + pr_err("%s: send_sig_info failed, sigret %d\n", __func__, sigret); + return -1; + } + } else { + pr_err("%s: finding task from PID failed\n", __func__); + return -1; + } + pr_debug("%s: return successfully\n", __func__); + return 0; +} + +static int trigger_onoff(struct pn8xt_dev *pn8xt_dev, pn8xt_access_st_t state) +{ + int timeout = 4500; //timeout in ms + unsigned long timeoutInJiffies = msecs_to_jiffies(timeout); + struct semaphore *sema; + pr_debug("%s: nfc service_pid: %ld\n", __func__, pn8xt_dev->service_pid); + + if(pn8xt_dev->service_pid <= 0) { + pr_err("%s:Invalid nfc service_pid %ld\n", __func__, pn8xt_dev->service_pid); + return 0; + } + if((state & ST_SPI_SVDD_SY_START) || (state & ST_SPI_SVDD_SY_END)) { + sema = &pn8xt_dev->svdd_onoff_sema; + } else { + sema = &pn8xt_dev->dwp_onoff_sema; + } + sema_init(sema, 0); + if (0 == signal_handler(state, pn8xt_dev->service_pid)) { + pr_debug("%s: Waiting for protection response", __func__); + if(down_timeout(sema, timeoutInJiffies) != 0) { + pr_err("%s: protection: Timeout", __func__); + return -1; + } + msleep(10); + pr_debug("%s: wait protection released", __func__); + } + return (pn8xt_dev->dwpLinkUpdateStat == 0x00) ? 0 : -1; +} + +/* + * pn8xt_nfc_pwr() - power control/firmware download + * @filp: pointer to the file descriptor + * @arg: mode that we want to move to + * + * Device power control. Depending on the arg value, device moves to + * different states + * (arg = 0):FW_DL GPIO = 0, VEN GPIO = 0 + * (arg = 1):FW_DL GPIO = 0, VEN GPIO = 1 + * (arg = 2):FW_DL GPIO = 1, KEEP VEN down/up - firmware download mode + * Return: 0 on success and error on failure + */ +static long pn8xt_nfc_pwr(struct nfc_dev *nfc_dev, unsigned long arg) +{ + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + pn8xt_access_st_t *cur_state = pn8xt_get_state(pn8xt_dev); + if (!pn8xt_dev) { + pr_err("%s: pn8xt_dev doesn't exist anymore\n", __func__); + return -ENODEV; + } + switch(arg) { + case 0: + /* power off */ + pr_debug("%s power off\n", __func__); + if (nfc_dev->firm_gpio) { + if ((*cur_state & (ST_WIRED | ST_SPI | ST_SPI_PRIO))== 0){ + pn8xt_update_state(pn8xt_dev, ST_IDLE, true); + } + gpio_set_value(nfc_dev->firm_gpio, 0); + } + pn8xt_dev->nfc_ven_enabled = false; + /* Don't change Ven state if spi made it high */ + if ((pn8xt_dev->spi_ven_enabled == false && !(pn8xt_dev->secure_timer_cnt)) + || (pn8xt_dev->pwr_scheme == PN80T_EXT_PMU_SCM)) { + gpio_set_value(nfc_dev->ven_gpio, 0); + } + break; + case 1: + /* power on */ + pr_debug("%s power on\n", __func__); + if (nfc_dev->firm_gpio) { + if ((*cur_state & (ST_WIRED|ST_SPI|ST_SPI_PRIO))== 0){ + pn8xt_update_state(pn8xt_dev, ST_IDLE, true); + } + if(*cur_state & ST_DN){ + pn8xt_update_state(pn8xt_dev, ST_DN, false); + } + gpio_set_value(nfc_dev->firm_gpio, 0); + } + pn8xt_dev->nfc_ven_enabled = true; + if (pn8xt_dev->spi_ven_enabled == false || (pn8xt_dev->pwr_scheme == PN80T_EXT_PMU_SCM)) { + gpio_set_value(nfc_dev->ven_gpio, 1); + } + break; + case 2: + if(*cur_state & (ST_SPI|ST_SPI_PRIO) && (pn8xt_dev->pwr_scheme != PN80T_EXT_PMU_SCM)) { + /* NFCC fw/download should not be allowed when SPI is being used*/ + pr_err("%s NFCC should not be allowed to reset/FW download \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + pn8xt_dev->nfc_ven_enabled = true; + if ((pn8xt_dev->spi_ven_enabled == false && !(pn8xt_dev->secure_timer_cnt)) + || (pn8xt_dev->pwr_scheme == PN80T_EXT_PMU_SCM)) + { + /* power on with firmware download (requires hw reset) + */ + pr_debug("%s power on with firmware\n", __func__); + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + if (nfc_dev->firm_gpio) { + pn8xt_update_state(pn8xt_dev, ST_DN, true); + gpio_set_value(nfc_dev->firm_gpio, 1); + } + msleep(10); + gpio_set_value(nfc_dev->ven_gpio, 0); + msleep(10); + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + } + break; + case 3: + if(*cur_state & (ST_SPI|ST_SPI_PRIO)) { + return -EPERM; /* Operation not permitted */ + } + if(*cur_state & ST_WIRED) { + pn8xt_update_state(pn8xt_dev, ST_WIRED, false); + } + break; + case 4: + pr_debug("%s FW dwld ioctl called from NFC \n", __func__); + /*NFC Service called FW dwnld*/ + if (nfc_dev->firm_gpio) { + pn8xt_update_state(pn8xt_dev, ST_DN, true); + gpio_set_value(nfc_dev->firm_gpio, 1); + msleep(10); + } + break; + default: + pr_err("%s bad arg %lu\n", __func__, arg); + return -EINVAL; + }; + return 0; +} + +static long pn8xt_ese_pwr(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg) +{ + bool isSignalTriggerReqd = !(arg & 0x10);/*5th bit to/not trigger signal*/ + unsigned long pwrLevel = arg & 0x0F; + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + pn8xt_access_st_t *cur_state = pn8xt_get_state(pn8xt_dev); + if (!pn8xt_dev) { + pr_err("%s: pn8xt_dev doesn't exist anymore\n", __func__); + return -ENODEV; + } + switch(pwrLevel) { + case 0: + pr_debug("%s: power off ese\n", __func__); + if(*cur_state & ST_SPI_PRIO){ + pn8xt_update_state(pn8xt_dev, ST_SPI_PRIO, false); + if (!(*cur_state & ST_JCP_DN)) { + if(!(*cur_state & ST_WIRED)) { + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_START | ST_SPI_PRIO_END); + } else { + signal_handler(ST_SPI_PRIO_END, pn8xt_dev->service_pid); + } + } else if (!(*cur_state & ST_WIRED)) { + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_START); + } + pn8xt_dev->spi_ven_enabled = false; + + if(pn8xt_dev->pwr_scheme == PN80T_EXT_PMU_SCM) + break; + + /*if secure timer is running, Delay the SPI by 25ms after sending End of Apdu + to enable eSE go into DPD gracefully(20ms after EOS+5ms DPD settlement time)*/ + if(pn8xt_dev->secure_timer_cnt) + usleep_range(25000, 30000); + + if (!(*cur_state & ST_WIRED) && !(pn8xt_dev->secure_timer_cnt)) { + gpio_set_value(nfc_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_END); + } + if ((pn8xt_dev->nfc_ven_enabled == false) && !(pn8xt_dev->secure_timer_cnt)) { + gpio_set_value(nfc_dev->ven_gpio, 0); + msleep(10); + } + } else if((*cur_state & ST_SPI) || (*cur_state & ST_SPI_FAILED)) { + if (!(*cur_state & ST_WIRED) && + (pn8xt_dev->pwr_scheme != PN80T_EXT_PMU_SCM) && + !(*cur_state & ST_JCP_DN)) { + if (isSignalTriggerReqd && !(*cur_state & ST_JCP_DN)) { + if(trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_START | ST_SPI_END)) { + pr_debug(" %s DWP link activation failed. Returning..", __func__); + pn8xt_update_state(pn8xt_dev, ST_SPI_FAILED, true); + return -1; + } + } + /*if secure timer is running,Delay the SPI close by 25ms after sending End of Apdu + to enable eSE go into DPD gracefully(20ms after EOS + 5ms DPD settlement time)*/ + if(pn8xt_dev->secure_timer_cnt) + usleep_range(25000, 30000); + + if (!(pn8xt_dev->secure_timer_cnt)) { + gpio_set_value(nfc_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); + if(*cur_state & ST_SPI_FAILED) { + pn8xt_update_state(pn8xt_dev, ST_SPI_FAILED, false); + } + pn8xt_update_state(pn8xt_dev, ST_SPI, false); + if(isSignalTriggerReqd) + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_END); + } + } + /*If JCOP3.2 or 3.3 for handling triple mode + protection signal NFC service */ + else { + if (isSignalTriggerReqd) { + if (!(*cur_state & ST_JCP_DN)) { + if(pn8xt_dev->pwr_scheme == PN80T_LEGACY_PWR_SCM) { + if(trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_START | ST_SPI_END)) { + pr_debug(" %s DWP link activation failed. Returning..", __func__); + pn8xt_update_state(pn8xt_dev, ST_SPI_FAILED, true); + return -1; + } + } else { + signal_handler(ST_SPI_END, pn8xt_dev->service_pid); + } + } else if (pn8xt_dev->pwr_scheme == PN80T_LEGACY_PWR_SCM) { + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_START); + } + } + if(pn8xt_dev->pwr_scheme == PN80T_LEGACY_PWR_SCM) { + gpio_set_value(nfc_dev->ese_pwr_gpio, 0); + if(*cur_state & ST_SPI_FAILED) { + pn8xt_update_state(pn8xt_dev, ST_SPI_FAILED, false); + } + pn8xt_update_state(pn8xt_dev, ST_SPI, false); + if(isSignalTriggerReqd) + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_END); + pr_debug("%s:PN80T legacy ese_pwr_gpio off", __func__); + } + } + pn8xt_dev->spi_ven_enabled = false; + if (pn8xt_dev->nfc_ven_enabled == false && (pn8xt_dev->pwr_scheme != PN80T_EXT_PMU_SCM) + && !(pn8xt_dev->secure_timer_cnt)) { + gpio_set_value(nfc_dev->ven_gpio, 0); + msleep(10); + } + } else { + pr_err("%s:failed, cur_state = %x\n", __func__, *cur_state); + return -EPERM; /* Operation not permitted */ + } + break; + case 1: + pr_err("%s: power on ese\n", __func__); + if (((*cur_state & (ST_SPI|ST_SPI_PRIO)) == 0) || (*cur_state & ST_SPI_FAILED)) { + /*To handle triple mode protection signal + NFC service when SPI session started*/ + if (isSignalTriggerReqd && !(*cur_state & ST_JCP_DN)) { + if(trigger_onoff(pn8xt_dev, ST_SPI)) { + pr_debug(" %s DWP link activation failed. Returning..", __func__); + pn8xt_update_state(pn8xt_dev, ST_SPI_FAILED, true); + return -1; + } + } + pn8xt_dev->spi_ven_enabled = true; + + if(pn8xt_dev->pwr_scheme == PN80T_EXT_PMU_SCM) + break; + if (pn8xt_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(nfc_dev->ese_pwr_gpio, 1); + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); + if(*cur_state & ST_SPI_FAILED) { + pn8xt_update_state(pn8xt_dev, ST_SPI_FAILED, false); + } + pn8xt_update_state(pn8xt_dev, ST_SPI, true); + if (pn8xt_dev->service_pid) { + up(&pn8xt_dev->dwp_complete_sema); + } + } else if ((*cur_state & (ST_SPI|ST_SPI_PRIO)) + && (gpio_get_value(nfc_dev->ese_pwr_gpio)) && (gpio_get_value(nfc_dev->ven_gpio))) { + /* Returning success if SET_SPI_PWR called while already SPI is open */ + return 0; + } else { + pr_info("%s : PN61_SET_SPI_PWR - power on ese failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + break; + case 2: + pr_debug("%s: reset\n", __func__); + if (*cur_state & (ST_IDLE|ST_SPI|ST_SPI_PRIO)) { + if (pn8xt_dev->spi_ven_enabled == false) { + pn8xt_dev->spi_ven_enabled = true; + if ((pn8xt_dev->nfc_ven_enabled == false) && (pn8xt_dev->pwr_scheme != PN80T_EXT_PMU_SCM)) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + } + } + if(pn8xt_dev->pwr_scheme != PN80T_EXT_PMU_SCM && !(pn8xt_dev->secure_timer_cnt)) { + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_START); + gpio_set_value(nfc_dev->ese_pwr_gpio, 0); + trigger_onoff(pn8xt_dev, ST_SPI_SVDD_SY_END); + msleep(10); + if(!gpio_get_value(nfc_dev->ese_pwr_gpio)) + gpio_set_value(nfc_dev->ese_pwr_gpio, 1); + msleep(10); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - reset failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + break; + case 3: + pr_debug("%s: Prio Session Start power on ese\n", __func__); + if ((*cur_state & (ST_SPI | ST_SPI_PRIO)) == 0) { + pn8xt_update_state(pn8xt_dev, ST_SPI_PRIO, true); + if (*cur_state & ST_WIRED) { + trigger_onoff(pn8xt_dev, ST_SPI_PRIO); + } + pn8xt_dev->spi_ven_enabled = true; + if(pn8xt_dev->pwr_scheme != PN80T_EXT_PMU_SCM) { + if (pn8xt_dev->nfc_ven_enabled == false) { + /* provide power to NFCC if, NFC service not provided */ + gpio_set_value(nfc_dev->ven_gpio, 1); + msleep(10); + } + /* pull the gpio to high once NFCC is power on*/ + gpio_set_value(nfc_dev->ese_pwr_gpio, 1); + + /* Delay (10ms) after SVDD_PWR_ON to allow JCOP to bootup (5ms jcop boot time + 5ms guard time) */ + usleep_range(10000, 12000); + } + } else { + pr_err("%s : Prio Session Start power on ese failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + break; + case 4: + pr_debug("%s: Prio Session End called\n", __func__); + if (*cur_state & ST_SPI_PRIO) { + pr_info("%s : PN61_SET_SPI_PWR - Prio Session Ending...\n", __func__); + pn8xt_update_state(pn8xt_dev, ST_SPI_PRIO, false); + /*after SPI prio timeout, the state is changing from SPI prio to SPI */ + pn8xt_update_state(pn8xt_dev, ST_SPI, true); + if (*cur_state & ST_WIRED) { + signal_handler(ST_SPI_PRIO_END, pn8xt_dev->service_pid); + } + } else { + pr_err("%s : PN61_SET_SPI_PWR - Prio Session End failed \n", __func__); + return -EBADRQC; /* Device or resource busy */ + } + break; + case 5: + pr_debug("%s: Up ese_access_sema\n", __func__); + up(&pn8xt_dev->ese_access_sema); + break; + default: + pr_err("%s bad ese pwr arg %lu\n", __func__, arg); + return -EBADRQC; /* Invalid request code */ + }; + return 0; +} + +static long set_jcop_download_state(struct pn8xt_dev *pn8xt_dev, unsigned long arg) +{ + long ret = 0; + pn8xt_access_st_t *cur_state = pn8xt_get_state(pn8xt_dev); + pr_debug("%s::JCOP Dwnld arg = %ld",__func__, arg); + switch(arg) { + case JCP_DN_INIT: + if(pn8xt_dev->service_pid) { + pr_err("%s:nfc service pid %ld", __func__, pn8xt_dev->service_pid); + signal_handler((pn8xt_access_st_t)JCP_DN_INIT, pn8xt_dev->service_pid); + } else { + if (*cur_state & ST_JCP_DN) { + ret = -EINVAL; + } else { + pn8xt_update_state(pn8xt_dev, ST_JCP_DN, true); + } + } + break; + case JCP_DN_START: + if (*cur_state & ST_JCP_DN) { + ret = -EINVAL; + } else { + pn8xt_update_state(pn8xt_dev, ST_JCP_DN, true); + } + break; + case JCP_SPI_DN_COMP: + signal_handler((pn8xt_access_st_t)JCP_DWP_DN_COMP, pn8xt_dev->service_pid); + pn8xt_update_state(pn8xt_dev, ST_JCP_DN, false); + break; + case JCP_DWP_DN_COMP: + pn8xt_update_state(pn8xt_dev, ST_JCP_DN, false); + break; + default: + pr_err("%s: bad ese pwr arg %lu\n", __func__, arg); + return -EBADRQC; /* Invalid request code */ + }; + return ret; +} + +static int set_wired_access(struct nfc_dev *nfc_dev, unsigned long arg) +{ + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + pn8xt_access_st_t *cur_state = pn8xt_get_state(pn8xt_dev); + if (!pn8xt_dev) { + pr_err("%s: pn8xt_dev doesn't exist anymore\n", __func__); + return -ENODEV; + } + switch(arg) { + case 0: + pr_debug("%s: disabling \n", __func__); + if (*cur_state & ST_WIRED) { + pn8xt_update_state(pn8xt_dev, ST_WIRED, false); + } else { + pr_err("%s: failed, cur_state = %x\n", __func__, *cur_state); + return -EPERM; /* Operation not permitted */ + } + break; + case 1: + if (*cur_state) + { + pr_debug("%s: enabling\n", __func__); + pn8xt_update_state(pn8xt_dev, ST_WIRED, true); + if (*cur_state & ST_SPI_PRIO) { + signal_handler(ST_SPI_PRIO, pn8xt_dev->service_pid); + } + } else { + pr_err("%s: enabling failed \n", __func__); + return -EBUSY; /* Device or resource busy */ + } + break; + case 2: + case 3: + pr_debug("%s: obsolete arguments for P67\n", __func__); + break; + case 4: + up(&pn8xt_dev->ese_access_sema); + break; + case 5: + gpio_set_value(nfc_dev->ese_pwr_gpio, 1); + if (gpio_get_value(nfc_dev->ese_pwr_gpio)) { + pr_info("%s: ese_pwr gpio is enabled\n", __func__); + } + break; + case 6: + gpio_set_value(nfc_dev->ese_pwr_gpio, 0); + pr_info("%s: ese_pwr gpio set to low\n", __func__); + break; + default: + pr_err("%s bad arg %lu\n", __func__, arg); + return -EBADRQC; /* Invalid request code */ + }; + return 0; +} + +//static void secure_timer_callback(unsigned long data) +static void secure_timer_callback(struct timer_list *t) +{ + //struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)data; + /* Flush and push the timer callback event to the bottom half(work queue) + to be executed later, at a safer time */ + flush_workqueue(pn8xt_dev->pSecureTimerCbWq); + queue_work(pn8xt_dev->pSecureTimerCbWq, &pn8xt_dev->wq_task); + return; +} + +static long start_seccure_timer(struct pn8xt_dev *pn8xt_dev, unsigned long timer_value) +{ + long ret = -EINVAL; + pr_debug("%s: called\n", __func__); + /* Delete the timer if timer pending */ + if(timer_pending(&pn8xt_dev->secure_timer) == 1) { + pr_debug("%s: delete pending timer \n", __func__); + /* delete timer if already pending */ + del_timer(&pn8xt_dev->secure_timer); + } + /* Start the timer if timer value is non-zero */ + if(timer_value) { + //init_timer(&pn8xt_dev->secure_timer); + //setup_timer(&pn8xt_dev->secure_timer, secure_timer_callback, (unsigned long)pn8xt_dev); + timer_setup(&pn8xt_dev->secure_timer, secure_timer_callback, 0); + + pr_debug("%s:timeout %lums (%lu)\n", __func__, timer_value, jiffies); + ret = mod_timer(&pn8xt_dev->secure_timer, jiffies + msecs_to_jiffies(timer_value)); + if (ret) + pr_err("%s:Error in mod_timer\n", __func__); + } + return ret; +} + +static void secure_timer_workqueue(struct work_struct *wq) +{ + struct pn8xt_dev *pn8xt_dev = container_of(wq, struct pn8xt_dev, wq_task); + struct nfc_dev *nfc_dev = pn8xt_dev->nfc_dev; + pn8xt_access_st_t *cur_state = pn8xt_get_state(pn8xt_dev); + pr_debug("%s:called (%lu).\n", __func__, jiffies); + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: START */ + get_ese_lock(pn8xt_dev, MAX_ESE_ACCESS_TIME_OUT_MS); + pn8xt_update_state(pn8xt_dev, ST_SECURE_MODE, false); + + if((*cur_state & (ST_SPI|ST_SPI_PRIO)) == 0) { + pr_debug("%s: make se_pwer_gpio low, state = %d", __func__, *cur_state); + gpio_set_value(nfc_dev->ese_pwr_gpio, 0); + /* Delay (2.5ms) after SVDD_PWR_OFF for the shutdown settlement time */ + usleep_range(2500, 3000); + if(pn8xt_dev->service_pid == 0x00) { + gpio_set_value(nfc_dev->ven_gpio, 0); + pr_debug("%s: make ven_gpio low, state = %d", __func__, *cur_state); + } + } + pn8xt_dev->secure_timer_cnt = 0; + /* Locking the critical section: ESE_PWR_OFF to allow eSE to shutdown peacefully :: END */ + up(&pn8xt_dev->ese_access_sema); + return; +} + + +static long secure_timer_operation(struct pn8xt_dev *pn8xt_dev, unsigned long arg) +{ + long ret = -EINVAL; + unsigned long timer_value = arg; + + pr_debug("%s: pwr scheme = %d\n", __func__, pn8xt_dev->pwr_scheme); + if(pn8xt_dev->pwr_scheme == PN80T_LEGACY_PWR_SCM) { + ret = start_seccure_timer(pn8xt_dev, timer_value); + if(!ret) { + pn8xt_dev->secure_timer_cnt = 1; + pn8xt_update_state(pn8xt_dev, ST_SECURE_MODE, true); + } else { + pn8xt_dev->secure_timer_cnt = 0; + pn8xt_update_state(pn8xt_dev, ST_SECURE_MODE, false); + pr_debug("%s :timer reset \n", __func__); + } + } else { + pr_info("%s: timer session not applicable\n", __func__); + } + return ret; +} + +long pn8xt_nfc_ese_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + if (!pn8xt_dev) { + pr_err("%s: pn8xt_dev doesn't exist anymore\n", __func__); + return -ENODEV; + } + if (cmd == PN8XT_GET_ESE_ACCESS) { + ret = get_ese_lock(pn8xt_dev, arg); + return ret; + } + + switch (cmd) { + case PN8XT_SET_SPI_PWR: + ret = pn8xt_ese_pwr(nfc_dev, cmd, arg); + break; + case PN8XT_GET_PWR_STATUS: + put_user(pn8xt_dev->cur_state, (int __user *)arg); + break; + case PN8XT_SET_DN_STATUS: + ret = set_jcop_download_state(pn8xt_dev, arg); + break; + case PN8XT_SET_POWER_SCM: + if(arg == PN80T_LEGACY_PWR_SCM || arg == PN80T_EXT_PMU_SCM) + pn8xt_dev->pwr_scheme = arg; + else + pr_err("%s : The power scheme is invalid,\n", __func__); + break; + case PN8XT_SECURE_TIMER_SESSION: + ret = secure_timer_operation(pn8xt_dev, arg); + break; + default: + pr_err("%s bad ioctl %u\n", __func__, cmd); + ret = -EINVAL; + }; + return ret; +} + +bool pn8xt_nfc_ven_enabled(struct nfc_dev *nfc_dev) +{ + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + + return pn8xt_dev->nfc_ven_enabled; +} + +long pn8xt_nfc_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + struct pn8xt_dev *pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + if (!pn8xt_dev) { + pr_err("%s: pn8xt_dev doesn't exist anymore\n", __func__); + return -ENODEV; + } + pr_debug("%s :enter cmd = %u, arg = %ld\n", __func__, cmd, arg); + + switch(cmd) { + case PN8XT_SET_PWR: + ret = pn8xt_nfc_pwr(nfc_dev, arg); + break; + case PN8XT_SET_WIRED_ACCESS: + ret = set_wired_access(nfc_dev, arg); + break; + case PN8XT_REL_SVDD_WAIT: + pn8xt_dev->dwpLinkUpdateStat = arg; + up(&pn8xt_dev->svdd_onoff_sema); + break; + case PN8XT_SET_NFC_SERVICE_PID: + pn8xt_dev->service_pid = arg; + break; + case PN8XT_REL_DWP_WAIT: + pn8xt_dev->dwpLinkUpdateStat = arg; + up(&pn8xt_dev->dwp_onoff_sema); + sema_init(&pn8xt_dev->dwp_complete_sema, 0); + /*release JNI only after all the SPI On related actions are completed*/ + if (down_timeout(&pn8xt_dev->dwp_complete_sema, msecs_to_jiffies(500)) != 0) { + pr_debug("Dwp On/off release wait protection: Timeout"); + } + pr_debug("Dwp On/Off release wait protection : released"); + break; + default: + ret = pn8xt_nfc_ese_ioctl(nfc_dev, cmd, arg); + if (ret) + pr_err("%s bad ioctl %u\n", __func__, cmd); + break; + }; + pr_debug("%s :exit cmd = %u, arg = %ld\n", __func__, cmd, arg); + return ret; +} + +#define SECURE_TIMER_WORK_QUEUE "SecTimerCbWq" +int pn8xt_nfc_probe(struct nfc_dev *nfc_dev) +{ + struct pn8xt_dev *pn8xt_dev; + pn8xt_dev = kzalloc(sizeof(struct pn8xt_dev), GFP_KERNEL); + if (!pn8xt_dev) { + pr_err("failed to allocate memory for pn8xt_dev\n"); + return -ENOMEM; + } + nfc_dev->pdata_op = pn8xt_dev; + pn8xt_dev->cur_state = ST_IDLE; + pn8xt_dev->pwr_scheme = PN80T_LEGACY_PWR_SCM; + pn8xt_dev->secure_timer_cnt = 0; + pn8xt_dev->nfc_ven_enabled = false; + pn8xt_dev->spi_ven_enabled = false; + /* init mutex and queues */ + sema_init(&pn8xt_dev->ese_access_sema, 1); + sema_init(&pn8xt_dev->dwp_complete_sema, 0); + pn8xt_dev->pSecureTimerCbWq = create_workqueue(SECURE_TIMER_WORK_QUEUE); + INIT_WORK(&pn8xt_dev->wq_task, secure_timer_workqueue); + pn8xt_dev->nfc_dev = nfc_dev; + return 0; +} + +int pn8xt_nfc_remove(struct nfc_dev *nfc_dev) +{ + struct pn8xt_dev *pn8xt_dev; + pr_debug("%s: called\n", __func__); + pn8xt_dev = (struct pn8xt_dev *)nfc_dev->pdata_op; + if (!pn8xt_dev) { + pr_err("%s: pn8xt_dev doesn't exist anymore\n", __func__); + return -ENODEV; + } + destroy_workqueue(pn8xt_dev->pSecureTimerCbWq); + pn8xt_dev->cur_state = ST_INVALID; + pn8xt_dev->nfc_ven_enabled = false; + pn8xt_dev->spi_ven_enabled = false; + pn8xt_dev->nfc_dev = NULL; + kfree(pn8xt_dev); + return 0; +} diff --git a/drivers/nfc/nxp/nfc/pn8xt.h b/drivers/nfc/nxp/nfc/pn8xt.h new file mode 100644 index 0000000000000000000000000000000000000000..190f3d21b55b39d7fd88e69677c0876cc1e26030 --- /dev/null +++ b/drivers/nfc/nxp/nfc/pn8xt.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * 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. + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2019 NXP Semiconductors + * * + * 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. + * + ******************************************************************************/ +#ifndef _NXP_NFC_PN8XT_H_ +#define _NXP_NFC_PN8XT_H_ + +/* + * NFC power control via ioctl + * PN8XT_SET_PWR(0): power off + * PN8XT_SET_PWR(1): power on + * PN8XT_SET_PWR(2): reset and power on with firmware download enabled + */ +#define PN8XT_SET_PWR _IOW(NXP_NFC_MAGIC, 0x01, unsigned int) +/* + * SPI Request NFCC to enable ESE power, only in param + * Only for SPI + * level 1 = Enable power + * level 0 = Disable power + */ +#define PN8XT_SET_SPI_PWR _IOW(NXP_NFC_MAGIC, 0x02, unsigned int) + +/* SPI or DWP can call this ioctl to get the current + * power state of ESE + * +*/ +#define PN8XT_GET_PWR_STATUS _IOR(NXP_NFC_MAGIC, 0x03, unsigned int) + +/* DWP side this ioctl will be called + * level 1 = Wired access is enabled/ongoing + * level 0 = Wired access is disabled/stopped +*/ +#define PN8XT_SET_WIRED_ACCESS _IOW(NXP_NFC_MAGIC, 0x04, unsigned int) + +/* + NFC Init will call the ioctl to register the PID with the i2c driver +*/ +#define PN8XT_SET_NFC_SERVICE_PID _IOW(NXP_NFC_MAGIC, 0x05, unsigned int) + +/* + NFC and SPI will call the ioctl to get the i2c/spi bus access +*/ +#define PN8XT_GET_ESE_ACCESS _IOW(NXP_NFC_MAGIC, 0x06, unsigned int) +/* + NFC and SPI will call the ioctl to update the power scheme +*/ +#define PN8XT_SET_POWER_SCM _IOW(NXP_NFC_MAGIC, 0x07, unsigned int) + +/* + NFC will call the ioctl to release the svdd protection +*/ +#define PN8XT_REL_SVDD_WAIT _IOW(NXP_NFC_MAGIC, 0x08, unsigned int) + +/* SPI or DWP can call this ioctl to get the current + * power state of ESE + * +*/ +#define PN8XT_SET_DN_STATUS _IOW(NXP_NFC_MAGIC, 0x09, unsigned int) +/* + NFC will call the ioctl to release the dwp on/off protection +*/ + +#define PN8XT_REL_DWP_WAIT _IOW(NXP_NFC_MAGIC, 0x0A, unsigned int) + +/* + NFC will call the ioctl to start Secure Timer +*/ + +#define PN8XT_SECURE_TIMER_SESSION _IOW(NXP_NFC_MAGIC, 0x0B, unsigned int) + +#define MAX_ESE_ACCESS_TIME_OUT_MS 200 + +typedef enum pn8xt_access_state { + ST_INVALID = 0x0000, + ST_IDLE = 0x0100, /*ESE is free to use */ + ST_WIRED = 0x0200, /*ESE is being accessed by DWP (NFCC)*/ + ST_SPI = 0x0400, /*ESE is being accessed by SPI */ + ST_DN = 0x0800, /*NFCC fw download is in progress */ + ST_SPI_PRIO = 0x1000, /*Start of ESE access by SPI on priority*/ + ST_SPI_PRIO_END = 0x2000, /*End of ESE access by SPI on priority*/ + ST_SPI_END = 0x4000, + ST_JCP_DN = 0x8000, /*JCOP downlad in progress */ + ST_SECURE_MODE = 0x100000, /*secure mode state*/ + ST_SPI_SVDD_SY_START = 0x0001, /*ESE_VDD Low req by SPI*/ + ST_SPI_SVDD_SY_END = 0x0002, /*ESE_VDD is Low by SPI*/ + ST_DWP_SVDD_SY_START = 0x0004, /*ESE_VDD Low req by Nfc*/ + ST_DWP_SVDD_SY_END = 0x0008, /*ESE_VDD is Low by Nfc*/ + ST_SPI_FAILED = 0x0010 /*SPI open/close failed*/ +}pn8xt_access_st_t; + +typedef enum pn8xt_pwr_scheme { + PN80T_LEGACY_PWR_SCM = 0x02, + PN80T_EXT_PMU_SCM, +}pn8xt_pwr_scm_t; + +typedef enum pn8xt_jcop_dwnld_state { + JCP_DN_IDLE = ST_JCP_DN, /* jcop dwnld is ongoing*/ + JCP_DN_INIT=0x8010, /* jcop dwonload init state*/ + JCP_DN_START=0x8020, /* download started */ + JCP_SPI_DN_COMP=0x8040, /* jcop download complete in spi interface*/ + JCP_DWP_DN_COMP=0x8080, /* jcop download complete */ +} pn8xt_jcop_dwnld_state_t; + +long pn8xt_nfc_ese_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg); +long pn8xt_nfc_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg); +bool pn8xt_nfc_ven_enabled(struct nfc_dev *nfc_dev); +int pn8xt_nfc_probe(struct nfc_dev *nfc_dev); +int pn8xt_nfc_remove(struct nfc_dev *nfc_dev); +void pn8xt_update_state_out(struct nfc_dev *nfc_dev, pn8xt_access_st_t state, bool set); +#endif //_NXP_NFC_PN8XT_H_ \ No newline at end of file diff --git a/drivers/nfc/nxp/nfc/sn1xx.c b/drivers/nfc/nxp/nfc/sn1xx.c new file mode 100644 index 0000000000000000000000000000000000000000..50a2717e0a858a2af58a1151b3692adceb28e1dd --- /dev/null +++ b/drivers/nfc/nxp/nfc/sn1xx.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * 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. + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2019 NXP Semiconductors + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfc.h" +#include "sn1xx.h" + +/* + * Power management of the eSE + */ +long sn1xx_nfc_ese_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + pr_debug("%s: cmd = %u, arg = %lu\n", __func__, cmd, arg); + switch(cmd) { + //TODO - add cases for the ESE mechanism + default: + pr_err("%s: bad ioctl: cmd = %u, arg = %lu\n", __func__, cmd, arg); + ret = -ENOIOCTLCMD; + }; + return ret; +} + +/* + * sn100_nfc_pwr() - power control/firmware download + * @filp: pointer to the file descriptor + * @arg: mode that we want to move to + * + * Device power control. Depending on the arg value, device moves to + * different states + * (arg = 1):FW_DL GPIO = 0 + * (arg = 2):FW_DL GPIO = 1 - Power up in firmware download mode + * (additional ioctl for sn100 because of keeping VEN always high) + * (arg = 4):enable firmware download via NCI commands + * (arg = 5):power on/reset NFC and ESE + * (arg = 6):disable firmware download via NCI commands + * + * Return: -ENOIOCTLCMD if arg is not supported, 0 in any other case + */ +static long sn1xx_nfc_pwr(struct nfc_dev *nfc_dev, unsigned long arg) +{ + pr_debug("%s: %lu\n", __func__, arg); + switch(arg) { + case 1: + case 6: + if (gpio_is_valid(nfc_dev->firm_gpio)) { + gpio_set_value(nfc_dev->firm_gpio, 0); + usleep_range(10000, 10100); + } + break; + case 2: + case 5: + nfc_ese_acquire(nfc_dev); + nfc_disable_irq(nfc_dev); + gpio_set_value(nfc_dev->ven_gpio, 0); + usleep_range(10000, 10100); + if (2 == arg) { + if (gpio_is_valid(nfc_dev->firm_gpio)) { + gpio_set_value(nfc_dev->firm_gpio, 1); + usleep_range(10000, 10100); + } + } + nfc_enable_irq(nfc_dev); + gpio_set_value(nfc_dev->ven_gpio, 1); + usleep_range(10000, 10100); + nfc_ese_release(nfc_dev); + break; + case 4: + if (gpio_is_valid(nfc_dev->firm_gpio)) { + gpio_set_value(nfc_dev->firm_gpio, 1); + usleep_range(10000, 10100); + } + break; + default: + pr_err("%s bad ioctl %lu\n", __func__, arg); + return -ENOIOCTLCMD; + } + return 0; +} + + +long sn1xx_nfc_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + pr_debug("%s: cmd = %u, arg = %lu\n", __func__, cmd, arg); + switch (cmd) { + case SN1XX_SET_PWR: + ret = sn1xx_nfc_pwr(nfc_dev, arg); + break; + default: + pr_err("%s: bad ioctl: cmd = %u, arg = %lu\n", __func__, cmd, arg); + ret = -ENOIOCTLCMD; + } + return ret; +} + +int sn1xx_nfc_probe(struct nfc_dev *nfc_dev) +{ + pr_debug("%s: enter\n", __func__); + /* VBAT--> VDDIO(HIGH) + Guardtime of min 5ms --> VEN(HIGH) */ + nfc_ese_acquire(nfc_dev); + msleep(5); + /* VEN toggle(reset) to proceed */ + gpio_set_value(nfc_dev->ven_gpio, 0); + msleep(5); + gpio_set_value(nfc_dev->ven_gpio, 1); + nfc_ese_release(nfc_dev); + return 0; +} + +int sn1xx_nfc_remove(struct nfc_dev *nfc_dev) +{ + /*nothing needed here in addition to generic driver*/ + return 0; +} diff --git a/drivers/nfc/nxp/nfc/sn1xx.h b/drivers/nfc/nxp/nfc/sn1xx.h new file mode 100644 index 0000000000000000000000000000000000000000..276451e71511c8bd39f8471b8dd3bd10e0c888e3 --- /dev/null +++ b/drivers/nfc/nxp/nfc/sn1xx.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 Trusted Logic S.A. + * + * 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. + * + */ +/****************************************************************************** + * + * The original Work has been changed by NXP Semiconductors. + * + * Copyright (C) 2013-2019 NXP Semiconductors + * * + * 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. + * + ******************************************************************************/ +#ifndef _NXP_NFC_SN1XX_H_ +#define _NXP_NFC_SN1XX_H_ + +/* + * NFC power control via ioctl + * SN1XX_SET_PWR(4): enable firmware download via NCI commands + * SN1XX_SET_PWR(5): power on/reset NFC and ESE + * SN1XX_SET_PWR(6): disable firmware download via NCI commands + */ +#define SN1XX_SET_PWR _IOW(NXP_NFC_MAGIC, 0x01, long) + +long sn1xx_nfc_ese_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg); +long sn1xx_nfc_ioctl(struct nfc_dev *nfc_dev, unsigned int cmd, unsigned long arg); +int sn1xx_nfc_probe(struct nfc_dev *nfc_dev); +int sn1xx_nfc_remove(struct nfc_dev *nfc_dev); +#endif //_NXP_NFC_SN1XX_H_ diff --git a/drivers/nvmem/qcom-spmi-sdam.c b/drivers/nvmem/qcom-spmi-sdam.c index e80a44671155dca794cb8caf6425bdd5895ab193..2cbb50b06b3cdd991e059f1c1f38dbca166b4d9d 100644 --- a/drivers/nvmem/qcom-spmi-sdam.c +++ b/drivers/nvmem/qcom-spmi-sdam.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #define SDAM_MEM_START 0x40 #define REGISTER_MAP_ID 0x40 @@ -154,9 +156,6 @@ static int sdam_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, nvmem); - pr_info("SDAM base=0x%04x size=%d registered successfully\n", - sdam->base, sdam->size); - return 0; } diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 688f1226eea2b6629887ae9edc2f812caa3c0c28..c637f5dc5cc51cdd9a8249e7cc2acb373a8861d8 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -32,6 +32,7 @@ #include "of_private.h" +void init_param_mem_base_size(phys_addr_t base, unsigned long size); /* * of_fdt_limit_memory - limit the number of regions in the /memory node * @limit: maximum entries @@ -673,6 +674,9 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n", uname, &base, (unsigned long)size / SZ_1M); + if (!strncmp(uname, "param_mem", 9)) + init_param_mem_base_size(base, size); + len -= t_len; if (first) { fdt_reserved_mem_save_node(node, uname, base, size); diff --git a/drivers/oneplus/Kconfig b/drivers/oneplus/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a43686d3bea6e8e4e309caaed73720f6dfe72dfb --- /dev/null +++ b/drivers/oneplus/Kconfig @@ -0,0 +1,19 @@ + +source "drivers/oneplus/coretech/Kconfig" +source "drivers/oneplus/input/Kconfig" +source "drivers/oneplus/fs/Kconfig" +source "drivers/oneplus/kernel/Kconfig" +source "drivers/oneplus/misc/Kconfig" +#source "drivers/oneplus/step_motor/Kconfig" +source "drivers/oneplus/tri_state_key/Kconfig" +#source "drivers/oneplus/vibrator/Kconfig" +source "drivers/oneplus/power/Kconfig" +source "drivers/oneplus/vibrator/Kconfig" +#source "drivers/oneplus/power/Kconfig" +source "drivers/oneplus/oneplus_healthinfo/Kconfig" +source "drivers/oneplus/mm/Kconfig" +source "drivers/oneplus/opslalib/Kconfig" +#source "drivers/oneplus/framework/Kconfig" +source "drivers/oneplus/vl53L1/Kconfig" +source "drivers/oneplus/op_freezer/Kconfig" +source "drivers/oneplus/hung_task_enhance/Kconfig" diff --git a/drivers/oneplus/Makefile b/drivers/oneplus/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..0874e0f87047f2a7dbd5fd15b5a3d8e38c513bdd --- /dev/null +++ b/drivers/oneplus/Makefile @@ -0,0 +1,17 @@ +# oem device deriver +obj-y += input/ +#obj-y += framework/ +obj-y += kernel/ +obj-y += coretech/ +obj-y += fs/ +obj-y += misc/ +#obj-y += step_motor/ +obj-y += tri_state_key/ +obj-y += power/ +obj-y += vibrator/ +obj-y += oneplus_healthinfo/ +obj-y += mm/ +obj-y += opslalib/ +obj-y += vl53L1/ +obj-$(CONFIG_OP_FREEZER) += op_freezer/ +obj-y += hung_task_enhance/ diff --git a/drivers/oneplus/coretech/Kconfig b/drivers/oneplus/coretech/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..b7fb0f1ae3d3a4123750ef673d2b699c9bf5c503 --- /dev/null +++ b/drivers/oneplus/coretech/Kconfig @@ -0,0 +1,94 @@ +config OPCHAIN + default n + bool "Oneplus CoreTech helper, used for opchain module" +config MEMPLUS + default n + bool "memory+ feature" + help + Memory+ feature +config SMART_BOOST + bool "support smart boost feature" + default n + help + this feature allow memory used by recent-app stay in kernel. +config DEFRAG + default n + bool "anti-defragment feature" + help + anti-defragment feature. +config FSC + default n + bool "system layer file status cache" + help + To cache absence file and avoid stat call storm +config HOUSTON + default n + bool "to collect system-wide and pmu data" + help + Realtime temperature monitor +config CONTROL_CENTER + default n + bool "control center" + help + A framework to adjust system resource such as perfd, but easy to extend + the scope of use. Support priority control between different request and + QoS for keep adjusting for a specific period. Besides resource controlling, + it also provide a decision model for helping governor to make decision. + +config AIGOV + default n + bool "A governor which using ai predicted info as input" + +config IM + bool "identify task itself" + default n + help + In many cases we need to identify task, all we do is simply string compare, + but in some performance sensitive context like scheduler, it's not a good choice to + do that. So this IM thing can let we check task only through one comparsion. + +config PCCORE + default n + bool "pccore feature" + +config VM_FRAGMENT_MONITOR + default n + bool "monitor virtual memory fragment" + +config UXCHAIN + default n + bool "A sched policy for ux relative threads " + +config UXCHAIN_V2 + default n + depends on UXCHAIN + bool "optimization for mmap_sem of mm_struct " + +config TPD + default n + bool "a task placement decision for cpu limitation" + +config TPP + default n + depends on IM + bool "Task parallel placement" + +config MEMEX_STANDALONE + default n + bool "MemEX feature" + help + MemEX feature + +config RATP + bool "restricted admission for task placement in low-end platfom" + default n + help + In low-end platform, we will restrict admission for task placement to avoid + CPU resource contention. + +config ZWB_HANDLE + default n + depends on ZRAM_WRITEBACK + bool "zram writeback feature" + help + zram writeback feature diff --git a/drivers/oneplus/coretech/Makefile b/drivers/oneplus/coretech/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..38208772a9c1ee3b98dc76e4c0621037e25ce61a --- /dev/null +++ b/drivers/oneplus/coretech/Makefile @@ -0,0 +1,36 @@ +obj-$(CONFIG_OPCHAIN) += uxcore/ +CORE_PATH = $(KBUILD_SRC)/drivers/oneplus/coretech/uxcore/core +ifeq ($(CORE_PATH),$(wildcard $(CORE_PATH))) +obj-$(CONFIG_OPCHAIN) += uxcore/core/ +endif + +obj-$(CONFIG_MEMPLUS) += memplus/ +CORE_PATH = $(KBUILD_SRC)/drivers/oneplus/coretech/memplus/core +ifeq ($(CORE_PATH),$(wildcard $(CORE_PATH))) +obj-$(CONFIG_MEMPLUS) += memplus/core/ +endif + +obj-$(CONFIG_SMART_BOOST) += smartboost/ +CORE_PATH = $(KBUILD_SRC)/drivers/oneplus/coretech/smartboost/core +ifeq ($(CORE_PATH),$(wildcard $(CORE_PATH))) +obj-$(CONFIG_SMART_BOOST) += smartboost/core/ +endif + +obj-$(CONFIG_DEFRAG) += defrag/ +CORE_PATH = $(KBUILD_SRC)/drivers/oneplus/coretech/defrag/core +ifeq ($(CORE_PATH),$(wildcard $(CORE_PATH))) +obj-$(CONFIG_DEFRAG) += defrag/core/ +endif + +obj-$(CONFIG_FSC) += fsc/ +obj-$(CONFIG_HOUSTON) += houston/ +obj-$(CONFIG_CONTROL_CENTER) += control_center/ +obj-$(CONFIG_IM) += im/ +obj-$(CONFIG_PCCORE) += pccore/ +obj-$(CONFIG_VM_FRAGMENT_MONITOR) += vm_fragment_monitor/ +obj-$(CONFIG_UXCHAIN) += uxchain/ +obj-$(CONFIG_TPD) += tpd/ +obj-$(CONFIG_TPP) += tpp/ +obj-$(CONFIG_MEMEX_STANDALONE) += memex_standalone_support/core/ +obj-$(CONFIG_RATP) += ratp/ +obj-$(CONFIG_ZWB_HANDLE) += zwb_handle/ diff --git a/drivers/oneplus/coretech/adj_chain/Makefile b/drivers/oneplus/coretech/adj_chain/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8360bc80ce0069e5bc593a035c9557f7c176aae0 --- /dev/null +++ b/drivers/oneplus/coretech/adj_chain/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ADJ_CHAIN) += adj_chain.o diff --git a/drivers/oneplus/coretech/adj_chain/adj_chain.c b/drivers/oneplus/coretech/adj_chain/adj_chain.c new file mode 100644 index 0000000000000000000000000000000000000000..261130fcac213e651b57edafd90fb81963e9bc31 --- /dev/null +++ b/drivers/oneplus/coretech/adj_chain/adj_chain.c @@ -0,0 +1,87 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +struct list_head adj_chain[ADJ_CHAIN_MAX + 1]; +EXPORT_SYMBOL(adj_chain); + +int adj_chain_ready = 0; +EXPORT_SYMBOL(adj_chain_ready); + +int adj_chain_hist_high = 0; +EXPORT_SYMBOL(adj_chain_hist_high); + +static void __adj_chain_detach(struct task_struct *p) +{ + p->adj_chain_status |= 1 << AC_DETACH; + list_del_rcu(&p->adj_chain_tasks); + p->adj_chain_status &= ~(1 << AC_DETACH); +} + +static void __adj_chain_attach(struct task_struct *p) +{ + p->adj_chain_status |= 1 << AC_ATTACH; + list_add_tail_rcu(&p->adj_chain_tasks, &adj_chain[__adjc(get_oom_score_adj(p))]); + p->adj_chain_status &= ~(1 << AC_ATTACH); + if (__adjc(get_oom_score_adj(p)) > adj_chain_hist_high) + adj_chain_hist_high = __adjc(get_oom_score_adj(p)); +} + +void adj_chain_update_oom_score_adj(struct task_struct *p) +{ + if (likely(adj_chain_ready)) { + /* sync with system task_list */ + write_lock_irq(&tasklist_lock); + spin_lock(¤t->sighand->siglock); + if (!thread_group_leader(p)) { + pr_warn("%s '%d' not update from group leader: %s '%d', leader: %s '%d'\n", + current->comm, current->pid, + p->comm, p->pid, p->group_leader->comm, p->group_leader->pid); + p = p->group_leader; + } + if (unlikely(p->flags & PF_EXITING)) + goto done; + p->adj_chain_status |= 1 << AC_UPDATE_ADJ; + __adj_chain_detach(p); + __adj_chain_attach(p); + p->adj_chain_status &= ~(1 << AC_UPDATE_ADJ); +done: + spin_unlock(¤t->sighand->siglock); + write_unlock_irq(&tasklist_lock); + } +} +EXPORT_SYMBOL(adj_chain_update_oom_score_adj); + +void adj_chain_attach(struct task_struct *p) +{ + if (likely(adj_chain_ready)) { + __adj_chain_attach(p); + } +} +EXPORT_SYMBOL(adj_chain_attach); + +void adj_chain_detach(struct task_struct *p) +{ + if (likely(adj_chain_ready)) { + __adj_chain_detach(p); + } +} +EXPORT_SYMBOL(adj_chain_detach); + +static int init_adj_chain(void) +{ + int i = 0; + + for (i = 0; i <= ADJ_CHAIN_MAX; ++i) { + INIT_LIST_HEAD(&adj_chain[i]); + } + pr_info("adj_chain init completed\n"); + adj_chain_ready = 1; + return 0; +} + +pure_initcall(init_adj_chain); +MODULE_DESCRIPTION("Oneplus adj chain"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/coretech/control_center/Makefile b/drivers/oneplus/coretech/control_center/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cb855c5643d4c98c4734f6ec6859f2d8ed8c6ac8 --- /dev/null +++ b/drivers/oneplus/coretech/control_center/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_CONTROL_CENTER) += control_center.o +obj-$(CONFIG_CONTROL_CENTER) += decision_maker.o diff --git a/drivers/oneplus/coretech/control_center/control_center.c b/drivers/oneplus/coretech/control_center/control_center.c new file mode 100644 index 0000000000000000000000000000000000000000..9bb76201d904312bf0b6e774591bd7fee1d76555 --- /dev/null +++ b/drivers/oneplus/coretech/control_center/control_center.c @@ -0,0 +1,1829 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OPCHAIN +#include +#include +#endif + +#include + +/* time measurement */ +#define CC_TIME_START(start) { \ + if (cc_time_measure) \ + start = ktime_get(); \ +} +#define CC_TIME_END(start, end, t, tmax) { \ + if (cc_time_measure) { \ + end = ktime_get(); \ + t = ktime_to_us(ktime_sub(end, begin)); \ + if (t > tmax) \ + tmax = t; \ + cc_logv("%s: cost: %lldus, max: %lldus\n", __func__, t, tmax); \ + }\ +} +static bool cc_time_measure = true; +module_param_named(time_measure, cc_time_measure, bool, 0644); + +/* boost enable options */ +static bool cc_cpu_boost_enable = true; +module_param_named(cpu_boost_enable, cc_cpu_boost_enable, bool, 0644); + +static bool cc_ddr_boost_enable = true; +module_param_named(ddr_boost_enable, cc_ddr_boost_enable, bool, 0644); + +bool cc_ddr_boost_enabled(void) +{ + return cc_ddr_boost_enable; +} + +static bool cc_fps_boost_enable = true; +module_param_named(fps_boost_enable, cc_fps_boost_enable, bool, 0644); + +/* turbo boost */ +static bool cc_tb_freq_boost_enable = true; +module_param_named(tb_freq_boost_enable, cc_tb_freq_boost_enable, bool, 0644); + +static bool cc_tb_place_boost_enable = true; +module_param_named(tb_place_boost_enable, cc_tb_place_boost_enable, bool, 0644); + +static bool cc_tb_nice_last_enable = false; +module_param_named(tb_nice_last_enable, cc_tb_nice_last_enable, bool, 0644); + +static int cc_tb_nice_last_period = 10; /* 10 jiffies equals to 40 ms */ +module_param_named(tb_nice_last_period, cc_tb_nice_last_period, int, 0644); + +static int cc_tb_idle_block_enable = true; +static int cc_tb_idle_block_enable_store(const char *buf, + const struct kernel_param *kp) +{ + unsigned int val; + int i; + + if (sscanf(buf, "%u\n", &val) <= 0) + return 0; + + cc_tb_idle_block_enable = !!val; + if (!cc_tb_idle_block_enable) { + for (i = CCDM_TB_CPU_0_IDLE_BLOCK; i <= CCDM_TB_CPU_7_IDLE_BLOCK; ++i) + ccdm_update_hint_1(i, ULLONG_MAX); + } + + return 0; +} + +static int cc_tb_idle_block_enable_show(char *buf, + const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", cc_tb_idle_block_enable); +} + +static struct kernel_param_ops cc_tb_idle_block_enable_ops = { + .set = cc_tb_idle_block_enable_store, + .get = cc_tb_idle_block_enable_show, +}; +module_param_cb(tb_idle_block_enable, &cc_tb_idle_block_enable_ops, NULL, 0644); + +static int cc_tb_idle_block_period = 10; /* 10 jiffies equals to 40 ms */ +module_param_named(tb_idle_block_period, cc_tb_idle_block_period, int, 0644); + +static unsigned long cc_expect_ddrfreq; +module_param_named(expect_ddrfreq, cc_expect_ddrfreq, ulong, 0644); + +unsigned long cc_get_expect_ddrfreq(void) +{ + return cc_expect_ddrfreq; +} + +/* statistics for control operations */ +struct cc_stat { + atomic64_t cnt[CC_CTL_CATEGORY_MAX]; + atomic64_t tcnt[CC_CTL_CATEGORY_MAX]; +} cc_stat; + +static inline void cc_stat_inc(int idx) +{ + if (likely(idx >= 0 && idx < CC_CTL_CATEGORY_MAX)) + atomic64_inc(&cc_stat.cnt[idx]); +} + +/* record */ +static struct cc_record { + spinlock_t lock; + /* priority list */ + struct list_head phead[CC_PRIO_MAX]; +} cc_record[CC_CTL_CATEGORY_MAX]; + +/* + * verbose output + * lv: 0 -> verbose + * lv: 1 -> info + * lv: 2 -> wraning + * lv: 3 -> error + */ +static int cc_log_lv = 1; +module_param_named(log_lv, cc_log_lv, int, 0644); + +static const char *cc_category_tags[CC_CTL_CATEGORY_MAX]; +static const char *cc_category_tags_mapping(int idx); + +#define CC_SYSTRACE_DEBUG 0 +#if CC_SYSTRACE_DEBUG +#define CC_TSK_SYSTRACE_MAGIC 80000 +#define CC_SYSTRACE_MAGIC 90000 + +/* systrace trace marker */ +static int cc_systrace_enable = 0; +module_param_named(systrace_enable, cc_systrace_enable, int, 0644); + +static inline void tracing_mark_write(struct cc_command *cc, int count, bool tsk) +{ + if (cc_systrace_enable) { + if (tsk) { + if (cc_systrace_enable == 2) { + int pid = cc->bind_leader ? cc->leader: cc->pid; + trace_printk("C|%d|%s-%d|%d\n", + CC_TSK_SYSTRACE_MAGIC + cc->category, cc_category_tags_mapping(cc->category), pid, count); + } else + trace_printk("C|%d|%s|%d\n", + CC_TSK_SYSTRACE_MAGIC + cc->category, cc_category_tags_mapping(cc->category), count); + } else { + if (cc_systrace_enable == 2) { + int pid = cc->bind_leader ? cc->leader : cc->pid; + trace_printk("C|%d|%s-%d|%d\n", + CC_SYSTRACE_MAGIC + cc->category, cc_category_tags_mapping(cc->category), pid, count); + } else + trace_printk("C|%d|%s|%d\n", + CC_SYSTRACE_MAGIC + cc->category, cc_category_tags_mapping(cc->category), count); + } + } +} +#else +static inline void tracing_mark_write(struct cc_command *cc, int count, bool tsk) {} +#endif + +static int cc_tb_cctl_boost_enable = true; +static int cc_tb_cctl_boost_enable_store(const char *buf, + const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return 0; + + cc_tb_cctl_boost_enable = !!val; + + return 0; +} + +static int cc_tb_cctl_boost_enable_show(char *buf, + const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", cc_tb_cctl_boost_enable); +} + +static struct kernel_param_ops cc_tb_cctl_boost_enable_ops = { + .set = cc_tb_cctl_boost_enable_store, + .get = cc_tb_cctl_boost_enable_show, +}; +module_param_cb(tb_cctl_boost_enable, &cc_tb_cctl_boost_enable_ops, NULL, 0644); + +static void cc_queue_rq(struct cc_command *cc); + +/* boost ts information */ +static struct cc_boost_ts cbt[CC_BOOST_TS_SIZE]; +static int boost_ts_idx = 0; +static DEFINE_SPINLOCK(boost_ts_lock); + +static inline bool cc_is_reset(struct cc_command *cc) +{ + return cc->type == CC_CTL_TYPE_RESET || + cc->type == CC_CTL_TYPE_RESET_NONBLOCK; +} + +static inline bool cc_is_query(int category) +{ + return category >= CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY + && category <= CC_CTL_CATEGORY_DDR_FREQ_QUERY; +} + +static inline bool cc_is_nonblock(struct cc_command *cc) +{ + bool nonblock = false; + + if (cc->type >= CC_CTL_TYPE_ONESHOT_NONBLOCK) { + nonblock = true; + cc->type -= CC_CTL_TYPE_ONESHOT_NONBLOCK; + cc_queue_rq(cc); + } + return nonblock; +} + +static inline void cc_remove_nonblock(struct cc_command *cc) +{ + if (cc->type >= CC_CTL_TYPE_ONESHOT_NONBLOCK) + cc->type -= CC_CTL_TYPE_ONESHOT_NONBLOCK; +} + +/* calling with lock held */ +static int boost_ts_get_idx(void) { + int idx = boost_ts_idx++; + return idx % CC_BOOST_TS_SIZE; +} + +static void cc_boost_ts_update(struct cc_command* cc) +{ + u64 ts_us = ktime_to_us(ktime_get()); + int idx = 0; + bool reset = cc_is_reset(cc); + + if (cc->category != CC_CTL_CATEGORY_CLUS_1_FREQ && + cc->category != CC_CTL_CATEGORY_TB_FREQ_BOOST) + return; + + if (cc->category == CC_CTL_CATEGORY_CLUS_1_FREQ) { + cc_logv("[%s] boost from %u group %u category %u type %u period %u min %llu max %llu\n", + reset ? "Exit" : "Enter", + cc->bind_leader ? cc->leader : cc->pid, + cc->group, cc->category, cc->type, cc->period_us, cc->params[0], cc->params[1]); + } + else if (cc->category == CC_CTL_CATEGORY_TB_FREQ_BOOST) { + cc_logv( + "[%s] turbo boost from %u group %u category %u type %u period %u hint %llu %llu %llu %llu\n", + reset ? "Exit" : "Enter", + cc->bind_leader ? cc->leader : cc->pid, + cc->group, cc->category, cc->type, cc->period_us, + cc->params[0], cc->params[1], + cc->params[2], cc->params[3]); + } + + spin_lock(&boost_ts_lock); + + idx = boost_ts_get_idx(); + cbt[idx].pid = cc->bind_leader? cc->leader: cc->pid; + cbt[idx].type = reset? 0: 1; + cbt[idx].ts_us = ts_us; + cbt[idx].min = cc->params[0]; + cbt[idx].max = cc->params[1]; + spin_unlock(&boost_ts_lock); +} + +void cc_boost_ts_collect(struct cc_boost_ts* source) +{ + spin_lock(&boost_ts_lock); + memcpy(source, cbt, sizeof(struct cc_boost_ts) * CC_BOOST_TS_SIZE); + memset(cbt, 0, sizeof(struct cc_boost_ts) * CC_BOOST_TS_SIZE); + boost_ts_idx = 0; + spin_unlock(&boost_ts_lock); +} + +/* cpufreq boost qos */ +enum cc_cpufreq_boost_lv { + CC_CPUFREQ_BOOST_LV_0 = 0, + CC_CPUFREQ_BOOST_LV_1, + CC_CPUFREQ_BOOST_LV_2, + CC_CPUFREQ_BOOST_LV_3, + CC_CPUFREQ_BOOST_LV_4, + + CC_CPUFREQ_BOOST_LV_MAX +}; + +/* boost timestamp */ + +/* async work */ +#define CC_ASYNC_RQ_MAX (64) +static struct cc_async_rq { + struct cc_command cc; + struct list_head node; + struct work_struct work; + int idx; +} cc_async_rq[CC_ASYNC_RQ_MAX]; + +static struct task_struct *cc_worker_task; +static struct list_head cc_request_list; +static struct list_head cc_pending_list; +static DEFINE_SPINLOCK(cc_async_lock); +static struct workqueue_struct *cc_wq; +extern cc_cal_next_freq_with_extra_util( + struct cpufreq_policy *pol, unsigned int next_freq); +extern void clk_get_ddr_freq(u64* val); +static void cc_queue_rq(struct cc_command *cc); + +static void __adjust_cpufreq( + struct cpufreq_policy *pol, u32 min, u32 max, bool reset) +{ + u32 req_freq = pol->req_freq; + u32 orig_req_freq = pol->req_freq; + u32 next_freq = pol->req_freq; + u32 cpu; + + spin_lock(&pol->cc_lock); + + /* quick check */ + if (pol->cc_max == max && pol->cc_min == min && !reset) { + spin_unlock(&pol->cc_lock); + goto out; + } + + /* cc max/min always inside current pol->max/min */ + pol->cc_max = (pol->max >= max)? max: pol->max; + pol->cc_min = (pol->min <= min)? min: pol->min; + if (reset) + req_freq = pol->req_freq; + else + req_freq = clamp_val(req_freq, pol->cc_min, pol->cc_max); + + spin_unlock(&pol->cc_lock); + + /* not update while current governor is not schedutil */ + if (unlikely(!pol->cc_enable)) + goto out; + + /* trigger frequency change */ + if (pol->fast_switch_enabled) { + next_freq = cpufreq_driver_fast_switch(pol, req_freq); + if (!next_freq || (next_freq == pol->cur)) + goto out; + + /* update cpufreq stat */ + pol->cur = next_freq; + for_each_cpu(cpu, pol->cpus) + trace_cpu_frequency(next_freq, cpu); + cpufreq_stats_record_transition(pol, next_freq); + } else { + cpufreq_driver_target(pol, req_freq, CPUFREQ_RELATION_H); + } +out: + cc_logv("cc_max: %u, cc_min: %u, target: %u, orig: %u, cur: %u, gov: %d\n", + pol->cc_max, pol->cc_min, req_freq, orig_req_freq, next_freq, pol->cc_enable); +} + +/* called with get_online_cpus() */ +static inline int cc_get_online_cpu(int start, int end) +{ + int idx = -1; + for (idx = start; idx <= end; ++idx) + if (cpu_online(idx)) + break; + return idx; +} + +static inline int cc_get_cpu_idx(int cluster) +{ + switch (cluster) { + case 0: return cc_get_online_cpu(0, 3); + case 1: return cc_get_online_cpu(4, 6); + case 2: return cc_get_online_cpu(7, 7); + } + return -1; +} + +static int __cc_adjust_cpufreq( + u32 clus, u32 min, u32 max, bool reset) +{ + struct cpufreq_policy *pol; + int idx; + int ret = 0; + + get_online_cpus(); + + idx = cc_get_cpu_idx(clus); + if (idx == -1) { + cc_logw("can' get cpu idx, input cluster %u\n", clus); + ret = -1; + goto out; + } + + pol = cpufreq_cpu_get(idx); + if (!pol) { + ret = -1; + cc_logw("can't get cluster %d cpufreqp policy\n", idx); + goto out; + } + + __adjust_cpufreq(pol, min, max, reset); + + cpufreq_cpu_put(pol); +out: + put_online_cpus(); + return ret; +} + +static void cc_adjust_cpufreq(struct cc_command* cc) +{ + u32 clus; + + if (!cc_cpu_boost_enable) + return; + + if (cc_is_nonblock(cc)) + return; + + switch (cc->category) { + case CC_CTL_CATEGORY_CLUS_0_FREQ: clus = 0; break; + case CC_CTL_CATEGORY_CLUS_1_FREQ: clus = 1; break; + case CC_CTL_CATEGORY_CLUS_2_FREQ: clus = 2; break; + default: + cc_logw("cpufreq query invalid, category %u\n", cc->category); + return; + } + + /* for min/max approach */ + if (cc->params[3] == 0) { + u32 min; + u32 max; + bool reset = false; + + if (cc_is_reset(cc)) { + min = 0; + max = UINT_MAX; + reset = true; + } else { + /* ONESHOT/PERIOD */ + min = cc->params[0]; + max = cc->params[1]; + /* validate parameters */ + if (min > max) { + cc_logw("cpufrq incorrect, min %u, max %u\n", min, max); + return; + } + } + + cc->status = __cc_adjust_cpufreq(clus, min, max, reset); + } else if (cc->params[3] == 1) { + /* for extra util */ + struct cpufreq_policy *pol; + int cpu; + unsigned int next_freq; + u64 val = cc->params[0]; + + if (!cc_tb_freq_boost_enable) + return; + + if (cc_is_reset(cc)) { + ccdm_update_hint_1(CCDM_TB_CLUS_0_FREQ_BOOST, 0); + ccdm_update_hint_1(CCDM_TB_CLUS_1_FREQ_BOOST, 0); + ccdm_update_hint_1(CCDM_TB_CLUS_2_FREQ_BOOST, 0); + } else { + switch (clus) { + case 0: + ccdm_update_hint_1(CCDM_TB_CLUS_0_FREQ_BOOST, val); + break; + case 1: + ccdm_update_hint_1(CCDM_TB_CLUS_1_FREQ_BOOST, val); + break; + case 2: + ccdm_update_hint_1(CCDM_TB_CLUS_2_FREQ_BOOST, val); + break; + } + } + + get_online_cpus(); + /* force trigger cpufreq change */ + pol = cpufreq_cpu_get(cc_get_cpu_idx(clus)); + if (unlikely(!pol)) { + put_online_cpus(); + return; + } + + if (unlikely(!pol->cc_enable)) + goto out; + + /* trigger frequency change */ + next_freq = + cc_cal_next_freq_with_extra_util(pol, pol->req_freq); + + /* reset cc_min/max */ + spin_lock(&pol->cc_lock); + pol->cc_max = pol->max; + pol->cc_min = pol->min; + spin_unlock(&pol->cc_lock); + + if (pol->fast_switch_enabled) { + next_freq = cpufreq_driver_fast_switch(pol, next_freq); + if (!next_freq || (next_freq == pol->cur)) + goto out; + + /* update cpufreq stat */ + pol->cur = next_freq; + for_each_cpu(cpu, pol->cpus) + trace_cpu_frequency(next_freq, cpu); + cpufreq_stats_record_transition(pol, next_freq); + } else { + cpufreq_driver_target(pol, next_freq, CPUFREQ_RELATION_H); + } +out: + cpufreq_cpu_put(pol); + put_online_cpus(); + } +} + +/* to change ai predict ddrfreq to devfreq */ +static inline u64 cc_ddr_to_devfreq(u64 val) +{ + int i; + u64 ddr_devfreq_avail_freq[] = { 0, 2597, 2929, 3879, 5161, 5931, 6881, 7980, 10437 }; + u64 ddr_aop_mapping_freq[] = { 0, 681, 768, 1017, 1353, 1555, 1804, 2092, 2736 }; + + /* map to devfreq whlie config is enabled */ + for (i = ARRAY_SIZE(ddr_devfreq_avail_freq) - 1; i >= 0; --i) { + if (val >= ddr_aop_mapping_freq[i]) + return ddr_devfreq_avail_freq[i]; + } + return val; +} + +void cc_set_cpu_idle_block(int cpu) +{ + u64 next_ts; + int ccdm_idle_block_idx = + cpu + CCDM_TB_CPU_0_IDLE_BLOCK; + + if (!cc_tb_idle_block_enable) + return; + + next_ts = get_jiffies_64() + cc_tb_idle_block_period; + ccdm_update_hint_1(ccdm_idle_block_idx, next_ts); +} + +void cc_check_renice(void *tsk) +{ + struct task_struct *t = (struct task_struct *) tsk; + u64 next_ts; + + if (unlikely(!im_main(t) && !im_enqueue(t) && !im_render(t))) + return; + + if (!cc_tb_nice_last_enable) + return; + + /* skip rt task */ + if (unlikely(t->prio < 100)) + return; + + next_ts = get_jiffies_64() + cc_tb_nice_last_period; + + if (likely(t->nice_effect_ts != next_ts)) { + t->nice_effect_ts = next_ts; + set_user_nice_no_cache(t, MIN_NICE); + } +} + +static void cc_tb_freq_boost(struct cc_command *cc) +{ + struct cpufreq_policy *pol; + int clus, cpu; + unsigned int next_freq; + + if (!cc_tb_freq_boost_enable) + return; + + if (cc_is_reset(cc)) + ccdm_update_hint_3(CCDM_TB_FREQ_BOOST, 0, 0, 0); + else + ccdm_update_hint_3(CCDM_TB_FREQ_BOOST, + cc->params[0], cc->params[1], cc->params[2]); + + get_online_cpus(); + /* force trigger cpufreq change */ + for (clus = 0; clus < 3; ++clus) { + if (!cc->params[clus]) + continue; + + pol = cpufreq_cpu_get(cc_get_cpu_idx(clus)); + if (unlikely(!pol)) + continue; + + if (unlikely(!pol->cc_enable)) { + cpufreq_cpu_put(pol); + continue; + } + + /* trigger frequency change */ + next_freq = + cc_cal_next_freq_with_extra_util(pol, pol->req_freq); + + if (pol->fast_switch_enabled) { + next_freq = cpufreq_driver_fast_switch(pol, next_freq); + if (!next_freq || (next_freq == pol->cur)) { + cpufreq_cpu_put(pol); + continue; + } + + /* update cpufreq stat */ + pol->cur = next_freq; + for_each_cpu(cpu, pol->cpus) + trace_cpu_frequency(next_freq, cpu); + cpufreq_stats_record_transition(pol, next_freq); + } else { + cpufreq_driver_target(pol, next_freq, CPUFREQ_RELATION_H); + } + cpufreq_cpu_put(pol); + } + put_online_cpus(); +} + +static void cc_tb_place_boost(struct cc_command *cc) +{ + if (!cc_tb_place_boost_enable) + return; + + if (cc_is_reset(cc)) + ccdm_update_hint_1(CCDM_TB_PLACE_BOOST, 0); + else + ccdm_update_hint_1(CCDM_TB_PLACE_BOOST, 1); +} + +static void cc_query_cpufreq(struct cc_command* cc) +{ + struct cpufreq_policy *pol; + u32 clus; + int idx; + + get_online_cpus(); + + switch (cc->category) { + case CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY: clus = 0; break; + case CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY: clus = 1; break; + case CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY: clus = 2; break; + default: + cc_logw("cpufreq query invalid, category %u\n", cc->category); + goto out; + } + + idx = cc_get_cpu_idx(clus); + if (idx == -1) { + cc_logw("can' get cpu idx, input cluster %u\n", clus); + goto out; + } + + pol = cpufreq_cpu_get(idx); + if (!pol) { + cc_logw("can't get cluster %d cpufreqp policy\n", idx); + goto out; + } + cc->response = pol->cur; + +out: + put_online_cpus(); +} + +#define CC_DDRFREQ_CHECK(name, target) \ + if (!strcmp(name, target)) { \ + cc_logi("mark device %s as ddrfreq related\n", name); \ + return true; \ + } + +bool cc_is_ddrfreq_related(const char* name) +{ + if (!unlikely(name)) + return false; + + /* ddrfreq voting device */ + CC_DDRFREQ_CHECK(name, "soc:qcom,gpubw"); + CC_DDRFREQ_CHECK(name, "soc:qcom,cpu-llcc-ddr-bw"); + CC_DDRFREQ_CHECK(name, "soc:qcom,cpu4-cpu-ddr-latfloor"); + CC_DDRFREQ_CHECK(name, "soc:qcom,cpu0-llcc-ddr-lat"); + CC_DDRFREQ_CHECK(name, "soc:qcom,cpu4-llcc-ddr-lat"); + //CC_DDRFREQ_CHECK(name, "aa00000.qcom,vidc:arm9_bus_ddr"); + //CC_DDRFREQ_CHECK(name, "aa00000.qcom,vidc:venus_bus_ddr"); + return false; +} + +static inline u64 query_ddrfreq(void) +{ + u64 val; + clk_get_ddr_freq(&val); + val /= 1000000; + /* process for easy deal with */ + if (val == 1018) val = 1017; + else if (val == 1355) val = 1353; + else if (val == 1805) val = 1804; + else if (val == 2096) val = 2092; + else if (val == 2739) val = 2736; + return val; +} + +static void cc_query_ddrfreq(struct cc_command* cc) +{ + cc->response = query_ddrfreq(); +} + +#define CC_DDR_RESET_VAL 0 +static void cc_adjust_ddr_voting_freq(struct cc_command *cc) +{ + u64 val = cc->params[0]; + + if (!cc_ddr_boost_enable) + return; + + if (cc_is_nonblock(cc)) + return; + + val = cc_ddr_to_devfreq(val); + + if (cc->type == CC_CTL_TYPE_RESET) + val = CC_DDR_RESET_VAL; + + cc_expect_ddrfreq = val; +} + +static void cc_adjust_ddr_lock_freq(struct cc_command *cc) +{ + u64 val = cc->params[0]; + u64 cur; + + if (!cc_ddr_boost_enable) + return; + + if (cc_is_nonblock(cc)) + return; + + if (cc->type == CC_CTL_TYPE_RESET) + val = CC_DDR_RESET_VAL; + + /* check if need update */ + cur = query_ddrfreq(); + +// if (cur != val) +// aop_lock_ddr_freq(val); +} + +static void cc_adjust_sched(struct cc_command *cc) +{ +#ifdef CONFIG_OPCHAIN + struct task_struct *task = NULL; + pid_t pid = cc->params[0]; +#endif + + if (cc_is_nonblock(cc)) + return; + +#ifdef CONFIG_OPCHAIN + if (cc_is_reset(cc)) { + opc_set_boost(0); + return; + } + + rcu_read_lock(); + task = find_task_by_vpid(pid); + if (task) { + cc_logv("set task %s %d to prime core\n", task->comm, task->pid); + task->etask_claim = UT_PERF_TOP; + opc_set_boost(1); + } else + cc_logw("can't find task %d\n", pid); + rcu_read_unlock(); +#endif +} + +static void cc_tb_cctl_boost(struct cc_command *cc) +{ + if (!cc_tb_cctl_boost_enable) + return; + + if (cc_is_reset(cc)) { + ccdm_update_hint_1(CCDM_TB_CCTL_BOOST, 0); + core_ctl_op_boost(false, 0); + } else { + ccdm_update_hint_1(CCDM_TB_CCTL_BOOST, 1); + core_ctl_op_boost(true, cc->params[0]); + } +} + +void cc_process(struct cc_command* cc) +{ + if (cc->type < CC_CTL_TYPE_ONESHOT_NONBLOCK) { + if (!cc_is_reset(cc)) + tracing_mark_write(cc, 1, false); + } + + cc_logv("pid: %u, group: %u, category: %u, type: %u, params: %llu %llu %llu %llu\n", + cc->pid, cc->group, cc->category, cc->type, cc->params[0], cc->params[1], cc->params[2], cc->params[3]); + + switch (cc->category) { + case CC_CTL_CATEGORY_CLUS_0_FREQ: + cc_logv("cpufreq: type: %u, cluster: 0 target: %llu version: %llu\n", + cc->type, cc->params[0], cc->params[3]); + cc_adjust_cpufreq(cc); + break; + case CC_CTL_CATEGORY_CLUS_1_FREQ: + cc_logv("cpufreq: type: %u, cluster: 1 target: %llu version: %llu\n", + cc->type, cc->params[0], cc->params[3]); + cc_adjust_cpufreq(cc); + break; + case CC_CTL_CATEGORY_CLUS_2_FREQ: + cc_logv("cpufreq: type: %u, cluster: 2 target: %llu version: %llu\n", + cc->type, cc->params[0], cc->params[3]); + cc_adjust_cpufreq(cc); + break; + case CC_CTL_CATEGORY_FPS_BOOST: + break; + case CC_CTL_CATEGORY_DDR_VOTING_FREQ: + cc_logv("ddrfreq voting: type: %u, target: %llu\n", cc->type, cc->params[0]); + cc_adjust_ddr_voting_freq(cc); + break; + case CC_CTL_CATEGORY_DDR_LOCK_FREQ: + cc_logv("ddrfreq lock: type: %u, target: %llu\n", cc->type, cc->params[0]); + cc_adjust_ddr_lock_freq(cc); + case CC_CTL_CATEGORY_SCHED_PRIME_BOOST: + cc_logv("sched prime boost: type: %u, param: %llu\n", cc->type, cc->params[0]); + cc_adjust_sched(cc); + break; + case CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY: + cc_query_cpufreq(cc); + cc_logv("cpufreq query: type: %u, cluster: 0, freq: %llu\n", cc->type, cc->response); + break; + case CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY: + cc_query_cpufreq(cc); + cc_logv("cpufreq query: type: %u, cluster: 1, freq: %llu\n", cc->type, cc->response); + break; + case CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY: + cc_query_cpufreq(cc); + cc_logv("cpufreq query: type: %u, cluster: 2, freq: %llu\n", cc->type, cc->response); + break; + case CC_CTL_CATEGORY_DDR_FREQ_QUERY: + cc_query_ddrfreq(cc); + cc_logv("ddrfreq query: type: %u, freq: %llu\n", cc->type, cc->response); + break; + /* Trubo rendering */ + case CC_CTL_CATEGORY_TB_FREQ_BOOST: + cc_logv("tb_freq_boost: type: %u, hint %llu %llu %llu %llu\n", + cc->type, cc->params[0], cc->params[1], + cc->params[2], cc->params[3]); + cc_tb_freq_boost(cc); + break; + case CC_CTL_CATEGORY_TB_PLACE_BOOST: + cc_logv("tb_place_boost: type: %u, hint %llu %llu %llu\n", + cc->type, cc->params[0], cc->params[1], + cc->params[2]); + cc_tb_place_boost(cc); + break; + case CC_CTL_CATEGORY_TB_CORECTL_BOOST: + cc_logv("tb_corectl_boost: type: %u, hint %llu\n", + cc->type, cc->params[0]); + cc_tb_cctl_boost(cc); + break; + default: + cc_logw("category %d not support\n", cc->category); + break; + } + + if (cc->type < CC_CTL_TYPE_ONESHOT_NONBLOCK) { + if (cc_is_reset(cc)) + tracing_mark_write(cc, 0, false); + } +} + +static inline void dump_cc(struct cc_command *cc, const char* func, const char* msg) +{ + cc_logv("%s: %s: pid: %d, period_us: %u, prio: %u, group: %u, category: %u, type: %u, [0]: %llu, [1]: %llu, [2]: %llu, [3]: %llu, response: %llu, bind_leader: %d, status: %d\n", + func, msg, + cc->pid, cc->period_us, cc->prio, cc->group, cc->category, + cc->type, cc->params[0], cc->params[1], cc->params[2], + cc->params[3], cc->response, cc->bind_leader, cc->status); +} + +static inline struct cc_command* find_highest_cc_nolock(int category) +{ + struct cc_tsk_data* data = NULL; + struct cc_command *cc = NULL; + int prio; + + /* find the highest priority request to perform */ + for (prio = CC_PRIO_HIGH; !cc && prio < CC_PRIO_MAX; ++prio) { + if (!list_empty(&cc_record[category].phead[prio])) { + list_for_each_entry(data, &cc_record[category].phead[prio], node) { + cc = &data->cc; + break; + } + } + } + return cc; +} + +/* find the highest priority request to perform */ +static struct cc_command* find_highest_cc(int category) +{ + struct cc_command* cc; + + spin_lock(&cc_record[category].lock); + cc = find_highest_cc_nolock(category); + spin_unlock(&cc_record[category].lock); + return cc; +} + + +static void cc_record_acq(int category, struct cc_command* cc) +{ + struct cc_command *high_cc = find_highest_cc(category); + + dump_cc(cc, __func__, "current request"); + if (high_cc) { + dump_cc(high_cc, __func__, "highest request"); + } else { + cc_logw("%s: can't find any request\n", __func__); + return; + } + + /* + * apply change + * if high_cc not equal to cc, it should be applied earlier + */ + if (high_cc == cc) + cc_process(high_cc); +} + +static void cc_record_rel(int category, struct cc_command *cc) +{ + struct cc_command* next_cc = find_highest_cc(category); + bool is_nonblock = cc->type >= CC_CTL_TYPE_ONESHOT_NONBLOCK; + + /* update reset type */ + cc->type = is_nonblock? CC_CTL_TYPE_RESET_NONBLOCK: CC_CTL_TYPE_RESET; + if (next_cc) { + /* apply next since we detach the highest before */ + cc_logv("got pending request, re-apply\n"); + dump_cc(next_cc, __func__, "next request"); + cc_process(next_cc); + } else { + /* no request pending, reset finally */ + cc_logv("no pending request, release\n"); + dump_cc(cc, __func__, "reset request"); + cc_process(cc); + } +} + +static void cc_record_init(void) +{ + int i, j; + + /* init cc_record */ + for (i = 0; i < CC_CTL_CATEGORY_MAX; ++i) { + /* assign acquire and release */ + spin_lock_init(&cc_record[i].lock); + for (j = 0; j < CC_PRIO_MAX; ++j) + INIT_LIST_HEAD(&cc_record[i].phead[j]); + } +} + +static void cc_tsk_acq(struct cc_tsk_data* data) +{ + struct cc_command *cc; + u32 delay_us; + u32 category; + int prio; + + tracing_mark_write(cc, 1, true); + + current->cc_enable = true; + + /* add into cc_record */ + /* TODO check category & prio value */ + category = data->cc.category; + prio = data->cc.prio; + cc = &data->cc; + delay_us = cc->period_us; + + /* update boost ts */ + cc_boost_ts_update(cc); + + dump_cc(cc, __func__, "current request"); + + /* if already inside list, detach first */ + spin_lock(&cc_record[category].lock); + if (!list_empty(&data->node)) { + /* cancel queued delayed work first */ + cancel_delayed_work(&data->dwork); + list_del_init(&data->node); + dump_cc(cc, __func__, "[detach]"); + } + list_add(&data->node, &cc_record[category].phead[prio]); + dump_cc(cc, __func__, "[attach]"); + spin_unlock(&cc_record[category].lock); + + /* trigger system control */ + cc_record_acq(category, cc); + + /* queue delay work for release */ + queue_delayed_work(cc_wq, &data->dwork, usecs_to_jiffies(delay_us)); + + /* update stat */ + cc_stat_inc(category); +} + +static void cc_tsk_rel(struct cc_tsk_data* data) +{ + struct cc_command* cc = &data->cc; + struct cc_command* high_cc; + u32 category = cc->category; + + /* update boost ts */ + cc_boost_ts_update(cc); + + /* detach first */ + dump_cc(cc, __func__, "current request"); + + spin_lock(&cc_record[category].lock); + high_cc = find_highest_cc_nolock(category); + /* detach first */ + if (!list_empty(&data->node)) { + cancel_delayed_work(&data->dwork); + list_del_init(&data->node); + dump_cc(cc, __func__, "[detach]"); + } else { + cc_logv("try to detach, but already detached\n"); + } + + if (cc != high_cc) { + /* no need to worry, just detach and return */ + spin_unlock(&cc_record[category].lock); + tracing_mark_write(cc, 0, true); + return; + } + spin_unlock(&cc_record[category].lock); + + /* trigger system control */ + cc_record_rel(category, cc); + tracing_mark_write(cc, 0, true); +} + +static void cc_delay_rel(struct work_struct *work) +{ + struct cc_tsk_data* data = container_of(work, struct cc_tsk_data, dwork.work); + struct cc_command* cc = &data->cc; + + /* delay work no need to use nonblock call */ + cc->type = CC_CTL_TYPE_RESET; + cc_tsk_rel(data); +} + +static struct cc_tsk_data* cc_init_ctd(void) +{ + struct cc_tsk_data *ctd = NULL; + int i = 0; + + ctd = kzalloc(sizeof(struct cc_tsk_data) * CC_CTL_CATEGORY_MAX, GFP_KERNEL); + if (!ctd) + return NULL; + + for (i = 0; i < CC_CTL_CATEGORY_MAX; ++i) { + /* init all category control */ + INIT_LIST_HEAD(&ctd[i].node); + INIT_DELAYED_WORK(&ctd[i].dwork, cc_delay_rel); + } + return ctd; +} + +static inline struct cc_command* get_tsk_cc(bool bind_leader, u32 category) +{ + struct task_struct* task = bind_leader? current->group_leader: current; + + /* FIXME may be race */ + /* init ctd */ + if (!task->ctd) { + task->ctd = cc_init_ctd(); + if (!task->ctd) { + cc_loge("task %s(%d) cc_tsk_data init failed\n", task->comm, task->pid); + return NULL; + } + cc_logv("%s: pid: %s(%d) init ctd successful\n", + __func__, task->comm, task->pid); + } + + return &task->ctd[category].cc; +} + +static inline struct cc_tsk_data* get_tsk_data(bool bind_leader, u32 category) +{ + struct task_struct* task = bind_leader? current->group_leader: current; + return &task->ctd[category]; +} + +static inline int cc_tsk_copy(struct cc_command* cc, bool copy_to_user) +{ + u32 category = cc->category; + + struct cc_command* tskcc = get_tsk_cc(cc->bind_leader, category); + + if (!tskcc) + return -1; + + if (copy_to_user) + memcpy(cc, tskcc, sizeof(struct cc_command)); + else + memcpy(tskcc, cc, sizeof(struct cc_command)); + + return 0; +} + +static inline struct task_struct *cc_get_owner(bool bind_leader) +{ + struct task_struct *task = current; + + rcu_read_lock(); + + if (bind_leader) + task = find_task_by_vpid(current->tgid); + + if (task) + get_task_struct(task); + + rcu_read_unlock(); + return task; +} + +static inline void cc_put_owner(struct task_struct *task) +{ + if (likely(task)) + put_task_struct(task); +} + +// call with get/put owner`s task_struct +static void __cc_tsk_process(struct cc_command* cc) +{ + u32 category = cc->category; + + /* query can return first */ + if (cc_is_query(category)) { + cc_process(cc); + return; + } + + /* copy cc */ + if (cc_tsk_copy(cc, false)) + return; + + if (cc_is_reset(cc)) + cc_tsk_rel(get_tsk_data(cc->bind_leader, category)); + else + cc_tsk_acq(get_tsk_data(cc->bind_leader, category)); + + /* copy back to userspace cc */ + cc_tsk_copy(cc, true); +} + +void cc_tsk_process(struct cc_command* cc) +{ + struct task_struct *owner = NULL; + + owner = cc_get_owner(cc->bind_leader); + + if (!owner) { + cc_logw("request owner is gone\n"); + return; + } + + if (likely(owner->cc_enable)) + __cc_tsk_process(cc); + else + cc_logw("request owner is going to leave\n"); + + cc_put_owner(owner); +} + +/* for fork and exit, use void* to avoid include sched.h in control_center.h */ +void cc_tsk_init(void* ptr) +{ + struct task_struct *task = (struct task_struct*) ptr; + + task->cc_enable = true; + task->ctd = NULL; +} + +void cc_tsk_disable(void* ptr) +{ + struct task_struct *task = (struct task_struct*) ptr; + struct cc_tsk_data *data = task->ctd; + u32 category; + + if (!task->ctd) + return; + + // disable to avoid further use + task->cc_enable = false; + + /* detach all */ + for (category = 0; category < CC_CTL_CATEGORY_MAX; ++category) { + bool need_free = false; + cc_logv("%s: pid: %s(%d) free category %d\n", + __func__, task->comm, task->pid, category); + spin_lock(&cc_record[category].lock); + if (!list_empty(&data[category].node)) { + need_free = true; + list_del_init(&data[category].node); + dump_cc(&data[category].cc, __func__, "[detach]"); + } + spin_unlock(&cc_record[category].lock); + + if (need_free) { + cc_logv("%s: pid: %s(%d) free category %d, need update.\n", + __func__, task->comm, task->pid, category); + cancel_delayed_work_sync(&data[category].dwork); + /* since we're going to free ctd, we need to force set type to blocked version */ + data[category].cc.type = CC_CTL_TYPE_RESET; + + cc_record_rel(category, &data[category].cc); + } + } +} + +void cc_tsk_free(void* ptr) +{ + struct task_struct *task = (struct task_struct*) ptr; + + if (!task->ctd) + return; + + kfree(task->ctd); + task->ctd = NULL; +} + +static int cc_ctl_show(struct seq_file *m, void *v) +{ + seq_printf(m, "control center version: %s\n", CC_CTL_VERSION); + return 0; +} + +static int cc_ctl_open(struct inode *ip, struct file *fp) +{ + cc_logv("opened by %s %d\n", current->comm, current->pid); + return single_open(fp, cc_ctl_show, NULL);; +} + +static int cc_ctl_close(struct inode *ip, struct file *fp) +{ + cc_logv("closed by %s %d\n", current->comm, current->pid); + return 0; +} + +static long cc_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long __user arg) +{ + ktime_t begin, end; + s64 t; + static s64 tmax = 0; + + if (_IOC_TYPE(cmd) != CC_IOC_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > CC_IOC_MAX) return -ENOTTY; + + CC_TIME_START(begin); + + cc_logv("%s: cmd: %u, arg: %lu\n", __func__, CC_IOC_COMMAND, arg); + switch (cmd) { + case CC_IOC_COMMAND: + { + struct cc_command cc; + + if (copy_from_user(&cc, (struct cc_command *) arg, sizeof(struct cc_command))) + break; + + cc_tsk_process(&cc); + + if (copy_to_user((struct cc_command *) arg, &cc, sizeof(struct cc_command))) + break; + } + } + + CC_TIME_END(begin, end, t, tmax); + return 0; +} + +static const struct file_operations cc_ctl_fops = { + .owner = THIS_MODULE, + .open = cc_ctl_open, + .release = cc_ctl_close, + .unlocked_ioctl = cc_ctl_ioctl, + .compat_ioctl = cc_ctl_ioctl, + + .read = seq_read, + .llseek = seq_lseek, +}; + +/* TODO try to simplify the register flow */ +static dev_t cc_ctl_dev; +static struct class *driver_class; +static struct cdev cdev; +static int cc_cdev_init(void) +{ + int rc; + struct device *class_dev; + + rc = alloc_chrdev_region(&cc_ctl_dev, 0, 1, CC_CTL_NODE); + if (rc < 0) { + cc_loge("alloc_chrdev_region failed %d\n", rc); + return 0; + } + + driver_class = class_create(THIS_MODULE, CC_CTL_NODE); + if (IS_ERR(driver_class)) { + rc = -ENOMEM; + cc_loge("class_create failed %d\n", rc); + goto exit_unreg_chrdev_region; + } + class_dev = device_create(driver_class, NULL, cc_ctl_dev, NULL, CC_CTL_NODE); + if (IS_ERR(class_dev)) { + cc_loge("class_device_create failed %d\n", rc); + rc = -ENOMEM; + goto exit_destroy_class; + } + cdev_init(&cdev, &cc_ctl_fops); + cdev.owner = THIS_MODULE; + rc = cdev_add(&cdev, MKDEV(MAJOR(cc_ctl_dev), 0), 1); + if (rc < 0) { + cc_loge("cdev_add failed %d\n", rc); + goto exit_destroy_device; + } + return 0; +exit_destroy_device: + device_destroy(driver_class, cc_ctl_dev); +exit_destroy_class: + class_destroy(driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(cc_ctl_dev, 1); + return 0; +} + +static struct cc_async_rq* cc_get_rq(struct list_head* head) +{ + struct cc_async_rq *rq = NULL; + + spin_lock(&cc_async_lock); + if (!list_empty(head)) { + list_for_each_entry(rq, head, node) { + list_del_init(&rq->node); + break; + } + } + spin_unlock(&cc_async_lock); + + return rq; +} + +static void __cc_attach_rq(struct cc_async_rq *rq, struct list_head* head) +{ + spin_lock(&cc_async_lock); + list_add(&rq->node, head); + spin_unlock(&cc_async_lock); +} + +static void cc_release_rq(struct cc_async_rq* rq, struct list_head* head) +{ + /* clean before release */ + memset(&rq->cc, 0, sizeof (struct cc_command)); + __cc_attach_rq(rq, head); +} + +static void __cc_queue_rq(struct cc_async_rq* rq, struct list_head* head) +{ + __cc_attach_rq(rq, head); +} + +static void cc_work(struct work_struct *work) +{ + /* time related */ + ktime_t begin, end; + s64 t; + static s64 tmax = 0; + + struct cc_async_rq* rq = + container_of(work, struct cc_async_rq, work); + + CC_TIME_START(begin); + + /* main loop */ + cc_process(&rq->cc); + + cc_release_rq(rq, &cc_request_list); + + CC_TIME_END(begin, end, t, tmax); +} + +static int cc_worker(void* arg) +{ + ktime_t begin, end; + s64 t; + static s64 tmax = 0; + + /* perform async system resousrce adjustment */ + while (!kthread_should_stop()) { + struct cc_async_rq *rq; + + CC_TIME_START(begin); +redo: + rq = cc_get_rq(&cc_pending_list); + if (!rq) { + goto finish; + } + /* main loop */ + cc_process(&rq->cc); + + cc_release_rq(rq, &cc_request_list); + goto redo; + +finish: + CC_TIME_END(begin, end, t, tmax); + + /* sleep for next wake up */ + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + return 0; +} + +static void cc_queue_rq(struct cc_command *cc) +{ + struct cc_async_rq *rq = cc_get_rq(&cc_request_list); + if (!rq) { + cc_logw("rq not enough\n"); + return; + } + + memcpy(&rq->cc, cc, sizeof(struct cc_command)); + + if (likely(cc_wq)) { + /* if support workqueue, using workqueue */ + queue_work(cc_wq, &rq->work); + } else if (likely(cc_worker_task)) { + /* if support worker, using worker */ + __cc_queue_rq(rq, &cc_pending_list); + wake_up_process(cc_worker_task); + } else { + /* fall back to original version */ + cc_logw_ratelimited("cc command fall back\n"); + cc_process(&rq->cc); + cc_release_rq(rq, &cc_request_list); + } +} + +static void cc_worker_init(void) +{ + int i; + + /* init for request/ pending/ lock */ + INIT_LIST_HEAD(&cc_request_list); + INIT_LIST_HEAD(&cc_pending_list); + + /* init requests */ + for (i = 0; i < CC_ASYNC_RQ_MAX; ++i) { + INIT_LIST_HEAD(&cc_async_rq[i].node); + INIT_WORK(&cc_async_rq[i].work, cc_work); + cc_async_rq[i].idx = i; + spin_lock(&cc_async_lock); + list_add(&cc_async_rq[i].node, &cc_request_list); + spin_unlock(&cc_async_lock); + } + + cc_worker_task = kthread_run(cc_worker, NULL, "cc_worker"); + if (IS_ERR(cc_worker_task)) + cc_loge("cc_worker create failed\n"); + + cc_wq = alloc_ordered_workqueue("cc_wq", 0); + if (!cc_wq) + cc_loge("alloc work queue fail\n"); +} + +static int cc_dump_list_show(char *buf, const struct kernel_param *kp) +{ + int cnt = 0; + int size = 0; + struct cc_async_rq *rq; + + spin_lock(&cc_async_lock); + + /* request list */ + size = 0; + list_for_each_entry(rq, &cc_request_list, node) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%d ", rq->idx); + ++size; + } + if (size) + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n", rq->idx); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "request list: size: %d\n", size); + + /* pending list */ + size = 0; + list_for_each_entry(rq, &cc_pending_list, node) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%d ", rq->idx); + ++size; + } + if (size) + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n", rq->idx); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "pending list: size: %d\n", size); + + spin_unlock(&cc_async_lock); + + return cnt; +} + +static struct kernel_param_ops cc_dump_list_ops = { + .get = cc_dump_list_show, +}; +module_param_cb(dump_list, &cc_dump_list_ops, NULL, 0644); + +static int cc_ddr_freq_show(char *buf, const struct kernel_param *kp) +{ + int cnt = 0; + u64 freqshow = 0; + clk_get_ddr_freq(&freqshow); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "ddrfreq: %llu\n", freqshow); + return cnt; +} + +static struct kernel_param_ops cc_ddr_freq_ops = { + .get = cc_ddr_freq_show, +}; +module_param_cb(freq_show, &cc_ddr_freq_ops, NULL, 0644); + +static int cc_dump_status_show(char *buf, const struct kernel_param *kp) +{ + struct cpufreq_policy *pol; + int cnt = 0; + int i, idx; + u64 val; + + /* dump cpufreq control status */ + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "cpufreq:\n"); + for (i = 0; i < CLUSTER_NUM; ++i) { + idx = cc_get_cpu_idx(i); + if (idx == -1) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "cluster %d offline\n", i); + continue; + } + pol = cpufreq_cpu_get(idx); + if (!pol) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "cluster %d can't get policy\n", i); + continue; + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "cluster %d min %u max %u cur %u, cc_min %u cc_max %u\n", + i, pol->min, pol->max, pol->cur, pol->cc_min, pol->cc_max); + cpufreq_cpu_put(pol); + } + + /* dump ddrfreq control status */ + val = query_ddrfreq(); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "ddrfreq: %llu\n", val); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "expected ddrfreq: %lu\n", cc_expect_ddrfreq); + return cnt; +} + +static struct kernel_param_ops cc_dump_status_ops = { + .get = cc_dump_status_show, +}; +module_param_cb(dump_status, &cc_dump_status_ops, NULL, 0644); + +static unsigned int ccdm_min_util_threshold = 35; +static int ccdm_min_util_threshold_store(const char *buf, + const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return 0; + + ccdm_min_util_threshold = val; + + return 0; +} + +static int ccdm_min_util_threshold_show(char *buf, + const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", ccdm_min_util_threshold); +} + +static struct kernel_param_ops ccdm_min_thres_ops = { + .set = ccdm_min_util_threshold_store, + .get = ccdm_min_util_threshold_show, +}; +module_param_cb(ccdm_min_util_thres, &ccdm_min_thres_ops, NULL, 0664); + +unsigned int ccdm_get_min_util_threshold(void) +{ + return ccdm_min_util_threshold; +} + +/* debug purpose, should be removed later */ +static int cc_ccdm_status_show(char *buf, const struct kernel_param *kp) +{ + struct cpufreq_policy *pol; + int cnt = 0; + int i, idx; + u64 val; + + /* TODO add a way to update trust/weight */ + struct ccdm_info { + long long c_min[3]; + long long c_max[3]; + long long c_fps_boost[3]; + long long fps_boost_hint; + long long trust[3]; + long long weight[3]; + long long c_fps_boost_ddrfreq; + long long ddrfreq; + long long tb_freq_boost[3]; + long long tb_place_boost_hint; + long long tb_idle_block_hint[8]; + long long tb_cctl_boost_hint; + } info; + + ccdm_get_status((void *) &info); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "cpufreq:\n"); + for (i = 0; i < 3; ++i) { + idx = cc_get_cpu_idx(i); + if (idx == -1) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "cluster %d offline\n", i); + continue; + } + pol = cpufreq_cpu_get(idx); + if (!pol) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "cluster %d can't get policy\n", i); + continue; + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "cluster %d min %u max %u cur %u, ", + i, pol->min, pol->max, pol->cur); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "ccdm: min %lld max %lld ", + info.c_min[i], info.c_max[i]); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "fps_boost %lld trust %lld weight %lld\n", + info.c_fps_boost[i], info.trust[i], info.weight[i]); + cpufreq_cpu_put(pol); + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "fps_boost hint %lld\n", info.fps_boost_hint); + + /* dump ddrfreq control status */ + val = query_ddrfreq(); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "ddrfreq: %llu exptected: %llu hint: %llu\n", + val, info.ddrfreq, info.c_fps_boost_ddrfreq); + + for (i = 0; i < 3; ++i) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "tb_freq_boost: clus %lld, extra util %lld\n", + i, info.tb_freq_boost[i]); + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "tb_place_boost: %lld\n", info.tb_place_boost_hint); + + for (i = 0; i < 8; ++i) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "tb_idle_block[%d]: %llu %llu\n", + i, get_jiffies_64(), (u64)info.tb_idle_block_hint[i]); + } + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "tb_corectl_boost: %lld\n", info.tb_cctl_boost_hint); + + return cnt; +} + +static struct kernel_param_ops cc_ccdm_status_ops = { + .get = cc_ccdm_status_show, +}; +module_param_cb(ccdm_status, &cc_ccdm_status_ops, NULL, 0644); + +static const char *cc_category_tags[CC_CTL_CATEGORY_MAX] = { + "cpufreq_0", + "cpufreq_1", + "cpufreq_2", + "fps_boost", + "ddrfreq voting:", + "ddrfreq lock:", + "sched_prime_boost", + "cpufreq_0_query", + "cpufreq_1_query", + "cpufreq_2_query", + "ddrfreq_query", + "turbo boost freq", + "turbo boost placement", + "turbo boost corectl boost" +}; + +static const char *cc_category_tags_mapping(int idx) +{ + if (idx >= 0 && idx < CC_CTL_CATEGORY_MAX) + return cc_category_tags[idx]; + + return ""; +} + +static int cc_dump_record_show(char *buf, const struct kernel_param *kp) +{ + struct cc_tsk_data* data; + const char* tag; + u32 prio; + int cnt = 0; + int i; + + for (i = 0; i < CC_CTL_CATEGORY_MAX; ++i) { + /* ignore query part */ + if (cc_is_query(i)) + continue; + + spin_lock(&cc_record[i].lock); + tag = cc_category_tags_mapping(i); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%s:\n", tag); + for (prio = 0; prio < CC_PRIO_MAX; ++prio) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, " p[%d]:\n", prio); + list_for_each_entry(data, &cc_record[i].phead[prio], node) { + struct cc_command* cc = &data->cc; + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + " pid: %d, period_us: %u, prio: %u, group: %u, category: %u" + ", type: %u, [0]: %llu, [1]: %llu, [2]: %llu, [3]: %llu" + ", response: %llu, status: %d\n", + cc->pid, cc->period_us, cc->prio, cc->group, cc->category, + cc->type, cc->params[0], cc->params[1], cc->params[2], + cc->params[3], cc->response, cc->status); + } + } + spin_unlock(&cc_record[i].lock); + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "cnt: %d\n", cnt); + return cnt; +} + +static struct kernel_param_ops cc_dump_record_ops = { + .get = cc_dump_record_show, +}; +module_param_cb(dump_record, &cc_dump_record_ops, NULL, 0644); + +static int cc_dump_stat_show(char *buf, const struct kernel_param *kp) +{ + const char *tag; + long long cc_cnt, cc_tcnt; + int cnt = 0; + int i; + + for (i = 0; i < CC_CTL_CATEGORY_MAX; ++i) { + tag = cc_category_tags_mapping(i); + cc_cnt = atomic64_read(&cc_stat.cnt[i]); + cc_tcnt = atomic64_read(&cc_stat.tcnt[i]) + cc_cnt; + atomic64_set(&cc_stat.cnt[i], 0); + atomic64_set(&cc_stat.tcnt[i], cc_tcnt); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, + "%s: %lld %lld\n", tag, cc_cnt, cc_tcnt); + } + return cnt; +} + +static struct kernel_param_ops cc_dump_stat_ops = { + .get = cc_dump_stat_show, +}; +module_param_cb(dump_stat, &cc_dump_stat_ops, NULL, 0644); + +static const struct file_operations cc_ctl_proc_fops = { + .owner = THIS_MODULE, + .open = cc_ctl_open, + .release = cc_ctl_close, + .unlocked_ioctl = cc_ctl_ioctl, + .compat_ioctl = cc_ctl_ioctl, + + .read = seq_read, + .llseek = seq_lseek, +}; + +static inline void cc_proc_init(void) +{ + proc_create(CC_CTL_NODE, S_IFREG | 0660, NULL, &cc_ctl_proc_fops); +} + +static int cc_init(void) +{ + /* FIXME + * remove later, so far just for compatible + */ + cc_cdev_init(); // create /dev/cc_ctl + + cc_proc_init(); // create /proc/cc_ctl + cc_record_init(); + cc_worker_init(); + cc_logi("control center inited\n"); + return 0; +} + +pure_initcall(cc_init); diff --git a/drivers/oneplus/coretech/control_center/decision_maker.c b/drivers/oneplus/coretech/control_center/decision_maker.c new file mode 100644 index 0000000000000000000000000000000000000000..1e856b814c61ef7be28593898f5da601cb1cf3fc --- /dev/null +++ b/drivers/oneplus/coretech/control_center/decision_maker.c @@ -0,0 +1,410 @@ +/* decision maker info */ + +#define CCDM_CLUS_SIZE 3 +#define CCDM_CPU_SIZE 8 +#define CCDM_ULLONG_MAX (0xffffffffffffffffULL) +struct ccdm_info { + long long c_min[CCDM_CLUS_SIZE]; + long long c_max[CCDM_CLUS_SIZE]; + long long c_fps_boost[CCDM_CLUS_SIZE]; + long long fps_boost_hint; + long long trust[CCDM_CLUS_SIZE]; + long long weight[CCDM_CLUS_SIZE]; + + long long c_fps_boost_ddrfreq; + long long ddrfreq; + /* Turbo Boost */ + long long tb_freq_boost[CCDM_CLUS_SIZE]; + long long tb_place_boost_hint; + long long tb_idle_block_hint[CCDM_CPU_SIZE]; + long long tb_cctl_boost_hint; +}; + +/* expected to public */ +enum { + CCDM_DEFAULT = 0, + CCDM_CLUS_0_CPUFREQ, + CCDM_CLUS_1_CPUFREQ, + CCDM_CLUS_2_CPUFREQ, + CCDM_FPS_BOOST, + CCDM_VOTING_DDRFREQ, + CCDM_FPS_BOOST_HINT, + + /* Turbo boost */ + CCDM_TB_CLUS_0_FREQ_BOOST, + CCDM_TB_CLUS_1_FREQ_BOOST, + CCDM_TB_CLUS_2_FREQ_BOOST, + CCDM_TB_FREQ_BOOST, + CCDM_TB_PLACE_BOOST, + + CCDM_TB_CPU_0_IDLE_BLOCK, + CCDM_TB_CPU_1_IDLE_BLOCK, + CCDM_TB_CPU_2_IDLE_BLOCK, + CCDM_TB_CPU_3_IDLE_BLOCK, + CCDM_TB_CPU_4_IDLE_BLOCK, + CCDM_TB_CPU_5_IDLE_BLOCK, + CCDM_TB_CPU_6_IDLE_BLOCK, + CCDM_TB_CPU_7_IDLE_BLOCK, + CCDM_TB_IDLE_BLOCK, + CCDM_TB_CCTL_BOOST, +}; + +static struct ccdm_info ginfo = { + { 0, 0, 0}, // c_min + { 0, 0, 0}, // c_max + { 0, 0, 0}, // fps_boost + 0, // fps_boost_hint + { 100, 100, 100}, // trust + { 100, 100, 100}, // weight + 0, // fps_boost_ddr + 0, // ddr + { 0, 0, 0}, // freq boost + 0, // place boost hint + { CCDM_ULLONG_MAX, CCDM_ULLONG_MAX, + CCDM_ULLONG_MAX, CCDM_ULLONG_MAX, + CCDM_ULLONG_MAX, CCDM_ULLONG_MAX, + CCDM_ULLONG_MAX, CCDM_ULLONG_MAX + }, // idle block + 0, + + +}; + +/* helper */ +static inline clamp(long long val, long long lo, long long hi) +{ + val = val >= lo ? val : lo; + val = val <= hi ? val : hi; + return val; +} + +/* update info part */ +void ccdm_update_hint_1(int type, long long arg1) +{ + switch (type) { + case CCDM_VOTING_DDRFREQ: + ginfo.ddrfreq = arg1; + break; + case CCDM_TB_CLUS_0_FREQ_BOOST: + ginfo.tb_freq_boost[0] = arg1; + break; + case CCDM_TB_CLUS_1_FREQ_BOOST: + ginfo.tb_freq_boost[1] = arg1; + break; + case CCDM_TB_CLUS_2_FREQ_BOOST: + ginfo.tb_freq_boost[2] = arg1; + break; + case CCDM_TB_PLACE_BOOST: + ginfo.tb_place_boost_hint = arg1; + break; + case CCDM_TB_CPU_0_IDLE_BLOCK: + ginfo.tb_idle_block_hint[0] = arg1; + break; + case CCDM_TB_CPU_1_IDLE_BLOCK: + ginfo.tb_idle_block_hint[1] = arg1; + break; + case CCDM_TB_CPU_2_IDLE_BLOCK: + ginfo.tb_idle_block_hint[2] = arg1; + break; + case CCDM_TB_CPU_3_IDLE_BLOCK: + ginfo.tb_idle_block_hint[3] = arg1; + break; + case CCDM_TB_CPU_4_IDLE_BLOCK: + ginfo.tb_idle_block_hint[4] = arg1; + break; + case CCDM_TB_CPU_5_IDLE_BLOCK: + ginfo.tb_idle_block_hint[5] = arg1; + break; + case CCDM_TB_CPU_6_IDLE_BLOCK: + ginfo.tb_idle_block_hint[6] = arg1; + break; + case CCDM_TB_CPU_7_IDLE_BLOCK: + ginfo.tb_idle_block_hint[7] = arg1; + break; + case CCDM_TB_CCTL_BOOST: + ginfo.tb_cctl_boost_hint = arg1; + break; + } +} + +void ccdm_update_hint_2(int type, long long arg1, long long arg2) +{ + switch (type) { + case CCDM_CLUS_0_CPUFREQ: + ginfo.c_min[0] = arg1; + ginfo.c_max[0] = arg2; + break; + case CCDM_CLUS_1_CPUFREQ: + ginfo.c_min[1] = arg1; + ginfo.c_max[1] = arg2; + break; + case CCDM_CLUS_2_CPUFREQ: + ginfo.c_min[2] = arg1; + ginfo.c_max[2] = arg2; + break; + } +} + +void ccdm_update_hint_3( + int type, + long long arg1, + long long arg2, + long long arg3) +{ + switch (type) { + case CCDM_TB_FREQ_BOOST: + ginfo.tb_freq_boost[0] = arg1; + ginfo.tb_freq_boost[1] = arg2; + ginfo.tb_freq_boost[2] = arg3; + break; + } +} + +void ccdm_update_hint_4( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ + switch (type) { + case CCDM_FPS_BOOST: + ginfo.c_fps_boost[0] = arg1; + ginfo.c_fps_boost[1] = arg2; + ginfo.c_fps_boost[2] = arg3; + ginfo.c_fps_boost_ddrfreq = arg4; + break; + } +} + +long long ccdm_get_hint(int type) +{ + switch (type) { + case CCDM_FPS_BOOST_HINT: + return ginfo.fps_boost_hint; + case CCDM_TB_PLACE_BOOST: + return ginfo.tb_place_boost_hint; + case CCDM_TB_CLUS_0_FREQ_BOOST: + return ginfo.tb_freq_boost[0]; + case CCDM_TB_CLUS_1_FREQ_BOOST: + return ginfo.tb_freq_boost[1]; + case CCDM_TB_CLUS_2_FREQ_BOOST: + return ginfo.tb_freq_boost[2]; + case CCDM_TB_CPU_0_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[0]; + case CCDM_TB_CPU_1_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[1]; + case CCDM_TB_CPU_2_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[2]; + case CCDM_TB_CPU_3_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[3]; + case CCDM_TB_CPU_4_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[4]; + case CCDM_TB_CPU_5_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[5]; + case CCDM_TB_CPU_6_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[6]; + case CCDM_TB_CPU_7_IDLE_BLOCK: + return ginfo.tb_idle_block_hint[7]; + case CCDM_TB_CCTL_BOOST: + return ginfo.tb_cctl_boost_hint; + } + return 0; +} + +int ccdm_any_hint(void) +{ + int i; + + for (i = CCDM_TB_CLUS_0_FREQ_BOOST; i < CCDM_TB_CPU_0_IDLE_BLOCK; ++i) { + if (ccdm_get_hint(i)) + return i; + } + + return 0; +} + +/* output util */ +static long long cpufreq_decision(int type, + long long util, + long long min_freq, + long long max_freq, + long long max_util) // TBD +{ + long long final_util, final_freq, extra_util; + long long w, t; + int clus_idx = 0; + long long target; + + switch (type) { + case CCDM_CLUS_0_CPUFREQ: + clus_idx = 0; + break; + case CCDM_CLUS_1_CPUFREQ: + clus_idx = 1; + break; + case CCDM_CLUS_2_CPUFREQ: + clus_idx = 2; + break; + default: + /* should not happen */ + return util; + } + + extra_util = (ginfo.c_fps_boost[clus_idx] * max_util / 10) * 4 / 5; + + /* read out in case changed */ + target = ginfo.c_max[clus_idx]; + + if (target == 0 || target == 2147483647 /* INT_MAX */) { + /* no cpufreq adjust, only take care of fps boost case */ + util += extra_util; + util = util > max_util ? max_util : util; + return util; + } else { + final_freq = target; + } + + if (!max_freq) + max_freq = 1; + + final_util = max_util * final_freq / max_freq; + w = ginfo.weight[clus_idx]; + t = ginfo.trust[clus_idx]; + + if (w) + final_util = + (util * (100 - w) / 100 + final_util * w / 100) * 4 / 5; + + /* pick lower one */ + final_util = final_util > util ? util : final_util; + + /* add extra boost */ + final_util += extra_util; + + /* cap with ceil */ + final_util = final_util > max_util ? max_util : final_util; + + return final_util; +} + +static long long ddrfreq_voting_decision(int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ + /* TODO add mapping table */ + return ginfo.ddrfreq; +} + +static inline long long decision(int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ + long long ret = 0; + + switch (type) { + case CCDM_CLUS_0_CPUFREQ: + case CCDM_CLUS_1_CPUFREQ: + case CCDM_CLUS_2_CPUFREQ: + ret = cpufreq_decision(type, arg1, arg2, arg3, arg4); + break; + case CCDM_VOTING_DDRFREQ: + ret = ddrfreq_voting_decision(type, arg1, arg2, arg3, arg4); + break; + } + return ret; +} + +/* decision part */ +long long ccdm_decision_1(int type, long long arg1) +{ + return decision(type, arg1, 0, 0, 0); +} + +long long ccdm_decision_2(int type, long long arg1, long long arg2) +{ + return decision(type, arg1, arg2, 0, 0); +} + +long long ccdm_decision_3( + int type, + long long arg1, + long long arg2, + long long arg3) +{ + return decision(type, arg1, arg2, arg3, 0); +} + +long long ccdm_decision_4( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ + return decision(type, arg1, arg2, arg3, arg4); +} + +long long ccdm_decision( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ + return decision(type, arg1, arg2, arg3, arg4); +} + +/* debug */ +void ccdm_get_status(void *ptr) +{ + struct ccdm_info *ccdm = (struct ccdm_info *) ptr; + int i; + + if (!ccdm) + return; + + for (i = 0; i < CCDM_CLUS_SIZE; ++i) { + ccdm->c_min[i] = ginfo.c_min[i]; + ccdm->c_max[i] = ginfo.c_max[i]; + ccdm->c_fps_boost[i] = ginfo.c_fps_boost[i]; + ccdm->trust[i] = ginfo.trust[i]; + ccdm->weight[i] = ginfo.weight[i]; + ccdm->tb_freq_boost[i] = ginfo.tb_freq_boost[i]; + } + ccdm->fps_boost_hint = ginfo.fps_boost_hint; + ccdm->ddrfreq = ginfo.ddrfreq; + ccdm->c_fps_boost_ddrfreq = ginfo.c_fps_boost_ddrfreq; + ccdm->tb_place_boost_hint = ginfo.tb_place_boost_hint; + ccdm->tb_cctl_boost_hint = ginfo.tb_cctl_boost_hint; + + for (i = 0; i < CCDM_CPU_SIZE; ++i) + ccdm->tb_idle_block_hint[i] = ginfo.tb_idle_block_hint[i]; +}; + +void ccdm_reset(void) +{ + int i = 0; + + for (i = 0; i < CCDM_CLUS_SIZE; ++i) { + ginfo.c_min[i] = 0; + ginfo.c_max[i] = 0; + ginfo.c_fps_boost[i] = 0; + /* leave default config not change */ + //ginfo.trust[i] = 100; + //ginfo.weight[i] = 100; + ginfo.tb_freq_boost[i] = 0; + } + ginfo.fps_boost_hint = 0; + ginfo.ddrfreq = 0; + ginfo.c_fps_boost_ddrfreq = 0; + ginfo.tb_place_boost_hint = 0; + ginfo.tb_cctl_boost_hint = 0; + + for (i = 0; i < CCDM_CPU_SIZE; ++i) + ginfo.tb_idle_block_hint[i] = CCDM_ULLONG_MAX; +} diff --git a/drivers/oneplus/coretech/control_center/test/Android.mk b/drivers/oneplus/coretech/control_center/test/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..500f5fb9905e45085267a887f654b03315a48806 --- /dev/null +++ b/drivers/oneplus/coretech/control_center/test/Android.mk @@ -0,0 +1,33 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := cd-unit-tests +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Wall -Wextra -Werror +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := cc_test.cpp +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_MODULE := cd-test-2 +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Wall -Wextra -Werror +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := cc_test_2.cpp +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := cd-test-3 +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Wall -Wextra -Werror +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := cc_test_3.cpp +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := cc_stress +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS := -Wall -Wextra -Werror +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := cc_stress.cpp +include $(BUILD_EXECUTABLE) diff --git a/drivers/oneplus/coretech/control_center/test/cc_stress.cpp b/drivers/oneplus/coretech/control_center/test/cc_stress.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b39d0d10b420df8406f66cb1b172a16ce4b6b1bb --- /dev/null +++ b/drivers/oneplus/coretech/control_center/test/cc_stress.cpp @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +int debug = 0; + +static void *cc_func1(void *arg __unused) { + FILE *fp = fopen("/proc/self/tb_ctl", "wb"); + + if (debug) + printf (" pthread: pid %d ppid %d tid %d, func %s\n", getpid(), getppid(), gettid(), __func__); + + while (1) { + int tid = gettid(); + char buf[100] = {0}; + + snprintf(buf, 100, "4,0,%d,%d,0,0,%d,10\n", tid, tid, rand()%5 + 3); + + if (debug) + printf ("%s\n", buf); + + fwrite(buf, 1, strlen(buf), fp); + fseek(fp, 0, SEEK_SET); + usleep(rand() % 8000 + 2000); + } + fclose(fp); + return NULL; +} + +static void *cc_func2(void *arg __unused) { + FILE *fp = fopen("/sys/module/houston/parameters/tb_ctl", "wb"); + + if (debug) + printf (" pthread: pid %d ppid %d tid %d, func %s\n", getpid(), getppid(), gettid(), __func__); + + while (1) { + int tid = gettid(); + char buf[100] = {0}; + + snprintf(buf, 100, "0,0,%d,%d,%d,20\n", tid, tid, rand()%5 + 3); + + if (debug) + printf ("%s\n", buf); + + fwrite(buf, 1, strlen(buf), fp); + fseek(fp, 0, SEEK_SET); + usleep(rand() % 8000 + 2000); + } + fclose(fp); + return NULL; +} + +int main(int argc __unused, char *argv[]) { + int pid = 0; + int now = 0; + int count = 1000; + time_t start, end; + double diff; + + int c; + while ((c = getopt (argc, argv, "c:v")) != -1) { + switch (c) + { + case 'v': + debug = 1; + break; + case 'c': + count = atoi(optarg); + break; + default: + abort (); + } + } + + time (&start); + + srand(time(0)); + while (now != count) { + pid = fork(); + printf ("Test: %d / %d\n", ++now, count); + if (pid) { + if (debug) + printf ("parent: pid %d ppid %d tid %d, child: %d\n", getpid(), getppid(), gettid(), pid); + + usleep (rand() % 80000 + 100000); + + if (debug) + printf ("kill child %d\n", pid); + + kill (pid, SIGKILL); + } else { + #define PTHREAD_SIZE 8 + pthread_t child[PTHREAD_SIZE]; + + for (int i = 0; i < PTHREAD_SIZE; ++i) + pthread_create(&child[i], NULL, (i & 0x1) ? &cc_func1 : &cc_func2, NULL); + + if (debug) + printf ("child: pid %d ppid %d tid %d\n", getpid(), getppid(), gettid()); + + for (int i = 0; i < PTHREAD_SIZE; ++i) + pthread_join(child[i], NULL); + } + } + + time (&end); + + diff = difftime(end, start); + printf ("execution time = %f sec\n", diff); + return 0; +} diff --git a/drivers/oneplus/coretech/control_center/test/cc_test.cpp b/drivers/oneplus/coretech/control_center/test/cc_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46ffffbd0da1f489ed29f2e8f914456435439a52 --- /dev/null +++ b/drivers/oneplus/coretech/control_center/test/cc_test.cpp @@ -0,0 +1,505 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +typedef unsigned int u32; +typedef unsigned long long u64; + +#define CC_CTL_PARAM_SIZE 4 + +enum CC_CTL_GROUP { + CC_CTL_GROUP_DEFAULT, + CC_CTL_GROUP_AI, + CC_CTL_GROUP_GRAPHIC, + CC_CTL_GROUP_FRAMEWORK, + CC_CTL_GROUP_SYSTEM, + CC_CTL_GROUP_OTHERS, + + CC_CTL_GROUP_MAX +}; + +enum CC_CTL_CATEGORY { + CC_CTL_CATEGORY_CLUS_0_FREQ, + CC_CTL_CATEGORY_CLUS_1_FREQ, + CC_CTL_CATEGORY_CLUS_2_FREQ, + CC_CTL_CATEGORY_CPU_FREQ_BOOST, + CC_CTL_CATEGORY_DDR_FREQ, + CC_CTL_CATEGORY_SCHED_PRIME_BOOST, + + CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY, + CC_CTL_CATEGORY_DDR_FREQ_QUERY, + + CC_CTL_CATEGORY_MAX +}; + +enum CC_CTL_TYPE { + CC_CTL_TYPE_ONESHOT, + CC_CTL_TYPE_PERIOD, + CC_CTL_TYPE_RESET, + + /* NONBLOCK region, the order is matter!! */ + CC_CTL_TYPE_ONESHOT_NONBLOCK, + CC_CTL_TYPE_PERIOD_NONBLOCK, + CC_CTL_TYPE_RESET_NONBLOCK, + + CC_CTL_TYPE_MAX +}; + +struct cc_command { + pid_t pid; + int period_us; + int prio; + int group; + int category; + int type; + u64 params[CC_CTL_PARAM_SIZE]; + u64 response; + int status; +}; + +#define CC_CTL "/dev/cc_ctl" +#define CC_IOC_MAGIC 'c' +#define CC_IOC_COMMAND _IOWR(CC_IOC_MAGIC, 0, struct cc_command) +#define CC_IOC_MAX 1 + +int& cd_get_group() +{ + static int group = -1; + return group; +} + +void cd_set_group(enum CC_CTL_GROUP ccg) +{ + int &group = cd_get_group(); + group = ccg; +} + +int cd_get_pid() +{ + static pid_t pid = 0; + if (pid == 0) + pid = getpid(); + return pid; +} + +/* return reference for update purpose */ +int& cd_get_fd() +{ + /* one time open, to avoid open too much times */ + static int cc_ctl_fd = 0; + if (cc_ctl_fd == 0) + cc_ctl_fd = open("/dev/cc_ctl", O_WRONLY); + return cc_ctl_fd; +} + +void cd_release() +{ + int& cc_ctl_fd = cd_get_fd(); + if (cc_ctl_fd > 0) + close(cc_ctl_fd); + cc_ctl_fd = 0; +} + +static inline void cd_cmd_setup(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + u64 param1, u64 param2, u64 param3, u64 param4, struct cc_command &cc) +{ + cc.group = cd_get_group(); + cc.category = ccc; + cc.type = cct; + cc.pid = cd_get_pid(); + cc.prio = 0; + cc.period_us = 5000000; + cc.params[0] = param1; /* optional */ + cc.params[1] = param2; /* optional */ + cc.params[2] = param3; /* optional */ + cc.params[3] = param4; /* optional */ + cc.response = 0; + cc.status = 0; +} + +static inline void cd_routine(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + u64 param1, u64 param2, u64 param3, u64 param4) +{ + struct cc_command cc; + int cc_ctl_fd = cd_get_fd(); + + if (cc_ctl_fd < 0) { + printf("control center not ready\n"); + return; + } + + cd_cmd_setup(ccc, cct, param1, param2, param3, param4, cc); + ioctl(cc_ctl_fd, CC_IOC_COMMAND, &cc); + + /* verify result */ + if (cc.status) + printf("%s failed\n", __func__); + else + printf("%s successful\n", __func__); +} + +void adjust(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + u64 param1 = 0, u64 param2 = 0, u64 param3 = 0, u64 param4 = 0) +{ + cd_routine(ccc, cct, param1, param2, param3, param4); +} + +void cd_init(enum CC_CTL_GROUP ccg) +{ + printf("control daemon init\n"); + cd_set_group(ccg); + if (cd_get_fd() < 0) + printf("open control center interface failed\n"); +} + +void cd_deinit() +{ + cd_release(); + printf("control daemon closed\n"); +} + +/* test part */ +bool valid_cpufreq(unsigned int target, int cluster) { + string paths[] = { + "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", + "/sys/devices/system/cpu/cpu4/cpufreq/scaling_cur_freq", + "/sys/devices/system/cpu/cpu7/cpufreq/scaling_cur_freq" + }; + ifstream ifs(paths[cluster].c_str()); + string result ((istreambuf_iterator(ifs)), istreambuf_iterator()); + cout << "Test cluster " << cluster << " set cpufreq to " << target << ", result " << stoi(result) << endl; + return stoi(result) == (int)target; +} + +bool valid_ddrfreq(long long target) { + string path("/sys/kernel/debug/clk/measure_only_mccc_clk/clk_measure"); + ifstream ifs(path.c_str()); + string result ((istreambuf_iterator(ifs)), istreambuf_iterator()); + cout << "Test set ddrfreq to " << target << ", " << stoll(result) << endl; + return stoll(result) == target; +} + +TEST(cpufreq_test, test0) { + int cluster_idx = 0; + unsigned int target[] = { + 576000, 672000, 768000, 844800, 940800, 1036800, 1113600, 1209600, 1305600, 1382400, 1478400, 1555200, 1632000, 1708800, 1785600 + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_RESET); + cd_deinit(); +} + +TEST(cpufreq_test, test1) { + int cluster_idx = 1; + unsigned int target[] = { + 710400, 825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200 + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_RESET); + cd_deinit(); +} + +TEST(cpufreq_test, test2) { + int cluster_idx = 2; + unsigned int target[] = { + 825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200, 2534400, 2649600, 2745600, 2841600 + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_ONESHOT, target[i], target[i]); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_RESET); + cd_deinit(); +} + +TEST(ddrfreq_test, test) { + unsigned int target[] = { + 200, 300, 451, 547, 681, 768, 1017, 1353, 1555, 1804, 2092 + }; + long long expected[] = { + 200000000LL, 300030003LL, 451263537LL, 547345374LL, 681663258LL, 768049155LL, 1018329938LL, 1355013550LL, 1555209953LL, 1805054151LL, 2096436058LL + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_ONESHOT, target[i]); + ASSERT_TRUE(valid_ddrfreq(expected[i])); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_ONESHOT, target[i]); + ASSERT_TRUE(valid_ddrfreq(expected[i])); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_ONESHOT, target[i]); + ASSERT_TRUE(valid_ddrfreq(expected[i])); + } + + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_RESET); + cd_deinit(); +} + +TEST(cpufreq_test_nb, test0) { + int cluster_idx = 0; + unsigned int target[] = { + 576000, 672000, 768000, 844800, 940800, 1036800, 1113600, 1209600, 1305600, 1382400, 1478400, 1555200, 1632000, 1708800, 1785600 + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ, CC_CTL_TYPE_RESET_NONBLOCK, cluster_idx); + sleep(1); + cd_deinit(); +} + +TEST(cpufreq_test_nb, test1) { + int cluster_idx = 1; + unsigned int target[] = { + 710400, 825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200 + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ, CC_CTL_TYPE_RESET_NONBLOCK, cluster_idx); + sleep(1); + cd_deinit(); +} + +TEST(cpufreq_test_nb, test2) { + int cluster_idx = 2; + unsigned int target[] = { + 825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200, 2534400, 2649600, 2745600, 2841600 + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i], target[i]); + sleep(1); + ASSERT_TRUE(valid_cpufreq(target[i], cluster_idx)); + } + + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ, CC_CTL_TYPE_RESET_NONBLOCK, cluster_idx); + sleep(1); + cd_deinit(); +} + +TEST(ddrfreq_test_nb, test) { + unsigned int target[] = { + 200, 300, 451, 547, 681, 768, 1017, 1353, 1555, 1804, 2092 + }; + long long expected[] = { + 200000000LL, 300030003LL, 451263537LL, 547345374LL, 681663258LL, 768049155LL, 1018329938LL, 1355013550LL, 1555209953LL, 1805054151LL, 2096436058LL + }; + cd_init(CC_CTL_GROUP_AI); + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i]); + sleep(1); + ASSERT_TRUE(valid_ddrfreq(expected[i])); + } + + for (int i = (int) sizeof(target)/sizeof(unsigned int) - 1; i >= 0; --i) { + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i]); + sleep(1); + ASSERT_TRUE(valid_ddrfreq(expected[i])); + } + + for (unsigned int i = 0; i < sizeof(target)/sizeof(unsigned int); ++i) { + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_ONESHOT_NONBLOCK, target[i]); + sleep(1); + ASSERT_TRUE(valid_ddrfreq(expected[i])); + } + + adjust(CC_CTL_CATEGORY_DDR_FREQ, CC_CTL_TYPE_RESET_NONBLOCK); + sleep(1); + cd_deinit(); +} + +TEST(sched_prime_boost_test, test) { + cd_init(CC_CTL_GROUP_AI); + adjust(CC_CTL_CATEGORY_SCHED_PRIME_BOOST, CC_CTL_TYPE_ONESHOT, getpid()); + adjust(CC_CTL_CATEGORY_SCHED_PRIME_BOOST, CC_CTL_TYPE_RESET); + cd_deinit(); +} + +TEST(sched_prime_boost_test_nb, test) { + cd_init(CC_CTL_GROUP_AI); + adjust(CC_CTL_CATEGORY_SCHED_PRIME_BOOST, CC_CTL_TYPE_ONESHOT_NONBLOCK, getpid()); + adjust(CC_CTL_CATEGORY_SCHED_PRIME_BOOST, CC_CTL_TYPE_RESET_NONBLOCK); + cd_deinit(); +} + +TEST(cpufreq_boost_boost_test, test) { + cd_init(CC_CTL_GROUP_AI); + adjust(CC_CTL_CATEGORY_CPU_FREQ_BOOST, CC_CTL_TYPE_ONESHOT, 1, 1); + adjust(CC_CTL_CATEGORY_CPU_FREQ_BOOST, CC_CTL_TYPE_RESET); + cd_deinit(); +} + +TEST(cpufreq_boost_boost_test_nb, test) { + cd_init(CC_CTL_GROUP_AI); + adjust(CC_CTL_CATEGORY_CPU_FREQ_BOOST, CC_CTL_TYPE_ONESHOT_NONBLOCK, 1, 1); + adjust(CC_CTL_CATEGORY_CPU_FREQ_BOOST, CC_CTL_TYPE_RESET_NONBLOCK); + cd_deinit(); +} + +TEST(query, test) { + cd_init(CC_CTL_GROUP_AI); + adjust(CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY, CC_CTL_TYPE_ONESHOT); + adjust(CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY, CC_CTL_TYPE_ONESHOT); + adjust(CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY, CC_CTL_TYPE_ONESHOT); + adjust(CC_CTL_CATEGORY_DDR_FREQ_QUERY, CC_CTL_TYPE_ONESHOT); + cd_deinit(); +} + +TEST(cpufreq_boundry_test, test_boundry_0) { + int cluster_idx = 0; + unsigned int target_max = UINT_MAX; + unsigned int target_min = 0; + unsigned int expected_max[3] = { 1785600, 2419200, 2841600 }; + unsigned int expected_min[3] = { 576000, 710400, 825600 }; + + cd_init(CC_CTL_GROUP_AI); + + for (cluster_idx = 0; cluster_idx < 3; ++cluster_idx) { + enum CC_CTL_CATEGORY ccc = CC_CTL_CATEGORY_CLUS_0_FREQ; + if (cluster_idx == 1) + ccc = CC_CTL_CATEGORY_CLUS_1_FREQ; + else if (cluster_idx == 2) + ccc = CC_CTL_CATEGORY_CLUS_2_FREQ; + + adjust(ccc, CC_CTL_TYPE_ONESHOT_NONBLOCK, target_max, target_max); + sleep(1); + ASSERT_TRUE(valid_cpufreq(expected_max[cluster_idx], cluster_idx)); + adjust(ccc, CC_CTL_TYPE_RESET_NONBLOCK, cluster_idx); + } + + for (cluster_idx = 0; cluster_idx < 3; ++cluster_idx) { + enum CC_CTL_CATEGORY ccc = CC_CTL_CATEGORY_CLUS_0_FREQ; + if (cluster_idx == 1) + ccc = CC_CTL_CATEGORY_CLUS_1_FREQ; + else if (cluster_idx == 2) + ccc = CC_CTL_CATEGORY_CLUS_2_FREQ; + + adjust(ccc, CC_CTL_TYPE_ONESHOT_NONBLOCK, target_min, target_min); + sleep(1); + ASSERT_TRUE(valid_cpufreq(expected_min[cluster_idx], cluster_idx)); + adjust(ccc, CC_CTL_TYPE_RESET_NONBLOCK, cluster_idx); + } + + cd_deinit(); +} diff --git a/drivers/oneplus/coretech/control_center/test/cc_test_2.cpp b/drivers/oneplus/coretech/control_center/test/cc_test_2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95cf3058089afe8f8716e3944a79618534d4c889 --- /dev/null +++ b/drivers/oneplus/coretech/control_center/test/cc_test_2.cpp @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +typedef unsigned int u32; +typedef unsigned long long u64; + +#define CC_CTL_PARAM_SIZE 4 + +enum CC_CTL_GROUP { + CC_CTL_GROUP_DEFAULT, + CC_CTL_GROUP_AI, + CC_CTL_GROUP_GRAPHIC, + CC_CTL_GROUP_FRAMEWORK, + CC_CTL_GROUP_SYSTEM, + CC_CTL_GROUP_OTHERS, + + CC_CTL_GROUP_MAX +}; + +enum CC_CTL_CATEGORY { + CC_CTL_CATEGORY_CLUS_0_FREQ, + CC_CTL_CATEGORY_CLUS_1_FREQ, + CC_CTL_CATEGORY_CLUS_2_FREQ, + CC_CTL_CATEGORY_CPU_FREQ_BOOST, + CC_CTL_CATEGORY_DDR_FREQ, + CC_CTL_CATEGORY_SCHED_PRIME_BOOST, + + CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY, + CC_CTL_CATEGORY_DDR_FREQ_QUERY, + + CC_CTL_CATEGORY_MAX +}; + +enum CC_CTL_TYPE { + CC_CTL_TYPE_ONESHOT, + CC_CTL_TYPE_PERIOD, + CC_CTL_TYPE_RESET, + + /* NONBLOCK region, the order is matter!! */ + CC_CTL_TYPE_ONESHOT_NONBLOCK, + CC_CTL_TYPE_PERIOD_NONBLOCK, + CC_CTL_TYPE_RESET_NONBLOCK, + + CC_CTL_TYPE_MAX +}; + +struct cc_command { + pid_t pid; + pid_t leader; + int period_us; + int prio; + int group; + int category; + int type; + u64 params[CC_CTL_PARAM_SIZE]; + u64 response; + bool bind_leader; + int status; +}; + +#define CC_CTL "/dev/cc_ctl" +#define CC_IOC_MAGIC 'c' +#define CC_IOC_COMMAND _IOWR(CC_IOC_MAGIC, 0, struct cc_command) +#define CC_IOC_MAX 1 + +int& cd_get_group() +{ + static int group = -1; + return group; +} + +void cd_set_group(enum CC_CTL_GROUP ccg) +{ + int &group = cd_get_group(); + group = ccg; +} + +int cd_get_pid() +{ + static pid_t pid = 0; + if (pid == 0) + pid = getpid(); + return pid; +} + +/* return reference for update purpose */ +int& cd_get_fd() +{ + /* one time open, to avoid open too much times */ + static int cc_ctl_fd = 0; + if (cc_ctl_fd == 0) + cc_ctl_fd = open("/dev/cc_ctl", O_WRONLY); + return cc_ctl_fd; +} + +void cd_release() +{ + int& cc_ctl_fd = cd_get_fd(); + if (cc_ctl_fd > 0) + close(cc_ctl_fd); + cc_ctl_fd = 0; +} + +static inline void cd_cmd_setup(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + int delay_us, u64 param1, u64 param2, u64 param3, u64 param4, struct cc_command &cc) +{ + cc.group = cd_get_group(); + cc.category = ccc; + cc.type = cct; + cc.pid = cd_get_pid(); + cc.period_us = delay_us; + cc.prio = rand() % 3; // 0 ~ 2 + cc.params[0] = param1; /* optional */ + cc.params[1] = param2; /* optional */ + cc.params[2] = param3; /* optional */ + cc.params[3] = param4; /* optional */ + cc.response = 0; + cc.status = 0; +} + +static inline void cd_routine(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + int delay_us, u64 param1, u64 param2, u64 param3, u64 param4) +{ + struct cc_command cc; + int cc_ctl_fd = cd_get_fd(); + + if (cc_ctl_fd < 0) { + printf("control center not ready\n"); + return; + } + + cd_cmd_setup(ccc, cct, delay_us, param1, param2, param3, param4, cc); + ioctl(cc_ctl_fd, CC_IOC_COMMAND, &cc); + + /* verify result */ + if (cc.status) + printf("%s failed\n", __func__); + else + printf("%s successful\n", __func__); +} + +void adjust(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + int delay_us, u64 param1 = 0, u64 param2 = 0, u64 param3 = 0, u64 param4 = 0) +{ + cd_routine(ccc, cct, delay_us, param1, param2, param3, param4); +} + +void cd_init(enum CC_CTL_GROUP ccg) +{ + printf("control daemon init\n"); + cd_set_group(ccg); + if (cd_get_fd() < 0) + printf("open control center interface failed\n"); +} + +void cd_deinit() +{ + cd_release(); + printf("control daemon closed\n"); +} + +int main(int, char**) { + enum CC_CTL_CATEGORY c = CC_CTL_CATEGORY_DDR_FREQ; + int s, p, t; + int target0[] = {576000, 672000, 768000, 844800, 940800, 1036800, 1113600, 1209600, 1305600, 1382400, 1478400, 1555200, 1632000, 1708800, 1785600}; + int target1[] = {710400, 825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200}; + int target2[] = {825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200, 2534400, 2649600, 2745600, 2841600}; + int target3[] = { + 200, 300, 451, 547, 681, 768, 1017, 1353, 1555, 1804, 2092 + }; + int* target = target3; + bool b; + + srand(time(NULL)); + + /* init */ + cd_init(CC_CTL_GROUP_AI); + while (1) { + int cc = rand() % 4; + switch (cc) { + case 0: c = CC_CTL_CATEGORY_CLUS_0_FREQ; target = target0; break; + case 1: c = CC_CTL_CATEGORY_CLUS_1_FREQ; target = target1; break; + case 2: c = CC_CTL_CATEGORY_CLUS_2_FREQ; target = target2; break; + case 3: c = CC_CTL_CATEGORY_DDR_FREQ; target = target3; break; + } + s = rand() % 15000 + 5000; // 5000 ~ 19999 us + p = rand() % 15000 + 5000; // 5000 ~ 19999 us + t = rand() % 11; + b = rand() % 2; // 0 ~ 1 + + cout << "s: " << s << ", p: " << p << ", target: " << target[t] << ", block: " << b << endl; + + /* adjust */ + adjust(c, (b? CC_CTL_TYPE_ONESHOT: CC_CTL_TYPE_ONESHOT_NONBLOCK), p /* delay us */, target[t] /* min freq */, target[t] /* max freq */); + + usleep (s); + + /* reset */ + adjust(c, (b? CC_CTL_TYPE_RESET: CC_CTL_TYPE_RESET_NONBLOCK), 0 /* delay us */); + } + /* deinit */ + cd_deinit(); + return 0; +} diff --git a/drivers/oneplus/coretech/control_center/test/cc_test_3.cpp b/drivers/oneplus/coretech/control_center/test/cc_test_3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85e3a086544b66711b1eddcd337bc9be9f04186b --- /dev/null +++ b/drivers/oneplus/coretech/control_center/test/cc_test_3.cpp @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +typedef unsigned int u32; +typedef unsigned long long u64; + +#define CC_CTL_PARAM_SIZE 4 + +enum CC_CTL_GROUP { + CC_CTL_GROUP_DEFAULT, + CC_CTL_GROUP_AI, + CC_CTL_GROUP_GRAPHIC, + CC_CTL_GROUP_FRAMEWORK, + CC_CTL_GROUP_SYSTEM, + CC_CTL_GROUP_OTHERS, + + CC_CTL_GROUP_MAX +}; + +enum CC_CTL_CATEGORY { + CC_CTL_CATEGORY_CLUS_0_FREQ, + CC_CTL_CATEGORY_CLUS_1_FREQ, + CC_CTL_CATEGORY_CLUS_2_FREQ, + CC_CTL_CATEGORY_CPU_FREQ_BOOST, + CC_CTL_CATEGORY_DDR_FREQ, + CC_CTL_CATEGORY_SCHED_PRIME_BOOST, + + CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY, + CC_CTL_CATEGORY_DDR_FREQ_QUERY, + + CC_CTL_CATEGORY_MAX +}; + +enum CC_CTL_TYPE { + CC_CTL_TYPE_ONESHOT, + CC_CTL_TYPE_PERIOD, + CC_CTL_TYPE_RESET, + + /* NONBLOCK region, the order is matter!! */ + CC_CTL_TYPE_ONESHOT_NONBLOCK, + CC_CTL_TYPE_PERIOD_NONBLOCK, + CC_CTL_TYPE_RESET_NONBLOCK, + + CC_CTL_TYPE_MAX +}; + +struct cc_command { + pid_t pid; + pid_t leader; + int period_us; + int prio; + int group; + int category; + int type; + u64 params[CC_CTL_PARAM_SIZE]; + u64 response; + bool bind_leader; + int status; +}; + +#define CC_CTL "/dev/cc_ctl" +#define CC_IOC_MAGIC 'c' +#define CC_IOC_COMMAND _IOWR(CC_IOC_MAGIC, 0, struct cc_command) +#define CC_IOC_MAX 1 + +int& cd_get_group() +{ + static int group = -1; + return group; +} + +void cd_set_group(enum CC_CTL_GROUP ccg) +{ + int &group = cd_get_group(); + group = ccg; +} + +int cd_get_pid() +{ + static pid_t pid = 0; + if (pid == 0) + pid = getpid(); + return pid; +} + +/* return reference for update purpose */ +int& cd_get_fd() +{ + /* one time open, to avoid open too much times */ + static int cc_ctl_fd = 0; + if (cc_ctl_fd == 0) + cc_ctl_fd = open("/dev/cc_ctl", O_WRONLY); + return cc_ctl_fd; +} + +void cd_release() +{ + int& cc_ctl_fd = cd_get_fd(); + if (cc_ctl_fd > 0) + close(cc_ctl_fd); + cc_ctl_fd = 0; +} + +static inline void cd_cmd_setup(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + int delay_us, u64 param1, u64 param2, u64 param3, u64 param4, struct cc_command &cc) +{ + cc.group = cd_get_group(); + cc.category = ccc; + cc.type = cct; + cc.pid = cd_get_pid(); + cc.period_us = delay_us; + cc.prio = rand() % 3; // 0 ~ 2 + cc.params[0] = param1; /* optional */ + cc.params[1] = param2; /* optional */ + cc.params[2] = param3; /* optional */ + cc.params[3] = param4; /* optional */ + cc.response = 0; + cc.status = 0; +} + +static inline void cd_routine(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + int delay_us, u64 param1, u64 param2, u64 param3, u64 param4) +{ + struct cc_command cc; + int cc_ctl_fd = cd_get_fd(); + + if (cc_ctl_fd < 0) { + printf("control center not ready\n"); + return; + } + + cd_cmd_setup(ccc, cct, delay_us, param1, param2, param3, param4, cc); + ioctl(cc_ctl_fd, CC_IOC_COMMAND, &cc); + + /* verify result */ + if (cc.status) + printf("%s failed\n", __func__); + else + printf("%s successful\n", __func__); +} + +void adjust(enum CC_CTL_CATEGORY ccc, enum CC_CTL_TYPE cct, + int delay_us, u64 param1 = 0, u64 param2 = 0, u64 param3 = 0, u64 param4 = 0) +{ + cd_routine(ccc, cct, delay_us, param1, param2, param3, param4); +} + +void cd_init(enum CC_CTL_GROUP ccg) +{ + printf("control daemon init\n"); + cd_set_group(ccg); + if (cd_get_fd() < 0) + printf("open control center interface failed\n"); +} + +void cd_deinit() +{ + cd_release(); + printf("control daemon closed\n"); +} + +int main(int, char**) { + enum CC_CTL_CATEGORY c = CC_CTL_CATEGORY_DDR_FREQ; + int s, p, t; + int target0[] = {576000, 672000, 768000, 844800, 940800, 1036800, 1113600, 1209600, 1305600, 1382400, 1478400, 1555200, 1632000, 1708800, 1785600}; + int target1[] = {710400, 825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200}; + int target2[] = {825600, 940800, 1056000, 1171200, 1286400, 1401600, 1497600, 1612800, 1708800, 1804800, 1920000, 2016000, 2131200, 2227200, 2323200, 2419200, 2534400, 2649600, 2745600, 2841600}; + int target3[] = { + 200, 300, 451, 547, 681, 768, 1017, 1353, 1555, 1804, 2092 + }; + int* target = target3; + bool b; + + srand(time(NULL)); + + /* init */ + cd_init(CC_CTL_GROUP_AI); + + int cc = rand() % 4; + switch (cc) { + case 0: c = CC_CTL_CATEGORY_CLUS_0_FREQ; target = target0; break; + case 1: c = CC_CTL_CATEGORY_CLUS_1_FREQ; target = target1; break; + case 2: c = CC_CTL_CATEGORY_CLUS_2_FREQ; target = target2; break; + case 3: c = CC_CTL_CATEGORY_DDR_FREQ; target = target3; break; + } + s = rand() % 15000 + 5000; // 5000 ~ 19999 us + p = rand() % 15000 + 5000; // 5000 ~ 19999 us + t = rand() % 11; + b = rand() % 2; // 0 ~ 1 + + cout << "s: " << s << ", p: " << p << ", target: " << target[t] << ", block: " << b << endl; + + /* adjust */ + adjust(c, (b? CC_CTL_TYPE_ONESHOT: CC_CTL_TYPE_ONESHOT_NONBLOCK), p /* delay us */, target[t] /* min freq */, target[t] /* max freq */); + + usleep (s); + + /* reset */ + adjust(c, (b? CC_CTL_TYPE_RESET: CC_CTL_TYPE_RESET_NONBLOCK), 0 /* delay us */); + + /* deinit */ + cd_deinit(); + return 0; +} diff --git a/drivers/oneplus/coretech/coretech_helper.c b/drivers/oneplus/coretech/coretech_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..7c78c2251d68d49f8aedf35ba73c4f1e0e7874d0 --- /dev/null +++ b/drivers/oneplus/coretech/coretech_helper.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011-2013,2015 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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 + +s64 ctech_get_time(void) +{ + return ktime_to_ms(ktime_get()); +} +EXPORT_SYMBOL(ctech_get_time); diff --git a/drivers/oneplus/coretech/coretech_helper.h b/drivers/oneplus/coretech/coretech_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..3bbeb78aed50912fe12a06b2b4a699f8237604fd --- /dev/null +++ b/drivers/oneplus/coretech/coretech_helper.h @@ -0,0 +1,6 @@ +#ifndef _LINUX_CORETECH_HELPER_H +#define _LINUX_CORETECH_HELPER_H + +extern s64 ctech_get_time(void); + +#endif diff --git a/drivers/oneplus/coretech/defrag/Makefile b/drivers/oneplus/coretech/defrag/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a1e70c67e401e009f65cbd09a408f9c0800d5737 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DEFRAG) += defrag_helper.o diff --git a/drivers/oneplus/coretech/defrag/core/Makefile b/drivers/oneplus/coretech/defrag/core/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3cef022e6559f657efb70b704ed3309066250097 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/core/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_DEFRAG) += defrag.o +defrag-objs := defrag_core.o defrag_proxy.o diff --git a/drivers/oneplus/coretech/defrag/core/defrag.h b/drivers/oneplus/coretech/defrag/core/defrag.h new file mode 100644 index 0000000000000000000000000000000000000000..05b13b91adeca3b63d57a0bb2968192ed486d16f --- /dev/null +++ b/drivers/oneplus/coretech/defrag/core/defrag.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * 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. + */ + +#ifndef _LINUX_MODULE_DEFRAG_H +#define _LINUX_MODULE_DEFRAG_H + +#include +#include +#include +#include +#include +#include "op_struct_offset_helper.h" + +void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long); +bool check_alloc_type(int migratetype, int order); +bool check_alloc_flag(int alloc_flag, int order); +int request_reserved_block(void); + +#endif /* _LINUX_MODULE_DEFRAG_H */ diff --git a/drivers/oneplus/coretech/defrag/core/defrag_core.c b/drivers/oneplus/coretech/defrag/core/defrag_core.c new file mode 100644 index 0000000000000000000000000000000000000000..622fcb9d191c1a6a14a615a0551ae6491ad753a0 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/core/defrag_core.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * 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 "defrag.h" +#define ALLOC_UNMOVE 0x800 +#define NR_RESERVED_BLOCKS 120 /* 60*4MB = 240MB for each zone */ + +bool check_alloc_flag(int alloc_flag, int order) +{ + if (likely(order < 2) || !(alloc_flag & ALLOC_UNMOVE)) + return true; + else + return false; +} +bool check_alloc_type(int migratetype, int order) +{ + if ((order >= 2) && migratetype == MIGRATE_UNMOVABLE) + return true; + else + return false; +} + +/* now we reserve 60 pageblocks (240MB) per zone, 480 MB total */ +int request_reserved_block(void) +{ + return NR_RESERVED_BLOCKS; +} diff --git a/drivers/oneplus/coretech/defrag/core/defrag_proxy.c b/drivers/oneplus/coretech/defrag/core/defrag_proxy.c new file mode 100644 index 0000000000000000000000000000000000000000..86c8f1b1699e1b562e7f01223a472157c5be0ee7 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/core/defrag_proxy.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * 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 "defrag.h" + + +static struct zone *ctech_first_zone(void) +{ + return NODE_DATA(first_online_node)->node_zones; +} + +static struct zone *ctech_next_zone(struct zone *zone) +{ + return next_zone(zone); +} + +static unsigned long ctech_zone_end_pfn(const struct zone *zone) +{ + return zone_end_pfn(zone); +} + +static int ctech_pfn_valid(unsigned long pfn) +{ + return pfn_valid(pfn); +} + +static struct page *ctech_pfn_to_page(unsigned long pfn) +{ + return pfn_to_page(pfn); +} + +static bool ctech_defrag_check_alloc_flag(unsigned int alloc_flag, int order) +{ + return !check_alloc_flag(alloc_flag, order); +} + +static struct page *ctech_defrag_pool_alloc(struct zone *zone, unsigned long flags, + int migratetype, int order) +{ + struct page *page = NULL; + + if (check_alloc_type(migratetype, order)) { + spin_lock_irqsave(&zone->lock, flags); + page = defrag___rmqueue(zone, order, + MIGRATE_UNMOVABLE_DEFRAG_POOL); + + if (page) { + spin_unlock(&zone->lock); + __mod_zone_page_state(zone, NR_FREE_PAGES, + -(1 << order)); + __mod_zone_page_state(zone, NR_FREE_DEFRAG_POOL, + -(1 << order)); + local_irq_restore(flags); + } else + spin_unlock_irqrestore(&zone->lock, flags); + } + + return page; +} + +/* return pool size, if this allocation cannot use our pool */ +static long ctech_calculate_reserved_pool(struct zone *z, int order, int alloc_flag) +{ + if (check_alloc_flag(alloc_flag, order)) + return zone_page_state(z, NR_FREE_DEFRAG_POOL); + else + return 0; +} + +static void release_unused_area(int request) +{ + struct zone *zone; + unsigned long start_pfn, pfn, end_pfn; + unsigned long block_mt; + unsigned long flags; + struct page *page; + int counter, pages_moved; + + if (request) + request = request_reserved_block(); + + /* for_each_zone(zone) { */ + for (zone = ctech_first_zone(); zone; zone = ctech_next_zone(zone)) { + if (strstr(zone->name, "Movable") != NULL) + continue; + spin_lock_irqsave(&zone->lock, flags); + start_pfn = zone->zone_start_pfn; + end_pfn = ctech_zone_end_pfn(zone); + start_pfn = roundup(start_pfn, pageblock_nr_pages); + counter = 0; + + for (pfn = start_pfn; pfn < end_pfn; + pfn += pageblock_nr_pages) { + if (!ctech_pfn_valid(pfn)) + continue; + page = ctech_pfn_to_page(pfn); + block_mt = get_pageblock_migratetype(page); + if (block_mt == MIGRATE_UNMOVABLE_DEFRAG_POOL) { + if (++counter <= request) + continue; + else { + set_pageblock_migratetype(page, + MIGRATE_MOVABLE); + pages_moved = move_freepages_block(zone, + page, MIGRATE_MOVABLE, NULL); + __mod_zone_page_state(zone, + NR_FREE_DEFRAG_POOL, + -pages_moved); + } + } + } + spin_unlock_irqrestore(&zone->lock, flags); + } +} + +static int __init defrag_pool_setup(void) +{ + struct zone *zone; + unsigned long start_pfn, pfn, end_pfn; + unsigned long block_mt; + unsigned long flags; + struct page *page; + int pages_moved; + int nr_pgblock = 0; + int nr_movebcak = 0; + + /* for_each_zone(zone) { */ + for (zone = ctech_first_zone(); zone; zone = ctech_next_zone(zone)) { + nr_pgblock = 0; + if (strstr(zone->name, "Movable") != NULL) + continue; + spin_lock_irqsave(&zone->lock, flags); + start_pfn = zone->zone_start_pfn; + end_pfn = ctech_zone_end_pfn(zone); + start_pfn = roundup(start_pfn, pageblock_nr_pages); + + for (pfn = start_pfn; pfn < end_pfn; + pfn += pageblock_nr_pages) { + if (!ctech_pfn_valid(pfn)) + continue; + page = ctech_pfn_to_page(pfn); + block_mt = get_pageblock_migratetype(page); + if (block_mt == MIGRATE_MOVABLE) { + pages_moved = move_freepages_block(zone, + page, MIGRATE_UNMOVABLE_DEFRAG_POOL, NULL); + + if (pages_moved == pageblock_nr_pages) { + nr_pgblock++; + set_pageblock_migratetype(page, MIGRATE_UNMOVABLE_DEFRAG_POOL); + __mod_zone_page_state(zone, NR_FREE_DEFRAG_POOL, pages_moved); + } else { + move_freepages_block(zone, page, block_mt, NULL); + nr_movebcak++; + } + if (nr_pgblock >= request_reserved_block()) + break; + } + } + spin_unlock_irqrestore(&zone->lock, flags); + printk("anti-defragment: zone(%s) setup page blocks(%d), moveback blcoks(%d)\n", zone->name, nr_pgblock, nr_movebcak); + } + return 0; +} + +static void release_migratetype(void) +{ + struct zone *zone; + unsigned long start_pfn, pfn, end_pfn; + unsigned long block_migratetype; + unsigned long flags; + struct page *page; + int counter, pages_moved; + + for_each_zone(zone) { + spin_lock_irqsave(&zone->lock, flags); + start_pfn = zone->zone_start_pfn; + end_pfn = zone_end_pfn(zone); + start_pfn = roundup(start_pfn, pageblock_nr_pages); + counter = 0; + + for (pfn = start_pfn; pfn < end_pfn; + pfn += pageblock_nr_pages) { + if (!pfn_valid(pfn)) + continue; + page = pfn_to_page(pfn); + block_migratetype = get_pageblock_migratetype(page); + if (block_migratetype == + MIGRATE_UNMOVABLE_DEFRAG_POOL) { + set_pageblock_migratetype(page, + MIGRATE_MOVABLE); + pages_moved = move_freepages_block(zone, page, + MIGRATE_MOVABLE, NULL); + __mod_zone_page_state(zone, + NR_FREE_DEFRAG_POOL, -pages_moved); + } + } + spin_unlock_irqrestore(&zone->lock, flags); + } +} + +unsigned int __read_mostly disable; + +static int disable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u", disable); +} + +static int disable_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + if (!strncmp(buf, "1", 1)) { + disable = val; + release_migratetype(); + defrag_unregister_cb_set(); + } + return 0; +} + +static const struct kernel_param_ops param_ops_disable = { + .get = disable_show, + .set = disable_store, +}; +module_param_cb(disable, ¶m_ops_disable, NULL, 0644); + +static inline int print_fp_statistics(char *buf) +{ + int order; + int size = 0; + + size += sprintf(buf + size, "fp_usage\t\t"); + for (order = 0; order < MAX_ORDER; ++order) + size += sprintf(buf + size, "%6lu ", atomic64_read(&fp_order_usage[order])); + size += sprintf(buf + size, "\n"); + size += sprintf(buf + size, "fp_fail \t\t"); + for (order = 0; order < MAX_ORDER; ++order) + size += sprintf(buf + size, "%6lu ", atomic64_read(&fp_order_fail[order])); + size += sprintf(buf + size, "\n"); + + return size; +} + +static int fp_fail_show(char *buf, const struct kernel_param *kp) +{ + int size = 0; + size = print_fp_statistics(buf); + return size; +} + +static const struct kernel_param_ops param_ops_fp_fail = { + .get = fp_fail_show, +}; +module_param_cb(fp_fail, ¶m_ops_fp_fail, NULL, 0444); + +static int __init defrag_pool_init(void) +{ + struct defrag_cb_set set; + set.defrag_alloc_cb = ctech_defrag_pool_alloc; + set.defrag_calc_cb = ctech_calculate_reserved_pool; + set.defrag_check_alloc_flag_cb = ctech_defrag_check_alloc_flag; + defrag_register_cb_set(&set); + + return 0; +} + +static void __exit defrag_pool_exit(void) +{ + defrag_unregister_cb_set(); + release_unused_area(0); +} +early_initcall(defrag_pool_setup) + +module_init(defrag_pool_init); +module_exit(defrag_pool_exit); + +MODULE_DESCRIPTION("OnePlus Defragger"); +MODULE_LICENSE("GPL"); diff --git a/drivers/oneplus/coretech/defrag/core/op_struct_offset_helper.c b/drivers/oneplus/coretech/defrag/core/op_struct_offset_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..e857d402bb82f75a76100e41c67d3be6ab225204 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/core/op_struct_offset_helper.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "op_struct_offset_helper.h" + +/* struct zone */ +unsigned int _zone_offset[__ZONE_OFFSET_MAX] = { + [ZONE_OFFSET_LOCK] = offsetof(struct zone, lock), + [ZONE_OFFSET_ZSP] = offsetof(struct zone, zone_start_pfn) +}; +gen_type_offset_impl(zone); + +/* struct pglist_data */ +unsigned int _pglist_data_offset[__PGLIST_DATA_OFFSET_MAX] = { + [PGLIST_DATA_OFFSET_NODE_ZONES] = offsetof(struct pglist_data, + node_zones) +}; +gen_type_offset_impl(pglist_data); diff --git a/drivers/oneplus/coretech/defrag/core/op_struct_offset_helper.h b/drivers/oneplus/coretech/defrag/core/op_struct_offset_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..9680b5ce93d68639371661c25807c882df9c9a28 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/core/op_struct_offset_helper.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#ifndef _OP_STRUCT_OFFSET_HELPER_INC_ +#define _OP_STRUCT_OFFSET_HELPER_INC_ + +/* define macro to extern function declaration */ +#define gen_type_offset(type) \ + extern unsigned int get_##type##_offset(int m) + +/* define macro to create offset impl and export get offset/value symbol */ +#define gen_type_offset_impl(type) \ + unsigned int get_##type##_offset(int m) \ + { return _##type##_offset[m]; } \ + EXPORT_SYMBOL(get_##type##_offset) + +/* enum of struct zone */ +enum { + ZONE_OFFSET_LOCK, + ZONE_OFFSET_ZSP, + + __ZONE_OFFSET_MAX +}; +#define ZONE_LOCK_R(zone) ((spinlock_t *)((char *)zone \ + + get_zone_offset(ZONE_OFFSET_LOCK))) +#define ZONE_ZSP_R(zone) (*(unsigned long *)((char *)zone \ + + get_zone_offset(ZONE_OFFSET_ZSP))) +gen_type_offset(zone); + +/* enum of struct pglist_data */ +enum { + PGLIST_DATA_OFFSET_NODE_ZONES, + + __PGLIST_DATA_OFFSET_MAX +}; +#define PGLIST_DATA_NODE_ZONES_R(pglist_data) ((struct zone *) \ + ((char *)pglist_data + \ + get_pglist_data_offset(PGLIST_DATA_OFFSET_NODE_ZONES))) +gen_type_offset(pglist_data); +#endif //_OP_STRUCT_OFFSET_HELPER_INC_ diff --git a/drivers/oneplus/coretech/defrag/defrag_helper.c b/drivers/oneplus/coretech/defrag/defrag_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..6538bfdbea34b1b642c6249ee57f672da7e361e8 --- /dev/null +++ b/drivers/oneplus/coretech/defrag/defrag_helper.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct defrag_cb_set defrag_cbs; +atomic64_t fp_order_usage[MAX_ORDER] = {ATOMIC64_INIT(0)}; +atomic64_t fp_order_fail[MAX_ORDER] = {ATOMIC64_INIT(0)}; + +/* calling functions */ +struct page *defrag_alloc(struct zone *zone, unsigned long flags, + int migratetype, int order) +{ + if (defrag_cbs.defrag_alloc_cb) + return defrag_cbs.defrag_alloc_cb(zone, + flags, migratetype, order); + return NULL; +} + +long defrag_calc(struct zone *zone, int order, int alloc_flag) +{ + if (likely(defrag_cbs.defrag_calc_cb)) + return defrag_cbs.defrag_calc_cb(zone, order, alloc_flag); + else + return defrag_zone_free_size(zone); +} + +bool defrag_check_alloc_flag(unsigned int alloc_flags, int order) +{ + if (defrag_cbs.defrag_check_alloc_flag_cb) + return defrag_cbs.defrag_check_alloc_flag_cb(alloc_flags, + order); + return false; +} + +void defrag_register_cb_set(struct defrag_cb_set *cbs) +{ + defrag_cbs = *cbs; +} + +void defrag_unregister_cb_set(void) +{ + defrag_cbs.defrag_alloc_cb = NULL; + defrag_cbs.defrag_check_alloc_flag_cb = NULL; + defrag_cbs.defrag_calc_cb = NULL; +} diff --git a/drivers/oneplus/coretech/fsc/Makefile b/drivers/oneplus/coretech/fsc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..418f3edafa583dcd4bd50fce014daf37b6321ec6 --- /dev/null +++ b/drivers/oneplus/coretech/fsc/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FSC) += fsc.o diff --git a/drivers/oneplus/coretech/fsc/fsc.c b/drivers/oneplus/coretech/fsc/fsc.c new file mode 100644 index 0000000000000000000000000000000000000000..e82ea2deb51df881707219403b5c26282655f886 --- /dev/null +++ b/drivers/oneplus/coretech/fsc/fsc.c @@ -0,0 +1,856 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct file_status_cache { + char path[FSC_PATH_MAX]; + atomic_t refcnt; + u64 last_scan_ts; + u64 last_ref_ts; + u64 first_ref_ts; + u32 hidx; + struct list_head node; + int allow_idx; /* allow list index */ + atomic_t d_cnt; /* direct return cnt */ + u32 d_ret_ceil; +}; + +/* hashing algorithm */ +struct fsc_hash { + struct list_head head; + atomic_t cnt; + spinlock_t lock; +} fsc_htbl[FSC_HASH_BUCKET]; + +unsigned int fsc_enable = 0; +static bool fsc_ready = false; +static bool fsc_details = false; +module_param_named(details, fsc_details, bool, 0644); +static u32 fsc_d_ret = 128; +module_param_named(d_ret, fsc_d_ret, uint, 0644); + +/* Set a ceil for fsc obj allocation */ +unsigned int fsc_max_val = 100000; +module_param_named(fsc_max_val, fsc_max_val, uint, 0644); +static atomic_t fsc_cur_used; + +/* + * Allowed list + * trailing character should not contain '/' + * Interface for add/ del allow listi + */ +#define FSC_ALLOW_LIST_SIZE (32) + +struct allow_obj { + char *path; + int idx; + size_t len; +}; + +/* leave the last one always empty */ +static struct allow_obj fsc_allow_list[FSC_ALLOW_LIST_SIZE + 1]; +static int allow_idx_map[FSC_ALLOW_LIST_SIZE]; +static atomic_t fsc_allow_list_cnt[FSC_ALLOW_LIST_SIZE]; +int fsc_allow_list_cur; + +static inline int get_empty_allow_idx(void) { + int i = 0; + for (; i < FSC_ALLOW_LIST_SIZE; ++i) { + if (!allow_idx_map[i]) { + allow_idx_map[i] = 1; + return i; + } + } + return -1; +} + +/* To reclaim `out of date` fsc object */ +struct fsc_reclaimer { + struct list_head head; + atomic_t cnt; + struct task_struct *tsk; + unsigned long period; + unsigned int thres; + char path[FSC_PATH_MAX]; +} period, instcln; + +void fsc_spin_lock(u32 hidx) +{ + spin_lock(&fsc_htbl[hidx].lock); +} + +void fsc_spin_unlock(u32 hidx) +{ + spin_unlock(&fsc_htbl[hidx].lock); +} + +/* dcache helper to get absolute path */ +char *fsc_absolute_path(struct path* path, struct dentry* dentry, char *buf, size_t buflen) +{ + char localbuf[FSC_PATH_MAX] = {0}; + char *abspath = NULL; + size_t rlen, dlen; + + if (!path || !dentry || dentry->d_name.name[0] == '\0') + return NULL; + + abspath = d_absolute_path((const struct path*) path, localbuf, FSC_PATH_MAX); + if (IS_ERR(abspath)) + return NULL; + rlen = strlen(abspath); + dlen = strlen(dentry->d_name.name); + if (rlen + dlen + 2 > buflen) + return NULL; + memcpy(buf, abspath, rlen); + buf[rlen] = '/'; + memcpy(buf + rlen + 1, dentry->d_name.name, dlen); + buf[rlen + 1 + dlen] = '\0'; + + pr_debug("%s get %s\n", __func__, buf); + return buf; +} + +/* Using kernel string hash algo to get hash value, and mod to fit bucket */ +unsigned int fsc_get_hidx(const char* path, size_t len) +{ + u32 hidx = full_name_hash(NULL, path, len) % FSC_HASH_BUCKET; + pr_debug("%s hashing str: %s to %u\n", __func__, path, hidx); + return hidx; +} + +/* Allock fsc object with initialed value */ +static struct file_status_cache* fsc_alloc(const char* path, size_t len, u32 hidx, int allow_idx) +{ + struct file_status_cache* obj; + unsigned int cur_used = atomic_read(&fsc_cur_used); + + if (cur_used >= fsc_max_val) { + pr_debug("%s reach alloc max %u\n", __func__, cur_used); + return NULL; + } + + obj = kzalloc(sizeof(struct file_status_cache), GFP_NOWAIT); + if (!obj) { + pr_warn("%s create failed\n", __func__); + return NULL; + } + + /* init */ + strncpy(obj->path, path, len); + obj->path[len] = '\0'; + atomic_set(&obj->refcnt, 1); + obj->last_scan_ts = 0; + obj->first_ref_ts = jiffies; + obj->last_ref_ts = jiffies; + obj->hidx = hidx; + obj->d_ret_ceil = 1; + obj->allow_idx = allow_idx; + atomic_set(&obj->d_cnt, obj->d_ret_ceil); + atomic_inc(&fsc_allow_list_cnt[obj->allow_idx]); + /* For some apps, it will catch too much during installing stage, remove those records */ + if (likely(instcln.tsk) && + atomic_read(&fsc_allow_list_cnt[obj->allow_idx]) >= instcln.thres) { + wake_up_process(instcln.tsk); + } + pr_debug("%s: %s %lu %p\n", __func__, obj->path, strlen(obj->path), obj); + atomic_inc(&fsc_cur_used); + return obj; +} + +/* Free it */ +static void fsc_free(struct file_status_cache* obj) +{ + pr_debug("%s: %p\n", __func__, obj); + if (obj) { + atomic_dec(&fsc_cur_used); + atomic_dec(&fsc_allow_list_cnt[obj->allow_idx]); + kfree(obj); + } +} + +static int fsc_allow_list_add_store(const char *buf, const struct kernel_param *kp) +{ + size_t len = strlen(buf); + int i = 0, allow_idx = -1; + char *path; + + if (!len) + return 0; + + if (fsc_allow_list_cur >= FSC_ALLOW_LIST_SIZE) { + pr_warn("allow list add failed due to reach list limitation\n"); + return -EINVAL; + } + + path = kzalloc(len + 1, GFP_KERNEL); + if (!path) { + pr_err("memory allocation failed\n"); + return -EINVAL; + } + + if (sscanf(buf, "%s", path) <= 0) { + kfree(path); + return -EINVAL; + } + + len = strlen(path); + for (i = 0; i < fsc_allow_list_cur && i < FSC_ALLOW_LIST_SIZE; ++i) { + /* to avoid add duplicate list */ + if (strlen(fsc_allow_list[i].path) == len && !strncmp(fsc_allow_list[i].path, path, len)) { + kfree(path); + return 0; + } + } + allow_idx = get_empty_allow_idx(); + if (allow_idx == -1) { + pr_err("Can't get allow idx\n"); + kfree(path); + return 0; + } + fsc_allow_list[fsc_allow_list_cur].path = path; + fsc_allow_list[fsc_allow_list_cur].idx = allow_idx; + fsc_allow_list[fsc_allow_list_cur].len = len; + ++fsc_allow_list_cur; + + return 0; +} + +static struct kernel_param_ops fsc_allow_list_add_ops = { + .set = fsc_allow_list_add_store, +}; +module_param_cb(allow_list_add, &fsc_allow_list_add_ops, NULL, 0220); + +static int fsc_allow_list_del_store(const char *buf, const struct kernel_param *kp) +{ + size_t len = strlen(buf); + char *path; + int i = 0, allow_idx; + + if (!len) + return 0; + + path = kzalloc(len + 1, GFP_KERNEL); + if (!path) { + pr_err("memory allocation failed\n"); + return -EINVAL; + } + + if (sscanf(buf, "%s", path) <= 0) { + kfree(path); + return -EINVAL; + } + + len = strlen(path); + for (i = 0; i < fsc_allow_list_cur && i < FSC_ALLOW_LIST_SIZE; ++i) { + if (strlen(fsc_allow_list[i].path) == len && !strncmp(fsc_allow_list[i].path, path, len)) { + kfree(path); + path = fsc_allow_list[i].path; + allow_idx = fsc_allow_list[i].idx; + memset(instcln.path, '\0', FSC_PATH_MAX); + strncpy(instcln.path, path, len); + + for (; i < fsc_allow_list_cur && i < FSC_ALLOW_LIST_SIZE; ++i) { + fsc_allow_list[i].path = fsc_allow_list[i + 1].path; + fsc_allow_list[i].idx = fsc_allow_list[i + 1].idx; + fsc_allow_list[i].len = fsc_allow_list[i + 1].len; + } + --fsc_allow_list_cur; + + /* release obj */ + wake_up_process(instcln.tsk); + allow_idx_map[allow_idx] = 0; + break; + } + } + kfree(path); + return 0; +} + +static struct kernel_param_ops fsc_allow_list_del_ops = { + .set = fsc_allow_list_del_store, +}; +module_param_cb(allow_list_del, &fsc_allow_list_del_ops, NULL, 0220); + +static int fsc_dump_allow_list_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "fsc allow list: Total %u\n", fsc_allow_list_cur); + for (i = 0; i < fsc_allow_list_cur && i < FSC_ALLOW_LIST_SIZE; ++i) + seq_printf(m, "%s, cnt: %u\n", fsc_allow_list[i].path, atomic_read(&fsc_allow_list_cnt[fsc_allow_list[i].idx])); + return 0; +} + +static int fsc_dump_allow_list_open(struct inode *inode, struct file *file) +{ + return single_open(file, fsc_dump_allow_list_show, NULL); +} + +static const struct file_operations fsc_dump_allow_list_fops = { + .open= fsc_dump_allow_list_open, + .read= seq_read, + .llseek= seq_lseek, + .release= single_release, +}; + +static bool fsc_path_allow(const char* path, size_t len, int *allow_idx) +{ + int i = 0; + size_t flen = 0; + size_t offset = 0; + + /* + * enhance for this most frequency case: user 0 + * /storage/emulated/0/Android/data/ + */ +#define FSC_ALLOW_COMMON_PREFIX "/storage/emulated/0/Android/data/" +#define FSC_ALLOW_COMMON_PREFIX_LEN (33) + if (len < FSC_ALLOW_COMMON_PREFIX_LEN - 1) { + /* at least len >= /storage/emulated//Android/data/ */ + return false; + } + + if (strncmp(FSC_ALLOW_COMMON_PREFIX, path, FSC_ALLOW_COMMON_PREFIX_LEN)) + goto fsc_slow_check; + + /* fsc_fast_check only applied on user 0 */ + offset = FSC_ALLOW_COMMON_PREFIX_LEN; + path += offset; + len -= offset; + for (i = 0; i < fsc_allow_list_cur && fsc_allow_list[i].path && i < FSC_ALLOW_LIST_SIZE; ++i) { + char *check_path = fsc_allow_list[i].path + offset; + flen = fsc_allow_list[i].len - offset; + if (len >= flen && !strncmp(path, check_path, flen)) { + *allow_idx = fsc_allow_list[i].idx; + return true; + } + } + return false; + +fsc_slow_check: + for (i = 0; i < fsc_allow_list_cur && fsc_allow_list[i].path && i < FSC_ALLOW_LIST_SIZE; ++i) { + flen = fsc_allow_list[i].len; + if (len >= flen && !strncmp(path, fsc_allow_list[i].path, flen)) { + *allow_idx = fsc_allow_list[i].idx; + return true; + } + } + return false; +} + +/* + * To check if path already cached. + * Calling with lock & unlock + * Note: + * if cached, then + * inc refcnt + * update ref timestamp + */ +bool fsc_is_absence_path_exist_locked(const char* path, size_t len, u32 hidx, bool d_check) +{ + struct file_status_cache* fsc = NULL; + int allow_idx = -1; + + if (list_empty(&fsc_htbl[hidx].head)) + return false; + + if (!fsc_path_allow(path, len, &allow_idx)) + return false; + + list_for_each_entry(fsc, &fsc_htbl[hidx].head, node) { + if (strlen(fsc->path) == len && !strncmp(path, fsc->path, len)) { + /* update ref status */ + fsc->last_ref_ts = jiffies; + atomic_inc(&fsc->refcnt); + /* direct return check */ + pr_debug("%s %s exits in bucket %u, d_check: %u, called from %pS\n", + __func__, path, hidx, d_check, __builtin_return_address(0)); + if (d_check) { + /* if d_cnt == 0, do real check; otherwise directly return */ + if (atomic_dec_and_test(&fsc->d_cnt)) { + /* set next d_cnt by shift d_ret_ceil 1 */ + if (fsc->d_ret_ceil < fsc_d_ret) + fsc->d_ret_ceil <<= 1; + /* set direct return ceil */ + atomic_set(&fsc->d_cnt, fsc->d_ret_ceil); + return false; + } + } + return true; + } + } + return false; +} + +/* To check if path is good to apply fsc */ +bool fsc_path_check(struct filename *name, size_t *len) +{ + const char *sc; + + if (name->name[0] != '/') + return false; + + for (sc = name->name; *sc != '\0'; ++sc) { + /* ignore // .. cases */ + if (sc != name->name && *sc == *(sc - 1) && (*sc == '/' || *sc == '.')) + return false; + /* ignore /./ case */ + else if (sc - name->name > 1 && *sc == '/' && *(sc - 1) == '.' && *(sc - 2) == '/') + return false; + } + *len = sc - name->name; + return name->name[*len - 1] != '/' && *len < FSC_PATH_MAX; +} + +/* + * To check if path already cahced. + * Lock unlock inside + */ +bool fsc_absence_check(const char* path, size_t len) +{ + unsigned int hidx = 0; + + hidx = fsc_get_hidx(path, len); + fsc_spin_lock(hidx); + if (fsc_is_absence_path_exist_locked(path, len, hidx, true)) { + fsc_spin_unlock(hidx); + return true; + } + fsc_spin_unlock(hidx); + return false; +} + +/* + * To insert absence path to hash table + * Calling with lock & unlock + * Check if file alread cached before calling + */ +void fsc_insert_absence_path_locked(const char* path, size_t len, u32 hidx) +{ + struct file_status_cache* fsc; + int allow_idx = -1; + + if (!fsc_path_allow(path, len, &allow_idx)) + return; + + if (fsc_is_absence_path_exist_locked(path, len, hidx, false)) + return; + + fsc = fsc_alloc(path, len, hidx, allow_idx); + if (!fsc) + return; + + list_add(&fsc->node, &fsc_htbl[hidx].head); + atomic_inc(&fsc_htbl[hidx].cnt); + pr_debug("%s %s insert to bucket %u, called from %pS\n", + __func__, path, hidx, __builtin_return_address(0)); +} + +/* + * To delete absence path from hash table + * Calling with lock & unlock + */ +void fsc_delete_absence_path_locked(const char* path, size_t len, u32 hidx) +{ + struct file_status_cache* fsc; + int allow_idx = -1; + + if (!fsc_path_allow(path, len, &allow_idx)) + return; + + /* remove fsc obj from hashing list */ + list_for_each_entry(fsc, &fsc_htbl[hidx].head, node) { + if (strlen(fsc->path) == len && !strncmp(path, fsc->path, len)) { + atomic_dec(&fsc_htbl[hidx].cnt); + list_del(&fsc->node); + pr_debug("%s %s delete from bucket %u, called from %pS\n", + __func__, path, hidx, __builtin_return_address(0)); + fsc_free(fsc); + return; + } + } +} + +/* + * To delete absence path dentry from hash table + * Lock and unlock inside function + */ +void fsc_delete_absence_path_dentry(struct path* path, struct dentry* dentry) +{ + char buf[FSC_PATH_MAX] = {0}; + char *abspath; + + abspath = fsc_absolute_path(path, dentry, buf, FSC_PATH_MAX); + + if (abspath) { + size_t len = strlen(abspath); + unsigned int hidx = fsc_get_hidx(abspath, len); + fsc_spin_lock(hidx); + fsc_delete_absence_path_locked(abspath, len, hidx); + fsc_spin_unlock(hidx); + pr_debug("%s %s delete from bucket %u, called from %pS\n", + __func__, abspath, hidx, __builtin_return_address(0)); + } +} + +/* summary */ +struct fsc_summary { + char path[FSC_PATH_MAX]; + char package[FSC_PATH_MAX]; + size_t len; + size_t plen; + u32 cnt; +}; + +static const char* prefix = "/storage/emulated/0/Android/data"; +static struct fsc_summary* summary[FSC_SUMMARY_MAX]; +static unsigned int summary_idx = 0; + +/* Debug for dump hash tabl */ +static unsigned int total_max; +static unsigned int len_max; +static int fsc_dump_htbl_proc_show(struct seq_file *m, void *v) +{ + int hidx; + unsigned int total = 0; + struct file_status_cache *fsc; + size_t len, prefix_len = strlen(prefix); + int i = 0; + + for (hidx = 0; hidx < FSC_HASH_BUCKET; ++hidx) { + unsigned int cnt = 0; + fsc_spin_lock(hidx); + cnt = atomic_read(&fsc_htbl[hidx].cnt); + total += cnt; + if (!list_empty(&fsc_htbl[hidx].head)) { + if (fsc_details) + seq_printf(m, "hidx: %d, cnt: %d\n", hidx, cnt); + /* cached list */ + list_for_each_entry(fsc, &fsc_htbl[hidx].head, node) { + len = strlen(fsc->path); + /* check if need summary */ + if (len > prefix_len && !strncmp(prefix, fsc->path, prefix_len) && summary_idx < FSC_SUMMARY_MAX) { + char package[FSC_PATH_MAX] = {0}; + char *token = NULL, *end = NULL; + memcpy(package, fsc->path, FSC_PATH_MAX); + end = package + prefix_len; + strsep(&end, "/"); + token = end; + if (token) { + size_t plen; + bool need_alloc = true; + strsep(&end, "/"); + if (end) { + plen = strlen(token); + + /* check if need allocate summary object */ + for (i = 0; i < summary_idx; ++i) { + if (plen == summary[i]->plen && !strncmp(token, summary[i]->package, plen)) { + need_alloc = false; + break; + } + } + + if (need_alloc) { + summary[summary_idx] = kzalloc(sizeof(struct fsc_summary), GFP_NOWAIT); + if (summary[summary_idx]) { + memcpy(summary[summary_idx]->path, fsc->path, prefix_len + 1 + plen + 1); + memcpy(summary[summary_idx]->package, token, plen); + summary[summary_idx]->len = strlen(summary[summary_idx]->path); + summary[summary_idx]->plen = plen; + pr_debug("%s summary path: %s\n", __func__, summary[summary_idx]->path); + pr_debug("%s summary package: %s\n", __func__, summary[summary_idx]->package); + pr_debug("%s summary len: %lu, plen: %lu\n", __func__, + summary[summary_idx]->len, summary[summary_idx]->plen); + pr_debug("%s summary cnt: %u\n", __func__, summary[summary_idx]->cnt); + ++summary_idx; + } else + pr_warn("%s summary alloc failed\n", __func__); + } + } + + /* summary package information */ + for (i = 0; i < summary_idx; ++i) { + if (len > summary[i]->len && !strncmp(fsc->path, summary[i]->path, summary[i]->len)) { + ++summary[i]->cnt; + break; + } + } + } + } + + if (len > len_max) + len_max = len; + if (fsc_details) + seq_printf(m, " C: %d %s %lu %llu %llu %u %u %d\n", + atomic_read(&fsc->refcnt), fsc->path, strlen(fsc->path), fsc->first_ref_ts, fsc->last_ref_ts, fsc->d_ret_ceil, atomic_read(&fsc->d_cnt), fsc->allow_idx); + } + } + fsc_spin_unlock(hidx); + } + if (total > total_max) + total_max = total; + seq_printf(m, "Cache: %u, Used: %u, history max: %u, len: %u, current: %lu\n", + total, atomic_read(&fsc_cur_used), total_max, len_max, jiffies); + + if (summary_idx) { + /* dump summary and reset summary */ + seq_printf(m, "Summary:\n"); + for (i = 0; i < summary_idx; ++i) { + seq_printf(m, "\t[%d]: package: %s, absence file records: %u\n", i, summary[i]->package, summary[i]->cnt); + if (summary[i]) + kfree(summary[i]); + } + summary_idx = 0; + } + return 0; +} + +static int fsc_dump_htbl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, fsc_dump_htbl_proc_show, NULL); +} + +static const struct file_operations fsc_dump_htbl_fops = { + .open= fsc_dump_htbl_proc_open, + .read= seq_read, + .llseek= seq_lseek, + .release= single_release, +}; + +static int fsc_enable_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + int hidx; + + if (unlikely(!fsc_ready)) + return 0; + + if (sscanf(buf, "%u", &val) <= 0) + return -EINVAL; + + fsc_enable = val; + + if (fsc_enable) + return 0; + + /* if turn off, flush table */ + for (hidx = 0; hidx < FSC_HASH_BUCKET; ++hidx) { + fsc_spin_lock(hidx); + if (!list_empty(&fsc_htbl[hidx].head)) { + struct file_status_cache *fsc, *tmp; + list_for_each_entry_safe(fsc, tmp, &fsc_htbl[hidx].head, node) { + if (fsc) { + list_del(&fsc->node); + fsc_free(fsc); + atomic_dec(&fsc_htbl[hidx].cnt); + } + } + } + fsc_spin_unlock(hidx); + } + return 0; +} + +static int fsc_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u", fsc_enable); +} + +static struct kernel_param_ops fsc_enable_ops = { + .set = fsc_enable_store, + .get = fsc_enable_show, +}; +module_param_cb(enable, &fsc_enable_ops, NULL, 0644); + +static int period_reclaim(void *arg) +{ + static unsigned int hidx = 0; + while (!kthread_should_stop()) { + int i = 0; + + if (!fsc_enable) { + msleep(period.period); + continue; + } + + for (i = 0; i < FSC_SCAN_BULK; ++i) { + hidx %= FSC_HASH_BUCKET; + fsc_spin_lock(hidx); + if (!list_empty(&fsc_htbl[hidx].head)) { + struct file_status_cache *fsc, *tmp; + list_for_each_entry_safe(fsc, tmp, &fsc_htbl[hidx].head, node) { + if (fsc) { + /* get rid of obj after 2 days (48 hours) passed */ + int delta = (jiffies - fsc->last_ref_ts)/(HZ * 172800L); + if (delta) { + /* time to go home */ + list_del(&fsc->node); + atomic_dec(&fsc_htbl[hidx].cnt); + list_add(&fsc->node, &period.head); + pr_debug("%s decay: %s out\n", __func__, fsc->path); + } + } + } + } + fsc_spin_unlock(hidx); + ++hidx; + } + + /* free them */ + if (!list_empty(&period.head)) { + struct file_status_cache *fsc, *tmp; + list_for_each_entry_safe(fsc, tmp, &period.head, node) { + list_del(&fsc->node); + fsc_free(fsc); + } + } + msleep(period.period); + } + return 0; +} + +/* scan for out of limit fsc object */ +static int instcln_reclaim(void* args) +{ + unsigned int i = 0; + char *uninst_pkg = (char *)args; + int uninst_len; + bool uninst_ing = false; + bool remove = false; + int target; + + while (!kthread_should_stop()) { + /* always reset target before really reclaim */ + target = -1; + + if (!fsc_enable) { + usleep_range(instcln.period, instcln.period + 1000000); + continue; + } + + /* step 1. find out which package is going to uninstall */ + uninst_len = strlen(uninst_pkg); + if (unlikely(uninst_len)) { + uninst_ing = true; + goto redo; + } + + /* step 2. find out which package over limit */ + for (i = 0; target == -1 && i < fsc_allow_list_cur; ++i) { + if (atomic_read(&fsc_allow_list_cnt[fsc_allow_list[i].idx]) >= instcln.thres) { + target = i; + break; + } + } + + if (target == -1) + goto done; + +redo: + /* step 3. reclaim objs */ + for (i = 0; i < FSC_HASH_BUCKET; ++i) { + fsc_spin_lock(i); + /* drop target fsc object */ + if (!list_empty(&fsc_htbl[i].head)) { + struct file_status_cache *fsc, *tmp; + list_for_each_entry_safe(fsc, tmp, &fsc_htbl[i].head, node) { + if (likely(fsc)) { + remove = false; + if (uninst_ing && !strncmp(fsc->path, uninst_pkg, uninst_len)) + remove = true; + else if (!uninst_ing && fsc->allow_idx == target) + remove = true; + if (remove) { + list_del(&fsc->node); + atomic_dec(&fsc_htbl[i].cnt); + list_add(&fsc->node, &instcln.head); + } + } + } + } + fsc_spin_unlock(i); + } + + if (!list_empty(&instcln.head)) { + struct file_status_cache *fsc, *tmp; + list_for_each_entry_safe(fsc, tmp, &instcln.head, node) { + list_del(&fsc->node); + fsc_free(fsc); + } + } + + /* step 4. check if any uninstall event happened during reclaim period */ + if (uninst_ing) + uninst_pkg[0] = '\0'; + uninst_len = strlen(uninst_pkg); + if (unlikely(uninst_len)) { + uninst_ing = true; + goto redo; + } +done: + uninst_ing = false; + usleep_range(instcln.period, instcln.period + 1000000); + } + return 0; +} + +static int __init fsc_init(void) +{ + int i = 0; + pr_info("%s\n", __func__); + + atomic_set(&fsc_cur_used, 0); + for (i = 0; i < FSC_HASH_BUCKET; ++i) { + INIT_LIST_HEAD(&fsc_htbl[i].head); + atomic_set(&fsc_htbl[i].cnt, 0); + spin_lock_init(&fsc_htbl[i].lock); + } + + for (i = 0; i < FSC_ALLOW_LIST_SIZE; ++i) + atomic_set(&fsc_allow_list_cnt[i], 0); + + /* init for period & instcln reclaimer */ + INIT_LIST_HEAD(&period.head); + period.period = 1 * 60 * 60 * 1000; // 1 hour, ms + period.tsk = kthread_run(period_reclaim, NULL, "fsc_period_reclaimer"); + if (!period.tsk) { + pr_err("%s: init period reclaimer failed\n", __func__); + return 0; + } + + INIT_LIST_HEAD(&instcln.head); + instcln.period = 1L * 60L * 60L * 1000L * 1000L; // 1 hour, us + instcln.thres = 10000; // per package should not cache more than this thres. + instcln.path[0] = '\0';; + instcln.tsk = kthread_run(instcln_reclaim, instcln.path, "fsc_instcln_reclaimer"); + if (!instcln.tsk) { + pr_err("%s: init instcln reclaimer failed\n", __func__); + kthread_stop(period.tsk); + return 0; + } + + /* info */ + proc_create("fsc_dump", S_IFREG | 0400, NULL, &fsc_dump_htbl_fops); + proc_create("fsc_allow_list", S_IFREG | 0400, NULL, &fsc_dump_allow_list_fops); + + pr_info("%s done\n", __func__); + + fsc_ready = true; + return 0; +} +pure_initcall(fsc_init); diff --git a/drivers/oneplus/coretech/fsc/test/Android.mk b/drivers/oneplus/coretech/fsc/test/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..91e2835a8ebd5356bf936ea63d48564f2d31c571 --- /dev/null +++ b/drivers/oneplus/coretech/fsc/test/Android.mk @@ -0,0 +1,9 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := fsc-unit-tests +LOCAL_MODULE_TAGS := tests +LOCAL_CFLAGS = -Wall -Wextra -Werror +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := fsc_test.cpp +include $(BUILD_NATIVE_TEST) diff --git a/drivers/oneplus/coretech/fsc/test/fsc_test.cpp b/drivers/oneplus/coretech/fsc/test/fsc_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b127799cb3f7019bbfa3dc817d00f846d292aa29 --- /dev/null +++ b/drivers/oneplus/coretech/fsc/test/fsc_test.cpp @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define TARGET_ALLOW_LIST "/data/local/tmp" +#define FSC_ENABLE "/sys/module/fsc/parameters/enable" +#define ADD_ALLOW_LIST_ENTRY "/sys/module/fsc/parameters/allow_list_add" +#define DEL_ALLOW_LIST_ENTRY "/sys/module/fsc/parameters/allow_list_del" +#define ALLOW_LIST_DUMP "/proc/fsc_allow_list" + +#define EMPTY_FILE "/data/local/tmp/fsc_test_file" +#define EMPTY_FILE_ALIAS_0 "/data/local/tmp/fsc_test_file" +#define EMPTY_FILE_ALIAS_1 "fsc_test_file" +#define EMPTY_FILE_ALIAS_2 "./fsc_test_file" +#define EMPTY_FILE_ALIAS_3 "../tmp/./././fsc_test_file" +#define EMPTY_FILE_ALIAS_4 ".././././//./tmp/fsc_test_file" +#define EMPTY_FILE_ALIAS_5 ".././//tmp/././//./fsc_test_file" + +#define PREPARE_FILE "/data/local/tmp/fsc_prepare_file" + + +static void fsc_test_init(void) { + /* reset fsc first */ + android::base::WriteStringToFile("0", FSC_ENABLE); + android::base::WriteStringToFile("1", FSC_ENABLE); + android::base::WriteStringToFile(TARGET_ALLOW_LIST, ADD_ALLOW_LIST_ENTRY); +} + +static void fsc_test_deinit(void) { + android::base::WriteStringToFile(TARGET_ALLOW_LIST, DEL_ALLOW_LIST_ENTRY); +} + +static bool fsc_check_allow_list(void) { + std::ifstream infile(ALLOW_LIST_DUMP); + std::string path; + while (std::getline(infile, path)) { + int coma = path.find(","); + path = path.substr(0, coma); + if (path == TARGET_ALLOW_LIST) + return true; + } + return false; +} + +static int fsc_check_file_exist(const char *name) { + struct stat sb; + return stat(name, &sb); +} + +static int fsc_create_file(const char *name, int flags, mode_t mode) { + int fd = open(name, flags, mode); + if (fd) EXPECT_EQ(close(fd), 0); + return fd; +} + +TEST(fsc, add_allow_list) { + int cnt = 1000; + while (--cnt) { + fsc_test_init(); + ASSERT_TRUE(fsc_check_allow_list()); + fsc_test_deinit(); + } +} + +/* + * testing coverage: + * open related + */ +#define GEN_TEST_OPEN_ALIAS(num) \ +TEST(fsc, open_alias_##num) { \ + const char* target = EMPTY_FILE_ALIAS_##num; \ + fsc_test_init(); \ + ASSERT_TRUE(fsc_check_allow_list()); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), -1); \ + EXPECT_GE(fsc_create_file(target, O_CREAT, S_IRUSR|S_IWUSR), 0); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), 0); \ + EXPECT_EQ(unlink(EMPTY_FILE), 0); \ + fsc_test_deinit(); \ +} + +GEN_TEST_OPEN_ALIAS(0); +GEN_TEST_OPEN_ALIAS(1); +GEN_TEST_OPEN_ALIAS(2); +GEN_TEST_OPEN_ALIAS(3); +GEN_TEST_OPEN_ALIAS(4); +GEN_TEST_OPEN_ALIAS(5); + +/* + * testing coverage: + * mv rename + */ +#define GEN_TEST_RENAME_ALIAS(num) \ +TEST(fsc, rename_alias_##num) { \ + const char* from = PREPARE_FILE; \ + const char* to = EMPTY_FILE_ALIAS_##num; \ + fsc_test_init(); \ + ASSERT_TRUE(fsc_check_allow_list()); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), -1); \ + EXPECT_GE(fsc_create_file(from, O_CREAT, S_IRUSR|S_IWUSR), 0); \ + EXPECT_EQ(rename(from, to), 0); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), 0); \ + EXPECT_EQ(unlink(EMPTY_FILE), 0); \ + fsc_test_deinit(); \ +} + +GEN_TEST_RENAME_ALIAS(0) +GEN_TEST_RENAME_ALIAS(1) +GEN_TEST_RENAME_ALIAS(2) +GEN_TEST_RENAME_ALIAS(3) +GEN_TEST_RENAME_ALIAS(4) +GEN_TEST_RENAME_ALIAS(5) + +/* + * testing coverage: + * link symlink + */ +#define GEN_TEST_LINK_ALIAS(num) \ +TEST(fsc, link_##num) { \ + const char* from = PREPARE_FILE; \ + const char* to = EMPTY_FILE_ALIAS_##num; \ + fsc_test_init(); \ + ASSERT_TRUE(fsc_check_allow_list()); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), -1); \ + EXPECT_GE(fsc_create_file(from, O_CREAT, S_IRUSR|S_IWUSR), 0); \ + EXPECT_EQ(link(from, to), 0); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), 0); \ + EXPECT_EQ(unlink(EMPTY_FILE), 0); \ + EXPECT_EQ(unlink(from), 0); \ + fsc_test_deinit(); \ +} + +GEN_TEST_LINK_ALIAS(0) +GEN_TEST_LINK_ALIAS(1) +GEN_TEST_LINK_ALIAS(2) +GEN_TEST_LINK_ALIAS(3) +GEN_TEST_LINK_ALIAS(4) +GEN_TEST_LINK_ALIAS(5) + +#define GEN_TEST_SYMLINK_ALIAS(num) \ +TEST(fsc, symlink_##num) { \ + const char* from = PREPARE_FILE; \ + const char* to = EMPTY_FILE_ALIAS_##num; \ + fsc_test_init(); \ + ASSERT_TRUE(fsc_check_allow_list()); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), -1); \ + EXPECT_GE(fsc_create_file(from, O_CREAT, S_IRUSR|S_IWUSR), 0); \ + EXPECT_EQ(symlink(from, to), 0); \ + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), 0); \ + EXPECT_EQ(unlink(EMPTY_FILE), 0); \ + EXPECT_EQ(unlink(from), 0); \ + fsc_test_deinit(); \ +} + +GEN_TEST_SYMLINK_ALIAS(0) +GEN_TEST_SYMLINK_ALIAS(1) +GEN_TEST_SYMLINK_ALIAS(2) +GEN_TEST_SYMLINK_ALIAS(3) +GEN_TEST_SYMLINK_ALIAS(4) +GEN_TEST_SYMLINK_ALIAS(5) + +/* + * testing for race + */ +static void *thread_stat(void *arg __unused) { + struct stat sb; + while (stat(EMPTY_FILE, &sb)); + return NULL; +} + +static void *thread_open(void *arg __unused) { + int fd = -1; + fd = open(EMPTY_FILE, O_CREAT, 0644); + if (fd) close(fd); + return NULL; +} + +#define TEST_ROUNDS (100000) +#define THREAD_MAX (10) +TEST(fsc, race) { + int ceil, i = 0; + int test = 0, test_ceil = TEST_ROUNDS; + pthread_t stat_tids[THREAD_MAX]; + pthread_t open_tid; + + fsc_test_init(); + ASSERT_TRUE(fsc_check_allow_list()); + EXPECT_EQ(fsc_check_file_exist(EMPTY_FILE), -1); + + GTEST_LOG_(INFO) << "RACE TEST: this test will take around 3 minutes to complete."; + while (test++ != test_ceil) { + srand(time(NULL)); + ceil = rand() % THREAD_MAX; + + for (i = 0; i <= ceil; ++i) + pthread_create(&stat_tids[i], NULL, &thread_stat, NULL); + + pthread_create(&open_tid, NULL, &thread_open, NULL); + + for (i = 0; i <= ceil; ++i) + pthread_join(stat_tids[i], NULL); + + pthread_join(open_tid, NULL); + + EXPECT_EQ(unlink(EMPTY_FILE), 0); + //GTEST_LOG_(INFO) << "RACE TEST: (" << test << "/" << test_ceil << ") pass"; + } + fsc_test_deinit(); +} diff --git a/drivers/oneplus/coretech/fsc/test/prebuilt/arm/fsc-unit-tests b/drivers/oneplus/coretech/fsc/test/prebuilt/arm/fsc-unit-tests new file mode 100755 index 0000000000000000000000000000000000000000..0277b94748b6c88d52a803285c322354a1036b6c Binary files /dev/null and b/drivers/oneplus/coretech/fsc/test/prebuilt/arm/fsc-unit-tests differ diff --git a/drivers/oneplus/coretech/fsc/test/prebuilt/arm64/fsc-unit-tests b/drivers/oneplus/coretech/fsc/test/prebuilt/arm64/fsc-unit-tests new file mode 100755 index 0000000000000000000000000000000000000000..239bcdc57bafd069e035fff835bbf5ad680fe8e0 Binary files /dev/null and b/drivers/oneplus/coretech/fsc/test/prebuilt/arm64/fsc-unit-tests differ diff --git a/drivers/oneplus/coretech/fsc/test/prebuilt/fsc-unit-tests.config b/drivers/oneplus/coretech/fsc/test/prebuilt/fsc-unit-tests.config new file mode 100644 index 0000000000000000000000000000000000000000..32fd307dc39cb265a25a49e4ee816e65c4622062 --- /dev/null +++ b/drivers/oneplus/coretech/fsc/test/prebuilt/fsc-unit-tests.config @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/drivers/oneplus/coretech/houston/Makefile b/drivers/oneplus/coretech/houston/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6235862bf602368015483862b0c7479bca3aca45 --- /dev/null +++ b/drivers/oneplus/coretech/houston/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HOUSTON) += houston.o diff --git a/drivers/oneplus/coretech/houston/houston.c b/drivers/oneplus/coretech/houston/houston.c new file mode 100644 index 0000000000000000000000000000000000000000..6521cb1ef3315536b09f7e04e6e69aa9869e1591 --- /dev/null +++ b/drivers/oneplus/coretech/houston/houston.c @@ -0,0 +1,2670 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../drivers/gpu/msm/kgsl.h" +#include "../drivers/gpu/msm/kgsl_pwrctrl.h" + +#include + +#include + +#ifdef CONFIG_OPCHAIN +#include +#endif + +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#include +#include <../kernel/sched/sched.h> + +/* perf raw counter */ +#define ARMV8_PMCR_MASK 0x3f +#define ARMV8_PMCR_E (1 << 0) /* Enable all counters */ +#define ARMV8_PMCR_C (1 << 2) /* Cycle counter reset */ +#define ARMV8_PMCR_LC (1 << 6) /* Cycle Counter 64bit overflow */ + +/* Need to align housotn.h HT_MONITOR_SIZE */ +static const char *ht_monitor_case[HT_MONITOR_SIZE] = { + "ts", + "clus_0_min", "clus_0_cur", "clus_0_max", "clus_0_iso", + "clus_1_min", "clus_1_cur", "clus_1_max", "clus_1_iso", + "clus_2_min", "clus_2_cur", "clus_2_max", "clus_2_iso", + "gpu_cur", "voltage_now", "current_now", "hw_instruction", + "hw_cache_miss", "hw_cycle", + "cpu-0-0-usr", "cpu-0-1-usr", "cpu-0-2-usr", "cpu-0-3-usr", + "cpu-1-0-usr", "cpu-1-1-usr", "cpu-1-2-usr", "cpu-1-3-usr", + "cpu-1-4-usr", "cpu-1-5-usr", "cpu-1-6-usr", "cpu-1-7-usr", + "shell_front", "shell_frame", "shell_back", + "util-0", "util-1", "util-2", "util-3", "util-4", + "util-5", "util-6", "util-7", + "process name", "layer name", "pid", "fps_align", "actualFps", + "predictFps", "Vsync", "gameFps", + "NULL", "NULL", "NULL", + "NULL", "missedLayer", "render_pid", "render_util", + "nt_rtg", "rtg_util_sum" +}; + +static struct game_fps_data { + u64 fps; + u64 enqueue_time; +} game_fps_data_; + +/* + * log output + * lv == 0 -> verbose info warning error + * lv == 1 -> info warning error + * lv == 2 -> wraning error + * lv >= 3 -> error + */ +static int ht_log_lv = 1; +module_param_named(log_lv, ht_log_lv, int, 0664); + +/* ais */ +static int ais_enable = 0; +module_param_named(ais_enable, ais_enable, int, 0664); + +static DEFINE_SPINLOCK(egl_buf_lock); +#define EGL_BUF_MAX (128) +static char egl_buf[EGL_BUF_MAX] = {0}; + +static int ai_on = 1; +module_param_named(ai_on, ai_on, int, 0664); + +static int render_pid; +module_param_named(render_pid, render_pid, int, 0664); + +/* fps */ +static int game_fps_pid = -1; +module_param_named(game_fps_pid, game_fps_pid, int, 0664); + +static int pccore_always_on; +module_param_named(pcc_always_on, pccore_always_on, int, 0664); +/* pmu */ +static int perf_ready = -1; + +#ifdef CONFIG_ONEPLUS_FG_OPT +unsigned int ht_fuse_boost = 0; +module_param_named(fuse_boost, ht_fuse_boost, uint, 0664); +#endif + +/* perf notify */ +static struct ai_parcel parcel; +static struct workqueue_struct *ht_perf_workq; + +static DEFINE_SPINLOCK(ht_perf_lock); +static DECLARE_WAIT_QUEUE_HEAD(ht_perf_waitq); +static DECLARE_WAIT_QUEUE_HEAD(ht_poll_waitq); + +/* render & rtg util*/ +static pid_t RenPid = -1; +static int get_util(bool isRender, int *num); + +/* hwui boost online config switch */ +static int ht_hwui_boost_enable = 1; +module_param_named(hwui_boost_enable, ht_hwui_boost_enable, int, 0664); + +/* + * perf event list + * A list chained with task which perf event created + */ +static DEFINE_SPINLOCK(ht_perf_event_lock); +static struct list_head ht_perf_event_head = LIST_HEAD_INIT(ht_perf_event_head); + +/* RTG (related thread group) */ +static DEFINE_SPINLOCK(ht_rtg_lock); +static struct list_head ht_rtg_head = LIST_HEAD_INIT(ht_rtg_head); + +/* + * tmp list for storing rtg tasks + * when traverse rtg list, we need hold spin lock, but in this context + * we can't collect perf data (might sleep), so we need to use another + * list to store these tasks, and then collect perf data in safe context. + */ +static struct list_head ht_rtg_perf_head = LIST_HEAD_INIT(ht_rtg_perf_head); + +/* report skin_temp to ais */ +static unsigned int thermal_update_period_hz = 100; +module_param_named(thermal_update_period_hz, thermal_update_period_hz, uint, 0664); + +/* + * filter mechanism + * base_util: rtg task util threshold + * rtg_filter_cnt: rtg task called cnt threshold under 1 sec + */ +static unsigned int base_util = 100; +module_param_named(base_util, base_util, uint, 0664); +static unsigned int rtg_filter_cnt = 10; +module_param_named(rtg_filter_cnt, rtg_filter_cnt, uint, 0664); + +/* sched */ +extern unsigned long long task_sched_runtime(struct task_struct *p); + +/* fps boost info */ +static atomic_t boost_cnt = ATOMIC_INIT(0); + +/* fps tag to align other dump report */ +static atomic64_t fps_align_ns; + +/* cpuload tracking */ +/* TODO these info maybe useless to sufraceflinger, should remove later */ +struct cpuload_info { + int cnt; + int cmin; + int cmax; + int sum; + long long iowait_min; + long long iowait_max; + long long iowait_sum; +}; +static long long ht_iowait[8] = {0}; +static long long ht_delta_iowait[8] = {0}; +static bool cpuload_query = false; +module_param_named(cpuload_query, cpuload_query, bool, 0664); + +/* battery query, it takes time to query */ +static bool bat_query = false; +module_param_named(bat_query, bat_query, bool, 0664); + +static bool bat_sample_high_resolution = false; +module_param_named(bat_sample_high_resolution, bat_sample_high_resolution, bool, 0664); + +/* force update battery current */ +static unsigned long bat_update_period_us = 1000000; // 1 sec +module_param_named(bat_update_period_us, bat_update_period_us, ulong, 0664); + +extern void bq27541_force_update_current(void); + +/* fps boost switch */ +static bool fps_boost_enable = true; +module_param_named(fps_boost_enable, fps_boost_enable, bool, 0664); + +static bool fps_boost_force_enable; +module_param_named(fps_boost_force_enable, fps_boost_force_enable, bool, 0664); + +/* trubo boost switch */ +static bool tb_enable = true; +module_param_named(tb_enable, tb_enable, bool, 0664); + +/* freq hispeed */ +static bool cpufreq_hispeed_enable = false; +module_param_named(cpufreq_hispeed_enable, cpufreq_hispeed_enable, bool, 0664); + +static unsigned int cpufreq_hispeed[HT_CLUSTERS] = { 1209600, 1612800, 1612800 }; +module_param_array_named(cpufreq_hispeed, cpufreq_hispeed, uint, NULL, 0664); + +static bool ddrfreq_hispeed_enable = true; +module_param_named(ddrfreq_hispeed_enable, ddrfreq_hispeed_enable, bool, 0664); + +static unsigned int ddrfreq_hispeed = 1017; +module_param_named(ddrfreq_hispeed, ddrfreq_hispeed, uint, 0664); + +/* choose boost freq to lock or lower bound */ +static unsigned int fps_boost_type = 1; +module_param_named(fps_boost_type, fps_boost_type, uint, 0664); + +/* filter out too close boost hint */ +static unsigned long fps_boost_filter_us = 8000; +module_param_named(fps_boost_filter_us, fps_boost_filter_us, ulong, 0664); + +/* houston monitor + * data: sample data + * layer: sample data for frame info + * process: sample data for frame process info + */ +struct sample_data { + u64 data[MAX_REPORT_PERIOD][HT_MONITOR_SIZE]; + char layer[MAX_REPORT_PERIOD][FPS_LAYER_LEN]; + char process[MAX_REPORT_PERIOD][FPS_PROCESS_NAME_LEN]; +}; + +struct ht_monitor { + struct power_supply *psy; + struct thermal_zone_device* tzd[HT_MONITOR_SIZE]; + struct task_struct *thread; + struct sample_data *buf; +} monitor = { + .psy = NULL, + .thread = NULL, + .buf = NULL, +}; + +/* MUST FIX: CPU deployment by different platform */ +struct ht_util_pol { + unsigned long *utils[HT_CPUS_PER_CLUS]; + unsigned long *hi_util; +}; + +/* monitor switch */ +static unsigned int ht_enable = 0; + +/* mask only allow within 64 events */ +static unsigned long ht_all_mask = 0; + +static unsigned long filter_mask = 0; +module_param_named(filter_mask, filter_mask, ulong, 0664); + +static unsigned long disable_mask = 0; +module_param_named(disable_mask, disable_mask, ulong, 0664); + +static unsigned int report_div[HT_MONITOR_SIZE]; +module_param_array_named(div, report_div, uint, NULL, 0664); + +/* + * monitor configuration + * sidx: current used idx (should be update only by monitor thread) + * record_cnt: current recorded sample amount + * cached_fps: to record current efps and fps info + * cached_layer_name: to record layer name. (debug purpose) + * ht_tzd_idx: thermal zone index + * gpwe: saved kgsl ptr, to get gpu freq + * sample_rate: sample rate in ms + * ht_utils: saved util prt, update from sugov + * keep_alive: monitor life cycle + */ +static int sidx; +static unsigned int record_cnt = 0; + +static atomic_t cached_fps[2]; +/*ignore pass layer name to aischeduler*/ +//static char cached_layer_name[FPS_CACHE_LAYER_LEN] = {0}; + +static int ht_tzd_idx = HT_CPU_0; +static struct kgsl_pwrctrl *gpwr; +static unsigned int sample_rate = 3000; +/* MUST FIX: CPU deployment by different platform */ +static struct ht_util_pol ht_utils[HT_CLUSTERS]; + +static bool __read_mostly keep_alive = false; + +static dev_t ht_ctl_dev; +static struct class *driver_class; +static struct cdev cdev; + +/* helper */ +static inline int cpu_to_clus(int cpu) +{ + switch (cpu) { + case 0: case 1: case 2: case 3: return 0; + case 4: case 5: case 6: return 1; + case 7: return 2; + } + return 0; +} + +static inline int clus_to_cpu(int clus) +{ + switch (clus) { + case 0: return CLUS_0_IDX; + case 1: return CLUS_1_IDX; + case 2: return CLUS_2_IDX; + } + return CLUS_0_IDX; +} + +static inline u64 ddr_find_target(u64 target) { + int i; + u64 ddr_options[12] = { + 200, 300, 451, 547, 681, 768, 1017, 1353, 1555, 1804, 2092, 2736 + }; + + for (i = 11; i >= 0; --i) { + if (target >= ddr_options[i]) { + target = ddr_options[i]; + break; + } + } + return target; +} + +static inline void ht_query_ddrfreq(u64* val) +{ + clk_get_ddr_freq(val); + + *val /= 1000000; + /* process for easy deal with */ + if (*val == 1018) *val = 1017; + else if (*val == 1355) *val = 1353; + else if (*val == 1805) *val = 1804; + else if (*val == 2096) *val = 2092; + else if (*val == 2739) *val = 2736; +} + +static inline int ht_next_sample_idx(void) +{ + ++sidx; + sidx %= MAX_REPORT_PERIOD; + + return sidx; +} + +static inline void ht_set_all_mask(void) +{ + int i; + + for (i = 0; i < HT_MONITOR_SIZE; ++i) + ht_all_mask |= (1L << i); +} + +static inline bool ht_is_all_disabled(unsigned long mask) +{ + return ht_all_mask == mask; +} + +static inline bool ht_is_all_filtered(unsigned long mask) +{ + return ht_all_mask == mask; +} + +static inline int ht_mapping_tags(char *name) +{ + int i; + + for (i = 0; i < HT_MONITOR_SIZE; ++i) + if (!strcmp(name, ht_monitor_case[i])) + return i; + + return HT_MONITOR_SIZE; +} + +static inline const char* ht_ioctl_str(unsigned int cmd) +{ + switch (cmd) { + case HT_IOC_COLLECT: return "HT_IOC_COLLECT"; + case HT_IOC_SCHEDSTAT: return "HT_IOC_SCHEDSTAT"; + case HT_IOC_CPU_LOAD: return "HT_IOC_CPU_LOAD"; + case HT_IOC_FPS_STABILIZER_UPDATE: return "HT_IOC_FPS_STABILIZER_UPDATE"; + case HT_IOC_FPS_PARTIAL_SYS_INFO: return "HT_IOC_FPS_PARTIAL_SYS_INFO"; + } + return "UNKNOWN"; +} + +static inline int ht_get_temp(int monitor_idx) +{ + int temp = 0; + + if (unlikely(!monitor.tzd[monitor_idx])) + return 0; + + if (disable_mask & (1 << monitor_idx)) + return 0; + + if (thermal_zone_get_temp(monitor.tzd[monitor_idx], &temp)) { + ht_logv("failed to read out thermal zone with idx %d\n", monitor.tzd[monitor_idx]->id); + return 0; + } + + return temp; +} + +static inline void ht_update_battery(void) +{ + static u64 prev = 0; + u64 cur = ktime_to_us(ktime_get()); + + if (cur - prev >= bat_update_period_us) { + if (bat_sample_high_resolution) + bq27541_force_update_current(); + ht_logv("force update battery info\n"); + prev = cur; + } else if (prev > cur) { + prev = cur; + ht_logv("fix update battery timestamp\n"); + } +} + +static inline u64 ht_get_iowait_time(int cpu) +{ + u64 iowait, iowait_usecs = -1ULL; + + if (cpu_online(cpu)) + iowait_usecs = get_cpu_iowait_time_us(cpu, NULL); + + if (iowait_usecs == -1ULL) + /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */ + iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; + else + iowait = iowait_usecs * NSEC_PER_USEC; + + return iowait; +} + +/* offline included */ +static inline int ht_iso_count(const cpumask_t *mask) +{ + cpumask_t count_mask = CPU_MASK_NONE; + + cpumask_complement(&count_mask, cpu_online_mask); + cpumask_or(&count_mask, &count_mask, cpu_isolated_mask); + cpumask_and(&count_mask, &count_mask, mask); + + return cpumask_weight(&count_mask); +} + +/* sched switch update */ +static inline void ht_sched_update(struct task_struct *task, bool in) +{ + u64 now = 0; + + spin_lock(&task->rtg_lock); + asm volatile("isb;mrs %0, pmccntr_el0" : "=r"(now)); + if (in) { + task->run_ts = task->end_ts = now; + } else { + task->acc_run_ts += now - task->run_ts; + task->end_ts = now; + } + spin_unlock(&task->rtg_lock); +} + +static inline u32 armv8pmu_pmcr_read(void) +{ + u64 val = 0; + asm volatile("mrs %0, pmcr_el0" : "=r" (val)); + return (u32)val; +} + +static inline void armv8pmu_pmcr_write(u32 val) +{ + val &= ARMV8_PMCR_MASK; + isb(); + asm volatile("msr pmcr_el0, %0" : : "r" ((u64)val)); +} + +static void enable_cpu_counters(void* data) +{ + armv8pmu_pmcr_write(armv8pmu_pmcr_read() | ARMV8_PMCR_LC | ARMV8_PMCR_E | ARMV8_PMCR_C); + ht_logi("CPU:%d enable counter\n", smp_processor_id()); +} + +static unsigned int ht_get_temp_delay(int idx) +{ + static unsigned long next[HT_MONITOR_SIZE] = {0}; + static unsigned int temps[HT_MONITOR_SIZE] = {0}; + + /* only allow for reading sensor data */ + if (unlikely(idx < HT_CPU_0 || idx > HT_THERM_2)) + return 0; + + /* update */ + if (jiffies > next[idx] && jiffies - next[idx] > thermal_update_period_hz) { + next[idx] = jiffies; + temps[idx] = ht_get_temp(idx); + } + + if (jiffies < next[idx]) { + next[idx] = jiffies; + temps[idx] = ht_get_temp(idx); + } + + return temps[idx]; +} + +/* + * boost cpufreq while no ais activated + * boost_target[0] : pid + * boost_target[1] : tid + */ +#ifdef CONFIG_CONTROL_CENTER +static int boost_target[FPS_TARGET_NUM] = {0}; +#endif + +void ht_rtg_init(struct task_struct *task) +{ + task->rtg_ts = 0; + INIT_LIST_HEAD(&task->rtg_node); + INIT_LIST_HEAD(&task->rtg_perf_node); + spin_lock_init(&task->rtg_lock); +} + +static int perf_ready_store(const char *buf, const struct kernel_param *kp) +{ + int val; + LIST_HEAD(release_pending); + struct task_struct* task, *next; + + if (!ai_on) + return 0; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + rcu_read_lock(); + spin_lock(&ht_rtg_lock); + + /* clean up */ + if (perf_ready != val) { + struct task_struct *task, *next; + list_for_each_entry_safe(task, next, &ht_rtg_head, rtg_node) { + ht_logv("release task %s(%d) from rtg list\n", task->comm, task->pid); + list_del_init(&task->rtg_node); + list_add(&task->perf_node, &release_pending); + get_task_struct(task); + } + + spin_lock(&ht_perf_event_lock); + list_for_each_entry_safe(task, next, &ht_perf_event_head, ht_perf_event_node) { + ht_logv("release task %s(%d) from perf list\n", task->comm, task->pid); + list_del_init(&task->ht_perf_event_node); + if (list_empty(&task->perf_node)) { + list_add(&task->perf_node, &release_pending); + get_task_struct(task); + } + } + spin_unlock(&ht_perf_event_lock); + } + perf_ready = val; + spin_unlock(&ht_rtg_lock); + rcu_read_unlock(); + + /* release perf event */ + list_for_each_entry_safe(task, next, &release_pending, perf_node) { + ht_logv("release task %s(%d) from pending list\n", task->comm, task->pid); + ht_perf_event_release(task); + list_del_init(&task->perf_node); + put_task_struct(task); + } + return 0; +} + +static int perf_ready_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", perf_ready); +} + +static struct kernel_param_ops perf_ready_ops = { + .set = perf_ready_store, + .get = perf_ready_show, +}; +module_param_cb(perf_ready, &perf_ready_ops, NULL, 0664); + +static int egl_buf_store(const char *buf, const struct kernel_param *kp) +{ + char _buf[EGL_BUF_MAX] = {0}; + + if (strlen(buf) >= EGL_BUF_MAX) + return 0; + + if (sscanf(buf, "%s\n", _buf) <= 0) + return 0; + + spin_lock(&egl_buf_lock); + memcpy(egl_buf, _buf, EGL_BUF_MAX); + egl_buf[EGL_BUF_MAX - 1] = '\0'; + spin_unlock(&egl_buf_lock); + + return 0; +} + +static int egl_buf_show(char *buf, const struct kernel_param *kp) +{ + char _buf[EGL_BUF_MAX] = {0}; + + spin_lock(&egl_buf_lock); + memcpy(_buf, egl_buf, EGL_BUF_MAX); + _buf[EGL_BUF_MAX - 1] = '\0'; + spin_unlock(&egl_buf_lock); + + return snprintf(buf, PAGE_SIZE, "%s\n", _buf); +} + +static struct kernel_param_ops egl_buf_ops = { + .set = egl_buf_store, + .get = egl_buf_show, +}; +module_param_cb(egl_buf, &egl_buf_ops, NULL, 0664); + +/* fps stable parameter, default -1 max */ +static int efps_max = -1; +static int efps_pid = 0; +static int expectfps = -1; +static int efps_max_store(const char *buf, const struct kernel_param *kp) +{ + int val; + int pid; + int eval; + int ret; + + ret = sscanf(buf, "%d,%d,%d\n", &pid, &val, &eval); + if (ret < 2) + return 0; + + efps_pid = pid; + efps_max = val; + expectfps = (ret == 3) ? eval : -1; + return 0; +} + +static int efps_max_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", efps_pid, efps_max, expectfps); +} + +static struct kernel_param_ops efps_max_ops = { + .set = efps_max_store, + .get = efps_max_show, +}; +module_param_cb(efps_max, &efps_max_ops, NULL, 0664); + +/* fps boost strategy (fbs) */ +static int fbs_pid = -1; +static int fbs_lv = -1; +static int fps_boost_strategy_store(const char *buf, const struct kernel_param *kp) +{ + int pid; + int val; + + if (sscanf(buf, "%d,%d\n", &pid, &val) <= 0) + return 0; + + fbs_pid = pid; + fbs_lv = val; + return 0; +} + +static int fps_boost_strategy_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d,%d\n", fbs_pid, fbs_lv); +} + +static struct kernel_param_ops fps_boost_strategy_ops = { + .set = fps_boost_strategy_store, + .get = fps_boost_strategy_show, +}; +module_param_cb(fps_boost_strategy, &fps_boost_strategy_ops, NULL, 0664); + +/* fps stabilizer update & online config update */ +static DECLARE_WAIT_QUEUE_HEAD(ht_fps_stabilizer_waitq); +static char ht_online_config_buf[PAGE_SIZE]; +static bool ht_disable_fps_stabilizer_bat = true; +module_param_named(disable_fps_stabilizer_bat, ht_disable_fps_stabilizer_bat, bool, 0664); + +static int ht_online_config_update_store(const char *buf, const struct kernel_param *kp) +{ + int ret; + + ret = sscanf(buf, "%s\n", ht_online_config_buf); + ht_logi("fpsst: %d, %s\n", ret, ht_online_config_buf); + wake_up(&ht_fps_stabilizer_waitq); + return 0; +} + +static int ht_online_config_update_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", ht_online_config_buf); +} + +static struct kernel_param_ops ht_online_config_update_ops = { + .set = ht_online_config_update_store, + .get = ht_online_config_update_show, +}; +module_param_cb(ht_online_config_update, &ht_online_config_update_ops, NULL, 0664); + +static inline void __ht_perf_event_enable(struct task_struct *task, int event_id) +{ + if (!(task->perf_activate & (1 << event_id))) { + bool status = ht_perf_event_open(task->pid, event_id); + if (status) { + /* Track tasks which have created perf events */ + spin_lock(&ht_perf_event_lock); + if (list_empty(&task->ht_perf_event_node)) + list_add_tail(&task->ht_perf_event_node, &ht_perf_event_head); + spin_unlock(&ht_perf_event_lock); + } + ht_logv("perf event create %s. task %s %d id %d\n", status? "successful": "failed", task->comm, task->pid, event_id); + } +} + +static int ht_track_events[] = { + //HT_PERF_COUNT_CPU_CYCLES, + HT_PERF_COUNT_INSTRUCTIONS, + //HT_PERF_COUNT_CACHE_MISSES_L1, + HT_PERF_COUNT_CACHE_MISSES_L2, + HT_PERF_COUNT_CACHE_MISSES_L3 +}; + +static inline void ht_perf_event_enable(struct task_struct *task) +{ + int i = 0; + for (i = 0; i < sizeof(ht_track_events)/ sizeof(int); ++i) + __ht_perf_event_enable(task, ht_track_events[i]); +} + +static inline void __ht_perf_event_read(struct task_struct *task, struct ai_thread_parcel* t, int event_id) +{ + u64 val; + if (!(task->perf_activate & (1 << event_id))) + return; + + /* read pmu counter value */ + val = ht_perf_read(task, event_id); + + /* sanity check */ + if (task->perf_counters[event_id] > val) { + ht_logw("counter value warning: task %d %s, id: %d, old: %llu, cur: %llu\n", + task->pid, task->comm, event_id, task->perf_counters[event_id], val); + } + task->perf_counters[event_id] = val; + + switch (event_id) { + case HT_PERF_COUNT_CPU_CYCLES: + t->cycle = val; break; + case HT_PERF_COUNT_INSTRUCTIONS: + t->inst = val; break; + case HT_PERF_COUNT_CACHE_MISSES_L1: + t->cache_miss_l1 = val; break; + case HT_PERF_COUNT_CACHE_MISSES_L2: + t->cache_miss_l2 = val; break; + case HT_PERF_COUNT_CACHE_MISSES_L3: + t->cache_miss_l3 = val; break; + } +} + +static inline void ht_perf_event_read(struct task_struct *task, struct ai_thread_parcel* t) +{ + int i = 0; + for (i = 0; i < sizeof(ht_track_events)/ sizeof(int); ++i) + __ht_perf_event_read(task, t, ht_track_events[i]); +} + +static inline void ht_collect_parcel_data( + struct task_struct *task, + struct ai_parcel* parcel, + int pidx, + bool is_enqueue_task) +{ + unsigned int cur_cpufreq = 0; + u64 delta = 0; + + parcel->thread_amount += 1; + parcel->t[pidx].tid = task->pid; + + if (is_enqueue_task) + ht_perf_event_read(task, &parcel->t[pidx]); + + switch (task->cpu) { + case 0: case 1: case 2: case 3: cur_cpufreq = parcel->cpu_cur_freq_0; break; + case 4: case 5: case 6: cur_cpufreq = parcel->cpu_cur_freq_1; break; + case 7: cur_cpufreq = parcel->cpu_cur_freq_2; break; + } + + /* overflow workaround */ + if (task->total_run_ts >= task->delta_ts && + task->total_run_ts - task->delta_ts < 0xffffffff00000000) + delta = task->total_run_ts - task->delta_ts; + + if (is_enqueue_task) { + parcel->t[pidx].exec_time_ns = cur_cpufreq? (delta * 1000000LL / cur_cpufreq): 0; + parcel->t[pidx].cycle = task->total_run_ts; + } else { + /* compare enqueue ts to check if rtg task presented at previous frame */ + unsigned long long cur_schedstat = task_sched_runtime(task); + parcel->t[pidx].exec_time_ns = (parcel->prev_queued_ts_us == task->prev_ts_us)? + (cur_schedstat - task->prev_schedstat): 0; + task->prev_ts_us = parcel->queued_ts_us; + task->prev_schedstat = cur_schedstat; + } +} + +void ht_collect_perf_data(struct work_struct *work) +{ + struct task_struct *task = container_of(work, struct task_struct, perf_work); + int pidx = 0; + struct task_struct *rtg_task, *next; + + if (unlikely(!task)) + return; + + get_task_struct(task); + + /* step 1. update enqueue timestamp */ + parcel.prev_queued_ts_us = parcel.queued_ts_us; + parcel.queued_ts_us = task->enqueue_ts; + + /* step 2. init need perf hw events */ + ht_perf_event_enable(task); + + /* step 3. collect perf data */ + if (!spin_trylock(&ht_perf_lock)) { + put_task_struct(task); + return; + } + + parcel.pid = task->tgid; + parcel.cpu = task->cpu; + parcel.clus = cpu_to_clus(task->cpu); + parcel.thread_amount = 0; + + /* RTG */ + rcu_read_lock(); + spin_lock(&ht_rtg_lock); + list_for_each_entry_safe(rtg_task, next, &ht_rtg_head, rtg_node) { + /* enqueue task mayibe also a RTG member, skip it! */ + if (rtg_task == task) + continue; + + /* + * evict rotten rtg tasks + * 1. not enter longer than threshold + * 2. util not reach the target + * 3. enter frequency not higher than threshold + */ + if (parcel.queued_ts_us - rtg_task->rtg_ts >= 1000000 /* 1 sec */ || + rtg_task->ravg.demand_scaled < base_util || + rtg_task->rtg_peak < rtg_filter_cnt) { + list_del_init(&rtg_task->rtg_node); + im_unset_flag(rtg_task, IM_ENQUEUE); + continue; + } + + /* create perf event */ + ht_logv( + "rtg_task: comm: %s, pid: %d, tgid: %d, fcnt: %u, fpeak: %u, rtg_cnt: %lu, rtg_peak: %lu, ts: %lld\n", + rtg_task->comm, rtg_task->pid, rtg_task->tgid, + rtg_task->f_cnt, rtg_task->f_peak, + rtg_task->rtg_cnt, rtg_task->rtg_peak, + rtg_task->enqueue_ts); + + /* add to perf list head to create perf event */ + get_task_struct(rtg_task); + list_add_tail(&rtg_task->rtg_perf_node, &ht_rtg_perf_head); + } + spin_unlock(&ht_rtg_lock); + rcu_read_unlock(); + + spin_unlock(&ht_perf_lock); + + /* collect enqueue task perf data */ + ht_collect_parcel_data(task, &parcel, pidx++, true); + + list_for_each_entry_safe(rtg_task, next, &ht_rtg_perf_head, rtg_perf_node) { + /* RTG tasks no need to collect perf data */ + if (rtg_task != task && pidx < AI_THREAD_PARCEL_MAX) + ht_collect_parcel_data(rtg_task, &parcel, pidx++, false); + list_del_init(&rtg_task->rtg_perf_node); + put_task_struct(rtg_task); + } + + /* notify ai_scheduler that data collected */ + wake_up(&ht_perf_waitq); + put_task_struct(task); +} + +static int ht_enable_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + ht_enable = !!val; + + if (ht_enable) { + if (!monitor.buf) { + ht_logi("try to init sample buffer\n"); + monitor.buf = vzalloc(sizeof(struct sample_data)); + if (monitor.buf) + ht_logi("sample buffer inited\n"); + else { + ht_loge("can't init sample buffer, set enable state to 0\n"); + ht_enable = 0; + return 0; + } + } + + ht_logi("wake up monitor thread\n"); + wake_up_process(monitor.thread); + } + + return 0; +} + +static int ht_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", ht_enable); +} + +static struct kernel_param_ops ht_enable_ops = { + .set = ht_enable_store, + .get = ht_enable_show, +}; +module_param_cb(ht_enable, &ht_enable_ops, NULL, 0664); + +static int sample_rate_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + sample_rate = val < MIN_POLLING_VAL? MIN_POLLING_VAL: val; + return 0; +} + +static int sample_rate_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", sample_rate); +} + +static struct kernel_param_ops sample_rate_ops = { + .set = sample_rate_store, + .get = sample_rate_show, +}; +module_param_cb(sample_rate_ms, &sample_rate_ops, NULL, 0664); + +#ifdef CONFIG_CONTROL_CENTER +static inline void do_cpufreq_boost_helper( + unsigned int cpu, + unsigned long val, + unsigned int period_us, + unsigned int *orig_freq, + unsigned int *cur_freq) +{ + struct cpufreq_policy *pol; + struct cc_command cc; + unsigned int cur, orig; + int idx = 0; + int category = 0; + + pol = cpufreq_cpu_get(cpu); + if (unlikely(!pol)) + return; + + idx = cpu_to_clus(cpu); + + orig = cur = pol->cur; + + switch (cpu) { + case CLUS_0_IDX: category = CC_CTL_CATEGORY_CLUS_0_FREQ; break; + case CLUS_1_IDX: category = CC_CTL_CATEGORY_CLUS_1_FREQ; break; + case CLUS_2_IDX: category = CC_CTL_CATEGORY_CLUS_2_FREQ; break; + } + + memset(&cc, 0, sizeof(struct cc_command)); + cc.pid = current->pid; + cc.prio = CC_PRIO_HIGH; + cc.period_us = period_us; + cc.group = CC_CTL_GROUP_GRAPHIC; + cc.category = category; + cc.response = 0; + cc.leader = current->tgid; + cc.bind_leader = true; + cc.status = 0; + cc.type = CC_CTL_TYPE_PERIOD_NONBLOCK; + + if (val == BOOST_LV_0) { + cc.type = CC_CTL_TYPE_RESET_NONBLOCK; + } else { + switch (val) { + case BOOST_LV_1: cur = cur + (cur >> 2); break; // scale 1.25 + case BOOST_LV_2: cur = cur + (cur >> 1); break; // scale 1.5 + case BOOST_LV_3: cur = cur + (cur >> 2) + (cur >> 1); break; // scale 1.75 + case BOOST_LV_4: cur = cur + cur; break; // scale 2.0 + case BOOST_LV_MAX: cur = pol->max; break; // jump to max + } + if (cpufreq_hispeed_enable && cpufreq_hispeed[idx] > cur) { + ht_logv("boost cpu hispeed from %u to %u\n", cur, cpufreq_hispeed[idx]); + cur = cpufreq_hispeed[idx]; + } + + /* cur should not large then pol->max */ + if (cur > pol->max) + cur = pol->max; + cc.params[0] = cur; + cc.params[1] = fps_boost_type? pol->max: cur; + } + cpufreq_cpu_put(pol); + + cc_tsk_process(&cc); + + /* update boosted freq info */ + *(orig_freq + idx) = orig; + *(cur_freq + idx) = cur; +} + +static void do_fps_boost(unsigned int val, unsigned int period_us) +{ + int ais_active = ais_enable; + int i = 0; + int boost_cluster[HT_CLUSTERS] = {0}; + unsigned int cur[HT_CLUSTERS] = {0}, orig[HT_CLUSTERS] = {0}; + struct task_struct *t; + u64 prev_ddr_target = 100; + u64 ddr_target = 100; /* default value */ + struct cc_command cc; + + ht_logv("boost handler: %llu\n", val); + + if (val > 0) { + /* ais version boost */ + if (ais_active) { + /* get cpus which need to be boost */ + rcu_read_lock(); + spin_lock(&ht_rtg_lock); + list_for_each_entry(t, &ht_rtg_head, rtg_node) { + ++boost_cluster[cpu_to_clus(t->cpu)]; + ht_logv("boost RTG target task %d %s on cpu %d\n", t->pid, t->comm, t->cpu); + } + spin_unlock(&ht_rtg_lock); + spin_lock(&ht_perf_event_lock); + list_for_each_entry(t, &ht_perf_event_head, ht_perf_event_node) { + ++boost_cluster[cpu_to_clus(t->cpu)]; + ht_logv("boost enqueue target task %d %s on cpu %d\n", t->pid, t->comm, t->cpu); + } + spin_unlock(&ht_perf_event_lock); + rcu_read_unlock(); + } else { + /* default version */ + for (i = 0; i < FPS_TARGET_NUM; ++i) { + if (boost_target[i] <= 0) + continue; + rcu_read_lock(); + t = find_task_by_vpid(boost_target[i]); + if (t) { + ++boost_cluster[cpu_to_clus(t->cpu)]; + ht_logv("boost default target task %d %s on cpu %d\n", t->pid, t->comm, t->cpu); + } + rcu_read_unlock(); + } + } + + /* boost */ + for (i = 0; i < HT_CLUSTERS; ++i) { + if (boost_cluster[i]) + do_cpufreq_boost_helper(clus_to_cpu(i), val, period_us, orig, cur); + } + } else { + /* no need to boost, reset it */ + do_cpufreq_boost_helper(CLUS_0_IDX, val, period_us, orig, cur); + do_cpufreq_boost_helper(CLUS_1_IDX, val, period_us, orig, cur); + do_cpufreq_boost_helper(CLUS_2_IDX, val, period_us, orig, cur); + } + + /* boost ddrfreq */ + if (ais_active) { + /* setup boost command */ + cc.pid = current->pid; + cc.prio = CC_PRIO_HIGH; + cc.period_us = period_us; + cc.group = CC_CTL_GROUP_GRAPHIC; + cc.category = CC_CTL_CATEGORY_DDR_VOTING_FREQ; + cc.response = 0; + cc.leader = current->tgid; + cc.bind_leader = true; + cc.status = 0; + cc.type = CC_CTL_TYPE_ONESHOT_NONBLOCK; + + if (val > 0) { + clk_get_ddr_freq(&prev_ddr_target); + ddr_target = prev_ddr_target; + ddr_target /= 1000000; + ddr_target *= 2; + ddr_target = ddr_find_target(ddr_target); + prev_ddr_target = ddr_find_target(prev_ddr_target/1000000); + if (ddrfreq_hispeed_enable && ddrfreq_hispeed > ddr_target) { + ht_logv("boost ddr hispeed from %u to %u\n", ddr_target, ddrfreq_hispeed); + ddr_target = ddrfreq_hispeed; + } + cc.params[0] = ddr_target; + cc_tsk_process(&cc); + } else { + cc.type = CC_CTL_TYPE_RESET_NONBLOCK; + cc_tsk_process(&cc); + } + } + + if (val > 0) { + for (i = 0; i < HT_CLUSTERS; ++i) { + if (boost_cluster[i]) { + ht_logv("boost cluster %d from %lu to %lu, ddr from %llu to %llu. ais %d\n", + i, orig[i], cur[i], prev_ddr_target, ddr_target, ais_active); + } + } + } + + if (val > 0) + atomic_inc(&boost_cnt); + +} +#endif + +static int ht_fps_boost_store(const char *buf, const struct kernel_param *kp) +{ +#ifdef CONFIG_CONTROL_CENTER + unsigned int vals[5] = {0}; + int ret; + u64 now; + + if (!fps_boost_force_enable) { + if (!fps_boost_enable) + return 0; + } + + ret = sscanf(buf, "%u,%u,%u,%u,%u\n", &vals[0], &vals[1], &vals[2], &vals[3], &vals[4]); + if (ret != 5) { + /* instead of return -EINVAL, just return 0 to keep fd connection keep working */ + ht_loge("boost params invalid. %s. IGNORED.\n", buf); + return 0; + } + + ht_logv("boost params: %u %u %u %u %u, from %s %d\n", + vals[0], vals[1], vals[2], vals[3], vals[4], current->comm, current->pid); + + /* check under ais is working */ + if (perf_ready > 0) { + /* ignore not tracking task */ + if (vals[1] != perf_ready) { + ht_logv("%u not the current target(%d). IGNORED\n", vals[1], perf_ready); + return 0; + } + + /* ignore boost which is too close to frame enqueue ts */ + if (vals[3] > 0) { + now = ktime_to_us(ktime_get()); + if (now - parcel.queued_ts_us < fps_boost_filter_us) { + ht_logv("boost too close, IGNORED. diff %llu\n", now - parcel.queued_ts_us); + return 0; + } + } + } + + /* update boost target */ + boost_target[0] = vals[1]; + boost_target[1] = vals[2]; + + if (vals[0] != FRAME_BOOST && vals[0] != CPU_BOOST) { + ht_loge("boost type not support\n"); + return 0; + } + + if (vals[4] == 0) { + ht_logw("boost period is 0\n"); + return 0; + } + + do_fps_boost(vals[3], vals[4] * 1000 /* us */); +#endif + return 0; +} + +static struct kernel_param_ops ht_fps_boost_ops = { + .set = ht_fps_boost_store, +}; +module_param_cb(fps_boost, &ht_fps_boost_ops, NULL, 0220); + +inline void tb_parse_req_v2( + unsigned int tb_pol, + unsigned int tb_type, + unsigned int *args, + int size) +{ + struct cc_command cc; + + if (!fps_boost_force_enable) { + if (!fps_boost_enable) + return; + if (!tb_enable) + return; + } + + if (tb_pol == TB_POL_HWUI_BOOST && !ht_hwui_boost_enable) { + ht_logv("turbo boost: hwui boost not enable\n"); + return; + } + + ht_logv("turbo boost params: %u %u %u %u %u %u %u %u, from %s %d\n", + tb_pol, tb_type, args[0], args[1], args[2], args[3], args[4], args[5], + current->comm, current->pid); + + /* first deal with tagging request */ + if (tb_pol == TB_POL_HOOK_API) { + im_set_flag_current(1 << args[0]); + return; + } + + /* init default turbo boost command */ + memset(&cc, 0, sizeof(struct cc_command)); + cc.pid = current->pid; + cc.prio = CC_PRIO_HIGH; + cc.period_us = args[4] * 1000; /* us*/ + cc.group = CC_CTL_GROUP_GRAPHIC; + cc.response = 0; + cc.status = 0; + cc.type = CC_CTL_TYPE_PERIOD_NONBLOCK; + /* compatible with old freq boost */ + cc.params[3] = 1; + cc.category = CC_CTL_CATEGORY_TB_FREQ_BOOST; + + switch (tb_type) { + case TB_TYPE_FREQ_BOOST: + { + int util = args[5]; + int i; + + cc.leader = current->pid; + cc.bind_leader = false; + + if (util > 0) { + /* TODO warp find cpus via tasks */ + int boost_cluster[HT_CLUSTERS] = {0}; + struct task_struct *t = NULL; + + /* hwui part */ + rcu_read_lock(); + for (i = 0; i < 4; ++i) { + /* only take case while pid is given */ + if (args[i]) { + t = find_task_by_vpid(args[i]); + if (t) { + ++boost_cluster[cpu_to_clus(t->cpu)]; + cc_set_cpu_idle_block(t->cpu); + } + } + } + rcu_read_unlock(); + + for (i = 0; i < HT_CLUSTERS; ++i) { + cc.params[0] = + boost_cluster[i] ? util : 0; + if (cc.params[0]) { + switch (i) { + case 0: + cc.category = CC_CTL_CATEGORY_CLUS_0_FREQ; + break; + case 1: + cc.category = CC_CTL_CATEGORY_CLUS_1_FREQ; + break; + case 2: + cc.category = CC_CTL_CATEGORY_CLUS_2_FREQ; + break; + } + cc_tsk_process(&cc); + } + } + + /* update boost statistic */ + atomic_inc(&boost_cnt); + } else { + cc.type = CC_CTL_TYPE_RESET_NONBLOCK; + for (i = 0; i < HT_CLUSTERS; ++i) { + cc.params[0] = 0; + switch (i) { + case 0: + cc.category = CC_CTL_CATEGORY_CLUS_0_FREQ; + break; + case 1: + cc.category = CC_CTL_CATEGORY_CLUS_1_FREQ; + break; + case 2: + cc.category = CC_CTL_CATEGORY_CLUS_2_FREQ; + break; + } + cc_tsk_process(&cc); + } + } + } + return; + case TB_TYPE_PLACE_BOOST: + cc.category = CC_CTL_CATEGORY_TB_PLACE_BOOST; + break; + case TB_TYPE_TAGGING: + return; + case TB_TYPE_CORECTL_BOOST: + cc.category = CC_CTL_CATEGORY_TB_CORECTL_BOOST; + if (args[0]) // core control boost level + cc.params[0] = args[0]; + break; + default: + ht_logw("turbo boost not support this type %u\n", tb_type); + return; + } + + cc_tsk_process(&cc); +} + +inline void tb_parse_req( + unsigned int tb_pol, + unsigned int tb_type, + unsigned int args[4]) +{ + struct cc_command cc; + + ht_logv("turbo boost params: %u %u %u %u %u %u, from %s %d\n", + tb_pol, tb_type, args[0], args[1], args[2], args[3], + current->comm, current->pid); + + /* first deal with tagging request */ + if (tb_pol == TB_POL_HOOK_API) { + im_set_flag_current(1 << args[0]); + return; + } + + /* init default turbo boost command */ + memset(&cc, 0, sizeof(struct cc_command)); + cc.pid = current->pid; + cc.prio = CC_PRIO_HIGH; + cc.period_us = args[2] * 1000; /* us*/ + cc.group = CC_CTL_GROUP_GRAPHIC; + cc.response = 0; + cc.status = 0; + cc.type = CC_CTL_TYPE_PERIOD_NONBLOCK; + cc.params[3] = 1; + + switch (tb_pol) { + case TB_POL_FPS_BOOST: + cc.category = CC_CTL_CATEGORY_TB_FREQ_BOOST; + break; + case TB_POL_DEADLINE_NOTIFY: + cc.category = CC_CTL_CATEGORY_TB_FREQ_BOOST; + break; + case TB_POL_SF_NOTIFY: + cc.category = CC_CTL_CATEGORY_TB_PLACE_BOOST; + break; + default: + ht_logw("turbo boost not support this policy %u\n", tb_pol); + return; + } + + switch (tb_type) { + case TB_TYPE_FREQ_BOOST: + { + int util = args[3]; + int i; + + cc.leader = current->tgid; + cc.bind_leader = true; + + if (util > 0) { + /* TODO warp find cpus via tasks */ + int boost_cluster[HT_CLUSTERS] = {0}; + struct task_struct *t = NULL; + + rcu_read_lock(); + + /* sf part */ + if (args[0]) { + t = find_task_by_vpid(args[0]); + if (t) { + ++boost_cluster[cpu_to_clus(t->cpu)]; + cc_set_cpu_idle_block(t->cpu); + } + } + /* render part */ + if (args[1]) { + t = find_task_by_vpid(args[1]); + if (t) { + ++boost_cluster[cpu_to_clus(t->cpu)]; + cc_check_renice((void *) t); + cc_set_cpu_idle_block(t->cpu); + } + } + rcu_read_unlock(); + + for (i = 0; i < HT_CLUSTERS; ++i) { + cc.params[0] = + boost_cluster[i] ? util : 0; + if (cc.params[0]) { + switch (i) { + case 0: + cc.category = CC_CTL_CATEGORY_CLUS_0_FREQ; + break; + case 1: + cc.category = CC_CTL_CATEGORY_CLUS_1_FREQ; + break; + case 2: + cc.category = CC_CTL_CATEGORY_CLUS_2_FREQ; + break; + } + cc_tsk_process(&cc); + } + } + + /* update boost statistic */ + atomic_inc(&boost_cnt); + } else { + cc.type = CC_CTL_TYPE_RESET_NONBLOCK; + for (i = 0; i < HT_CLUSTERS; ++i) { + cc.params[0] = 0; + switch (i) { + case 0: + cc.category = CC_CTL_CATEGORY_CLUS_0_FREQ; + break; + case 1: + cc.category = CC_CTL_CATEGORY_CLUS_1_FREQ; + break; + case 2: + cc.category = CC_CTL_CATEGORY_CLUS_2_FREQ; + break; + } + cc_tsk_process(&cc); + } + } + } + return; + case TB_TYPE_PLACE_BOOST: + break; + case TB_TYPE_TAGGING: + /* TBD + * dealed at first, but if want to tag tasks + * for a period time, should send command + * to control center + */ + return; + default: + ht_logw("turbo boost not support this type %u\n", tb_type); + return; + } + + cc_tsk_process(&cc); +} + +static int tb_ctl_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int tb_pol = 0; + unsigned int tb_type = 0; + unsigned int args[6] = {0}; + int ret; + + if (!fps_boost_force_enable) { + if (!fps_boost_enable) + return 0; + if (!tb_enable) + return 0; + } + + ret = sscanf(buf, "%u,%u,%u,%u,%u,%u,%u,%u\n", + &tb_pol, &tb_type, + &args[0], &args[1], &args[2], &args[3], &args[4], &args[5]); + if (ret != 6 && ret != 8) { + ht_loge("turbo boost params invalid. %d, %s. IGNORED.\n", ret, buf); + return 0; + } + + //ht_logv("turbo boost params: %u %u %u %u %u %u %u %u, from %s %d\n", + // tb_pol, tb_type, args[0], args[1], args[2], args[3], args[4], args[5], + // current->comm, current->pid); + + if (tb_pol == TB_POL_HWUI_BOOST) { + tb_parse_req_v2(tb_pol, tb_type, args, 6); + } else { + unsigned int v[4] = {0}; + memcpy(v, args, sizeof(unsigned int) * 4); + tb_parse_req(tb_pol, tb_type, v); + } + + return 0; +} + +static struct kernel_param_ops tb_ctl_ops = { + .set = tb_ctl_store, +}; +module_param_cb(tb_ctl, &tb_ctl_ops, NULL, 0220); + +void ht_register_kgsl_pwrctrl(void *pwr) +{ + gpwr = (struct kgsl_pwrctrl*) pwr; + ht_logi("ht register kgsl pwrctrl\n"); +} + +void ht_register_cpu_util(unsigned int cpu, unsigned int first_cpu, + unsigned long *util, unsigned long *hi_util) +{ + struct ht_util_pol *hus; + + switch (first_cpu) { +#ifndef CONFIG_ARCH_LITO + case 0: case 1: case 2: case 3: hus = &ht_utils[0]; break; + case 4: case 5: case 6: hus = &ht_utils[1]; break; +#else + case 0: case 1: case 2: case 3: case 4: case 5: hus = &ht_utils[0]; break; + case 6: hus = &ht_utils[1]; break; +#endif + case 7: hus = &ht_utils[2]; break; + default: + /* should not happen */ + ht_logw("wrnog first cpu utils idx %d\n", first_cpu); + return; + } + +#ifndef CONFIG_ARCH_LITO + if (cpu == CLUS_2_IDX) +#else + if (cpu == CLUS_1_IDX || cpu == CLUS_2_IDX) +#endif + cpu = 0; + else + cpu %= HT_CPUS_PER_CLUS; + hus->utils[cpu] = util; + hus->hi_util = hi_util; + ht_logv("ht register cpu %d util, first cpu %d\n", cpu, first_cpu); +} + +/* monitor hw event */ +void ht_update_hw_events(u64 inst, u64 miss, u64 cycle) +{ + unsigned int d_mask = disable_mask; + static int cur_idx = 0; + + if (!ht_enable) + return; + + if (ht_is_all_disabled(d_mask)) + return; + + if (!monitor.buf) + return; + + if (cur_idx != sidx) { + cur_idx = sidx; + monitor.buf->data[cur_idx][HT_HW_INSTRUCTION] = 0; + monitor.buf->data[cur_idx][HT_HW_CACHE_MISS] = 0; + monitor.buf->data[cur_idx][HT_HW_CYCLE] = 0; + } + + monitor.buf->data[cur_idx][HT_HW_INSTRUCTION] += inst; + monitor.buf->data[cur_idx][HT_HW_CACHE_MISS] += miss; + monitor.buf->data[cur_idx][HT_HW_CYCLE] += cycle; +} + +void ht_register_thermal_zone_device(struct thermal_zone_device *tzd) +{ + int idx; + + /* tzd is guaranteed has value */ + ht_logi("tzd: %s id: %d\n", tzd->type, tzd->id); + idx = ht_mapping_tags(tzd->type); + + if (idx > HT_THERM_2) + return; + if (ht_tzd_idx <= HT_THERM_2 && !monitor.tzd[idx]) { + ++ht_tzd_idx; + monitor.tzd[idx] = tzd; + } +} + +int ht_pcc_alwayson(void) +{ + return pccore_always_on; +} + +void ht_register_power_supply(struct power_supply *psy) +{ + if (!psy) + return; + + ht_logi("ht power supply list %s\n", psy->desc->name); + if (!strcmp(psy->desc->name, "battery")) { + monitor.psy = psy; + ht_logi("ht power supply registed %s\n", psy->desc->name); + } +} + +static int ht_fps_data_sync_store(const char *buf, const struct kernel_param *kp) +{ + u64 fps_data[FPS_COLS] = {0}; + static long long fps_align = 0; + static int cur_idx = 0; + //size_t len; + int ret; + + if (strlen(buf) >= FPS_DATA_BUF_SIZE) + return 0; + + ret = sscanf(buf, "%llu,%llu,%llu,%llu,%llu,%lld\n", + &fps_data[0], &fps_data[1], &fps_data[2], &fps_data[3], + &fps_data[4], &fps_align); + if (ret != 6) { + /* instead of return -EINVAL, just return 0 to keep fd connection keep working */ + ht_loge("fps data params invalid. ret %d, %s. IGNORED.\n", ret, buf); + return 0; + } + game_fps_data_.enqueue_time = fps_align; + game_fps_data_.fps = fps_data[3]; + + ht_logv("fps data params: %llu %llu %llu %llu %llu %lld\n", + fps_data[0], fps_data[1], fps_data[2], fps_data[3], fps_data[4], fps_align); + + /* + * cached_fps should be always updated + * rounding up + */ + //atomic_set(&cached_fps[0], (fps_data[0] + 5)/ 10); + // use vsync duration replace old fps data + atomic_set(&cached_fps[0], (fps_data[7])); + atomic_set(&cached_fps[1], (fps_data[1] + 5)/ 10); + + atomic64_set(&fps_align_ns, fps_align); + + // ignore pass layer name to aischeduler + /* + memset(cached_layer_name, 0, FPS_CACHE_LAYER_LEN); + len = strlen(fps_layer_name); + if (len < FPS_CACHE_LAYER_LEN) + memcpy(cached_layer_name, fps_layer_name, len); + else { + // first 32 bytes + last 31 bytes + \0 + memcpy(cached_layer_name + (FPS_CACHE_LAYER_LEN/2), fps_layer_name + len - (FPS_CACHE_LAYER_LEN/2) + 1, FPS_CACHE_LAYER_LEN/2); + memcpy(cached_layer_name, fps_layer_name, (FPS_CACHE_LAYER_LEN/2)); + } + ht_logv("cached: fps: %u, efps: %u, layer: %s\n", atomic_read(&cached_fps[0]), atomic_read(&cached_fps[1]), cached_layer_name); + */ + + if (!monitor.buf) + return 0; + + if (cur_idx != sidx) { + /* new frame data */ + cur_idx = sidx; + monitor.buf->layer[cur_idx][0] = '\0'; + monitor.buf->process[cur_idx][0] = '\0'; + monitor.buf->data[cur_idx][HT_FPS_1] = 0; + monitor.buf->data[cur_idx][HT_FPS_2] = 0; + monitor.buf->data[cur_idx][HT_FPS_3] = 0; + monitor.buf->data[cur_idx][HT_FPS_4] = 0; + monitor.buf->data[cur_idx][HT_FPS_5] = 0; + monitor.buf->data[cur_idx][HT_FPS_6] = 0; + monitor.buf->data[cur_idx][HT_FPS_7] = 0; + monitor.buf->data[cur_idx][HT_FPS_8] = 0; + monitor.buf->data[cur_idx][HT_FPS_MISS_LAYER] = 0; + } else if (monitor.buf->layer[cur_idx]) { + monitor.buf->data[cur_idx][HT_FPS_MISS_LAYER] += 1; + return 0; + } + + monitor.buf->data[cur_idx][HT_FPS_1] = fps_data[0]; //actualFps + monitor.buf->data[cur_idx][HT_FPS_2] = fps_data[1]; //predictFps + monitor.buf->data[cur_idx][HT_FPS_3] = fps_data[2]; //vSync + monitor.buf->data[cur_idx][HT_FPS_4] = fps_data[3]; //fps + monitor.buf->data[cur_idx][HT_FPS_PID] = fps_data[4]; //pid + monitor.buf->data[cur_idx][HT_FPS_ALIGN]= fps_align; //fps align ts + + return 0; +} + +static struct kernel_param_ops ht_fps_data_sync_ops = { + .set = ht_fps_data_sync_store, +}; +module_param_cb(fps_data_sync, &ht_fps_data_sync_ops, NULL, 0220); + +/* poll for fps data synchronization */ +static unsigned int ht_ctl_poll(struct file *fp, poll_table *wait) +{ + poll_wait(fp, &ht_poll_waitq, wait); + return POLLIN; +} + +static void ht_collect_system_data(struct ai_parcel *p) +{ + struct cpufreq_policy *pols[HT_CLUSTERS]; + union power_supply_propval prop = {0, }; + int i, ret; + + pols[0] = cpufreq_cpu_get(CLUS_0_IDX); + pols[1] = cpufreq_cpu_get(CLUS_1_IDX); + pols[2] = cpufreq_cpu_get(CLUS_2_IDX); + + p->fps_align_ns = atomic64_read(&fps_align_ns); + + p->fps = atomic_read(&cached_fps[0]); + p->efps = atomic_read(&cached_fps[1]); + //memcpy(p->layer, cached_layer_name, FPS_CACHE_LAYER_LEN); + p->cpu_cur_freq_0 = pols[0]? pols[0]->cur: 0; + p->cpu_cur_freq_1 = pols[1]? pols[1]->cur: 0; + p->cpu_cur_freq_2 = pols[2]? pols[2]->cur: 0; + p->cpu_orig_freq_0 = pols[0]? pols[0]->req_freq: 0; + p->cpu_orig_freq_1 = pols[1]? pols[1]->req_freq: 0; + p->cpu_orig_freq_2 = pols[2]? pols[2]->req_freq: 0; + p->cpu_cc_min_freq_1 = pols[1] ? pols[1]->cc_min : 0; + p->cpu_cc_max_freq_1 = pols[1] ? pols[1]->cc_max : 0; + p->cpu_orig_min_freq_1 = pols[1] ? pols[1]->min : 0; + p->cpu_orig_max_freq_1 = pols[1] ? pols[1]->max : 0; + p->gpu_freq = gpwr? (int) kgsl_pwrctrl_active_freq(gpwr): 0; + ht_query_ddrfreq(&p->ddr_freq); + p->ddr_voting = cc_get_expect_ddrfreq(); + if (bat_query) { + ht_update_battery(); + ret = power_supply_get_property(monitor.psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); + p->volt_now = ret >= 0? prop.intval: 0; + ret = power_supply_get_property(monitor.psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + p->curr_now = ret >= 0? prop.intval: 0; + } + /* utils */ + p->utils[0] = ht_utils[0].utils[0]? (u64) *(ht_utils[0].utils[0]): 0; + p->utils[1] = ht_utils[0].utils[1]? (u64) *(ht_utils[0].utils[1]): 0; + p->utils[2] = ht_utils[0].utils[2]? (u64) *(ht_utils[0].utils[2]): 0; + p->utils[3] = ht_utils[0].utils[3]? (u64) *(ht_utils[0].utils[3]): 0; +#ifndef CONFIG_ARCH_LITO + p->utils[4] = ht_utils[1].utils[0]? (u64) *(ht_utils[1].utils[0]): 0; + p->utils[5] = ht_utils[1].utils[1]? (u64) *(ht_utils[1].utils[1]): 0; + p->utils[6] = ht_utils[1].utils[2]? (u64) *(ht_utils[1].utils[2]): 0; +#else + p->utils[4] = ht_utils[0].utils[4]? (u64) *(ht_utils[0].utils[4]): 0; + p->utils[5] = ht_utils[0].utils[5]? (u64) *(ht_utils[0].utils[5]): 0; + p->utils[6] = ht_utils[1].utils[0]? (u64) *(ht_utils[1].utils[0]): 0; +#endif + p->utils[7] = ht_utils[2].utils[0]? (u64) *(ht_utils[2].utils[0]): 0; + + for (i = 0; i < HT_CLUSTERS; ++i) + if (pols[i]) cpufreq_cpu_put(pols[i]); + +#ifdef CONFIG_CONTROL_CENTER + /* collect boost ts information */ + cc_boost_ts_collect(p->cbt); +#endif + + p->boost_cnt = atomic_read(&boost_cnt); + p->notify_start_ts_us = p->queued_ts_us; + p->notify_end_ts_us = ktime_to_us(ktime_get()); + p->skin_temp = ht_get_temp_delay(HT_THERM_0); +} + +static inline void ht_cpuload_helper(int clus, int cpus, struct cpuload_info *cli) +{ + int i, util; + long long iowait; + for (i = 0; i < cpus; ++i) { + /* not ready */ + if (!ht_utils[clus].utils[i]) + return; + + util = (u32) *(ht_utils[clus].utils[i]); + if (util >= cli->cmax) + cli->cmax = util; + if (util <= cli->cmin) + cli->cmin = util; + cli->sum += util; + + iowait = ht_delta_iowait[i]; + if (iowait >= cli->iowait_max) + cli->iowait_max = iowait; + if (iowait <= cli->iowait_min) + cli->iowait_min = iowait; + cli->iowait_sum += iowait; + + ++(cli->cnt); + } +} + +static inline void ht_dump_parcel(struct ai_parcel *p) +{ + ht_logv("%s: dump pid %u fps %u volt %llu current %llu skin %lu\n", + __func__, p->pid, p->fps, p->volt_now, p->curr_now, p->skin_temp); +} + +static long ht_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long __user arg) +{ + if (_IOC_TYPE(cmd) != HT_IOC_MAGIC) return 0; + if (_IOC_NR(cmd) > HT_IOC_MAX) return 0; + + ht_logv("%s: cmd: %s %x, arg: %lu\n", __func__, ht_ioctl_str(cmd), cmd, arg); + switch (cmd) { + case HT_IOC_COLLECT: + { + DEFINE_WAIT(wait); + prepare_to_wait(&ht_perf_waitq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(&ht_perf_waitq, &wait); + ht_collect_system_data(&parcel); + ht_dump_parcel(&parcel); + if (copy_to_user((struct ai_parcel __user *) arg, &parcel, sizeof(parcel))) + return 0; + break; + } + case HT_IOC_SCHEDSTAT: + { + struct task_struct *task; + u64 exec_ns = 0; + u64 pid; + if (copy_from_user(&pid, (u64 *) arg, sizeof(u64))) + return 0; + + rcu_read_lock(); + task = find_task_by_vpid(pid); + if (task) { + get_task_struct(task); + rcu_read_unlock(); + exec_ns = task_sched_runtime(task); + put_task_struct(task); + if (exec_ns == 0) + ht_logw("schedstat is 0\n"); + } else { + rcu_read_unlock(); + ht_logw("can't find task for schedstat\n"); + } + if (copy_to_user((u64 *) arg, &exec_ns, sizeof(u64))) + return 0; + break; + } + case HT_IOC_CPU_LOAD: + { + struct task_struct *task; + struct cpuload_info cli = { + 0, INT_MAX, INT_MIN, 0, LONG_MAX, LONG_MIN, 0 + }; + struct cpuload cl; + int clus = 0; + int cpu; + int i; + + if (!cpuload_query) { + ht_logv("cpuload query not enabled\n"); + return 0; + } + + if (copy_from_user(&cl, (struct cpuload *) arg, sizeof(struct cpuload))) + return 0; + + ht_logv("pid %u tid %u\n", cl.pid, cl.tid); + rcu_read_lock(); + task = find_task_by_vpid(cl.pid); + if (task) + clus |= 1 << cpu_to_clus(task->cpu); + task = find_task_by_vpid(cl.tid); + if (task) + clus |= 1 << cpu_to_clus(task->cpu); + rcu_read_unlock(); + + /* update iowait info */ + for_each_online_cpu(cpu) { + long long iowait = ht_get_iowait_time(cpu); + ht_delta_iowait[cpu] = iowait - ht_iowait[cpu]; + ht_iowait[cpu] = iowait; + } + + for (i = 0; i < 3; ++i) { + if (clus & (1 << i)) { + switch (i) { + case 0: +#ifndef CONFIG_ARCH_LITO + ht_cpuload_helper(0, 4, &cli); +#else + ht_cpuload_helper(0, 6, &cli); +#endif + break; + case 1: +#ifndef CONFIG_ARCH_LITO + ht_cpuload_helper(1, 3, &cli); +#else + ht_cpuload_helper(1, 1, &cli); +#endif + break; + case 2: + ht_cpuload_helper(2, 1, &cli); + break; + } + } + } + cl.min = cli.cmin; + cl.max = cli.cmax; + cl.sum = cli.sum; + cl.avg = cli.cnt? cli.sum/cli.cnt: 0; + cl.iowait_min = cli.iowait_min; + cl.iowait_max = cli.iowait_max; + cl.iowait_sum = cli.iowait_sum; + cl.iowait_avg = cli.cnt? cli.iowait_sum/cli.cnt: 0; + + ht_logv("cpuload min %d max %d sum %d avg %d, iowait min %lld max %lld sum %lld avg %llu\n", + cl.min, cl.max, cl.sum, cl.avg, cl.iowait_min, cl.iowait_max, cl.iowait_sum, cl.iowait_avg); + if (copy_to_user((struct cpuload *) arg, &cl, sizeof(struct cpuload))) + return 0; + break; + } + case HT_IOC_FPS_STABILIZER_UPDATE: + { + DEFINE_WAIT(wait); + prepare_to_wait(&ht_fps_stabilizer_waitq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(&ht_fps_stabilizer_waitq, &wait); + + ht_logi("fpsst: %s\n", ht_online_config_buf); + + if (ht_online_config_buf[0] == '\0') { + // force invalid config + char empty[] = "{}"; + copy_to_user((struct ht_fps_stabilizer_buf __user *) arg, &empty, strlen(empty)); + } else { + copy_to_user((struct ht_fps_stabilizer_buf __user *) arg, &ht_online_config_buf, PAGE_SIZE); + } + break; + } + case HT_IOC_FPS_PARTIAL_SYS_INFO: + { + struct ht_partial_sys_info data; + union power_supply_propval prop = {0, }; + int ret; + + if (ht_disable_fps_stabilizer_bat) { + data.volt = data.curr = 0; + } else { + ht_update_battery(); + ret = power_supply_get_property(monitor.psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); + data.volt = ret >= 0? prop.intval: 0; + ret = power_supply_get_property(monitor.psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + data.curr = ret >= 0? prop.intval: 0; + } + + // related to cpu cluster configuration + // clus 0 + data.utils[0] = ht_utils[0].utils[0]? (u64) *(ht_utils[0].utils[0]): 0; + data.utils[1] = ht_utils[0].utils[1]? (u64) *(ht_utils[0].utils[1]): 0; + data.utils[2] = ht_utils[0].utils[2]? (u64) *(ht_utils[0].utils[2]): 0; + data.utils[3] = ht_utils[0].utils[3]? (u64) *(ht_utils[0].utils[3]): 0; + // clus 1 + data.utils[4] = ht_utils[1].utils[0]? (u64) *(ht_utils[1].utils[0]): 0; + data.utils[5] = ht_utils[1].utils[1]? (u64) *(ht_utils[1].utils[1]): 0; + data.utils[6] = ht_utils[1].utils[2]? (u64) *(ht_utils[1].utils[2]): 0; + // clus 2 + data.utils[7] = ht_utils[2].utils[0]? (u64) *(ht_utils[2].utils[0]): 0; + + // pick highest temp + data.skin_temp = max(ht_get_temp_delay(HT_THERM_0), + max(ht_get_temp_delay(HT_THERM_1), + ht_get_temp_delay(HT_THERM_2))); + + if (copy_to_user((struct ht_partial_sys_info __user *) arg, &data, sizeof(struct ht_partial_sys_info))) + return 0; + break; + } + default: + { + // handle unsupported ioctl cmd + return -1; + } + } + return 0; +} + +static const struct file_operations ht_ctl_fops = { + .owner = THIS_MODULE, + .poll = ht_ctl_poll, + .unlocked_ioctl = ht_ctl_ioctl, + .compat_ioctl = ht_ctl_ioctl, +}; + +static void ht_collect_data(void) +{ + union power_supply_propval prop = {0, }; + struct cpufreq_policy *pol; + int idx; + int ret; + int num = 0; + + if (unlikely(!ht_enable)) + return; + + if (unlikely(!monitor.buf)) + return; + + if (ht_is_all_disabled(disable_mask)) + return; + + idx = ht_next_sample_idx(); + + /* set timestamp */ + monitor.buf->data[idx][HT_TS] = ktime_to_ms(ktime_get()); + + /* wake up fps data sync polling */ + wake_up_interruptible(&ht_poll_waitq); + + /* temperature part */ + monitor.buf->data[idx][HT_CPU_0] = ht_get_temp(HT_CPU_0); + monitor.buf->data[idx][HT_CPU_1] = ht_get_temp(HT_CPU_1); + monitor.buf->data[idx][HT_CPU_2] = ht_get_temp(HT_CPU_2); + monitor.buf->data[idx][HT_CPU_3] = ht_get_temp(HT_CPU_3); + monitor.buf->data[idx][HT_CPU_4_0] = ht_get_temp(HT_CPU_4_0); + monitor.buf->data[idx][HT_CPU_4_1] = ht_get_temp(HT_CPU_4_1); + monitor.buf->data[idx][HT_CPU_5_0] = ht_get_temp(HT_CPU_5_0); + monitor.buf->data[idx][HT_CPU_5_1] = ht_get_temp(HT_CPU_5_1); + monitor.buf->data[idx][HT_CPU_6_0] = ht_get_temp(HT_CPU_6_0); + monitor.buf->data[idx][HT_CPU_6_1] = ht_get_temp(HT_CPU_6_1); + monitor.buf->data[idx][HT_CPU_7_0] = ht_get_temp(HT_CPU_7_0); + monitor.buf->data[idx][HT_CPU_7_1] = ht_get_temp(HT_CPU_7_1); + monitor.buf->data[idx][HT_THERM_0] = ht_get_temp(HT_THERM_0); + monitor.buf->data[idx][HT_THERM_1] = ht_get_temp(HT_THERM_1); + monitor.buf->data[idx][HT_THERM_2] = ht_get_temp(HT_THERM_2); + + /* cpu part */ + pol = cpufreq_cpu_get(CLUS_0_IDX); + if (likely(pol)) { + monitor.buf->data[idx][HT_CLUS_FREQ_0_MIN] = pol->min; + monitor.buf->data[idx][HT_CLUS_FREQ_0_CUR] = pol->cur; + monitor.buf->data[idx][HT_CLUS_FREQ_0_MAX] = pol->max; + monitor.buf->data[idx][HT_ISO_0] = ht_iso_count(pol->related_cpus); + cpufreq_cpu_put(pol); + } + pol = cpufreq_cpu_get(CLUS_1_IDX); + if (likely(pol)) { + monitor.buf->data[idx][HT_CLUS_FREQ_1_MIN] = pol->min; + monitor.buf->data[idx][HT_CLUS_FREQ_1_CUR] = pol->cur; + monitor.buf->data[idx][HT_CLUS_FREQ_1_MAX] = pol->max; + monitor.buf->data[idx][HT_ISO_1] = ht_iso_count(pol->related_cpus); + cpufreq_cpu_put(pol); + } + pol = cpufreq_cpu_get(CLUS_2_IDX); + if (likely(pol)) { + monitor.buf->data[idx][HT_CLUS_FREQ_2_MIN] = pol->min; + monitor.buf->data[idx][HT_CLUS_FREQ_2_CUR] = pol->cur; + monitor.buf->data[idx][HT_CLUS_FREQ_2_MAX] = pol->max; + monitor.buf->data[idx][HT_ISO_2] = ht_iso_count(pol->related_cpus); + cpufreq_cpu_put(pol); + } + pol = NULL; + + /* gpu part */ + monitor.buf->data[idx][HT_GPU_FREQ] = gpwr? (int) kgsl_pwrctrl_active_freq(gpwr): 0; + + /* util part */ + monitor.buf->data[idx][HT_UTIL_0] = ht_utils[0].utils[0]? (u64) *(ht_utils[0].utils[0]): 0; + monitor.buf->data[idx][HT_UTIL_1] = ht_utils[0].utils[1]? (u64) *(ht_utils[0].utils[1]): 0; + monitor.buf->data[idx][HT_UTIL_2] = ht_utils[0].utils[2]? (u64) *(ht_utils[0].utils[2]): 0; + monitor.buf->data[idx][HT_UTIL_3] = ht_utils[0].utils[3]? (u64) *(ht_utils[0].utils[3]): 0; +#ifndef CONFIG_ARCH_LITO + monitor.buf->data[idx][HT_UTIL_4] = ht_utils[1].utils[0]? (u64) *(ht_utils[1].utils[0]): 0; + monitor.buf->data[idx][HT_UTIL_5] = ht_utils[1].utils[1]? (u64) *(ht_utils[1].utils[1]): 0; + monitor.buf->data[idx][HT_UTIL_6] = ht_utils[1].utils[2]? (u64) *(ht_utils[1].utils[2]): 0; +#else + monitor.buf->data[idx][HT_UTIL_4] = ht_utils[0].utils[4]? (u64) *(ht_utils[0].utils[4]): 0; + monitor.buf->data[idx][HT_UTIL_5] = ht_utils[0].utils[5]? (u64) *(ht_utils[0].utils[5]): 0; + monitor.buf->data[idx][HT_UTIL_6] = ht_utils[1].utils[0]? (u64) *(ht_utils[1].utils[0]): 0; +#endif + monitor.buf->data[idx][HT_UTIL_7] = ht_utils[2].utils[0]? (u64) *(ht_utils[2].utils[0]): 0; + + /* battery part */ + ht_update_battery(); + ret = power_supply_get_property(monitor.psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); + monitor.buf->data[idx][HT_BAT_VOLT_NOW] = ret >= 0? prop.intval: 0; + ret = power_supply_get_property(monitor.psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + monitor.buf->data[idx][HT_BAT_CURR_NOW] = ret >= 0? prop.intval: 0; + + /* render & rtg util part*/ + monitor.buf->data[idx][HT_RENDER_PID] = RenPid; + monitor.buf->data[idx][HT_RENDER_UTIL] = get_util(true, &num); + monitor.buf->data[idx][HT_RTG_UTIL_SUM] = get_util(false, &num); + monitor.buf->data[idx][HT_NT_RTG] = num; + + ++record_cnt; + record_cnt = min(record_cnt, (unsigned int) MAX_REPORT_PERIOD); +} + +/* main thread for monitor */ +static int ht_monitor(void *arg) +{ + while (likely(keep_alive)) { + if (!ht_enable) { + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + continue; + } + + if (likely(!pm_freezing)) + ht_collect_data(); + + msleep(sample_rate); + } + return 0; +} + +static int ht_registered_show(char* buf, const struct kernel_param *kp) +{ + int i, offset = 0; + struct thermal_zone_device* tzd; + + if (ht_tzd_idx == 0) + return 0; + + for (i = 0; i <= HT_THERM_2; ++i) { + tzd = monitor.tzd[i]; + if (tzd) + offset += snprintf(buf + offset, PAGE_SIZE - offset, "%s, id: %d\n", tzd->type, tzd->id); + else if (i < HT_CPU_0) + offset += snprintf(buf + offset, PAGE_SIZE - offset, "%s\n", ht_monitor_case[i]); + } + + for (i = HT_UTIL_0; i < HT_MONITOR_SIZE; ++i) + offset += snprintf(buf + offset, PAGE_SIZE - offset, "%s\n", ht_monitor_case[i]); + + return offset; +} + +static struct kernel_param_ops ht_registed_ops = { + .get = ht_registered_show, +}; +module_param_cb(ht_registed, &ht_registed_ops, NULL, 0444); + +static int ht_reset_store(const char *buf, const struct kernel_param *kp) +{ + int val; + if (sscanf(buf, "%d\n", &val) != 1) + return -EINVAL; + + if (val != 1) + return 0; + + if (monitor.buf) + memset(monitor.buf, 0, sizeof(struct sample_data)); + + record_cnt = 0; + RenPid = -1; + ht_logi("sample data reset\n"); + + return 0; +} + +static struct kernel_param_ops ht_reset_ops = { + .set = ht_reset_store, +}; +module_param_cb(reset, &ht_reset_ops, NULL, 0664); + +static int ht_report_proc_show(struct seq_file *m, void *v) +{ + unsigned int i, cnt = 0, j; + unsigned long f_mask = filter_mask, d_mask = disable_mask; + unsigned int report_cnt = 0; + + if (!monitor.buf) { + seq_printf(m, "sample buffer not inited\n"); + return 0; + } + + report_cnt = record_cnt; + + /* cap max */ + report_cnt = min(report_cnt, (unsigned int) MAX_REPORT_PERIOD); + + if (!report_cnt) { + seq_printf(m, "no data recorded\n"); + return 0; + } + + if (ht_is_all_filtered(f_mask) || ht_is_all_disabled(d_mask)) { + seq_printf(m, "all data be masked out\n"); + return 0; + } + + /* mark */ + for (i = 0; i < ht_tzd_idx; ++i) { + if (f_mask & (1 << i) || d_mask & (1 << i)) + continue; + if (monitor.tzd[i]) + seq_printf(m, "%s,", monitor.tzd[i]->type); + else if (i < HT_CPU_0) + seq_printf(m, "%s,", ht_monitor_case[i]); + } + + /* TODO should refine this part */ + for (i = HT_UTIL_0; i < HT_MONITOR_SIZE; ++i) { + if (f_mask & (1 << i) || d_mask & (1 << i)) + continue; + seq_printf(m, "%s,", ht_monitor_case[i]); + } + seq_printf(m, "\n"); + + /* fill gap */ + i = sidx + MAX_REPORT_PERIOD - report_cnt + 1; + + /* value */ + for (; cnt < report_cnt; ++cnt, ++i) { + i %= MAX_REPORT_PERIOD; + + for (j = 0; j < HT_MONITOR_SIZE; ++j) { + if (f_mask & (1 << j) || d_mask & (1 << j)) + continue; + if (j == HT_FPS_LAYER) { + seq_printf(m, "%s,", monitor.buf->layer[i]); + continue; + } + if (j == HT_FPS_PROCESS) { + seq_printf(m, "%s,", monitor.buf->process[i]); + continue; + } + seq_printf(m, "%llu,", monitor.buf->data[i][j]/ (report_div[j]? report_div[j]: 1)); + } + seq_printf(m, "\n"); + } + + return 0; +} + +static int ht_report_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ht_report_proc_show, NULL); +} + +static const struct file_operations ht_report_proc_fops = { + .open= ht_report_proc_open, + .read= seq_read, + .llseek= seq_lseek, + .release= single_release, +}; + +int ht_group_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, group_show, NULL); +} + +static const struct file_operations ht_group_proc_fops = { + .open = ht_group_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int fps_sync_init(void) +{ + int rc; + struct device *class_dev; + + rc = alloc_chrdev_region(&ht_ctl_dev, 0, 1, HT_CTL_NODE); + if (rc < 0) { + ht_loge("alloc_chrdev_region failed %d\n", rc); + return 0; + } + + driver_class = class_create(THIS_MODULE, HT_CTL_NODE); + if (IS_ERR(driver_class)) { + rc = -ENOMEM; + ht_loge("class_create failed %d\n", rc); + goto exit_unreg_chrdev_region; + } + class_dev = device_create(driver_class, NULL, ht_ctl_dev, NULL, HT_CTL_NODE); + if (IS_ERR(class_dev)) { + ht_loge("class_device_create failed %d\n", rc); + rc = -ENOMEM; + goto exit_destroy_class; + } + cdev_init(&cdev, &ht_ctl_fops); + cdev.owner = THIS_MODULE; + rc = cdev_add(&cdev, MKDEV(MAJOR(ht_ctl_dev), 0), 1); + if (rc < 0) { + ht_loge("cdev_add failed %d\n", rc); + goto exit_destroy_device; + } + ht_logi("fps data sync ready\n"); + return 0; +exit_destroy_device: + device_destroy(driver_class, ht_ctl_dev); +exit_destroy_class: + class_destroy(driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(ht_ctl_dev, 1); + return 0; +} + +void ht_update_enqueue_ts(struct task_struct *task) +{ + u64 now = 0; + spin_lock(&task->rtg_lock); + asm volatile("isb;mrs %0, PMCCNTR_EL0" : "=r"(now)); + + if (task->run_ts == task->end_ts) { + /* task not finished yet */ + task->acc_run_ts += now - task->run_ts; + } + task->delta_ts = task->total_run_ts; + task->total_run_ts += task->acc_run_ts; + task->acc_run_ts = 0; + task->run_ts = task->end_ts = now; + spin_unlock(&task->rtg_lock); +} + +void ht_perf_notify(void) +{ + u64 time; + + /* treat any notify task as UX */ + im_set_flag_current(IM_ENQUEUE); + render_pid = current->pid; + + if (perf_ready <= 0) + return; + + if (perf_ready != current->tgid) { + current->enqueue_ts = 0; + ht_logv("notify: task %s %d ignored due to not target process\n", current->comm, current->pid); + return; + } + + /* if thread been tracked by perf, skip it */ + if (current->perf_regular_activate) { + ht_logv("notify: task %s %d ignored due to perf already activated\n", current->comm, current->pid); + return; + } + + ht_logv("notify: task: comm: %s, pid: %d, tgid: %d, freq: %u, peak: %u, leader: %s %d %d, ts: %lld\n", + current->comm, current->pid, current->tgid, current->f_cnt, current->f_peak, + current->group_leader->comm, current->group_leader->pid, current->group_leader->tgid, + current->enqueue_ts); + + RenPid = current->pid; + + /* fps info update */ + wake_up_interruptible(&ht_poll_waitq); + + /* get timestamp */ + time = ktime_to_us(ktime_get()); + ht_update_enqueue_ts(current); + current->enqueue_ts = time; + + /* may need to handle overflow */ + if (time < current->f_ts || + time - current->f_ts >= 1000000 /* 1 sec */) { + current->f_peak = current->f_cnt; + current->f_cnt = 0; + current->f_ts = time; + } + ++current->f_cnt; + + if (likely(ht_perf_workq)) { + queue_work(ht_perf_workq, ¤t->perf_work); + } +} + +void ht_perf_event_init(struct task_struct *task) +{ + int i; + + INIT_LIST_HEAD(&task->ht_perf_event_node); + INIT_LIST_HEAD(&task->perf_node); + INIT_WORK(&task->perf_work, ht_collect_perf_data); + for (i = 0; i < HT_PERF_COUNT_MAX; ++i) { + task->perf_events[i] = NULL; + task->perf_counters[i] = 0; + } + task->perf_activate = 0; + task->perf_regular_activate = 0; + task->enqueue_ts = 0; + task->run_ts = 0; + task->end_ts = 0; + task->acc_run_ts = 0; + task->delta_ts = 0; + task->total_run_ts = 0; +} + +void ht_perf_event_release(struct task_struct *task) +{ + int i; + + mutex_lock(&task->perf_event_mutex); + for (i = 0; i < HT_PERF_COUNT_MAX; ++i) { + if (task->perf_events[i]) { + perf_event_disable(task->perf_events[i]); + perf_event_release_kernel(task->perf_events[i]); + task->perf_events[i] = NULL; + task->perf_activate &= ~(1 << i); + ht_logv("perf event released. task %s %d id %d\n", task->comm, task->pid, i); + } + } + mutex_unlock(&task->perf_event_mutex); + + spin_lock(&ht_perf_event_lock); + if (!list_empty(&task->ht_perf_event_node)) + list_del_init(&task->ht_perf_event_node); + spin_unlock(&ht_perf_event_lock); +} + +void ht_sched_switch_update(struct task_struct *prev, struct task_struct *next) +{ + if (perf_ready <= 0) + return; + + if (prev->tgid != perf_ready && next->tgid != perf_ready) + return; + + if (!prev->enqueue_ts && !next->enqueue_ts) + return; + + if (prev->enqueue_ts) + ht_sched_update(prev, false); + if (next->enqueue_ts) + ht_sched_update(next, true); +} + +/* perform LRU order */ +void ht_rtg_list_add_tail(struct task_struct *task) +{ + u64 time; + + if (perf_ready <= 0) + return; + + if (!task->pid) + return; + + if (task->tgid != perf_ready) + return; + + ht_logv("rtg task add list: %s(%d) util: %d, peak: %d\n", + task->comm, task->pid, task->ravg.demand_scaled, task->rtg_peak); + + if (task->ravg.demand_scaled < base_util) + return; + + time = ktime_to_us(ktime_get()); + + /* if calling too close, ignore it */ + if (time < task->rtg_ts2 || + time - task->rtg_ts2 <= 1000 /* 1 ms */) + return; + + task->rtg_ts2 = time; + + /* may need to handle overflow */ + if (time < task->rtg_period_ts || + time - task->rtg_period_ts >= 1000000 /* 1 sec */) { + task->rtg_peak = task->rtg_cnt; + task->rtg_cnt = 0; + task->rtg_period_ts = time; + } + ++task->rtg_cnt; + task->rtg_ts = time; + + /* filter out low frequent candidate */ + if (task->rtg_peak < rtg_filter_cnt) + return; + + /* quick check with no lock */ + if (!list_empty(&task->rtg_node)) + return; + + /* real list update */ + spin_lock(&ht_rtg_lock); + if (list_empty(&task->rtg_node)) + list_add_tail(&task->rtg_node, &ht_rtg_head); + im_set_flag(task, IM_ENQUEUE); + spin_unlock(&ht_rtg_lock); +} +EXPORT_SYMBOL(ht_rtg_list_add_tail); + +void ht_rtg_list_del(struct task_struct *task) +{ + if (!task->pid) + return; + + spin_lock(&ht_rtg_lock); + if (!list_empty(&task->rtg_node)) { + ht_logv("rtg task del list: %s(%d) util: %d, peak: %d\n", + task->comm, task->pid, task->ravg.demand_scaled, task->rtg_peak); + list_del_init(&task->rtg_node); + im_unset_flag(task, IM_ENQUEUE); + } + spin_unlock(&ht_rtg_lock); +} +EXPORT_SYMBOL(ht_rtg_list_del); + +static int rtg_dump_show(char *buf, const struct kernel_param *kp) +{ + int cnt = 0; + int size = 0; + u64 time = ktime_to_us(ktime_get()); + struct task_struct *t; + + rcu_read_lock(); + spin_lock(&ht_rtg_lock); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "RTG list: comm, pid, util, peak, cnt, delta ts, ts\n"); + list_for_each_entry(t, &ht_rtg_head, rtg_node) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%s %d %hu %u %u %lld %lld\n", + t->comm, t->pid, t->ravg.demand_scaled, + t->rtg_peak, t->rtg_cnt, + time - t->rtg_ts, t->rtg_ts); + ++size; + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "Total: %d\n", size); + spin_unlock(&ht_rtg_lock); + size = 0; + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "RTG perf event created list: comm, pid\n"); + spin_lock(&ht_perf_event_lock); + list_for_each_entry(t, &ht_perf_event_head, ht_perf_event_node) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%s %d\n", t->comm, t->pid); + ++size; + } + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "Total: %d\n", size); + spin_unlock(&ht_perf_event_lock); + rcu_read_unlock(); + return cnt; +} + +static struct kernel_param_ops rtg_dump_ops = { + .get = rtg_dump_show, +}; +module_param_cb(rtg_dump, &rtg_dump_ops, NULL, 0444); + + +static int get_gpu_percentage() +{ + struct kgsl_clk_stats *stats = NULL; + if (gpwr) { + stats = &gpwr->clk_stats; + return stats->total_old != 0 ? stats->busy_old * 100 / stats->total_old : 0; + } + return 0; +} + +static int game_info_show(char *buf, const struct kernel_param *kp) +{ + int gpu, cpu, fps; + static u64 last_enqueue_time; + //static int last_game_fps_pid; + if (game_fps_pid == -1) { + gpu = -1; + cpu = -1; + fps = -1; + } else { + wake_up_interruptible(&ht_poll_waitq); + cpu = ohm_get_cur_cpuload(true); + gpu = get_gpu_percentage(); + fps = game_fps_data_.fps / 10; + + if (fps < 0 || fps > 150) { + ht_loge("fps %d out of range", fps); + fps = 0; + } + if (game_fps_data_.enqueue_time == last_enqueue_time) { + ht_loge("Didn't update new fps data"); + fps = 0; + } + + last_enqueue_time = game_fps_data_.enqueue_time; + } + return snprintf(buf, PAGE_SIZE, "%d %d %d\n", gpu, cpu, fps); +} + +static struct kernel_param_ops game_info_ops = { + .get = game_info_show, +}; +module_param_cb(game_info, &game_info_ops, NULL, 0664); + +static int get_util(bool isRender, int *num) +{ + int util = 0; + struct task_struct *t; + + rcu_read_lock(); + + if (!isRender) { + spin_lock(&ht_rtg_lock); + list_for_each_entry(t, &ht_rtg_head, rtg_node) { + util += t->ravg.demand_scaled; + (*num)++; + ht_logv("RTG: comm:%s pid:%d util:%lu\n", + t->comm, t->pid, t->ravg.demand_scaled); + } + spin_unlock(&ht_rtg_lock); + } else { + spin_lock(&ht_perf_event_lock); + list_for_each_entry(t, &ht_perf_event_head, + ht_perf_event_node) { + if (RenPid != t->pid) + continue; + util = t->ravg.demand_scaled; + ht_logv("Render: comm:%s pid:%d util:%lu\n", + t->comm, t->pid, t->ravg.demand_scaled); + break; + } + spin_unlock(&ht_perf_event_lock); + } + + rcu_read_unlock(); + + return util; +} + +static int ht_init(void) +{ + int i; + + /* init cached fps info */ + atomic_set(&cached_fps[0], 60); + atomic_set(&cached_fps[1], 60); + atomic64_set(&fps_align_ns, 0); + + for (i = 0; i < HT_MONITOR_SIZE; ++i) + report_div[i] = (i >= HT_CPU_0 && i <= HT_THERM_2)? 100: 1; + + ht_set_all_mask(); + + monitor.thread = kthread_create(ht_monitor, NULL, "ht_monitor"); + if (IS_ERR(monitor.thread)) { + ht_loge("Can't create ht monitor thread\n"); + return -EAGAIN; + } + + keep_alive = true; + wake_up_process(monitor.thread); + + proc_create("ht_report", S_IFREG | 0444, NULL, &ht_report_proc_fops); + proc_create("ht_group", S_IFREG | 0444, NULL, &ht_group_proc_fops); + + fps_sync_init(); + ht_perf_workq = alloc_ordered_workqueue("ht_wq", 0); + if (!ht_perf_workq) { + /* TODO handle this */ + ht_loge("alloc work queue fail\n"); + } + + /* enable all counter */ + on_each_cpu(enable_cpu_counters, NULL, 1); + ht_logi("Enable Access PMU Initialized\n"); + return 0; +} +pure_initcall(ht_init); diff --git a/drivers/oneplus/coretech/houston/test/Android.mk b/drivers/oneplus/coretech/houston/test/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..c42f0edae6c060f3f0920513c1252e80a3a8967c --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/Android.mk @@ -0,0 +1,29 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := perf_event_test +LOCAL_CFLAGS = -Wall -Wextra -O0 +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := perf_event_test.cpp +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := perf_event_monitor +LOCAL_CFLAGS = -Wall -Wextra -O0 +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := perf_event_monitor.cpp +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := perf_ioctl +LOCAL_CFLAGS = -Wall -Wextra -O0 +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := perf_ioctl.cpp +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := stress_boost +LOCAL_CFLAGS = -Wall -Wextra -O0 +LOCAL_SHARED_LIBRARIES := libcutils libbase +LOCAL_SRC_FILES := stress_boost.cpp +include $(BUILD_EXECUTABLE) diff --git a/drivers/oneplus/coretech/houston/test/perf_event_monitor.cpp b/drivers/oneplus/coretech/houston/test/perf_event_monitor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..215669188fd9399022216697867da1d4affd25de --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/perf_event_monitor.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERF_MAX 5 + +struct read_format { + uint64_t nr; + struct { + uint64_t value; + uint64_t id; + } values[]; +}; + +/* test loading */ +void do_something() { + int i; + char* ptr; + + ptr = (char *) malloc(100*1024); + for (i = 0; i < 100*1024; i++) + ptr[i] = (char) (i & 0xff); // pagefault + free(ptr); +} + +static inline int monitor_cases(int idx) { + switch (idx) { + case 0: return PERF_COUNT_HW_CPU_CYCLES; + case 1: return PERF_COUNT_HW_INSTRUCTIONS; + case 2: return PERF_COUNT_HW_CACHE_MISSES; + case 3: return PERF_COUNT_HW_BUS_CYCLES; + case 4: return PERF_COUNT_HW_BRANCH_MISSES; + } + + return PERF_COUNT_HW_CPU_CYCLES; +} + +int main(int argc, char**argv) { + int i, cnt = 10, opt, events = 1, fds[PERF_MAX] = {0}; + bool grouping = false; + uint64_t ids[PERF_MAX] = {0}, vals[PERF_MAX] = {0}; + char buf[4096]; + struct read_format* rf = (struct read_format*) buf; + struct perf_event_attr peas[PERF_MAX]; + + while ((opt = getopt(argc, argv, "c:e:g")) != -1) { + switch (opt) { + case 'e': + events = atoi(optarg); + if (events < 1) events = 1; + if (events > PERF_MAX) events = PERF_MAX; + break; + case 'g': + grouping = true; + break; + case 'c': + cnt = atoi(optarg); + if (cnt < 10) cnt = 10; + if (cnt > 1000) cnt = 1000; + break; + default: /* '?' */ + fprintf(stderr, + "Usage: %s -e 3 -g 0 -c 10\n", argv[0]); + return 0; + } + } + + printf ("monitor events: %d\n", events); + printf ("using grouping: %d\n", grouping); + + /* start monitor perf events */ + memset(&peas, 0, sizeof(struct perf_event_attr) * PERF_MAX); + peas[0].type = PERF_TYPE_HARDWARE; + peas[0].size = sizeof(struct perf_event_attr); + peas[0].config = monitor_cases(0); + peas[0].disabled = 1; + peas[0].exclude_kernel = 1; + peas[0].exclude_hv = 1; + if (grouping) + peas[0].read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; + fds[0] = syscall(__NR_perf_event_open, &peas[0], 0, -1, -1, 0); + ioctl(fds[0], PERF_EVENT_IOC_ID, &ids[0]); + + for (i = 1; i < events; ++i) { + memset(&peas, 0, sizeof(struct perf_event_attr)); + peas[i].type = PERF_TYPE_HARDWARE; + peas[i].size = sizeof(struct perf_event_attr); + peas[i].config = monitor_cases(i); + peas[i].disabled = 1; + peas[i].exclude_kernel = 1; + peas[i].exclude_hv = 1; + if (grouping) { + peas[i].read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; + fds[i] = syscall(__NR_perf_event_open, &peas[i], 0, -1, fds[0], 0); + ioctl(fds[i], PERF_EVENT_IOC_ID, &ids[i]); + } else + fds[i] = syscall(__NR_perf_event_open, &peas[i], 0, -1, -1, 0); + } + + ioctl(fds[0], PERF_EVENT_IOC_RESET, grouping? PERF_IOC_FLAG_GROUP: 0); + ioctl(fds[0], PERF_EVENT_IOC_ENABLE, grouping? PERF_IOC_FLAG_GROUP: 0); + for (i = 1; i < events && !grouping; ++i) { + ioctl(fds[i], PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP); + ioctl(fds[i], PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP); + } + + while (cnt--) { + do_something(); + memset(buf, 0, sizeof(buf)); + if (grouping) { + read(fds[0], buf, sizeof(buf)); + for (uint64_t i = 0; i < rf->nr; i++) { + if (rf->values[i].id == ids[i]) { + vals[i] = rf->values[i].value; + } + } + } else { + for (i = 0; i < events; ++i) + read(fds[i], &vals[i], sizeof(uint64_t)); + } + printf("cpu cycles: %ld\n", vals[0]); + printf("instructions: %ld\n", vals[1]); + printf("cache misses: %ld\n", vals[2]); + printf("bus cycles: %ld\n", vals[3]); + printf("branch misses: %ld\n", vals[4]); + printf("----------------------\n"); + } + + /* disable */ + if (grouping) + ioctl(fds[0], PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP); + else { + for (i = 0; i < events; ++i) + if (fds[i]) + ioctl(fds[i], PERF_EVENT_IOC_DISABLE, 0); + } + return 0; +} diff --git a/drivers/oneplus/coretech/houston/test/perf_event_test.cpp b/drivers/oneplus/coretech/houston/test/perf_event_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9da29dc305a8567ba945c1502d3a536bebe6719 --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/perf_event_test.cpp @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define FREQ (576000) + +inline long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, + int cpu, int group_fd, unsigned long flags) +{ + return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); +} + +void test1() { + cout << getpid() << ": test: print 1000" << endl; + int cnt = 100000; + while (--cnt) + cout << cnt; + cout << endl; +} + +void test2() { + cout << getpid() << ": test: print 5000" << endl; + int cnt = 5000; + while (--cnt) + cout << cnt; + cout << endl; +} + +long long parse(string content) { + /* take first col */ + if (!content.empty()) { + stringstream ss(content); + string s; + getline(ss, s, ' '); + return stoll(s); + } + return 0LL; +} + +void loop(int fd, void (*f)(void)) { + cout << "---------------------------------" << endl; + long long count; + long long ts1, ts2; + + ioctl(fd, PERF_EVENT_IOC_RESET, 0); + ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); + + std::string content; + android::base::ReadFileToString("/proc/self/schedstat", &content); + cout << content; + ts1 = parse(content); + content.clear(); + + f(); + android::base::ReadFileToString("/proc/self/schedstat", &content); + cout << content; + ts2 = parse(content); + content.clear(); + + ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); + read(fd, &count, sizeof(long long)); + printf("%d: cpu time: %lld, cycle: %lld, freq: %d\n", getpid(), ts2 - ts1, count, FREQ); +} + +int main() +{ + struct perf_event_attr pe; + int fd; + + memset(&pe, 0, sizeof(struct perf_event_attr)); + pe.type = PERF_TYPE_HARDWARE; + pe.size = sizeof(struct perf_event_attr); + pe.config = PERF_COUNT_HW_CPU_CYCLES; + pe.disabled = 1; + pe.exclude_kernel = 1; + pe.exclude_hv = 1; + + fd = perf_event_open(&pe, 0, -1, -1, 0); + if (fd == -1) { + fprintf(stderr, "Error opening leader %llx\n", pe.config); + exit(EXIT_FAILURE); + } + + loop(fd, test1); +// loop(fd, test2); + + close(fd); + return 0; +} diff --git a/drivers/oneplus/coretech/houston/test/perf_ioctl.cpp b/drivers/oneplus/coretech/houston/test/perf_ioctl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0e017db3bf1819b816ee41a7cc57f6366778e75a --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/perf_ioctl.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +typedef unsigned int u32; +typedef unsigned long long u64; +typedef long long s64; + +#define HT_IOC_MAGIC 'k' +#define HT_IOC_COLLECT _IOR(HT_IOC_MAGIC, 0, struct ai_parcel) +#define HT_IOC_SCHEDSTAT _IOWR(HT_IOC_MAGIC, 1, int) +#define HT_IOC_MAX 2 + +#define AI_THREAD_PARCEL_MAX (10) + +struct ai_thread_parcel { + u32 tid; + u64 exec_time; // schedstat + u64 inst; // pmu related + u64 cycle; + u64 cache_miss_l1; + u64 cache_miss_l2; + u64 cache_miss_l3; +}; + +struct ai_parcel { + u32 pid; + u32 fps; + u32 efps; + char layer[64]; + u32 cpu_cur_freq_0; + u32 cpu_cur_freq_1; + u32 cpu_cur_freq_2; + u32 gpu_freq; + u64 ddr_freq; + u32 ddr_bw; + u32 volt_now; // battery part + u32 curr_now; + u64 queued_ts; + u64 prev_queued_ts; + u32 thread_amount; // default maximum 10 threads + u32 boost_cnt; + u64 boost_ts_us; + u64 boost_end_ts_us; + u64 data_collect_ts_us; + u64 data_collect_end_ts_us; + u64 utils[8]; + struct ai_thread_parcel t[AI_THREAD_PARCEL_MAX]; +}; +// sysnode /dev/ht_ctl (temporary) + +#define HT_AI_IOC_PATH "/dev/ht_ctl" + +void dump_parcel_thread(struct ai_thread_parcel &t, int idx) { + cout << "t[" << idx << "]: tid: " << t.tid << endl; + cout << "t[" << idx << "]: exec_time: " << t.exec_time << endl; + cout << "t[" << idx << "]: inst: " << t.inst << endl; + cout << "t[" << idx << "]: cycle: " << t.cycle << endl; + cout << "t[" << idx << "]: cache_miss_l1: " << t.cache_miss_l1 << endl; + cout << "t[" << idx << "]: cache_miss_l2: " << t.cache_miss_l2 << endl; + cout << "t[" << idx << "]: cache_miss_l2: " << t.cache_miss_l3 << endl; +} + +void dump_parcel(struct ai_parcel& p) { + cout << "pid: " << p.pid << endl; + cout << "fps: " << p.fps << endl; + cout << "efps: " << p.efps << endl; + cout << "layer: " << p.layer << endl; + cout << "cpu_cur_freq_0: " << p.cpu_cur_freq_0 << endl; + cout << "cpu_cur_freq_1: " << p.cpu_cur_freq_1 << endl; + cout << "cpu_cur_freq_2: " << p.cpu_cur_freq_2 << endl; + cout << "gpu_freq: " << p.gpu_freq << endl; + cout << "ddr_freq: " << p.ddr_freq << endl; + cout << "ddr_bw: " << p.ddr_bw << endl; + cout << "volt_now: " << p.volt_now << endl; + cout << "curr_now: " << p.curr_now << endl; + cout << "queued_ts: " << p.queued_ts << endl; + cout << "thread_amount: " << p.thread_amount << endl; + cout << "boost_cnt: " << p.boost_cnt << endl; + for (u32 i = 0; i < p.thread_amount; ++i) + dump_parcel_thread(p.t[i], i); +} + +int main(int, char**) { + int fd; + struct ai_parcel parcel; + + fd = open(HT_AI_IOC_PATH, O_WRONLY); + if (fd == -1) + return -1; + + ioctl(fd, HT_IOC_COLLECT, &parcel); + + /* parse data */ + dump_parcel(parcel); + + close(fd); + return 0; +} diff --git a/drivers/oneplus/coretech/houston/test/script/stress.py b/drivers/oneplus/coretech/houston/test/script/stress.py new file mode 100644 index 0000000000000000000000000000000000000000..1f6206b46eaaee8ca7ff2e499677f43f53307a3e --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/script/stress.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python2.7 +import time +import os +import subprocess +from subprocess import Popen, PIPE +import random +from datetime import datetime +import pandas + +cnt = 1 + +def process_csv(file_name): + print('process file %s' % file_name) + data = pandas.read_csv(file_name) + data['real'] = data['cycle'] * 1000000 / data['CLUS1 freq'] + tag = 'schedstat ' + if tag in list(data): + data['t1'] = data[tag] + else: + data['t1'] = data['schedstat'] + data['t1_%'] = data['t1'] / data['real'] + data['t1_m'] = data['t1_%'].mean() + data['t1_s'] = data['t1_%'].std() + + #data['t2'] = data['cachemiss_L2'] + #data['t2_%'] = data['t2'] / data['real'] + #data['t2_m'] = data['t2_%'].mean() + #data['t2_s'] = data['t2_%'].std() + + #print("status: t1_m: %f t1_s:%f t2_m:%f t2_s:%f" % (data['t1_m'][0], data['t1_s'][0], data['t2_m'][0], data['t2_s'][0])) + + print("status: t1_m: %f t1_s:%f" % (data['t1_m'][0], data['t1_s'][0])) + data.to_csv(file_name, index=False) + print('file processed') + +def print_sleep(sec): + while sec >= 0: + print(','), + time.sleep(1) + sec -= 1 + +while True: + print('test %d' % cnt) + print('waiting for device') + loop = True + while loop: + process = Popen(['lsusb'], stdout=PIPE) + output = process.communicate() + #print(output) + for line in output: + if line and line.find('Qual') >= 0: + loop = False + print('device is ready') + break + + print('screen unlock') + os.system('adb shell input keyevent 82') + + print('set top app to cpu 4-6') + os.system('adb shell \"echo 4-6 > /dev/cpuset/top-app/cpus \"') + + print('lock cpu/ddr freq'); + subprocess.call(['adb', 'shell', 'echo 1632000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq']) + subprocess.call(['adb', 'shell', 'echo 1632000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq']) + subprocess.call(['adb', 'shell', 'echo 1632000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq']) + subprocess.call(['adb', 'shell', 'echo 1632000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq']) + subprocess.call(['adb', 'shell', 'echo 710400 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq']) + subprocess.call(['adb', 'shell', 'echo 710400 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq']) + subprocess.call(['adb', 'shell', 'echo 710400 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq']) + subprocess.call(['adb', 'shell', 'echo 710400 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq']) + subprocess.call(['adb', 'shell', 'echo 2419200 > /sys/devices/system/cpu/cpu7/cpufreq/scaling_max_freq']) + subprocess.call(['adb', 'shell', 'echo 2419200 > /sys/devices/system/cpu/cpu7/cpufreq/scaling_min_freq']) + subprocess.call(['adb', 'shell', 'echo 2419200 > /sys/devices/system/cpu/cpu7/cpufreq/scaling_max_freq']) + subprocess.call(['adb', 'shell', 'echo 2419200 > /sys/devices/system/cpu/cpu7/cpufreq/scaling_min_freq']) + + subprocess.call(['adb', 'shell', 'echo {class: ddr, res: fixed, val: 681} > /sys/kernel/debug/aop_send_message']) + + print_sleep(5) + print('start activity') + os.system('adb shell \"am start -n com.tencent.tmgp.sgame/.SGameActivity \"') + + print_sleep(5) + print('get target_pid') + process = Popen(['adb', 'shell', 'ps -A | grep tencent | grep -v com.tencent.tmgp.sgame:xg_service_v3'], stdout=PIPE) + (output, err) = process.communicate() + #print(output) + target_pid = output.split()[1] + #print(target_pid) + if not target_pid: + print('don\'t get target pid') + exit() + + r = random.randint(4,7) + print('wait for %d sec' % r) + print_sleep(r) + print('echo target_pid %s to monitor' % target_pid) + cmd = 'echo ' + target_pid + ' > /sys/module/houston/parameters/perf_ready' + process = Popen(['adb', 'shell', cmd], stdout=PIPE) + process = Popen(['adb', 'shell', 'cat /sys/module/houston/parameters/perf_ready'], stdout=PIPE) + (output, err) = process.communicate() + if output and output.rstrip() != target_pid: + print('echo error') + exit() + print('collect data') + cmd = 'adb shell datacollector 1000' + subprocess.call(cmd.split()) + #output = str(datetime.now()).replace(' ', '_') + "_" + str(cnt) + ".csv" + output = str(cnt).zfill(4) + ".csv" + cmd = 'adb pull /data/test.csv ' + output + subprocess.call(cmd.split()) + process_csv(output) + print_sleep(3) + os.system('adb reboot') + print_sleep(60) + cnt += 1 diff --git a/drivers/oneplus/coretech/houston/test/script/stress_perf_event.sh b/drivers/oneplus/coretech/houston/test/script/stress_perf_event.sh new file mode 100644 index 0000000000000000000000000000000000000000..c7f619b8b4d62ed5766626c475040e5f674996c7 --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/script/stress_perf_event.sh @@ -0,0 +1,22 @@ +adb shell setenforce 0 +adb shell "echo 4-6 > /dev/cpuset/top-app/cpus" + + +# case 1 +cnt=100 +while [ $cnt -ne 0 ]; +do +adb shell "am start -n com.tencent.tmgp.sgame/.SGameActivity" +sleep 3 +pid=$(adb shell ps | grep -v xg_service | awk '/tencent/{print $2}') +echo "cnt $cnt pid $pid" +adb shell "echo '$pid' > /sys/module/houston/parameters/perf_ready" +adb shell aisdebug resume $pid com.tencent.tmgp.sgame +sleep 3 +adb shell aisdebug set_dumpfile true +sleep 10 +adb shell kill -9 $pid +sleep 3 +((--cnt)) +done + diff --git a/drivers/oneplus/coretech/houston/test/stress_boost.cpp b/drivers/oneplus/coretech/houston/test/stress_boost.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd48d0e4874c66995cb46442a0881b55667fd671 --- /dev/null +++ b/drivers/oneplus/coretech/houston/test/stress_boost.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +int main(int, char**) { + ofstream output; + srand(time(NULL)); + output.open("/sys/module/houston/parameters/fps_boost"); + while (1) { + if (!output.is_open()) + return 0; + output.seekp(0); + output << 1 << "," << 5 << "," << 21; + output.flush(); + + int nanosec = 10000 + rand() % 20000; + cout << "sleep " << nanosec << endl; + usleep(nanosec); + } + output.close(); + return 0; +} diff --git a/drivers/oneplus/coretech/im/Makefile b/drivers/oneplus/coretech/im/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fd17e80e9e4d83c2e9227b55bfaec812ff923897 --- /dev/null +++ b/drivers/oneplus/coretech/im/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_IM) += im.o diff --git a/drivers/oneplus/coretech/im/im.c b/drivers/oneplus/coretech/im/im.c new file mode 100644 index 0000000000000000000000000000000000000000..c9249dd4236452d5d49946ecd06da28464bfc62d --- /dev/null +++ b/drivers/oneplus/coretech/im/im.c @@ -0,0 +1,444 @@ +#include +#include +#include +#include +#include +#include "../kernel/sched/sched.h" +#include "../kernel/sched/walt.h" + +struct task_list_entry { + int pid; + struct list_head node; +}; + +static int tb_rdg_enable = 1; +static DEFINE_SPINLOCK(tb_render_group_lock); +static struct list_head task_list_head = LIST_HEAD_INIT(task_list_head); + +/* default list, empty string means no need to check */ +static struct im_target { + char val[64]; + const char* desc; +} im_target [IM_ID_MAX] = { + {"surfaceflinger", "sf "}, + {"", "kworker "}, + {"logd", "logd "}, + {"logcat", "logcat "}, + {"", "main "}, + {"", "enqueue "}, + {"", "gl "}, + {"", "vk "}, + {"composer-servic", "hwc "}, + {"HwBinder:", "hwbinder "}, + {"Binder:", "binder "}, + {"hwuiTask", "hwui "}, + {"", "render "}, + {"", "unity_wk"}, + {"UnityMain", "unityM"}, + {"neplus.launcher", "launcher "}, + {"HwuiTask", "HwuiEx "}, + {"CrRendererMain", "crender "}, +}; + +/* ignore list, not set any im_flag */ +static char target_ignore_prefix[IM_IG_MAX][64] = { + "Prober_", + "DispSync", + "app", + "sf", + "ScreenShotThrea", + "DPPS_THREAD", + "LTM_THREAD", +}; + +void im_to_str(int flag, char* desc, int size) +{ + char *base = desc; + int i; + + for (i = 0; i < IM_ID_MAX; ++i) { + if (flag & (1 << i)) { + size_t len = strlen(im_target[i].desc); + + if (len) { + if (size <= base - desc + len) { + pr_warn("im tag desc too long\n"); + return; + } + strncpy(base, im_target[i].desc, len); + base += len; + } + } + } +} + +static inline bool im_ignore(struct task_struct *task, int idx) +{ + size_t tlen = 0, len = 0; + + tlen = strlen(target_ignore_prefix[idx]); + if (tlen == 0) + return false; + + /* NOTE: task->comm has only 16 bytes */ + len = strlen(task->comm); + if (len < tlen) + return false; + + if (!strncmp(task->comm, target_ignore_prefix[idx], tlen)) { + task->im_flag = 0; + return true; + } + return false; +} + +static inline void im_tagging(struct task_struct *task, int idx) +{ + size_t tlen = 0, len = 0; + + tlen = strlen(im_target[idx].val); + if (tlen == 0) + return; + + /* NOTE: task->comm has only 16 bytes */ + len = strlen(task->comm); + + /* non restrict tagging for some prefixed tasks*/ + if (len < tlen) + return; + + /* prefix cases */ + if (!strncmp(task->comm, im_target[idx].val, tlen)) { + switch (idx) { + case IM_ID_HWBINDER: + task->im_flag |= IM_HWBINDER; + break; + case IM_ID_BINDER: + task->im_flag |= IM_BINDER; + break; + case IM_ID_HWUI: + task->im_flag |= IM_HWUI; + break; + case IM_ID_HWUI_EX: + task->im_flag |= IM_HWUI_EX; + break; + } + } + + /* restrict tagging for specific identical tasks */ + if (len != tlen) + return; + + if (!strncmp(task->comm, im_target[idx].val, len)) { + switch (idx) { + case IM_ID_SURFACEFLINGER: + task->im_flag |= IM_SURFACEFLINGER; + break; + case IM_ID_LOGD: + task->im_flag |= IM_LOGD; + break; + case IM_ID_LOGCAT: + task->im_flag |= IM_LOGCAT; + break; + case IM_ID_HWC: + task->im_flag |= IM_HWC; + break; + case IM_ID_LAUNCHER: + task->im_flag |= IM_LAUNCHER; + break; + case IM_ID_RENDER: + task->im_flag |= IM_RENDER; + break; + case IM_ID_UNITY_MAIN: + task->im_flag |= IM_UNITY_MAIN; + break; + } + } +} + +void im_wmi(struct task_struct *task) +{ + int i = 0; + struct task_struct *leader = task->group_leader; + + /* check for ignore */ + for (i = 0; i < IM_IG_MAX; ++i) + if (im_ignore(task, i)) + return; + + /* do the check and initial */ + task->im_flag = 0; + for (i = 0; i < IM_ID_MAX; ++i) + im_tagging(task, i); + + /* for hwc cases */ + if (im_hwc(leader)) { + struct task_struct *p; + rcu_read_lock(); + for_each_thread(task, p) { + if (im_binder_related(p)) + p->im_flag |= IM_HWC; + } + rcu_read_unlock(); + } + + /* for sf cases */ + if (im_sf(leader) && im_binder_related(task)) + task->im_flag |= IM_SURFACEFLINGER; +} + +void im_wmi_current(void) +{ + im_wmi(current); +} + +void im_set_flag(struct task_struct *task, int flag) +{ + struct task_struct *leader = task->group_leader; + + task->im_flag |= flag; + if (flag == IM_ENQUEUE) { + if (leader) + im_set_flag(leader, IM_MAIN); + } +} + +void im_set_flag_current(int flag) +{ + + struct task_struct *leader = current->group_leader; + + im_tagging(current, IM_ID_HWUI); + if (current->im_flag & IM_HWUI) { + return; + } + im_tagging(current, IM_ID_HWUI_EX); + if (current->im_flag & IM_HWUI_EX) { + return; + } + + current->im_flag |= flag; + if (flag == IM_ENQUEUE) { + if (leader) + im_set_flag(leader, IM_MAIN); + } +} + +void im_unset_flag(struct task_struct *task, int flag) +{ + task->im_flag &= ~flag; +} + +void im_unset_flag_current(int flag) +{ + current->im_flag &= ~flag; +} + +void im_reset_flag(struct task_struct *task) +{ + task->im_flag = 0; +} + +void im_reset_flag_current(void) +{ + current->im_flag = 0; +} + +static void change_grp_from_pool(bool grouping_enable) +{ + struct task_list_entry *p; + struct task_struct *task; + + if (list_empty(&task_list_head)) + return; + + spin_lock(&tb_render_group_lock); + list_for_each_entry(p, &task_list_head, node) { + + rcu_read_lock(); + task = find_task_by_vpid(p->pid); + if (task) + /* group_id of surfaceflinger is 0 by default, + * because sf is not top-app + */ + im_set_op_group(task, IM_SURFACEFLINGER, + grouping_enable); + + rcu_read_unlock(); + } + spin_unlock(&tb_render_group_lock); +} + +static int tb_rdg_enable_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (tb_rdg_enable == val) + return 0; + + tb_rdg_enable = val; + + change_grp_from_pool(!(tb_rdg_enable == 0)); + + // disable will change group 2 to 0 + if(!tb_rdg_enable) + group_remove(); + + return 0; +} + +static int tb_rdg_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", tb_rdg_enable); +} + +static struct kernel_param_ops tb_rdg_enable_ops = { + .set = tb_rdg_enable_store, + .get = tb_rdg_enable_show, +}; + +module_param_cb(tb_rdg_enable, &tb_rdg_enable_ops, NULL, 0664); + +static int tb_rdg_list_store(const char *buf, const struct kernel_param *kp) +{ + int val; + struct task_list_entry *p, *next; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (list_empty(&task_list_head)) + return 0; + + spin_lock(&tb_render_group_lock); + list_for_each_entry_safe(p, next, &task_list_head, node) { + + pr_debug("rm task pid=%d\n", p->pid); + list_del_init(&p->node); + kfree(p); + val--; + if (val == 0) + break; + } + spin_unlock(&tb_render_group_lock); + return 0; +} + +static int tb_rdg_list_show(char *buf, const struct kernel_param *kp) +{ + struct task_list_entry *p; + struct task_struct *task; + int cnt = 0; + + if (list_empty(&task_list_head)) + return cnt; + + spin_lock(&tb_render_group_lock); + list_for_each_entry(p, &task_list_head, node) { + + pr_info("show task pid=%d\n", p->pid); + rcu_read_lock(); + task = find_task_by_vpid(p->pid); + if (task) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%s %d\n", + task->comm, task->pid); + } else { + pr_warn("cannot find task pid=%d\n", p->pid); + } + + rcu_read_unlock(); + } + spin_unlock(&tb_render_group_lock); + + return cnt; +} + +static struct kernel_param_ops tb_rdg_list_ops = { + .set = tb_rdg_list_store, + .get = tb_rdg_list_show, +}; +module_param_cb(tb_rdg_list, &tb_rdg_list_ops, NULL, 0664); + +int im_render_grouping_enable(void) +{ + return tb_rdg_enable; +} + +void im_set_op_group(struct task_struct *task, int flag, bool insert) +{ + if (insert) { + if (flag != IM_KWORKER && flag != IM_LOGD && + flag != IM_LOGCAT) { + if (task->grp && task->grp->id == DEFAULT_CGROUP_COLOC_ID) + return; + + sched_set_group_id(task, DEFAULT_CGROUP_COLOC_ID); + } + } else { + struct related_thread_group *grp = task->grp; + + if (grp && grp->id == DEFAULT_CGROUP_COLOC_ID) + sched_set_group_id(task, 0); + } +} + +void im_list_add_task(struct task_struct *task) +{ + + struct task_list_entry *p; + + if (!im_sf(task)) + return; + + p = kmalloc(sizeof(struct task_list_entry), GFP_KERNEL); + if (p == NULL) + return; + + p->pid = task->pid; + INIT_LIST_HEAD(&p->node); + + pr_info("add task pid=%d comm=%s\n", + task->pid, task->comm); + + spin_lock(&tb_render_group_lock); + list_add_tail(&p->node, &task_list_head); + spin_unlock(&tb_render_group_lock); +} + +void im_list_del_task(struct task_struct *task) +{ + + struct task_list_entry *p, *next; + + if (!task->pid) + return; + + if (!im_sf(task)) + return; + + if (list_empty(&task_list_head)) + return; + + pr_info("rm task pid=%d\n", task->pid); + + spin_lock(&tb_render_group_lock); + list_for_each_entry_safe(p, next, &task_list_head, node) { + + if (p->pid == task->pid) { + list_del_init(&p->node); + kfree(p); + break; + } + } + spin_unlock(&tb_render_group_lock); +} + +void im_tsk_init_flag(void *ptr) +{ + struct task_struct *task = (struct task_struct*) ptr; + task->im_flag &= ~IM_HWUI; + task->im_flag &= ~IM_HWUI_EX; +} diff --git a/drivers/oneplus/coretech/memex_standalone_support/core/Makefile b/drivers/oneplus/coretech/memex_standalone_support/core/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b7e59619d197031c8c5b3a6f524c3702d5be6886 --- /dev/null +++ b/drivers/oneplus/coretech/memex_standalone_support/core/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MEMEX_STANDALONE) += memex_standalone_core.o diff --git a/drivers/oneplus/coretech/memex_standalone_support/core/memex_standalone_core.c b/drivers/oneplus/coretech/memex_standalone_support/core/memex_standalone_core.c new file mode 100644 index 0000000000000000000000000000000000000000..a862709c5beb45e1ddad558339bb6f427a37ae61 --- /dev/null +++ b/drivers/oneplus/coretech/memex_standalone_support/core/memex_standalone_core.c @@ -0,0 +1,577 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "memex_standalone_core.h" +#include +#include + +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page);}) + +#define MEMEX_SIZE 512 +#define MEMEX_DEBUG 0 +#define RD_SIZE 128 +#define DEBUG_TIME_INFO 0 +#define FEAT_RECLAIM_LIMIT 0 + +#if defined(CONFIG_DRM_PANEL) +extern struct drm_panel *lcd_active_panel; +#endif + +struct mp_reclaim_param { + struct vm_area_struct *vma; + /* Number of pages scanned */ + int nr_scanned; +#if FEAT_RECLAIM_LIMIT + unsigned long start_jiffies; +#endif + /* max pages to reclaim */ + int nr_to_reclaim; + /* pages reclaimed */ + int nr_reclaimed; + int type; +}; + +/* MemEx mode */ +static struct task_struct *memex_tsk; +static unsigned int memex_threshold __read_mostly; +static pid_t memex_proc[MEMEX_SIZE]; +static unsigned int vm_cam_aware __read_mostly = 1; +#if MEMEX_DEBUG +static unsigned int vm_swapin __read_mostly = 0; +module_param_named(memory_plus_swapin, vm_swapin, uint, S_IRUGO | S_IWUSR); +#endif + +/* -1 = system free to use swap, 0 = disable retention, swap not available, 1 = enable retention */ +static int vm_memory_plus __read_mostly = 0; +static unsigned long memplus_add_to_swap = 0; +unsigned long coretech_reclaim_pagelist(struct list_head *page_list, struct vm_area_struct *vma, void *sc); +unsigned long swapout_to_zram(struct list_head *page_list, struct vm_area_struct *vma); + +#if MEMEX_DEBUG +static bool is_fast_entry(swp_entry_t entry) +{ + struct swap_info_struct *p; + bool ret = false; + unsigned long offset, type; + + if (!entry.val) + goto out; + type = swp_type(entry); + p = swap_info[type]; + if (!(p->flags & SWP_USED)) + goto out; + offset = swp_offset(entry); + if (offset >= p->max) + goto out; + + spin_lock(&p->lock); + if (p->flags & SWP_SYNCHRONOUS_IO) + ret = true; + spin_unlock(&p->lock); +out: + return ret; +} +#endif + +static bool enough_swap_size(unsigned long req_size, int swap_bdv) +{ + bool ret = false; + unsigned int n = 0; + struct swap_info_struct *sis, *next; + unsigned int node = numa_node_id(); + + if (swap_bdv > 1) + return ret; + + spin_lock(&swap_lock); + plist_for_each_entry_safe(sis, next, &swap_avail_heads[node], avail_lists[node]) { + int fast_i = (sis->flags & SWP_SYNCHRONOUS_IO)? 1:0; + + if (fast_i == swap_bdv) { + spin_lock(&sis->lock); + if (sis->flags & SWP_WRITEOK) { + n += sis->pages - sis->inuse_pages; + if (n > req_size) { + ret = true; + spin_unlock(&sis->lock); + goto unlock; + } + } + spin_unlock(&sis->lock); + } + } + +unlock: + spin_unlock(&swap_lock); + return ret; +} + +extern int do_swap_page(struct vm_fault *vmf); +#if MEMEX_DEBUG +static int memplus_swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, + unsigned long end, struct mm_walk *walk) +{ + pte_t *orig_pte; + struct vm_area_struct *vma = walk->private; + unsigned long index; + int ret = 0; + + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) + return 0; + + for (index = start; index != end; index += PAGE_SIZE) { + pte_t pte; + swp_entry_t entry; + struct page *page; + spinlock_t *ptl; + + if (!list_empty(&vma->vm_mm->mmap_sem.wait_list)) + return -1; + + orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, start, &ptl); + pte = *(orig_pte + ((index - start) / PAGE_SIZE)); + pte_unmap_unlock(orig_pte, ptl); + + if (pte_present(pte) || pte_none(pte)) + continue; + entry = pte_to_swp_entry(pte); + if (unlikely(non_swap_entry(entry))) + continue; + + if (is_fast_entry(entry)) { + struct vm_fault fe = { + .vma = vma, + .pte = &pte, + .orig_pte = pte, + .address = index, + .flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT, + .pmd = pmd, + .vma_flags = vma->vm_flags, + .vma_page_prot = vma->vm_page_prot, + }; + + ret = do_swap_page(&fe); + if (ret & VM_FAULT_ERROR) { + printk(KERN_ERR "%s: do_swap_page ERROR\n", __func__); + return -1; + } + continue; + } else + page = read_swap_cache_async(entry, GFP_HIGHUSER_MOVABLE, + vma, index, false); + if (page) + put_page(page); + } + + return 0; +} +#endif + +static int memplus_reclaim_pte(pmd_t *pmd, unsigned long addr, + unsigned long end, struct mm_walk *walk) +{ + struct mp_reclaim_param *rp = walk->private; + struct vm_area_struct *vma = rp->vma; + pte_t *pte, ptent; + spinlock_t *ptl; + struct page *page; + LIST_HEAD(page_list); + int isolated; + int reclaimed = 0; + int reclaim_type = rp->type; + + split_huge_pmd(vma, addr, pmd); + if (pmd_trans_unstable(pmd) || !rp->nr_to_reclaim) + return 0; +cont: + isolated = 0; + pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); + for (; addr != end; pte++, addr += PAGE_SIZE) { + ptent = *pte; + if (!pte_present(ptent)) + continue; + + page = vm_normal_page(vma, addr, ptent); + if (!page) + continue; + + if ((reclaim_type == TYPE_NORMAL) && PageSwapCache(page)) + continue; + + /* About 11% of pages have more than 1 map_count + * only take care mapcount == 1 is good enough */ + if (page_mapcount(page) != 1) + continue; + + if (isolate_lru_page(page)) + continue; + + if (PageAnon(page) && !PageSwapBacked(page)) { + putback_lru_page(page); + continue; + } + + list_add(&page->lru, &page_list); + inc_node_page_state(page, NR_ISOLATED_ANON + + page_is_file_cache(page)); + isolated++; + rp->nr_scanned++; + + if ((isolated >= SWAP_CLUSTER_MAX) || !rp->nr_to_reclaim) + break; + } + pte_unmap_unlock(pte - 1, ptl); + + memplus_add_to_swap += isolated; + + reclaimed = swapout_to_zram(&page_list, vma); + + rp->nr_reclaimed += reclaimed; + rp->nr_to_reclaim -= reclaimed; + if (rp->nr_to_reclaim < 0) + rp->nr_to_reclaim = 0; + + if (rp->nr_to_reclaim && (addr != end)) + goto cont; + + /* TODO: is there other reschedule point we can add */ + cond_resched(); + + return 0; +} + +#if MEMEX_DEBUG +static ssize_t memex_do_swapin_anon(struct task_struct *task) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk walk = {}; + int task_anon = 0, task_swap = 0, err = 0; + +retry: + mm = get_task_mm(task); + if (!mm) + goto out; + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + walk.mm = mm; + walk.pmd_entry = memplus_swapin_walk_pmd_entry; + + down_read(&mm->mmap_sem); + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + walk.private = vma; + err = walk_page_range(vma->vm_start, vma->vm_end, &walk); + if (err == -1) + break; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + mmput(mm); + if (err) { + err = 0; +#if MEMEX_DEBUG + /* TODO: it's possible to loop forever here + * if we're swapin camera which is foreground actively used */ +#endif + goto retry; + } +out: + lru_add_drain(); /* Push any new pages onto the LRU now */ + return 0; +} +#endif + +/* get_task_struct before using this function */ +static ssize_t memex_do_reclaim_anon(struct task_struct *task, int prev_adj) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk reclaim_walk = {}; + struct mp_reclaim_param rp; + int task_anon = 0, task_swap = 0; + int a_task_anon = 0, a_task_swap = 0; + +#if DEBUG_TIME_INFO + struct timespec ts1, ts2; + getnstimeofday(&ts1); +#endif +#if FEAT_RECLAIM_LIMIT + rp.start_jiffies = jiffies; +#endif + rp.nr_to_reclaim = INT_MAX; + rp.nr_reclaimed = 0; + rp.nr_scanned = 0; + /* memex currently use zram by default */ + rp.type = TYPE_FREQUENT; + + /* if available zram is less than 32MB, quit early */ + if (!enough_swap_size(8192, TYPE_FREQUENT)) + goto out; + + /* TODO: do we need to use p = find_lock_task_mm(tsk); in case main thread got killed */ + mm = get_task_mm(task); + if (!mm) + goto out; + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + reclaim_walk.mm = mm; + reclaim_walk.pmd_entry = memplus_reclaim_pte; + reclaim_walk.private = &rp; + + down_read(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + rp.vma = vma; + + /* TODO: do we need this check? */ + if (!list_empty(&vma->vm_mm->mmap_sem.wait_list)) { +#if MEMEX_DEBUG + pr_info("MemEX mmap_sem waiting %s(%d)\n", task->comm, task->pid); +#endif + break; + } + + walk_page_range(vma->vm_start, vma->vm_end, + &reclaim_walk); + + if (!rp.nr_to_reclaim) + break; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + a_task_anon = get_mm_counter(mm, MM_ANONPAGES); + a_task_swap = get_mm_counter(mm, MM_SWAPENTS); + mmput(mm); +out: +#if DEBUG_TIME_INFO + getnstimeofday(&ts2); + ts2 = timespec_sub(ts2, ts1); + time_ns = timespec_to_ns(&ts2); +#endif + /* TODO : return proper value */ + return rp.nr_reclaimed; +} + +static inline bool should_skip(const char *comm) +{ + if (!vm_cam_aware) + return false; + /* provider@2.4-se, camera@1.0-serv, cameraserver, .camera.service, ctureprocessing, .oneplus.camera */ + return strnstr(comm, "camera", TASK_COMM_LEN) + || !strncmp("provider@2.4-se", comm, TASK_COMM_LEN) + || !strncmp("ctureprocessing", comm, TASK_COMM_LEN); +} + +static int memex_fn(void *p) +{ + struct task_struct *tsk; + int i, idx_sys, idx_app; + cpumask_t tmask; + + /* setup nice: 130 cpumask: 0x3f */ + cpumask_parse("3f", &tmask); + set_cpus_allowed_ptr(current, &tmask); + set_user_nice(current, 10); + + set_freezable(); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + + idx_sys = 0; + idx_app = MEMEX_SIZE - 1; + memset(memex_proc, 0, sizeof(memex_proc)); + + rcu_read_lock(); + for_each_process(tsk) { + if (tsk->flags & PF_KTHREAD) + continue; + + /* TODO: do we need this check? */ + if (should_skip(tsk->comm)) + continue; + + if (task_uid(tsk).val >= AID_APP) { + memex_proc[idx_app--] = tsk->pid; + } else { + memex_proc[idx_sys++] = tsk->pid; + } + + if (unlikely(idx_sys > idx_app)) + break; + } +#if MEMEX_DEBUG + pr_info("MemEX sys=%d app=%d\n", idx_sys, idx_app); +#endif + rcu_read_unlock(); + + for (i = 0; i < MEMEX_SIZE; i++) { + int pid = memex_proc[i]; + + while (memex_threshold && memex_threshold <= (si_mem_available() * PAGE_SIZE / (1024 * 1024))) { +#if MEMEX_DEBUG + pr_info("MemEX thresh = %u, MemAvail = %u\n" + , memex_threshold, (si_mem_available() * PAGE_SIZE / (1024 * 1024))); +#endif + freezable_schedule_timeout_interruptible(HZ / 30); + } + + /* monitor current mode change */ + if (unlikely(!memex_threshold)) + break; + + if (pid == 0) + continue; + + rcu_read_lock(); + tsk = find_task_by_vpid(pid); + if (!tsk) { + rcu_read_unlock(); + continue; + } + get_task_struct(tsk); + rcu_read_unlock(); +#if MEMEX_DEBUG + pr_info("MemEX processing %s (%d) \n", tsk->comm, tsk->pid); + if (vm_swapin) + memex_do_swapin_anon(tsk); + else +#endif + memex_do_reclaim_anon(tsk, 0); + put_task_struct(tsk); + } + + if (kthread_should_stop()) + break; + } + return 0; +} + +static int __init memplus_init(void) +{ + //TODO: priority tuning for reclaimd/swapind + + memex_tsk = kthread_run(memex_fn, 0, "memex"); + if (IS_ERR(memex_tsk)) { + pr_err("Failed to start memex_task\n"); + memex_tsk = NULL; + } + + return 0; +} + +/* return value mapping: + * 0 - success + * ESRCH - no MemEx daemon + * EINVAL- invalid input + */ +static int memory_plus_wake_memex_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (!memex_tsk) + return -ESRCH; + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + memex_threshold = val; + if (val) + wake_up_process(memex_tsk); + + return 0; +} + +static int memory_plus_wake_memex_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", memex_threshold); +} + +static struct kernel_param_ops memory_plus_wake_memex_ops = { + .set = memory_plus_wake_memex_store, + .get = memory_plus_wake_memex_show, +}; + +module_param_cb(memory_plus_wake_memex, &memory_plus_wake_memex_ops, NULL, 0644); + +module_param_named(memory_plus_enabled, vm_memory_plus, uint, S_IRUGO | S_IWUSR); +module_param_named(memplus_add_to_swap, memplus_add_to_swap, ulong, S_IRUGO | S_IWUSR); +module_param_named(memory_plus_cam_aware, vm_cam_aware, uint, S_IRUGO | S_IWUSR); + +module_init(memplus_init) diff --git a/drivers/oneplus/coretech/memex_standalone_support/core/memex_standalone_core.h b/drivers/oneplus/coretech/memex_standalone_support/core/memex_standalone_core.h new file mode 100644 index 0000000000000000000000000000000000000000..c77ecc9f89b91e5cf54eb036d4fe798fe035d7e3 --- /dev/null +++ b/drivers/oneplus/coretech/memex_standalone_support/core/memex_standalone_core.h @@ -0,0 +1,22 @@ +#ifndef _MEMORY_PLUS_H +#define _MEMORY_PLUS_H +#define AID_APP 10000 /* first app user */ + +enum { + RECLAIM_STANDBY, + RECLAIM_QUEUE, + RECLAIM_DONE, + SWAPIN_QUEUE, + GC_RECLAIM_QUEUE, +}; + +enum { + TYPE_NORMAL, + TYPE_FREQUENT, + TYPE_SYS_IGNORE, + TYPE_WILL_NEED, + TYPE_END +}; +#define MEMPLUS_TYPE_MASK 0x7 + +#endif /* _MEMORY_PLUS_H */ diff --git a/drivers/oneplus/coretech/memplus/Makefile b/drivers/oneplus/coretech/memplus/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2bff8d58cde398493f8e2a2499f629f79bb3c8dd --- /dev/null +++ b/drivers/oneplus/coretech/memplus/Makefile @@ -0,0 +1 @@ +obj-y += memplus_helper.o diff --git a/drivers/oneplus/coretech/memplus/core/Makefile b/drivers/oneplus/coretech/memplus/core/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cad044c7e1e31c408fc6251a8152eeb465f20160 --- /dev/null +++ b/drivers/oneplus/coretech/memplus/core/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MEMPLUS) += memplus_core.o diff --git a/drivers/oneplus/coretech/memplus/core/memplus.h b/drivers/oneplus/coretech/memplus/core/memplus.h new file mode 100644 index 0000000000000000000000000000000000000000..69e8baedf2470b99d4a5ab8db47803d611db6173 --- /dev/null +++ b/drivers/oneplus/coretech/memplus/core/memplus.h @@ -0,0 +1,23 @@ +#ifndef _MEMORY_PLUS_H +#define _MEMORY_PLUS_H +#include +#define AID_APP 10000 /* first app user */ + +enum { + RECLAIM_STANDBY, + RECLAIM_QUEUE, + RECLAIM_DONE, + SWAPIN_QUEUE, + GC_RECLAIM_QUEUE, +}; + +enum { + TYPE_NORMAL, + TYPE_FREQUENT, + TYPE_SYS_IGNORE, + TYPE_WILL_NEED, + TYPE_END +}; +#define MEMPLUS_TYPE_MASK 0x7 + +#endif /* _MEMORY_PLUS_H */ diff --git a/drivers/oneplus/coretech/memplus/core/memplus_core.c b/drivers/oneplus/coretech/memplus/core/memplus_core.c new file mode 100644 index 0000000000000000000000000000000000000000..39e5216b41df63a74b0880f7b5764cc5b2a765cf --- /dev/null +++ b/drivers/oneplus/coretech/memplus/core/memplus_core.c @@ -0,0 +1,1698 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "memplus.h" +#include +#include + +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page);}) + +#define MEMEX_SIZE 512 +#define MEMEX_DEBUG 0 +#define GC_SIZE 1024 +#define DEBUG_GCD 0 /*print gcd info */ +#define GCD_SST 0 /* stress test */ +#define RD_SIZE 128 +#define DEBUG_TIME_INFO 0 +#define FEAT_RECLAIM_LIMIT 0 +#define MEMPLUS_GET_ANON_MEMORY _IOWR('a', 1, unsigned long) +#define MEMPLUS_RECLAIM_ANON_MEMORY _IOWR('a', 2, unsigned long) +#define MEMPLUS_SWAPIN_ANON_MEMORY _IOWR('a', 3, unsigned long) +#define MEMPLUS_GET_AVAILABLE_SWAP_SPACE _IOWR('a', 4, unsigned long) + +#if defined(CONFIG_DRM_PANEL) +extern struct drm_panel *lcd_active_panel; +#endif + +struct mp_reclaim_param { + struct vm_area_struct *vma; + /* Number of pages scanned */ + int nr_scanned; +#if FEAT_RECLAIM_LIMIT + unsigned long start_jiffies; +#endif + /* max pages to reclaim */ + int nr_to_reclaim; + /* pages reclaimed */ + int nr_reclaimed; + int type; +}; + +struct reclaim_data { + pid_t pid; + int prev_adj; +}; + +struct reclaim_info { + struct reclaim_data rd[RD_SIZE]; + int i_idx; + int o_idx; + int count; +}; + +struct reclaim_info ri = { {{0}}, 0, 0, 0 }; +struct reclaim_info si = { {{0}}, 0, 0, 0 }; +static struct task_struct *reclaimd_tsk = NULL; +static struct task_struct *swapind_tsk = NULL; +static DEFINE_SPINLOCK(rd_lock); + +static atomic64_t accu_display_on_jiffies = ATOMIC64_INIT(0); +static struct notifier_block memplus_notify; +static unsigned long display_on_jiffies; +static pid_t proc[GC_SIZE] = { 0 }; +static struct task_struct *gc_tsk; +static bool display_on = true; + +/* MemEx mode */ +static struct task_struct *memex_tsk; +static unsigned int memex_threshold __read_mostly; +static pid_t memex_proc[MEMEX_SIZE]; +static unsigned int vm_cam_aware __read_mostly = 1; +#if MEMEX_DEBUG +static unsigned int vm_swapin __read_mostly = 0; +module_param_named(memory_plus_swapin, vm_swapin, uint, S_IRUGO | S_IWUSR); +#endif + +/* -1 = system free to use swap, 0 = disable retention, swap not available, 1 = enable retention */ +static int vm_memory_plus __read_mostly = 0; +static unsigned long memplus_add_to_swap = 0; +unsigned long coretech_reclaim_pagelist(struct list_head *page_list, struct vm_area_struct *vma, void *sc); +unsigned long swapout_to_zram(struct list_head *page_list, struct vm_area_struct *vma); +unsigned long swapout_to_disk(struct list_head *page_list, struct vm_area_struct *vma); + +static inline bool current_is_gcd(void) +{ + return current == gc_tsk; +} + +bool ctech_current_is_swapind() { + return current == swapind_tsk; +} + +bool ctech_memplus_check_isolate_page(struct page*page) +{ + return (memplus_enabled() && (!PageSwapCache(page) || PageWillneed(page))); +} + +static bool is_fast_entry(swp_entry_t entry) +{ + struct swap_info_struct *p; + bool ret = false; + unsigned long offset, type; + + if (!entry.val) + goto out; + type = swp_type(entry); + p = swap_info[type]; + if (!(p->flags & SWP_USED)) + goto out; + offset = swp_offset(entry); + if (offset >= p->max) + goto out; + + spin_lock(&p->lock); + if (p->flags & SWP_SYNCHRONOUS_IO) + ret = true; + spin_unlock(&p->lock); +out: + return ret; +} +static int enough_swap_size_mask(unsigned long req_size) +{ + int ret_mask = 0x0; + unsigned int n = 0; + struct swap_info_struct *sis, *next; + unsigned int node = numa_node_id(); + + spin_lock(&swap_lock); + plist_for_each_entry_safe(sis, next, &swap_avail_heads[node], avail_lists[node]) { + int fast_i = (sis->flags & SWP_SYNCHRONOUS_IO) ? 1:0; + + spin_lock(&sis->lock); + if (sis->flags & SWP_WRITEOK) { + n += sis->pages - sis->inuse_pages; + if (n > req_size) + ret_mask |= (1 << fast_i); + } + spin_unlock(&sis->lock); + } + spin_unlock(&swap_lock); + return ret_mask; +} +static bool enough_swap_size(unsigned long req_size, int swap_bdv) +{ + bool ret = false; + unsigned int n = 0; + struct swap_info_struct *sis, *next; + unsigned int node = numa_node_id(); + + if (swap_bdv > 1) + return ret; + + spin_lock(&swap_lock); + plist_for_each_entry_safe(sis, next, &swap_avail_heads[node], avail_lists[node]) { + int fast_i = (sis->flags & SWP_SYNCHRONOUS_IO)? 1:0; + + if (fast_i == swap_bdv) { + spin_lock(&sis->lock); + if (sis->flags & SWP_WRITEOK) { + n += sis->pages - sis->inuse_pages; + if (n > req_size) { + ret = true; + spin_unlock(&sis->lock); + goto unlock; + } + } + spin_unlock(&sis->lock); + } + } + +unlock: + spin_unlock(&swap_lock); + return ret; +} + +__always_inline void ctech_memplus_move_swapcache_to_anon_lru(struct page *page) +{ + struct zone *zone = page_zone(page); + unsigned long flag; + + if (memplus_enabled()) { + spin_lock_irqsave(zone_lru_lock(zone), flag); + if (PageLRU(page)) { + struct lruvec *lruvec; + enum lru_list lru, oldlru = page_lru(page); + + clear_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); + lru = page_lru(page); + lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); + list_move(&page->lru, &lruvec->lists[lru]); + update_lru_size(lruvec, oldlru, page_zonenum(page), -hpage_nr_pages(page)); + update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); + } else + clear_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); + spin_unlock_irqrestore(zone_lru_lock(zone), flag); + }else + clear_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); +} + +__always_inline void ctech_memplus_move_anon_to_swapcache_lru(struct page *page) +{ + struct zone *zone = page_zone(page); + unsigned long flag; + + if (memplus_enabled()) { + spin_lock_irqsave(zone_lru_lock(zone), flag); + if (likely(!PageLRU(page))) + set_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); + else { + struct lruvec *lruvec; + enum lru_list lru, oldlru = page_lru(page); + + set_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); + lru = page_lru(page); + lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); + list_move(&page->lru, &lruvec->lists[lru]); + update_lru_size(lruvec, oldlru, page_zonenum(page), -hpage_nr_pages(page)); + update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); + } + spin_unlock_irqrestore(zone_lru_lock(zone), flag); + } else + set_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); +} +extern int do_swap_page(struct vm_fault *vmf); +static int memplus_swapin_walk_pmd_entry(pmd_t *pmd, unsigned long start, + unsigned long end, struct mm_walk *walk) +{ + pte_t *orig_pte; + struct vm_area_struct *vma = walk->private; + unsigned long index; + int ret = 0; + + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) + return 0; + + for (index = start; index != end; index += PAGE_SIZE) { + pte_t pte; + swp_entry_t entry; + struct page *page; + spinlock_t *ptl; + + if (!list_empty(&vma->vm_mm->mmap_sem.wait_list)) + return -1; + + orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, start, &ptl); + pte = *(orig_pte + ((index - start) / PAGE_SIZE)); + pte_unmap_unlock(orig_pte, ptl); + + if (pte_present(pte) || pte_none(pte)) + continue; + entry = pte_to_swp_entry(pte); + if (unlikely(non_swap_entry(entry))) + continue; + + if (is_fast_entry(entry)) { + struct vm_fault fe = { + .vma = vma, + .pte = &pte, + .orig_pte = pte, + .address = index, + .flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT, + .pmd = pmd, + .vma_flags = vma->vm_flags, + .vma_page_prot = vma->vm_page_prot, + }; + + ret = do_swap_page(&fe); + if (ret & VM_FAULT_ERROR) { + printk(KERN_ERR "%s: do_swap_page ERROR\n", __func__); + return -1; + } + continue; + } else + page = read_swap_cache_async(entry, GFP_HIGHUSER_MOVABLE, + vma, index, false); + if (page) + put_page(page); + } + + return 0; +} + +static void enqueue_reclaim_data(pid_t nr, int prev_adj, struct reclaim_info *info) +{ + int idx; + struct task_struct *waken_task; + + waken_task = (info == &ri? reclaimd_tsk : swapind_tsk); + if (!waken_task) + return; + + spin_lock(&rd_lock); + if (info->count < RD_SIZE) { + info->count++; + idx = info->i_idx++ % RD_SIZE; + info->rd[idx].pid = nr; + info->rd[idx].prev_adj = prev_adj; + } + spin_unlock(&rd_lock); + BUG_ON(info->count > RD_SIZE || info->count < 0); + + if (waken_task->state == TASK_INTERRUPTIBLE) + wake_up_process(waken_task); +} + +bool ctech_memplus_enabled(void) +{ + return vm_memory_plus > 0 && total_swap_pages; +} + +__always_inline bool ctech__memplus_enabled(void) +{ + return vm_memory_plus > 0; +} + +static void __memplus_state_check(int cur_adj, int prev_adj, struct task_struct* task) +{ + int uid = task_uid(task).val; + + if (!memplus_enabled()) + return; + + /* special case that SmartBoost toggle disables this feature */ + if (vm_memory_plus == 2) + goto queue_swapin; + + if (task->signal->memplus_type == TYPE_SYS_IGNORE) + return; + + if (task->signal->memplus_type == TYPE_WILL_NEED) + goto queue_swapin; + + if (unlikely((prev_adj == -1) || (cur_adj == prev_adj))) + return; + + if (uid < AID_APP) { + //trace_printk("QUIT-reclaim %s (pid %d) (adj %d -> %d) (uid %d)\n", task->comm, task->pid, prev_adj, cur_adj, uid); + return; + } + + if (cur_adj >= 800 && time_after_eq(jiffies, task->signal->reclaim_timeout)) { + spin_lock(&task->signal->reclaim_state_lock); + /* reclaim should not kick-in within 2 secs */ + task->signal->reclaim_timeout = jiffies + 2*HZ; + + if (task->signal->swapin_should_readahead_m == RECLAIM_STANDBY) { + task->signal->swapin_should_readahead_m = RECLAIM_QUEUE; + //trace_printk("Q-reclaim %s (pid %d) (adj %d -> %d) (uid %d)\n", task->comm, task->pid, prev_adj, cur_adj, uid); + enqueue_reclaim_data(task->pid, prev_adj, &ri); + } + spin_unlock(&task->signal->reclaim_state_lock); + } else if (cur_adj == 0) { +queue_swapin: + spin_lock(&task->signal->reclaim_state_lock); + if (task->signal->swapin_should_readahead_m == RECLAIM_QUEUE) { + task->signal->reclaim_timeout = jiffies + 2*HZ; + task->signal->swapin_should_readahead_m = RECLAIM_STANDBY; + } else if (task->signal->swapin_should_readahead_m == RECLAIM_DONE) { + task->signal->reclaim_timeout = jiffies + 2*HZ; + task->signal->swapin_should_readahead_m = SWAPIN_QUEUE; + //trace_printk("Q-swapin %s (pid %d) (adj %d -> %d) (uid %d)\n", task->comm, task->pid, prev_adj, cur_adj, uid); + enqueue_reclaim_data(task->pid, prev_adj, &si); + } + spin_unlock(&task->signal->reclaim_state_lock); + } +} + +void ctech_memplus_state_check(bool legacy, int oom_adj, struct task_struct *task, int type, int update) +{ + int oldadj = task->signal->oom_score_adj; + + if (update) { + if (type >= TYPE_END || type < 0) + return; + task->signal->memplus_type = type; + + if (type == TYPE_WILL_NEED) + oom_adj = 0; + else if ((type & MEMPLUS_TYPE_MASK) < TYPE_SYS_IGNORE) + oom_adj = oldadj; + else + return; + } + + if (!legacy && (oom_adj >= 800 || oom_adj == 0)) + __memplus_state_check(oom_adj, oldadj, task); +} + +static bool dequeue_reclaim_data(struct reclaim_data *data, struct reclaim_info *info) +{ + int idx; + bool has_data = false; + + spin_lock(&rd_lock); + if (info->count > 0) { + has_data = true; + info->count--; + idx = info->o_idx++ % RD_SIZE; + *data = info->rd[idx]; + } + spin_unlock(&rd_lock); + BUG_ON(info->count > RD_SIZE || info->count < 0); + + return has_data; +} + +static ssize_t swapin_anon(struct task_struct *task, int prev_adj) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk walk = {}; + int task_anon = 0, task_swap = 0, err = 0; + //u64 time_ns = 0; +#if DEBUG_TIME_INFO + struct timespec ts1, ts2; + getnstimeofday(&ts1); +#endif + +retry: + /* TODO: do we need to use p = find_lock_task_mm(tsk); in case main thread got killed */ + mm = get_task_mm(task); + if (!mm) + goto out; + + /* system pid may reach its max value and this pid was reused by other process */ + if (unlikely(task->signal->swapin_should_readahead_m != SWAPIN_QUEUE)) { + mmput(mm); + return 0; + } + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + /* swapin only for large APP, flip 33000, bow 60000, eightpoll 16000 */ + if (task_swap <= 10000) { + mmput(mm); + //trace_printk("SMALL swapin: this task is too small\n"); + goto out; + } + + walk.mm = mm; + walk.pmd_entry = memplus_swapin_walk_pmd_entry; + + down_read(&mm->mmap_sem); + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (vma->memplus_flags) + continue; + + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + walk.private = vma; + err = walk_page_range(vma->vm_start, vma->vm_end, &walk); + if (err == -1) + break; + vma->memplus_flags = 1; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + mmput(mm); + if (err) { + err = 0; + //schedule(); + goto retry; + } +out: + /* TODO */ + lru_add_drain(); /* Push any new pages onto the LRU now */ +#if DEBUG_TIME_INFO + getnstimeofday(&ts2); + ts2 = timespec_sub(ts2, ts1); + time_ns = timespec_to_ns(&ts2); +#endif + //trace_printk("%s (pid %d)(size %d-%d) (adj %d -> %d) consumed %llu ms %llu us\n", task->comm, task->pid, task_anon, task_swap, prev_adj, task->signal->oom_score_adj, (time_ns/1000000), (time_ns/1000)%1000); + + spin_lock(&task->signal->reclaim_state_lock); + task->signal->swapin_should_readahead_m = RECLAIM_STANDBY; + spin_unlock(&task->signal->reclaim_state_lock); + + return 0; +} + +//TODO: blk_plug don't seem to work +static int swapind_fn(void *p) +{ + struct reclaim_data data; + struct task_struct *tsk; + + set_freezable(); + for ( ; ; ) { + while (!pm_freezing && dequeue_reclaim_data(&data, &si)) { + rcu_read_lock(); + tsk = find_task_by_vpid(data.pid); + + /* KTHREAD is almost impossible to hit this */ + //if (tsk->flags & PF_KTHREAD) { + // rcu_read_unlock(); + // continue; + //} + + if (!tsk) { + rcu_read_unlock(); + continue; + } + + get_task_struct(tsk); + rcu_read_unlock(); + + swapin_anon(tsk, data.prev_adj); + put_task_struct(tsk); + } + + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + + if (kthread_should_stop()) + break; + } + + return 0; +} + +static int memplus_reclaim_pte(pmd_t *pmd, unsigned long addr, + unsigned long end, struct mm_walk *walk) +{ + struct mp_reclaim_param *rp = walk->private; + struct vm_area_struct *vma = rp->vma; + pte_t *pte, ptent; + spinlock_t *ptl; + struct page *page; + LIST_HEAD(page_list); + int isolated; + int reclaimed = 0; + int reclaim_type = rp->type; + bool check_event = current_is_gcd(); +#if defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + struct page_ext *page_ext; +#endif + + split_huge_pmd(vma, addr, pmd); + if (pmd_trans_unstable(pmd) || !rp->nr_to_reclaim) + return 0; +cont: + isolated = 0; + pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); + for (; addr != end; pte++, addr += PAGE_SIZE) { + ptent = *pte; + if (!pte_present(ptent)) + continue; + + page = vm_normal_page(vma, addr, ptent); + if (!page) + continue; + + if (check_event) { +#if defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + page_ext = lookup_page_ext(page); + if (unlikely(!page_ext)) + continue; + + /* gc_tsk should respect countdown event */ + if ((page_ext->next_event > 0) && (--(page_ext->next_event) > 0)) + continue; +#else + /* gc_tsk should respect countdown event */ + if ((page->next_event > 0) && (--(page->next_event) > 0)) + continue; +#endif + } + + ClearPageWillneed(page); + + if ((reclaim_type == TYPE_NORMAL) && PageSwapCache(page)) + continue; + + /* About 11% of pages have more than 1 map_count + * only take care mapcount == 1 is good enough */ + if (page_mapcount(page) != 1) + continue; + + if (isolate_lru_page(page)) + continue; + + if (PageAnon(page) && !PageSwapBacked(page)) { + putback_lru_page(page); + continue; + } + + list_add(&page->lru, &page_list); + inc_node_page_state(page, NR_ISOLATED_ANON + + page_is_file_cache(page)); + isolated++; + rp->nr_scanned++; + + if ((isolated >= SWAP_CLUSTER_MAX) || !rp->nr_to_reclaim) + break; + } + pte_unmap_unlock(pte - 1, ptl); + + memplus_add_to_swap += isolated; + + if (reclaim_type == TYPE_NORMAL && !enough_swap_size(isolated, TYPE_NORMAL)) + reclaim_type = TYPE_FREQUENT; + + if (reclaim_type == TYPE_NORMAL) + reclaimed = swapout_to_disk(&page_list, vma); + else if (reclaim_type == TYPE_FREQUENT) + reclaimed = swapout_to_zram(&page_list, vma); + else { + if (!current_is_gcd()) + pr_info_ratelimited("!! %s(%d) is reclaiming unexpected task type (%d)\n" + , current->comm, current->pid, reclaim_type); + reclaimed = swapout_to_zram(&page_list, vma); + } + + rp->nr_reclaimed += reclaimed; + rp->nr_to_reclaim -= reclaimed; + if (rp->nr_to_reclaim < 0) + rp->nr_to_reclaim = 0; + +#if FEAT_RECLAIM_LIMIT + /* TODO: early quit */ + /* timeout (range from 10~20ms), emergency quit back to reclaim_anon() */ + /* statistics shows 90% of reclaim finish within 60ms, should be a good timeout value */ + /* statistics shows 80% of reclaim finish within 26ms, should be a good timeout value */ + /* statistics shows 77% of reclaim finish within 20ms, should be a good timeout value */ + /* statistics shows 68% of reclaim finish within 10ms, should be a good timeout value */ + //if (time_after_eq(jiffies, rp->start_jiffies + 2)) { + // rp->nr_to_reclaim = 0; + // return 1; + //} + + /* this will make black screen shorter */ + //if (rp->nr_reclaimed > 2000) { + // rp->nr_to_reclaim = 0; + // return 1; + //} +#endif + + if (rp->nr_to_reclaim && (addr != end)) + goto cont; + + /* TODO: is there other reschedule point we can add */ + cond_resched(); + + return 0; +} + +/* get_task_struct before using this function */ +static ssize_t reclaim_anon(struct task_struct *task, int prev_adj) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk reclaim_walk = {}; + struct mp_reclaim_param rp; + int task_anon = 0, task_swap = 0; + int a_task_anon = 0, a_task_swap = 0; + + //u64 time_ns = 0; +#if DEBUG_TIME_INFO + struct timespec ts1, ts2; + getnstimeofday(&ts1); +#endif +#if FEAT_RECLAIM_LIMIT + rp.start_jiffies = jiffies; +#endif + rp.nr_to_reclaim = INT_MAX; + rp.nr_reclaimed = 0; + rp.nr_scanned = 0; + + spin_lock(&task->signal->reclaim_state_lock); + if (task->signal->swapin_should_readahead_m == GC_RECLAIM_QUEUE) { + spin_unlock(&task->signal->reclaim_state_lock); + goto gc_proceed; + } + /*TODO: additional handle for PF_EXITING do_exit()->exit_signal()*/ + if (task->signal->swapin_should_readahead_m != RECLAIM_QUEUE) { + //trace_printk("EXIT reclaim: this task is either (reclaimed) or (adj 0 swapin)\n"); + spin_unlock(&task->signal->reclaim_state_lock); + goto out; + } + task->signal->swapin_should_readahead_m = RECLAIM_DONE; + spin_unlock(&task->signal->reclaim_state_lock); + +gc_proceed: + /* TODO: do we need to use p = find_lock_task_mm(tsk); in case main thread got killed */ + mm = get_task_mm(task); + if (!mm) + goto out; + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + reclaim_walk.mm = mm; + reclaim_walk.pmd_entry = memplus_reclaim_pte; + + /* if app is larger than 200MB, override its property to frequent */ + if (task_anon + task_swap > 51200) { + rp.type = TYPE_FREQUENT; + } else + rp.type = task->signal->memplus_type; + + reclaim_walk.private = &rp; + + down_read(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + if (!current_is_gcd() && task->signal->swapin_should_readahead_m != RECLAIM_DONE) + break; + + rp.vma = vma; + walk_page_range(vma->vm_start, vma->vm_end, + &reclaim_walk); + + vma->memplus_flags = 0; + if (!rp.nr_to_reclaim) + break; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + a_task_anon = get_mm_counter(mm, MM_ANONPAGES); + a_task_swap = get_mm_counter(mm, MM_SWAPENTS); + mmput(mm); +out: +#if DEBUG_TIME_INFO + getnstimeofday(&ts2); + ts2 = timespec_sub(ts2, ts1); + time_ns = timespec_to_ns(&ts2); +#endif + /* it's possible that rp data isn't initialized because mm don't exist */ + //trace_printk("%s (pid %d)(size %d-%d to %d-%d) (adj %d -> %d) reclaimed %d scan %d consumed %llu ms %llu us\n" + // , task->comm, task->pid, task_anon, task_swap, a_task_anon, a_task_swap + // , prev_adj, task->signal->oom_score_adj, rp.nr_reclaimed, rp.nr_scanned + // , (time_ns/1000000), (time_ns/1000)%1000); + + /* TODO : return proper value */ + return rp.nr_reclaimed; +} + +//TODO: should we mark reclaimd/swapind freezable? +static int reclaimd_fn(void *p) +{ + struct reclaim_data data; + struct task_struct *tsk; + + set_freezable(); + for ( ; ; ) { + while (!pm_freezing && dequeue_reclaim_data(&data, &ri)) { + rcu_read_lock(); + tsk = find_task_by_vpid(data.pid); + + /* KTHREAD is almost impossible to hit this */ + //if (tsk->flags & PF_KTHREAD) { + // rcu_read_unlock(); + // continue; + //} + + if (!tsk) { + rcu_read_unlock(); + continue; + } + + get_task_struct(tsk); + rcu_read_unlock(); + + do { + msleep(30); + } while (swapind_tsk && (swapind_tsk->state == TASK_RUNNING)); + + reclaim_anon(tsk, data.prev_adj); + put_task_struct(tsk); + } + + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + + if (kthread_should_stop()) + break; + } + return 0; +} + +/* do_swap_page() hook */ +static void ctech_memplus_next_event(struct page *page) +{ + unsigned long ret; +#if defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + struct page_ext *page_ext; +#endif + + /* skip if handled by reclaimd or current is swapind */ + if (current->signal->reclaim_timeout) + return; + +#if defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + page_ext = lookup_page_ext(page); + if (unlikely(!page_ext)) + return; +#endif + + /* next_event value + * 0 : gc always reclaim / default + * 1 : gc at next event + * N : N <= 7, countdown N to do gc + */ + ret = (atomic64_read(&accu_display_on_jiffies) + + (display_on ? (jiffies - display_on_jiffies) : 0)) / (3600 * HZ); + ret = ret >= 6 ? 1 : (7 - ret); + +#if defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + page_ext->next_event = ret; +#else + page->next_event = ret; +#endif +} + +static noinline void wait_for_suspend(void) +{ +#if GCD_SST + return; +#endif + /* wait until user-space process all freezed */ + while (!pm_nosig_freezing) { +#if DEBUG_GCD + pr_info("gc wait for suspend\n"); +#endif + /* suspend freezer only wake TASK_INTERRUPTIBLE */ + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + atomic64_set(&accu_display_on_jiffies, 0); +#if DEBUG_GCD + pr_info("gc finish waiting suspend\n"); +#endif + } +} + +#if defined(CONFIG_DRM_PANEL) +static int memplus_notifier_callback(struct notifier_block *nb, unsigned long event, void *data) +{ + int blank; + struct drm_panel_notifier *evdata = data; + static int old_status = -1; + + if (evdata && evdata->data) { + blank = *(int *)(evdata->data); +#if DEBUG_GCD + pr_info("event = %d blank = %d", event, blank); +#endif + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { + if (old_status == blank) + return 0; + switch (blank) { + case DRM_PANEL_BLANK_UNBLANK: + old_status = blank; + display_on = true; + display_on_jiffies = jiffies; +#if DEBUG_GCD + pr_info("display ON\n"); +#endif + break; + case DRM_PANEL_BLANK_POWERDOWN: + old_status = blank; + atomic64_add((jiffies - display_on_jiffies), &accu_display_on_jiffies); +#if DEBUG_GCD + pr_info("display OFF\n"); +#endif +#if GCD_SST + wake_up_process(gc_tsk); +#endif + display_on = false; + break; + default: + break; + } + } + } + return 0; +} +#endif + +/* return current status */ +static inline bool register_notifier(void) +{ + static bool initialized; +#if defined(CONFIG_DRM_PANEL) + int status; +#endif + + if (likely(initialized)) + goto out; +#if defined(CONFIG_DRM_PANEL) + if (!lcd_active_panel) { + pr_err("register drm panel notifier - lcd_active_panel not present\n"); + goto out; + } + memplus_notify.notifier_call = memplus_notifier_callback; + status = drm_panel_notifier_register(lcd_active_panel, &memplus_notify); + if (status) { + pr_err("Unable to register notifier: %d\n", status); + } else { + initialized = true; + pr_err("register drm panel notifier - success!"); + } +#else + pr_err("cannot register display notifier, please FIX IT!!!!!!\n"); +#endif + +out: + return initialized; +} + +static int gc_fn(void *p) +{ + struct task_struct *tsk; + int idx = 0, i; + + /* register display notifier */ + while (idx++ < 10) { + if (register_notifier()) + break; + msleep(2000); + } + + set_freezable(); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + + idx = 0; + memset(proc, 0, sizeof(proc)); + + rcu_read_lock(); + for_each_process(tsk) { + if (tsk->flags & PF_KTHREAD) + continue; +#if DEBUG_GCD + if (tsk->signal->reclaim_timeout) + pr_info("gc skip %s (pid %d uid %d, adj %d reclaim_time %ds before %llu %llu)\n" + , tsk->comm, tsk->pid, task_uid(tsk).val, tsk->signal->oom_score_adj + , (2*HZ + jiffies - tsk->signal->reclaim_timeout) / HZ, 2*HZ + jiffies + , tsk->signal->reclaim_timeout); +#endif + /* skip if being handled by reclaimd */ + if (tsk->signal->reclaim_timeout) + continue; + + proc[idx] = tsk->pid; + + if (++idx == GC_SIZE) + break; + } + rcu_read_unlock(); + + atomic64_set(&accu_display_on_jiffies, 0); + for (i = 0; i < idx; i++) { + int pid = proc[i]; + + if (pid == 0) + break; + + wait_for_suspend(); + + rcu_read_lock(); + tsk = find_task_by_vpid(pid); + + if (!tsk) { + rcu_read_unlock(); + continue; + } + + get_task_struct(tsk); + rcu_read_unlock(); +#if DEBUG_GCD + if (task_uid(tsk).val >= AID_APP) + pr_info("gc processing %s (pid %d uid %d, adj %d)\n" + , tsk->comm, tsk->pid, task_uid(tsk).val, tsk->signal->oom_score_adj); +#endif + spin_lock(&tsk->signal->reclaim_state_lock); + /* final check if handled by reclaimd */ + if (tsk->signal->reclaim_timeout) { + spin_unlock(&tsk->signal->reclaim_state_lock); + put_task_struct(tsk); + continue; + } + /* change to special state GC_RECLAIM_QUEUE */ + if (likely(tsk->signal->swapin_should_readahead_m == RECLAIM_STANDBY)) + tsk->signal->swapin_should_readahead_m = GC_RECLAIM_QUEUE; + else + pr_info("pre-check task %s(%d) unexpected status %d" + , tsk->comm, tsk->pid, tsk->signal->swapin_should_readahead_m); + spin_unlock(&tsk->signal->reclaim_state_lock); + + reclaim_anon(tsk, 0); + + spin_lock(&tsk->signal->reclaim_state_lock); + if (unlikely(tsk->signal->swapin_should_readahead_m != GC_RECLAIM_QUEUE)) + pr_info("post-check task %s(%d) unexpected status %d" + , tsk->comm, tsk->pid, tsk->signal->swapin_should_readahead_m); + tsk->signal->swapin_should_readahead_m = RECLAIM_STANDBY; + spin_unlock(&tsk->signal->reclaim_state_lock); + + put_task_struct(tsk); + } + + if (kthread_should_stop()) + break; + } + return 0; +} + +#if MEMEX_DEBUG +static ssize_t memex_do_swapin_anon(struct task_struct *task) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk walk = {}; + int task_anon = 0, task_swap = 0, err = 0; + +retry: + mm = get_task_mm(task); + if (!mm) + goto out; + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + walk.mm = mm; + walk.pmd_entry = memplus_swapin_walk_pmd_entry; + + down_read(&mm->mmap_sem); + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + walk.private = vma; + err = walk_page_range(vma->vm_start, vma->vm_end, &walk); + if (err == -1) + break; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + mmput(mm); + if (err) { + err = 0; + //schedule(); +#if MEMEX_DEBUG + /* TODO: it's possible to loop forever here + * if we're swapin camera which is foreground actively used */ +#endif + goto retry; + } +out: + lru_add_drain(); /* Push any new pages onto the LRU now */ + return 0; +} +#endif + +/* get_task_struct before using this function */ +static ssize_t memex_do_reclaim_anon(struct task_struct *task, int prev_adj) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk reclaim_walk = {}; + struct mp_reclaim_param rp; + int task_anon = 0, task_swap = 0; + int a_task_anon = 0, a_task_swap = 0; + int type_mask = 0; + + //u64 time_ns = 0; +#if DEBUG_TIME_INFO + struct timespec ts1, ts2; + getnstimeofday(&ts1); +#endif +#if FEAT_RECLAIM_LIMIT + rp.start_jiffies = jiffies; +#endif + /* if available zram is less than 32MB, quit early */ + type_mask = enough_swap_size_mask(8192); + if (!type_mask) + goto out; + + rp.nr_to_reclaim = INT_MAX; + rp.nr_reclaimed = 0; + rp.nr_scanned = 0; + /* memex currently use zram by default */ + rp.type = (type_mask & (1 << TYPE_FREQUENT)) ? TYPE_FREQUENT : TYPE_NORMAL; + + /* TODO: do we need to use p = find_lock_task_mm(tsk); in case main thread got killed */ + mm = get_task_mm(task); + if (!mm) + goto out; + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + reclaim_walk.mm = mm; + reclaim_walk.pmd_entry = memplus_reclaim_pte; + reclaim_walk.private = &rp; + + down_read(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + rp.vma = vma; + + /* TODO: do we need this check? */ + if (!list_empty(&vma->vm_mm->mmap_sem.wait_list)) { +#if MEMEX_DEBUG + pr_info("MemEX mmap_sem waiting %s(%d)\n", task->comm, task->pid); +#endif + break; + } + + walk_page_range(vma->vm_start, vma->vm_end, + &reclaim_walk); + + if (!rp.nr_to_reclaim) + break; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + a_task_anon = get_mm_counter(mm, MM_ANONPAGES); + a_task_swap = get_mm_counter(mm, MM_SWAPENTS); + mmput(mm); +out: +#if DEBUG_TIME_INFO + getnstimeofday(&ts2); + ts2 = timespec_sub(ts2, ts1); + time_ns = timespec_to_ns(&ts2); +#endif + /* TODO : return proper value */ + return rp.nr_reclaimed; +} + +static inline bool should_skip(const char *comm) +{ + if (!vm_cam_aware) + return false; + /* provider@2.4-se, camera@1.0-serv, cameraserver, .camera.service, ctureprocessing, .oneplus.camera */ + return strnstr(comm, "camera", TASK_COMM_LEN) + || !strncmp("provider@2.4-se", comm, TASK_COMM_LEN) + || !strncmp("ctureprocessing", comm, TASK_COMM_LEN); +} + +static int memex_fn(void *p) +{ + struct task_struct *tsk; + int i, idx_sys, idx_app; + cpumask_t tmask; + + /* setup nice: 130 cpumask: 0x7f */ + cpumask_parse("7f", &tmask); + set_cpus_allowed_ptr(current, &tmask); + set_user_nice(current, 10); + + set_freezable(); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + + idx_sys = 0; + idx_app = MEMEX_SIZE - 1; + memset(memex_proc, 0, sizeof(memex_proc)); + + rcu_read_lock(); + for_each_process(tsk) { + if (tsk->flags & PF_KTHREAD) + continue; + + /* TODO: do we need this check? */ + if (should_skip(tsk->comm)) + continue; + + if (task_uid(tsk).val >= AID_APP) { + memex_proc[idx_app--] = tsk->pid; + } else { + memex_proc[idx_sys++] = tsk->pid; + } + + if (unlikely(idx_sys > idx_app)) + break; + } +#if MEMEX_DEBUG + pr_info("MemEX sys=%d app=%d\n", idx_sys, idx_app); +#endif + rcu_read_unlock(); + + for (i = 0; i < MEMEX_SIZE; i++) { + int pid = memex_proc[i]; + + while (memex_threshold && memex_threshold <= (si_mem_available() * PAGE_SIZE / (1024 * 1024))) { +#if MEMEX_DEBUG + pr_info("MemEX thresh = %u, MemAvail = %u\n" + , memex_threshold, (si_mem_available() * PAGE_SIZE / (1024 * 1024))); +#endif + freezable_schedule_timeout_interruptible(HZ / 30); + } + + /* monitor current mode change */ + if (unlikely(!memex_threshold)) + break; + + if (pid == 0) + continue; + + rcu_read_lock(); + tsk = find_task_by_vpid(pid); + if (!tsk) { + rcu_read_unlock(); + continue; + } + get_task_struct(tsk); + rcu_read_unlock(); +#if MEMEX_DEBUG + pr_info("MemEX processing %s (%d) \n", tsk->comm, tsk->pid); + if (vm_swapin) + memex_do_swapin_anon(tsk); + else +#endif + memex_do_reclaim_anon(tsk, 0); + put_task_struct(tsk); + } + + if (kthread_should_stop()) + break; + } + return 0; +} + +int get_anon_memory(struct task_struct *task, unsigned long __user *buf) +{ + unsigned long size = 0; + struct mm_struct *mm = get_task_mm(task); + if (mm) { + size = get_mm_counter(mm, MM_ANONPAGES); + mmput(mm); + } + if (copy_to_user(buf, &size, sizeof(unsigned long))) + return -EFAULT; + return 0; +} +/* caller must hold spin lock before calling */ +static bool check_can_reclaimd(struct task_struct * task) { + bool ret = false; + if (task->signal->memplus_type != TYPE_WILL_NEED + && task->signal->oom_score_adj >= 800 + && time_after_eq(jiffies, task->signal->reclaim_timeout)) { + task->signal->reclaim_timeout = jiffies + 2*HZ; + ret = true; + } + return ret; +} + +static long memplus_sub_ioctl(unsigned int cmd, void __user *parg) +{ + long ret = 0; + unsigned long pid; + struct task_struct *task; + unsigned long size = 0; + int uid; + bool can_reclaim = false; + + if (copy_from_user(&pid, parg, sizeof(unsigned long))) + return -EFAULT; + + //printk("memplus_ioctl: pid = %lu\n", pid); + rcu_read_lock(); + task = find_task_by_vpid((int)pid); + + if (!task) { + rcu_read_unlock(); + return -ESRCH; + } + + get_task_struct(task); + rcu_read_unlock(); + uid = task_uid(task).val; + + switch (cmd) { + case MEMPLUS_GET_ANON_MEMORY: + if (get_anon_memory(task, parg)) + ret = -EFAULT; + break; + case MEMPLUS_RECLAIM_ANON_MEMORY: + /* TODO: reclaim directly, the reclaimd thread move to userspace */ + if (total_swap_pages == 0) { + pr_err("reclaim task anon memory failed, becauce of no swap space!\n"); + if (copy_to_user(parg, &size, sizeof(unsigned long))) + ret = -EFAULT; + break; + } + if (is_fg(uid)) { + pr_err("task %s(pid:%d uid:%d) is top app\n", task->comm, pid, uid); + if (copy_to_user(parg, &size, sizeof(unsigned long))) + ret = -EFAULT; + break; + } + if (!ctech__memplus_enabled()) { + spin_lock(&task->signal->reclaim_state_lock); + task->signal->swapin_should_readahead_m = RECLAIM_QUEUE; + spin_unlock(&task->signal->reclaim_state_lock); + size = reclaim_anon(task, 900); + } else { + spin_lock(&task->signal->reclaim_state_lock); + if (task->signal->swapin_should_readahead_m == RECLAIM_STANDBY) { + task->signal->swapin_should_readahead_m = RECLAIM_QUEUE; + can_reclaim = check_can_reclaimd(task); + spin_unlock(&task->signal->reclaim_state_lock); + if (can_reclaim && uid > AID_APP) { + size = reclaim_anon(task, 900); + } + } else { + spin_unlock(&task->signal->reclaim_state_lock); + pr_err("task %s(pid:%d) is doing swapin, top app?\n",task->comm, pid); + } + } + + if (copy_to_user(parg, &size, sizeof(unsigned long))) + ret = -EFAULT; + break; + case MEMPLUS_SWAPIN_ANON_MEMORY: + /* TODO: swapin directly, the swapind thread move to userspace, + * if the task's MM_SWAPENTS is zero, no need to swapin its memory. + * mark the task as swaping, let the task is doing reclaim stop immediately + */ + spin_lock(&task->signal->reclaim_state_lock); + task->signal->swapin_should_readahead_m = SWAPIN_QUEUE; + spin_unlock(&task->signal->reclaim_state_lock); + swapin_anon(task, 0); + break; + } + put_task_struct(task); + + return ret; +} + +long memplus_ioctl(struct file *file, unsigned int cmd, unsigned long args) +{ + long ret = 0; + void __user *parg = (void __user *)args; + unsigned long size = 0; + + if (cmd == MEMPLUS_GET_AVAILABLE_SWAP_SPACE) { + size = atomic_long_read(&nr_swap_pages); + if (copy_to_user(parg, &size, sizeof(unsigned long))) + return -EFAULT; + } else + ret = memplus_sub_ioctl(cmd, parg); + + return ret; +} + +static const struct file_operations memplus_ops = { + .unlocked_ioctl = memplus_ioctl, +}; + +void memplus_stop(void) +{ + if (reclaimd_tsk) { + kthread_stop(reclaimd_tsk); + reclaimd_tsk = NULL; + } + if (swapind_tsk) { + kthread_stop(swapind_tsk); + swapind_tsk = NULL; + } + if (gc_tsk) { + kthread_stop(gc_tsk); + gc_tsk = NULL; + } +} + +static int __init memplus_init(void) +{ + //TODO: priority tuning for reclaimd/swapind + //struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO -1 }; + //struct sched_param param = { .sched_priority = 1 }; + struct memplus_cb_set set; + struct miscdevice *misc = NULL; + + reclaimd_tsk = kthread_run(reclaimd_fn, 0, "reclaimd"); + if (IS_ERR(reclaimd_tsk)) { + pr_err("Failed to start reclaimd\n"); + reclaimd_tsk = NULL; + } + + swapind_tsk = kthread_run(swapind_fn, 0, "swapind"); + if (IS_ERR(swapind_tsk)) { + pr_err("Failed to start swapind\n"); + swapind_tsk = NULL; + } else { + /* if do_swap_page by swapind, don't calculate next event */ + swapind_tsk->signal->reclaim_timeout = 1; + //if (sched_setscheduler_nocheck(swapind_tsk, SCHED_FIFO, ¶m)) { + // pr_warn("%s: failed to set SCHED_FIFO\n", __func__); + //} + } + gc_tsk = kthread_run(gc_fn, 0, "system_gcd"); + if (IS_ERR(gc_tsk)) { + pr_err("Failed to start system_gcd\n"); + gc_tsk = NULL; + } + + memex_tsk = kthread_run(memex_fn, 0, "memex"); + if (IS_ERR(memex_tsk)) { + pr_err("Failed to start memex_task\n"); + memex_tsk = NULL; + } + +#if defined(CONFIG_PAGE_EXTENSION) && defined(CONFIG_PAGE_OWNER_ENABLE_DEFAULT) + pr_info("ext mode\n"); +#else + pr_info("normal mode\n"); +#endif + + misc = kzalloc(sizeof(struct miscdevice), GFP_KERNEL); + if (!misc) { + pr_err("Failed alloc memplus miscdevice\n"); + return -1; + } + misc->fops = &memplus_ops; + misc->name = "memplus"; + misc->minor = MISC_DYNAMIC_MINOR; + if (misc_register(misc)) { + pr_err("Failed to create dev/memplus\n"); + return -1; + } + set.current_is_swapind_cb = ctech_current_is_swapind; + set.memplus_check_isolate_page_cb = ctech_memplus_check_isolate_page; + set.memplus_enabled_cb = ctech_memplus_enabled; + set.memplus_move_anon_to_swapcache_lru_cb = ctech_memplus_move_anon_to_swapcache_lru; + set.memplus_move_swapcache_to_anon_lru_cb = ctech_memplus_move_swapcache_to_anon_lru; + set.memplus_state_check_cb = ctech_memplus_state_check; + set.__memplus_enabled_cb = ctech__memplus_enabled; + set.memplus_next_event_cb = ctech_memplus_next_event; + + register_cb_set(&set); + return 0; +} + +unsigned long memplus_scan(void) +{ + struct pagevec pvec; + unsigned nr_space = 0; + pgoff_t index = 0, indices[PAGEVEC_SIZE]; + int i, j, iso_count = 0; + struct address_space *spaces; + struct swap_info_struct *sis, *next; + unsigned int node = numa_node_id(); + unsigned int total_swapcache = total_swapcache_pages(); + LIST_HEAD(page_list); + + if (!total_swapcache) + return 0; + + spin_lock(&swap_lock); + plist_for_each_entry_safe(sis, next, &swap_avail_heads[node], avail_lists[node]) { + nr_space = DIV_ROUND_UP(sis->max, SWAP_ADDRESS_SPACE_PAGES); + spaces = rcu_dereference(swapper_spaces[sis->type]); + if (!nr_space || !spaces) + continue; + for (j = 0; j < nr_space; j++) { + index = 0; + pagevec_init(&pvec); + while (pagevec_lookup_entries(&pvec, &spaces[j], index, (pgoff_t)PAGEVEC_SIZE, indices)) { + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; + + index = indices[i]; + + if (radix_tree_exceptional_entry(page)) { + continue; + } + + if (!PageSwapCache(page)) + continue; + + if (PageWriteback(page)) + continue; + + if (isolate_lru_page(page)) + continue; + + if (PageAnon(page) && !PageSwapBacked(page)) { + putback_lru_page(page); + continue; + } + + ClearPageWillneed(page); + list_add(&page->lru, &page_list); + inc_node_page_state(page, NR_ISOLATED_ANON + + page_is_file_cache(page)); + iso_count ++; + } + pagevec_remove_exceptionals(&pvec); + pagevec_release(&pvec); + index++; + } + } + } + spin_unlock(&swap_lock); + return coretech_reclaim_pagelist(&page_list, NULL, NULL); +} + +static int memory_plus_test_worstcase_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + unsigned long freed = 0; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + if(val == 1) + freed = memplus_scan(); + printk("memory_plus_test_worstcase_store: freed = %ld\n", freed); + + return 0; +} + +/* return value mapping: + * 0 - success + * ESRCH - no GC daemon + * EPERM - memplus is diabled by user + * EINVAL- invalid input + * EBUSY - triggered too frequently + */ +static int memory_plus_wake_gcd_store(const char *buf, const struct kernel_param *kp) +{ + static ktime_t last_wake; + unsigned int val; + ktime_t cur_ktime; + s64 elapsed_hr; + + if (!gc_tsk) + return -ESRCH; + if (vm_memory_plus == 2 || vm_memory_plus == 0) + return -EPERM; + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + cur_ktime = ktime_get_boottime(); + elapsed_hr = ktime_to_ms(ktime_sub(cur_ktime, last_wake)) / (MSEC_PER_SEC * 3600); + +#if DEBUG_GCD + pr_info("elapsed bootime %d sec, hr %d\n" + , ktime_to_ms(ktime_sub(cur_ktime, last_wake)) / MSEC_PER_SEC, elapsed_hr); + pr_info("elapsed display on jiffies %d sec\n" + , (atomic64_read(&accu_display_on_jiffies) + + (display_on ? (jiffies - display_on_jiffies) : 0)) / HZ); +#endif +#if GCD_SST + wake_up_process(gc_tsk); +#endif + /* 24hr control */ + if (last_wake && elapsed_hr < 24) + return -EBUSY; + + wake_up_process(gc_tsk); + last_wake = cur_ktime; + + return 0; +} + +/* return value mapping: + * 0 - success + * ESRCH - no MemEx daemon + * EINVAL- invalid input + */ +static int memory_plus_wake_memex_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (!memex_tsk) + return -ESRCH; + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + memex_threshold = val; + if (val) + wake_up_process(memex_tsk); + + return 0; +} + +static int memory_plus_wake_memex_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", memex_threshold); +} + +static struct kernel_param_ops memory_plus_test_worstcase_ops = { + .set = memory_plus_test_worstcase_store, +}; + +static struct kernel_param_ops memory_plus_wake_gcd_ops = { + .set = memory_plus_wake_gcd_store, +}; + +static struct kernel_param_ops memory_plus_wake_memex_ops = { + .set = memory_plus_wake_memex_store, + .get = memory_plus_wake_memex_show, +}; + +module_param_cb(memory_plus_test_worstcase, &memory_plus_test_worstcase_ops, NULL, 0200); +module_param_cb(memory_plus_wake_gcd, &memory_plus_wake_gcd_ops, NULL, 0644); +module_param_cb(memory_plus_wake_memex, &memory_plus_wake_memex_ops, NULL, 0644); + +module_param_named(memory_plus_enabled, vm_memory_plus, uint, S_IRUGO | S_IWUSR); +module_param_named(memplus_add_to_swap, memplus_add_to_swap, ulong, S_IRUGO | S_IWUSR); +module_param_named(memory_plus_cam_aware, vm_cam_aware, uint, S_IRUGO | S_IWUSR); + +module_init(memplus_init) diff --git a/drivers/oneplus/coretech/memplus/memplus_helper.c b/drivers/oneplus/coretech/memplus/memplus_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..799fad41661706daafccbe09fda4ab15b7d1e49a --- /dev/null +++ b/drivers/oneplus/coretech/memplus/memplus_helper.c @@ -0,0 +1,67 @@ +#include +#include + +static struct memplus_cb_set cb_set; +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page); }) + +bool memplus_enabled(void) +{ + if (cb_set.memplus_enabled_cb) + return cb_set.memplus_enabled_cb(); + return false; +} +bool __memplus_enabled(void) +{ + if (cb_set.__memplus_enabled_cb) + return cb_set.__memplus_enabled_cb(); + return false; +} +bool current_is_swapind(void) +{ + if (cb_set.current_is_swapind_cb) + return cb_set.current_is_swapind_cb(); + return false; +} + +void memplus_move_swapcache_to_anon_lru(struct page *page) +{ + if (cb_set.memplus_move_swapcache_to_anon_lru_cb) + cb_set.memplus_move_swapcache_to_anon_lru_cb(page); + else + clear_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); +} +void memplus_move_anon_to_swapcache_lru(struct page *page) +{ + if (cb_set.memplus_move_anon_to_swapcache_lru_cb) + cb_set.memplus_move_anon_to_swapcache_lru_cb(page); + else + set_bit(PG_swapcache, &(PF_NO_TAIL(page, 1))->flags); +} +void memplus_state_check(bool legacy, int oom_adj, + struct task_struct *task, int type, int update) +{ + if (cb_set.memplus_state_check_cb) + cb_set.memplus_state_check_cb(legacy, + oom_adj, task, type, update); +} +bool memplus_check_isolate_page(struct page *page) +{ + if (cb_set.memplus_check_isolate_page_cb) + return cb_set.memplus_check_isolate_page_cb(page); + return false; +} + +void memplus_next_event(struct page *page) +{ + if (cb_set.memplus_next_event_cb) + return cb_set.memplus_next_event_cb(page); +} + +void register_cb_set(struct memplus_cb_set *set) +{ + cb_set = *set; +} + +#undef PF_NO_TAIL diff --git a/drivers/oneplus/coretech/pccore/Makefile b/drivers/oneplus/coretech/pccore/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2021a25b086a60af28c213988d8bf537705ecae2 --- /dev/null +++ b/drivers/oneplus/coretech/pccore/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PCCORE) += pccore.o diff --git a/drivers/oneplus/coretech/pccore/pccore.c b/drivers/oneplus/coretech/pccore/pccore.c new file mode 100644 index 0000000000000000000000000000000000000000..3dc134c9eb108be9ee7b8448d0507e65aca8068a --- /dev/null +++ b/drivers/oneplus/coretech/pccore/pccore.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include + +static int pcclog_lv = 1; +module_param_named(pcclog_lv, pcclog_lv, int, 0664); + +// param@1: enable or not, param@2: select_fd_mode, param@3: depress mode, param@4: depress level +static unsigned int params[PCC_PARAMS] = { 0, 0, 0, 0 }; +module_param_array_named(params, params, uint, NULL, 0664); + +bool get_op_select_freq_enable(void) +{ + return params[0]; +} +EXPORT_SYMBOL(get_op_select_freq_enable); + +static unsigned int op_cross_limit = 99; +module_param_named(op_cross_limit, op_cross_limit, uint, 0664); +unsigned int get_op_limit(void) +{ + return op_cross_limit; +} +EXPORT_SYMBOL(get_op_limit); + +unsigned int get_op_level(void) +{ + return params[3]; +} +EXPORT_SYMBOL(get_op_level); + +unsigned int get_op_fd_mode(void) +{ + return params[2]; +} +EXPORT_SYMBOL(get_op_fd_mode); + +unsigned int get_op_mode(void) +{ + return params[1]; +} +EXPORT_SYMBOL(get_op_mode); + +static unsigned int *get_cluster_arr(int cpu) +{ + + switch (cpu) { + case 0: + case 1: + case 2: + case 3: + return cpufreq_pd_0; + case 4: + case 5: + case 6: + return cpufreq_pd_1; + case 7: + return cpufreq_pd_2; + } + return NULL; +} + +static int get_cluster(int cpu) +{ + int err = -1; + + switch (cpu) { + case 0: + case 1: + case 2: + case 3: + return 0; + case 4: + case 5: + case 6: + return 1; + case 7: + return 2; + default: + return err; + } +} + +int cross_pd(int cpu, int prefer_idx, int target_idx, bool ascending) +{ + unsigned int *arr = get_cluster_arr(cpu); + unsigned int idx_max; + int cluster; + + cluster = get_cluster(cpu); + if (cluster < 0) + return target_idx; + + idx_max = cluster_pd[cluster]-1; + + if (ascending && (target_idx == 0 || target_idx > idx_max)) + return target_idx; + + if (!ascending && target_idx >= idx_max) + return target_idx; + + if (target_idx == prefer_idx) + return target_idx; + + if (arr == NULL) { + pcc_loge("can't get pd\n"); + return target_idx; + } + + if (ascending) { + if (arr[target_idx] == arr[prefer_idx]) + return target_idx; + } else { + if (idx_max < prefer_idx) + return target_idx; + + if (arr[idx_max - target_idx] == arr[idx_max - prefer_idx]) + return target_idx; + } + + return prefer_idx; +} +EXPORT_SYMBOL(cross_pd); + +int find_prefer_pd(int cpu, int target_idx, bool ascending, int lv_cnt) +{ + unsigned int *arr = get_cluster_arr(cpu); + unsigned int val; + int pre_idx; + int prefer_idx = target_idx; + unsigned int idx_max; + int cluster; + + cluster = get_cluster(cpu); + if (cluster < 0) + return target_idx; + + idx_max = cluster_pd[cluster]-1; + + + if (arr == NULL) { + pcc_loge("can't get pd\n"); + return target_idx; + } + + if (target_idx < 0 || target_idx > idx_max) { + pcc_loge("idx oob, idx=%d, max=%d\n", target_idx, idx_max); + return target_idx; + } + + if (ascending) { + + if (target_idx == 0 || lv_cnt <= 0) + return target_idx; + + pre_idx = target_idx - 1; + val = arr[target_idx]; + + while (lv_cnt > 0) { + + if (pre_idx == 0) { + if (val == arr[pre_idx]) + return prefer_idx; + else + return pre_idx; + } + + if (val != arr[pre_idx]) { + val = arr[pre_idx]; + prefer_idx = pre_idx; + lv_cnt--; + } + + pre_idx--; + } + + } else { + + if (target_idx == idx_max || lv_cnt <= 0) + return target_idx; + + pre_idx = target_idx + 1; + val = arr[target_idx]; + + while (lv_cnt > 0) { + + if (pre_idx == idx_max) { + if (val == arr[pre_idx]) + return prefer_idx; + else + return pre_idx; + } + + if (val != arr[pre_idx]) { + val = arr[pre_idx]; + prefer_idx = pre_idx; + lv_cnt--; + } + + pre_idx++; + } + + } + + return prefer_idx; +} +EXPORT_SYMBOL(find_prefer_pd); + +static int pccore_init(void) +{ + pcc_logi("pccore init\n"); + return 0; +} + +pure_initcall(pccore_init); diff --git a/drivers/oneplus/coretech/ratp/Makefile b/drivers/oneplus/coretech/ratp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..99412e53f11bc8f028d40185e92ad6c3a5f0ea97 --- /dev/null +++ b/drivers/oneplus/coretech/ratp/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_RATP) += ratp.o diff --git a/drivers/oneplus/coretech/ratp/ratp.c b/drivers/oneplus/coretech/ratp/ratp.c new file mode 100644 index 0000000000000000000000000000000000000000..04c22337496717a15052e59afb3235c7ec0f209d --- /dev/null +++ b/drivers/oneplus/coretech/ratp/ratp.c @@ -0,0 +1,103 @@ +#include +#include +#include + +static int ratp_enable = 0; +static int ratp_gmod = 0; +static int ratp_allowmost = 0; + +static int ratp_enable_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (ratp_enable == val) + return 0; + + ratp_enable = val; + + return 0; +} + +static int ratp_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ratp_enable); +} + +static struct kernel_param_ops ratp_enable_ops = { + .set = ratp_enable_store, + .get = ratp_enable_show, +}; + +module_param_cb(ratp_enable, &ratp_enable_ops, NULL, 0664); + +bool is_ratp_enable(void) +{ + return ratp_enable; +} + +static int ratp_gmod_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (ratp_gmod == val) + return 0; + + ratp_gmod = val; + + return 0; +} + +static int ratp_gmod_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ratp_gmod); +} + +static struct kernel_param_ops ratp_gmod_ops = { + .set = ratp_gmod_store, + .get = ratp_gmod_show, +}; + +module_param_cb(ratp_gmod, &ratp_gmod_ops, NULL, 0664); + +bool is_gmod_enable(void) +{ + return ratp_gmod; +} + +static int ratp_allowmost_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (ratp_allowmost == val) + return 0; + + ratp_allowmost = val; + + return 0; +} + +static int ratp_allowmost_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ratp_allowmost); +} + +static struct kernel_param_ops ratp_allowmost_ops = { + .set = ratp_allowmost_store, + .get = ratp_allowmost_show, +}; + +bool is_allowmost_enable(void) +{ + return ratp_allowmost; +} + +module_param_cb(ratp_allowmost, &ratp_allowmost_ops, NULL, 0664); diff --git a/drivers/oneplus/coretech/smartboost/Makefile b/drivers/oneplus/coretech/smartboost/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6091ef65fe332e906d216d61be8585f3f630ad53 --- /dev/null +++ b/drivers/oneplus/coretech/smartboost/Makefile @@ -0,0 +1 @@ +obj-y += smartboost_helper.o diff --git a/drivers/oneplus/coretech/smartboost/core/Makefile b/drivers/oneplus/coretech/smartboost/core/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a36d13e65523c04ec976f8dee52b7766511cc814 --- /dev/null +++ b/drivers/oneplus/coretech/smartboost/core/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SMART_BOOST) += smartboost_core.o diff --git a/drivers/oneplus/coretech/smartboost/core/smartboost_core.c b/drivers/oneplus/coretech/smartboost/core/smartboost_core.c new file mode 100644 index 0000000000000000000000000000000000000000..cf2604c0f0a95c7211fba711dafb9ef4f0a21de6 --- /dev/null +++ b/drivers/oneplus/coretech/smartboost/core/smartboost_core.c @@ -0,0 +1,746 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../fs/proc/internal.h" + +static int sysctl_page_cache_reside_switch; +unsigned long inactive_nr, active_nr; +unsigned long priority_nr[3]; + +static int lowmem_minfree[6] = { + 3 * 512, /* 6MB */ + 2 * 1024, /* 8MB */ + 4 * 1024, /* 16MB */ + 16 * 1024, /* 64MB */ +}; + +static int lowmem_minfree_size = 4; + +#define SMART_BOOST_PUTBACK_LRU 2 +#define VMPRESSURE_COUNT 5 +static atomic64_t vmpress[VMPRESSURE_COUNT]; + +static LIST_HEAD(hotcount_prio_list); +static DEFINE_RWLOCK(prio_list_lock); + +struct hotcount_prio_node { + unsigned int hotcount; + uid_t uid; + struct list_head list; +}; + +unsigned long get_max_minfree(void) +{ + return (lowmem_minfree[lowmem_minfree_size - 1] > 200640 ? + lowmem_minfree[lowmem_minfree_size - 1] : 200640); +} + +static unsigned int find_node_uid_prio(struct hotcount_prio_node **node, + struct list_head **prio_pos, + uid_t uid, + unsigned int hotcount) +{ + struct hotcount_prio_node *pos; + unsigned int ret_hotcount = 0; + + read_lock(&prio_list_lock); + list_for_each_entry(pos, &hotcount_prio_list, list) { + + if (*node && *prio_pos) + break; + + if (pos->uid == uid) { + *node = pos; + ret_hotcount = pos->hotcount; + } + if ((!(*prio_pos)) && + (pos->hotcount > hotcount)) + *prio_pos = &pos->list; + } + + if (!(*prio_pos)) + *prio_pos = &hotcount_prio_list; + + read_unlock(&prio_list_lock); + + return ret_hotcount; +} + +static void insert_prio_node(unsigned int new_hotcount, uid_t uid) +{ + struct hotcount_prio_node *node = NULL; + struct list_head *prio_pos = NULL; + unsigned int old_hotcount; + + old_hotcount = find_node_uid_prio(&node, &prio_pos, uid, new_hotcount); + + if (node) { + if (old_hotcount == new_hotcount) + return; + + write_lock(&prio_list_lock); + + if (&node->list == prio_pos) { + node->hotcount = new_hotcount; + goto unlock; + } + list_del(&node->list); + } else { + node = (struct hotcount_prio_node *) + kmalloc(sizeof(struct hotcount_prio_node), GFP_KERNEL); + if (!node) { + pr_err("no memory to insert prio_node!\n"); + return; + } + node->uid = uid; + write_lock(&prio_list_lock); + } + + node->hotcount = new_hotcount; + list_add_tail(&node->list, prio_pos); +unlock: + write_unlock(&prio_list_lock); +} + +static void delete_prio_node(uid_t uid) +{ + struct hotcount_prio_node *pos; + int found = 0; + + read_lock(&prio_list_lock); + list_for_each_entry(pos, &hotcount_prio_list, list) + if (pos->uid == uid) { + found = 1; + break; + } + read_unlock(&prio_list_lock); + + if (found) { + write_lock(&prio_list_lock); + list_del(&pos->list); + write_unlock(&prio_list_lock); + kfree(pos); + } +} + +static void print_prio_chain(struct seq_file *m) +{ + struct hotcount_prio_node *pos; + + read_lock(&prio_list_lock); + list_for_each_entry(pos, &hotcount_prio_list, list) + seq_printf(m, "%d(%d)\t", pos->uid, pos->hotcount); + read_unlock(&prio_list_lock); + + seq_putc(m, '\n'); +} + +#define UID_HASH_ORDER 5 +#define uid_hashfn(nr) hash_long((unsigned long)nr, UID_HASH_ORDER) + +static struct uid_node **alloc_uid_hash_table(void) +{ + struct uid_node **hash_table; + int size = (1 << UID_HASH_ORDER) * sizeof(struct uid_node *); + + if (size <= PAGE_SIZE) + hash_table = kzalloc(size, GFP_ATOMIC); + else + hash_table = (struct uid_node **)__get_free_pages( + GFP_ATOMIC | __GFP_ZERO, get_order(size)); + if (!hash_table) + return NULL; + return hash_table; +} + +static struct uid_node *alloc_uid_node(uid_t uid) +{ + struct uid_node *uid_nd; + + uid_nd = kzalloc(sizeof(struct uid_node), GFP_ATOMIC); + if (!uid_nd) + return NULL; + uid_nd->uid = uid; + uid_nd->hot_count = 0; /* initialize a new UID's count */ + uid_nd->next = NULL; + INIT_LIST_HEAD(&uid_nd->page_cache_list); + return uid_nd; +} + +static struct uid_node *insert_uid_node(struct uid_node **hash_table, uid_t uid) +{ + struct uid_node *puid; + unsigned int index, sise = 1 << UID_HASH_ORDER; + + index = uid_hashfn((unsigned long)uid); + if (index >= sise) + return NULL; + puid = alloc_uid_node(uid); + + if (!puid) + return NULL; + + rcu_assign_pointer(puid->next, hash_table[index]); + rcu_assign_pointer(hash_table[index], puid); + return puid; +} + +static struct uid_node *find_uid_node(uid_t uid, struct lruvec *lruvec) +{ + struct uid_node *uid_nd, *ret = NULL; + unsigned int index; + + index = uid_hashfn((unsigned int)uid); + + if (lruvec->uid_hash == NULL) + return NULL; + if (index >= (1 << UID_HASH_ORDER)) + return NULL; + for (uid_nd = rcu_dereference(lruvec->uid_hash[index]); + uid_nd != NULL; uid_nd = rcu_dereference(uid_nd->next)) { + if (uid_nd->uid == uid) { + ret = uid_nd; + break; + } + } + return ret; +} + +void free_hash_table(struct lruvec *lruvec) +{ + int i, table_num; + struct uid_node *puid, **np; + + table_num = 1 << UID_HASH_ORDER; + for (i = 0; i < table_num; i++) { + np = &lruvec->uid_hash[i]; + while ((puid = rcu_dereference(*np)) != NULL) { + rcu_assign_pointer(*np, rcu_dereference(puid->next)); + kfree_rcu(puid, rcu); + } + } +} + +__always_inline +bool ctech_smb_update_uid_lru_size(struct page *page, + struct lruvec *lruvec, enum lru_list lru) +{ + struct pglist_data *pgdata = lruvec_pgdat(lruvec); + + if (is_file_lru(lru) && PageUIDLRU(page)) { + ClearPageUIDLRU(page); + __mod_zone_page_state( + &pgdata->node_zones[page_zonenum(page)], + NR_ZONE_UID_LRU, -hpage_nr_pages(page)); + return true; + } else + return false; +} + + +static void _uid_lru_add_fn(struct page *page, struct lruvec *lruvec) +{ + struct uid_node *uid_nd; + unsigned long flag; + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + uid_t uid = __task_cred(current)->user->uid.val; + + if (!pgdat) + pgdat = page_pgdat(page); + + get_page(page); + spin_lock_irqsave(&pgdat->lru_lock, flag); + VM_BUG_ON_PAGE(PageAnon(page), page); + VM_BUG_ON_PAGE(PageLRU(page), page); + VM_BUG_ON_PAGE(PageUIDLRU(page), page); + SetPageUIDLRU(page); + SetPageLRU(page); + uid_nd = find_uid_node(uid, lruvec); + if (uid_nd == NULL) { + if (lruvec->uid_hash == NULL) + lruvec->uid_hash = alloc_uid_hash_table(); + uid_nd = insert_uid_node(lruvec->uid_hash, uid); + } + list_add(&page->lru, &uid_nd->page_cache_list); + mod_zone_page_state(page_zone(page), NR_ZONE_UID_LRU, + hpage_nr_pages(page)); + spin_unlock_irqrestore(&pgdat->lru_lock, flag); + put_page(page); +} + +static void __uid_lru_cache_add(struct page *page) +{ + struct pglist_data *pagepgdat = page_pgdat(page); + struct lruvec *lruvec; + + lruvec = mem_cgroup_page_lruvec(page, pagepgdat); + _uid_lru_add_fn(page, lruvec); +} + +static unsigned long isolate_uid_lru_pages(struct page *page) +{ + int ret = -EBUSY; + + //VM_BUG_ON_PAGE(!page_count(page), page); + WARN_RATELIMIT(PageTail(page), "trying to isolate tail page"); + + if (PageLRU(page)) { + struct zone *zone = page_zone(page); + struct lruvec *lruvec; + int lru = page_lru(page); + + if (unlikely(!get_page_unless_zero(page))) + return ret; + + if (PageUnevictable(page)) + return ret; + + lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); + ClearPageLRU(page); + del_page_from_lru_list(page, lruvec, lru); + ret = 0; + } + + return ret; +} + +static bool cache_is_low(void) +{ + unsigned long cache = + global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages(); + + if (cache < get_max_minfree()) + return true; + + return false; +} + +bool ctech_smb_uid_lru_add(struct page *page) +{ + if (!sysctl_page_cache_reside_switch) + return false; + + if (cache_is_low()) + return false; + + if (!current->group_leader->hot_count) + return false; + + VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageLRU(page), page); + __uid_lru_cache_add(page); + + return true; +} + +static unsigned long +smb_isolate_pages_by_uid(struct list_head *page_list, uid_t uid) +{ + LIST_HEAD(putback_page_list); + struct pglist_data *pgdat; + struct mem_cgroup *memcg; + struct uid_node *node; + struct lruvec *lruvec; + unsigned long nr_isolate = 0, nr_isolate_failed = 0; + struct page *page; + + for_each_online_pgdat(pgdat) { + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + lruvec = mem_cgroup_lruvec(pgdat, memcg); + if (!lruvec) + goto next; + spin_lock_irq(&pgdat->lru_lock); + node = find_uid_node(uid, lruvec); + if (!node) { + spin_unlock_irq(&pgdat->lru_lock); + goto next; + } + + while (!list_empty(&node->page_cache_list)) { + page = lru_to_page(&node->page_cache_list); + VM_BUG_ON_PAGE(!PageUIDLRU(page), page); + + if (isolate_uid_lru_pages(page)) { + list_move(&page->lru, + &putback_page_list); + nr_isolate_failed++; + continue; + } + + ClearPageActive(page); + list_add(&page->lru, page_list); + nr_isolate++; + inc_node_page_state(page, NR_ISOLATED_ANON + + page_is_file_cache(page)); + } + + list_splice_init(&putback_page_list, + &node->page_cache_list); + spin_unlock_irq(&pgdat->lru_lock); +next: + memcg = mem_cgroup_iter(NULL, memcg, NULL); + } while (memcg); + } + return nr_isolate; +} + + +static unsigned long uid_lru_size(void) +{ + return global_zone_page_state(NR_ZONE_UID_LRU); +} + +static int suitable_reclaim_check(struct lruvec *lruvec) +{ + unsigned long active = global_zone_page_state(NR_ZONE_ACTIVE_FILE); + unsigned long inactive = global_zone_page_state(NR_ZONE_INACTIVE_FILE); + unsigned long total_uid_lru_nr = uid_lru_size(); + + if ((active + inactive) > get_max_minfree()) + return ((active + inactive) << 3) < total_uid_lru_nr; + else + return SMART_BOOST_PUTBACK_LRU; +} + +static bool suitable_isolate_in_direct_reclaim(int priority, + bool enough_list_reclaimed) +{ + bool need_isolate = false; + + if (current_is_kswapd()) + need_isolate = false; + + if (priority <= 11 && !enough_list_reclaimed) + need_isolate = true; + + return need_isolate; +} + +unsigned long ctech_smb_isolate_list_or_putbcak(struct list_head *page_list, + struct lruvec *lruvec, struct pglist_data *pgdat, int priority, + bool enough_list_reclaimed) +{ + LIST_HEAD(putback_list); + unsigned long nr_isolated = 0, nr_isolate_failed = 0; + unsigned long uid_size = uid_lru_size(); + long nr_to_shrink = uid_size >> priority; + int stat = suitable_reclaim_check(lruvec); + struct hotcount_prio_node *pos; + struct page *page; + + if (!sysctl_page_cache_reside_switch) + return 0; + + if (!stat && + !suitable_isolate_in_direct_reclaim(priority,enough_list_reclaimed)) + return 0; + + if (uid_size <= 0) + return 0; + + if (stat == SMART_BOOST_PUTBACK_LRU) + nr_to_shrink = uid_size; + + read_lock(&prio_list_lock); + spin_lock_irq(&pgdat->lru_lock); + list_for_each_entry(pos, &hotcount_prio_list, list) { + struct uid_node *tmp_uid_list = find_uid_node(pos->uid, lruvec); + + if (!nr_to_shrink) + break; + + if (tmp_uid_list == NULL) + continue; + + while (!list_empty(&tmp_uid_list->page_cache_list)) { + page = lru_to_page(&tmp_uid_list->page_cache_list); + VM_BUG_ON_PAGE(!PageUIDLRU(page), page); + + if (isolate_uid_lru_pages(page)) { + list_move(&page->lru, &putback_list); + nr_isolate_failed++; + continue; + } + + ClearPageActive(page); + list_add(&page->lru, page_list); + nr_to_shrink--; + nr_isolated++; + if (!nr_to_shrink) + break; + } + + list_splice_init(&putback_list, &tmp_uid_list->page_cache_list); + } + spin_unlock_irq(&pgdat->lru_lock); + read_unlock(&prio_list_lock); + + if (stat == SMART_BOOST_PUTBACK_LRU) + while (!list_empty(page_list)) { + page = lru_to_page(page_list); + list_del(&page->lru); + putback_lru_page(page); + nr_isolated--; + } + + return nr_isolated; + +} + +static void uid_lru_info_show_print(struct seq_file *m, pg_data_t *pgdat) +{ + int i; + struct uid_node **table; + struct list_head *pos; + unsigned long nr_pages; + struct mem_cgroup *memcg; + + seq_puts(m, "vmpressure:\n0_20\t20_40\t40_60\t60_80\t80_100\n"); + for (i = 0; i < VMPRESSURE_COUNT; i++) + seq_printf(m, "%lu\t", atomic64_read(&vmpress[i])); + + seq_printf(m, "\nNode %d\n", pgdat->node_id); + seq_puts(m, "uid_lru_list priority:\n"); + print_prio_chain(m); + seq_puts(m, "uid\thot_count\tpages\n"); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg); + + if (!lruvec) + goto next; + + table = lruvec->uid_hash; + if (!table) + goto next; + + for (i = 0; i < (1 << 5); i++) { + struct uid_node *node = rcu_dereference(table[i]); + + if (!node) + continue; + + do { + nr_pages = 0; + list_for_each(pos, &node->page_cache_list) + nr_pages++; + seq_printf(m, "%d\t%d\t%lu\n", + node->uid, + node->hot_count, + nr_pages); + } while ((node = rcu_dereference(node->next)) != NULL); + } +next: + memcg = mem_cgroup_iter(NULL, memcg, NULL); + } while (memcg); + seq_putc(m, '\n'); +} +/* + * Output information about zones in @pgdat. + */ +static int uid_lru_info_show(struct seq_file *m, void *arg) +{ + pg_data_t *pgdat = (pg_data_t *)arg; + + uid_lru_info_show_print(m, pgdat); + + return 0; +} +static void *uid_lru_info_start(struct seq_file *m, loff_t *pos) +{ + pg_data_t *pgdat; + loff_t node = *pos; + + for (pgdat = first_online_pgdat(); + pgdat && node; + pgdat = next_online_pgdat(pgdat)) + --node; + + return pgdat; +} + +static void *uid_lru_info_next(struct seq_file *m, void *arg, loff_t *pos) +{ + pg_data_t *pgdat = (pg_data_t *)arg; + + (*pos)++; + return next_online_pgdat(pgdat); +} + +static void uid_lru_info_stop(struct seq_file *m, void *arg) +{ +} + +static const struct seq_operations uid_lru_info_op = { + .start = uid_lru_info_start, + .next = uid_lru_info_next, + .stop = uid_lru_info_stop, + .show = uid_lru_info_show, +}; + +static int uid_lru_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &uid_lru_info_op); +} + +static const struct file_operations proc_uid_lru_info_file_operations = { + .open = uid_lru_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int smb_vmpressure_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + unsigned long pressure = action; + + if (pressure < 20) + atomic64_inc(&vmpress[0]); + else if (pressure < 40) + atomic64_inc(&vmpress[1]); + else if (pressure < 60) + atomic64_inc(&vmpress[2]); + else if (pressure < 80) + atomic64_inc(&vmpress[3]); + else + atomic64_inc(&vmpress[4]); + + return 0; +} + +static struct notifier_block smb_vmpressure_statistic = { + .notifier_call = smb_vmpressure_notifier, +}; + +static void smart_boost_reclaim_by_uid(uid_t uid) +{ + LIST_HEAD(page_list); + unsigned long nr_isolate = 0; + unsigned long nr_reclaimed = 0; + + nr_isolate = smb_isolate_pages_by_uid(&page_list, uid); + if (!nr_isolate) + return; + + nr_reclaimed = coretech_reclaim_pagelist(&page_list, NULL, NULL); + + pr_err("clean uid(%d) pagecache:%d\n", uid, nr_reclaimed); +} + +static ssize_t page_hot_count_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + size_t len; + int page_hot_count; + + task = get_proc_task(file_inode(file)); + + if (!task) + return -ESRCH; + + page_hot_count = task->hot_count; + + put_task_struct(task); + + len = snprintf(buffer, sizeof(buffer), "%d\n", page_hot_count); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static ssize_t page_hot_count_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int page_hot_count; + int err; + uid_t uid; + + memset(buffer, 0, sizeof(buffer)); + + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + err = kstrtoint(strstrip(buffer), 0, &page_hot_count); + if (err) + goto out; + + task = get_proc_task(file_inode(file)); + if (!task) { + err = -ESRCH; + goto out; + } + + task->hot_count = page_hot_count; + uid = __task_cred(task)->user->uid.val; + + if (!page_hot_count) { + smart_boost_reclaim_by_uid(uid); + delete_prio_node(uid); + } else { + insert_prio_node(page_hot_count, uid); + } + + put_task_struct(task); + +out: + return err < 0 ? err : count; +} + +const struct file_operations proc_page_hot_count_operations = { + .read = page_hot_count_read, + .write = page_hot_count_write, +}; + +static int __init smartboost_init(void) +{ + struct smb_cb_set set; + + vmpressure_notifier_register(&smb_vmpressure_statistic); + + proc_create("uid_lru_info", 0444, NULL, + &proc_uid_lru_info_file_operations); + + set.smb_uid_lru_add_cb = ctech_smb_uid_lru_add; + set.smb_isolate_list_or_putbcak_cb = ctech_smb_isolate_list_or_putbcak; + set.smb_update_uid_lru_size_cb = ctech_smb_update_uid_lru_size; + smb_register_cb_set(&set); + + return 0; +} + +module_param_named(page_cache_reside_switch, + sysctl_page_cache_reside_switch, + uint, 0644); +module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, + S_IRUGO | S_IWUSR); + +module_init(smartboost_init) + diff --git a/drivers/oneplus/coretech/smartboost/smartboost_helper.c b/drivers/oneplus/coretech/smartboost/smartboost_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..6d5019c223c1302e75447be69755b97483f62a04 --- /dev/null +++ b/drivers/oneplus/coretech/smartboost/smartboost_helper.c @@ -0,0 +1,38 @@ +#include +#include + +struct smb_cb_set smb_cbs; + +bool smb_uid_lru_add(struct page *page) +{ + if (smb_cbs.smb_uid_lru_add_cb) + return smb_cbs.smb_uid_lru_add_cb(page); + else + return false; +} + +unsigned long smb_isolate_list_or_putbcak(struct list_head *page_list, + struct lruvec *lruvec, struct pglist_data *pgdat, int priority, + bool enough_list_reclaimed) +{ + if (smb_cbs.smb_isolate_list_or_putbcak_cb) + return smb_cbs.smb_isolate_list_or_putbcak_cb(page_list, + lruvec, pgdat, priority, enough_list_reclaimed); + else + return 0; +} + +bool smb_update_uid_lru_size(struct page *page, + struct lruvec *lruvec, enum lru_list lru) +{ + if (smb_cbs.smb_update_uid_lru_size_cb) + return smb_cbs.smb_update_uid_lru_size_cb(page, lruvec, lru); + else + return false; +} + +void smb_register_cb_set(struct smb_cb_set *set) +{ + smb_cbs = *set; +} + diff --git a/drivers/oneplus/coretech/tpd/Makefile b/drivers/oneplus/coretech/tpd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..804712c82f34e10d95b52c5e3ca3cdce5cd76f4d --- /dev/null +++ b/drivers/oneplus/coretech/tpd/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TPD) += tpd.o diff --git a/drivers/oneplus/coretech/tpd/tpd.c b/drivers/oneplus/coretech/tpd/tpd.c new file mode 100644 index 0000000000000000000000000000000000000000..fe849bac0ebe95b2245806130997dfe990343084 --- /dev/null +++ b/drivers/oneplus/coretech/tpd/tpd.c @@ -0,0 +1,857 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Task Placement Decision + * + * two main rules as below: + * 1. trigger tpd with tgid and thread's name which will be limited + * through online config, framework can tag threads and limit cpu placement + * of tagged threads that are also foreground task. + * tpd_cmds + * 2. trigger tpd with tgid and thread_id + * control the placement limitation by itself, set tpd_ctl = 1 will limit + * cpu placement of tagged threads, but need release by itself to set tpd_enable = 0, + * tpd_ctl = 0 and task->tpd = 0 + * tpd_id + * 3. control the placement limitation by itself, set tpd_ctl = 1 will limit + * cpu placement of tagged threads, but need release by itself to set tpd_enable = 0, + * tpd_ctl = 0 and task->tpd = 0 + * tpd_dynamic + */ + +struct tgid_list_entry { + int pid; + struct list_head node; +}; + +struct monitor_gp { + int decision; /* cpu affinity */ + spinlock_t tgid_list_lock; /* used to check dynamic tpd task */ + struct list_head tgid_head;/* used to check dynamic tpd task */ + spinlock_t miss_list_lock; /* used to check if need re-tag or not */ + unsigned int miss_list_tgid[MAX_MISS_LIST];/* used to check if need re-tag or not */ + char miss_list[MAX_MISS_LIST][TASK_COMM_LEN];/* used to check if need re-tag or not */ + int not_yet; + int cur_idx; +}; + +/* monitor group for dynamic tpd threads */ +static struct monitor_gp mgp[TPD_GROUP_MAX]; + +static atomic_t tpd_enable_rc = ATOMIC_INIT(0); +static int tpd_enable_rc_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tpd_enable_rc)); +} + +static struct kernel_param_ops tpd_enable_rc_ops = { + .get = tpd_enable_rc_show, +}; + +module_param_cb(tpd_en_rc, &tpd_enable_rc_ops, NULL, 0664); + +static int tpd_log_lv = 2; +module_param_named(log_lv, tpd_log_lv, int, 0664); + +static atomic_t tpd_ctl = ATOMIC_INIT(0); /* used to ignore fg task checking */ + +static bool should_update_tpd_enable(int enable) { + + bool ret = true; + int refcnt = 0; + + if (enable) { + if (atomic_inc_return(&tpd_enable_rc) > 1) + ret = false; + } else { + refcnt = atomic_read(&tpd_enable_rc); + if (refcnt < 1) { + ret = false; + goto out; + } + + /* tpd_enable ref count must greater or equal tpd_ctl */ + if (refcnt - 1 < atomic_read(&tpd_ctl)) { + ret = false; + goto out; + } + + if (atomic_dec_return(&tpd_enable_rc) > 0) { + tpd_loge("tpd cannot disable"); + ret = false; + } + } + +out: + tpd_logv("should_update_tpd_enable? %d", ret); + + return ret; +} + +static int tpd_enable = 0; +static int tpd_enable_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (should_update_tpd_enable(val)) + tpd_enable = val; + + return 0; +} + +static int tpd_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", tpd_enable); +} + +static struct kernel_param_ops tpd_enable_ops = { + .set = tpd_enable_store, + .get = tpd_enable_show, +}; + +module_param_cb(tpd_enable, &tpd_enable_ops, NULL, 0664); + +bool is_tpd_enable(void) +{ + return tpd_enable; +} + +static int miss_list_show(char *buf, const struct kernel_param *kp) +{ + int i, j; + int cnt = 0; + + for (j = TPD_GROUP_MEDIAPROVIDER; j < TPD_GROUP_MAX; ++j) { + spin_lock(&mgp[j].miss_list_lock); + if (mgp[j].not_yet > 0) { + for (i = 0; i < MAX_MISS_LIST; ++i) { + if(strlen(mgp[j].miss_list[i]) > 0) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%s %d\n", mgp[j].miss_list[i], mgp[j].miss_list_tgid[i]); + } + } + } + spin_unlock(&mgp[j].miss_list_lock); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n"); + } + return cnt; +} + +static struct kernel_param_ops miss_list_ops = { + .get = miss_list_show, +}; + +module_param_cb(miss_list, &miss_list_ops, NULL, 0664); + +bool is_dynamic_tpd_task(struct task_struct *tsk) +{ + int gid, len = 0, i; + bool ret = false; + struct monitor_gp *group; + struct tgid_list_entry *p; + struct task_struct *leader; + + /* this is for all tpd tasks reset(dynamic/not dynamic tpd tasks) */ + if (!tpd_enable) { + tsk->tpd = 0; + tsk->dtpdg = -1; + tsk->dtpd = 0; + return ret; + } + + leader = tsk ? tsk->group_leader : NULL; + if (leader == NULL) + return ret; + + gid = leader->dtpdg; + /* not dynamic tpd task will return */ + if (gid < TPD_GROUP_MEDIAPROVIDER || gid > TPD_GROUP_MAX) + return ret; + + group = &mgp[gid]; + + switch (gid) { + case TPD_GROUP_MEDIAPROVIDER: + + spin_lock(&group->tgid_list_lock); + + /* no dynamic tpd task enable of this dynamic tpd group id */ + if (list_empty(&group->tgid_head)) { + if (tsk->dtpd) { + tsk->dtpd = 0; + tsk->tpd = 0; + } + spin_unlock(&group->tgid_list_lock); + return ret; + } + + list_for_each_entry(p, &group->tgid_head, node) { + if (leader->pid != p->pid) + continue; + + /* parent of thread was dynamic tpd task */ + /* dynamic tpd task has already tagged */ + if (tsk->dtpd && tsk->tpd) { + ret = true; + break; + } + + /* start tagging process */ +#ifdef CONFIG_IM + /*binder thread of media provider */ + if (im_binder(tsk)) { + tsk->dtpd = 1; /* dynamic tpd */ + tsk->tpd = group->decision; + ret = true; + break; + } +#endif + +#ifdef CONFIG_ONEPLUS_FG_OPT + /* fuse related thread of media provider */ + if (tsk->fuse_boost) { + tsk->dtpd = 1; /* dynamic tpd */ + tsk->tpd = group->decision; + ret = true; + break; + } +#endif + /* re-tag missed thread, only one name with one thread */ + spin_lock(&group->miss_list_lock); + if (group->not_yet > 0) { + for (i = 0; i < MAX_MISS_LIST; ++i) { + len = strlen(group->miss_list[i]); + if (len == 0) + continue; + if (group->miss_list_tgid[i] != p->pid) + continue; + if (!strncmp(tsk->comm, group->miss_list[i], len)) { + strcpy(group->miss_list[i], ""); + group->miss_list_tgid[i] = 0; + tsk->dtpd = 1; + tsk->tpd = group->decision; + group->not_yet--; + ret = true; + break; + } + } + + if (ret) { + spin_unlock(&group->miss_list_lock); + break; + } + } + spin_unlock(&group->miss_list_lock); + /* end tagging process */ + } + spin_unlock(&group->tgid_list_lock); + + /* reset flag if dynamic tpd task removed (tgid was removed) */ + if (!ret) { + if (tsk->dtpd) { + tsk->dtpd = 0; + tsk->tpd = 0; + } + } + break; + default: + break; + } + + return ret; +} + +static void set_tpd_ctl(int force) +{ + if (force) + atomic_inc(&tpd_ctl); + else { + if (atomic_read(&tpd_ctl) > 0) + atomic_dec(&tpd_ctl); + } +} + +static int tpd_ctl_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + set_tpd_ctl(val); + + return 0; +} + +static int tpd_ctl_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tpd_ctl)); +} + +static struct kernel_param_ops tpd_ctl_ops = { + .set = tpd_ctl_store, + .get = tpd_ctl_show, +}; + +module_param_cb(tpd_ctl, &tpd_ctl_ops, NULL, 0664); + +static inline void tagging(struct task_struct *tsk, int decision) +{ + if (tsk == NULL) { + tpd_loge("task cannot set"); + return; + } + + tpd_logv("%s task: %s pid:%d decision:%d\n", __func__, tsk->comm, tsk->pid, decision); + + tsk->tpd = decision; +} + +static inline void tagging_by_name(struct task_struct *tsk, char* name, int decision, int *cnt) +{ + size_t tlen = 0, len = 0; + + tlen = strlen(name); + if (tlen == 0) + return; + + len = strlen(tsk->comm); + + if (len != tlen) + return; + + if (!strncmp(tsk->comm, name, tlen)) { + tpd_logv("%s task: %s pid:%d decision:%d name=%s\n", __func__, tsk->comm, tsk->pid, decision, name); + tsk->tpd = decision; + *cnt = *cnt + 1; + } +} + +static void tag_from_tgid(unsigned int tgid, int decision, char* thread_name, int *cnt) +{ + struct task_struct *p, *t; + + rcu_read_lock(); + p = find_task_by_vpid(tgid); + if (p) { + for_each_thread(p, t) + tagging_by_name(t, thread_name, decision, cnt); + } + rcu_read_unlock(); + +} + +static inline void dy_tagging_by_name(struct task_struct *tsk, const char* name, int decision, int dtpd, int *cnt) +{ + size_t tlen = 0, len = 0; + + tlen = strlen(name); + if (tlen == 0) + return; + + len = strlen(tsk->comm); + + if (len != tlen) + return; + + if (!strncmp(tsk->comm, name, tlen)) { + tpd_logv("%s task: %s pid:%d decision:%d name=%s, dtpd=%d\n", __func__, tsk->comm, tsk->pid, decision, name, dtpd); + tsk->tpd = decision; + tsk->dtpd = dtpd; + *cnt = *cnt + 1; + } +} + +static void dy_tag_from_tgid(unsigned int tgid, int decision, const char* thread_name, int dtpd, int *cnt) +{ + struct task_struct *p, *t; + + rcu_read_lock(); + p = find_task_by_vpid(tgid); + if (p) { + for_each_thread(p, t) + dy_tagging_by_name(t, thread_name, decision, dtpd, cnt); + } + rcu_read_unlock(); + +} + +/* set dtpd group id in the main thread */ +static void tag_dtpdg(unsigned int tgid, unsigned int dtpdg) +{ + struct task_struct *p; + + rcu_read_lock(); + p = find_task_by_vpid(tgid); + if (p) { + p->dtpdg = dtpdg; + } + rcu_read_unlock(); + +} + +static int tpd_cmd_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int tgid = 0; + int tp_decision = -1; + char threads[MAX_THREAD_INPUT][TASK_COMM_LEN] = {{0}, {0}, {0}, {0}, {0}, {0}}; + int ret, i, cnt = 0; + + ret = sscanf(buf, "%u %d %s %s %s %s %s %s\n", + &tgid, &tp_decision, + threads[0], threads[1], threads[2], threads[3], threads[4], threads[5]); + + tpd_logi("tpd params: %u %d %s %s %s %s %s %s, from %s %d, total=%d\n", + tgid, tp_decision, threads[0], threads[1], threads[2], threads[3], threads[4], threads[5], + current->comm, current->pid, ret); + + for (i = 0; i < MAX_THREAD_INPUT; i++) { + if (strlen(threads[i]) > 0) + tag_from_tgid(tgid, tp_decision, threads[i], &cnt); + } + + tpd_logv("tpd tagging count = %d\n", cnt); + + return 0; +} + +static struct kernel_param_ops tpd_cmd_ops = { + .set = tpd_cmd_store, +}; +module_param_cb(tpd_cmds, &tpd_cmd_ops, NULL, 0664); + +static void tag_from_tid(unsigned int pid, unsigned int tid, int decision) +{ + struct task_struct *p; + + rcu_read_lock(); + p = find_task_by_vpid(tid); + if (p) { + if (p->group_leader && (p->group_leader->pid == pid)) { + tpd_logv("tpd tagging task pid= %d\n", pid); + tagging(p, decision); + } + } else { + tpd_loge("cannot find task!!! pid = %d", tid); + } + rcu_read_unlock(); +} + +static int tpd_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int pid = 0; + unsigned int tid = 0; + int tpdenable = 0; + int tp_decision = -1; + int ret; + + ret = sscanf(buf, "%u,%u,%d,%d\n", + &pid, &tid, &tpdenable, &tp_decision); + + tpd_logi("tpd param pid:%u tid:%u, tpd_enable:%d decision:%d from %s %d\n", + pid, tid, tpdenable, tp_decision, current->comm, current->pid); + + if (ret != 4) { + tpd_loge("Invalid params!!!!!!"); + return 0; + } + + tag_from_tid(pid, tid, tpdenable ? tp_decision : 0); + + set_tpd_ctl(tpdenable); + + /* update tpd_enable ref cnt*/ + if (should_update_tpd_enable(tpdenable)) + tpd_enable = tpdenable; + + return 0; +} + +static struct kernel_param_ops tpd_ops = { + .set = tpd_store, +}; +module_param_cb(tpd_id, &tpd_ops, NULL, 0664); + +static void tgid_list_add(struct monitor_gp *_mgp, int pid) +{ + struct tgid_list_entry *p; + + p = kmalloc(sizeof(struct tgid_list_entry), GFP_KERNEL); + if (p == NULL) + return; + p->pid = pid; + INIT_LIST_HEAD(&p->node); + + spin_lock(&_mgp->tgid_list_lock); + list_add_tail(&p->node, &_mgp->tgid_head); + tpd_logv("add main thread: %d", pid); + spin_unlock(&_mgp->tgid_list_lock); +} + +static void reset_miss_list(struct monitor_gp *group) +{ + int i,len; + + spin_lock(&group->miss_list_lock); + for (i = 0; i < MAX_MISS_LIST; ++i) { + len = strlen(group->miss_list[i]); + if (len == 0) + continue; + strcpy(group->miss_list[i], ""); + group->miss_list_tgid[i] = 0; + } + group->not_yet = 0; + spin_unlock(&group->miss_list_lock); +} + +void tpd_tglist_del(struct task_struct *tsk) +{ + struct tgid_list_entry *p, *next; + struct monitor_gp *group; + + if (!tsk->pid) + return; + + if (tsk->dtpdg < 0 || tsk->dtpdg >= TPD_GROUP_MAX) + return; + + group = &mgp[tsk->dtpdg]; + + spin_lock(&group->tgid_list_lock); + + if (list_empty(&group->tgid_head)) + goto unlock; + + list_for_each_entry_safe(p, next, &group->tgid_head, node) { + if (p != NULL && (p->pid == tsk->pid)) { + list_del_init(&p->node); + tpd_logv("remove task: %d", tsk->pid); + kfree(p); + break; + } + } + + /* if no tgid in list, disable tpd_ctl && try to disable tpd */ + if (list_empty(&group->tgid_head)) { + set_tpd_ctl(0); + reset_miss_list(group); + if (should_update_tpd_enable(0)) + tpd_enable = 0; + } + +unlock: + spin_unlock(&group->tgid_list_lock); +} + +/* return true if list size is from one to empty */ +static bool tgid_list_del(struct monitor_gp *_mgp, int pid) +{ + struct tgid_list_entry *p, *next; + bool ret = false; + + spin_lock(&_mgp->tgid_list_lock); + /* do nothing if list empty */ + if (list_empty(&_mgp->tgid_head)) + goto unlock; + + list_for_each_entry_safe(p, next, &_mgp->tgid_head, node) { + if (p != NULL && (p->pid == pid)) { + list_del_init(&p->node); + tpd_logv("remove main thread: %d", pid); + kfree(p); + break; + } + } + /* re-check if list is empty after list deletion */ + if (list_empty(&_mgp->tgid_head)) + ret = true; + +unlock: + spin_unlock(&_mgp->tgid_list_lock); + return ret; +} + +static int list_show(char *buf, const struct kernel_param *kp) +{ + struct tgid_list_entry *p; + int cnt = 0; + int i; + + for (i = 0; i < TPD_GROUP_MAX; ++i) { + spin_lock(&mgp[i].tgid_list_lock); + + if (list_empty(&mgp[i].tgid_head)) + goto unlock; + + list_for_each_entry(p, &mgp[i].tgid_head, node) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%d %d\n", i, p->pid); + } +unlock: + spin_unlock(&mgp[i].tgid_list_lock); + } + + return cnt; +} + +static struct kernel_param_ops tgid_list_ops = { + .get = list_show, +}; + +module_param_cb(tgid_list, &tgid_list_ops, NULL, 0664); + +#define MONITOR_THREAD_NUM 1 +static int tpd_process_trigger_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int tgid = 0; + int tpdenable = 0; + int tp_decision = -1; + int tpd_group = -1; + int ret, i, cnt = 0, j; + const char *threads[MONITOR_THREAD_NUM] = {"bg"}; + struct monitor_gp *group; + + ret = sscanf(buf, "%d,%u,%d,%d\n", + &tpd_group, &tgid, &tpdenable, &tp_decision); + + tpd_logi("tpd param group:%d pid:%u tpd_enable:%d decision:%d from %s %d\n", + tpd_group, tgid, tpdenable, tp_decision, current->comm, current->pid); + + if (ret != 4) { + tpd_loge("Invalid params!!!!!!"); + return 0; + } + + if (tpd_group >= TPD_GROUP_MAX || tpd_group < 0) { + tpd_loge("Invalid group!!!!!!"); + return 0; + } + + group = &mgp[tpd_group]; + + if (!tpdenable) { + if (tgid_list_del(group, tgid)) + group->decision = 0; + + tag_dtpdg(tgid, -1); + } else { + group->decision = tp_decision; + tgid_list_add(group, tgid); + tag_dtpdg(tgid, tpd_group); + } + + set_tpd_ctl(tpdenable); + + + /* tagged by name from group: media provider */ + if (tpd_group == TPD_GROUP_MEDIAPROVIDER) { + for(i = 0; i < MONITOR_THREAD_NUM; i++) { + cnt = 0; + dy_tag_from_tgid(tgid, tpdenable ? tp_decision : 0, threads[i], tpdenable, &cnt); + /* can't find thread to tag/un-tag */ + if (cnt == 0) { + spin_lock(&group->miss_list_lock); + if (tpdenable) { + /* need re-tag, add thread name into miss_list */ + strncpy(group->miss_list[group->cur_idx], threads[i], TASK_COMM_LEN); + group->miss_list_tgid[group->cur_idx] = tgid; + group->cur_idx = (++group->cur_idx) % MAX_MISS_LIST; + group->not_yet++; + } else { + /* dynmic tpd disabled when miss_list still have thread need to tag, we clear the miss list */ + for (j = 0; j < MAX_MISS_LIST; ++j) { + if (group->miss_list_tgid[j] == tgid) { + strcpy(group->miss_list[j], ""); + group->miss_list_tgid[j] = 0; + group->not_yet--; + } + } + } + spin_unlock(&group->miss_list_lock); + } + } + } + + tpd_logv("tagging count = %d, tpd enable set:%d", cnt, tpdenable); + + /* update tpd_enable by ref cnt */ + if (should_update_tpd_enable(tpdenable)) + tpd_enable = tpdenable; + + return 0; +} + +static struct kernel_param_ops tpd_pt_ops = { + .set = tpd_process_trigger_store, +}; +module_param_cb(tpd_dynamic, &tpd_pt_ops, NULL, 0664); + +int tpd_suggested(struct task_struct* tsk, int min_idx, int mid_idx, int max_idx, int request_cpu) +{ + int suggest_cpu = request_cpu; + + if (!(task_is_fg(tsk) || atomic_read(&tpd_ctl))) + goto out; + + switch (tsk->tpd) { + case TPD_TYPE_S: + case TPD_TYPE_GS: + case TPD_TYPE_PS: + case TPD_TYPE_PGS: + suggest_cpu = min_idx; + break; + case TPD_TYPE_G: + case TPD_TYPE_PG: + suggest_cpu = mid_idx; + break; + case TPD_TYPE_P: + suggest_cpu = max_idx; + break; + default: + break; + } +out: + tpd_logi("pid = %d: comm = %s, tpd = %d, suggest_cpu = %d, task is fg? %d, tpd_ctl = %d\n", tsk->pid, tsk->comm, + tsk->tpd, suggest_cpu, task_is_fg(tsk), atomic_read(&tpd_ctl)); + return suggest_cpu; +} + +void tpd_mask(struct task_struct* tsk, int min_idx, int mid_idx, int max_idx, cpumask_t *request, int nrcpu) +{ + int start_idx = nrcpu, end_idx = -1, i, next_start_idx = nrcpu; + bool second_round = false; + + if (!(task_is_fg(tsk) || atomic_read(&tpd_ctl))) { + if (!task_is_fg(tsk)) + tpd_logv("task is not fg!!!\n"); + return; + } + + switch (tsk->tpd) { + case TPD_TYPE_S: + start_idx = mid_idx; + break; + case TPD_TYPE_G: + start_idx = min_idx; + end_idx = mid_idx; + second_round = true; + next_start_idx = max_idx; + break; + case TPD_TYPE_GS: + start_idx = max_idx; + break; + case TPD_TYPE_P: + start_idx = min_idx; + end_idx = max_idx; + break; + case TPD_TYPE_PS: + start_idx = mid_idx; + end_idx = max_idx; + break; + case TPD_TYPE_PG: + start_idx = min_idx; + end_idx = mid_idx; + break; + default: + break; + } + +redo: + for (i = start_idx; i < nrcpu; ++i) { + + if (i == end_idx) + break; + + tpd_logv("task: %d, cpu clear bit = %d\n", (tsk) ? tsk->pid : -1, i); + + cpumask_clear_cpu(i, request); + } + + if (second_round) { + start_idx = next_start_idx; + second_round = false; + goto redo; + } + + tpd_logi("pid = %d: comm = %s, tpd = %d, min_idx = %d, mid_idx = %d, max_idx = %d, task is fg? %d, tpd_ctl = %d\n", tsk->pid, tsk->comm, + tsk->tpd, min_idx, mid_idx, max_idx, task_is_fg(tsk), atomic_read(&tpd_ctl)); +} + +bool tpd_check(struct task_struct *tsk, int dest_cpu, int min_idx, int mid_idx, int max_idx) +{ + bool mismatch = false; + + if (!(task_is_fg(tsk) || atomic_read(&tpd_ctl))) + goto out; + + switch (tsk->tpd) { + case TPD_TYPE_S: + if (dest_cpu >= mid_idx) + mismatch = true; + break; + case TPD_TYPE_G: + if ((mid_idx != max_idx) && + (dest_cpu < mid_idx || dest_cpu >= max_idx)) + mismatch = true; + break; + case TPD_TYPE_GS: + /* if no gold plus cores, mid = max*/ + if (dest_cpu >= max_idx) + mismatch = true; + break; + case TPD_TYPE_P: + if (dest_cpu < max_idx) + mismatch = true; + break; + case TPD_TYPE_PS: + if (dest_cpu < max_idx && dest_cpu >= mid_idx) + mismatch = true; + break; + case TPD_TYPE_PG: + if (dest_cpu < mid_idx) + mismatch = true; + break; + default: + break; + } + +out: + tpd_logi("task:%d comm:%s dst: %d should migrate = %d, task is fg? %d\n", tsk->pid, tsk->comm, dest_cpu, !mismatch, task_is_fg(tsk)); + + return mismatch; +} + +static void tpd_mgp_init() +{ + int i, j; + + for (i = 0; i < TPD_GROUP_MAX; ++i) { + mgp[i].decision = 0; + spin_lock_init(&mgp[i].tgid_list_lock); + INIT_LIST_HEAD(&mgp[i].tgid_head); + spin_lock_init(&mgp[i].miss_list_lock); + for (j = 0; j < MAX_MISS_LIST; j++) { + mgp[i].miss_list_tgid[j] = 0; + strcpy(mgp[i].miss_list[j], ""); + } + mgp[i].not_yet = 0; + mgp[i].cur_idx = 0; + } +} + +static int tpd_init(void) +{ + tpd_mgp_init(); + tpd_logv("tpd init\n"); + return 0; +} + +pure_initcall(tpd_init); diff --git a/drivers/oneplus/coretech/tpp/Makefile b/drivers/oneplus/coretech/tpp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..94cced4a5200a98e05fa04e88cb7889d5eb09c7e --- /dev/null +++ b/drivers/oneplus/coretech/tpp/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TPP) += tpp.o diff --git a/drivers/oneplus/coretech/tpp/tpp.c b/drivers/oneplus/coretech/tpp/tpp.c new file mode 100644 index 0000000000000000000000000000000000000000..bd66688f65a7f90c8aab8294fa75446564c20395 --- /dev/null +++ b/drivers/oneplus/coretech/tpp/tpp.c @@ -0,0 +1,619 @@ +#include +#include +#include +#include +#include +#include +#include +#include "../../../../kernel/sched/sched.h" + +/* + * log output + * lv == 0 -> verbose info + * lv == 1 -> some infomation + * lv == 2 -> warning + * lv == 3 -> error + */ +static int tpp_log_lv = 1; + +// Set tpp_on 1 to open tpp features +static int tpp_on = 1; + +static int tpp_task_record_on = 0; + +static int tpp_strategy = TPP_UNITY_WORKER_THREAD_MIDDLE_CORE; + +static struct tpp_task_monitor_struct tpp_task_monitor = {.buf = NULL}; +static int get_tpp_thread_cnt(int flag, int cpu); + +static struct tpp_cpu_select_monitor_struct tpp_cpu_select_monitor = { + .buf = NULL, + .index = ATOMIC_INIT(-1) +}; + +// Need to align tpp.h TPP_MINITOR_SIZE + +static const char *tpp_task_monitor_case[TPP_TASK_MONITOR_SIZE] = { + "normal", + "worker_thread", +}; + +static const char *tpp_strategy_str[] = { + "orig", + "worker_thread_middle_core" +}; + +static inline bool tpp_worker_thread(struct task_struct *p) +{ + return (bool)(p->tpp_flag & TPP_UNITY_WORKER_THREAD); +} + +static inline bool cpu_available(int cpu) +{ + return cpu_online(cpu) && !cpu_isolated(cpu); +} + +static inline int get_tpp_task_id(struct task_struct *p) +{ + return tpp_worker_thread(p) ? TPP_UNITY_WORKER_THREAD_ID : TPP_OTHER_THREAD_ID; +} + +static inline bool im_tpp(struct task_struct *p) +{ + // Now only worker thread will be concerned + return tpp_worker_thread(p); +} + +static void __tpp_task_record(int tpp_task_id, int util, int cpu_orig, int cpu) { + int index; + int tag_index = tpp_task_id; + int offset; + + if (tpp_task_record_on && (!tpp_task_monitor.buf)) { + tpp_loge("init sample buffer failed, set enabled state to 0\n"); + tpp_task_record_on = 0; + } + if (!tpp_task_record_on || tag_index >= TPP_TASK_MONITOR_SIZE) { + return; + } + + index = atomic_inc_return(&tpp_task_monitor.index[tag_index]); + if (index >= TPP_TASK_REPORT_SIZE) + return; + offset = tag_index * TPP_TASK_COLUMN; + tpp_task_monitor.buf->data[index][offset + TPP_TASK_TAG_UTIL] = util; + tpp_task_monitor.buf->data[index][offset + TPP_TASK_TAG_CPU_ORIG] = cpu_orig; + tpp_task_monitor.buf->data[index][offset + TPP_TASK_TAG_CPU] = cpu; + if (cpu == -1) + cpu = cpu_orig; + tpp_task_monitor.buf->data[index][offset + TPP_TASK_TAG_WORK_THREAD] = + get_tpp_thread_cnt(TPP_UNITY_WORKER_THREAD_ID, cpu); +} + +static void tpp_task_record(struct task_struct *p, int cpu_orig, int cpu) +{ + int util = task_util(p); + int tpp_task_id = get_tpp_task_id(p); + + if (tpp_task_id > -1 && tpp_task_id < TPP_TASK_MONITOR_SIZE) { + __tpp_task_record(tpp_task_id, util, cpu_orig, cpu); + } +} + + +static inline void tpp_cpu_select_index_clear(void) +{ + if (!tpp_cpu_select_monitor.buf) + return; + atomic_set(&(tpp_cpu_select_monitor.index), -1); +} + +static inline void tpp_task_index_clear(void) +{ + int i = 0; + if (!tpp_task_monitor.buf) + return; + for (i = 0; i < TPP_TASK_MONITOR_SIZE; i ++) + atomic_set(&(tpp_task_monitor.index[i]), -1); +} + +static int tpp_task_record_on_set(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) { + tpp_loge("error setting argument. argument should be 1 or 0\n"); + return -EINVAL; + } + + tpp_task_record_on = !!val; + if (tpp_task_record_on) { + if (!tpp_task_monitor.buf) + tpp_task_monitor.buf = (struct tpp_task_sample*)vzalloc(sizeof(struct tpp_task_sample)); + if (!tpp_cpu_select_monitor.buf) + tpp_cpu_select_monitor.buf = (struct tpp_cpu_select_sample*)vzalloc(sizeof(struct tpp_cpu_select_sample)); + } else if (!tpp_task_record_on && tpp_task_monitor.buf && tpp_cpu_select_monitor.buf) { + tpp_task_index_clear(); + tpp_cpu_select_index_clear(); + } + return 0; +} + +static inline int tpp_task_record_on_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", tpp_task_record_on); +} + +static atomic_t tpp_thread_cnt[TPP_TASK_MONITOR_SIZE][TPP_NR_CPUS]; + +static inline int get_tpp_thread_cnt(int flag, int cpu) +{ + return flag != -1 ? atomic_read(&tpp_thread_cnt[flag][cpu]) : 0; +} + +static inline int wk_thrd_ops_show(char *buf, const struct kernel_param *kp) +{ + int i; + unsigned int l = 0; + for (i = 0; i < TPP_NR_CPUS; ++i) { + l += snprintf(buf + l, PAGE_SIZE - l,"%d ", get_tpp_thread_cnt(TPP_UNITY_WORKER_THREAD_ID, i)); + } + return l; +} + +static inline void tpp_thread_cnt_inc(int flag, int cpu) { + atomic_inc(&tpp_thread_cnt[flag][cpu]); +} + +static inline void tpp_thread_cnt_dec(int flag, int cpu) { + atomic_dec(&tpp_thread_cnt[flag][cpu]); +} + +static int strategy_names_show(char *buf, const struct kernel_param *kp) +{ + size_t len = 0; + int i; + + for (i = 0; i < TPP_STRATEGY_SIZE; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%d: %s\n", i, tpp_strategy_str[i]); + return len; +} + +static inline void clear_tpp_thread_cnt(void) { + int cpu, flag; + + for_each_possible_cpu(cpu) { + for (flag = 0; flag < TPP_TASK_MONITOR_SIZE; flag++) { + atomic_set(&tpp_thread_cnt[flag][cpu], 0); + } + } +} + +static int tpp_clear_threads_cnt(char const *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) >= 0 && val != 0) { + clear_tpp_thread_cnt(); + return 0; + } else { + tpp_logi(" not clear\n"); + return -1; + } +} + +static int tpp_cpu_select_index_set(const char *buf, const struct kernel_param *kp) +{ + int val; + size_t len = sscanf(buf, "%d\n", &val); + + if (tpp_cpu_select_monitor.buf && len > 0 && val < TPP_CPU_SELECT_MAX_REPORT_SIZE && val >= -1) { + tpp_logi("Set index to %d\n", val); + atomic_set(&(tpp_cpu_select_monitor.index), val); + return 0; + } else { + tpp_loge("Error setting argument." + "Argument should be integer between %d and %d.\n", + TPP_CPU_SELECT_MAX_REPORT_SIZE, -1); + return -EINVAL; + } +} + +static int tpp_task_index_set(const char *buf, const struct kernel_param *kp) +{ + int val[TPP_TASK_MONITOR_SIZE]; + int i; + size_t len = 0; + + for (i = 0; i < TPP_TASK_MONITOR_SIZE; i++) { + len += sscanf(buf+ len, " %d", &val[i]); + } + + for (i = 0; i < TPP_TASK_MONITOR_SIZE; i++) { + if (len > 0 && val[i] < TPP_TASK_REPORT_SIZE && val[i] >= -1) { + tpp_logi("Set index to %d\n", val[i]); + atomic_set(&(tpp_task_monitor.index[i]), val[i]); + } else { + tpp_loge("Error setting argument." + "Argument should be integer between %d and %d.\n", + TPP_TASK_REPORT_SIZE, -1); + return -EINVAL; + } + } + return 0; +} + +static int tpp_task_index_show(char *buf, const struct kernel_param *kp) +{ + size_t len = 0; + int i; + if (!tpp_task_monitor.buf) + return 0; + for (i = 0; i < TPP_TASK_MONITOR_SIZE; i++) { + len += snprintf(buf + len, PAGE_SIZE, "%d ", atomic_read(&tpp_task_monitor.index[i])); + } + len += snprintf(buf + len, PAGE_SIZE, "\n"); + return len; +} + +static int tpp_cpu_select_index_show(char *buf, const struct kernel_param *kp) +{ + if (!tpp_cpu_select_monitor.buf) + return 0; + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tpp_cpu_select_monitor.index)); +} + +static const char *tpp_task_tags[TPP_TASK_COLUMN] = { + "util", + "cpu_orig", + "cpu", + "worker_thread", +}; + +static inline void print_tpp_task_tag(struct seq_file *m) +{ + unsigned int i, j; + for (i = 0; i < TPP_TASK_MONITOR_SIZE; ++i) { + for (j = 0; j < TPP_TASK_COLUMN; ++j) { + seq_printf(m, "%s_%s,", tpp_task_monitor_case[i], tpp_task_tags[j]); + } + } + seq_printf(m, "\n"); +} + +static const char *tpp_cpu_select_tags[TPP_CPU_SELECT_MONITOR_SIZE] = { + "count", + "cpu", +}; + +static inline void print_tpp_cpu_select_tag(struct seq_file *m) +{ + unsigned int i; + + for (i = 0; i < TPP_CPU_SELECT_MONITOR_SIZE; ++i) { + seq_printf(m, "%s,", tpp_cpu_select_tags[i]); + } + seq_printf(m, "\n"); +} + + +static inline void print_tpp_task_data(struct seq_file *m) +{ + unsigned int i, j, k; + unsigned int report_size[TPP_TASK_MONITOR_SIZE]; + if (!tpp_task_monitor.buf) + return; + for (i = 0; i < TPP_TASK_MONITOR_SIZE; ++i) { + report_size[i] = atomic_read(&(tpp_task_monitor.index[i])) + 1; + report_size[i] = min(report_size[i], (unsigned int) TPP_TASK_REPORT_SIZE); + } + + for (i = 0; i < TPP_TASK_REPORT_SIZE; ++i) { + for (j = 0; j < TPP_TASK_MONITOR_SIZE; j++) { + for (k = 0; k < TPP_TASK_COLUMN && i < report_size[j]; k++) + seq_printf(m, "%d,", + tpp_task_monitor.buf->data[i][TPP_TASK_COLUMN * j + k]); + for (k = 0; k < TPP_TASK_COLUMN && i >= report_size[j]; k++) + seq_printf(m, ","); + } + seq_printf(m, "\n"); + } +} + +static inline void print_tpp_cpu_select_data(struct seq_file *m) +{ + unsigned int i, j; + unsigned int report_size; + + if (!tpp_cpu_select_monitor.buf) + return; + + report_size = atomic_read(&tpp_cpu_select_monitor.index) + 1; + report_size = min(report_size, (unsigned int) TPP_CPU_SELECT_MAX_REPORT_SIZE); + + for (i = 0; i < report_size; ++i) { + for (j = 0; j < TPP_CPU_SELECT_MONITOR_SIZE; ++j) + seq_printf(m, "%d," , tpp_cpu_select_monitor.buf->data[i][j]); + seq_printf(m, "\n"); + } +} + +static int tpp_cpu_select_show_report(struct seq_file *m, void *v) +{ + if (tpp_task_record_on) { + print_tpp_cpu_select_tag(m); + print_tpp_cpu_select_data(m); + } else { + seq_printf(m, "Not recorded\n"); + } + return 0; +} + +static int tpp_tagged_list_show(struct seq_file *m, void *v) +{ + struct task_struct *p, *t; + + read_lock(&tasklist_lock); + for_each_process_thread(p, t) { + if (im_tpp(t)) { + seq_printf(m, "pid: %u, tgid: %u im_flag: %u tpp_flag: %u\n", + t->pid, t->tgid, t->im_flag, t->tpp_flag); + } + } + read_unlock(&tasklist_lock); + return 0; +} + +static int tpp_task_show_report(struct seq_file *m, void *v) +{ + if (tpp_task_record_on) { + print_tpp_task_tag(m); + print_tpp_task_data(m); + } else { + seq_printf(m, "Not recorded\n"); + } + return 0; +} + +static int tpp_task_open_report(struct inode *inode, struct file *file) +{ + return single_open(file, tpp_task_show_report, NULL); +} + + +static int tpp_cpu_select_open_report(struct inode *inode, struct file *file) +{ + return single_open(file, tpp_cpu_select_show_report, NULL); +} + +static int tpp_tagged_list_open(struct inode *inode, struct file *file) +{ + return single_open(file, tpp_tagged_list_show, NULL); +} + +static const struct file_operations tpp_cpu_select_report_proc_fops = { + .open = tpp_cpu_select_open_report, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations tpp_tagged_list_proc_fops = { + .open = tpp_tagged_list_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations tpp_task_report_proc_fops = { + .open = tpp_task_open_report, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static inline void tpp_cpu_select_record(int tpp_task_id, int cpu) +{ + int index; + if (!tpp_task_record_on || !tpp_cpu_select_monitor.buf) + return; + index = atomic_inc_return(&tpp_cpu_select_monitor.index); + if (index < TPP_CPU_SELECT_MAX_REPORT_SIZE) { + tpp_cpu_select_monitor.buf->data[index][TPP_CPU_SELECT_TPP_TASK_ID] = tpp_task_id; + tpp_cpu_select_monitor.buf->data[index][TPP_CPU_SELECT_CPU] = cpu; + } +} + +static inline void tpp_thread_enqueue(int cpu, struct task_struct *p) +{ + int tpp_task_id = get_tpp_task_id(p); + + if (tpp_task_id >= TPP_TASK_MONITOR_SIZE || tpp_task_id < 0) + return; + else { + tpp_thread_cnt_inc(tpp_task_id, cpu); + tpp_cpu_select_record(tpp_task_id, cpu); + } +} + + +inline void tpp_enqueue(int cpu, struct task_struct *p) +{ + if (tpp_on && im_tpp(p)) { + tpp_thread_enqueue(cpu, p); + p->tpp_flag |= TPP_CFS_RQ; + } +} + +static inline void tpp_thread_dequeue(int cpu, struct task_struct *p) +{ + int tpp_task_id = get_tpp_task_id(p); + + if (tpp_task_id >= TPP_TASK_MONITOR_SIZE || tpp_task_id < 0) + return; + else { + tpp_thread_cnt_dec(tpp_task_id, cpu); + } +} + +static int unity_tgid = -1; +inline void tpp_tagging(struct task_struct *p) +{ + if (im_unity_main(p)) { + tpp_logv("unity_main tgid %d, pid %d", p->tgid, p->pid); + unity_tgid = p->tgid; + } + /* Let only the worker threads which belong to Unity will be tagged*/ + if (p->tgid == unity_tgid) { + size_t len = 0; + + if (p->tpp_flag & TPP_UNITY_WORKER_THREAD) { + p->im_flag |= IM_UNITY_WORKER_THREAD; + return; + } + + len = strlen(p->comm); + if ((len >= 6 && !strncmp(p->comm, "Worker", 6)) || + (len >= 10 && !strncmp(p->comm, "Job.Worker", 10))) { + p->im_flag |= IM_UNITY_WORKER_THREAD; + p->tpp_flag |= TPP_UNITY_WORKER_THREAD; + } + } +} + +inline void tpp_dequeue(int cpu, struct task_struct *p) +{ + if (p->tpp_flag & TPP_CFS_RQ) { + tpp_thread_dequeue(cpu, p); + p->tpp_flag &= ~(TPP_CFS_RQ); + } +} + +static inline int worker_thread_middle_core(struct task_struct *p, int cpu_orig) +{ + struct root_domain *rd = cpu_rq(smp_processor_id())->rd; + struct sched_domain *start_sd; + struct sched_group *sg; + int start_cpu; + int cpu; + int max_cnt_on_rq = -1; + int candicate_cpu = -1; + + if (!tpp_worker_thread(p)) + return cpu_orig; + start_cpu = rd->mid_cap_orig_cpu; + rcu_read_lock(); + start_sd = rcu_dereference(per_cpu(sd_asym_cpucapacity, start_cpu)); + if (!start_sd) { + rcu_read_unlock(); + return -1; + } + sg = start_sd->groups; + for_each_cpu(cpu, sched_group_span(sg)) { + if (cpu_available(cpu)) { + int cnt_on_rq = get_tpp_thread_cnt(TPP_UNITY_WORKER_THREAD_ID, cpu); + + if (max_cnt_on_rq < cnt_on_rq) { + candicate_cpu = cpu; + max_cnt_on_rq = cnt_on_rq; + } + } + } + rcu_read_unlock(); + + /* For the condition that cpu_orig is belong to middle core */ + if (cpu_orig >= start_cpu && max_cnt_on_rq == 0) + candicate_cpu = cpu_orig; + + return candicate_cpu; +} + +int tpp_find_cpu(struct task_struct *p, int cpu_orig) +{ + int cpu = cpu_orig; + if (!tpp_on) + return cpu_orig; + + switch (tpp_strategy) { + case TPP_UNITY_WORKER_THREAD_MIDDLE_CORE: + cpu = worker_thread_middle_core(p, cpu); + break; + case TPP_STRATEGY_ORIG: + default: + cpu = cpu_orig; + } + if (tpp_task_record_on) + tpp_task_record(p, cpu_orig, cpu); + if (cpu > -1 && cpu < TPP_NR_CPUS) + return cpu; + return cpu_orig; +} + +static struct kernel_param_ops tpp_task_monitor_index_ops = { + .set = tpp_task_index_set, + .get = tpp_task_index_show, +}; + +static struct kernel_param_ops tpp_cpu_select_monitor_index_ops = { + .set = tpp_cpu_select_index_set, + .get = tpp_cpu_select_index_show, +}; + +static struct kernel_param_ops clear_ops = { + .set = tpp_clear_threads_cnt, +}; + +static struct kernel_param_ops strategy_names_ops = { + .get = strategy_names_show, +}; + +static struct kernel_param_ops tpp_task_record_on_ops = { + .set = tpp_task_record_on_set, + .get = tpp_task_record_on_show, +}; + +static struct kernel_param_ops wk_thrd_cnt_ops = { + .get = wk_thrd_ops_show, +}; + +module_param_named(log_lv, tpp_log_lv, int, 0664); +module_param_named(strategy, tpp_strategy, int, 0664); + +module_param_named(tpp_on, tpp_on, int, 0664); +module_param_cb(tpp_task_record_on, &tpp_task_record_on_ops, NULL, 0664); +module_param_cb(tpp_task_monitor_index, &tpp_task_monitor_index_ops, + NULL, 0664); +module_param_cb(tpp_cpu_select_monitor_index, &tpp_cpu_select_monitor_index_ops, + NULL, 0664); +module_param_cb(strategy_names, &strategy_names_ops, NULL, 0664); +module_param_cb(wk_thrd_cnt, &wk_thrd_cnt_ops, NULL, 0664); + +module_param_cb(clear_threads_cnt, &clear_ops, NULL, 0664); + +static int __init tpp_init(void) +{ + tpp_logi("INIT TPP\n"); + proc_create("tpp_task_report", S_IFREG | 0444, NULL, + &tpp_task_report_proc_fops); + proc_create("tpp_tagged_list", S_IFREG | 0444, NULL, + &tpp_tagged_list_proc_fops); + proc_create("tpp_cpu_select_report", S_IFREG | 0444, NULL, + &tpp_cpu_select_report_proc_fops); + return 0; +} + +static void __exit tpp_exit(void) +{ + if (tpp_task_monitor.buf) { + vfree(tpp_task_monitor.buf); + tpp_task_monitor.buf = NULL; + } + if (tpp_cpu_select_monitor.buf) { + vfree(tpp_cpu_select_monitor.buf); + tpp_cpu_select_monitor.buf = NULL; + } + tpp_logi("EXIT TPP\n"); +} + +pure_initcall(tpp_init); +module_exit(tpp_exit); diff --git a/drivers/oneplus/coretech/uxchain/Makefile b/drivers/oneplus/coretech/uxchain/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..12f17158735df85e40242a665c2fe4ee01926f78 --- /dev/null +++ b/drivers/oneplus/coretech/uxchain/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_UXCHAIN) += uxchain.o +obj-$(CONFIG_UXCHAIN_V2) += uxchain_v2.o diff --git a/drivers/oneplus/coretech/uxchain/uxchain.c b/drivers/oneplus/coretech/uxchain/uxchain.c new file mode 100644 index 0000000000000000000000000000000000000000..37e4a78712dac5abf25cc01e22c3e2334cb75d79 --- /dev/null +++ b/drivers/oneplus/coretech/uxchain/uxchain.c @@ -0,0 +1,112 @@ +#ifdef CONFIG_UXCHAIN + +#include +#include +#include +#include +#include "../../../../kernel/sched/sched.h" +#define TID_MAGIC 0x57590000 + +struct task_struct *get_futex_owner(u32 __user *uaddr2) +{ + int owner_tid = -1; + struct task_struct *futex_owner = NULL; + + if (uaddr2 != NULL) { + if (copy_from_user(&owner_tid, uaddr2, sizeof(int))) { + } else if (owner_tid != 0) { + int tmp = owner_tid & 0xffff0000; + + if (tmp == TID_MAGIC) + owner_tid &= 0xffff; + else + return NULL; + rcu_read_lock(); + futex_owner = find_task_by_vpid(owner_tid); + if (futex_owner) + get_task_struct(futex_owner); + rcu_read_unlock(); + } + } + return futex_owner; +} + +static void uxchain_resched_task(struct task_struct *task) +{ + struct rq *rq; + struct rq_flags rf; + + rq = task_rq_lock(task, &rf); + if (task->state != TASK_RUNNING || rq->curr == task) { + task_rq_unlock(rq, task, &rf); + return; + } + update_rq_clock(rq); + deactivate_task(rq, task, DEQUEUE_NOCLOCK); + activate_task(rq, task, ENQUEUE_NOCLOCK); + task_rq_unlock(rq, task, &rf); + resched_cpu(task_cpu(task)); +} + +static void uxchain_list_add_ux(struct list_head *entry, struct list_head *head) +{ + struct list_head *pos = NULL; + struct list_head *n = NULL; + struct mutex_waiter *waiter = NULL; + list_for_each_safe(pos, n, head) { + waiter = list_entry(pos, struct mutex_waiter, list); + if (!waiter->task->static_ux) { + list_add(entry, waiter->list.prev); + return; + } + } + if (pos == head) { + list_add_tail(entry, head); + } +} + +void uxchain_mutex_list_add(struct task_struct *task, struct list_head *entry, struct list_head *head, struct mutex *lock) +{ + struct task_struct *owner; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + owner = __mutex_owner(lock); +#else + owner = lock->owner; +#endif + if (!entry || !head || !lock) { + return; + } + if (task->static_ux) { + uxchain_list_add_ux(entry, head); + } else { + list_add_tail(entry, head); + } +} + +void uxchain_dynamic_ux_boost(struct task_struct *owner, struct task_struct *task) +{ + if (task->static_ux && owner && !owner->dynamic_ux) { + owner->dynamic_ux = 1; + owner->ux_depth = task->ux_depth + 1; + uxchain_resched_task(owner); + } + if (task->dynamic_ux && owner && !owner->dynamic_ux /*&& task->ux_depth < 2*/) { + owner->dynamic_ux = 1; + owner->ux_depth = task->ux_depth + 1; + uxchain_resched_task(owner); + } +} + +void uxchain_dynamic_ux_reset(struct task_struct *task) +{ + task->dynamic_ux = 0; + task->ux_depth = 0; +} + +int ux_thread(struct task_struct *task) +{ + return task->dynamic_ux || task->static_ux; +} + +#endif diff --git a/drivers/oneplus/coretech/uxchain/uxchain_v2.c b/drivers/oneplus/coretech/uxchain/uxchain_v2.c new file mode 100644 index 0000000000000000000000000000000000000000..5509273c476db058f1a445f1cc34e713eb84e515 --- /dev/null +++ b/drivers/oneplus/coretech/uxchain/uxchain_v2.c @@ -0,0 +1,31 @@ +#ifdef CONFIG_UXCHAIN_V2 +#include "../../../../kernel/sched/sched.h" +#include +#include +#include +#include + + + +void uxchain_rwsem_wake(struct task_struct *tsk, struct rw_semaphore *sem) +{ + if (current->mm && sem == &(current->mm->mmap_sem) && sysctl_uxchain_v2) + tsk->ux_once = 1; +} + +void uxchain_rwsem_down(struct rw_semaphore *sem) +{ + if (current->mm && sem == &(current->mm->mmap_sem) && sysctl_uxchain_v2) { + current->get_mmlock = 1; + current->get_mmlock_ts = sched_ktime_clock(); + } +} + +void uxchain_rwsem_up(struct rw_semaphore *sem) +{ + if (current->mm && sem == &(current->mm->mmap_sem) && + current->get_mmlock == 1 && sysctl_uxchain_v2) + current->get_mmlock = 0; +} + +#endif diff --git a/drivers/oneplus/coretech/uxcore/Makefile b/drivers/oneplus/coretech/uxcore/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6a11f257f9308914e6e775165eca803f9b2e9624 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/Makefile @@ -0,0 +1 @@ +obj-y += opchain_helper.o diff --git a/drivers/oneplus/coretech/uxcore/core/Kconfig b/drivers/oneplus/coretech/uxcore/core/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..999d1cab9e9337d7ab9c00a80d647bdcab698466 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/Kconfig @@ -0,0 +1 @@ +new file mode 100755 \ No newline at end of file diff --git a/drivers/oneplus/coretech/uxcore/core/Makefile b/drivers/oneplus/coretech/uxcore/core/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..daa046bcd0fab14aec99a1985232e889dc8fae5d --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/Makefile @@ -0,0 +1,3 @@ +obj-y += opchain_struct_offset_helper.o +opchain-objs := opchain_proxy.o opchain_core.o +obj-y += opchain.o diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_core.c b/drivers/oneplus/coretech/uxcore/core/opchain_core.c new file mode 100644 index 0000000000000000000000000000000000000000..f787adb727c62df3f9fe5353273f673c9dc45b64 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/opchain_core.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2015-2017, The OnePlus corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include "opchain_proxy.h" +#include "opchain_struct_offset_helper.h" +#include +#include + +/* +1 for group leader*/ +/* 6 fore * 3 histories*/ +/* ******************************** + **rep 0***Render ***Binder***** + **rep 1***Leader ***SF ***** + **type ***UT_ETASK***UTASK ***** +*/ +#define UX_ENTRY_LEN 2 +#define UX_TOTAL_ENTRIES 18 +#define UX_GROUP_OTHER_ENTRIES 6 +#define R_MAGIC_ID_0 ((unsigned int)0x50656E4F) +#define R_MAGIC_ID_1 ((unsigned int)0x3F73756C) +#define MAGIC_SIZE (sizeof(R_MAGIC_ID_0) + sizeof(R_MAGIC_ID_1) + 1) +#define CLAIMSTONS 16000000 +#define UX_MIGRATE_LOAD_ADJ 20 + +#define UXTAG(t) TASK_UTASK_TAG_R(t) +#define GUXTAG(t) TASK_UTASK_TAG_R(TASK_GROUP_LEADER_R(t)) +#define UXTIME(t) TASK_UTASK_TAG_BASE_R(t) +#define GUXTIME(t) TASK_UTASK_TAG_BASE_R(TASK_GROUP_LEADER_R(t)) +#define CHAIN_REP(pos, sub) (ux_chain.caches[pos].rep[sub]) +#define CHAIN_TYPE(pos) (ux_chain.caches[pos].type) + +#define opc_claim_bit_test(claim, cpu) (claim & ((1 << cpu) | (1 << (cpu + NUMS_CPU)))) + +static unsigned int binder_tag; +static unsigned long ux_realm_util; +static unsigned long ux_realm_claim_util; + +static struct { + atomic_t lru_pos; + struct { + /*pid*/ + int rep[UX_ENTRY_LEN]; + int type; + } caches[UX_TOTAL_ENTRIES]; +} ux_chain = { + .lru_pos = ATOMIC_INIT(0), + .caches = {{{ 0 }, 0 } } +}; +static struct { + atomic_t claim_counts; + void *last_claimant; + unsigned long long last_pass_time; +} claim_store[] = { + [0 ... 31] = { ATOMIC_INIT(0), NULL, (unsigned long long)0 } /* max 32 cores supported, DONT extend this! */ +}; + +static unsigned int ctech_opc_get_claims(void **rq); +static int ctech_opc_get_claim_on_cpu(int cpu, void *rq); + +#if UX_DEBUG +#include +#include +#include "opchain_helper.h" +int opchain_status_show_core(char *buf, const struct kernel_param *kp) +{ + unsigned int most_recent = atomic_read(&ux_chain.lru_pos), size = 0; + char *buf_new; + int iters = UX_TOTAL_ENTRIES; + + buf_new = buf; + + for (; iters > 0; iters--) { + unsigned int pos = most_recent-- % UX_TOTAL_ENTRIES; + if (!pos && !(CHAIN_REP(pos, 0) || CHAIN_REP(pos, 1))) + break; + if (CHAIN_TYPE(pos)) { + printk(pr_fmt("%d, %d %d\n"), CHAIN_REP(pos, 0), CHAIN_REP(pos, 1), CHAIN_TYPE(pos)); + size = snprintf(buf_new, PAGE_SIZE - size, "%d, %d %d\n", CHAIN_REP(pos, 0), CHAIN_REP(pos, 1), CHAIN_TYPE(pos)); + buf_new += size; + size = buf_new - buf; + } + else { + printk(pr_fmt("%d, %d\n"), CHAIN_REP(pos, 0), CHAIN_REP(pos, 1)); + size = snprintf(buf_new, PAGE_SIZE - size, "%d, %d\n", CHAIN_REP(pos, 0), CHAIN_REP(pos, 1)); + buf_new += size; + size = buf_new - buf; + } + } + size += snprintf(buf_new, PAGE_SIZE - size, + "tag %u", atomic_read(&ux_chain.lru_pos)); + buf_new += size; + size = buf_new - buf; + printk(pr_fmt("tag %u\n"), atomic_read(&ux_chain.lru_pos)); + size += snprintf(buf_new, PAGE_SIZE - size, + "claims %x\n", opc_get_claims()); + buf_new += size; + size = buf_new - buf; + size += snprintf(buf_new, PAGE_SIZE - size, + "claim_count %d %d %d %d\n", opc_get_claim_on_cpu(0), opc_get_claim_on_cpu(1), opc_get_claim_on_cpu(2), opc_get_claim_on_cpu(3)); + + return size; +} +#endif +#if 0 +static inline bool ctech_is_major_utask(int pid, u32 tag) +{ + return (CHAIN_REP((tag % UX_TOTAL_ENTRIES), 0) == pid); +} +#endif +static unsigned int ctech_is_opc_task(void *rq, void *t, int type) +{ + unsigned long long tag = UXTAG(t); + unsigned long long avl_entries = 0; + + if (!tag || !chain_on) + return false; + + /*100ms*/ + if (latest_threshold && (type & UT_CLK_BASE) && + (RQ_CLOCK_R(rq) - UXTIME(t) > latest_threshold)) + return false; + + if ((type & UT_ETASK) && + !(CHAIN_TYPE(tag % UX_TOTAL_ENTRIES) & UT_ETASK)) + return false; + + if (type & UT_LATEST_ONE) + avl_entries = UX_GROUP_OTHER_ENTRIES; + else + avl_entries = UX_TOTAL_ENTRIES; + tag = tag + avl_entries - atomic_read(&ux_chain.lru_pos); + if (tag <= avl_entries) { + return true; + } + else + return false; +} + +static inline void ctech_ux_clock_base_mark(void *rq, void *t) +{ + GUXTIME(t) = UXTIME(t) = RQ_CLOCK_R(rq); +} + +static void ctech_ux_mark(void *rq, void *t, int ux_group) +{ + unsigned int cache_inpos, latest; + + latest = atomic_read(&ux_chain.lru_pos); + cache_inpos = latest % UX_TOTAL_ENTRIES; + + if (!ctech_is_opc_task(rq, t, UT_LATEST_ONE)) { + UXTAG(t) = atomic_inc_return(&ux_chain.lru_pos); + GUXTAG(t) = UXTAG(t); + cache_inpos = UXTAG(t) % UX_TOTAL_ENTRIES; + if (!ux_group) + binder_tag = UXTAG(t); + if (CHAIN_REP(cache_inpos, 0) != TASK_PID_R(t)) { + CHAIN_REP(cache_inpos, 0) = TASK_PID_R(t); + CHAIN_TYPE(cache_inpos) = ux_group; + } + if (CHAIN_REP(cache_inpos, 1) != TASK_TGID_R(t)) + CHAIN_REP(cache_inpos, 1) = TASK_TGID_R(t); +#if UX_DEBUG + printk(KERN_DEBUG pr_fmt("UX tag%llu, %d:%s, %d:%s %d %llu\n"), UXTAG(t), TASK_PID_R(t), TASK_COMM_R(t), TASK_TGID_R(t), TASK_COMM_R(TASK_GROUP_LEADER_R(t)), ux_group, RQ_CLOCK_R(rq)); +#endif + } +#if UX_DEBUG + else { + printk(KERN_DEBUG pr_fmt("UX tag%llu, only update time base %d:%s, %d:%s %llu\n"), UXTAG(t), TASK_PID_R(t), TASK_COMM_R(t), TASK_TGID_R(t), TASK_COMM_R(TASK_GROUP_LEADER_R(t)), RQ_CLOCK_R(rq)); + } +#endif +} + +static void ctech_opc_add_to_chain(void *rq, void *t) +{ + ctech_ux_mark(rq, t, UT_ETASK); + ctech_ux_clock_base_mark(rq, t); +} + +static int ctech_opc_binder_parse(void *rq, void *cur, + unsigned int dsize,unsigned int *data, + int send) +{ + /* dont move forward to cache diverse histories as many as possible */ + if (!TASK_EXIT_STATE_R(TASK_GROUP_LEADER_R(cur)) && + dsize > MAGIC_SIZE && + data[0] == R_MAGIC_ID_0 && + data[1] == R_MAGIC_ID_1) { + if (chain_on && send) { + ctech_ux_mark(rq, cur, UT_ETASK); + ctech_ux_clock_base_mark(rq, cur); + } + /* + else { + ctech_ux_mark(current, UTASK); + ctech_ux_clock_base_mark(current, render_base); + } + */ + return 1; + } + return 0; +} + +static inline int atomic_dec_if_positive_ported(atomic_t *v) +{ + int c, old, dec; + c = atomic_read(v); + for (;;) { + dec = c - 1; + if (unlikely(dec < 0)) + break; + old = atomic_cmpxchg((v), c, dec); + if (likely(old == c)) + break; + c = old; + } + return dec; +} + +static inline unsigned int audit_claim_cpu_range(int cpu) { + return (cpu >= 0 && cpu < ARRAY_SIZE(claim_store)); +} + +static void ctech_opc_task_switch( + unsigned int enqueue, int cpu, void *p, void *rq, unsigned long long clock) +{ + if (likely(p) && likely(audit_claim_cpu_range(cpu))) { + if (enqueue) { + if (ctech_is_opc_task(rq, p, UT_FORE)) { + atomic_inc(&claim_store[cpu].claim_counts); + claim_store[cpu].last_claimant = p; + TASK_ETASK_CLAIM_R(p) = 1; + if (TASK_CLAIM_CPU_R(p) != -1 && TASK_CLAIM_CPU_R(p) != cpu + && claim_store[TASK_CLAIM_CPU_R(p)].last_claimant == p) { + claim_store[TASK_CLAIM_CPU_R(p)].last_pass_time = 0; + TASK_CLAIM_CPU_R(p) = -1; + } + } + } else { + if (TASK_ETASK_CLAIM_R(p)) { + /* remove claim */ + TASK_ETASK_CLAIM_R(p) = 0; + if (!atomic_dec_if_positive_ported(&claim_store[cpu].claim_counts)) + TASK_CLAIM_CPU_R(p) = cpu; + claim_store[cpu].last_pass_time = clock; + } + } + } +} + +/* return value: + * > 0, return # of renders if any renders claim CPU + * = 0, no render + * < 0, if there's any render within a threshold (16ms) */ +static int ctech_opc_get_claim_on_cpu(int cpu, void *rq) +{ + if (!chain_on) + return 0; + + if (likely(audit_claim_cpu_range(cpu))) { + int render_counts = atomic_read(&claim_store[cpu].claim_counts); + u64 rq_time = RQ_CLOCK_R(rq); + + if (render_counts) { + return render_counts; + } else if (rq_time >= claim_store[cpu].last_pass_time && + (rq_time - claim_store[cpu].last_pass_time) <= CLAIMSTONS) { + return OP_CLAIM_S; + } + } + /* zero weight owing to no foreground ux tasks */ + return 0; +} + +static unsigned int ctech_opc_get_claims(void **rqs) +{ + unsigned int claims = 0; + int idx, num_cpus, t_claim; + + if (chain_on) { + for (idx = 0, num_cpus = NUMS_CPU; idx < num_cpus; idx++) { + t_claim = ctech_opc_get_claim_on_cpu(idx, rqs[idx]); + if (t_claim > 0) + claims |= (1 << idx); + else if (t_claim == OP_CLAIM_S) + claims |= (1 << (idx + num_cpus)); + } + } + + return claims; +} + +static unsigned int ctech_opc_is_slave_task(void *rq, void *t) +{ + if (TASK_UTASK_SLAVE_R(t)) { + if (RQ_CLOCK_R(rq) - UXTIME(t) < CLAIMSTONS) + return true; + else + TASK_UTASK_SLAVE_R(t) = 0; + } + + return false; +} + +/* return value: + * OP_PATH_NORMAL(-2) means normal case + * OP_PATH_OCCUPIED(-1) means prev_cpu is occuping by other renders, ignore it + * 0,1,2,3... means this task is render, keep running on previous CPU + * OP_PATH_CLAIM (-3) means there's render within 10ms, so this task should go somewhere else + * of course, this task would not meet any above conditions. + * + * Assume dormant min_cpus is 2. +*/ +static int ctech_opc_select_path(void **rqs, void *w_rq, void *t_rq, void *waker, void *t, int prev_cpu) +{ + unsigned int claims = ctech_opc_get_claims(rqs), last_cpu = NUMS_CPU - 1; + unsigned int t_is_ux_top = ctech_is_opc_task(t_rq, t, UT_FORE); + //int i; + + if (!chain_on) + return OP_PATH_NORMAL; + + if (t_is_ux_top) { + /* + if (prev_cpu >= MIN_POWER_CPU && CPU_VIRTUAL_PLUG_IN(prev_cpu)) + return prev_cpu; + for (i = NUMS_CPU - 1; i >= FIRST_BIG_CORE; i--) + if (CPU_VIRTUAL_PLUG_IN(i) && cpumask_test_cpu(i, TASK_CPUS_ALLOWED_ADDR(t)) && !opc_claim_bit_test(claims, i) && opc_idle_get_state_idx(i) == -1) + return i; + */ + return prev_cpu; + } else if ((ctech_is_opc_task(w_rq, waker, UT_FORE) || ctech_opc_is_slave_task(w_rq, waker)) && TASK_GROUP_LEADER_R(t) == TASK_GROUP_LEADER_R(waker)){ + TASK_UTASK_SLAVE_R(t) = true; + UXTIME(t) = UXTIME(waker); + return OP_PATH_SLAVE; + } + + if (claims & (1 << prev_cpu)) + return OP_PATH_OCCUPIED; + + if (claims & (1 << (prev_cpu + last_cpu + 1))) + return OP_PATH_CLAIM; + + return OP_PATH_NORMAL; +} + +unsigned long ctech_opc_cpu_util(unsigned long util, int cpu, void *t, void *rq, int prev_cpu) +{ + /*TODO: render real demand*/ + int get_claim = ctech_opc_get_claim_on_cpu(cpu, rq); + + if (!get_claim || TASK_UTASK_SLAVE_R(t)) + return util; + + if (get_claim <= 1 && prev_cpu != cpu) + util += ux_realm_claim_util; + else if (util < 1024) + util += get_claim * ux_realm_util; + + return (util > 1024) ? 1024 : util; +} + +static int ctech_opc_check_uxtop_cpu(int uxtop, int cpu) +{ + if (!uxtop || cpu >= FIRST_BIG_CORE) + return true; + return false; +} + +void __init ctech_opchain_init(struct opchain_cb *cb, unsigned long util) +{ + cb->is_opc_task_t = ctech_is_opc_task; + cb->opc_binder_pass_t = ctech_opc_binder_parse; + cb->opc_task_switch_t = ctech_opc_task_switch; + cb->opc_get_claim_on_cpu_t = ctech_opc_get_claim_on_cpu; + cb->opc_get_claims_t = ctech_opc_get_claims; + cb->opc_select_path_t = ctech_opc_select_path; + cb->opc_cpu_util_t = ctech_opc_cpu_util; + cb->opc_add_to_chain_t = ctech_opc_add_to_chain; + cb->opc_check_uxtop_cpu_t = ctech_opc_check_uxtop_cpu; + ux_realm_util = util; + ux_realm_claim_util = ux_realm_util >> 1; +} diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_core.h b/drivers/oneplus/coretech/uxcore/core/opchain_core.h new file mode 100755 index 0000000000000000000000000000000000000000..11c77b644c812a76687f5c4f84c7bdde50a8e08b --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/opchain_core.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_OPCHAIN_CORE_H +#define _LINUX_OPCHAIN_CORE_H + +#if UX_DEBUG +extern int opchain_status_show_core(char *buf, const struct kernel_param *kp); +#endif +extern void __init ctech_opchain_init(struct opchain_cb *cb, unsigned long util); +#endif diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c b/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c new file mode 100644 index 0000000000000000000000000000000000000000..c840effd92c1ba8c15439661ee6b13a28c0353da --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015-2017, The OnePlus corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "../kernel/sched/sched.h" +#include +#include "opchain_core.h" +#include + +unsigned int __read_mostly boost; +unsigned int __read_mostly boost_tl; +unsigned int __read_mostly boost_sample_time = 1; +unsigned int __read_mostly chain_on = 0; +unsigned int __read_mostly latest_ms = 100; +unsigned int __read_mostly latest_threshold = 100000000; + +#if UX_DEBUG +static int opchain_status_show(char *buf, const struct kernel_param *kp) +{ + return opchain_status_show_core(buf, kp); +} + +static const struct kernel_param_ops param_ops_opchain_status = { + .get = opchain_status_show, +}; +module_param_cb(opchain_status, ¶m_ops_opchain_status, NULL, 0644); +#endif + +static int latest_ms_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u", latest_ms); +} + +static int latest_ms_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + latest_ms = val; + latest_threshold = val * 1000000; + return 0; +} + +static const struct kernel_param_ops param_ops_latest_ms = { + .get = latest_ms_show, + .set = latest_ms_store, +}; + +module_param(boost, uint, 0644); +module_param(boost_sample_time, uint, 0644); +module_param(boost_tl, uint, 0644); +module_param(chain_on, uint, 0644); +module_param_cb(latest_ms, ¶m_ops_latest_ms, NULL, 0644); + +static int __init opchain_init(void) +{ + ctech_opchain_init(&uxcore_api, opc_get_orig_capacity(MIN_POWER_CPU)); + + return 0; +} + +module_init(opchain_init); + +static void __exit opchain_exit_module(void) +{ + opc_exit_module(); +} + +module_exit(opchain_exit_module); diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_proxy.h b/drivers/oneplus/coretech/uxcore/core/opchain_proxy.h new file mode 100755 index 0000000000000000000000000000000000000000..b9c3101276616fec0b084a51b7c8335fd64ef895 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/opchain_proxy.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_OPCHAIN_PROXY_H +#define _LINUX_OPCHAIN_PROXY_H + +extern unsigned int boost; +extern unsigned int boost_tl; +extern unsigned int boost_sample_time; +extern unsigned int chain_on; +extern unsigned int latest_threshold; +#endif diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.c b/drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.c new file mode 100755 index 0000000000000000000000000000000000000000..6b4eb6a88f9432dda94c238f532001bf470bc063 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015-2017, The OnePlus corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "opchain_struct_offset_helper.h" +#include "../kernel/sched/sched.h" + +/* struct task_struct */ +unsigned int opchain_task_struct_offset[__TASK_OFFSET_MAX] = { + [TASK_OFFSET_WAKEE_FLIPS] = offsetof(struct task_struct, wakee_flips), + [TASK_OFFSET_CPUS_ALLOWED] = offsetof(struct task_struct, cpus_allowed), + [TASK_OFFSET_PID] = offsetof(struct task_struct, pid), + [TASK_OFFSET_TGID] = offsetof(struct task_struct, tgid), + [TASK_OFFSET_GROUP_LEADER] = offsetof(struct task_struct, group_leader), + [TASK_OFFSET_COMM] = offsetof(struct task_struct, comm), + [TASK_OFFSET_UTASK_TAG] = offsetof(struct task_struct, utask_tag), + [TASK_OFFSET_UTASK_TAG_BASE] = offsetof(struct task_struct, utask_tag_base), + [TASK_OFFSET_ETASK_CLAIM] = offsetof(struct task_struct, etask_claim), + [TASK_OFFSET_CLAIM_CPU] = offsetof(struct task_struct, claim_cpu), + [TASK_OFFSET_UTASK_SLAVE] = offsetof(struct task_struct, utask_slave), + [TASK_OFFSET_EXIT_STATE] = offsetof(struct task_struct, exit_state) +}; +gen_type_offset_impl(task_struct); + +/* struct rq */ +unsigned int opchain_rq_offset[__RQ_OFFSET_MAX] = { +#ifdef CONFIG_SMP + [RQ_OFFSET_CPU_CAPACITY_ORIG] = offsetof(struct rq, cpu_capacity_orig), + [RQ_OFFSET_CPU] = offsetof(struct rq, cpu), +#endif +#ifdef CONFIG_SCHED_HMP + [RQ_OFFSET_WINDOW_START] = offsetof(struct rq, window_start), +#endif + [RQ_OFFSET_CLOCK] = offsetof(struct rq, clock) +}; +gen_type_offset_impl(rq); diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.h b/drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.h new file mode 100755 index 0000000000000000000000000000000000000000..feff6f495cf31e6bafd4c490a2018c83724fa8a8 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.h @@ -0,0 +1,68 @@ +#ifndef _OPCHAIN_STRUCT_OFFSET_HELPER_INC_ +#define _OPCHAIN_STRUCT_OFFSET_HELPER_INC_ + +/* define macro to extern function declaration */ +#define gen_type_offset(type) \ + extern unsigned int opchain_get_##type##_offset(int m); + +/* define macro to create offset impl and export get offset/value symbol */ +#define gen_type_offset_impl(type) \ + unsigned int opchain_get_##type##_offset(int m) { \ + return opchain_##type##_offset[m]; } \ + EXPORT_SYMBOL(opchain_get_##type##_offset); + +/* enum of struct task struct */ +enum { + TASK_OFFSET_WAKEE_FLIPS, + TASK_OFFSET_CPUS_ALLOWED, + TASK_OFFSET_PID, + TASK_OFFSET_TGID, + TASK_OFFSET_GROUP_LEADER, + TASK_OFFSET_COMM, + TASK_OFFSET_UTASK_TAG, + TASK_OFFSET_UTASK_TAG_BASE, + TASK_OFFSET_ETASK_CLAIM, + TASK_OFFSET_CLAIM_CPU, + TASK_OFFSET_UTASK_SLAVE, + TASK_OFFSET_EXIT_STATE, + + __TASK_OFFSET_MAX +}; +#define TASK_WAKEE_FLIPS_R(t) (*(unsigned long *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_WAKEE_FLIPS))) +#define TASK_CPUS_ALLOWED_ADDR(t) (cpumask_t *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_CPUS_ALLOWED)) +#define TASK_PID_R(t) (*(pid_t *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_PID))) +#define TASK_TGID_R(t) (*(pid_t *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_TGID))) +#define TASK_GROUP_LEADER_R(t) (*(struct task_struct **)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_GROUP_LEADER))) +#define TASK_COMM_R(t) ((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_COMM)) +#define TASK_UTASK_TAG_R(t) (*(u64 *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_UTASK_TAG))) +#define TASK_UTASK_TAG_BASE_R(t) (*(u64 *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_UTASK_TAG_BASE))) +#define TASK_ETASK_CLAIM_R(t) (*(int *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_ETASK_CLAIM))) +#define TASK_CLAIM_CPU_R(t) (*(int *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_CLAIM_CPU))) +#define TASK_UTASK_SLAVE_R(t) (*(bool *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_UTASK_SLAVE))) +#define TASK_EXIT_STATE_R(t) (*(bool *)((char *)t + opchain_get_task_struct_offset(TASK_OFFSET_EXIT_STATE))) +gen_type_offset(task_struct); + +/* enum of struct rq */ +enum { + RQ_OFFSET_CLOCK, +#ifdef CONFIG_SMP + RQ_OFFSET_CPU_CAPACITY_ORIG, + RQ_OFFSET_CPU, +#endif +#ifdef CONFIG_SCHED_HMP + RQ_OFFSET_WINDOW_START, +#endif + + __RQ_OFFSET_MAX +}; +#define RQ_CLOCK_R(rq) (*(u64 *)((char *)rq + opchain_get_rq_offset(RQ_OFFSET_CLOCK))) +#ifdef CONFIG_SMP +#define RQ_CPU_CAPACITY_ORIG_R(rq) (*(unsigned long *)((char *)rq + opchain_get_rq_offset(RQ_OFFSET_CPU_CAPACITY_ORIG))) +#define RQ_CPU_R(rq) (*(int *)((char *)rq + opchain_get_rq_offset(RQ_OFFSET_CPU))) +#endif +#ifdef CONFIG_SCHED_HMP +#define RQ_WINDOW_START_R(rq) (*(u64 *)((char *)rq + opchain_get_rq_offset(RQ_OFFSET_WINDOW_START))) +#endif +gen_type_offset(rq); + +#endif //_OPCHAIN_STRUCT_OFFSET_HELPER_INC_ diff --git a/drivers/oneplus/coretech/uxcore/opchain_helper.c b/drivers/oneplus/coretech/uxcore/opchain_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..8a49d7a5309750ffc634286701936d7e435d4e23 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/opchain_helper.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015-2017, The OnePlus corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "../kernel/sched/sched.h" +#include + +#ifdef CONFIG_HOUSTON +#include +#endif + +#define t_rq(t) task_rq(t) +#define c_rq(cpu) cpu_rq(cpu) + +struct opchain_cb uxcore_api = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; +EXPORT_SYMBOL(uxcore_api); + +unsigned int *opc_boost_tl; +EXPORT_SYMBOL(opc_boost_tl); + +unsigned int *opc_boost; +EXPORT_SYMBOL(opc_boost); + +void opc_set_boost(unsigned int val) +{ + if (opc_boost) + *opc_boost = val; +} +EXPORT_SYMBOL(opc_set_boost); + +bool is_opc_task(struct task_struct *t, int type) +{ + if (uxcore_api.is_opc_task_t) + return uxcore_api.is_opc_task_t((void *)t_rq(t), (void *)t, type); + return 0; +} +EXPORT_SYMBOL(is_opc_task); + +void opc_binder_pass(size_t data_size, uint32_t *data, int send) +{ + if (uxcore_api.opc_binder_pass_t) { + if (uxcore_api.opc_binder_pass_t((void *)t_rq(current), (void *)current, data_size, data, send)) { +#ifdef CONFIG_HOUSTON + ht_perf_notify(); +#endif + } + } +} +EXPORT_SYMBOL(opc_binder_pass); + +void opc_task_switch(unsigned int enqueue, int cpu, struct task_struct *p, u64 clock) { + if (uxcore_api.opc_task_switch_t) + uxcore_api.opc_task_switch_t(enqueue, cpu, (void *)p, (void *)t_rq(p), clock); +} +EXPORT_SYMBOL(opc_task_switch); + +int opc_get_claim_on_cpu(int cpu) +{ + if (uxcore_api.opc_get_claim_on_cpu_t) + return uxcore_api.opc_get_claim_on_cpu_t(cpu, (void *)c_rq(cpu)); + return 0; +} +EXPORT_SYMBOL(opc_get_claim_on_cpu); + +unsigned int opc_get_claims(void) +{ + void *rqs[NUMS_CPU]; + int idx; + + if (uxcore_api.opc_get_claims_t) { + for (idx = 0; idx < NUMS_CPU; idx++) { + rqs[idx] = (void *)c_rq(idx); + } + return uxcore_api.opc_get_claims_t(rqs); + } + return 0; +} +EXPORT_SYMBOL(opc_get_claims); + +int opc_select_path(struct task_struct *cur, struct task_struct *t, int prev_cpu) +{ + void *rqs[NUMS_CPU]; + int idx; + + if (uxcore_api.opc_select_path_t) { + for (idx = 0; idx < NUMS_CPU; idx++) { + rqs[idx] = (void *)c_rq(idx); + } + return uxcore_api.opc_select_path_t(rqs, (void *)t_rq(cur), (void *)t_rq(t), (void *)cur, (void *)t, prev_cpu); + } + return OP_PATH_NORMAL; +} +EXPORT_SYMBOL(opc_select_path); + +unsigned long opc_cpu_util(unsigned long util, int cpu, struct task_struct *t, int op_path) +{ + if (uxcore_api.opc_cpu_util_t) + return uxcore_api.opc_cpu_util_t(util, cpu, (void *)t, (void *)c_rq(cpu), op_path); + return util; +} +EXPORT_SYMBOL(opc_cpu_util); + +void opc_add_to_chain(struct task_struct *t) +{ + if (uxcore_api.opc_add_to_chain_t) + uxcore_api.opc_add_to_chain_t((void *)t_rq(t), (void *)t); +} +EXPORT_SYMBOL(opc_add_to_chain); + +bool opc_check_uxtop_cpu(int uxtop, int cpu) +{ + if (uxcore_api.opc_check_uxtop_cpu_t) + return uxcore_api.opc_check_uxtop_cpu_t(uxtop, cpu); + return true; +} +EXPORT_SYMBOL(opc_check_uxtop_cpu); + +unsigned long __init opc_get_orig_capacity(int cpu) +{ + return cpu_rq(cpu)->cpu_capacity_orig; +} +EXPORT_SYMBOL(opc_get_orig_capacity); + +bool opc_utask_slave(struct task_struct *t) +{ + return t->utask_slave; +} +EXPORT_SYMBOL(opc_utask_slave); + +void __exit opc_exit_module(void) +{ + uxcore_api.opc_binder_pass_t = NULL; + uxcore_api.is_opc_task_t = NULL; + uxcore_api.opc_task_switch_t = NULL; + uxcore_api.opc_get_claim_on_cpu_t = NULL; + uxcore_api.opc_get_claims_t = NULL; + uxcore_api.opc_select_path_t = NULL; + uxcore_api.opc_cpu_util_t = NULL; + uxcore_api.opc_add_to_chain_t = NULL; + uxcore_api.opc_check_uxtop_cpu_t = NULL; + opc_boost_tl = NULL; + opc_boost = NULL; +} +EXPORT_SYMBOL(opc_exit_module); diff --git a/drivers/oneplus/coretech/vm_fragment_monitor/Makefile b/drivers/oneplus/coretech/vm_fragment_monitor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c4961e52070099e660ac4ad9014ec2b428502278 --- /dev/null +++ b/drivers/oneplus/coretech/vm_fragment_monitor/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VM_FRAGMENT_MONITOR) += vm_fragment_monitor.o diff --git a/drivers/oneplus/coretech/vm_fragment_monitor/vm_fragment_monitor.c b/drivers/oneplus/coretech/vm_fragment_monitor/vm_fragment_monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..9cf0bbfdfd11f03e1dedb761f0c23f36581093c7 --- /dev/null +++ b/drivers/oneplus/coretech/vm_fragment_monitor/vm_fragment_monitor.c @@ -0,0 +1,161 @@ +/******************************************************************************** +** Copyright (C), 2014-2019, OnePlus Mobile Comm Corp., Ltd +** All rights reserved. +** +** File: vm_fragment_monitor.c +** Version Number: 1.0 +** Description: +** This driver is to get the max virtual memory fragment gap by pid +** For detail, Please refer to [OSP-3622] +** +** ------------------------------------------------------------------------------ +** +** allen.lv@ASTI 2019-10-12 v1 add init version +** +*********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GET_GAP_SIZE _IOR('a', 1, unsigned int) + +static dev_t devno; +static struct cdev *cdev; +static struct class *fragment_monitor_class; +static struct device *fragment_monitor_dev; + + +static long monitor_fragment_ioctl(struct file *file, unsigned int cmd, unsigned long args) +{ + unsigned long pid; + struct task_struct *task; + struct mm_struct *mm; + struct vm_area_struct *vma; + unsigned long vm_fragment_gap_max = 0; + unsigned long gl_fragment_gap_max = 0; + void __user *parg = (void __user *)args; + + if (cmd != GET_GAP_SIZE) + return -EFAULT; + + if (copy_from_user(&pid, parg, sizeof(unsigned long))) + return -EFAULT; + + rcu_read_lock(); + task = find_task_by_vpid((int)pid); + + if (!task) { + rcu_read_unlock(); + return -ESRCH; + } + + get_task_struct(task); + rcu_read_unlock(); + + if (!test_ti_thread_flag((struct thread_info *)task, TIF_32BIT)) { + put_task_struct(task); + return -EPERM; + } + + mm = get_task_mm(task); + if (!mm) { + put_task_struct(task); + return -ENOMEM; + } + + if (RB_EMPTY_ROOT(&mm->mm_rb)) + { + mmput(mm); + put_task_struct(task); + return -ENOMEM; + } + + vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb); + vm_fragment_gap_max = (vma->rb_subtree_gap >> 20); + gl_fragment_gap_max = (vma->rb_glfragment_gap >> 20); + mmput(mm); + put_task_struct(task); + + pr_info("monitor_fragment_ioctl : pid=%d, vm_fragment_gap_max=%d, gl_fragment_gap_max=%d\n", + (int)pid, (int)vm_fragment_gap_max, (int)gl_fragment_gap_max); + + if (copy_to_user(parg, &gl_fragment_gap_max, sizeof(unsigned long))) + return -EFAULT; + + return 0; +} + +static const struct file_operations chrdev_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = monitor_fragment_ioctl, +}; + +static int chrdev_register(void) +{ + int ret = 0; + + cdev = kzalloc(sizeof(struct cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + ret = alloc_chrdev_region(&devno, 0, 1, "fragment_monitor"); + if (ret) + goto err_alloc_chardev; + + cdev_init(cdev, &chrdev_fops); + cdev->owner = THIS_MODULE; + ret = cdev_add(cdev, devno, 1); + if (ret) + goto err_cdev_add; + + fragment_monitor_class = class_create(THIS_MODULE, "fragment_monitor"); + if (IS_ERR(fragment_monitor_class)) { + ret = PTR_ERR(fragment_monitor_class); + goto err_create_class; + } + fragment_monitor_dev = device_create(fragment_monitor_class, NULL, devno, NULL, "fragment_monitor"); + if (IS_ERR(fragment_monitor_dev)) + goto err_create_device; + + return 0; + +err_create_device: + class_destroy(fragment_monitor_class); +err_create_class: + cdev_del(cdev); +err_cdev_add: + unregister_chrdev_region(devno, 1); +err_alloc_chardev: + kfree(cdev); + return ret; +} + +static int __init monitor_fragment_init(void) +{ + int ret = 0; + ret = chrdev_register(); + return ret; +} + +static void __exit monitor_fragment_exit(void) +{ + cdev_del(cdev); + unregister_chrdev_region(devno, 1); +} + + +module_init(monitor_fragment_init); +module_exit(monitor_fragment_exit); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/oneplus/coretech/zwb_handle/Makefile b/drivers/oneplus/coretech/zwb_handle/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..de0910b0f191f603a3968f539a12082aa0851996 --- /dev/null +++ b/drivers/oneplus/coretech/zwb_handle/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ZWB_HANDLE) += zwb_handle.o diff --git a/drivers/oneplus/coretech/zwb_handle/zwb_handle.c b/drivers/oneplus/coretech/zwb_handle/zwb_handle.c new file mode 100644 index 0000000000000000000000000000000000000000..454120a3d1898873faa27b4a1692531661f5f3eb --- /dev/null +++ b/drivers/oneplus/coretech/zwb_handle/zwb_handle.c @@ -0,0 +1,274 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "../../../block/zram/zram_drv.h" + +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page);}) + +#define CLEAR_DEBUG 1 + +struct task_struct *zwb_clear_tsk; + +static bool is_fast_entry(swp_entry_t entry) +{ + struct swap_info_struct *p; + bool ret = false; + unsigned long offset, type; + + if (!entry.val) + goto out; + type = swp_type(entry); + p = swap_info[type]; + if (!(p->flags & SWP_USED)) + goto out; + offset = swp_offset(entry); + if (offset >= p->max) + goto out; + + spin_lock(&p->lock); + if (p->flags & SWP_SYNCHRONOUS_IO) + ret = true; + spin_unlock(&p->lock); +out: + return ret; +} + +static int zwb_clear_walk_pmd_entry(pmd_t *pmd, unsigned long start, + unsigned long end, struct mm_walk *walk) +{ + pte_t *orig_pte; + struct vm_area_struct *vma = walk->private; + unsigned long index; + + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) + return 0; + + for (index = start; index != end; index += PAGE_SIZE) { + pte_t pte; + swp_entry_t entry; + spinlock_t *ptl; + + if (!list_empty(&vma->vm_mm->mmap_sem.wait_list)) + return -1; + + orig_pte = pte_offset_map_lock(vma->vm_mm, pmd, start, &ptl); + pte = *(orig_pte + ((index - start) / PAGE_SIZE)); + pte_unmap_unlock(orig_pte, ptl); + + if (pte_present(pte) || pte_none(pte)) + continue; + entry = pte_to_swp_entry(pte); + if (unlikely(non_swap_entry(entry))) + continue; + + if (!is_fast_entry(entry)) { + struct swap_info_struct *sis = swp_swap_info(entry); + struct block_device *bdev = sis->bdev; + sector_t sector = ((sector_t)swp_offset(entry) << (PAGE_SHIFT - 9)) + get_start_sect(bdev); + struct zram *zram; + u32 index; + + blk_queue_enter(bdev->bd_queue, 0); + zram = bdev->bd_disk->private_data; + index = sector >> SECTORS_PER_PAGE_SHIFT; + bit_spin_lock(ZRAM_LOCK, &zram->table[index].flags); + zram->table[index].flags &= ~BIT(ZRAM_IDLE); + bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags); + blk_queue_exit(bdev->bd_queue); + } + } + + return 0; +} + +static ssize_t zwb_clear_idle_flag(struct task_struct *task) +{ + struct mm_struct *mm; + struct vm_area_struct *vma; + struct mm_walk walk = {}; + int task_anon = 0, task_swap = 0, err = 0; + +retry: + mm = get_task_mm(task); + if (!mm) + goto out; + + task_anon = get_mm_counter(mm, MM_ANONPAGES); + task_swap = get_mm_counter(mm, MM_SWAPENTS); + + walk.mm = mm; + walk.pmd_entry = zwb_clear_walk_pmd_entry; + + down_read(&mm->mmap_sem); + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (is_vm_hugetlb_page(vma)) + continue; + + if (vma->vm_file) + continue; + + /* if mlocked, don't reclaim it */ + if (vma->vm_flags & VM_LOCKED) + continue; + + walk.private = vma; + err = walk_page_range(vma->vm_start, vma->vm_end, &walk); + if (err == -1) + break; + } + + flush_tlb_mm(mm); + up_read(&mm->mmap_sem); + mmput(mm); + if (err) { + err = 0; + goto retry; + } +out: + return 0; +} + + +static inline bool should_skip(const char *comm) +{ + /* only A or B can go to processing */ + return strncmp("eplus.wallpaper", comm, TASK_COMM_LEN) && strncmp("ndroid.systemui", comm, TASK_COMM_LEN); +} + +/* clear ZRAM_IDLE flag for specific processes. */ +static int clear_fn(void *p) +{ + struct task_struct *tsk; + int count = 0; + + set_freezable(); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + + rcu_read_lock(); + for_each_process(tsk) { + if (tsk->flags & PF_KTHREAD) + continue; + /* TODO: do we need this check? */ + if (should_skip(tsk->comm)) + continue; + + count++; + get_task_struct(tsk); +#if CLEAR_DEBUG + pr_info("clear_idle_flag processing %s (%d) \n", tsk->comm, tsk->pid); +#endif + zwb_clear_idle_flag(tsk); + put_task_struct(tsk); + + if (count == 2) + break; + } + + rcu_read_unlock(); + +#if CLEAR_DEBUG + pr_info("clear_idle_flag finish"); +#endif + if (kthread_should_stop()) + break; + } + return 0; +} + +static int __init zwb_handle_init(void) +{ + //TODO: priority tuning for reclaimd/swapind + + zwb_clear_tsk = kthread_run(clear_fn, 0, "zwb_clear_flag"); + if (IS_ERR(zwb_clear_tsk)) { + pr_err("Failed to start zwb_clear_flag_task\n"); + zwb_clear_tsk = NULL; + } + + return 0; +} + +/* return value mapping: + * 0 - success + * ESRCH - no clear daemon + * EINVAL- invalid input + */ +static int zwb_handle_wake_clear_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (!zwb_clear_tsk) + return -ESRCH; + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + if (val) + wake_up_process(zwb_clear_tsk); + + return 0; +} + +static struct kernel_param_ops zwb_handle_wake_clear_ops = { + .set = zwb_handle_wake_clear_store, +}; + +module_param_cb(zwb_handle_wake_clear, &zwb_handle_wake_clear_ops, NULL, 0644); + +module_init(zwb_handle_init) diff --git a/drivers/oneplus/framework/Kconfig b/drivers/oneplus/framework/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a6ceadc5b308e23ca757a6f5ab0530a8af624446 --- /dev/null +++ b/drivers/oneplus/framework/Kconfig @@ -0,0 +1,7 @@ +config DYNAMIC_PAGE_POOL + default n + bool "Dynamic Page Pool" + help + Dynamic Page Pool is pre-allocated zeroed pages and will be used + for anon allocation. This brings improvements in launch latencies + where anon allocation are significant. diff --git a/drivers/oneplus/framework/Makefile b/drivers/oneplus/framework/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fecf0231a4ba6549ad32158d29d52086ba69a98d --- /dev/null +++ b/drivers/oneplus/framework/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DYNAMIC_PAGE_POOL) += dynamic_page_pool.o diff --git a/drivers/oneplus/framework/dynamic_page_pool.c b/drivers/oneplus/framework/dynamic_page_pool.c new file mode 100644 index 0000000000000000000000000000000000000000..bdfeba3a7943e5d956d34a428f5309bb91d46460 --- /dev/null +++ b/drivers/oneplus/framework/dynamic_page_pool.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +/* + * drivers/oneplus/framework/dynamic_page_pool.c + * + * Copyright (C) 2019 OnePlus. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define GRACE_PERIOD 2000 /* 2 Sec */ +#define HUGEPAGE_ORDER 9 /* 2^9 pages = 2 MB */ + +#define DPP_ANON_MIN 256 +#define DPP_ANON_MAX 25600 +#define DPP_ANON_SLEEP_MS 1000 + +#define DPP_ANON_HUGEPAGE_MIN 0 +#define DPP_ANON_HUGEPAGE_MAX 20 +#define DPP_ANON_HUGEPAGE_SLEEP_MS 1000 + +#define PAGES_TO_FREE 512 +#define HIGH_PRESSURE 95 +#define MID_PRESSURE 75 + +/* + * ANON-ZEROED pages pool. This pool is first use-case of this framework. + */ +struct dynamic_page_pool *anon_pool; +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +struct dynamic_page_pool *anon_hugepage_pool; +#endif + +static void *dynamic_page_pool_alloc_pages(struct dynamic_page_pool *pool) +{ + struct page *page; + + page = alloc_pages(pool->gfp_mask & ~__GFP_ZERO, pool->order); + if (!page) + return NULL; + + if (pool->gfp_mask & __GFP_ZERO) { + if (pool->order == 0) + clear_user_highpage(page, 0); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + else if (pool->order == HUGEPAGE_ORDER) + clear_huge_page(page, 0, HPAGE_PMD_NR); +#endif + } + + return page; +} + +static void dynamic_page_pool_free_pages(struct dynamic_page_pool *pool, + struct page *page) +{ + __free_pages(page, pool->order); +} + +static int dynamic_page_pool_add(struct dynamic_page_pool *pool, + struct page *page) +{ + mutex_lock(&pool->mutex); + list_add_tail(&page->lru, &pool->items); + pool->count++; + mutex_unlock(&pool->mutex); + + mod_node_page_state(page_pgdat(page), NR_INDIRECTLY_RECLAIMABLE_BYTES, + (1 << (PAGE_SHIFT + pool->order))); + return 0; +} + +static struct page *dynamic_page_pool_remove(struct dynamic_page_pool *pool) +{ + struct page *page; + + if (!mutex_trylock(&pool->mutex)) + return NULL; + + if (!pool->count) { + mutex_unlock(&pool->mutex); + return NULL; + } + + page = list_first_entry(&pool->items, struct page, lru); + pool->count--; + list_del(&page->lru); + mutex_unlock(&pool->mutex); + mod_node_page_state(page_pgdat(page), NR_INDIRECTLY_RECLAIMABLE_BYTES, + -(1 << (PAGE_SHIFT + pool->order))); + return page; +} + +void *dynamic_page_pool_alloc(struct dynamic_page_pool *pool) +{ + struct page *page = NULL; + + BUG_ON(!pool); + page = dynamic_page_pool_remove(pool); + + return page; +} + +void dynamic_page_pool_free(struct dynamic_page_pool *pool, struct page *page) +{ + /* TODO: IMPROVEMENT: + * These are free pages. We can directly add to the pool. Not doing + * that now as we want to rely on one source for now, which is + * dynamic_page_pool_grow(). + */ + dynamic_page_pool_free_pages(pool, page); +} + +/* + * @pool: The pool which we want to shrink + * @nr_to_scan: Number of 4KB pages we want to free + * + * Shrinker policy is, just do the minimum required free up as asked by + * kswapd() or someone else. + * + * Ideally, we don't wish to do much of a shrink as it is a waste of + * pooling and zeroing. So, we won't be much aggressive here and just + * do the thing as asked. + */ +static unsigned int dynamic_page_pool_shrink(struct dynamic_page_pool *pool, + int nr_to_scan, bool force) +{ + int count; + unsigned int freed = 0; + + /* + * For nr_to_scan = 1 or 2, it is not worth freeing any single page + * with very high order (such as 9, means we free 512 pages) + */ + if (nr_to_scan == 0 || (nr_to_scan >> pool->order) == 0) + return freed; + + /* + * We are interested to know when lastly shrinker has been called. + * Mainly for 2 reasons. First, we don't want to run refill funciton + * soon after shrinker has been called. Secondly, we also don't want + * to call shrinkers back to back. + */ + mutex_lock(&pool->mutex); + if (!force && (pool->last_shrink_time + pool->sleep_millisecs > + jiffies_to_msecs(jiffies))) { + mutex_unlock(&pool->mutex); + return freed; + } + + pool->last_shrink_time = jiffies_to_msecs(jiffies); + mutex_unlock(&pool->mutex); + + while (freed < nr_to_scan) { + struct page *page; + + mutex_lock(&pool->mutex); + count = pool->count; + mutex_unlock(&pool->mutex); + + if (count > pool->min_reserve_pages) { + page = dynamic_page_pool_remove(pool); + if (!page) + continue; + } else { + break; + } + + dynamic_page_pool_free_pages(pool, page); + freed += (1 << pool->order); + } + + return freed; +} + +/* + * Policy to grow pool size is simple, just reach to the max limit. The max + * limit is typically one big app's anon requirement. And we wish to be ready + * when someone requests for anon pages. + */ +static int dynamic_page_pool_grow(struct dynamic_page_pool *pool) +{ + struct page *page; + int refill_pages; + + mutex_lock(&pool->mutex); + refill_pages = (pool->max_reserve_pages > pool->count) ? + pool->max_reserve_pages - pool->count : + 0; + mutex_unlock(&pool->mutex); + + while (refill_pages) { + page = dynamic_page_pool_alloc_pages(pool); + + if (!page) + break; + + dynamic_page_pool_add(pool, page); + refill_pages--; + } + + return refill_pages; +} + +void dynamic_page_pool_set_max_pool_size(struct dynamic_page_pool *pool, + unsigned long max_reserve_pages) +{ + mutex_lock(&pool->mutex); + pool->max_reserve_pages = max_reserve_pages; + + if (pool->count - max_reserve_pages > 0) { + mutex_unlock(&pool->mutex); + /* + * While degrading pool size, we wish to have pool->count be + * operating in the same range as newly set. + */ + dynamic_page_pool_shrink(pool, (pool->count - max_reserve_pages) << pool->order, true); + return; + } + + mutex_unlock(&pool->mutex); +} + +unsigned long dynamic_page_pool_get_max_pool_size(struct dynamic_page_pool *pool) +{ + unsigned long count; + + mutex_lock(&pool->mutex); + count = pool->max_reserve_pages; + mutex_unlock(&pool->mutex); + return count; +} + +void dynamic_page_pool_set_current_size(struct dynamic_page_pool *pool, + unsigned int pages) +{ +} + +unsigned long dynamic_page_pool_get_current_size(struct dynamic_page_pool *pool) +{ + unsigned long count; + + mutex_lock(&pool->mutex); + count = pool->count; + mutex_unlock(&pool->mutex); + return count; +} + +void dynamic_page_pool_set_sleep_millisecs(struct dynamic_page_pool *pool, + unsigned int sleep_millisecs) +{ + mutex_lock(&pool->mutex); + pool->sleep_millisecs = sleep_millisecs; + mutex_unlock(&pool->mutex); +} + +unsigned long dynamic_page_pool_get_sleep_millisecs( + struct dynamic_page_pool *pool) +{ + unsigned long sleep_millisecs; + + mutex_lock(&pool->mutex); + sleep_millisecs = pool->sleep_millisecs; + mutex_unlock(&pool->mutex); + return sleep_millisecs; +} + +static int dynamic_page_pool_thread(void *nothing) +{ + struct dynamic_page_pool *pool; + unsigned long last_shrink_time; + unsigned int sleep_millisecs; + long diff; + int short_of; + + pool = (struct dynamic_page_pool *) nothing; + set_freezable(); + + while (1) { + mutex_lock(&pool->mutex); + last_shrink_time = pool->last_shrink_time; + sleep_millisecs = pool->sleep_millisecs; + mutex_unlock(&pool->mutex); + + /* + * As per the grow policy, we want to rest for some + * GRACE_PERIOD time since the last shrinker executed, + * before we start new grow procedure. The reason here + * is obvious, we don't want to grow the pool and at + * the same time perform shrink operation on it. + */ + diff = last_shrink_time + GRACE_PERIOD - jiffies_to_msecs(jiffies); + if (diff > 10 && diff < GRACE_PERIOD) + freezable_schedule_timeout_interruptible( + msecs_to_jiffies(diff)); + + if (!pm_freezing) { + short_of = dynamic_page_pool_grow(pool); + } else { + set_current_state(TASK_INTERRUPTIBLE); + freezable_schedule(); + } + + freezable_schedule_timeout_interruptible( + msecs_to_jiffies(sleep_millisecs)); + } + + return 0; +} + +struct dynamic_page_pool *dynamic_page_pool_create(const char *name, + gfp_t gfp_mask, + unsigned long min_reserve_pages, + unsigned long max_reserve_pages, + unsigned int order, + unsigned int sleep_millisecs) +{ + struct dynamic_page_pool *pool; + + pool = kmalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) + return NULL; + + pool->name = name; + pool->count = 0; + pool->gfp_mask = gfp_mask; + pool->order = order; + pool->min_reserve_pages = min_reserve_pages; + pool->max_reserve_pages = max_reserve_pages; + pool->sleep_millisecs = sleep_millisecs; + pool->last_shrink_time = 0; + mutex_init(&pool->mutex); + INIT_LIST_HEAD(&pool->items); + + pool->thread = kthread_run(dynamic_page_pool_thread, pool, pool->name); + if (IS_ERR(pool->thread)) { + pr_err("%s thread couldn't start\n", pool->name); + return NULL; + } + + return pool; +} + +void dynamic_page_pool_destroy(struct dynamic_page_pool *pool) +{ + kfree(pool); +} + +static int vmpressure_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + unsigned long pressure = action; + unsigned long freed = 0; + + if (!current_is_kswapd()) + return 0; + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + /* + * High pressure event needs at least 2 MB chunk at that time. + */ + if (pressure >= HIGH_PRESSURE) { + freed = dynamic_page_pool_shrink(anon_hugepage_pool, + PAGES_TO_FREE, + false); + return 0; + } +#endif + + /* + * We don't want to free too much on medium pressure + */ + if (pressure >= MID_PRESSURE) + freed = dynamic_page_pool_shrink(anon_pool, + PAGES_TO_FREE/4, + false); + + return 0; +} + +static struct notifier_block vmpr_nb = { + .notifier_call = vmpressure_notifier, +}; + +static int __init dynamic_page_pool_init(void) +{ + gfp_t pool_flags; + + /* + * Currently, we have an idea of only 2 pools. So, we define them + * explicitly. In case if it happens to add any new pool, it should + * be better to access each pool through some connecting data + * structure. + */ + pool_flags = __GFP_MOVABLE | GFP_HIGHUSER | __GFP_ZERO; + anon_pool = dynamic_page_pool_create("anon_pool", + pool_flags, + DPP_ANON_MIN, + DPP_ANON_MAX, + 0, + DPP_ANON_SLEEP_MS); + if (!anon_pool) + pr_err("There is some error in creating anon_pool\n"); + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + pool_flags = (GFP_TRANSHUGE | __GFP_ZERO); + anon_hugepage_pool = dynamic_page_pool_create("anon_hugepage_pool", + pool_flags, + DPP_ANON_HUGEPAGE_MIN, + DPP_ANON_HUGEPAGE_MAX, + HUGEPAGE_ORDER, + DPP_ANON_HUGEPAGE_SLEEP_MS); + + if (!anon_hugepage_pool) + pr_err("There is some error in creating anon_hugepage_pool\n"); +#endif + + vmpressure_notifier_register(&vmpr_nb); + return 0; +} +device_initcall(dynamic_page_pool_init); diff --git a/drivers/oneplus/fs/Kconfig b/drivers/oneplus/fs/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a965bd7e9ba72acfa177818e10ee98117f647395 --- /dev/null +++ b/drivers/oneplus/fs/Kconfig @@ -0,0 +1,3 @@ +# oem device deriver +source "drivers/oneplus/fs/proc/Kconfig" +source "drivers/oneplus/fs/f2fs/Kconfig" diff --git a/drivers/oneplus/fs/Makefile b/drivers/oneplus/fs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3f09d519dd4864df51f30f86a401c915e00d5870 --- /dev/null +++ b/drivers/oneplus/fs/Makefile @@ -0,0 +1,6 @@ +# oem device deriver +# +obj-y += proc/ +obj-y += f2fs/ + + diff --git a/drivers/oneplus/fs/f2fs/Kconfig b/drivers/oneplus/fs/f2fs/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3b12d46b5c4b6b70573b7f908f20d69ab72f770f --- /dev/null +++ b/drivers/oneplus/fs/f2fs/Kconfig @@ -0,0 +1,19 @@ +config F2FS_BD_STAT + bool "F2FS Bigdata Statisitics Information" + depends on F2FS_FS + default y + help + contains the f2fs big-data statistics information about specific partition + mounted as f2fs. + /proc/fs/f2fs//base_info: + - basic statistics information + /proc/fs/f2fs//discard_info + - discard statistics information + /proc/fs/f2fs//cp_info + - checkpoint statistics information + /proc/fs/f2fs//gc_info + - gc statistics information + /proc/fs/f2fs//fsync_info + - fsync statistics information + /proc/fs/f2fs//hotcold_info + - hot/cold statistics information diff --git a/drivers/oneplus/fs/f2fs/Makefile b/drivers/oneplus/fs/f2fs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d137c290f4ebbb247c1db6904503f134f63edd28 --- /dev/null +++ b/drivers/oneplus/fs/f2fs/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_F2FS_BD_STAT) += of2fs_bigdata.o diff --git a/drivers/oneplus/fs/f2fs/of2fs_bigdata.c b/drivers/oneplus/fs/f2fs/of2fs_bigdata.c new file mode 100755 index 0000000000000000000000000000000000000000..5b79a3660facc48ad66f3b553ca3b756a769d3cb --- /dev/null +++ b/drivers/oneplus/fs/f2fs/of2fs_bigdata.c @@ -0,0 +1,416 @@ +/*********************************************************** +** File: - of2fs_sysfs.c +** Description: f2fs bigdata statistics +** +** Version: 1.0 +** Date: 2019/08/14 +** Activity: [ASTI-147] +** +** ------------------ Revision History:------------------------ +** +** 2019/08/14 1.0 add code for f2fs bigdata statistics +****************************************************************/ + +#include +#include +#include + +#include "../../../../fs/f2fs/f2fs.h" +#include "../../../../fs/f2fs/segment.h" +#include "../../../../fs/f2fs/gc.h" + +#include "of2fs_bigdata.h" + +/* f2fs big-data statistics */ +#define OF2FS_PROC_DEF(_name) \ +static int of2fs_##_name##_open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, of2fs_##_name##_show, PDE_DATA(inode)); \ +} \ + \ +static const struct file_operations of2fs_##_name##_fops = { \ + .owner = THIS_MODULE, \ + .open = of2fs_##_name##_open, \ + .read = seq_read, \ + .write = of2fs_##_name##_write, \ + .llseek = seq_lseek, \ + .release = single_release, \ +}; + +static int of2fs_base_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + /* + * each column indicates: block_count fs_block_count + * free_segment_count reserved_segment_count + * valid_user_blocks + */ + seq_printf(seq, "%llu %llu %u %u %u\n", + le64_to_cpu(sbi->raw_super->block_count), + le64_to_cpu(sbi->raw_super->block_count) - le32_to_cpu(sbi->raw_super->main_blkaddr), + free_segments(sbi), reserved_segments(sbi), + valid_user_blocks(sbi)); + return 0; +} + +static ssize_t of2fs_base_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + return length; +} + +static int of2fs_discard_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * each colum indicates: discard_count discard_blocks undiscard_count + * undiscard_blocks discard_time max_discard_time + */ + bd_lock(sbi); + if (SM_I(sbi)->dcc_info) { + bd->undiscard_count = atomic_read(&SM_I(sbi)->dcc_info->discard_cmd_cnt); + bd->undiscard_blocks = SM_I(sbi)->dcc_info->undiscard_blks; + } + seq_printf(seq, "%u %u %u %u %llu %llu\n", bd->discard_count, + bd->discard_blocks, bd->undiscard_count, + bd->undiscard_blocks, bd->discard_time, + bd->max_discard_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_discard_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + bd->discard_count = 0; + bd->discard_blocks = 0; + bd->undiscard_count = 0; + bd->undiscard_blocks = 0; + bd->discard_time = 0; + bd->max_discard_time = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_cp_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * each column indicates: cp_count cp_success_count cp_time max_cp_time + * max_cp_submit_time max_cp_flush_meta_time max_cp_discard_time + */ + bd_lock(sbi); + bd->cp_count = sbi->stat_info->cp_count; + seq_printf(seq, "%u %u %llu %llu %llu %llu %llu\n", bd->cp_count, + bd->cp_success_count, bd->cp_time, bd->max_cp_time, + bd->max_cp_submit_time, bd->max_cp_flush_meta_time, + bd->max_cp_discard_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_cp_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + bd->cp_count = 0; + bd->cp_success_count = 0; + bd->cp_time = 0; + bd->max_cp_time = 0; + bd->max_cp_submit_time = 0; + bd->max_cp_flush_meta_time = 0; + bd->max_cp_discard_time = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_gc_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * each column indicates: bggc_cnt bggc_fail_cnt fggc_cnt fggc_fail_cnt + * bggc_data_seg_cnt bggc_data_blk_cnt bggc_node_seg_cnt bggc_node_blk_cnt + * fggc_data_seg_cnt fggc_data_blk_cnt fggc_node_seg_cnt fggc_node_blk_cnt + * node_ssr_cnt data_ssr_cnt node_lfs_cnt data_lfs_cnt data_ipu_cnt + * fggc_time + */ + bd_lock(sbi); + seq_printf(seq, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %llu\n", + bd->gc_count[BG_GC], bd->gc_fail_count[BG_GC], + bd->gc_count[FG_GC], bd->gc_fail_count[FG_GC], + bd->gc_data_segments[BG_GC], bd->gc_data_blocks[BG_GC], + bd->gc_node_segments[BG_GC], bd->gc_node_blocks[BG_GC], + bd->gc_data_segments[FG_GC], bd->gc_data_blocks[FG_GC], + bd->gc_node_segments[FG_GC], bd->gc_node_blocks[FG_GC], + bd->data_alloc_count[SSR], bd->node_alloc_count[SSR], + bd->data_alloc_count[LFS], bd->node_alloc_count[LFS], + bd->data_ipu_count, bd->fggc_time); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_gc_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + int i; + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + for (i = BG_GC; i <= FG_GC; i++) { + bd->gc_count[i] = 0; + bd->gc_fail_count[i] = 0; + bd->gc_data_count[i] = 0; + bd->gc_node_count[i] = 0; + bd->gc_data_segments[i] = 0; + bd->gc_data_blocks[i] = 0; + bd->gc_node_segments[i] = 0; + bd->gc_node_blocks[i] = 0; + } + bd->fggc_time = 0; + for (i = LFS; i <= SSR; i++) { + bd->node_alloc_count[i] = 0; + bd->data_alloc_count[i] = 0; + } + bd->data_ipu_count = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_fsync_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + /* + * eacho column indicates: fsync_reg_file_cnt fsync_dir_cnt fsync_time + * max_fsync_time fsync_wr_file_time max_fsync_wr_file_time + * fsync_cp_time max_fsync_cp_time fsync_sync_node_time + * max_fsync_sync_node_time fsync_flush_time max_fsync_flush_time + */ + bd_lock(sbi); + seq_printf(seq, "%u %u %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", + bd->fsync_reg_file_count, bd->fsync_dir_count, bd->fsync_time, + bd->max_fsync_time, bd->fsync_wr_file_time, + bd->max_fsync_wr_file_time, bd->fsync_cp_time, + bd->max_fsync_cp_time, bd->fsync_sync_node_time, + bd->max_fsync_sync_node_time, bd->fsync_flush_time, + bd->max_fsync_flush_time); + bd_unlock(sbi); + + return 0; +} + +static ssize_t of2fs_fsync_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + bd->fsync_reg_file_count = 0; + bd->fsync_dir_count = 0; + bd->fsync_time = 0; + bd->max_fsync_time = 0; + bd->fsync_cp_time = 0; + bd->max_fsync_cp_time = 0; + bd->fsync_wr_file_time = 0; + bd->max_fsync_wr_file_time = 0; + bd->fsync_sync_node_time = 0; + bd->max_fsync_sync_node_time = 0; + bd->fsync_flush_time = 0; + bd->max_fsync_flush_time = 0; + bd_unlock(sbi); + + return length; +} + +static int of2fs_hotcold_info_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + + bd_lock(sbi); + /* + * each colum indicates: hot_data_cnt, warm_data_cnt, cold_data_cnt, hot_node_cnt, + * warm_node_cnt, cold_node_cnt, meta_cp_cnt, meta_sit_cnt, meta_nat_cnt, meta_ssa_cnt, + * directio_cnt, gc_cold_data_cnt, rewrite_hot_data_cnt, rewrite_warm_data_cnt, + * gc_segment_hot_data_cnt, gc_segment_warm_data_cnt, gc_segment_cold_data_cnt, + * gc_segment_hot_node_cnt, gc_segment_warm_node_cnt, gc_segment_cold_node_cnt, + * gc_block_hot_data_cnt, gc_block_warm_data_cnt, gc_block_cold_data_cnt, + * gc_block_hot_node_cnt, gc_block_warm_node_cnt, gc_block_cold_node_cnt + */ + seq_printf(seq, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu " + "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", + bd->hotcold_count[HC_HOT_DATA], bd->hotcold_count[HC_WARM_DATA], + bd->hotcold_count[HC_COLD_DATA], bd->hotcold_count[HC_HOT_NODE], + bd->hotcold_count[HC_WARM_NODE], bd->hotcold_count[HC_COLD_NODE], + bd->hotcold_count[HC_META], bd->hotcold_count[HC_META_SB], + bd->hotcold_count[HC_META_CP], bd->hotcold_count[HC_META_SIT], + bd->hotcold_count[HC_META_NAT], bd->hotcold_count[HC_META_SSA], + bd->hotcold_count[HC_DIRECT_IO], bd->hotcold_count[HC_GC_COLD_DATA], + bd->hotcold_count[HC_REWRITE_HOT_DATA], + bd->hotcold_count[HC_REWRITE_WARM_DATA], + bd->hotcold_gc_segments[HC_HOT_DATA], + bd->hotcold_gc_segments[HC_WARM_DATA], + bd->hotcold_gc_segments[HC_COLD_DATA], + bd->hotcold_gc_segments[HC_HOT_NODE], + bd->hotcold_gc_segments[HC_WARM_NODE], + bd->hotcold_gc_segments[HC_COLD_NODE], + bd->hotcold_gc_blocks[HC_HOT_DATA], + bd->hotcold_gc_blocks[HC_WARM_DATA], + bd->hotcold_gc_blocks[HC_COLD_DATA], + bd->hotcold_gc_blocks[HC_HOT_NODE], + bd->hotcold_gc_blocks[HC_WARM_NODE], + bd->hotcold_gc_blocks[HC_COLD_NODE]); + bd_unlock(sbi); + return 0; +} + +static ssize_t of2fs_hotcold_info_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) +{ + struct seq_file *seq = file->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + char buffer[3] = {0}; + int i; + + if (!buf || length > 2 || length <= 0) + return -EINVAL; + + if (copy_from_user(&buffer, buf, length)) + return -EFAULT; + + if (buffer[0] != '0') + return -EINVAL; + + bd_lock(sbi); + for (i = 0; i < NR_HOTCOLD_TYPE; i++) + bd->hotcold_count[i] = 0; + for (i = 0; i < NR_CURSEG; i++) { + bd->hotcold_gc_segments[i] = 0; + bd->hotcold_gc_blocks[i] = 0; + } + bd_unlock(sbi); + + return length; +} + +OF2FS_PROC_DEF(base_info); +OF2FS_PROC_DEF(discard_info); +OF2FS_PROC_DEF(gc_info); +OF2FS_PROC_DEF(cp_info); +OF2FS_PROC_DEF(fsync_info); +OF2FS_PROC_DEF(hotcold_info); + +void f2fs_build_bd_stat(struct f2fs_sb_info *sbi) +{ + struct super_block *sb = sbi->sb; + + proc_create_data("base_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_base_info_fops, sb); + proc_create_data("discard_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_discard_info_fops, sb); + proc_create_data("cp_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_cp_info_fops, sb); + proc_create_data("gc_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_gc_info_fops, sb); + proc_create_data("fsync_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_fsync_info_fops, sb); + proc_create_data("hotcold_info", S_IRUGO | S_IWUGO, sbi->s_proc, + &of2fs_hotcold_info_fops, sb); +} + +void f2fs_destroy_bd_stat(struct f2fs_sb_info *sbi) +{ + remove_proc_entry("base_info", sbi->s_proc); + remove_proc_entry("discard_info", sbi->s_proc); + remove_proc_entry("cp_info", sbi->s_proc); + remove_proc_entry("gc_info", sbi->s_proc); + remove_proc_entry("fsync_info", sbi->s_proc); + remove_proc_entry("hotcold_info", sbi->s_proc); + + if (sbi->bd_info) { + kfree(sbi->bd_info); + sbi->bd_info = NULL; + } +} diff --git a/drivers/oneplus/fs/f2fs/of2fs_bigdata.h b/drivers/oneplus/fs/f2fs/of2fs_bigdata.h new file mode 100755 index 0000000000000000000000000000000000000000..ed9f07c14f09505a17c60ebf8d9c7875e0d80a34 --- /dev/null +++ b/drivers/oneplus/fs/f2fs/of2fs_bigdata.h @@ -0,0 +1,125 @@ +/*********************************************************** +** File: - of2fs_bigdata.h +** Description: f2fs bigdata statistics code +** +** Version: 1.0 +** Date: 2019/08/14 +** Activity: [ASTI-147] +** +** ------------------ Revision History:------------------------ +** +** 2019/08/14 1.0 add code for f2fs bigdata statistics +****************************************************************/ + +#ifndef _OF2FS_BIGDATA_H +#define _OF2FS_BIGDATA_H +/* unit for time: ns */ +enum { + HC_UNSET, + HC_HOT_DATA, + HC_WARM_DATA, + HC_COLD_DATA, + HC_HOT_NODE, + HC_WARM_NODE, + HC_COLD_NODE, + NR_CURSEG, + HC_META = NR_CURSEG, + HC_META_SB, + HC_META_CP, + HC_META_SIT, + HC_META_NAT, + HC_META_SSA, + HC_DIRECT_IO, + HC_GC_COLD_DATA, + HC_REWRITE_HOT_DATA, + HC_REWRITE_WARM_DATA, + NR_HOTCOLD_TYPE, +}; + +struct f2fs_bigdata_info { + /* CP info + * avg_cp_time = cp_time / cp_count + */ + unsigned int cp_count, cp_success_count; + u64 cp_time, max_cp_time, max_cp_submit_time, + max_cp_flush_meta_time, max_cp_discard_time; + + + /* Discard info + * avg_discard_time = discard_time / discard_count + */ + unsigned int discard_count, discard_blocks, + undiscard_count, undiscard_blocks; + u64 discard_time, max_discard_time; + + /* GC info: BG_GC = 0, FG_GC = 1 + * avg_[bg|fg]gc_data_segments = [bg|fg]gc_data_segments / [bg|fg]gc_data_count + * avg_[bg|fg]gc_data_blocks = [bg|fg]gc_data_blocks / [bg|fg]gc_data_count + * avg_fggc_time = fggc_time / fggc_count + * + */ + unsigned int gc_count[2], gc_fail_count[2], + gc_data_count[2], gc_node_count[2]; + unsigned int gc_data_segments[2], gc_data_blocks[2], + gc_node_segments[2], gc_node_blocks[2]; + u64 fggc_time; + + + /* Node alloc info: LFS = 0, SSR = 1 */ + unsigned int node_alloc_count[2], data_alloc_count[2], data_ipu_count; + + unsigned long last_node_alloc_count, last_data_alloc_count; + unsigned long curr_node_alloc_count, curr_data_alloc_count; + unsigned long ssr_last_jiffies; + + /* Fsync info */ + unsigned int fsync_reg_file_count, fsync_dir_count; + u64 fsync_time, max_fsync_time, fsync_cp_time, max_fsync_cp_time, + fsync_wr_file_time, max_fsync_wr_file_time, fsync_sync_node_time, + max_fsync_sync_node_time, fsync_flush_time, max_fsync_flush_time; + + /* Hot cold info */ + unsigned long hotcold_count[NR_HOTCOLD_TYPE]; + unsigned long hotcold_gc_segments[NR_CURSEG]; + unsigned long hotcold_gc_blocks[NR_CURSEG]; +}; + +static inline struct f2fs_bigdata_info *F2FS_BD_STAT(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_bigdata_info *)sbi->bd_info; +} + +#define bd_inc_val(sbi, member, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member += (val); \ +} while (0) +#define bd_inc_array_val(sbi, member, idx, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member[(idx)] += (val); \ +} while (0) + +#define bd_set_val(sbi, member, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member = (val); \ +} while (0) +#define bd_set_array_val(sbi, member, idx, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) \ + bd->member[(idx)] = (val); \ +} while (0) + +#define bd_max_val(sbi, member, val) do { \ + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); \ + if (bd) { \ + if (bd->member < (val)) \ + bd->member = (val); \ + } \ +} while (0) + +#define bd_lock_init(sbi) spin_lock_init(&(sbi)->bd_lock) +#define bd_lock(sbi) spin_lock(&(sbi)->bd_lock) +#define bd_unlock(sbi) spin_unlock(&(sbi)->bd_lock) +#endif diff --git a/drivers/oneplus/fs/proc/Kconfig b/drivers/oneplus/fs/proc/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..7e691d1ce02e2fff8496da026c4f8a04cec3de8f --- /dev/null +++ b/drivers/oneplus/fs/proc/Kconfig @@ -0,0 +1,5 @@ +config ONEPLUS_FG_OPT + bool "Enable /proc/fg_info/ if EXPERT" + default y + help + Add foreground process optimize support to promote performance . diff --git a/drivers/oneplus/fs/proc/Makefile b/drivers/oneplus/fs/proc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..245b48d0670038db7cc2163f0c7c8d682418e098 --- /dev/null +++ b/drivers/oneplus/fs/proc/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ONEPLUS_FG_OPT) += fg_uid.o diff --git a/drivers/oneplus/fs/proc/adj_chain_stat.c b/drivers/oneplus/fs/proc/adj_chain_stat.c new file mode 100644 index 0000000000000000000000000000000000000000..7777908be121ab3743d02ecd14433d34a8264aa6 --- /dev/null +++ b/drivers/oneplus/fs/proc/adj_chain_stat.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include +#include + +static int adj_chain_proc_show(struct seq_file *m, void *v) +{ + struct task_struct *tsk, *p; + int i = 0; + int tasksize = 0; + + rcu_read_lock(); + read_lock_irq(&tasklist_lock); + while (i <= adj_chain_hist_high) { + if (!list_empty(&adj_chain[i])) { + list_for_each_entry_rcu(tsk, &adj_chain[i], + adj_chain_tasks) { + tasksize = 0; + p = find_lock_task_mm(tsk); + if (!p) + goto just_print; + tasksize = get_mm_rss(p->mm); + task_unlock(p); +just_print: + seq_printf(m, "%d tsk: %s, %d, adj %d, size %d\n", + __adjr(i), tsk->comm, tsk->pid, + tsk->signal->oom_score_adj, tasksize); + } + } + ++i; + } + read_unlock_irq(&tasklist_lock); + rcu_read_unlock(); + seq_printf(m, "adj chain hist high: %d\n", __adjr(adj_chain_hist_high)); + return 0; +} + +static int adj_chain_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, adj_chain_proc_show, NULL); +} + +static const struct file_operations adj_chain_proc_fops = { + .open = adj_chain_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int adj_chain_verify_proc_show(struct seq_file *m, void *v) +{ + struct task_struct *tsk, *p; + int tasksize = 0; + + rcu_read_lock(); + for_each_process(tsk) { + if (tsk) { + tasksize = 0; + p = find_lock_task_mm(tsk); + if (!p) + goto just_print; + tasksize = get_mm_rss(p->mm); + task_unlock(p); +just_print: + seq_printf(m, "tsk: %s, %d, adj %d, size %d\n", + tsk->comm, tsk->pid, tsk->signal->oom_score_adj, + tasksize); + } + } + rcu_read_unlock(); + return 0; +} + +static int adj_chain_verify_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, adj_chain_verify_proc_show, NULL); +} + +static const struct file_operations adj_chain_verify_proc_fops = { + .open = adj_chain_verify_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_adj_chain_init(void) +{ + proc_create("adj_chain_stat", S_IFREG | 0400, NULL, + &adj_chain_proc_fops); + proc_create("adj_chain_verify", S_IFREG | 0400, NULL, + &adj_chain_verify_proc_fops); + return 0; +} +fs_initcall(proc_adj_chain_init); diff --git a/drivers/oneplus/fs/proc/fg_uid.c b/drivers/oneplus/fs/proc/fg_uid.c new file mode 100644 index 0000000000000000000000000000000000000000..58e2f486f6a28c5c85fb2b0770fc806fbb39ae82 --- /dev/null +++ b/drivers/oneplus/fs/proc/fg_uid.c @@ -0,0 +1,125 @@ +/* + *Copyright (c) 2018 OnePlus Mobile Comm Corp., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../../fs/proc/internal.h" +#include "fg_uid.h" + +#define FG_RW (S_IWUSR|S_IRUSR|S_IWGRP|S_IRGRP|S_IWOTH|S_IROTH) + +struct fg_info fginfo = { + .fg_num = 0, + .fg_uids = -555, +}; + +static struct proc_dir_entry *fg_dir; + +bool is_fg(int uid) +{ + bool ret = false; + if (uid == fginfo.fg_uids) + ret = true; + return ret; +} + +static int fg_uids_show(struct seq_file *m, void *v) +{ + seq_printf(m, "fg_uids: %d\n", fginfo.fg_uids); + return 0; +} + +static int fg_uids_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, fg_uids_show, inode); +} + +static ssize_t fg_uids_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[MAX_ARRAY_LENGTH]; + int err = 0; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user((void *)buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + fginfo.fg_uids = simple_strtol(buffer, NULL, 0); + fginfo.fg_num = 1; +out: + return err < 0 ? err : count; +} + +static const struct file_operations proc_fg_uids_operations = { + .open = fg_uids_open, + .read = seq_read, + .write = fg_uids_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static void uids_proc_fs_init(struct proc_dir_entry *p_parent) +{ + struct proc_dir_entry *p_temp; + + if (!p_parent) + goto out_p_temp; + + p_temp = proc_create(FS_FG_UIDS, FG_RW, p_parent, &proc_fg_uids_operations); + if (!p_temp) + goto out_p_temp; + +out_p_temp: + return ; +} + +static int __init fg_uids_init(void) +{ + struct proc_dir_entry *p_parent; + + p_parent = proc_mkdir(FS_FG_INFO_PATH, fg_dir); + if (!p_parent) { + return -ENOMEM; + } + uids_proc_fs_init(p_parent); + return 0; +} + +static void __exit fg_uids_exit(void) +{ + if (!fg_dir) + return ; + + remove_proc_entry(FS_FG_UIDS, fg_dir); +} + +module_init(fg_uids_init); +module_exit(fg_uids_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jared Wu "); +MODULE_DESCRIPTION("optimize foreground process to promote performance"); diff --git a/drivers/oneplus/fs/proc/fg_uid.h b/drivers/oneplus/fs/proc/fg_uid.h new file mode 100644 index 0000000000000000000000000000000000000000..73f993609e63f62420f601726846e112cd2df664 --- /dev/null +++ b/drivers/oneplus/fs/proc/fg_uid.h @@ -0,0 +1,30 @@ +/* + *Copyright (c) 2018 OnePlus Mobile Comm Corp., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _FG_UID_H +#define _FG_UID_H + +#include + +#define MAX_ARRAY_LENGTH 256 +#define FS_FG_INFO_PATH "fg_info" +#define FS_FG_UIDS "fg_uids" + +struct fg_info { + int fg_num; + int fg_uids; +}; + +#endif /*_FG_UID_H*/ diff --git a/drivers/oneplus/hung_task_enhance/Kconfig b/drivers/oneplus/hung_task_enhance/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..58dcab1220705ca85da3f5cb8231348041d7d149 --- /dev/null +++ b/drivers/oneplus/hung_task_enhance/Kconfig @@ -0,0 +1,6 @@ +config HUNG_TASK_ENHANCE + bool "hung task enhance" + default n + depends on DETECT_HUNG_TASK + help + define this config to enable HUNG_TASK_ENHANCE . diff --git a/drivers/oneplus/hung_task_enhance/Makefile b/drivers/oneplus/hung_task_enhance/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..85f6919fd650b0c2ecc8f9bb573fe60ded9c2426 --- /dev/null +++ b/drivers/oneplus/hung_task_enhance/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HUNG_TASK_ENHANCE) += hung_task_enhance.o diff --git a/drivers/oneplus/hung_task_enhance/hung_task_enhance.c b/drivers/oneplus/hung_task_enhance/hung_task_enhance.c new file mode 100644 index 0000000000000000000000000000000000000000..1490cb91788692a860bf39df9e961bb5e6488171 --- /dev/null +++ b/drivers/oneplus/hung_task_enhance/hung_task_enhance.c @@ -0,0 +1,188 @@ +/*************************************************************** +** File : hung_task_enhance.c +** Description : detect hung task in D state +** Version : 1.0 +** Date : 2020/08/18 +******************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * format: task_name,reason. e.g. system_server,uninterruptible for 60 secs + */ +#define HUNG_TASK_KILL_LEN 128 +char __read_mostly sysctl_hung_task_kill[HUNG_TASK_KILL_LEN]; +#define TWICE_DEATH_PERIOD 300000000000ULL /* 300s */ +#define MAX_DEATH_COUNT 3 +#define DISP_TASK_COMM_LEN_MASK 10 + +/* Foreground background optimization,change max io count */ +#define MAX_IO_WAIT_HUNG 5 +int __read_mostly sysctl_hung_task_maxiowait_count = MAX_IO_WAIT_HUNG; + +/* key process:zygote system_server surfaceflinger */ +static bool is_userspace_key_process(struct task_struct *t) +{ + const struct cred *tcred = __task_cred(t); + + if(!strcmp(t->comm, "main") && (tcred->uid.val == 0) && + (t->parent != 0 && !strcmp(t->parent->comm, "init"))) + return true; + if(!strncmp(t->comm, "system_server", TASK_COMM_LEN) || + !strncmp(t->comm, "surfaceflinger", TASK_COMM_LEN)) + return true; + if (!strncmp(t->comm, "Binder:", 7) && (t->group_leader->pid == t->pid) + && (tcred->uid.val == 1000) && (t->parent != 0 && !strcmp(t->parent->comm, "main"))) + return true; + + return false; +} + +static void oplus_check_hung_task(struct task_struct *t, unsigned long timeout, + unsigned int *iowait_count, bool *show_lock, bool *call_panic) +{ + unsigned long switch_count = t->nvcsw + t->nivcsw; + static unsigned long long last_death_time = 0; + unsigned long long cur_death_time = 0; + static int death_count = 0; + unsigned int local_iowait = 0; + + /* + * Ensure the task is not frozen. + * Also, skip vfork and any other user process that freezer should skip. + */ + if (unlikely(t->flags & (PF_FROZEN | PF_FREEZER_SKIP))) + return; + + /* + * When a freshly created task is scheduled once, changes its state to + * TASK_UNINTERRUPTIBLE without having ever been switched out once, it + * musn't be checked. + */ + if (unlikely(!switch_count)) + return; + + if (switch_count != t->last_switch_count) { + t->last_switch_count = switch_count; + t->last_switch_time = jiffies; + return; + } + if (time_is_after_jiffies(t->last_switch_time + timeout * HZ)) + return; + + trace_sched_process_hang(t); + + /* kill D/T/t state tasks ,if this task blocked at iowait. so maybe we should reboot system first */ + if(t->in_iowait) { + printk("hung_task_enhance: io wait too long time\n"); + if(t->mm != NULL && t == t->group_leader) { // only work on user main thread + *iowait_count = *iowait_count + 1; + local_iowait = 1; + } + } + if (is_userspace_key_process(t)) { + if (t->state == TASK_UNINTERRUPTIBLE) + snprintf(sysctl_hung_task_kill, HUNG_TASK_KILL_LEN, + "%s,uninterruptible for %ld seconds", + t->comm, timeout); + else if (t->state == TASK_STOPPED) + snprintf(sysctl_hung_task_kill, HUNG_TASK_KILL_LEN, + "%s,stopped for %ld seconds", + t->comm, timeout); + else if (t->state == TASK_TRACED) + snprintf(sysctl_hung_task_kill, HUNG_TASK_KILL_LEN, + "%s,traced for %ld seconds", + t->comm, timeout); + else + snprintf(sysctl_hung_task_kill, HUNG_TASK_KILL_LEN, + "%s,unknown hung for %ld seconds", + t->comm, timeout); + + death_count++; + printk("hung_task_enhance: task %s:%d blocked for more than %ld seconds in state 0x%lx. Count:%d\n", + t->comm, t->pid, timeout, t->state, death_count); + + sched_show_task(t); + debug_show_held_locks(t); + trigger_all_cpu_backtrace(); + + cur_death_time = local_clock(); + if (death_count >= MAX_DEATH_COUNT) { + if (cur_death_time - last_death_time < TWICE_DEATH_PERIOD) { + printk("hung_task_enhance: has been triggered %d times, \ + last time at: %llu\n", death_count, last_death_time); + panic("hung_task_enhance: key process recovery has been triggered more than 3 times"); + } + } + last_death_time = cur_death_time; + + if (oem_get_download_mode()) + panic("hung_task_enhance: %s hung in D state", t->comm); + + do_send_sig_info(SIGKILL, SEND_SIG_FORCED, t, PIDTYPE_TGID); + wake_up_process(t); + } + + if (sysctl_hung_task_panic) { + console_verbose(); + *show_lock = true; + *call_panic = true; + + /* Panic on critical process D-state */ + if (is_userspace_key_process(t)) { + trigger_all_cpu_backtrace(); + panic("hung_task_enhance: blocked tasks"); + } + } + + /* + * Ok, the task did not get scheduled for more than 2 minutes, + * complain: + */ + + /* Modify for make sure we could print the stack of iowait thread before panic */ + if (local_iowait) { + pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n", + t->comm, t->pid, timeout); + pr_err(" %s %s %.*s\n", + print_tainted(), init_utsname()->release, + (int)strcspn(init_utsname()->version, " "), + init_utsname()->version); + pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\"" + " disables this message.\n"); + sched_show_task(t); + *show_lock = true; + } + touch_nmi_watchdog(); +} + +void io_check_hung_detection(struct task_struct *t, unsigned long timeout, + unsigned int *iowait_count, bool *show_lock, bool *call_panic) +{ + /* add io wait monitor */ + if (t->state == TASK_UNINTERRUPTIBLE || t->state == TASK_STOPPED || t->state == TASK_TRACED) + /* Check for selective monitoring */ + if (!sysctl_hung_task_selective_monitoring || + t->hang_detection_enabled) + oplus_check_hung_task(t, timeout, iowait_count, show_lock, call_panic); +} +EXPORT_SYMBOL(io_check_hung_detection); + +void io_block_panic(unsigned int *iowait_count, unsigned int sys_mamxiowait_count) +{ +/* Foreground background optimization,change max io count */ + if(*iowait_count >= sysctl_hung_task_maxiowait_count) + panic("hung_task_enhance: [%u]IO blocked too long time", *iowait_count); +} +EXPORT_SYMBOL(io_block_panic); diff --git a/drivers/oneplus/include/linux/iolimit_cgroup.h b/drivers/oneplus/include/linux/iolimit_cgroup.h new file mode 100644 index 0000000000000000000000000000000000000000..885f26b2229ec99eff8a5efd5d870f343c6ba966 --- /dev/null +++ b/drivers/oneplus/include/linux/iolimit_cgroup.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Definitions for talking to the CUDA. The CUDA is a microcontroller + * which controls the ADB, system power, RTC, and various other things. + * + * Copyright (C) 1996 Paul Mackerras. + */ + +#ifndef _CGROUP_IOLIMIT_H +#define _CGROUP_IOLIMIT_H + +#include +#include +#include +#include + +#ifdef CONFIG_CGROUP_IOLIMIT + +extern bool iolimit_enable; + +struct iolimit_cgroup { + struct cgroup_subsys_state css; + atomic64_t switching; + + atomic64_t write_limit; + s64 write_part_nbyte; + s64 write_already_used; + struct timer_list write_timer; + spinlock_t write_lock; + wait_queue_head_t write_wait; + + atomic64_t read_limit; + s64 read_part_nbyte; + s64 read_already_used; + struct timer_list read_timer; + spinlock_t read_lock; + wait_queue_head_t read_wait; +}; + +static inline struct iolimit_cgroup *css_iolimit(struct cgroup_subsys_state *css) +{ + return css ? container_of(css, struct iolimit_cgroup, css) : NULL; +} + +static inline struct iolimit_cgroup *task_iolimitcg(struct task_struct *tsk) +{ + return css_iolimit(task_css(tsk, iolimit_cgrp_id)); +} + +void do_io_write_bandwidth_control(size_t count); + +void do_io_read_bandwidth_control(size_t count); + +static inline void io_read_bandwidth_control(size_t count) +{ + if (likely(task_css_is_root(current, iolimit_cgrp_id))) + return; + + do_io_read_bandwidth_control(count); +} + +static inline void io_write_bandwidth_control(size_t count) +{ + if (likely(task_css_is_root(current, iolimit_cgrp_id))) + return; + + do_io_write_bandwidth_control(count); +} + +static inline void io_generic_read_bandwidth_control(size_t count) +{ + if (likely(task_css_is_root(current, iolimit_cgrp_id))) + return; + + task_set_in_pagefault(current); + do_io_read_bandwidth_control(count); + task_clear_in_pagefault(current); +} +#else /* !CONFIG_CGROUP_IOLIMIT */ + +static inline void io_write_bandwidth_control(size_t count) +{ +} + +static inline void io_read_bandwidth_control(size_t count) +{ +} + +static inline void io_generic_read_bandwidth_control(size_t count) +{ +} +#endif /* !CONFIG_CGROUP_IOLIMIT */ + +#endif /* _CGROUP_IOLIMIT_H */ diff --git a/drivers/oneplus/include/linux/oem/adj_chain.h b/drivers/oneplus/include/linux/oem/adj_chain.h new file mode 100644 index 0000000000000000000000000000000000000000..2aa22a2e119e64a60ec41d48a1f8e468ddd8b353 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/adj_chain.h @@ -0,0 +1,47 @@ +#ifndef _LINUX_ADJ_CHAIN_H +#define _LINUX_ADJ_CHAIN_H + +#include +#include +#include +#include + +#define ADJ_CHAIN_MAX ((OOM_SCORE_ADJ_MAX) - (OOM_SCORE_ADJ_MIN)) + +// real adj to adj chain index +#define __adjc(adj) (adj + OOM_SCORE_ADJ_MAX) + +// adj chain index to real adj +#define __adjr(adj) (adj - OOM_SCORE_ADJ_MAX) + +// adj chain helper +#define __adj_tasks(adj) (adj_chain[adj].adj_chain_tasks) +#define adj_tasks(adj) (adj_chain[__adjc(adj)].adj_chain_tasks) +#define get_oom_score_adj(p) (p->signal->oom_score_adj) +#define get_task_struct_adj_chain_rcu(h) \ + list_entry_rcu(h, struct task_struct, adj_chain_tasks) +enum { + AC_ATTACH, + AC_DETACH, + AC_UPDATE_ADJ, + AC_PROM_LEADER +}; + +#ifdef CONFIG_ADJ_CHAIN +#define adj_chain_init_list(p) INIT_LIST_HEAD(&(p)->adj_chain_tasks) +#define adj_chain_empty(adj) list_empty(&__adj_tasks(adj)) +extern struct list_head adj_chain[ADJ_CHAIN_MAX + 1]; +extern int adj_chain_ready; +extern int adj_chain_hist_high; +extern void adj_chain_update_oom_score_adj(struct task_struct *p); +extern void adj_chain_attach(struct task_struct *p); +extern void adj_chain_detach(struct task_struct *p); +#else +#define adj_chain_init_list(p) +#define adj_chain_empty(adj) (1) +static inline void adj_chain_update_oom_score_adj(struct task_struct *p) { } +static inline void adj_chain_attach(struct task_struct *p) { } +static inline void adj_chain_detach(struct task_struct *p) { } +#endif // CONFIG_ADJ_CHAIN + +#endif // _LINUX_ADJ_CHAIN_H diff --git a/drivers/oneplus/include/linux/oem/boot_mode.h b/drivers/oneplus/include/linux/oem/boot_mode.h new file mode 100644 index 0000000000000000000000000000000000000000..1a0f2ba4b74c863533d85f0795ca3660850a6c46 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/boot_mode.h @@ -0,0 +1,26 @@ +#ifndef _BOOT_MODE_H_ +#define _BOOT_MODE_H_ 1 + +enum oem_boot_mode { + MSM_BOOT_MODE_NORMAL, + MSM_BOOT_MODE_FASTBOOT, + MSM_BOOT_MODE_RECOVERY, + MSM_BOOT_MODE_AGING, + MSM_BOOT_MODE_FACTORY, + MSM_BOOT_MODE_RF, + MSM_BOOT_MODE_CHARGE, +}; + +enum oem_boot_mode get_boot_mode(void); + +enum oem_projcet { + OEM_PROJECT_MAX, +}; + +int get_oem_project(void); +int get_small_board_1_absent(void); +int get_small_board_2_absent(void); +int get_hw_board_version(void); +int get_rf_version(void); +int get_prj_version(void); +#endif diff --git a/drivers/oneplus/include/linux/oem/control_center.h b/drivers/oneplus/include/linux/oem/control_center.h new file mode 100644 index 0000000000000000000000000000000000000000..b3ed5d70989bd8a7512126b6ca0bdc28a0a784c3 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/control_center.h @@ -0,0 +1,141 @@ +#ifndef __CONTROL_CENTER_INC__ +#define __CONTROL_CENTER_INC__ + +#define CC_CTL_VERSION "2.0" + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#define CLUSTER_NUM (3) + +#define CC_CTL_NODE "cc_ctl" +#define CC_TAG "control center: " + +#ifdef CONFIG_CONTROL_CENTER +#define cc_logv(fmt...) \ + do { \ + if (cc_log_lv < 1) \ + pr_info(CC_TAG fmt); \ + } while (0) + +#define cc_logi(fmt...) \ + do { \ + if (cc_log_lv < 2) \ + pr_info(CC_TAG fmt); \ + } while (0) + +#define cc_logw(fmt...) \ + do { \ + if (cc_log_lv < 3) \ + pr_warn(CC_TAG fmt); \ + } while (0) + +/* special for ratelimited version */ +#define cc_logw_ratelimited(fmt...) \ + do { \ + if (cc_log_lv < 3) \ + pr_warn_ratelimited(CC_TAG fmt); \ + } while (0) + +#define cc_loge(fmt...) pr_err(CC_TAG fmt) +#define cc_logd(fmt...) pr_debug(CC_TAG fmt) +#else +#define cc_logv(fmt...) +#define cc_logi(fmt...) +#define cc_logw(fmt...) +#define cc_logw_ratelimited(fmt...) +#define cc_loge(fmt...) +#define cc_logd(fmt...) +#endif + +enum CC_CTL_GROUP { + CC_CTL_GROUP_DEFAULT, + CC_CTL_GROUP_AI, + CC_CTL_GROUP_GRAPHIC, + CC_CTL_GROUP_FRAMEWORK, + CC_CTL_GROUP_SYSTEM, + CC_CTL_GROUP_OTHERS, + + CC_CTL_GROUP_MAX +}; + +enum CC_CTL_CATEGORY { + CC_CTL_CATEGORY_CLUS_0_FREQ, + CC_CTL_CATEGORY_CLUS_1_FREQ, + CC_CTL_CATEGORY_CLUS_2_FREQ, + CC_CTL_CATEGORY_FPS_BOOST, + CC_CTL_CATEGORY_DDR_VOTING_FREQ, + CC_CTL_CATEGORY_DDR_LOCK_FREQ, + CC_CTL_CATEGORY_SCHED_PRIME_BOOST, + + /* TODO move out from control part */ + /* query */ + CC_CTL_CATEGORY_CLUS_0_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_1_FREQ_QUERY, + CC_CTL_CATEGORY_CLUS_2_FREQ_QUERY, + CC_CTL_CATEGORY_DDR_FREQ_QUERY, + + /* Turbo Boost */ + CC_CTL_CATEGORY_TB_FREQ_BOOST, + CC_CTL_CATEGORY_TB_PLACE_BOOST, + CC_CTL_CATEGORY_TB_CORECTL_BOOST, + CC_CTL_CATEGORY_MAX +}; + +enum CC_CTL_TYPE { + CC_CTL_TYPE_ONESHOT, + CC_CTL_TYPE_PERIOD, + CC_CTL_TYPE_RESET, + + /* + * NONBLOCK version. + * Always paired with the original one! + */ + CC_CTL_TYPE_ONESHOT_NONBLOCK, + CC_CTL_TYPE_PERIOD_NONBLOCK, + CC_CTL_TYPE_RESET_NONBLOCK, + + CC_CTL_TYPE_MAX +}; + +/* TODO consider display off case */ +enum CC_PRIO { + CC_PRIO_HIGH, + CC_PRIO_MED, + CC_PRIO_LOW, + + CC_PRIO_MAX // not priority max, TODO rename later +}; + +#define CC_IOC_MAGIC 'c' +#define CC_IOC_COMMAND _IOWR(CC_IOC_MAGIC, 0, struct cc_command) +#define CC_IOC_MAX 1 + +extern void cc_process(struct cc_command* cc); +extern void cc_tsk_process(struct cc_command* cc); +extern void cc_boost_ts_collect(struct cc_boost_ts* source); +extern void cc_check_renice(void *tsk); +extern void cc_set_cpu_idle_block(int cpu); + +/* define for trubo boost */ +enum TB_POL { + TB_POL_FPS_BOOST, + TB_POL_DEADLINE_NOTIFY, + TB_POL_SF_NOTIFY, + TB_POL_HOOK_API, + TB_POL_HWUI_BOOST, + + TB_POL_MAX +}; + +enum TB_TYPE { + TB_TYPE_FREQ_BOOST, + TB_TYPE_PLACE_BOOST, + TB_TYPE_TAGGING, + TB_TYPE_CORECTL_BOOST, + + TB_TYPE_MAX +}; + +#endif diff --git a/drivers/oneplus/include/linux/oem/device_info.h b/drivers/oneplus/include/linux/oem/device_info.h new file mode 100644 index 0000000000000000000000000000000000000000..05001be78aa0282e1f17e7678e21906e373ec7c9 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/device_info.h @@ -0,0 +1,9 @@ +#ifndef _DEVICE_INFO_H_ +#define _DEVICE_INFO_H_ 1 +#ifdef CONFIG_PSTORE_DEVICE_INFO +void save_dump_reason_to_device_info(char *buf); +#else +inline void save_dump_reason_to_device_info(char *reason) {} +#endif + +#endif diff --git a/drivers/oneplus/include/linux/oem/fsc.h b/drivers/oneplus/include/linux/oem/fsc.h new file mode 100644 index 0000000000000000000000000000000000000000..fe8ecf5d2cfee6ee5cec5a4bd076a2921d3ca7fa --- /dev/null +++ b/drivers/oneplus/include/linux/oem/fsc.h @@ -0,0 +1,24 @@ +#ifndef _LINUX_FSC_H_ +#define _LINUX_FSC_H_ + +#include +#include + +#define FSC_PATH_MAX (256) +#define FSC_SCAN_BULK (512) +#define FSC_HASH_BUCKET (8192) +#define FSC_SUMMARY_MAX (128) + +extern unsigned int fsc_enable; +extern int fsc_allow_list_cur; + +extern void fsc_spin_lock(unsigned int hidx); +extern void fsc_spin_unlock(unsigned int hidx); +extern unsigned int fsc_get_hidx(const char* path, size_t len); +extern void fsc_insert_absence_path_locked(const char* path, size_t len, u32 hidx); +extern void fsc_delete_absence_path_locked(const char* path, size_t len, u32 hidx); +extern char *fsc_absolute_path(struct path* path, struct dentry* dentry, char *buf, size_t buflen); +extern void fsc_delete_absence_path_dentry(struct path*, struct dentry* dentry); +extern bool fsc_absence_check(const char* path, size_t len); +extern bool fsc_path_check(struct filename *name, size_t *len); +#endif diff --git a/drivers/oneplus/include/linux/oem/houston.h b/drivers/oneplus/include/linux/oem/houston.h new file mode 100644 index 0000000000000000000000000000000000000000..8cf399ef3744b907d4880cdc9b17ff4f2db9f5be --- /dev/null +++ b/drivers/oneplus/include/linux/oem/houston.h @@ -0,0 +1,235 @@ +#ifndef __INCLUDE_HOUSTON__ +#define __INCLUDE_HOUSTON__ + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#include +#include +#include + +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#define HT_CLUSTERS 3 + +#ifndef CONFIG_ARCH_LITO +#define HT_CPUS_PER_CLUS 4 +#else +#define HT_CPUS_PER_CLUS 6 +#endif + +#define CLUS_0_IDX 0 + +#ifndef CONFIG_ARCH_LITO +#define CLUS_1_IDX 4 +#else +#define CLUS_1_IDX 6 +#endif + +#define CLUS_2_IDX 7 + +#define MIN_POLLING_VAL 5 +#define MAX_REPORT_PERIOD 18000 + +#define HT_CTL_NODE "ht_ctl" +#define HT_TAG "ht_monitor: " +#define ht_logv(fmt...) \ + do { \ + if (ht_log_lv < 1) \ + pr_info(HT_TAG fmt); \ + } while (0) + +#define ht_logi(fmt...) \ + do { \ + if (ht_log_lv < 2) \ + pr_info(HT_TAG fmt); \ + } while (0) + +#define ht_logw(fmt...) \ + do { \ + if (ht_log_lv < 3) \ + pr_warn(HT_TAG fmt); \ + } while (0) + +#define ht_loge(fmt...) pr_err(HT_TAG fmt) +#define ht_logd(fmt...) pr_debug(HT_TAG fmt) + +#define FPS_COLS (5) +#define FPS_LAYER_LEN (128) +#define FPS_PROCESS_NAME_LEN (64) +#define FPS_DATA_BUF_SIZE (256) +#define FPS_CACHE_LAYER_LEN (64) +#define FPS_TARGET_NUM (2) + +enum boost_config { + FRAME_BOOST = 1, + CPU_BOOST, + + BOOST_MAX +}; + +enum boost_lv { + BOOST_LV_0 = 0, + BOOST_LV_1, + BOOST_LV_2, + BOOST_LV_3, + BOOST_LV_4, + + BOOST_LV_MAX +}; + +/* customize your monitor */ +enum { + HT_TS, + HT_CLUS_FREQ_0_MIN, + HT_CLUS_FREQ_0_CUR, + HT_CLUS_FREQ_0_MAX, + HT_ISO_0, + HT_CLUS_FREQ_1_MIN, + HT_CLUS_FREQ_1_CUR, + HT_CLUS_FREQ_1_MAX, + HT_ISO_1, + HT_CLUS_FREQ_2_MIN, + HT_CLUS_FREQ_2_CUR, + HT_CLUS_FREQ_2_MAX, + HT_ISO_2, + HT_GPU_FREQ, + HT_BAT_VOLT_NOW, + HT_BAT_CURR_NOW, + HT_HW_INSTRUCTION, + HT_HW_CACHE_MISS, + HT_HW_CYCLE, + HT_CPU_0, + HT_CPU_1, + HT_CPU_2, + HT_CPU_3, + HT_CPU_4_0, + HT_CPU_4_1, + HT_CPU_5_0, + HT_CPU_5_1, + HT_CPU_6_0, + HT_CPU_6_1, + HT_CPU_7_0, + HT_CPU_7_1, + HT_THERM_0, + HT_THERM_1, + HT_THERM_2, + HT_UTIL_0, + HT_UTIL_1, + HT_UTIL_2, + HT_UTIL_3, + HT_UTIL_4, + HT_UTIL_5, + HT_UTIL_6, + HT_UTIL_7, + HT_FPS_PROCESS, + HT_FPS_LAYER, + HT_FPS_PID, + HT_FPS_ALIGN, + HT_FPS_1, + HT_FPS_2, + HT_FPS_3, + HT_FPS_4, + HT_FPS_5, + HT_FPS_6, + HT_FPS_7, + HT_FPS_8, + HT_FPS_MISS_LAYER, + HT_RENDER_PID, + HT_RENDER_UTIL, + HT_NT_RTG, + HT_RTG_UTIL_SUM, + HT_MONITOR_SIZE +}; + +/* fps stabilizer related */ +struct ht_fps_stabilizer_buf { + char buf[PAGE_SIZE]; +}; + +struct ht_partial_sys_info { + u32 volt; + u32 curr; + u64 utils[8]; + u32 skin_temp; +}; + +/* pick one unique magic number */ +#define HT_IOC_MAGIC 'k' +#define HT_IOC_COLLECT _IOR(HT_IOC_MAGIC, 0, struct ai_parcel) +#define HT_IOC_SCHEDSTAT _IOWR(HT_IOC_MAGIC, 1, u64) +#define HT_IOC_CPU_LOAD _IOWR(HT_IOC_MAGIC, 2, struct cpuload) +#define HT_IOC_FPS_STABILIZER_UPDATE _IOR(HT_IOC_MAGIC, 3, struct ht_fps_stabilizer_buf) +#define HT_IOC_FPS_PARTIAL_SYS_INFO _IOR(HT_IOC_MAGIC, 4, struct ht_partial_sys_info) +#define HT_IOC_MAX 4 + +#define AI_THREAD_PARCEL_MAX (10) + +struct ai_thread_parcel { + u32 tid; + u64 exec_time_ns; // schedstat + u64 inst; // pmu related + u64 cycle; + u64 cache_miss_l1; + u64 cache_miss_l2; + u64 cache_miss_l3; +}; + +struct ai_parcel { + u32 pid; + u32 fps; + u32 efps; + long long fps_align_ns; + u32 cpu; + u32 clus; + //char layer[FPS_CACHE_LAYER_LEN]; + u32 cpu_cur_freq_0; + u32 cpu_cur_freq_1; + u32 cpu_cur_freq_2; + u32 cpu_orig_freq_0; + u32 cpu_orig_freq_1; + u32 cpu_orig_freq_2; + u32 cpu_cc_min_freq_1; + u32 cpu_cc_max_freq_1; + u32 cpu_orig_min_freq_1; + u32 cpu_orig_max_freq_1; + u32 gpu_freq; + u64 ddr_freq; + u32 ddr_voting; + u32 volt_now; // battery part + u32 curr_now; + u64 queued_ts_us; + u64 prev_queued_ts_us; + u32 thread_amount; // default maximum 10 threads + u32 boost_cnt; + u64 notify_start_ts_us; + u64 notify_end_ts_us; + u64 utils[8]; + u32 skin_temp; +#ifdef CONFIG_CONTROL_CENTER + struct cc_boost_ts cbt[CC_BOOST_TS_SIZE]; +#endif + struct ai_thread_parcel t[AI_THREAD_PARCEL_MAX]; +}; + +/* cpu load info */ +struct cpuload { + union { + int min; + int pid; + }; + union { + int max; + int tid; + }; + int avg; + int sum; + long long iowait_min; + long long iowait_max; + long long iowait_avg; + long long iowait_sum; +}; +#endif // __INCLUDE_HOUSTON__ diff --git a/drivers/oneplus/include/linux/oem/hung_task_enhance.h b/drivers/oneplus/include/linux/oem/hung_task_enhance.h new file mode 100644 index 0000000000000000000000000000000000000000..42e10f499b606b0e54717ff018f0859e4cd2fbf2 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/hung_task_enhance.h @@ -0,0 +1,21 @@ +#ifndef __HUNG_TASK_ENHANCE_H +#define __HUNG_TASK_ENHANCE_H +#include +#include +#include + +/* format: task_name,reason. e.g. system_server,uninterruptible for 60 secs */ +extern char sysctl_hung_task_kill[]; +/* Foreground background optimization,change max io count */ +extern int sysctl_hung_task_maxiowait_count; +static int five = 5; + +#ifdef CONFIG_HUNG_TASK_ENHANCE +void io_check_hung_detection(struct task_struct *t, unsigned long timeout, unsigned int *iowait_count, bool *show_lock, bool *call_panic); +void io_block_panic(unsigned int *iowait_count, unsigned int sys_mamxiowait_count); +#else +void io_check_hung_detection(struct task_struct *t, unsigned long timeout, unsigned int *iowait_count, bool *show_lock, bool *call_panic) {} +static void io_block_panic(unsigned int *iowait_count, unsigned int sys_mamxiowait_count) {} +#endif + +#endif \ No newline at end of file diff --git a/drivers/oneplus/include/linux/oem/im.h b/drivers/oneplus/include/linux/oem/im.h new file mode 100644 index 0000000000000000000000000000000000000000..9286a5769c7d975e8d224ce91fcfb0d774038047 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/im.h @@ -0,0 +1,258 @@ +#ifndef __IM_H__ +#define __IM_H__ + +#include +#include + + +/* since im_flag is 32bit, don't identify too much */ +enum { + IM_ID_SURFACEFLINGER = 0, // surfaceflinger + IM_ID_KWORKER, // kworker + IM_ID_LOGD, // logd + IM_ID_LOGCAT, //logcat + IM_ID_MAIN, // application main thread + IM_ID_ENQUEUE, // qneueue frame task + IM_ID_GL, //open GL tasks + IM_ID_VK, // vulkan tasks + IM_ID_HWC, //hwcomposer + IM_ID_HWBINDER, // hw binder + IM_ID_BINDER, // binder + IM_ID_HWUI, // hwui tasks + IM_ID_RENDER, // application render thread + IM_ID_UNITY_WORKER_THREAD, + IM_ID_UNITY_MAIN, + IM_ID_LAUNCHER, // launcher + IM_ID_HWUI_EX, // Hwui task (render enhancement feature) + IM_ID_BMT, + IM_ID_CRENDER, + IM_ID_MAX +}; + +#define IM_SURFACEFLINGER (1 << IM_ID_SURFACEFLINGER) +#define IM_KWORKER (1 << IM_ID_KWORKER) +#define IM_LOGD (1 << IM_ID_LOGD) +#define IM_LOGCAT (1 << IM_ID_LOGCAT) +#define IM_MAIN (1 << IM_ID_MAIN) +#define IM_ENQUEUE (1 << IM_ID_ENQUEUE) +#define IM_GL (1 << IM_ID_GL) +#define IM_VK (1 << IM_ID_VK) +#define IM_HWC (1 << IM_ID_HWC) +#define IM_HWBINDER (1 << IM_ID_HWBINDER) +#define IM_BINDER (1 << IM_ID_BINDER) +#define IM_HWUI (1 << IM_ID_HWUI) +#define IM_RENDER (1 << IM_ID_RENDER) +#define IM_UNITY_WORKER_THREAD (1 << IM_ID_UNITY_WORKER_THREAD) +#define IM_UNITY_MAIN (1 << IM_ID_UNITY_MAIN) +#define IM_LAUNCHER (1 << IM_ID_LAUNCHER) +#define IM_HWUI_EX (1 << IM_ID_HWUI_EX) +#define IM_BMT (1 << IM_ID_BMT) +#define IM_CRENDER (1 << IM_ID_CRENDER) + +/* to be update */ +enum { + IM_IG_SF_PROBER = 0, + IM_IG_SF_APP, + IM_IG_SF_SF, + IM_IG_SF_DISPSYNC, + IM_IG_SF_SCREENSHOTTHRES, + IM_IG_HWC_DPPS, + IM_IG_HWC_LTM, + IM_IG_MAX +}; + +/* TODO add for group identify */ +/* TODO add check for cmdline to cover zygote */ + +#ifdef CONFIG_IM +static inline bool im_sf(struct task_struct *task) +{ + return task->im_flag & IM_SURFACEFLINGER; +} + +static inline bool im_kw(struct task_struct *task) +{ + return task->im_flag & IM_KWORKER; +} + +static inline bool im_logd(struct task_struct *task) +{ + return task->im_flag & IM_LOGD; +} + +static inline bool im_logcat(struct task_struct *task) +{ + return task->im_flag & IM_LOGCAT; +} + +static inline bool im_rendering(struct task_struct *task) +{ +#ifdef CONFIG_RATP + if (is_ratp_enable() && is_allowmost_enable()) { + return task->im_flag & + (IM_MAIN | + IM_ENQUEUE | + IM_SURFACEFLINGER | + IM_GL | + IM_VK | + IM_RENDER | + IM_HWC | + IM_HWBINDER | + IM_BINDER | + IM_BMT | + IM_CRENDER); + } +#endif + + return task->im_flag & + (IM_MAIN | + IM_ENQUEUE | + IM_SURFACEFLINGER | + IM_GL | + IM_VK | + IM_HWC | + IM_RENDER | + IM_BMT | + IM_CRENDER); + +} + +static inline bool im_graphic(struct task_struct *task) +{ + return task->im_flag & (IM_GL | IM_VK | IM_HWUI | IM_HWUI_EX); +} + +static inline bool im_main(struct task_struct *task) +{ + return task->im_flag & IM_MAIN; +} + +static inline bool im_render(struct task_struct *task) +{ + return task->im_flag & IM_RENDER; +} + +static inline bool im_enqueue(struct task_struct *task) +{ + return task->im_flag & IM_ENQUEUE; +} + +static inline bool im_gl(struct task_struct *task) +{ + return task->im_flag & IM_GL; +} + +static inline bool im_vk(struct task_struct *task) +{ + return task->im_flag & IM_VK; +} + +static inline bool im_hwc(struct task_struct *task) +{ + return task->im_flag & IM_HWC; +} + +static inline bool im_hwbinder(struct task_struct *task) +{ + return task->im_flag & IM_HWBINDER; +} + +static inline bool im_binder(struct task_struct *task) +{ + return task->im_flag & IM_BINDER; +} + +static inline bool im_binder_related(struct task_struct *task) +{ + return task->im_flag & (IM_HWBINDER | IM_BINDER); +} + +static inline bool im_hwui(struct task_struct *task) +{ + return task->im_flag & IM_HWUI; +} + +static inline bool im_unity_worker_thread(struct task_struct *task) +{ + return task->im_flag & (IM_UNITY_WORKER_THREAD); +} + +static inline bool im_unity_main(struct task_struct *task) +{ + return task->im_flag & (IM_UNITY_MAIN); +} + +static inline bool im_launcher(struct task_struct *task) +{ + return task->im_flag & IM_LAUNCHER; +} + +static inline bool im_hwuiEx(struct task_struct *task) +{ + return task->im_flag & IM_HWUI_EX; +} + +static inline bool im_crender(struct task_struct *task) +{ + return task->im_flag & IM_CRENDER; +} + +static inline bool im_bmt(struct task_struct *task) +{ + return task->im_flag & IM_BMT; +} + +extern void im_wmi(struct task_struct *task); +extern void im_wmi_current(void); +extern void im_set_flag(struct task_struct *task, int flag); +extern void im_set_flag_current(int flag); +extern void im_unset_flag(struct task_struct *task, int flag); +extern void im_unset_flag_current(int flag); +extern void im_reset_flag(struct task_struct *task); +extern void im_reset_flag_current(void); +extern void im_set_op_group(struct task_struct *task, int flag, bool insert); +extern int im_render_grouping_enable(void); +extern void im_list_add_task(struct task_struct *task); +extern void im_list_del_task(struct task_struct *task); +extern void im_to_str(int flag, char* desc, int size); +extern void im_tsk_init_flag(void *ptr); +#else +static inline bool im_sf(struct task_struct *task) { return false; } +static inline bool im_kw(struct task_struct *task) { return false; } +static inline bool im_logd(struct task_struct *task) { return false; } +static inline bool im_logcat(struct task_struct *task) { return false; } +static inline bool im_rendering(struct task_struct *task) { return false; } +static inline bool im_main(struct task_struct *task) { return false; } +static inline bool im_enqueue(struct task_struct *task) { return false; } +static inline bool im_render(struct task_struct *task) { return false; } +static inline bool im_gl(struct task_struct *task) { return false; } +static inline bool im_vk(struct task_struct *task) { return false; } +static inline bool im_hwc(struct task_struct *task) { return false; } +static inline bool im_hwbinder(struct task_struct *task) { return false; } +static inline bool im_binder(struct task_struct *task) { return false; } +static inline bool im_binder_related(struct task_struct *task) { return false; } +static inline bool im_hwui(struct task_struct *task) { return false; } +static inline bool im_unity_worker_thread(struct task_struct *task) { return false; } +static inline bool im_unity_main(struct task_struct *task) { return false; } +static inline bool im_launcher(struct task_struct *task) { return false; } +static inline bool im_hwuiEx(struct task_struct *task) { return false; } +static inline bool im_crender(struct task_struct *task) { return false; } +static inline bool im_bmt(struct task_struct *task) { return false; } +static inline void im_wmi(struct task_struct *task) {} +static inline void im_wmi_current(void) {} +static inline void im_set_flag(struct task_struct *task, int flag) {} +static inline void im_set_flag_current(int flag) {} +static inline void im_unset_flag(struct task_struct *task, int flag) {} +static inline void im_unset_flag_current(int flag) {} +static inline void im_reset_flag(struct task_struct *task) {} +static inline void im_reset_flag_current(void) {} +static inline void im_set_op_group(struct task_struct *task, + int flag, bool insert) {} +static inline int im_render_grouping_enable(void) { return 0; } +static inline void im_list_add_task(struct task_struct *task) {} +static inline void im_list_del_task(struct task_struct *task) {} +static inline void im_to_str(int flag, char* desc, int size) {} +static inline void im_tsk_init_flag(void *ptr) {} +#endif + +#endif diff --git a/drivers/oneplus/include/linux/oem/memory_monitor.h b/drivers/oneplus/include/linux/oem/memory_monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..e4a8632bfa25ea1cd19e65d9d0769e8d25403812 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/memory_monitor.h @@ -0,0 +1,33 @@ +/* + *Copyright (c) 2018 OnePlus Mobile Comm Corp., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _MEMORY_MONITOR_H_ +#define _MEMORY_MONITOR_H_ + +struct alloc_wait_para { + u64 total_alloc_wait_h_cnt; + u64 total_alloc_wait_l_cnt; + u64 fg_alloc_wait_h_cnt; + u64 fg_alloc_wait_l_cnt; + u64 total_alloc_wait_max_ms; + u64 total_alloc_wait_max_order; + u64 fg_alloc_wait_max_ms; + u64 fg_alloc_wait_max_order; +}; + +extern void memory_alloc_monitor(gfp_t gfp_mask, unsigned int order, u64 wait_ms); +extern struct alloc_wait_para allocwait_para; +#endif /*_MEMORY_MONITOR_H_*/ diff --git a/drivers/oneplus/include/linux/oem/oem_force_dump.h b/drivers/oneplus/include/linux/oem/oem_force_dump.h new file mode 100644 index 0000000000000000000000000000000000000000..60332bfd6a94248acbb71d96f2623c9bc0becab6 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/oem_force_dump.h @@ -0,0 +1,62 @@ +/* + * oem_force_dump.h + * + * header file supporting debug functions for Oneplus device. + * + * hefaxi@filesystems, 2015/07/03. + */ + +#ifndef OEM_FORCE_DUMP_H +#define OEM_FORCE_DUMP_H + +#ifndef NETLINK_ADB +#define NETLINK_ADB 23 +#endif + +#define OEM_SERIAL_INIT + +extern void oem_check_force_dump_key(unsigned int code, int value); +extern int oem_get_download_mode(void); +void send_msg(char *message); +void send_msg_sync_mdm_dump(void); +#ifdef OEM_SERIAL_INIT +int msm_serial_oem_init(void); +#else +inline int msm_serial_oem_init(void){ return 0;} +#endif + +#ifdef CONFIG_OEM_FORCE_DUMP +enum key_stat_item { + KEY_RELEASED, + KEY_PRESSED +}; + +extern void send_sig_to_get_trace(char *name); +extern void send_sig_to_get_tombstone(char *name); +extern void get_init_sched_info(void); +extern void dump_runqueue(void); +extern void compound_key_to_get_trace(char *name); +extern void compound_key_to_get_tombstone(char *name); +extern enum key_stat_item pwr_status, vol_up_status; + +static inline void set_pwr_status(enum key_stat_item status) +{ + pwr_status = status; +} + +static inline void set_vol_up_status(enum key_stat_item status) +{ + vol_up_status = status; +} +#else +static void send_sig_to_get_trace(char *name) {} +static void send_sig_to_get_tombstone(char *name) {} +static void get_init_sched_info(void) {} +static void dump_runqueue(void) {} +static void compound_key_to_get_trace(char *name) {} +static void compound_key_to_get_tombstone(char *name) {} +static inline void set_pwr_status(enum key_stat_item status) {} +static inline void set_vol_up_status(enum key_stat_item status) {} +#endif + +#endif diff --git a/drivers/oneplus/include/linux/oem/oneplus_healthinfo.h b/drivers/oneplus/include/linux/oem/oneplus_healthinfo.h new file mode 100644 index 0000000000000000000000000000000000000000..1ea9c51f35d05ec8a60b8479bc2f9cbbc1ac93b0 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/oneplus_healthinfo.h @@ -0,0 +1,152 @@ +/********************************************************************************** +* Copyright (c) 2008-2015 OnePlus Mobile Comm Corp., Ltd +* VENDOR_EDIT +* Description: OnePlus Healthinfo Monitor +* Record Kernel Resourse Abnormal Stat +* Version : 2.0 +* Date : 2019-04-24 +* Author : jared.wu@PSP +* ------------------------------ Revision History: -------------------------------- +* +* Revision 1.0 2019-04-24 jared.wu@PSP Created for Healthinfomonitor +***********************************************************************************/ + +#ifndef _ONEPLUS_HEALTHINFO_H_ +#define _ONEPLUS_HEALTHINFO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +#include + + +#ifdef CONFIG_ONEPLUS_MEM_MONITOR +#include +#endif /*CONFIG_ONEPLUS_MEM_MONITOR*/ + +#define ohm_err(fmt, ...) \ + printk(KERN_ERR "[OHM_ERR][%s]"fmt, __func__, ##__VA_ARGS__) +#define ohm_debug(fmt, ...) \ + printk(KERN_INFO "[OHM_INFO][%s]"fmt, __func__, ##__VA_ARGS__) +#define ohm_debug_deferred(fmt, ...) \ + printk_deferred(KERN_INFO "[OHM_INFO][%s]"fmt, __func__, ##__VA_ARGS__) +#define ohm_err_deferred(fmt, ...) \ + printk_deferred(KERN_ERR "[OHM_ERR][%s]"fmt, __func__, ##__VA_ARGS__) + +#define OHM_FLASH_TYPE_EMC 1 +#define OHM_FLASH_TYPE_UFS 2 + +#define OHM_SCHED_TYPE_MAX 12 +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +#define DEFAULT_RT_LT 1000000 +#define DEFAULT_RT_HT 5000000 +#define MAX_RT_EXEC 10000000 +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17 add for stuck info*/ +enum { + STUCK_TRACE_RUNNABLE = 0, + STUCK_TRACE_DSTATE, + STUCK_TRACE_SSTATE, + STUCK_TRACE_RUNNING, +}; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ +enum { + /* SCHED_STATS 0 -11 */ + OHM_SCHED_IOWAIT = 0, + OHM_SCHED_SCHEDLATENCY, + OHM_SCHED_FSYNC, + OHM_SCHED_EMMCIO, + /*2020-06-22 ,OSP-5970 , monitor cpu info **/ + OHM_SCHED_DSTATE, + OHM_SCHED_TOTAL, + /* OTHER_TYPE 12 - */ + OHM_CPU_LOAD_CUR = OHM_SCHED_TYPE_MAX, + OHM_MEM_MON, + /*2020-06-22 ,OSP-5970 , monitor cpu info **/ + OHM_RT_MON, + OHM_PREEMPT_LATENCY, + OHM_IOPANIC_MON, + OHM_TYPE_TOTAL +}; + +struct rq; +struct rt_rq; + +struct sched_stat_common { + u64 max_ms; + u64 high_cnt; + u64 low_cnt; + u64 total_ms; + u64 total_cnt; +}; + +struct sched_stat_para { + bool ctrl; + bool logon; + bool trig; + int low_thresh_ms; + int high_thresh_ms; + u64 low_cnt; + u64 high_cnt; + u64 total_ms; + u64 total_cnt; + u64 fg_low_cnt; + u64 fg_high_cnt; + u64 fg_total_ms; + u64 fg_total_cnt; + u64 fg_max_delta_ms; + u64 delta_ms; + struct sched_stat_common all; + struct sched_stat_common fg; + struct sched_stat_common ux; +}; + +/* Preempt structure*/ +struct cpu_preempt_stat{ + struct sched_stat_common preempt_common; + int low_thresh_ms; + int high_thresh_ms; +}; + +/*rt structure*/ +struct longest_task_info { + char comment[16]; + u64 max_exec_ns; +}; +struct sched_stat_rt_para { + u64 each_cpu_rt; + u64 each_cpu_rt_total; + u64 thresh_cnt[3]; + struct longest_task_info *lt_info; +}; +/* irq latency structure*/ +struct irq_latency_para { + int low_thresh; + int high_thresh; + u64 max; + u64 high_cnt; + u64 low_cnt; + u64 total; + u64 total_cnt; +}; + +extern bool ohm_rtinfo_ctrl; +extern bool ohm_preempt_ctrl; +extern bool ohm_irqsoff_ctrl; + +extern void ohm_overload_record(struct rq *rq, u64 delta_ms); +extern void rt_thresh_times_record(struct task_struct *p, unsigned int cpu); +extern void rt_info_record(struct rt_rq *rt_rq, unsigned int cpu); +extern void rt_total_record(u64 delta_exec, unsigned int cpu); +extern void ohm_preempt_record(u64 delta, int cpu); +extern void ohm_irqsoff_record(u64 delta, int cpu); + +extern int ohm_get_cur_cpuload(bool ctrl); + +#endif /* _ONEPLUS_HEALTHINFO_H_*/ diff --git a/drivers/oneplus/include/linux/oem/oneplus_ion.h b/drivers/oneplus/include/linux/oem/oneplus_ion.h new file mode 100644 index 0000000000000000000000000000000000000000..c3162c4461221f1214450f014d086d728e3f1bd0 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/oneplus_ion.h @@ -0,0 +1,23 @@ +/* + *Copyright (c) 2018 OnePlus Mobile Comm Corp., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __LINUX_ION_H__ +#define __LINUX_ION_H__ + +#include "../../drivers/staging/android/ion/ion.h" + +#endif /* __LINUX_ION_H__ */ diff --git a/drivers/oneplus/include/linux/oem/op_rf_cable_monitor.h b/drivers/oneplus/include/linux/oem/op_rf_cable_monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..9a43dded248c9d815521be7204fa3848f9c7babc --- /dev/null +++ b/drivers/oneplus/include/linux/oem/op_rf_cable_monitor.h @@ -0,0 +1,10 @@ +#ifndef _OP_RF_CABLE_MONITOR +#define _OP_RF_CABLE_MONITOR 1 + +extern char *saved_command_line; +extern void op_restart_modem(void); + +#define CABLE_WAKELOCK_HOLD_TIME 5000 +#define PAGESIZE 512 + +#endif diff --git a/drivers/oneplus/include/linux/oem/opchain_define.h b/drivers/oneplus/include/linux/oem/opchain_define.h new file mode 100644 index 0000000000000000000000000000000000000000..27e359c838b661f29428be43d3f3b07b0f5a27d3 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/opchain_define.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#ifndef _LINUX_OPCHAIN_DEFINE_H +#define _LINUX_OPCHAIN_DEFINE_H + +#define UX_DEBUG 0 +#define UTASK 0 +#define UT_CLK_BASE 0x01 +#define UT_ETASK 0x02 +#define UT_LATEST_ONE 0x04 +#define UT_PERF_TOP 0x08 +#define UT_FORE (UT_CLK_BASE | UT_ETASK) + +#define OP_CLAIM_S -1 +#define OP_PATH_SLAVE -4 +#define OP_PATH_CLAIM -3 +#define OP_PATH_NORMAL -2 +#define OP_PATH_OCCUPIED -1 +#define MIN_POWER_CPU 0 + +#define ONESEC_NANO 1000000000 + +#if 1 +/* for MSM8998, SDM845*/ +#define FIRST_BIG_CORE 4 +#define NUMS_CPU 8 +#define CPU_VIRTUAL_PLUG_IN(i) (opc_cpu_active(i) && !opc_cpu_isolated(i)) +#else +/* for MSM8996*/ +#define FIRST_BIG_CORE 2 +#define NUMS_CPU 4 +#define CPU_VIRTUAL_PLUG_IN(i) (opc_cpu_active(i)) +#endif + +struct opchain_cb { + unsigned int (*is_opc_task_t)(void *rq, void *t, int type); + int (*opc_binder_pass_t)(void *rq, void* cur, unsigned int dsize, unsigned int *data, int send); + void (*opc_task_switch_t)(unsigned int enqueue, int cpu, void *p, void *rq, unsigned long long clock); + int (*opc_get_claim_on_cpu_t)(int cpu, void *rq); + unsigned int (*opc_get_claims_t)(void **rqs); + int (*opc_select_path_t)(void **rqs, void *w_rq, void *t_rq, void *cur, void *t, int prev_cpu); + unsigned long (*opc_cpu_util_t)(unsigned long util, int cpu, void *t, void *rq, int op_path); + void (*opc_add_to_chain_t)(void *rq, void *t); + int (*opc_check_uxtop_cpu_t)(int uxtop, int cpu); +}; +#endif diff --git a/drivers/oneplus/include/linux/oem/param_rw.h b/drivers/oneplus/include/linux/oem/param_rw.h new file mode 100644 index 0000000000000000000000000000000000000000..cb3978255fca0cf66a1fded330666704292ffcd4 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/param_rw.h @@ -0,0 +1,36 @@ +#ifndef __PARAM_RW_H +#define __PARAM_RW_H + +#define PARAM_SID_LENGTH 1024 +#define DEFAULT_PARAM_DUMP_SIZE 64 + +typedef unsigned int uint32; + +typedef enum { + PARAM_SID_PRODUCT = 0, + PARAM_SID_CONFIG, + PARAM_SID_LCD, + PARAM_SID_TP, + PARAM_SID_TP_KPD, + PARAM_SID_CAMERA, + PARAM_SID_SENSORS, + PARAM_SID_BATTERY, + PARAM_SID_RTC, + PARAM_SID_CRASH_RECORD, + PARAM_SID_SALEINFO, + PARAM_SID_MISC, + PARAM_SID_DOWNLOAD, + PARAM_SID_PHONE_HISTORY, + NUM_PARAM_PLAINTEXT_SEGMENT, + + PARAM_SID_INVALID = -1 +} param_sid_index_t; + +int get_param_by_index_and_offset(uint32 sid_index, uint32 offset, void * buf, int length); +int set_param_by_index_and_offset(uint32 sid_index, uint32 offset, void * buf, int length); + +int add_restart_08_count(void); +int add_restart_other_count(void); +//end +#endif + diff --git a/drivers/oneplus/include/linux/oem/pccore.h b/drivers/oneplus/include/linux/oem/pccore.h new file mode 100644 index 0000000000000000000000000000000000000000..ab3b677a4e4b69f099075f8c4882f5cf10f547d4 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/pccore.h @@ -0,0 +1,99 @@ +#ifndef __INCLUDE_PCCORE__ +#define __INCLUDE_PCCORE__ + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#define PCC_TAG "pccore:" + +#define PCC_PARAMS 4 +#define NR_CLU 3 + +#define pcc_logv(fmt...) \ + do { \ + if (pcclog_lv < 1) \ + pr_info(PCC_TAG fmt); \ + } while (0) + +#define pcc_logi(fmt...) \ + do { \ + if (pcclog_lv < 2) \ + pr_info(PCC_TAG fmt); \ + } while (0) + +#define pcc_logw(fmt...) \ + do { \ + if (pcclog_lv < 3) \ + pr_warn(PCC_TAG fmt); \ + } while (0) + +#define pcc_loge(fmt...) pr_err(PCC_TAG fmt) +#define pcc_logd(fmt...) pr_debug(PCC_TAG fmt) + +static unsigned int cluster_pd[NR_CLU] = {17, 18, 20}; +static unsigned int cpufreq_pd_0[17] = { + 0,//300000 + 0,//403200 + 0,//518400 + 0,//614400 + 0,//691200 + 1,//787200 + 1,//883200 + 2,//979200 + 2,//1075200 + 2,//1171200 + 3,//1248800 + 3,//1344000 + 3,//1420800 + 3,//1516800 + 4,//1612800 + 5,//1708800 + 5//1804800 +}; + +static unsigned int cpufreq_pd_1[18] = { + 0,//710400 + 1,//825600 + 1,//940800 + 2,//1056000 + 2,//1171200 + 3,//1286400 + 3,//1382400 + 3,//1478400 + 4,//1574400 + 4,//1670400 + 4,//1766400 + 5,//1862400 + 6,//1958400 + 6,//2054400 + 7,//2150400 + 8,//2246400 + 8,//2342400 + 8 //2419200 +}; + +static unsigned int cpufreq_pd_2[20] = { + 0,// 844800 + 1,// 960000 + 1,//1075200 + 2,//1190400 + 2,//1305600 + 2,//1401600 + 3,//1516800 + 3,//1632000 + 3,//1747200 + 4,//1862400 + 4,//1977600 + 4,//2073600 + 5,//2169600 + 6,//2265600 + 6,//2361600 + 7,//2457600 + 8,//2553600 + 8,//2649600 + 8,//2745600 + 8//2841600 +}; + +#endif // __INCLUDE_PCCORE__ diff --git a/drivers/oneplus/include/linux/oem/power/oem_external_fg.h b/drivers/oneplus/include/linux/oem/power/oem_external_fg.h new file mode 100644 index 0000000000000000000000000000000000000000..a5603fbc0c088c43f7f6ef776ab70219755784c4 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/power/oem_external_fg.h @@ -0,0 +1,187 @@ +#ifndef __OEM_EXTERNAL_FG_H__ +#define __OEM_EXTERNAL_FG_H__ +#include +#include + +#define OP_SWARP_SUPPORTED + +enum { + ADAPTER_FW_UPDATE_NONE, + ADAPTER_FW_NEED_UPDATE, + ADAPTER_FW_UPDATE_SUCCESS, + ADAPTER_FW_UPDATE_FAIL, +}; + +enum mcu_action_mode { + ACTION_MODE_ENABLE, + ACTION_MODE_RESET_ACTIVE, + ACTION_MODE_RESET_SLEEP, + ACTION_MODE_SWITCH_UPGRADE, + ACTION_MODE_SWITCH_NORMAL, + ACTION_MODE_SWITCH_WARP, +}; + +struct op_adapter_chip { + int timer_delay; + bool tx_byte_over; + bool rx_byte_over; + bool rx_timeout; + unsigned long uart_tx_gpio; + unsigned long uart_rx_gpio; + char *adapter_firmware_data; + unsigned int adapter_fw_data_count; + unsigned int tx_invalid_val; + bool adapter_update_ing; + struct op_adapter_operations *vops; +}; +struct op_adapter_operations { + bool (*adapter_update)(struct op_adapter_chip *chip, + unsigned long tx_pin, unsigned long rx_pin); +}; + +struct external_battery_gauge { + int (*get_battery_mvolts)(void); + int (*get_battery_mvolts_2cell_max)(void); + int (*get_battery_mvolts_2cell_min)(void); + int (*get_battery_temperature)(void); + bool (*is_battery_present)(void); + bool (*is_battery_temp_within_range)(void); + bool (*is_battery_id_valid)(void); + bool (*is_usb_switch_on)(void); + int (*get_battery_status)(void); + int (*get_batt_remaining_capacity)(void); + int (*get_batt_full_chg_capacity)(void); + int (*get_batt_health)(void); + int (*get_batt_bq_soc)(void); + int (*monitor_for_recharging)(void); + int (*get_battery_soc)(void); + int (*get_average_current)(void); + int (*get_batt_cc)(void); + /* yangfangbiao@oneplus.cn, 2015/02/13 Add fcc interface */ + int (*get_batt_fcc)(void); + /* yangfangbiao@oneplus.cn, */ + /*2015/01/06 Modify for sync with KK charge standard */ + bool (*fast_chg_started)(void); + bool (*fast_chg_status_is_ok)(void); + bool (*fast_switch_to_normal)(void); + int (*set_switch_to_noraml_false)(void); + int (*set_fast_chg_allow)(bool enable); + void (*clean)(void); + bool (*get_fast_chg_allow)(void); + int (*fast_normal_to_warm)(void); + int (*set_normal_to_warm_false)(void); + int (*get_adapter_update)(void); + bool (*is_enhance_dash)(void); + bool (*get_fast_chg_ing)(void); + bool (*get_fast_low_temp_full)(void); + int (*set_low_temp_full_false)(void); + int (*set_allow_reading)(int enable); + int (*set_lcd_off_status)(int status); + int (*fast_chg_started_status)(bool status); + bool (*get_fastchg_firmware_already_updated)(void); + int (*get_device_type)(void); + /* david.liu@bsp, 20161025 Add BQ27411 dash charging */ + int (*wlchg_started_status)(bool status); + int (*get_time_to_full)(void); +}; + +enum fast_charger_type { + CHARGER_DEFAULT = 0, + CHARGER_DASH, + CHARGER_WARP, + CHARGER_CAR, + CHARGER_SWARP_2, + CHARGER_SWARP_1, + CHARGER_PD, + CHARGER_QC, + CHARGER_WIRELESS, + CHARGER_MAX, +}; + +struct notify_dash_event { + int (*notify_event)(void); + int (*op_contrl)(int status, bool check_power_ok); + int (*notify_dash_charger_present)(int true); + int (*update_dash_type)(enum fast_charger_type type); + int (*update_adapter_sid)(unsigned int sid); + int (*suspend_disable_nor_charge)(bool suspend); +}; + +struct notify_usb_enumeration_status { + int (*notify_usb_enumeration)(int status); +}; + +enum temp_region_type { + BATT_TEMP_COLD = 0, + BATT_TEMP_LITTLE_COLD, + BATT_TEMP_COOL, + BATT_TEMP_LITTLE_COOL, + BATT_TEMP_PRE_NORMAL, + BATT_TEMP_NORMAL, + BATT_TEMP_WARM, + BATT_TEMP_HOT, + BATT_TEMP_INVALID, +}; +enum ffc_step { + FFC_DEFAULT = 0, + FFC_FAST, + FFC_FAST_2, + FFC_TAPER, + FFC_NOR_TAPER, + FFC_WARM_TAPER, + FFC_IDLE, +}; + +enum batt_status_type { + BATT_STATUS_GOOD, + BATT_STATUS_BAD_TEMP, /* cold or hot */ + BATT_STATUS_BAD, + BATT_STATUS_BAD_VOL_DIFF, + BATT_STATUS_REMOVED, /* on v2.2 only */ + BATT_STATUS_INVALID_v1 = BATT_STATUS_REMOVED, + BATT_STATUS_INVALID +}; +void op_pm8998_regmap_register(struct regmap *regmap); +void op_pm8150_regmap_register(struct regmap *regmap); +void op_sdram_regmap_register(struct regmap *regmap); + +void regsister_notify_usb_enumeration_status( + struct notify_usb_enumeration_status *event); +void notify_dash_unplug_register(struct notify_dash_event *event); +void notify_dash_unplug_unregister(struct notify_dash_event *event); +void fastcharge_information_unregister(struct external_battery_gauge *fast_chg); +void fastcharge_information_register(struct external_battery_gauge *fast_chg); +void external_battery_gauge_register(struct external_battery_gauge *batt_gauge); +void external_battery_gauge_unregister( + struct external_battery_gauge *batt_gauge); +void bq27541_information_register(struct external_battery_gauge *fast_chg); +void bq27541_information_unregister(struct external_battery_gauge *fast_chg); +void exfg_information_register(struct external_battery_gauge *exfg); +bool get_extern_fg_regist_done(void); +bool get_extern_bq_present(void); +int get_prop_pre_shutdown_soc(void); +extern int get_charging_status(void); +extern int fuelgauge_battery_temp_region_get(void); +extern bool get_oem_charge_done_status(void); +extern int load_soc(void); +extern void backup_soc_ex(int soc); +extern void clean_backup_soc_ex(void); +/*add for dash adapter update*/ +extern void op_bus_vote(int disable); +extern int is_hw_support_n76e(void); +void op_warp_config_for_swarp(void); +void op_pd_config_switch_normal(void); +void op_switch_normal_set(void); +void clean_backup_soc_ex(void); +bool get_4p45_battery_support(void); +bool check_skin_thermal_high(void); +bool check_skin_thermal_warm(void); +bool check_skin_thermal_medium(void); +bool check_call_on_status(void); +bool check_video_call_on_status(void); +bool check_lcd_on_status(void); +void update_fast_switch_off_status(void); +void update_disconnect_pd_status(bool en); +int opchg_mcu_action(enum mcu_action_mode mode); +int op_get_cool_down_value(void); +#endif diff --git a/drivers/oneplus/include/linux/oem/power/op_charge.h b/drivers/oneplus/include/linux/oem/power/op_charge.h new file mode 100644 index 0000000000000000000000000000000000000000..b9a5ba0048b1d8ae2b47cdc93cf128c7895e006a --- /dev/null +++ b/drivers/oneplus/include/linux/oem/power/op_charge.h @@ -0,0 +1,691 @@ +/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#ifndef __OP_CHARGE_H__ +#define __OP_CHARGE_H__ + +int con_temp_30k[] = { + -40, + -39, + -38, + -37, + -36, + -35, + -34, + -33, + -32, + -31, + -30, + -29, + -28, + -27, + -26, + -25, + -24, + -23, + -22, + -21, + -20, + -19, + -18, + -17, + -16, + -15, + -14, + -13, + -12, + -11, + -10, + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, +}; + +int con_volt_30k[] = { + 1788, + 1787, + 1786, + 1785, + 1784, + 1783, + 1781, + 1780, + 1779, + 1777, + 1776, + 1774, + 1772, + 1771, + 1769, + 1766, + 1764, + 1762, + 1760, + 1757, + 1754, + 1751, + 1748, + 1745, + 1742, + 1738, + 1735, + 1730, + 1727, + 1723, + 1718, + 1713, + 1708, + 1703, + 1697, + 1692, + 1687, + 1680, + 1674, + 1667, + 1660, + 1653, + 1646, + 1638, + 1630, + 1621, + 1613, + 1604, + 1594, + 1585, + 1575, + 1564, + 1554, + 1543, + 1531, + 1520, + 1508, + 1495, + 1483, + 1470, + 1456, + 1443, + 1429, + 1414, + 1400, + 1385, + 1369, + 1354, + 1338, + 1322, + 1306, + 1289, + 1272, + 1255, + 1238, + 1220, + 1203, + 1185, + 1167, + 1149, + 1131, + 1112, + 1094, + 1075, + 1057, + 1038, + 1020, + 1001, + 983, + 964, + 945, + 927, + 909, + 890, + 872, + 854, + 836, + 818, + 801, + 783, + 766, + 749, + 732, + 715, + 699, + 683, + 667, + 651, + 635, + 620, + 605, + 590, + 576, + 561, + 547, + 533, + 520, + 507, + 494, + 481, + 469, + 457, + 445, + 433, + 422, + 411, + 400, + 389, + 379, + 369, + 359, + 350, + 340, + 331, + 323, + 314, + 305, + 297, + 289, + 281, + 274, + 267, + 259, + 252, + 246, + 239, + 233, + 226, + 220, + 214, + 209, + 203, + 198, + 192, + 187, + 182, + 177, + 173, + 168, + 164, + 159, + 155, + 151, + 147, + 143, + 140, +}; + +int con_volt[] = { + 1721, + 1716, + 1710, + 1704, + 1697, + 1690, + 1683, + 1675, + 1667, + 1658, + 1649, + 1640, + 1630, + 1620, + 1609, + 1597, + 1586, + 1573, + 1560, + 1547, + 1533, + 1519, + 1504, + 1488, + 1472, + 1456, + 1438, + 1421, + 1403, + 1384, + 1365, + 1346, + 1326, + 1305, + 1285, + 1263, + 1242, + 1220, + 1198, + 1176, + 1153, + 1130, + 1107, + 1084, + 1061, + 1038, + 1014, + 991, + 967, + 944, + 921, + 898, + 875, + 852, + 829, + 807, + 785, + 763, + 741, + 720, + 699, + 678, + 658, + 638, + 619, + 600, + 581, + 563, + 545, + 527, + 510, + 494, + 477, + 462, + 446, + 432, + 417, + 403, + 389, + 376, + 363, + 351, + 339, + 327, + 316, + 305, + 295, + 284, + 274, + 265, + 256, + 247, + 238, + 230, + 222, + 214, + 207, + 200, + 193, + 186, + 180, + 173, + 167, + 162, + 156, + 151, + 145, + 140, + 136, + 131, + 127, + 122, + 118, + 114, + 110, + 106, + 103, + 99, + 96, + 93, + 90, + 87, + 84, + 81, + 79, + 76, + 73, + 71, + 69, + 67, + 64, + 62, + 60, + 58, + 57, + 55, + 53, + 51, + 50, + 48, + 47, + 45, + 44, + 42, + 41, + 40, + 39, + 38, + 36, + 35, + 34, + 33, + 32, + 31, + 30, + 29, + 29, + 28, + 27, + 26, + 25, + 25, + 24, + 23, + 23, + 22, +}; + +int con_temp[] = { + -40, + -39, + -38, + -37, + -36, + -35, + -34, + -33, + -32, + -31, + -30, + -29, + -28, + -27, + -26, + -25, + -24, + -23, + -22, + -21, + -20, + -19, + -18, + -17, + -16, + -15, + -14, + -13, + -12, + -11, + -10, + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, +}; +#endif /* __OP_CHARGE_H__ */ diff --git a/drivers/oneplus/include/linux/oem/power/op_wlc_helper.h b/drivers/oneplus/include/linux/oem/power/op_wlc_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..6901279a66f655a8ea165e153c0aeaa0e86f5b7a --- /dev/null +++ b/drivers/oneplus/include/linux/oem/power/op_wlc_helper.h @@ -0,0 +1,31 @@ +#ifndef _OP_WLC_HELPER_H_ +#define _OP_WLC_HELPER_H_ +#include +#include +#include + +#define chg_debug(fmt, ...) \ + printk(KERN_NOTICE "[WLCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define chg_err(fmt, ...) \ + printk(KERN_ERR "[WLCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define chg_info(fmt, ...) \ + printk(KERN_INFO "[WLCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define WLCHG_FTM_TEST_RX_ERR BIT(0) +#define WLCHG_FTM_TEST_CP1_ERR BIT(1) +#define WLCHG_FTM_TEST_CP2_ERR BIT(2) + +enum WLCHG_MSG_TYPE { + WLCHG_MSG_CHG_INFO, + WLCHG_MSG_CMD_RESULT, + WLCHG_MSG_CMD_ERR, + WLCHG_MSG_HEARTBEAT, +}; + +extern bool wlchg_wireless_charge_start(void); +extern int p922x_wireless_get_vout(void); +bool typec_is_otg_mode(void); +int switch_to_otg_mode(bool enable); +#endif diff --git a/drivers/oneplus/include/linux/oem/project_info.h b/drivers/oneplus/include/linux/oem/project_info.h new file mode 100644 index 0000000000000000000000000000000000000000..541524d5f87aa7393b6a374fdfb0a240d50b17f6 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/project_info.h @@ -0,0 +1,107 @@ +#ifndef _PROJECT_INFO_H_ +#define _PROJECT_INFO_H_ 1 +typedef __u32 uint32; +typedef __u8 uint8; + +/*******SECURE_BOOTn = 0x00786078+ 0x4*n, n=[1..14]******/ +#define SECURE_BOOT_BASE 0x00786078 +#define SECURE_BOOT1 (SECURE_BOOT_BASE + 0x4*1) +#define BUF_SIZE 64 + +#define SMEM_DUMP_INFO 135 +#define SMEM_PROJECT_INFO 136 +#define NONDEFINE -1 + +#include +#include +extern unsigned long totalram_pages; +extern void *panic_info; + +struct project_info { + char project_name[8]; + char project_codename[20]; + char reservename[12]; + uint32 prj_version; + uint32 hw_version; + uint32 rf_v1; + uint32 rf_v2; + uint32 rf_v3; + uint32 uart_boot_mode; + uint32 platform_id; + uint32 ddr_manufacture_info; + uint32 ddr_row; + uint32 ddr_column; + uint32 ddr_fw_version; + uint32 ddr_reserve_info; + uint32 reserve01; /*reserve for feture use*/ + uint32 reserve02; + uint32 reserve03; + uint32 reserve04; + uint32 reserve05; + uint32 reserve06; + uint32 reserve07; + uint32 reserve08; + uint32 reserve09; +}; + +#define DUMP_REASON_SIZE 256 + +struct dump_info{ + char dump_reason[DUMP_REASON_SIZE]; //dump reason +}; + +struct component_info { + char *version; + char *manufacture; +}; + +enum{ + HW_VERSION__UNKNOWN, + HW_VERSION__11 = 11,//all EVB + HW_VERSION__12, //T0 +}; + +enum COMPONENT_TYPE { + DDR, + EMMC, + F_CAMERA, + SECOND_F_CAMERA, + R_CAMERA, + SECOND_R_CAMERA, + THIRD_R_CAMERA, + FORTH_R_CAMERA, + R_MODULE, + F_MODULE, + R_OIS, + SECOND_R_OIS, + TP, + LCD, + WCN, + I_SENSOR, + G_SENSOR, + M_SENSOR, + GYRO, + BACKLIGHT, + MAINBOARD, + /*Add new component here*/ + FINGERPRINTS, + TOUCH_KEY, + UFS, + ABOARD, + NFC, + FAST_CHARGE, + WIRELESS_CHARGE, + CPU, + RF_VERSION, + COMPONENT_MAX, +}; + +char *parse_function_builtin_return_address(unsigned long function_address); +int push_component_info(enum COMPONENT_TYPE type, + char *version, char *manufacture); +int reset_component_info(enum COMPONENT_TYPE type); +uint32 get_hw_version(void); +void save_dump_reason_to_smem(char *info, char *function_name); + + +#endif diff --git a/drivers/oneplus/include/linux/oem/ratp.h b/drivers/oneplus/include/linux/oem/ratp.h new file mode 100644 index 0000000000000000000000000000000000000000..a84c737e926d7a8adc651aa58eaf23d12ee82963 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/ratp.h @@ -0,0 +1,14 @@ +#ifndef __RATP_H__ +#define __RATP_H__ + +#ifdef CONFIG_RATP +extern bool is_ratp_enable(void); +extern bool is_allowmost_enable(void); +extern bool is_gmod_enable(void); +#else +static inline bool is_ratp_enable(void) { return false; } +static inline bool is_allowmost_enable(void) { return false; } +static inline bool is_gmod_enable(void) { return false; } +#endif + +#endif diff --git a/drivers/oneplus/include/linux/oem/tpd.h b/drivers/oneplus/include/linux/oem/tpd.h new file mode 100644 index 0000000000000000000000000000000000000000..74f4a572522dc29d153545ff59351c4a24ae9038 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/tpd.h @@ -0,0 +1,74 @@ +#ifndef __TPD_H__ +#define __TPD_H__ + +#include +#include + +#define TPD_CLUSTER_0 (1 << 0) +#define TPD_CLUSTER_1 (1 << 1) +#define TPD_CLUSTER_2 (1 << 2) + +#define TPD_TYPE_S TPD_CLUSTER_0 /* Silver only */ +#define TPD_TYPE_G TPD_CLUSTER_1 /* gold only */ +#define TPD_TYPE_GS (TPD_CLUSTER_1 | TPD_CLUSTER_0) /* sliver + gold */ +#define TPD_TYPE_P TPD_CLUSTER_2 /* gold+ only */ +#define TPD_TYPE_PS (TPD_CLUSTER_2 | TPD_CLUSTER_0) /* gold+ + silver */ +#define TPD_TYPE_PG (TPD_CLUSTER_2 | TPD_CLUSTER_1) /* gold+ + gold */ +#define TPD_TYPE_PGS (TPD_CLUSTER_2 | TPD_CLUSTER_1 | TPD_CLUSTER_0) /* all */ + +#define MAX_THREAD_INPUT 6 +#define MAX_MISS_LIST 20 + +#define TPD_TAG "TPD_DEBUG: " + +#define tpd_logv(fmt...) \ + do { \ + if (tpd_log_lv < 1) \ + pr_info(TPD_TAG fmt); \ + } while (0) + +#define tpd_logi(fmt...) \ + do { \ + if (tpd_log_lv < 2) \ + pr_info(TPD_TAG fmt); \ + } while (0) + +#define tpd_logw(fmt...) \ + do { \ + if (tpd_log_lv < 3) \ + pr_warn(TPD_TAG fmt); \ + } while (0) + +#define tpd_loge(fmt...) pr_err(TPD_TAG fmt) +#define tpd_logd(fmt...) pr_debug(TPD_TAG fmt) + +enum dynamic_tpd_type { + TPD_GROUP_MEDIAPROVIDER = 0, + + TPD_GROUP_MAX +}; + +#ifdef CONFIG_TPD +extern bool is_tpd_enable(void); +extern int tpd_suggested(struct task_struct* tsk, int min_idx, int mid_idx, + int max_idx, int request_cpu); +extern void tpd_mask(struct task_struct* tsk, int min_idx, int mid_idx, int max_idx, + cpumask_t *request, int nrcpu); +extern bool tpd_check(struct task_struct *tsk, int dest_cpu, int min_idx, int mid_idx, int max_idx); +extern bool is_dynamic_tpd_task(struct task_struct *tsk); +static inline bool is_tpd_task(struct task_struct *tsk) { return tsk ? (tsk->tpd != 0) : false; } +extern void tpd_tglist_del(struct task_struct *tsk); +#else +static inline bool is_tpd_enable(void) { return false; } +static inline int tpd_suggested(struct task_struct* tsk, int min_idx, int mid_idx, + int max_idx, int request_cpu) { return request_cpu; } +static inline void tpd_mask(struct task_struct* tsk, int min_idx, int mid_idx, int max_idx, + cpumask_t *request, int nrcpu) {} +static inline bool tpd_check(struct task_struct *tsk, int dest_cpu, int min_idx, + int mid_idx, int max_idx) { return false; } +static inline bool is_dynamic_tpd_task(struct task_struct *tsk) { return false; } +static inline bool is_tpd_task(struct task_struct *tsk) { return false; } +static inline void tpd_tglist_del(struct task_struct *tsk) {}; +#endif + +#endif diff --git a/drivers/oneplus/include/linux/oem/tpp.h b/drivers/oneplus/include/linux/oem/tpp.h new file mode 100644 index 0000000000000000000000000000000000000000..c44cb34f4d1a314fd3d78d9fe960ac7f53c04d8a --- /dev/null +++ b/drivers/oneplus/include/linux/oem/tpp.h @@ -0,0 +1,99 @@ +#ifndef __INCLUDE_TPP__ +#define __INCLUDE_TPP__ + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#include + +#define TPP_CTL_NODE "tpp_ctl" +#define TPP_TAG "tpp_monitor: " + +/* log info */ +#define tpp_logv(fmt...) \ + do { \ + if (tpp_log_lv < 1) \ + pr_info(TPP_TAG fmt); \ + } while (0) + +#define tpp_logi(fmt...) \ + do { \ + if (tpp_log_lv < 2) \ + pr_info(TPP_TAG fmt); \ + } while (0) + +#define tpp_logw(fmt...) \ + do { \ + if (tpp_log_lv < 3) \ + pr_warn(TPP_TAG fmt); \ + } while (0) + +#define tpp_loge(fmt...) pr_err(TPP_TAG fmt) +#define tpp_logd(fmt...) pr_debug(TPP_TAG fmt) + +#define TPP_NR_CPUS (8) +#define TPP_TASK_REPORT_SIZE 360000 +#define TPP_CPU_SELECT_MAX_REPORT_SIZE 3600000 + +/* tpp monitor log */ +enum tpp_cpu_select_tags { + TPP_CPU_SELECT_TPP_TASK_ID, + TPP_CPU_SELECT_CPU, + TPP_CPU_SELECT_MONITOR_SIZE, +}; + +enum tpp_tasks { + TPP_OTHER_THREAD_ID = 0, + TPP_UNITY_WORKER_THREAD_ID = 1, + TPP_TASK_MONITOR_SIZE, +}; + +enum tpp_strategy { + TPP_STRATEGY_ORIG, + TPP_UNITY_WORKER_THREAD_MIDDLE_CORE, + TPP_STRATEGY_SIZE, +}; + +enum tpp_cpu_selection_state { + TPP_CPU_NOT_SELECT_YET = -1, +}; + +enum tpp_flags { + TPP_ID_CFS_RQ, + TPP_ID_UNITY_WORKER_THREAD, +}; + +#define TPP_CFS_RQ (1 << TPP_ID_CFS_RQ) +#define TPP_UNITY_WORKER_THREAD (1 << TPP_ID_UNITY_WORKER_THREAD) + +struct tpp_cpu_select_sample { + int data[TPP_CPU_SELECT_MAX_REPORT_SIZE][TPP_CPU_SELECT_MONITOR_SIZE]; +}; + +struct tpp_cpu_select_monitor_struct { + struct tpp_cpu_select_sample *buf; + atomic_t index; +}; + +enum tpp_task_tags_enum { + TPP_TASK_TAG_UTIL, + TPP_TASK_TAG_CPU_ORIG, + TPP_TASK_TAG_CPU, + TPP_TASK_TAG_WORK_THREAD, + TPP_TASK_COLUMN, +}; + +struct tpp_task_sample { + long long data[TPP_TASK_REPORT_SIZE][TPP_TASK_MONITOR_SIZE * TPP_TASK_COLUMN]; +}; + +struct tpp_task_monitor_struct { + struct tpp_task_sample *buf; + atomic_t index[TPP_TASK_MONITOR_SIZE]; +}; +extern void tpp_tagging(struct task_struct *p); +extern void tpp_dequeue(int cpu, struct task_struct *p); +extern void tpp_enqueue(int cpu, struct task_struct *p); +extern int tpp_find_cpu(struct task_struct *p, int cpu_orig); +#endif // __INCLUDE_TPP__ diff --git a/drivers/oneplus/input/Kconfig b/drivers/oneplus/input/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..3cefa368c8bc9088b06839d4c9d8b133df1f2a19 --- /dev/null +++ b/drivers/oneplus/input/Kconfig @@ -0,0 +1,8 @@ +# oem device deriver +source "drivers/oneplus/input/touchscreen/Kconfig" +source "drivers/oneplus/input/touchscreen_himax/Kconfig" +source "drivers/oneplus/input/fingerprint/Kconfig" + +config OP_HIMAX + default n + bool "Enable/Disable the touchscreen_himax driver" diff --git a/drivers/oneplus/input/Makefile b/drivers/oneplus/input/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..e31f5c3830480bf84835d005fbea0e6f6d3a9195 --- /dev/null +++ b/drivers/oneplus/input/Makefile @@ -0,0 +1,9 @@ +# oem device deriver +# +#obj-$(CONFIG_OP_TOUCHSCREEN) += touchscreen/ +ifeq ($(CONFIG_OP_HIMAX),y) +obj-$(CONFIG_OP_HIMAX) += touchscreen_himax/ +else +obj-$(CONFIG_OP_TOUCHSCREEN) += touchscreen/ +endif +obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/ diff --git a/drivers/oneplus/input/fingerprint/Kconfig b/drivers/oneplus/input/fingerprint/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..9a505aa689b47455f28b921018632cf6e54ee9d9 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/Kconfig @@ -0,0 +1,30 @@ +menuconfig INPUT_FINGERPRINT + bool "Fingerprint" + default y + help + Say Y here, and a list of supported fingerprint will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_FINGERPRINT + +config FINGERPRINT_DETECT + tristate "fingerprint detect support" + depends on SPI_MASTER + + +config FINGERPRINT_GOODIX + tristate "goodix fingerprint sensor support" + depends on SPI_MASTER + + +config MSM_QBT1000 + bool "QBT1000 Ultrasonic Fingerprint Sensor" + help + This driver provides services for configuring the fingerprint + sensor hardware and for communicating with the trusted app which + uses it. It enables clocks and provides commands for loading + trusted apps, unloading them and marshalling buffers to the + trusted fingerprint app. +endif diff --git a/drivers/oneplus/input/fingerprint/Makefile b/drivers/oneplus/input/fingerprint/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3b6ebd1ac501071313a411ce4ad70fba7984289f --- /dev/null +++ b/drivers/oneplus/input/fingerprint/Makefile @@ -0,0 +1,3 @@ +#fingerprint_detect should before fpc1022 +obj-$(CONFIG_FINGERPRINT_DETECT) += fingerprint_detect/ +obj-$(CONFIG_FINGERPRINT_GOODIX) += goodix/ diff --git a/drivers/oneplus/input/fingerprint/fingerprint_detect/Makefile b/drivers/oneplus/input/fingerprint/fingerprint_detect/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c9846540e94f29a3afea615b119a310c9a127ff8 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/fingerprint_detect/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FINGERPRINT_DETECT) += fingerprint_detect.o \ No newline at end of file diff --git a/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.c b/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.c new file mode 100755 index 0000000000000000000000000000000000000000..39a7c7589e84a62d0fb730b0aff608ab828cbaa6 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.c @@ -0,0 +1,227 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fingerprint_detect.h" +int fp_version; +int fp_dtsi_product = 0; + +static int fingerprint_detect_request_named_gpio( + struct fingerprint_detect_data *fp_detect, + const char *label, int *gpio) +{ + struct device *dev = fp_detect->dev; + struct device_node *np = dev->of_node; + int rc = of_get_named_gpio(np, label, 0); + + if (rc < 0) { + dev_err(dev, "failed to get '%s'\n", label); + *gpio = rc; + return rc; + } + *gpio = rc; + rc = devm_gpio_request(dev, *gpio, label); + if (rc) { + dev_err(dev, "failed to request gpio %d\n", *gpio); + return rc; + } + dev_info(dev, "%s - gpio: %d\n", label, *gpio); + return 0; +} + +static ssize_t sensor_version_get(struct device *device, + struct device_attribute *attribute, + char *buffer) +{ + struct fingerprint_detect_data *fp_detect = dev_get_drvdata(device); + + return scnprintf(buffer, PAGE_SIZE, "%i\n", fp_detect->sensor_version); +} + +static ssize_t sensor_version_set(struct device *device, + struct device_attribute *attribute, + const char *buffer, size_t count) +{ + int ret; + struct fingerprint_detect_data *fp_detect = dev_get_drvdata(device); + if (count < 32) + { + ret = kstrtoint(buffer, 10, &(fp_detect->sensor_version)); + if (ret) { + printk("%s: kstrtoint error return %d\n", __func__, ret); + return -1; + } + } else { + pr_info("%s write a wrong number!!!\n", __func__); + } + return count; +} + +static DEVICE_ATTR(sensor_version, S_IRUSR|S_IWUSR, sensor_version_get, sensor_version_set); + +static struct attribute *attributes[] = { + &dev_attr_sensor_version.attr, + NULL +}; + +static const struct attribute_group attribute_group = { + .attrs = attributes, +}; + +int fp_pinctrl_init(struct fingerprint_detect_data *fp_dev) +{ + int ret = 0; + struct device *dev = fp_dev->dev; + + fp_dev->fp_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(fp_dev->fp_pinctrl)) { + dev_err(dev, "Target does not use pinctrl\n"); + ret = PTR_ERR(fp_dev->fp_pinctrl); + goto err; + } + + fp_dev->id_state_init = + pinctrl_lookup_state(fp_dev->fp_pinctrl, "fp_id_init"); + if (IS_ERR_OR_NULL(fp_dev->id_state_init)) { + dev_err(dev, "Cannot get id active pinstate\n"); + ret = PTR_ERR(fp_dev->id_state_init); + goto err; + } + + ret = pinctrl_select_state(fp_dev->fp_pinctrl, fp_dev->id_state_init); + if (ret) { + dev_err(dev, "can not set %s pins\n", "fp_id_init"); + goto err; + } + + return ret; + +err: + fp_dev->fp_pinctrl = NULL; + fp_dev->id_state_init = NULL; + return ret; +} + +static int fingerprint_detect_probe(struct platform_device *pdev) +{ + int id0 = 0;// id1 = 0; + int rc = 0; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + struct fingerprint_detect_data *fp_detect = + devm_kzalloc(dev, sizeof(*fp_detect), + GFP_KERNEL); + if (!fp_detect) { + dev_err(dev, + "failed to allocate memory for struct fingerprint_detect_data\n"); + rc = -ENOMEM; + goto exit; + } + + pr_info("%s\n", __func__); + + fp_detect->dev = dev; + dev_set_drvdata(dev, fp_detect); + + if (!np) { + dev_err(dev, "no of node found\n"); + rc = -EINVAL; + goto exit; + } + + rc = fp_pinctrl_init(fp_detect); + if (rc) + goto exit; + + rc = fingerprint_detect_request_named_gpio(fp_detect, "fp-gpio-id0", &fp_detect->id0_gpio); + if (gpio_is_valid(fp_detect->id0_gpio)) { + dev_err(dev, "%s: gpio_is_valid(fp_detect->id0_gpio=%d)\n", + __func__, fp_detect->id0_gpio); + } +/* + rc = fingerprint_detect_request_named_gpio(fp_detect,"fp-gpio-id1", &fp_detect->id1_gpio); + if (gpio_is_valid(fp_detect->id1_gpio)) { + dev_err(dev, "%s: gpio_is_valid(fp_detect->id1_gpio=%d)\n", + __func__, fp_detect->id1_gpio); + } +*/ + rc = sysfs_create_group(&dev->kobj, &attribute_group); + if (rc) { + dev_err(dev, "could not create sysfs\n"); + goto exit; + } + + id0 = gpio_get_value(fp_detect->id0_gpio); +// id1 = gpio_get_value(fp_detect->id1_gpio); + + /** + * ID0(GPIO90) ID1(GPIO21) + * goodix9508 1 0 + * sileadgsl7000 0 1 + * qualcomm8*8 0 0 + * qualcomm4*9 1 1 + */ + + pr_info("%s: %d\n", __func__, id0); + if (id0) { + push_component_info(FINGERPRINTS, + "goodix9608", "goodix"); + fp_detect->sensor_version = 0x07; + } else if (!id0) { + push_component_info(FINGERPRINTS, + "goodix9608", "goodix"); + fp_detect->sensor_version = 0x9638; + }/* else if (!id0 && !id1) { + push_component_info(FINGERPRINTS, + "qbt1000", "qualcomm"); + fp_detect->sensor_version = 0x06; + } +*/ + + if (of_property_read_bool(fp_detect->dev->of_node, "oneplus,19805")){ + fp_dtsi_product = 19805; + if(id0){ + fp_detect->sensor_version = 0x9678; + }else{ + fp_detect->sensor_version = 0x9638; + } + } + + if (of_property_read_bool(fp_detect->dev->of_node, "oneplus,20801")){ + fp_dtsi_product = 20801; + fp_detect->sensor_version = 0x04; + } + + fp_version = fp_detect->sensor_version; + dev_info(dev, "%s: success\n", __func__); +exit: + return rc; +} + + +static const struct of_device_id fingerprint_detect_of_match[] = { + { .compatible = "oneplus,fpdetect", }, + {} +}; +MODULE_DEVICE_TABLE(op, fingerprint_detect_of_match); + +static struct platform_driver fingerprint_detect_driver = { + .driver = { + .name = "fingerprint_detect", + .owner = THIS_MODULE, + .of_match_table = fingerprint_detect_of_match, + }, + .probe = fingerprint_detect_probe, +}; +module_platform_driver(fingerprint_detect_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("yale liu"); +MODULE_DESCRIPTION("Fingerprint detect device driver."); diff --git a/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.h b/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.h new file mode 100755 index 0000000000000000000000000000000000000000..7ff5f8ecb3953e4ccee4a0bc07dac7778344f9c9 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/fingerprint_detect/fingerprint_detect.h @@ -0,0 +1,15 @@ +#ifndef __FINGERPRINT_DETETC_H_ +#define __FINGERPRINT_DETETC_H_ + +struct fingerprint_detect_data { + struct device *dev; + int id0_gpio; +// int id1_gpio; + struct pinctrl *fp_pinctrl; + struct pinctrl_state *id_state_init; + int sensor_version; +}; +extern int fp_version; +extern int fp_dtsi_product; +#endif + diff --git a/drivers/oneplus/input/fingerprint/goodix/Makefile b/drivers/oneplus/input/fingerprint/goodix/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9faa4a64360412ae3c2684a04a892832da2a617e --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FINGERPRINT_GOODIX) += gf_spi.o platform.o netlink.o diff --git a/drivers/oneplus/input/fingerprint/goodix/gf_spi.c b/drivers/oneplus/input/fingerprint/goodix/gf_spi.c new file mode 100755 index 0000000000000000000000000000000000000000..6b58652f916648429ee958a939c6614a4b735824 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/gf_spi.c @@ -0,0 +1,1156 @@ +/* + * TEE driver for goodix fingerprint sensor + * Copyright (C) 2016 Goodix + * + * 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. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#define CONFIG_MSM_RDM_NOTIFY +#undef CONFIG_FB + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include "gf_spi.h" + +#if defined(USE_SPI_BUS) +#include +#include +#elif defined(USE_PLATFORM_BUS) +#include +#endif + +#include "../fingerprint_detect/fingerprint_detect.h" + +#define VER_MAJOR 1 +#define VER_MINOR 2 +#define PATCH_LEVEL 8 + +#define WAKELOCK_HOLD_TIME 500 /* in ms */ + +#define GF_SPIDEV_NAME "goodix,fingerprint" +/*device name after register in charater*/ +#define GF_DEV_NAME "goodix_fp" +#define GF_INPUT_NAME "gf_input" /*"goodix_fp" */ + +#define CHRD_DRIVER_NAME "goodix_fp_spi" +#define CLASS_NAME "goodix_fp" + +#define N_SPI_MINORS 32 /* ... up to 256 */ +static int SPIDEV_MAJOR; + +static DECLARE_BITMAP(minors, N_SPI_MINORS); +static LIST_HEAD(device_list); +static DEFINE_MUTEX(device_list_lock); +static struct wakeup_source *fp_wakelock; +static struct gf_dev gf; +extern struct drm_panel *lcd_active_panel; +struct gf_key_map maps[] = { + { EV_KEY, GF_KEY_INPUT_HOME }, + { EV_KEY, GF_KEY_INPUT_MENU }, + { EV_KEY, GF_KEY_INPUT_BACK }, + { EV_KEY, GF_KEY_INPUT_POWER }, +#if defined(SUPPORT_NAV_EVENT) + { EV_KEY, GF_NAV_INPUT_UP }, + { EV_KEY, GF_NAV_INPUT_DOWN }, + { EV_KEY, GF_NAV_INPUT_RIGHT }, + { EV_KEY, GF_NAV_INPUT_LEFT }, + { EV_KEY, GF_NAV_INPUT_LONG_PRESS }, + { EV_KEY, GF_NAV_INPUT_F2}, +#endif +}; + +static void gf_enable_irq(struct gf_dev *gf_dev) +{ + if (gf_dev->irq_enabled) { + pr_warn("IRQ has been enabled.\n"); + } else { + enable_irq(gf_dev->irq); + gf_dev->irq_enabled = 1; + } +} + +static void gf_disable_irq(struct gf_dev *gf_dev) +{ + if (gf_dev->irq_enabled) { + gf_dev->irq_enabled = 0; + disable_irq(gf_dev->irq); + } else { + pr_warn("IRQ has been disabled.\n"); + } +} + +#ifdef AP_CONTROL_CLK +static long spi_clk_max_rate(struct clk *clk, unsigned long rate) +{ + long lowest_available, nearest_low, step_size, cur; + long step_direction = -1; + long guess = rate; + int max_steps = 10; + + cur = clk_round_rate(clk, rate); + if (cur == rate) + return rate; + + /* if we got here then: cur > rate */ + lowest_available = clk_round_rate(clk, 0); + if (lowest_available > rate) + return -EINVAL; + + step_size = (rate - lowest_available) >> 1; + nearest_low = lowest_available; + + while (max_steps-- && step_size) { + guess += step_size * step_direction; + cur = clk_round_rate(clk, guess); + + if ((cur < rate) && (cur > nearest_low)) + nearest_low = cur; + /* + * if we stepped too far, then start stepping in the other + * direction with half the step size + */ + if (((cur > rate) && (step_direction > 0)) + || ((cur < rate) && (step_direction < 0))) { + step_direction = -step_direction; + step_size >>= 1; + } + } + return nearest_low; +} + +static void spi_clock_set(struct gf_dev *gf_dev, int speed) +{ + long rate; + int rc; + + rate = spi_clk_max_rate(gf_dev->core_clk, speed); + if (rate < 0) { + pr_info("%s: no match found for requested clock frequency:%d", + __func__, speed); + return; + } + + rc = clk_set_rate(gf_dev->core_clk, rate); +} + +static int gfspi_ioctl_clk_init(struct gf_dev *data) +{ + pr_debug("%s: enter\n", __func__); + + data->clk_enabled = 0; + data->core_clk = clk_get(&data->spi->dev, "core_clk"); + if (IS_ERR_OR_NULL(data->core_clk)) { + pr_err("%s: fail to get core_clk\n", __func__); + return -EPERM; + } + data->iface_clk = clk_get(&data->spi->dev, "iface_clk"); + if (IS_ERR_OR_NULL(data->iface_clk)) { + pr_err("%s: fail to get iface_clk\n", __func__); + clk_put(data->core_clk); + data->core_clk = NULL; + return -ENOENT; + } + return 0; +} + +static int gfspi_ioctl_clk_enable(struct gf_dev *data) +{ + int err; + + pr_debug("%s: enter\n", __func__); + + if (data->clk_enabled) + return 0; + + err = clk_prepare_enable(data->core_clk); + if (err) { + pr_err("%s: fail to enable core_clk\n", __func__); + return -EPERM; + } + + err = clk_prepare_enable(data->iface_clk); + if (err) { + pr_err("%s: fail to enable iface_clk\n", __func__); + clk_disable_unprepare(data->core_clk); + return -ENOENT; + } + + data->clk_enabled = 1; + + return 0; +} + +static int gfspi_ioctl_clk_disable(struct gf_dev *data) +{ + pr_debug("%s: enter\n", __func__); + + if (!data->clk_enabled) + return 0; + + clk_disable_unprepare(data->core_clk); + clk_disable_unprepare(data->iface_clk); + data->clk_enabled = 0; + + return 0; +} + +static int gfspi_ioctl_clk_uninit(struct gf_dev *data) +{ + pr_debug("%s: enter\n", __func__); + + if (data->clk_enabled) + gfspi_ioctl_clk_disable(data); + + if (!IS_ERR_OR_NULL(data->core_clk)) { + clk_put(data->core_clk); + data->core_clk = NULL; + } + + if (!IS_ERR_OR_NULL(data->iface_clk)) { + clk_put(data->iface_clk); + data->iface_clk = NULL; + } + + return 0; +} +#endif + +static void nav_event_input(struct gf_dev *gf_dev, gf_nav_event_t nav_event) +{ + uint32_t nav_input = 0; + + switch (nav_event) { + case GF_NAV_FINGER_DOWN: + pr_debug("%s nav finger down\n", __func__); + break; + + case GF_NAV_FINGER_UP: + pr_debug("%s nav finger up\n", __func__); + break; + + case GF_NAV_DOWN: + nav_input = GF_NAV_INPUT_DOWN; + pr_debug("%s nav down\n", __func__); + break; + + case GF_NAV_UP: + nav_input = GF_NAV_INPUT_UP; + pr_debug("%s nav up\n", __func__); + break; + + case GF_NAV_LEFT: + nav_input = GF_NAV_INPUT_LEFT; + pr_debug("%s nav left\n", __func__); + break; + + case GF_NAV_RIGHT: + nav_input = GF_NAV_INPUT_RIGHT; + pr_debug("%s nav right\n", __func__); + break; + + case GF_NAV_CLICK: + nav_input = GF_NAV_INPUT_CLICK; + pr_debug("%s nav click\n", __func__); + break; + + case GF_NAV_HEAVY: + nav_input = GF_NAV_INPUT_HEAVY; + pr_debug("%s nav heavy\n", __func__); + break; + + case GF_NAV_LONG_PRESS: + nav_input = GF_NAV_INPUT_LONG_PRESS; + pr_debug("%s nav long press\n", __func__); + break; + + case GF_NAV_DOUBLE_CLICK: + nav_input = GF_NAV_INPUT_DOUBLE_CLICK; + pr_debug("%s nav double click\n", __func__); + break; + case GF_NAV_F2: + nav_input = GF_NAV_INPUT_F2; + pr_debug("%s nav f2\n", __func__); + break; + default: + pr_warn("%s unknown nav event: %d\n", __func__, nav_event); + break; + } + + if ((nav_event != GF_NAV_FINGER_DOWN) && (nav_event != GF_NAV_FINGER_UP)) { + input_report_key(gf_dev->input, nav_input, 1); + input_sync(gf_dev->input); + input_report_key(gf_dev->input, nav_input, 0); + input_sync(gf_dev->input); + } +} + +static irqreturn_t gf_irq(int irq, void *handle) +{ +#if defined(GF_NETLINK_ENABLE) + char msg = GF_NET_EVENT_IRQ; + //wake_lock_timeout(&fp_wakelock, msecs_to_jiffies(WAKELOCK_HOLD_TIME)); + __pm_wakeup_event(fp_wakelock, WAKELOCK_HOLD_TIME); + sendnlmsg(&msg); +#elif defined (GF_FASYNC) + struct gf_dev *gf_dev = &gf; + if (gf_dev->async) + kill_fasync(&gf_dev->async, SIGIO, POLL_IN); +#endif + return IRQ_HANDLED; +} + +static int irq_setup(struct gf_dev *gf_dev) +{ + int status; + + gf_dev->irq = gf_irq_num(gf_dev); + status = request_threaded_irq(gf_dev->irq, NULL, gf_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "gf", gf_dev); + + if (status) { + pr_err("failed to request IRQ:%d\n", gf_dev->irq); + return status; + } + enable_irq_wake(gf_dev->irq); + gf_dev->irq_enabled = 1; + + return status; +} + +/*static void irq_cleanup(struct gf_dev *gf_dev) +{ + gf_dev->irq_enabled = 0; + disable_irq(gf_dev->irq); + disable_irq_wake(gf_dev->irq); + free_irq(gf_dev->irq, gf_dev); +}*/ + +static void gf_kernel_key_input(struct gf_dev *gf_dev, struct gf_key *gf_key) +{ + uint32_t key_input = 0; + if (GF_KEY_HOME == gf_key->key) { + key_input = GF_KEY_INPUT_HOME; + } else if (GF_KEY_POWER == gf_key->key) { + key_input = GF_KEY_INPUT_POWER; + } else if (GF_KEY_CAMERA == gf_key->key) { + key_input = GF_KEY_INPUT_CAMERA; + } else if (GF_KEY_LONGPRESS == gf_key->key) { + key_input = GF_KEY_INPUT_LONG_PRESS; + } else { + /* add special key define */ + key_input = gf_key->key; + } + pr_info("%s: received key event[%d], key=%d, value=%d\n", + __func__, key_input, gf_key->key, gf_key->value); + + if ((GF_KEY_POWER == gf_key->key || GF_KEY_LONGPRESS == gf_key->key) + && (gf_key->value == 1)) { + input_report_key(gf_dev->input, key_input, 1); + input_sync(gf_dev->input); + input_report_key(gf_dev->input, key_input, 0); + input_sync(gf_dev->input); + } + + if (GF_KEY_HOME == gf_key->key) { + input_report_key(gf_dev->input, key_input, gf_key->value); + input_sync(gf_dev->input); + } +} + +static long gf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct gf_dev *gf_dev = &gf; + struct gf_key gf_key; +#if defined(SUPPORT_NAV_EVENT) + gf_nav_event_t nav_event = GF_NAV_NONE; +#endif + int retval = 0; + u8 netlink_route = NETLINK_TEST; + struct gf_ioc_chip_info info; + + if (_IOC_TYPE(cmd) != GF_IOC_MAGIC) + return -ENODEV; + + if (_IOC_DIR(cmd) & _IOC_READ) + retval = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + retval = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (retval) + return -EFAULT; + + if (gf_dev->device_available == 0) { + if ((cmd == GF_IOC_ENABLE_POWER) || (cmd == GF_IOC_DISABLE_POWER)) { + pr_info("power cmd\n"); + } else { + pr_info("Sensor is power off currently. \n"); + //return -ENODEV; + } + } + + switch (cmd) { + case GF_IOC_INIT: + pr_debug("%s GF_IOC_INIT\n", __func__); + if (copy_to_user((void __user *)arg, (void *)&netlink_route, sizeof(u8))) { + retval = -EFAULT; + break; + } + break; + case GF_IOC_EXIT: + pr_debug("%s GF_IOC_EXIT\n", __func__); + break; + case GF_IOC_DISABLE_IRQ: + pr_debug("%s GF_IOC_DISABEL_IRQ\n", __func__); + gf_disable_irq(gf_dev); + break; + case GF_IOC_ENABLE_IRQ: + pr_debug("%s GF_IOC_ENABLE_IRQ\n", __func__); + gf_enable_irq(gf_dev); + break; + case GF_IOC_RESET: + pr_info("%s GF_IOC_RESET. \n", __func__); + gf_hw_reset(gf_dev, 0); + break; + case GF_IOC_INPUT_KEY_EVENT: + if (copy_from_user(&gf_key, (struct gf_key *)arg, sizeof(struct gf_key))) { + pr_info("Failed to copy input key event from user to kernel\n"); + retval = -EFAULT; + break; + } + + gf_kernel_key_input(gf_dev, &gf_key); + break; +#if defined(SUPPORT_NAV_EVENT) + case GF_IOC_NAV_EVENT: + pr_debug("%s GF_IOC_NAV_EVENT\n", __func__); + if (copy_from_user(&nav_event, (gf_nav_event_t *)arg, sizeof(gf_nav_event_t))) { + pr_info("Failed to copy nav event from user to kernel\n"); + retval = -EFAULT; + break; + } + + nav_event_input(gf_dev, nav_event); + break; +#endif + + case GF_IOC_ENABLE_SPI_CLK: + pr_debug("%s GF_IOC_ENABLE_SPI_CLK\n", __func__); +#ifdef AP_CONTROL_CLK + gfspi_ioctl_clk_enable(gf_dev); +#else + pr_debug("Doesn't support control clock.\n"); +#endif + break; + case GF_IOC_DISABLE_SPI_CLK: + pr_debug("%s GF_IOC_DISABLE_SPI_CLK\n", __func__); +#ifdef AP_CONTROL_CLK + gfspi_ioctl_clk_disable(gf_dev); +#else + pr_debug("Doesn't support control clock\n"); +#endif + break; + case GF_IOC_ENABLE_POWER: + pr_debug("%s GF_IOC_ENABLE_POWER\n", __func__); + if (gf_dev->device_available == 1) + pr_info("Sensor has already powered-on.\n"); + else + gf_power_on(gf_dev); + gf_dev->device_available = 1; + break; + case GF_IOC_DISABLE_POWER: + pr_debug("%s GF_IOC_DISABLE_POWER\n", __func__); + if (gf_dev->device_available == 0) + pr_info("Sensor has already powered-off.\n"); + else + gf_power_off(gf_dev); + gf_dev->device_available = 0; + break; + case GF_IOC_ENTER_SLEEP_MODE: + pr_debug("%s GF_IOC_ENTER_SLEEP_MODE\n", __func__); + break; + case GF_IOC_GET_FW_INFO: + pr_debug("%s GF_IOC_GET_FW_INFO\n", __func__); + break; + + case GF_IOC_REMOVE: + //irq_cleanup(gf_dev); + //gf_cleanup(gf_dev); + pr_debug("%s GF_IOC_REMOVE\n", __func__); + break; + + case GF_IOC_CHIP_INFO: + pr_debug("%s GF_IOC_CHIP_INFO\n", __func__); + if (copy_from_user(&info, (struct gf_ioc_chip_info *)arg, sizeof(struct gf_ioc_chip_info))) { + retval = -EFAULT; + break; + } + pr_info("vendor_id : 0x%x\n", info.vendor_id); + pr_info("mode : 0x%x\n", info.mode); + pr_info("operation: 0x%x\n", info.operation); + break; + default: + pr_warn("unsupport cmd:0x%x\n", cmd); + break; + } + + return retval; +} + +#ifdef CONFIG_COMPAT +static long gf_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return gf_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif /*CONFIG_COMPAT*/ + + + +static int gf_open(struct inode *inode, struct file *filp) +{ + struct gf_dev *gf_dev = &gf; + int status = -ENXIO; + mutex_lock(&device_list_lock); + + list_for_each_entry(gf_dev, &device_list, device_entry) { + if (gf_dev->devt == inode->i_rdev) { + pr_info("Found\n"); + status = 0; + break; + } + } + if (status == 0) { + if (status == 0) { + gf_dev->users++; + filp->private_data = gf_dev; + nonseekable_open(inode, filp); + pr_info("Succeed to open device. irq = %d\n", + gf_dev->irq); + #if 0 //zoulian@20170727 parse dts move to probe + if (gf_dev->users == 1) { + status = gf_parse_dts(gf_dev); + if (status) + goto err_parse_dt; + + status = irq_setup(gf_dev); + if (status) + goto err_irq; + } + #endif + //gf_hw_reset(gf_dev, 5); + gf_dev->device_available = 1; + } + } else { + pr_info("No device for minor %d\n", iminor(inode)); + } + + mutex_unlock(&device_list_lock); + + return status; +#if 0 //zoulian@20170727 parse dts move to probe +err_irq: + gf_cleanup(gf_dev); +err_parse_dt: + return status; +#endif +} + +#ifdef GF_FASYNC +static int gf_fasync(int fd, struct file *filp, int mode) +{ + struct gf_dev *gf_dev = filp->private_data; + int ret; + + ret = fasync_helper(fd, filp, mode, &gf_dev->async); + pr_info("ret = %d\n", ret); + return ret; +} +#endif + +static int gf_release(struct inode *inode, struct file *filp) +{ + struct gf_dev *gf_dev = &gf; + int status = 0; + + mutex_lock(&device_list_lock); + gf_dev = filp->private_data; + filp->private_data = NULL; + + /*last close?? */ + gf_dev->users--; + if (!gf_dev->users) { + + pr_info("disble_irq. irq = %d\n", gf_dev->irq); + gf_disable_irq(gf_dev); + /*power off the sensor*/ + gf_dev->device_available = 0; + gf_power_off(gf_dev); + } + mutex_unlock(&device_list_lock); + return status; +} + +static const struct file_operations gf_fops = { + .owner = THIS_MODULE, + /* REVISIT switch to aio primitives, so that userspace + * gets more complete API coverage. It'll simplify things + * too, except for the locking. + */ + .unlocked_ioctl = gf_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gf_compat_ioctl, +#endif /*CONFIG_COMPAT*/ + .open = gf_open, + .release = gf_release, +#ifdef GF_FASYNC + .fasync = gf_fasync, +#endif +}; + +static ssize_t screen_state_get(struct device *device, + struct device_attribute *attribute, + char *buffer) +{ + struct gf_dev *gfDev = dev_get_drvdata(device); + + return scnprintf(buffer, PAGE_SIZE, "%i\n", gfDev->screen_state); +} + +static DEVICE_ATTR(screen_state, 0400, screen_state_get, NULL); + +static struct attribute *gf_attributes[] = { + &dev_attr_screen_state.attr, + NULL +}; + +static const struct attribute_group gf_attribute_group = { + .attrs = gf_attributes, +}; + +static struct fp_underscreen_info fp_tpinfo ={0}; +int opticalfp_irq_handler(struct fp_underscreen_info* tp_info) +{ + pr_info("[info]:%s", __func__); + + if (gf.spi == NULL) { + return 0; + } + fp_tpinfo = *tp_info; + + if (fp_tpinfo.touch_state == 1) { + pr_err("TOUCH DOWN, fp_tpinfo.x = %d, fp_tpinfo.y = %d \n", fp_tpinfo.x, fp_tpinfo.y); + fp_tpinfo.touch_state = GF_NET_EVENT_TP_TOUCHDOWN; + sendnlmsg_tp(&fp_tpinfo,sizeof(fp_tpinfo)); + } else if (fp_tpinfo.touch_state == 0) { + pr_err("TOUCH UP, fp_tpinfo.x = %d, fp_tpinfo.y = %d \n", fp_tpinfo.x, fp_tpinfo.y); + fp_tpinfo.touch_state = GF_NET_EVENT_TP_TOUCHUP; + sendnlmsg_tp(&fp_tpinfo,sizeof(fp_tpinfo)); + } + return 0; +} + +EXPORT_SYMBOL(opticalfp_irq_handler); +int gf_opticalfp_irq_handler(int event) +{ + char msg = 0; + + pr_info("[info]:%s, event %d", __func__, event); + + if (gf.spi == NULL) { + return 0; + } + if (event == 1) { + msg = GF_NET_EVENT_TP_TOUCHDOWN; + sendnlmsg(&msg); + } else if (event == 0) { + msg = GF_NET_EVENT_TP_TOUCHUP; + sendnlmsg(&msg); + } + + __pm_wakeup_event(fp_wakelock, 10*HZ); + + return 0; +} +EXPORT_SYMBOL(gf_opticalfp_irq_handler); + +#if defined(CONFIG_FB) +static int goodix_fb_state_chg_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct gf_dev *gf_dev; + struct fb_event *evdata = data; + unsigned int blank; + char msg = 0; + + if (val != FB_EARLY_EVENT_BLANK) + return 0; + pr_debug("[info] %s go to the goodix_fb_state_chg_callback value = %d\n", + __func__, (int)val); + gf_dev = container_of(nb, struct gf_dev, notifier); + + if (evdata && evdata->data && val == FB_EARLY_EVENT_BLANK && gf_dev) { + blank = *(int *)(evdata->data); + switch (blank) { + case FB_BLANK_POWERDOWN: + if (gf_dev->device_available == 1) { + gf_dev->fb_black = 1; +#if defined(GF_NETLINK_ENABLE) + msg = GF_NET_EVENT_FB_BLACK; + sendnlmsg(&msg); +#elif defined (GF_FASYNC) + if (gf_dev->async) { + kill_fasync(&gf_dev->async, SIGIO, POLL_IN); + } +#endif + } + break; + case FB_BLANK_UNBLANK: + if (gf_dev->device_available == 1) { + gf_dev->fb_black = 0; +#if defined(GF_NETLINK_ENABLE) + msg = GF_NET_EVENT_FB_UNBLACK; + sendnlmsg(&msg); +#elif defined (GF_FASYNC) + if (gf_dev->async) { + kill_fasync(&gf_dev->async, SIGIO, POLL_IN); + } +#endif + } + break; + default: + pr_info("%s defalut\n", __func__); + break; + } + } + return NOTIFY_OK; +} + +static struct notifier_block goodix_noti_block = { + .notifier_call = goodix_fb_state_chg_callback, +}; +#elif defined(CONFIG_MSM_RDM_NOTIFY) +static int goodix_fb_state_chg_callback( + struct notifier_block *nb, unsigned long val, void *data) +{ + + struct gf_dev *gf_dev; + struct drm_panel_notifier *evdata = data; + unsigned int blank; + char msg = 0; + pr_debug("[info] %s go to the msm_drm_notifier_callback value = %d\n", + __func__, (int)val); + if (val != DRM_PANEL_EARLY_EVENT_BLANK && + val != DRM_PANEL_ONSCREENFINGERPRINT_EVENT) + return 0; + + blank = *(int *)(evdata->data); + + if (val == DRM_PANEL_ONSCREENFINGERPRINT_EVENT) { + pr_info("[%s] UI ready enter\n", __func__); + + switch (blank) { + case 0: + pr_info("[%s] UI disappear\n", __func__); + msg = GF_NET_EVENT_UI_DISAPPEAR; + sendnlmsg(&msg); + break; + case 1: + pr_info("[%s] UI ready\n", __func__); + msg = GF_NET_EVENT_UI_READY; + sendnlmsg(&msg); + break; + default: + pr_info("[%s] Unknown EVENT\n", __func__); + break; + } + return 0; + } + + gf_dev = container_of(nb, struct gf_dev, msm_drm_notif); + if (evdata && evdata->data && val == + DRM_PANEL_EARLY_EVENT_BLANK && gf_dev) { + blank = *(int *)(evdata->data); + switch (blank) { + case DRM_PANEL_BLANK_POWERDOWN: + if (gf_dev->device_available == 1) { + gf_dev->fb_black = 1; +#if defined(GF_NETLINK_ENABLE) + msg = GF_NET_EVENT_FB_BLACK; + pr_info("[%s] SCREEN OFF\n", __func__); + sendnlmsg(&msg); +#elif defined(GF_FASYNC) + if (gf_dev->async) { + kill_fasync(&gf_dev->async, + SIGIO, POLL_IN); + } +#endif + } + gf_dev->screen_state = 0; + sysfs_notify(&gf_dev->spi->dev.kobj, + NULL, dev_attr_screen_state.attr.name); + break; + case DRM_PANEL_BLANK_UNBLANK: + if (gf_dev->device_available == 1) { + gf_dev->fb_black = 0; +#if defined(GF_NETLINK_ENABLE) + msg = GF_NET_EVENT_FB_UNBLACK; + pr_info("[%s] SCREEN ON\n", __func__); + sendnlmsg(&msg); +#elif defined(GF_FASYNC) + if (gf_dev->async) + kill_fasync(&gf_dev->async, + SIGIO, POLL_IN); +#endif + } + gf_dev->screen_state = 1; + sysfs_notify(&gf_dev->spi->dev.kobj, + NULL, dev_attr_screen_state.attr.name); + break; + default: + pr_info("%s defalut\n", __func__); + break; + } + } + return NOTIFY_OK; +} +#endif + +static struct class *gf_class; +#if defined(USE_SPI_BUS) +static int gf_probe(struct spi_device *spi) +#elif defined(USE_PLATFORM_BUS) +static int gf_probe(struct platform_device *pdev) +#endif +{ + struct gf_dev *gf_dev = &gf; + int status = -EINVAL; + unsigned long minor; + int i; + + /* Initialize the driver data */ + INIT_LIST_HEAD(&gf_dev->device_entry); +#if defined(USE_SPI_BUS) + gf_dev->spi = spi; +#elif defined(USE_PLATFORM_BUS) + gf_dev->spi = pdev; +#endif + gf_dev->irq_gpio = -EINVAL; + gf_dev->reset_gpio = -EINVAL; + gf_dev->pwr_gpio = -EINVAL; + gf_dev->vdd_3v3 = NULL; + gf_dev->device_available = 0; + gf_dev->fb_black = 0; + + /* If we can allocate a minor number, hook up this device. + * Reusing minors is fine so long as udev or mdev is working. + */ + mutex_lock(&device_list_lock); + minor = find_first_zero_bit(minors, N_SPI_MINORS); + if (minor < N_SPI_MINORS) { + struct device *dev; + + gf_dev->devt = MKDEV(SPIDEV_MAJOR, minor); + dev = device_create(gf_class, &gf_dev->spi->dev, gf_dev->devt, + gf_dev, GF_DEV_NAME); + status = IS_ERR(dev) ? PTR_ERR(dev) : 0; + } else { + dev_dbg(&gf_dev->spi->dev, "no minor number available!\n"); + status = -ENODEV; + mutex_unlock(&device_list_lock); + goto error_hw; + } + + if (status == 0) { + set_bit(minor, minors); + list_add(&gf_dev->device_entry, &device_list); + } else { + gf_dev->devt = 0; + } + mutex_unlock(&device_list_lock); + status = gf_parse_dts(gf_dev); + if (status) + goto err_parse_dt; + /* + * liuyan mv wakelock here + * it should before irq + */ + fp_wakelock = wakeup_source_register(&gf_dev->spi->dev, "fp_wakelock"); + status = irq_setup(gf_dev); + if (status) + goto err_irq; + + if (fp_dtsi_product != 19805) { + status = gf_pinctrl_init(gf_dev); + if (status) + goto err_irq; + } + if (get_boot_mode() != MSM_BOOT_MODE_FACTORY) { + if (fp_dtsi_product != 19805) { + status = pinctrl_select_state(gf_dev->gf_pinctrl, + gf_dev->gpio_state_enable); + if (status) { + pr_err("can not set %s pins\n", "fp_en_init"); + goto error_hw; + } + } else { + status = gf_power_on(gf_dev); + if (status) { + pr_err("can not set regulator power on.\n"); + goto error_hw; + } + } + } else { + if (fp_dtsi_product != 19805) { + status = pinctrl_select_state(gf_dev->gf_pinctrl, + gf_dev->gpio_state_disable); + if (status) { + pr_err("can not set %s pins\n", "fp_dis_init"); + goto error_hw; + } + } else { + status = gf_power_off(gf_dev); + if (status) { + pr_err("can not set regulator power off.\n"); + goto error_hw; + } + } + } + if (status == 0) { + /*input device subsystem */ + gf_dev->input = input_allocate_device(); + if (gf_dev->input == NULL) { + pr_err("%s, failed to allocate input device\n", __func__); + status = -ENOMEM; + goto error_dev; + } + for (i = 0; i < ARRAY_SIZE(maps); i++) + input_set_capability(gf_dev->input, maps[i].type, maps[i].code); + + gf_dev->input->name = GF_INPUT_NAME; + status = input_register_device(gf_dev->input); + if (status) { + pr_err("failed to register input device\n"); + goto error_input; + } + } +#ifdef AP_CONTROL_CLK + pr_info("Get the clk resource.\n"); + /* Enable spi clock */ + if (gfspi_ioctl_clk_init(gf_dev)) + goto gfspi_probe_clk_init_failed: + + if (gfspi_ioctl_clk_enable(gf_dev)) + goto gfspi_probe_clk_enable_failed; + + spi_clock_set(gf_dev, 1000000); +#endif + +#if defined(CONFIG_FB) + gf_dev->notifier = goodix_noti_block; + fb_register_client(&gf_dev->notifier); +#elif defined(CONFIG_MSM_RDM_NOTIFY) + gf_dev->msm_drm_notif.notifier_call = goodix_fb_state_chg_callback; +// status = msm_drm_register_client(&gf_dev->msm_drm_notif); +// if (status) +// pr_err("Unable to register msm_drm_notifier: %d\n", status); + if (lcd_active_panel) { + status = drm_panel_notifier_register(lcd_active_panel, &gf_dev->msm_drm_notif); + if (status) { + pr_err("Unable to register fb_notifier: %d\n", status); + }else{ + pr_err("register notifier drm panel success!"); + } + }else{ + pr_err("Ooops!!! lcd_active_panel is null, unable to register fb_notifier!"); + } +#endif + + #ifdef USE_SPI_BUS + spi_set_drvdata(spi, gf_dev); + #else + platform_set_drvdata(pdev, gf_dev); + #endif + status = sysfs_create_group(&gf_dev->spi->dev.kobj, + &gf_attribute_group); + if (status) { + pr_err("%s:could not create sysfs\n", __func__); + goto error_input; + } + pr_info("version V%d.%d.%02d\n", VER_MAJOR, VER_MINOR, PATCH_LEVEL); + + return status; + +#ifdef AP_CONTROL_CLK +gfspi_probe_clk_enable_failed: + gfspi_ioctl_clk_uninit(gf_dev); +gfspi_probe_clk_init_failed: +#endif + +error_input: + if (gf_dev->input != NULL) + input_free_device(gf_dev->input); +error_dev: + if (gf_dev->devt != 0) { + pr_info("Err: status = %d\n", status); + mutex_lock(&device_list_lock); + list_del(&gf_dev->device_entry); + device_destroy(gf_class, gf_dev->devt); + clear_bit(MINOR(gf_dev->devt), minors); + mutex_unlock(&device_list_lock); + } +err_irq: + gf_cleanup(gf_dev); +err_parse_dt: +error_hw: + gf_dev->device_available = 0; + + return status; +} + +#if defined(USE_SPI_BUS) +static int gf_remove(struct spi_device *spi) +#elif defined(USE_PLATFORM_BUS) +static int gf_remove(struct platform_device *pdev) +#endif +{ + struct gf_dev *gf_dev = &gf; + + wakeup_source_unregister(fp_wakelock); + +#if defined(CONFIG_FB) + fb_unregister_client(&gf_dev->notifier); +#elif defined(CONFIG_MSM_RDM_NOTIFY) +// if (drm_panel_notifier_unregister(lcd_active_panel,&gf_dev->msm_drm_notif)) +// pr_err("Error occurred while unregistering msm_drm_notifier.\n"); +#endif + if (gf_dev->input) + input_unregister_device(gf_dev->input); + input_free_device(gf_dev->input); + + /* prevent new opens */ + mutex_lock(&device_list_lock); + list_del(&gf_dev->device_entry); + device_destroy(gf_class, gf_dev->devt); + clear_bit(MINOR(gf_dev->devt), minors); + mutex_unlock(&device_list_lock); + + return 0; +} + +static struct of_device_id gx_match_table[] = { + { .compatible = GF_SPIDEV_NAME }, + {}, +}; + +#if defined(USE_SPI_BUS) +static struct spi_driver gf_driver = { +#elif defined(USE_PLATFORM_BUS) +static struct platform_driver gf_driver = { +#endif + .driver = { + .name = GF_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = gx_match_table, + }, + .probe = gf_probe, + .remove = gf_remove, +}; + +static int __init gf_init(void) +{ + int status; + + /* Claim our 256 reserved device numbers. Then register a class + * that will key udev/mdev to add/remove /dev nodes. Last, register + * the driver which manages those device numbers. + */ + pr_info("%s:fp version %x\n", __func__, fp_version); + if ((fp_version != 0x03) && (fp_version != 0x04) && (fp_version != 0x07) \ + && (fp_version != 0x9638) && (fp_version != 0x9678)) + return 0; + BUILD_BUG_ON(N_SPI_MINORS > 256); + status = register_chrdev(SPIDEV_MAJOR, CHRD_DRIVER_NAME, &gf_fops); + if (status < 0) { + pr_warn("Failed to register char device!\n"); + return status; + } + SPIDEV_MAJOR = status; + gf_class = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(gf_class)) { + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name); + pr_warn("Failed to create class.\n"); + return PTR_ERR(gf_class); + } +#if defined(USE_PLATFORM_BUS) + status = platform_driver_register(&gf_driver); +#elif defined(USE_SPI_BUS) + status = spi_register_driver(&gf_driver); +#endif + if (status < 0) { + class_destroy(gf_class); + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name); + pr_warn("Failed to register SPI driver.\n"); + } + +#ifdef GF_NETLINK_ENABLE + netlink_init(); +#endif + pr_info("status = 0x%x\n", status); + return 0; +} +late_initcall(gf_init); + +static void __exit gf_exit(void) +{ +#ifdef GF_NETLINK_ENABLE + netlink_exit(); +#endif +#if defined(USE_PLATFORM_BUS) + platform_driver_unregister(&gf_driver); +#elif defined(USE_SPI_BUS) + spi_unregister_driver(&gf_driver); +#endif + class_destroy(gf_class); + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name); +} +module_exit(gf_exit); + +MODULE_AUTHOR("Jiangtao Yi, "); +MODULE_AUTHOR("Jandy Gou, "); +MODULE_DESCRIPTION("goodix fingerprint sensor device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/oneplus/input/fingerprint/goodix/gf_spi.h b/drivers/oneplus/input/fingerprint/goodix/gf_spi.h new file mode 100755 index 0000000000000000000000000000000000000000..ca1a8719df3a28b87116d52a8ade4ac7b08b0944 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/gf_spi.h @@ -0,0 +1,191 @@ +/* + * driver definition for sensor driver + * + * Coypright (c) 2017 Goodix + */ +#ifndef __GF_SPI_H +#define __GF_SPI_H + +#define CONFIG_MSM_RDM_NOTIFY +#undef CONFIG_FB +#if defined(CONFIG_MSM_RDM_NOTIFY) +#include +#endif + +#include +#include +/**********************************************************/ +enum FP_MODE{ + GF_IMAGE_MODE = 0, + GF_KEY_MODE, + GF_SLEEP_MODE, + GF_FF_MODE, + GF_DEBUG_MODE = 0x56 +}; + +struct fp_underscreen_info { + uint8_t touch_state; + uint16_t x; + uint16_t y; +}; +#define SUPPORT_NAV_EVENT + +#if defined(SUPPORT_NAV_EVENT) +#define GF_NAV_INPUT_UP KEY_UP +#define GF_NAV_INPUT_DOWN KEY_DOWN +#define GF_NAV_INPUT_LEFT KEY_LEFT +#define GF_NAV_INPUT_RIGHT KEY_RIGHT +#define GF_NAV_INPUT_CLICK KEY_VOLUMEDOWN +#define GF_NAV_INPUT_DOUBLE_CLICK KEY_VOLUMEUP +#define GF_NAV_INPUT_LONG_PRESS BTN_B +#define GF_NAV_INPUT_F2 KEY_F2 +#define GF_NAV_INPUT_HEAVY KEY_CHAT +#endif + +#define GF_KEY_INPUT_HOME KEY_HOME +#define GF_KEY_INPUT_MENU KEY_MENU +#define GF_KEY_INPUT_BACK KEY_BACK +#define GF_KEY_INPUT_POWER KEY_POWER +#define GF_KEY_INPUT_CAMERA KEY_CAMERA +#define GF_KEY_INPUT_LONG_PRESS BTN_B + + +#if defined(SUPPORT_NAV_EVENT) +typedef enum gf_nav_event { + GF_NAV_NONE = 0, + GF_NAV_FINGER_UP, + GF_NAV_FINGER_DOWN, + GF_NAV_UP, + GF_NAV_DOWN, + GF_NAV_LEFT, + GF_NAV_RIGHT, + GF_NAV_CLICK, + GF_NAV_HEAVY, + GF_NAV_LONG_PRESS, + GF_NAV_DOUBLE_CLICK, + GF_NAV_F2, +} gf_nav_event_t; +#endif + +typedef enum gf_key_event { + GF_KEY_NONE = 0, + GF_KEY_HOME, + GF_KEY_POWER, + GF_KEY_MENU, + GF_KEY_BACK, + GF_KEY_CAMERA, + GF_KEY_LONGPRESS, +} gf_key_event_t; + +struct gf_key { + enum gf_key_event key; + uint32_t value; /* key down = 1, key up = 0 */ +}; + +struct gf_key_map { + unsigned int type; + unsigned int code; +}; + +struct gf_ioc_chip_info { + unsigned char vendor_id; + unsigned char mode; + unsigned char operation; + unsigned char reserved[5]; +}; + +#define GF_IOC_MAGIC 'g' //define magic number +#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t) +#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1) +#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2) +#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3) +#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4) +#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t) +#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6) +#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7) +#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8) +#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key) +#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10) +#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t) +#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12) +#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info) + +#if defined(SUPPORT_NAV_EVENT) +#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t) +#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */ +#else +#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */ +#endif + +//#define AP_CONTROL_CLK 1 +#define USE_PLATFORM_BUS 1 +//#define USE_SPI_BUS 1 +//#define GF_FASYNC 1 /*If support fasync mechanism.*/ +#define GF_NETLINK_ENABLE 1 +#define GF_NET_EVENT_IRQ 1 +#define GF_NET_EVENT_FB_BLACK 2 +#define GF_NET_EVENT_FB_UNBLACK 3 +#define GF_NET_EVENT_TP_TOUCHDOWN 4 +#define GF_NET_EVENT_TP_TOUCHUP 5 +#define GF_NET_EVENT_UI_READY 6 +#define GF_NET_EVENT_UI_DISAPPEAR 7 +#define NETLINK_TEST 25 + +struct gf_dev { + dev_t devt; + struct list_head device_entry; +#if defined(USE_SPI_BUS) + struct spi_device *spi; +#elif defined(USE_PLATFORM_BUS) + struct platform_device *spi; +#endif + struct clk *core_clk; + struct clk *iface_clk; + + struct input_dev *input; + /* buffer is NULL unless this device is open (users > 0) */ + unsigned users; + signed irq_gpio; + signed reset_gpio; + signed pwr_gpio; + int irq; + int irq_enabled; + int clk_enabled; + + struct regulator *vdd_3v3; + int regulator_vdd_vmin; + int regulator_vdd_vmax; + int regulator_vdd_current; + +#ifdef GF_FASYNC + struct fasync_struct *async; +#endif +#if defined(CONFIG_FB) + struct notifier_block notifier; +#elif defined(CONFIG_MSM_RDM_NOTIFY) + struct notifier_block msm_drm_notif; +#endif + char device_available; + char fb_black; + struct pinctrl *gf_pinctrl; + struct pinctrl_state *gpio_state_enable; + struct pinctrl_state *gpio_state_disable; + signed enable_gpio; + int screen_state; +}; +int gf_pinctrl_init(struct gf_dev* gf_dev); +int gf_parse_dts(struct gf_dev* gf_dev); +void gf_cleanup(struct gf_dev *gf_dev); +int gf_power_on(struct gf_dev *gf_dev); +int gf_power_off(struct gf_dev *gf_dev); + +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms); +int gf_irq_num(struct gf_dev *gf_dev); + +void sendnlmsg(char *msg); +void sendnlmsg_tp(struct fp_underscreen_info *msg, int length); +int netlink_init(void); +void netlink_exit(void); +extern int gf_opticalfp_irq_handler(int event); +extern int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); +#endif /*__GF_SPI_H*/ diff --git a/drivers/oneplus/input/fingerprint/goodix/netlink.c b/drivers/oneplus/input/fingerprint/goodix/netlink.c new file mode 100644 index 0000000000000000000000000000000000000000..ce5b3babeb52284c99447292c1bfdf37d3e36301 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/netlink.c @@ -0,0 +1,128 @@ +/* + * netlink interface + * + * Copyright (c) 2017 Goodix + */ +#include +#include +#include +#include +#include +#include +#include +#include "gf_spi.h" + +#define NETLINK_TEST 25 +#define MAX_MSGSIZE 32 + +static int pid = -1; +struct sock *gf_nl_sk = NULL; + +void sendnlmsg(char *msg) +{ + struct sk_buff *skb_1; + struct nlmsghdr *nlh; + int len = NLMSG_SPACE(MAX_MSGSIZE); + int ret = 0; + if (!msg || !gf_nl_sk || !pid) { + return ; + } + skb_1 = alloc_skb(len, GFP_KERNEL); + if (!skb_1) { + pr_err("alloc_skb error\n"); + return; + } + + nlh = nlmsg_put(skb_1, 0, 0, 0, MAX_MSGSIZE, 0); + + NETLINK_CB(skb_1).portid = 0; + NETLINK_CB(skb_1).dst_group = 0; + + memcpy(NLMSG_DATA(nlh), msg, sizeof(char)); + pr_debug("send message: %d\n", *(char *)NLMSG_DATA(nlh)); + + ret = netlink_unicast(gf_nl_sk, skb_1, pid, MSG_DONTWAIT); + if (!ret) { + //kfree_skb(skb_1); + pr_err("send msg from kernel to usespace failed ret 0x%x\n", ret); + } +} + +void sendnlmsg_tp(struct fp_underscreen_info *msg, int length) +{ + struct sk_buff *skb_1; + struct nlmsghdr *nlh; + int len = NLMSG_SPACE(MAX_MSGSIZE); + int ret = 0; + if (!msg || !gf_nl_sk || !pid) { + return ; + } + skb_1 = alloc_skb(len, GFP_KERNEL); + if (!skb_1) { + pr_err("alloc_skb error\n"); + return; + } + + nlh = nlmsg_put(skb_1, 0, 0, 0, length, 0); + + NETLINK_CB(skb_1).portid = 0; + NETLINK_CB(skb_1).dst_group = 0; + memcpy(NLMSG_DATA(nlh), msg, length);//core + // pr_debug("send message: %d\n", *(char *)NLMSG_DATA(nlh)); + ret = netlink_unicast(gf_nl_sk, skb_1, pid, MSG_DONTWAIT); + if (!ret) { + //kfree_skb(skb_1); + pr_err("send msg from kernel to usespace failed ret 0x%x\n", ret); + } +} + +void nl_data_ready(struct sk_buff *__skb) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + char str[100]; + skb = skb_get (__skb); + if(skb->len >= NLMSG_SPACE(0)) + { + nlh = nlmsg_hdr(skb); + + memcpy(str, NLMSG_DATA(nlh), sizeof(str)); + pid = nlh->nlmsg_pid; + + kfree_skb(skb); + } + +} + + +int netlink_init(void) +{ + struct netlink_kernel_cfg netlink_cfg; + memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg)); + + netlink_cfg.groups = 0; + netlink_cfg.flags = 0; + netlink_cfg.input = nl_data_ready; + netlink_cfg.cb_mutex = NULL; + + gf_nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, + &netlink_cfg); + + if(!gf_nl_sk){ + pr_err("create netlink socket error\n"); + return 1; + } + + return 0; +} + +void netlink_exit(void) +{ + if(gf_nl_sk != NULL){ + netlink_kernel_release(gf_nl_sk); + gf_nl_sk = NULL; + } + + pr_info("self module exited\n"); +} + diff --git a/drivers/oneplus/input/fingerprint/goodix/platform.c b/drivers/oneplus/input/fingerprint/goodix/platform.c new file mode 100755 index 0000000000000000000000000000000000000000..b76fb5ec92da9eed1c80a2cb6612d3ce4674da09 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/goodix/platform.c @@ -0,0 +1,194 @@ +/* + * platform indepent driver interface + * + * Coypritht (c) 2017 Goodix + */ +#include +#include +#include +#include +#include +#include +#include + +#include "gf_spi.h" +#include "../fingerprint_detect/fingerprint_detect.h" + +#if defined(USE_SPI_BUS) +#include +#include +#elif defined(USE_PLATFORM_BUS) +#include +#endif +//#include + +int gf_pinctrl_init(struct gf_dev* gf_dev) +{ + int ret = 0; + struct device *dev = &gf_dev->spi->dev; + + gf_dev->gf_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(gf_dev->gf_pinctrl)) { + dev_err(dev, "Target does not use pinctrl\n"); + ret = PTR_ERR(gf_dev->gf_pinctrl); + goto err; + } + + gf_dev->gpio_state_enable = + pinctrl_lookup_state(gf_dev->gf_pinctrl, "fp_en_init"); + if (IS_ERR_OR_NULL(gf_dev->gpio_state_enable)) { + dev_err(dev, "Cannot get active pinstate\n"); + ret = PTR_ERR(gf_dev->gpio_state_enable); + goto err; + } + + gf_dev->gpio_state_disable = + pinctrl_lookup_state(gf_dev->gf_pinctrl, "fp_dis_init"); + if (IS_ERR_OR_NULL(gf_dev->gpio_state_disable)) { + dev_err(dev, "Cannot get active pinstate\n"); + ret = PTR_ERR(gf_dev->gpio_state_disable); + goto err; + } + + return 0; +err: + gf_dev->gf_pinctrl = NULL; + gf_dev->gpio_state_enable = NULL; + //gf_dev->gpio_state_disable = NULL; + return ret; +} +int gf_parse_dts(struct gf_dev* gf_dev) +{ + int rc = 0; + struct device *dev = &gf_dev->spi->dev; + struct device_node *np = dev->of_node; + //u32 voltage_supply[2]; + //u32 current_supply; + + gf_dev->reset_gpio = of_get_named_gpio(np, "fp-gpio-reset", 0); + if (gf_dev->reset_gpio < 0) { + pr_err("falied to get reset gpio!\n"); + return gf_dev->reset_gpio; + } + + rc = devm_gpio_request(dev, gf_dev->reset_gpio, "goodix_reset"); + if (rc) { + pr_err("failed to request reset gpio, rc = %d\n", rc); + goto err_reset; + } + gpio_direction_output(gf_dev->reset_gpio, 0); + + gf_dev->irq_gpio = of_get_named_gpio(np, "fp-gpio-irq", 0); + if (gf_dev->irq_gpio < 0) { + pr_err("falied to get irq gpio!\n"); + return gf_dev->irq_gpio; + } + + rc = devm_gpio_request(dev, gf_dev->irq_gpio, "goodix_irq"); + if (rc) { + pr_err("failed to request irq gpio, rc = %d\n", rc); + goto err_irq; + } + gpio_direction_input(gf_dev->irq_gpio); + + return rc; +err_irq: + devm_gpio_free(dev, gf_dev->irq_gpio); +err_reset: + devm_gpio_free(dev, gf_dev->reset_gpio); + return rc; +} + +void gf_cleanup(struct gf_dev *gf_dev) +{ + pr_info("[info] %s\n",__func__); + if (gpio_is_valid(gf_dev->irq_gpio)) + { + gpio_free(gf_dev->irq_gpio); + pr_info("remove irq_gpio success\n"); + } + if (gpio_is_valid(gf_dev->reset_gpio)) + { + gpio_free(gf_dev->reset_gpio); + pr_info("remove reset_gpio success\n"); + } +} + +int gf_power_on(struct gf_dev* gf_dev) +{ + int rc = 0; + if (fp_dtsi_product != 20801) { + struct device *dev = &gf_dev->spi->dev; + struct regulator *vreg = gf_dev->vdd_3v3; + if (!vreg) { + vreg = regulator_get(dev, "fppower"); + if (IS_ERR(vreg)) { + pr_err("Unable to get fppower power.\n"); + return PTR_ERR(vreg); + } + } + if (regulator_count_voltages(vreg) > 0) { + rc = regulator_set_voltage(vreg, 3024000, 3024000); + if (rc) { + pr_err("Unable to set voltage on fppower, %d\n", rc); + } + } + rc = regulator_set_load(vreg, 150000); + if (rc < 0) { + pr_err("Unable to set current on fppower, %d\n", rc); + } + rc = regulator_enable(vreg); + if (rc) { + pr_err("error enabling fppower: %d\n", rc); + regulator_put(vreg); + gf_dev->vdd_3v3 = NULL; + } + } + pr_info("---- power on ok ----\n"); + + return rc; +} + +int gf_power_off(struct gf_dev* gf_dev) +{ + int rc = 0; + if (fp_dtsi_product != 20801) { + struct regulator *vreg = gf_dev->vdd_3v3; + if (vreg) { + if (regulator_is_enabled(vreg)) { + regulator_disable(vreg); + pr_err("disabled fppower\n"); + } + regulator_put(vreg); + gf_dev->vdd_3v3 = NULL; + } + } + pr_info("---- power off ----\n"); + + return rc; +} + +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms) +{ + if(gf_dev == NULL) { + pr_info("Input buff is NULL.\n"); + return -1; + } + gpio_direction_output(gf_dev->reset_gpio, 1); + gpio_set_value(gf_dev->reset_gpio, 0); + mdelay(3); + gpio_set_value(gf_dev->reset_gpio, 1); + mdelay(delay_ms); + return 0; +} + +int gf_irq_num(struct gf_dev *gf_dev) +{ + if(gf_dev == NULL) { + pr_info("Input buff is NULL.\n"); + return -1; + } else { + return gpio_to_irq(gf_dev->irq_gpio); + } +} + diff --git a/drivers/oneplus/input/fingerprint/qbt1000/Makefile b/drivers/oneplus/input/fingerprint/qbt1000/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5ccc1e7e91db4f4b22213c651a7f8ce4c8259c5 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/qbt1000/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MSM_QBT1000) += qbt1000.o diff --git a/drivers/oneplus/input/fingerprint/qbt1000/qbt1000.c b/drivers/oneplus/input/fingerprint/qbt1000/qbt1000.c new file mode 100644 index 0000000000000000000000000000000000000000..b1153ac2bac2950c5964a481f08b1f82849346f1 --- /dev/null +++ b/drivers/oneplus/input/fingerprint/qbt1000/qbt1000.c @@ -0,0 +1,1614 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +#define DEBUG +#define pr_fmt(fmt) "qbt1000:%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../misc/qseecom_kernel.h" +#include "../fingerprint_detect/fingerprint_detect.h" + + +#define QBT1000_DEV "qbt1000" +#define QBT1000_IN_DEV_NAME "qbt1000_key_input" +#define QBT1000_IN_DEV_VERSION 0x0100 +#define MAX_FW_EVENTS 128 +#define FW_MAX_IPC_MSG_DATA_SIZE 0x500 +#define SEND_TZ_CMD_RETRY_CNT 10 +#define SEND_TZ_CMD_DELAY 50 +#define MAX_TOUCHES 10 + +/* + * shared buffer size - init with max value, + * user space will provide new value upon tz app load + */ +static uint32_t g_app_buf_size = SZ_256K; +static char const *const FP_APP_NAME = "fingerpr"; +//static bool is_probed = false; +static struct qbt1000_drvdata *ts_cb_drvdata = NULL; +static signed qbt1000_int2 = 0; + +enum fp_app_cmd { + FP_APP_CMD_RX_IPC = 132, + +}; + +enum ipc_msg_id { + IPC_MSG_ID_CBGE_REQUIRED = 29, + IPC_MSG_ID_GESTURE_SWIPE_DOWN = 50, + IPC_MSG_ID_GESTURE_SWIPE_UP = 51, + IPC_MSG_ID_GESTURE_SWIPE_LEFT = 52, + IPC_MSG_ID_GESTURE_SWIPE_RIGHT = 53, + IPC_MSG_ID_GESTURE_LONG_PRESS = 54, + IPC_MSG_ID_FINGER_ON_SENSOR = 55, + IPC_MSG_ID_FINGER_OFF_SENSOR = 56, +}; + +enum fd_indication_mode { + FD_IND_MODE_BIOMETRIC = 0, + FD_IND_MODE_GESTURES, +}; + +struct finger_detect_gpio { + int gpio; + int active_low; + int irq; + struct work_struct work; + unsigned int key_code; + int power_key_enabled; + int last_gpio_state; +}; + +struct fw_event_desc { + enum qbt1000_fw_event ev; +}; + +struct fw_ipc_info { + int gpio; + int irq; +}; + +struct qbt1000_touch_status { + int x; + int y; +}; + +struct qbt1000_mt_status { + bool is_registered; + int slot; + struct qbt1000_touch_status touches[MAX_TOUCHES]; +}; + +struct qbt1000_drvdata { + struct class *qbt1000_class; + struct cdev qbt1000_cdev; + struct device *dev; + char *qbt1000_node; + struct clk **clocks; + unsigned int clock_count; + uint8_t clock_state; + unsigned int root_clk_idx; + unsigned int frequency; + atomic_t available; + struct mutex mutex; + spinlock_t fw_events_lock; + struct input_dev *in_dev; + struct fw_ipc_info fw_ipc; + struct finger_detect_gpio fd_gpio; + DECLARE_KFIFO(fw_events, struct fw_event_desc, MAX_FW_EVENTS); + wait_queue_head_t read_wait_queue; + struct qseecom_handle *app_handle; + struct qseecom_handle *fp_app_handle; + enum fd_indication_mode fd_ind_mode; + bool ipc_is_stale; + bool gestures_enabled; + struct qbt1000_sensor_pos sensor_pos; + struct qbt1000_mt_status mt; +}; + +/* + * struct fw_ipc_cmd - + * used to store IPC commands to/from firmware + * @status - indicates if sending/getting the IPC message was successful + * @msg_type - the type of IPC message + * @msg_len - the length of the message data + * @resp_needed - whether a response is needed for this message + * @msg_data - any extra data associated with the message + */ +struct fw_ipc_cmd { + uint32_t status; + uint32_t numMsgs; + uint8_t msg_data[FW_MAX_IPC_MSG_DATA_SIZE]; +}; + +struct fw_ipc_header { + uint32_t msg_type; + uint32_t msg_len; + uint32_t resp_needed; +}; + +/* + * struct ipc_msg_type_to_fw_event - + * entry in mapping between an IPC message type to a firmware event + * @msg_type - IPC message type, as reported by firmware + * @fw_event - corresponding firmware event code to report to driver client + */ +struct ipc_msg_type_to_fw_event { + uint32_t msg_type; + enum qbt1000_fw_event fw_event; +}; + +/* mapping between firmware IPC message types to HLOS firmware events */ +struct ipc_msg_type_to_fw_event g_msg_to_event[] = { + {IPC_MSG_ID_CBGE_REQUIRED, FW_EVENT_CBGE_REQUIRED}, + {IPC_MSG_ID_FINGER_ON_SENSOR, FW_EVENT_FINGER_DOWN}, + {IPC_MSG_ID_FINGER_OFF_SENSOR, FW_EVENT_FINGER_UP}, +}; + +static void gpio_report_event(struct qbt1000_drvdata *drvdata, int state); + +int qbt1000_int2_callback(int event) +{ + //if (!is_probed) + // return -1; + if (ts_cb_drvdata == NULL) { + pr_err("ts_cb_drvata is NULL"); + return -1; + } + + pr_info("%s: event %d", __func__, event); + + if (event == 1) { + //gpio_set_value(qbt1000_int2, 1); + gpio_report_event(ts_cb_drvdata,1); + } else if (event == 0) { + //gpio_set_value(qbt1000_int2, 0); + gpio_report_event(ts_cb_drvdata,0); + } + + return 0; +} +EXPORT_SYMBOL(qbt1000_int2_callback); + +/** + * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and + * aligns buffer lengths + * @hdl: index of qseecom_handle + * @cmd: req buffer - set to qseecom_handle.sbuf + * @cmd_len: ptr to req buffer len + * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset + * @rsp_len: ptr to rsp buffer len + * + * Return: 0 on success. Error code on failure. + */ +static int get_cmd_rsp_buffers(struct qseecom_handle *hdl, + void **cmd, + uint32_t *cmd_len, + void **rsp, + uint32_t *rsp_len) +{ + /* 64 bytes alignment for QSEECOM */ + uint64_t aligned_cmd_len = ALIGN((uint64_t)*cmd_len, 64); + uint64_t aligned_rsp_len = ALIGN((uint64_t)*rsp_len, 64); + + if ((aligned_rsp_len + aligned_cmd_len) > (uint64_t)g_app_buf_size) + return -ENOMEM; + + *cmd = hdl->sbuf; + *cmd_len = aligned_cmd_len; + *rsp = hdl->sbuf + *cmd_len; + *rsp_len = aligned_rsp_len; + + return 0; +} + +/** + * send_tz_cmd() - Function sends a command to TZ + * + * @drvdata: pointer to driver data + * @app_handle: handle to tz app + * @is_user_space: 1 if the cmd buffer is in user space, 0 + * otherwise + * @cmd: command buffer to send + * @cmd_len: length of the command buffer + * @rsp: output, will be set to location of response buffer + * @rsp_len: max size of response + * + * Return: 0 on success. + */ +static int send_tz_cmd(struct qbt1000_drvdata *drvdata, + struct qseecom_handle *app_handle, + int is_user_space, + void *cmd, uint32_t cmd_len, + void **rsp, uint32_t rsp_len) +{ + int rc = 0; + void *aligned_cmd; + void *aligned_rsp; + uint32_t aligned_cmd_len; + uint32_t aligned_rsp_len; + + /* init command and response buffers and align lengths */ + aligned_cmd_len = cmd_len; + aligned_rsp_len = rsp_len; + + rc = get_cmd_rsp_buffers(app_handle, + (void **)&aligned_cmd, + &aligned_cmd_len, + (void **)&aligned_rsp, + &aligned_rsp_len); + + if (rc != 0) + goto end; + + if (!aligned_cmd) { + dev_err(drvdata->dev, "%s: Null command buffer\n", + __func__); + rc = -EINVAL; + goto end; + } + + if (is_user_space) { + rc = copy_from_user(aligned_cmd, (void __user *)cmd, + cmd_len); + if (rc != 0) { + pr_err("failure to copy user space buf %d\n", rc); + rc = -EFAULT; + goto end; + } + } else + memcpy(aligned_cmd, cmd, cmd_len); + + /* send cmd to TZ */ + rc = qseecom_send_command(app_handle, + aligned_cmd, + aligned_cmd_len, + aligned_rsp, + aligned_rsp_len); + + if (rc != 0) { + pr_err("failure to send tz cmd %d\n", rc); + goto end; + } + + *rsp = aligned_rsp; + +end: + return rc; +} + +static void purge_finger_events(struct qbt1000_drvdata *drvdata) +{ + int i, fifo_len; + struct fw_event_desc fw_event; + + fifo_len = kfifo_len(&drvdata->fw_events); + + for (i = 0; i < fifo_len; i++) { + if (!kfifo_get(&drvdata->fw_events, &fw_event)) + pr_err("fw events fifo: could not remove oldest item\n"); + else if (fw_event.ev != FW_EVENT_FINGER_DOWN + && fw_event.ev != FW_EVENT_FINGER_UP) + kfifo_put(&drvdata->fw_events, fw_event); + } +} + +static void gpio_report_event(struct qbt1000_drvdata *drvdata, int state) +{ + struct fw_event_desc fw_event; + + pr_debug("gpio %d: last state %d, new state %d\n", + drvdata->fd_gpio.gpio, + drvdata->fd_gpio.last_gpio_state, + state); + + //if (state == drvdata->fd_gpio.last_gpio_state) + // return; + + drvdata->fd_gpio.last_gpio_state = state; + + if (drvdata->fd_ind_mode == FD_IND_MODE_GESTURES) { + pr_debug("tap detected\n"); + /* + * If a gesture IPC was sent but not yet decrypted and + * dealt with mark it as stale and don't report it + */ + drvdata->ipc_is_stale = true; + input_event(drvdata->in_dev, + EV_KEY, KEY_FP_GESTURE_TAP, 1); + input_sync(drvdata->in_dev); + input_event(drvdata->in_dev, + EV_KEY, KEY_FP_GESTURE_TAP, 0); + input_sync(drvdata->in_dev); + } else if (drvdata->fd_ind_mode == FD_IND_MODE_BIOMETRIC) { + if (state && drvdata->fd_gpio.power_key_enabled) { + input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 1); + input_sync(drvdata->in_dev); + input_event(drvdata->in_dev, EV_KEY, KEY_POWER, 0); + input_sync(drvdata->in_dev); + } else if (!drvdata->gestures_enabled) { + input_event(drvdata->in_dev, EV_KEY, + drvdata->fd_gpio.key_code, !!state); + input_sync(drvdata->in_dev); + } + fw_event.ev = state ? FW_EVENT_FINGER_DOWN : FW_EVENT_FINGER_UP; + + spin_lock(&drvdata->fw_events_lock); + if (kfifo_is_full(&drvdata->fw_events)) { + struct fw_event_desc dummy_fw_event; + + pr_warn("fw events fifo: full, dropping oldest item\n"); + if (!kfifo_get(&drvdata->fw_events, &dummy_fw_event)) + pr_err("fw events fifo: could not remove oldest item\n"); + } + + purge_finger_events(drvdata); + + if (!kfifo_put(&drvdata->fw_events, fw_event)) + pr_err("fw events fifo: error adding item\n"); + spin_unlock(&drvdata->fw_events_lock); + + wake_up_interruptible(&drvdata->read_wait_queue); + } else { + pr_err("invalid mode %d\n", drvdata->fd_ind_mode); + } +} + +/* Clear touch status */ +static void qbt1000_touch_clear_mt_status(struct qbt1000_mt_status *m) +{ + int i; + + m->slot = 0; + for (i = 0; i < MAX_TOUCHES; i++) { + m->touches[i].x = -1; + m->touches[i].y = -1; + } +} + +static bool qbt1000_touch_get_state(struct qbt1000_drvdata *drvdata) +{ + int i, state = 0; + struct qbt1000_mt_status *m = &drvdata->mt; + + if (unlikely(!drvdata->sensor_pos.enable)) + goto end; + + for (i = 0; i < MAX_TOUCHES; i++) { + if (m->touches[i].x >= drvdata->sensor_pos.left && + m->touches[i].x <= drvdata->sensor_pos.right && + m->touches[i].y >= drvdata->sensor_pos.top && + m->touches[i].y <= drvdata->sensor_pos.bottom) + state = 1; + + if (m->touches[i].x >= 0 || m->touches[i].y >= 0) + pr_debug("slot: %d, x: %d, y: %d, state: %d", + i, + m->touches[i].x, + m->touches[i].y, + state); + } + +end: + return state; +} + +static void qbt1000_touch_event(struct input_handle *handle, + unsigned int type, unsigned int code, int value) +{ + struct qbt1000_drvdata *drvdata = handle->handler->private; + struct qbt1000_mt_status *m = &drvdata->mt; + struct qbt1000_touch_status *t = &m->touches[m->slot]; + + if (likely(!drvdata->sensor_pos.enable || + (type != EV_SYN && type != EV_ABS))) + goto end; + + switch (code) { + case ABS_MT_SLOT: + m->slot = value; + break; + case ABS_MT_TRACKING_ID: + if (value < 0) { + t->x = -1; + t->y = -1; + } + break; + case ABS_MT_POSITION_X: + t->x = value; + break; + case ABS_MT_POSITION_Y: + t->y = value; + break; + case SYN_REPORT: + gpio_report_event(drvdata, + qbt1000_touch_get_state(drvdata)); + break; + default: + break; + } + +end: + return; +} + +static int qbt1000_touch_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "qbt1000_touch"; + + error = input_register_handle(handle); + if (error) + goto err_free_handle; + + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + pr_info("Connected device: %s (%s at %s)\n", + dev_name(&dev->dev), + dev->name ?: "unknown", + dev->phys ?: "unknown"); + + return 0; + + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; +} + +static void qbt1000_touch_disconnect(struct input_handle *handle) +{ + pr_info("Disconnected device: %s\n", + dev_name(&handle->dev->dev)); + + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id qbt1000_touch_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = {BIT_MASK(EV_ABS)}, + }, + {}, +}; + +MODULE_DEVICE_TABLE(input, qbt1000_touch_ids); + +static struct input_handler qbt1000_touch_handler = { + .event = qbt1000_touch_event, + .connect = qbt1000_touch_connect, + .disconnect = qbt1000_touch_disconnect, + .name = "qbt1000_touch", + .id_table = qbt1000_touch_ids, +}; + +/** + * qbt1000_open() - Function called when user space opens device. + * Successful if driver not currently open. + * @inode: ptr to inode object + * @file: ptr to file object + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_open(struct inode *inode, struct file *file) +{ + int rc = 0; + + struct qbt1000_drvdata *drvdata = container_of(inode->i_cdev, + struct qbt1000_drvdata, + qbt1000_cdev); + file->private_data = drvdata; + + pr_debug("%s begin\n", __func__); + /* disallowing concurrent opens */ + if (!atomic_dec_and_test(&drvdata->available)) { + atomic_inc(&drvdata->available); + rc = -EBUSY; + } + + pr_debug("%s end : %d\n", __func__, rc); + return rc; +} + +/** + * qbt1000_release() - Function called when user space closes device. + + * @inode: ptr to inode object + * @file: ptr to file object + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_release(struct inode *inode, struct file *file) +{ + struct qbt1000_drvdata *drvdata; + + if (!file || !file->private_data) { + pr_err("%s: NULL pointer passed", __func__); + return -EINVAL; + } + drvdata = file->private_data; + atomic_inc(&drvdata->available); + return 0; +} + +/** + * qbt1000_ioctl() - Function called when user space calls ioctl. + * @file: struct file - not used + * @cmd: cmd identifier:QBT1000_LOAD_APP,QBT1000_UNLOAD_APP, + * QBT1000_SEND_TZCMD + * @arg: ptr to relevant structe: either qbt1000_app or + * qbt1000_send_tz_cmd depending on which cmd is passed + * + * Return: 0 on success. Error code on failure. + */ +static long qbt1000_ioctl( + struct file *file, unsigned int cmd, unsigned long arg) +{ + int rc = 0; + void __user *priv_arg = (void __user *)arg; + struct qbt1000_drvdata *drvdata; + + if (!file || !file->private_data) { + pr_err("%s: NULL pointer passed", __func__); + return -EINVAL; + } + + drvdata = file->private_data; + + if (IS_ERR(priv_arg)) { + dev_err(drvdata->dev, "%s: invalid user space pointer %lu\n", + __func__, arg); + return -EINVAL; + } + + mutex_lock(&drvdata->mutex); + + pr_debug("%s %d\n", __func__, cmd); + + switch (cmd) { + case QBT1000_LOAD_APP: + { + struct qbt1000_app app; + struct qseecom_handle *app_handle; + + if (copy_from_user(&app, priv_arg, + sizeof(app)) != 0) { + rc = -EFAULT; + pr_err("failed copy from user space-LOAD\n"); + goto end; + } + + if (!app.app_handle) { + dev_err(drvdata->dev, "%s: LOAD app_handle is null\n", + __func__); + rc = -EINVAL; + goto end; + } + + if (strcmp(app.name, FP_APP_NAME)) { + dev_err(drvdata->dev, "%s: Invalid app name\n", + __func__); + rc = -EINVAL; + goto end; + } + + if (drvdata->app_handle) { + dev_err(drvdata->dev, "%s: LOAD app already loaded, unloading first\n", + __func__); + drvdata->fp_app_handle = 0; + rc = qseecom_shutdown_app(&drvdata->app_handle); + if (rc != 0) { + dev_err(drvdata->dev, "%s: LOAD current app failed to shutdown\n", + __func__); + goto end; + } + } + + pr_debug("app %s load before\n", app.name); + app.name[MAX_NAME_SIZE - 1] = '\0'; + + /* start the TZ app */ + rc = qseecom_start_app( + &drvdata->app_handle, app.name, app.size); + if (rc == 0) { + g_app_buf_size = app.size; + rc = qseecom_set_bandwidth(drvdata->app_handle, + app.high_band_width == 1 ? true : false); + if (rc != 0) { + /* log error, allow to continue */ + pr_err("App %s failed to set bw\n", app.name); + } + } else { + dev_err(drvdata->dev, "%s: Fingerprint Trusted App failed to load\n", + __func__); + goto end; + } + + /* copy a fake app handle to user */ + app_handle = drvdata->app_handle ? + (struct qseecom_handle *)123456 : 0; + rc = copy_to_user((void __user *)app.app_handle, &app_handle, + sizeof(*app.app_handle)); + + if (rc != 0) { + dev_err(drvdata->dev, + "%s: Failed copy 2us LOAD rc:%d\n", + __func__, rc); + rc = -ENOMEM; + goto end; + } + + pr_debug("app %s load after\n", app.name); + + drvdata->fp_app_handle = drvdata->app_handle; + break; + } + case QBT1000_UNLOAD_APP: + { + struct qbt1000_app app; + struct qseecom_handle *app_handle = 0; + + if (copy_from_user(&app, priv_arg, + sizeof(app)) != 0) { + rc = -ENOMEM; + pr_err("failed copy from user space-UNLOAD\n"); + goto end; + } + + if (!app.app_handle) { + dev_err(drvdata->dev, "%s: UNLOAD app_handle is null\n", + __func__); + rc = -EINVAL; + goto end; + } + + rc = copy_from_user(&app_handle, app.app_handle, + sizeof(app_handle)); + + if (rc != 0) { + dev_err(drvdata->dev, + "%s: Failed copy from user space-UNLOAD handle rc:%d\n", + __func__, rc); + rc = -ENOMEM; + goto end; + } + + /* if the app hasn't been loaded already, return err */ + if (!drvdata->app_handle) { + pr_err("app not loaded\n"); + rc = -EINVAL; + goto end; + } + + if (drvdata->fp_app_handle == drvdata->app_handle) + drvdata->fp_app_handle = 0; + + /* set bw & shutdown the TZ app */ + qseecom_set_bandwidth(drvdata->app_handle, + app.high_band_width == 1 ? true : false); + rc = qseecom_shutdown_app(&drvdata->app_handle); + if (rc != 0) { + pr_err("app failed to shutdown\n"); + goto end; + } + + /* copy the app handle (should be null) to user */ + rc = copy_to_user((void __user *)app.app_handle, &app_handle, + sizeof(*app.app_handle)); + + if (rc != 0) { + dev_err(drvdata->dev, + "%s: Failed copy 2us UNLOAD rc:%d\n", + __func__, rc); + rc = -ENOMEM; + goto end; + } + + break; + } + case QBT1000_SEND_TZCMD: + { + struct qbt1000_send_tz_cmd tzcmd; + void *rsp_buf; + + if (copy_from_user(&tzcmd, priv_arg, + sizeof(tzcmd)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + if (tzcmd.req_buf_len > g_app_buf_size || + tzcmd.rsp_buf_len > g_app_buf_size) { + rc = -ENOMEM; + pr_err("invalid cmd buf len, req=%d, rsp=%d\n", + tzcmd.req_buf_len, tzcmd.rsp_buf_len); + goto end; + } + + /* if the app hasn't been loaded already, return err */ + if (!drvdata->app_handle) { + pr_err("app not loaded\n"); + rc = -EINVAL; + goto end; + } + + rc = send_tz_cmd(drvdata, + drvdata->app_handle, 1, + tzcmd.req_buf, tzcmd.req_buf_len, + &rsp_buf, tzcmd.rsp_buf_len); + + if (rc < 0) { + pr_err("failure sending command to tz\n"); + goto end; + } + + /* copy rsp buf back to user space buffer */ + rc = copy_to_user((void __user *)tzcmd.rsp_buf, + rsp_buf, tzcmd.rsp_buf_len); + if (rc != 0) { + pr_err("failed copy 2us rc:%d bytes %d:\n", + rc, tzcmd.rsp_buf_len); + rc = -EFAULT; + goto end; + } + + break; + } + case QBT1000_SET_FINGER_DETECT_KEY: + { + struct qbt1000_set_finger_detect_key set_fd_key; + + if (copy_from_user(&set_fd_key, priv_arg, + sizeof(set_fd_key)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + drvdata->fd_gpio.key_code = set_fd_key.key_code; + break; + } + case QBT1000_CONFIGURE_POWER_KEY: + { + struct qbt1000_configure_power_key power_key; + + if (copy_from_user(&power_key, priv_arg, + sizeof(power_key)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + drvdata->fd_gpio.power_key_enabled = power_key.enable; + break; + } + case QBT1000_ENABLE_GESTURES: + { + struct qbt1000_enable_gestures enable_gestures; + + if (copy_from_user(&enable_gestures, priv_arg, + sizeof(enable_gestures)) + != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + if (enable_gestures.enable) { + drvdata->fd_ind_mode = FD_IND_MODE_GESTURES; + drvdata->gestures_enabled = true; + } else { + drvdata->fd_ind_mode = FD_IND_MODE_BIOMETRIC; + drvdata->gestures_enabled = false; + } + break; + } + case QBT1000_SET_SENSOR_POSITION: + { + struct qbt1000_sensor_pos sensor_pos; + + if (copy_from_user(&sensor_pos, priv_arg, + sizeof(sensor_pos)) != 0) { + rc = -EFAULT; + pr_err("failed copy from user space %d\n", rc); + goto end; + } + + if (sensor_pos.enable && !drvdata->sensor_pos.enable) { + pr_debug("enable: %d, top: %d, bottom: %d, left %d, right: %d)", + sensor_pos.enable, + sensor_pos.top, + sensor_pos.bottom, + sensor_pos.left, + sensor_pos.right); + + if (!drvdata->mt.is_registered) { + qbt1000_touch_handler.private = drvdata; + rc = input_register_handler( + &qbt1000_touch_handler); + drvdata->mt.is_registered = true; + } + qbt1000_touch_clear_mt_status(&drvdata->mt); + drvdata->fd_gpio.last_gpio_state = 0; + drvdata->sensor_pos.top = sensor_pos.top; + drvdata->sensor_pos.bottom = sensor_pos.bottom; + drvdata->sensor_pos.left = sensor_pos.left; + drvdata->sensor_pos.right = sensor_pos.right; + drvdata->sensor_pos.enable = sensor_pos.enable; + } else if (!sensor_pos.enable && drvdata->sensor_pos.enable) { + pr_debug("disable: %d, top: %d, bottom: %d, left %d, right: %d)", + sensor_pos.enable, + sensor_pos.top, + sensor_pos.bottom, + sensor_pos.left, + sensor_pos.right); + + drvdata->sensor_pos.enable = sensor_pos.enable; + drvdata->sensor_pos.top = 0; + drvdata->sensor_pos.bottom = 0; + drvdata->sensor_pos.left = 0; + drvdata->sensor_pos.right = 0; + } + break; + } + default: + pr_err("invalid cmd %d\n", cmd); + rc = -ENOIOCTLCMD; + goto end; + } + +end: + mutex_unlock(&drvdata->mutex); + return rc; +} + +static int get_events_fifo_len_locked(struct qbt1000_drvdata *drvdata) +{ + int len; + unsigned long flags; + + spin_lock_irqsave(&drvdata->fw_events_lock, flags); + len = kfifo_len(&drvdata->fw_events); + spin_unlock_irqrestore(&drvdata->fw_events_lock, flags); + + return len; +} + +static ssize_t qbt1000_read(struct file *filp, char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + struct fw_event_desc fw_event; + struct qbt1000_drvdata *drvdata = filp->private_data; + unsigned long flags; + + if (cnt < sizeof(fw_event.ev)) + return -EINVAL; + + spin_lock_irqsave(&drvdata->fw_events_lock, flags); + while (kfifo_len(&drvdata->fw_events) == 0) { + spin_unlock_irqrestore(&drvdata->fw_events_lock, flags); + + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + pr_debug("fw_events fifo: empty, waiting\n"); + + if (wait_event_interruptible(drvdata->read_wait_queue, + (get_events_fifo_len_locked(drvdata) > 0))) + return -ERESTARTSYS; + + spin_lock_irqsave(&drvdata->fw_events_lock, flags); + } + + if (!kfifo_get(&drvdata->fw_events, &fw_event)) { + spin_unlock_irqrestore(&drvdata->fw_events_lock, flags); + + pr_debug("fw_events fifo: unexpectedly empty\n"); + return -EINVAL; + } + + spin_unlock_irqrestore(&drvdata->fw_events_lock, flags); + + pr_debug("fw_event: %d\n", (int)fw_event.ev); + return copy_to_user(ubuf, &fw_event.ev, sizeof(fw_event.ev)); +} + +static unsigned int qbt1000_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct qbt1000_drvdata *drvdata = filp->private_data; + unsigned int mask = 0; + + poll_wait(filp, &drvdata->read_wait_queue, wait); + + if (kfifo_len(&drvdata->fw_events) > 0) + mask |= (POLLIN | POLLRDNORM); + + return mask; +} + +static const struct file_operations qbt1000_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = qbt1000_ioctl, + .open = qbt1000_open, + .release = qbt1000_release, + .read = qbt1000_read, + .poll = qbt1000_poll +}; + +static int qbt1000_dev_register(struct qbt1000_drvdata *drvdata) +{ + dev_t dev_no; + int ret = 0; + size_t node_size; + char *node_name = QBT1000_DEV; + struct device *dev = drvdata->dev; + struct device *device; + + node_size = strlen(node_name) + 1; + + drvdata->qbt1000_node = devm_kzalloc(dev, node_size, GFP_KERNEL); + if (!drvdata->qbt1000_node) { + ret = -ENOMEM; + goto err_alloc; + } + + strlcpy(drvdata->qbt1000_node, node_name, node_size); + + ret = alloc_chrdev_region(&dev_no, 0, 1, drvdata->qbt1000_node); + if (ret) { + pr_err("alloc_chrdev_region failed %d\n", ret); + goto err_alloc; + } + + cdev_init(&drvdata->qbt1000_cdev, &qbt1000_fops); + + drvdata->qbt1000_cdev.owner = THIS_MODULE; + ret = cdev_add(&drvdata->qbt1000_cdev, dev_no, 1); + if (ret) { + pr_err("cdev_add failed %d\n", ret); + goto err_cdev_add; + } + + drvdata->qbt1000_class = class_create(THIS_MODULE, + drvdata->qbt1000_node); + if (IS_ERR(drvdata->qbt1000_class)) { + ret = PTR_ERR(drvdata->qbt1000_class); + pr_err("class_create failed %d\n", ret); + goto err_class_create; + } + + device = device_create(drvdata->qbt1000_class, NULL, + drvdata->qbt1000_cdev.dev, drvdata, + drvdata->qbt1000_node); + if (IS_ERR(device)) { + ret = PTR_ERR(device); + pr_err("device_create failed %d\n", ret); + goto err_dev_create; + } + + return 0; +err_dev_create: + class_destroy(drvdata->qbt1000_class); +err_class_create: + cdev_del(&drvdata->qbt1000_cdev); +err_cdev_add: + unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1); +err_alloc: + return ret; +} + +/** + * qbt1000_create_input_device() - Function allocates an input + * device, configures it for key events and registers it + * + * @drvdata: ptr to driver data + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_create_input_device(struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + + drvdata->in_dev = input_allocate_device(); + if (drvdata->in_dev == NULL) { + dev_err(drvdata->dev, "%s: input_allocate_device() failed\n", + __func__); + rc = -ENOMEM; + goto end; + } + + drvdata->in_dev->name = QBT1000_IN_DEV_NAME; + drvdata->in_dev->phys = NULL; + drvdata->in_dev->id.bustype = BUS_HOST; + drvdata->in_dev->id.vendor = 0x0001; + drvdata->in_dev->id.product = 0x0001; + drvdata->in_dev->id.version = QBT1000_IN_DEV_VERSION; + + drvdata->in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + drvdata->in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + drvdata->in_dev->keybit[BIT_WORD(KEY_HOMEPAGE)] |= + BIT_MASK(KEY_HOMEPAGE); + drvdata->in_dev->keybit[BIT_WORD(KEY_CAMERA)] |= + BIT_MASK(KEY_CAMERA); + drvdata->in_dev->keybit[BIT_WORD(KEY_VOLUMEDOWN)] |= + BIT_MASK(KEY_VOLUMEDOWN); + drvdata->in_dev->keybit[BIT_WORD(KEY_POWER)] |= + BIT_MASK(KEY_POWER); + drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_UP)] |= + BIT_MASK(KEY_FP_GESTURE_UP); + drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_DOWN)] |= + BIT_MASK(KEY_FP_GESTURE_DOWN); + drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_LEFT)] |= + BIT_MASK(KEY_FP_GESTURE_LEFT); + drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_RIGHT)] |= + BIT_MASK(KEY_FP_GESTURE_RIGHT); + drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_LONG_PRESS)] |= + BIT_MASK(KEY_FP_GESTURE_LONG_PRESS); + drvdata->in_dev->keybit[BIT_WORD(KEY_FP_GESTURE_TAP)] |= + BIT_MASK(KEY_FP_GESTURE_TAP); + + input_set_abs_params(drvdata->in_dev, ABS_X, + 0, + 1000, + 0, 0); + input_set_abs_params(drvdata->in_dev, ABS_Y, + 0, + 1000, + 0, 0); + + rc = input_register_device(drvdata->in_dev); + if (rc) { + dev_err(drvdata->dev, "%s: input_reg_dev() failed %d\n", + __func__, rc); + goto end; + } + +end: + if (rc) + input_free_device(drvdata->in_dev); + return rc; +} + +static void qbt1000_gpio_report_event(struct qbt1000_drvdata *drvdata) +{ + int state; + + state = (__gpio_get_value(drvdata->fd_gpio.gpio) ? 1 : 0) + ^ drvdata->fd_gpio.active_low; + gpio_report_event(drvdata, state); +} + +static void qbt1000_gpio_work_func(struct work_struct *work) +{ + struct qbt1000_drvdata *drvdata = + container_of(work, struct qbt1000_drvdata, fd_gpio.work); + + qbt1000_gpio_report_event(drvdata); + + pm_relax(drvdata->dev); +} + +static irqreturn_t qbt1000_gpio_isr(int irq, void *dev_id) +{ + struct qbt1000_drvdata *drvdata = dev_id; + + if (irq != drvdata->fd_gpio.irq) { + pr_warn("invalid irq %d (expected %d)\n", + irq, drvdata->fd_gpio.irq); + return IRQ_HANDLED; + } + + pm_stay_awake(drvdata->dev); + schedule_work(&drvdata->fd_gpio.work); + + return IRQ_HANDLED; +} + +/** + * qbt1000_ipc_irq_handler() - function processes IPC + * interrupts on its own thread + * @irq: the interrupt that occurred + * @dev_id: pointer to the qbt1000_drvdata + * + * Return: IRQ_HANDLED when complete + */ +static irqreturn_t qbt1000_ipc_irq_handler(int irq, void *dev_id) +{ + uint8_t *msg_buffer; + struct fw_ipc_cmd *rx_cmd; + struct fw_ipc_header *header; + int i, j; + uint32_t rxipc = FP_APP_CMD_RX_IPC; + struct qbt1000_drvdata *drvdata = (struct qbt1000_drvdata *)dev_id; + int rc = 0; + uint32_t retry_count = SEND_TZ_CMD_RETRY_CNT; + unsigned long flags; + + pm_stay_awake(drvdata->dev); + + mutex_lock(&drvdata->mutex); + + if (irq != drvdata->fw_ipc.irq) { + pr_warn("invalid irq %d (expected %d)\n", + irq, drvdata->fw_ipc.irq); + goto end; + } + + pr_debug("firmware interrupt received (irq %d)\n", irq); + + if (!drvdata->fp_app_handle) + goto end; + + /* + * Indicate that IPC is valid (not stale) + * This is relevant only for gestures IPCs + */ + drvdata->ipc_is_stale = false; + + while (retry_count > 0) { + /* + * send the TZ command to fetch the message from firmware + * TZ will process the message if it can + */ + rc = send_tz_cmd(drvdata, drvdata->fp_app_handle, 0, + &rxipc, sizeof(rxipc), + (void *)&rx_cmd, sizeof(*rx_cmd)); + if (rc < 0) { + /* sleep before retry */ + msleep(SEND_TZ_CMD_DELAY); + retry_count -= 1; + continue; + } else { + pr_err("retry_count %d\n", retry_count); + break; + } + } + + if (rc < 0) { + pr_err("failure sending tz cmd %d\n", rxipc); + goto end; + } + + if (rx_cmd->status != 0) { + pr_err("tz command failed to complete\n"); + goto end; + } + + msg_buffer = rx_cmd->msg_data; + + for (j = 0; j < rx_cmd->numMsgs; j++) { + unsigned int key_event_code = 0; + + header = (struct fw_ipc_header *) msg_buffer; + + switch (header->msg_type) { + case IPC_MSG_ID_GESTURE_SWIPE_UP: + key_event_code = KEY_FP_GESTURE_UP; + break; + case IPC_MSG_ID_GESTURE_SWIPE_DOWN: + key_event_code = KEY_FP_GESTURE_DOWN; + break; + case IPC_MSG_ID_GESTURE_SWIPE_LEFT: + key_event_code = KEY_FP_GESTURE_LEFT; + break; + case IPC_MSG_ID_GESTURE_SWIPE_RIGHT: + key_event_code = KEY_FP_GESTURE_RIGHT; + break; + case IPC_MSG_ID_GESTURE_LONG_PRESS: + key_event_code = KEY_FP_GESTURE_LONG_PRESS; + break; + default: + key_event_code = 0; + break; + } + + if (key_event_code != 0) { + pr_debug("geseture detected %d\n", key_event_code); + /* + * Send gesture event if no tap arrived + * since the IPC was sent + */ + if (drvdata->ipc_is_stale == false) { + input_event(drvdata->in_dev, EV_KEY, + key_event_code, 1); + input_sync(drvdata->in_dev); + input_event(drvdata->in_dev, EV_KEY, + key_event_code, 0); + input_sync(drvdata->in_dev); + } + } else { + + /* + * given the IPC message type, search for a + * corresponding event for the driver client. + * If found, add to the events FIFO + */ + for (i = 0; i < ARRAY_SIZE(g_msg_to_event); i++) { + uint32_t msg_type = g_msg_to_event[i].msg_type; + + if (msg_type == header->msg_type) { + enum qbt1000_fw_event ev = + g_msg_to_event[i].fw_event; + struct fw_event_desc fw_ev_desc; + + pr_debug("fw events: add %d\n", + (int) ev); + fw_ev_desc.ev = ev; + + spin_lock_irqsave( + &drvdata->fw_events_lock, + flags); + purge_finger_events(drvdata); + + if (!kfifo_put(&drvdata->fw_events, + fw_ev_desc)) { + pr_err("fw events: fifo full"); + pr_err("drop event %d\n", + (int)ev); + } + + spin_unlock_irqrestore( + &drvdata->fw_events_lock, + flags); + break; + } + } + } + msg_buffer += sizeof(*header) + header->msg_len; + } + wake_up_interruptible(&drvdata->read_wait_queue); +end: + mutex_unlock(&drvdata->mutex); + pm_relax(drvdata->dev); + return IRQ_HANDLED; +} + +static int setup_fd_gpio_irq(struct platform_device *pdev, + struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + int irq; + const char *desc = "qbt_finger_detect"; + + rc = devm_gpio_request_one(&pdev->dev, drvdata->fd_gpio.gpio, + GPIOF_IN, desc); + + if (rc < 0) { + pr_err("failed to request gpio %d, error %d\n", + drvdata->fd_gpio.gpio, rc); + goto end; + } + + irq = gpio_to_irq(drvdata->fd_gpio.gpio); + if (irq < 0) { + rc = irq; + pr_err("unable to get irq number for gpio %d, error %d\n", + drvdata->fd_gpio.gpio, rc); + goto end; + } + + drvdata->fd_gpio.irq = irq; + INIT_WORK(&drvdata->fd_gpio.work, qbt1000_gpio_work_func); + + rc = devm_request_any_context_irq(&pdev->dev, drvdata->fd_gpio.irq, + qbt1000_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + desc, drvdata); + + if (rc < 0) { + pr_err("unable to claim irq %d; error %d\n", + drvdata->fd_gpio.irq, rc); + goto end; + } + +end: + return rc; +} + +static int setup_ipc_irq(struct platform_device *pdev, + struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + const char *desc = "qbt_ipc"; + + drvdata->fw_ipc.irq = gpio_to_irq(drvdata->fw_ipc.gpio); + pr_debug("\nirq %d gpio %d\n", + drvdata->fw_ipc.irq, drvdata->fw_ipc.gpio); + + if (drvdata->fw_ipc.irq < 0) { + rc = drvdata->fw_ipc.irq; + pr_err("no irq for gpio %d, error=%d\n", + drvdata->fw_ipc.gpio, rc); + goto end; + } + + rc = devm_gpio_request_one(&pdev->dev, drvdata->fw_ipc.gpio, + GPIOF_IN, desc); + + if (rc < 0) { + pr_err("failed to request gpio %d, error %d\n", + drvdata->fw_ipc.gpio, rc); + goto end; + } + + rc = devm_request_threaded_irq(&pdev->dev, + drvdata->fw_ipc.irq, + NULL, + qbt1000_ipc_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + desc, + drvdata); + + if (rc < 0) { + pr_err("failed to register for ipc irq %d, rc = %d\n", + drvdata->fw_ipc.irq, rc); + goto end; + } + +end: + return rc; +} + +/** + * qbt1000_read_device_tree() - Function reads device tree + * properties into driver data + * @pdev: ptr to platform device object + * @drvdata: ptr to driver data + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_read_device_tree(struct platform_device *pdev, + struct qbt1000_drvdata *drvdata) +{ + int rc = 0; + uint32_t rate; + int gpio; + enum of_gpio_flags flags; + + /* read clock frequency */ + if (of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &rate) == 0) { + pr_debug("clk frequency %d\n", rate); + drvdata->frequency = rate; + } + + /* read IPC gpio */ + drvdata->fw_ipc.gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,ipc-gpio", 0); + if (drvdata->fw_ipc.gpio < 0) { + rc = drvdata->fw_ipc.gpio; + pr_err("ipc gpio not found, error=%d\n", rc); + goto end; + } + + /** + * TODO: Need to revisit after adding GPIO in DTSI- read + * finger detect GPIO configuration + */ + + gpio = of_get_named_gpio_flags(pdev->dev.of_node, + "qcom,finger-detect-gpio", 0, &flags); + if (gpio < 0) { + pr_err("failed to get gpio flags\n"); + rc = gpio; + goto end; + } + + drvdata->fd_gpio.gpio = gpio; + drvdata->fd_gpio.active_low = flags & OF_GPIO_ACTIVE_LOW; + + /*****************************************************/ + // read QFP_Int2 gpio + qbt1000_int2 = of_get_named_gpio(pdev->dev.of_node, + "qfp-int2", 0); + if (qbt1000_int2 < 0) { + rc = qbt1000_int2; + pr_err("qfp-int2 gpio not found, error=%d\n", rc); + goto end; + } + pr_debug("get qfp-int2 success\n"); + +end: + return rc; +} +bool finger_type = false; +/** + * qbt1000_probe() - Function loads hardware config from device tree + * @pdev: ptr to platform device object + * + * Return: 0 on success. Error code on failure. + */ +static int qbt1000_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct qbt1000_drvdata *drvdata; + int rc = 0; + const char *desc = "qbt1000_int2"; + + pr_info("%s:fp version %x\n", __func__, fp_version); + if ((fp_version != 0x06)) + return -ENODEV; + pr_debug("%s begin\n", __func__); + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = &pdev->dev; + platform_set_drvdata(pdev, drvdata); + + rc = qbt1000_read_device_tree(pdev, drvdata); + if (rc < 0) + goto end; + + rc = devm_gpio_request_one(&pdev->dev, qbt1000_int2, + GPIOF_OUT_INIT_LOW, desc); + if (rc < 0) + goto end; + + atomic_set(&drvdata->available, 1); + + mutex_init(&drvdata->mutex); + spin_lock_init(&drvdata->fw_events_lock); + + rc = qbt1000_dev_register(drvdata); + if (rc < 0) + goto end; + + INIT_KFIFO(drvdata->fw_events); + init_waitqueue_head(&drvdata->read_wait_queue); + + rc = qbt1000_create_input_device(drvdata); + if (rc < 0) + goto end; + + rc = setup_fd_gpio_irq(pdev, drvdata); + if (rc < 0) + goto end; + + rc = setup_ipc_irq(pdev, drvdata); + if (rc < 0) + goto end; + + rc = device_init_wakeup(&pdev->dev, 1); + if (rc < 0) + goto end; + + finger_type = true; + //is_probed = true; + ts_cb_drvdata = drvdata; + +end: + pr_debug("%s : %d\n", __func__, rc); + return rc; +} + +static int qbt1000_remove(struct platform_device *pdev) +{ + struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev); + + if (drvdata->mt.is_registered) + input_unregister_handler(&qbt1000_touch_handler); + + input_unregister_device(drvdata->in_dev); + + mutex_destroy(&drvdata->mutex); + + device_destroy(drvdata->qbt1000_class, drvdata->qbt1000_cdev.dev); + class_destroy(drvdata->qbt1000_class); + cdev_del(&drvdata->qbt1000_cdev); + unregister_chrdev_region(drvdata->qbt1000_cdev.dev, 1); + + device_init_wakeup(&pdev->dev, 0); + + ts_cb_drvdata = NULL; + + return 0; +} + +static int qbt1000_suspend(struct platform_device *pdev, + pm_message_t state) +{ + int rc = 0; + struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev); + + /* + * Returning an error code if driver currently making a TZ call. + * Note: The purpose of this driver is to ensure that the clocks are on + * while making a TZ call. Hence the clock check to determine if the + * driver will allow suspend to occur. + */ + if (!mutex_trylock(&drvdata->mutex)) + return -EBUSY; + + if (drvdata->clock_state) + rc = -EBUSY; + else { + enable_irq_wake(drvdata->fd_gpio.irq); + enable_irq_wake(drvdata->fw_ipc.irq); + } + + mutex_unlock(&drvdata->mutex); + + return rc; +} + +static int qbt1000_resume(struct platform_device *pdev) +{ + struct qbt1000_drvdata *drvdata = platform_get_drvdata(pdev); + + disable_irq_wake(drvdata->fd_gpio.irq); + disable_irq_wake(drvdata->fw_ipc.irq); + + return 0; +} + +static const struct of_device_id qbt1000_match[] = { + { .compatible = "qcom,qbt1000" }, + {} +}; + +static struct platform_driver qbt1000_plat_driver = { + .probe = qbt1000_probe, + .remove = qbt1000_remove, + .suspend = qbt1000_suspend, + .resume = qbt1000_resume, + .driver = { + .name = "qbt1000", + .owner = THIS_MODULE, + .of_match_table = qbt1000_match, + }, +}; + +module_platform_driver(qbt1000_plat_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. QBT1000 driver"); diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9886/Kconfig b/drivers/oneplus/input/touchscreen/Goodix/GT9886/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3d032cc92a9ae8bd1209c48168e53ece720fcc80 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9886/Kconfig @@ -0,0 +1,5 @@ +config TOUCHPANEL_GOODIX_GT9886 + default y + bool "TP goodix gt9886 IC enable or not for OPPO" + ---help--- + say Y to enable driver for Touchpanel useing goodix gt9886 diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9886/Makefile b/drivers/oneplus/input/touchscreen/Goodix/GT9886/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1864f564cac7a1ae6553e0c310a9f1fea1992f39 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9886/Makefile @@ -0,0 +1,3 @@ +#gt9886 touchpanel driver + +obj-y += goodix_drivers_gt9886.o diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9886/goodix_drivers_gt9886.c b/drivers/oneplus/input/touchscreen/Goodix/GT9886/goodix_drivers_gt9886.c new file mode 100755 index 0000000000000000000000000000000000000000..031c46d805e281e832d2323ee9c99ae933795a23 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9886/goodix_drivers_gt9886.c @@ -0,0 +1,5699 @@ +/************************************************************** + * VENDOR_EDIT + * File : goodix_drivers_gt9886.c + * Description: Source file for Goodix GT9886 driver + * Version : 1.0 + * ---------------- Revision History: -------------------------- + * < author > + ****************************************************************/ +#include +#include "../goodix_common.h" +#include "../gtx8_tools.h" +#include "goodix_drivers_gt9886.h" +#include + +//struct chip_data_gt9886 *g_chip_info = NULL; +extern int tp_register_times; +extern struct touchpanel_data *g_tp; +#define PM_QOS_VALUE_TP 200 +extern struct pm_qos_request pm_qos_req_stp; + +//function delcare +static int goodix_reset(void *chip_data); +static u8 goodix_config_version_read(struct chip_data_gt9886 *chip_info); +static void gtx8_check_setting_group(struct gtx8_ts_test *ts_test, struct short_record *r_data); +static int goodix_enable_fingerprint_touchhold(struct chip_data_gt9886 *chip_info, uint32_t enable); +static int goodix_enable_gesture_mask(void *chip_data, uint32_t enable); +static int goodix_power_control(void *chip_data, bool enable); + + +/********** Start of special i2c tranfer interface used for goodix read/write*****************/ +/** + * gtx8_set_i2c_doze_mode - disable or enable doze mode + * @enable: true/flase + * return: 0 - ok; < 0 - error. + * This func must be used in pairs, when you disable doze + * mode, then you must enable it again. + * Between set_doze_false and set_doze_true, do not reset + * IC! + */ +static int goodix_set_i2c_doze_mode(struct i2c_client *client, int enable) +{ +#define GTP_REG_DOZE_CTRL 0x30F0 +#define GTP_REG_DOZE_STAT 0x3100 +#define DOZE_ENABLE_FLAG 0xCC +#define DOZE_DISABLE_FLAG 0xAA +#define DOZE_CLOSE_OK_FLAG 0xBB + int result = -EINVAL; + int i = 0; + u8 w_data = 0, r_data = 0; + static u32 doze_mode_set_count = 0; + static DEFINE_MUTEX(doze_mode_lock); + int retry_times = 0; + + mutex_lock(&doze_mode_lock); + + if (enable) { + if (doze_mode_set_count != 0) { + doze_mode_set_count--; + } + + /*when count equal 0, allow ic enter doze mode*/ + if (doze_mode_set_count == 0) { + w_data = DOZE_ENABLE_FLAG; + for (i = 0; i < 3; i++) { + if (touch_i2c_write_block(client, GTP_REG_DOZE_CTRL, 1, &w_data) >= 0) { + result = 0; + goto exit; + } + usleep_range(1000, 1100); + } + } else { + result = 0; + goto exit; + } + } else { + doze_mode_set_count++; + if (doze_mode_set_count == 1) { + w_data = DOZE_DISABLE_FLAG; + if (touch_i2c_write_block(client, GTP_REG_DOZE_CTRL, 1, &w_data) < 0) { + TPD_INFO("doze mode comunition disable FAILED\n"); + goto exit; + } + usleep_range(8000, 8100); + for (i = 0; i < 20; i++) { + if (touch_i2c_read_block(client, GTP_REG_DOZE_STAT, 1, &r_data) < 0) { + TPD_INFO("doze mode comunition disable FAILED\n"); + goto exit; + } + if (DOZE_CLOSE_OK_FLAG == r_data) { + result = 0; + goto exit; + } else if (DOZE_DISABLE_FLAG != r_data) { + w_data = DOZE_DISABLE_FLAG; + if (touch_i2c_write_block(client, GTP_REG_DOZE_CTRL, 1, &w_data) < 0) { + TPD_INFO("doze mode comunition disable FAILED, 0x%x!=0x%x\n", r_data, DOZE_DISABLE_FLAG); + goto exit; + } + } + retry_times++; + if(retry_times > 5) { + TPD_INFO("doze mode wait flag timeout,should clear int\n"); + w_data = 0; + touch_i2c_write_block(client, 0x4100, 1, &w_data); + } + usleep_range(10000, 11000); + } + TPD_INFO("doze mode disable FAILED\n"); + } else { + result = 0; + goto exit; + } + } + +exit: + mutex_unlock(&doze_mode_lock); + return result; +} + +/* + * goodix_i2c_read_wrapper + * + * */ +static int gt9886_i2c_read(struct i2c_client *client, u16 addr, s32 len, u8 *buffer) +{ + int ret = -EINVAL; + + if (goodix_set_i2c_doze_mode(client, false) != 0) { + TPD_INFO("gtx8 i2c read:0x%04x ERROR, disable doze mode FAILED\n", addr); + } + ret = touch_i2c_read_block(client, addr, len, buffer); + + if (goodix_set_i2c_doze_mode(client, true) != 0) + TPD_INFO("gtx8 i2c read:0x%04x ERROR, enable doze mode FAILED\n", addr); + + return ret; +} + +static int gt9886_i2c_write(struct i2c_client *client, u16 addr, s32 len, u8 *buffer) +{ + int ret = -EINVAL; + + if (goodix_set_i2c_doze_mode(client, false) != 0) { + TPD_INFO("gtx8 i2c write:0x%04x ERROR, disable doze mode FAILED\n", addr); + } + ret = touch_i2c_write_block(client, addr, len, buffer); + + if (goodix_set_i2c_doze_mode(client, true) != 0) { + TPD_INFO("gtx8 i2c write:0x%04x ERROR, enable doze mode FAILED\n", addr); + } + + return ret; +} + +/* + *goodix_i2c_read_dbl_check----used to double read and check the reading data + *@client : Handle to slave device + *@addr : address of register where to start read + *@buffer : buf used to store data read from register + *@len : data length we want to read + return 0: success, non-0: failed + */ +static int goodix_i2c_read_dbl_check(struct i2c_client *client, u16 addr, u8 *buffer, s32 len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + int ret = -1; + + if (len > 16) { + TPD_INFO("i2c_read_dbl_check length %d is too long, exceed %zu\n", len, sizeof(buf)); + return ret; + } + + memset(buf, 0xAA, sizeof(buf)); + ret = gt9886_i2c_read(client, addr, len, buf); + if (ret < 0) { + return ret; + } + + msleep(5); + memset(confirm_buf, 0, sizeof(confirm_buf)); + ret = gt9886_i2c_read(client, addr, len, confirm_buf); + if (ret < 0) { + return ret; + } + + if (!memcmp(buf, confirm_buf, len)) { + memcpy(buffer, confirm_buf, len); + return 0; + } + + TPD_INFO("i2c read 0x%04X, %d bytes, double check failed!\n", addr, len); + + return 1; +} + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +extern unsigned int upmu_get_rgs_chrdet(void); +static int goodix_get_usb_state(void) +{ + int ret = 0; + ret = upmu_get_rgs_chrdet(); + TPD_INFO("%s get usb status %d\n", __func__, ret); + return ret; +} +#else +static int goodix_get_usb_state(void) +{ + return 0; +} +#endif + +/* + * goodix_send_cmd----send cmd to Goodix ic to control it's function + * @chip_data: Handle to slave device + * @cmd: value for cmd reg(0x8040) + * @data:value for data reg(0x8041) + * Return 0: succeed, non-0: failed. + */ + +static DEFINE_MUTEX(cmd_mutex); +s32 goodix_send_cmd(void *chip_data, u8 cmd, u8 data) +{ + s32 ret = -1; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + u8 buffer[3] = { cmd, data, 0 }; + u8 buf_read_back = 0; + int retry = 20; + int retry_times = 0; + + /* cmd format: + * reg:0x6f68 cmd control(diffrent cmd indicates diffrent setting for touch IC ) + * reg:0x6f69 data reg(Correspond with 0x8040) + * reg:0x6f6a checksum (sum(0x8040~0x8042) == 0) */ + mutex_lock(&cmd_mutex); + buffer[2] = (u8) ((0 - cmd - data) & 0xFF); + + if (goodix_set_i2c_doze_mode(chip_info->client, false) != 0) { + TPD_INFO("%s: disable doze mode FAILED\n", __func__); + } + ret = touch_i2c_write_block(chip_info->client, chip_info->reg_info.GTP_REG_CMD1, 2, &buffer[1]); + if (ret < 0) { + TPD_INFO("%s send cmd failed,ret:%d\n", __func__, ret); + goto exit; + } + ret = touch_i2c_write_block(chip_info->client, chip_info->reg_info.GTP_REG_CMD, 1, &buffer[0]); + if (ret < 0) { + TPD_INFO("%s send cmd failed,ret:%d\n", __func__, ret); + goto exit; + } + usleep_range(8000, 8100); + while(retry--) { + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_CMD, 1, &buf_read_back); + if (ret < 0) { + usleep_range(10000, 11000); + TPD_INFO("%s,read back failed\n", __func__); + continue; + } + if (buf_read_back != cmd || cmd == TS_CMD_REG_READY) { + break; + } else { + TPD_DEBUG("%s: cmd isn't been handle, wait for it at: %d, readbak: 0x%x\n", __func__, retry, buf_read_back); + } + retry_times++; + if (retry_times > 5) { + TPD_INFO("%s: wait cmd flag failed, clear int\n", __func__); + buf_read_back = 0; + touch_i2c_write_block(chip_info->client, 0x4100, 1, &buf_read_back); + } + usleep_range(10000, 11000); + } + if (retry) { + ret = 0; + } else { + TPD_INFO("%s: cmd send to ic,but ic isn't handle it\n", __func__); + ret = -1; + } + +exit: + if (goodix_set_i2c_doze_mode(chip_info->client, true) != 0) { + TPD_INFO("%s: enable doze mode FAILED\n", __func__); + ret = -1; + } + + mutex_unlock(&cmd_mutex); + + return ret; +} +/*********** End of special i2c tranfer interface used for goodix read/write******************/ + + +/********* Start of function that work for touchpanel_operations callbacks***************/ +static int goodix_clear_irq(void *chip_data) +{ + int ret = -1; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + u8 clean_flag = 0; + + if (!gt8x_rawdiff_mode) { + ret = touch_i2c_write_block(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, &clean_flag); + if (ret < 0) { + TPD_INFO("I2C write end_cmd error!\n"); + } + } + + return ret; +} + +static void getSpecialCornerPoint(uint8_t *buf, int n, struct Coordinate *point) +{ + int x, y, i; + + point[0].x = (buf[0] & 0xFF) | (buf[1] & 0x0F) << 8; + point[0].y = (buf[2] & 0xFF) | (buf[3] & 0x0F) << 8; + point[1] = point[0]; + point[2] = point[0]; + point[3] = point[0]; + for (i = 0; i < n; i++) { + x = (buf[0 + 4 * i] & 0xFF) | (buf[1 + 4 * i] & 0x0F) << 8; + y = (buf[2 + 4 * i] & 0xFF) | (buf[3 + 4 * i] & 0x0F) << 8; + if (point[3].x < x) { //xmax + point[3].x = x; + point[3].y = y; + } + if (point[1].x > x) { //xmin + point[1].x = x; + point[1].y = y; + } + if (point[2].y < y) { //ymax + point[2].y = y; + point[2].x = x; + } + if (point[0].y > y) { //ymin + point[0].y = y; + point[0].x = x; + } + } +} + +static int clockWise(uint8_t *buf, int n) +{ + int i, j, k; + int count = 0; + struct Coordinate p[3]; + long int z; + + if (n < 3) + return 1; + for (i = 0; i < n; i++) { + j = (i + 1) % n; + k = (i + 2) % n; + p[0].x = (buf[0 + 4 * i] & 0xFF) | (buf[1 + 4 * i] & 0x0F) << 8; + p[0].y = (buf[2 + 4 * i] & 0xFF) | (buf[3 + 4 * i] & 0x0F) << 8; + p[1].x = (buf[0 + 4 * j] & 0xFF) | (buf[1 + 4 * j] & 0x0F) << 8; + p[1].y = (buf[2 + 4 * j] & 0xFF) | (buf[3 + 4 * j] & 0x0F) << 8; + p[2].x = (buf[0 + 4 * k] & 0xFF) | (buf[1 + 4 * k] & 0x0F) << 8; + p[2].y = (buf[2 + 4 * k] & 0xFF) | (buf[3 + 4 * k] & 0x0F) << 8; + if ((p[0].x == p[1].x) && (p[1].x == p[1].y)) + continue; + z = (p[1].x - p[0].x) * (p[2].y - p[1].y); + z -= (p[1].y - p[0].y) * (p[2].x - p[1].x); + if (z < 0) + count--; + else if (z > 0) + count++; + } + + TPD_INFO("ClockWise count = %d\n", count); + + if (count > 0) + return 1; + else + return 0; +} + +static void goodix_esd_check_enable(struct chip_data_gt9886 *chip_info, bool enable) +{ + TPD_INFO("%s %s\n", __func__, enable ? "enable" : "disable"); + /* enable/disable esd check flag */ + chip_info->esd_check_enabled = enable; +} + +/* +static int goodix_enter_sleep(struct chip_data_gt9886 *chip_info, bool config) +{ + s32 retry = 0; + + if (config) { + while (retry++ < 3) { + if (!goodix_send_cmd(chip_info, GTP_CMD_SLEEP, 0)) { + chip_info->halt_status = true; + TPD_INFO("enter sleep mode!\n"); + return 0; + } + msleep(10); + } + } + + if (retry >= 3) { + TPD_INFO("Enter sleep mode failed.\n"); + } + + return -1; +} +*/ +static int goodix_enable_gesture(struct chip_data_gt9886 *chip_info, bool enable) +{ + int ret = -1; + + TPD_INFO("%s, gesture enable = %d\n", __func__, enable); + + if (enable) { + ret = goodix_send_cmd(chip_info, GTP_CMD_GESTURE_ON, 1); + } else { + ret = goodix_send_cmd(chip_info, GTP_CMD_GESTURE_OFF, 0); + } + + return ret; +} + + +static int goodix_enable_edge_limit(struct chip_data_gt9886 *chip_info, int state) +{ + int ret = -1; + + TPD_INFO("%s, direction is %d\n", __func__, g_tp->limit_switch); + if (g_tp->limit_switch ==1)//LANDSCAPE 90 + ret = goodix_send_cmd(chip_info, GTM_CMD_EDGE_LIMIT_LANDSCAPE, 0x00); + else if (g_tp->limit_switch == 3)//LANDSCAPE 270 + ret = goodix_send_cmd(chip_info, GTM_CMD_EDGE_LIMIT_LANDSCAPE, 0x01); + else + ret = goodix_send_cmd(chip_info, GTM_CMD_EDGE_LIMIT_VERTICAL, 0x00); + return ret; +} + + +static int goodix_enable_charge_mode(struct chip_data_gt9886 *chip_info, bool enable) +{ + int ret = -1; + + TPD_INFO("%s, charge mode enable = %d\n", __func__, enable); + + if (enable) { + ret = goodix_send_cmd(chip_info, GTP_CMD_CHARGER_ON, 0); + } else { + ret = goodix_send_cmd(chip_info, GTP_CMD_CHARGER_OFF, 0); + } + + return ret; +} + +static int goodix_enable_game_mode(struct chip_data_gt9886 *chip_info, bool enable) +{ + int ret = 0; + + TPD_INFO("%s, game mode enable = %d\n", __func__, enable); + if(enable) { + ret = goodix_send_cmd(chip_info, GTP_CMD_GAME_MODE, 0x01); + TPD_INFO("%s: GTP_CMD_ENTER_GAME_MODE\n", __func__); + } else { + ret = goodix_send_cmd(chip_info, GTP_CMD_GAME_MODE, 0x00); + TPD_INFO("%s: GTP_CMD_EXIT_GAME_MODE\n", __func__); + } + + return ret; +} + +static int goodix_reset_esd_status(struct chip_data_gt9886 *chip_info) +{ + /* reset esd state */ + u8 value = 0xAA; + int ret; + + if (chip_info->is_power_down) { //power off state, no need reset + return 0; + } + + ret = gt9886_i2c_write(chip_info->client, chip_info->reg_info.GTP_REG_ESD_WRITE, 1, &value); + if (ret < 0) { + TPD_INFO("%s: TP set_reset_status failed\n", __func__); + return ret; + } + + return 0; +} + +static s32 goodix_read_version(struct chip_data_gt9886 *chip_info, struct panel_info *panel_data) +{ + s32 ret = -1; + u8 buf[72] = {0}; + u32 mask_id = 0; + u32 patch_id = 0; + u8 product_id[5] = {0}; + u8 sensor_id = 0; + //u8 match_opt = 0; + int i, retry = 3; + u8 checksum = 0; + struct goodix_version_info *ver_info = &chip_info->ver_info; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + while (retry--) { + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_PRODUCT_VER, sizeof(buf), buf); + if (ret > 0) { + checksum = 0; + + for (i = 0; i < sizeof(buf); i++) { + checksum += buf[i]; + } + + if (checksum == 0 && /* first 3 bytes must be number or char */ + IS_NUM_OR_CHAR(buf[9]) && IS_NUM_OR_CHAR(buf[10]) && IS_NUM_OR_CHAR(buf[11]) && buf[21] != 0xFF) { /*sensor id == 0xFF, retry */ + break; + } else { + TPD_INFO("product version data is error\n"); + } + } else { + TPD_INFO("Read product version from 0x452C failed\n"); + } + + TPD_DEBUG("Read product version retry = %d\n", retry); + msleep(100); + } + + if (retry <= 0) { + if (ver_info) + ver_info->sensor_id = 0; + TPD_INFO("Maybe the firmware of ic is error\n"); + goodix_set_i2c_doze_mode(chip_info->client, true); + return -1; + } + + mask_id = (u32) ((buf[6] << 16) | (buf[7] << 8 ) | buf[8]); + patch_id = (u32) ((buf[17] << 24) | (buf[18] << 16) | buf[19] << 8 | buf[20]); + memcpy(product_id, &buf[9], 4); + sensor_id = buf[21] & 0x0F; + //match_opt = (buf[10] >> 4) & 0x0F; + + TPD_INFO("goodix fw VERSION:GT%s(Product)_%08X(Patch)_%06X(MaskID)_%02X(SensorID)\n", product_id, patch_id, mask_id, sensor_id); + + if (ver_info != NULL) { + ver_info->mask_id = mask_id; + ver_info->patch_id = patch_id; + memcpy(ver_info->product_id, product_id, 5); + ver_info->sensor_id = sensor_id; + //ver_info->match_opt = match_opt; + } + + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + + return patch_id; +} + +static int goodix_check_cfg_valid(u8 *cfg, int length) +{ + int ret; + u8 bag_num; + u8 checksum; + int i, j; + int bag_start = 0; + int bag_end = 0; + if (!cfg || length < TS_CFG_HEAD_LEN) { + TPD_INFO("cfg is INVALID, len:%d", length); + ret = -EINVAL; + goto exit; + } + + checksum = 0; + for (i = 0; i < TS_CFG_HEAD_LEN; i++) + checksum += cfg[i]; + if (checksum != 0) { + TPD_INFO("cfg head checksum ERROR, ic type:normandy, checksum:0x%02x", + checksum); + ret = -EINVAL; + goto exit; + } + bag_num = cfg[TS_CFG_BAG_NUM_INDEX]; + bag_start = TS_CFG_BAG_START_INDEX; + + TPD_INFO("cfg bag_num:%d, cfg length:%d", bag_num, length); + + /*check each bag's checksum*/ + for (j = 0; j < bag_num; j++) { + if (bag_start >= length - 1) { + TPD_INFO("ERROR, overflow!!bag_start:%d, cfg_len:%d", bag_start, length); + ret = -EINVAL; + goto exit; + } + + bag_end = bag_start + cfg[bag_start + 1] + 3; + + checksum = 0; + if (bag_end > length) { + TPD_INFO("ERROR, overflow!!bag:%d, bag_start:%d, bag_end:%d, cfg length:%d", + j, bag_start, bag_end, length); + ret = -EINVAL; + goto exit; + } + for (i = bag_start; i < bag_end; i++) + checksum += cfg[i]; + if (checksum != 0) { + TPD_INFO("cfg INVALID, bag:%d checksum ERROR:0x%02x", j, checksum); + ret = -EINVAL; + goto exit; + } + bag_start = bag_end; + } + + ret = 0; + TPD_INFO("configuration check SUCCESS"); + +exit: + return ret; +} + + +static int goodix_wait_cfg_cmd_ready(struct chip_data_gt9886 *chip_info, + u8 right_cmd, u8 send_cmd) +{ + int try_times = 0; + u8 cmd_flag = 0; + u8 cmd_buf[3] = {0}; + u16 command_reg = chip_info->reg_info.GTP_REG_CMD; + + for (try_times = 0; try_times < TS_WAIT_CFG_READY_RETRY_TIMES; try_times++) { + if (gt9886_i2c_read(chip_info->client, command_reg, 3, cmd_buf) < 0) { + TPD_INFO("Read cmd_reg error"); + return -EINVAL; + } + cmd_flag = cmd_buf[0]; + if (cmd_flag == right_cmd) { + return 0; + } else if (cmd_flag != send_cmd) { + TPD_INFO("Read cmd_reg data abnormal,return:0x%02X, 0x%02X, 0x%02X, send again", + cmd_buf[0], cmd_buf[1], cmd_buf[2]); + if (goodix_send_cmd(chip_info, send_cmd, 0)) { + TPD_INFO("Resend cmd 0x%02X FAILED", send_cmd); + return -EINVAL; + } + } + usleep_range(10000, 11000); + } + + return -EINVAL; +} + + +static int goodix_send_large_config(struct chip_data_gt9886 *chip_info, u8 *config, int cfg_len) +{ + int r = 0; + int try_times = 0; + u8 buf = 0; + u16 command_reg = chip_info->reg_info.GTP_REG_CMD; + u16 cfg_reg = chip_info->reg_info.GTP_REG_CONFIG_DATA ; + + /*1. Inquire command_reg until it's free*/ + for (try_times = 0; try_times < TS_WAIT_CMD_FREE_RETRY_TIMES; try_times++) { + if (gt9886_i2c_read(chip_info->client, command_reg, 1, &buf) >= 0 && buf == TS_CMD_REG_READY) + break; + usleep_range(10000, 11000); + } + if (try_times >= TS_WAIT_CMD_FREE_RETRY_TIMES) { + TPD_INFO("Send large cfg FAILED, before send, reg:0x%04x is not 0xff", command_reg); + r = -EINVAL; + goto exit; + } + + /*2. send "start write cfg" command*/ + if (goodix_send_cmd(chip_info, COMMAND_START_SEND_LARGE_CFG, 0)) { + TPD_INFO("Send large cfg FAILED, send COMMAND_START_SEND_LARGE_CFG ERROR"); + r = -EINVAL; + goto exit; + } + + /*3. wait ic set command_reg to 0x82*/ + if (goodix_wait_cfg_cmd_ready(chip_info, COMMAND_SEND_CFG_PREPARE_OK, COMMAND_START_SEND_LARGE_CFG)) { + TPD_INFO("Send large cfg FAILED, reg:0x%04x is not 0x82", command_reg); + r = -EINVAL; + goto exit; + } + + /*4. write cfg*/ + if (gt9886_i2c_write(chip_info->client, cfg_reg, cfg_len, config) < 0) { + TPD_INFO("Send large cfg FAILED, write cfg to fw ERROR"); + r = -EINVAL; + goto exit; + } + + /*5. send "end send cfg" command*/ + if (goodix_send_cmd(chip_info, COMMAND_END_SEND_CFG, 0)) { + TPD_INFO("Send large cfg FAILED, send COMMAND_END_SEND_CFG ERROR"); + r = -EINVAL; + goto exit; + } + + /*6. wait ic set command_reg to 0xff*/ + for (try_times = 0; try_times < TS_WAIT_CMD_FREE_RETRY_TIMES; try_times++) { + if (gt9886_i2c_read(chip_info->client, command_reg, 1, &buf) >= 0 && buf == TS_CMD_REG_READY) + break; + usleep_range(10000, 11000); + } + if (try_times >= TS_WAIT_CMD_FREE_RETRY_TIMES) { + TPD_INFO("Send large cfg FAILED, after send, reg:0x%04x is not 0xff", command_reg); + r = -EINVAL; + goto exit; + } + msleep(100); + TPD_INFO("Send large cfg SUCCESS"); + r = 0; + +exit: + return r; +} + +static s32 goodix_send_config(struct chip_data_gt9886 *chip_info, u8 *config, int cfg_len) +{ + int ret = 0; + static DEFINE_MUTEX(config_lock); + + if (!config) { + TPD_INFO("Null config data"); + return -EINVAL; + } + + /*check configuration valid*/ + ret = goodix_check_cfg_valid(config, cfg_len); + if (ret != 0) { + TPD_INFO("cfg check FAILED"); + return -EINVAL; + } + + TPD_INFO("ver:%02xh,size:%d", config[0], cfg_len); + + mutex_lock(&config_lock); + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + ret = goodix_send_large_config(chip_info, config, cfg_len); + + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + + if (ret != 0) + TPD_INFO("send_cfg FAILED, cfg_len:%d", cfg_len); + + mutex_unlock(&config_lock); + + return ret; +} + +static s32 goodix_request_event_handler(struct chip_data_gt9886 *chip_info) +{ + s32 ret = -1; + u8 rqst_data = 0; + + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_RQST, 1, &rqst_data); + if (ret < 0) { + TPD_INFO("%s: i2c transfer error.\n", __func__); + return -1; + } + + TPD_INFO("%s: request state:0x%02x.\n", __func__, rqst_data); + + switch (rqst_data) { + case GTP_RQST_CONFIG: + TPD_INFO("HW request config.\n"); + ret = goodix_send_config(chip_info, chip_info->normal_cfg.data, chip_info->normal_cfg.length); + if (ret) { + TPD_INFO("request config, send config faild.\n"); + } + break; + + case GTP_RQST_RESET: + TPD_INFO("%s: HW requset reset.\n", __func__); + goodix_reset(chip_info); + break; + + case GTP_RQST_BASELINE: + TPD_INFO("%s: HW request baseline.\n", __func__); + break; + + case GTP_RQST_FRE: + TPD_INFO("%s: HW request frequence.\n", __func__); + break; + + case GTP_RQST_IDLE: + TPD_INFO("%s: HW request idle.\n", __func__); + break; + + default: + TPD_INFO("%s: Unknown hw request:%d.\n", __func__, rqst_data); + break; + } + + rqst_data = GTP_RQST_RESPONDED; + ret = touch_i2c_write_block(chip_info->client, chip_info->reg_info.GTP_REG_RQST, 1, &rqst_data); + if (ret) { + TPD_INFO("%s: failed to write rqst_data:%d.\n", __func__, rqst_data); + } + + return 0; +} + +/*#define getU32(a) ((u32)getUint((u8 *)(a), 4)) +#define getU16(a) ((u16)getUint((u8 *)(a), 2)) +static u32 getUint(u8 * buffer, int len) +{ +u32 num = 0; +int i; +for (i = 0; i < len; i++) { +num <<= 8; +num += buffer[i]; +} + +return num; +}*/ + +void goodix_reset_via_gpio(struct chip_data_gt9886 *chip_info) +{ + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + udelay(2000); + gpio_direction_output(chip_info->hw_res->reset_gpio, 1); + //msleep(10); + usleep_range(250,260); + chip_info->halt_status = false; //reset this flag when ic reset + } else { + TPD_INFO("reset gpio is invalid\n"); + } +} + +static int goodix_reset(void *chip_data) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + TPD_INFO("%s.\n", __func__); + + goodix_reset_via_gpio(chip_info); + + ret = goodix_reset_esd_status(chip_info); + if (ret < 0) { + TPD_INFO("goodix reset esd status failed\n"); + return ret; + } + + return ret; +} + +int goodix_get_channel_num(struct i2c_client *client, u32 *sen_num, u32 *drv_num) +{ + int ret = -1; + u8 buf[2] = {0}; + + ret = gt9886_i2c_read(client, SENSOR_NUM_ADDR, 1, buf); + if (ret < 0) { + TPD_INFO("Read sen_num fail."); + return ret; + } + + *sen_num = buf[0]; + + ret = gt9886_i2c_read(client, DRIVER_GROUP_A_NUM_ADDR, 2, buf); + if (ret < 0) { + TPD_INFO("Read drv_num fail."); + return ret; + } + + *drv_num = buf[0] + buf[1]; + TPD_INFO("sen_num : %d, drv_num : %d", *sen_num, *drv_num); + + return 0; +} + +/*********** End of function that work for touchpanel_operations callbacks***************/ + + +/********* Start of implementation of touchpanel_operations callbacks********************/ +static int goodix_ftm_process(void *chip_data) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + TPD_INFO("%s is called!\n", __func__); + tp_powercontrol_2v8(chip_info->hw_res, false); + tp_powercontrol_1v8(chip_info->hw_res, false); + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, false); + } + + return 0; +} + +static int goodix_get_vendor(void *chip_data, struct panel_info *panel_data) +{ + int len = 0; + char manu_temp[MAX_DEVICE_MANU_LENGTH] = "HD_"; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + len = strlen(panel_data->fw_name); + if ((len > 3) && (panel_data->fw_name[len-3] == 'i') && \ + (panel_data->fw_name[len-2] == 'm') && (panel_data->fw_name[len-1] == 'g')) { + panel_data->fw_name[len-3] = 'b'; + panel_data->fw_name[len-2] = 'i'; + panel_data->fw_name[len-1] = 'n'; + } + chip_info->tp_type = panel_data->tp_type; + chip_info->p_tp_fw = panel_data->manufacture_info.version; + strlcat(manu_temp, panel_data->manufacture_info.manufacture, MAX_DEVICE_MANU_LENGTH); + strncpy(panel_data->manufacture_info.manufacture, manu_temp, MAX_DEVICE_MANU_LENGTH); + TPD_INFO("chip_info->tp_type = %d, panel_data->fw_name = %s\n", chip_info->tp_type, panel_data->fw_name); + + return 0; +} + +static int goodix_get_chip_info(void *chip_data) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + struct goodix_register *reg_info = &chip_info->reg_info; + + reg_info->GTP_REG_FW_CHK_MAINSYS = 0x21E4; //if chip run in patch + //reg_info->GTP_REG_FW_CHK_SUBSYS = 0x5095; + reg_info->GTP_REG_CONFIG_DATA = 0x6F78; //cfg_addr + reg_info->GTP_REG_READ_COOR = 0x4100; //read_coor + reg_info->GTP_REG_WAKEUP_GESTURE = 0x4100; //read_gesture_info + reg_info->GTP_REG_GESTURE_COOR = 0x4128; //read_gesture_coor + reg_info->GTP_REG_CMD = 0x6F68; //command + reg_info->GTP_REG_CMD1 = 0x6F69; + reg_info->GTP_REG_RQST = 0x6F6D; //request by FW + //reg_info->GTP_REG_NOISE_DETECT = 0x804B; + reg_info->GTP_REG_PRODUCT_VER = 0x452C; //product version reg + reg_info->GTP_REG_ESD_WRITE = 0x30F3; //ESD write reg + reg_info->GTP_REG_ESD_READ = 0x3103; //ESD read reg + reg_info->GTP_REG_DEBUG = 0x608B; //debug log enable reg + reg_info->GTP_REG_DOWN_DIFFDATA = 0xAFB0; //down diff log + reg_info->GTP_REG_EDGE_INFO = 0x4154; //read edge points' info + + reg_info->GTP_REG_RAWDATA = 0x8FA0; //rawdata_reg + reg_info->GTP_REG_DIFFDATA = 0x9D20; //diffdata_reg + reg_info->GTP_REG_BASEDATA = 0xA980; //basedata_reg + + //return goodix_set_reset_status(chip_info); + return 0; +} + +static int goodix_power_control(void *chip_data, bool enable) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + if (true == enable) { + ret = tp_powercontrol_1v8(chip_info->hw_res, true); + if (ret) + return -1; + ret = tp_powercontrol_2v8(chip_info->hw_res, true); + if (ret) + return -1; + //msleep(20); + usleep_range(250,260); + goodix_reset_via_gpio(chip_info); + chip_info->is_power_down = false; + } else { + ret = tp_powercontrol_2v8(chip_info->hw_res, false); + if (ret) + return -1; + ret = tp_powercontrol_1v8(chip_info->hw_res, false); + if (ret) + return -1; + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + } + chip_info->is_power_down = true; + } + + return ret; +} + +static fw_check_state goodix_fw_check(void *chip_data, struct resolution_info *resolution_info, struct panel_info *panel_data) +{ + int retry = 2; + int ret = 0; + u8 reg_val[2] = {0}; + u32 fw_ver = 0; + u8 cfg_ver = 0; + //char dev_version[MAX_DEVICE_VERSION_LENGTH] = {0}; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + // TODO need confirm fw state check method + + do { + ret = goodix_i2c_read_dbl_check(chip_info->client, chip_info->reg_info.GTP_REG_FW_CHK_MAINSYS, reg_val, 1); + + if (ret < 0) { + TPD_INFO("%s,check i2c error!\n", __func__); + return ret; + } + if (reg_val[0] != 0xFC) { + TPD_INFO("Check fw status failed: reg[0x21e4] = 0x%2X!\n", reg_val[0]); + } else { + break; + } + } while(--retry); + + if (!retry) + return FW_ABNORMAL; + + fw_ver = goodix_read_version(chip_info, panel_data); + if (ret < 0) { + TPD_INFO("%s: goodix read version failed\n", __func__); + return FW_ABNORMAL; + } + + cfg_ver = goodix_config_version_read(chip_info); + + if (panel_data->manufacture_info.version) { + //panel_data->TP_FW = cfg_ver | (fw_ver & 0xFF) << 8; + //sprintf(dev_version, "%04x", panel_data->TP_FW); + //strlcpy(&(panel_data->manufacture_info.version[7]), dev_version, 5); + panel_data->TP_FW = fw_ver; + sprintf(panel_data->manufacture_info.version, "0x%x", panel_data->TP_FW); + } + + TPD_INFO("%s: panel_data->TP_FW = 0x%x \n", __func__, panel_data->TP_FW); + return FW_NORMAL; +} + +/*****************start of GT9886's update function********************/ + +/** + * goodix_parse_firmware - parse firmware header infomation + * and subsystem infomation from firmware data buffer + * + * @fw_data: firmware struct, contains firmware header info + * and firmware data. + * return: 0 - OK, < 0 - error + */ +static int goodix_parse_firmware(struct firmware_data *fw_data) +{ + const struct firmware *firmware; + struct firmware_info *fw_info; + unsigned int i, fw_offset, info_offset; + u16 checksum; + int r = 0; + + if (!fw_data || !fw_data->firmware) { + TPD_INFO("Invalid firmware data"); + return -EINVAL; + } + fw_info = &fw_data->fw_info; + + /* copy firmware head info */ + firmware = fw_data->firmware; + if (firmware->size < FW_SUBSYS_INFO_OFFSET) { + TPD_INFO("Invalid firmware size:%zu", firmware->size); + r = -EINVAL; + goto err_size; + } + memcpy(fw_info, firmware->data, FW_SUBSYS_INFO_OFFSET); + + /* check firmware size */ + fw_info->size = be32_to_cpu(fw_info->size); // Notice here + if (firmware->size != fw_info->size + 6) { + TPD_INFO("Bad firmware, size not match"); + r = -EINVAL; + goto err_size; + } + + /* calculate checksum, note: sum of bytes, but check + * by u16 checksum */ + for (i = 6, checksum = 0; i < firmware->size; i++) + checksum += firmware->data[i]; + + /* byte order change, and check */ + fw_info->checksum = be16_to_cpu(fw_info->checksum); + if (checksum != fw_info->checksum) { + TPD_INFO("Bad firmware, cheksum error"); + r = -EINVAL; + goto err_size; + } + + if (fw_info->subsys_num > FW_SUBSYS_MAX_NUM) { + TPD_INFO("Bad firmware, invalid subsys num: %d", fw_info->subsys_num); + r = -EINVAL; + goto err_size; + } + + /* parse subsystem info */ + fw_offset = FW_HEADER_SIZE; + for (i = 0; i < fw_info->subsys_num; i++) { + info_offset = FW_SUBSYS_INFO_OFFSET + i * FW_SUBSYS_INFO_SIZE; + fw_info->subsys[i].type = firmware->data[info_offset]; + fw_info->subsys[i].size = be32_to_cpup((__be32 *)&firmware->data[info_offset + 1]); + fw_info->subsys[i].flash_addr = be16_to_cpup((__be16 *)&firmware->data[info_offset + 5]); + + if (fw_offset > firmware->size) { + TPD_INFO("Sybsys offset exceed Firmware size"); + goto err_size; + } + + fw_info->subsys[i].data = firmware->data + fw_offset; + fw_offset += fw_info->subsys[i].size; + } + + TPD_INFO("Firmware package protocol: V%u", fw_info->protocol_ver); + TPD_INFO("Fimware PID:GT%s", fw_info->fw_pid); + TPD_INFO("Fimware VID:%02X%02X%02X%02X", fw_info->fw_vid[0], fw_info->fw_vid[1], fw_info->fw_vid[2], fw_info->fw_vid[3]); + TPD_INFO("Firmware chip type:%02X", fw_info->chip_type); + TPD_INFO("Firmware size:%u", fw_info->size); + TPD_INFO("Firmware subsystem num:%u", fw_info->subsys_num); + for (i = 0; i < fw_info->subsys_num; i++) { + TPD_DEBUG("------------------------------------------"); + TPD_DEBUG("Index:%d", i); + TPD_DEBUG("Subsystem type:%02X", fw_info->subsys[i].type); + TPD_DEBUG("Subsystem size:%u", fw_info->subsys[i].size); + TPD_DEBUG("Subsystem flash_addr:%08X", fw_info->subsys[i].flash_addr); + TPD_DEBUG("Subsystem Ptr:%p", fw_info->subsys[i].data); + } + TPD_DEBUG("------------------------------------------"); + +err_size: + return r; +} + + +/** + * goodix_check_update - compare the version of firmware running in + * touch device with the version getting from the firmware file. + * @fw_info: firmware infomation to be compared + * return: 0 firmware in the touch device needs to be updated + * < 0 no need to update firmware + */ +static int goodix_check_update(struct i2c_client *client, + const struct firmware_info *fw_info) +{ + int r = 0; + int res = 0; + u8 buffer[4] = {0}; + +#define PID_REG 0x4535 +#define VID_REG 0x453D +#define PID_LEN 4 +#define VID_LEN 4 + + /*disable doze mode ,just valid for nomandy + * this func must be used in pairs*/ + r = goodix_set_i2c_doze_mode(client, false); + if (r == -EINVAL) + goto need_update; + + /*read version from chip , if we got invalid + * firmware version ,maybe fimware in flash is + * incorrect,so we need to update firmware*/ + + /*read and compare PID*/ + r = gt9886_i2c_read(client, PID_REG, PID_LEN, buffer); + if (r < 0) { + TPD_INFO("Read pid failed"); + goto exit; + } + TPD_INFO("PID:%02x %02x %02x %02x", buffer[0], buffer[1], + buffer[2], buffer[3]); + + if (memcmp(buffer, fw_info->fw_pid, PID_LEN)) { + TPD_INFO("Product is not match,may header's fw is other product's"); + goto need_update; + } + + /*read and compare VID*/ + r = gt9886_i2c_read(client, VID_REG, VID_LEN, buffer); + if (r < 0) { + TPD_INFO("Read vid failed"); + goto exit; + } + TPD_INFO("VID:%02x %02x %02x %02x", buffer[0], buffer[1], + buffer[2], buffer[3]); + + res = memcmp(buffer, fw_info->fw_vid, VID_LEN); + if (0 == res) { + TPD_INFO("FW version is equal tp IC's,skip update"); + r = -EPERM; + goto exit; + } else if (res > 0) { + TPD_INFO("Warning: fw version is lower than IC's"); + } + +need_update: + TPD_INFO("Firmware needs tp be updated"); + r = 0; +exit: + /*enable doze mode, just valid for normandy + *this func must be used in pairs*/ + goodix_set_i2c_doze_mode(client, true); + return r; +} + +/** + * goodix_reg_write_confirm - write register and confirm the value + * in the register. + * @client: pointer to touch device client + * @addr: register address + * @data: pointer to data buffer + * @len: data length + * return: 0 write success and confirm ok + * < 0 failed + */ +static int goodix_reg_write_confirm(struct i2c_client *client, + unsigned int addr, unsigned char *data, unsigned int len) +{ + u8 *cfm, cfm_buf[32]; + int r, i; + + if (len > sizeof(cfm_buf)) { + cfm = kzalloc(len, GFP_KERNEL); + if (!cfm) { + TPD_INFO("Mem alloc failed"); + return -ENOMEM; + } + } else { + cfm = &cfm_buf[0]; + } + + for (i = 0; i < GOODIX_BUS_RETRY_TIMES; i++) { + r = touch_i2c_write_block(client, addr, len, data); + if (r < 0) + goto exit; + r = touch_i2c_read_block(client, addr, len, cfm); + if (r < 0) + goto exit; + + if (memcmp(data, cfm, len)) { + r = -EMEMCMP; + continue; + } else { + r = 0; + break; + } + } + +exit: + if (cfm != &cfm_buf[0]) + kfree(cfm); + return r; +} + + +/** + * goodix_load_isp - load ISP program to deivce ram + * @client: pointer to touch device client + * @fw_data: firmware data + * return 0 ok, <0 error + */ +static int goodix_load_isp(struct i2c_client *client, struct firmware_data *fw_data) +{ + struct fw_subsys_info *fw_isp; + u8 reg_val[8] = {0x00}; + int r; + int i; + + fw_isp = &fw_data->fw_info.subsys[0]; + + TPD_INFO("Loading ISP start"); + /* select bank0 */ + reg_val[0] = 0x00; + r = touch_i2c_write_block(client, HW_REG_BANK_SELECT, 1, reg_val); + if (r < 0) { + TPD_INFO("Failed to select bank0"); + return r; + } + TPD_DEBUG("Success select bank0, Set 0x%x -->0x00", HW_REG_BANK_SELECT); + + /* enable bank0 access */ + reg_val[0] = 0x01; + r = touch_i2c_write_block(client, HW_REG_ACCESS_PATCH0, 1, reg_val); + if (r < 0) { + TPD_INFO("Failed to enable patch0 access"); + return r; + } + TPD_DEBUG("Success select bank0, Set 0x%x -->0x01", HW_REG_ACCESS_PATCH0); + + r = goodix_reg_write_confirm(client, HW_REG_ISP_ADDR, (u8 *)fw_isp->data, fw_isp->size); + if (r < 0) { + TPD_INFO("Loading ISP error"); + return r; + } + + TPD_DEBUG("Success send ISP data to IC"); + + /* forbid patch access */ + reg_val[0] = 0x00; + r = goodix_reg_write_confirm(client, HW_REG_ACCESS_PATCH0, reg_val, 1); + if (r < 0) { + TPD_INFO("Failed to disable patch0 access"); + return r; + } + TPD_DEBUG("Success forbit bank0 accedd, set 0x%x -->0x00", HW_REG_ACCESS_PATCH0); + + /*clear 0x6006*/ + reg_val[0] = 0x00; + reg_val[1] = 0x00; + r = touch_i2c_write_block(client, HW_REG_ISP_RUN_FLAG, 2, reg_val); + if (r < 0) { + TPD_INFO("Failed to clear 0x%x", HW_REG_ISP_RUN_FLAG); + return r; + } + TPD_DEBUG("Success clear 0x%x", HW_REG_ISP_RUN_FLAG); + + /* TODO: change address 0xBDE6 set backdoor flag HW_REG_CPU_RUN_FROM */ + memset(reg_val, 0x55, 8); + r = touch_i2c_write_block(client, HW_REG_CPU_RUN_FROM, 8, reg_val); + if (r < 0) { + TPD_INFO("Failed set backdoor flag"); + return r; + } + TPD_DEBUG("Success write [8]0x55 to 0x%x", HW_REG_CPU_RUN_FROM); + + /* TODO: change reg_val 0x08---> 0x00 release ss51 */ + reg_val[0] = 0x00; + r = touch_i2c_write_block(client, HW_REG_CPU_CTRL, 1, reg_val); + if (r < 0) { + TPD_INFO("Failed to run isp"); + return r; + } + TPD_DEBUG("Success run isp, set 0x%x-->0x00", HW_REG_CPU_CTRL); + + /* check isp work state */ + for (i = 0; i < TS_CHECK_ISP_STATE_RETRY_TIMES; i++) { + r = touch_i2c_read_block(client, HW_REG_ISP_RUN_FLAG, 2, reg_val); + if (r < 0 || (reg_val[0] == 0xAA && reg_val[1] == 0xBB)) + break; + usleep_range(5000, 5100); + } + if (reg_val[0] == 0xAA && reg_val[1] == 0xBB) { + TPD_INFO("ISP working OK"); + return 0; + } else { + TPD_INFO("ISP not work,0x%x=0x%x, 0x%x=0x%x", + HW_REG_ISP_RUN_FLAG, reg_val[0], + HW_REG_ISP_RUN_FLAG + 1, reg_val[1]); + return -EFAULT; + } +} + +static int goodix_update_prepare(void *chip_data, struct fw_update_ctrl *fwu_ctrl) +{ + u8 reg_val[4] = { 0x00 }; + u8 temp_buf[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + int retry = 20; + int r; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + gt9886_i2c_write(chip_info->client, HW_REG_CPU_RUN_FROM, 8, temp_buf); + + /*reset IC*/ + TPD_INFO("normandy firmware update, reset"); + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + udelay(2000); + gpio_direction_output(chip_info->hw_res->reset_gpio, 1); + usleep_range(10000, 11000); + + retry = 20; + do { + reg_val[0] = 0x24; + r = goodix_reg_write_confirm(chip_info->client, HW_REG_CPU_CTRL, reg_val, 1); + if (r < 0) { + TPD_INFO("Failed to hold ss51, retry"); + msleep(20); + } else { + break; + } + } while (--retry); + if (!retry) { + TPD_INFO("Failed hold ss51,return =%d", r); + return -EINVAL; + } + TPD_DEBUG("Success hold ss51"); + + /* enable DSP & MCU power */ + reg_val[0] = 0x00; + r = goodix_reg_write_confirm(chip_info->client, HW_REG_DSP_MCU_POWER, reg_val, 1); + if (r < 0) { + TPD_INFO("Failed enable DSP&MCU power"); + return r; + } + TPD_DEBUG("Success enabled DSP&MCU power,set 0x%x-->0x00", HW_REG_DSP_MCU_POWER); + + /* disable watchdog timer */ + reg_val[0] = 0x00; + r = touch_i2c_write_block(chip_info->client, HW_REG_CACHE, 1, reg_val); + if (r < 0) { + TPD_INFO("Failed to clear cache"); + return r; + } + TPD_DEBUG("Success clear cache"); + + reg_val[0] = 0x95; + r = touch_i2c_write_block(chip_info->client, HW_REG_ESD_KEY, 1, reg_val); + reg_val[0] = 0x00; + r |= touch_i2c_write_block(chip_info->client, HW_REG_WTD_TIMER, 1, reg_val); + + reg_val[0] = 0x27; + r |= touch_i2c_write_block(chip_info->client, HW_REG_ESD_KEY, 1, reg_val); + if (r < 0) { + TPD_INFO("Failed to disable watchdog"); + return r; + } + TPD_DEBUG("Success disable watchdog"); + + /* set scramble */ + reg_val[0] = 0x00; + r = touch_i2c_write_block(chip_info->client, HW_REG_SCRAMBLE, 1, reg_val); + if (r < 0) { + TPD_INFO("Failed to set scramble"); + return r; + } + TPD_DEBUG("Succcess set scramble"); + + /* load ISP code and run form isp */ + r = goodix_load_isp(chip_info->client, &fwu_ctrl->fw_data); + if (r < 0) + TPD_INFO("Failed lode and run isp"); + + return r; +} + +static inline u16 checksum_be16(u8 *data, u32 size) +{ + u16 checksum = 0; + u32 i; + + for (i = 0; i < size; i += 2) + checksum += be16_to_cpup((__be16 *)(data + i)); + return checksum; +} + + +/** + * goodix_format_fw_packet - formate one flash packet + * @pkt: target firmware packet + * @flash_addr: flash address + * @size: packet size + * @data: packet data + */ +static int goodix_format_fw_packet(u8 *pkt, u32 flash_addr, + u16 len, const u8 *data) +{ + u16 checksum; + if (!pkt || !data) + return -EINVAL; + + /* + * checksum rule:sum of data in one format is equal to zero + * data format: byte/le16/be16/le32/be32/le64/be64 + */ + pkt[0] = (len >> 8) & 0xff; + pkt[1] = len & 0xff; + pkt[2] = (flash_addr >> 16) & 0xff; /* u16 >> 16bit seems nosense but really important */ + pkt[3] = (flash_addr >> 8) & 0xff; + memcpy(&pkt[4], data, len); + checksum = checksum_be16(pkt, len + 4); + checksum = 0 - checksum; + pkt[len + 4] = (checksum >> 8) & 0xff; + pkt[len + 5] = checksum & 0xff; + return 0; +} + +/** + * goodix_send_fw_packet - send one firmware packet to ISP + * @dev: target touch device + * @pkt: firmware packet + * return 0 ok, <0 error + */ +static int goodix_send_fw_packet(struct i2c_client *client, u8 type, + u8 *pkt, u32 len) +{ + u8 reg_val[4]; + int r, i; + u32 offset = 0; + u32 total_size = 0; + u32 data_size = 0; + + if (!pkt) + return -EINVAL; + + /*i2c max size is just 4k for mt6771*/ + total_size = len; + while (total_size > 0) { + data_size = total_size > I2C_DATA_MAX_BUFFERSIZE ? I2C_DATA_MAX_BUFFERSIZE : total_size; + TPD_INFO("I2C firmware to %08x,size:%u bytes all len:%u bytes", offset, data_size, len); + r = goodix_reg_write_confirm(client, HW_REG_ISP_BUFFER + offset, &pkt[offset], data_size); + if (r < 0) { + TPD_INFO("Failed to write firmware packet"); + return r; + } + + offset += data_size; + total_size -= data_size; + } /* end while */ + + reg_val[0] = 0; + reg_val[1] = 0; + /* clear flash flag 0X6022 */ + r = goodix_reg_write_confirm(client, HW_REG_FLASH_FLAG, reg_val, 2); + if (r < 0) { + TPD_INFO("Faile to clear flash flag"); + return r; + } + + /* write subsystem type 0X8020*/ + reg_val[0] = type; + reg_val[1] = type; + r = goodix_reg_write_confirm(client, HW_REG_SUBSYS_TYPE, reg_val, 2); + if (r < 0) { + TPD_INFO("Failed write subsystem type to IC"); + return r; + } + + for (i = 0; i < TS_READ_FLASH_STATE_RETRY_TIMES; i++) { + r = touch_i2c_read_block(client, HW_REG_FLASH_FLAG, 2, reg_val); + if (r < 0) { + TPD_INFO("Failed read flash state"); + return r; + } + + /* flash haven't end */ + if (reg_val[0] == ISP_STAT_WRITING && reg_val[1] == ISP_STAT_WRITING) { + TPD_DEBUG("Flash not ending..."); + usleep_range(55000, 56000); + continue; + } + if (reg_val[0] == ISP_FLASH_SUCCESS && reg_val[1] == ISP_FLASH_SUCCESS) { + /* read twice to confirm the result */ + r = touch_i2c_read_block(client, HW_REG_FLASH_FLAG, 2, reg_val); + if (r >= 0 && reg_val[0] == ISP_FLASH_SUCCESS && reg_val[1] == ISP_FLASH_SUCCESS) { + TPD_INFO("Flash subsystem ok"); + return 0; + } + } + if (reg_val[0] == ISP_FLASH_ERROR && reg_val[1] == ISP_FLASH_ERROR) { + TPD_INFO(" Flash subsystem failed"); + return -EAGAIN; + } + if (reg_val[0] == ISP_FLASH_CHECK_ERROR) { + TPD_INFO("Subsystem checksum err"); + return -EAGAIN; + } + + usleep_range(250, 260); + } + + TPD_INFO("Wait for flash end timeout, 0x6022= %x %x", reg_val[0], reg_val[1]); + return -EAGAIN; +} + +/** + * goodix_flash_subsystem - flash subsystem firmware, + * Main flow of flashing firmware. + * Each firmware subsystem is divided into several + * packets, the max size of packet is limited to + * @{ISP_MAX_BUFFERSIZE} + * @client: pointer to touch device client + * @subsys: subsystem infomation + * return: 0 ok, < 0 error + */ +static int goodix_flash_subsystem(struct i2c_client *client, struct fw_subsys_info *subsys) +{ + u16 data_size, offset; + u32 total_size; + u32 subsys_base_addr = subsys->flash_addr << 8; + u8 *fw_packet; + int r = 0, i; + + /* + * if bus(i2c/spi) error occued, then exit, we will do + * hardware reset and re-prepare ISP and then retry + * flashing + */ + total_size = subsys->size; + fw_packet = kzalloc(ISP_MAX_BUFFERSIZE + 6, GFP_KERNEL); + if (!fw_packet) { + TPD_INFO("Failed alloc memory"); + return -EINVAL; + } + + offset = 0; + while (total_size > 0) { + data_size = total_size > ISP_MAX_BUFFERSIZE ? ISP_MAX_BUFFERSIZE : total_size; + TPD_INFO("Flash firmware to %08x,size:%u bytes", subsys_base_addr + offset, data_size); + + /* format one firmware packet */ + r = goodix_format_fw_packet(fw_packet, subsys_base_addr + offset, data_size, &subsys->data[offset]); + if (r < 0) { + TPD_INFO("Invalid packet params"); + goto exit; + } + + /* send one firmware packet, retry 3 time if send failed */ + for (i = 0; i < 3; i++) { + r = goodix_send_fw_packet(client, subsys->type, fw_packet, data_size + 6); + if (!r) + break; + } + if (r) { + TPD_INFO("Failed flash subsystem"); + goto exit; + } + offset += data_size; + total_size -= data_size; + } /* end while */ + +exit: + kfree(fw_packet); + return r; +} + + + +/** + * goodix_flash_firmware - flash firmware + * @client: pointer to touch device client + * @fw_data: firmware data + * return: 0 ok, < 0 error + */ +static int goodix_flash_firmware(struct i2c_client *client, struct firmware_data *fw_data) +{ + struct fw_update_ctrl *fw_ctrl; + struct firmware_info *fw_info; + struct fw_subsys_info *fw_x; + int retry = GOODIX_BUS_RETRY_TIMES; + int i, r = 0, fw_num, prog_step; + + /* start from subsystem 1, + * subsystem 0 is the ISP program */ + fw_ctrl = container_of(fw_data, struct fw_update_ctrl, fw_data); + fw_info = &fw_data->fw_info; + fw_num = fw_info->subsys_num; + + /* we have 80% work here */ + prog_step = 80 / (fw_num - 1); + + for (i = 1; i < fw_num && retry;) { + TPD_INFO("--- Start to flash subsystem[%d] ---", i); + fw_x = &fw_info->subsys[i]; + r = goodix_flash_subsystem(client, fw_x); + if (r == 0) { + TPD_INFO("--- End flash subsystem[%d]: OK ---", i); + fw_ctrl->progress += prog_step; + i++; + } else if (r == -EAGAIN) { + retry--; + TPD_INFO("--- End flash subsystem%d: Fail, errno:%d, retry:%d ---", i, r, GOODIX_BUS_RETRY_TIMES - retry); + } else if (r < 0) { /* bus error */ + TPD_INFO("--- End flash subsystem%d: Fatal error:%d exit ---", i, r); + goto exit_flash; + } + } + +exit_flash: + return r; +} + +/** + * goodix_update_finish - update finished, free resource + * and reset flags--- + * @fwu_ctrl: pointer to fw_update_ctrl structrue + * return: 0 ok, < 0 error + */ +static int goodix_update_finish(void *chip_data, struct fw_update_ctrl *fwu_ctrl) +{ + u8 reg_val[8] = {0}; + int r = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + /* hold ss51 */ + reg_val[0] = 0x24; + r = touch_i2c_write_block(chip_info->client, HW_REG_CPU_CTRL, 1, reg_val); + if (r < 0) + TPD_INFO("Failed to hold ss51"); + + /* clear back door flag */ + memset(reg_val, 0, sizeof(reg_val)); + r = touch_i2c_write_block(chip_info->client, HW_REG_CPU_RUN_FROM, 8, reg_val); + if (r < 0) { + TPD_INFO("Failed set CPU run from normal firmware"); + return r; + } + + /* release ss51 */ + reg_val[0] = 0x00; + r = touch_i2c_write_block(chip_info->client, HW_REG_CPU_CTRL, 1, reg_val); + if (r < 0) + TPD_INFO("Failed to run ss51"); + + /*reset*/ + r = goodix_reset(chip_info); + + return r; +} + +u32 getUint(u8 *buffer, int len) +{ + u32 num = 0; + int i = 0; + for (i = 0; i < len; i++) { + num <<= 8; + num += buffer[i]; + } + return num; +} + +static int gtx8_parse_cfg_data(const struct firmware *cfg_bin, char *cfg_type, u8 *cfg, int *cfg_len, u8 sid) +{ + int i = 0, config_status = 0, one_cfg_count = 0; + int cfgPackageLen = 0; + + u8 bin_group_num = 0, bin_cfg_num = 0; + u16 cfg_checksum = 0, checksum = 0; + u8 sid_is_exist = GTX8_NOT_EXIST; + u16 cfg_offset = 0; + + TPD_DEBUG("%s run,sensor id:%d\n", __func__, sid); + + cfgPackageLen = getU32(cfg_bin->data) + BIN_CFG_START_LOCAL; + if ( cfgPackageLen > cfg_bin->size) { + TPD_INFO("%s:Bad firmware!,cfg package len:%d,firmware size:%d\n", + __func__, cfgPackageLen, (int)cfg_bin->size); + goto exit; + } + + /* check firmware's checksum */ + cfg_checksum = getU16(&cfg_bin->data[4]); + + for (i = BIN_CFG_START_LOCAL; i < (cfgPackageLen) ; i++) + checksum += cfg_bin->data[i]; + + if ((checksum) != cfg_checksum) { + TPD_INFO("%s:Bad firmware!(checksum: 0x%04X, header define: 0x%04X)\n", + __func__, checksum, cfg_checksum); + goto exit; + } + /* check head end */ + + bin_group_num = cfg_bin->data[MODULE_NUM]; + bin_cfg_num = cfg_bin->data[CFG_NUM]; + TPD_DEBUG("%s:bin_group_num = %d, bin_cfg_num = %d\n", __func__, bin_group_num, bin_cfg_num); + + if (!strncmp(cfg_type, GTX8_TEST_CONFIG, strlen(GTX8_TEST_CONFIG))) + config_status = 0; + else if (!strncmp(cfg_type, GTX8_NORMAL_CONFIG, strlen(GTX8_NORMAL_CONFIG))) + config_status = 1; + else if (!strncmp(cfg_type, GTX8_NORMAL_NOISE_CONFIG, strlen(GTX8_NORMAL_NOISE_CONFIG))) + config_status = 2; + else if (!strncmp(cfg_type, GTX8_GLOVE_CONFIG, strlen(GTX8_GLOVE_CONFIG))) + config_status = 3; + else if (!strncmp(cfg_type, GTX8_GLOVE_NOISE_CONFIG, strlen(GTX8_GLOVE_NOISE_CONFIG))) + config_status = 4; + else if (!strncmp(cfg_type, GTX8_HOLSTER_CONFIG, strlen(GTX8_HOLSTER_CONFIG))) + config_status = 5; + else if (!strncmp(cfg_type, GTX8_HOLSTER_NOISE_CONFIG, strlen(GTX8_HOLSTER_NOISE_CONFIG))) + config_status = 6; + else if (!strncmp(cfg_type, GTX8_NOISE_TEST_CONFIG, strlen(GTX8_NOISE_TEST_CONFIG))) + config_status = 7; + else { + TPD_INFO("%s: invalid config text field\n", __func__); + goto exit; + } + + cfg_offset = CFG_HEAD_BYTES + bin_group_num * bin_cfg_num * CFG_INFO_BLOCK_BYTES ; + for (i = 0 ; i < bin_group_num * bin_cfg_num; i++) { + /* find cfg's sid in cfg.bin */ + one_cfg_count = getU16(&cfg_bin->data[CFG_HEAD_BYTES + 2 + i * CFG_INFO_BLOCK_BYTES]); + if (sid == (cfg_bin->data[CFG_HEAD_BYTES + i * CFG_INFO_BLOCK_BYTES])) { + sid_is_exist = GTX8_EXIST; + if (config_status == (cfg_bin->data[CFG_HEAD_BYTES + 1 + i * CFG_INFO_BLOCK_BYTES])) { + memcpy(cfg, &cfg_bin->data[cfg_offset], one_cfg_count); + *cfg_len = one_cfg_count; + TPD_DEBUG("%s:one_cfg_count = %d, cfg_data1 = 0x%02x, cfg_data2 = 0x%02x\n", + __func__, one_cfg_count, cfg[0], cfg[1]); + break; + } + } + cfg_offset += one_cfg_count; + } + + if (i >= bin_group_num * bin_cfg_num) { + TPD_INFO("%s:(not find config ,config_status: %d)\n", __func__, config_status); + goto exit; + } + + TPD_DEBUG("%s exit\n", __func__); + return NO_ERR; +exit: + return RESULT_ERR; +} + +static int gtx8_get_cfg_data(void *chip_data_info, const struct firmware *cfg_bin, + char *config_name, struct gtx8_ts_config *config) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data_info; + u8 *cfg_data = NULL; + int cfg_len = 0; + int ret = NO_ERR; + + TPD_DEBUG("%s run\n", __func__); + + cfg_data = kzalloc(GOODIX_CFG_MAX_SIZE, GFP_KERNEL); + if (cfg_data == NULL) { + TPD_INFO("Memory allco err\n"); + goto exit; + } + + config->initialized = false; + mutex_init(&config->lock); + config->reg_base = 0x00; + + /* parse config data */ + ret = gtx8_parse_cfg_data(cfg_bin, config_name, cfg_data, + &cfg_len, chip_info->ver_info.sensor_id); + if (ret < 0) { + TPD_INFO("%s: parse %s data failed\n", __func__, config_name); + ret = -EINVAL; + goto exit; + } + + TPD_DEBUG("%s: %s version:%d , size:%d\n", __func__, config_name, cfg_data[0], cfg_len); + memcpy(config->data, cfg_data, cfg_len); + config->length = cfg_len; + + strncpy(config->name, config_name, MAX_STR_LEN); + config->initialized = true; + +exit: + if (cfg_data) { + kfree(cfg_data); + cfg_data = NULL; + } + TPD_DEBUG("%s exit\n", __func__); + return ret; +} + + +static int gtx8_get_cfg_parms(void *chip_data_info, const struct firmware *firmware) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data_info; + int ret = 0; + + TPD_DEBUG("%s run\n", __func__); + if(firmware == NULL) { + TPD_INFO("%s: firmware is null\n", __func__); + ret = -1; + goto exit; + } + + if (firmware->data == NULL) { + TPD_INFO("%s:Bad firmware!(config firmware data is null: )\n", __func__); + ret = -1; + goto exit; + } + + TPD_DEBUG("%s: cfg_bin_size:%d\n", __func__, (int)firmware->size); + + /* parse normal config data */ + ret = gtx8_get_cfg_data(chip_info, firmware, GTX8_NORMAL_CONFIG, &chip_info->normal_cfg); + if (ret < 0) { + TPD_INFO("%s: Failed to parse normal_config data:%d\n", __func__, ret); + } else { + TPD_DEBUG("%s: parse normal_config data success\n", __func__); + } + + ret = gtx8_get_cfg_data(chip_info, firmware, GTX8_TEST_CONFIG, &chip_info->test_cfg); + if (ret < 0) { + TPD_INFO("%s: Failed to parse test_config data:%d\n", __func__, ret); + } else { + TPD_DEBUG("%s: parse test_config data success\n", __func__); + } + + + /* parse normal noise config data */ + ret = gtx8_get_cfg_data(chip_info, firmware, GTX8_NORMAL_NOISE_CONFIG, &chip_info->normal_noise_cfg); + if (ret < 0) { + TPD_INFO("%s: Failed to parse normal_noise_config data\n", __func__); + } else { + TPD_DEBUG("%s: parse normal_noise_config data success\n", __func__); + } + + /* parse noise test config data */ + ret = gtx8_get_cfg_data(chip_info, firmware, GTX8_NOISE_TEST_CONFIG, &chip_info->noise_test_cfg); + if (ret < 0) { + memcpy(&chip_info->noise_test_cfg, &chip_info->normal_cfg, sizeof(chip_info->noise_test_cfg)); + TPD_INFO("%s: Failed to parse noise_test_config data,use normal_config data\n", __func__); + } else { + TPD_DEBUG("%s: parse noise_test_config data success\n", __func__); + } +exit: + TPD_DEBUG("%s exit:%d\n", __func__, ret); + return ret; +} + +//get fw firmware from firmware +//return value: +// 0: operate success +// other: failed +static int gtx8_get_fw_parms(void *chip_data_info, const struct firmware *firmware, struct firmware *fw_firmware) +{ + //struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data_info; + int ret = 0; + int cfgPackageLen = 0; + int fwPackageLen = 0; + + TPD_DEBUG("%s run\n", __func__); + if(firmware == NULL) { + TPD_INFO("%s: firmware is null\n", __func__); + ret = -1; + goto exit; + } + + if (firmware->data == NULL) { + TPD_INFO("%s:Bad firmware!(config firmware data si null)\n", __func__); + ret = -1; + goto exit; + } + + if(fw_firmware == NULL) { + TPD_INFO("%s:fw_firmware is null\n", __func__); + ret = -1; + goto exit; + } + + TPD_DEBUG("clear fw_firmware\n"); + memset(fw_firmware, 0, sizeof(struct firmware)); + + cfgPackageLen = getU32(firmware->data) + BIN_CFG_START_LOCAL; + TPD_DEBUG("%s cfg package len:%d\n", __func__, cfgPackageLen); + + if(firmware->size <= (cfgPackageLen + 16)) { + TPD_INFO("%s current firmware does not contain goodix fw\n", __func__); + TPD_INFO("%s cfg package len:%d,firmware size:%d\n", __func__, cfgPackageLen, (int)firmware->size); + ret = -1; + goto exit; + } + + if(!(firmware->data[cfgPackageLen + 0] == 'G' && firmware->data[cfgPackageLen + 1] == 'X' && + firmware->data[cfgPackageLen + 2] == 'F' && firmware->data[cfgPackageLen + 3] == 'W')) { + TPD_INFO("%s can't find fw package\n", __func__); + TPD_INFO("Data type:%c %c %c %c,dest type is:GXFW\n", firmware->data[cfgPackageLen + 0], + firmware->data[cfgPackageLen + 1], firmware->data[cfgPackageLen + 2], + firmware->data[cfgPackageLen + 3]); + ret = -1; + goto exit; + } + + if(firmware->data[cfgPackageLen + 4] != 1) { + TPD_INFO("%s can't support this ver:%d\n", __func__, firmware->data[cfgPackageLen + 4]); + ret = -1; + goto exit; + } + + fwPackageLen = getU32(firmware->data + cfgPackageLen + 8); + + TPD_DEBUG("%s fw package len:%d\n", __func__, fwPackageLen); + if((fwPackageLen + 16 + cfgPackageLen) > firmware->size ) { + TPD_INFO("%s bad firmware,need len:%d,actual firmware size:%d\n", + __func__, fwPackageLen + 16 + cfgPackageLen, (int)firmware->size); + ret = -1; + goto exit; + } + + fw_firmware->size = fwPackageLen; + fw_firmware->data = firmware->data + cfgPackageLen + 16; + + TPD_DEBUG("success get fw,len:%d\n", fwPackageLen); + TPD_DEBUG("fw head info:%*ph\n", 32, fw_firmware->data); + TPD_DEBUG("fw tail info:%*ph\n", 4, &fw_firmware->data[fwPackageLen - 4 - 1]); + ret = 0; + +exit: + TPD_DEBUG("%s exit:%d\n", __func__, ret); + return ret; +} + +static fw_update_state goodix_fw_update(void *chip_data, const struct firmware *cfg_fw_firmware, bool force) +{ + +#define FW_UPDATE_RETRY 2 + + int retry0; + int retry1; + int r; + int ret; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + struct fw_update_ctrl *fwu_ctrl = NULL; + struct firmware fw_firmware; + + fwu_ctrl = kzalloc(sizeof(struct fw_update_ctrl), GFP_KERNEL); + if (!fwu_ctrl) { + TPD_INFO("Failed to alloc memory for fwu_ctrl"); + return -ENOMEM; + } + + r = gtx8_get_cfg_parms(chip_data, cfg_fw_firmware); + if(r < 0) { + TPD_INFO("%s Failed get cfg from firmware\n", __func__); + //return -ENOMEM; + } else { + TPD_INFO("%s success get ic cfg from firmware\n", __func__); + } + + r = gtx8_get_fw_parms(chip_data, cfg_fw_firmware, &fw_firmware); + if(r < 0) { + TPD_INFO("%s Failed get ic fw from firmware\n", __func__); + goto err_parse_fw; + } else { + TPD_INFO("%s success get ic fw from firmware\n", __func__); + } + + retry0 = FW_UPDATE_RETRY; + retry1 = FW_UPDATE_RETRY; + r = 0; + + fwu_ctrl->fw_data.firmware = &fw_firmware; + fwu_ctrl->progress = 0; + fwu_ctrl->status = UPSTA_PREPARING; + + r = goodix_parse_firmware(&fwu_ctrl->fw_data); + if (r < 0) { + fwu_ctrl->status = UPSTA_ABORT; + goto err_parse_fw; + } + + /* TODO: set force update flag*/ + fwu_ctrl->progress = 10; + if (force == false) { + r = goodix_check_update(chip_info->client, &fwu_ctrl->fw_data.fw_info); + if (r == -EPERM) { + r = FW_NO_NEED_UPDATE; + fwu_ctrl->status = UPSTA_ABORT; + goto err_check_update; + } + } + +start_update: + fwu_ctrl->progress = 20; + fwu_ctrl->status = UPSTA_UPDATING; /* show upgrading status */ + r = goodix_update_prepare(chip_info, fwu_ctrl); + + if ((r == -EBUS || r == -5) && --retry0 > 0) { + TPD_INFO("Bus error, retry prepare ISP:%d", FW_UPDATE_RETRY - retry0); + goto start_update; + } else if (r < 0) { + TPD_INFO("Failed to prepare ISP, exit update:%d", r); + fwu_ctrl->status = UPSTA_FAILED; + goto err_fw_prepare; + } + + /* progress: 20%~100% */ + r = goodix_flash_firmware(chip_info->client, &fwu_ctrl->fw_data); + if ((r == -EBUS || r == -ETIMEOUT) && --retry1 > 0) { + /* we will retry[twice] if returns bus error[i2c/spi] + * we will do hardware reset and re-prepare ISP and then retry + * flashing + */ + TPD_INFO("Bus error, retry firmware update:%d", FW_UPDATE_RETRY - retry1); + goto start_update; + } else if (r < 0) { + TPD_INFO("Fatal error, exit update:%d", r); + fwu_ctrl->status = UPSTA_FAILED; + goto err_fw_flash; + } + + fwu_ctrl->status = UPSTA_SUCCESS; + +err_fw_flash: +err_fw_prepare: + goodix_update_finish(chip_info, fwu_ctrl); + + goodix_set_i2c_doze_mode(chip_info->client, false); + //clear update information + goodix_send_cmd(chip_info, COMMAND_CLEAR_UPDATE, 0); + TPD_INFO("clear update information\n"); + goodix_set_i2c_doze_mode(chip_info->client, true); +err_check_update: +err_parse_fw: + + ret = goodix_send_config(chip_info, chip_info->normal_cfg.data, chip_info->normal_cfg.length); + + + if(ret < 0) { + TPD_INFO("%s: send normal cfg failed:%d\n", __func__, ret); + } else { + TPD_INFO("%s: send normal cfg success\n", __func__); + r = FW_UPDATE_SUCCESS; + } + + msleep(200); + + if (fwu_ctrl->status == UPSTA_SUCCESS) { + TPD_INFO("Firmware update successfully"); + r = FW_UPDATE_SUCCESS; + } else if (fwu_ctrl->status == UPSTA_FAILED) { + TPD_INFO("Firmware update failed"); + r = FW_UPDATE_ERROR; + } + + if (fwu_ctrl) { + kfree(fwu_ctrl); + fwu_ctrl = NULL; + } + + return r; +} +/*****************end of GT9886's update function********************/ + +static u32 goodix_u32_trigger_reason(void *chip_data, int gesture_enable, int is_suspended) +{ + int ret = -1; + u8 touch_num = 0; + u8 check_sum = 0; + u32 result_event = 0; + int i = 0; + bool all_zero = true; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + pm_qos_add_request(&pm_qos_req_stp, PM_QOS_CPU_DMA_LATENCY, PM_QOS_VALUE_TP); + + if (chip_info->is_power_down) { + TPD_INFO("%s: power down, just return\n", __func__); + return IRQ_IGNORE; + } + + // TODO we can read 4 + BYTES_PER_COORD to accelerate i2c read speed + memset(chip_info->touch_data, 0, MAX_GT_IRQ_DATA_LENGTH); + if (chip_info->kernel_grip_support) { + memset(chip_info->edge_data, 0, MAX_GT_EDGE_DATA_LENGTH); + } + + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 4 + BYTES_PER_COORD, chip_info->touch_data); + if (ret < 0) { + TPD_INFO("%s: i2c transfer error!\n", __func__); + goto IGNORE_CLEAR_IRQ; + } + + if ( (chip_info->touch_data[0] & GOODIX_TOUCH_EVENT) == GOODIX_TOUCH_EVENT ) { + touch_num = chip_info->touch_data[1] & 0x0F; + touch_num = touch_num < MAX_POINT_NUM ? touch_num : MAX_POINT_NUM; + if (chip_info->kernel_grip_support) { + if (touch_num > 0) { + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_EDGE_INFO, BYTES_PER_EDGE * touch_num, chip_info->edge_data); + if (ret < 0) { + TPD_INFO("%s: i2c transfer error!\n", __func__); + goto IGNORE_CLEAR_IRQ; + } + } + } + + if (touch_num > 1) { + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR + 2, \ + BYTES_PER_COORD * touch_num + 2, &chip_info->touch_data[2]); //read out point data + if (ret < 0) { + TPD_INFO("read touch point data from coor_addr failed!\n"); + goto IGNORE_CLEAR_IRQ; + } + + } + + check_sum = 0; + for (i = 0; i < 2 + BYTES_PER_COORD * touch_num + 2; i++) { //do checksum + check_sum += chip_info->touch_data[i]; + } + if (check_sum) { + TPD_INFO("irq touch_data checksum is invalid\n"); + goto IGNORE_CLEAR_IRQ; + } + + } else if (unlikely((chip_info->touch_data[0] & GOODIX_GESTURE_EVENT) != GOODIX_GESTURE_EVENT)) { + check_sum = 0; + for (i = 0; i < 12; i++) { //do checksum + check_sum += chip_info->touch_data[i]; + if (chip_info->touch_data[i]) { + all_zero = false; + } + } + if (check_sum || all_zero) { + TPD_INFO("irq checksum is invalid at else\n"); + goto IGNORE_CLEAR_IRQ; + } + } + + if (gesture_enable && is_suspended && (chip_info->touch_data[0] & GOODIX_GESTURE_EVENT) == GOODIX_GESTURE_EVENT) { //check whether the gesture trigger + return IRQ_GESTURE; + } else if (is_suspended) { + goto IGNORE_CLEAR_IRQ; + } + if (unlikely((chip_info->touch_data[0] & GOODIX_FINGER_IDLE_EVENT) == GOODIX_FINGER_IDLE_EVENT)) { + goto IGNORE_CLEAR_IRQ; + } + if (unlikely((chip_info->touch_data[0] & GOODIX_REQUEST_EVENT) == GOODIX_REQUEST_EVENT)) { //int request + return IRQ_FW_CONFIG; + } + if (unlikely((chip_info->touch_data[0] & GOODIX_FINGER_STATUS_EVENT) == GOODIX_FINGER_STATUS_EVENT)) { + SET_BIT(result_event, IRQ_DATA_LOGGER); + } + + chip_info->touch_data[BYTES_PER_COORD * touch_num + 2] = 0; + chip_info->touch_data[BYTES_PER_COORD * touch_num + 3] = 0; + + if ((chip_info->touch_data[0] & GOODIX_TOUCH_EVENT) ==GOODIX_TOUCH_EVENT) { + SET_BIT(result_event, IRQ_TOUCH); + if ((chip_info->touch_data[0] & GOODIX_FINGER_PRINT_EVENT) == GOODIX_FINGER_PRINT_EVENT && + !is_suspended && (chip_info->fp_down_flag == false)) { + chip_info->fp_down_flag = true; + gf_opticalfp_irq_handler(1); + //SET_BIT(result_event, IRQ_FINGERPRINT); + TPD_INFO("%s:touch_hold status %d\n", __func__, chip_info->fp_down_flag); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } else if (!is_suspended && (chip_info->touch_data[0] & GOODIX_FINGER_PRINT_EVENT) != GOODIX_FINGER_PRINT_EVENT && + (chip_info->fp_down_flag == true) ) { + chip_info->fp_down_flag = false; + gf_opticalfp_irq_handler(0); + //SET_BIT(result_event, IRQ_FINGERPRINT); + TPD_INFO("%s:touch_hold status %d\n", __func__, chip_info->fp_down_flag); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + } + else + pm_qos_remove_request(&pm_qos_req_stp); + return result_event; + +IGNORE_CLEAR_IRQ: + TPD_DEBUG("error coor data :%*ph\n", 12, chip_info->touch_data); + ret = goodix_clear_irq(chip_info); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; +} + +static int goodix_get_touch_points(void *chip_data, struct point_info *points, int max_num) +{ + int ret, i; + int touch_map = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + u8 touch_num = 0; + u8 finger_processed = 0; + u8 *coor_data = NULL; + u8 *ew_data = NULL; + s32 id = 0; + + touch_num = chip_info->touch_data[1] & 0x0F; + if (touch_num == 0) { //Up event + goto END_TOUCH; + } + + coor_data = &chip_info->touch_data[2]; + ew_data = &chip_info->edge_data[0]; + id = coor_data[0] & 0x0F; + for (i = 0; i < max_num; i++) { + if (i == id) { + points[i].x = coor_data[1] | (coor_data[2] << 8); + points[i].y = coor_data[3] | (coor_data[4] << 8); + points[i].z = coor_data[5]; + points[i].width_major = 30; // any value + points[i].status = 1; + points[i].touch_major = coor_data[6]; + points[i].tx_press = ew_data[0]; + points[i].rx_press = ew_data[1]; + + if (coor_data[0] & 0x10) { + chip_info->fp_coor_report.fp_x_coor = points[i].x; + chip_info->fp_coor_report.fp_y_coor = points[i].y; + chip_info->fp_coor_report.fp_area = coor_data[7]; + } + + touch_map |= 0x01 << i; + coor_data += 8; + ew_data += 4; + + if (finger_processed++ < touch_num) { + id = coor_data[0] & 0x0F; + } + } + } +END_TOUCH: + ret = goodix_clear_irq(chip_info); + pm_qos_remove_request(&pm_qos_req_stp); + return touch_map; +} + +static int goodix_get_gesture_info(void *chip_data, struct gesture_info *gesture) +{ + int ret = -1; + int i; + u8 check_sum = 0; + uint8_t doze_buf[GSX_KEY_DATA_LEN] = {0}; + uint8_t point_data[MAX_GESTURE_POINT_NUM * 4 + 1]; + uint8_t point_num = 0; + uint8_t gesture_id = 0; + struct Coordinate limitPoint[4]; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_WAKEUP_GESTURE, sizeof(doze_buf), doze_buf); + if (ret < 0) { + TPD_INFO("%s: read gesture info i2c faild\n", __func__); + return -1; + } + + gesture_id = doze_buf[2]; + if (gesture_id == 0 || ((doze_buf[0] & GOODIX_GESTURE_EVENT) == 0)) { //no gesture type, no need handle + TPD_INFO("Read gesture data faild. doze_buf[0]=0x%x\n", doze_buf[0]); + goto END_GESTURE; + } + + for (i = 0, check_sum = 0; i < sizeof(doze_buf); i++) { + check_sum += doze_buf[i]; + } + if (check_sum) { + TPD_INFO("gesture checksum error: %x\n", check_sum); + goto END_GESTURE; + } + /*For FP_DOWN_DETECT FP_UP_DETECT no need to read GTP_REG_GESTURE_COOR data*/ + gesture->clockwise = 2; + switch (gesture_id) { //judge gesture type //Jarvis: need check with FW.protocol 3 + case FP_DOWN_DETECT: + gesture->gesture_type = FingerprintDown; + chip_info->fp_coor_report.fp_x_coor = (doze_buf[4] & 0xFF) | (doze_buf[5] & 0x0F) << 8; + chip_info->fp_coor_report.fp_y_coor = (doze_buf[6] & 0xFF) | (doze_buf[7] & 0x0F) << 8; + chip_info->fp_coor_report.fp_area = (doze_buf[12] & 0xFF) | (doze_buf[13] & 0x0F) << 8; + + gesture->Point_start.x = chip_info->fp_coor_report.fp_x_coor; + gesture->Point_start.y = chip_info->fp_coor_report.fp_y_coor; + gesture->Point_end.x = chip_info->fp_coor_report.fp_area; + chip_info->fp_down_flag = true; + gf_opticalfp_irq_handler(1); + TPD_INFO("%s:touch_hold status %d\n", __func__, chip_info->fp_down_flag); + goto REPORT_GESTURE; + break; + + case FP_UP_DETECT: + gesture->gesture_type = FingerprintUp; + chip_info->fp_coor_report.fp_x_coor = (doze_buf[4] & 0xFF) | (doze_buf[5] & 0x0F) << 8; + chip_info->fp_coor_report.fp_y_coor = (doze_buf[6] & 0xFF) | (doze_buf[7] & 0x0F) << 8; + chip_info->fp_coor_report.fp_area = (doze_buf[12] & 0xFF) | (doze_buf[13] & 0x0F) << 8; + + gesture->Point_start.x = chip_info->fp_coor_report.fp_x_coor; + gesture->Point_start.y = chip_info->fp_coor_report.fp_y_coor; + gesture->Point_end.x = chip_info->fp_coor_report.fp_area; + + chip_info->fp_down_flag = false; + gf_opticalfp_irq_handler(0); + TPD_INFO("%s:touch_hold status %d\n", __func__, chip_info->fp_down_flag); + goto REPORT_GESTURE; + break; + } + + memset(point_data, 0, sizeof(point_data)); + point_num = doze_buf[3]; + point_num = point_num < MAX_GESTURE_POINT_NUM ? point_num : MAX_GESTURE_POINT_NUM; + + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_GESTURE_COOR, point_num * 4 +1, point_data); //havn't add checksum here. + if (ret < 0) { + TPD_INFO("%s: read gesture data i2c faild\n", __func__); + goto END_GESTURE; + } + switch (gesture_id) { //judge gesture type //Jarvis: need check with FW.protocol 3 + case RIGHT_SLIDE_DETECT : + gesture->gesture_type = Left2RightSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case LEFT_SLIDE_DETECT : + gesture->gesture_type = Right2LeftSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case DOWN_SLIDE_DETECT : + gesture->gesture_type = Up2DownSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case UP_SLIDE_DETECT : + gesture->gesture_type = Down2UpSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case DTAP_DETECT: + gesture->gesture_type = DouTap; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_end.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + break; + + case STAP_DETECT: + gesture->gesture_type = SingleTap; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_end.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + break; + + case UP_VEE_DETECT : + gesture->gesture_type = UpVee; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case DOWN_VEE_DETECT : + gesture->gesture_type = DownVee; + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case LEFT_VEE_DETECT: + gesture->gesture_type = LeftVee; + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case RIGHT_VEE_DETECT ://this gesture is C + case RIGHT_VEE_DETECT2://this gesture is < + gesture->gesture_type = RightVee; + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case CIRCLE_DETECT : + gesture->gesture_type = Circle; + gesture->clockwise = clockWise(&point_data[0], point_num); + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[20] & 0xFF) | (point_data[21] & 0x0F) << 8; + gesture->Point_end.y = (point_data[22] & 0xFF) | (point_data[23] & 0x0F) << 8; + gesture->Point_1st = limitPoint[0]; //ymin + gesture->Point_2nd = limitPoint[1]; //xmin + gesture->Point_3rd = limitPoint[2]; //ymax + gesture->Point_4th = limitPoint[3]; //xmax + break; + + case DOUSWIP_DETECT : + gesture->gesture_type = DouSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_2nd.x = (point_data[12] & 0xFF) | (point_data[13] & 0x0F) << 8; + gesture->Point_2nd.y = (point_data[14] & 0xFF) | (point_data[15] & 0x0F) << 8; + break; + + case M_DETECT : + gesture->gesture_type = Mgestrue; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[16] & 0xFF) | (point_data[17] & 0x0F) << 8; + gesture->Point_end.y = (point_data[18] & 0xFF) | (point_data[19] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + gesture->Point_2nd.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_2nd.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_3rd.x = (point_data[12] & 0xFF) | (point_data[13] & 0x0F) << 8; + gesture->Point_3rd.y = (point_data[14] & 0xFF) | (point_data[15] & 0x0F) << 8; + break; + + case W_DETECT : + gesture->gesture_type = Wgestrue; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[16] & 0xFF) | (point_data[17] & 0x0F) << 8; + gesture->Point_end.y = (point_data[18] & 0xFF) | (point_data[19] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + gesture->Point_2nd.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_2nd.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_3rd.x = (point_data[12] & 0xFF) | (point_data[13] & 0x0F) << 8; + gesture->Point_3rd.y = (point_data[14] & 0xFF) | (point_data[15] & 0x0F) << 8; + break; + + case S_DETECT : + gesture->gesture_type = Sgestrue; + gesture->clockwise = clockWise(&point_data[0], point_num); + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[20] & 0xFF) | (point_data[21] & 0x0F) << 8; + gesture->Point_end.y = (point_data[22] & 0xFF) | (point_data[23] & 0x0F) << 8; + gesture->Point_1st = limitPoint[0]; //ymin + gesture->Point_2nd = limitPoint[1]; //xmin + gesture->Point_3rd = limitPoint[2]; //ymax + gesture->Point_4th = limitPoint[3]; //xmax + break; + + default: + gesture->gesture_type = UnkownGesture; + break; + } + +REPORT_GESTURE: + TPD_INFO("%s: gesture_id = 0x%x, gesture_type = %d, clockWise = %d, point:(%d %d)(%d %d)(%d %d)(%d %d)(%d %d)(%d %d)\n", + __func__, gesture_id, gesture->gesture_type, gesture->clockwise, + gesture->Point_start.x, gesture->Point_start.y, gesture->Point_end.x, gesture->Point_end.y, + gesture->Point_1st.x, gesture->Point_1st.y, gesture->Point_2nd.x, gesture->Point_2nd.y, + gesture->Point_3rd.x, gesture->Point_3rd.y, gesture->Point_4th.x, gesture->Point_4th.y); + +END_GESTURE: + ret = goodix_clear_irq(chip_info); //clear int + pm_qos_remove_request(&pm_qos_req_stp); + return 0; +} + +static void goodix_get_health_info(void *chip_data, struct monitor_data *mon_data) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + struct goodix_health_info *health_info; + struct goodix_health_info *health_local = &chip_info->health_info; + u8 log[20]; + int ret = 0; + u8 clear_flag = 0; + + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_DEBUG, 20, log); + if (ret < 0) { + TPD_INFO("%s: read debug log data i2c faild\n", __func__); + goto END_HEALTH; + } + + health_info = (struct goodix_health_info *)log; + + if (health_info->shield_water) { + mon_data->shield_water++; + //if (tp_debug != 0) { + TPD_INFO("%s: %s water mode\n", __func__, health_info->water_mode ? "enter" : "exit"); + //} + } + if (health_info->baseline_refresh) { + mon_data->reserve1++; + //if (tp_debug != 0) { + TPD_INFO("%s: baseline refresh type: %d \n", __func__, health_info->baseline_refresh_type); + //} + } + if (health_info->shield_freq != 0) { + mon_data->reserve2++; + //if (tp_debug != 0) { + TPD_INFO("%s: freq before: %d HZ, freq after: %d HZ\n", __func__, health_info->freq_before, health_info->freq_after); + //} + } + if (health_info->shield_esd != 0) { + mon_data->shield_esd++; + //if (tp_debug != 0) { + TPD_INFO("%s: before esd raw data max : %d\n", __func__, health_info->esd_raw); + //} + } + + memcpy(health_local, health_info, sizeof(struct goodix_health_info)); + + ret = touch_i2c_write_block(chip_info->client, chip_info->reg_info.GTP_REG_DEBUG, 1, &clear_flag); + if (ret < 0) { + TPD_INFO("%s: clear debug log data i2c faild\n", __func__); + } + +END_HEALTH: + ret = goodix_clear_irq(chip_info); //clear int + return; +} + +static int goodix_mode_switch(void *chip_data, work_mode mode, bool flag) +{ + int ret = -1; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + if (chip_info->is_power_down) { + goodix_power_control(chip_info, true); + } +/* poweroff state, no need reset */ +// if (chip_info->halt_status && (mode != MODE_NORMAL)) { +// goodix_reset(chip_info); +// } + + switch(mode) { + case MODE_NORMAL: + ret = 0; //after reset, it's already normal + break; + + case MODE_SLEEP: + //ret = goodix_enter_sleep(chip_info, flag); + //if (ret < 0) { + // TPD_INFO("%s: goodix enter sleep failed\n", __func__); + //} + //break + ret = goodix_power_control(chip_info, false); + if (ret < 0) { + TPD_INFO("%s: power down failed\n", __func__); + } + break; + + case MODE_GESTURE: + ret = goodix_enable_gesture(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: goodix enable:(%d) gesture failed.\n", __func__, flag); + return ret; + } + break; + + case MODE_EDGE: + ret = goodix_enable_edge_limit(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: goodix enable:(%d) edge limit failed.\n", __func__, flag); + return ret; + } + break; + + case MODE_CHARGE: + ret = goodix_enable_charge_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable charge mode : %d failed\n", __func__, flag); + } + break; + + case MODE_GAME: + ret = goodix_enable_game_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable game mode : %d failed\n", __func__, flag); + } + break; + + case MODE_TOUCH_HOLD: + ret = goodix_enable_fingerprint_touchhold(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable touchhold mode : %d failed\n", __func__, flag); + } + break; + + case MODE_GESTURE_SWITCH: + ret = goodix_enable_gesture_mask(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: switch gestrue mode : %d failed\n", __func__, flag); + } + break; + + default: + TPD_INFO("%s: mode %d not support.\n", __func__, mode); + } + + return ret; +} + +static int goodix_esd_handle(void *chip_data) //Jarvis:have not finished +{ + s32 ret = -1; + u8 esd_buf = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + if (!chip_info->esd_check_enabled) { + TPD_DEBUG("%s: close\n", __func__); + return 0; + } + + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_ESD_READ, 1, &esd_buf); + if ((ret < 0) || esd_buf == 0xAA) { + TPD_INFO("%s: esd dynamic esd occur, ret = %d, esd_buf = %d.\n", __func__, ret, esd_buf); + TPD_INFO("%s: IC works abnormally! Process esd reset.", __func__); + disable_irq_nosync(chip_info->client->irq); + + goodix_power_control(chip_info, false); + msleep(30); + goodix_power_control(chip_info, true); + msleep(10); + + goodix_reset(chip_data); // reset function have rewrite the esd reg no need to do it again + + tp_touch_btnkey_release(); + + enable_irq(chip_info->client->irq); + TPD_INFO("%s: Goodix esd reset over.", __func__); + pm_qos_remove_request(&pm_qos_req_stp); + return -1; + } else { + esd_buf = 0xAA; + ret = touch_i2c_write_block(chip_info->client, chip_info->reg_info.GTP_REG_ESD_WRITE, 1, &esd_buf); + if (ret < 0) { + TPD_INFO("%s: Failed to reset esd reg.", __func__); + pm_qos_remove_request(&pm_qos_req_stp); + } + } + + return 0; +} + +static int goodix_enable_fingerprint_touchhold(struct chip_data_gt9886 *chip_info, uint32_t enable) +{ + int ret = 0; + + TPD_INFO("%s, enable = %d\n", __func__, enable); + if (enable) { + ret = goodix_send_cmd(chip_info, GTP_CMD_FOD_FINGER_PRINT, 0); + } else { + ret = goodix_send_cmd(chip_info, GTP_CMD_FOD_FINGER_PRINT, 1); + } + + return ret; +} + +static int goodix_enable_gesture_mask(void *chip_data, uint32_t enable) +{ + int ret = -1; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + TPD_INFO("%s, enable = %d\n", __func__, enable); + if (enable) { + ret = goodix_send_cmd(chip_info, GTP_CMD_GESTURE_MASK, 0);/*mask all gestures */ + } else { + ret = goodix_send_cmd(chip_info, GTP_CMD_GESTURE_MASK, 1);/* enable all gesture */ + } + + return ret; +} + +static void goodix_screenon_fingerprint_info(void *chip_data, struct fp_underscreen_info *fp_tpinfo) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + TPD_INFO("%s: Entered into fingerprint function *****************\n", __func__); + if (chip_info->fp_down_flag) { + fp_tpinfo->x = chip_info->fp_coor_report.fp_x_coor; + fp_tpinfo->y = chip_info->fp_coor_report.fp_y_coor; + fp_tpinfo->area_rate = chip_info->fp_coor_report.fp_area; + fp_tpinfo->touch_state = FINGERPRINT_DOWN_DETECT; + } else { + fp_tpinfo->x = chip_info->fp_coor_report.fp_x_coor; + fp_tpinfo->y = chip_info->fp_coor_report.fp_y_coor; + fp_tpinfo->area_rate = chip_info->fp_coor_report.fp_area; + fp_tpinfo->touch_state = FINGERPRINT_UP_DETECT; + } +} + +static int goodix_fw_handle(void *chip_data) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + ret = goodix_request_event_handler(chip_info); + ret |= goodix_clear_irq(chip_info); + + pm_qos_remove_request(&pm_qos_req_stp); + return ret; +} + +static void goodix_register_info_read(void *chip_data, uint16_t register_addr, uint8_t *result, uint8_t length) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + gt9886_i2c_read(chip_info->client, register_addr, length, result); /*read data*/ +} + +static void goodix_set_touch_direction(void *chip_data, uint8_t dir) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + chip_info->touch_direction = dir; +} + +static uint8_t goodix_get_touch_direction(void *chip_data) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + return chip_info->touch_direction; +} + +static void goodix_specific_resume_operate(void *chip_data) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + TPD_DEBUG("%s call\n", __func__); + goodix_esd_check_enable(chip_info, true); +} + +static int goodix_enable_single_tap(void *chip_data, bool enable) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + chip_info->single_tap_flag = enable; + return 0; +} + +struct touchpanel_operations goodix_ops = { + .ftm_process = goodix_ftm_process, + .get_vendor = goodix_get_vendor, + .get_chip_info = goodix_get_chip_info, + .reset = goodix_reset, + .power_control = goodix_power_control, + .fw_check = goodix_fw_check, + .fw_update = goodix_fw_update, + .u32_trigger_reason = goodix_u32_trigger_reason, + .get_touch_points = goodix_get_touch_points, + .get_gesture_info = goodix_get_gesture_info, + .mode_switch = goodix_mode_switch, + .esd_handle = goodix_esd_handle, + .fw_handle = goodix_fw_handle, + .register_info_read = goodix_register_info_read, + .get_usb_state = goodix_get_usb_state, + //.enable_fingerprint = goodix_enable_fingerprint_underscreen, + //.enable_gesture_mask = goodix_enable_gesture_mask, + .screenon_fingerprint_info = goodix_screenon_fingerprint_info, + .set_touch_direction = goodix_set_touch_direction, + .get_touch_direction = goodix_get_touch_direction, + .specific_resume_operate = goodix_specific_resume_operate, + .health_report_1 = goodix_get_health_info, + .enable_single_tap = goodix_enable_single_tap, +}; +/********* End of implementation of touchpanel_operations callbacks**********************/ + +/******** Start of implementation of debug_info_proc_operations callbacks*********************/ +static void goodix_debug_info_read(struct seq_file *s, void *chip_data, debug_type debug_type) +{ + int ret = -1, i = 0, j = 0; + u8 *kernel_buf = NULL; + int addr = 0; + u8 clear_state = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + int TX_NUM = 0; + int RX_NUM = 0; + s16 data = 0; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + /*keep in active mode*/ + goodix_send_cmd(chip_info, GTP_CMD_ENTER_DOZE_TIME, 0xFF); + + ret = goodix_get_channel_num(chip_info->client, &RX_NUM, &TX_NUM); + if (ret < 0) { + TPD_INFO("get channel num fail, quit!\n"); + goto read_data_exit; + } + + kernel_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if(kernel_buf == NULL) { + TPD_INFO("%s kmalloc error\n", __func__); + return; + } + switch (debug_type) { + case GTP_RAWDATA: + addr = chip_info->reg_info.GTP_REG_RAWDATA; + break; + case GTP_DIFFDATA: + addr = chip_info->reg_info.GTP_REG_DIFFDATA; + break; + default: + addr = chip_info->reg_info.GTP_REG_BASEDATA; + break; + } + gt8x_rawdiff_mode = 1; + goodix_send_cmd(chip_info, GTP_CMD_RAWDATA, 0); + msleep(20); + gt9886_i2c_write(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, &clear_state); + + //wait for data ready + while(i++ < 10) { + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, kernel_buf); + TPD_INFO("ret = %d kernel_buf = %d\n", ret, kernel_buf[0]); + if((ret > 0) && ((kernel_buf[0] & 0x80) == 0x80)) { + TPD_INFO("Data ready OK"); + break; + } + msleep(20); + } + if(i >= 10) { + TPD_INFO("data not ready, quit!\n"); + goto read_data_exit; + } + + ret = gt9886_i2c_read(chip_info->client, addr, TX_NUM * RX_NUM * 2, kernel_buf); + msleep(5); + + for(i = 0; i < RX_NUM; i++) { + seq_printf(s, "[%2d] ", i); + for(j = 0; j < TX_NUM; j++) { + data = (kernel_buf[j * RX_NUM * 2 + i * 2] << 8) + kernel_buf[j * RX_NUM * 2 + i * 2 + 1]; + seq_printf(s, "%4d ", data); + } + seq_printf(s, "\n"); + } +read_data_exit: + goodix_send_cmd(chip_info, GTP_CMD_NORMAL, 0); + gt8x_rawdiff_mode = 0; + gt9886_i2c_write(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, &clear_state); + /*be normal in idle*/ + goodix_send_cmd(chip_info, GTP_CMD_DEFULT_DOZE_TIME, 0x00); + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + kfree(kernel_buf); + return; +} + +static void goodix_debug_info_printf(void *chip_data, debug_type debug_type) +{ + int ret = -1, i = 0, j = 0; + u8 *kernel_buf = NULL; + int addr = 0; + u8 clear_state = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + int TX_NUM = 0; + int RX_NUM = 0; + s16 data = 0; + unsigned char *Pstr = NULL; + unsigned char pTmp[15] = {0}; + int lsize = 7 * 16; + + Pstr = kzalloc(lsize * (sizeof(int)), GFP_KERNEL); + if (Pstr == NULL) + return; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + /*keep in active mode*/ + goodix_send_cmd(chip_info, GTP_CMD_ENTER_DOZE_TIME, 0xFF); + + ret = goodix_get_channel_num(chip_info->client, &RX_NUM, &TX_NUM); + if (ret < 0) { + TPD_INFO("get channel num fail, quit!\n"); + goto read_data_exit; + } + + kernel_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if(kernel_buf == NULL) { + TPD_INFO("%s kmalloc error\n", __func__); + return; + } + switch (debug_type) { + case GTP_RAWDATA: + addr = chip_info->reg_info.GTP_REG_RAWDATA; + break; + case GTP_DIFFDATA: + addr = chip_info->reg_info.GTP_REG_DIFFDATA; + break; + default: + addr = chip_info->reg_info.GTP_REG_BASEDATA; + break; + } + gt8x_rawdiff_mode = 1; + goodix_send_cmd(chip_info, GTP_CMD_RAWDATA, 0); + msleep(20); + gt9886_i2c_write(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, &clear_state); + + //wait for data ready + while(i++ < 10) { + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, kernel_buf); + TPD_INFO("ret = %d kernel_buf = %d\n", ret, kernel_buf[0]); + if((ret > 0) && ((kernel_buf[0] & 0x80) == 0x80)) { + TPD_INFO("Data ready OK"); + break; + } + msleep(20); + } + if(i >= 10) { + TPD_INFO("data not ready, quit!\n"); + goto read_data_exit; + } + + ret = gt9886_i2c_read(chip_info->client, addr, TX_NUM * RX_NUM * 2, kernel_buf); + msleep(5); + + for(i = 0; i < RX_NUM; i++) { + memset(Pstr, 0x0, lsize); + snprintf(pTmp, sizeof(pTmp), "[%d]", i); + strncat(Pstr, pTmp, lsize); + for(j = 0; j < TX_NUM; j++) { + data = (kernel_buf[j * RX_NUM * 2 + i * 2] << 8) + kernel_buf[j * RX_NUM * 2 + i * 2 + 1]; + snprintf(pTmp, sizeof(pTmp), "%4d ", data); + strncat(Pstr, pTmp, lsize); + } + TPD_INFO("%s\n", Pstr); + } +read_data_exit: + goodix_send_cmd(chip_info, GTP_CMD_NORMAL, 0); + gt8x_rawdiff_mode = 0; + gt9886_i2c_write(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 1, &clear_state); + /*be normal in idle*/ + goodix_send_cmd(chip_info, GTP_CMD_DEFULT_DOZE_TIME, 0x00); + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + kfree(Pstr); + kfree(kernel_buf); + return; +} + +static void goodix_down_diff_info_print(void *chip_data) +{ + int ret = -1, i = 0, j = 0; + u8 *kernel_buf = NULL; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + int TX_NUM = 0; + int RX_NUM = 0; + s16 diff_data = 0; + unsigned char *Pstr = NULL; + unsigned char pTmp[15] = {0}; + int lsize = 7 * 16; + + Pstr = kzalloc(lsize * (sizeof(int)), GFP_KERNEL); + if (Pstr == NULL) + return; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + kernel_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if(kernel_buf == NULL) { + TPD_INFO("%s kmalloc error\n", __func__); + return; + } + + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_DOWN_DIFFDATA, 2, kernel_buf); + if (ret < 0) { + TPD_INFO("%s failed to read down diff data.\n", __func__); + goto exit; + } + + TX_NUM = kernel_buf[0]; + RX_NUM = kernel_buf[1]; + + if (TX_NUM > 50 || RX_NUM > 50) { + TPD_INFO("%s first finger down diff data is invalid.\n", __func__); + goto exit; + } + + if ((TX_NUM * RX_NUM * 2+2) > PAGE_SIZE) { + TPD_INFO("%s: data invalid, tx:%d,rx :%d\n", __func__, TX_NUM, RX_NUM); + goto exit; + } + + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_DOWN_DIFFDATA, TX_NUM * RX_NUM * 2 + 2, kernel_buf); + if (ret < 0) { + TPD_INFO("%s failed to read down diff data.\n", __func__); + goto exit; + } + + TPD_INFO("\nfinger first down diff data:\n"); + + for(i = 0; i < RX_NUM; i++) { + memset(Pstr, 0x0, lsize); + snprintf(pTmp, sizeof(pTmp), "[%d]", i); + strncat(Pstr, pTmp, lsize); + + for(j = 0; j < TX_NUM; j++) { + diff_data = (kernel_buf[j * RX_NUM * 2 + i * 2 + 2] << 8) + kernel_buf[j * RX_NUM * 2 + i * 2 + 1 + 2]; + snprintf(pTmp, sizeof(pTmp), "%4d ", diff_data); + strncat(Pstr, pTmp, lsize); + } + TPD_INFO("%s\n", Pstr); + } + +exit: + goodix_set_i2c_doze_mode(chip_info->client, true); + if (kernel_buf) { + kfree(kernel_buf); + } + kfree(Pstr); + return; +} +static void goodix_down_diff_info_read(struct seq_file *s, void *chip_data) +{ + int ret = -1, i = 0, j = 0; + u8 *kernel_buf = NULL; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + int TX_NUM = 0; + int RX_NUM = 0; + s16 diff_data = 0; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + kernel_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if(kernel_buf == NULL) { + TPD_INFO("%s kmalloc error\n", __func__); + return; + } + + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_DOWN_DIFFDATA, 2, kernel_buf); + if (ret < 0) { + TPD_INFO("%s failed to read down diff data.\n", __func__); + goto exit; + } + + TX_NUM = kernel_buf[0]; + RX_NUM = kernel_buf[1]; + + if (TX_NUM > 50 || RX_NUM > 50) { + TPD_INFO("%s first finger down diff data is invalid.\n", __func__); + goto exit; + } + + if ((TX_NUM * RX_NUM * 2+2) > PAGE_SIZE) { + TPD_INFO("%s: data invalid, tx:%d,rx :%d\n", __func__, TX_NUM, RX_NUM); + goto exit; + } + + ret = gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_DOWN_DIFFDATA, TX_NUM * RX_NUM * 2 + 2, kernel_buf); + if (ret < 0) { + TPD_INFO("%s failed to read down diff data.\n", __func__); + goto exit; + } + + seq_printf(s, "\nfinger first down diff data:\n"); + + for(i = 0; i < RX_NUM; i++) { + seq_printf(s, "[%2d] ", i); + for(j = 0; j < TX_NUM; j++) { + diff_data = (kernel_buf[j * RX_NUM * 2 + i * 2 + 2] << 8) + kernel_buf[j * RX_NUM * 2 + i * 2 + 1 + 2]; + seq_printf(s, "%4d ", diff_data); + } + seq_printf(s, "\n"); + } + +exit: + goodix_set_i2c_doze_mode(chip_info->client, true); + if (kernel_buf) { + kfree(kernel_buf); + } + + return; +} + +//proc/touchpanel/debug_info/delta +void goodix_delta_print(bool enable) +{ + + goodix_debug_info_printf(g_tp->chip_data, GTP_DIFFDATA); + + goodix_down_diff_info_print(g_tp->chip_data); +}EXPORT_SYMBOL(goodix_delta_print); + +static void goodix_delta_read(struct seq_file *s, void *chip_data) +{ + goodix_debug_info_read(s, chip_data, GTP_DIFFDATA); + if (tp_debug) { + goodix_down_diff_info_read(s, chip_data); + } +} + +//proc/touchpanel/debug_info/baseline +static void goodix_baseline_read(struct seq_file *s, void *chip_data) +{ + goodix_debug_info_read(s, chip_data, GTP_RAWDATA); +} + +//proc/touchpanel/debug_info/main_register +static void goodix_main_register_read(struct seq_file *s, void *chip_data)//Jarvis:need change to GT9886's register +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + int ret = 0; + u8 *touch_data = NULL; + + /*. alloc touch data space */ + touch_data = kzalloc(4 + BYTES_PER_COORD, GFP_KERNEL); + if (touch_data == NULL) { + TPD_INFO("touch_data kzalloc error\n"); + return; + } + + seq_printf(s, "====================================================\n"); + if(chip_info->p_tp_fw) { + seq_printf(s, "tp fw = 0x%s\n", chip_info->p_tp_fw); + } + ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_READ_COOR, 4 + BYTES_PER_COORD, touch_data); + if (ret < 0) { + TPD_INFO("%s: i2c transfer error!\n", __func__); + goto out; + } + seq_printf(s, "touch_data reg 4100: %*ph\n", 4 + BYTES_PER_COORD, chip_info->touch_data); + TPD_INFO("%s: touch_data reg 4100: %*ph\n", __func__, 4 + BYTES_PER_COORD, chip_info->touch_data); + + seq_printf(s, "reg 4100: %*ph\n", 4 + BYTES_PER_COORD, touch_data); + TPD_INFO("%s: reg 4100: %*ph\n", __func__, 4 + BYTES_PER_COORD, touch_data); + seq_printf(s, "====================================================\n"); +out: + if (touch_data) { + kfree(touch_data); + touch_data = NULL; + } + return; +} + +static struct debug_info_proc_operations debug_info_proc_ops = { + .limit_read = goodix_limit_read, + .delta_read = goodix_delta_read, + .baseline_read = goodix_baseline_read, + .main_register_read = goodix_main_register_read, +}; +/********* End of implementation of debug_info_proc_operations callbacks**********************/ + +/************** Start of callback of proc/Goodix/config_version node**************************/ + + +/* success return config length else return -1 */ +static int goodix_do_read_config(void *chip_data, u32 base_addr, u8 *buf) +{ + int sub_bags = 0; + int offset = 0; + int subbag_len; + u8 checksum; + int i; + int ret; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + ret = gt9886_i2c_read(chip_info->client, base_addr, TS_CFG_HEAD_LEN, buf); + if (ret < 0) + goto err_out; + + offset = TS_CFG_BAG_START_INDEX; + sub_bags = buf[TS_CFG_BAG_NUM_INDEX]; + checksum = checksum_u8(buf, TS_CFG_HEAD_LEN); + if (checksum) { + TPD_INFO("Config head checksum err:0x%x,data:%*ph", checksum, TS_CFG_HEAD_LEN, buf); + ret = -EINVAL; + goto err_out; + } + + TPD_INFO("config_version:%u, vub_bags:%u", buf[0], sub_bags); + for (i = 0; i < sub_bags; i++) { + /* read sub head [0]: sub bag num, [1]: sub bag length */ + ret = gt9886_i2c_read(chip_info->client, base_addr + offset, 2, buf + offset); + if (ret < 0) + goto err_out; + + /* read sub bag data */ + subbag_len = buf[offset + 1]; + + TPD_DEBUG("sub bag num:%u,sub bag length:%u", buf[offset], subbag_len); + ret = gt9886_i2c_read(chip_info->client, base_addr + offset + 2, subbag_len + 1, buf + offset + 2); + if (ret < 0) + goto err_out; + checksum = checksum_u8(buf + offset, subbag_len + 3); + if (checksum) { + TPD_INFO("sub bag checksum err:0x%x", checksum); + ret = -EINVAL; + goto err_out; + } + offset += subbag_len + 3; + TPD_DEBUG("sub bag %d, data:%*ph", buf[offset], buf[offset + 1] + 3, buf + offset); + } + + + ret = offset; + TPD_INFO("config_version,offset:%d ", offset); + +err_out: + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + TPD_INFO("config_version2,offset:%d ", offset); + + return ret; +} + +/* success return config_len, <= 0 failed */ +int goodix_read_config(void *chip_data, u8 *config_data, u32 config_len) +{ + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + u8 cmd_flag = 0; + int ret = 0; + int i = 0; + u32 cmd_reg = chip_info->reg_info.GTP_REG_CMD; + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + /* wait for IC in IDLE state */ + for (i = 0; i < TS_WAIT_CMD_FREE_RETRY_TIMES; i++) { + cmd_flag = 0; + ret = gt9886_i2c_read(chip_info->client, cmd_reg, 1, &cmd_flag); + if (ret < 0 || cmd_flag == TS_CMD_REG_READY) + break; + usleep_range(10000, 11000); + } + if (cmd_flag != TS_CMD_REG_READY) { + TPD_INFO("Wait for IC ready IDEL state timeout:addr 0x%x\n", cmd_reg); + ret = -EAGAIN; + goto exit; + } + /* 0x86 read config command */ + ret = goodix_send_cmd(chip_info, COMMAND_START_READ_CFG, 0); + if (ret) { + TPD_INFO("Failed send read config command"); + goto exit; + } + /* wait for config data ready */ + if (goodix_wait_cfg_cmd_ready(chip_info, COMMAND_READ_CFG_PREPARE_OK, COMMAND_START_READ_CFG)) { + TPD_INFO("Wait for config data ready timeout"); + ret = -EAGAIN; + goto exit; + } + + if (config_len) { + TPD_INFO("%s:config_len:%d\n", __func__, config_len); + ret = gt9886_i2c_read(chip_info->client, cmd_reg + 16, config_len, config_data); + if (ret < 0) + TPD_INFO("Failed read config data"); + else + ret = config_len; + } else { + ret = goodix_do_read_config(chip_info, cmd_reg + 16, config_data); + if (ret < 0) + TPD_INFO("Failed read config data"); + if (ret > 0) + TPD_INFO("success read config, len:%d", ret); + } + + /* clear command */ + goodix_send_cmd(chip_info, TS_CMD_REG_READY, 0); + TPD_INFO("goodix_send_cmd exit:%d\n", ret); + + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + +exit: + TPD_INFO("goodix_read_config exit:%d\n", ret); + return ret; +} + +static void goodix_config_info_read(struct seq_file *s, void *chip_data) +{ + int ret = 0, i = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + char temp_data[TS_CFG_MAX_LEN] = {0}; + + seq_printf(s, "==== Goodix default config setting in driver====\n"); + for(i = 0; i < TS_CFG_MAX_LEN && i < chip_info->normal_cfg.length; i++) { + seq_printf(s, "0x%02X, ", chip_info->normal_cfg.data[i]); + if(i % 10 == 9) + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + seq_printf(s, "==== Goodix test cfg in driver====\n"); + for(i = 0; i < TS_CFG_MAX_LEN && i < chip_info->test_cfg.length; i++) { + seq_printf(s, "0x%02X, ", chip_info->test_cfg.data[i]); + if(i % 10 == 9) + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + seq_printf(s, "==== Goodix noise test cfg in driver====\n"); + for(i = 0; i < TS_CFG_MAX_LEN && i < chip_info->noise_test_cfg.length; i++) { + seq_printf(s, "0x%02X, ", chip_info->noise_test_cfg.data[i]); + if(i % 10 == 9) + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + + seq_printf(s, "==== Goodix config read from chip====\n"); + + if (!chip_info->reg_info.GTP_REG_CMD) { + TPD_INFO("command register ERROR:0x%04x", chip_info->reg_info.GTP_REG_CMD); + return; + } + + ret = goodix_read_config(chip_info, temp_data, 0); + if(ret < 0) { + TPD_INFO("goodix_config_info_read goodix_read_config error:%d\n", ret); + goto exit; + } + + seq_printf(s, "\n"); + seq_printf(s, "==== Goodix Version Info ====\n"); + + seq_printf(s, "ConfigVer: %02X\n", temp_data[0]); + gt9886_i2c_read(chip_info->client, chip_info->reg_info.GTP_REG_PRODUCT_VER, 72, temp_data); + seq_printf(s, "ProductID: GT%c%c%c%c\n", temp_data[9], temp_data[10], temp_data[11], temp_data[12]); + seq_printf(s, "PatchID: %02X%02X%02X%02X\n", temp_data[17], temp_data[18], temp_data[19], temp_data[20]); + seq_printf(s, "MaskID: %02X%02X%02X\n", temp_data[6], temp_data[7], temp_data[8]); + seq_printf(s, "SensorID: %02X\n", temp_data[21]); + + +exit: + return; +} +/*************** End of callback of proc/Goodix/config_version node***************************/ + +static u8 goodix_config_version_read(struct chip_data_gt9886 *chip_info) +{ + int ret = 0, i = 0; + u8 cmd_flag; + u32 cmd_reg = chip_info->reg_info.GTP_REG_CMD; + char temp_data[TS_CFG_MAX_LEN] = {0}; + + if (!chip_info->reg_info.GTP_REG_CMD) { + TPD_INFO("command register ERROR:0x%04x", chip_info->reg_info.GTP_REG_CMD); + return -EINVAL; + } + + /*disable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, false); + + /* wait for IC in IDLE state */ + for (i = 0; i < TS_WAIT_CMD_FREE_RETRY_TIMES; i++) { + cmd_flag = 0; + ret = gt9886_i2c_read(chip_info->client, cmd_reg, 1, &cmd_flag); + if (ret < 0 || cmd_flag == TS_CMD_REG_READY) + break; + usleep_range(10000, 11000); + } + if (cmd_flag != TS_CMD_REG_READY) { + TPD_INFO("Wait for IC ready IDEL state timeout:addr 0x%x\n", cmd_reg); + ret = -EAGAIN; + goto exit; + } + /* 0x86 read config command */ + ret = goodix_send_cmd(chip_info, COMMAND_START_READ_CFG, 0); + if (ret) { + TPD_INFO("Failed send read config command"); + goto exit; + } + /* wait for config data ready */ + if (goodix_wait_cfg_cmd_ready(chip_info, COMMAND_READ_CFG_PREPARE_OK, COMMAND_START_READ_CFG)) { + TPD_INFO("Wait for config data ready timeout"); + ret = -EAGAIN; + goto exit; + } + + ret = goodix_do_read_config(chip_info, cmd_reg + 16, temp_data); + if (ret < 0) + TPD_INFO("Failed read config data"); + if (ret > 0) + TPD_INFO("success read config, len:%d", ret); + + /* clear command */ + goodix_send_cmd(chip_info, TS_CMD_REG_READY, 0); + ret = temp_data[0]; + +exit: + /*enable doze mode*/ + goodix_set_i2c_doze_mode(chip_info->client, true); + return ret; +} + +/************** Start of atuo test func**************************/ + +/*********************************************************************** + * Function Name : gtx8_get_cfg_value + * Description : read config data specified by sub-bag number and inside-bag offset. + * config : pointer to config data + * buf : output buffer + * len : data length want to read, if len = 0, get full bag data + * sub_bag_num : sub-bag number + * offset : offset inside sub-bag + * Return : int(return offset with config[0], < 0 failed) + *******************************************************************************/ +static int gtx8_get_cfg_value(u8 *config, u8 *buf, u8 len, u8 sub_bag_num, u8 offset) +{ + u8 *sub_bag_ptr = NULL; + u8 i = 0; + + sub_bag_ptr = &config[4]; + for (i = 0; i < config[2]; i++) { + if (sub_bag_ptr[0] == sub_bag_num) + break; + sub_bag_ptr += sub_bag_ptr[1] + 3; + } + + if (i >= config[2]) { + TPD_INFO("Cann't find the specifiled bag num %d\n", sub_bag_num); + return -EINVAL; + } + + if (sub_bag_ptr[1] + 3 < offset + len) { + TPD_INFO("Sub bag len less then you want to read: %d < %d\n", sub_bag_ptr[1] + 3, offset + len); + return -EINVAL; + } + + if (len) + memcpy(buf, sub_bag_ptr + offset, len); + else + memcpy(buf, sub_bag_ptr, sub_bag_ptr[1] + 3); + return (sub_bag_ptr + offset - config); +} + +/******************************************************************************* + * Function Name : cfg_update_chksum + * Description : update check sum + * Input : u32* config + * Input : u16 cfg_len + * Output : u8* config + * Return : none + *******************************************************************************/ +static void cfg_update_chksum(u8 *config, u16 cfg_len) +{ + u16 pack_map_len_arr[100]; + u16 packNum = 0; + u16 pack_len_tmp = 0; + u16 pack_id_tmp = 0; + u16 i = 0, j = 0; + u16 cur_pos = 0; + u8 check_sum = 0; + + if (cfg_len < 4) return; + /* Head:4 bytes |byte0:version|byte1:config refresh|byte2:package total num|byte3:check sum|*/ + pack_map_len_arr[pack_id_tmp] = 4; + packNum = config[2]; + for (i = 4; i < cfg_len;) { + pack_id_tmp++; + pack_len_tmp = config[i + 1] + 3; + pack_map_len_arr[pack_id_tmp] = pack_len_tmp; + i += pack_len_tmp; + } + + cur_pos = 0; + for (i = 0; i <= pack_id_tmp; i++) { + check_sum = 0; + for (j = cur_pos; j < cur_pos + pack_map_len_arr[i] - 1; j++) { + check_sum += config[j]; + } + config[cur_pos + pack_map_len_arr[i] - 1] = (u8)(0 - check_sum); + cur_pos += pack_map_len_arr[i]; + } +} + +static int disable_hopping(struct gtx8_ts_test *ts_test, struct goodix_ts_config *test_config) +{ + int ret = 0; + u8 value = 0; + u16 offset = 0; + ret = gtx8_get_cfg_value(test_config->data, &value, 1, 10, 2); + if (ret < 0 ) { + TPD_INFO("Failed parse hopping reg\n"); + return -EINVAL; + } + offset = ret; + /* disable hopping */ + value = test_config->data[offset]; + value &= 0xfe; + test_config->data[offset] = value; + TPD_INFO("disable_hopping:0x%02x_%d", test_config->data[offset], offset); + cfg_update_chksum(test_config->data, test_config->length); + return ret; +} + +static int init_test_config(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + if (ts_test->test_config.length == 0) { + TPD_INFO("switch to orignal config!\n"); + memmove(ts_test->test_config.data, ts_test->orig_config.data, ts_test->orig_config.length); + ts_test->test_config.length = ts_test->orig_config.length; + } else { + ts_test->test_config.data[0] = ts_test->orig_config.data[0]; + ts_test->test_config.data[1] |= 0x01; + TPD_INFO("switch to test config!\n"); + } + ts_test->test_config.reg_base = chip_info->reg_info.GTP_REG_CONFIG_DATA; + mutex_init(&(ts_test->test_config.lock)); + ts_test->test_config.initialized = true; + strcpy(ts_test->test_config.name, "test_config"); + disable_hopping(ts_test, &ts_test->test_config); + return ret; +} + +static void gtx8_print_testdata(struct gtx8_ts_test *ts_test) +{ + struct ts_test_params *test_params = NULL; + int i = 0; + test_params = &ts_test->test_params; + + if (tp_debug < 2) + return; + TPD_DEBUG("rawdata:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->rawdata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("noisedata:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->noisedata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_rawdata:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->self_rawdata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_noisedata:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->self_noisedata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } +} + +static void gtx8_print_test_params(struct gtx8_ts_test *ts_test) +{ + struct ts_test_params *test_params = NULL; + int i = 0; + test_params = &ts_test->test_params; + + if (tp_debug < 2) + return; + TPD_DEBUG("sen_num:%d,drv_num:%d\n", test_params->sen_num, test_params->drv_num); + TPD_DEBUG("rawdata_addr:%d,noisedata_addr:%d\n", test_params->rawdata_addr, test_params->noisedata_addr); + TPD_DEBUG("self_rawdata_addr:%d,self_noisedata_addr:%d\n", test_params->self_rawdata_addr, test_params->self_noisedata_addr); + TPD_DEBUG("basedata_addr:%d\n", test_params->basedata_addr); + + TPD_DEBUG("max_limits:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d", test_params->max_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("min_limits:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->min_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("deviation_limits:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->deviation_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_max_limits:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->self_max_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_min_limits:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->self_min_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } +} + +static int gtx8_init_testlimits(struct gtx8_ts_test *ts_test) +{ + struct goodix_testdata *p_testdata = ts_test->p_testdata; + struct test_item_info *p_test_item_info = NULL; + /*for item parameter data*/ + uint32_t *para_data32 = NULL; + uint32_t para_num = 0; + int ret = 0; + struct ts_test_params *test_params = NULL; + + test_params = &ts_test->test_params; + test_params->drv_num = p_testdata->TX_NUM; + test_params->sen_num = p_testdata->RX_NUM; + TPD_INFO("sen_num:%d,drv_num:%d\n", test_params->sen_num, test_params->drv_num); + + para_data32 = getpara_for_item(p_testdata->fw, TYPE_NOISE_DATA_LIMIT, ¶_num); + if(para_data32) { + ts_test->is_item_support[TYPE_NOISE_DATA_LIMIT] = para_data32[0]; + if (para_num >= 2) { + /* store data to test_parms */ + test_params->noise_threshold = para_data32[1]; + } + } else { + TPD_INFO("%s: Failed get %s\n", __func__, CSV_TP_NOISE_LIMIT); + ret = -1; + goto INIT_LIMIT_END; + } + + para_data32 = getpara_for_item(p_testdata->fw, TYPE_SHORT_THRESHOLD, ¶_num); + if(para_data32) { + ts_test->is_item_support[TYPE_SHORT_THRESHOLD] = para_data32[0]; + TPD_INFO("get TYPE_SHORT_THRESHOLD data,len:%d\n", para_num); + if (para_num >= 8) { + /* store data to test_parms */ + test_params->short_threshold = para_data32[1]; + test_params->r_drv_drv_threshold = para_data32[2]; + test_params->r_drv_sen_threshold = para_data32[3]; + test_params->r_sen_sen_threshold = para_data32[4]; + test_params->r_drv_gnd_threshold = para_data32[5]; + test_params->r_sen_gnd_threshold = para_data32[6]; + test_params->avdd_value = para_data32[7]; + } + } else { + TPD_INFO("%s: Failed get %s\n", __func__, CSV_TP_SHORT_THRESHOLD); + ret = -1; + goto INIT_LIMIT_END; + } + + p_test_item_info = get_test_item_info(p_testdata->fw, TYPE_SPECIAL_RAW_MAX_MIN); + if(p_test_item_info) { + if (p_test_item_info->para_num) { + if (p_test_item_info->p_buffer[0]) { + TPD_INFO("get TYPE_SPECIAL_RAW_MAX_MIN data,len:%d\n", para_num); + ts_test->is_item_support[TYPE_SPECIAL_RAW_MAX_MIN] = p_test_item_info->p_buffer[0]; + if (p_test_item_info->item_limit_type == LIMIT_TYPE_MAX_MIN_DATA) { + test_params->max_limits = (uint32_t *)(p_testdata->fw->data + p_test_item_info->top_limit_offset); + test_params->min_limits = (uint32_t *)(p_testdata->fw->data + p_test_item_info->floor_limit_offset); + } else { + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_MAX_MIN); + } + } + } + } else { + ret = -1; + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_MAX_MIN); + } + + p_test_item_info = get_test_item_info(p_testdata->fw, TYPE_SPECIAL_RAW_DELTA); + if (p_test_item_info) { + if (p_test_item_info->para_num) { + if (p_test_item_info->p_buffer[0]) { + TPD_INFO("get TYPE_SPECIAL_RAW_DELTA data,len:%d\n", para_num); + ts_test->is_item_support[TYPE_SPECIAL_RAW_DELTA] = p_test_item_info->p_buffer[0]; + if (p_test_item_info->item_limit_type == LIMIT_TYPE_MAX_MIN_DATA) { + test_params->deviation_limits = (uint32_t *)(p_testdata->fw->data + p_test_item_info->top_limit_offset); + } else { + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_DELTA); + } + } + } + } else { + ret = -1; + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_DELTA); + } + + para_data32 = getpara_for_item(p_testdata->fw, TYPE_NOISE_SLEFDATA_LIMIT, ¶_num); + if(para_data32) { + ts_test->is_item_support[TYPE_NOISE_SLEFDATA_LIMIT] = para_data32[0]; + if (para_num >= 2) { + /* store data to test_parms */ + test_params->self_noise_threshold = para_data32[1]; + } + } else { + TPD_INFO("%s: Failed get %s\n", __func__, CSV_TP_SELFNOISE_LIMIT); + ret = -1; + goto INIT_LIMIT_END; + } + + p_test_item_info = get_test_item_info(p_testdata->fw, TYPE_SPECIAL_SELFRAW_MAX_MIN); + if(p_test_item_info) { + if (p_test_item_info->para_num) { + if (p_test_item_info->p_buffer[0]) { + ts_test->is_item_support[TYPE_SPECIAL_SELFRAW_MAX_MIN] = p_test_item_info->p_buffer[0]; + if (p_test_item_info->item_limit_type == IMIT_TYPE_SLEFRAW_DATA) { + TPD_INFO("get IMIT_TYPE_SLEFRAW_DATA data\n"); + test_params->self_max_limits = (int32_t *)(p_testdata->fw->data + p_test_item_info->top_limit_offset); + test_params->self_min_limits = (int32_t *)(p_testdata->fw->data + p_test_item_info->floor_limit_offset); + } else { + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_SELFRAW_MAX_MIN); + } + } else { + TPD_INFO("TYPE_SPECIAL_SELFRAW_MAX_MIN para_num is invalid\n"); + } + } + } else { + ret = -1; + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_SELFRAW_MAX_MIN); + } + + ret |= init_test_config(ts_test); + +INIT_LIMIT_END: + if (p_test_item_info) { + kfree(p_test_item_info); + } + return ret; +} + +static int gtx8_init_params(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + struct ts_test_params *test_params = &ts_test->test_params; + + TPD_INFO("%s run\n", __func__); + + test_params->rawdata_addr = GTP_RAWDATA_ADDR_9886; + test_params->noisedata_addr = GTP_NOISEDATA_ADDR_9886; + test_params->self_rawdata_addr = GTP_SELF_RAWDATA_ADDR_9886; + test_params->self_noisedata_addr = GTP_SELF_NOISEDATA_ADDR_9886; + test_params->basedata_addr = GTP_BASEDATA_ADDR_9886; + test_params->max_drv_num = MAX_DRV_NUM; + test_params->max_sen_num = MAX_SEN_NUM; + test_params->drv_map = gt9886_drv_map; + test_params->sen_map = gt9886_sen_map; + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +/* init cmd data*/ +static int gtx8_init_cmds(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + /* init rawdata cmd */ + ts_test->rawdata_cmd.initialized = 1; + ts_test->rawdata_cmd.cmd_reg = chip_info->reg_info.GTP_REG_CMD; + ts_test->rawdata_cmd.length = 3; + ts_test->rawdata_cmd.cmds[0] = GTX8_CMD_RAWDATA; + ts_test->rawdata_cmd.cmds[1] = 0x00; + ts_test->rawdata_cmd.cmds[2] = (u8)((0 - ts_test->rawdata_cmd.cmds[0] - + ts_test->rawdata_cmd.cmds[1]) & 0xff); + /* init normal cmd */ + ts_test->normal_cmd.initialized = 1; + ts_test->normal_cmd.cmd_reg = chip_info->reg_info.GTP_REG_CMD; + ts_test->normal_cmd.length = 3; + ts_test->normal_cmd.cmds[0] = GTX8_CMD_NORMAL; + ts_test->normal_cmd.cmds[1] = 0x00; + ts_test->normal_cmd.cmds[2] = (u8)((0 - ts_test->normal_cmd.cmds[0] - + ts_test->normal_cmd.cmds[1]) & 0xff); + + TPD_INFO("cmd addr.0x%04x\n", ts_test->rawdata_cmd.cmd_reg); + return ret; +} + +/* gtx8_read_origconfig + * + * read original config data + */ +static int gtx8_cache_origconfig(struct gtx8_ts_test *ts_test) +{ + int ret = -ENODEV; + u8 checksum = 0; + + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + TPD_INFO("gtx8_cache_origconfig run\n"); + + ret = goodix_read_config(chip_info, &ts_test->orig_config.data[0], 0); + if (ret < 0) { + TPD_INFO("Failed to read original config data\n"); + return ret; + } + TPD_INFO("gtx8_cache_origconfig read original config success\n"); + + ts_test->orig_config.data[1] |= GTX8_CONFIG_REFRESH_DATA; + checksum = checksum_u8(&ts_test->orig_config.data[0], 3); + ts_test->orig_config.data[3] = (u8)(0 - checksum); + + mutex_init(&ts_test->orig_config.lock); + ts_test->orig_config.length = ret; + strcpy(ts_test->orig_config.name, "original_config"); + ts_test->orig_config.initialized = true; + + TPD_INFO("gtx8_cache_origconfig exit\n"); + return NO_ERR; +} + +/* gtx8_tptest_prepare + * + * preparation before tp test + */ +static int gtx8_tptest_prepare(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + TPD_INFO("TP test preparation\n"); + ret = gtx8_cache_origconfig(ts_test); + if (ret) { + TPD_INFO("Failed cache origin config\n"); + return ret; + } + + /* init cmd*/ + ret = gtx8_init_cmds(ts_test); + if (ret) { + TPD_INFO("Failed init cmd\n"); + return ret; + } + + /* init reg addr and short cal map */ + ret = gtx8_init_params(ts_test); + if (ret) { + TPD_INFO("Failed init register address\n"); + return ret; + } + /* parse test limits from csv */ + ret = gtx8_init_testlimits(ts_test); + if (ret < 0) { + TPD_INFO("Failed to init testlimits from csv:%d\n", ret); + ts_test->error_count ++; + seq_printf(ts_test->p_seq_file, "Failed to init testlimits from csv\n"); + } + ret = goodix_send_config(chip_info, chip_info->noise_test_cfg.data, chip_info->noise_test_cfg.length); + if (ret < 0) { + TPD_INFO("Failed to send noise test config config:%d,noise_config len:%d\n", ret, chip_info->noise_test_cfg.length); + } + TPD_INFO("send noise test config success :%d,noise_config len:%d\n", ret, chip_info->noise_test_cfg.length); + //msleep(50); + + return ret; +} + +/* gtx8_tptest_finish + * + * finish test + */ +static int gtx8_tptest_finish(struct gtx8_ts_test *ts_test) +{ + int ret = RESULT_ERR; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + TPD_INFO("TP test finish\n"); + goodix_reset_via_gpio(chip_info); + + // if (goodix_set_i2c_doze_mode(core_data->ts_dev,true)) + // ts_info("WRNING: doze may enabled after reset\n"); + ret = goodix_send_config(chip_info, ts_test->orig_config.data, ts_test->orig_config.length); + if(ret < 0) { + TPD_INFO("gtx8_tptest_finish:Failed to send normal config:%d\n", ret); + } else { + TPD_INFO("gtx8_tptest_finish send normal config succesful\n"); + } + + return ret; +} + +static int normandy_sync_read_rawdata(struct i2c_client *client, + unsigned int sync_addr, unsigned char sync_mask, + unsigned int reg_addr, unsigned char *data, + unsigned int len) +{ + int ret = 0; + int retry_times = 0; + unsigned char sync_data[0]; + + + TPD_INFO("%s run,reg_addr:0x%04x,len:%d,sync_addr:0x%04x,sync_mask:0x%x\n", + __func__, reg_addr, len, sync_addr, sync_mask); + + while(retry_times ++ < 200) { + sync_data[0] = 0x00; + msleep(10); + ret = touch_i2c_read_block(client, sync_addr, 1, sync_data); + if(ret < 0 || ((sync_data[0] & sync_mask) == 0)) { + TPD_INFO("%s sync invalid,ret:%d,sync data:0x%x\n", + __func__, ret, sync_data[0]); + continue; + } + + TPD_INFO("%s sync is valid:0x%x\n", __func__, sync_data[0]); + + ret = touch_i2c_read_block(client, reg_addr, len, data); + if(ret < 0) { + TPD_INFO("sync read rawdata failed:%d\n", ret); + } else { + break; + } + } + + if(retry_times >= 200) { + TPD_INFO("sync read rawdata timeout\n"); + ret = -1; + } else { + TPD_INFO("sync read rawdata,get rawdata success\n"); + sync_data[0] = 0x00; + ret = touch_i2c_write_block(client, sync_addr, 1, sync_data); + TPD_INFO("sync read rawdata,clear sync\n"); + ret = 0; + } + + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +/** + * gtx8_cache_rawdata - cache rawdata + */ +static int gtx8_cache_rawdata(struct gtx8_ts_test *ts_test) +{ + int j = 0; + int i = 0; + int ret = -EINVAL; + u32 rawdata_size = 0; + u16 rawdata_addr = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + TPD_INFO("Cache rawdata\n"); + ts_test->rawdata.size = 0; + rawdata_size = ts_test->test_params.sen_num * ts_test->test_params.drv_num; + + if (rawdata_size > MAX_DRV_NUM * MAX_SEN_NUM || rawdata_size <= 0) { + TPD_INFO("Invalid rawdata size(%u)\n", rawdata_size); + return ret; + } + + rawdata_addr = ts_test->test_params.rawdata_addr; + TPD_INFO("Rawdata address=0x%x\n", rawdata_addr); + + for (j = 0; j < GTX8_RETRY_NUM_3; j++) { + /* read rawdata */ + ret = normandy_sync_read_rawdata(chip_info->client, + chip_info->reg_info.GTP_REG_READ_COOR, 0x80, rawdata_addr, + (u8 *)&ts_test->rawdata.data[0], rawdata_size * sizeof(u16)); + if (ret < 0) { + if (j == GTX8_RETRY_NUM_3 - 1) { + TPD_INFO("Failed to read rawdata:%d,at:%d\n", ret, j); + goto cache_exit; + } else { + continue; + } + } + for (i = 0; i < rawdata_size; i++) + ts_test->rawdata.data[i] = be16_to_cpu(ts_test->rawdata.data[i]); + ts_test->rawdata.size = rawdata_size; + TPD_INFO("Rawdata ready\n"); + break; + } + +cache_exit: + return ret; +} + +/** + * gtx8_cache_selfrawdata - cache selfrawdata + */ +static int gtx8_cache_self_rawdata(struct gtx8_ts_test *ts_test) +{ + int i = 0, j = 0; + int ret = -EINVAL; + u16 self_rawdata_size = 0; + u16 self_rawdata_addr = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + TPD_INFO("Cache selfrawdata\n"); + ts_test->self_rawdata.size = 0; + self_rawdata_size = ts_test->test_params.sen_num + ts_test->test_params.drv_num; + + if (self_rawdata_size > MAX_DRV_NUM + MAX_SEN_NUM || self_rawdata_size <= 0) { + TPD_INFO("Invalid selfrawdata size(%u)\n", self_rawdata_size); + return ret; + } + + self_rawdata_addr = ts_test->test_params.self_rawdata_addr; + TPD_INFO("Selfraw address=0x%x\n", self_rawdata_addr); + + for (j = 0; j < GTX8_RETRY_NUM_3; j++) { + /* read selfrawdata */ + ret = normandy_sync_read_rawdata(chip_info->client, + chip_info->reg_info.GTP_REG_READ_COOR, 0x80, + self_rawdata_addr, (u8 *)&ts_test->self_rawdata.data[0], + self_rawdata_size * sizeof(u16)); + if (ret < 0) { + if (j == GTX8_RETRY_NUM_3 - 1) { + TPD_INFO("Failed to read self_rawdata:%d\n", ret); + goto cache_exit; + } else { + continue; + } + } + for (i = 0; i < self_rawdata_size; i++) + ts_test->self_rawdata.data[i] = be16_to_cpu(ts_test->self_rawdata.data[i]); + ts_test->self_rawdata.size = self_rawdata_size; + TPD_INFO("self_Rawdata ready\n"); + break; + } + +cache_exit: + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +/** + * gtx8_noisetest_prepare- noisetest prepare + */ +static int gtx8_noisetest_prepare(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + u32 noise_data_size = 0; + u32 self_noise_data_size = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + TPD_INFO("%s run\n", __func__); + noise_data_size = ts_test->test_params.sen_num * ts_test->test_params.drv_num; + self_noise_data_size = ts_test->test_params.sen_num + ts_test->test_params.drv_num; + + if (noise_data_size <= 0 || noise_data_size > MAX_DRV_NUM * MAX_SEN_NUM) { + TPD_INFO("%s: Bad noise_data_size[%d]\n", __func__, noise_data_size); + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + return -EINVAL; + } + + if (self_noise_data_size <= 0 || self_noise_data_size > MAX_DRV_NUM + MAX_SEN_NUM) { + TPD_INFO("%s: Bad self_noise_data_size[%d]\n", __func__, self_noise_data_size); + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; + return -EINVAL; + } + + ts_test->noisedata.size = noise_data_size; + ts_test->self_noisedata.size = self_noise_data_size; + + TPD_INFO("%s: noise test prepare rawdata addr:0x%04x,len:%d", + __func__, ts_test->rawdata_cmd.cmd_reg, + ts_test->rawdata_cmd.length); + /* change to rawdata mode */ + ret = touch_i2c_write_block(chip_info->client, ts_test->rawdata_cmd.cmd_reg, + ts_test->rawdata_cmd.length, ts_test->rawdata_cmd.cmds); + if (ret < 0) { + TPD_INFO("%s: Failed send rawdata command:ret%d\n", __func__, ret); + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; + return ret; + } + msleep(50); + + TPD_INFO("%s: Enter rawdata mode\n", __func__); + + return ret; +} + +/** + * gtx8_cache_noisedata- cache noisedata + */ +static int gtx8_cache_noisedata(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + int ret1 = 0; + u16 noisedata_addr = 0; + u16 self_noisedata_addr = 0; + u32 noise_data_size = 0; + u32 self_noise_data_size = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + noisedata_addr = ts_test->test_params.noisedata_addr; + self_noisedata_addr = ts_test->test_params.self_noisedata_addr; + noise_data_size = ts_test->noisedata.size; + self_noise_data_size = ts_test->self_noisedata.size; + + /* read noise data */ + ret = normandy_sync_read_rawdata(chip_info->client, + chip_info->reg_info.GTP_REG_READ_COOR, 0x80, + noisedata_addr, (u8 *)&ts_test->noisedata.data[0], + noise_data_size * sizeof(u16)); + if (ret < 0) { + TPD_INFO("%s: Failed read noise data\n", __func__); + ts_test->noisedata.size = 0; + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + } + + /* read self noise data */ + ret1 = normandy_sync_read_rawdata(chip_info->client, + chip_info->reg_info.GTP_REG_READ_COOR, 0x80, + self_noisedata_addr, (u8 *)&ts_test->self_noisedata.data[0], + self_noise_data_size * sizeof(u16)); + if (ret1 < 0) { + TPD_INFO("%s: Failed read self noise data\n", __func__); + ts_test->self_noisedata.size = 0; + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; + } + + TPD_INFO("%s exit:%d\n", __func__, ret | ret1); + return ret | ret1; +} + +/** + * gtx8_analyse_noisedata- analyse noisedata + */ +static void gtx8_analyse_noisedata(struct gtx8_ts_test *ts_test) +{ + int i = 0; + u32 find_bad_node = 0; + s16 noise_value = 0; + + for (i = 0; i < ts_test->noisedata.size; i++) { + noise_value = (s16)be16_to_cpu(ts_test->noisedata.data[i]); + ts_test->noisedata.data[i] = abs(noise_value); + + if (ts_test->noisedata.data[i] > ts_test->test_params.noise_threshold) { + find_bad_node++; + TPD_INFO("noise check failed: niose[%d][%d]:%u, > %u\n", + (u32)div_s64(i, ts_test->test_params.sen_num), + i % ts_test->test_params.sen_num, + ts_test->noisedata.data[i], + ts_test->test_params.noise_threshold); + } + } + if (find_bad_node) { + TPD_INFO("%s:noise test find bad node\n", __func__); + ts_test->test_result[GTP_NOISE_TEST] = GTP_PANEL_REASON; + } else { + ts_test->test_result[GTP_NOISE_TEST] = GTP_TEST_PASS; + TPD_INFO("noise test check pass\n"); + } + + return; +} + +/** + * gtx8_analyse_self_noisedata- analyse self noisedata + */ +static void gtx8_analyse_self_noisedata(struct gtx8_ts_test *ts_test) +{ + int i = 0; + u32 self_find_bad_node = 0; + s16 self_noise_value = 0; + TPD_INFO("%s run\n", __func__); + for (i = 0; i < ts_test->self_noisedata.size; i++) { + self_noise_value = (s16)be16_to_cpu(ts_test->self_noisedata.data[i]); + ts_test->self_noisedata.data[i] = abs(self_noise_value); + + if (ts_test->self_noisedata.data[i] > ts_test->test_params.self_noise_threshold) { + self_find_bad_node++; + TPD_INFO("self noise check failed: self_noise[%d][%d]:%u, > %u\n", + (u32)div_s64(i, ts_test->test_params.drv_num), + i % ts_test->test_params.drv_num, + ts_test->self_noisedata.data[i], + ts_test->test_params.self_noise_threshold); + } + } + + if (self_find_bad_node) { + TPD_INFO("%s:self_noise test find bad node", __func__); + ts_test->test_result[GTP_SELFNOISE_TEST] = GTP_PANEL_REASON; + } else { + ts_test->test_result[GTP_SELFNOISE_TEST] = GTP_TEST_PASS; + TPD_INFO("self noise test check passed\n"); + } + TPD_INFO("%s exit\n", __func__); + return; +} + + +/* test noise data */ +static void gtx8_test_noisedata(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + int test_cnt = 0; + u8 buf[1]; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + TPD_INFO("%s run\n", __func__); + ret = gtx8_noisetest_prepare(ts_test); + if (ret < 0) { + TPD_INFO("%s :Noisetest prepare failed\n", __func__); + goto soft_err_out; + } + + /* read noisedata and self_noisedata,calculate result */ + for (test_cnt = 0; test_cnt < RAWDATA_TEST_TIMES; test_cnt++) { + ret = gtx8_cache_noisedata(ts_test); + if (ret) { + if (test_cnt == RAWDATA_TEST_TIMES - 1) { + TPD_INFO("%s: Cache noisedata failed\n", __func__); + goto soft_err_out; + } else { + continue; + } + } + gtx8_analyse_noisedata(ts_test); + + gtx8_analyse_self_noisedata(ts_test); + break; + } + + TPD_INFO("%s: Noisedata and Self_noisedata test end\n", __func__); + goto noise_test_exit; + +soft_err_out: + ts_test->noisedata.size = 0; + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + ts_test->self_noisedata.size = 0; + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; +noise_test_exit: + //core_data->ts_dev->hw_ops->send_cmd(core_data->ts_dev, &ts_test->normal_cmd); + ret = touch_i2c_write_block(chip_info->client, ts_test->normal_cmd.cmd_reg, + ts_test->normal_cmd.length, ts_test->normal_cmd.cmds); + + buf[0] = 0x00; + ret = touch_i2c_write_block(chip_info->client, GTP_REG_COOR, 1, buf); + return; +} + +static int gtx8_self_rawcapacitance_test(struct ts_test_self_rawdata *rawdata, + struct ts_test_params *test_params) +{ + int i = 0; + int ret = NO_ERR; + + for (i = 0; i < rawdata->size; i++) { + if (rawdata->data[i] > test_params->self_max_limits[i]) { + TPD_INFO("self_rawdata[%d][%d]:%u >self_max_limit:%u, NG\n", + (u32)div_s64(i, test_params->drv_num), i % test_params->drv_num, + rawdata->data[i], test_params->self_max_limits[i]); + ret = RESULT_ERR; + } + + if (rawdata->data[i] < test_params->self_min_limits[i]) { + TPD_INFO("self_rawdata[%d][%d]:%u < min_limit:%u, NG\n", + (u32)div_s64(i, test_params->drv_num), i % test_params->drv_num, + rawdata->data[i], test_params->self_min_limits[i]); + ret = RESULT_ERR; + } + } + + return ret; +} + + +/* gtx8_captest_prepare + * + * parse test peremeters from dt + */ +static int gtx8_captest_prepare(struct gtx8_ts_test *ts_test) +{ + int ret = -EINVAL; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + TPD_INFO("%s run\n", __func__); + + ret = goodix_send_config(chip_info, chip_info->test_cfg.data, chip_info->test_cfg.length); + if (ret) + TPD_INFO("Failed to send test config:%d\n", ret); + else + TPD_INFO("Success send test config"); + + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +static int gtx8_rawcapacitance_test(struct ts_test_rawdata *rawdata, + struct ts_test_params *test_params) +{ + int i = 0; + int ret = NO_ERR; + + for (i = 0; i < rawdata->size; i++) { + if (rawdata->data[i] > test_params->max_limits[i]) { + TPD_INFO("rawdata[%d][%d]:%u > max_limit:%u, NG\n", + (u32)div_s64(i, test_params->sen_num), i % test_params->sen_num, + rawdata->data[i], test_params->max_limits[i]); + ret = RESULT_ERR; + } + + if (rawdata->data[i] < test_params->min_limits[i]) { + TPD_INFO("rawdata[%d][%d]:%u < min_limit:%u, NG\n", + (u32)div_s64(i, test_params->sen_num), i % test_params->sen_num, + rawdata->data[i], test_params->min_limits[i]); + ret = RESULT_ERR; + } + } + + return ret; +} + +static int gtx8_deltacapacitance_test(struct ts_test_rawdata *rawdata, + struct ts_test_params *test_params) +{ + int i = 0; + int ret = NO_ERR; + int cols = 0; + u32 max_val = 0; + u32 rawdata_val = 0; + u32 sc_data_num = 0; + u32 up = 0, down = 0, left = 0, right = 0; + + cols = test_params->sen_num; + sc_data_num = test_params->drv_num * test_params->sen_num; + if (cols <= 0) { + TPD_INFO("%s: parmas invalid\n", __func__); + return RESULT_ERR; + } + + for (i = 0; i < sc_data_num; i++) { + rawdata_val = rawdata->data[i]; + max_val = 0; + /* calculate deltacpacitance with above node */ + if (i - cols >= 0) { + up = rawdata->data[i - cols]; + up = abs(rawdata_val - up); + if (up > max_val) + max_val = up; + } + + /* calculate deltacpacitance with bellow node */ + if (i + cols < sc_data_num) { + down = rawdata->data[i + cols]; + down = abs(rawdata_val - down); + if (down > max_val) + max_val = down; + } + + /* calculate deltacpacitance with left node */ + if (i % cols) { + left = rawdata->data[i - 1]; + left = abs(rawdata_val - left); + if (left > max_val) + max_val = left; + } + + /* calculate deltacpacitance with right node */ + if ((i + 1) % cols) { + right = rawdata->data[i + 1]; + right = abs(rawdata_val - right); + if (right > max_val) + max_val = right; + } + + /* float to integer */ + if (rawdata_val) { + max_val *= FLOAT_AMPLIFIER; + max_val = (u32)div_s64(max_val, rawdata_val); + if (max_val > test_params->deviation_limits[i]) { + TPD_INFO("deviation[%d][%d]:%u > delta_limit:%u, NG\n", + (u32)div_s64(i, cols), i % cols, max_val, + test_params->deviation_limits[i]); + ret = RESULT_ERR; + } + } else { + TPD_INFO("Find rawdata=0 when calculate deltacapacitance:[%d][%d]\n", + (u32)div_s64(i, cols), i % cols); + ret = RESULT_ERR; + } + } + + return ret; +} + +/* gtx8_rawdata_test + * test rawdata with one frame + */ +static void gtx8_rawdata_test(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + /* read rawdata and calculate result, statistics fail times */ + ret = gtx8_cache_rawdata(ts_test); + if (ret < 0) { + /* Failed read rawdata */ + TPD_INFO("Read rawdata failed\n"); + ts_test->test_result[GTP_CAP_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_DELTA_TEST] = SYS_SOFTWARE_REASON; + } else { + ret = gtx8_rawcapacitance_test(&ts_test->rawdata, &ts_test->test_params); + if (!ret) { + ts_test->test_result[GTP_CAP_TEST] = GTP_TEST_PASS; + TPD_INFO("Rawdata test pass\n"); + } else { + ts_test->test_result[GTP_CAP_TEST] = GTP_PANEL_REASON; + TPD_INFO("RawCap test failed\n"); + } + + ret = gtx8_deltacapacitance_test(&ts_test->rawdata, &ts_test->test_params); + if (!ret) { + ts_test->test_result[GTP_DELTA_TEST] = GTP_TEST_PASS; + TPD_INFO("DeltaCap test pass\n"); + } else { + ts_test->test_result[GTP_DELTA_TEST] = GTP_PANEL_REASON; + TPD_INFO("DeltaCap test failed\n"); + } + } +} + +static void gtx8_capacitance_test(struct gtx8_ts_test *ts_test) +{ + int ret = 0; + u8 buf[1]; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + TPD_INFO("%s run\n", __func__); + ret = gtx8_captest_prepare(ts_test); + if (ret) { + TPD_INFO("Captest prepare failed\n"); + ts_test->test_result[GTP_CAP_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_DELTA_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_SELFCAP_TEST] = SYS_SOFTWARE_REASON; + return; + } + /* read rawdata and calculate result, statistics fail times */ + ret = touch_i2c_write_block(chip_info->client, ts_test->rawdata_cmd.cmd_reg, + ts_test->rawdata_cmd.length, ts_test->rawdata_cmd.cmds); + if (ret < 0) { + TPD_INFO("%s:Failed send rawdata cmd:ret%d\n", __func__, ret); + goto capac_test_exit; + } else { + TPD_INFO("%s: Success change to rawdata mode\n", __func__); + } + msleep(50); + + gtx8_rawdata_test(ts_test); + + /* read selfrawdata and calculate result, statistics fail times */ + ret = gtx8_cache_self_rawdata(ts_test); + if (ret < 0) { + /* Failed read selfrawdata */ + TPD_INFO("Read selfrawdata failed\n"); + ts_test->test_result[GTP_SELFCAP_TEST] = SYS_SOFTWARE_REASON; + goto capac_test_exit; + } else { + ret = gtx8_self_rawcapacitance_test(&ts_test->self_rawdata, &ts_test->test_params); + if (!ret) { + ts_test->test_result[GTP_SELFCAP_TEST] = GTP_TEST_PASS; + TPD_INFO("selfrawdata test pass\n"); + } else { + ts_test->test_result[GTP_SELFCAP_TEST] = GTP_PANEL_REASON; + TPD_INFO("selfrawCap test failed\n"); + } + } +capac_test_exit: + ret = touch_i2c_write_block(chip_info->client, ts_test->normal_cmd.cmd_reg, + ts_test->normal_cmd.length, ts_test->normal_cmd.cmds); + + buf[0] = 0x00; + ret = touch_i2c_write_block(chip_info->client, GTP_REG_COOR, 1, buf); + return; +} + +static void gtx8_intgpio_test(struct gtx8_ts_test *p_gtx8_ts_test) +{ + /*for interrupt pin test*/ + int eint_status = 0, eint_count = 0, read_gpio_num = 0; + + TPD_INFO("%s, step 0: begin to check INT-GND short item\n", __func__); + + while (read_gpio_num--) { + msleep(5); + eint_status = gpio_get_value(p_gtx8_ts_test->p_testdata->irq_gpio); + if (eint_status == 1) { + eint_count--; + } else { + eint_count++; + } + TPD_INFO("%s eint_count = %d eint_status = %d\n", __func__, eint_count, eint_status); + } + TPD_INFO("TP EINT PIN %s direct short! eint_count = %d\n", eint_count == 10 ? "is" : "not", eint_count); + if (eint_count == 10) { + TPD_INFO("error : TP EINT PIN direct short!\n"); + seq_printf(p_gtx8_ts_test->p_seq_file, "eint_status is low, TP EINT direct stort\n"); + eint_count = 0; + p_gtx8_ts_test->error_count ++; + p_gtx8_ts_test->test_result[GTP_INTPIN_TEST] = GTP_PANEL_REASON; + } + p_gtx8_ts_test->test_result[GTP_INTPIN_TEST] = GTP_TEST_PASS; +} + + +/* short test */ +static int gtx8_short_test_prepare(struct gtx8_ts_test *ts_test) +{ + int ret = 0, i = 0, retry = GTX8_RETRY_NUM_3; + u8 data[MAX_DRV_NUM + MAX_SEN_NUM] = {0}; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + u8 short_cmd[3]; + u16 short_cmd_reg = 0; + + short_cmd[0] = GTP_CMD_SHORT_TEST; + short_cmd[1] = 0x00; + short_cmd[2] = (u8)((0 - short_cmd[0] - short_cmd[1]) & 0xff); + short_cmd_reg = chip_info->reg_info.GTP_REG_CMD; + + TPD_INFO("Short test prepare+\n"); + while (--retry) { + /* switch to shrot test system */ + ret = gt9886_i2c_write(chip_info->client, short_cmd_reg, 3, short_cmd); + if (ret < 0) { + TPD_INFO("Can not switch to short test system\n"); + return ret; + } + msleep(50); + + /* check firmware running */ + for (i = 0; i < 20; i++) { + TPD_INFO("Check firmware running.."); + ret = touch_i2c_read_block(chip_info->client, SHORT_STATUS_REG, 1, &data[0]); + if (ret < 0) { + TPD_INFO("Check firmware running failed\n"); + return ret; + } else if (data[0] == 0xaa) { + TPD_INFO("Short firmware is running\n"); + break; + } + msleep(10); + } + if (i < 20) { + break; + } else { + goodix_reset_via_gpio(chip_info); + // if (goodix_set_i2c_doze_mode(core_data->ts_dev,false)) + // ts_info("WRNING: doze may enabled after reset\n"); + } + } + if (retry <= 0) { + ret = -EINVAL; + TPD_INFO("Switch to short test mode timeout\n"); + return ret; + } + + data[0] = 0; + /* turn off watch dog timer */ + ret = touch_i2c_write_block(chip_info->client, WATCH_DOG_TIMER_REG, 1, data); + if (ret < 0) { + TPD_INFO("Failed turn off watch dog timer\n"); + return ret; + } + + TPD_INFO("Firmware in short test mode\n"); + + data[0] = (ts_test->test_params.short_threshold >> 8) & 0xff; + data[1] = ts_test->test_params.short_threshold & 0xff; + + /* write tx/tx, tx/rx, rx/rx short threshold value to 0x8408 */ + ret = touch_i2c_write_block(chip_info->client, TXRX_THRESHOLD_REG, 2, data); + if (ret < 0) { + TPD_INFO("Failed write tx/tx, tx/rx, rx/rx short threshold value\n"); + return ret; + } + data[0] = (GNDAVDD_SHORT_VALUE >> 8) & 0xff; + data[1] = GNDAVDD_SHORT_VALUE & 0xff; + /* write default txrx/gndavdd short threshold value 16 to 0x804A*/ + ret = touch_i2c_write_block(chip_info->client, GNDVDD_THRESHOLD_REG, 2, data); + if (ret < 0) { + TPD_INFO("Failed write txrx/gndavdd short threshold value\n"); + return ret; + } + + /* Write ADC dump data num to 0x840c */ + data[0] = (ADC_DUMP_NUM >> 8) & 0xff; + data[1] = ADC_DUMP_NUM & 0xff; + ret = touch_i2c_write_block(chip_info->client, ADC_DUMP_NUM_REG, 2, data); + if (ret < 0) { + TPD_INFO("Failed write ADC dump data number\n"); + return ret; + } + + /* write 0x01 to 0x5095 start short test */ + data[0] = 0x01; + ret = touch_i2c_write_block(chip_info->client, SHORT_STATUS_REG, 1, data); + if (ret < 0) { + TPD_INFO("Failed write running dsp reg\n"); + return ret; + } + + TPD_INFO("Short test prepare-\n"); + return 0; +} + +static u32 map_die2pin(struct ts_test_params *test_params, u32 chn_num) +{ + int i = 0; + u32 res = 255; + + if (chn_num & DRV_CHANNEL_FLAG) + chn_num = (chn_num & ~DRV_CHANNEL_FLAG) + test_params->max_sen_num; + + for (i = 0; i < test_params->max_sen_num; i++) { + if (test_params->sen_map[i] == chn_num) { + res = i; + break; + } + } + + /* res != 255 mean found the corresponding channel num */ + if (res != 255) + return res; + + /* if cannot find in SenMap try find in DrvMap */ + for (i = 0; i < test_params->max_drv_num; i++) { + if (test_params->drv_map[i] == chn_num) { + res = i; + break; + } + } + if (i >= test_params->max_drv_num) + TPD_INFO("Faild found corrresponding channel num:%d\n", chn_num); + else + res |= DRV_CHANNEL_FLAG; + + return res; +} + +static int gtx8_check_resistance_to_gnd(struct ts_test_params *test_params, + u16 adc_signal, u32 pos) +{ + long r = 0; + u16 r_th = 0, avdd_value = 0; + u32 chn_id_tmp = 0; + u32 pin_num = 0; + + avdd_value = test_params->avdd_value; + if (adc_signal == 0 || adc_signal == 0x8000) + adc_signal |= 1; + + if ((adc_signal & 0x8000) == 0) /* short to GND */ + r = SHORT_TO_GND_RESISTER(adc_signal); + else /* short to VDD */ + r = SHORT_TO_VDD_RESISTER(adc_signal, avdd_value); + + r = (long)div_s64(r, 100); + r = r > MAX_U16_VALUE ? MAX_U16_VALUE : r; + r = r < 0 ? 0 : r; + + if (pos < MAX_DRV_NUM) + r_th = test_params->r_drv_gnd_threshold; + else + r_th = test_params->r_sen_gnd_threshold; + + chn_id_tmp = pos; + if (chn_id_tmp < test_params->max_drv_num) + chn_id_tmp |= DRV_CHANNEL_FLAG; + else + chn_id_tmp -= test_params->max_drv_num; + + if (r < r_th) { + pin_num = map_die2pin(test_params, chn_id_tmp); + TPD_INFO("%s%d shortcircut to %s,R=%ldK,R_Threshold=%dK\n", + (pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (pin_num & ~DRV_CHANNEL_FLAG), + (adc_signal & 0x8000) ? "VDD" : "GND", + r, r_th); + + return RESULT_ERR; + } + return NO_ERR; +} + +static u32 gtx8_short_resistance_calc(struct gtx8_ts_test *ts_test, + struct short_record *r_data, u16 self_capdata, u8 flag) +{ + u16 lineDrvNum = 0, lineSenNum = 0; + u8 DieNumber1 = 0, DieNumber2 = 0; + long r = 0; + + lineDrvNum = ts_test->test_params.max_drv_num; + lineSenNum = ts_test->test_params.max_sen_num; + + if (flag == 0) { + if (r_data->group1 != r_data->group2) { /* different Group */ + r = div_s64(self_capdata * 81 * FLOAT_AMPLIFIER, r_data->short_code); + r -= (81 * FLOAT_AMPLIFIER); + } else { + DieNumber1 = ((r_data->master & 0x80) == 0x80) ? (r_data->master + lineSenNum) : r_data->master; + DieNumber2 = ((r_data->slave & 0x80) == 0x80) ? (r_data->slave + lineSenNum) : r_data->slave; + DieNumber1 = (DieNumber1 >= DieNumber2) ? (DieNumber1 - DieNumber2) : (DieNumber2 - DieNumber1); + if ((DieNumber1 > 3) && (r_data->group1 == 0)) { + r = div_s64(self_capdata * 81 * FLOAT_AMPLIFIER, r_data->short_code); + r -= (81 * FLOAT_AMPLIFIER); + } else { + r = div_s64(self_capdata * 64 * FLOAT_AMPLIFIER, r_data->short_code); + r -= (64 * FLOAT_AMPLIFIER); + } + } + } else { + r = div_s64(self_capdata * 81 * FLOAT_AMPLIFIER, r_data->short_code); + r -= (81 * FLOAT_AMPLIFIER); + } + + /*if (r < 6553) + r *= 10; + else + r = 65535;*/ + r = (long)div_s64(r, FLOAT_AMPLIFIER); + r = r > MAX_U16_VALUE ? MAX_U16_VALUE : r; + + return r >= 0 ? r : 0; +} + +static int gtx8_shortcircut_analysis(struct gtx8_ts_test *ts_test) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u32 master_pin_num, slave_pin_num; + u16 adc_signal = 0, data_addr = 0; + u8 short_flag = 0, *data_buf = NULL, short_status[3] = {0}; + u16 self_capdata[MAX_DRV_NUM + MAX_SEN_NUM] = {0}, short_die_num = 0; + struct short_record temp_short_info; + struct ts_test_params *test_params = &ts_test->test_params; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + + ret = touch_i2c_read_block(chip_info->client, TEST_RESTLT_REG, 1, &short_flag); + if (ret < 0) { + TPD_INFO("Read TEST_TESULT_REG falied\n"); + goto shortcircut_analysis_error; + } else if ((short_flag & 0x0F) == 0x00) { + TPD_INFO("No shortcircut\n"); + return NO_ERR; + } + TPD_INFO("short test flag:0x%x\n", short_flag); + + data_buf = kzalloc((MAX_DRV_NUM + MAX_SEN_NUM) * 2, GFP_KERNEL); + if (!data_buf) { + TPD_INFO("Failed to alloc memory\n"); + goto shortcircut_analysis_error; + } + + /* shortcircut to gnd&vdd */ + if (short_flag & 0x08) { + /* read diff code, diff code will be used to calculate + * resistance between channel and GND */ + size = (MAX_DRV_NUM + MAX_SEN_NUM) * 2; + ret = touch_i2c_read_block(chip_info->client, DIFF_CODE_REG, size, data_buf); + if (ret < 0) { + TPD_INFO("Failed read to-gnd rawdata\n"); + goto shortcircut_analysis_error; + } + for (i = 0; i < size; i += 2) { + adc_signal = be16_to_cpup((__be16 *)&data_buf[i]); + ret = gtx8_check_resistance_to_gnd(test_params, + adc_signal, i >> 1); /* i >> 1 = i / 2 */ + if (ret) { + TPD_INFO("Resistance to-gnd test failed\n"); + err |= ret; + } + } + } + + /* read self-capdata+ */ + size = (MAX_DRV_NUM + MAX_SEN_NUM) * 2; + ret = touch_i2c_read_block(chip_info->client, DRV_SELF_CODE_REG, size, data_buf); + if (ret < 0) { + TPD_INFO("Failed read selfcap rawdata\n"); + goto shortcircut_analysis_error; + } + for (i = 0; i < MAX_DRV_NUM + MAX_SEN_NUM; i++) + self_capdata[i] = be16_to_cpup((__be16 *)&data_buf[i * 2]) & 0x7fff; + /* read self-capdata- */ + + /* read tx tx short number + ** short_status[0]: tr tx + ** short_status[1]: tr rx + ** short_status[2]: rx rx + */ + ret = touch_i2c_read_block(chip_info->client, TX_SHORT_NUM, 3, &short_status[0]); + if (ret < 0) { + TPD_INFO("Failed read tx-to-tx short rawdata\n"); + goto shortcircut_analysis_error; + } + TPD_INFO("Tx&Tx:%d,Rx&Rx:%d,Tx&Rx:%d\n", short_status[0], short_status[1], short_status[2]); + + /* drv&drv shortcircut check */ + data_addr = 0x8460; + for (i = 0; i < short_status[0]; i++) { + size = SHORT_CAL_SIZE(MAX_DRV_NUM); /* 4 + MAX_DRV_NUM * 2 + 2; */ + ret = touch_i2c_read_block(chip_info->client, data_addr, size, data_buf); + if (ret < 0) { + TPD_INFO("Failed read drv-to-drv short rawdata\n"); + goto shortcircut_analysis_error; + } + + r_threshold = test_params->r_drv_drv_threshold; + short_die_num = be16_to_cpup((__be16 *)&data_buf[0]); + if (short_die_num > MAX_DRV_NUM + MAX_SEN_NUM || + short_die_num < MAX_SEN_NUM) { + TPD_INFO("invalid short pad num:%d\n", short_die_num); + continue; + } + + /* TODO: j start position need recheck */ + short_die_num -= test_params->max_sen_num; + for (j = short_die_num + 1; j < MAX_DRV_NUM; j++) { + adc_signal = be16_to_cpup((__be16 *)&data_buf[4 + j * 2]); + + if (adc_signal > test_params->short_threshold) { + temp_short_info.master = short_die_num | DRV_CHANNEL_FLAG; + temp_short_info.slave = j | DRV_CHANNEL_FLAG; + temp_short_info.short_code = adc_signal; + gtx8_check_setting_group(ts_test, &temp_short_info); + + if (self_capdata[short_die_num] == 0xffff || + self_capdata[short_die_num] == 0) { + TPD_INFO("invalid self_capdata:0x%x\n", self_capdata[short_die_num]); + continue; + } + + short_r = gtx8_short_resistance_calc(ts_test, &temp_short_info, + self_capdata[short_die_num], 0); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(test_params, temp_short_info.master); + slave_pin_num = map_die2pin(test_params, temp_short_info.slave); + TPD_INFO("Tx/Tx short circut:R=%dK,R_Threshold=%dK\n", + short_r, r_threshold); + TPD_INFO("%s%d--%s%d shortcircut\n", + (master_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err |= -EINVAL; + } + } + } + data_addr += size; + } + + /* sen&sen shortcircut check */ + data_addr = 0x91d0; + for (i = 0; i < short_status[1]; i++) { + size = SHORT_CAL_SIZE(MAX_SEN_NUM); /* 4 + MAX_SEN_NUM * 2 + 2; */ + ret = touch_i2c_read_block(chip_info->client, data_addr, size, data_buf); + if (ret < 0) { + TPD_INFO("Failed read sen-to-sen short rawdata\n"); + goto shortcircut_analysis_error; + } + + r_threshold = ts_test->test_params.r_sen_sen_threshold; + short_die_num = be16_to_cpup((__be16 *)&data_buf[0]); + if (short_die_num > MAX_SEN_NUM) + continue; + + for (j = short_die_num + 1; j < MAX_SEN_NUM; j++) { + adc_signal = be16_to_cpup((__be16 *)&data_buf[4 + j * 2]); + if (adc_signal > ts_test->test_params.short_threshold) { + temp_short_info.master = short_die_num; + temp_short_info.slave = j; + temp_short_info.short_code = adc_signal; + gtx8_check_setting_group(ts_test, &temp_short_info); + + if (self_capdata[short_die_num + test_params->max_drv_num] == 0xffff || + self_capdata[short_die_num + test_params->max_drv_num] == 0) { + TPD_INFO("invalid self_capdata:0x%x\n", + self_capdata[short_die_num + test_params->max_drv_num]); + continue; + } + + short_r = gtx8_short_resistance_calc(ts_test, &temp_short_info, + self_capdata[short_die_num + test_params->max_drv_num], 0); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(test_params, temp_short_info.master); + slave_pin_num = map_die2pin(test_params, temp_short_info.slave); + TPD_INFO("Rx/Rx short circut:R=%dK,R_Threshold=%dK\n", + short_r, r_threshold); + TPD_INFO("%s%d--%s%d shortcircut\n", + (master_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err |= -EINVAL; + } + } + } + data_addr += size; + } + + /* sen&drv shortcircut check */ + data_addr = 0x9cc8; + for (i = 0; i < short_status[2]; i++) { + size = SHORT_CAL_SIZE(MAX_DRV_NUM); /* size = 4 + MAX_SEN_NUM * 2 + 2; */ + ret = touch_i2c_read_block(chip_info->client, data_addr, size, data_buf); + if (ret < 0) { + TPD_INFO("Failed read sen-to-drv short rawdata\n"); + goto shortcircut_analysis_error; + } + + r_threshold = ts_test->test_params.r_drv_sen_threshold; + short_die_num = be16_to_cpup((__be16 *)&data_buf[0]); + if (short_die_num > MAX_SEN_NUM) + continue; + + for (j = 0; j < MAX_DRV_NUM; j++) { + adc_signal = be16_to_cpup((__be16 *)&data_buf[4 + j * 2]); + if (adc_signal > ts_test->test_params.short_threshold) { + temp_short_info.master = short_die_num; + temp_short_info.slave = j | DRV_CHANNEL_FLAG; + temp_short_info.short_code = adc_signal; + gtx8_check_setting_group(ts_test, &temp_short_info); + + if (self_capdata[short_die_num + test_params->max_drv_num] == 0xffff || + self_capdata[short_die_num + test_params->max_drv_num] == 0) { + TPD_INFO("invalid self_capdata:0x%x\n", + self_capdata[short_die_num + test_params->max_drv_num]); + continue; + } + + short_r = gtx8_short_resistance_calc(ts_test, &temp_short_info, + self_capdata[short_die_num + test_params->max_drv_num], 0); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(test_params, temp_short_info.master); + slave_pin_num = map_die2pin(test_params, temp_short_info.slave); + TPD_INFO("Rx/Tx short circut:R=%dK,R_Threshold=%dK\n", + short_r, r_threshold); + TPD_INFO("%s%d--%s%d shortcircut\n", + (master_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err |= -EINVAL; + } + } + } + data_addr += size; + } + + if (data_buf) { + kfree(data_buf); + data_buf = NULL; + } + + TPD_INFO("%s exit:%d\n", __func__, err); + return err ? -EFAULT : NO_ERR; +shortcircut_analysis_error: + if (data_buf != NULL) { + kfree(data_buf); + data_buf = NULL; + } + TPD_INFO("%s exit with some error\n", __func__); + return -EINVAL; +} + +static void gtx8_shortcircut_test(struct gtx8_ts_test *ts_test) +{ + int i = 0; + int ret = 0; + u8 data[2] = {0}; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)ts_test->ts; + struct ts_test_params *test_params = &ts_test->test_params; + int N = test_params->drv_num; + int M = test_params->sen_num; + int wait_time = 0; + + wait_time = ((N * (N + 1)) + (M * (M + 1))) / 2 + M * N + N + M; + wait_time = (int)(86 * wait_time /100 + 100); + TPD_INFO("wait_time:%d(ms),tx:%d,rx:%d\n", wait_time, test_params->drv_num, test_params->sen_num); + + ts_test->test_result[GTP_SHORT_TEST] = GTP_TEST_PASS; + ret = gtx8_short_test_prepare(ts_test); + if (ret < 0) { + TPD_INFO("Failed enter short test mode\n"); + ts_test->test_result[GTP_SHORT_TEST] = SYS_SOFTWARE_REASON; + return; + } + msleep(wait_time); + for (i = 0; i < 150; i++) { + msleep(50); + TPD_INFO("waitting for short test end...:retry=%d\n", i); + ret = touch_i2c_read_block(chip_info->client, SHORT_TESTEND_REG, 1, data); + if (ret < 0 ) + TPD_INFO("Failed get short test result: retry%d\n", i); + else if (data[0] == 0x88) /* test ok*/ + break; + } + + if (i < 150) { + ret = gtx8_shortcircut_analysis(ts_test); + if (ret) { + ts_test->test_result[GTP_SHORT_TEST] = GTP_PANEL_REASON; + TPD_INFO("Short test failed\n"); + } else { + TPD_INFO("Short test success\n"); + } + } else { + TPD_INFO("Wait short test finish timeout:reg_val=0x%x\n", data[0]); + ts_test->test_result[GTP_SHORT_TEST] = SYS_SOFTWARE_REASON; + for (i = 0; i < 8 ; i++) { + udelay(1000); + data[0] = 0x00; + ret = touch_i2c_read_block(chip_info->client,0x2244,2,data); + if(ret < 0){ + TPD_INFO("short test,read 0x2244 failed:%d\n",ret); + continue; + } + TPD_INFO("short test,i:%d,0x2244:0x%x,0x%x\n",i,data[0],data[1]); + } + } + return; +} + + +static void gtx8_check_setting_group(struct gtx8_ts_test *ts_test, struct short_record *r_data) +{ + u32 dMaster = 0; + u32 dSlave = 0; + + if (r_data->master & 0x80) + dMaster = ts_test->test_params.max_sen_num; + + if (r_data->slave & 0x80) + dSlave = ts_test->test_params.max_sen_num; + + dMaster += (r_data->master & 0x7f); + dSlave += (r_data->slave & 0x7f); + + if ((dMaster >= 0) && (dMaster < 9)) /* pad s0~s8 */ + r_data->group1 = 5; + + else if ((dMaster >= 9) && (dMaster < 14)) /* pad s9~s13 */ + r_data->group1 = 4; + + else if ((dMaster >= 14) && (dMaster < 18)) /* pad s14~s17 */ + r_data->group1 = 3; + + else if ((dMaster >= 18) && (dMaster < 27)) /* pad s18~s26 */ + r_data->group1 = 2; + + else if ((dMaster >= 27) && (dMaster < 32)) /* pad s27~s31 */ + r_data->group1 = 1; + + else if ((dMaster >= 32) && (dMaster < 36)) /* pad s32~s35 */ + r_data->group1 = 0; + + else if ((dMaster >= 36) && (dMaster < 45)) /* pad d0~d8 */ + r_data->group1 = 5; + + else if ((dMaster >= 45) && (dMaster < 54)) /* pad d9~d17 */ + r_data->group1 = 2; + + else if ((dMaster >= 54) && (dMaster < 59)) /* pad d18~d22 */ + r_data->group1 = 1; + + else if ((dMaster >= 59) && (dMaster < 63)) /* pad d23~d26 */ + r_data->group1 = 0; + + else if ((dMaster >= 63) && (dMaster < 67)) /* pad d27~d30 */ + r_data->group1 = 3; + + else if ((dMaster >= 67) && (dMaster < 72)) /* pad d31~d35 */ + r_data->group1 = 4; + + else if ((dMaster >= 72) && (dMaster < 76)) /* pad d36~d39 */ + r_data->group1 = 0; + + + if ((dSlave > 0) && (dSlave < 9)) /* pad s0~s8 */ + r_data->group2 = 5; + + else if ((dSlave >= 9) && (dSlave < 14)) /* pad s9~s13 */ + r_data->group2 = 4; + + else if ((dSlave >= 14) && (dSlave < 18)) /* pad s14~s17 */ + r_data->group2 = 3; + + else if ((dSlave >= 18) && (dSlave < 27)) /* pad s18~s26 */ + r_data->group2 = 2; + + else if ((dSlave >= 27) && (dSlave < 32)) /* pad s27~s31 */ + r_data->group2 = 1; + + else if ((dSlave >= 32) && (dSlave < 36)) /* pad s32~s35 */ + r_data->group2 = 0; + + else if ((dSlave >= 36) && (dSlave < 45)) /* pad d0~d8 */ + r_data->group2 = 5; + + else if ((dSlave >= 45) && (dSlave < 54)) /* pad d9~d17 */ + r_data->group2 = 2; + + else if ((dSlave >= 54) && (dSlave < 59)) /* pad d18~d22 */ + r_data->group2 = 1; + + else if ((dSlave >= 59) && (dSlave < 63)) /* pad d23~d26 */ + r_data->group2 = 0; + + else if ((dSlave >= 63) && (dSlave < 67)) /* pad d27~d30 */ + r_data->group2 = 3; + + else if ((dSlave >= 67) && (dSlave < 72)) /* pad d31~d35 */ + r_data->group2 = 4; + + else if ((dSlave >= 72) && (dSlave < 76)) /* pad d36~d39 */ + r_data->group2 = 0; +} + +static void gtx8_put_test_result( + struct gtx8_ts_test *ts_test) +{ + uint8_t data_buf[64]; + struct goodix_testdata *p_testdata; + int i; + /*save test fail result*/ + struct timespec now_time; + struct rtc_time rtc_now_time; + mm_segment_t old_fs; + uint8_t file_data_buf[128]; + struct file *filp; + + p_testdata = ts_test->p_testdata; + + for (i = 1; i < MAX_TEST_ITEMS; i++) { + /* if have tested, show result */ + if (ts_test->test_result[i]) { + if (GTP_TEST_PASS == ts_test->test_result[i]) { + } else if(GTP_PANEL_REASON == ts_test->test_result[i]) { + ts_test->error_count ++; + } else if(SYS_SOFTWARE_REASON == ts_test->test_result[i]) { + ts_test->error_count ++; + } + } + TPD_INFO("test_result_info %s[%d]%d\n", test_item_name[i], i, ts_test->test_result[i]); + } + //step2: create a file to store test data in /sdcard/Tp_Test + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + //if test fail,save result to path:/sdcard/TpTestReport/screenOn/NG/ + if(ts_test->error_count) { + snprintf(file_data_buf, 128, "/sdcard/TpTestReport/screenOn/tp_testlimit_%02d%02d%02d-%02d%02d%02d-fail-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + } else { + snprintf(file_data_buf, 128, "/sdcard/TpTestReport/screenOn/tp_testlimit_%02d%02d%02d-%02d%02d%02d-pass-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + ksys_mkdir("/sdcard/TpTestReport", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn", 0666); + filp = filp_open(file_data_buf, O_RDWR | O_CREAT, 0); + if (IS_ERR(filp)) { + TPD_INFO("Open log file '%s' failed. %ld\n", file_data_buf, PTR_ERR(filp)); + set_fs(old_fs); + /*add for *#899# test for it can not acess sdcard*/ + } + p_testdata->fp = filp; + p_testdata->pos = 0; + + memset(data_buf, 0, sizeof(data_buf)); + if (ts_test->rawdata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "%s\n", "[RAW DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->rawdata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "%d,", ts_test->rawdata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + if (!((i + 1) % p_testdata->RX_NUM) && (i != 0)) { + snprintf(data_buf, 64, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + } + } + if (ts_test->noisedata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s\n", "[NOISE DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->noisedata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "%d,", ts_test->noisedata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + if (!((i + 1) % p_testdata->RX_NUM) && (i != 0)) { + snprintf(data_buf, 64, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + } + } + + if (ts_test->self_noisedata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s\n", "[SELF NOISE DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->self_noisedata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "%d,", ts_test->self_noisedata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + if (ts_test->self_rawdata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s\n", "[SELF RAW DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->self_rawdata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "%d,", ts_test->self_rawdata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "TX:%d,RX:%d\n", p_testdata->TX_NUM, p_testdata->RX_NUM); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "FW verision:%lld\n", p_testdata->TP_FW); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + + for (i = 1; i < MAX_TEST_ITEMS; i++) { + /* if have tested, show result */ + if (ts_test->test_result[i]) { + if (GTP_TEST_PASS == ts_test->test_result[i]) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s %d:%s\n", test_item_name[i], i, "pass"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } else if(GTP_PANEL_REASON == ts_test->test_result[i]) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s %d:%s\n", test_item_name[i], i, "NG:PANEL REASON"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + seq_printf(ts_test->p_seq_file, "%s", data_buf); + } + } else if(SYS_SOFTWARE_REASON == ts_test->test_result[i]) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s %d:%s\n", test_item_name[i], i, "NG:SOFTWARE_REASON"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + seq_printf(ts_test->p_seq_file, "%s", data_buf); + } + } + } + } + + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + filp_close(p_testdata->fp, NULL); + set_fs(old_fs); + } + TPD_INFO("%s exit\n", __func__); + return; +} + + +static void goodix_auto_test(struct seq_file *s, void *chip_data, struct goodix_testdata *p_testdata) +{ + int ret = 0; + struct gtx8_ts_test *gts_test = NULL; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + u16 *p_noisedata = NULL; + u16 *p_rawdata = NULL; + u16 *p_self_rawdata = NULL; + u16 *p_self_noisedata = NULL; + + TPD_INFO("%s: enter\n", __func__); + + if (!chip_data) { + TPD_INFO("%s: chip_data is NULL\n", __func__); + return; + } + if (!p_testdata) { + TPD_INFO("%s: goodix_testdata is null\n", __func__); + return; + } + + gts_test = kzalloc(sizeof(struct gtx8_ts_test), GFP_KERNEL); + if (!gts_test) { + TPD_INFO("%s: goodix_testdata is null\n", __func__); + seq_printf(s, "1 error(s).\n"); + return; + } + + p_rawdata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM * p_testdata->RX_NUM), GFP_KERNEL); + if (!p_rawdata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + p_noisedata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM * p_testdata->RX_NUM), GFP_KERNEL); + if (!p_noisedata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + + p_self_rawdata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM + p_testdata->RX_NUM), GFP_KERNEL); + if (!p_self_rawdata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + p_self_noisedata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM + p_testdata->RX_NUM), GFP_KERNEL); + if (!p_self_noisedata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + TPD_INFO("%s: alloc mem:%ld\n", __func__, sizeof(struct gtx8_ts_test) + 4 * (sizeof(u16) * (p_testdata->TX_NUM * p_testdata->RX_NUM))); + + gts_test->p_seq_file = s; + gts_test->ts = chip_info; + gts_test->p_testdata = p_testdata; + + gts_test->rawdata.data = p_rawdata; + gts_test->noisedata.data = p_noisedata; + gts_test->self_rawdata.data = p_self_rawdata; + gts_test->self_noisedata.data = p_self_noisedata; + + ret = gtx8_tptest_prepare(gts_test); + if (ret) { + TPD_INFO("%s: Failed parse test peremeters, exit test\n", __func__); + gts_test->error_count ++; + goto exit_finish; + } + TPD_INFO("%s: TP test prepare OK\n", __func__); + + goodix_set_i2c_doze_mode(chip_info->client, false); + + gtx8_print_test_params(gts_test); + gtx8_intgpio_test(gts_test); + gtx8_test_noisedata(gts_test); /*3F 7F test*/ + gtx8_capacitance_test(gts_test); /* 1F 2F 6F test*/ + gtx8_shortcircut_test(gts_test); /* 5F test */ + gtx8_put_test_result(gts_test); + gtx8_print_testdata(gts_test); + gtx8_tptest_finish(gts_test); + + goodix_set_i2c_doze_mode(chip_info->client, true); + +exit_finish: + seq_printf(s, "imageid = %lld, deviceid = %lld\n", p_testdata->TP_FW, p_testdata->TP_FW); + seq_printf(s, "%d error(s). %s\n", gts_test->error_count, gts_test->error_count ? "" : "All test passed."); + TPD_INFO(" TP auto test %d error(s). %s\n", gts_test->error_count, gts_test->error_count ? "" : "All test passed."); + TPD_INFO("%s exit:%d\n", __func__, ret); + if (p_rawdata) { + kfree(p_rawdata); + p_rawdata = NULL; + } + if (p_noisedata) { + kfree(p_noisedata); + p_noisedata = NULL; + } + if (p_self_rawdata) { + kfree(p_self_rawdata); + p_self_rawdata = NULL; + } + if (p_self_noisedata) { + kfree(p_self_noisedata); + p_self_noisedata = NULL; + } + if (gts_test) { + kfree(gts_test); + gts_test = NULL; + } + return; +} +/*************** End of atuo test func***************************/ + +static int goodix_set_health_info_state (void *chip_data, uint8_t enable) +{ + int ret = 0; + struct chip_data_gt9886 *chip_info = (struct chip_data_gt9886 *)chip_data; + + TPD_INFO("%s, enable : %d\n", __func__, enable); + if (enable) { + ret = goodix_send_cmd(chip_info, GTP_CMD_DEBUG, 0x55); + ret |= goodix_send_cmd(chip_info, GTP_CMD_DOWN_DELTA, 0x55); + TPD_INFO("%s: enable debug log %s\n", __func__, ret < 0 ? "failed" : "success"); + } else { + ret = goodix_send_cmd(chip_info, GTP_CMD_DEBUG, 0x00); + ret |= goodix_send_cmd(chip_info, GTP_CMD_DOWN_DELTA, 0x55); + TPD_INFO("%s: disable debug log %s\n", __func__, ret < 0 ? "failed" : "success"); + } + + return ret; +} + +static int goodix_get_health_info_state (void *chip_data) +{ + TPD_INFO("%s enter\n", __func__); + return 0; +} + +struct goodix_proc_operations goodix_gt9886_proc_ops = { + .goodix_config_info_read = goodix_config_info_read, + .auto_test = goodix_auto_test, + .set_health_info_state = goodix_set_health_info_state, + .get_health_info_state = goodix_get_health_info_state, +}; + +/*********** Start of I2C Driver and Implementation of it's callbacks*************************/ +static int goodix_tp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct chip_data_gt9886 *chip_info = NULL; + struct touchpanel_data *ts = NULL; + int ret = -1; + + TPD_INFO("%s is called\n", __func__); + + TPD_INFO("%s: Entered into goodix_tp_probe got called *****************\n", __func__); + if (tp_register_times > 0) { + TPD_INFO("TP driver have success loaded %d times, exit\n", tp_register_times); + return -1; + } + + /* 1. Alloc chip_info */ + chip_info = kzalloc(sizeof(struct chip_data_gt9886), GFP_KERNEL); + if (chip_info == NULL) { + TPD_INFO("chip info kzalloc error\n"); + ret = -ENOMEM; + return ret; + } + + /* 2. Alloc common ts */ + ts = common_touch_data_alloc(); + if (ts == NULL) { + TPD_INFO("ts kzalloc error\n"); + goto ts_malloc_failed; + } + + /* 3. alloc touch data space */ + chip_info->touch_data = kzalloc(MAX_GT_IRQ_DATA_LENGTH, GFP_KERNEL); + if (chip_info->touch_data == NULL) { + TPD_INFO("touch_data kzalloc error\n"); + goto err_register_driver; + } + chip_info->edge_data = kzalloc(MAX_GT_EDGE_DATA_LENGTH, GFP_KERNEL); + if (chip_info->edge_data == NULL) { + TPD_INFO("edge_data kzalloc error\n"); + goto err_touch_data_alloc; + } + + /* 4. bind client and dev for easy operate */ + chip_info->client = client; + chip_info->goodix_ops = &goodix_gt9886_proc_ops; + ts->debug_info_ops = &debug_info_proc_ops; + ts->client = client; + ts->irq = client->irq; + ts->dev = &client->dev; + ts->chip_data = chip_info; + chip_info->hw_res = &ts->hw_res; + i2c_set_clientdata(client, ts); + + /* 5. file_operations callbacks binding */ + ts->ts_ops = &goodix_ops; + + /* 6. register common touch device*/ + ret = register_common_touch_device(ts); + if (ret < 0) { + goto err_edge_data_alloc; + } + chip_info->kernel_grip_support = ts->kernel_grip_support; + + /* 8. create goodix tool node */ + gtx8_init_tool_node(ts); + + /* 9. create goodix debug files */ + Goodix_create_proc(ts, chip_info->goodix_ops); + + goodix_esd_check_enable(chip_info, true); + +// goodix_set_health_info_state(chip_info, true); + + TPD_INFO("%s, probe normal end\n", __func__); + return 0; + +err_edge_data_alloc: + if (chip_info->edge_data) { + kfree(chip_info->edge_data); + } + chip_info->edge_data = NULL; + +err_touch_data_alloc: + if (chip_info->touch_data) { + kfree(chip_info->touch_data); + } + chip_info->touch_data = NULL; + +err_register_driver: + common_touch_data_free(ts); + ts = NULL; + +ts_malloc_failed: + kfree(chip_info); + chip_info = NULL; + ret = -1; + + TPD_INFO("%s, probe error\n", __func__); + return ret; +} + +static int goodix_tp_remove(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + + TPD_INFO("%s is called\n", __func__); + kfree(ts); + + return 0; +} + +static int goodix_i2c_suspend(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s: is called\n", __func__); + tp_i2c_suspend(ts); + + return 0; +} + +static int goodix_i2c_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s is called\n", __func__); + tp_i2c_resume(ts); + + return 0; +} +static void goodix_tp_shutdown(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + int ret = 0; + + TPD_INFO("%s is called\n", __func__); + if (!ts->ts_ops->power_control) { + ret = -EINVAL; + TPD_INFO("tp power_control NULL!\n"); + return; + } + ret = ts->ts_ops->power_control(ts->chip_data, false); +} + +static const struct i2c_device_id tp_id[] = { + {TPD_DEVICE, 0}, + {}, +}; + +static struct of_device_id tp_match_table[] = { + { .compatible = TPD_DEVICE, }, + { }, +}; + +static const struct dev_pm_ops tp_pm_ops = { +#ifdef CONFIG_FB + .suspend = goodix_i2c_suspend, + .resume = goodix_i2c_resume, +#endif +}; + +static struct i2c_driver tp_i2c_driver = { + .probe = goodix_tp_probe, + .remove = goodix_tp_remove, + .shutdown = goodix_tp_shutdown, + .id_table = tp_id, + .driver = { + .name = TPD_DEVICE, + .owner = THIS_MODULE, + .of_match_table = tp_match_table, + .pm = &tp_pm_ops, + }, +}; +/******************* End of I2C Driver and It's dev_pm_ops***********************/ + +/***********************Start of module init and exit****************************/ +static int __init tp_driver_init(void) +{ + TPD_INFO("%s is called\n", __func__); + + TPD_INFO("%s: Entered into tp_driver_init *****************\n", __func__); + // if (!tp_judge_ic_match(TPD_DEVICE)) + // return -1; + + if (i2c_add_driver(&tp_i2c_driver) != 0) { + TPD_INFO("unable to add i2c driver.\n"); + return -1; + } + + return 0; +} + + +static void __exit tp_driver_exit(void) +{ + TPD_INFO("%s: Entered into tp_driver_exit *****************\n", __func__); + i2c_del_driver(&tp_i2c_driver); + + return; +} + + +late_initcall(tp_driver_init); + +module_exit(tp_driver_exit); +/***********************End of module init and exit*******************************/ + +MODULE_DESCRIPTION("GTP Touchpanel Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9886/goodix_drivers_gt9886.h b/drivers/oneplus/input/touchscreen/Goodix/GT9886/goodix_drivers_gt9886.h new file mode 100755 index 0000000000000000000000000000000000000000..82f6614ffda92c56995b374dbc854c9752804036 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9886/goodix_drivers_gt9886.h @@ -0,0 +1,698 @@ +/************************************************************** + * Copyright (c) 2008- 2030 Oppo Mobile communication Corp.ltd. + * VENDOR_EDIT + * File : goodix_drivers_gt9886.h + * Description: header file for Goodix GT9886 driver + * Version : 1.0 + * Date : 2019-08-27 + * Author : Zengpeng.Chen@Bsp.Group.Tp + * TAG : BSP.TP.Init + * ---------------- Revision History: -------------------------- + * < author > + ****************************************************************/ + +#ifndef TOUCHPANEL_GOODIX_9886_H +#define TOUCHPANEL_GOODIX_9886_H + +#include +#include +#include +#include +#include +#include +#include +#include "../goodix_common.h" +#include "../gtx8_tools.h" + +#define TPD_DEVICE "Goodix-gt9886" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do {\ + if (LEVEL_DEBUG == tp_debug) {\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do {\ + if (LEVEL_BASIC != tp_debug) {\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }\ + }while(0) + +#define TPD_DEBUG_NTAG(a, arg...)\ + do {\ + if (tp_debug) {\ + printk(a, ##arg);\ + }\ + }while(0) + +/****************************Start of define declare****************************/ + +#define set_reg_bit(reg, pos, val) ((reg) = ((reg) & (~(1 << (pos)))) | (!!(val) << (pos))) + +#define MAX_POINT_NUM 10 //max touch point number this ic support +#define MAX_GT_IRQ_DATA_LENGTH 90 //irq data(points,key,checksum) size read from irq +#define MAX_GT_EDGE_DATA_LENGTH 50 //irq edge data read from irq + +#define MAX_GESTURE_POINT_NUM 128 //max point number of black gesture + +#define GTP_DRIVER_SEND_CFG 1 // send config to TP while initializing (for no config built in TP's flash) + +//Request type define +#define GTP_RQST_RESPONDED 0x00 +#define GTP_RQST_CONFIG 0x01 +#define GTP_RQST_BASELINE 0x02 +#define GTP_RQST_RESET 0x03 +#define GTP_RQST_FRE 0x04 +#define GTP_RQST_IDLE 0xFF + +//triger event +#define GOODIX_TOUCH_EVENT 0x80 +#define GOODIX_REQUEST_EVENT 0x40 +#define GOODIX_GESTURE_EVENT 0x20 +#define GOODIX_FINGER_PRINT_EVENT 0x08 +#define GOODIX_FINGER_STATUS_EVENT 0x02 +#define GOODIX_FINGER_IDLE_EVENT 0x04 + +//config define +#define BYTES_PER_COORD 8 +#define BYTES_PER_EDGE 4 +#define TS_MAX_SENSORID 5 +#define TS_CFG_MAX_LEN 1024 +#define TS_CFG_HEAD_LEN 4 +#define TS_CFG_BAG_NUM_INDEX 2 +#define TS_CFG_BAG_START_INDEX 4 +#define GOODIX_CFG_MAX_SIZE 1024 +#define TS_WAIT_CFG_READY_RETRY_TIMES 30 +#define TS_WAIT_CMD_FREE_RETRY_TIMES 10 + + +//command define +#define GTP_CMD_NORMAL 0x00 +#define GTP_CMD_RAWDATA 0x01 +#define GTP_CMD_SLEEP 0x05 +#define GTP_CMD_CHARGER_ON 0x06 +#define GTP_CMD_CHARGER_OFF 0x07 +#define GTP_CMD_GESTURE_ON 0x08 +#define GTP_CMD_GESTURE_OFF 0x09 +#define GTP_CMD_SHORT_TEST 0x0B +#define GTM_CMD_EDGE_LIMIT_LANDSCAPE 0x0E +#define GTM_CMD_EDGE_LIMIT_VERTICAL 0x0F +#define GTP_CMD_ENTER_DOZE_TIME 0x10 +#define GTP_CMD_DEFULT_DOZE_TIME 0x11 +#define GTP_CMD_FACE_DETECT_ON 0x12 +#define GTP_CMD_FACE_DETECT_OFF 0x13 +#define GTP_CMD_FOD_FINGER_PRINT 0x19 +#define GTP_CMD_GESTURE_ENTER_IDLE 0x1A + +#define GTP_CMD_FINGER_PRINT_AREA 0x40 //change the finger print detect area +#define GTP_CMD_FILTER 0x41 //changer filter +#define GTP_CMD_DEBUG 0x42 +#define GTP_CMD_DOWN_DELTA 0x43 +#define GTP_CMD_GESTURE_DEBUG 0x44 +#define GTP_CMD_GAME_MODE 0x45 +#define GTP_CMD_GESTURE_MASK 0x46 + +//config cmd +#define COMMAND_CLEAR_UPDATE 0x50 +#define COMMAND_START_SEND_LARGE_CFG 0x80 +#define COMMAND_START_SEND_SMALL_CFG 0x81 +#define COMMAND_SEND_CFG_PREPARE_OK 0x82 +#define COMMAND_END_SEND_CFG 0x83 +#define COMMAND_READ_CFG_PREPARE_OK 0x85 +#define COMMAND_START_READ_CFG 0x86 +#define COMMAND_FLASH_READY 0x89 + +#define TS_CMD_REG_READY 0xFF + + +//gesture type fw send +#define DTAP_DETECT 0xCC +#define STAP_DETECT 0x4C +#define UP_VEE_DETECT 0x76 +#define DOWN_VEE_DETECT 0x5e +#define LEFT_VEE_DETECT 0x3e +#define RIGHT_VEE_DETECT 0x63 //this gesture is C +#define RIGHT_VEE_DETECT2 0x3c //this gesture is < +#define CIRCLE_DETECT 0x6f +#define DOUSWIP_DETECT 0x48 +#define RIGHT_SLIDE_DETECT 0xAA +#define LEFT_SLIDE_DETECT 0xbb +#define DOWN_SLIDE_DETECT 0xAB +#define UP_SLIDE_DETECT 0xBA +#define M_DETECT 0x6D +#define W_DETECT 0x77 +#define S_DETECT 0x73 +#define FP_DOWN_DETECT 0x46 +#define FP_UP_DETECT 0x55 + +//gesture define +#define GSX_KEY_DATA_LEN 37 +#define GSX_GESTURE_TYPE_LEN 32 + +//just define to pass compile +#define VERTICAL_SCREEN 0 +#define LANDSCAPE_SCREEN_90 90 +#define LANDSCAPE_SCREEN_270 270 + +//commented to make compilation successful (1-9-2020) +//#define FINGERPRINT_DOWN_DETECT 1 +//#define FINGERPRINT_UP_DETECT 0 + +//debug info define +#define SENSOR_NUM_ADDR 0x5473 +#define DRIVER_GROUP_A_NUM_ADDR 0x5477 +//#define DRIVER_GROUP_B_NUM_ADDR 0x5478 + +/****************************End of define declare***************************/ + +/****************************Start of auto test ********************/ +#define GTX8_RETRY_NUM_3 3 +#define GTX8_CONFIG_REFRESH_DATA 0x01 + +#define FLOAT_AMPLIFIER 1000 +#define MAX_U16_VALUE 65535 +#define RAWDATA_TEST_TIMES 10 + +#define MAX_TEST_ITEMS 10 /* 0P-1P-2P-3P-5P total test items */ + +#define GTP_INTPIN_TEST 0 +#define GTP_CAP_TEST 1 +#define GTP_DELTA_TEST 2 +#define GTP_NOISE_TEST 3 +#define GTP_SHORT_TEST 5 +#define GTP_SELFCAP_TEST 6 +#define GTP_SELFNOISE_TEST 7 + +static char *test_item_name[MAX_TEST_ITEMS] = { + "GTP_INTPIN_TEST", + "GTP_CAP_TEST", + "GTP_DELTA_TEST", + "GTP_NOISE_TEST", + "no test", + "GTP_SHORT_TEST", + "GTP_SELFCAP_TEST", + "GTP_SELFNOISE_TEST", + "no test", + "no test", +}; + +#define GTP_TEST_PASS 1 +#define GTP_PANEL_REASON 2 +#define SYS_SOFTWARE_REASON 3 + +/* error code */ +#define NO_ERR 0 +#define RESULT_ERR -1 +#define RAWDATA_SIZE_LIMIT -2 + +/*param key word in .csv */ +#define CSV_TP_SPECIAL_RAW_MIN "specail_raw_min" +#define CSV_TP_SPECIAL_RAW_MAX "specail_raw_max" +#define CSV_TP_SPECIAL_RAW_DELTA "special_raw_delta" +#define CSV_TP_SHORT_THRESHOLD "shortciurt_threshold" +#define CSV_TP_SPECIAL_SELFRAW_MAX "special_selfraw_max" +#define CSV_TP_SPECIAL_SELFRAW_MIN "special_selfraw_min" +#define CSV_TP_SELFNOISE_LIMIT "noise_selfdata_limit" +#define CSV_TP_TEST_CONFIG "test_config" +#define CSV_TP_NOISE_CONFIG "noise_config" +#define CSV_TP_NOISE_LIMIT "noise_data_limit" + +/*GTX8 CMD*/ +#define GTX8_CMD_NORMAL 0x00 +#define GTX8_CMD_RAWDATA 0x01 +/* Regiter for rawdata test*/ +#define GTP_RAWDATA_ADDR_9886 0x8FA0 +#define GTP_NOISEDATA_ADDR_9886 0x9D20 +#define GTP_BASEDATA_ADDR_9886 0xA980 +#define GTP_SELF_RAWDATA_ADDR_9886 0x4C0C +#define GTP_SELF_NOISEDATA_ADDR_9886 0x4CA4 + +#define GTP_REG_COOR 0x4100 +/* short test*/ +#define SHORT_TO_GND_RESISTER(sig) (div_s64(5266285, (sig) & (~0x8000)) - 40 * 100) /* (52662.85/code-40) * 100 */ +#define SHORT_TO_VDD_RESISTER(sig, value) (div_s64(36864 * ((value) - 9) * 100, (((sig) & (~0x8000)) * 7)) - 40 * 100) + +#define DRV_CHANNEL_FLAG 0x80 +#define SHORT_STATUS_REG 0x5095 +#define WATCH_DOG_TIMER_REG 0x20B0 + +#define TXRX_THRESHOLD_REG 0x8408 +#define GNDVDD_THRESHOLD_REG 0x840A +#define ADC_DUMP_NUM_REG 0x840C + +#define GNDAVDD_SHORT_VALUE 16 +#define ADC_DUMP_NUM 200 +#define SHORT_CAL_SIZE(a) (4 + (a) * 2 + 2) + +#define SHORT_TESTEND_REG 0x8400 +#define TEST_RESTLT_REG 0x8401 +#define TX_SHORT_NUM 0x8402 + +#define DIFF_CODE_REG 0xA97A +#define DRV_SELF_CODE_REG 0xA8E0 +#define TX_SHORT_NUM_REG 0x8802 + +#define MAX_DRV_NUM 40 +#define MAX_SEN_NUM 36 +/* end */ + +static u8 gt9886_drv_map[] = {46, 48, 49, 47, 45, 50, 56, 52, 51, 53, 55, 54, 59, 64, 57, 60, 62, 58, 65, 63, 61, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; +static u8 gt9886_sen_map[] = {32, 34, 35, 30, 31, 33, 27, 28, 29, 10, 25, 26, 23, 13, 24, 12, 9, 11, 8, 7, 5, 6, 4, 3, 2, 1, 0, 73, 75, 74, 39, 72, 40, 36, 37, 38}; + +/****************************End of define declare***************************/ + +/****************************Start of Firmware update info********************/ +#define FW_HEADER_SIZE 256 +#define FW_SUBSYS_INFO_SIZE 8 +#define FW_SUBSYS_INFO_OFFSET 32 +#define FW_SUBSYS_MAX_NUM 28 + +#define GOODIX_BUS_RETRY_TIMES 3 + +/*mtk max i2c size is 4k*/ +#define ISP_MAX_BUFFERSIZE (1024 * 4) + +#define I2C_DATA_MAX_BUFFERSIZE (1024 * 3) + +#define HW_REG_CPU_CTRL 0x2180 +#define HW_REG_DSP_MCU_POWER 0x2010 +#define HW_REG_RESET 0x2184 +#define HW_REG_SCRAMBLE 0x2218 +#define HW_REG_BANK_SELECT 0x2048 +#define HW_REG_ACCESS_PATCH0 0x204D +#define HW_REG_EC_SRM_START 0x204F +#define HW_REG_CPU_RUN_FROM 0x4506 /* for nor_L is 0x4006 */ +#define HW_REG_ISP_RUN_FLAG 0x6006 +#define HW_REG_ISP_ADDR 0xC000 +#define HW_REG_ISP_BUFFER 0x6100 +#define HW_REG_SUBSYS_TYPE 0x6020 +#define HW_REG_FLASH_FLAG 0x6022 +#define HW_REG_CACHE 0x204B +#define HW_REG_ESD_KEY 0x2318 +#define HW_REG_WTD_TIMER 0x20B0 + +#define CPU_CTRL_PENDING 0x00 +#define CPU_CTRL_RUNNING 0x01 + +#define ISP_STAT_IDLE 0xFF +#define ISP_STAT_READY 0xAA +#define ISP_STAT_WRITING 0xAA +#define ISP_FLASH_SUCCESS 0xBB +#define ISP_FLASH_ERROR 0xCC +#define ISP_FLASH_CHECK_ERROR 0xDD +#define ISP_CMD_PREPARE 0x55 +#define ISP_CMD_FLASH 0xAA + +#define TS_CHECK_ISP_STATE_RETRY_TIMES 200 +#define TS_READ_FLASH_STATE_RETRY_TIMES 200 + +/* cfg parse from bin */ +#define CFG_BIN_SIZE_MIN 279 +#define BIN_CFG_START_LOCAL 6 +#define MODULE_NUM 22 +#define CFG_NUM 23 +#define CFG_INFO_BLOCK_BYTES 8 +#define CFG_HEAD_BYTES 32 + +#define GTX8_EXIST 1 +#define GTX8_NOT_EXIST 0 + +/* GTX8 cfg name */ +#define GTX8_NORMAL_CONFIG "normal_config" //config_type: 0x01 +#define GTX8_TEST_CONFIG "tptest_config" //config_type: 0x00, test config +#define GTX8_NORMAL_NOISE_CONFIG "normal_noise_config" //config_type: 0x02,normal sensitivity, use for charging +#define GTX8_GLOVE_CONFIG "glove_config" //config_type: 0x03,high sensitivity +#define GTX8_GLOVE_NOISE_CONFIG "glove_noise_config" //config_type: 0x04,high sensitivity, use for charging +#define GTX8_HOLSTER_CONFIG "holster_config" //config_type: 0x05,holster +#define GTX8_HOLSTER_NOISE_CONFIG "holster_noise_config" //config_type: 0x06,holster ,use for charging +#define GTX8_NOISE_TEST_CONFIG "tpnoise_test_config" //config_type: 0x07,noise test config + +#define getU32(a) ((u32)getUint((u8 *)(a), 4)) +#define getU16(a) ((u16)getUint((u8 *)(a), 2)) +/****************************End of Firmware update info********************/ + +/****************************Start of config data****************************/ +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 10000 + +//define offset in the config +#define RESOLUTION_LOCATION 234 +#define TRIGGER_LOCATION 286 + +//Normal config setting +/*****************************End of config data*****************************/ + +/***************************Start of struct declare**************************/ +struct fw_subsystem_info { + int type; + int length; + u32 address; + int offset; +}; + +struct fw_info { + u32 length; + u16 checksum; + u8 target_mask[6]; + u8 target_mask_version[3]; + u8 pid[6]; + u8 version[3]; + u8 subsystem_count; + u8 chip_type; + u8 reserved[6]; + struct fw_subsystem_info subsystem[12]; +}; + +//stuct of firmware update + +/** + * fw_subsys_info - subsytem firmware infomation + * @type: sybsystem type + * @size: firmware size + * @flash_addr: flash address + * @data: firmware data + */ +struct fw_subsys_info { + u8 type; + u32 size; + u16 flash_addr; + const u8 *data; +}; + +/** + * firmware_info + * @size: fw total length + * @checksum: checksum of fw + * @hw_pid: mask pid string + * @hw_pid: mask vid code + * @fw_pid: fw pid string + * @fw_vid: fw vid code + * @subsys_num: number of fw subsystem + * @chip_type: chip type + * @protocol_ver: firmware packing + * protocol version + * @subsys: sybsystem info + */ +struct firmware_info { + u32 size; + u16 checksum; + u8 hw_pid[6]; + u8 hw_vid[3]; + u8 fw_pid[8]; + u8 fw_vid[4]; + u8 subsys_num; + u8 chip_type; + u8 protocol_ver; + u8 reserved[2]; + struct fw_subsys_info subsys[FW_SUBSYS_MAX_NUM]; +}; + +/** + * firmware_data - firmware data structure + * @fw_info: firmware infomation + * @firmware: firmware data structure + */ +struct firmware_data { + struct firmware_info fw_info; + const struct firmware *firmware; +}; + +enum update_status { + UPSTA_NOTWORK = 0, + UPSTA_PREPARING, + UPSTA_UPDATING, + UPSTA_ABORT, + UPSTA_SUCCESS, + UPSTA_FAILED +}; + +/** + * fw_update_ctrl - sturcture used to control the + * firmware update process + * @status: update status + * @progress: indicate the progress of update + * @fw_data: firmware data + * @ts_dev: touch device + */ +struct fw_update_ctrl { + enum update_status status; + unsigned int progress; + bool force_update; + struct firmware_data fw_data; +}; + + +struct goodix_register { + uint16_t GTP_REG_FW_CHK_MAINSYS; /*mainsys reg used to check fw status*/ + uint16_t GTP_REG_FW_CHK_SUBSYS; /*subsys reg used to check fw status*/ + uint16_t GTP_REG_CONFIG_DATA; /*configure firmware*/ + uint16_t GTP_REG_READ_COOR; /*touch state and info*/ + uint16_t GTP_REG_PRODUCT_VER; /*product id & version*/ + uint16_t GTP_REG_WAKEUP_GESTURE; /*gesture type*/ + uint16_t GTP_REG_GESTURE_COOR; /*gesture point data*/ + uint16_t GTP_REG_CMD; /*recevice cmd from host*/ + uint16_t GTP_REG_CMD1; + uint16_t GTP_REG_RQST; /*request from ic*/ + uint16_t GTP_REG_NOISE_DETECT; /*noise state*/ + uint16_t GTP_REG_ESD_WRITE; /*esd state write*/ + uint16_t GTP_REG_ESD_READ; /*esd state read*/ + uint16_t GTP_REG_DEBUG; /*debug log*/ + uint16_t GTP_REG_DOWN_DIFFDATA; /*down diff data log*/ + uint16_t GTP_REG_EDGE_INFO; /*edge points' info:ewx/ewy/xer/yer*/ + + uint16_t GTP_REG_RAWDATA; + uint16_t GTP_REG_DIFFDATA; + uint16_t GTP_REG_BASEDATA; +}; + +struct config_info { + u8 goodix_int_type; + u32 goodix_abs_x_max; + u32 goodix_abs_y_max; +}; + +struct goodix_version_info { + u8 product_id[5]; + u32 patch_id; + u32 mask_id; + u8 sensor_id; + u8 match_opt; +}; +#define MAX_STR_LEN 32 + +/* + * struct gtx8_ts_config - chip config data + * @initialized: whether intialized + * @name: name of this config + * @lock: mutex + * @reg_base: register base of config data + * @length: bytes of the config + * @delay: delay time after sending config + * @data: config data buffer + */ +struct gtx8_ts_config { + bool initialized; + char name[MAX_STR_LEN + 1]; + struct mutex lock; + unsigned int reg_base; + unsigned int length; + unsigned int delay; /*ms*/ + unsigned char data[GOODIX_CFG_MAX_SIZE]; +}; + +struct goodix_fp_coor { + u16 fp_x_coor; + u16 fp_y_coor; + u16 fp_area; +}; + +struct chip_data_gt9886 { + bool halt_status; //1: need ic reset + bool is_power_down; + u8 *touch_data; + u8 *edge_data; + tp_dev tp_type; + u16 *spuri_fp_touch_raw_data; + struct i2c_client *client; + struct goodix_version_info ver_info; + struct config_info config_info; + struct goodix_register reg_info; + struct fw_update_info update_info; + struct hw_resource *hw_res; + struct goodix_proc_operations *goodix_ops; //goodix func provide for debug + struct goodix_fp_coor fp_coor_report; + struct goodix_health_info health_info; + struct gtx8_ts_config normal_cfg; + struct gtx8_ts_config normal_noise_cfg; + struct gtx8_ts_config glove_cfg; + struct gtx8_ts_config glove_noise_cfg; + struct gtx8_ts_config holster_cfg; + struct gtx8_ts_config holster_noise_cfg; + struct gtx8_ts_config test_cfg; + struct gtx8_ts_config noise_test_cfg; + + bool esd_check_enabled; + bool fp_down_flag; + bool single_tap_flag; + uint8_t touch_direction; + char *p_tp_fw; + bool kernel_grip_support; +}; + +/** + * struct ts_test_params - test parameters + * drv_num: touch panel tx(driver) number + * sen_num: touch panel tx(sensor) number + * max_limits: max limits of rawdata + * min_limits: min limits of rawdata + * deviation_limits: channel deviation limits + * short_threshold: short resistance threshold + * r_drv_drv_threshold: resistance threshold between drv and drv + * r_drv_sen_threshold: resistance threshold between drv and sen + * r_sen_sen_threshold: resistance threshold between sen and sen + * r_drv_gnd_threshold: resistance threshold between drv and gnd + * r_sen_gnd_threshold: resistance threshold between sen and gnd + * avdd_value: avdd voltage value + */ +struct ts_test_params { + u16 rawdata_addr; + u16 noisedata_addr; + u16 self_rawdata_addr; + u16 self_noisedata_addr; + + u16 basedata_addr; + u32 max_drv_num; + u32 max_sen_num; + u32 drv_num; + u32 sen_num; + u8 *drv_map; + u8 *sen_map; + + u32 *max_limits; + u32 *min_limits; + + u32 *deviation_limits;; + u32 *self_max_limits; + u32 *self_min_limits; + + u32 noise_threshold; + u32 self_noise_threshold; + u32 short_threshold; + u32 r_drv_drv_threshold; + u32 r_drv_sen_threshold; + u32 r_sen_sen_threshold; + u32 r_drv_gnd_threshold; + u32 r_sen_gnd_threshold; + u32 avdd_value; +}; + +/** + * struct ts_test_rawdata - rawdata structure + * data: rawdata buffer + * size: rawdata size + */ +struct ts_test_rawdata { + u16 *data; + u32 size; +}; + +struct ts_test_self_rawdata { + u16 *data; + u32 size; +}; + +/* + * struct goodix_ts_cmd - command package + * @initialized: whether initialized + * @cmd_reg: command register + * @length: command length in bytes + * @cmds: command data,0:cmd,1:data,2:checksum + */ +#pragma pack(4) +struct goodix_ts_cmd { + u32 initialized; + u32 cmd_reg; + u32 length; + u8 cmds[3]; +}; +#pragma pack() + +/* + * struct goodix_ts_config - chip config data + * @initialized: whether intialized + * @name: name of this config + * @lock: mutex + * @reg_base: register base of config data + * @length: bytes of the config + * @delay: delay time after sending config + * @data: config data buffer + */ +struct goodix_ts_config { + bool initialized; + char name[24]; + struct mutex lock; + unsigned int reg_base; + unsigned int length; + unsigned int delay; /*ms*/ + unsigned char data[GOODIX_CFG_MAX_SIZE]; +}; + +/** + * struct gtx8_ts_test - main data structrue + * ts: gtx8 touch screen data + * test_config: test mode config data + * orig_config: original config data + * noise_config: noise config data + * test_param: test parameters from limit img + * rawdata: raw data structure from ic data + * noisedata: noise data structure from ic data + * self_rawdata: self raw data structure from ic data + * self_noisedata: self noise data structure from ic data + * test_result: test result string + */ +struct gtx8_ts_test { + void *ts; + struct goodix_ts_config test_config; + struct goodix_ts_config orig_config; + struct goodix_ts_config noise_config; + struct goodix_ts_cmd rawdata_cmd; + struct goodix_ts_cmd normal_cmd; + struct ts_test_params test_params; + bool is_item_support[MAX_TEST_ITEMS]; + struct ts_test_rawdata rawdata; + struct ts_test_rawdata noisedata; + struct ts_test_self_rawdata self_rawdata; + struct ts_test_self_rawdata self_noisedata; + + struct goodix_testdata *p_testdata; + struct seq_file *p_seq_file; + /*[0][0][0][0][0].. 0 without test; 1 pass, 2 panel failed; 3 software failed */ + char test_result[MAX_TEST_ITEMS]; + int error_count; +}; + +struct short_record { + u32 master; + u32 slave; + u16 short_code; + u8 group1; + u8 group2; +}; + +/****************************End of struct declare***************************/ + +extern int gt8x_rawdiff_mode; + +static inline u8 checksum_u8(u8 *data, u32 size) +{ + u8 checksum = 0; + u32 i = 0; + for(i = 0; i < size; i++) { + checksum += data[i]; + } + return checksum; +} + +#endif/*TOUCHPANEL_GOODIX_9886_H*/ diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9897/Kconfig b/drivers/oneplus/input/touchscreen/Goodix/GT9897/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..1b4bb541176a893d050243178900272402a27a20 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9897/Kconfig @@ -0,0 +1,7 @@ +config TOUCHPANEL_GOODIX_GT9897 +# default y + bool "TP goodix gt9897 IC enable" + ---help--- + say Y to enable driver for Touchpanel useing goodix gt9897 + +#endif diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9897/Makefile b/drivers/oneplus/input/touchscreen/Goodix/GT9897/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..c216f1c2dd96c2681aadbf33abd51d3bb07b51c7 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9897/Makefile @@ -0,0 +1,4 @@ +#gt9897 touchpanel driver + +#obj-$(CONFIG_TOUCHPANEL_GOODIX_GT9897) += goodix_drivers_brl.o +obj-y += goodix_drivers_brl.o diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9897/goodix_drivers_brl.c b/drivers/oneplus/input/touchscreen/Goodix/GT9897/goodix_drivers_brl.c new file mode 100755 index 0000000000000000000000000000000000000000..e36cacb821dd17b6e541cb00d51b23cdff48075d --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9897/goodix_drivers_brl.c @@ -0,0 +1,5571 @@ +/************************************************************** + * VENDOR_EDIT + * File : goodix_drivers_brl.c + * Description: Source file for Goodix GT9897 driver + * Version : 1.0 + * Date : 2019-08-27 + * Author : bsp + * TAG : BSP.TP.Init + ****************************************************************/ +#include +#include +#include "goodix_drivers_brl.h" + +extern int tp_register_times; +extern struct touchpanel_data *g_tp; + +/* + * goodix_i2c_read_wrapper + * + * */ +/*static int brl_i2c_read(struct i2c_client *client, u32 addr, unsigned int len, u8 *buffer) + { + int ret = -EINVAL; + + ret = touch_i2c_read_block_u32(client, addr, len, buffer); + + return ret; + } + + static int brl_i2c_write(struct i2c_client *client, u32 addr, unsigned int len, u8 *buffer) + { + int ret = -EINVAL; + + ret = touch_i2c_write_block_u32(client, addr, len, buffer); + + return ret; + }*/ + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +extern unsigned int upmu_get_rgs_chrdet(void); +static int goodix_get_usb_state(void) +{ + int ret = 0; + ret = upmu_get_rgs_chrdet(); + TPD_INFO("%s get usb status %d\n", __func__, ret); + return ret; +} +#else +static int goodix_get_usb_state(void) +{ + return 0; +} +#endif + +/***************************************************************************** + * goodix_append_checksum + * @summary + * Calcualte data checksum with the specified mode. + * + * @param data + * data need to be calculate + * @param len + * data length + * @param mode + * calculate for u8 or u16 checksum + * @return + * return the data checksum value. + * + *****************************************************************************/ +u32 goodix_append_checksum(u8 *data, int len, int mode) +{ + u32 checksum = 0; + int i; + + checksum = 0; + if (mode == CHECKSUM_MODE_U8_LE) { + for (i = 0; i < len; i++) + checksum += data[i]; + } else { + for (i = 0; i < len; i+=2) + checksum += (data[i] + (data[i+1] << 8)); + } + + if (mode == CHECKSUM_MODE_U8_LE) { + data[len] = checksum & 0xff; + data[len + 1] = (checksum >> 8) & 0xff; + return 0xFFFF & checksum; + } + data[len] = checksum & 0xff; + data[len + 1] = (checksum >> 8) & 0xff; + data[len + 2] = (checksum >> 16) & 0xff; + data[len + 3] = (checksum >> 24) & 0xff; + return checksum; +} + +/* checksum_cmp: check data valid or not + * @data: data need to be check + * @size: data length need to be check(include the checksum bytes) + * @mode: compare with U8 or U16 mode + * */ +int checksum_cmp(const u8 *data, int size, int mode) +{ + u32 cal_checksum = 0; + u32 r_checksum = 0; + u32 i; + + if (mode == CHECKSUM_MODE_U8_LE) { + if (size < 2) + return 1; + for (i = 0; i < size - 2; i++) + cal_checksum += data[i]; + + r_checksum = data[size - 2] + (data[size - 1] << 8); + return (cal_checksum & 0xFFFF) == r_checksum ? 0 : 1; + } + + if (size < 4) + return 1; + for (i = 0; i < size - 4; i += 2) + cal_checksum += data[i] + (data[i + 1] << 8); + r_checksum = data[size - 4] + (data[size - 3] << 8) + + (data[size - 2] << 16) + (data[size - 1] << 24); + return cal_checksum == r_checksum ? 0 : 1; +} + +/* command ack info */ +#define CMD_ACK_IDLE 0x01 +#define CMD_ACK_BUSY 0x02 +#define CMD_ACK_BUFFER_OVERFLOW 0x03 +#define CMD_ACK_CHECKSUM_ERROR 0x04 +#define CMD_ACK_OK 0x80 + +#define GOODIX_CMD_RETRY 6 +static int brl_send_cmd(struct chip_data_brl *chip_info, + struct goodix_ts_cmd *cmd) +{ + int ret, retry, i; + struct goodix_ts_cmd cmd_ack; + struct goodix_ic_info_misc *misc = &chip_info->ic_info.misc; + + if (!misc->cmd_addr) { + TPD_INFO("%s: invalied cmd addr\n", __func__); + return -EINVAL; + } + cmd->state = 0; + cmd->ack = 0; + goodix_append_checksum(&(cmd->buf[2]), cmd->len - 2, + CHECKSUM_MODE_U8_LE); + TPD_DEBUG("cmd data %*ph\n", cmd->len, &(cmd->buf[2])); + + retry = 0; + while (retry++ < GOODIX_CMD_RETRY) { + ret = touch_i2c_write_block_u32(chip_info->client, + misc->cmd_addr, sizeof(*cmd), cmd->buf); + if (ret < 0) { + TPD_INFO("%s: failed write command\n", __func__); + return ret; + } + for (i = 0; i < GOODIX_CMD_RETRY; i++) { + /* check command result */ + ret = touch_i2c_read_block_u32(chip_info->client, + misc->cmd_addr, sizeof(cmd_ack), cmd_ack.buf); + if (ret < 0) { + TPD_INFO("%s: failed read command ack, %d\n", + __func__, ret); + return ret; + } + TPD_DEBUG("cmd ack data %*ph\n", + (int)sizeof(cmd_ack), cmd_ack.buf); + if (cmd_ack.ack == CMD_ACK_OK) { + usleep_range(2000, 2100); + return 0; + } + + if (cmd_ack.ack == CMD_ACK_BUSY || + cmd_ack.ack == 0x00) { + usleep_range(1000, 1100); + continue; + } + if (cmd_ack.ack == CMD_ACK_BUFFER_OVERFLOW) + usleep_range(10000, 11000); + usleep_range(1000, 1100); + break; + } + } + TPD_INFO("%s, failed get valid cmd ack\n", __func__); + return -EINVAL; +} + +/* this is for send cmd with one byte cmd_data parameters */ +static int goodix_send_cmd_simple(struct chip_data_brl *chip_info, + u8 cmd_type, u8 cmd_data) +{ + + struct goodix_ts_cmd cmd; + /* + if (cmd_type == 0) { + TPD_INFO("%s: goodix unsupproted cmd\n", __func__); + return 0; + } + */ + cmd.len = 4; + cmd.cmd = cmd_type; + // cmd.data[0] = cmd_data; + return brl_send_cmd(chip_info, &cmd); +} +static int goodix_send_cmd_simple_onedata(struct chip_data_brl *chip_info, + u8 cmd_type, u8 cmd_data) +{ + + struct goodix_ts_cmd cmd; + + if (cmd_type == 0) { + TPD_INFO("%s: goodix unsupproted cmd\n", __func__); + return 0; + } + + cmd.len = 5; + cmd.cmd = cmd_type; + cmd.data[0] = cmd_data; + return brl_send_cmd(chip_info, &cmd); +} + + +/********* Start of function that work for touchpanel_operations callbacks***************/ +static int goodix_clear_irq(void *chip_data) +{ + int ret = -1; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + u8 clean_flag = 0; + + if (!gt8x_rawdiff_mode) { + ret = touch_i2c_write_block_u32(chip_info->client, + chip_info->ic_info.misc.touch_data_addr, 1, &clean_flag); + if (ret < 0) { + TPD_INFO("I2C write end_cmd error!\n"); + } + } + + return ret; +} + +static void getSpecialCornerPoint(uint8_t *buf, int n, struct Coordinate *point) +{ + int x, y, i; + + point[0].x = (buf[0] & 0xFF) | (buf[1] & 0x0F) << 8; + point[0].y = (buf[2] & 0xFF) | (buf[3] & 0x0F) << 8; + point[1] = point[0]; + point[2] = point[0]; + point[3] = point[0]; + for (i = 0; i < n; i++) { + x = (buf[0 + 4 * i] & 0xFF) | (buf[1 + 4 * i] & 0x0F) << 8; + y = (buf[2 + 4 * i] & 0xFF) | (buf[3 + 4 * i] & 0x0F) << 8; + if (point[3].x < x) { //xmax + point[3].x = x; + point[3].y = y; + } + if (point[1].x > x) { //xmin + point[1].x = x; + point[1].y = y; + } + if (point[2].y < y) { //ymax + point[2].y = y; + point[2].x = x; + } + if (point[0].y > y) { //ymin + point[0].y = y; + point[0].x = x; + } + } +} + +static int clockWise(uint8_t *buf, int n) +{ + int i, j, k; + int count = 0; + struct Coordinate p[3]; + long int z; + + if (n < 3) + return 1; + for (i = 0; i < n; i++) { + j = (i + 1) % n; + k = (i + 2) % n; + p[0].x = (buf[0 + 4 * i] & 0xFF) | (buf[1 + 4 * i] & 0x0F) << 8; + p[0].y = (buf[2 + 4 * i] & 0xFF) | (buf[3 + 4 * i] & 0x0F) << 8; + p[1].x = (buf[0 + 4 * j] & 0xFF) | (buf[1 + 4 * j] & 0x0F) << 8; + p[1].y = (buf[2 + 4 * j] & 0xFF) | (buf[3 + 4 * j] & 0x0F) << 8; + p[2].x = (buf[0 + 4 * k] & 0xFF) | (buf[1 + 4 * k] & 0x0F) << 8; + p[2].y = (buf[2 + 4 * k] & 0xFF) | (buf[3 + 4 * k] & 0x0F) << 8; + if ((p[0].x == p[1].x) && (p[1].x == p[1].y)) + continue; + z = (p[1].x - p[0].x) * (p[2].y - p[1].y); + z -= (p[1].y - p[0].y) * (p[2].x - p[1].x); + if (z < 0) + count--; + else if (z > 0) + count++; + } + + TPD_INFO("ClockWise count = %d\n", count); + + if (count > 0) + return 1; + else + return 0; + return 1; +} + +static void goodix_esd_check_enable(struct chip_data_brl *chip_info, bool enable) +{ + TPD_INFO("%s %s\n", __func__, enable ? "enable" : "disable"); + /* enable/disable esd check flag */ + chip_info->esd_check_enabled = enable; +} + +static int goodix_enter_sleep(struct chip_data_brl *chip_info, bool config) +{ + s32 retry = 0; + + if (config) { + while (retry++ < 3) { + if (!goodix_send_cmd_simple(chip_info, GTP_CMD_SLEEP, 0)) { + chip_info->halt_status = true; + TPD_INFO("enter sleep mode!\n"); + return 0; + } + msleep(10); + } + } + + if (retry >= 3) { + TPD_INFO("Enter sleep mode failed.\n"); + } + + return -1; +} + +static int goodix_enable_gesture(struct chip_data_brl *chip_info, bool enable) +{ + int ret = -1; + + TPD_INFO("%s, gesture enable = %d\n", __func__, enable); + + if (enable) { + if (chip_info->single_tap_flag) { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_GESTURE_ON, 1); + } else { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_GESTURE_ON, 0); + } + } else { + ret = goodix_send_cmd_simple(chip_info, GTP_CMD_GESTURE_OFF, 0); + } + + return ret; +} + +static int goodix_enable_edge_limit(struct chip_data_brl *chip_info, int state) +{ + int ret = -1; + + TPD_INFO("%s, edge limit enable = %d\n", __func__, state); + TPD_INFO("%s, direction is %d\n", __func__, g_tp->limit_switch); + + if (state == 1) { + if (g_tp->limit_switch == 1)//LANDSCRAPE_SCREEN_90 + ret = goodix_send_cmd_simple_onedata(chip_info, GTM_CMD_EDGE_LIMIT_LANDSCAPE, 0x00); + if (g_tp->limit_switch == 3)//LANDSCRAPE_SCREEN_270 + ret = goodix_send_cmd_simple_onedata(chip_info, GTM_CMD_EDGE_LIMIT_LANDSCAPE, 0x01); + } else //VERTICAL_SCREEN + ret = goodix_send_cmd_simple(chip_info, GTM_CMD_EDGE_LIMIT_VERTICAL, 0x00); + + return ret; +} + +static int goodix_enable_charge_mode(struct chip_data_brl *chip_info, bool enable) +{ + int ret = -1; + + TPD_INFO("%s, charge mode enable = %d\n", __func__, enable); + + if (enable) { + ret = goodix_send_cmd_simple(chip_info, GTP_CMD_CHARGER_ON, 0); + } else { + ret = goodix_send_cmd_simple(chip_info, GTP_CMD_CHARGER_OFF, 0); + } + + return ret; +} + +static int goodix_enable_game_mode(struct chip_data_brl *chip_info, bool enable) +{ + int ret = 0; + struct goodix_ts_cmd cmd; + TPD_INFO("%s, game mode enable = %d\n", __func__, enable); + if(enable) { + cmd.len = 6; + cmd.cmd = GTP_CMD_ENTER_GAME_MODE; + cmd.data[0] = 0x01; //enter game mode + cmd.data[1] = 0x14; //Active to idle time + ret = brl_send_cmd(chip_info, &cmd); + //ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_GAME_MODE, 0x01); + TPD_INFO("%s: GTP_CMD_ENTER_GAME_MODE\n", __func__); + } else { + cmd.len = 4; + cmd.cmd = GTP_CMD_EXIT_GAME_MODE; + ret = brl_send_cmd(chip_info, &cmd); + + // ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_GAME_MODE, 0x00); + TPD_INFO("%s: GTP_CMD_EXIT_GAME_MODE\n", __func__); + } + + return ret; +} + +#pragma pack(1) +struct goodix_config_head { + union { + struct { + u8 panel_name[8]; + u8 fw_pid[8]; + u8 fw_vid[4]; + u8 project_name[8]; + u8 file_ver[2]; + u32 cfg_id; + u8 cfg_ver; + u8 cfg_time[8]; + u8 reserved[15]; + u8 flag; + u16 cfg_len; + u8 cfg_num; + u16 checksum; + }; + u8 buf[64]; + }; +}; +#pragma pack() + +#define CONFIG_CND_LEN 4 +#define CONFIG_CMD_START 0x04 +#define CONFIG_CMD_WRITE 0x05 +#define CONFIG_CMD_EXIT 0x06 +#define CONFIG_CMD_READ_START 0x07 +#define CONFIG_CMD_READ_EXIT 0x08 + +#define CONFIG_CMD_STATUS_PASS 0x80 +#define CONFIG_CMD_WAIT_RETRY 20 + +static int wait_cmd_status(struct chip_data_brl *chip_info, u8 target_status, int retry) +{ + struct goodix_ts_cmd cmd_ack; + struct goodix_ic_info_misc *misc = &chip_info->ic_info.misc; + int i, ret; + + for (i = 0; i < retry; i++) { + ret = touch_i2c_read_block_u32(chip_info->client, + misc->cmd_addr, sizeof(cmd_ack), cmd_ack.buf); + if (!ret && cmd_ack.state == target_status) { + TPD_DEBUG("status check pass\n"); + return 0; + } + + TPD_INFO("%s: cmd status not ready, retry %d, ack 0x%x, status 0x%x, ret %d\n",__func__, + i, cmd_ack.ack, cmd_ack.state, ret); + TPD_INFO("cmd buf %*ph\n", (int)sizeof(cmd_ack), cmd_ack.buf); + msleep(15); + } + return -EINVAL; +} + +static int send_cfg_cmd(struct chip_data_brl *chip_info, + struct goodix_ts_cmd *cfg_cmd) +{ + int ret; + + ret = brl_send_cmd(chip_info, cfg_cmd); + if (ret) { + TPD_INFO("%s: failed write cfg prepare cmd %d\n",__func__, ret); + return ret; + } + ret = wait_cmd_status(chip_info, CONFIG_CMD_STATUS_PASS, + CONFIG_CMD_WAIT_RETRY); + if (ret) { + TPD_INFO("%s: failed wait for fw ready for config, %d\n", + __func__, ret); + return ret; + } + return 0; +} + +static s32 goodix_send_config(struct chip_data_brl *chip_info, u8 *cfg, int len) +{ + int ret; + u8 *tmp_buf; + struct goodix_ts_cmd cfg_cmd; + struct goodix_ic_info_misc *misc = &chip_info->ic_info.misc; + + if (len > misc->fw_buffer_max_len) { + TPD_INFO("%s: config len exceed limit %d > %d\n", __func__, + len , misc->fw_buffer_max_len); + return -EINVAL; + } + if (cfg == NULL){ + TPD_INFO ("%s,the cfg value is null\n",__func__); + return -EINVAL; + } + + tmp_buf = kzalloc(len, GFP_KERNEL); + if (!tmp_buf) { + TPD_INFO("%s: failed alloc malloc\n", __func__); + return -ENOMEM; + } + + cfg_cmd.len = CONFIG_CND_LEN; + cfg_cmd.cmd = CONFIG_CMD_START; + ret = send_cfg_cmd(chip_info, &cfg_cmd); + if (ret) { + TPD_INFO("%s: failed write cfg prepare cmd %d\n", + __func__, ret); + goto exit; + } + + TPD_DEBUG("try send config to 0x%x, len %d\n", + misc->fw_buffer_addr, len); + ret = touch_i2c_write_block_u32(chip_info->client, + misc->fw_buffer_addr, len, cfg); + if (ret) { + TPD_INFO("%s: failed write config data, %d\n", __func__, ret); + goto exit; + } + ret = touch_i2c_read_block_u32(chip_info->client, + misc->fw_buffer_addr, len, tmp_buf); + if (ret) { + TPD_INFO("%s: failed read back config data\n", __func__); + goto exit; + } + + if (memcmp(cfg, tmp_buf, len)) { + TPD_INFO("%s: config data read back compare file\n", __func__); + ret = -EINVAL; + goto exit; + } + /* notify fw for recive config */ + memset(cfg_cmd.buf, 0, sizeof(cfg_cmd)); + cfg_cmd.len = CONFIG_CND_LEN; + cfg_cmd.cmd = CONFIG_CMD_WRITE; + ret = send_cfg_cmd(chip_info, &cfg_cmd); + if (ret) + TPD_INFO("%s: failed send config data ready cmd %d\n", __func__, ret); + +exit: + memset(cfg_cmd.buf, 0, sizeof(cfg_cmd)); + cfg_cmd.len = CONFIG_CND_LEN; + cfg_cmd.cmd = CONFIG_CMD_EXIT; + if (send_cfg_cmd(chip_info, &cfg_cmd)) { + TPD_INFO("%s: failed send config write end command\n", __func__); + ret = -EINVAL; + } + + if (!ret) { + TPD_INFO("success send config!,config_len is :%d, config_version is :0x %x \n ",len,cfg[34]); + msleep(100); + } + + kfree(tmp_buf); + return ret; +} + +static int goodix_reset(void *chip_data) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + udelay(2000); + gpio_direction_output(chip_info->hw_res->reset_gpio, 1); + chip_info->halt_status = false; //reset this flag when ic reset + } else { + TPD_INFO("reset gpio is invalid\n"); + } + + msleep(300); + return 0; +} + +/*********** End of function that work for touchpanel_operations callbacks***************/ + + +/********* Start of implementation of touchpanel_operations callbacks********************/ +static int goodix_ftm_process(void *chip_data) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + TPD_INFO("%s is called!\n", __func__); + tp_powercontrol_2v8(chip_info->hw_res, false); + tp_powercontrol_1v8(chip_info->hw_res, false); + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, false); + } + + return 0; +} + +static void goodix_util_get_vendor(struct hw_resource * hw_res, + struct panel_info *panel_data) +{ + char manuf_version[MAX_DEVICE_VERSION_LENGTH] = "0202 "; + char manuf_manufacture[MAX_DEVICE_MANU_LENGTH] = "GD_"; + char gt_fw_name[16] = "GT9897.bin"; + char gt_test_limit_name[MAX_DEVICE_MANU_LENGTH] = "Brl__limit"; + + memcpy (panel_data->manufacture_info.version, + &manuf_version[0], MAX_DEVICE_VERSION_LENGTH); + memcpy (panel_data->manufacture_info.manufacture, + &manuf_manufacture[0], MAX_DEVICE_MANU_LENGTH); + memcpy (panel_data->fw_name , >_fw_name [0],16); + memcpy (panel_data->test_limit_name, + >_test_limit_name[0], MAX_DEVICE_MANU_LENGTH); +} + +static int goodix_get_vendor(void *chip_data, struct panel_info *panel_data) +{ + int len = 0; + char manu_temp[MAX_DEVICE_MANU_LENGTH] = "HD_"; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + len = strlen(panel_data->fw_name); + chip_info->tp_type = panel_data->tp_type; + chip_info->p_tp_fw = panel_data->manufacture_info.version; + strlcat(manu_temp, panel_data->manufacture_info.manufacture, MAX_DEVICE_MANU_LENGTH); + strncpy(panel_data->manufacture_info.manufacture, manu_temp, MAX_DEVICE_MANU_LENGTH); + TPD_INFO("chip_info->tp_type = %d, panel_data->fw_name = %s\n", chip_info->tp_type, panel_data->fw_name); + + return 0; +} + + +#define GOODIX_READ_VERSION_RETRY 5 +#define FW_VERSION_INFO_ADDR 0x1000C //0x10068 +#define GOODIX_NORMAL_PID "9897" +/* + * return: 0 for no error. + * -EINVAL when encounter a bus error + * -EFAULT version checksum error + */ +static int brl_read_version(struct chip_data_brl *chip_info, + struct goodix_fw_version *version) +{ + int ret, i; + u8 buf[sizeof(struct goodix_fw_version)] = {0}; + + for (i = 0; i < GOODIX_READ_VERSION_RETRY; i++) { + ret = touch_i2c_read_block_u32(chip_info->client, + FW_VERSION_INFO_ADDR, sizeof(buf), buf); + if (ret) { + TPD_INFO("read fw version: %d, retry %d\n", ret, i); + ret = -EINVAL; + msleep(5); + continue; + } + + if (!checksum_cmp(buf, sizeof(buf), CHECKSUM_MODE_U8_LE)) + break; + + TPD_INFO("invalid fw version: checksum error!\n"); + TPD_INFO("fw version:%*ph\n", (int)sizeof(buf), buf); + ret = -EFAULT; + msleep(10); + } + if (ret) { + TPD_INFO("%s: failed get valied fw version\n", __func__); + return ret; + } + memcpy(version, buf, sizeof(*version)); + TPD_INFO("rom_pid:%*ph\n", + (int)sizeof(version->rom_pid), version->rom_pid); + TPD_INFO("rom_vid:%*ph\n", + (int)sizeof(version->rom_vid), version->rom_vid); + TPD_INFO("pid:%*ph\n", + (int)sizeof(version->patch_pid), version->patch_pid); + TPD_INFO("vid:%*ph\n", + (int)sizeof(version->patch_vid), version->patch_vid); + TPD_INFO("sensor_id:%d\n", version->sensor_id); + if (memcmp(GOODIX_NORMAL_PID, version->patch_pid, + strlen(GOODIX_NORMAL_PID))) { + TPD_INFO("abnormal patch id detected\n"); + //return GOODIX_EVERSION; + } + return 0; +} + +#define LE16_TO_CPU(x) (x = le16_to_cpu(x)) +#define LE32_TO_CPU(x) (x = le32_to_cpu(x)) +static int convert_ic_info(struct goodix_ic_info *info, const u8 *data) +{ + int i; + struct goodix_ic_info_version *version = &info->version; + struct goodix_ic_info_feature *feature = &info->feature; + struct goodix_ic_info_param *parm = &info->parm; + struct goodix_ic_info_misc *misc = &info->misc; + + info->length = le16_to_cpup((__le16 *)data); + + data += 2; + memcpy(version, data, sizeof(*version)); + version->config_id = le32_to_cpu(version->config_id); + + data += sizeof(struct goodix_ic_info_version); + memcpy(feature, data, sizeof(*feature)); + feature->freqhop_feature = le16_to_cpu(feature->freqhop_feature); + feature->calibration_feature = le16_to_cpu(feature->calibration_feature); + feature->gesture_feature = le16_to_cpu(feature->gesture_feature); + feature->side_touch_feature = le16_to_cpu(feature->side_touch_feature); + feature->stylus_feature = le16_to_cpu(feature->stylus_feature); + + data += sizeof(struct goodix_ic_info_feature); + parm->drv_num = *(data++); + parm->sen_num = *(data++); + parm->button_num = *(data++); + parm->force_num = *(data++); + parm->active_scan_rate_num = *(data++); + if (parm->active_scan_rate_num > MAX_SCAN_RATE_NUM) { + TPD_INFO("%s: invalid scan rate num %d > %d\n", __func__, + parm->active_scan_rate_num, MAX_SCAN_RATE_NUM); + return -EINVAL; + } + for (i = 0; i < parm->active_scan_rate_num; i++) + parm->active_scan_rate[i] = le16_to_cpup((__le16 *)(data + i * 2)); + + data += parm->active_scan_rate_num * 2; + parm->mutual_freq_num = *(data++); + if (parm->mutual_freq_num > MAX_SCAN_FREQ_NUM) { + TPD_INFO("%s: invalid mntual freq num %d > %d\n", __func__, + parm->mutual_freq_num, MAX_SCAN_FREQ_NUM); + return -EINVAL; + } + for (i = 0; i < parm->mutual_freq_num; i++) + parm->mutual_freq[i] = le16_to_cpup((__le16 *)(data + i * 2)); + + data += parm->mutual_freq_num * 2; + parm->self_tx_freq_num = *(data++); + if (parm->self_tx_freq_num > MAX_SCAN_FREQ_NUM) { + TPD_INFO("%s: invalid tx freq num %d > %d\n", __func__, + parm->self_tx_freq_num, MAX_SCAN_FREQ_NUM); + return -EINVAL; + } + for (i = 0; i < parm->self_tx_freq_num; i++) + parm->self_tx_freq[i] = le16_to_cpup((__le16 *)(data + i * 2)); + + data += parm->self_tx_freq_num * 2; + parm->self_rx_freq_num = *(data++); + if (parm->self_rx_freq_num > MAX_SCAN_FREQ_NUM) { + TPD_INFO("%s: invalid rx freq num %d > %d\n", __func__, + parm->self_rx_freq_num, MAX_SCAN_FREQ_NUM); + return -EINVAL; + } + for (i = 0; i < parm->self_rx_freq_num; i++) + parm->self_rx_freq[i] = le16_to_cpup((__le16 *)(data + i * 2)); + + data += parm->self_rx_freq_num * 2; + parm->stylus_freq_num = *(data++); + if (parm->stylus_freq_num > MAX_FREQ_NUM_STYLUS) { + TPD_INFO("%s: invalid stylus freq num %d > %d\n", __func__, + parm->stylus_freq_num, MAX_FREQ_NUM_STYLUS); + return -EINVAL; + } + for (i = 0; i < parm->stylus_freq_num; i++) + parm->stylus_freq[i] = le16_to_cpup((__le16 *)(data + i * 2)); + + data += parm->stylus_freq_num * 2; + memcpy(misc, data, sizeof(*misc)); + misc->cmd_addr = le32_to_cpu(misc->cmd_addr); + misc->cmd_max_len = le16_to_cpu(misc->cmd_max_len); + misc->cmd_reply_addr = le32_to_cpu(misc->cmd_reply_addr); + misc->cmd_reply_len = le16_to_cpu(misc->cmd_reply_len); + misc->fw_state_addr = le32_to_cpu(misc->fw_state_addr); + misc->fw_state_len = le16_to_cpu(misc->fw_state_len); + misc->fw_buffer_addr = le32_to_cpu(misc->fw_buffer_addr); + misc->fw_buffer_max_len = le16_to_cpu(misc->fw_buffer_max_len); + misc->frame_data_addr = le32_to_cpu(misc->frame_data_addr); + misc->frame_data_head_len = le16_to_cpu(misc->frame_data_head_len); + + misc->fw_attr_len = le16_to_cpu(misc->fw_attr_len); + misc->fw_log_len = le16_to_cpu(misc->fw_log_len); + misc->stylus_struct_len = le16_to_cpu(misc->stylus_struct_len); + misc->mutual_struct_len = le16_to_cpu(misc->mutual_struct_len); + misc->self_struct_len = le16_to_cpu(misc->self_struct_len); + misc->noise_struct_len = le16_to_cpu(misc->noise_struct_len); + misc->touch_data_addr = le32_to_cpu(misc->touch_data_addr); + misc->touch_data_head_len = le16_to_cpu(misc->touch_data_head_len); + misc->point_struct_len = le16_to_cpu(misc->point_struct_len); + LE32_TO_CPU(misc->mutual_rawdata_addr); + LE32_TO_CPU(misc->mutual_diffdata_addr); + LE32_TO_CPU(misc->mutual_refdata_addr); + LE32_TO_CPU(misc->self_rawdata_addr); + LE32_TO_CPU(misc->self_diffdata_addr); + LE32_TO_CPU(misc->self_refdata_addr); + LE32_TO_CPU(misc->iq_rawdata_addr); + LE32_TO_CPU(misc->iq_refdata_addr); + LE32_TO_CPU(misc->im_rawdata_addr); + LE16_TO_CPU(misc->im_readata_len); + LE32_TO_CPU(misc->noise_rawdata_addr); + LE16_TO_CPU(misc->noise_rawdata_len); + LE32_TO_CPU(misc->stylus_rawdata_addr); + LE16_TO_CPU(misc->stylus_rawdata_len); + LE32_TO_CPU(misc->noise_data_addr); + LE32_TO_CPU(misc->esd_addr); + + return 0; +} + +static void print_ic_info(struct goodix_ic_info *ic_info) +{ + struct goodix_ic_info_version *version = &ic_info->version; + struct goodix_ic_info_feature *feature = &ic_info->feature; + struct goodix_ic_info_param *parm = &ic_info->parm; + struct goodix_ic_info_misc *misc = &ic_info->misc; + + TPD_INFO("ic_info_length: %d\n", ic_info->length); + TPD_INFO("info_customer_id: 0x%01X\n", version->info_customer_id); + TPD_INFO("info_version_id: 0x%01X\n", version->info_version_id); + TPD_INFO("ic_die_id: 0x%01X\n", version->ic_die_id); + TPD_INFO("ic_version_id: 0x%01X\n", version->ic_version_id); + TPD_INFO("config_id: 0x%4X\n", version->config_id); + TPD_INFO("config_version: 0x%01X\n", version->config_version); + TPD_INFO("frame_data_customer_id: 0x%01X\n", version->frame_data_customer_id); + TPD_INFO("frame_data_version_id: 0x%01X\n", version->frame_data_version_id); + TPD_INFO("touch_data_customer_id: 0x%01X\n", version->touch_data_customer_id); + TPD_INFO("touch_data_version_id: 0x%01X\n", version->touch_data_version_id); + + TPD_INFO("freqhop_feature: 0x%04X\n", feature->freqhop_feature); + TPD_INFO("calibration_feature: 0x%04X\n", feature->calibration_feature); + TPD_INFO("gesture_feature: 0x%04X\n", feature->gesture_feature); + TPD_INFO("side_touch_feature: 0x%04X\n", feature->side_touch_feature); + TPD_INFO("stylus_feature: 0x%04X\n", feature->stylus_feature); + + TPD_INFO("Drv*Sen,Button,Force num: %d x %d, %d, %d\n", + parm->drv_num, parm->sen_num, parm->button_num, parm->force_num); + + TPD_INFO("Cmd: 0x%04X, %d\n", + misc->cmd_addr, misc->cmd_max_len); + TPD_INFO("Cmd-Reply: 0x%04X, %d\n", + misc->cmd_reply_addr, misc->cmd_reply_len); + TPD_INFO("FW-State: 0x%04X, %d\n", + misc->fw_state_addr, misc->fw_state_len); + TPD_INFO("FW-Buffer: 0x%04X, %d\n", + misc->fw_buffer_addr, misc->fw_buffer_max_len); + TPD_INFO("Touch-Data: 0x%04X, %d\n", + misc->touch_data_addr, misc->touch_data_head_len); + TPD_INFO("point_struct_len: %d\n", misc->point_struct_len); + TPD_INFO("mutual_rawdata_addr: 0x%04X\n", + misc->mutual_rawdata_addr); + TPD_INFO("mutual_diffdata_addr: 0x%04X\n", + misc->mutual_diffdata_addr); + TPD_INFO("self_rawdata_addr: 0x%04X\n", + misc->self_rawdata_addr); + TPD_INFO("self_difdata_addr: 0x%04X\n", + misc->self_diffdata_addr); + TPD_INFO("stylus_diffdata_addr: 0x%04X, %d\n", + misc->stylus_rawdata_addr, misc->stylus_rawdata_len); + TPD_INFO("esd_addr: 0x%04X\n", misc->esd_addr); +} + +#define GOODIX_GET_IC_INFO_RETRY 3 +#define GOODIX_IC_INFO_MAX_LEN 1024 +#define GOODIX_IC_INFO_ADDR 0x10068 +static u8 GOODIX_IC_INFO_DEFAULT[200] = { 0x9C,0x00,0x03,0x00,0x20,0x00,0x39,0x71,0x5F,0x35,0x02,0x01,0x00,0x01,0x00,0x6E,0x41,0x11,0x02,0x00, + 0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x10,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x01, + 0x00,0x10,0x00,0x48,0x02,0x01,0x00,0x10,0x00,0xDC,0x02,0x01,0x00,0x5C,0x00,0xB4,0x5E,0x01,0x00,0x74, + 0x0F,0x00,0x00,0x00,0x00,0x10,0x00,0x16,0x00,0x84,0x00,0x03,0x00,0x00,0x00,0x88,0x04,0x72,0x00,0x0A, + 0x00,0x38,0x03,0x01,0x00,0x08,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x10,0x16,0x01,0x00,0xF4,0x1C,0x01, + 0x00,0x2C,0x0F,0x01,0x00,0xAC,0x0E,0x01,0x00,0x2C,0x0E,0x01,0x00,0xAC,0x0D,0x01,0x00,0x74,0x33,0x01, + 0x00,0x54,0x3B,0x01,0x00,0x3C,0x2B,0x01,0x00,0x7E,0x00,0x28,0x09,0x01,0x00,0x54,0x00,0xE8,0x7D,0x01, + 0x00,0xC6,0x02,0x78,0x08,0x01,0x00,0x68,0x01,0x01,0x00,0x00,0x00,0x00,0x9A,0x11,0xCE,0x92,0x1C,0x0C, + 0x9B,0x2F,0x48,0x08,0xBB,0xAF,0x49,0xF3,0xBF,0x0A,0x2F,0x36,0x58,0x5E,0x22,0x44,0xD2,0xFA,0x3F,0x85, + 0x44,0x9D,0xA0,0x18,0x5A,0x87,0x38,0x80,0xBF,0xA3,0x21,0x2F,0x0F,0xB1,0x61,0x74,0x86,0x9E,0x9D,0x9B}; + +static int brl_get_ic_info(struct chip_data_brl *chip_info, + struct goodix_ic_info *ic_info) +{ + int ret, i; + u16 length = 0; + u8 afe_data[GOODIX_IC_INFO_MAX_LEN] = {0}; + //u8 flag = 0; + + for (i = 0; i < GOODIX_GET_IC_INFO_RETRY; i++) { + ret = touch_i2c_read_block_u32(chip_info->client, + GOODIX_IC_INFO_ADDR, + sizeof(length), (u8 *)&length); + if (ret) { + TPD_INFO("failed get ic info length, %d\n", ret); + usleep_range(5000, 5100); + continue; + } + length = le16_to_cpu(length); + if (length >= GOODIX_IC_INFO_MAX_LEN) { + TPD_INFO("invalid ic info length %d, retry %d\n", length, i); + continue; + } + + ret = touch_i2c_read_block_u32(chip_info->client, + GOODIX_IC_INFO_ADDR, length, afe_data); + if (ret) { + TPD_INFO("failed get ic info data, %d\n", ret); + usleep_range(5000, 5100); + continue; + } + /* judge whether the data is valid */ + /*if (is_risk_data((const uint8_t *)afe_data, length)) { + TPD_INFO("fw info data invalid\n"); + usleep_range(5000, 5100); + continue; + }*/ + if (checksum_cmp((const uint8_t *)afe_data, + length, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("fw info checksum error!\n"); + usleep_range(5000, 5100); + continue; + } + break; + } + if (i == GOODIX_GET_IC_INFO_RETRY) { + TPD_INFO("%s: failed get ic info\n", __func__); + /* set ic_info length =0 to indicate this is invalid */ + ic_info->length = 0; + // return -EINVAL; + //flag = 1; + } + + //if(flag == 1) { + memset(afe_data,0,sizeof(afe_data)); + memcpy(afe_data, GOODIX_IC_INFO_DEFAULT, 190); + TPD_INFO("get ic info from default\n"); + //flag = 0; + //} + + ret = convert_ic_info(ic_info, afe_data); + if (ret) { + TPD_INFO("%s: convert ic info encounter error\n", __func__); + ic_info->length = 0; + return ret; + } + print_ic_info(ic_info); + /* check some key info */ + if (!ic_info->misc.cmd_addr || !ic_info->misc.fw_buffer_addr || + !ic_info->misc.touch_data_addr) { + TPD_INFO("%s: cmd_addr fw_buf_addr and touch_data_addr is null\n", __func__); + ic_info->length = 0; + //return -EINVAL; + goto Error_icinfo; + } + TPD_INFO("success get ic info %d\n", ic_info->length); + return 0; + +Error_icinfo: + TPD_INFO("failed get ic info \n"); + return 0; +} + +static int goodix_get_chip_info(void *chip_data) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + return brl_get_ic_info(chip_info, &chip_info->ic_info); +} + +static int goodix_power_control(void *chip_data, bool enable) +{ + int ret = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + if (true == enable) { + ret = tp_powercontrol_1v8(chip_info->hw_res, true); + if (ret) + return -1; + usleep_range(3000, 3100); + ret = tp_powercontrol_2v8(chip_info->hw_res, true); + if (ret) + return -1; + msleep(10); + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, 1); + } + msleep(100); + } else { + ret = tp_powercontrol_1v8(chip_info->hw_res, false); + if (ret) + return -1; + ret = tp_powercontrol_2v8(chip_info->hw_res, false); + if (ret) + return -1; + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + } + } + + return ret; +} + + +static int goodix_read_config(struct chip_data_brl *chip_info, u8 *cfg, int size); + +static fw_check_state goodix_fw_check(void *chip_data, + struct resolution_info *resolution_info, + struct panel_info *panel_data) +{ + int ret = 0; + u32 fw_ver_num = 0; + u8 cfg_ver = 0; + //char dev_version[MAX_DEVICE_VERSION_LENGTH] = {0}; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_fw_version *fw_ver; + // struct goodix_ts_config temp_cfg; + + // TODO need confirm fw state check method + fw_ver = &chip_info->ver_info; + ret = brl_read_version(chip_data, fw_ver); + if (ret < 0) { + TPD_INFO("%s: goodix read version failed\n", __func__); + return FW_ABNORMAL; + } + if (!isdigit(fw_ver->patch_pid[0]) || !isdigit(fw_ver->patch_pid[1]) || + !isdigit(fw_ver->patch_pid[2]) || !isdigit(fw_ver->patch_pid[3])) { + TPD_INFO("%s: goodix abnormal patch id found: %s\n", __func__, + fw_ver->patch_pid); + return FW_ABNORMAL; + } + fw_ver_num = be32_to_cpup((__be32 *)&fw_ver->patch_vid[0]); + + cfg_ver = chip_info->normal_cfg.data[34]; + + if (panel_data->manufacture_info.version) { + //panel_data->TP_FW = cfg_ver | (fw_ver_num & 0xFF) << 8; + //sprintf(dev_version, "%04x", panel_data->TP_FW); + //strlcpy(&(panel_data->manufacture_info.version[7]), dev_version, 5); + panel_data->TP_FW = cfg_ver | (fw_ver_num & 0xFF) << 8;; + sprintf(panel_data->manufacture_info.version, "0x%x", panel_data->TP_FW); + } + + TPD_INFO("%s: panel_data->TP_FW = 0x%x \n", __func__, panel_data->TP_FW); + return FW_NORMAL; +} + +/*****************start of GT9886's update function********************/ + +#define FW_HEADER_SIZE 256 +#define FW_SUBSYS_INFO_SIZE 10 +#define FW_SUBSYS_INFO_OFFSET 36 +#define FW_SUBSYS_MAX_NUM 28 + +#define ISP_MAX_BUFFERSIZE (1024 * 4) + +#define NO_NEED_UPDATE 99 + +#define FW_PID_LEN 8 +#define FW_VID_LEN 4 +#define FLASH_CMD_LEN 11 + +#define FW_FILE_CHECKSUM_OFFSET 8 +#define CONFIG_ID_OFFSET 30 +#define CONFIG_DATA_TYPE 4 + +#define ISP_RAM_ADDR 0x18400 +#define HW_REG_CPU_RUN_FROM 0x10000 +#define FLASH_CMD_REG 0x10400 +#define HW_REG_ISP_BUFFER 0x10410 +#define CONFIG_DATA_ADDR 0x3E000 + +#define HOLD_CPU_REG_W 0x0002 +#define HOLD_CPU_REG_R 0x2000 +#define MISCTL_REG 0xD807 +#define ESD_KEY_REG 0xCC58 +#define WATCH_DOG_REG 0xCC54 + + +#define FLASH_CMD_TYPE_READ 0xAA +#define FLASH_CMD_TYPE_WRITE 0xBB +#define FLASH_CMD_ACK_CHK_PASS 0xEE +#define FLASH_CMD_ACK_CHK_ERROR 0x33 +#define FLASH_CMD_ACK_IDLE 0x11 +#define FLASH_CMD_W_STATUS_CHK_PASS 0x22 +#define FLASH_CMD_W_STATUS_CHK_FAIL 0x33 +#define FLASH_CMD_W_STATUS_ADDR_ERR 0x44 +#define FLASH_CMD_W_STATUS_WRITE_ERR 0x55 +#define FLASH_CMD_W_STATUS_WRITE_OK 0xEE + + +/** + * fw_subsys_info - subsytem firmware infomation + * @type: sybsystem type + * @size: firmware size + * @flash_addr: flash address + * @data: firmware data + */ +struct fw_subsys_info { + u8 type; + u32 size; + u32 flash_addr; + const u8 *data; +}; + +/** + * firmware_summary + * @size: fw total length + * @checksum: checksum of fw + * @hw_pid: mask pid string + * @hw_pid: mask vid code + * @fw_pid: fw pid string + * @fw_vid: fw vid code + * @subsys_num: number of fw subsystem + * @chip_type: chip type + * @protocol_ver: firmware packing + * protocol version + * @bus_type: 0 represent I2C, 1 for SPI + * @subsys: sybsystem info + */ +#pragma pack(1) +struct firmware_summary { + u32 size; + u32 checksum; + u8 hw_pid[6]; + u8 hw_vid[3]; + u8 fw_pid[FW_PID_LEN]; + u8 fw_vid[FW_VID_LEN]; + u8 subsys_num; + u8 chip_type; + u8 protocol_ver; + u8 bus_type; + u8 flash_protect; + u8 reserved[2]; + struct fw_subsys_info subsys[FW_SUBSYS_MAX_NUM]; +}; +#pragma pack() + +/** + * firmware_data - firmware data structure + * @fw_summary: firmware infomation + * @firmware: firmware data structure + */ +struct firmware_data { + struct firmware_summary fw_summary; + const struct firmware *firmware; +}; + +struct config_data { + u8 *data; + int size; +}; + +#pragma pack(1) +struct goodix_flash_cmd { + union { + struct { + u8 status; + u8 ack; + u8 len; + u8 cmd; + u8 fw_type; + u16 fw_len; + u32 fw_addr; + //u16 checksum; + }; + u8 buf[16]; + }; +}; +#pragma pack() + +struct fw_update_ctrl { + int mode; + struct goodix_ts_config *ic_config; + struct chip_data_brl *chip_info; + struct firmware_data fw_data; +}; + +/** + * goodix_parse_firmware - parse firmware header infomation + * and subsystem infomation from firmware data buffer + * + * @fw_data: firmware struct, contains firmware header info + * and firmware data. + * return: 0 - OK, < 0 - error + */ +/* sizeof(length) + sizeof(checksum) */ + +static int goodix_parse_firmware(struct firmware_data *fw_data) +{ + const struct firmware *firmware; + struct firmware_summary *fw_summary; + unsigned int i, fw_offset, info_offset; + u32 checksum; + int r = 0; + + fw_summary = &fw_data->fw_summary; + + /* copy firmware head info */ + firmware = fw_data->firmware; + if (firmware->size < FW_SUBSYS_INFO_OFFSET) { + TPD_INFO("%s: Invalid firmware size:%zu\n", + __func__, firmware->size); + r = -EINVAL; + goto err_size; + } + memcpy(fw_summary, firmware->data, sizeof(*fw_summary)); + + /* check firmware size */ + fw_summary->size = le32_to_cpu(fw_summary->size); + if (firmware->size != fw_summary->size + FW_FILE_CHECKSUM_OFFSET) { + TPD_INFO("%s: Bad firmware, size not match, %zu != %d\n", + __func__, firmware->size, fw_summary->size + 6); + r = -EINVAL; + goto err_size; + } + + for (i = FW_FILE_CHECKSUM_OFFSET, checksum = 0; + i < firmware->size; i+=2) + checksum += firmware->data[i] + (firmware->data[i+1] << 8); + + /* byte order change, and check */ + fw_summary->checksum = le32_to_cpu(fw_summary->checksum); + if (checksum != fw_summary->checksum) { + TPD_INFO("%s: Bad firmware, cheksum error\n", __func__); + r = -EINVAL; + goto err_size; + } + + if (fw_summary->subsys_num > FW_SUBSYS_MAX_NUM) { + TPD_INFO("%s: Bad firmware, invalid subsys num: %d\n", + __func__, fw_summary->subsys_num); + r = -EINVAL; + goto err_size; + } + + /* parse subsystem info */ + fw_offset = FW_HEADER_SIZE; + for (i = 0; i < fw_summary->subsys_num; i++) { + info_offset = FW_SUBSYS_INFO_OFFSET + + i * FW_SUBSYS_INFO_SIZE; + + fw_summary->subsys[i].type = firmware->data[info_offset]; + fw_summary->subsys[i].size = + le32_to_cpup((__le32 *)&firmware->data[info_offset + 1]); + + fw_summary->subsys[i].flash_addr = + le32_to_cpup((__le32 *)&firmware->data[info_offset + 5]); + if (fw_offset > firmware->size) { + TPD_INFO("%s: Sybsys offset exceed Firmware size\n", + __func__); + goto err_size; + } + + fw_summary->subsys[i].data = firmware->data + fw_offset; + fw_offset += fw_summary->subsys[i].size; + } + + TPD_INFO("Firmware package protocol: V%u\n", fw_summary->protocol_ver); + TPD_INFO("Fimware PID:GT%s\n", fw_summary->fw_pid); + TPD_INFO("Fimware VID:%*ph\n", 4, fw_summary->fw_vid); + TPD_INFO("Firmware chip type:%02X\n", fw_summary->chip_type); + TPD_INFO("Firmware bus type:%d\n", fw_summary->bus_type); + TPD_INFO("Firmware size:%u\n", fw_summary->size); + TPD_INFO("Firmware subsystem num:%u\n", fw_summary->subsys_num); + + for (i = 0; i < fw_summary->subsys_num; i++) { + TPD_DEBUG("------------------------------------------\n"); + TPD_DEBUG("Index:%d\n", i); + TPD_DEBUG("Subsystem type:%02X\n", fw_summary->subsys[i].type); + TPD_DEBUG("Subsystem size:%u\n", fw_summary->subsys[i].size); + TPD_DEBUG("Subsystem flash_addr:%08X\n", + fw_summary->subsys[i].flash_addr); + TPD_DEBUG("Subsystem Ptr:%p\n", fw_summary->subsys[i].data); + } + +err_size: + return r; +} + +static int goodix_reg_write(struct chip_data_brl *chip_info, unsigned int addr, + unsigned char *data, unsigned int len) +{ + + return touch_i2c_write_block_u32(chip_info->client, addr, len, data); +} + +static int goodix_reg_read(struct chip_data_brl *chip_info, unsigned int addr, + unsigned char *data, unsigned int len) +{ + return touch_i2c_read_block_u32(chip_info->client, addr, len, data); +} + +/** + * goodix_reg_write_confirm - write register and confirm the value + * in the register. + * @client: pointer to touch device client + * @addr: register address + * @data: pointer to data buffer + * @len: data length + * return: 0 write success and confirm ok + * < 0 failed + */ +static int goodix_reg_write_confirm(struct i2c_client *client, + unsigned int addr, unsigned char *data, + unsigned int len) +{ + u8 *cfm, cfm_buf[32]; + int r, i; + + if (len > sizeof(cfm_buf)) { + cfm = kzalloc(len, GFP_KERNEL); + if (!cfm) { + TPD_INFO("Mem alloc failed\n"); + return -ENOMEM; + } + } else { + cfm = &cfm_buf[0]; + } + + for (i = 0; i < GOODIX_BUS_RETRY_TIMES; i++) { + r = touch_i2c_write_block_u32(client, addr, len, data); + if (r < 0) + goto exit; + r = touch_i2c_read_block_u32(client, addr, len, cfm); + if (r < 0) + goto exit; + + if (memcmp(data, cfm, len)) { + r = -EMEMCMP; + continue; + } else { + r = 0; + break; + } + } + +exit: + if (cfm != &cfm_buf[0]) + kfree(cfm); + return r; +} + +static int goodix_fw_update_reset(struct fw_update_ctrl *fwu_ctrl, int delay_ms) +{ + struct chip_data_brl *chip_info = fwu_ctrl->chip_info; + + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + udelay(2000); + gpio_direction_output(chip_info->hw_res->reset_gpio, 1); + if (delay_ms < 20) + usleep_range(delay_ms * 1000, delay_ms * 1000 + 100); + else + msleep(delay_ms); + } + return 0; +} + +/** + * goodix_fw_version_compare - compare the active version with + * firmware file version. + * @fwu_ctrl: firmware infomation to be compared + * return: 0 equal, < 0 unequal + */ +static int goodix_fw_version_compare(struct fw_update_ctrl *fwu_ctrl) +{ + int ret = 0; + struct goodix_fw_version fw_version = {{0}}; + struct firmware_summary *fw_summary = &fwu_ctrl->fw_data.fw_summary; + + ret = brl_read_version(fwu_ctrl->chip_info, &fw_version); + if (ret) { + TPD_INFO("failed get active fw version\n"); + return -EINVAL; + } + + if (memcmp(fw_version.patch_pid, fw_summary->fw_pid, FW_PID_LEN)) { + TPD_INFO("%s: Product ID mismatch:%s:%s\n", __func__, + fw_version.patch_pid, fw_summary->fw_pid); + return -EINVAL; + } + + ret = memcmp(fw_version.patch_vid, fw_summary->fw_vid, FW_VID_LEN); + if (ret) { + TPD_INFO("active firmware version:%*ph\n", FW_VID_LEN, + fw_version.patch_vid); + TPD_INFO("firmware file version: %*ph\n", FW_VID_LEN, + fw_summary->fw_vid); + return -EINVAL; + } + + TPD_INFO("Firmware version equal\n"); + return 0; + //return -EINVAL; +} + +/** + * goodix_load_isp - load ISP program to deivce ram + * @dev: pointer to touch device + * @fw_data: firmware data + * return 0 ok, <0 error + */ +static int goodix_load_isp(struct fw_update_ctrl *fwu_ctrl) +{ + struct firmware_data *fw_data = &fwu_ctrl->fw_data; + struct goodix_fw_version isp_fw_version = {{0}}; + struct fw_subsys_info *fw_isp; + u8 reg_val[8] = {0x00}; + int r; + + fw_isp = &fw_data->fw_summary.subsys[0]; + + TPD_INFO("Loading ISP start\n"); + r = goodix_reg_write_confirm(fwu_ctrl->chip_info->client, ISP_RAM_ADDR, + (u8 *)fw_isp->data, fw_isp->size); + if (r < 0) { + TPD_INFO("%s: Loading ISP error\n", __func__); + return r; + } + + TPD_INFO("Success send ISP data\n"); + + /* SET BOOT OPTION TO 0X55 */ + memset(reg_val, 0x55, 8); + r = goodix_reg_write_confirm(fwu_ctrl->chip_info->client, + HW_REG_CPU_RUN_FROM, reg_val, 8); + if (r < 0) { + TPD_INFO("%s: Failed set REG_CPU_RUN_FROM flag\n", __func__); + return r; + } + TPD_INFO("Success write [8]0x55 to 0x%x\n", HW_REG_CPU_RUN_FROM); + + if (goodix_fw_update_reset(fwu_ctrl, 100)) + TPD_INFO("%s: reset abnormal\n", __func__); + /*check isp state */ + if (brl_read_version(fwu_ctrl->chip_info, &isp_fw_version)) { + TPD_INFO("%s: failed read isp version\n", __func__); + return -2; + } + if (memcmp(&isp_fw_version.patch_pid[3], "ISP", 3)) { + TPD_INFO("%s: patch id error %c%c%c != %s\n", __func__, + isp_fw_version.patch_pid[3], isp_fw_version.patch_pid[4], + isp_fw_version.patch_pid[5], "ISP"); + return -3; + } + TPD_INFO("ISP running successfully\n"); + return 0; +} + +/** + * goodix_update_prepare - update prepare, loading ISP program + * and make sure the ISP is running. + * @fwu_ctrl: pointer to fimrware control structure + * return: 0 ok, <0 error + */ +static int goodix_update_prepare(struct fw_update_ctrl *fwu_ctrl) +{ + u8 reg_val[4] = {0}; + u8 temp_buf[64] = {0}; + int retry = 20; + int r; + + /*reset IC*/ + TPD_INFO("firmware update, reset\n"); + if (goodix_fw_update_reset(fwu_ctrl, 5)) + TPD_INFO("%s: reset abnormal\n", __func__); + + retry = 100; + /* Hold cpu*/ + do { + reg_val[0] = 0x01; + reg_val[1] = 0x00; + r = goodix_reg_write(fwu_ctrl->chip_info, + HOLD_CPU_REG_W, reg_val, 2); + r |= goodix_reg_read(fwu_ctrl->chip_info, + HOLD_CPU_REG_R, &temp_buf[0], 4); + r |= goodix_reg_read(fwu_ctrl->chip_info, + HOLD_CPU_REG_R, &temp_buf[4], 4); + r |= goodix_reg_read(fwu_ctrl->chip_info, + HOLD_CPU_REG_R, &temp_buf[8], 4); + if (!r && !memcmp(&temp_buf[0], &temp_buf[4], 4) && + !memcmp(&temp_buf[4], &temp_buf[8], 4) && + !memcmp(&temp_buf[0], &temp_buf[8], 4)) { + break; + } + usleep_range(1000, 1100); + TPD_INFO("retry hold cpu %d\n", retry); + TPD_DEBUG("data:%*ph\n", 12, temp_buf); + } while (--retry); + if (!retry) { + TPD_INFO("%s: Failed to hold CPU, return =%d\n", __func__, r); + return -1; + } + TPD_INFO("Success hold CPU\n"); + + /* enable misctl clock */ + reg_val[0] = 0x08; + r = goodix_reg_write(fwu_ctrl->chip_info, MISCTL_REG, reg_val, 1); + TPD_INFO("enbale misctl clock\n"); + + /* open ESD_KEY */ + retry = 20; + do { + reg_val[0] = 0x95; + r = goodix_reg_write(fwu_ctrl->chip_info, + ESD_KEY_REG, reg_val, 1); + r |= goodix_reg_read(fwu_ctrl->chip_info, + ESD_KEY_REG, temp_buf, 1); + if (!r && temp_buf[0] == 0x01) + break; + usleep_range(1000, 1100); + TPD_INFO("retry %d enable esd key, 0x%x\n", retry, temp_buf[0]); + } while (--retry); + if (!retry) { + TPD_INFO("%s: Failed to enable esd key, return =%d\n", __func__, r); + return -2; + } + TPD_INFO("success enable esd key\n"); + + /* disable watch dog */ + reg_val[0] = 0x00; + r = goodix_reg_write(fwu_ctrl->chip_info, WATCH_DOG_REG, reg_val, 1); + TPD_INFO("disable watch dog\n"); + + /* load ISP code and run form isp */ + r = goodix_load_isp(fwu_ctrl); + if (r < 0) + TPD_INFO("%s: Failed lode and run isp\n", __func__); + + return r; +} + +/* goodix_send_flash_cmd: send command to read or write flash data + * @flash_cmd: command need to send. + * */ +static int goodix_send_flash_cmd(struct fw_update_ctrl *fwu_ctrl, + struct goodix_flash_cmd *flash_cmd) +{ + int i, ret, retry; + struct goodix_flash_cmd tmp_cmd; + + TPD_INFO("try send flash cmd:%*ph\n", (int)sizeof(flash_cmd->buf), + flash_cmd->buf); + memset(tmp_cmd.buf, 0, sizeof(tmp_cmd)); + ret = goodix_reg_write(fwu_ctrl->chip_info, FLASH_CMD_REG, + flash_cmd->buf, sizeof(flash_cmd->buf)); + if (ret) { + TPD_INFO("%s: failed send flash cmd %d\n", __func__, ret); + return ret; + } + + retry = 5; + for (i = 0; i < retry; i++) { + ret = goodix_reg_read(fwu_ctrl->chip_info, FLASH_CMD_REG, + tmp_cmd.buf, sizeof(tmp_cmd.buf)); + if (!ret && tmp_cmd.ack == FLASH_CMD_ACK_CHK_PASS) + break; + usleep_range(5000, 5100); + TPD_INFO("flash cmd ack error retry %d, ack 0x%x, ret %d\n", + i, tmp_cmd.ack, ret); + } + if (tmp_cmd.ack != FLASH_CMD_ACK_CHK_PASS) { + TPD_INFO("%s: flash cmd ack error, ack 0x%x, ret %d\n", + __func__, tmp_cmd.ack, ret); + TPD_INFO("%s: data:%*ph\n", __func__, + (int)sizeof(tmp_cmd.buf), tmp_cmd.buf); + return -EINVAL; + } + TPD_INFO("flash cmd ack check pass\n"); + + msleep(80); + retry = 20; + for (i = 0; i < retry; i++) { + ret = goodix_reg_read(fwu_ctrl->chip_info, FLASH_CMD_REG, + tmp_cmd.buf, sizeof(tmp_cmd.buf)); + if (!ret && tmp_cmd.ack == FLASH_CMD_ACK_CHK_PASS && + tmp_cmd.status == FLASH_CMD_W_STATUS_WRITE_OK) { + TPD_INFO("flash status check pass\n"); + return 0; + } + + TPD_INFO("flash cmd status not ready, retry %d, ack 0x%x, status 0x%x, ret %d\n", + i, tmp_cmd.ack, tmp_cmd.status, ret); + msleep(15); + } + + TPD_INFO("%s: flash cmd status error %d, ack 0x%x, status 0x%x, ret %d\n", __func__, + i, tmp_cmd.ack, tmp_cmd.status, ret); + if (ret) { + TPD_INFO("reason: bus or paltform error\n"); + return -EINVAL; + } + + switch (tmp_cmd.status) { + case FLASH_CMD_W_STATUS_CHK_PASS: + TPD_INFO("%s: data check pass, but failed get follow-up results\n", __func__); + return -EFAULT; + case FLASH_CMD_W_STATUS_CHK_FAIL: + TPD_INFO("%s: data check failed, please retry\n", __func__); + return -EAGAIN; + case FLASH_CMD_W_STATUS_ADDR_ERR: + TPD_INFO("%s: flash target addr error, please check\n", __func__); + return -EFAULT; + case FLASH_CMD_W_STATUS_WRITE_ERR: + TPD_INFO("%s: flash data write err, please retry\n", __func__); + return -EAGAIN; + default: + TPD_INFO("%s: unknown status\n", __func__); + return -EFAULT; + } +} + +static int goodix_flash_package(struct fw_update_ctrl *fwu_ctrl, + u8 subsys_type, u8 *pkg, u32 flash_addr, u16 pkg_len) +{ + int ret, retry; + struct goodix_flash_cmd flash_cmd; + + retry = 2; + do { + ret = goodix_reg_write_confirm(fwu_ctrl->chip_info->client, + HW_REG_ISP_BUFFER, pkg, pkg_len); + if (ret < 0) { + TPD_INFO("%s: Failed to write firmware packet\n", __func__); + return ret; + } + + flash_cmd.status = 0; + flash_cmd.ack = 0; + flash_cmd.len = FLASH_CMD_LEN; + flash_cmd.cmd = FLASH_CMD_TYPE_WRITE; + flash_cmd.fw_type = subsys_type; + flash_cmd.fw_len = cpu_to_le16(pkg_len); + flash_cmd.fw_addr = cpu_to_le32(flash_addr); + + goodix_append_checksum(&(flash_cmd.buf[2]), + 9, CHECKSUM_MODE_U8_LE); + + ret = goodix_send_flash_cmd(fwu_ctrl, &flash_cmd); + if (!ret) { + TPD_INFO("success write package to 0x%x, len %d\n", + flash_addr, pkg_len - 4); + return 0; + } + } while (ret == -EAGAIN && --retry); + + return ret; +} + +/** + * goodix_flash_subsystem - flash subsystem firmware, + * Main flow of flashing firmware. + * Each firmware subsystem is divided into several + * packets, the max size of packet is limited to + * @{ISP_MAX_BUFFERSIZE} + * @dev: pointer to touch device + * @subsys: subsystem infomation + * return: 0 ok, < 0 error + */ +static int goodix_flash_subsystem(struct fw_update_ctrl *fwu_ctrl, + struct fw_subsys_info *subsys) +{ + u16 data_size, offset; + u32 total_size; + //TODO: confirm flash addr ,<< 8?? + u32 subsys_base_addr = subsys->flash_addr; + u8 *fw_packet = NULL; + int r = 0; + + /* + * if bus(i2c/spi) error occued, then exit, we will do + * hardware reset and re-prepare ISP and then retry + * flashing + */ + total_size = subsys->size; + fw_packet = kzalloc(ISP_MAX_BUFFERSIZE + 4, GFP_KERNEL); + if (!fw_packet) { + TPD_INFO("%s: Failed alloc memory\n", __func__); + return -EINVAL; + } + + offset = 0; + while (total_size > 0) { + data_size = total_size > ISP_MAX_BUFFERSIZE ? + ISP_MAX_BUFFERSIZE : total_size; + TPD_INFO("Flash firmware to %08x,size:%u bytes\n", + subsys_base_addr + offset, data_size); + + memcpy(fw_packet, &subsys->data[offset], data_size); + /* set checksum for package data */ + goodix_append_checksum(fw_packet, + data_size, CHECKSUM_MODE_U16_LE); + + r = goodix_flash_package(fwu_ctrl, subsys->type, fw_packet, + subsys_base_addr + offset, data_size + 4); + if (r) { + TPD_INFO("%s: failed flash to %08x,size:%u bytes\n", + __func__, subsys_base_addr + offset, data_size); + break; + } + offset += data_size; + total_size -= data_size; + } /* end while */ + + kfree(fw_packet); + return r; +} + +/** + * goodix_flash_firmware - flash firmware + * @dev: pointer to touch device + * @fw_data: firmware data + * return: 0 ok, < 0 error + */ +static int goodix_flash_firmware(struct fw_update_ctrl *fw_ctrl) +{ + struct firmware_data *fw_data = &fw_ctrl->fw_data; + struct firmware_summary *fw_summary; + struct fw_subsys_info *fw_x; + struct fw_subsys_info subsys_cfg = {0}; + int retry = GOODIX_BUS_RETRY_TIMES; + int i, r = 0, fw_num; + + /* start from subsystem 1, + * subsystem 0 is the ISP program */ + + fw_summary = &fw_data->fw_summary; + fw_num = fw_summary->subsys_num; + + /* flash config data first if we have */ + if (fw_ctrl->ic_config && fw_ctrl->ic_config->length) { + subsys_cfg.data = fw_ctrl->ic_config->data; + subsys_cfg.size = fw_ctrl->ic_config->length; + subsys_cfg.flash_addr = CONFIG_DATA_ADDR; + subsys_cfg.type = CONFIG_DATA_TYPE; + r = goodix_flash_subsystem(fw_ctrl, &subsys_cfg); + if (r) { + TPD_INFO("%s: failed flash config with ISP, %d\n", + __func__, r); + return r; + } + TPD_INFO("success flash config with ISP\n"); + } + + for (i = 1; i < fw_num && retry;) { + TPD_INFO("--- Start to flash subsystem[%d] ---\n", i); + fw_x = &fw_summary->subsys[i]; + r = goodix_flash_subsystem(fw_ctrl, fw_x); + if (r == 0) { + TPD_INFO("--- End flash subsystem[%d]: OK ---\n", i); + i++; + } else if (r == -EAGAIN) { + retry--; + TPD_INFO("%s: --- End flash subsystem%d: Fail, errno:%d, retry:%d ---\n", __func__, + i, r, GOODIX_BUS_RETRY_TIMES - retry); + } else if (r < 0) { /* bus error */ + TPD_INFO("%s: --- End flash subsystem%d: Fatal error:%d exit ---\n", __func__, + i, r); + goto exit_flash; + } + } + +exit_flash: + return r; +} + +/** + * goodix_update_finish - update finished, FREE resource + * and reset flags--- + * @fwu_ctrl: pointer to fw_update_ctrl structrue + * return: 0 ok, < 0 error + */ +static int goodix_update_finish(struct fw_update_ctrl *fwu_ctrl) +{ + if (goodix_fw_update_reset(fwu_ctrl, 100)) + TPD_INFO("%s: reset abnormal\n", __func__); + if (goodix_fw_version_compare(fwu_ctrl)) + return -EINVAL; + + return 0; +} + +static u32 getUint(u8 *buffer, int len) +{ + u32 num = 0; + int i = 0; + for (i = 0; i < len; i++) { + num <<= 8; + num += buffer[i]; + } + return num; +} + +static int goodix_parse_cfg_data(const struct firmware *cfg_bin, + char *cfg_type, u8 *cfg, int *cfg_len, u8 sid) +{ + int i = 0, config_status = 0, one_cfg_count = 0; + int cfgPackageLen = 0; + + u8 bin_group_num = 0, bin_cfg_num = 0; + u16 cfg_checksum = 0, checksum = 0; + u8 sid_is_exist = GOODIX_NOT_EXIST; + u16 cfg_offset = 0; + + TPD_DEBUG("%s run,sensor id:%d\n", __func__, sid); + + cfgPackageLen = getU32(cfg_bin->data) + BIN_CFG_START_LOCAL; + if ( cfgPackageLen > cfg_bin->size) { + TPD_INFO("%s:Bad firmware!,cfg package len:%d,firmware size:%d\n", + __func__, cfgPackageLen, (int)cfg_bin->size); + goto exit; + } + + /* check firmware's checksum */ + cfg_checksum = getU16(&cfg_bin->data[4]); + + for (i = BIN_CFG_START_LOCAL; i < (cfgPackageLen) ; i++) + checksum += cfg_bin->data[i]; + + if ((checksum) != cfg_checksum) { + TPD_INFO("%s:Bad firmware!(checksum: 0x%04X, header define: 0x%04X)\n", + __func__, checksum, cfg_checksum); + goto exit; + } + /* check head end */ + + bin_group_num = cfg_bin->data[MODULE_NUM]; + bin_cfg_num = cfg_bin->data[CFG_NUM]; + TPD_DEBUG("%s:bin_group_num = %d, bin_cfg_num = %d\n", + __func__, bin_group_num, bin_cfg_num); + + if (!strncmp(cfg_type, GOODIX_TEST_CONFIG, strlen(GOODIX_TEST_CONFIG))) + config_status = 0; + else if (!strncmp(cfg_type, GOODIX_NORMAL_CONFIG, strlen(GOODIX_NORMAL_CONFIG))) + config_status = 1; + else if (!strncmp(cfg_type, GOODIX_NORMAL_NOISE_CONFIG, strlen(GOODIX_NORMAL_NOISE_CONFIG))) + config_status = 2; + else if (!strncmp(cfg_type, GOODIX_GLOVE_CONFIG, strlen(GOODIX_GLOVE_CONFIG))) + config_status = 3; + else if (!strncmp(cfg_type, GOODIX_GLOVE_NOISE_CONFIG, strlen(GOODIX_GLOVE_NOISE_CONFIG))) + config_status = 4; + else if (!strncmp(cfg_type, GOODIX_HOLSTER_CONFIG, strlen(GOODIX_HOLSTER_CONFIG))) + config_status = 5; + else if (!strncmp(cfg_type, GOODIX_HOLSTER_NOISE_CONFIG, strlen(GOODIX_HOLSTER_NOISE_CONFIG))) + config_status = 6; + else if (!strncmp(cfg_type, GOODIX_NOISE_TEST_CONFIG, strlen(GOODIX_NOISE_TEST_CONFIG))) + config_status = 7; + else { + TPD_INFO("%s: invalid config text field\n", __func__); + goto exit; + } + + cfg_offset = CFG_HEAD_BYTES + bin_group_num * bin_cfg_num * CFG_INFO_BLOCK_BYTES ; + for (i = 0 ; i < bin_group_num * bin_cfg_num; i++) { + /* find cfg's sid in cfg.bin */ + one_cfg_count = getU16(&cfg_bin->data[CFG_HEAD_BYTES + 2 + i * CFG_INFO_BLOCK_BYTES]); + if (sid == (cfg_bin->data[CFG_HEAD_BYTES + i * CFG_INFO_BLOCK_BYTES])) { + sid_is_exist = GOODIX_EXIST; + if (config_status == (cfg_bin->data[CFG_HEAD_BYTES + 1 + i * CFG_INFO_BLOCK_BYTES])) { + memcpy(cfg, &cfg_bin->data[cfg_offset], one_cfg_count); + *cfg_len = one_cfg_count; + TPD_DEBUG("%s:one_cfg_count = %d, cfg_data1 = 0x%02x, cfg_data2 = 0x%02x\n", + __func__, one_cfg_count, cfg[0], cfg[1]); + break; + } + } + cfg_offset += one_cfg_count; + } + + if (i >= bin_group_num * bin_cfg_num) { + TPD_INFO("%s:(not find config ,config_status: %d)\n", __func__, config_status); + goto exit; + } + + TPD_DEBUG("%s exit\n", __func__); + return NO_ERR; +exit: + return RESULT_ERR; +} + +static int goodix_get_cfg_data(void *chip_data_info, const struct firmware *cfg_bin, + char *config_name, struct goodix_ts_config *config) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data_info; + u8 *cfg_data = NULL; + int cfg_len = 0; + int ret = NO_ERR; + + TPD_DEBUG("%s run\n", __func__); + + cfg_data = kzalloc(GOODIX_CFG_MAX_SIZE, GFP_KERNEL); + if (cfg_data == NULL) { + TPD_INFO("Memory allco err\n"); + goto exit; + } + + config->length = 0; + chip_info->ver_info.sensor_id = 0x01; + TPD_INFO("use default id is %d\n", chip_info->ver_info.sensor_id); + /* parse config data */ + ret = goodix_parse_cfg_data(cfg_bin, config_name, cfg_data, + &cfg_len, chip_info->ver_info.sensor_id); + if (ret < 0) { + TPD_INFO("%s: parse %s data failed\n", __func__, config_name); + ret = -EINVAL; + goto exit; + } + + TPD_DEBUG("%s: %s version:%d , size:%d\n", __func__, + config_name, cfg_data[0], cfg_len); + memcpy(config->data, cfg_data, cfg_len); + config->length = cfg_len; + + strncpy(config->name, config_name, MAX_STR_LEN); + +exit: + if (cfg_data) { + kfree(cfg_data); + cfg_data = NULL; + } + TPD_DEBUG("%s exit\n", __func__); + return ret; +} + + +static int goodix_get_cfg_parms(void *chip_data_info, + const struct firmware *firmware) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data_info; + int ret = 0; + + TPD_DEBUG("%s run\n", __func__); + if(firmware == NULL) { + TPD_INFO("%s: firmware is null\n", __func__); + ret = -1; + goto exit; + } + + if (firmware->data == NULL) { + TPD_INFO("%s:Bad firmware!(config firmware data is null: )\n", __func__); + ret = -1; + goto exit; + } + + TPD_INFO("%s: cfg_bin_size:%d\n", __func__, (int)firmware->size); + if (firmware->size > 56) { + TPD_INFO("cfg_bin head info:%*ph\n", 32, firmware->data); + TPD_INFO("cfg_bin head info:%*ph\n", 24, firmware->data + 32); + } + + /* parse normal config data */ + ret = goodix_get_cfg_data(chip_info, firmware, + GOODIX_NORMAL_CONFIG, &chip_info->normal_cfg); + if (ret < 0) { + TPD_INFO("%s: Failed to parse normal_config data:%d\n", __func__, ret); + } else { + TPD_DEBUG("%s: parse normal_config data success\n", __func__); + } + + ret = goodix_get_cfg_data(chip_info, firmware, + GOODIX_TEST_CONFIG, &chip_info->test_cfg); + if (ret < 0) { + TPD_INFO("%s: Failed to parse test_config data:%d\n", __func__, ret); + } else { + TPD_DEBUG("%s: parse test_config data success\n", __func__); + } + + /* parse normal noise config data */ + ret = goodix_get_cfg_data(chip_info, firmware, + GOODIX_NORMAL_NOISE_CONFIG, &chip_info->normal_noise_cfg); + if (ret < 0) { + TPD_INFO("%s: Failed to parse normal_noise_config data\n", __func__); + } else { + TPD_DEBUG("%s: parse normal_noise_config data success\n", __func__); + } + + /* parse noise test config data */ + ret = goodix_get_cfg_data(chip_info, firmware, + GOODIX_NOISE_TEST_CONFIG, &chip_info->noise_test_cfg); + if (ret < 0) { + memcpy(&chip_info->noise_test_cfg, &chip_info->normal_cfg, + sizeof(chip_info->noise_test_cfg)); + TPD_INFO("%s: Failed to parse noise_test_config data,use normal_config data\n", __func__); + } else { + TPD_DEBUG("%s: parse noise_test_config data success\n", __func__); + } +exit: + TPD_DEBUG("%s exit:%d\n", __func__, ret); + return ret; +} + +//get fw firmware from firmware +//return value: +// 0: operate success +// other: failed +static int goodix_get_fw_parms(void *chip_data_info, + const struct firmware *firmware, struct firmware *fw_firmware) +{ + //struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data_info; + int ret = 0; + int cfgPackageLen = 0; + int fwPackageLen = 0; + + TPD_DEBUG("%s run\n", __func__); + if(firmware == NULL) { + TPD_INFO("%s: firmware is null\n", __func__); + ret = -1; + goto exit; + } + + if (firmware->data == NULL) { + TPD_INFO("%s:Bad firmware!(config firmware data si null)\n", __func__); + ret = -1; + goto exit; + } + + if(fw_firmware == NULL) { + TPD_INFO("%s:fw_firmware is null\n", __func__); + ret = -1; + goto exit; + } + + TPD_DEBUG("clear fw_firmware\n"); + memset(fw_firmware, 0, sizeof(struct firmware)); + + cfgPackageLen = getU32(firmware->data) + BIN_CFG_START_LOCAL; + TPD_DEBUG("%s cfg package len:%d\n", __func__, cfgPackageLen); + + if(firmware->size <= (cfgPackageLen + 16)) { + TPD_INFO("%s current firmware does not contain goodix fw\n", __func__); + TPD_INFO("%s cfg package len:%d,firmware size:%d\n", __func__, + cfgPackageLen, (int)firmware->size); + ret = -1; + goto exit; + } + + if(!(firmware->data[cfgPackageLen + 0] == 'G' && firmware->data[cfgPackageLen + 1] == 'X' && + firmware->data[cfgPackageLen + 2] == 'F' && firmware->data[cfgPackageLen + 3] == 'W')) { + TPD_INFO("%s can't find fw package\n", __func__); + TPD_INFO("Data type:%c %c %c %c,dest type is:GXFW\n", firmware->data[cfgPackageLen + 0], + firmware->data[cfgPackageLen + 1], firmware->data[cfgPackageLen + 2], + firmware->data[cfgPackageLen + 3]); + ret = -1; + goto exit; + } + + if(firmware->data[cfgPackageLen + 4] != 1) { + TPD_INFO("%s can't support this ver:%d\n", __func__, + firmware->data[cfgPackageLen + 4]); + ret = -1; + goto exit; + } + + fwPackageLen = getU32(firmware->data + cfgPackageLen + 8); + + TPD_DEBUG("%s fw package len:%d\n", __func__, fwPackageLen); + if((fwPackageLen + 16 + cfgPackageLen) > firmware->size ) { + TPD_INFO("%s bad firmware,need len:%d,actual firmware size:%d\n", + __func__, fwPackageLen + 16 + cfgPackageLen, (int)firmware->size); + ret = -1; + goto exit; + } + + fw_firmware->size = fwPackageLen; + fw_firmware->data = firmware->data + cfgPackageLen + 16; + + TPD_DEBUG("success get fw,len:%d\n", fwPackageLen); + TPD_DEBUG("fw head info:%*ph\n", 32, fw_firmware->data); + TPD_DEBUG("fw tail info:%*ph\n", 4, &fw_firmware->data[fwPackageLen - 4 - 1]); + ret = 0; + +exit: + TPD_DEBUG("%s exit:%d\n", __func__, ret); + return ret; +} + +static fw_update_state goodix_fw_update(void *chip_data, + const struct firmware *cfg_fw_firmware, bool force) +{ + +#define FW_UPDATE_RETRY 2 + int retry0 = FW_UPDATE_RETRY; + int retry1 = FW_UPDATE_RETRY; + int r, ret; + struct chip_data_brl *chip_info; + struct fw_update_ctrl *fwu_ctrl = NULL; + struct firmware fw_firmware; + + fwu_ctrl = kzalloc(sizeof(struct fw_update_ctrl), GFP_KERNEL); + if (!fwu_ctrl) { + TPD_INFO("Failed to alloc memory for fwu_ctrl\n"); + return -ENOMEM; + } + chip_info = (struct chip_data_brl *)chip_data; + fwu_ctrl->chip_info = chip_info; + + r = goodix_get_cfg_parms(chip_data, cfg_fw_firmware); + if(r < 0) { + TPD_INFO("%s Failed get cfg from firmware\n", __func__); + } else { + TPD_INFO("%s success get ic cfg from firmware\n", __func__); + } + + r = goodix_get_fw_parms(chip_data, cfg_fw_firmware, &fw_firmware); + if(r < 0) { + TPD_INFO("%s Failed get ic fw from firmware\n", __func__); + goto err_parse_fw; + } else { + TPD_INFO("%s success get ic fw from firmware\n", __func__); + } + + fwu_ctrl->fw_data.firmware = &fw_firmware; + fwu_ctrl->ic_config = &fwu_ctrl->chip_info->normal_cfg; + r = goodix_parse_firmware(&fwu_ctrl->fw_data); + if (r < 0) { + goto err_parse_fw; + } + + /* TODO: set force update flag*/ + if (force == false) { + r = goodix_fw_version_compare(fwu_ctrl); + if (!r) { + TPD_INFO("firmware upgraded\n"); + r = FW_NO_NEED_UPDATE; + goto err_check_update; + } + } + +start_update: + do { + ret = goodix_update_prepare(fwu_ctrl); + if (ret) { + TPD_INFO("%s: failed prepare ISP, retry %d\n", __func__, + FW_UPDATE_RETRY - retry0); + } + } while (ret && --retry0 > 0); + if (ret) { + TPD_INFO("%s: Failed to prepare ISP, exit update:%d\n", + __func__, ret); + goto err_fw_prepare; + } + + /* progress: 20%~100% */ + ret = goodix_flash_firmware(fwu_ctrl); + if (ret == -EAGAIN && --retry1 > 0) { + TPD_INFO("%s: Bus error, retry firmware update:%d\n", __func__, + FW_UPDATE_RETRY - retry1); + goto start_update; + } + if (ret) + TPD_INFO("flash fw data enter error\n"); + else + TPD_INFO("flash fw data success, need check version\n"); + +err_fw_prepare: + ret = goodix_update_finish(fwu_ctrl); + if (!ret) { + TPD_INFO("Firmware update successfully\n"); + brl_get_ic_info(chip_info, &chip_info->ic_info); + r = FW_UPDATE_SUCCESS; + } else { + TPD_INFO("%s: Firmware update failed\n", __func__); + r = FW_UPDATE_ERROR; + } +err_check_update: +err_parse_fw: + ret = goodix_send_config(chip_info, chip_info->normal_cfg.data, chip_info->normal_cfg.length); + + if(ret < 0) { + TPD_INFO("%s: send normal cfg failed:%d\n", __func__, ret); + } else { + TPD_INFO("%s: send normal cfg success\n", __func__); + } + + if (fwu_ctrl) { + kfree(fwu_ctrl); + fwu_ctrl = NULL; + } + + return r; +} +/*****************end of GT9886's update function********************/ + +static u32 goodix_u32_trigger_reason(void *chip_data, + int gesture_enable, int is_suspended) +{ + int ret = -1; + u8 touch_num = 0; + u32 result_event = 0; + int pre_read_len; + u8 event_status; + struct goodix_ic_info_misc *misc; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + memset(chip_info->touch_data, 0, MAX_GT_IRQ_DATA_LENGTH); + if (chip_info->kernel_grip_support) { + memset(chip_info->edge_data, 0, MAX_GT_EDGE_DATA_LENGTH); + } + + misc = &chip_info->ic_info.misc; + if (!misc->touch_data_addr) { + TPD_INFO("%s: invalied touch data address\n", __func__); + return IRQ_IGNORE; + } + pre_read_len = IRQ_EVENT_HEAD_LEN + + BYTES_PER_POINT + COOR_DATA_CHECKSUM_SIZE; + + ret = touch_i2c_read_block_u32(chip_info->client, misc->touch_data_addr, + pre_read_len, chip_info->touch_data); + if (ret < 0) { + TPD_INFO("%s: i2c transfer error!\n", __func__); + goto IGNORE_CLEAR_IRQ; + } + + if (checksum_cmp(chip_info->touch_data, + IRQ_EVENT_HEAD_LEN, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("%s: touch head checksum err\n", __func__); + TPD_INFO("%s: touch_head %*ph\n", __func__, IRQ_EVENT_HEAD_LEN, + chip_info->touch_data); + goto IGNORE_CLEAR_IRQ; + } + + event_status = chip_info->touch_data[IRQ_EVENT_TYPE_OFFSET]; + + if (event_status & GOODIX_TOUCH_EVENT) { + touch_num = chip_info->touch_data[POINT_NUM_OFFSET] & 0x0F; + touch_num = touch_num < MAX_POINT_NUM ? touch_num : MAX_POINT_NUM; + if (chip_info->kernel_grip_support) { + if (touch_num > 0) { + // TODO add EDGE data info read function + // ret = touch_i2c_read_block_u32(chip_info->client, edge_data_addr, BYTES_PER_EDGE * touch_num, chip_info->edge_data); + // if (ret < 0) { + // TPD_INFO("%s: i2c transfer error!\n", __func__); + // goto IGNORE_CLEAR_IRQ; + // } + } + } + if (touch_num > 1) { + ret = touch_i2c_read_block_u32(chip_info->client, + misc->touch_data_addr + pre_read_len, + (touch_num - 1) * BYTES_PER_POINT, + &chip_info->touch_data[pre_read_len]); //read out point data + if (ret < 0) { + TPD_INFO("read touch point data from coor_addr failed!\n"); + goto IGNORE_CLEAR_IRQ; + } + } + + if (touch_num && checksum_cmp(&chip_info->touch_data[IRQ_EVENT_HEAD_LEN], + touch_num * BYTES_PER_POINT + 2, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("%s: touch data checksum error\n", __func__); + TPD_INFO("%s: data:%*ph", __func__, touch_num * BYTES_PER_POINT + 2,&chip_info->touch_data[IRQ_EVENT_HEAD_LEN]); + goto IGNORE_CLEAR_IRQ; + } + } else if (!(event_status & (GOODIX_GESTURE_EVENT | GOODIX_FINGER_IDLE_EVENT))) { + //TODO check this event + } + + if (gesture_enable && is_suspended && (event_status & GOODIX_GESTURE_EVENT)) { //check whether the gesture trigger + return IRQ_GESTURE; + } else if (is_suspended) { + goto IGNORE_CLEAR_IRQ; + } + if (event_status & GOODIX_FINGER_IDLE_EVENT) { + goto IGNORE_IDLETOACTIVE_IRQ; + } + if (event_status & GOODIX_REQUEST_EVENT) { //int request + return IRQ_FW_CONFIG; + } + + if (event_status & GOODIX_FINGER_STATUS_EVENT) { + SET_BIT(result_event, IRQ_FW_HEALTH); + //goto IGNORE_CLEAR_IRQ; + + } + + if (event_status & GOODIX_TOUCH_EVENT) { + SET_BIT(result_event, IRQ_TOUCH); + if ((event_status & GOODIX_FINGER_PRINT_EVENT) && + !is_suspended && (chip_info->fp_down_flag == false)) { + chip_info->fp_down_flag = true; + SET_BIT(result_event, IRQ_FINGERPRINT); + } else if (!is_suspended && (event_status & GOODIX_FINGER_PRINT_EVENT) && + (chip_info->fp_down_flag == true) ) { + chip_info->fp_down_flag = false; + SET_BIT(result_event, IRQ_FINGERPRINT); + } + } + return result_event; + +IGNORE_CLEAR_IRQ: + TPD_DEBUG("error coor data :%*ph\n", pre_read_len, chip_info->touch_data); + ret = goodix_clear_irq(chip_info); + return IRQ_IGNORE; + +IGNORE_IDLETOACTIVE_IRQ: + TPD_DEBUG("idle to active :%*ph\n", pre_read_len, chip_info->touch_data); + return IRQ_IGNORE; +} + +static int goodix_get_touch_points(void *chip_data, + struct point_info *points, int max_num) +{ + int ret, i; + int touch_map = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + u8 touch_num = 0; + + u8 finger_processed = 0; + u8 *coor_data = NULL; + u8 *ew_data = NULL; + s32 id = 0; + + touch_num = chip_info->touch_data[POINT_NUM_OFFSET] & 0x0F; + if (touch_num == 0) { //Up event + goto END_TOUCH; + } + + coor_data = &chip_info->touch_data[IRQ_EVENT_HEAD_LEN]; + ew_data = &chip_info->edge_data[0]; + id = (coor_data[0] >> 4) & 0x0F; + for (i = 0; i < max_num; i++) { + if (i == id) { + //finger_processed++; + //if(finger_processed > touch_num) + //goto END_TOUCH; + + points[i].x = le16_to_cpup((__le16 *)(coor_data + 2)); + points[i].y = le16_to_cpup((__le16 *)(coor_data + 4)); + points[i].z = coor_data[6]; + points[i].width_major = 30; // any value + points[i].status = 1; + points[i].touch_major = coor_data[7]; + points[i].tx_press = ew_data[0]; + points[i].rx_press = ew_data[1]; + + if (coor_data[1] & 0x01) { + // TODO need confirm + // chip_info->fp_coor_report.fp_x_coor = points[i].x; + // chip_info->fp_coor_report.fp_y_coor = points[i].y; + // chip_info->fp_coor_report.fp_area = coor_data[7]; + } + + touch_map |= 0x01 << i; + coor_data += BYTES_PER_POINT; + ew_data += BYTES_PER_EDGE; + + if (++finger_processed < touch_num) { + id = (coor_data[0] >> 4) & 0x0F; + } else { + break; + } + } + } +END_TOUCH: + ret = goodix_clear_irq(chip_info); + return touch_map; +} + + +//gesture define +//#define GSX_KEY_DATA_LEN 42 +//#define GSX_GESTURE_TYPE_LEN 32 +/**************************************/ +/*************************************/ +static int goodix_get_gesture_info(void *chip_data, struct gesture_info *gesture) +{ + int ret = -1; + uint8_t doze_buf[GSX_KEY_DATA_LEN] = {0}; + uint8_t point_data[MAX_GESTURE_POINT_NUM * 4 + 1]; + uint8_t point_num = 0; + uint8_t gesture_id = 0; + struct Coordinate limitPoint[4]; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + ret = touch_i2c_read_block_u32(chip_info->client, chip_info->ic_info.misc.touch_data_addr, sizeof(doze_buf), doze_buf); + if (ret < 0) { + TPD_INFO("%s: read gesture info i2c faild\n", __func__); + return -1; + } + + gesture_id = doze_buf[4]; + if (gesture_id == 0 || ((doze_buf[0] & GOODIX_GESTURE_EVENT) == 0)) { //no gesture type, no need handle + TPD_INFO("Read gesture data faild. doze_buf[0]=0x%x\n", doze_buf[0]); + goto END_GESTURE; + } + + if (checksum_cmp(doze_buf, IRQ_EVENT_HEAD_LEN, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("%s: gesture head checksum err\n", __func__); + TPD_INFO("%s: touch_head %*ph\n", __func__, IRQ_EVENT_HEAD_LEN, + &doze_buf[0]); + goto END_GESTURE; + } + + if (checksum_cmp(&doze_buf[IRQ_EVENT_HEAD_LEN], 34, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("%s: gesture coor data checksum err\n", __func__); + TPD_INFO("%s: gesture coor data %*ph\n", __func__, 34, + &doze_buf[IRQ_EVENT_HEAD_LEN]); + goto END_GESTURE; + } + + /*For FP_DOWN_DETECT FP_UP_DETECT no need to read GTP_REG_GESTURE_COOR data*/ + gesture->clockwise = 2; + switch (gesture_id) { //judge gesture type //Jarvis: need check with FW.protocol 3 + case FP_DOWN_DETECT: + gesture->gesture_type = FingerprintDown; + chip_info->fp_coor_report.fp_x_coor = (doze_buf[8] & 0xFF) | (doze_buf[9] & 0x0F) << 8; + chip_info->fp_coor_report.fp_y_coor = (doze_buf[10] & 0xFF) | (doze_buf[11] & 0x0F) << 8; + chip_info->fp_coor_report.fp_area = (doze_buf[16] & 0xFF) | (doze_buf[17] & 0x0F) << 8; + + gesture->Point_start.x = chip_info->fp_coor_report.fp_x_coor; + gesture->Point_start.y = chip_info->fp_coor_report.fp_y_coor; + gesture->Point_end.x = chip_info->fp_coor_report.fp_area; + chip_info->fp_down_flag = true; + goto REPORT_GESTURE; + break; + + case FP_UP_DETECT: + gesture->gesture_type = FingerprintUp; + chip_info->fp_coor_report.fp_x_coor = (doze_buf[8] & 0xFF) | (doze_buf[9] & 0x0F) << 8; + chip_info->fp_coor_report.fp_y_coor = (doze_buf[10] & 0xFF) | (doze_buf[11] & 0x0F) << 8; + chip_info->fp_coor_report.fp_area = (doze_buf[16] & 0xFF) | (doze_buf[17] & 0x0F) << 8; + + gesture->Point_start.x = chip_info->fp_coor_report.fp_x_coor; + gesture->Point_start.y = chip_info->fp_coor_report.fp_y_coor; + gesture->Point_end.x = chip_info->fp_coor_report.fp_area; + + chip_info->fp_down_flag = false; + goto REPORT_GESTURE; + break; + } + + memset(point_data, 0, sizeof(point_data)); + point_num = doze_buf[3]; + point_num = point_num < MAX_GESTURE_POINT_NUM ? point_num : MAX_GESTURE_POINT_NUM; + + //ret = touch_i2c_read_block(chip_info->client, chip_info->reg_info.GTP_REG_GESTURE_COOR, point_num * 4 +1, point_data); //havn't add checksum here. + ret = touch_i2c_read_block_u32(chip_info->client, chip_info->ic_info.misc.touch_data_addr + 42, point_num * 4 +1, point_data); + if (ret < 0) { + TPD_INFO("%s: read gesture data i2c faild\n", __func__); + goto END_GESTURE; + } + + switch (gesture_id) { //judge gesture type //Jarvis: need check with FW.protocol 3 + case RIGHT_SLIDE_DETECT : + gesture->gesture_type = Left2RightSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case LEFT_SLIDE_DETECT : + gesture->gesture_type = Right2LeftSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case DOWN_SLIDE_DETECT : + gesture->gesture_type = Up2DownSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case UP_SLIDE_DETECT : + gesture->gesture_type = Down2UpSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case DTAP_DETECT: + gesture->gesture_type = DouTap; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_end.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + break; + + case STAP_DETECT: + gesture->gesture_type = SingleTap; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_end.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + break; + + case UP_VEE_DETECT : + gesture->gesture_type = UpVee; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case DOWN_VEE_DETECT : + gesture->gesture_type = DownVee; + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case LEFT_VEE_DETECT: + gesture->gesture_type = LeftVee; + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case RIGHT_VEE_DETECT ://this gesture is C + case RIGHT_VEE_DETECT2://this gesture is < + gesture->gesture_type = RightVee; + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_end.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + break; + + case CIRCLE_DETECT : + gesture->gesture_type = Circle; + gesture->clockwise = clockWise(&point_data[0], point_num); + getSpecialCornerPoint(&point_data[0], point_num, &limitPoint[0]); + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[20] & 0xFF) | (point_data[21] & 0x0F) << 8; + gesture->Point_end.y = (point_data[22] & 0xFF) | (point_data[23] & 0x0F) << 8; + gesture->Point_1st = limitPoint[0]; //ymin + gesture->Point_2nd = limitPoint[1]; //xmin + gesture->Point_3rd = limitPoint[2]; //ymax + gesture->Point_4th = limitPoint[3]; //xmax + break; + + case DOUSWIP_DETECT : + gesture->gesture_type = DouSwip; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_end.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_2nd.x = (point_data[12] & 0xFF) | (point_data[13] & 0x0F) << 8; + gesture->Point_2nd.y = (point_data[14] & 0xFF) | (point_data[15] & 0x0F) << 8; + break; + + case M_DETECT : + gesture->gesture_type = Mgestrue; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[16] & 0xFF) | (point_data[17] & 0x0F) << 8; + gesture->Point_end.y = (point_data[18] & 0xFF) | (point_data[19] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + gesture->Point_2nd.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_2nd.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_3rd.x = (point_data[12] & 0xFF) | (point_data[13] & 0x0F) << 8; + gesture->Point_3rd.y = (point_data[14] & 0xFF) | (point_data[15] & 0x0F) << 8; + break; + + case W_DETECT : + gesture->gesture_type = Wgestrue; + gesture->Point_start.x = (point_data[0] & 0xFF) | (point_data[1] & 0x0F) << 8; + gesture->Point_start.y = (point_data[2] & 0xFF) | (point_data[3] & 0x0F) << 8; + gesture->Point_end.x = (point_data[16] & 0xFF) | (point_data[17] & 0x0F) << 8; + gesture->Point_end.y = (point_data[18] & 0xFF) | (point_data[19] & 0x0F) << 8; + gesture->Point_1st.x = (point_data[4] & 0xFF) | (point_data[5] & 0x0F) << 8; + gesture->Point_1st.y = (point_data[6] & 0xFF) | (point_data[7] & 0x0F) << 8; + gesture->Point_2nd.x = (point_data[8] & 0xFF) | (point_data[9] & 0x0F) << 8; + gesture->Point_2nd.y = (point_data[10] & 0xFF) | (point_data[11] & 0x0F) << 8; + gesture->Point_3rd.x = (point_data[12] & 0xFF) | (point_data[13] & 0x0F) << 8; + gesture->Point_3rd.y = (point_data[14] & 0xFF) | (point_data[15] & 0x0F) << 8; + break; + + default: + gesture->gesture_type = UnkownGesture; + break; + } + +REPORT_GESTURE: + TPD_INFO("%s: gesture_id = 0x%x, gesture_type = %d, clockWise = %d, point:(%d %d)(%d %d)(%d %d)(%d %d)(%d %d)(%d %d)\n", + __func__, gesture_id, gesture->gesture_type, gesture->clockwise, + gesture->Point_start.x, gesture->Point_start.y, gesture->Point_end.x, gesture->Point_end.y, + gesture->Point_1st.x, gesture->Point_1st.y, gesture->Point_2nd.x, gesture->Point_2nd.y, + gesture->Point_3rd.x, gesture->Point_3rd.y, gesture->Point_4th.x, gesture->Point_4th.y); + +END_GESTURE: + ret = goodix_clear_irq(chip_info); //clear int + return 0; + + /************************************************************/ + // TODO need add gesture process code + gesture->gesture_type = UnkownGesture; + ret = goodix_clear_irq(chip_info); //clear int + return 0; +} + +//#define GTP_REG_DEBUG 0x102DC + +static void goodix_get_health_info(void *chip_data, struct monitor_data *mon_data) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_health_info *health_info; + struct goodix_health_info *health_local = &chip_info->health_info; + u8 log[50]; + int ret = 0; + u8 clear_flag = 0; + + ret = touch_i2c_read_block_u32(chip_info->client, chip_info->ic_info.misc.fw_state_addr,50,log); + if (ret < 0) { + TPD_INFO("%s: read debug log data i2c faild\n", __func__); + goto END_HEALTH; + } + TPD_INFO("GTP_REG_DEBUG:%*ph\n", 50, log); + if (checksum_cmp(log, 50, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("%s: read debug log data checksum erro\n", __func__); + } + + health_info = (struct goodix_health_info *)log; + + if (health_info->shield_water) { + mon_data->shield_water++; + if (tp_debug != 0) { + TPD_INFO("%s: enter water mode\n", __func__); + } + } + if (health_info->baseline_refresh) { + switch(health_info->baseline_refresh_type) { + case BASE_DC_COMPONENT: + mon_data->reserve1++; + break; + case BASE_SYS_UPDATE: + mon_data->reserve2++; + break; + case BASE_NEGATIVE_FINGER: + mon_data->reserve3++; + break; + case BASE_MONITOR_UPDATE: + mon_data->reserve4++; + break; + case BASE_CONSISTENCE: + mon_data->reserve4++; + break; + case BASE_FORCE_UPDATE: + mon_data->baseline_err++; + break; + default: + break; + } + if (tp_debug != 0) { + TPD_INFO("%s: baseline refresh type: %d \n", __func__, health_info->baseline_refresh_type); + } + } + if (health_info->shield_freq != 0) { + mon_data->noise_count++; + if (tp_debug != 0) { + TPD_INFO("%s: freq before: %d HZ, freq after: %d HZ\n", __func__,health_info->freq_before_l | health_info->freq_before_h<<8,health_info->freq_after_h<< 8 | health_info->freq_after_l); + + } + } + if (health_info->fw_rst != 0) { + switch(health_info->reset_reason) { + case RST_MAIN_REG: + mon_data->hard_rst++; + break; + case RST_OVERLAY_ERROR: + mon_data->inst_rst++; + break; + case RST_LOAD_OVERLAY: + mon_data->parity_rst++; + break; + case RST_CHECK_PID: + mon_data->wd_rst++; + break; + case RST_CHECK_RAM: + mon_data->other_rst++; + break; + case RST_CHECK_RAWDATA: + mon_data->other_rst++; + break; + default: + break; + } + + if (tp_debug != 0) { + TPD_INFO("%s: fw reset type : %d\n", __func__, health_info->reset_reason); + } + } + if (health_info->shield_palm != 0) { + mon_data->shield_palm++; + TPD_DEBUG("%s: enter palm mode\n", __func__); + } + + if (health_info->baseline_status!= 0) { + if (tp_debug != 0) { + TPD_DEBUG("%s: baseline_type is :0x%x \n", __func__,health_info->baseline_study_status); + } + } + + if (health_info->ub_freqhop_status != 0) { + if (tp_debug != 0) { + TPD_DEBUG("%s: ub_freqhop_status is :0x%x \n", __func__,health_info->ub_freqhop_type); + } + } + + if (health_info->noise_stutus != 0) { + if (tp_debug != 0) { + TPD_DEBUG("%s: last_frame_noise_value is :0x%x , current_frame_noise_value is :0x%x \n", __func__,health_info->last_noise_value_h << 8 | health_info->last_noise_value_l,health_info->current_noise_value_h << 8 | health_info->current_noise_value_l); + } + } + + if (tp_debug != 0) { + TPD_INFO("%s: abs_max:,abs_avg: %d %d \n",__func__, + (int) (health_info->abs_max_h <<8 | health_info->abs_max_l),(int) ( health_info->abs_avg_h << 8 | health_info->abs_avg_l)); + + TPD_INFO("%s: mutual_diff_max, mutual_diff_min: %d %d \n",__func__, + health_info->mutualdif_max_h << 8 | health_info->mutualdif_max_l, health_info->mutualdif_min_h << 8 | health_info->mutualdif_min_l); + + TPD_INFO("%s: self_tx_diff_max:,self_txdiff_min: %d %d \n",__func__, + health_info->selftx_diff_max_h << 8 | health_info->selftx_diff_max_l, health_info->selftx_diff_min_h<<8 | health_info->selftx_diff_min_l); + + TPD_INFO("%s: self_rx_diff_max:,self_rxdiff_min: %d %d \n",__func__, + health_info->selfrx_diff_max_h<<8 | health_info->selfrx_diff_max_l, health_info->selfrx_diff_min_h<<8 | health_info->selfrx_diff_min_l); + + TPD_INFO("%s: touch_num:,rect_num: %d %d \n",__func__,health_info->touch_num, health_info->rectnum); + } + + mon_data->shield_esd = chip_info->esd_err_count; + mon_data->reserve5 = chip_info->send_cmd_err_count; + memcpy(health_local, health_info, sizeof(struct goodix_health_info)); + + ret = touch_i2c_write_block_u32(chip_info->client,chip_info->ic_info.misc.fw_state_addr,1,&clear_flag); + if (ret < 0) { + TPD_INFO("%s: clear debug log data i2c faild\n", __func__); + } + +END_HEALTH: + + // TOO add health info + ret = goodix_clear_irq(chip_info); //clear int + return; +} + +static int goodix_mode_switch(void *chip_data, work_mode mode, bool flag) +{ + int ret = -1; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + if (!chip_info->ic_info.length) { + TPD_INFO("%s: goodix ic info invalid\n", __func__); + return ret; + } + if (chip_info->halt_status && (mode != MODE_NORMAL)) { + goodix_reset(chip_info); + } + + switch(mode) { + case MODE_NORMAL: + ret = 0; //after reset, it's already normal + break; + + case MODE_SLEEP: + ret = goodix_enter_sleep(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: goodix enter sleep failed\n", __func__); + } + break; + + case MODE_GESTURE: + ret = goodix_enable_gesture(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: goodix enable:(%d) gesture failed.\n", __func__, flag); + return ret; + } + break; + + case MODE_LIMIT_SWITCH: + ret = goodix_enable_edge_limit(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: goodix enable:(%d) edge limit failed.\n", __func__, flag); + return ret; + } + break; + + case MODE_CHARGE: + ret = goodix_enable_charge_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable charge mode : %d failed\n", __func__, flag); + } + break; + + case MODE_GAME: + ret = goodix_enable_game_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable game mode : %d failed\n", __func__, flag); + } + break; + + default: + TPD_INFO("%s: mode %d not support.\n", __func__, mode); + } + + return ret; +} + +static int goodix_esd_handle(void *chip_data) //Jarvis:have not finished +{ + s32 ret = -1; + u8 esd_buf = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_ic_info_misc *misc = &chip_info->ic_info.misc; + + if (!chip_info->esd_check_enabled || !misc->esd_addr) { + TPD_DEBUG("%s: close\n", __func__); + return 0; + } + + ret = touch_i2c_read_block_u32(chip_info->client, misc->esd_addr, 1, &esd_buf); + if ((ret < 0) || esd_buf == 0xAA) { + TPD_INFO("%s: esd dynamic esd occur, ret = %d, esd_buf = %d.\n", + __func__, ret, esd_buf); + TPD_INFO("%s: IC works abnormally! Process esd reset.\n", __func__); + disable_irq_nosync(chip_info->client->irq); + + goodix_power_control(chip_info, false); + msleep(30); + goodix_power_control(chip_info, true); + msleep(10); + + goodix_reset(chip_data); // reset function have rewrite the esd reg no need to do it again + + tp_touch_btnkey_release(); + + enable_irq(chip_info->client->irq); + TPD_INFO("%s: Goodix esd reset over.\n", __func__); + chip_info->esd_err_count ++; + return -1; + } else { + esd_buf = 0xAA; + ret = touch_i2c_write_block_u32(chip_info->client, + chip_info->ic_info.misc.esd_addr, 1, &esd_buf); + if (ret < 0) { + TPD_INFO("%s: Failed to reset esd reg.\n", __func__); + } + } + + return 0; +} + +static void goodix_enable_fingerprint_underscreen(void *chip_data, uint32_t enable) +{ + int ret = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + TPD_INFO("%s, enable = %d\n", __func__, enable); + if (enable) { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_FOD_FINGER_PRINT, 0); + } else { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_FOD_FINGER_PRINT, 1); + } + + return; +} + +static void goodix_enable_gesture_mask(void *chip_data, uint32_t enable) +{ + int ret = -1; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + TPD_INFO("%s, enable = %d\n", __func__, enable); + if (enable) { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_GESTURE_MASK, 1);/* enable all gesture */ + } else { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_GESTURE_MASK, 0);/* mask all gesture */ + } + + return; +} + +static void goodix_screenon_fingerprint_info(void *chip_data, + struct fp_underscreen_info *fp_tpinfo) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + if (chip_info->fp_down_flag) { + fp_tpinfo->x = chip_info->fp_coor_report.fp_x_coor; + fp_tpinfo->y = chip_info->fp_coor_report.fp_y_coor; + fp_tpinfo->area_rate = chip_info->fp_coor_report.fp_area; + fp_tpinfo->touch_state = FINGERPRINT_DOWN_DETECT; + } else { + fp_tpinfo->x = chip_info->fp_coor_report.fp_x_coor; + fp_tpinfo->y = chip_info->fp_coor_report.fp_y_coor; + fp_tpinfo->area_rate = chip_info->fp_coor_report.fp_area; + fp_tpinfo->touch_state = FINGERPRINT_UP_DETECT; + } +} + +static int goodix_request_event_handler(struct chip_data_brl *chip_info) +{ + int ret = -1; + u8 rqst_code = 0; + + rqst_code = chip_info->touch_data[REQUEST_EVENT_TYPE_OFFSET]; + TPD_INFO("%s: request state:0x%02x.\n", __func__, rqst_code); + + switch (rqst_code) { + case GTP_RQST_CONFIG: + TPD_INFO("HW request config.\n"); + ret = goodix_send_config(chip_info, chip_info->normal_cfg.data, + chip_info->normal_cfg.length); + if (ret) { + TPD_INFO("request config, send config faild.\n"); + } + break; + case GTP_RQST_RESET: + TPD_INFO("%s: HW requset reset.\n", __func__); + goodix_reset(chip_info); + break; + default: + TPD_INFO("%s: Unknown hw request:%d.\n", __func__, rqst_code); + break; + } + + goodix_clear_irq(chip_info); + return 0; +} + +static int goodix_fw_handle(void *chip_data) +{ + int ret = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + ret = goodix_request_event_handler(chip_info); + ret |= goodix_clear_irq(chip_info); + + return ret; +} + +static void goodix_register_info_read(void *chip_data, + uint16_t register_addr, uint8_t *result, uint8_t length) +{ + //struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + // TODO need change framework to support u32 address + //touch_i2c_read_block_u32(chip_info->client, register_addr, length, result); /*read data*/ +} + +static void goodix_set_touch_direction(void *chip_data, uint8_t dir) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + chip_info->touch_direction = dir; +} + +static uint8_t goodix_get_touch_direction(void *chip_data) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + return chip_info->touch_direction; +} + +static void goodix_specific_resume_operate(void *chip_data) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + TPD_DEBUG("%s call\n", __func__); + goodix_esd_check_enable(chip_info, true); +} + +static int goodix_enable_single_tap(void *chip_data, bool enable) +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + chip_info->single_tap_flag = enable; + return 0; +} + +struct touchpanel_operations brl_goodix_ops = { + .ftm_process = goodix_ftm_process, + .get_vendor = goodix_get_vendor, + .get_util_vendor = goodix_util_get_vendor, + .get_chip_info = goodix_get_chip_info, + .reset = goodix_reset, + .power_control = goodix_power_control, + .fw_check = goodix_fw_check, + .fw_update = goodix_fw_update, + .u32_trigger_reason = goodix_u32_trigger_reason, + .get_touch_points = goodix_get_touch_points, + .get_gesture_info = goodix_get_gesture_info, + .mode_switch = goodix_mode_switch, + .esd_handle = goodix_esd_handle, + .fw_handle = goodix_fw_handle, + .register_info_read = goodix_register_info_read, + .get_usb_state = goodix_get_usb_state, + .enable_fingerprint = goodix_enable_fingerprint_underscreen, + .enable_gesture_mask = goodix_enable_gesture_mask, + .screenon_fingerprint_info = goodix_screenon_fingerprint_info, + .set_touch_direction = goodix_set_touch_direction, + .get_touch_direction = goodix_get_touch_direction, + .specific_resume_operate = goodix_specific_resume_operate, + .gt_health_report = goodix_get_health_info, + .enable_single_tap = goodix_enable_single_tap, +}; +/********* End of implementation of touchpanel_operations callbacks**********************/ + +/******** Start of implementation of debug_info_proc_operations callbacks*********************/ +static void goodix_debug_info_read(struct seq_file *s, + void *chip_data, debug_type debug_type) +{ + int ret = -1, i = 0, j = 0; + u8 *kernel_buf = NULL; + int addr = 0; + u8 clear_state = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_ic_info *ic_info; + int TX_NUM = 0; + int RX_NUM = 0; + s16 data = 0; + + // /*keep in active mode*/ + // goodix_send_cmd_simple(chip_info, GTP_CMD_ENTER_DOZE_TIME, 0xFF); + + ic_info = &chip_info->ic_info; + RX_NUM = ic_info->parm.sen_num; + TX_NUM = ic_info->parm.drv_num; + if (!TX_NUM || !RX_NUM) { + TPD_INFO("%s: error invalid tx %d or rx %d num\n", + __func__, TX_NUM, RX_NUM); + return; + } + + kernel_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if(kernel_buf == NULL) { + TPD_INFO("%s kmalloc error\n", __func__); + return; + } + switch (debug_type) { + case GTP_RAWDATA: + addr = ic_info->misc.mutual_rawdata_addr; + break; + case GTP_DIFFDATA: + addr = ic_info->misc.mutual_diffdata_addr; + break; + default: + addr = ic_info->misc.mutual_refdata_addr; + break; + } + gt8x_rawdiff_mode = 1; + goodix_send_cmd_simple(chip_info, GTP_CMD_RAWDATA, 0); + msleep(20); + touch_i2c_write_block_u32(chip_info->client, ic_info->misc.touch_data_addr, 1, &clear_state); + + //wait for data ready + while(i++ < 10) { + ret = touch_i2c_read_block_u32(chip_info->client, ic_info->misc.touch_data_addr, 1, kernel_buf); + TPD_INFO("ret = %d kernel_buf = %d\n", ret, kernel_buf[0]); + if(!ret && (kernel_buf[0] & 0x80)) { + TPD_INFO("Data ready OK\n"); + break; + } + msleep(20); + } + if(i >= 10) { + TPD_INFO("data not ready, quit!\n"); + goto read_data_exit; + } + + ret = touch_i2c_read_block_u32(chip_info->client, addr, TX_NUM * RX_NUM * 2, kernel_buf); + msleep(5); + + for(i = 0; i < RX_NUM; i++) { + seq_printf(s, "[%2d] ", i); + for(j = 0; j < TX_NUM; j++) { + data = kernel_buf[j * RX_NUM * 2 + i * 2] + (kernel_buf[j * RX_NUM * 2 + i * 2 + 1] << 8); + seq_printf(s, "%4d ", data); + } + seq_printf(s, "\n"); + } +read_data_exit: + goodix_send_cmd_simple(chip_info, GTP_CMD_NORMAL, 0); + gt8x_rawdiff_mode = 0; + touch_i2c_write_block_u32(chip_info->client, ic_info->misc.touch_data_addr, 1, &clear_state); + // /*be normal in idle*/ + // goodix_send_cmd_simple(chip_info, GTP_CMD_DEFULT_DOZE_TIME, 0x00); + + kfree(kernel_buf); + return; +} + +static void goodix_down_diff_info_read(struct seq_file *s, void *chip_data) +{ + //TODO need add down diff addr info to ic_info struct + int ret = -1, i = 0, j = 0; + u8 *kernel_buf = NULL; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_ic_info *ic_info; + int TX_NUM = 0; + int RX_NUM = 0; + s16 diff_data = 0; + + ic_info = &chip_info->ic_info; + + kernel_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if(kernel_buf == NULL) { + TPD_INFO("%s kmalloc error\n", __func__); + return; + } + + RX_NUM = ic_info->parm.sen_num; + TX_NUM = ic_info->parm.drv_num; + + if (TX_NUM > 50 || RX_NUM > 50) { + TPD_INFO("%s first finger down diff data is invalid.\n", __func__); + goto exit; + } + + if ((TX_NUM * RX_NUM * 2+2) > PAGE_SIZE) { + TPD_INFO("%s: data invalid, tx:%d,rx :%d\n", __func__, TX_NUM, RX_NUM); + goto exit; + } + + //ret = touch_i2c_read_block_u32(chip_info->client, ic_info->misc.touch_data_addr, TX_NUM * RX_NUM * 2 + 2, kernel_buf); + ret = touch_i2c_read_block_u32(chip_info->client, 0x17DE8, TX_NUM * RX_NUM * 2 + 2 , kernel_buf); + if (ret < 0) { + TPD_INFO("%s failed to read down diff data.\n", __func__); + goto exit; + } + + seq_printf(s, "\nfinger first down diff data:\n"); + + for(i = 0; i < RX_NUM; i++) { + seq_printf(s, "[%2d] ", i); + for(j = 0; j < TX_NUM; j++) { + diff_data = (kernel_buf[j * RX_NUM * 2 + i * 2 + 2]) + (kernel_buf[j * RX_NUM * 2 + i * 2 + 1 + 2] <<8); + seq_printf(s, "%4d ", diff_data); + } + seq_printf(s, "\n"); + } + +exit: + + if (kernel_buf) { + kfree(kernel_buf); + } + + return; +} + +//proc/touchpanel/debug_info/delta +static void goodix_delta_read(struct seq_file *s, void *chip_data) +{ + //struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + //int ret =0; + goodix_debug_info_read(s, chip_data, GTP_DIFFDATA); + if (tp_debug) { + goodix_down_diff_info_read(s, chip_data); + } +} + +//proc/touchpanel/debug_info/baseline +static void goodix_baseline_read(struct seq_file *s, void *chip_data) +{ + goodix_debug_info_read(s, chip_data, GTP_RAWDATA); +} + +//proc/touchpanel/debug_info/main_register +static void goodix_main_register_read(struct seq_file *s, void *chip_data)//Jarvis:need change to GT9886's register +{ + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_ic_info_misc *ic_info_misc; + int ret = 0; + u8 touch_data[IRQ_EVENT_HEAD_LEN + BYTES_PER_POINT + COOR_DATA_CHECKSUM_SIZE] = {0}; + + ic_info_misc = &chip_info->ic_info.misc; + seq_printf(s, "====================================================\n"); + if(chip_info->p_tp_fw) { + seq_printf(s, "tp fw = 0x%s\n", chip_info->p_tp_fw); + } + ret = touch_i2c_read_block_u32(chip_info->client, ic_info_misc->touch_data_addr, + sizeof(touch_data), touch_data); + if (ret < 0) { + TPD_INFO("%s: i2c transfer error!\n", __func__); + goto out; + } + seq_printf(s, "cached touch_data: %*ph\n", (int)sizeof(touch_data), chip_info->touch_data); + TPD_INFO("%s: cached touch_data: %*ph\n", __func__, (int)sizeof(touch_data), chip_info->touch_data); + // TODO need confirm the data, address and length + seq_printf(s, "current touch_data: %*ph\n", (int)sizeof(touch_data), touch_data); + TPD_INFO("%s: current touch_data: %*ph\n", __func__, (int)sizeof(touch_data), touch_data); + seq_printf(s, "====================================================\n"); +out: + return; +} + +static struct debug_info_proc_operations debug_info_proc_ops = { + .limit_read = goodix_limit_read, + .delta_read = goodix_delta_read, + .baseline_read = goodix_baseline_read, + .main_register_read = goodix_main_register_read, +}; +/********* End of implementation of debug_info_proc_operations callbacks**********************/ + +/************** Start of callback of proc/Goodix/config_version node**************************/ + +/* success return config_len, <= 0 failed */ +static int goodix_read_config(struct chip_data_brl *chip_info, u8 *cfg, int size) +{ + int ret; + struct goodix_ts_cmd cfg_cmd; + struct goodix_ic_info_misc *misc = &chip_info->ic_info.misc; + struct goodix_config_head cfg_head; + + if (!cfg) + return -EINVAL; + + cfg_cmd.len = CONFIG_CND_LEN; + cfg_cmd.cmd = CONFIG_CMD_READ_START; + ret = send_cfg_cmd(chip_info, &cfg_cmd); + if (ret) { + TPD_INFO("%s: failed send config read prepare command\n", __func__); + return ret; + } + + ret = touch_i2c_read_block_u32(chip_info->client, misc->fw_buffer_addr, + sizeof(cfg_head), cfg_head.buf); + if (ret) { + TPD_INFO("%s: failed read config head %d\n", __func__, ret); + goto exit; + } + + if (checksum_cmp(cfg_head.buf, sizeof(cfg_head), CHECKSUM_MODE_U8_LE)) { + TPD_INFO("%s: config head checksum error\n", __func__); + ret = -EINVAL; + goto exit; + } + + cfg_head.cfg_len = le16_to_cpu(cfg_head.cfg_len); + if (cfg_head.cfg_len > misc->fw_buffer_max_len || + cfg_head.cfg_len > size) { + TPD_INFO("%s: cfg len exceed buffer size %d > %d\n", __func__, cfg_head.cfg_len, + misc->fw_buffer_max_len); + ret = -EINVAL; + goto exit; + } + + memcpy(cfg, cfg_head.buf, sizeof(cfg_head)); + ret = touch_i2c_read_block_u32(chip_info->client, misc->fw_buffer_addr + sizeof(cfg_head), + cfg_head.cfg_len, cfg + sizeof(cfg_head)); + if (ret) { + TPD_INFO("%s: failed read cfg pack, %d\n", __func__, ret); + goto exit; + } + + TPD_INFO("config len %d\n", cfg_head.cfg_len); + if (checksum_cmp(cfg + sizeof(cfg_head), + cfg_head.cfg_len, CHECKSUM_MODE_U16_LE)) { + TPD_INFO("%s: config body checksum error\n", __func__); + ret = -EINVAL; + goto exit; + } + TPD_INFO("success read config data: len %zu,config_version is : %d\n", + cfg_head.cfg_len + sizeof(cfg_head),cfg[34]); +exit: + memset(cfg_cmd.buf, 0, sizeof(cfg_cmd)); + cfg_cmd.len = CONFIG_CND_LEN; + cfg_cmd.cmd = CONFIG_CMD_READ_EXIT; + if (send_cfg_cmd(chip_info, &cfg_cmd)) { + TPD_INFO("%s: failed send config read finish command\n", __func__); + ret = -EINVAL; + } + if (ret) + return -EINVAL; + return cfg_head.cfg_len + sizeof(cfg_head); +} + +static void goodix_config_info_read(struct seq_file *s, void *chip_data) +{ + int ret = 0, i = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_fw_version *fw_version = &chip_info->ver_info; + struct goodix_ic_info *ic_info = &chip_info->ic_info; + + seq_printf(s, "==== Goodix default config setting in driver====\n"); + for(i = 0; i < TS_CFG_MAX_LEN && i < chip_info->normal_cfg.length; i++) { + seq_printf(s, "0x%02X, ", chip_info->normal_cfg.data[i]); + if(i % 10 == 9) + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + seq_printf(s, "==== Goodix test cfg in driver====\n"); + for(i = 0; i < TS_CFG_MAX_LEN && i < chip_info->test_cfg.length; i++) { + seq_printf(s, "0x%02X, ", chip_info->test_cfg.data[i]); + if(i % 10 == 9) + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + seq_printf(s, "==== Goodix noise test cfg in driver====\n"); + for(i = 0; i < TS_CFG_MAX_LEN && i < chip_info->noise_test_cfg.length; i++) { + seq_printf(s, "0x%02X, ", chip_info->noise_test_cfg.data[i]); + if(i % 10 == 9) + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + + seq_printf(s, "==== Goodix config read from chip====\n"); + + ret = brl_get_ic_info(chip_info, ic_info); + if (ret) { + TPD_INFO("%s: failed get ic info, ret %d\n", __func__, ret); + goto exit; + } + ret = brl_read_version(chip_info, fw_version); + if(ret) { + TPD_INFO("goodix_config_info_read goodix_read_config error:%d\n", ret); + goto exit; + } + + seq_printf(s, "\n"); + seq_printf(s, "==== Goodix Version Info ====\n"); + seq_printf(s, "ConfigVer: %02X\n", ic_info->version.config_version); + seq_printf(s, "ProductID: GT%s\n", fw_version->patch_pid); + seq_printf(s, "PatchID: %*ph\n", (int)sizeof(fw_version->patch_pid), fw_version->patch_pid); + seq_printf(s, "MaskID: %*ph\n", (int)sizeof(fw_version->rom_vid), fw_version->rom_vid); + seq_printf(s, "SensorID: %02X\n", fw_version->sensor_id); + +exit: + return; +} +/*************** End of callback of proc/Goodix/config_version node***************************/ + +/************** Start of atuo test func**************************/ +static int init_test_config(struct goodix_ts_test *ts_test) +{ + int ret = 0; + + return ret; +} + +static void goodix_print_testdata(struct goodix_ts_test *ts_test) +{ + struct ts_test_params *test_params = NULL; + int i = 0; + test_params = &ts_test->test_params; + + if (tp_debug < 2) + return; + TPD_DEBUG("rawdata:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->rawdata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("noisedata:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->noisedata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_rawdata:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->self_rawdata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_noisedata:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", ts_test->self_noisedata.data[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } +} + +static void goodix_print_test_params(struct goodix_ts_test *ts_test) +{ + struct ts_test_params *test_params = NULL; + int i = 0; + test_params = &ts_test->test_params; + + if (tp_debug < 2) + return; + TPD_DEBUG("sen_num:%d,drv_num:%d\n", test_params->sen_num, test_params->drv_num); + TPD_DEBUG("rawdata_addr:%d,noisedata_addr:%d\n", test_params->rawdata_addr, test_params->noisedata_addr); + TPD_DEBUG("self_rawdata_addr:%d,self_noisedata_addr:%d\n", test_params->self_rawdata_addr, test_params->self_noisedata_addr); + TPD_DEBUG("basedata_addr:%d\n", test_params->basedata_addr); + + TPD_DEBUG("max_limits:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->max_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("min_limits:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->min_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("deviation_limits:\n"); + for(i = 0; i < test_params->drv_num * test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->deviation_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_max_limits:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->self_max_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } + + TPD_DEBUG("self_min_limits:\n"); + for(i = 0; i < test_params->drv_num + test_params->sen_num; i++) { + TPD_DEBUG("%d,", test_params->self_min_limits[i]); + if (!((i + 1) % test_params->sen_num) && (i != 0)) + TPD_DEBUG("\n"); + } +} + +static int goodix_init_testlimits(struct goodix_ts_test *ts_test) +{ + struct goodix_testdata *p_testdata = ts_test->p_testdata; + struct test_item_info *p_test_item_info = NULL; + /*for item parameter data*/ + uint32_t *para_data32 = NULL; + uint32_t para_num = 0; + int ret = 0; + struct ts_test_params *test_params = NULL; + + test_params = &ts_test->test_params; + test_params->drv_num = p_testdata->TX_NUM; + test_params->sen_num = p_testdata->RX_NUM; + TPD_INFO("sen_num:%d,drv_num:%d\n", test_params->sen_num, test_params->drv_num); + + para_data32 = getpara_for_item(p_testdata->fw, TYPE_NOISE_DATA_LIMIT, ¶_num); + if(para_data32) { + ts_test->is_item_support[TYPE_NOISE_DATA_LIMIT] = para_data32[0]; + if (para_num >= 2) { + test_params->noise_threshold = para_data32[1]; + } + } else { + TPD_INFO("%s: Failed get %s\n", __func__, CSV_TP_NOISE_LIMIT); + ret = -1; + goto INIT_LIMIT_END; + } + + para_data32 = getpara_for_item(p_testdata->fw, TYPE_SHORT_THRESHOLD, ¶_num); + if(para_data32) { + ts_test->is_item_support[TYPE_SHORT_THRESHOLD] = para_data32[0]; + TPD_INFO("get TYPE_SHORT_THRESHOLD data,len:%d\n", para_num); + if (para_num >= 8) { + // store data to test_parms + test_params->short_threshold = para_data32[1]; + test_params->r_drv_drv_threshold = para_data32[2]; + test_params->r_drv_sen_threshold = para_data32[3]; + test_params->r_sen_sen_threshold = para_data32[4]; + test_params->r_drv_gnd_threshold = para_data32[5]; + test_params->r_sen_gnd_threshold = para_data32[6]; + test_params->avdd_value = para_data32[7]; + } + } else { + TPD_INFO("%s: Failed get %s\n", __func__, CSV_TP_SHORT_THRESHOLD); + ret = -1; + goto INIT_LIMIT_END; + } + + p_test_item_info = get_test_item_info(p_testdata->fw, TYPE_SPECIAL_RAW_MAX_MIN); + if(p_test_item_info) { + if (p_test_item_info->para_num) { + if (p_test_item_info->p_buffer[0]) { + TPD_INFO("get TYPE_SPECIAL_RAW_MAX_MIN data,len:%d\n", para_num); + ts_test->is_item_support[TYPE_SPECIAL_RAW_MAX_MIN] = p_test_item_info->p_buffer[0]; + if (p_test_item_info->item_limit_type == LIMIT_TYPE_MAX_MIN_DATA) { + test_params->max_limits = (uint32_t *)(p_testdata->fw->data + p_test_item_info->top_limit_offset); + test_params->min_limits = (uint32_t *)(p_testdata->fw->data + p_test_item_info->floor_limit_offset); + } else { + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_MAX_MIN); + } + } + } + } else { + ret = -1; + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_MAX_MIN); + } + + p_test_item_info = get_test_item_info(p_testdata->fw, TYPE_SPECIAL_RAW_DELTA); + if (p_test_item_info) { + if (p_test_item_info->para_num) { + if (p_test_item_info->p_buffer[0]) { + TPD_INFO("get TYPE_SPECIAL_RAW_DELTA data,len:%d\n", para_num); + ts_test->is_item_support[TYPE_SPECIAL_RAW_DELTA] = p_test_item_info->p_buffer[0]; + if (p_test_item_info->item_limit_type == LIMIT_TYPE_MAX_MIN_DATA) { + test_params->deviation_limits = (uint32_t *)(p_testdata->fw->data + p_test_item_info->top_limit_offset); + } else { + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_DELTA); + } + } + } + } else { + ret = -1; + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_RAW_DELTA); + } + + para_data32 = getpara_for_item(p_testdata->fw, TYPE_NOISE_SLEFDATA_LIMIT, ¶_num); + if(para_data32) { + ts_test->is_item_support[TYPE_NOISE_SLEFDATA_LIMIT] = para_data32[0]; + if (para_num >= 2) { + // store data to test_parms + test_params->self_noise_threshold = para_data32[1]; + } + } else { + TPD_INFO("%s: Failed get %s\n", __func__, CSV_TP_SELFNOISE_LIMIT); + ret = -1; + goto INIT_LIMIT_END; + } + + p_test_item_info = get_test_item_info(p_testdata->fw, TYPE_SPECIAL_SELFRAW_MAX_MIN); + if(p_test_item_info) { + if (p_test_item_info->para_num) { + if (p_test_item_info->p_buffer[0]) { + ts_test->is_item_support[TYPE_SPECIAL_SELFRAW_MAX_MIN] = p_test_item_info->p_buffer[0]; + if (p_test_item_info->item_limit_type == IMIT_TYPE_SLEFRAW_DATA) { + TPD_INFO("get IMIT_TYPE_SLEFRAW_DATA data\n"); + test_params->self_max_limits = (int32_t *)(p_testdata->fw->data + p_test_item_info->top_limit_offset); + test_params->self_min_limits = (int32_t *)(p_testdata->fw->data + p_test_item_info->floor_limit_offset); + } else { + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_SELFRAW_MAX_MIN); + } + } else { + TPD_INFO("TYPE_SPECIAL_SELFRAW_MAX_MIN para_num is invalid\n"); + } + } + } else { + ret = -1; + TPD_INFO("item: %d get_test_item_info fail\n", TYPE_SPECIAL_SELFRAW_MAX_MIN); + } + + ret |= init_test_config(ts_test); + +INIT_LIMIT_END: + if (p_test_item_info) { + kfree(p_test_item_info); + } + return ret; +} + +static int goodix_init_params(struct goodix_ts_test *ts_test) +{ + int ret = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + struct ts_test_params *test_params = &ts_test->test_params; + + TPD_INFO("%s run\n", __func__); + + test_params->rawdata_addr = chip_info->ic_info.misc.mutual_rawdata_addr; + test_params->noisedata_addr = chip_info->ic_info.misc.mutual_diffdata_addr; + test_params->self_rawdata_addr = chip_info->ic_info.misc.self_rawdata_addr; + test_params->self_noisedata_addr = chip_info->ic_info.misc.self_diffdata_addr; + test_params->basedata_addr = chip_info->ic_info.misc.mutual_refdata_addr; + test_params->max_drv_num = MAX_DRV_NUM; + test_params->max_sen_num = MAX_SEN_NUM; + test_params->drv_map = gt9897_drv_map; + test_params->sen_map = gt9897_sen_map; + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + + +/* goodix_read_origconfig + * + * read original config data + */ +static int goodix_cache_origconfig(struct goodix_ts_test *ts_test) +{ + int ret = -ENODEV; + + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("goodix_cache_origconfig run\n"); + + ret = goodix_read_config(chip_info, &ts_test->orig_config.data[0], TS_CFG_MAX_LEN); + if (ret < 0) { + TPD_INFO("Failed to read original config data\n"); + return ret; + } + TPD_INFO("goodix_cache_origconfig read original config success\n"); + /* + ts_test->orig_config.data[1] |= GOODIX_CONFIG_REFRESH_DATA; + checksum = checksum_u8(&ts_test->orig_config.data[0], 3); + ts_test->orig_config.data[3] = (u8)(0 - checksum); + */ + ts_test->orig_config.length = ret; + strcpy(ts_test->orig_config.name, "original_config"); + + TPD_INFO("goodix_cache_origconfig exit\n"); + return NO_ERR; +} + +/* goodix_tptest_prepare + * + * preparation before tp test + */ +static int goodix_tptest_prepare(struct goodix_ts_test *ts_test) +{ + int ret = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("TP test preparation\n"); + ret = goodix_cache_origconfig(ts_test); + if (ret) { + TPD_INFO("Failed cache origin config\n"); + return ret; + } + + /* init reg addr and short cal map */ + ret = goodix_init_params(ts_test); + if (ret) { + TPD_INFO("Failed init register address\n"); + return ret; + } + /* parse test limits from csv */ + ret = goodix_init_testlimits(ts_test); + if (ret < 0) { + TPD_INFO("Failed to init testlimits from csv:%d\n", ret); + ts_test->error_count ++; + seq_printf(ts_test->p_seq_file, "Failed to init testlimits from csv\n"); + } + ret = goodix_send_config(chip_info, chip_info->noise_test_cfg.data, chip_info->noise_test_cfg.length); + if (ret < 0) { + TPD_INFO("Failed to send noise test config config:%d,noise_config len:%d\n", ret, chip_info->noise_test_cfg.length); + } + TPD_INFO("send noise test config success :%d,noise_config len:%d\n", ret, chip_info->noise_test_cfg.length); + msleep(200); + + return ret; +} + +/* goodix_tptest_finish + * + * finish test + */ +static int goodix_tptest_finish(struct goodix_ts_test *ts_test) +{ + int ret = RESULT_ERR; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("TP test finish\n"); + goodix_reset(chip_info); + + // if (goodix_set_i2c_doze_mode(core_data->ts_dev,true)) + // TPD_INFO("WRNING: doze may enabled after reset\n"); + + ret = goodix_send_config(chip_info, ts_test->orig_config.data, ts_test->orig_config.length); + // ret = goodix_send_config(chip_info, chip_info->noise_test_cfg.data, chip_info->noise_test_cfg.length); + if(ret < 0) { + TPD_INFO("goodix_tptest_finish:Failed to send normal config:%d\n", ret); + } else { + TPD_INFO("goodix_tptest_finish send normal config succesful\n"); + } + + return ret; +} + +static int normandy_sync_read_rawdata(struct i2c_client *client, + unsigned int sync_addr, unsigned char sync_mask, + unsigned int reg_addr, unsigned char *data, + unsigned int len) +{ + int ret = 0; + int retry_times = 0; + unsigned char sync_data[0]; + + TPD_INFO("%s run,reg_addr:0x%04x,len:%d,sync_addr:0x%04x,sync_mask:0x%x\n", + __func__, reg_addr, len, sync_addr, sync_mask); + + while(retry_times ++ < 200) { + sync_data[0] = 0x00; + msleep(10); + ret = touch_i2c_read_block_u32(client, sync_addr, 1, sync_data); + if(ret < 0 || ((sync_data[0] & sync_mask) == 0)) { + TPD_INFO("%s sync invalid,ret:%d,sync data:0x%x\n", + __func__, ret, sync_data[0]); + continue; + } + + TPD_INFO("%s sync is valid:0x%x\n", __func__, sync_data[0]); + + ret = touch_i2c_read_block_u32(client, reg_addr, len, data); + if(ret < 0) { + TPD_INFO("sync read rawdata failed:%d\n", ret); + } else { + break; + } + } + + if(retry_times >= 200) { + TPD_INFO("sync read rawdata timeout\n"); + ret = -1; + } else { + TPD_INFO("sync read rawdata,get rawdata success\n"); + sync_data[0] = 0x00; + ret = touch_i2c_write_block_u32(client, sync_addr, 1, sync_data); + TPD_INFO("sync read rawdata,clear sync\n"); + ret = 0; + } + + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +/** + * goodix_cache_rawdata - cache rawdata + */ +static int goodix_cache_rawdata(struct goodix_ts_test *ts_test) +{ + int j = 0; + int i = 0; + int ret = -EINVAL; + u32 rawdata_size = 0; + u32 rawdata_addr = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + TPD_INFO("Cache rawdata\n"); + ts_test->rawdata.size = 0; + rawdata_size = ts_test->test_params.sen_num * ts_test->test_params.drv_num; + + if (rawdata_size > MAX_DRV_NUM * MAX_SEN_NUM || rawdata_size <= 0) { + TPD_INFO("Invalid rawdata size(%u)\n", rawdata_size); + return ret; + } + + rawdata_addr = ts_test->test_params.rawdata_addr; + TPD_INFO("Rawdata address=0x%x\n", rawdata_addr); + + for (j = 0; j < GOODIX_RETRY_NUM_3; j++) { + /* read rawdata */ + ret = normandy_sync_read_rawdata(chip_info->client, + chip_info->ic_info.misc.touch_data_addr, 0x80, rawdata_addr, + (u8 *)&ts_test->rawdata.data[0], rawdata_size * sizeof(u16)); + if (ret < 0) { + if (j == GOODIX_RETRY_NUM_3 - 1) { + TPD_INFO("Failed to read rawdata:%d,at:%d\n", ret, j); + goto cache_exit; + } else { + continue; + } + } + for (i = 0; i < rawdata_size; i++) + ts_test->rawdata.data[i] = le16_to_cpu(ts_test->rawdata.data[i]); + ts_test->rawdata.size = rawdata_size; + TPD_INFO("Rawdata ready\n"); + break; + } + +cache_exit: + return ret; +} + +/** + * goodix_cache_selfrawdata - cache selfrawdata + */ +static int goodix_cache_self_rawdata(struct goodix_ts_test *ts_test) +{ + int i = 0, j = 0; + int ret = -EINVAL; + u16 self_rawdata_size = 0; + u32 self_rawdata_addr = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + TPD_INFO("Cache selfrawdata\n"); + ts_test->self_rawdata.size = 0; + self_rawdata_size = ts_test->test_params.sen_num + ts_test->test_params.drv_num; + + if (self_rawdata_size > MAX_DRV_NUM + MAX_SEN_NUM || self_rawdata_size <= 0) { + TPD_INFO("Invalid selfrawdata size(%u)\n", self_rawdata_size); + return ret; + } + + self_rawdata_addr = ts_test->test_params.self_rawdata_addr; + TPD_INFO("Selfraw address=0x%x\n", self_rawdata_addr); + + for (j = 0; j < GOODIX_RETRY_NUM_3; j++) { + /* read selfrawdata */ + ret = normandy_sync_read_rawdata(chip_info->client, + chip_info->ic_info.misc.touch_data_addr, 0x80, + self_rawdata_addr, (u8 *)&ts_test->self_rawdata.data[0], + self_rawdata_size * sizeof(u16)); + if (ret < 0) { + if (j == GOODIX_RETRY_NUM_3 - 1) { + TPD_INFO("Failed to read self_rawdata:%d\n", ret); + goto cache_exit; + } else { + continue; + } + } + for (i = 0; i < self_rawdata_size; i++) + ts_test->self_rawdata.data[i] = le16_to_cpu(ts_test->self_rawdata.data[i]); + ts_test->self_rawdata.size = self_rawdata_size; + TPD_INFO("self_Rawdata ready\n"); + break; + } + +cache_exit: + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +/** + * goodix_noisetest_prepare- noisetest prepare + */ +static int goodix_noisetest_prepare(struct goodix_ts_test *ts_test) +{ + int ret = 0; + u32 noise_data_size = 0; + u32 self_noise_data_size = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("%s run\n", __func__); + noise_data_size = ts_test->test_params.sen_num * ts_test->test_params.drv_num; + self_noise_data_size = ts_test->test_params.sen_num + ts_test->test_params.drv_num; + + if (noise_data_size <= 0 || noise_data_size > MAX_DRV_NUM * MAX_SEN_NUM) { + TPD_INFO("%s: Bad noise_data_size[%d]\n", __func__, noise_data_size); + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + return -EINVAL; + } + + if (self_noise_data_size <= 0 || self_noise_data_size > MAX_DRV_NUM + MAX_SEN_NUM) { + TPD_INFO("%s: Bad self_noise_data_size[%d]\n", __func__, self_noise_data_size); + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; + return -EINVAL; + } + + ts_test->noisedata.size = noise_data_size; + ts_test->self_noisedata.size = self_noise_data_size; + + /* change to rawdata mode */ + ret = goodix_send_cmd_simple(chip_info, GTP_CMD_RAWDATA, 0); + if (ret < 0) { + TPD_INFO("%s: Failed send rawdata command:ret:%d\n", __func__, ret); + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; + return ret; + } + msleep(50); + + TPD_INFO("%s: Enter rawdata mode\n", __func__); + + return ret; +} + +/** + * goodix_cache_noisedata- cache noisedata + */ +static int goodix_cache_noisedata(struct goodix_ts_test *ts_test) +{ + int ret = 0; + int ret1 = 0; + u32 noisedata_addr = 0; + u32 self_noisedata_addr = 0; + u32 noise_data_size = 0; + u32 self_noise_data_size = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + noisedata_addr = ts_test->test_params.noisedata_addr; + self_noisedata_addr = ts_test->test_params.self_noisedata_addr; + noise_data_size = ts_test->noisedata.size; + self_noise_data_size = ts_test->self_noisedata.size; + + /* read noise data */ + ret = normandy_sync_read_rawdata(chip_info->client, + chip_info->ic_info.misc.touch_data_addr, 0x80, + noisedata_addr, (u8 *)&ts_test->noisedata.data[0], + noise_data_size * sizeof(u16)); + if (ret < 0) { + TPD_INFO("%s: Failed read noise data\n", __func__); + ts_test->noisedata.size = 0; + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + } + + /* read self noise data */ + ret1 = normandy_sync_read_rawdata(chip_info->client, + chip_info->ic_info.misc.touch_data_addr, 0x80, + self_noisedata_addr, (u8 *)&ts_test->self_noisedata.data[0], + self_noise_data_size * sizeof(u16)); + if (ret1 < 0) { + TPD_INFO("%s: Failed read self noise data\n", __func__); + ts_test->self_noisedata.size = 0; + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; + } + + TPD_INFO("%s exit:%d\n", __func__, ret | ret1); + return ret | ret1; +} + +/** + * goodix_analyse_noisedata- analyse noisedata + */ +static void goodix_analyse_noisedata(struct goodix_ts_test *ts_test) +{ + int i = 0; + u32 find_bad_node = 0; + s16 noise_value = 0; + + for (i = 0; i < ts_test->noisedata.size; i++) { + noise_value = (s16)le16_to_cpu(ts_test->noisedata.data[i]); + ts_test->noisedata.data[i] = abs(noise_value); + + if (ts_test->noisedata.data[i] > ts_test->test_params.noise_threshold) { + find_bad_node++; + TPD_INFO("noise check failed: niose[%d][%d]:%u, > %u\n", + (u32)div_s64(i, ts_test->test_params.sen_num), + i % ts_test->test_params.sen_num, + ts_test->noisedata.data[i], + ts_test->test_params.noise_threshold); + } + } + if (find_bad_node) { + TPD_INFO("%s:noise test find bad node\n", __func__); + ts_test->test_result[GTP_NOISE_TEST] = GTP_PANEL_REASON; + } else { + ts_test->test_result[GTP_NOISE_TEST] = GTP_TEST_PASS; + TPD_INFO("noise test check pass\n"); + } + + return; +} + +/** + * goodix_analyse_self_noisedata- analyse self noisedata + */ +static void goodix_analyse_self_noisedata(struct goodix_ts_test *ts_test) +{ + int i = 0; + u32 self_find_bad_node = 0; + s16 self_noise_value = 0; + TPD_INFO("%s run\n", __func__); + for (i = 0; i < ts_test->self_noisedata.size; i++) { + self_noise_value = (s16)be16_to_cpu(ts_test->self_noisedata.data[i]); + ts_test->self_noisedata.data[i] = abs(self_noise_value); + + if (ts_test->self_noisedata.data[i] > ts_test->test_params.self_noise_threshold) { + self_find_bad_node++; + TPD_INFO("self noise check failed: self_noise[%d][%d]:%u, > %u\n", + (u32)div_s64(i, ts_test->test_params.drv_num), + i % ts_test->test_params.drv_num, + ts_test->self_noisedata.data[i], + ts_test->test_params.self_noise_threshold); + } + } + + if (self_find_bad_node) { + TPD_INFO("%s:self_noise test find bad node\n", __func__); + ts_test->test_result[GTP_SELFNOISE_TEST] = GTP_PANEL_REASON; + } else { + ts_test->test_result[GTP_SELFNOISE_TEST] = GTP_TEST_PASS; + TPD_INFO("self noise test check passed\n"); + } + TPD_INFO("%s exit\n", __func__); + return; +} + + +/* test noise data */ +static void goodix_test_noisedata(struct goodix_ts_test *ts_test) +{ + int ret = 0; + int test_cnt = 0; + u8 buf[1]; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("%s run\n", __func__); + ret = goodix_noisetest_prepare(ts_test); + if (ret < 0) { + TPD_INFO("%s :Noisetest prepare failed\n", __func__); + goto soft_err_out; + } + + /* read noisedata and self_noisedata,calculate result */ + for (test_cnt = 0; test_cnt < RAWDATA_TEST_TIMES; test_cnt++) { + ret = goodix_cache_noisedata(ts_test); + if (ret) { + if (test_cnt == RAWDATA_TEST_TIMES - 1) { + TPD_INFO("%s: Cache noisedata failed\n", __func__); + goto soft_err_out; + } else { + continue; + } + } + goodix_analyse_noisedata(ts_test); + + goodix_analyse_self_noisedata(ts_test); + break; + } + + TPD_INFO("%s: Noisedata and Self_noisedata test end\n", __func__); + goto noise_test_exit; + +soft_err_out: + ts_test->noisedata.size = 0; + ts_test->test_result[GTP_NOISE_TEST] = SYS_SOFTWARE_REASON; + ts_test->self_noisedata.size = 0; + ts_test->test_result[GTP_SELFNOISE_TEST] = SYS_SOFTWARE_REASON; +noise_test_exit: + ret = goodix_send_cmd_simple(chip_info, GTP_CMD_NORMAL, 0); + + buf[0] = 0x00; + ret = touch_i2c_write_block_u32(chip_info->client, chip_info->ic_info.misc.touch_data_addr, 1, buf); + return; +} + +static int goodix_self_rawcapacitance_test(struct ts_test_self_rawdata *rawdata, + struct ts_test_params *test_params) +{ + int i = 0; + int ret = NO_ERR; + + for (i = 0; i < rawdata->size; i++) { + if (rawdata->data[i] > test_params->self_max_limits[i]) { + TPD_INFO("self_rawdata[%d][%d]:%u >self_max_limit:%u, NG\n", + (u32)div_s64(i, test_params->drv_num), i % test_params->drv_num, + rawdata->data[i], test_params->self_max_limits[i]); + ret = RESULT_ERR; + } + + if (rawdata->data[i] < test_params->self_min_limits[i]) { + TPD_INFO("self_rawdata[%d][%d]:%u < min_limit:%u, NG\n", + (u32)div_s64(i, test_params->drv_num), i % test_params->drv_num, + rawdata->data[i], test_params->self_min_limits[i]); + ret = RESULT_ERR; + } + } + + return ret; +} + +/* goodix_captest_prepare + * + * parse test peremeters from dt + */ +static int goodix_captest_prepare(struct goodix_ts_test *ts_test) +{ + int ret = -EINVAL; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + TPD_INFO("%s run\n", __func__); + + ret = goodix_send_config(chip_info, chip_info->test_cfg.data, chip_info->test_cfg.length); + if (ret) + TPD_INFO("Failed to send test config:%d\n", ret); + else + TPD_INFO("Success send test config\n"); + + TPD_INFO("%s exit:%d\n", __func__, ret); + return ret; +} + +static int goodix_rawcapacitance_test(struct ts_test_rawdata *rawdata, + struct ts_test_params *test_params) +{ + int i = 0; + int ret = NO_ERR; + + for (i = 0; i < rawdata->size; i++) { + if (rawdata->data[i] > test_params->max_limits[i]) { + TPD_INFO("rawdata[%d][%d]:%u > max_limit:%u, NG\n", + (u32)div_s64(i, test_params->sen_num), i % test_params->sen_num, + rawdata->data[i], test_params->max_limits[i]); + ret = RESULT_ERR; + } + + if (rawdata->data[i] < test_params->min_limits[i]) { + TPD_INFO("rawdata[%d][%d]:%u < min_limit:%u, NG\n", + (u32)div_s64(i, test_params->sen_num), i % test_params->sen_num, + rawdata->data[i], test_params->min_limits[i]); + ret = RESULT_ERR; + } + } + + return ret; +} + +static int goodix_deltacapacitance_test(struct ts_test_rawdata *rawdata, + struct ts_test_params *test_params) +{ + int i = 0; + int ret = NO_ERR; + int cols = 0; + u32 max_val = 0; + u32 rawdata_val = 0; + u32 sc_data_num = 0; + u32 up = 0, down = 0, left = 0, right = 0; + + cols = test_params->sen_num; + sc_data_num = test_params->drv_num * test_params->sen_num; + if (cols <= 0) { + TPD_INFO("%s: parmas invalid\n", __func__); + return RESULT_ERR; + } + + for (i = 0; i < sc_data_num; i++) { + rawdata_val = rawdata->data[i]; + max_val = 0; + /* calculate deltacpacitance with above node */ + if (i - cols >= 0) { + up = rawdata->data[i - cols]; + up = abs(rawdata_val - up); + if (up > max_val) + max_val = up; + } + + /* calculate deltacpacitance with bellow node */ + if (i + cols < sc_data_num) { + down = rawdata->data[i + cols]; + down = abs(rawdata_val - down); + if (down > max_val) + max_val = down; + } + + /* calculate deltacpacitance with left node */ + if (i % cols) { + left = rawdata->data[i - 1]; + left = abs(rawdata_val - left); + if (left > max_val) + max_val = left; + } + + /* calculate deltacpacitance with right node */ + if ((i + 1) % cols) { + right = rawdata->data[i + 1]; + right = abs(rawdata_val - right); + if (right > max_val) + max_val = right; + } + + /* float to integer */ + if (rawdata_val) { + max_val *= FLOAT_AMPLIFIER; + max_val = (u32)div_s64(max_val, rawdata_val); + if (max_val > test_params->deviation_limits[i]) { + TPD_INFO("deviation[%d][%d]:%u > delta_limit:%u, NG\n", + (u32)div_s64(i, cols), i % cols, max_val, + test_params->deviation_limits[i]); + ret = RESULT_ERR; + } + } else { + TPD_INFO("Find rawdata=0 when calculate deltacapacitance:[%d][%d]\n", + (u32)div_s64(i, cols), i % cols); + ret = RESULT_ERR; + } + } + + return ret; +} + +/* goodix_rawdata_test + * test rawdata with one frame + */ +static void goodix_rawdata_test(struct goodix_ts_test *ts_test) +{ + int ret = 0; + /* read rawdata and calculate result, statistics fail times */ + ret = goodix_cache_rawdata(ts_test); + if (ret < 0) { + /* Failed read rawdata */ + TPD_INFO("Read rawdata failed\n"); + ts_test->test_result[GTP_CAP_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_DELTA_TEST] = SYS_SOFTWARE_REASON; + } else { + ret = goodix_rawcapacitance_test(&ts_test->rawdata, &ts_test->test_params); + if (!ret) { + ts_test->test_result[GTP_CAP_TEST] = GTP_TEST_PASS; + TPD_INFO("Rawdata test pass\n"); + } else { + ts_test->test_result[GTP_CAP_TEST] = GTP_PANEL_REASON; + TPD_INFO("RawCap test failed\n"); + } + + ret = goodix_deltacapacitance_test(&ts_test->rawdata, &ts_test->test_params); + if (!ret) { + ts_test->test_result[GTP_DELTA_TEST] = GTP_TEST_PASS; + TPD_INFO("DeltaCap test pass\n"); + } else { + ts_test->test_result[GTP_DELTA_TEST] = GTP_PANEL_REASON; + TPD_INFO("DeltaCap test failed\n"); + } + } +} + +static void goodix_capacitance_test(struct goodix_ts_test *ts_test) +{ + int ret = 0; + u8 buf[1]; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("%s run\n", __func__); + ret = goodix_captest_prepare(ts_test); + if (ret) { + TPD_INFO("Captest prepare failed\n"); + ts_test->test_result[GTP_CAP_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_DELTA_TEST] = SYS_SOFTWARE_REASON; + ts_test->test_result[GTP_SELFCAP_TEST] = SYS_SOFTWARE_REASON; + return; + } + /* read rawdata and calculate result, statistics fail times */ + ret = goodix_send_cmd_simple(chip_info, GTP_CMD_RAWDATA, 0); + if (ret < 0) { + TPD_INFO("%s:Failed send rawdata cmd:ret%d\n", __func__, ret); + goto capac_test_exit; + } else { + TPD_INFO("%s: Success change to rawdata mode\n", __func__); + } + msleep(50); + + goodix_rawdata_test(ts_test); + + /* read selfrawdata and calculate result, statistics fail times */ + ret = goodix_cache_self_rawdata(ts_test); + if (ret < 0) { + /* Failed read selfrawdata */ + TPD_INFO("Read selfrawdata failed\n"); + ts_test->test_result[GTP_SELFCAP_TEST] = SYS_SOFTWARE_REASON; + goto capac_test_exit; + } else { + ret = goodix_self_rawcapacitance_test(&ts_test->self_rawdata, &ts_test->test_params); + if (!ret) { + ts_test->test_result[GTP_SELFCAP_TEST] = GTP_TEST_PASS; + TPD_INFO("selfrawdata test pass\n"); + } else { + ts_test->test_result[GTP_SELFCAP_TEST] = GTP_PANEL_REASON; + TPD_INFO("selfrawCap test failed\n"); + } + } +capac_test_exit: + goodix_send_cmd_simple(chip_info, GTP_CMD_NORMAL, 0); + + buf[0] = 0x00; + ret = touch_i2c_write_block_u32(chip_info->client, chip_info->ic_info.misc.touch_data_addr, 1, buf); + return; +} + +static void goodix_intgpio_test(struct goodix_ts_test *p_ts_test) +{ + /*for interrupt pin test*/ + int eint_status = 0, eint_count = 0, read_gpio_num = 0;//not test int pin + + TPD_INFO("%s, step 0: begin to check INT-GND short item\n", __func__); + + while (read_gpio_num--) { + msleep(5); + eint_status = gpio_get_value(p_ts_test->p_testdata->irq_gpio); + if (eint_status == 1) { + eint_count--; + } else { + eint_count++; + } + TPD_INFO("%s eint_count = %d eint_status = %d\n", __func__, eint_count, eint_status); + } + TPD_INFO("TP EINT PIN %s direct short! eint_count = %d\n", eint_count == 10 ? "is" : "not", eint_count); + if (eint_count == 10) { + TPD_INFO("error : TP EINT PIN direct short!\n"); + seq_printf(p_ts_test->p_seq_file, "eint_status is low, TP EINT direct stort\n"); + eint_count = 0; + p_ts_test->error_count ++; + p_ts_test->test_result[GTP_INTPIN_TEST] = GTP_PANEL_REASON; + } + p_ts_test->test_result[GTP_INTPIN_TEST] = GTP_TEST_PASS; +} + +/* Error code of AFE Inspection */ +typedef enum { + THP_AFE_INSPECT_OK = 0, /* OK */ + THP_AFE_INSPECT_ESPI = (1 << 0), // 0:0x0001, SPI communication error + THP_AFE_INSPECT_ERAW = (1 << 1), // 1:0x0002, Raw data error + THP_AFE_INSPECT_ENOISE = (1 << 2), // 2:0x0004, Noise error + THP_AFE_INSPECT_EOPEN = (1 << 3), // 3:0x0008, Sensor open error + THP_AFE_INSPECT_ESHORT = (1 << 4), // 4:0x0010, Sensor short error + THP_AFE_INSPECT_ERC = (1 << 5), // 5:0x0020, Sensor RC error + THP_AFE_INSPECT_EPIN = (1 << 6), // 6:0x0040, + /* Errors of TSVD/TSHD/TRCST/TRCRQ and other PINs + when Report Rate Switching between 60 Hz and 120 Hz */ + THP_AFE_INSPECT_EOTHER = (1 << 7) // 7:0x0080, All other errors +} THP_AFE_INSPECT_ERR_ENUM; + + +static u32 gt9897_short_parms[] = {10, 150, 150, 150, 100, 100, 30}; + +/* max pin num */ +#define MAX_DRV_PIN_NUM 21 +#define MAX_SEN_PIN_NUM 42 +#define DRV_CHANNEL_FLAG 0x80 + +/**************************************************/ + +#define INSPECT_FW_SWITCH_CMD 0x85 +#define INSPECT_PARAM_CMD 0xAA + +#define INSPECT_CMD_ACK_DONE 0xEE + +#define INSPECT_CMD_STATUS_RUNNING 0x00 +#define INSPECT_CMD_STATUS_DRV_DONE 0x08 +#define INSPECT_CMD_STATUS_SEN_DONE 0x80 +#define INSPECT_CMD_STATUS_FINISH 0x88 + +#define SHORT_FW_CMD_REG 0x10400 +#define SHORT_TEST_TIME_REG 0x11FF2 +#define GTX8_RETRY_NUM(x) (x) +#define TEST_FW_PID "OST" /* PID3-5 */ +#define MAX_TEST_TIME_MS 5000 +#define DEFAULT_TEST_TIME_MS 1000 +#define MIN_TEST_TIME_MS 800 + + + +#define DFT_SHORT_THRESHOLD 16 +#define DFT_DIFFCODE_SHORT_THRESHOLD 16 +#define DFT_ADC_DUMP_NUM 1396 + +#define DRV_TO_DRV_R(selfcode, V2) (((selfcode)/(V2) - 1) * 63) +#define SEN_TO_SEN_R(selfcode, V2) (((selfcode)/(V2) - 1) * 63) +#define SEN_TO_DRV_R(selfcode, V2) (((selfcode)/(V2) - 1) * 63) + + + +//#define DRV_TO_AVDD_R(diffcode, avdd) ((1.25 * 1024 * ((avdd) - 12.5) * 40) / ((diffcode) * 10) - 40) +#define DRV_TO_AVDD_R(diffcode, avdd) ((51200*avdd)-(125*5120))/(((diffcode) * 10) - 40) + +//((1.25 * 1024 * ((avdd) - 12.5) * 40) / ((diffcode) * 10) - 40) + +#define SEN_TO_AVDD_R(diffcode, avdd) ((51200*avdd)-(125*5120))/(((diffcode) * 10) - 40) +//((1.25 * 1024 * ((avdd) - 12.5) * 40) / ((diffcode) * 10) - 40) +//#define SEN_TO_AVDD_R(diffcode, avdd) ((1.25 * 1024 * ((avdd) - 12.5) * 40) / ((diffcode) * 10) - 40) +#define DRV_TO_GND_R(diffcode) ((64148 / (diffcode)) - 40) +#define SEN_TO_GND_R(diffcode) ((64148 / (diffcode)) - 40) + +#define SHORT_CELL_SIZE(a) (4 + (a) * 2 + 2) + +static u8 map_die2pin(struct ts_test_params *test_params, u8 chn_num) +{ + int i = 0; + u8 res = 255; + + for (i = 0; i < MAX_SEN_PIN_NUM; i++) { + if (test_params->sen_map[i] == chn_num) { + res = i; + break; + } + } + + /* res != 0xFF mean found the corresponding channel num */ + if (res != 0xFF) + return res; + + /* if cannot find in SenMap try find in DrvMap */ + for (i = 0; i < MAX_DRV_PIN_NUM; i++) { + if (test_params->drv_map[i] == chn_num) { + res = i; + break; + } + } + if (res >= MAX_DRV_PIN_NUM) { + TPD_INFO("Faild found corrresponding channel num:%d\n", chn_num); + } else { + res |= DRV_CHANNEL_FLAG; + } + return res; +} + + +#define SHORT_TYPE_FLAG ((uint16_t)1 << 15) + +static int gdix_check_resistance_to_gnd(struct ts_test_params *test_params, + u16 adc_signal, u32 pos) +{ + long r = 0; + u16 r_th = 0, avdd_value = 0; + u16 chn_id_tmp = 0; + u8 pin_num = 0; + + avdd_value = test_params->avdd_value; + if (adc_signal == 0 || adc_signal == 0x8000) + adc_signal |= 1; + + if ((adc_signal & 0x8000) == 0) { /* short to GND */ + if (pos < MAX_DRV_NUM) + r = DRV_TO_GND_R(adc_signal); + else + r = SEN_TO_GND_R(adc_signal); + } else { /* short to VDD */ + //adc_signal = adc_signal & ~0x8000; + if (pos < MAX_DRV_NUM) + r = DRV_TO_AVDD_R((adc_signal & ~0x8000), avdd_value); + else + r = SEN_TO_AVDD_R((adc_signal & ~0x8000), avdd_value); + } + + if (pos < MAX_DRV_NUM) + r_th = test_params->r_drv_gnd_threshold; + else + r_th = test_params->r_sen_gnd_threshold; + + chn_id_tmp = pos; + if (chn_id_tmp < MAX_DRV_NUM) + chn_id_tmp += MAX_SEN_NUM; + else + chn_id_tmp -= MAX_DRV_NUM; + + if (r < r_th) { + pin_num = map_die2pin(test_params, chn_id_tmp); + TPD_INFO("%s%d shortcircut to %s,R=%ldK,R_Threshold=%dK\n", + (pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (pin_num & ~DRV_CHANNEL_FLAG), + (adc_signal & 0x8000) ? "VDD" : "GND", + r, r_th); + + return THP_AFE_INSPECT_ESHORT; + } + return THP_AFE_INSPECT_OK; +} + + + +#define DRV_DRV_SELFCODE_REG 0x1045E +static int gdix_check_tx_tx_shortcircut(struct goodix_ts_test *ts_test, u8 short_ch_num) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u16 adc_signal = 0; + u8 master_pin_num, slave_pin_num; + u8 *data_buf = NULL; + uint32_t data_reg; + //struct short_record temp_short_info; + struct ts_test_params *test_params = &ts_test->test_params; + u16 self_capdata, short_die_num = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *) ts_test->ts; + + + size = SHORT_CELL_SIZE(MAX_DRV_NUM); /* 4 + MAX_DRV_NUM * 2 + 2; */ + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + TPD_INFO("Failed to alloc memory\n"); + return THP_AFE_INSPECT_EOTHER; + } + + /* drv&drv shortcircut check */ + data_reg = DRV_DRV_SELFCODE_REG; + for (i = 0; i < short_ch_num; i++) { + ret = touch_i2c_read_block_u32(chip_info->client,data_reg, size, data_buf); + if (ret) { + TPD_INFO("Failed read Drv-to-Drv short rawdata\n"); + err |= THP_AFE_INSPECT_ESPI; + break; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("Drv-to-Drv adc data checksum error\n"); + //NLOGI_ARRAY(data_buf, size); + TPD_INFO("%s: data_buf:%*ph " ,__func__,40,data_buf); + err |= THP_AFE_INSPECT_ESPI; + break; + } + + r_threshold = test_params->r_drv_drv_threshold; + short_die_num = le16_to_cpup((__le16 *)&data_buf[0]); //info->length = le16_to_cpup((__le16 *)data); + short_die_num -= MAX_SEN_NUM; + if (short_die_num >= MAX_DRV_NUM) { + TPD_INFO("invalid short pad num:%d\n", + short_die_num + MAX_SEN_NUM); + continue; + } + + /* TODO: j start position need recheck */ + self_capdata = le16_to_cpup((__le16 *)&data_buf[2]); + if (self_capdata == 0xffff || self_capdata == 0) { + TPD_INFO("invalid self_capdata:0x%x\n", self_capdata); + continue; + } + + for (j = short_die_num + 1; j < MAX_DRV_NUM; j++) { + adc_signal = le16_to_cpup((__le16 *)&data_buf[4 + j * 2]); + if (adc_signal < test_params->short_threshold) + continue; + short_r = DRV_TO_DRV_R(self_capdata, adc_signal); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(test_params, short_die_num + MAX_SEN_NUM); + slave_pin_num = map_die2pin(test_params, j + MAX_SEN_NUM); + if (master_pin_num == 0xFF || slave_pin_num == 0xFF) { + TPD_INFO("WARNNING invalid pin"); + continue; + } + TPD_INFO("short circut:R=%dK,R_Threshold=%dK\n", + short_r, r_threshold); + TPD_INFO("%s%d--%s%d shortcircut\n", + (master_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err |= THP_AFE_INSPECT_ESHORT; + } + } + data_reg += size; + } + + if (data_buf != NULL) { + kfree(data_buf); + data_buf = NULL; + } + return err; +} + +#define SEN_SEN_SELFCODE_REG 0x1084E +static int gdix_check_rx_rx_shortcircut(struct goodix_ts_test *ts_test, u8 short_ch_num) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u16 adc_signal = 0; + u8 master_pin_num, slave_pin_num; + u8 *data_buf = NULL; + uint32_t data_reg; + // struct short_record temp_short_info; + struct ts_test_params *test_params = &ts_test->test_params; + u16 self_capdata, short_die_num = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *) ts_test->ts; + + + size = SHORT_CELL_SIZE(MAX_SEN_NUM); /* 4 + MAX_SEN_NUM * 2 + 2; */ + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + TPD_INFO("Failed to alloc memory\n"); + return THP_AFE_INSPECT_EOTHER; + } + + /* drv&drv shortcircut check */ + data_reg = SEN_SEN_SELFCODE_REG; + for (i = 0; i < short_ch_num; i++) { + ret = touch_i2c_read_block_u32(chip_info->client ,data_reg, size, data_buf); + if (ret) { + TPD_INFO("Failed read Sen-to-Sen short rawdata\n"); + err |= THP_AFE_INSPECT_ESPI; + break; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("Sen-to-Sen adc data checksum error\n"); + //NLOGI_ARRAY(data_buf, size); + TPD_INFO("%s: data_buf:%*ph " ,__func__,size,data_buf); + err |= THP_AFE_INSPECT_ESPI; + break; + } + + r_threshold = test_params->r_sen_sen_threshold; + short_die_num = le16_to_cpup((__le16 *)&data_buf[0]); + if (short_die_num >= MAX_SEN_NUM) { + TPD_INFO("invalid short pad num:%d\n", short_die_num); + continue; + } + + /* TODO: j start position need recheck */ + self_capdata = le16_to_cpup((__le16 *)&data_buf[2]); + if (self_capdata == 0xffff || self_capdata == 0) { + TPD_INFO("invalid self_capdata:0x%x\n", self_capdata); + continue; + } + + for (j = short_die_num + 1; j < MAX_SEN_NUM; j++) { + adc_signal = le16_to_cpup((__le16 *)&data_buf[4 + j * 2]); + if (adc_signal < test_params->short_threshold) + continue; + + short_r = SEN_TO_SEN_R(self_capdata, adc_signal); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(test_params, short_die_num); + slave_pin_num = map_die2pin(test_params, j); + if (master_pin_num == 0xFF || slave_pin_num == 0xFF) { + TPD_INFO("WARNNING invalid pin"); + continue; + } + TPD_INFO("short circut:R=%dK,R_Threshold=%dK\n", + short_r, r_threshold); + TPD_INFO("%s%d--%s%d shortcircut\n", + (master_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err |= THP_AFE_INSPECT_ESHORT; + } + } + data_reg += size; + } + + if (data_buf != NULL) { + kfree(data_buf); + data_buf = NULL; + } + return err; +} + +#define DRV_SEN_SELFCODE_REG 0x11712 +static int gdix_check_tx_rx_shortcircut(struct goodix_ts_test *ts_test, u8 short_ch_num) +{ + int ret = 0, err = 0; + u32 r_threshold = 0, short_r = 0; + int size = 0, i = 0, j = 0; + u16 adc_signal = 0; + u8 master_pin_num, slave_pin_num; + u8 *data_buf = NULL; + uint32_t data_reg; + // struct short_record temp_short_info; + struct ts_test_params *test_params = &ts_test->test_params; + u16 self_capdata, short_die_num = 0; + struct chip_data_brl *chip_info = (struct chip_data_brl *) ts_test->ts; + + size = SHORT_CELL_SIZE(MAX_DRV_NUM); /* 4 + MAX_SEN_NUM * 2 + 2; */ + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + TPD_INFO("Failed to alloc memory\n"); + return THP_AFE_INSPECT_EOTHER; + } + + /* drv&sen shortcircut check */ + data_reg = DRV_SEN_SELFCODE_REG; + for (i = 0; i < short_ch_num; i++) { + ret = touch_i2c_read_block_u32(chip_info->client ,data_reg, size, data_buf); + if (ret) { + TPD_INFO("Failed read Drv-to-Sen short rawdata\n"); + err |= THP_AFE_INSPECT_ESPI; + break; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("Drv-to-Sen adc data checksum error\n"); + //NLOGI_ARRAY(data_buf, size); + TPD_INFO("%s: data_buf:%*ph " ,__func__,size,data_buf); + err |= THP_AFE_INSPECT_ESPI; + break; + } + + r_threshold = test_params->r_drv_sen_threshold; + short_die_num = le16_to_cpup((__le16 *)&data_buf[0]); + if (short_die_num >= MAX_SEN_NUM) { + TPD_INFO("invalid short pad num:%d\n", short_die_num); + continue; + } + + /* TODO: j start position need recheck */ + self_capdata = le16_to_cpup((__le16 *)&data_buf[2]); + if (self_capdata == 0xffff || self_capdata == 0) { + TPD_INFO("invalid self_capdata:0x%x\n", self_capdata); + continue; + } + + for (j = 0; j < MAX_DRV_NUM; j++) { + adc_signal = le16_to_cpup((__le16 *)&data_buf[4 + j * 2]); + + if (adc_signal < test_params->short_threshold) + continue; + + short_r = SEN_TO_DRV_R(self_capdata, adc_signal); + if (short_r < r_threshold) { + master_pin_num = map_die2pin(test_params, short_die_num); + slave_pin_num = map_die2pin(test_params, j + MAX_SEN_NUM); + if (master_pin_num == 0xFF || slave_pin_num == 0xFF) { + TPD_INFO("WARNNING invalid pin"); + continue; + } + TPD_INFO("short circut:R=%dK,R_Threshold=%dK\n", + short_r, r_threshold); + TPD_INFO("%s%d--%s%d shortcircut\n", + (master_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (master_pin_num & ~DRV_CHANNEL_FLAG), + (slave_pin_num & DRV_CHANNEL_FLAG) ? "DRV" : "SEN", + (slave_pin_num & ~DRV_CHANNEL_FLAG)); + err |= THP_AFE_INSPECT_ESHORT; + } + } + data_reg += size; + } + + if (data_buf != NULL) { + kfree(data_buf); + data_buf = NULL; + } + return err; +} + + +#define DIFF_CODE_DATA_REG 0x11F72 +static int gdix_check_gndvdd_shortcircut(struct goodix_ts_test *ts_test) +{ + int ret = 0, err = 0; + int size = 0, i = 0; + u16 adc_signal = 0; + u8 *data_buf = NULL; + struct chip_data_brl *chip_info = (struct chip_data_brl *) ts_test->ts; + + + size = (MAX_DRV_NUM + MAX_SEN_NUM) * 2 + 2; + data_buf = kzalloc(size, GFP_KERNEL); + if (!data_buf) { + TPD_INFO("Failed to alloc memory\n"); + return THP_AFE_INSPECT_EOTHER; + } + /* read diff code, diff code will be used to calculate + * resistance between channel and GND */ + ret = touch_i2c_read_block_u32(chip_info->client ,DIFF_CODE_DATA_REG, size, data_buf); /* DIFF_CODE_REG 0xA97A */ + if (ret < 0) { + TPD_INFO("Failed read to-gnd rawdata\n"); + err |= THP_AFE_INSPECT_ESPI; + goto err_out; + } + + if (checksum_cmp(data_buf, size, CHECKSUM_MODE_U8_LE)) { + TPD_INFO("diff code checksum error\n"); + //NLOGI_ARRAY(data_buf, size); + TPD_INFO("%s: data_buf:%*ph " ,__func__,(MAX_DRV_NUM + MAX_SEN_NUM) * 2 + 2,data_buf); + err |= THP_AFE_INSPECT_ESPI; + goto err_out; + } + + for (i = 0; i < MAX_DRV_NUM + MAX_SEN_NUM; i++) { + adc_signal = le16_to_cpup((__le16 *)&data_buf[i * 2]); + ret = gdix_check_resistance_to_gnd(&ts_test->test_params, + adc_signal, i); + if (ret != THP_AFE_INSPECT_OK) { + TPD_INFO("Resistance to-gnd/vdd short\n"); + err |= ret; + } + } + +err_out: + if (data_buf != NULL) { + kfree(data_buf); + data_buf = NULL; + } + return err; +} + +/***************************************/ +typedef struct __attribute__((packed)) { + uint8_t result; + uint8_t drv_drv_num; + uint8_t sen_sen_num; + uint8_t drv_sen_num; + uint8_t drv_gnd_avdd_num; + uint8_t sen_gnd_avdd_num; + uint16_t checksum; +} test_result_t; + +/***************************************/ +#define TEST_RESULT_REG 0x10410 +#define TEST_CHANNEL_MAP_REG 0x10410 + + +static int gdix_shortcircut_analysis(struct goodix_ts_test *ts_test) +{ + int ret = 0, err = 0; + test_result_t test_result = {0}; + struct chip_data_brl *chip_info = (struct chip_data_brl *) ts_test->ts; + + + TPD_INFO(">>>>>start analysis test result"); + ret = touch_i2c_read_block_u32(chip_info->client,TEST_RESULT_REG, sizeof(test_result),(u8 *)&test_result); + if (ret < 0) { + TPD_INFO("Read TEST_RESULT_REG falied\n"); + return THP_AFE_INSPECT_ESPI; + } + + if (checksum_cmp((uint8_t*)&test_result, sizeof(test_result), CHECKSUM_MODE_U8_LE)) { + TPD_INFO("shrot result checksum err\n"); + //NLOGI_ARRAY((uint8_t*)&test_result, sizeof(test_result)); + TPD_INFO("%s: test_result:%*ph " ,__func__,8,(uint8_t*)&test_result); + return THP_AFE_INSPECT_EOTHER; + } + + if (!(test_result.result & 0x0F)) { + TPD_INFO(">>>>>No shortcircut\n"); + return THP_AFE_INSPECT_OK; + } + + TPD_INFO("short flag 0x%02x, drv&drv:%d, sen&sen:%d, drv&sen:%d, drv/GNDVDD:%d, sen/GNDVDD:%d\n", test_result.result, test_result.drv_drv_num, test_result.sen_sen_num, + test_result.drv_sen_num, test_result.drv_gnd_avdd_num, test_result.sen_gnd_avdd_num); + + /* get channel map */ + // ret = thp_spi_read(TEST_CHANNEL_MAP_REG, (uint8_t *)&(ts_test->test_params.channel_map), + // sizeof(ts_test->test_params.channel_map)); + // if (ret) { + // NLOGE("failed get channel map info"); + // return THP_AFE_INSPECT_ESPI; + // } + // if (checksum_cmp((uint8_t *)&(ts_test->test_params.channel_map), sizeof(ts_test->test_params.channel_map), CHECKSUM_MODE_U8)) { + // NLOGE("channel map checksum error"); + // NLOGI_ARRAY((uint8_t *)&(ts_test->test_params.channel_map), sizeof(ts_test->test_params.channel_map)); + // return THP_AFE_INSPECT_EOTHER; + // } + + if (test_result.drv_drv_num) + err |= gdix_check_tx_tx_shortcircut(ts_test, test_result.drv_drv_num); + if (test_result.sen_sen_num) + err |= gdix_check_rx_rx_shortcircut(ts_test, test_result.sen_sen_num); + if (test_result.drv_sen_num) + err |= gdix_check_tx_rx_shortcircut(ts_test, test_result.drv_sen_num); + if (test_result.drv_gnd_avdd_num || test_result.sen_gnd_avdd_num) + err |= gdix_check_gndvdd_shortcircut(ts_test); + + TPD_INFO(">>>>>short check return 0x%x", err); + return err; +} + + + +static int goodix_do_short_test(struct goodix_ts_test *ts_test) +{ + int ret; + int retry; + uint16_t test_time = 0; + //fw_info_t *fw_info = ts_test->fw_info; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + struct goodix_ts_cmd test_parm_cmd ; + struct goodix_ts_cmd tmp_cmd ; + + + usleep_range(2000, 2100); + ret = touch_i2c_read_block_u32(chip_info->client,SHORT_TEST_TIME_REG,2, (uint8_t *)&test_time); + if (ret) { + TPD_INFO("failed get short test time info, default %dms", DEFAULT_TEST_TIME_MS); + test_time = DEFAULT_TEST_TIME_MS; + } else { + test_time = le16_to_cpu(test_time); + test_time /= 10; /* convert to ms */ + if (test_time > MAX_TEST_TIME_MS) { + TPD_INFO("test time too long %d > %d",test_time, MAX_TEST_TIME_MS); + test_time = MAX_TEST_TIME_MS; + } + TPD_INFO("get test time %dms", test_time); + } + + test_parm_cmd.len = 0x0A; + test_parm_cmd.cmd = INSPECT_PARAM_CMD; + test_parm_cmd.data[0] = DFT_SHORT_THRESHOLD & 0xFF; + test_parm_cmd.data[1] = (DFT_SHORT_THRESHOLD >> 8) & 0xFF; + + test_parm_cmd.data[2] = DFT_DIFFCODE_SHORT_THRESHOLD & 0xFF; + test_parm_cmd.data[3] = (DFT_DIFFCODE_SHORT_THRESHOLD >> 8) & 0xFF; + + test_parm_cmd.data[4] = DFT_ADC_DUMP_NUM & 0xFF; + test_parm_cmd.data[5] = (DFT_ADC_DUMP_NUM >> 8) & 0xFF; + goodix_append_checksum(&(test_parm_cmd.buf[2]), 8, CHECKSUM_MODE_U8_LE); + TPD_INFO("%s: test_parm_cmd.buf:%*ph " ,__func__,12,test_parm_cmd.buf); + + ret = touch_i2c_write_block_u32(chip_info->client,SHORT_FW_CMD_REG,12,test_parm_cmd.buf); + if (ret) { + TPD_INFO("failed send short test param %d", ret); + return ret; + } + retry = GTX8_RETRY_NUM(10); + do { + ret = touch_i2c_read_block_u32(chip_info->client ,SHORT_FW_CMD_REG, sizeof(tmp_cmd.buf), tmp_cmd.buf); + if (!ret && tmp_cmd.ack == INSPECT_CMD_ACK_DONE) + break; + TPD_INFO("ack not ready 0x%x", tmp_cmd.ack); + //NLOGI_ARRAY(tmp_cmd.buf, sizeof(tmp_cmd.buf)); + //TPD_INFO("%s: tmp_cmd.buf:%*ph " ,__func__,sizeof(tmp_cmd.buf),test_parm_cmd.buf); + usleep_range(1000,1100); + } while (--retry); + + if (tmp_cmd.ack != INSPECT_CMD_ACK_DONE) { + TPD_INFO("failed get ack ready flag ack 0x%x != 0x%x", + tmp_cmd.ack, INSPECT_CMD_ACK_DONE); + return -EINVAL; + } + TPD_INFO(">>>>>success send short test params"); + /* check test result */ + msleep(test_time); + retry = GTX8_RETRY_NUM(50); + do { + ret = touch_i2c_read_block_u32(chip_info->client ,SHORT_FW_CMD_REG, sizeof(tmp_cmd.buf), tmp_cmd.buf); + if (!ret && tmp_cmd.state== INSPECT_CMD_STATUS_FINISH) + break; + TPD_INFO("short test ack 0x%x status 0x%x", tmp_cmd.ack, tmp_cmd.state); + usleep_range(50000,51000); + } while (--retry); + + if (tmp_cmd.state== INSPECT_CMD_STATUS_FINISH) { + TPD_INFO(">>>>>test finished"); + return 0; + } + TPD_INFO(">>>>>test status error"); + return -EINVAL; +} + + +/**************************************************/ +/* short test */ +static int gdix_short_test_prepare(struct goodix_ts_test *ts_test) +{ + int ret; + int retry; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + struct goodix_fw_version fw_ver; + struct goodix_ts_cmd fw_switch_cmd ; + + fw_switch_cmd.len = 0x04; + fw_switch_cmd.cmd = INSPECT_FW_SWITCH_CMD; + //goodix_append_checksum(&(fw_switch_cmd.buf[2]), 2, CHECKSUM_MODE_U8_LE); + //TPD_INFO("%s: fw_switch_cmd.buf:%*ph " ,__func__,6,fw_switch_cmd.buf); + //TPD_INFO("%s: cmd_addr:0x%4x\n " ,__func__,chip_info->ic_info.misc.cmd_addr); + + retry = GTX8_RETRY_NUM(5); + do { + /* + ret = touch_i2c_write_block_u32(chip_info->client,chip_info->ic_info.misc.cmd_addr,6,fw_switch_cmd.buf); + if (ret) { + TPD_INFO("failed send short FW switch cmd %d", ret); + return ret; + } + */ + if ( brl_send_cmd(chip_info, &fw_switch_cmd) != 0) + TPD_INFO("send short test cmd fail---by benson"); + usleep_range(30000,31000); + msleep(100); + /* + static int brl_read_version(struct chip_data_brl *chip_info, + struct goodix_fw_version *version) + */ + ret = brl_read_version(chip_info,&fw_ver); + if (ret) { + TPD_INFO("failed get fw version, retry %d", retry); + } else { + if (memcmp(&(fw_ver.patch_pid[3]), TEST_FW_PID, strlen(TEST_FW_PID))) { + TPD_INFO("patch ID dismatch %s != %s", fw_ver.patch_pid, + TEST_FW_PID); + ret = -EINVAL; + } + } + } while (ret && --retry); + + if (ret) { + TPD_INFO("faild switch to short test firmware, %d", ret); + return ret; + } + + TPD_INFO(">>>>>success switch to short firmware"); + return goodix_do_short_test(ts_test); +} + + + +/* gdix_test_params_init + * + * preparation before tp test + */ +static int gdix_test_params_init(struct goodix_ts_test *ts_test) +{ + + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + struct ts_test_params *test_params = &ts_test->test_params; + + test_params->max_drv_num = MAX_DRV_NUM; + test_params->max_sen_num = MAX_SEN_NUM; + test_params->sen_num =chip_info->ic_info.parm.sen_num; //ts_test->fw_info->sen_num; + test_params->drv_num = chip_info->ic_info.parm.drv_num; //ts_test->fw_info->drv_num; + + test_params->drv_map = gt9897_drv_map; + test_params->sen_map = gt9897_sen_map; + + test_params->short_threshold = gt9897_short_parms[0]; + test_params->r_drv_drv_threshold = gt9897_short_parms[1]; + test_params->r_drv_sen_threshold = gt9897_short_parms[2]; + test_params->r_sen_sen_threshold = gt9897_short_parms[3]; + test_params->r_drv_gnd_threshold = gt9897_short_parms[4]; + test_params->r_sen_gnd_threshold = gt9897_short_parms[5]; + test_params->avdd_value = gt9897_short_parms[6]; + + TPD_INFO("short test sen_num %d, drv_num %d\n", ts_test->test_params.sen_num, ts_test->test_params.drv_num); + //if (ts_test->test_params.sen_num > ts_test->test_params.max_sen_num || + // ts_test->test_params.drv_num > ts_test->test_params.max_drv_num) { + if (ts_test->test_params.sen_num > MAX_SEN_PIN_NUM || + ts_test->test_params.drv_num > MAX_DRV_PIN_NUM) { + TPD_INFO("invalied sensor and driver number\n"); + return -1; + } + return 0; +} + + + +/****************add by benson********************************** + int gdix_shortcircut_test(fw_info_t *fw_info) + + + **************************************************************/ +unsigned long long debug_ret = 0; + +static int goodix_shortcircut_test(struct goodix_ts_test *ts_test) +{ + int ret = 0 ; + struct chip_data_brl *chip_info = (struct chip_data_brl *)ts_test->ts; + + TPD_INFO("===========short test in==============\n"); + + + ts_test->test_result[GTP_SHORT_TEST] = GTP_TEST_PASS; + // ts_test.fw_info = fw_info; + + ret = gdix_test_params_init(ts_test); + if (ret < 0) { + TPD_INFO("Failed init test parameters\n"); + ts_test->test_result[GTP_SHORT_TEST] = SYS_SOFTWARE_REASON; + debug_ret |= 0xFF00000000000000; + return THP_AFE_INSPECT_EOTHER; + } + + ret = gdix_short_test_prepare(ts_test); + if (ret != THP_AFE_INSPECT_OK) { + TPD_INFO("Failed do short test\n"); + ts_test->test_result[GTP_SHORT_TEST] = SYS_SOFTWARE_REASON; + goto finish_test; + } + + ret = gdix_shortcircut_analysis(ts_test); + if (ret) { + /*TODO debug return value 0F for Rest Pin test */ + ts_test->test_result[GTP_SHORT_TEST] = GTP_PANEL_REASON; + debug_ret |= 0x2F0000; + + } +finish_test: + /*reset IC*/ + TPD_INFO("short test finish, ret 0x%x\n", ret); + goodix_reset(chip_info); + return ret; + +} + + +/*************************************************************/ + + +static void goodix_put_test_result(struct goodix_ts_test *ts_test) +{ + uint8_t data_buf[64]; + struct goodix_testdata *p_testdata; + int i; + /*save test fail result*/ + struct timespec now_time; + struct rtc_time rtc_now_time; + mm_segment_t old_fs; + uint8_t file_data_buf[128]; + struct file *filp; + + p_testdata = ts_test->p_testdata; + + for (i = 0; i < MAX_TEST_ITEMS; i++) { + /* if have tested, show result */ + if (ts_test->test_result[i]) { + if (GTP_TEST_PASS == ts_test->test_result[i]) { + } else if(GTP_PANEL_REASON == ts_test->test_result[i]) { + ts_test->error_count ++; + } else if(SYS_SOFTWARE_REASON == ts_test->test_result[i]) { + ts_test->error_count ++; + } + } + TPD_INFO("test_result_info %s[%d]%d\n", test_item_name[i], i, ts_test->test_result[i]); + } + //step2: create a file to store test data in /sdcard/Tp_Test + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + //if test fail,save result to path:/sdcard/TpTestReport/screenOn/NG/ + if(ts_test->error_count) { + snprintf(file_data_buf, 128, "/sdcard/TpTestReport/screenOn/NG/tp_testlimit_%02d%02d%02d-%02d%02d%02d-fail-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + } else { + snprintf(file_data_buf, 128, "/sdcard/TpTestReport/screenOn/OK/tp_testlimit_%02d%02d%02d-%02d%02d%02d-pass-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + + } + old_fs = get_fs(); + set_fs(KERNEL_DS); + ksys_mkdir("/sdcard/TpTestReport", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn/NG", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn/OK", 0666); + filp = filp_open(file_data_buf, O_RDWR | O_CREAT, 0644); + if (IS_ERR(filp)) { + TPD_INFO("Open log file '%s' failed. %ld\n", file_data_buf, PTR_ERR(filp)); + set_fs(old_fs); + /*add for *#899# test for it can not acess sdcard*/ + } + p_testdata->fp = filp; + p_testdata->pos = 0; + + memset(data_buf, 0, sizeof(data_buf)); + if (ts_test->rawdata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "%s\n", "[RAW DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->rawdata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "%d,", ts_test->rawdata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + if (!((i + 1) % p_testdata->RX_NUM) && (i != 0)) { + snprintf(data_buf, 64, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + } + } + if (ts_test->noisedata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s\n", "[NOISE DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->noisedata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "%d,", ts_test->noisedata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + if (!((i + 1) % p_testdata->RX_NUM) && (i != 0)) { + snprintf(data_buf, 64, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + } + } + + if (ts_test->self_noisedata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s\n", "[SELF NOISE DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->self_noisedata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "%d,", ts_test->self_noisedata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + if (ts_test->self_rawdata.size) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s\n", "[SELF RAW DATA]"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + for (i = 0; i < ts_test->self_rawdata.size; i++) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "%d,", ts_test->self_rawdata.data[i]); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + sprintf(data_buf, "\n"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } + + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "TX:%d,RX:%d\n", p_testdata->TX_NUM, p_testdata->RX_NUM); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "Img version:%lld,device version:%lld\n", p_testdata->TP_FW, ts_test->device_tp_fw); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + + for (i = 0; i < MAX_TEST_ITEMS; i++) { + /* if have tested, show result */ + if (ts_test->test_result[i]) { + if (GTP_TEST_PASS == ts_test->test_result[i]) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s %d:%s\n", test_item_name[i], i, "pass"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + } + } else if(GTP_PANEL_REASON == ts_test->test_result[i]) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s %d:%s\n", test_item_name[i], i, "NG:PANEL REASON"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + seq_printf(ts_test->p_seq_file, "%s", data_buf); + } + } else if(SYS_SOFTWARE_REASON == ts_test->test_result[i]) { + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + snprintf(data_buf, 64, "\n%s %d:%s\n", test_item_name[i], i, "NG:SOFTWARE_REASON"); + vfs_write(p_testdata->fp, data_buf, strlen(data_buf), &p_testdata->pos); + seq_printf(ts_test->p_seq_file, "%s", data_buf); + } + } + } + } + + if (!IS_ERR_OR_NULL(p_testdata->fp)) { + filp_close(p_testdata->fp, NULL); + set_fs(old_fs); + } + TPD_INFO("%s exit\n", __func__); + return; +} + +static void goodix_auto_test(struct seq_file *s, void *chip_data, struct goodix_testdata *p_testdata) +{ + int ret = 0; + struct goodix_ts_test *gts_test = NULL; + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + struct goodix_fw_version *ver_info = &chip_info->ver_info; + u16 *p_noisedata = NULL; + u16 *p_rawdata = NULL; + u16 *p_self_rawdata = NULL; + u16 *p_self_noisedata = NULL; + u32 fw_ver = 0; + u8 cfg_ver = 0; + + TPD_INFO("%s: enter\n", __func__); + + if (!chip_data) { + TPD_INFO("%s: chip_data is NULL\n", __func__); + return; + } + if (!p_testdata) { + TPD_INFO("%s: goodix_testdata is null\n", __func__); + return; + } + + gts_test = kzalloc(sizeof(struct goodix_ts_test), GFP_KERNEL); + if (!gts_test) { + TPD_INFO("%s: goodix_testdata is null\n", __func__); + seq_printf(s, "1 error(s).\n"); + return; + } + + p_rawdata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM * p_testdata->RX_NUM), GFP_KERNEL); + if (!p_rawdata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + p_noisedata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM * p_testdata->RX_NUM), GFP_KERNEL); + if (!p_noisedata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + + p_self_rawdata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM + p_testdata->RX_NUM), GFP_KERNEL); + if (!p_self_rawdata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + p_self_noisedata = kzalloc(sizeof(u16) * (p_testdata->TX_NUM + p_testdata->RX_NUM), GFP_KERNEL); + if (!p_self_noisedata) { + TPD_INFO("Failed to alloc rawdata info memory\n"); + gts_test->error_count ++; + ret = -1; + goto exit_finish; + } + TPD_INFO("%s: alloc mem:%ld\n", __func__, sizeof(struct goodix_ts_test) + 4 * (sizeof(u16) * (p_testdata->TX_NUM * p_testdata->RX_NUM))); + + gts_test->p_seq_file = s; + gts_test->ts = chip_info; + gts_test->p_testdata = p_testdata; + + gts_test->rawdata.data = p_rawdata; + gts_test->noisedata.data = p_noisedata; + gts_test->self_rawdata.data = p_self_rawdata; + gts_test->self_noisedata.data = p_self_noisedata; + + goodix_intgpio_test(gts_test); + ret = goodix_tptest_prepare(gts_test); + if (ret) { + TPD_INFO("%s: Failed parse test peremeters, exit test\n", __func__); + gts_test->error_count ++; + goto exit_finish; + } + TPD_INFO("%s: TP test prepare OK\n", __func__); + + goodix_print_test_params(gts_test); + + goodix_test_noisedata(gts_test); /*3F 7F test*/ + goodix_capacitance_test(gts_test); /* 1F 2F 6F test*/ + + goodix_shortcircut_test(gts_test); /* 5F test */ + goodix_print_testdata(gts_test); + goodix_tptest_finish(gts_test); + + /*read device fw version*/ + fw_ver = be32_to_cpup((__be32 *)&ver_info->patch_vid[0]); + cfg_ver = chip_info->ic_info.version.config_version; + gts_test->device_tp_fw = cfg_ver | (fw_ver & 0xFF) << 8; + goodix_put_test_result(gts_test); + +exit_finish: + seq_printf(s, "imageid = %lld, deviceid = %lld\n", p_testdata->TP_FW, gts_test->device_tp_fw); + TPD_INFO("imageid= %lld, deviceid= %lld\n", p_testdata->TP_FW, gts_test->device_tp_fw); + seq_printf(s, "%d error(s). %s\n", gts_test->error_count, gts_test->error_count ? "" : "All test passed."); + TPD_INFO(" TP auto test %d error(s). %s\n", gts_test->error_count, gts_test->error_count ? "" : "All test passed."); + TPD_INFO("%s exit:%d\n", __func__, ret); + if (p_rawdata) { + kfree(p_rawdata); + p_rawdata = NULL; + } + if (p_noisedata) { + kfree(p_noisedata); + p_noisedata = NULL; + } + if (p_self_rawdata) { + kfree(p_self_rawdata); + p_self_rawdata = NULL; + } + if (p_self_noisedata) { + kfree(p_self_noisedata); + p_self_noisedata = NULL; + } + if (gts_test) { + kfree(gts_test); + gts_test = NULL; + } + return; +} +/*************** End of atuo test func***************************/ + +static int goodix_set_health_info_state (void *chip_data, uint8_t enable) +{ + int ret = 0; + + struct chip_data_brl *chip_info = (struct chip_data_brl *)chip_data; + + + TPD_INFO("%s, enable : %d\n", __func__, enable); + if (enable) { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_DEBUG, 0x55); + ret |= goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_DOWN_DELTA, 0x55); + TPD_INFO("%s: enable debug log %s\n", __func__, ret < 0 ? "failed" : "success"); + } else { + ret = goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_DEBUG, 0x00); + ret |= goodix_send_cmd_simple_onedata(chip_info, GTP_CMD_DOWN_DELTA, 0x55); + TPD_INFO("%s: disable debug log %s\n", __func__, ret < 0 ? "failed" : "success"); + } + + return ret; +} + +static int goodix_get_health_info_state (void *chip_data) +{ + TPD_INFO("%s enter\n", __func__); + return 0; +} + +struct goodix_proc_operations goodix_brl_proc_ops = { + .goodix_config_info_read = goodix_config_info_read, + .auto_test = goodix_auto_test, + .set_health_info_state = goodix_set_health_info_state, + .get_health_info_state = goodix_get_health_info_state, +}; + +/*********** Start of I2C Driver and Implementation of it's callbacks*************************/ +static int goodix_tp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct chip_data_brl *chip_info = NULL; + struct touchpanel_data *ts = NULL; + int ret = -1; + + TPD_INFO("%s is called\n", __func__); + + if (tp_register_times > 0) { + TPD_INFO("TP driver have success loaded %d times, exit\n", tp_register_times); + return -1; + } + + /* 1. Alloc chip_info */ + chip_info = kzalloc(sizeof(struct chip_data_brl), GFP_KERNEL); + if (chip_info == NULL) { + TPD_INFO("chip info kzalloc error\n"); + ret = -ENOMEM; + return ret; + } + + /* 2. Alloc common ts */ + ts = common_touch_data_alloc(); + if (ts == NULL) { + TPD_INFO("ts kzalloc error\n"); + goto ts_malloc_failed; + } + + /* 3. alloc touch data space */ + chip_info->touch_data = kzalloc(MAX_GT_IRQ_DATA_LENGTH, GFP_KERNEL); + if (chip_info->touch_data == NULL) { + TPD_INFO("touch_data kzalloc error\n"); + goto err_register_driver; + } + chip_info->edge_data = kzalloc(MAX_GT_EDGE_DATA_LENGTH, GFP_KERNEL); + if (chip_info->edge_data == NULL) { + TPD_INFO("edge_data kzalloc error\n"); + goto err_touch_data_alloc; + } + + /* 4. bind client and dev for easy operate */ + chip_info->client = client; + chip_info->goodix_ops = &goodix_brl_proc_ops; + ts->debug_info_ops = &debug_info_proc_ops; + ts->client = client; + ts->irq = client->irq; + ts->dev = &client->dev; + ts->chip_data = chip_info; + chip_info->hw_res = &ts->hw_res; + i2c_set_clientdata(client, ts); + + /* 5. file_operations callbacks binding */ + ts->ts_ops = &brl_goodix_ops; + + /* 6. register common touch device*/ + ret = register_common_touch_device(ts); + if (ret < 0) { + goto err_edge_data_alloc; + } + chip_info->kernel_grip_support = ts->kernel_grip_support; + + /* 8. create goodix tool node */ + gtx8_init_tool_node(ts); + + /* 9. create goodix debug files */ + Goodix_create_proc(ts, chip_info->goodix_ops); + + goodix_esd_check_enable(chip_info, true); + + TPD_INFO("%s, probe normal end\n", __func__); + + return 0; + +err_edge_data_alloc: + if (chip_info->edge_data) { + kfree(chip_info->edge_data); + } + chip_info->edge_data = NULL; + +err_touch_data_alloc: + if (chip_info->touch_data) { + kfree(chip_info->touch_data); + } + chip_info->touch_data = NULL; + +err_register_driver: + common_touch_data_free(ts); + ts = NULL; + +ts_malloc_failed: + kfree(chip_info); + chip_info = NULL; + ret = -1; + + TPD_INFO("%s, probe error\n", __func__); + return ret; +} + +static int goodix_tp_remove(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + + TPD_INFO("%s is called\n", __func__); + kfree(ts); + + return 0; +} + +static int goodix_i2c_suspend(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s: is called\n", __func__); + tp_i2c_suspend(ts); + + return 0; +} + +static int goodix_i2c_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s is called\n", __func__); + tp_i2c_resume(ts); + + return 0; +} + +static const struct i2c_device_id tp_id[] = { + {TPD_DEVICE, 0}, + {}, +}; + + +static struct of_device_id tp_match_table[] = { + { .compatible = "Goodix-brl", }, + { }, + /* + static struct of_device_id tp_match_table[] = { + { .compatible = TPD_DEVICE, }, + { }, + */ +}; + +static const struct dev_pm_ops tp_pm_ops = { +#ifdef CONFIG_FB + .suspend = goodix_i2c_suspend, + .resume = goodix_i2c_resume, +#endif +}; + +static struct i2c_driver tp_i2c_driver = { + .probe = goodix_tp_probe, + .remove = goodix_tp_remove, + .id_table = tp_id, + .driver = { + .name = TPD_DEVICE, + .owner = THIS_MODULE, + .of_match_table = tp_match_table, + .pm = &tp_pm_ops, + }, +}; +/******************* End of I2C Driver and It's dev_pm_ops***********************/ + +/***********************Start of module init and exit****************************/ +static int __init tp_driver_init(void) +{ + TPD_INFO("%s is called\n", __func__); + + /*if (!tp_judge_ic_match(TPD_DEVICE)) + return -1;*/ + + if (i2c_add_driver(&tp_i2c_driver) != 0) { + TPD_INFO("unable to add i2c driver.\n"); + return -1; + } + + return 0; +} + + +static void __exit tp_driver_exit(void) +{ + i2c_del_driver(&tp_i2c_driver); + + return; +} + +late_initcall(tp_driver_init); + +module_exit(tp_driver_exit); +/***********************End of module init and exit*******************************/ + +MODULE_DESCRIPTION("GTP Touchpanel Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/input/touchscreen/Goodix/GT9897/goodix_drivers_brl.h b/drivers/oneplus/input/touchscreen/Goodix/GT9897/goodix_drivers_brl.h new file mode 100755 index 0000000000000000000000000000000000000000..7623815d6bb82359dc162aff0ffa488be3176233 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/GT9897/goodix_drivers_brl.h @@ -0,0 +1,573 @@ +/************************************************************** + * Copyright (c) 2008- 2030 Oppo Mobile communication Corp.ltd. + * VENDOR_EDIT + * File : goodix_drivers_gt9886.h + * Description: header file for Goodix GT9886 driver + * Version : 1.0 + * Date : 2019-08-27 + * Author : Zengpeng.Chen@Bsp.Group.Tp + * TAG : BSP.TP.Init + * ---------------- Revision History: -------------------------- + * < author > + ****************************************************************/ + +#ifndef TOUCHPANEL_GOODIX_BRL_H +#define TOUCHPANEL_GOODIX_BRL_H + +#include +#include +#include +#include +#include +#include +#include +#include "../goodix_common.h" +#include "../gtx8_tools.h" + +#define TPD_DEVICE "Goodix-brl" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do {\ + if (LEVEL_DEBUG == tp_debug) {\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do {\ + if (LEVEL_BASIC != tp_debug) {\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }\ + }while(0) + +#define TPD_DEBUG_NTAG(a, arg...)\ + do {\ + if (tp_debug) {\ + printk(a, ##arg);\ + }\ + }while(0) + +/****************************Start of define declare****************************/ + +#define set_reg_bit(reg, pos, val) ((reg) = ((reg) & (~(1 << (pos)))) | (!!(val) << (pos))) + +#define MAX_POINT_NUM 10 //max touch point number this ic support +#define MAX_GT_IRQ_DATA_LENGTH 95 //irq data(points,key,checksum) size read from irq +#define MAX_GT_EDGE_DATA_LENGTH 50 //irq edge data read from irq + +#define MAX_GESTURE_POINT_NUM 128 //max point number of black gesture + +#define GTP_DRIVER_SEND_CFG 1 // send config to TP while initializing (for no config built in TP's flash) + +//Request type define +#define GTP_RQST_RESPONDED 0x00 +#define GTP_RQST_CONFIG 0x01 +#define GTP_RQST_FRE 0x02 +#define GTP_RQST_RESET 0x03 +#define GTP_RQST_CLOCK 0x04 +#define GTP_RQST_IDLE 0xFF + +//triger event +#define GOODIX_TOUCH_EVENT 0x80 +#define GOODIX_REQUEST_EVENT 0x40 +#define GOODIX_GESTURE_EVENT 0x20 +// TODO need confirm those event value +#define GOODIX_FINGER_PRINT_EVENT 0x08 +#define GOODIX_FINGER_STATUS_EVENT 0x02 +#define GOODIX_FINGER_IDLE_EVENT 0x04 +//config define +#define IRQ_EVENT_HEAD_LEN 8 +#define BYTES_PER_POINT 8 +#define COOR_DATA_CHECKSUM_SIZE 2 + +#define POINT_NUM_OFFSET 2 +#define IRQ_EVENT_TYPE_OFFSET 0 +#define REQUEST_EVENT_TYPE_OFFSET 2 + +#define BYTES_PER_EDGE 2 +#define TS_MAX_SENSORID 9 +#define TS_CFG_MAX_LEN 4096 +#define TS_CFG_HEAD_LEN 4 +#define TS_CFG_BAG_NUM_INDEX 2 +#define TS_CFG_BAG_START_INDEX 4 +#define GOODIX_CFG_MAX_SIZE 4096 + +//command define +#define GTP_CMD_NORMAL 0x00 +#define GTP_CMD_RAWDATA 0x01 +#define GTP_CMD_SLEEP 0x84 +#define GTP_CMD_CHARGER_ON 0x10 +#define GTP_CMD_CHARGER_OFF 0x11 +#define GTP_CMD_GESTURE_ON 0x12 +#define GTP_CMD_GESTURE_OFF 0x13 +#define GTP_CMD_CLEAR_CFG 0X55 + + +#define GTP_CMD_SHORT_TEST 0x85 +#define GTM_CMD_EDGE_LIMIT_LANDSCAPE 0x17 +#define GTM_CMD_EDGE_LIMIT_VERTICAL 0x18 +//#define GTP_CMD_ENTER_DOZE_TIME 0x1A +#define GTP_CMD_DEFULT_DOZE_TIME 0 +#define GTP_CMD_FACE_DETECT_ON 0 +#define GTP_CMD_FACE_DETECT_OFF 0 +#define GTP_CMD_FOD_FINGER_PRINT 0x14 +#define GTP_CMD_GESTURE_ENTER_IDLE 0 + +#define GTP_CMD_FINGER_PRINT_AREA 0x40 //change the finger print detect area +#define GTP_CMD_FILTER 0x41 //changer filter +#define GTP_CMD_DEBUG 0x42 +#define GTP_CMD_DOWN_DELTA 0x43 +#define GTP_CMD_GESTURE_DEBUG 0x44 +#define GTP_CMD_ENTER_GAME_MODE 0x1A +#define GTP_CMD_EXIT_GAME_MODE 0x1B +#define GTP_CMD_GESTURE_MASK 0x46 + + +/******************************************************************/ +//gesture type fw send +#define DTAP_DETECT 0xCC +#define STAP_DETECT 0x4C +#define UP_VEE_DETECT 0x76 +#define DOWN_VEE_DETECT 0x5e +#define LEFT_VEE_DETECT 0x3e +#define RIGHT_VEE_DETECT 0x63 //this gesture is C +#define RIGHT_VEE_DETECT2 0x3c //this gesture is < +#define CIRCLE_DETECT 0x6f +#define DOUSWIP_DETECT 0x48 +#define RIGHT_SLIDE_DETECT 0xAA +#define LEFT_SLIDE_DETECT 0xbb +#define DOWN_SLIDE_DETECT 0xAB +#define UP_SLIDE_DETECT 0xBA +#define M_DETECT 0x6D +#define W_DETECT 0x77 +#define FP_DOWN_DETECT 0x46 +#define FP_UP_DETECT 0x55 +//gesture define +#define GSX_KEY_DATA_LEN 42 +#define GSX_GESTURE_TYPE_LEN 32 + +/****************************Start of auto test ********************/ +#define GOODIX_RETRY_NUM_3 3 +#define GOODIX_CONFIG_REFRESH_DATA 0x01 + +#define FLOAT_AMPLIFIER 1000 +#define MAX_U16_VALUE 65535 +#define RAWDATA_TEST_TIMES 10 + +#define MAX_TEST_ITEMS 10 /* 0P-1P-2P-3P-5P total test items */ + +#define GTP_INTPIN_TEST 0 +#define GTP_CAP_TEST 1 +#define GTP_DELTA_TEST 2 +#define GTP_NOISE_TEST 3 +#define GTP_SHORT_TEST 5 +#define GTP_SELFCAP_TEST 6 +#define GTP_SELFNOISE_TEST 7 + +static char *test_item_name[MAX_TEST_ITEMS] = { + "GTP_INTPIN_TEST", + "GTP_CAP_TEST", + "GTP_DELTA_TEST", + "GTP_NOISE_TEST", + "no test", + "GTP_SHORT_TEST", + "GTP_SELFCAP_TEST", + "GTP_SELFNOISE_TEST", + "no test", + "no test", +}; + +#define GTP_TEST_PASS 1 +#define GTP_PANEL_REASON 2 +#define SYS_SOFTWARE_REASON 3 + +/* error code */ +#define NO_ERR 0 +#define RESULT_ERR -1 +#define RAWDATA_SIZE_LIMIT -2 + +/*param key word in .csv */ +#define CSV_TP_SPECIAL_RAW_MIN "specail_raw_min" +#define CSV_TP_SPECIAL_RAW_MAX "specail_raw_max" +#define CSV_TP_SPECIAL_RAW_DELTA "special_raw_delta" +#define CSV_TP_SHORT_THRESHOLD "shortciurt_threshold" +#define CSV_TP_SPECIAL_SELFRAW_MAX "special_selfraw_max" +#define CSV_TP_SPECIAL_SELFRAW_MIN "special_selfraw_min" +#define CSV_TP_SELFNOISE_LIMIT "noise_selfdata_limit" +#define CSV_TP_TEST_CONFIG "test_config" +#define CSV_TP_NOISE_CONFIG "noise_config" +#define CSV_TP_NOISE_LIMIT "noise_data_limit" + +#define MAX_DRV_NUM 21 +#define MAX_SEN_NUM 42 +static u8 gt9897_drv_map[] = {42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62}; +static u8 gt9897_sen_map[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41}; + +/****************************Start of Firmware update info********************/ + +/*mtk max i2c size is 4k*/ +#define ISP_MAX_BUFFERSIZE (1024 * 4) + +#define I2C_DATA_MAX_BUFFERSIZE (1024 * 3) + +/* cfg parse from bin */ +#define CFG_BIN_SIZE_MIN 279 +#define BIN_CFG_START_LOCAL 6 +#define MODULE_NUM 22 +#define CFG_NUM 23 +#define CFG_INFO_BLOCK_BYTES 8 +#define CFG_HEAD_BYTES 32 + +#define GOODIX_EXIST 1 +#define GOODIX_NOT_EXIST 0 + +/* GTX8 cfg name */ +#define GOODIX_NORMAL_CONFIG "normal_config" //config_type: 0x01 +#define GOODIX_TEST_CONFIG "tptest_config" //config_type: 0x00, test config +#define GOODIX_NORMAL_NOISE_CONFIG "normal_noise_config" //config_type: 0x02,normal sensitivity, use for charging +#define GOODIX_GLOVE_CONFIG "glove_config" //config_type: 0x03,high sensitivity +#define GOODIX_GLOVE_NOISE_CONFIG "glove_noise_config" //config_type: 0x04,high sensitivity, use for charging +#define GOODIX_HOLSTER_CONFIG "holster_config" //config_type: 0x05,holster +#define GOODIX_HOLSTER_NOISE_CONFIG "holster_noise_config" //config_type: 0x06,holster ,use for charging +#define GOODIX_NOISE_TEST_CONFIG "tpnoise_test_config" //config_type: 0x07,noise test config + +#define getU32(a) ((u32)getUint((u8 *)(a), 4)) +#define getU16(a) ((u16)getUint((u8 *)(a), 2)) +/****************************End of Firmware update info********************/ + +/****************************Start of config data****************************/ +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_CONFIG_MAX_LENGTH 10000 + + +struct goodix_register { + // uint16_t GTP_REG_FW_CHK_MAINSYS; /*mainsys reg used to check fw status*/ + // uint16_t GTP_REG_FW_CHK_SUBSYS; /*subsys reg used to check fw status*/ + // uint16_t GTP_REG_CONFIG_DATA; /*configure firmware*/ + // uint16_t GTP_REG_READ_COOR; /*touch state and info*/ + // uint16_t GTP_REG_PRODUCT_VER; /*product id & version*/ + // uint16_t GTP_REG_WAKEUP_GESTURE; /*gesture type*/ + // uint16_t GTP_REG_GESTURE_COOR; /*gesture point data*/ + // uint16_t GTP_REG_CMD; /*recevice cmd from host*/ + // uint16_t GTP_REG_RQST; /*request from ic*/ + // uint16_t GTP_REG_NOISE_DETECT; /*noise state*/ + // uint16_t GTP_REG_ESD_WRITE; /*esd state write*/ + // uint16_t GTP_REG_ESD_READ; /*esd state read*/ + // uint16_t GTP_REG_DEBUG; /*debug log*/ + // uint16_t GTP_REG_DOWN_DIFFDATA; /*down diff data log*/ + // uint16_t GTP_REG_EDGE_INFO; /*edge points' info:ewx/ewy/xer/yer*/ + + // uint16_t GTP_REG_RAWDATA; + // uint16_t GTP_REG_DIFFDATA; + // uint16_t GTP_REG_BASEDATA; +}; + +struct goodix_fp_coor { + u16 fp_x_coor; + u16 fp_y_coor; + u16 fp_area; +}; + +#define MAX_SCAN_FREQ_NUM 5 +#define MAX_SCAN_RATE_NUM 5 +#define MAX_FREQ_NUM_STYLUS 8 +#define MAX_STYLUS_SCAN_FREQ_NUM 6 +#pragma pack(1) +struct goodix_fw_version { + u8 rom_pid[6]; /* rom PID */ + u8 rom_vid[3]; /* Mask VID */ + u8 rom_vid_reserved; + u8 patch_pid[8]; /* Patch PID */ + u8 patch_vid[4]; /* Patch VID */ + u8 patch_vid_reserved; + u8 sensor_id; + u8 reserved[2]; + u16 checksum; +}; + +struct goodix_ic_info_version { + u8 info_customer_id; + u8 info_version_id; + u8 ic_die_id; + u8 ic_version_id; + u32 config_id; + u8 config_version; + u8 frame_data_customer_id; + u8 frame_data_version_id; + u8 touch_data_customer_id; + u8 touch_data_version_id; + u8 reserved[3]; +}; + +struct goodix_ic_info_feature { /* feature info*/ + u16 freqhop_feature; + u16 calibration_feature; + u16 gesture_feature; + u16 side_touch_feature; + u16 stylus_feature; +}; + +struct goodix_ic_info_param { /* param */ + u8 drv_num; + u8 sen_num; + u8 button_num; + u8 force_num; + u8 active_scan_rate_num; + u16 active_scan_rate[MAX_SCAN_RATE_NUM]; + u8 mutual_freq_num; + u16 mutual_freq[MAX_SCAN_FREQ_NUM]; + u8 self_tx_freq_num; + u16 self_tx_freq[MAX_SCAN_FREQ_NUM]; + u8 self_rx_freq_num; + u16 self_rx_freq[MAX_SCAN_FREQ_NUM]; + u8 stylus_freq_num; + u16 stylus_freq[MAX_FREQ_NUM_STYLUS]; +}; + +struct goodix_ic_info_misc { /* other data */ + u32 cmd_addr; + u16 cmd_max_len; + u32 cmd_reply_addr; + u16 cmd_reply_len; + u32 fw_state_addr; + u16 fw_state_len; + u32 fw_buffer_addr; + u16 fw_buffer_max_len; + u32 frame_data_addr; + u16 frame_data_head_len; + u16 fw_attr_len; + u16 fw_log_len; + u8 pack_max_num; + u8 pack_compress_version; + u16 stylus_struct_len; + u16 mutual_struct_len; + u16 self_struct_len; + u16 noise_struct_len; + u32 touch_data_addr; + u16 touch_data_head_len; + u16 point_struct_len; + u16 reserved1; + u16 reserved2; + u32 mutual_rawdata_addr; + u32 mutual_diffdata_addr; + u32 mutual_refdata_addr; + u32 self_rawdata_addr; + u32 self_diffdata_addr; + u32 self_refdata_addr; + u32 iq_rawdata_addr; + u32 iq_refdata_addr; + u32 im_rawdata_addr; + u16 im_readata_len; + u32 noise_rawdata_addr; + u16 noise_rawdata_len; + u32 stylus_rawdata_addr; + u16 stylus_rawdata_len; + u32 noise_data_addr; + u32 esd_addr; +}; + +struct goodix_ic_info { + u16 length; + struct goodix_ic_info_version version; + struct goodix_ic_info_feature feature; + struct goodix_ic_info_param parm; + struct goodix_ic_info_misc misc; +}; +#pragma pack() + +#define MAX_CMD_DATA_LEN 10 +#define MAX_CMD_BUF_LEN 16 +#pragma pack(1) +struct goodix_ts_cmd { + union { + struct { + u8 state; + u8 ack; + u8 len; + u8 cmd; + u8 data[MAX_CMD_DATA_LEN]; + }; + u8 buf[MAX_CMD_BUF_LEN]; + }; +}; +#pragma pack() + +struct config_info { + u8 goodix_int_type; + u32 goodix_abs_x_max; + u32 goodix_abs_y_max; +}; +#define MAX_STR_LEN 32 + +enum CHECKSUM_MODE { + CHECKSUM_MODE_U8_LE, + CHECKSUM_MODE_U16_LE, +}; + +/* + * struct goodix_ts_config - chip config data + * @initialized: whether intialized + * @name: name of this config + * @lock: mutex + * @reg_base: register base of config data + * @length: bytes of the config + * @delay: delay time after sending config + * @data: config data buffer + */ +struct goodix_ts_config { + unsigned int length; + char name[MAX_STR_LEN + 1]; + unsigned char data[GOODIX_CFG_MAX_SIZE]; +}; + +struct chip_data_brl { + bool halt_status; //1: need ic reset + u8 *touch_data; + u8 *edge_data; + tp_dev tp_type; + u16 *spuri_fp_touch_raw_data; + struct i2c_client *client; + struct goodix_fw_version ver_info; + struct goodix_ic_info ic_info; + struct config_info config_info; + struct goodix_register reg_info; + struct fw_update_info update_info; + struct hw_resource *hw_res; + struct goodix_proc_operations *goodix_ops; //goodix func provide for debug + struct goodix_fp_coor fp_coor_report; + struct goodix_health_info health_info; + + struct goodix_ts_config normal_cfg; + struct goodix_ts_config normal_noise_cfg; + struct goodix_ts_config test_cfg; + struct goodix_ts_config noise_test_cfg; + + bool esd_check_enabled; + bool fp_down_flag; + bool single_tap_flag; + uint8_t touch_direction; + char *p_tp_fw; + bool kernel_grip_support; + //add for healthinfo + unsigned int esd_err_count; + unsigned int send_cmd_err_count; +}; + +/** + * struct ts_test_params - test parameters + * drv_num: touch panel tx(driver) number + * sen_num: touch panel tx(sensor) number + * max_limits: max limits of rawdata + * min_limits: min limits of rawdata + * deviation_limits: channel deviation limits + * short_threshold: short resistance threshold + * r_drv_drv_threshold: resistance threshold between drv and drv + * r_drv_sen_threshold: resistance threshold between drv and sen + * r_sen_sen_threshold: resistance threshold between sen and sen + * r_drv_gnd_threshold: resistance threshold between drv and gnd + * r_sen_gnd_threshold: resistance threshold between sen and gnd + * avdd_value: avdd voltage value + */ +struct ts_test_params { + u32 rawdata_addr; + u32 noisedata_addr; + u32 self_rawdata_addr; + u32 self_noisedata_addr; + + u32 basedata_addr; + u32 max_drv_num; + u32 max_sen_num; + u32 drv_num; + u32 sen_num; + u8 *drv_map; + u8 *sen_map; + + u32 *max_limits; + u32 *min_limits; + + u32 *deviation_limits; + u32 *self_max_limits; + u32 *self_min_limits; + + u32 noise_threshold; + u32 self_noise_threshold; + u32 short_threshold; + u32 r_drv_drv_threshold; + u32 r_drv_sen_threshold; + u32 r_sen_sen_threshold; + u32 r_drv_gnd_threshold; + u32 r_sen_gnd_threshold; + u32 avdd_value; +}; + +/** + * struct ts_test_rawdata - rawdata structure + * data: rawdata buffer + * size: rawdata size + */ +struct ts_test_rawdata { + int16_t *data; + u32 size; +}; + +struct ts_test_self_rawdata { + u16 *data; + u32 size; +}; + +/** + * struct goodix_ts_test - main data structrue + * ts: goodix touch screen data + * test_config: test mode config data + * orig_config: original config data + * noise_config: noise config data + * test_param: test parameters from limit img + * rawdata: raw data structure from ic data + * noisedata: noise data structure from ic data + * self_rawdata: self raw data structure from ic data + * self_noisedata: self noise data structure from ic data + * test_result: test result string + */ +struct goodix_ts_test { + void *ts; + struct goodix_ts_config test_config; + struct goodix_ts_config orig_config; + struct goodix_ts_config noise_config; + struct ts_test_params test_params; + bool is_item_support[MAX_TEST_ITEMS]; + struct ts_test_rawdata rawdata; + struct ts_test_rawdata noisedata; + struct ts_test_self_rawdata self_rawdata; + struct ts_test_self_rawdata self_noisedata; + + struct goodix_testdata *p_testdata; + struct seq_file *p_seq_file; + /*[0][0][0][0][0].. 0 without test; 1 pass, 2 panel failed; 3 software failed */ + char test_result[MAX_TEST_ITEMS]; + int error_count; + uint64_t device_tp_fw; +}; + +struct short_record { + u32 master; + u32 slave; + u16 short_code; + u8 group1; + u8 group2; +}; + +/****************************End of struct declare***************************/ + +extern int gt8x_rawdiff_mode; + +static inline u8 checksum_u8(u8 *data, u32 size) +{ + u8 checksum = 0; + u32 i = 0; + for(i = 0; i < size; i++) { + checksum += data[i]; + } + return checksum; +} + +#endif /*TOUCHPANEL_GOODIX_BRL_H*/ diff --git a/drivers/oneplus/input/touchscreen/Goodix/Kconfig b/drivers/oneplus/input/touchscreen/Goodix/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..f5350dbd5158d939cfa1bc2393e2dd18f5b633a4 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/Kconfig @@ -0,0 +1,3 @@ + +source "drivers/oneplus/input/touchscreen/Goodix/GT9886/Kconfig" +source "drivers/oneplus/input/touchscreen/Goodix/GT9897/Kconfig" diff --git a/drivers/oneplus/input/touchscreen/Goodix/Makefile b/drivers/oneplus/input/touchscreen/Goodix/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..a3eca7a314ff46eb829f94caff00803e121fb52e --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_TOUCHPANEL_GOODIX_GT9886) += GT9886/ + +obj-y += goodix_common.o +obj-y += goodix_tool.o +obj-y += gtx8_tools.o +obj-y += GT9897/ + + +#endif diff --git a/drivers/oneplus/input/touchscreen/Goodix/goodix_common.c b/drivers/oneplus/input/touchscreen/Goodix/goodix_common.c new file mode 100755 index 0000000000000000000000000000000000000000..d1edd7587eb76e53b41dee6eaf54969441675bfc --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/goodix_common.c @@ -0,0 +1,1002 @@ +/*************************************************** + * File:goodix_common.c + * Description: + * goodix common driver + * Version:1.0: + * * + * -------------- Revision History: ----------------- + * + ***************************************************/ + +#include "goodix_common.h" + +#define TPD_DEVICE "goodix_common" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +/** + * search_for_item_offset - get each item offset form test limit fw + * @fw: pointer to fw + * @item_cnt: max item number + * @item_index: item index + * we can using this function to get item offset form index item + * Returning parameter number(success) or negative errno(failed) + */ + + + +/* i2c read/write ops for support u32 addr */ +int touch_i2c_read_block_u32(struct i2c_client *client, u32 reg, + unsigned int len, unsigned char *data) +{ + unsigned int transfer_length = 0; + unsigned int pos = 0, address = reg; + unsigned char get_buf[128], addr_buf[GOODIX_REG_ADDR_SIZE]; + int retry, r = 0; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = !I2C_M_RD, + .buf = &addr_buf[0], + .len = GOODIX_REG_ADDR_SIZE, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + } + }; + + if (likely(len < sizeof(get_buf))) { + /* code optimize, use stack memory */ + msgs[1].buf = &get_buf[0]; + } else { + msgs[1].buf = kzalloc(len, GFP_KERNEL); + if (msgs[1].buf == NULL) + return -ENOMEM; + } + + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE)) + transfer_length = I2C_MAX_TRANSFER_SIZE; + else + transfer_length = len - pos; + + msgs[0].buf[0] = (address >> 24) & 0xFF; + msgs[0].buf[1] = (address >> 16) & 0xFF; + msgs[0].buf[2] = (address >> 8) & 0xFF; + msgs[0].buf[3] = address & 0xFF; + msgs[1].len = transfer_length; + + for (retry = 0; retry < GOODIX_BUS_RETRY_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, + msgs, 2) == 2)) { + memcpy(&data[pos], msgs[1].buf, + transfer_length); + pos += transfer_length; + address += transfer_length; + break; + } + TPD_INFO("%s: I2c read retry[%d]:0x%x\n", __func__, retry + 1, reg); + msleep(20); + } + if (unlikely(retry == GOODIX_BUS_RETRY_TIMES)) { + TPD_INFO("%s, I2c read failed,dev:%02x,reg:%04x,size:%u\n", __func__, + client->addr, reg, len); + r = -EAGAIN; + goto read_exit; + } + } + +read_exit: + if (unlikely(len >= sizeof(get_buf))) + kfree(msgs[1].buf); + return r; +} + +int touch_i2c_write_block_u32(struct i2c_client *client, u32 reg, + unsigned int len, unsigned char const *data) +{ + unsigned int pos = 0, transfer_length = 0; + unsigned int address = reg; + unsigned char put_buf[128]; + int retry, r = 0; + struct i2c_msg msg = { + .addr = client->addr, + .flags = !I2C_M_RD, + }; + + if (likely(len + GOODIX_REG_ADDR_SIZE < sizeof(put_buf))) { + /* code optimize,use stack memory*/ + msg.buf = &put_buf[0]; + } else { + msg.buf = kmalloc(len + GOODIX_REG_ADDR_SIZE, GFP_KERNEL); + if (msg.buf == NULL) + return -ENOMEM; + } + + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE - + GOODIX_REG_ADDR_SIZE)) + transfer_length = I2C_MAX_TRANSFER_SIZE - + GOODIX_REG_ADDR_SIZE; + else + transfer_length = len - pos; + msg.buf[0] = (address >> 24) & 0xFF; + msg.buf[1] = (address >> 16) & 0xFF; + msg.buf[2] = (address >> 8) & 0xFF; + msg.buf[3] = address & 0xFF; + + msg.len = transfer_length + GOODIX_REG_ADDR_SIZE; + memcpy(&msg.buf[GOODIX_REG_ADDR_SIZE], + &data[pos], transfer_length); + + for (retry = 0; retry < GOODIX_BUS_RETRY_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, + &msg, 1) == 1)) { + pos += transfer_length; + address += transfer_length; + break; + } + TPD_DEBUG("I2c write retry[%d]\n", retry + 1); + msleep(20); + } + if (unlikely(retry == GOODIX_BUS_RETRY_TIMES)) { + TPD_INFO("%s: I2c write failed,dev:%02x,reg:%04x,size:%u\n", __func__, + client->addr, reg, len); + r = -EAGAIN; + goto write_exit; + } + } + +write_exit: + if (likely(len + GOODIX_REG_ADDR_SIZE >= sizeof(put_buf))) + kfree(msg.buf); + return r; +} + + + + +uint32_t search_for_item_offset(const struct firmware *fw, int item_cnt, uint8_t item_index) +{ + int i = 0; + uint32_t item_offset = 0; + struct auto_test_item_header *item_header = NULL; + uint32_t *p_item_offset = (uint32_t *)(fw->data + 16); + + /*check the matched item offset*/ + for (i = 0; i < item_cnt; i++) { + item_header = (struct auto_test_item_header *)(fw->data + p_item_offset[i]); + if (item_header->item_bit == item_index) { + item_offset = p_item_offset[i]; + TPD_INFO("p_item_offset:0X%x,i_value is:%d\n",p_item_offset[i],i); + } + } + return item_offset; +} + +/** + * getpara_for_item - get parameter from item + * @fw: pointer to fw + * @item_index: item index + * @para_num: parameter number + * we can using this function to get parameter form index item + * Returning pointer to parameter buffer + */ +int32_t *getpara_for_item(const struct firmware *fw, uint8_t item_index, uint32_t *para_num) +{ + uint32_t item_offset = 0; + int i = 0; + uint32_t item_cnt = 0; + struct auto_test_item_header *item_header = NULL; + struct auto_test_header *test_header = NULL; + int32_t *p_buffer = NULL; + test_header = (struct auto_test_header *)fw->data; + + /*step1: check item index is support or not*/ + if (!(test_header->test_item & (1 << item_index))) { + TPD_INFO("item_index:%d is not support\n", item_index); + return NULL; + } + + /*step2: get max item*/ + for (i = 0; i < 8 * sizeof(test_header->test_item); i++) { + if ((test_header->test_item >> i) & 0x01 ) { + item_cnt++; + } + } + + /*step3: find item_index offset from the limit img*/ + item_offset = search_for_item_offset(fw, item_cnt, item_index); + if (item_offset == 0) { + TPD_INFO("search for item limit offset failed\n"); + return NULL; + } + + /*step4: check the item magic is support or not*/ + item_header = (struct auto_test_item_header *)(fw->data + item_offset); + if (item_header->item_magic != Limit_MagicItem) { + TPD_INFO("test item: %d magic number(%4x) is wrong\n", item_index, item_header->item_magic); + return NULL; + } + + /*step5: get the parameter from the limit img*/ + if (item_header->para_num == 0) { + TPD_INFO("item: %d has %d no parameter\n", item_index, item_header->para_num); + return NULL; + } else { + p_buffer = (int32_t *)(fw->data + item_offset + sizeof(struct auto_test_item_header)); + for (i = 0; i < item_header->para_num; i++) { + TPD_INFO("item: %d has parameter:%d\n", item_index, p_buffer[i]); + } + } + *para_num = item_header->para_num; + return p_buffer; +} + +/** + * get_info_for_item - get all infomation from item + * @fw: pointer to fw + * @item_index: item index + * we can using this function to get infomation form index item + * Returning pointer to test_item_info buffer + */ +struct test_item_info *get_test_item_info(const struct firmware *fw, uint8_t item_index) +{ + uint32_t item_offset = 0; + int i = 0; + uint32_t item_cnt = 0; + struct auto_test_item_header *item_header = NULL; + struct auto_test_header *test_header = NULL; + int32_t *p_buffer = NULL; + + /*result: test_item_info */ + struct test_item_info *p = NULL; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return NULL; + + /*step1: check item index is support or not*/ + test_header = (struct auto_test_header *)fw->data; + if (!(test_header->test_item & (1 << item_index))) { + TPD_INFO("item_index:%d is not support\n", item_index); + goto ERROR; + } + /*step2: get max item*/ + for (i = 0; i < 8 * sizeof(test_header->test_item); i++) { + if ((test_header->test_item >> i) & 0x01 ) { + item_cnt++; + } + } + + /*step3: find item_index offset from the limit img*/ + item_offset = search_for_item_offset(fw, item_cnt, item_index); + if (item_offset == 0) { + TPD_INFO("search for item limit offset failed\n"); + goto ERROR; + } + /*get item_offset*/ + p->item_offset = item_offset; + + /*step4: check the item magic is support or not*/ + item_header = (struct auto_test_item_header *)(fw->data + item_offset); + if (item_header->item_magic != Limit_MagicItem) { + TPD_INFO("test item: %d magic number(%4x) is wrong\n", item_index, item_header->item_magic); + goto ERROR; + } + /*get item_header*/ + p->item_magic = item_header->item_magic; + p->item_size = item_header->item_size; + p->item_bit = item_header->item_bit; + p->item_limit_type = item_header->item_limit_type; + p->top_limit_offset = item_header->top_limit_offset; + p->floor_limit_offset = item_header->floor_limit_offset; + + /*step5: get the parameter from the limit img*/ + if (item_header->para_num == 0) { + TPD_INFO("item: %d has %d no parameter\n", item_index, item_header->para_num); + goto ERROR; + } else { + p_buffer = (int32_t *)(fw->data + item_offset + sizeof(struct auto_test_item_header)); + for (i = 0; i < item_header->para_num; i++) { + TPD_INFO("item: %d has parameter:%d\n", item_index, p_buffer[i]); + } + } + /*get item para number and para buffer*/ + p->para_num = item_header->para_num; + p->p_buffer = p_buffer; + + return p; + +ERROR: + if (p) { + kfree(p); + } + return NULL; +} + +void tp_kfree(void **mem) +{ + if(*mem != NULL) { + kfree(*mem); + *mem = NULL; + } +} + + +/* + * @para buf + * @ return + * function +*/ +char *goto_next_line (char *buf) +{ + //int j = 0; + +// TPD_INFO("%s --enter",__func__); + if (!buf) { + TPD_INFO("%s:the buf is null",__func__); + return 0; + } + + do { + buf =buf +1; + //TPD_INFO ("J value is :%d\n", j++); + } + while ((*buf != '\n') && (*buf != '\0')); + if(*buf == '\0') + return buf; + buf = buf +1 ; + return buf; + } + +/* +* +* +*/ +static void copy_one_line (char *copy_from,char *copy_to) +{ +// TPD_INFO("%s --enter",__func__); + + do { + *copy_to = *copy_from; + copy_to ++; + copy_from++; + } + while ( (*copy_from != '\n') && ( *copy_from != '\t') && ( *copy_from != '\0')); + *copy_to = '\n'; + } + +/* + * parse_valid_data(char *buf_start, loff_t buf_size,char *ptr, int32_t* data, int rows) + * + * + */ + +static int parse_valid_data(char *buf ,int32_t *data,int rows) +{ + int i = 0,j = 0; + char *temp_data,*token; + char rows_data[512] ; + + // TPD_INFO("%s --enter",__func__); + if (!buf) { + TPD_INFO("%s,the buf is null...\n",__func__); + return -1; + } + if (!data) { + TPD_INFO ("%s,the data is null...",__func__); + return -1; + } + + for (i = 0;i < rows;i++ ) { + memset(rows_data,0,sizeof(rows_data)); + copy_one_line(buf,rows_data); + temp_data = rows_data; + + // TPD_INFO("token size_111 is %d,%*ph",strlen(buf),6,buf); + // TPD_INFO("token size_222 is %d,%*ph",strlen(rows_data ),6,rows_data); + // TPD_INFO("token size_333 is %d,%*ph",strlen(temp_data),6,temp_data); + + while ((token = strsep(&temp_data,",\n\r\t\0"))) { + if(strlen(token) == 0) + continue; + // TPD_INFO("token size is %d,%*ph",strlen(token),6,token); + data [j] = (int32_t)simple_strtol (token,NULL,10); + //j++; + // TPD_INFO ("token data 444 :%2x,%d\n",data[j],j); + j++; + } + buf = goto_next_line (buf); + if ( !buf || (0 == strlen(buf)) ) + break; + } + return 0; +} + + static void print_csv_data(int32_t *data, int rows,int columns) + { + int i = 0 ,j = 0; + + TPD_INFO("%s --enter,rows value is :%d,columns value is :%d, data size is:%d\n ",__func__, rows,columns,sizeof(data) ); + if(!data) { + + TPD_INFO("print_csv_data is null"); + //return 0; + return; + } + + for ( i = 0; i < rows; i++ ) { + for( j = 0; j < columns;j++ ) { +// TPD_INFO("%d\n", data[i*columns + j]); + } + } + } + + + +/* + * get_test_value_from_limit - get all infomation from item + * @fw: pointer to fw + * @item_index: item index + * we can using this function to get infomation form index item + * Returning pointer to test_item_info buffer + */ + +int gt988x_parse_csvfile(const struct firmware *fw, char *target_name, int32_t *data, int rows, int columns) + { + char *ptr = NULL ,*buf = NULL; + // int ret; + + if (target_name == NULL) { + TPD_INFO("%s :target_name is null\n",__func__); + goto exit_free; + } + ptr = (char*)kzalloc (sizeof(fw->size),GFP_KERNEL); + ptr = (char*)(fw->data); + buf = strstr(ptr, target_name); + TPD_INFO("%s --enter,%*ph",__func__,60,buf); + if(buf == NULL) { + goto exit_free; + } + buf = goto_next_line(buf); + /* + if (ret < 0) { + TPD_INFO ("%s : get next line is null\n",__func__); + } + */ + + TPD_INFO("%s --enter-1,%*ph",__func__,60,buf); + if (data) { + parse_valid_data (buf,data,rows); + print_csv_data(data,rows,columns); + } +exit_free: + if(!ptr) { + kfree(ptr); + return -1; + } + return 0; + } + +void GetCirclePoints(struct Coordinate *input_points, int number, struct Coordinate *pPnts) +{ + int i = 0; + int k = 0, j = 0, m = 0, n = 0; + int max_y, min_y, max_x, min_x; + + max_y = input_points[0].y; + min_y = input_points[0].y; + max_x = input_points[0].x; + min_x = input_points[0].x; + + for (i = 0; i < number; i++) { + if (input_points[i].y > max_y) { + max_y = input_points[i].y; + k = i; + } + } + pPnts[2] = input_points[k]; + + for (i = 0; i < number; i++) { + if (input_points[i].y < min_y) { + min_y = input_points[i].y; + j = i; + } + } + pPnts[0] = input_points[j]; + + for (i = 0; i < number; i++) { + if (input_points[i].x > max_x) { + max_x = input_points[i].x; + m = i; + } + } + pPnts[3] = input_points[m]; + + for (i = 0; i < number; i++) { + if (input_points[i].x < min_x) { + min_x = input_points[i].x; + n = i; + } + } + pPnts[1] = input_points[n]; +} + +/** + * ClockWise - calculate clockwise for circle gesture + * @p: coordinate array head point. + * @n: how many points need to be calculated + * Return 1--clockwise, 0--anticlockwise, not circle, report 2 + */ +int ClockWise(struct Coordinate *p, int n) +{ + int i, j, k; + int count = 0; + long int z; + + if (n < 3) + return 1; + for (i = 0; i < n; i++) { + j = (i + 1) % n; + k = (i + 2) % n; + if ((p[i].x == p[j].x) && (p[j].x == p[j].y)) + continue; + z = (p[j].x - p[i].x) * (p[k].y - p[j].y); + z -= (p[j].y - p[i].y) * (p[k].x - p[j].x); + if (z < 0) + count--; + else if (z > 0) + count++; + } + + TPD_INFO("ClockWise count = %d\n", count); + + if (count > 0) + return 1; + else + return 0; +} + +static ssize_t tp_devices_check_read_func(struct file *file, char __user *page, size_t size, loff_t *ppos) +{ + char pagesize[64] = {0}; + int ret = 0; + struct touchpanel_data *ts = (struct touchpanel_data *)PDE_DATA(file_inode(file)); + if(!ts) + return 0; + + ret = sprintf(pagesize, "%d\n", ts->panel_data.tp_type); + ret = simple_read_from_buffer(page, size, ppos, pagesize, strlen(pagesize)); + return ret; +} + +static const struct file_operations gt1x_devices_check = { + .owner = THIS_MODULE, + .read = tp_devices_check_read_func, +}; + +static ssize_t proc_health_info_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + char page[PAGESIZE] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct goodix_proc_operations *goodix_ops; + + if (!ts) + return 0; + + goodix_ops = (struct goodix_proc_operations *)ts->private_data; + + if (!goodix_ops->get_health_info_state) + return 0; + + snprintf(page, PAGESIZE-1, "%d.\n", goodix_ops->get_health_info_state(ts->chip_data)); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_health_info_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[4] = {0}; + int temp = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct goodix_proc_operations *goodix_ops; + + if (!ts) + return count; + + goodix_ops = (struct goodix_proc_operations *)ts->private_data; + + if (!goodix_ops->set_health_info_state) + return count; + + if (count > 2) + return count; + if (copy_from_user(buf, buffer, count)) { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + if (kstrtoint(buf, 10, &temp)) + { + TPD_INFO("%s: kstrtoint error\n", __func__); + return count; + } + if (temp > 2) + return count; + + mutex_lock(&ts->mutex); + TPD_INFO("%s: value = %d\n", __func__, temp); + goodix_ops->set_health_info_state(ts->chip_data, temp); + mutex_unlock(&ts->mutex); + + return count; +} + +static const struct file_operations goodix_health_info_ops = +{ + .read = proc_health_info_read, + .write = proc_health_info_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +//proc/touchpanel/Goodix/config_version +static int gt1x_tp_config_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct goodix_proc_operations *goodix_ops; + + if(!ts) + return 0; + goodix_ops = (struct goodix_proc_operations *)(ts->private_data); + if (!goodix_ops) { + return 0; + } + if (!goodix_ops->goodix_config_info_read) { + seq_printf(s, "Not support auto-test proc node\n"); + return 0; + } + disable_irq_nosync(ts->client->irq); + mutex_lock(&ts->mutex); + + goodix_ops->goodix_config_info_read(s, ts->chip_data); + + mutex_unlock(&ts->mutex); + enable_irq(ts->client->irq); + return 0; +} + +static int proc_data_config_version_read(struct seq_file *s, void *v) + +{ + gt1x_tp_config_read_func(s, v); + return 0; +} + +static int gt1x_data_config_version_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_data_config_version_read, PDE_DATA(inode)); +} + +static const struct file_operations gt1x_tp_config_version_proc_fops = { + .owner = THIS_MODULE, + .open = gt1x_data_config_version_open, + .read = seq_read, + .release = single_release, +}; + +static ssize_t goodix_water_protect_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct goodix_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct goodix_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->goodix_water_protect_read) { + if(copy_to_user(buff, "Not support auto-test proc node\n", strlen("Not support auto-test proc node\n"))) + TPD_INFO("%s,here:%d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->goodix_water_protect_read(file, buff, len, pos); + return ret; +} + +static ssize_t goodix_water_protect_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct goodix_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct goodix_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->goodix_water_protect_write) { + TPD_INFO("Not support dd proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->goodix_water_protect_write(file, buff, len, pos); + return ret; +} + +static struct file_operations goodix_water_protect_debug_ops = { + .owner = THIS_MODULE, + .read = goodix_water_protect_read, + .write = goodix_water_protect_write, +}; + +void goodix_limit_read(struct seq_file *s, struct touchpanel_data *ts) +{ + int ret = 0, m = 0, i = 0, j = 0, item_cnt = 0; + const struct firmware *fw = NULL; + struct auto_test_header *ph = NULL; + struct auto_test_item_header *item_head = NULL; + uint32_t *p_item_offset = NULL; + int32_t *p_data32 = NULL; + + ret = request_firmware(&fw, ts->panel_data.test_limit_name, ts->dev); + if (ret < 0) { + TPD_INFO("Request firmware failed - %s (%d)\n", ts->panel_data.test_limit_name, ret); + seq_printf(s, "Request failed, Check the path\n"); + return; + } + + ph = (struct auto_test_header *)(fw->data); + p_item_offset = (uint32_t *)(fw->data + 16); + if ((ph->magic1 != 0x494D494C) || (ph->magic2 != 0x474D4954)) { + TPD_INFO("ph->magic1 is: 0x%04x, ph->magic2 is :0x%04x\n",ph->magic1,ph->magic2); + TPD_INFO("limit image is not generated\n"); + seq_printf(s, "limit image is not generated\n"); + release_firmware(fw); + return; + } + + for (i = 0; i < 8 * sizeof(ph->test_item); i++) { + if ((ph->test_item >> i) & 0x01 ) { + item_cnt++; + } + } + if (!item_cnt) { + TPD_INFO("limit image has no test item\n"); + seq_printf(s, "limit image has no test item\n"); + } + + for (m = 0; m < item_cnt; m++) { + item_head = (struct auto_test_item_header *)(fw->data + p_item_offset[m]); + if (item_head->item_magic != 0x4F50504F) { + seq_printf(s, "item: %d limit data has some problem\n", item_head->item_bit); + continue; + } + + seq_printf(s, "item %d[size %d, limit type %d, para num %d] :\n", item_head->item_bit, item_head->item_size, item_head->item_limit_type, item_head->para_num); + if (item_head->item_limit_type == LIMIT_TYPE_NO_DATA) { + seq_printf(s, "no limit data\n"); + } else if (item_head->item_limit_type == LIMIT_TYPE_CERTAIN_DATA) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "top limit data: %d\n", *p_data32); + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "floor limit data: %d\n", *p_data32); + } else if (item_head->item_limit_type == LIMIT_TYPE_MAX_MIN_DATA) { + seq_printf(s, "top data: \n"); + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + for (i = 0 ; i < (ts->hw_res.TX_NUM * ts->hw_res.RX_NUM) ; i++) { + if (i % ts->hw_res.RX_NUM == 0) + seq_printf(s, "\n[%2d] ", (i / ts->hw_res.RX_NUM)); + seq_printf(s, "%4d, ", p_data32[i]); + TPD_DEBUG("%d, ", p_data32[i]); + } + seq_printf(s, "\nfloor data: \n"); + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + for (i = 0 ; i < (ts->hw_res.TX_NUM * ts->hw_res.RX_NUM); i++) { + if (i % ts->hw_res.RX_NUM == 0) { + seq_printf(s, "\n[%2d] ", (i / ts->hw_res.RX_NUM)); + } + seq_printf(s, "%4d, ", p_data32[i]); + TPD_DEBUG("%d, ", p_data32[i]); + } + } else if (item_head->item_limit_type == IMIT_TYPE_DELTA_DATA) { + seq_printf(s, "delta data: \n"); + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + for (i = 0 ; i < (ts->hw_res.TX_NUM * ts->hw_res.RX_NUM) ; i++) { + if (i % ts->hw_res.RX_NUM == 0) { + seq_printf(s, "\n[%2d] ", (i / ts->hw_res.RX_NUM)); + } + seq_printf(s, "%4d, ", p_data32[i]); + TPD_DEBUG("%d, ", p_data32[i]); + } + } else if (item_head->item_limit_type == IMIT_TYPE_SLEFRAW_DATA) { + seq_printf(s, "top data:\n"); + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + for (i = 0 ; i < (ts->hw_res.TX_NUM + ts->hw_res.RX_NUM) ; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + TPD_DEBUG("%d, ", p_data32[i]); + } + seq_printf(s, "\nfloor data:\n"); + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + for (i = 0 ; i < (ts->hw_res.TX_NUM + ts->hw_res.RX_NUM) ; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + TPD_DEBUG("%d, ", p_data32[i]); + } + } + + p_data32 = (int32_t *)(fw->data + p_item_offset[m] + sizeof(struct auto_test_item_header)); + if (item_head->para_num) { + seq_printf(s, "parameter:"); + for (j = 0; j < item_head->para_num; j++) { + seq_printf(s, "%d, ", p_data32[j]); + } + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + } + + release_firmware(fw); +} + +static int tp_auto_test_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct goodix_proc_operations *goodix_ops; + const struct firmware *fw = NULL; + int ret = -1; + struct auto_test_header *test_head = NULL; + uint32_t *p_data32 = NULL; + + struct goodix_testdata goodix_testdata = { + .TX_NUM = 0, + .RX_NUM = 0, + .fp = NULL, + .irq_gpio = -1, + .TP_FW = 0, + .fw = NULL, + .test_item = 0, + }; + + if (!ts) + return 0; + goodix_ops = (struct goodix_proc_operations *)ts->private_data; + if (!goodix_ops) + return 0; + if (!goodix_ops->auto_test) { + seq_printf(s, "Not support auto-test proc node\n"); + return 0; + } + + //step1:disable_irq && get mutex locked + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + //step3:request test limit data from userspace + ret = request_firmware(&fw, ts->panel_data.test_limit_name, ts->dev); + if (ret < 0) { + TPD_INFO("Request firmware failed - %s (%d)\n", ts->panel_data.test_limit_name, ret); + seq_printf(s, "No limit IMG\n"); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; + } + + //step4: decode the limit image + test_head = (struct auto_test_header *)fw->data; + p_data32 = (uint32_t *)(fw->data + 16); + if ((test_head->magic1 != 0x494D494C) || (test_head->magic2 != 0x474D4954)) { + TPD_INFO("fuck_ph->magic1 is: 0x%04x\n, ph->magic2 is :0x%04x\n",test_head->magic1,test_head->magic2); + TPD_INFO("current test item: %llx\n", test_head->test_item); + TPD_INFO("limit image is not generated\n"); + seq_printf(s, "limit image is not generated\n"); + // goto OUT; + } + TPD_INFO("current test item: %llx\n", test_head->test_item); + + //init goodix_testdata + goodix_testdata.TX_NUM = ts->hw_res.TX_NUM; + goodix_testdata.RX_NUM = ts->hw_res.RX_NUM; + goodix_testdata.irq_gpio = ts->hw_res.irq_gpio; + goodix_testdata.TP_FW = ts->panel_data.TP_FW; + goodix_testdata.fw = fw; + goodix_testdata.test_item = test_head->test_item; + goodix_testdata.TP_FW = ts->panel_data.TP_FW; + + goodix_ops->auto_test(s, ts->chip_data, &goodix_testdata); + +//OUT: + + release_firmware(fw); + + //step5: return to normal mode + ts->ts_ops->reset(ts->chip_data); + operate_mode_switch(ts); + + //step6: unlock the mutex && enable irq trigger + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + + return 0; +} +static int baseline_autotest_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_auto_test_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_auto_test_proc_fops = { + .owner = THIS_MODULE, + .open = baseline_autotest_open, + .read = seq_read, + .release = single_release, +}; + +int Goodix_create_proc(struct touchpanel_data *ts, struct goodix_proc_operations *goodix_ops) +{ + int ret = 0; + struct proc_dir_entry *prEntry_tmp = NULL; + struct proc_dir_entry *prEntry_gt = NULL; + + ts->private_data = goodix_ops; + + // touchpanel_auto_test interface + prEntry_tmp = proc_create_data("baseline_test", 0666, ts->prEntry_tp, &tp_auto_test_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("TP_AUTO_TEST_ID", 0777, ts->prEntry_tp, >1x_devices_check, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("health_info_enable", 0777, ts->prEntry_tp, &goodix_health_info_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_gt = proc_mkdir("Goodix", ts->prEntry_tp); + if (prEntry_gt == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create GT TP proc entry\n", __func__); + } + + //show config and firmware id interface + prEntry_tmp = proc_create_data("config_version", 0666, prEntry_gt, >1x_tp_config_version_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("water_protect", 0666, prEntry_gt, &goodix_water_protect_debug_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create water_protect proc entry, %d\n", __func__, __LINE__); + } + + return ret; +} +EXPORT_SYMBOL(gt988x_parse_csvfile); diff --git a/drivers/oneplus/input/touchscreen/Goodix/goodix_common.h b/drivers/oneplus/input/touchscreen/Goodix/goodix_common.h new file mode 100755 index 0000000000000000000000000000000000000000..72a9d392e4d25744575fb1b16b5a6ab49953f7d0 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/goodix_common.h @@ -0,0 +1,259 @@ +/*************************************************** + * File:goodix_common.h + * VENDOR_EDIT + * Copyright(C) 2008-2012 OPPO Mobile Comm Corp., Ltd + * Description: + * goodix common driver + * Version:1.0: + * Date created:2016/09/02 + * Author: Tong.han@Bsp.Driver + * TAG: BSP.TP.Init + * * + * -------------- Revision History: ----------------- + * + ***************************************************/ + +#ifndef _TOUCHPANEL_COMMON_GOODIX_H_ +#define _TOUCHPANEL_COMMON_GOODIX_H_ + +#include +#include "../touchpanel_common.h" + +#include +#include +#include +#include +#include + +#define IS_NUM_OR_CHAR(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= '0' && (x) <= '9')) + +/****************************PART1:auto test define*************************************/ +#define Limit_MagicNum1 0x494D494C +#define Limit_MagicNum2 0x474D4954 +#define Limit_MagicItem 0x4F50504F + +struct auto_test_header { + uint32_t magic1; + uint32_t magic2; + uint64_t test_item; +}; + +struct auto_test_item_header { + uint32_t item_magic; + uint32_t item_size; + uint16_t item_bit; + uint16_t item_limit_type; + uint32_t top_limit_offset; + uint32_t floor_limit_offset; + uint32_t para_num; +}; + +/*get item information*/ +struct test_item_info { + uint32_t item_magic; + uint32_t item_size; + uint16_t item_bit; + uint16_t item_limit_type; + uint32_t top_limit_offset; + uint32_t floor_limit_offset; + uint32_t para_num; /*number of parameter*/ + int32_t *p_buffer; /*pointer to item parameter buffer*/ + uint32_t item_offset; /*item offset*/ +}; + +struct goodix_testdata { + int TX_NUM; + int RX_NUM; + + struct file *fp; + loff_t pos; + int irq_gpio; + int key_TX; + int key_RX; + uint64_t TP_FW; + const struct firmware *fw; + uint64_t test_item; +}; + +enum { + LIMIT_TYPE_NO_DATA = 0x00, //means no limit data + LIMIT_TYPE_CERTAIN_DATA = 0x01, //means all nodes limit data is a certain data + LIMIT_TYPE_MAX_MIN_DATA = 0x02, //means all nodes have it's own limit + IMIT_TYPE_DELTA_DATA = 0x03, //means all nodes have it's own limit + IMIT_TYPE_PARA_DATA = 0x04, //means all nodes have it's own limit + IMIT_TYPE_SLEFRAW_DATA = 0x05, //means all nodes have it's own limit + LIMIT_TYPE_INVALID_DATA = 0xFF, //means wrong limit data type +}; + +//test item +enum { + //TYPE_ERROR = 0x00, + TYPE_MUTUAL_RAW_OFFSET_DATA_SDC = 0x01, + TYPE_MUTUAL_RAW_DATA = 0x02, + TYPE_SELF_RAW_OFFSET_DATA_SDC = 0x03, + TYPE_MUTU_RAW_NOI_P2P = 0x04, + //TYPE_MAX = 0xFF, +}; + +//test item +enum { + TYPE_ERROR = 0x00, + TYPE_NOISE_DATA_LIMIT = 0x01, + TYPE_SHORT_THRESHOLD = 0x02, + TYPE_SPECIAL_RAW_MAX_MIN = 0x03, + TYPE_SPECIAL_RAW_DELTA = 0x04, + TYPE_NOISE_SLEFDATA_LIMIT = 0x05, + TYPE_SPECIAL_SELFRAW_MAX_MIN = 0x06, + TYPE_MAX = 0xFF, +}; + +/****************************PART2:FW Update define*************************************/ +#define FW_HEAD_SIZE 128 +#define FW_HEAD_SUBSYSTEM_INFO_SIZE 8 +#define FW_HEAD_OFFSET_SUBSYSTEM_INFO_BASE 32 +#define PACK_SIZE 256 +#define UPDATE_STATUS_IDLE 0 +#define UPDATE_STATUS_RUNNING 1 +#define UPDATE_STATUS_ABORT 2 +#define FW_SECTION_TYPE_SS51_PATCH 0x02 + +typedef enum { + GTP_RAWDATA, + GTP_DIFFDATA, + GTP_BASEDATA, +} debug_type; + +struct goodix_proc_operations { + void (*goodix_config_info_read) (struct seq_file *s, void *chip_data); + size_t (*goodix_water_protect_write) (struct file *file, const char *buff, size_t len, loff_t *pos); + size_t (*goodix_water_protect_read) (struct file *file, char *buff, size_t len, loff_t *pos); + void (*auto_test) (struct seq_file *s, void *chip_data, struct goodix_testdata *p_testdata); + int (*set_health_info_state) (void *chip_data, uint8_t enable); + int (*get_health_info_state) (void *chip_data); +}; + +struct fw_update_info { + u8 *buffer; + u8 *firmware_file_data; + u32 fw_length; + int status; + int progress; + int max_progress; + struct fw_info *firmware; +}; + +typedef enum { + BASE_DC_COMPONENT =0X01, + BASE_SYS_UPDATE =0X02, + BASE_NEGATIVE_FINGER = 0x03, + BASE_MONITOR_UPDATE= 0x04, + BASE_CONSISTENCE = 0x06, + BASE_FORCE_UPDATE = 0x07, +} BASELINE_ERR; + +typedef enum { + RST_MAIN_REG = 0x01, + RST_OVERLAY_ERROR = 0x02, + RST_LOAD_OVERLAY = 0x03, + RST_CHECK_PID = 0x04, + RST_CHECK_RAM = 0x06, + RST_CHECK_RAWDATA = 0x07, +} RESET_REASON; + +struct goodix_health_info { + uint8_t shield_water:1; + uint8_t shield_freq:1; + uint8_t baseline_refresh:1; + uint8_t fw_rst:1; + uint8_t shield_esd:1; + uint8_t reserve_bit:4; + uint8_t shield_palm:1; + uint8_t baseline_status:1; + uint8_t ub_freqhop_status:1; + uint8_t noise_stutus:1; + uint8_t reserve; + uint8_t water_mode; + uint8_t water_status; + uint8_t freq_before; + uint8_t freq_before_l; + uint8_t freq_before_h; + uint8_t freq_after; + uint8_t freq_after_l; + uint8_t freq_after_h; + uint8_t baseline_refresh_type; + uint8_t esd_raw; + uint8_t reset_reason; + uint8_t large_palm_status; + uint8_t baseline_study_status; + uint8_t ub_freqhop_type; + uint8_t last_noise_value_l; + uint8_t last_noise_value_h; + uint8_t current_noise_value_l; + uint8_t current_noise_value_h; + uint8_t reserve1; + uint8_t reserve2; + uint8_t reserve3; + uint8_t reserve4; + uint8_t reserve5; + uint8_t reserve6; + uint8_t reserve7; + uint8_t abs_max_l; + uint8_t abs_max_h; + uint8_t abs_avg_l; + uint8_t abs_avg_h; + int8_t mutualdif_max_l; + int8_t mutualdif_max_h; + int8_t mutualdif_min_l; + int8_t mutualdif_min_h; + int8_t selftx_diff_max_l; + int8_t selftx_diff_max_h; + int8_t selftx_diff_min_l; + int8_t selftx_diff_min_h; + int8_t selfrx_diff_max_l; + int8_t selfrx_diff_max_h; + int8_t selfrx_diff_min_l; + int8_t selfrx_diff_min_h; + uint8_t touch_num; + uint8_t rectnum; + uint8_t reserve8; + uint8_t reserve9; + uint8_t reserve10; + uint8_t reserve11; + uint8_t reserve12; + uint8_t reserve13; + uint8_t reserve14; + uint8_t checksum; + uint8_t checksum0; + uint8_t checksum1; +}; + + + + + +/****************************PART3:FUNCTION*************************************/ +#define I2C_MAX_TRANSFER_SIZE 255 +#define GOODIX_BUS_RETRY_TIMES 3 +#define GOODIX_REG_ADDR_SIZE 4 + + + + +void GetCirclePoints(struct Coordinate *input_points, int number, struct Coordinate *pPnts); +int ClockWise(struct Coordinate *p, int n); +int Goodix_create_proc(struct touchpanel_data *ts, struct goodix_proc_operations *goodix_ops); +int gt988x_parse_csvfile(const struct firmware *fw, char *target_name, int32_t *data, int rows, int columns); + +uint32_t search_for_item_offset(const struct firmware *fw, int item_cnt, uint8_t item_index); +int32_t *getpara_for_item(const struct firmware *fw, uint8_t item_index, uint32_t *para_num); +struct test_item_info *get_test_item_info(const struct firmware *fw, uint8_t item_index); +void goodix_limit_read(struct seq_file *s, struct touchpanel_data *ts); +void tp_kfree(void **mem); + +int touch_i2c_read_block_u32(struct i2c_client *client, u32 reg,unsigned int len, unsigned char *data); +int touch_i2c_write_block_u32(struct i2c_client *client, u32 reg,unsigned int len, unsigned char const *data); + + + +#endif + diff --git a/drivers/oneplus/input/touchscreen/Goodix/goodix_tool.c b/drivers/oneplus/input/touchscreen/Goodix/goodix_tool.c new file mode 100755 index 0000000000000000000000000000000000000000..7009b518fd9b148807e4563a60e12c03fca5ec80 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/goodix_tool.c @@ -0,0 +1,485 @@ +/*************************************************** + * File:goodix_tool.c + * VENDOR_EDIT + * Copyright (c) 2008- 2030 Oppo Mobile communication Corp.ltd. + * Description: + * goodix debugging tool code + * Version:1.0: + * Date created:2016/09/02 + * Author: Tong.han@Bsp.Driver + * TAG: BSP.TP.Init + * * + * -------------- Revision History: ----------------- + * + ***************************************************/ + +#include "goodix_tool.h" + +int gt1x_rawdiff_mode ; + +/****************************PART1:Log TAG****************************/ + +#define TPD_DEVICE "Goodix-TOOL" +#define TPD_INFO(fmt, arg...) pr_err(TPD_DEVICE ": " fmt, ##arg) +#define TPD_DEBUG(fmt, arg...) do{\ + if (tp_debug)\ + pr_err(TPD_DEVICE ": " fmt, ##arg);\ +}while(0) + +#define TPD_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if (tp_debug)\ + {\ + pr_err("<< GTP-TOOL-DBG >>");\ + for (i = 0; i < (num); i++)\ + {\ + pr_err("%02x ", (a)[i]);\ + if ((i + 1) % 10 == 0)\ + {\ + pr_err("\n<< GTP-DBG >>");\ + }\ + }\ + pr_err("\n");\ + }\ +}while(0) + +/****************************PART2:Code * && function****************************/ + +static ssize_t gt1x_tool_read (struct file *filp, char __user * buffer, size_t count, loff_t * ppos); +static ssize_t gt1x_tool_write (struct file *filp, const char *buffer, size_t count, loff_t * ppos); +static int gt1x_tool_release(struct inode *inode, struct file *filp); +static int gt1x_tool_open (struct inode *inode, struct file *file); + +static struct file_operations gt1x_tool_fops = { + .read = gt1x_tool_read, + .write = gt1x_tool_write, + .open = gt1x_tool_open, + .release = gt1x_tool_release, + .owner = THIS_MODULE, +}; + +int gt1x_init_tool_node(struct touchpanel_data *ts, struct fw_update_info *update_info) +{ + struct proc_dir_entry *gt1x_tool_proc_entry; + struct Goodix_tool_info *gt_tool_info; + gt_tool_info = kzalloc(sizeof(struct Goodix_tool_info), GFP_KERNEL); + + gt_tool_info->is_suspended = &ts->is_suspended; + gt_tool_info->esd_handle_support = ts->esd_handle_support; + gt_tool_info->esd_info = &ts->esd_info; + gt_tool_info->client = ts->client; + gt_tool_info->chip_data = ts->chip_data; + gt_tool_info->hw_res = &(ts->hw_res); + gt_tool_info->reset = ts->ts_ops->reset; + gt_tool_info->cmd_head.wr = 1; //if the first operation is read, will return fail. + + gt_tool_info->cmd_head.data = kzalloc(DATA_LENGTH_UINT, GFP_KERNEL); + gt_tool_info->update_info = update_info; + + if (NULL == gt_tool_info->cmd_head.data) { + TPD_INFO("Apply for memory failed."); + goto OUT2; + } + TPD_INFO("Alloc memory size:%d.", DATA_LENGTH_UINT); + + gt1x_tool_proc_entry = proc_create_data("goodix_tool", 0666, NULL, >1x_tool_fops, gt_tool_info); + if (gt1x_tool_proc_entry == NULL) { + TPD_INFO("CAN't create proc entry /proc/goodix_tool."); + goto OUT1; + } else { + TPD_INFO("Created proc entry /proc/goodix_tool."); + } + return 0; + +OUT1: + if (gt_tool_info->cmd_head.data) { + kfree(gt_tool_info->cmd_head.data); + } +OUT2: + if (gt_tool_info) { + kfree(gt_tool_info); + } + return -1; +} + +#if 0 +void gt1x_deinit_tool_node(void) +{ + remove_proc_entry("goodix_tool", NULL); + kfree(cmd_head.data); + cmd_head.data = NULL; +} +#endif + +static s32 tool_i2c_read(struct i2c_client *client, u8 * buf, u16 len) +{ + int ret = 0; + u16 addr = (buf[0] << 8) + buf[1]; + + ret = touch_i2c_read_block(client, addr, len, &buf[2]); + if (ret < 0) { + return -1; + } + + return 1; +} + +static s32 tool_i2c_write(struct i2c_client *client, u8 * buf, u16 len) +{ + int ret = 0; + u16 addr = (buf[0] << 8) + buf[1]; + + ret = touch_i2c_write_block(client, addr, len-2, &buf[2]); + if (ret < 0) { + return -1; + } + + return 1; +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + TPD_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32) ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* +Function: +Comfirm function. +Input: +None. +Output: +Return write length. + ********************************************************/ +static u8 comfirm(struct Goodix_tool_info *gt_tool_info) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, gt_tool_info->cmd_head.flag_addr, gt_tool_info->cmd_head.addr_len); + + for (i = 0; i < gt_tool_info->cmd_head.times; i++) { + if (tool_i2c_read(gt_tool_info->client, buf, 1) <= 0) { + TPD_INFO("Read flag data failed!"); + return -1; + } + + if (true == relation(buf[GTP_ADDR_LENGTH], gt_tool_info->cmd_head.flag_val, gt_tool_info->cmd_head.flag_relation)) { + TPD_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]); + TPD_DEBUG("flag value:0x%02x.", gt_tool_info->cmd_head.flag_val); + break; + } + + msleep(gt_tool_info->cmd_head.circle); + } + + if (i >= gt_tool_info->cmd_head.times) { + TPD_INFO("Didn't get the flag to continue!"); + return -1; + } + + return 0; +} + +/******************************************************* +Function: +Goodix tool write function. +Input: +standard proc write function param. +Output: +Return write length. + ********************************************************/ +static ssize_t gt1x_tool_write(struct file *filp, const char __user * buff, size_t len, loff_t * data) +{ + struct Goodix_tool_info *gt_tool_info = PDE_DATA(file_inode(filp)); + u64 ret = 0; + struct st_cmd_head *cmd_head = >_tool_info->cmd_head; + struct i2c_client *client = gt_tool_info->client; + + TPD_DEBUG_ARRAY((u8 *) buff, len); + + if (*(gt_tool_info->is_suspended)) { + TPD_INFO("IC halt"); + gt1x_rawdiff_mode = 0; + + return -1; + } + + ret = copy_from_user(cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + TPD_INFO("copy_from_user failed."); + } + + TPD_DEBUG("wr :0x%02x.", cmd_head->wr); + + /* + TPD_DEBUG("flag:0x%02x.", cmd_head.flag); + TPD_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]); + TPD_DEBUG("flag val:0x%02x.", cmd_head.flag_val); + TPD_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation); + TPD_DEBUG("circle :%d.", (s32)cmd_head.circle); + TPD_DEBUG("times :%d.", (s32)cmd_head.times); + TPD_DEBUG("retry :%d.", (s32)cmd_head.retry); + TPD_DEBUG("delay :%d.", (s32)cmd_head.delay); + TPD_DEBUG("data len:%d.", (s32)cmd_head.data_len); + TPD_DEBUG("addr len:%d.", (s32)cmd_head.addr_len); + TPD_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]); + TPD_DEBUG("len:%d.", (s32)len); + TPD_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]); + */ + + if (1 == cmd_head->wr) { + u16 addr, data_len, pos; + + if (1 == cmd_head->flag) { + if (comfirm(gt_tool_info)) { + TPD_INFO("[WRITE]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head->flag) { + //Need interrupt! + } + + addr = (cmd_head->addr[0] << 8) + cmd_head->addr[1]; + data_len = cmd_head->data_len; + pos = 0; + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + ret = copy_from_user(&cmd_head->data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH + pos], len); + if (ret) { + TPD_INFO("[WRITE]copy_from_user failed."); + return -1; + } + cmd_head->data[0] = ((addr >> 8) & 0xFF); + cmd_head->data[1] = (addr & 0xFF); + + TPD_DEBUG_ARRAY(cmd_head->data, len + GTP_ADDR_LENGTH); + + if (tool_i2c_write(client, cmd_head->data, len + GTP_ADDR_LENGTH) <= 0) { + TPD_INFO("[WRITE]Write data failed!"); + return -1; + } + addr += len; + pos += len; + data_len -= len; + } + + if (cmd_head->delay) { + msleep(cmd_head->delay); + } + + return cmd_head->data_len + CMD_HEAD_LENGTH; + } else if (3 == cmd_head->wr) { //gt1x unused + + //memcpy(IC_TYPE, cmd_head->data, cmd_head->data_len); + return cmd_head->data_len + CMD_HEAD_LENGTH; + } else if (5 == cmd_head->wr) { //? + + //memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + return cmd_head->data_len + CMD_HEAD_LENGTH; + } else if (7 == cmd_head->wr) { //disable irq! + disable_irq_nosync(client->irq); + + if(gt_tool_info->esd_handle_support) + esd_handle_switch(gt_tool_info->esd_info, false); //disable esd check + + return CMD_HEAD_LENGTH; + } else if (9 == cmd_head->wr) { //enable irq! + enable_irq(client->irq); + if(gt_tool_info->esd_handle_support) + esd_handle_switch(gt_tool_info->esd_info, true); //enable esd check + return CMD_HEAD_LENGTH; + } else if (17 == cmd_head->wr) { + cmd_head->data_len = cmd_head->data_len > DATA_LENGTH ? DATA_LENGTH : cmd_head->data_len; + ret = copy_from_user(&cmd_head->data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head->data_len); + if (ret) { + TPD_INFO("copy_from_user failed."); + return -1; + } + + if (cmd_head->data[GTP_ADDR_LENGTH]) { + TPD_DEBUG("gtp enter rawdiff."); + gt1x_rawdiff_mode = true; + } else { + gt1x_rawdiff_mode = false; + TPD_DEBUG("gtp leave rawdiff."); + } + + return CMD_HEAD_LENGTH; + } else if (11 == cmd_head->wr) { + if(gt_tool_info->esd_handle_support) //add test tool + esd_handle_switch(gt_tool_info->esd_info, false); //disable esd check + // disable_irq_nosync(client->irq); + } else if (13 == cmd_head->wr) { + gt_tool_info->reset(gt_tool_info->chip_data); + if(gt_tool_info->esd_handle_support) + esd_handle_switch(gt_tool_info->esd_info, true); + gt_tool_info->update_info->status = UPDATE_STATUS_IDLE; + // enable_irq(client->irq); + } else if (15 == cmd_head->wr) { + + /*struct task_struct *thrd = NULL; + memset(cmd_head->data, 0, cmd_head->data_len + 1); + memcpy(cmd_head->data, &buff[CMD_HEAD_LENGTH], cmd_head->data_len); + TPD_DEBUG("update firmware, filename: %s", cmd_head->data); + thrd = kthread_run(gt1x_update_firmware, (void *)cmd_head->data, "GT1x FW Update"); + if (IS_ERR(thrd)) { + return PTR_ERR(thrd); + } + */ + } + return CMD_HEAD_LENGTH; +} + +static int gt1x_tool_open(struct inode *inode, struct file *file) +{ + struct Goodix_tool_info *gt_tool_info = PDE_DATA(inode); + + if (gt_tool_info->devicecount > 0) { + return -ERESTARTSYS; + TPD_INFO("tools open failed!"); + } + gt_tool_info->devicecount++; + + return 0; +} + +static int gt1x_tool_release(struct inode *inode, struct file *filp) +{ + struct Goodix_tool_info *gt_tool_info = PDE_DATA(inode); + + gt_tool_info->devicecount--; + + return 0; +} +/******************************************************* +Function: +Goodix tool read function. +Input: +standard proc read function param. +Output: +Return read length. + ********************************************************/ +static ssize_t gt1x_tool_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) +{ + struct Goodix_tool_info *gt_tool_info = PDE_DATA(file_inode(filp)); + struct st_cmd_head *cmd_head = >_tool_info->cmd_head; + + if (*ppos) { + TPD_DEBUG("[PARAM]size: %zd, *ppos: %d", count, (int)*ppos); + *ppos = 0; + + return 0; + } + + if (*(gt_tool_info->is_suspended)) { + TPD_INFO("IC halt"); + gt1x_rawdiff_mode = 0; + + return -1; + } + if (cmd_head->wr % 2) { + TPD_INFO("[READ] invaild operator fail!"); + return -1; + } else if (!cmd_head->wr) { + /* general i2c read */ + u16 addr, data_len, len, loc; + + if (1 == cmd_head->flag) { + if (comfirm(gt_tool_info)) { + TPD_INFO("[READ]Comfirm fail!"); + return -1; + } + } else if (2 == cmd_head->flag) { + //Need interrupt! + } + + addr = (cmd_head->addr[0] << 8) + cmd_head->addr[1]; + data_len = cmd_head->data_len; + loc = 0; + + TPD_DEBUG("[READ] ADDR:0x%04X.", addr); + TPD_DEBUG("[READ] Length: %d", data_len); + + if (cmd_head->delay) { + msleep(cmd_head->delay); + } + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head->data[0] = (addr >> 8) & 0xFF; + cmd_head->data[1] = (addr & 0xFF); + if (tool_i2c_read(gt_tool_info->client, cmd_head->data, len) <= 0) { + TPD_INFO("[READ]Read data failed!"); + return -1; + } + + memcpy(&buffer[loc], &cmd_head->data[GTP_ADDR_LENGTH], len); + data_len -= len; + addr += len; + loc += len; + TPD_DEBUG_ARRAY(&cmd_head->data[GTP_ADDR_LENGTH], len); + } + *ppos += cmd_head->data_len; + return cmd_head->data_len; + } else if (2 == cmd_head->wr) { + TPD_DEBUG("Return ic type:%s len:%d.", buffer, (s32) cmd_head->data_len); + return -1; + } else if (4 == cmd_head->wr) { + /* read fw update progress */ + buffer[0] = gt_tool_info->update_info->progress >> 8; + buffer[1] = gt_tool_info->update_info->progress & 0xff; + buffer[2] = gt_tool_info->update_info->max_progress >> 8; + buffer[3] = gt_tool_info->update_info->max_progress & 0xff; + *ppos += 4; + + return 4; + } else if (6 == cmd_head->wr) { + //Read error code! + return -1; + } else if (8 == cmd_head->wr) { + /* Read driver version */ + s32 tmp_len; + tmp_len = strlen(GTP_DRIVER_VERSION); + memcpy(buffer, GTP_DRIVER_VERSION, tmp_len); + buffer[tmp_len] = 0; + *ppos += tmp_len + 1; + return (tmp_len + 1); + } + *ppos += cmd_head->data_len; + + return cmd_head->data_len; +} diff --git a/drivers/oneplus/input/touchscreen/Goodix/goodix_tool.h b/drivers/oneplus/input/touchscreen/Goodix/goodix_tool.h new file mode 100644 index 0000000000000000000000000000000000000000..3d36e88338b10bc71c8e909fe4e5b3e921b15a07 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/goodix_tool.h @@ -0,0 +1,65 @@ +/*************************************************** + * File:goodix_tool.h + * VENDOR_EDIT + * Copyright (c) 2008- 2030 Oppo Mobile communication Corp.ltd. + * Description: + * goodix debugging tool code + * Version:1.0: + * Date created:2016/09/02 + * Author: Tong.han@Bsp.Driver + * TAG: BSP.TP.Init + * * + * -------------- Revision History: ----------------- + * + ***************************************************/ + +#ifndef _TOUCHPANEL_TOOL_GOODIX_H_ +#define _TOUCHPANEL_TOOL_GOODIX_H_ + +#include "../touchpanel_common.h" +#include "goodix_common.h" + +#pragma pack(1) +struct st_cmd_head{ + u8 wr; //write read flag£¬0:R 1:W 2:PID 3: + u8 flag; //0:no need flag/int 1: need flag 2:need int + u8 flag_addr[2]; //flag address + u8 flag_val; //flag val + u8 flag_relation; //flag_val:flag 0:not equal 1:equal 2:> 3:< + u16 circle; //polling cycle + u8 times; //plling times + u8 retry; //I2C retry times + u16 delay; //delay befor read or after write + u16 data_len; //data length + u8 addr_len; //address length + u8 addr[2]; //address + u8 res[3]; //reserved + u8 *data; //data pointer +} ; +#pragma pack() + +struct Goodix_tool_info{ + u8 devicecount; + bool esd_handle_support; /*esd handle support feature*/ + int *is_suspended; + void *chip_data; + struct hw_resource *hw_res; + struct i2c_client *client; + struct st_cmd_head cmd_head; + struct fw_update_info *update_info; + struct esd_information *esd_info; + + int (*reset) (void *chip_data); /*Reset Touchpanel*/ +}; + +int gt1x_init_tool_node(struct touchpanel_data *ts, struct fw_update_info *update_info); + +#define GTP_ESD_PROTECT 0 +#define GTP_DRIVER_VERSION "V1.4<2015/07/10>" + +#define DATA_LENGTH_UINT 512 +#define GTP_ADDR_LENGTH 2 +#define DATA_LENGTH (DATA_LENGTH_UINT - GTP_ADDR_LENGTH) +#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8*)) + +#endif diff --git a/drivers/oneplus/input/touchscreen/Goodix/gtx8_tools.c b/drivers/oneplus/input/touchscreen/Goodix/gtx8_tools.c new file mode 100755 index 0000000000000000000000000000000000000000..9d57bea55bd0609c4ac34c795431999c3bce70ae --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/gtx8_tools.c @@ -0,0 +1,321 @@ +/************************************************************** + * Copyright (c) 2008- 2030 Oppo Mobile communication Corp.ltd. + * VENDOR_EDIT + * File : gtx8_tools.c + * Description: goodix debugging tool code + * Version : 1.0 + * Date : 2019-08-27 + * Author : Zengpeng.Chen@Bsp.Group.Tp + * TAG : BSP.TP.Init + * ---------------- Revision History: -------------------------- + * < author > + ****************************************************************/ +#include "gtx8_tools.h" + +/****************************PART1:Log TAG****************************/ +#define TPD_DEVICE "Goodix-TOOL" +#define TPD_INFO(fmt, arg...) pr_err(TPD_DEVICE ": " fmt, ##arg) +#define TPD_DEBUG(fmt, arg...) do{\ + if (tp_debug)\ + pr_err(TPD_DEVICE ": " fmt, ##arg);\ +}while(0) + +#define TPD_DEBUG_ARRAY(array, num) do{\ + s32 i;\ + u8* a = array;\ + if (tp_debug)\ + {\ + pr_err("<< GTP-TOOL-DBG >>");\ + for (i = 0; i < (num); i++)\ + {\ + pr_err("%02x ", (a)[i]);\ + if ((i + 1) % 10 == 0)\ + {\ + pr_err("\n<< GTP-DBG >>");\ + }\ + }\ + pr_err("\n");\ + }\ +}while(0) + +#define GOODIX_TOOLS_NAME "gtp_tools" +#define GOODIX_TS_IOC_MAGIC 'G' +#define NEGLECT_SIZE_MASK (~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) + +#define GTP_IRQ_ENABLE _IO(GOODIX_TS_IOC_MAGIC, 0) +#define GTP_DEV_RESET _IO(GOODIX_TS_IOC_MAGIC, 1) +#define GTP_SEND_COMMAND (_IOW(GOODIX_TS_IOC_MAGIC, 2, u8) & NEGLECT_SIZE_MASK) +#define GTP_SEND_CONFIG (_IOW(GOODIX_TS_IOC_MAGIC, 3, u8) & NEGLECT_SIZE_MASK) +#define GTP_ASYNC_READ (_IOR(GOODIX_TS_IOC_MAGIC, 4, u8) & NEGLECT_SIZE_MASK) +#define GTP_SYNC_READ (_IOR(GOODIX_TS_IOC_MAGIC, 5, u8) & NEGLECT_SIZE_MASK) +#define GTP_ASYNC_WRITE (_IOW(GOODIX_TS_IOC_MAGIC, 6, u8) & NEGLECT_SIZE_MASK) +#define GTP_READ_CONFIG (_IOW(GOODIX_TS_IOC_MAGIC, 7, u8) & NEGLECT_SIZE_MASK) +#define GTP_ESD_ENABLE _IO(GOODIX_TS_IOC_MAGIC, 8) +#define GTP_CLEAR_RAWDATA_FLAG _IO(GOODIX_TS_IOC_MAGIC, 9) +#define GTP_TOOLS_CTRL_SYNC (_IOW(GOODIX_TS_IOC_MAGIC,10,u8) & NEGLECT_SIZE_MASK) + +#define GOODIX_TS_IOC_MAXNR 10 +#define GOODIX_TOOLS_MAX_DATA_LEN 16*1024 +#define I2C_MSG_HEAD_LEN 20 + +#define GTX8_TOOLS_CLOSE 0 +#define GTX8_TOOLS_OPEN 1 + +#define MISC_DYNAMIC_MINOR 255 +int gt8x_rawdiff_mode; + +static struct Goodix_tool_info gtx8_tool_info; + +/* read data from i2c asynchronous, +** success return bytes read, else return <= 0 +*/ +static int async_read(void __user *arg) +{ + u8 *databuf = NULL; + int ret = 0; + u32 reg_addr = 0; + u32 length = 0; + u8 i2c_msg_head[I2C_MSG_HEAD_LEN]; + + ret = copy_from_user(&i2c_msg_head, arg, I2C_MSG_HEAD_LEN); + if (ret) { + ret = -EFAULT; + return ret; + } + + reg_addr = i2c_msg_head[0] + (i2c_msg_head[1] << 8) + + (i2c_msg_head[2] << 16) + (i2c_msg_head[3] << 24); + length = i2c_msg_head[4] + (i2c_msg_head[5] << 8) + + (i2c_msg_head[6] << 16) + (i2c_msg_head[7] << 24); + if (length > GOODIX_TOOLS_MAX_DATA_LEN) { + TPD_INFO("%s: Invalied data length:%d\n", __func__, length); + return -EFAULT; + } + + databuf = kzalloc(length, GFP_KERNEL); + if (!databuf) { + TPD_INFO("Alloc memory failed\n"); + return -ENOMEM; + } + + if (touch_i2c_read_block_u32(gtx8_tool_info.client, reg_addr, length, databuf) >= 0) { + if (copy_to_user((u8 *)arg + I2C_MSG_HEAD_LEN, databuf, length)) { + ret = -EFAULT; + TPD_INFO("Copy_to_user failed\n"); + } else { + ret = length; + } + } else { + ret = -EBUSY; + TPD_INFO("Read i2c failed\n"); + } + + if(databuf) { + kfree(databuf); + databuf = NULL; + } + return ret; +} + +/* write data to i2c asynchronous, +** success return bytes write, else return <= 0 +*/ +static int async_write(void __user *arg) +{ + u8 *databuf = NULL; + int ret = 0; + u32 reg_addr = 0; + u32 length = 0; + u8 i2c_msg_head[I2C_MSG_HEAD_LEN]; + + ret = copy_from_user(&i2c_msg_head, arg, I2C_MSG_HEAD_LEN); + if (ret) { + TPD_INFO("Copy data from user failed\n"); + return -EFAULT; + } + + reg_addr = i2c_msg_head[0] + (i2c_msg_head[1] << 8) + + (i2c_msg_head[2] <<16) + (i2c_msg_head[3] << 24); + length = i2c_msg_head[4] + (i2c_msg_head[5] << 8) + + (i2c_msg_head[6] << 16) + (i2c_msg_head[7] << 24); + + if (length > GOODIX_TOOLS_MAX_DATA_LEN) { + TPD_INFO("%s: Invalied data length:%d\n", __func__, length); + return -EFAULT; + } + databuf = kzalloc(length, GFP_KERNEL); + if (!databuf) { + TPD_INFO("Alloc memory failed\n"); + return -ENOMEM; + } + + ret = copy_from_user(databuf, (u8 *)arg + I2C_MSG_HEAD_LEN, length); + if (ret) { + ret = -EFAULT; + TPD_INFO("Copy data from user failed\n"); + goto err_out; + } + + if (touch_i2c_write_block_u32(gtx8_tool_info.client, reg_addr, length, databuf) < 0) { + ret = -EBUSY; + TPD_INFO("Write data to device failed\n"); + } else { + ret = length; + } + +err_out: + if(databuf) { + kfree(databuf); + databuf = NULL; + } + return ret; +} + +static int goodix_tools_open(struct inode *inode, struct file *filp) +{ + TPD_INFO("tools open\n"); + if (gtx8_tool_info.devicecount > 0) { + return -ERESTARTSYS; + TPD_INFO("tools open failed!"); + } + gtx8_tool_info.devicecount++; + + return 0; +} + +static int goodix_tools_release(struct inode *inode, struct file *filp) +{ + TPD_INFO("tools release\n"); + gtx8_tool_info.devicecount--; + gt8x_rawdiff_mode = 0; + return 0; +} + +/** + * goodix_tools_ioctl - ioctl implementation + * + * @filp: Pointer to file opened + * @cmd: Ioctl opertion command + * @arg: Command data + * Returns >=0 - succeed, else failed + */ +#define TOOL_CMD_LEN 2 +static long goodix_tools_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + struct i2c_client *client = gtx8_tool_info.client; + + if (_IOC_TYPE(cmd) != GOODIX_TS_IOC_MAGIC) { + TPD_INFO("Bad magic num:%c\n", _IOC_TYPE(cmd)); + + return -ENOTTY; + } + + switch (cmd & NEGLECT_SIZE_MASK) { + case GTP_IRQ_ENABLE: + if (arg) { + enable_irq(client->irq); + } else { + disable_irq_nosync(client->irq); + } + TPD_INFO("set irq mode: %s\n", arg ? "enable" : "disable"); + ret = 0; + break; + case GTP_ESD_ENABLE: + ret = 0; + if(!gtx8_tool_info.esd_handle_support) { + TPD_INFO("Unsupport esd operation\n"); + } else { + esd_handle_switch(gtx8_tool_info.esd_info, !!arg); + TPD_DEBUG("set esd mode: %s\n", arg ? "enable" : "disable"); + } + break; + case GTP_DEV_RESET: + gtx8_tool_info.reset(gtx8_tool_info.chip_data); + break; + + case GTP_ASYNC_READ: + ret = async_read((void __user *)arg); + if (ret < 0) + TPD_INFO("Async data read failed\n"); + break; + case GTP_SYNC_READ: + gt8x_rawdiff_mode = 1; + break; + case GTP_ASYNC_WRITE: + ret = async_write((void __user *)arg); + if (ret < 0) + TPD_INFO("Async data write failed\n"); + break; + case GTP_CLEAR_RAWDATA_FLAG: + gt8x_rawdiff_mode = 0; + ret = 0; + break; + case GTP_TOOLS_CTRL_SYNC: + gt8x_rawdiff_mode = !!arg; + TPD_INFO("set tools ctrl sync %d\n", gt8x_rawdiff_mode); + break; + + default: + TPD_INFO("Invalid cmd\n"); + ret = -ENOTTY; + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +static long goodix_tools_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *arg32 = compat_ptr(arg); + + if (!file->f_op || !file->f_op->unlocked_ioctl) + return -1; + return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)arg32); +} +#endif + +static const struct file_operations goodix_tools_fops = { + .owner = THIS_MODULE, + .open = goodix_tools_open, + .release = goodix_tools_release, + .unlocked_ioctl = goodix_tools_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = goodix_tools_compat_ioctl, +#endif +}; + +static struct miscdevice goodix_tools_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = GOODIX_TOOLS_NAME, + .fops = &goodix_tools_fops, +}; + +int gtx8_init_tool_node(struct touchpanel_data *ts) +{ + int ret = NO_ERR; + + ret = misc_register(&goodix_tools_miscdev); + if (ret) { + TPD_INFO("Debug tools miscdev register failed\n"); + } + gtx8_tool_info.devicecount = 0; + gtx8_tool_info.is_suspended = &ts->is_suspended; + gtx8_tool_info.esd_handle_support = ts->esd_handle_support; + gtx8_tool_info.esd_info = &ts->esd_info; + gtx8_tool_info.client = ts->client; + gtx8_tool_info.chip_data = ts->chip_data; + gtx8_tool_info.hw_res = &(ts->hw_res); + gtx8_tool_info.reset = ts->ts_ops->reset; + + return ret; +} + +void gtx8_deinit_tool_node(void) +{ + misc_deregister(&goodix_tools_miscdev); + TPD_INFO("Goodix tools miscdev exit\n"); +} diff --git a/drivers/oneplus/input/touchscreen/Goodix/gtx8_tools.h b/drivers/oneplus/input/touchscreen/Goodix/gtx8_tools.h new file mode 100755 index 0000000000000000000000000000000000000000..e986c365169c79613088d6cd85aaa2ca7315efbd --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Goodix/gtx8_tools.h @@ -0,0 +1,54 @@ +/************************************************************** + * Copyright (c) 2008- 2030 Oppo Mobile communication Corp.ltd. + * VENDOR_EDIT + * File : gtx8_tools.h + * Description: header file for goodix debugging tool code + * Version : 1.0 + * Date : 2019-08-27 + * Author : Zengpeng.Chen@Bsp.Group.Tp + * TAG : BSP.TP.Init + * ---------------- Revision History: -------------------------- + * < author > + ****************************************************************/ + +#ifndef _TOUCHPANEL_TOOL_GTX8_H_ +#define _TOUCHPANEL_TOOL_GTX8_H_ + +#include "../touchpanel_common.h" +#include "goodix_common.h" +#include + + +/****************************Start of modify declare****************************/ +#define NO_ERR 0 +#define EMEMCMP 1003 +#define EBUS 1000 +#define ETIMEOUT 1001 +#define ECHKSUM 1002 + +/****************************End of modify declare****************************/ + + +struct Goodix_tool_info { + u8 devicecount; + bool esd_handle_support; /*esd handle support feature*/ + int *is_suspended; + void *chip_data; + struct hw_resource *hw_res; + struct i2c_client *client; + struct fw_update_info *update_info; + struct esd_information *esd_info; + + int (*reset) (void *chip_data); /*Reset Touchpanel*/ +}; + +int gtx8_init_tool_node(struct touchpanel_data *ts); + +#define GTP_ESD_PROTECT 0 +#define GTP_DRIVER_VERSION "V1.4<2015/07/10>" + +#define DATA_LENGTH_UINT 512 +#define GTP_ADDR_LENGTH 2 +#define DATA_LENGTH (DATA_LENGTH_UINT - GTP_ADDR_LENGTH) + +#endif diff --git a/drivers/oneplus/input/touchscreen/Kconfig b/drivers/oneplus/input/touchscreen/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..eb3a52c1976fb629b9d6bd16d15ee7ddd7058f67 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Kconfig @@ -0,0 +1,9 @@ + +source "drivers/oneplus/input/touchscreen/util_interface/Kconfig" +source "drivers/oneplus/input/touchscreen/samsung/Kconfig" +source "drivers/oneplus/input/touchscreen/synaptics/Kconfig" +source "drivers/oneplus/input/touchscreen/Goodix/Kconfig" + +config OP_TOUCHSCREEN + default y + bool "Enable/Disable the touchscreen common driver" diff --git a/drivers/oneplus/input/touchscreen/Makefile b/drivers/oneplus/input/touchscreen/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..3508f9d74f8a6f9a9aa2641f7733e15ed6ddf23c --- /dev/null +++ b/drivers/oneplus/input/touchscreen/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the touchscreen drivers. +# +obj-y += samsung/ +obj-y += util_interface/ +obj-y += touchpanel_common_driver.o +obj-y += synaptics/ +obj-y += Goodix/ diff --git a/drivers/oneplus/input/touchscreen/samsung/Kconfig b/drivers/oneplus/input/touchscreen/samsung/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..07a229da9ff028a1bbc44c3e4b680456a5308f6f --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/Kconfig @@ -0,0 +1,3 @@ + +source "drivers/oneplus/input/touchscreen/samsung/s6sy761/Kconfig" + diff --git a/drivers/oneplus/input/touchscreen/samsung/Makefile b/drivers/oneplus/input/touchscreen/samsung/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..1c1e53b8f57c8f9bccf45d645346cc3377d92de1 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the touchscreen drivers. +# +obj-$(CONFIG_TOUCHPANEL_SAMSUNG_S6SY761) += s6sy761/ +obj-$(CONFIG_TOUCHPANEL_SAMSUNG) += sec_common.o diff --git a/drivers/oneplus/input/touchscreen/samsung/s6sy761/Kconfig b/drivers/oneplus/input/touchscreen/samsung/s6sy761/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..e243fd53506446c931370959b82918dcbe4d1eb9 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/s6sy761/Kconfig @@ -0,0 +1,12 @@ + +config TOUCHPANEL_SAMSUNG_S6SY761 + default y + bool "TP Samsung s6sy761 IC enable or not for oem" + ---help--- + say Y to enable driver for Touchpanel using Samsung s6sy761 + +config TOUCHPANEL_SAMSUNG + default y + bool "TP Samsung IC enable or not for oem" + ---help--- + say Y to enable driver for Touchpanel using Samsung diff --git a/drivers/oneplus/input/touchscreen/samsung/s6sy761/Makefile b/drivers/oneplus/input/touchscreen/samsung/s6sy761/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..5cfbd7f37bce4d863fe6c5615fe9f097bc030aa7 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/s6sy761/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the touchscreen drivers. +# + +obj-$(CONFIG_TOUCHPANEL_SAMSUNG_S6SY761) += sec_drivers_s6sy761.o diff --git a/drivers/oneplus/input/touchscreen/samsung/s6sy761/sec_drivers_s6sy761.c b/drivers/oneplus/input/touchscreen/samsung/s6sy761/sec_drivers_s6sy761.c new file mode 100755 index 0000000000000000000000000000000000000000..3a5df3c1de54cce6c2eaeca6f1f3c4422436be30 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/s6sy761/sec_drivers_s6sy761.c @@ -0,0 +1,3559 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_FB +#include +#include +#endif + +#include "sec_drivers_s6sy761.h" + +extern int tp_register_times; +extern struct touchpanel_data *g_tp; +#define PM_QOS_VALUE_TP 200 +struct pm_qos_request pm_qos_req_stp; + +/****************** Start of Log Tag Declear and level define*******************************/ +#define TPD_DEVICE "sec-s6sy761" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (LEVEL_DEBUG == tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do{\ + if (LEVEL_BASIC != tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DEBUG_NTAG(a, arg...)\ + do{\ + if (tp_debug)\ + printk(a, ##arg);\ + }while(0) +/******************** End of Log Tag Declear and level define*********************************/ + +/*************************** start of function delcare****************************************/ +void sec_mdelay(unsigned int ms); +static int sec_reset(void *chip_data); +static int sec_power_control(void *chip_data, bool enable); +static int sec_get_verify_result(struct chip_data_s6sy761 *chip_info); +static void sec_ts_read_info_work(struct work_struct *work); +int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); + + +/**************************** end of function delcare*****************************************/ + + +/****** Start of other functions that work for touchpanel_operations callbacks***********/ +static int sec_enable_black_gesture(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + int i = 0; + + TPD_INFO("%s, enable = %d\n", __func__, enable); + + if (enable) { + for (i = 0; i < 20; i++) + { + touch_i2c_write_word(chip_info->client, SEC_CMD_WAKEUP_GESTURE_MODE, 0xFFFF); + touch_i2c_write_byte(chip_info->client, SEC_CMD_SET_POWER_MODE, 0x01); + sec_mdelay(10); + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_SET_POWER_MODE); + if (0x01 == ret) + break; + } + } else { + for (i = 0; i < 20; i++) + { + touch_i2c_write_word(chip_info->client, SEC_CMD_WAKEUP_GESTURE_MODE, 0x0000); + touch_i2c_write_byte(chip_info->client, SEC_CMD_SET_POWER_MODE, 0x00); + sec_mdelay(10); + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_SET_POWER_MODE); + if (0x00 == ret) + break; + } + return 0; + } + + if (i >= 5) { + ret = -1; + TPD_INFO("%s: enter black gesture failed\n", __func__); + } else { + TPD_INFO("%s: %d times enter black gesture success\n", __func__, i); + } + return ret; +} + +static int sec_enable_edge_limit(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_word(chip_info->client, SEC_CMD_GRIP_SWITCH, 0x2000); + } else { + ret = touch_i2c_write_word(chip_info->client, SEC_CMD_GRIP_SWITCH, 0x0000); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_enable_charge_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SET_CMD_SET_CHARGER_MODE, 0x02); + } else { + ret = touch_i2c_write_byte(chip_info->client, SET_CMD_SET_CHARGER_MODE, 0x01); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_enable_wireless_charge_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SET_CMD_SET_CHARGER_MODE, 0x04); + } else { + ret = touch_i2c_write_byte(chip_info->client, SET_CMD_SET_CHARGER_MODE, 0x01); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; + +} + +static int sec_enable_reverse_wireless_charge(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SEC_NOISE_MODE, 0x11);//enter noise mode + } else { + ret = touch_i2c_write_byte(chip_info->client, SEC_NOISE_MODE, 0x10);//enter normal mode + ret = touch_i2c_write_byte(chip_info->client, SEC_NOISE_MODE, 0x00);//start normal mode + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; + +} + +static int sec_enable_wet_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + g_tp->wet_mode_status = 1; + ret = touch_i2c_write_byte(chip_info->client, SEC_WET_MODE, 1); + TPD_INFO("enter wet mode, close it\n"); + } else { + g_tp->wet_mode_status = 0; + ret = touch_i2c_write_byte(chip_info->client, SEC_WET_MODE, 0); + } + + return 0; +} +static int sec_audio_noise_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SET_CMD_SET_AUDIO_NOISE_MODE, 0x01); + } else { + ret = touch_i2c_write_byte(chip_info->client, SET_CMD_SET_AUDIO_NOISE_MODE, 0x00); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; + +} + + +static int sec_enable_earsense_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_HOVER_DETECT, 1); + ret |= touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, TYPE_DATA_DELTA); + } else { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_HOVER_DETECT, 0); + ret |= touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, TYPE_SIGNAL_DATA); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_enable_face_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_HOVER_DETECT, 1); + } else { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_HOVER_DETECT, 0); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_face_reduce_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_TOUCHHOLD_CALIBRATE, 1); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_enable_palm_reject(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_word(chip_info->client, SEC_CMD_PALM_SWITCH, 0x0061); + } else { + ret = touch_i2c_write_word(chip_info->client, SEC_CMD_PALM_SWITCH, 0x0041); + } + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_enable_game_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_GAME_FAST_SLIDE, 1); + else + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_GAME_FAST_SLIDE, 0); + + TPD_INFO("%s: state: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_refresh_switch_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_REFRESH_RATE_SWITCH, 0x5A); + } else { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_REFRESH_RATE_SWITCH, 0x3C); + } + TPD_INFO("%s: refresh_switch: %s %s!\n", __func__, enable == 0 ? "60HZ":"90HZ", ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_touchhold_switch_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + int i = 0; + + if (enable == 1) { + for(i = 0; i < 10; i++) { + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH); + ret |= 0x01; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH, ret); + sec_mdelay(10); + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH); + if (ret == 1) + break; + } + } else if (enable == 0){ + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH); + ret &= 0xFE; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH, ret); + } + TPD_INFO("%s: touchhold_enable: %d %s!\n", __func__, enable, ret < 0 ? "failed" : "success"); + return ret; +} + +static int sec_toucharea_switch_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH); + ret |= 0x02; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH, ret); + TPD_INFO("%s:cmd = 0x%x, touch area switch qualcom %s\n", __func__, ret, ret < 0 ? "failed" : "success"); + } else { + ret = touch_i2c_read_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH); + ret &= 0xFD; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_TOUCHHOLD_SWITCH, ret); + TPD_INFO("%s:cmd = 0x%x, touch area switch goodix %s\n", __func__, ret, ret < 0 ? "failed" : "success"); + } + + return ret; +} +static int sec_limit_switch_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + unsigned char buf[5] = {0}; + unsigned char cmd[3] = {0}; + unsigned char extra_cmd[3] = {0}; + + TPD_INFO("limit_switch is %d\n", g_tp->limit_switch); + if (g_tp->limit_switch == 1) { //LANDSPACE + cmd[0] = 0x01; + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SCREEN_ORIEN, 3, cmd);//change mode + } else if (g_tp->limit_switch == 3) { + cmd[0] = 0x02; + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SCREEN_ORIEN, 3, cmd); + } else { //portrait + cmd[0] = 0x00; + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SCREEN_ORIEN, 3, cmd); + } + //dead zone type 1 + if ((g_tp->limit_switch == 1) || (g_tp->limit_switch == 3)) //landscape + buf[2] = g_tp->dead_zone_l; //default x=15px + else //portrait + buf[2] = g_tp->dead_zone_p; //default x=15px + + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_PARA, 5, buf); + //dead zone type 2 + buf[0] = 0x01; + if ((g_tp->limit_switch == 1) || (g_tp->limit_switch == 3)) { //landscape + buf[2] = 0x50;//x=80px + buf[4] = 0x50;//y=80px + } else { //portrait + buf[2] = 0x1E;//x=30px + buf[4] = 0x82;//y=130px + } + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_PARA, 5, buf); + //long press reject zone + buf[0] = 0x02; + TPD_INFO("project info is %d\n", g_tp->project_info); + if(g_tp->project_info == 1) {//19811 + buf[2] = 0x3C;//x=60px + buf[4] = 0x50;//y=80px + } else { + buf[2] = 0x1E;//x=30px + buf[4] = 0x32;//y=50px + } + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_PARA, 5, buf); + extra_cmd[0] = 0x02; + extra_cmd[1] = 0x14; + extra_cmd[2] = 0x46; + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_EXTRA, 3, extra_cmd); + //large touch reject zone + buf[0] = 0x03; + buf[2] = 0x64;//x=100px + buf[4] = 0x64;//y=100px + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_PARA, 5, buf); + extra_cmd[0] = 0x03; + extra_cmd[1] = 0x0F; + extra_cmd[2] = 0x28; + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_EXTRA, 3, extra_cmd); + //corner long press reject zone + buf[0] = 0x04; + if (g_tp->project_info == 1) { + buf[2] = 0x78;//120px + buf[4] = 0x78;//120px + } else { + buf[2] = 0x64;//100px + buf[4] = 0x64;//100px + } + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_PARA, 5, buf); + extra_cmd[0] = 0x04; + extra_cmd[1] = 0x32; + extra_cmd[2] = 0x00; + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_GRIP_EXTRA, 3, extra_cmd); + + return ret; + +} + +static int sec_gesture_switch_mode(struct chip_data_s6sy761 *chip_info, bool enable) +{ + int ret = -1; + + if (enable) { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_DISABLE_GESTURE_MODE, 1); //disable gesture + } else { + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_DISABLE_GESTURE_MODE, 0); //enable gesture + } + + TPD_INFO("%s: gesture_switch: %s %s!\n", __func__, enable == 0 ? "enable":"disable", ret < 0 ? "failed" : "success"); + return ret; +} + +void sec_mdelay(unsigned int ms) +{ + if (ms < 20) + usleep_range(ms * 1000, ms * 1000); + else + msleep(ms); +} + +int sec_wait_for_ready(struct chip_data_s6sy761 *chip_info, unsigned int ack) +{ + int rc = -1; + int retry = 0, retry_cnt = 100; + int8_t status = -1; + u8 tBuff[SEC_EVENT_BUFF_SIZE] = {0,}; + int num = 0; + + while (touch_i2c_read_block(chip_info->client, SEC_READ_ONE_EVENT, SEC_EVENT_BUFF_SIZE, tBuff) > 0) { + status = (tBuff[0] >> 2) & 0xF; + if ((status == TYPE_STATUS_EVENT_INFO) || (status == TYPE_STATUS_EVENT_VENDOR_INFO)) { + if (tBuff[1] == ack) { + rc = 0; + break; + } + } + num++; + if (retry++ > retry_cnt) { + TPD_INFO("%s: Time Over, event_buf: %02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X \n", \ + __func__, tBuff[0], tBuff[1], tBuff[2], tBuff[3], tBuff[4], tBuff[5], tBuff[6], tBuff[7]); + status = touch_i2c_read_byte(chip_info->client, SEC_READ_BOOT_STATUS); + if (status == SEC_STATUS_BOOT_MODE) { + TPD_INFO("%s: firmware in bootloader mode,boot failed\n", __func__); + } + break; + } + sec_mdelay(20); + } + TPD_INFO("num is %d\n", num); + return rc; +} + +static int sec_enter_fw_mode(struct chip_data_s6sy761 *chip_info) +{ + int ret = -1; + u8 device_id[3] = {0}; + u8 fw_update_mode_passwd[] = {0x55, 0xAC}; + + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_ENTER_FW_MODE, sizeof(fw_update_mode_passwd), fw_update_mode_passwd); + sec_mdelay(20); + if (ret < 0) { + TPD_INFO("%s: write cmd to enter fw mode failed\n", __func__); + return -1; + } + + //need soft reset or hard reset + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + gpio_direction_output(chip_info->hw_res->reset_gpio, false); + sec_mdelay(10); + gpio_direction_output(chip_info->hw_res->reset_gpio, true); + } else { + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SOFT_RESET, 0, NULL); + if (ret < 0) { + TPD_INFO("%s: write soft reset failed\n", __func__); + return -1; + } + } + sec_mdelay(100); + + ret = touch_i2c_read_byte(chip_info->client, SEC_READ_BOOT_STATUS); //after reset, check bootloader again + if (ret < 0) { + TPD_INFO("%s: read boot status failed\n", __func__); + return -1; + } + if (ret != SEC_STATUS_BOOT_MODE) { + TPD_INFO("%s: read boot status, but no in boot mode(%d)\n", __func__, ret); + return -1; + } + + sec_mdelay(10); + + ret = touch_i2c_read_block(chip_info->client, SEC_READ_ID, 3, device_id); + if (ret < 0) { + TPD_INFO("%s: read 3 byte device id failed\n", __func__); + return -1; + } + + chip_info->boot_ver[0] = device_id[0]; + chip_info->boot_ver[1] = device_id[1]; + chip_info->boot_ver[2] = device_id[2]; + chip_info->flash_page_size = SEC_FW_BLK_DEFAULT_SIZE; + if ((device_id[1] == 0x37) && ((device_id[2] == 0x61) || (device_id[2] == 0x91))) + chip_info->flash_page_size = 512; + + return 0; +} + +static u8 sec_checksum(u8 *data, int offset, int size) +{ + int i; + u8 checksum = 0; + + for (i = 0; i < size; i++) + checksum += data[i + offset]; + + return checksum; +} + +static int sec_flash_page_erase(struct chip_data_s6sy761 *chip_info, u32 page_idx, u32 page_num) +{ + int ret = -1; + u8 tCmd[6] = {0}; + + tCmd[0] = SEC_CMD_FLASH_ERASE; + tCmd[1] = (u8)((page_idx >> 8) & 0xFF); + tCmd[2] = (u8)((page_idx >> 0) & 0xFF); + tCmd[3] = (u8)((page_num >> 8) & 0xFF); + tCmd[4] = (u8)((page_num >> 0) & 0xFF); + tCmd[5] = sec_checksum(tCmd, 1, 4); + + ret = touch_i2c_write(chip_info->client, tCmd, 6); + + return ret; +} + +static int sec_flash_page_write(struct chip_data_s6sy761 *chip_info, u32 page_idx, u8 *page_data) +{ + int ret; + u8 tCmd[1 + 2 + SEC_FW_BLK_SIZE_MAX + 1]; + int flash_page_size = (int)chip_info->flash_page_size; + + tCmd[0] = SEC_CMD_FLASH_WRITE; + tCmd[1] = (u8)((page_idx >> 8) & 0xFF); + tCmd[2] = (u8)((page_idx >> 0) & 0xFF); + + memcpy(&tCmd[3], page_data, flash_page_size); + tCmd[1 + 2 + flash_page_size] = sec_checksum(tCmd, 1, 2 + flash_page_size); + + ret = touch_i2c_write(chip_info->client, tCmd, 1 + 2 + flash_page_size + 1); + return ret; +} + +static int sec_limited_flash_page_write(struct chip_data_s6sy761 *chip_info, u32 page_idx, u8 *page_data) +{ + int ret = -1; + u8 *tCmd = NULL; + u8 copy_data[3 + SEC_FW_BLK_SIZE_MAX]; + int copy_left = (int)chip_info->flash_page_size + 3; + int copy_size = 0; + int copy_max = I2C_BURSTMAX - 1; + int flash_page_size = (int)chip_info->flash_page_size; + + copy_data[0] = (u8)((page_idx >> 8) & 0xFF); /* addH */ + copy_data[1] = (u8)((page_idx >> 0) & 0xFF); /* addL */ + + memcpy(©_data[2], page_data, flash_page_size); /* DATA */ + copy_data[2 + flash_page_size] = sec_checksum(copy_data, 0, 2 + flash_page_size); /* CS */ + + while (copy_left > 0) { + int copy_cur = (copy_left > copy_max) ? copy_max : copy_left; + + tCmd = kzalloc(copy_cur + 1, GFP_KERNEL); + if (!tCmd) + goto err_write; + + if (copy_size == 0) + tCmd[0] = SEC_CMD_FLASH_WRITE; + else + tCmd[0] = SEC_CMD_FLASH_PADDING; + + memcpy(&tCmd[1], ©_data[copy_size], copy_cur); + + ret = touch_i2c_write(chip_info->client, tCmd, 1 + copy_cur); + if (ret < 0) { + ret = touch_i2c_write(chip_info->client, tCmd, 1 + copy_cur); + if (ret < 0) { + TPD_INFO("%s: failed, ret:%d\n", __func__, ret); + } + } + + copy_size += copy_cur; + copy_left -= copy_cur; + kfree(tCmd); + } + return ret; + +err_write: + TPD_INFO("%s: failed to alloc.\n", __func__); + return -ENOMEM; + +} + +static int sec_flash_write(struct chip_data_s6sy761 *chip_info, u32 mem_addr, u8 *mem_data, u32 mem_size) +{ + int ret = -1; + u32 page_idx = 0, size_copy = 0, flash_page_size = 0; + u32 page_idx_start = 0, page_idx_end = 0, page_num = 0; + u8 page_buf[SEC_FW_BLK_SIZE_MAX] = {0}; + + if (mem_size == 0) + return 0; + + flash_page_size = chip_info->flash_page_size; + page_idx_start = mem_addr / flash_page_size; + page_idx_end = (mem_addr + mem_size - 1) / flash_page_size; + page_num = page_idx_end - page_idx_start + 1; + + ret = sec_flash_page_erase(chip_info, page_idx_start, page_num); + if (ret < 0) { + TPD_INFO("%s: fw erase failed, mem_addr= %08X, pagenum = %d\n", __func__, mem_addr, page_num); + return -EIO; + } + + sec_mdelay(page_num + 10); + + size_copy = mem_size % flash_page_size; + if (size_copy == 0) + size_copy = flash_page_size; + + memset(page_buf, 0, flash_page_size); + + for (page_idx = page_num - 1;; page_idx--) { + memcpy(page_buf, mem_data + (page_idx * flash_page_size), size_copy); + if (chip_info->boot_ver[0] == 0xB2) { + ret = sec_flash_page_write(chip_info, (page_idx + page_idx_start), page_buf); + if (ret < 0) { + sec_mdelay(50); + ret = sec_flash_page_write(chip_info, (page_idx + page_idx_start), page_buf); + if (ret < 0) { + TPD_INFO("%s: fw write failed, page_idx = %u\n", __func__, page_idx); + goto err; + } + } + } else { + ret = sec_limited_flash_page_write(chip_info, (page_idx + page_idx_start), page_buf); + if (ret < 0) { + sec_mdelay(50); + ret = sec_limited_flash_page_write(chip_info, (page_idx + page_idx_start), page_buf); + if (ret < 0) { + TPD_INFO("%s: fw write failed, page_idx = %u\n", __func__, page_idx); + goto err; + } + } + + } + + size_copy = flash_page_size; + sec_mdelay(5); + + if (page_idx == 0) /* end condition (page_idx >= 0) page_idx type unsinged int */ + break; + } + + return mem_size; +err: + return -EIO; +} + +static int sec_block_read(struct chip_data_s6sy761 *chip_info, u32 mem_addr, int mem_size, u8 *buf) +{ + int ret; + u8 cmd[5]; + u8 *data; + + if (mem_size >= 64 * 1024) { + TPD_INFO("%s: mem size over 64K\n", __func__); + return -EIO; + } + + cmd[0] = (u8)SEC_CMD_FLASH_READ_ADDR; + cmd[1] = (u8)((mem_addr >> 24) & 0xff); + cmd[2] = (u8)((mem_addr >> 16) & 0xff); + cmd[3] = (u8)((mem_addr >> 8) & 0xff); + cmd[4] = (u8)((mem_addr >> 0) & 0xff); + + ret = touch_i2c_write(chip_info->client, cmd, 5); + if (ret < 0) { + TPD_INFO("%s: send command failed, %02X\n", __func__, cmd[0]); + return -EIO; + } + + udelay(10); + cmd[0] = (u8)SEC_CMD_FLASH_READ_SIZE; + cmd[1] = (u8)((mem_size >> 8) & 0xff); + cmd[2] = (u8)((mem_size >> 0) & 0xff); + + ret = touch_i2c_write(chip_info->client, cmd, 3); + if (ret < 0) { + TPD_INFO("%s: send command failed, %02X\n", __func__, cmd[0]); + return -EIO; + } + + udelay(10); + cmd[0] = (u8)SEC_CMD_FLASH_READ_DATA; + data = buf; + + ret = touch_i2c_read(chip_info->client, cmd, 1, data, mem_size); + if (ret < 0) { + TPD_INFO("%s: memory read failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int sec_memory_read(struct chip_data_s6sy761 *chip_info, u32 mem_addr, u8 *mem_data, u32 mem_size) +{ + int ret; + int retry = 3; + int read_size = 0; + int unit_size; + int max_size = I2C_BURSTMAX; + int read_left = (int)mem_size; + u8 *tmp_data; + + tmp_data = kmalloc(max_size, GFP_KERNEL); + if (!tmp_data) { + TPD_INFO("%s: failed to kmalloc\n", __func__); + return -ENOMEM; + } + + while (read_left > 0) { + unit_size = (read_left > max_size) ? max_size : read_left; + retry = 3; + do { + ret = sec_block_read(chip_info, mem_addr, unit_size, tmp_data); + if (retry-- == 0) { + TPD_INFO("%s: fw read fail mem_addr=%08X, unit_size=%d\n", __func__, mem_addr, unit_size); + kfree(tmp_data); + return -1; + } + + memcpy(mem_data + read_size, tmp_data, unit_size); + } while (ret < 0); + + mem_addr += unit_size; + read_size += unit_size; + read_left -= unit_size; + } + + kfree(tmp_data); + + return read_size; +} + +static int sec_chunk_update(struct chip_data_s6sy761 *chip_info, u32 addr, u32 size, u8 *data) +{ + int ii = 0, ret = 0; + u8 *mem_rb = NULL; + u32 write_size = 0; + u32 fw_size = size; + + write_size = sec_flash_write(chip_info, addr, data, fw_size); + if (write_size != fw_size) { + TPD_INFO("%s: fw write failed\n", __func__); + ret = -1; + goto err_write_fail; + } + + mem_rb = vzalloc(fw_size); + if (!mem_rb) { + TPD_INFO("%s: vzalloc failed\n", __func__); + ret = -1; + goto err_write_fail; + } + + if (sec_memory_read(chip_info, addr, mem_rb, fw_size) >= 0) { + for (ii = 0; ii < fw_size; ii++) { + if (data[ii] != mem_rb[ii]) + break; + } + + if (fw_size != ii) { + TPD_INFO("%s: fw verify fail at data[%d](%d, %d)\n", __func__, ii, data[ii], mem_rb[ii]); + ret = -1; + goto out; + } + } else { + ret = -1; + goto out; + } + + TPD_INFO("%s: verify done(%d)\n", __func__, ret); + +out: + vfree(mem_rb); +err_write_fail: + sec_mdelay(10); + + return ret; +} + +int sec_read_calibration_report(struct chip_data_s6sy761 *chip_info) +{ + int ret; + u8 buf[5] = { 0 }; + + buf[0] = SEC_CMD_READ_CALIBRATION_REPORT; + + ret = touch_i2c_read(chip_info->client, &buf[0], 1, &buf[1], 4); + if (ret < 0) { + TPD_INFO("%s: failed to read, ret = %d\n", __func__, ret); + return ret; + } + + TPD_INFO("%s: count:%d, pass count:%d, fail count:%d, status:0x%X\n", + __func__, buf[1], buf[2], buf[3], buf[4]); + + return buf[4]; +} + +int sec_execute_force_calibration(struct chip_data_s6sy761 *chip_info) +{ + int rc = -1; + + if (touch_i2c_write_block(chip_info->client, SEC_CMD_FACTORY_PANELCALIBRATION, 0, NULL) < 0) { + TPD_INFO("%s: Write Cal commend failed!\n", __func__); + return rc; + } + + sec_mdelay(1000); + rc = sec_wait_for_ready(chip_info, SEC_VENDOR_ACK_OFFSET_CAL_DONE); + + return rc; +} + +static void handleFourCornerPoint(struct Coordinate *point, int n) +{ + int i = 0; + struct Coordinate left_most = point[0], right_most = point[0], top_most = point[0], down_most = point[0]; + + if (n < 4) + return; + + for (i = 0; i < n; i++) { + if (right_most.x < point[i].x) { //xmax + right_most = point[i]; + } + if (left_most.x > point[i].x) { //xmin + left_most = point[i]; + } + if (down_most.y < point[i].y) { //ymax + down_most = point[i]; + } + if (top_most.y > point[i].y) { //ymin + top_most = point[i]; + } + } + point[0] = top_most; + point[1] = left_most; + point[2] = down_most; + point[3] = right_most; +} +/****** End of other functions that work for touchpanel_operations callbacks*************/ + +/********* Start of implementation of touchpanel_operations callbacks********************/ +static int sec_reset(void *chip_data) +{ + int ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + TPD_INFO("%s is called\n", __func__); + if (chip_info->is_power_down) { //power off state, no need reset + return 0; + } + + disable_irq_nosync(chip_info->client->irq); + + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { //rsted by rst pin + TPD_INFO("reset by pull down rst pin"); + gpio_direction_output(chip_info->hw_res->reset_gpio, false); + sec_mdelay(5); + gpio_direction_output(chip_info->hw_res->reset_gpio, true); + } else { //otherwise by soft reset + touch_i2c_write_block(chip_info->client, SEC_CMD_SOFT_RESET, 0, NULL); + } + + sec_mdelay(RESET_TO_NORMAL_TIME); + sec_wait_for_ready(chip_info, SEC_ACK_BOOT_COMPLETE); + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SENSE_ON, 0, NULL); + TPD_INFO("%s: write sense on %s\n", __func__, (ret < 0) ? "failed" : "success"); + + enable_irq(chip_info->client->irq); + + return 0; +} + +static int sec_get_vendor(void *chip_data, struct panel_info *panel_data) +{ + int len = 0; + char manu_temp[MAX_DEVICE_MANU_LENGTH] = "SEC_"; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + len = strlen(panel_data->fw_name); + if ((len > 3) && (panel_data->fw_name[len-3] == 'i') && \ + (panel_data->fw_name[len-2] == 'm') && (panel_data->fw_name[len-1] == 'g')) { + panel_data->fw_name[len-3] = 'b'; + panel_data->fw_name[len-2] = 'i'; + panel_data->fw_name[len-1] = 'n'; + } + chip_info->tp_type = panel_data->tp_type; + strlcat(manu_temp, panel_data->manufacture_info.manufacture, MAX_DEVICE_MANU_LENGTH); + strncpy(panel_data->manufacture_info.manufacture, manu_temp, MAX_DEVICE_MANU_LENGTH); + TPD_INFO("chip_info->tp_type = %d, panel_data->fw_name = %s\n", chip_info->tp_type, panel_data->fw_name); + + return 0; +} + +static int sec_get_chip_info(void *chip_data) +{ + return 0; +} + +static int sec_power_control(void *chip_data, bool enable) +{ + int ret = 0; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + TPD_INFO("%s enable :%d\n", __func__, enable); + if (true == enable) { + tp_powercontrol_1v8(chip_info->hw_res, true); + tp_powercontrol_2v8(chip_info->hw_res, true); + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + TPD_INFO("Set the reset_gpio \n"); + gpio_direction_output(chip_info->hw_res->reset_gpio, 1); + } + msleep(RESET_TO_NORMAL_TIME); + sec_wait_for_ready(chip_info, SEC_ACK_BOOT_COMPLETE); + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SENSE_ON, 0, NULL); + TPD_INFO("%s: write sense on %s\n", __func__, (ret < 0) ? "failed" : "success"); + chip_info->is_power_down = false; + } else { + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + TPD_INFO("Set the reset_gpio \n"); + gpio_direction_output(chip_info->hw_res->reset_gpio, 0); + } + usleep_range(100, 100); + tp_powercontrol_2v8(chip_info->hw_res, false); + msleep(5); + tp_powercontrol_1v8(chip_info->hw_res, false); + + chip_info->is_power_down = true; + } + + return ret; +} + +static fw_check_state sec_fw_check(void *chip_data, struct resolution_info *resolution_info, struct panel_info *panel_data) +{ + int ret = 0; + unsigned char data[5] = { 0 }; + bool valid_fw_integrity = false; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + ret = touch_i2c_read_byte(chip_info->client, SEC_READ_FIRMWARE_INTEGRITY); //judge whether fw is right + if (ret < 0) { + TPD_INFO("%s: failed to do integrity check (%d)\n", __func__, ret); + } else { + if (ret & 0x80) { + valid_fw_integrity = true; + } else { + valid_fw_integrity = false; + TPD_INFO("invalid firmware integrity (%d)\n", ret); + } + } + + ret = touch_i2c_read_byte(chip_info->client, SEC_READ_BOOT_STATUS); + if (ret < 0) { + TPD_INFO("%s: failed to read boot status\n", __func__); + } else { + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TS_STATUS, 4, &data[1]); + if (ret < 0) { + TPD_INFO("%s: failed to read touch status\n", __func__); + } + } + if ((((data[0] == SEC_STATUS_APP_MODE) && (data[2] == TOUCH_SYSTEM_MODE_FLASH)) || (ret < 0)) && (valid_fw_integrity == false)) { + TPD_INFO("%s: fw id abnormal, need update\n", __func__); + return FW_ABNORMAL; + } + + memset(data, 0, 5); + touch_i2c_read_block(chip_info->client, SEC_READ_IMG_VERSION, 4, data); + panel_data->TP_FW = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + if (panel_data->manufacture_info.version) + sprintf(panel_data->manufacture_info.version, "0x%x", panel_data->TP_FW); + + // ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SENSE_ON, 0, NULL); + // TPD_INFO("%s: write sense on %s\n", (ret < 0) ? "failed" : "success"); + return FW_NORMAL; +} + +static fw_update_state sec_fw_update(void *chip_data, const struct firmware *fw, bool force) +{ + int i = 0, ret = 0; + u8 buf[4] = {0}; + u8 *fd = NULL; + uint8_t cal_status = 0; + sec_fw_chunk *fw_ch = NULL; + sec_fw_header *fw_hd = NULL; + uint32_t fw_version_in_bin = 0, fw_version_in_ic = 0; + uint32_t config_version_in_bin = 0, config_version_in_ic = 0; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + if (!chip_info) { + TPD_INFO("Chip info is NULL\n"); + return 0; + } + + TPD_INFO("%s is called, force update:%d\n", __func__, force); + + fd = (u8 *)(fw->data); + fw_hd = (sec_fw_header *)(fw->data); + buf[3] = (fw_hd->img_ver >> 24) & 0xff; + buf[2] = (fw_hd->img_ver >> 16) & 0xff; + buf[1] = (fw_hd->img_ver >> 8) & 0xff; + buf[0] = (fw_hd->img_ver >> 0) & 0xff; + fw_version_in_bin = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + memset(buf, 0, 4); + touch_i2c_read_block(chip_info->client, SEC_READ_IMG_VERSION, 4, buf); + fw_version_in_ic = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + TPD_INFO("img version in bin is 0x%04x, img version in ic is 0x%04x\n", fw_version_in_bin, fw_version_in_ic); + + buf[3] = (fw_hd->para_ver >> 24) & 0xff; + buf[2] = (fw_hd->para_ver >> 16) & 0xff; + buf[1] = (fw_hd->para_ver >> 8) & 0xff; + buf[0] = (fw_hd->para_ver >> 0) & 0xff; + config_version_in_bin = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + memset(buf, 0, 4); + touch_i2c_read_block(chip_info->client, SEC_READ_CONFIG_VERSION, 4, buf); + config_version_in_ic = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + TPD_INFO("config version in bin is 0x%04x, config version in ic is 0x%04x\n", config_version_in_bin, config_version_in_ic); + msleep(10); + ret = touch_i2c_read_byte(chip_info->client, SEC_STATUS);//check wet mode status + TPD_INFO("ret is %d\n", ret); + if (ret == 1) { + TPD_INFO("enter water mode\n"); + g_tp->wet_mode_status = 1; + } + ret = touch_i2c_read_byte(chip_info->client, SEC_READ_BOOT_STATUS); + if (ret == SEC_STATUS_BOOT_MODE) { + force = 1; + TPD_INFO("%s: still in bootloader mode, will do force update\n", __func__); + } + + if (!force) { + if (fw_version_in_bin == fw_version_in_ic) { + return FW_NO_NEED_UPDATE; + } + } + + if (sec_enter_fw_mode(chip_info)) { + TPD_INFO("%s: enter fw mode failed\n", __func__); + return FW_UPDATE_ERROR; + } + + if (fw_hd->signature != SEC_FW_HEADER_SIGN) { + TPD_INFO("%s: firmware header error(0x%08x)\n", __func__, fw_hd->signature); + return FW_UPDATE_ERROR; + } + + fd += sizeof(sec_fw_header); + for (i = 0; i < fw_hd->num_chunk; i++) { + fw_ch = (sec_fw_chunk *)fd; + TPD_INFO("update %d chunk(addr: 0x%08x, size: 0x%08x)\n", i, fw_ch->addr, fw_ch->size); + if (fw_ch->signature != SEC_FW_CHUNK_SIGN) { + TPD_INFO("%s: firmware chunk error(0x%08x)\n", __func__, fw_ch->signature); + return FW_UPDATE_ERROR; + } + fd += sizeof(sec_fw_chunk); + ret = sec_chunk_update(chip_info, fw_ch->addr, fw_ch->size, fd); + if (ret < 0) { + TPD_INFO("update chunk failed\n"); + return FW_UPDATE_ERROR; + } + fd += fw_ch->size; + } + + sec_reset(chip_info); + cal_status = sec_read_calibration_report(chip_info); //read out calibration result + if ((cal_status == 0) || (cal_status == 0xFF) || (config_version_in_ic != config_version_in_bin)) { + TPD_INFO("start calibration.\n"); + ret = sec_execute_force_calibration(chip_info); + if (ret < 0) { + TPD_INFO("calibration failed once, try again.\n"); + ret = sec_execute_force_calibration(chip_info); + } + TPD_INFO("calibration %s\n", (ret < 0) ? "failed" : "success"); + } + TPD_INFO("%s: update success\n", __func__); + + return FW_UPDATE_SUCCESS; +} + +static u8 sec_trigger_reason(void *chip_data, int gesture_enable, int is_suspended) +{ + int ret = 0; + int event_id = 0; + u8 left_event_cnt = 0; + int i2c_error_num = 0; + struct sec_event_status *p_event_status = NULL; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + struct fp_underscreen_info tp_info; + + pm_qos_add_request(&pm_qos_req_stp, PM_QOS_CPU_DMA_LATENCY, PM_QOS_VALUE_TP); + memset(chip_info->first_event, 0, SEC_EVENT_BUFF_SIZE); + ret = touch_i2c_read_block(chip_info->client, SEC_READ_ONE_EVENT, SEC_EVENT_BUFF_SIZE, chip_info->first_event); + if (ret < 0) { + while(ret < 0 && i2c_error_num < 4) { + i2c_error_num++; + ret = touch_i2c_read_block(chip_info->client, SEC_READ_ONE_EVENT, SEC_EVENT_BUFF_SIZE, chip_info->first_event); + if (ret >= 0) + break; + } + if (i2c_error_num == 4) { + TPD_INFO("%s: read one event failed\n", __func__); + if (!g_tp->is_suspended) {//suspend not allow reset. + sec_reset(chip_info); + operate_mode_switch(g_tp); + } + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + } + + TPD_DEBUG("first event: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", \ + chip_info->first_event[0], chip_info->first_event[1], chip_info->first_event[2], chip_info->first_event[3],\ + chip_info->first_event[4], chip_info->first_event[5], chip_info->first_event[6], chip_info->first_event[7]); + + if (chip_info->first_event[0] == 0) { + TPD_DETAIL("%s: event buffer is empty\n", __func__); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + p_event_status = (struct sec_event_status *)chip_info->first_event; + if ((p_event_status->stype == TYPE_STATUS_EVENT_VENDOR_INFO) + && chip_info->first_event[1] >= 0x30 && chip_info->first_event[1] <= 0x40) { + TPD_INFO("debug event: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", \ + chip_info->first_event[0], chip_info->first_event[1], chip_info->first_event[2], chip_info->first_event[3],\ + chip_info->first_event[4], chip_info->first_event[5], chip_info->first_event[6], chip_info->first_event[7]); + } + + left_event_cnt = chip_info->first_event[7] & 0x3F; + if ((left_event_cnt > MAX_EVENT_COUNT - 1) || (left_event_cnt == 0xFF)) { + TPD_INFO("%s: event buffer overflow, do clear the buffer\n", __func__); + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_CLEAR_EVENT_STACK, 0, NULL); + if (ret < 0) { + TPD_INFO("%s: clear event buffer failed\n", __func__); + } + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + + event_id = chip_info->first_event[0] & 0x3; + if (event_id == SEC_STATUS_EVENT) { + /* watchdog reset -> send SENSEON command */ + p_event_status = (struct sec_event_status *)chip_info->first_event; + if ((p_event_status->stype == TYPE_STATUS_EVENT_INFO) && + (p_event_status->status_id == SEC_ACK_BOOT_COMPLETE) && (p_event_status->status_data_1 == 0x20)) { + + ret = touch_i2c_write_block(chip_info->client, SEC_CMD_SENSE_ON, 0, NULL); + if (ret < 0) { + TPD_INFO("%s: write sense on failed\n", __func__); + } + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_FW_AUTO_RESET; + } + + /* event queue full-> all finger release */ + if ((p_event_status->stype == TYPE_STATUS_EVENT_ERR) && (p_event_status->status_id == SEC_ERR_EVENT_QUEUE_FULL)) { + TPD_INFO("%s: IC Event Queue is full\n", __func__); + tp_touch_btnkey_release(); + } + + if ((p_event_status->stype == TYPE_STATUS_EVENT_ERR) && (p_event_status->status_id == SEC_ERR_EVENT_ESD)) { + TPD_INFO("%s: ESD detected. run reset\n", __func__); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_EXCEPTION; + } + + if ((p_event_status->stype == TYPE_STATUS_EVENT_VENDOR_INFO) && (p_event_status->status_id == SEC_STATUS_EARDETECTED)) { + chip_info->proximity_status = p_event_status->status_data_1; + TPD_INFO("%s: face detect status %d\n",__func__, chip_info->proximity_status); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_FACE_STATE; + } + + if ((p_event_status->stype == TYPE_STATUS_EVENT_VENDOR_INFO) && (p_event_status->status_id == SEC_STATUS_TOUCHHOLD)) { + if (p_event_status->status_data_1 == 1) { + tp_info.x = (p_event_status->status_data_2 <<4)|((p_event_status->status_data_4 >> 4) & 0x0F); //720; + tp_info.y = (p_event_status->status_data_3 <<4)|((p_event_status->status_data_4 >> 0) & 0x0F);//2728; + tp_info.touch_state = 1; + g_tp->touchold_event = 1; + opticalfp_irq_handler(&tp_info); + TPD_INFO("%s: tp_info.x = %d, tp_info.y= %d\n",__func__, tp_info.x, tp_info.y); + } else if (p_event_status->status_data_1 == 0) { + tp_info.x = (p_event_status->status_data_2 << 4)|((p_event_status->status_data_4 >> 4) & 0x0F); //720; + tp_info.y = (p_event_status->status_data_3 << 4)|((p_event_status->status_data_4 >> 0) & 0x0F);//2728; + tp_info.touch_state = 0; + g_tp->touchold_event = 0; + TPD_INFO("%s: tp_info.x = %d, tp_info.y= %d\n",__func__, tp_info.x, tp_info.y); + opticalfp_irq_handler(&tp_info); + } + TPD_INFO("%s: touch_hold status %d\n",__func__, p_event_status->status_data_1); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + + if ((p_event_status->stype == TYPE_STATUS_EVENT_INFO) && (p_event_status->status_id == SEC_TS_ACK_WET_MODE)) { + chip_info->wet_mode = p_event_status->status_data_1; + TPD_INFO("%s: water wet mode %d\n",__func__, chip_info->wet_mode); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + if ((p_event_status->stype == TYPE_STATUS_EVENT_VENDOR_INFO) && (p_event_status->status_id == SEC_TS_VENDOR_ACK_NOISE_STATUS_NOTI)) { + chip_info->touch_noise_status = !!p_event_status->status_data_1; + TPD_INFO("first event: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", \ + chip_info->first_event[0], chip_info->first_event[1], chip_info->first_event[2], chip_info->first_event[3],\ + chip_info->first_event[4], chip_info->first_event[5], chip_info->first_event[6], chip_info->first_event[7]); + TPD_INFO("%s: TSP NOISE MODE %s[%d]\n", + __func__,chip_info->touch_noise_status == 0 ? "OFF" : "ON", + p_event_status->status_data_1); + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; + } + } else if (event_id == SEC_COORDINATE_EVENT) { + return IRQ_TOUCH; + } else if (event_id == SEC_GESTURE_EVENT) { + return IRQ_GESTURE; + } + pm_qos_remove_request(&pm_qos_req_stp); + return IRQ_IGNORE; +} + +static int sec_get_touch_points(void *chip_data, struct point_info *points, int max_num) +{ + int i = 0; + int t_id = 0; + int ret = -1; + int left_event = 0; + struct sec_event_coordinate *p_event_coord = NULL; + uint32_t obj_attention = 0; + u8 *event_buff; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + event_buff = kzalloc(MAX_EVENT_COUNT*SEC_EVENT_BUFF_SIZE * (sizeof(uint8_t)), GFP_KERNEL); + if (!event_buff) { + TPD_INFO("event_buff kzalloc failed\n"); + pm_qos_remove_request(&pm_qos_req_stp); + return -ENOMEM; + } + p_event_coord = (struct sec_event_coordinate *)chip_info->first_event; + t_id = (p_event_coord->tid - 1); + if ((t_id < max_num) && ((p_event_coord->tchsta == SEC_COORDINATE_ACTION_PRESS) || (p_event_coord->tchsta == SEC_COORDINATE_ACTION_MOVE))) { + points[t_id].x = (p_event_coord->x_11_4 << 4) | (p_event_coord->x_3_0); + points[t_id].y = (p_event_coord->y_11_4 << 4) | (p_event_coord->y_3_0); + points[t_id].z = p_event_coord->z & 0x3F; + points[t_id].width_major = p_event_coord->major; + points[t_id].touch_major = p_event_coord->major; + points[t_id].status = 1; + + if (points[t_id].z <= 0) { + points[t_id].z = 1; + } + obj_attention = obj_attention | (1 << t_id); //set touch bit + } + + left_event = chip_info->first_event[7] & 0x3F; + if (left_event == 0) { + kfree(event_buff); + pm_qos_remove_request(&pm_qos_req_stp); + return obj_attention; + } else if (left_event > max_num - 1) { + TPD_INFO("%s: read left event beyond max touch points\n", __func__); + left_event = max_num - 1; + } + ret = touch_i2c_read_block(chip_info->client, SEC_READ_ALL_EVENT, sizeof(u8) * (SEC_EVENT_BUFF_SIZE) * (left_event), &event_buff[0]); + if (ret < 0) { + TPD_INFO("%s: i2c read all event failed\n", __func__); + kfree(event_buff); + pm_qos_remove_request(&pm_qos_req_stp); + return obj_attention; + } + + for (i = 0; i < left_event; i++) { + p_event_coord = (struct sec_event_coordinate *)&event_buff[i*SEC_EVENT_BUFF_SIZE]; + t_id = (p_event_coord->tid - 1); + if ((t_id < max_num) && ((p_event_coord->tchsta == SEC_COORDINATE_ACTION_PRESS) || (p_event_coord->tchsta == SEC_COORDINATE_ACTION_MOVE))) { + points[t_id].x = (p_event_coord->x_11_4 << 4) | (p_event_coord->x_3_0); + points[t_id].y = (p_event_coord->y_11_4 << 4) | (p_event_coord->y_3_0); + points[t_id].z = p_event_coord->z & 0x3F; + points[t_id].width_major = p_event_coord->major; + points[t_id].touch_major = p_event_coord->major; + points[t_id].status = 1; + + if (points[t_id].z <= 0) { + points[t_id].z = 1; + } + obj_attention = obj_attention | (1 << t_id); //set touch bit + } + } + kfree(event_buff); + pm_qos_remove_request(&pm_qos_req_stp); + return obj_attention; +} + +static int sec_get_gesture_info(void *chip_data, struct gesture_info * gesture) +{ + int i = 0, ret = -1; + uint8_t coord[18] = {0}; + struct Coordinate limitPoint[4]; + struct sec_gesture_status *p_event_gesture = NULL; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + p_event_gesture = (struct sec_gesture_status *)chip_info->first_event; + if (p_event_gesture->coordLen > 18) { + p_event_gesture->coordLen = 18; + } + + ret = touch_i2c_read_block(chip_info->client, SEC_READ_GESTURE_EVENT, p_event_gesture->coordLen, coord); + if (ret < 0) { + TPD_INFO("%s: read gesture data failed\n", __func__); + } + + if (LEVEL_BASIC != tp_debug) { + TPD_INFO("gesture points:"); + for (i = 0; i < p_event_gesture->coordLen/3; i++) { + printk("(%d, %d) ",(coord[3*i] << 4) | ((coord[3*i+2] >> 0) & 0x0F), (coord[3*i+1] << 4) | ((coord[3*i+2] >> 4) & 0x0F)); + } + } + + switch (p_event_gesture->gestureId) //judge gesture type + { + case GESTURE_RIGHT: + gesture->gesture_type = Left2RightSwip; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_end.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_LEFT: + gesture->gesture_type = Right2LeftSwip; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_end.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_DOWN: + gesture->gesture_type = Up2DownSwip; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_end.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_UP: + gesture->gesture_type = Down2UpSwip; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_end.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_DOUBLECLICK: + gesture->gesture_type = DouTap; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end = gesture->Point_start; + break; + + case GESTURE_UP_V: + gesture->gesture_type = UpVee; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_end.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_DOWN_V: + gesture->gesture_type = DownVee; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_end.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_LEFT_V: + gesture->gesture_type = LeftVee; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_end.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_RIGHT_V: + gesture->gesture_type = RightVee; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_end.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + break; + + case GESTURE_O: + gesture->gesture_type = Circle; + gesture->clockwise = (p_event_gesture->data == 0) ? 1 : 0; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + limitPoint[0].x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); //ymin + limitPoint[0].y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + limitPoint[1].x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); //xmin + limitPoint[1].y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + limitPoint[2].x = (coord[9] << 4) | ((coord[11] >> 4) & 0x0F); //ymax + limitPoint[2].y = (coord[10] << 4) | ((coord[11] >> 0) & 0x0F); + limitPoint[3].x = (coord[12] << 4) | ((coord[14] >> 4) & 0x0F); //xmax + limitPoint[3].y = (coord[13] << 4) | ((coord[14] >> 0) & 0x0F); + gesture->Point_end.x = (coord[15] << 4) | ((coord[17] >> 4) & 0x0F); + gesture->Point_end.y = (coord[16] << 4) | ((coord[17] >> 0) & 0x0F); + handleFourCornerPoint(&limitPoint[0], 4); + gesture->Point_1st = limitPoint[0]; //ymin + gesture->Point_2nd = limitPoint[1]; //xmin + gesture->Point_3rd = limitPoint[2]; //ymax + gesture->Point_4th = limitPoint[3]; //xmax + break; + + case GESTURE_DOUBLE_LINE: + gesture->gesture_type = DouSwip; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_end.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_end.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_2nd.x = (coord[9] << 4) | ((coord[11] >> 4) & 0x0F); + gesture->Point_2nd.y = (coord[10] << 4) | ((coord[11] >> 0) & 0x0F); + break; + + case GESTURE_M: + gesture->gesture_type = Mgestrue; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + gesture->Point_2nd.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_2nd.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_3rd.x = (coord[9] << 4) | ((coord[11] >> 4) & 0x0F); + gesture->Point_3rd.y = (coord[10] << 4) | ((coord[11] >> 0) & 0x0F); + gesture->Point_end.x = (coord[12] << 4) | ((coord[14] >> 4) & 0x0F); + gesture->Point_end.y = (coord[13] << 4) | ((coord[14] >> 0) & 0x0F); + break; + + case GESTURE_W: + gesture->gesture_type = Wgestrue; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + gesture->Point_2nd.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_2nd.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_3rd.x = (coord[9] << 4) | ((coord[11] >> 4) & 0x0F); + gesture->Point_3rd.y = (coord[10] << 4) | ((coord[11] >> 0) & 0x0F); + gesture->Point_end.x = (coord[12] << 4) | ((coord[14] >> 4) & 0x0F); + gesture->Point_end.y = (coord[13] << 4) | ((coord[14] >> 0) & 0x0F); + break; + + case GESTURE_SINGLE_TAP: + gesture->gesture_type = SingleTap; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + break; + + case GESTURE_S: + gesture->gesture_type = Sgestrue; + gesture->Point_start.x = (coord[0] << 4) | ((coord[2] >> 4) & 0x0F); + gesture->Point_start.y = (coord[1] << 4) | ((coord[2] >> 0) & 0x0F); + gesture->Point_1st.x = (coord[3] << 4) | ((coord[5] >> 4) & 0x0F); + gesture->Point_1st.y = (coord[4] << 4) | ((coord[5] >> 0) & 0x0F); + gesture->Point_2nd.x = (coord[6] << 4) | ((coord[8] >> 4) & 0x0F); + gesture->Point_2nd.y = (coord[7] << 4) | ((coord[8] >> 0) & 0x0F); + gesture->Point_end.x = (coord[9] << 4) | ((coord[11] >> 4) & 0x0F); + gesture->Point_end.y = (coord[10] << 4) | ((coord[11] >> 0) & 0x0F); + break; + + + default: + gesture->gesture_type = UnkownGesture; + break; + } + + TPD_INFO("%s, gesture_id: 0x%x, gesture_type: %d, clockwise: %d, points: (%d, %d)(%d, %d)(%d, %d)(%d, %d)(%d, %d)(%d, %d)\n", \ + __func__, p_event_gesture->gestureId, gesture->gesture_type, gesture->clockwise, \ + gesture->Point_start.x, gesture->Point_start.y, \ + gesture->Point_end.x, gesture->Point_end.y, \ + gesture->Point_1st.x, gesture->Point_1st.y, \ + gesture->Point_2nd.x, gesture->Point_2nd.y, \ + gesture->Point_3rd.x, gesture->Point_3rd.y, \ + gesture->Point_4th.x, gesture->Point_4th.y); + pm_qos_remove_request(&pm_qos_req_stp); + + return 0; +} + +static int sec_mode_switch(void *chip_data, work_mode mode, bool flag) +{ + int ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + if (chip_info->is_power_down) { + sec_power_control(chip_info, true); + } + + switch(mode) { + case MODE_NORMAL: + ret = 0; + break; + + case MODE_SLEEP: + ret = sec_power_control(chip_info, false); + if (ret < 0) { + TPD_INFO("%s: power down failed\n", __func__); + } + break; + + case MODE_GESTURE: + ret = sec_enable_black_gesture(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: sec enable gesture failed.\n", __func__); + return ret; + } + break; + + case MODE_EDGE: + ret = sec_enable_edge_limit(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: sec enable edg limit failed.\n", __func__); + return ret; + } + break; + + case MODE_CHARGE: + ret = sec_enable_charge_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable charge mode : %d failed\n", __func__, flag); + } + break; + case MODE_WIRELESS_CHARGE: + ret = sec_enable_wireless_charge_mode(chip_info, flag); + if (ret < 0) + TPD_INFO("%s: enable wireless charge mode : %d failes\n", __func__, flag); + break; + case MODE_EARSENSE: + ret = sec_enable_earsense_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable earsense mode : %d failed\n", __func__, flag); + } + break; + + case MODE_FACE_DETECT: + ret = sec_enable_face_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable face detect mode : %d failed\n", __func__, flag); + } + break; + + case MODE_FACE_CALIBRATE: + ret = sec_face_reduce_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable face reduce mode : %d failed\n", __func__, flag); + } + break; + case MODE_PALM_REJECTION: + ret = sec_enable_palm_reject(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable palm rejection: %d failed\n", __func__, flag); + } + break; + + case MODE_GAME: + ret = sec_enable_game_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: enable game mode: %d failed\n", __func__, flag); + } + break; + + case MODE_REFRESH_SWITCH: + ret = sec_refresh_switch_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: swhitch refresh rate mode: %d failed\n", __func__, flag); + } + break; + + case MODE_TOUCH_HOLD: + ret = sec_touchhold_switch_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: open touchhold mode: %d failed\n", __func__, flag); + } + break; + + case MODE_TOUCH_AREA_SWITCH: + ret = sec_toucharea_switch_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: switch touchhold area: %d failed\n", __func__, flag); + } + break; + + case MODE_LIMIT_SWITCH: + ret = sec_limit_switch_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: limit switch: %d failed\n", __func__, flag); + } + break; + + case MODE_GESTURE_SWITCH: + ret = sec_gesture_switch_mode(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: switch gestrue mode: %d failed\n", __func__, flag); + } + break; + + case MODE_AUDIO_NOISE: + ret = sec_audio_noise_mode(chip_info, flag); + if (ret < 0) + TPD_INFO("%s: switch audio noise mode : %d failes\n", __func__, flag); + break; + + case MODE_REVERSE_WIRELESS_CHARGE: + ret = sec_enable_reverse_wireless_charge(chip_info, flag); + if (ret < 0) + TPD_INFO("%s: switch reverse wireless mode : %d failes\n", __func__, flag); + break; + case MODE_WET_DETECT: + ret = sec_enable_wet_mode(chip_info, flag); + if (ret < 0) + TPD_INFO("%s: change wet mode : %d failes\n", __func__, flag); + break; + default: + TPD_INFO("%s: Wrong mode.\n", __func__); + } + + return ret; +} + +static int sec_get_face_detect(void * chip_data) +{ + int state = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + if (chip_info->proximity_status == 0x2E) { + state = 0; //far + } else if (chip_info->proximity_status == 0) { + state = 1; //near + } + return state; +} + + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +extern unsigned int upmu_get_rgs_chrdet(void); +static int sec_get_usb_state(void) +{ + return upmu_get_rgs_chrdet(); +} +#else +static int sec_get_usb_state(void) +{ + return 0; +} +#endif + +static struct touchpanel_operations sec_ops = { + .get_vendor = sec_get_vendor, + .get_chip_info = sec_get_chip_info, + .reset = sec_reset, + .power_control = sec_power_control, + .fw_check = sec_fw_check, + .fw_update = sec_fw_update, + .trigger_reason = sec_trigger_reason, + .get_touch_points = sec_get_touch_points, + .get_gesture_info = sec_get_gesture_info, + .mode_switch = sec_mode_switch, + .get_usb_state = sec_get_usb_state, + .get_face_state = sec_get_face_detect, +}; +/********* End of implementation of touchpanel_operations callbacks**********************/ + + +/**************** Start of implementation of debug_info proc callbacks************************/ +int sec_fix_tmode(struct chip_data_s6sy761 *chip_info, u8 mode, u8 state) +{ + int ret = -1; + u8 tBuff[2] = { mode, state }; + + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_STATEMANAGE_ON, STATE_MANAGE_OFF); + sec_mdelay(20); + ret |= touch_i2c_write_block(chip_info->client, SEC_CMD_CHG_SYSMODE, sizeof(tBuff), tBuff); + sec_mdelay(20); + + return ret; +} + +int sec_release_tmode(struct chip_data_s6sy761 *chip_info) +{ + int ret = -1; + + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_STATEMANAGE_ON, STATE_MANAGE_ON); + sec_mdelay(20); + + return ret; +} + +static int sec_read_self(struct chip_data_s6sy761 *chip_info, u8 type, char *data, int len) +{ + int ret = 0; + unsigned int data_len = (chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM) * 2; + + if (len != data_len) { + return -1; + } + + ret = sec_fix_tmode(chip_info, TOUCH_SYSTEM_MODE_TOUCH, TOUCH_MODE_STATE_TOUCH); + if (ret < 0) { + TPD_INFO("%s: fix touch mode failed\n", __func__); + goto err_out; + } + + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_SELF_RAW_TYPE, type); + if (ret < 0) { + TPD_INFO("%s: Set self type failed\n", __func__); + goto err_out; + } + + sec_mdelay(50); + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_SELF_RAWDATA, data_len, data); + if (ret < 0) { + TPD_INFO("%s: read self failed!\n", __func__); + } + + /* release data monitory (unprepare AFE data memory) */ + ret |= touch_i2c_write_byte(chip_info->client, SEC_CMD_SELF_RAW_TYPE, TYPE_INVALID_DATA); + if (ret < 0) { + TPD_INFO("%s: Set self type failed\n", __func__); + } + +err_out: + ret |= sec_release_tmode(chip_info); + + return ret; +} + +static int sec_read_mutual(struct chip_data_s6sy761 *chip_info, u8 type, char *data, int len) +{ + int ret = 0; + u8 buf[2] = {0}; + unsigned int data_len = (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) * 2; + + if ((len > data_len) || (len % chip_info->hw_res->TX_NUM != 0)) { + return -1; + } + + ret = sec_fix_tmode(chip_info, TOUCH_SYSTEM_MODE_TOUCH, TOUCH_MODE_STATE_TOUCH); + if (ret < 0) { + TPD_INFO("%s: fix touch mode failed\n", __func__); + goto err_out; + } + + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, type); + if (ret < 0) { + TPD_INFO("%s: Set mutual type failed\n", __func__); + goto err_out; + } + + sec_mdelay(20); + buf[0] = (u8)((len >> 8) & 0xFF); + buf[1] = (u8)(len & 0xFF); + touch_i2c_write_block(chip_info->client, SEC_CMD_TOUCH_RAWDATA_SETLEN, 2, buf); + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_RAWDATA, len, data); + if (ret < 0) { + TPD_INFO("%s: read mutual failed!\n", __func__); + } + + /* release data monitory (unprepare AFE data memory) */ + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, TYPE_INVALID_DATA); + if (ret < 0) { + TPD_INFO("%s: Set mutual type failed\n", __func__); + } + +err_out: + ret |= sec_release_tmode(chip_info); + + return ret; +} + +static void sec_delta_read(struct seq_file *s, void *chip_data) +{ + u8 *data = NULL; + int16_t x = 0, y = 0, z = 0, temp_delta = 0, ret = 0; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + int readbytes = chip_info->hw_res->TX_NUM * (chip_info->hw_res->RX_NUM) * 2; + + data = kmalloc(readbytes, GFP_KERNEL); + if (!data) { + return; + } + + memset(data, 0, readbytes); + ret = sec_read_mutual(chip_info, TYPE_SIGNAL_DATA, data, readbytes); + if (ret < 0) { + seq_printf(s, "read delta failed\n"); + goto kfree_out; + } + + for (x = 0; x < chip_info->hw_res->TX_NUM; x++) { + seq_printf(s, "\n[%2d]", x); + for (y = chip_info->hw_res->RX_NUM - 1; y >= 0; y--) { + z = chip_info->hw_res->RX_NUM * x + y; + temp_delta = ((data[z * 2] << 8) | data[z * 2 + 1]); + seq_printf(s, "%4d, ", temp_delta); + } + } + seq_printf(s, "\n"); + +kfree_out: + kfree(data); + return; +} + +static void sec_baseline_read(struct seq_file *s, void *chip_data) +{ + u8 *data = NULL; + int16_t x = 0, y = 0, z = 0, temp_delta = 0, ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + int readbytes = (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) * 2; + + data = kmalloc(readbytes, GFP_KERNEL); + if (!data) { + return; + } + + //read decoded data + memset(data, 0, readbytes); + ret = sec_read_mutual(chip_info, TYPE_DECODED_DATA, data, readbytes); + if (ret < 0) { + seq_printf(s, "read rawdata failed\n"); + goto kfree_out; + } + + seq_printf(s, "DECODED DATA:"); + for (x = 0; x < chip_info->hw_res->TX_NUM; x++) { + seq_printf(s, "\n[%2d]", x); + for (y = chip_info->hw_res->RX_NUM - 1; y >= 0; y--) { + z = chip_info->hw_res->RX_NUM * x + y; + temp_delta = (data[z * 2] << 8) | data[z * 2 + 1]; + seq_printf(s, "%4d, ", temp_delta); + } + } + seq_printf(s, "\n"); + + //read ambient data + memset(data, 0, readbytes); + ret = sec_read_mutual(chip_info, TYPE_AMBIENT_DATA, data, readbytes); + if (ret < 0) { + seq_printf(s, "read rawdata failed\n"); + goto kfree_out; + } + + seq_printf(s, "AMBIENT DATA:"); + for (x = 0; x < chip_info->hw_res->TX_NUM; x++) { + seq_printf(s, "\n[%2d]", x); + for (y = chip_info->hw_res->RX_NUM - 1; y >= 0; y--) { + z = chip_info->hw_res->RX_NUM * x + y; + temp_delta = (data[z * 2] << 8) | data[z * 2 + 1]; + seq_printf(s, "%4d, ", temp_delta); + } + } + seq_printf(s, "\n"); + +kfree_out: + kfree(data); + return; +} + +static void sec_self_delta_read(struct seq_file *s, void *chip_data) +{ + u8 *data = NULL; + int16_t x = 0, rx_offset = 0, temp_delta = 0, ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + int readbytes = (chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM) * 2; + + data = kmalloc(readbytes, GFP_KERNEL); + if (!data) { + return; + } + + memset(data, 0, readbytes); + ret = sec_read_self(chip_info, TYPE_SIGNAL_DATA, data, readbytes); + if (ret < 0) { + seq_printf(s, "read self delta failed\n"); + goto kfree_out; + } + + seq_printf(s, "TX:\n"); + for (x = 0; x < chip_info->hw_res->TX_NUM; x++) { + temp_delta = (data[x * 2] << 8) | data[x * 2 + 1]; + seq_printf(s, "%4d, ", temp_delta); + } + + seq_printf(s, "\nRX:\n"); + rx_offset = chip_info->hw_res->TX_NUM * 2; + for (x = 0; x < chip_info->hw_res->RX_NUM; x++) { + temp_delta = (data[x * 2 + rx_offset] << 8) | data[x * 2 + 1 + rx_offset]; + seq_printf(s, "%4d, ", temp_delta); + } + seq_printf(s, "\n"); + +kfree_out: + kfree(data); + return; +} + +static void sec_self_raw_read(struct seq_file *s, void *chip_data) +{ + u8 *data = NULL; + int16_t x = 0, rx_offset = 0, temp_delta = 0, ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + int readbytes = (chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM) * 2; + + data = kmalloc(readbytes, GFP_KERNEL); + if (!data) { + return; + } + + memset(data, 0, readbytes); + ret = sec_read_self(chip_info, TYPE_RAW_DATA, data, readbytes); + if (ret < 0) { + seq_printf(s, "read self rawdata failed\n"); + goto kfree_out; + } + + seq_printf(s, "TX:\n"); + for (x = 0; x < chip_info->hw_res->TX_NUM; x++) { + temp_delta = (data[x * 2] << 8) | data[x * 2 + 1]; + seq_printf(s, "%4d, ", temp_delta); + } + + seq_printf(s, "\nRX:\n"); + rx_offset = chip_info->hw_res->TX_NUM * 2; + for (x = 0; x < chip_info->hw_res->RX_NUM; x++) { + temp_delta = (data[x * 2 + rx_offset] << 8) | data[x * 2 + 1 + rx_offset]; + seq_printf(s, "%4d, ", temp_delta); + } + seq_printf(s, "\n"); + +kfree_out: + kfree(data); + return; +} + +static void sec_main_register_read(struct seq_file *s, void *chip_data) +{ + u8 buf[4] = {0}; + int state = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + state = sec_read_calibration_report(chip_info); + seq_printf(s, "calibration status: 0x%02x\n", state); + + state = sec_get_verify_result(chip_info); + seq_printf(s, "calibration result: 0x%02x\n", state); + + state = touch_i2c_read_byte(chip_info->client, SET_CMD_SET_CHARGER_MODE); + seq_printf(s, "charger state: 0x%02x\n", state); + + memset(buf, 0, 4); + touch_i2c_read_block(chip_info->client, SEC_READ_ID, 3, buf); + seq_printf(s, "boot state: 0x%02x\n", buf[0]); + + state = touch_i2c_read_byte(chip_info->client, 0x30); + seq_printf(s, "touch function: 0x%02x(proximity/wetmode/palm/stylus/glove/cover/hover/touch)\n", state); + + state = touch_i2c_read_byte(chip_info->client, 0x3B); + seq_printf(s, "wetmode state: 0x%02x\n", state); + + state = touch_i2c_read_word(chip_info->client, SEC_CMD_WAKEUP_GESTURE_MODE); + seq_printf(s, "gesture mode: 0x%04x\n", state); + + memset(buf, 0, 4); + touch_i2c_read_block(chip_info->client, SEC_READ_IMG_VERSION, 4, buf); + seq_printf(s, "fw img version: 0x%08x\n", (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); + + memset(buf, 0, 4); + touch_i2c_read_block(chip_info->client, SEC_READ_CONFIG_VERSION, 4, buf); + seq_printf(s, "config version: 0x%08x\n", (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); + + state = touch_i2c_read_byte(chip_info->client, SEC_CMD_STATEMANAGE_ON); + seq_printf(s, "auto change enabled: 0x%02x\n", state); + + state = touch_i2c_read_byte(chip_info->client, SEC_CMD_HOVER_DETECT); + seq_printf(s, "earsense state: 0x%02x\n", state); + + state = touch_i2c_read_word(chip_info->client, SEC_CMD_PALM_SWITCH); + seq_printf(s, "palm state: 0x%04x(0x0041-off/0x0061-on)\n", state); + + state = touch_i2c_read_word(chip_info->client, SEC_CMD_GRIP_SWITCH); + seq_printf(s, "grip state: 0x%04x(0x0000-off/0x2000-on)\n", state); + + memset(buf, 0, 4); + touch_i2c_read_block(chip_info->client, SEC_READ_TS_STATUS, 4, buf); + seq_printf(s, "power mode: 0x%02x[normal-0x02/lpwg-0x05], 0x%02x[indle-0x00/active-0x02]\n", buf[1], buf[3]); + return; +} + +static void sec_reserve_read(struct seq_file *s, void *chip_data) +{ + static int int_state = 1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + if (int_state) { + int_state = 0; + touch_i2c_write_byte(chip_info->client, SEC_CMD_INTERRUPT_SWITCH, 1); //disable interrupt + } else { + int_state = 1; + touch_i2c_write_block(chip_info->client, SEC_CMD_CLEAR_EVENT_STACK, 0, NULL); //clear event buffer + touch_i2c_write_byte(chip_info->client, SEC_CMD_INTERRUPT_SWITCH, 0); //enable interrupt + } +} + +static struct debug_info_proc_operations debug_info_proc_ops = { + .limit_read = sec_limit_read, + .delta_read = sec_delta_read, + .self_delta_read = sec_self_delta_read, + .baseline_read = sec_baseline_read, + .self_raw_read = sec_self_raw_read, + .main_register_read = sec_main_register_read, + .reserve_read = sec_reserve_read, +}; + +static void sec_earsese_rawdata_read(void *chip_data, char *rawdata, int read_len) +{ + int ret = 0; + u8 buf[2] = {0}; + int i = 0, j = 0; + int8_t tmp_byte[2] = {0}; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + uint8_t len_y = chip_info->hw_res->EARSENSE_RX_NUM; + uint8_t len_x = chip_info->hw_res->EARSENSE_TX_NUM; + + if ((!chip_info) || (!rawdata)) + return; + + buf[0] = (u8)((read_len >> 8) & 0xFF); + buf[1] = (u8)(read_len & 0xFF); + touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, TYPE_DATA_RAWDATA); + touch_i2c_write_block(chip_info->client, SEC_CMD_TOUCH_RAWDATA_SETLEN, 2, buf); + ret = touch_i2c_read_block(chip_info->client, SEC_CMD_TOUCH_RAWDATA_READ, read_len, rawdata); + if (ret < 0) { + TPD_INFO("read rawdata failed\n"); + return; + } + TPD_INFO("sec_earsese_rawdata_read lenx = %d, leny =%d\n",len_x,len_y); + for(i = 0; i < read_len; i++ ) { + TPD_INFO("rawdata = %d\n",rawdata[i]); + } + for (i = 0; i < len_y; i++) { + for (j = 0; j < len_x/2; j++) { + tmp_byte[0] = rawdata[2*(len_x*i+j)]; + tmp_byte[1] = rawdata[2*(len_x*i+j)+1]; + rawdata[2*(len_x*i+j)] = rawdata[2*(len_x*i+len_x-1-j)+1]; + rawdata[2*(len_x*i+j)+1] = rawdata[2*(len_x*i+len_x-1-j)]; + rawdata[2*(len_x*i+len_x-1-j)] = tmp_byte[1]; + rawdata[2*(len_x*i+len_x-1-j)+1] = tmp_byte[0]; + } + } + if (len_x%2) { + j = len_x/2; + for (i = 0; i < len_y; i++) { + tmp_byte[0] = rawdata[2*(len_x*i+j)]; + rawdata[2*(len_x*i+j)] = rawdata[2*(len_x*i+j)+1]; + rawdata[2*(len_x*i+j)+1] = tmp_byte[0]; + } + } + return; +} + +static void sec_earsese_delta_read(void *chip_data, char *earsense_delta, int read_len) +{ + int ret = 0, hover_status = 0, data_type = 0; + u8 buf[2] = {0}; + int i = 0, j = 0; + int8_t tmp_byte[2] = {0}; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + uint8_t len_x = chip_info->hw_res->EARSENSE_TX_NUM; + uint8_t len_y = chip_info->hw_res->EARSENSE_RX_NUM; + + if (!chip_info) + return ; + + if (!earsense_delta) { + TPD_INFO("earsense_delta is NULL\n"); + return; + } + + buf[0] = (u8)((read_len >> 8) & 0xFF); + buf[1] = (u8)(read_len & 0xFF); + hover_status = touch_i2c_read_byte(chip_info->client, SEC_CMD_HOVER_DETECT); //read hover state + data_type = touch_i2c_read_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE); //read current data type + if (hover_status && (data_type != TYPE_DATA_DELTA)) { + touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, TYPE_DATA_DELTA); + sec_mdelay(20); + } else if (!hover_status && (data_type != TYPE_SIGNAL_DATA)){ + touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, TYPE_SIGNAL_DATA); + sec_mdelay(20); + } + + touch_i2c_write_block(chip_info->client, SEC_CMD_TOUCH_RAWDATA_SETLEN, 2, buf); + ret = touch_i2c_read_block(chip_info->client, SEC_CMD_TOUCH_DELTA_READ, read_len, earsense_delta); + if (ret < 0) { + TPD_INFO("read delta failed\n"); + return; + } + for(i = 0; i < read_len; i++ ) { + TPD_INFO("earsense_delta = %d\n",earsense_delta[i]); + } + for (i = 0; i < len_y; i++) { + for (j = 0; j < len_x/2; j++) { + tmp_byte[0] = earsense_delta[2*(len_x*i+j)]; + tmp_byte[1] = earsense_delta[2*(len_x*i+j)+1]; + earsense_delta[2*(len_x*i+j)] = earsense_delta[2*(len_x*i+len_x-1-j)+1]; + earsense_delta[2*(len_x*i+j)+1] = earsense_delta[2*(len_x*i+len_x-1-j)]; + earsense_delta[2*(len_x*i+len_x-1-j)] = tmp_byte[1]; + earsense_delta[2*(len_x*i+len_x-1-j)+1] = tmp_byte[0]; + } + } + if (len_x%2) { + j = len_x/2; + for (i = 0; i < len_y; i++) { + tmp_byte[0] = earsense_delta[2*(len_x*i+j)]; + earsense_delta[2*(len_x*i+j)] = earsense_delta[2*(len_x*i+j)+1]; + earsense_delta[2*(len_x*i+j)+1] = tmp_byte[0]; + } + } + return; +} + +static void sec_earsese_selfdata_read( void *chip_data, char *self_data, int read_len) +{ + int i = 0, ret = 0; + int8_t tmp = 0; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + if ((!chip_info) || (!self_data)) + return ; + + ret = touch_i2c_read_block(chip_info->client, SEC_CMD_TOUCH_SELFDATA_READ, read_len, self_data); + if (ret < 0) { + TPD_INFO("read selfdata failed\n"); + return; + } + for(i = 0; i < read_len; i++ ) { + TPD_INFO("self_data = %d\n",self_data[i]); + } + for (i = 0; i < chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM; i++) { + tmp = self_data[2*i]; + self_data[2*i] = self_data[2*i + 1]; + self_data[2*i + 1] = tmp; + } + return; +} + + +static struct earsense_proc_operations earsense_proc_ops = { + .rawdata_read = sec_earsese_rawdata_read, + .delta_read = sec_earsese_delta_read, + .self_data_read = sec_earsese_selfdata_read, +}; +/***************** End of implementation of debug_info proc callbacks*************************/ +static void sec_swap(u8 *a, u8 *b) +{ + u8 temp = *a; + *a = *b; + *b = temp; +} + +static void rearrange_sft_result(u8 *data, int length) +{ + int i = 0; + + for(i = 0; i < length; i += 4) { + sec_swap(&data[i], &data[i + 3]); + sec_swap(&data[i + 1], &data[i + 2]); + } +} + +static int sec_execute_selftest(struct seq_file *s, struct chip_data_s6sy761 *chip_info, struct sec_testdata *sec_testdata) +{ + int rc = -1; + u8 tpara[2] = {0x25, 0x40}; + u8 *rBuff = NULL; + int i; + int result_size = SEC_SELFTEST_REPORT_SIZE + sec_testdata->TX_NUM * sec_testdata->RX_NUM * 2; + + /* save selftest result in flash */ + tpara[0] = 0x21; + + rBuff = kzalloc(result_size, GFP_KERNEL); + if (!rBuff) { + seq_printf(s, "kzalloc space failed\n"); + return -ENOMEM; + } + + //send self test cmd + rc = touch_i2c_write_block(chip_info->client, SEC_CMD_SELFTEST, 2, tpara); + if (rc < 0) { + TPD_INFO("%s: Send selftest cmd failed!\n", __func__); + seq_printf(s, "Step 0-0:Send selftest cmd failed!\n"); + goto ERR_EXIT; + } + + sec_mdelay(350); + + rc = sec_wait_for_ready(chip_info, SEC_VENDOR_ACK_SELF_TEST_DONE); + if (rc < 0) { + TPD_INFO("%s: Selftest execution time out!\n", __func__); + seq_printf(s, "Step 0-1:Selftest execution time out!\n"); + goto ERR_EXIT; + } + + rc = touch_i2c_read_block(chip_info->client, SEC_READ_SELFTEST_RESULT, result_size, rBuff); + if (rc < 0) { + TPD_INFO("%s: read selftest relest failed\n", __func__); + seq_printf(s, "Step 0-2:read selftest relest failed\n"); + goto ERR_EXIT; + } + rearrange_sft_result(rBuff, result_size); + + TPD_INFO("sec_ts : \n"); + for (i = 0; i < 80; i += 4) { + if (i / 4 == 0) TPD_DEBUG_NTAG("SIG"); + else if (i / 4 == 1) TPD_DEBUG_NTAG("VER"); + else if (i / 4 == 2) TPD_DEBUG_NTAG("SIZ"); + else if (i / 4 == 3) TPD_DEBUG_NTAG("CRC"); + else if (i / 4 == 4) TPD_DEBUG_NTAG("RES"); + else if (i / 4 == 5) TPD_DEBUG_NTAG("COU"); + else if (i / 4 == 6) TPD_DEBUG_NTAG("PAS"); + else if (i / 4 == 7) TPD_DEBUG_NTAG("FAI"); + else if (i / 4 == 8) TPD_DEBUG_NTAG("CHA"); + else if (i / 4 == 9) TPD_DEBUG_NTAG("AMB"); + else if (i / 4 == 10) TPD_DEBUG_NTAG("RXS"); + else if (i / 4 == 11) TPD_DEBUG_NTAG("TXS"); + else if (i / 4 == 12) TPD_DEBUG_NTAG("RXO"); + else if (i / 4 == 13) TPD_DEBUG_NTAG("TXO"); + else if (i / 4 == 14) TPD_DEBUG_NTAG("RXG"); + else if (i / 4 == 15) TPD_DEBUG_NTAG("TXG"); + else if (i / 4 == 16) TPD_DEBUG_NTAG("RXR"); + else if (i / 4 == 17) TPD_DEBUG_NTAG("TXT"); + else if (i / 4 == 18) TPD_DEBUG_NTAG("RXT"); + else if (i / 4 == 19) TPD_DEBUG_NTAG("TXR"); + + TPD_DEBUG_NTAG(": %2X, %2X, %2X, %2X \n", rBuff[i], rBuff[i + 1], rBuff[i + 2], rBuff[i + 3]); + + if (i / 4 == 4) { + /* RX, RX open check. */ + if ((rBuff[i + 3] & 0x30) != 0) { + rc = 0; + seq_printf(s, "Step 0-3:RX, RX open check failed\n"); + } + /* TX, RX GND(VDD) short check. */ + else if ((rBuff[i + 3] & 0xC0) != 0) { + rc = 0; + seq_printf(s, "Step 0-4:TX, RX GND(VDD) short check failed\n"); + } + /* RX-RX, TX-TX short check. */ + else if ((rBuff[i + 2] & 0x03) != 0) { + rc = 0; + seq_printf(s, "Step 0-5:RX-RX, TX-TX short check failed\n"); + } + /* TX-RX short check. */ + else if ((rBuff[i + 2] & 0x04) != 0) { + rc = 0; + seq_printf(s, "Step 0-6:TX-RX short check failed\n"); + } + else + rc = 1; + } + + } + +ERR_EXIT: + kfree(rBuff); + return rc; +} + +int sec_execute_p2ptest(struct seq_file *s, struct chip_data_s6sy761 *chip_info, struct sec_testdata *sec_testdata) +{ + int rc; + u8 tpara[2] = {0x0F, 0x11}; + + TPD_INFO("%s: P2P test start!\n", __func__); + rc = touch_i2c_write_block(chip_info->client, SEC_CMD_SET_P2PTEST_MODE, 2, tpara); + if (rc < 0) { + seq_printf(s, "%s: Send P2Ptest Mode cmd failed!\n", __func__); + goto err_exit; + } + + sec_mdelay(15); + + tpara[0] = 0x00; + tpara[1] = 0x64; + rc = touch_i2c_write_block(chip_info->client, SEC_CMD_P2PTEST, 2, tpara); + if (rc < 0) { + seq_printf(s, "%s: Send P2Ptest cmd failed!\n", __func__); + goto err_exit; + } + + sec_mdelay(1000); + + rc = sec_wait_for_ready(chip_info, SEC_VENDOR_ACK_P2P_TEST_DONE); + if (rc < 0) { + seq_printf(s, "%s: P2Ptest execution time out!\n", __func__); + goto err_exit; + } + + TPD_INFO("%s: P2P test done!\n", __func__); + +err_exit: + return rc; +} + +static void store_to_file(int fd, char* format, ...) +{ + va_list args; + char buf[64] = {0}; + + va_start(args, format); + vsnprintf(buf, 64, format, args); + va_end(args); + + if(fd >= 0) { + ksys_write(fd, buf, strlen(buf)); + } +} + +static uint32_t search_for_item(const struct firmware *fw, int item_cnt, uint8_t item_index) +{ + int i = 0; + uint32_t item_offset = 0; + struct sec_test_item_header *item_header = NULL; + uint32_t *p_item_offset = (uint32_t *)(fw->data + 16); + + for (i = 0; i < item_cnt; i++) { + item_header = (struct sec_test_item_header *)(fw->data + p_item_offset[i]); + if (item_header->item_bit == item_index) { //check the matched item offset + item_offset = p_item_offset[i]; + } + } + + return item_offset; +} + +static void sec_auto_test(struct seq_file *s, void *chip_data, struct sec_testdata *sec_testdata) +{ + u8 type = 0; + uint32_t err_cnt = 0, item_offset = 0; + uint8_t *pRead = NULL; + int eint_status = 0, eint_count = 0, read_gpio_num = 0; + int16_t nodeData = 0, Buff16 = 0, Buff16_2 = 0, nodeGap = 0; + int i = 0, j = 0, item_cnt = 0, iArrayIndex = 0, iArrayIndex_2 = 0, ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + const uint32_t readbytes = sec_testdata->TX_NUM * sec_testdata->RX_NUM * 2; + const uint32_t readselfbytes = (sec_testdata->TX_NUM + sec_testdata->RX_NUM) * 2; + struct sec_test_item_header *item_header = NULL; + int32_t *p_mutual_p = NULL, *p_mutual_n = NULL, *p_mutualGap_p = NULL, *p_mutualGap_n = NULL; + int32_t *p_tx_offset_p = NULL, *p_tx_offset_n = NULL, *p_rx_offset_p = NULL, *p_rx_offset_n = NULL; + int32_t *p_p2p_p = NULL, *p_p2p_n = NULL; + + + //interrupt pin short test + read_gpio_num = 10; + touch_i2c_write_byte(chip_info->client, SEC_CMD_INTERRUPT_SWITCH, 1); //disable interrupt + touch_i2c_write_block(chip_info->client, SEC_CMD_CLEAR_EVENT_STACK, 0, NULL); //clear event buffer + while (read_gpio_num--) { + sec_mdelay(5); + eint_status = gpio_get_value(sec_testdata->irq_gpio); + if (eint_status == 1) { + eint_count--; + } else { + eint_count++; + } + } + TPD_INFO("TP EINT PIN direct short test! eint_count = %d\n", eint_count); + if (eint_count == 10) { + TPD_INFO("error : TP EINT PIN direct short!\n"); + err_cnt++; + seq_printf(s, "Step 0:eint_status is low, TP EINT direct short\n"); + goto ERR_INT; + + return; + } + touch_i2c_write_byte(chip_info->client, SEC_CMD_INTERRUPT_SWITCH, 0); //enable interrupt + + for (i = 0; i < 8*sizeof(sec_testdata->test_item); i++) { + if ((sec_testdata->test_item >> i) & 0x01 ) { + item_cnt++; + } + } + + pRead = kzalloc(readbytes, GFP_KERNEL); + if (!pRead) { + TPD_INFO("kzalloc space failed\n"); + seq_printf(s, "kzalloc space failed\n"); + return; + } + + /* execute selftest */ + ret = sec_execute_selftest(s, chip_info, sec_testdata); + if (ret <= 0) { + err_cnt++; + TPD_INFO("%s: execute selftest failed\n", __func__); + seq_printf(s, "Step 0:execute selftest failed\n"); + if (ret < 0) + goto ERR_OUT; + } + + //test item mutual_raw offset_data_sec + if (sec_testdata->test_item & (1 << TYPE_MUTUAL_RAW_OFFSET_DATA_SDC)) { + TPD_INFO("do test item mutual_raw offset_data_sec\n"); + + item_offset = search_for_item(sec_testdata->fw, item_cnt, TYPE_MUTUAL_RAW_OFFSET_DATA_SDC); + if (item_offset == 0) { + err_cnt++; + TPD_INFO("search for item limit offset failed\n"); + seq_printf(s, "Step 1:search for item limit offset failed\n"); + goto ERR_OUT; + } + item_header = (struct sec_test_item_header *)(sec_testdata->fw->data + item_offset); + if (item_header->item_magic != 0x4F50504F) { + err_cnt++; + TPD_INFO("test item: %d magic number(%4x) is wrong\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->item_magic); + seq_printf(s, "Step 2:test item: %d magic number(%4x) is wrong\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->item_magic); + goto ERR_OUT; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_mutual_p = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset); + p_mutualGap_p = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset + 4*sec_testdata->TX_NUM*sec_testdata->RX_NUM); + p_mutual_n = (int32_t *)(sec_testdata->fw->data + item_header->floor_limit_offset); + p_mutualGap_n = (int32_t *)(sec_testdata->fw->data + item_header->floor_limit_offset + 4*sec_testdata->TX_NUM*sec_testdata->RX_NUM); + } else { + err_cnt++; + TPD_INFO("item: %d has invalid limit type(%d)\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->item_limit_type); + seq_printf(s, "Step 3:item: %d has invalid limit type(%d)\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->item_limit_type); + goto ERR_OUT; + } + if (item_header->para_num == 0) { + } else { + err_cnt++; + TPD_INFO("item: %d has %d parameter\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->para_num); + seq_printf(s, "Step 4:item: %d has %d parameter\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->para_num); + goto ERR_OUT; + } + + /* set reference data */ + type = TYPE_OFFSET_DATA_SDC; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, type); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: set OFFSET_DATA_SEC type failed\n", __func__); + seq_printf(s, "Step 5 :set OFFSET_DATA_SEC type failed\n"); + goto ERR_OUT; + } + + sec_mdelay(50); + /* read reference data */ + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_RAWDATA, readbytes, pRead); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: read mutual rawdata failed!\n", __func__); + seq_printf(s, "Step 5:read mutual rawdata failed\n"); + goto ERR_OUT; + } + /* store and judge reference data */ + store_to_file(sec_testdata->fd, "TYPE_MUTUAL_RAW_OFFSET_DATA_SDC:\n"); + for (j = 0; j < sec_testdata->RX_NUM; j++) { + for (i = 0; i < sec_testdata->TX_NUM; i++) { + iArrayIndex = i * sec_testdata->RX_NUM + j; + nodeData = (pRead[iArrayIndex*2] << 8) | pRead[iArrayIndex*2+1]; + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "%d, ", nodeData); + } + if ((nodeData < p_mutual_n[iArrayIndex]) || (nodeData > p_mutual_p[iArrayIndex])) { + TPD_INFO(" mutual offset_data failed at data[%d][%d] = %d [%d,%d]\n", i, j, nodeData, p_mutual_n[iArrayIndex], p_mutual_p[iArrayIndex]); + if (!err_cnt) { + seq_printf(s, "Step 7: mutual offset_data failed at data[%d][%d] = %d [%d,%d]\n", i, j, nodeData, p_mutual_n[iArrayIndex], p_mutual_p[iArrayIndex]); + } + err_cnt++; + } + } + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "\n"); + } + } + + /* CM Offseet gap (left-right)*/ + for (j = 0; j < sec_testdata->RX_NUM; j++) { + for (i = 0; i < sec_testdata->TX_NUM - 1; i++) { + iArrayIndex = i * sec_testdata->RX_NUM + j; + iArrayIndex_2 = (i + 1) * sec_testdata->RX_NUM + j; + Buff16 = (pRead[iArrayIndex * 2] << 8) | pRead[iArrayIndex * 2 + 1]; + Buff16_2 = (pRead[iArrayIndex_2 * 2] << 8) | pRead[iArrayIndex_2 * 2 + 1]; + if (Buff16 > Buff16_2) { + nodeGap = 100 - (Buff16_2 * 100 / Buff16); + } else { + nodeGap = 100 - (Buff16 * 100 / Buff16_2); + } + if ((nodeGap > p_mutualGap_p[iArrayIndex]) || (nodeGap < p_mutualGap_n[iArrayIndex])) { + TPD_INFO("mutual node[%d, %d]=%d and node[%d, %d]=%d gap beyond [%d, %d]\n", i, j, Buff16, i+1, j, Buff16_2, p_mutualGap_n[iArrayIndex], p_mutualGap_p[iArrayIndex]); + if (!err_cnt) { + seq_printf(s, "Step 8-1:mutual node[%d, %d]=%d and node[%d, %d]=%d gap beyond [%d, %d]\n", i, j, Buff16, i+1, j, Buff16_2, p_mutualGap_n[iArrayIndex], p_mutualGap_p[iArrayIndex]); + } + err_cnt++; + } + } + } + /* CM Offseet gap (up-down)*/ + for (j = 0; j < sec_testdata->RX_NUM - 1; j++) { + for (i = 0; i < sec_testdata->TX_NUM; i++) { + iArrayIndex = i * sec_testdata->RX_NUM + j; + iArrayIndex_2 = i * sec_testdata->RX_NUM + j + 1; + Buff16 = (pRead[iArrayIndex * 2] << 8) | pRead[iArrayIndex * 2 + 1]; + Buff16_2 = (pRead[iArrayIndex_2 * 2] << 8) | pRead[iArrayIndex_2 * 2 + 1]; + if (Buff16 > Buff16_2) { + nodeGap = 100 - (Buff16_2 * 100 / Buff16); + } else { + nodeGap = 100 - (Buff16 * 100 / Buff16_2); + } + if ((nodeGap > p_mutualGap_p[iArrayIndex]) || (nodeGap < p_mutualGap_n[iArrayIndex])) { + TPD_INFO("mutual node[%d, %d]=%d and node[%d, %d]=%d gap beyond [%d, %d]\n", j, i, Buff16, j+1, i, Buff16_2, p_mutualGap_n[iArrayIndex], p_mutualGap_p[iArrayIndex]); + if (!err_cnt) { + seq_printf(s, "Step 8-2:mutual node[%d, %d]=%d and node[%d, %d]=%d gap beyond [%d, %d]\n", j, i, Buff16, j+1, i, Buff16_2, p_mutualGap_n[iArrayIndex], p_mutualGap_p[iArrayIndex]); + } + err_cnt++; + } + } + } + } + + //test item self_raw offset_data_sec + if (sec_testdata->test_item & (1 << TYPE_SELF_RAW_OFFSET_DATA_SDC)) { + TPD_INFO("do test item self_raw offset_data_sec\n"); + + item_offset = search_for_item(sec_testdata->fw, item_cnt, TYPE_SELF_RAW_OFFSET_DATA_SDC); + if (item_offset == 0) { + err_cnt++; + TPD_INFO("search for item limit offset failed\n"); + seq_printf(s, "search for item limit offset failed\n"); + goto ERR_OUT; + } + item_header = (struct sec_test_item_header *)(sec_testdata->fw->data + item_offset); + if (item_header->item_magic != 0x4F50504F) { + err_cnt++; + TPD_INFO("test item: %d magic number(%4x) is wrong\n", TYPE_SELF_RAW_OFFSET_DATA_SDC, item_header->item_magic); + seq_printf(s, "test item: %d magic number(%4x) is wrong\n", TYPE_SELF_RAW_OFFSET_DATA_SDC, item_header->item_magic); + goto ERR_OUT; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_tx_offset_p = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset); + p_tx_offset_n = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset + 4*sec_testdata->TX_NUM); + p_rx_offset_p = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset + 2*4*sec_testdata->TX_NUM); + p_rx_offset_n = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset + 2*4*sec_testdata->TX_NUM + 4*sec_testdata->RX_NUM); + } else { + err_cnt++; + TPD_INFO("item: %d has invalid limit type(%d)\n", TYPE_SELF_RAW_OFFSET_DATA_SDC, item_header->item_limit_type); + seq_printf(s, "item: %d has invalid limit type(%d)\n", TYPE_SELF_RAW_OFFSET_DATA_SDC, item_header->item_limit_type); + goto ERR_OUT; + } + if (item_header->para_num == 0) { + } else { + err_cnt++; + TPD_INFO("item: %d has %d parameter\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->para_num); + seq_printf(s, "item: %d has %d parameter\n", TYPE_MUTUAL_RAW_OFFSET_DATA_SDC, item_header->para_num); + goto ERR_OUT; + } + + /* check self offset data */ + type = TYPE_OFFSET_DATA_SDC; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_SELF_RAW_TYPE, type); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: set self rawdata type failed\n", __func__); + seq_printf(s, "set self rawdata type failed\n"); + goto ERR_OUT; + } + + sec_mdelay(100); + /* read raw data */ + memset(pRead, 0, readbytes); //clear buffer + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_SELF_RAWDATA, readselfbytes, pRead); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: read self rawdata failed!\n", __func__); + seq_printf(s, "read self rawdata failed\n"); + goto ERR_OUT; + } + + /* store and judge self minimum frame data */ + store_to_file(sec_testdata->fd, "TYPE_SELF_TX_OFFSET_DATA:\n"); + /* check long channel of self data */ + for (i = 0; i < sec_testdata->TX_NUM; i++) { + nodeData = (pRead[i*2] << 8) | pRead[i*2+1]; + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "%d, ", nodeData); + } + if ((nodeData < p_tx_offset_n[i]) || (nodeData > p_tx_offset_p[i])) { + TPD_INFO("self_offset_tx_data failed at data[%d] = %d [%d,%d]\n", i, nodeData, p_tx_offset_n[i], p_tx_offset_p[i]); + if (!err_cnt) { + seq_printf(s, "Step 9-1:self_offset_tx_data failed at data[%d] = %d [%d,%d]\n", i, nodeData, p_tx_offset_n[i], p_tx_offset_p[i]); + } + err_cnt++; + } + } + store_to_file(sec_testdata->fd, "\n"); + + store_to_file(sec_testdata->fd, "TYPE_SELF_RX_OFFSET_DATA:\n"); + /* check short channel of self data */ + for (i = 0; i < sec_testdata->RX_NUM; i++) { + nodeData = (pRead[sec_testdata->TX_NUM*2 + i*2] << 8) | pRead[sec_testdata->TX_NUM*2 + i*2 +1]; + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "%d, ", nodeData); + } + if ((nodeData < p_rx_offset_n[i]) || (nodeData > p_rx_offset_p[i])) { + TPD_INFO("self_offset_rx_data failed at data[%d] = %d [%d,%d]\n", i, nodeData, p_rx_offset_n[i], p_rx_offset_p[i]); + if (!err_cnt) { + seq_printf(s, "Step 9-2:self_offset_rx_data failed at data[%d] = %d [%d,%d]\n", i, nodeData, p_rx_offset_n[i], p_rx_offset_p[i]); + } + err_cnt++; + } + } + store_to_file(sec_testdata->fd, "\n"); + } + + ret = sec_execute_p2ptest(s, chip_info, sec_testdata); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: p2ptest failed\n", __func__); + seq_printf(s, "Step 10:p2ptest failed\n"); + goto ERR_OUT; + } + + //test item mutual raw noise + if (sec_testdata->test_item & (1 << TYPE_MUTU_RAW_NOI_P2P)) { + TPD_INFO("do test item raw noise p2p\n"); + + item_offset = search_for_item(sec_testdata->fw, item_cnt, TYPE_MUTU_RAW_NOI_P2P); + if (item_offset == 0) { + err_cnt++; + TPD_INFO("search for item limit offset failed\n"); + seq_printf(s, "search for item limit offset failed\n"); + goto ERR_OUT; + } + item_header = (struct sec_test_item_header *)(sec_testdata->fw->data + item_offset); + if (item_header->item_magic != 0x4F50504F) { + err_cnt++; + TPD_INFO("test item: %d magic number(%4x) is wrong\n", TYPE_MUTU_RAW_NOI_P2P, item_header->item_magic); + seq_printf(s, "test item: %d magic number(%4x) is wrong\n", TYPE_MUTU_RAW_NOI_P2P, item_header->item_magic); + goto ERR_OUT; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_p2p_p = (int32_t *)(sec_testdata->fw->data + item_header->top_limit_offset); + p_p2p_n = (int32_t *)(sec_testdata->fw->data + item_header->floor_limit_offset); + } else { + err_cnt++; + TPD_INFO("item: %d has invalid limit type(%d)\n", TYPE_MUTU_RAW_NOI_P2P, item_header->item_limit_type); + seq_printf(s, "item: %d has invalid limit type(%d)\n", TYPE_MUTU_RAW_NOI_P2P, item_header->item_limit_type); + goto ERR_OUT; + } + if (item_header->para_num == 0) { + } else { + err_cnt++; + TPD_INFO("item: %d has %d parameter\n", TYPE_MUTU_RAW_NOI_P2P, item_header->para_num); + seq_printf(s, "item: %d has %d parameter\n", TYPE_MUTU_RAW_NOI_P2P, item_header->para_num); + goto ERR_OUT; + } + + /* read minimum value frame from p2p test result */ + type = TYPE_NOI_P2P_MIN; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, type); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: set rawdata type failed\n", __func__); + seq_printf(s, "set rawdata type failed\n"); + goto ERR_OUT; + } + + sec_mdelay(100); + /* read raw data */ + memset(pRead, 0, readbytes); //clear buffer + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_RAWDATA, readbytes, pRead); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: read rawdata failed!\n", __func__); + seq_printf(s, "read rawdata failed\n"); + goto ERR_OUT; + } + + store_to_file(sec_testdata->fd, "TYPE_P2P_MIN_DATA:\n"); + /* check minimum value */ + for (j = 0; j < sec_testdata->RX_NUM; j++) { + for (i = 0; i < sec_testdata->TX_NUM; i++) { + iArrayIndex = i * sec_testdata->RX_NUM + j; + nodeData = (pRead[iArrayIndex*2] << 8) | pRead[iArrayIndex*2+1]; + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "%d, ", nodeData); + } + if ((nodeData < p_p2p_n[iArrayIndex])) { + TPD_INFO("p2p_min_data failed at data[%d][%d] = %d [%d]\n", i, j, nodeData, p_p2p_n[iArrayIndex]); + if (!err_cnt) { + seq_printf(s, "Step 10-1:p2p_min_data failed at data[%d][%d] = %d [%d]\n", i, j, nodeData, p_p2p_n[iArrayIndex]); + } + err_cnt++; + } + } + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "\n"); + } + } + + /* read maximum value frame from p2p test result */ + type = TYPE_NOI_P2P_MAX; + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, type); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: set rawdata type failed\n", __func__); + seq_printf(s, "set rawdata type failed\n"); + goto ERR_OUT; + } + + sec_mdelay(100); + /* read raw data */ + memset(pRead, 0, readbytes); //clear buffer + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_RAWDATA, readbytes, pRead); + if (ret < 0) { + err_cnt++; + TPD_INFO("%s: read rawdata failed!\n", __func__); + seq_printf(s, "read rawdata failed\n"); + goto ERR_OUT; + } + + store_to_file(sec_testdata->fd, "TYPE_P2P_MAX_DATA:\n"); + /* check maximum value */ + for (j = 0; j < sec_testdata->RX_NUM; j++) { + for (i = 0; i < sec_testdata->TX_NUM; i++) { + iArrayIndex = i * sec_testdata->RX_NUM + j; + nodeData = (pRead[iArrayIndex*2] << 8) | pRead[iArrayIndex*2+1]; + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "%d, ", nodeData); + } + if ((nodeData > p_p2p_p[iArrayIndex])) { + TPD_INFO("p2p_max_data failed at data[%d][%d] = %d [%d]\n", i, j, nodeData, p_p2p_p[iArrayIndex]); + if (!err_cnt) { + seq_printf(s, "Step 10-2:p2p_max_data failed at data[%d][%d] = %d [%d]\n", i, j, nodeData, p_p2p_p[iArrayIndex]); + } + err_cnt++; + } + } + if (sec_testdata->fd >= 0) { + store_to_file(sec_testdata->fd, "\n"); + } + } + } + +ERR_OUT: + if (pRead) { + kfree(pRead); + pRead = NULL; + } + +ERR_INT: + seq_printf(s, "FW:0x%llx\n", sec_testdata->TP_FW); + seq_printf(s, "%d error(s). %s\n", err_cnt, err_cnt?"":"All test passed."); + TPD_INFO(" TP auto test %d error(s). %s\n", err_cnt, err_cnt?"":"All test passed."); +} + +static int sec_get_verify_result(struct chip_data_s6sy761 *chip_info) +{ + int ret = -1; + + sec_fix_tmode(chip_info, TOUCH_SYSTEM_MODE_TOUCH, TOUCH_MODE_STATE_TOUCH); + touch_i2c_write_block(chip_info->client, 0xA7, 0, NULL); //set to verify calibration + sec_mdelay(100); + //get calibration result, 0x0F:FAIL(bit[0]:data condition FAIL, bit[1]:RX gap FAIL, bit[2]:TX gap FAIL, bit[3]:TX/RX peak FAIL) + ret = touch_i2c_read_byte(chip_info->client, 0xA8); + sec_release_tmode(chip_info); + + return ret; +} + + +int execute_selftest(struct chip_data_s6sy761 *chip_info, bool save_result) +{ + u8 pStr[50] = {0}; + u8 pTmp[20]; + int rc = 0; + u8 tpara[2] = {0x25, 0x40}; + u8 *rBuff; + int i; + int result_size = SEC_SELFTEST_REPORT_SIZE + chip_info->hw_res->TX_NUM* chip_info->hw_res->RX_NUM * 2; + + /* save selftest result in flash */ + if (save_result) + tpara[0] = 0x25; + else + tpara[0] = 0xA5; + + rBuff = kzalloc(result_size, GFP_KERNEL); + if (!rBuff) + return -ENOMEM; + + TPD_INFO("%s: Self test start!\n", __func__); + rc = touch_i2c_write_block(chip_info->client, SEC_CMD_SELFTEST, 2, tpara); + if (rc < 0) { + TPD_INFO("%s: Send selftest cmd failed!\n", __func__); + goto err_exit; + } + + sec_mdelay(350); + + rc = sec_wait_for_ready(chip_info, SEC_VENDOR_ACK_SELF_TEST_DONE); + if (rc < 0) { + TPD_INFO("%s: Selftest execution time out!\n", __func__); + goto err_exit; + } + + TPD_INFO("%s: Self test done!\n", __func__); + + rc = touch_i2c_read_block(chip_info->client, SEC_READ_SELFTEST_RESULT, result_size, rBuff); + if (rc < 0) { + TPD_INFO("%s: Selftest execution time out!\n", __func__); + goto err_exit; + } + + rearrange_sft_result(rBuff, result_size); + + for (i = 0; i < 80; i += 4) { + if (i / 4 == 0) + strncat(pStr, "SIG ", 5); + else if (i / 4 == 1) + strncat(pStr, "VER ", 5); + else if (i / 4 == 2) + strncat(pStr, "SIZ ", 5); + else if (i / 4 == 3) + strncat(pStr, "CRC ", 5); + else if (i / 4 == 4) + strncat(pStr, "RES ", 5); + else if (i / 4 == 5) + strncat(pStr, "COU ", 5); + else if (i / 4 == 6) + strncat(pStr, "PAS ", 5); + else if (i / 4 == 7) + strncat(pStr, "FAI ", 5); + else if (i / 4 == 8) + strncat(pStr, "CHA ", 5); + else if (i / 4 == 9) + strncat(pStr, "AMB ", 5); + else if (i / 4 == 10) + strncat(pStr, "RXS ", 5); + else if (i / 4 == 11) + strncat(pStr, "TXS ", 5); + else if (i / 4 == 12) + strncat(pStr, "RXO ", 5); + else if (i / 4 == 13) + strncat(pStr, "TXO ", 5); + else if (i / 4 == 14) + strncat(pStr, "RXG ", 5); + else if (i / 4 == 15) + strncat(pStr, "TXG ", 5); + else if (i / 4 == 16) + strncat(pStr, "RXR ", 5); + else if (i / 4 == 17) + strncat(pStr, "TXT ", 5); + else if (i / 4 == 18) + strncat(pStr, "RXT ", 5); + else if (i / 4 == 19) + strncat(pStr, "TXR ", 5); + + snprintf(pTmp, sizeof(pTmp), "%2X, %2X, %2X, %2X", + rBuff[i], rBuff[i + 1], rBuff[i + 2], rBuff[i + 3]); + strncat(pStr, pTmp, strnlen(pTmp, sizeof(pTmp))); + + if (i / 4 == 4) { + if ((rBuff[i + 3] & 0x30) != 0)// RX, RX open check. + rc = 0; + else + rc = 1; + + } + if (i % 8 == 4) { + TPD_INFO("%s\n", pStr); + memset(pStr, 0x00, sizeof(pStr)); + } else { + strncat(pStr, " ", 3); + } + } + +err_exit: + kfree(rBuff); + return rc; +} + + +static void sec_ts_print_channel(struct chip_data_s6sy761 *chip_info) +{ + unsigned char *pStr = NULL; + unsigned char pTmp[16] = { 0 }; + int i = 0, j = 0, k = 0; + + if (!chip_info->hw_res->TX_NUM) + return; + + pStr = vzalloc(7 * (chip_info->hw_res->TX_NUM + 1)); + if (!pStr) + return; + + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " TX"); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + + for (k = 0; k < chip_info->hw_res->TX_NUM; k++) { + snprintf(pTmp, sizeof(pTmp), " %02d", k); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + } + TPD_INFO("%s\n", pStr); + + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " +"); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + + for (k = 0; k < chip_info->hw_res->TX_NUM; k++) { + snprintf(pTmp, sizeof(pTmp), "------"); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + } + TPD_INFO("%s\n", pStr); + + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " | "); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + + for (i = 0; i < (chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM) * 2; i += 2) { + if (j == chip_info->hw_res->TX_NUM) { + TPD_INFO("%s\n", pStr); + TPD_INFO("\n"); + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " RX"); + strncat(pStr, pTmp, 7 *chip_info->hw_res->TX_NUM); + + for (k = 0; k < chip_info->hw_res->TX_NUM; k++) { + snprintf(pTmp, sizeof(pTmp), " %02d", k); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + } + + TPD_INFO("%s\n", pStr); + + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " +"); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + + for (k = 0; k < chip_info->hw_res->TX_NUM; k++) { + snprintf(pTmp, sizeof(pTmp), "------"); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + } + TPD_INFO("%s\n", pStr); + + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " | "); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + } else if (j && !(j % chip_info->hw_res->TX_NUM)) { + TPD_INFO("%s\n", pStr); + memset(pStr, 0x0, 7 * (chip_info->hw_res->TX_NUM + 1)); + snprintf(pTmp, sizeof(pTmp), " | "); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + } + + snprintf(pTmp, sizeof(pTmp), " %5d", chip_info->pFrame[j]); + strncat(pStr, pTmp, 7 * chip_info->hw_res->TX_NUM); + + j++; + } + TPD_INFO("%s\n", pStr); + vfree(pStr); +} + +static int sec_ts_read_channel(struct chip_data_s6sy761 *chip_info, u8 type, + short *min, short *max, bool save_result) +{ + unsigned char *pRead = NULL; + u8 mode = TYPE_INVALID_DATA; + int ret = 0; + int ii = 0; + int jj = 0; + unsigned int data_length = (chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM) * 2; + u8 w_data; + + TPD_INFO("%s: type %d\n", __func__, type); + + pRead = kzalloc(data_length, GFP_KERNEL); + if (!pRead) + return -ENOMEM; + + /* set OPCODE and data type */ + w_data = type; + + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_SELF_RAW_TYPE, type); + if (ret < 0) { + TPD_DEBUG("%s: Set rawdata type failed\n", __func__); + goto out_read_channel; + } + + sec_mdelay(50); + + if (type == TYPE_OFFSET_DATA_SDC) { + /* execute selftest for real cap offset data, + * because real cap data is not memory data in normal touch. + */ + char para = 0;// 0 for return touch mode + disable_irq(chip_info->client->irq); + ret = execute_selftest(chip_info, save_result); + if (ret < 0) { + TPD_DEBUG("%s: execute_selftest failed!\n", __func__); + enable_irq(chip_info->client->irq); + goto err_read_data; + } + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_SET_POWER_MODE, para); + if (ret < 0) { + TPD_DEBUG("%s: set rawdata type failed!\n", __func__); + enable_irq(chip_info->client->irq); + goto err_read_data; + } + enable_irq(chip_info->client->irq); + /* end */ + } + /* read data */ + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_SELF_RAWDATA, data_length, pRead); + if (ret < 0) { + TPD_DEBUG("%s: read rawdata failed!\n", __func__); + goto err_read_data; + } + + /* clear all pFrame data */ + memset(chip_info->pFrame, 0x00, data_length); + + for (ii = 0; ii < data_length; ii += 2) { + chip_info->pFrame[jj] = ((pRead[ii] << 8) | pRead[ii + 1]); + + if (ii == 0) + *min = *max =chip_info->pFrame[jj]; + + if(chip_info->pFrame[jj] < *min ) *min = chip_info->pFrame[jj]; + if(chip_info->pFrame[jj] > *max ) *max = chip_info->pFrame[jj]; + jj++; + } + + sec_ts_print_channel(chip_info); + +err_read_data: + /* release data monitory (unprepare AFE data memory) */ + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_SELF_RAW_TYPE, mode); + if (ret < 0) + TPD_DEBUG("%s: Set rawdata type failed\n", __func__); + +out_read_channel: + kfree(pRead); + + return ret; +} + +static void sec_ts_print_frame(struct chip_data_s6sy761 *chip_info, short *min, short *max) +{ + int i = 0; + int j = 0; + unsigned char *pStr = NULL; + unsigned char pTmp[16] = { 0 }; + int lsize = 7 * (chip_info->hw_res->TX_NUM + 1); + + TPD_INFO("%s\n", __func__); + + pStr = kzalloc(lsize * (sizeof(int)), GFP_KERNEL); + if (pStr == NULL) + return; + + memset(pStr, 0x0, lsize); + snprintf(pTmp, sizeof(pTmp), " TX"); + strncat(pStr, pTmp, lsize); + + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) { + snprintf(pTmp, sizeof(pTmp), " %02d ", i); + strncat(pStr, pTmp, lsize); + } + if (chip_info->print_num == 1) { + TPD_INFO("%s\n", pStr); + } else { + TPD_DEBUG("%s\n", pStr); + } + memset(pStr, 0x0, lsize); + snprintf(pTmp, sizeof(pTmp), " +"); + strncat(pStr, pTmp, lsize); + + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) { + snprintf(pTmp, sizeof(pTmp), "----"); + strncat(pStr, pTmp, lsize); + } + if (chip_info->print_num == 1) { + TPD_INFO("%s\n", pStr); + } else { + TPD_DEBUG("%s\n", pStr); + } + for (i = 0; i < chip_info->hw_res->RX_NUM; i++) { + memset(pStr, 0x0, lsize); + snprintf(pTmp, sizeof(pTmp), "Rx%02d | ", i); + strncat(pStr, pTmp, lsize); + + for (j = 0; j < chip_info->hw_res->TX_NUM; j++) { + snprintf(pTmp, sizeof(pTmp), " %3d", chip_info->pFrame[(j * chip_info->hw_res->RX_NUM) + i]); + + if (chip_info->pFrame[(j * chip_info->hw_res->RX_NUM) + i] < *min) + *min = chip_info->pFrame[(j * chip_info->hw_res->RX_NUM) + i]; + + if (chip_info->pFrame[(j * chip_info->hw_res->RX_NUM) + i] > *max) + *max = chip_info->pFrame[(j * chip_info->hw_res->RX_NUM) + i]; + + strncat(pStr, pTmp, lsize); + } + if (chip_info->print_num == 1) { + TPD_INFO("%s\n", pStr); + } else { + TPD_DEBUG("%s\n", pStr); + } + } + kfree(pStr); +} + +static int sec_ts_read_frame(struct chip_data_s6sy761 *chip_info, u8 type, short *min, + short *max, bool save_result) +{ + unsigned int readbytes = 0xFF; + unsigned char *pRead = NULL; + u8 mode = TYPE_INVALID_DATA; + int ret = 0; + int i = 0; + int j = 0; + short *temp = NULL; + + TPD_INFO("%s: type %d\n", __func__, type); + + /* set data length, allocation buffer memory */ + readbytes = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM * 2; + + pRead = kzalloc(readbytes, GFP_KERNEL); + if (!pRead) + return -ENOMEM; + + /* set OPCODE and data type */ + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, type); + if (ret < 0) { + TPD_INFO("%s: Set rawdata type failed\n", __func__); + goto ErrorExit; + } + + sec_mdelay(50); + + if (type == TYPE_OFFSET_DATA_SDC) { + /* excute selftest for real cap offset data, because real cap data is not memory data in normal touch. */ + char para = 0;//0 for return touch mode + + disable_irq(chip_info->client->irq); + + ret = execute_selftest(chip_info, save_result); + if (ret < 0) { + TPD_DEBUG("%s: execute_selftest failed\n", __func__); + enable_irq(chip_info->client->irq); + goto ErrorRelease; + } + + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_SET_POWER_MODE, para); + if (ret < 0) { + TPD_DEBUG( "%s: Set power mode failed\n", __func__); + enable_irq(chip_info->client->irq); + goto ErrorRelease; + } + + enable_irq(chip_info->client->irq); + } + + /* read data */ + ret = touch_i2c_read_block(chip_info->client, SEC_READ_TOUCH_RAWDATA, readbytes, pRead); + if (ret < 0) { + TPD_DEBUG("%s: read rawdata failed!\n", __func__); + goto ErrorRelease; + } + + memset(chip_info->pFrame, 0x00, readbytes); + + for (i = 0; i < readbytes; i += 2) + chip_info->pFrame[i / 2] = pRead[i + 1] + (pRead[i] << 8); + + *min = *max = chip_info->pFrame[0]; + +#ifdef DEBUG_MSG + TPD_INFO("%s: 02X%02X%02X readbytes=%d\n", __func__, + pRead[0], pRead[1], pRead[2], readbytes); +#endif + sec_ts_print_frame(chip_info, min, max); + + temp = kzalloc(readbytes, GFP_KERNEL); + if (!temp) + goto ErrorRelease; + + memcpy(temp, chip_info->pFrame, readbytes); + memset(chip_info->pFrame, 0x00, readbytes); + + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) { + for (j = 0; j < chip_info->hw_res->RX_NUM; j++) + chip_info->pFrame[(j * chip_info->hw_res->TX_NUM) + i] = temp[(i * chip_info->hw_res->RX_NUM) + j]; + } + + kfree(temp); + +ErrorRelease: + /* release data monitory (unprepare AFE data memory) */ + ret = touch_i2c_write_byte(chip_info->client, SEC_CMD_MUTU_RAW_TYPE, mode); + if (ret < 0) + TPD_DEBUG("%s: Set rawdata type failed\n", __func__); + +ErrorExit: + kfree(pRead); + + return ret; +} + +/* + * sec_ts_run_rawdata_all : read all raw data + * + * when you want to read full raw data (full_read : true) + * "mutual/self 3, 5, 29, 1, 19" data will be saved in log + * + * otherwise, (full_read : false, especially on boot time) + * only "mutual 3, 5, 29" data will be saved in log + */ +void sec_ts_run_rawdata_all(void *chip_data, bool full_read) +{ + short min = 0, max = 0; + int ret = 0, i = 0, read_num = 0; + u8 test_type[5] = {TYPE_AMBIENT_DATA, TYPE_DECODED_DATA, + TYPE_SIGNAL_DATA, TYPE_OFFSET_DATA_SEC, TYPE_OFFSET_DATA_SDC}; + + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + chip_info->pFrame = kzalloc(chip_info->hw_res->TX_NUM* chip_info->hw_res->RX_NUM* 2, GFP_KERNEL); + if (!chip_info->pFrame) { + TPD_INFO("%s: chip_info->pFrame kzalloc fail\n", __func__); + return; + } + TPD_INFO("%s: start (noise:%d, wet:%d)##\n", + __func__, chip_info->touch_noise_status, chip_info->wet_mode); + + ret = sec_fix_tmode(chip_info, TOUCH_SYSTEM_MODE_TOUCH, TOUCH_MODE_STATE_TOUCH); + if (ret < 0) { + TPD_INFO("%s: failed to fix tmode\n",__func__); + goto out; + } + + if (full_read) { + read_num = 5; + } else { + read_num = 3; + test_type[read_num - 1] = TYPE_OFFSET_DATA_SEC; + } + + for (i = 0; i < read_num; i++) { + chip_info->print_num = i; + ret = sec_ts_read_frame(chip_info, test_type[i], &min, &max, false); + if (ret < 0) { + TPD_INFO("%s: mutual %d : error ## ret:%d\n", + __func__, test_type[i], ret); + goto out; + } else { + TPD_INFO("%s: mutual %d : Max/Min %d,%d ##\n", + __func__, test_type[i], max, min); + } + sec_mdelay(20); + + if (full_read) { + ret = sec_ts_read_channel(chip_info, test_type[i], &min, &max, false); + if (ret < 0) { + TPD_INFO("%s: self %d : error ## ret:%d\n", + __func__, test_type[i], ret); + goto out; + } else { + TPD_INFO("%s: self %d : Max/Min %d,%d ##\n", + __func__, test_type[i], max, min); + } + sec_mdelay(20); + } + } + + sec_release_tmode(chip_info); + +out: + TPD_INFO("%s: done (noise:%d, wet:%d)##\n", + __func__, chip_info->touch_noise_status, chip_info->wet_mode); + + tp_touch_btnkey_release(); + +} + + +static void sec_ts_read_info_work(struct work_struct *work) +{ + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, + work_read_info.work); + + TPD_INFO("%s\n", __func__); + mutex_lock(&ts->mutex); + sec_ts_run_rawdata_all(ts->chip_data, false); + mutex_unlock(&ts->mutex); +} + +static void sec_calibrate(struct seq_file *s, void *chip_data) +{ + int ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + ret = sec_execute_force_calibration(chip_info); + if (ret < 0) { + TPD_INFO("%s calibration failed\n", __func__); + seq_printf(s, "1 error, calibration failed\n"); + } else { + TPD_INFO("%s calibration successed\n", __func__); + seq_printf(s, "0 error, calibration successed\n"); + } + + return; +} + +static void sec_verify_calibration(struct seq_file *s, void *chip_data) +{ + int ret = -1; + struct chip_data_s6sy761 *chip_info = (struct chip_data_s6sy761 *)chip_data; + + ret = sec_get_verify_result(chip_info); + if (ret != 0) { + TPD_INFO("%s verify calibration failed\n", __func__); + seq_printf(s, "1 error, verify calibration result failed(0x%02x)\n", ret); + } else { + TPD_INFO("%s verify calibration successed\n", __func__); + seq_printf(s, "0 error, verify calibration result successed\n"); + } + + return; +} + +static void sec_calibration_data(struct seq_file *s, void *chip_data) +{ + schedule_delayed_work(&g_tp->work_read_info, msecs_to_jiffies(10)); +} + +static struct sec_proc_operations sec_proc_ops = { + .auto_test = sec_auto_test, + .calibrate = sec_calibrate, + .verify_calibration = sec_verify_calibration, + .calibration_data = sec_calibration_data, +}; + +/*********** Start of I2C Driver and Implementation of it's callbacks*************************/ +static int sec_tp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct chip_data_s6sy761 *chip_info = NULL; + struct touchpanel_data *ts = NULL; + int ret = -1; + + TPD_INFO("%s is called\n", __func__); + if (tp_register_times > 0) { + TPD_INFO("TP driver have success loaded %d times, exit\n", tp_register_times); + return -1; + } + /* 1. alloc chip info */ + chip_info = kzalloc(sizeof(struct chip_data_s6sy761), GFP_KERNEL); + if (chip_info == NULL) { + TPD_INFO("chip info kzalloc error\n"); + ret = -ENOMEM; + return ret; + } + memset(chip_info, 0, sizeof(*chip_info)); + + /* 2. Alloc common ts */ + ts = common_touch_data_alloc(); + if (ts == NULL) { + TPD_INFO("ts kzalloc error\n"); + goto ts_malloc_failed; + } + memset(ts, 0, sizeof(*ts)); + + /* 3. bind client and dev for easy operate */ + chip_info->client = client; + ts->debug_info_ops = &debug_info_proc_ops; + ts->client = client; + ts->irq = client->irq; + i2c_set_clientdata(client, ts); + ts->dev = &client->dev; + ts->chip_data = chip_info; + chip_info->hw_res = &ts->hw_res; + /* 4. file_operations callbacks binding */ + ts->ts_ops = &sec_ops; + ts->earsense_ops = &earsense_proc_ops; + + /* 5. register common touch device*/ + ret = register_common_touch_device(ts); + if (ret < 0) { + goto err_register_driver; + } + //ts->tp_resume_order = LCD_TP_RESUME; + INIT_DELAYED_WORK(&ts->work_read_info, sec_ts_read_info_work); + /* 6. create debug interface*/ + sec_raw_device_init(ts); + sec_create_proc(ts, &sec_proc_ops); + schedule_delayed_work(&ts->work_read_info, msecs_to_jiffies(50)); + TPD_INFO("%s, probe normal end\n", __func__); + return 0; + +err_register_driver: + common_touch_data_free(ts); + ts = NULL; + +ts_malloc_failed: + kfree(chip_info); + chip_info = NULL; + ret = -1; + + TPD_INFO("%s, probe error\n", __func__); + return ret; +} + +static int sec_tp_remove(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + + TPD_INFO("%s is called\n", __func__); + + cancel_delayed_work_sync(&ts->work_read_info); + flush_delayed_work(&ts->work_read_info); + kfree(ts); + + return 0; +} + +static int sec_i2c_suspend(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s: is called\n", __func__); + tp_i2c_suspend(ts); + + return 0; +} + +static int sec_i2c_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s is called\n", __func__); + tp_i2c_resume(ts); + + return 0; +} + +static void sec_tp_shutdown(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + int ret = 0; + + TPD_INFO("%s is called\n", __func__); + if (!ts->ts_ops->power_control) { + ret = -EINVAL; + TPD_INFO("tp power_control NULL!\n"); + return; + } + ret = ts->ts_ops->power_control(ts->chip_data, false); +} + + +static const struct i2c_device_id tp_id[] = +{ + {TPD_DEVICE, 0}, + {}, +}; + +static struct of_device_id tp_match_table[] = +{ + { .compatible = TPD_DEVICE, }, + { }, +}; + +static const struct dev_pm_ops tp_pm_ops = { +#ifdef CONFIG_FB + .suspend = sec_i2c_suspend, + .resume = sec_i2c_resume, +#endif +}; + +static struct i2c_driver tp_i2c_driver = +{ + .probe = sec_tp_probe, + .remove = sec_tp_remove, + .shutdown = sec_tp_shutdown, + .id_table = tp_id, + .driver = { + .name = TPD_DEVICE, + .owner = THIS_MODULE, + .of_match_table = tp_match_table, + .pm = &tp_pm_ops, + }, +}; +/******************* End of I2C Driver and It's dev_pm_ops***********************/ + +/***********************Start of module init and exit****************************/ +static int __init tp_driver_init(void) +{ + TPD_INFO("%s is called\n", __func__); + if (i2c_add_driver(&tp_i2c_driver)!= 0) { + TPD_INFO("unable to add i2c driver.\n"); + return -1; + } + return 0; +} + +static void __exit tp_driver_exit(void) +{ + i2c_del_driver(&tp_i2c_driver); +} + +late_initcall(tp_driver_init); +module_exit(tp_driver_exit); +/***********************End of module init and exit*******************************/ + +MODULE_AUTHOR("Samsung Driver"); +MODULE_DESCRIPTION("Samsung Electronics TouchScreen driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/input/touchscreen/samsung/s6sy761/sec_drivers_s6sy761.h b/drivers/oneplus/input/touchscreen/samsung/s6sy761/sec_drivers_s6sy761.h new file mode 100755 index 0000000000000000000000000000000000000000..7fa3f3d9758bcef41d76c4407fe8ddc044a60ae9 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/s6sy761/sec_drivers_s6sy761.h @@ -0,0 +1,283 @@ +/*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : sec_drivers_s6sy761.h + * + * Function : third party interface + * + * Source : provide by LSI + * + * Version : V1.0 + * + ***********************************************************/ +#ifndef SEC_H_S6SY761 +#define SEC_H_S6SY761 + +/*********PART1:Head files**********************/ +#include +#ifdef CONFIG_FB +#include +#include +#endif +#include "../sec_common.h" + +/*********PART2:Define Area**********************/ +#define GESTURE_DOUBLECLICK 0x00 +#define GESTURE_UP_V 0x01 +#define GESTURE_DOWN_V 0x02 +#define GESTURE_LEFT_V 0x03 +#define GESTURE_RIGHT_V 0x04 +#define GESTURE_O 0x05 +#define GESTURE_UP 0x06 +#define GESTURE_DOWN 0x07 +#define GESTURE_LEFT 0x08 +#define GESTURE_RIGHT 0x09 +#define GESTURE_M 0x0A +#define GESTURE_W 0x0B +#define GESTURE_DOUBLE_LINE 0x0C +#define GESTURE_SINGLE_TAP 0x0E +#define GESTURE_S 0x0F + + +#define GESTURE_EARSENSE 0x0E + +#define RESET_TO_NORMAL_TIME (70) +#define SEC_EVENT_BUFF_SIZE 8 +#define MAX_EVENT_COUNT 32 +#define SEC_FW_BLK_DEFAULT_SIZE (512) +#define SEC_FW_BLK_SIZE_MAX (512) +#define SEC_FW_HEADER_SIGN 0x53494654 +#define SEC_FW_CHUNK_SIGN 0x53434654 +#define SEC_SELFTEST_REPORT_SIZE 80 + +#define SEC_COORDINATE_ACTION_NONE 0 +#define SEC_COORDINATE_ACTION_PRESS 1 +#define SEC_COORDINATE_ACTION_MOVE 2 +#define SEC_COORDINATE_ACTION_RELEASE 3 + +/* SEC event id */ +#define SEC_COORDINATE_EVENT 0 +#define SEC_STATUS_EVENT 1 +#define SEC_GESTURE_EVENT 2 +#define SEC_EMPTY_EVENT 3 + +//sec status type +#define TYPE_STATUS_EVENT_ERR 1 +#define TYPE_STATUS_EVENT_INFO 2 +#define TYPE_STATUS_EVENT_VENDOR_INFO 7 + +/* SEC_TS_INFO : Info acknowledge event */ +#define SEC_ACK_BOOT_COMPLETE 0x00 +#define SEC_ACK_WET_MODE 0x01 +#define SEC_VENDOR_ACK_OFFSET_CAL_DONE 0x40 +#define SEC_VENDOR_ACK_SELF_TEST_DONE 0x41 +#define SEC_VENDOR_ACK_P2P_TEST_DONE 0x42 + +/* SEC_TS_ERROR : Error event */ +#define SEC_ERR_EVNET_CORE_ERR 0x0 +#define SEC_ERR_EVENT_QUEUE_FULL 0x01 +#define SEC_ERR_EVENT_ESD 0x2 + +//earsense status +#define SEC_STATUS_EARDETECTED 0x6A //84 (70.4 change to 6A) + +//touchhold status +#define SEC_STATUS_TOUCHHOLD 0x6B + +//wet and noise mode +#define SEC_TS_ACK_WET_MODE 0x1 +#define SEC_TS_VENDOR_ACK_NOISE_STATUS_NOTI 0x64 + +//boot status +#define SEC_STATUS_BOOT_MODE 0x10 +#define SEC_STATUS_APP_MODE 0x20 + +#define STATE_MANAGE_ON 1 +#define STATE_MANAGE_OFF 0 + +//cmd +#define SEC_READ_ONE_EVENT 0x60 +#define SEC_READ_ALL_EVENT 0x61 +#define SEC_CMD_CLEAR_EVENT_STACK 0x62 +#define SEC_READ_GESTURE_EVENT 0x63 +#define SEC_READ_DEVICE_ID 0x22 //for custom to print IC info +#define SEC_READ_ID 0x52 //for debug with IC touch mode +#define SEC_READ_FIRMWARE_INTEGRITY 0x21 +#define SEC_READ_BOOT_STATUS 0x55 +#define SEC_READ_TS_STATUS 0xAF +#define SEC_READ_FW_VERSION 0xA3 +#define SEC_READ_CONFIG_VERSION 0xA4 +#define SEC_CMD_SENSE_ON 0x10 +#define SEC_CMD_SENSE_OFF 0x11 +#define SEC_READ_IMG_VERSION 0xA5 +#define SEC_CMD_ENTER_FW_MODE 0x57 +#define SEC_CMD_SOFT_RESET 0x12 +#define SEC_CMD_FLASH_ERASE 0xD8 +#define SEC_CMD_FLASH_WRITE 0xD9 +#define SEC_CMD_FLASH_PADDING 0xDA +#define SEC_CMD_FLASH_READ_ADDR 0xD0 +#define SEC_CMD_FLASH_READ_SIZE 0xD1 +#define SEC_CMD_FLASH_READ_DATA 0xD2 +#define SEC_CMD_WAKEUP_GESTURE_MODE 0x39 +#define SEC_CMD_DISABLE_GESTURE_MODE 0x65 +#define SEC_CMD_SET_POWER_MODE 0xE4 +#define SET_CMD_SET_CHARGER_MODE 0x32 +#define SEC_CMD_READ_CALIBRATION_REPORT 0xF1 +#define SEC_CMD_FACTORY_PANELCALIBRATION 0x14 +#define SEC_CMD_MUTU_RAW_TYPE 0x70 +#define SEC_CMD_SELF_RAW_TYPE 0x71 +#define SEC_READ_TOUCH_RAWDATA 0x72 //read all frame rawdata(ordered by RX len) +#define SEC_READ_TOUCH_SELF_RAWDATA 0x73 +#define SEC_READ_TOUCH_SETLEN_RAWDATA 0x74 //read out self define length rawdata(ordered by TX len) +#define SEC_CMD_TOUCH_RAWDATA_SETLEN 0x75 //set rawdata length of reading +#define SEC_CMD_TOUCH_DELTA_READ 0x76 //cmd to read delta data +#define SEC_CMD_TOUCH_RAWDATA_READ 0x77 //cmd to read rawdata data +#define SEC_CMD_TOUCH_SELFDATA_READ 0x78 //cmd to read self data +#define SEC_CMD_SELFTEST 0xAE +#define SEC_READ_SELFTEST_RESULT 0x80 +#define SEC_CMD_STATEMANAGE_ON 0x8E +#define SEC_CMD_CHG_SYSMODE 0xD7 +#define SEC_CMD_HOVER_DETECT 0xEE //proximity function +#define SEC_CMD_SET_P2PTEST_MODE 0x83 +#define SEC_CMD_P2PTEST 0x82 +#define SEC_CMD_INTERRUPT_SWITCH 0x89 +#define SEC_CMD_PALM_SWITCH 0x30 +#define SEC_CMD_GRIP_SWITCH 0xAA +#define SEC_CMD_SENSETIVE_CTRL 0x3F +#define SEC_CMD_REFRESH_RATE_SWITCH 0x40 +#define SEC_CMD_TOUCHHOLD_SWITCH 0x43 +#define SEC_CMD_TOUCHHOLD_CALIBRATE 0x44 +#define SEC_CMD_GAME_FAST_SLIDE 0x45 +#define SEC_CMD_SCREEN_ORIEN 0xAD //0 is portrait,1 is landscape +#define SEC_CMD_GRIP_EXTRA 0xAB +#define SEC_CMD_GRIP_PARA 0xAC +#define SET_CMD_SET_AUDIO_NOISE_MODE 0x46 +#define SEC_NOISE_MODE 0xBB +#define SEC_WET_MODE 0x8B +#define SEC_STATUS 0x3B + + + + +/*********PART3:Struct Area**********************/ +typedef struct { + u32 signature; /* signature */ + u32 version; /* version */ + u32 totalsize; /* total size */ + u32 checksum; /* checksum */ + u32 img_ver; /* image file version */ + u32 img_date; /* image file date */ + u32 img_description; /* image file description */ + u32 fw_ver; /* firmware version */ + u32 fw_date; /* firmware date */ + u32 fw_description; /* firmware description */ + u32 para_ver; /* parameter version */ + u32 para_date; /* parameter date */ + u32 para_description; /* parameter description */ + u32 num_chunk; /* number of chunk */ + u32 reserved1; + u32 reserved2; +} sec_fw_header; + +typedef struct { + u32 signature; + u32 addr; + u32 size; + u32 reserved; +} sec_fw_chunk; + +struct sec_gesture_status { + u8 eid:2; + u8 gtype:4; + u8 stype:2; + u8 gestureId; + u8 coordLen; + u8 data; + u8 reserved[4]; +} __attribute__ ((packed)); + +/* 8 byte */ +struct sec_event_status { + u8 eid:2; + u8 stype:4; + u8 sf:2; + u8 status_id; + u8 status_data_1; + u8 status_data_2; + u8 status_data_3; + u8 status_data_4; + u8 status_data_5; + u8 left_event_5_0:6; + u8 reserved_2:2; +} __attribute__ ((packed)); + +/* 8 byte */ +struct sec_event_coordinate { + u8 eid:2; + u8 tid:4; + u8 tchsta:2; + u8 x_11_4; + u8 y_11_4; + u8 y_3_0:4; + u8 x_3_0:4; + u8 major; + u8 minor; + u8 z:6; + u8 ttype_3_2:2; + u8 left_event:6; + u8 ttype_1_0:2; +} __attribute__ ((packed)); + +typedef enum { + TOUCH_SYSTEM_MODE_BOOT = 0, + TOUCH_SYSTEM_MODE_CALIBRATION = 1, + TOUCH_SYSTEM_MODE_TOUCH = 2, + TOUCH_SYSTEM_MODE_SELFTEST = 3, + TOUCH_SYSTEM_MODE_FLASH = 4, + TOUCH_SYSTEM_MODE_LOWPOWER = 5, + TOUCH_SYSTEM_MODE_LISTEN +} TOUCH_SYSTEM_MODE; + +typedef enum { + TOUCH_MODE_STATE_IDLE = 0, + TOUCH_MODE_STATE_HOVER = 1, + TOUCH_MODE_STATE_TOUCH = 2, + TOUCH_MODE_STATE_NOISY = 3, + TOUCH_MODE_STATE_CAL = 4, + TOUCH_MODE_STATE_CAL2 = 5, + TOUCH_MODE_STATE_WAKEUP = 10 +} TOUCH_MODE_STATE; + +enum { + TYPE_RAW_DATA = 0, /* Total - Offset : delta data */ + TYPE_SIGNAL_DATA = 1, /* Signal - Filtering & Normalization */ + TYPE_AMBIENT_BASELINE = 2, /* Cap Baseline */ + TYPE_AMBIENT_DATA = 3, /* Cap Ambient */ + TYPE_REMV_BASELINE_DATA = 4, + TYPE_DECODED_DATA = 5, /* Raw */ + TYPE_REMV_AMB_DATA = 6, /* TYPE_RAW_DATA - TYPE_AMBIENT_DATA */ + TYPE_OFFSET_DATA_SEC = 19, /* Cap Offset in SEC Manufacturing Line */ + TYPE_OFFSET_DATA_SDC = 29, /* Cap Offset in SDC Manufacturing Line */ + TYPE_NOI_P2P_MIN = 30, /* Peak-to-peak noise Min */ + TYPE_NOI_P2P_MAX = 31, /* Peak-to-peak noise Max */ + TYPE_DATA_DELTA = 60, /* delta */ + TYPE_DATA_RAWDATA = 61, /* rawdata */ + TYPE_INVALID_DATA = 0xFF, /* Invalid data type for release factory mode */ +}; + +struct chip_data_s6sy761 { + tp_dev tp_type; + struct i2c_client *client; + u8 boot_ver[3]; + bool is_power_down; + struct hw_resource *hw_res; + uint32_t flash_page_size; + u8 first_event[SEC_EVENT_BUFF_SIZE]; + u8 wet_mode; + u8 proximity_status; + u8 touch_noise_status; + short *pFrame; + bool print_num; +}; + +#endif diff --git a/drivers/oneplus/input/touchscreen/samsung/sec_common.c b/drivers/oneplus/input/touchscreen/samsung/sec_common.c new file mode 100755 index 0000000000000000000000000000000000000000..854660db2d479a5c4195ae79f9d433109c08c658 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/sec_common.c @@ -0,0 +1,571 @@ +#include "sec_common.h" +//#include +/*******LOG TAG Declear*****************************/ + +#define TPD_DEVICE "sec_common" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +/*********** sec tool operate content***********************/ +u8 lv1cmd; +static int lv1_readsize; + +static ssize_t sec_ts_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t sec_ts_regreadsize_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t sec_ts_regread_show(struct device *dev, struct device_attribute *attr, char *buf); + +static DEVICE_ATTR(sec_ts_reg, (S_IWUSR | S_IWGRP), NULL, sec_ts_reg_store); +static DEVICE_ATTR(sec_ts_regreadsize, (S_IWUSR | S_IWGRP), NULL, sec_ts_regreadsize_store); +static DEVICE_ATTR(sec_ts_regread, S_IRUGO, sec_ts_regread_show, NULL); + +static struct attribute *cmd_attributes[] = { + &dev_attr_sec_ts_reg.attr, + &dev_attr_sec_ts_regreadsize.attr, + &dev_attr_sec_ts_regread.attr, + NULL, +}; + +static struct attribute_group cmd_attr_group = { + .attrs = cmd_attributes, +}; + +static ssize_t sec_ts_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + if (size > 0) { + mutex_lock(&ts->mutex); + touch_i2c_write(ts->client, (u8 *)buf, size); + mutex_unlock(&ts->mutex); + } + + TPD_DEBUG("%s: 0x%x, 0x%x, size %d\n", __func__, buf[0], buf[1], (int)size); + return size; +} + +static ssize_t sec_ts_regread_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + int ret = -1; + u8 *read_lv1_buff = NULL; + int length = 0, remain = 0, offset = 0; + + disable_irq_nosync(ts->irq); + mutex_lock(&ts->mutex); + + read_lv1_buff = kzalloc(lv1_readsize, GFP_KERNEL); + if (!read_lv1_buff) + goto malloc_err; + + remain = lv1_readsize; + offset = 0; + do { + if (remain >= I2C_BURSTMAX) + length = I2C_BURSTMAX; + else + length = remain; + + if (offset == 0) + ret = touch_i2c_read_block(ts->client, lv1cmd, length, &read_lv1_buff[offset]); + else + ret = touch_i2c_read(ts->client, NULL, 0, &read_lv1_buff[offset], length); + + if (ret < 0) { + TPD_INFO("%s: i2c read %x command, remain =%d\n", __func__, lv1cmd, remain); + goto i2c_err; + } + + remain -= length; + offset += length; + } while (remain > 0); + + TPD_DEBUG("%s: lv1_readsize = %d\n", __func__, lv1_readsize); + memcpy(buf, read_lv1_buff, lv1_readsize); + +i2c_err: + kfree(read_lv1_buff); +malloc_err: + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + + return lv1_readsize; +} + +static ssize_t sec_ts_regreadsize_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + mutex_lock(&ts->mutex); + + lv1cmd = buf[0]; + lv1_readsize = ((unsigned int)buf[4] << 24) | + ((unsigned int)buf[3] << 16) | ((unsigned int) buf[2] << 8) | ((unsigned int)buf[1] << 0); + + mutex_unlock(&ts->mutex); + + return size; +} + +//create sec debug interfaces +void sec_raw_device_init(struct touchpanel_data *ts) +{ + int ret = -1; + struct class *sec_class = NULL; + + sec_class = class_create(THIS_MODULE, "sec"); + ret = IS_ERR_OR_NULL(sec_class); + if (ret) { + TPD_INFO("%s: fail to create class\n", __func__); + return; + } + + ts->dev = device_create(sec_class, NULL, 0, ts, "sec_ts"); + ret = IS_ERR(ts->dev); + if (ret) { + TPD_INFO("%s: fail - device_create\n", __func__); + return; + } + + ret = sysfs_create_group(&ts->dev->kobj, &cmd_attr_group); + if (ret < 0) { + TPD_INFO("%s: fail - sysfs_create_group\n", __func__); + goto err_sysfs; + } + + TPD_INFO("create debug interface success\n"); + return; +err_sysfs: + TPD_INFO("%s: fail\n", __func__); + return; +} + + +void sec_limit_read(struct seq_file *s, struct touchpanel_data *ts) +{ + int ret = 0, m = 0, i = 0, j = 0, item_cnt = 0, array_index = 0; + const struct firmware *fw = NULL; + struct sec_test_header *ph = NULL; + struct sec_test_item_header *item_head = NULL; + uint32_t *p_item_offset = NULL; + int32_t *p_data32 = NULL; + + ret = request_firmware(&fw, ts->panel_data.test_limit_name, ts->dev); + if (ret < 0) { + TPD_INFO("Request firmware failed - %s (%d)\n", ts->panel_data.test_limit_name, ret); + seq_printf(s, "Request failed, Check the path\n"); + return; + } + + ph = (struct sec_test_header *)(fw->data); + p_item_offset = (uint32_t *)(fw->data + 16); + if ((ph->magic1 != 0x494D494C) || (ph->magic2 != 0x474D4954)) { + TPD_INFO("limit image is not generated\n"); + seq_printf(s, "limit image is not generated\n"); + release_firmware(fw); + return; + } + + for (i = 0; i < 8*sizeof(ph->test_item); i++) { + if ((ph->test_item >> i) & 0x01 ) { + item_cnt++; + } + } + if (!item_cnt) { + TPD_INFO("limit image has no test item\n"); + seq_printf(s, "limit image has no test item\n"); + } + + for (m = 0; m < item_cnt; m++) { + item_head = (struct sec_test_item_header *)(fw->data + p_item_offset[m]); + if (item_head->item_magic != 0x4F50504F) { + seq_printf(s, "item: %d limit data has some problem\n", item_head->item_bit); + continue; + } + + seq_printf(s, "item %d[size %d, limit type %d, para num %d] :\n", item_head->item_bit, item_head->item_size, item_head->item_limit_type, item_head->para_num); + if (item_head->item_limit_type == LIMIT_TYPE_NO_DATA) { + seq_printf(s, "no limit data\n"); + } else if (item_head->item_limit_type == LIMIT_TYPE_CERTAIN_DATA) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "top limit data: %d\n", *p_data32); + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "floor limit data: %d\n", *p_data32); + } else if (item_head->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + if (item_head->item_bit == TYPE_MUTUAL_RAW_OFFSET_DATA_SDC) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "mutual raw top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset + 4 * ts->hw_res.TX_NUM * ts->hw_res.RX_NUM); + seq_printf(s, "mutual gap top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "mutual raw floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset + 4 * ts->hw_res.TX_NUM * ts->hw_res.RX_NUM); + seq_printf(s, "mutual gap floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + } else if(item_head->item_bit == TYPE_SELF_RAW_OFFSET_DATA_SDC){ + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "tx top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset + 4*ts->hw_res.TX_NUM); + seq_printf(s, "tx floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset + 2*4*ts->hw_res.TX_NUM); + seq_printf(s, "rx top data: \n"); + for (i = 0; i < ts->hw_res.RX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset + 2*4*ts->hw_res.TX_NUM + 4*ts->hw_res.RX_NUM); + seq_printf(s, "rx floor data: \n"); + for (i = 0; i < ts->hw_res.RX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + } else if (item_head->item_bit == TYPE_MUTU_RAW_NOI_P2P) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "noise top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "noise floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + } + } + + p_data32 = (int32_t *)(fw->data + p_item_offset[m] + sizeof(struct sec_test_item_header)); + if (item_head->para_num) { + seq_printf(s, "parameter:"); + for (j = 0; j < item_head->para_num; j++) { + seq_printf(s, "%d, ", p_data32[j]); + } + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + } + + release_firmware(fw); +} + +/************ sec auto test content*************************/ + +static int tp_auto_test_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct sec_proc_operations *sec_ops; + const struct firmware *fw = NULL; + struct timespec now_time; + struct rtc_time rtc_now_time; + mm_segment_t old_fs; + uint8_t data_buf[128]; + int fd = -1, ret = -1; + struct sec_test_header *test_head = NULL; + uint32_t *p_data32 = NULL; + + struct sec_testdata sec_testdata = + { + .TX_NUM = 0, + .RX_NUM = 0, + .fd = -1, + .irq_gpio = -1, + .TP_FW = 0, + .fw = NULL, + .test_item = 0, + }; + + if (!ts) + return 0; + sec_ops = (struct sec_proc_operations *)ts->private_data; + if (!sec_ops) + return 0; + if (!sec_ops->auto_test) { + seq_printf(s, "Not support auto-test proc node\n"); + return 0; + } + + //step1:disable_irq && get mutex locked + disable_irq_nosync(ts->irq); + mutex_lock(&ts->mutex); + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + //step2: create a file to store test data in /sdcard/Tp_Test + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + snprintf(data_buf, 128, "/sdcard/TpTestReport/screenOn/tp_testlimit_%02d%02d%02d-%02d%02d%02d-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + old_fs = get_fs(); + set_fs(KERNEL_DS); + ksys_mkdir("/sdcard/TpTestReport", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn", 0666); + fd = ksys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); + if (fd < 0) { + TPD_INFO("Open log file '%s' failed.\n", data_buf); + set_fs(old_fs); + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + return 0; + } + + //step3:request test limit data from userspace + ret = request_firmware(&fw, ts->panel_data.test_limit_name, ts->dev); + if (ret < 0) { + TPD_INFO("Request firmware failed - %s (%d)\n", ts->panel_data.test_limit_name, ret); + seq_printf(s, "No limit IMG\n"); + ksys_close(fd); + set_fs(old_fs); + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + return 0; + } + + //step4: decode the limit image + test_head = (struct sec_test_header *)fw->data; + p_data32 = (uint32_t *)(fw->data + 16); + if ((test_head->magic1 != 0x494D494C) || (test_head->magic2 != 0x474D4954)) { + TPD_INFO("limit image is not generated\n"); + seq_printf(s, "limit image is not generated by\n"); + goto OUT; + } + TPD_INFO("current test item: %llx\n", test_head->test_item); + + //init syna_testdata + sec_testdata.fd = fd; + sec_testdata.TX_NUM = ts->hw_res.TX_NUM; + sec_testdata.RX_NUM = ts->hw_res.RX_NUM; + sec_testdata.irq_gpio = ts->hw_res.irq_gpio; + sec_testdata.TP_FW = ts->panel_data.TP_FW; + sec_testdata.fw = fw; + sec_testdata.test_item = test_head->test_item; + + sec_ops->auto_test(s, ts->chip_data, &sec_testdata); + +OUT: + //step4: close file && release test limit firmware + if (fd >= 0) { + ksys_close(fd); + set_fs(old_fs); + } + release_firmware(fw); + + //step5: return to normal mode + ts->ts_ops->reset(ts->chip_data); + operate_mode_switch(ts); + + //step6: unlock the mutex && enable irq trigger + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + + return 0; +} + +static int baseline_autotest_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_auto_test_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_auto_test_proc_fops = { + .owner = THIS_MODULE, + .open = baseline_autotest_open, + .read = seq_read, + .release = single_release, +}; + +static int calibrate_fops_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct sec_proc_operations *sec_ops = (struct sec_proc_operations *)ts->private_data; + + if (!sec_ops->calibrate) + return 0; + + disable_irq_nosync(ts->irq); + TPD_INFO("Start calibration\n"); + mutex_lock(&ts->mutex); +// if (!ts->touch_count) { + sec_ops->calibrate(s, ts->chip_data); +// } else { +// seq_printf(s, "1 error, release touch on the screen\n"); +// } + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + + return 0; +} + +static int proc_calibrate_fops_open(struct inode *inode, struct file *file) +{ + return single_open(file, calibrate_fops_read_func, PDE_DATA(inode)); +} + +static const struct file_operations proc_calibrate_fops = { + .owner = THIS_MODULE, + .open = proc_calibrate_fops_open, + .read = seq_read, + .release = single_release, +}; + +static int verify_fops_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct sec_proc_operations *sec_ops = (struct sec_proc_operations *)ts->private_data; + + if (!sec_ops->verify_calibration) + return 0; + + disable_irq_nosync(ts->irq); + mutex_lock(&ts->mutex); + TPD_INFO("Start verify calibration result\n"); + if (!ts->touch_count) { + sec_ops->verify_calibration(s, ts->chip_data); + } else { + seq_printf(s, "1 error, skip verify when touch on screen\n"); + } + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + + return 0; +} + +static int proc_verify_fops_open(struct inode *inode, struct file *file) +{ + return single_open(file, verify_fops_read_func, PDE_DATA(inode)); +} + +static const struct file_operations proc_verify_fops = { + .owner = THIS_MODULE, + .open = proc_verify_fops_open, + .read = seq_read, + .release = single_release, +}; + +static int calibrate_data_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct sec_proc_operations *sec_ops = (struct sec_proc_operations *)ts->private_data; + + if (!sec_ops->calibration_data) + return 0; + + if (ts->is_suspended) + return 0; + disable_irq_nosync(ts->irq); + mutex_lock(&ts->mutex); + if (!ts->touch_count) { + sec_ops->calibration_data(s, ts->chip_data); + } else { + seq_printf(s, "1 error, skip calibrate_data when touch on screen\n"); + } + mutex_unlock(&ts->mutex); + enable_irq(ts->irq); + + return 0; +} + +static int proc_calibrate_data_fops_open(struct inode *inode, struct file *file) +{ + return single_open(file, calibrate_data_read_func, PDE_DATA(inode)); +} + +static const struct file_operations proc_calibrate_data_fops = { + .owner = THIS_MODULE, + .open = proc_calibrate_data_fops_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/baseline_test +int sec_create_proc(struct touchpanel_data *ts, struct sec_proc_operations *sec_ops) +{ + int ret = 0; + + // touchpanel_auto_test interface + struct proc_dir_entry *prEntry_tmp = NULL; + ts->private_data = sec_ops; + prEntry_tmp = proc_create_data("baseline_test", 0666, ts->prEntry_tp, &tp_auto_test_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("calibration", 0666, ts->prEntry_tp, &proc_calibrate_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("calibration_verify", 0666, ts->prEntry_tp, &proc_verify_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("calibrate_data", 0666, ts->prEntry_tp, &proc_calibrate_data_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + return ret; +} diff --git a/drivers/oneplus/input/touchscreen/samsung/sec_common.h b/drivers/oneplus/input/touchscreen/samsung/sec_common.h new file mode 100755 index 0000000000000000000000000000000000000000..c5de019311122ebd21595e5ebed413bc49f75150 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/samsung/sec_common.h @@ -0,0 +1,84 @@ +/*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : sec_common.h + * + * Function : third party interface + * + * Source : provide by LSI + * + * Version : V1.0 + * + ***********************************************************/ +#ifndef SEC_H +#define SEC_H + +/*********PART1:Head files**********************/ +#include +#include +#include +#include +#include + +#include "../touchpanel_common.h" + +#define I2C_BURSTMAX (256) +/*********PART2:Define Area**********************/ +struct sec_testdata{ + int TX_NUM; + int RX_NUM; + int fd; + int irq_gpio; + uint64_t TP_FW; + const struct firmware *fw; + uint64_t test_item; +}; + +struct sec_test_header { + uint32_t magic1; + uint32_t magic2; + uint64_t test_item; +}; + +enum { + LIMIT_TYPE_NO_DATA = 0x00, //means no limit data + LIMIT_TYPE_CERTAIN_DATA = 0x01, //means all nodes limit data is a certain data + LIMIT_TYPE_EACH_NODE_DATA = 0x02, //means all nodes have it's own limit + LIMIT_TYPE_INVALID_DATA = 0xFF, //means wrong limit data type +}; + +//test item +enum { + TYPE_ERROR = 0x00, + TYPE_MUTUAL_RAW_OFFSET_DATA_SDC = 0x01, + TYPE_MUTUAL_RAW_DATA = 0x02, + TYPE_SELF_RAW_OFFSET_DATA_SDC = 0x03, + TYPE_MUTU_RAW_NOI_P2P = 0x04, + TYPE_MAX = 0xFF, +}; + +struct sec_test_item_header { + uint32_t item_magic; + uint32_t item_size; + uint16_t item_bit; + uint16_t item_limit_type; + uint32_t top_limit_offset; + uint32_t floor_limit_offset; + uint32_t para_num; +}; + +/*********PART3:Struct Area**********************/ +struct sec_proc_operations { + void (*auto_test) (struct seq_file *s, void *chip_data, struct sec_testdata *sec_testdata); + void (*calibrate) (struct seq_file *s, void *chip_data); + void (*verify_calibration) (struct seq_file *s, void *chip_data); + void (*calibration_data) (struct seq_file *s, void *chip_data); +}; + +/*********PART4:function declare*****************/ +int sec_create_proc(struct touchpanel_data *ts, struct sec_proc_operations *sec_ops); +void sec_flash_proc_init(struct touchpanel_data *ts, const char *name); +void sec_limit_read(struct seq_file *s, struct touchpanel_data *ts); +void sec_raw_device_init(struct touchpanel_data *ts); + +#endif diff --git a/drivers/oneplus/input/touchscreen/synaptics/Kconfig b/drivers/oneplus/input/touchscreen/synaptics/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..3420bce4ceeadd4ad78314818a2b50b60b82be8d --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/Kconfig @@ -0,0 +1,2 @@ + +source "drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Kconfig" diff --git a/drivers/oneplus/input/touchscreen/synaptics/Makefile b/drivers/oneplus/input/touchscreen/synaptics/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..c9411cef2832ea93258b0144cf53128bb4149649 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL) +=syna_tcm_oncell/ +#obj-$(CONFIG_TOUCHPANEL_SYNAPTICS) += synaptics_touch_panel_remote.o +#obj-$(CONFIG_TOUCHPANEL_SYNAPTICS) += synaptics_common.o + +obj-y += synaptics_touch_panel_remote.o +obj-y += synaptics_common.o +#endif diff --git a/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Kconfig b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..499862eb1804025001d1e0269649ac704dbe6743 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Kconfig @@ -0,0 +1,9 @@ +# +# Synaptics TCM touchscreen driver configuration +# +config TOUCHPANEL_SYNAPTICS_TCM_ONCELL + default y + bool "TP IC enable or not for oem" + ---help--- + say Y to enable driver for Touchpanel + diff --git a/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Makefile b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..72d0a6c4ae5c0a0dccabfd827a0c64f30d0fddb6 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the Synaptics TCM touchscreen driver. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL) += synaptics_tcm_oncell.o +obj-$(CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL) += synaptics_tcm_device.o +obj-$(CONFIG_TOUCHPANEL_SYNAPTICS_TCM_ONCELL) += synaptics_tcm_recovery.o + diff --git a/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_device.c b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_device.c new file mode 100755 index 0000000000000000000000000000000000000000..410252b441bc0c1b23690c20741e5f0f87465bf9 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_device.c @@ -0,0 +1,581 @@ + +#include +#include +#include +#include +#include "synaptics_tcm_oncell.h" + +#define CHAR_DEVICE_NAME "tcm" +#define PLATFORM_DRIVER_NAME "synaptics_tcm" +#define CONCURRENT true + +#define DEVICE_IOC_MAGIC 's' +#define DEVICE_IOC_RESET _IO(DEVICE_IOC_MAGIC, 0) /* 0x00007300 */ +#define DEVICE_IOC_IRQ _IOW(DEVICE_IOC_MAGIC, 1, int) /* 0x40047301 */ +#define DEVICE_IOC_RAW _IOW(DEVICE_IOC_MAGIC, 2, int) /* 0x40047302 */ +#define DEVICE_IOC_CONCURRENT _IOW(DEVICE_IOC_MAGIC, 3, int) /* 0x40047303 */ + +static struct device_hcd *g_device_hcd = NULL; + +static int rmidev_major_num; + +static void device_capture_touch_report(unsigned int count) +{ + int retval; + unsigned char id; + unsigned int idx; + unsigned int size; + unsigned char *data; + struct syna_tcm_data *tcm_info = g_device_hcd->tcm_info; + static bool report; + static unsigned int offset; + static unsigned int remaining_size; + + if (count < 2) + return; + + data = &g_device_hcd->resp.buf[0]; + + if (data[0] != MESSAGE_MARKER) + return; + + id = data[1]; + size = 0; + + LOCK_BUFFER(g_device_hcd->report); + + switch (id) { + case REPORT_TOUCH: + if (count >= 4) { + remaining_size = le2_to_uint(&data[2]); + } else { + report = false; + goto exit; + } + retval = syna_tcm_alloc_mem(&g_device_hcd->report, remaining_size); + if (retval < 0) { + pr_err("Failed to allocate memory for device_hcd->report.buf\n"); + report = false; + goto exit; + } + idx = 4; + size = count - idx; + offset = 0; + report = true; + break; + case STATUS_CONTINUED_READ: + if (report == false) + goto exit; + if (count >= 2) { + idx = 2; + size = count - idx; + } + break; + default: + goto exit; + } + + if (size) { + size = MIN(size, remaining_size); + retval = secure_memcpy(&g_device_hcd->report.buf[offset], + g_device_hcd->report.buf_size - offset, + &data[idx], + count - idx, + size); + if (retval < 0) { + pr_err("Failed to copy touch report data\n"); + report = false; + goto exit; + } else { + offset += size; + remaining_size -= size; + g_device_hcd->report.data_length += size; + } + } + + if (remaining_size) + goto exit; + + LOCK_BUFFER(tcm_info->report.buffer); + + tcm_info->report.buffer.buf = g_device_hcd->report.buf; + tcm_info->report.buffer.buf_size = g_device_hcd->report.buf_size; + tcm_info->report.buffer.data_length = g_device_hcd->report.data_length; + + g_device_hcd->report_touch(tcm_info); + + UNLOCK_BUFFER(tcm_info->report.buffer); + + report = false; + +exit: + UNLOCK_BUFFER(g_device_hcd->report); + + return; +} + +static int device_capture_touch_report_config(unsigned int count) +{ + int retval; + unsigned int size; + unsigned char *data; + struct syna_tcm_data *tcm_info = g_device_hcd->tcm_info; + + if (g_device_hcd->raw_mode) { + if (count < 3) { + pr_err("Invalid write data\n"); + return -EINVAL; + } + + size = le2_to_uint(&g_device_hcd->out.buf[1]); + + if (count - 3 < size) { + pr_err("Incomplete write data\n"); + return -EINVAL; + } + + if (!size) + return 0; + + data = &g_device_hcd->out.buf[3]; + } else { + size = count - 1; + + if (!size) + return 0; + + data = &g_device_hcd->out.buf[1]; + } + + LOCK_BUFFER(tcm_info->config); + + retval = syna_tcm_alloc_mem(&tcm_info->config, size); + if (retval < 0) { + pr_err("Failed to allocate memory for tcm_info->config.buf\n"); + UNLOCK_BUFFER(tcm_info->config); + return retval; + } + + retval = secure_memcpy(tcm_info->config.buf, + tcm_info->config.buf_size, + data, + size, + size); + if (retval < 0) { + pr_err("Failed to copy touch report config data\n"); + UNLOCK_BUFFER(tcm_info->config); + return retval; + } + + tcm_info->config.data_length = size; + + UNLOCK_BUFFER(tcm_info->config); + + return 0; +} + +#ifdef HAVE_UNLOCKED_IOCTL +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +#else +static int device_ioctl(struct inode *inp, struct file *filp, unsigned int cmd, + unsigned long arg) +#endif +{ + int retval = 0; + struct syna_tcm_data *tcm_info = g_device_hcd->tcm_info; + + pr_info("%s: 0x%x\n", __func__, cmd); + + mutex_lock(&g_device_hcd->extif_mutex); + + switch (cmd) { + case DEVICE_IOC_RESET: + retval = g_device_hcd->reset(tcm_info); + break; + case DEVICE_IOC_IRQ: + if (arg == 0) { + if (g_device_hcd->flag == 1) { + disable_irq(g_device_hcd->irq); + g_device_hcd->flag = 0; + } + } else if (arg == 1) { + if (g_device_hcd->flag == 0) { + enable_irq(g_device_hcd->irq); + g_device_hcd->flag = 1; + } + } + break; + case DEVICE_IOC_RAW: + if (arg == 0) + g_device_hcd->raw_mode = false; + else if (arg == 1) + g_device_hcd->raw_mode = true; + break; + case DEVICE_IOC_CONCURRENT: + if (arg == 0) + g_device_hcd->concurrent = false; + else if (arg == 1) + g_device_hcd->concurrent = true; + break; + default: + retval = -ENOTTY; + break; + } + + mutex_unlock(&g_device_hcd->extif_mutex); + + return retval; +} + +static loff_t device_llseek(struct file *filp, loff_t off, int whence) +{ + return -EINVAL; +} + +static ssize_t device_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + int retval; + struct syna_tcm_data *tcm_info = g_device_hcd->tcm_info; + + if (count == 0) + return 0; + + mutex_lock(&g_device_hcd->extif_mutex); + + LOCK_BUFFER(g_device_hcd->resp); + + if (g_device_hcd->raw_mode) { + retval = syna_tcm_alloc_mem(&g_device_hcd->resp, count); + if (retval < 0) { + pr_err("Failed to allocate memory for device_hcd->resp.buf\n"); + UNLOCK_BUFFER(g_device_hcd->resp); + goto exit; + } + + retval = g_device_hcd->read_message(tcm_info, + g_device_hcd->resp.buf, + count); + if (retval < 0) { + pr_err("Failed to read message\n"); + UNLOCK_BUFFER(g_device_hcd->resp); + goto exit; + } + } else { + if (count != g_device_hcd->resp.data_length) { + pr_err("Invalid length information\n"); + UNLOCK_BUFFER(g_device_hcd->resp); + retval = -EINVAL; + goto exit; + } + } + + if (copy_to_user(buf, g_device_hcd->resp.buf, count)) { + pr_err("Failed to copy data to user space\n"); + UNLOCK_BUFFER(g_device_hcd->resp); + retval = -EINVAL; + goto exit; + } + + if (!g_device_hcd->concurrent) + goto skip_concurrent; + + if (g_device_hcd->report_touch == NULL) { + pr_err("Unable to report touch\n"); + g_device_hcd->concurrent = false; + } + + if (g_device_hcd->raw_mode) + device_capture_touch_report(count); + +skip_concurrent: + UNLOCK_BUFFER(g_device_hcd->resp); + + retval = count; + +exit: + mutex_unlock(&g_device_hcd->extif_mutex); + + return retval; +} + +static ssize_t device_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + int retval; + struct syna_tcm_data *tcm_info = g_device_hcd->tcm_info; + + if (count == 0) + return 0; + + mutex_lock(&g_device_hcd->extif_mutex); + + LOCK_BUFFER(g_device_hcd->out); + + retval = syna_tcm_alloc_mem(&g_device_hcd->out, count == 1 ? count + 1 : count); + if (retval < 0) { + pr_err("Failed to allocate memory for device_hcd->out.buf\n"); + UNLOCK_BUFFER(g_device_hcd->out); + goto exit; + } + + if (copy_from_user(g_device_hcd->out.buf, buf, count)) { + pr_err("Failed to copy data from user space\n"); + UNLOCK_BUFFER(g_device_hcd->out); + retval = -EINVAL; + goto exit; + } + + LOCK_BUFFER(g_device_hcd->resp); + + pr_info("%s: cmd 0x%x\n", __func__, g_device_hcd->out.buf[0]); + if (g_device_hcd->raw_mode) { + retval = g_device_hcd->write_message(tcm_info, + g_device_hcd->out.buf[0], + &g_device_hcd->out.buf[1], + count == 1 ? count : count - 1, + NULL, + NULL, + NULL, + 0); + } else { + mutex_lock(&tcm_info->reset_mutex); + retval = g_device_hcd->write_message(tcm_info, + g_device_hcd->out.buf[0], + &g_device_hcd->out.buf[1], + count == 1 ? count : count - 1, + &g_device_hcd->resp.buf, + &g_device_hcd->resp.buf_size, + &g_device_hcd->resp.data_length, + 0); + mutex_unlock(&tcm_info->reset_mutex); + } + + if (g_device_hcd->out.buf[0] == CMD_ERASE_FLASH) { + msleep(500); + } + + if (retval < 0) { + pr_err("Failed to write command 0x%02x\n", + g_device_hcd->out.buf[0]); + UNLOCK_BUFFER(g_device_hcd->resp); + UNLOCK_BUFFER(g_device_hcd->out); + goto exit; + } + + if (count && g_device_hcd->out.buf[0] == CMD_SET_TOUCH_REPORT_CONFIG) { + retval = device_capture_touch_report_config(count); + if (retval < 0) { + pr_err("Failed to capture touch report config\n"); + } + } + + UNLOCK_BUFFER(g_device_hcd->out); + + if (g_device_hcd->raw_mode) + retval = count; + else + retval = g_device_hcd->resp.data_length; + + UNLOCK_BUFFER(g_device_hcd->resp); + +exit: + mutex_unlock(&g_device_hcd->extif_mutex); + + return retval; +} + +static int device_open(struct inode *inp, struct file *filp) +{ + int retval; + + mutex_lock(&g_device_hcd->extif_mutex); + + if (g_device_hcd->ref_count < 1) { + g_device_hcd->ref_count++; + retval = 0; + } else { + retval = -EACCES; + } + + g_device_hcd->flag = 1; + + mutex_unlock(&g_device_hcd->extif_mutex); + + return retval; +} + +static int device_release(struct inode *inp, struct file *filp) +{ + + mutex_lock(&g_device_hcd->extif_mutex); + + if (g_device_hcd->ref_count) + g_device_hcd->ref_count--; + + mutex_unlock(&g_device_hcd->extif_mutex); + + return 0; +} + +static char *device_devnode(struct device *dev, umode_t *mode) +{ + if (!mode) + return NULL; + + *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + return kasprintf(GFP_KERNEL, "%s/%s", PLATFORM_DRIVER_NAME, + dev_name(dev)); +} + +static int device_create_class(void) +{ + if (g_device_hcd->class != NULL) + return 0; + + g_device_hcd->class = class_create(THIS_MODULE, PLATFORM_DRIVER_NAME); + + if (IS_ERR(g_device_hcd->class)) { + pr_err("Failed to create class\n"); + return -ENODEV; + } + + g_device_hcd->class->devnode = device_devnode; + + return 0; +} + +static const struct file_operations device_fops = { + .owner = THIS_MODULE, +#ifdef HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = device_ioctl, +#ifdef HAVE_COMPAT_IOCTL + .compat_ioctl = device_ioctl, +#endif +#else + .ioctl = device_ioctl, +#endif + .llseek = device_llseek, + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release, +}; + +static int device_init(struct syna_tcm_data *tcm_info) +{ + int retval; + dev_t dev_num; + + g_device_hcd = kzalloc(sizeof(*g_device_hcd), GFP_KERNEL); + if (!g_device_hcd) { + pr_err("Failed to allocate memory for device_hcd\n"); + return -ENOMEM; + } + + mutex_init(&g_device_hcd->extif_mutex); + + g_device_hcd->tcm_info = tcm_info; + g_device_hcd->concurrent = CONCURRENT; + + INIT_BUFFER(g_device_hcd->out, false); + INIT_BUFFER(g_device_hcd->resp, false); + INIT_BUFFER(g_device_hcd->report, false); + + if (rmidev_major_num) { + dev_num = MKDEV(rmidev_major_num, 0); + retval = register_chrdev_region(dev_num, 1, + PLATFORM_DRIVER_NAME); + if (retval < 0) { + pr_err("Failed to register char device\n"); + goto err_register_chrdev_region; + } + } else { + retval = alloc_chrdev_region(&dev_num, 0, 1, + PLATFORM_DRIVER_NAME); + if (retval < 0) { + pr_err("Failed to allocate char device\n"); + goto err_alloc_chrdev_region; + } + + rmidev_major_num = MAJOR(dev_num); + } + + g_device_hcd->dev_num = dev_num; + + cdev_init(&g_device_hcd->char_dev, &device_fops); + + retval = cdev_add(&g_device_hcd->char_dev, dev_num, 1); + if (retval < 0) { + pr_err("Failed to add char device\n"); + goto err_add_chardev; + } + + retval = device_create_class(); + if (retval < 0) { + pr_err("Failed to create class\n"); + goto err_create_class; + } + + g_device_hcd->device = device_create(g_device_hcd->class, NULL, + g_device_hcd->dev_num, NULL, CHAR_DEVICE_NAME"%d", + MINOR(g_device_hcd->dev_num)); + if (IS_ERR(g_device_hcd->device)) { + pr_err("Failed to create device\n"); + retval = -ENODEV; + goto err_create_device; + } + return 0; + +err_create_device: + class_destroy(g_device_hcd->class); + +err_create_class: + cdev_del(&g_device_hcd->char_dev); + +err_add_chardev: + unregister_chrdev_region(dev_num, 1); + +err_alloc_chrdev_region: +err_register_chrdev_region: + RELEASE_BUFFER(g_device_hcd->report); + RELEASE_BUFFER(g_device_hcd->resp); + RELEASE_BUFFER(g_device_hcd->out); + + kfree(g_device_hcd); + g_device_hcd = NULL; + + return retval; +} + +struct device_hcd *syna_remote_device_init(struct syna_tcm_data *tcm_info) +{ + device_init(tcm_info); + + return g_device_hcd; +} + +int syna_remote_device_destory(struct syna_tcm_data *tcm_info) +{ + if (!g_device_hcd) + return 0; + + device_destroy(g_device_hcd->class, g_device_hcd->dev_num); + + class_destroy(g_device_hcd->class); + + cdev_del(&g_device_hcd->char_dev); + + unregister_chrdev_region(g_device_hcd->dev_num, 1); + + RELEASE_BUFFER(g_device_hcd->report); + RELEASE_BUFFER(g_device_hcd->resp); + RELEASE_BUFFER(g_device_hcd->out); + + kfree(g_device_hcd); + g_device_hcd = NULL; + + return 0; +} + diff --git a/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_oncell.c b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_oncell.c new file mode 100755 index 0000000000000000000000000000000000000000..b5b53ae1554e8a498d1a9afb98c2901cdca9d8d9 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_oncell.c @@ -0,0 +1,4828 @@ + +#include +#include +#include +#include +#include "synaptics_tcm_oncell.h" + +#define PREDICTIVE_READING +#define MIN_READ_LENGTH 9 +#define RESPONSE_TIMEOUT_MS_SHORT 300 +#define RESPONSE_TIMEOUT_MS_DEFAULT 1000 +#define RESPONSE_TIMEOUT_MS_LONG 3000 + +#define ERASE_FLASH_DELAY_MS 5000 +#define WRITE_FLASH_DELAY_MS 200 + +#define APP_STATUS_POLL_TIMEOUT_MS 1000 +#define APP_STATUS_POLL_MS 100 + +#define NOT_NEED_SLEEP 1 + +DECLARE_COMPLETION(response_complete); +DECLARE_COMPLETION(report_complete); + +extern int tp_register_times; +extern struct touchpanel_data *g_tp; +static struct syna_tcm_data *g_tcm_info; + +extern struct device_hcd *syna_remote_device_init(struct syna_tcm_data *tcm_info); +extern int syna_remote_device_destory(struct syna_tcm_data *tcm_info); +static void syna_main_register(struct seq_file *s, void *chip_data); + +static int syna_tcm_write_message(struct syna_tcm_data *tcm_info, + unsigned char command, unsigned char *payload, + unsigned int length, unsigned char **resp_buf, + unsigned int *resp_buf_size, unsigned int *resp_length, + unsigned int polling_delay_ms); +static void syna_tcm_test_report(struct syna_tcm_data *tcm_info); +static int syna_tcm_helper(struct syna_tcm_data *tcm_info); +static int syna_power_control(void *chip_data, bool enable); + +static int syna_tp_delta_print(struct syna_tcm_data *tcm_info); + +//static int syna_tcm_enable_report(struct syna_tcm_data *tcm_info, enum report_type report_type, bool enable); + +inline int syna_tcm_rmi_read(struct syna_tcm_data *tcm_info, + unsigned short addr, unsigned char *data, unsigned int length) +{ + int retval = 0; + unsigned short tmp_addr = tcm_info->client->addr; + + tcm_info->client->addr = tcm_info->ubl_addr; + retval = touch_i2c_read_block(tcm_info->client, addr, length, data); + tcm_info->client->addr = tmp_addr; + + return retval; +} + +inline int syna_tcm_rmi_write(struct syna_tcm_data *tcm_info, + unsigned short addr, unsigned char *data, unsigned int length) +{ + int retval = 0; + unsigned short tmp_addr = tcm_info->client->addr; + + tcm_info->client->addr = tcm_info->ubl_addr; + retval = touch_i2c_write_block(tcm_info->client, addr, length, data); + tcm_info->client->addr = tmp_addr; + + return retval; +} + +static inline int syna_tcm_read(struct syna_tcm_data *tcm_info, + unsigned char *data, unsigned int length) +{ + return touch_i2c_continue_read(tcm_info->client, length, data); +} + +static inline int syna_tcm_write(struct syna_tcm_data *tcm_info, + unsigned char *data, unsigned int length) +{ + return touch_i2c_continue_write(tcm_info->client, length, data); +} + +/** + * syna_get_report_data - Retrieve data from touch report + * + * @tcm_info: handle of tcm module + * @offset: start bit of retrieved data + * @bits: total bits of retrieved data + * @data: pointer of data, at most 4 byte + * Retrieve data from the touch report based on the bit offset and bit length + * information from the touch report configuration. + */ +static int syna_get_report_data(struct syna_tcm_data *tcm_info, unsigned int offset, + unsigned int bits, unsigned int *data) +{ + unsigned char mask = 0; + unsigned char byte_data = 0; + unsigned int output_data = 0; + unsigned int bit_offset = offset % 8; + unsigned int byte_offset = offset / 8; + unsigned int data_bits = 0; + unsigned int available_bits = 0; + unsigned int remaining_bits = bits; + unsigned char *touch_report = tcm_info->report.buffer.buf; + int retval = 0; + + if (bits == 0 || bits > 32) { + TPD_DEBUG("larger than 32 bits:%d\n", bits); + retval = secure_memcpy((unsigned char *)data, bits / 8, &touch_report[byte_offset], bits / 8, bits / 8); + if (retval < 0) { + TPD_INFO("Failed to copy report data\n"); + return retval; + } + return 0; + } + + if (offset + bits > tcm_info->report.buffer.data_length * 8) { + TPD_DETAIL("offset and bits beyond total read length\n"); + *data = 0; + return 0; + } + + while (remaining_bits) { + byte_data = touch_report[byte_offset]; + byte_data >>= bit_offset; + + available_bits = 8 - bit_offset; + data_bits = MIN(available_bits, remaining_bits); + mask = 0xff >> (8 - data_bits); + + byte_data &= mask; + + output_data |= byte_data << (bits - remaining_bits); + + bit_offset = 0; + byte_offset += 1; + remaining_bits -= data_bits; + } + + *data = output_data; + + return 0; +} + +/** + * touch_parse_report() - Parse touch report + * + * Traverse through the touch report configuration and parse the touch report + * generated by the device accordingly to retrieve the touch data. + */ +static int syna_parse_report(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + bool active_only = false, num_of_active_objects = false; + unsigned char code; + unsigned int size = 0, idx = 0, obj = 0; + unsigned int next = 0, data = 0, bits = 0, offset = 0, objects = 0; + unsigned int active_objects = 0; + unsigned int report_size = 0, config_size = 0; + unsigned char *config_data = NULL; + struct touch_hcd *touch_hcd = NULL; + struct touch_data *touch_data = NULL; + struct object_data *object_data = NULL; + static unsigned int end_of_foreach = 0; + + touch_hcd = tcm_info->touch_hcd; + touch_data = &touch_hcd->touch_data; + object_data = touch_hcd->touch_data.object_data; + config_data = tcm_info->config.buf; + config_size = tcm_info->config.data_length; + report_size = tcm_info->report.buffer.data_length; + size = sizeof(*object_data) * touch_hcd->max_objects; + memset(touch_hcd->touch_data.object_data, 0x00, size); + + while (idx < config_size) { + code = config_data[idx++]; + switch (code) { + case TOUCH_END: + goto exit; + case TOUCH_FOREACH_ACTIVE_OBJECT: + obj = 0; + next = idx; + active_only = true; + break; + case TOUCH_FOREACH_OBJECT: + obj = 0; + next = idx; + active_only = false; + break; + case TOUCH_FOREACH_END: + end_of_foreach = idx; + if (active_only) { + if (num_of_active_objects) { + objects++; + if (objects < active_objects) + idx = next; + } else if (offset < report_size * 8) { + idx = next; + } + } else { + obj++; + if (obj < touch_hcd->max_objects) + idx = next; + } + break; + case TOUCH_PAD_TO_NEXT_BYTE: + offset = ceil_div(offset, 8) * 8; + break; + case TOUCH_TIMESTAMP: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get timestamp\n"); + return retval; + } + touch_data->timestamp = data; + offset += bits; + break; + case TOUCH_OBJECT_N_INDEX: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &obj); + if (retval < 0) { + TPD_INFO("Failed to get object index\n"); + return retval; + } + offset += bits; + break; + case TOUCH_OBJECT_N_CLASSIFICATION: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object classification\n"); + return retval; + } + object_data[obj].status = data; + offset += bits; + break; + case TOUCH_OBJECT_N_X_POSITION: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object x position\n"); + return retval; + } + object_data[obj].x_pos = data; + offset += bits; + break; + case TOUCH_OBJECT_N_Y_POSITION: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object y position\n"); + return retval; + } + object_data[obj].y_pos = data; + offset += bits; + break; + case TOUCH_OBJECT_N_Z: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object z\n"); + return retval; + } + object_data[obj].z = data; + offset += bits; + break; + case TOUCH_OBJECT_N_X_WIDTH: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object x width\n"); + return retval; + } + object_data[obj].x_width = data; + offset += bits; + break; + case TOUCH_OBJECT_N_Y_WIDTH: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object y width\n"); + return retval; + } + object_data[obj].y_width = data; + offset += bits; + break; + case TOUCH_OBJECT_N_TX_POSITION_TIXELS: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object tx position\n"); + return retval; + } + object_data[obj].tx_pos = data; + offset += bits; + break; + case TOUCH_OBJECT_N_RX_POSITION_TIXELS: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get object rx position\n"); + return retval; + } + object_data[obj].rx_pos = data; + offset += bits; + break; + case TOUCH_0D_BUTTONS_STATE: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get 0D buttons state\n"); + return retval; + } + touch_data->buttons_state = data; + offset += bits; + break; + case TOUCH_GESTURE_DOUBLE_TAP: + case TOUCH_REPORT_GESTURE_SWIPE: + case TOUCH_REPORT_GESTURE_CIRCLE: + case TOUCH_REPORT_GESTURE_UNICODE: + case TOUCH_REPORT_GESTURE_VEE: + case TOUCH_REPORT_GESTURE_TRIANGLE: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get gesture double tap\n"); + return retval; + } + touch_data->lpwg_gesture = data; + offset += bits; + break; + case TOUCH_REPORT_GESTURE_INFO: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, (unsigned int *)(&touch_data->extra_gesture_info[0])); + if (retval < 0) { + TPD_INFO("Failed to get gesture double tap\n"); + return retval; + } + offset += bits; + break; + case TOUCH_REPORT_GESTURE_COORDINATE: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, (unsigned int *)(&touch_data->data_point[0])); + if (retval < 0) { + TPD_INFO("Failed to get gesture double tap\n"); + return retval; + } + offset += bits; + break; + case TOUCH_FRAME_RATE: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get frame rate\n"); + return retval; + } + touch_data->frame_rate = data; + offset += bits; + break; + case TOUCH_POWER_IM: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get power IM\n"); + return retval; + } + touch_data->power_im = data; + offset += bits; + break; + case TOUCH_CID_IM: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get CID IM\n"); + return retval; + } + touch_data->cid_im = data; + offset += bits; + break; + case TOUCH_RAIL_IM: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get rail IM\n"); + return retval; + } + touch_data->rail_im = data; + offset += bits; + break; + case TOUCH_CID_VARIANCE_IM: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get CID variance IM\n"); + return retval; + } + touch_data->cid_variance_im = data; + offset += bits; + break; + case TOUCH_NSM_FREQUENCY: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get NSM frequency\n"); + return retval; + } + touch_data->nsm_frequency = data; + offset += bits; + break; + case TOUCH_NSM_STATE: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get NSM state\n"); + return retval; + } + touch_data->nsm_state = data; + offset += bits; + break; + case TOUCH_NUM_OF_ACTIVE_OBJECTS: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get number of active objects\n"); + return retval; + } + active_objects = data; + num_of_active_objects = true; + touch_data->num_of_active_objects = data; + offset += bits; + if (touch_data->num_of_active_objects == 0) + idx = end_of_foreach; + break; + case TOUCH_NUM_OF_CPU_CYCLES_USED_SINCE_LAST_FRAME: + bits = config_data[idx++]; + retval = syna_get_report_data(tcm_info, offset, bits, &data); + if (retval < 0) { + TPD_INFO("Failed to get number of CPU cycles used since last frame\n"); + return retval; + } + touch_data->num_of_cpu_cycles = data; + offset += bits; + break; + case TOUCH_TUNING_GAUSSIAN_WIDTHS: + bits = config_data[idx++]; + offset += bits; + break; + case TOUCH_TUNING_SMALL_OBJECT_PARAMS: + bits = config_data[idx++]; + offset += bits; + break; + case TOUCH_TUNING_0D_BUTTONS_VARIANCE: + bits = config_data[idx++]; + offset += bits; + break; + } + } + +exit: + return 0; +} + +static int syna_get_input_params(struct syna_tcm_data *tcm_info) +{ + int retval; + + LOCK_BUFFER(tcm_info->config); + + retval = syna_tcm_write_message(tcm_info, CMD_GET_TOUCH_REPORT_CONFIG, + NULL, 0, &tcm_info->config.buf, &tcm_info->config.buf_size, &tcm_info->config.data_length, 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_GET_TOUCH_REPORT_CONFIG)); + UNLOCK_BUFFER(tcm_info->config); + return retval; + } + + UNLOCK_BUFFER(tcm_info->config); + + return 0; +} + +static int syna_set_default_report_config(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + int length = 0; + + LOCK_BUFFER(tcm_info->config); + + length = tcm_info->default_config.buf_size; + + if (tcm_info->default_config.buf) { + retval = syna_tcm_alloc_mem(&tcm_info->config, length); + if (retval < 0) { + TPD_INFO("Failed to alloc mem\n"); + goto exit; + } + + memcpy(tcm_info->config.buf, tcm_info->default_config.buf, length); + tcm_info->config.buf_size = tcm_info->default_config.buf_size; + tcm_info->config.data_length = tcm_info->default_config.data_length; + } + +exit: + UNLOCK_BUFFER(tcm_info->config); + + return retval; +} + +static int syna_get_default_report_config(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + unsigned int length; + + length = le2_to_uint(tcm_info->app_info.max_touch_report_config_size); + + LOCK_BUFFER(tcm_info->default_config); + + retval = syna_tcm_write_message(tcm_info, + CMD_GET_TOUCH_REPORT_CONFIG, + NULL, + 0, + &tcm_info->default_config.buf, + &tcm_info->default_config.buf_size, + &tcm_info->default_config.data_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_GET_TOUCH_REPORT_CONFIG)); + goto exit; + } + +exit: + UNLOCK_BUFFER(tcm_info->default_config); + return retval; +} + +static int syna_set_normal_report_config(struct syna_tcm_data *tcm_info) +{ + int retval; + unsigned int idx = 0; + unsigned int length; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + + TPD_DEBUG("%s:set normal report\n", __func__); + length = le2_to_uint(tcm_info->app_info.max_touch_report_config_size); + + if (length < TOUCH_REPORT_CONFIG_SIZE) { + TPD_INFO("Invalid maximum touch report config size\n"); + return -EINVAL; + } + + LOCK_BUFFER(touch_hcd->out); + + retval = syna_tcm_alloc_mem(&touch_hcd->out, length); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for touch_hcd->out.buf\n"); + UNLOCK_BUFFER(touch_hcd->out); + return retval; + } + + touch_hcd->out.buf[idx++] = TOUCH_GESTURE_DOUBLE_TAP; + touch_hcd->out.buf[idx++] = 8; + touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_INFO; + touch_hcd->out.buf[idx++] = 48; + touch_hcd->out.buf[idx++] = TOUCH_FOREACH_ACTIVE_OBJECT; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_INDEX; + touch_hcd->out.buf[idx++] = 4; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_CLASSIFICATION; + touch_hcd->out.buf[idx++] = 4; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_X_POSITION; + touch_hcd->out.buf[idx++] = 12; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_Y_POSITION; + touch_hcd->out.buf[idx++] = 12; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_X_WIDTH; + touch_hcd->out.buf[idx++] = 12; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_Y_WIDTH; + touch_hcd->out.buf[idx++] = 12; + touch_hcd->out.buf[idx++] = TOUCH_FOREACH_END; + touch_hcd->out.buf[idx++] = TOUCH_END; + + LOCK_BUFFER(touch_hcd->resp); + + retval = syna_tcm_write_message(tcm_info, + CMD_SET_TOUCH_REPORT_CONFIG, + touch_hcd->out.buf, + length, + &touch_hcd->resp.buf, + &touch_hcd->resp.buf_size, + &touch_hcd->resp.data_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_SET_TOUCH_REPORT_CONFIG)); + UNLOCK_BUFFER(touch_hcd->resp); + UNLOCK_BUFFER(touch_hcd->out); + return retval; + } + + UNLOCK_BUFFER(touch_hcd->resp); + UNLOCK_BUFFER(touch_hcd->out); + + return retval; +} + +static int syna_set_gesture_report_config(struct syna_tcm_data *tcm_info) +{ + int retval; + unsigned int idx = 0; + unsigned int length; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + + TPD_DEBUG("%s: set gesture report\n", __func__); + length = le2_to_uint(tcm_info->app_info.max_touch_report_config_size); + + if (length < TOUCH_REPORT_CONFIG_SIZE) { + TPD_INFO("Invalid maximum touch report config size\n"); + return -EINVAL; + } + + LOCK_BUFFER(touch_hcd->out); + + retval = syna_tcm_alloc_mem(&touch_hcd->out, length); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for touch_hcd->out.buf\n"); + UNLOCK_BUFFER(touch_hcd->out); + return retval; + } + + touch_hcd->out.buf[idx++] = TOUCH_GESTURE_DOUBLE_TAP; + touch_hcd->out.buf[idx++] = 8; + // touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_CIRCLE; + // touch_hcd->out.buf[idx++] = 1; + // touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_SWIPE; + // touch_hcd->out.buf[idx++] = 1; + // touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_UNICODE; + // touch_hcd->out.buf[idx++] = 1; + // touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_VEE; + // touch_hcd->out.buf[idx++] = 1; + // touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_TRIANGLE; + // touch_hcd->out.buf[idx++] = 1; + // touch_hcd->out.buf[idx++] = TOUCH_PAD_TO_NEXT_BYTE; + touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_INFO; + touch_hcd->out.buf[idx++] = 48; + touch_hcd->out.buf[idx++] = TOUCH_REPORT_GESTURE_COORDINATE; + touch_hcd->out.buf[idx++] = 192; + touch_hcd->out.buf[idx++] = TOUCH_FOREACH_ACTIVE_OBJECT; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_INDEX; + touch_hcd->out.buf[idx++] = 4; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_CLASSIFICATION; + touch_hcd->out.buf[idx++] = 4; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_X_POSITION; + touch_hcd->out.buf[idx++] = 12; + touch_hcd->out.buf[idx++] = TOUCH_OBJECT_N_Y_POSITION; + touch_hcd->out.buf[idx++] = 12; + touch_hcd->out.buf[idx++] = TOUCH_FOREACH_END; + touch_hcd->out.buf[idx++] = TOUCH_END; + + LOCK_BUFFER(touch_hcd->resp); + + retval = syna_tcm_write_message(tcm_info, + CMD_SET_TOUCH_REPORT_CONFIG, + touch_hcd->out.buf, + length, + &touch_hcd->resp.buf, + &touch_hcd->resp.buf_size, + &touch_hcd->resp.data_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_SET_TOUCH_REPORT_CONFIG)); + UNLOCK_BUFFER(touch_hcd->resp); + UNLOCK_BUFFER(touch_hcd->out); + return retval; + } + + UNLOCK_BUFFER(touch_hcd->resp); + UNLOCK_BUFFER(touch_hcd->out); + + return 0; +} + +int syna_set_input_reporting(struct syna_tcm_data *tcm_info, bool suspend) +{ + int retval = 0; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + + TPD_DEBUG("%s: mode 0x%x, state %d\n", __func__, tcm_info->id_info.mode, suspend); + if (tcm_info->id_info.mode != MODE_APPLICATION || tcm_info->app_status != APP_STATUS_OK) { + TPD_INFO("Application firmware not running\n"); + return 0; + } + + touch_hcd->report_touch = false; + + mutex_lock(&touch_hcd->report_mutex); + + if (!suspend) { + retval = syna_set_normal_report_config(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to set report config\n"); + goto default_config; + } + } else { + retval = syna_set_gesture_report_config(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to set report config\n"); + goto default_config; + } + } + + retval = syna_get_input_params(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to get input parameters\n"); + } + + goto exit; + +default_config: + /*if failed to set report config, use default report config */ + retval = syna_set_default_report_config(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to set default report config"); + } + +exit: + mutex_unlock(&touch_hcd->report_mutex); + + touch_hcd->report_touch = retval < 0 ? false : true; + + return retval; +} + +static void syna_set_trigger_reason(struct syna_tcm_data *tcm_info, irq_reason trigger_reason) +{ + SET_BIT(tcm_info->trigger_reason, trigger_reason); + if (tcm_info->cb.invoke_common) + tcm_info->cb.invoke_common(); + + tcm_info->trigger_reason = 0; +} + +static void syna_tcm_resize_chunk_size(struct syna_tcm_data *tcm_info) +{ + unsigned int max_write_size; + + max_write_size = le2_to_uint(tcm_info->id_info.max_write_size); + tcm_info->wr_chunk_size = MIN(max_write_size, WR_CHUNK_SIZE); + if (tcm_info->wr_chunk_size == 0) + tcm_info->wr_chunk_size = max_write_size; + +} + +/** + * syna_tcm_dispatch_report() - dispatch report received from device + * + * @tcm_info: handle of core module + * + * The report generated by the device is forwarded to the synchronous inbox of + * each registered application module for further processing. In addition, the + * report notifier thread is woken up for asynchronous notification of the + * report occurrence. + */ +static void syna_tcm_dispatch_report(struct syna_tcm_data *tcm_info) +{ + int ret = 0; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + struct touch_data *touch_data = &touch_hcd->touch_data; + + LOCK_BUFFER(tcm_info->in); + LOCK_BUFFER(tcm_info->report.buffer); + + tcm_info->report.buffer.buf = &tcm_info->in.buf[MESSAGE_HEADER_SIZE]; + tcm_info->report.buffer.buf_size = tcm_info->in.buf_size - MESSAGE_HEADER_SIZE; + tcm_info->report.buffer.data_length = tcm_info->payload_length; + tcm_info->report.id = tcm_info->report_code; + + if (tcm_info->report.id == REPORT_TOUCH) { + ret = syna_parse_report(tcm_info); + if (ret < 0) { + TPD_INFO("Failed to parse report\n"); + goto exit; + } + + if (*tcm_info->in_suspend) { + if ((touch_data->lpwg_gesture == TOUCH_HOLD_UP) || (touch_data->lpwg_gesture == TOUCH_HOLD_DOWN)) { + syna_set_trigger_reason(tcm_info, IRQ_FINGERPRINT); + goto exit; + } + syna_set_trigger_reason(tcm_info, IRQ_GESTURE); + } else { + syna_set_trigger_reason(tcm_info, IRQ_TOUCH); + if ((touch_data->lpwg_gesture == TOUCH_HOLD_UP) || (touch_data->lpwg_gesture == TOUCH_HOLD_DOWN)) { + syna_set_trigger_reason(tcm_info, IRQ_FINGERPRINT); + } + } + } else if (tcm_info->report.id == REPORT_IDENTIFY) { + if (tcm_info->cb.async_work && tcm_info->id_info.mode == MODE_APPLICATION) + tcm_info->cb.async_work(); + } else if (tcm_info->report.id == REPORT_TOUCH_HOLD) { + syna_set_trigger_reason(tcm_info, IRQ_FINGERPRINT); + } else if (tcm_info->report.id == REPORT_LOG) { + syna_set_trigger_reason(tcm_info, IRQ_DATA_LOGGER); + } else { + syna_tcm_test_report(tcm_info); + } + +exit: + UNLOCK_BUFFER(tcm_info->report.buffer); + UNLOCK_BUFFER(tcm_info->in); + return; +} + + +/** + * syna_tcm_dispatch_response() - dispatch response received from device + * + * @tcm_info: handle of core module + * + * The response to a command is forwarded to the sender of the command. + */ +static void syna_tcm_dispatch_response(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + + if (atomic_read(&tcm_info->command_status) != CMD_BUSY) + return; + + LOCK_BUFFER(tcm_info->resp); + + if (tcm_info->payload_length == 0) { + UNLOCK_BUFFER(tcm_info->resp); + atomic_set(&tcm_info->command_status, CMD_IDLE); + goto exit; + } + + retval = syna_tcm_alloc_mem(&tcm_info->resp, tcm_info->payload_length); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for tcm_info->resp.buf\n"); + UNLOCK_BUFFER(tcm_info->resp); + atomic_set(&tcm_info->command_status, CMD_ERROR); + goto exit; + } + + LOCK_BUFFER(tcm_info->in); + + retval = secure_memcpy(tcm_info->resp.buf, tcm_info->resp.buf_size, + &tcm_info->in.buf[MESSAGE_HEADER_SIZE], tcm_info->in.buf_size - MESSAGE_HEADER_SIZE, tcm_info->payload_length); + if (retval < 0) { + TPD_INFO("Failed to copy payload\n"); + UNLOCK_BUFFER(tcm_info->in); + UNLOCK_BUFFER(tcm_info->resp); + atomic_set(&tcm_info->command_status, CMD_ERROR); + goto exit; + } + + tcm_info->resp.data_length = tcm_info->payload_length; + + UNLOCK_BUFFER(tcm_info->in); + UNLOCK_BUFFER(tcm_info->resp); + + atomic_set(&tcm_info->command_status, CMD_IDLE); + +exit: + complete(&response_complete); + + return; +} + +/** + * syna_tcm_dispatch_message() - dispatch message received from device + * + * @tcm_info: handle of core module + * + * The information received in the message read in from the device is dispatched + * to the appropriate destination based on whether the information represents a + * report or a response to a command. + */ +static void syna_tcm_dispatch_message(struct syna_tcm_data *tcm_info) +{ + int retval; + unsigned int payload_length; + + if (tcm_info->report_code == REPORT_IDENTIFY) { + payload_length = tcm_info->payload_length; + + LOCK_BUFFER(tcm_info->in); + + retval = secure_memcpy((unsigned char *)&tcm_info->id_info, sizeof(tcm_info->id_info), + &tcm_info->in.buf[MESSAGE_HEADER_SIZE], tcm_info->in.buf_size - MESSAGE_HEADER_SIZE, + MIN(sizeof(tcm_info->id_info), payload_length)); + if (retval < 0) { + TPD_INFO("Failed to copy identification info\n"); + UNLOCK_BUFFER(tcm_info->in); + return; + } + + UNLOCK_BUFFER(tcm_info->in); + + syna_tcm_resize_chunk_size(tcm_info); + TPD_INFO("Received identify report (firmware mode = 0x%02x)\n", tcm_info->id_info.mode); + + if (atomic_read(&tcm_info->command_status) == CMD_BUSY) { + switch (tcm_info->command) { + case CMD_RESET: + case CMD_RUN_BOOTLOADER_FIRMWARE: + case CMD_RUN_APPLICATION_FIRMWARE: + atomic_set(&tcm_info->command_status, CMD_IDLE); + complete(&response_complete); + break; + default: + TPD_INFO("Device has been reset\n"); + atomic_set(&tcm_info->command_status, CMD_ERROR); + complete(&response_complete); + break; + } + } + + if (tcm_info->id_info.mode == MODE_HOST_DOWNLOAD) + return; + + syna_tcm_helper(tcm_info); + } + + if (tcm_info->report_code >= REPORT_IDENTIFY) + syna_tcm_dispatch_report(tcm_info); + else + syna_tcm_dispatch_response(tcm_info); + + return; +} + +/** + * syna_tcm_continued_read() - retrieve entire payload from device + * + * @tcm_info: handle of core module + * + * Read transactions are carried out until the entire payload is retrieved from + * the device and stored in the handle of the core module. + */ +static int syna_tcm_continued_read(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + unsigned char marker = 0, code = 0; + unsigned int idx = 0, offset = 0, chunks = 0; + unsigned int chunk_space = 0, xfer_length = 0, total_length = 0, remaining_length = 0; + + total_length = MESSAGE_HEADER_SIZE + tcm_info->payload_length + 1; + remaining_length = total_length - tcm_info->read_length; + + LOCK_BUFFER(tcm_info->in); + + retval = syna_tcm_realloc_mem(&tcm_info->in, total_length); + if (retval < 0) { + TPD_INFO("Failed to reallocate memory for tcm_info->in.buf\n"); + UNLOCK_BUFFER(tcm_info->in); + return retval; + } + + /* available chunk space for payload = total chunk size minus header + * marker byte and header code byte */ + if (tcm_info->rd_chunk_size == 0) + chunk_space = remaining_length; + else + chunk_space = tcm_info->rd_chunk_size - 2; + + chunks = ceil_div(remaining_length, chunk_space); + + chunks = chunks == 0 ? 1 : chunks; + + offset = tcm_info->read_length; + + LOCK_BUFFER(tcm_info->temp); + + for (idx = 0; idx < chunks; idx++) { + if (remaining_length > chunk_space) + xfer_length = chunk_space; + else + xfer_length = remaining_length; + + if (xfer_length == 1) { + tcm_info->in.buf[offset] = MESSAGE_PADDING; + offset += xfer_length; + remaining_length -= xfer_length; + continue; + } + + retval = syna_tcm_alloc_mem(&tcm_info->temp, xfer_length + 2); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for tcm_info->temp.buf\n"); + UNLOCK_BUFFER(tcm_info->temp); + UNLOCK_BUFFER(tcm_info->in); + return retval; + } + + retval = touch_i2c_continue_read(tcm_info->client, xfer_length + 2, tcm_info->temp.buf); + if (retval < 0) { + TPD_INFO("Failed to read from device\n"); + UNLOCK_BUFFER(tcm_info->temp); + UNLOCK_BUFFER(tcm_info->in); + return retval; + } + + marker = tcm_info->temp.buf[0]; + code = tcm_info->temp.buf[1]; + + if (marker != MESSAGE_MARKER) { + TPD_INFO("Incorrect header marker (0x%02x)\n", marker); + UNLOCK_BUFFER(tcm_info->temp); + UNLOCK_BUFFER(tcm_info->in); + return -EIO; + } + + if (code != STATUS_CONTINUED_READ) { + TPD_INFO("Incorrect header code (0x%02x)\n", code); + UNLOCK_BUFFER(tcm_info->temp); + UNLOCK_BUFFER(tcm_info->in); + return -EIO; + } + + retval = secure_memcpy(&tcm_info->in.buf[offset], total_length - offset, &tcm_info->temp.buf[2], xfer_length, xfer_length); + if (retval < 0) { + TPD_INFO("Failed to copy payload\n"); + UNLOCK_BUFFER(tcm_info->temp); + UNLOCK_BUFFER(tcm_info->in); + return retval; + } + + offset += xfer_length; + + remaining_length -= xfer_length; + } + + UNLOCK_BUFFER(tcm_info->temp); + UNLOCK_BUFFER(tcm_info->in); + + return 0; +} + +/** + * syna_tcm_raw_read() - retrieve specific number of data bytes from device + * + * @tcm_info: handle of core module + * @in_buf: buffer for storing data retrieved from device + * @length: number of bytes to retrieve from device + * + * Read transactions are carried out until the specific number of data bytes are + * retrieved from the device and stored in in_buf. + */ +static int syna_tcm_raw_read(struct syna_tcm_data *tcm_info, unsigned char *in_buf, unsigned int length) +{ + int retval = 0; + unsigned char code = 0; + unsigned int idx = 0, offset = 0; + unsigned int chunks = 0, chunk_space = 0; + unsigned int xfer_length = 0, remaining_length = 0; + + if (length < 2) { + TPD_INFO("Invalid length information\n"); + return -EINVAL; + } + + /* minus header marker byte and header code byte */ + remaining_length = length - 2; + + /* available chunk space for data = total chunk size minus header marker + * byte and header code byte */ + if (tcm_info->rd_chunk_size == 0) + chunk_space = remaining_length; + else + chunk_space = tcm_info->rd_chunk_size - 2; + + chunks = ceil_div(remaining_length, chunk_space); + + chunks = chunks == 0 ? 1 : chunks; + + offset = 0; + + LOCK_BUFFER(tcm_info->temp); + + for (idx = 0; idx < chunks; idx++) { + if (remaining_length > chunk_space) + xfer_length = chunk_space; + else + xfer_length = remaining_length; + + if (xfer_length == 1) { + in_buf[offset] = MESSAGE_PADDING; + offset += xfer_length; + remaining_length -= xfer_length; + continue; + } + + retval = syna_tcm_alloc_mem(&tcm_info->temp, xfer_length + 2); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for tcm_info->temp.buf\n"); + UNLOCK_BUFFER(tcm_info->temp); + return retval; + } + + retval = syna_tcm_read(tcm_info, tcm_info->temp.buf, xfer_length + 2); + if (retval < 0) { + TPD_INFO("Failed to read from device\n"); + UNLOCK_BUFFER(tcm_info->temp); + return retval; + } + + code = tcm_info->temp.buf[1]; + + if (idx == 0) { + retval = secure_memcpy(&in_buf[0], length, &tcm_info->temp.buf[0], xfer_length + 2, xfer_length + 2); + } else { + if (code != STATUS_CONTINUED_READ) { + TPD_INFO("Incorrect header code (0x%02x)\n", code); + UNLOCK_BUFFER(tcm_info->temp); + return -EIO; + } + + retval = secure_memcpy(&in_buf[offset], + length - offset, &tcm_info->temp.buf[2], + xfer_length, xfer_length); + } + if (retval < 0) { + TPD_INFO("Failed to copy data\n"); + UNLOCK_BUFFER(tcm_info->temp); + return retval; + } + + if (idx == 0) + offset += (xfer_length + 2); + else + offset += xfer_length; + + remaining_length -= xfer_length; + } + + UNLOCK_BUFFER(tcm_info->temp); + + return 0; +} + +/** + * syna_tcm_raw_write() - write command/data to device without receiving + * response + * + * @tcm_info: handle of core module + * @command: command to send to device + * @data: data to send to device + * @length: length of data in bytes + * + * A command and its data, if any, are sent to the device. + */ +static int syna_tcm_raw_write(struct syna_tcm_data *tcm_info, unsigned char command, + unsigned char *data, unsigned int length) +{ + int retval = 0; + unsigned int idx = 0, chunks = 0, chunk_space = 0; + unsigned int xfer_length = 0, remaining_length = length; + + /* available chunk space for data = total chunk size minus command byte */ + if (tcm_info->wr_chunk_size == 0) + chunk_space = remaining_length; + else + chunk_space = tcm_info->wr_chunk_size - 1; + + chunks = ceil_div(remaining_length, chunk_space); + + chunks = chunks == 0 ? 1 : chunks; + + LOCK_BUFFER(tcm_info->out); + + for (idx = 0; idx < chunks; idx++) { + if (remaining_length > chunk_space) + xfer_length = chunk_space; + else + xfer_length = remaining_length; + + retval = syna_tcm_alloc_mem(&tcm_info->out, xfer_length + 1); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for tcm_info->out.buf\n"); + UNLOCK_BUFFER(tcm_info->out); + return retval; + } + + if (idx == 0) + tcm_info->out.buf[0] = command; + else + tcm_info->out.buf[0] = CMD_CONTINUE_WRITE; + + if (xfer_length) { + retval = secure_memcpy(&tcm_info->out.buf[1], + xfer_length, + &data[idx * chunk_space], + remaining_length, + xfer_length); + if (retval < 0) { + TPD_INFO("Failed to copy data\n"); + UNLOCK_BUFFER(tcm_info->out); + return retval; + } + } + + retval = syna_tcm_write(tcm_info, tcm_info->out.buf, xfer_length + 1); + if (retval < 0) { + TPD_INFO("Failed to write to device\n"); + UNLOCK_BUFFER(tcm_info->out); + return retval; + } + + remaining_length -= xfer_length; + } + + UNLOCK_BUFFER(tcm_info->out); + + return 0; +} + +/*add this for debug. remove before pvt*/ +/* + static void syna_tcm_debug_message(char *buf, int len) + { + int i = 0; + char buffer[161] = {0}; + + for (i = 0; i < len; i++) { + if (i > 32) + break; + + sprintf(&buffer[5 * i], "0x%02x ", buf[i]); + } + + if (len > 0) + TPD_INFO("payload data: %s\n", buffer); + } + */ + +/** + * syna_tcm_read_message() - read message from device + * + * @tcm_info: handle of core module + * @in_buf: buffer for storing data in raw read mode + * @length: length of data in bytes in raw read mode + * + * If in_buf is not NULL, raw read mode is used and syna_tcm_raw_read() is + * called. Otherwise, a message including its entire payload is retrieved from + * the device and dispatched to the appropriate destination. + */ +static int syna_tcm_read_message(struct syna_tcm_data *tcm_info, unsigned char *in_buf, unsigned int length) +{ + int retval = 0; + unsigned int total_length = 0; + struct syna_tcm_message_header *header = NULL; + + TPD_DEBUG("%s\n", __func__); + mutex_lock(&tcm_info->rw_mutex); + + if (in_buf != NULL) { + retval = syna_tcm_raw_read(tcm_info, in_buf, length); + goto exit; + } + + LOCK_BUFFER(tcm_info->in); + + retval = touch_i2c_continue_read(tcm_info->client, tcm_info->read_length, tcm_info->in.buf); + if (retval < 0) { + TPD_INFO("Failed to read from device\n"); + UNLOCK_BUFFER(tcm_info->in); + goto exit; + } + + header = (struct syna_tcm_message_header *)tcm_info->in.buf; + if (header->marker != MESSAGE_MARKER) { + TPD_INFO("wrong header marker:0x%02x\n", header->marker); + UNLOCK_BUFFER(tcm_info->in); + retval = -ENXIO; + goto exit; + } + + tcm_info->report_code = header->code; + tcm_info->payload_length = le2_to_uint(header->length); + TPD_DEBUG("Header code = 0x%02x Payload len = %d\n", tcm_info->report_code, tcm_info->payload_length); + + if (tcm_info->report_code <= STATUS_ERROR || tcm_info->report_code == STATUS_INVALID) { + switch (tcm_info->report_code) { + case STATUS_OK: + break; + case STATUS_CONTINUED_READ: + //TPD_INFO("Out-of-sync continued read\n"); + case STATUS_IDLE: + case STATUS_BUSY: + tcm_info->payload_length = 0; + UNLOCK_BUFFER(tcm_info->in); + retval = 0; + goto exit; + default: + TPD_INFO("Incorrect header code (0x%02x)\n", tcm_info->report_code); + if (tcm_info->report_code != STATUS_ERROR) { + UNLOCK_BUFFER(tcm_info->in); + retval = -EIO; + goto exit; + } + } + } + + total_length = MESSAGE_HEADER_SIZE + tcm_info->payload_length + 1; + +#ifdef PREDICTIVE_READING + if (total_length <= tcm_info->read_length) { + goto check_padding; + } else if (total_length - 1 == tcm_info->read_length) { + tcm_info->in.buf[total_length - 1] = MESSAGE_PADDING; + goto check_padding; + } +#else + if (tcm_info->payload_length == 0) { + tcm_info->in.buf[total_length - 1] = MESSAGE_PADDING; + goto check_padding; + } +#endif + + UNLOCK_BUFFER(tcm_info->in); + + retval = syna_tcm_continued_read(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to do continued read\n"); + goto exit; + }; + + LOCK_BUFFER(tcm_info->in); + + tcm_info->in.buf[0] = MESSAGE_MARKER; + tcm_info->in.buf[1] = tcm_info->report_code; + tcm_info->in.buf[2] = (unsigned char)tcm_info->payload_length; + tcm_info->in.buf[3] = (unsigned char)(tcm_info->payload_length >> 8); + +check_padding: + if (tcm_info->in.buf[total_length - 1] != MESSAGE_PADDING) { + TPD_INFO("Incorrect message padding byte (0x%02x)\n", tcm_info->in.buf[total_length - 1]); + UNLOCK_BUFFER(tcm_info->in); + retval = -EIO; + goto exit; + } + + UNLOCK_BUFFER(tcm_info->in); + +#ifdef PREDICTIVE_READING + total_length = MAX(total_length, MIN_READ_LENGTH); + tcm_info->read_length = MIN(total_length, tcm_info->rd_chunk_size); + if (tcm_info->rd_chunk_size == 0) + tcm_info->read_length = total_length; +#endif + + /*add for debug, remove before pvt*/ + //if (LEVEL_BASIC != tp_debug) { + // syna_tcm_debug_message(&tcm_info->in.buf[4], tcm_info->payload_length); + //} + + syna_tcm_dispatch_message(tcm_info); + + retval = 0; + +exit: + if ((retval < 0) && (atomic_read(&tcm_info->command_status) == CMD_BUSY)) { + atomic_set(&tcm_info->command_status, CMD_ERROR); + complete(&response_complete); + } + + mutex_unlock(&tcm_info->rw_mutex); + + return retval; +} + +/** + * syna_tcm_write_message() - write message to device and receive response + * + * @tcm_info: handle of core module + * @command: command to send to device + * @payload: payload of command + * @length: length of payload in bytes + * @resp_buf: buffer for storing command response + * @resp_buf_size: size of response buffer in bytes + * @resp_length: length of command response in bytes + * @polling_delay_ms: delay time after sending command before resuming polling + * + * If resp_buf is NULL, raw write mode is used and syna_tcm_raw_write() is + * called. Otherwise, a command and its payload, if any, are sent to the device + * and the response to the command generated by the device is read in. + */ +static int syna_tcm_write_message(struct syna_tcm_data *tcm_info, + unsigned char command, unsigned char *payload, + unsigned int length, unsigned char **resp_buf, + unsigned int *resp_buf_size, unsigned int *resp_length, + unsigned int timeout) +{ + int retval = 0; + unsigned int idx = 0, chunks = 0, chunk_space = 0; + unsigned int xfer_length = 0, remaining_length = 0; + unsigned int command_status = 0; + unsigned int timeout_ms = 0; + + mutex_lock(&tcm_info->command_mutex); + mutex_lock(&tcm_info->rw_mutex); + + if (resp_buf == NULL) { + retval = syna_tcm_raw_write(tcm_info, command, payload, length); + mutex_unlock(&tcm_info->rw_mutex); + goto exit; + } + + atomic_set(&tcm_info->command_status, CMD_BUSY); + reinit_completion(&response_complete); + tcm_info->command = command; + + LOCK_BUFFER(tcm_info->resp); + + tcm_info->resp.buf = *resp_buf; + tcm_info->resp.buf_size = *resp_buf_size; + tcm_info->resp.data_length = 0; + + UNLOCK_BUFFER(tcm_info->resp); + + /* adding two length bytes as part of payload */ + remaining_length = length + 2; + + /* available chunk space for payload = total chunk size minus command + * byte */ + if (tcm_info->wr_chunk_size == 0) + chunk_space = remaining_length; + else + chunk_space = tcm_info->wr_chunk_size - 1; + + chunks = ceil_div(remaining_length, chunk_space); + + chunks = chunks == 0 ? 1 : chunks; + + TPD_INFO("%s:Command = 0x%02x chunk = %d\n", __func__, command, chunks); + + LOCK_BUFFER(tcm_info->out); + + for (idx = 0; idx < chunks; idx++) { + if (remaining_length > chunk_space) + xfer_length = chunk_space; + else + xfer_length = remaining_length; + + retval = syna_tcm_alloc_mem(&tcm_info->out, xfer_length + 1); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for tcm_info->out.buf\n"); + UNLOCK_BUFFER(tcm_info->out); + mutex_unlock(&tcm_info->rw_mutex); + goto exit; + } + + if (idx == 0) { + tcm_info->out.buf[0] = command; + tcm_info->out.buf[1] = (unsigned char)length; + tcm_info->out.buf[2] = (unsigned char)(length >> 8); + + if (xfer_length > 2) { + retval = secure_memcpy(&tcm_info->out.buf[3], + xfer_length - 2, + payload, + remaining_length - 2, + xfer_length - 2); + if (retval < 0) { + TPD_INFO("Failed to copy payload\n"); + UNLOCK_BUFFER(tcm_info->out); + mutex_unlock(&tcm_info->rw_mutex); + goto exit; + } + } + } else { + tcm_info->out.buf[0] = CMD_CONTINUE_WRITE; + + retval = secure_memcpy(&tcm_info->out.buf[1], + xfer_length, + &payload[idx * chunk_space - 2], + remaining_length, + xfer_length); + if (retval < 0) { + TPD_INFO("Failed to copy payload\n"); + UNLOCK_BUFFER(tcm_info->out); + mutex_unlock(&tcm_info->rw_mutex); + goto exit; + } + } + + retval = syna_tcm_write(tcm_info, tcm_info->out.buf, xfer_length + 1); + if (retval < 0) { + TPD_INFO("Failed to write to device\n"); + UNLOCK_BUFFER(tcm_info->out); + mutex_unlock(&tcm_info->rw_mutex); + goto exit; + } + + remaining_length -= xfer_length; + } + UNLOCK_BUFFER(tcm_info->out); + + mutex_unlock(&tcm_info->rw_mutex); + + if (timeout == 0) { + timeout_ms = RESPONSE_TIMEOUT_MS_DEFAULT; + } else { + timeout_ms = timeout; + } + + retval = wait_for_completion_timeout(&response_complete, + msecs_to_jiffies(timeout_ms)); + if (retval == 0) { + TPD_INFO("Timed out waiting for response (command 0x%02x)\n", + tcm_info->command); + retval = -EIO; + } else { + command_status = atomic_read(&tcm_info->command_status); + + if (command_status != CMD_IDLE || + tcm_info->report_code == STATUS_ERROR) { + TPD_INFO("command_status = %d, report_code = %d.\n", command_status, tcm_info->report_code); + TPD_INFO("Failed to get valid response\n"); + retval = -EIO; + goto exit; + } + + retval = 0; + } + +exit: + if (command_status == CMD_IDLE) { + LOCK_BUFFER(tcm_info->resp); + + if (tcm_info->report_code == STATUS_ERROR) { + if (tcm_info->resp.data_length) { + TPD_INFO("Error code = 0x%02x\n", + tcm_info->resp.buf[0]); + } + } + + if (resp_buf != NULL) { + *resp_buf = tcm_info->resp.buf; + *resp_buf_size = tcm_info->resp.buf_size; + *resp_length = tcm_info->resp.data_length; + } + + UNLOCK_BUFFER(tcm_info->resp); + } + + tcm_info->command = CMD_NONE; + atomic_set(&tcm_info->command_status, CMD_IDLE); + mutex_unlock(&tcm_info->command_mutex); + + return retval; +} + +static int syna_tcm_get_app_info(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + unsigned int timeout = APP_STATUS_POLL_TIMEOUT_MS; + +get_app_info: + retval = syna_tcm_write_message(tcm_info, + CMD_GET_APPLICATION_INFO, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_GET_APPLICATION_INFO)); + goto exit; + } + + retval = secure_memcpy((unsigned char *)&tcm_info->app_info, + sizeof(tcm_info->app_info), + resp_buf, + resp_buf_size, + MIN(sizeof(tcm_info->app_info), resp_length)); + if (retval < 0) { + TPD_INFO("Failed to copy application info\n"); + goto exit; + } + + tcm_info->app_status = le2_to_uint(tcm_info->app_info.status); + + if (tcm_info->app_status == APP_STATUS_BOOTING || tcm_info->app_status == APP_STATUS_UPDATING) { + if (timeout > 0) { + msleep(APP_STATUS_POLL_MS); + timeout -= APP_STATUS_POLL_MS; + goto get_app_info; + } + } + + retval = 0; + +exit: + kfree(resp_buf); + + return retval; +} + +static int syna_tcm_get_boot_info(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + + retval = syna_tcm_write_message(tcm_info, + CMD_GET_BOOT_INFO, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_GET_BOOT_INFO)); + goto exit; + } + + retval = secure_memcpy((unsigned char *)&tcm_info->boot_info, + sizeof(tcm_info->boot_info), + resp_buf, + resp_buf_size, + MIN(sizeof(tcm_info->boot_info), resp_length)); + if (retval < 0) { + TPD_INFO("Failed to copy boot info\n"); + goto exit; + } + + retval = 0; + +exit: + kfree(resp_buf); + + return retval; +} + +static int syna_tcm_identify(struct syna_tcm_data *tcm_info, bool id) +{ + int retval; + unsigned char *resp_buf; + unsigned int resp_buf_size = 0; + unsigned int resp_length = 0; + + resp_buf = NULL; + resp_buf_size = 0; + + mutex_lock(&tcm_info->identify_mutex); + + if (!id) + goto get_info; + + retval = syna_tcm_write_message(tcm_info, + CMD_IDENTIFY, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_IDENTIFY)); + goto exit; + } + + retval = secure_memcpy((unsigned char *)&tcm_info->id_info, + sizeof(tcm_info->id_info), + resp_buf, + resp_buf_size, + MIN(sizeof(tcm_info->id_info), resp_length)); + if (retval < 0) { + TPD_INFO("Failed to copy identification info\n"); + goto exit; + } + + syna_tcm_resize_chunk_size(tcm_info); + +get_info: + if (tcm_info->id_info.mode == MODE_APPLICATION) { + retval = syna_tcm_get_app_info(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to get application info\n"); + goto exit; + } + } else { + retval = syna_tcm_get_boot_info(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to get boot info\n"); + goto exit; + } + } + + retval = 0; + +exit: + mutex_unlock(&tcm_info->identify_mutex); + + kfree(resp_buf); + + return retval; +} + +static int syna_tcm_run_application_firmware(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + bool retry = true; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + +retry: + retval = syna_tcm_write_message(tcm_info, + CMD_RUN_APPLICATION_FIRMWARE, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_RUN_APPLICATION_FIRMWARE)); + goto exit; + } + + retval = syna_tcm_identify(tcm_info, false); + if (retval < 0) { + TPD_INFO("Failed to do identification\n"); + goto exit; + } + + if (tcm_info->id_info.mode != MODE_APPLICATION) { + TPD_INFO("Failed to run application firmware (boot status = 0x%02x)\n", tcm_info->boot_info.status); + if (retry) { + retry = false; + goto retry; + } + retval = -EINVAL; + goto exit; + } else if (tcm_info->app_status != APP_STATUS_OK) { + TPD_INFO("Application status = 0x%02x\n", tcm_info->app_status); + } + + retval = 0; + +exit: + kfree(resp_buf); + + return retval; +} + + +static int syna_tcm_run_bootloader_firmware(struct syna_tcm_data *tcm_info) +{ + int retval = 0; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + + retval = syna_tcm_write_message(tcm_info, + CMD_RUN_BOOTLOADER_FIRMWARE, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_RUN_BOOTLOADER_FIRMWARE)); + goto exit; + } + + retval = syna_tcm_identify(tcm_info, false); + if (retval < 0) { + TPD_INFO("Failed to do identification\n"); + goto exit; + } + + if (tcm_info->id_info.mode == MODE_APPLICATION) { + TPD_INFO("Failed to enter bootloader mode\n"); + retval = -EINVAL; + goto exit; + } + + retval = 0; + +exit: + kfree(resp_buf); + + return retval; +} + + +static int syna_tcm_switch_mode(struct syna_tcm_data *tcm_info, enum firmware_mode mode) +{ + int retval = 0; + + mutex_lock(&tcm_info->reset_mutex); + + switch (mode) { + case FW_MODE_BOOTLOADER: + retval = syna_tcm_run_bootloader_firmware(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to switch to bootloader mode\n"); + goto exit; + } + break; + case FW_MODE_APPLICATION: + retval = syna_tcm_run_application_firmware(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to switch to application mode\n"); + goto exit; + } + break; + default: + TPD_INFO("Invalid firmware mode\n"); + retval = -EINVAL; + goto exit; + } + +exit: + mutex_unlock(&tcm_info->reset_mutex); + + return retval; +} + +static int syna_tcm_get_dynamic_config(struct syna_tcm_data *tcm_info, + enum dynamic_config_id id, unsigned short *value) +{ + int retval = 0; + unsigned char out_buf = (unsigned char)id; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + + retval = syna_tcm_write_message(tcm_info, + CMD_GET_DYNAMIC_CONFIG, + &out_buf, + sizeof(out_buf), + &resp_buf, + &resp_buf_size, + &resp_length, + RESPONSE_TIMEOUT_MS_SHORT); + if (retval < 0 || resp_length < 2) { + retval = -EINVAL; + TPD_INFO("Failed to read dynamic config\n"); + goto exit; + } + + *value = (unsigned short)le2_to_uint(resp_buf); +exit: + kfree(resp_buf); + return retval; +} + +static int syna_tcm_set_dynamic_config(struct syna_tcm_data *tcm_info, + enum dynamic_config_id id, unsigned short value) +{ + int retval = 0; + unsigned char out_buf[3] = {0}; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + + TPD_DEBUG("%s:config 0x%x, value %d\n", __func__, id, value); + + out_buf[0] = (unsigned char)id; + out_buf[1] = (unsigned char)value; + out_buf[2] = (unsigned char)(value >> 8); + + retval = syna_tcm_write_message(tcm_info, + CMD_SET_DYNAMIC_CONFIG, + out_buf, + sizeof(out_buf), + &resp_buf, + &resp_buf_size, + &resp_length, + RESPONSE_TIMEOUT_MS_SHORT); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_SET_DYNAMIC_CONFIG)); + goto exit; + } + +exit: + kfree(resp_buf); + + return retval; +} + +static int syna_tcm_sleep(struct syna_tcm_data *tcm_info, bool en) +{ + int retval = 0; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0; + unsigned char command = en ? CMD_ENTER_DEEP_SLEEP : CMD_EXIT_DEEP_SLEEP; + + TPD_INFO("%s: %s .\n", __func__, en ? "enter" : "exit"); + + if (NOT_NEED_SLEEP) { + return retval; + } + + retval = syna_tcm_write_message(tcm_info, + command, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", en ? STR(CMD_ENTER_DEEP_SLEEP) : STR(CMD_EXIT_DEEP_SLEEP)); + goto exit; + } + +exit: + kfree(resp_buf); + + return retval; +} + +static int syna_tcm_refresh_switch(int fps) +{ + int retval = 0; + + if (!g_tcm_info) { + return retval; + } + + if (fps == 1) + g_tcm_info->display_refresh_rate = 90; + else if ((fps == 2) || (fps == 0)) + g_tcm_info->display_refresh_rate = 60; + + //g_tcm_info->display_refresh_rate = fps ? 90 : 60; + + if (!*g_tcm_info->in_suspend) { + //retval = syna_tcm_set_dynamic_config(g_tcm_info, DC_SET_REPORT_FRE, g_tcm_info->display_refresh_rate == 60 ? 0x01 : 0x02); + retval = syna_tcm_set_dynamic_config(g_tcm_info, DC_SET_REPORT_FRE, fps); //1:180Hz 2:120Hz 3:240Hz + if (retval < 0) { + TPD_INFO("Failed to set dynamic report frequence config\n"); + } + } + TPD_INFO("%s: report_rate: Mode %d (1:180Hz 2:120Hz 3:240Hz) %s!\n", __func__, fps, retval < 0 ? "failed" : "success"); + + return retval; +} +//EXPORT_SYMBOL(syna_tcm_refresh_switch); + +static int synaptics_resetgpio_set(struct hw_resource *hw_res, bool on) +{ + if (gpio_is_valid(hw_res->reset_gpio)) { + TPD_INFO("Set the reset_gpio \n"); + gpio_direction_output(hw_res->reset_gpio, on); + } + + return 0; +} + +static int syna_tcm_reset(void *chip_data) +{ + int retval = 0; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0; + unsigned int resp_length = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + mutex_lock(&tcm_info->reset_mutex); + + synaptics_resetgpio_set(tcm_info->hw_res, false); + msleep(POWEWRUP_TO_RESET_TIME); + synaptics_resetgpio_set(tcm_info->hw_res, true); + msleep(RESET_TO_NORMAL_TIME); + + retval = syna_tcm_identify(tcm_info, false); + if (retval < 0) { + TPD_INFO("Failed to do identification\n"); + goto exit; + } + + if (tcm_info->id_info.mode == MODE_APPLICATION) + goto dispatch_reset; + + retval = syna_tcm_write_message(tcm_info, + CMD_RUN_APPLICATION_FIRMWARE, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_RUN_APPLICATION_FIRMWARE)); + //goto exit; + } + + retval = syna_tcm_identify(tcm_info, false); + if (retval < 0) { + TPD_INFO("Failed to do identification\n"); + goto exit; + } + +dispatch_reset: + TPD_INFO("Firmware mode = 0x%02x, boot status 0x%02x, app status 0x%02x\n", + tcm_info->id_info.mode, + tcm_info->boot_info.status, + tcm_info->app_status); + +exit: + mutex_unlock(&tcm_info->reset_mutex); + + kfree(resp_buf); + + return retval; +} + +static int syna_get_chip_info(void *chip_data) +{ + int ret = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + TPD_INFO("%s: Enter\n", __func__); + + ret = syna_tcm_reset(tcm_info); // reset to get bootloader info or boot info + if (ret < 0) { + TPD_INFO("failed to reset device\n"); + return ret; + } + + ret = syna_get_default_report_config(tcm_info); + if (ret < 0) { + TPD_INFO("failed to get default report config\n"); + return ret; + } + return 0; +} + +static int syna_get_vendor(void *chip_data, struct panel_info *panel_data) +{ + char manu_temp[MAX_DEVICE_MANU_LENGTH] = SYNAPTICS_PREFIX; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + tcm_info->iHex_name = panel_data->extra; + + strlcat(manu_temp, panel_data->manufacture_info.manufacture, MAX_DEVICE_MANU_LENGTH); + strncpy(panel_data->manufacture_info.manufacture, manu_temp, MAX_DEVICE_MANU_LENGTH); + TPD_INFO("chip_info->tp_type = %d, panel_data->fw_name = %s\n", panel_data->tp_type, panel_data->fw_name); + return 0; +} + +static u32 syna_trigger_reason(void *chip_data, int gesture_enable, int is_suspended) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + return tcm_info->trigger_reason; +} + +static int syna_get_touch_points(void *chip_data, struct point_info *points, int max_num) +{ + unsigned int idx = 0, status = 0; + struct object_data *object_data = NULL; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + static unsigned int obj_attention = 0x00; + + if (points == NULL) + return obj_attention; + object_data = touch_hcd->touch_data.object_data; + + for (idx = 0; idx < touch_hcd->max_objects; idx++) { + status = object_data[idx].status; + if (status != LIFT) { + obj_attention |= (0x1 << idx); + } else { + if ((~obj_attention) & ((0x1) << idx)) + continue; + else + obj_attention &= (~(0x1 << idx)); + } + + points[idx].x = object_data[idx].x_pos; + points[idx].y = object_data[idx].y_pos; + TPD_DEBUG("x is %d, y is %d\n", points[idx].x, points[idx].y); + points[idx].touch_major = max(object_data[idx].x_width, object_data[idx].y_width); + points[idx].width_major = min(object_data[idx].x_width, object_data[idx].y_width); + points[idx].status = 1; + } + + return obj_attention; +} + +static int syna_tcm_set_gesture_mode(struct syna_tcm_data *tcm_info, bool enable) +{ + int retval = 0; + + /*this command may take too much time, if needed can add flag to skip this */ + TPD_INFO("%s: enable(%d)\n", __func__, enable); + + if (enable) { + retval = syna_tcm_sleep(tcm_info, false); + if (retval < 0) { + TPD_INFO("%s: Failed to exit sleep mode\n", __func__); + return retval; + } + + retval = syna_set_input_reporting(tcm_info, true); + if (retval < 0) { + TPD_INFO("%s: Failed to set input reporting\n", __func__); + return retval; + } + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_IN_WAKEUP_GESTURE_MODE, true); + if (retval < 0) { + TPD_INFO("%s: Failed to set dynamic gesture config\n", __func__); + return retval; + } + retval = syna_tcm_set_dynamic_config(tcm_info, DC_GESTURE_MASK, 0xFFFE); + if (retval < 0) { + TPD_INFO("%s: Failed to set dynamic gesture mask config\n", __func__); + return retval; + } + } else { + retval = syna_tcm_sleep(tcm_info, true); + if (retval < 0) { + TPD_INFO("%s: Failed to enter sleep mode\n", __func__); + return retval; + } + } + + return retval; +} + +static int syna_tcm_enable_gesture_mask(struct syna_tcm_data *tcm_info, bool enable) +{ + int retval = 0; + + /*this command may take too much time, if needed can add flag to skip this */ + TPD_INFO("%s: enable(%d)\n", __func__, enable); + + if (!enable) { //1:disable gesture 0:enable gesture + retval = syna_tcm_set_dynamic_config(tcm_info, DC_GESTURE_MASK, 0xFFFE); + if (retval < 0) { + TPD_INFO("%s: Failed to set dynamic gesture mask config\n", __func__); + } + } else { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_GESTURE_MASK, 0x0000); + if (retval < 0) { + TPD_INFO("%s: Failed to set dynamic gesture mask config\n", __func__); + } + } + + return retval; +} + +static int syna_tcm_set_game_mode(struct syna_tcm_data *tcm_info, bool enable) +{ + int retval = 0; + unsigned short noise_length = 0; + + tcm_info->game_mode = enable; + TPD_INFO("%s: enable(%d)\n", __func__, tcm_info->game_mode); + + if (enable) { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_ERROR_PRIORITY, true); + if (retval < 0) { + TPD_INFO("Failed to set dynamic error priority config\n"); + return retval; + } + + noise_length = 0x0A; + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NOISE_LENGTH, noise_length); + if (retval < 0) { + TPD_INFO("Failed to set dynamic noise length config\n"); + return retval; + } + retval = syna_tcm_set_dynamic_config(tcm_info, DC_SET_REPORT_FRE, 0x03); //240Hz + if (retval < 0) { + TPD_INFO("Failed to set dynamic report frequence config\n"); + return retval; + } + } else { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_ERROR_PRIORITY, false); + if (retval < 0) { + TPD_INFO("Failed to set dynamic error priority config\n"); + return retval; + } + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NOISE_LENGTH, tcm_info->default_noise_length); + if (retval < 0) { + TPD_INFO("Failed to set dynamic noise length config\n"); + return retval; + } + retval = syna_tcm_set_dynamic_config(tcm_info, DC_SET_REPORT_FRE, tcm_info->display_refresh_rate == 90 ? 0x01 : 0x02); + if (retval < 0) { + TPD_INFO("Failed to set dynamic report frequence config\n"); + return retval; + } + } + + return retval; +} + +#if 0 +static int syna_tcm_set_gesture_mode(struct syna_tcm_data *tcm_info, bool enable) +{ + int retval = 0; + unsigned short config = 0; + + /*this command may take too much time, if needed can add flag to skip this */ + TPD_INFO("%s: enable(%d)\n", __func__, enable); + retval = syna_tcm_get_dynamic_config(tcm_info, DC_IN_WAKEUP_GESTURE_MODE, &config); + if (retval < 0) { + TPD_INFO("Failed to get dynamic config\n"); + return retval; + } + + TPD_DEBUG("config id is %d\n", config); + + if (enable) { + if (!config) { + retval = syna_set_input_reporting(tcm_info, true); + if (retval < 0) { + TPD_INFO("Failed to set input reporting\n"); + return retval; + } + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_IN_WAKEUP_GESTURE_MODE, true); + if (retval < 0) { + TPD_INFO("Failed to set dynamic gesture config\n"); + return retval; + } + } + } + + /*set to sleep*/ + retval = syna_tcm_sleep(tcm_info, !enable); + if (retval < 0) { + TPD_INFO("Failed to set sleep mode"); + } + + return retval; +} +#endif + +static int syna_tcm_normal_mode(struct syna_tcm_data *tcm_info) +{ + int retval; + + retval = syna_set_input_reporting(tcm_info, false); + if (retval < 0) { + TPD_INFO("Failed to set input reporting\n"); + return retval; + } + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_IN_WAKEUP_GESTURE_MODE, false); + if (retval < 0) { + TPD_INFO("Failed to set dynamic gesture config\n"); + return retval; + } + + retval = syna_tcm_refresh_switch(tcm_info->display_refresh_rate == 90); + if (retval < 0) { + TPD_INFO("Failed to set dynamic refresh config\n"); + return retval; + } + return retval; +} + +static int syna_corner_limit_handle(struct syna_tcm_data *tcm_info) +{ + int ret = -1; + + TPD_INFO("limit_switch is %d\n", g_tp->limit_switch); + + if (g_tp->limit_switch == 1) { + //if(LANDSCAPE_SCREEN_90 == tcm_info->touch_direction) { + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL, 0x01); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_SEL, 0x0F); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_SEL\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_X, g_tp->dead_zone_l); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_X\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_Y, 0x0A); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_Y\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_DARK_ZONE_ENABLE, 0x03); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_DARK_ZONE_ENABLE\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_DARK_ZONE_X, g_tp->corner_dead_zone_xl); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_DARK_ZONE_X\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_DARK_ZONE_Y, g_tp->corner_dead_zone_yl); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_DARK_ZONE_Y\n", __func__); + return ret; + } + //} else if (LANDSCAPE_SCREEN_270 == tcm_info->touch_direction) { + } else if (g_tp->limit_switch == 3) { + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL, 0x01); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_SEL, 0x0F); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_SEL\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_X, g_tp->dead_zone_l); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_X\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_Y, 0x0A); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_Y\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_DARK_ZONE_ENABLE, 0x0C); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_DARK_ZONE_ENABLE\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_DARK_ZONE_X, g_tp->corner_dead_zone_xl); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_DARK_ZONE_X\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_DARK_ZONE_Y, g_tp->corner_dead_zone_yl); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_DARK_ZONE_Y\n", __func__); + return ret; + } + //} else if (VERTICAL_SCREEN == tcm_info->touch_direction) { + } else { + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL, 0x00); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_SEL, 0x07); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_SEL\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_X, g_tp->dead_zone_p); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_X\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_Y, 0x05); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_Y\n", __func__); + return ret; + } + //ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_U, 0x32); + //if (ret < 0) { + // TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_U\n", __func__); + // return ret; + //} + //ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ABS_DARK_V, 0x64); + //if (ret < 0) { + // TPD_INFO("%s:failed to set DC_GRIP_ABS_DARK_V\n", __func__); + // return ret; + //} + ret = syna_tcm_set_dynamic_config(tcm_info, DC_DARK_ZONE_ENABLE, 0x05); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_DARK_ZONE_ENABLE\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_DARK_ZONE_X, g_tp->corner_dead_zone_xp); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_DARK_ZONE_X\n", __func__); + return ret; + } + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_DARK_ZONE_Y, g_tp->corner_dead_zone_yp); + if (ret < 0) { + TPD_INFO("%s:failed to set DC_GRIP_DARK_ZONE_Y\n", __func__); + return ret; + } + } + + return ret; +} + +static int syna_enable_edge_limit(struct syna_tcm_data *tcm_info) +{ + int ret = 0; + TPD_INFO("%s: enter\n", __func__); + + ret = syna_tcm_set_dynamic_config(tcm_info, DC_GRIP_ENABLED, 0x01); + if (ret < 0) { + TPD_INFO("%s:failed to enable grip suppression\n", __func__); + return ret; + } + + ret = syna_corner_limit_handle(tcm_info); + if (ret < 0) { + TPD_INFO("%s:failed to set grip suppression para\n", __func__); + return ret; + } + + return ret; +} + +static int syna_tcm_enable_touchhold(struct syna_tcm_data *tcm_info, bool enable) +{ + int retval = 0; + TPD_INFO("%s: enable(%d)\n", __func__, enable); + + if (enable) { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_TOUCH_HOLD, 0x07); + if (retval < 0) { + TPD_INFO("Failed to set dynamic touch and hold config\n"); + return retval; + } + + //retval = syna_tcm_enable_report(tcm_info, REPORT_TOUCH_HOLD, *tcm_info->in_suspend ? false : true); + //if (retval < 0) { + // TPD_INFO("Failed to set enable touch and hold report\n"); + // return retval; + //} + } else { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_TOUCH_HOLD, 0x00); + if (retval < 0) { + TPD_INFO("Failed to set dynamic touch and hold config\n"); + return retval; + } + //retval = syna_tcm_enable_report(tcm_info, REPORT_TOUCH_HOLD, false); + //if (retval < 0) { + // TPD_INFO("Failed to set disable touch and hold report\n"); + // return retval; + //} + } + + if (retval < 0) { + TPD_INFO("Failed to set dynamic touch and hold config\n"); + } + + return retval; +} + +static int syna_mode_switch(void *chip_data, work_mode mode, bool flag) +{ + int ret = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + switch(mode) { + case MODE_NORMAL: + ret = syna_tcm_normal_mode(tcm_info); + if (ret < 0) { + TPD_INFO("normal mode switch failed\n"); + } + break; + case MODE_GESTURE: + ret = syna_tcm_set_gesture_mode(tcm_info, flag); + if (ret < 0) { + TPD_INFO("%s:Failed to set gesture mode\n", __func__); + } + break; + case MODE_GESTURE_SWITCH: + ret = syna_tcm_enable_gesture_mask(tcm_info, flag); + if (ret < 0) { + TPD_INFO("%s: switch gestrue mode: %d failed\n", __func__, flag); + } + break; + case MODE_SLEEP: + ret = syna_tcm_sleep(tcm_info, flag); + if (ret < 0) { + TPD_INFO("%s: failed to switch to sleep", __func__); + } + break; + case MODE_CHARGE: + ret = syna_tcm_set_dynamic_config(tcm_info, DC_CHARGER_CONNECTED, flag ? 1 : 0); + if (ret < 0) { + TPD_INFO("%s:failed to set charger mode\n", __func__); + } + break; + case MODE_EDGE: + ret = syna_enable_edge_limit(tcm_info); + if (ret < 0) { + TPD_INFO("%s: failed to enable edg limit.\n", __func__); + } + break; + case MODE_LIMIT_SWITCH: + ret = syna_corner_limit_handle(tcm_info); + if (ret < 0) { + TPD_INFO("%s: limit switch: %d failed\n", __func__, flag); + } + break; + case MODE_REFRESH_SWITCH: + ret = syna_tcm_refresh_switch(flag); + if (ret < 0) { + TPD_INFO("%s: swhitch refresh rate mode: %d failed\n", __func__, flag); + } + break; + case MODE_GAME: + ret = syna_tcm_set_game_mode(tcm_info, flag); + if (ret < 0) { + TPD_INFO("%s:failed to set game mode\n", __func__); + } + break; + case MODE_TOUCH_HOLD: + ret = syna_tcm_enable_touchhold(tcm_info, flag); + if (ret < 0) { + TPD_INFO("%s: open touchhold mode: %d failed\n", __func__, flag); + } + break; + case MODE_TP_DELTA_PRINT: + ret = syna_tp_delta_print(tcm_info); + if (ret < 0) { + TPD_INFO("%s: print tp delta: %d failed\n", __func__, flag); + } + break; + default: + break; + } + return 0; +} +/* + static int syna_ftm_process(void *chip_data) + { + TPD_INFO("%s: go into sleep\n", __func__); + syna_get_chip_info(chip_data); + syna_mode_switch(chip_data, MODE_SLEEP, true); + return 0; + } + */ +static int syna_tcm_reinit_device (void *chip_data) +{ + complete_all(&response_complete); + complete_all(&report_complete); + + return 0; +} + +static int syna_power_control(void *chip_data, bool enable) +{ + int ret = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + TPD_DEBUG("%s: %d\n", __func__, enable); + + if (true == enable) { + ret = tp_powercontrol_2v8(tcm_info->hw_res, true); + if (ret) { + return -1; + } + ret = tp_powercontrol_1v8(tcm_info->hw_res, true); + if (ret) { + return -1; + } + //synaptics_resetgpio_set(tcm_info->hw_res, false); + //msleep(POWEWRUP_TO_RESET_TIME); + //synaptics_resetgpio_set(tcm_info->hw_res, true); + //msleep(RESET_TO_NORMAL_TIME); + //syna_tcm_reset(tcm_info); + } else { + synaptics_resetgpio_set(tcm_info->hw_res, false); + ret = tp_powercontrol_1v8(tcm_info->hw_res, false); + if (ret) { + return -1; + } + ret = tp_powercontrol_2v8(tcm_info->hw_res, false); + if (ret) { + return -1; + } + } + + return ret; +} + +static fw_check_state syna_fw_check(void *chip_data, struct resolution_info *resolution_info, struct panel_info *panel_data) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + u16 config = 0; + int retval = 0; + + TPD_INFO("fw id %d, custom config id 0x%s\n", panel_data->TP_FW, tcm_info->app_info.customer_config_id); + + if (strlen(tcm_info->app_info.customer_config_id) == 0) { + return FW_ABNORMAL; + } + + panel_data->TP_FW = le4_to_uint(tcm_info->id_info.build_id); + //sscanf(tcm_info->app_info.customer_config_id, "%x", &panel_data->TP_FW); + if (panel_data->TP_FW == 0) { + return FW_ABNORMAL; + } + + if (panel_data->manufacture_info.version) { + sprintf(panel_data->manufacture_info.version, "0x%s", tcm_info->app_info.customer_config_id); + } + retval = syna_tcm_get_dynamic_config(tcm_info, DC_NOISE_LENGTH, &config); + if (retval < 0) { + TPD_INFO("Failed to get default noise length\n"); + } + + tcm_info->default_noise_length = config; + + return FW_NORMAL; +} + +static int syna_tcm_helper(struct syna_tcm_data *tcm_info) +{ + if (tcm_info->id_info.mode != MODE_APPLICATION && !mutex_is_locked(&tcm_info->reset_mutex)) { + TPD_INFO("%s: use helper\n", __func__); + queue_work(tcm_info->helper_workqueue, &tcm_info->helper_work); + } + + return 0; +} + +static void syna_tcm_helper_work(struct work_struct *work) +{ + int retval = 0; + struct syna_tcm_data *tcm_info = container_of(work, struct syna_tcm_data, helper_work); + + mutex_lock(&tcm_info->reset_mutex); + retval = syna_tcm_run_application_firmware(tcm_info); + if (retval < 0) { + TPD_INFO("Failed to switch to app mode\n"); + } + + mutex_unlock(&tcm_info->reset_mutex); +} + +static int syna_tcm_async_work(void *chip_data) +{ + int retval = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + if (tcm_info->id_info.mode != MODE_APPLICATION) { + return 0; + } + + retval = syna_tcm_identify(tcm_info, false); + if (retval < 0) { + TPD_INFO("Failed to do identification\n"); + return retval; + } + + syna_set_trigger_reason(tcm_info, IRQ_FW_AUTO_RESET); + return 0; +} + +#if 0 +static int syna_tcm_enable_report(struct syna_tcm_data *tcm_info, enum report_type report_type, bool enable) +{ + int retval; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char out[2] = {0}; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0; + unsigned int resp_length = 0; + + test_hcd->report_index = 0; + test_hcd->report_type = report_type; + + out[0] = test_hcd->report_type; + + retval = syna_tcm_write_message(tcm_info, + enable ? CMD_ENABLE_REPORT : CMD_DISABLE_REPORT, + out, + 1, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write message %s\n", enable ? STR(CMD_ENABLE_REPORT) : STR(CMD_DISABLE_REPORT)); + } + + return retval; +} +#endif + +static void syna_tcm_enable_fingerprint(void *chip_data, uint32_t enable) +{ + int retval = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + TPD_INFO("%s: enable(%d)\n", __func__, enable); + + if (enable) { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_TOUCH_HOLD, 0x07); + if (retval < 0) { + TPD_INFO("Failed to set dynamic touch and hold config\n"); + return; + } + //retval = syna_tcm_enable_report(tcm_info, REPORT_TOUCH_HOLD, *tcm_info->in_suspend ? false : true); + //if (retval < 0) { + // TPD_INFO("Failed to set enable touch and hold report\n"); + // return; + //} + } else { + retval = syna_tcm_set_dynamic_config(tcm_info, DC_TOUCH_HOLD, 0x00); + if (retval < 0) { + TPD_INFO("Failed to set dynamic touch and hold config\n"); + return; + } + //retval = syna_tcm_enable_report(tcm_info, REPORT_TOUCH_HOLD, false); + //if (retval < 0) { + // TPD_INFO("Failed to set disable touch and hold report\n"); + // return; + //} + } + + return; +} + +static void syna_tcm_fingerprint_info(void *chip_data, struct fp_underscreen_info *fp_tpinfo) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + struct touch_data *touch_data = &touch_hcd->touch_data; + //u8 *fp_buf = tcm_info->report.buffer.buf; + u8 *fp_buf = touch_data->extra_gesture_info; + + if (!fp_tpinfo) { + return; + } + + TPD_INFO("%s:lpwg_gesture = 0x%02x\n", __func__, touch_data->lpwg_gesture); + + if (tcm_info->report.buffer.data_length < 8 && touch_data->lpwg_gesture == TOUCH_HOLD_DOWN) { + TPD_INFO("%s: invalid fingerprint buf length\n", __func__); + return; + } + + if (touch_data->lpwg_gesture == TOUCH_HOLD_DOWN) { + fp_tpinfo->touch_state = FINGERPRINT_DOWN_DETECT; + fp_tpinfo->x = fp_buf[0] | fp_buf[1] << 8; + fp_tpinfo->y = fp_buf[2] | fp_buf[3] << 8; + fp_tpinfo->area_rate = fp_buf[4] | fp_buf[5] << 8; + } else if (touch_data->lpwg_gesture == TOUCH_HOLD_UP) { + fp_tpinfo->touch_state = FINGERPRINT_UP_DETECT; + } + + return; +} + + +static void syna_tcm_get_health_info(void *chip_data) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + struct health_info *health_info = (struct health_info *)tcm_info->report.buffer.buf; + int data_length = tcm_info->report.buffer.data_length; + struct health_info *health_local = &tcm_info->health_info; + int i = 0; + + if (data_length < 20) { + TPD_INFO("%s: invalid health debug buf length\n", __func__); + return; + } + + memcpy(health_local, health_info, sizeof(struct health_info)); + + for (i = 0; i < data_length; i++) { + if (i == 14) { + TPD_INFO("*[0x%x], ", tcm_info->report.buffer.buf[i]); + } else { + TPD_INFO("[0x%x], ", tcm_info->report.buffer.buf[i]); + } + } + +} + + +static int syna_tcm_erase_flash(struct syna_tcm_data *tcm_info, unsigned int page_start, unsigned int page_count) +{ + int ret = 0; + unsigned char out_buf[4] = {0}; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0; + unsigned int resp_length = 0; + unsigned int cmd_length = 0; + + TPD_INFO("start page %d, page count %d\n", page_start, page_count); + if (page_start > 0xff || page_count > 0xff) { + cmd_length = 4; + out_buf[0] = (unsigned char)(page_start & 0xff); + out_buf[1] = (unsigned char)((page_start >> 8) & 0xff); + out_buf[2] = (unsigned char)(page_count & 0xff); + out_buf[3] = (unsigned char)((page_count >> 8) & 0xff); + } else { + cmd_length = 2; + out_buf[0] = (unsigned char)page_start; + out_buf[1] = (unsigned char)page_count; + } + + ret = syna_tcm_write_message(tcm_info, CMD_ERASE_FLASH, out_buf, cmd_length, + &resp_buf, &resp_buf_size, &resp_length, ERASE_FLASH_DELAY_MS); + if (ret < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_ERASE_FLASH)); + } + + kfree(resp_buf); + return ret; +} + +static int syna_tcm_write_flash(struct syna_tcm_data *tcm_info, struct reflash_hcd *reflash_hcd, + unsigned int address, const unsigned char *data, unsigned int datalen) +{ + int retval; + unsigned int w_len, xfer_len, remaining_len; + unsigned int flash_addr, block_addr; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0, resp_length = 0, offset = 0; + struct syna_tcm_buffer out; + + memset(&out, 0, sizeof(out)); + INIT_BUFFER(out, false); + + w_len = tcm_info->wr_chunk_size - 5; + w_len = w_len - (w_len % reflash_hcd->write_block_size); + w_len = MIN(w_len, reflash_hcd->max_write_payload_size); + + remaining_len = datalen; + + while(remaining_len) { + if (remaining_len > w_len) { + xfer_len = w_len; + } else { + xfer_len = remaining_len; + } + + retval = syna_tcm_alloc_mem(&out, xfer_len + 2); + if (retval < 0) { + TPD_INFO("Failed to alloc memory\n"); + break; + } + + flash_addr = address + offset; + block_addr = flash_addr / reflash_hcd->write_block_size; + out.buf[0] = (unsigned char)block_addr; + out.buf[1] = (unsigned char)(block_addr >> 8); + + retval = secure_memcpy(&out.buf[2], + xfer_len, + &data[offset], + datalen - offset, + xfer_len); + if (retval < 0) { + TPD_INFO("Failed to copy write data\n"); + break; + } + + retval = syna_tcm_write_message(tcm_info, CMD_WRITE_FLASH, + out.buf, + xfer_len + 2, + &resp_buf, + &resp_buf_size, + &resp_length, + WRITE_FLASH_DELAY_MS); + if (retval < 0) { + TPD_INFO("Failed to write message %s, Addr 0x%08x, Len 0x%d\n", + STR(CMD_WRITE_FLASH), flash_addr, xfer_len); + break; + } + + offset += xfer_len; + remaining_len -= xfer_len; + } + + RELEASE_BUFFER(out); + kfree(resp_buf); + return 0; +} + +extern int try_to_recovery_ic(struct syna_tcm_data *tcm_info, char *iHex); + +static fw_update_state syna_tcm_fw_update(void *chip_data, const struct firmware *fw, bool force) +{ + int ret = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + struct image_info image_info; + unsigned int image_fw_id, device_fw_id; + unsigned char *device_config_id = NULL; + unsigned char *image_config_id = NULL; + struct app_config_header *header = NULL; + int temp = 0, page_start = 0, page_count = 0; + unsigned int size = 0, flash_addr = 0, device_addr = 0, device_size = 0; + const unsigned char *data; + struct reflash_hcd reflash_hcd; + + /*first check whether in ubl mode, if yes, do iHex update first. may have i2c error */ + /*if not force, do not do recovery*/ + /* + if (force) { + ret = try_to_recovery_ic(tcm_info, tcm_info->iHex_name); + + if (ret > 0) { + ret = syna_tcm_switch_mode(tcm_info, FW_MODE_APPLICATION); //switch to app mode to get app info + if (ret < 0) { + TPD_INFO("Failed to switch to normal mode\n"); + return FW_UPDATE_ERROR; + } + } + } + */ + + memset(&image_info, 0, sizeof(struct image_info)); + ret = synaptics_parse_header_v2(&image_info, fw->data); + if (ret < 0) { + TPD_INFO("Failed to parse fw image\n"); + return FW_UPDATE_FATAL; + } + + header = (struct app_config_header *)image_info.app_config.data; + + image_fw_id = le4_to_uint(header->build_id); + device_fw_id = le4_to_uint(tcm_info->id_info.build_id); + TPD_INFO("image build id %d, device build id %d\n", image_fw_id, device_fw_id); + + image_config_id = header->customer_config_id; + device_config_id = tcm_info->app_info.customer_config_id; + TPD_INFO("image config id 0x%s, device config id 0x%s\n", image_config_id, device_config_id); + + if (!force) { + if ((image_fw_id == device_fw_id) && (strncmp(image_config_id, device_config_id, 16) == 0)) { + TPD_INFO("same firmware/config id, no need to update\n"); + return FW_NO_NEED_UPDATE; + } + } + + ret = syna_tcm_identify(tcm_info, true); + if (ret < 0) { + return FW_UPDATE_ERROR; + } + + if (tcm_info->id_info.mode == MODE_APPLICATION) { + ret = syna_tcm_switch_mode(tcm_info, FW_MODE_BOOTLOADER); + if (ret < 0) { + TPD_INFO("Failed to switch to bootloader mode\n"); + return FW_UPDATE_ERROR; + } + } + + temp = tcm_info->boot_info.write_block_size_words; + reflash_hcd.write_block_size = temp * 2; + + temp = le2_to_uint(tcm_info->boot_info.erase_page_size_words); + reflash_hcd.page_size = temp * 2; + + temp = le2_to_uint(tcm_info->boot_info.max_write_payload_size); + reflash_hcd.max_write_payload_size = temp; + + TPD_INFO("Write block size %d, page size %d, payload_size %d\n", + reflash_hcd.write_block_size, + reflash_hcd.page_size, + reflash_hcd.max_write_payload_size); + + if (reflash_hcd.write_block_size > (tcm_info->wr_chunk_size - 5)) { + TPD_INFO("write block size is exceed\n"); + return FW_UPDATE_ERROR; + } + + if (image_info.app_firmware.size == 0) { + TPD_INFO("no application firmware in image\n\n"); + return FW_UPDATE_ERROR; + } + + /* erase application firmware */ + page_start = image_info.app_firmware.flash_addr / reflash_hcd.page_size; + page_count = ceil_div(image_info.app_firmware.size, reflash_hcd.page_size); + ret = syna_tcm_erase_flash(tcm_info, page_start, page_count); + if (ret < 0) { + TPD_INFO("Failed to erase firmware\n"); + return FW_UPDATE_ERROR; + } + + /* write application firmware */ + data = image_info.app_firmware.data; + size = image_info.app_firmware.size; + flash_addr = image_info.app_firmware.flash_addr; + + ret = syna_tcm_write_flash(tcm_info, &reflash_hcd, flash_addr, data, size); + if (ret < 0) { + TPD_INFO("Failed to write flash \n"); + return FW_UPDATE_ERROR; + } + + /* update app config start */ + data = image_info.app_config.data; + size = image_info.app_config.size; + flash_addr = image_info.app_config.flash_addr; + + temp = le2_to_uint(tcm_info->app_info.app_config_start_write_block); + device_addr = temp * reflash_hcd.write_block_size; + device_size = le2_to_uint(tcm_info->app_info.app_config_size); + + TPD_INFO("Config Device addr/size 0x%x/%d, flash addr/size 0x%x/%d\n", + device_addr, device_size, flash_addr, size); + + page_start = image_info.app_config.flash_addr / reflash_hcd.page_size; + page_count = ceil_div(image_info.app_config.size, reflash_hcd.page_size); + + ret = syna_tcm_erase_flash(tcm_info, page_start, page_count); + if (ret < 0) { + TPD_INFO("Failed to erase config\n"); + return FW_UPDATE_ERROR; + } + + ret = syna_tcm_write_flash(tcm_info, &reflash_hcd, flash_addr, data, size); + if (ret < 0) { + TPD_INFO("Failed to write config \n"); + return FW_UPDATE_ERROR; + } + + TPD_INFO("end of config update\n"); + /* update app config end */ + + return FW_UPDATE_SUCCESS; +} + + +static int syna_get_gesture_info(void *chip_data, struct gesture_info *gesture) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + struct touch_hcd *touch_hcd = tcm_info->touch_hcd; + struct touch_data *touch_data = &touch_hcd->touch_data; + + gesture->clockwise = 2; + switch (touch_data->lpwg_gesture) { + case STAP_DETECT: + gesture->gesture_type = SingleTap; + break; + //case DTAP_DETECT: + // gesture->gesture_type = DouTap; + // break; + case CIRCLE_DETECT: + gesture->gesture_type = Circle; + if (touch_data->extra_gesture_info[2] == 0x10) + gesture->clockwise = 1; + else if (touch_data->extra_gesture_info[2] == 0x20) + gesture->clockwise = 0; + break; + case SWIPE_DETECT: + if (touch_data->extra_gesture_info[4] == 0x41) {//x+ + gesture->gesture_type = Left2RightSwip; + } else if (touch_data->extra_gesture_info[4] == 0x42) {//x- + gesture->gesture_type = Right2LeftSwip; + } else if (touch_data->extra_gesture_info[4] == 0x44) {//y+ + gesture->gesture_type = Up2DownSwip; + } else if (touch_data->extra_gesture_info[4] == 0x48) {//y- + gesture->gesture_type = Down2UpSwip; + } else if (touch_data->extra_gesture_info[4] == 0x81) {//2x- + gesture->gesture_type = DouSwip; + } else if (touch_data->extra_gesture_info[4] == 0x82) {//2x+ + gesture->gesture_type = DouSwip; + } else if (touch_data->extra_gesture_info[4] == 0x84) {//2y+ + gesture->gesture_type = DouSwip; + } else if (touch_data->extra_gesture_info[4] == 0x88) {//2y- + gesture->gesture_type = DouSwip; + } + break; + case M_UNICODE: + gesture->gesture_type = Mgestrue; + break; + case W_UNICODE: + gesture->gesture_type = Wgestrue; + break; + case S_UNICODE: + gesture->gesture_type = Sgestrue; + break; + case VEE_DETECT: + if (touch_data->extra_gesture_info[2] == 0x02) {//up + gesture->gesture_type = UpVee; + } else if (touch_data->extra_gesture_info[2] == 0x01) {//down + gesture->gesture_type = DownVee; + } else if (touch_data->extra_gesture_info[2] == 0x08) {//left + gesture->gesture_type = LeftVee; + } else if (touch_data->extra_gesture_info[2] == 0x04) {//right + gesture->gesture_type = RightVee; + } + break; + case TOUCH_HOLD_DOWN: + gesture->gesture_type = FingerprintDown; + break; + case TOUCH_HOLD_UP: + gesture->gesture_type = FingerprintUp; + break; + case TRIANGLE_DETECT: + default: + TPD_DEBUG("not support\n"); + break; + } + if (gesture->gesture_type != UnkownGesture) { + gesture->Point_start.x = (touch_data->data_point[0] | (touch_data->data_point[1] << 8)); + gesture->Point_start.y = (touch_data->data_point[2] | (touch_data->data_point[3] << 8)); + gesture->Point_end.x = (touch_data->data_point[4] | (touch_data->data_point[5] << 8)); + gesture->Point_end.y = (touch_data->data_point[6] | (touch_data->data_point[7] << 8)); + gesture->Point_1st.x = (touch_data->data_point[8] | (touch_data->data_point[9] << 8)); + gesture->Point_1st.y = (touch_data->data_point[10] | (touch_data->data_point[11] << 8)); + gesture->Point_2nd.x = (touch_data->data_point[12] | (touch_data->data_point[13] << 8)); + gesture->Point_2nd.y = (touch_data->data_point[14] | (touch_data->data_point[15] << 8)); + gesture->Point_3rd.x = (touch_data->data_point[16] | (touch_data->data_point[17] << 8)); + gesture->Point_3rd.y = (touch_data->data_point[18] | (touch_data->data_point[19] << 8)); + gesture->Point_4th.x = (touch_data->data_point[20] | (touch_data->data_point[21] << 8)); + gesture->Point_4th.y = (touch_data->data_point[22] | (touch_data->data_point[23] << 8)); + } + + if (gesture->gesture_type == SingleTap) { + gesture->Point_start.x = (touch_data->extra_gesture_info[0] | (touch_data->extra_gesture_info[1] << 8)); + gesture->Point_start.y = (touch_data->extra_gesture_info[2] | (touch_data->extra_gesture_info[3] << 8)); + } + + TPD_INFO("lpwg:0x%x, type:%d\n", touch_data->lpwg_gesture, gesture->gesture_type); + + TPD_INFO("lpwg:0x%x, type:%d, clockwise: %d, points: (%d, %d)(%d, %d)(%d, %d)(%d, %d)(%d, %d)(%d, %d)\n", + touch_data->lpwg_gesture, gesture->gesture_type, gesture->clockwise,\ + gesture->Point_start.x, gesture->Point_start.y, \ + gesture->Point_end.x, gesture->Point_end.y, \ + gesture->Point_1st.x, gesture->Point_1st.y, \ + gesture->Point_2nd.x, gesture->Point_2nd.y, \ + gesture->Point_3rd.x, gesture->Point_3rd.y, \ + gesture->Point_4th.x, gesture->Point_4th.y); + + return 0; +} + + +static void store_to_file(int fd, char *format, ...) +{ + va_list args; + char buf[64] = {0}; + + va_start(args, format); + vsnprintf(buf, 64, format, args); + va_end(args); + + if(fd >= 0) { + ksys_write(fd, buf, strlen(buf)); + } +} + +int syna_tcm_get_frame_size_words(struct syna_tcm_data *tcm_info, bool image_only) +{ + unsigned int rows; + unsigned int cols; + unsigned int hybrid; + unsigned int buttons; + int size = 0; + struct syna_tcm_app_info *app_info = &tcm_info->app_info; + + rows = le2_to_uint(app_info->num_of_image_rows); + cols = le2_to_uint(app_info->num_of_image_cols); + hybrid = le2_to_uint(app_info->has_hybrid_data); + buttons = le2_to_uint(app_info->num_of_buttons); + + size = rows * cols; + + if (!image_only) { + if (hybrid) + size += rows + cols; + size += buttons; + } + + return size; +} + +static int testing_run_prod_test_item(struct syna_tcm_data *tcm_info, enum test_item_bit test_code) +{ + int retval = 0; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + + if (tcm_info->id_info.mode != MODE_APPLICATION || tcm_info->app_status != APP_STATUS_OK) { + TPD_INFO("Application firmware not running\n"); + return -ENODEV; + } + + LOCK_BUFFER(test_hcd->test_out); + + retval = syna_tcm_alloc_mem(&test_hcd->test_out, + 1); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for test_hcd->test_out.buf\n"); + UNLOCK_BUFFER(test_hcd->test_out); + return retval; + } + + test_hcd->test_out.buf[0] = test_code; + + LOCK_BUFFER(test_hcd->test_resp); + retval = syna_tcm_write_message(tcm_info, + CMD_PRODUCTION_TEST, + test_hcd->test_out.buf, + 1, + &test_hcd->test_resp.buf, + &test_hcd->test_resp.buf_size, + &test_hcd->test_resp.data_length, + RESPONSE_TIMEOUT_MS_LONG + ); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", + STR(CMD_PRODUCTION_TEST)); + UNLOCK_BUFFER(test_hcd->test_resp); + UNLOCK_BUFFER(test_hcd->test_out); + return retval; + } + + UNLOCK_BUFFER(test_hcd->test_resp); + UNLOCK_BUFFER(test_hcd->test_out); + + return 0; +} + +static uint32_t search_for_item(const struct firmware *fw, int item_cnt, uint8_t item_index) +{ + int i = 0; + uint32_t item_offset = 0; + struct syna_test_item_header *item_header = NULL; + uint32_t *p_item_offset = (uint32_t *)(fw->data + sizeof(struct test_header_new)); + + for (i = 0; i < item_cnt; i++) { + item_header = (struct syna_test_item_header *)(fw->data + p_item_offset[i]); + if (item_header->item_bit == item_index) { //check the matched item offset + item_offset = p_item_offset[i]; + } + } + + return item_offset; +} + +static int syna_int_pin_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + int eint_status, eint_count = 0, read_gpio_num = 10; + + TPD_INFO("%s start.\n", __func__); + while(read_gpio_num--) { + msleep(5); + eint_status = gpio_get_value(syna_testdata->irq_gpio); + if (eint_status == 1) + eint_count--; + else + eint_count++; + TPD_INFO("%s eint_count = %d eint_status = %d\n", __func__, eint_count, eint_status); + } + if (eint_count == 10) { + TPD_INFO("interrupt gpio is short to gnd.\n"); + if (!error_count) + seq_printf(s, "interrupt gpio is short to gnd.\n"); + error_count++; + return error_count; + } + + return error_count; +} + +static int syna_trx_short_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + uint8_t u_data8 = 0; + int i = 0, j = 0, ret = 0; + unsigned int checked_bits = 0, total_bits = 0; + struct syna_test_item_header *item_header = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + total_bits = syna_testdata->TX_NUM + syna_testdata->RX_NUM; + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("trx short test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 0:trx short test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_TRX_SHORT); + if (ret < 0) { + TPD_INFO("run trx short test failed.\n"); + if (!error_count) + seq_printf(s, "Step 0:run trx short test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "trx_short:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + u_data8 = buf[i]; + store_to_file(syna_testdata->fd, "0x%02x, ", u_data8); + for (j = 0; j < 8; j++) { + if (1 == (u_data8 & (1 << j))) { + TPD_INFO("trx short test failed at %d bits.\n", checked_bits + 1); + if (!error_count) + seq_printf(s, "Step 0:+trx short test failed at %d bits.\n", checked_bits + 1); + error_count++; + } + checked_bits++; + if (checked_bits >= total_bits) + goto full_out; + } + + i += 1; + } + +full_out: + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_trx_open_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + uint8_t u_data8 = 0; + int i = 0, j = 0, ret = 0; + unsigned int checked_bits = 0, total_bits = 0; + struct syna_test_item_header *item_header = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + total_bits = syna_testdata->TX_NUM + syna_testdata->RX_NUM; + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("trx open test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 1:trx open test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_TRX_OPEN); + if (ret < 0) { + TPD_INFO("run trx open test failed.\n"); + if (!error_count) + seq_printf(s, "Step 1:run trx open test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "tx_tx_open:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + u_data8 = buf[i]; + store_to_file(syna_testdata->fd, "0x%02x, ", u_data8); + for (j = 0; j < 8; j++) { + if (0 == (u_data8 & (1 << j))) { + TPD_INFO("trx open test failed at %d bits.\n", checked_bits + 1); + if (!error_count) + seq_printf(s, "Step 1:trx open test failed at %d bits.\n", checked_bits + 1); + error_count++; + } + checked_bits++; + if (checked_bits >= total_bits) + goto full_out; + } + + i += 1; + } + +full_out: + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_trx_gndshort_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + uint8_t u_data8 = 0; + int i = 0, j = 0, ret = 0; + unsigned int checked_bits = 0, total_bits = 0; + struct syna_test_item_header *item_header = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + total_bits = syna_testdata->TX_NUM + syna_testdata->RX_NUM; + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("trx gndshort test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 2:trx gndshort test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_TRXGND_SHORT); + if (ret < 0) { + TPD_INFO("run trx gndshort test failed.\n"); + if (!error_count) + seq_printf(s, "Step 2:run trx gndshort test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "tx_tx_gndshort:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + u_data8 = buf[i]; + store_to_file(syna_testdata->fd, "0x%02x, ", u_data8); + for (j = 0; j < 8; j++) { + if (0 == (u_data8 & (1 << j))) { + TPD_INFO("trx gndshort test failed at %d bits.\n", checked_bits + 1); + if (!error_count) + seq_printf(s, "Step 2:trx gndshort test failed at %d bits.\n", checked_bits + 1); + error_count++; + } + checked_bits++; + if (checked_bits >= total_bits) + goto full_out; + } + + i += 1; + } + +full_out: + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_full_rawcap_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + uint16_t u_data16 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 2; + struct syna_test_item_header *item_header = NULL; + int32_t *p_mutual_p = NULL, *p_mutual_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("full rawcap test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 3:full rawcap test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_mutual_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_mutual_n = (int32_t *)(syna_testdata->fw->data + item_header->floor_limit_offset); + } else { + TPD_INFO("full rawcap test limit type(%2x) is wrong.\n", item_header->item_limit_type); + if (!error_count) + seq_printf(s, "Step 3:full rawcap test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_FULLRAW_CAP); + if (ret < 0) { + TPD_INFO("run full rawcap test failed.\n"); + if (!error_count) + seq_printf(s, "Step 3:run full rawcap test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "full_rawcap:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + u_data16 = (buf[i] | (buf[i + 1] << 8)); + if (0 == index % (syna_testdata->RX_NUM)) + store_to_file(syna_testdata->fd, "\n"); + store_to_file(syna_testdata->fd, "%04d, ", u_data16); + if ((u_data16 < p_mutual_n[index]) || (u_data16 > p_mutual_p[index])) { + TPD_INFO("full rawcap test failed at node[%d]=%d [%d %d].\n", index, u_data16, p_mutual_n[index], p_mutual_p[index]); + if (!error_count) + seq_printf(s, "Step 3:full rawcap test failed at node[%d]=%d [%d %d].\n", index, u_data16, p_mutual_n[index], p_mutual_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_delta_noise_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + int16_t data16 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 2; + struct syna_test_item_header *item_header = NULL; + int32_t *p_mutual_p = NULL, *p_mutual_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("delta noise test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 4:delta noise test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_mutual_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_mutual_n = (int32_t *)(syna_testdata->fw->data + item_header->floor_limit_offset); + } else { + if (!error_count) + seq_printf(s, "Step 4:delta noise test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_DELTA_NOISE); + if (ret < 0) { + TPD_INFO("run delta noise rawcap test failed.\n"); + if (!error_count) + seq_printf(s, "Step 4:run delta noise test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "delta_noise:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + data16 = (buf[i] | (buf[i + 1] << 8)); + if (0 == index % (syna_testdata->RX_NUM)) + store_to_file(syna_testdata->fd, "\n"); + store_to_file(syna_testdata->fd, "%04d, ", data16); + if ((data16 < p_mutual_n[index]) || (data16 > p_mutual_p[index])) { + TPD_INFO("delta noise test failed at node[%d]=%d [%d %d].\n", index, data16, p_mutual_n[index], p_mutual_p[index]); + if (!error_count) + seq_printf(s, "Step 4:delta noise test failed at node[%d]=%d [%d %d].\n", index, data16, p_mutual_n[index], p_mutual_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_hybrid_rawcap_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + int32_t data32 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 4; + struct syna_test_item_header *item_header = NULL; + int32_t *p_hybridcap_p = NULL, *p_hybridcap_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("hybrid_rawcap test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 5:hybrid_rawcap test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_hybridcap_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_hybridcap_n = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset + 4 * (syna_testdata->TX_NUM + syna_testdata->RX_NUM)); + } else { + TPD_INFO("hybrid_rawcap test limit type(%2x) is wrong.\n", item_header->item_limit_type); + if (!error_count) + seq_printf(s, "Step 5:hybrid_rawcap test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_HYBRIDRAW_CAP); + if (ret < 0) { + TPD_INFO("run hybrid rawcap test failed.\n"); + if (!error_count) + seq_printf(s, "Step 5:run hybrid rawcap test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "hybrid_rawcap:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + data32 = (buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16) | (buf[i + 3] << 24)); + store_to_file(syna_testdata->fd, "%08d, ", data32); + if ((data32 < p_hybridcap_n[index]) || (data32 > p_hybridcap_p[index])) { + TPD_INFO("hybrid rawcap test failed at node[%d]=%d [%d %d].\n", index, data32, p_hybridcap_n[index], p_hybridcap_p[index]); + if (!error_count) + seq_printf(s, "Step 5:hybrid rawcap test failed at node[%d]=%d [%d %d].\n", index, data32, p_hybridcap_n[index], p_hybridcap_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_rawcap_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + int16_t data16 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 2; + struct syna_test_item_header *item_header = NULL; + int32_t *p_mutual_p = NULL, *p_mutual_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("raw cap test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 6:raw cap test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_mutual_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_mutual_n = (int32_t *)(syna_testdata->fw->data + item_header->floor_limit_offset); + } else { + TPD_INFO("raw cap test limit type(%2x) is wrong.\n", item_header->item_limit_type); + if (!error_count) + seq_printf(s, "Step 6:raw cap test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_RAW_CAP); + if (ret < 0) { + TPD_INFO("run raw cap test failed.\n"); + if (!error_count) + seq_printf(s, "Step 6:run raw cap test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "raw_cap:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + data16 = (buf[i] | (buf[i + 1] << 8)); + if (0 == index % (syna_testdata->RX_NUM)) + store_to_file(syna_testdata->fd, "\n"); + store_to_file(syna_testdata->fd, "%04d, ", data16); + if ((data16 < p_mutual_n[index]) || (data16 > p_mutual_p[index])) { + TPD_INFO("rawcap test failed at node[%d]=%d [%d %d].\n", index, data16, p_mutual_n[index], p_mutual_p[index]); + if (!error_count) + seq_printf(s, "Step 6:rawcap test failed at node[%d]=%d [%d %d].\n", index, data16, p_mutual_n[index], p_mutual_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_trex_shortcustom_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + uint16_t u_data16 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 2; + struct syna_test_item_header *item_header = NULL; + int32_t *p_tx_p = NULL, *p_tx_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("trex short custom test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 7:trex short custom test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_tx_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_tx_n = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset + 4 * syna_testdata->RX_NUM); + } else { + TPD_INFO("trex short custom test limit type(%2x) is wrong.\n", item_header->item_limit_type); + if (!error_count) + seq_printf(s, "Step 7:trex short custom test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_TREXSHORT_CUSTOM); + if (ret < 0) { + TPD_INFO("run trex short custom test failed.\n"); + if (!error_count) + seq_printf(s, "Step 7:run trex short custom test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "trex_shorcustom:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + u_data16 = (buf[i] | (buf[i + 1] << 8)); + store_to_file(syna_testdata->fd, "%04d, ", u_data16); + if ((u_data16 < p_tx_n[index]) || (u_data16 > p_tx_p[index])) { + TPD_INFO("trex_shorcustom test failed at node[%d]=%d [%d %d].\n", index, u_data16, p_tx_n[index], p_tx_p[index]); + if (!error_count) + seq_printf(s, "Step 7:trex_shorcustom test failed at node[%d]=%d [%d %d].\n", index, u_data16, p_tx_n[index], p_tx_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_hybrid_diffcbc_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + uint16_t u_data16 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 2; + struct syna_test_item_header *item_header = NULL; + int32_t *p_selfdata_p = NULL, *p_selfdata_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("hybrid diffcbc test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 8:hybrid diffcbc test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_selfdata_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_selfdata_n = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset + 4 * (syna_testdata->TX_NUM + syna_testdata->RX_NUM)); + } else { + TPD_INFO("hybrid diffcbc test limit type(%2x) is wrong.\n", item_header->item_limit_type); + if (!error_count) + seq_printf(s, "Step 8:hybrid diffcbc test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_HYBRIDABS_DIFF_CBC); + if (ret < 0) { + TPD_INFO("run hybrid diffcbc test failed.\n"); + if (!error_count) + seq_printf(s, "Step 8:run hybrid diffcbc test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "hybrid_diffwithcbc:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + u_data16 = (buf[i] | (buf[i + 1] << 8)); + store_to_file(syna_testdata->fd, "%04d, ", u_data16); + if ((u_data16 < p_selfdata_n[index]) || (u_data16 > p_selfdata_p[index])) { + TPD_INFO("hybrid diffcbc test failed at node[%d]=%d [%d %d].\n", index, u_data16, p_selfdata_n[index], p_selfdata_p[index]); + if (!error_count) + seq_printf(s, "Step 8:hybrid diffcbc test failed at node[%d]=%d [%d %d].\n", index, u_data16, p_selfdata_n[index], p_selfdata_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static int syna_hybrid_absnoise_test(struct seq_file *s, struct syna_tcm_data *tcm_info, + struct syna_testdata *syna_testdata, int item_offset, int error_count) +{ + int16_t data16 = 0; + int i = 0, ret = 0, index = 0, byte_cnt = 2; + struct syna_test_item_header *item_header = NULL; + int32_t *p_selfdata_p = NULL, *p_selfdata_n = NULL; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char *buf = NULL; + + item_header = (struct syna_test_item_header *)(syna_testdata->fw->data + item_offset); + if (item_header->item_magic != Limit_ItemMagic) { + TPD_INFO("hybrid abs noise test magic number(%4x) is wrong.\n", item_header->item_magic); + if (!error_count) + seq_printf(s, "Step 9:hybrid abs noise test magic number(%4x) is wrong.\n", item_header->item_magic); + error_count++; + return error_count; + } + if (item_header->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + p_selfdata_p = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset); + p_selfdata_n = (int32_t *)(syna_testdata->fw->data + item_header->top_limit_offset + 4 * (syna_testdata->TX_NUM + syna_testdata->RX_NUM)); + } else { + TPD_INFO("hybrid abs noise test limit type(%2x) is wrong.\n", item_header->item_limit_type); + if (!error_count) + seq_printf(s, "Step 9:hybrid abs noise test limit type(%2x) is wrong.\n", item_header->item_limit_type); + error_count++; + return error_count; + } + + TPD_INFO("%s start.\n", __func__); + ret = testing_run_prod_test_item(tcm_info, TYPE_HYBRIDABS_NOSIE); + if (ret < 0) { + TPD_INFO("run hybrid abs noise test failed.\n"); + if (!error_count) + seq_printf(s, "Step 9:run hybrid abs noise test failed.\n"); + error_count++; + return error_count; + } + + LOCK_BUFFER(test_hcd->test_resp); + buf = test_hcd->test_resp.buf; + TPD_INFO("%s read data size:%d\n", __func__, test_hcd->test_resp.data_length); + store_to_file(syna_testdata->fd, "hybrid_absnoise:\n"); + for (i = 0; i < test_hcd->test_resp.data_length;) { + index = i / byte_cnt; + data16 = (buf[i] | (buf[i + 1] << 8)); + store_to_file(syna_testdata->fd, "%04d, ", data16); + if ((data16 < p_selfdata_n[index]) || (data16 > p_selfdata_p[index])) { + TPD_INFO("hybrid abs noise test failed at node[%d]=%d [%d %d].\n", index, data16, p_selfdata_n[index], p_selfdata_p[index]); + if (!error_count) + seq_printf(s, "Step 9:hybrid abs noise test failed at node[%d]=%d [%d %d].\n", index, data16, p_selfdata_n[index], p_selfdata_p[index]); + error_count++; + } + + i += byte_cnt; + } + UNLOCK_BUFFER(test_hcd->test_resp); + store_to_file(syna_testdata->fd, "\n"); + + return error_count; +} + +static void syna_auto_test(struct seq_file *s, void *chip_data, struct syna_testdata *syna_testdata) +{ + int i = 0, error_count = 0, item_offset = 0, item_cnt = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + //calculate the total test item + for (i = 0; i < 8 * sizeof(syna_testdata->test_item); i++) { + if ((syna_testdata->test_item >> i) & 0x01) { + item_cnt++; + } + } + TPD_INFO("this test have %d test_item.\n", item_cnt); + + //tp int short test + syna_int_pin_test(s, tcm_info, syna_testdata, item_offset, error_count); + + //check if it support tx and rx short test + if (syna_testdata->test_item & (1 << TYPE_TRX_SHORT)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_TRX_SHORT); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_TRX_SHORT); + seq_printf(s, "Step 0:search for item(%d) limit offset failed.\n", TYPE_TRX_SHORT); + } else { + error_count = syna_trx_short_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support tx and rx open test + if (syna_testdata->test_item & (1 << TYPE_TRX_OPEN)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_TRX_OPEN); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_TRX_OPEN); + seq_printf(s, "Step 1:search for item(%d) limit offset failed.\n", TYPE_TRX_OPEN); + } else { + error_count = syna_trx_open_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support tx and rx gnd short test + if (syna_testdata->test_item & (1 << TYPE_TRXGND_SHORT)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_TRXGND_SHORT); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_TRXGND_SHORT); + seq_printf(s, "Step 2:search for item(%d) limit offset failed.\n", TYPE_TRXGND_SHORT); + } else { + error_count = syna_trx_gndshort_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support full rawcap test + if (syna_testdata->test_item & (1 << TYPE_FULLRAW_CAP)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_FULLRAW_CAP); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_FULLRAW_CAP); + seq_printf(s, "Step 3:search for item(%d) limit offset failed.\n", TYPE_FULLRAW_CAP); + } else { + error_count = syna_full_rawcap_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support delta noise test + if (syna_testdata->test_item & (1 << TYPE_DELTA_NOISE)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_DELTA_NOISE); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_DELTA_NOISE); + seq_printf(s, "Step 4:search for item(%d) limit offset failed.\n", TYPE_DELTA_NOISE); + } else { + error_count = syna_delta_noise_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support hybrid rawcap test + if (syna_testdata->test_item & (1 << TYPE_HYBRIDRAW_CAP)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_HYBRIDRAW_CAP); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_HYBRIDRAW_CAP); + seq_printf(s, "Step 5:search for item(%d) limit offset failed.\n", TYPE_HYBRIDRAW_CAP); + } else { + error_count = syna_hybrid_rawcap_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support rawcap test + if (syna_testdata->test_item & (1 << TYPE_RAW_CAP)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_RAW_CAP); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_RAW_CAP); + seq_printf(s, "Step 6:search for item(%d) limit offset failed.\n", TYPE_RAW_CAP); + } else { + error_count = syna_rawcap_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support trex shor custom test + if (syna_testdata->test_item & (1 << TYPE_TREXSHORT_CUSTOM)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_TREXSHORT_CUSTOM); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_TREXSHORT_CUSTOM); + seq_printf(s, "Step 7:search for item(%d) limit offset failed.\n", TYPE_TREXSHORT_CUSTOM); + } else { + error_count = syna_trex_shortcustom_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + //check if it support hybrid absdiff with cbc test + if (syna_testdata->test_item & (1 << TYPE_HYBRIDABS_DIFF_CBC)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_HYBRIDABS_DIFF_CBC); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_HYBRIDABS_DIFF_CBC); + seq_printf(s, "Step 8:search for item(%d) limit offset failed.\n", TYPE_HYBRIDABS_DIFF_CBC); + } else { + error_count = syna_hybrid_diffcbc_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + syna_tcm_reset(tcm_info); + //check if it support hybrid noise test + if (syna_testdata->test_item & (1 << TYPE_HYBRIDABS_NOSIE)) { + item_offset = search_for_item(syna_testdata->fw, item_cnt, TYPE_HYBRIDABS_NOSIE); + if (!item_offset) { + error_count++; + TPD_INFO("search for item(%d) limit offset failed.\n", TYPE_HYBRIDABS_NOSIE); + seq_printf(s, "Step 9:search for item(%d) limit offset failed.\n", TYPE_HYBRIDABS_NOSIE); + } else { + error_count = syna_hybrid_absnoise_test(s, tcm_info, syna_testdata, item_offset, error_count); + } + } + + seq_printf(s, "imageid = %lld customID 0x%s\n", syna_testdata->TP_FW, tcm_info->app_info.customer_config_id); + seq_printf(s, "%d error(s). %s\n", error_count, error_count ? "" : "All test passed."); + TPD_INFO(" TP auto test %d error(s). %s\n", error_count, error_count ? "" : "All test passed."); +} + +static int syna_tcm_collect_reports(struct syna_tcm_data *tcm_info, enum report_type report_type, unsigned int num_of_reports) +{ + int retval; + bool completed = false; + unsigned int timeout; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + unsigned char out[2] = {0}; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0; + unsigned int resp_length; + + test_hcd->report_index = 0; + test_hcd->report_type = report_type; + test_hcd->num_of_reports = num_of_reports; + + reinit_completion(&report_complete); + + out[0] = test_hcd->report_type; + + retval = syna_tcm_write_message(tcm_info, + CMD_ENABLE_REPORT, + out, + 1, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write message %s\n", STR(CMD_ENABLE_REPORT)); + completed = false; + goto exit; + } + + timeout = REPORT_TIMEOUT_MS * num_of_reports; + + retval = wait_for_completion_timeout(&report_complete, + msecs_to_jiffies(timeout)); + if (retval == 0) { + TPD_INFO("Timed out waiting for report collection\n"); + } else { + completed = true; + } + + out[0] = test_hcd->report_type; + + retval = syna_tcm_write_message(tcm_info, + CMD_DISABLE_REPORT, + out, + 1, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write message %s\n", STR(CMD_DISABLE_REPORT)); + } + + if (!completed) { + retval = -EIO; + } +exit: + + return retval; +} + +static void syna_tcm_test_report(struct syna_tcm_data *tcm_info) +{ + int retval; + unsigned int offset, report_size; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + + if (tcm_info->report.id != test_hcd->report_type) { + TPD_INFO("Not request report type\n"); + return; + } + + report_size = tcm_info->report.buffer.data_length; + LOCK_BUFFER(test_hcd->report); + + if (test_hcd->report_index == 0) { + retval = syna_tcm_alloc_mem(&test_hcd->report, report_size * test_hcd->num_of_reports); + if (retval < 0) { + TPD_INFO("Failed to allocate memory\n"); + UNLOCK_BUFFER(test_hcd->report); + return; + } + } + + if (test_hcd->report_index < test_hcd->num_of_reports) { + offset = report_size * test_hcd->report_index; + retval = secure_memcpy(test_hcd->report.buf + offset, + test_hcd->report.buf_size - offset, + tcm_info->report.buffer.buf, + tcm_info->report.buffer.buf_size, + tcm_info->report.buffer.data_length); + if (retval < 0) { + TPD_INFO("Failed to copy report data\n"); + + UNLOCK_BUFFER(test_hcd->report); + return; + } + + test_hcd->report_index++; + test_hcd->report.data_length += report_size; + } + + UNLOCK_BUFFER(test_hcd->report); + + if (test_hcd->report_index == test_hcd->num_of_reports) { + complete(&report_complete); + } + return; +} + +static void syna_tcm_format_print(struct seq_file *s, struct syna_tcm_data *tcm_info, char *buffer) +{ + unsigned int row, col; + unsigned int rows, cols; + unsigned int cnt = 0; + short *pdata_16; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + + rows = le2_to_uint(tcm_info->app_info.num_of_image_rows); + cols = le2_to_uint(tcm_info->app_info.num_of_image_cols); + + TPD_INFO("report size:%d\n", test_hcd->report.data_length); + if (buffer == NULL) + pdata_16 = (short *)&test_hcd->report.buf[0]; + else + pdata_16 = (short *)buffer; + + for (row = 0; row < rows; row++) { + seq_printf(s, "[%02d] ", row); + for (col = 0; col < cols; col++) { + seq_printf(s, "%5d ", *pdata_16); + pdata_16++; + } + seq_printf(s, "\n"); + } + + if (test_hcd->report.data_length == rows * cols * 2 + (rows + cols) * 2) { + for (cnt = 0; cnt < rows + cols; cnt++) { + seq_printf(s, "%5d ", *pdata_16); + pdata_16++; + } + } + seq_printf(s, "\n"); + + return; +} + +static void syna_tcm_format_unsigned_print(struct seq_file *s, struct syna_tcm_data *tcm_info, char *buffer) +{ + unsigned int row, col; + unsigned int rows, cols; + unsigned int cnt = 0; + unsigned short *pdata_16; + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + + rows = le2_to_uint(tcm_info->app_info.num_of_image_rows); + cols = le2_to_uint(tcm_info->app_info.num_of_image_cols); + + TPD_INFO("report size:%d\n", test_hcd->report.data_length); + if (buffer == NULL) + pdata_16 = (unsigned short *)&test_hcd->report.buf[0]; + else + pdata_16 = (unsigned short *)buffer; + + for (row = 0; row < rows; row++) { + seq_printf(s, "[%02d] ", row); + for (col = 0; col < cols; col++) { + seq_printf(s, "%5d ", *pdata_16); + pdata_16++; + } + seq_printf(s, "\n"); + } + + if (test_hcd->report.data_length == rows * cols * 2 + (rows + cols) * 2) { + for (cnt = 0; cnt < rows + cols; cnt++) { + seq_printf(s, "%5d ", *pdata_16); + pdata_16++; + } + } + seq_printf(s, "\n"); + + return; +} +static void syna_main_register(struct seq_file *s, void *chip_data) +{ + int retval = 0; + unsigned char *resp_buf = NULL; + unsigned int resp_buf_size = 0; + unsigned int resp_length = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + retval = syna_tcm_write_message(tcm_info, + CMD_GET_NSM_INFO, + NULL, + 0, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + TPD_INFO("Failed to write command %s\n", STR(CMD_GET_NSM_INFO)); + if (s) { + seq_printf(s, "Failed to write command %s\n", STR(CMD_GET_NSM_INFO)); + } + goto exit; + } + + if (resp_length < 10) { + TPD_INFO("Error response data\n"); + if (s) { + seq_printf(s, "Error response data\n"); + } + goto exit; + } + + TPD_INFO("Reset reason:0x%02x%02x\n", resp_buf[1], resp_buf[0]); + TPD_INFO("power im: 0x%02x%02x\n", resp_buf[3], resp_buf[2]); + TPD_INFO("nsm Frequency: 0x%02x%02x\n", resp_buf[5], resp_buf[4]); + TPD_INFO("nsm State: 0x%02x%02x\n", resp_buf[7], resp_buf[6]); + TPD_INFO("esd State: 0x%02x%02x\n", resp_buf[8], resp_buf[9]); + TPD_INFO("Buid ID:%d, Custom ID:0x%s\n", + le4_to_uint(tcm_info->id_info.build_id), + tcm_info->app_info.customer_config_id); + + if (!s) { + goto exit; + } + + seq_printf(s, "Reset reason:0x%02x%02x\n", resp_buf[1], resp_buf[0]); + seq_printf(s, "power im: 0x%02x%02x\n", resp_buf[3], resp_buf[2]); + seq_printf(s, "nsm Frequency: 0x%02x%02x\n", resp_buf[5], resp_buf[4]); + seq_printf(s, "nsm State: 0x%02x%02x\n", resp_buf[7], resp_buf[6]); + seq_printf(s, "esd State: 0x%02x%02x\n", resp_buf[8], resp_buf[9]); + seq_printf(s, "Buid ID:%d, Custom ID:0x%s\n", + le4_to_uint(tcm_info->id_info.build_id), + tcm_info->app_info.customer_config_id); +exit: + kfree(resp_buf); + + return; +} + +static int syna_tp_delta_print(struct syna_tcm_data *tcm_info) +{ + int retval = -1; + int i, j = 0; + unsigned char *Pstr = NULL; + unsigned char pTmp[40] = {0}; + int lsize = 36 * 16; + short *pdata_16; + + struct syna_tcm_test *test_hcd = tcm_info->test_hcd; + + Pstr = kzalloc(lsize * (sizeof(int)), GFP_KERNEL); + if (Pstr == NULL) + return retval; + + TPD_DEBUG("%s:enter", __func__); + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 1); + if (retval < 0) { + TPD_DEBUG("Failed to exit doze\n"); + } + + msleep(20); // delay 20ms + + retval = syna_tcm_collect_reports(tcm_info, REPORT_DELTA, 1); + if (retval < 0) { + TPD_DEBUG("Failed to read delta data\n"); + return retval; + } + + pdata_16 = (short *)&test_hcd->report.buf[0]; + for(i = 0; i < 16; i++) { + memset(Pstr, 0x0, lsize); + snprintf(pTmp, sizeof(pTmp), "[%d]", i); + strncat(Pstr, pTmp, lsize); + for(j = 0; j < 36; j++) { + snprintf(pTmp, sizeof(pTmp), "%4d ", *pdata_16); + pdata_16++; + strncat(Pstr, pTmp, lsize); + } + TPD_DEBUG("%s\n", Pstr); + } + + /*set normal doze*/ + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 0); + if (retval < 0) { + TPD_DEBUG("Failed to switch to normal\n"); + } + + return retval; +} + +static void syna_delta_read(struct seq_file *s, void *chip_data) +{ + int retval; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 1); + if (retval < 0) { + TPD_INFO("Failed to exit doze\n"); + } + + msleep(20); // delay 20ms + + retval = syna_tcm_collect_reports(tcm_info, REPORT_DELTA, 1); + if (retval < 0) { + seq_printf(s, "Failed to read delta data\n"); + return; + } + + syna_tcm_format_print(s, tcm_info, NULL); + + /*set normal doze*/ + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 0); + if (retval < 0) { + TPD_INFO("Failed to switch to normal\n"); + } + + return; +} + +static void syna_baseline_read(struct seq_file *s, void *chip_data) +{ + int retval; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 1); + if (retval < 0) { + TPD_INFO("Failed to exit doze\n"); + } + + msleep(20); // delay 20ms + + retval = syna_tcm_collect_reports(tcm_info, REPORT_RAW, 1); + if (retval < 0) { + seq_printf(s, "Failed to read baseline data\n"); + return; + } + + syna_tcm_format_unsigned_print(s, tcm_info, NULL); + + /*set normal doze*/ + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 0); + if (retval < 0) { + TPD_INFO("Failed to switch to normal\n"); + } + + return; +} + +static void syna_tcm_drt_read(struct seq_file *s, void *chip_data) +{ + int retval; + unsigned char out[2] = {0}; + unsigned char *resp_buf; + unsigned int resp_buf_size = 0; + unsigned int resp_length = 0; + unsigned int frame_size; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + resp_buf = NULL; + resp_buf_size = 0; + + if (tcm_info->id_info.mode != MODE_APPLICATION || tcm_info->app_status != APP_STATUS_OK) { + seq_printf(s, "Not in app mode\n"); + return; + } + + out[0] = TEST_DYNAMIC_RANGE; + + retval = syna_tcm_write_message(tcm_info, + CMD_PRODUCTION_TEST, + out, + 1, + &resp_buf, + &resp_buf_size, + &resp_length, + 0); + if (retval < 0) { + seq_printf(s, "Failed to write %s\n", STR(CMD_PRODUCTION_TEST)); + goto exit; + } + + frame_size = syna_tcm_get_frame_size_words(tcm_info, false); + if (frame_size != resp_buf_size / 2) { + seq_printf(s, "Size not match\n"); + goto exit; + } + + syna_tcm_format_print(s, tcm_info, resp_buf); + +exit: + kfree(resp_buf); + return; +} + +static struct synaptics_proc_operations syna_proc_ops = { + .auto_test = syna_auto_test, +}; + +void syna_reserve_read(struct seq_file *s, void *chip_data) +{ + int retval; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 1); + if (retval < 0) { + TPD_INFO("Failed to exit doze\n"); + } + + msleep(20); // delay 20ms + + retval = syna_tcm_collect_reports(tcm_info, REPORT_DEBUG, 1); + if (retval < 0) { + seq_printf(s, "Failed to read delta data\n"); + return; + } + + syna_tcm_format_unsigned_print(s, tcm_info, NULL); + + /*set normal doze*/ + retval = syna_tcm_set_dynamic_config(tcm_info, DC_NO_DOZE, 0); + if (retval < 0) { + TPD_INFO("Failed to switch to normal\n"); + } + + return; +} + +static struct debug_info_proc_operations syna_debug_proc_ops = { + .delta_read = syna_delta_read, + .baseline_read = syna_baseline_read, + .main_register_read = syna_main_register, + .DRT = syna_tcm_drt_read, + .limit_read = synaptics_limit_read, + .reserve_read = syna_reserve_read, +}; + +static int syna_device_report_touch(struct syna_tcm_data *tcm_info) +{ + int ret = syna_parse_report(tcm_info); + if (ret < 0) { + TPD_INFO("Failed to parse report\n"); + return -EINVAL; + } + + syna_set_trigger_reason(tcm_info, IRQ_TOUCH); + return 0; +} + +static int syna_tcm_irq_handle(void *chip_data) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + + return syna_tcm_read_message(tcm_info, NULL, 0); +} + +static void syna_set_touch_direction(void *chip_data, uint8_t dir) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + tcm_info->touch_direction = dir; +} + +static uint8_t syna_get_touch_direction(void *chip_data) +{ + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + + return tcm_info->touch_direction; +} + +void syna_freq_hop_trigger(void *chip_data) +{ + static int freq_point = 0; + int retval = 0; + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)chip_data; + TPD_INFO("%s : send cmd to tigger frequency hopping here!!!\n", __func__); + + switch (freq_point) { + case 0: + TPD_INFO("%s : Hop to frequency : %d\n", __func__, freq_point); + retval = syna_tcm_set_dynamic_config(tcm_info, DC_FREQUENCE_HOPPING, freq_point); + if (retval < 0) { + TPD_INFO("Failed to hop frequency\n"); + } + freq_point = 4; + break; + + case 4: + TPD_INFO("%s : Hop to frequency : %d\n", __func__, freq_point); + retval = syna_tcm_set_dynamic_config(tcm_info, DC_FREQUENCE_HOPPING, freq_point); + if (retval < 0) { + TPD_INFO("Failed to hop frequency\n"); + } + freq_point = 5; + break; + + case 5: + TPD_INFO("%s : Hop to frequency : %d\n", __func__, freq_point); + retval = syna_tcm_set_dynamic_config(tcm_info, DC_FREQUENCE_HOPPING, freq_point); + if (retval < 0) { + TPD_INFO("Failed to hop frequency\n"); + } + freq_point = 0; + break; + + default: + break; + } +} +static struct touchpanel_operations syna_tcm_ops = { + //.ftm_process = syna_ftm_process, + .get_vendor = syna_get_vendor, + .get_chip_info = syna_get_chip_info, + .get_touch_points = syna_get_touch_points, + .get_gesture_info = syna_get_gesture_info, + .power_control = syna_power_control, + .reset = syna_tcm_reset, + .u32_trigger_reason = syna_trigger_reason, + .mode_switch = syna_mode_switch, + .irq_handle_unlock = syna_tcm_irq_handle, + .fw_check = syna_fw_check, + .fw_update = syna_tcm_fw_update, + .async_work = syna_tcm_async_work, + .reinit_device = syna_tcm_reinit_device, + .enable_fingerprint = syna_tcm_enable_fingerprint, + .screenon_fingerprint_info = syna_tcm_fingerprint_info, + .health_report = syna_tcm_get_health_info, + .set_touch_direction = syna_set_touch_direction, + .get_touch_direction = syna_get_touch_direction, + .freq_hop_trigger = syna_freq_hop_trigger, + //.enable_gesture_mask = syna_tcm_enable_gesture_mask, +}; + +static int syna_tcm_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int retval = 0; + struct syna_tcm_data *tcm_info = NULL; + struct touchpanel_data *ts = NULL; + struct device_hcd *device_hcd = NULL; + + TPD_INFO("%s: enter\n", __func__); + + if (tp_register_times > 0) { + TPD_INFO("TP driver have success loaded %d times, exit\n", tp_register_times); + return -1; + } + + //1. alloc mem for tcm_data + tcm_info = kzalloc(sizeof(*tcm_info), GFP_KERNEL); + if (!tcm_info) { + TPD_INFO("no more memory\n"); + return -ENOMEM; + } + + //2. alloc mem for touchpanel_data + ts = common_touch_data_alloc(); + if (ts == NULL) { + TPD_INFO("failed to alloc common data\n"); + goto ts_alloc_failed; + } + + //3. init member of ts + ts->dev = &client->dev; + ts->client = client; + ts->irq = client->irq; + ts->chip_data = tcm_info; + ts->has_callback = true; + ts->use_resume_notify = true; + i2c_set_clientdata(client, ts); + ts->ts_ops = &syna_tcm_ops; + ts->debug_info_ops = &syna_debug_proc_ops; + + //4. init member of tcm_info + tcm_info->client = client; + tcm_info->hw_res = &ts->hw_res; + tcm_info->ubl_addr = 0x2c; + tcm_info->rd_chunk_size = RD_CHUNK_SIZE; + tcm_info->wr_chunk_size = WR_CHUNK_SIZE; + tcm_info->read_length = MIN_READ_LENGTH; + tcm_info->in_suspend = &ts->is_suspended; + tcm_info->syna_ops = &syna_proc_ops; + tcm_info->display_refresh_rate = 90; + tcm_info->game_mode = false; + atomic_set(&tcm_info->command_status, CMD_IDLE); + + mutex_init(&tcm_info->reset_mutex); + mutex_init(&tcm_info->rw_mutex); + mutex_init(&tcm_info->command_mutex); + mutex_init(&tcm_info->identify_mutex); + + INIT_BUFFER(tcm_info->in, false); + INIT_BUFFER(tcm_info->out, false); + INIT_BUFFER(tcm_info->resp, true); + INIT_BUFFER(tcm_info->temp, false); + INIT_BUFFER(tcm_info->config, false); + INIT_BUFFER(tcm_info->default_config, false); + INIT_BUFFER(tcm_info->report.buffer, true); + + //5. alloc mem for reading in buffer + LOCK_BUFFER(tcm_info->in); + retval = syna_tcm_alloc_mem(&tcm_info->in, MAX_READ_LENGTH); + TPD_INFO("%s read_length:%d\n", __func__, tcm_info->read_length); + if (retval < 0) { + TPD_INFO("Failed to allocate memory for tcm_info->in.buf\n"); + goto err_malloc_inbuffer; + } + UNLOCK_BUFFER(tcm_info->in); + + //6. create workqueue and init helper work + tcm_info->helper_workqueue = create_singlethread_workqueue("syna_tcm_helper"); + INIT_WORK(&tcm_info->helper_work, syna_tcm_helper_work); + + //7. alloc mem for touch_hcd and init it's member + tcm_info->touch_hcd = (struct touch_hcd *)kzalloc(sizeof(struct touch_hcd), GFP_KERNEL); + if (!tcm_info->touch_hcd) { + retval = -ENOMEM; + goto err_malloc_touchhcd; + } + INIT_BUFFER(tcm_info->touch_hcd->out, false); + INIT_BUFFER(tcm_info->touch_hcd->resp, false); + mutex_init(&tcm_info->touch_hcd->report_mutex); + of_property_read_u32(ts->dev->of_node, "touchpanel,max-num-support", &tcm_info->touch_hcd->max_objects); + TPD_INFO("max-num support is %d\n", tcm_info->touch_hcd->max_objects); + tcm_info->touch_hcd->touch_data.object_data = + (struct object_data *)kzalloc(sizeof(struct object_data) * tcm_info->touch_hcd->max_objects, GFP_KERNEL); + if (!tcm_info->touch_hcd->touch_data.object_data) { + retval = -ENOMEM; + goto err_malloc_objdata; + } + + //8. alloc mem for test_hcd and it's member + tcm_info->test_hcd = (struct syna_tcm_test *)kzalloc(sizeof(struct syna_tcm_test), GFP_KERNEL); + if (!tcm_info->test_hcd) { + retval = -ENOMEM; + goto err_malloc_testhcd; + } + + INIT_BUFFER(tcm_info->test_hcd->report, false); + INIT_BUFFER(tcm_info->test_hcd->test_resp, false); + INIT_BUFFER(tcm_info->test_hcd->test_out, false); + + //9. register common part of touchpanel driver + retval = register_common_touch_device(ts); + if (retval < 0 && (retval != -EFTM)) { + TPD_INFO("Failed to init device information\n"); + goto err_register_driver; + } + ts->mode_switch_type = SINGLE; + + //10. create synaptics common file + synaptics_create_proc(ts, tcm_info->syna_ops); + + //11. create remote device file and init it's callback + device_hcd = syna_remote_device_init(tcm_info); + if (device_hcd) { + device_hcd->irq = tcm_info->client->irq; + device_hcd->read_message = syna_tcm_read_message; + device_hcd->write_message = syna_tcm_write_message; + device_hcd->reset = syna_tcm_reset; + device_hcd->report_touch = syna_device_report_touch; + } + g_tcm_info = tcm_info; + + return 0; + +err_register_driver: + if (tcm_info->test_hcd) { + kfree(tcm_info->test_hcd); + tcm_info->test_hcd = NULL; + } +err_malloc_testhcd: + if (tcm_info->touch_hcd->touch_data.object_data) { + kfree(tcm_info->touch_hcd->touch_data.object_data); + tcm_info->touch_hcd->touch_data.object_data = NULL; + } +err_malloc_objdata: + if (tcm_info->touch_hcd) { + kfree(tcm_info->touch_hcd); + tcm_info->touch_hcd = NULL; + } +err_malloc_touchhcd: + RELEASE_BUFFER(tcm_info->in); +err_malloc_inbuffer: + common_touch_data_free(ts); + ts = NULL; + +ts_alloc_failed: + if (tcm_info) { + kfree(tcm_info); + tcm_info = NULL; + } + + return retval; +} + +static int syna_tcm_remove(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)ts->chip_data; + + RELEASE_BUFFER(tcm_info->report.buffer); + RELEASE_BUFFER(tcm_info->config); + RELEASE_BUFFER(tcm_info->temp); + RELEASE_BUFFER(tcm_info->resp); + RELEASE_BUFFER(tcm_info->out); + RELEASE_BUFFER(tcm_info->in); + + kfree(tcm_info); + kfree(ts); + + return 0; +} + +static void syna_tp_shutdown(struct i2c_client *client) +{ + struct touchpanel_data *ts = i2c_get_clientdata(client); + struct syna_tcm_data *tcm_info = (struct syna_tcm_data *)ts->chip_data; + int ret = 0; + + TPD_INFO("%s is called\n", __func__); + synaptics_resetgpio_set(tcm_info->hw_res, false); + + if (!ts->ts_ops->power_control) { + ret = -EINVAL; + TPD_INFO("tp power_control NULL!\n"); + return; + } + ret = ts->ts_ops->power_control(ts->chip_data, false); +} + +static int syna_i2c_suspend(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s: is called\n", __func__); + tp_i2c_suspend(ts); + return 0; +} + +static int syna_i2c_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s is called\n", __func__); + tp_i2c_resume(ts); + return 0; +} + +static const struct dev_pm_ops syna_pm_ops = { + .suspend = syna_i2c_suspend, + .resume = syna_i2c_resume, +}; + +static const struct i2c_device_id syna_tmc_id[] = { + { TPD_DEVICE, 0 }, + { } +}; + +static struct of_device_id syna_match_table[] = { + { .compatible = "synaptics-s3908",}, + { } +}; + +static struct i2c_driver syna_i2c_driver = { + .probe = syna_tcm_probe, + .remove = syna_tcm_remove, + .shutdown = syna_tp_shutdown, + .id_table = syna_tmc_id, + .driver = { + .name = TPD_DEVICE, + .of_match_table = syna_match_table, + .pm = &syna_pm_ops, + }, +}; + + +static int __init syna_tcm_module_init(void) +{ + TPD_INFO("%s is called\n", __func__); + + if (i2c_add_driver(&syna_i2c_driver) != 0) { + TPD_INFO("unable to add i2c driver.\n"); + return -1; + } + + return 0; +} + +static void __exit syna_tcm_module_exit(void) +{ + i2c_del_driver(&syna_i2c_driver); + return; +} + +late_initcall(syna_tcm_module_init); +module_exit(syna_tcm_module_exit); + +MODULE_AUTHOR("Synaptics, Inc."); +MODULE_DESCRIPTION("Synaptics TCM Touch Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_oncell.h b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_oncell.h new file mode 100755 index 0000000000000000000000000000000000000000..855633721db876cf86ff036b1245458bd7bb4691 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_oncell.h @@ -0,0 +1,618 @@ + +#ifndef _SYNAPTICS_TCM_CORE_H_ +#define _SYNAPTICS_TCM_CORE_H_ + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FB +#include +#include +#endif + +#include "../../touchpanel_common.h" +#include "../synaptics_common.h" + + +#define TPD_DEVICE "syna-tcm" + +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (LEVEL_DEBUG == tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do{\ + if (LEVEL_BASIC != tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DEBUG_NTAG(a, arg...)\ + do{\ + if (tp_debug)\ + printk(a, ##arg);\ + }while(0) + + +#define SYNAPTICS_TCM_ID_PRODUCT (1 << 0) +#define SYNAPTICS_TCM_ID_VERSION 0x0007 + +#define RD_CHUNK_SIZE 0 /* read length limit in bytes, 0 = unlimited */ +#define WR_CHUNK_SIZE 0 /* write length limit in bytes, 0 = unlimited */ + +#define MESSAGE_HEADER_SIZE 4 +#define MESSAGE_MARKER 0xA5 +#define MESSAGE_PADDING 0x5A + +#define REPORT_TIMEOUT_MS 1000 +#define POWEWRUP_TO_RESET_TIME 10 +#define RESET_TO_NORMAL_TIME 80 + +#define MAX_READ_LENGTH 64*1024 + +#define INIT_BUFFER(buffer, is_clone) \ + mutex_init(&buffer.buf_mutex); \ +buffer.clone = is_clone + +#define LOCK_BUFFER(buffer) \ + mutex_lock(&buffer.buf_mutex) + +#define UNLOCK_BUFFER(buffer) \ + mutex_unlock(&buffer.buf_mutex) + +#define RELEASE_BUFFER(buffer) \ + do { \ + if (buffer.clone == false) { \ + kfree(buffer.buf); \ + buffer.buf_size = 0; \ + buffer.data_length = 0; \ + } \ + } while (0) + +#define MAX(a, b) \ + ({__typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; }) + +#define MIN(a, b) \ + ({__typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a < _b ? _a : _b; }) + +#define STR(x) #x + +#define CONCAT(a, b) a##b + +#define TOUCH_REPORT_CONFIG_SIZE 128 + +#define DTAP_DETECT 0x01 +#define SWIPE_DETECT 0x02 +#define TRIANGLE_DETECT 0x03 +#define CIRCLE_DETECT 0x04 +#define VEE_DETECT 0x05 +#define UNICODE_DETECT 0x08 +#define M_UNICODE 0x6d +#define W_UNICODE 0x77 +#define S_UNICODE 0x73 +#define STAP_DETECT 0x10 + +#define TOUCH_HOLD_DOWN 0x80 +#define TOUCH_HOLD_UP 0x81 + + +enum test_code { + TEST_TRX_TRX_SHORTS = 0, + TEST_TRX_SENSOR_OPENS = 1, + TEST_TRX_GROUND_SHORTS = 2, + TEST_DYNAMIC_RANGE = 7, + TEST_OPEN_SHORT_DETECTOR = 8, + TEST_NOISE = 10, + TEST_PT11 = 11, + TEST_PT12 = 12, + TEST_PT13 = 13, + TEST_DYNAMIC_RANGE_DOZE = 14, + TEST_NOISE_DOZE = 15, +}; + +enum touch_status { + LIFT = 0, + FINGER = 1, + GLOVED_FINGER = 2, + NOP = -1, +}; + +enum touch_report_code { + TOUCH_END = 0, + TOUCH_FOREACH_ACTIVE_OBJECT, + TOUCH_FOREACH_OBJECT, + TOUCH_FOREACH_END, + TOUCH_PAD_TO_NEXT_BYTE, + TOUCH_TIMESTAMP, + TOUCH_OBJECT_N_INDEX, + TOUCH_OBJECT_N_CLASSIFICATION, + TOUCH_OBJECT_N_X_POSITION, + TOUCH_OBJECT_N_Y_POSITION, + TOUCH_OBJECT_N_Z, + TOUCH_OBJECT_N_X_WIDTH, + TOUCH_OBJECT_N_Y_WIDTH, + TOUCH_OBJECT_N_TX_POSITION_TIXELS, + TOUCH_OBJECT_N_RX_POSITION_TIXELS, + TOUCH_0D_BUTTONS_STATE, + TOUCH_GESTURE_DOUBLE_TAP, + TOUCH_FRAME_RATE, + TOUCH_POWER_IM, + TOUCH_CID_IM, + TOUCH_RAIL_IM, + TOUCH_CID_VARIANCE_IM, + TOUCH_NSM_FREQUENCY, + TOUCH_NSM_STATE, + TOUCH_NUM_OF_ACTIVE_OBJECTS, + TOUCH_NUM_OF_CPU_CYCLES_USED_SINCE_LAST_FRAME, + TOUCH_TUNING_GAUSSIAN_WIDTHS = 0x80, + TOUCH_TUNING_SMALL_OBJECT_PARAMS, + TOUCH_TUNING_0D_BUTTONS_VARIANCE, + TOUCH_REPORT_GESTURE_SWIPE = 193, + TOUCH_REPORT_GESTURE_CIRCLE = 194, + TOUCH_REPORT_GESTURE_UNICODE = 195, + TOUCH_REPORT_GESTURE_VEE = 196, + TOUCH_REPORT_GESTURE_TRIANGLE = 197, + TOUCH_REPORT_GESTURE_INFO = 198, + TOUCH_REPORT_GESTURE_COORDINATE = 199, +}; + +enum module_type { + TCM_TOUCH = 0, + TCM_DEVICE = 1, + TCM_TESTING = 2, + TCM_REFLASH = 3, + TCM_RECOVERY = 4, + TCM_ZEROFLASH = 5, + TCM_DIAGNOSTICS = 6, + TCM_LAST, +}; + +enum boot_mode { + MODE_APPLICATION = 0x01, + MODE_HOST_DOWNLOAD = 0x02, + MODE_BOOTLOADER = 0x0b, + MODE_TDDI_BOOTLOADER = 0x0c, +}; + +enum boot_status { + BOOT_STATUS_OK = 0x00, + BOOT_STATUS_BOOTING = 0x01, + BOOT_STATUS_APP_BAD_DISPLAY_CRC = 0xfc, + BOOT_STATUS_BAD_DISPLAY_CONFIG = 0xfd, + BOOT_STATUS_BAD_APP_FIRMWARE = 0xfe, + BOOT_STATUS_WARM_BOOT = 0xff, +}; + +enum app_status { + APP_STATUS_OK = 0x00, + APP_STATUS_BOOTING = 0x01, + APP_STATUS_UPDATING = 0x02, + APP_STATUS_BAD_APP_CONFIG = 0xff, +}; + +enum firmware_mode { + FW_MODE_BOOTLOADER = 0, + FW_MODE_APPLICATION = 1, +}; + +enum dynamic_config_id { + DC_UNKNOWN = 0x00, + DC_NO_DOZE, + DC_DISABLE_NOISE_MITIGATION, + DC_INHIBIT_FREQUENCY_SHIFT, + DC_REQUESTED_FREQUENCY, + DC_DISABLE_HSYNC, + DC_REZERO_ON_EXIT_DEEP_SLEEP, + DC_CHARGER_CONNECTED, + DC_NO_BASELINE_RELAXATION, + DC_IN_WAKEUP_GESTURE_MODE, + DC_STIMULUS_FINGERS, + DC_GRIP_SUPPRESSION_ENABLED, + DC_ENABLE_THICK_GLOVE, + DC_ENABLE_GLOVE, + DC_PS_STATUS = 0xC1, + DC_DISABLE_ESD = 0xC2, + DC_FREQUENCE_HOPPING = 0xD2, + DC_TOUCH_HOLD = 0xD4, + DC_ERROR_PRIORITY = 0xD5, + DC_NOISE_LENGTH = 0xD6, + DC_GRIP_ROATE_TO_HORIZONTAL_LEVEL = 0xDC, + DC_DARK_ZONE_ENABLE = 0xDD, + DC_GRIP_ENABLED = 0xDE, + DC_GRIP_DARK_ZONE_X = 0xDF, + DC_GRIP_DARK_ZONE_Y = 0xE0, + DC_GRIP_ABS_DARK_X = 0xE1, + DC_GRIP_ABS_DARK_Y = 0xE2, + DC_GRIP_ABS_DARK_U = 0xE3, + DC_GRIP_ABS_DARK_V = 0xE4, + DC_GRIP_ABS_DARK_SEL = 0xE5, + DC_SET_REPORT_FRE = 0xE6, + DC_GESTURE_MASK = 0xFE, +}; + +enum command { + CMD_NONE = 0x00, + CMD_CONTINUE_WRITE = 0x01, + CMD_IDENTIFY = 0x02, + CMD_RESET = 0x04, + CMD_ENABLE_REPORT = 0x05, + CMD_DISABLE_REPORT = 0x06, + CMD_GET_BOOT_INFO = 0x10, + CMD_ERASE_FLASH = 0x11, + CMD_WRITE_FLASH = 0x12, + CMD_READ_FLASH = 0x13, + CMD_RUN_APPLICATION_FIRMWARE = 0x14, + CMD_SPI_MASTER_WRITE_THEN_READ = 0x15, + CMD_REBOOT_TO_ROM_BOOTLOADER = 0x16, + CMD_RUN_BOOTLOADER_FIRMWARE = 0x1f, + CMD_GET_APPLICATION_INFO = 0x20, + CMD_GET_STATIC_CONFIG = 0x21, + CMD_SET_STATIC_CONFIG = 0x22, + CMD_GET_DYNAMIC_CONFIG = 0x23, + CMD_SET_DYNAMIC_CONFIG = 0x24, + CMD_GET_TOUCH_REPORT_CONFIG = 0x25, + CMD_SET_TOUCH_REPORT_CONFIG = 0x26, + CMD_REZERO = 0x27, + CMD_COMMIT_CONFIG = 0x28, + CMD_DESCRIBE_DYNAMIC_CONFIG = 0x29, + CMD_PRODUCTION_TEST = 0x2a, + CMD_SET_CONFIG_ID = 0x2b, + CMD_ENTER_DEEP_SLEEP = 0x2c, + CMD_EXIT_DEEP_SLEEP = 0x2d, + CMD_GET_TOUCH_INFO = 0x2e, + CMD_GET_DATA_LOCATION = 0x2f, + CMD_DOWNLOAD_CONFIG = 0xc0, + CMD_GET_NSM_INFO = 0xc3, + CMD_EXIT_ESD = 0xc4, +}; + +enum status_code { + STATUS_IDLE = 0x00, + STATUS_OK = 0x01, + STATUS_BUSY = 0x02, + STATUS_CONTINUED_READ = 0x03, + STATUS_RECEIVE_BUFFER_OVERFLOW = 0x0c, + STATUS_PREVIOUS_COMMAND_PENDING = 0x0d, + STATUS_NOT_IMPLEMENTED = 0x0e, + STATUS_ERROR = 0x0f, + STATUS_INVALID = 0xff, +}; + +enum report_type { + REPORT_IDENTIFY = 0x10, + REPORT_TOUCH = 0x11, + REPORT_DELTA = 0x12, + REPORT_RAW = 0x13, + REPORT_PRINTF = 0x82, + REPORT_STATUS = 0xc0, + REPORT_DEBUG = 0x14, + REPORT_HDL = 0xfe, + REPORT_LOG = 0x1d, + REPORT_TOUCH_HOLD = 0x20, +}; + +enum command_status { + CMD_IDLE = 0, + CMD_BUSY = 1, + CMD_ERROR = -1, +}; + +enum flash_area { + BOOTLOADER = 0, + BOOT_CONFIG, + APP_FIRMWARE, + APP_CONFIG, + DISP_CONFIG, + CUSTOM_OTP, + CUSTOM_LCM, + CUSTOM_OEM, + PPDT, +}; + +enum flash_data { + LCM_DATA = 1, + OEM_DATA, + PPDT_DATA, +}; + +struct syna_tcm_buffer { + bool clone; + unsigned char *buf; + unsigned int buf_size; + unsigned int data_length; + struct mutex buf_mutex; +}; + +struct syna_tcm_report { + unsigned char id; + struct syna_tcm_buffer buffer; +}; + +struct syna_tcm_identification { + unsigned char version; + unsigned char mode; + unsigned char part_number[16]; + unsigned char build_id[4]; + unsigned char max_write_size[2]; +}; + +struct syna_tcm_boot_info { + unsigned char version; + unsigned char status; + unsigned char asic_id[2]; + unsigned char write_block_size_words; + unsigned char erase_page_size_words[2]; + unsigned char max_write_payload_size[2]; + unsigned char last_reset_reason; + unsigned char pc_at_time_of_last_reset[2]; + unsigned char boot_config_start_block[2]; + unsigned char boot_config_size_blocks[2]; + unsigned char display_config_start_block[4]; + unsigned char display_config_length_blocks[2]; + unsigned char backup_display_config_start_block[4]; + unsigned char backup_display_config_length_blocks[2]; + unsigned char custom_otp_start_block[2]; + unsigned char custom_otp_length_blocks[2]; +}; + +struct syna_tcm_app_info { + unsigned char version[2]; + unsigned char status[2]; + unsigned char static_config_size[2]; + unsigned char dynamic_config_size[2]; + unsigned char app_config_start_write_block[2]; + unsigned char app_config_size[2]; + unsigned char max_touch_report_config_size[2]; + unsigned char max_touch_report_payload_size[2]; + unsigned char customer_config_id[16]; + unsigned char max_x[2]; + unsigned char max_y[2]; + unsigned char max_objects[2]; + unsigned char num_of_buttons[2]; + unsigned char num_of_image_rows[2]; + unsigned char num_of_image_cols[2]; + unsigned char has_hybrid_data[2]; +}; + +struct syna_tcm_touch_info { + unsigned char image_2d_scale_factor[4]; + unsigned char image_0d_scale_factor[4]; + unsigned char hybrid_x_scale_factor[4]; + unsigned char hybrid_y_scale_factor[4]; +}; + +struct syna_tcm_message_header { + unsigned char marker; + unsigned char code; + unsigned char length[2]; +}; + +struct input_params { + unsigned int max_x; + unsigned int max_y; + unsigned int max_objects; +}; + +struct object_data { + unsigned char status; + unsigned int x_pos; + unsigned int y_pos; + unsigned int x_width; + unsigned int y_width; + unsigned int z; + unsigned int tx_pos; + unsigned int rx_pos; +}; + +struct touch_data { + struct object_data *object_data; + unsigned char data_point[24]; //6 points + unsigned char extra_gesture_info[6]; + unsigned int timestamp; + unsigned int buttons_state; + unsigned int gesture_double_tap; + unsigned int lpwg_gesture; + unsigned int frame_rate; + unsigned int power_im; + unsigned int cid_im; + unsigned int rail_im; + unsigned int cid_variance_im; + unsigned int nsm_frequency; + unsigned int nsm_state; + unsigned int num_of_active_objects; + unsigned int num_of_cpu_cycles; +}; + +struct touch_hcd { + bool report_touch; + unsigned int max_objects; + struct mutex report_mutex; + struct touch_data touch_data; + struct syna_tcm_buffer out; + struct syna_tcm_buffer resp; +}; + +struct reflash_hcd { + bool disp_cfg_update; + unsigned int image_size; + unsigned int page_size; + unsigned int write_block_size; + unsigned int max_write_payload_size; +}; + +struct syna_tcm_test { + unsigned int num_of_reports; + unsigned char report_type; + unsigned int report_index; + struct syna_tcm_buffer report; + struct syna_tcm_buffer test_resp; + struct syna_tcm_buffer test_out; +}; + +struct syna_tcm_data { + /*must be first*/ + struct invoke_method cb; + struct i2c_client *client; + struct hw_resource *hw_res; + struct touch_hcd *touch_hcd; + struct syna_tcm_test *test_hcd; + struct synaptics_proc_operations *syna_ops; + struct health_info health_info; + + struct workqueue_struct *helper_workqueue; + struct work_struct helper_work; + + atomic_t command_status; + char *iHex_name; + int *in_suspend; + u16 default_noise_length; + uint8_t touch_direction; + int display_refresh_rate; + bool game_mode; + + unsigned short ubl_addr; + u32 trigger_reason; + unsigned char command; + unsigned char report_code; + unsigned int read_length; + unsigned int payload_length; + unsigned int rd_chunk_size; + unsigned int wr_chunk_size; + unsigned int app_status; + + struct mutex reset_mutex; + struct mutex rw_mutex; + struct mutex command_mutex; + struct mutex identify_mutex; + + struct syna_tcm_buffer in; + struct syna_tcm_buffer out; + struct syna_tcm_buffer resp; + struct syna_tcm_buffer temp; + struct syna_tcm_buffer config; + struct syna_tcm_buffer default_config; + struct syna_tcm_report report; + struct syna_tcm_app_info app_info; + struct syna_tcm_boot_info boot_info; + struct syna_tcm_touch_info touch_info; + struct syna_tcm_identification id_info; +}; + +struct device_hcd { + dev_t dev_num; + bool raw_mode; + bool concurrent; + unsigned int ref_count; + int irq; + int flag; + struct cdev char_dev; + struct class *class; + struct device *device; + struct mutex extif_mutex; + struct syna_tcm_buffer out; + struct syna_tcm_buffer resp; + struct syna_tcm_buffer report; + struct syna_tcm_data *tcm_info; + int (*reset)(void *chip_data); + int (*write_message)(struct syna_tcm_data *tcm_info, + unsigned char command, unsigned char *payload, + unsigned int length, unsigned char **resp_buf, + unsigned int *resp_buf_size, unsigned int *resp_length, + unsigned int polling_delay_ms); + int (*read_message)(struct syna_tcm_data *tcm_info, unsigned char *in_buf, unsigned int length); + int (*report_touch) (struct syna_tcm_data *tcm_info); +}; + +static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size, + const unsigned char *src, unsigned int src_size, + unsigned int count) +{ + if (dest == NULL || src == NULL) + return -EINVAL; + + if (count > dest_size || count > src_size) { + pr_err("%s: src_size = %d, dest_size = %d, count = %d\n", + __func__, src_size, dest_size, count); + return -EINVAL; + } + + memcpy((void *)dest, (const void *)src, count); + + return 0; +} + +static inline int syna_tcm_realloc_mem(struct syna_tcm_buffer *buffer, unsigned int size) +{ + int retval; + unsigned char *temp; + + if (size > buffer->buf_size) { + temp = buffer->buf; + + buffer->buf = kmalloc(size, GFP_KERNEL); + if (!(buffer->buf)) { + TPD_INFO("%s: Failed to allocate memory\n", __func__); + buffer->buf = temp; + //kfree(temp); + //buffer->buf_size = 0; + return -ENOMEM; + } + + retval = secure_memcpy(buffer->buf, size, temp, buffer->buf_size, buffer->buf_size); + if (retval < 0) { + TPD_INFO("%s: Failed to copy data\n", __func__); + kfree(temp); + //kfree(buffer->buf); + buffer->buf_size = size; + return retval; + } + + kfree(temp); + buffer->buf_size = size; + } + + return 0; +} + +static inline int syna_tcm_alloc_mem(struct syna_tcm_buffer *buffer, unsigned int size) +{ + if (size > buffer->buf_size) { + kfree(buffer->buf); + buffer->buf = kmalloc(size, GFP_KERNEL); + if (!(buffer->buf)) { + TPD_INFO("%s: Failed to allocate memory, size %d\n", __func__, size); + buffer->buf_size = 0; + buffer->data_length = 0; + return -ENOMEM; + } + buffer->buf_size = size; + } + + memset(buffer->buf, 0, buffer->buf_size); + buffer->data_length = 0; + + return 0; +} + + +static inline unsigned int ceil_div(unsigned int dividend, unsigned divisor) +{ + return (dividend + divisor - 1) / divisor; +} + +int syna_tcm_rmi_read(struct syna_tcm_data *tcm_info, + unsigned short addr, unsigned char *data, unsigned int length); + +int syna_tcm_rmi_write(struct syna_tcm_data *tcm_info, + unsigned short addr, unsigned char *data, unsigned int length); + +#endif diff --git a/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_recovery.c b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_recovery.c new file mode 100755 index 0000000000000000000000000000000000000000..2c00b01e80af8d42d98ebf983b3ba2415c940673 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/syna_tcm_oncell/synaptics_tcm_recovery.c @@ -0,0 +1,555 @@ + +#include "synaptics_tcm_oncell.h" + +#define SET_UP_RECOVERY_MODE true +#define ENABLE_SYSFS_INTERFACE true + +#define IHEX_BUF_SIZE (1024 * 1024) +#define DATA_BUF_SIZE (512 * 1024) +#define IHEX_RECORD_SIZE 14 +#define PDT_START_ADDR 0x00e9 +#define UBL_FN_NUMBER 0x35 +#define F35_CHUNK_SIZE 16 +#define F35_CHUNK_SIZE_WORDS 8 +#define F35_ERASE_ALL_WAIT_MS 5000 +#define F35_ERASE_ALL_POLL_MS 100 +#define F35_DATA5_OFFSET 5 +#define F35_CTRL3_OFFSET 18 +#define F35_RESET_COMMAND 16 +#define F35_ERASE_ALL_COMMAND 3 +#define F35_WRITE_CHUNK_COMMAND 2 +#define F35_READ_FLASH_STATUS_COMMAND 1 + +struct rmi_pdt_entry { + unsigned char query_base_addr; + unsigned char command_base_addr; + unsigned char control_base_addr; + unsigned char data_base_addr; + unsigned char intr_src_count: 3; + unsigned char reserved_1: 2; + unsigned char fn_version: 2; + unsigned char reserved_2: 1; + unsigned char fn_number; +} __packed; + +struct rmi_addr { + unsigned short query_base; + unsigned short command_base; + unsigned short control_base; + unsigned short data_base; +}; + +struct recovery_hcd { + unsigned char chunk_buf[F35_CHUNK_SIZE + 3]; + unsigned char out_buf[3]; + unsigned char *ihex_buf; + unsigned char *data_buf; + unsigned int ihex_size; + unsigned int ihex_records; + unsigned int data_entries; + struct rmi_addr f35_addr; + struct syna_tcm_data *tcm_info; + const struct firmware *fw_entry; +}; + +static int recovery_device_reset(struct recovery_hcd *recovery_hcd) +{ + int retval; + unsigned char command = F35_RESET_COMMAND; + + retval = syna_tcm_rmi_write(recovery_hcd->tcm_info, + recovery_hcd->f35_addr.control_base + F35_CTRL3_OFFSET, + &command, + sizeof(command)); + if (retval < 0) { + TPD_INFO("Failed to write F$35 command\n"); + return retval; + } + + msleep(200); + + return 0; +} + +static int recovery_add_data_entry(struct recovery_hcd *recovery_hcd, unsigned char data) +{ + if (recovery_hcd->data_entries >= DATA_BUF_SIZE) { + TPD_INFO("Reached data buffer size limit\n"); + return -EINVAL; + } + + recovery_hcd->data_buf[recovery_hcd->data_entries++] = data; + + return 0; +} + +static int recovery_add_padding(struct recovery_hcd *recovery_hcd, unsigned int *words) +{ + int retval; + unsigned int padding; + + padding = (F35_CHUNK_SIZE_WORDS - *words % F35_CHUNK_SIZE_WORDS); + padding %= F35_CHUNK_SIZE_WORDS; + + while (padding) { + retval = recovery_add_data_entry(recovery_hcd, 0xff); + if (retval < 0) { + TPD_INFO("Failed to add data entry\n"); + return retval; + } + + retval = recovery_add_data_entry(recovery_hcd, 0xff); + if (retval < 0) { + TPD_INFO("Failed to add data entry\n"); + return retval; + } + + (*words)++; + padding--; + } + + return 0; +} + +static int recovery_parse_ihex(struct recovery_hcd *recovery_hcd) +{ + int retval; + unsigned char colon; + unsigned char *buf; + unsigned int addr; + unsigned int type; + unsigned int addrl; + unsigned int addrh; + unsigned int data0; + unsigned int data1; + unsigned int count; + unsigned int words; + unsigned int offset; + unsigned int record; + + words = 0; + offset = 0; + buf = recovery_hcd->ihex_buf; + recovery_hcd->data_entries = 0; + + for (record = 0; record < recovery_hcd->ihex_records; record++) { + buf[(record + 1) * IHEX_RECORD_SIZE - 1] = 0x00; + retval = sscanf(&buf[record * IHEX_RECORD_SIZE], + "%c%02x%02x%02x%02x%02x%02x", + &colon, + &count, + &addrh, + &addrl, + &type, + &data0, + &data1); + if (retval != 7) { + TPD_INFO("Failed to read ihex record\n"); + return -EINVAL; + } + + if (type == 0x00) { + if ((words % F35_CHUNK_SIZE_WORDS) == 0) { + addr = (addrh << 8) + addrl; + addr += offset; + addr >>= 4; + + retval = recovery_add_data_entry(recovery_hcd, addr); + if (retval < 0) { + TPD_INFO("Failed to add data entry\n"); + return retval; + } + + retval = recovery_add_data_entry(recovery_hcd, addr >> 8); + if (retval < 0) { + TPD_INFO("Failed to add data entry\n"); + return retval; + } + } + + retval = recovery_add_data_entry(recovery_hcd, data0); + if (retval < 0) { + TPD_INFO("Failed to add data entry\n"); + return retval; + } + + retval = recovery_add_data_entry(recovery_hcd, data1); + if (retval < 0) { + TPD_INFO("Failed to add data entry\n"); + return retval; + } + + words++; + } else if (type == 0x02) { + retval = recovery_add_padding(recovery_hcd, &words); + if (retval < 0) { + TPD_INFO("Failed to add padding\n"); + return retval; + } + + offset = (data0 << 8) + data1; + offset <<= 4; + } + } + + retval = recovery_add_padding(recovery_hcd, &words); + if (retval < 0) { + TPD_INFO("Failed to add padding\n"); + return retval; + } + + return 0; +} + +static int recovery_check_status(struct recovery_hcd *recovery_hcd) +{ + int retval; + unsigned char status; + + retval = syna_tcm_rmi_read(recovery_hcd->tcm_info, + recovery_hcd->f35_addr.data_base, + &status, + sizeof(status)); + if (retval < 0) { + TPD_INFO("Failed to read status\n"); + return retval; + } + + status = status & 0x1f; + + if (status != 0x00) { + TPD_INFO("Recovery mode status = 0x%02x\n", status); + return -EINVAL; + } + + return 0; +} + +static int recovery_write_flash(struct recovery_hcd *recovery_hcd) +{ + int retval; + unsigned char *data_ptr; + unsigned int chunk_buf_size; + unsigned int chunk_data_size; + unsigned int entries_written; + unsigned int entries_to_write; + + entries_written = 0; + + data_ptr = recovery_hcd->data_buf; + + chunk_buf_size = sizeof(recovery_hcd->chunk_buf); + + chunk_data_size = chunk_buf_size - 1; + + recovery_hcd->chunk_buf[chunk_buf_size - 1] = F35_WRITE_CHUNK_COMMAND; + + while (entries_written < recovery_hcd->data_entries) { + entries_to_write = F35_CHUNK_SIZE + 2; + + retval = secure_memcpy(recovery_hcd->chunk_buf, + chunk_buf_size - 1, + data_ptr, + recovery_hcd->data_entries - entries_written, + entries_to_write); + if (retval < 0) { + TPD_INFO("Failed to copy chunk data\n"); + return retval; + } + + retval = syna_tcm_rmi_write(recovery_hcd->tcm_info, + recovery_hcd->f35_addr.control_base, + recovery_hcd->chunk_buf, + chunk_buf_size); + if (retval < 0) { + TPD_INFO("Failed to write chunk data\n"); + return retval; + } + + data_ptr += entries_to_write; + entries_written += entries_to_write; + } + + retval = recovery_check_status(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to get no error recovery mode status\n"); + return retval; + } + + return 0; +} + +static int recovery_poll_erase_completion(struct recovery_hcd *recovery_hcd) +{ + int retval; + unsigned char status; + unsigned char command; + unsigned char data_base; + unsigned int timeout; + + timeout = F35_ERASE_ALL_WAIT_MS; + + data_base = recovery_hcd->f35_addr.data_base; + + do { + command = F35_READ_FLASH_STATUS_COMMAND; + + retval = syna_tcm_rmi_write(recovery_hcd->tcm_info, + recovery_hcd->f35_addr.command_base, + &command, + sizeof(command)); + if (retval < 0) { + TPD_INFO("Failed to write F$35 command\n"); + return retval; + } + + do { + retval = syna_tcm_rmi_read(recovery_hcd->tcm_info, + recovery_hcd->f35_addr.command_base, + &command, + sizeof(command)); + if (retval < 0) { + TPD_INFO("Failed to read command status\n"); + return retval; + } + + if (command == 0x00) + break; + + if (timeout == 0) + break; + + msleep(F35_ERASE_ALL_POLL_MS); + timeout -= F35_ERASE_ALL_POLL_MS; + } while (true); + + if (command != 0 && timeout == 0) { + retval = -EINVAL; + goto exit; + } + + retval = syna_tcm_rmi_read(recovery_hcd->tcm_info, + data_base + F35_DATA5_OFFSET, + &status, + sizeof(status)); + if (retval < 0) { + TPD_INFO("Failed to read flash status\n"); + return retval; + } + + if ((status & 0x01) == 0x00) + break; + + if (timeout == 0) { + retval = -EINVAL; + goto exit; + } + + msleep(F35_ERASE_ALL_POLL_MS); + timeout -= F35_ERASE_ALL_POLL_MS; + } while (true); + + retval = 0; + +exit: + if (retval < 0) { + TPD_INFO("Failed to get erase completion\n"); + } + + return retval; +} + +static int recovery_erase_flash(struct recovery_hcd *recovery_hcd) +{ + int retval; + unsigned char command; + + command = F35_ERASE_ALL_COMMAND; + + retval = syna_tcm_rmi_write(recovery_hcd->tcm_info, + recovery_hcd->f35_addr.control_base + F35_CTRL3_OFFSET, + &command, + sizeof(command)); + if (retval < 0) { + TPD_INFO("Failed to write F$35 command\n"); + return retval; + } + + if (recovery_hcd->f35_addr.command_base) { + retval = recovery_poll_erase_completion(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to wait for erase completion\n"); + return retval; + } + } else { + msleep(F35_ERASE_ALL_WAIT_MS); + } + + retval = recovery_check_status(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to get no error recovery mode status\n"); + return retval; + } + + return 0; +} + +static int recovery_in_ubl_mode(struct recovery_hcd *recovery_hcd) +{ + int retval = 0; + struct rmi_pdt_entry p_entry; + retval = syna_tcm_rmi_read(recovery_hcd->tcm_info, + PDT_START_ADDR, + (unsigned char *)&p_entry, + sizeof(p_entry)); + if (retval < 0) { + TPD_INFO("Failed to read PDT entry\n"); + return false; + } + + if (p_entry.fn_number != UBL_FN_NUMBER) { + TPD_INFO("Failed to find F$35\n"); + return false; + } + return true; +} +static int recovery_get_fw_ihex(struct recovery_hcd *recovery_hcd, char *iHex) +{ + int retval; + + retval = request_firmware(&recovery_hcd->fw_entry, iHex, &recovery_hcd->tcm_info->client->dev); + if (retval < 0) { + TPD_INFO("Failed to request %s\n", iHex); + return retval; + } + + TPD_INFO("ihex file size = %d\n", (unsigned int)recovery_hcd->fw_entry->size); + retval = secure_memcpy(recovery_hcd->ihex_buf, + recovery_hcd->fw_entry->size, + recovery_hcd->fw_entry->data, + recovery_hcd->fw_entry->size, + recovery_hcd->fw_entry->size); + if (retval < 0) { + TPD_INFO("Failed to copy ihex data\n"); + return retval; + } + + recovery_hcd->ihex_size = recovery_hcd->fw_entry->size; + recovery_hcd->ihex_records = recovery_hcd->ihex_size / IHEX_RECORD_SIZE; + return 0; +} + +int recovery_do_recovery(struct recovery_hcd *recovery_hcd, char *iHex) +{ + int retval; + struct rmi_pdt_entry p_entry; + + retval = recovery_get_fw_ihex(recovery_hcd, iHex); + if (retval < 0) { + TPD_INFO("Failed to get ihex data\n"); + return retval; + } + + retval = recovery_parse_ihex(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to parse ihex data\n"); + return retval; + } + + retval = syna_tcm_rmi_read(recovery_hcd->tcm_info, + PDT_START_ADDR, + (unsigned char *)&p_entry, + sizeof(p_entry)); + if (retval < 0) { + TPD_INFO("Failed to read PDT entry\n"); + return retval; + } + + if (p_entry.fn_number != UBL_FN_NUMBER) { + TPD_INFO("Failed to find F$35\n"); + return -ENODEV; + } + + recovery_hcd->f35_addr.query_base = p_entry.query_base_addr; + recovery_hcd->f35_addr.command_base = p_entry.command_base_addr; + recovery_hcd->f35_addr.control_base = p_entry.control_base_addr; + recovery_hcd->f35_addr.data_base = p_entry.data_base_addr; + + TPD_INFO("Start of recovery\n"); + + retval = recovery_erase_flash(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to erase flash\n"); + return retval; + } + + TPD_INFO("Flash erased\n"); + + retval = recovery_write_flash(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to write to flash\n"); + return retval; + } + + TPD_INFO("Flash written\n"); + + retval = recovery_device_reset(recovery_hcd); + if (retval < 0) { + TPD_INFO("Failed to do reset\n"); + return retval; + } + + TPD_INFO("End of recovery\n"); + + return 0; +} + +int try_to_recovery_ic(struct syna_tcm_data *tcm_info, char *iHex) +{ + int retval = 0; + struct recovery_hcd *recovery_hcd; + + recovery_hcd = kzalloc(sizeof(*recovery_hcd), GFP_KERNEL); + if (!recovery_hcd) { + TPD_INFO("Failed to allocate memory for recovery_hcd\n"); + return -ENOMEM; + } + + recovery_hcd->ihex_buf = kzalloc(IHEX_BUF_SIZE, GFP_KERNEL); + if (!recovery_hcd->ihex_buf) { + TPD_INFO("Failed to allocate memory for recovery_hcd->ihex_buf\n"); + retval = -ENOMEM; + goto err_allocate_ihex_buf; + } + + recovery_hcd->data_buf = kzalloc(DATA_BUF_SIZE, GFP_KERNEL); + if (!recovery_hcd->data_buf) { + TPD_INFO("Failed to allocate memory for recovery_hcd->data_buf\n"); + retval = -ENOMEM; + goto err_allocate_data_buf; + } + + recovery_hcd->out_buf[0] = CMD_REBOOT_TO_ROM_BOOTLOADER; + recovery_hcd->out_buf[1] = 0; + recovery_hcd->out_buf[2] = 0; + recovery_hcd->tcm_info = tcm_info; + + if (!recovery_in_ubl_mode(recovery_hcd)) { + TPD_INFO("not in ubl mode, goto normal fw update process\n"); + retval = 0; + goto exit; + } + + recovery_do_recovery(recovery_hcd, iHex); + + retval = 1; +exit: + kfree(recovery_hcd->data_buf); +err_allocate_data_buf: + kfree(recovery_hcd->ihex_buf); +err_allocate_ihex_buf: + kfree(recovery_hcd); + recovery_hcd = NULL; + + return retval; +} diff --git a/drivers/oneplus/input/touchscreen/synaptics/synaptics_common.c b/drivers/oneplus/input/touchscreen/synaptics/synaptics_common.c new file mode 100755 index 0000000000000000000000000000000000000000..866f23cae3fbaaeaa0cb7b07fca090d9854ebaf3 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/synaptics_common.c @@ -0,0 +1,755 @@ + +#include "../touchpanel_common.h" +#include "synaptics_common.h" +#include +#include + +/*******Part0:LOG TAG Declear********************/ + +#define TPD_DEVICE "synaptics_common" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (LEVEL_DEBUG == tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do{\ + if (LEVEL_BASIC != tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + + +/*******Part1:Call Back Function implement*******/ + +unsigned int extract_uint_le(const unsigned char *ptr) +{ + return (unsigned int)ptr[0] + + (unsigned int)ptr[1] * 0x100 + + (unsigned int)ptr[2] * 0x10000 + + (unsigned int)ptr[3] * 0x1000000; +} + +/*******************Limit File With "limit_block" Format*************************************/ +int synaptics_get_limit_data(char *type, const unsigned char *fw_image) +{ + int i = 0; + unsigned int offset, count; + struct limit_info *limit_info; + struct limit_block *limit_block; + + limit_info = (struct limit_info *)fw_image; + count = limit_info->count; + + offset = sizeof(struct limit_info); + for (i = 0; i < count; i++) { + limit_block = (struct limit_block *)(fw_image + offset); + pr_info("name: %s, size: %d, offset %d\n", limit_block->name, limit_block->size, offset); + if (strncmp(limit_block->name, type, MAX_LIMIT_NAME_SIZE) == 0) { + break; + } + + offset += (sizeof(struct limit_block) - 4 + 2*limit_block->size); /*minus 4, because byte align*/ + } + + if (i == count) { + return 0; + } + + return offset; +} + +/*************************************TCM Firmware Parse Funtion**************************************/ +int synaptics_parse_header_v2(struct image_info *image_info, const unsigned char *fw_image) +{ + struct image_header_v2 *header; + unsigned int magic_value; + unsigned int number_of_areas; + unsigned int i = 0; + unsigned int addr; + unsigned int length; + unsigned int checksum; + unsigned int flash_addr; + const unsigned char *content; + struct area_descriptor *descriptor; + int offset = sizeof(struct image_header_v2); + + header = (struct image_header_v2 *)fw_image; + magic_value = le4_to_uint(header->magic_value); + + if (magic_value != IMAGE_FILE_MAGIC_VALUE) { + pr_err("invalid magic number %d\n", magic_value); + return -EINVAL; + } + + number_of_areas = le4_to_uint(header->num_of_areas); + + for (i = 0; i < number_of_areas; i++) { + addr = le4_to_uint(fw_image + offset); + descriptor = (struct area_descriptor *)(fw_image + addr); + offset += 4; + + magic_value = le4_to_uint(descriptor->magic_value); + if (magic_value != FLASH_AREA_MAGIC_VALUE) + continue; + + length = le4_to_uint(descriptor->length); + content = (unsigned char *)descriptor + sizeof(*descriptor); + flash_addr = le4_to_uint(descriptor->flash_addr_words) * 2; + checksum = le4_to_uint(descriptor->checksum); + + if (0 == strncmp((char *)descriptor->id_string, + BOOT_CONFIG_ID, + strlen(BOOT_CONFIG_ID))) { + if (checksum != (crc32(~0, content, length) ^ ~0)) { + pr_err("Boot config checksum error\n"); + return -EINVAL; + } + image_info->boot_config.size = length; + image_info->boot_config.data = content; + image_info->boot_config.flash_addr = flash_addr; + pr_info("Boot config size = %d, address = 0x%08x\n", length, flash_addr); + } else if (0 == strncmp((char *)descriptor->id_string, + APP_CODE_ID, + strlen(APP_CODE_ID))) { + if (checksum != (crc32(~0, content, length) ^ ~0)) { + pr_err("Application firmware checksum error\n"); + return -EINVAL; + } + image_info->app_firmware.size = length; + image_info->app_firmware.data = content; + image_info->app_firmware.flash_addr = flash_addr; + pr_info("Application firmware size = %d address = 0x%08x\n", length, flash_addr); + } else if (0 == strncmp((char *)descriptor->id_string, + APP_CONFIG_ID, + strlen(APP_CONFIG_ID))) { + if (checksum != (crc32(~0, content, length) ^ ~0)) { + pr_err("Application config checksum error\n"); + return -EINVAL; + } + image_info->app_config.size = length; + image_info->app_config.data = content; + image_info->app_config.flash_addr = flash_addr; + pr_info("Application config size = %d address = 0x%08x\n",length, flash_addr); + } else if (0 == strncmp((char *)descriptor->id_string, + DISP_CONFIG_ID, + strlen(DISP_CONFIG_ID))) { + if (checksum != (crc32(~0, content, length) ^ ~0)) { + pr_err("Display config checksum error\n"); + return -EINVAL; + } + image_info->disp_config.size = length; + image_info->disp_config.data = content; + image_info->disp_config.flash_addr = flash_addr; + pr_info("Display config size = %d address = 0x%08x\n", length, flash_addr); + } + } + return 0; +} + +/**********************************RMI Firmware Parse Funtion*****************************************/ +void synaptics_parse_header(struct image_header_data *header, const unsigned char *fw_image) +{ + struct image_header *data = (struct image_header *)fw_image; + + header->checksum = extract_uint_le(data->checksum); + TPD_DEBUG(" checksume is %x", header->checksum); + + header->bootloader_version = data->bootloader_version; + TPD_DEBUG(" bootloader_version is %d\n", header->bootloader_version); + + header->firmware_size = extract_uint_le(data->firmware_size); + TPD_DEBUG(" firmware_size is %x\n", header->firmware_size); + + header->config_size = extract_uint_le(data->config_size); + TPD_DEBUG(" header->config_size is %x\n", header->config_size); + + /* only available in s4322 , reserved in other, begin*/ + header->bootloader_offset = extract_uint_le(data->bootloader_addr ); + header->bootloader_size = extract_uint_le(data->bootloader_size); + TPD_DEBUG(" header->bootloader_offset is %x\n", header->bootloader_offset); + TPD_DEBUG(" header->bootloader_size is %x\n", header->bootloader_size); + + header->disp_config_offset = extract_uint_le(data->dsp_cfg_addr); + header->disp_config_size = extract_uint_le(data->dsp_cfg_size); + TPD_DEBUG(" header->disp_config_offset is %x\n", header->disp_config_offset); + TPD_DEBUG(" header->disp_config_size is %x\n", header->disp_config_size); + /* only available in s4322 , reserved in other , end*/ + + memcpy(header->product_id, data->product_id, sizeof(data->product_id)); + header->product_id[sizeof(data->product_id)] = 0; + + memcpy(header->product_info, data->product_info, sizeof(data->product_info)); + + header->contains_firmware_id = data->options_firmware_id; + TPD_DEBUG(" header->contains_firmware_id is %x\n", header->contains_firmware_id); + if (header->contains_firmware_id) + header->firmware_id = extract_uint_le(data->firmware_id); + + return; +} + +void synaptics_print_limit_v2(struct seq_file *s, struct touchpanel_data *ts, const struct firmware *fw) +{ + int i = 0, index = 0; + int row, col; + int rows, cols; + unsigned int offset, count; + int16_t *data_16; + struct limit_info *limit_info; + struct limit_block *limit_block; + const char *data = fw->data; + + limit_info = (struct limit_info*)data; + count = limit_info->count; + + offset = sizeof(struct limit_info); + for (i = 0; i < count; i++) { + limit_block = (struct limit_block *)(data + offset); + pr_info("name: %s, size: %d, offset %d\n", limit_block->name, limit_block->size, offset); + + seq_printf(s, "%s\n", limit_block->name); + + data_16 = &limit_block->data; + offset += (sizeof(struct limit_block) - 4 + 2*limit_block->size); /*minus 4, because byte align*/ + + if ((ts->hw_res.TX_NUM*ts->hw_res.RX_NUM) != limit_block->size/2) { + continue; + } + + cols = ts->hw_res.TX_NUM; + rows = ts->hw_res.RX_NUM; + + index = 0; + for (row = 0; row < rows; row++){ + seq_printf(s, "[%02d]:", row); + for(col = 0; col < cols; col++) { + seq_printf(s, "%4d %4d,", *(data_16 + 2*index), *(data_16 + 2*index + 1)); + index++; + } + seq_printf(s, "\n"); + } + + } + return; +} + +void synaptics_print_limit_v1(struct seq_file *s, struct touchpanel_data *ts, const struct firmware *fw) +{ + uint16_t *prow = NULL; + uint16_t *prowcbc = NULL; + int i = 0; + struct test_header *ph = NULL; + + ph = (struct test_header *)(fw->data); + prow = (uint16_t *)(fw->data + ph->array_limit_offset); + prowcbc = (uint16_t *)(fw->data + ph->array_limitcbc_offset); + TPD_INFO("synaptics_test_limit_show:array_limit_offset = %x array_limitcbc_offset = %x \n", + ph->array_limit_offset, ph->array_limitcbc_offset); + TPD_DEBUG("test begin:\n"); + seq_printf(s, "Without cbc:"); + + for (i = 0 ; i < (ph->array_limit_size / 2); i++) { + if (i % (2 * ts->hw_res.RX_NUM) == 0) + seq_printf(s, "\n[%2d] ", (i / ts->hw_res.RX_NUM) / 2); + seq_printf(s, "%4d, ", prow[i]); + TPD_DEBUG("%d, ", prow[i]); + } + if (ph->withCBC == 1) { + seq_printf(s, "\nWith cbc:"); + for (i = 0 ; i < (ph->array_limitcbc_size / 2); i++) { + if (i % (2 * ts->hw_res.RX_NUM) == 0) + seq_printf(s, "\n[%2d] ", (i / ts->hw_res.RX_NUM) / 2); + seq_printf(s, "%4d, ", prowcbc[i]); + TPD_DEBUG("%d, ", prowcbc[i]); + } + } + + seq_printf(s, "\n"); + return; +} + +void synaptics_print_limit_v3(struct seq_file *s, struct touchpanel_data *ts, const struct firmware *fw) +{ + int32_t *p_data32 = NULL; + uint32_t i = 0, j = 0, m = 0, item_cnt = 0, array_index = 0; + uint32_t *p_item_offset = NULL; + struct test_header_new *ph = NULL; + struct syna_test_item_header *item_head = NULL; + + ph = (struct test_header_new *)(fw->data); + p_item_offset = (uint32_t *)(fw->data + sizeof(struct test_header_new)); + for (i = 0; i < 8*sizeof(ph->test_item); i++) { + if ((ph->test_item >> i) & 0x01) { + item_cnt++; + } + } + + for (m = 0; m < item_cnt; m++) { + item_head = (struct syna_test_item_header *)(fw->data + p_item_offset[m]); + if (item_head->item_magic != Limit_ItemMagic) { + seq_printf(s, "item: %d limit data has some problem\n", item_head->item_bit); + continue; + } + + seq_printf(s, "item %d[size %d, limit type %d, para num %d] :\n", item_head->item_bit, item_head->item_size, item_head->item_limit_type, item_head->para_num); + if (item_head->item_limit_type == LIMIT_TYPE_NO_DATA) { + seq_printf(s, "no limit data\n"); + } else if (item_head->item_limit_type == LIMIT_TYPE_CERTAIN_DATA) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "top limit data: %d\n", *p_data32); + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "floor limit data: %d\n", *p_data32); + } else if (item_head->item_limit_type == LIMIT_TYPE_EACH_NODE_DATA) { + if ((item_head->item_bit == TYPE_FULLRAW_CAP) || (item_head->item_bit == TYPE_DELTA_NOISE) || (item_head->item_bit == TYPE_RAW_CAP)) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "[%02d] ", i); + for (j = 0; j < ts->hw_res.RX_NUM; j++) { + array_index = i * ts->hw_res.RX_NUM + j; + seq_printf(s, "%4d, ", p_data32[array_index]); + } + seq_printf(s, "\n"); + } + } else if((item_head->item_bit == TYPE_HYBRIDRAW_CAP) || (item_head->item_bit == TYPE_HYBRIDABS_DIFF_CBC) || (item_head->item_bit == TYPE_HYBRIDABS_NOSIE)){ + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM + ts->hw_res.RX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM + ts->hw_res.RX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + } else if (item_head->item_bit == TYPE_TREXSHORT_CUSTOM) { + p_data32 = (int32_t *)(fw->data + item_head->top_limit_offset); + seq_printf(s, "top data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + + p_data32 = (int32_t *)(fw->data + item_head->floor_limit_offset); + seq_printf(s, "floor data: \n"); + for (i = 0; i < ts->hw_res.TX_NUM; i++) { + seq_printf(s, "%4d, ", p_data32[i]); + } + seq_printf(s, "\n"); + } + } + + p_data32 = (int32_t *)(fw->data + p_item_offset[m] + sizeof(struct syna_test_item_header)); + if (item_head->para_num) { + seq_printf(s, "parameter:"); + for (j = 0; j < item_head->para_num; j++) { + seq_printf(s, "%d, ", p_data32[j]); + } + seq_printf(s, "\n"); + } + seq_printf(s, "\n"); + } +} + +void synaptics_limit_read(struct seq_file *s, struct touchpanel_data *ts) +{ + int ret = 0; + const struct firmware *fw = NULL; + struct test_header *ph = NULL; + uint32_t *p_firstitem_offset = NULL, *p_firstitem = NULL; + + ret = request_firmware(&fw, ts->panel_data.test_limit_name, ts->dev); + if (ret < 0) { + TPD_INFO("Request firmware failed - %s (%d)\n", ts->panel_data.test_limit_name, ret); + seq_printf(s, "Request failed, Check the path %s\n",ts->panel_data.test_limit_name); + return; + } + + ph = (struct test_header *)(fw->data); + p_firstitem_offset = (uint32_t *)(fw->data + sizeof(struct test_header_new)); + if (ph->magic1 == Limit_MagicNum1 && ph->magic2 == Limit_MagicNum2 && (fw->size >= *p_firstitem_offset+sizeof(uint32_t))) { + p_firstitem = (uint32_t *)(fw->data + *p_firstitem_offset); + if (*p_firstitem == Limit_ItemMagic) { + synaptics_print_limit_v3(s, ts, fw); + release_firmware(fw); + return; + } + } + if (ph->magic1 == Limit_MagicNum1 && ph->magic2 == Limit_MagicNum2_V2) { + synaptics_print_limit_v2(s, ts, fw); + } else { + synaptics_print_limit_v1(s, ts, fw); + } + release_firmware(fw); +} + +//proc/touchpanel/baseline_test +static int tp_auto_test_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct synaptics_proc_operations *syna_ops; + struct timespec now_time; + struct rtc_time rtc_now_time; + const struct firmware *fw = NULL; + struct test_header_new *test_head = NULL; + mm_segment_t old_fs; + uint8_t data_buf[64]; + int ret = 0; + int fd = -1; + + struct syna_testdata syna_testdata = + { + .TX_NUM = 0, + .RX_NUM = 0, + .fd = -1, + .irq_gpio = -1, + .key_TX = 0, + .key_RX = 0, + .TP_FW = 0, + .fw = NULL, + .fd_support = false, + .fingerprint_underscreen_support = false, + }; + + if (!ts) + return 0; + syna_ops = (struct synaptics_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + if (!syna_ops->auto_test) { + seq_printf(s, "Not support auto-test proc node\n"); + return 0; + } + + /*if resume not completed, do not do screen on test*/ + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume state\n"); + return 0; + } + + //step1:disable_irq && get mutex locked + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + + //step2: create a file to store test data in /sdcard/Tp_Test + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + sprintf(data_buf, "/sdcard/tp_testlimit_%02d%02d%02d-%02d%02d%02d-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + old_fs = get_fs(); + set_fs(KERNEL_DS); + fd = ksys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); + if (fd < 0) { + TPD_INFO("Open log file '%s' failed.\n", data_buf); + set_fs(old_fs); + } + + //step3:request test limit data from userspace + ret = request_firmware(&fw, ts->panel_data.test_limit_name, ts->dev); + if (ret < 0) { + TPD_INFO("Request firmware failed - %s (%d)\n", ts->panel_data.test_limit_name, ret); + if (fd >= 0) { + ksys_close(fd); + set_fs(old_fs); + } + seq_printf(s, "No limit IMG\n"); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; + } + + ts->in_test_process = true; + + test_head = (struct test_header_new *)fw->data; + if ((test_head->magic1 == Limit_MagicNum1) && (test_head->magic2 == Limit_MagicNum2)) { + syna_testdata.test_item = test_head->test_item; + } + //step4:init syna_testdata + syna_testdata.fd = fd; + syna_testdata.TX_NUM = ts->hw_res.TX_NUM; + syna_testdata.RX_NUM = ts->hw_res.RX_NUM; + syna_testdata.irq_gpio = ts->hw_res.irq_gpio; + syna_testdata.key_TX = ts->hw_res.key_TX; + syna_testdata.key_RX = ts->hw_res.key_RX; + syna_testdata.TP_FW = ts->panel_data.TP_FW; + syna_testdata.fw = fw; + syna_testdata.fd_support = ts->face_detect_support; + // syna_testdata.fingerprint_underscreen_support = ts->fingerprint_underscreen_support; + + syna_ops->auto_test(s, ts->chip_data, &syna_testdata); + + //step5: close file && release test limit firmware + if (fd >= 0) { + ksys_close(fd); + set_fs(old_fs); + } + release_firmware(fw); + + //step6: return to normal mode + ts->ts_ops->reset(ts->chip_data); + operate_mode_switch(ts); + + //step7: unlock the mutex && enable irq trigger + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + + ts->in_test_process = false; + return 0; +} + +static int baseline_autotest_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_auto_test_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_auto_test_proc_fops = { + .owner = THIS_MODULE, + .open = baseline_autotest_open, + .read = seq_read, + .release = single_release, +}; + +static int tp_RT251_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->RT251) { + seq_printf(s, "Not support RT251 proc node\n"); + return 0; + } + disable_irq_nosync(ts->client->irq); + mutex_lock(&ts->mutex); + debug_info_ops->RT251(s, ts->chip_data); + mutex_unlock(&ts->mutex); + enable_irq(ts->client->irq); + + return 0; +} + +static int RT251_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_RT251_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_RT251_proc_fops = { + .owner = THIS_MODULE, + .open = RT251_open, + .read = seq_read, + .release = single_release, +}; + +static int tp_RT76_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->RT76) { + seq_printf(s, "Not support RT76 proc node\n"); + return 0; + } + disable_irq_nosync(ts->client->irq); + mutex_lock(&ts->mutex); + debug_info_ops->RT76(s, ts->chip_data); + mutex_unlock(&ts->mutex); + enable_irq(ts->client->irq); + + return 0; +} + +static int RT76_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_RT76_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_RT76_proc_fops = { + .owner = THIS_MODULE, + .open = RT76_open, + .read = seq_read, + .release = single_release, +}; + +static int tp_DRT_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->DRT) { + seq_printf(s, "Not support RT76 proc node\n"); + return 0; + } + + if (ts->is_suspended && (ts->gesture_enable != 1)) { + seq_printf(s, "In suspend state, and gesture not enable\n"); + return 0; + } + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + + mutex_lock(&ts->mutex); + debug_info_ops->DRT(s, ts->chip_data); + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->client->irq); + } + return 0; + +} + +static int DRT_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_DRT_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_DRT_proc_fops = { + .owner = THIS_MODULE, + .open = DRT_open, + .read = seq_read, + .release = single_release, +}; + +static ssize_t proc_touchfilter_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + char page[PAGESIZE] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct synaptics_proc_operations *syn_ops; + + if (!ts) + return 0; + + syn_ops = (struct synaptics_proc_operations *)ts->private_data; + + if (!syn_ops->get_touchfilter_state) + return 0; + + snprintf(page, PAGESIZE-1, "%d.\n", syn_ops->get_touchfilter_state(ts->chip_data)); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_touchfilter_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8] = {0}; + int temp = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct synaptics_proc_operations *syn_ops; + + if (!ts) + return count; + + syn_ops = (struct synaptics_proc_operations *)ts->private_data; + + if (!syn_ops->set_touchfilter_state) + return count; + + if (count > 2) + return count; + if (copy_from_user(buf, buffer, count)) { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%d", &temp); + mutex_lock(&ts->mutex); + TPD_INFO("%s: value = %d\n", __func__, temp); + syn_ops->set_touchfilter_state(ts->chip_data, temp); + mutex_unlock(&ts->mutex); + + return count; +} + +static const struct file_operations touch_filter_proc_fops = +{ + .read = proc_touchfilter_control_read, + .write = proc_touchfilter_control_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +int synaptics_create_proc(struct touchpanel_data *ts, struct synaptics_proc_operations *syna_ops) +{ + int ret = 0; + + // touchpanel_auto_test interface + struct proc_dir_entry *prEntry_tmp = NULL; + ts->private_data = syna_ops; + prEntry_tmp = proc_create_data("baseline_test", 0666, ts->prEntry_tp, &tp_auto_test_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show RT251 interface + prEntry_tmp = proc_create_data("RT251", 0666, ts->prEntry_debug_tp, &tp_RT251_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show RT76 interface + prEntry_tmp = proc_create_data("RT76", 0666, ts->prEntry_debug_tp, &tp_RT76_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("DRT", 0666, ts->prEntry_debug_tp, &tp_DRT_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + if (ts->face_detect_support) { + prEntry_tmp = proc_create_data("touch_filter", 0666, ts->prEntry_tp, &touch_filter_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + return ret; +} diff --git a/drivers/oneplus/input/touchscreen/synaptics/synaptics_common.h b/drivers/oneplus/input/touchscreen/synaptics/synaptics_common.h new file mode 100755 index 0000000000000000000000000000000000000000..45f0c9d643a9a55d79debf10e4f6bbab5ebaf33a --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/synaptics_common.h @@ -0,0 +1,247 @@ + +#ifndef SYNAPTICS_H +#define SYNAPTICS_H +#define CONFIG_SYNAPTIC_RED + +/*********PART1:Head files**********************/ +#include +#include +#include +#include +#include + +#include "../touchpanel_common.h" +#include "synaptics_firmware_v2.h" + +/*********PART2:Define Area**********************/ +#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10 +#define SYNAPTICS_RMI4_PRODUCT_INFO_SIZE 2 + +#define DiagonalUpperLimit 1100 +#define DiagonalLowerLimit 900 + +#define MAX_RESERVE_SIZE 4 +#define MAX_LIMIT_NAME_SIZE 16 + +#define Limit_MagicNum1 0x494D494C +#define Limit_MagicNum2 0x474D4954 +#define Limit_MagicNum2_V2 0x32562D54 +#define Limit_ItemMagic 0x4F50504F + + +/*********PART3:Struct Area**********************/ +typedef enum { + BASE_NEGATIVE_FINGER = 0x02, + BASE_MUTUAL_SELF_CAP = 0x04, + BASE_ENERGY_RATIO = 0x08, + BASE_RXABS_BASELINE = 0x10, + BASE_TXABS_BASELINE = 0x20, +} BASELINE_ERR; + +typedef enum { + SHIELD_PALM = 0x01, + SHIELD_GRIP = 0x02, + SHIELD_METAL = 0x04, + SHIELD_MOISTURE = 0x08, + SHIELD_ESD = 0x10, +} SHIELD_MODE; + +typedef enum { + RST_HARD = 0x01, + RST_INST = 0x02, + RST_PARITY = 0x04, + RST_WD = 0x08, + RST_OTHER = 0x10, +} RESET_REASON; + +struct health_info { + uint16_t grip_count; + uint16_t grip_x; + uint16_t grip_y; + uint16_t freq_scan_count; + uint16_t baseline_err; + uint16_t curr_freq; + uint16_t noise_state; + uint16_t cid_im; + uint16_t shield_mode; + uint16_t reset_reason; +}; + +struct excep_count { + uint16_t grip_count; + //baseline error type + uint16_t neg_finger_count; + uint16_t cap_incons_count; + uint16_t energy_ratio_count; + uint16_t rx_baseline_count; + uint16_t tx_baseline_count; + //noise status + uint16_t noise_count; + //shield report fingers + uint16_t shield_palm_count; + uint16_t shield_edge_count; + uint16_t shield_metal_count; + uint16_t shield_water_count; + uint16_t shield_esd_count; + //exception reset count + uint16_t hard_rst_count; + uint16_t inst_rst_count; + uint16_t parity_rst_count; + uint16_t wd_rst_count; + uint16_t other_rst_count; +}; + +struct image_header { + /* 0x00 - 0x0f */ + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char options_firmware_id:1; + unsigned char options_contain_bootloader:1; + /* only available in s4322 , reserved in other, begin*/ + unsigned char options_guest_code:1; + unsigned char options_tddi:1; + unsigned char options_reserved:4; + /* only available in s4322 , reserved in other , end*/ + unsigned char bootloader_version; + unsigned char firmware_size[4]; + unsigned char config_size[4]; + /* 0x10 - 0x1f */ + unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE]; + unsigned char package_id[2]; + unsigned char package_id_revision[2]; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; + /* 0x20 - 0x2f */ + /* only available in s4322 , reserved in other, begin*/ + unsigned char bootloader_addr[4]; + unsigned char bootloader_size[4]; + unsigned char ui_addr[4]; + unsigned char ui_size[4]; + /* only available in s4322 , reserved in other , end*/ + /* 0x30 - 0x3f */ + unsigned char ds_id[16]; + /* 0x40 - 0x4f */ + /* only available in s4322 , reserved in other, begin*/ + union { + struct { + unsigned char dsp_cfg_addr[4]; + unsigned char dsp_cfg_size[4]; + unsigned char reserved_48_4f[8]; + }; + }; + /* only available in s4322 , reserved in other , end*/ + /* 0x50 - 0x53 */ + unsigned char firmware_id[4]; +}; + +struct image_header_data { + bool contains_firmware_id; + unsigned int firmware_id; + unsigned int checksum; + unsigned int firmware_size; + unsigned int config_size; + /* only available in s4322 , reserved in other, begin*/ + unsigned int disp_config_offset; + unsigned int disp_config_size; + unsigned int bootloader_offset; + unsigned int bootloader_size; + /* only available in s4322 , reserved in other , end*/ + unsigned char bootloader_version; + unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; +}; + +struct limit_block { + char name[MAX_LIMIT_NAME_SIZE]; + int mode; + int reserve[MAX_RESERVE_SIZE]; /*16*/ + int size; + int16_t data; +}; + +struct limit_info { + unsigned int magic1; + unsigned int magic2; + unsigned int count; +}; + +struct test_header { + unsigned int magic1; + unsigned int magic2; + unsigned int withCBC; + unsigned int array_limit_offset; + unsigned int array_limit_size; + unsigned int array_limitcbc_offset; + unsigned int array_limitcbc_size; +}; + +struct test_header_new { + uint32_t magic1; + uint32_t magic2; + uint64_t test_item; +}; + +struct syna_test_item_header { + uint32_t item_magic; + uint32_t item_size; + uint16_t item_bit; + uint16_t item_limit_type; + uint32_t top_limit_offset; + uint32_t floor_limit_offset; + uint32_t para_num; +}; + +enum test_item_bit { + TYPE_TRX_SHORT = 1, + TYPE_TRX_OPEN = 2, + TYPE_TRXGND_SHORT = 3, + TYPE_FULLRAW_CAP = 5, + TYPE_DELTA_NOISE = 10, + TYPE_HYBRIDRAW_CAP = 18, + TYPE_RAW_CAP = 22, + TYPE_TREXSHORT_CUSTOM = 25, + TYPE_HYBRIDABS_DIFF_CBC = 26, + TYPE_HYBRIDABS_NOSIE = 29, +}; + +enum { + LIMIT_TYPE_NO_DATA = 0x00, //means no limit data + LIMIT_TYPE_CERTAIN_DATA = 0x01, //means all nodes limit data is a certain data + LIMIT_TYPE_EACH_NODE_DATA = 0x02, //means all nodes have it's own limit + LIMIT_TYPE_INVALID_DATA = 0xFF, //means wrong limit data type +}; + +struct syna_testdata{ + int TX_NUM; + int RX_NUM; + int fd; + int irq_gpio; + int key_TX; + int key_RX; + uint64_t TP_FW; + const struct firmware *fw; + bool fd_support; + bool fingerprint_underscreen_support; + uint64_t test_item; +}; + +//import from "android/bootable/bootloader/lk/platform/msm_shared/include/msm_panel.h" +enum { + OP16037JDI_R63452_1080P_CMD_PANEL = 13, + OP16037SAMSUNG_S6E3FA5_1080P_CMD_PANEL = 14, + UNKNOWN_PANEL +}; + +struct synaptics_proc_operations { + void (*auto_test) (struct seq_file *s, void *chip_data, struct syna_testdata *syna_testdata); + void (*set_touchfilter_state) (void *chip_data, uint8_t range_size); + uint8_t (*get_touchfilter_state) (void *chip_data); +}; + +void synaptics_limit_read(struct seq_file *s, struct touchpanel_data *ts); +int synaptics_create_proc(struct touchpanel_data *ts, struct synaptics_proc_operations *syna_ops); +void synaptics_parse_header(struct image_header_data *header, const unsigned char *fw_image); +int synaptics_parse_header_v2(struct image_info *image_info, const unsigned char *fw_image); +int synaptics_get_limit_data(char *type, const unsigned char *fw_image); + +#endif diff --git a/drivers/oneplus/input/touchscreen/synaptics/synaptics_firmware_v2.h b/drivers/oneplus/input/touchscreen/synaptics/synaptics_firmware_v2.h new file mode 100755 index 0000000000000000000000000000000000000000..d4c210de81eb81ec3d52a828654c00f9615f1dd5 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/synaptics_firmware_v2.h @@ -0,0 +1,100 @@ +/*************************************************** + * File:synaptics_common.h + * VENDOR_EDIT + * Description: + * synaptics common driver + * Version:1.0: + * * + * -------------- Revision History: ----------------- + * + ***************************************************/ + +#ifndef SYNAPTICS_FIRMWARE_V2_H +#define SYNAPTICS_FIRMWARE_V2_H + +/*********PART1:Head files**********************/ +#include +#include +#include +#include +#include + +#define IMAGE_FILE_MAGIC_VALUE 0x4818472b +#define FLASH_AREA_MAGIC_VALUE 0x7c05e516 + +#define BOOT_CONFIG_ID "BOOT_CONFIG" +#define APP_CODE_ID "APP_CODE" +#define APP_CONFIG_ID "APP_CONFIG" +#define DISP_CONFIG_ID "DISPLAY" + +struct app_config_header { + unsigned short magic_value[4]; + unsigned char checksum[4]; + unsigned char length[2]; + unsigned char build_id[4]; + unsigned char customer_config_id[16]; +}; + +struct area_descriptor { + unsigned char magic_value[4]; + unsigned char id_string[16]; + unsigned char flags[4]; + unsigned char flash_addr_words[4]; + unsigned char length[4]; + unsigned char checksum[4]; +}; + +struct block_data_v2 { + const unsigned char *data; + unsigned int size; + unsigned int flash_addr; +}; + +struct image_info { + unsigned int packrat_number; + struct block_data_v2 boot_config; + struct block_data_v2 app_firmware; + struct block_data_v2 app_config; + struct block_data_v2 disp_config; +}; + +struct image_header_v2 { + unsigned char magic_value[4]; + unsigned char num_of_areas[4]; +}; + +struct boot_config { + union { + unsigned char i2c_address; + struct { + unsigned char cpha:1; + unsigned char cpol:1; + unsigned char word0_b2__7:6; + } __packed; + }; + unsigned char attn_polarity:1; + unsigned char attn_drive:2; + unsigned char attn_pullup:1; + unsigned char word0_b12__14:3; + unsigned char used:1; + unsigned short customer_part_id; + unsigned short boot_timeout; + unsigned short continue_on_reset:1; + unsigned short word3_b1__15:15; +} __packed; + +static inline unsigned int le2_to_uint(const unsigned char *src) +{ + return (unsigned int)src[0] + + (unsigned int)src[1] * 0x100; +} + +static inline unsigned int le4_to_uint(const unsigned char *src) +{ + return (unsigned int)src[0] + + (unsigned int)src[1] * 0x100 + + (unsigned int)src[2] * 0x10000 + + (unsigned int)src[3] * 0x1000000; +} + +#endif diff --git a/drivers/oneplus/input/touchscreen/synaptics/synaptics_touch_panel_remote.c b/drivers/oneplus/input/touchscreen/synaptics/synaptics_touch_panel_remote.c new file mode 100755 index 0000000000000000000000000000000000000000..2f93b27947ff417d2132b33477079ec07b89de0c --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/synaptics_touch_panel_remote.c @@ -0,0 +1,1018 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "synaptics_touch_panel_remote.h" + +#define CHAR_DEVICE_NAME "rmi" +#define DEVICE_CLASS_NAME "rmidev" +#define DEV_NUMBER 1 +#define REG_ADDR_LIMIT 0xFFFF + +static ssize_t rmidev_sysfs_data_show(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t rmidev_sysfs_data_store(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count); + +static ssize_t rmidev_sysfs_open_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static ssize_t rmidev_sysfs_release_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static ssize_t rmidev_sysfs_address_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static ssize_t rmidev_sysfs_length_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static ssize_t rmidev_sysfs_attn_state_show(struct device *dev, + struct device_attribute *attr, char *buf); + +static int remote_rmi4_i2c_read(unsigned short addr, unsigned char *data, unsigned short length); +static int remote_rmi4_i2c_write(unsigned short addr, unsigned char *data, unsigned short length); +static int remote_rmi4_i2c_enable(bool enable); +static int remote_rmi4_get_irq_gpio(void); +static int remote_rmit_set_page(unsigned int address); +static int remote_rmit_put_page(void); + +static struct input_dev *remote_rmi4_get_input(void); +static struct i2c_client *remote_rmi4_get_i2c_client(void); +static void remote_rmi4_delay_work(struct work_struct *work); +static struct remotepanel_data *remote_free_panel_data(struct remotepanel_data *pdata); + +#define MASK_8BIT 0xFF ; +#define SYN_I2C_RETRY_TIMES 3; +#define BUFFER_SIZE 252 +struct rmidev_handle { + dev_t dev_no; + unsigned short address; + unsigned int length; + struct device dev; + struct kobject *sysfs_dir; + void *data; +}; + +struct rmidev_data { + int ref_count; + struct cdev main_dev; + struct class *device_class; + struct mutex file_mutex; + struct rmidev_handle *rmi_dev; + struct remotepanel_data *pdata; +}; + +static struct bin_attribute attr_data = { + .attr = { + .name = "data", + .mode = (S_IRUSR | S_IWUSR), + }, + .size = 0, + .read = rmidev_sysfs_data_show, + .write = rmidev_sysfs_data_store, +}; + +static struct device_attribute attrs[] = { + __ATTR(open, S_IRUSR | S_IWUSR, + NULL, + rmidev_sysfs_open_store), + __ATTR(release, S_IRUSR | S_IWUSR, + NULL, + rmidev_sysfs_release_store), + __ATTR(address, S_IRUSR | S_IWUSR, + NULL, + rmidev_sysfs_address_store), + __ATTR(length, S_IRUSR | S_IWUSR, + NULL, + rmidev_sysfs_length_store), + __ATTR(attn_state, S_IRUSR | S_IWUSR, + rmidev_sysfs_attn_state_show, + NULL), +}; + +static int rmidev_major_num; + +static struct class *rmidev_device_class; + +static struct rmidev_handle *rmidev; + +static struct device *device_ptr; +static struct delayed_work delay_work; + + +static ssize_t rmidev_sysfs_data_show(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + int retval; + unsigned int data_length = rmidev->length; + + if (data_length > (REG_ADDR_LIMIT - rmidev->address)) + data_length = REG_ADDR_LIMIT - rmidev->address; + + if (count < data_length) { + dev_err(device_ptr, + "%s: Not enough space (%zd bytes) in buffer\n", + __func__, count); + return -EINVAL; + } + + if (data_length) { + retval = remote_rmi4_i2c_read( + rmidev->address, + (unsigned char *)buf, + data_length); + if (retval < 0) { + dev_err(device_ptr, + "%s: Failed to read data\n", + __func__); + return retval; + } + } else { + return -EINVAL; + } + + return data_length; +} + +static ssize_t rmidev_sysfs_data_store(struct file *data_file, + struct kobject *kobj, struct bin_attribute *attributes, + char *buf, loff_t pos, size_t count) +{ + int retval; + unsigned int data_length = rmidev->length; + + if (data_length > (REG_ADDR_LIMIT - rmidev->address)) + data_length = REG_ADDR_LIMIT - rmidev->address; + + if (data_length) { + retval = remote_rmi4_i2c_write( + rmidev->address, + (unsigned char *)buf, + data_length); + if (retval < 0) { + dev_err(device_ptr, + "%s: Failed to write data\n", + __func__); + return retval; + } + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t rmidev_sysfs_open_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input != 1) + return -EINVAL; + + remote_rmi4_i2c_enable(false); + dev_dbg(device_ptr, + "%s: Attention interrupt disabled\n", + __func__); + + return count; +} + +static ssize_t rmidev_sysfs_release_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input != 1) + return -EINVAL; + + remote_rmi4_i2c_enable(true); + dev_dbg(device_ptr, + "%s: Attention interrupt enabled\n", + __func__); + + return count; +} + +static ssize_t rmidev_sysfs_address_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input > REG_ADDR_LIMIT) + return -EINVAL; + + rmidev->address = (unsigned short)input; + + return count; +} + +static ssize_t rmidev_sysfs_length_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int input; + + if (sscanf(buf, "%u", &input) != 1) + return -EINVAL; + + if (input > REG_ADDR_LIMIT) + return -EINVAL; + + rmidev->length = input; + + return count; +} + +static ssize_t rmidev_sysfs_attn_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int attn_state; + + attn_state = gpio_get_value(remote_rmi4_get_irq_gpio()); + + return snprintf(buf, PAGE_SIZE, "%d\n", attn_state); +} + +static int remote_rmi4_get_irq_gpio(void) +{ + struct rmidev_data *dev_data = (struct rmidev_data *)rmidev->data; + return dev_data->pdata->irq_gpio; +} + +static struct input_dev *remote_rmi4_get_input(void) +{ + struct rmidev_data *dev_data = (struct rmidev_data *)rmidev->data; + return dev_data->pdata->input_dev; +} + +static struct i2c_client* remote_rmi4_get_i2c_client(void) +{ + struct rmidev_data *dev_data = (struct rmidev_data *)rmidev->data; + return dev_data->pdata->client; +} + +static int remote_rmit_set_page(unsigned int address) { + struct i2c_client* i2c_client = remote_rmi4_get_i2c_client(); + unsigned char retry; + unsigned char *buf = NULL; + struct i2c_msg msg[] = { + { + .addr = i2c_client->addr, + .flags = 0, + .len = 2, + .buf = buf, + } + }; + + buf = kzalloc(2, GFP_KERNEL | GFP_DMA); + if (!buf) { + pr_err("kzalloc buf failed.\n"); + return -ENOMEM; + } + + buf[0] = 0xff; + buf[1] = ((address >> 8) & 0xFF); + + msg[0].buf = buf; + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(i2c_client->adapter, msg, 1) == 1) { + break; + } + msleep(20); + } + + if (retry == 2) { + kfree(buf); + buf = NULL; + return -EIO; + } + + kfree(buf); + buf = NULL; + + return 0; +} + +static int remote_rmit_put_page(void) +{ + struct i2c_client* i2c_client = remote_rmi4_get_i2c_client(); + unsigned char retry; + unsigned char *buf = NULL; + struct i2c_msg msg[] = { + { + .addr = i2c_client->addr, + .flags = 0, + .len = 2, + .buf = buf, + } + }; + + buf = kzalloc(2, GFP_KERNEL | GFP_DMA); + if (!buf) { + pr_err("kzalloc buf failed.\n"); + return -ENOMEM; + } + + buf[0] = 0xff; + buf[1] = 0x00; + + msg[0].buf = buf; + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(i2c_client->adapter, msg, 1) == 1) { + break; + } + msleep(20); + } + + if (retry == 2) { + kfree(buf); + buf = NULL; + return -EIO; + } + + kfree(buf); + buf = NULL; + + return 0; +} + +int remote_rmi4_i2c_read(unsigned short addr, unsigned char *data, unsigned short length) +{ + int retval; + unsigned char retry; + unsigned char *buf = NULL; + unsigned char *read_buf = NULL; + struct i2c_client* i2c_client = remote_rmi4_get_i2c_client(); + struct i2c_msg msg[] = { + { + .addr = i2c_client->addr, + .flags = 0, + .len = 1, + .buf = buf, + }, + { + .addr = i2c_client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = read_buf, + }, + }; + + buf = kzalloc(1, GFP_KERNEL | GFP_DMA); + if (!buf) { + pr_err("kzalloc buf failed.\n"); + return -ENOMEM; + } + + read_buf = kzalloc(length, GFP_KERNEL | GFP_DMA); + if (!read_buf) { + pr_err("kzalloc read_buf failed.\n"); + kfree(buf); + buf = NULL; + return -ENOMEM; + } + + *buf = addr & 0xff; + + msg[0].buf = buf; + msg[1].buf = read_buf; + + retval = remote_rmit_set_page(addr); + if (retval < 0) + goto exit; + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(i2c_client->adapter, msg, 2) == 2) { + retval = length; + break; + } + msleep(20); + } + + if (retry == 2) { + retval = -EIO; + goto exit; + } + + memcpy(data, read_buf, length); + +exit: + kfree(buf); + buf = NULL; + kfree(read_buf); + read_buf = NULL; + remote_rmit_put_page(); + + return retval; +} + +int remote_rmi4_i2c_write(unsigned short addr, unsigned char *data, unsigned short length) +{ + int retval; + unsigned char retry; + unsigned char *buf = NULL; + struct i2c_client* i2c_client = remote_rmi4_get_i2c_client(); + struct i2c_msg msg[] = { + { + .addr = i2c_client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf = kzalloc(length + 1, GFP_KERNEL | GFP_DMA); + if (buf == NULL) { + pr_err("buf info kzalloc error\n"); + return -ENOMEM; + } + msg[0].buf = buf; + retval = remote_rmit_set_page(addr); + if (retval < 0) + goto exit; + + buf[0] = addr & 0xff; + memcpy(&buf[1], &data[0], length); + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(i2c_client->adapter, msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + msleep(10); + if (retry == 2) { + kfree(buf); + buf = NULL; + retval = -EIO; + } + +exit: + remote_rmit_put_page(); + kfree(buf); + buf = NULL; + + return retval; +} + +int remote_rmi4_i2c_enable(bool enable) +{ + struct rmidev_data *dev_data = (struct rmidev_data *)rmidev->data; + + if (enable) { + *(dev_data->pdata->enable_remote) = 0; + }else{ + *(dev_data->pdata->enable_remote) = 1; + } + return 0 ; +} + + +/* + * rmidev_llseek - used to set up register address + * + * @filp: file structure for seek + * @off: offset + * if whence == SEEK_SET, + * high 16 bits: page address + * low 16 bits: register address + * if whence == SEEK_CUR, + * offset from current position + * if whence == SEEK_END, + * offset from end position (0xFFFF) + * @whence: SEEK_SET, SEEK_CUR, or SEEK_END + */ +static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence) +{ + loff_t newpos; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { + pr_err("%s: Pointer of char device data is invalid", __func__); + return -EBADF; + } + + + mutex_lock(&(dev_data->file_mutex)); + + switch (whence) { + case SEEK_SET: + newpos = off; + break; + case SEEK_CUR: + newpos = filp->f_pos + off; + break; + case SEEK_END: + newpos = REG_ADDR_LIMIT + off; + break; + default: + newpos = -EINVAL; + goto clean_up; + } + + if (newpos < 0 || newpos > REG_ADDR_LIMIT) { + dev_err(device_ptr, + "%s: New position 0x%04x is invalid\n", + __func__, (unsigned int)newpos); + newpos = -EINVAL; + goto clean_up; + } + + filp->f_pos = newpos; + +clean_up: + mutex_unlock(&(dev_data->file_mutex)); + + return newpos; +} + +/* + * rmidev_read: - use to read data from rmi device + * + * @filp: file structure for read + * @buf: user space buffer pointer + * @count: number of bytes to read + * @f_pos: offset (starting register address) + */ +static ssize_t rmidev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + ssize_t retval; + unsigned char *tmpbuf = NULL; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { + pr_err("%s: Pointer of char device data is invalid", __func__); + return -EBADF; + } + + if (count == 0) + return 0; + + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + + tmpbuf = kzalloc(count + 1, GFP_KERNEL); + if(tmpbuf == NULL) { + pr_err("buf info kzalloc error\n"); + return -ENOMEM; + } + + mutex_lock(dev_data->pdata->pmutex); + mutex_lock(&(dev_data->file_mutex)); + + retval = remote_rmi4_i2c_read( + *f_pos, + tmpbuf, + count); + if (retval < 0) + goto clean_up; + + if (copy_to_user(buf, tmpbuf, count)) + retval = -EFAULT; + else + *f_pos += retval; + +clean_up: + mutex_unlock(&(dev_data->file_mutex)); + mutex_unlock(dev_data->pdata->pmutex); + kfree(tmpbuf); + tmpbuf = NULL; + + return retval; +} + +/* + * rmidev_write: - used to write data to rmi device + * + * @filep: file structure for write + * @buf: user space buffer pointer + * @count: number of bytes to write + * @f_pos: offset (starting register address) + */ +static ssize_t rmidev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + ssize_t retval; + unsigned char *tmpbuf = NULL; + struct rmidev_data *dev_data = filp->private_data; + + if (IS_ERR(dev_data)) { + pr_err("%s: Pointer of char device data is invalid", __func__); + return -EBADF; + } + + if (count == 0) + return 0; + + if (count > (REG_ADDR_LIMIT - *f_pos)) + count = REG_ADDR_LIMIT - *f_pos; + + tmpbuf = kzalloc(count + 1, GFP_KERNEL); + if(tmpbuf == NULL) { + pr_err("buf info kzalloc error\n"); + return -ENOMEM; + } + + if (copy_from_user(tmpbuf, buf, count)) { + retval = -EFAULT; + goto clean_up; + } + + mutex_lock(dev_data->pdata->pmutex); + mutex_lock(&(dev_data->file_mutex)); + + retval = remote_rmi4_i2c_write( + *f_pos, + tmpbuf, + count); + if (retval >= 0) + *f_pos += retval; + + mutex_unlock(&(dev_data->file_mutex)); + mutex_unlock(dev_data->pdata->pmutex); + +clean_up: + kfree(tmpbuf); + tmpbuf = NULL; + return retval; +} + +static int rmidev_create_attr(bool create) { + int retval = 0; + unsigned char attr_count; + struct input_dev *input_dev = remote_rmi4_get_input(); + + if (!create) + goto err_sysfs_attrs ; + + if (rmidev->sysfs_dir) + return 0 ; + + if (!input_dev) + return -1; + /* + retval = gpio_export(remote_rmi4_get_irq_gpio(), false); + if (retval < 0) { + dev_err(device_ptr, + "%s: Failed to export attention gpio\n", + __func__); + } else { + retval = gpio_export_link(&(input_dev->dev), + "attn", remote_rmi4_get_irq_gpio()); + if (retval < 0) { + dev_err(device_ptr, + "%s Failed to create gpio symlink\n", + __func__); + } + } + */ + rmidev->sysfs_dir = kobject_create_and_add("rmidev", + &input_dev->dev.kobj); + if (!rmidev->sysfs_dir) { + dev_err(device_ptr, + "%s: Failed to create sysfs directory\n", __func__); + return -1; + } + + retval = sysfs_create_bin_file(rmidev->sysfs_dir, + &attr_data); + if (retval < 0) { + dev_err(device_ptr, + "%s: Failed to create sysfs bin file\n", + __func__); + goto err_sysfs_bin; + } + + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + retval = sysfs_create_file(rmidev->sysfs_dir, &attrs[attr_count].attr); + if (retval < 0) { + dev_err(device_ptr, + "%s: Failed to create sysfs attributes\n", __func__); + retval = -ENODEV; + goto err_sysfs_attrs; + } + } + + return 0 ; + +err_sysfs_attrs: + if (!rmidev->sysfs_dir) + return 0 ; + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { + sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr); + } + + sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data); + +err_sysfs_bin: + kobject_put(rmidev->sysfs_dir); + rmidev->sysfs_dir = NULL; + + return retval; +} + +/* + * rmidev_open: enable access to rmi device + * @inp: inode struture + * @filp: file structure + */ +static int rmidev_open(struct inode *inp, struct file *filp) +{ + int retval = 0; + struct rmidev_data *dev_data = + container_of(inp->i_cdev, struct rmidev_data, main_dev); + + rmidev_create_attr(true); + + filp->private_data = dev_data; + + mutex_lock(&(dev_data->file_mutex)); + *(dev_data->pdata->enable_remote) = 1; + //remote_rmi4_i2c_enable(false); + dev_dbg(device_ptr, + "%s: Attention interrupt disabled\n", __func__); + disable_irq_nosync(dev_data->pdata->irq); + + if (dev_data->ref_count < 1) + dev_data->ref_count++; + else + retval = -EACCES; + + mutex_unlock(&(dev_data->file_mutex)); + + return retval; +} + +/* + * rmidev_release: - release access to rmi device + * @inp: inode structure + * @filp: file structure + */ +static int rmidev_release(struct inode *inp, struct file *filp) +{ + struct rmidev_data *dev_data = + container_of(inp->i_cdev, struct rmidev_data, main_dev); + + rmidev_create_attr(false); + + mutex_lock(&(dev_data->file_mutex)); + + dev_data->ref_count--; + if (dev_data->ref_count < 0) + dev_data->ref_count = 0; + + remote_rmi4_i2c_enable(true); + dev_dbg(device_ptr, + "%s: Attention interrupt enabled\n", __func__); + enable_irq(dev_data->pdata->irq); + mutex_unlock(&(dev_data->file_mutex)); + + return 0; +} + +static const struct file_operations rmidev_fops = { + .owner = THIS_MODULE, + .llseek = rmidev_llseek, + .read = rmidev_read, + .write = rmidev_write, + .open = rmidev_open, + .release = rmidev_release, +}; + +static void rmidev_device_cleanup(struct rmidev_data *dev_data) +{ + dev_t devno; + + if (dev_data) { + devno = dev_data->main_dev.dev; + + if (dev_data->device_class) + device_destroy(dev_data->device_class, devno); + + cdev_del(&dev_data->main_dev); + unregister_chrdev_region(devno, 1); + remote_free_panel_data(dev_data->pdata); + + dev_dbg(device_ptr, + "%s: rmidev device removed\n", __func__); + } + + return; +} + +static char *rmi_char_devnode(struct device *dev, umode_t *mode) +{ + if (!mode) + return NULL; + + *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + + return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev)); +} + +static int rmidev_create_device_class(void) +{ + rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME); + + if (IS_ERR(rmidev_device_class)) { + pr_err("%s: Failed to create /dev/%s\n", + __func__, CHAR_DEVICE_NAME); + return -ENODEV; + } + + rmidev_device_class->devnode = rmi_char_devnode; + + return 0; +} + +static void remote_rmi4_delay_work(struct work_struct *work) { + rmidev_create_attr(true) ; +} + +struct remotepanel_data *remote_alloc_panel_data(void) +{ + if (rmidev) + { + pr_err("%s:remote panel data has alloc already null\n", __func__); + return NULL; + } + + return kzalloc(sizeof(struct remotepanel_data), GFP_KERNEL); +} + +static struct remotepanel_data *remote_free_panel_data(struct remotepanel_data *pdata) +{ + if (pdata) + kfree(pdata); + pdata = NULL; + return NULL; +} + +//int rmidev_init_device(void) +int register_remote_device(struct remotepanel_data *pdata) +{ + int retval; + dev_t dev_no; + struct rmidev_data *dev_data = NULL; + + + if (pdata == NULL) + { + pr_err("%s:pdata is null\n", __func__); + return -1; + } + if (rmidev) + { + pr_err("%s:remote device has register already null\n", __func__); + return -1; + } + rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL); + if (!rmidev) { + retval = -ENOMEM; + goto err_rmidev; + } + + retval = rmidev_create_device_class(); + if (retval < 0) { + goto err_device_class; + } + + if (rmidev_major_num) { + dev_no = MKDEV(rmidev_major_num, DEV_NUMBER); + retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME); + if (retval < 0) { + goto err_device_region; + } + } else { + retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME); + if (retval < 0) { + goto err_device_region; + } + + rmidev_major_num = MAJOR(dev_no); + } + + dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL); + if (!dev_data) { + retval = -ENOMEM; + goto err_dev_data; + } + + dev_data->pdata = pdata; + + mutex_init(&dev_data->file_mutex); + dev_data->rmi_dev = rmidev; + rmidev->data = dev_data; + + cdev_init(&dev_data->main_dev, &rmidev_fops); + + retval = cdev_add(&dev_data->main_dev, dev_no, 1); + if (retval < 0) { + goto err_char_device; + } + + dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no)); + dev_data->device_class = rmidev_device_class; + + device_ptr = device_create(dev_data->device_class, NULL, dev_no, + NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no)); + if (IS_ERR(device_ptr)) { + dev_err(device_ptr, + "%s: Failed to create rmi char device\n", __func__); + retval = -ENODEV; + goto err_char_device; + } + + INIT_DELAYED_WORK(&delay_work, remote_rmi4_delay_work); + schedule_delayed_work(&delay_work, msecs_to_jiffies(8*1000)); + + return 0; + +err_char_device: + remote_free_panel_data(dev_data->pdata); + rmidev_device_cleanup(dev_data); + kfree(dev_data); + +err_dev_data: + unregister_chrdev_region(dev_no, 1); + +err_device_region: + class_destroy(rmidev_device_class); + +err_device_class: + kfree(rmidev); + rmidev = NULL; +err_rmidev: + return retval; +} + +//void rmidev_remove_device(void) +void unregister_remote_device(void) +{ + struct rmidev_data *dev_data; + + if (!rmidev) + return; + + dev_data = rmidev->data; + if (dev_data) { + rmidev_device_cleanup(dev_data); + kfree(dev_data); + } + + unregister_chrdev_region(rmidev->dev_no, 1); + + class_destroy(rmidev_device_class); + + kfree(rmidev); + + return; +} + +/* + static int __init rmidev_module_init(void) + { + rmidev_init_device(); + + return 0; + } + + static void __exit rmidev_module_exit(void) + { + rmidev_remove_device(); + + return; + } + + module_init(rmidev_module_init); + module_exit(rmidev_module_exit); + + MODULE_AUTHOR("Synaptics, Inc."); + MODULE_DESCRIPTION("Synaptics DSX RMI Dev Module"); + MODULE_LICENSE("GPL v2"); + */ + diff --git a/drivers/oneplus/input/touchscreen/synaptics/synaptics_touch_panel_remote.h b/drivers/oneplus/input/touchscreen/synaptics/synaptics_touch_panel_remote.h new file mode 100755 index 0000000000000000000000000000000000000000..33c89845da7482fda6430299d21a17c3e620942b --- /dev/null +++ b/drivers/oneplus/input/touchscreen/synaptics/synaptics_touch_panel_remote.h @@ -0,0 +1,16 @@ + +#ifndef _SYNAPTICS_REDREMOTE_H_ +#define _SYNAPTICS_REDREMOTE_H_ +struct remotepanel_data{ + struct i2c_client *client; + struct input_dev *input_dev; + // struct input_dev *kpd; + struct mutex *pmutex; + int irq_gpio; + unsigned int irq; + int *enable_remote; +}; +struct remotepanel_data *remote_alloc_panel_data(void); +int register_remote_device(struct remotepanel_data *pdata); +void unregister_remote_device(void); +#endif diff --git a/drivers/oneplus/input/touchscreen/touchpanel_common.h b/drivers/oneplus/input/touchscreen/touchpanel_common.h new file mode 100755 index 0000000000000000000000000000000000000000..c63b27559490914478202162a8e01c16f58fb6fb --- /dev/null +++ b/drivers/oneplus/input/touchscreen/touchpanel_common.h @@ -0,0 +1,721 @@ +/*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : touchpanel_common.h + * + * Function : touchpanel public interface + * + * Version : V1.0 + * + ***********************************************************/ +#ifndef _TOUCHPANEL_COMMON_H_ +#define _TOUCHPANEL_COMMON_H_ + +/*********PART1:Head files**********************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include + + +#include "util_interface/touch_interfaces.h" +#include "tp_devices.h" + +#define EFTM (250) +#define FW_UPDATE_COMPLETE_TIMEOUT msecs_to_jiffies(40*1000) + +/*********PART2:Define Area**********************/ +#define TPD_USE_EINT +#define TYPE_B_PROTOCOL + +#define PAGESIZE 512 +#define MAX_GESTURE_COORD 6 + +#define UnkownGesture 0 +#define DouTap 1 // double tap +#define UpVee 2 // V +#define DownVee 3 // ^ +#define LeftVee 4 // > +#define RightVee 5 // < +#define Circle 6 // O +#define DouSwip 7 // || +#define Left2RightSwip 8 // --> +#define Right2LeftSwip 9 // <-- +#define Up2DownSwip 10 // |v +#define Down2UpSwip 11 // |^ +#define Mgestrue 12 // M +#define Wgestrue 13 // W +#define SingleTap 15 // single tap +#define Sgestrue 14 // S +//just define to pass compile +#define FingerprintDown 16 +#define FingerprintUp 17 + +#define BIT0 (0x1 << 0) +#define BIT1 (0x1 << 1) +#define BIT2 (0x1 << 2) +#define BIT3 (0x1 << 3) +#define BIT4 (0x1 << 4) +#define BIT5 (0x1 << 5) +#define BIT6 (0x1 << 6) +#define BIT7 (0x1 << 7) + +#define FINGERPRINT_DOWN_DETECT 0X0f +#define FINGERPRINT_UP_DETECT 0X1f + +/* bit operation */ +#define SET_BIT(data, flag) ((data) |= (flag)) +#define CLR_BIT(data, flag) ((data) &= ~(flag)) +#define CHK_BIT(data, flag) ((data) & (flag)) +#define VK_TAB {KEY_MENU, KEY_HOMEPAGE, KEY_BACK, KEY_SEARCH} + +#define TOUCH_BIT_CHECK 0x3FF //max support 10 point report.using for detect non-valid points +#define MAX_FW_NAME_LENGTH 60 +#define MAX_EXTRA_NAME_LENGTH 60 +#define MAX_LIMIT_DATA_LENGTH 60 + + +#define MAX_DEVICE_VERSION_LENGTH 16 +#define MAX_DEVICE_MANU_LENGTH 16 + +#define SYNAPTICS_PREFIX "SY_" +#define GOODIX_PREFIX "GT_" +#define FOCAL_PREFIX "FT_" + +#define FW_UPDATE_DELAY msecs_to_jiffies(2*1000) + +/*********PART3:Struct Area**********************/ +typedef enum { + TYPE_DELTA_IDLE, /*means not in reading delta*/ + TYPE_DELTA_BUSY, /*reading delta data*/ +}delta_state; + +typedef enum { + TYPE_PROPERTIES = 1, /*using board_properties*/ + TYPE_AREA_SEPRATE, /*using same IC (button zone && touch zone are seprate)*/ + TYPE_DIFF_IC, /*using diffrent IC (button zone && touch zone are seprate)*/ + TYPE_NO_NEED, /*No need of virtual key process*/ +}vk_type; + +typedef enum { + AREA_NOTOUCH, + AREA_EDGE, + AREA_CRITICAL, + AREA_NORMAL, + AREA_CORNER, +}touch_area; + +typedef enum { + CORNER_TOPLEFT, /*When Phone Face you in portrait top left corner*/ + CORNER_TOPRIGHT, /*When Phone Face you in portrait top right corner*/ + CORNER_BOTTOMLEFT, /*When Phone Face you in portrait bottom left corner*/ + CORNER_BOTTOMRIGHT, /*When Phone Face you in portrait 7bottom right corner*/ +}corner_type; + +typedef enum { + MODE_NORMAL, + MODE_SLEEP, + MODE_EDGE, + MODE_GESTURE, + MODE_GLOVE, + MODE_CHARGE, + MODE_WIRELESS_CHARGE, + MODE_GAME, + MODE_EARSENSE, + MODE_PALM_REJECTION, + MODE_FACE_DETECT, + MODE_FACE_CALIBRATE, + MODE_REFRESH_SWITCH, + MODE_TOUCH_HOLD, + MODE_TOUCH_AREA_SWITCH, + MODE_LIMIT_SWITCH, + MODE_GESTURE_SWITCH, + MODE_FINGERPRINT_TEST, + MODE_AUDIO_NOISE, + MODE_REVERSE_WIRELESS_CHARGE, + MODE_WET_DETECT, + MODE_TP_DELTA_PRINT, +}work_mode; + +typedef enum { + HEALTH_NONE, + HEALTH_INTERACTIVE_CLEAR = 1, /*INTERACTIVE SW CLAR DATA*/ + HEALTH_FORMAL_CLEAR, /*FORMAL SW CLAR DATA*/ + HEALTH_UPDATARP, /*trigger chip to update those data*/ + HEALTH_INFO_GET, /*health_monitor node show*/ + HEALTH_LASTEXCP_GET, /*health_monitor node show*/ +} health_ctl; + +typedef enum { + FW_NORMAL, /*fw might update, depend on the fw id*/ + FW_ABNORMAL, /*fw abnormal, need update*/ +}fw_check_state; + +typedef enum { + FW_UPDATE_SUCCESS, + FW_NO_NEED_UPDATE, + FW_UPDATE_ERROR, + FW_UPDATE_FATAL, +}fw_update_state; + +typedef enum { + TP_SUSPEND_EARLY_EVENT, + TP_SUSPEND_COMPLETE, + TP_RESUME_EARLY_EVENT, + TP_RESUME_COMPLETE, + TP_SPEEDUP_RESUME_COMPLETE, +}suspend_resume_state; + +typedef enum IRQ_TRIGGER_REASON { + IRQ_TOUCH = 0x01, + IRQ_GESTURE = 0x02, + IRQ_BTN_KEY = 0x04, + IRQ_EXCEPTION = 0x08, + IRQ_FW_CONFIG = 0x10, + IRQ_DATA_LOGGER = 0x20, + IRQ_FW_HEALTH = 0x20, + IRQ_FW_AUTO_RESET = 0x40, + IRQ_FACE_STATE = 0x80, + IRQ_IGNORE = 0x00, + IRQ_FINGERPRINT = 0x0100, +}irq_reason; + +typedef enum vk_bitmap{ + BIT_reserve = 0x08, + BIT_BACK = 0x04, + BIT_HOME = 0x02, + BIT_MENU = 0x01, +}vk_bitmap; + +typedef enum finger_protect_status { + FINGER_PROTECT_TOUCH_UP, + FINGER_PROTECT_TOUCH_DOWN, + FINGER_PROTECT_NOTREADY, +}fp_touch_state; + +typedef enum debug_level { + LEVEL_BASIC, /*printk basic tp debug info*/ + LEVEL_DEBUG, /*printk all tp debug info*/ + LEVEL_DETAIL, /*printk tp detail log for stress test*/ +}tp_debug_level; + +typedef enum resume_order { + TP_LCD_RESUME, + LCD_TP_RESUME, +}tp_resume_order; + +typedef enum suspend_order { + TP_LCD_SUSPEND, + LCD_TP_SUSPEND, +}tp_suspend_order; + +typedef enum lcd_power { + LCD_POWER_OFF, + LCD_POWER_ON, +}lcd_power_status; + +struct Coordinate { + int x; + int y; +}; + +typedef enum interrupt_mode { + BANNABLE, + UNBANNABLE, + INTERRUPT_MODE_MAX, +}tp_interrupt_mode; + +typedef enum switch_mode_type { + SEQUENCE, + SINGLE, +}tp_switch_mode; + +enum touch_direction { + VERTICAL_SCREEN, + LANDSCAPE_SCREEN_90, + LANDSCAPE_SCREEN_270, +}; + +struct gesture_info { + uint32_t gesture_type; + uint32_t clockwise; + struct Coordinate Point_start; + struct Coordinate Point_end; + struct Coordinate Point_1st; + struct Coordinate Point_2nd; + struct Coordinate Point_3rd; + struct Coordinate Point_4th; +}; + +struct fp_underscreen_info { + uint8_t touch_state; + uint8_t area_rate; + uint16_t x; + uint16_t y; +}; + +struct point_info { + uint16_t x; + uint16_t y; + uint16_t z; + uint8_t width_major; + uint8_t touch_major; + uint8_t status; + touch_area type; + //just defined to pass compilation + uint8_t tx_press; + uint8_t rx_press; +}; + +/* add haptic audio tp mask */ +struct shake_point { + uint16_t x; + uint16_t y; + uint8_t status; +}; + +struct corner_info { + uint8_t id; + bool flag; + struct point_info point; +}; + +struct manufacture_info { + char *version; + char *manufacture; +}; + +struct panel_info { + char *fw_name; /*FW name*/ + char *test_limit_name; /*test limit name*/ + char *extra; /*for some ic, may need other information*/ + const char *chip_name; /*chip name the panel is controlled by*/ + const char *project_name; /*project_name*/ + uint32_t TP_FW; /*FW Version Read from IC*/ + tp_dev tp_type; + struct manufacture_info manufacture_info; /*touchpanel device info*/ +}; + +struct hw_resource { + //gpio + int id1_gpio; + int id2_gpio; + int id3_gpio; + + int irq_gpio; /*irq GPIO num*/ + int reset_gpio; /*Reset GPIO*/ + + int enable2v8_gpio; /*vdd_2v8 enable GPIO*/ + int enable1v8_gpio; /*vcc_1v8 enable GPIO*/ + + //TX&&RX Num + int TX_NUM; + int RX_NUM; + int key_TX; /*the tx num occupied by touchkey*/ + int key_RX; /*the rx num occupied by touchkey*/ + int EARSENSE_TX_NUM; /*for earsense function data reading*/ + int EARSENSE_RX_NUM; /*for earsense function data reading*/ + + //power + struct regulator *vdd_2v8; /*power 2v8*/ + struct regulator *vcc_1v8; /*power 1v8*/ + uint32_t vdd_volt; /*avdd specific volt*/ + + //pinctrl + struct pinctrl *pinctrl; + struct pinctrl_state *pin_set_high; + struct pinctrl_state *pin_set_low; +}; + +struct edge_limit { + int limit_area; + int left_x1; + int right_x1; + int left_x2; + int right_x2; + int left_x3; + int right_x3; + int left_y1; + int right_y1; + int left_y2; + int right_y2; + int left_y3; + int right_y3; + touch_area in_which_area; +}; + +struct touch_major_limit { + int width_range; + int height_range; +}; + +struct button_map { + int width_x; /*width of each key area */ + int height_y; /*height of each key area*/ + struct Coordinate coord_menu; /*Menu centre coordinates*/ + struct Coordinate coord_home; /*Home centre coordinates*/ + struct Coordinate coord_back; /*Back centre coordinates*/ +}; + +struct resolution_info { + uint32_t max_x; /*touchpanel width */ + uint32_t max_y; /*touchpanel height*/ + uint32_t LCD_WIDTH; /*LCD WIDTH */ + uint32_t LCD_HEIGHT; /*LCD HEIGHT */ +}; + +struct esd_information { + bool esd_running_flag; + int esd_work_time; + struct mutex esd_lock; + struct workqueue_struct *esd_workqueue; + struct delayed_work esd_check_work; +}; + +struct spurious_fp_touch { + bool fp_trigger; /*thread only turn into runnning state by fingerprint kick proc/touchpanel/finger_protect_trigger*/ + bool lcd_resume_ok; + bool lcd_trigger_fp_check; + fp_touch_state fp_touch_st; /*provide result to fingerprint of touch status data*/ + struct task_struct *thread; /*tread use for fingerprint susprious touch check*/ +}; + +struct register_info { + uint8_t reg_length; + uint16_t reg_addr; + uint8_t * reg_result; +}; + +struct black_gesture_test { + bool gesture_backup; /*store the gesture enable flag */ + bool flag; /* indicate do black gesture test or not*/ + char *message; /* failure information if gesture test failed */ +}; +struct monitor_data { + unsigned long monitor_down; + unsigned long monitor_up; + health_ctl ctl_type; + + int bootup_test; + int repeat_finger; + int miss_irq; + int grip_report; + int baseline_err; + int noise_count; + int shield_palm; + int shield_edge; + int shield_metal; + int shield_water; + int shield_esd; + int hard_rst; + int inst_rst; + int parity_rst; + int wd_rst; + int other_rst; + int reserve1; + int reserve2; + int reserve3; + int reserve4; + int reserve5; + + int fw_download_retry; + int fw_download_fail; + + int eli_size; + int eli_ver_range; + int eli_hor_range; + int *eli_ver_pos; + int *eli_hor_pos; +}; + +struct debug_info_proc_operations; +struct earsense_proc_operations; +struct touchpanel_data { + bool register_is_16bit; /*register is 16bit*/ + bool glove_mode_support; /*glove_mode support feature*/ + bool black_gesture_support; /*black_gesture support feature*/ + bool charger_pump_support; /*charger_pump support feature*/ + bool edge_limit_support; /*edge_limit support feature*/ + bool esd_handle_support; /*esd handle support feature*/ + bool spurious_fp_support; /*avoid fingerprint spurious trrigger feature*/ + bool gesture_test_support; /*indicate test black gesture or not*/ + bool game_switch_support; /*indicate game switch support or not*/ + bool ear_sense_support; /*touch porximity function*/ + bool smart_gesture_support; /*feature used to controltouch_major report*/ + bool face_detect_support; /*touch porximity function*/ + bool lcd_refresh_rate_switch; /*switch lcd refresh rate 60-90hz*/ + bool touch_hold_support; /*touchhold function for fingerprint*/ + + bool audio_noise_detect; /*support audio_noise_detect*/ + bool audio_noise_support; + bool charge_detect; + bool charge_detect_support; + bool wireless_charge_detect; /*suppor wireless_charge_detect*/ + bool wireless_charge_support; + bool module_id_support; /*update firmware by lcd module id*/ + bool i2c_ready; /*i2c resume status*/ + bool is_usb_checked; /*state of charger or usb*/ + bool loading_fw; /*touchpanel FW updating*/ + bool is_incell_panel; /*touchpanel is incell*/ + bool is_noflash_ic; /*noflash ic*/ + bool has_callback; /*whether have callback method to invoke common*/ + bool use_resume_notify; /*notify speed resume process*/ + bool fw_update_app_support; /*bspFwUpdate is used*/ + bool health_monitor_support; + bool in_test_process; /*flag whether in test process*/ + u8 vk_bitmap ; /*every bit declear one state of key "reserve(keycode)|home(keycode)|menu(keycode)|back(keycode)"*/ + vk_type vk_type; /*virtual_key type*/ + delta_state delta_state; + + uint32_t irq_flags; /*irq setting flag*/ + int irq; /*irq num*/ + bool skip_enable_touchhold; + int gesture_enable; /*control state of black gesture*/ + int palm_enable; + int es_enable; + int fd_enable; + int fd_calibrate; + int fp_enable; + int lcd_refresh_rate; + bool project_info; /*different project using different parameter*/ + + int touch_hold_enable; + int touch_area_switch; + int touch_count; + int glove_enable; /*control state of glove gesture*/ + int limit_enable; /*control state of limit ebale */ + int limit_edge; /*control state of limit edge*/ + int limit_corner; /*control state of limit corner*/ + int is_suspended; /*suspend/resume flow exec flag*/ + int corner_delay_up; /*corner mode flag*/ + suspend_resume_state suspend_state; /*detail suspend/resume state*/ + + int boot_mode; /*boot up mode */ + int view_area_touched; /*view area touched flag*/ + int force_update; /*force update flag*/ + int max_num; /*max muti-touch num supportted*/ + int irq_slot; /*debug use, for print all finger's first touch log*/ + int firmware_update_type; /*firmware_update_type: 0=check firmware version 1=force update; 2=for FAE debug*/ + int dead_zone_l; /*landscape dead zone*/ + int dead_zone_p; /*portrait dead zone*/ + int corner_dead_zone_xl; + int corner_dead_zone_yl; + int corner_dead_zone_xp; + int corner_dead_zone_yp; + tp_resume_order tp_resume_order; + tp_suspend_order tp_suspend_order; + tp_interrupt_mode int_mode; /*whether interrupt and be disabled*/ + tp_switch_mode mode_switch_type; /*used for switch mode*/ + bool skip_reset_in_resume; /*some incell ic is reset by lcd reset*/ + bool skip_suspend_operate; /*LCD and TP is in one chip,lcd power off in suspend at first, + can not operate i2c when tp suspend*/ + bool ps_status; /*save ps status, ps near = 1, ps far = 0*/ + int noise_level; /*save ps status, ps near = 1, ps far = 0*/ + bool gesture_switch; /*gesture mode close or open gesture*/ + bool reject_point; /*reject point for sensor*/ + bool fingerprint_int_test; /*fingerprint int pin test*/ + u8 limit_switch; /*0 is phone up 1 is crosswise*/ + u8 touchold_event; /*0 is touchhold down 1 is up*/ + bool reverse_charge_status; /*reverse charge status*/ + bool wet_mode_status; /*wet mode status*/ + bool kernel_grip_support; /* just defined to pass compilation */ + bool kernel_grip_support_special; + bool report_flow_unlock_support; /*report flow is unlock, need to lock when all touch release*/ + bool game_mode_status; /*status of game mode*/ +#if defined(TPD_USE_EINT) + struct hrtimer timer; /*using polling instead of IRQ*/ +#endif + //#if defined(CONFIG_FB) + struct notifier_block fb_notif; /*register to control suspend/resume*/ + //#endif + struct monitor_data monitor_data; + struct notifier_block reverse_charge_notif; /*register to control noise mode when reverse_charge*/ + struct notifier_block tp_delta_print_notif; /*register to print tp delta*/ + struct mutex mutex; /*mutex for lock i2c related flow*/ + struct mutex report_mutex; /*mutex for lock input report flow*/ + struct mutex mutex_earsense; + struct completion pm_complete; /*completion for control suspend and resume flow*/ + struct completion fw_complete; /*completion for control fw update*/ + struct completion resume_complete; /*completion for control fw update*/ + struct panel_info panel_data; /*GPIO control(id && pinctrl && tp_type)*/ + struct hw_resource hw_res; /*hw resourc information*/ + struct edge_limit edge_limit; /*edge limit*/ + struct button_map button_map; /*virtual_key button area*/ + struct resolution_info resolution_info; /*resolution of touchpanel && LCD*/ + struct gesture_info gesture; /*gesture related info*/ + struct touch_major_limit touch_major_limit; /*used for control touch major reporting area*/ + struct fp_underscreen_info fp_info; /*tp info used for underscreen fingerprint*/ + + struct work_struct speed_up_work; /*using for speedup resume*/ + struct workqueue_struct *speedup_resume_wq; /*using for touchpanel speedup resume wq*/ + + struct work_struct read_delta_work; /*using for read delta*/ + struct workqueue_struct *delta_read_wq; + + struct work_struct async_work; + struct workqueue_struct *async_workqueue; + struct work_struct fw_update_work; /*using for fw update*/ + struct delayed_work work_read_info; /*using for print more rawdata when probe*/ + struct wakeup_source *source; + + + struct esd_information esd_info; + struct spurious_fp_touch spuri_fp_touch; /*spurious_finger_support*/ + + struct device *dev; /*used for i2c->dev*/ + struct i2c_client *client; + struct spi_device *s_client; + struct input_dev *input_dev; + struct input_dev *kpd_input_dev; + + struct touchpanel_operations *ts_ops; /*call_back function*/ + struct proc_dir_entry *prEntry_tp; /*struct proc_dir_entry of "/proc/touchpanel"*/ + struct proc_dir_entry *prEntry_debug_tp; /*struct proc_dir_entry of "/proc/touchpanel/debug_info"*/ + struct debug_info_proc_operations *debug_info_ops; /*debug info data*/ + struct earsense_proc_operations *earsense_ops; + struct register_info reg_info; /*debug node for register length*/ + struct black_gesture_test gesture_test; /*gesture test struct*/ + + void *chip_data; /*Chip Related data*/ + void *private_data; /*Reserved Private data*/ + char *earsense_delta; +}; + +struct touchpanel_operations { + int (*ftm_process) (void *chip_data); + void (*ftm_process_extra) (void); + void (*get_util_vendor) (struct hw_resource *hw_res,struct panel_info *panel_data); + void (*gt_health_report) (void *chip_data, struct monitor_data *mon_data); +// u32 (*u32_trigger_reason) (void *chip_data, int gesture_enable, int is_suspended); +// void (*enable_fingerprint) (void *chip_data, uint32_t enable); +// void (*enable_gesture_mask) (void *chip_data, uint32_t enable); +// void (*screenon_fingerprint_info) (void *chip_data, struct fp_underscreen_info *fp_tpinfo); +// void (*set_touch_direction) (void *chip_data, uint8_t dir); +// u8 (*get_touch_direction) (void *chip_data); + void (*health_report_1) (void *chip_data, struct monitor_data *mon_data); +// int (*enable_single_tap) (void *chip_data, bool enable); + int (*get_chip_info) (void *chip_data); /*return 0:success;other:failed*/ + int (*mode_switch) (void *chip_data, work_mode mode, bool flag); /*return 0:success;other:failed*/ + int (*get_touch_points) (void *chip_data, struct point_info *points, int max_num); /*return point bit-map*/ + int (*get_gesture_info) (void *chip_data, struct gesture_info * gesture); /*return 0:success;other:failed*/ + int (*get_vendor) (void *chip_data, struct panel_info *panel_data); /*distingush which panel we use, (TRULY/OFLIM/BIEL/TPK)*/ + int (*reset) (void *chip_data); /*Reset Touchpanel*/ + int (*reinit_device) (void *chip_data); + fw_check_state (*fw_check) (void *chip_data, struct resolution_info *resolution_info, + struct panel_info *panel_data); /*return < 0 :failed; 0 sucess*/ + fw_update_state (*fw_update) (void *chip_data, const struct firmware *fw, bool force); /*return 0 normal; return -1:update failed;*/ + int (*power_control) (void *chip_data, bool enable); /*return 0:success;other:abnormal, need to jump out*/ + int (*reset_gpio_control) (void *chip_data, bool enable); /*used for reset gpio*/ + u8 (*trigger_reason) (void *chip_data, int gesture_enable, int is_suspended); /*clear innterrupt reg && detect irq trigger reason*/ + u32 (*u32_trigger_reason) (void *chip_data, int gesture_enable, int is_suspended); + u8 (*get_keycode) (void *chip_data); /*get touch-key code*/ + int (*esd_handle) (void *chip_data); + int (*fw_handle) (void *chip_data); /*return 0 normal; return -1:update failed;*/ + void (*resume_prepare) (void *chip_data); /*using for operation before resume flow, +eg:incell 3320 need to disable gesture to release inter pins for lcd resume*/ + fp_touch_state (*spurious_fp_check) (void *chip_data); /*spurious fingerprint check*/ + void (*finger_proctect_data_get) (void *chip_data); /*finger protect data get*/ + void (*data_logger_open) (void *chip_data); /*get data logger open status in probe or after fwupdate*/ + void (*data_logger_get) (void *chip_data); /*data logger get*/ + void (*exit_esd_mode) (void *chip_data); /*add for s4322 exit esd mode*/ + void (*register_info_read)(void * chip_data, uint16_t register_addr, uint8_t *result, uint8_t length); /*add for read registers*/ + void (*write_ps_status) (void *chip_data, int ps_status); /*when detect iron plate, if ps is near ,enter iron plate mode;if ps is far, can not enter; exit esd mode when ps is far*/ + void (*specific_resume_operate) (void *chip_data); /*some ic need specific opearation in resuming*/ + int (*get_usb_state) (void); /*get current usb state*/ + void (*black_screen_test) (void *chip_data, char *msg); /*message of black gesture test*/ + int (*irq_handle_unlock) (void *chip_info); /*irq handler without mutex*/ + int (*async_work) (void *chip_info); /*async work*/ + int (*get_face_state) (void *chip_info); /*get face detect state*/ + void (*health_report) (void *chip_data); /*data logger get*/ + //void (*bootup_test) (void *chip_data, const struct firmware *fw, struct monitor_data *mon_data, struct hw_resource *hw_res); /*boot_up test*/ + void (*get_gesture_coord) (void *chip_data, uint32_t gesture_type); + void (*enable_fingerprint) (void *chip_data, uint32_t enable); + void (*enable_gesture_mask) (void *chip_data, uint32_t enable); + void (*set_touch_direction) (void *chip_data, uint8_t dir); + uint8_t (*get_touch_direction) (void *chip_data); + void (*screenon_fingerprint_info) (void *chip_data, struct fp_underscreen_info *fp_tpinfo); /*get gesture info of fingerprint underscreen when screen on*/ + void (*freq_hop_trigger) (void *chip_data); /*trigger frequency-hopping*/ + void (*set_noise_modetest) (void *chip_data, bool enable); + uint8_t (*get_noise_modetest) (void *chip_data); + void (*tp_queue_work_prepare) (void); /*If the tp ic need do something, use this!*/ + int (*set_report_point_first) (void *chip_data, uint32_t enable); + int (*get_report_point_first) (void *chip_data); + //void (*enable_kernel_grip) (void *chip_data, struct kernel_grip_info *grip_info); /*enable kernel grip in fw*/ + int (*enable_single_tap) (void *chip_data, bool enable); + bool (*tp_irq_throw_away) (void *chip_data); + void (*rate_white_list_ctrl) (void *chip_data, int value); + //int (*smooth_lv_set) (void *chip_data, int level); +#ifdef CONFIG_TOUCHPANEL_ALGORITHM + int (*special_points_report) (void *chip_data, struct point_info *points, int max_num); +#endif +}; + +struct debug_info_proc_operations { + void (*limit_read) (struct seq_file *s, struct touchpanel_data *ts); + void (*delta_read) (struct seq_file *s, void *chip_data); + void (*self_delta_read) (struct seq_file *s, void *chip_data); + void (*self_raw_read) (struct seq_file *s, void *chip_data); + void (*baseline_read) (struct seq_file *s, void *chip_data); + void (*baseline_blackscreen_read) (struct seq_file *s, void *chip_data); + void (*main_register_read) (struct seq_file *s, void *chip_data); + void (*reserve_read) (struct seq_file *s, void *chip_data); + void (*abs_doze_read) (struct seq_file *s, void *chip_data); + void (*RT251) (struct seq_file *s, void *chip_data); + void (*RT76) (struct seq_file *s, void *chip_data); + void (*RT254) (struct seq_file *s, void *chip_data); + void (*DRT) (struct seq_file *s, void *chip_data); +}; + +struct invoke_method { + void (*invoke_common)(void); + void (*async_work)(void); +}; + +struct earsense_proc_operations { + void (*rawdata_read) (void *chip_data, char *earsense_baseline, int read_length); + void (*delta_read) (void *chip_data, char *earsense_delta, int read_length); + void (*self_data_read) (void *chip_data, char *earsense_self_data, int read_length); +}; + +/*********PART3:function or variables for other files**********************/ +extern unsigned int tp_debug ; /*using for print debug log*/ + +struct touchpanel_data *common_touch_data_alloc(void); + +int common_touch_data_free(struct touchpanel_data *pdata); +int register_common_touch_device(struct touchpanel_data *pdata); + +void tp_i2c_suspend(struct touchpanel_data *ts); +void tp_i2c_resume (struct touchpanel_data *ts); + +int tp_powercontrol_1v8(struct hw_resource *hw_res, bool on); +int tp_powercontrol_2v8(struct hw_resource *hw_res, bool on); + +void operate_mode_switch (struct touchpanel_data *ts); +void input_report_key_reduce(struct input_dev *dev, unsigned int code, int value); +void esd_handle_switch(struct esd_information *esd_info, bool on); +void clear_view_touchdown_flag(void); +void tp_touch_btnkey_release(void); +void tp_util_get_vendor(struct touchpanel_data *ts, struct panel_info *panel_data); +extern bool tp_judge_ic_match(char * tp_ic_name); +/* add haptic audio tp mask */ +extern int msm_drm_notifier_call_chain(unsigned long val, void *v); +extern int gf_opticalfp_irq_handler(int event); +extern int register_reverse_charge_notifier(struct notifier_block *nb); +extern int unregister_reverse_charge_notifier(struct notifier_block *nb); +extern int register_tp_delta_print_notifier(struct notifier_block *nb); +extern int unregister_tp_delta_print_notifier(struct notifier_block *nb); + +#endif + diff --git a/drivers/oneplus/input/touchscreen/touchpanel_common_driver.c b/drivers/oneplus/input/touchscreen/touchpanel_common_driver.c new file mode 100755 index 0000000000000000000000000000000000000000..297b3a638d363f5370abeeea29af647727984d51 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/touchpanel_common_driver.c @@ -0,0 +1,5833 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef TPD_USE_EINT +#include +#endif + +#ifdef CONFIG_FB +#include +#include +#endif + +//#ifdef CONFIG_DRM_MSM +//#include +#include +//#endif + +#include "touchpanel_common.h" +#include "samsung/s6sy761/sec_drivers_s6sy761.h" +#include "util_interface/touch_interfaces.h" + +/*******Part0:LOG TAG Declear************************/ +#define TPD_PRINT_POINT_NUM 150 +#define TPD_DEVICE "touchpanel" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (LEVEL_DEBUG == tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do{\ + if (LEVEL_BASIC != tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_SPECIFIC_PRINT(count, a, arg...)\ + do{\ + if (count++ == TPD_PRINT_POINT_NUM || LEVEL_DEBUG == tp_debug) {\ + TPD_INFO(TPD_DEVICE ": " a, ##arg);\ + count = 0;\ + }\ + }while(0) + +/*******Part1:Global variables Area********************/ +unsigned int tp_debug = 0; +unsigned int tp_register_times = 0; +//unsigned int probe_time = 0; +struct touchpanel_data *g_tp = NULL; +struct point_info *pre_points = NULL; +int tp_1v8_power = 0; +static DECLARE_WAIT_QUEUE_HEAD(waiter); +static struct input_dev *ps_input_dev = NULL; +static int lcd_id = 0; +static int project_code = 0; +static int gesture_switch_value = 0; +struct drm_panel *lcd_active_panel; + + +int sigle_num = 0; +struct timeval tpstart, tpend; +int pointx[2] = {0, 0}; +int pointy[2] = {0, 0}; +#define ABS(a,b) ((a - b > 0) ? a - b : b - a) + +uint8_t DouTap_enable = 0; // double tap +uint8_t UpVee_enable = 0; // V +uint8_t LeftVee_enable = 0; // > +uint8_t RightVee_enable = 0; // < +uint8_t Circle_enable = 0; // O +uint8_t DouSwip_enable = 0; // || +uint8_t Mgestrue_enable = 0; // M +uint8_t Wgestrue_enable = 0; // W +uint8_t Sgestrue_enable = 0; // S +uint8_t SingleTap_enable = 0; // single tap +uint8_t Enable_gesture = 0; + +/*******Part2:declear Area********************************/ +static void speedup_resume(struct work_struct *work); +void esd_handle_switch(struct esd_information *esd_info, bool flag); +int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); + + +#ifdef TPD_USE_EINT +static irqreturn_t tp_irq_thread_fn(int irq, void *dev_id); +#endif + +//#if defined(CONFIG_FB) || defined(CONFIG_DRM_MSM) +static int tfb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +//#endif +static int reverse_charge_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +static int tp_delta_print_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +static void tp_touch_release(struct touchpanel_data *ts); +static void tp_btnkey_release(struct touchpanel_data *ts); +static void tp_fw_update_work(struct work_struct *work); +static int init_debug_info_proc(struct touchpanel_data *ts); +static void tp_work_func(struct touchpanel_data *ts); +__attribute__((weak)) int request_firmware_select(const struct firmware **firmware_p, const char *name, struct device *device) {return 1;} +__attribute__((weak)) int register_devinfo(char *name, struct manufacture_info *info) {return 1;} +__attribute__((weak)) int preconfig_power_control(struct touchpanel_data *ts) {return 0;} +__attribute__((weak)) int reconfig_power_control(struct touchpanel_data *ts) {return 0;} + +static int __init get_cmdlinelcd_id(char *str) +{ + TPD_INFO("%s enter %s\n", __func__, str); + if (str) { + if (strncmp(str, "qcom,mdss_dsi_samsung_oneplus_dsc_cmd:", 33) == 0) { //using 18821 TP + lcd_id = 0; + } else if (strncmp(str, "qcom,mdss_dsi_samsung_ana6706_dsc_cmd:", 33) == 0) { //using 19811 TP + lcd_id = 1; + } + } + return 0; +} +__setup("msm_drm.dsi_display0=", get_cmdlinelcd_id); + + +int check_touchirq_triggerd(void) +{ + int value = -1; + + if (!g_tp) { + return 0; + } + if (!g_tp->gesture_enable) { + return 0; + } + value = gpio_get_value(g_tp->hw_res.irq_gpio); + if ((value == 0) && (g_tp->irq_flags & IRQF_TRIGGER_LOW)) { + return 1; + } + + return 0; +} + +/*******Part3:Function Area********************************/ +/** + * operate_mode_switch - switch work mode based on current params + * @ts: touchpanel_data struct using for common driver + * + * switch work mode based on current params(gesture_enable, limit_enable, glove_enable) + * Do not care the result: Return void type + */ +void operate_mode_switch(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->mode_switch) { + TPD_INFO("not support ts_ops->mode_switch callback\n"); + return; + } + + TPD_INFO("%s:enter", __func__); + + if (ts->is_suspended) { + if (ts->game_switch_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_GAME, false); + + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, true); + if (ts->mode_switch_type == SEQUENCE) + ts->ts_ops->mode_switch(ts->chip_data, MODE_NORMAL, true); + //if (ts->touch_hold_support){ + // if(ts->ts_ops->enable_fingerprint){ + // ts->ts_ops->enable_fingerprint(ts->chip_data, ts->touch_hold_enable); + // } + //} + } else { + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, false); + if (ts->mode_switch_type == SEQUENCE) + ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + } + } else + ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + } else { + if (ts->ear_sense_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, ts->es_enable == 1); + ts->ts_ops->mode_switch(ts->chip_data, MODE_PALM_REJECTION, ts->palm_enable); + } + + if (ts->face_detect_support) { + //ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, ts->fd_enable == 1); + } + + //if (ts->touch_hold_support) { + // if(ts->ts_ops->enable_fingerprint){ + // ts->ts_ops->enable_fingerprint(ts->chip_data, ts->touch_hold_enable); + // } + //} + if (ts->mode_switch_type == SEQUENCE) { + if (ts->black_gesture_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, false); + } + if (ts->edge_limit_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_EDGE, ts->limit_edge); + + if (ts->glove_mode_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_GLOVE, ts->glove_enable); + + if (ts->charge_detect_support) { + if (ts->charge_detect == 1)//if in charge status,enable charge mode + ts->ts_ops->mode_switch(ts->chip_data, MODE_CHARGE, true); + } + if (ts->wireless_charge_support) { + if (ts->wireless_charge_detect == 1)//if in wireless sstatus, enable wireless mode + ts->ts_ops->mode_switch(ts->chip_data, MODE_WIRELESS_CHARGE, true); + } + if (ts->touch_hold_support) + if (!ts->skip_enable_touchhold)//fingerprint is lock, enable touchhold when resume. + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_HOLD, ts->touch_hold_enable); + + if (ts->reverse_charge_status) + ts->ts_ops->mode_switch(ts->chip_data, MODE_REVERSE_WIRELESS_CHARGE, ts->reverse_charge_status); + + if (ts->audio_noise_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_AUDIO_NOISE, ts->audio_noise_detect); + + if (ts->wet_mode_status) + ts->ts_ops->mode_switch(ts->chip_data, MODE_WET_DETECT, ts->wet_mode_status); + + ts->ts_ops->mode_switch(ts->chip_data, MODE_LIMIT_SWITCH, ts->limit_switch); + + ts->ts_ops->mode_switch(ts->chip_data, MODE_NORMAL, true); + } +} + +static void tp_touch_down(struct touchpanel_data *ts, struct point_info points, int touch_report_num, int id) +{ + static int last_width_major; + static int point_num = 0; + + if (ts->input_dev == NULL) + return; + + input_report_key(ts->input_dev, BTN_TOUCH, 1); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 1); +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (ts->boot_mode == RECOVERY_BOOT) +#else + if (ts->boot_mode == MSM_BOOT_MODE_RECOVERY) +#endif + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, points.z); + else { + if (touch_report_num == 1) { + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, points.width_major); + last_width_major = points.width_major; + } else if (!(touch_report_num & 0x7f) || touch_report_num == 30) { //avoid same point info getevent cannot report + //if touch_report_num == 127, every 127 points, change width_major + //down and keep long time, auto repeat per 5 seconds, for weixing + //report move event after down event, for weixing voice delay problem, 30 -> 300ms in order to avoid the intercept by shortcut + if (last_width_major == points.width_major) + last_width_major = points.width_major + 1; + else + last_width_major = points.width_major; + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, last_width_major); + } + if (ts->smart_gesture_support && (points.touch_major > 0x12) &&\ + (points.x > ts->touch_major_limit.width_range) && (points.x < ts->resolution_info.max_x - ts->touch_major_limit.width_range) &&\ + (points.y > ts->touch_major_limit.height_range) && (points.y < ts->resolution_info.max_y - ts->touch_major_limit.height_range)) { + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, points.touch_major); + } + if(!CHK_BIT(ts->irq_slot, (1<input_dev, ABS_MT_POSITION_X, points.x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, points.y); + + TPD_SPECIFIC_PRINT(point_num, "Touchpanel id %d :Down[%4d %4d %4d]\n", id, points.x, points.y, points.z); + +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif +} + +static void tp_touch_up(struct touchpanel_data *ts) +{ + if (ts->input_dev == NULL) + return; + + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif +} + +static void tp_exception_handle(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->reset) { + TPD_INFO("not support ts->ts_ops->reset callback\n"); + return; + } + + ts->ts_ops->reset(ts->chip_data); // after reset, all registers set to default + operate_mode_switch(ts); + + tp_btnkey_release(ts); + tp_touch_release(ts); +} + +static void tp_fw_auto_reset_handle(struct touchpanel_data *ts) +{ + TPD_INFO("%s\n", __func__); + + if(ts->ts_ops->write_ps_status) { + ts->ts_ops->write_ps_status(ts->chip_data, ts->ps_status); + + if (!ts->ps_status) { + if (ts->ts_ops->exit_esd_mode) { + ts->ts_ops->exit_esd_mode(ts->chip_data); + } + } + } + + operate_mode_switch(ts); + + tp_btnkey_release(ts); + tp_touch_release(ts); +} + +static void tp_geture_info_transform(struct gesture_info * gesture, struct resolution_info *resolution_info) +{ + gesture->Point_start.x = gesture->Point_start.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_start.y = gesture->Point_start.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_end.x = gesture->Point_end.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_end.y = gesture->Point_end.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_1st.x = gesture->Point_1st.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_1st.y = gesture->Point_1st.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_2nd.x = gesture->Point_2nd.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_2nd.y = gesture->Point_2nd.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_3rd.x = gesture->Point_3rd.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_3rd.y = gesture->Point_3rd.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_4th.x = gesture->Point_4th.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_4th.y = gesture->Point_4th.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); +} + +int sec_double_tap(struct gesture_info *gesture) +{ + uint32_t timeuse = 0; + + if (sigle_num == 0) { + do_gettimeofday(&tpstart); + pointx[0] = gesture->Point_start.x; + pointy[0] = gesture->Point_start.y; + sigle_num ++; + TPD_DEBUG("first enter double tap\n"); + } else if (sigle_num == 1) { + do_gettimeofday(&tpend); + pointx[1] = gesture->Point_start.x; + pointy[1] = gesture->Point_start.y; + sigle_num = 0; + timeuse = 1000000 * (tpend.tv_sec-tpstart.tv_sec) + + tpend.tv_usec-tpstart.tv_usec; + TPD_DEBUG("timeuse = %d, distance[x] = %d, distance[y] = %d\n", timeuse, ABS(pointx[0], pointx[1]), ABS(pointy[0], pointy[1])); + if((ABS(pointx[0], pointx[1]) < 150) && (ABS(pointy[0], pointy[1]) < 200) && (timeuse < 500000)){ + return 1; + }else { + TPD_DEBUG("not match double tap\n"); + do_gettimeofday(&tpstart); + pointx[0] = gesture->Point_start.x; + pointy[0] = gesture->Point_start.y; + sigle_num = 1; + } + } + return 0; + +} + +static void tp_gesture_handle(struct touchpanel_data *ts) +{ + struct gesture_info gesture_info_temp; + + if (project_code == 20801) { + if (!ts->ts_ops->enable_single_tap) { + TPD_INFO("not support ts->ts_ops->enable_single_tap \n"); + return; + } + } + if (!ts->ts_ops->get_gesture_info) { + TPD_INFO("not support ts->ts_ops->get_gesture_info callback\n"); + return; + } + + memset(&gesture_info_temp, 0, sizeof(struct gesture_info)); + if (project_code == 20801) { + ts->ts_ops->enable_single_tap(ts->chip_data, true); + } + ts->ts_ops->get_gesture_info(ts->chip_data, &gesture_info_temp); + tp_geture_info_transform(&gesture_info_temp, &ts->resolution_info); + if (DouTap_enable) { + if(gesture_info_temp.gesture_type == SingleTap) { + if (sec_double_tap(&gesture_info_temp) == 1) + { + gesture_info_temp.gesture_type = DouTap; + } + } + } + + TPD_INFO("detect %s gesture\n", gesture_info_temp.gesture_type == DouTap ? "double tap" : + gesture_info_temp.gesture_type == UpVee ? "up vee" : + gesture_info_temp.gesture_type == DownVee ? "down vee" : + gesture_info_temp.gesture_type == LeftVee ? "(>)" : + gesture_info_temp.gesture_type == RightVee ? "(<)" : + gesture_info_temp.gesture_type == Circle ? "o" : + gesture_info_temp.gesture_type == DouSwip ? "(||)" : + gesture_info_temp.gesture_type == Left2RightSwip ? "(-->)" : + gesture_info_temp.gesture_type == Right2LeftSwip ? "(<--)" : + gesture_info_temp.gesture_type == Up2DownSwip ? "up to down |" : + gesture_info_temp.gesture_type == Down2UpSwip ? "down to up |" : + gesture_info_temp.gesture_type == Mgestrue ? "(M)" : + gesture_info_temp.gesture_type == Sgestrue ? "(S)" : + gesture_info_temp.gesture_type == SingleTap ? "(single tap)" : + gesture_info_temp.gesture_type == Wgestrue ? "(W)" : "unknown"); + + if ((gesture_info_temp.gesture_type == DouTap && DouTap_enable) || + (gesture_info_temp.gesture_type == UpVee && UpVee_enable) || + (gesture_info_temp.gesture_type == LeftVee&& LeftVee_enable) || + (gesture_info_temp.gesture_type == RightVee && RightVee_enable) || + (gesture_info_temp.gesture_type == Circle && Circle_enable) || + (gesture_info_temp.gesture_type == DouSwip && DouSwip_enable) || + (gesture_info_temp.gesture_type == Mgestrue && Mgestrue_enable) || + (gesture_info_temp.gesture_type == Sgestrue && Sgestrue_enable) || + (gesture_info_temp.gesture_type == SingleTap && SingleTap_enable) || + (gesture_info_temp.gesture_type == Wgestrue && Wgestrue_enable)) { + memcpy(&ts->gesture, &gesture_info_temp, sizeof(struct gesture_info)); + input_report_key(ts->input_dev, KEY_F4, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_F4, 0); + input_sync(ts->input_dev); + } +} + +void tp_touch_btnkey_release(void) +{ + struct touchpanel_data *ts = g_tp; + + if (!ts) { + TPD_INFO("ts is NULL\n"); + return ; + } + + tp_touch_release(ts); + tp_btnkey_release(ts); +} + +static void tp_touch_release(struct touchpanel_data *ts) +{ + int i = 0; + +#ifdef TYPE_B_PROTOCOL + if (ts->report_flow_unlock_support) { + mutex_lock(&ts->report_mutex); + } + for (i = 0; i < ts->max_num; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); + input_sync(ts->input_dev); + if (ts->report_flow_unlock_support) { + mutex_unlock(&ts->report_mutex); + } +#else + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); + input_mt_sync(ts->input_dev); + input_sync(ts->input_dev); +#endif + TPD_INFO("release all touch point and key, clear tp touch down flag\n"); + ts->view_area_touched = 0; //realse all touch point,must clear this flag + ts->touch_count = 0; + ts->irq_slot = 0; + ts->corner_delay_up = -1; +} + +static bool edge_point_process(struct touchpanel_data *ts, struct point_info points) +{ + if (ts->limit_edge) { + if (points.x > ts->edge_limit.left_x2 && points.x < ts->edge_limit.right_x2) { + if (ts->edge_limit.in_which_area == AREA_EDGE) + tp_touch_release(ts); + ts->edge_limit.in_which_area = AREA_NORMAL; + } else if ((points.x > ts->edge_limit.left_x1 && points.x < ts->edge_limit.left_x2) || (points.x >ts->edge_limit.right_x2 && points.x < ts->edge_limit.right_x1)) {//area2 + if (ts->edge_limit.in_which_area == AREA_EDGE) { + ts->edge_limit.in_which_area = AREA_CRITICAL; + } + } else if (points.x < ts->edge_limit.left_x1 || points.x > ts->edge_limit.right_x1) { //area 1 + if (ts->edge_limit.in_which_area == AREA_CRITICAL) { + ts->edge_limit.in_which_area = AREA_EDGE; + return true; + } + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + ts->edge_limit.in_which_area = AREA_EDGE; + } + } + + return false; +} + +static bool corner_point_process(struct touchpanel_data *ts, struct corner_info *corner, struct point_info *points, int i) +{ + int j; + if (ts->limit_corner) { + if ((ts->limit_corner & (1 << CORNER_TOPLEFT)) && (points[i].x < ts->edge_limit.left_x3 && points[i].y < ts->edge_limit.left_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_TOPLEFT].id = i; + corner[CORNER_TOPLEFT].point = points[i]; + corner[CORNER_TOPLEFT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + if ((ts->limit_corner & (1 << CORNER_TOPRIGHT)) && (points[i].x < ts->edge_limit.left_x3 && points[i].y > ts->edge_limit.right_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_TOPRIGHT].id = i; + corner[CORNER_TOPRIGHT].point = points[i]; + corner[CORNER_TOPRIGHT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + if ((ts->limit_corner & (1 << CORNER_BOTTOMLEFT)) && (points[i].x > ts->edge_limit.right_x3 && points[i].y < ts->edge_limit.left_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_BOTTOMLEFT].id = i; + corner[CORNER_BOTTOMLEFT].point = points[i]; + corner[CORNER_BOTTOMLEFT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + if ((ts->limit_corner & (1 << CORNER_BOTTOMRIGHT)) && (points[i].x > ts->edge_limit.right_x3 && points[i].y > ts->edge_limit.right_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_BOTTOMRIGHT].id = i; + corner[CORNER_BOTTOMRIGHT].point = points[i]; + corner[CORNER_BOTTOMRIGHT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + + if (points[i].type != AREA_CORNER) { + if (ts->edge_limit.in_which_area == AREA_CORNER) { + if(ts->corner_delay_up == 0) { + for (j = 0; j < 4; j++) { + if (corner[j].flag) { +#ifdef TYPE_B_PROTOCOL + input_mt_slot(ts->input_dev, corner[j].id); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); +#endif + } + } + ts->corner_delay_up = -1; + } else { + ts->corner_delay_up = 1; + } + } + if(ts->corner_delay_up == -1) { + points[i].type = AREA_NORMAL; + ts->edge_limit.in_which_area = points[i].type; + } + } + + } + + return false; +} + +static void tp_touch_handle(struct touchpanel_data *ts) +{ + int i = 0; + uint8_t finger_num = 0, touch_near_edge = 0; + int obj_attention = 0; + struct point_info *points; + struct corner_info corner[4]; + static bool up_status = false; + static struct point_info last_point = {.x = 0, .y = 0}; + static int touch_report_num = 0; + + if (!ts->ts_ops->get_touch_points) { + TPD_INFO("not support ts->ts_ops->get_touch_points callback\n"); + return; + } + + points= kzalloc(sizeof(struct point_info)*ts->max_num, GFP_KERNEL); + if (!points) { + TPD_INFO("points kzalloc failed\n"); + return; + } + + memset(corner, 0, sizeof(corner)); + if (ts->reject_point) { //sensor will reject point when call mode. + if (ts->touch_count) { +#ifdef TYPE_B_PROTOCOL + for (i = 0; i < ts->max_num; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif + input_sync(ts->input_dev); + } + kfree(points); + return; + } + + obj_attention = ts->ts_ops->get_touch_points(ts->chip_data, points, ts->max_num); + mutex_lock(&ts->report_mutex); + if ((obj_attention & TOUCH_BIT_CHECK) != 0) { + up_status = false; + for (i = 0; i < ts->max_num; i++) { + if (((obj_attention & TOUCH_BIT_CHECK) >> i) & 0x01 && (points[i].status == 0)) // buf[0] == 0 is wrong point, no process + continue; + if (((obj_attention & TOUCH_BIT_CHECK) >> i) & 0x01 && (points[i].status != 0)) { + //Edge process before report abs + if (ts->edge_limit_support) { + if (ts->corner_delay_up < 1 && corner_point_process(ts, corner, points, i)) + continue; + if (edge_point_process(ts, points[i])) + continue; + } +#ifdef TYPE_B_PROTOCOL + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); +#endif + touch_report_num++; + tp_touch_down(ts, points[i], touch_report_num, i); + SET_BIT(ts->irq_slot, (1< ts->resolution_info.max_x / 100 && points[i].x < ts->resolution_info.max_x * 99 / 100) { + ts->view_area_touched = finger_num; + } else { + touch_near_edge++; + } + /*strore the last point data*/ + memcpy(&last_point, &points[i], sizeof(struct point_info)); + } +#ifdef TYPE_B_PROTOCOL + else { + if (pre_points[i].status != 0) { + TPD_INFO("last touch point id %d [%4d %4d %4d]\n", i, pre_points[i].x, pre_points[i].y, pre_points[i].z); + } + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + CLR_BIT(ts->irq_slot, (1<corner_delay_up > -1) { + TPD_DETAIL("corner_delay_up is %d\n", ts->corner_delay_up); + } + ts->corner_delay_up = ts->corner_delay_up > 0 ? ts->corner_delay_up - 1 : ts->corner_delay_up; + if (touch_near_edge == finger_num) { //means all the touchpoint is near the edge + ts->view_area_touched = 0; + } + if(ts->ear_sense_support && ts->es_enable && (finger_num > ts->touch_count)) { + ts->delta_state = TYPE_DELTA_BUSY; + queue_work(ts->delta_read_wq, &ts->read_delta_work); + } + } else { + if (up_status) { + tp_touch_up(ts); + mutex_unlock(&ts->report_mutex); + return; + } + finger_num = 0; + touch_report_num = 0; +#ifdef TYPE_B_PROTOCOL + for (i = 0; i < ts->max_num; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + tp_touch_up(ts); + ts->view_area_touched = 0; + ts->irq_slot = 0; + up_status = true; + ts->corner_delay_up = -1; + TPD_DETAIL("all touch up,view_area_touched=%d finger_num=%d\n",ts->view_area_touched, finger_num); + TPD_INFO("last point x:%d y:%d\n", last_point.x, last_point.y); + if (ts->edge_limit_support) + ts->edge_limit.in_which_area = AREA_NOTOUCH; + } + input_sync(ts->input_dev); + ts->touch_count = finger_num; + kfree(points); + + mutex_unlock(&ts->report_mutex); +} + +static void tp_btnkey_release(struct touchpanel_data *ts) +{ + if (CHK_BIT(ts->vk_bitmap, BIT_MENU)) + input_report_key_reduce(ts->kpd_input_dev, KEY_MENU, 0); + if (CHK_BIT(ts->vk_bitmap, BIT_HOME)) + input_report_key_reduce(ts->kpd_input_dev, KEY_HOMEPAGE, 0); + if (CHK_BIT(ts->vk_bitmap, BIT_BACK)) + input_report_key_reduce(ts->kpd_input_dev, KEY_BACK, 0); + input_sync(ts->kpd_input_dev); +} + +static void tp_btnkey_handle(struct touchpanel_data *ts) +{ + u8 touch_state = 0; + + if (ts->vk_type != TYPE_AREA_SEPRATE) { + TPD_DEBUG("TP vk_type not proper, checktouchpanel, button-type\n"); + + return; + } + if (!ts->ts_ops->get_keycode) { + TPD_INFO("not support ts->ts_ops->get_keycode callback\n"); + + return; + } + touch_state = ts->ts_ops->get_keycode(ts->chip_data); + + if (CHK_BIT(ts->vk_bitmap, BIT_MENU)) + input_report_key_reduce(ts->kpd_input_dev, KEY_MENU, CHK_BIT(touch_state, BIT_MENU)); + if (CHK_BIT(ts->vk_bitmap, BIT_HOME)) + input_report_key_reduce(ts->kpd_input_dev, KEY_HOMEPAGE, CHK_BIT(touch_state, BIT_HOME)); + if (CHK_BIT(ts->vk_bitmap, BIT_BACK)) + input_report_key_reduce(ts->kpd_input_dev, KEY_BACK, CHK_BIT(touch_state, BIT_BACK)); + input_sync(ts->kpd_input_dev); +} + +static void tp_config_handle(struct touchpanel_data *ts) +{ + int ret = 0; + if (!ts->ts_ops->fw_handle) { + TPD_INFO("not support ts->ts_ops->fw_handle callback\n"); + return; + } + + ret = ts->ts_ops->fw_handle(ts->chip_data); +} + +static void tp_datalogger_handle(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->data_logger_get) { + TPD_INFO("not support ts->ts_ops->data_logger_get callback\n"); + return; + } + + ts->ts_ops->data_logger_get(ts->chip_data); +} +static void tp_healthreport_handle(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->health_report) { + TPD_INFO("not support ts->ts_ops->health_report callback\n"); + return; + } + + ts->ts_ops->health_report(ts->chip_data); +} + +static void health_monitor_handle(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->health_report_1) { + TPD_INFO("not support ts->debug_info_ops->health_report callback\n"); + return; + } + + ts->ts_ops->health_report_1(ts->chip_data, &ts->monitor_data); + +} + +static void ex_health_monitor_handle(struct touchpanel_data *ts) +{ + if (ts->ts_ops->gt_health_report) { + TPD_INFO("support ts->debug_info_ops->health_report callback\n"); + ts->ts_ops->gt_health_report(ts->chip_data, &ts->monitor_data); + } +} +static void tp_face_detect_handle(struct touchpanel_data *ts) +{ + int ps_state = 0; + + if (!ts->ts_ops->get_face_state) { + TPD_INFO("not support ts->ts_ops->get_face_state callback\n"); + return; + } + TPD_INFO("enter tp_face_detect_handle\n"); + ps_state = ts->ts_ops->get_face_state(ts->chip_data); + TPD_DETAIL("ps state: %s\n", ps_state > 0 ? "near" : "far"); + + input_event(ps_input_dev, EV_MSC, MSC_RAW, ps_state > 0); + input_sync(ps_input_dev); +} +static void tp_fingerprint_handle(struct touchpanel_data *ts) +{ + struct fp_underscreen_info fp_tpinfo; + + TPD_INFO("%s: enter\n", __func__); + + if (!ts->ts_ops->screenon_fingerprint_info) { + TPD_INFO("not support screenon_fingerprint_info callback.\n"); + return; + } + + ts->ts_ops->screenon_fingerprint_info(ts->chip_data, &fp_tpinfo); + ts->fp_info.area_rate = fp_tpinfo.area_rate; + ts->fp_info.x = fp_tpinfo.x; + ts->fp_info.y = fp_tpinfo.y; + if(fp_tpinfo.touch_state == FINGERPRINT_DOWN_DETECT) { + TPD_INFO("screen on down : (%d, %d)\n", ts->fp_info.x, ts->fp_info.y); + ts->fp_info.touch_state = 1; + g_tp->touchold_event = 1; + opticalfp_irq_handler(&ts->fp_info); + } else if(fp_tpinfo.touch_state == FINGERPRINT_UP_DETECT) { + TPD_INFO("screen on up : (%d, %d)\n", ts->fp_info.x, ts->fp_info.y); + ts->fp_info.touch_state = 0; + g_tp->touchold_event = 0; + opticalfp_irq_handler(&ts->fp_info); + } else if (ts->fp_info.touch_state) { + TPD_DEBUG("fingerprint.touch_state = %d", ts->fp_info.touch_state); + // opticalfp_irq_handler(&ts->fp_info); + } +} + +static void tp_async_work_callback(void) +{ + struct touchpanel_data *ts = g_tp; + + if (ts == NULL) + return; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if ((ts->boot_mode == META_BOOT || ts->boot_mode == FACTORY_BOOT)) +#else + if ((ts->boot_mode == MSM_BOOT_MODE_FACTORY || ts->boot_mode == MSM_BOOT_MODE_RF)) +#endif + + { + TPD_INFO("%s: in ftm mode, no need to call back\n", __func__); + return; + } + + + TPD_INFO("%s: async work\n", __func__); + if (ts->use_resume_notify && ts->suspend_state == TP_RESUME_COMPLETE) { + complete(&ts->resume_complete); + return; + } + + if (ts->in_test_process) { + TPD_INFO("%s: In test process, do not switch mode\n", __func__); + return; + } + + queue_work(ts->async_workqueue, &ts->async_work); +} + +static void tp_async_work_lock(struct work_struct *work) +{ + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, async_work); + mutex_lock(&ts->mutex); + if (ts->ts_ops->async_work) { + ts->ts_ops->async_work(ts->chip_data); + } + mutex_unlock(&ts->mutex); +} + +static void tp_work_common_callback(void) +{ + struct touchpanel_data *ts; + + TPD_DEBUG("%s:enter\n", __func__); + + if (g_tp == NULL) + return; + ts = g_tp; + tp_work_func(ts); +} + +static void tp_work_func(struct touchpanel_data *ts) +{ + u32 cur_event = 0; + + if (!ts->ts_ops->trigger_reason && !ts->ts_ops->u32_trigger_reason) { + TPD_INFO("not support ts_ops->trigger_reason callback\n"); + return; + } + /* + * trigger_reason:this callback determine which trigger reason should be + * The value returned has some policy! + * 1.IRQ_EXCEPTION /IRQ_GESTURE /IRQ_IGNORE /IRQ_FW_CONFIG --->should be only reported individually + * 2.IRQ_TOUCH && IRQ_BTN_KEY --->should depends on real situation && set correspond bit on trigger_reason + */ + if (ts->ts_ops->u32_trigger_reason) + cur_event = ts->ts_ops->u32_trigger_reason(ts->chip_data, ts->gesture_enable, ts->is_suspended); + else + cur_event = ts->ts_ops->trigger_reason(ts->chip_data, ts->gesture_enable, ts->is_suspended); + + if (CHK_BIT(cur_event, IRQ_TOUCH) || CHK_BIT(cur_event, IRQ_BTN_KEY) || CHK_BIT(cur_event, IRQ_DATA_LOGGER) || \ + CHK_BIT(cur_event, IRQ_FACE_STATE) || CHK_BIT(cur_event, IRQ_FINGERPRINT)) { + if (CHK_BIT(cur_event, IRQ_BTN_KEY)) { + tp_btnkey_handle(ts); + } + if (CHK_BIT(cur_event, IRQ_TOUCH)) { + tp_touch_handle(ts); + } + if (CHK_BIT(cur_event, IRQ_DATA_LOGGER)) { + if(ts->int_mode == UNBANNABLE) { + tp_healthreport_handle(ts); + } else if (project_code == 20801) { + health_monitor_handle(ts); + }else { + tp_datalogger_handle(ts); + } + } + if (CHK_BIT(cur_event, IRQ_FACE_STATE) && ts->fd_enable) { + tp_face_detect_handle(ts); + } + if (project_code != 20801) { + if (CHK_BIT(cur_event, IRQ_FINGERPRINT) && ts->touch_hold_enable) { + tp_fingerprint_handle(ts); + } + } + } else if (CHK_BIT(cur_event, IRQ_GESTURE)) { + tp_gesture_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_EXCEPTION)) { + tp_exception_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_FW_CONFIG)) { + tp_config_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_FW_AUTO_RESET)) { + tp_fw_auto_reset_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_FW_HEALTH) && (!ts->is_suspended)) { + ex_health_monitor_handle(ts); + } else { + TPD_DEBUG("unknown irq trigger reason\n"); + } +} + +static void tp_work_func_unlock(struct touchpanel_data *ts) +{ + if (ts->ts_ops->irq_handle_unlock) { + ts->ts_ops->irq_handle_unlock(ts->chip_data); + } +} + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +extern void primary_display_esd_check_enable(int enable); +#endif +void __attribute__((weak)) display_esd_check_enable_bytouchpanel(bool enable) {return;} + +static void tp_fw_update_work(struct work_struct *work) +{ + const struct firmware *fw = NULL; + int ret, fw_update_result = 0; + int count_tmp = 0, retry = 5; + char *p_node = NULL; + char *fw_name_fae = NULL; + char *postfix = "_FAE"; + uint8_t copy_len = 0; + + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, + fw_update_work); + + if (!ts->ts_ops->fw_check || !ts->ts_ops->reset) { + TPD_INFO("not support ts_ops->fw_check callback\n"); + complete(&ts->fw_complete); + return; + } + + TPD_INFO("%s: fw_name = %s\n", __func__, ts->panel_data.fw_name); + + mutex_lock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + ts->loading_fw = true; + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + display_esd_check_enable_bytouchpanel(0); +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + primary_display_esd_check_enable(0); //avoid rst pulled to low while updating +#endif + + if (ts->ts_ops->fw_update) { + do { + if(ts->firmware_update_type == 0 || ts->firmware_update_type == 1) { + if(ts->fw_update_app_support) { + fw_name_fae = kzalloc(MAX_FW_NAME_LENGTH, GFP_KERNEL); + if(fw_name_fae == NULL) { + TPD_INFO("fw_name_fae kzalloc error!\n"); + goto EXIT; + } + p_node = strstr(ts->panel_data.fw_name, "."); + copy_len = p_node - ts->panel_data.fw_name; + memcpy(fw_name_fae, ts->panel_data.fw_name, copy_len); + strlcat(fw_name_fae, postfix, MAX_FW_NAME_LENGTH); + strlcat(fw_name_fae, p_node, MAX_FW_NAME_LENGTH); + TPD_INFO("fw_name_fae is %s\n", fw_name_fae); + ret = request_firmware(&fw, fw_name_fae, ts->dev); + if (!ret) + break; + } else { + ret = request_firmware(&fw, ts->panel_data.fw_name, ts->dev); + if (!ret) + break; + } + } else { + ret = request_firmware_select(&fw, ts->panel_data.fw_name, ts->dev); + if (!ret) + break; + } + } while((ret < 0) && (--retry > 0)); + + TPD_INFO("retry times %d\n", 5 - retry); + + if (!ret || ts->is_noflash_ic) { + do { + count_tmp++; + ret = ts->ts_ops->fw_update(ts->chip_data, fw, ts->force_update); + fw_update_result = ret; + if (ret == FW_NO_NEED_UPDATE) { + break; + } + + if(!ts->is_noflash_ic) { //noflash update fw in reset and do bootloader reset in get_chip_info + ret |= ts->ts_ops->reset(ts->chip_data); + ret |= ts->ts_ops->get_chip_info(ts->chip_data); + } + + ret |= ts->ts_ops->fw_check(ts->chip_data, &ts->resolution_info, &ts->panel_data); + } while((count_tmp < 2) && (ret != 0)); + + if(fw != NULL) { + release_firmware(fw); + } + } else { + TPD_INFO("%s: fw_name request failed %s %d\n", __func__, ts->panel_data.fw_name, ret); + goto EXIT; + } + } + + tp_touch_release(ts); + tp_btnkey_release(ts); + operate_mode_switch(ts); + if (fw_update_result != FW_NO_NEED_UPDATE) { + if (ts->spurious_fp_support && ts->ts_ops->finger_proctect_data_get) { + ts->ts_ops->finger_proctect_data_get(ts->chip_data); + } + if (ts->ts_ops->data_logger_open) { + ts->ts_ops->data_logger_open(ts->chip_data); + } + } + +EXIT: + ts->loading_fw = false; + + display_esd_check_enable_bytouchpanel(1); +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + primary_display_esd_check_enable(1); //avoid rst pulled to low while updating +#endif + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, true); + } + + kfree(fw_name_fae); + fw_name_fae = NULL; + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + mutex_unlock(&ts->mutex); + + ts->force_update = 0; + + complete(&ts->fw_complete); //notify to init.rc that fw update finished + return; +} + +#ifndef TPD_USE_EINT +static enum hrtimer_restart touchpanel_timer_func(struct hrtimer *timer) +{ + struct touchpanel_data *ts = container_of(timer, struct touchpanel_data, timer); + + mutex_lock(&ts->mutex); + tp_work_func(ts); + mutex_unlock(&ts->mutex); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +#else +static irqreturn_t tp_irq_thread_fn(int irq, void *dev_id) +{ + struct touchpanel_data *ts = (struct touchpanel_data *)dev_id; + + TPD_DEBUG("%s: int_mode = %d\n", __func__, ts->int_mode); + + if (ts->int_mode == BANNABLE) { + __pm_stay_awake(ts->source); //avoid system enter suspend lead to i2c error + mutex_lock(&ts->mutex); + tp_work_func(ts); + mutex_unlock(&ts->mutex); + __pm_relax(ts->source); + } else { + TPD_DEBUG("enter func unlock\n"); + tp_work_func_unlock(ts); + } + return IRQ_HANDLED; +} +#endif + +/** + * tp_gesture_enable_flag - expose gesture control status for other module. + * Return gesture_enable status. + */ +int tp_gesture_enable_flag(void) +{ + if (!g_tp || !g_tp->is_incell_panel) + return LCD_POWER_OFF; + + return (g_tp->gesture_enable > 0)?LCD_POWER_ON: LCD_POWER_OFF; +} + +/* + *Interface for lcd to control reset pin + */ +int tp_control_reset_gpio(bool enable) +{ + if (!g_tp) { + return 0; + } + + if (gpio_is_valid(g_tp->hw_res.reset_gpio)) { + if (g_tp->ts_ops->reset_gpio_control) { + g_tp->ts_ops->reset_gpio_control(g_tp->chip_data, enable); + } + } + + return 0; +} + +/* + * check_usb_state----expose to be called by charger int to get usb state + * @usb_state : 1 if usb checked, otherwise is 0 + */ +void switch_usb_state(int usb_state) +{ + if (!g_tp) { + return; + } + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if ((g_tp->boot_mode == META_BOOT || g_tp->boot_mode == FACTORY_BOOT)) +#else + if ((g_tp->boot_mode == MSM_BOOT_MODE_FACTORY || g_tp->boot_mode == MSM_BOOT_MODE_RF)) +#endif + + { + TPD_INFO("Ftm mode, do not switch usb state\n"); + return; + } + + if (g_tp->charger_pump_support && (g_tp->is_usb_checked != usb_state)) { + g_tp->is_usb_checked = !!usb_state; + TPD_INFO("%s: check usb state : %d, is_suspended: %d\n", __func__, usb_state, g_tp->is_suspended); + if (!g_tp->is_suspended && (g_tp->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + mutex_lock(&g_tp->mutex); + g_tp->ts_ops->mode_switch(g_tp->chip_data, MODE_CHARGE, g_tp->is_usb_checked); + mutex_unlock(&g_tp->mutex); + } + } +} +EXPORT_SYMBOL(switch_usb_state); + +/* + * gesture_enable = 0 : disable gesture + * gesture_enable = 1 : enable gesture when ps is far away + * gesture_enable = 2 : disable gesture when ps is near + */ +static ssize_t proc_gesture_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + TPD_INFO("%s write argc1[0x%x],argc2[0x%x]\n",__func__,buf[0],buf[1]); + UpVee_enable = (buf[0] & BIT0)?1:0; + DouSwip_enable = (buf[0] & BIT1)?1:0; + LeftVee_enable = (buf[0] & BIT3)?1:0; + RightVee_enable = (buf[0] & BIT4)?1:0; + Circle_enable = (buf[0] & BIT6)?1:0; + DouTap_enable = (buf[0] & BIT7)?1:0; + Sgestrue_enable = (buf[1] & BIT0)?1:0; + Mgestrue_enable = (buf[1] & BIT1)?1:0; + Wgestrue_enable = (buf[1] & BIT2)?1:0; + SingleTap_enable = (buf[1] & BIT3)?1:0; + Enable_gesture = (buf[1] & BIT7)?1:0; + + if (UpVee_enable || DouSwip_enable || LeftVee_enable || RightVee_enable + || Circle_enable || DouTap_enable || Sgestrue_enable || Mgestrue_enable + || Wgestrue_enable || SingleTap_enable || Enable_gesture) { + value = 1; + } else { + value = 0; + } + + mutex_lock(&ts->mutex); + if (ts->gesture_enable != value) { + ts->gesture_enable = value; + tp_1v8_power = ts->gesture_enable; + TPD_INFO("%s: gesture_enable = %d, is_suspended = %d\n", __func__, ts->gesture_enable, ts->is_suspended); + if (ts->is_incell_panel && (ts->suspend_state == TP_RESUME_EARLY_EVENT) && (ts->tp_resume_order == LCD_TP_RESUME)) { + TPD_INFO("tp will resume, no need mode_switch in incell panel\n"); /*avoid i2c error or tp rst pulled down in lcd resume*/ + } else if (ts->is_suspended) + operate_mode_switch(ts); + }else { + TPD_INFO("%s: do not do same operator :%d\n", __func__, value); + } + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_gesture_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("gesture_enable is: %d\n", ts->gesture_enable); + ret = sprintf(page, "%d\n", ts->gesture_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_coordinate_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s:gesture_type = %d\n", __func__, ts->gesture.gesture_type); + ret = sprintf(page, "%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d\n", ts->gesture.gesture_type, + ts->gesture.Point_start.x, ts->gesture.Point_start.y, ts->gesture.Point_end.x, ts->gesture.Point_end.y, + ts->gesture.Point_1st.x, ts->gesture.Point_1st.y, ts->gesture.Point_2nd.x, ts->gesture.Point_2nd.y, + ts->gesture.Point_3rd.x, ts->gesture.Point_3rd.y, ts->gesture.Point_4th.x, ts->gesture.Point_4th.y, + ts->gesture.clockwise); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations proc_gesture_control_fops = { + .write = proc_gesture_control_write, + .read = proc_gesture_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static const struct file_operations proc_coordinate_fops = { + .read = proc_coordinate_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_ps_status_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + if (count > 2) + return count; + if (!ts) + return count; + + if (!ts->ts_ops->write_ps_status) { + TPD_INFO("not support ts_ops->write_ps_status callback\n"); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + mutex_lock(&ts->mutex); + ts->ps_status = value; + ts->ts_ops->write_ps_status(ts->chip_data, value); + mutex_unlock(&ts->mutex); + } + + return count; +} + +static ssize_t proc_ps_support_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else if (!ts->ts_ops->write_ps_status) { + sprintf(page, "%d\n", -1); + } else { + sprintf(page, "%d\n", 0);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_write_ps_status_fops = { + .write = proc_ps_status_write, + .read = proc_ps_support_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +//proc/touchpanel/game_switch_enable +static ssize_t proc_game_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (!ts->ts_ops->mode_switch) { + TPD_INFO("%s:not support ts_ops->mode_switch callback\n",__func__); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%x", &value); + ts->noise_level = value; + ts->game_mode_status = value > 0 ? 1 : 0; + + TPD_INFO("%s: game_switch value=0x%x\n", __func__, value); + if (!ts->is_suspended) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_GAME, value > 0); + mutex_unlock(&ts->mutex); + } else { + TPD_INFO("%s: game_switch_support is_suspended.\n", __func__); + } + + return count; +} + +static ssize_t proc_game_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->noise_level);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_game_switch_fops = { + .write = proc_game_switch_write, + .read = proc_game_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_gesture_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (gesture_switch_value == value) { + //TPD_INFO("gesture_switch_value is %d\n", value); + return count; + } + gesture_switch_value = value; + value = value - 1; //cmd 2 is disable gesture,cmd 1 is open gesture + ts->gesture_switch = value; + + TPD_DEBUG("%s: gesture_switch value= %d\n", __func__, value); + if ((ts->is_suspended == 1) && (ts->gesture_enable ==1)) { + __pm_stay_awake(ts->source); //avoid system enter suspend lead to i2c error + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE_SWITCH, ts->gesture_switch); + mutex_unlock(&ts->mutex); + __pm_relax(ts->source); + } else { + TPD_INFO("%s: gesture mode switch must be suspend.\n", __func__); + } + + return count; +} + +static ssize_t proc_gesture_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->gesture_switch);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + + +static const struct file_operations proc_gesture_switch_fops = { + .write = proc_gesture_switch_write, + .read = proc_gesture_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_reject_point_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + ts->reject_point = value; + + TPD_INFO("%s: ts->reject_poin = %d\n", __func__, value); + + return count; +} + +static ssize_t proc_reject_point_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->reject_point);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_reject_point_fops = { + .write = proc_reject_point_write, + .read = proc_reject_point_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_limit_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + ts->limit_switch = value; + + TPD_DEBUG("%s: ts->limit_switch = %d\n", __func__, value); + if (ts->is_suspended == 0) { + mutex_lock(&ts->mutex); + if (project_code == 20801) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EDGE, ts->limit_switch); + } else { + ts->ts_ops->mode_switch(ts->chip_data, MODE_LIMIT_SWITCH, ts->limit_switch); + } + mutex_unlock(&ts->mutex); + } + return count; +} + +static ssize_t proc_limit_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->limit_switch);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + + + +static ssize_t proc_dead_zone_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8] = {0}; + int data[6] = {0}; + int ret = -1; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + ret = copy_from_user(buf, buffer, count); + if (ret) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (sscanf(buf, "%d,%d", &data[0], &data[1]) == 2) { + if (data[0] > 50 || data[1] > 50) { + TPD_INFO("data not allow\n"); + return count; + } + ts->dead_zone_l = data[0]; + ts->dead_zone_p = data[1]; + } + TPD_INFO("data[0] is %d, data[1] is %d\n", data[0], data[1]); + + if (ts->is_suspended == 0) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_LIMIT_SWITCH, ts->limit_switch); + mutex_unlock(&ts->mutex); + } + return count; +} + +static ssize_t proc_dead_zone_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[9] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d,%d\n", ts->dead_zone_l, ts->dead_zone_p);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_limit_switch_fops = { + .write = proc_limit_switch_write, + .read = proc_limit_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static const struct file_operations proc_tp_dead_zone_fops = { + .write = proc_dead_zone_write, + .read = proc_dead_zone_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_corner_dead_zone_l_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8] = {0}; + int data[6] = {0}; + int ret = -1; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + ret = copy_from_user(buf, buffer, count); + if (ret) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (sscanf(buf, "%d,%d", &data[0], &data[1]) == 2) { + ts->corner_dead_zone_xl = data[0]; + ts->corner_dead_zone_yl = data[1]; + } + TPD_INFO("data[0] is %d, data[1] is %d\n", data[0], data[1]); + + if (ts->is_suspended == 0) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_LIMIT_SWITCH, ts->limit_switch); + mutex_unlock(&ts->mutex); + } + return count; +} + +static ssize_t proc_corner_dead_zone_l_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[9] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d,%d\n", ts->corner_dead_zone_xl, ts->corner_dead_zone_yl);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_tp_corner_dead_zone_l_fops = { + .write = proc_corner_dead_zone_l_write, + .read = proc_corner_dead_zone_l_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_corner_dead_zone_p_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8] = {0}; + int data[6] = {0}; + int ret = -1; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + ret = copy_from_user(buf, buffer, count); + if (ret) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (sscanf(buf, "%d,%d", &data[0], &data[1]) == 2) { + ts->corner_dead_zone_xp = data[0]; + ts->corner_dead_zone_yp = data[1]; + } + TPD_INFO("data[0] is %d, data[1] is %d\n", data[0], data[1]); + + if (ts->is_suspended == 0) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_LIMIT_SWITCH, ts->limit_switch); + mutex_unlock(&ts->mutex); + } + return count; +} + +static ssize_t proc_corner_dead_zone_p_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[9] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d,%d\n", ts->corner_dead_zone_xp, ts->corner_dead_zone_yp);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_tp_corner_dead_zone_p_fops = { + .write = proc_corner_dead_zone_p_write, + .read = proc_corner_dead_zone_p_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +//proc/touchpanel/black_screen_test +static ssize_t proc_black_screen_test_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + int retry = 20; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + TPD_INFO("%s %ld %lld\n", __func__, count, *ppos); + + if (!ts || !ts->gesture_test.flag) + return 0; + + ts->gesture_test.message = kzalloc(256, GFP_KERNEL); + if (!ts->gesture_test.message) { + TPD_INFO("failed to alloc memory\n"); + return 0; + } + + /* wait until tp is in sleep, then sleep 500ms to make sure tp is in gesture mode*/ + do { + if (ts->is_suspended) { + msleep(500); + break; + } + msleep(200); + } while(--retry); + + TPD_INFO("%s retry times %d\n", __func__, retry); + if (retry == 0 && !ts->is_suspended) { + sprintf(ts->gesture_test.message, "1 errors: not in sleep "); + goto OUT; + } + + mutex_lock(&ts->mutex); + if (ts->ts_ops->black_screen_test) { + ts->ts_ops->black_screen_test(ts->chip_data, ts->gesture_test.message); + } else { + TPD_INFO("black_screen_test not support\n"); + sprintf(ts->gesture_test.message, "1 errors:not support gesture test"); + } + mutex_unlock(&ts->mutex); + +OUT: + ts->gesture_test.flag = false; + ts->gesture_enable = ts->gesture_test.gesture_backup; + + ret = simple_read_from_buffer(user_buf, count, ppos, ts->gesture_test.message, strlen(ts->gesture_test.message)); + kfree(ts->gesture_test.message); + return ret; +} + +static ssize_t proc_black_screen_test_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2 || !ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + TPD_INFO("%s %d\n", __func__, value); + + ts->gesture_test.gesture_backup = ts->gesture_enable; + ts->gesture_enable = true; + ts->gesture_test.flag = !!value; + + return count; +} + +static const struct file_operations proc_black_screen_test_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_black_screen_test_read, + .write = proc_black_screen_test_write, +}; + +//proc/touchpanel/irq_depth +static ssize_t proc_get_irq_depth_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct irq_desc *desc = NULL; + + if(!ts) { + return count; + } + + desc = irq_to_desc(ts->irq); + + sprintf(page, "%d\n", desc->depth); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t proc_irq_status_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2 || !ts) + return count; + + if (copy_from_user(buf, user_buf, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + TPD_INFO("%s %d, %s ts->irq=%d\n", __func__, value, value ? "enable" : "disable", ts->irq); + + if (value == 1) { + enable_irq(ts->irq); + } else { + disable_irq_nosync(ts->irq); + } + + return count; +} + +static const struct file_operations proc_get_irq_depth_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_get_irq_depth_read, + .write = proc_irq_status_write, +}; + +static ssize_t proc_vendor_id_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if(!ts) { + return count; + } + + sprintf(page, "%d\n", ts->panel_data.tp_type); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations vendor_id_proc_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_vendor_id_read, +}; + +static ssize_t proc_glove_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int ret = 0 ; + char buf[3] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + if (count > 2) + return count; + if (!ts->ts_ops->mode_switch) { + TPD_INFO("not support ts_ops->mode_switch callback\n"); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &ret); + TPD_INFO("%s:buf = %d, ret = %d\n", __func__, *buf, ret); + if ((ret == 0) || (ret == 1)) { + mutex_lock(&ts->mutex); + ts->glove_enable = ret; + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_GLOVE, ts->glove_enable); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + mutex_unlock(&ts->mutex); + } + switch(ret) { + case 0: + TPD_DEBUG("tp_glove_func will be disable\n"); + break; + case 1: + TPD_DEBUG("tp_glove_func will be enable\n"); + break; + default: + TPD_DEBUG("Please enter 0 or 1 to open or close the glove function\n"); + } + + return count; +} + +static ssize_t proc_glove_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_INFO("glove mode enable is: %d\n", ts->glove_enable); + ret = sprintf(page, "%d\n", ts->glove_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations proc_glove_control_fops = { + .write = proc_glove_control_write, + .read = proc_glove_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t cap_vk_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct button_map *button_map; + if (!g_tp) + return sprintf(buf, "not support"); + + button_map = &g_tp->button_map; + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":%d:%d:%d:%d" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOMEPAGE) ":%d:%d:%d:%d" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":%d:%d:%d:%d" + "\n", button_map->coord_menu.x, button_map->coord_menu.y, button_map->width_x, button_map->height_y, \ + button_map->coord_home.x, button_map->coord_home.y, button_map->width_x, button_map->height_y, \ + button_map->coord_back.x, button_map->coord_back.y, button_map->width_x, button_map->height_y); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys."TPD_DEVICE, + .mode = S_IRUGO, + }, + .show = &cap_vk_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + +static ssize_t proc_debug_control_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[PAGESIZE]; + + TPD_INFO("%s: tp_debug = %d.\n", __func__, tp_debug); + sprintf(page, "%d", tp_debug); + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_debug_control_write(struct file *file, const char __user *buf, size_t count, loff_t *lo) +{ + int tmp = 0; + char buffer[4] = {0}; + + if (count > 2) { + return count; + } + + if (copy_from_user(buffer, buf, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (1 == sscanf(buffer, "%d", &tmp)) { + tp_debug = tmp; + } else { + TPD_DEBUG("invalid content: '%s', length = %zd\n", buf, count); + } + + return count; +} + +static const struct file_operations proc_debug_control_ops = +{ + .write = proc_debug_control_write, + .read = proc_debug_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_limit_area_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + char page[PAGESIZE]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + TPD_DEBUG("limit_area is: %d\n", ts->edge_limit.limit_area); + ret = sprintf(page, "limit_area = %d left_x1 = %d right_x1 = %d left_x2 = %d right_x2 = %d left_x3 = %d right_x3 = %d left_y1 = %d right_y1 = %d left_y2 = %d right_y2 = %d left_y3 = %d right_y3 = %d\n", + ts->edge_limit.limit_area, ts->edge_limit.left_x1, ts->edge_limit.right_x1, ts->edge_limit.left_x2, ts->edge_limit.right_x2, ts->edge_limit.left_x3, ts->edge_limit.right_x3, + ts->edge_limit.left_y1, ts->edge_limit.right_y1, ts->edge_limit.left_y2, ts->edge_limit.right_y2, ts->edge_limit.left_y3, ts->edge_limit.right_y3); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_limit_area_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8]; + int temp; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%d", &temp); + if (temp < 0 || temp > 10) + return count; + + ts->edge_limit.limit_area = temp; + ts->edge_limit.left_x1 = (ts->edge_limit.limit_area*1000)/100; + ts->edge_limit.right_x1 = ts->resolution_info.LCD_WIDTH - ts->edge_limit.left_x1; + ts->edge_limit.left_x2 = 2 * ts->edge_limit.left_x1; + ts->edge_limit.right_x2 = ts->resolution_info.LCD_WIDTH - (2 * ts->edge_limit.left_x1); + ts->edge_limit.left_x3 = 5 * ts->edge_limit.left_x1; + ts->edge_limit.right_x3 = ts->resolution_info.LCD_WIDTH - (5 * ts->edge_limit.left_x1); + + TPD_INFO("limit_area = %d; left_x1 = %d; right_x1 = %d; left_x2 = %d; right_x2 = %d; left_x3 = %d; right_x3 = %d\n", + ts->edge_limit.limit_area, ts->edge_limit.left_x1, ts->edge_limit.right_x1, ts->edge_limit.left_x2, ts->edge_limit.right_x2, ts->edge_limit.left_x3, ts->edge_limit.right_x3); + + ts->edge_limit.left_y1 = (ts->edge_limit.limit_area*1000)/100; + ts->edge_limit.right_y1 = ts->resolution_info.LCD_HEIGHT - ts->edge_limit.left_y1; + ts->edge_limit.left_y2 = 2 * ts->edge_limit.left_y1; + ts->edge_limit.right_y2 = ts->resolution_info.LCD_HEIGHT - (2 * ts->edge_limit.left_y1); + ts->edge_limit.left_y3 = 5 * ts->edge_limit.left_y1; + ts->edge_limit.right_y3 = ts->resolution_info.LCD_HEIGHT - (5 * ts->edge_limit.left_y1); + + TPD_INFO("limit_area = %d; left_y1 = %d; right_y1 = %d; left_y2 = %d; right_y2 = %d; left_y3 = %d; right_y3 = %d\n", + ts->edge_limit.limit_area, ts->edge_limit.left_y1, ts->edge_limit.right_y1, ts->edge_limit.left_y2, ts->edge_limit.right_y2, ts->edge_limit.left_y3, ts->edge_limit.right_y3); + + return count; +} + +static const struct file_operations proc_limit_area_ops = +{ + .read = proc_limit_area_read, + .write = proc_limit_area_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_limit_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + char page[PAGESIZE]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_INFO("limit_enable is: 0x%x, ts->limit_edge = 0x%x, ts->limit_corner = 0x%x\n", ts->limit_enable, ts->limit_edge, ts->limit_corner); + ret = sprintf(page, "%d\n", ts->limit_enable); + + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_limit_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8] = {0}; + int ret, temp; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + if (count > 3) + count = 3; + if (copy_from_user(buf, buffer, count)) { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%x", &temp); + if (temp > 0x1F) { + TPD_INFO("%s: temp = 0x%x > 0x1F \n", __func__, temp); + return count; + } + + mutex_lock(&ts->mutex); + ts->limit_enable = temp; + ts->limit_edge = ts->limit_enable & 1; + ts->limit_corner = ts->limit_enable >> 1; + TPD_INFO("%s: limit_enable = 0x%x, ts->limit_edge = 0x%x, ts->limit_corner=0x%x\n", __func__, ts->limit_enable, ts->limit_edge, ts->limit_corner); + + if (ts->is_suspended == 0) { + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_EDGE, ts->limit_edge); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + } + mutex_unlock(&ts->mutex); + + return count; +} + +static const struct file_operations proc_limit_control_ops = +{ + .read = proc_limit_control_read, + .write = proc_limit_control_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_fw_update_write(struct file *file, const char __user *page, size_t size, loff_t *lo) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int val = 0; + int ret = 0; + char buf[4] = {0}; + if (!ts) + return size; + if (size > 2) + return size; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (ts->boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT) +#else + if (ts->boot_mode == MSM_BOOT_MODE_CHARGE) +#endif + + { + TPD_INFO("boot mode is MSM_BOOT_MODE__CHARGE,not need update tp firmware\n"); + return size; + } + + + if (copy_from_user(buf, page, size)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return size; + } + + sscanf(buf, "%d", &val); + ts->firmware_update_type = val; + if (!ts->force_update && ts->firmware_update_type != 2) + ts->force_update = !!val; + + schedule_work(&ts->fw_update_work); + + ret = wait_for_completion_killable_timeout(&ts->fw_complete, FW_UPDATE_COMPLETE_TIMEOUT); + if (ret < 0) { + TPD_INFO("kill signal interrupt\n"); + } + + TPD_INFO("fw update finished\n"); + return size; +} + + + +static const struct file_operations proc_fw_update_ops = +{ + .write = proc_fw_update_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_finger_protect_result_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[16] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + if(!ts) + return 0; + + if(ts->spuri_fp_touch.fp_touch_st == FINGER_PROTECT_TOUCH_UP || ts->spuri_fp_touch.fp_touch_st == FINGER_PROTECT_TOUCH_DOWN) + TPD_INFO("%s report_finger_protect = %d\n", __func__, ts->spuri_fp_touch.fp_touch_st); + ret = sprintf(page, "%d\n", ts->spuri_fp_touch.fp_touch_st); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + + +static const struct file_operations proc_finger_protect_result= { + .read = proc_finger_protect_result_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_finger_protect_trigger_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int op = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) { + return count; + } + if (!ts) { + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (1 == sscanf(buf, "%d", &op)) { + if (op == 1) { + ts->spuri_fp_touch.fp_trigger= true; + ts->spuri_fp_touch.fp_touch_st = FINGER_PROTECT_NOTREADY; + TPD_INFO("%s : %d\n",__func__,__LINE__); + wake_up_interruptible(&waiter); + } + } else { + TPD_INFO("invalid content: '%s', length = %zd\n", buffer, count); + return -EINVAL; + } + + return count; +} + +static const struct file_operations proc_finger_protect_trigger= { + .write = proc_finger_protect_trigger_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +void lcd_wakeup_finger_protect(bool wakeup) +{ + TPD_INFO("%s wakeup=%d\n",__func__,wakeup); + if (g_tp != NULL) { + if (g_tp->spuri_fp_touch.lcd_trigger_fp_check) { + if(wakeup) { + g_tp->spuri_fp_touch.lcd_resume_ok = true; + wake_up_interruptible(&waiter); + } + else { + mutex_lock(&g_tp->mutex); + g_tp->spuri_fp_touch.lcd_resume_ok = false; + mutex_unlock(&g_tp->mutex); + } + } + } +} + +static int finger_protect_handler(void *data) +{ + struct touchpanel_data *ts = (struct touchpanel_data *)data; + if (!ts) { + TPD_INFO("ts is null should nerver get here!\n"); + return 0; + }; + if (!ts->ts_ops->spurious_fp_check) { + TPD_INFO("not support spurious_fp_check call back\n"); + return 0; + } + + do { + if (ts->spuri_fp_touch.lcd_trigger_fp_check) + wait_event_interruptible(waiter, ts->spuri_fp_touch.fp_trigger && ts->i2c_ready && ts->spuri_fp_touch.lcd_resume_ok); + else + wait_event_interruptible(waiter, ts->spuri_fp_touch.fp_trigger && ts->i2c_ready); + ts->spuri_fp_touch.fp_trigger = false; + ts->spuri_fp_touch.fp_touch_st = FINGER_PROTECT_NOTREADY; + + mutex_lock(&ts->mutex); + if (g_tp->spuri_fp_touch.lcd_trigger_fp_check && !g_tp->spuri_fp_touch.lcd_resume_ok) { + TPD_INFO("LCD is suspend, can not detect finger touch in incell panel\n"); + mutex_unlock(&ts->mutex); + continue; + } + + ts->spuri_fp_touch.fp_touch_st = ts->ts_ops->spurious_fp_check(ts->chip_data); + if (ts->view_area_touched) { + TPD_INFO("%s tp touch down,clear flag\n",__func__); + ts->view_area_touched = 0; + } + operate_mode_switch(ts); + mutex_unlock(&ts->mutex); + } while (!kthread_should_stop()); + return 0; +} + +//proc/touchpanel/register_info node use info: +//first choose register_add and lenght, example: echo 000e,1 > register_info +//second read: cat register_info +static ssize_t proc_register_info_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + int i = 0; + ssize_t num_read_chars = 0; + char page[256] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + if (ts->reg_info.reg_length < 1 || ts->reg_info.reg_length > 9) { + TPD_INFO("ts->reg_info.reg_length error!\n"); + return count; + } + ts->reg_info.reg_result = kzalloc(ts->reg_info.reg_length * (sizeof(uint16_t)), GFP_KERNEL); + if (!ts->reg_info.reg_result) { + TPD_INFO("ts->reg_info.reg_result kzalloc error\n"); + return count; + } + + if (ts->ts_ops->register_info_read) { + mutex_lock(&ts->mutex); + ts->ts_ops->register_info_read(ts->chip_data, ts->reg_info.reg_addr, ts->reg_info.reg_result, ts->reg_info.reg_length); + mutex_unlock(&ts->mutex); + for(i = 0; i < ts->reg_info.reg_length; i++) { + num_read_chars += sprintf(&(page[num_read_chars]), "reg_addr(0x%x) = 0x%x\n", ts->reg_info.reg_addr, ts->reg_info.reg_result[i]); + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + } + + kfree(ts->reg_info.reg_result); + return ret; +} + +//write info: echo 000e,1 > register_info +static ssize_t proc_register_info_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int addr = 0, length = 0; + char buf[16] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 7) { + TPD_INFO("%s count = %ld\n", __func__, count); + return count; + } + if (!ts) { + TPD_INFO("ts not exist!\n"); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%x,%d", &addr, &length); + ts->reg_info.reg_addr = (uint16_t)addr; + ts->reg_info.reg_length = (uint16_t)length; + TPD_INFO("ts->reg_info.reg_addr = 0x%x, ts->reg_info.reg_lenght = %d\n", ts->reg_info.reg_addr, ts->reg_info.reg_length); + + return count; +} + + +static const struct file_operations proc_register_info_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_register_info_read, + .write = proc_register_info_write, +}; + +static ssize_t proc_incell_panel_info_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[32]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + sprintf(page, "%d", ts->is_incell_panel); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations proc_incell_panel_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_incell_panel_info_read, +}; + +/** + * init_touchpanel_proc - Using for create proc interface + * @ts: touchpanel_data struct using for common driver + * + * we need to set touchpanel_data struct as private_data to those file_inode + * Returning zero(success) or negative errno(failed) + */ +static ssize_t sec_update_fw_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t size) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + int val; + int ret = 0; + + if (!ts) + return size; + if (size > 2) + return size; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (ts->boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT) +#else + if (ts->boot_mode == MSM_BOOT_MODE_CHARGE) +#endif + + { + TPD_INFO("boot mode is MSM_BOOT_MODE__CHARGE,not need update tp firmware\n"); + return size; + } + + ret = kstrtoint(buffer, 10, &val); + if (ret != 0) { + TPD_INFO("invalid content: '%s', length = %zd\n", buffer, size); + return ret; + } + ts->firmware_update_type = val; + if (!ts->force_update && ts->firmware_update_type != 2) + ts->force_update = !!val; + + schedule_work(&ts->fw_update_work); + + ret = wait_for_completion_killable_timeout(&ts->fw_complete, FW_UPDATE_COMPLETE_TIMEOUT); + if (ret < 0) { + TPD_INFO("kill signal interrupt\n"); + } + + TPD_INFO("fw update finished\n"); + return size; + +} +static ssize_t sec_update_fw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + return snprintf(buf, 2, "%d\n", ts->loading_fw); +} + +static DEVICE_ATTR(tp_fw_update, 0644, sec_update_fw_show, sec_update_fw_store); + +static int init_touchpanel_proc(struct touchpanel_data *ts) +{ + int ret = 0; + struct proc_dir_entry *prEntry_tp = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + TPD_INFO("%s entry\n", __func__); + + //proc files-step1:/proc/devinfo/tp (touchpanel device info) + if(ts->fw_update_app_support) { + register_devinfo("tp", &ts->panel_data.manufacture_info); + } + + if (device_create_file(&ts->client->dev, &dev_attr_tp_fw_update)) { + TPD_INFO("driver_create_file failt\n"); + ret = -ENOMEM; + } + //proc files-step2:/proc/touchpanel + prEntry_tp = proc_mkdir("touchpanel", NULL); + if (prEntry_tp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create TP proc entry\n", __func__); + } + + //proc files-step2-1:/proc/touchpanel/tp_debug_log_level (log control interface) + prEntry_tmp = proc_create("tp_debug_log", 0644, prEntry_tp, &proc_debug_control_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files-step2-2:/proc/touchpanel/tp_fw_update (FW update interface) + prEntry_tmp = proc_create_data("tp_fw_update", 0644, prEntry_tp, &proc_fw_update_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files-step2-3:/proc/touchpanel/tp_fw_update (edge limit control interface) + if (ts->edge_limit_support) { + prEntry_tmp = proc_create_data("tp_limit_area", 0664, prEntry_tp, &proc_limit_area_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("tp_limit_enable", 0664, prEntry_tp, &proc_limit_control_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-4:/proc/touchpanel/double_tap_enable (black gesture related interface) + if (ts->black_gesture_support) { + prEntry_tmp = proc_create_data("gesture_enable", 0666, prEntry_tp, &proc_gesture_control_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("coordinate", 0444, prEntry_tp, &proc_coordinate_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-5:/proc/touchpanel/glove_mode_enable (Glove mode related interface) + if (ts->glove_mode_support) { + prEntry_tmp = proc_create_data("glove_mode_enable", 0666, prEntry_tp, &proc_glove_control_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-6:/proc/touchpanel/finger_protect_result + if (ts->spurious_fp_support) { + prEntry_tmp = proc_create_data("finger_protect_result", 0666, prEntry_tp, &proc_finger_protect_result, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("finger_protect_trigger", 0666, prEntry_tp, &proc_finger_protect_trigger, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-7:/proc/touchpanel/register_info + prEntry_tmp = proc_create_data("register_info", 0664, prEntry_tp, &proc_register_info_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("ps_status", 0666, prEntry_tp, &proc_write_ps_status_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + + //proc files-step2-8:/proc/touchpanel/incell_panel + if (ts->is_incell_panel) { + prEntry_tmp = proc_create_data("incell_panel", 0664, prEntry_tp, &proc_incell_panel_fops, ts); + } + + if (ts->gesture_test_support) { + prEntry_tmp = proc_create_data("black_screen_test", 0666, prEntry_tp, &proc_black_screen_test_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc file-step2-9:/proc/touchpanel/irq_depth + prEntry_tmp = proc_create_data("irq_depth", 0666, prEntry_tp, &proc_get_irq_depth_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc file-step2-10:/proc/touchpanel/vendor_id + prEntry_tmp = proc_create_data("vendor_id", 0444, prEntry_tp, &vendor_id_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files-step2-3:/proc/touchpanel/game_switch_enable (edge limit control interface) + if (ts->game_switch_support) { + prEntry_tmp = proc_create_data("game_switch_enable", 0666, prEntry_tp, &proc_game_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + prEntry_tmp = proc_create_data("gesture_switch", 0666, prEntry_tp, &proc_gesture_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("reject_point", 0666, prEntry_tp, &proc_reject_point_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("tpedge_limit_enable", 0666, prEntry_tp, &proc_limit_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("tp_switch_dead_zone", 0666, prEntry_tp, &proc_tp_dead_zone_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("tp_switch_corner_dead_l_zone", 0666, prEntry_tp, &proc_tp_corner_dead_zone_l_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("tp_switch_corner_dead_p_zone", 0666, prEntry_tp, &proc_tp_corner_dead_zone_p_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + ts->prEntry_tp = prEntry_tp; + + //create debug_info node + init_debug_info_proc(ts); + + return ret; +} + +//proc/touchpanel/debug_info/baseline +static int tp_baseline_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)(ts->debug_info_ops); + if (!debug_info_ops) { + TPD_INFO("debug_info_ops==NULL"); + return 0; + } + if (!debug_info_ops->baseline_read && !debug_info_ops->baseline_blackscreen_read) { + seq_printf(s, "Not support baseline proc node\n"); + return 0; + } + if ((ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) && (1 != ts->gesture_enable)) { + seq_printf(s, "Not in resume over or gesture state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + if (ts->is_suspended && ts->gesture_enable) { + if (debug_info_ops->baseline_blackscreen_read) { + debug_info_ops->baseline_blackscreen_read(s, ts->chip_data); + } + } else { + if (debug_info_ops->baseline_read) { + debug_info_ops->baseline_read(s, ts->chip_data); + } + } + + //step6: return to normal mode + ts->ts_ops->reset(ts->chip_data); + operate_mode_switch(ts); + + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; + +} + +static int data_baseline_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_baseline_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_baseline_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_baseline_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/delta +static int tp_delta_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->delta_read) { + seq_printf(s, "Not support delta proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->delta_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int data_delta_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_delta_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_delta_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_delta_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/self_delta +static int tp_self_delta_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->self_delta_read) { + seq_printf(s, "Not support self_delta proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->self_delta_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int data_self_delta_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_self_delta_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_self_delta_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_self_delta_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/self_raw +static int tp_self_raw_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->self_raw_read) { + seq_printf(s, "Not support self_raw proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->self_raw_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int data_self_raw_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_self_raw_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_self_raw_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_self_raw_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/main_register +static int tp_main_register_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->main_register_read) { + seq_printf(s, "Not support main_register proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + seq_printf(s, "es_enable:%d\n", ts->es_enable); + seq_printf(s, "touch_count:%d\n", ts->touch_count); + debug_info_ops->main_register_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int main_register_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_main_register_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_main_register_proc_fops = { + .owner = THIS_MODULE, + .open = main_register_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/reserve +static int tp_reserve_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->reserve_read) { + seq_printf(s, "Not support main_register proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->reserve_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int reserve_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_reserve_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_reserve_proc_fops = { + .owner = THIS_MODULE, + .open = reserve_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/data_limit +static int tp_limit_data_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + if (!debug_info_ops) + return 0; + if (!debug_info_ops->limit_read) { + seq_printf(s, "Not support limit_data proc node\n"); + return 0; + } + debug_info_ops->limit_read(s, ts); + + return 0; +} + +static int limit_data_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_limit_data_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_limit_data_proc_fops = { + .owner = THIS_MODULE, + .open = limit_data_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/abs_doze +static int tp_abs_doze_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->abs_doze_read) { + seq_printf(s, "Not support main_register proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->abs_doze_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int abs_doze_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_abs_doze_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_abs_doze_proc_fops = { + .owner = THIS_MODULE, + .open = abs_doze_open, + .read = seq_read, + .release = single_release, +}; + +//write function of /proc/touchpanel/earsense/palm_control +static ssize_t proc_earsense_palm_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, palm_enable :%d\n", __func__, value, ts->palm_enable); + if (value == ts->palm_enable) + return count; + + mutex_lock(&ts->mutex); + ts->palm_enable = value; + if (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_PALM_REJECTION, value); + } + mutex_unlock(&ts->mutex); + + return count; +} + +//read function of /proc/touchpanel/earsense/palm_control +static ssize_t proc_earsense_palm_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->palm_enable); + ret = sprintf(page, "%d\n", ts->palm_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/earsense/palm_control +static const struct file_operations tp_earsense_palm_control_fops = { + .write = proc_earsense_palm_control_write, + .read = proc_earsense_palm_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// write function of /proc/touchpanel/earsense/es_enable +static ssize_t proc_earsense_es_enable_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + bool state_changed = true; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, es_enable :%d\n", __func__, value, ts->es_enable); + if (value == ts->es_enable) + return count; + + mutex_lock(&ts->mutex); + if ((ts->es_enable != 1) && (value != 1)) + state_changed =false; + ts->es_enable = value; + if (!ts->es_enable) { + memset(ts->earsense_delta, 0, 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM); + } + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) && state_changed) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, ts->es_enable == 1); + } + mutex_unlock(&ts->mutex); + + return count; +} + +// read function of /proc/touchpanel/earsense/es_enable +static ssize_t proc_earsense_es_enable_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->es_enable); + ret = sprintf(page, "%d\n", ts->es_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/earsense/es_enable +static const struct file_operations tp_earsense_es_enable_fops = { + .write = proc_earsense_es_enable_write, + .read = proc_earsense_es_enable_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/es_touch_count +static ssize_t proc_earsense_touchcnt_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->touch_count); + mutex_lock(&ts->mutex); + ret = sprintf(page, "%d\n", ts->touch_count); + mutex_unlock(&ts->mutex); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/earsense/es_touch_count +static const struct file_operations tp_earsense_es_touchcnt_fops = { + .read = proc_earsense_touchcnt_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/rawdata +static ssize_t proc_earsense_rawdata_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int read_len = 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM; + + char *tmp_data = NULL; + if (!ts) + *ppos += 11; + if (*ppos > 10) + return 0; + if (count != read_len) { + TPD_INFO("%s, length:%d not match data_len:%d\n", __func__, (int)count, read_len); + return 0; + } + + TPD_DEBUG("%s is called\n", __func__); + mutex_lock(&ts->mutex); + if ((!ts->es_enable) || (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE)) { + *ppos += 11; + mutex_unlock(&ts->mutex); + return 0; + } + if (ts->delta_state == TYPE_DELTA_IDLE) { + tmp_data = kzalloc(read_len ,GFP_KERNEL); + ts->earsense_ops->rawdata_read(ts->chip_data, tmp_data, read_len); + mutex_unlock(&ts->mutex); + ret = copy_to_user(user_buf, tmp_data, read_len); + if (ret) + TPD_INFO("touch rawdata read fail\n"); + kfree(tmp_data); + *ppos += 11; + } else { + mutex_unlock(&ts->mutex); + msleep(3); + *ppos += 1; + } + + return read_len; +} + +// operation of /proc/touchpanel/earsense/rawdata +static const struct file_operations tp_earsense_rawdata_fops = { + .read = proc_earsense_rawdata_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/delta +static ssize_t proc_earsense_delta_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int read_len = 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM; + + if (!ts) + return count; + if (*ppos > 0) + return 0; + if (count != read_len) { + TPD_INFO("%s, length:%d not match data_len:%d\n", __func__, (int)count, read_len); + return 0; + } + + TPD_DEBUG("%s is called\n", __func__); + if ((!ts->es_enable) || (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE)) { + return 0; + } + + mutex_lock(&ts->mutex_earsense); + ret = copy_to_user(user_buf, ts->earsense_delta, read_len); + mutex_unlock(&ts->mutex_earsense); + if (ret) + TPD_INFO("tp rawdata read fail\n"); + *ppos += read_len; + return read_len; +} + +// operation of /proc/touchpanel/earsense/delta +static const struct file_operations tp_earsense_delta_fops = { + .read = proc_earsense_delta_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/hover_selfdata +static ssize_t proc_earsense_selfdata_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + uint16_t data_len = 2*(ts->hw_res.TX_NUM + ts->hw_res.RX_NUM); + + char *tmp_data = NULL; + if (!ts) + *ppos += 11; + if (*ppos > 10) + return 0; + if (count != data_len) { + TPD_INFO("%s, length:%d not match data_len:%d\n", __func__, (int)count, data_len); + return 0; + } + + TPD_DEBUG("%s is called\n", __func__); + mutex_lock(&ts->mutex); + if ((!ts->es_enable) || (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE)) { + *ppos += 11; + mutex_unlock(&ts->mutex); + return 0; + } + if (ts->delta_state == TYPE_DELTA_IDLE) { + tmp_data = kzalloc(data_len ,GFP_KERNEL); + ts->earsense_ops->self_data_read(ts->chip_data, tmp_data, data_len); + mutex_unlock(&ts->mutex); + ret = copy_to_user(user_buf, tmp_data, data_len); + if (ret) + TPD_INFO("tp self delta read fail\n"); + kfree(tmp_data); + *ppos += 11; + } else { + mutex_unlock(&ts->mutex); + msleep(3); + *ppos += 1; + } + + return data_len; +} + +// operation of /proc/touchpanel/earsense/hover_selfdata +static const struct file_operations tp_earsense_selfdata_fops = { + .read = proc_earsense_selfdata_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// write function of /proc/touchpanel/earsense/es_enable +static ssize_t proc_fd_enable_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, es_enable :%d\n", __func__, value, ts->fd_enable); + if (!value) { + input_event(ps_input_dev, EV_MSC, MSC_RAW, 2); + input_sync(ps_input_dev); + } + if (value == ts->fd_enable) + return count; + + mutex_lock(&ts->mutex); + ts->fd_enable = value; + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, ts->fd_enable == 1); + input_event(ps_input_dev, EV_MSC, MSC_RAW, 0); //when open fd report default key for sensor. + input_sync(ps_input_dev); + } + mutex_unlock(&ts->mutex); + + return count; +} + +// read function of /proc/touchpanel/fd_enable +static ssize_t proc_fd_enable_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->fd_enable); + ret = sprintf(page, "%d\n", ts->fd_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/fd_enable +static const struct file_operations tp_fd_enable_fops = { + .write = proc_fd_enable_write, + .read = proc_fd_enable_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/event_num +static ssize_t proc_event_num_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + const char *devname = NULL; + struct input_handle *handle; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + list_for_each_entry(handle, &ps_input_dev->h_list, d_node) { + if (strncmp(handle->name, "event", 5) == 0) { + devname = handle->name; + break; + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, devname, strlen(devname)); + return ret; +} + +// operation of /proc/touchpanel/event_num +static const struct file_operations tp_event_num_fops = { + .read = proc_event_num_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_fd_calibrate_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, fd_calibrate :%d\n", __func__, value, ts->fd_calibrate); + + mutex_lock(&ts->mutex); + ts->fd_calibrate = value; + if (ts->fd_enable) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_CALIBRATE, ts->fd_calibrate); + } + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_fd_calibrate_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->fd_calibrate); + ret = sprintf(page, "%d\n", ts->fd_calibrate); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations tp_fd_calibrate_fops = { + .write = proc_fd_calibrate_write, + .read = proc_fd_calibrate_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_refresh_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 4) + return count; + + TPD_DEBUG("%s value: %d, lcd_refresh_rate_switch :%d\n", __func__, value, ts->lcd_refresh_rate); + if (value == ts->lcd_refresh_rate) + return count; + + mutex_lock(&ts->mutex); + ts->lcd_refresh_rate = value; + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_REFRESH_SWITCH, ts->lcd_refresh_rate); + } + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_refresh_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->lcd_refresh_rate); + ret = sprintf(page, "%d\n", ts->lcd_refresh_rate); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} +// operation of /proc/touchpanel/lcd_refresh_rate_switch +static const struct file_operations tp_lcd_refresh_switch_fops = { + .write = proc_refresh_switch_write, + .read = proc_refresh_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_touch_hold_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, touch_hold_enable :%d\n", __func__, value, ts->touch_hold_enable); + if (value == 2) {//fingerprint unlock success in FOD, close touchhold + if (ts->is_suspended) + ts->skip_reset_in_resume = true; + ts->skip_enable_touchhold = true; + return count; + } else { + ts->skip_reset_in_resume = false; + } + + ts->touch_hold_enable = value; + ts->skip_enable_touchhold = false; + + if ((ts->is_suspended) && (!ts->gesture_enable)) { //suspend and close gesture cannot response touchhold + return count; + } + + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_HOLD, ts->touch_hold_enable); + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_touch_hold_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->touch_hold_enable); + ret = sprintf(page, "%d\n", ts->touch_hold_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/touch_hold +static const struct file_operations tp_touch_hold_switch_fops = { + .write = proc_touch_hold_switch_write, + .read = proc_touch_hold_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_touch_area_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 1) + return count; + + TPD_DEBUG("%s value: %d, touch_hold_enable :%d\n", __func__, value, ts->touch_area_switch); + if (value == ts->touch_area_switch) + return count; + + if ((ts->is_suspended) && (!ts->gesture_enable)) { //suspend and close gesture cannot response touchhold + return count; + } + + mutex_lock(&ts->mutex); + ts->touch_area_switch = value; + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_AREA_SWITCH, ts->touch_area_switch == 1); + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_touch_area_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->touch_area_switch); + ret = sprintf(page, "%d\n", ts->touch_area_switch); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/touch_hold +static const struct file_operations tp_touch_area_switch_fops = { + .write = proc_touch_area_switch_write, + .read = proc_touch_area_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; +static ssize_t proc_fingerprint_int_test_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 1) + return count; + + TPD_DEBUG("%s value: %d, fingerprint_int_test :%d\n", __func__, value, ts->fingerprint_int_test); + if (value == ts->fingerprint_int_test) + return count; + + mutex_lock(&ts->mutex); + ts->fingerprint_int_test = value; + ts->ts_ops->mode_switch(ts->chip_data, MODE_FINGERPRINT_TEST, ts->fingerprint_int_test == 1); + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_fingerprint_int_test_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->fingerprint_int_test); + ret = sprintf(page, "%d\n", ts->fingerprint_int_test); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations tp_fingerprint_int_test_fops = { + .write = proc_fingerprint_int_test_write, + .read = proc_fingerprint_int_test_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_charge_detect_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, charge detect enable:%d\n", __func__, value, ts->charge_detect); + ts->charge_detect = value; + mutex_lock(&ts->mutex); + if (ts->charge_detect_support && ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_CHARGE, ts->charge_detect); + } + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_charge_detect_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->charge_detect); + ret = sprintf(page, "%d\n", ts->charge_detect); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/charge_detect +static const struct file_operations tp_charge_detect_fops = { + .write = proc_charge_detect_write, + .read = proc_charge_detect_read, + .open = simple_open, + .owner = THIS_MODULE, +}; +static ssize_t proc_wireless_charge_detect_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, charge detect enable:%d\n", __func__, value, ts->wireless_charge_detect); + ts->wireless_charge_detect = value; + mutex_lock(&ts->mutex); + if (ts->wireless_charge_support && ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_WIRELESS_CHARGE, ts->wireless_charge_detect); + } + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_wireless_charge_detect_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->wireless_charge_detect); + ret = sprintf(page, "%d\n", ts->wireless_charge_detect); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/wireless_charge_detect +static const struct file_operations tp_wireless_charge_detect_fops = { + .write = proc_wireless_charge_detect_write, + .read = proc_wireless_charge_detect_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_audio_noise_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, audio noise detect enable:%d\n", __func__, value, ts->audio_noise_detect); + ts->audio_noise_detect = value; + mutex_lock(&ts->mutex); + if (ts->audio_noise_support && ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_AUDIO_NOISE, ts->audio_noise_detect); + } + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_audio_noise_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->audio_noise_detect); + ret = sprintf(page, "%d\n", ts->audio_noise_detect); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/audio_noise_switch +static const struct file_operations tp_audio_noise_switch_fops = { + .write = proc_audio_noise_switch_write, + .read = proc_audio_noise_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + + +//proc/touchpanel/debug_info/ +static int init_debug_info_proc(struct touchpanel_data *ts) +{ + int ret = 0; + struct proc_dir_entry *prEntry_debug_info = NULL; + struct proc_dir_entry *prEntry_earsense = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + TPD_INFO("%s entry\n", __func__); + + //proc files-step1:/proc/touchpanel/debug_info + prEntry_debug_info = proc_mkdir("debug_info", ts->prEntry_tp); + if (prEntry_debug_info == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create debug_info proc entry\n", __func__); + } + + // show limit data interface + prEntry_tmp = proc_create_data("data_limit", 0666, prEntry_debug_info, &tp_limit_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show baseline data interface + prEntry_tmp = proc_create_data("baseline", 0666, prEntry_debug_info, &tp_baseline_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show delta interface + prEntry_tmp = proc_create_data("delta", 0666, prEntry_debug_info, &tp_delta_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show self delta interface + prEntry_tmp = proc_create_data("self_delta", 0666, prEntry_debug_info, &tp_self_delta_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show self_raw interface + prEntry_tmp = proc_create_data("self_raw", 0666, prEntry_debug_info, &tp_self_raw_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show main_register interface + prEntry_tmp = proc_create_data("main_register", 0666, prEntry_debug_info, &tp_main_register_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show reserve interface + prEntry_tmp = proc_create_data("reserve", 0666, prEntry_debug_info, &tp_reserve_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show abs_doze interface + prEntry_tmp = proc_create_data("abs_doze", 0666, prEntry_debug_info, &tp_abs_doze_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ts->prEntry_debug_tp = prEntry_debug_info; + + if (ts->ear_sense_support) { + //proc files-step1:/proc/touchpanel/earsense + prEntry_earsense = proc_mkdir("earsense", ts->prEntry_tp); + if (prEntry_earsense == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create debug_info proc entry\n", __func__); + } + // show baseline for earsense + prEntry_tmp = proc_create_data("rawdata", 0666, prEntry_earsense, &tp_earsense_rawdata_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // show delta for earsense + prEntry_tmp = proc_create_data("delta", 0666, prEntry_earsense, &tp_earsense_delta_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // show self delta for earsense + prEntry_tmp = proc_create_data("hover_selfdata", 0666, prEntry_earsense, &tp_earsense_selfdata_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // palm control for earsense + prEntry_tmp = proc_create_data("palm_control", 0666, prEntry_earsense, &tp_earsense_palm_control_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // es_enable for earsense + prEntry_tmp = proc_create_data("es_enable", 0666, prEntry_earsense, &tp_earsense_es_enable_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // touch count for earsense + prEntry_tmp = proc_create_data("es_touch_count", 0666, prEntry_earsense, &tp_earsense_es_touchcnt_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + if (ts->face_detect_support) { + // proc for face detect + prEntry_tmp = proc_create_data("fd_enable", 0666, ts->prEntry_tp, &tp_fd_enable_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("event_num", 0666, ts->prEntry_tp, &tp_event_num_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("fd_calibrate", 0666, ts->prEntry_tp, &tp_fd_calibrate_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + if (ts->lcd_refresh_rate_switch) { + // proc for lcd_refresh_rate_switch + prEntry_tmp = proc_create_data("lcd_refresh_rate_switch", 0666, ts->prEntry_tp, &tp_lcd_refresh_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + if (ts->touch_hold_support) { + // proc for touchhold switch + prEntry_tmp = proc_create_data("touch_hold", 0666, ts->prEntry_tp, &tp_touch_hold_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("touch_area_switch", 0666, ts->prEntry_tp, &tp_touch_area_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + // proc for lcd_refresh_rate_switch + prEntry_tmp = proc_create_data("fingerprint_int_test", 0666, ts->prEntry_tp, &tp_fingerprint_int_test_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // proc for charge detect + prEntry_tmp = proc_create_data("charge_detect", 0666, ts->prEntry_tp, &tp_charge_detect_fops, ts); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entey, %d\n", __func__, __LINE__); + } + + //proc for wireless charge detect + prEntry_tmp = proc_create_data("wireless_charge_detect", 0666, ts->prEntry_tp, &tp_wireless_charge_detect_fops, ts); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entey, %d\n", __func__, __LINE__); + } + + //proc for audio noise switch + prEntry_tmp = proc_create_data("audio_noise_switch", 0666, ts->prEntry_tp, &tp_audio_noise_switch_fops, ts); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entey, %d\n", __func__, __LINE__); + } + + return ret; +} + +/** + * init_input_device - Using for register input device + * @ts: touchpanel_data struct using for common driver + * + * we should using this function setting input report capbility && register input device + * Returning zero(success) or negative errno(failed) + */ +static int init_input_device(struct touchpanel_data *ts) +{ + int ret = 0; + struct kobject *vk_properties_kobj; + + TPD_INFO("%s is called\n", __func__); + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + TPD_INFO("Failed to allocate input device\n"); + return ret; + } + + ts->kpd_input_dev = input_allocate_device(); + if (ts->kpd_input_dev == NULL) { + ret = -ENOMEM; + TPD_INFO("Failed to allocate key input device\n"); + return ret; + } + + if (ts->face_detect_support) { + ps_input_dev = input_allocate_device(); + if (ps_input_dev == NULL) { + ret = -ENOMEM; + TPD_INFO("Failed to allocate ps input device\n"); + return ret; + } + + ps_input_dev->name = TPD_DEVICE"_ps"; + set_bit(EV_MSC, ps_input_dev->evbit); + set_bit(MSC_RAW, ps_input_dev->mscbit); + } + + ts->input_dev->name = TPD_DEVICE; + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit); + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + set_bit(BTN_TOUCH, ts->input_dev->keybit); + if (ts->black_gesture_support) { + set_bit(KEY_F4, ts->input_dev->keybit); + } + + ts->kpd_input_dev->name = TPD_DEVICE"_kpd"; + set_bit(EV_KEY, ts->kpd_input_dev->evbit); + set_bit(EV_SYN, ts->kpd_input_dev->evbit); + + switch(ts->vk_type) { + case TYPE_PROPERTIES : + { + TPD_DEBUG("Type 1: using board_properties\n"); + vk_properties_kobj = kobject_create_and_add("board_properties", NULL); + if (vk_properties_kobj) + ret = sysfs_create_group(vk_properties_kobj, &properties_attr_group); + if (!vk_properties_kobj || ret) + TPD_DEBUG("failed to create board_properties\n"); + break; + } + case TYPE_AREA_SEPRATE: + { + TPD_DEBUG("Type 2:using same IC (button zone && touch zone are seprate)\n"); + if (CHK_BIT(ts->vk_bitmap, BIT_MENU)) + set_bit(KEY_MENU, ts->kpd_input_dev->keybit); + if (CHK_BIT(ts->vk_bitmap, BIT_HOME)) + set_bit(KEY_HOMEPAGE, ts->kpd_input_dev->keybit); + if (CHK_BIT(ts->vk_bitmap, BIT_BACK)) + set_bit(KEY_BACK, ts->kpd_input_dev->keybit); + break; + } + default : + break; + } + +#ifdef TYPE_B_PROTOCOL + input_mt_init_slots(ts->input_dev, ts->max_num, 0); +#endif + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->resolution_info.max_x, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->resolution_info.max_y, 0, 0); + input_set_drvdata(ts->input_dev, ts); + input_set_drvdata(ts->kpd_input_dev, ts); + + if (input_register_device(ts->input_dev)) { + TPD_INFO("%s: Failed to register input device\n", __func__); + input_free_device(ts->input_dev); + return -1; + } + + if (input_register_device(ts->kpd_input_dev)) { + TPD_INFO("%s: Failed to register key input device\n", __func__); + input_free_device(ts->kpd_input_dev); + return -1; + } + + if (ts->face_detect_support) { + if (input_register_device(ps_input_dev)) { + TPD_INFO("%s: Failed to register ps input device\n", __func__); + input_free_device(ps_input_dev); + return -1; + } + } + + return 0; +} + +/** + * init_parse_dts - parse dts, get resource defined in Dts + * @dev: i2c_client->dev using to get device tree + * @ts: touchpanel_data, using for common driver + * + * If there is any Resource needed by chip_data, we can add a call-back func in this function + * Do not care the result : Returning void type + */ +static void init_parse_dts(struct device *dev, struct touchpanel_data *ts) +{ + int rc; + struct device_node *np; + int temp_array[8]; + int tx_rx_num[2]; + int val = 0; + + np = dev->of_node; + + ts->register_is_16bit = of_property_read_bool(np, "register-is-16bit"); + ts->edge_limit_support = of_property_read_bool(np, "edge_limit_support"); + ts->glove_mode_support = of_property_read_bool(np, "glove_mode_support"); + ts->esd_handle_support = of_property_read_bool(np, "esd_handle_support"); + ts->spurious_fp_support = of_property_read_bool(np, "spurious_fingerprint_support"); + ts->charger_pump_support = of_property_read_bool(np, "charger_pump_support"); + ts->black_gesture_support = of_property_read_bool(np, "black_gesture_support"); + ts->gesture_test_support = of_property_read_bool(np, "black_gesture_test_support"); + ts->fw_update_app_support = of_property_read_bool(np, "fw_update_app_support"); + ts->game_switch_support = of_property_read_bool(np, "game_switch_support"); + ts->ear_sense_support = of_property_read_bool(np, "ear_sense_support"); + ts->smart_gesture_support = of_property_read_bool(np, "smart_gesture_support"); + ts->is_noflash_ic = of_property_read_bool(np, "noflash_support"); + ts->face_detect_support = of_property_read_bool(np, "face_detect_support"); + ts->lcd_refresh_rate_switch = of_property_read_bool(np, "lcd_refresh_rate_switch"); + ts->touch_hold_support = of_property_read_bool(np, "touch_hold_support"); + ts->project_info = of_property_read_bool(np, "project_info"); + ts->charge_detect_support = of_property_read_bool(np, "charge_detect_support"); + ts->wireless_charge_support = of_property_read_bool(np, "wireless_charge_support"); + ts->module_id_support = of_property_read_bool(np, "module_id_support"); + ts->audio_noise_support = of_property_read_bool(np, "audio_noise_support"); + ts->spuri_fp_touch.lcd_trigger_fp_check = of_property_read_bool(np, "lcd_trigger_fp_check"); + ts->report_flow_unlock_support = of_property_read_bool(np, "report_flow_unlock_support"); + ts->spuri_fp_touch.lcd_resume_ok = true; + + TPD_DEBUG("ts->report_flow_unlock_support = %d", ts->report_flow_unlock_support); + + rc = of_property_read_string(np, "project-name", &ts->panel_data.project_name); + if (rc < 0) { + TPD_INFO("failed to get project name, firmware/limit name will be invalid\n"); + } + rc = of_property_read_string(np, "chip-name", &ts->panel_data.chip_name); + if (rc < 0) { + TPD_INFO("failed to get chip name, firmware/limit name will be invalid\n"); + } + rc = of_property_read_u32(np, "module_id" , &ts->panel_data.tp_type); + if(rc < 0) { + TPD_INFO("module id is not specified\n"); + ts->panel_data.tp_type = 0; + } + + rc = of_property_read_u32(np, "vdd_2v8_volt", &ts->hw_res.vdd_volt); + if (rc < 0) { + ts->hw_res.vdd_volt = 0; + TPD_INFO("vdd_2v8_volt not defined\n"); + } + + if(strcmp(ts->panel_data.project_name, "20801") == 0){ // comparing project code of avicii + project_code = 20801; + TPD_INFO("project-code***************: %d ",project_code); + } + // irq gpio + ts->hw_res.irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0, &(ts->irq_flags)); + if (gpio_is_valid(ts->hw_res.irq_gpio)) { + rc= gpio_request(ts->hw_res.irq_gpio, "tp_irq_gpio"); + if (rc) { + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.irq_gpio); + } + } else { + TPD_INFO("irq-gpio not specified in dts\n"); + } + + ts->irq = gpio_to_irq(ts->hw_res.irq_gpio); + ts->client->irq = ts->irq; + // reset gpio + ts->hw_res.reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (gpio_is_valid(ts->hw_res.reset_gpio)) { + rc = gpio_request(ts->hw_res.reset_gpio, "reset-gpio"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.reset_gpio); + } else { + TPD_INFO("ts->reset-gpio not specified\n"); + } + + TPD_INFO("%s : irq_gpio = %d, irq_flags = 0x%x ts_irq = %d, reset_gpio = %d\n", + __func__, ts->hw_res.irq_gpio, ts->irq_flags, ts->irq, ts->hw_res.reset_gpio); + + // tp type gpio + ts->hw_res.id1_gpio = of_get_named_gpio(np, "id1-gpio", 0); + if (gpio_is_valid(ts->hw_res.id1_gpio)) { + rc = gpio_request(ts->hw_res.id1_gpio, "TP_ID1"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.id1_gpio); + } else { + TPD_INFO("id1_gpio not specified\n"); + } + + ts->hw_res.id2_gpio = of_get_named_gpio(np, "id2-gpio", 0); + if (gpio_is_valid(ts->hw_res.id2_gpio)) { + rc = gpio_request(ts->hw_res.id2_gpio, "TP_ID2"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.id2_gpio); + } else { + TPD_INFO("id2_gpio not specified\n"); + } + + ts->hw_res.id3_gpio = of_get_named_gpio(np, "id3-gpio", 0); + if (gpio_is_valid(ts->hw_res.id3_gpio)) { + rc = gpio_request(ts->hw_res.id3_gpio, "TP_ID3"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.id3_gpio); + } else { + TPD_INFO("id3_gpio not specified\n"); + } + + ts->hw_res.pinctrl= devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(ts->hw_res.pinctrl)) { + TPD_INFO("Getting pinctrl handle failed"); + } else { + ts->hw_res.pin_set_high = pinctrl_lookup_state(ts->hw_res.pinctrl, "pin_set_high"); + if (IS_ERR_OR_NULL(ts->hw_res.pin_set_high)) { + TPD_INFO("Failed to get the high state pinctrl handle \n"); + } + ts->hw_res.pin_set_low = pinctrl_lookup_state(ts->hw_res.pinctrl, "pin_set_low"); + if (IS_ERR_OR_NULL(ts->hw_res.pin_set_low)) { + TPD_INFO(" Failed to get the low state pinctrl handle\n"); + } + } + ts->hw_res.enable2v8_gpio = of_get_named_gpio(np, "enable2v8_gpio", 0); + if (ts->hw_res.enable2v8_gpio < 0) { + TPD_INFO("ts->hw_res.enable2v8_gpio not specified\n"); + } else { + if (gpio_is_valid(ts->hw_res.enable2v8_gpio)) { + rc = gpio_request(ts->hw_res.enable2v8_gpio, "vdd2v8-gpio"); + if (rc) { + TPD_INFO("unable to request gpio [%d] %d\n", ts->hw_res.enable2v8_gpio, rc); + } + } + } + + ts->hw_res.enable1v8_gpio = of_get_named_gpio(np, "enable1v8_gpio", 0); + if (ts->hw_res.enable1v8_gpio < 0) { + TPD_INFO("ts->hw_res.enable1v8_gpio not specified\n"); + } else { + if (gpio_is_valid(ts->hw_res.enable1v8_gpio)) { + rc = gpio_request(ts->hw_res.enable1v8_gpio, "vcc1v8-gpio"); + if (rc) { + TPD_INFO("unable to request gpio [%d], %d\n", ts->hw_res.enable1v8_gpio, rc); + } + } + } + + // interrupt mode + ts->int_mode = BANNABLE; + rc = of_property_read_u32(np, "touchpanel,int-mode", &val); + if (rc) { + TPD_INFO("int-mode not specified\n"); + } else { + if (val < INTERRUPT_MODE_MAX) { + ts->int_mode = val; + } + } + + // resolution info + rc = of_property_read_u32(np, "touchpanel,max-num-support", &ts->max_num); + if (rc) { + TPD_INFO("ts->max_num not specified\n"); + ts->max_num = 10; + } + + rc = of_property_read_u32_array(np, "touchpanel,tx-rx-num", tx_rx_num, 2); + if (rc) { + TPD_INFO("tx-rx-num not set\n"); + ts->hw_res.TX_NUM = 0; + ts->hw_res.RX_NUM = 0; + } else { + ts->hw_res.TX_NUM = tx_rx_num[0]; + ts->hw_res.RX_NUM = tx_rx_num[1]; + } + TPD_INFO("TX_NUM = %d, RX_NUM = %d \n", ts->hw_res.TX_NUM, ts->hw_res.RX_NUM); + + rc = of_property_read_u32_array(np, "earsense,tx-rx-num", tx_rx_num, 2); + if (rc) { + TPD_INFO("tx-rx-num not set\n"); + ts->hw_res.EARSENSE_TX_NUM = ts->hw_res.TX_NUM; + ts->hw_res.EARSENSE_RX_NUM = ts->hw_res.RX_NUM / 2; + } else { + ts->hw_res.EARSENSE_TX_NUM = tx_rx_num[0]; + ts->hw_res.EARSENSE_RX_NUM = tx_rx_num[1]; + } + TPD_INFO("EARSENSE_TX_NUM = %d, EARSENSE_RX_NUM = %d \n", ts->hw_res.EARSENSE_TX_NUM, ts->hw_res.EARSENSE_RX_NUM); + + rc = of_property_read_u32_array(np, "touchpanel,display-coords", temp_array, 2); + if (rc) { + TPD_INFO("Lcd size not set\n"); + ts->resolution_info.LCD_WIDTH = 0; + ts->resolution_info.LCD_HEIGHT = 0; + }else{ + ts->resolution_info.LCD_WIDTH = temp_array[0]; + ts->resolution_info.LCD_HEIGHT = temp_array[1]; + } + if (ts->module_id_support && lcd_id == 0) { //18821 TP + ts->resolution_info.LCD_WIDTH = 1439; + ts->resolution_info.LCD_HEIGHT = 3119; + } + if (lcd_id == 1) { //19811 TP + ts->resolution_info.LCD_WIDTH = 1439; + ts->resolution_info.LCD_HEIGHT = 3168; + ts->hw_res.TX_NUM = 17; + ts->hw_res.RX_NUM = 38; + } + if (lcd_id == 2) { + ts->resolution_info.LCD_WIDTH = 1079; + ts->resolution_info.LCD_HEIGHT = 2399; + ts->hw_res.TX_NUM = 16; + ts->hw_res.RX_NUM = 36; + } + + rc = of_property_read_u32_array(np, "touchpanel,panel-coords", temp_array, 2); + if (rc) { + ts->resolution_info.max_x = 0; + ts->resolution_info.max_y = 0; + }else{ + ts->resolution_info.max_x = temp_array[0]; + ts->resolution_info.max_y = temp_array[1]; + } + if (ts->module_id_support && lcd_id == 0) { //18821 TP + ts->resolution_info.max_x = 1439; + ts->resolution_info.max_y = 3199; + } + if (lcd_id == 1) { //19811 TP + ts->resolution_info.max_x = 1439; + ts->resolution_info.max_y = 3168; + } + if (lcd_id == 2) { + ts->resolution_info.max_x = 1079; + ts->resolution_info.max_y = 2399; + } + + rc = of_property_read_u32_array(np, "touchpanel,touchmajor-limit", temp_array, 2); + if (rc) { + ts->touch_major_limit.width_range = 0; + ts->touch_major_limit.height_range = 0; + }else{ + ts->touch_major_limit.width_range = temp_array[0]; + ts->touch_major_limit.height_range = temp_array[1]; + } + TPD_INFO("LCD_WIDTH = %d, LCD_HEIGHT = %d, max_x = %d, max_y = %d, limit_witdh = %d, limit_height = %d\n", + ts->resolution_info.LCD_WIDTH, ts->resolution_info.LCD_HEIGHT, ts->resolution_info.max_x, ts->resolution_info.max_y,\ + ts->touch_major_limit.width_range, ts->touch_major_limit.height_range); + + // virturl key Related + rc = of_property_read_u32_array(np, "touchpanel,button-type", temp_array, 2); + if (rc < 0) { + TPD_INFO("error:button-type should be setting in dts!"); + } else { + ts->vk_type = temp_array[0]; + ts->vk_bitmap = temp_array[1] & 0xFF; + if (ts->vk_type == TYPE_PROPERTIES) { + rc = of_property_read_u32_array(np, "touchpanel,button-map", temp_array, 8); + if (rc) { + TPD_INFO("button-map not set\n"); + }else{ + ts->button_map.coord_menu.x = temp_array[0]; + ts->button_map.coord_menu.y = temp_array[1]; + ts->button_map.coord_home.x = temp_array[2]; + ts->button_map.coord_home.y = temp_array[3]; + ts->button_map.coord_back.x = temp_array[4]; + ts->button_map.coord_back.y = temp_array[5]; + ts->button_map.width_x = temp_array[6]; + ts->button_map.height_y = temp_array[7]; + } + } + } + + //touchkey take tx num and rx num + rc = of_property_read_u32_array(np, "touchpanel.button-TRx", temp_array, 2); + if(rc < 0) { + TPD_INFO("error:button-TRx should be setting in dts!\n"); + ts->hw_res.key_TX = 0; + ts->hw_res.key_RX = 0; + } else { + ts->hw_res.key_TX = temp_array[0]; + ts->hw_res.key_RX = temp_array[1]; + TPD_INFO("key_tx is %d, key_rx is %d\n", ts->hw_res.key_TX, ts->hw_res.key_RX); + } + + //set incell panel parameter, for of_property_read_bool return 1 when success and return 0 when item is not exist + rc = ts->is_incell_panel = of_property_read_bool(np, "incell_screen"); + if(rc > 0) { + TPD_INFO("panel is incell!\n"); + ts->is_incell_panel = 1; + } else { + TPD_INFO("panel is oncell!\n"); + ts->is_incell_panel = 0; + } + + // We can Add callback fuction here if necessary seprate some dts config for chip_data +} + +int init_power_control(struct touchpanel_data *ts) +{ + int ret = 0; + + // 1.8v + ts->hw_res.vcc_1v8 = regulator_get(ts->dev, "vcc_1v8"); + if (IS_ERR_OR_NULL(ts->hw_res.vcc_1v8)) { + TPD_INFO("Regulator get failed vcc_1v8, ret = %d\n", ret); + } else { + if (regulator_count_voltages(ts->hw_res.vcc_1v8) > 0) { + ret = regulator_set_voltage(ts->hw_res.vcc_1v8, 1800000, 1800000); + if (ret) { + dev_err(ts->dev, "Regulator set_vtg failed vcc_i2c rc = %d\n", ret); + goto regulator_vcc_1v8_put; + } + + ret = regulator_set_load(ts->hw_res.vcc_1v8, 200000); + if (ret < 0) { + dev_err(ts->dev, "Failed to set vcc_1v8 mode(rc:%d)\n", ret); + goto regulator_vcc_1v8_put; + } + } + } + // vdd 2.8v + ts->hw_res.vdd_2v8 = regulator_get(ts->dev, "vdd_2v8"); + if (IS_ERR_OR_NULL(ts->hw_res.vdd_2v8)) { + TPD_INFO("Regulator vdd2v8 get failed, ret = %d\n", ret); + } else { + if (regulator_count_voltages(ts->hw_res.vdd_2v8) > 0) { + TPD_INFO("set avdd voltage to %d uV\n", ts->hw_res.vdd_volt); + if (ts->hw_res.vdd_volt) { + ret = regulator_set_voltage(ts->hw_res.vdd_2v8, ts->hw_res.vdd_volt, ts->hw_res.vdd_volt); + } else { + ret = regulator_set_voltage(ts->hw_res.vdd_2v8, 3100000, 3100000); + } + if (ret) { + dev_err(ts->dev, "Regulator set_vtg failed vdd rc = %d\n", ret); + goto regulator_vdd_2v8_put; + } + + ret = regulator_set_load(ts->hw_res.vdd_2v8, 200000); + if (ret < 0) { + dev_err(ts->dev, "Failed to set vdd_2v8 mode(rc:%d)\n", ret); + goto regulator_vdd_2v8_put; + } + } + } + + return 0; + +regulator_vdd_2v8_put: + regulator_put(ts->hw_res.vdd_2v8); + ts->hw_res.vdd_2v8 = NULL; +regulator_vcc_1v8_put: + if (!IS_ERR_OR_NULL(ts->hw_res.vcc_1v8)) { + regulator_put(ts->hw_res.vcc_1v8); + ts->hw_res.vcc_1v8 = NULL; + } + + return ret; +} + +int tp_powercontrol_1v8(struct hw_resource *hw_res, bool on) +{ + int ret = 0; + + if (on) {// 1v8 power on + if (!IS_ERR_OR_NULL(hw_res->vcc_1v8)) { + TPD_INFO("Enable the Regulator1v8.\n"); + ret = regulator_enable(hw_res->vcc_1v8); + if (ret) { + TPD_INFO("Regulator vcc_i2c enable failed ret = %d\n", ret); + return ret; + } + } + + if (hw_res->enable1v8_gpio > 0) { + TPD_INFO("Enable the 1v8_gpio\n"); + ret = gpio_direction_output(hw_res->enable1v8_gpio, 1); + if (ret) { + TPD_INFO("enable the enable1v8_gpio failed.\n"); + return ret; + } + } + } else {// 1v8 power off + if (!IS_ERR_OR_NULL(hw_res->vcc_1v8)) { + TPD_INFO("Disable the Regulator1v8.\n"); + ret = regulator_disable(hw_res->vcc_1v8); + if (ret) { + TPD_INFO("Regulator vcc_i2c enable failed rc = %d\n", ret); + return ret; + } + } + + if (hw_res->enable1v8_gpio > 0) { + TPD_INFO("disable the 1v8_gpio\n"); + ret = gpio_direction_output(hw_res->enable1v8_gpio, 0); + if (ret) { + TPD_INFO("disable the enable1v8_gpio failed.\n"); + return ret; + } + } + } + + return 0; +} + +int tp_powercontrol_2v8(struct hw_resource *hw_res, bool on) +{ + int ret = 0; + + if (on) {// 2v8 power on + if (!IS_ERR_OR_NULL(hw_res->vdd_2v8)) { + TPD_INFO("Enable the Regulator2v8.\n"); + ret = regulator_enable(hw_res->vdd_2v8); + if (ret) { + TPD_INFO("Regulator vdd enable failed ret = %d\n", ret); + return ret; + } + } + if (hw_res->enable2v8_gpio > 0) { + TPD_INFO("Enable the 2v8_gpio, hw_res->enable2v8_gpio is %d\n", hw_res->enable2v8_gpio); + ret = gpio_direction_output(hw_res->enable2v8_gpio, 1); + if (ret) { + TPD_INFO("enable the enable2v8_gpio failed.\n"); + return ret; + } + } + } else {// 2v8 power off + if (!IS_ERR_OR_NULL(hw_res->vdd_2v8)) { + TPD_INFO("disable the vdd_2v8\n"); + ret = regulator_disable(hw_res->vdd_2v8); + if (ret) { + TPD_INFO("Regulator vdd disable failed rc = %d\n", ret); + return ret; + } + } + if (hw_res->enable2v8_gpio > 0) { + TPD_INFO("disable the 2v8_gpio\n"); + ret = gpio_direction_output(hw_res->enable2v8_gpio, 0); + if (ret) { + TPD_INFO("disable the enable2v8_gpio failed.\n"); + return ret; + } + } + } + return ret; +} + + +static void esd_handle_func(struct work_struct *work) +{ + int ret = 0; + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, + esd_info.esd_check_work.work); + + if (ts->loading_fw) { + TPD_INFO("FW is updating, stop esd handle!\n"); + return; + } + + mutex_lock(&ts->esd_info.esd_lock); + if (!ts->esd_info.esd_running_flag) { + TPD_INFO("Esd protector has stopped!\n"); + goto ESD_END; + } + + if (ts->is_suspended == 1) { + TPD_INFO("Touch panel has suspended!\n"); + goto ESD_END; + } + + if (!ts->ts_ops->esd_handle) { + TPD_INFO("not support ts_ops->esd_handle callback\n"); + goto ESD_END; + } + + ret = ts->ts_ops->esd_handle(ts->chip_data); + if (ret == -1) { //-1 means esd hanppened: handled in IC part, recovery the state here + operate_mode_switch(ts); + } + + if (ts->esd_info.esd_running_flag) + queue_delayed_work(ts->esd_info.esd_workqueue, &ts->esd_info.esd_check_work, ts->esd_info.esd_work_time); + else + TPD_INFO("Esd protector suspended!"); + +ESD_END: + mutex_unlock(&ts->esd_info.esd_lock); + return; +} + +/** + * esd_handle_switch - open or close esd thread + * @esd_info: touchpanel_data, using for common driver resource + * @on: bool variable using for indicating open or close esd check function. + * true:open; + * false:close; + */ +void esd_handle_switch(struct esd_information *esd_info, bool on) +{ + mutex_lock(&esd_info->esd_lock); + + if (on) { + if (!esd_info->esd_running_flag) { + esd_info->esd_running_flag = 1; + + TPD_INFO("Esd protector started, cycle: %d s\n", esd_info->esd_work_time/HZ); + queue_delayed_work(esd_info->esd_workqueue, &esd_info->esd_check_work, esd_info->esd_work_time); + } + } else { + if (esd_info->esd_running_flag) { + esd_info->esd_running_flag = 0; + + TPD_INFO("Esd protector stoped!\n"); + cancel_delayed_work(&esd_info->esd_check_work); + } + } + + mutex_unlock(&esd_info->esd_lock); +} + +int tp_register_irq_func(struct touchpanel_data *ts) +{ + int ret = 0; + +#ifdef TPD_USE_EINT + if (gpio_is_valid(ts->hw_res.irq_gpio)) { + TPD_DEBUG("%s, irq_gpio is %d, ts->irq is %d\n", __func__, ts->hw_res.irq_gpio, ts->irq); + ret = request_threaded_irq(ts->irq, NULL, + tp_irq_thread_fn, + ts->irq_flags | IRQF_ONESHOT, + TPD_DEVICE, ts); + if (ret < 0) { + TPD_INFO("%s request_threaded_irq ret is %d\n", __func__, ret); + } + } else { + TPD_INFO("%s:no valid irq\n", __func__); + } +#else + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = touchpanel_timer_func; + hrtimer_start(&ts->timer, ktime_set(3, 0), HRTIMER_MODE_REL); +#endif + + return ret; +} + +//work schdule for reading&update delta +static void touch_read_delta(struct work_struct *work) +{ + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, read_delta_work); + + mutex_lock(&ts->mutex_earsense); + mutex_lock(&ts->mutex); + ts->earsense_ops->delta_read(ts->chip_data, ts->earsense_delta, 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM); + mutex_unlock(&ts->mutex); + mutex_unlock(&ts->mutex_earsense); + ts->delta_state=TYPE_DELTA_IDLE; +} + +void tp_util_get_vendor(struct touchpanel_data *ts, struct panel_info *panel_data) +{ + + panel_data->test_limit_name = kzalloc(MAX_LIMIT_DATA_LENGTH, GFP_KERNEL); + if (panel_data->test_limit_name == NULL) { + TPD_INFO("panel_data.test_limit_name kzalloc error\n"); + } + + if (ts->module_id_support) { + TPD_INFO("enter %s\n", __func__); + if (lcd_id) { + if (lcd_id == 1) { + panel_data->project_name = "19811"; + panel_data->chip_name = "SY79x"; + } + if (lcd_id == 2) { + panel_data->project_name = "19821"; + panel_data->chip_name = "SY771"; + } + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/FW_%s_%s.img", panel_data->project_name, panel_data->chip_name); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/LIMIT_%s_%s.img", panel_data->project_name, panel_data->chip_name); + } + } else { + panel_data->chip_name = "SY761"; + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/FW_%s_%s.img", panel_data->project_name, panel_data->chip_name); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/LIMIT_%s_%s.img", panel_data->project_name, panel_data->chip_name); + } + } + } else { + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/FW_%s_%s.img", panel_data->project_name, panel_data->chip_name); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/LIMIT_%s_%s.img", panel_data->project_name, panel_data->chip_name); + } + } + TPD_INFO("end %s\n", __func__); + sprintf(panel_data->manufacture_info.version, "0x%x", panel_data->TP_FW); + sprintf(panel_data->manufacture_info.manufacture, panel_data->chip_name); + + push_component_info(TOUCH_KEY, panel_data->manufacture_info.version, panel_data->manufacture_info.manufacture); + push_component_info(TP, panel_data->manufacture_info.version, panel_data->manufacture_info.manufacture); + + TPD_INFO("%s fw:%s limit:%s\n", __func__, panel_data->fw_name, panel_data->test_limit_name); +} + + +void sec_ts_pinctrl_configure(struct hw_resource *hw_res, bool enable) +{ + int ret; + + if (enable) { + if (hw_res->pinctrl) { + ret = pinctrl_select_state(hw_res->pinctrl, hw_res->pin_set_high); + if (ret) + TPD_INFO("%s could not set active pinstate", __func__); + } + } else { + if (hw_res->pinctrl) { + ret = pinctrl_select_state(hw_res->pinctrl, hw_res->pin_set_low); + if (ret) + TPD_INFO("%s could not set suspend pinstate", __func__); + } + } +} + + +/** + * register_common_touch_device - parse dts, get resource defined in Dts + * @pdata: touchpanel_data, using for common driver + * + * entrance of common touch Driver + * Returning zero(sucess) or negative errno(failed) + */ + +static int get_lcd_name(const char *str) +{ + TPD_INFO("enter %s, cld_name is %s\n", __func__, str); + if (!strcmp(str, "qcom,mdsss_dsi_samsung_oneplus_dsc_cmd")) { //using 18821 TP + lcd_id = 0; + } else if (!strcmp(str, "qcom,mdss_dsi_samsung_ana6706_dsc_cmd")) { //using 19811 TP + lcd_id = 1; + } else if ((!strcmp(str, "qcom,mdss_dsi_samsung_ana6705_dsc_cmd")) || (!strcmp(str, "qcom,mdss_dsi_samsung_dd305_dsc_cmd")) + || (!strcmp(str, "qcom,mdss_dsi_samsung_amb655x_dsc_cmd"))) { //using 19821 TP + lcd_id = 2; + } + + TPD_INFO("lcd_id is %d\n", lcd_id); + return 0; +} + + +static int check_dt(struct device_node *np) +{ + int i; + int count; + struct device_node *node; + struct drm_panel *panel; + + count = of_count_phandle_with_args(np, "panel", NULL); + TPD_INFO("count is %d\n", count); + if (count <= 0) + return ENODEV; + + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "panel", i); + TPD_INFO("node name is %s\n", node->name); + panel = of_drm_find_panel(node); + if (!IS_ERR(panel)) { + get_lcd_name(node->name); + lcd_active_panel = panel; + return 0; + } + of_node_put(node); + TPD_INFO("%s: error3\n", __func__); + } + + return -ENODEV; +} + +int register_common_touch_device(struct touchpanel_data *pdata) +{ + struct touchpanel_data *ts = pdata; + struct invoke_method *invoke; + struct device_node *dp = pdata->client->dev.of_node; + + int ret = -1; + + TPD_INFO("%s is called\n", __func__); + ret = check_dt(dp); + if (ret != 0 || + !i2c_check_functionality(ts->client->adapter, I2C_FUNC_I2C)) { + ret = -EIO; + TPD_INFO("check dt failed ret is %d\n", ret); + return ret; + } + + + //step : FTM process + ts->boot_mode = get_boot_mode(); + if (ts->boot_mode == MSM_BOOT_MODE_FACTORY || ts->boot_mode == MSM_BOOT_MODE_RF || ts->boot_mode == MSM_BOOT_MODE_CHARGE) + { + TPD_INFO("%s: not int normal mode, return.\n", __func__); + return -1; + } + + //step1 : dts parse + init_parse_dts(ts->dev, ts); + + //step2 : IIC interfaces init + init_touch_interfaces(ts->dev, ts->register_is_16bit); + + //step3 : mutex init + mutex_init(&ts->mutex); + mutex_init(&ts->report_mutex); + init_completion(&ts->pm_complete); + init_completion(&ts->fw_complete); + init_completion(&ts->resume_complete); + + ts->async_workqueue = create_singlethread_workqueue("tp_async"); + if (!ts->async_workqueue) { + ret = -ENOMEM; + return -1; + } + INIT_WORK(&ts->async_work, tp_async_work_lock); + + if (ts->has_callback) { + invoke = (struct invoke_method *)pdata->chip_data; + invoke->invoke_common = tp_work_common_callback; + invoke->async_work = tp_async_work_callback; + } + gpio_direction_output(ts->hw_res.reset_gpio, 0); + + sec_ts_pinctrl_configure(&ts->hw_res, true); + //step4 : Power init && setting + + preconfig_power_control(ts); + ret = init_power_control(ts); + if (ret) { + TPD_INFO("%s: tp power init failed.\n", __func__); + return -1; + } + ret = reconfig_power_control(ts); + if (ret) { + TPD_INFO("%s: reconfig power failed.\n", __func__); + return -1; + } + if (!ts->ts_ops->power_control) { + ret = -EINVAL; + TPD_INFO("tp power_control NULL!\n"); + goto power_control_failed; + } + ret = ts->ts_ops->power_control(ts->chip_data, true); + if (ret) { + TPD_INFO("%s: tp power init failed.\n", __func__); + goto power_control_failed; + } + //step5 : I2C function check + if (!ts->is_noflash_ic) { + if (!i2c_check_functionality(ts->client->adapter, I2C_FUNC_I2C)) { + TPD_INFO("%s: need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err_check_functionality_failed; + } + } + + //step6 : touch input dev init + ret = init_input_device(ts); + if (ret < 0) { + ret = -EINVAL; + TPD_INFO("tp_input_init failed!\n"); + goto err_check_functionality_failed; + } + + if (ts->int_mode == UNBANNABLE) { + ret = tp_register_irq_func(ts); + if (ret < 0) { + goto free_touch_panel_input; + } + } + + //step8 : Alloc fw_name/devinfo memory space + ts->panel_data.fw_name = kzalloc(MAX_FW_NAME_LENGTH, GFP_KERNEL); + if (ts->panel_data.fw_name == NULL) { + ret = -ENOMEM; + TPD_INFO("panel_data.fw_name kzalloc error\n"); + goto free_touch_panel_input; + } + + ts->panel_data.manufacture_info.version = kzalloc(MAX_DEVICE_VERSION_LENGTH, GFP_KERNEL); + if (ts->panel_data.manufacture_info.version == NULL) { + ret = -ENOMEM; + TPD_INFO("manufacture_info.version kzalloc error\n"); + goto manu_version_alloc_err; + } + + ts->panel_data.manufacture_info.manufacture = kzalloc(MAX_DEVICE_MANU_LENGTH, GFP_KERNEL); + if (ts->panel_data.manufacture_info.manufacture == NULL) { + ret = -ENOMEM; + TPD_INFO("panel_data.fw_name kzalloc error\n"); + goto manu_info_alloc_err; + } + + pre_points= kzalloc(sizeof(struct point_info)*ts->max_num, GFP_KERNEL); + if (!pre_points) { + TPD_INFO("pre_points kzalloc failed\n"); + } + + //step8 : touchpanel vendor + tp_util_get_vendor(ts, &ts->panel_data); + if (ts->ts_ops->get_vendor) { + ts->ts_ops->get_vendor(ts->chip_data, &ts->panel_data); + } + + //step10:get chip info + if (!ts->ts_ops->get_chip_info) { + ret = -EINVAL; + TPD_INFO("tp get_chip_info NULL!\n"); + goto err_check_functionality_failed; + } + ret = ts->ts_ops->get_chip_info(ts->chip_data); + if (ret < 0) { + ret = -EINVAL; + TPD_INFO("tp get_chip_info failed!\n"); + goto err_check_functionality_failed; + } + + //step11 : touchpanel Fw check + if(!ts->is_noflash_ic) { //noflash don't have firmware before fw update + if (!ts->ts_ops->fw_check) { + ret = -EINVAL; + TPD_INFO("tp fw_check NULL!\n"); + goto manu_info_alloc_err; + } + ret = ts->ts_ops->fw_check(ts->chip_data, &ts->resolution_info, &ts->panel_data); + if (ret == FW_ABNORMAL) { + ts->force_update = 1; + TPD_INFO("This FW need to be updated!\n"); + } else if (ret == -2) { + ret = -EINVAL; + TPD_INFO("fw_check fail\n"); + goto err_check_functionality_failed; + } else { + ts->force_update = 0; + } + } + + //step12 : enable touch ic irq output ability + if (!ts->ts_ops->mode_switch) { + ret = -EINVAL; + TPD_INFO("tp mode_switch NULL!\n"); + goto manu_info_alloc_err; + } + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_NORMAL, true); + if (ret < 0) { + ret = -EINVAL; + TPD_INFO("%s:modem switch failed!\n", __func__); + goto manu_info_alloc_err; + } + + ts->source = wakeup_source_register(ts->dev, "tp_syna"); + //step13 : irq request setting + if (ts->int_mode == BANNABLE) { + ret = tp_register_irq_func(ts); + if (ret < 0) { + goto manu_info_alloc_err; + } + } + //step14 : suspend && resume fuction register + + //#if defined(CONFIG_DRM_MSM) + ts->fb_notif.notifier_call = tfb_notifier_callback; + //ret = msm_drm_register_client(&ts->fb_notif); + if (lcd_active_panel) { + ret = drm_panel_notifier_register(lcd_active_panel, &ts->fb_notif); + if (ret) { + TPD_INFO("Unable to register fb_notifier: %d\n", ret); + } + } + ts->reverse_charge_notif.notifier_call = reverse_charge_notifier_callback; + #ifndef CONFIG_TOUCHPANEL_GOODIX_GT9886 + ret = register_reverse_charge_notifier(&ts->reverse_charge_notif);/*commented to make compilation successful for Android_R */ + if (ret) + TPD_INFO("unable to register severse_charge_notifier:%d\n", ret); + #endif + ts->tp_delta_print_notif.notifier_call = tp_delta_print_notifier_callback; + #ifndef CONFIG_TOUCHPANEL_GOODIX_GT9886 + ret = register_tp_delta_print_notifier(&ts->tp_delta_print_notif);/*commented to make compilation successful for Android_R */ + if (ret) + TPD_INFO("unable to register tp_delta_print_notifier:%d\n", ret); + #endif + //step15 : workqueue create(speedup_resume) + ts->speedup_resume_wq = create_singlethread_workqueue("speedup_resume_wq"); + if (!ts->speedup_resume_wq) { + ret = -ENOMEM; + goto threaded_irq_free; + } + + INIT_WORK(&ts->speed_up_work, speedup_resume); + INIT_WORK(&ts->fw_update_work, tp_fw_update_work); + + //step 16 : short edge shield + if (ts->edge_limit_support) { + ts->limit_enable = 1; + ts->limit_edge = ts->limit_enable & 1; + ts->limit_corner = 0; + ts->edge_limit.limit_area = 1; + ts->edge_limit.in_which_area = AREA_NOTOUCH; + + ts->edge_limit.left_x1 = (ts->edge_limit.limit_area * 1000)/100; + ts->edge_limit.right_x1 = ts->resolution_info.LCD_WIDTH - ts->edge_limit.left_x1; + ts->edge_limit.left_x2 = 2 * ts->edge_limit.left_x1; + ts->edge_limit.right_x2 = ts->resolution_info.LCD_WIDTH - (2 * ts->edge_limit.left_x1); + ts->edge_limit.left_x3 = 5 * ts->edge_limit.left_x1; + ts->edge_limit.right_x3 = ts->resolution_info.LCD_WIDTH - (5 * ts->edge_limit.left_x1); + + ts->edge_limit.left_y1 = (ts->edge_limit.limit_area * 1000)/100; + ts->edge_limit.right_y1 = ts->resolution_info.LCD_HEIGHT - ts->edge_limit.left_y1; + ts->edge_limit.left_y2 = 2 * ts->edge_limit.left_y1; + ts->edge_limit.right_y2 = ts->resolution_info.LCD_HEIGHT - (2 * ts->edge_limit.left_y1); + ts->edge_limit.left_y3 = 5 * ts->edge_limit.left_y1; + ts->edge_limit.right_y3 = ts->resolution_info.LCD_HEIGHT - (5 * ts->edge_limit.left_y1); + } + + //step 17:esd recover support + if (ts->esd_handle_support) { + ts->esd_info.esd_workqueue = create_singlethread_workqueue("esd_workthread"); + INIT_DELAYED_WORK(&ts->esd_info.esd_check_work, esd_handle_func); + + mutex_init(&ts->esd_info.esd_lock); + + ts->esd_info.esd_running_flag = 0; + ts->esd_info.esd_work_time = 2 * HZ; // HZ: clock ticks in 1 second generated by system + TPD_INFO("Clock ticks for an esd cycle: %d\n", ts->esd_info.esd_work_time); + + esd_handle_switch(&ts->esd_info, true); + } + + //step 18:spurious_fingerprint support + if (ts->spurious_fp_support) { + ts->spuri_fp_touch.thread = kthread_run(finger_protect_handler, ts, "touchpanel_fp"); + if (IS_ERR(ts->spuri_fp_touch.thread)) { + TPD_INFO("spurious fingerprint thread create failed\n"); + } + } + + //step 19: charge pump support + if (ts->charger_pump_support) { + if (ts->ts_ops->get_usb_state) { + ts->is_usb_checked = !!ts->ts_ops->get_usb_state(); + } else { + ts->is_usb_checked = 0; + } + TPD_INFO("curent usb state is %d\n", ts->is_usb_checked); + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_CHARGE, ts->is_usb_checked); + if (ret < 0) { + TPD_INFO("switch charge mode failed\n"); + } + } + + // step 20: ear sense support + if (ts->ear_sense_support) { + mutex_init(&ts->mutex_earsense); // init earsense operate mutex + + //malloc space for storing earsense delta + ts->earsense_delta = kzalloc(2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM, GFP_KERNEL); + if (ts->earsense_delta == NULL) { + ret = -ENOMEM; + TPD_INFO("earsense_delta kzalloc error\n"); + goto threaded_irq_free; + } + + //create work queue for read earsense delta + ts->delta_read_wq = create_singlethread_workqueue("touch_delta_wq"); + if (!ts->delta_read_wq) { + ret = -ENOMEM; + goto earsense_alloc_free; + } + INIT_WORK(&ts->read_delta_work, touch_read_delta); + } + + //step 21 : createproc proc files interface + init_touchpanel_proc(ts); + + //step 22 : Other**** + ts->i2c_ready = true; + ts->loading_fw = false; + ts->is_suspended = 0; + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + ts->gesture_enable = 0; + ts->es_enable = 0; + ts->fd_enable = 0; + ts->palm_enable = 1; + ts->touch_count = 0; + ts->glove_enable = 0; + ts->view_area_touched = 0; + ts->tp_suspend_order = LCD_TP_SUSPEND; + ts->tp_resume_order = TP_LCD_RESUME; + ts->skip_suspend_operate = false; + ts->skip_reset_in_resume = false; + ts->skip_enable_touchhold = false; + ts->reverse_charge_status = false; + ts->irq_slot = 0; + ts->touch_hold_enable = 0; + ts->lcd_refresh_rate = 0; + ts->reject_point = 0; + ts->charge_detect = 0; + ts->firmware_update_type = 0; + ts->corner_delay_up = -1; + ts->game_mode_status = 0; + if (project_code == 20801) { + ts->monitor_data.eli_size = 10; + ts->monitor_data.eli_ver_range = 300; + ts->monitor_data.eli_hor_range = 300; + } + ts->wet_mode_status = 0; + if (ts->project_info == 1) {//project 19811 + ts->dead_zone_l = 25; + ts->dead_zone_p = 25; + } else { + ts->dead_zone_l = 20; + ts->dead_zone_p = 20; + } + if (ts->int_mode == UNBANNABLE) { + ts->dead_zone_l = 10; + ts->dead_zone_p = 10; + ts->corner_dead_zone_xl = 0x88; + ts->corner_dead_zone_yl = 0x44; + ts->corner_dead_zone_xp = 0x24; + ts->corner_dead_zone_yp = 0xF5; + } + if(ts->is_noflash_ic) { + ts->irq = ts->s_client->irq; + } else { + ts->irq = ts->client->irq; + } + tp_register_times++; + g_tp = ts; + complete(&ts->pm_complete); + TPD_INFO("Touch panel probe : normal end\n"); + return 0; + +earsense_alloc_free: + kfree(ts->earsense_delta); + +threaded_irq_free: + free_irq(ts->irq, ts); + +manu_info_alloc_err: + kfree(ts->panel_data.manufacture_info.version); + +manu_version_alloc_err: + kfree(ts->panel_data.fw_name); + +free_touch_panel_input: + input_unregister_device(ts->input_dev); + input_unregister_device(ts->kpd_input_dev); + input_unregister_device(ps_input_dev); + + +err_check_functionality_failed: + if (ts->int_mode == UNBANNABLE) { + free_irq(ts->irq, ts); + } + //ts->ts_ops->power_control(ts->chip_data, false); + +power_control_failed: + + if (!IS_ERR_OR_NULL(ts->hw_res.vdd_2v8)) { + regulator_disable(ts->hw_res.vdd_2v8); + regulator_put(ts->hw_res.vdd_2v8); + ts->hw_res.vdd_2v8 = NULL; + } + + if (!IS_ERR_OR_NULL(ts->hw_res.vcc_1v8)) { + regulator_disable(ts->hw_res.vcc_1v8); + regulator_put(ts->hw_res.vcc_1v8); + ts->hw_res.vcc_1v8 = NULL; + } + + if (gpio_is_valid(ts->hw_res.enable2v8_gpio)) + gpio_free(ts->hw_res.enable2v8_gpio); + + if (gpio_is_valid(ts->hw_res.enable1v8_gpio)) + gpio_free(ts->hw_res.enable1v8_gpio); + + if (gpio_is_valid(ts->hw_res.irq_gpio)) { + gpio_free(ts->hw_res.irq_gpio); + } + + if (gpio_is_valid(ts->hw_res.reset_gpio)) { + gpio_free(ts->hw_res.reset_gpio); + } + + if (gpio_is_valid(ts->hw_res.id1_gpio)) { + gpio_free(ts->hw_res.id1_gpio); + } + + if (gpio_is_valid(ts->hw_res.id2_gpio)) { + gpio_free(ts->hw_res.id2_gpio); + } + + if (gpio_is_valid(ts->hw_res.id3_gpio)) { + gpio_free(ts->hw_res.id3_gpio); + } + msleep(200); + sec_ts_pinctrl_configure(&ts->hw_res, false); + + return ret; +} + +/** + * touchpanel_ts_suspend - touchpanel suspend function + * @dev: i2c_client->dev using to get touchpanel_data resource + * + * suspend function bind to LCD on/off status + * Returning zero(sucess) or negative errno(failed) + */ +static int tp_suspend(struct device *dev) +{ + int ret; + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s: start.\n", __func__); + + TPD_INFO("tp_suspend ts->spuri_fp_touch.fp_trigger =%d ts->i2c_ready =%d ts->spuri_fp_touch.lcd_resume_success=%d \n", + ts->spuri_fp_touch.fp_trigger , ts->i2c_ready , ts->spuri_fp_touch.lcd_resume_ok); + ts->spuri_fp_touch.lcd_resume_ok = false; + //step1:detect whether we need to do suspend + if (ts->input_dev == NULL) { + TPD_INFO("input_dev registration is not complete\n"); + goto NO_NEED_SUSPEND; + } + if (ts->loading_fw) { + TPD_INFO("FW is updating while suspending"); + goto NO_NEED_SUSPEND; + } + +#ifndef TPD_USE_EINT + hrtimer_cancel(&ts->timer); +#endif + + /* release all complete first */ + if (ts->ts_ops->reinit_device) { + ts->ts_ops->reinit_device(ts->chip_data); + } + + //step2:get mutex && start process suspend flow + mutex_lock(&ts->mutex); + if (!ts->is_suspended) { + ts->is_suspended = 1; + ts->suspend_state = TP_SUSPEND_COMPLETE; + } else { + TPD_INFO("%s: do not suspend twice.\n", __func__); + goto EXIT; + } + + //step3:Release key && touch event before suspend + tp_btnkey_release(ts); + tp_touch_release(ts); + + //step4:cancel esd test + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + //step5:ear sense support + if (ts->ear_sense_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, false); + } + if (ts->face_detect_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, false); + } + + //step6:gesture mode status process + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + if (ts->int_mode == UNBANNABLE) { //workaroud for config fail when suspend for 19805 + msleep(20); + } + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_HOLD, false);//suspend, close touchhold function. + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, true); + goto EXIT; + } + } + + //step7:skip suspend operate only when gesture_enable is 0 + if (ts->skip_suspend_operate && (!ts->gesture_enable)) { + goto EXIT; + } + + //step8:switch mode to sleep + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + + sec_ts_pinctrl_configure(&ts->hw_res, false); + + +EXIT: + TPD_INFO("%s: end.\n", __func__); + mutex_unlock(&ts->mutex); + +NO_NEED_SUSPEND: + complete(&ts->pm_complete); + + return 0; +} + +/** + * touchpanel_ts_suspend - touchpanel resume function + * @dev: i2c_client->dev using to get touchpanel_data resource + * + * resume function bind to LCD on/off status, this fuction start thread to speedup screen on flow. + * Do not care the result: Return void type + */ +static void tp_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s start.\n", __func__); + + if (!ts->is_suspended) { + TPD_INFO("%s: do not resume twice.\n", __func__); + goto NO_NEED_RESUME; + } + ts->is_suspended = 0; + ts->suspend_state = TP_RESUME_COMPLETE; + if (ts->loading_fw) + goto NO_NEED_RESUME; + + //free irq at first + free_irq(ts->irq, ts); + + if (ts->ts_ops->reinit_device) { + ts->ts_ops->reinit_device(ts->chip_data); + } + if(ts->ts_ops->resume_prepare) { + mutex_lock(&ts->mutex); + ts->ts_ops->resume_prepare(ts->chip_data); + mutex_unlock(&ts->mutex); + } + + queue_work(ts->speedup_resume_wq, &ts->speed_up_work); + return; + +NO_NEED_RESUME: + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + complete(&ts->pm_complete); +} + +/** + * speedup_resume - speedup resume thread process + * @work: work struct using for this thread + * + * do actully resume function + * Do not care the result: Return void type + */ +static void speedup_resume(struct work_struct *work) +{ + //int timed_out = 0; + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, + speed_up_work); + struct fp_underscreen_info tp_info; + + TPD_INFO("%s is called\n", __func__); + + //step1: get mutex for locking i2c acess flow + mutex_lock(&ts->mutex); + + //step2:before Resume clear All of touch/key event Reset some flag to default satus + if (ts->edge_limit_support) + ts->edge_limit.in_which_area = AREA_NOTOUCH; + tp_btnkey_release(ts); + tp_touch_release(ts); + + if (ts->int_mode == UNBANNABLE) { + ts->ts_ops->power_control(ts->chip_data, 1); + TPD_INFO("before irq register, power on\n"); + //msleep(20); + tp_register_irq_func(ts); + //ts->ts_ops->reset(ts->chip_data); + } + + //if (ts->use_resume_notify && (!ts->fp_info.touch_state)) { + // reinit_completion(&ts->resume_complete); + //} + //step3:Reset IC && switch work mode, ft8006 is reset by lcd, no more reset needed + if (!ts->skip_reset_in_resume) { + //if (ts->int_mode != UNBANNABLE) { + ts->ts_ops->reset(ts->chip_data); + //} + if (ts->gesture_enable) {//double tap wakeup,click touchhold area quickly before ending resume flow, + if (g_tp->touchold_event) { + if (project_code == 20801) { + TPD_INFO("touchhold up\n"); + g_tp->touchold_event = 0; + gf_opticalfp_irq_handler(0);//(FP G3 sensor)do reset will lost touchhold up event, which will lead fingerptint highlight + }else { + g_tp->touchold_event = 0; + tp_info.x = 0; + tp_info.y = 0; + tp_info.touch_state = 0; + TPD_INFO("%s: tp_info.x = %d, tp_info.y= %d\n",__func__, tp_info.x, tp_info.y); + opticalfp_irq_handler(&tp_info);//do reset will lost touchhold up event,which will lead fingerptint highlight + } + } + } + } + ts->skip_reset_in_resume = false; + if (!ts->gesture_enable) { + sec_ts_pinctrl_configure(&ts->hw_res, true); + } + + //step4:If use resume notify, exit wait first + //if (ts->use_resume_notify && (!ts->fp_info.touch_state)) { + //reinit_completion(&ts->resume_complete); + // timed_out = 0; //wait_for_completion_timeout(&ts->resume_complete, 1*HZ); //wait resume over for 1s + // if ((0 == timed_out) || (ts->resume_complete.done)) { + // TPD_INFO("resume state, timed_out:%d, done:%d\n", timed_out, ts->resume_complete.done); + // } + //} + + if (ts->ts_ops->specific_resume_operate) { + ts->ts_ops->specific_resume_operate(ts->chip_data); + } + + //step5: set default ps status to far + if (ts->ts_ops->write_ps_status) { + ts->ts_ops->write_ps_status(ts->chip_data, 0); + } + + operate_mode_switch(ts); + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, true); + } + + //step6:Request irq again + if (ts->int_mode == BANNABLE) { + tp_register_irq_func(ts); + } + + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + + //step7:Unlock && exit + TPD_INFO("%s: end!\n", __func__); + mutex_unlock(&ts->mutex); + complete(&ts->pm_complete); +} + +//#if defined(CONFIG_FB) || defined(CONFIG_DRM_MSM) +static int tfb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + int *blank; + int timed_out = -1; + //struct fb_event *evdata = data; + struct drm_panel_notifier *evdata = data; + struct touchpanel_data *ts = container_of(self, struct touchpanel_data, fb_notif); + + //to aviod some kernel bug (at fbmem.c some local veriable are not initialized) + + if(event != DRM_PANEL_EARLY_EVENT_BLANK && event != DRM_PANEL_EVENT_BLANK) + return 0; + + if (evdata && evdata->data && ts && ts->chip_data) { + blank = evdata->data; + TPD_INFO("%s: event = %ld, blank = %d\n", __func__, event, *blank); + if (*blank == DRM_PANEL_BLANK_POWERDOWN_CUST) { //suspend + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { //early event + + timed_out = wait_for_completion_timeout(&ts->pm_complete, 0.5*HZ); //wait resume over for 0.5s + if ((0 == timed_out) || (ts->pm_complete.done)) { + TPD_INFO("completion state, timed_out:%d, done:%d\n", timed_out, ts->pm_complete.done); + } + + ts->suspend_state = TP_SUSPEND_EARLY_EVENT; //set suspend_resume_state + if (ts->esd_handle_support && ts->is_incell_panel && (ts->tp_suspend_order == LCD_TP_SUSPEND)) { + esd_handle_switch(&ts->esd_info, false); //incell panel need cancel esd early + } + + if (ts->tp_suspend_order == TP_LCD_SUSPEND) { + tp_suspend(ts->dev); + } else if (ts->tp_suspend_order == LCD_TP_SUSPEND) { + if (!ts->gesture_enable) { + TPD_INFO("disable tp isr 111, tp irq %d\n", ts->irq); + disable_irq_nosync(ts->irq); //avoid iic error + } + tp_suspend(ts->dev); + if (!ts->gesture_enable) { + if (ts->int_mode == UNBANNABLE) + ts->ts_ops->power_control(ts->chip_data, 0); + } + } + } else if (event == DRM_PANEL_EVENT_BLANK) { //event + + if (ts->tp_suspend_order == TP_LCD_SUSPEND) { + + } else if (ts->tp_suspend_order == LCD_TP_SUSPEND) { + tp_suspend(ts->dev); + } + } + } else if (*blank == DRM_PANEL_BLANK_UNBLANK_CUST) {//resume + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { //early event + + timed_out = wait_for_completion_timeout(&ts->pm_complete, 0.5*HZ); //wait suspend over for 0.5s + if ((0 == timed_out) || (ts->pm_complete.done)) { + TPD_INFO("completion state, timed_out:%d, done:%d\n", timed_out, ts->pm_complete.done); + } + + ts->suspend_state = TP_RESUME_EARLY_EVENT; //set suspend_resume_state + + if (ts->tp_resume_order == TP_LCD_RESUME) { + TPD_INFO("TP_LCD_RESUME\n"); + tp_resume(ts->dev); + } else if (ts->tp_resume_order == LCD_TP_RESUME) { + TPD_INFO("disable tp isr 112, tp irq %d\n", ts->irq); + disable_irq_nosync(ts->irq); + } + } else if (event == DRM_PANEL_EVENT_BLANK) { //event + + if (ts->tp_resume_order == TP_LCD_RESUME) { + + } else if (ts->tp_resume_order == LCD_TP_RESUME) { + tp_resume(ts->dev); + TPD_INFO("enable tp isr 113, tp irq %d\n", ts->irq); + enable_irq(ts->irq); + } + } + }else if (*blank == DRM_PANEL_DYNAMICFPS_60 && ts->lcd_refresh_rate_switch && ts->game_mode_status == 0) { //60-90HZ LCD refresh switch + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { + mutex_lock(&ts->mutex); + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_REFRESH_SWITCH, 0); + } + mutex_unlock(&ts->mutex); + } + } else if (*blank == DRM_PANEL_DYNAMICFPS_90 && ts->game_mode_status == 0) { + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { + mutex_lock(&ts->mutex); + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_REFRESH_SWITCH, 1); + } + mutex_unlock(&ts->mutex); + } + } else if (*blank == 120) { + if (event == DRM_PANEL_EARLY_EVENT_BLANK && ts->game_mode_status == 0) { + mutex_lock(&ts->mutex); + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_REFRESH_SWITCH, 1); + } + mutex_unlock(&ts->mutex); + } + } + } + + return 0; +} +//#endif + +static int reverse_charge_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + struct touchpanel_data *ts = container_of(self, struct touchpanel_data, reverse_charge_notif); + + if (ts == NULL) { + TPD_INFO("tp chip is null , return\n"); + return -EINVAL; + } + + TPD_INFO("%s event is %d\n", __func__, event); + if (event == 1) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_REVERSE_WIRELESS_CHARGE, 1); + g_tp->reverse_charge_status = true; + mutex_unlock(&ts->mutex); + } else if (event == 0) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_REVERSE_WIRELESS_CHARGE, 0); + g_tp->reverse_charge_status = false; + mutex_unlock(&ts->mutex); + } + + return 0; +} + +static int tp_delta_print_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + struct touchpanel_data *ts = container_of(self, struct touchpanel_data, tp_delta_print_notif); + + if (ts == NULL) { + TPD_INFO("tp chip is null , return\n"); + return -EINVAL; + } + + TPD_INFO("%s event is %d\n", __func__, event); + + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_TP_DELTA_PRINT, 1); + mutex_unlock(&ts->mutex); + + return 0; +} + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +void tp_i2c_suspend(struct touchpanel_data *ts) +{ + ts->i2c_ready = false; + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*enable gpio wake system through interrupt*/ + enable_irq_wake(ts->irq); + return; + } + } + disable_irq_nosync(ts->irq); +} + +void tp_i2c_resume(struct touchpanel_data *ts) +{ + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*disable gpio wake system through intterrupt*/ + disable_irq_wake(ts->irq); + goto OUT; + } + } + enable_irq(ts->irq); + +OUT: + ts->i2c_ready = true; + if (ts->spurious_fp_support && ts->spuri_fp_touch.fp_trigger) { + wake_up_interruptible(&waiter); + } +} + +#else +void tp_i2c_suspend(struct touchpanel_data *ts) +{ + ts->i2c_ready = false; + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*enable gpio wake system through interrupt*/ + enable_irq_wake(ts->irq); + return; + } + } + disable_irq_nosync(ts->irq); +} + +void tp_i2c_resume(struct touchpanel_data *ts) +{ + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*disable gpio wake system through intterrupt*/ + disable_irq_wake(ts->irq); + goto OUT; + } + } + enable_irq(ts->irq); +OUT: + ts->i2c_ready = true; + if (ts->spurious_fp_support && ts->spuri_fp_touch.fp_trigger) { + wake_up_interruptible(&waiter); + } +} +#endif + +struct touchpanel_data *common_touch_data_alloc(void) +{ + if (g_tp) { + TPD_INFO("%s:common panel struct has alloc already!\n", __func__); + return NULL; + } + return kzalloc(sizeof(struct touchpanel_data), GFP_KERNEL); +} + +int common_touch_data_free(struct touchpanel_data *pdata) +{ + if (pdata) { + kfree(pdata); + } + + g_tp = NULL; + return 0; +} + +/** + * input_report_key_reduce - Using for report virtual key + * @work: work struct using for this thread + * + * before report virtual key, detect whether touch_area has been touched + * Do not care the result: Return void type + */ +void input_report_key_reduce(struct input_dev *dev, unsigned int code, int value) +{ + if (value) {//report Key[down] + if (g_tp) { + if (g_tp->view_area_touched == 0) { + input_report_key(dev, code, value); + } + else + TPD_INFO("Sorry,tp is touch down,can not report touch key\n"); + } + } else { + input_report_key(dev, code, value); + } +} + +void clear_view_touchdown_flag(void) +{ + if (g_tp) { + g_tp->view_area_touched = 0; + } +} + diff --git a/drivers/oneplus/input/touchscreen/tp_devices.h b/drivers/oneplus/input/touchscreen/tp_devices.h new file mode 100755 index 0000000000000000000000000000000000000000..b618978aff94a054b0e24a0d0876fa8dcc5a2abe --- /dev/null +++ b/drivers/oneplus/input/touchscreen/tp_devices.h @@ -0,0 +1,38 @@ + /*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : tp_devices.h + * + * Function : touchpanel public interface + * + * Version : V1.0 + * + ***********************************************************/ +#ifndef TP_DEVICES_H +#define TP_DEVICES_H +//device list define +typedef enum tp_dev{ + TP_OFILM, + TP_BIEL, + TP_TRULY, + TP_BOE, + TP_G2Y, + TP_TPK, + TP_JDI, + TP_SAMSUNG, + TP_DSJM, + TP_BOE_B8, + TP_INNOLUX, + TP_HIMAX_DPT, + TP_AUO, + TP_DEPUTE, + TP_UNKNOWN, +}tp_dev; + +struct tp_dev_name { + tp_dev type; + char name[32]; +}; + +#endif + diff --git a/drivers/oneplus/input/touchscreen/util_interface/Kconfig b/drivers/oneplus/input/touchscreen/util_interface/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..ce1219f11d20db601f4b85b518f1512778ca4096 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/util_interface/Kconfig @@ -0,0 +1,8 @@ + +config TOUCHPANEL_ONEPLUS + default y + bool "TP Synaptics " + ---help--- + say Y to enable driver for Touchpanel useing Synaptics_IC + + diff --git a/drivers/oneplus/input/touchscreen/util_interface/Makefile b/drivers/oneplus/input/touchscreen/util_interface/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..19be4449b129b23b72d11065677897e08cb82f26 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/util_interface/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the touchscreen drivers. +# + +obj-$(CONFIG_TOUCHPANEL_ONEPLUS) += touch_interfaces.o + diff --git a/drivers/oneplus/input/touchscreen/util_interface/touch_interfaces.c b/drivers/oneplus/input/touchscreen/util_interface/touch_interfaces.c new file mode 100755 index 0000000000000000000000000000000000000000..fe3479193d51e75edfc870b32ae27e7d04e25539 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/util_interface/touch_interfaces.c @@ -0,0 +1,568 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "touch_interfaces.h" + +#define TPD_DEVICE "touch_interface" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define FIX_I2C_LENGTH 256 +static bool register_is_16bit = 0; + +/** + * touch_i2c_continue_read - Using for "read sequence bytes" through IIC + * @client: Handle to slave device + * @length: data size we want to read + * @data: data read from IIC + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_continue_read(struct i2c_client* client, unsigned short length, unsigned char *data) +{ + int retval; + unsigned char retry; + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = data; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + dev_err(&client->dev, "%s: I2C read over retry limit\n", __func__); + retval = -EIO; + } + return retval; + +} + +/** + * touch_i2c_read_block - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @length: data size we want to send + * @data: data we want to send + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_read_block(struct i2c_client* client, u16 addr, unsigned short length, unsigned char *data) +{ + int retval; + unsigned char retry; + static unsigned char *buffer = NULL; + static unsigned int read_buf_size = 0; + static unsigned char *read_buf = NULL; + struct i2c_msg msg[2]; + + buffer = kzalloc(2, GFP_KERNEL | GFP_DMA); + if (length > FIX_I2C_LENGTH) { + if (read_buf_size < length) { + if (read_buf) { + kfree(read_buf); + TPD_INFO("read block_1,free onec\n"); + } + read_buf =kzalloc(length, GFP_KERNEL); + if(!read_buf) { + read_buf_size = 0; + TPD_INFO("read block kzaloc faied\n"); + return -ENOMEM; + } + read_buf_size = length; + } else { + memset(read_buf, 0 ,length); + } + } else { + if (read_buf_size > FIX_I2C_LENGTH) { + kfree(read_buf); + read_buf = kzalloc(FIX_I2C_LENGTH, + GFP_KERNEL | GFP_DMA); + if(!read_buf) { + read_buf_size = 0; + TPD_INFO("read block kzaloc faied\n"); + return -ENOMEM; + } + read_buf_size = FIX_I2C_LENGTH; + } else { + if(!read_buf) { + read_buf = kzalloc(FIX_I2C_LENGTH, + GFP_KERNEL | GFP_DMA); + if (!read_buf) { + read_buf_size = 0; + TPD_INFO("read block kzaloc faied\n"); + return -ENOMEM; + } + read_buf_size = FIX_I2C_LENGTH; + } else { + memset(read_buf, 0, length); + } + } + } + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].buf = buffer; + + if (!register_is_16bit) { // if register is 8bit + msg[0].len = 1; + msg[0].buf[0] = addr & 0xff; + } else { + msg[0].len = 2; + msg[0].buf[0] = addr >> 8 & 0xff; + msg[0].buf[1] = addr & 0xff; + } + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = read_buf; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + dev_err(&client->dev, "%s: I2C read over retry limit\n", __func__); + retval = -EIO; + } + memcpy(data, read_buf,length); + kfree(buffer); + return retval; +} + +/** + * touch_i2c_continue_write - Using for "write sequence bytes" through IIC + * @client: Handle to slave device + * @length: data size we want to write + * @data: data write to IIC + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_continue_write(struct i2c_client* client, unsigned short length, unsigned char *data) +{ + int retval; + unsigned char retry; + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = 0; + msg.buf = data; + msg.len = length; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + dev_err(&client->dev, "%s: I2C write over retry limit\n", __func__); + retval = -EIO; + } + return retval; +} + +/** + * touch_i2c_write_block - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @length: data size we want to send + * @data: data we want to send + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_write_block(struct i2c_client* client, u16 addr, unsigned short length, unsigned char const *data) +{ + int retval; + unsigned char retry; + //unsigned char buffer[length + 2]; + unsigned char *buffer; + struct i2c_msg msg[1]; + buffer = (unsigned char *)kzalloc(length + 2,GFP_KERNEL); + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].buf = buffer; + + if (!register_is_16bit) // if register is 8bit + { + msg[0].len = length + 1; + msg[0].buf[0] = addr & 0xff; + + memcpy(&buffer[1], &data[0], length); + } + else + { + msg[0].len = length + 2; + msg[0].buf[0] = (addr >> 8) & 0xff; + msg[0].buf[1] = addr & 0xff; + + memcpy(&buffer[2], &data[0], length); + } + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + dev_err(&client->dev, "%s: I2C write over retry limit\n", __func__); + retval = -EIO; + } + kfree(buffer); + return retval; +} + +/** + * touch_i2c_read_byte - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to read + * + * Actully, This function call touch_i2c_read_block for IIC transfer, + * Returning zero(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_read_byte(struct i2c_client* client, unsigned short addr) +{ + int retval = 0; + unsigned char buf[2] = {0}; + + if (!client) { + dump_stack(); + return -1; + } + retval = touch_i2c_read_block(client, addr, 1, buf); + if (retval >= 0) + retval = buf[0] & 0xff; + + return retval; +} + + +/** + * touch_i2c_write_byte - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @data: data we want to send + * + * Actully, This function call touch_i2c_write_block for IIC transfer, + * Returning zero(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_write_byte(struct i2c_client* client, unsigned short addr, unsigned char data) +{ + int retval; + int length_trans = 1; + unsigned char data_send = data; + + if (!client) { + dump_stack(); + return -EINVAL; + } + retval = touch_i2c_write_block(client, addr, length_trans, &data_send); + if (retval == length_trans) + retval = 0; + + return retval; +} + +/** + * touch_i2c_read_word - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @data: data we want to read + * + * Actully, This func call touch_i2c_Read_block for IIC transfer, + * Returning negative errno else a 16-bit unsigned "word" received from the device. + */ +int touch_i2c_read_word(struct i2c_client* client, unsigned short addr) +{ + int retval; + unsigned char buf[2] = {0}; + + if (!client) { + dump_stack(); + return -EINVAL; + } + retval = touch_i2c_read_block(client, addr, 2, buf); + if (retval >= 0) + retval = buf[1] << 8 | buf[0]; + + return retval; +} + +/** + * touch_i2c_write_word - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @data: data we want to send + * + * Actully, This function call touch_i2c_write_block for IIC transfer, + * Returning zero(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_write_word(struct i2c_client* client, unsigned short addr, unsigned short data) +{ + int retval; + int length_trans = 2; + unsigned char buf[2] = {data & 0xff, (data >> 8) & 0xff}; + + if (!client) { + dump_stack(); + return -EINVAL; + } + + retval = touch_i2c_write_block(client, addr, length_trans, buf); + if (retval == length_trans) + retval = 0; + + return retval; +} + +/** + * touch_i2c_read - Using for "read data from ic after writing or not" through IIC + * @client: Handle to slave device + * @writebuf: buf to write + * @writelen: data size we want to send + * @readbuf: buf we want save data + * @readlen: data size we want to receive + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer msg length(transfer success) or most likely negative errno(transfer EIO error) + */ +int touch_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen) +{ + int retval = 0; + int retry = 0; + + if (client == NULL) { + TPD_INFO("%s: i2c_client == NULL!\n", __func__); + return -1; + } + + if (readlen > 0) { + if (writelen > 0) { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msgs, 2) == 2) { + retval = 2; + break; + } + msleep(20); + } + } else { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msgs, 1) == 1) { + retval = 1; + break; + } + msleep(20); + } + } + + if (retry == MAX_I2C_RETRY_TIME) { + TPD_INFO("%s: i2c_transfer(read) over retry limit\n", __func__); + retval = -EIO; + } + } + + return retval; +} + +/** + * touch_i2c_write - Using for "write data to ic" through IIC + * @client: Handle to slave device + * @writebuf: buf data wo want to send + * @writelen: data size we want to send + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer msg length(transfer success) or most likely negative errno(transfer EIO error) + */ +int touch_i2c_write(struct i2c_client *client, char *writebuf, int writelen) +{ + int retval = 0; + int retry = 0; + + if (client == NULL) { + TPD_INFO("%s: i2c_client == NULL!", __func__); + return -1; + } + + if (writelen > 0) { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msgs, 1) == 1) { + retval = 1; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + TPD_INFO("%s: i2c_transfer(write) over retry limit\n", __func__); + retval = -EIO; + } + } + + return retval; +} + + +/** + * init_touch_interfaces - Using for Register IIC interface + * @dev: i2c_client->dev using to alloc memory for dma transfer + * @flag_register_16bit: bool param to detect whether this device using 16bit IIC address or 8bit address + * + * Actully, This function don't have many operation, we just detect device address length && alloc DMA memory for MTK platform + * Returning zero(sucess) or -ENOMEM(memory alloc failed) + */ +int init_touch_interfaces(struct device *dev, bool flag_register_16bit) +{ + register_is_16bit = flag_register_16bit; + + return 0; +} + +/******************************************************* +Description: + Novatek touchscreen spi read/write core function. + +return: + Executive outcomes. 0---succeed. +*******************************************************/ +int32_t spi_read_write(struct spi_device *client, uint8_t *buf, size_t len , uint8_t *rbuf, SPI_RW rw) +{ + struct spi_message m; + struct spi_transfer t = { + .len = len, + }; + + switch (rw) { + case SPIREAD: + t.tx_buf = &buf[0]; + t.rx_buf = rbuf; + t.len = (len + DUMMY_BYTES); + break; + + case SPIWRITE: + t.tx_buf = buf; + break; + } + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + return spi_sync(client, &m); +} + +/******************************************************* +Description: + Novatek touchscreen spi read function. + +return: + Executive outcomes. 2---succeed. -5---I/O error +*******************************************************/ +int32_t CTP_SPI_READ(struct spi_device *client, uint8_t *buf, uint16_t len) +{ + int32_t ret = -1; + int32_t retries = 0; + uint8_t rbuf[SPI_TANSFER_LEN+1] = {0}; + + buf[0] = SPI_READ_MASK(buf[0]); + + while (retries < 5) { + ret = spi_read_write(client, buf, len, rbuf, SPIREAD); + if (ret == 0) break; + retries++; + } + + if (unlikely(retries == 5)) { + TPD_INFO("read error, ret=%d\n", ret); + ret = -EIO; + } else { + memcpy((buf+1), (rbuf+2), (len-1)); + } + + return ret; +} + +/******************************************************* +Description: + Novatek touchscreen spi write function. + +return: + Executive outcomes. 1---succeed. -5---I/O error +*******************************************************/ +int32_t CTP_SPI_WRITE(struct spi_device *client, uint8_t *buf, uint16_t len) +{ + int32_t ret = -1; + int32_t retries = 0; + + buf[0] = SPI_WRITE_MASK(buf[0]); + + while (retries < 5) { + ret = spi_read_write(client, buf, len, NULL, SPIWRITE); + if (ret == 0) break; + retries++; + } + + if (unlikely(retries == 5)) { + TPD_INFO("error, ret=%d\n", ret); + ret = -EIO; + } + + return ret; +} + diff --git a/drivers/oneplus/input/touchscreen/util_interface/touch_interfaces.h b/drivers/oneplus/input/touchscreen/util_interface/touch_interfaces.h new file mode 100755 index 0000000000000000000000000000000000000000..0e00c08923fb1bf63a4b13db1c7016f5bb6c3050 --- /dev/null +++ b/drivers/oneplus/input/touchscreen/util_interface/touch_interfaces.h @@ -0,0 +1,49 @@ +/*********************************************************** +* Description : OnePlus touchpanel driver +* +* File : touch_interfaces.h +* +* Function : touchpanel public interface +* +* Version : V1.0 +* +***********************************************************/ +#include +#ifndef TOUCH_INTERFACES_H +#define TOUCH_INTERFACES_H + +#define MAX_I2C_RETRY_TIME 2 + +//---SPI READ/WRITE--- +#define SPI_WRITE_MASK(a) (a | 0x80) +#define SPI_READ_MASK(a) (a & 0x7F) +#define DUMMY_BYTES (1) +#define SPI_TANSFER_LEN 512 + +typedef enum { + SPIWRITE = 1, + SPIREAD = 2 +} SPI_RW; + +int touch_i2c_read_byte(struct i2c_client* client, u16 addr); +int touch_i2c_write_byte(struct i2c_client* client, u16 addr, unsigned char data); + +int touch_i2c_read_word(struct i2c_client* client, u16 addr); +int touch_i2c_write_word(struct i2c_client* client, u16 addr, unsigned short data); + +int touch_i2c_read_block(struct i2c_client* client, u16 addr, unsigned short length, unsigned char *data); +int touch_i2c_write_block(struct i2c_client* client, u16 addr, unsigned short length, unsigned char const *data); + +int touch_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen); +int touch_i2c_write(struct i2c_client *client, char *writebuf, int writelen); + +int init_touch_interfaces(struct device *dev, bool flag_register_16bit); +int touch_i2c_continue_read(struct i2c_client* client, unsigned short length, unsigned char *data); +int touch_i2c_continue_write(struct i2c_client* client, unsigned short length, unsigned char *data); +int32_t spi_read_write(struct spi_device *client, uint8_t *buf, size_t len, uint8_t *rbuf, SPI_RW rw); +int32_t CTP_SPI_READ(struct spi_device *client, uint8_t *buf, uint16_t len); +int32_t CTP_SPI_WRITE(struct spi_device *client, uint8_t *buf, uint16_t len); + + +#endif + diff --git a/drivers/oneplus/input/touchscreen_himax/Kconfig b/drivers/oneplus/input/touchscreen_himax/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..d9bd6a71a622becd111f8d969f9581302b9cc6ef --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/Kconfig @@ -0,0 +1,5 @@ + +source "drivers/oneplus/input/touchscreen_himax/util_interface/Kconfig" +#source "drivers/oneplus/input/touchscreen/samsung/Kconfig" +source "drivers/oneplus/input/touchscreen_himax/himax/Kconfig" +#source "drivers/oneplus/input/touchscreen/Goodix/Kconfig" diff --git a/drivers/oneplus/input/touchscreen_himax/Makefile b/drivers/oneplus/input/touchscreen_himax/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..277cd8237df3d6dd6573bc9b313ee47819d173c6 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the touchscreen drivers. +# +#obj-y += samsung/ +obj-y += util_interface/ +obj-y += touchpanel_common_driver_himax.o +obj-y += update_tpfw_notifier.o +obj-y += himax/ +#obj-y += synaptics/ diff --git a/drivers/oneplus/input/touchscreen_himax/himax/Kconfig b/drivers/oneplus/input/touchscreen_himax/himax/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..fb9301144411620eef3f5d167ec2a698e6dc01a1 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/Kconfig @@ -0,0 +1,2 @@ +source "drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Kconfig" + diff --git a/drivers/oneplus/input/touchscreen_himax/himax/Makefile b/drivers/oneplus/input/touchscreen_himax/himax/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2bbcba9faf29c9511584ec6de0cab96d563ffab3 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. +obj-y += himax_common.o +obj-y += hx83112f_noflash/ + + +#endif diff --git a/drivers/oneplus/input/touchscreen_himax/himax/himax_common.c b/drivers/oneplus/input/touchscreen_himax/himax/himax_common.c new file mode 100644 index 0000000000000000000000000000000000000000..be6b6f77b42c7d950ac3e31b0aadcb88851473c3 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/himax_common.c @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 "../touchpanel_common_himax.h" +#include "himax_common.h" + +/*******Part0:LOG TAG Declear********************/ + +#define TPD_DEVICE "himax_common" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do {\ + if (tp_debug == LEVEL_DEBUG)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + } while (0) + +#define TPD_DETAIL(a, arg...)\ + do {\ + if (tp_debug != LEVEL_BASIC)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + } while (0) + + +/*******Part1:Call Back Function implement*******/ +void himax_parse_header(struct image_header_data *header, const unsigned char *fw_image) +{ +} + +void himax_limit_read(struct seq_file *s, struct touchpanel_data *ts) +{ + struct hx_limit_data *limit_data = NULL; + struct himax_proc_operations *syna_ops; + int i; + int j; + + TPD_INFO("%s: Entering\n", __func__); + syna_ops = (struct himax_proc_operations *)ts->private_data; + limit_data = kzalloc(sizeof(struct hx_limit_data), GFP_KERNEL); + if (!limit_data) { + TPD_INFO("limit_data allocat fail!\n"); + goto FAIL_ALLOC_MEM; + } + if (!syna_ops->fp_hx_limit_get) { + TPD_INFO("%s:Doesn't support!\n", __func__); + goto FAIL_FUNC; + } else { + syna_ops->fp_hx_limit_get(ts, limit_data); + } + if (limit_data != NULL) { + for (i = 0 ; i < limit_data->item_size; i++) { + seq_printf(s, "%s:\n", limit_data->item_name[i]); + TPD_INFO("%s: [%d]Size of =%d\n", __func__, i, (int)sizeof(limit_data->item_name[i])); + + for (j = 0 ; j < limit_data->rawdata_size; j++) { + if (j % (ts->hw_res.RX_NUM) == 0) + seq_printf(s, "\n[%2d] ", (j / ts->hw_res.RX_NUM)); + seq_printf(s, "%4d, ", limit_data->crtra_val[i][j]); + } + seq_puts(s, "\n"); + } + } + seq_puts(s, "\n"); + TPD_INFO("%s: END PRINT!\n", __func__); +FAIL_FUNC: + if (limit_data != NULL) { + for (i = 0 ; i < limit_data->item_size; i++) { + kfree(limit_data->item_name[i]); + kfree(limit_data->crtra_val[i]); + } + kfree(limit_data); + } +FAIL_ALLOC_MEM: + TPD_INFO("%s: End\n", __func__); +} + +//proc/touchpanel/baseline_test +static int tp_auto_test_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct himax_proc_operations *syna_ops; +// struct timespec now_time; +// struct rtc_time rtc_now_time; + mm_segment_t old_fs; +// uint8_t data_buf[64]; +// int ret = 0; + int fd = -1; + + struct syna_testdata syna_testdata = { + .TX_NUM = 0, + .RX_NUM = 0, + .fd = -1, + .irq_gpio = -1, + .key_TX = 0, + .key_RX = 0, + .TP_FW = 0, + .fw = NULL, + }; + + if (!ts) + return 0; + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + if (!syna_ops->auto_test) { + seq_puts(s, "Not support auto-test proc node\n"); + return 0; + } + + //step1:disable_irq && get mutex locked + if (!ts->is_noflash_ic) + disable_irq_nosync(ts->client->irq); + else + disable_irq_nosync(ts->s_client->irq); + + mutex_lock(&ts->mutex); + + //step2: create a file to store test data in /sdcard/Tp_Test + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ksys_mkdir("/sdcard/TpTestReport", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn/NG", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOn/OK", 0666); + + ksys_mkdir("/sdcard/TpTestReport/screenOff", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOff/NG", 0666); + ksys_mkdir("/sdcard/TpTestReport/screenOff/OK", 0666); + + //step4:init syna_testdata + syna_testdata.fd = fd; + syna_testdata.TX_NUM = ts->hw_res.TX_NUM; + syna_testdata.RX_NUM = ts->hw_res.RX_NUM; + syna_testdata.irq_gpio = ts->hw_res.irq_gpio; + syna_testdata.key_TX = ts->hw_res.key_TX; + syna_testdata.key_RX = ts->hw_res.key_RX; + syna_testdata.TP_FW = ts->panel_data.TP_FW; + + syna_ops->auto_test(s, ts->chip_data, &syna_testdata); + + + //step5: close file && release test limit firmware + set_fs(old_fs); + + //step6: return to normal mode + //ts->ts_ops->reset(ts->chip_data); + //operate_mode_switch(ts); + + //step7: unlock the mutex && enable irq trigger + mutex_unlock(&ts->mutex); + if (!ts->is_noflash_ic) + enable_irq(ts->client->irq); + else + enable_irq(ts->s_client->irq); + + return 0; +} + +static int baseline_autotest_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_auto_test_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_auto_test_proc_fops = { + .owner = THIS_MODULE, + .open = baseline_autotest_open, + .read = seq_read, + .release = single_release, +}; + +static ssize_t himax_proc_register_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_register_read) { + if (copy_to_user(buff, "Not support auto-test proc node\n", + strlen("Not support auto-test proc node\n"))) + TPD_INFO("%s,here:%d\n", __func__, __LINE__); + return 0; + } + + mutex_lock(&ts->mutex); + ret = syna_ops->himax_proc_register_read(file, buff, len, pos); + mutex_unlock(&ts->mutex); + return ret; +} + +static ssize_t himax_proc_register_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_register_write) { + TPD_INFO("Not support auto-test proc node %s %d\n", __func__, __LINE__); + return 0; + } + + mutex_lock(&ts->mutex); + ret = syna_ops->himax_proc_register_write(file, buff, len, pos); + mutex_unlock(&ts->mutex); + return ret; +} + +static const struct file_operations himax_proc_register_ops = { + .owner = THIS_MODULE, + .read = himax_proc_register_read, + .write = himax_proc_register_write, +}; + +static ssize_t himax_proc_diag_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_diag_read) { + if (copy_to_user(buff, "Not support auto-test proc node\n", + strlen("Not support auto-test proc node\n"))) + TPD_INFO("%s,here:%d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_diag_read(file, buff, len, pos); + return ret; +} + +static ssize_t himax_proc_diag_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_diag_write) { + TPD_INFO("Not support auto-test proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_diag_write(file, buff, len, pos); + return ret; +} + +static const struct file_operations himax_proc_diag_ops = { + .owner = THIS_MODULE, + .read = himax_proc_diag_read, + .write = himax_proc_diag_write, +}; + +static ssize_t himax_proc_DD_debug_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_DD_debug_read) { + if (copy_to_user(buff, "Not support auto-test proc node\n", + strlen("Not support auto-test proc node\n"))) + TPD_INFO("%s,here:%d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_DD_debug_read(file, buff, len, pos); + return ret; +} + +static ssize_t himax_proc_DD_debug_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_DD_debug_write) { + TPD_INFO("Not support dd proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_DD_debug_write(file, buff, len, pos); + return ret; +} + +static const struct file_operations himax_proc_dd_debug_ops = { + .owner = THIS_MODULE, + .read = himax_proc_DD_debug_read, + .write = himax_proc_DD_debug_write, +}; + +static ssize_t himax_proc_FW_debug_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_FW_debug_read) { + TPD_INFO("Not support fw proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_FW_debug_read(file, buff, len, pos); + return ret; +} + +static const struct file_operations himax_proc_fw_debug_ops = { + .owner = THIS_MODULE, + .read = himax_proc_FW_debug_read, +}; + +static ssize_t himax_proc_reset_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_reset_write) { + TPD_INFO("Not support reset proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_reset_write(file, buff, len, pos); + return ret; +} + +static const struct file_operations himax_proc_reset_ops = { + .owner = THIS_MODULE, + .write = himax_proc_reset_write, +}; + +static ssize_t himax_proc_sense_on_off_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_sense_on_off_write) { + TPD_INFO("Not support senseonoff proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_sense_on_off_write(file, buff, len, pos); + return ret; +} + +static const struct file_operations himax_proc_sense_on_off_ops = { + .owner = THIS_MODULE, + .write = himax_proc_sense_on_off_write, +}; + +static ssize_t himax_proc_vendor_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct himax_proc_operations *syna_ops; + ssize_t ret = 0; + + if (!ts) + return 0; + + syna_ops = (struct himax_proc_operations *)ts->private_data; + if (!syna_ops) + return 0; + + if (!syna_ops->himax_proc_vendor_read) { + TPD_INFO("Not support fw proc node %s %d\n", __func__, __LINE__); + return 0; + } + + ret = syna_ops->himax_proc_vendor_read(file, buff, len, pos); + return ret; +} + +static const struct file_operations himax_proc_vendor_ops = { + .owner = THIS_MODULE, + .read = himax_proc_vendor_read, +}; + +int himax_create_proc(struct touchpanel_data *ts, struct himax_proc_operations *syna_ops) +{ + int ret = 0; + + // touchpanel_auto_test interface + struct proc_dir_entry *prEntry_himax = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + ts->private_data = syna_ops; + prEntry_tmp = proc_create_data("ctp_openshort_test", 0664, ts->prEntry_tp, &tp_auto_test_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files:/proc/touchpanel/debug_info/himax + prEntry_himax = proc_mkdir("himax", ts->prEntry_debug_tp); + if (prEntry_himax == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create /proc/touchpanel/debug_info/himax proc entry\n", __func__); + } + + //proc files: /proc/touchpanel/debug_info/himax/register + prEntry_tmp = proc_create_data("register", 0666, prEntry_himax, &himax_proc_register_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files: /proc/touchpanel/debug_info/himax/diag + prEntry_tmp = proc_create_data("diag", 0666, prEntry_himax, &himax_proc_diag_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files: /proc/touchpanel/debug_info/himax/dd + prEntry_tmp = proc_create_data("dd", 0666, prEntry_himax, &himax_proc_dd_debug_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files: /proc/touchpanel/debug_info/himax/fw + prEntry_tmp = proc_create_data("fw", 0666, prEntry_himax, &himax_proc_fw_debug_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files: /proc/touchpanel/debug_info/himax/reset + prEntry_tmp = proc_create_data("reset", 0666, prEntry_himax, &himax_proc_reset_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files: /proc/touchpanel/debug_info/himax/senseonoff + prEntry_tmp = proc_create_data("senseonoff", 0666, prEntry_himax, &himax_proc_sense_on_off_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files: /proc/touchpanel/debug_info/himax/vendor + prEntry_tmp = proc_create_data("vendor", 0664, prEntry_himax, &himax_proc_vendor_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + return ret; +} diff --git a/drivers/oneplus/input/touchscreen_himax/himax/himax_common.h b/drivers/oneplus/input/touchscreen_himax/himax/himax_common.h new file mode 100755 index 0000000000000000000000000000000000000000..5177e908739207795200c21ec39114876ae33358 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/himax_common.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0*/ +/* Oneplus Android Driver Code for spi config functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef HIMAX_COMMON_H +#define HIMAX_COMMON_H + +/*********PART1:Head files**********************/ +#include +#include +#include +#include +#include + +#include "../touchpanel_common_himax.h" + + +/*********PART2:Define Area**********************/ +#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10 +#define SYNAPTICS_RMI4_PRODUCT_INFO_SIZE 2 + +#define DiagonalUpperLimit 1100 +#define DiagonalLowerLimit 900 + + + +/*********PART3:Struct Area**********************/ +struct image_header { + /* 0x00 - 0x0f */ + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char options_firmware_id:1; + unsigned char options_contain_bootloader:1; + /* only available in s4322 , reserved in other, begin*/ + unsigned char options_guest_code:1; + unsigned char options_tddi:1; + unsigned char options_reserved:4; + /* only available in s4322 , reserved in other , end*/ + unsigned char bootloader_version; + unsigned char firmware_size[4]; + unsigned char config_size[4]; + /* 0x10 - 0x1f */ + unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE]; + unsigned char package_id[2]; + unsigned char package_id_revision[2]; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; + /* 0x20 - 0x2f */ + /* only available in s4322 , reserved in other, begin*/ + unsigned char bootloader_addr[4]; + unsigned char bootloader_size[4]; + unsigned char ui_addr[4]; + unsigned char ui_size[4]; + /* only available in s4322 , reserved in other , end*/ + /* 0x30 - 0x3f */ + unsigned char ds_id[16]; + /* 0x40 - 0x4f */ + /* only available in s4322 , reserved in other, begin*/ + union { + struct { + unsigned char dsp_cfg_addr[4]; + unsigned char dsp_cfg_size[4]; + unsigned char reserved_48_4f[8]; + }; + }; + /* only available in s4322 , reserved in other , end*/ + /* 0x50 - 0x53 */ + unsigned char firmware_id[4]; +}; + +struct image_header_data { + bool contains_firmware_id; + unsigned int firmware_id; + unsigned int checksum; + unsigned int firmware_size; + unsigned int config_size; + /* only available in s4322 , reserved in other, begin*/ + unsigned int disp_config_offset; + unsigned int disp_config_size; + unsigned int bootloader_offset; + unsigned int bootloader_size; + /* only available in s4322 , reserved in other , end*/ + unsigned char bootloader_version; + unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; +}; + + +struct test_header { + unsigned int magic1; + unsigned int magic2; + unsigned int withCBC; + unsigned int array_limit_offset; + unsigned int array_limit_size; + unsigned int array_limitcbc_offset; + unsigned int array_limitcbc_size; +}; +struct hx_limit_data { + int item_size; + int rawdata_size; + char **item_name; + int **crtra_val; +}; + +struct syna_testdata { + int TX_NUM; + int RX_NUM; + int fd; + int irq_gpio; + int key_TX; + int key_RX; + uint64_t TP_FW; + const struct firmware *fw; +}; + +//import from "android/bootable/bootloader/lk/platform/msm_shared/include/msm_panel.h" +enum { + OP16037JDI_R63452_1080P_CMD_PANEL = 13, + OP16037SAMSUNG_S6E3FA5_1080P_CMD_PANEL = 14, + UNKNOWN_PANEL +}; + +struct himax_proc_operations { + void (*auto_test)(struct seq_file *s, void *chip_data, struct syna_testdata *syna_testdata); + size_t (*himax_proc_register_write)(struct file *file, const char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_register_read)(struct file *file, char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_diag_write)(struct file *file, const char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_diag_read)(struct file *file, char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_DD_debug_read)(struct file *file, char *buf, size_t len, loff_t *pos); + size_t (*himax_proc_DD_debug_write)(struct file *file, const char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_FW_debug_read)(struct file *file, char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_reset_write)(struct file *file, const char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_sense_on_off_write)(struct file *file, const char *buff, size_t len, loff_t *pos); + size_t (*himax_proc_vendor_read)(struct file *file, char *buff, size_t len, loff_t *pos); + void (*fp_hx_limit_get)(struct touchpanel_data *ts, struct hx_limit_data *limit); +}; + + +void himax_limit_read(struct seq_file *s, struct touchpanel_data *ts); +int himax_create_proc(struct touchpanel_data *ts, struct himax_proc_operations *syna_ops); +void himax_parse_header(struct image_header_data *header, const unsigned char *fw_image); + +#endif diff --git a/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Kconfig b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..9366517dec9e3fed2396e9826e401023b54a62e5 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Kconfig @@ -0,0 +1,8 @@ +#Added by ZhongWenjie@Bsp.group.Tp for himax hx833112A NOFLASH ic driver + +config TOUCHPANEL_HIMAX_HX83112F_NOFLASH +# default y + bool "TP himax hx83112f no-flash IC enable or not for OP" + help + say Y to enable driver for Touchpanel useing himax hx83112a no-flash + diff --git a/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Makefile b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e44b834ba21b81a266f93d32feb45a85b31d5a29 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for the touchscreen drivers. +# +ifeq ($(CONFIG_TRUSTONIC_TEE_SUPPORT),y) +subdir-ccflags-y += -I$(srctree)/drivers/spi/trustzone/spi/Tlspi/inc +endif + +ifeq ($(CONFIG_TRUSTONIC_TEE_SUPPORT),y) + include $(srctree)/drivers/misc/mediatek/gud/Makefile.include +endif +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/mt6763/include +subdir-ccflags-y += -I$(srctree)/drivers/spi/mediatek/mt6763/ -fPIC + +# Each configuration option enables a list of files. +obj-$(CONFIG_TOUCHPANEL_HIMAX_HX83112F_NOFLASH) += hx83112f_noflash.o +#endif diff --git a/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/hx83112f_noflash.c b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/hx83112f_noflash.c new file mode 100755 index 0000000000000000000000000000000000000000..9121acdb3c4b1e74759b98135a182582c2d5aca7 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/hx83112f_noflash.c @@ -0,0 +1,7194 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for HX83112 chipset + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_FB +#include +#include +#endif + +#include +#include + +#include +#include + +#include "hx83112f_noflash.h" + +#define OP17001TRULY_TD4322_1080P_CMD_PANEL 29 + +/*******Part0:LOG TAG Declear********************/ +#define TPD_DEVICE "himax,hxcommon" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do {\ + if (tp_debug == LEVEL_DEBUG)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + } while (0) + +#define TPD_DETAIL(a, arg...)\ + do {\ + if (tp_debug != LEVEL_BASIC)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + } while (0) + +#define TPD_DEBUG_NTAG(a, arg...)\ + do {\ + if (tp_debug)\ + TPD_INFO(a, ##arg);\ + } while (0) + +struct himax_report_data *hx_touch_data; +struct chip_data_hx83112f *g_chip_info; +struct zf_operation *pzf_op; + +int himax_touch_data_size = 128; +int HX_HW_RESET_ACTIVATE; +static int HX_TOUCH_INFO_POINT_CNT; +int g_lcd_vendor; +int irq_en_cnt; + +int g_1kind_raw_size; +uint32_t g_rslt_data_len; +char *g_rslt_data; +int **hx83112f_nf_inspection_criteria; +int *hx83112f_nf_inspt_crtra_flag; +int HX_CRITERIA_ITEM = 4; +int HX_CRITERIA_SIZE; +char *g_file_path_OK; +char *g_file_path_NG; +bool isRead_csv = true; +int hx83112f_nf_fail_write_count; + +int g_zero_event_count; +/* 128k+ */ +int hx83112f_nf_cfg_crc = -1; +int hx83112f_nf_cfg_sz; +uint8_t hx83112f_nf_sram_min[4]; +unsigned char *hx83112f_nf_FW_buf; +/* 128k- */ +struct himax_core_fp g_core_fp; + +bool p_sensor_rec; +int check_point_format; +unsigned char switch_algo; +uint8_t HX_PROC_SEND_FLAG; + +struct dsi_panel *TP_Panel = NULL; +extern int tp_shutdown(struct device *dev); + +/*******Part0: SPI Interface***************/ +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + const struct mtk_chip_config hx_spi_ctrdata = { + .rx_mlsb = 1, + .tx_mlsb = 1, + .cs_pol = 0, + }; +#else +const struct mt_chip_conf hx_spi_ctrdata = { + .setuptime = 25, + .holdtime = 25, + .high_time = 3, /* 16.6MHz */ + .low_time = 3, + .cs_idletime = 2, + .ulthgh_thrsh = 0, + + .cpol = 0, + .cpha = 0, + + .rx_mlsb = 1, + .tx_mlsb = 1, + + .tx_endian = 0, + .rx_endian = 0, + + .com_mod = DMA_TRANSFER, + + .pause = 0, + .finish_intr = 1, + .deassert = 0, + .ulthigh = 0, + .tckdly = 0, +}; +#endif + +int hx83112f_resetgpio_set(struct hw_resource *hw_res, bool on); + +static ssize_t himax_spi_sync(struct touchpanel_data *ts, struct spi_message *message) +{ + int status; + + status = spi_sync(ts->s_client, message); + + if (status == 0) { + status = message->status; + if (status == 0) + status = message->actual_length; + } + return status; +} + +static int himax_spi_read(uint8_t *command, uint8_t command_len, uint8_t *data, uint32_t length, uint8_t toRetry) +{ + struct spi_message message; + struct spi_transfer xfer[2]; + int retry = 0; + int error = -1; + + spi_message_init(&message); + memset(xfer, 0, sizeof(xfer)); + + xfer[0].tx_buf = command; + xfer[0].len = command_len; + spi_message_add_tail(&xfer[0], &message); + + xfer[1].rx_buf = data; + xfer[1].len = length; + spi_message_add_tail(&xfer[1], &message); + + for (retry = 0; retry < toRetry; retry++) { + error = spi_sync(private_ts->s_client, &message); + if (error) + TPD_INFO("SPI read error: %d\n", error); + else + break; + } + if (retry == toRetry) { + TPD_INFO("%s: SPI read error retry over %d\n", + __func__, toRetry); + return -EIO; + } + + return 0; +} + +static int himax_spi_write(uint8_t *buf, uint32_t length) +{ + + struct spi_transfer t = { + .tx_buf = buf, + .len = length, + }; + struct spi_message m; + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + return himax_spi_sync(private_ts, &m); +} + +static int himax_bus_read(uint8_t command, uint32_t length, uint8_t *data) +{ + int result = 0; + uint8_t spi_format_buf[3]; + + mutex_lock(&(g_chip_info->spi_lock)); + spi_format_buf[0] = 0xF3; + spi_format_buf[1] = command; + spi_format_buf[2] = 0x00; + result = himax_spi_read(&spi_format_buf[0], 3, data, length, 10); + mutex_unlock(&(g_chip_info->spi_lock)); + + return result; +} + +static int himax_bus_write(uint8_t command, uint32_t length, uint8_t *data) +{ + /* uint8_t spi_format_buf[length + 2]; */ + int result = 0; + static uint8_t *spi_format_buf; + int alloc_size = 0; +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + alloc_size = 256; +#else + alloc_size = 49156; +#endif + mutex_lock(&(g_chip_info->spi_lock)); + if (spi_format_buf == NULL) + spi_format_buf = kzalloc((alloc_size + 2) * sizeof(uint8_t), GFP_KERNEL); + + if (spi_format_buf == NULL) { + TPD_INFO("%s: Can't allocate enough buf\n", __func__); + return -ENOMEM; + } + spi_format_buf[0] = 0xF2; + spi_format_buf[1] = command; + + memcpy((uint8_t *)(&spi_format_buf[2]), data, length); + result = himax_spi_write(spi_format_buf, length + 2); + mutex_unlock(&(g_chip_info->spi_lock)); + + return result; +} + +/*******Part1: Function Declearation*******/ +static int hx83112f_power_control(void *chip_data, bool enable); +static int hx83112f_get_chip_info(void *chip_data); +static int hx83112f_mode_switch(void *chip_data, work_mode mode, bool flag); +static uint32_t himax_hw_check_CRC(uint8_t *start_addr, int reload_length); +static fw_check_state hx83112f_fw_check(void *chip_data, + struct resolution_info *resolution_info, + struct panel_info *panel_data); +static void himax_read_FW_ver(void); +#ifdef HX_RST_PIN_FUNC +static int hx83112f_resetgpio_set(struct hw_resource *hw_res, bool on); +#endif +void __attribute__((weak)) switch_spi7cs_state(bool normal) +{ +} +/*******Part2:Call Back Function implement*******/ + +/* add for himax */ +void himax_flash_write_burst(uint8_t *reg_byte, uint8_t *write_data) +{ + uint8_t data_byte[8]; + int i = 0; + int j = 0; + + for (i = 0; i < 4; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4; j < 8; j++) + data_byte[j] = write_data[j - 4]; + + if (himax_bus_write(0x00, 8, data_byte) < 0) + TPD_INFO("%s: spi bus access fail!\n", __func__); +} + +void himax_flash_write_burst_length(uint8_t *reg_byte, + uint8_t *write_data, int length) +{ + uint8_t *data_byte; + + data_byte = kzalloc(sizeof(uint8_t) * (length + 4), GFP_KERNEL); + if (data_byte == NULL) { + TPD_INFO("%s: Can't allocate enough buf\n", __func__); + return; + } + memcpy(data_byte, reg_byte, 4); /* assign addr 4bytes */ + memcpy(data_byte + 4, write_data, length); /* assign data n bytes */ + + if (himax_bus_write(0, length + 4, data_byte) < 0) + TPD_INFO("%s: spi bus access fail!\n", __func__); + + kfree(data_byte); +} + +void himax_burst_enable(uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + + tmp_data[0] = 0x31; + if (himax_bus_write(0x13, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + if (himax_bus_write(0x0D, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } +} + +void himax_register_read(uint8_t *read_addr, int read_length, + uint8_t *read_data, bool cfg_flag) +{ + uint8_t tmp_data[4]; + int ret; + + if (cfg_flag == false) { + if (read_length > 256) { + TPD_INFO("%s: read len over 256!\n", __func__); + return; + } + if (read_length > 4) + himax_burst_enable(1); + else + himax_burst_enable(0); + + tmp_data[0] = read_addr[0]; + tmp_data[1] = read_addr[1]; + tmp_data[2] = read_addr[2]; + tmp_data[3] = read_addr[3]; + ret = himax_bus_write(0x00, 4, tmp_data); + if (ret < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + ret = himax_bus_write(0x0C, 1, tmp_data); + if (ret < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + + if (himax_bus_read(0x08, read_length, read_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + if (read_length > 4) + himax_burst_enable(0); + } else if (cfg_flag == true) { + if (himax_bus_read(read_addr[0], read_length, read_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + } else { + TPD_INFO("%s: cfg_flag = %d, value is wrong!\n", __func__, cfg_flag); + return; + } +} + +void himax_register_write(uint8_t *write_addr, int write_length, uint8_t *write_data, bool cfg_flag) +{ + int i = 0; + int address = 0; + + if (cfg_flag == false) { + address = (write_addr[3] << 24) + + (write_addr[2] << 16) + + (write_addr[1] << 8) + + write_addr[0]; + + for (i = address; i < address + write_length; i++) { + if (write_length > 4) + himax_burst_enable(1); + else + himax_burst_enable(0); + himax_flash_write_burst_length(write_addr, write_data, write_length); + } + } else if (cfg_flag == true) { + if (himax_bus_write(write_addr[0], write_length, write_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + } else { + TPD_INFO("%s: cfg_flag = %d, value is wrong!\n", __func__, cfg_flag); + return; + } +} + +static int himax_mcu_register_write(uint8_t *write_addr, uint32_t write_length, + uint8_t *write_data, uint8_t cfg_flag) +{ + int total_read_times = 0; + int max_bus_size = 128, test = 0; + int total_size_temp = 0; + int address = 0; + int i = 0; + + uint8_t tmp_addr[4]; + uint8_t *tmp_data; + + total_size_temp = write_length; + TPD_DETAIL("%s, Entering - total write size=%d\n", __func__, total_size_temp); + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (write_length > 240) + max_bus_size = 240; + else + max_bus_size = write_length; + + +#else + if (write_length > 49152) + max_bus_size = 49152; + else + max_bus_size = write_length; + +#endif + + himax_burst_enable(1); + + tmp_addr[3] = write_addr[3]; + tmp_addr[2] = write_addr[2]; + tmp_addr[1] = write_addr[1]; + tmp_addr[0] = write_addr[0]; + TPD_INFO("%s, write addr = 0x%02X%02X%02X%02X\n", __func__, + tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]); + + tmp_data = kcalloc(max_bus_size, sizeof(uint8_t), GFP_KERNEL); + if (tmp_data == NULL) { + TPD_INFO("%s: Can't allocate enough buf\n", __func__); + return -EINVAL; + } + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_bus_size) { + memcpy(tmp_data, write_data + (i * max_bus_size), max_bus_size); + himax_flash_write_burst_length(tmp_addr, tmp_data, max_bus_size); + + total_size_temp = total_size_temp - max_bus_size; + } else { + test = total_size_temp % max_bus_size; + memcpy(tmp_data, write_data + (i * max_bus_size), test); + TPD_DEBUG("last total_size_temp=%d\n", total_size_temp % max_bus_size); + + himax_flash_write_burst_length(tmp_addr, tmp_data, max_bus_size); + } + + address = ((i + 1) * max_bus_size); + tmp_addr[0] = write_addr[0] + (uint8_t) ((address) & 0x00FF); + + if (tmp_addr[0] < write_addr[0]) + tmp_addr[1] = write_addr[1] + (uint8_t) ((address >> 8) & 0x00FF) + 1; + else + tmp_addr[1] = write_addr[1] + (uint8_t) ((address >> 8) & 0x00FF); + udelay(100); + } + TPD_DETAIL("%s, End\n", __func__); + kfree(tmp_data); + return 0; +} + +void hx_chk_write_register(uint8_t *addr, uint8_t *data) +{ + uint8_t read_data[4] = {0}; + int retry = 10; + + TPD_INFO("%s: Now write addr=0x%02X%02X%02X%02X", __func__, addr[3], addr[2], addr[1], addr[0]); + do { + himax_flash_write_burst_length(addr, data, 4); + mdelay(20); + himax_register_read(addr, 4, read_data, false); + mdelay(20); + TPD_INFO("%s: times %d,Now read[3]=0x%02X,read[2]=0x%02X,read[1]=0x%02X,read[0]=0x%02X\n", + __func__, retry, read_data[3], read_data[2], read_data[1], read_data[0]); + retry--; + } while (retry > 0 && + (data[3] != read_data[3] + || data[2] != read_data[2] + || data[1] != read_data[1] + || data[0] != read_data[0])); + TPD_INFO("%s:END", __func__); +} + +bool himax_mcu_sys_reset(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + //int retry = 0; + + TPD_INFO("%s: called\n", __func__); + + //do { + /* addr:0x31 write value:0x27 */ + tmp_data[0] = 0x27; + if (himax_bus_write(0x31, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return false; + } + /* addr:0x32 write value:0x95 */ + tmp_data[0] = 0x95; + if (himax_bus_write(0x32, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return false; + } + /* addr:0x31 write value:0x00 */ + tmp_data[0] = 0x00; + if (himax_bus_write(0x31, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return false; + } + //usleep_range(1000, 1001); + mdelay(1); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xE4; + himax_register_read(tmp_addr, 4, tmp_data, false); + //TPD_INFO("%s: 1 retry= %d!\n", __func__, retry); + //} while ((tmp_data[1] != 0x02 || tmp_data[0] != 0x00) && retry++ < 5); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; + tmp_addr[0] = 0x04; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: Now addr=0x%02X%02X%02X%02X, value=0x%02X%02X%02X%02X\n", + __func__, tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0], + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + + return true; +} + + +bool himax_sense_off(void) +{ + uint8_t cnt = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + //do { + if (cnt == 0 + || (tmp_data[0] != 0xA5 + && tmp_data[0] != 0x00 + && tmp_data[0] != 0x87)) { + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0xA5; + himax_flash_write_burst(tmp_addr, tmp_data); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + himax_register_read(tmp_addr, 4, tmp_data, false); + if (tmp_data[0] != 0x05) { + TPD_INFO("%s: it already in safe mode=0x%02X\n", __func__, tmp_data[0]); + //break; + } + }else{ + //usleep_range(10000, 10001); + mdelay(10); + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x5C; + himax_register_read(tmp_addr, 4, tmp_data, false); + cnt++; + TPD_INFO("%s: save mode lock cnt = %d, data[0] = %2X!\n", __func__, cnt, tmp_data[0]); + } + //} while (tmp_data[0] != 0x87 && (cnt < 50)); + + cnt = 0; + + //do { + /* addr:0x31 write value:0x27*/ + tmp_data[0] = 0x27; + if (himax_bus_write(0x31, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return false; + } + /* addr:0x32 write value:0x95*/ + tmp_data[0] = 0x95; + if (himax_bus_write(0x32, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return false; + } + /* Check enter_save_mode */ + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_INFO("%s: Check enter_save_mode data[0]=%X\n", __func__, tmp_data[0]); + + if (tmp_data[0] == 0x0C) { + /* Reset TCON */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + mdelay(20); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + himax_flash_write_burst(tmp_addr, tmp_data); + + /* Reset ADC */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x94; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + mdelay(20); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x01; + himax_flash_write_burst(tmp_addr, tmp_data); + return true; + } + mdelay(20); +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(g_chip_info->hw_res, false); + hx83112f_resetgpio_set(g_chip_info->hw_res, true); +#else + himax_mcu_sys_reset(); +#endif + //} while (cnt++ < 15); + + if (cnt >= 15) { +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(g_chip_info->hw_res, false); // reset gpio + hx83112f_resetgpio_set(g_chip_info->hw_res, true); // reset gpio +#else + himax_mcu_sys_reset(); +#endif + //=========================================== + // 0x31 ==> 0x27 + //=========================================== + tmp_data[0] = 0x27; + if (himax_bus_write(0x31, 1, tmp_data) < 0) { + TPD_INFO("%s: i2c access fail!\n", __func__); + return false; + } + //=========================================== + // 0x32 ==> 0x95 + //=========================================== + tmp_data[0] = 0x95; + if (himax_bus_write(0x32, 1, tmp_data) < 0) { + TPD_INFO("%s: i2c access fail!\n", __func__); + return false; + } + /* Turn off auto mux */ + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x02; + tmp_addr[1] = 0x02; + tmp_addr[0] = 0xBC; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 0x900000A8, tmp_data[0]=%x, tmp_data[1]=%x, tmp_data[2]=%x, tmp_data[3]=%x\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + } + + return false; +} + +void himax_interface_on(void) +{ + uint8_t tmp_data[5]; + uint8_t tmp_data2[2]; + int cnt = 0; + + /* Read a dummy register to wake up I2C. */ + if (himax_bus_read(0x08, 4, tmp_data) < 0) { /* to knock I2C */ + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + + do { + /* Enable continuous burst mode : 0x13 ==> 0x31 */ + tmp_data[0] = 0x31; + if (himax_bus_write(0x13, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + /* Do not AHB address auto +4 : 0x0D ==> 0x10 */ + tmp_data[0] = (0x10); + if (himax_bus_write(0x0D, 1, tmp_data) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return; + } + + /* Check cmd */ + himax_bus_read(0x13, 1, tmp_data); + himax_bus_read(0x0D, 1, tmp_data2); + + if (tmp_data[0] == 0x31 && tmp_data2[0] == 0x10) + break; + mdelay(20); + } while (++cnt < 10); + + if (cnt > 0) + TPD_INFO("%s:Polling burst mode: %d times", __func__, cnt); +} + +void himax_diag_register_set(uint8_t diag_command) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + TPD_INFO("diag_command = %d\n", diag_command); + + himax_interface_on(); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0xEC; + + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = diag_command; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: tmp_data[3] = 0x%02X, tmp_data[2] = 0x%02X, tmp_data[1] = 0x%02X, tmp_data[0] = 0x%02X!\n", + __func__, tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); +} + +static void himax_hx83112f_reload_to_active(void) +{ + uint8_t addr[4] = {0}; + uint8_t data[4] = {0}; + uint8_t retry_cnt = 0; + + addr[3] = 0x90; + addr[2] = 0x00; + addr[1] = 0x00; + addr[0] = 0x48; + + do { + data[3] = 0x00; + data[2] = 0x00; + data[1] = 0x00; + data[0] = 0xEC; + himax_register_write(addr, 4, data, 0); + //usleep_range(1000,1001); + mdelay(1); + himax_register_read(addr, 4, data, 0); + TPD_INFO("%s: data[1]=%d, data[0]=%d, retry_cnt=%d\n", __func__, data[1], data[0], retry_cnt); + retry_cnt++; + } while ((data[1] != 0x01 || data[0] != 0xEC) + && retry_cnt < HIMAX_REG_RETRY_TIMES); +} + +void himax_sense_on(uint8_t FlashMode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int retry = 0; + + TPD_DETAIL("Enter %s\n", __func__); + + himax_interface_on(); + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + + if (!FlashMode) { + himax_mcu_sys_reset(); + himax_hx83112f_reload_to_active(); + } else { + himax_hx83112f_reload_to_active(); + do { + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x98; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x53; + himax_register_write(tmp_addr, 4, tmp_data, false); + + tmp_addr[0] = 0xE4; + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_DETAIL("%s:Read status from IC = %X, %X\n", __func__, tmp_data[0], tmp_data[1]); + } while ((tmp_data[1] != 0x01 || tmp_data[0] != 0x00) && retry++ < 5); + + if (retry >= 5) { + TPD_INFO("%s: Fail:\n", __func__); + himax_mcu_sys_reset(); + himax_register_write(tmp_addr, 4, tmp_data, false); + himax_hx83112f_reload_to_active(); + } else { + TPD_DETAIL("%s:OK and Read status from IC = %X, %X\n", __func__, tmp_data[0], tmp_data[1]); + + /* reset code*/ + tmp_data[0] = 0x00; + if (himax_bus_write(0x31, 1, tmp_data) < 0) + TPD_INFO("%s: spi bus access fail!\n", __func__); + if (himax_bus_write(0x32, 1, tmp_data) < 0) + TPD_INFO("%s: spi bus access fail!\n", __func__); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x98; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_register_write(tmp_addr, 4, tmp_data, false); + } + } +} + +/** + * hx83112f_enable_interrupt - Device interrupt ability control. + * @chip_info: struct include i2c resource. + * @enable: disable or enable control purpose. + * Return 0: succeed, -1: failed. + */ +static int hx83112f_enable_interrupt(struct chip_data_hx83112f *chip_info, bool enable) +{ + + + if (enable == true && irq_en_cnt == 0) { + enable_irq(chip_info->hx_irq); + irq_en_cnt = 1; + TPD_DETAIL("%s enter, enable irq=%d.\n", __func__, chip_info->hx_irq); + } else if (enable == false && irq_en_cnt == 1) { + disable_irq_nosync(chip_info->hx_irq); + //disable_irq(chip_info->hx_irq); + irq_en_cnt = 0; + TPD_DETAIL("%s enter, disable irq=%d.\n", __func__, chip_info->hx_irq); + } else { + TPD_DETAIL("irq is not pairing! enable= %d, cnt = %d\n", enable, irq_en_cnt); + } + + + return 0; +} + +void himax_in_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len) +{ + switch (len) { + case 1: + cmd[0] = addr; + break; + case 2: + cmd[0] = addr % 0x100; + cmd[1] = (addr >> 8) % 0x100; + break; + case 4: + cmd[0] = addr % 0x100; + cmd[1] = (addr >> 8) % 0x100; + cmd[2] = (addr >> 16) % 0x100; + cmd[3] = addr / 0x1000000; + break; + default: + TPD_INFO("%s: input length fault, len = %d!\n", __func__, len); + } +} + +int hx_dis_rload_0f(void) +{ + /* Disable Flash Reload */ + int retry = 10; + int check_val = 0; + uint8_t tmp_data[4] = {0}; + uint8_t addr[4] = {0xc0, 0x72, 0x00, 0x10}; + uint8_t data[4] = {0x00, 0x00, 0x00, 0x00}; + + TPD_DETAIL("%s: Entering !\n", __func__); + + do { + himax_flash_write_burst(pzf_op->addr_dis_flash_reload, pzf_op->data_dis_flash_reload); + //usleep_range(1000,1001); + mdelay(1); + himax_register_read(pzf_op->addr_dis_flash_reload, 4, tmp_data, false); + TPD_DETAIL("Now data: tmp[3] = 0x%02X ||tmp[2] =0x%02X || tmp[1] = 0x%02X || tmp[0] = 0x%02X\n", + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + if (tmp_data[3] != 0x00 || tmp_data[2] != 0x00 || tmp_data[1] != 0x9A || tmp_data[0] != 0xA9) { + TPD_INFO("Not Same,Write Fail, there is %d retry times!\n", retry); + check_val = 1; + } else { + check_val = 0; + TPD_DETAIL("It's same! Write success!\n"); + } + } while (check_val == 1 && retry-- > 0); + + /* 100072c0 clear 00 */ + himax_flash_write_burst(addr, data); + himax_register_read(addr, 4, tmp_data, false); + TPD_DETAIL("tmp_data[3]=0x%02X,tmp_data[2]=0x%02X,tmp_data[1]=0x%02X,tmp_data[0]=0x%02X\n", + tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + if (tmp_data[3] != 0x00 || tmp_data[2] != 0x00 || tmp_data[1] != 0x00 || tmp_data[0] != 0x00) + TPD_INFO("%s: 100072c0 clear 00 failed!\n", __func__); + + TPD_DETAIL("%s: END !\n", __func__); + + return check_val; +} + +void himax_mcu_write_sram_0f(const struct firmware *fw_entry, uint8_t *addr, int start_index, uint32_t write_len) +{ + int total_read_times = 0; + int max_bus_size = MAX_TRANS_SZ; + int total_size_temp = 0; + int total_size = 0; + int address = 0; + int i = 0; + + uint8_t tmp_addr[4]; + //uint8_t *tmp_data; + uint32_t now_addr; + + TPD_DETAIL("%s, ---Entering\n", __func__); + + total_size = fw_entry->size; + + total_size_temp = write_len; +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (write_len > MAX_TRANS_SZ) + max_bus_size = MAX_TRANS_SZ; + else + max_bus_size = write_len; +#else + if (write_len > 49152) + max_bus_size = 49152; + else + max_bus_size = write_len; +#endif + himax_burst_enable(1); + + tmp_addr[3] = addr[3]; + tmp_addr[2] = addr[2]; + tmp_addr[1] = addr[1]; + tmp_addr[0] = addr[0]; + TPD_DETAIL("%s, write = 0x%2.2X, = 0x%2.2X, [1] = 0x%2.2X, [0] = 0x%2.2X\n", + __func__, tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]); + now_addr = (addr[3] << 24) + (addr[2] << 16) + (addr[1] << 8) + addr[0]; + TPD_DETAIL("now addr= 0x%08X\n", now_addr); + + TPD_DETAIL("%s, total size=%d\n", __func__, total_size); + + if (g_chip_info->tmp_data == NULL) { + //TPD_INFO("%s, enteralloc g_chip_info->tmp_data\n", __func__); + g_chip_info->tmp_data = kcalloc(firmware_update_space, sizeof(uint8_t), GFP_KERNEL); + if (g_chip_info->tmp_data == NULL) { + TPD_INFO("%s, alloc g_chip_info->tmp_data failed\n", __func__); + return; + } + //TPD_INFO("%s, end---------alloc g_chip_info->tmp_data\n", __func__); + } + memcpy(g_chip_info->tmp_data, fw_entry->data, total_size); + + if (total_size_temp % max_bus_size == 0) + total_read_times = total_size_temp / max_bus_size; + else + total_read_times = total_size_temp / max_bus_size + 1; + + for (i = 0; i < (total_read_times); i++) { + /* + * TPD_INFO("[log]write %d time start!\n", i); + * TPD_INFO("[log]addr[3] = 0x%02X, addr[2] = 0x%02X, addr[1] = 0x%02X, addr[0] = 0x%02X!\n", + * tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]); + */ + if (total_size_temp >= max_bus_size) { + himax_flash_write_burst_length(tmp_addr, + &(g_chip_info->tmp_data[start_index + i * max_bus_size]), + max_bus_size); + total_size_temp = total_size_temp - max_bus_size; + } else { + TPD_DETAIL("last total_size_temp=%d\n", total_size_temp); + himax_flash_write_burst_length(tmp_addr, + &(g_chip_info->tmp_data[start_index + i * max_bus_size]), + total_size_temp % max_bus_size); + } + + /*TPD_INFO("[log]write %d time end!\n", i);*/ + address = ((i + 1) * max_bus_size); + tmp_addr[0] = addr[0] + (uint8_t) ((address) & 0x00FF); + + if (tmp_addr[0] < addr[0]) + tmp_addr[1] = addr[1] + (uint8_t) ((address >> 8) & 0x00FF) + 1; + else + tmp_addr[1] = addr[1] + (uint8_t) ((address >> 8) & 0x00FF); + + udelay(100); + } + TPD_DETAIL("%s, ----END\n", __func__); + //kfree (tmp_data); + memset(g_chip_info->tmp_data, 0, total_size); +} +int himax_sram_write_crc_check(const struct firmware *fw_entry, uint8_t *addr, int strt_idx, uint32_t len) +{ + //int retry = 0; + int crc = -1; + + //do { + g_core_fp.fp_write_sram_0f(fw_entry, addr, strt_idx, len); + crc = himax_hw_check_CRC(pzf_op->data_sram_start_addr, HX64K); + TPD_INFO("%s, crc = %d\n", __func__, crc); + //retry++; + /*I("%s, HW CRC %s in %d time\n", __func__, (crc == 0)?"OK":"Fail", retry);*/ + //} while (crc != 0 && retry < 10); + + return crc; +} +static int himax_mcu_Calculate_CRC_with_AP(unsigned char *FW_content, int CRC_from_FW, int len) +{ + int i, j, length = 0; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + + length = len / 4; + + for (i = 0; i < length; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1; j < 4; j++) { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + + CRC = fw_data ^ CRC; + + for (j = 0; j < 32; j++) { + if ((CRC % 2) != 0) + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + else + CRC = (((CRC >> 1) & 0x7FFFFFFF)); + } + /*I("CRC = %x, i = %d\n", CRC, i);*/ + } + + return CRC; +} + +bool hx_parse_bin_cfg_data(const struct firmware *fw_entry) +{ + //bool flag_1k_header = false; + int part_num = 0; + int i = 0; + uint8_t buf[16]; + int i_max = 0; + int i_min = 0; + uint32_t dsram_base = 0xFFFFFFFF; + uint32_t dsram_max = 0; + struct zf_info *zf_info_arr; + + /*0. check 1k header*/ +/* + if (fw_entry->data[0x00] == 0x00 + && fw_entry->data[0x01] == 0x00 + && fw_entry->data[0x02] == 0x00 + && fw_entry->data[0x03] == 0x00 + && fw_entry->data[0x04] == 0x00 + && fw_entry->data[0x05] == 0x00 + && fw_entry->data[0x06] == 0x00 + && fw_entry->data[0x07] == 0x00 + && fw_entry->data[0x0E] == 0x87) + flag_1k_header = true; + else + flag_1k_header = false; +*/ + /*1. get number of partition*/ +/* if (flag_1k_header == true) + part_num = fw_entry->data[HX64K + HX1K + 12]; + else + part_num = fw_entry->data[HX64K + 12]; +*/ + + part_num = fw_entry->data[HX64K + HX1K + 12]; + + TPD_INFO("%s, Number of partition is %d\n", __func__, part_num); + if (part_num <= 1) { + TPD_INFO("%s, size of cfg part failed! part_num = %d\n", __func__, part_num); + return false; + } + /*2. initial struct of array*/ + zf_info_arr = kzalloc(part_num * sizeof(struct zf_info), GFP_KERNEL); + if (zf_info_arr == NULL) { + TPD_INFO("%s, Allocate ZF info array failed!\n", __func__); + return false; + } + + for (i = 0; i < part_num; i++) { + /*3. get all partition*/ +/* + if (flag_1k_header == true) + memcpy(buf, &fw_entry->data[i * 0x10 + HX64K + HX1K], 16); + else + memcpy(buf, &fw_entry->data[i * 0x10 + HX64K], 16); +*/ + memcpy(buf, &fw_entry->data[i * 0x10 + HX64K + HX1K], 16); + + memcpy(zf_info_arr[i].sram_addr, buf, 4); + zf_info_arr[i].write_size = buf[5] << 8 | buf[4]; + //zf_info_arr[i].fw_addr = buf[9] << 8 | buf[8]; + zf_info_arr[i].fw_addr = buf[10] << 16 | buf[9] << 8 | buf[8]; + zf_info_arr[i].cfg_addr = zf_info_arr[i].sram_addr[0]; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[1] << 8; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[2] << 16; + zf_info_arr[i].cfg_addr += zf_info_arr[i].sram_addr[3] << 24; + + //TPD_INFO("%s, [%d] SRAM addr = %08X\n", __func__, i, zf_info_arr[i].cfg_addr); + //TPD_INFO("%s, [%d] fw_addr = %04X!\n", __func__, i, zf_info_arr[i].fw_addr); + //TPD_INFO("%s, [%d] write_size = %d!\n", __func__, i, zf_info_arr[i].write_size); + if (i == 0) + continue; + if (dsram_base > zf_info_arr[i].cfg_addr) { + dsram_base = zf_info_arr[i].cfg_addr; + i_min = i; + } else if (dsram_max < zf_info_arr[i].cfg_addr) { + dsram_max = zf_info_arr[i].cfg_addr; + i_max = i; + } + } + + for (i = 0; i < 4; i++) + hx83112f_nf_sram_min[i] = zf_info_arr[i_min].sram_addr[i]; + hx83112f_nf_cfg_sz = (dsram_max - dsram_base) + zf_info_arr[i_max].write_size; + hx83112f_nf_cfg_sz = hx83112f_nf_cfg_sz + (hx83112f_nf_cfg_sz % 16); + + TPD_INFO("%s, hx83112f_nf_cfg_sz = %d!, dsram_base = %X, dsram_max = %X\n", + __func__, hx83112f_nf_cfg_sz, dsram_base, dsram_max); + + if (hx83112f_nf_FW_buf == NULL) { + hx83112f_nf_FW_buf = kzalloc(sizeof(unsigned char) * FW_BIN_16K_SZ, GFP_KERNEL); + if (hx83112f_nf_FW_buf == NULL) { + TPD_INFO("%s, Allocate hx83112f_nf_FW_buf failed!\n", __func__); + return false; + } + } + + for (i = 1; i < part_num; i++) + memcpy(hx83112f_nf_FW_buf + (zf_info_arr[i].cfg_addr - dsram_base), + (unsigned char *)&fw_entry->data[zf_info_arr[i].fw_addr], zf_info_arr[i].write_size); + + hx83112f_nf_cfg_crc = himax_mcu_Calculate_CRC_with_AP(hx83112f_nf_FW_buf, 0, hx83112f_nf_cfg_sz); + TPD_INFO("chenyunrui:hx83112f_nf_cfg_crc = %ld\n", hx83112f_nf_cfg_crc); + kfree(zf_info_arr); + return true; +} + +static int hx83112f_nf_zf_part_info(const struct firmware *fw_entry) +{ + bool ret = false; + //bool flag_1k_header = false; + //struct timespec timeStart, timeEnd, timeDelta; + int retry = 0; + int crc = -1; + uint8_t tmp_data[4] = {0, 0, 0, 0}; + + //getnstimeofday(&timeStart); + if (!hx_parse_bin_cfg_data(fw_entry)) + TPD_INFO("%s, Parse cfg from bin failed\n", __func__); + + himax_mcu_sys_reset(); + himax_sense_off(); + //getnstimeofday(&timeStart); + /* first 64K */ + + + /*0. check 1k header*/ + /*if (fw_entry->data[0x00] == 0x00 + && fw_entry->data[0x01] == 0x00 + && fw_entry->data[0x02] == 0x00 + && fw_entry->data[0x03] == 0x00 + && fw_entry->data[0x04] == 0x00 + && fw_entry->data[0x05] == 0x00 + && fw_entry->data[0x06] == 0x00 + && fw_entry->data[0x07] == 0x00 + && fw_entry->data[0x0E] == 0x87) + flag_1k_header = true; + else + flag_1k_header = false; + + TPD_INFO("64K CRC Failed! flag_1k_header= %d\n", flag_1k_header); + + if (flag_1k_header == true) + crc = himax_sram_write_crc_check(fw_entry, pzf_op->data_sram_start_addr, HX1K, HX64K); + else + crc = himax_sram_write_crc_check(fw_entry, pzf_op->data_sram_start_addr, 0, HX64K); + //crc = himax_hw_check_CRC(pzf_op->data_sram_start_addr, HX64K); + */ + + crc = himax_sram_write_crc_check(fw_entry, pzf_op->data_sram_start_addr, HX1K, HX64K); + + ret = (crc == 0) ? true : false; + if (ret == false) + TPD_INFO("64K CRC Failed! CRC = %X", crc); + + //do { + himax_mcu_register_write(hx83112f_nf_sram_min, hx83112f_nf_cfg_sz, hx83112f_nf_FW_buf, 0); + /*himax_register_write(hx83112f_nf_sram_min, hx83112f_nf_cfg_sz, hx83112f_nf_FW_buf, 0); */ + crc = himax_hw_check_CRC(hx83112f_nf_sram_min, hx83112f_nf_cfg_sz); + if (crc != hx83112f_nf_cfg_crc) { + TPD_INFO("Config CRC FAIL, HW CRC = %X, SW CRC = %X, retry time = %d", + crc, hx83112f_nf_cfg_crc, retry); + //retry++; + ret = false; + } else { + ret = true; + } + //} while (!ret && retry < 10); + + himax_register_write(pzf_op->data_mode_switch, 4, tmp_data, false); + //getnstimeofday(&timeEnd); + //timeDelta.tv_nsec = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) - + //(timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + //TPD_INFO("update firmware time = %ld us\n", timeDelta.tv_nsec / 1000); + TPD_INFO("-------------------update firmware time ---------------------\n"); + return 0; +} + +void himax_mcu_firmware_update_0f(const struct firmware *fw_entry) +{ + //int retry = 0; + //int crc = -1; + int ret = 0; + //uint8_t temp_addr[4]; + //uint8_t temp_data[4]; + struct firmware *request_fw_headfile = NULL; + const struct firmware *tmp_fw_entry = NULL; + bool reload = false; + + if (g_f_0f_updat == 1) { + TPD_INFO("%s:[Warning]Other thread is updating now!\n", __func__); + return; + } + TPD_INFO("%s:Entering Update Flow!\n", __func__); + g_f_0f_updat = 1; + + if (fw_entry == NULL || reload) { + TPD_INFO("Get FW from headfile\n"); + if (request_fw_headfile == NULL) + request_fw_headfile = kzalloc(sizeof(struct firmware), GFP_KERNEL); + + if (request_fw_headfile == NULL) { + TPD_INFO("%s kzalloc failed!\n", __func__); + goto END; + } + if (g_chip_info->g_fw_sta) { + TPD_INFO("request firmware failed, get from g_fw_buf\n"); + request_fw_headfile->size = g_chip_info->g_fw_len; + request_fw_headfile->data = g_chip_info->g_fw_buf; + tmp_fw_entry = request_fw_headfile; + + } else { + TPD_INFO("request firmware failed, get from headfile\n"); + if (0) { + // request_fw_headfile->size = g_chip_info->p_firmware_headfile->firmware_size; + // request_fw_headfile->data = g_chip_info->p_firmware_headfile->firmware_data; + // tmp_fw_entry = request_fw_headfile; + // g_chip_info->using_headfile = true; + } else { + TPD_INFO("firmware_data is NULL! exit firmware update!\n"); + if (request_fw_headfile != NULL) { + kfree(request_fw_headfile); + request_fw_headfile = NULL; + } + goto END; + } + } + } else { + tmp_fw_entry = fw_entry; + } + + if ((int)tmp_fw_entry->size > HX64K) { + TPD_INFO("%s: fw is larger than HX64K\n", __func__); + ret = hx83112f_nf_zf_part_info(tmp_fw_entry); + } else { + TPD_INFO("%s: fw is less than HX64K, do nothing!!!\n", __func__); + goto END; + } + if (private_ts->suspend_state != TP_RESUME_COMPLETE) { + hx83112f_fw_check(private_ts->chip_data, &private_ts->resolution_info, &private_ts->panel_data); + } + if (request_fw_headfile != NULL) { + kfree(request_fw_headfile); + request_fw_headfile = NULL; + } + +END: + g_f_0f_updat = 0; + + TPD_DETAIL("%s, END\n", __func__); +} + +int himax_mcu_0f_operation_test_dirly(char *fw_name) +{ + int err = NO_ERR; + const struct firmware *fw_entry = NULL; + + TPD_DETAIL("%s, Entering\n", __func__); + TPD_DETAIL("file name = %s\n", fw_name); + TPD_INFO("Request TP firmware.\n"); + err = request_firmware(&fw_entry, fw_name, private_ts->dev); + if (err < 0) { + TPD_INFO("%s, fail in line%d error code=%d, file maybe fail\n", __func__, __LINE__, err); + if (fw_entry != NULL) { + release_firmware(fw_entry); + fw_entry = NULL; + } + return err; + } + + himax_mcu_firmware_update_0f(fw_entry); + release_firmware(fw_entry); + + TPD_DETAIL("%s, END\n", __func__); + return err; +} + +void himax_mcu_0f_operation(struct work_struct *work) +{ + hx83112f_enable_interrupt(g_chip_info, false); + TPD_INFO("file name = %s\n", private_ts->panel_data.fw_name); + + /* trigger reset */ +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(g_chip_info->hw_res, false); + hx83112f_resetgpio_set(g_chip_info->hw_res, true); + //#else + // himax_mcu_sys_reset(); +#endif + himax_mcu_firmware_update_0f(NULL); + //release_firmware (g_chip_info->g_fw_entry); + + g_core_fp.fp_reload_disable(); + mdelay(20); + himax_read_FW_ver(); + mdelay(20); + himax_sense_on(0x00); + mdelay(20); + TPD_INFO("%s:End\n", __func__); + +#ifdef CONFIG_OP_TP_APK + if (g_chip_info->debug_mode_sta) { + if (private_ts->apk_op && private_ts->apk_op->apk_debug_set) + private_ts->apk_op->apk_debug_set(private_ts->chip_data, true); + } +#endif + + hx83112f_enable_interrupt(g_chip_info, true); + + g_f_0f_updat = 0; + TPD_INFO("%s, END\n", __func__); +} + +int hx_0f_init(void) +{ + pzf_op = kzalloc(sizeof(struct zf_operation), GFP_KERNEL); + if (!pzf_op) { + TPD_INFO("%s:alloc pzf_op failed\n", __func__); + return 0; + } + + g_core_fp.fp_reload_disable = hx_dis_rload_0f; + g_core_fp.fp_write_sram_0f = himax_mcu_write_sram_0f; + + himax_in_parse_assign_cmd(zf_addr_dis_flash_reload, pzf_op->addr_dis_flash_reload, + sizeof(pzf_op->addr_dis_flash_reload)); + himax_in_parse_assign_cmd(zf_data_dis_flash_reload, pzf_op->data_dis_flash_reload, + sizeof(pzf_op->data_dis_flash_reload)); + himax_in_parse_assign_cmd(zf_addr_system_reset, pzf_op->addr_system_reset, sizeof(pzf_op->addr_system_reset)); + himax_in_parse_assign_cmd(zf_data_system_reset, pzf_op->data_system_reset, sizeof(pzf_op->data_system_reset)); + himax_in_parse_assign_cmd(zf_data_sram_start_addr, pzf_op->data_sram_start_addr, + sizeof(pzf_op->data_sram_start_addr)); + himax_in_parse_assign_cmd(zf_data_sram_clean, pzf_op->data_sram_clean, sizeof(pzf_op->data_sram_clean)); + himax_in_parse_assign_cmd(zf_data_cfg_info, pzf_op->data_cfg_info, sizeof(pzf_op->data_cfg_info)); + himax_in_parse_assign_cmd(zf_data_fw_cfg_p1, pzf_op->data_fw_cfg_p1, sizeof(pzf_op->data_fw_cfg_p1)); + himax_in_parse_assign_cmd(zf_data_fw_cfg_p2, pzf_op->data_fw_cfg_p2, sizeof(pzf_op->data_fw_cfg_p2)); + himax_in_parse_assign_cmd(zf_data_fw_cfg_p3, pzf_op->data_fw_cfg_p3, sizeof(pzf_op->data_fw_cfg_p3)); + himax_in_parse_assign_cmd(zf_data_adc_cfg_1, pzf_op->data_adc_cfg_1, sizeof(pzf_op->data_adc_cfg_1)); + himax_in_parse_assign_cmd(zf_data_adc_cfg_2, pzf_op->data_adc_cfg_2, sizeof(pzf_op->data_adc_cfg_2)); + himax_in_parse_assign_cmd(zf_data_adc_cfg_3, pzf_op->data_adc_cfg_3, sizeof(pzf_op->data_adc_cfg_3)); + himax_in_parse_assign_cmd(zf_data_map_table, pzf_op->data_map_table, sizeof(pzf_op->data_map_table)); + himax_in_parse_assign_cmd(zf_data_mode_switch, pzf_op->data_mode_switch, sizeof(pzf_op->data_mode_switch)); + + + return 0; +} + +bool himax_ic_package_check(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t ret_data = 0x00; + int i = 0; + + hx83112f_resetgpio_set(g_chip_info->hw_res, true); // reset gpio + hx83112f_resetgpio_set(g_chip_info->hw_res, false); // reset gpio + hx83112f_resetgpio_set(g_chip_info->hw_res, true); // reset gpio + mdelay(20); + + himax_sense_off(); + + for (i = 0; i < 5; i++) { + // Product ID + // Touch + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xD0; + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_INFO("%s:Read driver IC ID = %X, %X, %X\n", __func__, tmp_data[3], tmp_data[2], tmp_data[1]); + push_component_info(TP, "83112F", "Himax"); + + if ((tmp_data[3] == 0x83) && (tmp_data[2] == 0x11) && (tmp_data[1] == 0x2f)) { + IC_TYPE = HX_83112F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + hx_0f_init(); + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 49157; //0x00C005 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 49158; //0x00C006 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 49408; //0x00C100 + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 49409; //0x00C101 + CFG_VER_MIN_FLASH_LENG = 1; + CID_VER_MAJ_FLASH_ADDR = 49154; //0x00C002 + CID_VER_MAJ_FLASH_LENG = 1; + CID_VER_MIN_FLASH_ADDR = 49155; //0x00C003 + CID_VER_MIN_FLASH_LENG = 1; + //PANEL_VERSION_ADDR = 49156; //0x00C004 + //PANEL_VERSION_LENG = 1; +#ifdef HX_AUTO_UPDATE_FW + g_i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR] << 8 | i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; + g_i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR] << 8 | i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; + g_i_CID_MAJ = i_CTPM_FW[CID_VER_MAJ_FLASH_ADDR]; + g_i_CID_MIN = i_CTPM_FW[CID_VER_MIN_FLASH_ADDR]; +#endif + TPD_INFO("Himax IC package 83112_in\n"); + ret_data = true; + break; + } + ret_data = false; + TPD_INFO("%s:Read driver ID register Fail:\n", __func__); + push_component_info(TP, "unknow", "unknow"); + } + + return ret_data; +} + + +void himax_power_on_init(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + TPD_INFO("%s\n", __func__); + + /*RawOut select initial*/ + //tmp_addr[3] = 0x80; + //tmp_addr[2] = 0x02; + //tmp_addr[1] = 0x04; + //tmp_addr[0] = 0xB4; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0xEC; + + + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_register_write(tmp_addr, 4, tmp_data, false); + + /*DSRAM func initial*/ + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x07; + tmp_addr[0] = 0xFC; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_register_write(tmp_addr, 4, tmp_data, false); + + himax_sense_on(0x00); +} + +int himax_check_remapping(void) +{ + uint8_t cmd[4]; + uint8_t data[64]; + uint8_t data2[64]; + int retry = 200; + int reload_status = 1; + + while (reload_status == 1) { + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x7f; + cmd[0] = 0x00; + himax_register_read(cmd, 4, data, false); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x72; + cmd[0] = 0xc0; + himax_register_read(cmd, 4, data2, false); + + if ((data[2] == 0x9A && data[3] == 0xA9) || (data2[1] == 0x72 && data2[0] == 0xc0)) { + TPD_INFO("reload OK!\n"); + reload_status = 0; + break; + } else if (retry == 0) { + TPD_INFO("reload 20 times! fail\n"); + break; + } + retry--; + //usleep_range(10000,10001); + mdelay(10); + TPD_INFO("reload fail, delay 10ms retry=%d\n", retry); + } + TPD_INFO("%s : data[0] = 0x%2.2X, data[1] = 0x%2.2X, data[2] = 0x%2.2X, data[3] = 0x%2.2X\n", + __func__, data[0], data[1], data[2], data[3]); + TPD_INFO("reload_status=%d\n", reload_status); + return reload_status; +} + +static void himax_read_FW_ver(void) +{ + uint8_t cmd[4]; + uint8_t data[64]; + //uint8_t data2[64]; + //int retry = 200; + //int reload_status = 0; + + himax_sense_on(0); + + if (himax_check_remapping()) + return; + + himax_sense_off(); + + /* Read FW version : 0x1000_7004 but 05,06 are the real addr for FW Version */ + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x04; + himax_register_read(cmd, 4, data, false); + + + TPD_INFO("PANEL_VER : %X\n", data[0]); + TPD_INFO("FW_VER : %X\n", data[1] << 8 | data[2]); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x14; + himax_register_read(cmd, 4, data, false); + g_chip_info->fw_id = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + TPD_INFO("%s : data[0] = 0x%2.2X, data[1] = 0x%2.2X, data[2] = 0x%2.2X, data[3] = 0x%2.2X\n", + __func__, data[0], data[1], data[2], data[3]); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x84; + himax_register_read(cmd, 4, data, false); + g_chip_info->touch_ver = data[2]; + TPD_INFO("CFG_VER : %X\n", data[2] << 8 | data[3]); + TPD_INFO("TOUCH_VER : %X\n", data[2]); + TPD_INFO("DISPLAY_VER : %X\n", data[3]); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x00; + himax_register_read(cmd, 4, data, false); + g_chip_info->fw_ver = data[2] << 8 | data[3]; + TPD_INFO("CID_VER : %X\n", (data[2] << 8 | data[3])); + +} + +void himax_read_OP_FW_ver(struct chip_data_hx83112f *chip_info) +{ + uint8_t cmd[4]; + uint8_t data[4]; + // uint32_t touch_ver = 0; + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x14; + himax_register_read(cmd, 4, data, false); + + chip_info->fw_id = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + TPD_INFO("%s : data[0] = 0x%2.2X, data[1] = 0x%2.2X, data[2] = 0x%2.2X, data[3] = 0x%2.2X\n", + __func__, data[0], data[1], data[2], data[3]); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x84; + himax_register_read(cmd, 4, data, false); + chip_info->touch_ver = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + TPD_INFO("%s :touch_ver = 0x%08X\n", __func__, chip_info->touch_ver); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x00; + himax_register_read(cmd, 4, data, false); + chip_info->fw_ver = data[2] << 8 | data[3]; + TPD_INFO("%s :fw_Ver = 0x%04X\n", __func__, chip_info->fw_ver); + +} + +uint32_t himax_hw_check_CRC(uint8_t *start_addr, int reload_length) +{ + uint32_t result = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + //int cnt = 0; + int length = reload_length / 4; + + //CRC4 // 0x8005_0020 <= from, 0x8005_0028 <= 0x0099_length + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x05; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x20; + //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xFB; tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, start_addr); + + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x05; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; + tmp_data[2] = 0x99; + tmp_data[1] = (length >> 8); + tmp_data[0] = length; + himax_flash_write_burst(tmp_addr, tmp_data); + + //cnt = 0; + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x05; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + //do { + himax_register_read(tmp_addr, 4, tmp_data, false); + + if ((tmp_data[0] & 0x01) != 0x01) { + tmp_addr[3] = 0x80; + tmp_addr[2] = 0x05; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x18; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_DETAIL("%s: tmp_data[3]=%X, tmp_data[2]=%X, tmp_data[1]=%X, tmp_data[0]=%X\n", + __func__, tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]); + result = ((tmp_data[3] << 24) + (tmp_data[2] << 16) + (tmp_data[1] << 8) + tmp_data[0]); + //break; + } + //} while (cnt++ < 100); + TPD_INFO("%s : result = %X\n", __func__, result); + return result; +} + +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max) +{ + int RawDataLen; + + if (raw_cnt_rmd != 0x00) + RawDataLen = 128 - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 1; + else + RawDataLen = 128 - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 1; + + return RawDataLen; +} + + +int himax_report_data_init(int max_touch_point, int tx_num, int rx_num) +{ + if (hx_touch_data->hx_coord_buf != NULL) + kfree(hx_touch_data->hx_coord_buf); + + if (hx_touch_data->diag_mutual != NULL) + kfree(hx_touch_data->diag_mutual); + + //#if defined(HX_SMART_WAKEUP) + hx_touch_data->event_size = 128; + //#endif + + hx_touch_data->touch_all_size = 128; //himax_get_touch_data_size(); + + HX_TOUCH_INFO_POINT_CNT = max_touch_point * 4; + + if ((max_touch_point % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (max_touch_point / 4) * 4; + else + HX_TOUCH_INFO_POINT_CNT += ((max_touch_point / 4) + 1) * 4; + + hx_touch_data->raw_cnt_max = max_touch_point / 4; + hx_touch_data->raw_cnt_rmd = max_touch_point % 4; + + if (hx_touch_data->raw_cnt_rmd != 0x00) {//more than 4 fingers + hx_touch_data->rawdata_size = cal_data_len + (hx_touch_data->raw_cnt_rmd, max_touch_point, hx_touch_data->raw_cnt_max); + hx_touch_data->touch_info_size = (max_touch_point + hx_touch_data->raw_cnt_max + 2) * 4; + } else {//less than 4 fingers + hx_touch_data->rawdata_size = + cal_data_len(hx_touch_data->raw_cnt_rmd, max_touch_point, hx_touch_data->raw_cnt_max); + hx_touch_data->touch_info_size = (max_touch_point + hx_touch_data->raw_cnt_max + 1) * 4; + } + + if ((tx_num * rx_num + tx_num + rx_num) % hx_touch_data->rawdata_size == 0) + hx_touch_data->rawdata_frame_size = (tx_num * rx_num + tx_num + rx_num) / hx_touch_data->rawdata_size; + else + hx_touch_data->rawdata_frame_size = + (tx_num * rx_num + tx_num + rx_num) / hx_touch_data->rawdata_size + 1; + + TPD_INFO("%s: rawdata_frame_size = %d ", __func__, hx_touch_data->rawdata_frame_size); + TPD_INFO("%s: max point:%d, max:%d, raw_cnt_rmd:%d, rawdata_size:%d, touch_info_size:%d\n", + __func__, max_touch_point, hx_touch_data->raw_cnt_max, hx_touch_data->raw_cnt_rmd, + hx_touch_data->rawdata_size, hx_touch_data->touch_info_size); + + hx_touch_data->hx_coord_buf = kzalloc(sizeof(uint8_t) * (hx_touch_data->touch_info_size), GFP_KERNEL); + if (hx_touch_data->hx_coord_buf == NULL) + goto mem_alloc_fail; + + hx_touch_data->diag_mutual = kzalloc(tx_num * rx_num * sizeof(int32_t), GFP_KERNEL); + if (hx_touch_data->diag_mutual == NULL) + goto mem_alloc_fail; + + //#ifdef HX_TP_PROC_DIAG + hx_touch_data->hx_rawdata_buf = kzalloc(sizeof(uint8_t) * + (hx_touch_data->touch_all_size - hx_touch_data->touch_info_size), GFP_KERNEL); + if (hx_touch_data->hx_rawdata_buf == NULL) + goto mem_alloc_fail; + //#endif + + //#if defined(HX_SMART_WAKEUP) + hx_touch_data->hx_event_buf = kzalloc(sizeof(uint8_t) * (hx_touch_data->event_size), GFP_KERNEL); + if (hx_touch_data->hx_event_buf == NULL) + goto mem_alloc_fail; + //#endif + + return NO_ERR; + +mem_alloc_fail: + kfree(hx_touch_data->hx_coord_buf); + //#if defined(HX_TP_PROC_DIAG) + kfree(hx_touch_data->hx_rawdata_buf); + //#endif + //#if defined(HX_SMART_WAKEUP) + kfree(hx_touch_data->hx_event_buf); + //#endif + + TPD_INFO("%s: Memory allocate fail!\n", __func__); + return MEM_ALLOC_FAIL; + +} + +bool himax_read_event_stack(uint8_t *buf, uint8_t length) +{ + uint8_t cmd[4]; + + // AHB_I2C Burst Read Off + cmd[0] = 0x00; + if (himax_bus_write(0x11, 1, cmd) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return 0; + } + + himax_bus_read(0x30, length, buf); + + // AHB_I2C Burst Read On + cmd[0] = 0x01; + if (himax_bus_write(0x11, 1, cmd) < 0) { + TPD_INFO("%s: spi bus access fail!\n", __func__); + return 0; + } + return 1; +} + +int himax_ic_esd_recovery(int hx_esd_event, int hx_zero_event, int length) +{ + if (hx_esd_event == length) { + g_zero_event_count = 0; + goto checksum_fail; + } else if (hx_zero_event == length) { + g_zero_event_count++; + TPD_INFO("[HIMAX TP MSG]: ALL Zero event is %d times.\n", g_zero_event_count); + if (g_zero_event_count > 10) { + g_zero_event_count = 0; + TPD_INFO("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + goto checksum_fail; + } + goto err_workqueue_out; + } + +checksum_fail: + return CHECKSUM_FAIL; +err_workqueue_out: + return WORK_OUT; +} + +int hx83112f_resetgpio_set(struct hw_resource *hw_res, bool on) +{ + int ret = 0; + + if (gpio_is_valid(hw_res->reset_gpio)) { + TPD_DETAIL("Set the reset_gpio on=%d\n", on); + ret = gpio_direction_output(hw_res->reset_gpio, on); + if (ret) + TPD_INFO("Set the reset_gpio on=%d fail\n", on); + else + HX_RESET_STATE = on; + + mdelay(RESET_TO_NORMAL_TIME); + TPD_DETAIL("%s hw_res->reset_gpio = %d\n", __func__, hw_res->reset_gpio); + } + + return ret; +} + + +void himax_esd_hw_reset(struct chip_data_hx83112f *chip_info) +{ + int ret = 0; + int load_fw_times = 10; + + if (!chip_info->first_download_finished) { + TPD_INFO("%s: first download not finished, do not esd reset\n", __func__); + return; + } + TPD_DETAIL("START_Himax TP: ESD - Reset\n"); + HX_ESD_RESET_ACTIVATE = 1; + + hx83112f_enable_interrupt(g_chip_info, false); + + do { + load_fw_times--; + himax_mcu_firmware_update_0f(NULL); + ret = g_core_fp.fp_reload_disable(); + } while (ret && load_fw_times > 0); + + if (!load_fw_times) + TPD_INFO("%s: load_fw_times over 10 times\n", __func__); + + himax_sense_on(0x00); + himax_check_remapping(); + /* need_modify + * report all leave event + * himax_report_all_leave_event(private_ts); + */ + + hx83112f_enable_interrupt(g_chip_info, true); +} + +int himax_checksum_cal(struct chip_data_hx83112f *chip_info, uint8_t *buf, int ts_status) +{ + //#if defined(HX_ESD_RECOVERY) + int hx_EB_event = 0; + int hx_EC_event = 0; + int hx_ED_event = 0; + int hx_esd_event = 0; + int hx_zero_event = 0; + int shaking_ret = 0; + //#endif + uint16_t check_sum_cal = 0; + int32_t loop_i = 0; + int length = 0; + + /* Normal */ + if (ts_status == HX_REPORT_COORD) + length = hx_touch_data->touch_info_size; + else if (ts_status == HX_REPORT_SMWP_EVENT) + length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN); + else + TPD_INFO("%s, Neither Normal Nor SMWP error!\n", __func__); + + //TPD_INFO("Now status=%d,length=%d\n",ts_status,length); + for (loop_i = 0; loop_i < length; loop_i++) { + check_sum_cal += buf[loop_i]; + /* #ifdef HX_ESD_RECOVERY */ + if (ts_status == HX_REPORT_COORD) { + /* case 1 ESD recovery flow */ + if (buf[loop_i] == 0xEB) { + hx_EB_event++; + } else if (buf[loop_i] == 0xEC) { + hx_EC_event++; + } else if (buf[loop_i] == 0xED) { + hx_ED_event++; + } else if (buf[loop_i] == 0x00) {/* case 2 ESD recovery flow-Disable */ + hx_zero_event++; + } else { + hx_EB_event = 0; + hx_EC_event = 0; + hx_ED_event = 0; + hx_zero_event = 0; + g_zero_event_count = 0; + } + + if (hx_EB_event == length) { + hx_esd_event = length; + hx_EB_event_flag++; + TPD_INFO("[HIMAX TP MSG]: ESD event checked - ALL 0xEB.\n"); + } else if (hx_EC_event == length) { + hx_esd_event = length; + hx_EC_event_flag++; + TPD_INFO("[HIMAX TP MSG]: ESD event checked - ALL 0xEC.\n"); + } else if (hx_ED_event == length) { + hx_esd_event = length; + hx_ED_event_flag++; + TPD_INFO("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); + } else { + hx_esd_event = 0; + } + } + /* #endif */ + } + + if (ts_status == HX_REPORT_COORD) { + //#ifdef HX_ESD_RECOVERY + if (hx_esd_event == length || hx_zero_event == length) { + shaking_ret = himax_ic_esd_recovery(hx_esd_event, hx_zero_event, length); + if (shaking_ret == CHECKSUM_FAIL) { + himax_esd_hw_reset(chip_info); + goto checksum_fail; + } else if (shaking_ret == ERR_WORK_OUT) { + goto err_workqueue_out; + } else { + //TPD_INFO("I2C running. Nothing to be done!\n"); + goto workqueue_out; + } + } else if (HX_ESD_RESET_ACTIVATE) { + /* drop 1st interrupts after chip reset */ + HX_ESD_RESET_ACTIVATE = 0; + TPD_INFO("[HX_ESD_RESET_ACTIVATE]:%s: Back from reset, ready to serve.\n", __func__); + goto checksum_fail; + } else if (HX_HW_RESET_ACTIVATE) { + /* drop 1st interrupts after chip reset */ + HX_HW_RESET_ACTIVATE = 0; + TPD_INFO("[HX_HW_RESET_ACTIVATE]:%s: Back from reset, ready to serve.\n", __func__); + goto ready_to_serve; + } + } + //#endif + if ((check_sum_cal % 0x100 != 0)) { + TPD_INFO("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); + //goto checksum_fail; + goto workqueue_out; + } + + /* TPD_INFO("%s:End\n",__func__); */ + return NO_ERR; + +ready_to_serve: + return READY_TO_SERVE; +checksum_fail: + return CHECKSUM_FAIL; + //#ifdef HX_ESD_RECOVERY +err_workqueue_out: + return ERR_WORK_OUT; +workqueue_out: + return WORK_OUT; + //#endif +} + +void himax_log_touch_data(uint8_t *buf, struct himax_report_data *hx_touch_data) +{ + int loop_i = 0; + int print_size = 0; + + if (!hx_touch_data->diag_cmd) + print_size = hx_touch_data->touch_info_size; + else + print_size = hx_touch_data->touch_all_size; + + for (loop_i = 0; loop_i < print_size; loop_i++) { + //if (loop_i % 8 == 0) + //TPD_INFO("KERN_CONT [himax]"); + + TPD_DETAIL(KERN_CONT "0x%02X ", buf[loop_i]); + if ((loop_i + 1) % 8 == 0) + TPD_DETAIL(KERN_CONT "\n"); + + if (loop_i == (print_size - 1)) + TPD_DETAIL("KERN_CONT\n"); + } +} + +void himax_idle_mode(int disable) +{ + int retry = 20; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t switch_cmd = 0x00; + + TPD_INFO("%s:entering\n", __func__); + do { + TPD_INFO("%s,now %d times\n!", __func__, retry); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x70; + tmp_addr[0] = 0x88; + himax_register_read(tmp_addr, 4, tmp_data, false); + + if (disable) + switch_cmd = 0x17; + else + switch_cmd = 0x1F; + + tmp_data[0] = switch_cmd; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s:After turnON/OFF IdleMode [0]=0x%02X,[1]=0x%02X,[2]=0x%02X,[3]=0x%02X\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + retry--; + mdelay(20); + } while ((tmp_data[0] != switch_cmd) && retry > 0); + + TPD_INFO("%s: setting OK!\n", __func__); +} + +int hx_test_data_pop_out(struct chip_data_hx83112f *chip_info, + char *g_Test_list_log, char *g_Company_info_log, + char *g_project_test_info_log, char *rslt_buf, char *filepath) +{ + struct file *raw_file = NULL; + struct filename *vts_name = NULL; + char *line = "=================================================\n"; + char *Company = "Himax for OP: Driver Seneor Test\n"; + char *Info = "Test Info as follow\n"; + char *project_name_log = "OP_"; + mm_segment_t fs; + loff_t pos = 0; + int ret_val = NO_ERR; + + TPD_INFO("%s: Entering!\n", __func__); + TPD_INFO("data size = 0x%04X\n", (uint32_t)strlen(rslt_buf)); + + /*Company Info*/ + snprintf(g_Company_info_log, 160, "%s%s%s%s", line, Company, Info, line); + TPD_DETAIL("%s 000: %s\n", __func__, g_Company_info_log); + + /*project Info*/ + /*Himax_DB_Test Start*/ + snprintf(g_project_test_info_log, 118, + "Project_name: %s%d\nFW_ID: %8X\nFW_Ver: %4X\nPanel Info: TX_Num=%d RX_Num=%d\nTest stage: Mobile\n", + project_name_log, 86260, + chip_info->fw_id, chip_info->fw_ver, chip_info->hw_res->TX_NUM, chip_info->hw_res->RX_NUM); + //snprintf(g_project_test_info_log, 118, + //"Project_name: %s%d\nFW_ID: %8X\nFW_Ver: %4X\nPanel Info: TX_Num=%d RX_Num=%d\nTest stage: Mobile\n", + //project_name_log, 12345, chip_info->fw_id, chip_info->fw_ver, chip_info->hw_res->TX_NUM, + //chip_info->hw_res->RX_NUM);//get_project() = 12345 + /*Himax_DB_Test End*/ + TPD_DETAIL("%s 001: %s\n", __func__, g_project_test_info_log); + + vts_name = getname_kernel(filepath); + //if (IS_ERR(vts_name)) + // return ERR_CAST(vts_name); + if (raw_file == NULL) + raw_file = file_open_name(vts_name, O_TRUNC | O_CREAT | O_RDWR, 0660); + + if (IS_ERR(raw_file)) { + TPD_INFO("%s open file failed = %ld\n", __func__, PTR_ERR(raw_file)); + ret_val = -EIO; + goto SAVE_DATA_ERR; + } + + fs = get_fs(); + set_fs(get_ds()); + vfs_write(raw_file, g_Company_info_log, (int)(strlen(g_Company_info_log)), &pos); + pos = pos + (int)(strlen(g_Company_info_log)); + + vfs_write(raw_file, g_project_test_info_log, (int)(strlen(g_project_test_info_log)), &pos); + pos = pos + (int)(strlen(g_project_test_info_log)); + + vfs_write(raw_file, g_Test_list_log, (int)(strlen(g_Test_list_log)), &pos); + pos = pos + (int)(strlen(g_Test_list_log)); + + vfs_write(raw_file, rslt_buf, g_1kind_raw_size * HX_CRITERIA_ITEM * sizeof(char), &pos); + if (raw_file != NULL) + filp_close(raw_file, NULL); + + set_fs(fs); + +SAVE_DATA_ERR: + TPD_INFO("%s: End!\n", __func__); + return ret_val; +} + + +int hx_test_data_get(struct chip_data_hx83112f *chip_info, uint32_t RAW[], char *start_log, char *result, int now_item) +{ + uint32_t i; + + ssize_t len = 0; + char *testdata = NULL; + uint32_t SZ_SIZE = g_1kind_raw_size; + + TPD_INFO("%s: Entering, Now type=%s!\n", __func__, + g_himax_inspection_mode[now_item]); + + testdata = kzalloc(sizeof(char) * SZ_SIZE, GFP_KERNEL); + if (!testdata) { + TPD_INFO("%s:%d testdata kzalloc buf error\n", __func__, __LINE__); + return -ENOMEM; + } + len += snprintf((testdata + len), SZ_SIZE - len, "%s", start_log); + for (i = 0; i < chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; i++) { + if (i > 1 && ((i + 1) % chip_info->hw_res->RX_NUM) == 0) + len += snprintf((testdata + len), SZ_SIZE - len, "%5d,\n", RAW[i]); + else + len += snprintf((testdata + len), SZ_SIZE - len, + "%5d,", RAW[i]); + } + len += snprintf((testdata + len), SZ_SIZE - len, "\n%s", result); + + memcpy(&g_rslt_data[g_rslt_data_len], testdata, len); + g_rslt_data_len += len; + TPD_INFO("%s: g_rslt_data_len=%d!\n", __func__, g_rslt_data_len); + + kfree(testdata); + TPD_INFO("%s: End!\n", __func__); + return NO_ERR; + +} + + +int himax_get_rawdata(struct chip_data_hx83112f *chip_info, uint32_t *RAW, uint32_t datalen) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t *tmp_rawdata; + uint8_t retry = 0; + uint16_t checksum_cal; + uint32_t i = 0; + + uint8_t max_i2c_size = MAX_RECVS_SZ; + int address = 0; + int total_read_times = 0; + int total_size = datalen * 2 + 4; + int total_size_temp; + + uint32_t j = 0; + uint32_t index = 0; + uint32_t Min_DATA = 0xFFFFFFFF; + uint32_t Max_DATA = 0x00000000; + + //1 Set Data Ready PWD + while (retry < 200) { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = Data_PWD1; + tmp_data[0] = Data_PWD0; + himax_flash_write_burst_length(tmp_addr, tmp_data, 4); + + himax_register_read(tmp_addr, 4, tmp_data, false); + if ((tmp_data[0] == Data_PWD0 && tmp_data[1] == Data_PWD1) || + (tmp_data[0] == Data_PWD1 && tmp_data[1] == Data_PWD0)) { + break; + } + + retry++; + mdelay(20); + } + + if (retry >= 200) + return RESULT_ERR; + + retry = 0; + + while (retry < 200) { + if (tmp_data[0] == Data_PWD1 && tmp_data[1] == Data_PWD0) + break; + + retry++; + mdelay(20); + himax_register_read(tmp_addr, 4, tmp_data, false); + } + + if (retry >= 200) + return RESULT_ERR; + + retry = 0; + + //tmp_rawdata = kzalloc(sizeof(uint8_t)*(datalen*2),GFP_KERNEL); + tmp_rawdata = kzalloc(sizeof(uint8_t) * (total_size + 8), GFP_KERNEL); + if (!tmp_rawdata) + return RESULT_ERR; + + //2 Read Data from SRAM + while (retry < 10) { + checksum_cal = 0; + total_size_temp = total_size; + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + + if (total_size % max_i2c_size == 0) + total_read_times = total_size / max_i2c_size; + else + total_read_times = total_size / max_i2c_size + 1; + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_i2c_size) { + himax_register_read(tmp_addr, max_i2c_size, &tmp_rawdata[i * max_i2c_size], false); + total_size_temp = total_size_temp - max_i2c_size; + } else { + //TPD_INFO("last total_size_temp=%d\n",total_size_temp); + himax_register_read(tmp_addr, total_size_temp % max_i2c_size, + &tmp_rawdata[i * max_i2c_size], false); + } + + address = ((i + 1) * max_i2c_size); + tmp_addr[1] = (uint8_t)((address >> 8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + } + + // + //3 Check Checksum + for (i = 2; i < total_size; i = i + 2) + checksum_cal += tmp_rawdata[i + 1] * 256 + tmp_rawdata[i]; + + if (checksum_cal == 0) + break; + + retry++; + } + if (retry >= 10) { + TPD_INFO("Retry over 10 times: do recovery\n"); + himax_esd_hw_reset(chip_info); + return RESULT_RETRY; + } + + //4 Copy Data + for (i = 0; i < chip_info->hw_res->RX_NUM * chip_info->hw_res->TX_NUM; i++) + RAW[i] = tmp_rawdata[(i * 2) + 1 + 4] * 256 + tmp_rawdata[(i * 2) + 4]; + + for (j = 0; j < chip_info->hw_res->TX_NUM; j++) { + if (j == 0) + TPD_DETAIL(KERN_CONT "[himax] RX%2d", j + 1); + else + TPD_DETAIL(KERN_CONT " RX%2d", j + 1); + + } + TPD_DETAIL(KERN_CONT "\n"); + + for (i = 0; i < chip_info->hw_res->RX_NUM; i++) { + TPD_DETAIL(KERN_CONT "[himax]TX%2d", i + 1); + for (j = 0; j < chip_info->hw_res->TX_NUM; j++) { + //if ((j == SKIPRXNUM) && (i >= SKIPTXNUM_START) && (i <= SKIPTXNUM_END)) { + // continue; + //} else { + index = ((chip_info->hw_res->RX_NUM * chip_info->hw_res->TX_NUM - i) - + chip_info->hw_res->RX_NUM * j) - 1; + + TPD_DETAIL(KERN_CONT "%6d", RAW[index]); + + if (RAW[index] > Max_DATA) + Max_DATA = RAW[index]; + + if (RAW[index] < Min_DATA) + Min_DATA = RAW[index]; + } + //index++; + //TPD_INFO("KERN_CONT\n"); + } + + TPD_INFO("Max = %5d, Min = %5d\n", Max_DATA, Min_DATA); + + kfree(tmp_rawdata); + + return RESULT_OK; +} + +void himax_switch_data_type(uint8_t checktype) +{ + uint8_t datatype = 0x00; + + switch (checktype) { + case HIMAX_INSPECTION_OPEN: + datatype = DATA_OPEN; + break; + case HIMAX_INSPECTION_MICRO_OPEN: + datatype = DATA_MICRO_OPEN; + break; + case HIMAX_INSPECTION_SHORT: + datatype = DATA_SHORT; + break; + case HIMAX_INSPECTION_RAWDATA: + datatype = DATA_RAWDATA; + break; + case HIMAX_INSPECTION_NOISE: + datatype = DATA_NOISE; + break; + case HIMAX_INSPECTION_BACK_NORMAL: + datatype = DATA_BACK_NORMAL; + break; + case HIMAX_INSPECTION_LPWUG_RAWDATA: + datatype = DATA_LPWUG_RAWDATA; + break; + case HIMAX_INSPECTION_LPWUG_NOISE: + datatype = DATA_LPWUG_NOISE; + break; + case HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA: + datatype = DATA_LPWUG_IDLE_RAWDATA; + break; + case HIMAX_INSPECTION_LPWUG_IDLE_NOISE: + datatype = DATA_LPWUG_IDLE_NOISE; + break; + default: + TPD_INFO("Wrong type=%d\n", checktype); + break; + } + himax_diag_register_set(datatype); +} + +int himax_switch_mode(int mode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + TPD_INFO("%s: Entering\n", __func__); + + //Stop Handshaking + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst_length(tmp_addr, tmp_data, 4); + + //Switch Mode + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x04; + switch (mode) { + case HIMAX_INSPECTION_SORTING: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_SORTING_START; + tmp_data[0] = PWD_SORTING_START; + break; + case HIMAX_INSPECTION_OPEN: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_OPEN_START; + tmp_data[0] = PWD_OPEN_START; + break; + case HIMAX_INSPECTION_MICRO_OPEN: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_OPEN_START; + tmp_data[0] = PWD_OPEN_START; + break; + case HIMAX_INSPECTION_SHORT: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_SHORT_START; + tmp_data[0] = PWD_SHORT_START; + break; + case HIMAX_INSPECTION_RAWDATA: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_RAWDATA_START; + tmp_data[0] = PWD_RAWDATA_START; + break; + case HIMAX_INSPECTION_NOISE: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_NOISE_START; + tmp_data[0] = PWD_NOISE_START; + break; + case HIMAX_INSPECTION_LPWUG_RAWDATA: + case HIMAX_INSPECTION_LPWUG_NOISE: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_LPWUG_START; + tmp_data[0] = PWD_LPWUG_START; + break; + case HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA: + case HIMAX_INSPECTION_LPWUG_IDLE_NOISE: + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = PWD_LPWUG_IDLE_START; + tmp_data[0] = PWD_LPWUG_IDLE_START; + break; + } + himax_flash_write_burst_length(tmp_addr, tmp_data, 4); + + TPD_INFO("%s: End of setting!\n", __func__); + + return 0; + +} + + +void himax_set_N_frame(uint16_t Nframe, uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0x94; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)((Nframe & 0xFF00) >> 8); + tmp_data[0] = (uint8_t)(Nframe & 0x00FF); + himax_flash_write_burst_length(tmp_addr, tmp_data, 4); + + //SKIP FRMAE + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x70; + tmp_addr[0] = 0xF4; + himax_register_read(tmp_addr, 4, tmp_data, false); + + switch (checktype) { + case HIMAX_INSPECTION_LPWUG_RAWDATA: + case HIMAX_INSPECTION_LPWUG_NOISE: + tmp_data[0] = BS_LPWUG; + break; + case HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA: + case HIMAX_INSPECTION_LPWUG_IDLE_NOISE: + tmp_data[0] = BS_LPWUG_dile; + break; + case HIMAX_INSPECTION_RAWDATA: + case HIMAX_INSPECTION_NOISE: + tmp_data[0] = BS_RAWDATANOISE; + break; + default: + tmp_data[0] = BS_OPENSHORT; + break; + } + himax_flash_write_burst_length(tmp_addr, tmp_data, 4); +} + + +uint32_t himax_check_mode(uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t wait_pwd[2]; + // uint8_t count = 0; + + wait_pwd[0] = PWD_NONE; + wait_pwd[1] = PWD_NONE; + + switch (checktype) { + case HIMAX_INSPECTION_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HIMAX_INSPECTION_MICRO_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HIMAX_INSPECTION_SHORT: + wait_pwd[0] = PWD_SHORT_END; + wait_pwd[1] = PWD_SHORT_END; + break; + case HIMAX_INSPECTION_RAWDATA: + wait_pwd[0] = PWD_RAWDATA_END; + wait_pwd[1] = PWD_RAWDATA_END; + break; + case HIMAX_INSPECTION_NOISE: + wait_pwd[0] = PWD_NOISE_END; + wait_pwd[1] = PWD_NOISE_END; + break; + case HIMAX_INSPECTION_LPWUG_RAWDATA: + case HIMAX_INSPECTION_LPWUG_NOISE: + wait_pwd[0] = PWD_LPWUG_END; + wait_pwd[1] = PWD_LPWUG_END; + break; + case HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA: + case HIMAX_INSPECTION_LPWUG_IDLE_NOISE: + wait_pwd[0] = PWD_LPWUG_IDLE_END; + wait_pwd[1] = PWD_LPWUG_IDLE_END; + break; + default: + TPD_INFO("Wrong type=%d\n", checktype); + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x04; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: himax_wait_sorting_mode, tmp_data[0]=%x, tmp_data[1]=%x\n", __func__, tmp_data[0], tmp_data[1]); + + if (wait_pwd[0] == tmp_data[0] && wait_pwd[1] == tmp_data[1]) { + TPD_INFO("Change to mode=%s\n", g_himax_inspection_mode[checktype]); + return 0; + } else + return 1; +} + +void himax_get_noise_base(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t ratio, threshold, threshold_LPWUG; + + /* tmp_addr[3] = 0x10; + * tmp_addr[2] = 0x00; + * tmp_addr[1] = 0x70; + * tmp_addr[0] = 0x8C; + */ + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x70; + tmp_addr[0] = 0x94; /*ratio*/ + himax_register_read(tmp_addr, 4, tmp_data, false); + ratio = tmp_data[1]; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x70; + tmp_addr[0] = 0xA0; /*threshold_LPWUG*/ + himax_register_read(tmp_addr, 4, tmp_data, false); + threshold_LPWUG = tmp_data[0]; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x70; + tmp_addr[0] = 0x9C; /*threshold*/ + himax_register_read(tmp_addr, 4, tmp_data, false); + threshold = tmp_data[0]; + + /*TPD_INFO("tmp_data[0]=0x%x tmp_data[1]=0x%x tmp_data[2]=0x%x tmp_data[3]=0x%x\n", + * tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + */ + /*NOISEMAX = tmp_data[3]*(NOISE_P/256);*/ + NOISEMAX = ratio * threshold; + LPWUG_NOISEMAX = ratio * threshold_LPWUG; + TPD_INFO("NOISEMAX=%d LPWUG_NOISE_MAX=%d\n", NOISEMAX, LPWUG_NOISEMAX); +} + +uint16_t himax_get_noise_weight(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint16_t weight; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0xC8; + himax_register_read(tmp_addr, 4, tmp_data, false); + weight = (tmp_data[1] << 8) | tmp_data[0]; + TPD_INFO("%s: weight = %d ", __func__, weight); + + return weight; +} + +uint32_t himax_wait_sorting_mode(uint8_t checktype) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t wait_pwd[2]; + uint8_t count = 0; + + wait_pwd[0] = PWD_NONE; + wait_pwd[1] = PWD_NONE; + + switch (checktype) { + case HIMAX_INSPECTION_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HIMAX_INSPECTION_MICRO_OPEN: + wait_pwd[0] = PWD_OPEN_END; + wait_pwd[1] = PWD_OPEN_END; + break; + case HIMAX_INSPECTION_SHORT: + wait_pwd[0] = PWD_SHORT_END; + wait_pwd[1] = PWD_SHORT_END; + break; + case HIMAX_INSPECTION_RAWDATA: + wait_pwd[0] = PWD_RAWDATA_END; + wait_pwd[1] = PWD_RAWDATA_END; + break; + case HIMAX_INSPECTION_NOISE: + wait_pwd[0] = PWD_NOISE_END; + wait_pwd[1] = PWD_NOISE_END; + break; + case HIMAX_INSPECTION_LPWUG_RAWDATA: + case HIMAX_INSPECTION_LPWUG_NOISE: + wait_pwd[0] = PWD_LPWUG_END; + wait_pwd[1] = PWD_LPWUG_END; + break; + case HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA: + case HIMAX_INSPECTION_LPWUG_IDLE_NOISE: + wait_pwd[0] = PWD_LPWUG_IDLE_END; + wait_pwd[1] = PWD_LPWUG_IDLE_END; + break; + default: + TPD_INFO("Wrong type=%d\n", checktype); + break; + } + + do { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x04; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: tmp_data[0]=%x, tmp_data[1]=%x\n", __func__, tmp_data[0], tmp_data[1]); + + if (wait_pwd[0] == tmp_data[0] && wait_pwd[1] == tmp_data[1]) + return 0; + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 0x900000A8, tmp_data[0]=%x, tmp_data[1]=%x, tmp_data[2]=%x, tmp_data[3]=%x\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xE4; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 0x900000E4, tmp_data[0]=%x, tmp_data[1]=%x, tmp_data[2]=%x, tmp_data[3]=%x\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xF8; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 0x900000F8, tmp_data[0]=%x, tmp_data[1]=%x, tmp_data[2]=%x, tmp_data[3]=%x\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + TPD_INFO("Now retry %d times!\n", count++); + mdelay(50); + } while (count < 50); + + return 1; +} + +int mpTestFunc(struct chip_data_hx83112f *chip_info, uint8_t checktype, uint32_t datalen) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + + uint32_t i/*, j*/ = 0; + uint16_t weight = 0; + uint32_t *RAW = NULL; +#ifdef RAWDATA_NOISE + uint32_t RAW_Rawdata[datalen]; +#endif + char *rslt_log = NULL; + char *start_log = NULL; + int ret = 0; + int CRITERIA_RAWDATA_MIN = RAWMIN; + int CRITERIA_RAWDATA_MAX = RAWMAX; + int CRITERIA_LPWUG_RAWDATA_MAX = LPWUG_RAWDATA_MAX; + int CRITERIA_LPWUG_IDLE_RAWDATA_MAX = LPWUG_IDLE_RAWDATA_MAX; + + RAW = kcalloc(datalen, sizeof(uint32_t), GFP_KERNEL); + if (RAW == NULL) + return -EINVAL; + + if (himax_check_mode(checktype)) { + TPD_INFO("Need Change Mode, target=%s", g_himax_inspection_mode[checktype]); + + himax_sense_off(); + + himax_switch_mode(checktype); + + if (checktype == HIMAX_INSPECTION_NOISE) { + himax_set_N_frame(NOISEFRAME, checktype); + /*himax_get_noise_base();*/ + } else if (checktype >= HIMAX_INSPECTION_LPWUG_RAWDATA) { + TPD_INFO("N frame = %d\n", 1); + himax_set_N_frame(1, checktype); + } else { + himax_set_N_frame(2, checktype); + } + + + himax_sense_on(1); + + ret = himax_wait_sorting_mode(checktype); + if (ret) { + TPD_INFO("%s: himax_wait_sorting_mode FAIL\n", __func__); + + kfree(RAW); + RAW = NULL; + + return ret; + } + } + + himax_switch_data_type(checktype); + + ret = himax_get_rawdata(chip_info, RAW, datalen); + if (ret) { + TPD_INFO("%s: himax_get_rawdata FAIL\n", __func__); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0xA8; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 900000A8: data[0]=%0x02X, data[1]=%0x02X, data[2]=%0x02X, data[3]=%0x02X,\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x40; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 10007F40: data[0]=%0x02X, data[1]=%0x02X, data[2]=%0x02X, data[3]=%0x02X,\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 10000000: data[0]=%0x02X, data[1]=%0x02X, data[2]=%0x02X, data[3]=%0x02X,\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x04; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 10007F04: data[0]=%0x02X, data[1]=%0x02X, data[2]=%0x02X, data[3]=%0x02X,\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + //tmp_addr[3] = 0x80; + //tmp_addr[2] = 0x02; + //tmp_addr[1] = 0x04; + //tmp_addr[0] = 0xB4; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x72; + tmp_addr[0] = 0xEC; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: 800204B4: data[0]=%0x02X, data[1]=%0x02X, data[2]=%0x02X, data[3]=%0x02X,\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + //900000A8,10007F40,10000000,10007F04,800204B4 + + kfree(RAW); + RAW = NULL; + + return ret; + } + + /* back to normal */ + himax_switch_data_type(HIMAX_INSPECTION_BACK_NORMAL); + + rslt_log = kzalloc(256 * sizeof(char), GFP_KERNEL); + if (!rslt_log) { + TPD_INFO("%s:%d rslt_log kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + start_log = kzalloc(256 * sizeof(char), GFP_KERNEL); + if (!start_log) { + TPD_INFO("%s:%d start_log kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + + snprintf(start_log, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], ": data as follow!\n"); + //Check Data + switch (checktype) { + case HIMAX_INSPECTION_OPEN: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > OPENMAX || RAW[i] < OPENMIN) { + TPD_INFO("%s: open test FAIL\n", __func__); + ret = RESULT_ERR; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_OPENMAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_OPENMIN][i]) { + TPD_INFO("%s: open test FAIL\n", __func__); + ret = RESULT_ERR; + } + } + } + if (ret != RESULT_ERR) + TPD_INFO("%s: open test PASS\n", __func__); + break; + + case HIMAX_INSPECTION_MICRO_OPEN: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > M_OPENMAX || RAW[i] < M_OPENMIN) { + TPD_INFO("%s: micro open test FAIL\n", __func__); + ret = RESULT_ERR; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_M_OPENMAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_M_OPENMIN][i]) { + TPD_INFO("%s: micro open test FAIL\n", __func__); + ret = RESULT_ERR; + } + } + } + TPD_INFO("M_OPENMAX = %d, M_OPENMIN = %d\n", + hx83112f_nf_inspection_criteria[IDX_M_OPENMAX][1], + hx83112f_nf_inspection_criteria[IDX_M_OPENMIN][1]); + if (ret != RESULT_ERR) + TPD_INFO("%s: micro open test PASS\n", __func__); + break; + + case HIMAX_INSPECTION_SHORT: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > SHORTMAX || RAW[i] < SHORTMIN) { + TPD_INFO("%s: short test FAIL\n", __func__); + ret = RESULT_ERR; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_SHORTMAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_SHORTMIN][i]) { + TPD_INFO("%s: short test FAIL\n", __func__); + ret = RESULT_ERR; + } + } + } + if (ret != RESULT_ERR) + TPD_INFO("%s: short test PASS\n", __func__); + break; + + case HIMAX_INSPECTION_RAWDATA: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > CRITERIA_RAWDATA_MAX || RAW[i] < CRITERIA_RAWDATA_MIN) { + TPD_INFO("%s: rawdata test FAIL\n", __func__); + ret = RESULT_ERR; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_RAWDATA_MAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_RAWDATA_MIN][i]) { + TPD_INFO("%s: rawdata test FAIL\n", __func__); + ret = RESULT_ERR; + } + } + } + if (ret != RESULT_ERR) + TPD_INFO("%s: rawdata test PASS\n", __func__); + break; + + case HIMAX_INSPECTION_NOISE: + himax_get_noise_base(); + + snprintf(start_log, 256 * sizeof(char), "\n Threshold = %d\n", NOISEMAX); + weight = himax_get_noise_weight(); + if (weight > NOISEMAX) { + TPD_INFO("%s: noise test FAIL\n", __func__); + ret = RESULT_ERR; + } + if (ret != RESULT_ERR) + TPD_INFO("%s: noise test PASS\n", __func__); + +#ifdef RAWDATA_NOISE + TPD_INFO("[MP_RAW_TEST_RAW]\n"); + + himax_switch_data_type(HIMAX_INSPECTION_RAWDATA); + ret = himax_get_rawdata(chip_info, RAW, datalen); + if (ret == RESULT_ERR) { + TPD_INFO("%s: himax_get_rawdata FAIL\n", __func__); + ret = RESULT_ERR; + } +#endif + break; + + case HIMAX_INSPECTION_LPWUG_RAWDATA: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > CRITERIA_LPWUG_RAWDATA_MAX || RAW[i] < LPWUG_RAWDATA_MIN) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_RAWDATA FAIL\n", __func__); + ret = THP_AFE_INSPECT_ERAW; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_LPWUG_RAWDATA_MAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_LPWUG_RAWDATA_MIN][i]) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_RAWDATA FAIL\n", __func__); + ret = THP_AFE_INSPECT_ERAW; + } + } + } + if (ret != THP_AFE_INSPECT_ERAW) + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_RAWDATA PASS\n", __func__); + break; + case HIMAX_INSPECTION_LPWUG_NOISE: + himax_get_noise_base(); + weight = himax_get_noise_weight(); + if (isRead_csv == false) { + if (weight > LPWUG_NOISEMAX || weight < LPWUG_NOISE_MIN) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_NOISE FAIL\n", __func__); + ret = THP_AFE_INSPECT_ENOISE; + } + } else { + if (weight > LPWUG_NOISEMAX || + weight < hx83112f_nf_inspection_criteria[IDX_LPWUG_NOISE_MIN][i]) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_NOISE FAIL\n", __func__); + ret = THP_AFE_INSPECT_ENOISE; + } + } + if (ret != THP_AFE_INSPECT_ENOISE) + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_NOISE PASS\n", __func__); + break; + + case HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > CRITERIA_LPWUG_IDLE_RAWDATA_MAX || RAW[i] < LPWUG_IDLE_RAWDATA_MIN) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA FAIL\n", __func__); + ret = THP_AFE_INSPECT_ERAW; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_LPWUG_IDLE_RAWDATA_MAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_LPWUG_IDLE_RAWDATA_MIN][i]) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA FAIL\n", __func__); + ret = THP_AFE_INSPECT_ERAW; + } + } + } + if (ret != THP_AFE_INSPECT_ERAW) + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA PASS\n", __func__); + break; + case HIMAX_INSPECTION_LPWUG_IDLE_NOISE: + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (isRead_csv == false) { + if (RAW[i] > LPWUG_IDLE_NOISE_MAX || RAW[i] < LPWUG_IDLE_NOISE_MIN) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_IDLE_NOISE FAIL\n", __func__); + ret = THP_AFE_INSPECT_ENOISE; + } + } else { + if (RAW[i] > hx83112f_nf_inspection_criteria[IDX_LPWUG_IDLE_NOISE_MAX][i] || + RAW[i] < hx83112f_nf_inspection_criteria[IDX_LPWUG_IDLE_NOISE_MIN][i]) { + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_IDLE_NOISE FAIL\n", __func__); + ret = THP_AFE_INSPECT_ENOISE; + } + } + } + if (ret != THP_AFE_INSPECT_ENOISE) + TPD_INFO("%s: HIMAX_INSPECTION_LPWUG_IDLE_NOISE PASS\n", __func__); + break; + + default: + TPD_INFO("Wrong type=%d\n", checktype); + break; + } + + snprintf(rslt_log, 256 * sizeof(char), "\n%s%s\n", + g_himax_inspection_mode[checktype], " Test Pass!\n"); + + hx_test_data_get(chip_info, RAW, start_log, rslt_log, checktype); + + kfree(rslt_log); + + kfree(start_log); + + kfree(RAW); + RAW = NULL; + + if (ret) + return ret; + else + return RESULT_OK; + +RET_OUT: + + kfree(rslt_log); + + kfree(start_log); + + kfree(RAW); + RAW = NULL; + + return RESULT_ERR; +} + +static int himax_saperate_comma(const struct firmware *file_entry, + char **result, int str_size) +{ + int count = 0; + int str_count = 0; /* now string*/ + int char_count = 0; /* now char count in string*/ + + do { + switch (file_entry->data[count]) { + case ASCII_COMMA: + case ACSII_SPACE: + case ASCII_CR: + case ASCII_LF: + count++; + /* If end of line as above condifiton, + * differencing the count of char. + * If char_count != 0 + * it's meaning this string is parsing over . + * The Next char is belong to next string + */ + if (char_count != 0) { + char_count = 0; + str_count++; + } + break; + default: + result[str_count][char_count++] = + file_entry->data[count]; + count++; + break; + } + } while (count < file_entry->size && str_count < str_size); + + return str_count; +} + +static int hx_diff_str(char *str1, char *str2) +{ + int i = 0; + int result = 0; /* zero is all same, non-zero is not same index*/ + int str1_len = strlen(str1); + int str2_len = strlen(str2); + + if (str1_len != str2_len) { + TPD_DEBUG("%s:Size different!\n", __func__); + return LENGTH_FAIL; + } + + for (i = 0; i < str1_len; i++) { + if (str1[i] != str2[i]) { + result = i + 1; + TPD_INFO("%s: different in %d!\n", __func__, result); + return result; + } + } + + return result; +} + +/* get idx of criteria where parsing file */ +int hx_find_crtra_id(char *input) +{ + int i = 0; + int result = 0; + + for (i = 0 ; i < HX_CRITERIA_SIZE ; i++) { + if (hx_diff_str(g_hx_inspt_crtra_name[i], input) == 0) { + result = i; + TPD_INFO("find the str=%s, idx=%d\n", + g_hx_inspt_crtra_name[i], i); + break; + } + } + if (i > (HX_CRITERIA_SIZE - 1)) { + TPD_INFO("%s: find Fail!\n", __func__); + return LENGTH_FAIL; + } + + return result; +} + +/* claculate 10's power function */ +static int himax_power_cal(int pow, int number) +{ + int i = 0; + int result = 1; + + for (i = 0; i < pow; i++) + result *= 10; + result = result * number; + + return result; + +} + +/* String to int */ +static int hiamx_parse_str2int(char *str) +{ + int i = 0; + int temp_cal = 0; + int result = 0; + int str_len = strlen(str); + int negtive_flag = 0; + + for (i = 0; i < strlen(str); i++) { + if (str[i] != '-' && str[i] > '9' && str[i] < '0') { + TPD_INFO("%s: Parsing fail!\n", __func__); + result = -9487; + negtive_flag = 0; + break; + } + if (str[i] == '-') { + negtive_flag = 1; + continue; + } + temp_cal = str[i] - '0'; + result += himax_power_cal(str_len - i - 1, temp_cal); + /* str's the lowest char is the number's the highest number + * So we should reverse this number before using the power + * function + * -1: starting number is from 0 ex:10^0 = 1, 10^1 = 10 + */ + } + + if (negtive_flag == 1) + result = 0 - result; + + return result; +} + +int hx_print_crtra_after_parsing(struct chip_data_hx83112f *chip_info) +{ + int i = 0, j = 0; + int all_mut_len = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + TPD_DETAIL("Now is %s\n", g_hx_inspt_crtra_name[i]); + if (hx83112f_nf_inspt_crtra_flag[i] == 1) { + for (j = 0; j < all_mut_len; j++) { + TPD_DETAIL(KERN_CONT "%d, ", hx83112f_nf_inspection_criteria[i][j]); + if (j % 16 == 15) + TPD_DETAIL(KERN_CONT "\n"); + } + } else { + TPD_DETAIL(KERN_CONT "No this Item in this criteria file!\n"); + } + TPD_DETAIL(KERN_CONT "\n"); + } + + return 0; +} + +static int hx_get_crtra_by_name(struct chip_data_hx83112f *chip_info, char **result, int size_of_result_str) +{ + int i = 0; + /* count of criteria type */ + int count_type = 0; + /* count of criteria data */ + int count_data = 0; + int err = THP_AFE_INSPECT_OK; + int all_mut_len = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; + int temp = 0; + + /* get criteria and assign to a global array(2-Dimensional/int) */ + /* basiclly the size of criteria will be + * (crtra_count * (all_mut_len) + crtra_count) + * but we use file size to be the end of counter + */ + for (i = 0; i < size_of_result_str && result[i] != NULL; i++) { + /* It have get one page(all mutual) criteria data! + * And we should skip the string of criteria name! + */ + if (i == 0 || i == ((i / (all_mut_len)) + (i / (all_mut_len) * (all_mut_len)))) { + count_data = 0; + + TPD_DEBUG("Now find str=%s, idx=%d\n", result[i], i); + + /* check the item of criteria is in criteria file + * or not + */ + count_type = hx_find_crtra_id(result[i]); + if (count_type < 0) { + TPD_INFO("1. %s:Name Not match!\n", __func__); + /* E("can recognize[%d]=%s\n", count_type, + * g_hx_inspt_crtra_name[count_type]); + */ + TPD_INFO("get from file[%d]=%s\n", i, result[i]); + TPD_INFO("Please check criteria file again!\n"); + err = THP_AFE_INSPECT_EFILE; + goto END_FUNCTION; + } else { + TPD_INFO("Now str=%s, idx=%d\n", + g_hx_inspt_crtra_name[count_type], count_type); + hx83112f_nf_inspt_crtra_flag[count_type] = 1; + } + continue; + } + /* change string to int*/ + temp = hiamx_parse_str2int(result[i]); + if (temp != -9487) { + hx83112f_nf_inspection_criteria[count_type][count_data] = temp; + } else { + TPD_INFO("%s: Parsing Fail in %d\n", __func__, i); + TPD_INFO("in range:[%d]=%s\n", count_type, + g_hx_inspt_crtra_name[count_type]); + TPD_INFO("btw, get from file[%d]=%s\n", i, result[i]); + break; + } + /* dbg + * I("[%d]hx83112f_nf_inspection_criteria[%d][%d]=%d\n", + * i, count_type, count_data, + * hx83112f_nf_inspection_criteria[count_type][count_data]); + */ + count_data++; + + } + + /* dbg:print all of criteria from parsing file */ + hx_print_crtra_after_parsing(chip_info); + + TPD_INFO("Total loop=%d\n", i); +END_FUNCTION: + return err; +} + + +/* Get sub-string from original string by using some characters + * return size of result + */ + +int hx_get_size_str_arr(char **input) +{ + int i = 0; + int result = 0; + + while (input[i] != NULL) + i++; + + result = i; + TPD_DEBUG("There is %d in [0]=%s\n", result, input[0]); + + return result; +} +static void himax_limit_get(struct touchpanel_data *ts, struct hx_limit_data *limit) +{ + int err = THP_AFE_INSPECT_OK; + const struct firmware *file_entry = NULL; + //char *file_name = "hx_criteria.csv"; + static char **result; + int i = 0; + int j = 0; + int crtra_count; + int data_size = 0; /* The maximum of number Data*/ + int all_mut_len = g_chip_info->hw_res->TX_NUM * g_chip_info->hw_res->RX_NUM; + int str_max_len = 0; + int result_all_len = 0; + int file_size = 0; + int size_of_result_str = 0; + + TPD_INFO("%s, Entering\n", __func__); + + HX_CRITERIA_ITEM = hx_get_size_str_arr(g_himax_inspection_mode); + HX_CRITERIA_SIZE = hx_get_size_str_arr(g_hx_inspt_crtra_name); + TPD_INFO("%s:There is %d HX_CRITERIA_ITEM and %d HX_CRITERIA_SIZE\n", + __func__, HX_CRITERIA_ITEM, HX_CRITERIA_SIZE); + crtra_count = HX_CRITERIA_SIZE; + /* init criteria data*/ + if (!hx83112f_nf_inspt_crtra_flag) + hx83112f_nf_inspt_crtra_flag = kzalloc(HX_CRITERIA_SIZE * sizeof(int), GFP_KERNEL); + if (!hx83112f_nf_inspection_criteria) + hx83112f_nf_inspection_criteria = kzalloc(sizeof(int *)*HX_CRITERIA_SIZE, GFP_KERNEL); + if (hx83112f_nf_inspt_crtra_flag == NULL || hx83112f_nf_inspection_criteria == NULL) { + TPD_INFO("%s: %d, Memory allocation failed!\n", __func__, __LINE__); + goto FAIL_ALLOC_MEM; + } + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (!hx83112f_nf_inspection_criteria[i]) { + hx83112f_nf_inspection_criteria[i] = kcalloc( + (g_chip_info->hw_res->TX_NUM * g_chip_info->hw_res->RX_NUM), + sizeof(int), GFP_KERNEL); + } + if (hx83112f_nf_inspection_criteria[i] == NULL) { + TPD_INFO("%s: %d, Memory allocation failed!\n", __func__, __LINE__); + goto FAIL_ALLOC_MEM; + } + } + + /* get file */ + TPD_INFO("file name = %s\n", g_chip_info->test_limit_name); + /* default path is /system/etc/firmware */ + err = request_firmware(&file_entry, g_chip_info->test_limit_name, private_ts->dev); + if (err < 0) { + TPD_INFO("%s, fail in line%d error code=%d\n", __func__, __LINE__, err); + err = THP_AFE_INSPECT_EFILE; + isRead_csv = false; + goto END_FUNC_REQ_FAIL; + } + + limit->item_size = crtra_count; + limit->rawdata_size = all_mut_len; + + limit->item_name = kcalloc(limit->item_size, sizeof(char *), GFP_KERNEL); + for (i = 0; i < limit->item_size; i++) { + if (g_hx_inspt_crtra_name[i] != NULL) { + limit->item_name[i] = kcalloc(strlen(g_hx_inspt_crtra_name[i]), sizeof(char), GFP_KERNEL); + memcpy(limit->item_name[i], g_hx_inspt_crtra_name[i], + sizeof(char) * strlen(g_hx_inspt_crtra_name[i])); + } + } + limit->crtra_val = kzalloc(sizeof(int *) * limit->item_size, GFP_KERNEL); + for (i = 0; i < limit->item_size; i++) + limit->crtra_val[i] = kcalloc(limit->rawdata_size, sizeof(int), GFP_KERNEL); + + /* size of criteria include name string */ + data_size = ((all_mut_len) * crtra_count) + crtra_count; + + /* init the array which store original criteria and include + * name string + */ + while (g_hx_inspt_crtra_name[j] != NULL) { + if (strlen(g_hx_inspt_crtra_name[j]) > str_max_len) + str_max_len = strlen(g_hx_inspt_crtra_name[j]); + j++; + } + + if (result == NULL) { + TPD_INFO("%s: result is NULL, alloc memory.\n", __func__); + result = kcalloc(data_size, sizeof(char *), GFP_KERNEL); + if (result != NULL) { + for (i = 0 ; i < data_size; i++) { + result[i] = kcalloc(str_max_len, sizeof(char), GFP_KERNEL); + if (result[i] == NULL) { + TPD_INFO("%s: rst_arr Memory allocation failed!\n", __func__); + goto rst_arr_mem_alloc_failed; + } + } + } else { + TPD_INFO("%s: Memory allocation failed!\n", __func__); + goto rst_mem_alloc_failed; + } + } else { + //memset(result, 0x00, data_size * sizeof(char)); + for (i = 0 ; i < data_size; i++) + memset(result[i], 0x00, str_max_len * sizeof(char)); + } + + + result_all_len = data_size; + file_size = file_entry->size; + TPD_INFO("Now result_all_len=%d\n", result_all_len); + TPD_INFO("Now file_size=%d\n", file_size); + + /* dbg */ + TPD_DEBUG("first 4 bytes 0x%2X, 0x%2X, 0x%2X, 0x%2X !\n", + file_entry->data[0], file_entry->data[1], + file_entry->data[2], file_entry->data[3]); + + /* parse value in to result array(1-Dimensional/String) */ + size_of_result_str = + himax_saperate_comma(file_entry, result, data_size); + + TPD_INFO("%s: now size_of_result_str=%d\n", __func__, size_of_result_str); + + err = hx_get_crtra_by_name(g_chip_info, result, size_of_result_str); + if (err != THP_AFE_INSPECT_OK) { + TPD_INFO("%s:Load criteria from file fail, go end!\n", __func__); + } else { + if (hx83112f_nf_inspection_criteria != NULL) { + for (i = 0; i < limit->item_size; i++) { + for (j = 0; j < limit->rawdata_size; j++) { + //if(hx83112f_nf_inspection_criteria[i][j] != NULL) + limit->crtra_val[i][j] = hx83112f_nf_inspection_criteria[i][j]; + // else { + // TPD_INFO("%s:data wrong[%d][%d]!\n", __func__, i, j); + // } + } + } + } + } + + goto END_FUNC; +FAIL_ALLOC_MEM: + if (hx83112f_nf_inspt_crtra_flag != NULL) + kfree(hx83112f_nf_inspt_crtra_flag); + if (hx83112f_nf_inspection_criteria != NULL) { + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (hx83112f_nf_inspection_criteria[i] != NULL) + kfree(hx83112f_nf_inspection_criteria[i]); + + kfree(hx83112f_nf_inspection_criteria); + } + } +rst_arr_mem_alloc_failed: + for (i = 0 ; i < data_size; i++) + kfree(result[i]); + + kfree(result); +rst_mem_alloc_failed: +END_FUNC: + release_firmware(file_entry); +END_FUNC_REQ_FAIL: + TPD_INFO("%s, END\n", __func__); +} + +static char **result; +static int himax_parse_criteria_file(struct chip_data_hx83112f *chip_info) +{ + int err = THP_AFE_INSPECT_OK; + const struct firmware *file_entry = NULL; + int i = 0; + int j = 0; + int crtra_count = HX_CRITERIA_SIZE; + int data_size = 0; /* The maximum of number Data*/ + int all_mut_len = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; + int str_max_len = 0; + int result_all_len = 0; + int file_size = 0; + int size_of_result_str = 0; + + TPD_INFO("%s, Entering\n", __func__); + TPD_INFO("file name = %s\n", chip_info->test_limit_name); + + /* default path is /system/etc/firmware */ + err = request_firmware(&file_entry, chip_info->test_limit_name, private_ts->dev); + if (err < 0) { + TPD_INFO("%s, fail in line%d error code=%d\n", __func__, __LINE__, err); + err = THP_AFE_INSPECT_EFILE; + isRead_csv = false; + goto END_FUNC_REQ_FAIL; + } + + /* size of criteria include name string */ + data_size = ((all_mut_len) * crtra_count) + crtra_count; + + /* init the array which store original criteria and include + * name string + */ + while (g_hx_inspt_crtra_name[j] != NULL) { + if (strlen(g_hx_inspt_crtra_name[j]) > str_max_len) + str_max_len = strlen(g_hx_inspt_crtra_name[j]); + j++; + } + + if (result == NULL) { + TPD_INFO("%s: result is NULL, alloc memory.\n", __func__); + result = kcalloc(data_size, sizeof(char *), GFP_KERNEL); + if (result != NULL) { + for (i = 0 ; i < data_size; i++) { + result[i] = kcalloc(str_max_len, sizeof(char), GFP_KERNEL); + if (result[i] == NULL) { + TPD_INFO("%s: rst_arr Memory allocation failed!\n", __func__); + goto rst_arr_mem_alloc_failed; + } + } + } else { + mdelay(3); + TPD_INFO("%s: result is NULL, alloc memory the second time.\n", __func__); + result = kcalloc(data_size, sizeof(char *), GFP_KERNEL); + if (result != NULL) { + for (i = 0 ; i < data_size; i++) { + result[i] = kcalloc(str_max_len, sizeof(char), GFP_KERNEL); + if (result[i] == NULL) { + TPD_INFO("%s: rst_arr Memory allocation failed!\n", __func__); + goto rst_arr_mem_alloc_failed; + } + } + } else { + TPD_INFO("%s: Memory allocation failed!\n", __func__); + goto rst_mem_alloc_failed; + } + } + } else { + TPD_INFO("%s: result is not the first, no need alloc memory.\n", __func__); + for (i = 0 ; i < data_size; i++) + memset(result[i], 0x00, str_max_len * sizeof(char)); + } + + result_all_len = data_size; + file_size = file_entry->size; + TPD_INFO("Now result_all_len=%d\n", result_all_len); + TPD_INFO("Now file_size=%d\n", file_size); + + /* dbg */ + TPD_DEBUG("first 4 bytes 0x%2X, 0x%2X, 0x%2X, 0x%2X !\n", + file_entry->data[0], file_entry->data[1], + file_entry->data[2], file_entry->data[3]); + + /* parse value in to result array(1-Dimensional/String) */ + size_of_result_str = + himax_saperate_comma(file_entry, result, data_size); + + TPD_INFO("%s: now size_of_result_str=%d\n", __func__, size_of_result_str); + + err = hx_get_crtra_by_name(chip_info, result, size_of_result_str); + if (err != THP_AFE_INSPECT_OK) + TPD_INFO("%s:Load criteria from file fail, go end!\n", __func__); + + goto END_FUNC; + +rst_arr_mem_alloc_failed: + for (i = 0 ; i < data_size; i++) + kfree(result[i]); + + kfree(result); +rst_mem_alloc_failed: +END_FUNC: + release_firmware(file_entry); +END_FUNC_REQ_FAIL: + TPD_INFO("%s, END\n", __func__); + return err; + /* parsing Criteria end */ +} + + +static int himax_self_test_data_init(struct chip_data_hx83112f *chip_info) +{ + int ret = THP_AFE_INSPECT_OK; + int i = 0; + + /* get test item and its items of criteria*/ + HX_CRITERIA_ITEM = hx_get_size_str_arr(g_himax_inspection_mode); + HX_CRITERIA_SIZE = hx_get_size_str_arr(g_hx_inspt_crtra_name); + TPD_INFO("There is %d HX_CRITERIA_ITEM and %d HX_CRITERIA_SIZE\n", + HX_CRITERIA_ITEM, HX_CRITERIA_SIZE); + + /* init criteria data*/ + hx83112f_nf_inspt_crtra_flag = kcalloc(HX_CRITERIA_SIZE, sizeof(int), GFP_KERNEL); + hx83112f_nf_inspection_criteria = kzalloc(sizeof(int *)*HX_CRITERIA_SIZE, GFP_KERNEL); + if (hx83112f_nf_inspt_crtra_flag == NULL || hx83112f_nf_inspection_criteria == NULL) { + TPD_INFO("%s: %d, Memory allocation failed!\n", __func__, __LINE__); + return MEM_ALLOC_FAIL; + } + + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + hx83112f_nf_inspection_criteria[i] = kcalloc( + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM), sizeof(int), GFP_KERNEL); + if (hx83112f_nf_inspection_criteria[i] == NULL) { + TPD_INFO("%s: %d, Memory allocation failed!\n", __func__, __LINE__); + return MEM_ALLOC_FAIL; + } + } + + /* parsing criteria from file*/ + ret = himax_parse_criteria_file(chip_info); + + /* print get criteria string */ + for (i = 0 ; i < HX_CRITERIA_SIZE ; i++) { + if (hx83112f_nf_inspt_crtra_flag[i] != 0) + TPD_DEBUG("%s: [%d]There is String=%s\n", __func__, i, g_hx_inspt_crtra_name[i]); + } + + return ret; +} + +static void hx83112f_black_screen_test(void *chip_data, char *message) +{ + int error = 0; + int error_num = 0; + int retry_cnt = 3; + struct timespec now_time; + struct rtc_time rtc_now_time; + char *buf = NULL; + char *g_file_name_OK = NULL; + char *g_file_name_NG = NULL; + char *g_Test_list_log = NULL; + char *g_project_test_info_log = NULL; + char *g_Company_info_log = NULL; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + int i = 0; + + TPD_INFO("%s\n", __func__); + + buf = kzalloc(sizeof(char) * 128, GFP_KERNEL); + if (!buf) { + TPD_INFO("%s:%d buf kzalloc error\n", __func__, __LINE__); + goto RET_OUT; + } + g_file_name_OK = kzalloc(sizeof(char) * 64, GFP_KERNEL); + if (!g_file_name_OK) { + TPD_INFO("%s:%d g_file_name_OK kzalloc error\n", __func__, __LINE__); + goto RET_OUT; + } + g_file_name_NG = kzalloc(sizeof(char) * 64, GFP_KERNEL); + if (!g_file_name_NG) { + TPD_INFO("%s:%d g_file_name_NG kzalloc error\n", __func__, __LINE__); + goto RET_OUT; + } + g_rslt_data_len = 0; + + /*init criteria data*/ + error = himax_self_test_data_init(chip_info); + /*init criteria data*/ + + /*Init Log Data */ + g_1kind_raw_size = 5 * chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM * 2; + g_Company_info_log = kcalloc(256, sizeof(char), GFP_KERNEL); + g_Test_list_log = kcalloc(256, sizeof(char), GFP_KERNEL); + g_project_test_info_log = kcalloc(256, sizeof(char), GFP_KERNEL); + hx83112f_nf_fail_write_count = 0; + g_file_path_OK = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_file_path_OK) { + TPD_INFO("%s:%d g_file_path_OK kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + g_file_path_NG = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_file_path_NG) { + TPD_INFO("%s:%d g_file_path_NG kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + + if (g_rslt_data == NULL) { + TPD_INFO("g_rslt_data is NULL"); + g_rslt_data = kcalloc(g_1kind_raw_size * HX_CRITERIA_ITEM, + sizeof(char), GFP_KERNEL); + if (!g_rslt_data) { + TPD_INFO("%s:%d g_rslt_data kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + } else { + memset(g_rslt_data, 0x00, g_1kind_raw_size * HX_CRITERIA_ITEM * + sizeof(char)); + } + /*Init Log Data */ + hx83112f_enable_interrupt(chip_info, false); + himax_sense_off(); + himax_switch_mode(HIMAX_INSPECTION_LPWUG_RAWDATA); + + //6. LPWUG RAWDATA + TPD_INFO("[MP_LPWUG_TEST_RAW]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_LPWUG_RAWDATA, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "6. MP_LPWUG_TEST_RAW: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 15, "test Item:\n"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "6. MP_LPWUG_TEST_RAW: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + snprintf(message, sizeof(message), "%s\n", buf); + if (error != 0) + error_num++; + + //7. LPWUG NOISE + retry_cnt = 3; + TPD_INFO("[MP_LPWUG_TEST_NOISE]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_LPWUG_NOISE, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "7. MP_LPWUG_TEST_NOISE: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "7. MP_LPWUG_TEST_NOISE: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + snprintf(message, sizeof(message), "%s\n", buf); + if (error != 0) + error_num++; + + //8. LPWUG IDLE RAWDATA + retry_cnt = 3; + TPD_INFO("[MP_LPWUG_IDLE_TEST_RAW]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "8. MP_LPWUG_IDLE_TEST_RAW: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "8. MP_LPWUG_IDLE_TEST_RAW: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + snprintf(message, sizeof(message), "%s\n", buf); + if (error != 0) + error_num++; + + //9. LPWUG IDLE RAWDATA + retry_cnt = 3; + TPD_INFO("[MP_LPWUG_IDLE_TEST_NOISE]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_LPWUG_IDLE_NOISE, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "9. MP_LPWUG_IDLE_TEST_NOISE: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "9. MP_LPWUG_IDLE_TEST_NOISE: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + snprintf(message, sizeof(message), "%s\n", buf); + if (error != 0) + error_num++; + + hx83112f_enable_interrupt(chip_info, true); + /*Save Log Data */ + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + snprintf(g_file_name_OK, sizeof(g_file_name_OK), "tp_testlimit_gesture_OK_%02d%02d%02d-%02d%02d%02d-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + snprintf(g_file_name_NG, sizeof(g_file_name_NG), "tp_testlimit_gesture_NG_%02d%02d%02d-%02d%02d%02d-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 22, "Final_result: %s\n", error_num ? "Fail" : "Pass"); + if (error) { + snprintf(g_file_path_NG, + (int)(strlen(HX_GES_RSLT_OUT_PATH_NG) + strlen(g_file_name_NG) + 1), + "%s%s", HX_GES_RSLT_OUT_PATH_NG, g_file_name_NG); + hx_test_data_pop_out(chip_info, g_Test_list_log, g_Company_info_log, + g_project_test_info_log, g_rslt_data, g_file_path_NG); + } else { + snprintf(g_file_path_OK, + (int)(strlen(HX_GES_RSLT_OUT_PATH_OK) + strlen(g_file_name_OK) + 1), + "%s%s", HX_GES_RSLT_OUT_PATH_OK, g_file_name_OK); + hx_test_data_pop_out(chip_info, g_Test_list_log, g_Company_info_log, + g_project_test_info_log, g_rslt_data, g_file_path_OK); + } + /*Save Log Data */ + + + snprintf(message, sizeof(message), "%d errors. %s", error_num, error_num ? "" : "result=1"); + TPD_INFO("%d errors. %s\n", error_num, error_num ? "" : "result=1"); + +RET_OUT: + if (hx83112f_nf_inspection_criteria != NULL) { + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (hx83112f_nf_inspection_criteria[i] != NULL) { + kfree(hx83112f_nf_inspection_criteria[i]); + hx83112f_nf_inspection_criteria[i] = NULL; + } + } + kfree(hx83112f_nf_inspection_criteria); + hx83112f_nf_inspection_criteria = NULL; + TPD_INFO("Now it have free the hx83112f_nf_inspection_criteria!\n"); + } else { + TPD_INFO("No Need to free hx83112f_nf_inspection_criteria!\n"); + } + + kfree(hx83112f_nf_inspt_crtra_flag); + hx83112f_nf_inspt_crtra_flag = NULL; + + kfree(g_file_path_OK); + g_file_path_OK = NULL; + + kfree(g_file_path_NG); + g_file_path_NG = NULL; + + kfree(g_Test_list_log); + g_Test_list_log = NULL; + + kfree(g_project_test_info_log); + g_project_test_info_log = NULL; + + + kfree(g_Company_info_log); + g_Company_info_log = NULL; + + kfree(buf); + buf = NULL; + + kfree(g_file_name_OK); + g_file_name_OK = NULL; + + kfree(g_file_name_NG); + g_file_name_NG = NULL; +} + +int himax_chip_self_test(struct seq_file *s, struct chip_data_hx83112f *chip_info, char *g_Test_list_log) +{ + int error = 0; + int error_num = 0; + char *buf; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t back_data[4]; + uint8_t retry_cnt = 3; + + TPD_INFO("%s:Entering\n", __func__); + + buf = kzalloc(sizeof(char) * 128, GFP_KERNEL); + if (!buf) { + TPD_INFO("%s:%d buf kzalloc error\n", __func__, __LINE__); + error_num = -ENOMEM; + goto RET_OUT; + } + //1. Open Test + TPD_INFO("[MP_OPEN_TEST_RAW]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_OPEN, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 15, "test Item:\n"); + snprintf(buf, 128, "1. Open Test: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "1. Open Test: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + //seq_printf(s, buf); + if (error != 0) + error_num++; +/* + * 2. Micro-Open Test + * retry_cnt = 3; + * TPD_INFO("[MP_MICRO_OPEN_TEST_RAW]\n"); + * do { + * error = mpTestFunc(chip_info, HIMAX_INSPECTION_MICRO_OPEN, + * (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + * chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + * retry_cnt--; + * } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + * snprintf(buf, 128, "2. Micro Open Test: %s\n", error ? "Error" : "Ok"); + * hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + * 32, "2. Micro Open Test: %s\n", error ? "NG" : "Ok"); + * TPD_INFO("%s", buf); + * seq_printf(s, buf); + * if (error != 0) + * error_num++; + */ + //3. Short Test + retry_cnt = 3; + TPD_INFO("[MP_SHORT_TEST_RAW]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_SHORT, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "3. Short Test: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "3. Short Test: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + //seq_printf(s, buf); + if (error != 0) + error_num++; + +#ifndef RAWDATA_NOISE + //4. RawData Test + retry_cnt = 3; + TPD_INFO("[MP_RAW_TEST_RAW]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_RAWDATA, + (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM) + + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "4. Raw data Test: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "4. Raw data Test: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + //seq_printf(s, buf); + if (error != 0) + error_num++; +#endif + + //5. Noise Test + retry_cnt = 3; + TPD_INFO("[MP_NOISE_TEST_RAW]\n"); + do { + error = mpTestFunc(chip_info, HIMAX_INSPECTION_NOISE, (chip_info->hw_res->TX_NUM * + chip_info->hw_res->RX_NUM) + chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); + retry_cnt--; + } while ((error == RESULT_RETRY) && (retry_cnt > 0)); + snprintf(buf, 128, "5. Noise Test: %s\n", error ? "Error" : "Ok"); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 32, "5. Noise Test: %s\n", error ? "NG" : "Ok"); + TPD_INFO("%s", buf); + //seq_printf(s, buf); + if (error != 0) + error_num++; + + himax_set_N_frame(1, HIMAX_INSPECTION_NOISE); + //himax_set_SMWP_enable(ts->SMWP_enable,suspended); + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + //Enable:0x10007F10 = 0xA55AA55A + retry_cnt = 0; + do { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x10; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + back_data[3] = 0XA5; + back_data[2] = 0X5A; + back_data[1] = 0XA5; + back_data[0] = 0X5A; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: tmp_data[0] = 0x%02X, retry_cnt=%d\n", __func__, tmp_data[0], retry_cnt); + retry_cnt++; + } while ((tmp_data[3] != back_data[3] || tmp_data[2] != back_data[2] || tmp_data[1] != + back_data[1] || tmp_data[0] != back_data[0]) && retry_cnt < HIMAX_REG_RETRY_TIMES); + + TPD_INFO("%s:End", __func__); + //himax_sense_off(); + //himax_switch_mode(HIMAX_INSPECTION_LPWUG_RAWDATA); + hx83112f_nf_fail_write_count += snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 22, "Final_result: %s\n", error_num ? "Fail" : "Pass"); +RET_OUT: + kfree(buf); + return error_num; +} + +static size_t hx83112f_proc_register_read(struct file *file, char *buf, size_t len, loff_t *pos) +{ + size_t ret = 0; + uint16_t loop_i; + uint8_t *data; + char *temp_buf; + int max_bus_size = 128; + + //struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + data = kcalloc(max_bus_size, sizeof(uint8_t), GFP_KERNEL); + if (!data) { + TPD_INFO("%s: Can't allocate enough data\n", __func__); + ret = -ENOMEM; + goto RET_OUT; + } + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + + TPD_INFO("himax_register_show: %02X, %02X, %02X, %02X\n", + register_command[3], register_command[2], register_command[1], register_command[0]); + + himax_register_read(register_command, max_bus_size, data, cfg_flag); + + ret += snprintf(temp_buf + ret, len - ret, "command: %02X, %02X, %02X, %02X\n", + register_command[3], register_command[2], register_command[1], register_command[0]); + + for (loop_i = 0; loop_i < max_bus_size; loop_i++) { + ret += snprintf(temp_buf + ret, len - ret, "0x%2.2X ", data[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf + ret, len - ret, "\n"); + } + ret += snprintf(temp_buf + ret, len - ret, "\n"); + if (copy_to_user(buf, temp_buf, len)) + TPD_INFO("%s, here:%d\n", __func__, __LINE__); + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else { + HX_PROC_SEND_FLAG = 0; + } +RET_OUT: + kfree(data); + return ret; +} + +static size_t hx83112f_proc_register_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + char buf[81] = {0}; + char buf_tmp[16]; + uint8_t length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 2; + char *data_str = NULL; + uint8_t w_data[20]; + uint8_t x_pos[20]; + uint8_t count = 0; + //struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (len >= 80) { + TPD_INFO("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + buf[len] = '\0'; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memset(w_data, 0x0, sizeof(w_data)); + memset(x_pos, 0x0, sizeof(x_pos)); + + TPD_INFO("himax %s\n", buf); + + if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':' && buf[2] == 'x') { + length = strlen(buf); + + //TPD_INFO("%s: length = %d.\n", __func__,length); + for (loop_i = 0; loop_i < length; loop_i++) {//find postion of 'x' + if (buf[loop_i] == 'x') { + x_pos[count] = loop_i; + count++; + } + } + + data_str = strrchr(buf, 'x'); + TPD_INFO("%s: %s.\n", __func__, data_str); + length = strlen(data_str + 1) - 1; + + if (buf[0] == 'r') { + if (buf[3] == 'F' && buf[4] == 'E' && length == 4) { + length = length - base; + cfg_flag = true; + memcpy(buf_tmp, data_str + base + 1, length); + } else { + cfg_flag = false; + memcpy(buf_tmp, data_str + 1, length); + } + + byte_length = length / 2; + if (!kstrtoul(buf_tmp, 16, &result)) { + for (loop_i = 0 ; loop_i < byte_length ; loop_i++) + register_command[loop_i] = (uint8_t)(result >> loop_i * 8); + } + } else if (buf[0] == 'w') { + if (buf[3] == 'F' && buf[4] == 'E') { + cfg_flag = true; + memcpy(buf_tmp, buf + base + 3, length); + } else { + cfg_flag = false; + memcpy(buf_tmp, buf + 3, length); + } + if (count < 3) { + byte_length = length / 2; + if (!kstrtoul(buf_tmp, 16, &result)) {//command + for (loop_i = 0 ; loop_i < byte_length ; loop_i++) + register_command[loop_i] = (uint8_t)(result >> loop_i * 8); + } + if (!kstrtoul(data_str + 1, 16, &result)) { //data + for (loop_i = 0 ; loop_i < byte_length ; loop_i++) + w_data[loop_i] = (uint8_t)(result >> loop_i * 8); + } + himax_register_write(register_command, byte_length, w_data, cfg_flag); + } else { + byte_length = x_pos[1] - x_pos[0] - 2; + for (loop_i = 0; loop_i < count; loop_i++) {//parsing addr after 'x' + memcpy(buf_tmp, buf + x_pos[loop_i] + 1, byte_length); + //TPD_INFO("%s: buf_tmp = %s\n", __func__,buf_tmp); + if (!kstrtoul(buf_tmp, 16, &result) && loop_i == 0) { + register_command[loop_i] = (uint8_t)(result); + //TPD_INFO("%s: register_command = %X\n", + //__func__,register_command[0]); + } else if (!kstrtoul(buf_tmp, 16, &result)) + w_data[loop_i - 1] = (uint8_t)(result); + //TPD_INFO("%s: w_data[%d] = %2X\n", + //__func__,loop_i - 1,w_data[loop_i - 1]) + } + + byte_length = count - 1; + himax_register_write(register_command, byte_length, &w_data[0], cfg_flag); + } + } else { + return len; + } + + } + return len; +} + +void himax_return_event_stack(void) +{ + int retry = 20; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + TPD_INFO("%s:entering\n", __func__); + do { + TPD_INFO("%s, now %d times\n!", __func__, retry); + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + retry--; + //mdelay(10); + + } while ((tmp_data[1] != 0x00 && tmp_data[0] != 0x00) && retry > 0); + + TPD_INFO("%s: End of setting!\n", __func__); + +} +/*IC_BASED_END*/ + +int himax_write_read_reg(uint8_t *tmp_addr, uint8_t *tmp_data, uint8_t hb, uint8_t lb) +{ + int cnt = 0; + + do { + himax_flash_write_burst(tmp_addr, tmp_data); + + mdelay(20); + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s:Now tmp_data[0] = 0x%02X, [1] = 0x%02X, [2] = 0x%02X, [3] = 0x%02X\n", + __func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + } while ((tmp_data[1] != hb && tmp_data[0] != lb) && cnt++ < 100); + + if (cnt >= 99) { + TPD_INFO("%s ERR Now register 0x%08X : high byte = 0x%02X, low byte = 0x%02X\n", + __func__, tmp_addr[3], tmp_data[1], tmp_data[0]); + return -EINVAL; + } + + TPD_INFO("Now register 0x%08X : high byte = 0x%02X, low byte = 0x%02X\n", + tmp_addr[3], tmp_data[1], tmp_data[0]); + return NO_ERR; +} + +void himax_get_DSRAM_data(uint8_t *info_data, uint8_t x_num, uint8_t y_num) +{ + int i = 0; + //int cnt = 0; + unsigned char tmp_addr[4]; + unsigned char tmp_data[4]; + uint8_t max_i2c_size = MAX_RECVS_SZ; + int m_key_num = 0; + int total_size = (x_num * y_num + x_num + y_num) * 2 + 4; + int total_size_temp; + int mutual_data_size = x_num * y_num * 2; + int total_read_times = 0; + int address = 0; + uint8_t *temp_info_data; //max mkey size = 8 + uint32_t check_sum_cal = 0; + int fw_run_flag = -1; + //uint16_t temp_check_sum_cal = 0; + + temp_info_data = kzalloc(sizeof(uint8_t) * (total_size + 8), GFP_KERNEL); + + /*1. Read number of MKey R100070E8H to determin data size*/ + m_key_num = 0; + //TPD_INFO("%s,m_key_num=%d\n",__func__,m_key_num); + total_size += m_key_num * 2; + + /* 2. Start DSRAM Rawdata and Wait Data Ready */ + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x5A; + tmp_data[0] = 0xA5; + fw_run_flag = himax_write_read_reg(tmp_addr, tmp_data, 0xA5, 0x5A); + if (fw_run_flag < 0) { + TPD_INFO("%s Data NOT ready => bypass\n", __func__); + kfree(temp_info_data); + return; + } + + /* 3. Read RawData */ + total_size_temp = total_size; + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + + if (total_size % max_i2c_size == 0) + total_read_times = total_size / max_i2c_size; + else + total_read_times = total_size / max_i2c_size + 1; + + for (i = 0; i < (total_read_times); i++) { + if (total_size_temp >= max_i2c_size) { + himax_register_read(tmp_addr, max_i2c_size, &temp_info_data[i * max_i2c_size], false); + total_size_temp = total_size_temp - max_i2c_size; + } else { + //TPD_INFO("last total_size_temp=%d\n",total_size_temp); + himax_register_read(tmp_addr, total_size_temp % max_i2c_size, + &temp_info_data[i * max_i2c_size], false); + } + + address = ((i + 1) * max_i2c_size); + tmp_addr[1] = (uint8_t)((address >> 8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + } + + /* 4. FW stop outputing */ + //TPD_INFO("DSRAM_Flag=%d\n",DSRAM_Flag); + if (DSRAM_Flag == false) { + //TPD_INFO("Return to Event Stack!\n"); + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + } else { + //TPD_INFO("Continue to SRAM!\n"); + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = 0x00; + tmp_data[3] = 0x11; + tmp_data[2] = 0x22; + tmp_data[1] = 0x33; + tmp_data[0] = 0x44; + himax_flash_write_burst(tmp_addr, tmp_data); + } + + /* 5. Data Checksum Check */ + for (i = 2; i < total_size; i = i + 2) { /* 2:PASSWORD NOT included */ + check_sum_cal += (temp_info_data[i + 1] * 256 + temp_info_data[i]); + TPD_DETAIL(KERN_CONT "0x%2x:0x%4x ", temp_info_data[i], check_sum_cal); + } + + if (check_sum_cal % 0x10000 != 0) { + memcpy(info_data, &temp_info_data[4], mutual_data_size * sizeof(uint8_t)); + TPD_INFO("%s check_sum_cal fail=%2x\n", __func__, check_sum_cal); + kfree(temp_info_data); + } else { + memcpy(info_data, &temp_info_data[4], mutual_data_size * sizeof(uint8_t)); + kfree(temp_info_data); + TPD_INFO("%s checksum PASS\n", __func__); + } +} + +void himax_ts_diag_func(struct chip_data_hx83112f *chip_info, int32_t *mutual_data) +{ + int i = 0; + int j = 0; + unsigned int index = 0; + int total_size = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM * 2; + uint8_t *info_data = NULL; + + int32_t new_data; + /* 1:common dsram,2:100 frame Max,3:N-(N-1)frame */ + int dsram_type = 0; + char *write_buf = NULL; + + dsram_type = g_diag_command / 10; + + TPD_INFO("%s:Entering g_diag_command=%d\n!", __func__, g_diag_command); + + info_data = kcalloc(total_size, sizeof(uint8_t), GFP_KERNEL); + if (info_data == NULL) + return; + + write_buf = kzalloc((total_size * 3)*sizeof(char), GFP_KERNEL); + if (write_buf == NULL) { + kfree(info_data); + info_data = NULL; + return; + } + + if (dsram_type == 8) { + dsram_type = 1; + TPD_INFO("%s Sorting Mode run sram type1 !\n", __func__); + } + + himax_burst_enable(1); + himax_get_DSRAM_data(info_data, chip_info->hw_res->RX_NUM, chip_info->hw_res->TX_NUM); + + index = 0; + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) { + for (j = 0; j < chip_info->hw_res->RX_NUM; j++) { + new_data = ((int8_t)info_data[index + 1] << 8 | info_data[index]); + mutual_data[i * chip_info->hw_res->RX_NUM + j] = new_data; + index += 2; + } + } + + kfree(info_data); + info_data = NULL; + kfree(write_buf); + write_buf = NULL; + +} + +void diag_parse_raw_data(struct himax_report_data *hx_touch_data, int mul_num, + int self_num, uint8_t diag_cmd, int32_t *mutual_data, int32_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2, i; + + if (hx_touch_data->hx_rawdata_buf[0] == 0x3A + && hx_touch_data->hx_rawdata_buf[1] == 0xA3 + && hx_touch_data->hx_rawdata_buf[2] > 0 + && hx_touch_data->hx_rawdata_buf[3] == diag_cmd) { + RawDataLen_word = hx_touch_data->rawdata_size / 2; + index = (hx_touch_data->hx_rawdata_buf[2] - 1) * RawDataLen_word; + for (i = 0; i < RawDataLen_word; i++) { + temp1 = index + i; + + if (temp1 < mul_num) { + //mutual + mutual_data[index + i] = + ((int8_t)hx_touch_data->hx_rawdata_buf[i * 2 + 4 + 1]) * 256 + + hx_touch_data->hx_rawdata_buf[i * 2 + 4]; /* 4: RawData Header, 1:HSB */ + } else { + //self + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + break; + + self_data[i + index - mul_num] = + (((int8_t)hx_touch_data->hx_rawdata_buf[i * 2 + 4 + 1]) << 8) | + hx_touch_data->hx_rawdata_buf[i * 2 + 4]; /* 4: RawData Header */ + //self_data[i+index-mul_num+1] = hx_touch_data->hx_rawdata_buf[i*2 + 4 + 1]; + } + } + } + +} + +bool diag_check_sum(struct himax_report_data *hx_touch_data) /*return checksum value */ +{ + uint16_t check_sum_cal = 0; + int i; + + //Check 128th byte CRC + for (i = 0, check_sum_cal = 0; + i < (hx_touch_data->touch_all_size - hx_touch_data->touch_info_size); i = i + 2) + check_sum_cal += (hx_touch_data->hx_rawdata_buf[i + 1] * 256 + hx_touch_data->hx_rawdata_buf[i]); + + if (check_sum_cal % 0x10000 != 0) { + TPD_INFO("%s fail=%2X\n", __func__, check_sum_cal); + return 0; + //goto bypass_checksum_failed_packet; + } + + return 1; +} + +static size_t hx83112f_proc_diag_write(struct file *file, const char *buff, size_t len, loff_t *pos) +{ + char messages[80] = {0}; + uint8_t command[2] = {0x00, 0x00}; + uint8_t receive[1]; + + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)ts->chip_data; + + /* 0: common, other: dsram*/ + int storage_type = 0; + /* 1:IIR, 2:DC, 3:Bank, 4:IIR2, 5:IIR2_N, 6:FIR2, 7:Baseline, 8:dump coord */ + int rawdata_type = 0; + + memset(receive, 0x00, sizeof(receive)); + + if (len >= 80) { + TPD_INFO("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(messages, buff, len)) + return -EFAULT; + + if (messages[1] == 0x0A) + g_diag_command = messages[0] - '0'; + else + g_diag_command = (messages[0] - '0') * 10 + (messages[1] - '0'); + + storage_type = g_diag_command / 10; + rawdata_type = g_diag_command % 10; + + TPD_INFO(" messages = %s\n" + " g_diag_command = 0x%x\n" + " storage_type = 0x%x\n" + " rawdata_type = 0x%x\n", + messages, g_diag_command, storage_type, rawdata_type); + + if (g_diag_command > 0 && rawdata_type == 0) { + TPD_INFO("[Himax]g_diag_command = 0x%x, storage_type=%d, rawdata_type=%d! Maybe no support!\n", + g_diag_command, storage_type, rawdata_type); + g_diag_command = 0x00; + } else { + TPD_INFO("[Himax]g_diag_command = 0x%x, storage_type=%d, rawdata_type=%d\n", + g_diag_command, storage_type, rawdata_type); + } + + if (storage_type == 0 && rawdata_type > 0 && rawdata_type < 8) { + TPD_INFO("%s, common\n", __func__); + if (DSRAM_Flag) { + //(1) Clear DSRAM flag + DSRAM_Flag = false; + //(2) Enable ISR + // enable_irq(chip_info->hx_irq); + hx83112f_enable_interrupt(chip_info, true); + //(3) FW leave sram and return to event stack + himax_return_event_stack(); + } + + command[0] = g_diag_command; + himax_diag_register_set(command[0]); + } else if (storage_type > 0 && storage_type < 8 && rawdata_type > 0 && rawdata_type < 8) { + TPD_INFO("%s, dsram\n", __func__); + + //0. set diag flag + if (DSRAM_Flag) { + //(1) Clear DSRAM flag + DSRAM_Flag = false; + //(2) Enable ISR + // enable_irq(chip_info->hx_irq); + hx83112f_enable_interrupt(chip_info, true); + //(3) FW leave sram and return to event stack + himax_return_event_stack(); + } + + switch (rawdata_type) { + case 1: + command[0] = 0x09; //IIR + break; + + case 2: + command[0] = 0x0A;//RAWDATA + break; + + case 3: + command[0] = 0x08;//Baseline + break; + + default: + command[0] = 0x00; + TPD_INFO("%s: Sram no support this type !\n", __func__); + break; + } + himax_diag_register_set(command[0]); + TPD_INFO("%s: Start get raw data in DSRAM\n", __func__); + //1. Disable ISR + hx83112f_enable_interrupt(chip_info, false); + + //2. Set DSRAM flag + DSRAM_Flag = true; + } else { + //set diag flag + if (DSRAM_Flag) { + TPD_INFO("return and cancel sram thread!\n"); + //(1) Clear DSRAM flag + DSRAM_Flag = false; + himax_return_event_stack(); + } + command[0] = 0x00; + g_diag_command = 0x00; + himax_diag_register_set(command[0]); + TPD_INFO("return to normal g_diag_command = 0x%x\n", g_diag_command); + } + return len; +} + +static size_t hx83112f_proc_diag_read(struct file *file, char *buff, size_t len, loff_t *pos) +{ + size_t ret = 0; + char *temp_buf; + uint16_t mutual_num; + uint16_t self_num; + uint16_t width; + int dsram_type = 0; + int data_type = 0; + int i = 0; + int j = 0; + int k = 0; + + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)ts->chip_data; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) + goto RET_OUT; + + dsram_type = g_diag_command / 10; + data_type = g_diag_command % 10; + + mutual_num = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; + self_num = chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM; //don't add KEY_COUNT + width = chip_info->hw_res->RX_NUM; + ret += snprintf(temp_buf + ret, len - ret, "ChannelStart (rx tx) : %4d, %4d\n\n", + chip_info->hw_res->RX_NUM, chip_info->hw_res->TX_NUM); + + // start to show out the raw data in adb shell + if ((data_type >= 1 && data_type <= 7)) { + if (dsram_type > 0) + himax_ts_diag_func(chip_info, hx_touch_data->diag_mutual); + + for (j = 0; j < chip_info->hw_res->RX_NUM ; j++) { + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) { + k = ((mutual_num - j) - chip_info->hw_res->RX_NUM * i) - 1; + ret += snprintf(temp_buf + ret, len - ret, "%6d", + hx_touch_data->diag_mutual[k]); + } + ret += snprintf(temp_buf + ret, len - ret, " %6d\n", diag_self[j]); + } + + ret += snprintf(temp_buf + ret, len - ret, "\n"); + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) + ret += snprintf(temp_buf + ret, len - ret, "%6d", diag_self[i]); + + } + + ret += snprintf(temp_buf + ret, len - ret, "\n"); + ret += snprintf(temp_buf + ret, len - ret, "ChannelEnd"); + ret += snprintf(temp_buf + ret, len - ret, "\n"); + + //if ((g_diag_command >= 1 && g_diag_command <= 7) || dsram_type > 0) + { + /* print Mutual/Slef Maximum and Minimum */ + //himax_get_mutual_edge(); + for (i = 0; i < (chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM); i++) { + if (hx_touch_data->diag_mutual[i] > g_max_mutual) + g_max_mutual = hx_touch_data->diag_mutual[i]; + + if (hx_touch_data->diag_mutual[i] < g_min_mutual) + g_min_mutual = hx_touch_data->diag_mutual[i]; + + } + + //himax_get_self_edge(); + for (i = 0; i < (chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM); i++) { + if (diag_self[i] > g_max_self) + g_max_self = diag_self[i]; + + if (diag_self[i] < g_min_self) + g_min_self = diag_self[i]; + } + + ret += snprintf(temp_buf + ret, len - ret, "Mutual Max:%3d, Min:%3d\n", + g_max_mutual, g_min_mutual); + ret += snprintf(temp_buf + ret, len - ret, "Self Max:%3d, Min:%3d\n", g_max_self, g_min_self); + + /* recovery status after print*/ + g_max_mutual = 0; + g_min_mutual = 0xFFFF; + g_max_self = 0; + g_min_self = 0xFFFF; + } + if (copy_to_user(buff, temp_buf, len)) + TPD_INFO("%s, here:%d\n", __func__, __LINE__); + HX_PROC_SEND_FLAG = 1; +RET_OUT: + kfree(temp_buf); + } else { + HX_PROC_SEND_FLAG = 0; + } + + return ret; +} + +static int hx83112f_configuration_init(struct chip_data_hx83112f *chip_info, bool config) +{ + int ret = 0; + int retry_cnt = 0; + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + uint8_t back_data[4] = {0}; + + TPD_INFO("%s, configuration init = %d\n", __func__, config); + if (config) { + g_zero_event_count = 0; + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xD0; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + do { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + back_data[3] = 0x00; + back_data[2] = 0x00; + back_data[1] = 0x00; + back_data[0] = 0x00; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: tmp_data[0] = 0x%02X, retry_cnt=%d\n", __func__, tmp_data[0], retry_cnt); + retry_cnt++; + } while ((tmp_data[3] != back_data[3] || tmp_data[2] != back_data[2] || tmp_data[1] != back_data[1] || + tmp_data[0] != back_data[0]) && retry_cnt < HIMAX_REG_RETRY_TIMES); + } else { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xD0; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + hx_chk_write_register(tmp_addr, tmp_data); + } + return ret; +} + +int himax_ic_reset(struct chip_data_hx83112f *chip_info, uint8_t loadconfig, uint8_t int_off) +{ + int ret = 0; + + HX_HW_RESET_ACTIVATE = 1; + TPD_INFO("%s, status: loadconfig=%d, int_off=%d\n", __func__, loadconfig, int_off); + + if (chip_info->hw_res->reset_gpio) { + if (int_off) { + + ret = hx83112f_enable_interrupt(chip_info, false); + if (ret < 0) { + TPD_INFO("%s: hx83112f enable interrupt failed.\n", __func__); + return ret; + } + } +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(chip_info->hw_res, false); // reset gpio + hx83112f_resetgpio_set(chip_info->hw_res, true); // reset gpio +#else + himax_mcu_sys_reset(); +#endif + himax_hx83112f_reload_to_active();//morgen add + if (loadconfig) { + ret = hx83112f_configuration_init(chip_info, false); + if (ret < 0) { + TPD_INFO("%s: hx83112f configuration init failed.\n", __func__); + return ret; + } + ret = hx83112f_configuration_init(chip_info, true); + if (ret < 0) { + TPD_INFO("%s: hx83112f configuration init failed.\n", __func__); + return ret; + } + } + if (int_off) { + ret = hx83112f_enable_interrupt(chip_info, true); + if (ret < 0) { + TPD_INFO("%s: hx83112f enable interrupt failed.\n", __func__); + return ret; + } + } + } + return 0; +} + +static size_t hx83112f_proc_reset_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[12]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)ts->chip_data; + + if (len >= 12) { + TPD_INFO("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + return -EFAULT; + + if (buf_tmp[0] == '1') + himax_ic_reset(chip_info, false, false); + else if (buf_tmp[0] == '2') + himax_ic_reset(chip_info, false, true); + else if (buf_tmp[0] == '3') + himax_ic_reset(chip_info, true, false); + else if (buf_tmp[0] == '4') + himax_ic_reset(chip_info, true, true); + + + return len; +} + +static size_t hx83112f_proc_sense_on_off_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf[80] = {0}; + //struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (len >= 80) { + TPD_INFO("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + return -EFAULT; + + if (buf[0] == '0') { + himax_sense_off(); + TPD_INFO("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == 's') { + himax_sense_on(0x00); + TPD_INFO("Sense on re-map on, run sram\n"); + } else { + himax_sense_on(0x01); + TPD_INFO("Sense on re-map off, run flash\n"); + } + } else { + TPD_INFO("Do nothing\n"); + } + return len; +} + +static size_t hx83112f_proc_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + + hx83112f_enable_interrupt(g_chip_info, false); + himax_read_FW_ver(); + himax_sense_on(0x00); + hx83112f_enable_interrupt(g_chip_info, true); + + ret += snprintf(temp_buf + ret, len - ret, "FW_ID:0x%08X\n", g_chip_info->fw_id); + ret += snprintf(temp_buf + ret, len - ret, "FW_VER:0x%04X\n", g_chip_info->fw_ver); + ret += snprintf(temp_buf + ret, len - ret, "TOUCH_VER:0x%02X\n", g_chip_info->touch_ver); + ret += snprintf(temp_buf + ret, len - ret, "DRIVER_VER:%s\n", DRIVER_VERSION); + + if (copy_to_user(buf, temp_buf, len)) + TPD_INFO("%s, here:%d\n", __func__, __LINE__); + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; + return ret; +} + +#ifdef CONFIG_OP_TP_APK +static void himax_gesture_debug_mode_set(bool on_off) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + char buf[80] = {0}; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xF8; + + if (on_off) { + switch_algo = buf[0]; + check_point_format = 1; + tmp_data[3] = 0xA1; + tmp_data[2] = 0x1A; + tmp_data[1] = 0xA1; + tmp_data[0] = 0x1A; + himax_register_write(tmp_addr, 4, tmp_data, 0); + TPD_INFO("%s: Report 40 trajectory coordinate points .\n", __func__); + } else { + switch_algo = 0; + check_point_format = 0; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + + himax_register_write(tmp_addr, 4, tmp_data, 0); + TPD_INFO("%s: close FW enter algorithm switch.\n", __func__); + } +} + + +static void himax_debug_mode_set(bool on_off) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + char buf[80] = {0}; + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xF8; + + if (on_off) { + switch_algo = buf[0]; + check_point_format = 0; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_register_write(tmp_addr, 4, tmp_data, 0); + TPD_INFO("%s: open FW enter algorithm switch.\n", __func__); + } else { + switch_algo = 0; + check_point_format = 0; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + + himax_register_write(tmp_addr, 4, tmp_data, 0); + TPD_INFO("%s: close FW enter algorithm switch.\n", __func__); + } +} + +static void himax_debug_sta_judge(struct chip_data_hx83112f *chip_info) +{ + static struct himax_fw_debug_info last_sta; + struct himax_fw_debug_info sta; + + memcpy(&sta, &hx_touch_data->hx_state_info[3], sizeof(sta)); + + if (last_sta.recal0 != sta.recal0) { + if (sta.recal0) + log_buf_write(private_ts, 1); + else + log_buf_write(private_ts, 2); + } + + if (last_sta.recal1 != sta.recal1) { + if (sta.recal1) + log_buf_write(private_ts, 4); + else + log_buf_write(private_ts, 3); + } + + if (last_sta.paseline != sta.paseline) { + if (sta.paseline) + log_buf_write(private_ts, 5); + } + + if (last_sta.palm != sta.palm) { + if (sta.palm) + log_buf_write(private_ts, 7); + else + log_buf_write(private_ts, 6); + } + if (last_sta.idle != sta.idle) { + if (sta.idle) + log_buf_write(private_ts, 9); + else + log_buf_write(private_ts, 8); + } + + if (last_sta.water != sta.water) { + if (sta.water) + log_buf_write(private_ts, 11); + else + log_buf_write(private_ts, 10); + } + + if (last_sta.hopping != sta.hopping) { + if (sta.hopping) + log_buf_write(private_ts, 13); + else + log_buf_write(private_ts, 12); + } + + if (last_sta.noise != sta.noise) { + if (sta.noise) + log_buf_write(private_ts, 15); + else + log_buf_write(private_ts, 14); + + } + + if (last_sta.glove != sta.glove) { + if (sta.glove) + log_buf_write(private_ts, 17); + else + log_buf_write(private_ts, 16); + } + + if (last_sta.border != sta.border) { + if (sta.border) + log_buf_write(private_ts, 19); + else + log_buf_write(private_ts, 18); + } + + if (last_sta.vr != sta.vr) { + if (sta.vr) + log_buf_write(private_ts, 21); + else + log_buf_write(private_ts, 20); + } + + if (last_sta.big_small != sta.big_small) { + if (sta.big_small) + log_buf_write(private_ts, 23); + else + log_buf_write(private_ts, 22); + } + + if (last_sta.one_block != sta.one_block) { + if (sta.one_block) + log_buf_write(private_ts, 25); + else + log_buf_write(private_ts, 24); + } + + if (last_sta.blewing != sta.blewing) { + if (sta.blewing) + log_buf_write(private_ts, 27); + else + log_buf_write(private_ts, 26); + } + + if (last_sta.thumb_flying != sta.thumb_flying) { + if (sta.thumb_flying) + log_buf_write(private_ts, 29); + else + log_buf_write(private_ts, 28); + } + + if (last_sta.border_extend != sta.border_extend) { + if (sta.border_extend) + log_buf_write(private_ts, 31); + else + log_buf_write(private_ts, 30); + } + + memcpy(&last_sta, &sta, sizeof(last_sta)); + + if (tp_debug > 0) { + TPD_INFO("The sta is = 0x%02X,0x%02X\n", + hx_touch_data->hx_state_info[3], + hx_touch_data->hx_state_info[4]); + } +} +#endif + +static int hx83112f_get_touch_points(void *chip_data, struct point_info *points, int max_num) +{ + int i, x, y, z = 1, obj_attention = 0; + + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + char *buf; + uint16_t mutual_num; + uint16_t self_num; + int ret = 0; + int check_sum_cal; + int ts_status = HX_REPORT_COORD; + int hx_point_num; + uint8_t hx_state_info_pos; + + if (!hx_touch_data) + TPD_INFO("%s:%d hx_touch_data is NULL\n", __func__, __LINE__); + + if (!hx_touch_data->hx_coord_buf) { + TPD_INFO("%s:%d hx_touch_data->hx_coord_buf is NULL\n", __func__, __LINE__); + return 0; + } + + buf = kzalloc(sizeof(char) * 128, GFP_KERNEL); + if (!buf) { + TPD_INFO("%s:%d buf kzalloc error\n", __func__, __LINE__); + return -ENOMEM; + } + + himax_burst_enable(0); + if (g_diag_command) + ret = himax_read_event_stack(buf, 128); + else + ret = himax_read_event_stack(buf, hx_touch_data->touch_info_size); + if (!ret) { + TPD_INFO("%s: can't read data from chip in normal!\n", __func__); + goto checksum_fail; + } + + if (tp_debug == LEVEL_DEBUG) + himax_log_touch_data(buf, hx_touch_data); + + check_sum_cal = himax_checksum_cal(chip_info, buf, ts_status);//????checksum + if (check_sum_cal == CHECKSUM_FAIL) + goto checksum_fail; + else if (check_sum_cal == ERR_WORK_OUT) + goto err_workqueue_out; + else if (check_sum_cal == WORK_OUT) + goto workqueue_out; + + //himax_assign_touch_data(buf,ts_status);//??buf??, ??hx_coord_buf + + hx_state_info_pos = hx_touch_data->touch_info_size - 6; + if (ts_status == HX_REPORT_COORD) { + memcpy(hx_touch_data->hx_coord_buf, &buf[0], hx_touch_data->touch_info_size); + if (buf[hx_state_info_pos] != 0xFF && buf[hx_state_info_pos + 1] != 0xFF) + memcpy(hx_touch_data->hx_state_info, &buf[hx_state_info_pos], 5); + else + memset(hx_touch_data->hx_state_info, 0x00, sizeof(hx_touch_data->hx_state_info)); + } + if (g_diag_command) { + mutual_num = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; + self_num = chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM; + TPD_INFO("hx_touch_data->touch_all_size= %d hx_touch_data->touch_info_size = %d, %d\n", + hx_touch_data->touch_all_size, hx_touch_data->touch_info_size, + hx_touch_data->touch_all_size - hx_touch_data->touch_info_size); + memcpy(hx_touch_data->hx_rawdata_buf, &buf[hx_touch_data->touch_info_size], + hx_touch_data->touch_all_size - hx_touch_data->touch_info_size); + if (!diag_check_sum(hx_touch_data)) + goto err_workqueue_out; + diag_parse_raw_data(hx_touch_data, mutual_num, self_num, + g_diag_command, hx_touch_data->diag_mutual, diag_self); + } + + if (hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] == 0xff)//HX_TOUCH_INFO_POINT_CNT buf??????? + hx_point_num = 0; + else + hx_point_num = hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + + for (i = 0; i < 10; i++) { + x = hx_touch_data->hx_coord_buf[i * 4] << 8 | hx_touch_data->hx_coord_buf[i * 4 + 1]; + y = (hx_touch_data->hx_coord_buf[i * 4 + 2] << 8 | hx_touch_data->hx_coord_buf[i * 4 + 3]); + z = hx_touch_data->hx_coord_buf[i + 40]; + if (x >= 0 && x <= private_ts->resolution_info.max_x && y >= 0 && + y <= private_ts->resolution_info.max_y) { + points[i].x = x; + points[i].y = y; + points[i].width_major = z; + points[i].touch_major = z; + points[i].status = 1; + obj_attention = obj_attention | (0x0001 << i); + } + } + + //TPD_DEBUG("%s:%d obj_attention = 0x%x\n", __func__, __LINE__, obj_attention); + +checksum_fail: + return obj_attention; +err_workqueue_out: +workqueue_out: + kfree(buf); + //himax_ic_reset(chip_info, false, true); + return -EINVAL; + +} + +static int hx83112f_ftm_process(void *chip_data) +{ +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(g_chip_info->hw_res, false); // reset gpio +#endif + switch_spi7cs_state(false); // in case of current leakaging in ftm mode + return 0; +} + +static int hx83112f_get_vendor(void *chip_data, struct panel_info *panel_data) +{ + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + chip_info->tp_type = panel_data->tp_type; + chip_info->p_tp_fw = &panel_data->TP_FW; + TPD_INFO("chip_info->tp_type = %d, panel_data->test_limit_name = %s, panel_data->fw_name = %s\n", + chip_info->tp_type, panel_data->test_limit_name, panel_data->fw_name); + return 0; +} + + +static int hx83112f_get_chip_info(void *chip_data) +{ + return 1; +} + +/** + * hx83112f_get_fw_id - get device fw id. + * @chip_info: struct include i2c resource. + * Return fw version result. + */ +static uint32_t hx83112f_get_fw_id(struct chip_data_hx83112f *chip_info) +{ + uint32_t current_firmware = 0; + uint8_t cmd[4]; + uint8_t data[64]; + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x14; + himax_register_read(cmd, 4, data, false); + + TPD_INFO("%s : [0] = 0x%2.2X, [1] = 0x%2.2X, [2] = 0x%2.2X, [3] = 0x%2.2X\n", + __func__, data[0], data[1], data[2], data[3]); + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x84; + himax_register_read(cmd, 4, data, false); + TPD_INFO("TOUCH_VER : %X\n", data[2]); + // current_firmware = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + current_firmware = data[2]; + TPD_INFO("CURRENT_FIRMWARE_ID = 0x%x\n", current_firmware); + + return current_firmware; + +} + +#define HX_DEV_VERSION_LEN 8 +static fw_check_state hx83112f_fw_check(void *chip_data, + struct resolution_info *resolution_info, struct panel_info *panel_data) +{ + uint8_t ver_len = 0; + char dev_version[HX_DEV_VERSION_LEN] = {0}; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + //fw check normal need update TP_FW && device info + panel_data->TP_FW = hx83112f_get_fw_id(chip_info); + snprintf(dev_version, HX_DEV_VERSION_LEN, "%02X", panel_data->TP_FW); + snprintf(Ctp_name, sizeof(Ctp_name), "TM,HX83112,FW:0x%x\n", panel_data->TP_FW); + TPD_INFO("%s: panel_data->TP_FW = %d\n", __func__, panel_data->TP_FW); + TPD_INFO("%s: g_lcd_vendor = %d\n", __func__, g_lcd_vendor); + TPD_INFO("%s: dev_version = %s\n", __func__, dev_version); + if (panel_data->manufacture_info.version) { + //sprintf(panel_data->manufacture_info.version, "0x%x-%d", + //panel_data->TP_FW, g_lcd_vendor); + ver_len = strlen(panel_data->manufacture_info.version); + if (ver_len <= 9) + strlcat(panel_data->manufacture_info.version, dev_version, MAX_DEVICE_VERSION_LENGTH); + else + strlcpy(&panel_data->manufacture_info.version[12], dev_version, 3); + } + + return FW_NORMAL; +} + +static u8 hx83112f_trigger_reason(void *chip_data, int gesture_enable, int is_suspended) +{ + if ((gesture_enable == 1) && is_suspended) + return IRQ_GESTURE; + else + return IRQ_TOUCH; +} + +static void hx83112f_exit_esd_mode(void *chip_data) +{ + TPD_INFO("exit esd mode ok\n"); +} + + +//return success: 0 ; fail : negative + +static int hx83112f_reset(void *chip_data) +{ + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + int ret = 0; + int load_fw_times = 10; + + TPD_INFO("%s.\n", __func__); + + if (!chip_info->first_download_finished) { + TPD_INFO("%s:First download has not finished, don't do reset.\n", __func__); + return 0; + } + + g_zero_event_count = 0; + + clear_view_touchdown_flag(); //clear touch download flag + //esd hw reset + HX_ESD_RESET_ACTIVATE = 0; + + hx83112f_enable_interrupt(chip_info, false); + + do { + load_fw_times--; + himax_mcu_firmware_update_0f(NULL); + ret = g_core_fp.fp_reload_disable(); + } while (ret && load_fw_times > 0); + + if (!load_fw_times) + TPD_INFO("%s: load_fw_times over 10 times\n", __func__); + + himax_sense_on(0x00); + himax_check_remapping(); + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + // enable_irq(chip_info->hx_irq); + hx83112f_enable_interrupt(chip_info, true); +#endif + //hx83112f_enable_interrupt(g_chip_info, true); + //esd hw reset + return ret; +} + +void himax_ultra_enter(void) +{ + uint8_t tmp_data[4]; + int rtimes = 0; + + TPD_INFO("%s:entering\n", __func__); + + /* 34 -> 11 */ + do { + if (rtimes > 10) { + TPD_INFO("%s:1/6 retry over 10 times!\n", __func__); + return; + } + tmp_data[0] = 0x11; + if (himax_bus_write(0x34, 1, tmp_data) < 0) { + TPD_INFO("%s: spi write fail!\n", __func__); + continue; + } + mdelay(1); + tmp_data[0] = 0x00; + if (himax_bus_read(0x34, 1, tmp_data) < 0) { + TPD_INFO("%s: spi read fail!\n", __func__); + continue; + } + + TPD_INFO("%s:retry %d, addr = 0x34, correct = 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != 0x11); + + /* 33 -> 33 */ + rtimes = 0; + do { + if (rtimes > 10) { + TPD_INFO("%s:2/6 retry over 10 times!\n", __func__); + return; + } + tmp_data[0] = 0x33; + if (himax_bus_write(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi write fail!\n", __func__); + continue; + } + mdelay(1); + tmp_data[0] = 0x00; + if (himax_bus_read(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi read fail!\n", __func__); + continue; + } + + TPD_INFO("%s:retry %d, addr = 0x33, correct = 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != 0x33); + + /* 34 -> 22 */ + rtimes = 0; + do { + if (rtimes > 10) { + TPD_INFO("%s:3/6 retry over 10 times!\n", __func__); + return; + } + tmp_data[0] = 0x22; + if (himax_bus_write(0x34, 1, tmp_data) < 0) { + TPD_INFO("%s: spi write fail!\n", __func__); + continue; + } + mdelay(1); + tmp_data[0] = 0x00; + if (himax_bus_read(0x34, 1, tmp_data) < 0) { + TPD_INFO("%s: spi read fail!\n", __func__); + continue; + } + + TPD_INFO("%s:retry %d, addr = 0x34, correct = 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != 0x22); + + /* 33 -> AA */ + rtimes = 0; + do { + if (rtimes > 10) { + TPD_INFO("%s:4/6 retry over 10 times!\n", __func__); + return; + } + tmp_data[0] = 0xAA; + if (himax_bus_write(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi write fail!\n", __func__); + continue; + } + mdelay(1); + tmp_data[0] = 0x00; + if (himax_bus_read(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi read fail!\n", __func__); + continue; + } + + TPD_INFO("%s:retry %d, addr = 0x33, 0xAA = 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != 0xAA); + + /* 33 -> 33 */ + rtimes = 0; + do { + if (rtimes > 10) { + TPD_INFO("%s:5/6 retry over 10 times!\n", __func__); + return; + } + tmp_data[0] = 0x33; + if (himax_bus_write(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi write fail!\n", __func__); + continue; + } + mdelay(1); + tmp_data[0] = 0x00; + if (himax_bus_read(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi read fail!\n", __func__); + continue; + } + + TPD_INFO("%s:retry %d, addr = 0x33, correct = 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != 0x33); + + /* 33 -> AA */ + rtimes = 0; + do { + if (rtimes > 10) { + TPD_INFO("%s:6/6 retry over 10 times!\n", __func__); + return; + } + tmp_data[0] = 0xAA; + if (himax_bus_write(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi write fail!\n", __func__); + continue; + } + mdelay(1); + tmp_data[0] = 0x00; + if (himax_bus_read(0x33, 1, tmp_data) < 0) { + TPD_INFO("%s: spi read fail!\n", __func__); + continue; + } + + TPD_INFO("%s:retry %d, addr = 0x33, 0xAA = 0x%2.2X\n", + __func__, rtimes, tmp_data[0]); + rtimes++; + } while (tmp_data[0] != 0xAA); + + TPD_INFO("%s:END\n", __func__); +} + +static int hx83112f_enable_black_gesture(struct chip_data_hx83112f *chip_info, bool enable) +{ + int ret = 0; + int retry_cnt = 0; + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + uint8_t back_data[4] = {0}; + static char psensor_delay_done = 0; + + struct touchpanel_data *ts = spi_get_drvdata(chip_info->hx_spi); + + TPD_INFO("%s:enable=%d, ts->is_suspended=%d\n", __func__, enable, ts->is_suspended); + //private_ts->int_mode = UNBANNABLE; + + if (ts->is_suspended) { + if (enable) { + if (!p_sensor_rec) { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xD0; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + + do { + /*A33A : fw skip 11 29*/ + /* A55A : FW wait for 11 29*/ + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x10; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + back_data[3] = 0XA5; + back_data[2] = 0X5A; + back_data[1] = 0XA5; + back_data[0] = 0X5A; + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s: tmp_data[0] = 0x%02X, retry_cnt=%d\n", + __func__, tmp_data[0], retry_cnt); + retry_cnt++; + } while ((tmp_data[3] != back_data[3] + || tmp_data[2] != back_data[2] + || tmp_data[1] != back_data[1] + || tmp_data[0] != back_data[0]) + && retry_cnt < HIMAX_REG_RETRY_TIMES); + } + if (p_sensor_rec) { + p_sensor_rec = false; + hx83112f_enable_interrupt(chip_info, false); + +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(chip_info->hw_res, true); // reset gpio + hx83112f_resetgpio_set(chip_info->hw_res, false); // reset gpio + hx83112f_resetgpio_set(chip_info->hw_res, true); // reset gpio +#else + himax_mcu_sys_reset(); +#endif + usleep_range(2000, 2001); + himax_hx83112f_reload_to_active(); + hx83112f_enable_interrupt(chip_info, true); + } + +#ifdef CONFIG_OP_TP_APK + if (chip_info->debug_gesture_sta) + himax_gesture_debug_mode_set(true); +#endif + } else { + if (psensor_delay_done == 0) { + TPD_INFO("%s, first enter ultra \n", __func__); + msleep(100); + } + p_sensor_rec = true; + psensor_delay_done = 1; + himax_ultra_enter(); + } + } else { + g_zero_event_count = 0; + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xD0; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + //himax_sense_on(0); + psensor_delay_done = 0; + TPD_INFO("%s, psensor_delay_done=%d\n", __func__,psensor_delay_done); + } + //private_ts->int_mode = BANNABLE; + return ret; +} + +static int hx83112f_enable_charge_mode(struct chip_data_hx83112f *chip_info, bool enable) +{ + int ret = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + TPD_INFO("%s, charge mode enable = %d\n", __func__, enable); + /*Enable:0x10007F38 = 0xA55AA55A */ + if (enable) { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x38; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + } else { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x38; + tmp_data[3] = 0x77; + tmp_data[2] = 0x88; + tmp_data[1] = 0x77; + tmp_data[0] = 0x88; + himax_flash_write_burst(tmp_addr, tmp_data); + } + + return ret; +} + +/*on = 1:on 0:off */ +static int hx83112f_jitter_switch(struct chip_data_hx83112f *chip_info, bool on) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int rtimes = 0; + int ret = 0; + + TPD_INFO("%s:entering\n", __func__); + + if (!on) {//jitter off + do { + if (rtimes > 10) { + TPD_INFO("%s:retry over 10, jitter off failed!\n", __func__); + TPD_INFO("%s:0x5A, 0xA5, 0x5A, 0xA5\n", __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xE0; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_INFO("%s:retry %d, [0, 1, 2, 3] = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA5 || tmp_data[2] != 0x5A + || tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A); + TPD_INFO("%s:jitter off success!\n", __func__); + } else { //jitter on + do { + if (rtimes > 10) { + TPD_INFO("%s:retry over 10, jitter on failed!\n", __func__); + TPD_INFO("%s:correct tmp_data 0x00, 0x00, 0x00, 0x00\n", __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_INFO("%s:retry %d, current = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] == 0xA5 && tmp_data[2] == 0x5A + && tmp_data[1] == 0xA5 && tmp_data[0] == 0x5A); + TPD_INFO("%s:jitter on success!\n", __func__); + } + TPD_INFO("%s:END\n", __func__); + return ret; +} + +static int hx83112f_enable_headset_mode(struct chip_data_hx83112f *chip_info, bool enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int rtimes = 0; + int ret = 0; + //struct touchpanel_data *ts = spi_get_drvdata(chip_info->hx_spi); + + if (0) { + if (enable) {/* insert headset */ + do { + if (rtimes > 10) { + TPD_INFO("%s:insert headset failed!\n", __func__); + TPD_INFO("%s:correct data 0x5A, 0xA5, 0x5A, 0xA5\n", __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xE8; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_DETAIL("%s:retry %d, current [0, 1, 2, 3] = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA5 || tmp_data[2] != 0x5A + || tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A); + + TPD_INFO("%s:insert headset success!\n", __func__); + } else {/* remove headset */ + do { + if (rtimes > 10) { + TPD_INFO("%s:remove headset failed!\n", __func__); + TPD_INFO("%s:correct 0x5A, 0xA5, 0x5A, 0xA5\n", __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xE8; + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_DETAIL("%s:retry %d, current [0, 1, 2, 3] = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0x00 || tmp_data[2] != 0x00 + || tmp_data[1] != 0x00 || tmp_data[0] != 0x00); + + TPD_INFO("%s:remove headset success!\n", __func__); + } + } + return ret; +} + +//mode = 0:off 1:normal 2:turn right 3:turn left +static int hx83112f_rotative_switch(struct chip_data_hx83112f *chip_info, int mode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int rtimes = 0; + int ret = 0; + struct touchpanel_data *ts = spi_get_drvdata(chip_info->hx_spi); + + TPD_INFO("fw_edge = %d, mode = %d.ts->limit_switch = %d\n", ts->fw_edge_limit_support, mode, ts->limit_switch); + if (ts->fw_edge_limit_support) { + if (ts->limit_switch == 0 && VERTICAL_SCREEN == chip_info->touch_direction) {/* vertical */ + do { + if (rtimes > 10) { + TPD_INFO("%s:rotative normal failed!\n", __func__); + TPD_INFO("%s: [0, 1, 2, 3] = 0x5A, 0xA5, 0x5A, 0xA5\n", + __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x3C; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s:retry %d, [0, 1, 2, 3] = x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA5 || tmp_data[2] != 0x5A + || tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A); + + TPD_INFO("%s:rotative normal success!\n", __func__); + + } else { + rtimes = 0; + if (ts->limit_switch == 3 || chip_info->touch_direction == LANDSCAPE_SCREEN_270) { //turn right + do { + if (rtimes > 10) { + TPD_INFO("%s:rotative right failed!\n", __func__); + TPD_INFO("%s:[0, 1, 2, 3] = 0x3A, 0xA3, 0x3A, 0xA3\n", __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x3C; + tmp_data[3] = 0xA3; + tmp_data[2] = 0x3A; + tmp_data[1] = 0xA3; + tmp_data[0] = 0x3A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_INFO("%s:retry %d, [0, 1, 2, 3] = x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA3 || tmp_data[2] != 0x3A + || tmp_data[1] != 0xA3 || tmp_data[0] != 0x3A); + + TPD_INFO("%s:rotative right success!\n", __func__); + + } else if (ts->limit_switch == 1) { //turn left + do { + if (rtimes > 10) { + TPD_INFO("%s:rotative left failed!\n", __func__); + TPD_INFO("%s:correct [0, 1, 2, 3] = x1A, 0xA1, 0x1A, 0xA1\n", + __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x3C; + tmp_data[3] = 0xA1; + tmp_data[2] = 0x1A; + tmp_data[1] = 0xA1; + tmp_data[0] = 0x1A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + + TPD_INFO("%s:retry%d, [0, 1, 2, 3] = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA1 || tmp_data[2] != 0x1A + || tmp_data[1] != 0xA1 || tmp_data[0] != 0x1A); + + TPD_INFO("%s:rotative left success!\n", __func__); + + } + } + } else { + if (mode) {//open + do { + if (rtimes > 10) { + TPD_INFO("%s:open edge limit failed!\n", __func__); + TPD_INFO("%s:correct [0, 1, 2, 3] = 0x5A, 0xA5, 0x5A, 0xA5\n", + __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x3C; + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s:retry %d, current[0, 1, 2, 3] = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA5 || tmp_data[2] != 0x5A + || tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A); + + TPD_INFO("%s:open edge limit success!\n", __func__); + + } else {//close + do { + if (rtimes > 10) { + TPD_INFO("%s:close edge limit failed!\n", __func__); + TPD_INFO("%s:correct tmp_data[0, 1, 2, 3] =0x9A, 0xA9, 0x9A, 0xA9\n", + __func__); + ret = -1; + break; + } + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0x3C; + tmp_data[3] = 0xA9; + tmp_data[2] = 0x9A; + tmp_data[1] = 0xA9; + tmp_data[0] = 0x9A; + himax_flash_write_burst(tmp_addr, tmp_data); + + himax_register_read(tmp_addr, 4, tmp_data, false); + TPD_INFO("%s:retry %d,tmp[0, 1, 2, 3] = 0x%2.2X, 0x%2.2X, 0x%2.2X, 0x%2.2X\n", + __func__, rtimes, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + rtimes++; + } while (tmp_data[3] != 0xA9 || tmp_data[2] != 0x9A + || tmp_data[1] != 0xA9 || tmp_data[0] != 0x9A); + + TPD_INFO("%s:close edge limit success!\n", __func__); + } + } + TPD_INFO("%s:END\n", __func__); + return ret; +} + +static int hx83112f_mode_switch(void *chip_data, work_mode mode, bool flag) +{ + int ret = -1; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + switch (mode) { + case MODE_NORMAL: + ret = 0; + break; + + case MODE_SLEEP: + if (!p_sensor_rec) { + TPD_INFO("%s, enter sleep mode.\n", __func__); + himax_sense_off(); + } + ret = 0; + break; + + case MODE_GESTURE_SWITCH: + case MODE_GESTURE: + ret = hx83112f_enable_black_gesture(chip_info, flag); + if (ret < 0) { + TPD_INFO("%s: hx83112f enable gesture failed.\n", __func__); + return ret; + } + break; + + case MODE_GLOVE: + break; + + case MODE_EDGE: + //ret = hx83112f_enable_edge_limit(chip_info, flag); + ret = hx83112f_rotative_switch(chip_info, flag); + + if (ret < 0) { + TPD_INFO("%s: hx83112f enable edg & corner limit failed.\n", __func__); + return ret; + } + break; + + case MODE_CHARGE: + ret = hx83112f_enable_charge_mode(chip_info, flag); + if (ret < 0) + TPD_INFO("%s: enable charge mode : %d failed\n", __func__, flag); + break; + + case MODE_HEADSET: + ret = hx83112f_enable_headset_mode(chip_info, flag); + if (ret < 0) + TPD_INFO("%s: enable headset mode : %d failed\n", __func__, flag); + break; + + case MODE_GAME: + ret = hx83112f_jitter_switch(chip_info, !flag); + if (ret < 0) + TPD_INFO("%s: enable game mode : %d failed\n", __func__, !flag); + break; + + default: + TPD_INFO("%s: Wrong mode.\n", __func__); + } + + return ret; +} + +static int hx83112f_get_gesture_info(void *chip_data, struct gesture_info *gesture) +{ + int i = 0; + int gesture_sign = 0; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + uint8_t *buf; + int gest_len; + int check_FC = 0; + + int check_sum_cal; + int ts_status = HX_REPORT_SMWP_EVENT; + + //TPD_DEBUG("%s:%d\n", __func__, __LINE__); + + buf = kcalloc(hx_touch_data->event_size, sizeof(uint8_t), GFP_KERNEL); + if (!buf) { + TPD_INFO("%s:%d kzalloc buf error\n", __func__, __LINE__); + return -EINVAL; + } + + himax_burst_enable(0); + if (!himax_read_event_stack(buf, hx_touch_data->event_size)) { + TPD_INFO("%s: can't read data from chip in gesture!\n", __func__); + kfree(buf); + return -EINVAL; + } + + for (i = 0; i < 128; i++) { + if (!i) + TPD_DETAIL(KERN_CONT "%s: gesture buf data\n", __func__); + + + if (i % 8 == 0) + TPD_DETAIL(KERN_CONT "[himax]"); + + TPD_DETAIL(KERN_CONT "%02d ", buf[i]); + + if ((i + 1) % 8 == 0) + TPD_DETAIL(KERN_CONT "\n"); + + if (i == (128 - 1)) + TPD_DETAIL(KERN_CONT "\n"); + } + + check_sum_cal = himax_checksum_cal(chip_info, buf, ts_status); + if (check_sum_cal == CHECKSUM_FAIL) + return -EINVAL; + else if (check_sum_cal == ERR_WORK_OUT) + goto err_workqueue_out; + + for (i = 0; i < 4; i++) { + if (check_FC == 0) { + if ((buf[0] != 0x00) && ((buf[0] < 0x10))) { + check_FC = 1; + gesture_sign = buf[i]; + } else { + check_FC = 0; + //TPD_DEBUG("ID START at %x , value = %x skip the event\n", i, buf[i]); + break; + } + } else { + if (buf[i] != gesture_sign) { + check_FC = 0; + break; + } + } + //TPD_DEBUG("0x%2.2X ", buf[i]); + } + //TPD_DEBUG("Himax gesture_sign= %x\n",gesture_sign ); + //TPD_DEBUG("Himax check_FC is %d\n", check_FC); + + if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 || + buf[GEST_PTLG_ID_LEN + 1] != GEST_PTLG_HDR_ID2) { + goto RET_OUT; + } + + if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 && + buf[GEST_PTLG_ID_LEN + 1] == GEST_PTLG_HDR_ID2) { + gest_len = buf[GEST_PTLG_ID_LEN + 2]; + if (gest_len > 52) + gest_len = 52; + i = 0; + gest_pt_cnt = 0; + //TPD_DEBUG("gest doornidate start %s\n",__func__); +#ifdef CONFIG_OP_TP_APK + if (check_point_format == 0) { +#endif + while (i < (gest_len + 1) / 2) { + if (i == 6) { + gest_pt_x[gest_pt_cnt] = buf[GEST_PTLG_ID_LEN + 4 + i * 2]; + } else { + gest_pt_x[gest_pt_cnt] = buf[GEST_PTLG_ID_LEN + 4 + i * 2] + * private_ts->resolution_info.max_x / 255; + } + gest_pt_y[gest_pt_cnt] = buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1] + * private_ts->resolution_info.max_y / 255; + i++; + //TPD_DEBUG("gest_pt_x[%d]=%d\n",gest_pt_cnt,gest_pt_x[gest_pt_cnt]); + //TPD_DEBUG("gest_pt_y[%d]=%d\n",gest_pt_cnt,gest_pt_y[gest_pt_cnt]); + gest_pt_cnt += 1; + } +#ifdef CONFIG_OP_TP_APK + } else { + int j = 0; + int nn; + int n = 24; + int m = 26; + int pt_num; + + gest_pt_cnt = 40; + if (private_ts->gesture_buf) { + pt_num = gest_len + buf[126]; + if (pt_num > 104) + pt_num = 104; + + private_ts->gesture_buf[0] = gesture_sign; + private_ts->gesture_buf[1] = buf[127]; + + if (private_ts->gesture_buf[0] == 0x07) { + for (j = 0; j < gest_len * 2; j = j + 2) { + private_ts->gesture_buf[3 + j] = buf[n]; + private_ts->gesture_buf[3 + j + 1] = buf[n + 1]; + n = n + 4; + } + + for (nn = 0; nn < (pt_num - gest_len) * 2 ; nn = nn + 2) { + private_ts->gesture_buf[3 + j + nn] = buf[m]; + private_ts->gesture_buf[3 + j + nn + 1] = buf[m + 1]; + m = m + 4; + } + private_ts->gesture_buf[2] = pt_num; + } else { + private_ts->gesture_buf[2] = gest_len; + memcpy(&private_ts->gesture_buf[3], &buf[24], 80); + } + } + } +#endif + + if (gest_pt_cnt) { + gesture->gesture_type = gesture_sign;/* id */ + gesture->Point_start.x = gest_pt_x[0];/* start x */ + gesture->Point_start.y = gest_pt_y[0];/* start y */ + gesture->Point_end.x = gest_pt_x[1];/* end x */ + gesture->Point_end.y = gest_pt_y[1];/* end y */ + gesture->Point_1st.x = gest_pt_x[2]; /* 1 */ + gesture->Point_1st.y = gest_pt_y[2]; + gesture->Point_2nd.x = gest_pt_x[3];/* 2 */ + gesture->Point_2nd.y = gest_pt_y[3]; + gesture->Point_3rd.x = gest_pt_x[4];/* 3 */ + gesture->Point_3rd.y = gest_pt_y[4]; + gesture->Point_4th.x = gest_pt_x[5];/* 4 */ + gesture->Point_4th.y = gest_pt_y[5]; + gesture->clockwise = gest_pt_x[6]; /* 1, 0 */ + } + } + +RET_OUT: + kfree(buf); + return 0; + +err_workqueue_out: + //himax_ic_reset(chip_info, false, true); + return -EINVAL; +} + +static int hx83112f_power_control(void *chip_data, bool enable) +{ + int ret = 0; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + if (true == enable) { + ret = tp_powercontrol_2v8(chip_info->hw_res, true); + if (ret) + return -EINVAL; + ret = tp_powercontrol_1v8(chip_info->hw_res, true); + if (ret) + return -EINVAL; +#ifdef HX_RST_PIN_FUNC + ret = hx83112f_resetgpio_set(chip_info->hw_res, true); + if (ret) + return -EINVAL; +#endif + } else { +#ifdef HX_RST_PIN_FUNC + ret = hx83112f_resetgpio_set(chip_info->hw_res, false); + if (ret) + return -EINVAL; +#endif + ret = tp_powercontrol_1v8(chip_info->hw_res, false); + if (ret) + return -EINVAL; + ret = tp_powercontrol_2v8(chip_info->hw_res, false); + if (ret) + return -EINVAL; + } + return ret; +} + +static int hx83112f_int_pin_test(struct seq_file *s, void *chip_data, + struct syna_testdata *syna_testdata, char *g_Test_list_log) +{ + int eint_status, eint_count = 0, read_gpio_num = 10; + + TPD_INFO("%s, step 0: begin to check INT-GND short item\n", __func__); + while (read_gpio_num--) { + mdelay(20); + eint_status = gpio_get_value(syna_testdata->irq_gpio); + if (eint_status == 1) + eint_count--; + else + eint_count++; + TPD_INFO("%s eint_count = %d eint_status = %d\n", __func__, eint_count, eint_status); + } + TPD_INFO("TP EINT PIN direct short! eint_count = %d\n", eint_count); + if (eint_count == 10) { + TPD_INFO("error : TP EINT PIN direct short!\n"); + seq_puts(s, "TP EINT direct stort\n"); + hx83112f_nf_fail_write_count += + snprintf(g_Test_list_log + hx83112f_nf_fail_write_count, + 45, "eint_status is low, TP EINT direct stort\n"); + //store_to_file(syna_testdata->fd, "eint_status is low, TP EINT direct stort,\n"); + eint_count = 0; + return TEST_FAIL; + } + + return TEST_PASS; +} + +static void hx83112f_auto_test(struct seq_file *s, void *chip_data, struct syna_testdata *syna_testdata) +{ + int error_count = 0; + int ret = THP_AFE_INSPECT_OK; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + char *p_node = NULL; + char *fw_name_test = NULL; + char *postfix = "_TEST.img"; + uint8_t copy_len = 0; + struct timespec now_time; + struct rtc_time rtc_now_time; + char g_file_name_OK[64]; + char g_file_name_NG[64]; + char *g_Test_list_log = NULL; + char *g_project_test_info_log = NULL; + char *g_Company_info_log = NULL; + int i = 0; + + g_rslt_data_len = 0; + fw_name_test = kzalloc(MAX_FW_NAME_LENGTH, GFP_KERNEL); + if (fw_name_test == NULL) { + TPD_INFO("fw_name_test kzalloc error!\n"); + goto RET_OUT; + } + + /*init criteria data*/ + ret = himax_self_test_data_init(chip_info); + /*init criteria data*/ + + /*Init Log Data */ + g_1kind_raw_size = 5 * chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM * 2; + g_Company_info_log = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_Company_info_log) { + TPD_INFO("%s:%d g_Company_info_log kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + g_Test_list_log = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_Test_list_log) { + TPD_INFO("%s:%d g_Test_list_log kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + g_project_test_info_log = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_project_test_info_log) { + TPD_INFO("%s:%d g_project_test_info_log kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + hx83112f_nf_fail_write_count = 0; + g_file_path_OK = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_file_path_OK) { + TPD_INFO("%s:%d g_file_path_OK kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + g_file_path_NG = kcalloc(256, sizeof(char), GFP_KERNEL); + if (!g_file_path_NG) { + TPD_INFO("%s:%d g_file_path_NG kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + + if (g_rslt_data == NULL) { + TPD_INFO("g_rslt_data is NULL"); + g_rslt_data = kcalloc(g_1kind_raw_size * HX_CRITERIA_ITEM, + sizeof(char), GFP_KERNEL); + if (!g_rslt_data) { + TPD_INFO("%s:%d g_rslt_data kzalloc buf error\n", __func__, __LINE__); + goto RET_OUT; + } + } else { + memset(g_rslt_data, 0x00, g_1kind_raw_size * HX_CRITERIA_ITEM * + sizeof(char)); + } + /*Init Log Data */ + + p_node = strnstr(private_ts->panel_data.fw_name, ".", MAX_FW_NAME_LENGTH); + copy_len = p_node - private_ts->panel_data.fw_name; + memcpy(fw_name_test, private_ts->panel_data.fw_name, copy_len); + strlcat(fw_name_test, postfix, MAX_FW_NAME_LENGTH); + TPD_INFO("%s : fw_name_test is %s\n", __func__, fw_name_test); + + himax_mcu_0f_operation_test_dirly(fw_name_test); + mdelay(20); + g_core_fp.fp_reload_disable(); + mdelay(20); + himax_sense_on(0x00); + himax_check_remapping(); + himax_read_OP_FW_ver(chip_info); + + error_count += hx83112f_int_pin_test(s, chip_info, syna_testdata, g_Test_list_log); + error_count += himax_chip_self_test(s, chip_info, g_Test_list_log); + /*Save Log Data */ + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + snprintf(g_file_name_OK, sizeof(g_file_name_OK), "tp_testlimit_OK_%02d%02d%02d-%02d%02d%02d-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + snprintf(g_file_name_NG, sizeof(g_file_name_NG), "tp_testlimit_NG_%02d%02d%02d-%02d%02d%02d-utc.csv", + (rtc_now_time.tm_year + 1900) % 100, rtc_now_time.tm_mon + 1, rtc_now_time.tm_mday, + rtc_now_time.tm_hour, rtc_now_time.tm_min, rtc_now_time.tm_sec); + + if (error_count) { + snprintf(g_file_path_NG, + (int)(strlen(HX_RSLT_OUT_PATH_NG) + strlen(g_file_name_NG) + 1), + "%s%s", HX_RSLT_OUT_PATH_NG, g_file_name_NG); + hx_test_data_pop_out(chip_info, g_Test_list_log, g_Company_info_log, + g_project_test_info_log, g_rslt_data, g_file_path_NG); + + } else { + snprintf(g_file_path_OK, + (int)(strlen(HX_RSLT_OUT_PATH_OK) + strlen(g_file_name_OK) + 1), + "%s%s", HX_RSLT_OUT_PATH_OK, g_file_name_OK); + hx_test_data_pop_out(chip_info, g_Test_list_log, g_Company_info_log, + g_project_test_info_log, g_rslt_data, g_file_path_OK); + } + /*Save Log Data */ + + //seq_printf(s, "imageid = 0x%llx, deviceid = 0x%llx\n", syna_testdata->TP_FW, syna_testdata->TP_FW); + seq_printf(s, "%s\n", error_count ? "result=0" : "result=1"); + TPD_INFO(" TP auto test %d error(s). %s\n", error_count, error_count ? "" : "result=1"); + +RET_OUT: + kfree(fw_name_test); + fw_name_test = NULL; + + if (hx83112f_nf_inspection_criteria != NULL) { + for (i = 0; i < HX_CRITERIA_SIZE; i++) { + if (hx83112f_nf_inspection_criteria[i] != NULL) { + kfree(hx83112f_nf_inspection_criteria[i]); + hx83112f_nf_inspection_criteria[i] = NULL; + } + } + kfree(hx83112f_nf_inspection_criteria); + hx83112f_nf_inspection_criteria = NULL; + TPD_INFO("Now it have free the hx83112f_nf_inspection_criteria!\n"); + } else { + TPD_INFO("No Need to free hx83112f_nf_inspection_criteria!\n"); + } + kfree(hx83112f_nf_inspt_crtra_flag); + kfree(g_file_path_OK); + kfree(g_file_path_NG); + kfree(g_Test_list_log); + kfree(g_project_test_info_log); + kfree(g_Company_info_log); + + hx83112f_nf_inspt_crtra_flag = NULL; + g_file_path_OK = NULL; + g_file_path_NG = NULL; + g_Test_list_log = NULL; + g_project_test_info_log = NULL; + g_Company_info_log = NULL; +} + +static void hx83112f_read_debug_data(struct seq_file *s, void *chip_data, int debug_data_type) +{ + uint16_t mutual_num; + uint16_t self_num; + uint16_t width; + int i = 0; + int j = 0; + int k = 0; + int32_t *data_mutual_sram; + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + if (!chip_info) + return; + + data_mutual_sram = kzalloc(chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM * sizeof(int32_t), GFP_KERNEL); + if (!data_mutual_sram) + goto RET_OUT; + + mutual_num = chip_info->hw_res->TX_NUM * chip_info->hw_res->RX_NUM; + self_num = chip_info->hw_res->TX_NUM + chip_info->hw_res->RX_NUM; //don't add KEY_COUNT + width = chip_info->hw_res->RX_NUM; + seq_printf(s, "ChannelStart (rx tx) : %4d, %4d\n\n", chip_info->hw_res->RX_NUM, chip_info->hw_res->TX_NUM); + + //start to show debug data + switch (debug_data_type) { + case DEBUG_DATA_BASELINE: + seq_puts(s, "Baseline data:\n"); + TPD_INFO("Baseline data:\n"); + break; + + case DEBUG_DATA_RAW: + seq_puts(s, "Raw data:\n"); + TPD_INFO("Raw data:\n"); + break; + + case DEBUG_DATA_DELTA: + seq_puts(s, "Delta data:\n"); + TPD_INFO("Delta data:\n"); + break; + + case DEBUG_DATA_DOWN: + seq_puts(s, "Finger down data:\n"); + TPD_INFO("Finger down data:\n"); + break; + + default: + seq_puts(s, "No this debug datatype\n"); + TPD_INFO("No this debug datatype\n"); + goto RET_OUT; + } + if (debug_data_type == DEBUG_DATA_DOWN) { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xF8; + + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_register_write(tmp_addr, 4, tmp_data, 0); + himax_diag_register_set(DEBUG_DATA_DELTA); + } else { + himax_diag_register_set(debug_data_type); + } + TPD_INFO("%s: Start get debug data in DSRAM\n", __func__); + DSRAM_Flag = true; + + himax_ts_diag_func(chip_info, data_mutual_sram); + + for (j = 0; j < chip_info->hw_res->RX_NUM; j++) { + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) { + k = ((mutual_num - j) - chip_info->hw_res->RX_NUM * i) - 1; + seq_printf(s, "%6d", data_mutual_sram[k]); + } + seq_printf(s, " %6d\n", diag_self[j]); + } + + seq_puts(s, "\n"); + for (i = 0; i < chip_info->hw_res->TX_NUM; i++) + seq_printf(s, "%6d", diag_self[i]); + //Clear DSRAM flag + himax_diag_register_set(0x00); + DSRAM_Flag = false; + himax_return_event_stack(); + + seq_puts(s, "\n"); + seq_puts(s, "ChannelEnd"); + seq_puts(s, "\n"); + + TPD_INFO("%s, here:%d\n", __func__, __LINE__); + + if (debug_data_type == DEBUG_DATA_DOWN) { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xF8; + + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = 0x00; + himax_register_write(tmp_addr, 4, tmp_data, 0); + } + +RET_OUT: + kfree(data_mutual_sram); +} + +static void hx83112f_baseline_read(struct seq_file *s, void *chip_data) +{ + hx83112f_read_debug_data(s, chip_data, DEBUG_DATA_BASELINE); + hx83112f_read_debug_data(s, chip_data, DEBUG_DATA_RAW); +} + +static void hx83112f_delta_read(struct seq_file *s, void *chip_data) +{ + + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + hx83112f_read_debug_data(s, chip_data, DEBUG_DATA_DELTA); +#ifdef CONFIG_OP_TP_APK + if (chip_info->debug_mode_sta) + hx83112f_read_debug_data(s, chip_data, DEBUG_DATA_DOWN); +#endif +} + +static void hx83112f_main_register_read(struct seq_file *s, void *chip_data) +{ +} + +//Reserved node +static void hx83112f_reserve_read(struct seq_file *s, void *chip_data) +{ +} + +static fw_update_state hx83112f_fw_update(void *chip_data, const struct firmware *fw, bool force) +{ + uint32_t CURRENT_FIRMWARE_ID = 0, FIRMWARE_ID = 0; + uint8_t cmd[4]; + uint8_t data[64]; + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + const uint8_t *p_fw_id = NULL; + + if (fw) { + if (chip_info->g_fw_buf) { + chip_info->g_fw_len = fw->size; + memcpy(chip_info->g_fw_buf, fw->data, fw->size); + chip_info->g_fw_sta = true; + } + } + if (fw == NULL) { + TPD_INFO("fw is NULL\n"); + return FW_NO_NEED_UPDATE; + } + + p_fw_id = fw->data + 12414; + + if (!chip_info) { + TPD_INFO("Chip info is NULL\n"); + return 0; + } + + TPD_INFO("%s is called\n", __func__); + + //step 1:fill Fw related header, get all data. + + + //step 2:Get FW version from IC && determine whether we need get into update flow. + + CURRENT_FIRMWARE_ID = (*p_fw_id << 24) | (*(p_fw_id + 1) << 16) | (*(p_fw_id + 2) << 8) | *(p_fw_id + 3); + + + cmd[3] = 0x10; + cmd[2] = 0x00; + cmd[1] = 0x70; + cmd[0] = 0x14; + himax_register_read(cmd, 4, data, false); + FIRMWARE_ID = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + TPD_INFO("CURRENT TP FIRMWARE ID is 0x%x, FIRMWARE IMAGE ID is 0x%x\n", CURRENT_FIRMWARE_ID, FIRMWARE_ID); + + //disable_irq_nosync(chip_info->hx_irq); + + //step 3:Get into program mode + /********************get into prog end************/ + //step 4:flash firmware zone + TPD_INFO("update-----------------firmware ------------------update!\n"); + // fts_ctpm_fw_upgrade_with_sys_fs_64k((unsigned char *)fw->data, fw->size, false); + himax_mcu_firmware_update_0f(fw); + g_core_fp.fp_reload_disable(); + mdelay(20); + + TPD_INFO("Firmware && configuration flash over\n"); + himax_read_OP_FW_ver(chip_info); + himax_sense_on(0x00); + himax_check_remapping(); + mdelay(20); + + // enable_irq(chip_info->hx_irq); + hx83112f_enable_interrupt(chip_info, true); + // hx83112f_reset(chip_info); + // mdelay(200); + + chip_info->first_download_finished = true; + return FW_UPDATE_SUCCESS; +} + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + extern unsigned int upmu_get_rgs_chrdet(void); +static int hx83112f_get_usb_state(void) +{ + return upmu_get_rgs_chrdet(); +} +#else +static int hx83112f_get_usb_state(void) +{ + return 0; +} +#endif + + +static int hx83112f_reset_gpio_control(void *chip_data, bool enable) +{ + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + if (gpio_is_valid(chip_info->hw_res->reset_gpio)) { + TPD_INFO("%s: set reset state %d\n", __func__, enable); +#ifdef HX_RST_PIN_FUNC + hx83112f_resetgpio_set(g_chip_info->hw_res, enable); +#endif + TPD_DETAIL("%s: set reset state END\n", __func__); + } + return 0; +} + +static void hx83112f_set_touch_direction(void *chip_data, uint8_t dir) +{ + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + chip_info->touch_direction = dir; +} + +static uint8_t hx83112f_get_touch_direction(void *chip_data) +{ + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + return chip_info->touch_direction; +} + +static int himax_enable_single_tap(void *chip_data, bool enable) +{ + struct chip_data_hx83112f *chip_info = (struct chip_data_hx83112f *)chip_data; + + chip_info->single_tap_flag = enable; + return 0; +} + +static struct touchpanel_operations hx83112f_ops = { + .ftm_process = hx83112f_ftm_process, + .get_vendor = hx83112f_get_vendor, + .get_chip_info = hx83112f_get_chip_info, + .reset = hx83112f_reset, + .power_control = hx83112f_power_control, + .fw_check = hx83112f_fw_check, + .fw_update = hx83112f_fw_update, + .trigger_reason = hx83112f_trigger_reason, + .get_touch_points = hx83112f_get_touch_points, + .get_gesture_info = hx83112f_get_gesture_info, + .mode_switch = hx83112f_mode_switch, + .exit_esd_mode = hx83112f_exit_esd_mode, + //.resume_prepare = hx83112f_resume_prepare, + .get_usb_state = hx83112f_get_usb_state, + .black_screen_test = hx83112f_black_screen_test, + .reset_gpio_control = hx83112f_reset_gpio_control, + .set_touch_direction = hx83112f_set_touch_direction, + .get_touch_direction = hx83112f_get_touch_direction, + .enable_single_tap = himax_enable_single_tap, + /*Himax_DB_Test Start*/ + // .freq_hop_trigger = hx83112f_freq_hop_trigger, + /*Himax_DB_Test End*/ +}; + +static struct himax_proc_operations hx83112f_proc_ops = { + .auto_test = hx83112f_auto_test, + .himax_proc_register_write = hx83112f_proc_register_write, + .himax_proc_register_read = hx83112f_proc_register_read, + .himax_proc_diag_write = hx83112f_proc_diag_write, + .himax_proc_diag_read = hx83112f_proc_diag_read, + .himax_proc_reset_write = hx83112f_proc_reset_write, + .himax_proc_sense_on_off_write = hx83112f_proc_sense_on_off_write, + .himax_proc_vendor_read = hx83112f_proc_vendor_read, + .fp_hx_limit_get = himax_limit_get, +#ifdef HX_ENTER_ALGORITHM_NUMBER + //.himax_proc_enter_algorithm_switch_write = himax_enter_algorithm_number_write, + //.himax_proc_enter_algorithm_switch_read = himax_enter_algorithm_number_read, +#endif +}; + +static struct debug_info_proc_operations debug_info_proc_ops = { + .limit_read = himax_limit_read, + .delta_read = hx83112f_delta_read, + .baseline_read = hx83112f_baseline_read, + .main_register_read = hx83112f_main_register_read, + .reserve_read = hx83112f_reserve_read, +}; + +#ifdef CONFIG_OP_TP_APK + +static void himax_enter_hopping_write(bool on_off) +{ + uint8_t tmp_addr[4] = {0}; + uint8_t tmp_data[4] = {0}; + + if (on_off) { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xF8; + + tmp_data[3] = 0xA5; + tmp_data[2] = 0x5A; + tmp_data[1] = 0xA5; + tmp_data[0] = 0x5A; + himax_register_write(tmp_addr, 4, tmp_data, 0); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xC4; + + tmp_data[3] = 0xA1; + tmp_data[2] = 0x1A; + tmp_data[1] = 0xA1; + tmp_data[0] = 0x1A; + himax_register_write(tmp_addr, 4, tmp_data, 0); + TPD_INFO("%s: open himax enter hopping write.\n", __func__); + } else { + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xF8; + + tmp_data[3] = 0; + tmp_data[2] = 0; + tmp_data[1] = 0; + tmp_data[0] = 0; + himax_register_write(tmp_addr, 4, tmp_data, 0); + + tmp_addr[3] = 0x10; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x7F; + tmp_addr[0] = 0xC4; + + tmp_data[3] = 0; + tmp_data[2] = 0; + tmp_data[1] = 0; + tmp_data[0] = 0; + himax_register_write(tmp_addr, 4, tmp_data, 0); + + TPD_INFO("%s: close himax hopping write.\n", __func__); + } + +} + + +static void himax_apk_game_set(void *chip_data, bool on_off) +{ + hx83112f_mode_switch(chip_data, MODE_GAME, on_off); +} + +static bool himax_apk_game_get(void *chip_data) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + return chip_info->lock_point_status; +} + +static void himax_apk_debug_set(void *chip_data, bool on_off) +{ + //u8 cmd[1]; + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + himax_debug_mode_set(on_off); + chip_info->debug_mode_sta = on_off; +} + +static bool himax_apk_debug_get(void *chip_data) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + return chip_info->debug_mode_sta; +} + +static void himax_apk_gesture_debug(void *chip_data, bool on_off) +{ + + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + //get_gesture_fail_reason(on_off); + chip_info->debug_gesture_sta = on_off; +} + +static bool himax_apk_gesture_get(void *chip_data) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + return chip_info->debug_gesture_sta; +} + +static int himax_apk_gesture_info(void *chip_data, char *buf, int len) +{ + int ret = 0; + int i; + int num; + u8 temp; + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + + if (len < 2) + return 0; + + buf[0] = 255; + + temp = private_ts->gesture_buf[0]; + if (temp == 0x00) + temp = private_ts->gesture_buf[1] | 0x80; + + buf[0] = temp; + + //buf[0] = gesture_buf[0]; + num = private_ts->gesture_buf[2]; + + if (num > 40) + num = 40; + + ret = 2; + + buf[1] = num; + //print all data + for (i = 0; i < num; i++) { + int x; + int y; + + x = private_ts->gesture_buf[i * 2 + 3]; + x = x * private_ts->resolution_info.max_x / 255; + + y = private_ts->gesture_buf[i * 2 + 4]; + y = y * private_ts->resolution_info.max_y / 255; + + + //TPD_INFO("nova_apk_gesture_info:gesture x is %d,y is %d.\n", x, y); + if (len < i * 4 + 2) + break; + + buf[i * 4 + 2] = x & 0xFF; + buf[i * 4 + 3] = (x >> 8) & 0xFF; + buf[i * 4 + 4] = y & 0xFF; + buf[i * 4 + 5] = (y >> 8) & 0xFF; + ret += 4; + + } + + return ret; +} + + +static void himax_apk_earphone_set(void *chip_data, bool on_off) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + hx83112f_mode_switch(chip_data, MODE_HEADSET, on_off); + chip_info->earphone_sta = on_off; +} + +static bool himax_apk_earphone_get(void *chip_data) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + return chip_info->earphone_sta; +} + +static void himax_apk_charger_set(void *chip_data, bool on_off) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + hx83112f_mode_switch(chip_data, MODE_CHARGE, on_off); + chip_info->plug_status = on_off; + +} + +static bool himax_apk_charger_get(void *chip_data) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + return chip_info->plug_status; + +} + +static void himax_apk_noise_set(void *chip_data, bool on_off) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + himax_enter_hopping_write(on_off); + chip_info->noise_sta = on_off; + +} + +static bool himax_apk_noise_get(void *chip_data) +{ + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + + return chip_info->noise_sta; + +} + + +static int himax_apk_tp_info_get(void *chip_data, char *buf, int len) +{ + int ret; + struct chip_data_hx83112f *chip_info; + + chip_info = (struct chip_data_hx83112f *)chip_data; + ret = snprintf(buf, len, "IC:HIMAX%06X\nFW_VER:0x%04X\nCH:%dX%d\n", + 0x83112F, + chip_info->fw_ver, + chip_info->hw_res->TX_NUM, + chip_info->hw_res->RX_NUM); + if (ret > len) + ret = len; + return ret; +} + +static void himax_init_op_apk_op(struct touchpanel_data *ts) +{ + ts->apk_op = kzalloc(sizeof(APK_OPERATION), GFP_KERNEL); + if (ts->apk_op) { + ts->apk_op->apk_game_set = himax_apk_game_set; + ts->apk_op->apk_game_get = himax_apk_game_get; + ts->apk_op->apk_debug_set = himax_apk_debug_set; + ts->apk_op->apk_debug_get = himax_apk_debug_get; + //apk_op->apk_proximity_set = ili_apk_proximity_set; + //apk_op->apk_proximity_dis = ili_apk_proximity_dis; + ts->apk_op->apk_noise_set = himax_apk_noise_set; + ts->apk_op->apk_noise_get = himax_apk_noise_get; + ts->apk_op->apk_gesture_debug = himax_apk_gesture_debug; + ts->apk_op->apk_gesture_get = himax_apk_gesture_get; + ts->apk_op->apk_gesture_info = himax_apk_gesture_info; + ts->apk_op->apk_earphone_set = himax_apk_earphone_set; + ts->apk_op->apk_earphone_get = himax_apk_earphone_get; + ts->apk_op->apk_charger_set = himax_apk_charger_set; + ts->apk_op->apk_charger_get = himax_apk_charger_get; + ts->apk_op->apk_tp_info_get = himax_apk_tp_info_get; + //apk_op->apk_data_type_set = ili_apk_data_type_set; + //apk_op->apk_rawdata_get = ili_apk_rawdata_get; + //apk_op->apk_diffdata_get = ili_apk_diffdata_get; + //apk_op->apk_basedata_get = ili_apk_basedata_get; + //ts->apk_op->apk_backdata_get = nova_apk_backdata_get; + //apk_op->apk_debug_info = ili_apk_debug_info; + } else { + TPD_INFO("Can not kzalloc apk op.\n"); + } +} +#endif + +static int check_dt(struct device_node *np) +{ + int i; + int count; + struct device_node *node; + struct drm_panel *panel; + + count = of_count_phandle_with_args(np, "panel", NULL); + TPD_INFO("count is %d\n", count); + if (count <= 0) + return -ENODEV; + + for (i = 0; i < count; i++) { + node = of_parse_phandle(np, "panel", i); + TPD_INFO("node name is %s\n", node->name); + panel = of_drm_find_panel(node); + if (!IS_ERR(panel)) { + //get_lcd_name(node->name); + tp_active_panel = panel; + lcd_active_panel = panel; + return 0; + } + of_node_put(node); + TPD_INFO("%s: error3\n", __func__); + } + + return -ENODEV; +} + +static int hx83112f_tp_probe(struct spi_device *spi) +{ + struct chip_data_hx83112f *chip_info = NULL; + struct touchpanel_data *ts = NULL; + struct device_node *dp = spi->dev.of_node; + int ret = -1; + + TPD_INFO("%s is called\n", __func__); + ret = check_dt(dp); + if (ret != 0) { + ret = -EPROBE_DEFER; + TPD_INFO("check dt failed ret is %d\n", ret); + return ret; + } + + //step1:Alloc chip_info + chip_info = kzalloc(sizeof(struct chip_data_hx83112f), GFP_KERNEL); + if (chip_info == NULL) { + TPD_INFO("chip info kzalloc error\n"); + ret = -ENOMEM; + return ret; + } + //memset(chip_info, 0, sizeof(*chip_info)); + g_chip_info = chip_info; + + /* allocate himax report data */ + hx_touch_data = kzalloc(sizeof(struct himax_report_data), GFP_KERNEL); + if (hx_touch_data == NULL) + goto err_register_driver; + + //step2:Alloc common ts + ts = common_touch_data_alloc(); + if (ts == NULL) { + TPD_INFO("ts kzalloc error\n"); + goto err_register_driver; + } + memset(ts, 0, sizeof(*ts)); + + chip_info->g_fw_buf = vmalloc(128 * 1024); + if (chip_info->g_fw_buf == NULL) { + TPD_INFO("fw buf vmalloc error\n"); + //ret = -ENOMEM; + goto err_g_fw_buf; + } + + //step3:binding dev for easy operate + chip_info->hx_spi = spi; + chip_info->syna_ops = &hx83112f_proc_ops; + ts->debug_info_ops = &debug_info_proc_ops; + ts->s_client = spi; + chip_info->hx_irq = spi->irq; + ts->irq = spi->irq; + spi_set_drvdata(spi, ts); + ts->dev = &spi->dev; + ts->chip_data = chip_info; + chip_info->hw_res = &ts->hw_res; + mutex_init(&(chip_info->spi_lock)); + chip_info->touch_direction = VERTICAL_SCREEN; + chip_info->using_headfile = false; + chip_info->first_download_finished = false; + + if (ts->s_client->master->flags & SPI_MASTER_HALF_DUPLEX) { + TPD_INFO("Full duplex not supported by master\n"); + ret = -EIO; + goto err_spi_setup; + } + ts->s_client->bits_per_word = 8; + ts->s_client->mode = SPI_MODE_3; + ts->s_client->chip_select = 0; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + /* new usage of MTK spi API */ + memcpy(&chip_info->hx_spi_mcc, &hx_spi_ctrdata, sizeof(struct mtk_chip_config)); + ts->s_client->controller_data = (void *)&chip_info->hx_spi_mcc; +#else + /* old usage of MTK spi API */ + memcpy(&chip_info->hx_spi_mcc, &hx_spi_ctrdata, sizeof(struct mt_chip_conf)); + ts->s_client->controller_data = (void *)&chip_info->hx_spi_mcc; + + ret = spi_setup(ts->s_client); + if (ret < 0) { + TPD_INFO("Failed to perform SPI setup\n"); + goto err_spi_setup; + } +#endif + chip_info->p_spuri_fp_touch = &(ts->spuri_fp_touch); + + //disable_irq_nosync(chip_info->hx_irq); + + //step4:file_operations callback binding + ts->ts_ops = &hx83112f_ops; + + private_ts = ts; + +#ifdef CONFIG_OP_TP_APK + himax_init_op_apk_op(ts); +#endif + + //step5:register common touch + ret = register_common_touch_device(ts); + if (ret < 0) + goto err_register_driver; + + // disable_irq_nosync(chip_info->hx_irq); + hx83112f_enable_interrupt(chip_info, false); + if (himax_ic_package_check() == false) { + TPD_INFO("Himax chip doesn NOT EXIST"); + goto err_register_driver; + } + chip_info->test_limit_name = ts->panel_data.test_limit_name; + + //chip_info->p_firmware_headfile = &ts->panel_data.firmware_headfile; + + chip_info->himax_0f_update_wq = create_singlethread_workqueue("HMX_0f_update_request"); + INIT_DELAYED_WORK(&chip_info->work_0f_update, himax_mcu_0f_operation); + + himax_power_on_init(); + + //touch data init + ret = himax_report_data_init(ts->max_num, ts->hw_res.TX_NUM, ts->hw_res.RX_NUM); + if (ret) + goto err_register_driver; + + ts->tp_suspend_order = TP_LCD_SUSPEND; + ts->tp_resume_order = LCD_TP_RESUME; + //ts->skip_suspend_operate = true; + //ts->skip_reset_in_resume = true; + ts->skip_reset_in_resume = false; + + //step7:create hx83112f related proc files + himax_create_proc(ts, chip_info->syna_ops); + irq_en_cnt = 1; + TPD_INFO("%s, probe normal end\n", __func__); + hx83112f_enable_interrupt(chip_info, false); + if (ts->boot_mode == MSM_BOOT_MODE_RECOVERY) + schedule_delayed_work(&ts->fw_update_delayed_work, msecs_to_jiffies(4500)); + return 0; +err_spi_setup: + if (chip_info->g_fw_buf) + vfree(chip_info->g_fw_buf); +err_g_fw_buf: +err_register_driver: + hx83112f_enable_interrupt(chip_info, false); + + common_touch_data_free(ts); + ts = NULL; + kfree(hx_touch_data); + kfree(chip_info); + + ret = -1; + TPD_INFO("%s, probe error\n", __func__); + + return ret; +} + +static int hx83112f_tp_remove(struct spi_device *spi) +{ + struct touchpanel_data *ts = spi_get_drvdata(spi); + + ts->s_client = NULL; + /* spin_unlock_irq(&ts->spi_lock); */ + spi_set_drvdata(spi, NULL); + + TPD_INFO("%s is called\n", __func__); + kfree(ts); + + return 0; +} + +/*add codes for touchpanel shutdown*/ +static void hx83112f_tp_shutdown(struct spi_device *spi) +{ + int rc; + int i = 100; + struct touchpanel_data *ts = spi_get_drvdata(spi); + + TPD_INFO("%s is called\n", __func__); + + tp_shutdown(ts->dev); + + //if (ts->int_mode == BANNABLE) { + disable_irq_wake(ts->irq); + //} + disable_irq_nosync(ts->irq); + + free_irq(ts->irq, ts); + + /* + if(TP_Panel != NULL){ + gpio_set_value(TP_Panel->reset_config.reset_gpio, 0); + usleep_range(10000, 12000); + rc = dsi_pwr_enable_regulator(&TP_Panel->power_info, false); + if (rc) + TPD_INFO("failed to enable vregs, rc=%d\n", rc); + } + */ + if(TP_Panel != NULL){ + gpio_set_value(TP_Panel->reset_config.reset_gpio, 0); + } + mdelay(5); + gpio_direction_output(ts->hw_res.reset_gpio, 0); + mdelay(5); + gpio_direction_output(ts->hw_res.cs_gpio, 0); + while(gpio_get_value(ts->hw_res.cs_gpio) != 0&&(i>0)){ + usleep_range(10000, 10200); + i--; + } + + mdelay(20); + + if(TP_Panel != NULL){ + usleep_range(10000, 12000); + rc = dsi_pwr_enable_regulator(&TP_Panel->power_info, false); + if (rc) + TPD_INFO("failed to enable vregs, rc=%d\n", rc); + } + + TPD_INFO("%s is called cs is below\n", __func__); + return ; +} + +static int hx83112f_i2c_suspend(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s: is called gesture_enable =%d\n", __func__, ts->gesture_enable); + tp_i2c_suspend(ts); + + return 0; +} + +static int hx83112f_i2c_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s is called\n", __func__); + tp_i2c_resume(ts); + return 0; +} + +static const struct spi_device_id tp_id[] = { + { TPD_DEVICE, 0 }, + { } +}; + +static const struct of_device_id tp_match_table[] = { + { .compatible = TPD_DEVICE,}, + { }, +}; + +static const struct dev_pm_ops tp_pm_ops = { + .suspend = hx83112f_i2c_suspend, + .resume = hx83112f_i2c_resume, +}; + +static struct spi_driver himax_common_driver = { + .probe = hx83112f_tp_probe, + .remove = hx83112f_tp_remove, + .shutdown = hx83112f_tp_shutdown, + .id_table = tp_id, + .driver = { + .name = TPD_DEVICE, + .owner = THIS_MODULE, + .of_match_table = tp_match_table, + .pm = &tp_pm_ops, + }, +}; + +static int __init tp_driver_init(void) +{ + int status = 0; + + TPD_INFO("%s is called\n", __func__); + status = spi_register_driver(&himax_common_driver); + TPD_INFO("%s, spi_register_driver done.\n", __func__); + if (status < 0) { + TPD_INFO("%s, Failed to register SPI driver.\n", __func__); + return -EINVAL; + } + + return 0; +} + +/* should never be called */ +static void __exit tp_driver_exit(void) +{ + spi_unregister_driver(&himax_common_driver); +} + +late_initcall(tp_driver_init); +module_exit(tp_driver_exit); + +MODULE_DESCRIPTION("Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/hx83112f_noflash.h b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/hx83112f_noflash.h new file mode 100755 index 0000000000000000000000000000000000000000..eb5abfd29ab0995fc52a09371dc2b4b89e1a4147 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/hx83112f_noflash.h @@ -0,0 +1,570 @@ +/* SPDX-License-Identifier: GPL-2.0*/ +/* Oneplus Android Driver Sample Code for common functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#ifndef HX83112F_H +#define HX83112F_H +#define DRIVER_VERSION "HX83112F_DRIVER_VERSION_0.0.0.4" +/*********PART1:Head files**********************/ +#include +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_SPI_MT65XX +#include +#endif +#include "../himax_common.h" +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +//#include "mtk_gpio.h" +#else +#include "op_spi.h" +#endif +#define HX_VERSION_SELF_DEF 200302 +//#define HX_RST_PIN_FUNC +#define HX_ENTER_ALGORITHM_NUMBER /*Support calculation enter algorithm number*/ + +/*********PART2:Define Area**********************/ +#define ENABLE_UNICODE 0x40 +#define ENABLE_VEE 0x20 +#define ENABLE_CIRCLE 0x08 +#define ENABLE_SWIPE 0x02 +#define ENABLE_DTAP 0x01 + +#define UNICODE_DETECT 0x0b +#define VEE_DETECT 0x0a +#define CIRCLE_DETECT 0x08 +#define SWIPE_DETECT 0x07 +#define DTAP_DETECT 0x03 + +#define RESET_TO_NORMAL_TIME 5 /*Sleep time after reset*/ + +#define SPURIOUS_FP_LIMIT 100 +#define SPURIOUS_FP_RX_NUM 8 +#define SPURIOUS_FP_TX_NUM 9 +#define SPURIOUS_FP_BASE_DATA_RETRY 10 + +#define I2C_ERROR_MAX_TIME 5 + +#define HX_32K_SZ 0x8000 +#define FOUR_BYTE_ADDR_SZ 4 + +#define EXTEND_EE_SHORT_RESET_DUR 60 +#define EXTEND_EE_SHORT_INT_DUR 150 +#define EXTEND_EE_SHORT_TX_ON_COUNT 146 +#define EXTEND_EE_SHORT_RX_ON_COUNT 146 +#define EXTEND_EE_SHORT_TEST_LIMIT_PART1 160 +#define EXTEND_EE_SHORT_TEST_LIMIT_PART2 80 // ( unit = ratio ) + +/* tddi f54 test reporting - */ +#define ELEC_OPEN_TEST_TX_ON_COUNT 2 +#define ELEC_OPEN_TEST_RX_ON_COUNT 2 +#define ELEC_OPEN_INT_DUR_ONE 15 +#define ELEC_OPEN_INT_DUR_TWO 25 +#define ELEC_OPEN_TEST_LIMIT_ONE 500 +#define ELEC_OPEN_TEST_LIMIT_TWO 50 + +#define COMMAND_FORCE_UPDATE 4 + +//#define UPDATE_DISPLAY_CONFIG + +//Self Capacitance key test limite +#define MENU_LOW_LIMITE 1630 +#define MENU_HIGH_LIMITE 3803 + +#define BACK_LOW_LIMITE 3016 +#define BACK_HIGH_LIMITE 7039 + +#define TEST_FAIL 1 +#define TEST_PASS 0 + +#define LIMIT_DOZE_LOW 50 +#define LIMIT_DOZE_HIGH 975 +#define firmware_update_space 131072 /*128*1024*/ + + +//gmq-himax + +#define HX64K 0x10000 +#define HX1K 0x400 + +#define FW_BIN_16K_SZ 0x4000 +struct touchpanel_data *private_ts; +int g_f_0f_updat; + +/**COMMON USE ***START***/ +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CID_VER_MAJ_FLASH_ADDR; +unsigned long CID_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_LENG; +unsigned long CID_VER_MAJ_FLASH_LENG; +unsigned long CID_VER_MIN_FLASH_LENG; +unsigned long FW_CFG_VER_FLASH_ADDR; +uint8_t HX_PROC_SEND_FLAG; + +struct proc_dir_entry *himax_proc_register_file; +uint8_t byte_length; +uint8_t register_command[4]; +bool cfg_flag; + +//#ifdef HX_ESD_RECOVERY +u8 HX_ESD_RESET_ACTIVATE; +int hx_EB_event_flag; +int hx_EC_event_flag; +int hx_ED_event_flag; +//#endif + +bool HX_RESET_STATE; + +unsigned char IC_TYPE = 11; +unsigned char IC_CHECKSUM; +bool DSRAM_Flag; +int g_diag_command; +uint8_t diag_coor[128]; +int32_t diag_self[100] = {0}; + +int g_max_mutual; +int g_min_mutual = 255; +int g_max_self; +int g_min_self = 255; + +int mutual_set_flag; +uint8_t cmd_set[8]; + +/**GESTURE_TRACK*/ +static int gest_pt_cnt; +static int gest_pt_x[10]; +static int gest_pt_y[10]; + + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 +#define HIMAX_REG_RETRY_TIMES 10 + +#define HX_83112A_SERIES_PWON 16 +#define HX_83112B_SERIES_PWON 17 +#define HX_83112F_SERIES_PWON 18 + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +#define SHIFTBITS 5 + +#define FW_SIZE_64k 65536 +#define FW_SIZE_128k 131072 + +#define NO_ERR 0 +#define READY_TO_SERVE 1 +#define WORK_OUT 2 +#define I2C_FAIL -1 +#define MEM_ALLOC_FAIL -2 +#define CHECKSUM_FAIL -3 +#define GESTURE_DETECT_FAIL -4 +#define INPUT_REGISTER_FAIL -5 +#define FW_NOT_READY -6 +#define LENGTH_FAIL -7 +#define OPEN_FILE_FAIL -8 +#define ERR_WORK_OUT -10 + +#define HX_FINGER_ON 1 +#define HX_FINGER_LEAVE 2 + +#define HX_REPORT_COORD 1 +#define HX_REPORT_SMWP_EVENT 2 + +//gesture head information +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +#define BS_RAWDATANOISE 10 +#define BS_OPENSHORT 0 + +#define SKIPRXNUM 31 +/**COMMON USE*********END***/ + +/** FOR DEBUG USE*****START***/ +enum DEBUG_DATA_TYPE { + DEBUG_DATA_BASELINE = 0x08, + DEBUG_DATA_DELTA = 0x09, + DEBUG_DATA_RAW = 0x0A, + DEBUG_DATA_DOWN = 0x0B, +}; + +//self test use + +/* ASCII format */ +#define ASCII_LF (0x0A) +#define ASCII_CR (0x0D) +#define ASCII_COMMA (0x2C) +#define ASCII_ZERO (0x30) +#define CHAR_EL '\0' +#define CHAR_NL '\n' +#define ACSII_SPACE (0x20) + +enum THP_INSPECTION_ENUM { + HIMAX_INSPECTION_OPEN, + HIMAX_INSPECTION_MICRO_OPEN, + HIMAX_INSPECTION_SHORT, + HIMAX_INSPECTION_RAWDATA, + HIMAX_INSPECTION_NOISE, + HIMAX_INSPECTION_SORTING, + HIMAX_INSPECTION_BACK_NORMAL, + HIMAX_INSPECTION_LPWUG_RAWDATA, + HIMAX_INSPECTION_LPWUG_NOISE, + HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA, + HIMAX_INSPECTION_LPWUG_IDLE_NOISE, +}; + +/* Error code of AFE Inspection */ +#define HX_RSLT_OUT_PATH_OK "/sdcard/TpTestReport/screenOn/OK/" +#define HX_RSLT_OUT_PATH_NG "/sdcard/TpTestReport/screenOn/NG/" +#define HX_GES_RSLT_OUT_PATH_OK "/sdcard/TpTestReport/screenOff/OK/" +#define HX_GES_RSLT_OUT_PATH_NG "/sdcard/TpTestReport/screenOff/NG/" + +/*#define HX_RSLT_OUT_FILE_OK "tp_testlimit_OK_"*/ +/*#define HX_RSLT_OUT_FILE_NG "tp_testlimitst_NG_"*/ + +enum RETURN_RESLUT { + RESULT_OK = 0, + RESULT_ERR, + RESULT_RETRY, +}; + +enum SKIPTXNUMINDEX { + SKIPTXNUM_START = 6, + SKIPTXNUM_6 = SKIPTXNUM_START, + SKIPTXNUM_7, + SKIPTXNUM_8, + SKIPTXNUM_9, + SKIPTXNUM_END = SKIPTXNUM_9, +}; + +char *g_himax_inspection_mode[] = { + "HIMAX_INSPECTION_OPEN", + "HIMAX_INSPECTION_MICRO_OPEN", + "HIMAX_INSPECTION_SHORT", + "HIMAX_INSPECTION_RAWDATA", + "HIMAX_INSPECTION_NOISE", + "HIMAX_INSPECTION_SORTING", + "HIMAX_INSPECTION_BACK_NORMAL", + "HIMAX_INSPECTION_LPWUG_RAWDATA", + "HIMAX_INSPECTION_LPWUG_NOISE", + "HIMAX_INSPECTION_LPWUG_IDLE_RAWDATA", + "HIMAX_INSPECTION_LPWUG_IDLE_NOISE", +}; + +/* for criteria */ +char *g_hx_inspt_crtra_name[] = { + "CRITERIA_OPEN_MIN", + "CRITERIA_OPEN_MAX", + "CRITERIA_MICRO_OPEN_MIN", + "CRITERIA_MICRO_OPEN_MAX", + "CRITERIA_SHORT_MIN", + "CRITERIA_SHORT_MAX", + "CRITERIA_RAWDATA_MIN", /* CRITERIA_RAW_MIN */ + "CRITERIA_RAWDATA_MAX", /* CRITERIA_RAW_MAX */ + "CRITERIA_NOISE_MAX", + "LPWUG_RAWDATA_MIN", + "LPWUG_RAWDATA_MAX", + "LPWUG_NOISE_MIN", + "LPWUG_NOISE_MAX", + "LPWUG_IDLE_RAWDATA_MIN", + "LPWUG_IDLE_RAWDATA_MAX", + "LPWUG_IDLE_NOISE_MIN", + "LPWUG_IDLE_NOISE_MAX", + NULL +}; + +enum HX_CRITERIA_ENUM { + IDX_OPENMIN = 0, + IDX_OPENMAX, + IDX_M_OPENMIN, + IDX_M_OPENMAX, + IDX_SHORTMIN, + IDX_SHORTMAX, + IDX_RAWDATA_MIN, + IDX_RAWDATA_MAX, + IDX_NOISEMAX, + IDX_LPWUG_RAWDATA_MIN, + IDX_LPWUG_RAWDATA_MAX, + IDX_LPWUG_NOISE_MIN, + IDX_LPWUG_NOISE_MAX, + IDX_LPWUG_IDLE_RAWDATA_MIN, + IDX_LPWUG_IDLE_RAWDATA_MAX, + IDX_LPWUG_IDLE_NOISE_MIN, + IDX_LPWUG_IDLE_NOISE_MAX, +}; + +/* Error code of AFE Inspection */ +enum THP_AFE_INSPECT_ERR_ENUM { + THP_AFE_INSPECT_OK = 0, /* OK */ + THP_AFE_INSPECT_ESPI = (1 << 0), /* SPI communication error */ + THP_AFE_INSPECT_ERAW = (1 << 1), /* Raw data error */ + THP_AFE_INSPECT_ENOISE = (1 << 2), /* Noise error */ + THP_AFE_INSPECT_EOPEN = (1 << 3), /* Sensor open error */ + THP_AFE_INSPECT_EMOPEN = (1 << 4), /* Sensor micro open error */ + THP_AFE_INSPECT_ESHORT = (1 << 5), /* Sensor short error */ + THP_AFE_INSPECT_ERC = (1 << 6), /* Sensor RC error */ + THP_AFE_INSPECT_EPIN = (1 << 7), + // Errors of TSVD!FTSHD!FTRCST!FTRCRQ and other PINs + // when Report Rate Switching between 60 Hz and 120 Hz + THP_AFE_INSPECT_EOTHER = (1 << 8), /* All other errors */ + THP_AFE_INSPECT_EFILE = (1 << 9) /* Get Criteria file error */ +}; + + +//Himax MP Limit +//#define RAWMIN 3547*0.05 +//#define RAWMAX 5352*0.9 + +/* Define Criteria*/ +#define RAWMIN 906 +#define RAWMAX 16317 +#define SHORTMIN 0 +#define SHORTMAX 150 +#define OPENMIN 50 +#define OPENMAX 500 +#define M_OPENMIN 0 +#define M_OPENMAX 150 + +#define RAWMIN_BD12 895 +#define RAWMAX_BD12 16117 +#define LPWUG_RAWDATA_MAX_BD12 9999 +#define LPWUG_IDLE_RAWDATA_MAX_BD12 9999 + +#define NOISEFRAME (BS_RAWDATANOISE+40) +#define NOISE_P 256 //gmqtest +#define UNIFMAX 500 + +//Himax MP Password +#define PWD_OPEN_START 0x77 +#define PWD_OPEN_END 0x88 +#define PWD_SHORT_START 0x11 +#define PWD_SHORT_END 0x33 +#define PWD_RAWDATA_START 0x00 +#define PWD_RAWDATA_END 0x99 +#define PWD_NOISE_START 0x00 +#define PWD_NOISE_END 0x99 +#define PWD_SORTING_START 0xAA +#define PWD_SORTING_END 0xCC + +//Himax DataType +#define DATA_OPEN 0x0B +#define DATA_MICRO_OPEN 0x0C +#define DATA_SHORT 0x0A +#define DATA_RAWDATA 0x0A +#define DATA_NOISE 0x0F +#define DATA_BACK_NORMAL 0x00 +#define DATA_LPWUG_RAWDATA 0x0C +#define DATA_LPWUG_NOISE 0x0F +//#define DATA_DOZE_RAWDATA 0x0A +//#define DATA_DOZE_NOISE 0x0F +#define DATA_LPWUG_IDLE_RAWDATA 0x0A +#define DATA_LPWUG_IDLE_NOISE 0x0F + +//Himax Data Ready Password +#define Data_PWD0 0xA5 +#define Data_PWD1 0x5A + +static uint16_t NOISEMAX; +static uint16_t LPWUG_NOISEMAX; + +#define BS_LPWUG 1 +/*#define BS_DOZE 1*/ +#define BS_LPWUG_dile 1 + +/* Define Criteria*/ +#define LPWUG_NOISE_MAX 100 +#define LPWUG_NOISE_MIN 0 +#define LPWUG_RAWDATA_MAX 15000 +#define LPWUG_RAWDATA_MIN 0 +#define DOZE_NOISE_MAX 100 +#define DOZE_NOISE_MIN 0 +#define DOZE_RAWDATA_MAX 9999 +#define DOZE_RAWDATA_MIN 0 +#define LPWUG_IDLE_NOISE_MAX 100 +#define LPWUG_IDLE_NOISE_MIN 0 +#define LPWUG_IDLE_RAWDATA_MAX 15000 +#define LPWUG_IDLE_RAWDATA_MIN 0 + +#define PWD_NONE 0x00 +#define PWD_LPWUG_START 0x55 +#define PWD_LPWUG_END 0x66 +//#define PWD_DOZE_START 0x22 +//#define PWD_DOZE_END 0x44 +#define PWD_LPWUG_IDLE_START 0x50 +#define PWD_LPWUG_IDLE_END 0x60 + +#define SKIP_NOTCH_START 5 +#define SKIP_NOTCH_END 10 +#define SKIP_DUMMY_START 23 //TX+SKIP_NOTCH_START +#define SKIP_DUMMY_END 28 // TX+SKIP_NOTCH_END + +/** FOR DEBUG USE ****END****/ + +struct himax_report_data { + int touch_all_size; + int raw_cnt_max; + int raw_cnt_rmd; + int touch_info_size; + uint8_t finger_num; + uint8_t finger_on; + uint8_t *hx_coord_buf; + uint8_t hx_state_info[5]; + + int event_size; + uint8_t *hx_event_buf; + int hx_event_buf_op[128]; + + int rawdata_size; + uint8_t diag_cmd; + uint8_t *hx_rawdata_buf; + //uint32_t *diag_mutual; + int32_t *diag_mutual; + uint8_t rawdata_frame_size; +}; + +/*********PART3:Struct Area**********************/ +struct himax_fw_debug_info { + u16 recal0 : 1; + u16 recal1 : 1; + u16 paseline : 1; + u16 palm : 1; + u16 idle : 1; + u16 water : 1; + u16 hopping : 1; + u16 noise : 1; + u16 glove : 1; + u16 border : 1; + u16 vr : 1; + u16 big_small : 1; + u16 one_block : 1; + u16 blewing : 1; + u16 thumb_flying : 1; + u16 border_extend : 1; +}; + +struct chip_data_hx83112f { + uint32_t *p_tp_fw; + tp_dev tp_type; + char *test_limit_name; + struct himax_proc_operations *syna_ops; /*hx83112f func provide to hx83112f common driver*/ + + struct hw_resource *hw_res; + int16_t *spuri_fp_data; + struct spurious_fp_touch *p_spuri_fp_touch; + /********SPI bus*******************************/ + struct spi_device *hx_spi; + int hx_irq; +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + struct mtk_chip_config hx_spi_mcc; +#else + struct mt_chip_conf hx_spi_mcc; +#endif + /********SPI bus*******************************/ + struct mutex spi_lock; + struct workqueue_struct *himax_0f_update_wq; + struct delayed_work work_0f_update; + uint8_t *tmp_data; + uint8_t touch_direction; //show touchpanel current direction + bool using_headfile; + bool first_download_finished; + + uint32_t fw_id; + uint16_t fw_ver; + uint8_t touch_ver; + + u8 *g_fw_buf; + size_t g_fw_len; + bool g_fw_sta; + +#ifdef CONFIG_OP_TP_APK + bool lock_point_status; + bool plug_status; + bool debug_mode_sta; + bool debug_gesture_sta; + bool earphone_sta; + bool charger_sta; + bool noise_sta; +#endif + bool single_tap_flag; + +}; + +/*********PART4:ZERO FLASH**********************/ +#define MAX_TRANS_SZ 240 /*MTK:240_WRITE_limit*/ +#define MAX_RECVS_SZ 64 /*MTK:56_READ_limit*/ + +#define zf_addr_dis_flash_reload 0x10007f00 +#define zf_data_dis_flash_reload 0x00009AA9 +#define zf_addr_system_reset 0x90000018 +#define zf_data_system_reset 0x00000055 +//#define zf_data_sram_start_addr 0x08000000 +#define zf_data_sram_start_addr 0x20000000 + +#define zf_data_sram_clean 0x10000000 +#define zf_data_cfg_info 0x10007000 +#define zf_data_fw_cfg_p1 0x10007084 +#define zf_data_fw_cfg_p2 0x10007264 +#define zf_data_fw_cfg_p3 0x10007300 +#define zf_data_adc_cfg_1 0x10006A00 +#define zf_data_adc_cfg_2 0x10007B28 +#define zf_data_adc_cfg_3 0x10007AF0 +#define zf_data_map_table 0x10007500 +#define zf_data_mode_switch 0x10007294 + +struct zf_operation { + uint8_t addr_dis_flash_reload[4]; + uint8_t data_dis_flash_reload[4]; + uint8_t addr_system_reset[4]; + uint8_t data_system_reset[4]; + uint8_t data_sram_start_addr[4]; + uint8_t data_sram_clean[4]; + uint8_t data_cfg_info[4]; + uint8_t data_fw_cfg[4]; + uint8_t data_fw_cfg_p1[4]; + uint8_t data_fw_cfg_p2[4]; + uint8_t data_fw_cfg_p3[4]; + uint8_t data_adc_cfg_1[4]; + uint8_t data_adc_cfg_2[4]; + uint8_t data_adc_cfg_3[4]; + uint8_t data_map_table[4]; + uint8_t data_mode_switch[4]; +}; +struct zf_info { + uint8_t sram_addr[4]; + int write_size; + uint32_t fw_addr; + uint32_t cfg_addr; +}; + + +struct himax_core_fp { + int (*fp_reload_disable)(void); + void (*fp_clean_sram_0f)(uint8_t *addr, int write_len, int type); + void (*fp_write_sram_0f)(const struct firmware *fw_entry, uint8_t *addr, int start_index, uint32_t write_len); +}; + +#endif diff --git a/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/op_spi.h b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/op_spi.h new file mode 100755 index 0000000000000000000000000000000000000000..331813fda4ea8e5f9340777fc490474219ff0e80 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/himax/hx83112f_noflash/op_spi.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0*/ +/* Oneplus Android Driver Code for spi config functions + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_SPI_H__ +#define __MTK_SPI_H__ + + +#include +#include +#ifdef CONFIG_TRUSTONIC_TEE_SUPPORT +#include +#include +#endif + +//define struct for spi driver + +enum spi_sample_sel { + POSEDGE, + NEGEDGE +}; +enum spi_cs_pol { + ACTIVE_LOW, + ACTIVE_HIGH +}; + +enum spi_cpol { + SPI_CPOL_0, + SPI_CPOL_1 +}; + +enum spi_cpha { + SPI_CPHA_0, + SPI_CPHA_1 +}; + +enum spi_mlsb { + SPI_LSB, + SPI_MSB +}; + +enum spi_endian { + SPI_LENDIAN, + SPI_BENDIAN +}; + +enum spi_transfer_mode { + FIFO_TRANSFER, + DMA_TRANSFER, + OTHER1, + OTHER2, +}; + +enum spi_pause_mode { + PAUSE_MODE_DISABLE, + PAUSE_MODE_ENABLE +}; +enum spi_finish_intr { + FINISH_INTR_DIS, + FINISH_INTR_EN, +}; + +enum spi_deassert_mode { + DEASSERT_DISABLE, + DEASSERT_ENABLE +}; + +enum spi_ulthigh { + ULTRA_HIGH_DISABLE, + ULTRA_HIGH_ENABLE +}; + +enum spi_tckdly { + TICK_DLY0, + TICK_DLY1, + TICK_DLY2, + TICK_DLY3 +}; + +struct mt_chip_conf { + u32 setuptime; + u32 holdtime; + u32 high_time; + u32 low_time; + u32 cs_idletime; + u32 ulthgh_thrsh; + enum spi_sample_sel sample_sel; + enum spi_cs_pol cs_pol; + enum spi_cpol cpol; + enum spi_cpha cpha; + enum spi_mlsb tx_mlsb; + enum spi_mlsb rx_mlsb; + enum spi_endian tx_endian; + enum spi_endian rx_endian; + enum spi_transfer_mode com_mod; + enum spi_pause_mode pause; + enum spi_finish_intr finish_intr; + enum spi_deassert_mode deassert; + enum spi_ulthigh ulthigh; + enum spi_tckdly tckdly; +}; + +//void secspi_enable_clk(struct spi_device *spidev); +#ifdef CONFIG_TRUSTONIC_TEE_SUPPORT +//int secspi_session_open(u32 spinum); +//int secspi_execute(u32 cmd, tciSpiMessage_t *param); +#endif + +#endif diff --git a/drivers/oneplus/input/touchscreen_himax/touchpanel_common_driver_himax.c b/drivers/oneplus/input/touchscreen_himax/touchpanel_common_driver_himax.c new file mode 100755 index 0000000000000000000000000000000000000000..b06def2043e707285e8e07b3890cc6043bd31b85 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/touchpanel_common_driver_himax.c @@ -0,0 +1,5572 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +#ifndef TPD_USE_EINT +#include +#endif + +#ifdef CONFIG_FBhx_parse_bin_cfg_data +#include +#include +#endif + +//#ifdef CONFIG_DRM_MSM +//#include +#include +//#endif + +#include "touchpanel_common_himax.h" +//#include "samsung/s6sy761/sec_drivers_s6sy761.h" +#include "util_interface/touch_interfaces.h" + +/*******Part0:LOG TAG Declear************************/ +#define TPD_PRINT_POINT_NUM 150 +#define TPD_DEVICE "touchpanel" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define TPD_DEBUG(a, arg...)\ + do{\ + if (LEVEL_DEBUG == tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_DETAIL(a, arg...)\ + do{\ + if (LEVEL_BASIC != tp_debug)\ + pr_err("[TP]"TPD_DEVICE ": " a, ##arg);\ + }while(0) + +#define TPD_SPECIFIC_PRINT(count, a, arg...)\ + do{\ + if (count++ == TPD_PRINT_POINT_NUM || LEVEL_DEBUG == tp_debug) {\ + TPD_INFO(TPD_DEVICE ": " a, ##arg);\ + count = 0;\ + }\ + }while(0) + +/*******Part1:Global variables Area********************/ +unsigned int tp_debug = 0; +unsigned int tp_register_times = 0; +//unsigned int probe_time = 0; +struct touchpanel_data *g_tp = NULL; +int tp_1v8_power = 0; +static DECLARE_WAIT_QUEUE_HEAD(waiter); +static struct input_dev *ps_input_dev = NULL; +static int lcd_id = 0; +static int gesture_switch_value = 0; +struct drm_panel *tp_active_panel; +struct drm_panel *lcd_active_panel; +extern struct dsi_panel *TP_Panel;; + + +int gesture_mode_value; +int himax_boot_mode; +int sigle_num = 0; +struct timeval tpstart, tpend; +int pointx[2] = {0, 0}; +int pointy[2] = {0, 0}; +#define ABS(a,b) ((a - b > 0) ? a - b : b - a) + +uint8_t DouTap_enable = 0; // double tap +uint8_t UpVee_enable = 0; // V +uint8_t LeftVee_enable = 0; // > +uint8_t RightVee_enable = 0; // < +uint8_t Circle_enable = 0; // O +uint8_t DouSwip_enable = 0; // || +uint8_t Mgestrue_enable = 0; // M +uint8_t Wgestrue_enable = 0; // W +uint8_t Sgestrue_enable = 0; // S +uint8_t SingleTap_enable = 0; // single tap +uint8_t Enable_gesture = 0; + +/*******Part2:declear Area********************************/ +static void speedup_resume(struct work_struct *work); +// +//static void speedup_resume_test(struct touchpanel_data *ts); +// +static void tp_resume(struct device *dev); +void esd_handle_switch(struct esd_information *esd_info, bool flag); +int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); + + +#ifdef TPD_USE_EINT +static irqreturn_t tp_irq_thread_fn(int irq, void *dev_id); +#endif + +//#if defined(CONFIG_FB) || defined(CONFIG_DRM_MSM) +static int tfb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +//#endif + +static void tp_touch_release(struct touchpanel_data *ts); +static void tp_btnkey_release(struct touchpanel_data *ts); +static void tp_fw_update_work(struct work_struct *work); +static int init_debug_info_proc(struct touchpanel_data *ts); +static void tp_work_func(struct touchpanel_data *ts); +__attribute__((weak)) int request_firmware_select(const struct firmware **firmware_p, const char *name, struct device *device) {return 1;} +__attribute__((weak)) int register_devinfo(char *name, struct manufacture_info *info) {return 1;} +__attribute__((weak)) int preconfig_power_control(struct touchpanel_data *ts) {return 0;} +__attribute__((weak)) int reconfig_power_control(struct touchpanel_data *ts) {return 0;} + +int tp_shutdown(struct device *dev); + +static int touchpanel_notifier_update_fw(struct notifier_block *self, unsigned long event, void *data) +{ + int timed_out = -1; + struct touchpanel_data *ts = container_of(self, struct touchpanel_data, notifier_update_fw); + + if (event == DRM_PANEL_UPDATE_TPFW_BLANK) { + TPD_INFO("update_fw\n"); + + disable_irq_nosync(ts->irq); + TPD_INFO("disable_irq_nosync\n"); + + timed_out = wait_for_completion_timeout(&ts->pm_complete, 0.5*HZ); //wait suspend over for 0.5s + if ((ts->pm_complete.done) || (timed_out == 0)) + TPD_INFO("completion state, timed_out:%d, done:%d\n", timed_out, ts->pm_complete.done); + + ts->suspend_state = TP_RESUME_EARLY_EVENT; //set suspend_resume_state + tp_resume(ts->dev); + TPD_INFO("enable tp isr 113, tp irq %d\n", ts->irq); + + } else if (event == DRM_PANEL_CS_HIGH_BLANK) { + TPD_INFO("cs_high\n"); + } else if (event == DRM_PANEL_CS_LOW_BLANK) { + TPD_INFO("cs_low\n"); + } + return 0; +} + +static void touchpanel_update_fw_notifier_init(struct touchpanel_data *ts) +{ + int res = 0; + + TPD_INFO("touchpanelupdate_fw_notifier_init\n"); + + ts->notifier_update_fw.notifier_call = touchpanel_notifier_update_fw; + res = update_tpfw_register_client(&ts->notifier_update_fw); + +} + +static int __init get_cmdlinelcd_id(char *str) +{ + TPD_INFO("%s enter %s\n", __func__, str); + if (str) { + if (strncmp(str, "qcom,mdss_dsi_samsung_oneplus_dsc_cmd:", 33) == 0) { //using 18821 TP + lcd_id = 0; + } else if (strncmp(str, "qcom,mdss_dsi_samsung_ana6706_dsc_cmd:", 33) == 0) { //using 19811 TP + lcd_id = 1; + } + } + return 0; // should rever after lcd info +} +__setup("msm_drm.dsi_display0=", get_cmdlinelcd_id); + + +int check_touchirq_triggerd(void) +{ + int value = -1; + + if (!g_tp) { + return 0; + } + if (!g_tp->gesture_enable) { + return 0; + } + value = gpio_get_value(g_tp->hw_res.irq_gpio); + if ((value == 0) && (g_tp->irq_flags & IRQF_TRIGGER_LOW)) { + return 1; + } + + return 0; +} + +/*******Part3:Function Area********************************/ +/** + * operate_mode_switch - switch work mode based on current params + * @ts: touchpanel_data struct using for common driver + * + * switch work mode based on current params(gesture_enable, limit_enable, glove_enable) + * Do not care the result: Return void type + */ +void operate_mode_switch(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->mode_switch) { + TPD_INFO("not support ts_ops->mode_switch callback\n"); + return; + } + + if (ts->is_suspended) { + if (ts->game_switch_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_GAME, false); + + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, true); + if (ts->mode_switch_type == SEQUENCE) + ts->ts_ops->mode_switch(ts->chip_data, MODE_NORMAL, true); + } else { + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, false); + if (ts->mode_switch_type == SEQUENCE) + ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + } + } else + ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + } else { + if (ts->ear_sense_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, ts->es_enable == 1); + ts->ts_ops->mode_switch(ts->chip_data, MODE_PALM_REJECTION, ts->palm_enable); + } + + if (ts->face_detect_support) { + //ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, ts->fd_enable == 1); + } + + if (ts->mode_switch_type == SEQUENCE) { + if (ts->black_gesture_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, false); + } + if (ts->edge_limit_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_EDGE, ts->limit_edge); + + if (ts->glove_mode_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_GLOVE, ts->glove_enable); + + if (ts->charge_detect_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_CHARGE, ts->charge_detect); + + if (ts->wireless_charge_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_WIRELESS_CHARGE, ts->wireless_charge_detect); + + if (ts->touch_hold_support) + if (!ts->skip_enable_touchhold)//fingerprint is lock, enable touchhold when resume. + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_HOLD, ts->touch_hold_enable); + + if (ts->audio_noise_support) + ts->ts_ops->mode_switch(ts->chip_data, MODE_AUDIO_NOISE, ts->audio_noise_detect); + + ts->ts_ops->mode_switch(ts->chip_data, MODE_NORMAL, true); + } +} + +static void tp_touch_down(struct touchpanel_data *ts, struct point_info points, int touch_report_num, int id) +{ + static int last_width_major; + static int point_num = 0; + + if (ts->input_dev == NULL) + return; + + input_report_key(ts->input_dev, BTN_TOUCH, 1); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 1); +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (ts->boot_mode == RECOVERY_BOOT) +#else + if (ts->boot_mode == MSM_BOOT_MODE_RECOVERY) +#endif + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, points.z); + else { + if (touch_report_num == 1) { + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, points.width_major); + last_width_major = points.width_major; + } else if (!(touch_report_num & 0x7f) || touch_report_num == 30) { //avoid same point info getevent cannot report + //if touch_report_num == 127, every 127 points, change width_major + //down and keep long time, auto repeat per 5 seconds, for weixing + //report move event after down event, for weixing voice delay problem, 30 -> 300ms in order to avoid the intercept by shortcut + if (last_width_major == points.width_major) + last_width_major = points.width_major + 1; + else + last_width_major = points.width_major; + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, last_width_major); + } + if (ts->smart_gesture_support && (points.touch_major > 0x12) &&\ + (points.x > ts->touch_major_limit.width_range) && (points.x < ts->resolution_info.max_x - ts->touch_major_limit.width_range) &&\ + (points.y > ts->touch_major_limit.height_range) && (points.y < ts->resolution_info.max_y - ts->touch_major_limit.height_range)) { + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, points.touch_major); + } + if(!CHK_BIT(ts->irq_slot, (1<input_dev, ABS_MT_POSITION_X, points.x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, points.y); + + TPD_SPECIFIC_PRINT(point_num, "Touchpanel id %d :Down[%4d %4d %4d]\n", id, points.x, points.y, points.z); + +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif +} + +static void tp_touch_up(struct touchpanel_data *ts) +{ + if (ts->input_dev == NULL) + return; + + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif +} + +static void tp_exception_handle(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->reset) { + TPD_INFO("not support ts->ts_ops->reset callback\n"); + return; + } + + ts->ts_ops->reset(ts->chip_data); // after reset, all registers set to default + operate_mode_switch(ts); + + tp_btnkey_release(ts); + tp_touch_release(ts); +} + +static void tp_fw_auto_reset_handle(struct touchpanel_data *ts) +{ + TPD_INFO("%s\n", __func__); + + if(ts->ts_ops->write_ps_status) { + ts->ts_ops->write_ps_status(ts->chip_data, ts->ps_status); + + if (!ts->ps_status) { + if (ts->ts_ops->exit_esd_mode) { + ts->ts_ops->exit_esd_mode(ts->chip_data); + } + } + } + + operate_mode_switch(ts); + + tp_btnkey_release(ts); + tp_touch_release(ts); +} + +static void tp_geture_info_transform(struct gesture_info * gesture, struct resolution_info *resolution_info) +{ + gesture->Point_start.x = gesture->Point_start.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_start.y = gesture->Point_start.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_end.x = gesture->Point_end.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_end.y = gesture->Point_end.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_1st.x = gesture->Point_1st.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_1st.y = gesture->Point_1st.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_2nd.x = gesture->Point_2nd.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_2nd.y = gesture->Point_2nd.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_3rd.x = gesture->Point_3rd.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_3rd.y = gesture->Point_3rd.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); + gesture->Point_4th.x = gesture->Point_4th.x * resolution_info->LCD_WIDTH / (resolution_info->max_x); + gesture->Point_4th.y = gesture->Point_4th.y * resolution_info->LCD_HEIGHT / (resolution_info->max_y); +} + +int sec_double_tap(struct gesture_info *gesture) +{ + uint32_t timeuse = 0; + + if (sigle_num == 0) { + do_gettimeofday(&tpstart); + pointx[0] = gesture->Point_start.x; + pointy[0] = gesture->Point_start.y; + sigle_num ++; + TPD_DEBUG("first enter double tap\n"); + } else if (sigle_num == 1) { + do_gettimeofday(&tpend); + pointx[1] = gesture->Point_start.x; + pointy[1] = gesture->Point_start.y; + sigle_num = 0; + timeuse = 1000000 * (tpend.tv_sec-tpstart.tv_sec) + + tpend.tv_usec-tpstart.tv_usec; + TPD_DEBUG("timeuse = %d, distance[x] = %d, distance[y] = %d\n", timeuse, ABS(pointx[0], pointx[1]), ABS(pointy[0], pointy[1])); + if((ABS(pointx[0], pointx[1]) < 150) && (ABS(pointy[0], pointy[1]) < 200) && (timeuse < 500000)){ + return 1; + }else { + TPD_DEBUG("not match double tap\n"); + do_gettimeofday(&tpstart); + pointx[0] = gesture->Point_start.x; + pointy[0] = gesture->Point_start.y; + sigle_num = 1; + } + } + return 0; + +} + +static void tp_gesture_handle(struct touchpanel_data *ts) +{ + struct gesture_info gesture_info_temp; + + if (!ts->ts_ops->enable_single_tap) { + TPD_INFO("not support ts->ts_ops->enable_single_tap \n"); + return; + } + + if (!ts->ts_ops->get_gesture_info) { + TPD_INFO("not support ts->ts_ops->get_gesture_info callback\n"); + return; + } + + memset(&gesture_info_temp, 0, sizeof(struct gesture_info)); + ts->ts_ops->enable_single_tap(ts->chip_data, true); + ts->ts_ops->get_gesture_info(ts->chip_data, &gesture_info_temp); + tp_geture_info_transform(&gesture_info_temp, &ts->resolution_info); + if (DouTap_enable) { + if(gesture_info_temp.gesture_type == SingleTap) { + if (sec_double_tap(&gesture_info_temp) == 1) + { + gesture_info_temp.gesture_type = DouTap; + } + } + } + + TPD_INFO("detect %s gesture\n", gesture_info_temp.gesture_type == DouTap ? "double tap" : + gesture_info_temp.gesture_type == UpVee ? "up vee" : + gesture_info_temp.gesture_type == DownVee ? "down vee" : + gesture_info_temp.gesture_type == LeftVee ? "(>)" : + gesture_info_temp.gesture_type == RightVee ? "(<)" : + gesture_info_temp.gesture_type == Circle ? "o" : + gesture_info_temp.gesture_type == DouSwip ? "(||)" : + gesture_info_temp.gesture_type == Left2RightSwip ? "(-->)" : + gesture_info_temp.gesture_type == Right2LeftSwip ? "(<--)" : + gesture_info_temp.gesture_type == Up2DownSwip ? "up to down |" : + gesture_info_temp.gesture_type == Down2UpSwip ? "down to up |" : + gesture_info_temp.gesture_type == Mgestrue ? "(M)" : + gesture_info_temp.gesture_type == Sgestrue ? "(S)" : + gesture_info_temp.gesture_type == SingleTap ? "(single tap)" : + gesture_info_temp.gesture_type == Wgestrue ? "(W)" : "unknown"); + + if ((gesture_info_temp.gesture_type == DouTap && DouTap_enable) || + (gesture_info_temp.gesture_type == UpVee && UpVee_enable) || + (gesture_info_temp.gesture_type == LeftVee&& LeftVee_enable) || + (gesture_info_temp.gesture_type == RightVee && RightVee_enable) || + (gesture_info_temp.gesture_type == Circle && Circle_enable) || + (gesture_info_temp.gesture_type == DouSwip && DouSwip_enable) || + (gesture_info_temp.gesture_type == Mgestrue && Mgestrue_enable) || + (gesture_info_temp.gesture_type == Sgestrue && Sgestrue_enable) || + (gesture_info_temp.gesture_type == SingleTap && SingleTap_enable) || + (gesture_info_temp.gesture_type == Wgestrue && Wgestrue_enable)) { + memcpy(&ts->gesture, &gesture_info_temp, sizeof(struct gesture_info)); + input_report_key(ts->input_dev, KEY_F4, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_F4, 0); + input_sync(ts->input_dev); + } +} + +void tp_touch_btnkey_release(void) +{ + struct touchpanel_data *ts = g_tp; + + if (!ts) { + TPD_INFO("ts is NULL\n"); + return ; + } + + tp_touch_release(ts); + tp_btnkey_release(ts); +} + +static void tp_touch_release(struct touchpanel_data *ts) +{ + int i = 0; + +#ifdef TYPE_B_PROTOCOL + for (i = 0; i < ts->max_num; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); + input_sync(ts->input_dev); +#else + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); + input_mt_sync(ts->input_dev); + input_sync(ts->input_dev); +#endif + TPD_INFO("release all touch point and key, clear tp touch down flag\n"); + ts->view_area_touched = 0; //realse all touch point,must clear this flag + ts->touch_count = 0; + ts->irq_slot = 0; + ts->corner_delay_up = -1; +} + +static bool edge_point_process(struct touchpanel_data *ts, struct point_info points) +{ + if (ts->limit_edge) { + if (points.x > ts->edge_limit.left_x2 && points.x < ts->edge_limit.right_x2) { + if (ts->edge_limit.in_which_area == AREA_EDGE) + tp_touch_release(ts); + ts->edge_limit.in_which_area = AREA_NORMAL; + } else if ((points.x > ts->edge_limit.left_x1 && points.x < ts->edge_limit.left_x2) || (points.x >ts->edge_limit.right_x2 && points.x < ts->edge_limit.right_x1)) {//area2 + if (ts->edge_limit.in_which_area == AREA_EDGE) { + ts->edge_limit.in_which_area = AREA_CRITICAL; + } + } else if (points.x < ts->edge_limit.left_x1 || points.x > ts->edge_limit.right_x1) { //area 1 + if (ts->edge_limit.in_which_area == AREA_CRITICAL) { + ts->edge_limit.in_which_area = AREA_EDGE; + return true; + } + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + ts->edge_limit.in_which_area = AREA_EDGE; + } + } + + return false; +} + +static bool corner_point_process(struct touchpanel_data *ts, struct corner_info *corner, struct point_info *points, int i) +{ + int j; + if (ts->limit_corner) { + if ((ts->limit_corner & (1 << CORNER_TOPLEFT)) && (points[i].x < ts->edge_limit.left_x3 && points[i].y < ts->edge_limit.left_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_TOPLEFT].id = i; + corner[CORNER_TOPLEFT].point = points[i]; + corner[CORNER_TOPLEFT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + if ((ts->limit_corner & (1 << CORNER_TOPRIGHT)) && (points[i].x < ts->edge_limit.left_x3 && points[i].y > ts->edge_limit.right_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_TOPRIGHT].id = i; + corner[CORNER_TOPRIGHT].point = points[i]; + corner[CORNER_TOPRIGHT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + if ((ts->limit_corner & (1 << CORNER_BOTTOMLEFT)) && (points[i].x > ts->edge_limit.right_x3 && points[i].y < ts->edge_limit.left_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_BOTTOMLEFT].id = i; + corner[CORNER_BOTTOMLEFT].point = points[i]; + corner[CORNER_BOTTOMLEFT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + if ((ts->limit_corner & (1 << CORNER_BOTTOMRIGHT)) && (points[i].x > ts->edge_limit.right_x3 && points[i].y > ts->edge_limit.right_y1)) { + points[i].type = AREA_CORNER; + if (ts->edge_limit.in_which_area == AREA_NORMAL) + return true; + + corner[CORNER_BOTTOMRIGHT].id = i; + corner[CORNER_BOTTOMRIGHT].point = points[i]; + corner[CORNER_BOTTOMRIGHT].flag = true; + + ts->edge_limit.in_which_area = points[i].type; + } + + if (points[i].type != AREA_CORNER) { + if (ts->edge_limit.in_which_area == AREA_CORNER) { + if(ts->corner_delay_up == 0) { + for (j = 0; j < 4; j++) { + if (corner[j].flag) { +#ifdef TYPE_B_PROTOCOL + input_mt_slot(ts->input_dev, corner[j].id); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); +#endif + } + } + ts->corner_delay_up = -1; + } else { + ts->corner_delay_up = 1; + } + } + if(ts->corner_delay_up == -1) { + points[i].type = AREA_NORMAL; + ts->edge_limit.in_which_area = points[i].type; + } + } + + } + + return false; +} + +static void tp_touch_handle(struct touchpanel_data *ts) +{ + int i = 0; + uint8_t finger_num = 0, touch_near_edge = 0; + int obj_attention = 0; + struct point_info *points; + struct corner_info corner[4]; + static struct point_info last_point = {.x = 0, .y = 0}; + static int touch_report_num = 0; + + if (!ts->ts_ops->get_touch_points) { + TPD_INFO("not support ts->ts_ops->get_touch_points callback\n"); + return; + } + + points= kzalloc(sizeof(struct point_info)*ts->max_num, GFP_KERNEL); + if (!points) { + TPD_INFO("points kzalloc failed\n"); + return; + } + memset(corner, 0, sizeof(corner)); + if (ts->reject_point) { //sensor will reject point when call mode. + if (ts->touch_count) { +#ifdef TYPE_B_PROTOCOL + for (i = 0; i < ts->max_num; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif + input_sync(ts->input_dev); + } + kfree(points); + return; + } + obj_attention = ts->ts_ops->get_touch_points(ts->chip_data, points, ts->max_num); + if ((obj_attention & TOUCH_BIT_CHECK) != 0) { + for (i = 0; i < ts->max_num; i++) { + if (((obj_attention & TOUCH_BIT_CHECK) >> i) & 0x01 && (points[i].status == 0)) // buf[0] == 0 is wrong point, no process + continue; + if (((obj_attention & TOUCH_BIT_CHECK) >> i) & 0x01 && (points[i].status != 0)) { + //Edge process before report abs + if (ts->edge_limit_support) { + if (ts->corner_delay_up < 1 && corner_point_process(ts, corner, points, i)) + continue; + if (edge_point_process(ts, points[i])) + continue; + } +#ifdef TYPE_B_PROTOCOL + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); +#endif + touch_report_num++; + tp_touch_down(ts, points[i], touch_report_num, i); + SET_BIT(ts->irq_slot, (1< ts->resolution_info.max_x / 100 && points[i].x < ts->resolution_info.max_x * 99 / 100) { + ts->view_area_touched = finger_num; + } else { + touch_near_edge++; + } + /*strore the last point data*/ + memcpy(&last_point, &points[i], sizeof(struct point_info)); + } +#ifdef TYPE_B_PROTOCOL + else { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + } + + if(ts->corner_delay_up > -1) { + TPD_DETAIL("corner_delay_up is %d\n", ts->corner_delay_up); + } + ts->corner_delay_up = ts->corner_delay_up > 0 ? ts->corner_delay_up - 1 : ts->corner_delay_up; + if (touch_near_edge == finger_num) { //means all the touchpoint is near the edge + ts->view_area_touched = 0; + } + if(ts->ear_sense_support && ts->es_enable && (finger_num > ts->touch_count)) { + ts->delta_state = TYPE_DELTA_BUSY; + queue_work(ts->delta_read_wq, &ts->read_delta_work); + } + } else { + finger_num = 0; + touch_report_num = 0; +#ifdef TYPE_B_PROTOCOL + for (i = 0; i < ts->max_num; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } +#endif + tp_touch_up(ts); + ts->view_area_touched = 0; + ts->irq_slot = 0; + ts->corner_delay_up = -1; + TPD_DETAIL("all touch up,view_area_touched=%d finger_num=%d\n",ts->view_area_touched, finger_num); + TPD_INFO("last point x:%d y:%d\n", last_point.x, last_point.y); + if (ts->edge_limit_support) + ts->edge_limit.in_which_area = AREA_NOTOUCH; + } + input_sync(ts->input_dev); + ts->touch_count = finger_num; + kfree(points); +} + +static void tp_btnkey_release(struct touchpanel_data *ts) +{ + if (CHK_BIT(ts->vk_bitmap, BIT_MENU)) + input_report_key_reduce(ts->kpd_input_dev, KEY_MENU, 0); + if (CHK_BIT(ts->vk_bitmap, BIT_HOME)) + input_report_key_reduce(ts->kpd_input_dev, KEY_HOMEPAGE, 0); + if (CHK_BIT(ts->vk_bitmap, BIT_BACK)) + input_report_key_reduce(ts->kpd_input_dev, KEY_BACK, 0); + input_sync(ts->kpd_input_dev); +} + +static void tp_btnkey_handle(struct touchpanel_data *ts) +{ + u8 touch_state = 0; + + if (ts->vk_type != TYPE_AREA_SEPRATE) { + TPD_DEBUG("TP vk_type not proper, checktouchpanel, button-type\n"); + + return; + } + if (!ts->ts_ops->get_keycode) { + TPD_INFO("not support ts->ts_ops->get_keycode callback\n"); + + return; + } + touch_state = ts->ts_ops->get_keycode(ts->chip_data); + + if (CHK_BIT(ts->vk_bitmap, BIT_MENU)) + input_report_key_reduce(ts->kpd_input_dev, KEY_MENU, CHK_BIT(touch_state, BIT_MENU)); + if (CHK_BIT(ts->vk_bitmap, BIT_HOME)) + input_report_key_reduce(ts->kpd_input_dev, KEY_HOMEPAGE, CHK_BIT(touch_state, BIT_HOME)); + if (CHK_BIT(ts->vk_bitmap, BIT_BACK)) + input_report_key_reduce(ts->kpd_input_dev, KEY_BACK, CHK_BIT(touch_state, BIT_BACK)); + input_sync(ts->kpd_input_dev); +} + +static void tp_config_handle(struct touchpanel_data *ts) +{ + int ret = 0; + if (!ts->ts_ops->fw_handle) { + TPD_INFO("not support ts->ts_ops->fw_handle callback\n"); + return; + } + + ret = ts->ts_ops->fw_handle(ts->chip_data); +} + +static void tp_datalogger_handle(struct touchpanel_data *ts) +{ + if (!ts->ts_ops->data_logger_get) { + TPD_INFO("not support ts->ts_ops->data_logger_get callback\n"); + return; + } + + ts->ts_ops->data_logger_get(ts->chip_data); +} + +static void tp_face_detect_handle(struct touchpanel_data *ts) +{ + int ps_state = 0; + + if (!ts->ts_ops->get_face_state) { + TPD_INFO("not support ts->ts_ops->get_face_state callback\n"); + return; + } + TPD_INFO("enter tp_face_detect_handle\n"); + ps_state = ts->ts_ops->get_face_state(ts->chip_data); + TPD_DETAIL("ps state: %s\n", ps_state > 0 ? "near" : "far"); + + input_event(ps_input_dev, EV_MSC, MSC_RAW, ps_state > 0); + input_sync(ps_input_dev); +} + +static void tp_async_work_callback(void) +{ + struct touchpanel_data *ts = g_tp; + + if (ts == NULL) + return; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if ((ts->boot_mode == META_BOOT || ts->boot_mode == FACTORY_BOOT)) +#else + if ((ts->boot_mode == MSM_BOOT_MODE_FACTORY || ts->boot_mode == MSM_BOOT_MODE_RF)) +#endif + + { + TPD_INFO("%s: in ftm mode, no need to call back\n", __func__); + return; + } + + + TPD_INFO("%s: async work\n", __func__); + if (ts->use_resume_notify && ts->suspend_state == TP_RESUME_COMPLETE) { + complete(&ts->resume_complete); + return; + } + + if (ts->in_test_process) { + TPD_INFO("%s: In test process, do not switch mode\n", __func__); + return; + } + + queue_work(ts->async_workqueue, &ts->async_work); +} + +static void tp_async_work_lock(struct work_struct *work) +{ + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, async_work); + mutex_lock(&ts->mutex); + if (ts->ts_ops->async_work) { + ts->ts_ops->async_work(ts->chip_data); + } + mutex_unlock(&ts->mutex); +} + +static void tp_work_common_callback(void) +{ + struct touchpanel_data *ts; + + if (g_tp == NULL) + return; + ts = g_tp; + tp_work_func(ts); +} + +static void tp_work_func(struct touchpanel_data *ts) +{ + u8 cur_event = 0; + + if (!ts->ts_ops->trigger_reason && !ts->ts_ops->u32_trigger_reason) { + TPD_INFO("not support ts_ops->trigger_reason callback\n"); + return; + } + /* + * trigger_reason:this callback determine which trigger reason should be + * The value returned has some policy! + * 1.IRQ_EXCEPTION /IRQ_GESTURE /IRQ_IGNORE /IRQ_FW_CONFIG --->should be only reported individually + * 2.IRQ_TOUCH && IRQ_BTN_KEY --->should depends on real situation && set correspond bit on trigger_reason + */ + if (ts->ts_ops->u32_trigger_reason) { + cur_event = ts->ts_ops->u32_trigger_reason(ts->chip_data, ts->gesture_enable, ts->is_suspended); + } else { + cur_event = ts->ts_ops->trigger_reason(ts->chip_data, ts->gesture_enable, ts->is_suspended); + } + if (CHK_BIT(cur_event, IRQ_TOUCH) || CHK_BIT(cur_event, IRQ_BTN_KEY) || CHK_BIT(cur_event, IRQ_DATA_LOGGER) || CHK_BIT(cur_event, IRQ_FACE_STATE)) { + if (CHK_BIT(cur_event, IRQ_BTN_KEY)) { + tp_btnkey_handle(ts); + } + if (CHK_BIT(cur_event, IRQ_TOUCH)) { + tp_touch_handle(ts); + } + if (CHK_BIT(cur_event, IRQ_DATA_LOGGER)) { + tp_datalogger_handle(ts); + } + if (CHK_BIT(cur_event, IRQ_FACE_STATE) && ts->fd_enable) { + tp_face_detect_handle(ts); + } + } else if (CHK_BIT(cur_event, IRQ_GESTURE)) { + tp_gesture_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_EXCEPTION)) { + tp_exception_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_FW_CONFIG)) { + tp_config_handle(ts); + } else if (CHK_BIT(cur_event, IRQ_FW_AUTO_RESET)) { + tp_fw_auto_reset_handle(ts); + } else { + TPD_DEBUG("unknown irq trigger reason\n"); + } +} + +static void tp_work_func_unlock(struct touchpanel_data *ts) +{ + if (ts->ts_ops->irq_handle_unlock) { + ts->ts_ops->irq_handle_unlock(ts->chip_data); + } +} + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +extern void primary_display_esd_check_enable(int enable); +#endif +void __attribute__((weak)) display_esd_check_enable_bytouchpanel(bool enable) {return;} + +static void tp_fw_update_work(struct work_struct *work) +{ + const struct firmware *fw = NULL; + int ret, fw_update_result = 0; + int count_tmp = 0, retry = 20; + char *p_node = NULL; + char *fw_name_fae = NULL; + char *postfix = "_FAE"; + uint8_t copy_len = 0; + struct touchpanel_data *ts = NULL; + + if (himax_boot_mode == 1) + ts = container_of(work, struct touchpanel_data, + fw_update_delayed_work.work); + else + ts = container_of(work, struct touchpanel_data, + fw_update_work); + if (ts == NULL) + TPD_INFO("%s: %s\n", __func__, __LINE__); + + if (!ts->ts_ops->fw_check || !ts->ts_ops->reset) { + TPD_INFO("not support ts_ops->fw_check callback\n"); + complete(&ts->fw_complete); + return; + } + + TPD_INFO("%s: fw_name = %s\n", __func__, ts->panel_data.fw_name); + + mutex_lock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + ts->loading_fw = true; + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + display_esd_check_enable_bytouchpanel(0); +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + primary_display_esd_check_enable(0); //avoid rst pulled to low while updating +#endif + + if (ts->ts_ops->fw_update) { + do { + if(ts->firmware_update_type == 0 || ts->firmware_update_type == 1) { + if(ts->fw_update_app_support) { + fw_name_fae = kzalloc(MAX_FW_NAME_LENGTH, GFP_KERNEL); + if(fw_name_fae == NULL) { + TPD_INFO("fw_name_fae kzalloc error!\n"); + goto EXIT; + } + p_node = strstr(ts->panel_data.fw_name, "."); + copy_len = p_node - ts->panel_data.fw_name; + memcpy(fw_name_fae, ts->panel_data.fw_name, copy_len); + strlcat(fw_name_fae, postfix, MAX_FW_NAME_LENGTH); + strlcat(fw_name_fae, p_node, MAX_FW_NAME_LENGTH); + TPD_INFO("fw_name_fae is %s\n", fw_name_fae); + ret = request_firmware(&fw, fw_name_fae, ts->dev); + if (!ret) + break; + } else { + if (himax_boot_mode == 1) { + msleep(500); + TPD_INFO("request_firmware for recovery\n"); + } + ret = request_firmware(&fw, ts->panel_data.fw_name, ts->dev); + if (!ret) + break; + } + } else { + ret = request_firmware_select(&fw, ts->panel_data.fw_name, ts->dev); + if (!ret) + break; + } + } while((ret < 0) && (--retry > 0)); + + TPD_INFO("retry times %d\n", 20 - retry); + + if (!ret || ts->is_noflash_ic) { + do { + count_tmp++; + ret = ts->ts_ops->fw_update(ts->chip_data, fw, ts->force_update); + fw_update_result = ret; + if (ret == FW_NO_NEED_UPDATE) { + break; + } + + if(!ts->is_noflash_ic) { //noflash update fw in reset and do bootloader reset in get_chip_info + ret |= ts->ts_ops->reset(ts->chip_data); + ret |= ts->ts_ops->get_chip_info(ts->chip_data); + } + + ret |= ts->ts_ops->fw_check(ts->chip_data, &ts->resolution_info, &ts->panel_data); + } while((count_tmp < 2) && (ret != 0)); + + if(fw != NULL) { + release_firmware(fw); + } + } else { + TPD_INFO("%s: fw_name request failed %s %d\n", __func__, ts->panel_data.fw_name, ret); + goto EXIT; + } + } + + tp_touch_release(ts); + tp_btnkey_release(ts); + operate_mode_switch(ts); + if (fw_update_result != FW_NO_NEED_UPDATE) { + if (ts->spurious_fp_support && ts->ts_ops->finger_proctect_data_get) { + ts->ts_ops->finger_proctect_data_get(ts->chip_data); + } + if (ts->ts_ops->data_logger_open) { + ts->ts_ops->data_logger_open(ts->chip_data); + } + } + +EXIT: + ts->loading_fw = false; + + display_esd_check_enable_bytouchpanel(1); +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + primary_display_esd_check_enable(1); //avoid rst pulled to low while updating +#endif + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, true); + } + + kfree(fw_name_fae); + fw_name_fae = NULL; + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + mutex_unlock(&ts->mutex); + + ts->force_update = 0; + + complete(&ts->fw_complete); //notify to init.rc that fw update finished + return; +} + +#ifndef TPD_USE_EINT +static enum hrtimer_restart touchpanel_timer_func(struct hrtimer *timer) +{ + struct touchpanel_data *ts = container_of(timer, struct touchpanel_data, timer); + + mutex_lock(&ts->mutex); + tp_work_func(ts); + mutex_unlock(&ts->mutex); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +#else +static irqreturn_t tp_irq_thread_fn(int irq, void *dev_id) +{ + struct touchpanel_data *ts = (struct touchpanel_data *)dev_id; + + if (ts->int_mode == BANNABLE) { + __pm_stay_awake(ts->source); //avoid system enter suspend lead to i2c error + mutex_lock(&ts->mutex); + tp_work_func(ts); + mutex_unlock(&ts->mutex); + __pm_relax(ts->source); + } else { + TPD_DEBUG("enter func unlock\n"); + tp_work_func_unlock(ts); + } + return IRQ_HANDLED; +} +#endif + +/** + * tp_gesture_enable_flag - expose gesture control status for other module. + * Return gesture_enable status. + */ +int tp_gesture_enable_flag(void) +{ + if (!g_tp || !g_tp->is_incell_panel) + return LCD_POWER_OFF; + + return (g_tp->gesture_enable > 0)?LCD_POWER_ON: LCD_POWER_OFF; +} + +/* + *Interface for lcd to control reset pin + */ +int tp_control_reset_gpio(bool enable) +{ + if (!g_tp) { + return 0; + } + + if (gpio_is_valid(g_tp->hw_res.reset_gpio)) { + if (g_tp->ts_ops->reset_gpio_control) { + g_tp->ts_ops->reset_gpio_control(g_tp->chip_data, enable); + } + } + + return 0; +} + +/* + * check_usb_state----expose to be called by charger int to get usb state + * @usb_state : 1 if usb checked, otherwise is 0 + */ +void switch_usb_state(int usb_state) +{ + if (!g_tp) { + return; + } + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if ((g_tp->boot_mode == META_BOOT || g_tp->boot_mode == FACTORY_BOOT)) +#else + if ((g_tp->boot_mode == MSM_BOOT_MODE_FACTORY || g_tp->boot_mode == MSM_BOOT_MODE_RF)) +#endif + + { + TPD_INFO("Ftm mode, do not switch usb state\n"); + return; + } + + if (g_tp->charger_pump_support && (g_tp->is_usb_checked != usb_state)) { + g_tp->is_usb_checked = !!usb_state; + TPD_INFO("%s: check usb state : %d, is_suspended: %d\n", __func__, usb_state, g_tp->is_suspended); + if (!g_tp->is_suspended && (g_tp->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + mutex_lock(&g_tp->mutex); + g_tp->ts_ops->mode_switch(g_tp->chip_data, MODE_CHARGE, g_tp->is_usb_checked); + mutex_unlock(&g_tp->mutex); + } + } +} +EXPORT_SYMBOL(switch_usb_state); + +/* + * gesture_enable = 0 : disable gesture + * gesture_enable = 1 : enable gesture when ps is far away + * gesture_enable = 2 : disable gesture when ps is near + */ +static ssize_t proc_gesture_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int i = 15; + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + TPD_DEBUG("%s write argc1[0x%x],argc2[0x%x]\n",__func__,buf[0],buf[1]); + UpVee_enable = (buf[0] & BIT0)?1:0; + DouSwip_enable = (buf[0] & BIT1)?1:0; + LeftVee_enable = (buf[0] & BIT3)?1:0; + RightVee_enable = (buf[0] & BIT4)?1:0; + Circle_enable = (buf[0] & BIT6)?1:0; + DouTap_enable = (buf[0] & BIT7)?1:0; + Sgestrue_enable = (buf[1] & BIT0)?1:0; + Mgestrue_enable = (buf[1] & BIT1)?1:0; + Wgestrue_enable = (buf[1] & BIT2)?1:0; + SingleTap_enable = (buf[1] & BIT3)?1:0; + Enable_gesture = (buf[1] & BIT7)?1:0; + + if (UpVee_enable || DouSwip_enable || LeftVee_enable || RightVee_enable + || Circle_enable || DouTap_enable || Sgestrue_enable || Mgestrue_enable + || Wgestrue_enable || SingleTap_enable || Enable_gesture) { + value = 1; + } else { + value = 0; + } + + if((ts->is_suspended)){ + while((TP_Panel->panel_initialized)&&(i>0)){ + usleep_range(10000, 10200); + i--; + } + TPD_INFO("%s: wait for LCM panel off , time = %d\n", __func__, i); + } + + gesture_mode_value = value; + TPD_INFO("%s: gesture_mode_value = value = %d\n", __func__, value); + + mutex_lock(&ts->mutex); + if (ts->gesture_enable != value) { + ts->gesture_enable = value; + tp_1v8_power = ts->gesture_enable; + TPD_INFO("%s: gesture_enable = %d, is_suspended = %d\n", __func__, ts->gesture_enable, ts->is_suspended); + if (ts->is_incell_panel && (ts->suspend_state == TP_RESUME_EARLY_EVENT) && (ts->tp_resume_order == LCD_TP_RESUME)) { + TPD_INFO("tp will resume, no need mode_switch in incell panel\n"); /*avoid i2c error or tp rst pulled down in lcd resume*/ + } else if (ts->is_suspended) + operate_mode_switch(ts); + }else { + TPD_INFO("%s: do not do same operator :%d\n", __func__, value); + } + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_gesture_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("gesture_enable is: %d\n", ts->gesture_enable); + ret = sprintf(page, "%d\n", ts->gesture_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_coordinate_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s:gesture_type = %d\n", __func__, ts->gesture.gesture_type); + ret = sprintf(page, "%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d\n", ts->gesture.gesture_type, + ts->gesture.Point_start.x, ts->gesture.Point_start.y, ts->gesture.Point_end.x, ts->gesture.Point_end.y, + ts->gesture.Point_1st.x, ts->gesture.Point_1st.y, ts->gesture.Point_2nd.x, ts->gesture.Point_2nd.y, + ts->gesture.Point_3rd.x, ts->gesture.Point_3rd.y, ts->gesture.Point_4th.x, ts->gesture.Point_4th.y, + ts->gesture.clockwise); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations proc_gesture_control_fops = { + .write = proc_gesture_control_write, + .read = proc_gesture_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static const struct file_operations proc_coordinate_fops = { + .read = proc_coordinate_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_ps_status_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + if (count > 2) + return count; + if (!ts) + return count; + + if (!ts->ts_ops->write_ps_status) { + TPD_INFO("not support ts_ops->write_ps_status callback\n"); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + mutex_lock(&ts->mutex); + ts->ps_status = value; + ts->ts_ops->write_ps_status(ts->chip_data, value); + mutex_unlock(&ts->mutex); + } + + return count; +} + +static ssize_t proc_ps_support_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else if (!ts->ts_ops->write_ps_status) { + sprintf(page, "%d\n", -1); + } else { + sprintf(page, "%d\n", 0);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_write_ps_status_fops = { + .write = proc_ps_status_write, + .read = proc_ps_support_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +//proc/touchpanel/game_switch_enable +static ssize_t proc_game_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (!ts->ts_ops->mode_switch) { + TPD_INFO("%s:not support ts_ops->mode_switch callback\n",__func__); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%x", &value); + ts->noise_level = value; + + TPD_INFO("%s: game_switch value=0x%x\n", __func__, value); + if (!ts->is_suspended) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_GAME, value > 0); + mutex_unlock(&ts->mutex); + } else { + TPD_INFO("%s: game_switch_support is_suspended.\n", __func__); + } + + return count; +} + +static ssize_t proc_game_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->noise_level);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_game_switch_fops = { + .write = proc_game_switch_write, + .read = proc_game_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_gesture_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (gesture_switch_value == value) { + //TPD_INFO("gesture_switch_value is %d\n", value); + return count; + } + gesture_switch_value = value; + value = value - 1; //cmd 2 is disable gesture,cmd 1 is open gesture + ts->gesture_switch = !value; + + TPD_DEBUG("%s: gesture_switch value= %d\n", __func__, value); + if ((ts->is_suspended == 1) && (ts->gesture_enable ==1)) { + __pm_stay_awake(ts->source); //avoid system enter suspend lead to i2c error + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE_SWITCH, ts->gesture_switch); + mutex_unlock(&ts->mutex); + __pm_relax(ts->source); + } else { + TPD_INFO("%s: gesture mode switch must be suspend.\n", __func__); + } + + return count; +} + +static ssize_t proc_gesture_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->gesture_switch);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + + +static const struct file_operations proc_gesture_switch_fops = { + .write = proc_gesture_switch_write, + .read = proc_gesture_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_reject_point_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + ts->reject_point = value; + + TPD_INFO("%s: ts->reject_poin = %d\n", __func__, value); + + return count; +} + +static ssize_t proc_reject_point_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->reject_point);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_reject_point_fops = { + .write = proc_reject_point_write, + .read = proc_reject_point_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_limit_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0 ; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 4) { + TPD_INFO("%s:count > 4\n",__func__); + return count; + } + + if (!ts) { + TPD_INFO("%s: ts is NULL\n",__func__); + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + ts->limit_switch = value; + + TPD_DEBUG("%s: ts->limit_switch = %d\n", __func__, value); + if (ts->is_suspended == 0) { + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_EDGE, ts->limit_switch); + mutex_unlock(&ts->mutex); + } + return count; +} + +static ssize_t proc_limit_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) { + sprintf(page, "%d\n", -1);//no support + } else { + sprintf(page, "%d\n", ts->limit_switch);//support + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations proc_limit_switch_fops = { + .write = proc_limit_switch_write, + .read = proc_limit_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +//proc/touchpanel/black_screen_test +static ssize_t proc_black_screen_test_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + int retry = 20; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + TPD_INFO("%s %ld %lld\n", __func__, count, *ppos); + + if (!ts || !ts->gesture_test.flag) + return 0; + + ts->gesture_test.message = kzalloc(256, GFP_KERNEL); + if (!ts->gesture_test.message) { + TPD_INFO("failed to alloc memory\n"); + return 0; + } + + /* wait until tp is in sleep, then sleep 500ms to make sure tp is in gesture mode*/ + do { + if (ts->is_suspended) { + msleep(500); + break; + } + msleep(200); + } while(--retry); + + TPD_INFO("%s retry times %d\n", __func__, retry); + if (retry == 0 && !ts->is_suspended) { + sprintf(ts->gesture_test.message, "1 errors: not in sleep "); + goto OUT; + } + + mutex_lock(&ts->mutex); + if (ts->ts_ops->black_screen_test) { + ts->ts_ops->black_screen_test(ts->chip_data, ts->gesture_test.message); + } else { + TPD_INFO("black_screen_test not support\n"); + sprintf(ts->gesture_test.message, "1 errors:not support gesture test"); + } + mutex_unlock(&ts->mutex); + +OUT: + ts->gesture_test.flag = false; + ts->gesture_enable = ts->gesture_test.gesture_backup; + + ret = simple_read_from_buffer(user_buf, count, ppos, ts->gesture_test.message, strlen(ts->gesture_test.message)); + kfree(ts->gesture_test.message); + return ret; +} + +static ssize_t proc_black_screen_test_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2 || !ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + TPD_INFO("%s %d\n", __func__, value); + + ts->gesture_test.gesture_backup = ts->gesture_enable; + ts->gesture_enable = true; + ts->gesture_test.flag = !!value; + + return count; +} + +static const struct file_operations proc_black_screen_test_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_black_screen_test_read, + .write = proc_black_screen_test_write, +}; + +//proc/touchpanel/irq_depth +static ssize_t proc_get_irq_depth_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + struct irq_desc *desc = NULL; + + if(!ts) { + return count; + } + + desc = irq_to_desc(ts->irq); + + sprintf(page, "%d\n", desc->depth); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t proc_irq_status_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2 || !ts) + return count; + + if (copy_from_user(buf, user_buf, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + TPD_INFO("%s %d, %s ts->irq=%d\n", __func__, value, value ? "enable" : "disable", ts->irq); + + if (value == 1) { + enable_irq(ts->irq); + } else { + disable_irq_nosync(ts->irq); + } + + return count; +} + +static const struct file_operations proc_get_irq_depth_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_get_irq_depth_read, + .write = proc_irq_status_write, +}; + +static ssize_t proc_vendor_id_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if(!ts) { + return count; + } + + sprintf(page, "%d\n", ts->panel_data.tp_type); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations vendor_id_proc_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_vendor_id_read, +}; + +static ssize_t proc_glove_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int ret = 0 ; + char buf[3] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + if (count > 2) + return count; + if (!ts->ts_ops->mode_switch) { + TPD_INFO("not support ts_ops->mode_switch callback\n"); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &ret); + TPD_INFO("%s:buf = %d, ret = %d\n", __func__, *buf, ret); + if ((ret == 0) || (ret == 1)) { + mutex_lock(&ts->mutex); + ts->glove_enable = ret; + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_GLOVE, ts->glove_enable); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + mutex_unlock(&ts->mutex); + } + switch(ret) { + case 0: + TPD_DEBUG("tp_glove_func will be disable\n"); + break; + case 1: + TPD_DEBUG("tp_glove_func will be enable\n"); + break; + default: + TPD_DEBUG("Please enter 0 or 1 to open or close the glove function\n"); + } + + return count; +} + +static ssize_t proc_glove_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_INFO("glove mode enable is: %d\n", ts->glove_enable); + ret = sprintf(page, "%d\n", ts->glove_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations proc_glove_control_fops = { + .write = proc_glove_control_write, + .read = proc_glove_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t cap_vk_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct button_map *button_map; + if (!g_tp) + return sprintf(buf, "not support"); + + button_map = &g_tp->button_map; + return sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_MENU) ":%d:%d:%d:%d" + ":" __stringify(EV_KEY) ":" __stringify(KEY_HOMEPAGE) ":%d:%d:%d:%d" + ":" __stringify(EV_KEY) ":" __stringify(KEY_BACK) ":%d:%d:%d:%d" + "\n", button_map->coord_menu.x, button_map->coord_menu.y, button_map->width_x, button_map->height_y, \ + button_map->coord_home.x, button_map->coord_home.y, button_map->width_x, button_map->height_y, \ + button_map->coord_back.x, button_map->coord_back.y, button_map->width_x, button_map->height_y); +} + +static struct kobj_attribute virtual_keys_attr = { + .attr = { + .name = "virtualkeys."TPD_DEVICE, + .mode = S_IRUGO, + }, + .show = &cap_vk_show, +}; + +static struct attribute *properties_attrs[] = { + &virtual_keys_attr.attr, + NULL +}; + +static struct attribute_group properties_attr_group = { + .attrs = properties_attrs, +}; + +static ssize_t proc_debug_control_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[PAGESIZE]; + + TPD_INFO("%s: tp_debug = %d.\n", __func__, tp_debug); + sprintf(page, "%d", tp_debug); + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_debug_control_write(struct file *file, const char __user *buf, size_t count, loff_t *lo) +{ + int tmp = 0; + char buffer[4] = {0}; + + if (count > 2) { + return count; + } + + if (copy_from_user(buffer, buf, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (1 == sscanf(buffer, "%d", &tmp)) { + tp_debug = tmp; + } else { + TPD_DEBUG("invalid content: '%s', length = %zd\n", buf, count); + } + + return count; +} + +static const struct file_operations proc_debug_control_ops = +{ + .write = proc_debug_control_write, + .read = proc_debug_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_limit_area_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + char page[PAGESIZE]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + TPD_DEBUG("limit_area is: %d\n", ts->edge_limit.limit_area); + ret = sprintf(page, "limit_area = %d left_x1 = %d right_x1 = %d left_x2 = %d right_x2 = %d left_x3 = %d right_x3 = %d left_y1 = %d right_y1 = %d left_y2 = %d right_y2 = %d left_y3 = %d right_y3 = %d\n", + ts->edge_limit.limit_area, ts->edge_limit.left_x1, ts->edge_limit.right_x1, ts->edge_limit.left_x2, ts->edge_limit.right_x2, ts->edge_limit.left_x3, ts->edge_limit.right_x3, + ts->edge_limit.left_y1, ts->edge_limit.right_y1, ts->edge_limit.left_y2, ts->edge_limit.right_y2, ts->edge_limit.left_y3, ts->edge_limit.right_y3); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_limit_area_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8]; + int temp; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%d", &temp); + if (temp < 0 || temp > 10) + return count; + + ts->edge_limit.limit_area = temp; + ts->edge_limit.left_x1 = (ts->edge_limit.limit_area*1000)/100; + ts->edge_limit.right_x1 = ts->resolution_info.LCD_WIDTH - ts->edge_limit.left_x1; + ts->edge_limit.left_x2 = 2 * ts->edge_limit.left_x1; + ts->edge_limit.right_x2 = ts->resolution_info.LCD_WIDTH - (2 * ts->edge_limit.left_x1); + ts->edge_limit.left_x3 = 5 * ts->edge_limit.left_x1; + ts->edge_limit.right_x3 = ts->resolution_info.LCD_WIDTH - (5 * ts->edge_limit.left_x1); + + TPD_INFO("limit_area = %d; left_x1 = %d; right_x1 = %d; left_x2 = %d; right_x2 = %d; left_x3 = %d; right_x3 = %d\n", + ts->edge_limit.limit_area, ts->edge_limit.left_x1, ts->edge_limit.right_x1, ts->edge_limit.left_x2, ts->edge_limit.right_x2, ts->edge_limit.left_x3, ts->edge_limit.right_x3); + + ts->edge_limit.left_y1 = (ts->edge_limit.limit_area*1000)/100; + ts->edge_limit.right_y1 = ts->resolution_info.LCD_HEIGHT - ts->edge_limit.left_y1; + ts->edge_limit.left_y2 = 2 * ts->edge_limit.left_y1; + ts->edge_limit.right_y2 = ts->resolution_info.LCD_HEIGHT - (2 * ts->edge_limit.left_y1); + ts->edge_limit.left_y3 = 5 * ts->edge_limit.left_y1; + ts->edge_limit.right_y3 = ts->resolution_info.LCD_HEIGHT - (5 * ts->edge_limit.left_y1); + + TPD_INFO("limit_area = %d; left_y1 = %d; right_y1 = %d; left_y2 = %d; right_y2 = %d; left_y3 = %d; right_y3 = %d\n", + ts->edge_limit.limit_area, ts->edge_limit.left_y1, ts->edge_limit.right_y1, ts->edge_limit.left_y2, ts->edge_limit.right_y2, ts->edge_limit.left_y3, ts->edge_limit.right_y3); + + return count; +} + +static const struct file_operations proc_limit_area_ops = +{ + .read = proc_limit_area_read, + .write = proc_limit_area_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_limit_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + char page[PAGESIZE]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_INFO("limit_enable is: 0x%x, ts->limit_edge = 0x%x, ts->limit_corner = 0x%x\n", ts->limit_enable, ts->limit_edge, ts->limit_corner); + ret = sprintf(page, "%d\n", ts->limit_enable); + + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_limit_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[8] = {0}; + int ret, temp; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + if (count > 3) + count = 3; + if (copy_from_user(buf, buffer, count)) { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%x", &temp); + if (temp > 0x1F) { + TPD_INFO("%s: temp = 0x%x > 0x1F \n", __func__, temp); + return count; + } + + mutex_lock(&ts->mutex); + ts->limit_enable = temp; + ts->limit_edge = ts->limit_enable & 1; + ts->limit_corner = ts->limit_enable >> 1; + TPD_INFO("%s: limit_enable = 0x%x, ts->limit_edge = 0x%x, ts->limit_corner=0x%x\n", __func__, ts->limit_enable, ts->limit_edge, ts->limit_corner); + + if (ts->is_suspended == 0) { + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_EDGE, ts->limit_edge); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + } + mutex_unlock(&ts->mutex); + + return count; +} + +static const struct file_operations proc_limit_control_ops = +{ + .read = proc_limit_control_read, + .write = proc_limit_control_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_fw_update_write(struct file *file, const char __user *page, size_t size, loff_t *lo) +{ + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int val = 0; + int ret = 0; + char buf[4] = {0}; + if (!ts) + return size; + if (size > 2) + return size; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (ts->boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT) +#else + if (ts->boot_mode == MSM_BOOT_MODE_CHARGE) +#endif + + { + TPD_INFO("boot mode is MSM_BOOT_MODE__CHARGE,not need update tp firmware\n"); + return size; + } + + + if (copy_from_user(buf, page, size)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return size; + } + + sscanf(buf, "%d", &val); + ts->firmware_update_type = val; + if (!ts->force_update && ts->firmware_update_type != 2) + ts->force_update = !!val; + + schedule_work(&ts->fw_update_work); + + ret = wait_for_completion_killable_timeout(&ts->fw_complete, FW_UPDATE_COMPLETE_TIMEOUT); + if (ret < 0) { + TPD_INFO("kill signal interrupt\n"); + } + + TPD_INFO("fw update finished\n"); + return size; +} + + + +static const struct file_operations proc_fw_update_ops = +{ + .write = proc_fw_update_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_finger_protect_result_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[16] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + if(!ts) + return 0; + + if(ts->spuri_fp_touch.fp_touch_st == FINGER_PROTECT_TOUCH_UP || ts->spuri_fp_touch.fp_touch_st == FINGER_PROTECT_TOUCH_DOWN) + TPD_INFO("%s report_finger_protect = %d\n", __func__, ts->spuri_fp_touch.fp_touch_st); + ret = sprintf(page, "%d\n", ts->spuri_fp_touch.fp_touch_st); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + + +static const struct file_operations proc_finger_protect_result= { + .read = proc_finger_protect_result_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_finger_protect_trigger_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int op = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) { + return count; + } + if (!ts) { + return count; + } + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + if (1 == sscanf(buf, "%d", &op)) { + if (op == 1) { + ts->spuri_fp_touch.fp_trigger= true; + ts->spuri_fp_touch.fp_touch_st = FINGER_PROTECT_NOTREADY; + TPD_INFO("%s : %d\n",__func__,__LINE__); + wake_up_interruptible(&waiter); + } + } else { + TPD_INFO("invalid content: '%s', length = %zd\n", buffer, count); + return -EINVAL; + } + + return count; +} + +static const struct file_operations proc_finger_protect_trigger= { + .write = proc_finger_protect_trigger_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +void lcd_wakeup_finger_protect(bool wakeup) +{ + TPD_INFO("%s wakeup=%d\n",__func__,wakeup); + if (g_tp != NULL) { + if (g_tp->spuri_fp_touch.lcd_trigger_fp_check) { + if(wakeup) { + g_tp->spuri_fp_touch.lcd_resume_ok = true; + wake_up_interruptible(&waiter); + } + else { + mutex_lock(&g_tp->mutex); + g_tp->spuri_fp_touch.lcd_resume_ok = false; + mutex_unlock(&g_tp->mutex); + } + } + } +} + +static int finger_protect_handler(void *data) +{ + struct touchpanel_data *ts = (struct touchpanel_data *)data; + if (!ts) { + TPD_INFO("ts is null should nerver get here!\n"); + return 0; + }; + if (!ts->ts_ops->spurious_fp_check) { + TPD_INFO("not support spurious_fp_check call back\n"); + return 0; + } + + do { + if (ts->spuri_fp_touch.lcd_trigger_fp_check) + wait_event_interruptible(waiter, ts->spuri_fp_touch.fp_trigger && ts->i2c_ready && ts->spuri_fp_touch.lcd_resume_ok); + else + wait_event_interruptible(waiter, ts->spuri_fp_touch.fp_trigger && ts->i2c_ready); + ts->spuri_fp_touch.fp_trigger = false; + ts->spuri_fp_touch.fp_touch_st = FINGER_PROTECT_NOTREADY; + + mutex_lock(&ts->mutex); + if (g_tp->spuri_fp_touch.lcd_trigger_fp_check && !g_tp->spuri_fp_touch.lcd_resume_ok) { + TPD_INFO("LCD is suspend, can not detect finger touch in incell panel\n"); + mutex_unlock(&ts->mutex); + continue; + } + + ts->spuri_fp_touch.fp_touch_st = ts->ts_ops->spurious_fp_check(ts->chip_data); + if (ts->view_area_touched) { + TPD_INFO("%s tp touch down,clear flag\n",__func__); + ts->view_area_touched = 0; + } + operate_mode_switch(ts); + mutex_unlock(&ts->mutex); + } while (!kthread_should_stop()); + return 0; +} + +//proc/touchpanel/register_info node use info: +//first choose register_add and lenght, example: echo 000e,1 > register_info +//second read: cat register_info +static ssize_t proc_register_info_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + int i = 0; + ssize_t num_read_chars = 0; + char page[256] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + if (ts->reg_info.reg_length < 1 || ts->reg_info.reg_length > 9) { + TPD_INFO("ts->reg_info.reg_length error!\n"); + return count; + } + ts->reg_info.reg_result = kzalloc(ts->reg_info.reg_length * (sizeof(uint16_t)), GFP_KERNEL); + if (!ts->reg_info.reg_result) { + TPD_INFO("ts->reg_info.reg_result kzalloc error\n"); + return count; + } + + if (ts->ts_ops->register_info_read) { + mutex_lock(&ts->mutex); + ts->ts_ops->register_info_read(ts->chip_data, ts->reg_info.reg_addr, ts->reg_info.reg_result, ts->reg_info.reg_length); + mutex_unlock(&ts->mutex); + for(i = 0; i < ts->reg_info.reg_length; i++) { + num_read_chars += sprintf(&(page[num_read_chars]), "reg_addr(0x%x) = 0x%x\n", ts->reg_info.reg_addr, ts->reg_info.reg_result[i]); + } + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + } + + kfree(ts->reg_info.reg_result); + return ret; +} + +//write info: echo 000e,1 > register_info +static ssize_t proc_register_info_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int addr = 0, length = 0; + char buf[16] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 7) { + TPD_INFO("%s count = %ld\n", __func__, count); + return count; + } + if (!ts) { + TPD_INFO("ts not exist!\n"); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + + sscanf(buf, "%x,%d", &addr, &length); + ts->reg_info.reg_addr = (uint16_t)addr; + ts->reg_info.reg_length = (uint16_t)length; + TPD_INFO("ts->reg_info.reg_addr = 0x%x, ts->reg_info.reg_lenght = %d\n", ts->reg_info.reg_addr, ts->reg_info.reg_length); + + return count; +} + + +static const struct file_operations proc_register_info_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_register_info_read, + .write = proc_register_info_write, +}; + +static ssize_t proc_incell_panel_info_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[32]; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + sprintf(page, "%d", ts->is_incell_panel); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations proc_incell_panel_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = proc_incell_panel_info_read, +}; + +/** + * init_touchpanel_proc - Using for create proc interface + * @ts: touchpanel_data struct using for common driver + * + * we need to set touchpanel_data struct as private_data to those file_inode + * Returning zero(success) or negative errno(failed) + */ +static ssize_t sec_update_fw_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t size) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + int val; + int ret = 0; + + if (!ts) + return size; + if (size > 2) + return size; + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM + if (ts->boot_mode == KERNEL_POWER_OFF_CHARGING_BOOT) +#else + if (ts->boot_mode == MSM_BOOT_MODE_CHARGE) +#endif + + { + TPD_INFO("boot mode is MSM_BOOT_MODE__CHARGE,not need update tp firmware\n"); + return size; + } + + ret = kstrtoint(buffer, 10, &val); + if (ret != 0) { + TPD_INFO("invalid content: '%s', length = %zd\n", buffer, size); + return ret; + } + ts->firmware_update_type = val; + if (!ts->force_update && ts->firmware_update_type != 2) + ts->force_update = !!val; + + schedule_work(&ts->fw_update_work); + + ret = wait_for_completion_killable_timeout(&ts->fw_complete, FW_UPDATE_COMPLETE_TIMEOUT); + if (ret < 0) { + TPD_INFO("kill signal interrupt\n"); + } + + TPD_INFO("fw update finished\n"); + return size; + +} +static ssize_t sec_update_fw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + return snprintf(buf, 2, "%d\n", ts->loading_fw); +} + +static DEVICE_ATTR(tp_fw_update, 0644, sec_update_fw_show, sec_update_fw_store); + +static int init_touchpanel_proc(struct touchpanel_data *ts) +{ + int ret = 0; + struct proc_dir_entry *prEntry_tp = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + TPD_INFO("%s entry\n", __func__); + + //proc files-step1:/proc/devinfo/tp (touchpanel device info) + if(ts->fw_update_app_support) { + register_devinfo("tp", &ts->panel_data.manufacture_info); + } + + if (device_create_file(&ts->s_client->dev, &dev_attr_tp_fw_update)) { + TPD_INFO("driver_create_file failt\n"); + ret = -ENOMEM; + } + + //proc files-step2:/proc/touchpanel + prEntry_tp = proc_mkdir("touchpanel", NULL); + if (prEntry_tp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create TP proc entry\n", __func__); + } + + //proc files-step2-1:/proc/touchpanel/tp_debug_log_level (log control interface) + prEntry_tmp = proc_create("tp_debug_log", 0644, prEntry_tp, &proc_debug_control_ops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files-step2-2:/proc/touchpanel/tp_fw_update (FW update interface) + prEntry_tmp = proc_create_data("tp_fw_update", 0644, prEntry_tp, &proc_fw_update_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files-step2-3:/proc/touchpanel/tp_fw_update (edge limit control interface) + if (ts->edge_limit_support) { + prEntry_tmp = proc_create_data("tp_limit_area", 0664, prEntry_tp, &proc_limit_area_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("tp_limit_enable", 0664, prEntry_tp, &proc_limit_control_ops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-4:/proc/touchpanel/double_tap_enable (black gesture related interface) + if (ts->black_gesture_support) { + prEntry_tmp = proc_create_data("gesture_enable", 0666, prEntry_tp, &proc_gesture_control_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("coordinate", 0444, prEntry_tp, &proc_coordinate_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-5:/proc/touchpanel/glove_mode_enable (Glove mode related interface) + if (ts->glove_mode_support) { + prEntry_tmp = proc_create_data("glove_mode_enable", 0666, prEntry_tp, &proc_glove_control_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-6:/proc/touchpanel/finger_protect_result + if (ts->spurious_fp_support) { + prEntry_tmp = proc_create_data("finger_protect_result", 0666, prEntry_tp, &proc_finger_protect_result, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("finger_protect_trigger", 0666, prEntry_tp, &proc_finger_protect_trigger, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc files-step2-7:/proc/touchpanel/register_info + prEntry_tmp = proc_create_data("register_info", 0664, prEntry_tp, &proc_register_info_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("ps_status", 0666, prEntry_tp, &proc_write_ps_status_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + + //proc files-step2-8:/proc/touchpanel/incell_panel + if (ts->is_incell_panel) { + prEntry_tmp = proc_create_data("incell_panel", 0664, prEntry_tp, &proc_incell_panel_fops, ts); + } + + if (ts->gesture_test_support) { + prEntry_tmp = proc_create_data("black_screen_test", 0666, prEntry_tp, &proc_black_screen_test_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + //proc file-step2-9:/proc/touchpanel/irq_depth + prEntry_tmp = proc_create_data("irq_depth", 0666, prEntry_tp, &proc_get_irq_depth_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc file-step2-10:/proc/touchpanel/vendor_id + prEntry_tmp = proc_create_data("vendor_id", 0444, prEntry_tp, &vendor_id_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + //proc files-step2-3:/proc/touchpanel/game_switch_enable (edge limit control interface) + if (ts->game_switch_support) { + prEntry_tmp = proc_create_data("game_switch_enable", 0666, prEntry_tp, &proc_game_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + prEntry_tmp = proc_create_data("gesture_switch", 0666, prEntry_tp, &proc_gesture_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("reject_point", 0666, prEntry_tp, &proc_reject_point_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("tpedge_limit_enable", 0666, prEntry_tp, &proc_limit_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ts->prEntry_tp = prEntry_tp; + + //create debug_info node + init_debug_info_proc(ts); + + return ret; +} + +//proc/touchpanel/debug_info/baseline +static int tp_baseline_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)(ts->debug_info_ops); + if (!debug_info_ops) { + TPD_INFO("debug_info_ops==NULL"); + return 0; + } + if (!debug_info_ops->baseline_read && !debug_info_ops->baseline_blackscreen_read) { + seq_printf(s, "Not support baseline proc node\n"); + return 0; + } + if ((ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) && (1 != ts->gesture_enable)) { + seq_printf(s, "Not in resume over or gesture state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + if (ts->is_suspended && ts->gesture_enable) { + if (debug_info_ops->baseline_blackscreen_read) { + debug_info_ops->baseline_blackscreen_read(s, ts->chip_data); + } + } else { + if (debug_info_ops->baseline_read) { + debug_info_ops->baseline_read(s, ts->chip_data); + } + } + + //step6: return to normal mode + ts->ts_ops->reset(ts->chip_data); + operate_mode_switch(ts); + + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; + +} + +static int data_baseline_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_baseline_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_baseline_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_baseline_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/delta +static int tp_delta_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->delta_read) { + seq_printf(s, "Not support delta proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->delta_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int data_delta_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_delta_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_delta_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_delta_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/self_delta +static int tp_self_delta_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->self_delta_read) { + seq_printf(s, "Not support self_delta proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->self_delta_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int data_self_delta_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_self_delta_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_self_delta_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_self_delta_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/self_raw +static int tp_self_raw_debug_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->self_raw_read) { + seq_printf(s, "Not support self_raw proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->self_raw_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int data_self_raw_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_self_raw_debug_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_self_raw_data_proc_fops = { + .owner = THIS_MODULE, + .open = data_self_raw_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/main_register +static int tp_main_register_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->main_register_read) { + seq_printf(s, "Not support main_register proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + seq_printf(s, "es_enable:%d\n", ts->es_enable); + seq_printf(s, "touch_count:%d\n", ts->touch_count); + debug_info_ops->main_register_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int main_register_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_main_register_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_main_register_proc_fops = { + .owner = THIS_MODULE, + .open = main_register_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/reserve +static int tp_reserve_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->reserve_read) { + seq_printf(s, "Not support main_register proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->reserve_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int reserve_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_reserve_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_reserve_proc_fops = { + .owner = THIS_MODULE, + .open = reserve_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/data_limit +static int tp_limit_data_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + if (!debug_info_ops) + return 0; + if (!debug_info_ops->limit_read) { + seq_printf(s, "Not support limit_data proc node\n"); + return 0; + } + debug_info_ops->limit_read(s, ts); + + return 0; +} + +static int limit_data_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_limit_data_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_limit_data_proc_fops = { + .owner = THIS_MODULE, + .open = limit_data_open, + .read = seq_read, + .release = single_release, +}; + +//proc/touchpanel/debug_info/abs_doze +static int tp_abs_doze_read_func(struct seq_file *s, void *v) +{ + struct touchpanel_data *ts = s->private; + struct debug_info_proc_operations *debug_info_ops; + + if (!ts) + return 0; + debug_info_ops = (struct debug_info_proc_operations *)ts->debug_info_ops; + + if (!debug_info_ops) + return 0; + if (!debug_info_ops->abs_doze_read) { + seq_printf(s, "Not support main_register proc node\n"); + return 0; + } + if (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE) { + seq_printf(s, "Not in resume over state\n"); + return 0; + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + mutex_lock(&ts->mutex); + debug_info_ops->abs_doze_read(s, ts->chip_data); + mutex_unlock(&ts->mutex); + + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } + return 0; +} + +static int abs_doze_open(struct inode *inode, struct file *file) +{ + return single_open(file, tp_abs_doze_read_func, PDE_DATA(inode)); +} + +static const struct file_operations tp_abs_doze_proc_fops = { + .owner = THIS_MODULE, + .open = abs_doze_open, + .read = seq_read, + .release = single_release, +}; + +//write function of /proc/touchpanel/earsense/palm_control +static ssize_t proc_earsense_palm_control_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, palm_enable :%d\n", __func__, value, ts->palm_enable); + if (value == ts->palm_enable) + return count; + + mutex_lock(&ts->mutex); + ts->palm_enable = value; + if (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_PALM_REJECTION, value); + } + mutex_unlock(&ts->mutex); + + return count; +} + +//read function of /proc/touchpanel/earsense/palm_control +static ssize_t proc_earsense_palm_control_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->palm_enable); + ret = sprintf(page, "%d\n", ts->palm_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/earsense/palm_control +static const struct file_operations tp_earsense_palm_control_fops = { + .write = proc_earsense_palm_control_write, + .read = proc_earsense_palm_control_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// write function of /proc/touchpanel/earsense/es_enable +static ssize_t proc_earsense_es_enable_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + bool state_changed = true; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, es_enable :%d\n", __func__, value, ts->es_enable); + if (value == ts->es_enable) + return count; + + mutex_lock(&ts->mutex); + if ((ts->es_enable != 1) && (value != 1)) + state_changed =false; + ts->es_enable = value; + if (!ts->es_enable) { + memset(ts->earsense_delta, 0, 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM); + } + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) && state_changed) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, ts->es_enable == 1); + } + mutex_unlock(&ts->mutex); + + return count; +} + +// read function of /proc/touchpanel/earsense/es_enable +static ssize_t proc_earsense_es_enable_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->es_enable); + ret = sprintf(page, "%d\n", ts->es_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/earsense/es_enable +static const struct file_operations tp_earsense_es_enable_fops = { + .write = proc_earsense_es_enable_write, + .read = proc_earsense_es_enable_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/es_touch_count +static ssize_t proc_earsense_touchcnt_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->touch_count); + mutex_lock(&ts->mutex); + ret = sprintf(page, "%d\n", ts->touch_count); + mutex_unlock(&ts->mutex); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/earsense/es_touch_count +static const struct file_operations tp_earsense_es_touchcnt_fops = { + .read = proc_earsense_touchcnt_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/rawdata +static ssize_t proc_earsense_rawdata_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int read_len = 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM; + + char *tmp_data = NULL; + if (!ts) + *ppos += 11; + if (*ppos > 10) + return 0; + if (count != read_len) { + TPD_INFO("%s, length:%d not match data_len:%d\n", __func__, (int)count, read_len); + return 0; + } + + TPD_DEBUG("%s is called\n", __func__); + mutex_lock(&ts->mutex); + if ((!ts->es_enable) || (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE)) { + *ppos += 11; + mutex_unlock(&ts->mutex); + return 0; + } + if (ts->delta_state == TYPE_DELTA_IDLE) { + tmp_data = kzalloc(read_len ,GFP_KERNEL); + ts->earsense_ops->rawdata_read(ts->chip_data, tmp_data, read_len); + mutex_unlock(&ts->mutex); + ret = copy_to_user(user_buf, tmp_data, read_len); + if (ret) + TPD_INFO("touch rawdata read fail\n"); + kfree(tmp_data); + *ppos += 11; + } else { + mutex_unlock(&ts->mutex); + msleep(3); + *ppos += 1; + } + + return read_len; +} + +// operation of /proc/touchpanel/earsense/rawdata +static const struct file_operations tp_earsense_rawdata_fops = { + .read = proc_earsense_rawdata_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/delta +static ssize_t proc_earsense_delta_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + int read_len = 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM; + + if (!ts) + return count; + if (*ppos > 0) + return 0; + if (count != read_len) { + TPD_INFO("%s, length:%d not match data_len:%d\n", __func__, (int)count, read_len); + return 0; + } + + TPD_DEBUG("%s is called\n", __func__); + if ((!ts->es_enable) || (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE)) { + return 0; + } + + mutex_lock(&ts->mutex_earsense); + ret = copy_to_user(user_buf, ts->earsense_delta, read_len); + mutex_unlock(&ts->mutex_earsense); + if (ret) + TPD_INFO("tp rawdata read fail\n"); + *ppos += read_len; + return read_len; +} + +// operation of /proc/touchpanel/earsense/delta +static const struct file_operations tp_earsense_delta_fops = { + .read = proc_earsense_delta_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/earsense/hover_selfdata +static ssize_t proc_earsense_selfdata_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + uint16_t data_len = 2*(ts->hw_res.TX_NUM + ts->hw_res.RX_NUM); + + char *tmp_data = NULL; + if (!ts) + *ppos += 11; + if (*ppos > 10) + return 0; + if (count != data_len) { + TPD_INFO("%s, length:%d not match data_len:%d\n", __func__, (int)count, data_len); + return 0; + } + + TPD_DEBUG("%s is called\n", __func__); + mutex_lock(&ts->mutex); + if ((!ts->es_enable) || (ts->suspend_state != TP_SPEEDUP_RESUME_COMPLETE)) { + *ppos += 11; + mutex_unlock(&ts->mutex); + return 0; + } + if (ts->delta_state == TYPE_DELTA_IDLE) { + tmp_data = kzalloc(data_len ,GFP_KERNEL); + ts->earsense_ops->self_data_read(ts->chip_data, tmp_data, data_len); + mutex_unlock(&ts->mutex); + ret = copy_to_user(user_buf, tmp_data, data_len); + if (ret) + TPD_INFO("tp self delta read fail\n"); + kfree(tmp_data); + *ppos += 11; + } else { + mutex_unlock(&ts->mutex); + msleep(3); + *ppos += 1; + } + + return data_len; +} + +// operation of /proc/touchpanel/earsense/hover_selfdata +static const struct file_operations tp_earsense_selfdata_fops = { + .read = proc_earsense_selfdata_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// write function of /proc/touchpanel/earsense/es_enable +static ssize_t proc_fd_enable_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, es_enable :%d\n", __func__, value, ts->fd_enable); + if (!value) { + input_event(ps_input_dev, EV_MSC, MSC_RAW, 2); + input_sync(ps_input_dev); + } + if (value == ts->fd_enable) + return count; + + mutex_lock(&ts->mutex); + ts->fd_enable = value; + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, ts->fd_enable == 1); + input_event(ps_input_dev, EV_MSC, MSC_RAW, 0); //when open fd report default key for sensor. + input_sync(ps_input_dev); + } + mutex_unlock(&ts->mutex); + + return count; +} + +// read function of /proc/touchpanel/fd_enable +static ssize_t proc_fd_enable_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->fd_enable); + ret = sprintf(page, "%d\n", ts->fd_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/fd_enable +static const struct file_operations tp_fd_enable_fops = { + .write = proc_fd_enable_write, + .read = proc_fd_enable_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +// read function of /proc/touchpanel/event_num +static ssize_t proc_event_num_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + const char *devname = NULL; + struct input_handle *handle; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + list_for_each_entry(handle, &ps_input_dev->h_list, d_node) { + if (strncmp(handle->name, "event", 5) == 0) { + devname = handle->name; + break; + } + } + + ret = simple_read_from_buffer(user_buf, count, ppos, devname, strlen(devname)); + return ret; +} + +// operation of /proc/touchpanel/event_num +static const struct file_operations tp_event_num_fops = { + .read = proc_event_num_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_fd_calibrate_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, fd_calibrate :%d\n", __func__, value, ts->fd_calibrate); + + mutex_lock(&ts->mutex); + ts->fd_calibrate = value; + if (ts->fd_enable) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_CALIBRATE, ts->fd_calibrate); + } + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_fd_calibrate_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->fd_calibrate); + ret = sprintf(page, "%d\n", ts->fd_calibrate); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations tp_fd_calibrate_fops = { + .write = proc_fd_calibrate_write, + .read = proc_fd_calibrate_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_refresh_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 2) + return count; + + TPD_DEBUG("%s value: %d, lcd_refresh_rate_switch :%d\n", __func__, value, ts->lcd_refresh_rate); + if (value == ts->lcd_refresh_rate) + return count; + + mutex_lock(&ts->mutex); + ts->lcd_refresh_rate = value; + if (!ts->is_suspended && (ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE)) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_REFRESH_SWITCH, ts->lcd_refresh_rate == 1); + } + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_refresh_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->lcd_refresh_rate); + ret = sprintf(page, "%d\n", ts->lcd_refresh_rate); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} +// operation of /proc/touchpanel/lcd_refresh_rate_switch +static const struct file_operations tp_lcd_refresh_switch_fops = { + .write = proc_refresh_switch_write, + .read = proc_refresh_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_touch_hold_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, touch_hold_enable :%d\n", __func__, value, ts->touch_hold_enable); + if (value == 2) {//fingerprint unlock success in FOD, close touchhold + ts->skip_reset_in_resume = true; + ts->skip_enable_touchhold = true; + return count; + } + + ts->touch_hold_enable = value; + ts->skip_enable_touchhold = false; + + if ((ts->is_suspended) && (!ts->gesture_enable)) { //suspend and close gesture cannot response touchhold + return count; + } + + mutex_lock(&ts->mutex); + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_HOLD, ts->touch_hold_enable); + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_touch_hold_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->touch_hold_enable); + ret = sprintf(page, "%d\n", ts->touch_hold_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/touch_hold +static const struct file_operations tp_touch_hold_switch_fops = { + .write = proc_touch_hold_switch_write, + .read = proc_touch_hold_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_touch_area_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 1) + return count; + + TPD_DEBUG("%s value: %d, touch_hold_enable :%d\n", __func__, value, ts->touch_area_switch); + if (value == ts->touch_area_switch) + return count; + + if ((ts->is_suspended) && (!ts->gesture_enable)) { //suspend and close gesture cannot response touchhold + return count; + } + + mutex_lock(&ts->mutex); + ts->touch_area_switch = value; + ts->ts_ops->mode_switch(ts->chip_data, MODE_TOUCH_AREA_SWITCH, ts->touch_area_switch == 1); + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_touch_area_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->touch_area_switch); + ret = sprintf(page, "%d\n", ts->touch_area_switch); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/touch_hold +static const struct file_operations tp_touch_area_switch_fops = { + .write = proc_touch_area_switch_write, + .read = proc_touch_area_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; +static ssize_t proc_fingerprint_int_test_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + if (value > 1) + return count; + + TPD_DEBUG("%s value: %d, fingerprint_int_test :%d\n", __func__, value, ts->fingerprint_int_test); + if (value == ts->fingerprint_int_test) + return count; + + mutex_lock(&ts->mutex); + ts->fingerprint_int_test = value; + ts->ts_ops->mode_switch(ts->chip_data, MODE_FINGERPRINT_TEST, ts->fingerprint_int_test == 1); + mutex_unlock(&ts->mutex); + + return count; +} + +static ssize_t proc_fingerprint_int_test_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->fingerprint_int_test); + ret = sprintf(page, "%d\n", ts->fingerprint_int_test); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +static const struct file_operations tp_fingerprint_int_test_fops = { + .write = proc_fingerprint_int_test_write, + .read = proc_fingerprint_int_test_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_charge_detect_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, charge detect enable:%d\n", __func__, value, ts->charge_detect); + ts->charge_detect = value; + mutex_lock(&ts->mutex); + if (ts->charge_detect_support && ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_CHARGE, ts->charge_detect); + } + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_charge_detect_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->charge_detect); + ret = sprintf(page, "%d\n", ts->charge_detect); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/charge_detect +static const struct file_operations tp_charge_detect_fops = { + .write = proc_charge_detect_write, + .read = proc_charge_detect_read, + .open = simple_open, + .owner = THIS_MODULE, +}; +static ssize_t proc_wireless_charge_detect_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, charge detect enable:%d\n", __func__, value, ts->wireless_charge_detect); + ts->wireless_charge_detect = value; + mutex_lock(&ts->mutex); + if (ts->wireless_charge_support && ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_WIRELESS_CHARGE, ts->wireless_charge_detect); + } + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_wireless_charge_detect_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->wireless_charge_detect); + ret = sprintf(page, "%d\n", ts->wireless_charge_detect); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/wireless_charge_detect +static const struct file_operations tp_wireless_charge_detect_fops = { + .write = proc_wireless_charge_detect_write, + .read = proc_wireless_charge_detect_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_audio_noise_switch_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int value = 0; + char buf[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (count > 2) + return count; + if (!ts) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_INFO("%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &value); + + TPD_DEBUG("%s value: %d, audio noise detect enable:%d\n", __func__, value, ts->audio_noise_detect); + ts->audio_noise_detect = value; + mutex_lock(&ts->mutex); + if (ts->audio_noise_support && ts->suspend_state == TP_SPEEDUP_RESUME_COMPLETE) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_AUDIO_NOISE, ts->audio_noise_detect); + } + mutex_unlock(&ts->mutex); + return count; +} + +static ssize_t proc_audio_noise_switch_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4] = {0}; + struct touchpanel_data *ts = PDE_DATA(file_inode(file)); + + if (!ts) + return count; + + TPD_DEBUG("%s value: %d\n", __func__, ts->audio_noise_detect); + ret = sprintf(page, "%d\n", ts->audio_noise_detect); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + + return ret; +} + +// operation of /proc/touchpanel/audio_noise_switch +static const struct file_operations tp_audio_noise_switch_fops = { + .write = proc_audio_noise_switch_write, + .read = proc_audio_noise_switch_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + + +//proc/touchpanel/debug_info/ +static int init_debug_info_proc(struct touchpanel_data *ts) +{ + int ret = 0; + struct proc_dir_entry *prEntry_debug_info = NULL; + struct proc_dir_entry *prEntry_earsense = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + TPD_INFO("%s entry\n", __func__); + + //proc files-step1:/proc/touchpanel/debug_info + prEntry_debug_info = proc_mkdir("debug_info", ts->prEntry_tp); + if (prEntry_debug_info == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create debug_info proc entry\n", __func__); + } + + // show limit data interface + prEntry_tmp = proc_create_data("data_limit", 0666, prEntry_debug_info, &tp_limit_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show baseline data interface + prEntry_tmp = proc_create_data("baseline", 0666, prEntry_debug_info, &tp_baseline_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show delta interface + prEntry_tmp = proc_create_data("delta", 0666, prEntry_debug_info, &tp_delta_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show self delta interface + prEntry_tmp = proc_create_data("self_delta", 0666, prEntry_debug_info, &tp_self_delta_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show self_raw interface + prEntry_tmp = proc_create_data("self_raw", 0666, prEntry_debug_info, &tp_self_raw_data_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show main_register interface + prEntry_tmp = proc_create_data("main_register", 0666, prEntry_debug_info, &tp_main_register_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show reserve interface + prEntry_tmp = proc_create_data("reserve", 0666, prEntry_debug_info, &tp_reserve_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // show abs_doze interface + prEntry_tmp = proc_create_data("abs_doze", 0666, prEntry_debug_info, &tp_abs_doze_proc_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + ts->prEntry_debug_tp = prEntry_debug_info; + + if (ts->ear_sense_support) { + //proc files-step1:/proc/touchpanel/earsense + prEntry_earsense = proc_mkdir("earsense", ts->prEntry_tp); + if (prEntry_earsense == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create debug_info proc entry\n", __func__); + } + // show baseline for earsense + prEntry_tmp = proc_create_data("rawdata", 0666, prEntry_earsense, &tp_earsense_rawdata_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // show delta for earsense + prEntry_tmp = proc_create_data("delta", 0666, prEntry_earsense, &tp_earsense_delta_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // show self delta for earsense + prEntry_tmp = proc_create_data("hover_selfdata", 0666, prEntry_earsense, &tp_earsense_selfdata_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // palm control for earsense + prEntry_tmp = proc_create_data("palm_control", 0666, prEntry_earsense, &tp_earsense_palm_control_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // es_enable for earsense + prEntry_tmp = proc_create_data("es_enable", 0666, prEntry_earsense, &tp_earsense_es_enable_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + // touch count for earsense + prEntry_tmp = proc_create_data("es_touch_count", 0666, prEntry_earsense, &tp_earsense_es_touchcnt_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + if (ts->face_detect_support) { + // proc for face detect + prEntry_tmp = proc_create_data("fd_enable", 0666, ts->prEntry_tp, &tp_fd_enable_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("event_num", 0666, ts->prEntry_tp, &tp_event_num_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + + prEntry_tmp = proc_create_data("fd_calibrate", 0666, ts->prEntry_tp, &tp_fd_calibrate_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + if (ts->lcd_refresh_rate_switch) { + // proc for lcd_refresh_rate_switch + prEntry_tmp = proc_create_data("lcd_refresh_rate_switch", 0666, ts->prEntry_tp, &tp_lcd_refresh_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + if (ts->touch_hold_support) { + // proc for touchhold switch + prEntry_tmp = proc_create_data("touch_hold", 0666, ts->prEntry_tp, &tp_touch_hold_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + prEntry_tmp = proc_create_data("touch_area_switch", 0666, ts->prEntry_tp, &tp_touch_area_switch_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + } + + // proc for lcd_refresh_rate_switch + prEntry_tmp = proc_create_data("fingerprint_int_test", 0666, ts->prEntry_tp, &tp_fingerprint_int_test_fops, ts); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + // proc for charge detect + prEntry_tmp = proc_create_data("charge_detect", 0666, ts->prEntry_tp, &tp_charge_detect_fops, ts); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entey, %d\n", __func__, __LINE__); + } + + //proc for wireless charge detect + prEntry_tmp = proc_create_data("wireless_charge_detect", 0666, ts->prEntry_tp, &tp_wireless_charge_detect_fops, ts); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entey, %d\n", __func__, __LINE__); + } + + //proc for audio noise switch + prEntry_tmp = proc_create_data("audio_noise_switch", 0666, ts->prEntry_tp, &tp_audio_noise_switch_fops, ts); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_INFO("%s: Couldn't create proc entey, %d\n", __func__, __LINE__); + } + + return ret; +} + +/** + * init_input_device - Using for register input device + * @ts: touchpanel_data struct using for common driver + * + * we should using this function setting input report capbility && register input device + * Returning zero(success) or negative errno(failed) + */ +static int init_input_device(struct touchpanel_data *ts) +{ + int ret = 0; + struct kobject *vk_properties_kobj; + + TPD_INFO("%s is called\n", __func__); + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + TPD_INFO("Failed to allocate input device\n"); + return ret; + } + + ts->kpd_input_dev = input_allocate_device(); + if (ts->kpd_input_dev == NULL) { + ret = -ENOMEM; + TPD_INFO("Failed to allocate key input device\n"); + return ret; + } + + if (ts->face_detect_support) { + ps_input_dev = input_allocate_device(); + if (ps_input_dev == NULL) { + ret = -ENOMEM; + TPD_INFO("Failed to allocate ps input device\n"); + return ret; + } + + ps_input_dev->name = TPD_DEVICE"_ps"; + set_bit(EV_MSC, ps_input_dev->evbit); + set_bit(MSC_RAW, ps_input_dev->mscbit); + } + + ts->input_dev->name = TPD_DEVICE; + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + set_bit(ABS_MT_TOUCH_MAJOR, ts->input_dev->absbit); + set_bit(ABS_MT_WIDTH_MAJOR, ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_X, ts->input_dev->absbit); + set_bit(ABS_MT_POSITION_Y, ts->input_dev->absbit); + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + set_bit(BTN_TOUCH, ts->input_dev->keybit); + if (ts->black_gesture_support) { + set_bit(KEY_F4, ts->input_dev->keybit); + } + + ts->kpd_input_dev->name = TPD_DEVICE"_kpd"; + set_bit(EV_KEY, ts->kpd_input_dev->evbit); + set_bit(EV_SYN, ts->kpd_input_dev->evbit); + + switch(ts->vk_type) { + case TYPE_PROPERTIES : + { + TPD_DEBUG("Type 1: using board_properties\n"); + vk_properties_kobj = kobject_create_and_add("board_properties", NULL); + if (vk_properties_kobj) + ret = sysfs_create_group(vk_properties_kobj, &properties_attr_group); + if (!vk_properties_kobj || ret) + TPD_DEBUG("failed to create board_properties\n"); + break; + } + case TYPE_AREA_SEPRATE: + { + TPD_DEBUG("Type 2:using same IC (button zone && touch zone are seprate)\n"); + if (CHK_BIT(ts->vk_bitmap, BIT_MENU)) + set_bit(KEY_MENU, ts->kpd_input_dev->keybit); + if (CHK_BIT(ts->vk_bitmap, BIT_HOME)) + set_bit(KEY_HOMEPAGE, ts->kpd_input_dev->keybit); + if (CHK_BIT(ts->vk_bitmap, BIT_BACK)) + set_bit(KEY_BACK, ts->kpd_input_dev->keybit); + break; + } + default : + break; + } + +#ifdef TYPE_B_PROTOCOL + input_mt_init_slots(ts->input_dev, ts->max_num, 0); +#endif + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->resolution_info.max_x, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->resolution_info.max_y, 0, 0); + input_set_drvdata(ts->input_dev, ts); + input_set_drvdata(ts->kpd_input_dev, ts); + + if (input_register_device(ts->input_dev)) { + TPD_INFO("%s: Failed to register input device\n", __func__); + input_free_device(ts->input_dev); + return -1; + } + + if (input_register_device(ts->kpd_input_dev)) { + TPD_INFO("%s: Failed to register key input device\n", __func__); + input_free_device(ts->kpd_input_dev); + return -1; + } + + if (ts->face_detect_support) { + if (input_register_device(ps_input_dev)) { + TPD_INFO("%s: Failed to register ps input device\n", __func__); + input_free_device(ps_input_dev); + return -1; + } + } + + return 0; +} + +/** + * init_parse_dts - parse dts, get resource defined in Dts + * @dev: i2c_client->dev using to get device tree + * @ts: touchpanel_data, using for common driver + * + * If there is any Resource needed by chip_data, we can add a call-back func in this function + * Do not care the result : Returning void type + */ +static void init_parse_dts(struct device *dev, struct touchpanel_data *ts) +{ + int rc; + struct device_node *np; + int temp_array[8]; + int tx_rx_num[2]; + int val = 0; + + np = dev->of_node; + + ts->register_is_16bit = of_property_read_bool(np, "register-is-16bit"); + ts->edge_limit_support = of_property_read_bool(np, "edge_limit_support"); + ts->glove_mode_support = of_property_read_bool(np, "glove_mode_support"); + ts->esd_handle_support = of_property_read_bool(np, "esd_handle_support"); + ts->spurious_fp_support = of_property_read_bool(np, "spurious_fingerprint_support"); + ts->charger_pump_support = of_property_read_bool(np, "charger_pump_support"); + ts->black_gesture_support = of_property_read_bool(np, "black_gesture_support"); + ts->gesture_test_support = of_property_read_bool(np, "black_gesture_test_support"); + ts->fw_update_app_support = of_property_read_bool(np, "fw_update_app_support"); + ts->game_switch_support = of_property_read_bool(np, "game_switch_support"); + ts->ear_sense_support = of_property_read_bool(np, "ear_sense_support"); + ts->smart_gesture_support = of_property_read_bool(np, "smart_gesture_support"); + ts->is_noflash_ic = of_property_read_bool(np, "noflash_support"); + ts->face_detect_support = of_property_read_bool(np, "face_detect_support"); + ts->lcd_refresh_rate_switch = of_property_read_bool(np, "lcd_refresh_rate_switch"); + ts->touch_hold_support = of_property_read_bool(np, "touch_hold_support"); + ts->project_info = of_property_read_bool(np, "project_info"); + ts->charge_detect_support = of_property_read_bool(np, "charge_detect_support"); + ts->wireless_charge_support = of_property_read_bool(np, "wireless_charge_support"); + ts->module_id_support = of_property_read_bool(np, "module_id_support"); + ts->audio_noise_support = of_property_read_bool(np, "audio_noise_support"); + ts->fw_edge_limit_support = of_property_read_bool(np, "fw_edge_limit_support"); + ts->spuri_fp_touch.lcd_trigger_fp_check = of_property_read_bool(np, "lcd_trigger_fp_check"); + ts->spuri_fp_touch.lcd_resume_ok = true; + + rc = of_property_read_string(np, "project-name", &ts->panel_data.project_name); + if (rc < 0) { + TPD_INFO("failed to get project name, firmware/limit name will be invalid\n"); + } + rc = of_property_read_string(np, "chip-name", &ts->panel_data.chip_name); + if (rc < 0) { + TPD_INFO("failed to get chip name, firmware/limit name will be invalid\n"); + } + rc = of_property_read_u32(np, "module_id" , &ts->panel_data.tp_type); + if(rc < 0) { + TPD_INFO("module id is not specified\n"); + ts->panel_data.tp_type = 0; + } + + rc = of_property_read_u32(np, "vdd_2v8_volt", &ts->hw_res.vdd_volt); + if (rc < 0) { + ts->hw_res.vdd_volt = 0; + TPD_INFO("vdd_2v8_volt not defined\n"); + } + + // irq gpio + ts->hw_res.irq_gpio = of_get_named_gpio_flags(np, "touchpanel,irq-gpio", 0, &(ts->irq_flags)); + if (gpio_is_valid(ts->hw_res.irq_gpio)) { + rc= gpio_request(ts->hw_res.irq_gpio, "tp_irq_gpio"); + if (rc) { + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.irq_gpio); + } + } else { + TPD_INFO("irq-gpio not specified in dts\n"); + } + + ts->irq = gpio_to_irq(ts->hw_res.irq_gpio); + ts->s_client->irq = ts->irq; + // reset gpio + ts->hw_res.reset_gpio = of_get_named_gpio(np, "touchpanel,reset-gpio", 0); + if (gpio_is_valid(ts->hw_res.reset_gpio)) { + rc = gpio_request(ts->hw_res.reset_gpio, "tp-reset-gpio"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.reset_gpio); + } else { + TPD_INFO("ts->reset-gpio not specified\n"); + } + TPD_INFO("ts->reset-gpio reset begain\n"); + gpio_direction_output(ts->hw_res.reset_gpio, 0); + msleep(5); + gpio_direction_output(ts->hw_res.reset_gpio, 1); + msleep(5); + TPD_INFO("ts->reset-gpio reset end\n"); + +//cs gpio + ts->hw_res.cs_gpio = of_get_named_gpio(np, "touchpanel,cs-gpio", 0); + if (gpio_is_valid(ts->hw_res.cs_gpio)) { + rc = gpio_request(ts->hw_res.cs_gpio, "tp-cs-gpio"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.cs_gpio); + } else { + TPD_INFO("ts->cs-gpio not specified\n"); + } + + TPD_INFO("%s : irq_gpio = %d, irq_flags = 0x%x ts_irq = %d, reset_gpio = %d, cs_gpio = %d\n", + __func__, ts->hw_res.irq_gpio, ts->irq_flags, ts->irq, ts->hw_res.reset_gpio, ts->hw_res.cs_gpio); + + + // tp type gpio + ts->hw_res.id1_gpio = of_get_named_gpio(np, "id1-gpio", 0); + if (gpio_is_valid(ts->hw_res.id1_gpio)) { + rc = gpio_request(ts->hw_res.id1_gpio, "TP_ID1"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.id1_gpio); + } else { + TPD_INFO("id1_gpio not specified\n"); + } + + ts->hw_res.id2_gpio = of_get_named_gpio(np, "id2-gpio", 0); + if (gpio_is_valid(ts->hw_res.id2_gpio)) { + rc = gpio_request(ts->hw_res.id2_gpio, "TP_ID2"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.id2_gpio); + } else { + TPD_INFO("id2_gpio not specified\n"); + } + + ts->hw_res.id3_gpio = of_get_named_gpio(np, "id3-gpio", 0); + if (gpio_is_valid(ts->hw_res.id3_gpio)) { + rc = gpio_request(ts->hw_res.id3_gpio, "TP_ID3"); + if (rc) + TPD_INFO("unable to request gpio [%d]\n", ts->hw_res.id3_gpio); + } else { + TPD_INFO("id3_gpio not specified\n"); + } + + ts->hw_res.pinctrl= devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(ts->hw_res.pinctrl)) { + TPD_INFO("Getting pinctrl handle failed"); + } else { + ts->hw_res.pin_set_high = pinctrl_lookup_state(ts->hw_res.pinctrl, "pin_set_high"); + if (IS_ERR_OR_NULL(ts->hw_res.pin_set_high)) { + TPD_INFO("Failed to get the high state pinctrl handle \n"); + } + ts->hw_res.pin_set_low = pinctrl_lookup_state(ts->hw_res.pinctrl, "pin_set_low"); + if (IS_ERR_OR_NULL(ts->hw_res.pin_set_low)) { + TPD_INFO(" Failed to get the low state pinctrl handle\n"); + } + } + ts->hw_res.enable2v8_gpio = of_get_named_gpio(np, "enable2v8_gpio", 0); + if (ts->hw_res.enable2v8_gpio < 0) { + TPD_INFO("ts->hw_res.enable2v8_gpio not specified\n"); + } else { + if (gpio_is_valid(ts->hw_res.enable2v8_gpio)) { + rc = gpio_request(ts->hw_res.enable2v8_gpio, "vdd2v8-gpio"); + if (rc) { + TPD_INFO("unable to request gpio [%d] %d\n", ts->hw_res.enable2v8_gpio, rc); + } + } + } + + ts->hw_res.enable1v8_gpio = of_get_named_gpio(np, "enable1v8_gpio", 0); + if (ts->hw_res.enable1v8_gpio < 0) { + TPD_INFO("ts->hw_res.enable1v8_gpio not specified\n"); + } else { + if (gpio_is_valid(ts->hw_res.enable1v8_gpio)) { + rc = gpio_request(ts->hw_res.enable1v8_gpio, "vcc1v8-gpio"); + if (rc) { + TPD_INFO("unable to request gpio [%d], %d\n", ts->hw_res.enable1v8_gpio, rc); + } + } + } + + // interrupt mode + ts->int_mode = BANNABLE; + rc = of_property_read_u32(np, "touchpanel,int-mode", &val); + if (rc) { + TPD_INFO("int-mode not specified\n"); + } else { + if (val < INTERRUPT_MODE_MAX) { + ts->int_mode = val; + } + } + + // resolution info + rc = of_property_read_u32(np, "touchpanel,max-num-support", &ts->max_num); + if (rc) { + TPD_INFO("ts->max_num not specified\n"); + ts->max_num = 10; + } + + rc = of_property_read_u32_array(np, "touchpanel,tx-rx-num", tx_rx_num, 2); + if (rc) { + TPD_INFO("tx-rx-num not set\n"); + ts->hw_res.TX_NUM = 0; + ts->hw_res.RX_NUM = 0; + } else { + ts->hw_res.TX_NUM = tx_rx_num[0]; + ts->hw_res.RX_NUM = tx_rx_num[1]; + } + TPD_INFO("TX_NUM = %d, RX_NUM = %d \n", ts->hw_res.TX_NUM, ts->hw_res.RX_NUM); + + rc = of_property_read_u32_array(np, "earsense,tx-rx-num", tx_rx_num, 2); + if (rc) { + TPD_INFO("tx-rx-num not set\n"); + ts->hw_res.EARSENSE_TX_NUM = ts->hw_res.TX_NUM; + ts->hw_res.EARSENSE_RX_NUM = ts->hw_res.RX_NUM / 2; + } else { + ts->hw_res.EARSENSE_TX_NUM = tx_rx_num[0]; + ts->hw_res.EARSENSE_RX_NUM = tx_rx_num[1]; + } + TPD_INFO("EARSENSE_TX_NUM = %d, EARSENSE_RX_NUM = %d \n", ts->hw_res.EARSENSE_TX_NUM, ts->hw_res.EARSENSE_RX_NUM); + + rc = of_property_read_u32_array(np, "touchpanel,display-coords", temp_array, 2); + if (rc) { + TPD_INFO("Lcd size not set\n"); + ts->resolution_info.LCD_WIDTH = 0; + ts->resolution_info.LCD_HEIGHT = 0; + }else{ + ts->resolution_info.LCD_WIDTH = temp_array[0]; + ts->resolution_info.LCD_HEIGHT = temp_array[1]; + } + rc = of_property_read_u32_array(np, "touchpanel,panel-coords", temp_array, 2); + if (rc) { + ts->resolution_info.max_x = 0; + ts->resolution_info.max_y = 0; + }else{ + ts->resolution_info.max_x = temp_array[0]; + ts->resolution_info.max_y = temp_array[1]; + } + + rc = of_property_read_u32_array(np, "touchpanel,touchmajor-limit", temp_array, 2); + if (rc) { + ts->touch_major_limit.width_range = 0; + ts->touch_major_limit.height_range = 0; + }else{ + ts->touch_major_limit.width_range = temp_array[0]; + ts->touch_major_limit.height_range = temp_array[1]; + } + TPD_INFO("LCD_WIDTH = %d, LCD_HEIGHT = %d, max_x = %d, max_y = %d, limit_witdh = %d, limit_height = %d\n", + ts->resolution_info.LCD_WIDTH, ts->resolution_info.LCD_HEIGHT, ts->resolution_info.max_x, ts->resolution_info.max_y,\ + ts->touch_major_limit.width_range, ts->touch_major_limit.height_range); + + // virturl key Related + rc = of_property_read_u32_array(np, "touchpanel,button-type", temp_array, 2); + if (rc < 0) { + TPD_INFO("error:button-type should be setting in dts!"); + } else { + ts->vk_type = temp_array[0]; + ts->vk_bitmap = temp_array[1] & 0xFF; + if (ts->vk_type == TYPE_PROPERTIES) { + rc = of_property_read_u32_array(np, "touchpanel,button-map", temp_array, 8); + if (rc) { + TPD_INFO("button-map not set\n"); + }else{ + ts->button_map.coord_menu.x = temp_array[0]; + ts->button_map.coord_menu.y = temp_array[1]; + ts->button_map.coord_home.x = temp_array[2]; + ts->button_map.coord_home.y = temp_array[3]; + ts->button_map.coord_back.x = temp_array[4]; + ts->button_map.coord_back.y = temp_array[5]; + ts->button_map.width_x = temp_array[6]; + ts->button_map.height_y = temp_array[7]; + } + } + } + + //touchkey take tx num and rx num + rc = of_property_read_u32_array(np, "touchpanel.button-TRx", temp_array, 2); + if(rc < 0) { + TPD_INFO("error:button-TRx should be setting in dts!\n"); + ts->hw_res.key_TX = 0; + ts->hw_res.key_RX = 0; + } else { + ts->hw_res.key_TX = temp_array[0]; + ts->hw_res.key_RX = temp_array[1]; + TPD_INFO("key_tx is %d, key_rx is %d\n", ts->hw_res.key_TX, ts->hw_res.key_RX); + } + + //set incell panel parameter, for of_property_read_bool return 1 when success and return 0 when item is not exist + rc = ts->is_incell_panel = of_property_read_bool(np, "incell_screen"); + if(rc > 0) { + TPD_INFO("panel is incell!\n"); + ts->is_incell_panel = 1; + } else { + TPD_INFO("panel is oncell!\n"); + ts->is_incell_panel = 0; + } + + // We can Add callback fuction here if necessary seprate some dts config for chip_data +} + +int init_power_control(struct touchpanel_data *ts) +{ + int ret = 0; + + // 1.8v + ts->hw_res.vcc_1v8 = regulator_get(ts->dev, "vcc_1v8"); + if (IS_ERR_OR_NULL(ts->hw_res.vcc_1v8)) { + TPD_INFO("Regulator get failed vcc_1v8, ret = %d\n", ret); + } else { + if (regulator_count_voltages(ts->hw_res.vcc_1v8) > 0) { + ret = regulator_set_voltage(ts->hw_res.vcc_1v8, 1800000, 1800000); + if (ret) { + dev_err(ts->dev, "Regulator set_vtg failed vcc_i2c rc = %d\n", ret); + goto regulator_vcc_1v8_put; + } + + ret = regulator_set_load(ts->hw_res.vcc_1v8, 200000); + if (ret < 0) { + dev_err(ts->dev, "Failed to set vcc_1v8 mode(rc:%d)\n", ret); + goto regulator_vcc_1v8_put; + } + } + } + // vdd 2.8v + ts->hw_res.vdd_2v8 = regulator_get(ts->dev, "vdd_2v8"); + if (IS_ERR_OR_NULL(ts->hw_res.vdd_2v8)) { + TPD_INFO("Regulator vdd2v8 get failed, ret = %d\n", ret); + } else { + if (regulator_count_voltages(ts->hw_res.vdd_2v8) > 0) { + TPD_INFO("set avdd voltage to %d uV\n", ts->hw_res.vdd_volt); + if (ts->hw_res.vdd_volt) { + ret = regulator_set_voltage(ts->hw_res.vdd_2v8, ts->hw_res.vdd_volt, ts->hw_res.vdd_volt); + } else { + ret = regulator_set_voltage(ts->hw_res.vdd_2v8, 3100000, 3100000); + } + if (ret) { + dev_err(ts->dev, "Regulator set_vtg failed vdd rc = %d\n", ret); + goto regulator_vdd_2v8_put; + } + + ret = regulator_set_load(ts->hw_res.vdd_2v8, 200000); + if (ret < 0) { + dev_err(ts->dev, "Failed to set vdd_2v8 mode(rc:%d)\n", ret); + goto regulator_vdd_2v8_put; + } + } + } + + return 0; + +regulator_vdd_2v8_put: + regulator_put(ts->hw_res.vdd_2v8); + ts->hw_res.vdd_2v8 = NULL; +regulator_vcc_1v8_put: + if (!IS_ERR_OR_NULL(ts->hw_res.vcc_1v8)) { + regulator_put(ts->hw_res.vcc_1v8); + ts->hw_res.vcc_1v8 = NULL; + } + + return ret; +} + +int tp_powercontrol_1v8(struct hw_resource *hw_res, bool on) +{ + int ret = 0; + + if (on) {// 1v8 power on + if (!IS_ERR_OR_NULL(hw_res->vcc_1v8)) { + TPD_INFO("Enable the Regulator1v8.\n"); + ret = regulator_enable(hw_res->vcc_1v8); + if (ret) { + TPD_INFO("Regulator vcc_i2c enable failed ret = %d\n", ret); + return ret; + } + } + + if (hw_res->enable1v8_gpio > 0) { + TPD_INFO("Enable the 1v8_gpio\n"); + ret = gpio_direction_output(hw_res->enable1v8_gpio, 1); + if (ret) { + TPD_INFO("enable the enable1v8_gpio failed.\n"); + return ret; + } + } + } else {// 1v8 power off + if (!IS_ERR_OR_NULL(hw_res->vcc_1v8)) { + ret = regulator_disable(hw_res->vcc_1v8); + if (ret) { + TPD_INFO("Regulator vcc_i2c enable failed rc = %d\n", ret); + return ret; + } + } + + if (hw_res->enable1v8_gpio > 0) { + TPD_INFO("disable the 1v8_gpio\n"); + ret = gpio_direction_output(hw_res->enable1v8_gpio, 0); + if (ret) { + TPD_INFO("disable the enable1v8_gpio failed.\n"); + return ret; + } + } + } + + return 0; +} + +int tp_powercontrol_2v8(struct hw_resource *hw_res, bool on) +{ + int ret = 0; + + if (on) {// 2v8 power on + if (!IS_ERR_OR_NULL(hw_res->vdd_2v8)) { + TPD_INFO("Enable the Regulator2v8.\n"); + ret = regulator_enable(hw_res->vdd_2v8); + if (ret) { + TPD_INFO("Regulator vdd enable failed ret = %d\n", ret); + return ret; + } + } + if (hw_res->enable2v8_gpio > 0) { + TPD_INFO("Enable the 2v8_gpio, hw_res->enable2v8_gpio is %d\n", hw_res->enable2v8_gpio); + ret = gpio_direction_output(hw_res->enable2v8_gpio, 1); + if (ret) { + TPD_INFO("enable the enable2v8_gpio failed.\n"); + return ret; + } + } + } else {// 2v8 power off + if (!IS_ERR_OR_NULL(hw_res->vdd_2v8)) { + TPD_INFO("disable the vdd_2v8\n"); + ret = regulator_disable(hw_res->vdd_2v8); + if (ret) { + TPD_INFO("Regulator vdd disable failed rc = %d\n", ret); + return ret; + } + } + if (hw_res->enable2v8_gpio > 0) { + TPD_INFO("disable the 2v8_gpio\n"); + ret = gpio_direction_output(hw_res->enable2v8_gpio, 0); + if (ret) { + TPD_INFO("disable the enable2v8_gpio failed.\n"); + return ret; + } + } + } + return ret; +} + + +static void esd_handle_func(struct work_struct *work) +{ + int ret = 0; + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, + esd_info.esd_check_work.work); + + if (ts->loading_fw) { + TPD_INFO("FW is updating, stop esd handle!\n"); + return; + } + + mutex_lock(&ts->esd_info.esd_lock); + if (!ts->esd_info.esd_running_flag) { + TPD_INFO("Esd protector has stopped!\n"); + goto ESD_END; + } + + if (ts->is_suspended == 1) { + TPD_INFO("Touch panel has suspended!\n"); + goto ESD_END; + } + + if (!ts->ts_ops->esd_handle) { + TPD_INFO("not support ts_ops->esd_handle callback\n"); + goto ESD_END; + } + + ret = ts->ts_ops->esd_handle(ts->chip_data); + if (ret == -1) { //-1 means esd hanppened: handled in IC part, recovery the state here + operate_mode_switch(ts); + } + + if (ts->esd_info.esd_running_flag) + queue_delayed_work(ts->esd_info.esd_workqueue, &ts->esd_info.esd_check_work, ts->esd_info.esd_work_time); + else + TPD_INFO("Esd protector suspended!"); + +ESD_END: + mutex_unlock(&ts->esd_info.esd_lock); + return; +} + +/** + * esd_handle_switch - open or close esd thread + * @esd_info: touchpanel_data, using for common driver resource + * @on: bool variable using for indicating open or close esd check function. + * true:open; + * false:close; + */ +void esd_handle_switch(struct esd_information *esd_info, bool on) +{ + mutex_lock(&esd_info->esd_lock); + + if (on) { + if (!esd_info->esd_running_flag) { + esd_info->esd_running_flag = 1; + + TPD_INFO("Esd protector started, cycle: %d s\n", esd_info->esd_work_time/HZ); + queue_delayed_work(esd_info->esd_workqueue, &esd_info->esd_check_work, esd_info->esd_work_time); + } + } else { + if (esd_info->esd_running_flag) { + esd_info->esd_running_flag = 0; + + TPD_INFO("Esd protector stoped!\n"); + cancel_delayed_work(&esd_info->esd_check_work); + } + } + + mutex_unlock(&esd_info->esd_lock); +} + +int tp_register_irq_func(struct touchpanel_data *ts) +{ + int ret = 0; + +#ifdef TPD_USE_EINT + if (gpio_is_valid(ts->hw_res.irq_gpio)) { + TPD_DEBUG("%s, irq_gpio is %d, ts->irq is %d\n", __func__, ts->hw_res.irq_gpio, ts->irq); + ret = request_threaded_irq(ts->irq, NULL, + tp_irq_thread_fn, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + TPD_DEVICE, ts); + if (ret < 0) { + TPD_INFO("%s request_threaded_irq ret is %d\n", __func__, ret); + }else{ + TPD_INFO("%s request_threaded_irq ret is %d success\n", __func__, ret); + } + } else { + TPD_INFO("%s:no valid irq\n", __func__); + } +#else + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = touchpanel_timer_func; + hrtimer_start(&ts->timer, ktime_set(3, 0), HRTIMER_MODE_REL); +#endif + + return ret; +} + +//work schdule for reading&update delta +static void touch_read_delta(struct work_struct *work) +{ + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, read_delta_work); + + mutex_lock(&ts->mutex_earsense); + mutex_lock(&ts->mutex); + ts->earsense_ops->delta_read(ts->chip_data, ts->earsense_delta, 2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM); + mutex_unlock(&ts->mutex); + mutex_unlock(&ts->mutex_earsense); + ts->delta_state=TYPE_DELTA_IDLE; +} + +void tp_util_get_vendor(struct touchpanel_data *ts, struct panel_info *panel_data) +{ + + panel_data->test_limit_name = kzalloc(MAX_LIMIT_DATA_LENGTH, GFP_KERNEL); + if (panel_data->test_limit_name == NULL) { + TPD_INFO("panel_data.test_limit_name kzalloc error\n"); + } + + if (ts->module_id_support) { + TPD_INFO("enter %s\n", __func__); + if (lcd_id) { + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/FW_%s_%s.img", panel_data->project_name, panel_data->chip_name); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/LIMIT_%s_%s.img", panel_data->project_name, panel_data->chip_name); + } + } else { + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "tp/FW_%s_%s.img", panel_data->project_name, panel_data->chip_name); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "tp/LIMIT_%s_%s.img", panel_data->project_name, panel_data->chip_name); + } + } + } else { + snprintf(panel_data->fw_name, MAX_FW_NAME_LENGTH, + "%s_%s.bin", "Himax", "firmware"); + + if (panel_data->test_limit_name) { + snprintf(panel_data->test_limit_name, MAX_LIMIT_DATA_LENGTH, + "%s_%s.csv", "hx", "criteria"); + } + } + TPD_INFO("end %s\n", __func__); + //sprintf(panel_data->manufacture_info.version, "0x%x", panel_data->TP_FW); + //sprintf(panel_data->manufacture_info.manufacture, panel_data->chip_name); + + //push_component_info(TOUCH_KEY, panel_data->manufacture_info.version, + //panel_data->manufacture_info.manufacture); + //push_component_info(TP, panel_data->manufacture_info.version, panel_data->manufacture_info.manufacture); + + //TPD_INFO("%s fw:%s limit:%s\n", __func__, panel_data->fw_name, panel_data->test_limit_name); +} + +/* +void sec_ts_pinctrl_configure(struct hw_resource *hw_res, bool enable) +{ + int ret; + + if (enable) { + if (hw_res->pinctrl) { + ret = pinctrl_select_state(hw_res->pinctrl, hw_res->pin_set_high); + if (ret) + TPD_INFO("%s could not set active pinstate", __func__); + } + } else { + if (hw_res->pinctrl) { + ret = pinctrl_select_state(hw_res->pinctrl, hw_res->pin_set_low); + if (ret) + TPD_INFO("%s could not set suspend pinstate", __func__); + } + } +} + +*/ +/** + * register_common_touch_device - parse dts, get resource defined in Dts + * @pdata: touchpanel_data, using for common driver + * + * entrance of common touch Driver + * Returning zero(sucess) or negative errno(failed) + */ + /* +static int get_lcd_name(const char *str) +{ + TPD_INFO("enter %s, cld_name is %s\n", __func__, str); + if (!strcmp(str, "qcom,mdsss_dsi_samsung_oneplus_dsc_cmd")) { //using 18821 TP + lcd_id = 0; + } else if (!strcmp(str, "qcom,mdss_dsi_samsung_ana6706_dsc_cmd")) { //using 19811 TP + lcd_id = 1; + } else if (!strcmp(str, "qcom,mdss_dsi_samsung_ana6705_dsc_cmd")) { //using 19821 TP + lcd_id = 2; + } + lcd_id = 2; //should revert by srinivs after display info + + TPD_INFO("lcd_id is hardcode to 2 by default by srinivas %d\n", lcd_id); + TPD_INFO("lcd_id is %d\n", lcd_id); + + return 0; +} +*/ + +int register_common_touch_device(struct touchpanel_data *pdata) +{ + struct touchpanel_data *ts = pdata; + struct invoke_method *invoke; + int ret = -1; + TPD_INFO("%s is called\n", __func__); + + //step : FTM process + ts->boot_mode = get_boot_mode(); + TPD_INFO("boot_mode is %d\n", ts->boot_mode); + if (ts->boot_mode == MSM_BOOT_MODE_RECOVERY) + himax_boot_mode = 1; + TPD_INFO("boot_mode is %d\n", ts->boot_mode); + //step1 : dts parse + init_parse_dts(ts->dev, ts); + + //step2 : IIC interfaces init + init_touch_interfaces(ts->dev, ts->register_is_16bit); + + //step3 : mutex init + mutex_init(&ts->mutex); + init_completion(&ts->pm_complete); + init_completion(&ts->fw_complete); + init_completion(&ts->resume_complete); + + ts->async_workqueue = create_singlethread_workqueue("tp_async"); + if (!ts->async_workqueue) { + ret = -ENOMEM; + return -1; + } + INIT_WORK(&ts->async_work, tp_async_work_lock); + + if (ts->has_callback) { + invoke = (struct invoke_method *)pdata->chip_data; + invoke->invoke_common = tp_work_common_callback; + invoke->async_work = tp_async_work_callback; + } + + //gpio_direction_output(ts->hw_res.reset_gpio, 0); + + //sec_ts_pinctrl_configure(&ts->hw_res, true); + //step4 : Power init && setting + + preconfig_power_control(ts); + ret = init_power_control(ts); + if (ret) { + TPD_INFO("%s: tp power init failed.\n", __func__); + return -1; + } + ret = reconfig_power_control(ts); + if (ret) { + TPD_INFO("%s: reconfig power failed.\n", __func__); + return -1; + } + if (!ts->ts_ops->power_control) { + ret = -EINVAL; + TPD_INFO("tp power_control NULL!\n"); + goto power_control_failed; + } + ret = ts->ts_ops->power_control(ts->chip_data, true); + if (ret) { + TPD_INFO("%s: tp power init failed.\n", __func__); + goto power_control_failed; + } + //step5 : I2C function check + if (!ts->is_noflash_ic) { + if (!i2c_check_functionality(ts->client->adapter, I2C_FUNC_I2C)) { + TPD_INFO("%s: need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err_check_functionality_failed; + } + } + + //step6 : touch input dev init + ret = init_input_device(ts); + if (ret < 0) { + ret = -EINVAL; + TPD_INFO("tp_input_init failed!\n"); + goto err_check_functionality_failed; + } + + if (ts->int_mode == UNBANNABLE) { + ret = tp_register_irq_func(ts); + if (ret < 0) { + goto free_touch_panel_input; + } + } + + //step8 : Alloc fw_name/devinfo memory space + ts->panel_data.fw_name = kzalloc(MAX_FW_NAME_LENGTH, GFP_KERNEL); + if (ts->panel_data.fw_name == NULL) { + ret = -ENOMEM; + TPD_INFO("panel_data.fw_name kzalloc error\n"); + goto free_touch_panel_input; + } + + ts->panel_data.manufacture_info.version = kzalloc(MAX_DEVICE_VERSION_LENGTH, GFP_KERNEL); + if (ts->panel_data.manufacture_info.version == NULL) { + ret = -ENOMEM; + TPD_INFO("manufacture_info.version kzalloc error\n"); + goto manu_version_alloc_err; + } + + ts->panel_data.manufacture_info.manufacture = kzalloc(MAX_DEVICE_MANU_LENGTH, GFP_KERNEL); + if (ts->panel_data.manufacture_info.manufacture == NULL) { + ret = -ENOMEM; + TPD_INFO("panel_data.fw_name kzalloc error\n"); + goto manu_info_alloc_err; + } + + //step8 : touchpanel vendor + tp_util_get_vendor(ts, &ts->panel_data); + if (ts->ts_ops->get_vendor) { + ts->ts_ops->get_vendor(ts->chip_data, &ts->panel_data); + } + + //step10:get chip info + if (!ts->ts_ops->get_chip_info) { + ret = -EINVAL; + TPD_INFO("tp get_chip_info NULL!\n"); + goto err_check_functionality_failed; + } + ret = ts->ts_ops->get_chip_info(ts->chip_data); + if (ret < 0) { + ret = -EINVAL; + TPD_INFO("tp get_chip_info failed!\n"); + goto err_check_functionality_failed; + } + + //step11 : touchpanel Fw check + if(!ts->is_noflash_ic) { //noflash don't have firmware before fw update + if (!ts->ts_ops->fw_check) { + ret = -EINVAL; + TPD_INFO("tp fw_check NULL!\n"); + goto manu_info_alloc_err; + } + ret = ts->ts_ops->fw_check(ts->chip_data, &ts->resolution_info, &ts->panel_data); + if (ret == FW_ABNORMAL) { + ts->force_update = 1; + TPD_INFO("This FW need to be updated!\n"); + } else if (ret == -2) { + ret = -EINVAL; + TPD_INFO("fw_check fail\n"); + goto err_check_functionality_failed; + } else { + ts->force_update = 0; + } + } + + //step12 : enable touch ic irq output ability + if (!ts->ts_ops->mode_switch) { + ret = -EINVAL; + TPD_INFO("tp mode_switch NULL!\n"); + goto manu_info_alloc_err; + } + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_NORMAL, true); + if (ret < 0) { + ret = -EINVAL; + TPD_INFO("%s:modem switch failed!\n", __func__); + goto manu_info_alloc_err; + } + + //wakeup_source_init(&ts->source, "tp_syna"); + ts->source = wakeup_source_register(ts->dev, "tp_syna"); + //step13 : irq request setting + if (ts->int_mode == BANNABLE) { + ret = tp_register_irq_func(ts); + if (ret < 0) { + goto manu_info_alloc_err; + } + } + //step14 : suspend && resume fuction register + touchpanel_update_fw_notifier_init(ts); + + //#if defined(CONFIG_DRM_MSM) + ts->fb_notif.notifier_call = tfb_notifier_callback; + //ret = msm_drm_register_client(&ts->fb_notif); + if (tp_active_panel) { + ret = drm_panel_notifier_register(tp_active_panel, &ts->fb_notif); + if (ret) { + TPD_INFO("Unable to register fb_notifier: %d\n", ret); + } + } + //step15 : workqueue create(speedup_resume) + ts->speedup_resume_wq = create_singlethread_workqueue("speedup_resume_wq"); + if (!ts->speedup_resume_wq) { + ret = -ENOMEM; + goto threaded_irq_free; + } + + INIT_WORK(&ts->speed_up_work, speedup_resume); + if (himax_boot_mode == 0) + INIT_WORK(&ts->fw_update_work, tp_fw_update_work); + else + INIT_DELAYED_WORK(&ts->fw_update_delayed_work, tp_fw_update_work); + + + //step 16 : short edge shield + if (ts->edge_limit_support) { + ts->limit_enable = 1; + ts->limit_edge = ts->limit_enable & 1; + ts->limit_corner = 0; + ts->edge_limit.limit_area = 1; + ts->edge_limit.in_which_area = AREA_NOTOUCH; + + ts->edge_limit.left_x1 = (ts->edge_limit.limit_area * 1000)/100; + ts->edge_limit.right_x1 = ts->resolution_info.LCD_WIDTH - ts->edge_limit.left_x1; + ts->edge_limit.left_x2 = 2 * ts->edge_limit.left_x1; + ts->edge_limit.right_x2 = ts->resolution_info.LCD_WIDTH - (2 * ts->edge_limit.left_x1); + ts->edge_limit.left_x3 = 5 * ts->edge_limit.left_x1; + ts->edge_limit.right_x3 = ts->resolution_info.LCD_WIDTH - (5 * ts->edge_limit.left_x1); + + ts->edge_limit.left_y1 = (ts->edge_limit.limit_area * 1000)/100; + ts->edge_limit.right_y1 = ts->resolution_info.LCD_HEIGHT - ts->edge_limit.left_y1; + ts->edge_limit.left_y2 = 2 * ts->edge_limit.left_y1; + ts->edge_limit.right_y2 = ts->resolution_info.LCD_HEIGHT - (2 * ts->edge_limit.left_y1); + ts->edge_limit.left_y3 = 5 * ts->edge_limit.left_y1; + ts->edge_limit.right_y3 = ts->resolution_info.LCD_HEIGHT - (5 * ts->edge_limit.left_y1); + } + + //step 17:esd recover support + if (ts->esd_handle_support) { + ts->esd_info.esd_workqueue = create_singlethread_workqueue("esd_workthread"); + INIT_DELAYED_WORK(&ts->esd_info.esd_check_work, esd_handle_func); + + mutex_init(&ts->esd_info.esd_lock); + + ts->esd_info.esd_running_flag = 0; + ts->esd_info.esd_work_time = 2 * HZ; // HZ: clock ticks in 1 second generated by system + TPD_INFO("Clock ticks for an esd cycle: %d\n", ts->esd_info.esd_work_time); + + esd_handle_switch(&ts->esd_info, true); + } + + //step 18:spurious_fingerprint support + if (ts->spurious_fp_support) { + ts->spuri_fp_touch.thread = kthread_run(finger_protect_handler, ts, "touchpanel_fp"); + if (IS_ERR(ts->spuri_fp_touch.thread)) { + TPD_INFO("spurious fingerprint thread create failed\n"); + } + } + + //step 19: charge pump support + if (ts->charger_pump_support) { + if (ts->ts_ops->get_usb_state) { + ts->is_usb_checked = !!ts->ts_ops->get_usb_state(); + } else { + ts->is_usb_checked = 0; + } + TPD_INFO("curent usb state is %d\n", ts->is_usb_checked); + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_CHARGE, ts->is_usb_checked); + if (ret < 0) { + TPD_INFO("switch charge mode failed\n"); + } + } + + // step 20: ear sense support + if (ts->ear_sense_support) { + mutex_init(&ts->mutex_earsense); // init earsense operate mutex + + //malloc space for storing earsense delta + ts->earsense_delta = kzalloc(2 * ts->hw_res.EARSENSE_TX_NUM * ts->hw_res.EARSENSE_RX_NUM, GFP_KERNEL); + if (ts->earsense_delta == NULL) { + ret = -ENOMEM; + TPD_INFO("earsense_delta kzalloc error\n"); + goto threaded_irq_free; + } + + //create work queue for read earsense delta + ts->delta_read_wq = create_singlethread_workqueue("touch_delta_wq"); + if (!ts->delta_read_wq) { + ret = -ENOMEM; + goto earsense_alloc_free; + } + INIT_WORK(&ts->read_delta_work, touch_read_delta); + } + + //step 21 : createproc proc files interface + init_touchpanel_proc(ts); + + //step 22 : Other**** + ts->i2c_ready = true; + ts->loading_fw = false; + ts->is_suspended = 0; + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + ts->gesture_enable = 0; + ts->es_enable = 0; + ts->fd_enable = 0; + ts->palm_enable = 1; + ts->touch_count = 0; + ts->glove_enable = 0; + ts->view_area_touched = 0; + ts->tp_suspend_order = LCD_TP_SUSPEND; + ts->tp_resume_order = TP_LCD_RESUME; + ts->skip_suspend_operate = false; + ts->skip_reset_in_resume = false; + ts->skip_enable_touchhold = false; + ts->irq_slot = 0; + ts->touch_hold_enable = 0; + ts->lcd_refresh_rate = 0; + ts->reject_point = 0; + ts->charge_detect = 0; + ts->firmware_update_type = 0; + ts->corner_delay_up = -1; + if(ts->is_noflash_ic) { + ts->irq = ts->s_client->irq; + } else { + ts->irq = ts->client->irq; + } + tp_register_times++; + g_tp = ts; + complete(&ts->pm_complete); + TPD_INFO("Touch panel probe : normal end\n"); + return 0; + +earsense_alloc_free: + kfree(ts->earsense_delta); + +threaded_irq_free: + free_irq(ts->irq, ts); + +manu_info_alloc_err: + kfree(ts->panel_data.manufacture_info.version); + +manu_version_alloc_err: + kfree(ts->panel_data.fw_name); + +free_touch_panel_input: + input_unregister_device(ts->input_dev); + input_unregister_device(ts->kpd_input_dev); + input_unregister_device(ps_input_dev); + + +err_check_functionality_failed: + if (ts->int_mode == UNBANNABLE) { + free_irq(ts->irq, ts); + } + //ts->ts_ops->power_control(ts->chip_data, false); + +power_control_failed: + + if (!IS_ERR_OR_NULL(ts->hw_res.vdd_2v8)) { + regulator_disable(ts->hw_res.vdd_2v8); + regulator_put(ts->hw_res.vdd_2v8); + ts->hw_res.vdd_2v8 = NULL; + } + + if (!IS_ERR_OR_NULL(ts->hw_res.vcc_1v8)) { + regulator_disable(ts->hw_res.vcc_1v8); + regulator_put(ts->hw_res.vcc_1v8); + ts->hw_res.vcc_1v8 = NULL; + } + + if (gpio_is_valid(ts->hw_res.enable2v8_gpio)) + gpio_free(ts->hw_res.enable2v8_gpio); + + if (gpio_is_valid(ts->hw_res.enable1v8_gpio)) + gpio_free(ts->hw_res.enable1v8_gpio); + + if (gpio_is_valid(ts->hw_res.irq_gpio)) { + gpio_free(ts->hw_res.irq_gpio); + } + + if (gpio_is_valid(ts->hw_res.reset_gpio)) { + gpio_free(ts->hw_res.reset_gpio); + } + + if (gpio_is_valid(ts->hw_res.cs_gpio)) { + gpio_free(ts->hw_res.cs_gpio); + } + + if (gpio_is_valid(ts->hw_res.id1_gpio)) { + gpio_free(ts->hw_res.id1_gpio); + } + + if (gpio_is_valid(ts->hw_res.id2_gpio)) { + gpio_free(ts->hw_res.id2_gpio); + } + + if (gpio_is_valid(ts->hw_res.id3_gpio)) { + gpio_free(ts->hw_res.id3_gpio); + } + msleep(200); +// sec_ts_pinctrl_configure(&ts->hw_res, false); + + return ret; +} + +/** + * touchpanel_ts_suspend - touchpanel suspend function + * @dev: i2c_client->dev using to get touchpanel_data resource + * + * suspend function bind to LCD on/off status + * Returning zero(sucess) or negative errno(failed) + */ +static int tp_suspend(struct device *dev) +{ + int ret; + struct touchpanel_data *ts = dev_get_drvdata(dev); + int i = 100; + + TPD_INFO("%s: start.\n", __func__); + + TPD_INFO("tp_suspend ts->spuri_fp_touch.fp_trigger =%d ts->i2c_ready =%d ts->spuri_fp_touch.lcd_resume_success=%d \n", + ts->spuri_fp_touch.fp_trigger , ts->i2c_ready , ts->spuri_fp_touch.lcd_resume_ok); + ts->spuri_fp_touch.lcd_resume_ok = false; + //step1:detect whether we need to do suspend + if (ts->input_dev == NULL) { + TPD_INFO("input_dev registration is not complete\n"); + goto NO_NEED_SUSPEND; + } + if (ts->loading_fw) { + TPD_INFO("FW is updating while suspending"); + goto NO_NEED_SUSPEND; + } + +#ifndef TPD_USE_EINT + hrtimer_cancel(&ts->timer); +#endif + + /* release all complete first */ + if (ts->ts_ops->reinit_device) { + ts->ts_ops->reinit_device(ts->chip_data); + } + + //step2:get mutex && start process suspend flow + mutex_lock(&ts->mutex); + if (!ts->is_suspended) { + ts->is_suspended = 1; + ts->suspend_state = TP_SUSPEND_COMPLETE; + } else { + TPD_INFO("%s: do not suspend twice.\n", __func__); + goto EXIT; + } + + //step3:Release key && touch event before suspend + tp_btnkey_release(ts); + tp_touch_release(ts); + + //step4:cancel esd test + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + //step5:ear sense support + if (ts->ear_sense_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, false); + } + if (ts->face_detect_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, false); + } + + //step6:gesture mode status process + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_GESTURE, true); + goto EXIT; + } + } + + //step7:skip suspend operate only when gesture_enable is 0 + if (ts->skip_suspend_operate && (!ts->gesture_enable)) { + goto EXIT; + } + + //step8:switch mode to sleep + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + gpio_direction_output(ts->hw_res.reset_gpio, 0); + + //sec_ts_pinctrl_configure(&ts->hw_res, false); + TPD_INFO("TP %s: spi_set_cs begain\n", __func__); + gpio_direction_output(ts->hw_res.cs_gpio, 0); + while(gpio_get_value(ts->hw_res.cs_gpio) != 0&&(i>0)){ + usleep_range(10000, 10200); + i--; + } + TPD_INFO("TP %s: spi_set_cs end i = %d\n", __func__, i); + +EXIT: + TPD_INFO("%s: end.\n", __func__); + mutex_unlock(&ts->mutex); + +NO_NEED_SUSPEND: + complete(&ts->pm_complete); + + return 0; +} + +int tp_shutdown(struct device *dev) +{ + int ret; + struct touchpanel_data *ts = dev_get_drvdata(dev); + int i = 100; + + TPD_INFO("%s: start.\n", __func__); + + TPD_INFO("tp_suspend ts->spuri_fp_touch.fp_trigger =%d ts->i2c_ready =%d ts->spuri_fp_touch.lcd_resume_success=%d \n", + ts->spuri_fp_touch.fp_trigger , ts->i2c_ready , ts->spuri_fp_touch.lcd_resume_ok); + ts->spuri_fp_touch.lcd_resume_ok = false; + //step1:detect whether we need to do suspend + if (ts->input_dev == NULL) { + TPD_INFO("input_dev registration is not complete\n"); + return -1; + } + +#ifndef TPD_USE_EINT + hrtimer_cancel(&ts->timer); +#endif + + /* release all complete first */ + if (ts->ts_ops->reinit_device) { + ts->ts_ops->reinit_device(ts->chip_data); + } + + //step2:get mutex && start process suspend flow + mutex_lock(&ts->mutex); + if (!ts->is_suspended) { + ts->is_suspended = 1; + ts->suspend_state = TP_SUSPEND_COMPLETE; + } else { + TPD_INFO("%s: do not suspend twice.\n", __func__); + goto EXIT; + } + + //step3:Release key && touch event before suspend + tp_btnkey_release(ts); + tp_touch_release(ts); + + //step4:cancel esd test + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, false); + } + + //step5:ear sense support + if (ts->ear_sense_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_EARSENSE, false); + } + if (ts->face_detect_support) { + ts->ts_ops->mode_switch(ts->chip_data, MODE_FACE_DETECT, false); + } + + //step8:switch mode to sleep + ret = ts->ts_ops->mode_switch(ts->chip_data, MODE_SLEEP, true); + if (ret < 0) { + TPD_INFO("%s, Touchpanel operate mode switch failed\n", __func__); + } + + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } + gpio_direction_output(ts->hw_res.reset_gpio, 0); + + //sec_ts_pinctrl_configure(&ts->hw_res, false); + TPD_INFO("TP %s: spi_set_cs begain\n", __func__); + gpio_direction_output(ts->hw_res.cs_gpio, 0); + while(gpio_get_value(ts->hw_res.cs_gpio) != 0&&(i>0)){ + usleep_range(10000, 10200); + i--; + } + TPD_INFO("TP %s: spi_set_cs end i = %d\n", __func__, i); + +EXIT: + TPD_INFO("%s: end.\n", __func__); + mutex_unlock(&ts->mutex); + + return 0; +} + +/** + * touchpanel_ts_suspend - touchpanel resume function + * @dev: i2c_client->dev using to get touchpanel_data resource + * + * resume function bind to LCD on/off status, this fuction start thread to speedup screen on flow. + * Do not care the result: Return void type + */ +static void tp_resume(struct device *dev) +{ + struct touchpanel_data *ts = dev_get_drvdata(dev); + + TPD_INFO("%s start.\n", __func__); + + if (!ts->is_suspended) { + TPD_INFO("%s: do not resume twice.\n", __func__); + goto NO_NEED_RESUME; + } + ts->is_suspended = 0; + ts->suspend_state = TP_RESUME_COMPLETE; + if (ts->loading_fw) + goto NO_NEED_RESUME; + + //free irq at first + free_irq(ts->irq, ts); + TPD_INFO("%s free_irq end.\n", __func__); + if (ts->ts_ops->reinit_device) { + ts->ts_ops->reinit_device(ts->chip_data); + } + gpio_direction_output(ts->hw_res.cs_gpio, 1); + gpio_direction_output(ts->hw_res.reset_gpio, 1); + + if(ts->ts_ops->resume_prepare) { + mutex_lock(&ts->mutex); + ts->ts_ops->resume_prepare(ts->chip_data); + mutex_unlock(&ts->mutex); + } + TPD_INFO("%s speed_up_work start.\n", __func__); + queue_work(ts->speedup_resume_wq, &ts->speed_up_work); + //speedup_resume_test(ts); + TPD_INFO("%s speed_up_work end.\n", __func__); + return; + +NO_NEED_RESUME: + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + complete(&ts->pm_complete); +} + +/** + * speedup_resume - speedup resume thread process + * @work: work struct using for this thread + * + * do actully resume function + * Do not care the result: Return void type + */ +static void speedup_resume(struct work_struct *work) +{ + int timed_out = 0; + struct touchpanel_data *ts = container_of(work, struct touchpanel_data, + speed_up_work); + struct fp_underscreen_info tp_info; + + struct sched_param param = { .sched_priority = -1 }; + sched_setscheduler(current, SCHED_FIFO, ¶m); + + TPD_INFO("%s is called\n", __func__); + + //step1: get mutex for locking i2c acess flow + mutex_lock(&ts->mutex); + + //step2:before Resume clear All of touch/key event Reset some flag to default satus + if (ts->edge_limit_support) + ts->edge_limit.in_which_area = AREA_NOTOUCH; + tp_btnkey_release(ts); + tp_touch_release(ts); + + if (ts->int_mode == UNBANNABLE) { + ts->ts_ops->power_control(ts->chip_data, 1); + TPD_INFO("before irq register, power on\n"); + mdelay(20); + tp_register_irq_func(ts); + } + + + //step3:Reset IC && switch work mode, ft8006 is reset by lcd, no more reset needed + if (!ts->skip_reset_in_resume) { + ts->ts_ops->reset(ts->chip_data); + if (ts->gesture_enable) {//double tap wakeup,click touchhold area quickly before ending resume flow, + if (g_tp->touchold_event) { + g_tp->touchold_event = 0; + tp_info.x = 0; + tp_info.y = 0; + tp_info.touch_state = 0; + TPD_INFO("%s: tp_info.x = %d, tp_info.y= %d\n",__func__, tp_info.x, tp_info.y); + //opticalfp_irq_handler(&tp_info);//do reset will lost touchhold up event,which will lead fingerptint highlight + } + } + } + ts->skip_reset_in_resume = false; + if (!ts->gesture_enable) { + // sec_ts_pinctrl_configure(&ts->hw_res, true); + } + + //step4:If use resume notify, exit wait first + if (ts->use_resume_notify) { + reinit_completion(&ts->resume_complete); + timed_out = wait_for_completion_timeout(&ts->resume_complete, 1*HZ); //wait resume over for 1s + if ((0 == timed_out) || (ts->resume_complete.done)) { + TPD_INFO("resume state, timed_out:%d, done:%d\n", timed_out, ts->resume_complete.done); + } + } + + if (ts->ts_ops->specific_resume_operate) { + ts->ts_ops->specific_resume_operate(ts->chip_data); + } + + //step5: set default ps status to far + if (ts->ts_ops->write_ps_status) { + ts->ts_ops->write_ps_status(ts->chip_data, 0); + } + + operate_mode_switch(ts); + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, true); + } + + //step6:Request irq again + if (ts->int_mode == BANNABLE) { + tp_register_irq_func(ts); + } + + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + + //step7:Unlock && exit + TPD_INFO("%s: end!\n", __func__); + mutex_unlock(&ts->mutex); + complete(&ts->pm_complete); +} + +/* +static void speedup_resume_test(struct touchpanel_data *ts) +{ + int timed_out = 0; + struct fp_underscreen_info tp_info; + + TPD_INFO("%s is called\n", __func__); + + //step1: get mutex for locking i2c acess flow + mutex_lock(&ts->mutex); + + //step2:before Resume clear All of touch/key event Reset some flag to default satus + if (ts->edge_limit_support) + ts->edge_limit.in_which_area = AREA_NOTOUCH; + tp_btnkey_release(ts); + tp_touch_release(ts); + + if (ts->int_mode == UNBANNABLE) { + ts->ts_ops->power_control(ts->chip_data, 1); + TPD_INFO("before irq register, power on\n"); + msleep(20); + tp_register_irq_func(ts); + } + + + //step3:Reset IC && switch work mode, ft8006 is reset by lcd, no more reset needed + if (!ts->skip_reset_in_resume) { + ts->ts_ops->reset(ts->chip_data); + if (ts->gesture_enable) {//double tap wakeup,click touchhold area quickly before ending resume flow, + if (g_tp->touchold_event) { + g_tp->touchold_event = 0; + tp_info.x = 0; + tp_info.y = 0; + tp_info.touch_state = 0; + TPD_INFO("%s: tp_info.x = %d, tp_info.y= %d\n",__func__, tp_info.x, tp_info.y); + //opticalfp_irq_handler(&tp_info);//do reset will lost touchhold up event,which will lead fingerptint highlight + } + } + } + ts->skip_reset_in_resume = false; + if (!ts->gesture_enable) { + // sec_ts_pinctrl_configure(&ts->hw_res, true); + } + + //step4:If use resume notify, exit wait first + if (ts->use_resume_notify) { + reinit_completion(&ts->resume_complete); + timed_out = wait_for_completion_timeout(&ts->resume_complete, 1*HZ); //wait resume over for 1s + if ((0 == timed_out) || (ts->resume_complete.done)) { + TPD_INFO("resume state, timed_out:%d, done:%d\n", timed_out, ts->resume_complete.done); + } + } + + if (ts->ts_ops->specific_resume_operate) { + ts->ts_ops->specific_resume_operate(ts->chip_data); + } + + //step5: set default ps status to far + if (ts->ts_ops->write_ps_status) { + ts->ts_ops->write_ps_status(ts->chip_data, 0); + } + + operate_mode_switch(ts); + + if (ts->esd_handle_support) { + esd_handle_switch(&ts->esd_info, true); + } + + //step6:Request irq again + if (ts->int_mode == BANNABLE) { + tp_register_irq_func(ts); + } + + ts->suspend_state = TP_SPEEDUP_RESUME_COMPLETE; + + //step7:Unlock && exit + TPD_INFO("%s: end!\n", __func__); + mutex_unlock(&ts->mutex); + complete(&ts->pm_complete); +} +*/ + +//#if defined(CONFIG_FB) || defined(CONFIG_DRM_MSM) +static int tfb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + int *blank; + int timed_out = -1; + //struct fb_event *evdata = data; + struct drm_panel_notifier *evdata = data; + struct touchpanel_data *ts = container_of(self, struct touchpanel_data, fb_notif); + + //to aviod some kernel bug (at fbmem.c some local veriable are not initialized) + + if(event != DRM_PANEL_EARLY_EVENT_BLANK && event != DRM_PANEL_EVENT_BLANK) + return 0; + + if (evdata && evdata->data && ts && ts->chip_data) { + blank = evdata->data; + //TPD_INFO("%s: event = %ld, blank = %d\n", __func__, event, *blank); + if (*blank == DRM_PANEL_BLANK_POWERDOWN) { //suspend + if (event == DRM_PANEL_EARLY_EVENT_BLANK) { //early event + + timed_out = wait_for_completion_timeout(&ts->pm_complete, 0.5*HZ); //wait resume over for 0.5s + if ((0 == timed_out) || (ts->pm_complete.done)) { + TPD_INFO("completion state, timed_out:%d, done:%d\n", timed_out, ts->pm_complete.done); + } + + ts->suspend_state = TP_SUSPEND_EARLY_EVENT; //set suspend_resume_state + if (ts->esd_handle_support && ts->is_incell_panel && (ts->tp_suspend_order == LCD_TP_SUSPEND)) { + esd_handle_switch(&ts->esd_info, false); //incell panel need cancel esd early + } + + if (ts->tp_suspend_order == TP_LCD_SUSPEND) { + tp_suspend(ts->dev); + } else if (ts->tp_suspend_order == LCD_TP_SUSPEND) { + if (!ts->gesture_enable) { + TPD_INFO("disable tp isr 111, tp irq %d\n", ts->irq); + disable_irq_nosync(ts->irq); //avoid iic error + } + //tp_suspend(ts->dev); + if (!ts->gesture_enable) { + if (ts->int_mode == UNBANNABLE) + ts->ts_ops->power_control(ts->chip_data, 0); + } + } + } else if (event == DRM_PANEL_EVENT_BLANK) { //event + + if (ts->tp_suspend_order == TP_LCD_SUSPEND) { + + } else if (ts->tp_suspend_order == LCD_TP_SUSPEND) { + tp_suspend(ts->dev); + } + } + } + } + + return 0; +} +//#endif + +#ifdef CONFIG_TOUCHPANEL_MTK_PLATFORM +void tp_i2c_suspend(struct touchpanel_data *ts) +{ + ts->i2c_ready = false; + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*enable gpio wake system through interrupt*/ + enable_irq_wake(ts->irq); + return; + } + } + disable_irq_nosync(ts->irq); +} + +void tp_i2c_resume(struct touchpanel_data *ts) +{ + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*disable gpio wake system through intterrupt*/ + disable_irq_wake(ts->irq); + goto OUT; + } + } + enable_irq(ts->irq); + +OUT: + ts->i2c_ready = true; + if (ts->spurious_fp_support && ts->spuri_fp_touch.fp_trigger) { + wake_up_interruptible(&waiter); + } +} + +#else +void tp_i2c_suspend(struct touchpanel_data *ts) +{ + ts->i2c_ready = false; + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*enable gpio wake system through interrupt*/ + enable_irq_wake(ts->irq); + return; + } + } + if (ts->int_mode == BANNABLE) { + disable_irq_nosync(ts->irq); + } +} + +void tp_i2c_resume(struct touchpanel_data *ts) +{ + if (ts->black_gesture_support) { + if (ts->gesture_enable == 1) { + /*disable gpio wake system through intterrupt*/ + disable_irq_wake(ts->irq); + goto out; + } + } + if (ts->int_mode == BANNABLE) { + enable_irq(ts->irq); + } +out: + ts->i2c_ready = true; + if (ts->spurious_fp_support && ts->spuri_fp_touch.fp_trigger) { + wake_up_interruptible(&waiter); + } +} +#endif + +struct touchpanel_data *common_touch_data_alloc(void) +{ + if (g_tp) { + TPD_INFO("%s:common panel struct has alloc already!\n", __func__); + return NULL; + } + return kzalloc(sizeof(struct touchpanel_data), GFP_KERNEL); +} + +int common_touch_data_free(struct touchpanel_data *pdata) +{ + if (pdata) { + kfree(pdata); + } + + g_tp = NULL; + return 0; +} + +/** + * input_report_key_reduce - Using for report virtual key + * @work: work struct using for this thread + * + * before report virtual key, detect whether touch_area has been touched + * Do not care the result: Return void type + */ +void input_report_key_reduce(struct input_dev *dev, unsigned int code, int value) +{ + if (value) {//report Key[down] + if (g_tp) { + if (g_tp->view_area_touched == 0) { + input_report_key(dev, code, value); + } + else + TPD_INFO("Sorry,tp is touch down,can not report touch key\n"); + } + } else { + input_report_key(dev, code, value); + } +} + +void clear_view_touchdown_flag(void) +{ + if (g_tp) { + g_tp->view_area_touched = 0; + } +} diff --git a/drivers/oneplus/input/touchscreen_himax/touchpanel_common_himax.h b/drivers/oneplus/input/touchscreen_himax/touchpanel_common_himax.h new file mode 100755 index 0000000000000000000000000000000000000000..43630353f53d6bfcf3e5741270edae9d69c2b88c --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/touchpanel_common_himax.h @@ -0,0 +1,660 @@ +/*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : touchpanel_common.h + * + * Function : touchpanel public interface + * + * Version : V1.0 + * + ***********************************************************/ +#ifndef _TOUCHPANEL_COMMON_H_ +#define _TOUCHPANEL_COMMON_H_ + +/*********PART1:Head files**********************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // modified to oem by kuppala.rao@oneplus.com +#include +#include + +#include "util_interface/touch_interfaces.h" +#include "tp_devices.h" + +#define EFTM (250) +#define FW_UPDATE_COMPLETE_TIMEOUT msecs_to_jiffies(40*1000) + +/*********PART2:Define Area**********************/ +#define TPD_USE_EINT +#define TYPE_B_PROTOCOL + +#define PAGESIZE 512 +#define MAX_GESTURE_COORD 6 + +#define UnkownGesture 0 +#define DouTap 1 // double tap +#define UpVee 2 // V +#define DownVee 3 // ^ +#define LeftVee 4 // > +#define RightVee 5 // < +#define Circle 6 // O +#define DouSwip 7 // || +#define Left2RightSwip 8 // --> +#define Right2LeftSwip 9 // <-- +#define Up2DownSwip 10 // |v +#define Down2UpSwip 11 // |^ +#define Mgestrue 12 // M +#define Wgestrue 13 // W +#define SingleTap 15 // single tap +#define Sgestrue 14 // S +//just define to pass compile +#define FingerprintUp 16 +#define FingerprintDown 17 + +#define BIT0 (0x1 << 0) +#define BIT1 (0x1 << 1) +#define BIT2 (0x1 << 2) +#define BIT3 (0x1 << 3) +#define BIT4 (0x1 << 4) +#define BIT5 (0x1 << 5) +#define BIT6 (0x1 << 6) +#define BIT7 (0x1 << 7) + +/* bit operation */ +#define SET_BIT(data, flag) ((data) |= (flag)) +#define CLR_BIT(data, flag) ((data) &= ~(flag)) +#define CHK_BIT(data, flag) ((data) & (flag)) +#define VK_TAB {KEY_MENU, KEY_HOMEPAGE, KEY_BACK, KEY_SEARCH} + +#define TOUCH_BIT_CHECK 0x3FF //max support 10 point report.using for detect non-valid points +#define MAX_FW_NAME_LENGTH 60 +#define MAX_EXTRA_NAME_LENGTH 60 +#define MAX_LIMIT_DATA_LENGTH 60 + + +#define MAX_DEVICE_VERSION_LENGTH 16 +#define MAX_DEVICE_MANU_LENGTH 16 + +#define SYNAPTICS_PREFIX "SY_" +#define GOODIX_PREFIX "GT_" +#define FOCAL_PREFIX "FT_" + +#define FW_UPDATE_DELAY msecs_to_jiffies(2*1000) +extern struct drm_panel *lcd_active_panel; +extern struct drm_panel *tp_active_panel; +extern char Ctp_name[HARDWARE_MAX_ITEM_LONGTH]; + +/*********PART3:Struct Area**********************/ +typedef enum { + TYPE_DELTA_IDLE, /*means not in reading delta*/ + TYPE_DELTA_BUSY, /*reading delta data*/ +}delta_state; + +typedef enum { + TYPE_PROPERTIES = 1, /*using board_properties*/ + TYPE_AREA_SEPRATE, /*using same IC (button zone && touch zone are seprate)*/ + TYPE_DIFF_IC, /*using diffrent IC (button zone && touch zone are seprate)*/ + TYPE_NO_NEED, /*No need of virtual key process*/ +}vk_type; + +typedef enum { + AREA_NOTOUCH, + AREA_EDGE, + AREA_CRITICAL, + AREA_NORMAL, + AREA_CORNER, +}touch_area; + +typedef enum { + CORNER_TOPLEFT, /*When Phone Face you in portrait top left corner*/ + CORNER_TOPRIGHT, /*When Phone Face you in portrait top right corner*/ + CORNER_BOTTOMLEFT, /*When Phone Face you in portrait bottom left corner*/ + CORNER_BOTTOMRIGHT, /*When Phone Face you in portrait 7bottom right corner*/ +}corner_type; + +typedef enum { + MODE_NORMAL, + MODE_SLEEP, + MODE_EDGE, + MODE_GESTURE, + MODE_GLOVE, + MODE_CHARGE, + MODE_HEADSET, + MODE_WIRELESS_CHARGE, + MODE_GAME, + MODE_EARSENSE, + MODE_PALM_REJECTION, + MODE_FACE_DETECT, + MODE_FACE_CALIBRATE, + MODE_REFRESH_SWITCH, + MODE_TOUCH_HOLD, + MODE_TOUCH_AREA_SWITCH, + MODE_LIMIT_SWITCH, + MODE_GESTURE_SWITCH, + MODE_FINGERPRINT_TEST, + MODE_AUDIO_NOISE, +}work_mode; + +typedef enum { + FW_NORMAL, /*fw might update, depend on the fw id*/ + FW_ABNORMAL, /*fw abnormal, need update*/ +}fw_check_state; + +typedef enum { + FW_UPDATE_SUCCESS, + FW_NO_NEED_UPDATE, + FW_UPDATE_ERROR, + FW_UPDATE_FATAL, +}fw_update_state; + +typedef enum { + TP_SUSPEND_EARLY_EVENT, + TP_SUSPEND_COMPLETE, + TP_RESUME_EARLY_EVENT, + TP_RESUME_COMPLETE, + TP_SPEEDUP_RESUME_COMPLETE, +}suspend_resume_state; + +typedef enum IRQ_TRIGGER_REASON { + IRQ_TOUCH = 0x01, + IRQ_GESTURE = 0x02, + IRQ_BTN_KEY = 0x04, + IRQ_EXCEPTION = 0x08, + IRQ_FW_CONFIG = 0x10, + IRQ_DATA_LOGGER = 0x20, + IRQ_FW_AUTO_RESET = 0x40, + IRQ_FACE_STATE = 0x80, + IRQ_IGNORE = 0x00, + //just define to pass compile + IRQ_FW_HEALTH = 0x03, + IRQ_FINGERPRINT = 0x05, +}irq_reason; + +typedef enum vk_bitmap{ + BIT_reserve = 0x08, + BIT_BACK = 0x04, + BIT_HOME = 0x02, + BIT_MENU = 0x01, +}vk_bitmap; + +typedef enum finger_protect_status { + FINGER_PROTECT_TOUCH_UP, + FINGER_PROTECT_TOUCH_DOWN, + FINGER_PROTECT_NOTREADY, +}fp_touch_state; + +typedef enum debug_level { + LEVEL_BASIC, /*printk basic tp debug info*/ + LEVEL_DEBUG, /*printk all tp debug info*/ + LEVEL_DETAIL, /*printk tp detail log for stress test*/ +}tp_debug_level; + +typedef enum resume_order { + TP_LCD_RESUME, + LCD_TP_RESUME, +}tp_resume_order; + +typedef enum suspend_order { + TP_LCD_SUSPEND, + LCD_TP_SUSPEND, +}tp_suspend_order; + +typedef enum lcd_power { + LCD_POWER_OFF, + LCD_POWER_ON, +}lcd_power_status; + +struct Coordinate { + int x; + int y; +}; + +typedef enum interrupt_mode { + BANNABLE, + UNBANNABLE, + INTERRUPT_MODE_MAX, +}tp_interrupt_mode; + +typedef enum switch_mode_type { + SEQUENCE, + SINGLE, +}tp_switch_mode; + +struct gesture_info { + uint32_t gesture_type; + uint32_t clockwise; + struct Coordinate Point_start; + struct Coordinate Point_end; + struct Coordinate Point_1st; + struct Coordinate Point_2nd; + struct Coordinate Point_3rd; + struct Coordinate Point_4th; +}; + +struct fp_underscreen_info { + uint8_t touch_state; + uint8_t area_rate; + uint16_t x; + uint16_t y; +}; + +struct goodix_health_info { + uint8_t shield_water:1; + uint8_t shield_freq:1; + uint8_t baseline_refresh:1; + uint8_t shield_esd:1; + uint8_t reserve_bit:4; + uint8_t water_mode; + uint8_t freq_before; + uint8_t freq_after; + uint8_t baseline_refresh_type; + uint16_t esd_raw; + uint8_t reserve1; + uint8_t reserve2; + uint8_t reserve3; + uint8_t reserve4; + uint8_t reserve5; + uint8_t reserve6; + uint8_t reserve7; + uint8_t reserve8; + uint8_t reserve9; + uint8_t reserve10; + uint8_t reserve11; + uint8_t reserve12; + uint8_t reserve13; + uint8_t checksum; +}; +struct point_info { + uint16_t x; + uint16_t y; + uint16_t z; + uint8_t width_major; + uint8_t touch_major; + uint8_t status; + touch_area type; + //just defined to pass compilation + uint8_t tx_press; + uint8_t rx_press; +}; + +/* add haptic audio tp mask */ +struct shake_point { + uint16_t x; + uint16_t y; + uint8_t status; +}; + +struct corner_info { + uint8_t id; + bool flag; + struct point_info point; +}; + +struct manufacture_info { + char *version; + char *manufacture; +}; + +struct panel_info { + char *fw_name; /*FW name*/ + char *test_limit_name; /*test limit name*/ + char *extra; /*for some ic, may need other information*/ + const char *chip_name; /*chip name the panel is controlled by*/ + const char *project_name; /*project_name*/ + uint32_t TP_FW; /*FW Version Read from IC*/ + tp_dev tp_type; + struct manufacture_info manufacture_info; /*touchpanel device info*/ +}; + +struct hw_resource { + //gpio + int id1_gpio; + int id2_gpio; + int id3_gpio; + + int irq_gpio; /*irq GPIO num*/ + int reset_gpio; /*Reset GPIO*/ + int cs_gpio; + + int enable2v8_gpio; /*vdd_2v8 enable GPIO*/ + int enable1v8_gpio; /*vcc_1v8 enable GPIO*/ + + //TX&&RX Num + int TX_NUM; + int RX_NUM; + int key_TX; /*the tx num occupied by touchkey*/ + int key_RX; /*the rx num occupied by touchkey*/ + int EARSENSE_TX_NUM; /*for earsense function data reading*/ + int EARSENSE_RX_NUM; /*for earsense function data reading*/ + + //power + struct regulator *vdd_2v8; /*power 2v8*/ + struct regulator *vcc_1v8; /*power 1v8*/ + uint32_t vdd_volt; /*avdd specific volt*/ + + //pinctrl + struct pinctrl *pinctrl; + struct pinctrl_state *pin_set_high; + struct pinctrl_state *pin_set_low; +}; + +struct edge_limit { + int limit_area; + int left_x1; + int right_x1; + int left_x2; + int right_x2; + int left_x3; + int right_x3; + int left_y1; + int right_y1; + int left_y2; + int right_y2; + int left_y3; + int right_y3; + touch_area in_which_area; +}; + +struct touch_major_limit { + int width_range; + int height_range; +}; + +struct button_map { + int width_x; /*width of each key area */ + int height_y; /*height of each key area*/ + struct Coordinate coord_menu; /*Menu centre coordinates*/ + struct Coordinate coord_home; /*Home centre coordinates*/ + struct Coordinate coord_back; /*Back centre coordinates*/ +}; + +struct resolution_info { + uint32_t max_x; /*touchpanel width */ + uint32_t max_y; /*touchpanel height*/ + uint32_t LCD_WIDTH; /*LCD WIDTH */ + uint32_t LCD_HEIGHT; /*LCD HEIGHT */ +}; + +struct esd_information { + bool esd_running_flag; + int esd_work_time; + struct mutex esd_lock; + struct workqueue_struct *esd_workqueue; + struct delayed_work esd_check_work; +}; + +struct spurious_fp_touch { + bool fp_trigger; /*thread only turn into runnning state by fingerprint kick proc/touchpanel/finger_protect_trigger*/ + bool lcd_resume_ok; + bool lcd_trigger_fp_check; + fp_touch_state fp_touch_st; /*provide result to fingerprint of touch status data*/ + struct task_struct *thread; /*tread use for fingerprint susprious touch check*/ +}; + +struct register_info { + uint8_t reg_length; + uint16_t reg_addr; + uint8_t * reg_result; +}; + +struct black_gesture_test { + bool gesture_backup; /*store the gesture enable flag */ + bool flag; /* indicate do black gesture test or not*/ + char *message; /* failure information if gesture test failed */ +}; + +enum touch_direction { + VERTICAL_SCREEN, + LANDSCAPE_SCREEN_90, + LANDSCAPE_SCREEN_270, +}; + +struct debug_info_proc_operations; +struct earsense_proc_operations; +struct touchpanel_data { + bool register_is_16bit; /*register is 16bit*/ + bool glove_mode_support; /*glove_mode support feature*/ + bool black_gesture_support; /*black_gesture support feature*/ + bool charger_pump_support; /*charger_pump support feature*/ + bool edge_limit_support; /*edge_limit support feature*/ + bool esd_handle_support; /*esd handle support feature*/ + bool fw_edge_limit_support; /*edge_limit by FW support feature*/ + bool spurious_fp_support; /*avoid fingerprint spurious trrigger feature*/ + bool gesture_test_support; /*indicate test black gesture or not*/ + bool game_switch_support; /*indicate game switch support or not*/ + bool ear_sense_support; /*touch porximity function*/ + bool smart_gesture_support; /*feature used to controltouch_major report*/ + bool face_detect_support; /*touch porximity function*/ + bool lcd_refresh_rate_switch; /*switch lcd refresh rate 60-90hz*/ + bool touch_hold_support; /*touchhold function for fingerprint*/ + + bool audio_noise_detect; /*support audio_noise_detect*/ + bool audio_noise_support; + bool charge_detect; + bool charge_detect_support; + bool wireless_charge_detect; /*suppor wireless_charge_detect*/ + bool wireless_charge_support; + bool module_id_support; /*update firmware by lcd module id*/ + bool i2c_ready; /*i2c resume status*/ + bool is_usb_checked; /*state of charger or usb*/ + bool loading_fw; /*touchpanel FW updating*/ + bool is_incell_panel; /*touchpanel is incell*/ + bool is_noflash_ic; /*noflash ic*/ + bool has_callback; /*whether have callback method to invoke common*/ + bool use_resume_notify; /*notify speed resume process*/ + bool fw_update_app_support; /*bspFwUpdate is used*/ + bool in_test_process; /*flag whether in test process*/ + u8 vk_bitmap ; /*every bit declear one state of key "reserve(keycode)|home(keycode)|menu(keycode)|back(keycode)"*/ + vk_type vk_type; /*virtual_key type*/ + delta_state delta_state; + + uint32_t irq_flags; /*irq setting flag*/ + int irq; /*irq num*/ + bool skip_enable_touchhold; + int gesture_enable; /*control state of black gesture*/ + int palm_enable; + int es_enable; + int fd_enable; + int fd_calibrate; + int lcd_refresh_rate; + bool project_info; /*different project using different parameter*/ + + int touch_hold_enable; + int touch_area_switch; + int touch_count; + int glove_enable; /*control state of glove gesture*/ + int limit_enable; /*control state of limit ebale */ + int limit_edge; /*control state of limit edge*/ + int limit_corner; /*control state of limit corner*/ + int is_suspended; /*suspend/resume flow exec flag*/ + int corner_delay_up; /*corner mode flag*/ + suspend_resume_state suspend_state; /*detail suspend/resume state*/ + + int boot_mode; /*boot up mode */ + int view_area_touched; /*view area touched flag*/ + int force_update; /*force update flag*/ + int max_num; /*max muti-touch num supportted*/ + int irq_slot; /*debug use, for print all finger's first touch log*/ + int firmware_update_type; /*firmware_update_type: 0=check firmware version 1=force update; 2=for FAE debug*/ + + tp_resume_order tp_resume_order; + tp_suspend_order tp_suspend_order; + tp_interrupt_mode int_mode; /*whether interrupt and be disabled*/ + tp_switch_mode mode_switch_type; /*used for switch mode*/ + bool skip_reset_in_resume; /*some incell ic is reset by lcd reset*/ + bool skip_suspend_operate; /*LCD and TP is in one chip,lcd power off in suspend at first, + can not operate i2c when tp suspend*/ + bool ps_status; /*save ps status, ps near = 1, ps far = 0*/ + int noise_level; /*save ps status, ps near = 1, ps far = 0*/ + bool gesture_switch; /*gesture mode close or open gesture*/ + bool reject_point; /*reject point for sensor*/ + bool fingerprint_int_test; /*fingerprint int pin test*/ + u8 limit_switch; /*0 is phone up 1 is crosswise*/ + u8 touchold_event; /*0 is touchhold down 1 is up*/ + bool kernel_grip_support; /* just defined to pass compilation */ + +#if defined(TPD_USE_EINT) + struct hrtimer timer; /*using polling instead of IRQ*/ +#endif + //#if defined(CONFIG_FB) + struct notifier_block fb_notif; /*register to control suspend/resume*/ + //#endif + + struct mutex mutex; /*mutex for lock i2c related flow*/ + struct mutex mutex_earsense; + struct completion pm_complete; /*completion for control suspend and resume flow*/ + struct completion fw_complete; /*completion for control fw update*/ + struct completion resume_complete; /*completion for control fw update*/ + struct panel_info panel_data; /*GPIO control(id && pinctrl && tp_type)*/ + struct hw_resource hw_res; /*hw resourc information*/ + struct edge_limit edge_limit; /*edge limit*/ + struct button_map button_map; /*virtual_key button area*/ + struct resolution_info resolution_info; /*resolution of touchpanel && LCD*/ + struct gesture_info gesture; /*gesture related info*/ + struct touch_major_limit touch_major_limit; /*used for control touch major reporting area*/ + + struct work_struct speed_up_work; /*using for speedup resume*/ + struct workqueue_struct *speedup_resume_wq; /*using for touchpanel speedup resume wq*/ + struct notifier_block notifier_update_fw; + + struct work_struct read_delta_work; /*using for read delta*/ + struct workqueue_struct *delta_read_wq; + + struct work_struct async_work; + struct workqueue_struct *async_workqueue; + struct work_struct fw_update_work; /*using for fw update*/ + struct delayed_work fw_update_delayed_work; + struct delayed_work work_read_info; /*using for print more rawdata when probe*/ + struct wakeup_source *source; + + + struct esd_information esd_info; + struct spurious_fp_touch spuri_fp_touch; /*spurious_finger_support*/ + + struct device *dev; /*used for i2c->dev*/ + struct i2c_client *client; + struct spi_device *s_client; + struct input_dev *input_dev; + struct input_dev *kpd_input_dev; + + struct touchpanel_operations *ts_ops; /*call_back function*/ + struct proc_dir_entry *prEntry_tp; /*struct proc_dir_entry of "/proc/touchpanel"*/ + struct proc_dir_entry *prEntry_debug_tp; /*struct proc_dir_entry of "/proc/touchpanel/debug_info"*/ + struct debug_info_proc_operations *debug_info_ops; /*debug info data*/ + struct earsense_proc_operations *earsense_ops; + struct register_info reg_info; /*debug node for register length*/ + struct black_gesture_test gesture_test; /*gesture test struct*/ + + void *chip_data; /*Chip Related data*/ + void *private_data; /*Reserved Private data*/ + char *earsense_delta; +}; + +struct touchpanel_operations { + int (*ftm_process) (void *chip_data); + u32 (*u32_trigger_reason) (void *chip_data, int gesture_enable, int is_suspended); + void (*enable_fingerprint) (void *chip_data, uint32_t enable); + void (*enable_gesture_mask) (void *chip_data, uint32_t enable); + void (*screenon_fingerprint_info) (void *chip_data, struct fp_underscreen_info *fp_tpinfo); + void (*set_touch_direction) (void *chip_data, uint8_t dir); + u8 (*get_touch_direction) (void *chip_data); + void (*health_report) (void *chip_data, struct goodix_health_info *mon_data); + int (*enable_single_tap) (void *chip_data, bool enable); + int (*get_chip_info) (void *chip_data); /*return 0:success;other:failed*/ + int (*mode_switch) (void *chip_data, work_mode mode, bool flag); /*return 0:success;other:failed*/ + int (*get_touch_points) (void *chip_data, struct point_info *points, int max_num); /*return point bit-map*/ + int (*get_gesture_info) (void *chip_data, struct gesture_info * gesture); /*return 0:success;other:failed*/ + int (*get_vendor) (void *chip_data, struct panel_info *panel_data); /*distingush which panel we use, (TRULY/OFLIM/BIEL/TPK)*/ + int (*reset) (void *chip_data); /*Reset Touchpanel*/ + int (*reinit_device) (void *chip_data); + fw_check_state (*fw_check) (void *chip_data, struct resolution_info *resolution_info, + struct panel_info *panel_data); /*return < 0 :failed; 0 sucess*/ + fw_update_state (*fw_update) (void *chip_data, const struct firmware *fw, bool force); /*return 0 normal; return -1:update failed;*/ + int (*power_control) (void *chip_data, bool enable); /*return 0:success;other:abnormal, need to jump out*/ + int (*reset_gpio_control) (void *chip_data, bool enable); /*used for reset gpio*/ + u8 (*trigger_reason) (void *chip_data, int gesture_enable, int is_suspended); /*clear innterrupt reg && detect irq trigger reason*/ + u8 (*get_keycode) (void *chip_data); /*get touch-key code*/ + int (*esd_handle) (void *chip_data); + int (*fw_handle) (void *chip_data); /*return 0 normal; return -1:update failed;*/ + void (*resume_prepare) (void *chip_data); /*using for operation before resume flow, +eg:incell 3320 need to disable gesture to release inter pins for lcd resume*/ + fp_touch_state (*spurious_fp_check) (void *chip_data); /*spurious fingerprint check*/ + void (*finger_proctect_data_get) (void *chip_data); /*finger protect data get*/ + void (*data_logger_open) (void *chip_data); /*get data logger open status in probe or after fwupdate*/ + void (*data_logger_get) (void *chip_data); /*data logger get*/ + void (*exit_esd_mode) (void *chip_data); /*add for s4322 exit esd mode*/ + void (*register_info_read)(void * chip_data, uint16_t register_addr, uint8_t *result, uint8_t length); /*add for read registers*/ + void (*write_ps_status) (void *chip_data, int ps_status); /*when detect iron plate, if ps is near ,enter iron plate mode;if ps is far, can not enter; exit esd mode when ps is far*/ + void (*specific_resume_operate) (void *chip_data); /*some ic need specific opearation in resuming*/ + int (*get_usb_state) (void); /*get current usb state*/ + void (*black_screen_test) (void *chip_data, char *msg); /*message of black gesture test*/ + int (*irq_handle_unlock) (void *chip_info); /*irq handler without mutex*/ + int (*async_work) (void *chip_info); /*async work*/ + int (*get_face_state) (void *chip_info); /*get face detect state*/ +}; + +struct debug_info_proc_operations { + void (*limit_read) (struct seq_file *s, struct touchpanel_data *ts); + void (*delta_read) (struct seq_file *s, void *chip_data); + void (*self_delta_read) (struct seq_file *s, void *chip_data); + void (*self_raw_read) (struct seq_file *s, void *chip_data); + void (*baseline_read) (struct seq_file *s, void *chip_data); + void (*baseline_blackscreen_read) (struct seq_file *s, void *chip_data); + void (*main_register_read) (struct seq_file *s, void *chip_data); + void (*reserve_read) (struct seq_file *s, void *chip_data); + void (*abs_doze_read) (struct seq_file *s, void *chip_data); + void (*RT251) (struct seq_file *s, void *chip_data); + void (*RT76) (struct seq_file *s, void *chip_data); + void (*RT254) (struct seq_file *s, void *chip_data); + void (*DRT) (struct seq_file *s, void *chip_data); +}; + +struct invoke_method { + void (*invoke_common)(void); + void (*async_work)(void); +}; + +struct earsense_proc_operations { + void (*rawdata_read) (void *chip_data, char *earsense_baseline, int read_length); + void (*delta_read) (void *chip_data, char *earsense_delta, int read_length); + void (*self_data_read) (void *chip_data, char *earsense_self_data, int read_length); +}; + +/*********PART3:function or variables for other files**********************/ +extern unsigned int tp_debug ; /*using for print debug log*/ + +struct touchpanel_data *common_touch_data_alloc(void); + +int common_touch_data_free(struct touchpanel_data *pdata); +int register_common_touch_device(struct touchpanel_data *pdata); + +void tp_i2c_suspend(struct touchpanel_data *ts); +void tp_i2c_resume (struct touchpanel_data *ts); + +int tp_powercontrol_1v8(struct hw_resource *hw_res, bool on); +int tp_powercontrol_2v8(struct hw_resource *hw_res, bool on); + +void operate_mode_switch (struct touchpanel_data *ts); +void input_report_key_reduce(struct input_dev *dev, unsigned int code, int value); +void esd_handle_switch(struct esd_information *esd_info, bool on); +void clear_view_touchdown_flag(void); +void tp_touch_btnkey_release(void); +void tp_util_get_vendor(struct touchpanel_data *ts, struct panel_info *panel_data); +extern bool tp_judge_ic_match(char * tp_ic_name); +/* add haptic audio tp mask */ +extern int msm_drm_notifier_call_chain(unsigned long val, void *v); +extern int gf_opticalfp_irq_handler(int event); + +#endif + diff --git a/drivers/oneplus/input/touchscreen_himax/tp_devices.h b/drivers/oneplus/input/touchscreen_himax/tp_devices.h new file mode 100755 index 0000000000000000000000000000000000000000..b618978aff94a054b0e24a0d0876fa8dcc5a2abe --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/tp_devices.h @@ -0,0 +1,38 @@ + /*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : tp_devices.h + * + * Function : touchpanel public interface + * + * Version : V1.0 + * + ***********************************************************/ +#ifndef TP_DEVICES_H +#define TP_DEVICES_H +//device list define +typedef enum tp_dev{ + TP_OFILM, + TP_BIEL, + TP_TRULY, + TP_BOE, + TP_G2Y, + TP_TPK, + TP_JDI, + TP_SAMSUNG, + TP_DSJM, + TP_BOE_B8, + TP_INNOLUX, + TP_HIMAX_DPT, + TP_AUO, + TP_DEPUTE, + TP_UNKNOWN, +}tp_dev; + +struct tp_dev_name { + tp_dev type; + char name[32]; +}; + +#endif + diff --git a/drivers/oneplus/input/touchscreen_himax/update_tpfw_notifier.c b/drivers/oneplus/input/touchscreen_himax/update_tpfw_notifier.c new file mode 100644 index 0000000000000000000000000000000000000000..a73818b588493a4bd0309192e08bff4f4d31e8e3 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/update_tpfw_notifier.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Himax Android Driver Sample Code for HX83112 chipset + * + * Copyright (C) 2019 Himax Corporation. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +BLOCKING_NOTIFIER_HEAD(tpfw_notifier_list); + +int update_tpfw_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&tpfw_notifier_list, nb); +} +EXPORT_SYMBOL(update_tpfw_register_client); + +int update_tpfw_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&tpfw_notifier_list, nb); +} +EXPORT_SYMBOL(update_tpfw_unregister_client); + + +int update_tpfw_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&tpfw_notifier_list, val, v); + +} +EXPORT_SYMBOL_GPL(update_tpfw_notifier_call_chain); + + diff --git a/drivers/oneplus/input/touchscreen_himax/util_interface/Kconfig b/drivers/oneplus/input/touchscreen_himax/util_interface/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..ce1219f11d20db601f4b85b518f1512778ca4096 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/util_interface/Kconfig @@ -0,0 +1,8 @@ + +config TOUCHPANEL_ONEPLUS + default y + bool "TP Synaptics " + ---help--- + say Y to enable driver for Touchpanel useing Synaptics_IC + + diff --git a/drivers/oneplus/input/touchscreen_himax/util_interface/Makefile b/drivers/oneplus/input/touchscreen_himax/util_interface/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..19be4449b129b23b72d11065677897e08cb82f26 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/util_interface/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the touchscreen drivers. +# + +obj-$(CONFIG_TOUCHPANEL_ONEPLUS) += touch_interfaces.o + diff --git a/drivers/oneplus/input/touchscreen_himax/util_interface/touch_interfaces.c b/drivers/oneplus/input/touchscreen_himax/util_interface/touch_interfaces.c new file mode 100755 index 0000000000000000000000000000000000000000..20f6599723911df59fc9c70dcf0e73e12276a224 --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/util_interface/touch_interfaces.c @@ -0,0 +1,639 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "touch_interfaces.h" + +#define TPD_DEVICE "touch_interface" +#define TPD_INFO(a, arg...) pr_err("[TP]"TPD_DEVICE ": " a, ##arg) +#define FIX_I2C_LENGTH 256 +static bool register_is_16bit = 0; +static struct mutex i2c_mutex; + + +/** + * touch_i2c_continue_read - Using for "read sequence bytes" through IIC + * @client: Handle to slave device + * @length: data size we want to read + * @data: data read from IIC + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_continue_read(struct i2c_client* client, unsigned short length, unsigned char *data) +{ + int retval; + unsigned char retry; + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = I2C_M_RD; + msg.len = length; + msg.buf = data; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + dev_err(&client->dev, "%s: I2C read over retry limit\n", __func__); + retval = -EIO; + } + return retval; + +} + +/** + * touch_i2c_read_block - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @length: data size we want to send + * @data: data we want to send + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_read_block(struct i2c_client *client, u16 addr, unsigned short length, unsigned char *data) +{ + int retval; + unsigned char retry; + static unsigned char *read_buf = NULL; + static unsigned int read_buf_size = 0; + static unsigned char *buffer = NULL; + struct i2c_msg msg[2]; + + mutex_lock(&i2c_mutex); + + if (!buffer) { + buffer = kzalloc(2, GFP_KERNEL | GFP_DMA); + if (!buffer) { + TPD_INFO("kzalloc buffer failed.\n"); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + } + buffer[0] = (addr >> 8) & 0xff; + buffer[1] = addr & 0xff; + + if (length > FIX_I2C_LENGTH) { + if (read_buf_size < length) { + if (read_buf) { + kfree(read_buf); + TPD_INFO("read block_1, free once.\n"); + } + read_buf = kzalloc(length, GFP_KERNEL | GFP_DMA); + if (!read_buf) { + read_buf_size = 0; + TPD_INFO("read block_1, kzalloc failed(len:%d, buf_size:%d).\n", length, read_buf_size); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + read_buf_size = length; + TPD_INFO("read block_1, kzalloc success(len:%d, buf_size:%d).\n", length, read_buf_size); + } else { + memset(read_buf, 0, length); + } + } else { + if (read_buf_size > FIX_I2C_LENGTH) { + kfree(read_buf); + read_buf = kzalloc(FIX_I2C_LENGTH, GFP_KERNEL | GFP_DMA); + if (!read_buf) { + read_buf_size = 0; + TPD_INFO("read block_2, kzalloc failed(len:%d, buf_size:%d).\n", length, read_buf_size); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + read_buf_size = FIX_I2C_LENGTH; + TPD_INFO("read block_2, kzalloc success(len:%d, buf_size:%d).\n", length, read_buf_size); + } else { + if (!read_buf) { + read_buf = kzalloc(FIX_I2C_LENGTH, GFP_KERNEL | GFP_DMA); + if (!read_buf) { + read_buf_size = 0; + TPD_INFO("read block_3, kzalloc failed(len:%d, buf_size:%d).\n", length, read_buf_size); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + read_buf_size = FIX_I2C_LENGTH; + TPD_INFO("read block_3, kzalloc success(len:%d, buf_size:%d).\n", length, read_buf_size); + } else { + memset(read_buf, 0, length); + } + } + } + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].buf = buffer; + + if (!register_is_16bit) { // if register is 8bit + msg[0].len = 1; + msg[0].buf[0] = buffer[1]; + } else { + msg[0].len = 2; + msg[0].buf[0] = buffer[0]; + msg[0].buf[1] = buffer[1]; + } + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = read_buf; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + TPD_INFO("%s: I2C read over retry limit\n", __func__); + retval = -EIO; + } + memcpy(data, read_buf, length); + + mutex_unlock(&i2c_mutex); + return retval; +} + + +/** + * touch_i2c_continue_write - Using for "write sequence bytes" through IIC + * @client: Handle to slave device + * @length: data size we want to write + * @data: data write to IIC + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_continue_write(struct i2c_client* client, unsigned short length, unsigned char *data) +{ + int retval; + unsigned char retry; + struct i2c_msg msg; + + msg.addr = client->addr; + msg.flags = 0; + msg.buf = data; + msg.len = length; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + dev_err(&client->dev, "%s: I2C write over retry limit\n", __func__); + retval = -EIO; + } + return retval; +} + +/** + * touch_i2c_write_block - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @length: data size we want to send + * @data: data we want to send + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer length(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_write_block(struct i2c_client *client, u16 addr, unsigned short length, unsigned char const *data) +{ + int retval; + unsigned char retry; + unsigned int total_length = 0; + static unsigned int write_buf_size = 0; + static unsigned char *write_buf = NULL; + struct i2c_msg msg[1]; + + mutex_lock(&i2c_mutex); + + total_length = length + (register_is_16bit ? 2 : 1); + if (total_length > FIX_I2C_LENGTH) { + if (write_buf_size < total_length) { + if (write_buf) { + kfree(write_buf); + TPD_INFO("write block_1, free once.\n"); + } + write_buf = kzalloc(total_length, GFP_KERNEL | GFP_DMA); + if (!write_buf) { + write_buf_size = 0; + TPD_INFO("write block_1, kzalloc failed(len:%d, buf_size:%d).\n", total_length, write_buf_size); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + write_buf_size = total_length; + TPD_INFO("write block_1, kzalloc success(len:%d, buf_size:%d).\n", total_length, write_buf_size); + } else { + memset(write_buf, 0, total_length); + } + } else { + if (write_buf_size > FIX_I2C_LENGTH) { + kfree(write_buf); + write_buf = kzalloc(FIX_I2C_LENGTH, GFP_KERNEL | GFP_DMA); + if (!write_buf) { + write_buf_size = 0; + TPD_INFO("write block_2, kzalloc failed(len:%d, buf_size:%d).\n", total_length, write_buf_size); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + write_buf_size = FIX_I2C_LENGTH; + TPD_INFO("write block_2, kzalloc success(len:%d, buf_size:%d).\n", total_length, write_buf_size); + } else { + if (!write_buf) { + write_buf = kzalloc(FIX_I2C_LENGTH, GFP_KERNEL | GFP_DMA); + if (!write_buf) { + write_buf_size = 0; + TPD_INFO("write block_3, kzalloc failed(len:%d, buf_size:%d).\n", total_length, write_buf_size); + mutex_unlock(&i2c_mutex); + return -ENOMEM; + } + write_buf_size = FIX_I2C_LENGTH; + TPD_INFO("write block_3, kzalloc success(len:%d, buf_size:%d).\n", total_length, write_buf_size); + } else { + memset(write_buf, 0, total_length); + } + } + } + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].buf = write_buf; + + if (!register_is_16bit) { // if register is 8bit + msg[0].len = length + 1; + msg[0].buf[0] = addr & 0xff; + + memcpy(&write_buf[1], &data[0], length); + } else { + msg[0].len = length + 2; + msg[0].buf[0] = (addr >> 8) & 0xff; + msg[0].buf[1] = addr & 0xff; + + memcpy(&write_buf[2], &data[0], length); + } + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + TPD_INFO("%s: I2C write over retry limit\n", __func__); + retval = -EIO; + } + + mutex_unlock(&i2c_mutex); + return retval; +} + +/** + * touch_i2c_read_byte - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to read + * + * Actully, This function call touch_i2c_read_block for IIC transfer, + * Returning zero(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_read_byte(struct i2c_client* client, unsigned short addr) +{ + int retval = 0; + unsigned char buf[2] = {0}; + + if (!client) { + dump_stack(); + return -1; + } + retval = touch_i2c_read_block(client, addr, 1, buf); + if (retval >= 0) + retval = buf[0] & 0xff; + + return retval; +} + + +/** + * touch_i2c_write_byte - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @data: data we want to send + * + * Actully, This function call touch_i2c_write_block for IIC transfer, + * Returning zero(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_write_byte(struct i2c_client* client, unsigned short addr, unsigned char data) +{ + int retval; + int length_trans = 1; + unsigned char data_send = data; + + if (!client) { + dump_stack(); + return -EINVAL; + } + retval = touch_i2c_write_block(client, addr, length_trans, &data_send); + if (retval == length_trans) + retval = 0; + + return retval; +} + +/** + * touch_i2c_read_word - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @data: data we want to read + * + * Actully, This func call touch_i2c_Read_block for IIC transfer, + * Returning negative errno else a 16-bit unsigned "word" received from the device. + */ +int touch_i2c_read_word(struct i2c_client* client, unsigned short addr) +{ + int retval; + unsigned char buf[2] = {0}; + + if (!client) { + dump_stack(); + return -EINVAL; + } + retval = touch_i2c_read_block(client, addr, 2, buf); + if (retval >= 0) + retval = buf[1] << 8 | buf[0]; + + return retval; +} + +/** + * touch_i2c_write_word - Using for "read word" through IIC + * @client: Handle to slave device + * @addr: addr to write + * @data: data we want to send + * + * Actully, This function call touch_i2c_write_block for IIC transfer, + * Returning zero(transfer success) or most likely negative errno(transfer error) + */ +int touch_i2c_write_word(struct i2c_client* client, unsigned short addr, unsigned short data) +{ + int retval; + int length_trans = 2; + unsigned char buf[2] = {data & 0xff, (data >> 8) & 0xff}; + + if (!client) { + dump_stack(); + return -EINVAL; + } + + retval = touch_i2c_write_block(client, addr, length_trans, buf); + if (retval == length_trans) + retval = 0; + + return retval; +} + +/** + * touch_i2c_read - Using for "read data from ic after writing or not" through IIC + * @client: Handle to slave device + * @writebuf: buf to write + * @writelen: data size we want to send + * @readbuf: buf we want save data + * @readlen: data size we want to receive + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer msg length(transfer success) or most likely negative errno(transfer EIO error) + */ +int touch_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen) +{ + int retval = 0; + int retry = 0; + + if (client == NULL) { + TPD_INFO("%s: i2c_client == NULL!\n", __func__); + return -1; + } + + if (readlen > 0) { + if (writelen > 0) { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msgs, 2) == 2) { + retval = 2; + break; + } + msleep(20); + } + } else { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, + }; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msgs, 1) == 1) { + retval = 1; + break; + } + msleep(20); + } + } + + if (retry == MAX_I2C_RETRY_TIME) { + TPD_INFO("%s: i2c_transfer(read) over retry limit\n", __func__); + retval = -EIO; + } + } + + return retval; +} + +/** + * touch_i2c_write - Using for "write data to ic" through IIC + * @client: Handle to slave device + * @writebuf: buf data wo want to send + * @writelen: data size we want to send + * + * Actully, This function call i2c_transfer for IIC transfer, + * Returning transfer msg length(transfer success) or most likely negative errno(transfer EIO error) + */ +int touch_i2c_write(struct i2c_client *client, char *writebuf, int writelen) +{ + int retval = 0; + int retry = 0; + + if (client == NULL) { + TPD_INFO("%s: i2c_client == NULL!", __func__); + return -1; + } + + if (writelen > 0) { + struct i2c_msg msgs[] = + { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + + for (retry = 0; retry < MAX_I2C_RETRY_TIME; retry++) { + if (i2c_transfer(client->adapter, msgs, 1) == 1) { + retval = 1; + break; + } + msleep(20); + } + if (retry == MAX_I2C_RETRY_TIME) { + TPD_INFO("%s: i2c_transfer(write) over retry limit\n", __func__); + retval = -EIO; + } + } + + return retval; +} + + +/** + * init_touch_interfaces - Using for Register IIC interface + * @dev: i2c_client->dev using to alloc memory for dma transfer + * @flag_register_16bit: bool param to detect whether this device using 16bit IIC address or 8bit address + * + * Actully, This function don't have many operation, we just detect device address length && alloc DMA memory for MTK platform + * Returning zero(sucess) or -ENOMEM(memory alloc failed) + */ +int init_touch_interfaces(struct device *dev, bool flag_register_16bit) +{ + register_is_16bit = flag_register_16bit; + mutex_init(&i2c_mutex); + + return 0; +} + +/******************************************************* +Description: +Novatek touchscreen spi read/write core function. + +return: +Executive outcomes. 0---succeed. + *******************************************************/ +int32_t spi_read_write(struct spi_device *client, uint8_t *buf, size_t len , uint8_t *rbuf, SPI_RW rw) +{ + struct spi_message m; + struct spi_transfer t = { + .len = len, + }; + + switch (rw) { + case SPIREAD: + t.tx_buf = &buf[0]; + t.rx_buf = rbuf; + t.len = (len + DUMMY_BYTES); + break; + + case SPIWRITE: + t.tx_buf = buf; + break; + } + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + return spi_sync(client, &m); +} + +/******************************************************* +Description: +Novatek touchscreen spi read function. + +return: +Executive outcomes. 2---succeed. -5---I/O error + *******************************************************/ +int32_t CTP_SPI_READ(struct spi_device *client, uint8_t *buf, uint16_t len) +{ + int32_t ret = -1; + int32_t retries = 0; + uint8_t rbuf[SPI_TANSFER_LEN+1] = {0}; + + buf[0] = SPI_READ_MASK(buf[0]); + + while (retries < 5) { + ret = spi_read_write(client, buf, len, rbuf, SPIREAD); + if (ret == 0) break; + retries++; + } + + if (unlikely(retries == 5)) { + TPD_INFO("read error, ret=%d\n", ret); + ret = -EIO; + } else { + memcpy((buf+1), (rbuf+2), (len-1)); + } + + return ret; +} + +/******************************************************* +Description: +Novatek touchscreen spi write function. + +return: +Executive outcomes. 1---succeed. -5---I/O error + *******************************************************/ +int32_t CTP_SPI_WRITE(struct spi_device *client, uint8_t *buf, uint16_t len) +{ + int32_t ret = -1; + int32_t retries = 0; + + buf[0] = SPI_WRITE_MASK(buf[0]); + + while (retries < 5) { + ret = spi_read_write(client, buf, len, NULL, SPIWRITE); + if (ret == 0) break; + retries++; + } + + if (unlikely(retries == 5)) { + TPD_INFO("error, ret=%d\n", ret); + ret = -EIO; + } + + return ret; +} + diff --git a/drivers/oneplus/input/touchscreen_himax/util_interface/touch_interfaces.h b/drivers/oneplus/input/touchscreen_himax/util_interface/touch_interfaces.h new file mode 100755 index 0000000000000000000000000000000000000000..ce8c17e95b5e987bbcc0b18bdaf1da43596116ff --- /dev/null +++ b/drivers/oneplus/input/touchscreen_himax/util_interface/touch_interfaces.h @@ -0,0 +1,49 @@ +/*********************************************************** + * Description : OnePlus touchpanel driver + * + * File : touch_interfaces.h + * + * Function : touchpanel public interface + * + * Version : V1.0 + * + ***********************************************************/ +#include +#ifndef TOUCH_INTERFACES_H +#define TOUCH_INTERFACES_H + +#define MAX_I2C_RETRY_TIME 2 + +//---SPI READ/WRITE--- +#define SPI_WRITE_MASK(a) (a | 0x80) +#define SPI_READ_MASK(a) (a & 0x7F) +#define DUMMY_BYTES (1) +#define SPI_TANSFER_LEN 512 + +typedef enum { + SPIWRITE = 1, + SPIREAD = 2 +} SPI_RW; + +int touch_i2c_read_byte(struct i2c_client* client, u16 addr); +int touch_i2c_write_byte(struct i2c_client* client, u16 addr, unsigned char data); + +int touch_i2c_read_word(struct i2c_client* client, u16 addr); +int touch_i2c_write_word(struct i2c_client* client, u16 addr, unsigned short data); + +int touch_i2c_read_block(struct i2c_client* client, u16 addr, unsigned short length, unsigned char *data); +int touch_i2c_write_block(struct i2c_client* client, u16 addr, unsigned short length, unsigned char const *data); + +int touch_i2c_read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen); +int touch_i2c_write(struct i2c_client *client, char *writebuf, int writelen); + +int init_touch_interfaces(struct device *dev, bool flag_register_16bit); +int touch_i2c_continue_read(struct i2c_client* client, unsigned short length, unsigned char *data); +int touch_i2c_continue_write(struct i2c_client* client, unsigned short length, unsigned char *data); +int32_t spi_read_write(struct spi_device *client, uint8_t *buf, size_t len, uint8_t *rbuf, SPI_RW rw); +int32_t CTP_SPI_READ(struct spi_device *client, uint8_t *buf, uint16_t len); +int32_t CTP_SPI_WRITE(struct spi_device *client, uint8_t *buf, uint16_t len); + + +#endif + diff --git a/drivers/oneplus/kernel/Kconfig b/drivers/oneplus/kernel/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..0f5ed7b0db825b374c26a6e02bb4060d8ca84c08 --- /dev/null +++ b/drivers/oneplus/kernel/Kconfig @@ -0,0 +1,9 @@ +config PANIC_FLUSH + bool "flush blk device in panic flow" + default y + help + add flush behaviour in panic flow + also contains the blk_issue_flush statistics information + /proc/sysctl/blkdev_issue_flush_count +# oem device deriver +source "drivers/oneplus/kernel/cgroup/Kconfig" diff --git a/drivers/oneplus/kernel/Makefile b/drivers/oneplus/kernel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ad4ad63dc990ba5ec0a5fc280d803a2e860f1210 --- /dev/null +++ b/drivers/oneplus/kernel/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_PANIC_FLUSH) += panic_flush.o +obj-y += cgroup/ diff --git a/drivers/oneplus/kernel/cgroup/Kconfig b/drivers/oneplus/kernel/cgroup/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..362b52b0025f14769e056d1dea99d36f63175868 --- /dev/null +++ b/drivers/oneplus/kernel/cgroup/Kconfig @@ -0,0 +1,7 @@ +config CGROUP_IOLIMIT + bool "limit controller" + default n + help + This feature lets vfs recognize task groups and control IO + bandwidth allocation to such task groups. It uses cgroups to group + tasks. diff --git a/drivers/oneplus/kernel/cgroup/Makefile b/drivers/oneplus/kernel/cgroup/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0f4e6fec54bb89be160cf7fea9681c417cb75cbf --- /dev/null +++ b/drivers/oneplus/kernel/cgroup/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CGROUP_IOLIMIT) += cgroup_io_limit.o diff --git a/drivers/oneplus/kernel/cgroup/cgroup_io_limit.c b/drivers/oneplus/kernel/cgroup/cgroup_io_limit.c new file mode 100644 index 0000000000000000000000000000000000000000..0d839b560c1cb11d2bf260f3edd5a5e37bee21e2 --- /dev/null +++ b/drivers/oneplus/kernel/cgroup/cgroup_io_limit.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.1 +/* + * cgroup_iolimit.c - control group iolimit subsystem + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include +#include +#include +#include +#include "../../include/linux/iolimit_cgroup.h" +#include + +bool iolimit_enable; +bool iolimit_enable_registered = false; + +static int is_need_iolimit(struct iolimit_cgroup *iolimitcg) +{ + int ret = 0; + + if (current_is_fg()) { + return 0; + } + + + ret = signal_pending_state(TASK_INTERRUPTIBLE, current); + if (ret == 1) { + return 0; + } + return atomic64_read(&iolimitcg->switching); +} + +static bool is_write_need_wakeup(struct iolimit_cgroup *iolimitcg) +{ + int ret = false; + + if (atomic64_read(&iolimitcg->switching) == 0) + ret = true; + + if (iolimitcg->write_part_nbyte > iolimitcg->write_already_used) + ret = true; + + rcu_read_lock(); + if (iolimitcg != task_iolimitcg(current)) + ret = true; + + if (current_is_fg()) + ret = true; + + rcu_read_unlock(); + return ret; +} + +static bool is_read_need_wakeup(struct iolimit_cgroup *iolimitcg) +{ + int ret = false; + + if (atomic64_read(&iolimitcg->switching) == 0) + ret = true; + + if (iolimitcg->read_part_nbyte > iolimitcg->read_already_used) + ret = true; + + rcu_read_lock(); + if (iolimitcg != task_iolimitcg(current)) + ret = true; + + if (current_is_fg()) + ret = true; + + rcu_read_unlock(); + pr_info("[iolimit] current: %s, uid: %d, ret: %d", current -> comm, current_uid().val, current_is_fg()); + return ret; +} + +void do_io_write_bandwidth_control(size_t count) +{ + size_t may_io_cnt; + struct iolimit_cgroup *iolimitcg; + +repeat: + rcu_read_lock(); + iolimitcg = task_iolimitcg(current); + if (!is_need_iolimit(iolimitcg)) { + rcu_read_unlock(); + return; + } + pr_info("[iolimit] need limit: %s, is_fg: %d", current ->comm, current_is_fg()); + + spin_lock_bh(&iolimitcg->write_lock); + may_io_cnt = iolimitcg->write_part_nbyte - iolimitcg->write_already_used; + if (may_io_cnt < count) { + spin_unlock_bh(&iolimitcg->write_lock); + if (css_tryget_online(&iolimitcg->css)) { + rcu_read_unlock(); + wait_event_interruptible_timeout(iolimitcg->write_wait, + is_write_need_wakeup(iolimitcg), msecs_to_jiffies(125)); + css_put(&iolimitcg->css); + } else { + rcu_read_unlock(); + } + goto repeat; + } else if (may_io_cnt >= count) { + may_io_cnt = count; + iolimitcg->write_already_used += may_io_cnt; + } + + spin_unlock_bh(&iolimitcg->write_lock); + rcu_read_unlock(); +} + +void do_io_read_bandwidth_control(size_t count) +{ + size_t may_io_cnt; + struct iolimit_cgroup *iolimitcg; + +repeat: + rcu_read_lock(); + iolimitcg = task_iolimitcg(current); + if (!is_need_iolimit(iolimitcg)) { + rcu_read_unlock(); + return; + } + + spin_lock_bh(&iolimitcg->read_lock); + may_io_cnt = iolimitcg->read_part_nbyte - iolimitcg->read_already_used; + if (may_io_cnt < count) { + spin_unlock_bh(&iolimitcg->read_lock); + if (css_tryget_online(&iolimitcg->css)) { + rcu_read_unlock(); + wait_event_interruptible_timeout(iolimitcg->read_wait, + is_read_need_wakeup(iolimitcg), msecs_to_jiffies(125)); + css_put(&iolimitcg->css); + } else { + rcu_read_unlock(); + } + + if (task_in_pagefault(current)) + return; + + goto repeat; + } else if (may_io_cnt >= count) { + may_io_cnt = count; + iolimitcg->read_already_used += may_io_cnt; + } + + spin_unlock_bh(&iolimitcg->read_lock); + rcu_read_unlock(); +} + +//static void write_timer_handler(unsigned long data) +static void write_timer_handler(struct timer_list *t) +{ +// struct iolimit_cgroup *iolimitcg = (struct iolimit_cgroup *)data; + struct iolimit_cgroup *iolimitcg = from_timer(iolimitcg, t, write_timer); + + spin_lock_bh(&iolimitcg->write_lock); + iolimitcg->write_already_used = 0; + spin_unlock_bh(&iolimitcg->write_lock); + wake_up_all(&iolimitcg->write_wait); + mod_timer(&iolimitcg->write_timer, jiffies + HZ / 8); +} + +//static void read_timer_handler(unsigned long data) +static void read_timer_handler(struct timer_list *t) +{ +// struct iolimit_cgroup *iolimitcg = (struct iolimit_cgroup *)data; + struct iolimit_cgroup *iolimitcg = from_timer(iolimitcg, t, read_timer); + + spin_lock_bh(&iolimitcg->read_lock); + iolimitcg->read_already_used = 0; + spin_unlock_bh(&iolimitcg->read_lock); + wake_up_all(&iolimitcg->read_wait); + mod_timer(&iolimitcg->read_timer, jiffies + HZ / 8); +} + +static int iolimit_enable_seq_show(struct seq_file *seq, void *p) +{ + seq_printf(seq, "%d\n", iolimit_enable?1:0); + return 0; +} + +static ssize_t iolimit_enable_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[64] = { 0 }; + int user_set_value = 0; + int ret = -1; + + if (cnt > sizeof(buf) - 1) + cnt = sizeof(buf) - 1; + + if (copy_from_user(&buf[0], ubuf, cnt)) + return -EFAULT; + + ret = kstrtoint(strstrip(&buf[0]), 0, &user_set_value); + + if (ret < 0) + return ret; + + iolimit_enable = !!user_set_value; + return cnt; +} + +static int iolimit_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, iolimit_enable_seq_show, NULL); +} + +static const struct file_operations iolimit_enable_ops = { + .open = iolimit_enable_open, + .read = seq_read, + .write = iolimit_enable_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static struct cgroup_subsys_state *iolimit_css_alloc(struct cgroup_subsys_state *parent) +{ + struct iolimit_cgroup *iolimitcg; + + iolimitcg = kzalloc(sizeof(struct iolimit_cgroup), GFP_KERNEL); + if (!iolimitcg) + return ERR_PTR(-ENOMEM); + + atomic64_set(&iolimitcg->switching, 0); + + atomic64_set(&iolimitcg->write_limit, 0); + iolimitcg->write_part_nbyte = 0; + iolimitcg->write_already_used = 0; +// init_timer(&iolimitcg->write_timer); +// iolimitcg->write_timer.data = (unsigned long)iolimitcg; +// iolimitcg->write_timer.function = write_timer_handler; + timer_setup(&iolimitcg->write_timer, write_timer_handler, TIMER_DEFERRABLE); + spin_lock_init(&iolimitcg->write_lock); + init_waitqueue_head(&iolimitcg->write_wait); + + atomic64_set(&iolimitcg->read_limit, 0); + iolimitcg->read_part_nbyte = 0; + iolimitcg->read_already_used = 0; +// init_timer(&iolimitcg->read_timer); +// iolimitcg->read_timer.data = (unsigned long)iolimitcg; +// iolimitcg->read_timer.function = read_timer_handler; + timer_setup(&iolimitcg->read_timer, read_timer_handler, TIMER_DEFERRABLE); + spin_lock_init(&iolimitcg->read_lock); + init_waitqueue_head(&iolimitcg->read_wait); + if (!iolimit_enable_registered && !proc_create("iolimit_enable", 0644, NULL, + &iolimit_enable_ops)){ + pr_err("%s : Failed to register proc interface\n", __func__); + } else { + iolimit_enable_registered = true; + } + pr_info("IOLimit Debug:%s\n", __func__); + return &iolimitcg->css; +} + +static void iolimit_css_free(struct cgroup_subsys_state *css) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + + del_timer_sync(&iolimitcg->write_timer); + del_timer_sync(&iolimitcg->read_timer); + kfree(css_iolimit(css)); +} + +static s64 iolimit_switching_read(struct cgroup_subsys_state *css, struct cftype *cft) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + + return atomic64_read(&iolimitcg->switching); +} + +static int iolimit_switching_write(struct cgroup_subsys_state *css, struct cftype *cft, s64 switching) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + int err = 0; + + if (switching != 0 && switching != 1) { + err = -EINVAL; + goto out; + } + atomic64_set(&iolimitcg->switching, switching); + if (switching == 0) { + wake_up_all(&iolimitcg->write_wait); + del_timer_sync(&iolimitcg->write_timer); + + wake_up_all(&iolimitcg->read_wait); + del_timer_sync(&iolimitcg->read_timer); + } else if (switching == 1) { + mod_timer(&iolimitcg->write_timer, jiffies + HZ / 8); + iolimitcg->write_already_used = iolimitcg->write_part_nbyte; + + mod_timer(&iolimitcg->read_timer, jiffies + HZ / 8); + iolimitcg->read_already_used = iolimitcg->read_part_nbyte; + } +out: + return err; +} + +static s64 writeiolimit_read(struct cgroup_subsys_state *css, struct cftype *cft) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + + return atomic64_read(&iolimitcg->write_limit); +} + +static int writeiolimit_write(struct cgroup_subsys_state *css, struct cftype *cft, s64 limit) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + int err = 0; + + if (limit <= 0) { + err = -EINVAL; + goto out; + } + + atomic64_set(&iolimitcg->write_limit, limit); + spin_lock_bh(&iolimitcg->write_lock); + iolimitcg->write_part_nbyte = limit / 8; + spin_unlock_bh(&iolimitcg->write_lock); +out: + return err; +} + +static s64 readiolimit_read(struct cgroup_subsys_state *css, struct cftype *cft) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + + return atomic64_read(&iolimitcg->read_limit); +} + +static int readiolimit_write(struct cgroup_subsys_state *css, struct cftype *cft, + s64 limit) +{ + struct iolimit_cgroup *iolimitcg = css_iolimit(css); + int err = 0; + + if (limit <= 0) { + err = -EINVAL; + goto out; + } + + atomic64_set(&iolimitcg->read_limit, limit); + spin_lock_bh(&iolimitcg->read_lock); + iolimitcg->read_part_nbyte = limit / 8; + spin_unlock_bh(&iolimitcg->read_lock); +out: + return err; +} + +static void iolimit_attach(struct cgroup_taskset *tset) +{ + struct task_struct *task; + struct cgroup_subsys_state *dst_css; + + cgroup_taskset_for_each(task, dst_css, tset) + wake_up_process(task); +} + +static struct cftype iolimit_files[] = { + { + .name = "switching", + .flags = CFTYPE_NOT_ON_ROOT, + .read_s64 = iolimit_switching_read, + .write_s64 = iolimit_switching_write, + }, + { + .name = "write_limit", + .flags = CFTYPE_NOT_ON_ROOT, + .read_s64 = writeiolimit_read, + .write_s64 = writeiolimit_write, + }, + { + .name = "read_limit", + .flags = CFTYPE_NOT_ON_ROOT, + .read_s64 = readiolimit_read, + .write_s64 = readiolimit_write, + }, + {} +}; + +struct cgroup_subsys iolimit_cgrp_subsys = { + .css_alloc = iolimit_css_alloc, + .css_free = iolimit_css_free, + .attach = iolimit_attach, + .legacy_cftypes = iolimit_files, +}; diff --git a/drivers/oneplus/kernel/panic_flush.c b/drivers/oneplus/kernel/panic_flush.c new file mode 100644 index 0000000000000000000000000000000000000000..ba5c98f27a13cf6adf1f85cf734bb092ae79824b --- /dev/null +++ b/drivers/oneplus/kernel/panic_flush.c @@ -0,0 +1,154 @@ +/*********************************************************** +** File: - panic_flush.c +** Description: code to flush device cache in panic +** +** Version: 1.0 +** Date: 2019/08/27 +** Activity: [ITN-14106] +****************************************************************/ + +#define DEBUG +#include +#include +#include +#include +#include + +#define PANIC_FLUSH_POLL_MS (10) +struct panic_flush_control { + struct task_struct *flush_thread; + wait_queue_head_t flush_wq; + atomic_t flush_issuing; + atomic_t flush_issued; + atomic_t flush_circled; +}; + +static struct panic_flush_control *pfc; +static void panic_issue_flush(struct super_block *sb ,void *arg) +{ + int ret = -1; + int *flush_count = (int *)arg; + if (!(sb->s_flags & MS_RDONLY) && NULL != sb->s_bdev) { + ret = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); + } + if (!ret) { + (*flush_count)++; + pr_emerg("blkdev_issue_flush before panic return %d\n", *flush_count); + } +} + +static int panic_flush_thread(void *data) +{ + int flush_count = 0; + int flush_count_circle = 0; +repeat: + if (kthread_should_stop()) + return 0; + + if (atomic_read(&pfc->flush_circled) > 0) + wait_event_timeout(pfc->flush_wq, kthread_should_stop() || atomic_read(&pfc->flush_issuing) > 0, msecs_to_jiffies(500)); + else + wait_event(pfc->flush_wq, kthread_should_stop() || atomic_read(&pfc->flush_issuing) > 0 || atomic_read(&pfc->flush_circled) > 0); + + if (atomic_read(&pfc->flush_issuing) > 0) { + iterate_supers(panic_issue_flush, &flush_count); + pr_emerg("Up to now, total %d panic_issue_flush_count\n", flush_count); + atomic_inc(&pfc->flush_issued); + atomic_dec(&pfc->flush_issuing); + } else if (atomic_read(&pfc->flush_circled) > 0) { + iterate_supers(panic_issue_flush, &flush_count_circle); + pr_emerg("Up to now, total %d panic_issue_flush_count_circled\n", flush_count_circle); + } + + goto repeat; +} + +int panic_flush_device_cache(int timeout) +{ + pr_emerg("%s\n", __func__); + if (!pfc) { + pr_emerg("%s: skip flush device cache\n", __func__); + return timeout; + } + + if (atomic_inc_return(&pfc->flush_issuing) == 1 && + waitqueue_active(&pfc->flush_wq)) { + pr_emerg("%s: flush device cache\n", __func__); + atomic_set(&pfc->flush_issued, 0); + wake_up(&pfc->flush_wq); + while (timeout > 0 && atomic_read(&pfc->flush_issued) == 0) { + mdelay(PANIC_FLUSH_POLL_MS); + timeout -= PANIC_FLUSH_POLL_MS; + } + pr_emerg("%s: remaining timeout = %d\n", __func__, timeout); + } + return timeout; +} +EXPORT_SYMBOL(panic_flush_device_cache); + +void panic_flush_device_cache_circled_on(void) +{ + pr_emerg("%s\n", __func__); + if (!pfc) { + pr_emerg("%s: skip flush device cache\n", __func__); + return; + } + + if (atomic_inc_return(&pfc->flush_circled) == 1 && + waitqueue_active(&pfc->flush_wq)) { + pr_emerg("%s: flush device cache circle on\n", __func__); + wake_up(&pfc->flush_wq); + } +} +EXPORT_SYMBOL(panic_flush_device_cache_circled_on); + +void panic_flush_device_cache_circled_off(void) +{ + pr_emerg("%s\n", __func__); + if (!pfc) { + pr_emerg("%s: skip flush device cache\n", __func__); + return; + } + atomic_set(&pfc->flush_circled, 0); + pr_emerg("%s: flush device cache circle off\n", __func__); +} +EXPORT_SYMBOL(panic_flush_device_cache_circled_off); + +static int __init create_panic_flush_control(void) +{ + int err = 0; + pr_debug("%s\n", __func__); + pfc = kzalloc(sizeof(*pfc), GFP_KERNEL); + if (!pfc) { + pr_err("%s: fail to allocate memory\n", __func__); + return -ENOMEM; + } + + init_waitqueue_head(&pfc->flush_wq); + atomic_set(&pfc->flush_issuing, 0); + atomic_set(&pfc->flush_issued, 0); + atomic_set(&pfc->flush_circled, 0); + pfc->flush_thread = kthread_run(panic_flush_thread, pfc, "panic_flush"); + if (IS_ERR(pfc->flush_thread)) { + err = PTR_ERR(pfc->flush_thread); + kfree(pfc); + pfc = NULL; + } + return err; +} + +static void __exit destroy_panic_flush_control(void) +{ + pr_debug("%s\n", __func__); + if (pfc && pfc->flush_thread) { + pr_debug("%s: stop panic_flush thread\n", __func__); + kthread_stop(pfc->flush_thread); + kfree(pfc); + pfc = NULL; + } +} +module_init(create_panic_flush_control); +module_exit(destroy_panic_flush_control); +MODULE_DESCRIPTION("ONEPLUS panic flush control"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/oneplus/misc/Kconfig b/drivers/oneplus/misc/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..a725b95be99e18a2432e52690e3322cf89539a6e --- /dev/null +++ b/drivers/oneplus/misc/Kconfig @@ -0,0 +1,62 @@ +config OEM_FORCE_DUMP + default n + bool "OEM force dump function, it will enable goto the force dump" + +config PARAM_READ_WRITE + bool "Param partition read/write support" + default n + help + if you want to read/write the param partition in kernel, + then you must say Y here. +config PROJECT_INFO + bool "detect project info" + default n + help + detect projcet info If unsure, say n. + +config OEM_BOOT_MODE + bool "detect oem boot mode" + default n + help + detect oem boot mode If unsure, say y. + +config RF_CABLE_DETECT + bool "detect RF cable connection" + help + detect RF cable connection for different RF configuration + To compile this driver as a module, choose M here: the module + will be called RF cable. + If unsure, say N. + +config PSTORE_DEVICE_INFO + bool "Log user space messages" + depends on PSTORE + help + add device_info.txt for ramdump. + + If unsure, say N. + +config BOOTLOADER_LOG + tristate "show bootloader log" + depends on OF + default y + help + show bootloader log in kernel + +config WB_KERNEL_LOG + tristate "reserve kernel log to partition driver" + default n + + +config GPIO_SWITCH + tristate "use gpio swith" + default y + help + we can use gpio switch set gpio out high or low + +config REGULATOR_DEMO + tristate "use regultor demo" + default y + help + we can use regulator demo to control regulator + diff --git a/drivers/oneplus/misc/Makefile b/drivers/oneplus/misc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a859bfc15c6676ef806064d648a3063d758a5d7c --- /dev/null +++ b/drivers/oneplus/misc/Makefile @@ -0,0 +1,10 @@ +obj-$(CONFIG_OEM_FORCE_DUMP) += oem_force_dump.o +obj-$(CONFIG_PARAM_READ_WRITE) += param_read_write.o +obj-$(CONFIG_PROJECT_INFO) += project_info.o +obj-$(CONFIG_OEM_BOOT_MODE) += boot_mode.o +obj-$(CONFIG_RF_CABLE_DETECT) += op_rf_cable_monitor.o +obj-$(CONFIG_PSTORE_DEVICE_INFO) += device_info.o +obj-$(CONFIG_BOOTLOADER_LOG) += bootloader_log.o +obj-$(CONFIG_WB_KERNEL_LOG) += wb_kernel_log.o +obj-$(CONFIG_GPIO_SWITCH) += gpio_switch.o +obj-$(CONFIG_REGULATOR_DEMO) += regulator_demo.o diff --git a/drivers/oneplus/misc/boot_mode.c b/drivers/oneplus/misc/boot_mode.c new file mode 100644 index 0000000000000000000000000000000000000000..abdcf5c4f6e97bc57b5d2038d965790c8fc142df --- /dev/null +++ b/drivers/oneplus/misc/boot_mode.c @@ -0,0 +1,174 @@ +#include +#include +#include + +static enum oem_boot_mode boot_mode = MSM_BOOT_MODE_NORMAL; +int oem_project = 0; +int small_board_1_absent = 0; +int small_board_2_absent = 0; +int hw_version = 0; +int rf_version = 0; +int prj_version = 0; + +char *enum_ftm_mode[] = {"normal", + "fastboot", + "recovery", + "aging", + "ftm_at", + "ftm_rf", + "charger" +}; + +enum oem_boot_mode get_boot_mode(void) +{ + return boot_mode; +} +EXPORT_SYMBOL(get_boot_mode); + +static int __init boot_mode_init(char *str) +{ + + pr_info("boot_mode_init %s\n", str); + + if (str) { + if (strncmp(str, "ftm_at", 6) == 0) + boot_mode = MSM_BOOT_MODE_FACTORY; + else if (strncmp(str, "ftm_rf", 6) == 0) + boot_mode = MSM_BOOT_MODE_RF; + else if (strncmp(str, "ftm_recovery", 12) == 0) + boot_mode = MSM_BOOT_MODE_RECOVERY; + else if (strncmp(str, "ftm_aging", 9) == 0) + boot_mode = MSM_BOOT_MODE_AGING; + } + + pr_info("kernel boot_mode = %s[%d]\n", + enum_ftm_mode[boot_mode], boot_mode); + return 0; +} +__setup("androidboot.ftm_mode=", boot_mode_init); + +static int __init boot_mode_init_normal(void) +{ + char *substrftm = strnstr(boot_command_line, + "androidboot.ftm_mode=", strlen(boot_command_line)); + char *substrnormal = strnstr(boot_command_line, + "androidboot.mode=", strlen(boot_command_line)); + char *substrftmstr = NULL; + char *substrnormalstr = NULL; + + substrftmstr = substrftm + strlen("androidboot.ftm_mode="); + substrnormalstr = substrnormal + strlen("androidboot.mode="); + + if (substrftm != NULL && substrftmstr != NULL) { + + } else if (substrnormal != NULL && substrnormalstr != NULL) { + if (strncmp(substrnormalstr, "recovery", 8) == 0) + boot_mode = MSM_BOOT_MODE_RECOVERY; + else if (strncmp(substrnormalstr, "charger", 7) == 0) + boot_mode = MSM_BOOT_MODE_CHARGE; + } + + pr_info("kernel normal boot_mode = %s[%d]\n", + enum_ftm_mode[boot_mode], boot_mode); + + return 0; +} +arch_initcall(boot_mode_init_normal); + +int get_oem_project(void) +{ + return oem_project; +} +EXPORT_SYMBOL(get_oem_project); + +static int __init get_oem_project_init(char *str) +{ + oem_project=simple_strtol(str, NULL, 0); + pr_info("kernel oem_project %d\n",oem_project); + return 0; +} + +__setup("androidboot.project_name=", get_oem_project_init); + +static int __init get_recovery_reason(char *str) +{ + pr_info("recovery mode reason:%s\n", str); + return 0; +} + +__setup("androidboot.recoveryreason=", get_recovery_reason); + +/*wireless*/ +int get_small_board_1_absent(void) +{ + return small_board_1_absent; +} +EXPORT_SYMBOL(get_small_board_1_absent); + +static int __init get_small_board_1_absent_init(char *str) +{ + small_board_1_absent=simple_strtol(str, NULL, 0); + pr_info("kernel small_board_1_absent %d\n",small_board_1_absent); + return 0; +} +__setup("androidboot.small_board_1_absent=", get_small_board_1_absent_init); + +/*camera*/ +int get_small_board_2_absent(void) +{ + return small_board_2_absent; +} +EXPORT_SYMBOL(get_small_board_2_absent); + +static int __init get_small_board_2_absent_init(char *str) +{ + small_board_2_absent=simple_strtol(str, NULL, 0); + pr_info("kernel small_board_2_absent %d\n",small_board_2_absent); + return 0; +} +__setup("androidboot.small_board_2_absent=", get_small_board_2_absent_init); + +int get_hw_board_version(void) +{ + return hw_version; +} +EXPORT_SYMBOL(get_hw_board_version); + +static int __init get_hw_version_init(char *str) +{ + hw_version=simple_strtol(str, NULL, 0); + pr_info("kernel get_hw_version %d\n",hw_version); + return 0; +} + +__setup("androidboot.hw_version=", get_hw_version_init); + +int get_rf_version(void) +{ + return rf_version; +} +EXPORT_SYMBOL(get_rf_version); + +static int __init get_rf_version_init(char *str) +{ + rf_version=simple_strtol(str, NULL, 0); + pr_info("kernel get_rf_version %d\n",rf_version); + return 0; +} + +__setup("androidboot.rf_version=", get_rf_version_init); + +int get_prj_version(void) +{ + return prj_version; +} +EXPORT_SYMBOL(get_prj_version); + +static int __init get_prj_version_init(char *str) +{ + prj_version=simple_strtol(str, NULL, 0); + pr_info("kernel get_prj_version %d\n",prj_version); + return 0; +} + +__setup("androidboot.prj_version=", get_prj_version_init); diff --git a/drivers/oneplus/misc/bootloader_log.c b/drivers/oneplus/misc/bootloader_log.c new file mode 100644 index 0000000000000000000000000000000000000000..c4c23810cbf345d5d04b7d32bce51c758f7caefb --- /dev/null +++ b/drivers/oneplus/misc/bootloader_log.c @@ -0,0 +1,229 @@ +/* Copyright (c) 2016 OnePlus. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct bootloader_log_platform_data { + unsigned long mem_size; + unsigned long mem_address; + unsigned int mem_type; + +}; + +struct bootloader_log_ram_zone_t { + phys_addr_t paddr; + size_t size; + void *vaddr; + char *buffer; + +} bootloader_log_ram_zone; + +static int bootloader_log_proc_show(struct seq_file *m, void *v) +{ + bootloader_log_ram_zone.buffer[bootloader_log_ram_zone.size - 1] = '\0'; + seq_printf(m, "%s\n", bootloader_log_ram_zone.buffer); + return 0; +} + +static int bootloader_log_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, bootloader_log_proc_show, NULL); +} + +static const struct file_operations bootloader_log_proc_fops = { + .open = bootloader_log_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int proc_bootloader_log_init(void) +{ + proc_create("bootloader_log", 0, NULL, &bootloader_log_proc_fops); + return 0; +} + + +static int __init of_bootloader_log_platform_data(struct device_node *node, + struct bootloader_log_platform_data *pdata) +{ + const u32 *addr; + u64 size; + struct device_node *pnode; + + memset(pdata, 0, sizeof(*pdata)); + + pnode = of_parse_phandle(node, "linux,contiguous-region", 0); + if (pnode) { + addr = of_get_address(pnode, 0, &size, NULL); + if (!addr) { + pr_err("failed to parse the bootloader log memory address\n"); + of_node_put(pnode); + return -EINVAL; + } + pdata->mem_address = of_read_ulong(addr, 2); + pdata->mem_size = (unsigned long) size; + of_node_put(pnode); + } else { + pr_err("mem reservation for bootloader log not present\n"); + return -EINVAL; + } + + return 0; +} + +static void *persistent_ram_vmap(phys_addr_t start, size_t size) +{ + struct page **pages; + phys_addr_t page_start; + unsigned int page_count; + pgprot_t prot; + unsigned int i; + void *vaddr; + + page_start = start - offset_in_page(start); + page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); + + prot = pgprot_noncached(PAGE_KERNEL); + + + pages = kmalloc_array(page_count, sizeof(struct page *), GFP_KERNEL); + if (!pages) + return NULL; + + for (i = 0; i < page_count; i++) { + phys_addr_t addr = page_start + i * PAGE_SIZE; + + pages[i] = pfn_to_page(addr >> PAGE_SHIFT); + } + vaddr = vmap(pages, page_count, VM_MAP, prot); + kfree(pages); + + return vaddr; +} + + +static int persistent_ram_buffer_map(phys_addr_t start, size_t size, + struct bootloader_log_ram_zone_t *blrz) +{ + blrz->paddr = start; + blrz->size = size; + + blrz->vaddr = persistent_ram_vmap(start, size); + + if (!blrz->vaddr) { + pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__, + (unsigned long long)size, (unsigned long long)start); + return -ENOMEM; + } + + blrz->buffer = blrz->vaddr + offset_in_page(start); + return 0; +} + + +static int bootloader_log_probe(struct platform_device *pdev) +{ + struct bootloader_log_platform_data *pdata = pdev->dev.platform_data; + struct bootloader_log_platform_data of_pdata; + + phys_addr_t paddr; + int err = -EINVAL; + + pr_err("bootloader_log_probe\n"); + + if (pdev->dev.of_node) { + if (of_bootloader_log_platform_data(pdev->dev.of_node, + &of_pdata)) { + pr_err("Invalid bootloader log device tree data\n"); + goto fail_out; + } + pdata = &of_pdata; + } + + if (!pdata->mem_size) { + pr_err("memory size and record size must be non-zero\n"); + goto fail_out; + } + + paddr = pdata->mem_address; + + + err = persistent_ram_buffer_map(paddr, pdata->mem_size, + &bootloader_log_ram_zone); + if (err) + goto fail_out; + + proc_bootloader_log_init(); + + + pr_info("bootloader_log!\n"); + + return 0; + +fail_out: + pr_err("bootloader_log, fail_out!\n"); + return err; +} + +static int __exit bootloader_log_remove(struct platform_device *pdev) +{ + return -EBUSY; +} + +static const struct of_device_id bootloader_log_of_match[] = { + { .compatible = "bootloader_log", }, + { }, +}; +MODULE_DEVICE_TABLE(of, bootloader_log_of_match); + +static struct platform_driver bootloader_log_driver = { + .probe = bootloader_log_probe, + .remove = __exit_p(bootloader_log_remove), + .driver = { + .name = "bootloader_log", + .owner = THIS_MODULE, + .of_match_table = bootloader_log_of_match, + }, +}; + + +static int __init bootloader_log_init(void) +{ + return platform_driver_register(&bootloader_log_driver); +} +postcore_initcall(bootloader_log_init); + +static void __exit bootloader_log_exit(void) +{ + platform_driver_unregister(&bootloader_log_driver); + +} +module_exit(bootloader_log_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("software@oneplus.cn>"); + diff --git a/drivers/oneplus/misc/device_info.c b/drivers/oneplus/misc/device_info.c new file mode 100644 index 0000000000000000000000000000000000000000..fa70ebd1cb06d1bce0efb00b1346d036e31a7b3b --- /dev/null +++ b/drivers/oneplus/misc/device_info.c @@ -0,0 +1,200 @@ + +#include + +#include + +#include + +#include +#include + +#include +#include "../../../fs/pstore/internal.h" +#include +#include + +extern struct pstore_info *psinfo; + +#define MAX_ITEM 5 +#define MAX_LENGTH 32 + +enum +{ + serialno = 0, + hw_version, + rf_version, + ddr_manufacture_info, + pcba_number +}; + +char oem_serialno[16]; +char oem_hw_version[3]; +char oem_rf_version[3]; +char oem_ddr_manufacture_info[16]; +char oem_pcba_number[30]; + +const char cmdline_info[MAX_ITEM][MAX_LENGTH] = +{ + "androidboot.serialno=", + "androidboot.hw_version=", + "androidboot.rf_version=", + "ddr_manufacture_info=", + "androidboot.pcba_number=", +}; + + + +static int __init device_info_init(void) +{ + int i, j; + char *substr, *target_str; + + for(i=0; idata; + struct pstore_record record; + + if (psinfo == NULL) + return; + + size = cxt->device_info_size; + + pstore_record_init(&record, psinfo); + record.type = PSTORE_TYPE_DEVICE_INFO; + record.buf = psinfo->buf; + record.size = size; + + oldsize = psinfo->bufsize; + + + if (size > psinfo->bufsize) + size = psinfo->bufsize; + + memset(record.buf, ' ', size); + psinfo->write(&record); + + psinfo->bufsize = oldsize ; +} + +static void pstore_write_device_info(const char *s, unsigned c) +{ + + const char *e = s + c; + + if (psinfo == NULL) + return; + + while (s < e) { + struct pstore_record record; + pstore_record_init(&record, psinfo); + record.type = PSTORE_TYPE_DEVICE_INFO; + + if (c > psinfo->bufsize) + c = psinfo->bufsize; + + record.buf = (char *)s; + record.size = c; + psinfo->write(&record); + s += c; + c = e - s; + } + +} + +static void write_device_info(const char *key, const char *value) +{ + pstore_write_device_info(key, strlen(key)); + pstore_write_device_info(": ", 2); + pstore_write_device_info(value, strlen(value)); + pstore_write_device_info("\r\n", 2); +} + +static int __init init_device_info(void) +{ + char *ptr = NULL; + ptr = oem_pcba_number; + get_param_by_index_and_offset(0, 0x4D, ptr, 28); + + pstore_device_info_init(); + + device_info_init(); + + write_device_info("hardware version", oem_hw_version); + write_device_info("rf version", oem_rf_version); + write_device_info("modem baseline", is_na_board() ? "NA":"NON_NA" ); + write_device_info("ddr manufacturer", oem_ddr_manufacture_info); + write_device_info("pcba number", oem_pcba_number); + write_device_info("serial number", oem_serialno); + + scnprintf(oem_serialno, sizeof(oem_serialno), "%x", socinfo_get_serial_number()); + write_device_info("socinfo serial_number", oem_serialno); + + write_device_info("kernel version", linux_banner); + write_device_info("boot command", saved_command_line); + + return 0; +} + +late_initcall(init_device_info); + +void save_dump_reason_to_device_info(char *reason) { + write_device_info("dump reason is ", reason); +} diff --git a/drivers/oneplus/misc/gpio_switch.c b/drivers/oneplus/misc/gpio_switch.c new file mode 100644 index 0000000000000000000000000000000000000000..cf83295745ff140a889f76f266ffcaaa26955a86 --- /dev/null +++ b/drivers/oneplus/misc/gpio_switch.c @@ -0,0 +1,303 @@ +/* + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "../../../fs/proc/internal.h" +#include + +#define DRV_NAME "gpio_switch" +#define GPIO_STATE_ACTIVE "gpio_switch_pin_active" +#define GPIO_STATE_SUSPEND "gpio_switch_pin_suspend" + +#define MAX_GPIO_ID_LEN 24 + +enum GPIO_GPIO{ + GPIO_MIN_NUM, + GPIO_065=1, + GPIO_066, + GPIO_073, + GPIO_074, + GPIO_077, + GPIO_078, + PM8009_01, + PM8009_02, + PM8009_04, + GPIO_MAX_NUM, +}; + +struct gpio_list { + int gpio; + char name[MAX_GPIO_ID_LEN]; +}; + +static struct gpio_list gpio_lists[]= +{ + {GPIO_MIN_NUM,"GPIO_MIN_NUM"}, + {GPIO_065, "GPIO_065"}, + {GPIO_066, "GPIO_066"}, + {GPIO_073, "GPIO_073"}, + {GPIO_074, "GPIO_074"}, + {GPIO_077, "GPIO_077"}, + {GPIO_078, "GPIO_078"}, + {PM8009_01, "PM8009_01"}, + {PM8009_02, "PM8009_02"}, + {PM8009_04, "PM8009_04"}, + {GPIO_MAX_NUM,"GPIO_MAX_NUM"} +}; + +struct gpio_dev_data { + int gpios[GPIO_MAX_NUM]; + struct device *dev; + int gpio_state; + struct pinctrl *gpio_pinctrl; + struct pinctrl_state *gpio_pinctrl_active; + struct pinctrl_state *gpio_pinctrl_suspend; +}; + +static struct gpio_dev_data *gpio_data; + +static DEFINE_MUTEX(sem); +static int gpio_state_show(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "%d\n", gpio_data->gpio_state); + return 0; +} + +static ssize_t gpio_state_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ + + int gpio_state; + int gpio; + int enable; + char buf[10]={0}; + + if (!gpio_data) { + return -EFAULT; + } + mutex_lock(&sem); + + if( copy_from_user(buf, buffer, sizeof (buf)) ){ + return count; + } + + sscanf(buf, "%d", &gpio_state); + + gpio = gpio_state/10; + enable = gpio_state%10; + printk("gpio_state before(%d),current(%d) gpio_index=(%d),gpionum=%d enable=(%d)\n",gpio_data->gpio_state,gpio_state,gpio,gpio_data->gpios[gpio],!!enable); + + gpio_data->gpio_state=gpio_state; + + if(gpio > GPIO_MIN_NUM && gpio < GPIO_MAX_NUM) + { + if(gpio_is_valid(gpio_data->gpios[gpio])) + { + gpio_direction_output(gpio_data->gpios[gpio],!!enable); + gpio_state = gpio_get_value(gpio_data->gpios[gpio]); + printk("gpio_name (%d) enable=(%d) ,get_gpio=%d \n",gpio_data->gpios[gpio],!!enable,gpio_state); + } + } + + mutex_unlock(&sem); + return count; +} + +static int gpio_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, gpio_state_show, gpio_data); +} + +static const struct file_operations gpio_state_proc_fops = { + .owner = THIS_MODULE, + .open = gpio_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = gpio_state_write, +}; + +static int gpio_dev_get_devtree_pdata(struct device *dev) +{ + struct device_node *node; + int i=0; + node = dev->of_node; + if (!node) + return -EINVAL; + + for (i = 1; i < GPIO_MAX_NUM; i++) { + gpio_data->gpios[i] = of_get_gpio(node, i-1); + pr_err("i= %d gpio=: %d\n", i,gpio_data->gpios[i]); + if (gpio_data->gpios[i] < 0) + pr_warn("%s: Fail to get 5wire gpio: %d\n",__func__, i); + } + return 0; +} + +static int gpio_pinctrl_init(struct platform_device *pdev) +{ + int retval; + printk("%s \n",__func__); + //Get pinctrl if target uses pinctrl + gpio_data->gpio_pinctrl = devm_pinctrl_get(&(pdev->dev)); + if (IS_ERR_OR_NULL(gpio_data->gpio_pinctrl)) { + retval = PTR_ERR(gpio_data->gpio_pinctrl); + dev_dbg(&pdev->dev,"Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + gpio_data->gpio_pinctrl_active + = pinctrl_lookup_state(gpio_data->gpio_pinctrl, + GPIO_STATE_ACTIVE); + if (IS_ERR_OR_NULL(gpio_data->gpio_pinctrl_active)) { + retval = PTR_ERR(gpio_data->gpio_pinctrl_active); + dev_err(&pdev->dev, + "Can not lookup %s pinstate %d\n", + GPIO_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + gpio_data->gpio_pinctrl_suspend + = pinctrl_lookup_state(gpio_data->gpio_pinctrl, + GPIO_STATE_SUSPEND); + if (IS_ERR_OR_NULL(gpio_data->gpio_pinctrl_suspend)) { + retval = PTR_ERR(gpio_data->gpio_pinctrl_suspend); + dev_err(&pdev->dev, + "Can not lookup %s pinstate %d\n", + GPIO_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + if ( gpio_data->gpio_pinctrl) { + + retval = pinctrl_select_state(gpio_data->gpio_pinctrl, + gpio_data->gpio_pinctrl_active); + if (retval < 0) { + dev_err(&pdev->dev, + "failed to select pin to active state"); + } + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(gpio_data->gpio_pinctrl); +err_pinctrl_get: + gpio_data->gpio_pinctrl = NULL; + return retval; +} + + +static int gpio_dev_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int error=0; + int i=0,j=0; + printk(KERN_ERR"%s\n",__func__); + + gpio_data = kzalloc(sizeof(struct gpio_dev_data), GFP_KERNEL); + gpio_data->dev = dev; + + //parse device tree node + error = gpio_dev_get_devtree_pdata(dev); + + if (error) { + dev_err(dev, "parse device tree fail!!!\n"); + goto err_gpio_dev_register; + } + + if (!proc_create_data("demogpio", 0666, NULL, &gpio_state_proc_fops, gpio_data)) { + error = -ENOMEM; + goto err_gpio_dev_register; + } + + error= gpio_pinctrl_init(pdev); + if(error < 0) + { + printk(KERN_ERR "%s: gpio_pinctrl_init, err=%d", __func__, error); + goto err_set_gpio; + } + + for (i = 1; i < GPIO_MAX_NUM; i++) { + + error =gpio_request(gpio_data->gpios[i],gpio_lists[i].name); + if(error < 0) + { + printk(KERN_ERR "%s: gpio_request, err=%d", __func__, error); + goto err_set_gpio; + } + error = gpio_direction_output(gpio_data->gpios[i],0); + if(error < 0) + { + printk(KERN_ERR "%s: gpio_direction_output, err=%d", __func__, error); + goto err_set_gpio; + } + } + + printk("%s ok!\n",__func__); + return 0; + +err_set_gpio: + for (j = i-1; i > GPIO_MIN_NUM; i--) { + if (gpio_is_valid(gpio_data->gpios[i])) + gpio_free(gpio_data->gpios[i]); + } +err_gpio_dev_register: + kfree(gpio_data); + return error; +} + +static int gpio_dev_remove(struct platform_device *pdev) +{ + int j=0; + printk("%s\n",__func__); + for (j = GPIO_MAX_NUM-1; j > GPIO_MIN_NUM; j--) { + if (gpio_is_valid(gpio_data->gpios[j])) + gpio_free(gpio_data->gpios[j]); + } + + kfree(gpio_data); + + return 0; +} + +static struct of_device_id gpio_of_match[] = { + { .compatible = "oneplus,gpio_switch", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_of_match); + + +static struct platform_driver gpio_dev_driver = { + .probe = gpio_dev_probe, + .remove = gpio_dev_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gpio_of_match), + }, +}; +module_platform_driver(gpio_dev_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("gpio switch by gpio's driver"); + diff --git a/drivers/oneplus/misc/gpio_switch.txt b/drivers/oneplus/misc/gpio_switch.txt new file mode 100644 index 0000000000000000000000000000000000000000..9649dbf1f1d64ce77c3613c4de0c28cfed6b05f6 --- /dev/null +++ b/drivers/oneplus/misc/gpio_switch.txt @@ -0,0 +1,27 @@ +&pm8009_gpios { + pm8009_gpios_pinctl: pm8009_gpios_pinctl { + + pm8009_gpios01: pm8009_gpios01 { + pins = "gpio1"; + function = "normal"; + power-source = <1>; + }; + pm8009_gpios02: pm8009_gpios02{ + pins = "gpio2"; + function = "normal"; + power-source = <1>; + }; + }; +}; + +&soc { + gpio_switch { + compatible = "oneplus,gpio_switch"; + gpios = <&pm8009_gpios 1 0>, + <&pm8009_gpios 2 0>; + + pinctrl-names = "gpio_switch_pin_active"; + pinctrl-0 = <&pm8009_gpios01 &pm8009_gpios02 &pm8009_gpios04>; + }; +}; + diff --git a/drivers/oneplus/misc/oem_force_dump.c b/drivers/oneplus/misc/oem_force_dump.c new file mode 100644 index 0000000000000000000000000000000000000000..7b9c30758e830336bb37d7c7122e7da37fb1d35b --- /dev/null +++ b/drivers/oneplus/misc/oem_force_dump.c @@ -0,0 +1,440 @@ +/* + * oem_force_dump.c + * + * drivers supporting debug functions for Oneplus device. + * + * hefaxi@filesystems, 2015/07/03. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../kernel/sched/sched.h" + +struct sock *nl_sk; +static int fd = -1; +static struct workqueue_struct *smg_workwq; +static struct work_struct smg_work; + +#define MAX_MSGSIZE 1024 +#define SIGNAL_DEBUGGER (SIGRTMIN + 3) +static int message_state = -1; +enum key_stat_item pwr_status, vol_up_status; + +static bool find_task_by_name(struct task_struct *t, char *name) +{ + const struct cred *tcred = __task_cred(t); + + if (!strncmp(t->comm, name, TASK_COMM_LEN)) + return true; + if (!strncmp(t->comm, "Binder:", 7) && (t->group_leader->pid == t->pid) + && (tcred->uid.val == 1000) && (t->parent != 0 && !strcmp(t->parent->comm, "main"))) + return true; + + return false; +} + +void send_sig_to_get_trace(char *name) +{ + struct task_struct *g, *t; + + rcu_read_lock(); + for_each_process_thread(g, t) { + if (find_task_by_name(t, name)) { + do_send_sig_info(SIGQUIT, SEND_SIG_FORCED, t, PIDTYPE_TGID); + msleep(500); + goto out; + } + } +out: + rcu_read_unlock(); +} + + +void send_sig_to_get_tombstone(char *name) +{ + struct task_struct *p; + + rcu_read_lock(); + for_each_process(p) { + if (!strncmp(p->comm, name, TASK_COMM_LEN)) { + do_send_sig_info(SIGNAL_DEBUGGER, SEND_SIG_FORCED, p, PIDTYPE_TGID); + msleep(500); + break; + } + } + rcu_read_unlock(); +} + +void get_init_sched_info(void) +{ + struct task_struct *p, *t; + + for_each_process(p) { + if (p->pid == 1) + break; + } + + for_each_thread(p, t) + sched_show_task(t); + +} + +static void dump_task_info(char *status, struct task_struct *p, + bool dump_sched_info, bool dump_call_stack) +{ + if (p) { + pr_info("%s: %s(pid: %d)\n", status, p->comm, p->pid); +#ifdef CONFIG_SCHED_INFO + if (dump_sched_info) + pr_info("Exec_Started_at: %llu nsec, Last_Queued_at: %llu nsec, Prio: %d Preempt_count: %#x\n", + p->sched_info.last_arrival, + p->sched_info.last_queued, + p->prio, p->thread_info.preempt_count); +#else + if (dump_sched_info) + pr_info(" vrun: %lu arr: %lu sum_ex: %lu\n", + (unsigned long)p->se.vruntime, + (unsigned long)p->se.exec_start, + (unsigned long)p->se.sum_exec_runtime); + +#endif + if (dump_call_stack) + sched_show_task(p); + } else + pr_info("%s: None\n", status); +} + +static void dump_rq(struct rq *rq) +{ + dump_task_info("curr", rq->curr, false, false); + dump_task_info("idle", rq->idle, false, false); + dump_task_info("stop", rq->stop, false, false); +} + +static void dump_cfs_rq(struct cfs_rq *cfs_rq); + +static void dump_cgroup_state(char *status, struct sched_entity *se_p) +{ + struct task_struct *task; + struct cfs_rq *my_q = NULL; + unsigned int nr_running; + + if (!se_p) { + dump_task_info(status, NULL, false, false); + return; + } +#ifdef CONFIG_FAIR_GROUP_SCHED + my_q = se_p->my_q; +#endif + if (!my_q) { + task = container_of(se_p, struct task_struct, se); + dump_task_info(status, task, true, true); + return; + } + nr_running = my_q->nr_running; + pr_info("%s: %d process is grouping\n", + status, nr_running); + dump_cfs_rq(my_q); +} + +static void dump_cfs_node_func(struct rb_node *node) +{ + struct sched_entity *se_p = container_of(node, struct sched_entity, + run_node); + + dump_cgroup_state("pend", se_p); +} + +static void dump_rb_walk_cfs(struct rb_root_cached *rb_root_cached_p) +{ + int max_walk = 200; + struct rb_node *leftmost = rb_root_cached_p->rb_leftmost; + struct rb_root *root = &rb_root_cached_p->rb_root; + struct rb_node *rb_node = rb_first(root); + + if (!leftmost) + return; + while (rb_node && max_walk--) { + dump_cfs_node_func(rb_node); + rb_node = rb_next(rb_node); + } +} + +static void dump_rt_rq(struct rt_rq *rt_rq) +{ + struct rt_prio_array *array = &rt_rq->active; + struct sched_rt_entity *rt_se; + int idx; + + pr_info("RT %d process is pending\n", rt_rq->rt_nr_running); + + if (bitmap_empty(array->bitmap, MAX_RT_PRIO)) + return; + + idx = sched_find_first_bit(array->bitmap); + while (idx < MAX_RT_PRIO) { + list_for_each_entry(rt_se, array->queue + idx, run_list) { + struct task_struct *p; + +#ifdef CONFIG_RT_GROUP_SCHED + if (rt_se->my_q) + continue; +#endif + + p = container_of(rt_se, struct task_struct, rt); + dump_task_info("pend", p, true, true); + } + idx = find_next_bit(array->bitmap, MAX_RT_PRIO, idx + 1); + } +} + +static void dump_cfs_rq(struct cfs_rq *cfs_rq) +{ + struct rb_root_cached *rb_root_cached_p = &cfs_rq->tasks_timeline; + + pr_info("CFS %d process is pending\n", cfs_rq->nr_running); + + dump_cgroup_state("curr", cfs_rq->curr); + dump_cgroup_state("next", cfs_rq->next); + dump_cgroup_state("last", cfs_rq->last); + dump_cgroup_state("skip", cfs_rq->skip); + dump_rb_walk_cfs(rb_root_cached_p); +} + +void dump_runqueue(void) +{ + int cpu; + struct rq *rq; + struct rt_rq *rt; + struct cfs_rq *cfs; + + pr_info("==================== RUNQUEUE STATE ====================\n"); + for_each_possible_cpu(cpu) { + rq = cpu_rq(cpu); + rt = &rq->rt; + cfs = &rq->cfs; + pr_info("CPU%d %d process is running\n", cpu, rq->nr_running); + dump_rq(rq); + dump_cfs_rq(cfs); + dump_rt_rq(rt); + } +} + +void compound_key_to_get_trace(char *name) +{ + if (pwr_status == KEY_PRESSED && vol_up_status == KEY_PRESSED) + send_sig_to_get_trace(name); +} + +void compound_key_to_get_tombstone(char *name) +{ + if (pwr_status == KEY_PRESSED && vol_up_status == KEY_PRESSED) + send_sig_to_get_tombstone(name); +} + + +/* + * the way goto force dump: + * 1. press the voluemup key and then relase it. + * 2. press the volumedown key and then relase it. + * 3. long press volumeup key, without release it. + * 4. press twice power key, and release it. + * 5. release the volumeup key. + * 6. presss the volumeup key, without release it. + * 7. press the power key. + * after those step, the device will goto the force dump. + */ +void oem_check_force_dump_key(unsigned int code, int value) +{ + static enum { NONE, STEP1, STEP2, STEP3, STEP4, STEP5, + STEP6, STEP7, STEP8, STEP9, STEP10, STEP11, STEP_DEBUG1} state = NONE; + + switch (state) { + case NONE: + if (code == KEY_VOLUMEUP && value) + state = STEP1; + else + state = NONE; + break; + case STEP1: + if (code == KEY_VOLUMEUP && !value) + state = STEP2; + else + state = NONE; + break; + case STEP2: + if (code == KEY_VOLUMEDOWN && value) + state = STEP3; + else + state = NONE; + break; + case STEP3: + if (code == KEY_VOLUMEDOWN && !value) + state = STEP4; + else + state = NONE; + break; + case STEP4: + if (code == KEY_VOLUMEUP && value) + state = STEP5; + else + state = NONE; + break; + case STEP5: + if (code == KEY_POWER && value) + state = STEP6; + else + state = NONE; + break; + case STEP6: + if (code == KEY_POWER && !value) + state = STEP7; + else + state = NONE; + break; + case STEP7: + if (code == KEY_POWER && value) + state = STEP8; + else + state = NONE; + break; + case STEP8: + if (code == KEY_POWER && !value) + state = STEP9; + else + state = NONE; + break; + case STEP9: + if (code == KEY_VOLUMEUP && !value) + state = STEP10; + else + state = NONE; + break; + case STEP10: + if (code == KEY_VOLUMEUP && value) + state = STEP11; + else if (code == KEY_VOLUMEDOWN && value) + state = STEP_DEBUG1; + else + state = NONE; + break; + case STEP11: + if (code == KEY_POWER && value) { + if (oem_get_download_mode()) + panic("Force Dump"); + } else + state = NONE; + break; + + case STEP_DEBUG1: + if (code == KEY_POWER && value) { + state = NONE; + } else if (code == KEY_VOLUMEDOWN && !value) { + message_state = 2; + queue_work(smg_workwq, &smg_work); + state = NONE; + } else + state = NONE; + break; + } +} + +static void send_msg_worker(struct work_struct *work) +{ + if (message_state == 1) + send_msg("Enable DEBUG!"); + else if (message_state == 2) { + pr_info("force oem serial\n"); + msm_serial_oem_init(); + send_msg("ENABLE_OEM_FORCE_SERIAL"); + } + message_state = 0; +} + +void send_msg_sync_mdm_dump(void) +{ + send_msg("FORCE_MDM_DUMP_SYNC"); +} + +void send_msg(char *message) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int len = NLMSG_SPACE(MAX_MSGSIZE); + + pr_info("%s,%s\n",__func__,message); + + if (!message || !nl_sk) + return; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return; + nlh = nlmsg_put(skb, 0, 0, 0, MAX_MSGSIZE, 0); + NETLINK_CB(skb).portid = 0; + NETLINK_CB(skb).dst_group = 0; + strlcpy(NLMSG_DATA(nlh), message, MAX_MSGSIZE); + netlink_unicast(nl_sk, skb, fd, MSG_DONTWAIT); +} + +void recv_nlmsg(struct sk_buff *skb) +{ + struct nlmsghdr *nlh = nlmsg_hdr(skb); + + if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) + return; + fd = nlh->nlmsg_pid; + pr_err("received:%s %d\n", (char *)NLMSG_DATA(nlh), fd); +} + +struct netlink_kernel_cfg nl_kernel_cfg = { + .groups = 0, + .flags = 0, + .input = recv_nlmsg, + .cb_mutex = NULL, + .bind = NULL, + .compare = NULL, +}; + +int op_netlink_init(void) +{ + nl_sk = netlink_kernel_create(&init_net, NETLINK_ADB, &nl_kernel_cfg); + if (!nl_sk) { + pr_err("%s: Create netlink socket error.\n", __func__); + return 1; + } + smg_workwq = create_singlethread_workqueue("oem_key_dump"); + if (!smg_workwq) { + pr_err("%s: Create oem_key_dump error.\n", __func__); + return 1; + } + INIT_WORK(&smg_work, send_msg_worker); + pr_err("%s\n", __func__); + return 0; +} + +static void op_netlink_exit(void) +{ + if (nl_sk != NULL) + sock_release(nl_sk->sk_socket); + if (smg_workwq != NULL) + destroy_workqueue(smg_workwq); + pr_err("%s\n", __func__); +} + +module_init(op_netlink_init); +module_exit(op_netlink_exit); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/misc/op_rf_cable_monitor.c b/drivers/oneplus/misc/op_rf_cable_monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..f52729a50cf0490128895af4dda339e337f10b6e --- /dev/null +++ b/drivers/oneplus/misc/op_rf_cable_monitor.c @@ -0,0 +1,625 @@ +/*For OEM project monitor RF cable connection status, + * and config different RF configuration + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RF_CABLE_STATE_ACTIVE "oem_rf_cable_active" + +static struct class *rf_uevent_class; +static struct device *rf_uevent_device; +static struct project_info *project_info_desc; + +#ifdef CONFIG_ARCH_LITO +#define CABLE_GPIO_NUM 3 +#else +#define CABLE_GPIO_NUM 4 +#endif + +struct cable_data { + int irq[CABLE_GPIO_NUM]; + int cable_gpio[CABLE_GPIO_NUM]; + int support_timer; + struct delayed_work work; + struct workqueue_struct *wqueue; + struct device *dev; + struct wakeup_source *wl; + int rf_v2; + int rf_v3; + int rf_v3_pre; + spinlock_t lock; + int enable; + int is_rf_factory_mode; + int gpio_state; + struct pinctrl *gpio_pinctrl; + struct pinctrl_state *gpio_pinctrl_active; + struct pinctrl_state *gpio_pinctrl_suspend; + bool connected; + bool uevent_feature; +}; +static struct cable_data *rf_cable_data; + +static char *cmdline_find_option(char *str) +{ + return strnstr(saved_command_line, str, strlen(saved_command_line)); +} + +int modify_rf_cable_smem_info(uint32 status) +{ + size_t size; + + project_info_desc = qcom_smem_get(QCOM_SMEM_HOST_ANY,SMEM_PROJECT_INFO, &size); + + if (IS_ERR_OR_NULL(project_info_desc)) + pr_err("%s: get project_info failure\n", __func__); + else { + project_info_desc->rf_v3 = status; + pr_err("%s: rf_cable: %d\n", + __func__, project_info_desc->rf_v3); + } + return 0; +} + +int modify_rf_v2_info(uint32 status) +{ + size_t size; + + project_info_desc = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_PROJECT_INFO, &size); + + if (IS_ERR_OR_NULL(project_info_desc)) + pr_err("%s: get project_info failure\n", __func__); + else { + project_info_desc->rf_v2 = status; + pr_err("%s: rf_cable: %d\n", + __func__, project_info_desc->rf_v3); + } + return 0; +} +int local_pow(int x,int y) +{ + int i = 0; + int val = 1; + for(i = 0; i< y; i++) + val = val*x; + + return val; +} + +int get_all_gpio_val(void) +{ + int i = 0; + int gpiostate = 0; + for(i = 0; i< CABLE_GPIO_NUM; i++) + gpiostate = gpiostate + (gpio_get_value(rf_cable_data->cable_gpio[i]) * local_pow(10, CABLE_GPIO_NUM - i - 1)); + /*only 19811 china and 19821 china use ANT6(gpio109)*/ + if((get_prj_version() == 12 && get_rf_version() == 11) + ||(get_prj_version() == 11 && get_rf_version() == 11) + ||(get_prj_version() == 14)) + return gpiostate; + else + return gpiostate - gpiostate % 10; +} + +static void irq_cable_enable(int enable) +{ + unsigned long flags; + int i = 0; + if (!rf_cable_data->support_timer) { + + spin_lock_irqsave(&rf_cable_data->lock, flags); + if (enable) { + for(i = 0; i< CABLE_GPIO_NUM; i++) + enable_irq(rf_cable_data->irq[i]); + } else { + for(i = 0; i< CABLE_GPIO_NUM; i++) + disable_irq_nosync(rf_cable_data->irq[i]); + } + spin_unlock_irqrestore(&rf_cable_data->lock, flags); + } +} + +static void cable_connect_state(int enable) +{ + char *connected[2] = { "CABLE_STATE=CONNECTED", NULL }; + char *disconnected[2] = { "CABLE_STATE=DISCONNECTED", NULL }; + + if (rf_cable_data->uevent_feature) { + if (enable) { + kobject_uevent_env(&rf_uevent_device->kobj, + KOBJ_CHANGE, connected); + rf_cable_data->connected = true; + pr_err("%s: sent uevent %s\n", __func__, + connected[0]); + } else { + kobject_uevent_env(&rf_uevent_device->kobj, + KOBJ_CHANGE, disconnected); + pr_err("%s: sent uevent %s\n", __func__, + disconnected[0]); + rf_cable_data->connected = false; + } + } +} +static void rc_cable_state_change(int state,int restart) +{ + + modify_rf_cable_smem_info(state); + cable_connect_state(state); + + if (restart && !rf_cable_data->uevent_feature) + op_restart_modem(); +} + +static void rf_cable_work(struct work_struct *work) +{ + int current_gpio_state = 0; + + irq_cable_enable(0); + current_gpio_state = get_all_gpio_val(); + + pr_err("%s rf_v3_pre=%d, rf_v3=%d gpio=%2d,\n", + __func__, rf_cable_data->rf_v3_pre, + rf_cable_data->rf_v3,current_gpio_state); + + if (rf_cable_data->gpio_state != current_gpio_state) { + pr_err("%s gpio_state=%d, current_gpio_state=%d ignore\n", + __func__, rf_cable_data->gpio_state, current_gpio_state); + goto out; + } + + rf_cable_data->rf_v3 = current_gpio_state; + + if (rf_cable_data->rf_v3 != rf_cable_data->rf_v3_pre) { + rc_cable_state_change(rf_cable_data->rf_v3,1); + } + rf_cable_data->rf_v3_pre =current_gpio_state; + +out: + irq_cable_enable(1); + + if (rf_cable_data->support_timer) { + queue_delayed_work(rf_cable_data->wqueue, &rf_cable_data->work, + msecs_to_jiffies(2*HZ)); + } +} + +irqreturn_t cable_interrupt(int irq, void *_dev) +{ + + rf_cable_data->gpio_state = get_all_gpio_val(); + + __pm_wakeup_event(rf_cable_data->wl, + msecs_to_jiffies(CABLE_WAKELOCK_HOLD_TIME)); + queue_delayed_work(rf_cable_data->wqueue, + &rf_cable_data->work, msecs_to_jiffies(500)); + return IRQ_HANDLED; +} +static void factory_mode_state_change(int state) +{ + modify_rf_v2_info(state); +} + +static ssize_t rf_factory_mode_proc_read_func(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char page[PAGESIZE]; + int len; + + len = scnprintf(page, sizeof(page), "%d\n", rf_cable_data->is_rf_factory_mode); + + return simple_read_from_buffer(user_buf, + count, ppos, page, len); +} + +static ssize_t rf_factory_mode_proc_write_func(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + + int enable = 0; + char buf[10] = {0}; + int ret = 0; + + if (copy_from_user(buf, buffer, count)) { + pr_err("%s: read proc input error.\n", __func__); + return count; + } + + ret = kstrtoint(buf, 0, &enable); + if (ret < 0) + return ret; + + pr_err("%s: input : %d\n", enable, __func__); + irq_cable_enable(0); + rf_cable_data->is_rf_factory_mode = enable; + if (!rf_cable_data->is_rf_factory_mode) { + factory_mode_state_change(0); + } else { + factory_mode_state_change(2); + } + irq_cable_enable(1); + + return count; +} + +static const struct file_operations rf_factory_mode_proc_fops = { + .write = rf_factory_mode_proc_write_func, + .read = rf_factory_mode_proc_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t rf_cable_proc_read_func(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + char page[PAGESIZE]; + int len; + + len = scnprintf(page, sizeof(page), "%d\n", rf_cable_data->enable); + + return simple_read_from_buffer(user_buf, + count, ppos, page, len); +} + +static ssize_t rf_cable_proc_write_func(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + int enable = 0; + char buf[10]; + int ret; + + if (copy_from_user(buf, buffer, count)) { + pr_err("%s: read proc input error.\n", __func__); + return count; + } + + ret = kstrtoint(buf, 0, &enable); + if (ret < 0) + return ret; + + irq_cable_enable(0); + + if (enable != rf_cable_data->enable) { + rf_cable_data->enable = enable; + rc_cable_state_change(rf_cable_data->enable,1); + } + irq_cable_enable(1); + + return count; +} + +static const struct file_operations rf_enable_proc_fops = { + .write = rf_cable_proc_write_func, + .read = rf_cable_proc_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +int create_rf_cable_procfs(void) +{ + int ret = 0; + + if (!proc_create("rf_cable_config", + 0644, NULL, &rf_enable_proc_fops)) { + pr_err("%s: proc_create enable fail!\n", __func__); + ret = -1; + } + rf_cable_data->enable = 1; + + if (!proc_create("rf_factory_mode", + 0644, NULL, &rf_factory_mode_proc_fops)) { + pr_err("%s: proc_create re_factory_mode fail!\n", __func__); + ret = -1; + } + rf_cable_data->is_rf_factory_mode = 0; + return ret; +} + +static int op_rf_request_named_gpio(const char *label, int *gpio) +{ + struct device *dev = rf_cable_data->dev; + struct device_node *np = dev->of_node; + int rc = of_get_named_gpio(np, label, 0); + + if (rc < 0) { + dev_err(dev, "failed to get '%s'\n", label); + *gpio = rc; + return rc; + } + *gpio = rc; + rc = devm_gpio_request(dev, *gpio, label); + if (rc) { + dev_err(dev, "failed to request gpio %d\n", *gpio); + return rc; + } + dev_info(dev, "%s - gpio: %d\n", label, *gpio); + return 0; +} +static int rf_cable_gpio_pinctrl_init(struct platform_device *pdev) +{ + int retval; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + rf_cable_data->gpio_pinctrl = devm_pinctrl_get(&(pdev->dev)); + if (IS_ERR_OR_NULL(rf_cable_data->gpio_pinctrl)) { + retval = PTR_ERR(rf_cable_data->gpio_pinctrl); + dev_dbg(&pdev->dev, "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + rf_cable_data->gpio_pinctrl_active + = pinctrl_lookup_state(rf_cable_data->gpio_pinctrl, + RF_CABLE_STATE_ACTIVE); + if (IS_ERR_OR_NULL(rf_cable_data->gpio_pinctrl_active)) { + retval = PTR_ERR(rf_cable_data->gpio_pinctrl_active); + dev_err(&pdev->dev, + "Can not lookup %s pinstate %d\n", + RF_CABLE_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + if (rf_cable_data->gpio_pinctrl) { + + retval = pinctrl_select_state(rf_cable_data->gpio_pinctrl, + rf_cable_data->gpio_pinctrl_active); + if (retval < 0) { + dev_err(&pdev->dev, + "failed to select pin to active state"); + } + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(rf_cable_data->gpio_pinctrl); +err_pinctrl_get: + rf_cable_data->gpio_pinctrl = NULL; + return retval; +} + +static bool is_oem_dump = true; +static ssize_t oem_dump_show(struct device *pdev, struct device_attribute *attr, + char *buf) +{ + char *state = "DISABLE"; + + if (is_oem_dump == true) + state = "ENABLE"; + + return snprintf(buf, sizeof(state), "%s\n", state); +} +static ssize_t oem_dump_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t size) +{ + int val; + int ret = 0; + + char *oem_dump_on[2] = { "OEM_DUMP=ENABLE", NULL }; + char *oem_dump_off[2] = { "OEM_DUMP=DISABLE", NULL }; + + ret = kstrtoint(buffer, 10, &val); + if (ret != 0) { + pr_err("%s: invalid content: '%s', length = %zd\n", __func__, + buffer, size); + return ret; + } + + if (val) { + kobject_uevent_env(&rf_uevent_device->kobj, + KOBJ_CHANGE, oem_dump_on); + is_oem_dump = true; + pr_err("%s: sent uevent %s\n", __func__, + oem_dump_on[0]); + } else { + kobject_uevent_env(&rf_uevent_device->kobj, + KOBJ_CHANGE, oem_dump_off); + pr_err("%s: sent uevent %s\n", __func__, + oem_dump_off[0]); + is_oem_dump = false; + } + return size; + +} +static DEVICE_ATTR(oem_dump, 0644, oem_dump_show, oem_dump_store); +static ssize_t state_show(struct device *pdev, struct device_attribute *attr, + char *buf) +{ + char *state = "DISCONNECTED"; + + if (rf_cable_data->connected == true) + state = "CONNECTED"; + return snprintf(buf, sizeof(state), "%s\n", state); +} +static ssize_t state_store(struct device *dev, struct device_attribute *attr, + const char *buffer, size_t size) +{ + int val; + int ret = 0; + + ret = kstrtoint(buffer, 10, &val); + if (ret != 0) { + pr_err("%s: invalid content: '%s', length = %zd\n", __func__, + buffer, size); + return ret; + } + + cable_connect_state(val); + return size; + +} +static DEVICE_ATTR(state, 0644, state_show, state_store); + +static struct device_attribute *rf_uevent_attributes[] = { + &dev_attr_state, + &dev_attr_oem_dump, + NULL +}; + +static int op_rf_cable_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + int cable_state = 0; + struct device_attribute **attrs; + struct device_attribute *attr; + int err,i; + + rf_cable_data = kzalloc(sizeof(struct cable_data), GFP_KERNEL); + if (!rf_cable_data) + goto exit; + + rf_cable_data->dev = dev; + dev_set_drvdata(dev, rf_cable_data); + + rf_cable_data->uevent_feature = of_property_read_bool(pdev->dev.of_node, + "oem,rf_uevent_feature_enable"); + + rc = of_property_read_u32(pdev->dev.of_node, "rf,cable-support-timer", + &rf_cable_data->support_timer); + if (rc) { + pr_err("%s: cable-support-timer fail\n",__func__); + goto exit_gpio; + } + + rf_cable_gpio_pinctrl_init(pdev); + + rf_cable_data->wqueue = create_singlethread_workqueue( + "op_rf_cable_wqueue"); + INIT_DELAYED_WORK(&rf_cable_data->work, rf_cable_work); + + if (rf_cable_data->support_timer) + queue_delayed_work(rf_cable_data->wqueue, &rf_cable_data->work, msecs_to_jiffies(HZ)); + + pr_err("cable uevent init\n"); + rf_uevent_class = class_create(THIS_MODULE, "sdx5x_rf_cable"); + if (IS_ERR(rf_uevent_class)) { + pr_err("%s: class_create fail - %d!\n", __func__, + PTR_ERR(rf_uevent_class)); + return PTR_ERR(rf_uevent_class); + } + + rf_uevent_device = device_create(rf_uevent_class, rf_cable_data->dev, + MKDEV(0, 0), NULL, "rf_cable"); + if (IS_ERR(rf_uevent_device)) { + pr_err("%s: rf_uevent_device fail - %d!\n", __func__, + PTR_ERR(rf_uevent_device)); + return PTR_ERR(rf_uevent_device); + } + + attrs = rf_uevent_attributes; + while ((attr = *attrs++)) { + err = device_create_file(rf_uevent_device, attr); + if (err) { + device_destroy(rf_uevent_device->class, + rf_uevent_device->devt); + return err; + } + } + + rf_cable_data->wl = wakeup_source_register(rf_cable_data->dev,"rf_cable_wake_lock"); + spin_lock_init(&rf_cable_data->lock); + + for(i = 0; i < CABLE_GPIO_NUM; i++) { + + char cable[PAGESIZE]; + memset(cable, 0, sizeof(cable)); + scnprintf(cable, sizeof(cable), "rf,cable-gpio-%d", i); + + rc = op_rf_request_named_gpio(cable, &rf_cable_data->cable_gpio[i]); + if (rc) { + pr_err("%s: op_rf_request_named_gpio gpio-%d fail\n",__func__,i); + goto exit_gpio; + } + gpio_direction_input(rf_cable_data->cable_gpio[i]); + + rf_cable_data->irq[i] = gpio_to_irq(rf_cable_data->cable_gpio[i]); + if (rf_cable_data->irq[i] < 0) { + pr_err("Unable to get irq number for GPIO %d, error %d\n", + rf_cable_data->cable_gpio[i], rf_cable_data->irq[i]); + rc = rf_cable_data->irq[i]; + goto exit_gpio; + } + rc = request_irq(rf_cable_data->irq[i], cable_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "rf,cable-gpio", rf_cable_data); + if (rc) { + pr_err("could not request irq %d\n", rf_cable_data->irq[i]); + goto exit_gpio; + } + pr_err("requested irq %d\n", rf_cable_data->irq[i]); + enable_irq_wake(rf_cable_data->irq[i]); + } + create_rf_cable_procfs(); + + cable_state = get_all_gpio_val(); + pr_err("%s gpio=%d ,\n", __func__, cable_state); + + if (cmdline_find_option("ftm_mode=ftm_rf")) { + pr_err("%s: ftm_mode FOUND! use 1 always\n", __func__); + rc_cable_state_change(1,0); + } else { + rc_cable_state_change(cable_state,0); + } + pr_err("%s: probe success!\n", __func__); + return 0; + +exit_gpio: + kfree(rf_cable_data); +exit: + pr_err("%s: probe Fail!\n", __func__); + + return rc; +} + +static const struct of_device_id rf_of_match[] = { + { .compatible = "oem,rf_cable", }, + {} +}; +MODULE_DEVICE_TABLE(of, rf_of_match); + +static struct platform_driver op_rf_cable_driver = { + .driver = { + .name = "op_rf_cable", + .owner = THIS_MODULE, + .of_match_table = rf_of_match, + }, + .probe = op_rf_cable_probe, +}; + +static int __init op_rf_cable_init(void) +{ + int ret; + + ret = platform_driver_register(&op_rf_cable_driver); + if (ret) + pr_err("rf_cable_driver register failed: %d\n", ret); + + return ret; +} + +MODULE_LICENSE("GPL v2"); +late_initcall(op_rf_cable_init); + diff --git a/drivers/oneplus/misc/param_read_write.c b/drivers/oneplus/misc/param_read_write.c new file mode 100644 index 0000000000000000000000000000000000000000..2620a7dd0cf2fe9e0c1b4343848404f7fb37bf71 --- /dev/null +++ b/drivers/oneplus/misc/param_read_write.c @@ -0,0 +1,401 @@ +/* + * drivers/param_read_write/param_read_write.c + * + * hefaxi@filesystems,2015/04/30 + * + * This program is used to read/write param partition in kernel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PARAM_PARTITION "/dev/block/bootdevice/by-name/param" +#define READ_CHUNK_MAX_SIZE (1024) +#define WRITE_CHUNK_MAX_SIZE (1024) + +typedef struct{ + phys_addr_t paddr; + size_t size; + void *vaddr; + void *buffer; + struct mutex mutex; +}param_ram_zone_t; + +static DEFINE_MUTEX(param_lock); +static bool param_init_done = 0; +static param_ram_zone_t param_ram_zone; + +static int write_param_partition(const char *buf, unsigned long count, + loff_t offset) +{ + struct file *filp; + mm_segment_t fs; + int ret = 0; + + filp = filp_open(PARAM_PARTITION,O_RDWR|O_SYNC,0); + if(IS_ERR(filp)) { + ret = PTR_ERR(filp); + pr_err("open file %s failed.(%d)\n",PARAM_PARTITION,ret); + return ret; + } + + fs = get_fs(); + set_fs(get_ds()); + + ret = filp->f_op->llseek(filp, offset, SEEK_SET); + if(ret < 0){ + pr_err("%s: llseek failed.(%d)\n",__func__,ret); + goto out; + } + //ret = filp->f_op->write(filp,(char __user *)buf,count,&filp->f_pos); + ret = vfs_write(filp, (char __user *)buf, count, &filp->f_pos); + +out: + set_fs(fs); + filp_close(filp,NULL); + return ret; +} + +int get_param_by_index_and_offset(uint32 sid_index, + uint32 offset, void * buf, int length) +{ + int ret = length; + uint32 file_offset; + mutex_lock(¶m_ram_zone.mutex); + pr_info("%s[%d] sid_index = %d offset = %d buf = %p length = %d\n", + __func__, __LINE__,sid_index,offset,buf,length); + + file_offset = PARAM_SID_LENGTH*sid_index+ offset; + + if (buf && ((offset + length) <= PARAM_SID_LENGTH) && + (file_offset + length) <= param_ram_zone.size) + memcpy(buf,(param_ram_zone.buffer +file_offset), length); + else{ + pr_info("%s:invaild argument, sid_index=%d offset=%d buf=%p length=%d\n", + __func__, sid_index, offset, buf, length); + ret = -EINVAL; + } + + mutex_unlock(¶m_ram_zone.mutex); + return ret; +} +EXPORT_SYMBOL(get_param_by_index_and_offset); + +int set_param_by_index_and_offset(uint32 sid_index, + uint32 offset, void * buf, int length) +{ + int ret; + uint32 file_offset; + mutex_lock(¶m_ram_zone.mutex); + pr_info("%s[%d]sid_index = %d offset = %d buf = %p length = %d\n", + __func__, __LINE__,sid_index,offset,buf,length); + + file_offset = PARAM_SID_LENGTH*sid_index + offset; + + if (buf && ((offset + length) <= PARAM_SID_LENGTH) && + (file_offset + length) <= param_ram_zone.size) + memcpy((param_ram_zone.buffer+file_offset),buf,length); + else{ + pr_info("%s:invaild argument,sid_index=%d offset=%d buf=%p length=%d\n", + __func__,sid_index,offset,buf,length); + ret = -EINVAL; + goto out; + } + + ret = write_param_partition((param_ram_zone.buffer+file_offset), + length,file_offset); + if ( ret < 0){ + pr_info("Error write param partition.(%d)\n",ret); + } +out: + mutex_unlock(¶m_ram_zone.mutex); + return ret; +} +EXPORT_SYMBOL(set_param_by_index_and_offset); + +static void *persistent_ram_vmap(phys_addr_t start, size_t size) +{ + struct page **pages; + phys_addr_t page_start; + unsigned int page_count; + pgprot_t prot; + unsigned int i; + void *vaddr; + + page_start = start - offset_in_page(start); + page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); + + /* prot = pgprot_noncached(PAGE_KERNEL); */ + prot = pgprot_writecombine(PAGE_KERNEL); + + pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); + if (!pages) { + pr_err("%s: Failed to allocate array for %u pages\n", __func__, + page_count); + return NULL; + } + + for (i = 0; i < page_count; i++) { + phys_addr_t addr = page_start + i * PAGE_SIZE; + pages[i] = pfn_to_page(addr >> PAGE_SHIFT); + } + vaddr = vmap(pages, page_count, VM_MAP, prot); + kfree(pages); + return vaddr; +} + +static int param_ram_buffer_map(phys_addr_t start, phys_addr_t size, + param_ram_zone_t *prz) +{ + prz->paddr = start; + prz->size = size; + prz->vaddr = persistent_ram_vmap(start, size); + + if (!prz->vaddr) { + pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__, + (unsigned long long)size, (unsigned long long)start); + return -ENOMEM; + } + + prz->buffer = prz->vaddr + offset_in_page(start); + return 0; +} + +static ssize_t param_read(struct file *file, char __user *buff, + size_t count, loff_t *pos) +{ + void * temp_buffer; + int chunk_sz; + int copied; + int left; + int ret; + + if (mutex_lock_interruptible(¶m_lock)) + return -ERESTARTSYS; + + chunk_sz = count < READ_CHUNK_MAX_SIZE ? count : READ_CHUNK_MAX_SIZE; + temp_buffer = kzalloc(chunk_sz, GFP_KERNEL); + + if (temp_buffer == NULL) + return -ENOMEM; + + left = count; + copied = 0; + + while (left) { + chunk_sz = (left <= READ_CHUNK_MAX_SIZE) ? + left : READ_CHUNK_MAX_SIZE; + ret = get_param_by_index_and_offset(*pos/PARAM_SID_LENGTH, + *pos%PARAM_SID_LENGTH, temp_buffer, chunk_sz); + + if (ret < 0) { + pr_err("get_param_by_index_and_offset fail %d\n", ret); + goto out; + } + + if (copy_to_user(buff + copied, temp_buffer, chunk_sz)) { + ret = -EFAULT; + pr_info("copy_to_user failure\n"); + goto out; + } + + *pos += chunk_sz; + left -= chunk_sz; + copied += chunk_sz; + } + +out: + kfree(temp_buffer); + mutex_unlock(¶m_lock); + return copied; +} + +static ssize_t param_write(struct file *file, const char __user *buff, + size_t count, loff_t *pos) +{ + + void * temp_buffer; + int chunk_sz; + int written; + int left; + int ret; + if (mutex_lock_interruptible(¶m_lock)) + return -ERESTARTSYS; + + chunk_sz = count < WRITE_CHUNK_MAX_SIZE ? count : WRITE_CHUNK_MAX_SIZE; + temp_buffer = kzalloc(chunk_sz, GFP_KERNEL); + + if (temp_buffer == NULL) + return -ENOMEM; + + left = count; + written = 0; + + while (left > 0) { + chunk_sz = (left <= WRITE_CHUNK_MAX_SIZE) ? + left : WRITE_CHUNK_MAX_SIZE; + ret = copy_from_user(temp_buffer, buff + written, chunk_sz); + if (ret < 0) { + pr_info("copy_from_user failure %d\n", ret); + goto out; + } + + ret = set_param_by_index_and_offset(*pos / PARAM_SID_LENGTH, + *pos % PARAM_SID_LENGTH, temp_buffer, chunk_sz); + + if (ret < 0) { + pr_err("set_param_by_index_and_offset failure %d\n", + ret); + goto out; + } + + *pos += chunk_sz; + left -= chunk_sz; + written += chunk_sz; + } +out: + kfree(temp_buffer); + mutex_unlock(¶m_lock); + return written; +} + +static const struct file_operations param_fops = { + .owner = THIS_MODULE, + .read = param_read, + .write = param_write, + .llseek = default_llseek, +}; + +struct miscdevice param_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "param", + .fops = ¶m_fops, +}; + +static int __init param_core_init(void) +{ + + if(param_ram_buffer_map((phys_addr_t)param_ram_zone.paddr, + param_ram_zone.size, (param_ram_zone_t *)¶m_ram_zone)){ + pr_err("param_ram_buffer_map failred\n"); + return -1; + } + mutex_init(¶m_ram_zone.mutex); + + param_init_done= 1; + return 0; +} +pure_initcall(param_core_init); + +static int __init param_device_init(void) +{ + int ret; + ret = misc_register(¶m_misc); + if(ret){ + pr_err("misc_register failure %d\n",ret); + return -1; + } + return ret; +} +device_initcall(param_device_init); + +void init_param_mem_base_size(phys_addr_t base, unsigned long size) +{ + param_ram_zone.paddr = base; + param_ram_zone.size = size; +} +EXPORT_SYMBOL(init_param_mem_base_size); + +/* +*Add more function here +* +*/ + +int restart_08_count; +int add_restart_08_count(void) +{ + int ret; + + ret = get_param_by_index_and_offset(9, 0x15c, + &restart_08_count, sizeof(restart_08_count)); + + restart_08_count = restart_08_count + 1; + + ret = set_param_by_index_and_offset(9, 0x15c, + &restart_08_count, sizeof(restart_08_count)); + + if (ret < 0) + pr_info("%s[%d] failed!\n", __func__, __LINE__); + + return ret; +} +EXPORT_SYMBOL(add_restart_08_count); + +static int param_get_restart_08_count(char *val, const struct kernel_param *kp) +{ + + int cnt = 0; + int ret; + + ret = get_param_by_index_and_offset(9, 0x15c, + &restart_08_count, sizeof(restart_08_count)); + + if (ret < 0) + pr_info("%s[%d] failed!\n", __func__, __LINE__); + + cnt = snprintf(val, 4, "%d", restart_08_count); + + return cnt; +} +module_param_call(restart_08_count, NULL, param_get_restart_08_count, &restart_08_count, 0644); + +int restart_other_count=0; +int add_restart_other_count(void) +{ + int ret; + + ret = get_param_by_index_and_offset(9, 0x160, + &restart_other_count, sizeof(restart_other_count)); + + restart_other_count = restart_other_count + 1; + + ret = set_param_by_index_and_offset(9, 0x160, + &restart_other_count, sizeof(restart_other_count)); + + if (ret < 0) + pr_info("%s[%d] failed!\n", __func__, __LINE__); + + return ret; +} +EXPORT_SYMBOL(add_restart_other_count); +static int param_get_restart_other_count(char *val, const struct kernel_param *kp) +{ + + int cnt = 0; + int ret; + + ret = get_param_by_index_and_offset(9, 0x160, + &restart_other_count, sizeof(restart_other_count)); + + if (ret < 0) + pr_info("%s[%d] failed!\n", __func__, __LINE__); + + cnt = snprintf(val, 4, "%d", restart_other_count); + + return cnt; +} +module_param_call(restart_other_count, NULL, param_get_restart_other_count, &restart_other_count, 0644); +//end diff --git a/drivers/oneplus/misc/project_info.c b/drivers/oneplus/misc/project_info.c new file mode 100644 index 0000000000000000000000000000000000000000..5104cdeffcb550d6e02b735f7dbaf4313905e6eb --- /dev/null +++ b/drivers/oneplus/misc/project_info.c @@ -0,0 +1,889 @@ +/* For OEM project information + *such as project name, hardware ID + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +static struct component_info component_info_desc[COMPONENT_MAX]; +static struct kobject *project_info_kobj; +static struct project_info *project_info_desc; +static struct dump_info *dp_info; + +void *panic_info = NULL; + +static char caller_function_name[KSYM_SYMBOL_LEN]; +int a_board_val = 0; +static struct kobject *component_info; +static ssize_t project_info_get(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t component_info_get(struct device *dev, + struct device_attribute *attr, char *buf); +static int op_aboard_read_gpio(void); + +static DEVICE_ATTR(project_name, 0444, project_info_get, NULL); +static DEVICE_ATTR(hw_id, 0444, project_info_get, NULL); +static DEVICE_ATTR(rf_id_v1, 0444, project_info_get, NULL); +static DEVICE_ATTR(rf_id_v2, 0444, project_info_get, NULL); +static DEVICE_ATTR(rf_id_v3, 0444, project_info_get, NULL); +static DEVICE_ATTR(ddr_manufacture_info, 0444, project_info_get, NULL); +static DEVICE_ATTR(ddr_row, 0444, project_info_get, NULL); +static DEVICE_ATTR(ddr_column, 0444, project_info_get, NULL); +static DEVICE_ATTR(ddr_fw_version, 0444, project_info_get, NULL); +static DEVICE_ATTR(ddr_reserve_info, 0444, project_info_get, NULL); +static DEVICE_ATTR(secboot_status, 0444, project_info_get, NULL); +static DEVICE_ATTR(platform_id, 0444, project_info_get, NULL); +static DEVICE_ATTR(serialno, 0444, project_info_get, NULL); +static DEVICE_ATTR(aboard_id, 0444, project_info_get, NULL); + +char *parse_regs_pc(unsigned long address, int *length) +{ + static char function_name[KSYM_SYMBOL_LEN]; + if (!address) + return NULL; + *length = sprint_symbol(function_name, address); + + return function_name; +} +char *parse_function_builtin_return_address(unsigned long function_address) +{ + char *cur = caller_function_name; + + if (!function_address) + return NULL; + + sprint_symbol(caller_function_name, function_address); + strsep(&cur, "+"); + return caller_function_name; +} +EXPORT_SYMBOL(parse_function_builtin_return_address); + +void save_dump_reason_to_smem(char *info, char *function_name) +{ + int strl = 0, strl1 = 0, length = 0; + size_t size; + static int flag = 0; + char buf[7], *buf1; + struct pt_regs *regs; + char *caller_function_name; + + /* Make sure save_dump_reason_to_smem() is not + called infinite times by nested panic caller fns etc*/ + if (flag > 1) + return; + + dp_info = qcom_smem_get(QCOM_SMEM_HOST_ANY,SMEM_DUMP_INFO,&size); + + if (IS_ERR_OR_NULL(dp_info)) + pr_debug("%s: get dp_info failure\n", __func__); + else { + pr_debug("%s: info : %s\n",__func__, info); + + strl = strlen(info)+1; + strl1 = strlen(function_name)+1; + strl = strl < DUMP_REASON_SIZE ? strl : DUMP_REASON_SIZE; + strl1 = strl1 < DUMP_REASON_SIZE ? strl1: DUMP_REASON_SIZE; + if ((strlen(dp_info->dump_reason) + strl) < DUMP_REASON_SIZE) + strncat(dp_info->dump_reason, info, strl); + + if (function_name != NULL && + ((strlen(dp_info->dump_reason) + strl1 + 3) < DUMP_REASON_SIZE)) { + strncat(dp_info->dump_reason, "\r\n", 2); + strncat(dp_info->dump_reason, function_name, strl1); + } + + caller_function_name = parse_function_builtin_return_address( + (unsigned long)__builtin_return_address(0)); + if ((strcmp(caller_function_name, "panic") == 0)) { + regs = (struct pt_regs *)panic_info; + if (regs) { + buf1 = parse_regs_pc(regs->pc, &length); + length = length < DUMP_REASON_SIZE ? length: DUMP_REASON_SIZE; + if ((strlen(dp_info->dump_reason) + length + 12) < DUMP_REASON_SIZE) { + strncat(dp_info->dump_reason,"\r\n", 2); + strncpy(buf, "PC at:", 7); + strncat(dp_info->dump_reason, buf, 7); + strncat(dp_info->dump_reason, buf1, length); + strncat(dp_info->dump_reason, "\r\n", 2); + } + } + } + } + + pr_debug("\r%s: dump_reason : %s strl=%d function caused panic :%s strl1=%d \n", __func__, + dp_info->dump_reason, strl, function_name, strl1); + save_dump_reason_to_device_info(dp_info->dump_reason); + flag++; +} + +uint8 get_secureboot_fuse_status(void) +{ + void __iomem *oem_config_base; + uint8 secure_oem_config = 0; + + oem_config_base = ioremap(SECURE_BOOT1, 1); + if (!oem_config_base) + return -EINVAL; + secure_oem_config = __raw_readb(oem_config_base); + iounmap(oem_config_base); + pr_debug("secure_oem_config 0x%x\n", secure_oem_config); + + return secure_oem_config; +} + +static ssize_t project_info_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + if (project_info_desc) { + if (attr == &dev_attr_project_name) + return snprintf(buf, BUF_SIZE, "%s\n", + project_info_desc->project_name); + if (attr == &dev_attr_hw_id) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->hw_version); + if (attr == &dev_attr_rf_id_v1) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->rf_v1); + if (attr == &dev_attr_rf_id_v2) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->rf_v2); + if (attr == &dev_attr_rf_id_v3) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->rf_v3); + if (attr == &dev_attr_ddr_manufacture_info) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->ddr_manufacture_info); + if (attr == &dev_attr_ddr_row) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->ddr_row); + if (attr == &dev_attr_ddr_column) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->ddr_column); + if (attr == &dev_attr_ddr_fw_version) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->ddr_fw_version); + if (attr == &dev_attr_ddr_reserve_info) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->ddr_reserve_info); + if (attr == &dev_attr_secboot_status) + return snprintf(buf, BUF_SIZE, "%d\n", + get_secureboot_fuse_status()); + if (attr == &dev_attr_platform_id) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->platform_id); + + if (attr == &dev_attr_serialno) + return snprintf(buf, BUF_SIZE, "0x%x\n", + socinfo_get_serial_number()); + + if (attr == &dev_attr_aboard_id) + return snprintf(buf, BUF_SIZE, "%d\n",a_board_val); + } + + return -EINVAL; +} + +static struct attribute *project_info_sysfs_entries[] = { + &dev_attr_project_name.attr, + &dev_attr_hw_id.attr, + &dev_attr_rf_id_v1.attr, + &dev_attr_rf_id_v2.attr, + &dev_attr_rf_id_v3.attr, + &dev_attr_ddr_manufacture_info.attr, + &dev_attr_ddr_row.attr, + &dev_attr_ddr_column.attr, + &dev_attr_ddr_fw_version.attr, + &dev_attr_ddr_reserve_info.attr, + &dev_attr_secboot_status.attr, + &dev_attr_platform_id.attr, + &dev_attr_serialno.attr, + &dev_attr_aboard_id.attr, + NULL, +}; + +static struct attribute_group project_info_attr_group = { + .attrs = project_info_sysfs_entries, +}; + +static DEVICE_ATTR(ddr, 0444, component_info_get, NULL); +static DEVICE_ATTR(emmc, 0444, component_info_get, NULL); +static DEVICE_ATTR(f_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(second_f_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(r_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(second_r_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(third_r_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(forth_r_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(r_ois, 0444, component_info_get, NULL); +static DEVICE_ATTR(second_r_ois, 0444, component_info_get, NULL); +static DEVICE_ATTR(tp, 0444, component_info_get, NULL); +static DEVICE_ATTR(lcd, 0444, component_info_get, NULL); +static DEVICE_ATTR(wcn, 0444, component_info_get, NULL); +static DEVICE_ATTR(l_sensor, 0444, component_info_get, NULL); +static DEVICE_ATTR(g_sensor, 0444, component_info_get, NULL); +static DEVICE_ATTR(m_sensor, 0444, component_info_get, NULL); +static DEVICE_ATTR(gyro, 0444, component_info_get, NULL); +static DEVICE_ATTR(backlight, 0444, component_info_get, NULL); +static DEVICE_ATTR(mainboard, 0444, component_info_get, NULL); +static DEVICE_ATTR(fingerprints, 0444, component_info_get, NULL); +static DEVICE_ATTR(touch_key, 0444, component_info_get, NULL); +static DEVICE_ATTR(ufs, 0444, component_info_get, NULL); +static DEVICE_ATTR(Aboard, 0444, component_info_get, NULL); +static DEVICE_ATTR(nfc, 0444, component_info_get, NULL); +static DEVICE_ATTR(fast_charge, 0444, component_info_get, NULL); +static DEVICE_ATTR(wireless_charge, 0444, component_info_get, NULL); +static DEVICE_ATTR(cpu, 0444, component_info_get, NULL); +static DEVICE_ATTR(rf_version, 0444, component_info_get, NULL); + + +char *get_component_version(enum COMPONENT_TYPE type) +{ + if (type >= COMPONENT_MAX) { + pr_err("%s == type %d invalid\n", __func__, type); + return "N/A"; + } + return component_info_desc[type].version?:"N/A"; +} + +char *get_component_manufacture(enum COMPONENT_TYPE type) +{ + if (type >= COMPONENT_MAX) { + pr_err("%s == type %d invalid\n", __func__, type); + return "N/A"; + } + return component_info_desc[type].manufacture?:"N/A"; + +} + +int push_component_info(enum COMPONENT_TYPE type, + char *version, char *manufacture) +{ + if (type >= COMPONENT_MAX) + return -ENOMEM; + component_info_desc[type].version = version; + component_info_desc[type].manufacture = manufacture; + + return 0; +} +EXPORT_SYMBOL(push_component_info); + +int reset_component_info(enum COMPONENT_TYPE type) +{ + if (type >= COMPONENT_MAX) + return -ENOMEM; + component_info_desc[type].version = NULL; + component_info_desc[type].manufacture = NULL; + + return 0; +} +EXPORT_SYMBOL(reset_component_info); + + +static struct attribute *component_info_sysfs_entries[] = { + &dev_attr_ddr.attr, + &dev_attr_emmc.attr, + &dev_attr_f_camera.attr, + &dev_attr_second_f_camera.attr, + &dev_attr_r_camera.attr, + &dev_attr_second_r_camera.attr, + &dev_attr_third_r_camera.attr, + &dev_attr_forth_r_camera.attr, + &dev_attr_r_ois.attr, + &dev_attr_second_r_ois.attr, + &dev_attr_tp.attr, + &dev_attr_lcd.attr, + &dev_attr_wcn.attr, + &dev_attr_l_sensor.attr, + &dev_attr_g_sensor.attr, + &dev_attr_m_sensor.attr, + &dev_attr_gyro.attr, + &dev_attr_backlight.attr, + &dev_attr_mainboard.attr, + &dev_attr_fingerprints.attr, + &dev_attr_touch_key.attr, + &dev_attr_ufs.attr, + &dev_attr_Aboard.attr, + &dev_attr_nfc.attr, + &dev_attr_fast_charge.attr, + &dev_attr_wireless_charge.attr, + &dev_attr_cpu.attr, + &dev_attr_rf_version.attr, + NULL, +}; + +static struct attribute_group component_info_attr_group = { + .attrs = component_info_sysfs_entries, +}; + +static ssize_t component_info_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + if (attr == &dev_attr_ddr) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(DDR), + get_component_manufacture(DDR)); + if (attr == &dev_attr_emmc) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(EMMC), + get_component_manufacture(EMMC)); + if (attr == &dev_attr_f_camera) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(F_CAMERA), + get_component_manufacture(F_CAMERA)); + if (attr == &dev_attr_second_f_camera) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(SECOND_F_CAMERA), + get_component_manufacture(SECOND_F_CAMERA)); + if (attr == &dev_attr_r_camera) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(R_CAMERA), + get_component_manufacture(R_CAMERA)); + if (attr == &dev_attr_second_r_camera) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(SECOND_R_CAMERA), + get_component_manufacture(SECOND_R_CAMERA)); + if (attr == &dev_attr_third_r_camera) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(THIRD_R_CAMERA), + get_component_manufacture(THIRD_R_CAMERA)); + if (attr == &dev_attr_forth_r_camera) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(FORTH_R_CAMERA), + get_component_manufacture(FORTH_R_CAMERA)); + if (attr == &dev_attr_r_ois) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(R_OIS), + get_component_manufacture(R_OIS)); + if (attr == &dev_attr_second_r_ois) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(SECOND_R_OIS), + get_component_manufacture(SECOND_R_OIS)); + if (attr == &dev_attr_tp) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(TP), + get_component_manufacture(TP)); + if (attr == &dev_attr_lcd) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(LCD), + get_component_manufacture(LCD)); + if (attr == &dev_attr_wcn) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(WCN), + get_component_manufacture(WCN)); + if (attr == &dev_attr_l_sensor) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(I_SENSOR), + get_component_manufacture(I_SENSOR)); + if (attr == &dev_attr_g_sensor) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(G_SENSOR), + get_component_manufacture(G_SENSOR)); + if (attr == &dev_attr_m_sensor) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(M_SENSOR), + get_component_manufacture(M_SENSOR)); + if (attr == &dev_attr_gyro) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(GYRO), + get_component_manufacture(GYRO)); + if (attr == &dev_attr_backlight) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(BACKLIGHT), + get_component_manufacture(BACKLIGHT)); + if (attr == &dev_attr_mainboard) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(MAINBOARD), + get_component_manufacture(MAINBOARD)); + if (attr == &dev_attr_fingerprints) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(FINGERPRINTS), + get_component_manufacture(FINGERPRINTS)); + if (attr == &dev_attr_touch_key) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(TOUCH_KEY), + get_component_manufacture(TOUCH_KEY)); + if (attr == &dev_attr_ufs) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(UFS), + get_component_manufacture(UFS)); + if (attr == &dev_attr_Aboard) { + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(ABOARD), + get_component_manufacture(ABOARD)); + } + if (attr == &dev_attr_nfc) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(NFC), + get_component_manufacture(NFC)); + if (attr == &dev_attr_fast_charge) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(FAST_CHARGE), + get_component_manufacture(FAST_CHARGE)); + if (attr == &dev_attr_wireless_charge) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(WIRELESS_CHARGE), + get_component_manufacture(WIRELESS_CHARGE)); + if (attr == &dev_attr_cpu) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(CPU), + get_component_manufacture(CPU)); + if (attr == &dev_attr_rf_version) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(RF_VERSION), + get_component_manufacture(RF_VERSION)); + return -EINVAL; +} + +static int __init project_info_init_sysfs(void) +{ + int error = 0; + + project_info_kobj = kobject_create_and_add("project_info", NULL); + if (!project_info_kobj) + return -ENOMEM; + error = sysfs_create_group(project_info_kobj, &project_info_attr_group); + if (error) { + pr_err("project_info_init_sysfs project_info_attr_group failure\n"); + return error; + } + + component_info = kobject_create_and_add("component_info", + project_info_kobj); + pr_info("project_info_init_sysfs success\n"); + if (!component_info) + return -ENOMEM; + + error = sysfs_create_group(component_info, &component_info_attr_group); + if (error) { + pr_err("project_info_init_sysfs project_info_attr_group failure\n"); + return error; + } + return 0; +} + +late_initcall(project_info_init_sysfs); + +struct ddr_manufacture { + int id; + char name[20]; +}; +//ddr id and ddr name +static char ddr_version[32] = {0}; +static char ddr_manufacture[20] = {0}; +char ddr_manufacture_and_fw_verion[40] = {0}; +static char cpu_type[20] = {0}; + +struct ddr_manufacture ddr_manufacture_list[] = { + {1, "Samsung "}, + {2, "Qimonda "}, + {3, "Elpida "}, + {4, "Etpon "}, + {5, "Nanya "}, + {6, "Hynix "}, + {7, "Mosel "}, + {8, "Winbond "}, + {9, "Esmt "}, + {255, "Micron"}, + {0, "Unknown"}, +}; + +struct cpu_list { + int id; + char name[20]; +}; + +struct cpu_list cpu_list_msm[] = { + {321, "SDM845 "}, + {339, "SM8150 "}, + {356, "SM8250 "}, + {400, "SM7250 "}, + {0, "Unknown"}, +}; + +void get_ddr_manufacture_name(void) +{ + uint32 i, length; + + length = ARRAY_SIZE(ddr_manufacture_list); + if (project_info_desc) { + for (i = 0; i < length; i++) { + if (ddr_manufacture_list[i].id == + project_info_desc->ddr_manufacture_info) { + snprintf(ddr_manufacture, sizeof(ddr_manufacture), "%s", + ddr_manufacture_list[i].name); + break; + } + } + } +} + +void get_cpu_type(void) +{ + uint32 i, length; + + length = ARRAY_SIZE(cpu_list_msm); + if (project_info_desc) { + for (i = 0; i < length; i++) { + if (cpu_list_msm[i].id == + project_info_desc->platform_id) { + snprintf(cpu_type, sizeof(cpu_type), + "%s", cpu_list_msm[i].name); + break; + } + } + } +} + +static char mainboard_version[64] = {0}; +static char mainboard_manufacture[8] = {'O', + 'N', 'E', 'P', 'L', 'U', 'S', '\0'}; +static char Aboard_version[16] = {0}; +static char rf_version[16] = {0}; + +struct a_board_version{ + + int version; + char name[16]; +}; + +struct main_board_info{ + int prj_version; + int hw_version; + int rf_version; + char version_name[32]; +}; + +struct a_board_version a_board_version_string_arry_gpio[]={ + + {0, "NOQET"}, + {1, "QET"}, +}; + +struct main_board_info main_board_info_check[]={ + /* prj hw rf version*/ + { 11 , 11 , NONDEFINE ,"19811 T0"}, + { 11 , 12 , NONDEFINE ,"19811 EVT1"}, + { 11 , 13 , NONDEFINE ,"19811 EVT2"}, + { 11 , 14 , NONDEFINE ,"19811 DVT"}, + { 11 , 15 , NONDEFINE ,"19811 PVT/MP"}, + { 11 , 51 , NONDEFINE ,"19811 EVT2 SEC"}, + { 11 , 52 , NONDEFINE ,"19811 DVT SEC"}, + { 11 , 53 , NONDEFINE ,"19811 PVT/MP SEC"}, + + { 12 , 11 , 12 ,"19855 T0"}, + { 12 , 12 , 12 ,"19855 EVT1"}, + { 12 , 13 , 12 ,"19855 EVT2"}, + { 12 , 14 , 12 ,"19855 DVT"}, + { 12 , 15 , 12 ,"19855 PVT/MP"}, + + + { 12 , 11 , NONDEFINE ,"19821 T0"}, + { 12 , 12 , NONDEFINE ,"19821 EVT1"}, + { 12 , 13 , NONDEFINE ,"19821 EVT2"}, + { 12 , 14 , NONDEFINE ,"19821 DVT"}, + { 12 , 54 , NONDEFINE ,"19821 EVT2 SEC"}, + { 12 , 55 , NONDEFINE ,"19821 DVT SEC"}, + { 12 , 15 , NONDEFINE ,"19821 PVT/MP"}, + + { 13 , 11 , NONDEFINE ,"19867 T0"}, + { 13 , 12 , NONDEFINE ,"19867 EVT1"}, + { 13 , 13 , NONDEFINE ,"19867 EVT2"}, + { 13 , 14 , NONDEFINE ,"19867 DVT"}, + { 13 , 15 , NONDEFINE ,"19867 PVT/MP"}, + + { 11 , 11 ,NONDEFINE,"19811 T0"}, + {NONDEFINE,NONDEFINE,NONDEFINE,"Unknown"} +}; + +uint32 get_hw_version(void) +{ + size_t size; + + project_info_desc = qcom_smem_get(QCOM_SMEM_HOST_ANY,SMEM_PROJECT_INFO, &size); + + if (IS_ERR_OR_NULL(project_info_desc)) + pr_err("%s: get project_info failure\n", __func__); + else { + pr_err("%s: hw version: %d\n", __func__, + project_info_desc->hw_version); + return project_info_desc->hw_version; + } + return 0; +} + +void dump_reason_init_smem(void) +{ + int ret; + + ret = qcom_smem_alloc(QCOM_SMEM_HOST_ANY,SMEM_DUMP_INFO, + sizeof(struct dump_info)); + + if (ret < 0 && ret != -EEXIST) { + pr_err("%s:unable to allocate dp_info \n", __func__); + return; + } +} + +int __init init_project_info(void) +{ + static bool project_info_init_done; + int ddr_size = 0; + size_t size; + int i = 0; + char *p = NULL; + + if (project_info_init_done) + return 0; + + project_info_desc = qcom_smem_get(QCOM_SMEM_HOST_ANY,SMEM_PROJECT_INFO, &size); + + if (IS_ERR_OR_NULL(project_info_desc)) { + pr_err("%s: get project_info failure\n", __func__); + return -1; + } + pr_err("%s: project_name: %s hw_version: %d prj=%d rf_v1: %d rf_v2: %d: rf_v3: %d paltform_id:%d\n", + __func__, project_info_desc->project_name, + project_info_desc->hw_version, + project_info_desc->prj_version, + project_info_desc->rf_v1, + project_info_desc->rf_v2, + project_info_desc->rf_v3, + project_info_desc->platform_id); + + + p = &main_board_info_check[ARRAY_SIZE(main_board_info_check)-1].version_name[0]; + + for( i = 0 ; i < ARRAY_SIZE(main_board_info_check) ; i++ ) + { + if(project_info_desc->prj_version == main_board_info_check[i].prj_version && + project_info_desc->hw_version == main_board_info_check[i].hw_version && + (project_info_desc->rf_v1 == main_board_info_check[i].rf_version || + NONDEFINE == main_board_info_check[i].rf_version )) + { + p = &main_board_info_check[i].version_name[0]; + break; + } + } + + snprintf(mainboard_version, sizeof(mainboard_version), "%d %d %s %s ", + project_info_desc->prj_version,project_info_desc->hw_version, + project_info_desc->project_name, p); + + pr_err("board info: %s\n", mainboard_version); + push_component_info(MAINBOARD, + mainboard_version, + mainboard_manufacture); + + snprintf(rf_version, sizeof(rf_version), " %d",project_info_desc->rf_v1); + push_component_info(RF_VERSION, rf_version, mainboard_manufacture); + + get_ddr_manufacture_name(); + + /* approximate as ceiling of total pages */ + ddr_size = (totalram_pages + (1 << 18) - 1) >> 18; + + snprintf(ddr_version, sizeof(ddr_version), "size_%dG_r_%d_c_%d", + ddr_size, project_info_desc->ddr_row, + project_info_desc->ddr_column); + snprintf(ddr_manufacture_and_fw_verion, + sizeof(ddr_manufacture_and_fw_verion), + "%s%s %u.%u", ddr_manufacture, + project_info_desc->ddr_reserve_info == 0x05 ? "20nm" : + (project_info_desc->ddr_reserve_info == 0x06 ? "18nm" : " "), + project_info_desc->ddr_fw_version >> 16, + project_info_desc->ddr_fw_version & 0x0000FFFF); + push_component_info(DDR, ddr_version, ddr_manufacture_and_fw_verion); + + get_cpu_type(); + push_component_info(CPU, cpu_type, "Qualcomm"); + project_info_init_done = true; + dump_reason_init_smem(); + + return 0; +} +struct aboard_data { + int aboard_gpio_0; + int aboard_gpio_1; + int support_aboard_gpio_0; + int support_aboard_gpio_1; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_sleep; + struct device *dev; +}; +static struct aboard_data *data; + +static int op_aboard_request_named_gpio(const char *label, int *gpio) +{ + struct device *dev = data->dev; + struct device_node *np = dev->of_node; + int rc = of_get_named_gpio(np, label, 0); + + if (rc < 0) { + dev_err(dev, "failed to get '%s'\n", label); + *gpio = rc; + return rc; + } + *gpio = rc; + + rc = devm_gpio_request(dev, *gpio, label); + if (rc) { + dev_err(dev, "failed to request gpio %d\n", *gpio); + return rc; + } + + dev_info(dev, "%s gpio: %d\n", label, *gpio); + return 0; +} + +static int op_aboard_read_gpio(void) +{ + int gpio0 = 0; + int gpio1 = 0; + if ( data == NULL || IS_ERR_OR_NULL(project_info_desc)) + { + return 0 ; + } + if(data->support_aboard_gpio_0 == 1) + gpio0 = gpio_get_value(data->aboard_gpio_0); + if(data->support_aboard_gpio_1 == 1) + gpio1 = gpio_get_value(data->aboard_gpio_1); + + a_board_val = gpio0; + snprintf(Aboard_version, sizeof(Aboard_version), "%d %s", + a_board_val, a_board_version_string_arry_gpio[a_board_val].name); + + push_component_info(ABOARD, Aboard_version, mainboard_manufacture); + pr_err("%s: Aboard_gpio(%s)\n", __func__, Aboard_version); + return 0 ; + +} + +static int oem_aboard_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + + data = kzalloc(sizeof(struct aboard_data), GFP_KERNEL); + if (!data) { + pr_err("%s: failed to allocate memory\n", __func__); + rc = -ENOMEM; + goto exit; + } + + data->dev = dev; + rc = op_aboard_request_named_gpio("oem,aboard-gpio-0",&data->aboard_gpio_0); + if (rc) { + pr_err("%s: oem,aboard-gpio-0 fail\n", __func__); + }else{ + data->support_aboard_gpio_0 = 1; + } + + rc = op_aboard_request_named_gpio("oem,aboard-gpio-1",&data->aboard_gpio_1); + if (rc) { + pr_err("%s: oem,aboard-gpio-1 fail\n", __func__); + }else{ + data->support_aboard_gpio_1 = 1; + } + + data->pinctrl = devm_pinctrl_get((data->dev)); + if (IS_ERR_OR_NULL(data->pinctrl)) { + rc = PTR_ERR(data->pinctrl); + pr_err("%s pinctrl error!\n",__func__); + goto err_pinctrl_get; + } + + data->pinctrl_state_active = pinctrl_lookup_state(data->pinctrl, "oem_aboard_active"); + + if (IS_ERR_OR_NULL(data->pinctrl_state_active)) { + rc = PTR_ERR(data->pinctrl_state_active); + pr_err("%s pinctrl state active error!\n",__func__); + goto err_pinctrl_lookup; + } + + if (data->pinctrl) { + rc = pinctrl_select_state(data->pinctrl,data->pinctrl_state_active); + } + if(data->support_aboard_gpio_0 == 1) + gpio_direction_input(data->aboard_gpio_0); + if(data->support_aboard_gpio_1 == 1) + gpio_direction_input(data->aboard_gpio_1); + op_aboard_read_gpio(); + + data->pinctrl_state_sleep = pinctrl_lookup_state(data->pinctrl, "oem_aboard_sleep"); + + if (data->pinctrl && !IS_ERR_OR_NULL(data->pinctrl_state_sleep)) { + rc = pinctrl_select_state(data->pinctrl,data->pinctrl_state_sleep); + } + + pr_err("%s: probe finish!\n", __func__); + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(data->pinctrl); +err_pinctrl_get: + data->pinctrl = NULL; + kfree(data); +exit: + pr_err("%s: probe Fail!\n", __func__); + + return rc; +} + +static const struct of_device_id aboard_of_match[] = { + { .compatible = "oem,aboard", }, + {} +}; +MODULE_DEVICE_TABLE(of, aboard_of_match); + +static struct platform_driver aboard_driver = { + .driver = { + .name = "op_aboard", + .owner = THIS_MODULE, + .of_match_table = aboard_of_match, + }, + .probe = oem_aboard_probe, +}; + +static int __init init_project(void) +{ + int ret; + + ret = init_project_info(); + + return ret; +} +static int __init init_aboard(void) +{ + int ret; + + ret = platform_driver_register(&aboard_driver); + if (ret) + pr_err("aboard_driver register failed: %d\n", ret); + + return ret; +} + + +subsys_initcall(init_project); +late_initcall(init_aboard); + diff --git a/drivers/oneplus/misc/regulator_demo.c b/drivers/oneplus/misc/regulator_demo.c new file mode 100644 index 0000000000000000000000000000000000000000..451bb87cf2c27c7e23ddc2f8ff5827b12d582ff1 --- /dev/null +++ b/drivers/oneplus/misc/regulator_demo.c @@ -0,0 +1,180 @@ +/* + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include "../../../fs/proc/internal.h" +#include + +#define DRV_NAME "regulator_demo" + +struct regulator_demo_dev_data { + struct device *dev; + int regulator_demo_value; + struct regulator *regulator_demo; +}; + +static struct regulator_demo_dev_data *regulator_demo_data; + +static int regulator_demo_state_show(struct seq_file *seq, void *offset) +{ + seq_printf(seq, "%d\n", regulator_demo_data->regulator_demo_value); + return 0; +} + +static ssize_t regulator_demo_state_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) +{ + int regulator_demo_value = 0; + char buf[10]={0}; + int ret; + + if (!regulator_demo_data) { + return -EFAULT; + } + + if( copy_from_user(buf, buffer, sizeof (buf)) ){ + return count; + } + + snprintf(buf, sizeof(buf), "%d", ®ulator_demo_value); + printk("%s before(%d),current(%d) \n",__func__,regulator_demo_data->regulator_demo_value,regulator_demo_value); + regulator_demo_data->regulator_demo_value=regulator_demo_value; + + if (regulator_count_voltages(regulator_demo_data->regulator_demo) > 0) { + ret = regulator_set_voltage(regulator_demo_data->regulator_demo, regulator_demo_value, regulator_demo_value); + if (ret) { + pr_err( "Regulator set demo fail rc = %d\n", ret); + goto regulator_demo_put; + } + + ret = regulator_set_load(regulator_demo_data->regulator_demo, 200000); + if (ret < 0) { + pr_err( "Failed to set demo mode(rc:%d)\n", ret); + goto regulator_demo_put; + } + } +regulator_demo_put: + return count; +} + +static int regulator_demo_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, regulator_demo_state_show, regulator_demo_data); +} + +static const struct file_operations regulator_demo_state_proc_fops = { + .owner = THIS_MODULE, + .open = regulator_demo_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = regulator_demo_state_write, +}; + +static int regulator_demo_init(struct platform_device *pdev) +{ + int ret = 0; + printk("%s \n",__func__); + + regulator_demo_data->regulator_demo = regulator_get(&pdev->dev, "regulator_demo"); + if (IS_ERR_OR_NULL(regulator_demo_data->regulator_demo)) { + pr_err("Regulator get failed vcc_1v8, ret = %d\n", ret); + } else { + if (regulator_count_voltages(regulator_demo_data->regulator_demo) > 0) { + ret = regulator_set_voltage(regulator_demo_data->regulator_demo, 2000000, 2000000); + if (ret) { + pr_err( "Regulator set_vtg failed vcc_i2c rc = %d\n", ret); + goto regulator_demo_put; + } + + ret = regulator_set_load(regulator_demo_data->regulator_demo, 200000); + if (ret < 0) { + pr_err( "Failed to set vcc_1v8 mode(rc:%d)\n", ret); + goto regulator_demo_put; + } + } + } + + return 0; + +regulator_demo_put: + regulator_put(regulator_demo_data->regulator_demo); + regulator_demo_data->regulator_demo = NULL; + return ret; +} + + +static int regulator_demo_dev_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int error=0; + + printk(KERN_ERR"%s\n",__func__); + + regulator_demo_data = kzalloc(sizeof(struct regulator_demo_dev_data), GFP_KERNEL); + regulator_demo_data->dev = dev; + + if (!proc_create_data("regulator_demo", 0666, NULL, ®ulator_demo_state_proc_fops, regulator_demo_data)) { + error = -ENOMEM; + goto err_set_regulator_demo; + } + + error= regulator_demo_init(pdev); + if (error < 0) { + printk(KERN_ERR "%s: regulator_demo_pinctrl_init, err=%d", __func__, error); + goto err_set_regulator_demo; + } + + printk("%s ok!\n",__func__); + return 0; + + err_set_regulator_demo: + kfree(regulator_demo_data); + return error; +} + +static int regulator_demo_dev_remove(struct platform_device *pdev) +{ + printk("%s\n",__func__); + return 0; +} + +static struct of_device_id regulator_demo_of_match[] = { + { .compatible = "oneplus,regulator_demo", }, + { }, +}; +MODULE_DEVICE_TABLE(of, regulator_demo_of_match); + +static struct platform_driver regulator_demo_dev_driver = { + .probe = regulator_demo_dev_probe, + .remove = regulator_demo_dev_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(regulator_demo_of_match), + }, +}; +module_platform_driver(regulator_demo_dev_driver); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("regulator_demo switch by driver"); + diff --git a/drivers/oneplus/misc/regulator_demo.txt b/drivers/oneplus/misc/regulator_demo.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed77c730499e82bec49c605bf987b82dd419b635 --- /dev/null +++ b/drivers/oneplus/misc/regulator_demo.txt @@ -0,0 +1,6 @@ +&soc { + regulator_demo { + compatible = "oneplus,regulator_demo"; + regulator_demo-supply = <&pm8150_s5>; + }; +}; diff --git a/drivers/oneplus/misc/wb_kernel_log.c b/drivers/oneplus/misc/wb_kernel_log.c new file mode 100644 index 0000000000000000000000000000000000000000..63734d216ef1a2193d4075dc96336d233f5d6e15 --- /dev/null +++ b/drivers/oneplus/misc/wb_kernel_log.c @@ -0,0 +1,404 @@ +/* + * This driver is used to reserve kernel log in kernel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wb_kernel_log.h" + +static struct task_struct *tsk; +static int wb_page_num; +static int while_times; +static bool no_data; +static DECLARE_COMPLETION(klog_record_lock); +static u32 buf_offset; +static u32 log_buf_offset; +static u32 log_text_offset; + +static void bio_done(struct bio *bio) +{ + bio_put(bio); + complete(&klog_record_lock); +} + +/* padding remain buf to full size content */ +static size_t padding_remain_buf(void *buf, void *src, size_t max_size, size_t current_size) +{ + if (buf == NULL || src == NULL) + return 0; + + memcpy(buf, src, max_size - current_size); + + return max_size - current_size; +} + +static size_t add_change_line(char *buf) +{ + if (buf == NULL) + return 0; + + *buf = '\n'; + return EOL_SIZE; +} + +static char *log_text_dup(const struct printk_log_dup *msg) +{ + return (char *)msg + sizeof(struct printk_log_dup); +} + +/* TODO: Handle read from head if kernel run out of printk buffer */ +static size_t do_log_copy(void *dst, void *src, size_t size) +{ + struct printk_log_dup *msg; + void *curr_dst, *curr_src; + size_t total_cp_size; + size_t cp_size; + + total_cp_size = 0; + while (total_cp_size <= size) { + msg = (struct printk_log_dup *)((char *)src + log_buf_offset); + curr_dst = dst + total_cp_size; + curr_src = log_text_dup(msg) + log_text_offset; + + /* out of printk log */ + if (msg->text_len == 0 && msg->len == 0) + return total_cp_size; + + /* count cp size per round */ + if (log_text_offset == NEED_EOL) { + total_cp_size += add_change_line((char *)curr_dst); + log_text_offset = 0; + log_buf_offset += msg->len; + continue; + } else + cp_size = msg->text_len - log_text_offset; + + /* padding remain buf and record src text offset */ + if (total_cp_size + cp_size + EOL_SIZE > size) { + log_text_offset += padding_remain_buf(curr_dst, curr_src, size, total_cp_size); + + /* checking spectial case of only lack a EOL */ + log_text_offset = (log_text_offset == msg->text_len)?NEED_EOL : log_text_offset; + return size; + } + + memcpy(curr_dst, curr_src, cp_size); + + log_buf_offset += msg->len; + total_cp_size += cp_size; + /* after memcpy curr_dst had change, re-count dst */ + total_cp_size += add_change_line((char *)dst + total_cp_size); + log_text_offset = 0; + } + + return total_cp_size; +} + +static void wb_a_page_log(struct block_device *bdev, int start_segment, char *buf) +{ + struct bio *w_bio; + struct gendisk *gd; + struct block_device *bd; + void *vaddr; + dev_t di; + int sector_offset; + int dummy; + u32 last_buf_offset; + static first_write = 1; + + /* + * if ((while_times + 1) >= LOG_TIME) + * pr_alert("Op_kernel_log: will sync finish\n"); + */ + + + vaddr = (void *)log_buf_addr_get(); + di = bdev->bd_dev; + + if (di == 0) { + pr_alert("Op_kernel_log: dev_t null\n"); + return; + } + + gd = get_gendisk(di, &dummy); + + if (gd == NULL) { + pr_alert("Op_kernel_log: gendisk null\n"); + return; + } + + /* write full page content to block last time, clean the buf */ + if (buf_offset == 0) + memset(buf, 0, LOG_PAGE_SIZE); + + last_buf_offset = buf_offset; + + /* copy printk buf to local buf from end of last */ + if(first_write) { + first_write = 0; + buf_offset += do_log_copy((void *)buf + buf_offset + 8, vaddr, LOG_PAGE_SIZE - buf_offset - 8); + buf[0] = '\n'; + buf[1] = 'O'; + buf[2] = 'P'; + buf[3] = 'L'; + buf[4] = 'O'; + buf[5] = 'G'; + buf[6] = '0' + start_segment; + buf[7] = '\n'; + } else + buf_offset += do_log_copy((void *)buf + buf_offset, vaddr, LOG_PAGE_SIZE - buf_offset); + + if (last_buf_offset == buf_offset) { + no_data = 1; + return; + } + w_bio = bio_map_kern(gd->queue, buf, LOG_PAGE_SIZE, GFP_KERNEL); + + if (IS_ERR(w_bio)) + return; + + bd = blkdev_get_by_dev(bdev->bd_dev, FMODE_READ|FMODE_WRITE, NULL); + sector_offset = ((HEADER_SHIFT + wb_page_num + start_segment * SEGMENT_SIZE) * 8); + + if (sector_offset >= SECTOR_OFFSET_MAXIMUM) + return; + + w_bio->bi_iter.bi_sector = + (bd->bd_part->start_sect) + sector_offset; + w_bio->bi_disk = bd->bd_disk; + w_bio->bi_end_io = bio_done; + w_bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH; + submit_bio(w_bio); + wait_for_completion(&klog_record_lock); + blkdev_put(bd, FMODE_READ|FMODE_WRITE); + + /* write full page content to block, write next page of block next time */ + if (buf_offset == LOG_PAGE_SIZE) { + wb_page_num++; + buf_offset = 0; + } +} + +static void do_wb_logs(struct block_device *bdev, int start_segment) +{ + char *buf = NULL; + + pr_alert("Op_kernel_log: start syncing\n"); + + buf = kmalloc(LOG_PAGE_SIZE, GFP_KERNEL); + if (!buf) { + pr_err("Op_kernel_log: allocate fail\n"); + return; + } + while (wb_page_num < SEGMENT_SIZE) { + while (!no_data) { + wb_a_page_log(bdev, start_segment, buf); + msleep(20); + } + no_data = 0; + while_times++; + //pr_alert("Op_kernel_log: times %d\n", while_times); + if (while_times >= LOG_TIME) { + pr_alert("Op_kernel_log: sync finish\n"); + break; + } + msleep(500); + } + if (buf != NULL) { + kfree(buf); + buf = NULL; + } +} + + +static void wb_header(struct block_device *bdev, char *buf) +{ + struct bio *w_bio; + struct gendisk *gd; + struct block_device *bd; + dev_t di; + int dummy; + + di = bdev->bd_dev; + + if (di == 0) { + pr_alert("Op_kernel_log: dev_t null\n"); + return; + } + + gd = get_gendisk(di, &dummy); + + if (gd == NULL) { + pr_alert("Op_kernel_log: gendisk null\n"); + return; + } + + w_bio = bio_map_kern(gd->queue, buf, LOG_PAGE_SIZE, GFP_KERNEL); + + if (IS_ERR(w_bio)) { + kfree(buf); + return; + } + + bd = blkdev_get_by_dev(bdev->bd_dev, FMODE_READ|FMODE_WRITE, NULL); + + w_bio->bi_iter.bi_sector = bd->bd_part->start_sect; + w_bio->bi_disk = bd->bd_disk; + w_bio->bi_end_io = bio_done; + w_bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH; + submit_bio(w_bio); + wait_for_completion(&klog_record_lock); + blkdev_put(bd, FMODE_READ|FMODE_WRITE); +} + +static int parser_log_head(char *buf) +{ + char opheader[HEADER_SIZE]; + unsigned char bootcount = 0; + const char start_count = 0; + const char op_log_header[11] = "OPKERNELLOG"; + int offset; + int ret; + + offset = offsetof(struct log_segment_status, OPlogheader); + memcpy(opheader, buf + offset, sizeof(((struct log_segment_status *)0)->OPlogheader)); + ret = memcmp(opheader, op_log_header, HEADER_SIZE); + if (ret == 0) { + pr_err("Op_kernel_log: found header\n"); + offset = offsetof(struct log_segment_status, klog_boot_count); + memcpy(&bootcount, (buf + offset), sizeof(((struct log_segment_status *)0)->klog_boot_count)); + bootcount++; + pr_err("Op_kernel_log: bootcount %d\n", (int)bootcount); + memcpy((buf + offset), &bootcount, sizeof(((struct log_segment_status *)0)->klog_boot_count)); + return (bootcount % RECORD_MAXIMUM); + + } else { + pr_err("Op_kernel_log: not find header\n"); + memset(buf, 0, LOG_SECTOR_SIZE); + offset = offsetof(struct log_segment_status, OPlogheader); + memcpy(buf, op_log_header, sizeof(((struct log_segment_status *)0)->OPlogheader)); + offset = offsetof(struct log_segment_status, klog_boot_count); + memcpy(buf + offset, &start_count, sizeof(((struct log_segment_status *)0)->klog_boot_count)); + return 0; + } + return 0; +} + +static char *read_log_header(struct block_device *bdev) +{ + struct bio *r_bio; + struct gendisk *gd; + struct block_device *bd; + dev_t di; + char *buf = NULL; + int dummy; + + di = bdev->bd_dev; + + pr_alert("Op_kernel_log: read log header\n"); + if (di == 0) { + pr_err("Op_kernel_log: dev_t null\n"); + return NULL; + } + + gd = get_gendisk(di, &dummy); + + if (gd == NULL) { + pr_err("Op_kernel_log: gendisk null\n"); + return NULL; + } + + buf = kmalloc(LOG_SECTOR_SIZE, GFP_KERNEL); + if (!buf) + return NULL; + + memset(buf, 0, LOG_SECTOR_SIZE); + r_bio = bio_map_kern(gd->queue, buf, LOG_SECTOR_SIZE, GFP_KERNEL); + + bd = blkdev_get_by_dev(bdev->bd_dev, FMODE_READ|FMODE_WRITE, NULL); + r_bio->bi_iter.bi_sector = (bd->bd_part->start_sect); + r_bio->bi_disk = bd->bd_disk; + r_bio->bi_end_io = bio_done; + r_bio->bi_opf = READ | REQ_SYNC; + + submit_bio(r_bio); + wait_for_completion(&klog_record_lock); + blkdev_put(bd, FMODE_READ|FMODE_WRITE); + return buf; +} + + +static int kernel_log_wb_main(void *arg) +{ + struct block_device *log_partition = NULL; + char *buf = NULL; + int start_segment; + int retry_count = 20; + + pr_alert("Op_kernel_log: find reserve partition\n"); + while (log_partition == NULL && retry_count > 0) { + retry_count--; + pr_err("Op_kernel_log: bdev null, retry count %d\n", retry_count); + msleep(20); + log_partition = find_reserve_partition(); + } + + if(retry_count <= 0 || log_partition == NULL) { + pr_err("Op_kernel_log: bdev null and retry count = 0, stop record log\n"); + return 0; + } + + buf = read_log_header(log_partition); + + if (buf == NULL) + return 0; + + start_segment = parser_log_head(buf); + pr_alert("Op_kernel_log: start_segment %d\n", start_segment); + wb_header(log_partition, buf); + do_wb_logs(log_partition, start_segment); + + if (tsk) + kthread_stop(tsk); + tsk = NULL; + return 1; +} + + +static int kernel_log_wb_init(void) +{ + if (get_boot_mode() == MSM_BOOT_MODE_FASTBOOT + || get_boot_mode() == MSM_BOOT_MODE_RECOVERY) { + pr_alert("Op_kernel_log: No logging mode %d\n", get_boot_mode()); + return 0; + } + wb_page_num = 0; + while_times = 0; + no_data = 0; + buf_offset = 0; + log_buf_offset = 0; + log_text_offset = 0; + + pr_alert("Op_kernel_log: kernel_log_wb_int1\n"); + tsk = kthread_run(kernel_log_wb_main, NULL, "Op_kernel_log"); + if (!tsk) + pr_err("Op_kernel_log: kthread init failed\n"); + pr_alert("Op_kernel_log: init done\n"); + return 0; +} + +module_init(kernel_log_wb_init); diff --git a/drivers/oneplus/misc/wb_kernel_log.h b/drivers/oneplus/misc/wb_kernel_log.h new file mode 100644 index 0000000000000000000000000000000000000000..d0f0db7a32dd8268c62fd1a089a70c2ee0a2d141 --- /dev/null +++ b/drivers/oneplus/misc/wb_kernel_log.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _WB_KERNEL_LOG_H +#define _WB_KERNEL_LOG_H + +#define LOG_PAGE_SIZE 4096 +#define LOG_SECTOR_SIZE 4096 +#define SEGMENT_SIZE 256 //256 * LOG_PAGE_SIZE +#define LOG_TIME 120 //LOG_TINE * 500ms +#define HEADER_SHIFT 1 //LOG_TINE * 500ms +#define RECORD_MAXIMUM 7 +#define HEADER_SIZE 7 +#define SECTOR_OFFSET_MAXIMUM 16192 +#define EOL_SIZE 1 +#define NEED_EOL 0xffffffff + +struct log_segment_status { + char OPlogheader[HEADER_SIZE]; + char klog_boot_count; +}; + +struct printk_log_dup { + u64 ts_nsec; /* timestamp in nanoseconds */ + u16 len; /* length of entire record */ + u16 text_len; /* length of text buffer */ + u16 dict_len; /* length of dictionary buffer */ + u8 facility; /* syslog facility */ + u8 flags:5; /* internal record flags */ + u8 level:3; /* syslog level */ +}; + +#endif diff --git a/drivers/oneplus/mm/Kconfig b/drivers/oneplus/mm/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..f84322fabfc36cfd00489f2deef109caa4c1fb3c --- /dev/null +++ b/drivers/oneplus/mm/Kconfig @@ -0,0 +1,5 @@ +config ONEPLUS_MEM_MONITOR + bool "memory monitor " + default n + help + memory monitor. diff --git a/drivers/oneplus/mm/Makefile b/drivers/oneplus/mm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4d2458ce80dd80d7dd9b31e063c5db288b4798bb --- /dev/null +++ b/drivers/oneplus/mm/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ONEPLUS_MEM_MONITOR) += memory_monitor.o diff --git a/drivers/oneplus/mm/memory_monitor.c b/drivers/oneplus/mm/memory_monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..5bb5a9d5d4fc5b5a445d45b734c04c73ff52fa29 --- /dev/null +++ b/drivers/oneplus/mm/memory_monitor.c @@ -0,0 +1,94 @@ +/* + *Copyright (c) 2018 OnePlus Mobile Comm Corp., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../mm/internal.h" +#include +#include + +struct alloc_wait_para allocwait_para = {0, 0, 0, 0, 0, 0, 0, 0}; + +#ifdef CONFIG_ONEPLUS_HEALTHINFO +extern bool ohm_memmon_ctrl; +extern bool ohm_memmon_logon; +extern bool ohm_memmon_trig; +extern void ohm_action_trig(int type); +#else +static bool ohm_memmon_ctrl; +static bool ohm_memmon_logon; +static bool ohm_memmon_trig; +void ohm_action_trig(int type) +{ + return; +} +#endif + +static int alloc_wait_h_ms = 50; +static int alloc_wait_l_ms = 10; +static int alloc_wait_log_ms = 1000; +static int alloc_wait_trig_ms = 10000; + +void memory_alloc_monitor(gfp_t gfp_mask, unsigned int order, u64 wait_ms) +{ + int fg = 0; + if (!ohm_memmon_ctrl) + return; + + fg = current_is_fg(); + if (fg) { + if (wait_ms >= alloc_wait_h_ms) { + allocwait_para.fg_alloc_wait_h_cnt++; + } else if (wait_ms >= alloc_wait_l_ms) { + allocwait_para.fg_alloc_wait_l_cnt++; + } + if (allocwait_para.fg_alloc_wait_max_ms < wait_ms) { + allocwait_para.fg_alloc_wait_max_ms = wait_ms; + allocwait_para.fg_alloc_wait_max_order = order; + } + } + + if (wait_ms >= alloc_wait_h_ms) { + allocwait_para.total_alloc_wait_h_cnt++; + if (ohm_memmon_logon && (wait_ms >= alloc_wait_log_ms)) { + ohm_debug("[alloc_wait / %s] long, order %d, wait %lld ms!\n", + (fg ? "fg":"bg"), order, wait_ms); + warn_alloc(gfp_mask, NULL, "page allocation stalls for %lld ms, order: %d", + wait_ms, order); + } + if (ohm_memmon_trig && wait_ms >= alloc_wait_trig_ms) { + /* Trig Uevent */ + ohm_action_trig(OHM_MEM_MON); + } + } else if (wait_ms >= alloc_wait_l_ms) { + allocwait_para.total_alloc_wait_l_cnt++; + } + if (allocwait_para.total_alloc_wait_max_ms < wait_ms) { + allocwait_para.total_alloc_wait_max_ms = wait_ms; + allocwait_para.total_alloc_wait_max_order = order; + } +} + +module_param_named(alloc_wait_h_ms, alloc_wait_h_ms, int, S_IRUGO | S_IWUSR); +module_param_named(alloc_wait_l_ms, alloc_wait_l_ms, int, S_IRUGO | S_IWUSR); +module_param_named(alloc_wait_log_ms, alloc_wait_log_ms, int, S_IRUGO | S_IWUSR); +module_param_named(alloc_wait_trig_ms, alloc_wait_trig_ms, int, S_IRUGO | S_IWUSR); diff --git a/drivers/oneplus/oneplus_healthinfo/Kconfig b/drivers/oneplus/oneplus_healthinfo/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..2fabc4d50e934db6fdae842c1d812b71327a93d7 --- /dev/null +++ b/drivers/oneplus/oneplus_healthinfo/Kconfig @@ -0,0 +1,12 @@ +config ONEPLUS_HEALTHINFO + depends on OPCHAIN + default n + bool "config oneplus healthinfo" + help + define this config to init oneplus healthinfo. +config ONEPLUS_TASKLOAD_INFO + bool "config oneplus healthinfo" + depends on ONEPLUS_HEALTHINFO + default y + help + define this config to init oneplus taskload info. diff --git a/drivers/oneplus/oneplus_healthinfo/Makefile b/drivers/oneplus/oneplus_healthinfo/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9f5e4add6da9d16d4baeec4de18f8fe5a16d9c5a --- /dev/null +++ b/drivers/oneplus/oneplus_healthinfo/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ONEPLUS_HEALTHINFO) += oneplus_healthinfo.o diff --git a/drivers/oneplus/oneplus_healthinfo/oneplus_healthinfo.c b/drivers/oneplus/oneplus_healthinfo/oneplus_healthinfo.c new file mode 100644 index 0000000000000000000000000000000000000000..9be1540393bdbf34e3759c05d5bf7c35f075b28a --- /dev/null +++ b/drivers/oneplus/oneplus_healthinfo/oneplus_healthinfo.c @@ -0,0 +1,1768 @@ +/********************************************************************************** +* Copyright (c) 2008-2015 OnePlus Mobile Comm Corp., Ltd +* VENDOR_EDIT +* Description: Healthinfo Monitor Kernel Driver +* +* Version : 1.0 +* Date : 2019-04-24 +* Author : jared.wu@PSP +* ------------------------------ Revision History: -------------------------------- +* +* Revision 1.0 2018-04-24 jared.wu@PSP Created for Healthinfomonitor +***********************************************************************************/ + +#include +#include +#include +#include +#include +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +#include +#include +#endif +#ifdef CONFIG_ONEPLUS_MEM_MONITOR +#include +#endif +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +#include +#include "../../../../kernel/sched/sched.h" +#include "../../../../kernel/sched/walt.h" +#include "../../../../include/linux/cred.h" + +struct io_latency_para{ + bool ctrl; + bool logon; + bool trig; + + int low_thresh_ms; + u64 low_cnt; + + int high_thresh_ms; + u64 high_cnt; + + u64 total_us; + u64 emmc_total_us; + u64 total_cnt; + u64 fg_low_cnt; + u64 fg_high_cnt; + u64 fg_total_ms; + u64 fg_total_cnt; + u64 fg_max_delta_ms; + u64 delta_ms; + + //fg + u64 iosize_write_count_fg; + u64 iosize_write_us_fg; + u64 iosize_500ms_syncwrite_count_fg; + u64 iosize_200ms_syncwrite_count_fg; + u64 iosize_500ms_asyncwrite_count_fg; + u64 iosize_200ms_asyncwrite_count_fg; + u64 iosize_read_count_fg; + u64 iosize_read_us_fg; + u64 iosize_500ms_read_count_fg; + u64 iosize_200ms_read_count_fg; + + //bg + u64 iosize_write_count_bg; + u64 iosize_write_us_bg; + u64 iosize_2s_asyncwrite_count_bg; + u64 iosize_500ms_asyncwrite_count_bg; + u64 iosize_200ms_asyncwrite_count_bg; + u64 iosize_2s_syncwrite_count_bg; + u64 iosize_500ms_syncwrite_count_bg; + u64 iosize_200ms_syncwrite_count_bg; + u64 iosize_read_count_bg; + u64 iosize_read_us_bg; + u64 iosize_2s_read_count_bg; + u64 iosize_500ms_read_count_bg; + u64 iosize_200ms_read_count_bg; + + //4k + u64 iosize_4k_read_count; + u64 iosize_4k_read_us; + u64 iosize_4k_write_count; + u64 iosize_4k_write_us; +}; + +struct io_latency_para oneplus_io_para; + +#define BUFFER_SIZE_S 256 +#define BUFFER_SIZE_M 512 +#define BUFFER_SIZE_L 1024 + +/* rt info monitor */ +bool rt_info_ctrl; +u64 rt_low_thresh = DEFAULT_RT_LT; +u64 rt_high_thresh = DEFAULT_RT_HT; + +struct sched_stat_rt_para rt_para[NR_CPUS]; +struct cpu_preempt_stat preempt_para[NR_CPUS]; + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +static struct timer_list task_load_info_timer; +u64 ohm_read_thresh = 1048576; /* default 1MB per 5s */ +u64 ohm_write_thresh = 1048576; /* default 1MB per 5s */ +u64 ohm_runtime_thresh_fg = 4000000000; /* default 4s per 5s */ +u64 ohm_runtime_thresh_bg = 1500000000; /* default 1.5s per 5s */ +static u32 ohm_sample_time = 5; /* default 5s */ +#endif + +struct sched_stat_para oneplus_sched_para[OHM_SCHED_TOTAL]; +static char *sched_list[OHM_TYPE_TOTAL] = { + /* SCHED_STATS 0 -11 */ + "iowait", + "sched_latency", + "fsync", + "emmcio", + "downread", + "downwrite", + /*2020-06-22 ,OSP-5970 , monitor cpu info **/ + "dstate", + "sched_default_05", + "sched_default_06", + "sched_default_07", + "sched_default_10", + "sched_default_11", + /* OTHER_TYPE 12 - */ + "cur_cpu_load", + "memory_monitor", + "io_panic", + "rt_info", + "preempt_latency" +}; + +/****** Action ******/ +#define MAX_OHMEVENT_PARAM 4 +#define TRIG_MIN_INTERVAL 400 +static struct kobject *ohm_kobj; +static char *ohm_detect_env[MAX_OHMEVENT_PARAM] = { "OHMACTION=uevent", NULL }; +static bool ohm_action_ctrl; +static unsigned long last_trig; +static unsigned long iowait_summ_start; +static int iowait_summ_period; +static int iowait_summ_thresh; +static int iowait_total; +static bool iowait_summ_reset = true; + +static atomic_t ohm_scheduled; +static struct kthread_worker __rcu *ohm_kworker; +static struct kthread_delayed_work ohm_work; + +void ohm_action_trig(int type) +{ + struct kthread_worker *kworker; + + if (!ohm_action_ctrl) { + ohm_err_deferred("ctrl off\n"); + return; + } + ohm_debug_deferred("%s trig action\n", sched_list[type]); + if (OHM_MEM_MON == type || OHM_SCHED_FSYNC == type) { + if (!ohm_kobj) { + ohm_err_deferred("kobj NULL\n"); + return; + } + if (atomic_cmpxchg(&ohm_scheduled, 0, 1) != 0) + return; + sprintf(ohm_detect_env[1], "OHMTYPE=%s", sched_list[type]); + sprintf(ohm_detect_env[2], "NOLEVEL"); + ohm_detect_env[MAX_OHMEVENT_PARAM - 1] = NULL; + rcu_read_lock(); + kworker = rcu_dereference(ohm_kworker); + if (likely(kworker)) + kthread_queue_delayed_work(kworker, &ohm_work, msecs_to_jiffies(1)); + rcu_read_unlock(); + } +} + +void ohm_action_trig_level(int type, bool highlevel) +{ + struct kthread_worker *kworker; + + if (!ohm_action_ctrl) { + ohm_err_deferred("ctrl off\n"); + return; + } + ohm_debug_deferred("%s trig action\n", sched_list[type]); + if (OHM_MEM_MON == type || OHM_SCHED_FSYNC == type || OHM_SCHED_IOWAIT == type) { + if (!ohm_kobj) { + ohm_err_deferred("kobj NULL\n"); + return; + } + if (!time_after(jiffies, last_trig + msecs_to_jiffies(TRIG_MIN_INTERVAL))) + return; + if (atomic_cmpxchg(&ohm_scheduled, 0, 1) != 0) + return; + ohm_debug_deferred("%s trig action\n", sched_list[type]); + sprintf(ohm_detect_env[1], "OHMTYPE=%s", sched_list[type]); + sprintf(ohm_detect_env[2], "OHMLEVEL=%s", highlevel?"HIGH":"LOW"); + ohm_detect_env[MAX_OHMEVENT_PARAM - 1] = NULL; + rcu_read_lock(); + kworker = rcu_dereference(ohm_kworker); + if (likely(kworker)) + kthread_queue_delayed_work(kworker, &ohm_work, msecs_to_jiffies(1)); + rcu_read_unlock(); + last_trig = jiffies; + } +} + +void ohm_detect_work(struct kthread_work *work) +{ + ohm_debug_deferred("Uevent Para: %s, %s\n", ohm_detect_env[0], ohm_detect_env[1]); + kobject_uevent_env(ohm_kobj, KOBJ_CHANGE, ohm_detect_env); + ohm_debug_deferred("Uevent Done!\n"); + atomic_set(&ohm_scheduled, 0); +} + +void ohm_action_init(void) +{ + int i = 0; + struct kthread_worker *kworker; + + for (i = 1; i < MAX_OHMEVENT_PARAM - 1; i++) { + ohm_detect_env[i] = kzalloc(50, GFP_KERNEL); + if (!ohm_detect_env[i]) { + ohm_err("kzalloc ohm uevent param failed\n"); + goto ohm_action_init_free_memory; + } + } + + ohm_kobj = kset_find_obj(module_kset, KBUILD_MODNAME); + if (!ohm_kobj) { + goto ohm_action_init_kobj_failed; + } + last_trig = jiffies; + kworker = kthread_create_worker(0, "healthinfo"); + if (IS_ERR(kworker)) { + goto ohm_action_init_free_memory; + } + kthread_init_delayed_work(&ohm_work, ohm_detect_work); + rcu_assign_pointer(ohm_kworker, kworker); + atomic_set(&ohm_scheduled, 0); + ohm_debug("Success !\n"); + return; + +ohm_action_init_kobj_failed: + ohm_err("Ohm kobj init err\n"); +ohm_action_init_free_memory: + for (i--; i > 0; i--) { + kfree(ohm_detect_env[i]); + } + ohm_err("Failed !\n"); +} + +/****** Sched record ******/ +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +static inline void ohm_sched_stat_record_common(struct sched_stat_para *sched_stat,struct sched_stat_common *stat_common, u64 delta_ms) +{ + stat_common->total_ms += delta_ms; + stat_common->total_cnt++; + if (delta_ms > stat_common->max_ms) { + stat_common->max_ms = delta_ms; + } + if (delta_ms >= sched_stat->high_thresh_ms) { + stat_common->high_cnt++; + } else if (delta_ms >= sched_stat->low_thresh_ms) { + stat_common->low_cnt++; + } +} + +void ohm_schedstats_record(int sched_type, struct task_struct *task, u64 delta_ms) +{ + + struct sched_stat_para *sched_stat = &oneplus_sched_para[sched_type]; + + if (unlikely(!sched_stat->ctrl)){ + return; + } + + sched_stat->delta_ms = delta_ms; + ohm_sched_stat_record_common(sched_stat, &sched_stat->all, delta_ms); + + if (task_is_fg(task)) { + ohm_sched_stat_record_common(sched_stat, &sched_stat->fg, delta_ms); + if (sched_type == OHM_SCHED_IOWAIT) { + if (time_after(jiffies, iowait_summ_start + msecs_to_jiffies(iowait_summ_period)) || iowait_summ_reset) { + iowait_total = delta_ms; + iowait_summ_start = jiffies - msecs_to_jiffies(delta_ms); + iowait_summ_reset = false; + } else { + iowait_total += delta_ms; + } + } + if (unlikely(delta_ms >= sched_stat->high_thresh_ms)){ + if (oneplus_sched_para[sched_type].logon) { + ohm_debug_deferred("[%s / %s] high_cnt, delay = %llu ms\n", + sched_list[sched_type], "fg", delta_ms); + } + + if (oneplus_sched_para[sched_type].trig) + ohm_action_trig_level(sched_type, true); + + } else if (delta_ms >= sched_stat->low_thresh_ms) { + if (oneplus_sched_para[sched_type].trig) + ohm_action_trig_level(sched_type, false); + } else if (iowait_total >= iowait_summ_thresh) { + iowait_summ_reset = true; + if (oneplus_sched_para[sched_type].trig) + ohm_action_trig_level(sched_type, false); + } + } + + return; +} + +void ohm_overload_record(struct rq *rq, u64 delta) +{ + struct sched_stat_para *sched_stat = NULL; + sched_stat = rq->cluster->overload; + sched_stat->delta_ms = delta; + ohm_sched_stat_record_common(sched_stat, &sched_stat->all, delta); + return; +} +static inline void ohm_preempt_stat_record_common(struct cpu_preempt_stat *sched_stat,struct sched_stat_common *stat_common, u64 delta_ms) +{ + stat_common->total_ms += delta_ms; + stat_common->total_cnt++; + + if (delta_ms > stat_common->max_ms) { + stat_common->max_ms = delta_ms; + } + + if (delta_ms >= sched_stat->high_thresh_ms) { + stat_common->high_cnt++; + } else if (delta_ms >= sched_stat->low_thresh_ms) { + stat_common->low_cnt++; + } + +} + +void ohm_preempt_record(u64 delta,int cpu) +{ + struct cpu_preempt_stat *preempt_stat = &preempt_para[cpu]; + + if (!preempt_stat) + return ; + + ohm_preempt_stat_record_common(preempt_stat,&(preempt_stat->preempt_common),delta); + return ; + +} + +struct irq_latency_para irq_latency_stat[NR_CPUS]; +void ohm_irqsoff_record(u64 delta, int cpu) +{ + irq_latency_stat[cpu].total += delta; + irq_latency_stat[cpu].total_cnt++; + + if (delta > irq_latency_stat[cpu].max) { + irq_latency_stat[cpu].max = delta; + } + + if (delta >= irq_latency_stat[cpu].high_thresh) { + irq_latency_stat[cpu].high_cnt++; + } else if (delta >= irq_latency_stat[cpu].low_thresh) { + irq_latency_stat[cpu].low_cnt++; + } +} + + +/****** stuck info read start ******/ +/* 2020-06-17, add for stuck monitor*/ +void update_stuck_trace_info(struct task_struct *tsk, int trace_type, unsigned int cpu, u64 delta) +{ + + static unsigned int ltt_cpu_nr = 0; + /* this just for 8150,4+3+1*/ + static unsigned int mid_cpu_end = 6; + static unsigned int big_cpu_end = 7; + + if (!tsk->stuck_trace) { + return; + } + + if (!ltt_cpu_nr) { + ltt_cpu_nr = cpumask_weight(topology_core_cpumask(ltt_cpu_nr)); + printk("fuyou_update_stuck_trace_info ltt_cpu_nr = %u",ltt_cpu_nr); + } + + if (trace_type == STUCK_TRACE_RUNNABLE) { // runnable + tsk->oneplus_stuck_info.runnable_state += delta; + } else if (trace_type == STUCK_TRACE_DSTATE) { // D state + tsk->oneplus_stuck_info.d_state.cnt++; + if (tsk->in_iowait) { + tsk->oneplus_stuck_info.d_state.iowait_ns += delta; + } else if (tsk->in_mutex) { + tsk->oneplus_stuck_info.d_state.mutex_ns += delta; + } else if (tsk->in_downread) { + tsk->oneplus_stuck_info.d_state.downread_ns += delta; + } else if (tsk->in_downwrite) { + tsk->oneplus_stuck_info.d_state.downwrite_ns += delta; + } else { + tsk->oneplus_stuck_info.d_state.other_ns += delta; + } + } else if (trace_type == STUCK_TRACE_SSTATE) { // S state + tsk->oneplus_stuck_info.s_state.cnt++; + if (tsk->in_binder) { + tsk->oneplus_stuck_info.s_state.binder_ns += delta; + } else if (tsk->in_futex) { + tsk->oneplus_stuck_info.s_state.futex_ns += delta; + } else if (tsk->in_epoll) { + tsk->oneplus_stuck_info.s_state.epoll_ns += delta; + } else { + tsk->oneplus_stuck_info.s_state.other_ns += delta; + } + } else if (trace_type == STUCK_TRACE_RUNNING) { // running + if (cpu < ltt_cpu_nr) { + tsk->oneplus_stuck_info.ltt_running_state += delta; + } else if (cpu <= mid_cpu_end) { + tsk->oneplus_stuck_info.mid_running_state += delta; + } else if (cpu == big_cpu_end) { + tsk->oneplus_stuck_info.big_running_state += delta; + } + } +} + +/****** Flash IO Latency record ******/ +void ohm_iolatency_record(struct request *req, unsigned int nr_bytes, int fg, u64 delta_us) +{ + u64 delta_ms = delta_us / 1000; + + if (!oneplus_io_para.ctrl) + return; + if (!req) + return; + if (fg) + { + oneplus_io_para.fg_total_ms += delta_ms; + oneplus_io_para.fg_total_cnt++; + if (delta_ms > oneplus_io_para.fg_max_delta_ms) + { + oneplus_io_para.fg_max_delta_ms = delta_ms; + } + } + + if (delta_ms >= oneplus_io_para.high_thresh_ms) + { + oneplus_io_para.high_cnt++; + + if (oneplus_io_para.logon) + { + ohm_debug("[io latency / %s] high_cnt, delay = %llu ms\n", + (fg ? "fg" : "bg"), delta_ms); + } + if (fg) + { + oneplus_io_para.fg_high_cnt++; + if (oneplus_io_para.trig) + ohm_action_trig(OHM_SCHED_EMMCIO); + } + } + else if (delta_ms >= oneplus_io_para.low_thresh_ms) + { + oneplus_io_para.low_cnt++; + if (fg) + { + oneplus_io_para.fg_low_cnt++; + } + } + + if (fg) + { + if ((req_op(req) != REQ_OP_DISCARD) && (req_op(req) != REQ_OP_SECURE_ERASE)) + { + if (req_op(req) == REQ_OP_WRITE || req_op(req) == REQ_OP_WRITE_SAME) + { + oneplus_io_para.iosize_write_count_fg++; + oneplus_io_para.iosize_write_us_fg += delta_us; + if (rq_is_sync(req)) + { + if (delta_ms > 500) + { + oneplus_io_para.iosize_500ms_syncwrite_count_fg++; + } + else if (delta_ms > 200) + { + oneplus_io_para.iosize_200ms_syncwrite_count_fg++; + } + } + else + { + if (delta_ms > 500) + { + oneplus_io_para.iosize_500ms_asyncwrite_count_fg++; + } + else if (delta_ms > 200) + { + oneplus_io_para.iosize_200ms_asyncwrite_count_fg++; + } + } + } + else + { + oneplus_io_para.iosize_read_count_fg++; + oneplus_io_para.iosize_read_us_fg += delta_us; + if (delta_ms > 500) + { + oneplus_io_para.iosize_500ms_read_count_fg++; + } + else if (delta_ms > 200) + { + oneplus_io_para.iosize_200ms_read_count_fg++; + } + } + } + } + else + { + if ((req_op(req) != REQ_OP_DISCARD) && (req_op(req) != REQ_OP_SECURE_ERASE)) + { + if (req_op(req) == REQ_OP_WRITE || req_op(req) == REQ_OP_WRITE_SAME) + { + oneplus_io_para.iosize_write_count_bg++; + oneplus_io_para.iosize_write_us_bg += delta_us; + if (rq_is_sync(req)) + { + if (delta_ms > 2000) + { + oneplus_io_para.iosize_2s_syncwrite_count_bg++; + if (oneplus_io_para.trig) + ohm_action_trig(OHM_SCHED_EMMCIO); + } + else if (delta_ms > 500) + { + oneplus_io_para.iosize_500ms_syncwrite_count_bg++; + } + else if (delta_ms > 200) + { + oneplus_io_para.iosize_200ms_syncwrite_count_bg++; + } + } + else + { + if (delta_ms > 2000) + { + oneplus_io_para.iosize_2s_asyncwrite_count_bg++; + if (oneplus_io_para.trig) + ohm_action_trig(OHM_SCHED_EMMCIO); + } + else if (delta_ms > 500) + { + oneplus_io_para.iosize_500ms_asyncwrite_count_bg++; + } + else if (delta_ms > 200) + { + oneplus_io_para.iosize_200ms_asyncwrite_count_bg++; + } + } + } + else + { + oneplus_io_para.iosize_read_count_bg++; + oneplus_io_para.iosize_read_us_bg += delta_us; + if (delta_ms > 2000) + { + oneplus_io_para.iosize_2s_read_count_bg++; + if (oneplus_io_para.trig) + ohm_action_trig(OHM_SCHED_EMMCIO); + } + else if (delta_ms > 500) + { + oneplus_io_para.iosize_500ms_read_count_bg++; + } + else if (delta_ms > 200) + { + oneplus_io_para.iosize_200ms_read_count_bg++; + } + } + } + } + //4k + if ((req_op(req) != REQ_OP_DISCARD) && (req_op(req) != REQ_OP_SECURE_ERASE)) + { + if (req_op(req) == REQ_OP_WRITE || req_op(req) == REQ_OP_WRITE_SAME) + { + if (blk_rq_bytes(req) == 4096) + { + oneplus_io_para.iosize_4k_write_count++; + oneplus_io_para.iosize_4k_write_us += delta_us; + } + } + else + { + if (blk_rq_bytes(req) == 4096) + { + oneplus_io_para.iosize_4k_read_count++; + oneplus_io_para.iosize_4k_read_us += delta_us; + } + } + } + oneplus_io_para.delta_ms = delta_ms; + oneplus_io_para.total_us += delta_us; + oneplus_io_para.emmc_total_us += req->flash_io_latency; + oneplus_io_para.total_cnt++; + + return; +} + +/**** Ctrl init ****/ +/* + CTRL - TOTAL -32 + CTRL0: logon +iowait record; + + CTRL1: +sched latency; + + CTRL2: logon trig +fsync record; + + CTRL3: +emmcio record; + ****** + ****** + CTRL12: +cpu load cur; + + CTRL13: logon trig +mem mon; +......; +......; + CTRL31: +......; +*/ +#define OHM_LIST_MAGIC 0x5a000000 +#define OHM_CTRL_MAX 32 +#define OHM_INT_MAX 20 +#define OHM_CTRL_IOWAIT BIT(OHM_SCHED_IOWAIT) +#define OHM_CTRL_SCHEDLATENCY BIT(OHM_SCHED_SCHEDLATENCY) +#define OHM_CTRL_FSYNC BIT(OHM_SCHED_FSYNC) +#define OHM_CTRL_EMMCIO BIT(OHM_SCHED_EMMCIO) +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +#define OHM_CTRL_DSTATE BIT(OHM_SCHED_DSTATE) +#define OHM_CTRL_SCHEDTOTAL (OHM_CTRL_EMMCIO | OHM_CTRL_FSYNC | OHM_CTRL_SCHEDLATENCY | OHM_CTRL_IOWAIT | OHM_CTRL_DSTATE) +#define OHM_CTRL_CPU_CUR BIT(OHM_CPU_LOAD_CUR) +#define OHM_CTRL_MEMMON BIT(OHM_MEM_MON) +#define OHM_CTRL_IOPANIC_MON BIT(OHM_IOPANIC_MON) + + +/* +ohm_ctrl_list = 0x5a0fffff +ohm_logon_list = 0x5a002005 +ohm_trig_list = 0x5a002000 +*/ + +/*Default*/ +static int ohm_ctrl_list = OHM_LIST_MAGIC | OHM_CTRL_CPU_CUR | OHM_CTRL_MEMMON | OHM_CTRL_SCHEDTOTAL; +static int ohm_logon_list = OHM_LIST_MAGIC; +static int ohm_trig_list = OHM_LIST_MAGIC | OHM_CTRL_IOWAIT; + +bool ohm_cpu_ctrl = true; +bool ohm_cpu_logon; +bool ohm_cpu_trig; + +bool ohm_memmon_ctrl; +bool ohm_memmon_logon; +bool ohm_memmon_trig; + +bool ohm_iopanic_mon_ctrl; +bool ohm_iopanic_mon_logon; +bool ohm_iopanic_mon_trig; +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +bool ohm_irqsoff_ctrl = false; +bool ohm_preempt_ctrl = true; +bool ohm_rtinfo_ctrl = false; + +/****** Para Update *****/ +#define LOW_THRESH_MS_DEFAULT 10 +#define HIGH_THRESH_MS_DEFAULT 50 +/* low thresh 10~1000ms*/ +#define LOW_THRESH_MS_LOW 10 +#define LOW_THRESH_MS_HIGH 1000 +/* high thresh 100~5000ms*/ +#define HIGH_THRESH_MS_LOW 50 +#define HIGH_THRESH_MS_HIGH 5000 + +struct thresh_para { + int l_ms; + int h_ms; +}; + +struct thresh_para ohm_thresh_para[OHM_SCHED_TOTAL] = { + { LOW_THRESH_MS_DEFAULT, HIGH_THRESH_MS_DEFAULT}, + { LOW_THRESH_MS_DEFAULT, HIGH_THRESH_MS_DEFAULT}, + { LOW_THRESH_MS_DEFAULT, HIGH_THRESH_MS_DEFAULT}, + { LOW_THRESH_MS_DEFAULT, HIGH_THRESH_MS_DEFAULT}, + { LOW_THRESH_MS_DEFAULT, HIGH_THRESH_MS_DEFAULT}, +}; + +void ohm_para_update(void) +{ + int i; + for (i = 0; i < OHM_SCHED_TOTAL; i++) { + if (ohm_thresh_para[i].l_ms < LOW_THRESH_MS_LOW + || ohm_thresh_para[i].l_ms > LOW_THRESH_MS_HIGH + || ohm_thresh_para[i].h_ms < HIGH_THRESH_MS_LOW + || ohm_thresh_para[i].h_ms > HIGH_THRESH_MS_HIGH) { + /********** Legal Check **********/ + ohm_err("Para illegal: sched_type %s, l_ms %d, h_ms %d\n", + sched_list[i], ohm_thresh_para[i].l_ms, ohm_thresh_para[i].h_ms); + ohm_thresh_para[i].l_ms = LOW_THRESH_MS_DEFAULT; + ohm_thresh_para[i].h_ms = HIGH_THRESH_MS_DEFAULT; + return; + } + oneplus_sched_para[i].low_thresh_ms = ohm_thresh_para[i].l_ms; + oneplus_sched_para[i].high_thresh_ms = ohm_thresh_para[i].h_ms; + } + ohm_debug("Success update ohm_para!\n"); +} + +/**** Init ****/ +static inline void ohm_rt_para_init(void) +{ + int i,j; + + for (i = 0; i < NR_CPUS; i++) { + rt_para[i].each_cpu_rt = 0; + rt_para[i].each_cpu_rt_total = 0; + for (j = 0 ;j < 3 ; j++) { + rt_para[i].thresh_cnt[j] = 0; + } + rt_para[i].lt_info = (struct longest_task_info*)kzalloc(sizeof(struct longest_task_info), GFP_ATOMIC); + } + ohm_rtinfo_ctrl = true; + return; +} +static inline void ohm_preempt_para_init(void) +{ + int i; + for(i = 0; i < NR_CPUS; i++){ + preempt_para[i].high_thresh_ms = 10; + preempt_para[i].low_thresh_ms = 1; + preempt_para[i].preempt_common.high_cnt = 0; + preempt_para[i].preempt_common.low_cnt = 0; + preempt_para[i].preempt_common.max_ms = 0; + preempt_para[i].preempt_common.total_cnt = 0; + preempt_para[i].preempt_common.total_ms = 0; + } + ohm_preempt_ctrl = true; + return ; +} +static inline void _ohm_para_init(struct sched_stat_para *sched_para) +{ + sched_para->delta_ms = 0; + memset(&sched_para->all, 0 , sizeof(struct sched_stat_common)); + memset(&sched_para->ux, 0 , sizeof(struct sched_stat_common)); + memset(&sched_para->fg, 0 , sizeof(struct sched_stat_common)); + + return; +} + +void ohm_trig_init(void) +{ + int i; + ohm_memmon_trig = (ohm_trig_list & OHM_CTRL_MEMMON) ? true : false; + ohm_cpu_trig = (ohm_trig_list & OHM_CTRL_CPU_CUR) ? true : false; + ohm_iopanic_mon_trig = (ohm_trig_list & OHM_CTRL_IOPANIC_MON) ? true : false; + for (i = 0; i < OHM_SCHED_TOTAL; i++) { + oneplus_sched_para[i].trig = (ohm_trig_list & BIT(i)) ? true : false; + if(i == OHM_SCHED_EMMCIO ) + oneplus_io_para.trig = (ohm_trig_list & BIT(i)) ? true : false; + } + return; +} + +void ohm_logon_init(void) +{ + int i; + ohm_cpu_logon = (ohm_logon_list & OHM_CTRL_CPU_CUR) ? true : false; + ohm_memmon_logon = (ohm_logon_list & OHM_CTRL_MEMMON) ? true : false; + ohm_iopanic_mon_logon = (ohm_logon_list & OHM_CTRL_IOPANIC_MON) ? true : false; + for (i = 0; i < OHM_SCHED_TOTAL; i++) { + oneplus_sched_para[i].logon = (ohm_logon_list & BIT(i)) ? true : false; + if(i == OHM_SCHED_EMMCIO ) + oneplus_io_para.logon = (ohm_logon_list & BIT(i)) ? true : false; + } + return; +} + +void ohm_ctrl_init(void) +{ + int i; + ohm_cpu_ctrl = (ohm_ctrl_list & OHM_CTRL_CPU_CUR) ? true : false; + ohm_memmon_ctrl = (ohm_ctrl_list & OHM_CTRL_MEMMON) ? true : false; + ohm_iopanic_mon_ctrl = (ohm_ctrl_list & OHM_CTRL_IOPANIC_MON) ? true : false; + for (i = 0; i < OHM_SCHED_TOTAL; i++) { + oneplus_sched_para[i].ctrl = (ohm_ctrl_list & BIT(i)) ? true : false; + if(i == OHM_SCHED_EMMCIO ) + oneplus_io_para.ctrl = (ohm_ctrl_list & BIT(i)) ? true : false; + } + ohm_irqsoff_ctrl = true; + return; +} + +void ohm_para_init(void) +{ + int i; + for (i = 0; i < OHM_SCHED_TOTAL; i++) { + memset(&oneplus_sched_para[i], 0, sizeof(struct sched_stat_para)); + oneplus_sched_para[i].low_thresh_ms = LOW_THRESH_MS_DEFAULT; + oneplus_sched_para[i].high_thresh_ms = HIGH_THRESH_MS_DEFAULT; + } + for (i = 0 ;i < OHM_SCHED_TOTAL ;i++ ) + _ohm_para_init(&oneplus_sched_para[i]); + oneplus_sched_para[OHM_SCHED_EMMCIO].low_thresh_ms = LOW_THRESH_MS_DEFAULT; + oneplus_sched_para[OHM_SCHED_EMMCIO].high_thresh_ms = HIGH_THRESH_MS_DEFAULT; + + oneplus_io_para.low_thresh_ms = 100; + oneplus_io_para.high_thresh_ms = 200; + + for (i = 0 ;i < NR_CPUS ;i++ ){ + memset(&irq_latency_stat, 0 , sizeof(struct irq_latency_para)); + irq_latency_stat[i].high_thresh = 500; + irq_latency_stat[i].low_thresh = 100; + } + ohm_rt_para_init(); + ohm_preempt_para_init(); + ohm_ctrl_init(); + ohm_logon_init(); + ohm_trig_init(); + ohm_debug("origin list: ctrl 0x%08x, logon 0x%08x, trig 0x%08x\n", ohm_ctrl_list, ohm_logon_list, ohm_trig_list); + return; +} + +/****** Cur cpuloading ******/ + +static ssize_t cpu_load_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[BUFFER_SIZE_S] = {0}; + int len = 0; + int load = ohm_get_cur_cpuload(ohm_cpu_ctrl); + + if (load < 0) + load = 0; + len = sprintf(page, "cur_cpuloading: %d\n""cur_cpu_ctrl: %s\n""cur_cpu_logon: %s\n""cur_cpu_trig: %s\n", + load, (ohm_cpu_ctrl ? "true" : "false"), (ohm_cpu_logon ? "true" : "false"), (ohm_cpu_trig ? "true" : "false")); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + return (len < count ? len : count); +} + +static const struct file_operations proc_cpu_load_fops = { + .read = cpu_load_read, +}; + +/****** Sched latency stat *****/ +static ssize_t sched_latency_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[1024] = {0}; + int len = 0; + int type = OHM_SCHED_SCHEDLATENCY; + + len = sprintf(page, "sched_low_thresh_ms: %d\n""sched_high_thresh_ms: %d\n" + "sched_all_low_cnt: %lld\n""sched_all_high_cnt: %lld\n" + "sched_all_total_ms: %lld\n""sched_all_total_cnt: %lld\n" + "sched_all_max_ms: %lld\n""sched_fg_low_cnt: %lld\n" + "sched_fg_high_cnt: %lld\n""sched_fg_total_ms: %lld\n" + "sched_fg_total_cnt: %lld\n""sched_fg_max_ms: %lld\n" + "sched_delta_ms: %lld\n""sched_latency_ctrl: %s\n" + "sched_latency_logon: %s\n""sched_latency_trig: %s\n", + oneplus_sched_para[type].low_thresh_ms, + oneplus_sched_para[type].high_thresh_ms, + oneplus_sched_para[type].all.max_ms, + oneplus_sched_para[type].all.high_cnt, + oneplus_sched_para[type].all.low_cnt, + oneplus_sched_para[type].all.total_ms, + oneplus_sched_para[type].all.total_cnt, + oneplus_sched_para[type].fg.max_ms, + oneplus_sched_para[type].fg.high_cnt, + oneplus_sched_para[type].fg.low_cnt, + oneplus_sched_para[type].fg.total_ms, + oneplus_sched_para[type].fg.total_cnt, + oneplus_sched_para[type].delta_ms, + oneplus_sched_para[type].ctrl ? "true" : "false", + oneplus_sched_para[type].logon ? "true" : "false", + oneplus_sched_para[type].trig ? "true" : "false"); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + return (len < count ? len : count); +} + +static const struct file_operations proc_sched_latency_fops = { + .read = sched_latency_read, +}; + +/****** Sched iowait stat *****/ +static ssize_t iowait_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[1024] = {0}; + int len = 0; + int type = OHM_SCHED_IOWAIT; + + len = sprintf(page,"iowait_ctrl: %s\n""iowait_logon: %s\n""iowait_trig: %s\n" \ + "iowait_delta_ms: %u\n""iowait_low_thresh_ms: %u\n""iowait_high_thresh_ms: %u\n" \ + "iowait_all_max_ms: %llu\n""iowait_all_high_cnt: %llu\n""iowait_all_low_cnt: %llu\n" \ + "iowait_all_total_ms: %llu\n""iowait_all_total_cnt: %llu\n" \ + "iowait_fg_max_ms: %llu\n""iowait_fg_high_cnt: %llu\n""iowait_fg_low_cnt: %llu\n" \ + "iowait_fg_total_ms: %llu\n""iowait_fg_total_cnt: %llu\n", \ + oneplus_sched_para[type].ctrl ? "true":"false", \ + oneplus_sched_para[type].logon ? "true":"false", \ + oneplus_sched_para[type].trig ? "true":"false", \ + oneplus_sched_para[type].delta_ms, \ + oneplus_sched_para[type].low_thresh_ms, \ + oneplus_sched_para[type].high_thresh_ms, \ + oneplus_sched_para[type].all.max_ms, \ + oneplus_sched_para[type].all.high_cnt, \ + oneplus_sched_para[type].all.low_cnt, \ + oneplus_sched_para[type].all.total_ms, \ + oneplus_sched_para[type].all.total_cnt, \ + oneplus_sched_para[type].fg.max_ms, \ + oneplus_sched_para[type].fg.high_cnt, \ + oneplus_sched_para[type].fg.low_cnt, \ + oneplus_sched_para[type].fg.total_ms, \ + oneplus_sched_para[type].fg.total_cnt); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + + return (len < count ? len : count); +} + +static const struct file_operations proc_iowait_fops = { + .read = iowait_read, +}; + +/****** Sched sync wait stat ******/ +static ssize_t fsync_wait_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[1024] = {0}; + int len = 0; + int type = OHM_SCHED_FSYNC; + + len = sprintf(page, "fsync_ctrl: %s\n""fsync_logon: %s\n""fsync_trig: %s\n" \ + "fsync_delta_ms: %llu\n""fsync_low_thresh_ms: %u\n""fsync_high_thresh_ms: %u\n" \ + "fsync_all_max_ms: %llu\n""fsync_all_high_cnt: %llu\n""fsync_all_low_cnt: %llu\n" \ + "fsync_all_total_ms: %llu\n""fsync_all_total_cnt: %llu\n" \ + "fsync_fg_max_ms: %llu\n""fsync_fg_high_cnt: %llu\n""fsync_fg_low_cnt: %llu\n" \ + "fsync_fg_total_ms: %llu\n""fsync_fg_total_cnt: %llu\n", \ + oneplus_sched_para[type].ctrl ? "true":"false", \ + oneplus_sched_para[type].logon ? "true":"false", \ + oneplus_sched_para[type].trig ? "true":"false", \ + oneplus_sched_para[type].delta_ms, \ + oneplus_sched_para[type].low_thresh_ms, \ + oneplus_sched_para[type].high_thresh_ms, \ + oneplus_sched_para[type].all.max_ms, \ + oneplus_sched_para[type].all.high_cnt, \ + oneplus_sched_para[type].all.low_cnt, \ + oneplus_sched_para[type].all.total_ms, \ + oneplus_sched_para[type].all.total_cnt, \ + oneplus_sched_para[type].fg.max_ms, \ + oneplus_sched_para[type].fg.high_cnt, \ + oneplus_sched_para[type].fg.low_cnt, \ + oneplus_sched_para[type].fg.total_ms, \ + oneplus_sched_para[type].fg.total_cnt); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + + return (len < count ? len : count); +} + +static const struct file_operations proc_fsync_wait_fops = { + .read = fsync_wait_read, +}; + +/****** emcdrv_iowait stat ******/ +/* Emmc - 1 ; Ufs - 2 */ +int ohm_flash_type = OHM_FLASH_TYPE_UFS; +static ssize_t emmcio_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + int len = 0; + char *page = kzalloc(2048, GFP_KERNEL); + if (!page) + return -ENOMEM; + //int type = OHM_SCHED_EMMCIO; + len = sprintf(page, "emcdrv_iowait_low_thresh_ms: %d\n" //low thresh parameter + "emcdrv_iowait_low_cnt: %lld\n" + //high thresh parameter + "emcdrv_iowait_high_thresh_ms: %d\n" + "emcdrv_iowait_high_cnt: %lld\n" + //total parameter + "emcdrv_iowait_total_ms: %lld\n" + "flashio_total_latency: %lld\n" + "blockio_total_latency: %lld\n" + "emcdrv_iowait_total_cnt: %lld\n" + //fg latency parameter + "emcdrv_iowait_fg_low_cnt: %lld\n" + "emcdrv_iowait_fg_high_cnt: %lld\n" + "emcdrv_iowait_fg_total_ms: %lld\n" + "emcdrv_iowait_fg_total_cnt: %lld\n" + "emcdrv_iowait_fg_max_ms: %lld\n" + "emcdrv_iowait_delta_ms: %lld\n" + // fg + "iosize_write_count_fg: %lld\n" + "iosize_write_us_fg: %lld\n" + "iosize_500ms_syncwrite_count_fg: %lld\n" + "iosize_200ms_syncwrite_count_fg: %lld\n" + "iosize_500ms_asyncwrite_count_fg: %lld\n" + "iosize_200ms_asyncwrite_count_fg: %lld\n" + "iosize_read_count_fg: %lld\n" + "iosize_read_us_fg: %lld\n" + "iosize_500ms_read_count_fg: %lld\n" + "iosize_200ms_read_count_fg: %lld\n" + //bg + "iosize_write_count_bg: %lld\n" + "iosize_write_us_bg: %lld\n" + "iosize_2s_asyncwrite_count_bg: %lld\n" + "iosize_500ms_asyncwrite_count_bg: %lld\n" + "iosize_200ms_asyncwrite_count_bg: %lld\n" + "iosize_2s_syncwrite_count_bg: %lld\n" + "iosize_500ms_syncwrite_count_bg: %lld\n" + "iosize_200ms_syncwrite_count_bg: %lld\n" + "iosize_read_count_bg: %lld\n" + "iosize_read_us_bg: %lld\n" + "iosize_2s_read_count_bg: %lld\n" + "iosize_500ms_read_count_bg: %lld\n" + "iosize_200ms_read_count_bg: %lld\n" + //4k + "iosize_4k_read_count: %lld\n" + "iosize_4k_read_ms: %lld\n" + "iosize_4k_write_count: %lld\n" + "iosize_4k_write_ms: %lld\n" + // option + "emcdrv_iowait_ctrl: %s\n" + "emcdrv_iowait_logon: %s\n" + "emcdrv_iowait_trig: %s\n", + oneplus_io_para.low_thresh_ms, //low thresh parameter + oneplus_io_para.low_cnt, + //high thresh parameter + oneplus_io_para.high_thresh_ms, + oneplus_io_para.high_cnt, + //total parameter + (oneplus_io_para.total_us / 1000), + (oneplus_io_para.emmc_total_us / 1000), + (oneplus_io_para.total_us - oneplus_io_para.emmc_total_us) / 1000, + oneplus_io_para.total_cnt, + //fg latency parameter + oneplus_io_para.fg_low_cnt, + oneplus_io_para.fg_high_cnt, + oneplus_io_para.fg_total_ms, + oneplus_io_para.fg_total_cnt, + oneplus_io_para.fg_max_delta_ms, + oneplus_io_para.delta_ms, + //fg + oneplus_io_para.iosize_write_count_fg, + oneplus_io_para.iosize_write_us_fg, + oneplus_io_para.iosize_500ms_syncwrite_count_fg, + oneplus_io_para.iosize_200ms_syncwrite_count_fg, + oneplus_io_para.iosize_500ms_asyncwrite_count_fg, + oneplus_io_para.iosize_200ms_asyncwrite_count_fg, + oneplus_io_para.iosize_read_count_fg, + oneplus_io_para.iosize_read_us_fg, + oneplus_io_para.iosize_500ms_read_count_fg, + oneplus_io_para.iosize_200ms_read_count_fg, + //bg + oneplus_io_para.iosize_write_count_bg, + oneplus_io_para.iosize_write_us_bg, + oneplus_io_para.iosize_2s_asyncwrite_count_bg, + oneplus_io_para.iosize_500ms_asyncwrite_count_bg, + oneplus_io_para.iosize_200ms_asyncwrite_count_bg, + oneplus_io_para.iosize_2s_syncwrite_count_bg, + oneplus_io_para.iosize_500ms_syncwrite_count_bg, + oneplus_io_para.iosize_200ms_syncwrite_count_bg, + oneplus_io_para.iosize_read_count_bg, + oneplus_io_para.iosize_read_us_bg, + oneplus_io_para.iosize_2s_read_count_bg, + oneplus_io_para.iosize_500ms_read_count_bg, + oneplus_io_para.iosize_200ms_read_count_bg, + //4k + oneplus_io_para.iosize_4k_read_count, + (oneplus_io_para.iosize_4k_read_us / 1000), + oneplus_io_para.iosize_4k_write_count, + (oneplus_io_para.iosize_4k_write_us / 1000), + // option + oneplus_io_para.ctrl ? "true" : "false", + oneplus_io_para.logon ? "true" : "false", + oneplus_io_para.trig ? "true" : "false"); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + kfree(page); + return -EFAULT; + } + kfree(page); + *off += len < count ? len : count; + return (len < count ? len : count); +} + +static const struct file_operations proc_emmcio_fops = { + .read = emmcio_read, +}; + +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ +static inline ssize_t sched_data_to_user(char __user *buff, size_t count, loff_t *off, char *format_str, int len) +{ + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, format_str, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + + return (len < count ? len : count); +} + +/****** dstat statistics ******/ + +#define LATENCY_STRING_FORMAT(BUF, MODULE, SCHED_STAT) sprintf(BUF, \ + #MODULE"_ctrl: %s\n"#MODULE"_logon: %s\n"#MODULE"_trig: %s\n" \ + #MODULE"_delta_ms: %llu\n"#MODULE"_low_thresh_ms: %u\n"#MODULE"_high_thresh_ms: %u\n" \ + #MODULE"_all_max_ms: %llu\n"#MODULE"_all_high_cnt: %llu\n"#MODULE"_all_low_cnt: %llu\n" \ + #MODULE"_all_total_ms: %llu\n"#MODULE"_all_total_cnt: %llu\n" \ + #MODULE"_fg_max_ms: %llu\n"#MODULE"_fg_high_cnt: %llu\n"#MODULE"_fg_low_cnt: %llu\n" \ + #MODULE"_fg_total_ms: %llu\n"#MODULE"_fg_total_cnt: %llu\n", \ + SCHED_STAT->ctrl ? "true":"false", \ + SCHED_STAT->logon ? "true":"false", \ + SCHED_STAT->trig ? "true":"false", \ + SCHED_STAT->delta_ms, \ + SCHED_STAT->low_thresh_ms, \ + SCHED_STAT->high_thresh_ms, \ + SCHED_STAT->all.max_ms, \ + SCHED_STAT->all.high_cnt, \ + SCHED_STAT->all.low_cnt, \ + SCHED_STAT->all.total_ms, \ + SCHED_STAT->all.total_cnt, \ + SCHED_STAT->fg.max_ms, \ + SCHED_STAT->fg.high_cnt, \ + SCHED_STAT->fg.low_cnt, \ + SCHED_STAT->fg.total_ms, \ + SCHED_STAT->fg.total_cnt) + +static ssize_t dstate_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[BUFFER_SIZE_L] = {0}; + int len = 0; + int type = OHM_SCHED_DSTATE; + + struct sched_stat_para *sched_stat = &oneplus_sched_para[type]; + + len = LATENCY_STRING_FORMAT(page, dstate, sched_stat); + return sched_data_to_user(buff, count, off, page, len); +} + +static const struct file_operations proc_dstate_fops = { + .read = dstate_read, +}; + +/****** irqs latency ******/ +#define COMMON_STRING_FORMAT(BUF, MODULE, SCHED_STAT, NUM) sprintf(BUF, \ + "cpu%d_"#MODULE"_max: %llu\n""cpu%d_"#MODULE"_high_cnt: %llu\n""cpu%d_"#MODULE"_low_cnt: %llu\n" \ + "cpu%d_"#MODULE"_total: %llu\n""cpu%d_"#MODULE"_total_cnt: %llu\n", \ + NUM, \ + SCHED_STAT->max, \ + NUM, \ + SCHED_STAT->high_cnt, \ + NUM, \ + SCHED_STAT->low_cnt, \ + NUM, \ + SCHED_STAT->total, \ + NUM, \ + SCHED_STAT->total_cnt) + +static ssize_t irq_latency_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + int len = 0,i; + struct irq_latency_para *sched_stat; + char *page = kzalloc(2048,GFP_KERNEL); + if (!page) + return -ENOMEM; + + for ( i = 0; i < NR_CPUS; i++) { + len += sprintf(page + len, "cpu%d:\n", i); + sched_stat = &irq_latency_stat[i]; + len += COMMON_STRING_FORMAT(page + len, irq_latency, sched_stat, i); + } + + len += sprintf(page+len, "ohm_irqsoff_ctrl:%s \n", ohm_irqsoff_ctrl ? "true":"false"); + + return sched_data_to_user(buff, count, off, page, len); +} + +static const struct file_operations proc_irq_latency_fops = { + .read = irq_latency_read, +}; + +/****** Preempt state *****/ +#define PREEMPT_STRING_FORMAT(BUF, SCHED_STAT, NUM) sprintf(BUF,\ + "cpu%d_preempt_max_ms: %llu\n""cpu%d_preempt_high_cnt: %llu\n""cpu%d_preempt_low_cnt: %llu\n" \ + "cpu%d_preempt_total_ms: %llu\n""cpu%d_preempt_total_cnt: %llu\n", \ + NUM, \ + SCHED_STAT.max_ms, \ + NUM, \ + SCHED_STAT.high_cnt, \ + NUM, \ + SCHED_STAT.low_cnt, \ + NUM, \ + SCHED_STAT.total_ms, \ + NUM, \ + SCHED_STAT.total_cnt) + +static ssize_t preempt_latency_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + int len = 0,j; + char *page = kzalloc(2048,GFP_KERNEL); + if (!page) + return -ENOMEM; + + len = sprintf(page, "Show preemp-latency stat on per-cpu \n""\nCpu count:%d\n",NR_CPUS); + for ( j = 0; j < NR_CPUS; j++){ + len += sprintf(page+len,"cpu:%d\n", j); + len += PREEMPT_STRING_FORMAT(page+len, preempt_para[j].preempt_common, j); + } + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (copy_to_user(buff, page, (len < count ? len : count))) { + kfree(page); + return -EFAULT; + } + kfree(page); + *off += len < count ? len : count; + return (len < count ? len : count); + +} +static const struct file_operations proc_preempt_latency_fops = { + .read = preempt_latency_read, +}; + +/****** RT Sched stat *****/ +void rt_thresh_times_record(struct task_struct *p, unsigned int cpu) +{ + u64 exec_runtime_ns = p->rtend_time - p->rtstart_time ; + if(rt_para[cpu].lt_info->max_exec_ns < exec_runtime_ns && exec_runtime_ns > 0 && exec_runtime_ns < MAX_RT_EXEC ) { + rt_para[cpu].lt_info->max_exec_ns = exec_runtime_ns; + strcpy(rt_para[cpu].lt_info->comment,p->comm); + } + if (exec_runtime_ns < MAX_RT_EXEC && (exec_runtime_ns) > DEFAULT_RT_HT){ + rt_para[cpu].thresh_cnt[0]++; + } + else if ( DEFAULT_RT_HT> exec_runtime_ns && exec_runtime_ns > DEFAULT_RT_LT){ + rt_para[cpu].thresh_cnt[1]++; + } + else if ( DEFAULT_RT_LT> exec_runtime_ns && exec_runtime_ns > 0) + rt_para[cpu].thresh_cnt[2]++; + return ; +} +void rt_info_record(struct rt_rq *rt_rq, unsigned int cpu) +{ + if (!rt_rq) + return; + rt_para[cpu].each_cpu_rt = rt_rq->rt_time; + return ; +} +void rt_total_record(u64 delta_exec, unsigned int cpu) +{ + rt_para[cpu].each_cpu_rt_total += delta_exec; + return; +} +static char *thresh_list[3] = {"high","mid","low"}; + +static ssize_t cpu_rtime_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + int len = 0,i,j; + char *page = kzalloc(2048,GFP_KERNEL); + if (!page) + return -ENOMEM; + + len = sprintf(page, "Collect information about rt processes on per cpu \n""\nCpu count:%d\n""High_thresh_ns:%d\n""Low_thresh_ns:%d\n", + NR_CPUS,DEFAULT_RT_HT,DEFAULT_RT_LT); + for (i = 0; i < NR_CPUS; i++) { + len += sprintf(page+len,"\ncpu%d: \n""cpu%d_total_runtimes_ns: %lld\n""cpu%d_curr_runtimes_ns: %lld\n""cpu%d_comm:%s \n" + "cpu%d_exec_time_ns: %lld\n",i, i, rt_para[i].each_cpu_rt_total, i, rt_para[i].each_cpu_rt, i, rt_para[i].lt_info->comment, + i, rt_para[i].lt_info->max_exec_ns); + for (j = 0; j < 3; j++){ + if(j != 0 ) + len += sprintf(page+len,"cpu%d_%s_thresh_count: %llu\n", i, thresh_list[j], rt_para[i].thresh_cnt[j]); + else + len += sprintf(page+len,"cpu%d_%s_thresh_count: %d\n", i, thresh_list[j], rt_para[i].thresh_cnt[j]); + } + } + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + return (len < count ? len : count); +} +static const struct file_operations proc_cpu_rtime_stat_fops = { + .read = cpu_rtime_read, + }; + +/****** cpu overload ******/ + +#define OVERLOAD_STRING_FORMAT(BUF, SCHED_STAT, NUM) sprintf(BUF, \ + "cluster%d_overload_delta_ms: %llu\n""cluster%d_overload_low_thresh_ms: %u\n" \ + "cluster%d_overload_high_thresh_ms: %u\n""cluster%d_overload_all_max_ms: %llu\n" \ + "cluster%d_overload_all_high_cnt: %llu\n""cluster%d_overload_all_low_cnt: %llu\n" \ + "cluster%d_overload_all_total_ms: %llu\n""cluster%d_overload_all_total_cnt: %llu\n" ,\ + NUM, \ + SCHED_STAT->delta_ms, \ + NUM, \ + SCHED_STAT->low_thresh_ms, \ + NUM, \ + SCHED_STAT->high_thresh_ms, \ + NUM, \ + SCHED_STAT->all.max_ms, \ + NUM, \ + SCHED_STAT->all.high_cnt, \ + NUM, \ + SCHED_STAT->all.low_cnt, \ + NUM, \ + SCHED_STAT->all.total_ms, \ + NUM, \ + SCHED_STAT->all.total_cnt) + +static ssize_t overload_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[BUFFER_SIZE_L + BUFFER_SIZE_M] = {0}; + int len = 0; + int nr_clusters = MAX_CLUSTERS; + struct sched_cluster *cluster; + len += sprintf(page + len, "nr_clusters:%d\n", nr_clusters); + for_each_sched_cluster(cluster){ + len += sprintf(page+len, "cluster%d:\n", cluster->id); + len += OVERLOAD_STRING_FORMAT(page+len, cluster->overload, cluster->id); + } + return sched_data_to_user(buff, count, off, page, len); +} +static const struct file_operations proc_overload_fops = { + .read = overload_read, +}; + +/****** mem monitor read ******/ +#ifdef CONFIG_ONEPLUS_MEM_MONITOR +static ssize_t alloc_wait_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[1024] = {0}; + int len = 0; + + len = sprintf(page, "total_alloc_wait_h_cnt: %lld\n""total_alloc_wait_l_cnt: %lld\n" + "fg_alloc_wait_h_cnt: %lld\n""fg_alloc_wait_l_cnt: %lld\n" + "total_alloc_wait_max_ms: %lld\n""total_alloc_wait_max_order: %lld\n" + "fg_alloc_wait_max_ms: %lld\n""fg_alloc_wait_max_order: %lld\n" + "alloc_wait_ctrl: %s\n""alloc_wait_logon: %s\n""alloc_wait_trig: %s\n", + allocwait_para.total_alloc_wait_h_cnt, allocwait_para.total_alloc_wait_l_cnt, + allocwait_para.fg_alloc_wait_h_cnt, allocwait_para.fg_alloc_wait_l_cnt, + allocwait_para.total_alloc_wait_max_ms, allocwait_para.total_alloc_wait_max_order, + allocwait_para.fg_alloc_wait_max_ms, allocwait_para.fg_alloc_wait_max_order, + ohm_memmon_ctrl ? "true" : "false", ohm_memmon_logon ? "true":"false", ohm_memmon_trig ? "true":"false"); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + return (len < count ? len : count); +} + +static const struct file_operations proc_alloc_wait_fops = { + .read = alloc_wait_read, +}; +#endif /*CONFIG_ONEPLUS_MEM_MONITOR*/ + +/****** Proc para ******/ +static ssize_t ohm_para_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[256] = {0}; + int len = 0; + + len = sprintf(page, "action: %s\n""ctrl: 0x%08x\n""logon: 0x%08x\n""trig: 0x%08x\n", + (ohm_action_ctrl ? "true":"false"), ohm_ctrl_list, ohm_logon_list, ohm_trig_list); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + return (len < count ? len : count); +} + +static ssize_t ohm_para_write(struct file *file, const char __user *buff, size_t len, loff_t *ppos) +{ + char write_data[32] = {0}; + char ctrl_list[32] = {0}; + + if (raw_copy_from_user(&write_data, buff, len)) { + ohm_err("write error.\n"); + return -EFAULT; + } + write_data[len] = '\0'; + if (write_data[len - 1] == '\n') { + write_data[len - 1] = '\0'; + } + + if (0 == strncmp(write_data, "ohmctrl", 7)) { + strncpy(ctrl_list, &write_data[7], OHM_INT_MAX); + ctrl_list[OHM_INT_MAX] = '\0'; + ohm_ctrl_list = (int)simple_strtol(ctrl_list, NULL, 10); + ohm_ctrl_init(); + } else if (0 == strncmp(write_data, "ohmlogon", 8)) { + strncpy(ctrl_list, &write_data[8], OHM_INT_MAX); + ctrl_list[OHM_INT_MAX] = '\0'; + ohm_logon_list = (int)simple_strtol(ctrl_list, NULL, 10); + ohm_logon_init(); + } else if (0 == strncmp(write_data, "ohmtrig", 7)) { + strncpy(ctrl_list, &write_data[7], OHM_INT_MAX); + ctrl_list[OHM_INT_MAX] = '\0'; + ohm_trig_list = (int)simple_strtol(ctrl_list, NULL, 10); + ohm_trig_init(); + } else if (0 == strncmp(write_data, "ohmparaupdate", 13)) { + ohm_para_update(); + return len; + } else { + ohm_err("input illegal\n"); + return -EFAULT; + } + ohm_debug("write: %s, set: %s, ctrl: 0x%08x, logon: 0x%08x, trig: 0x%08x\n", + write_data, ctrl_list, ohm_ctrl_list, ohm_logon_list, ohm_trig_list); + return len; +} + +static const struct file_operations proc_para_fops = { + .read = ohm_para_read, + .write = ohm_para_write, +}; + +/****** iowait hung show ******/ +unsigned int iowait_hung_cnt; +unsigned int iowait_panic_cnt; +static ssize_t iowait_hung_read(struct file *filp, char __user *buff, size_t count, loff_t *off) +{ + char page[1024] = {0}; + int len = 0; + + len = sprintf(page, "iowait_hung_cnt: %u\n""iowait_panic_cnt: %u\n" + "ohm_iopanic_mon_ctrl: %s\n""ohm_iopanic_mon_logon: %s\n""ohm_iopanic_mon_trig: %s\n", + iowait_hung_cnt, iowait_panic_cnt, + (ohm_iopanic_mon_ctrl ? "true" : "false"), (ohm_iopanic_mon_logon ? "true" : "false"), (ohm_iopanic_mon_trig ? "true" : "false")); + + if (len > *off) { + len -= *off; + } else { + len = 0; + } + if (raw_copy_to_user(buff, page, (len < count ? len : count))) { + return -EFAULT; + } + *off += len < count ? len : count; + return (len < count ? len : count); +} + +static const struct file_operations proc_iowait_hung_fops = { + .read = iowait_hung_read, +}; + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +/****** rw_overload show ******/ +static int rw_overload_show(struct seq_file *s, void *v) +{ + struct task_struct *p; + struct task_struct *group; + u64 window_index = sample_window.window_index; + u64 timestamp = sample_window.timestamp; + u64 spead; + u64 task_index; + bool index = ODD(window_index); + seq_printf(s, "window_index:%llu timestamp:%llu\n", window_index, timestamp); + seq_printf(s, "%-10s\t%-10s\t%-16s\t%-16s\t%-8s\t%-16s\n", "TID", "TGID", "COMM", "spead", "r/w", "task_index"); + rcu_read_lock(); + do_each_thread(group, p) { + if (window_index != (p->tli[!index].task_sample_index + 1)) + continue; + if (p->tli[!index].tli_overload_flag & TASK_WRITE_OVERLOAD_FLAG) { + spead = p->tli[!index].write_bytes; + task_index = p->tli[!index].task_sample_index; + seq_printf(s, "%-10d\t%-10d\t%-16s\t%-16llu\t%-8s\t%-16llu\n", p->pid, p->tgid, p->comm, spead, "write", task_index); + } + if (p->tli[!index].tli_overload_flag & TASK_READ_OVERLOAD_FLAG) { + spead = p->tli[!index].read_bytes; + task_index = p->tli[!index].task_sample_index; + seq_printf(s, "%-10d\t%-10d\t%-16s\t%-16llu\t%-8s\t%-16llu\n", p->pid, p->tgid, p->comm, spead, "read", task_index); + } + } while_each_thread(group, p); + rcu_read_unlock(); + return 0; +} + +static int rw_overload_open(struct inode *inode, struct file *file) +{ + return single_open(file, rw_overload_show, NULL); +} + +static const struct file_operations proc_rw_overload_fops = { + .open = rw_overload_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/****** runtime_overload show ******/ +static int runtime_overload_show(struct seq_file *s, void *v) +{ + struct task_struct *p; + struct task_struct *group; + u64 window_index = sample_window.window_index; + u64 timestamp = sample_window.timestamp; + u64 runtime; + u64 task_index; + u64 rt; + bool index = ODD(window_index); + seq_printf(s, "window_index:%llu timestamp:%llu\n", window_index, timestamp); + seq_printf(s, "%-10s\t%-10s\t%-16s\t%-16s\t%-6s\t%-6s\t%-16s\n", "TID", "TGID", "COMM", "runtime", "FG/BG", "RT", "task_index"); + do_each_thread(group, p) { + if (window_index != (p->tli[!index].task_sample_index + 1)) + continue; + rt = p->tli[!index].tli_overload_flag & TASK_RT_THREAD_FLAG; + if (p->tli[!index].tli_overload_flag & TASK_CPU_OVERLOAD_FG_FLAG) { + runtime = p->tli[!index].runtime[1]; + task_index = p->tli[!index].task_sample_index; + seq_printf(s, "%-10d\t%-10d\t%-16s\t%-16llu\t%-6s\t%-6s\t%-16llu\n", p->pid, p->tgid, p->comm, runtime, "FG", rt?"YES":"NO", task_index); + } + if (p->tli[!index].tli_overload_flag & TASK_CPU_OVERLOAD_BG_FLAG) { + runtime = p->tli[!index].runtime[0]; + task_index = p->tli[!index].task_sample_index; + seq_printf(s, "%-10d\t%-10d\t%-16s\t%-16llu\t%-6s\t%-6s\t%-16llu\n", p->pid, p->tgid, p->comm, runtime, "BG", rt?"YES":"NO", task_index); + } + } while_each_thread(group, p); + return 0; +} + +static int runtime_overload_open(struct inode *inode, struct file *file) +{ + return single_open(file, runtime_overload_show, NULL); +} + +static const struct file_operations proc_runtime_overload_fops = { + .open = runtime_overload_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif +/****** End ******/ + +#define HEALTHINFO_PROC_NODE "oneplus_healthinfo" +static struct proc_dir_entry *oneplus_healthinfo; + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +static void adjust_window() { + sample_window.timestamp = jiffies_64; + sample_window.window_index++; + mod_timer(&task_load_info_timer, jiffies + ohm_sample_time*HZ); /* 5s */ +} +#endif + +static int __init oneplus_healthinfo_init(void) +{ + int ret = 0; + struct proc_dir_entry *pentry; + + ohm_para_init(); + ohm_action_init(); + oneplus_healthinfo = proc_mkdir(HEALTHINFO_PROC_NODE, NULL); + iowait_total = 0; + iowait_summ_start = jiffies; + iowait_summ_period = 100; + iowait_summ_thresh = 20; + if (!oneplus_healthinfo) { + ohm_err("can't create oneplus_healthinfo proc\n"); + goto ERROR_INIT_VERSION; + } +/****** ctrl *****/ + pentry = proc_create("para_update", S_IRUGO | S_IWUGO, oneplus_healthinfo, &proc_para_fops); + if (!pentry) { + ohm_err("create healthinfo_switch proc failed.\n"); + goto ERROR_INIT_VERSION; + } + +/****** Stat ******/ + pentry = proc_create("fsync_wait", S_IRUGO, oneplus_healthinfo, &proc_fsync_wait_fops); + if (!pentry) { + ohm_err("create fsync_wait proc failed.\n"); + goto ERROR_INIT_VERSION; + } + + pentry = proc_create("cpu_loading", S_IRUGO, oneplus_healthinfo, &proc_cpu_load_fops); + if (!pentry) { + ohm_err("create cpu_loading proc failed.\n"); + goto ERROR_INIT_VERSION; + } + + pentry = proc_create("iowait", S_IRUGO, oneplus_healthinfo, &proc_iowait_fops); + if (!pentry) { + ohm_err("create iowait proc failed.\n"); + goto ERROR_INIT_VERSION; + } + + pentry = proc_create("sched_latency", S_IRUGO, oneplus_healthinfo, &proc_sched_latency_fops); + if (!pentry) { + ohm_err("create sched_latency proc failed.\n"); + goto ERROR_INIT_VERSION; + } + + pentry = proc_create("emcdrv_iowait", S_IRUGO, oneplus_healthinfo, &proc_emmcio_fops); + if (!pentry) { + ohm_err("create emmc_driver_io_wait proc failed.\n"); + goto ERROR_INIT_VERSION; + } + + pentry = proc_create("iowait_hung", S_IRUGO, oneplus_healthinfo, &proc_iowait_hung_fops); + if (!pentry) { + ohm_err("create iowait_hung proc failed.\n"); + goto ERROR_INIT_VERSION; + } + +/*2020-06-22 ,OSP-5970 , monitor cpu info **/ + pentry = proc_create("dstate", S_IRUGO, oneplus_healthinfo, &proc_dstate_fops); + if (!pentry) { + ohm_err("create dstate proc failed.\n"); + goto ERROR_INIT_VERSION; + } + + pentry = proc_create("overload", S_IRUGO, oneplus_healthinfo, &proc_overload_fops); + if(!pentry) { + ohm_err("create overload proc failed.\n"); + goto ERROR_INIT_VERSION; + } + pentry = proc_create("cpu_rt_info", S_IRUGO, oneplus_healthinfo, &proc_cpu_rtime_stat_fops); + if(!pentry) { + ohm_err("create cpu_rtime_read proc failed.\n"); + goto ERROR_INIT_VERSION; + } + pentry = proc_create("preempt_latency", S_IRUGO, oneplus_healthinfo, &proc_preempt_latency_fops); + if(!pentry) { + ohm_err("create preempt latency proc failed.\n"); + goto ERROR_INIT_VERSION; + } + pentry = proc_create("irq_latency", S_IRUGO, oneplus_healthinfo, &proc_irq_latency_fops); + if(!pentry) { + ohm_err("create irq_latency proc failed.\n"); + goto ERROR_INIT_VERSION; + } + +#ifdef CONFIG_ONEPLUS_MEM_MONITOR + pentry = proc_create("alloc_wait", S_IRUGO, oneplus_healthinfo, &proc_alloc_wait_fops); + if (!pentry) { + ohm_err("create alloc_wait proc failed.\n"); + goto ERROR_INIT_VERSION; + } + +#endif /*CONFIG_ONEPLUS_MEM_MONITOR*/ +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + sample_window.timestamp = jiffies; + sample_window.window_index = 0; + timer_setup(&task_load_info_timer, NULL, TIMER_DEFERRABLE); + task_load_info_timer.function = &adjust_window; + task_load_info_timer.expires = jiffies + ohm_sample_time*HZ; + add_timer(&task_load_info_timer); + + pentry = proc_create("rw_overload", S_IRUGO, oneplus_healthinfo, &proc_rw_overload_fops); + if (!pentry) { + ohm_err("create rw_overload proc failed.\n"); + goto ERROR; + } + + pentry = proc_create("runtime_overload", S_IRUGO, oneplus_healthinfo, &proc_runtime_overload_fops); + if (!pentry) { + ohm_err("create runtime_overload proc failed.\n"); + goto ERROR; + } +#endif + + ohm_debug("Success \n"); + return ret; +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +ERROR: + del_timer(&task_load_info_timer); +#endif +ERROR_INIT_VERSION: + remove_proc_entry(HEALTHINFO_PROC_NODE, NULL); + return -ENOENT; +} + +module_init(oneplus_healthinfo_init); + +module_param_named(ohm_action_ctrl, ohm_action_ctrl, bool, S_IRUGO | S_IWUSR); +module_param_named(ohm_iowait_l_ms, oneplus_sched_para[OHM_SCHED_IOWAIT].low_thresh_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_iowait_h_ms, oneplus_sched_para[OHM_SCHED_IOWAIT].high_thresh_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_schedlatency_l_ms, ohm_thresh_para[OHM_SCHED_SCHEDLATENCY].l_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_schedlatency_h_ms, ohm_thresh_para[OHM_SCHED_SCHEDLATENCY].h_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_fsync_l_ms, ohm_thresh_para[OHM_SCHED_FSYNC].l_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_fsync_h_ms, ohm_thresh_para[OHM_SCHED_FSYNC].h_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_emmcio_l_ms, ohm_thresh_para[OHM_SCHED_EMMCIO].l_ms, int, S_IRUGO | S_IWUSR); +module_param_named(ohm_emmcio_h_ms, ohm_thresh_para[OHM_SCHED_EMMCIO].h_ms, int, S_IRUGO | S_IWUSR); +module_param_named(iowait_summ_period, iowait_summ_period, int, S_IRUGO | S_IWUSR); +module_param_named(iowait_summ_thresh, iowait_summ_thresh, int, S_IRUGO | S_IWUSR); +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +module_param_named(ohm_write_thresh, ohm_write_thresh, ullong, S_IRUGO | S_IWUSR); +module_param_named(ohm_read_thresh, ohm_read_thresh, ullong, S_IRUGO | S_IWUSR); +module_param_named(ohm_runtime_thresh_fg, ohm_runtime_thresh_fg, ullong, S_IRUGO | S_IWUSR); +module_param_named(ohm_runtime_thresh_bg, ohm_runtime_thresh_bg, ullong, S_IRUGO | S_IWUSR); +module_param_named(ohm_sample_time, ohm_sample_time, uint, S_IRUGO | S_IWUSR); +#endif + +MODULE_DESCRIPTION("OnePlus healthinfo monitor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/op_freezer/Kconfig b/drivers/oneplus/op_freezer/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..00dfd0a0056643f8d52d9ab194937e3fc24ad55b --- /dev/null +++ b/drivers/oneplus/op_freezer/Kconfig @@ -0,0 +1,5 @@ +config OP_FREEZER + bool "op_freezer kernel and freezer native communication channel" + default n + help + Key events (signal/network package/binder) report to freezer native. \ No newline at end of file diff --git a/drivers/oneplus/op_freezer/Makefile b/drivers/oneplus/op_freezer/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..488674528145e33ff441f194a6bd9edc76a7cc44 --- /dev/null +++ b/drivers/oneplus/op_freezer/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_OP_FREEZER) += op_freezer.o +obj-$(CONFIG_OP_FREEZER) += op_freezer_netfilter.o diff --git a/drivers/oneplus/op_freezer/op_freezer.c b/drivers/oneplus/op_freezer/op_freezer.c new file mode 100644 index 0000000000000000000000000000000000000000..4d147487ad4738b9f5f060a233cf66a49f9e5ca2 --- /dev/null +++ b/drivers/oneplus/op_freezer/op_freezer.c @@ -0,0 +1,187 @@ +/* op_freezer.c + * + * add for oneplus freeze manager + * + * Copyright (C) 2007-2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#define NETLINK_PORT_OP_FREEZER (0x15356) + +static struct sock *sock_handle = NULL; +static atomic_t op_freezer_deamon_port; + +/* + * netlink report function to tell freezer native deamon unfreeze process info + * if the parameters is empty, fill it with (pid/uid with -1) + */ +int op_freezer_report(enum message_type type, int caller_pid, int target_uid, const char *rpc_name, int code) +{ + int len = 0; + int ret = 0; + struct op_freezer_message *data = NULL; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + + if (atomic_read(&op_freezer_deamon_port) == -1) { + pr_err("%s: op_freezer_deamon_port invalid!\n", __func__); + return OP_FREEZER_ERROR; + } + + if (sock_handle == NULL) { + pr_err("%s: sock_handle invalid!\n", __func__); + return OP_FREEZER_ERROR; + } + + if (type >= TYPE_MAX) { + pr_err("%s: type = %d invalid!\n", __func__, type); + return OP_FREEZER_ERROR; + } + + len = sizeof(struct op_freezer_message); + skb = nlmsg_new(len, GFP_ATOMIC); + if (skb == NULL) { + pr_err("%s: type =%d, nlmsg_new failed!\n", __func__, type); + return OP_FREEZER_ERROR; + } + + nlh = nlmsg_put(skb, 0, 0, 0, len, 0); + if (nlh == NULL) { + pr_err("%s: type =%d, nlmsg_put failed!\n", __func__, type); + kfree_skb(skb); + return OP_FREEZER_ERROR; + } + + data = nlmsg_data(nlh); + if(data == NULL) { + pr_err("%s: type =%d, nlmsg_data failed!\n", __func__, type); + return OP_FREEZER_ERROR; + } + data->type = type; + data->port = NETLINK_PORT_OP_FREEZER; + data->caller_pid = caller_pid; + data->target_uid = target_uid; + data->pkg_cmd = -1; //invalid package cmd + data->code = code; + strlcpy(data->rpc_name, rpc_name, INTERFACETOKEN_BUFF_SIZE); + nlmsg_end(skb, nlh); + + if ((ret = nlmsg_unicast(sock_handle, skb, (u32)atomic_read(&op_freezer_deamon_port))) < 0) { + pr_err("%s: nlmsg_unicast failed! err = %d\n", __func__ , ret); + return OP_FREEZER_ERROR; + } + + return OP_FREEZER_NOERROR; +} + +// op_freezer kernel module handle the message from freezer native deamon +static void op_freezer_handler(struct sk_buff *skb) +{ + struct op_freezer_message *data = NULL; + struct nlmsghdr *nlh = NULL; + unsigned int len = 0; + + if (!skb) { + pr_err("%s: recv skb NULL!\n", __func__); + return; + } + + if (skb->len >= NLMSG_SPACE(0)) { + nlh = nlmsg_hdr(skb); + len = NLMSG_PAYLOAD(nlh, 0); + data = (struct op_freezer_message *)NLMSG_DATA(nlh); + + if (len < sizeof (struct op_freezer_message)) { + pr_err("%s: op_freezer_message len check faied! len = %d min_expected_len = %lu!\n", __func__, len, sizeof(struct op_freezer_message)); + return; + } + + if (data->port < 0) { + pr_err("%s: portid = %d invalid!\n", __func__, data->port); + return; + } + if (data->type >= TYPE_MAX) { + pr_err("%s: type = %d invalid!\n", __func__, data->type); + return; + } + if (atomic_read(&op_freezer_deamon_port) == -1 && data->type != LOOP_BACK) { + pr_err("%s: handshake not setup, type = %d!\n", __func__, data->type); + return; + } + + switch (data->type) { + case LOOP_BACK: /*Loop back message, only for native deamon and kernel handshake*/ + atomic_set(&op_freezer_deamon_port, data->port); + op_freezer_report(LOOP_BACK, -1, -1, "loop back", -1); + printk(KERN_ERR "%s: --> LOOP_BACK, port = %d\n", __func__, data->port); + break; + case PKG: + printk(KERN_ERR "%s: --> PKG, uid = %d, pkg_cmd = %d\n", __func__, data->target_uid, data->pkg_cmd); + op_freezer_network_cmd_parse(data->target_uid, data->pkg_cmd); + break; + case FROZEN_TRANS: + printk(KERN_ERR "%s: --> FROZEN_TRANS, uid = %d\n", __func__, data->target_uid); + op_freezer_check_frozen_transcation(data->target_uid); + break; + + default: + pr_err("%s: op_freezer_messag type invalid %d\n", __func__, data->type); + break; + } + } +} + +static int __init op_freezer_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = op_freezer_handler, + }; + + atomic_set(&op_freezer_deamon_port, -1); + + sock_handle = netlink_kernel_create(&init_net, NETLINK_OP_FREEZER, &cfg); + if (sock_handle == NULL) { + pr_err("%s: create netlink socket failed!\n", __func__); + return OP_FREEZER_ERROR; + } + + if (op_freezer_netfilter_init() == OP_FREEZER_ERROR) { + pr_err("%s: netfilter init failed!\n", __func__); + netlink_kernel_release(sock_handle); //release socket + return OP_FREEZER_ERROR; + } + + printk(KERN_INFO "%s: -\n", __func__); + return OP_FREEZER_NOERROR; +} + +static void __exit op_freezer_exit(void) +{ + if (sock_handle) + netlink_kernel_release(sock_handle); + + op_freezer_netfilter_deinit(); + printk(KERN_INFO "%s: -\n", __func__); +} + +module_init(op_freezer_init); +module_exit(op_freezer_exit); + +MODULE_LICENSE("GPL"); + diff --git a/drivers/oneplus/op_freezer/op_freezer_netfilter.c b/drivers/oneplus/op_freezer/op_freezer_netfilter.c new file mode 100644 index 0000000000000000000000000000000000000000..3bdde1198324a7b1ddbc8b8f70c34bcf4759436d --- /dev/null +++ b/drivers/oneplus/op_freezer/op_freezer_netfilter.c @@ -0,0 +1,232 @@ +/* op_freezer_netfilter.c + * + * add for oneplus freeze manager + * + * Copyright (C) 2007-2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_SLOT (100) +static uid_t monitored_uids[MAX_SLOT]; +spinlock_t uids_lock; + +static inline uid_t sock2uid(struct sock *sk) +{ + if(sk && sk->sk_socket) + return SOCK_INODE(sk->sk_socket)->i_uid.val; + else + return 0; +} + +// Add netlink monitor uid. When the monitored UID has incoming network package, tell op freezer native deamon +static void op_freezer_add_monitored_uid(uid_t target_uid) +{ + int i = 0; + int fisrt_empty_slot = MAX_SLOT; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + if (monitored_uids[i] == target_uid) { //already in the monitored array + spin_unlock_irqrestore(&uids_lock, flags); + //printk(KERN_WARNING "%s: uid = %d already in array\n", __func__, target_uid); + return; + } else if (monitored_uids[i] == 0 && fisrt_empty_slot == MAX_SLOT) { // first empty slot for monitoring uid + fisrt_empty_slot = i; + } + } + + if (fisrt_empty_slot >= MAX_SLOT) { + spin_unlock_irqrestore(&uids_lock, flags); + pr_err("%s: monitored uid = %d add failed!\n", __func__, target_uid); + return; + } + monitored_uids[fisrt_empty_slot] = target_uid; + spin_unlock_irqrestore(&uids_lock, flags); +} + +static void op_freezer_remove_monitored_uid(uid_t target_uid) +{ + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + if (monitored_uids[i] == target_uid) { + monitored_uids[i] = 0; + spin_unlock_irqrestore(&uids_lock, flags); + return; + } + } + spin_unlock_irqrestore(&uids_lock, flags); + printk(KERN_WARNING "%s: uid = %d remove uid not found\n", __func__, target_uid); +} + +static void op_freezer_remove_all_monitored_uid(void) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + + for (i = 0; i < MAX_SLOT; i++) + monitored_uids[i] = 0; + + spin_unlock_irqrestore(&uids_lock, flags); +} + +static bool op_freezer_find_remove_monitored_uid(uid_t target_uid) +{ + bool found = false; + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&uids_lock, flags); + for (i = 0; i < MAX_SLOT; i++) { + if (unlikely (monitored_uids[i] == target_uid)) { + found = true; + monitored_uids[i] = 0; + break; + } + } + spin_unlock_irqrestore(&uids_lock, flags); + + if (found) + printk(KERN_WARNING "%s: uid = %d found and removed\n", __func__, target_uid); + return found; +} + +void op_freezer_network_cmd_parse(uid_t uid, enum pkg_cmd cmd) +{ + switch (cmd) { + case ADD_ONE_UID: + op_freezer_add_monitored_uid(uid); + break; + case DEL_ONE_UID: + op_freezer_remove_monitored_uid(uid); + break; + case DEL_ALL_UID: + op_freezer_remove_all_monitored_uid(); + break; + default: + pr_err("%s: pkg_cmd type invalid %d\n", __func__, cmd); + break; + } +} + +// Moniter the uid by netlink filter hook function. +static unsigned int op_freezer_nf_ipv4v6_in(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct sock *sk; + uid_t uid; + unsigned int thoff = 0; + unsigned short frag_off = 0; + bool found = false; + + if (ip_hdr(skb)->version == 4) { + if (ip_hdr(skb)->protocol != IPPROTO_TCP) + return NF_ACCEPT; +#if IS_ENABLED(CONFIG_IPV6) + } else if (ip_hdr(skb)->version == 6) { + if (ipv6_find_hdr(skb, &thoff, -1, &frag_off, NULL) != IPPROTO_TCP) + return NF_ACCEPT; +#endif + } else { + return NF_ACCEPT; + } + + sk = skb_to_full_sk(skb); + if (sk == NULL) + return NF_ACCEPT; + + if (!sk_fullsock(sk)) + return NF_ACCEPT; + + uid = sock2uid(sk); + if (uid < MIN_USERAPP_UID) + return NF_ACCEPT; + + // Find the monitored UID and clear it from the monitor array + found = op_freezer_find_remove_monitored_uid(uid); + if (!found) + return NF_ACCEPT; + if (op_freezer_report(PKG, -1, uid, "PKG", -1) != OP_FREEZER_NOERROR) + pr_err("%s: op_freezer_report PKG failed!, uid = %d\n", __func__, uid); + + return NF_ACCEPT; +} + +//Only monitor input network packages +static struct nf_hook_ops op_freezer_nf_ops[] = { + + { + .hook = op_freezer_nf_ipv4v6_in, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_SELINUX_LAST + 1, + }, +#if IS_ENABLED(CONFIG_IPV6) + { + .hook = op_freezer_nf_ipv4v6_in, + .pf = NFPROTO_IPV6, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP6_PRI_SELINUX_LAST + 1, + }, +#endif +}; + +void op_freezer_netfilter_deinit(void) +{ + struct net *net; + + rtnl_lock(); + for_each_net(net) { + nf_unregister_net_hooks(net, op_freezer_nf_ops, ARRAY_SIZE(op_freezer_nf_ops)); + } + rtnl_unlock(); +} + +int op_freezer_netfilter_init(void) +{ + struct net *net = NULL; + int err = 0; + + spin_lock_init(&uids_lock); + op_freezer_remove_all_monitored_uid(); + + rtnl_lock(); + for_each_net(net) { + err = nf_register_net_hooks(net, op_freezer_nf_ops, ARRAY_SIZE(op_freezer_nf_ops)); + if (err != 0) { + pr_err("%s: register netfilter hooks failed!\n", __func__); + break; + } + } + rtnl_unlock(); + + if (err != 0) { + op_freezer_netfilter_deinit(); + return OP_FREEZER_ERROR; + } + return OP_FREEZER_NOERROR; +} + diff --git a/drivers/oneplus/opslalib/Kconfig b/drivers/oneplus/opslalib/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..f00ba65c4f7d34c37330bfbabb148d6358905d9b --- /dev/null +++ b/drivers/oneplus/opslalib/Kconfig @@ -0,0 +1,9 @@ +config SLA + default n + bool "to monitor netlink traffic" + help + Realtime netlink traffic monitor. + +config SLA_ALGO + default n + bool "OnePlus SLA algorithm" diff --git a/drivers/oneplus/opslalib/Makefile b/drivers/oneplus/opslalib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6794aaf7c5fb4744b2621c06b533023f00f155ba --- /dev/null +++ b/drivers/oneplus/opslalib/Makefile @@ -0,0 +1,4 @@ +SLA_LIB_PATH = $(KBUILD_SRC)/drivers/oneplus/opslalib/slalib +ifeq ($(SLA_LIB_PATH),$(wildcard $(SLA_LIB_PATH))) +obj-$(subst y,$(CONFIG_SLA),$(CONFIG_SLA_ALGO)) += slalib/op_sla_help_lib.o +endif diff --git a/drivers/oneplus/opslalib/slalib/op_sla_help_lib.c b/drivers/oneplus/opslalib/slalib/op_sla_help_lib.c new file mode 100644 index 0000000000000000000000000000000000000000..91e43b78c341be5fd09c2cfa7c8ee56bebf66dc5 --- /dev/null +++ b/drivers/oneplus/opslalib/slalib/op_sla_help_lib.c @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 2018-2019, The OnePlus corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * 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 + +#define GAME_LINK_SWITCH_TIME (10 * 60 * 100) //10minutes +#define PINGPONG_AVOID_TIME (60 * 60 * 1000) //60minutes + +#define WLAN_SCORE_BAD_NUM 10 +#define WLAN_SCORE_GOOD 65 +#define WLAN_SCORE_BAD 55 + +#define RTT_NUM 5 +#define MAX_RTT 500 + +#define APP_RTT_THREASHOLD 250 + +struct op_sla_params_info { + int sla_rtt; + int wzry_rtt; + int cjzc_rtt; + int pubg_rtt; + int qqcar_rtt; +}; +struct op_sla_params_info sla_params_info = { + .sla_rtt = 200, + .wzry_rtt = 200, + .cjzc_rtt = 300, + .pubg_rtt = 300, + .qqcar_rtt = 300, +}; +struct op_game_app_info op_sla_game_app_list; +struct op_dev_info op_sla_info[IFACE_NUM]; +int rtt_record_num = MAX_RTT_RECORD_NUM; +int rtt_queue[MAX_RTT_RECORD_NUM]; +int rtt_rear; +int game_rtt_wan_detect_flag; +int game_data[5]; +int op_sla_enable; +int game_start_state; +int sla_game_switch_enable; +int sla_app_switch_enable; +int sla_screen_on; +int wlan_score_bad_count; + +enum { + GAME_WZRY = 1, + GAME_WZRY_2, + GAME_CJZC, + GAME_PUBG, + GAME_PUBG_TW, + GAME_MOBILE_LEGENDS, + GAME_AOV, + GAME_JZPAJ, + GAME_JZPAJ_TW, + GAME_QQ_CAR, + GAME_QQ_CAR_TW, + GAME_BRAWLSTARS, + GAME_CLASHROYALE_H2, + GAME_CLASHROYALE, + GAME_DWRG_H2, + GAME_DWRG, + GAME_DWRG_TW, + GAME_MRZH_H2, + GAME_MRZH, + GAME_MRZH_TW, +}; + +enum { + APP_WECHAT = 100, + APP_WECHAT_PARALLEL, +}; + +int abs(int num) +{ + return (num >= 0 ? num : ((-1) * num)); +} + +int is_ping_pong(int game_type, int time_now) +{ + if (op_sla_game_app_list.switch_count[game_type] > 1 && + op_sla_game_app_list.repeat_switch_time[game_type] != 0 && + (time_now - op_sla_game_app_list.repeat_switch_time[game_type]) + < PINGPONG_AVOID_TIME) + return 1; + return 0; +} + +int get_app_rtt_threshold(int game_type, int game_lost_count) +{ + int max_rtt = sla_params_info.sla_rtt; + + if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + max_rtt = sla_params_info.wzry_rtt; + if (rtt_rear == 4 && game_lost_count == 0 && + rtt_queue[0] == MAX_GAME_RTT && + rtt_queue[1] == MAX_GAME_RTT && + rtt_queue[2] == MAX_GAME_RTT && + rtt_queue[3] == MAX_GAME_RTT) { + op_sla_game_app_list.rtt[game_type] = 0; + } + } else if (game_type == GAME_CJZC) { + max_rtt = sla_params_info.cjzc_rtt; + } else if (game_type == GAME_PUBG || game_type == GAME_PUBG_TW) { + max_rtt = sla_params_info.pubg_rtt; + } else if (game_type == GAME_QQ_CAR_TW) { + max_rtt = sla_params_info.qqcar_rtt; + } + return max_rtt; +} + +void op_rx_interval_error_estimator(int game_type, int time_error) +{ + int dropnum = 0; + int gamethreshold = 0; + + if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + dropnum = 5; + gamethreshold = 300; + } else if (game_type == GAME_QQ_CAR) { + dropnum = 2; + gamethreshold = 1000; + } + if (dropnum != 0 && + op_sla_game_app_list.special_rx_count[game_type] >= dropnum && + (gamethreshold != 0 && time_error >= gamethreshold)) + op_sla_game_app_list.special_rx_error_count[game_type]++; + else if (dropnum != 0 && + op_sla_game_app_list.special_rx_count[game_type] >= dropnum && + op_sla_game_app_list.special_rx_error_count[game_type]) + op_sla_game_app_list.special_rx_error_count[game_type]--; + + op_sla_game_app_list.special_rx_count[game_type]++; +} + +void rttQueueEnqueue(int data) +{ + if (rtt_rear == rtt_record_num) + return; + rtt_queue[rtt_rear] = data; + rtt_rear++; +} + +void rttQueueDequeue(void) +{ + int i; + + if (rtt_rear == 0) + return; + for (i = 0; i < rtt_rear - 1; i++) + rtt_queue[i] = rtt_queue[i + 1]; + rtt_rear--; +} + +int average_rtt_queue(void) +{ + int sum = 0; + int i = 0; + + for (i = 0; i < rtt_rear; i++) + sum += rtt_queue[i] * (i + 1) / 10; + return sum; +} + +void op_game_rtt_estimator(int *game_data) +{ + int game_type = game_data[0]; + int rtt = game_data[1]; + int op_game_time_interval = game_data[2]; + int op_game_lost_count = game_data[3]; + int game_rtt_wan_detect_flag = game_data[4]; + int averagertt = 0; + int game_rtt_detect_lag = 0; + + op_sla_game_app_list.rtt_num[game_type]++; + if (op_sla_game_app_list.rtt_num[game_type] <= (rtt_record_num >> 1)) + return; + + if (rtt_rear == rtt_record_num) { + rttQueueDequeue(); + rttQueueEnqueue(rtt); + averagertt = average_rtt_queue(); + } else { + rttQueueEnqueue(rtt); + } + + if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + game_rtt_detect_lag = + (abs(op_game_time_interval - 5000) >= 50) ? 1 : 0; + //if game rtt not regular and last game rtt + //over 300 ms + if (game_rtt_detect_lag && + rtt_rear == MAX_RTT_RECORD_NUM && + rtt == MAX_GAME_RTT) { + averagertt = MAX_GAME_RTT; + //if game rtt continue over 200ms and current + //rtt bigger than before + } else if (rtt_rear == MAX_RTT_RECORD_NUM && + (rtt_queue[rtt_rear - 2] >= + sla_params_info.wzry_rtt && + rtt_queue[rtt_rear - 1] >= + sla_params_info.wzry_rtt)) { + averagertt = MAX_GAME_RTT; + //ct->op_game_lost_count + } else if (op_game_lost_count >= 1 && + rtt == MAX_GAME_RTT) { + averagertt = MAX_GAME_RTT; + } + } else if (game_type == GAME_PUBG || + game_type == GAME_PUBG_TW || + game_type == GAME_AOV || + game_type == GAME_QQ_CAR_TW) { + if (op_game_lost_count >= 1 && + rtt == MAX_GAME_RTT && + game_rtt_wan_detect_flag) { + averagertt = MAX_GAME_RTT; + } + } else if (game_type == GAME_CJZC) { + if (op_game_lost_count >= 3 && + rtt == MAX_GAME_RTT) { + averagertt = MAX_GAME_RTT; + } + } + op_sla_game_app_list.rtt[game_type] = averagertt; +} + +int op_get_ct_cell_quality(int game_type) +{ + int score_base = 0; + + if (op_sla_game_app_list.mark[game_type] == CELLULAR_MARK) + score_base = 10; + + if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + return (op_sla_info[CELLULAR_INDEX].cur_score + >= (CELL_SCORE_BAD - score_base)) ? 1 : 0; + } else if (game_type == GAME_CJZC || game_type == GAME_PUBG || + game_type == GAME_PUBG_TW || game_type == GAME_QQ_CAR || + game_type == GAME_QQ_CAR_TW) { + return (op_sla_info[CELLULAR_INDEX].cur_score + >= (-110 - score_base)) ? 1 : 0; + } else { + return (op_sla_info[CELLULAR_INDEX].cur_score + >= (CELL_SCORE_BAD - score_base)) ? 1 : 0; + } +} + +int op_get_cur_cell_quality(void) +{ + return (op_sla_info[CELLULAR_INDEX].cur_score >= -110) ? 1 : 0; +} + +int switch_to_cell(int cell_quality_good, + int game_rtt, + int gamelostcount, + int game_switch_interval, + int game_type) +{ + int max_rtt = get_app_rtt_threshold(game_type, gamelostcount); + + if ((cell_quality_good && op_sla_info[CELLULAR_INDEX].netlink_valid && + ((game_rtt != 0 && game_rtt >= max_rtt) || + op_sla_game_app_list.special_rx_error_count[game_type] >= 2) && + op_sla_game_app_list.mark[game_type] == WLAN_MARK) && + (!op_sla_game_app_list.switch_time[game_type] || + game_switch_interval > 30000)) + return 1; + return 0; +} + +int switch_to_wifi(int wlan_bad, + int game_rtt, + int gamelostcount, + int game_switch_interval, + int game_type) +{ + int max_rtt = get_app_rtt_threshold(game_type, gamelostcount); + + if ((!wlan_bad && op_sla_info[WLAN_INDEX].netlink_valid && + ((game_rtt != 0 && game_rtt >= max_rtt) || + op_sla_game_app_list.special_rx_error_count[game_type] >= 2) && + op_sla_game_app_list.mark[game_type] == CELLULAR_MARK) && + (!op_sla_game_app_list.switch_time[game_type] || + game_switch_interval > 30000)) + return 1; + return 0; +} + +void reset_sla_game_app_rx_error(int game_type) +{ + op_sla_game_app_list.special_rx_error_count[game_type] = 0; + op_sla_game_app_list.special_rx_count[game_type] = 0; +} + +void reset_sla_game_app_rtt(int game_type) +{ + op_sla_game_app_list.rtt[game_type] = 0; + op_sla_game_app_list.rtt_num[game_type] = 0; +} + +void record_sla_game_cell_state(int game_type, + int game_switch_interval, + int time_now) +{ + reset_sla_game_app_rx_error(game_type); + reset_sla_game_app_rtt(game_type); + op_sla_game_app_list.switch_count[game_type]++; + if (op_sla_game_app_list.switch_count[game_type] > 1 && + game_switch_interval < GAME_LINK_SWITCH_TIME) { + op_sla_game_app_list.repeat_switch_time[game_type] = + time_now; + } + op_sla_game_app_list.switch_time[game_type] = time_now; + op_sla_game_app_list.mark[game_type] = CELLULAR_MARK; +} + +void record_sla_game_wifi_state(int game_type, + int game_switch_interval, + int time_now) +{ + reset_sla_game_app_rx_error(game_type); + reset_sla_game_app_rtt(game_type); + op_sla_game_app_list.switch_count[game_type]++; + if (game_switch_interval < GAME_LINK_SWITCH_TIME) { + op_sla_game_app_list.repeat_switch_time[game_type] = + time_now; + } + op_sla_game_app_list.switch_time[game_type] = time_now; + op_sla_game_app_list.mark[game_type] = WLAN_MARK; +} + +int get_lost_count_threshold(int game_type) +{ + if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + if (op_sla_game_app_list.mark[game_type] == CELLULAR_MARK) + return 2; + else + return 1; + } else if (game_type == GAME_PUBG || game_type == GAME_PUBG_TW || + game_type == GAME_AOV || game_type == GAME_QQ_CAR_TW) { + return 1; + } else { + return 3; + } +} + +int get_game_interval(int game_type, int game_interval) +{ + if (game_type == GAME_PUBG || game_type == GAME_PUBG_TW || + game_type == GAME_QQ_CAR_TW) { + return 5000; + } else if (game_type == GAME_AOV) { + return 2000; + } else if (game_type == GAME_CJZC) { + return 1000; + } else { + return game_interval; + } +} + +int check_wan_detect_flag(int game_type) +{ + if ((game_type == GAME_PUBG || game_type == GAME_PUBG_TW || + game_type == GAME_AOV || game_type == GAME_QQ_CAR_TW) && + !game_rtt_wan_detect_flag) { + game_rtt_wan_detect_flag = 1; + return 1; + } + return 0; +} + +int is_detect_game_lost(int game_lost_count, + int game_lost_count_threshold, + int game_time_interval) +{ + if (op_sla_enable && + game_lost_count >= game_lost_count_threshold && + (game_time_interval > 300 || game_rtt_wan_detect_flag)) + return 1; + return 0; +} + +int is_support_detect_game_tx(int game_type, + int special_rx_pkt_last_timestamp) +{ + if (game_type == GAME_QQ_CAR && + special_rx_pkt_last_timestamp) + return 1; + return 0; +} + +void get_rx_pkt_threshold(int game_type, + int time_now, + int special_rx_pkt_last_timestamp, + int *rtt_callback) +{ + if (game_type == GAME_QQ_CAR) { + rtt_callback[0] = 10000 * 1.2; + rtt_callback[1] = 10000 / 2; + rtt_callback[2] = time_now - special_rx_pkt_last_timestamp; + } +} + +int data_stall_detect(int lastspecialrxtiming, + int specialrxthreshold, + int datastalltimer, + int datastallthreshold) +{ + if (op_sla_enable && + lastspecialrxtiming >= specialrxthreshold && + datastalltimer >= datastallthreshold) + return 1; + return 0; +} + +int get_game_tx_category(int game_type, int skb_len) +{ + if (game_type == GAME_CJZC) { + return 1; + } else if ((game_type == GAME_PUBG || game_type == GAME_PUBG_TW || + game_type == GAME_AOV || game_type == GAME_QQ_CAR_TW) && + skb_len == 33) { + return 2; + } else if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + if (skb_len == 47) + return 3; + else + return 4; + } + return 0; +} + +int get_game_rx_category(int game_type, unsigned int skb_len) +{ + if (game_type == GAME_QQ_CAR && skb_len == 83) + return 1; + else if ((game_type == GAME_WZRY || game_type == GAME_WZRY_2) && + skb_len == 100) + return 2; + return 0; +} + +int drop_pkt_check(int game_type, int skb_len) +{ + if (skb_len > 150 || (game_type == GAME_CJZC && skb_len == 123)) + return 1; + return 0; +} + +int is_support_rtt_wan_detect(int game_type) +{ + if (game_type == GAME_PUBG || game_type == GAME_PUBG_TW || + game_type == GAME_AOV || game_type == GAME_QQ_CAR_TW) + return 1; + return 0; +} + +int get_rx_interval_error(int game_category, + int time_now, + int rx_pkt_timestamp) +{ + if (game_category == 1) + return abs((time_now - rx_pkt_timestamp) - 10000); + else + return abs((time_now - rx_pkt_timestamp) - 2000); +} + +int is_need_check_game_rtt(int game_detect_status, + int game_timestamp, + int skb_len) +{ + if (game_detect_status == GAME_RTT_DETECTED_STREAM && + game_timestamp && skb_len <= 150) + return 1; + return 0; +} + +int get_game_rtt(int time_now, int game_timestamp, int game_type) +{ + int game_rtt = (time_now - game_timestamp); + + if ((game_type == GAME_WZRY || game_type == GAME_WZRY_2) && + game_rtt > MAX_GAME_RTT) + return MAX_GAME_RTT; + return game_rtt; +} + +int is_skip_rx_rtt(int game_type, int game_time_interval) +{ + if (game_type == GAME_WZRY || game_type == GAME_WZRY_2) { + if (game_time_interval < 1000 && + op_sla_game_app_list.mark[game_type] == CELLULAR_MARK) + return 1; + } else { + if (game_time_interval < 200) + return 1; + } + return 0; +} + +int is_support_game_mark(int game_type) +{ + if (game_type == GAME_CJZC || game_type == GAME_WZRY || + game_type == GAME_WZRY_2) + return 1; + return 0; +} + +int need_enable_sla(int cell_quality_good) +{ + if (!op_sla_enable && game_start_state && + sla_game_switch_enable && cell_quality_good) + return 1; + return 0; +} + +int need_enable_sla_for_wlan_score(void) +{ + if (op_sla_info[WLAN_INDEX].cur_score <= (WLAN_SCORE_BAD - 4) && + !op_sla_info[CELLULAR_INDEX].if_up && + (!op_sla_enable && game_start_state && + sla_game_switch_enable && sla_screen_on)) + return 1; + return 0; +} + +void set_sla_game_parameter(int num) +{ + op_sla_game_app_list.switch_time[num] = 0; + op_sla_game_app_list.switch_count[num] = 0; + op_sla_game_app_list.repeat_switch_time[num] = 0; + op_sla_game_app_list.game_type[num] = num; + op_sla_game_app_list.mark[num] = WLAN_MARK; +} + +void op_init_game_online_info(int num, int time_now) +{ + op_sla_game_app_list.mark[num] = WLAN_MARK; + op_sla_game_app_list.switch_time[num] = time_now; + op_sla_game_app_list.switch_count[num] = 0; + op_sla_game_app_list.repeat_switch_time[num] = 0; +} + +int op_get_wlan_quality(void) +{ + if (wlan_score_bad_count >= WLAN_SCORE_BAD_NUM) + return 1; + return 0; +} + +void update_wlan_score(void) +{ + if (op_sla_info[WLAN_INDEX].cur_score <= (WLAN_SCORE_BAD - 5)) { + wlan_score_bad_count += WLAN_SCORE_BAD_NUM; + } else if (op_sla_info[WLAN_INDEX].cur_score <= (WLAN_SCORE_BAD - 2)) { + wlan_score_bad_count += 2; + } else if (op_sla_info[WLAN_INDEX].cur_score <= WLAN_SCORE_BAD) { + wlan_score_bad_count++; + } else if (op_sla_info[WLAN_INDEX].cur_score >= WLAN_SCORE_GOOD) { + wlan_score_bad_count = 0; + } else if (op_sla_info[WLAN_INDEX].cur_score + >= (WLAN_SCORE_GOOD - 2) && wlan_score_bad_count >= 2) { + wlan_score_bad_count -= 2; + } else if (op_sla_info[WLAN_INDEX].cur_score + >= (WLAN_SCORE_GOOD - 5) && wlan_score_bad_count) { + wlan_score_bad_count--; + } + + if (wlan_score_bad_count > (2 * WLAN_SCORE_BAD_NUM)) + wlan_score_bad_count = 2 * WLAN_SCORE_BAD_NUM; +} + +int mark_retransmits_syn_skb(unsigned int sla_mark) +{ + unsigned int tmp_mark = sla_mark & MARK_MASK; + unsigned int tmp_retran_mark = sla_mark & RETRAN_MASK; + + if (RETRAN_MARK & tmp_retran_mark) { + if (tmp_mark == WLAN_MARK) + return (CELLULAR_MARK | RETRAN_SECOND_MARK); + else if (tmp_mark == CELLULAR_MARK) + return (WLAN_MARK | RETRAN_SECOND_MARK); + } + return 0; +} + +int mark_force_reset_skb(unsigned int sla_mark) +{ + unsigned int tmp_mark = sla_mark & MARK_MASK; + unsigned int tmp_reset_mark = sla_mark & FORCE_RESET_MASK; + + if (FORCE_RESET_MARK & tmp_reset_mark) { + if (tmp_mark == WLAN_MARK) + return CELLULAR_MARK; + else if (tmp_mark == CELLULAR_MARK) + return WLAN_MARK; + } + return 0; +} + +int find_iface_index_by_mark(unsigned int mark) +{ + int index = -1; + int tmp_mark = mark & MARK_MASK; + + if (op_sla_info[WLAN_INDEX].if_up && tmp_mark == WLAN_MARK) + return WLAN_INDEX; + else if (op_sla_info[CELLULAR_INDEX].if_up && tmp_mark == CELLULAR_MARK) + return CELLULAR_INDEX; + return index; +} + +int find_tcp_iface_index_by_mark(unsigned int mark) +{ + int ifaceindex = -1; + + ifaceindex = find_iface_index_by_mark(mark); + if (ifaceindex == -1) { + if (!op_sla_enable) { + if (op_sla_info[WLAN_INDEX].if_up && op_sla_info[WLAN_INDEX].netlink_valid) + ifaceindex = WLAN_INDEX; + else if (op_sla_info[CELLULAR_INDEX].if_up && op_sla_info[CELLULAR_INDEX].netlink_valid) + ifaceindex = CELLULAR_INDEX; + } + } + return ifaceindex; +} + +int update_sla_tcp_info(unsigned int tcp_rtt, unsigned int total_retrans, unsigned int mark) +{ + int ifaceindex = -1; + + ifaceindex = find_iface_index_by_mark(mark); + if (ifaceindex == -1) { + if (!op_sla_enable) { + if (op_sla_info[WLAN_INDEX].if_up) + ifaceindex = WLAN_INDEX; + else if (op_sla_info[CELLULAR_INDEX].if_up) + ifaceindex = CELLULAR_INDEX; + } else { + if (mark == 0) + ifaceindex = WLAN_INDEX; + } + } + if (ifaceindex != -1) { + if ((tcp_rtt >= APP_RTT_THREASHOLD || total_retrans >= 5) && + op_sla_info[ifaceindex].env_dirty_count < 20) { + if (tcp_rtt >= APP_RTT_THREASHOLD) + op_sla_info[ifaceindex].env_dirty_count++; + else if (total_retrans >= 5) + op_sla_info[ifaceindex].env_dirty_count = + op_sla_info[ifaceindex].env_dirty_count + 2; + } else if ((tcp_rtt < APP_RTT_THREASHOLD && total_retrans < 3) && + op_sla_info[ifaceindex].env_dirty_count > 0) { + op_sla_info[ifaceindex].env_dirty_count--; + } + } + return ifaceindex; +} + +int is_tcp_unreachable(int ifaceindex, unsigned int tcp_rtt, unsigned int total_retrans) +{ + if (ifaceindex == -1 || ifaceindex == CELLULAR_INDEX) + return 0; + + if ((tcp_rtt >= APP_RTT_THREASHOLD || total_retrans >= 5) && op_sla_info[ifaceindex].env_dirty_count >= 5) + return 1; + return 0; +} + +int is_syn_need_mark(unsigned int ctmark) +{ + int rtt_mark = ctmark & RTT_MASK; + + if (rtt_mark & RTT_MARK) + return 1; + return 0; +} + +unsigned int config_syn_retran(int index, unsigned int ctmark) +{ + op_sla_info[index].syn_retran++; + ctmark |= RTT_MARK; + return ctmark; +} + +int set_syn_skb_result(void) +{ + return SLA_SKB_MARKED; +} + +int set_syn_ack_skb_result(void) +{ + return SLA_SKB_REMARK; +} + +int is_retran_second_mark(unsigned int sla_mark) +{ + unsigned int tmp_retran_mark = sla_mark & RETRAN_MASK; + + if (RETRAN_SECOND_MARK & tmp_retran_mark) + return 1; + return 0; +} + +unsigned int config_syn_retan(unsigned int sla_mark) +{ + sla_mark |= RETRAN_MARK; + return sla_mark; +} + +unsigned short get_dns_response(unsigned short response) +{ + response &= 0x8000; + response = response >> 15; + return response; +} + +unsigned short get_reply_code(unsigned short response) +{ + response &= 0x000f; + return response; +} + +void update_sla_dns_info(unsigned short rcode, unsigned int dst_addr, + unsigned int wifiip, unsigned int cellip) +{ + if (rcode == 5) { + if (dst_addr == wifiip && + op_sla_info[WLAN_INDEX].dns_refuse < 2) { + op_sla_info[WLAN_INDEX].dns_refuse++; + calc_rtt_by_dev_index(WLAN_INDEX, UNREACHABLE_RTT); + } else if (dst_addr == cellip && + op_sla_info[CELLULAR_INDEX].dns_refuse < 2) { + op_sla_info[CELLULAR_INDEX].dns_refuse++; + calc_rtt_by_dev_index(CELLULAR_INDEX, UNREACHABLE_RTT); + } + } else if (rcode == 0) { + if (dst_addr == wifiip) { + op_sla_info[WLAN_INDEX].dns_refuse = 0; + op_sla_info[WLAN_INDEX].icmp_unreachable = 0; + op_sla_info[WLAN_INDEX].dns_query_counts = 0; + } else if (dst_addr == cellip) { + op_sla_info[CELLULAR_INDEX].dns_refuse = 0; + op_sla_info[CELLULAR_INDEX].icmp_unreachable = 0; + op_sla_info[CELLULAR_INDEX].dns_query_counts = 0; + } + } +} + +void record_dns_query_info(int index, unsigned long time_now) +{ + if (op_sla_info[index].dns_query_counts == 0) + op_sla_info[index].dns_first_query_time = time_now; + op_sla_info[index].dns_query_counts++; +} + +int is_dns_query_not_response(int index, unsigned long time_now) +{ + if (op_sla_info[index].dns_refuse >= 2 || + (op_sla_info[index].dns_query_counts >= 2 && + (time_now - op_sla_info[index].dns_first_query_time) >= 5000)) { + return 1; + } + return 0; +} + +int is_iface_not_valid(int ifaceindex, unsigned long time_now) +{ + if (op_sla_info[ifaceindex].icmp_unreachable >= 2 || + is_dns_query_not_response(ifaceindex, time_now)) { + return 1; + } + return 0; +} + +int is_iface_quality_not_good(int ifaceindex) +{ + return (op_sla_info[ifaceindex].avg_rtt >= APP_RTT_THREASHOLD) ? 1 : 0; +} + +/** + * Design logic as below: + * 1. mobile dns not response + * case a: wifi dns no response, try to use wifi and fallback to cell each 5 times. + * case b: wifi dns good, use wifi. + * 2. mobile good + * case a: wifi dns no response, try to use cell and fallback to wifi each 5 times. + * case c: wifi dns good, use wifi. + */ +void update_dns_mark(unsigned int *dns_callback, unsigned long time_now) +{ + int cell_quality_good = op_get_cur_cell_quality(); + + if (is_dns_query_not_response(CELLULAR_INDEX, time_now)) { + if (is_dns_query_not_response(WLAN_INDEX, time_now) && + op_sla_info[CELLULAR_INDEX].dns_mark_times >= 5 && + cell_quality_good) { + dns_callback[0] = CELLULAR_MARK; + dns_callback[1] = SLA_SKB_MARKED; + return; + } + op_sla_info[CELLULAR_INDEX].dns_mark_times++; + dns_callback[0] = WLAN_MARK; + dns_callback[1] = SLA_SKB_ACCEPT; + } else { + if (is_dns_query_not_response(WLAN_INDEX, time_now) && cell_quality_good) { + if (op_sla_info[WLAN_INDEX].dns_mark_times >= 5) { + op_sla_info[WLAN_INDEX].dns_mark_times = 0; + dns_callback[0] = WLAN_MARK; + dns_callback[1] = SLA_SKB_ACCEPT; + return; + } + op_sla_info[WLAN_INDEX].dns_mark_times++; + dns_callback[0] = CELLULAR_MARK; + dns_callback[1] = SLA_SKB_MARKED; + } else { + dns_callback[0] = WLAN_MARK; + dns_callback[1] = SLA_SKB_ACCEPT; + } + } +} + +/** + * Design logic as below: + * 1. mobile not valid + * case a: wifi not valid, try to use wifi and fallback to cell each 5 times. + * case b: wifi quality bad, try to use wifi and fallback to cell each 10 times. + * case c: wifi good, use wifi. + * 2. mobile quality bad + * case a: wifi not valid, try to use cell and fallback to wifi each 10 times. + * case b: wifi quality bad, try to use wifi and fallback to cell each 5 times. + * case c: wifi good, use wifi. + * 3. mobile good + * case a: wifi not valid, try to use cell and fallback to wifi each 10 times. + * case b: wifi quality bad, try to use cell and fallback to wifi each 5 times. + * case c: wifi good, use wifi. + */ +void update_tcp_mark(unsigned int *tcp_callback, unsigned long time_now) +{ + int wlan_bad = op_get_wlan_quality(); + int cell_quality_good = op_get_cur_cell_quality(); + + if (is_iface_not_valid(CELLULAR_INDEX, time_now)) { + if (cell_quality_good && + ((is_iface_not_valid(WLAN_INDEX, time_now) && + op_sla_info[CELLULAR_INDEX].tcp_mark_times >= 5) || + (is_iface_quality_not_good(WLAN_INDEX) && + op_sla_info[CELLULAR_INDEX].tcp_mark_times >= 10))) { + op_sla_info[CELLULAR_INDEX].tcp_mark_times = 0; + tcp_callback[0] = CELLULAR_MARK; + return; + } + op_sla_info[CELLULAR_INDEX].tcp_mark_times++; + tcp_callback[0] = WLAN_MARK; + } else if (is_iface_quality_not_good(CELLULAR_INDEX)) { + if (is_iface_not_valid(WLAN_INDEX, time_now)) { + if (op_sla_info[WLAN_INDEX].tcp_mark_times >= 10) { + op_sla_info[WLAN_INDEX].tcp_mark_times = 0; + tcp_callback[0] = WLAN_MARK; + return; + } + op_sla_info[WLAN_INDEX].tcp_mark_times++; + tcp_callback[0] = CELLULAR_MARK; + } else { + if (is_iface_quality_not_good(WLAN_INDEX) && + op_sla_info[CELLULAR_INDEX].tcp_mark_times >= 5 && + cell_quality_good) { + op_sla_info[CELLULAR_INDEX].tcp_mark_times = 0; + tcp_callback[0] = CELLULAR_MARK; + return; + } + op_sla_info[CELLULAR_INDEX].tcp_mark_times++; + tcp_callback[0] = WLAN_MARK; + } + } else { + if (is_iface_not_valid(WLAN_INDEX, time_now) && cell_quality_good) { + if (op_sla_info[WLAN_INDEX].tcp_mark_times >= 10) { + op_sla_info[WLAN_INDEX].tcp_mark_times = 0; + tcp_callback[0] = WLAN_MARK; + return; + } + op_sla_info[WLAN_INDEX].tcp_mark_times++; + tcp_callback[0] = CELLULAR_MARK; + } else if (is_iface_quality_not_good(WLAN_INDEX) && cell_quality_good) { + if (op_sla_info[WLAN_INDEX].tcp_mark_times >= 5 && !wlan_bad) { + op_sla_info[WLAN_INDEX].tcp_mark_times = 0; + tcp_callback[0] = WLAN_MARK; + return; + } + op_sla_info[WLAN_INDEX].tcp_mark_times++; + tcp_callback[0] = CELLULAR_MARK; + } else { + tcp_callback[0] = WLAN_MARK; + } + } +} + +void update_sla_icmp_info(unsigned int dst_addr, unsigned int wifiip, unsigned int cellip) +{ + if (dst_addr == wifiip && + op_sla_info[WLAN_INDEX].icmp_unreachable < 2) { + op_sla_info[WLAN_INDEX].icmp_unreachable++; + calc_rtt_by_dev_index(WLAN_INDEX, UNREACHABLE_RTT); + } else if (dst_addr == cellip && + op_sla_info[CELLULAR_INDEX].icmp_unreachable < 2) { + op_sla_info[CELLULAR_INDEX].icmp_unreachable++; + calc_rtt_by_dev_index(CELLULAR_INDEX, UNREACHABLE_RTT); + } +} + +void reset_sla_info(void) +{ + op_sla_enable = 0; + if (!op_sla_info[WLAN_INDEX].if_up) { + op_sla_info[WLAN_INDEX].syn_retran = 0; + op_sla_info[WLAN_INDEX].dns_refuse = 0; + op_sla_info[WLAN_INDEX].dns_query_counts = 0; + op_sla_info[WLAN_INDEX].dns_mark_times = 0; + op_sla_info[WLAN_INDEX].tcp_mark_times = 0; + op_sla_info[WLAN_INDEX].icmp_unreachable = 0; + op_sla_info[WLAN_INDEX].env_dirty_count = 0; + op_sla_info[WLAN_INDEX].sum_rtt = 0; + op_sla_info[WLAN_INDEX].avg_rtt = 0; + op_sla_info[WLAN_INDEX].rtt_index = 0; + } + if (!op_sla_info[CELLULAR_INDEX].if_up) { + op_sla_info[CELLULAR_INDEX].syn_retran = 0; + op_sla_info[CELLULAR_INDEX].dns_refuse = 0; + op_sla_info[CELLULAR_INDEX].dns_query_counts = 0; + op_sla_info[CELLULAR_INDEX].dns_mark_times = 0; + op_sla_info[CELLULAR_INDEX].tcp_mark_times = 0; + op_sla_info[CELLULAR_INDEX].icmp_unreachable = 0; + op_sla_info[CELLULAR_INDEX].env_dirty_count = 0; + op_sla_info[CELLULAR_INDEX].sum_rtt = 0; + op_sla_info[CELLULAR_INDEX].avg_rtt = 0; + op_sla_info[CELLULAR_INDEX].rtt_index = 0; + } +} + +void reset_sla_mobile_info(void) +{ + op_sla_info[CELLULAR_INDEX].syn_retran = 0; + op_sla_info[CELLULAR_INDEX].dns_refuse = 0; + op_sla_info[CELLULAR_INDEX].dns_query_counts = 0; + op_sla_info[CELLULAR_INDEX].dns_mark_times = 0; + op_sla_info[CELLULAR_INDEX].tcp_mark_times = 0; + op_sla_info[CELLULAR_INDEX].icmp_unreachable = 0; + op_sla_info[CELLULAR_INDEX].env_dirty_count = 0; + op_sla_info[CELLULAR_INDEX].sum_rtt = 0; + op_sla_info[CELLULAR_INDEX].avg_rtt = 0; + op_sla_info[CELLULAR_INDEX].rtt_index = 0; +} + +void calc_rtt_by_dev_index(int index, int tmp_rtt) +{ + if (!sla_screen_on) + return; + + op_sla_info[index].rtt_index++; + if (tmp_rtt > MAX_RTT) + tmp_rtt = MAX_RTT; + op_sla_info[index].sum_rtt += tmp_rtt; +} + +void calc_network_rtt(void) +{ + int index = 0; + int avg_rtt = 0; + + for (index = 0; index < IFACE_NUM; index++) { + avg_rtt = 0; + if (op_sla_info[index].if_up) { + if (op_sla_info[index].rtt_index >= RTT_NUM) { + avg_rtt = op_sla_info[index].sum_rtt / op_sla_info[index].rtt_index; + op_sla_info[index].avg_rtt = (7 * op_sla_info[index].avg_rtt + avg_rtt) / 8; + op_sla_info[index].sum_rtt = 0; + op_sla_info[index].rtt_index = 0; + } + } + } +} + +int try_to_fast_reset(int app_type) +{ + if (app_type != APP_WECHAT && app_type != APP_WECHAT_PARALLEL) + return 1; + return 0; +} diff --git a/drivers/oneplus/power/Kconfig b/drivers/oneplus/power/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..e61ca251444e40e63db8303a5a3b326c640ba64c --- /dev/null +++ b/drivers/oneplus/power/Kconfig @@ -0,0 +1,3 @@ +# oem device driver for charge +# +source "drivers/oneplus/power/supply/Kconfig" diff --git a/drivers/oneplus/power/Makefile b/drivers/oneplus/power/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cc45babc31d04949ac147c5ddb99e5211ada63ae --- /dev/null +++ b/drivers/oneplus/power/Makefile @@ -0,0 +1,4 @@ +# oem device driver for charge +# +obj-$(CONFIG_OP_POWER_SUPPLY) += supply/ +obj-$(CONFIG_OP_POWER_SUPPLY) += OP_power_cut_test.o diff --git a/drivers/oneplus/power/OP_power_cut_test.c b/drivers/oneplus/power/OP_power_cut_test.c new file mode 100755 index 0000000000000000000000000000000000000000..81c93f77de7a30392bebbc9387e0c176756b4527 --- /dev/null +++ b/drivers/oneplus/power/OP_power_cut_test.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +// martin.li@coreBsp,2020.1.25 add for power cut testing +int power_cut_mode, power_cut_delay; +struct delayed_work power_cut_delayed_work; +static void __iomem *op_msm_ps_hold; +#define SCM_IO_DEASSERT_PS_HOLD 2 + +static int __init power_cut_test_param(char *str) +{ + int value = simple_strtol(str, NULL, 0); + int min, max, tmp; + + power_cut_mode = value/1000000; + min = (value%1000000)/1000 ; + max = value%1000; + + if(min > max) { + tmp = min; + min = max; + max = tmp; + } + + pr_info("power cut test mode:%d, mindelay:%d, maxdelay:%d, value:%d\n", + power_cut_mode, min, max, value); + + if(min == max) + power_cut_delay = min; + else + power_cut_delay = get_random_u32()%(max - min + 1) + min; + + pr_info("power cut test delay %d\n", power_cut_delay); + return 0; +} +__setup("androidboot.power_cut_test=", power_cut_test_param); + +static void deassert_ps_hold(void) +{ + struct scm_desc desc = { + .args[0] = 0, + .arginfo = SCM_ARGS(1), + }; + + if (scm_is_call_available(SCM_SVC_PWR, SCM_IO_DEASSERT_PS_HOLD) > 0) { + /* This call will be available on ARMv8 only */ + scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_PWR, + SCM_IO_DEASSERT_PS_HOLD), &desc); + } + printk("%s:%d\n",__func__,__LINE__); + /* Fall-through to the direct write in case the scm_call "returns" */ + __raw_writel(0, op_msm_ps_hold); +} + +void drop_pshold_work_func (struct work_struct *p_work) +{ + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + deassert_ps_hold(); +} +void batfet_work_func (struct work_struct *p_work) +{ + return; +} + +static ssize_t write_deassert_ps_hold(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + if (count) { + char c; + + if (get_user(c, buf)) + return -EFAULT; + + if (c == 'c') { + qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + deassert_ps_hold(); + } + } + + return count; +} + +static const struct file_operations deassert_ps_hold_operations = { + .write = write_deassert_ps_hold, + .llseek = noop_llseek, +}; + +static int init_power_cut_test(void) +{ + struct device_node *np; + + np = of_find_compatible_node(NULL, NULL,"qcom,pshold"); + if (!np) { + pr_err("unable to find pshold-base node\n"); + } else { + op_msm_ps_hold = of_iomap(np, 0); + if (!op_msm_ps_hold) { + pr_err("unable to map pshold-base offset\n"); + return -ENOMEM; + } + + if (!proc_create("deassert_ps_hold", S_IWUSR, NULL, + &deassert_ps_hold_operations)) + pr_err("Failed to register proc interface\n"); + } + + switch (power_cut_mode) { + case 1:// drop ps hold + INIT_DELAYED_WORK(&power_cut_delayed_work, drop_pshold_work_func); + schedule_delayed_work(&power_cut_delayed_work, msecs_to_jiffies(power_cut_delay*1000)); + break; + case 2:// force all power off + INIT_DELAYED_WORK(&power_cut_delayed_work, batfet_work_func); + schedule_delayed_work(&power_cut_delayed_work, msecs_to_jiffies(power_cut_delay*1000)); + break; + default: + return 0; + } + return 0; +} +core_initcall(init_power_cut_test); diff --git a/drivers/oneplus/power/supply/Kconfig b/drivers/oneplus/power/supply/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..95da8d7ec12c273c78ec15137ba65decb2b85a95 --- /dev/null +++ b/drivers/oneplus/power/supply/Kconfig @@ -0,0 +1,8 @@ +# oem device driver for charge +# +source "drivers/oneplus/power/supply/qcom/Kconfig" +source "drivers/oneplus/power/supply/wlchg/Kconfig" + +config OP_POWER_SUPPLY + default y + bool "Enable/Disable oneplus power related drivers" diff --git a/drivers/oneplus/power/supply/Makefile b/drivers/oneplus/power/supply/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..37f4fa19058e826baf2d6569808148447c57b0f0 --- /dev/null +++ b/drivers/oneplus/power/supply/Makefile @@ -0,0 +1,5 @@ +# oem device driver for charge +# +obj-$(CONFIG_ARCH_QCOM) += qcom/ +obj-$(CONFIG_ONEPLUS_WIRELESSCHG) += wlchg/ + diff --git a/drivers/oneplus/power/supply/qcom/Kconfig b/drivers/oneplus/power/supply/qcom/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..4dc0296649515eb59efc1974ed0ba7c3effb4ae4 --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/Kconfig @@ -0,0 +1,43 @@ +# oem device driver for charge + +config FG_BQ27541 + tristate "TI bq27541 fg" + depends on I2C + help + Say Y here to enable the TI Fuel Gauge driver.This adds support + for battery fuel gauging and state of charge of battery connected to + the fuel gauge. The state of charge is reported through a BMS power + supply property and also sends uevents when the capacity is updated. + +config OP_DEBUG_CHG + tristate "OP DEBUG CHARGE" + depends on MFD_SPMI_PMIC + help + Enables support for the debug charging peripheral + When use agingboot,can dump pmic register and + print vbus vbat current information + a + +config ONEPLUS_FASTCHG + tristate "ONEPLUS FAST CHARGE" + depends on I2C + help + Say Y here to enable the ONEPLUS FAST CHARGE driver.This adds support + for WARP charge and state of charge of battery connected to + the battery. The state of charge is reported through a battery power + supply property + +config CP_DA9313 + tristate "Dialog da9313 dual cell switched capacitor divider" + depends on I2C + help + Say Y here to enable the da9313 divider driver.This adds support + for dual cell switched capacitor divider to power system. + +config CHGIC_MP2762 + tristate "MPS mp2762 buck and boost charger ic" + depends on I2C + help + Say Y here to enable the MP2762 buck and boost charger driver.This adds support + for dual cell switched capacitor divider to power system. + diff --git a/drivers/oneplus/power/supply/qcom/Makefile b/drivers/oneplus/power/supply/qcom/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4f19f45203912f99bb3eef8ae41c911ccaeb8eec --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/Makefile @@ -0,0 +1,6 @@ +# oem device driver for charge +obj-$(CONFIG_FG_BQ27541) += bq27541_fuelgauger.o +obj-$(CONFIG_ONEPLUS_FASTCHG) += oneplus_fastchg.o +obj-$(CONFIG_CP_DA9313) += op_da9313.o +obj-$(CONFIG_CHGIC_MP2762) += op_mp2650.o + diff --git a/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.c b/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.c new file mode 100644 index 0000000000000000000000000000000000000000..951bd24864e0a6b83421be803ee6b1ac85aadb40 --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.c @@ -0,0 +1,2635 @@ +/* Copyright (C) 2008 Rodolfo Giometti + * Copyright (C) 2008 Eurotech S.p.A. + * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. + * + * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ +#define pr_fmt(fmt) "BQ: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF +#include +#include +#endif +#include +#include +#include +#include "bq27541_fuelgauger.h" + +/* If the system has several batteries we need a different name for each + * of them... + */ +static DEFINE_IDR(battery_id); +static DEFINE_MUTEX(battery_mutex); +static DEFINE_MUTEX(bq28z610_alt_manufacturer_access); + +int panel_flag1; +int panel_flag2; + +struct update_pre_capacity_data { + struct delayed_work work; + struct workqueue_struct *workqueue; + int suspend_time; +}; +static struct update_pre_capacity_data update_pre_capacity_data; +static int __debug_temp_mask; +module_param_named( + debug_temp_mask, __debug_temp_mask, int, 0600 +); +static void bq27411_modify_soc_smooth_parameter( + struct bq27541_device_info *di, bool is_powerup); + +static int bq27541_i2c_txsubcmd(u8 reg, unsigned short subcmd, + struct bq27541_device_info *di); +static int bq27541_average_current(struct bq27541_device_info *di); +static bool check_bat_present(struct bq27541_device_info *di); + +static int bq28z610_get_balancing_config(struct bq27541_device_info *di); +static int bq28z610_get_2cell_voltage(void); +static int bq27541_get_battery_mvolts_2cell_max(void); +static int bq27541_get_battery_mvolts_2cell_min(void); + +static int bq27541_read_i2c_block(u8 cmd, u8 length, u8 *returnData, + struct bq27541_device_info *di); +static void bq28z610_modify_soc_smooth_parameter(struct bq27541_device_info *di); +static int bq28z610_get_time_to_full(void); +static int bq27541_get_batt_bq_soc(void); +static bool get_dash_started(void); +static int bq27541_set_allow_reading(int enable); + +static int bq27541_read(u8 reg, int *rt_value, int b_single, + struct bq27541_device_info *di) +{ + return di->bus->read(reg, rt_value, b_single, di); +} + +/* + * Return the battery temperature in tenths of degree Celsius + * Or < 0 if something fails. + */ +#define TEMP_LT_16C 1//-2-3-4-5-6-7 +#define TEMP_LT_39C 2//-1-2-3-4-5 +#define TEMP_HT_39C 3//-1-2-3-4 +#define BATT_TEMP_16C 160 +#define BATT_TEMP_39C 390 +static int batt_balancing_config = 0; + +enum { + REFRESH_TRUE = 1, + REFRESH_FALSE +}; +#if 0 //not use now, build error +static int bq28z610_get_battery_balancing_status(void) +{ + return batt_balancing_config; +} +#endif + +static int bq27541_battery_temperature(struct bq27541_device_info *di) +{ + int ret; + int temp = 0; + int error_temp; + static int count; + static int pre_batt_balancing_config = 0; + static int cb_count = 0; + static int cb_flag = 0; + static int temp_status = 0; + static int delta_temp = 0; + struct task_struct *t = NULL; + + /* Add for get right*/ + /*soc when sleep long time */ + if (atomic_read(&di->suspended) == 1) + return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; + + if (di->allow_reading) { + +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + ret = bq27541_read(di->cmd_addr.reg_temp, + &temp, 0, di); +#else + ret = bq27541_read(BQ27541_REG_TEMP, &temp, 0, di); +#endif + /* Add for don't report battery*/ + /*not connect when reading error once. */ + if (ret) { + count++; + pr_err("error reading temperature\n"); + if (count > 1) { + count = 0; + /* Add for it report bad*/ + /*status when plug out battery */ + di->temp_pre = + -400 - ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; + error_temp = -400; + return error_temp; + } else { + return di->temp_pre + +ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; + } + } + count = 0; + } else { + return di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; + } + + if (di->bq28z610_need_balancing) { + t = get_current(); + if (t != NULL && !strncmp(t->comm, "tbatt_pwroff", 12)) + goto cb_exit; + + batt_balancing_config = bq28z610_get_balancing_config(di); + if (pre_batt_balancing_config == 0 && batt_balancing_config == 1 && temp_status == 0) { + if (di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN <= BATT_TEMP_16C) { + temp_status = TEMP_LT_16C; + delta_temp = 10; + } else if (di->temp_pre + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN <= BATT_TEMP_39C) { + temp_status = TEMP_LT_39C; + delta_temp = 0; + } else { + temp_status = TEMP_HT_39C; + delta_temp = 0; + } + printk(KERN_ERR "SJC-TEST: temp_status[%d], delta_temp[%d]\n", temp_status, delta_temp); + } + pre_batt_balancing_config = batt_balancing_config; + + if (batt_balancing_config == 1) { + + cb_flag = 1; + cb_count++; + + if (cb_count >= 6 && temp_status == TEMP_LT_16C) { + temp = temp - (60 + delta_temp); + printk(KERN_ERR "SJC-TEST: - %d\n", 60 + delta_temp); + } else if (cb_count >= 5 && temp_status != TEMP_HT_39C) { + temp = temp - (50 + delta_temp); + printk(KERN_ERR "SJC-TEST: - %d\n", 50 + delta_temp); + } else if (cb_count >= 4) { + temp = temp - (40 + delta_temp); + printk(KERN_ERR "SJC-TEST: - %d\n", 40 + delta_temp); + } else if (cb_count >= 3) { + temp = temp - (30 + delta_temp); + printk(KERN_ERR "SJC-TEST: - %d\n", 30 + delta_temp); + } else if (cb_count >= 2) { + temp = temp - (20 + delta_temp); + printk(KERN_ERR "SJC-TEST: - %d\n", 20 + delta_temp); + } else if (cb_count >= 1) { + temp = temp - (10 + delta_temp); + printk(KERN_ERR "SJC-TEST: - %d\n", 10 + delta_temp); + } + + if (temp_status == TEMP_LT_16C) { + if (cb_count >= 6) + cb_count = 6; + } else if (temp_status != TEMP_HT_39C) { + if (cb_count >= 5) + cb_count = 5; + } else { + if (cb_count >= 4) + cb_count = 4; + } + } else if (cb_flag == 1 && cb_count > 0) { + if (cb_count >= 6 && temp_status == TEMP_LT_16C) { + temp = temp - (60 + delta_temp); + printk(KERN_ERR "SJC-TEST 6: - %d\n", 60 + delta_temp); + } else if (cb_count >= 5 && temp_status != TEMP_HT_39C) { + temp = temp - (50 + delta_temp); + printk(KERN_ERR "SJC-TEST 5: - %d\n", 50 + delta_temp); + } else if (cb_count >= 4) { + temp = temp - (40 + delta_temp); + printk(KERN_ERR "SJC-TEST 4: - %d\n", 40 + delta_temp); + } else if (cb_count >= 3) { + temp = temp - (30 + delta_temp); + printk(KERN_ERR "SJC-TEST 3: - %d\n", 30 + delta_temp); + } else if (cb_count >= 2) { + temp = temp - (20 + delta_temp); + printk(KERN_ERR "SJC-TEST 2: - %d\n", 20 + delta_temp); + } else if (cb_count >= 1) { + temp = temp - (10 + delta_temp); + printk(KERN_ERR "SJC-TEST 1: - %d\n", 10 + delta_temp); + } + cb_count--; + } else { + cb_count = 0; + cb_flag = 0; + temp_status = 0; + delta_temp = 0; + } + } + +cb_exit: + di->temp_pre = temp; + return temp + ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN; +} + +/* + * Return the battery Voltage in milivolts + * Or < 0 if something fails. + */ +static int bq27541_battery_voltage(struct bq27541_device_info *di) +{ + int ret; + int volt = 0; + + /* Add for get right soc when sleep long time */ + if (atomic_read(&di->suspended) == 1) + return di->batt_vol_pre; + + if (di->allow_reading) { +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + ret = bq27541_read(di->cmd_addr.reg_volt, + &volt, 0, di); +#else + ret = bq27541_read(BQ27541_REG_VOLT, &volt, 0, di); +#endif + if (ret) { + pr_err("error reading voltage,ret:%d\n", ret); + di->batt_cell_max_vol = di->max_vol_pre; + di->batt_cell_min_vol = di->min_vol_pre; + return di->batt_vol_pre; + } + + if(di->batt_bq28z610) { + bq28z610_get_2cell_voltage(); + di->max_vol_pre = di->batt_cell_max_vol; + di->min_vol_pre = di->batt_cell_min_vol; + //return di->batt_cell_max_vol; + volt = di->batt_cell_max_vol; + //bq28z610_get_2cell_balance_time(); + } else { + di->batt_cell_max_vol = volt; + di->batt_cell_min_vol = volt; + di->max_vol_pre = di->batt_cell_max_vol; + di->min_vol_pre = di->batt_cell_min_vol; + } + di->batt_vol_pre = volt * 1000; + } + + return di->batt_vol_pre; +} + +static int bq28z610_get_balancing_config(struct bq27541_device_info *di) +{ + u8 data[4] = {0, 0, 0, 0}; + int ret = 0; + int balancing_config = 0; + static int pre_balancing_config = 0; + static int count = 0; + + if (!di) { + return 0; + } + + if (atomic_read(&di->suspended) == 1) { + return 0; + } + + if (di->batt_bq28z610) { + if (di->allow_reading) { + mutex_lock(&bq28z610_alt_manufacturer_access); + bq27541_i2c_txsubcmd(BQ28Z610_OPERATION_STATUS_EN_ADDR, + BQ28Z610_OPERATION_STATUS_CMD, di); + usleep_range(1000, 1000); + ret = bq27541_read_i2c_block(BQ28Z610_REG_OPERATION_STATUS_ADDR, + BQ28Z610_OPERATION_STATUS_SIZE, data, di); + mutex_unlock(&bq28z610_alt_manufacturer_access); + if (ret) { + dev_err(di->dev, "error reading operation status.\n"); + return pre_balancing_config; + } + balancing_config = ((data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]) + & BQ28Z610_BALANCING_CONFIG_BIT) >> 28; + count++; + if (balancing_config ^ pre_balancing_config || count >= 10) { + count = 0; + dev_info(di->dev, "operation status[0x%x], cb28[%d]\n", + data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0], balancing_config); + } + pre_balancing_config = balancing_config; + return balancing_config; + } else { + return pre_balancing_config; + } + } + return 0; +} + +static void bq27541_cntl_cmd(struct bq27541_device_info *di, + int subcmd) +{ + mutex_lock(&battery_mutex); + bq27541_i2c_txsubcmd(BQ27541_REG_CNTL, subcmd, di); + mutex_unlock(&battery_mutex); + +} + +/* + * i2c specific code + */ +static int bq27541_i2c_txsubcmd(u8 reg, unsigned short subcmd, + struct bq27541_device_info *di) +{ + struct i2c_msg msg; + unsigned char data[3]; + int ret; + + if (!di->client) + return -ENODEV; + + memset(data, 0, sizeof(data)); + data[0] = reg; + data[1] = subcmd & 0x00FF; + data[2] = (subcmd & 0xFF00) >> 8; + + msg.addr = di->client->addr; + msg.flags = 0; + msg.len = 3; + msg.buf = data; + + ret = i2c_transfer(di->client->adapter, &msg, 1); + if (ret < 0) + return -EIO; + + return 0; +} + +static int bq27541_chip_config(struct bq27541_device_info *di) +{ + int flags = 0, ret = 0; + + bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + ret = bq27541_read(BQ27541_REG_CNTL, &flags, 0, di); + if (ret < 0) { + pr_err("error reading register %02x ret = %d\n", + BQ27541_REG_CNTL, ret); + return ret; + } + udelay(66); + + bq27541_cntl_cmd(di, BQ27541_SUBCMD_ENABLE_IT); + udelay(66); + + if (!(flags & BQ27541_CS_DLOGEN)) { + bq27541_cntl_cmd(di, BQ27541_SUBCMD_ENABLE_DLOG); + udelay(66); + } + + return 0; +} +static bool bq27541_registered; +struct bq27541_device_info *bq27541_di; +static struct i2c_client *new_client; + +#define TEN_PERCENT 10 +#define SOC_SHUTDOWN_VALID_LIMITS 19 +#define TEN_MINUTES 600 +#define FIVE_MINUTES 300 +#define TWO_POINT_FIVE_MINUTES 150 +#define ONE_MINUTE 60 +#define TWENTY_MINUTES 1200 +#define TWENTY_PERCENT 20 +#define TWENTY_SECS 20 + + +#define CAPACITY_SALTATE_COUNTER_60 38 /* 40 1min */ +#define CAPACITY_SALTATE_COUNTER_95 78 /* 60 2.5min */ +#define CAPACITY_SALTATE_COUNTER_FULL 200 /* 150 120 5min */ +#define CAPACITY_SALTATE_COUNTER_CHARGING_TERM 30 /* 30 1min */ +#define CAPACITY_SALTATE_COUNTER 4 +#define CAPACITY_SALTATE_COUNTER_NOT_CHARGING 24 /* >=40sec */ +#define LOW_BATTERY_PROTECT_VOLTAGE 3300000 +#define CAPACITY_CALIBRATE_TIME_60_PERCENT 45 /* 45s */ +#define LOW_BATTERY_CAPACITY_THRESHOLD 20 + +#define SHORT_TIME_STANDBY_SOC_CHECK_COUNT 15 +#define LOW_BATTERY_LEVEL_THRESHOLD 8 +#define BATTERY_SOC_UPDATE_MS 12000 +#define LOW_BAT_SOC_UPDATE_MS 6000 + +#define RESUME_SCHDULE_SOC_UPDATE_WORK_MS 60000 + +static int get_current_time(unsigned long *now_tm_sec) +{ + struct rtc_time tm; + struct rtc_device *rtc; + int rc; + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc == NULL) { + pr_err("%s: unable to open rtc device (%s)\n", + __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); + return -EINVAL; + } + + rc = rtc_read_time(rtc, &tm); + if (rc) { + pr_err("Error reading rtc device (%s) : %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + rc = rtc_valid_tm(&tm); + if (rc) { + pr_err("Invalid RTC time (%s): %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + rtc_tm_to_time(&tm, now_tm_sec); + +close_time: + rtc_class_close(rtc); + return rc; +} + +bool get_4p45_battery_support(void) +{ + if (bq27541_di->bat_4p45v) + return true; + else + return false; +} + +int get_prop_pre_shutdown_soc(void) +{ + int soc_load; + + soc_load = load_soc(); + if (soc_load == -1) + return 50; + else + return soc_load; +} + +static int fg_soc_calibrate(struct bq27541_device_info *di, int soc) +{ + union power_supply_propval ret = {0,}; + unsigned int soc_calib; + unsigned long soc_current_time, time_last; + static bool first_enter; + static int charging_status, charging_status_pre; + bool chg_done; + int temp_region, vbat_mv, ibat_ma, soc_load, soc_temp, counter_temp = 0; + + if (false == first_enter) { + di->batt_psy = power_supply_get_by_name("battery"); + if (di->batt_psy) { + first_enter = true; + soc_load = load_soc(); + pr_info("soc=%d, soc_load=%d\n", soc, soc_load); + if (soc_load < 0) { + /* get last soc error */ + di->soc_pre = soc; + } else if (soc_load >= 0 && soc_load < 100) { + if (abs(soc_load - soc) > SOC_SHUTDOWN_VALID_LIMITS) + di->soc_pre = soc; + else if (soc_load > soc) + di->soc_pre = soc_load - 1; + else + di->soc_pre = soc_load; + } else if (soc_load == 100 + && abs(soc_load - soc) > TEN_PERCENT) { + /* decrease soc when gap between soc_load and */ + /* real_soc is over 10% */ + di->soc_pre = soc_load - 1; + } else { + di->soc_pre = soc_load; + } + + if (!di->batt_psy) { + pr_err( + "batt_psy is absent, soc_pre=%d\n", + di->soc_pre); + return di->soc_pre; + } + /* store the soc when boot first time */ + get_current_time(&di->soc_pre_time); + clean_backup_soc_ex(); + } else { + return soc; + } + } + soc_temp = di->soc_pre; + + if (!di->batt_psy) { + soc_calib = soc; + goto out; + } + + ret.intval = get_charging_status(); + di->batt_vol_pre = bq27541_battery_voltage(di); + chg_done = get_oem_charge_done_status(); + temp_region = fuelgauge_battery_temp_region_get(); + if ((temp_region == BATT_TEMP_LITTLE_COOL + || temp_region == BATT_TEMP_COOL + || temp_region == BATT_TEMP_NORMAL + || temp_region == BATT_TEMP_PRE_NORMAL) + && chg_done) { + ret.intval = POWER_SUPPLY_STATUS_FULL; + } + + if (ret.intval == POWER_SUPPLY_STATUS_CHARGING + || ret.intval == POWER_SUPPLY_STATUS_FULL + || bq27541_di->fastchg_started + || bq27541_di->wlchg_started) + charging_status = 1; + else + charging_status = 0; + + if (charging_status ^ charging_status_pre) { + if (charging_status_pre) { + get_current_time(&soc_current_time); + di->soc_store_time = + soc_current_time - di->soc_pre_time; + } + + get_current_time(&di->soc_pre_time); + if (!charging_status_pre && di->soc_store_time) + di->soc_pre_time -= di->soc_store_time; + charging_status_pre = charging_status; + di->saltate_counter = 0; + } + + get_current_time(&soc_current_time); + time_last = soc_current_time - di->soc_pre_time; + if (charging_status) { /* is charging */ + if (ret.intval == POWER_SUPPLY_STATUS_FULL) { + soc_calib = di->soc_pre; + if (di->soc_pre < 100 + && (temp_region == BATT_TEMP_LITTLE_COOL + || temp_region == BATT_TEMP_NORMAL + || temp_region == BATT_TEMP_PRE_NORMAL + || temp_region == BATT_TEMP_COOL)) { + if (time_last > TWENTY_SECS) + soc_calib = di->soc_pre + 1; + } + } else { + if (soc - di->soc_pre > 0) { + di->saltate_counter++; + if ((bq27541_di->fastchg_started + && time_last < 10) + || (!bq27541_di->fastchg_started + && time_last < 20)) + return di->soc_pre; + di->saltate_counter = 0; + soc_calib = di->soc_pre + 1; + } else if (soc < (di->soc_pre - 1)) { + di->saltate_counter++; + if (di->soc_pre == 100) { + counter_temp = + CAPACITY_SALTATE_COUNTER_FULL; + /* t>=5min */ + } else if (di->soc_pre > 95) { + counter_temp = + CAPACITY_SALTATE_COUNTER_95; + /* t>=2.5min */ + } else if (di->soc_pre > 60) { + counter_temp = + CAPACITY_SALTATE_COUNTER_60; + /* t>=1min */ + } else { + if (time_last > + CAPACITY_CALIBRATE_TIME_60_PERCENT + && (soc - di->soc_pre) < 0) + counter_temp = 0; + else + /* t>=40sec */ + counter_temp = + CAPACITY_SALTATE_COUNTER_NOT_CHARGING; + } + + /* avoid dead battery shutdown */ + if (di->batt_vol_pre <= + LOW_BATTERY_PROTECT_VOLTAGE + && di->batt_vol_pre > 2500 * 1000 + && di->soc_pre + <= LOW_BATTERY_CAPACITY_THRESHOLD) { + /* check again */ + vbat_mv = + bq27541_battery_voltage(di); + if (vbat_mv <= + LOW_BATTERY_PROTECT_VOLTAGE + && vbat_mv > 2500 * 1000) { + /* about 9s */ + counter_temp = + CAPACITY_SALTATE_COUNTER - 1; + } + } + + ibat_ma = bq27541_average_current(di); + if (ibat_ma <= 0 && di->soc_pre == 100) { + di->saltate_counter = 0; + return di->soc_pre; + } + /* don't allow soc down*/ + /*if chg current > -200mA */ + if (di->saltate_counter < counter_temp + || ibat_ma < -200 * 1000) + return di->soc_pre; + di->saltate_counter = 0; + + soc_calib = di->soc_pre - 1; + } else if ((soc == 0 && soc < di->soc_pre) + && di->soc_pre <= 2) { + di->saltate_counter++; + if (time_last > + CAPACITY_CALIBRATE_TIME_60_PERCENT + && (soc - di->soc_pre) < 0) + counter_temp = 0; + else + /* t>=40sec */ + counter_temp = + CAPACITY_SALTATE_COUNTER_NOT_CHARGING; + + if (di->saltate_counter < counter_temp) + return di->soc_pre; + di->saltate_counter = 0; + soc_calib = di->soc_pre - 1; + } else { + soc_calib = di->soc_pre; + } + } + } else { /* not charging */ + if ((soc < di->soc_pre) + || (di->batt_vol_pre <= LOW_BATTERY_PROTECT_VOLTAGE + && di->batt_vol_pre > 2500 * 1000)) { + if (di->soc_pre == 100) { + counter_temp = FIVE_MINUTES; + } else if (di->soc_pre >= 95) { + counter_temp = TWO_POINT_FIVE_MINUTES; + } else if (di->soc_pre >= 60) { + counter_temp = ONE_MINUTE; + } else { + if (time_last >= + CAPACITY_CALIBRATE_TIME_60_PERCENT + && (soc - di->soc_pre) < 0) + counter_temp = 0; + else + /* t>=40sec */ + counter_temp = + CAPACITY_SALTATE_COUNTER_NOT_CHARGING + + 20; + } + /* avoid dead battery shutdown */ + if (di->batt_vol_pre <= + LOW_BATTERY_PROTECT_VOLTAGE + && di->batt_vol_pre > 2500 * 1000 + && di->soc_pre <= + LOW_BATTERY_CAPACITY_THRESHOLD) { + /* check again */ + vbat_mv = bq27541_battery_voltage(di); + if (vbat_mv <= LOW_BATTERY_PROTECT_VOLTAGE + && vbat_mv > 2500 * 1000 && time_last > 9) + counter_temp = 0; + } + + if (time_last < counter_temp) + return di->soc_pre; + } + + if (soc < di->soc_pre) + soc_calib = di->soc_pre - 1; + else if (di->batt_vol_pre <= LOW_BATTERY_PROTECT_VOLTAGE + && di->batt_vol_pre > 2500 * 1000 + && di->soc_pre > 0 && time_last > 9) + soc_calib = di->soc_pre - 1; + else + soc_calib = di->soc_pre; + } + +out: + if (soc_calib > 100) + soc_calib = 100; + if (soc_calib < 0) + soc_calib = 0; + if (soc_calib == 0) { + if ((di->batt_vol_pre/1000) > 3300) + soc_calib = 1; + } + di->soc_pre = soc_calib; + if (soc_temp != soc_calib) { + get_current_time(&di->soc_pre_time); + /* store when soc changed */ + power_supply_changed(di->batt_psy); + pr_info("soc:%d, soc_calib:%d, VOLT:%d, current:%d\n", + soc, soc_calib, bq27541_battery_voltage(di) / 1000, + bq27541_average_current(di) / 1000); + } + + return soc_calib; +} + + +static int bq27541_battery_soc( +struct bq27541_device_info *di, int suspend_time_ms) +{ + int ret; + int soc = 0; + int soc_delt = 0; + static int soc_pre; + bool fg_soc_changed = false; + + /* Add for get right soc when sleep long time */ + if (atomic_read(&di->suspended) == 1) { + dev_warn(di->dev, + "di->suspended di->soc_pre=%d\n", di->soc_pre); + return di->soc_pre; + } + + if (di->allow_reading) { +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + ret = bq27541_read(di->cmd_addr.reg_soc, + &soc, 0, di); +#else + ret = bq27541_read(BQ27541_REG_SOC, &soc, 0, di); +#endif + if (ret) { + pr_err("error reading soc=%d, ret:%d\n", soc, ret); + goto read_soc_err; + } + if (soc_pre != soc) + pr_err("bq27541_battery_soc = %d\n", soc); + + soc_pre = soc; + } else { + if (di->soc_pre) + return di->soc_pre; + else + return 0; + } + /* Add for get right soc when sleep long time */ + if (suspend_time_ms && di->lcd_is_off) { + if (soc < di->soc_pre) { + soc_delt = di->soc_pre - soc; + fg_soc_changed = (soc < TWENTY_PERCENT + || soc_delt > di->lcd_off_delt_soc + || suspend_time_ms > TEN_MINUTES); + pr_info("suspend_time_ms=%d,soc_delt=%d,di->lcd_off_delt_soc=%d\n", + suspend_time_ms, soc_delt, di->lcd_off_delt_soc); + if (fg_soc_changed) { + if (suspend_time_ms/TEN_MINUTES) { + di->soc_pre -= + (suspend_time_ms / TEN_MINUTES < soc_delt + ? suspend_time_ms / TEN_MINUTES : soc_delt); + } else if (di->soc_pre - soc > TEN_PERCENT) + di->soc_pre -= TEN_PERCENT/2; + else { + di->soc_pre -= 1; + } + /* store when soc changed */ + get_current_time(&di->soc_pre_time); + power_supply_changed(di->batt_psy); + pr_err("system resume,soc:%d, soc_calib:%d,VOLT:%d,current:%d\n", + soc, di->soc_pre, + bq27541_battery_voltage(di) / 1000, + bq27541_average_current(di) / 1000); + } + } + goto read_soc_err; + } + if (di->disable_calib_soc) + return soc; + soc = fg_soc_calibrate(di, soc); + return soc; + +read_soc_err: + if (di->soc_pre) { + dev_warn(di->dev, + "read_soc_exit ,di->soc_pre=%d\n", di->soc_pre); + return di->soc_pre; + } else + return 0; +} + +static int bq27541_average_current(struct bq27541_device_info *di) +{ + int ret; + int curr = 0; + + /* Add for get right soc when sleep long time */ + if (atomic_read(&di->suspended) == 1) + return -di->current_pre; + + if (di->allow_reading) { +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + ret = bq27541_read(di->cmd_addr.reg_ai, + &curr, 0, di); +#else + ret = bq27541_read(BQ27541_REG_AI, &curr, 0, di); +#endif + if (ret) { + pr_err("error reading current.\n"); + return ret; + } + } else { + return -di->current_pre; + } + /* negative current */ + if (curr & 0x8000) + curr = -((~(curr-1)) & 0xFFFF); + di->current_pre = 1000 * curr; + return -curr * 1000; +} + +static int bq27541_remaining_capacity(struct bq27541_device_info *di) +{ + int ret; + int cap = 0; + + if (atomic_read(&di->suspended) == 1) + return di->remain_pre; + if (di->allow_reading || panel_flag1) { +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + ret = bq27541_read(di->cmd_addr.reg_rm, + &cap, 0, di); +#else + ret = bq27541_read(BQ27541_REG_RM, &cap, 0, di); +#endif + if (ret) { + pr_err("error reading capacity.\n"); + return ret; + } + if (panel_flag1) + panel_flag1 = 0; + } else { + return di->remain_pre; + } + + di->remain_pre = cap; + return cap; +} +static int bq27541_full_chg_capacity(struct bq27541_device_info *di) +{ + int ret; + int cap = 0; + + /* Add for get right soc when sleep long time */ + if (atomic_read(&di->suspended) == 1) + return di->cap_pre; + + if (di->allow_reading || panel_flag2) { +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + ret = bq27541_read(di->cmd_addr.reg_fcc, + &cap, 0, di); +#else + ret = bq27541_read(BQ27541_REG_FCC, &cap, 0, di); +#endif + if (ret) { + pr_err("error reading full chg capacity.\n"); + return ret; + } + if (panel_flag2) + panel_flag2 = 0; + } else { + return di->cap_pre; + } + + di->cap_pre = cap; + return cap; +} + + +static int bq27541_batt_health(struct bq27541_device_info *di) +{ + int ret; + int health = 0; + + if (di->allow_reading) { + ret = bq27541_read(di->cmd_addr.reg_helth, + &health, 0, di); + if (ret) { + pr_err("error reading health\n"); + return ret; + } + if (di->device_type == DEVICE_BQ27411) + di->health_pre = (health & 0xFF); + else + di->health_pre = health; + } + + return di->health_pre; +} + +static int bq27541_get_battery_mvolts(void) +{ + return bq27541_battery_voltage(bq27541_di); +} + +static int bq27541_get_batt_remaining_capacity(void) +{ + return bq27541_remaining_capacity(bq27541_di); +} + +static int bq27541_get_batt_full_chg_capacity(void) +{ + return bq27541_full_chg_capacity(bq27541_di); +} +static int bq27541_get_batt_health(void) +{ + return bq27541_batt_health(bq27541_di); +} +static int bq27541_get_batt_bq_soc(void) +{ + int soc; + + if (!get_dash_started()) { + if (!bq27541_di->allow_reading) + bq27541_set_allow_reading(true); + } + bq27541_di->disable_calib_soc = true; + soc = bq27541_battery_soc(bq27541_di, 0); + bq27541_di->disable_calib_soc = false; + if (!get_dash_started()) { + if (!bq27541_di->allow_reading) + bq27541_set_allow_reading(false); + } + return soc; +} +static bool battery_is_match(void) +{ + if (!bq27541_di->check_match) + return true; + + if ((bq27541_di->fw_ver == FW_VERSION_4P45V_01 + || bq27541_di->fw_ver == FW_VERSION_4P45V_02) + && bq27541_di->bat_4p45v) + return true; + else if (bq27541_di->fw_ver != FW_VERSION_4P45V_01 + && bq27541_di->fw_ver != FW_VERSION_4P45V_02 + && !bq27541_di->bat_4p45v) + return true; + else + return false; +} + +#define SHUTDOWN_TBAT 680 +static int bq27541_get_battery_temperature(void) +{ + int ret; + static unsigned long pre_time; + unsigned long current_time, time_last; + + if (__debug_temp_mask) + return __debug_temp_mask; + if (bq27541_di->bat_4p45v) { + if (!battery_is_match()) + return SHUTDOWN_TBAT+10; + } + ret = bq27541_battery_temperature(bq27541_di); + if (ret >= SHUTDOWN_TBAT) { + bq27541_di->t_count++; + if (bq27541_di->t_count == 1) + get_current_time(&pre_time); + get_current_time(¤t_time); + time_last = current_time - pre_time; + if (time_last < 8) + return SHUTDOWN_TBAT - 1; + else { + pr_info("Tbat =%d T_tol=%d\n", + ret, (int)(current_time - pre_time)); + } + } + bq27541_di->t_count = 0; + return ret; +} +static bool bq27541_is_battery_present(void) +{ + return check_bat_present(bq27541_di); +} + +static bool bq27541_is_battery_temp_within_range(void) +{ + return true; +} + +static bool bq27541_is_battery_id_valid(void) +{ + return true; +} + +#ifdef CONFIG_GAUGE_BQ27411 +/* david.liu@bsp, 20161025 Add BQ27411 dash charging */ +static int bq27541_get_device_type(void) +{ + if (bq27541_di) + return bq27541_di->device_type; + + return 0; +} +#endif + +static int bq27541_get_battery_soc(void) +{ + return bq27541_battery_soc(bq27541_di, 0); +} + +static int bq27541_get_average_current(void) +{ + return bq27541_average_current(bq27541_di); +} + +static int bq27541_set_allow_reading(int enable) +{ + if (bq27541_di) + bq27541_di->allow_reading = enable; + + return 0; +} + +static int bq27541_set_lcd_off_status(int off) +{ + int soc; + + pr_info("off=%d\n", off); + if (bq27541_di && bq27541_registered) { + if (off) { + soc = bq27541_get_batt_bq_soc(); + bq27541_di->lcd_off_delt_soc = + bq27541_di->soc_pre - soc; + pr_info("lcd_off_delt_soc:%d,soc=%d,soc_pre=%d\n", + bq27541_di->lcd_off_delt_soc, soc, + bq27541_di->soc_pre); + get_current_time(&bq27541_di->lcd_off_time); + bq27541_di->lcd_is_off = true; + } else { + bq27541_di->lcd_is_off = false; + bq27541_di->lcd_off_delt_soc = 0; + schedule_delayed_work(&bq27541_di->battery_soc_work, + msecs_to_jiffies(RESUME_SCHDULE_SOC_UPDATE_WORK_MS)); + } + } + return 0; +} + +static int bq27541_get_fastchg_started_status(bool fastchg_started_status) +{ + if (bq27541_di) + bq27541_di->fastchg_started = fastchg_started_status; + + return 0; +} + +static int bq27541_set_wlchg_started_status(bool wlchg_started_status) +{ + if (bq27541_di) + bq27541_di->wlchg_started = wlchg_started_status; + + return 0; +} + +static struct external_battery_gauge bq27541_batt_gauge = { + .get_battery_mvolts = bq27541_get_battery_mvolts, + .get_battery_mvolts_2cell_max = bq27541_get_battery_mvolts_2cell_max, + .get_battery_mvolts_2cell_min = bq27541_get_battery_mvolts_2cell_min, + .get_battery_temperature = bq27541_get_battery_temperature, + .is_battery_present = bq27541_is_battery_present, + .is_battery_temp_within_range = bq27541_is_battery_temp_within_range, + .is_battery_id_valid = bq27541_is_battery_id_valid, + .get_batt_remaining_capacity + = bq27541_get_batt_remaining_capacity, + .get_batt_full_chg_capacity + = bq27541_get_batt_full_chg_capacity, + .get_batt_health = bq27541_get_batt_health, + .get_batt_bq_soc = bq27541_get_batt_bq_soc, +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161025 Add BQ27411 dash charging */ + .get_device_type = bq27541_get_device_type, +#endif + .get_battery_soc = bq27541_get_battery_soc, + .get_average_current = bq27541_get_average_current, + .set_allow_reading = bq27541_set_allow_reading, + .set_lcd_off_status = bq27541_set_lcd_off_status, + .fast_chg_started_status = bq27541_get_fastchg_started_status, + .wlchg_started_status = bq27541_set_wlchg_started_status, + .get_time_to_full = bq28z610_get_time_to_full, +}; + + +static int is_usb_pluged(void) +{ + static struct power_supply *psy; + union power_supply_propval ret = {0,}; + int usb_present, rc; /* david@bsp modified */ + + if (!psy) { + psy = power_supply_get_by_name("usb"); + if (!psy) { + pr_err("failed to get ps usb\n"); + return -EINVAL; + } + } + + /* david@bsp modified */ + rc = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, &ret); + if (rc) + return -EINVAL; + + if (ret.intval < 0) + return -EINVAL; + + usb_present = ret.intval; + return usb_present; +} + +static bool get_dash_started(void) +{ + if (bq27541_di && bq27541_di->fastchg_started) + return bq27541_di->fastchg_started; + else + return false; +} +#define TEMP_UPDATE_COUNT 5 +#define TEMP_UPDATE_THRESHOLD 450 + + +static int bq27541_temperature_thrshold_update(int temp) +{ + int ret; + + if (!bq27541_di->batt_psy) + return 0; + if (temp >= TEMP_UPDATE_THRESHOLD) { + bq27541_di->temp_thr_update_count++; + if (bq27541_di->temp_thr_update_count > TEMP_UPDATE_COUNT) { + bq27541_di->temp_thr_update_count = 0; + power_supply_changed(bq27541_di->batt_psy); + } + } else { + bq27541_di->temp_thr_update_count = 0; + } + + return ret; +} + +static void update_battery_soc_work(struct work_struct *work) +{ + int schedule_time, vbat, temp, switch_flag = 0; + static int pre_plugin_status = 0; + static bool pre_dash_started = 0; + + pr_info("plugin:%d,dash_start:%d:smooth:%d\n", + is_usb_pluged(), get_dash_started(),bq27541_di->set_smoothing); + switch_flag = REFRESH_TRUE; + if (pre_plugin_status != is_usb_pluged() + || pre_dash_started != get_dash_started()) + pr_info("usb_plugin:%d,dash_started:%d:set_smooth:%d\n", + is_usb_pluged(), get_dash_started(),bq27541_di->set_smoothing); + pre_plugin_status = is_usb_pluged(); + pre_dash_started = get_dash_started(); + if (is_usb_pluged() || get_dash_started()) { + schedule_delayed_work( + &bq27541_di->battery_soc_work, + msecs_to_jiffies(BATTERY_SOC_UPDATE_MS)); + if (get_dash_started()) + return; + if (bq27541_di->set_smoothing) + return; + if (!bq27541_di->allow_reading) + bq27541_set_allow_reading(true); + return; + } + bq27541_set_allow_reading(true); + bq28z610_get_time_to_full(); + vbat = bq27541_get_battery_mvolts()/1000; + bq27541_get_average_current(); + temp = bq27541_get_battery_temperature(); + bq27541_get_battery_soc(); + bq27541_get_batt_remaining_capacity(); + bq27541_get_batt_full_chg_capacity(); + bq27541_set_allow_reading(false); + bq27541_temperature_thrshold_update(temp); + if (!bq27541_di->already_modify_smooth) + schedule_delayed_work( + &bq27541_di->modify_soc_smooth_parameter, 1000); + if (bq27541_di->lcd_is_off) + schedule_time = 2 * RESUME_SCHDULE_SOC_UPDATE_WORK_MS; + else + schedule_time = + vbat < 3600 ? LOW_BAT_SOC_UPDATE_MS : BATTERY_SOC_UPDATE_MS; + schedule_delayed_work(&bq27541_di->battery_soc_work, + msecs_to_jiffies(schedule_time)); +} + +bool get_extern_fg_regist_done(void) +{ + return bq27541_registered; +} +bool get_extern_bq_present(void) +{ + if (bq27541_di) + return bq27541_di->bq_present; + return 0; +} + +#ifdef CONFIG_HOUSTON +void bq27541_force_update_current(bool enable) +{ + if (likely(bq27541_registered)) { + if (atomic_read(&bq27541_di->suspended) != 1) { + pr_info("bq27541_force_update_current\n"); + cancel_delayed_work_sync(&bq27541_di->battery_soc_work); + schedule_delayed_work(&bq27541_di->battery_soc_work, + msecs_to_jiffies(1)); + } + } +} +#endif + +#ifdef CONFIG_GAUGE_BQ27411 +/* david.liu@bsp, 20161004 Add BQ27411 support */ +static void gauge_set_cmd_addr(int device_type) +{ + if (device_type == DEVICE_BQ27541) { + bq27541_di->cmd_addr.reg_temp = BQ27541_REG_TEMP; + bq27541_di->cmd_addr.reg_volt = BQ27541_REG_VOLT; + bq27541_di->cmd_addr.reg_rm = BQ27541_REG_RM; + bq27541_di->cmd_addr.reg_ai = BQ27541_REG_AI; + bq27541_di->cmd_addr.reg_soc = BQ27541_REG_SOC; + bq27541_di->cmd_addr.reg_helth = BQ27541_REG_NIC; + bq27541_di->cmd_addr.reg_fcc = BQ27541_REG_FCC; + } else { /* device_bq27411 */ + bq27541_di->cmd_addr.reg_temp = BQ27411_REG_TEMP; + bq27541_di->cmd_addr.reg_volt = BQ27411_REG_VOLT; + bq27541_di->cmd_addr.reg_rm = BQ27411_REG_RM; + bq27541_di->cmd_addr.reg_ai = BQ27411_REG_AI; + bq27541_di->cmd_addr.reg_soc = BQ27411_REG_SOC; + bq27541_di->cmd_addr.reg_helth = BQ27411_REG_HEALTH; + bq27541_di->cmd_addr.reg_fcc = BQ27411_REG_FCC; + } +} +#endif + +static void bq_modify_soc_smooth_parameter(struct work_struct *work) +{ + struct bq27541_device_info *di; + + di = container_of(work, struct bq27541_device_info, + modify_soc_smooth_parameter.work); + if (get_dash_started()) + return; + if (di->already_modify_smooth) + return; + bq27541_set_allow_reading(false); + di->set_smoothing = true; + if (di->batt_bq28z610) + bq28z610_modify_soc_smooth_parameter(di); + else + bq27411_modify_soc_smooth_parameter(di, true); + di->set_smoothing = false; + bq27541_set_allow_reading(true); +} +static ssize_t battery_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t battery_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations battery_exist_operations = { + .read = battery_exist_read, + .write = battery_exist_write, +}; + +static void init_battery_exist_node(void) +{ + if (!proc_create("battery_exist", 0644, NULL, + &battery_exist_operations)){ + pr_err("%s : Failed to register proc interface\n", __func__); + } +} + + +static bool check_bat_present(struct bq27541_device_info *di) +{ + int flags = 0, ret = 0; + + ret = bq27541_read(BQ27541_SUBCMD_CHEM_ID, &flags, 0, di); + if (ret < 0) { + pr_err("read bq27541 fail\n"); + mdelay(100); + ret = bq27541_read(BQ27541_SUBCMD_CHEM_ID, &flags, 0, di); + if (ret < 0) { + pr_err("read bq27541 fail again\n"); + di->bq_present = false; + return false; + } + } + di->bq_present = true; + return true; +} + +static void bq27541_hw_config(struct work_struct *work) +{ + int ret = 0, flags = 0, type = 0, fw_ver = 0; + struct bq27541_device_info *di; + + di = container_of(work, struct bq27541_device_info, + hw_config.work); + ret = bq27541_chip_config(di); + if (ret) { + pr_err("Failed to config Bq27541\n"); + /* Add for retry when config fail */ + di->retry_count--; + if (di->retry_count > 0) + schedule_delayed_work(&di->hw_config, HZ); + else + bq27541_registered = true; + + return; + } + external_battery_gauge_register(&bq27541_batt_gauge); + bq27541_information_register(&bq27541_batt_gauge); +#ifdef CONFIG_ONEPLUS_WIRELESSCHG + exfg_information_register(&bq27541_batt_gauge); +#endif + bq27541_cntl_cmd(di, BQ27541_SUBCMD_CTNL_STATUS); + udelay(66); + bq27541_read(BQ27541_REG_CNTL, &flags, 0, di); + bq27541_cntl_cmd(di, BQ27541_SUBCMD_DEVCIE_TYPE); + udelay(66); + bq27541_read(BQ27541_REG_CNTL, &type, 0, di); + bq27541_cntl_cmd(di, BQ27541_SUBCMD_FW_VER); + udelay(66); + bq27541_read(BQ27541_REG_CNTL, &fw_ver, 0, di); + di->fw_ver = fw_ver; + +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + if (type == DEVICE_TYPE_BQ27411) { + di->device_type = DEVICE_BQ27411; + pr_info("DEVICE_BQ27411\n"); + } else { + di->device_type = DEVICE_BQ27541; + pr_info("DEVICE_BQ27541\n"); + } + gauge_set_cmd_addr(di->device_type); + if (type == DEVICE_TYPE_BQ28Z610) { + di->cmd_addr.reg_ai = Bq28Z610_REG_TI; + } + di->allow_reading = true; +#endif + + bq27541_registered = true; + pr_info("DEVICE_TYPE is 0x%02X, FIRMWARE_VERSION is 0x%02X\n", + type, fw_ver); + pr_info("Complete bq27541 configuration 0x%02X\n", flags); + schedule_delayed_work( + &di->modify_soc_smooth_parameter, + SET_BQ_PARAM_DELAY_MS); +} + +static int bq27541_read_i2c(u8 reg, int *rt_value, int b_single, + struct bq27541_device_info *di) +{ + struct i2c_client *client = di->client; + struct i2c_msg msg[2]; + unsigned char data[2]; + int err; + + if (!client->adapter) + return -ENODEV; + mutex_lock(&battery_mutex); + + /* Write register */ + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = data; + data[0] = reg; + /* Read data */ + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + if (!b_single) + msg[1].len = 2; + else + msg[1].len = 1; + msg[1].buf = data; + err = i2c_transfer(client->adapter, msg, 2); + if (err >= 0) { + if (!b_single) + *rt_value = get_unaligned_le16(data); + else + *rt_value = data[0]; + mutex_unlock(&battery_mutex); + return 0; + } + mutex_unlock(&battery_mutex); + return err; +} + +static int bq27541_read_i2c_block(u8 cmd, u8 length, u8 *returnData, + struct bq27541_device_info *di) +{ + if(!di->client) { + pr_err(" di->client NULL,return\n"); + return 0; + } + if(cmd == BQ27541_BQ27411_CMD_INVALID) + return 0; + mutex_lock(&battery_mutex); + i2c_smbus_read_i2c_block_data(di->client, cmd, length, returnData); + mutex_unlock(&battery_mutex); + //pr_err(" cmd = 0x%x, returnData = 0x%x\r\n",cmd,*returnData) ; + return 0; +} + +static int bq27541_write_i2c_block(u8 cmd, u8 length, u8 *writeData, + struct bq27541_device_info *di) +{ + if (!di->client) { + pr_err(" di->client NULL, return\n"); + return 0; + } + if (cmd == BQ27541_BQ27411_CMD_INVALID) { + return 0; + } + mutex_lock(&battery_mutex); + i2c_smbus_write_i2c_block_data(di->client, cmd, length, writeData); + mutex_unlock(&battery_mutex); + return 0; +} + + +#ifdef CONFIG_BQ27541_TEST_ENABLE +static int reg; +static int subcmd; +static ssize_t bq27541_read_stdcmd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + int temp = 0; + struct platform_device *client; + struct bq27541_device_info *di; + + client = to_platform_device(dev); + di = platform_get_drvdata(client); + + if (reg <= BQ27541_REG_ICR && reg > 0x00) { + ret = bq27541_read(reg, &temp, 0, di); + if (ret) + ret = snprintf(buf, PAGE_SIZE, "Read Error!\n"); + else + ret = snprintf(buf, PAGE_SIZE, "0x%02x\n", temp); + } else + ret = snprintf(buf, PAGE_SIZE, "Register Error!\n"); + + return ret; +} + +static ssize_t bq27541_write_stdcmd(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + int cmd; + int rc; + + rc = kstrtou32(buf, 0, &cmd); + if (rc != 1) + pr_err("%s,scanf error\n"); + reg = cmd; + return ret; +} + +static ssize_t bq27541_read_subcmd(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + int temp = 0; + struct platform_device *client; + struct bq27541_device_info *di; + + client = to_platform_device(dev); + di = platform_get_drvdata(client); + + if (subcmd == BQ27541_SUBCMD_DEVCIE_TYPE || + subcmd == BQ27541_SUBCMD_FW_VER || + subcmd == BQ27541_SUBCMD_HW_VER || + subcmd == BQ27541_SUBCMD_CHEM_ID) { + + bq27541_cntl_cmd(di, subcmd); /* Retrieve Chip status */ + udelay(66); + ret = bq27541_read(BQ27541_REG_CNTL, &temp, 0, di); + + if (ret) + ret = snprintf(buf, PAGE_SIZE, "Read Error!\n"); + else + ret = snprintf(buf, PAGE_SIZE, "0x%02x\n", temp); + } else + ret = snprintf(buf, PAGE_SIZE, "Register Error!\n"); + + return ret; +} + +static ssize_t bq27541_write_subcmd(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = strnlen(buf, PAGE_SIZE); + int cmd, rc; + + rc = kstrtou32(buf, 0, &cmd); + if (rc != 1) + pr_err("%s,scanf error\n"); + subcmd = cmd; + return ret; +} + +static DEVICE_ATTR(std_cmd, 0644, bq27541_read_stdcmd, + bq27541_write_stdcmd); +static DEVICE_ATTR(sub_cmd, 0644, bq27541_read_subcmd, + bq27541_write_subcmd); +static struct attribute *fs_attrs[] = { + &dev_attr_std_cmd.attr, + &dev_attr_sub_cmd.attr, + NULL, +}; +static struct attribute_group fs_attr_group = { + .attrs = fs_attrs, +}; + +static struct platform_device this_device = { + .name = "bq27541-test", + .id = -1, + .dev.platform_data = NULL, +}; +#endif + +static void update_pre_capacity_func(struct work_struct *w) +{ + pr_info("enter\n"); + bq27541_set_allow_reading(true); + bq27541_get_battery_temperature(); + bq27541_battery_soc(bq27541_di, update_pre_capacity_data.suspend_time); + bq27541_get_batt_remaining_capacity(); + bq27541_get_batt_full_chg_capacity(); + bq27541_set_allow_reading(false); + __pm_relax(bq27541_di->update_soc_wake_lock); + pr_info("exit\n"); +} + +#define MAX_RETRY_COUNT 5 +#define DEFAULT_INVALID_SOC_PRE -22 + +static void bq27541_parse_dt(struct bq27541_device_info *di) +{ + struct device_node *node = di->dev->of_node; + + di->modify_soc_smooth = of_property_read_bool(node, + "qcom,modify-soc-smooth"); + pr_info("di->modify_soc_smooth=%d\n", di->modify_soc_smooth); + di->bat_4p45v = of_property_read_bool(node, + "op,bat-4p45v"); + di->check_match = of_property_read_bool(node, + "op,check-match"); + pr_info("BQ 4p45V=%d, check-match=%d\n", di->bat_4p45v, di->check_match); +#ifdef CONFIG_GAUGE_BQ27411 + di->batt_bq28z610 = of_property_read_bool(node, "op,batt_bq28z610"); + di->bq28z610_need_balancing = of_property_read_bool(node, + "op,bq28z610_need_balancing"); +#endif +} +static int sealed(void) +{ + /*return control_cmd_read(di, CONTROL_STATUS) & (1 << 13);*/ + int value = 0; + + bq27541_cntl_cmd(bq27541_di, CONTROL_STATUS); + /*bq27541_cntl_cmd(di,CONTROL_STATUS);*/ + usleep_range(10000, 10001); + bq27541_read_i2c(CONTROL_STATUS, &value, 0, bq27541_di); + + pr_debug(" REG_CNTL: 0x%x\n", value); + + if (bq27541_di->device_type == DEVICE_BQ27541) + return value & BIT(14); + else if (bq27541_di->device_type == DEVICE_BQ27411) + return value & BIT(13); + else + return 1; +} + +static int seal(void) +{ + int i = 0; + + if (sealed()) { + pr_err("bq27541/27411 sealed,return\n"); + return 1; + } + bq27541_cntl_cmd(bq27541_di, SEAL_SUBCMD); + usleep_range(10000, 10001); + for (i = 0; i < SEAL_POLLING_RETRY_LIMIT; i++) { + if (sealed()) + return 1; + usleep_range(10000, 10001); + } + return 0; +} + + +static int unseal(u32 key) +{ + int i = 0; + + if (!sealed()) + goto out; + +re_unseal: + if (bq27541_di->device_type == DEVICE_BQ27411) { + usleep_range(10000, 10001); + /*bq27541_write(CONTROL_CMD, key & 0xFFFF, false, di);*/ + bq27541_cntl_cmd(bq27541_di, 0x8000); + usleep_range(10000, 10001); + bq27541_cntl_cmd(bq27541_di, 0x8000); + usleep_range(10000, 10001); + } + bq27541_cntl_cmd(bq27541_di, 0xffff); + usleep_range(10000, 10001); + bq27541_cntl_cmd(bq27541_di, 0xffff); + usleep_range(10000, 10001); + + while (i < SEAL_POLLING_RETRY_LIMIT) { + i++; + if (!sealed()) + break; + usleep_range(10000, 10001); + goto re_unseal; + } + +out: + pr_info("bq27541 : i=%d,bq27541_di->device_type=%d\n", + i, bq27541_di->device_type); + + if (i == SEAL_POLLING_RETRY_LIMIT) { + pr_err("bq27541 failed\n"); + return 0; + } else { + return 1; + } +} + +static int bq27541_read_i2c_onebyte(u8 cmd, u8 *returnData) +{ + if (!new_client) { + pr_err(" new_client NULL,return\n"); + return 0; + } + if (cmd == BQ27541_BQ27411_CMD_INVALID) + return 0; + + mutex_lock(&battery_mutex); + *returnData = i2c_smbus_read_byte_data(new_client, cmd); + + mutex_unlock(&battery_mutex); + /*pr_err(" cmd = 0x%x, returnData = 0x%x\r\n",cmd,*returnData) ;*/ + if (*returnData < 0) + return 1; + else + return 0; +} + +static int bq27541_i2c_txsubcmd_onebyte(u8 cmd, u8 writeData) +{ + if (!new_client) { + pr_err(" new_client NULL,return\n"); + return 0; + } + if (cmd == BQ27541_BQ27411_CMD_INVALID) + return 0; + + mutex_lock(&battery_mutex); + i2c_smbus_write_byte_data(new_client, cmd, writeData); + mutex_unlock(&battery_mutex); + return 0; +} + + +static int bq27411_write_block_data_cmd(struct bq27541_device_info *di, + int block_id, u8 reg_addr, u8 new_value) +{ + int rc = 0; + u8 old_value = 0, old_csum = 0, new_csum = 0; + /*u8 new_csum_test = 0, csum_temp = 0;*/ + + usleep_range(1000, 1001); + bq27541_i2c_txsubcmd(BQ27411_DATA_CLASS_ACCESS, block_id, di); + usleep_range(10000, 10001); + rc = bq27541_read_i2c_onebyte(reg_addr, &old_value); + if (rc) { + pr_err("%s read reg_addr = 0x%x fail\n", __func__, reg_addr); + return 1; + } + if (old_value == new_value) + return 0; + usleep_range(1000, 1001); + rc = bq27541_read_i2c_onebyte(BQ27411_CHECKSUM_ADDR, &old_csum); + if (rc) { + pr_err("%s read checksum fail\n", __func__); + return 1; + } + usleep_range(1000, 1001); + bq27541_i2c_txsubcmd_onebyte(reg_addr, new_value); + usleep_range(1000, 1001); + new_csum = (old_value + old_csum - new_value) & 0xff; + usleep_range(1000, 1001); + bq27541_i2c_txsubcmd_onebyte(BQ27411_CHECKSUM_ADDR, new_csum); + pr_err("bq27411 write blk_id = 0x%x, addr = 0x%x, old_val = 0x%x, new_val = 0x%x, old_csum = 0x%x, new_csum = 0x%x\n", + block_id, reg_addr, old_value, new_value, old_csum, new_csum); + return 0; +} + +static int bq27411_read_block_data_cmd(struct bq27541_device_info *di, + int block_id, u8 reg_addr) +{ + u8 value = 0; + + usleep_range(1000, 1001); + bq27541_i2c_txsubcmd(BQ27411_DATA_CLASS_ACCESS, block_id, di); + usleep_range(10000, 10001); + bq27541_read_i2c_onebyte(reg_addr, &value); + return value; +} + +static int bq27411_enable_config_mode( + struct bq27541_device_info *di, bool enable) +{ + int config_mode = 0, i = 0, rc = 0; + + if (enable) { /*enter config mode*/ + usleep_range(1000, 1001); + bq27541_cntl_cmd(bq27541_di, BQ27411_SUBCMD_SET_CFG); + usleep_range(1000, 1001); + for (i = 0; i < BQ27411_CONFIG_MODE_POLLING_LIMIT; i++) { + i++; + rc = bq27541_read_i2c(BQ27411_SUBCMD_CONFIG_MODE, + &config_mode, 0, di); + if (rc < 0) { + pr_err("%s i2c read error\n", __func__); + return 1; + } + if (config_mode & BIT(4)) + break; + msleep(50); + } + } else { /* exit config mode*/ + usleep_range(1000, 1001); + bq27541_cntl_cmd(bq27541_di, BQ27411_SUBCMD_EXIT_CFG); + usleep_range(1000, 1001); + for (i = 0; i < BQ27411_CONFIG_MODE_POLLING_LIMIT; i++) { + i++; + rc = bq27541_read_i2c(BQ27411_SUBCMD_CONFIG_MODE, + &config_mode, 0, di); + if (rc < 0) { + pr_err("%s i2c read error\n", __func__); + return 1; + } + if ((config_mode & BIT(4)) == 0) + break; + msleep(50); + } + } + if (i == BQ27411_CONFIG_MODE_POLLING_LIMIT) { + pr_err("%s fail config_mode = 0x%x, enable = %d\n", + __func__, config_mode, enable); + return 1; + } + pr_err("%s success i = %d, config_mode = 0x%x, enable = %d\n", + __func__, i, config_mode, enable); + return 0; +} + +static bool bq27411_check_soc_smooth_parameter( + struct bq27541_device_info *di, bool is_powerup) +{ + int value_read = 0; + u8 dead_band_val = 0, op_cfgb_val = 0, dodat_val = 0, rc = 0; + + return true; /*not check because it costs 5.5 seconds*/ + + msleep(4000); + if (sealed()) { + if (!unseal(BQ27411_UNSEAL_KEY)) + return false; + msleep(50); + } + + if (is_powerup) { + dead_band_val = BQ27411_CC_DEAD_BAND_POWERUP_VALUE; + op_cfgb_val = BQ27411_OPCONFIGB_POWERUP_VALUE; + dodat_val = BQ27411_DODATEOC_POWERUP_VALUE; + } else { /*shutdown*/ + dead_band_val = BQ27411_CC_DEAD_BAND_SHUTDOWN_VALUE; + op_cfgb_val = BQ27411_OPCONFIGB_SHUTDOWN_VALUE; + dodat_val = BQ27411_DODATEOC_SHUTDOWN_VALUE; + } + rc = bq27411_enable_config_mode(di, true); + if (rc) { + pr_err("%s enable config mode fail\n", __func__); + return false; + } + /*enable block data control*/ + rc = bq27541_i2c_txsubcmd_onebyte(BQ27411_BLOCK_DATA_CONTROL, 0x00); + if (rc) { + pr_err("%s enable block data control fail\n", __func__); + goto check_error; + } + usleep_range(5000, 5001); + + /*check cc-dead-band*/ + value_read = bq27411_read_block_data_cmd(di, + BQ27411_CC_DEAD_BAND_ID, BQ27411_CC_DEAD_BAND_ADDR); + if (value_read != dead_band_val) { + pr_err("%s cc_dead_band error, value_read = 0x%x\n", + __func__, value_read); + goto check_error; + } + + /*check opconfigB*/ + value_read = bq27411_read_block_data_cmd(di, + BQ27411_OPCONFIGB_ID, + BQ27411_OPCONFIGB_ADDR); + if (value_read != op_cfgb_val) { + pr_err("%s opconfigb error, value_read = 0x%x\n", + __func__, value_read); + goto check_error; + } + + /*check dodateoc*/ + value_read = bq27411_read_block_data_cmd(di, + BQ27411_DODATEOC_ID, BQ27411_DODATEOC_ADDR); + if (value_read != dodat_val) { + pr_err("%s dodateoc error, value_read = 0x%x\n", + __func__, value_read); + goto check_error; + } + bq27411_enable_config_mode(di, false); + return true; + +check_error: + bq27411_enable_config_mode(di, false); + return false; +} + +static int bq27411_write_soc_smooth_parameter( + struct bq27541_device_info *di, bool is_powerup) +{ + int rc = 0; + u8 dead_band_val = 0, op_cfgb_val = 0, dodat_val = 0; + + if (is_powerup) { + dead_band_val = BQ27411_CC_DEAD_BAND_POWERUP_VALUE; + op_cfgb_val = BQ27411_OPCONFIGB_POWERUP_VALUE; + dodat_val = BQ27411_DODATEOC_POWERUP_VALUE; + } else { /*shutdown*/ + dead_band_val = BQ27411_CC_DEAD_BAND_SHUTDOWN_VALUE; + op_cfgb_val = BQ27411_OPCONFIGB_SHUTDOWN_VALUE; + dodat_val = BQ27411_DODATEOC_SHUTDOWN_VALUE; + } + + /*enter config mode*/ + rc = bq27411_enable_config_mode(di, true); + if (rc) { + pr_err("%s enable config mode fail\n", __func__); + return 1; + } + /*enable block data control*/ + bq27541_i2c_txsubcmd_onebyte(BQ27411_BLOCK_DATA_CONTROL, 0x00); + + usleep_range(5000, 5001); + /*step1: update cc-dead-band*/ + rc = bq27411_write_block_data_cmd(di, BQ27411_CC_DEAD_BAND_ID, + BQ27411_CC_DEAD_BAND_ADDR, dead_band_val); + if (rc) { + pr_err("%s cc_dead_band fail\n", __func__); + goto exit_config_mode; + } + /*step2: update opconfigB*/ + rc = bq27411_write_block_data_cmd(di, BQ27411_OPCONFIGB_ID, + BQ27411_OPCONFIGB_ADDR, op_cfgb_val); + if (rc) { + pr_err("%s opconfigB fail\n", __func__); + goto exit_config_mode; + } + /*step3: update dodateoc*/ + rc = bq27411_write_block_data_cmd(di, BQ27411_DODATEOC_ID, + BQ27411_DODATEOC_ADDR, dodat_val); + if (rc) { + pr_err("%s dodateoc fail\n", __func__); + goto exit_config_mode; + } + bq27411_enable_config_mode(di, false); + return 0; + +exit_config_mode: + bq27411_enable_config_mode(di, false); + return 1; +} + +static void bq27411_modify_soc_smooth_parameter( + struct bq27541_device_info *di, bool is_powerup) +{ + int rc = 0; + bool check_result = false, tried_again = false; + + if (di->modify_soc_smooth == false + || di->device_type == DEVICE_BQ27541) { + return; + } + + pr_info("%s begin\n", __func__); + if (sealed()) { + if (!unseal(BQ27411_UNSEAL_KEY)) + return; + msleep(50); + } +write_parameter: + rc = bq27411_write_soc_smooth_parameter(di, is_powerup); + if (rc && tried_again == false) { + tried_again = true; + goto write_parameter; + } else { + check_result = + bq27411_check_soc_smooth_parameter(di, is_powerup); + if (check_result == false && tried_again == false) { + tried_again = true; + goto write_parameter; + } + } + + usleep_range(1000, 1001); + if (sealed() == 0) { + usleep_range(1000, 1001); + seal(); + } + di->already_modify_smooth = true; + pr_info("%s end\n", __func__); +} + +static int bq8z610_sealed(void) +{ + int value = 0; + u8 CNTL1_VAL[BQ28Z610_REG_CNTL1_SIZE] = {0,0,0,0}; + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, BQ28Z610_SEAL_STATUS, bq27541_di); + usleep_range(10000, 10000); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, CNTL1_VAL, bq27541_di); + pr_err("%s bq8z610_sealed CNTL1_VAL[0] = %x,CNTL1_VAL[1] = %x,\ + CNTL1_VAL[2] = %x,CNTL1_VAL[3] = %x,\n", + __func__,CNTL1_VAL[0],CNTL1_VAL[1],CNTL1_VAL[2],CNTL1_VAL[3]); + value = (CNTL1_VAL[3] & BQ28Z610_SEAL_BIT); + if(value == BQ28Z610_SEAL_VALUE) { + pr_err("bq8z610 sealed, value = %x return 1\n",value); + return 1; + } else { + pr_err("bq8z610 sealed, value = %x return 0\n",value); + return 0; + } +} + +static int bq8z610_seal(void) +{ + int i = 0; + + if (bq8z610_sealed()) { + pr_err("bq8z610 sealed, return\n"); + return 1; + } + bq27541_i2c_txsubcmd(0, BQ28Z610_SEAL_SUBCMD, bq27541_di); + //usleep_range(10000, 10000); + msleep(1000); + for (i = 0;i < BQ28Z610_SEAL_POLLING_RETRY_LIMIT;i++) { + if (bq8z610_sealed()) { + return 1; + } + //bq27541_i2c_txsubcmd(0, BQ28Z610_SEAL_SUBCMD, bq27541_di); + usleep_range(10000, 10000); + } + return 0; +} + +static int bq8z610_unseal(void) +{ + int i = 0; + + if (!bq8z610_sealed()) { + goto out; + } + bq27541_i2c_txsubcmd(0, BQ28Z610_UNSEAL_SUBCMD1, bq27541_di); + usleep_range(10000, 10000); + //msleep(100); + bq27541_i2c_txsubcmd(0, BQ28Z610_UNSEAL_SUBCMD2, bq27541_di); + //usleep_range(10000, 10000); + msleep(1000); + while (i < BQ28Z610_SEAL_POLLING_RETRY_LIMIT) { + i++; + if (!bq8z610_sealed()) { + break; + } + usleep_range(10000, 10000); + } + +out: + pr_info("bq8z610 : i=%d\n", i); + if (i == SEAL_POLLING_RETRY_LIMIT) { + pr_err("bq8z610 unseal failed\n"); + return 0; + } else { + return 1; + } +} + +static int bq28z610_write_flash_busy_wait_i2c_err(struct bq27541_device_info *di) +{ + //int rc = 0; + u8 I2C_VAL[BQ28Z610_REG_I2C_SIZE] = {0,0,0}; + u8 I2C_write1[BQ28Z610_REG_I2C_SIZE] = {0x03,0x46,0xA0}; + + bq27541_write_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_I2C_SIZE, &I2C_write1[0], di); + msleep(100); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL2, 0x0516, di); + msleep(100); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x4603, di);//physical address is 0x4603 + msleep(100); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_I2C_SIZE, I2C_VAL, di); + pr_err("%s I2C Configuration I2C_VAL[0] = %x,I2C_VAL[1] = %x,I2C_VAL[2] = %x\n", + __func__,I2C_VAL[0],I2C_VAL[1],I2C_VAL[2]); + if(((I2C_VAL[2] << 16) |(I2C_VAL[1] << 8) | I2C_VAL[0]) != 0xA04603) { + pr_err("%s To change I2C Configuration 0x20 -> 0xA0. ERR.\n", __func__); + return -1; + } else { + pr_err("%s To change I2C Configuration 0x20 -> 0xA0. OK\n", __func__); + } + return 0; +} + +#if 0 //not use now, build error. +int bq28z610_write_soc_smooth_parameter(struct bq27541_device_info *di) +{ + //int rc = 0; + u8 CNTL1_VAL[BQ28Z610_REG_CNTL1_SIZE] = {0,0,0,0}; + u8 CNTL1_write1[BQ28Z610_REG_CNTL1_SIZE] = {0xF4,0x46,0xdC,0x00}; + //u8 CNTL1_write2[BQ28Z610_REG_CNTL1_SIZE] = {0x08,0x47,0x78,0x00};//120ma + u8 CNTL1_write2[BQ28Z610_REG_CNTL1_SIZE] = {0x08,0x47,0x96,0x00};//150ma + u8 CNTL1_write3[BQ28Z610_REG_CNTL1_SIZE] = {0x0C,0x47,0x28,0x00}; + bq27541_write_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, &CNTL1_write1[0], di); + msleep(100); + //bq8z610_cntl2_cmd(0x06E9); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL2, 0x06E9, di); + //usleep_range(10000, 5000); + msleep(100); + //bq8z610_cntl1_cmd(0x46F4); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x46F4, di); + //usleep_range(5000, 5000); + msleep(100); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, CNTL1_VAL, di); + pr_err("%s Charge Term Taper Current CNTL1_VAL[0] = %x,\ + CNTL1_VAL[1] = %x,CNTL1_VAL[2] = %x,CNTL1_VAL[3] = %x,\n", + __func__,CNTL1_VAL[0],CNTL1_VAL[1],CNTL1_VAL[2],CNTL1_VAL[3]); + if((((CNTL1_VAL[1] << 8) | CNTL1_VAL[0]) != 0x46F4) + || (((CNTL1_VAL[3] << 8) | CNTL1_VAL[2]) != 0x00DC)) { + pr_err("%s Charge Term Taper Current 150mA (=0x0096) -> 220mA (=0x00DC). ERR.\n", __func__); + return -1; + } else { + pr_err("%s Charge Term Taper Current (=0x0096) -> 220mA (=0x00DC). OK\n", __func__); + } + bq27541_write_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, &CNTL1_write2[0], di); + msleep(100); + //bq8z610_cntl2_cmd(0x06E9); + //bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL2, 0x0638, di);//120ma + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL2, 0x061A, di);//150ma + //usleep_range(5000, 5000); + msleep(100); + //bq8z610_cntl1_cmd(0x46F4); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x4708, di); + //usleep_range(5000, 5000); + msleep(100); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, CNTL1_VAL, di); + pr_err("%s Dsg Current Threshold CNTL1_VAL[0] = %x,\ + CNTL1_VAL[1] = %x,CNTL1_VAL[2] = %x,CNTL1_VAL[3] = %x,\n", + __func__,CNTL1_VAL[0],CNTL1_VAL[1],CNTL1_VAL[2],CNTL1_VAL[3]); + //if((((CNTL1_VAL[1] << 8) | CNTL1_VAL[0]) != 0x4708) || (((CNTL1_VAL[3] << 8) | CNTL1_VAL[2]) != 0x0078))//120ma + if((((CNTL1_VAL[1] << 8) | CNTL1_VAL[0]) != 0x4708) + || (((CNTL1_VAL[3] << 8) | CNTL1_VAL[2]) != 0x0096)) { + pr_err("%s Dsg Current Threshold 40mA (0x0028) -> 150mA (0x0078) ERR.\n", __func__); + return -1; + } else { + pr_err("%s Dsg Current Threshold 40mA (0x0028) -> 150mA (0x0078) OK\n", __func__); + } + bq27541_write_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, &CNTL1_write3[0], di); + msleep(100); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL2, 0x0684, di); + msleep(100); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x470C, di); + msleep(100); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, CNTL1_VAL, di); + pr_err("%s Quit Current CNTL1_VAL[0] = %x,\ + CNTL1_VAL[1] = %x,CNTL1_VAL[2] = %x,CNTL1_VAL[3] = %x,\n", + __func__,CNTL1_VAL[0],CNTL1_VAL[1],CNTL1_VAL[2],CNTL1_VAL[3]); + if((((CNTL1_VAL[1] << 8) | CNTL1_VAL[0]) != 0x470C) + || (((CNTL1_VAL[3] << 8) | CNTL1_VAL[2]) != 0x0028)) { + pr_err("%s Quit Current 20mA (0x0014) -> 40mA (0x0028). ERR.\n", __func__); + return -1; + } else { + pr_err("%s Quit Current 20mA (0x0014) -> 40mA (0x0028). OK\n", __func__); + } + return 0; +} +#endif + +static int bq28z610_write_iterm_Taper_parameter(struct bq27541_device_info *di) { + u8 CNTL1_VAL[BQ28Z610_REG_CNTL1_SIZE] = {0,0,0,0}; + u8 CNTL1_write1[BQ28Z610_REG_CNTL1_SIZE] = {0xF4,0x46,0x96,0x00}; + bq27541_write_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, &CNTL1_write1[0], di); + msleep(100); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL2, 0x062F, di); + msleep(100); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x46F4, di); + msleep(100); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, CNTL1_VAL, di); + pr_err("%s Charge Term Taper Current CNTL1_VAL[0] = %x,\ + CNTL1_VAL[1] = %x,CNTL1_VAL[2] = %x,CNTL1_VAL[3] = %x,\n", + __func__,CNTL1_VAL[0],CNTL1_VAL[1],CNTL1_VAL[2],CNTL1_VAL[3]); + if((((CNTL1_VAL[1] << 8) | CNTL1_VAL[0]) != 0x46F4) + || (((CNTL1_VAL[3] << 8) | CNTL1_VAL[2]) != 0x0096)) { + pr_err("%s Charge Term Taper Current 220mA (=0x00DC) -> 150mA (=0x0096). ERR.\n", __func__); + return -1; + } else { + pr_err("%s Charge Term Taper Current 220mA (=0x00DC) -> 150mA (=0x0096). OK\n", __func__); + } + return 0; +} + +static void bq28z610_modify_soc_smooth_parameter(struct bq27541_device_info *di) +{ + int rc = 0; + bool tried_again = false; + + if (di->modify_soc_smooth == false + || di->device_type != DEVICE_BQ28Z610) { + return; + } + + pr_err("%s begin\n", __func__); + if (bq8z610_sealed()) { + if (!bq8z610_unseal()) { + return; + } else { + msleep(50); + } + } + +write_parameter: + //rc = bq28z610_write_soc_smooth_parameter(chip); + rc = bq28z610_write_iterm_Taper_parameter(di); + rc = bq28z610_write_flash_busy_wait_i2c_err(di); + if (rc && tried_again == false) { + tried_again = true; + goto write_parameter; + } + usleep_range(1000, 1000); + if (bq8z610_sealed() == 0) { + usleep_range(1000, 1000); + bq8z610_seal(); + } + di->already_modify_smooth = true; + pr_err("%s end\n", __func__); +} + +#if 0 // not use now, build error. +static int bq8z610_check_gauge_enable(void) +{ + /* return control_cmd_read(di, CONTROL_STATUS) & (1 << 13);*/ + int value = 0; + u8 CNTL1_VAL[BQ28Z610_REG_CNTL1_SIZE] = {0,0,0,0}; + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, BQ28Z610_REG_GAUGE_EN, bq27541_di); + //usleep_range(10000, 10000); + msleep(1000); + bq27541_read_i2c_block(BQ28Z610_REG_CNTL1, BQ28Z610_REG_CNTL1_SIZE, CNTL1_VAL, bq27541_di); + pr_err("%s CNTL1_VAL[0] = %x,CNTL1_VAL[1] = %x,\ + CNTL1_VAL[2] = %x,CNTL1_VAL[3] = %x,\n", + __func__,CNTL1_VAL[0],CNTL1_VAL[1],CNTL1_VAL[2],CNTL1_VAL[3]); + value = (CNTL1_VAL[2] & BQ28Z610_GAUGE_EN_BIT); + if(value == BQ28Z610_GAUGE_EN_BIT) { + pr_err("bq8z610 gauge_enable, value = %x return 1\n",value); + return 1; + } else { + pr_err("bq8z610 gauge_enable, value = %x return 0\n",value); + return 0; + } +} + +static int bq28z610_write_dod0_parameter(struct bq27541_device_info *di) +{ + //bq8z610_cntl1_cmd(0x46F4); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x0021, di); + //usleep_range(5000, 5000); + msleep(1000); + //bq8z610_cntl1_cmd(0x00DC); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x0021, di); + //usleep_range(5000, 5000); + msleep(2000); + if(bq8z610_check_gauge_enable() == false) { + //bq8z610_cntl1_cmd(0x00DC); + bq27541_i2c_txsubcmd(BQ28Z610_REG_CNTL1, 0x0021, di); + //usleep_range(5000, 5000); + msleep(300); + } + return 0; +} + +static void bq28z610_modify_dod0_parameter(struct bq27541_device_info *di) +{ + int rc = 0; + + pr_err("%s begin\n", __func__); + if (bq8z610_sealed()) { + if (!bq8z610_unseal()) { + return; + } else { + msleep(50); + } + } + rc = bq28z610_write_dod0_parameter(di); + usleep_range(1000, 1000); + if (bq8z610_sealed() == 0) { + usleep_range(1000, 1000); + bq8z610_seal(); + } + pr_err("%s end\n", __func__); +} +#endif + +static int bq28z610_get_2cell_voltage(void) +{ + u8 cell_vol[BQ28Z610_MAC_CELL_VOLTAGE_SIZE] = {0, 0, 0, 0}; + struct bq27541_device_info *di = bq27541_di; + + if (!di) { + return 0; + } + + mutex_lock(&bq28z610_alt_manufacturer_access); + bq27541_i2c_txsubcmd(BQ28Z610_MAC_CELL_VOLTAGE_EN_ADDR, + BQ28Z610_MAC_CELL_VOLTAGE_CMD, di); + usleep_range(1000, 1000); + bq27541_read_i2c_block(BQ28Z610_MAC_CELL_VOLTAGE_ADDR, + BQ28Z610_MAC_CELL_VOLTAGE_SIZE, cell_vol, di); + mutex_unlock(&bq28z610_alt_manufacturer_access); + di->batt_cell_1_vol = (cell_vol[1] << 8) | cell_vol[0]; + di->batt_cell_2_vol = (cell_vol[3] << 8) | cell_vol[2]; + if (di->batt_cell_1_vol < di->batt_cell_2_vol) { + di->batt_cell_max_vol = di->batt_cell_2_vol; + di->batt_cell_min_vol = di->batt_cell_1_vol; + } else { + di->batt_cell_max_vol = di->batt_cell_1_vol; + di->batt_cell_min_vol = di->batt_cell_2_vol; + } + /*chg_err("batt_cell_1_vol = %dmV, batt_cell_2_vol = %dmV, batt_cell_max_vol = %dmV\n", + di->batt_cell_1_vol, + di->batt_cell_2_vol, + di->batt_cell_max_vol);*/ + + return 0; +} + +static int bq27541_get_battery_mvolts_2cell_max(void) +{ + if(!bq27541_di) { + return 0; + } + return bq27541_di->batt_cell_max_vol; +} + +static int bq27541_get_battery_mvolts_2cell_min(void) +{ + if(!bq27541_di) { + return 0; + } + return bq27541_di->batt_cell_min_vol; +} + +static int bq28z610_get_time_to_full(void) +{ + int ret = -1; + int time_to_full = 0; + + if(!bq27541_di) + return -ENODEV; + + if (atomic_read(&bq27541_di->suspended) == 1) + return bq27541_di->time_to_full; + + if (!bq27541_di->batt_bq28z610) + return -ENODATA; + + if (bq27541_di->allow_reading) { + ret = bq27541_read(BQ28Z610_REG_TIME_TO_FULL, &time_to_full, 0, bq27541_di); + if (ret < 0) { + pr_err("error reading time to full,ret:%d\n", ret); + return ret; + } + if (time_to_full == 65535) { + if (bq27541_di->time_to_full == 0) + return -ENODATA; + return bq27541_di->time_to_full; + } + bq27541_di->time_to_full = time_to_full * 60; + return time_to_full * 60; + } + + return bq27541_di->time_to_full; +} + +static int bq27541_battery_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + char *name; + struct bq27541_device_info *di; + struct bq27541_access_methods *bus; + int num; + int retval = 0; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + update_pre_capacity_data.workqueue = + create_workqueue("update_pre_capacity"); + INIT_DELAYED_WORK(&(update_pre_capacity_data.work), + update_pre_capacity_func); + + mutex_lock(&battery_mutex); + num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL); + mutex_unlock(&battery_mutex); + if (retval < 0) + return retval; + + name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num); + if (!name) { + pr_err("failed to allocate device name\n"); + retval = -ENOMEM; + goto batt_failed_1; + } + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) { + retval = -ENOMEM; + goto batt_failed_2; + } + di->id = num; + + bus = kzalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) { + retval = -ENOMEM; + goto batt_failed_3; + } + + i2c_set_clientdata(client, di); + di->dev = &client->dev; + bus->read = &bq27541_read_i2c; + di->bus = bus; + di->client = client; + + new_client = client; + + di->update_soc_wake_lock = wakeup_source_register(&client->dev, "bq_delt_soc_wake_lock"); + di->soc_pre = DEFAULT_INVALID_SOC_PRE; + di->temp_pre = 0; +#ifndef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + di->allow_reading = true; +#endif + /* Add for retry when config fail */ + di->retry_count = MAX_RETRY_COUNT; + atomic_set(&di->suspended, 0); + +#ifdef CONFIG_BQ27541_TEST_ENABLE + platform_set_drvdata(&this_device, di); + retval = platform_device_register(&this_device); + if (!retval) { + retval = sysfs_create_group(&this_device.dev.kobj, + &fs_attr_group); + if (retval) + goto batt_failed_4; + } else + goto batt_failed_4; +#endif + + if (retval) { + pr_err("failed to setup bq27541\n"); + goto batt_failed_4; + } + + if (retval) { + pr_err("failed to powerup bq27541\n"); + goto batt_failed_4; + } + bq27541_di = di; + bq27541_parse_dt(di); + di->t_count = 0; + di->lcd_is_off = false; + INIT_DELAYED_WORK(&di->hw_config, bq27541_hw_config); + INIT_DELAYED_WORK(&di->modify_soc_smooth_parameter, + bq_modify_soc_smooth_parameter); + INIT_DELAYED_WORK(&di->battery_soc_work, update_battery_soc_work); + schedule_delayed_work(&di->hw_config, BQ27541_INIT_DELAY); + schedule_delayed_work(&di->battery_soc_work, BATTERY_SOC_UPDATE_MS); + retval = check_bat_present(di); + if( retval ) { + init_battery_exist_node(); + pr_info("probe success battery exist \n"); + } + else { + pr_info("probe success battery not exist \n"); + } + return 0; + +batt_failed_4: + kfree(bus); +batt_failed_3: + kfree(di); +batt_failed_2: + kfree(name); +batt_failed_1: + mutex_lock(&battery_mutex); + idr_remove(&battery_id, num); + mutex_unlock(&battery_mutex); + + return retval; +} + +static int bq27541_battery_remove(struct i2c_client *client) +{ + struct bq27541_device_info *di = i2c_get_clientdata(client); + + external_battery_gauge_unregister(&bq27541_batt_gauge); + bq27541_information_unregister(&bq27541_batt_gauge); + bq27541_cntl_cmd(di, BQ27541_SUBCMD_DISABLE_DLOG); + udelay(66); + bq27541_cntl_cmd(di, BQ27541_SUBCMD_DISABLE_IT); + cancel_delayed_work_sync(&di->hw_config); + cancel_delayed_work_sync(&di->modify_soc_smooth_parameter); + kfree(di->bus); + + mutex_lock(&battery_mutex); + idr_remove(&battery_id, di->id); + mutex_unlock(&battery_mutex); + + kfree(di); + return 0; +} + + +static int bq27541_battery_suspend(struct device *dev) +{ + int ret = 0; + struct bq27541_device_info *di = dev_get_drvdata(dev); + + pr_info("bq27541_battery_suspend\n"); + //cancel_delayed_work_sync(&di->battery_soc_work); + atomic_set(&di->suspended, 1); + ret = get_current_time(&di->rtc_suspend_time); + if (ret) { + pr_err("Failed to read RTC time\n"); + return 0; + } + return 0; +} + + +/*1 minute*/ + +#define RESUME_TIME 60 +static int bq27541_battery_resume(struct device *dev) +{ + int ret = 0; + int suspend_time; + struct bq27541_device_info *di = dev_get_drvdata(dev); + + atomic_set(&di->suspended, 0); + ret = get_current_time(&di->rtc_resume_time); + if (ret) { + pr_err("Failed to read RTC time\n"); + return 0; + } + suspend_time = di->rtc_resume_time - di->rtc_suspend_time; + pr_info("suspend_time=%d\n", suspend_time); + update_pre_capacity_data.suspend_time = suspend_time; + if (di->soc_pre < LOW_BATTERY_LEVEL_THRESHOLD) + di->short_time_standby_count += SHORT_TIME_STANDBY_SOC_CHECK_COUNT; + if ((di->rtc_resume_time - di->lcd_off_time >= TWO_POINT_FIVE_MINUTES) + || di->short_time_standby_count >= SHORT_TIME_STANDBY_SOC_CHECK_COUNT) { + pr_err("di->rtc_resume_time - di->lcd_off_time=%ld\n", + di->rtc_resume_time - di->lcd_off_time); + __pm_stay_awake(di->update_soc_wake_lock); + get_current_time(&di->lcd_off_time); + queue_delayed_work_on(0, + update_pre_capacity_data.workqueue, + &(update_pre_capacity_data.work), + msecs_to_jiffies(1000)); + di->short_time_standby_count = 0; + } else { + di->short_time_standby_count++; + } + schedule_delayed_work(&bq27541_di->battery_soc_work, + msecs_to_jiffies(RESUME_SCHDULE_SOC_UPDATE_WORK_MS)); + return 0; +} + + +static void bq27541_shutdown(struct i2c_client *client) +{ + struct bq27541_device_info *di = i2c_get_clientdata(client); + + if (bq27541_di) { + if (di->already_modify_smooth) + bq27411_modify_soc_smooth_parameter(bq27541_di, false); + } + + if (di->soc_pre != DEFAULT_INVALID_SOC_PRE) + backup_soc_ex(di->soc_pre); +} + +static const struct of_device_id bq27541_match[] = { + { .compatible = "ti,bq27541-battery" }, + { }, +}; + +static const struct i2c_device_id bq27541_id[] = { + { "bq27541-battery", 1 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, BQ27541_id); +static const struct dev_pm_ops bq27541_pm = { + SET_SYSTEM_SLEEP_PM_OPS(bq27541_battery_suspend, bq27541_battery_resume) +}; + +static struct i2c_driver bq27541_battery_driver = { + .driver = { + .name = "bq27541-battery", + .pm = &bq27541_pm, + }, + .probe = bq27541_battery_probe, + .remove = bq27541_battery_remove, + .shutdown = bq27541_shutdown, + .id_table = bq27541_id, +}; + +static int __init bq27541_battery_init(void) +{ + int ret; + + ret = i2c_add_driver(&bq27541_battery_driver); + if (ret) + pr_err("Unable to register BQ27541 driver\n"); + + return ret; +} +module_init(bq27541_battery_init); + +static void __exit bq27541_battery_exit(void) +{ + i2c_del_driver(&bq27541_battery_driver); +} +module_exit(bq27541_battery_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Qualcomm Innovation Center, Inc."); +MODULE_DESCRIPTION("BQ27541 battery monitor driver"); diff --git a/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.h b/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.h new file mode 100644 index 0000000000000000000000000000000000000000..17b7236ad49e117bc0aecad4389785079122a76e --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/bq27541_fuelgauger.h @@ -0,0 +1,279 @@ +#ifndef __OP_BQ27541_H__ +#define __OP_BQ27541_H__ +/* david.liu@bsp, 20161004 Add BQ27411 support */ +#define CONFIG_GAUGE_BQ27411 1 +#define DEVICE_TYPE_BQ27541 0x0541 +#define DEVICE_TYPE_BQ27411 0x0421 +#define DEVICE_TYPE_BQ28Z610 0xFFA5 +#define DEVICE_BQ27541 0 +#define DEVICE_BQ27411 1 +#define DEVICE_BQ28Z610 2 + +#define DRIVER_VERSION "1.1.0" + +/* Bq28Z610 standard data commands */ +#define Bq28Z610_REG_TI 0x0c +#define Bq28Z610_REG_AI 0x14 + +/* Bq27541 standard data commands */ +#define BQ27541_REG_CNTL 0x00 +#define BQ27541_REG_AR 0x02 +#define BQ27541_REG_ARTTE 0x04 +#define BQ27541_REG_TEMP 0x06 +#define BQ27541_REG_VOLT 0x08 +#define BQ27541_REG_FLAGS 0x0A +#define BQ27541_REG_NAC 0x0C +#define BQ27541_REG_FAC 0x0e +#define BQ27541_REG_RM 0x10 +#define BQ27541_REG_FCC 0x12 +#define BQ27541_REG_AI 0x14 +#define BQ27541_REG_TTE 0x16 +#define BQ27541_REG_TTF 0x18 +#define BQ27541_REG_SI 0x1a +#define BQ27541_REG_STTE 0x1c +#define BQ27541_REG_MLI 0x1e +#define BQ27541_REG_MLTTE 0x20 +#define BQ27541_REG_AE 0x22 +#define BQ27541_REG_AP 0x24 +#define BQ27541_REG_TTECP 0x26 +#define BQ27541_REG_SOH 0x28 +#define BQ27541_REG_SOC 0x2c +#define BQ27541_REG_NIC 0x2e +#define BQ27541_REG_ICR 0x30 +#define BQ27541_REG_LOGIDX 0x32 +#define BQ27541_REG_LOGBUF 0x34 + +#define BQ27541_FLAG_DSC BIT(0) +#define BQ27541_FLAG_FC BIT(9) + +#define BQ27541_CS_DLOGEN BIT(15) +#define BQ27541_CS_SS BIT(13) + +#ifdef CONFIG_GAUGE_BQ27411 +/* david.liu@bsp, 20161004 Add BQ27411 support */ +/* Bq27411 standard data commands */ +#define BQ27411_REG_TEMP 0x02 +#define BQ27411_REG_VOLT 0x04 +#define BQ27411_REG_RM 0x0A +#define BQ27411_REG_AI 0x10 +#define BQ27411_REG_SOC 0x1c +#define BQ27411_REG_HEALTH 0x20 +#define BQ27411_REG_FCC 0x2E + +#define CONTROL_CMD 0x00 +#define CONTROL_STATUS 0x00 +#define SEAL_POLLING_RETRY_LIMIT 100 +#define BQ27541_UNSEAL_KEY 0x11151986 +#define BQ27411_UNSEAL_KEY 0x80008000 + +#define BQ27541_RESET_SUBCMD 0x0041 +#define BQ27411_RESET_SUBCMD 0x0042 +#define SEAL_SUBCMD 0x0020 + +#define BQ27411_CONFIG_MODE_POLLING_LIMIT 60 +#define BQ27411_CONFIG_MODE_BIT BIT(4) +#define BQ27411_BLOCK_DATA_CONTROL 0x61 +#define BQ27411_DATA_CLASS_ACCESS 0x003e +#define BQ27411_CC_DEAD_BAND_ID 0x006b +#define BQ27411_CC_DEAD_BAND_ADDR 0x42 +#define BQ27411_CHECKSUM_ADDR 0x60 +#define BQ27411_CC_DEAD_BAND_POWERUP_VALUE 0x11 +#define BQ27411_CC_DEAD_BAND_SHUTDOWN_VALUE 0x71 + +#define BQ27411_OPCONFIGB_ID 0x0040 +#define BQ27411_OPCONFIGB_ADDR 0x42 +#define BQ27411_OPCONFIGB_POWERUP_VALUE 0x07 +#define BQ27411_OPCONFIGB_SHUTDOWN_VALUE 0x0f + +#define BQ27411_DODATEOC_ID 0x0024 +#define BQ27411_DODATEOC_ADDR 0x48 +#define BQ27411_DODATEOC_POWERUP_VALUE 0x32 +#define BQ27411_DODATEOC_SHUTDOWN_VALUE 0x32 + +/* Bq28z610 standard data commands */ +#define BQ28Z610_REG_CNTL1 0x3e +#define BQ28Z610_REG_CNTL2 0x60 +#define BQ28Z610_SEAL_POLLING_RETRY_LIMIT 10 + +#define BQ28Z610_SEAL_STATUS 0x0054 +#define BQ28Z610_SEAL_SUBCMD 0x0030 +#define BQ28Z610_UNSEAL_SUBCMD1 0x0414 +#define BQ28Z610_UNSEAL_SUBCMD2 0x3672 +//#define BQ28Z610_SEAL_BIT (BIT(8) | BIT(9)) +#define BQ28Z610_SEAL_BIT (BIT(0) | BIT(1)) + +#define BQ28Z610_SEAL_SHIFT 8 +#define BQ28Z610_SEAL_VALUE 3 +#define BQ28Z610_MAC_CELL_VOLTAGE_ADDR 0x40 +#define BQ28Z610_REG_CNTL1_SIZE 4 + +#define BQ28Z610_REG_I2C_SIZE 3 + +#define BQ28Z610_REG_GAUGE_EN 0x0057 +#define BQ28Z610_GAUGE_EN_BIT BIT(3) + +#define BQ28Z610_MAC_CELL_VOLTAGE_EN_ADDR 0x3E +#define BQ28Z610_MAC_CELL_VOLTAGE_CMD 0x0071 +#define BQ28Z610_MAC_CELL_VOLTAGE_ADDR 0x40 +#define BQ28Z610_MAC_CELL_VOLTAGE_SIZE 4//total 34byte,only read 4byte(aaAA bbBB) + +#define BQ28Z610_MAC_CELL_BALANCE_TIME_EN_ADDR 0x3E +#define BQ28Z610_MAC_CELL_BALANCE_TIME_CMD 0x0076 +#define BQ28Z610_MAC_CELL_BALANCE_TIME_ADDR 0x40 +#define BQ28Z610_MAC_CELL_BALANCE_TIME_SIZE 4//total 10byte,only read 4byte(aaAA bbBB) + +#define BQ28Z610_OPERATION_STATUS_EN_ADDR 0x3E +#define BQ28Z610_OPERATION_STATUS_CMD 0x0054 +#define BQ28Z610_REG_OPERATION_STATUS_ADDR 0x40 +#define BQ28Z610_OPERATION_STATUS_SIZE 4 +#define BQ28Z610_BALANCING_CONFIG_BIT BIT(28) + +#define BQ28Z610_REG_TIME_TO_FULL 0x18 +#endif + +/* BQ27541 Control subcommands */ +#define BQ27541_SUBCMD_CTNL_STATUS 0x0000 +#define BQ27541_SUBCMD_DEVCIE_TYPE 0x0001 +#define BQ27541_SUBCMD_FW_VER 0x0002 +#define BQ27541_SUBCMD_HW_VER 0x0003 +#define BQ27541_SUBCMD_DF_CSUM 0x0004 +#define BQ27541_SUBCMD_PREV_MACW 0x0007 +#define BQ27541_SUBCMD_CHEM_ID 0x0008 +#define BQ27541_SUBCMD_BD_OFFSET 0x0009 +#define BQ27541_SUBCMD_INT_OFFSET 0x000a +#define BQ27541_SUBCMD_CC_VER 0x000b +#define BQ27541_SUBCMD_OCV 0x000c +#define BQ27541_SUBCMD_BAT_INS 0x000d +#define BQ27541_SUBCMD_BAT_REM 0x000e +#define BQ27541_SUBCMD_SET_HIB 0x0011 +#define BQ27541_SUBCMD_CLR_HIB 0x0012 +#define BQ27541_SUBCMD_SET_SLP 0x0013 +#define BQ27541_SUBCMD_CLR_SLP 0x0014 +#define BQ27541_SUBCMD_FCT_RES 0x0015 +#define BQ27541_SUBCMD_ENABLE_DLOG 0x0018 +#define BQ27541_SUBCMD_DISABLE_DLOG 0x0019 +#define BQ27541_SUBCMD_SEALED 0x0020 +#define BQ27541_SUBCMD_ENABLE_IT 0x0021 +#define BQ27541_SUBCMD_DISABLE_IT 0x0023 +#define BQ27541_SUBCMD_CAL_MODE 0x0040 +#define BQ27541_SUBCMD_RESET 0x0041 +#define ZERO_DEGREE_CELSIUS_IN_TENTH_KELVIN (-2731) +#define BQ27541_INIT_DELAY ((HZ)*1) +#define SET_BQ_PARAM_DELAY_MS 6000 + + +/* Bq27411 sub commands */ +#define BQ27411_SUBCMD_CNTL_STATUS 0x0000 +#define BQ27411_SUBCMD_DEVICE_TYPE 0x0001 +#define BQ27411_SUBCMD_FW_VER 0x0002 +#define BQ27411_SUBCMD_DM_CODE 0x0004 +#define BQ27411_SUBCMD_CONFIG_MODE 0x0006 +#define BQ27411_SUBCMD_PREV_MACW 0x0007 +#define BQ27411_SUBCMD_CHEM_ID 0x0008 +#define BQ27411_SUBCMD_SET_HIB 0x0011 +#define BQ27411_SUBCMD_CLR_HIB 0x0012 +#define BQ27411_SUBCMD_SET_CFG 0x0013 +#define BQ27411_SUBCMD_SEALED 0x0020 +#define BQ27411_SUBCMD_RESET 0x0041 +#define BQ27411_SUBCMD_SOFTRESET 0x0042 +#define BQ27411_SUBCMD_EXIT_CFG 0x0043 + +#define BQ27411_SUBCMD_ENABLE_DLOG 0x0018 +#define BQ27411_SUBCMD_DISABLE_DLOG 0x0019 +#define BQ27411_SUBCMD_ENABLE_IT 0x0021 +#define BQ27411_SUBCMD_DISABLE_IT 0x0023 + +#define BQ27541_BQ27411_CMD_INVALID 0xFF +#define FW_VERSION_4P45V_01 0x0110 +#define FW_VERSION_4P45V_02 0x0200 + + +#define ERROR_SOC 33 +#define ERROR_BATT_VOL (3800 * 1000) + +#ifdef CONFIG_GAUGE_BQ27411 +/* david.liu@bsp, 20161004 Add BQ27411 support */ +struct cmd_address { + u8 reg_temp; + u8 reg_volt; + u8 reg_rm; + u8 reg_ai; + u8 reg_soc; + u8 reg_helth; + u8 reg_fcc; +}; +#endif + +struct bq27541_device_info; +struct bq27541_access_methods { + int (*read)(u8 reg, int *rt_value, int b_single, + struct bq27541_device_info *di); +}; + +struct bq27541_device_info { + struct device *dev; + int id; + struct bq27541_access_methods *bus; + struct i2c_client *client; + struct work_struct counter; + /* 300ms delay is needed after bq27541 is powered up + * and before any successful I2C transaction + */ + struct delayed_work hw_config; + struct delayed_work modify_soc_smooth_parameter; + struct delayed_work battery_soc_work; + struct wakeup_source *update_soc_wake_lock; + struct power_supply *batt_psy; + int saltate_counter; + /* Add for retry when config fail */ + int retry_count; + /* Add for get right soc when sleep long time */ + int soc_pre; + int batt_vol_pre; + int current_pre; + int cap_pre; + int remain_pre; + int health_pre; + unsigned long rtc_resume_time; + unsigned long rtc_suspend_time; + atomic_t suspended; + int temp_pre; + int lcd_off_delt_soc; + int t_count; + int temp_thr_update_count; + int fw_ver; + int time_to_full; + int short_time_standby_count; + + bool lcd_is_off; + bool allow_reading; + bool fastchg_started; + bool wlchg_started; + bool bq_present; + bool set_smoothing; + bool disable_calib_soc; + unsigned long lcd_off_time; + unsigned long soc_pre_time; + /* david.liu@oneplus.tw, 2016/05/16 Fix capacity won't udate */ + unsigned long soc_store_time; +#ifdef CONFIG_GAUGE_BQ27411 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + int device_type; + struct cmd_address cmd_addr; + bool modify_soc_smooth; + bool already_modify_smooth; + bool batt_bq28z610; + bool bq28z610_need_balancing; + int batt_cell_1_vol; + int batt_cell_2_vol; + int batt_cell_max_vol; + int batt_cell_min_vol; + int max_vol_pre; + int min_vol_pre; +#endif + bool bat_4p45v; + bool check_match; +}; + + +#endif diff --git a/drivers/oneplus/power/supply/qcom/oneplus_fastchg.c b/drivers/oneplus/power/supply/qcom/oneplus_fastchg.c new file mode 100644 index 0000000000000000000000000000000000000000..0eabae771c65a5efdfd1274a11b4b4b632608234 --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/oneplus_fastchg.c @@ -0,0 +1,4121 @@ +/**************************************************** + **Description:fastchg update firmware and driver + *****************************************************/ +#define pr_fmt(fmt) "FASTCHG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BYTE_OFFSET 2 +#define BYTES_TO_WRITE 16 + +#define READ_COUNT 192 +#define FW_CHECK_FAIL 0 +#define FW_CHECK_SUCCESS 1 + +#define SHOW_FW_VERSION_DELAY_MS 18000 + +enum dpdm_mode { + DPDM_MODE_NORMAL, + DPDM_MODE_WARP, +}; + +struct fastchg_device_info { + struct i2c_client *client; + struct miscdevice dash_device; + struct mutex read_mutex; + struct mutex gpio_mutex; + wait_queue_head_t read_wq; + + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspended; + struct pinctrl_state *pinctrl_mcu_data_read; + struct pinctrl_state *pinctrl_mcu_data_write; + struct pinctrl *pinctrl; + bool fast_chg_started; + bool fast_low_temp_full; + bool fast_chg_ing; + bool fast_switch_to_normal; + bool fast_normal_to_warm; + bool fast_chg_error; + bool irq_enabled; + bool fast_chg_allow; + bool firmware_already_updated; + bool n76e_present; + bool is_mcl_verion; +#ifdef OP_SWARP_SUPPORTED + struct pinctrl_state *pinctrl_mcu_id_hiz; + struct pinctrl_state *pinctrl_mcu_id_pull_up; + struct pinctrl_state *pinctrl_mcu_id_pull_down; + bool is_swarp_supported; + bool warp_normal_path_need_config; + bool fw_ver_not_match; + int asic_hw_id; +#endif + bool is_4115mAh_4p45_support; + bool is_4300mAh_4p45_support; + bool is_4320mAh_4p45_support; + bool is_4510mAh_4p45_support; + int skin_hi_curr_max; + int skin_wrm_curr_max; + int skin_med_curr_max; + int skin_hi_lcdoff_curr_max; + int skin_med_lcdoff_curr_max; + int dash_firmware_ok; + int mcu_reset_ahead; + int erase_count; + int addr_low; + int addr_high; + int adapter_update_report; + int adapter_update_real; + int battery_type; + int irq; + int mcu_en_gpio; + int usb_sw_1_gpio; + int usb_sw_2_gpio; + int usb_on_gpio; + int usb_on_gpio_1; + int ap_clk; + int ap_data; + int dash_enhance; + int dashchg_fw_ver_count; + unsigned int sid; + + struct power_supply *batt_psy; + struct work_struct fastcg_work; + struct work_struct charger_present_status_work; + struct timer_list watchdog; + struct wakeup_source *fastchg_wake_lock; + struct wakeup_source *fastchg_update_fireware_lock; + + struct delayed_work update_firmware; + struct delayed_work update_fireware_version_work; + struct delayed_work adapter_update_work; +#if (defined(OP_SWARP_SUPPORTED) && !defined(GET_HWID_BY_GPIO)) + struct delayed_work get_asic_hwid_work; +#endif + struct delayed_work disable_mcu_work; + char fw_id[255]; + char manu_name[255]; + + enum dpdm_mode dpdm_mode; +}; + +struct fastchg_device_info *fastchg_di; + +static unsigned char *dashchg_firmware_data; +static struct i2c_client *mcu_client; + +#ifdef OP_SWARP_SUPPORTED +static const char * const mcu_id_text[] = { +"Silergy", "Rockchip", "Richtek" +}; +static const unsigned short i2c_addr[] = {0x06, 0x0a, 0x0e}; +enum swarp_asic_hw_id { + SILERGY_SY6610 = 0, + ROCKCHIP_RK826, + RICHTEK_RT5125, +}; + +static void oneplus_notify_dash_charger_type(enum fast_charger_type type); +#endif +static void oneplus_notify_adapter_sid(unsigned int sid); +void switch_mode_to_normal(void); +//for mcu_data irq delay issue 2017.10.14@Infi +extern void msm_cpuidle_set_sleep_disable(bool disable); + +static int is_usb_pluged(void) +{ + static struct power_supply *psy; + union power_supply_propval ret = {0,}; + int usb_present, rc; + + if (!psy) { + psy = power_supply_get_by_name("usb"); + if (!psy) { + pr_err("fastchg failed to get ps usb\n"); + return -EINVAL; + } + } + + rc = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, &ret); + if (rc) { + pr_err("fastchg failed to get POWER_SUPPLY_PROP_PRESENT\n"); + return -EINVAL; + } + + if (ret.intval < 0) { + pr_err("fastchg get POWER_SUPPLY_PROP_PRESENT EINVAL \n"); + return -EINVAL; + } + + usb_present = ret.intval; + return usb_present; +} + +static ssize_t warp_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t warp_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations warp_chg_exist_operations = { + .read = warp_exist_read, + .write = warp_exist_write, +}; +static void init_warp_chg_exist_node(void) +{ + if (!proc_create("warp_chg_exit", 0644, NULL, + &warp_chg_exist_operations)){ + pr_info("Failed to register n76e node\n"); + } +} + +#ifdef OP_SWARP_SUPPORTED +static ssize_t swarp_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + char buffer[7]; + int len = 0; + len = snprintf(buffer, 7, "%d\n", fastchg_di->asic_hw_id); + return simple_read_from_buffer(puser_buf, count, p_offset, buffer, len);; +} + +static ssize_t swarp_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations swarp_chg_exist_operations = { + .read = swarp_exist_read, + .write = swarp_exist_write, +}; +static void init_swarp_chg_exist_node(void) +{ + if (!proc_create("swarp_chg_exist", 0644, NULL, + &swarp_chg_exist_operations)){ + pr_info("Failed to register swarp node\n"); + } +} +#endif + +static ssize_t dash_4115mAh_4p45_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t dash_4115mAh_4p45_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations dash_4115mAh_4p45_exist_operations = { + .read = dash_4115mAh_4p45_exist_read, + .write = dash_4115mAh_4p45_exist_write, +}; + +static void init_dash_4115mAh_4p45_exist_node(void) +{ + if (!proc_create("dash_4115_4p45_exit", 0644, NULL, + &dash_4115mAh_4p45_exist_operations)){ + pr_info("Failed to register dash_4115mAh_4p45 node\n"); + } +} + +static ssize_t dash_4300mAh_4p45_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t dash_4300mAh_4p45_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations dash_4300mAh_4p45_exist_operations = { + .read = dash_4300mAh_4p45_exist_read, + .write = dash_4300mAh_4p45_exist_write, +}; + +static void init_dash_4300mAh_4p45_exist_node(void) +{ + if (!proc_create("dash_4300_4p45_exit", 0644, NULL, + &dash_4300mAh_4p45_exist_operations)){ + pr_info("Failed to register dash_4300mAh_4p45 node\n"); + } +} + +static ssize_t dash_4320mAh_4p45_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t dash_4320mAh_4p45_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations dash_4320mAh_4p45_exist_operations = { + .read = dash_4320mAh_4p45_exist_read, + .write = dash_4320mAh_4p45_exist_write, +}; + +static void init_dash_4320mAh_4p45_exist_node(void) +{ + if (!proc_create("dash_4320_4p45_exit", 0644, NULL, + &dash_4320mAh_4p45_exist_operations)){ + pr_info("Failed to register dash_4320mAh_4p45 node\n"); + } +} + +static ssize_t dash_4510mAh_4p45_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t dash_4510mAh_4p45_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations dash_4510mAh_4p45_exist_operations = { + .read = dash_4510mAh_4p45_exist_read, + .write = dash_4510mAh_4p45_exist_write, +}; + +static void init_dash_4510mAh_4p45_exist_node(void) +{ + if (!proc_create("dash_4510_4p45_exit", 0644, NULL, + &dash_4510mAh_4p45_exist_operations)){ + pr_info("Failed to register dash_4510mAh_4p45 node\n"); + } +} + +static ssize_t n76e_exist_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 0; +} + +static ssize_t n76e_exist_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + return 0; +} + +static const struct file_operations n76e_exist_operations = { + .read = n76e_exist_read, + .write = n76e_exist_write, +}; + +static void init_n76e_exist_node(void) +{ + if (!proc_create("n76e_exit", 0644, NULL, + &n76e_exist_operations)){ + pr_info("Failed to register n76e node\n"); + } +} +#define PAGESIZE 512 + +static ssize_t enhance_exist_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct fastchg_device_info *di = fastchg_di; + + if (!di) + return ret; + ret = snprintf(page, 255, "%d", di->dash_enhance); + ret = simple_read_from_buffer(user_buf, + count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t enhance_exist_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + struct fastchg_device_info *di = fastchg_di; + int ret = 0; + char buf[4] = {0}; + + if (count > 2) + return count; + + if (copy_from_user(buf, buffer, count)) { + pr_err("%s: write proc dash error.\n", __func__); + return count; + } + + if (-1 == sscanf(buf, "%d", &ret)) { + pr_err("%s sscanf error\n", __func__); + return count; + } + if (!di) + return count; + if ((ret == 0) || (ret == 1)) + di->dash_enhance = ret; + pr_info("%s:the dash enhance is = %d\n", + __func__, di->dash_enhance); + return count; +} + +static const struct file_operations enhance_exist_operations = { + .read = enhance_exist_read, + .write = enhance_exist_write, +}; + +static void init_enhance_dash_exist_node(void) +{ + if (!proc_create("enhance_dash", 0644, NULL, + &enhance_exist_operations)) + pr_err("Failed to register enhance dash node\n"); +} + +static ssize_t dash_firmware_exist_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct fastchg_device_info *di = fastchg_di; + + if (!di) + return ret; + ret = snprintf(page, 255, "%d", di->dash_firmware_ok); + ret = simple_read_from_buffer(user_buf, + count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t dash_firmware_exist_write(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + return count; +} + +static const struct file_operations dash_frimware_done_operations = { + .read = dash_firmware_exist_read, + .write = dash_firmware_exist_write, +}; + +static void init_dash_firmware_done_node(void) +{ + if (!proc_create("dash_firmware_ok", 0644, NULL, + &dash_frimware_done_operations)) + pr_err("Failed to register dash_frimware_done_operations node\n"); +} + +void opchg_set_mcu_data_read(struct fastchg_device_info *chip) +{ + gpio_direction_input(chip->ap_data); + if (chip->pinctrl && + !IS_ERR_OR_NULL(chip->pinctrl_mcu_data_read)) + pinctrl_select_state(chip->pinctrl, + chip->pinctrl_mcu_data_read); +} + +void set_mcu_active(int value) +{ + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) { +#ifdef OP_SWARP_SUPPORTED + if (fastchg_di->is_swarp_supported) + gpio_direction_output(fastchg_di->mcu_en_gpio, value); + else +#endif + gpio_direction_output(fastchg_di->mcu_en_gpio, !(value & 0x01)); + } +} + +void mcu_en_reset(void) +{ + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) { +#ifdef OP_SWARP_SUPPORTED + if (fastchg_di->is_swarp_supported) { + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); + usleep_range(2000, 2001); + gpio_direction_output(fastchg_di->mcu_en_gpio, 1); + } else +#endif + gpio_direction_output(fastchg_di->mcu_en_gpio, 1); + } +} + +void mcu_en_gpio_set(int value) +{ + if (value) { + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) { + if (fastchg_di->is_swarp_supported) + gpio_direction_output(fastchg_di->mcu_en_gpio, 1); + else + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); + } + } else { + if (gpio_is_valid(fastchg_di->mcu_en_gpio)) { +#ifdef OP_SWARP_SUPPORTED + if (fastchg_di->is_swarp_supported) { + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); + usleep_range(10000, 10001); + gpio_direction_output(fastchg_di->mcu_en_gpio, 1); + } else { +#endif + gpio_direction_output(fastchg_di->mcu_en_gpio, 1); + usleep_range(10000, 10001); + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); +#ifdef OP_SWARP_SUPPORTED + } +#endif + } + } +} +#define ADAPTER_UPDATE_DELAY 1400 + +void usb_sw_gpio_set(int value) +{ + pr_info("set usb_sw_gpio=%d\n", value); + if (!gpio_is_valid(fastchg_di->usb_sw_1_gpio) + && !gpio_is_valid(fastchg_di->usb_sw_2_gpio)) { + pr_err("gpio is invalid\n"); + return; + } + + if (value) { + if (gpio_is_valid(fastchg_di->usb_on_gpio)) { + gpio_direction_output(fastchg_di->usb_on_gpio, 1); + gpio_direction_output(fastchg_di->usb_on_gpio_1, 1); + gpio_direction_output(fastchg_di->usb_sw_1_gpio, 1); + gpio_direction_output(fastchg_di->usb_sw_2_gpio, 0); + } else { + gpio_direction_output(fastchg_di->usb_sw_1_gpio, 1); + gpio_direction_output(fastchg_di->usb_sw_2_gpio, 1); + } + } else { + if (gpio_is_valid(fastchg_di->usb_on_gpio)) { + gpio_direction_output(fastchg_di->usb_on_gpio, 0); + gpio_direction_output(fastchg_di->usb_on_gpio_1, 0); + } + gpio_direction_output(fastchg_di->usb_sw_1_gpio, 0); + gpio_direction_output(fastchg_di->usb_sw_2_gpio, 0); + } + fastchg_di->fast_chg_allow = value; + /* david@bsp add log */ + pr_info("get usb_sw_gpio=%d&%d\n" + , gpio_get_value(fastchg_di->usb_sw_1_gpio) + , gpio_get_value(fastchg_di->usb_sw_2_gpio)); +} + +void opchg_set_mcu_data_write(struct fastchg_device_info *chip) +{ + gpio_direction_output(chip->ap_data, 0); + if (chip->pinctrl && + !IS_ERR_OR_NULL(chip->pinctrl_mcu_data_write)) + pinctrl_select_state(chip->pinctrl, + chip->pinctrl_mcu_data_write); +} + +static inline int opchg_mcu_enable(struct fastchg_device_info *di, bool en) +{ + int rc = 0; + + if (!gpio_is_valid(di->mcu_en_gpio)) { + pr_err("mcu en gpio is invalid\n"); + return -ENODEV; + } + + if (di->is_swarp_supported) + rc = gpio_direction_output(di->mcu_en_gpio, en); + else + rc = gpio_direction_output(di->mcu_en_gpio, !en); + if (rc < 0) { + pr_err("%s mcu failed, rc=%d\n", en ? "enbale" : "disable", rc); + return rc; + } + return 0; +} + +static inline bool opchg_mcu_is_enabled(struct fastchg_device_info *di) +{ + if (!gpio_is_valid(di->mcu_en_gpio)) { + pr_err("mcu en gpio is invalid\n"); + return false; + } + + if (di->is_swarp_supported) + return !!gpio_get_value(di->mcu_en_gpio); + else + return !gpio_get_value(di->mcu_en_gpio); +} + +static inline int opchg_switch_dmdm(struct fastchg_device_info *di, + enum dpdm_mode mode) +{ + int rc = 0; + + if (!gpio_is_valid(di->usb_sw_1_gpio) && + !gpio_is_valid(di->usb_sw_2_gpio)) { + pr_err("sw gpio is invalid\n"); + return -ENODEV; + } + + if (mode == DPDM_MODE_WARP) { + if (gpio_is_valid(di->usb_on_gpio)) { + rc = gpio_direction_output(di->usb_on_gpio, 1); + if (rc < 0) { + pr_err("switch usb on(=1) err, rc=%d\n", rc); + goto error; + } + rc = gpio_direction_output(di->usb_on_gpio_1, 1); + if (rc < 0) { + pr_err("switch usb on1(=1) err, rc=%d\n", rc); + goto error; + } + rc = gpio_direction_output(di->usb_sw_1_gpio, 1); + if (rc < 0) { + pr_err("switch sw1(=1) err, rc=%d\n", rc); + goto error; + } + rc = gpio_direction_output(di->usb_sw_2_gpio, 0); + if (rc < 0) { + pr_err("switch sw2(=0) err, rc=%d\n", rc); + goto error; + } + } else { + rc = gpio_direction_output(di->usb_sw_1_gpio, 1); + if (rc < 0) { + pr_err("switch sw1(=1) err, rc=%d\n", rc); + goto error; + } + rc = gpio_direction_output(di->usb_sw_2_gpio, 1); + if (rc < 0) { + pr_err("switch sw2(=1) err, rc=%d\n", rc); + goto error; + } + } + di->fast_chg_allow = true; + } else { + if (gpio_is_valid(di->usb_on_gpio)) { + rc = gpio_direction_output(di->usb_on_gpio, 0); + if (rc < 0) { + pr_err("switch usb on(=0) err, rc=%d\n", rc); + goto error; + } + rc = gpio_direction_output(di->usb_on_gpio_1, 0); + if (rc < 0) { + pr_err("switch usb on1(=0) err, rc=%d\n", rc); + goto error; + } + } + rc = gpio_direction_output(di->usb_sw_1_gpio, 1); + if (rc < 0) { + pr_err("switch sw1(=1) err, rc=%d\n", rc); + goto error; + } + rc = gpio_direction_output(di->usb_sw_2_gpio, 0); + if (rc < 0) { + pr_err("switch sw2(=0) err, rc=%d\n", rc); + goto error; + } + di->fast_chg_allow = false; + } + + pr_info("get usb_sw_gpio=%d&%d\n", + gpio_get_value(di->usb_sw_1_gpio), + gpio_get_value(di->usb_sw_2_gpio)); + + return 0; +error: + di->fast_chg_allow = false; + if (gpio_is_valid(di->usb_on_gpio)) { + gpio_direction_output(di->usb_on_gpio, 0); + gpio_direction_output(di->usb_on_gpio_1, 0); + } + gpio_direction_output(di->usb_sw_1_gpio, 1); + gpio_direction_output(di->usb_sw_2_gpio, 0); + pr_info("get usb_sw_gpio=%d&%d\n", + gpio_get_value(di->usb_sw_1_gpio), + gpio_get_value(di->usb_sw_2_gpio)); + return rc; +} + +static inline int opchg_mcu_switch_to_upgrade_mode(struct fastchg_device_info *di) +{ + int rc = 0; + + if (!gpio_is_valid(di->ap_clk)) { + pr_err("ap clk gpio is invalid\n"); + return -ENODEV; + } + + rc = gpio_direction_output(di->ap_clk, 0); + if (rc < 0) { + pr_err("set ap_clk(=0) error, rc=%d\n", rc); + return rc; + } + usleep_range(10000, 10001); + if (di->dpdm_mode != DPDM_MODE_NORMAL) { + (void)opchg_switch_dmdm(di, DPDM_MODE_NORMAL); + di->dpdm_mode = DPDM_MODE_NORMAL; + } + rc = opchg_mcu_enable(di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(5000, 5001); + rc = opchg_mcu_enable(di, false); + if (rc < 0) { + pr_err("%d: set mcu disable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(10000, 10001); + rc = opchg_mcu_enable(di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + msleep(2500); + rc = gpio_direction_output(di->ap_clk, 1); + if (rc < 0) { + pr_err("set ap_clk(=1) error, rc=%d\n", rc); + goto error; + } + usleep_range(10000, 10001); + + return 0; + +error: // disable mcu + (void) opchg_mcu_enable(di, false); + return rc; +} + +int opchg_mcu_action(enum mcu_action_mode mode) +{ + int rc = 0; + int count; + + if (fastchg_di == NULL) { + pr_err("warp device not found\n"); + return -ENODEV; + } + + pr_info("mcu action %d\n", mode); + mutex_lock(&fastchg_di->gpio_mutex); + switch (mode) { + case ACTION_MODE_ENABLE: + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + break; + case ACTION_MODE_RESET_ACTIVE: + if (fastchg_di->dpdm_mode != DPDM_MODE_NORMAL) + (void)opchg_switch_dmdm(fastchg_di, DPDM_MODE_NORMAL); + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(5000, 5001); + rc = opchg_mcu_enable(fastchg_di, false); + if (rc < 0) { + pr_err("%d: set mcu disable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(10000, 10001); + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(2500, 2501); + if (fastchg_di->dpdm_mode == DPDM_MODE_WARP) { + count = 0; + while (!opchg_mcu_is_enabled(fastchg_di) && count < 50) { + count++; + usleep_range(1000, 1001); + } + if (count >= 50) { + pr_err("can't enable mcu\n"); + goto error; + } + rc = opchg_switch_dmdm(fastchg_di, DPDM_MODE_WARP); + if (rc < 0) { + pr_err("%d: switch to warp mode error, rc=%d\n", + __LINE__); + goto error; + } + } + break; + case ACTION_MODE_RESET_SLEEP: + if (fastchg_di->dpdm_mode != DPDM_MODE_NORMAL) + (void)opchg_switch_dmdm(fastchg_di, DPDM_MODE_NORMAL); + fastchg_di->dpdm_mode = DPDM_MODE_NORMAL; + rc = opchg_mcu_enable(fastchg_di, false); + if (rc < 0) { + pr_err("%d: set mcu disable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(1000, 1001); + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(5000, 5001); + rc = opchg_mcu_enable(fastchg_di, false); + if (rc < 0) { + pr_err("%d: set mcu disable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(1000, 1001); + break; + case ACTION_MODE_SWITCH_UPGRADE: + rc = opchg_mcu_switch_to_upgrade_mode(fastchg_di); + if (rc < 0) + goto error; + break; + case ACTION_MODE_SWITCH_NORMAL: + if (fastchg_di->dpdm_mode != DPDM_MODE_NORMAL) + (void)opchg_switch_dmdm(fastchg_di, DPDM_MODE_NORMAL); + fastchg_di->dpdm_mode = DPDM_MODE_NORMAL; + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(5000, 5001); + break; + case ACTION_MODE_SWITCH_WARP: + if (fastchg_di->dpdm_mode != DPDM_MODE_NORMAL) + (void)opchg_switch_dmdm(fastchg_di, DPDM_MODE_NORMAL); + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(5000, 5001); + rc = opchg_mcu_enable(fastchg_di, false); + if (rc < 0) { + pr_err("%d: set mcu disable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(10000, 10001); + rc = opchg_mcu_enable(fastchg_di, true); + if (rc < 0) { + pr_err("%d: set mcu enable error, rc=%d\n", __LINE__); + goto error; + } + usleep_range(2500, 2501); + count = 0; + while (!opchg_mcu_is_enabled(fastchg_di) && count < 50) { + count++; + usleep_range(1000, 1001); + } + if (count >= 50) { + pr_err("can't enable mcu\n"); + goto error; + } + rc = opchg_switch_dmdm(fastchg_di, DPDM_MODE_WARP); + if (rc < 0) { + pr_err("%d: switch to warp mode error, rc=%d\n", + __LINE__); + goto error; + } + fastchg_di->dpdm_mode = DPDM_MODE_WARP; + break; + default: + rc = -EINVAL; + pr_err("unknown active mode=(=%d)\n", mode); + goto error; + } + mutex_unlock(&fastchg_di->gpio_mutex); + + return 0; + +error: + if (fastchg_di->dpdm_mode != DPDM_MODE_NORMAL) + (void)opchg_switch_dmdm(fastchg_di, DPDM_MODE_NORMAL); + fastchg_di->dpdm_mode = DPDM_MODE_NORMAL; + (void)opchg_mcu_enable(fastchg_di, false); + usleep_range(1000, 1001); + (void)opchg_mcu_enable(fastchg_di, true); + usleep_range(5000, 5001); + (void)opchg_mcu_enable(fastchg_di, false); + usleep_range(1000, 1001); + mutex_unlock(&fastchg_di->gpio_mutex); + return rc; +} + +#define ADAPTER_UPDATE_DELAY 1400 + +static int set_property_on_smbcharger( + enum power_supply_property prop, bool data) +{ + static struct power_supply *psy; + union power_supply_propval value = {data, }; + int ret; + + if (!psy) { + psy = power_supply_get_by_name("battery"); + if (!psy) { + pr_err("failed to get ps battery\n"); + return -EINVAL; + } + } + ret = power_supply_set_property(psy, prop, &value); + /* david@bsp modified */ + if (ret) + return -EINVAL; + + return 0; +} + +#ifdef OP_SWARP_SUPPORTED +#define ASIC_ADD_COUNT 2 +#define p9415_MAX_I2C_READ_CNT 10 +static int oneplus_u16_i2c_read(struct i2c_client *client, u16 reg, int count, + u8 *data) +{ + int ret = -1; + struct i2c_msg i2c_msg[2]; + u8 reg_buf[2] = {reg & 0xff, reg >> 8}; + + //write msg + i2c_msg[0].addr = client->addr; + i2c_msg[0].flags = 0; + i2c_msg[0].len = 2; + i2c_msg[0].buf = reg_buf; + + //read msg + i2c_msg[1].addr = client->addr; + i2c_msg[1].flags = I2C_M_RD; + i2c_msg[1].len = count; + i2c_msg[1].buf = data; + + ret = i2c_transfer(client->adapter, i2c_msg, 2); + if (ret != 2) { + pr_err("read reg(=0x%04x) error, ret=%d\n", reg, ret); + return ret; + } + + return count; +} + +static int oneplus_u16_i2c_write(struct i2c_client *client, int reg, + int count, u8 *data) +{ + int ret; + struct i2c_msg i2c_msg; + u8 *buf; + buf = kzalloc(count + 2, GFP_KERNEL); + if (!buf) { + pr_err("can't alloc memory!\n"); + return -ENOMEM; + } + + buf[0] = reg & 0xff; + buf[1] = reg >> 8; + + memcpy(buf + 2, data, count); + + //write msg + i2c_msg.addr = client->addr; + i2c_msg.flags = 0; + i2c_msg.len = count + 2; + i2c_msg.buf = buf; + + ret = i2c_transfer(client->adapter, &i2c_msg, 1); + if (ret != 1) { + pr_err("write reg(=0x%04x) error, ret=%d\n", reg, ret); + kfree(buf); + return ret; + } + + kfree(buf); + return count; +} +#endif + +static int oneplus_dash_i2c_read( + struct i2c_client *client, u8 addr, s32 len, u8 *rxbuf) +{ + return i2c_smbus_read_i2c_block_data(client, addr, len, rxbuf); +} + +static int oneplus_dash_i2c_write( + struct i2c_client *client, u8 addr, s32 len, u8 *txbuf) +{ + return i2c_smbus_write_i2c_block_data(client, addr, len, txbuf); +} + +static unsigned char addr_buf[2]; +static bool n76e_fw_check(struct fastchg_device_info *chip) +{ + unsigned char data_buf[16] = {0x0}; + int rc = 0; + int j = 0, i; + int fw_line = 0; + int total_line = 0; + + total_line = chip->dashchg_fw_ver_count / 18; + + for (fw_line = 0; fw_line < total_line; fw_line++) { + addr_buf[0] = dashchg_firmware_data[fw_line * 18 + 1]; + addr_buf[1] = dashchg_firmware_data[fw_line * 18]; + rc = oneplus_dash_i2c_write(chip->client, + 0x01, 2, &addr_buf[0]); + if (rc < 0) { + pr_err("i2c_write 0x01 error\n"); + return FW_CHECK_FAIL; + } + + data_buf[0] = 0; + oneplus_dash_i2c_write(chip->client, 0x03, 1, &data_buf[0]); + usleep_range(2000, 2100); + oneplus_dash_i2c_read(chip->client, 0x03, 16, &data_buf[0]); + + for (j = 0; j < 16; j++) { + if (data_buf[j] != dashchg_firmware_data[fw_line * 18 + 2 + j]) { + pr_err("fail, data_buf[%d]:0x%x != n76e_firmware_data[%d]:0x%x\n", + j, data_buf[j], (fw_line * 18 + 2 + j), + dashchg_firmware_data[fw_line * 18 + 2 + j]); + for (i = 0; i < 16; i++) + pr_info("data_buf[%d]:0x%x\n", i, data_buf[i]); + pr_info("fail line=%d\n", fw_line); + return FW_CHECK_FAIL; + } + } + } + return FW_CHECK_SUCCESS; +} + + +static bool dashchg_fw_check(void) +{ + unsigned char addr_buf[2] = {0x88, 0x00}; + unsigned char data_buf[32] = {0x0}; + int rc, i, j, addr; + int fw_line = 0; + + addr_buf[0] = fastchg_di->addr_low; + addr_buf[1] = fastchg_di->addr_high; + rc = oneplus_dash_i2c_write(mcu_client, 0x01, 2, &addr_buf[0]); + if (rc < 0) { + pr_err("%s i2c_write 0x01 error\n", __func__); + goto i2c_err; + } + + usleep_range(2000, 2001); + for (i = 0; i < READ_COUNT; i++) { + oneplus_dash_i2c_read(mcu_client, 0x03, 16, &data_buf[0]); + usleep_range(2000, 2001); + oneplus_dash_i2c_read(mcu_client, 0x03, 16, &data_buf[16]); + addr = 0x8800 + i * 32; + + /* compare recv_buf with dashchg_firmware_data[] begin */ + if (addr == ((dashchg_firmware_data[fw_line * 34 + 1] << 8) + | dashchg_firmware_data[fw_line * 34])) { + for (j = 0; j < 32; j++) { + if (data_buf[j] != dashchg_firmware_data + [fw_line * 34 + 2 + j]) { + pr_info("%s fail,data_buf[%d]:0x%x!=dashchg_firmware_data[%d]:0x%x\n", + __func__, j, data_buf[j], + (fw_line * 34 + 2 + j), + dashchg_firmware_data[fw_line * 34 + 2 + j]); + pr_info("%s addr = 0x%x", __func__, addr); + for (j = 0; j <= 31; j++) + pr_info("%x\n", data_buf[j]); + return FW_CHECK_FAIL; + } + } + fw_line++; + } else { + /*pr_err("%s addr dismatch,addr:0x%x,stm_data:0x%x\n",__func__,*/ + /*addr,(dashchg_firmware_data[fw_line * 34 + 1] << 8) | */ + /*dashchg_firmware_data[fw_line * 34]);*/ + } + /* compare recv_buf with dashchg_firmware_data[] end */ + } + pr_info("result=success\n"); + return FW_CHECK_SUCCESS; +i2c_err: + pr_err("result=fail\n"); + return FW_CHECK_FAIL; +} + +static int dashchg_fw_write( + unsigned char *data_buf, + unsigned int offset, unsigned int length) +{ + unsigned int count = 0; + unsigned char zero_buf[1] = {0}; + unsigned char temp_buf[1] = {0}; + unsigned char addr_buf[2] = {0x88, 0x00}; + int rc; + + addr_buf[0] = fastchg_di->addr_low; + addr_buf[1] = fastchg_di->addr_high; + count = offset; + /* write data begin */ + while (count < (offset + length)) { + addr_buf[0] = data_buf[count + 1]; + addr_buf[1] = data_buf[count]; + + rc = oneplus_dash_i2c_write(mcu_client, 0x01, 2, &addr_buf[0]); + if (rc < 0) { + pr_err("i2c_write 0x01 error\n"); + return -EFAULT; + } + + /* write 16 bytes data to dashchg */ + oneplus_dash_i2c_write(mcu_client, + 0x02, BYTES_TO_WRITE, &data_buf[count+BYTE_OFFSET]); + oneplus_dash_i2c_write(mcu_client, 0x05, 1, &zero_buf[0]); + oneplus_dash_i2c_read(mcu_client, 0x05, 1, &temp_buf[0]); + + /* write 16 bytes data to dashchg again */ + if (!fastchg_di->n76e_present) { + oneplus_dash_i2c_write(mcu_client, + 0x02, BYTES_TO_WRITE, + &data_buf[count+BYTE_OFFSET+BYTES_TO_WRITE]); + oneplus_dash_i2c_write(mcu_client, + 0x05, 1, &zero_buf[0]); + oneplus_dash_i2c_read(mcu_client, + 0x05, 1, &temp_buf[0]); + count = count + BYTE_OFFSET + 2 * BYTES_TO_WRITE; + } else + count = count + BYTE_OFFSET + BYTES_TO_WRITE; + + usleep_range(2000, 2001); + if (count > (offset + length - 1)) + break; + } + return 0; +} + +#ifdef OP_SWARP_SUPPORTED +/*RockChip RK826 firmware upgrade start*/ +#define ERASE_COUNT 959 /*0x0000-0x3BFF*/ +#define BYTE_OFFSET 2 +#define BYTES_TO_WRITE 16 +#define FW_CHECK_FAIL 0 +#define FW_CHECK_SUCCESS 1 +#define PAGE_UNIT 128 +#define TRANSFER_LIMIT 72 +#define I2C_ADDR 0x14 +#define REG_RESET 0x5140 +#define REG_SYS0 0x52C0 +#define REG_HOST 0x52C8 +#define REG_SLAVE 0x52CC +#define REG_STATE 0x52C4 +#define REG_MTP_SELECT 0x4308 +#define REG_MTP_ADDR 0x4300 +#define REG_MTP_DATA 0x4304 +#define REG_SRAM_BEGIN 0x2000 +#define SYNC_FLAG 0x53594E43 +#define NOT_SYNC_FLAG (~SYNC_FLAG) +#define REC_01_FLAG 0x52454301 +#define REC_0O_FLAG 0x52454300 +#define RESTART_FLAG 0x52455354 +#define MTP_SELECT_FLAG 0x000f0001 +#define MTP_ADDR_FLAG 0xffff8000 +#define SLAVE_IDLE 0x49444C45 +#define SLAVE_BUSY 0x42555359 +#define SLAVE_ACK 0x41434B00 +#define SLAVE_ACK_01 0x41434B01 +#define FORCE_UPDATE_FLAG 0xaf1c0b76 +#define SW_RESET_FLAG 0X0000fdb9 +#define STATE_READY 0x0 +#define STATE_SYNC 0x1 +#define STATE_REQUEST 0x2 +#define STATE_FIRMWARE 0x3 +#define STATE_FINISH 0x4 + +typedef struct { + u32 tag; + u32 length; + u32 timeout; + u32 ram_offset; + u32 fw_crc; + u32 header_crc; +} struct_req, *pstruct_req; + +static bool rk826_fw_check(struct fastchg_device_info *chip) +{ + int ret = 0; + u8 data_buf[4]= {0}; + u32 mtp_select_flag = cpu_to_le32(MTP_SELECT_FLAG); + u32 mtp_addr_flag = cpu_to_le32(MTP_ADDR_FLAG); + u32 i = 0; + + pr_err("wkcs: fw check\n"); + ret = oneplus_u16_i2c_write(chip->client, REG_MTP_SELECT, 4, (u8 *)(&mtp_select_flag)); + if (ret < 0) { + pr_err("write mtp select reg error\n"); + goto fw_update_check_err; + } + + for (i = chip->dashchg_fw_ver_count - 11; i <= chip->dashchg_fw_ver_count - 4; i++) { + mtp_addr_flag = (MTP_ADDR_FLAG | i); + ret = oneplus_u16_i2c_write(chip->client, REG_MTP_ADDR, 4, (u8 *)(&mtp_addr_flag)); + if (ret < 0) { + pr_err("write mtp addr error\n"); + goto fw_update_check_err; + } + + ret = oneplus_u16_i2c_read(chip->client, REG_MTP_ADDR, 4, data_buf); + if (ret < 0) { + pr_err("read mtp addr error\n"); + goto fw_update_check_err; + } + + do { + ret = oneplus_u16_i2c_read(chip->client, REG_MTP_SELECT, 4, data_buf); + if (ret < 0) { + pr_err("read mtp select reg error\n"); + goto fw_update_check_err; + } + } while (!(data_buf[1] & 0x01)); + + ret = oneplus_u16_i2c_read(chip->client, REG_MTP_DATA, 4, data_buf); + if (ret < 0) { + pr_err("read mtp data error\n"); + goto fw_update_check_err; + } + pr_info("the read compare data: %02x, target:%02x\n", data_buf[0], dashchg_firmware_data[i]); + if (data_buf[0] != dashchg_firmware_data[i]) { + //pr_err("rk826_fw_data check fail\n"); + if ((i == chip->dashchg_fw_ver_count - 5) + || (i == chip->dashchg_fw_ver_count - 4)) + chip->fw_ver_not_match = true; + goto fw_update_check_err; + } + } + + return FW_CHECK_SUCCESS; + +fw_update_check_err: + pr_err("rk826_fw_data check fail\n"); + return FW_CHECK_FAIL; +} + +static u32 js_hash_en(u32 hash, const u8 *buf, u32 len) +{ + u32 i; + + for (i = 0; i < len; i++) + hash ^= ((hash << 5) + buf[i] + (hash >> 2)); + return hash; +} + +static u32 js_hash(const u8 *buf, u32 len) +{ + return js_hash_en(0x47C6A7E6, buf, len); +} + +int WriteSram(struct fastchg_device_info *chip, const u8 *buf, u32 size) +{ + u8 offset = 0; + u16 reg_addr; + int ret = 0; + int i = 0; + int cur_size = 0; + int try_count = 5; + u8 readbuf[4] = {0}; + u8 tx_buff[4] = {0}; + u8 TEST[72] = {0}; + u32 rec_0O_flag = cpu_to_le32(REC_0O_FLAG); + u32 rec_01_flag = cpu_to_le32(REC_01_FLAG); + + while (size) { + if (size >= TRANSFER_LIMIT) { + cur_size = TRANSFER_LIMIT; + } else + cur_size = size; + memcpy(TEST, buf, 72); + for (i = 0; i < cur_size / 4; i++) { + reg_addr = REG_SRAM_BEGIN + i * 4; + memcpy(tx_buff, buf + offset + i * 4, 4); + ret = oneplus_u16_i2c_write(chip->client, reg_addr, 4, tx_buff); + if (ret < 0) { + pr_err("write SRAM fail"); + return -1; + } + } + //ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, readbuf); + //pr_err("teh REG_STATE1: %d", *(u32*)readbuf); + ret = oneplus_u16_i2c_write(chip->client, REG_HOST, 4, (u8 *)(&rec_0O_flag)); + //mdelay(3); + //write rec_00 into host + if (ret < 0) { + pr_err("write rec_00 into host"); + return -1; + } + //read slave + do { + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, readbuf); + pr_err(" the try_count: %d, the REG_STATE: %d", try_count, *(u32*)readbuf); + //msleep(10); + ret = oneplus_u16_i2c_read(chip->client, REG_SLAVE, 4, readbuf); + if (ret < 0) { + pr_err("read slave ack fail"); + return -1; + } + try_count--; + } while (*(u32 *)readbuf == SLAVE_BUSY); + pr_info("the try_count: %d, the readbuf: %x\n", try_count, *(u32 *)readbuf); + if ((*(u32 *)readbuf != SLAVE_ACK) && (*(u32 *)readbuf != SLAVE_ACK_01)) { + pr_err(" slave ack fail"); + return -1; + } + + //write rec_01 into host + ret = oneplus_u16_i2c_write(chip->client, REG_HOST, 4, (u8 *)(&rec_01_flag)); + //write rec_00 into host + if (ret < 0) { + pr_err("write rec_00 into host"); + return -1; + } + + //msleep(50); + offset += cur_size; + size -= cur_size; + try_count = 5; + } + return 0; +} + +int rk826_download_erase_byte(struct fastchg_device_info *chip, const u8 byte) +{ + u8 transfer_buf[TRANSFER_LIMIT]; + u32 onetime_size = TRANSFER_LIMIT - 8; + u32 index = 0; + //u32 offset = 0; + int ret = 0; + int size=16384;// erase 16kb + + pr_info("size: %d\n", size); + pr_err("erase_rk826_%02x start\n", byte); + do { + memset(transfer_buf, byte, TRANSFER_LIMIT); + + if (size >= onetime_size) { + //memcpy(transfer_buf, buf + offset, onetime_size); + size-= onetime_size; + //offset += onetime_size; + } else { + //memcpy(transfer_buf, buf + offset, size); + //offset += size; + size = 0; + } + *((u32 *)(transfer_buf + onetime_size)) = index; + *((u32 *)(transfer_buf + onetime_size + 4)) = js_hash(transfer_buf, onetime_size + 4); + + ret = WriteSram(chip, transfer_buf, TRANSFER_LIMIT); + if (ret != 0) { + return ret; + } + pr_info("index: %d\n", index); + index++; + } while (size); + pr_err("erase_rk826_%02x end\n", byte); + return 0; +} + +static int rk826_erase_fw_by_byte(struct fastchg_device_info *chip, const u8 byte) +{ + int ret = 0; + int iTryCount = 3; + struct_req req = {0}; + u32 sync_flag = cpu_to_le32(SYNC_FLAG); + u32 force_update_flag = cpu_to_le32(FORCE_UPDATE_FLAG); + u32 sw_reset_flag = cpu_to_le32(SW_RESET_FLAG); + u32 rec_01_flag = cpu_to_le32(REC_01_FLAG); + u8 read_buf[4] = {0}; + + oneplus_u16_i2c_write(chip->client, REG_SYS0, 4, (u8 *)(&force_update_flag)); + msleep(10); + oneplus_u16_i2c_write(chip->client, REG_RESET, 4, (u8 *)(&sw_reset_flag)); + while (iTryCount) { + msleep(10); + ret = oneplus_u16_i2c_write(chip->client, REG_HOST, 4, (u8 *)(&sync_flag)); + if (ret < 0) { + pr_err("write sync failed!"); + goto update_fw_err; + } + + //2.check ~sync + msleep(10); + ret = oneplus_u16_i2c_read(chip->client, REG_HOST, 4, read_buf); + pr_info("the data: %x, %x, %x, %x\n", read_buf[0], read_buf[1], read_buf[2], read_buf[3]); + pr_info("the data: %x, %x, %x, %x\n", *(u8 *)(&sync_flag), *((u8 *)(&sync_flag) + 1), *((u8 *)(&sync_flag) + 2), *((u8 *)(&sync_flag) + 3)); + + if (ret < 0) { + pr_err("read sync failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != NOT_SYNC_FLAG) { + pr_err("check ~sync failed!"); + iTryCount--; + msleep(50); + continue; + } + break; + } + + if (iTryCount == 0) { + pr_err("Failed to sync!"); + goto update_fw_err; + } + + // write rec_01 + ret = oneplus_u16_i2c_write(chip->client, REG_HOST, 4, (u8 *)(&rec_01_flag)); + if (ret < 0) { + pr_err("write rec_01 flag failed!"); + goto update_fw_err; + } + msleep(10); + + // read reg_state + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, read_buf); + if (ret<0) { + pr_err("write rec_01 flag failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != STATE_REQUEST) { + pr_err("Failed to go into request_state!"); + goto update_fw_err; + } + + // send req + req.tag = 0x51455220; + req.ram_offset = 0; + req.length = 16384;//for erase + req.timeout = 0; + if (byte == 0x00) + req.fw_crc = 0xd55e99fb;//for crc hash + else if (byte == 0xff) + req.fw_crc = 0x8d8369dd; + req.header_crc = js_hash((const u8*)&req, sizeof(req) - 4); + if ((ret = WriteSram(chip, (const u8* )&req, sizeof(req))) != 0) { + pr_err("failed to send request!err=%d\n", ret); + goto update_fw_err; + } + msleep(10); + + // read state firwware + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, read_buf); + pr_info("read state firwware: %x\n", *(u32 *)read_buf); + if (ret < 0) { + pr_err("write REG_STATE flag failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != STATE_FIRMWARE) { + pr_err("Failed to go into firmware_state"); + goto update_fw_err; + } + + // send fw + if ((ret = rk826_download_erase_byte(chip, byte)) != 0) { + pr_err("failed to send firmware"); + goto update_fw_err; + } + + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, read_buf); + if (ret < 0) { + pr_err("write REG_STATE flag failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != STATE_FINISH) { + pr_err("Failed to go into finish_state"); + goto update_fw_err; + } + oneplus_u16_i2c_write(chip->client, REG_RESET, 4, (u8 *)(&sw_reset_flag)); + pr_info("success\n"); + return 0; + +update_fw_err: + pr_err("fail\n"); + return 1; +} + +int DownloadFirmware(struct fastchg_device_info *chip, const u8 *buf, u32 size) +{ + u8 transfer_buf[TRANSFER_LIMIT]; + u32 onetime_size = TRANSFER_LIMIT - 8; + u32 index = 0; + u32 offset = 0; + int ret = 0; + + pr_info("size: %d\n", size); + do { + memset(transfer_buf, 0, TRANSFER_LIMIT); + if (size >= onetime_size) { + memcpy(transfer_buf, buf + offset, onetime_size); + size-= onetime_size; + offset += onetime_size; + } else { + memcpy(transfer_buf, buf + offset, size); + offset += size; + size = 0; + } + *((u32 *)(transfer_buf + onetime_size)) = index; + *((u32 *)(transfer_buf + onetime_size + 4)) = js_hash(transfer_buf, onetime_size + 4); + ret = WriteSram(chip, transfer_buf, TRANSFER_LIMIT); + if (ret != 0) { + return ret; + } + pr_info("index: %d\n", index); + index++; + } while (size); + return 0; +} + +static int rk826_fw_write(struct fastchg_device_info *chip, + const unsigned char *data_buf, + unsigned int offset, unsigned int length) +{ + int ret = 0; + int iTryCount = 3; + struct_req req = {0}; + u32 sync_flag = cpu_to_le32(SYNC_FLAG); + u32 force_update_flag = cpu_to_le32(FORCE_UPDATE_FLAG); + u32 force_dis_update_flag = 0x00000000; + u32 sw_reset_flag = cpu_to_le32(SW_RESET_FLAG); + u32 rec_01_flag = cpu_to_le32(REC_01_FLAG); + u8 read_buf[4] = {0}; + + oneplus_u16_i2c_write(chip->client, REG_SYS0, 4, (u8 *)(&force_update_flag)); + msleep(10); + oneplus_u16_i2c_write(chip->client, REG_RESET, 4, (u8 *)(&sw_reset_flag)); + while (iTryCount) { + msleep(10); + ret = oneplus_u16_i2c_write(chip->client, REG_HOST, 4, (u8 *)(&sync_flag)); + if (ret < 0) { + pr_err("write sync failed!"); + goto update_fw_err; + } + + //2.check ~sync + msleep(10); + ret = oneplus_u16_i2c_read(chip->client, REG_HOST, 4, read_buf); + pr_info("the data: %x, %x, %x, %x\n", read_buf[0], read_buf[1], read_buf[2], read_buf[3]); + pr_info("the data: %x, %x, %x, %x\n", *(u8 *)(&sync_flag), *((u8 *)(&sync_flag) + 1), *((u8 *)(&sync_flag) + 2), *((u8 *)(&sync_flag) + 3)); + + if (ret < 0) { + pr_err("read sync failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != NOT_SYNC_FLAG) { + pr_err("check ~sync failed!, data=0x%x\n", *(u32 *)read_buf); + iTryCount--; + msleep(50); + continue; + } + break; + } + + if (iTryCount == 0) { + pr_err("Failed to sync!"); + goto update_fw_err; + } + + // write rec_01 + ret = oneplus_u16_i2c_write(chip->client, REG_HOST, 4, (u8 *)(&rec_01_flag)); + if (ret < 0) { + pr_err("write rec_01 flag failed!"); + goto update_fw_err; + } + msleep(10); + + // read reg_state + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, read_buf); + if (ret<0) { + pr_err("write rec_01 flag failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != STATE_REQUEST) { + pr_err("Failed to go into request_state!"); + goto update_fw_err; + } + + // send req + req.tag = 0x51455220; + req.ram_offset = 0; + req.length = chip->dashchg_fw_ver_count; + req.timeout = 0; + req.fw_crc = js_hash(data_buf, req.length); + req.header_crc = js_hash((const u8*)&req, sizeof(req) - 4); + if ((ret = WriteSram(chip, (const u8* )&req, sizeof(req))) != 0) { + pr_err("failed to send request!err=%d\n", ret); + goto update_fw_err; + } + msleep(10); + + // read state firwware + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, read_buf); + pr_info("read state firwware: %x\n", *(u32 *)read_buf); + if (ret < 0) { + pr_err("write REG_STATE flag failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != STATE_FIRMWARE) { + pr_err("Failed to go into firmware_state"); + goto update_fw_err; + } + + // send fw + if ((ret = DownloadFirmware(chip, data_buf, chip->dashchg_fw_ver_count)) != 0) { + pr_err("failed to send firmware"); + goto update_fw_err; + } + + ret = oneplus_u16_i2c_read(chip->client, REG_STATE, 4, read_buf); + if (ret < 0) { + pr_err("write REG_STATE flag failed!"); + goto update_fw_err; + } + if (*(u32 *)read_buf != STATE_FINISH) { + pr_err("Failed to go into finish_state"); + goto update_fw_err; + } + msleep(10); + oneplus_u16_i2c_write(chip->client, REG_SYS0, 4, (u8 *)(&force_dis_update_flag)); + msleep(2); + oneplus_u16_i2c_write(chip->client, REG_RESET, 4, (u8 *)(&sw_reset_flag)); + pr_info("success\n"); + return 0; + +update_fw_err: + pr_err("fail\n"); + return 1; +} +/*RockChip RK826 firmware upgrade end*/ + +/*RichTek RT5125 firmware upgrade start*/ +#define DEFAULT_MAX_BINSIZE (16 * 1024) +#define DEFAULT_MAX_DATALEN (128) +#define DEFAULT_MAX_PAGELEN (128) +#define DEFAULT_MAX_PAGEIDX (DEFAULT_MAX_BINSIZE / DEFAULT_MAX_PAGELEN) +#define DEFAULT_VERINFO_LEN (10) +#define DEFAULT_PAGEWR_RETRY (110) +#define DEFAULT_I2C_RETRY (5) +/* cmd 1 + data 128 + crc8 */ +#define DEFAULT_MAX_BUFFLEN (1 + DEFAULT_MAX_DATALEN + 1) +#define RT5125_CRC16_INIT (0xffff) +#define RT5125_CID (0x5125) + +#define RT5125_CHIP_ID (0x00) +#define RT5125_MTP_INFO_0 (0x01) +#define RT5125_PAGE_IDX (0x10) +#define RT5125_ACCESS_CTL (0x12) +#define RT5125_STATUS (0x13) +#define RT5125_DATA_BUF (0x80) +#define RT5125_FW_CRC16_INFO (0x90) +#define RT5125_CMD_CRC8_INFO (0x91) + +#define RT5125_MTP_MODE BIT(0) +#define RT5125_FW_CRC16_RSLT BIT(3) +#define RT5125_OPSTATUS_MASK (0x7) +#define RT5125_OPSTATUS_DFAIL (0x7) +#define RT5125_OPSTATUS_CFAIL (0x6) +#define RT5125_OPSTATUS_PFAIL (0x5) +#define RT5125_OPSTATUS_FAIL (0x4) +#define RT5125_OPSTATUS_SUCCESS (0x2) +#define RT5125_OPSTATUS_ONGOING (0x1) +#define RT5125_OPSTATUS_IDLE (0x0) +#define RT5125_OPSTATUS_FAILMSK BIT(2) +#define RT5125_WT_PAGE BIT(7) +#define RT5125_RD_PAGE BIT(6) +#define RT5125_WT_FW_CRC16 BIT(3) +#define RT5125_FW_CRC16_VRFY BIT(2) +#define RT5125_WT_KEY BIT(1) +#define CRC8_TABLE_SIZE 256 + +static u8 crc8_table[CRC8_TABLE_SIZE]; +static DEFINE_MUTEX(data_lock); + +static u16 const crc16_table[256] = { +0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, +0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, +0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, +0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, +0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, +0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, +0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, +0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, +0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, +0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, +0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, +0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, +0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, +0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, +0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, +0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, +0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, +0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, +0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, +0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, +0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, +0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, +0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, +0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, +0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, +0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, +0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, +0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, +0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, +0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, +0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, +0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +static u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc) +{ + /* loop over the buffer data */ + while (nbytes-- > 0) + crc = table[(crc ^ *pdata++) & 0xff]; + + return crc; +} + +static void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial) +{ + int i, j; + const u8 msbit = 0x80; + u8 t = msbit; + + table[0] = 0; + for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) { + t = (t << 1) ^ (t & msbit ? polynomial : 0); + for (j = 0; j < i; j++) + table[i+j] = table[j] ^ t; + } +} + +static inline u16 crc16_byte(u16 crc, const u8 data) +{ + return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff]; +} + +static u16 crc16(u16 crc, u8 const *buffer, size_t len) +{ + while (len--) + crc = crc16_byte(crc, *buffer++); + return crc; +} + +DEFINE_MUTEX(dma_wr_access_rt5125); +#define I2C_MASK_FLAG (0x00ff) +#define GTP_DMA_MAX_TRANSACTION_LENGTH 255 /* for DMA mode */ +static int op_i2c_dma_read(struct i2c_client *client, u8 addr, s32 len, u8 *rxbuf) +{ + int ret; + s32 retry = 0; + u8 buffer[1] = {0}; + char gpDMABuf_pa[GTP_DMA_MAX_TRANSACTION_LENGTH] = {0}; + struct i2c_msg msg[2] = { + { + .addr = (client->addr & I2C_MASK_FLAG), + .flags = 0, + .buf = buffer, + .len = 1, + }, + { + .addr = (client->addr & I2C_MASK_FLAG), + .flags = I2C_M_RD, + .buf = (__u8 *)gpDMABuf_pa, /*modified by PengNan*/ + .len = len, + }, + }; + + mutex_lock(&dma_wr_access_rt5125); + buffer[0] = (u8)(addr & 0xFF); + + if (rxbuf == NULL) { + mutex_unlock(&dma_wr_access_rt5125); + return -1; + } + //chg_debug("rk826 dma i2c read: 0x%x, %d bytes(s)\n", addr, len); + for (retry = 0; retry < 5; ++retry) { + ret = i2c_transfer(client->adapter, &msg[0], 2); + if (ret < 0) { + continue; + } + memcpy(rxbuf, gpDMABuf_pa, len); + mutex_unlock(&dma_wr_access_rt5125); + return 0; + } + pr_err(" Error: 0x%04X, %d byte(s), err-code: %d\n", addr, len, ret); + mutex_unlock(&dma_wr_access_rt5125); + + return ret; +} + +static int op_i2c_dma_write(struct i2c_client *client, u8 addr, s32 len, u8 const *txbuf) +{ + int ret = 0; + s32 retry = 0; + char gpDMABuf_pa[GTP_DMA_MAX_TRANSACTION_LENGTH] = {0}; + u8 *wr_buf = gpDMABuf_pa; + struct i2c_msg msg = { + .addr = (client->addr & I2C_MASK_FLAG), + .flags = 0, + .buf = (__u8 *)gpDMABuf_pa, /*modified by PengNan*/ + .len = 1 + len, + }; + + mutex_lock(&dma_wr_access_rt5125); + wr_buf[0] = (u8)(addr & 0xFF); + if (txbuf == NULL) { + mutex_unlock(&dma_wr_access_rt5125); + return -1; + } + memcpy(wr_buf + 1, txbuf, len); + //chg_debug("rk826 dma i2c write: 0x%x, %d bytes(s)\n", addr, len); + for (retry = 0; retry < 5; ++retry) { + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + continue; + } + mutex_unlock(&dma_wr_access_rt5125); + return 0; + } + pr_err(" Error: 0x%04X, %d byte(s), err-code: %d\n", addr, len, ret); + mutex_unlock(&dma_wr_access_rt5125); + + return ret; +} + +static int rt5125_i2c_block_read(struct fastchg_device_info *chip, + u8 cmd, u8 *data, s32 len) +{ + u8 crc; + int retry = 0, ret; + static u8 data_buff[DEFAULT_MAX_BUFFLEN]; +// chip->client = the_chip->client; + + if (len > DEFAULT_MAX_DATALEN || len <= 0) + return -EINVAL; + + mutex_lock(&data_lock); +retry_read: + if (retry++ >= DEFAULT_I2C_RETRY) { + ret = -EIO; + goto out_read; + } + + ret = op_i2c_dma_read(chip->client, cmd, len + 1, data_buff + 1); + if (ret < 0) + goto out_read; + data_buff[0] = cmd; + /* verify crc 8 : cmd + data */ + crc = crc8(crc8_table, data_buff, len + 1, 0); + if (crc != data_buff[len + 1]) + goto retry_read; + memcpy(data, data_buff + 1, len); +out_read: + mutex_unlock(&data_lock); + return ret; +} + +static int rt5125_i2c_block_write(struct fastchg_device_info *chip, + u8 cmd, const u8 *data, s32 len) +{ + int retry = 0, ret; + static u8 data_buff[DEFAULT_MAX_BUFFLEN]; + + if (len > DEFAULT_MAX_DATALEN || len <= 0) + return -EINVAL; + + mutex_lock(&data_lock); +retry_write: + if (retry++ >= DEFAULT_I2C_RETRY) { + ret = -EIO; + goto out_write; + } + + data_buff[0] = cmd; + memcpy(data_buff + 1, data, len); + data_buff[len + 1] = crc8(crc8_table, data_buff, len + 1, 0); + ret = op_i2c_dma_write(chip->client, cmd, len + 1, data_buff + 1); + if (ret < 0) + goto out_write; + ret = op_i2c_dma_read(chip->client, RT5125_CMD_CRC8_INFO, 1, data_buff); + if (ret < 0) + goto out_write; + if (data_buff[0] != (~data_buff[len +1] & 0xff)) + goto retry_write; + +out_write: + mutex_unlock(&data_lock); + return ret; +} + +static bool rt5125_fw_check(struct fastchg_device_info *chip) +{ + const u8 *data = dashchg_firmware_data; + s32 len = chip->dashchg_fw_ver_count; + u8 rwdata = 0, status, fwdata[DEFAULT_MAX_PAGELEN * 2]; + u8 last_page[DEFAULT_MAX_PAGELEN]; + u8 verinfo[DEFAULT_VERINFO_LEN]; + u32 fw_info = 0; + int i, idx, ret, retry = 0; + + if (!data) { + pr_err("rt5125_fw_data Null, Return\n"); + return FW_CHECK_FAIL; + } + + /* poly = x^8 + x^2 + x^1 + 1 */ + crc8_populate_msb(crc8_table, 0x7); + + /* write access for crc16 verify */ + rwdata = (u8)RT5125_FW_CRC16_VRFY; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("fw_crc_vrfy access fail\n"); + goto fw_update_check_err; + } + +busy_retry: + /* wait 200ms for CRC verify */ + msleep(200); + + /* check fw_crc_vrfy status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("fw_crc_vrfy read status fail\n"); + goto fw_update_check_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_ONGOING) { + pr_err("fw_crc_vrfy ongoing\n"); + if (++retry < 10) + goto busy_retry; + else { + pr_err("fw_crc_vrfy busy retry fail\n"); + goto fw_update_check_err; + } + } else if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("fw_crc_vrfy status fail\n"); + goto fw_update_check_err; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("fw_crc_vrfy success\n"); + } else { + pr_err("fw_crc_vrfy unknown 0x%02x\n", status); + goto fw_update_check_err; + } + + if (!(rwdata & RT5125_FW_CRC16_RSLT)) { + pr_err("fw_crc_vrfy crc result fail\n"); + goto fw_update_check_err; + } + pr_info("fw_crc_vrfy OK\n"); + + /* read orig fw info */ + idx = DEFAULT_MAX_PAGEIDX - 1; + rwdata = (u8)idx; + ret = rt5125_i2c_block_write(chip, RT5125_PAGE_IDX, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] rdpage idx fail\n", idx); + goto fw_update_check_err; + } + + /* access to read page from mtp to buffer */ + rwdata = (u8)RT5125_RD_PAGE; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d]rdpage access fail\n", idx); + goto fw_update_check_err; + } + + /* wait 5ms for mtp read */ + msleep(5); + + /* check page rd status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] read status fail\n", idx); + goto fw_update_check_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("[%d] rdpage fail 0x%02x\n", idx, status); + goto fw_update_check_err; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("[%d] rdpage success\n", idx); + } else { + pr_err("[%d]rdpage unknown 0x%02x\n", idx, status); + goto fw_update_check_err; + } + + /* page data */ + ret = rt5125_i2c_block_read(chip, RT5125_DATA_BUF, + last_page, DEFAULT_MAX_PAGELEN); + if (ret < 0) { + pr_err("[%d] rdpage data fail\n", idx); + goto fw_update_check_err; + } + /* get fw size */ + fw_info = (last_page[123] << 8) + last_page[122]; + if (fw_info < DEFAULT_VERINFO_LEN) { + pr_err("size [%d] smaller than verinfo\n", fw_info); + goto fw_update_check_err; + } + + /* always read last two single page */ + idx = fw_info / DEFAULT_MAX_PAGELEN - 1; + for (i = 0; i < 2; i++) { + /* page idx */ + if ((idx + i) < 0 || (idx + i) >= DEFAULT_MAX_PAGEIDX) + continue; + rwdata = (u8)(idx + i); + ret = rt5125_i2c_block_write(chip, RT5125_PAGE_IDX, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] rdpage idx fail\n", idx + i); + goto fw_update_check_err; + } + + /* access to read page from mtp to buffer */ + rwdata = (u8)RT5125_RD_PAGE; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d]rdpage access fail\n", idx + i); + goto fw_update_check_err; + } + + /* wait 5ms for mtp read */ + msleep(5); + + /* check page rd status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] read status fail\n", idx + i); + goto fw_update_check_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("[%d] rdpage fail 0x%02x\n", idx + i, status); + goto fw_update_check_err; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("[%d] rdpage success\n", idx + i); + } else { + pr_err("[%d]rdpage unknown 0x%02x\n", idx + i, status); + goto fw_update_check_err; + } + + /* page data */ + ret = rt5125_i2c_block_read(chip, RT5125_DATA_BUF, + fwdata + i * DEFAULT_MAX_PAGELEN, + DEFAULT_MAX_PAGELEN); + if (ret < 0) { + pr_err("[%d] rdpage data fail\n", idx + i); + goto fw_update_check_err; + } + } + + idx = DEFAULT_MAX_PAGELEN + + fw_info % DEFAULT_MAX_PAGELEN - DEFAULT_VERINFO_LEN; + memcpy(verinfo, fwdata + idx, DEFAULT_VERINFO_LEN); + + idx = len - DEFAULT_VERINFO_LEN; + ret = memcmp(verinfo, data + idx, DEFAULT_VERINFO_LEN); + if (ret != 0) { + pr_err("verinfo not equal\n"); + goto fw_update_check_err; + } + + return FW_CHECK_SUCCESS; +fw_update_check_err: + pr_err("rt5125_fw_data check fail\n"); + return FW_CHECK_FAIL; +} + +static int rt5125_fw_update(struct fastchg_device_info *chip) +{ + const u8 *data = dashchg_firmware_data; + s32 len = chip->dashchg_fw_ver_count; + u8 rwdata = 0, status, fwdata[DEFAULT_MAX_PAGELEN]; + s32 elapsed, wr_len; + u32 fw_info; + int i, idx, retry, ret; + + /* poly = x^8 + x^2 + x^1 + 1 */ + crc8_populate_msb(crc8_table, 0x7); + + ret = rt5125_i2c_block_read(chip, RT5125_MTP_INFO_0, + &status, sizeof(status)); + pr_err("MTP status=0x%02x", status); + /* wirte every single page */ + for (i = 0; i < len ; i += DEFAULT_MAX_PAGELEN) { + idx = i / DEFAULT_MAX_PAGELEN; + elapsed = len - i; + wr_len = (elapsed > DEFAULT_MAX_PAGELEN) + ? DEFAULT_MAX_PAGELEN : elapsed; + memset(fwdata, 0xff, DEFAULT_MAX_PAGELEN); + memcpy(fwdata, data + i, wr_len); + /* page idx */ + rwdata = (u8)idx; + ret = rt5125_i2c_block_write(chip, RT5125_PAGE_IDX, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] wrpage idx fail, ret=%d\n", idx, ret); + goto update_fw_err; + } + + /* page data */ + ret = rt5125_i2c_block_write(chip, RT5125_DATA_BUF, + fwdata, DEFAULT_MAX_PAGELEN); + if (ret < 0) { + pr_err("[%d] wrpage data fail\n", idx); + goto update_fw_err; + } + + /* access to write page from buffer to mtp */ + rwdata = (u8)RT5125_WT_PAGE; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] wrpage access fail\n", idx); + goto update_fw_err; + } + + /* wait 128ms for mtp write */ + msleep(128); + retry = 0; + +busy_check: + if (retry++ > DEFAULT_PAGEWR_RETRY) { + pr_err("[%d] wrpage over retrycnt\n", idx); + goto update_fw_err; + } + + msleep(5); + /* check page wr status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("[%d] read status fail\n", idx); + goto update_fw_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("[%d] wrpage fail 0x%02x\n", idx, status); + goto update_fw_err; + } else if (status == RT5125_OPSTATUS_ONGOING) { + pr_err("[%d] wrpage ongoing\n", idx); + goto busy_check; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("[%d] wrpage success\n", idx); + } else { + pr_err("[%d] wrpage unknown 0x%02x\n", idx, status); + goto update_fw_err; + } + } + + /* FWINFO[31:16] = CRC16_H:CRC16_L */ + fw_info = crc16(RT5125_CRC16_INIT, data, len) << 16; + /* FWINFO[15:0] = FWSIZE_H:FWSIZE_L */ + fw_info |= (u16)len; + ret = rt5125_i2c_block_write(chip, RT5125_FW_CRC16_INFO, + (void *)&fw_info, sizeof(fw_info)); + if (ret < 0) { + pr_err("write fw info fail\n"); + goto update_fw_err; + } + + /* write access for crc16 write */ + rwdata = (u8)RT5125_WT_FW_CRC16;; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("wr_fw_crc access fail\n"); + goto update_fw_err; + } + + /* wait 20ms for CRC write */ + msleep(20); + + /* check wr_fw_crc status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("wr_fw_crc read status fail\n"); + goto update_fw_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("wr_fw_crc status fail\n"); + goto update_fw_err; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("wr_fw_crc success\n"); + } else { + pr_err("wr_fw_crc unknown 0x%02x\n", status); + goto update_fw_err; + } + + + /* write access for crc16 verify */ + rwdata = (u8)RT5125_FW_CRC16_VRFY;; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("fw_crc_vrfy access fail\n"); + goto update_fw_err; + } + + /* wait 200ms for CRC verify */ + msleep(200); + + /* check fw_crc_vrfy status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("fw_crc_vrfy read status fail\n"); + goto update_fw_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("fw_crc_vrfy status fail\n"); + goto update_fw_err; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("fw_crc_vrfy success\n"); + } else { + pr_err("fw_crc_vrfy unknown 0x%02x\n", status); + goto update_fw_err; + } + + if (!(rwdata & RT5125_FW_CRC16_RSLT)) { + pr_err("fw_crc_vrfy crc result fail\n"); + goto update_fw_err; + } + pr_info("fw_crc_vrfy OK\n"); + + /* write access for keyword */ + rwdata = (u8)RT5125_WT_KEY; + ret = rt5125_i2c_block_write(chip, RT5125_ACCESS_CTL, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("key_write access fail\n"); + goto update_fw_err; + } + + /* wait keyword write success */ + msleep(10); + + /* check keyword write status */ + ret = rt5125_i2c_block_read(chip, RT5125_STATUS, + &rwdata, sizeof(rwdata)); + if (ret < 0) { + pr_err("key_write read status fail\n"); + goto update_fw_err; + } + status = rwdata & RT5125_OPSTATUS_MASK; + if (status & RT5125_OPSTATUS_FAILMSK) { + pr_err("key_write status fail\n"); + goto update_fw_err; + } else if (status == RT5125_OPSTATUS_SUCCESS) { + pr_err("key_write success\n"); + } else { + pr_err("key_write unknown 0x%02x\n", status); + goto update_fw_err; + } + + pr_info("success\n"); + return 0; +update_fw_err: + pr_err("fail\n"); + return 1; +} +#endif + +static irqreturn_t irq_rx_handler(int irq, void *dev_id); +static void reset_mcu_and_request_irq(struct fastchg_device_info *di) +{ + int ret; + + pr_info("\n"); + gpio_direction_output(di->ap_clk, 1); + usleep_range(10000, 10001); + if (di->is_swarp_supported) { + (void)opchg_mcu_action(ACTION_MODE_RESET_ACTIVE); + } else { + gpio_direction_output(di->mcu_en_gpio, 1); + usleep_range(10000, 10001); + gpio_direction_output(di->mcu_en_gpio, 0); + usleep_range(5000, 5001); + } + opchg_set_mcu_data_read(di); + di->irq = gpio_to_irq(di->ap_data); + + /* 0x01:rising edge, 0x02:falling edge */ + ret = request_irq(di->irq, irq_rx_handler, + IRQF_TRIGGER_RISING, "mcu_data", di); + if (ret < 0) + pr_err("request ap rx irq failed.\n"); + else + di->irq_enabled = true; + irq_set_status_flags(di->irq, IRQ_DISABLE_UNLAZY); +} + + +static void dashchg_fw_update(struct work_struct *work) +{ + unsigned char zero_buf[1] = {0}; + unsigned char addr_buf[2] = {0x88, 0x00}; + unsigned char temp_buf[1] = {0}; + u8 value_buf[2] = {0}; + int i, rc = 0; + unsigned int addr; + int download_again = 0; + int fw_check_err = 0; + struct fastchg_device_info *di = container_of(work, + struct fastchg_device_info, + update_firmware.work); + + addr_buf[0] = fastchg_di->addr_low; + addr_buf[1] = fastchg_di->addr_high; + addr = (addr_buf[0] << 8) + (addr_buf[1] & 0xFF); + __pm_stay_awake(di->fastchg_update_fireware_lock); + if (di->n76e_present) { + rc = n76e_fw_check(di); +#ifdef OP_SWARP_SUPPORTED + } else if (di->is_swarp_supported) { + (void)opchg_mcu_action(ACTION_MODE_SWITCH_UPGRADE); + if (di->asic_hw_id == ROCKCHIP_RK826) { + rc = rk826_fw_check(di); + } else if (di->asic_hw_id == RICHTEK_RT5125) { + rc = rt5125_fw_check(di); + } +#endif + } else { + rc = dashchg_fw_check(); + } + if (rc == FW_CHECK_SUCCESS) { + di->firmware_already_updated = true; + reset_mcu_and_request_irq(di); +#ifdef OP_SWARP_SUPPORTED + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); +#endif + __pm_relax(di->fastchg_update_fireware_lock); + set_property_on_smbcharger(POWER_SUPPLY_PROP_SWITCH_DASH, true); + di->dash_firmware_ok = 1; + pr_info("FW check success\n"); /* david@bsp add log */ + return; + } +#ifdef OP_SWARP_SUPPORTED +update_asic_fw: + if (di->is_swarp_supported) { + if (di->asic_hw_id == ROCKCHIP_RK826) { + if (!download_again && !fw_check_err + && di->fw_ver_not_match) { + // erase mtp. + rk826_erase_fw_by_byte(di, 0x00); + msleep(10); + rk826_erase_fw_by_byte(di, 0xff); + msleep(10); + rk826_erase_fw_by_byte(di, 0x00); + msleep(10); + } + rc = rk826_fw_write(di, dashchg_firmware_data, 0, di->dashchg_fw_ver_count); + } else if (di->asic_hw_id == RICHTEK_RT5125) { + rc = rt5125_fw_update(di); + } + if (rc) { + download_again++; + if (download_again > 3) + goto update_fw_err; + (void)opchg_mcu_action(ACTION_MODE_SWITCH_UPGRADE); + msleep(1000); + pr_err("fw download fail, download fw again\n"); + goto update_asic_fw; + } else { + if (di->asic_hw_id == ROCKCHIP_RK826) { + usleep_range(100000, 100001); + rc = oneplus_u16_i2c_read(di->client, 0x52f8, 2, value_buf); + if (rc < 0) { + pr_err("rk826 read register 0x52f8 fail, rc = %d\n", rc); + pr_info("rk826 fw upgrade check ok."); + } else { + pr_info("read 0x52f8 success 0x%x", value_buf[0] | (value_buf[1] << 8)); + fw_check_err++; + if (fw_check_err > 3) + goto update_fw_err; + (void)opchg_mcu_action(ACTION_MODE_SWITCH_UPGRADE); + msleep(1000); + pr_err("fw download fail(time:%d), download fw again\n", fw_check_err); + goto update_asic_fw; + } + } + } + goto update_done; + } +#endif + pr_info("start erasing data.......\n"); +update_fw: + /* erase address 0x200-0x7FF */ + for (i = 0; i < di->erase_count; i++) { + /* first:set address */ + rc = oneplus_dash_i2c_write(mcu_client, 0x01, 2, &addr_buf[0]); + if (rc < 0) { + pr_err("dashchg_update_fw, i2c_write 0x01 error\n"); + goto update_fw_err; + } + + /* erase data:0x10 words once */ + if (!di->n76e_present) + oneplus_dash_i2c_write(mcu_client, + 0x04, 1, &zero_buf[0]); + usleep_range(1000, 1001); + oneplus_dash_i2c_read(mcu_client, 0x04, 1, &temp_buf[0]); + if (di->n76e_present) + usleep_range(7000, 7100); + /* erase data:0x10 words once */ + addr = addr + 0x10; + addr_buf[0] = addr >> 8; + addr_buf[1] = addr & 0xFF; + } + usleep_range(10000, 10001); + dashchg_fw_write(dashchg_firmware_data, 0, di->dashchg_fw_ver_count); + + /* fw check begin:read data from mcu and compare*/ + /*it with dashchg_firmware_data[] */ + if (di->n76e_present) + rc = n76e_fw_check(di); + else + rc = dashchg_fw_check(); + if (rc == FW_CHECK_FAIL) { + download_again++; + if (download_again > 3) + goto update_fw_err; + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_ACTIVE); + else + mcu_en_gpio_set(0); + msleep(1000); + pr_err("fw check fail, download fw again\n"); + goto update_fw; + } + /* fw check end */ + + usleep_range(2000, 2001); + /* jump to app code begin */ + oneplus_dash_i2c_write(mcu_client, 0x06, 1, &zero_buf[0]); + oneplus_dash_i2c_read(mcu_client, 0x06, 1, &temp_buf[0]); + /* jump to app code end */ +#ifdef OP_SWARP_SUPPORTED +update_done: +#endif + di->firmware_already_updated = true; + reset_mcu_and_request_irq(di); +#ifdef OP_SWARP_SUPPORTED + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); +#endif + __pm_relax(di->fastchg_update_fireware_lock); + set_property_on_smbcharger(POWER_SUPPLY_PROP_SWITCH_DASH, true); + di->dash_firmware_ok = 1; + pr_info("result=success\n"); + return; + +update_fw_err: + di->firmware_already_updated = true; + reset_mcu_and_request_irq(di); +#ifdef OP_SWARP_SUPPORTED + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); +#endif + __pm_relax(di->fastchg_update_fireware_lock); + set_property_on_smbcharger(POWER_SUPPLY_PROP_SWITCH_DASH, true); + pr_err("result=fail\n"); +} + +static struct external_battery_gauge *bq27541_data; +void bq27541_information_register( + struct external_battery_gauge *fast_chg) +{ + if (bq27541_data) { + bq27541_data = fast_chg; + pr_err("multiple battery gauge called\n"); + } else { + bq27541_data = fast_chg; + } +} +EXPORT_SYMBOL(bq27541_information_register); + +void bq27541_information_unregister(struct external_battery_gauge *batt_gauge) +{ + bq27541_data = NULL; +} + +static bool bq27541_fast_chg_started(void) +{ + if (fastchg_di) + return fastchg_di->fast_chg_started; + + return false; +} + +static bool get_fastchg_status(void) +{ + if (fastchg_di) + return !fastchg_di->fast_chg_error; + return true; +} + +static bool bq27541_get_fast_low_temp_full(void) +{ + if (fastchg_di) + return fastchg_di->fast_low_temp_full; + + return false; +} + +static int bq27541_set_fast_chg_allow(bool enable) +{ + if (fastchg_di) + fastchg_di->fast_chg_allow = enable; + + return 0; +} + +static void clean_status(void) +{ + if (fastchg_di) { + fastchg_di->dash_enhance = 0; + fastchg_di->sid = 0; +#ifdef OP_SWARP_SUPPORTED + oneplus_notify_dash_charger_type(CHARGER_DEFAULT); +#endif + oneplus_notify_adapter_sid(fastchg_di->sid); + schedule_delayed_work(&fastchg_di->disable_mcu_work, + msecs_to_jiffies(2000)); + fastchg_di->fast_chg_started = false; + fastchg_di->fast_chg_ing = false; + msm_cpuidle_set_sleep_disable(false); + } +} +static void disable_mcu_work_func(struct work_struct *work) +{ + if (!is_usb_pluged() && fastchg_di->is_swarp_supported + && fastchg_di->firmware_already_updated) { + pr_err("usb unpluged, disable mcu."); + if (fastchg_di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + else + set_mcu_active(0); + } +} + +#ifdef OP_SWARP_SUPPORTED +static int dash_get_fastchg_warm(void) +{ + if (fastchg_di) + return fastchg_di->fast_normal_to_warm ? 1 : 0; + + return 0; +} +#endif +static bool bq27541_get_fast_chg_allow(void) +{ + if (fastchg_di) + return fastchg_di->fast_chg_allow; + + return false; +} + +static bool bq27541_fast_switch_to_normal(void) +{ + if (fastchg_di) + return fastchg_di->fast_switch_to_normal; + + return false; +} + +static bool bq27541_get_fast_chg_ing(void) +{ + if (fastchg_di) + return fastchg_di->fast_chg_ing; + + return false; +} + + +static int bq27541_set_switch_to_noraml_false(void) +{ + if (fastchg_di) + fastchg_di->fast_switch_to_normal = false; + + return 0; +} + +static bool get_fastchg_firmware_already_updated(void) +{ + if (fastchg_di) + return fastchg_di->firmware_already_updated; + + return false; +} + +static bool fastchg_is_usb_switch_on(void) +{ + if (fastchg_di) { + if (gpio_is_valid(fastchg_di->usb_on_gpio)) + return gpio_get_value(fastchg_di->usb_on_gpio); + else + return gpio_get_value(fastchg_di->usb_sw_1_gpio); + } + + return false; +} + +static bool enhance_dash_on(void) +{ + if (fastchg_di) + return fastchg_di->dash_enhance; + + return false; +} + +void enhance_dash_type_set(int type) +{ + if (fastchg_di) { + if (type >= 0 && type <= 6) + fastchg_di->dash_enhance = type; + pr_info("set dash enhance %d.", type); + } +} + +int dash_get_adapter_update_status(void) +{ + if (!fastchg_di) + return ADAPTER_FW_UPDATE_NONE; + else + return fastchg_di->adapter_update_report; +} +static struct external_battery_gauge fastcharge_information = { + .fast_chg_status_is_ok = + get_fastchg_status, + .fast_chg_started = + bq27541_fast_chg_started, + .get_fast_low_temp_full = + bq27541_get_fast_low_temp_full, + .fast_switch_to_normal = + bq27541_fast_switch_to_normal, + .get_fast_chg_ing = + bq27541_get_fast_chg_ing, + .set_fast_chg_allow = + bq27541_set_fast_chg_allow, + .get_fast_chg_allow = + bq27541_get_fast_chg_allow, + .set_switch_to_noraml_false = + bq27541_set_switch_to_noraml_false, + .get_fastchg_firmware_already_updated = + get_fastchg_firmware_already_updated, + .is_usb_switch_on = fastchg_is_usb_switch_on, + .get_adapter_update = dash_get_adapter_update_status, + .is_enhance_dash = enhance_dash_on, + .clean = clean_status, + .fast_normal_to_warm = dash_get_fastchg_warm, +}; + +static struct notify_dash_event *notify_event; + +void notify_dash_unplug_register(struct notify_dash_event *event) +{ + if (notify_event) { + notify_event = event; + pr_err("multiple battery gauge called\n"); + } else { + notify_event = event; + } +} +EXPORT_SYMBOL(notify_dash_unplug_register); + +void notify_dash_unplug_unregister(struct notify_dash_event *notify_event) +{ + notify_event = NULL; +} +EXPORT_SYMBOL(notify_dash_unplug_unregister); + +static void mcu_init(struct fastchg_device_info *di) +{ + gpio_direction_output(di->ap_clk, 0); + if (di->is_swarp_supported) { + (void)opchg_mcu_action(ACTION_MODE_RESET_ACTIVE); + } else { + usleep_range(1000, 1001); + gpio_direction_output(di->mcu_en_gpio, 1); + usleep_range(1000, 1001); + gpio_direction_output(di->mcu_en_gpio, 0); + } +} + +static irqreturn_t irq_rx_handler(int irq, void *dev_id) +{ + struct fastchg_device_info *di = dev_id; + + pr_debug("triggered\n"); + schedule_work(&di->fastcg_work); + return IRQ_HANDLED; +} + +static void oneplus_notify_dash_charger_present(bool status) +{ + if (notify_event && notify_event->notify_dash_charger_present) + notify_event->notify_dash_charger_present(status); +} + +#ifdef OP_SWARP_SUPPORTED +static void oneplus_notify_dash_charger_type(enum fast_charger_type type) +{ + if (notify_event && notify_event->update_dash_type) + notify_event->update_dash_type(type); +} +#endif + +static void oneplus_notify_adapter_sid(unsigned int sid) +{ + if (notify_event && notify_event->update_adapter_sid) + (void)notify_event->update_adapter_sid(sid); +} + +static void oneplus_notify_pmic_check_charger_present(void) +{ + if (notify_event && notify_event->notify_event) + notify_event->notify_event(); +} + +static void notify_check_usb_suspend(bool status, bool check_power_ok) +{ + if (notify_event && notify_event->op_contrl + && !fastchg_di->is_swarp_supported) + notify_event->op_contrl(status, check_power_ok); +} + +static void oneplus_notify_suspend_normalchg(bool en) +{ + if (notify_event && notify_event->suspend_disable_nor_charge) + notify_event->suspend_disable_nor_charge(en); +} + +static void update_charger_present_status(struct work_struct *work) +{ + /* switch off fast chg */ + switch_mode_to_normal(); + notify_check_usb_suspend(true, true); + oneplus_notify_dash_charger_present(false); + oneplus_notify_pmic_check_charger_present(); +} + +static int op_get_device_type(void) +{ + if (bq27541_data && bq27541_data->get_device_type) + return bq27541_data->get_device_type(); + else + return 0; +} + +static int onplus_get_battery_mvolts(void) +{ + if (bq27541_data && bq27541_data->get_battery_mvolts) + return bq27541_data->get_battery_mvolts(); + else + return 4010 * 1000; /* retrun 4.01v for default */ +} + +static int onplus_get_battery_temperature(void) +{ + if (bq27541_data && bq27541_data->get_battery_temperature) + return bq27541_data->get_battery_temperature(); + else + return 255; /* retrun 25.5 for default temp */ +} + +static int onplus_get_batt_remaining_capacity(void) +{ + if (bq27541_data && bq27541_data->get_batt_remaining_capacity) + return bq27541_data->get_batt_remaining_capacity(); + else + return 5; /* retrun 5 for default remaining_capacity */ +} + +static int onplus_get_battery_soc(void) +{ + if (bq27541_data && bq27541_data->get_battery_soc) + return bq27541_data->get_battery_soc(); + else + return 50; /* retrun 50 for default soc */ +} + +static int onplus_get_average_current(void) +{ + if (bq27541_data && bq27541_data->get_average_current) + return bq27541_data->get_average_current(); + else + return 666 * 1000; /* retrun 666ma for default current */ +} + +void op_check_charger_collapse_rerun_aicl(void); + +void switch_mode_to_normal(void) +{ + if (fastchg_di->is_swarp_supported) { + (void)opchg_mcu_action(ACTION_MODE_SWITCH_NORMAL); + } else { + usb_sw_gpio_set(0); + mcu_en_gpio_set(1); + op_check_charger_collapse_rerun_aicl(); + } + msm_cpuidle_set_sleep_disable(false); + update_disconnect_pd_status(false); +} + +static void update_fast_chg_started(void) +{ + if (bq27541_data && bq27541_data->fast_chg_started_status) + bq27541_data->fast_chg_started_status( + fastchg_di->fast_chg_started); +} + +static void request_mcu_irq(struct fastchg_device_info *di) +{ + int retval; + + opchg_set_mcu_data_read(di); + gpio_set_value(di->ap_clk, 0); + usleep_range(10000, 10001); + gpio_set_value(di->ap_clk, 1); + if (di->adapter_update_real + != ADAPTER_FW_NEED_UPDATE) { + pr_info("%s\n", __func__); + if (!di->irq_enabled) { + retval = request_irq(di->irq, irq_rx_handler, + IRQF_TRIGGER_RISING, "mcu_data", di); + if (retval < 0) + pr_err("request ap rx irq failed.\n"); + else + di->irq_enabled = true; + irq_set_status_flags(di->irq, IRQ_DISABLE_UNLAZY); + } + } else { + di->irq_enabled = true; + } +} + +static void fastcg_work_func(struct work_struct *work) +{ + struct fastchg_device_info *di = container_of(work, + struct fastchg_device_info, + fastcg_work); + pr_info("\n"); + if (di->irq_enabled) { + free_irq(di->irq, di); + msleep(25); + di->irq_enabled = false; + wake_up(&di->read_wq); + } +} + +static void update_fireware_version_func(struct work_struct *work) +{ + struct fastchg_device_info *di = container_of(work, + struct fastchg_device_info, + update_fireware_version_work.work); + + if (!dashchg_firmware_data || di->dashchg_fw_ver_count == 0) + return; + + snprintf(di->fw_id, 255, "0x%x", + dashchg_firmware_data[di->dashchg_fw_ver_count - 4]); + if (di->is_swarp_supported) + snprintf(di->manu_name, 255, "%s", mcu_id_text[di->asic_hw_id]); + else + snprintf(di->manu_name, 255, "%s", "ONEPLUS"); + push_component_info(FAST_CHARGE, di->fw_id, di->manu_name); +} +void di_watchdog(struct timer_list *t) +{ + struct fastchg_device_info *di = fastchg_di; + + pr_err("di_watchdog can't receive mcu data\n"); + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + di->fast_switch_to_normal = false; + di->fast_low_temp_full = false; + di->fast_chg_allow = false; + di->fast_normal_to_warm = false; + di->fast_chg_ing = false; + di->fast_chg_error = false; + schedule_work(&di->charger_present_status_work); + pr_err("switch off fastchg\n"); + + __pm_relax(di->fastchg_wake_lock); +} + +#define MAX_BUFFER_SIZE 1024 +#define ALLOW_DATA 0x2 +#define REJECT_DATA 0x11 + +#ifndef CONFIG_ARCH_LITO + /* warp */ /* swarp */ +#define CURRENT_LIMIT_1 0x1 /* 3.6A */ /* 2.5A */ +#define CURRENT_LIMIT_2 0x2 /* 2.5A */ /* 2.0A */ +#define CURRENT_LIMIT_3 0x3 /* 3.0A */ /* 3.0A */ +#define CURRENT_LIMIT_4 0x4 /* 4.0A */ /* 4.0A */ +#define CURRENT_LIMIT_5 0x5 /* 5.0A */ /* 5.0A */ +#define CURRENT_LIMIT_6 0x6 /* 6.0A */ /* 6.5A */ +#else +// Current limits as per the dash firwmare using by 4115mA battery in AVICII +#define CURRENT_LIMIT_1 0x1 /* 2A */ +#define CURRENT_LIMIT_2 0x2 /* 2.5A */ +#define CURRENT_LIMIT_3 0x3 /* 3.0A */ +#define CURRENT_LIMIT_4 0x4 /* 4.0A */ +#define CURRENT_LIMIT_5 0x5 /* 5.0A */ +#define CURRENT_LIMIT_6 0x6 /* 6.0A */ +#endif + +/* Legacy write function */ +/* +static void dash_write(struct fastchg_device_info *di, int data) +{ + int i; + int device_type = op_get_device_type(); + + usleep_range(2000, 2001); + gpio_direction_output(di->ap_data, 0); + if (di->pinctrl && + !IS_ERR_OR_NULL(di->pinctrl_mcu_data_state_suspended)) + pinctrl_select_state(di->pinctrl, + di->pinctrl_mcu_data_state_suspended); + for (i = 0; i < 3; i++) { + if (i == 0) + gpio_set_value(di->ap_data, data >> 1); + else if (i == 1) + gpio_set_value(di->ap_data, data & 0x1); + else + gpio_set_value(di->ap_data, device_type); + gpio_set_value(di->ap_clk, 0); + usleep_range(1000, 1001); + gpio_set_value(di->ap_clk, 1); + usleep_range(19000, 19001); + } +} +*/ + +static void dash_write_4bits(struct fastchg_device_info *di, int data) +{ + int i = 0; + int device_type = op_get_device_type(); + + usleep_range(2000, 2001); + opchg_set_mcu_data_write(di); + for (i = 0; i < 4; i++) { + if (i == 0) { + gpio_set_value(di->ap_data, (data & BIT(2)) >> 2); + } else if (i == 1) { + gpio_set_value(di->ap_data, (data & BIT(1)) >> 1); + } else if (i == 2) { + gpio_set_value(di->ap_data, data & BIT(0)); + } else { + gpio_set_value(di->ap_data, device_type); + } + gpio_set_value(di->ap_clk, 0); + usleep_range(1000, 1001); + gpio_set_value(di->ap_clk, 1); + usleep_range(19000, 19001); + } +} + +static int dash_read(struct fastchg_device_info *di) +{ + int i; + int bit = 0; + int data = 0; + + for (i = 0; i < 7; i++) { + gpio_set_value(di->ap_clk, 0); + usleep_range(1000, 1001); + gpio_set_value(di->ap_clk, 1); + usleep_range(19000, 19001); + bit = gpio_get_value(di->ap_data); + data |= bit<<(6-i); + } + pr_err("recv data:0x%x\n", data); + return data; +} + +static int dash_dev_open(struct inode *inode, struct file *filp) +{ + struct fastchg_device_info *dash_dev = container_of(filp->private_data, + struct fastchg_device_info, dash_device); + + filp->private_data = dash_dev; + pr_debug("%d,%d\n", imajor(inode), iminor(inode)); + return 0; +} + +static ssize_t dash_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct fastchg_device_info *di = filp->private_data; + + int data = 0; + int ret = 0; + + mutex_lock(&di->read_mutex); + while (1) { + ret = wait_event_interruptible(di->read_wq, + (!di->irq_enabled)); + if (ret) + goto fail; + if (di->irq_enabled) + pr_err("dash false wakeup,ret=%d\n", ret); + data = dash_read(di); + mutex_unlock(&di->read_mutex); + if (copy_to_user(buf, &data, 1)) { + pr_err("failed to copy to user space\n"); + return -EFAULT; + } + break; + } + return ret; +fail: + mutex_unlock(&di->read_mutex); + return ret; +} +static struct op_adapter_chip *g_adapter_chip; + +static void adapter_update_work_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct fastchg_device_info *chip = + container_of(dwork, + struct fastchg_device_info, adapter_update_work); + bool update_result = false; + int i = 0; + + if (!g_adapter_chip) { + pr_info("%s g_adapter_chip NULL\n", __func__); + return; + } + pr_info("%s begin\n", __func__); + opchg_set_mcu_data_read(chip); + /*pm_qos_update_request(&big_cpu_update_freq, MAX_CPUFREQ);*/ + op_bus_vote(false); + msleep(1000); + for (i = 0; i < 3; i++) { + update_result = + g_adapter_chip->vops->adapter_update(g_adapter_chip, + chip->ap_clk, chip->ap_data); + if (update_result == true) + break; + if (i < 1) + msleep(1650); + } + msleep(5000); + if (update_result) { + chip->adapter_update_real = ADAPTER_FW_UPDATE_SUCCESS; + } else { + chip->adapter_update_real = ADAPTER_FW_UPDATE_FAIL; + chip->adapter_update_report = chip->adapter_update_real; + } + msleep(20); + if (chip->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_ENABLE); + else + mcu_en_gpio_set(1); + chip->fast_chg_started = false; + chip->fast_chg_allow = false; + chip->fast_chg_ing = false; + msleep(1000); + if (update_result) { + msleep(2000); + chip->adapter_update_report = ADAPTER_FW_UPDATE_SUCCESS; + } + notify_check_usb_suspend(true, false); + oneplus_notify_pmic_check_charger_present(); + oneplus_notify_dash_charger_present(false); + reset_mcu_and_request_irq(chip); + + pr_info("%s end update_result:%d\n", + __func__, update_result); + __pm_relax(chip->fastchg_wake_lock); + op_bus_vote(true); + +} + +#ifdef SUPPORT_ADAPTER_FW_UPDATE +static void dash_adapter_update(struct fastchg_device_info *chip) +{ + pr_err("%s\n", __func__); + /*schedule_delayed_work_on(5,*/ + /*&chip->adapter_update_work,*/ + /*round_jiffies_relative(*/ + /*msecs_to_jiffies(ADAPTER_UPDATE_DELAY)));*/ + schedule_delayed_work(&chip->adapter_update_work, + msecs_to_jiffies(ADAPTER_UPDATE_DELAY)); +} +#endif + +void op_adapter_init(struct op_adapter_chip *chip) +{ + g_adapter_chip = chip; +} + +#define DASH_IOC_MAGIC 0xff +#define DASH_NOTIFY_FIRMWARE_UPDATE _IO(DASH_IOC_MAGIC, 1) +#define DASH_NOTIFY_FAST_PRESENT _IOW(DASH_IOC_MAGIC, 2, int) +#define DASH_NOTIFY_FAST_ABSENT _IOW(DASH_IOC_MAGIC, 3, int) +#define DASH_NOTIFY_NORMAL_TEMP_FULL _IOW(DASH_IOC_MAGIC, 4, int) +#define DASH_NOTIFY_LOW_TEMP_FULL _IOW(DASH_IOC_MAGIC, 5, int) +#define DASH_NOTIFY_BAD_CONNECTED _IOW(DASH_IOC_MAGIC, 6, int) +#define DASH_NOTIFY_TEMP_OVER _IOW(DASH_IOC_MAGIC, 7, int) +#define DASH_NOTIFY_ADAPTER_FW_UPDATE _IOW(DASH_IOC_MAGIC, 8, int) +#define DASH_NOTIFY_BTB_TEMP_OVER _IOW(DASH_IOC_MAGIC, 9, int) +#define DASH_NOTIFY_ALLOW_READING_IIC _IOW(DASH_IOC_MAGIC, 10, int) +#define DASH_NOTIFY_UNDEFINED_CMD _IO(DASH_IOC_MAGIC, 11) +#define DASH_NOTIFY_INVALID_DATA_CMD _IO(DASH_IOC_MAGIC, 12) +#define DASH_NOTIFY_REQUEST_IRQ _IO(DASH_IOC_MAGIC, 13) +#define DASH_NOTIFY_UPDATE_DASH_PRESENT _IOW(DASH_IOC_MAGIC, 14, int) +#define DASH_NOTIFY_UPDATE_ADAPTER_INFO _IOW(DASH_IOC_MAGIC, 15, int) +#ifdef OP_SWARP_SUPPORTED +#define DASH_NOTIFY_ADAPTER_NOT_MATCH _IOW(DASH_IOC_MAGIC, 16, int) +#endif +#define DASH_NOTIFY_UPDATE_ADAPTER_SID _IOW(DASH_IOC_MAGIC, 17, int) + +static long dash_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct fastchg_device_info *di = filp->private_data; + int volt = 0; + int temp = 0; + int soc = 0; + int current_now = 0; + int remain_cap = 0; + int need_send_msg = 0; + bool is_skin_temp_high = false; + bool is_skin_temp_warm = false; + bool is_skin_thermal_medium = false; + bool is_call_on = false; + bool is_video_call_on = false; + bool is_lcd_on = false; + int cool_down = 0; + static int lcd_on_msg; + + switch (cmd) { + case DASH_NOTIFY_FIRMWARE_UPDATE: + di->fw_ver_not_match = false; + schedule_delayed_work(&di->update_firmware, + msecs_to_jiffies(2200)); + break; + case DASH_NOTIFY_FAST_PRESENT: + oneplus_notify_dash_charger_present(true); + if (arg == DASH_NOTIFY_FAST_PRESENT + 1) { + __pm_stay_awake(di->fastchg_wake_lock); + bq27541_data->set_allow_reading(false); + di->fast_chg_allow = false; + di->fast_normal_to_warm = false; + di->warp_normal_path_need_config = false; + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(15000)); + } else if (arg == DASH_NOTIFY_FAST_PRESENT + 2) { + pr_err("REJECT_DATA\n"); + dash_write_4bits(di, REJECT_DATA); + di->warp_normal_path_need_config = false; + } else if (arg == DASH_NOTIFY_FAST_PRESENT + 3) { + notify_check_usb_suspend(false, false); + di->fast_chg_error = false; + dash_write_4bits(di, ALLOW_DATA); + di->fast_chg_started = true; + msm_cpuidle_set_sleep_disable(true); + } + break; + case DASH_NOTIFY_FAST_ABSENT: + if (arg == DASH_NOTIFY_FAST_ABSENT + 1) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + di->fast_chg_allow = false; + di->fast_switch_to_normal = false; + di->fast_normal_to_warm = false; + di->fast_chg_ing = false; + di->dash_enhance = 0; + di->sid = 0; +#ifdef OP_SWARP_SUPPORTED + oneplus_notify_dash_charger_type(di->dash_enhance); +#endif + oneplus_notify_adapter_sid(di->sid); + pr_err("fastchg stop unexpectly, switch off fastchg\n"); + switch_mode_to_normal(); + update_fast_switch_off_status(); + del_timer(&di->watchdog); + dash_write_4bits(di, REJECT_DATA); + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + } else if (arg == DASH_NOTIFY_FAST_ABSENT + 2) { + notify_check_usb_suspend(true, true); + oneplus_notify_dash_charger_present(false); + oneplus_notify_pmic_check_charger_present(); + __pm_relax(di->fastchg_wake_lock); + } + break; + case DASH_NOTIFY_ALLOW_READING_IIC: + if (arg == DASH_NOTIFY_ALLOW_READING_IIC + 1) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = true; + di->fast_chg_ing = true; + volt = onplus_get_battery_mvolts(); + temp = onplus_get_battery_temperature(); + remain_cap = + onplus_get_batt_remaining_capacity(); + soc = onplus_get_battery_soc(); + current_now = onplus_get_average_current(); + pr_err("volt:%d,temp:%d,remain_cap:%d,soc:%d,current:%d\n", + volt, temp, remain_cap, soc, current_now); + if (!di->batt_psy) + di->batt_psy = + power_supply_get_by_name("battery"); + if (di->batt_psy) + power_supply_changed(di->batt_psy); + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(15000)); + if (di->is_swarp_supported) { + oneplus_notify_suspend_normalchg(true); + } + bq27541_data->set_allow_reading(false); + + cool_down = op_get_cool_down_value(); + if (cool_down < 0) { + is_skin_thermal_medium = check_skin_thermal_medium(); + is_skin_temp_warm = check_skin_thermal_warm(); + is_skin_temp_high = check_skin_thermal_high(); + is_call_on = check_call_on_status(); + is_video_call_on = check_video_call_on_status(); + is_lcd_on = check_lcd_on_status(); + + if (is_call_on || is_video_call_on) + lcd_on_msg = CURRENT_LIMIT_2; + else { + if (is_skin_temp_high) + lcd_on_msg = is_lcd_on ? di->skin_hi_curr_max : di->skin_hi_lcdoff_curr_max; + else if (is_skin_temp_warm) + lcd_on_msg = is_lcd_on ? di->skin_wrm_curr_max : CURRENT_LIMIT_6; + else if (is_skin_thermal_medium) + lcd_on_msg = is_lcd_on ? di->skin_med_curr_max: di->skin_med_lcdoff_curr_max; + else + lcd_on_msg = CURRENT_LIMIT_6; + } + } else if (cool_down >= CURRENT_LIMIT_1 + && cool_down <= CURRENT_LIMIT_6) { + lcd_on_msg = cool_down; + } else + lcd_on_msg = CURRENT_LIMIT_6; + + if (!di->is_swarp_supported) + dash_write_4bits(di, lcd_on_msg); +#ifdef OP_SWARP_SUPPORTED + } else if (di->is_swarp_supported) { + need_send_msg = arg & 0xff; + if (need_send_msg < CURRENT_LIMIT_1 || need_send_msg > CURRENT_LIMIT_6) { + pr_err("dashd give an invalid msg(0x%02x).", need_send_msg); + need_send_msg = CURRENT_LIMIT_6; + } + need_send_msg = need_send_msg <= lcd_on_msg ? need_send_msg : lcd_on_msg; + pr_info("send msg(0x%02x) to asic.", need_send_msg); + dash_write_4bits(di, need_send_msg); + lcd_on_msg = CURRENT_LIMIT_6; // reset lcd_on_msg +#endif + } + break; + case DASH_NOTIFY_BTB_TEMP_OVER: + if (di->fast_chg_ing) + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(15000)); + dash_write_4bits(di, ALLOW_DATA); + break; + case DASH_NOTIFY_UPDATE_ADAPTER_INFO: + if (is_usb_pluged()) { + di->dash_enhance = arg; +#ifdef OP_SWARP_SUPPORTED + oneplus_notify_dash_charger_type(di->dash_enhance); +#endif + } + if (!di->batt_psy) + di->batt_psy = + power_supply_get_by_name("battery"); + if (di->batt_psy) + power_supply_changed(di->batt_psy); + break; + case DASH_NOTIFY_UPDATE_ADAPTER_SID: + if (is_usb_pluged()) + di->sid = arg; + else + di->sid = 0; + oneplus_notify_adapter_sid(di->sid); + if (!di->batt_psy) + di->batt_psy = + power_supply_get_by_name("battery"); + if (di->batt_psy) + power_supply_changed(di->batt_psy); + break; + case DASH_NOTIFY_BAD_CONNECTED: + case DASH_NOTIFY_NORMAL_TEMP_FULL: + if (arg == DASH_NOTIFY_NORMAL_TEMP_FULL + 1) { + pr_err("fastchg full, switch off fastchg, set usb_sw_gpio 0\n"); + di->fast_switch_to_normal = true; + switch_mode_to_normal(); + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + del_timer(&di->watchdog); + } else if (arg == DASH_NOTIFY_NORMAL_TEMP_FULL + 2) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + di->fast_chg_allow = false; + di->fast_chg_ing = false; + di->fast_chg_error = false; + notify_check_usb_suspend(true, false); + oneplus_notify_pmic_check_charger_present(); + __pm_relax(di->fastchg_wake_lock); + } else if (arg == DASH_NOTIFY_NORMAL_TEMP_FULL + 3) { + op_switch_normal_set(); + } + break; + case DASH_NOTIFY_TEMP_OVER: + if (arg == DASH_NOTIFY_TEMP_OVER + 1) { + pr_err("fastchg temp over\n"); + switch_mode_to_normal(); + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + del_timer(&di->watchdog); + } else if (arg == DASH_NOTIFY_TEMP_OVER + 2) { + di->fast_normal_to_warm = true; + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + di->fast_chg_allow = false; + di->fast_chg_ing = false; + di->fast_chg_error = true; + notify_check_usb_suspend(true, false); + oneplus_notify_pmic_check_charger_present(); + oneplus_notify_dash_charger_present(false); + if (di->is_swarp_supported) + op_pd_config_switch_normal(); + __pm_relax(di->fastchg_wake_lock); + } + break; + case DASH_NOTIFY_ADAPTER_FW_UPDATE: + if (arg == DASH_NOTIFY_ADAPTER_FW_UPDATE + 1) { +#ifdef SUPPORT_ADAPTER_FW_UPDATE + di->adapter_update_real + = ADAPTER_FW_NEED_UPDATE; + di->adapter_update_report + = di->adapter_update_real; +#else + di->adapter_update_real + = ADAPTER_FW_UPDATE_NONE; + di->adapter_update_report + = di->adapter_update_real; +#endif + } else if (arg == DASH_NOTIFY_ADAPTER_FW_UPDATE + 2) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; +#ifdef SUPPORT_ADAPTER_FW_UPDATE + oneplus_notify_dash_charger_present(true); + dash_write_4bits(di, ALLOW_DATA); + __pm_stay_awake(di->fastchg_wake_lock); + dash_adapter_update(di); +#else + dash_write_4bits(di, 0x01); + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(25000)); +#endif + } + break; + case DASH_NOTIFY_UNDEFINED_CMD: + if (di->fast_chg_started) { + pr_err("UNDEFINED_CMD, switch off fastchg\n"); + switch_mode_to_normal(); + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + msleep(500); /* avoid i2c conflict */ + /* data err */ + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + __pm_relax(di->fastchg_wake_lock); + di->fast_chg_allow = false; + di->fast_switch_to_normal = false; + di->fast_normal_to_warm = false; + di->fast_chg_ing = false; + di->fast_chg_error = true; + notify_check_usb_suspend(true, false); + } + break; + case DASH_NOTIFY_INVALID_DATA_CMD: + if (di->fast_chg_started) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + di->fast_chg_allow = false; + di->fast_switch_to_normal = false; + di->fast_normal_to_warm = false; + di->fast_chg_ing = false; + di->fast_chg_error = true; + pr_err("DASH_NOTIFY_INVALID_DATA_CMD, switch off fastchg\n"); + switch_mode_to_normal(); + if (di->is_swarp_supported) + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + del_timer(&di->watchdog); + __pm_relax(di->fastchg_wake_lock); + notify_check_usb_suspend(true, true); + oneplus_notify_pmic_check_charger_present(); + } + break; + case DASH_NOTIFY_REQUEST_IRQ: + request_mcu_irq(di); + break; + case DASH_NOTIFY_UPDATE_DASH_PRESENT: + if (arg == DASH_NOTIFY_UPDATE_DASH_PRESENT+1) + update_fast_chg_started(); + break; +#ifdef OP_SWARP_SUPPORTED + case DASH_NOTIFY_ADAPTER_NOT_MATCH: + if (arg == DASH_NOTIFY_ADAPTER_NOT_MATCH + 1) { + // not allow switch to dash again. + di->fast_chg_allow = false; + di->fast_switch_to_normal = true; + bq27541_data->set_allow_reading(true); + di->warp_normal_path_need_config = true; + di->fast_chg_started = false; + } else if (arg == DASH_NOTIFY_ADAPTER_NOT_MATCH + 2) { + volt = onplus_get_battery_mvolts(); + temp = onplus_get_battery_temperature(); + remain_cap = + onplus_get_batt_remaining_capacity(); + soc = onplus_get_battery_soc(); + current_now = onplus_get_average_current(); + pr_err("volt:%d,temp:%d,remain_cap:%d,soc:%d,current:%d\n", + volt, temp, remain_cap, soc, current_now); + if (!di->batt_psy) + di->batt_psy = + power_supply_get_by_name("battery"); + if (di->batt_psy) + power_supply_changed(di->batt_psy); + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(15000)); + dash_write_4bits(di, ALLOW_DATA); + if (di->warp_normal_path_need_config) { + op_warp_config_for_swarp(); + di->warp_normal_path_need_config = false; + } + } else if (arg == DASH_NOTIFY_ADAPTER_NOT_MATCH + 3) { + if (is_usb_pluged()) + fastchg_di->fast_chg_started = true; + di->warp_normal_path_need_config = false; + dash_write_4bits(di, 0x01); + switch_mode_to_normal(); + del_timer(&di->watchdog); + } else if (arg == DASH_NOTIFY_ADAPTER_NOT_MATCH + 4) { + fastchg_di->fast_chg_started = false; + __pm_relax(di->fastchg_wake_lock); + } + break; +#endif + default: + pr_err("bad ioctl %u\n", cmd); + } + return 0; +} + +static ssize_t dash_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct fastchg_device_info *di = filp->private_data; + + /*malloc for firmware, do not free*/ + if (di->firmware_already_updated) + return 0; + + dashchg_firmware_data = kmalloc(count, GFP_ATOMIC); + di->dashchg_fw_ver_count = count; + if (copy_from_user(dashchg_firmware_data, buf, count)) { + pr_err("failed to copy from user space\n"); + kfree(dashchg_firmware_data); + return -EFAULT; + } + schedule_delayed_work(&di->update_fireware_version_work, + msecs_to_jiffies(SHOW_FW_VERSION_DELAY_MS)); + pr_info("fw_ver_count=%d\n", di->dashchg_fw_ver_count); + return count; +} + +static const struct file_operations dash_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = dash_dev_write, + .read = dash_dev_read, + .open = dash_dev_open, + .unlocked_ioctl = dash_dev_ioctl, +}; + +static int dash_parse_dt(struct fastchg_device_info *di) +{ + u32 flags; + int rc; + struct device_node *dev_node = di->client->dev.of_node; + + if (!dev_node) { + pr_err("device tree info. missing\n"); + return -EINVAL; + } + + di->usb_sw_1_gpio = of_get_named_gpio_flags(dev_node, + "microchip,usb-sw-1-gpio", 0, &flags); + di->usb_sw_2_gpio = of_get_named_gpio_flags(dev_node, + "microchip,usb-sw-2-gpio", 0, &flags); + di->usb_on_gpio = of_get_named_gpio_flags(dev_node, + "microchip,usb-on", 0, &flags); + di->usb_on_gpio_1 = of_get_named_gpio_flags(dev_node, + "microchip,usb-on_46", 0, &flags); + di->ap_clk = of_get_named_gpio_flags(dev_node, + "microchip,ap-clk", 0, &flags); + di->ap_data = of_get_named_gpio_flags(dev_node, + "microchip,ap-data", 0, &flags); + di->mcu_en_gpio = of_get_named_gpio_flags(dev_node, + "microchip,mcu-en-gpio", 0, &flags); + di->n76e_present = of_property_read_bool(dev_node, + "op,n76e_support"); + di->is_mcl_verion = of_property_read_bool(dev_node, + "op,mcl_verion"); +#ifdef OP_SWARP_SUPPORTED + di->is_swarp_supported = of_property_read_bool(dev_node, + "op,swarp_supported"); +#endif + di->is_4115mAh_4p45_support = of_property_read_bool(dev_node, + "op,4115mAh_4p45_support"); + di->is_4300mAh_4p45_support = of_property_read_bool(dev_node, + "op,4300mAh_4p45_support"); + di->is_4320mAh_4p45_support = of_property_read_bool(dev_node, + "op,4320mAh_4p45_support"); + di->is_4510mAh_4p45_support = of_property_read_bool(dev_node, + "op,4510mAh_4p45_support"); + rc = of_property_read_u32(dev_node, + "op,fw-erase-count", &di->erase_count); + if (rc < 0) + di->erase_count = 384; + rc = of_property_read_u32(dev_node, + "op,fw-addr-low", &di->addr_low); + if (rc < 0) + di->addr_low = 0x88; + rc = of_property_read_u32(dev_node, + "op,fw-addr-high", &di->addr_high); + if (rc < 0) + di->addr_high = 0; + return 0; +} + +static int request_dash_gpios(struct fastchg_device_info *di) +{ + int ret; + + if (gpio_is_valid(di->usb_sw_1_gpio) + && gpio_is_valid(di->usb_sw_2_gpio)) { + ret = gpio_request(di->usb_sw_1_gpio, "usb_sw_1_gpio"); + if (ret) { + pr_err("gpio_request failed for %d ret=%d\n", + di->usb_sw_1_gpio, ret); + return -EINVAL; + } + gpio_direction_output(di->usb_sw_1_gpio, 0); + + ret = gpio_request(di->usb_sw_2_gpio, "usb_sw_2_gpio"); + if (ret) { + pr_err("gpio_request failed for %d ret=%d\n", + di->usb_sw_2_gpio, ret); + return -EINVAL; + } + gpio_direction_output(di->usb_sw_2_gpio, 0); + } else + return -EINVAL; + + if (gpio_is_valid(di->usb_on_gpio)) { + ret = gpio_request(di->usb_on_gpio, "usb_on_gpio"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + di->usb_on_gpio, ret); + gpio_direction_output(di->usb_on_gpio, 0); + } + + di->dpdm_mode = DPDM_MODE_NORMAL; + + if (gpio_is_valid(di->usb_on_gpio_1)) { + ret = gpio_request(di->usb_on_gpio_1, "usb_on_gpio"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + di->usb_on_gpio_1, ret); + gpio_direction_output(di->usb_on_gpio_1, 0); + } + + if (gpio_is_valid(di->ap_clk)) { + ret = gpio_request(di->ap_clk, "ap_clk"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + di->ap_clk, ret); + } + + if (gpio_is_valid(di->mcu_en_gpio)) { + ret = gpio_request(di->mcu_en_gpio, "mcu_en_gpio"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + di->mcu_en_gpio, ret); + else { + gpio_direction_output(di->mcu_en_gpio, 0); + } + } + + if (gpio_is_valid(di->ap_data)) { + ret = gpio_request(di->ap_data, "mcu_data"); + if (ret) + pr_err("gpio_request failed for %d ret=%d\n", + di->ap_data, ret); + } + + return 0; +} + +static int dash_pinctrl_init(struct fastchg_device_info *di) +{ + di->pinctrl = devm_pinctrl_get(&di->client->dev); + if (IS_ERR_OR_NULL(di->pinctrl)) { + dev_err(&di->client->dev, + "Unable to acquire pinctrl\n"); + di->pinctrl = NULL; + return 0; + } else { + di->pinctrl_state_active = + pinctrl_lookup_state(di->pinctrl, "mux_fastchg_active"); + if (IS_ERR_OR_NULL(di->pinctrl_state_active)) { + dev_err(&di->client->dev, + "Can not fastchg_active state\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_state_active); + } + di->pinctrl_state_suspended = + pinctrl_lookup_state(di->pinctrl, + "mux_fastchg_suspend"); + if (IS_ERR_OR_NULL(di->pinctrl_state_suspended)) { + dev_err(&di->client->dev, + "Can not fastchg_suspend state\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_state_suspended); + } + + di->pinctrl_mcu_data_read = + pinctrl_lookup_state(di->pinctrl, + "mcu_data_read"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_data_read)) { + dev_err(&di->client->dev, + "Can not mcu_data_read state\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_mcu_data_read); + } + di->pinctrl_mcu_data_write = + pinctrl_lookup_state(di->pinctrl, + "mcu_data_write"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_data_write)) { + dev_err(&di->client->dev, + "Can not fastchg_suspend state\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_mcu_data_write); + } +#ifdef OP_SWARP_SUPPORTED + if (di->is_swarp_supported) { + di->pinctrl_mcu_id_hiz = + pinctrl_lookup_state(di->pinctrl, "mcu_id_hiz"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_id_hiz)) { + dev_err(&di->client->dev, + "Can not mcu_id_hiz\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_mcu_id_hiz); + } + di->pinctrl_mcu_id_pull_up = + pinctrl_lookup_state(di->pinctrl, "mcu_id_pull_up"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_id_pull_up)) { + dev_err(&di->client->dev, + "Can not mcu_id_pull_up\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_mcu_id_pull_up); + } + di->pinctrl_mcu_id_pull_down = + pinctrl_lookup_state(di->pinctrl, "mcu_id_pull_down"); + if (IS_ERR_OR_NULL(di->pinctrl_mcu_id_pull_down)) { + dev_err(&di->client->dev, + "Can not mcu_id_pull_down\n"); + devm_pinctrl_put(di->pinctrl); + di->pinctrl = NULL; + return PTR_ERR(di->pinctrl_mcu_id_pull_down); + } + } + } +#endif + if (pinctrl_select_state(di->pinctrl, + di->pinctrl_state_active) < 0) + pr_err("pinctrl set active fail\n"); + + if (pinctrl_select_state(di->pinctrl, + di->pinctrl_mcu_data_read) < 0) + pr_err("pinctrl set pinctrl_mcu_data_read fail\n"); +#ifdef OP_SWARP_SUPPORTED + if (di->is_swarp_supported && pinctrl_select_state(di->pinctrl, + di->pinctrl_mcu_id_hiz) < 0) + pr_err("pinctrl set mcu_id_hiz fail\n"); +#endif + return 0; + +} + +static void check_n76e_support(struct fastchg_device_info *di) +{ + if (di->n76e_present) { + init_n76e_exist_node(); + pr_info("n76e 4p45 exist\n"); + } else { + pr_info("n76e 4p45 not exist\n"); + } + +} + +static void check_enhance_support(struct fastchg_device_info *di) +{ + if (di->is_mcl_verion) { + init_warp_chg_exist_node(); + pr_info("warp dash exist\n"); + } else { + pr_info("warp dash not exist\n"); + } + +} + +#ifdef OP_SWARP_SUPPORTED +static void check_swarp_support(struct fastchg_device_info *di) +{ + if (di->is_swarp_supported) { + init_swarp_chg_exist_node(); + pr_info("swarp dash exist\n"); + } else { + pr_info("swarp dash not exist\n"); + } + +} +#ifdef GET_HWID_BY_GPIO +static int dash_get_asic_hw_id(struct fastchg_device_info *di) +{ + int hw_id_gpio = 0; + int id_val[3] = { 0 }; + int rc = 0; + struct device_node *dev_node = di->client->dev.of_node; + + hw_id_gpio = of_get_named_gpio(dev_node, "microchip,id-m0", 0); + if (hw_id_gpio < 0) { + pr_err("hw_id_m0 not specified\n"); + di->asic_hw_id = 1; //default rk826 + return -EINVAL; + } + if (gpio_is_valid(hw_id_gpio)) { + rc = gpio_request(hw_id_gpio, "asic-id-gpio"); + if (rc) { + pr_err("unable to request asic_hw_id gpio [%d], rc=%d\n", hw_id_gpio, rc); + return rc; + } + if (di->pinctrl != NULL + && !IS_ERR_OR_NULL(di->pinctrl_mcu_id_hiz) + && !IS_ERR_OR_NULL(di->pinctrl_mcu_id_pull_up) + && !IS_ERR_OR_NULL(di->pinctrl_mcu_id_pull_down)){ + id_val[0] = gpio_get_value(hw_id_gpio); + usleep_range(10000, 10001); + if (pinctrl_select_state(di->pinctrl, + di->pinctrl_mcu_id_pull_up) < 0) + pr_err("pinctrl set mcu_id_pull_up fail\n"); + usleep_range(10000, 10001); + id_val[1] = gpio_get_value(hw_id_gpio); + usleep_range(10000, 10001); + if (pinctrl_select_state(di->pinctrl, + di->pinctrl_mcu_id_pull_down) < 0) + pr_err("pinctrl set mcu_id_pull_down fail\n"); + usleep_range(10000, 10001); + id_val[2] = gpio_get_value(hw_id_gpio); + pr_err("id gpio val[0-2]=[%d,%d,%d]", id_val[0], id_val[1],id_val[2]); + if (pinctrl_select_state(di->pinctrl, + di->pinctrl_mcu_id_hiz) < 0) + pr_err("pinctrl set mcu_id_hiz fail\n"); + } + gpio_free(hw_id_gpio); + di->asic_hw_id = id_val[1]^id_val[2] ? 2 : id_val[0]; + } else + di->asic_hw_id = 1; //default rk826 + + return 0; +} +#endif +#endif + +static void check_4p45_support(struct fastchg_device_info *di) +{ + if (di->is_4300mAh_4p45_support) { + init_dash_4300mAh_4p45_exist_node(); + pr_info("4300mAh_4p45 dash exist\n"); + } else if (di->is_4320mAh_4p45_support) { + init_dash_4320mAh_4p45_exist_node(); + pr_info("4320mAh_4p45 dash exist\n"); + } else if (di->is_4115mAh_4p45_support) { + init_dash_4115mAh_4p45_exist_node(); + pr_info("4115mAh_4p45 dash exist\n"); + } else if (di->is_4510mAh_4p45_support) { + init_dash_4510mAh_4p45_exist_node(); + pr_info("4510mAh_4p45 dash exist\n"); + } else { + pr_info("ST 4p45 dash not exist\n"); + } + +} + +#if (defined(OP_SWARP_SUPPORTED) && !defined(GET_HWID_BY_GPIO)) +static bool is_sy6610(struct i2c_client *client) +{ + u8 value = 0; + int rc = 0; + + client->addr = 0x06; + + rc = op_i2c_dma_read(client, 0x08, 1, &value); + if (rc < 0) { + pr_err("op10 read register 0x08 fail, rc = %d\n", rc); + return false; + } else { + if (value == 0x02) { + pr_err("op10 detected, register 0x08: 0x %x\n", value); + return true; + } + } + + return false; +} +static bool is_rk826(struct i2c_client *client) +{ + u8 value_buf[2] = {0}; + u32 value = 0; + int rc = 0; + + client->addr = 0x0a; + rc = oneplus_u16_i2c_read(client, 0x52f8, 2, value_buf); + if (rc < 0) { + pr_err("rk826 read register 0x52f8 fail, rc = %d\n", rc); + return false; + } else { + pr_err("register 0x52f8: 0x%x, 0x%x\n", value_buf[0], value_buf[1]); + value = value_buf[0] | (value_buf[1] << 8); + pr_err("register 0x52f8: 0x%x\n", value); + if (value == 0x826A) { + pr_err("rk826 detected, register 0x52f8: 0x%x\n", value); + return true; + } + } + return false; +} +static bool is_rt5125(struct i2c_client *client) +{ + u8 value = 0; + int rc = 0; + + client->addr = 0x0e; + + rc = op_i2c_dma_read(client, 0x02, 1, &value); + if (rc < 0) { + pr_err("rt5125 read register 0x02 fail, rc = %d\n", rc); + return false; + } else { + if (value == 0x80) { + pr_err("rt5125 detected, register 0x02: 0x%x\n", value); + return true; + } + } + return false; +} +static void get_asic_hw_id_by_i2c_work(struct work_struct *work) +{ + struct fastchg_device_info *di = container_of(work, + struct fastchg_device_info, + get_asic_hwid_work.work); + bool is_online = false; + int i = 0; + + (void)opchg_mcu_action(ACTION_MODE_SWITCH_UPGRADE); + for (i = 0; i < 3; i++) { + if (i == 0) + is_online = is_sy6610(di->client); + else if (i == 1) + is_online = is_rk826(di->client); + else if (i == 2) + is_online = is_rt5125(di->client); + if (is_online) + break; + } + if (i < 3) + di->asic_hw_id = i; + else + di->asic_hw_id = 1; + pr_err("asic_hw_id=%d", di->asic_hw_id); + di->client->addr = i2c_addr[di->asic_hw_id]; + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); +} +#endif + +static int dash_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct fastchg_device_info *di; + int ret; + + pr_info("dash_probe\n"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + pr_err("i2c_func error\n"); + goto err_check_functionality_failed; + } + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) { + ret = -ENOMEM; + goto err_check_functionality_failed; + } + di->client = mcu_client = client; + di->firmware_already_updated = false; + di->irq_enabled = true; + di->fast_chg_ing = false; + di->fast_low_temp_full = false; + di->fast_chg_started = false; + + fastchg_di = di; + dev_set_drvdata(&client->dev, di); + + ret = dash_parse_dt(di); + if (ret == -EINVAL) + goto err_read_dt; + + ret = request_dash_gpios(di); + /* + if (ret < 0) + goto err_read_dt; + */ + dash_pinctrl_init(di); + mutex_init(&di->read_mutex); + mutex_init(&di->gpio_mutex); + + init_waitqueue_head(&di->read_wq); + di->fastchg_wake_lock = wakeup_source_register(&client->dev, "fastcg_wake_lock"); + di->fastchg_update_fireware_lock = wakeup_source_register(&client->dev, + "fastchg_fireware_lock"); + + INIT_WORK(&di->fastcg_work, fastcg_work_func); + INIT_WORK(&di->charger_present_status_work, + update_charger_present_status); + INIT_DELAYED_WORK(&di->update_fireware_version_work, + update_fireware_version_func); + INIT_DELAYED_WORK(&di->update_firmware, dashchg_fw_update); + INIT_DELAYED_WORK(&di->adapter_update_work, adapter_update_work_func); +#if (defined(OP_SWARP_SUPPORTED) && !defined(GET_HWID_BY_GPIO)) + INIT_DELAYED_WORK(&di->get_asic_hwid_work, get_asic_hw_id_by_i2c_work); +#endif + INIT_DELAYED_WORK(&di->disable_mcu_work, disable_mcu_work_func); + + __init_timer(&di->watchdog, di_watchdog, TIMER_IRQSAFE); + //di->watchdog.data = (unsigned long)di;//20190707 + //di->watchdog.function = di_watchdog;//20190707 + + di->dash_device.minor = MISC_DYNAMIC_MINOR; + di->dash_device.name = "dash"; + di->dash_device.fops = &dash_dev_fops; + ret = misc_register(&di->dash_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto err_misc_register_failed; + } + + mcu_init(di); + check_n76e_support(di); + check_enhance_support(di); +#ifdef OP_SWARP_SUPPORTED + check_swarp_support(di); + if (di->is_swarp_supported) { +#ifdef GET_HWID_BY_GPIO + dash_get_asic_hw_id(di); + client->addr = i2c_addr[di->asic_hw_id]; +#else + di->asic_hw_id = -1; + schedule_delayed_work(&di->get_asic_hwid_work, + msecs_to_jiffies(1000)); + di->skin_hi_curr_max = CURRENT_LIMIT_2; + di->skin_wrm_curr_max = CURRENT_LIMIT_1; + di->skin_med_curr_max = CURRENT_LIMIT_3; + di->skin_hi_lcdoff_curr_max = CURRENT_LIMIT_2; + di->skin_med_lcdoff_curr_max = CURRENT_LIMIT_6; +#endif + } else { +#ifndef CONFIG_ARCH_LITO + di->skin_hi_curr_max = CURRENT_LIMIT_2; + di->skin_wrm_curr_max = CURRENT_LIMIT_1; + di->skin_med_curr_max = CURRENT_LIMIT_1; + di->skin_hi_lcdoff_curr_max = CURRENT_LIMIT_1; + di->skin_med_lcdoff_curr_max = CURRENT_LIMIT_6; +#else + di->skin_hi_curr_max = CURRENT_LIMIT_1; // 2A + di->skin_wrm_curr_max = CURRENT_LIMIT_3; // 3A + di->skin_med_curr_max = CURRENT_LIMIT_4; // 4A + di->skin_hi_lcdoff_curr_max = CURRENT_LIMIT_2; // 2.5A + di->skin_med_lcdoff_curr_max = CURRENT_LIMIT_3; // 3A +#endif + } +#endif + check_4p45_support(di); + init_enhance_dash_exist_node(); + init_dash_firmware_done_node(); + fastcharge_information_register(&fastcharge_information); + pr_info("dash_probe success\n"); + + return 0; + +err_misc_register_failed: +err_read_dt: + kfree(di); +err_check_functionality_failed: + pr_err("dash_probe fail\n"); + return 0; +} + +static int dash_remove(struct i2c_client *client) +{ + struct fastchg_device_info *di = dev_get_drvdata(&client->dev); + + fastcharge_information_unregister(&fastcharge_information); + if (gpio_is_valid(di->mcu_en_gpio)) + gpio_free(di->mcu_en_gpio); + if (gpio_is_valid(di->usb_sw_1_gpio)) + gpio_free(di->usb_sw_1_gpio); + if (gpio_is_valid(di->usb_sw_2_gpio)) + gpio_free(di->usb_sw_2_gpio); + if (gpio_is_valid(di->usb_on_gpio)) + gpio_free(di->usb_on_gpio); + if (gpio_is_valid(di->usb_on_gpio_1)) + gpio_free(di->usb_on_gpio_1); + if (gpio_is_valid(di->ap_clk)) + gpio_free(di->ap_clk); + if (gpio_is_valid(di->ap_data)) + gpio_free(di->ap_data); + + dev_set_drvdata(&client->dev, NULL); + return 0; +} + +static void dash_shutdown(struct i2c_client *client) +{ + struct fastchg_device_info *di = dev_get_drvdata(&client->dev); + + if (di->is_swarp_supported) { + (void)opchg_mcu_action(ACTION_MODE_RESET_SLEEP); + msleep(10); + if (di->fast_chg_started) { + gpio_direction_output(di->ap_clk, 1); + msleep(10); + (void)opchg_mcu_action(ACTION_MODE_RESET_ACTIVE); + } + msleep(80); + } else { + usb_sw_gpio_set(0); + mcu_en_reset(); + usleep_range(2000, 2001); + set_mcu_active(0); + } +} + +static const struct of_device_id dash_match[] = { + { .compatible = "microchip,oneplus_fastchg" }, + { }, +}; + +static const struct i2c_device_id dash_id[] = { + { "dash_fastchg", 1 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, dash_id); + +static struct i2c_driver dash_fastcg_driver = { + .driver = { + .name = "dash_fastchg", + .owner = THIS_MODULE, + .of_match_table = dash_match, + }, + .probe = dash_probe, + .remove = dash_remove, + .shutdown = dash_shutdown, + .id_table = dash_id, +}; + +static int __init dash_fastcg_init(void) +{ + return i2c_add_driver(&dash_fastcg_driver); +} +module_init(dash_fastcg_init); + +static void __exit dash_fastcg_exit(void) +{ + i2c_del_driver(&dash_fastcg_driver); +} +module_exit(dash_fastcg_exit); diff --git a/drivers/oneplus/power/supply/qcom/op_da9313.c b/drivers/oneplus/power/supply/qcom/op_da9313.c new file mode 100644 index 0000000000000000000000000000000000000000..de3be0d549d4ae77a6ba697b4ec7c1cdf9ff9bc4 --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/op_da9313.c @@ -0,0 +1,461 @@ +/************************************************************************************ +** --------------------------- Revision History: ------------------------------------------------------------ +* +* Revision 1.0 2015-06-22 Fanhong.Kong@ProDrv.CHG Created for new architecture +* Revision 2.0 2018-04-14 Fanhong.Kong@ProDrv.CHG Upgrade for SWARP +************************************************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct chip_da9313 *the_chip = NULL; +static DEFINE_MUTEX(da9313_i2c_access); + +static int __da9313_read_reg(int reg, int *returnData) +{ + int ret = 0; + int retry = 3; + struct chip_da9313 *chip = the_chip; + + ret = i2c_smbus_read_byte_data(chip->client, reg); + if (ret < 0) { + while(retry > 0) { + msleep(10); + ret = i2c_smbus_read_byte_data(chip->client, reg); + if (ret < 0) { + retry--; + } else { + *returnData = ret; + return 0; + } + } + chg_err("i2c read fail: can't read from %02x: %d\n", reg, ret); + return ret; + } else { + *returnData = ret; + } + + return 0; +} + +static int da9313_read_reg(int reg, int *returnData) +{ + int ret = 0; + + mutex_lock(&da9313_i2c_access); + ret = __da9313_read_reg(reg, returnData); + mutex_unlock(&da9313_i2c_access); + return ret; +} + +static int __da9313_write_reg(int reg, int val) +{ + int ret = 0; + struct chip_da9313 *chip = the_chip; + + ret = i2c_smbus_write_byte_data(chip->client, reg, val); + if (ret < 0) { + chg_err("i2c write fail: can't write %02x to %02x: %d\n", + val, reg, ret); + return ret; + } + + return 0; +} + +/********************************************************** + * + * [Read / Write Function] + * + *********************************************************/ +/* +static int da9313_read_interface (int RegNum, int *val, int MASK, int SHIFT) +{ + int da9313_reg = 0; + int ret = 0; + + //chg_err("--------------------------------------------------\n"); + + ret = da9313_read_reg(RegNum, &da9313_reg); + + //chg_err(" Reg[%x]=0x%x\n", RegNum, da9313_reg); + + da9313_reg &= (MASK << SHIFT); + *val = (da9313_reg >> SHIFT); + + //chg_err(" val=0x%x\n", *val); + + return ret; +} +*/ + +static int da9313_config_interface (int RegNum, int val, int MASK) +{ + int da9313_reg = 0; + int ret = 0; + + mutex_lock(&da9313_i2c_access); + ret = __da9313_read_reg(RegNum, &da9313_reg); + + if (ret >= 0) { + da9313_reg &= ~MASK; + da9313_reg |= val; + + if (RegNum == REG04_DA9313_ADDRESS) { + if ((da9313_reg & 0x01) == 0) { + chg_err("[REG04_DA9313_ADDRESS] can't write 0 to bit0, da9313_reg[0x%x] bug here\n", da9313_reg); + dump_stack(); + da9313_reg |= 0x01; + } + } + ret = __da9313_write_reg(RegNum, da9313_reg); + } + __da9313_read_reg(RegNum, &da9313_reg); + + mutex_unlock(&da9313_i2c_access); + + return ret; +} + +void da9313_dump_registers(void) +{ + int rc; + int addr; + + unsigned int val_buf[DA9313_REG2_NUMBER] = {0x0}; + + for (addr = DA9313_FIRST_REG; addr <= DA9313_LAST_REG; addr++) { + rc = da9313_read_reg(addr, &val_buf[addr]); + if (rc) { + chg_err("Couldn't read 0x%02x rc = %d\n", addr, rc); + } else { + pr_err("%s success addr = %d, value = 0x%x\n", + __func__, addr, val_buf[addr]); + } + } + + for (addr = DA9313_FIRST2_REG; addr <= DA9313_LAST2_REG; addr++) { + rc = da9313_read_reg(addr, &val_buf[addr]); + if (rc) { + chg_err("Couldn't read 0x%02x rc = %d\n", addr, rc); + } + } +} + +static int da9313_work_mode_set(int work_mode) +{ + int rc = 0; + struct chip_da9313 *divider_ic = the_chip; + + if(divider_ic == NULL) { + chg_err("%s: da9313 driver is not ready\n", __func__); + return rc; + } + if (atomic_read(÷r_ic->suspended) == 1) { + return 0; + } + if(divider_ic->fixed_mode_set_by_dev_file == true + && work_mode == DA9313_WORK_MODE_AUTO) { + chg_err("%s: maybe in high GSM work fixed mode ,return here\n", __func__); + return rc; + } +/* + if (op_warp_get_allow_reading() == false) { + return -1; + } +*/ + chg_err("%s: work_mode [%d]\n", __func__, work_mode); + if(work_mode != 0) { + rc = da9313_config_interface(REG04_DA9313_ADDRESS, REG04_DA9313_PVC_MODE_AUTO, REG04_DA9313_PVC_MODE_MASK); + } else { + rc = da9313_config_interface(REG04_DA9313_ADDRESS, REG04_DA9313_PVC_MODE_FIXED, REG04_DA9313_PVC_MODE_MASK); + } + return rc; +} + +int op_set_divider_work_mode(int work_mode) +{ + return da9313_work_mode_set(work_mode); +} +EXPORT_SYMBOL(op_set_divider_work_mode); + +int da9313_hardware_init(void) +{ + int rc = 0; + struct chip_da9313 *divider_ic = the_chip; + + if(divider_ic == NULL) { + chg_err("%s: da9313 driver is not ready\n", __func__); + return 0; + } + if (atomic_read(÷r_ic->suspended) == 1) { + return 0; + } + + rc = da9313_config_interface(REG04_DA9313_ADDRESS, REG04_DA9313_PVC_MODE_AUTO, REG04_DA9313_PVC_MODE_MASK); + return rc; +} +static ssize_t proc_work_mode_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[10]; + int work_mode = 0; + struct chip_da9313 *divider_ic = the_chip; + + if(divider_ic == NULL) { + chg_err("%s: da9313 driver is not ready\n", __func__); + return 0; + } + if (atomic_read(÷r_ic->suspended) == 1) { + return 0; + } +/* + if (op_warp_get_allow_reading() == false) { + return 0; + } +*/ + ret = da9313_read_reg(REG04_DA9313_ADDRESS, &work_mode); + work_mode = ((work_mode & 0x02)? 1:0); + + chg_err("%s: work_mode = %d.\n", __func__, work_mode); + sprintf(page, "%d", work_mode); + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_work_mode_write(struct file *file, const char __user *buf, size_t count, loff_t *lo) +{ + char buffer[1] = {0}; + int work_mode = 0; + struct chip_da9313 *divider_ic = the_chip; + + chg_err("%s: start.count[%ld]\n", __func__, count); + if(divider_ic == NULL) { + chg_err("%s: da9313 driver is not ready\n", __func__); + return 0; + } + + if (atomic_read(÷r_ic->suspended) == 1) { + return 0; + } + + if (count != 1) { + return count; + } + + if (copy_from_user(buffer, buf, 1)) { + chg_err("%s: read proc input error.\n", __func__); + return count; + } + + if (1 == sscanf(buffer, "%d", &work_mode)) { + chg_err("%s:new work_mode = %d.\n", __func__, work_mode); + } else { + chg_err("invalid content: '%s', length = %zd\n", buf, count); + } + + if (work_mode != 0) { + divider_ic->fixed_mode_set_by_dev_file = false; + } else { + divider_ic->fixed_mode_set_by_dev_file = true; + } +/* + if (op_warp_get_allow_reading() == false) { + return 0; + } +*/ + if (work_mode != 0) { + da9313_config_interface(REG04_DA9313_ADDRESS, REG04_DA9313_PVC_MODE_AUTO, REG04_DA9313_PVC_MODE_MASK); + } else { + da9313_config_interface(REG04_DA9313_ADDRESS, REG04_DA9313_PVC_MODE_FIXED, REG04_DA9313_PVC_MODE_MASK); + } + + return count; +} + +static const struct file_operations proc_work_mode_ops = +{ + .read = proc_work_mode_read, + .write = proc_work_mode_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static int init_da9313_proc(struct chip_da9313 *da) +{ + int ret = 0; + struct proc_dir_entry *prEntry_da = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + prEntry_da = proc_mkdir("da9313", NULL); + if (prEntry_da == NULL) { + ret = -ENOMEM; + chg_debug("%s: Couldn't create da9313 proc entry\n", __func__); + } + + prEntry_tmp = proc_create_data("work_mode", 0644, prEntry_da, &proc_work_mode_ops, da); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_debug("%s: Couldn't create proc entry, %d\n", __func__, __LINE__); + } + return 0; +} + +static int da9313_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct chip_da9313 *divider_ic; + + divider_ic = devm_kzalloc(&client->dev, sizeof(struct chip_da9313), GFP_KERNEL); + if (!divider_ic) { + dev_err(&client->dev, "failed to allocate divider_ic\n"); + return -ENOMEM; + } + + chg_debug( " call \n"); + divider_ic->client = client; + divider_ic->dev = &client->dev; + the_chip = divider_ic; + divider_ic->fixed_mode_set_by_dev_file = false; + + da9313_dump_registers(); + + da9313_hardware_init(); + init_da9313_proc(divider_ic); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +static int da9313_pm_resume(struct device *dev) +{ + if (!the_chip) { + return 0; + } + atomic_set(&the_chip->suspended, 0); + return 0; +} + +static int da9313_pm_suspend(struct device *dev) +{ + if (!the_chip) { + return 0; + } + atomic_set(&the_chip->suspended, 1); + return 0; +} + +static const struct dev_pm_ops da9313_pm_ops = { + .resume = da9313_pm_resume, + .suspend = da9313_pm_suspend, +}; +#else /*(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))*/ +static int da9313_resume(struct i2c_client *client) +{ + if (!the_chip) { + return 0; + } + atomic_set(&the_chip->suspended, 0); + return 0; +} + +static int da9313_suspend(struct i2c_client *client, pm_message_t mesg) +{ + if (!the_chip) { + return 0; + } + atomic_set(&the_chip->suspended, 1); + return 0; +} +#endif /*(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))*/ + +static struct i2c_driver da9313_i2c_driver; + +static int da9313_driver_remove(struct i2c_client *client) +{ + int ret=0; + + chg_debug( " ret = %d\n", ret); + return 0; +} + +static void da9313_shutdown(struct i2c_client *client) +{ + int rc = 0; + struct chip_da9313 *divider_ic = the_chip; + + if(divider_ic == NULL) { + chg_err("%s: da9313 driver is not ready\n", __func__); + return ; + } + if (atomic_read(÷r_ic->suspended) == 1) { + return ; + } + + rc = da9313_config_interface(REG04_DA9313_ADDRESS, REG04_DA9313_PVC_MODE_AUTO, REG04_DA9313_PVC_MODE_MASK); + + return ; +} + + +/********************************************************** + * + * [platform_driver API] + * + *********************************************************/ + +static const struct of_device_id da9313_match[] = { + { .compatible = "op,da9313-divider"}, + { }, +}; + +static const struct i2c_device_id da9313_id[] = { + {"da9313-divider", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, da9313_id); + + +static struct i2c_driver da9313_i2c_driver = { + .driver = { + .name = "da9313-divider", + .owner = THIS_MODULE, + .of_match_table = da9313_match, +#ifdef CONFIG_PM_SLEEP //#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + .pm = &da9313_pm_ops, +#endif + }, + .probe = da9313_driver_probe, + .remove = da9313_driver_remove, + .id_table = da9313_id, +#ifndef CONFIG_PM_SLEEP //#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) + .resume = da9313_resume, + .suspend = da9313_suspend, +#endif + .shutdown = da9313_shutdown, +}; + + +module_i2c_driver(da9313_i2c_driver); +MODULE_DESCRIPTION("Driver for da9313 divider chip"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:da9313-divider"); diff --git a/drivers/oneplus/power/supply/qcom/op_da9313.h b/drivers/oneplus/power/supply/qcom/op_da9313.h new file mode 100644 index 0000000000000000000000000000000000000000..14bfed5a75c925c6b1c34fc6ddcbe5f6b070097c --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/op_da9313.h @@ -0,0 +1,75 @@ +/************************************************************************************ +** --------------------------- Revision History: ------------------------------------------------------------ +* +* Revision 1.0 2015-06-22 Fanhong.Kong@ProDrv.CHG Created for new architecture +* Revision 2.0 2018-04-14 Fanhong.Kong@ProDrv.CHG Upgrade for SWARP +************************************************************************************************************/ + + +#ifndef __OP_DA9313_H__ + +#define __OP_DA9313_H__ + +#include + +#define chg_debug(fmt, ...) \ + printk(KERN_NOTICE "[SWARPCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define chg_err(fmt, ...) \ + printk(KERN_ERR "[SWARPCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define chg_info(fmt, ...) \ + printk(KERN_INFO "[SWARPCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define DA9313_FIRST_REG 0x00 +#define DA9313_LAST_REG 0x14 +#define DA9313_REG_NUMBER 0x15 + +#define DA9313_FIRST2_REG 0x30 +#define DA9313_LAST2_REG 0x33 +#define DA9313_REG2_NUMBER 0x34 + +//0x04 +#define REG04_DA9313_ADDRESS 0x04 + +#define REG04_DA9313_PVC_MODE_MASK BIT(1) +#define REG04_DA9313_PVC_MODE_FIXED 0 +#define REG04_DA9313_PVC_MODE_AUTO BIT(1) + +//0x0E +#define REG0E_DA9313_ADDRESS 0x0E + +#define REG0E_DA9313_PVC_DROP_MASK (BIT(7) | BIT(6)) +#define REG0E_DA9313_PVC_DROP_20MV 0 +#define REG0E_DA9313_PVC_DROP_30MV BIT(6) +#define REG0E_DA9313_PVC_DROP_40MV BIT(7)//default +#define REG0E_DA9313_PVC_DROP_50MV (BIT(7) | BIT(6)) + +#define REG0E_DA9313_PVC_HYST_MASK (BIT(5) | BIT(4)) +#define REG0E_DA9313_PVC_HYST_00MV 0 +#define REG0E_DA9313_PVC_HYST_10MV BIT(4) +#define REG0E_DA9313_PVC_HYST_20MV BIT(5)//default +#define REG0E_DA9313_PVC_HYST_30MV (BIT(5) | BIT(4)) + +#define REG0E_DA9313_PVC_MS_DROP_MASK (BIT(3) | BIT(2)) +#define REG0E_DA9313_PVC_MS_DROP_15MV 0 +#define REG0E_DA9313_PVC_MS_DROP_30MV BIT(2)//default +#define REG0E_DA9313_PVC_MS_DROP_45MV BIT(3) +#define REG0E_DA9313_PVC_MS_DROP_60MV (BIT(3) | BIT(2)) + +#define REG0E_DA9313_PVC_MS_HYST_MASK (BIT(1) | BIT(0)) +#define REG0E_DA9313_PVC_MS_HYST_00MV 0 +#define REG0E_DA9313_PVC_MS_HYST_15MV BIT(0) +#define REG0E_DA9313_PVC_MS_HYST_30MV BIT(1)//default +#define REG0E_DA9313_PVC_MS_HYST_45MV (BIT(1) | BIT(0)) + +#define DA9313_WORK_MODE_AUTO 1 +#define DA9313_WORK_MODE_FIXED 0 + +struct chip_da9313 { + struct i2c_client *client; + struct device *dev; + bool fixed_mode_set_by_dev_file; + atomic_t suspended; +}; +#endif diff --git a/drivers/oneplus/power/supply/qcom/op_mp2650.c b/drivers/oneplus/power/supply/qcom/op_mp2650.c new file mode 100644 index 0000000000000000000000000000000000000000..d11eb8aabdfcf64d3c266e0960c46b92827b788f --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/op_mp2650.c @@ -0,0 +1,1981 @@ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/oem/project_info.h" + +#include +#include + +#define DEBUG_BY_FILE_OPS +#define MP2762_CP_PSY + +struct mp2650_charger *s_mcharger = NULL; +int reg_access_allow = 0; +int mp2650_reg = 0; + +static void mp2650_set_mps_otg_en_val(int value); +static int mp2650_otg_enable(struct mp2650_charger *chg, bool en); +static int mp2650_get_vbus_voltage(int *vbus_mv); +static void mp2650_dump_registers(void); +static int mp2650_otg_ilim_set(int ilim_ma); +static int mp2650_read_reg(int reg, int *returnData); +static int mp2650_set_prechg_voltage_threshold(u8 bit); + +static DEFINE_MUTEX(mp2650_i2c_access); + +static int test_mp2650_write_reg(int reg, int val) +{ + int ret = 0; + struct mp2650_charger *chg = s_mcharger; + + if(!chg) { + chg_err("chg is NULL\n"); + return 0; + } + + ret = i2c_smbus_write_byte_data(chg->client, reg, val); + if (ret < 0) { + chg_err("i2c write fail: can't write %02x to %02x: %d\n", + val, reg, ret); + return ret; + } + + return 0; +} + +static ssize_t mp2650_reg_access_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%02x\n", reg_access_allow); +} +static ssize_t mp2650_reg_access_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_err("%s: value=%d\n", __FUNCTION__, val); + reg_access_allow = val; + + return count; + +} + +static ssize_t mp2650_reg_set_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t count = 0; + int reg_val = 0; + int ret = 0; + + ret = mp2650_read_reg(mp2650_reg, ®_val); + if (ret < 0) { + pr_err("read reg 0x%02x err.", mp2650_reg); + return ret; + } + + count += snprintf(buf+count, PAGE_SIZE-count, "reg[0x%02x]: 0x%02x\n", mp2650_reg, reg_val); + return count; +} + +static ssize_t mp2650_reg_set_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned int databuf[2] = {0, 0}; + + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + pr_err("%s:reg[0x%02x]=0x%02x\n", __FUNCTION__, databuf[0], databuf[1]); + mp2650_reg = databuf[0]; + test_mp2650_write_reg((int)databuf[0], (int)databuf[1]); + } + return count; +} + +static ssize_t mp2650_regs_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + int i = 0; + int reg_val = 0; + + for (i = MP2650_FIRST_REG; i <= MP2650_LAST_REG; i++) { + (void)mp2650_read_reg(i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val); + } + return len; +} +static ssize_t mp2650_regs_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + return count; +} + +static DEVICE_ATTR(reg_access, S_IWUSR | S_IRUGO, mp2650_reg_access_show, mp2650_reg_access_store); +static DEVICE_ATTR(reg_set, S_IWUSR | S_IRUGO, mp2650_reg_set_show, mp2650_reg_set_store); +static DEVICE_ATTR(read_regs, S_IWUSR | S_IRUGO, mp2650_regs_show, mp2650_regs_store); + +static struct attribute *mp2650_attributes[] = { + &dev_attr_reg_access.attr, + &dev_attr_reg_set.attr, + &dev_attr_read_regs.attr, + NULL +}; + +static struct attribute_group mp2650_attribute_group = { + .attrs = mp2650_attributes +}; + +static int __mp2650_read_reg(int reg, int *returnData) +{ + int ret = 0; + struct mp2650_charger *chg = s_mcharger; + + ret = i2c_smbus_read_byte_data(chg->client, (unsigned char)reg); + if (ret < 0) { + chg_err("i2c read fail: can't read from %02x: %d\n", reg, ret); + return ret; + } else { + *returnData = ret; + } + + return 0; +} + +static int mp2650_read_reg(int reg, int *returnData) +{ + int ret = 0; + + mutex_lock(&mp2650_i2c_access); + ret = __mp2650_read_reg(reg, returnData); + mutex_unlock(&mp2650_i2c_access); + return ret; +} + +static int __mp2650_write_reg(int reg, int val) +{ + int ret = 0; + struct mp2650_charger *chg = s_mcharger; + + if (reg_access_allow != 0) { + chg_err("can not access registers\n"); + return 0; + } + ret = i2c_smbus_write_byte_data(chg->client, reg, val); + if (ret < 0) { + chg_err("i2c write fail: can't write %02x to %02x: %d\n", + val, reg, ret); + return ret; + } + + return 0; +} + +/********************************************************** + * + * [Read / Write Function] + * + *********************************************************/ +/* +*/ + +static int mp2650_config_interface(int RegNum, int val, int MASK) +{ + int mp2650_reg = 0; + int ret = 0; + + mutex_lock(&mp2650_i2c_access); + + ret = __mp2650_read_reg(RegNum, &mp2650_reg); + + //chg_err(" Reg[%x]=0x%x\n", RegNum, mp2650_reg); + + mp2650_reg &= ~MASK; + mp2650_reg |= val; + + ret = __mp2650_write_reg(RegNum, mp2650_reg); + + //chg_err(" write Reg[%x]=0x%x\n", RegNum, mp2650_reg); + + __mp2650_read_reg(RegNum, &mp2650_reg); + + //chg_err(" Check Reg[%x]=0x%x\n", RegNum, mp2650_reg); + + mutex_unlock(&mp2650_i2c_access); + + return ret; + +} + +static int mp2650_set_vindpm_vol(int vol_mv)//default 4.5V +{ + // Input voltage limit threshold (0-25.5V) + int rc; + int tmp = 0; + + struct mp2650_charger *chg = s_mcharger; + + if (atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + tmp = (vol_mv - REG01_MP2650_VINDPM_THRESHOLD_OFFSET) / REG01_MP2650_VINDPM_THRESHOLD_STEP; + rc = mp2650_config_interface(REG01_MP2650_ADDRESS, tmp << REG01_MP2650_VINDPM_THRESHOLD_SHIFT, REG01_MP2650_VINDPM_THRESHOLD_MASK); + + return rc; +} + +static int mp2650_get_vindpm_vol(void) +{ + int reg_val = 0; + int rc = 0; + rc = mp2650_read_reg(REG01_MP2650_ADDRESS, ®_val); + if (rc) { + chg_err("Couldn't read REG00_mp2650_ADDRESS rc = %d\n", rc); + return 0; + } + reg_val = reg_val * REG01_MP2650_VINDPM_THRESHOLD_STEP + REG01_MP2650_VINDPM_THRESHOLD_OFFSET; + return reg_val; +} + +static void mp2650_set_aicl_point(int vbatt_mv) +{ + struct mp2650_charger *chip = s_mcharger; + + if(chip->hw_aicl_point == 4440 && vbatt_mv > 4140) { + chip->hw_aicl_point = 4520; // real 4500 + chip->sw_aicl_point = 4650; + mp2650_set_vindpm_vol(chip->hw_aicl_point); + } else if(chip->hw_aicl_point == 4520 && vbatt_mv < 4000) { + chip->hw_aicl_point = 4440; // real 4400 + chip->sw_aicl_point = 4650; + mp2650_set_vindpm_vol(chip->hw_aicl_point); + } + + if (!chip->pre_chg_thd_6600 && vbatt_mv > 3500) { + chip->pre_chg_thd_6600 = true; + mp2650_set_prechg_voltage_threshold(REG07_MP2650_PRECHARGE_THRESHOLD_6600MV); + } +} + +static int mp2650_charging_current_write_fast(int chg_cur) +{ + int rc = 0; + int tmp = 0; + struct mp2650_charger *chg = s_mcharger; + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg_err("set charge current = %d\n", chg_cur); + + + tmp = chg_cur - REG02_MP2650_CHARGE_CURRENT_SETTING_OFFSET; + tmp = tmp / REG02_MP2650_CHARGE_CURRENT_SETTING_STEP; + + rc = mp2650_config_interface(REG02_MP2650_ADDRESS, tmp << REG02_MP2650_CHARGE_CURRENT_SETTING_SHIFT, REG02_MP2650_CHARGE_CURRENT_SETTING_MASK); + + return rc; +} + +static int mp2650_charging_current_read_fast(int *chg_cur) +{ + int rc = 0; + int tmp = 0; + struct mp2650_charger *chg = s_mcharger; + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_read_reg(REG02_MP2650_ADDRESS, &tmp); + if (rc < 0) { + chg_err("can't read REG02 fcc, rc = %d\n", rc); + *chg_cur = 0; + } else + *chg_cur = tmp * REG02_MP2650_CHARGE_CURRENT_SETTING_STEP + REG02_MP2650_CHARGE_CURRENT_SETTING_OFFSET; + + return rc; +} + +static int mp2650_set_enable_volatile_writes(void) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + //need do nothing + + return rc; +} + +static int mp2650_set_complete_charge_timeout(int val) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + if (val == OVERTIME_AC) { + val = REG09_MP2650_CHARGE_TIMER_EN_ENABLE | REG09_MP2650_FAST_CHARGE_TIMER_8H; + } else if (val == OVERTIME_USB) { + val = REG09_MP2650_CHARGE_TIMER_EN_ENABLE | REG09_MP2650_FAST_CHARGE_TIMER_12H; + } else { + val = REG09_MP2650_CHARGE_TIMER_EN_DISABLE | REG09_MP2650_FAST_CHARGE_TIMER_20H; + } + + rc = mp2650_config_interface(REG09_MP2650_ADDRESS, val, REG09_MP2650_FAST_CHARGE_TIMER_MASK | REG09_MP2650_CHARGE_TIMER_EN_MASK); + if (rc < 0) { + chg_err("Couldn't complete charge timeout rc = %d\n", rc); + } + return 0; +} + +static int mp2650_float_voltage_write(int vfloat_mv) +{ + int rc = 0; + int tmp = 0; + int fv_val = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg_err("vfloat_mv = %d\n", vfloat_mv); + + if (vfloat_mv > 5000) { + if (vfloat_mv > 9000) { + vfloat_mv = 9000; + } + vfloat_mv = vfloat_mv / 2; + } + + if (vfloat_mv > 4500) { + vfloat_mv = 4500; + } + + tmp = vfloat_mv * 10 - REG04_MP2650_CHARGE_FULL_VOL_OFFSET; + tmp = tmp / REG04_MP2650_CHARGE_FULL_VOL_STEP; + tmp <<= REG04_MP2650_CHARGE_FULL_VOL_SHIFT; + + + rc = mp2650_read_reg(REG04_MP2650_ADDRESS, &fv_val); + if (rc) { + rc = 0; + chg_err("Couldn't read REG04_MP2650_ADDRESS rc = %d\n", rc); + } else if ((fv_val & REG04_MP2650_CHARGE_FULL_VOL_MASK) == tmp) { + chg_err("set the same fv 0x%2x, return!", tmp); + return 0; + } + + rc = mp2650_config_interface(REG04_MP2650_ADDRESS, tmp, REG04_MP2650_CHARGE_FULL_VOL_MASK); + + return rc; +} + +static int mp2650_float_voltage_read(int *vfloat_mv) +{ + int rc = 0; + int fv_val = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + rc = mp2650_read_reg(REG04_MP2650_ADDRESS, &fv_val); + if (rc) { + chg_err("Couldn't read REG04_MP2650_ADDRESS rc = %d\n", rc); + return rc; + } + + *vfloat_mv = ((fv_val & REG04_MP2650_CHARGE_FULL_VOL_MASK) * REG04_MP2650_CHARGE_FULL_VOL_STEP + + REG04_MP2650_CHARGE_FULL_VOL_OFFSET * 2) / 10; + + return 0; +} + +static int mp2650_set_prechg_voltage_threshold(u8 bit) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_config_interface(REG07_MP2650_ADDRESS, bit, REG07_MP2650_PRECHARGE_THRESHOLD_MASK); + + return 0; +} + +static int mp2650_set_prechg_current( int ipre_mA) +{ + int tmp = 0; + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + tmp = ipre_mA - REG03_MP2650_PRECHARGE_CURRENT_LIMIT_OFFSET; + tmp = tmp / REG03_MP2650_PRECHARGE_CURRENT_LIMIT_STEP; + rc = mp2650_config_interface(REG03_MP2650_ADDRESS, (tmp + 1) << REG03_MP2650_PRECHARGE_CURRENT_LIMIT_SHIFT, REG03_MP2650_PRECHARGE_CURRENT_LIMIT_MASK); + + return 0; +} + +static int mp2650_set_termchg_current(int term_curr) +{ + int rc = 0; + int tmp = 0; + + struct mp2650_charger *chg = s_mcharger; + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg_err("term_current = %d\n", term_curr); + tmp = term_curr - REG03_MP2650_TERMINATION_CURRENT_LIMIT_OFFSET; + tmp = tmp / REG03_MP2650_TERMINATION_CURRENT_LIMIT_STEP; + + rc = mp2650_config_interface(REG03_MP2650_ADDRESS, tmp << REG03_MP2650_TERMINATION_CURRENT_LIMIT_SHIFT, REG03_MP2650_TERMINATION_CURRENT_LIMIT_MASK); + return 0; +} + +static int mp2650_set_rechg_voltage(int recharge_mv) +{ + int rc = 0; + int tmp = 0; + struct mp2650_charger *chg = s_mcharger; + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + tmp = recharge_mv - REG04_MP2650_BAT_RECHARGE_THRESHOLD_OFFSET; + tmp = tmp / REG04_MP2650_BAT_RECHARGE_THRESHOLD_STEP; + + + /*The rechg voltage is: Charge Full Voltage - 100mV or - 200mV, default is - 100mV*/ + rc = mp2650_config_interface(REG04_MP2650_ADDRESS, tmp << REG04_MP2650_BAT_RECHARGE_THRESHOLD_SHIFT, REG04_MP2650_BAT_RECHARGE_THRESHOLD_MASK); + + if (rc) { + chg_err("Couldn't set recharging threshold rc = %d\n", rc); + } + return rc; +} + +static int mp2650_set_wdt_timer(int reg) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_config_interface(REG09_MP2650_ADDRESS, reg, REG09_MP2650_WTD_TIMER_MASK); + if (rc) { + chg_err("Couldn't set recharging threshold rc = %d\n", rc); + } + + return 0; +} + +static int mp2650_set_chging_term_enable(bool enable) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + if (atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + chg_info("%sable charging term.", enable ? "en" : "dis"); + if (enable) + rc = mp2650_config_interface(REG09_MP2650_ADDRESS, REG09_MP2650_CCHARGE_TERMINATION_EN_ENABLE, REG09_MP2650_CHARGE_TERMINATION_EN_MASK); + else + rc = mp2650_config_interface(REG09_MP2650_ADDRESS, REG09_MP2650_CHARGE_TERMINATION_EN_DISABLE, REG09_MP2650_CHARGE_TERMINATION_EN_MASK); + if (rc) { + chg_err("Couldn't set chging term %sable rc = %d\n", enable ? "en" : "dis",rc); + } + return rc; +} + +static int mp2650_enable_charging(struct mp2650_charger *chg, bool enable) +{ + int rc; + + if (chg == NULL) + return -ENODEV; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + if (enable) { + mp2650_otg_enable(chg, false); + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_CHG_EN_ENABLE, REG08_MP2650_CHG_EN_MASK); + } else { + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_CHG_EN_DISABLE, REG08_MP2650_CHG_EN_MASK); + } + if (rc < 0) { + chg_err("Couldn'tmp2650_enable_charging rc = %d\n", rc); + } + + chg_err("mp2650 %sable charging.", enable ? "en" : "dis"); + return rc; +} + +static int mp2650_check_charging_enable(struct mp2650_charger *chg) +{ + int rc = 0; + int reg_val = 0; + //struct mp2650_charger *chg = s_mcharger; + bool charging_enable = false; + + if (chg == NULL) + return -ENODEV; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + rc = mp2650_read_reg(REG08_MP2650_ADDRESS, ®_val); + if (rc) { + chg_err("Couldn't read REG08_MP2650_ADDRESS rc = %d\n", rc); + return 0; + } + + charging_enable = ((reg_val & REG08_MP2650_CHG_EN_MASK) == REG08_MP2650_CHG_EN_ENABLE) ? 1 : 0; + + return charging_enable; +} + +static int mp2650_get_vbus_voltage(int *vbus_mv) +{ + int vol_high = 0; + int vol_low = 0; + int rc = 0; + + rc = mp2650_read_reg(REG1C1D_MP2650_ADDRESS, &vol_low); + if (rc) { + chg_err("Couldn't read REG1C1D_MP2650_ADDRESS rc = %d\n", rc); + *vbus_mv = 0; + return rc; + } + + rc = mp2650_read_reg((REG1C1D_MP2650_ADDRESS + 1), &vol_high); + if (rc) { + chg_err("Couldn't read REG1C1D_MP2650_ADDRESS rc = %d\n", rc); + *vbus_mv = 0; + return rc; + } + + *vbus_mv = (vol_high * 100) + ((vol_low >> 6) * 25); + //chg_err("vol_high = 0x%x, vol_low = 0x%x, vbus_vol[%d]\n", vol_high, vol_low, vbus_vol); + + return rc; +} + +static int mp2650_get_ibus_current(int *ibus_ua) +{ + int cur_high = 0; + int cur_low = 0; + int rc = 0; + + rc = mp2650_read_reg(REG1E1F_MP2650_ADDRESS, &cur_low); + if (rc) { + chg_err("Couldn't read REG1E1F_MP2650_ADDRESS rc = %d\n", rc); + return rc; + } + + rc = mp2650_read_reg((REG1E1F_MP2650_ADDRESS + 1), &cur_high); + if (rc) { + chg_err("Couldn't read REG1E1F_MP2650_ADDRESS + 1 rc = %d\n", rc); + return rc; + } + + *ibus_ua = (cur_high * 25000) + ((cur_low >> 6) * 6250); + chg_err("cur_high = 0x%x, cur_low = 0x%x, ibus_curr[%d]\n", cur_high, cur_low, *ibus_ua); + + return rc; +} + +static int mp2650_get_charge_status(int *status) +{ + int rc; + int chg_stat_bit = 0; + int chg_stat = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_read_reg(REG13_MP2650_ADDRESS, &chg_stat_bit); + if (rc) { + chg_err("Couldn't read STAT_C rc = %d\n", rc); + return rc; + } + + chg_stat = chg_stat_bit & REG13_MP2650_VIN_POWER_GOOD_MASK; + if (chg_stat == REG13_MP2650_VIN_POWER_GOOD_NO) { + *status = POWER_SUPPLY_STATUS_DISCHARGING; + return 0; + } + + chg_stat = chg_stat_bit & REG13_MP2650_CHARGING_STATUS_MASK; + switch (chg_stat) { + case REG13_MP2650_CHARGING_STATUS_NOT_CHARGING: + *status = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + // Fall-through. + case REG13_MP2650_CHARGING_STATUS_PRE_CHARGE: + case REG13_MP2650_CHARGING_STATUS_FAST_CHARGE: + *status = POWER_SUPPLY_STATUS_CHARGING; + break; + case REG13_MP2650_CHARGING_STATUS_CHARGE_TERMINATION: + chg_err("the mp2650 is full"); + *status = POWER_SUPPLY_STATUS_FULL; + mp2650_dump_registers(); + break; + default: + *status = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + + return 0; +} + +static int mp2650_enable_suspend_charger(bool enable) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if (atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg->input_suspend = enable; + if (enable) + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_LEARN_EN_ENABLE, REG08_MP2650_LEARN_EN_MASK); + else + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_LEARN_EN_DISABLE, REG08_MP2650_LEARN_EN_MASK); + + chg_info( " rc = %d\n", rc); + if (rc < 0) { + chg_err("Couldn't mp2650_%ssuspend_charger rc = %d\n", enable ? "" : "un", rc); + } + + return rc; +} + +static int mp2650_otg_enable(struct mp2650_charger *chg, bool enable) +{ + int rc; + + if (chg == NULL) + return -ENODEV; + + if (atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg->otg_enabled = enable; + if (enable) { + mp2650_set_mps_otg_en_val(1); //set output 5V vbus + + rc = mp2650_otg_ilim_set(MP2650_OTG_CURRENT_LIMIT_DEFAULT); + if (rc < 0) { + chg_err("Couldn't mp2650_otg_ilim_set rc = %d\n", rc); + } + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_OTG_EN_ENABLE, REG08_MP2650_OTG_EN_MASK); + if (rc < 0) { + chg_err("Couldn't mp2650_otg_enable rc = %d\n", rc); + } + + mp2650_set_wdt_timer(REG09_MP2650_WTD_TIMER_DISABLE); + } else { + mp2650_set_mps_otg_en_val(0); //set disable output 5V vbus + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_OTG_EN_DISABLE, REG08_MP2650_OTG_EN_MASK); + if (rc < 0) { + chg_err("Couldn't mp2650_otg_disable rc = %d\n", rc); + } + + mp2650_set_wdt_timer(REG09_MP2650_WTD_TIMER_40S); + } + return rc; +} + +static int mp2650_other_registers_init(void) +{ + int rc; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_config_interface(REG10_MP2650_ADDRESS, 0x01, 0xff); + rc = mp2650_config_interface(REG11_MP2650_ADDRESS, 0xfe, 0xff); + rc = mp2650_config_interface(REG2D_MP2650_ADDRESS, 0x0f, 0xff); + return rc; +} + +int mp2650_reset_charger(void) +{ + int rc; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg_err(" mp2650_reset_charger start \n"); + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_REG_RST_RESET, REG08_MP2650_REG_RST_MASK); + if (rc < 0) { + chg_err("Couldn't mp2650_reset_charger rc = %d\n", rc); + } + + return rc; +} + +static int mp2650_otg_ilim_set(int ilim_ma) +{ + int rc; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + ilim_ma /= REG07_MP2650_OTG_CURRENT_LIMIT_STEP; + rc = mp2650_config_interface(REG07_MP2650_ADDRESS, + ilim_ma, REG07_MP2650_OTG_CURRENT_LIMIT_MASK ); + if (rc < 0) { + chg_err("Couldn't mp2650_otg_ilim_set rc = %d\n", rc); + } + + return rc; +} + +static int mp2650_otg_ilim_get(int *ilim_ma) +{ + int rc; + int ocl_bit; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_read_reg(REG07_MP2650_ADDRESS, &ocl_bit); + if (rc < 0) { + chg_err("Couldn't read REG07 rc = %d\n", rc); + *ilim_ma = 0; + return rc; + } + + *ilim_ma = (ocl_bit & REG07_MP2650_OTG_CURRENT_LIMIT_MASK) * REG07_MP2650_OTG_CURRENT_LIMIT_STEP; + + return 0; +} + +int mp2650_set_switching_frequency(void) +{ + // set default 800k; + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_config_interface(REG0B_MP2650_ADDRESS, REG0B_MP2650_SW_FREQ_800K, REG0B_MP2650_SW_FREQ_MASK); + return 0; +} + +static int mp2650_set_mps_otg_voltage(bool is_9v) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + if(is_9v){ + rc = mp2650_config_interface(REG06_MP2650_ADDRESS, REG06_MP2650_OTG_VOL_OPTION_8750MV, REG06_MP2650_OTG_VOL_OPTION_MASK); + rc = mp2650_config_interface(REG06_MP2650_ADDRESS, REG06_MP2650_2ND_OTG_VOL_SETTING_250MV, REG06_MP2650_2ND_OTG_VOL_SETTING_MASK); + } else { + rc = mp2650_config_interface(REG06_MP2650_ADDRESS, REG06_MP2650_OTG_VOL_OPTION_4750MV, REG06_MP2650_OTG_VOL_OPTION_MASK); + rc = mp2650_config_interface(REG06_MP2650_ADDRESS, REG06_MP2650_2ND_OTG_VOL_SETTING_250MV, REG06_MP2650_2ND_OTG_VOL_SETTING_MASK); + } + return 0; +} + +int mp2650_set_mps_otg_enable(bool enable) +{ + //int value; + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg_err("%sable start.", enable ? "en" : "dis"); + if (enable) + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_OTG_EN_ENABLE, REG08_MP2650_OTG_EN_MASK); + else + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_OTG_EN_DISABLE, REG08_MP2650_OTG_EN_MASK); + return 0; +} + +int mp2650_enable_hiz(bool enable) +{ + int rc; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + if (enable) + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_LEARN_EN_ENABLE, REG08_MP2650_LEARN_EN_MASK); + else + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, + REG08_MP2650_LEARN_EN_DISABLE, REG08_MP2650_LEARN_EN_MASK); + if (rc < 0) { + chg_err("Couldn'mp2650_%sable_hiz rc = %d\n", enable ? "en" : "dis", rc); + } + + chg_err("mp2650_%sable_hiz.", enable ? "en" : "dis"); + + return rc; +} + +static int mp2650_enable_buck_switch(bool enable) +{ + int rc; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + chg->buck_switcher_on = enable; + if (enable) + rc = mp2650_config_interface(REG12_MP2650_ADDRESS, + REG12_MP2650_BUCK_SWITCH_ENABLE, REG12_MP2650_BUCK_SWITCH_MASK); + else + rc = mp2650_config_interface(REG12_MP2650_ADDRESS, + REG12_MP2650_BUCK_SWITCH_DISABLE, REG12_MP2650_BUCK_SWITCH_MASK); + if (rc < 0) { + chg_err("Couldn'mp2650_%sable_dig_skip rc = %d\n", enable ? "en" : "dis", rc); + } + + chg_err("mp2650_%sable_dig_skip \n", enable ? "en" : "dis"); + + return rc; +} + +static int mp2650_vbus_avoid_electric_config(void) +{ + int rc; + struct mp2650_charger *chip = s_mcharger; + if(atomic_read(&chip->charger_suspended) == 1) { + return 0; + } + rc = mp2650_config_interface(REG53_MP2650_ADDRESS, 0x95, 0xff); + rc = mp2650_config_interface(REG39_MP2650_ADDRESS, 0x40, 0xff); + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, 0x36, 0xff); + rc = mp2650_config_interface(REG08_MP2650_ADDRESS, 0x16, 0xff); + rc = mp2650_config_interface(REG39_MP2650_ADDRESS, 0x00, 0xff); + rc = mp2650_config_interface(REG53_MP2650_ADDRESS, 0x00, 0xff); + rc = mp2650_config_interface(REG2F_MP2650_ADDRESS, 0x15, 0xff); + return 0; +} + +static int mp2650_set_charger_vsys_threshold(int val) +{ + int rc; + struct mp2650_charger *chip = s_mcharger; + + if(atomic_read(&chip->charger_suspended) == 1) { + return 0; + } + + //change Vsys Skip threshold + rc = mp2650_config_interface(REG31_MP2650_ADDRESS, val, 0xff); + + return rc; +} + +static int mp2650_burst_mode_enable(bool enable) +{ + int rc; + struct mp2650_charger *chip = s_mcharger; + + if(atomic_read(&chip->charger_suspended) == 1) { + return 0; + } + + //Enable or disable Burst mode + if (enable) + rc = mp2650_config_interface(REG37_MP2650_ADDRESS, 0x67, 0xff); + else + rc = mp2650_config_interface(REG37_MP2650_ADDRESS, 0x66, 0xff); + + return rc; +} + +#define DUMP_REG_LOG_CNT_30S 6 +static void mp2650_dump_registers(void) +{ + int rc; + int addr; + static int dump_count = 0; + struct mp2650_charger *chg = s_mcharger; + unsigned int val_buf[MP2650_DUMP_MAX_REG + 3] = {0x0}; + + if(atomic_read(&chg->charger_suspended) == 1) { + return ; + } + + if(dump_count == DUMP_REG_LOG_CNT_30S) { + dump_count = 0; + for (addr = MP2650_FIRST_REG; addr <= MP2650_DUMP_MAX_REG; addr++) { + rc = mp2650_read_reg(addr, &val_buf[addr]); + if (rc) { + chg_err("Couldn't read 0x%02x rc = %d\n", addr, rc); + } + } + rc = mp2650_read_reg(0x48, &val_buf[MP2650_DUMP_MAX_REG + 1]); + if (rc) { + chg_err("Couldn't read 0x48 rc = %d\n", rc); + } + rc = mp2650_read_reg(0x49, &val_buf[MP2650_DUMP_MAX_REG + 2]); + if (rc) { + chg_err("Couldn't read 0x49 rc = %d\n", rc); + } + + printk(KERN_ERR "mp2650_dump_reg: [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x],\ + [reg48=0x%02x,reg49=0x%02x]\n", + val_buf[0], val_buf[1], val_buf[2], val_buf[3], val_buf[4], + val_buf[5], val_buf[6], val_buf[7], val_buf[8], val_buf[9], + val_buf[10], val_buf[11], val_buf[12], val_buf[13], val_buf[14], + val_buf[15], val_buf[16], val_buf[17], val_buf[18], val_buf[19], + val_buf[20], val_buf[21], val_buf[22], val_buf[23], val_buf[24], + val_buf[25], val_buf[26], val_buf[27], val_buf[28], val_buf[29], + val_buf[30], val_buf[31], val_buf[32], val_buf[33], val_buf[34], + val_buf[35], val_buf[36]); + } + dump_count++; +} +bool mp2650_need_to_check_ibatt(void) +{ + return false; +} + +int mp2650_get_chg_current_step(void) +{ + int rc = 50; + + return rc; +} + +static int mp2650_input_current_limit_init(void) +{ + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if (atomic_read(&chg->charger_suspended) == 1) { + chg_err("mp2650_input_current_limit_init: in suspended\n"); + return 0; + } + rc = mp2650_config_interface(REG00_MP2650_ADDRESS, REG00_MP2650_1ST_CURRENT_LIMIT_500MA, REG00_MP2650_1ST_CURRENT_LIMIT_MASK); + rc = mp2650_config_interface(REG0F_MP2650_ADDRESS, REG00_MP2650_1ST_CURRENT_LIMIT_500MA, REG0F_MP2650_2ND_CURRENT_LIMIT_MASK); + + if (rc < 0) { + chg_err("Couldn't mp2650_input_current_limit_init rc = %d\n", rc); + } + + return rc; +} + +static int mp2650_input_current_limit_without_aicl(int current_ma) +{ + int rc = 0; + int reg_val = 0; + struct mp2650_charger *chg = s_mcharger; + + if (atomic_read(&chg->charger_suspended) == 1) { + chg_err("mp2650_input_current_limit_init: in suspended\n"); + return 0; + } + chg->pre_current_ma = current_ma; + + reg_val = current_ma / REG00_MP2650_1ST_CURRENT_LIMIT_STEP; + chg_err(" reg_val current [%d]-%dma\n", reg_val, current_ma); + rc = mp2650_config_interface(REG00_MP2650_ADDRESS, reg_val, REG00_MP2650_1ST_CURRENT_LIMIT_MASK); + rc = mp2650_config_interface(REG0F_MP2650_ADDRESS, reg_val, REG0F_MP2650_2ND_CURRENT_LIMIT_MASK); + + if (rc < 0) { + chg_err("Couldn't mp2650_input_current_limit_init rc = %d\n", rc); + } + + //debug only, remove after stable. + //cancel_delayed_work_sync(&chg->dump_reg_work); + //schedule_delayed_work(&chg->dump_reg_work, msecs_to_jiffies(1500)); + chg->sw_aicl_result_ma = current_ma; + + return rc; +} + +#define DEC_STEP 500 +#define INC_STEP 200 +static int mp2650_input_current_limit_sw_aicl(int current_ma) +{ + int rc = 0; + int tmp = 0; + int tmp_bit = 0; + int count =0; + int step = 0; + int vbus = 0; + int cur_now = 0; + int dec_target = 0; + struct mp2650_charger *chg = s_mcharger; + + if(atomic_read(&chg->charger_suspended) == 1) { + return 0; + } + + rc = mp2650_read_reg(REG00_MP2650_ADDRESS, &tmp_bit); + if (rc) { + chg_err("Couldn't read REG00_mp2650_ADDRESS rc = %d\n", rc); + return 0; + } + + tmp = tmp_bit * 50; + // warp(target ICL greater than 3A) decrease to 1A. + if (current_ma > 3000) + dec_target = 1000 / DEC_STEP; + else + dec_target = 500 / DEC_STEP; + + count = tmp / DEC_STEP; + //chg_info("tmp=%d,count=%d", tmp, count); + for (; count >= dec_target; count--) { + tmp = DEC_STEP * count - REG00_MP2650_1ST_CURRENT_LIMIT_OFFSET; + chg_err("set charge current limit = %d\n", tmp); + tmp_bit = tmp / REG00_MP2650_1ST_CURRENT_LIMIT_STEP; + rc = mp2650_config_interface(REG00_MP2650_ADDRESS, tmp_bit << REG00_MP2650_1ST_CURRENT_LIMIT_SHIFT, REG00_MP2650_1ST_CURRENT_LIMIT_MASK); + rc = mp2650_config_interface(REG0F_MP2650_ADDRESS, tmp_bit << REG0F_MP2650_2ND_CURRENT_LIMIT_SHIFT, REG0F_MP2650_2ND_CURRENT_LIMIT_MASK); + msleep(25); + } + + //mp2650_set_vindpm_vol(4400); + + step = (current_ma - tmp) / INC_STEP; + cur_now = tmp + (current_ma - tmp) % INC_STEP; + //chg_info("step=%d,cur_now=%d", step, cur_now); + for (count = 0; count <= step; count++) { + tmp = cur_now + INC_STEP * count - REG00_MP2650_1ST_CURRENT_LIMIT_OFFSET; + chg_err("set charge current limit = %d\n", tmp); + tmp_bit = tmp / REG00_MP2650_1ST_CURRENT_LIMIT_STEP; + rc = mp2650_config_interface(REG00_MP2650_ADDRESS, tmp_bit << REG00_MP2650_1ST_CURRENT_LIMIT_SHIFT, REG00_MP2650_1ST_CURRENT_LIMIT_MASK); + rc = mp2650_config_interface(REG0F_MP2650_ADDRESS, tmp_bit << REG0F_MP2650_2ND_CURRENT_LIMIT_SHIFT, REG0F_MP2650_2ND_CURRENT_LIMIT_MASK); + msleep(90); + mp2650_get_vbus_voltage(&vbus); + if (vbus <= chg->sw_aicl_point) + break; + } + + tmp = count > step ? current_ma : (tmp - 200); + tmp_bit = tmp / REG00_MP2650_1ST_CURRENT_LIMIT_STEP; + chg_info("setting ICL=%d", tmp); + rc = mp2650_config_interface(REG00_MP2650_ADDRESS, tmp_bit << REG00_MP2650_1ST_CURRENT_LIMIT_SHIFT, REG00_MP2650_1ST_CURRENT_LIMIT_MASK); + rc = mp2650_config_interface(REG0F_MP2650_ADDRESS, tmp_bit << REG0F_MP2650_2ND_CURRENT_LIMIT_SHIFT, REG0F_MP2650_2ND_CURRENT_LIMIT_MASK); + + mp2650_set_vindpm_vol(chg->hw_aicl_point); + chg->sw_aicl_result_ma = tmp; + return rc; +} + +int mp2650_parse_dt(void) +{ + return 0; +} + +int mp2650_hardware_init(void) +{ + struct mp2650_charger *chg = s_mcharger; + + chg_err("init mp2650 hardware! \n"); + + //must be before set_vindpm_vol and set_input_current + chg->hw_aicl_point = 4440; + chg->sw_aicl_point = 4650; + chg->sw_aicl_result_ma = 500; + + mp2650_reset_charger(); + mp2650_enable_charging(chg, false); + + mp2650_set_chging_term_enable(false); + + mp2650_input_current_limit_init(); + + mp2650_float_voltage_write(WPC_TERMINATION_VOLTAGE); + + mp2650_otg_ilim_set(MP2650_OTG_CURRENT_LIMIT_DEFAULT); + + mp2650_set_enable_volatile_writes(); + + mp2650_set_complete_charge_timeout(OVERTIME_DISABLED); + + mp2650_set_prechg_voltage_threshold(REG07_MP2650_PRECHARGE_THRESHOLD_7200MV); + chg->pre_chg_thd_6600 = false; + + mp2650_set_prechg_current(WPC_PRECHARGE_CURRENT); + + mp2650_charging_current_write_fast(WPC_CHARGE_CURRENT_DEFAULT); + + mp2650_set_termchg_current(WPC_TERMINATION_CURRENT); + + mp2650_set_rechg_voltage(WPC_RECHARGE_VOLTAGE_OFFSET); + + mp2650_set_switching_frequency(); + + mp2650_set_vindpm_vol(chg->hw_aicl_point); + + mp2650_set_mps_otg_voltage(false); + + mp2650_set_mps_otg_enable(true); + + mp2650_other_registers_init(); + + mp2650_enable_suspend_charger(false); + + mp2650_enable_charging(chg, true); + + mp2650_set_wdt_timer(REG09_MP2650_WTD_TIMER_40S); + + return true; +} + +#ifdef CONFIG_OP_RTC_DET_SUPPORT +static int rtc_reset_check(void) +{ + struct rtc_time tm; + struct rtc_device *rtc; + int rc = 0; + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc == NULL) { + pr_err("%s: unable to open rtc device (%s)\n", + __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); + return 0; + } + + rc = rtc_read_time(rtc, &tm); + if (rc) { + pr_err("Error reading rtc device (%s) : %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + rc = rtc_valid_tm(&tm); + if (rc) { + pr_err("Invalid RTC time (%s): %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + if ((tm.tm_year == 110) && (tm.tm_mon == 0) && (tm.tm_mday <= 1)) { + chg_debug(": Sec: %d, Min: %d, Hour: %d, Day: %d, Mon: %d, Year: %d @@@ wday: %d, yday: %d, isdst: %d\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, + tm.tm_wday, tm.tm_yday, tm.tm_isdst); + rtc_class_close(rtc); + return 1; + } + + chg_debug(": Sec: %d, Min: %d, Hour: %d, Day: %d, Mon: %d, Year: %d ### wday: %d, yday: %d, isdst: %d\n", + tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon, tm.tm_year, + tm.tm_wday, tm.tm_yday, tm.tm_isdst); + + close_time: + rtc_class_close(rtc); + return 0; +} +#endif /* CONFIG_OP_RTC_DET_SUPPORT */ + +static int mp2650_mps_otg_en_gpio_init(struct mp2650_charger *chg) +{ + + if (!chg) { + printk(KERN_ERR "[OP_CHG][%s]: mp2650_charger not ready!\n", __func__); + return -EINVAL; + } + + chg->pinctrl = devm_pinctrl_get(chg->dev); + if (IS_ERR_OR_NULL(chg->pinctrl)) { + chg_err("get mps_otg_en pinctrl fail\n"); + return -EINVAL; + } + + chg->mps_otg_en_active = pinctrl_lookup_state(chg->pinctrl, "mps_otg_en_active"); + if (IS_ERR_OR_NULL(chg->mps_otg_en_active)) { + chg_err("get mps_otg_en_active fail\n"); + return -EINVAL; + } + + chg->mps_otg_en_sleep = pinctrl_lookup_state(chg->pinctrl, "mps_otg_en_sleep"); + if (IS_ERR_OR_NULL(chg->mps_otg_en_sleep)) { + chg_err("get mps_otg_en fail\n"); + return -EINVAL; + } + + chg->mps_otg_en_default = pinctrl_lookup_state(chg->pinctrl, "mps_otg_en_default"); + if (IS_ERR_OR_NULL(chg->mps_otg_en_default)) { + chg_err("get mps_otg_en_default fail\n"); + return -EINVAL; + } + + + pinctrl_select_state(chg->pinctrl, chg->mps_otg_en_sleep); + chg_err("gpio_val:%d\n", gpio_get_value(chg->mps_otg_en_gpio)); + + return 0; +} + +static int mp2650_gpio_init(struct mp2650_charger *chg) +{ + + int rc=0; + struct device_node *node = chg->dev->of_node; + + // Parsing gpio mps_otg_en + chg->mps_otg_en_gpio = of_get_named_gpio(node, "mp,mps_otg_en-gpio", 0); + if(chg->mps_otg_en_gpio < 0 ){ + pr_err("chg->mps_otg_en_gpio not specified\n"); + } + else + { + if( gpio_is_valid(chg->mps_otg_en_gpio) ){ + rc = gpio_request(chg->mps_otg_en_gpio, "mps_otg_en-gpio"); + if(rc){ + pr_err("unable to request gpio [%d]\n", chg->mps_otg_en_gpio); + } + } + rc = mp2650_mps_otg_en_gpio_init(chg); + pr_err("chg->mps_otg_en_gpio =%d\n",chg->mps_otg_en_gpio); + } + + + chg_err(" mp2650_gpio_init FINISH\n"); + + return rc; +} + +static void mp2650_set_mps_otg_en_val(int value) +{ + struct mp2650_charger *chg = s_mcharger; + if (!chg) { + printk(KERN_ERR "[OP_CHG][%s]: mp2650_charger not ready!\n", __func__); + return; + } + + if (chg->mps_otg_en_gpio <= 0) { + chg_err("mps_otg_en_gpio not exist, return\n"); + return; + } + + if (IS_ERR_OR_NULL(chg->pinctrl) + || IS_ERR_OR_NULL(chg->mps_otg_en_active) + || IS_ERR_OR_NULL(chg->mps_otg_en_sleep) + || IS_ERR_OR_NULL(chg->mps_otg_en_default)) { + chg_err("pinctrl null, return\n"); + return; + } + + if (value) { + gpio_direction_output(chg->mps_otg_en_gpio, 1); + pinctrl_select_state(chg->pinctrl, + chg->mps_otg_en_active); + } else { + gpio_direction_output(chg->mps_otg_en_gpio, 0); + pinctrl_select_state(chg->pinctrl, + chg->mps_otg_en_default); + } + + chg_err("<~WPC~>set value:%d, gpio_val:%d\n", + value, gpio_get_value(chg->mps_otg_en_gpio)); +} + +int mp2650_get_mps_otg_en_val(void) +{ + struct mp2650_charger *chg = s_mcharger; + + if (!chg) { + printk(KERN_ERR "[OP_CHG][%s]: mp2650_charger not ready!\n", __func__); + return -1; + } + + if (chg->mps_otg_en_gpio <= 0) { + chg_err("mps_otg_en_gpio not exist, return\n"); + return -1; + } + + if (IS_ERR_OR_NULL(chg->pinctrl) + || IS_ERR_OR_NULL(chg->mps_otg_en_active) + || IS_ERR_OR_NULL(chg->mps_otg_en_sleep) + || IS_ERR_OR_NULL(chg->mps_otg_en_default)) { + chg_err("pinctrl null, return\n"); + return -1; + } + + return gpio_get_value(chg->mps_otg_en_gpio); +} +#ifdef DEBUG_BY_FILE_OPS +char mp2650_add; + +/*echo "xx" > /proc/mp2650_write_log*/ +static ssize_t mp2650_data_log_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + char write_data[32] = {0}; + int critical_log = 0; + int rc; + + if (copy_from_user(&write_data, buff, len)) { + pr_err("mp2650_data_log_write error.\n"); + return -EFAULT; + } + + write_data[len] = '\0'; + if(write_data[len - 1] == '\n') { + write_data[len - 1] = '\0'; + } + + critical_log = (int)simple_strtoul(write_data, NULL, 10); + if(critical_log > 256) { + critical_log = 256; + } + + pr_err("%s: input data = %s, write_mp2650_data = 0x%02X\n", __func__, write_data, critical_log); + + rc = mp2650_config_interface(mp2650_add, critical_log, 0xff); + if (rc) { + chg_err("Couldn't write 0x%02X rc = %d\n", mp2650_add, rc); + } + + return len; +} + +static const struct file_operations mp2650_write_log_proc_fops = { + .write = mp2650_data_log_write, +}; +static void init_mp2650_write_log(void) +{ + struct proc_dir_entry *p = NULL; + + p = proc_create("mp2650_write_log", 0664, NULL, &mp2650_write_log_proc_fops); + if (!p) { + pr_err("proc_create mp2650_write_log fail!\n"); + } +} + +/*echo "xx" > /proc/mp2650_read_log*/ +static ssize_t mp2650_data_log_read(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + char write_data[32] = {0}; + int critical_log = 0; + int rc; + int val_buf; + + if (copy_from_user(&write_data, buff, len)) { + pr_err("mp2650_data_log_read error.\n"); + return -EFAULT; + } + + write_data[len] = '\0'; + if(write_data[len - 1] == '\n') { + write_data[len - 1] = '\0'; + } + + critical_log = (int)simple_strtoul(write_data, NULL, 10); + if(critical_log > 256) { + critical_log = 256; + } + + mp2650_add = critical_log; + + pr_err("%s: input data = %s, mp2650_addr = 0x%02X\n", __func__, write_data, mp2650_add); + + rc = mp2650_read_reg(mp2650_add, &val_buf); + if (rc) { + chg_err("Couldn't read 0x%02X rc = %d\n", mp2650_add, rc); + } else { + chg_err("mp2650_read 0x%02X = 0x%02X\n", mp2650_add, val_buf); + } + + return len; +} + +static const struct file_operations mp2650_read_log_proc_fops = { + .write = mp2650_data_log_read, +}; + +static void init_mp2650_read_log(void) +{ + struct proc_dir_entry *p = NULL; + + p = proc_create("mp2650_read_log", 0664, NULL, &mp2650_read_log_proc_fops); + if (!p) { + pr_err("proc_create mp2650_read_log fail!\n"); + } +} +#endif /*DEBUG_BY_FILE_OPS*/ + +#ifdef MP2762_CP_PSY +static enum power_supply_property mp2650_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_OTG_SWITCH, + POWER_SUPPLY_PROP_CHARGE_ENABLED, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_INPUT_SUSPEND, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_CP_SWITCHER_EN, +}; + +static int mp2650_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct mp2650_charger *chg = power_supply_get_drvdata(psy); + int rc = 0; + int val_mx; + + if (!chg) + return -ENODEV; + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + rc = mp2650_get_charge_status(&val_mx); + if (rc) + val->intval = 0; + else + val->intval = val_mx; + break; + case POWER_SUPPLY_PROP_OTG_SWITCH: + val->intval = chg->otg_enabled?1:0; + break; + case POWER_SUPPLY_PROP_CHARGE_ENABLED: + val->intval = mp2650_check_charging_enable(chg)?1:0; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + rc = mp2650_get_vbus_voltage(&val_mx); + if (rc < 0) + val->intval = 0; + else + val->intval = val_mx * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + rc = mp2650_get_ibus_current(&val_mx); + if (rc < 0) + val->intval = 0; + else + val->intval = val_mx; // getted ua + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = chg->sw_aicl_result_ma * 1000; + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + rc = mp2650_charging_current_read_fast(&val_mx); + if (rc) + val->intval = 0; + else + val->intval = val_mx * 1000; + break; + case POWER_SUPPLY_PROP_INPUT_SUSPEND: + val->intval = chg->input_suspend?1:0; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + rc = mp2650_float_voltage_read(&val_mx); + if (rc) + val->intval = 0; + else + val->intval = val_mx * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + val->intval = mp2650_get_vindpm_vol(); + if (val->intval <= 0) + val->intval = chg->hw_aicl_point; + break; + case POWER_SUPPLY_PROP_CP_SWITCHER_EN: + val->intval = chg->buck_switcher_on?1:0; + break; + case POWER_SUPPLY_PROP_OTG_OCL: + rc = mp2650_otg_ilim_get(&val_mx); + val->intval = val_mx * 1000; + break; + case POWER_SUPPLY_PROP_HWTERM: + val->intval = 0; + break; + case POWER_SUPPLY_PROP_SWAICL: + val->intval = chg->sw_aicl_result_ma * 1000; + break; + case POWER_SUPPLY_PROP_VSYS_THD: + val->intval = 0; + break; + case POWER_SUPPLY_PROP_EN_BURST: + val->intval = 0; + break; + default: + chg_err("mp2650 power supply prop %d not supported\n", psp); + return -EINVAL; + } + + if (rc < 0) { + chg_err("Couldn't get prop %d rc = %d\n", psp, rc); + return -ENODATA; + } + + return 0; +} + +static int mp2650_set_prop(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + int rc = 0; + int val_mx; + struct mp2650_charger *chg = power_supply_get_drvdata(psy); + + if (!chg) + return -ENODEV; + switch (prop) { + case POWER_SUPPLY_PROP_OTG_SWITCH: + if (val->intval == 1) + rc = mp2650_otg_enable(chg, true); + else + rc = mp2650_otg_enable(chg, false); + break; + case POWER_SUPPLY_PROP_CHARGE_ENABLED: + if (val->intval == 1) + rc = mp2650_enable_charging(chg, true); + else + rc = mp2650_enable_charging(chg, false); + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + val_mx = val->intval / 1000; // ua to ma + rc = mp2650_input_current_limit_without_aicl(val_mx); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + val_mx = val->intval / 1000; // ua to ma + rc = mp2650_charging_current_write_fast(val_mx); + break; + case POWER_SUPPLY_PROP_INPUT_SUSPEND: + if (val->intval == 1) + rc = mp2650_enable_suspend_charger(true); + else + rc = mp2650_enable_suspend_charger(false); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + val_mx = val->intval / 1000; // uv to mv + rc = mp2650_float_voltage_write(val_mx); + if (rc) + chg_err("set float voltage fail, rc=%d", rc); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + mp2650_set_aicl_point(val->intval); + rc = 0; + break; + case POWER_SUPPLY_PROP_CP_SWITCHER_EN: + if (val->intval == 1) + rc = mp2650_enable_buck_switch(true); + else + rc = mp2650_enable_buck_switch(false); + break; + case POWER_SUPPLY_PROP_OTG_OCL: + val_mx = val->intval / 1000; // ua to ma + rc = mp2650_otg_ilim_set(val_mx); + break; + case POWER_SUPPLY_PROP_HWTERM: + if (val->intval == 1) { + rc = mp2650_set_termchg_current(100); + rc = mp2650_set_chging_term_enable(true); + } else { + rc = mp2650_set_chging_term_enable(false); + rc = mp2650_set_termchg_current(WPC_TERMINATION_CURRENT); + } + break; + case POWER_SUPPLY_PROP_SWAICL: + val_mx = val->intval / 1000; // ua to ma + mp2650_input_current_limit_sw_aicl(val_mx); + rc = 0; + break; + case POWER_SUPPLY_PROP_VSYS_THD: + mp2650_set_charger_vsys_threshold(val->intval); + break; + case POWER_SUPPLY_PROP_EN_BURST: + val_mx = val->intval; + mp2650_burst_mode_enable(!!val_mx); + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static int mp2650_prop_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_OTG_SWITCH: + case POWER_SUPPLY_PROP_CHARGE_ENABLED: + case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + case POWER_SUPPLY_PROP_INPUT_SUSPEND: + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + case POWER_SUPPLY_PROP_CP_SWITCHER_EN: + return 1; + default: + break; + } + + return 0; +} + +static const struct power_supply_desc mp2650_psy_desc = { + .name = "op_charger", + .type = POWER_SUPPLY_TYPE_PARALLEL, + .properties = mp2650_props, + .num_properties = ARRAY_SIZE(mp2650_props), + .get_property = mp2650_get_prop, + .set_property = mp2650_set_prop, + .property_is_writeable = mp2650_prop_is_writeable, +}; + +static int mp2650_init_psy(struct mp2650_charger *chg) +{ + struct power_supply_config mp2650_cfg = {}; + int rc = 0; + + mp2650_cfg.drv_data = chg; + mp2650_cfg.of_node = chg->dev->of_node; + chg->cp_psy = devm_power_supply_register(chg->dev, + &mp2650_psy_desc, + &mp2650_cfg); + if (IS_ERR(chg->cp_psy)) { + chg_err("Couldn't register battery power supply\n"); + return PTR_ERR(chg->cp_psy); + } + + return rc; +} +#endif + +static bool mp2650_is_writeable_reg(struct device *dev, unsigned int reg) +{ + unsigned int addr; + + addr = reg; + if ((addr >= 0x00 && addr <= 0x12) + || (addr == 0x31) || (addr == 0x33) + || (addr == 0x36)) + return true; + return false; +} + +static struct regmap_config mp2650_regmap_config = { + .name = "mp2650", + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x48, + .writeable_reg = mp2650_is_writeable_reg, +}; + +static void mp2650_dump_reg_work(struct work_struct *work) +{ + int i = 0, rc = 0; + int reg_val = 0; + + for (i = 0; i <= 0x48; i++) { + rc = mp2650_read_reg(i, ®_val); + if (rc) + chg_err("read reg 0x%2x error rc=%d.", i, rc); + chg_err("reg 0x%02x value=0x%02x", i, reg_val); + } +} + +static int mp2650_driver_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = 0; + struct mp2650_charger *chg_ic; + + chg_ic = devm_kzalloc(&client->dev, + sizeof(struct mp2650_charger), GFP_KERNEL); + if (!chg_ic) { + chg_err(" kzalloc() failed\n"); + return -ENOMEM; + } + + chg_debug( " call \n"); + chg_ic->client = client; + chg_ic->dev = &client->dev; + chg_ic->regmap = devm_regmap_init_i2c(client, &mp2650_regmap_config); + if (!chg_ic->regmap) { + chg_err("regmap init error."); + return -ENODEV; + } + + s_mcharger = chg_ic; + atomic_set(&chg_ic->charger_suspended, 0); + mp2650_dump_registers(); + mp2650_vbus_avoid_electric_config(); + mp2650_parse_dt(); + mp2650_hardware_init(); + mp2650_gpio_init(chg_ic); + + ret = sysfs_create_group(&chg_ic->dev->kobj, &mp2650_attribute_group); + if (ret < 0) { + chg_debug(" sysfs_create_group error fail\n"); + ///return ret; + } + +#ifdef DEBUG_BY_FILE_OPS + init_mp2650_write_log(); + init_mp2650_read_log(); +#endif + mp2650_init_psy(chg_ic); + + INIT_DELAYED_WORK(&chg_ic->dump_reg_work, mp2650_dump_reg_work); + + chg_debug(" success\n"); + + return ret; +} + +static struct i2c_driver mp2650_i2c_driver; + +static int mp2650_driver_remove(struct i2c_client *client) +{ + + int ret=0; + + //ret = i2c_del_driver(&mp2650_i2c_driver); + chg_debug( " ret = %d\n", ret); + return 0; +} + +static unsigned long suspend_tm_sec = 0; +static int get_current_time(unsigned long *now_tm_sec) +{ + struct rtc_time tm; + struct rtc_device *rtc = NULL; + int rc = 0; + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc == NULL) { + chg_err("%s: unable to open rtc device (%s)\n", + __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); + return -EINVAL; + } + + rc = rtc_read_time(rtc, &tm); + if (rc) { + chg_err("Error reading rtc device (%s) : %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + rc = rtc_valid_tm(&tm); + if (rc) { + chg_err("Invalid RTC time (%s): %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + rtc_tm_to_time(&tm, now_tm_sec); + + close_time: + rtc_class_close(rtc); + return rc; +} + +#ifdef CONFIG_PM_SLEEP +static int mp2650_pm_resume(struct device *dev) +{ + unsigned long resume_tm_sec = 0; + unsigned long sleep_time = 0; + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(!chg) { + return 0; + } + atomic_set(&chg->charger_suspended, 0); + rc = get_current_time(&resume_tm_sec); + if (rc || suspend_tm_sec == -1) { + chg_err("RTC read failed\n"); + sleep_time = 0; + } else { + sleep_time = resume_tm_sec - suspend_tm_sec; + } + + return 0; + +} + +static int mp2650_pm_suspend(struct device *dev) +{ + struct mp2650_charger *chg = s_mcharger; + + if(!chg) { + return 0; + } + atomic_set(&chg->charger_suspended, 1); + if (get_current_time(&suspend_tm_sec)) { + chg_err("RTC read failed\n"); + suspend_tm_sec = -1; + } + return 0; + +} + +static const struct dev_pm_ops mp2650_pm_ops = { + .resume = mp2650_pm_resume, + .suspend = mp2650_pm_suspend, +}; +#else +static int mp2650_resume(struct i2c_client *client) +{ + unsigned long resume_tm_sec = 0; + unsigned long sleep_time = 0; + int rc = 0; + struct mp2650_charger *chg = s_mcharger; + + if(!chg) { + return 0; + } + atomic_set(&chg->charger_suspended, 0); + rc = get_current_time(&resume_tm_sec); + if (rc || suspend_tm_sec == -1) { + chg_err("RTC read failed\n"); + sleep_time = 0; + } else { + sleep_time = resume_tm_sec - suspend_tm_sec; + } + + return 0; +} + +static int mp2650_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct mp2650_charger *chg = s_mcharger; + + if(!chg) { + return 0; + } + atomic_set(&chg->charger_suspended, 1); + if (get_current_time(&suspend_tm_sec)) { + chg_err("RTC read failed\n"); + suspend_tm_sec = -1; + } + return 0; +} +#endif + +static void mp2650_reset(struct i2c_client *client) +{ + struct mp2650_charger *chg = s_mcharger; + mp2650_otg_enable(chg, false); +} + +/********************************************************** + * + * [platform_driver API] + * + *********************************************************/ + +static const struct of_device_id mp2650_match[] = { + { .compatible = "op,mp2650-charger"}, + { }, +}; + +static const struct i2c_device_id mp2650_id[] = { + {"mp2650-charger", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, mp2650_id); + +static struct i2c_driver mp2650_i2c_driver = { + .driver = { + .name = "mp2650-charger", + .owner = THIS_MODULE, + .of_match_table = mp2650_match, +#ifdef CONFIG_PM_SLEEP + .pm = &mp2650_pm_ops, +#endif + }, + .probe = mp2650_driver_probe, + .remove = mp2650_driver_remove, +#ifndef CONFIG_PM_SLEEP + .resume = mp2650_resume, + .suspend = mp2650_suspend, +#endif + .shutdown = mp2650_reset, + .id_table = mp2650_id, +}; + +module_i2c_driver(mp2650_i2c_driver); +MODULE_DESCRIPTION("Driver for mp2650 charger chg"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:mp2650-charger"); diff --git a/drivers/oneplus/power/supply/qcom/op_mp2650.h b/drivers/oneplus/power/supply/qcom/op_mp2650.h new file mode 100644 index 0000000000000000000000000000000000000000..7f072dd7db880dd0280f1626bb1851a9010f92cf --- /dev/null +++ b/drivers/oneplus/power/supply/qcom/op_mp2650.h @@ -0,0 +1,604 @@ +/************************************************************************************ +** --------------------------- Revision History: ------------------------------------------------------------ +* +* Revision 1.0 2015-06-22 Fanhong.Kong@ProDrv.CHG Created for new architecture +************************************************************************************************************/ + + +#ifndef __OP_MP2650_H__ + +#define __OP_MP2650_H__ + +#define OP_MP2650 + +#include +#include + +#define chg_debug(fmt, ...) \ + printk(KERN_NOTICE "[SWARPCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define chg_err(fmt, ...) \ + printk(KERN_ERR "[SWARPCHG][%s]" fmt, __func__, ##__VA_ARGS__) + +#define chg_info(fmt, ...) \ + printk(KERN_INFO "[SWARPCHG][%s]" fmt, __func__, ##__VA_ARGS__) + + +#define WPC_PRECHARGE_CURRENT 480 + +#define MP2650_FIRST_REG 0x00 +#define MP2650_DUMP_MAX_REG 0x22 +#define MP2650_LAST_REG 0x48 +#define MP2650_REG_NUMBER 0x30 + + +/* Address:00h */ +#define REG00_MP2650_ADDRESS 0x00 + +#define REG00_MP2650_1ST_CURRENT_LIMIT_MASK (BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_SHIFT 0 +#define REG00_MP2650_1ST_CURRENT_LIMIT_OFFSET 0 +#define REG00_MP2650_1ST_CURRENT_LIMIT_STEP 50 //default 3A +#define REG00_MP2650_1ST_CURRENT_LIMIT_500MA (BIT(3) | BIT(1)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_900MA (BIT(4) | BIT(1)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1100MA (BIT(4) | BIT(2) | BIT(1)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1200MA (BIT(4) | BIT(3)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1350MA (BIT(4) | BIT(3) | BIT(1) | BIT(0)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1400MA (BIT(4) |BIT(3) |BIT(2)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1500MA (BIT(4) |BIT(3) |BIT(2) |BIT(1)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1600MA (BIT(5)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1700MA (BIT(5) | BIT(1)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_1900MA (BIT(5) | BIT(2) | BIT(1)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_2000MA (BIT(5) | BIT(3)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_2400MA (BIT(5) | BIT(4)) +#define REG00_MP2650_1ST_CURRENT_LIMIT_3600MA (BIT(6) | BIT(3)) + +/* Address:01h */ +#define REG01_MP2650_ADDRESS 0x01 + +#define REG01_MP2650_VINDPM_THRESHOLD_MASK (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG01_MP2650_VINDPM_THRESHOLD_SHIFT 0 +#define REG01_MP2650_VINDPM_THRESHOLD_OFFSET 0 +#define REG01_MP2650_VINDPM_THRESHOLD_STEP 100 //default 4.5V + + +/* Address:02h */ +#define REG02_MP2650_ADDRESS 0x02 + +#define REG02_MP2650_CHARGE_CURRENT_SETTING_MASK (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG02_MP2650_CHARGE_CURRENT_SETTING_SHIFT 0 +#define REG02_MP2650_CHARGE_CURRENT_SETTING_OFFSET 0 +#define REG02_MP2650_CHARGE_CURRENT_SETTING_STEP 50 //default 3A + + +/* Address:03h */ +#define REG03_MP2650_ADDRESS 0x03 + +#define REG03_MP2650_TERMINATION_CURRENT_LIMIT_MASK (BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG03_MP2650_TERMINATION_CURRENT_LIMIT_SHIFT 0 +#define REG03_MP2650_TERMINATION_CURRENT_LIMIT_OFFSET 0 +#define REG03_MP2650_TERMINATION_CURRENT_LIMIT_STEP 100 //default 200mA +#define REG03_MP2650_TERMINATION_CURRENT_600MA (BIT(2) | BIT(1)) +#define REG03_MP2650_TERMINATION_CURRENT_200MA BIT(1) +#define REG03_MP2650_TERMINATION_CURRENT_100MA BIT(0) + +#define REG03_MP2650_PRECHARGE_CURRENT_LIMIT_MASK (BIT(7) | BIT(6) | BIT(5) | BIT(4)) +#define REG03_MP2650_PRECHARGE_CURRENT_LIMIT_SHIFT 4 +#define REG03_MP2650_PRECHARGE_CURRENT_LIMIT_OFFSET 0 +#define REG03_MP2650_PRECHARGE_CURRENT_LIMIT_STEP 60 //default 400mA + + +/* Address:04h */ +#define REG04_MP2650_ADDRESS 0x04 + +#define REG04_MP2650_BAT_RECHARGE_THRESHOLD_MASK BIT(0) +#define REG04_MP2650_BAT_RECHARGE_THRESHOLD_100MV 0//default +#define REG04_MP2650_BAT_RECHARGE_THRESHOLD_200MV BIT(0) +#define REG04_MP2650_BAT_RECHARGE_THRESHOLD_SHIFT 0//default +#define REG04_MP2650_BAT_RECHARGE_THRESHOLD_OFFSET 100 +#define REG04_MP2650_BAT_RECHARGE_THRESHOLD_STEP 100 + +#define REG04_MP2650_CHARGE_FULL_VOL_MASK (BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)) +#define REG04_MP2650_CHARGE_FULL_VOL_SHIFT 1 +#define REG04_MP2650_CHARGE_FULL_VOL_OFFSET 37125 +#define REG04_MP2650_CHARGE_FULL_VOL_STEP 125 //12.5mV, default 4.2V + + +/* Address:05h */ +#define REG05_MP2650_ADDRESS 0x05 + +#define REG05_MP2650_THERMAL_REGULATION_THRESHOLD_MASK (BIT(1) | BIT(0)) +#define REG05_MP2650_THERMAL_REGULATION_THRESHOLD_SHIFT 0 +#define REG05_MP2650_THERMAL_REGULATION_THRESHOLD_OFFSET 60 +#define REG05_MP2650_THERMAL_REGULATION_THRESHOLD_STEP 20 //default 120 + +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_CLAMP_MASK (BIT(4) | BIT(3) | BIT(2)) +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_CLAMP_SHIFT 2 +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_CLAMP_OFFSET 0 +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_CLAMP_STEP 30 //default 0mV + +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_SETTING_MASK (BIT(7) | BIT(6) | BIT(5)) +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_SETTING_SHIFT 5 +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_SETTING_OFFSET 0 +#define REG05_MP2650_IR_COMPENSATION_RESISTOR_SETTING_STEP 25 //default 0mO + + +/* Address:06h */ +#define REG06_MP2650_ADDRESS 0x06 + +#define REG06_MP2650_2ND_OTG_VOL_SETTING_MASK (BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG06_MP2650_2ND_OTG_VOL_SETTING_SHIFT 0 +#define REG06_MP2650_2ND_OTG_VOL_SETTING_OFFSET 0 +#define REG06_MP2650_2ND_OTG_VOL_SETTING_STEP 50 //default 250mV +#define REG06_MP2650_2ND_OTG_VOL_SETTING_250MV (BIT(2) | BIT(0)) + +#define REG06_MP2650_OTG_VOL_OPTION_MASK (BIT(6) | BIT(5) | BIT(4)) +#define REG06_MP2650_OTG_VOL_OPTION_SHIFT 4 +#define REG06_MP2650_OTG_VOL_OPTION_4750MV 0 //default +#define REG06_MP2650_OTG_VOL_OPTION_8750MV BIT(4) +#define REG06_MP2650_OTG_VOL_OPTION_11750MV BIT(5) +#define REG06_MP2650_OTG_VOL_OPTION_14750MV (BIT(5) | BIT(4)) +#define REG06_MP2650_OTG_VOL_OPTION_1950MV BIT(6) + + +/* Address:07h */ +#define REG07_MP2650_ADDRESS 0x07 + +#define REG07_MP2650_OTG_CURRENT_LIMIT_MASK (BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG07_MP2650_OTG_CURRENT_LIMIT_SHIFT 0 +#define REG07_MP2650_OTG_CURRENT_LIMIT_OFFSET 0 +#define REG07_MP2650_OTG_CURRENT_LIMIT_STEP 250 //default 1A +#define REG07_MP2650_OTG_CURRENT_LIMIT_1A BIT(2) +#define REG07_MP2650_OTG_CURRENT_LIMIT_1250MA (BIT(2) | BIT(0)) +#define MP2650_OTG_CURRENT_LIMIT_DEFAULT 1500 + +#define REG07_MP2650_PRECHARGE_THRESHOLD_MASK (BIT(5) | BIT(4)) +#define REG07_MP2650_PRECHARGE_THRESHOLD_6600MV 0 +#define REG07_MP2650_PRECHARGE_THRESHOLD_6800MV BIT(4)//default +#define REG07_MP2650_PRECHARGE_THRESHOLD_7400MV BIT(5) +#define REG07_MP2650_PRECHARGE_THRESHOLD_7200MV (BIT(5) | BIT(4)) + +#define REG07_MP2650_BAT_NUMBER_MASK (BIT(7) | BIT(6)) +#define REG07_MP2650_BAT_NUMBER_2_CELL 0 //default +#define REG07_MP2650_BAT_NUMBER_3_CELL BIT(6) +#define REG07_MP2650_BAT_NUMBER_4_CELL BIT(7) + +/* Address:08h */ +#define REG08_MP2650_ADDRESS 0x08 + +#define REG08_MP2650_BFET_ALWON_MASK BIT(0) +#define REG08_MP2650_BFET_ALWON_DEPEND_BFET_EN 0 //default +#define REG08_MP2650_BFET_ALWON_FULL_ON BIT(0) + +#define REG08_MP2650_BFET_EN_MASK BIT(1) +#define REG08_MP2650_BFET_DISABLE 0 +#define REG08_MP2650_BFET_ENABLE BIT(1) //default + +#define REG08_MP2650_NTC_GCOMP_SEL_MASK BIT(2) +#define REG08_MP2650_NTC_GCOMP_SEL_INDEPENDENT 0 +#define REG08_MP2650_NTC_GCOMP_SEL_ORIGINAL BIT(2) //default + +#define REG08_MP2650_LEARN_EN_MASK BIT(3) +#define REG08_MP2650_LEARN_EN_DISABLE 0 //default +#define REG08_MP2650_LEARN_EN_ENABLE BIT(3) + +#define REG08_MP2650_CHG_EN_MASK BIT(4) +#define REG08_MP2650_CHG_EN_DISABLE 0 +#define REG08_MP2650_CHG_EN_ENABLE BIT(4) //default + +#define REG08_MP2650_OTG_EN_MASK BIT(5) +#define REG08_MP2650_OTG_EN_DISABLE 0 //default +#define REG08_MP2650_OTG_EN_ENABLE BIT(5) + +#define REG08_MP2650_WTD_RST_MASK BIT(6) +#define REG08_MP2650_WTD_RST_NORMAL 0 //default +#define REG08_MP2650_WTD_RST_RESET BIT(6) + +#define REG08_MP2650_REG_RST_MASK BIT(7) +#define REG08_MP2650_REG_RST_KEEP 0 //default +#define REG08_MP2650_REG_RST_RESET BIT(7) + + +/* Address:09h */ +#define REG09_MP2650_ADDRESS 0x09 + +#define REG09_MP2650_TIM2X_EN_MASK BIT(0) +#define REG09_MP2650_TIM2X_EN_DISABLE 0 //default +#define REG09_MP2650_TIM2X_EN_ENABLE BIT(0) + +#define REG09_MP2650_FAST_CHARGE_TIMER_MASK (BIT(2) | BIT(1)) +#define REG09_MP2650_FAST_CHARGE_TIMER_5H 0 +#define REG09_MP2650_FAST_CHARGE_TIMER_8H BIT(1) +#define REG09_MP2650_FAST_CHARGE_TIMER_12H BIT(2) //default +#define REG09_MP2650_FAST_CHARGE_TIMER_20H (BIT(2) | BIT(1)) + +#define REG09_MP2650_CHARGE_TIMER_EN_MASK BIT(3) +#define REG09_MP2650_CHARGE_TIMER_EN_DISABLE 0 +#define REG09_MP2650_CHARGE_TIMER_EN_ENABLE BIT(3) //default + +#define REG09_MP2650_WTD_TIMER_MASK (BIT(5) | BIT(4)) +#define REG09_MP2650_WTD_TIMER_DISABLE 0 //default +#define REG09_MP2650_WTD_TIMER_40S BIT(4) +#define REG09_MP2650_WTD_TIMER_80S BIT(5) +#define REG09_MP2650_WTD_TIMER_160S (BIT(5) | BIT(4)) + +#define REG09_MP2650_CHARGE_TERMINATION_EN_MASK BIT(6) +#define REG09_MP2650_CHARGE_TERMINATION_EN_DISABLE 0 +#define REG09_MP2650_CCHARGE_TERMINATION_EN_ENABLE BIT(6) //default + + +/* Address:0Ah */ +#define REG0A_MP2650_ADDRESS 0x0A + +#define REG0A_MP2650_NTC_COOL_MASK (BIT(1) | BIT(0)) +#define REG0A_MP2650_NTC_COOL_707_PERMILLE 0 +#define REG0A_MP2650_NTC_COOL_697_PERMILLE BIT(0) +#define REG0A_MP2650_NTC_COOL_686_PERMILLE BIT(1) //default +#define REG0A_MP2650_NTC_COOL_673_PERMILLE (BIT(1) | BIT(0)) + +#define REG0A_MP2650_NTC_WARM_MASK (BIT(3) | BIT(2)) +#define REG0A_MP2650_NTC_WARM_583_PERMILLE 0 +#define REG0A_MP2650_NTC_WARM_561_PERMILLE BIT(2) //default +#define REG0A_MP2650_NTC_WARM_537_PERMILLE BIT(3) +#define REG0A_MP2650_NTC_WARM_513_PERMILLE (BIT(3) | BIT(2)) + +#define REG0A_MP2650_NTC_CTRL_MASK (BIT(5) | BIT(4)) +#define REG0A_MP2650_NTC_CTRL_JEITA 0 //default +#define REG0A_MP2650_NTC_CTRL_STANDARD BIT(4) +#define REG0A_MP2650_NTC_CTRL_PCB BIT(5) +#define REG0A_MP2650_NTC_CTRL_DISABLE (BIT(5) | BIT(4)) + +#define REG0A_MP2650_JEITA_VSET_MASK BIT(6) +#define REG0A_MP2650_JEITA_VSET_150MV 0 //default +#define REG0A_MP2650_JEITA_VSET_300MV BIT(6) + +#define REG0A_MP2650_JEITA_ISET_MASK BIT(7) +#define REG0A_MP2650_JEITA_ISET_50_PERCENT 0 +#define REG0A_MP2650_JEITA_ISET_20_PERCENT BIT(7) //default + +/* Address:0Bh */ +#define REG0B_MP2650_ADDRESS 0x0B + +#define REG0B_MP2650_PROCHOT_PSYS_CFG_MASK (BIT(1) | BIT(0)) +#define REG0B_MP2650_PROCHOT_PSYS_CFG_DISABLE 0 +#define REG0B_MP2650_PROCHOT_PSYS_CFG_PROCHOT BIT(0) //default +#define REG0B_MP2650_PROCHOT_PSYS_CFG_ENABLE BIT(1) + +#define REG0B_MP2650_AICL_EN_MASK BIT(2) +#define REG0B_MP2650_AICL_EN_DISABLE 0 +#define REG0B_MP2650_AICL_EN_ENABLE BIT(2) + +#define REG0B_MP2650_SW_FREQ_MASK (BIT(4) | BIT(3)) +#define REG0B_MP2650_SW_FREQ_600K 0 //default +#define REG0B_MP2650_SW_FREQ_800K BIT(3) +#define REG0B_MP2650_SW_FREQ_1000K BIT(4) +#define REG0B_MP2650_SW_FREQ_1250K (BIT(4) | BIT(3)) + +#define REG0B_MP2650_IBM_CFG_MASK BIT(5) +#define REG0B_MP2650_IBM_CFG_REFLECT_CHARGE_CURRENT 0 //default +#define REG0B_MP2650_IBM_CFG_REFLECT_DISCHARGE_CURRENT BIT(5) + +#define REG0B_MP2650_IBM_EN_MASK BIT(6) +#define REG0B_MP2650_IBM_EN_DISABLE 0 //default +#define REG0B_MP2650_IBM_EN_ENABLE BIT(6) + + +/* Address:0Ch */ +#define REG0C_MP2650_ADDRESS 0x0C + +#define REG0C_MP2650_COMPARATOR_REFERENCE_MASK BIT(0) +#define REG0C_MP2650_COMPARATOR_REFERENCE_2100MV 0 //default +#define REG0C_MP2650_COMPARATOR_REFERENCE_1200MV BIT(0) + +#define REG0C_MP2650_COMPARATOR_CFG_MASK BIT(1) +#define REG0C_MP2650_COMPARATOR_CFG_AS_PROCHOT 0 //default +#define REG0C_MP2650_COMPARATOR_CFG_NOT_PROCHOT BIT(1) + +#define REG0C_MP2650_VIN_DSG_MASK BIT(2) +#define REG0C_MP2650_VIN_DSG_DISABLE 0 //default +#define REG0C_MP2650_VIN_DSG_ENABLE BIT(2) + +#define REG0C_MP2650_IDEAL_DIODE_EN_MASK BIT(3) +#define REG0C_MP2650_IDEAL_DIODE_EN_DISABLE 0 //default +#define REG0C_MP2650_IDEAL_DIODE_EN_ENABLE BIT(3) + +#define REG0C_MP2650_VSYS_PROCHOT_TDB_MASK BIT(4) +#define REG0C_MP2650_VSYS_PROCHOT_TDB_10US 0 //default +#define REG0C_MP2650_VSYS_PROCHOT_TDB_20US BIT(4) + +#define REG0C_MP2650_DIS_OC_PROCHOT_MASK (BIT(7) | BIT(6) | BIT(5)) +#define REG0C_MP2650_DIS_OC_PROCHOT_SHIFT 5 +#define REG0C_MP2650_DIS_OC_PROCHOT_OFFSET 0 +#define REG0C_MP2650_DIS_OC_PROCHOT_STEP 2 //default 12A + + +/* Address:0Dh */ +#define REG0D_MP2650_ADDRESS 0x0D + +#define REG0D_MP2650_SYS_UV_PROCHOT_MASK (BIT(1) | BIT(0)) +#define REG0D_MP2650_YS_UV_PROCHOT_5600MV 0 +#define REG0D_MP2650_YS_UV_PROCHOT_5800MV BIT(0) //default +#define REG0D_MP2650_YS_UV_PROCHOT_6000MV BIT(1) +#define REG0D_MP2650_YS_UV_PROCHOT_6200MV (BIT(1) | BIT(0)) + +#define REG0D_MP2650_VOTG_VSYS_UV_MASK (BIT(3) | BIT(2)) +#define REG0D_MP2650_VOTG_VSYS_UV_75_PERCENT 0 //default +#define REG0D_MP2650_VOTG_VSYS_UV_80_PERCENT BIT(2) +#define REG0D_MP2650_VOTG_VSYS_UV_85_PERCENT BIT(3) +#define REG0D_MP2650_VOTG_VSYS_UV_90_PERCENT (BIT(3) | BIT(2)) + +#define REG0D_MP2650_VOTG_VSYS_OV_MASK (BIT(5) | BIT(4)) +#define REG0D_MP2650_VOTG_VSYS_OV_125_PERCENT 0 //default +#define REG0D_MP2650_VOTG_VSYS_OV_120_PERCENT BIT(4) +#define REG0D_MP2650_VOTG_VSYS_OV_115_PERCENT BIT(5) +#define REG0D_MP2650_VOTG_VSYS_OV_110_PERCENT (BIT(5) | BIT(4)) + + +/* Address:0Eh */ +#define REG0E_MP2650_ADDRESS 0x0E + +#define REG0E_MP2650_DURATION_PROCHOT_ASSERTED_MASK (BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG0E_MP2650_DURATION_PROCHOT_ASSERTED_SHIFT 0 +#define REG0E_MP2650_DURATION_PROCHOT_ASSERTEDT_OFFSET 0 +#define REG0E_MP2650_DURATION_PROCHOT_ASSERTED_STEP 100 //default 300us + +#define REG0E_MP2650_TIME_BEFORE_PROCHOT_MASK (BIT(7) | BIT(6) | BIT(5)) +#define REG0E_MP2650_TIME_BEFORE_PROCHOT_SHIFT 5 +#define REG0E_MP2650_TIME_BEFORE_PROCHOT_OFFSET 0 +#define REG0E_MP2650_TIME_BEFORE_PROCHOT_STEP 100 //default 200us + + +/* Address:0Fh */ +#define REG0F_MP2650_ADDRESS 0x0F + +#define REG0F_MP2650_2ND_CURRENT_LIMIT_MASK (BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG0F_MP2650_2ND_CURRENT_LIMIT_SHIFT 0 +#define REG0F_MP2650_2ND_CURRENT_LIMIT_OFFSET 0 +#define REG0F_MP2650_2ND_CURRENT_LIMIT_STEP 50 //default 3A +#define REG0F_MP2650_2ND_CURRENT_LIMIT_1600MA BIT(5) +#define REG0F_MP2650_2ND_CURRENT_LIMIT_3600MA (BIT(6) | BIT(3)) + + +/* Address:10h */ +#define REG10_MP2650_ADDRESS 0x10 + +#define REG10_MP2650_2ND_CURRENT_LIMIT_TIME_MASK (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG10_MP2650_2ND_CURRENT_LIMIT_TIME_SHIFT 0 +#define REG10_MP2650_2ND_CURRENT_LIMIT_TIME_OFFSET 100 +#define REG10_MP2650_2ND_CURRENT_LIMIT_TIME_STEP 100 //default 700us + + +/* Address:11h */ +#define REG11_MP2650_ADDRESS 0x11 + +#define REG11_MP2650_CURRENT_LIMIT_TOTAL_TIME_MASK (BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)) +#define REG11_MP2650_CURRENT_LIMIT_TOTAL_TIMEE_SHIFT 0 +#define REG11_MP2650_CURRENT_LIMIT_TOTAL_TIME_OFFSET 100 +#define REG11_MP2650_CURRENT_LIMIT_TOTAL_TIME_STEP 100 //default 1600us + + +/* Address:12h */ +#define REG12_MP2650_ADDRESS 0x12 + +#define REG12_MP2650_INPUT_OVA_THRESHOLD_MASK (BIT(6) | BIT(5) | BIT(4) | BIT(3)) +#define REG12_MP2650_INPUT_OVA_THRESHOLD_SHIFT 3 +#define REG12_MP2650_INPUT_OVA_THRESHOLD_OFFSET 0 +#define REG12_MP2650_INPUT_OVA_THRESHOLD_STEP 800 //default 11.2A + +#define REG12_MP2650_BUCK_SWITCH_MASK BIT(2) +#define REG12_MP2650_BUCK_SWITCH_DISABLE BIT(2) +#define REG12_MP2650_BUCK_SWITCH_ENABLE 0 + + +/* Address:13h (Read only)*/ +#define REG13_MP2650_ADDRESS 0x13 + +#define REG13_MP2650_IN_VSYSMIN_REGULATION_MASK BIT(0) +#define REG13_MP2650_IN_VSYSMIN_REGULATION_YES 0 +#define REG13_MP2650_IN_VSYSMIN_REGULATION_NO BIT(0) //default + +#define REG13_MP2650_VIN_POWER_GOOD_MASK BIT(1) +#define REG13_MP2650_VIN_POWER_GOOD_NO 0 //default +#define REG13_MP2650_VIN_POWER_GOOD_YES BIT(1) + +#define REG13_MP2650_CHARGING_STATUS_MASK (BIT(3) | BIT(2)) +#define REG13_MP2650_CHARGING_STATUS_NOT_CHARGING 0 //default +#define REG13_MP2650_CHARGING_STATUS_PRE_CHARGE BIT(2) +#define REG13_MP2650_CHARGING_STATUS_FAST_CHARGE BIT(3) +#define REG13_MP2650_CHARGING_STATUS_CHARGE_TERMINATION (BIT(3) | BIT(2)) + +#define REG13_MP2650_PPM_STAT_MASK BIT(4) +#define REG13_MP2650_PPM_STAT_NO_DPM 0 //default +#define REG13_MP2650_PPM_STAT_VINDPM_INDPM BIT(4) + +#define REG13_MP2650_AICL_STAT_MASK BIT(5) +#define REG13_MP2650_DETECTION_IN_PROGRESS 0 //default +#define REG13_MP2650_MAX_INPUT_DETECTED BIT(5) + +#define REG13_MP2650_VSYS_UV_MASK BIT(6) +#define REG13_MP2650_VSYS_UV_NO 0 //default +#define REG13_MP2650_VSYS_UV_YES BIT(6) + +#define REG13_MP2650_BATT_UVLO_MASK BIT(7) +#define REG13_MP2650_BATT_UVLO_NO 0 //default +#define REG13_MP2650_BATT_UVLO_YES BIT(7) + + +/* Address:14h (Read only)*/ +#define REG14_MP2650_ADDRESS 0x14 + +#define REG14_MP2650_NTC_FAULT_MASK (BIT(2) | BIT(1) | BIT(0)) +#define REG14_MP2650_NTC_FAULT_NORMAL 0 //default +#define REG14_MP2650_NTC_FAULT_COLD BIT(0) +#define REG14_MP2650_NTC_FAULT_COOL BIT(1) +#define REG14_MP2650_NTC_FAULT_WARM (BIT(1) | BIT(0)) +#define REG14_MP2650_NTC_FAULT_HOT BIT(2) + +#define REG14_MP2650_BAT_FAULT_MASK BIT(3) +#define REG14_MP2650_BAT_FAULT_NO 0 //default +#define REG14_MP2650_BAT_FAULT_OVP BIT(3) + +#define REG14_MP2650_CHARGE_FAULT_MASK (BIT(5) | BIT(4)) +#define REG14_MP2650_CHARGE_FAULT_NORMAL 0 //default +#define REG14_MP2650_CHARGE_FAULT_INPUT_FAULT BIT(4) +#define REG14_MP2650_CHARGE_FAULT_THERMAL_SHUTDOWN BIT(5) +#define REG14_MP2650_CHARGE_FAULT_SAFETY_TIMEOUT (BIT(5) | BIT(4)) + +#define REG14_MP2650_OTG_MODE_FAULT_MASK BIT(6) +#define REG14_MP2650_OTG_MODE_FAULT_NO 0 //default +#define REG14_MP2650_OTG_MODE_FAULT_YES BIT(6) + +#define REG14_MP2650_WATCHDOG_FAULT_MASK BIT(7) +#define REG14_MP2650_WATCHDOG_FAULT_NO 0 //default +#define REG14_MP2650_WATCHDOG_FAULT_YES BIT(7) + + +/* Address:15h (Read only)*/ +#define REG15_MP2650_ADDRESS 0x15 + +#define REG15_MP2650_DEVICE_REVISION_MASK (BIT(2) | BIT(1) | BIT(0)) +#define REG15_MP2650_DEVICE_REVISION_MP2650 000 + +#define REG15_MP2650_DEVICE_CONFIGURATION_MASK (BIT(5) | BIT(4) | BIT(3)) +#define REG15_MP2650_DEVICE_CONFIGURATION_1ST 000 + +/* Address:16h 17h(Read only)*/ +#define REG1617_MP2650_ADDRESS 0x16 + +#define REG1617_MP2650_BAT_VOLTAGE_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG1617_MP2650_BAT_VOLTAGE_SHIFT 6 +#define REG1617_MP2650_BAT_VOLTAGE_OFFSET 0 +#define REG1617_MP2650_BAT_VOLTAGE_STEP 12.5 //12.5mV + + +/* Address:18h 19h(Read only)*/ +#define REG1819_MP2650_ADDRESS 0x18 + +#define REG1819_MP2650_SYS_VOLTAGE_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG1819_MP2650_SYS_VOLTAGE_SHIFT 6 +#define REG1819_MP2650_SYS_VOLTAGE_OFFSET 0 +#define REG1819_MP2650_SYS_VOLTAGE_STEP 12.5 //12.5mV + + +/* Address:1Ah 1Bh(Read only)*/ +#define REG1A1B_MP2650_ADDRESS 0x1A + +#define REG1A1B_MP2650_CHARGE_CURRENT_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG1A1B_MP2650_CHARGE_CURRENT_SHIFT 6 +#define REG1A1B_MP2650_CHARGE_CURRENT_OFFSET 0 +#define REG1A1B_MP2650_CHARGE_CURRENT_STEP 12.5 //12.5mA + + +/* Address:1Ch 1Dh(Read only)*/ +#define REG1C1D_MP2650_ADDRESS 0x1C + +#define REG1C1D_MP2650_INPUT_VOLTAGE_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG1C1D_MP2650_INPUT_VOLTAGE_SHIFT 6 +#define REG1C1D_MP2650_INPUT_VOLTAGE_OFFSET 0 +#define REG1C1D_MP2650_INPUT_VOLTAGE_STEP 25 //25mV + + +/* Address:1Eh 1Fh(Read only)*/ +#define REG1E1F_MP2650_ADDRESS 0x1E + +#define REG1E1F_MP2650_INPUT_CURRENT_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG1E1F_MP2650_INPUT_CURRENT_SHIFT 6 +#define REG1E1F_MP2650_INPUT_CURRENT_OFFSET 0 +#define REG1E1F_MP2650_INPUT_CURRENT_STEP 6.25 //6.25mA + + +/* Address:20h 21h(Read only)*/ +#define REG2021_MP2650_ADDRESS 0x20 + +#define REG2021_MP2650_OTG_VOLTAGE_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG2021_MP2650_OTG_VOLTAGE_SHIFT 6 +#define REG2021_MP2650_OTG_VOLTAGE_OFFSET 0 +#define REG2021_MP2650_OTG_VOLTAGE_STEP 25 //25mV + + +/* Address:22h 23h(Read only)*/ +#define REG2223_MP2650_ADDRESS 0x22 + +#define REG2223_MP2650_OTG_CURRENT_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG2223_MP2650_OTG_CURRENT_SHIFT 6 +#define REG2223_MP2650_OTG_CURRENT_OFFSET 0 +#define REG2223_MP2650_OTG_CURRENT_STEP 6.25 //6.25mA + +/* Address:24h 25h(Read only)*/ +#define REG2425_MP2650_ADDRESS 0x24 + +#define REG2425_MP2650_TEMPERATURE_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG2425_MP2650_TEMPERATURE_SHIFT 6 +#define REG2425_MP2650_TEMPERATURE_OFFSET 0 +#define REG2425_MP2650_TEMPERATURE_STEP 1 //Temperature = 903 - 2.578 * T + + +/* Address:26h 27h(Read only)*/ +#define REG2627_MP2650_ADDRESS 0x26 + +#define REG2627_MP2650_SYS_POWER_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG2627_MP2650_SYS_POWER_SHIFT 6 +#define REG2627_MP2650_SYS_POWER_OFFSET 0 +#define REG2627_MP2650_SYS_POWER_STEP 125 //125mW + + +/* Address:28h 29h(Read only)*/ +#define REG2829_MP2650_ADDRESS 0x28 + +#define REG2829_MP2650_DISCHARGE_CURRENT_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6)) +#define REG2829_MP2650_SDISCHARGE_CURRENT_SHIFT 6 +#define REG2829_MP2650_DISCHARGE_CURRENT_OFFSET 0 +#define REG2829_MP2650_SDISCHARGE_CURRENT_STEP 12.5 //12.5mA + +#define REG2D_MP2650_ADDRESS 0x2D +#define REG2F_MP2650_ADDRESS 0x2F +#define REG31_MP2650_ADDRESS 0x31 +#define REG37_MP2650_ADDRESS 0x37 +#define REG39_MP2650_ADDRESS 0x39 + +#define REG53_MP2650_ADDRESS 0x53 + +/*Addition WPC start*/ +#define WPC_CHARGER_INPUT_CURRENT_LIMIT_DEFAULT 1000 +#define WPC_TERMINATION_VOLTAGE_DEFAULT 4370 +#define WPC_TERMINATION_VOLTAGE WPC_TERMINATION_VOLTAGE_DEFAULT +#define WPC_TERMINATION_CURRENT 100 //200 +#define WPC_CHARGE_CURRENT_DEFAULT 500 //500mA +#define WPC_RECHARGE_VOLTAGE_OFFSET 200 +/*Addition WPC end*/ + +enum { + OVERTIME_AC = 0, + OVERTIME_USB, + OVERTIME_DISABLED, +}; + + +struct mp2650_charger { + struct i2c_client *client; + struct device *dev; + struct regmap *regmap; + int hw_aicl_point; + int sw_aicl_point; + int pre_current_ma; + int sw_aicl_result_ma; + int status_irq; + int prochot_irq; + + bool otg_enabled; + bool buck_switcher_on; + bool input_suspend; + bool pre_chg_thd_6600; + + int mps_otg_en_gpio; + struct pinctrl *pinctrl; + struct pinctrl_state *mps_otg_en_active; + struct pinctrl_state *mps_otg_en_sleep; + struct pinctrl_state *mps_otg_en_default; + + atomic_t charger_suspended; + struct power_supply *cp_psy; + struct power_supply *batt_psy; + struct delayed_work dump_reg_work; +}; +#endif diff --git a/drivers/oneplus/power/supply/wlchg/Kconfig b/drivers/oneplus/power/supply/wlchg/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..c702fda29d3323e66108608343f52717f8c6450d --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/Kconfig @@ -0,0 +1,10 @@ +# oem device driver for charge + +config ONEPLUS_WIRELESSCHG + tristate "ONEPLUS WIRELESS CHARGE" + depends on I2C + help + Say Y here to enable the ONEPLUS WIRELESS CHARGE driver.This adds support + for wireless charge and state of charge of battery connected to + the battery. The state of charge is reported through a battery power + supply property diff --git a/drivers/oneplus/power/supply/wlchg/Makefile b/drivers/oneplus/power/supply/wlchg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48fa48dfaaf98b7f8d5c64d4160cbeba144e8290 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/Makefile @@ -0,0 +1,7 @@ +ccflags-y += -I$(srctree)/drivers/power/supply/qcom +obj-y += op_p9415.o +obj-y += op_wlchg_rx.o +obj-y += op_chargepump.o +obj-y += bq2597x_charger.o +obj-y += op_wlchg_policy.o + diff --git a/drivers/oneplus/power/supply/wlchg/bq25970_reg.h b/drivers/oneplus/power/supply/wlchg/bq25970_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..76edcf808d0fac1d5397a69fbb6d819936ae0a76 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/bq25970_reg.h @@ -0,0 +1,789 @@ + +#ifndef __BQ2597X_HEADER__ +#define __BQ2597X_HEADER__ + +/* Register 00h */ +#define BQ2597X_REG_00 0x00 +#define BQ2597X_BAT_OVP_DIS_MASK 0x80 +#define BQ2597X_BAT_OVP_DIS_SHIFT 7 +#define BQ2597X_BAT_OVP_ENABLE 0 +#define BQ2597X_BAT_OVP_DISABLE 1 + +#define BQ2597X_BAT_OVP_MASK 0x3F +#define BQ2597X_BAT_OVP_SHIFT 0 +#define BQ2597X_BAT_OVP_BASE 3475 +#define BQ2597X_BAT_OVP_LSB 25 + +/* Register 01h */ +#define BQ2597X_REG_01 0x01 +#define BQ2597X_BAT_OVP_ALM_DIS_MASK 0x80 +#define BQ2597X_BAT_OVP_ALM_DIS_SHIFT 7 +#define BQ2597X_BAT_OVP_ALM_ENABLE 0 +#define BQ2597X_BAT_OVP_ALM_DISABLE 1 + +#define BQ2597X_BAT_OVP_ALM_MASK 0x3F +#define BQ2597X_BAT_OVP_ALM_SHIFT 0 +#define BQ2597X_BAT_OVP_ALM_BASE 3500 +#define BQ2597X_BAT_OVP_ALM_LSB 25 + +/* Register 02h */ +#define BQ2597X_REG_02 0x02 +#define BQ2597X_BAT_OCP_DIS_MASK 0x80 +#define BQ2597X_BAT_OCP_DIS_SHIFT 7 +#define BQ2597X_BAT_OCP_ENABLE 0 +#define BQ2597X_BAT_OCP_DISABLE 1 + +#define BQ2597X_BAT_OCP_MASK 0x7F +#define BQ2597X_BAT_OCP_SHIFT 0 +#define BQ2597X_BAT_OCP_BASE 2000 +#define BQ2597X_BAT_OCP_LSB 100 + +/* Register 03h */ +#define BQ2597X_REG_03 0x03 +#define BQ2597X_BAT_OCP_ALM_DIS_MASK 0x80 +#define BQ2597X_BAT_OCP_ALM_DIS_SHIFT 7 +#define BQ2597X_BAT_OCP_ALM_ENABLE 0 +#define BQ2597X_BAT_OCP_ALM_DISABLE 1 + +#define BQ2597X_BAT_OCP_ALM_MASK 0x7F +#define BQ2597X_BAT_OCP_ALM_SHIFT 0 +#define BQ2597X_BAT_OCP_ALM_BASE 2000 +#define BQ2597X_BAT_OCP_ALM_LSB 100 + +/* Register 04h */ +#define BQ2597X_REG_04 0x04 +#define BQ2597X_BAT_UCP_ALM_DIS_MASK 0x80 +#define BQ2597X_BAT_UCP_ALM_DIS_SHIFT 7 +#define BQ2597X_BAT_UCP_ALM_ENABLE 0 +#define BQ2597X_BAT_UCP_ALM_DISABLE 1 + +#define BQ2597X_BAT_UCP_ALM_MASK 0x7F +#define BQ2597X_BAT_UCP_ALM_SHIFT 0 +#define BQ2597X_BAT_UCP_ALM_BASE 0 +#define BQ2597X_BAT_UCP_ALM_LSB 50 + +/* Register 05h */ +#define BQ2597X_REG_05 0x05 +#define BQ2597X_AC_OVP_STAT_MASK 0x80 +#define BQ2597X_AC_OVP_STAT_SHIFT 7 + +#define BQ2597X_AC_OVP_FLAG_MASK 0x40 +#define BQ2597X_AC_OVP_FLAG_SHIFT 6 + +#define BQ2597X_AC_OVP_MASK_MASK 0x20 +#define BQ2597X_AC_OVP_MASK_SHIFT 5 + +#define BQ2597X_VDROP_THRESHOLD_SET_MASK 0x10 +#define BQ2597X_VDROP_THRESHOLD_SET_SHIFT 4 +#define BQ2597X_VDROP_THRESHOLD_300MV 0 +#define BQ2597X_VDROP_THRESHOLD_400MV 1 + +#define BQ2597X_VDROP_DEGLITCH_SET_MASK 0x08 +#define BQ2597X_VDROP_DEGLITCH_SET_SHIFT 3 +#define BQ2597X_VDROP_DEGLITCH_8US 0 +#define BQ2597X_VDROP_DEGLITCH_5MS 1 + +#define BQ2597X_AC_OVP_MASK 0x07 +#define BQ2597X_AC_OVP_SHIFT 0 +#define BQ2597X_AC_OVP_BASE 11 +#define BQ2597X_AC_OVP_LSB 1 +#define BQ2597X_AC_OVP_6P5V 65 + +/* Register 06h */ +#define BQ2597X_REG_06 0x06 +#define BQ2597X_VBUS_PD_EN_MASK 0x80 +#define BQ2597X_VBUS_PD_EN_SHIFT 7 +#define BQ2597X_VBUS_PD_ENABLE 1 +#define BQ2597X_VBUS_PD_DISABLE 0 + +#define BQ2597X_BUS_OVP_MASK 0x7F +#define BQ2597X_BUS_OVP_SHIFT 0 +#define BQ2597X_BUS_OVP_BASE 5950 +#define BQ2597X_BUS_OVP_LSB 50 + +/* Register 07h */ +#define BQ2597X_REG_07 0x07 +#define BQ2597X_BUS_OVP_ALM_DIS_MASK 0x80 +#define BQ2597X_BUS_OVP_ALM_DIS_SHIFT 7 +#define BQ2597X_BUS_OVP_ALM_ENABLE 0 +#define BQ2597X_BUS_OVP_ALM_DISABLE 1 + +#define BQ2597X_BUS_OVP_ALM_MASK 0x7F +#define BQ2597X_BUS_OVP_ALM_SHIFT 0 +#define BQ2597X_BUS_OVP_ALM_BASE 6000 +#define BQ2597X_BUS_OVP_ALM_LSB 50 + +/* Register 08h */ +#define BQ2597X_REG_08 0x08 +#define BQ2597X_BUS_OCP_DIS_MASK 0x80 +#define BQ2597X_BUS_OCP_DIS_SHIFT 7 +#define BQ2597X_BUS_OCP_ENABLE 0 +#define BQ2597X_BUS_OCP_DISABLE 1 + +#define BQ2597X_IBUS_UCP_RISE_FLAG_MASK 0x40 +#define BQ2597X_IBUS_UCP_RISE_FLAG_SHIFT 6 + +#define BQ2597X_IBUS_UCP_RISE_MASK_MASK 0x20 +#define BQ2597X_IBUS_UCP_RISE_MASK_SHIFT 5 +#define BQ2597X_IBUS_UCP_RISE_MASK_ENABLE 1 +#define BQ2597X_IBUS_UCP_RISE_MASK_DISABLE 0 + +#define BQ2597X_IBUS_UCP_FALL_FLAG_MASK 0x10 +#define BQ2597X_IBUS_UCP_FALL_FLAG_SHIFT 4 + +#define BQ2597X_BUS_OCP_MASK 0x0F +#define BQ2597X_BUS_OCP_SHIFT 0 +#define BQ2597X_BUS_OCP_BASE 1000 +#define BQ2597X_BUS_OCP_LSB 250 + +/* Register 09h */ +#define BQ2597X_REG_09 0x09 +#define BQ2597X_BUS_OCP_ALM_DIS_MASK 0x80 +#define BQ2597X_BUS_OCP_ALM_DIS_SHIFT 7 +#define BQ2597X_BUS_OCP_ALM_ENABLE 0 +#define BQ2597X_BUS_OCP_ALM_DISABLE 1 + +#define BQ2597X_BUS_OCP_ALM_MASK 0x7F +#define BQ2597X_BUS_OCP_ALM_SHIFT 0 +#define BQ2597X_BUS_OCP_ALM_BASE 0 +#define BQ2597X_BUS_OCP_ALM_LSB 50 + +/* Register 0Ah */ +#define BQ2597X_REG_0A 0x0A +#define BQ2597X_TSHUT_FLAG_MASK 0x80 +#define BQ2597X_TSHUT_FLAG_SHIFT 7 + +#define BQ2597X_TSHUT_STAT_MASK 0x40 +#define BQ2597X_TSHUT_STAT_SHIFT 6 + +#define BQ2597X_VBUS_ERRORLO_STAT_MASK 0x20 +#define BQ2597X_VBUS_ERRORLO_STAT_SHIFT 5 + +#define BQ2597X_VBUS_ERRORHI_STAT_MASK 0x10 +#define BQ2597X_VBUS_ERRORHI_STAT_SHIFT 4 + +#define BQ2597X_SS_TIMEOUT_FLAG_MASK 0x08 +#define BQ2597X_SS_TIMEOUT_FLAG_SHIFT 3 + +#define BQ2597X_CONV_SWITCHING_STAT_MASK 0x04 +#define BQ2597X_CONV_SWITCHING_STAT_SHIFT 2 + +#define BQ2597X_CONV_OCP_FLAG_MASK 0x02 +#define BQ2597X_CONV_OCP_FLAG_SHIFT 1 + +#define BQ2597X_PIN_DIAG_FALL_FLAG_MASK 0x01 +#define BQ2597X_PIN_DIAG_FALL_FLAG_SHIFT 0 + +/* Register 0Bh */ +#define BQ2597X_REG_0B 0x0B +#define BQ2597X_REG_RST_MASK 0x80 +#define BQ2597X_REG_RST_SHIFT 7 +#define BQ2597X_REG_RST_ENABLE 1 +#define BQ2597X_REG_RST_DISABLE 0 + +#define BQ2597X_FSW_SET_MASK 0x70 +#define BQ2597X_FSW_SET_SHIFT 4 +#define BQ2597X_FSW_SET_187P5KHZ 0 +#define BQ2597X_FSW_SET_250KHZ 1 +#define BQ2597X_FSW_SET_300KHZ 2 +#define BQ2597X_FSW_SET_375KHZ 3 +#define BQ2597X_FSW_SET_500KHZ 4 +#define BQ2597X_FSW_SET_750KHZ 5 + +#define BQ2597X_WD_TIMEOUT_FLAG_MASK 0x08 +#define BQ2597X_WD_TIMEOUT_SHIFT 3 + +#define BQ2597X_WATCHDOG_DIS_MASK 0x04 +#define BQ2597X_WATCHDOG_DIS_SHIFT 2 +#define BQ2597X_WATCHDOG_ENABLE 0 +#define BQ2597X_WATCHDOG_DISABLE 1 + +#define BQ2597X_WATCHDOG_MASK 0x03 +#define BQ2597X_WATCHDOG_SHIFT 0 +#define BQ2597X_WATCHDOG_0P5S 0 +#define BQ2597X_WATCHDOG_1S 1 +#define BQ2597X_WATCHDOG_5S 2 +#define BQ2597X_WATCHDOG_30S 3 + +/* Register 0Ch */ +#define BQ2597X_REG_0C 0x0C +#define BQ2597X_CHG_EN_MASK 0x80 +#define BQ2597X_CHG_EN_SHIFT 7 +#define BQ2597X_CHG_ENABLE 1 +#define BQ2597X_CHG_DISABLE 0 + +#define BQ2597X_MS_MASK 0x60 +#define BQ2597X_MS_SHIFT 5 +#define BQ2597X_MS_STANDALONE 0 +#define BQ2597X_MS_SLAVE 1 +#define BQ2597X_MS_MASTER 2 + +#define BQ2597X_FREQ_SHIFT_MASK 0x18 +#define BQ2597X_FREQ_SHIFT_SHIFT 3 +#define BQ2597X_FREQ_SHIFT_NORMINAL 0 +#define BQ2597X_FREQ_SHIFT_POSITIVE10 1 +#define BQ2597X_FREQ_SHIFT_NEGATIVE10 2 +#define BQ2597X_FREQ_SHIFT_SPREAD_SPECTRUM 3 + +#define BQ2597X_TSBUS_DIS_MASK 0x04 +#define BQ2597X_TSBUS_DIS_SHIFT 2 +#define BQ2597X_TSBUS_ENABLE 0 +#define BQ2597X_TSBUS_DISABLE 1 + +#define BQ2597X_TSBAT_DIS_MASK 0x02 +#define BQ2597X_TSBAT_DIS_SHIFT 1 +#define BQ2597X_TSBAT_ENABLE 0 +#define BQ2597X_TSBAT_DISABLE 1 + +#define BQ2597X_TDIE_DIS_MASK 0x01 +#define BQ2597X_TDIE_DIS_SHIFT 0 +#define BQ2597X_TDIE_ENABLE 0 +#define BQ2597X_TDIE_DISABLE 1 + +/* Register 0Dh */ +#define BQ2597X_REG_0D 0x0D +#define BQ2597X_BAT_OVP_ALM_STAT_MASK 0x80 +#define BQ2597X_BAT_OVP_ALM_STAT_SHIFT 7 + +#define BQ2597X_BAT_OCP_ALM_STAT_MASK 0x40 +#define BQ2597X_BAT_OCP_ALM_STAT_SHIFT 6 + +#define BQ2597X_BUS_OVP_ALM_STAT_MASK 0x20 +#define BQ2597X_BUS_OVP_ALM_STAT_SHIFT 5 + +#define BQ2597X_BUS_OCP_ALM_STAT_MASK 0x10 +#define BQ2597X_BUS_OCP_ALM_STAT_SHIFT 4 + +#define BQ2597X_BAT_UCP_ALM_STAT_MASK 0x08 +#define BQ2597X_BAT_UCP_ALM_STAT_SHIFT 3 + +#define BQ2597X_ADAPTER_INSERT_STAT_MASK 0x04 +#define BQ2597X_ADAPTER_INSERT_STAT_SHIFT 2 + +#define BQ2597X_VBAT_INSERT_STAT_MASK 0x02 +#define BQ2597X_VBAT_INSERT_STAT_SHIFT 1 + +#define BQ2597X_ADC_DONE_STAT_MASK 0x01 +#define BQ2597X_ADC_DONE_STAT_SHIFT 0 +#define BQ2597X_ADC_DONE_STAT_COMPLETE 1 +#define BQ2597X_ADC_DONE_STAT_NOTCOMPLETE 0 + +/* Register 0Eh */ +#define BQ2597X_REG_0E 0x0E +#define BQ2597X_BAT_OVP_ALM_FLAG_MASK 0x80 +#define BQ2597X_BAT_OVP_ALM_FLAG_SHIFT 7 + +#define BQ2597X_BAT_OCP_ALM_FLAG_MASK 0x40 +#define BQ2597X_BAT_OCP_ALM_FLAG_SHIFT 6 + +#define BQ2597X_BUS_OVP_ALM_FLAG_MASK 0x20 +#define BQ2597X_BUS_OVP_ALM_FLAG_SHIFT 5 + +#define BQ2597X_BUS_OCP_ALM_FLAG_MASK 0x10 +#define BQ2597X_BUS_OCP_ALM_FLAG_SHIFT 4 + +#define BQ2597X_BAT_UCP_ALM_FLAG_MASK 0x08 +#define BQ2597X_BAT_UCP_ALM_FLAG_SHIFT 3 + +#define BQ2597X_ADAPTER_INSERT_FLAG_MASK 0x04 +#define BQ2597X_ADAPTER_INSERT_FLAG_SHIFT 2 + +#define BQ2597X_VBAT_INSERT_FLAG_MASK 0x02 +#define BQ2597X_VBAT_INSERT_FLAG_SHIFT 1 + +#define BQ2597X_ADC_DONE_FLAG_MASK 0x01 +#define BQ2597X_ADC_DONE_FLAG_SHIFT 0 +#define BQ2597X_ADC_DONE_FLAG_COMPLETE 1 +#define BQ2597X_ADC_DONE_FLAG_NOTCOMPLETE 0 + +/* Register 0Fh */ +#define BQ2597X_REG_0F 0x0F +#define BQ2597X_BAT_OVP_ALM_MASK_MASK 0x80 +#define BQ2597X_BAT_OVP_ALM_MASK_SHIFT 7 +#define BQ2597X_BAT_OVP_ALM_MASK_ENABLE 1 +#define BQ2597X_BAT_OVP_ALM_MASK_DISABLE 0 + +#define BQ2597X_BAT_OCP_ALM_MASK_MASK 0x40 +#define BQ2597X_BAT_OCP_ALM_MASK_SHIFT 6 +#define BQ2597X_BAT_OCP_ALM_MASK_ENABLE 1 +#define BQ2597X_BAT_OCP_ALM_MASK_DISABLE 0 + +#define BQ2597X_BUS_OVP_ALM_MASK_MASK 0x20 +#define BQ2597X_BUS_OVP_ALM_MASK_SHIFT 5 +#define BQ2597X_BUS_OVP_ALM_MASK_ENABLE 1 +#define BQ2597X_BUS_OVP_ALM_MASK_DISABLE 0 + +#define BQ2597X_BUS_OCP_ALM_MASK_MASK 0x10 +#define BQ2597X_BUS_OCP_ALM_MASK_SHIFT 4 +#define BQ2597X_BUS_OCP_ALM_MASK_ENABLE 1 +#define BQ2597X_BUS_OCP_ALM_MASK_DISABLE 0 + +#define BQ2597X_BAT_UCP_ALM_MASK_MASK 0x08 +#define BQ2597X_BAT_UCP_ALM_MASK_SHIFT 3 +#define BQ2597X_BAT_UCP_ALM_MASK_ENABLE 1 +#define BQ2597X_BAT_UCP_ALM_MASK_DISABLE 0 + +#define BQ2597X_ADAPTER_INSERT_MASK_MASK 0x04 +#define BQ2597X_ADAPTER_INSERT_MASK_SHIFT 2 +#define BQ2597X_ADAPTER_INSERT_MASK_ENABLE 1 +#define BQ2597X_ADAPTER_INSERT_MASK_DISABLE 0 + +#define BQ2597X_VBAT_INSERT_MASK_MASK 0x02 +#define BQ2597X_VBAT_INSERT_MASK_SHIFT 1 +#define BQ2597X_VBAT_INSERT_MASK_ENABLE 1 +#define BQ2597X_VBAT_INSERT_MASK_DISABLE 0 + +#define BQ2597X_ADC_DONE_MASK_MASK 0x01 +#define BQ2597X_ADC_DONE_MASK_SHIFT 0 +#define BQ2597X_ADC_DONE_MASK_ENABLE 1 +#define BQ2597X_ADC_DONE_MASK_DISABLE 0 + +/* Register 10h */ +#define BQ2597X_REG_10 0x10 +#define BQ2597X_BAT_OVP_FLT_STAT_MASK 0x80 +#define BQ2597X_BAT_OVP_FLT_STAT_SHIFT 7 + +#define BQ2597X_BAT_OCP_FLT_STAT_MASK 0x40 +#define BQ2597X_BAT_OCP_FLT_STAT_SHIFT 6 + +#define BQ2597X_BUS_OVP_FLT_STAT_MASK 0x20 +#define BQ2597X_BUS_OVP_FLT_STAT_SHIFT 5 + +#define BQ2597X_BUS_OCP_FLT_STAT_MASK 0x10 +#define BQ2597X_BUS_OCP_FLT_STAT_SHIFT 4 + +#define BQ2597X_TSBUS_TSBAT_ALM_STAT_MASK 0x08 +#define BQ2597X_TSBUS_TSBAT_ALM_STAT_SHIFT 3 + +#define BQ2597X_TSBAT_FLT_STAT_MASK 0x04 +#define BQ2597X_TSBAT_FLT_STAT_SHIFT 2 + +#define BQ2597X_TSBUS_FLT_STAT_MASK 0x02 +#define BQ2597X_TSBUS_FLT_STAT_SHIFT 1 + +#define BQ2597X_TDIE_ALM_STAT_MASK 0x01 +#define BQ2597X_TDIE_ALM_STAT_SHIFT 0 + +/* Register 11h */ +#define BQ2597X_REG_11 0x11 +#define BQ2597X_BAT_OVP_FLT_FLAG_MASK 0x80 +#define BQ2597X_BAT_OVP_FLT_FLAG_SHIFT 7 + +#define BQ2597X_BAT_OCP_FLT_FLAG_MASK 0x40 +#define BQ2597X_BAT_OCP_FLT_FLAG_SHIFT 6 + +#define BQ2597X_BUS_OVP_FLT_FLAG_MASK 0x20 +#define BQ2597X_BUS_OVP_FLT_FLAG_SHIFT 5 + +#define BQ2597X_BUS_OCP_FLT_FLAG_MASK 0x10 +#define BQ2597X_BUS_OCP_FLT_FLAG_SHIFT 4 + +#define BQ2597X_TSBUS_TSBAT_ALM_FLAG_MASK 0x08 +#define BQ2597X_TSBUS_TSBAT_ALM_FLAG_SHIFT 3 + +#define BQ2597X_TSBAT_FLT_FLAG_MASK 0x04 +#define BQ2597X_TSBAT_FLT_FLAG_SHIFT 2 + +#define BQ2597X_TSBUS_FLT_FLAG_MASK 0x02 +#define BQ2597X_TSBUS_FLT_FLAG_SHIFT 1 + +#define BQ2597X_TDIE_ALM_FLAG_MASK 0x01 +#define BQ2597X_TDIE_ALM_FLAG_SHIFT 0 + +/* Register 12h */ +#define BQ2597X_REG_12 0x12 +#define BQ2597X_BAT_OVP_FLT_MASK_MASK 0x80 +#define BQ2597X_BAT_OVP_FLT_MASK_SHIFT 7 +#define BQ2597X_BAT_OVP_FLT_MASK_ENABLE 1 +#define BQ2597X_BAT_OVP_FLT_MASK_DISABLE 0 + +#define BQ2597X_BAT_OCP_FLT_MASK_MASK 0x40 +#define BQ2597X_BAT_OCP_FLT_MASK_SHIFT 6 +#define BQ2597X_BAT_OCP_FLT_MASK_ENABLE 1 +#define BQ2597X_BAT_OCP_FLT_MASK_DISABLE 0 + +#define BQ2597X_BUS_OVP_FLT_MASK_MASK 0x20 +#define BQ2597X_BUS_OVP_FLT_MASK_SHIFT 5 +#define BQ2597X_BUS_OVP_FLT_MASK_ENABLE 1 +#define BQ2597X_BUS_OVP_FLT_MASK_DISABLE 0 + +#define BQ2597X_BUS_OCP_FLT_MASK_MASK 0x10 +#define BQ2597X_BUS_OCP_FLT_MASK_SHIFT 4 +#define BQ2597X_BUS_OCP_FLT_MASK_ENABLE 1 +#define BQ2597X_BUS_OCP_FLT_MASK_DISABLE 0 + +#define BQ2597X_TSBUS_TSBAT_ALM_MASK_MASK 0x08 +#define BQ2597X_TSBUS_TSBAT_ALM_MASK_SHIFT 3 +#define BQ2597X_TSBUS_TSBAT_ALM_MASK_ENABLE 1 +#define BQ2597X_TSBUS_TSBAT_ALM_MASK_DISABLE 0 + +#define BQ2597X_TSBAT_FLT_MASK_MASK 0x04 +#define BQ2597X_TSBAT_FLT_MASK_SHIFT 2 +#define BQ2597X_TSBAT_FLT_MASK_ENABLE 1 +#define BQ2597X_TSBAT_FLT_MASK_DISABLE 0 + +#define BQ2597X_TSBUS_FLT_MASK_MASK 0x02 +#define BQ2597X_TSBUS_FLT_MASK_SHIFT 1 +#define BQ2597X_TSBUS_FLT_MASK_ENABLE 1 +#define BQ2597X_TSBUS_FLT_MASK_DISABLE 0 + +#define BQ2597X_TDIE_ALM_MASK_MASK 0x01 +#define BQ2597X_TDIE_ALM_MASK_SHIFT 0 +#define BQ2597X_TDIE_ALM_MASK_ENABLE 1 +#define BQ2597X_TDIE_ALM_MASK_DISABLE 0 + +/* Register 13h */ +#define BQ2597X_REG_13 0x13 +#define BQ2597X_DEV_ID_MASK 0x0F +#define BQ2597X_DEV_ID_SHIFT 0 + +/* Register 14h */ +#define BQ2597X_REG_14 0x14 +#define BQ2597X_ADC_EN_MASK 0x80 +#define BQ2597X_ADC_EN_SHIFT 7 +#define BQ2597X_ADC_ENABLE 1 +#define BQ2597X_ADC_DISABLE 0 + +#define BQ2597X_ADC_RATE_MASK 0x40 +#define BQ2597X_ADC_RATE_SHIFT 6 +#define BQ2597X_ADC_RATE_CONTINOUS 0 +#define BQ2597X_ADC_RATE_ONESHOT 1 + +#define BQ2597X_ADC_AVG_MASK 0x20 +#define BQ2597X_ADC_AVG_SHIFT 5 +#define BQ2597X_ADC_AVG_DISABLE 0 +#define BQ2597X_ADC_AVG_ENABLE 1 + +#define BQ2597X_ADC_AVG_INIT_MASK 0x10 +#define BQ2597X_ADC_AVG_INIT_SHIFT 4 +#define BQ2597X_ADC_AVG_INIT_EXIST_REG_VAL 0 +#define BQ2597X_ADC_AVG_INIT_NEW_CONVERSION 1 + +#define BQ2597X_ADC_SAMPLE_MASK 0x0C +#define BQ2597X_ADC_SAMPLE_SHIFT 2 +#define BQ2597X_ADC_SAMPLE_15BITS 0 +#define BQ2597X_ADC_SAMPLE_14BITS 1 +#define BQ2597X_ADC_SAMPLE_13BITS 2 +#define BQ2597X_ADC_SAMPLE_12BITS 3 + +#define BQ2597X_IBUS_ADC_DIS_MASK 0x01 +#define BQ2597X_IBUS_ADC_DIS_SHIFT 0 +#define BQ2597X_IBUS_ADC_ENABLE 0 +#define BQ2597X_IBUS_ADC_DISABLE 1 + +/* Register 15h */ +#define BQ2597X_REG_15 0x15 +#define BQ2597X_VBUS_ADC_DIS_MASK 0x80 +#define BQ2597X_VBUS_ADC_DIS_SHIFT 7 +#define BQ2597X_VBUS_ADC_ENABLE 0 +#define BQ2597X_VBUS_ADC_DISABLE 1 + +#define BQ2597X_VAC_ADC_DIS_MASK 0x40 +#define BQ2597X_VAC_ADC_DIS_SHIFT 6 +#define BQ2597X_VAC_ADC_ENABLE 0 +#define BQ2597X_VAC_ADC_DISABLE 1 + +#define BQ2597X_VOUT_ADC_DIS_MASK 0x20 +#define BQ2597X_VOUT_ADC_DIS_SHIFT 5 +#define BQ2597X_VOUT_ADC_ENABLE 0 +#define BQ2597X_VOUT_ADC_DISABLE 1 + +#define BQ2597X_VBAT_ADC_DIS_MASK 0x10 +#define BQ2597X_VBAT_ADC_DIS_SHIFT 4 +#define BQ2597X_VBAT_ADC_ENABLE 0 +#define BQ2597X_VBAT_ADC_DISABLE 1 + +#define BQ2597X_IBAT_ADC_DIS_MASK 0x08 +#define BQ2597X_IBAT_ADC_DIS_SHIFT 3 +#define BQ2597X_IBAT_ADC_ENABLE 0 +#define BQ2597X_IBAT_ADC_DISABLE 1 + +#define BQ2597X_TSBUS_ADC_DIS_MASK 0x04 +#define BQ2597X_TSBUS_ADC_DIS_SHIFT 2 +#define BQ2597X_TSBUS_ADC_ENABLE 0 +#define BQ2597X_TSBUS_ADC_DISABLE 1 + +#define BQ2597X_TSBAT_ADC_DIS_MASK 0x02 +#define BQ2597X_TSBAT_ADC_DIS_SHIFT 1 +#define BQ2597X_TSBAT_ADC_ENABLE 0 +#define BQ2597X_TSBAT_ADC_DISABLE 1 + +#define BQ2597X_TDIE_ADC_DIS_MASK 0x01 +#define BQ2597X_TDIE_ADC_DIS_SHIFT 0 +#define BQ2597X_TDIE_ADC_ENABLE 0 +#define BQ2597X_TDIE_ADC_DISABLE 1 + +/* Register 16h */ +#define BQ2597X_REG_16 0x16 +#define BQ2597X_IBUS_POL_MASK 0x80 +#define BQ2597X_IBUS_POL_SHIFT 7 +#define BQ2597X_IBUS_POL_POSITIVE 0 +#define BQ2597X_IBUS_POL_NAGETIVE 1 + +#define BQ2597X_IBUS_ADC1_MASK 0x7F +#define BQ2597X_IBUS_ADC1_SHIFT 0 +#define BQ2597X_IBUS_ADC1_BASE 0 +#define BQ2597X_IBUS_ADC1_LSB 256 + +/* Register 17h */ +#define BQ2597X_REG_17 0x17 +#define BQ2597X_IBUS_ADC0_MASK 0xFF +#define BQ2597X_IBUS_ADC0_SHIFT 0 +#define BQ2597X_IBUS_ADC0_BASE 0 +#define BQ2597X_IBUS_ADC0_LSB 1 + +/* Register 18h */ +#define BQ2597X_REG_18 0x18 +#define BQ2597X_VBUS_POL_MASK 0x80 +#define BQ2597X_VBUS_POL_SHIFT 7 +#define BQ2597X_VBUS_POL_POSITIVE 0 +#define BQ2597X_VBUS_POL_NEGATIVE 1 + +#define BQ2597X_VBUS_ADC1_MASK 0x7F +#define BQ2597X_VBUS_ADC1_SHIFT 0 +#define BQ2597X_VBUS_ADC1_BASE 0 +#define BQ2597X_VBUS_ADC1_LSB 256 + +/* Register 19h */ +#define BQ2597X_REG_19 0x19 +#define BQ2597X_VBUS_ADC0_MASK 0xFF +#define BQ2597X_VBUS_ADC0_SHIFT 0 +#define BQ2597X_VBUS_ADC0_BASE 0 +#define BQ2597X_VBUS_ADC0_LSB 1 + +/* Register 1Ah */ +#define BQ2597X_REG_1A 0x1A +#define BQ2597X_VAC_POL_MASK 0x80 +#define BQ2597X_VAC_POL_SHIFT 7 +#define BQ2597X_VAC_POL_POSITIVE 0 +#define BQ2597X_VAC_POL_NEGATIVE 1 + +#define BQ2597X_VAC_ADC1_MASK 0x7F +#define BQ2597X_VAC_ADC1_SHIFT 0 +#define BQ2597X_VAC_ADC1_BASE 0 +#define BQ2597X_VAC_ADC1_LSB 256 + +/* Register 1Bh */ +#define BQ2597X_REG_1B 0x1B +#define BQ2597X_VAC_ADC0_MASK 0xFF +#define BQ2597X_VAC_ADC0_SHIFT 0 +#define BQ2597X_VAC_ADC0_BASE 0 +#define BQ2597X_VAC_ADC0_LSB 1 + +/* Register 1Ch */ +#define BQ2597X_REG_1C 0x1C +#define BQ2597X_VOUT_POL_MASK 0x80 +#define BQ2597X_VOUT_POL_SHIFT 7 +#define BQ2597X_VOUT_POL_POSITIVE 0 +#define BQ2597X_VOUT_POL_NEGATIVE 1 + +#define BQ2597X_VOUT_ADC1_MASK 0x7F +#define BQ2597X_VOUT_ADC1_SHIFT 0 +#define BQ2597X_VOUT_ADC1_BASE 0 +#define BQ2597X_VOUT_ADC1_LSB 256 + +/* Register 1Dh */ +#define BQ2597X_REG_1D 0x1D +#define BQ2597X_VOUT_ADC0_MASK 0xFF +#define BQ2597X_VOUT_ADC0_SHIFT 0 +#define BQ2597X_VOUT_ADC0_BASE 0 +#define BQ2597X_VOUT_ADC0_LSB 1 + +/* Register 1Eh */ +#define BQ2597X_REG_1E 0x1E +#define BQ2597X_VBAT_POL_MASK 0x80 +#define BQ2597X_VBAT_POL_SHIFT 7 +#define BQ2597X_VBAT_POL_POSITIVE 0 +#define BQ2597X_VBAT_POL_NEGATIVE 1 + +#define BQ2597X_VBAT_ADC1_MASK 0x7F +#define BQ2597X_VBAT_ADC1_SHIFT 0 +#define BQ2597X_VBAT_ADC1_BASE 0 +#define BQ2597X_VBAT_ADC1_LSB 256 + +/* Register 1Fh */ +#define BQ2597X_REG_1F 0x1F +#define BQ2597X_VBAT_ADC0_MASK 0xFF +#define BQ2597X_VBAT_ADC0_SHIFT 0 +#define BQ2597X_VBAT_ADC0_BASE 0 +#define BQ2597X_VBAT_ADC0_LSB 1 + +/* Register 20h */ +#define BQ2597X_REG_20 0x20 +#define BQ2597X_IBAT_POL_MASK 0x80 +#define BQ2597X_IBAT_POL_SHIFT 7 +#define BQ2597X_IBAT_POL_POSITIVE 0 +#define BQ2597X_IBAT_POL_NEGATIVE 1 + +#define BQ2597X_IBAT_ADC1_MASK 0x7F +#define BQ2597X_IBAT_ADC1_SHIFT 0 +#define BQ2597X_IBAT_ADC1_BASE 0 +#define BQ2597X_IBAT_ADC1_LSB 256 + +/* Register 21h */ +#define BQ2597X_REG_21 0x21 +#define BQ2597X_IBAT_ADC0_MASK 0xFF +#define BQ2597X_IBAT_ADC0_SHIFT 0 +#define BQ2597X_IBAT_ADC0_BASE 0 +#define BQ2597X_IBAT_ADC0_LSB 1 + +/* Register 22h */ +#define BQ2597X_REG_22 0x22 +#define BQ2597X_TSBUS_POL_MASK 0x80 +#define BQ2597X_TSBUS_POL_SHIFT 7 +#define BQ2597X_TSBUS_POL_POSITIVE 0 +#define BQ2597X_TSBUS_POL_NEGATIVE 1 + +#define BQ2597X_TSBUS_ADC1_MASK 0x7F +#define BQ2597X_TSBUS_ADC1_SHIFT 0 +#define BQ2597X_TSBUS_ADC1_BASE 0 +#define BQ2597X_TSBUS_ADC1_LSB 25 + +/* Register 23h */ +#define BQ2597X_REG_23 0x23 +#define BQ2597X_TSBUS_ADC0_MASK 0xFF +#define BQ2597X_TSBUS_ADC0_SHIFT 0 +#define BQ2597X_TSBUS_ADC0_BASE 0 +#define BQ2597X_TSBUS_ADC0_LSB 0.09766 + +/* Register 24h */ +#define BQ2597X_REG_24 0x24 +#define BQ2597X_TSBAT_POL_MASK 0x80 +#define BQ2597X_TSBAT_POL_SHIFT 7 +#define BQ2597X_TSBAT_POL_POSITIVE 0 +#define BQ2597X_TSBAT_POL_NEGATIVE 1 + +#define BQ2597X_TSBAT_ADC1_MASK 0x7F +#define BQ2597X_TSBAT_ADC1_SHIFT 0 +#define BQ2597X_TSBAT_ADC1_BASE 0 +#define BQ2597X_TSBAT_ADC1_LSB 25 + +/* Register 25h */ +#define BQ2597X_REG_25 0x25 +#define BQ2597X_TSBAT_ADC0_MASK 0xFF +#define BQ2597X_TSBAT_ADC0_SHIFT 0 +#define BQ2597X_TSBAT_ADC0_BASE 0 +#define BQ2597X_TSBAT_ADC0_LSB 0.09766 + +/* Register 26h */ +#define BQ2597X_REG_26 0x26 +#define BQ2597X_TDIE_POL_MASK 0x80 +#define BQ2597X_TDIE_POL_SHIFT 7 +#define BQ2597X_TDIE_POL_POSITIVE 0 +#define BQ2597X_TDIE_POL_NEGATIVE 1 + +#define BQ2597X_TDIE_ADC1_MASK 0x7F +#define BQ2597X_TDIE_ADC1_SHIFT 0 +#define BQ2597X_TDIE_ADC1_BASE 0 +#define BQ2597X_TDIE_ADC1_LSB 128 + +/* Register 27h */ +#define BQ2597X_REG_27 0x27 +#define BQ2597X_TDIE_ADC0_MASK 0xFF +#define BQ2597X_TDIE_ADC0_SHIFT 0 +#define BQ2597X_TDIE_ADC0_BASE 0 +#define BQ2597X_TDIE_ADC0_LSB 0.5 + +/* Register 28h */ +#define BQ2597X_REG_28 0x28 +#define BQ2597X_TSBUS_FLT1_MASK 0xFF +#define BQ2597X_TSBUS_FLT1_SHIFT 0 +#define BQ2597X_TSBUS_FLT1_BASE 0 +#define BQ2597X_TSBUS_FLT1_LSB 0.19531 + +/* Register 29h */ +#define BQ2597X_REG_29 0x29 +#define BQ2597X_TSBAT_FLT0_MASK 0xFF +#define BQ2597X_TSBAT_FLT0_SHIFT 0 +#define BQ2597X_TSBAT_FLT0_BASE 0 +#define BQ2597X_TSBAT_FLT0_LSB 0.19531 + +/* Register 2Ah */ +#define BQ2597X_REG_2A 0x2A +#define BQ2597X_TDIE_ALM_MASK 0xFF +#define BQ2597X_TDIE_ALM_SHIFT 0 +#define BQ2597X_TDIE_ALM_BASE 30 + +#define BQ2597X_TDIE_ALM_LSB \ + 2 /*careful \ +multiply is used for calc*/ + +/* Register 2Bh */ +#define BQ2597X_REG_2B 0x2B +#define BQ2597X_SS_TIMEOUT_SET_MASK 0xE0 +#define BQ2597X_SS_TIMEOUT_SET_SHIFT 5 +#define BQ2597X_SS_TIMEOUT_DISABLE 0 +#define BQ2597X_SS_TIMEOUT_12P5MS 1 +#define BQ2597X_SS_TIMEOUT_25MS 2 +#define BQ2597X_SS_TIMEOUT_50MS 3 +#define BQ2597X_SS_TIMEOUT_100MS 4 +#define BQ2597X_SS_TIMEOUT_400MS 5 +#define BQ2597X_SS_TIMEOUT_1500MS 6 +#define BQ2597X_SS_TIMEOUT_100000MS 7 + +#define BQ2597X_EN_REGULATION_MASK 0x10 +#define BQ2597X_EN_REGULATION_SHIFT 4 +#define BQ2597X_EN_REGULATION_ENABLE 1 +#define BQ2597X_EN_REGULATION_DISABLE 0 + +#define BQ2597X_VOUT_OVP_DIS_MASK 0x08 +#define BQ2597X_VOUT_OVP_DIS_SHIFT 3 +#define BQ2597X_VOUT_OVP_ENABLE 1 +#define BQ2597X_VOUT_OVP_DISABLE 0 + +#define BQ2597X_IBUS_UCP_RISE_TH_MASK 0x04 +#define BQ2597X_IBUS_UCP_RISE_TH_SHIFT 2 +#define BQ2597X_IBUS_UCP_RISE_300MA 0 +#define BQ2597X_IBUS_UCP_RISE_500MA 1 + +#define BQ2597X_SET_IBAT_SNS_RES_MASK 0x02 +#define BQ2597X_SET_IBAT_SNS_RES_SHIFT 1 +#define BQ2597X_SET_IBAT_SNS_RES_2MHM 0 +#define BQ2597X_SET_IBAT_SNS_RES_5MHM 1 + +#define BQ2597X_VAC_PD_EN_MASK 0x01 +#define BQ2597X_VAC_PD_EN_SHIFT 0 +#define BQ2597X_VAC_PD_ENABLE 1 +#define BQ2597X_VAC_PD_DISABLE 0 + +/* Register 2Ch */ +#define BQ2597X_REG_2C 0x2C +#define BQ2597X_IBAT_REG_MASK 0xC0 +#define BQ2597X_IBAT_REG_SHIFT 6 +#define BQ2597X_IBAT_REG_200MA 0 +#define BQ2597X_IBAT_REG_300MA 1 +#define BQ2597X_IBAT_REG_400MA 2 +#define BQ2597X_IBAT_REG_500MA 3 +#define BQ2597X_VBAT_REG_MASK 0x30 +#define BQ2597X_VBAT_REG_SHIFT 4 +#define BQ2597X_VBAT_REG_50MV 0 +#define BQ2597X_VBAT_REG_100MV 1 +#define BQ2597X_VBAT_REG_150MV 2 +#define BQ2597X_VBAT_REG_200MV 3 + +#define BQ2597X_VBAT_REG_ACTIVE_STAT_MASK 0x08 +#define BQ2597X_IBAT_REG_ACTIVE_STAT_MASK 0x04 +#define BQ2597X_VDROP_OVP_ACTIVE_STAT_MASK 0x02 +#define BQ2597X_VOUT_OVP_ACTIVE_STAT_MASK 0x01 + +#define BQ2597X_REG_2D 0x2D +#define BQ2597X_VBAT_REG_ACTIVE_FLAG_MASK 0x80 +#define BQ2597X_IBAT_REG_ACTIVE_FLAG_MASK 0x40 +#define BQ2597X_VDROP_OVP_FLAG_MASK 0x20 +#define BQ2597X_VOUT_OVP_FLAG_MASK 0x10 +#define BQ2597X_VBAT_REG_ACTIVE_MASK_MASK 0x08 +#define BQ2597X_IBAT_REG_ACTIVE_MASK_MASK 0x04 +#define BQ2597X_VDROP_OVP_MASK_MASK 0x02 +#define BQ2597X_VOUT_OVP_MASK_MASK 0x01 + +#define BQ2597X_REG_2E 0x2E +#define BQ2597X_VBUS_ERR_LOW_DG_MASK 0x10 +#define BQ2597X_VBUS_ERR_LOW_DG_SHIFT 4 +#define BQ2597X_VBUS_ERR_LOW_DG_10US 0 +#define BQ2597X_VBUS_ERR_LOW_DG_10MS 1 +#define BQ2597X_IBUS_LOW_DG_MASK 0x08 +#define BQ2597X_IBUS_LOW_DG_SHIFT 3 +#define BQ2597X_IBUS_LOW_DG_10US 0 +#define BQ2597X_IBUS_LOW_DG_5MS 1 + +#endif diff --git a/drivers/oneplus/power/supply/wlchg/bq2597x_charger.c b/drivers/oneplus/power/supply/wlchg/bq2597x_charger.c new file mode 100644 index 0000000000000000000000000000000000000000..bad78af83e3b214f96f9103904c32cc2ce9bebc9 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/bq2597x_charger.c @@ -0,0 +1,2595 @@ +/* + * BQ2570x battery charging driver + * + * Copyright (C) 2017 Texas Instruments * + * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#define pr_fmt(fmt) "[bq2597x] %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bq25970_reg.h" +#include "bq2597x_charger.h" + +#define BQ25970_ROLE_STDALONE 0 +#define BQ25970_ROLE_SLAVE 1 +#define BQ25970_ROLE_MASTER 2 + +enum { + BQ25970_STDALONE, + BQ25970_SLAVE, + BQ25970_MASTER, +}; + +static int bq2597x_mode_data[] = { + [BQ25970_STDALONE] = BQ25970_STDALONE, + [BQ25970_MASTER] = BQ25970_ROLE_MASTER, + [BQ25970_SLAVE] = BQ25970_ROLE_SLAVE, +}; + +#define BAT_OVP_ALARM BIT(7) +#define BAT_OCP_ALARM BIT(6) +#define BUS_OVP_ALARM BIT(5) +#define BUS_OCP_ALARM BIT(4) +#define BAT_UCP_ALARM BIT(3) +#define VBUS_INSERT BIT(2) +#define VBAT_INSERT BIT(1) +#define ADC_DONE BIT(0) +#define BQ_ALARM_MASK GENMASK(7, 1) + +#define BAT_OVP_FAULT BIT(7) +#define BAT_OCP_FAULT BIT(6) +#define BUS_OVP_FAULT BIT(5) +#define BUS_OCP_FAULT BIT(4) +#define TBUS_TBAT_ALARM BIT(3) +#define TS_BAT_FAULT BIT(2) +#define TS_BUS_FAULT BIT(1) +#define TS_DIE_FAULT BIT(0) + +/*below used for comm with other module*/ +#define BAT_OVP_FAULT_SHIFT 0 +#define BAT_OCP_FAULT_SHIFT 1 +#define BUS_OVP_FAULT_SHIFT 2 +#define BUS_OCP_FAULT_SHIFT 3 +#define BAT_THERM_FAULT_SHIFT 4 +#define BUS_THERM_FAULT_SHIFT 5 +#define DIE_THERM_FAULT_SHIFT 6 +#define BQ_FAULT_MASK (GENMASK(7, 4) | GENMASK(2, 0)) + +#define BAT_OVP_FAULT_MASK (1 << BAT_OVP_FAULT_SHIFT) +#define BAT_OCP_FAULT_MASK (1 << BAT_OCP_FAULT_SHIFT) +#define BUS_OVP_FAULT_MASK (1 << BUS_OVP_FAULT_SHIFT) +#define BUS_OCP_FAULT_MASK (1 << BUS_OCP_FAULT_SHIFT) +#define BAT_THERM_FAULT_MASK (1 << BAT_THERM_FAULT_SHIFT) +#define BUS_THERM_FAULT_MASK (1 << BUS_THERM_FAULT_SHIFT) +#define DIE_THERM_FAULT_MASK (1 << DIE_THERM_FAULT_SHIFT) + +#define BAT_OVP_ALARM_SHIFT 0 +#define BAT_OCP_ALARM_SHIFT 1 +#define BUS_OVP_ALARM_SHIFT 2 +#define BUS_OCP_ALARM_SHIFT 3 +#define BAT_THERM_ALARM_SHIFT 4 +#define BUS_THERM_ALARM_SHIFT 5 +#define DIE_THERM_ALARM_SHIFT 6 +#define BAT_UCP_ALARM_SHIFT 7 + +#define BAT_OVP_ALARM_MASK (1 << BAT_OVP_ALARM_SHIFT) +#define BAT_OCP_ALARM_MASK (1 << BAT_OCP_ALARM_SHIFT) +#define BUS_OVP_ALARM_MASK (1 << BUS_OVP_ALARM_SHIFT) +#define BUS_OCP_ALARM_MASK (1 << BUS_OCP_ALARM_SHIFT) +#define BAT_THERM_ALARM_MASK (1 << BAT_THERM_ALARM_SHIFT) +#define BUS_THERM_ALARM_MASK (1 << BUS_THERM_ALARM_SHIFT) +#define DIE_THERM_ALARM_MASK (1 << DIE_THERM_ALARM_SHIFT) +#define BAT_UCP_ALARM_MASK (1 << BAT_UCP_ALARM_SHIFT) + +#define VBAT_REG_STATUS_SHIFT 0 +#define IBAT_REG_STATUS_SHIFT 1 + +#define VBAT_REG_STATUS_MASK (1 << VBAT_REG_STATUS_SHIFT) +#define IBAT_REG_STATUS_MASK (1 << VBAT_REG_STATUS_SHIFT) + +#define bq_err(fmt, ...) \ + do { \ + if (bq->mode == BQ25970_ROLE_MASTER) \ + printk(KERN_ERR "[bq2597x-MASTER]:%s:" fmt, __func__, \ + ##__VA_ARGS__); \ + else if (bq->mode == BQ25970_ROLE_SLAVE) \ + printk(KERN_ERR "[bq2597x-SLAVE]:%s:" fmt, __func__, \ + ##__VA_ARGS__); \ + else \ + printk(KERN_ERR "[bq2597x-STANDALONE]:%s:" fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +#define bq_info(fmt, ...) \ + do { \ + if (bq->mode == BQ25970_ROLE_MASTER) \ + printk(KERN_INFO "[bq2597x-MASTER]:%s:" fmt, __func__, \ + ##__VA_ARGS__); \ + else if (bq->mode == BQ25970_ROLE_SLAVE) \ + printk(KERN_INFO "[bq2597x-SLAVE]:%s:" fmt, __func__, \ + ##__VA_ARGS__); \ + else \ + printk(KERN_INFO "[bq2597x-STANDALONE]:%s:" fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +#define bq_dbg(fmt, ...) \ + do { \ + if (bq->mode == BQ25970_ROLE_MASTER) \ + printk(KERN_DEBUG "[bq2597x-MASTER]:%s:" fmt, \ + __func__, ##__VA_ARGS__); \ + else if (bq->mode == BQ25970_ROLE_SLAVE) \ + printk(KERN_DEBUG "[bq2597x-SLAVE]:%s:" fmt, __func__, \ + ##__VA_ARGS__); \ + else \ + printk(KERN_DEBUG "[bq2597x-STANDALONE]:%s:" fmt, \ + __func__, ##__VA_ARGS__); \ + } while (0) + +/*end*/ + +struct bq2597x_cfg { + bool bat_ovp_disable; + bool bat_ocp_disable; + bool bat_ovp_alm_disable; + bool bat_ocp_alm_disable; + + int bat_ovp_th; + int bat_ovp_alm_th; + int bat_ocp_th; + int bat_ocp_alm_th; + + bool bus_ovp_alm_disable; + bool bus_ocp_disable; + bool bus_ocp_alm_disable; + + int bus_ovp_th; + int bus_ovp_alm_th; + int bus_ocp_th; + int bus_ocp_alm_th; + + bool bat_ucp_alm_disable; + + int bat_ucp_alm_th; + int ac_ovp_th; + + bool bat_therm_disable; + bool bus_therm_disable; + bool die_therm_disable; + + int bat_therm_th; /*in %*/ + int bus_therm_th; /*in %*/ + int die_therm_th; /*in degC*/ + + int sense_r_mohm; +}; + +struct bq2597x *bq_pump; +struct delayed_work get_reg_task_work; + +int bq2597x_enable_adc(struct bq2597x *bq, bool enable); +/************************************************************************/ +static int __bq2597x_read_byte(struct bq2597x *bq, u8 reg, u8 *data) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(bq->client, reg); + if (ret < 0) { + bq_err("i2c read fail: can't read from reg 0x%02X\n", reg); + return ret; + } + + *data = (u8)ret; + + return 0; +} + +static int __bq2597x_write_byte(struct bq2597x *bq, int reg, u8 val) +{ + s32 ret; + + ret = i2c_smbus_write_byte_data(bq->client, reg, val); + if (ret < 0) { + bq_err("i2c write fail: can't write 0x%02X to reg 0x%02X: %d\n", + val, reg, ret); + return ret; + } + return 0; +} + +static int __bq2597x_read_word(struct bq2597x *bq, u8 reg, u16 *data) +{ + s32 ret; + + ret = i2c_smbus_read_word_data(bq->client, reg); + if (ret < 0) { + bq_err("i2c read fail: can't read from reg 0x%02X\n", reg); + return ret; + } + + *data = (u16)ret; + + return 0; +} + +static int bq2597x_read_byte(struct bq2597x *bq, u8 reg, u8 *data) +{ + int ret; + + if (bq->skip_reads) { + *data = 0; + return 0; + } + + mutex_lock(&bq->i2c_rw_lock); + ret = __bq2597x_read_byte(bq, reg, data); + mutex_unlock(&bq->i2c_rw_lock); + + return ret; +} + +static int bq2597x_write_byte(struct bq2597x *bq, u8 reg, u8 data) +{ + int ret; + + if (bq->skip_writes) + return 0; + + mutex_lock(&bq->i2c_rw_lock); + ret = __bq2597x_write_byte(bq, reg, data); + mutex_unlock(&bq->i2c_rw_lock); + + return ret; +} + +static int bq2597x_read_word(struct bq2597x *bq, u8 reg, u16 *data) +{ + int ret; + + if (bq->skip_reads) { + *data = 0; + return 0; + } + + mutex_lock(&bq->i2c_rw_lock); + ret = __bq2597x_read_word(bq, reg, data); + mutex_unlock(&bq->i2c_rw_lock); + + return ret; +} + +static int bq2597x_update_bits(struct bq2597x *bq, u8 reg, u8 mask, u8 data) +{ + int ret; + u8 tmp; + + if (bq->skip_reads || bq->skip_writes) { + bq_err("skip because skip_reads=%d,skip_writes=%d\n", + bq->skip_reads, bq->skip_writes); + return 0; + } + + mutex_lock(&bq->i2c_rw_lock); + ret = __bq2597x_read_byte(bq, reg, &tmp); + if (ret) { + bq_err("Failed: reg=%02X, ret=%d\n", reg, ret); + goto out; + } + + bq_err("read reg(0x%02x)=0x%02x, wanna write data=0x%02x.\n", reg, tmp, + data); + tmp &= ~mask; + tmp |= data & mask; + + ret = __bq2597x_write_byte(bq, reg, tmp); + if (ret) + bq_err("Failed: reg=%02X, ret=%d\n", reg, ret); + + bq_err("write reg(0x%02x)=0x%02x.\n", reg, tmp); +out: + mutex_unlock(&bq->i2c_rw_lock); + return ret; +} + +/*********************************************************************/ + +static int bq2597x_enable_charge(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_CHG_ENABLE; + else + val = BQ2597X_CHG_DISABLE; + + val <<= BQ2597X_CHG_EN_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_0C, BQ2597X_CHG_EN_MASK, val); + + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_charge); + +int bq2597x_check_charge_enabled(struct bq2597x *bq, bool *enabled) +{ + int ret; + u8 val; + + if (bq == NULL) { + pr_err("bq2597x is null"); + return -ENODEV; + } + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0C, &val); + bq_dbg("read reg(0x0c)=0x%02x.\n", val); + if (!ret) + *enabled = !!(val & BQ2597X_CHG_EN_MASK); + return ret; +} + +int bq2597x_enable_charge_pump(bool enable) +{ + int ret = 0; + struct bq2597x *bq = bq_pump; + + if (bq == NULL) { + pr_err("bq2597x is null"); + return -ENODEV; + } + + bq_err("%s 2nd charge pump\n", enable ? "enable" : "disable"); + + ret = bq2597x_enable_adc(bq, enable); + if (ret) { + bq_err("adc %s err.\n", enable ? "enable" : "disable"); + return ret; + } + + ret = bq2597x_check_charge_enabled(bq, &bq->charge_enabled); + if (bq->charge_enabled == enable) { + bq_err("bq2597x is already %s.", + enable ? "enabled" : "disabled"); + return 0; + } + + ret = bq2597x_enable_charge(bq, enable); + if (ret) { + bq_err("%s bq err.\n", enable ? "enable" : "disable"); + return ret; + } + ret = bq2597x_check_charge_enabled(bq, &bq->charge_enabled); + return ret; +} + +static int bq2597x_enable_wdt(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_WATCHDOG_ENABLE; + else + val = BQ2597X_WATCHDOG_DISABLE; + + val <<= BQ2597X_WATCHDOG_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_0B, BQ2597X_WATCHDOG_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_wdt); + +static int bq2597x_set_wdt(struct bq2597x *bq, int ms) +{ + int ret; + u8 val; + + if (ms == 500) + val = BQ2597X_WATCHDOG_0P5S; + else if (ms == 1000) + val = BQ2597X_WATCHDOG_1S; + else if (ms == 5000) + val = BQ2597X_WATCHDOG_5S; + else if (ms == 30000) + val = BQ2597X_WATCHDOG_30S; + else + val = BQ2597X_WATCHDOG_30S; + + val <<= BQ2597X_WATCHDOG_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_0B, BQ2597X_WATCHDOG_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_wdt); + +static int bq2597x_enable_batovp(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BAT_OVP_ENABLE; + else + val = BQ2597X_BAT_OVP_DISABLE; + + val <<= BQ2597X_BAT_OVP_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_00, BQ2597X_BAT_OVP_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_batovp); + +static int bq2597x_set_batovp_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BAT_OVP_BASE) + threshold = BQ2597X_BAT_OVP_BASE; + + val = (threshold - BQ2597X_BAT_OVP_BASE) / BQ2597X_BAT_OVP_LSB; + + val <<= BQ2597X_BAT_OVP_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_00, BQ2597X_BAT_OVP_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_batovp_th); + +static int bq2597x_enable_batovp_alarm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BAT_OVP_ALM_ENABLE; + else + val = BQ2597X_BAT_OVP_ALM_DISABLE; + + val <<= BQ2597X_BAT_OVP_ALM_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_01, + BQ2597X_BAT_OVP_ALM_DIS_MASK, val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_batovp_alarm); + +static int bq2597x_set_batovp_alarm_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BAT_OVP_ALM_BASE) + threshold = BQ2597X_BAT_OVP_ALM_BASE; + + val = (threshold - BQ2597X_BAT_OVP_ALM_BASE) / BQ2597X_BAT_OVP_ALM_LSB; + + val <<= BQ2597X_BAT_OVP_ALM_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_01, BQ2597X_BAT_OVP_ALM_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_batovp_alarm_th); + +static int bq2597x_enable_batocp(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BAT_OCP_ENABLE; + else + val = BQ2597X_BAT_OCP_DISABLE; + + val <<= BQ2597X_BAT_OCP_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_02, BQ2597X_BAT_OCP_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_batocp); + +static int bq2597x_set_batocp_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BAT_OCP_BASE) + threshold = BQ2597X_BAT_OCP_BASE; + + val = (threshold - BQ2597X_BAT_OCP_BASE) / BQ2597X_BAT_OCP_LSB; + + val <<= BQ2597X_BAT_OCP_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_02, BQ2597X_BAT_OCP_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_batocp_th); + +static int bq2597x_enable_batocp_alarm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BAT_OCP_ALM_ENABLE; + else + val = BQ2597X_BAT_OCP_ALM_DISABLE; + + val <<= BQ2597X_BAT_OCP_ALM_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_03, + BQ2597X_BAT_OCP_ALM_DIS_MASK, val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_batocp_alarm); + +static int bq2597x_set_batocp_alarm_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BAT_OCP_ALM_BASE) + threshold = BQ2597X_BAT_OCP_ALM_BASE; + + val = (threshold - BQ2597X_BAT_OCP_ALM_BASE) / BQ2597X_BAT_OCP_ALM_LSB; + + val <<= BQ2597X_BAT_OCP_ALM_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_03, BQ2597X_BAT_OCP_ALM_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_batocp_alarm_th); + +static int bq2597x_set_busovp_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BUS_OVP_BASE) + threshold = BQ2597X_BUS_OVP_BASE; + + val = (threshold - BQ2597X_BUS_OVP_BASE) / BQ2597X_BUS_OVP_LSB; + + val <<= BQ2597X_BUS_OVP_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_06, BQ2597X_BUS_OVP_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_busovp_th); + +static int bq2597x_enable_busovp_alarm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BUS_OVP_ALM_ENABLE; + else + val = BQ2597X_BUS_OVP_ALM_DISABLE; + + val <<= BQ2597X_BUS_OVP_ALM_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_07, + BQ2597X_BUS_OVP_ALM_DIS_MASK, val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_busovp_alarm); + +static int bq2597x_set_busovp_alarm_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BUS_OVP_ALM_BASE) + threshold = BQ2597X_BUS_OVP_ALM_BASE; + + val = (threshold - BQ2597X_BUS_OVP_ALM_BASE) / BQ2597X_BUS_OVP_ALM_LSB; + + val <<= BQ2597X_BUS_OVP_ALM_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_07, BQ2597X_BUS_OVP_ALM_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_busovp_alarm_th); + +static int bq2597x_enable_busocp(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BUS_OCP_ENABLE; + else + val = BQ2597X_BUS_OCP_DISABLE; + + val <<= BQ2597X_BUS_OCP_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_08, BQ2597X_BUS_OCP_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_busocp); + +static int bq2597x_set_busocp_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BUS_OCP_BASE) + threshold = BQ2597X_BUS_OCP_BASE; + + val = (threshold - BQ2597X_BUS_OCP_BASE) / BQ2597X_BUS_OCP_LSB; + + val <<= BQ2597X_BUS_OCP_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_08, BQ2597X_BUS_OCP_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_busocp_th); + +static int bq2597x_enable_busocp_alarm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BUS_OCP_ALM_ENABLE; + else + val = BQ2597X_BUS_OCP_ALM_DISABLE; + + val <<= BQ2597X_BUS_OCP_ALM_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_09, + BQ2597X_BUS_OCP_ALM_DIS_MASK, val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_busocp_alarm); + +static int bq2597x_set_busocp_alarm_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BUS_OCP_ALM_BASE) + threshold = BQ2597X_BUS_OCP_ALM_BASE; + + val = (threshold - BQ2597X_BUS_OCP_ALM_BASE) / BQ2597X_BUS_OCP_ALM_LSB; + + val <<= BQ2597X_BUS_OCP_ALM_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_09, BQ2597X_BUS_OCP_ALM_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_busocp_alarm_th); + +static int bq2597x_enable_batucp_alarm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_BAT_UCP_ALM_ENABLE; + else + val = BQ2597X_BAT_UCP_ALM_DISABLE; + + val <<= BQ2597X_BAT_UCP_ALM_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_04, + BQ2597X_BAT_UCP_ALM_DIS_MASK, val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_batucp_alarm); + +static int bq2597x_set_batucp_alarm_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_BAT_UCP_ALM_BASE) + threshold = BQ2597X_BAT_UCP_ALM_BASE; + + val = (threshold - BQ2597X_BAT_UCP_ALM_BASE) / BQ2597X_BAT_UCP_ALM_LSB; + + val <<= BQ2597X_BAT_UCP_ALM_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_04, BQ2597X_BAT_UCP_ALM_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_batucp_alarm_th); + +static int bq2597x_set_acovp_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold < BQ2597X_AC_OVP_BASE) + threshold = BQ2597X_AC_OVP_BASE; + + if (threshold == BQ2597X_AC_OVP_6P5V) + val = 0x07; + else + val = (threshold - BQ2597X_AC_OVP_BASE) / BQ2597X_AC_OVP_LSB; + + val <<= BQ2597X_AC_OVP_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_05, BQ2597X_AC_OVP_MASK, val); + + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_acovp_th); + +static int bq2597x_set_vdrop_th(struct bq2597x *bq, int threshold) +{ + int ret; + u8 val; + + if (threshold == 300) + val = BQ2597X_VDROP_THRESHOLD_300MV; + else + val = BQ2597X_VDROP_THRESHOLD_400MV; + + val <<= BQ2597X_VDROP_THRESHOLD_SET_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_05, + BQ2597X_VDROP_THRESHOLD_SET_MASK, val); + + return ret; +} + +static int bq2597x_set_vdrop_deglitch(struct bq2597x *bq, int us) +{ + int ret; + u8 val; + + if (us == 8) + val = BQ2597X_VDROP_DEGLITCH_8US; + else + val = BQ2597X_VDROP_DEGLITCH_5MS; + + val <<= BQ2597X_VDROP_DEGLITCH_SET_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_05, + BQ2597X_VDROP_DEGLITCH_SET_MASK, val); + return ret; +} + +static int bq2597x_enable_bat_therm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_TSBAT_ENABLE; + else + val = BQ2597X_TSBAT_DISABLE; + + val <<= BQ2597X_TSBAT_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_0C, BQ2597X_TSBAT_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_bat_therm); + +/* + * the input threshold is the raw value that would write to register directly. + */ +static int bq2597x_set_bat_therm_th(struct bq2597x *bq, u8 threshold) +{ + int ret; + + ret = bq2597x_write_byte(bq, BQ2597X_REG_29, threshold); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_bat_therm_th); + +static int bq2597x_enable_bus_therm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_TSBUS_ENABLE; + else + val = BQ2597X_TSBUS_DISABLE; + + val <<= BQ2597X_TSBUS_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_0C, BQ2597X_TSBUS_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_bus_therm); + +/* + * the input threshold is the raw value that would write to register directly. + */ +static int bq2597x_set_bus_therm_th(struct bq2597x *bq, u8 threshold) +{ + int ret; + + ret = bq2597x_write_byte(bq, BQ2597X_REG_28, threshold); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_bus_therm_th); + +static int bq2597x_enable_die_therm(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_TDIE_ENABLE; + else + val = BQ2597X_TDIE_DISABLE; + + val <<= BQ2597X_TDIE_DIS_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_0C, BQ2597X_TDIE_DIS_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_die_therm); + +/* + * please be noted that the unit here is degC + */ +static int bq2597x_set_die_therm_th(struct bq2597x *bq, u8 threshold) +{ + int ret; + u8 val; + + /*BE careful, LSB is here is 1/LSB, so we use multiply here*/ + val = (threshold - BQ2597X_TDIE_ALM_BASE) * BQ2597X_TDIE_ALM_LSB; + val <<= BQ2597X_TDIE_ALM_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_2A, BQ2597X_TDIE_ALM_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_die_therm_th); + +int bq2597x_enable_adc(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_ADC_ENABLE; + else + val = BQ2597X_ADC_DISABLE; + + val <<= BQ2597X_ADC_EN_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_14, BQ2597X_ADC_EN_MASK, val); + if (ret == 0) + bq->adc_enabled = enable; + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_enable_adc); + +static int bq2597x_set_adc_average(struct bq2597x *bq, bool avg) +{ + int ret; + u8 val; + + if (avg) + val = BQ2597X_ADC_AVG_ENABLE; + else + val = BQ2597X_ADC_AVG_DISABLE; + + val <<= BQ2597X_ADC_AVG_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_14, BQ2597X_ADC_AVG_MASK, + val); + return 0; +} +EXPORT_SYMBOL_GPL(bq2597x_set_adc_average); + +static int bq2597x_set_adc_scanrate(struct bq2597x *bq, bool oneshot) +{ + int ret; + u8 val; + + if (oneshot) + val = BQ2597X_ADC_RATE_ONESHOT; + else + val = BQ2597X_ADC_RATE_CONTINOUS; + + val <<= BQ2597X_ADC_RATE_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_14, BQ2597X_ADC_EN_MASK, val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_adc_scanrate); + +static int bq2597x_set_adc_bits(struct bq2597x *bq, int bits) +{ + int ret; + u8 val; + + if (bits > 15) + bits = 15; + if (bits < 12) + bits = 12; + val = 15 - bits; + + val <<= BQ2597X_ADC_SAMPLE_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_14, BQ2597X_ADC_SAMPLE_MASK, + val); + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_adc_bits); + +#define ADC_REG_BASE 0x16 +int bq2597x_get_adc_data(struct bq2597x *bq, int channel, int *result) +{ + int ret; + u16 val; + s16 t; + + if (channel > ADC_MAX_NUM) + return -EINVAL; + + ret = bq2597x_read_word(bq, ADC_REG_BASE + (channel << 1), &val); + if (ret < 0) + return ret; + t = val & 0xFF; + t <<= 8; + t |= (val >> 8) & 0xFF; + *result = t; + + return 0; +} +EXPORT_SYMBOL_GPL(bq2597x_get_adc_data); + +static int bq2597x_set_adc_scan(struct bq2597x *bq, int channel, bool enable) +{ + int ret; + u8 reg; + u8 mask; + u8 shift; + u8 val; + + if (channel > ADC_MAX_NUM) + return -EINVAL; + + if (channel == ADC_IBUS) { + reg = BQ2597X_REG_14; + shift = BQ2597X_IBUS_ADC_DIS_SHIFT; + mask = BQ2597X_IBUS_ADC_DIS_MASK; + } else { + reg = BQ2597X_REG_15; + shift = 8 - channel; + mask = 1 << shift; + } + + if (enable) + val = 0 << shift; + else + val = 1 << shift; + + ret = bq2597x_update_bits(bq, reg, mask, val); + + return ret; +} + +static int bq2597x_set_alarm_int_mask(struct bq2597x *bq, u8 mask) +{ + int ret; + u8 val; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0F, &val); + if (ret) + return ret; + + val |= mask; + + ret = bq2597x_write_byte(bq, BQ2597X_REG_0F, val); + + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_alarm_int_mask); + +static int bq2597x_clear_alarm_int_mask(struct bq2597x *bq, u8 mask) +{ + int ret; + u8 val; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0F, &val); + if (ret) + return ret; + + val &= ~mask; + + ret = bq2597x_write_byte(bq, BQ2597X_REG_0F, val); + + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_clear_alarm_int_mask); + +static int bq2597x_set_fault_int_mask(struct bq2597x *bq, u8 mask) +{ + int ret; + u8 val; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_12, &val); + if (ret) + return ret; + + val |= mask; + + ret = bq2597x_write_byte(bq, BQ2597X_REG_12, val); + + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_set_fault_int_mask); + +static int bq2597x_clear_fault_int_mask(struct bq2597x *bq, u8 mask) +{ + int ret; + u8 val; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_12, &val); + if (ret) + return ret; + + val &= ~mask; + + ret = bq2597x_write_byte(bq, BQ2597X_REG_12, val); + + return ret; +} +EXPORT_SYMBOL_GPL(bq2597x_clear_fault_int_mask); + +static int bq2597x_set_sense_resistor(struct bq2597x *bq, int r_mohm) +{ + int ret; + u8 val; + + if (r_mohm == 2) + val = BQ2597X_SET_IBAT_SNS_RES_2MHM; + else if (r_mohm == 5) + val = BQ2597X_SET_IBAT_SNS_RES_5MHM; + else + return 0; + + val <<= BQ2597X_SET_IBAT_SNS_RES_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_2B, + BQ2597X_SET_IBAT_SNS_RES_MASK, val); + return ret; +} + +static int bq2597x_enable_regulation(struct bq2597x *bq, bool enable) +{ + int ret; + u8 val; + + if (enable) + val = BQ2597X_EN_REGULATION_ENABLE; + else + val = BQ2597X_EN_REGULATION_DISABLE; + + val <<= BQ2597X_EN_REGULATION_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_2B, + BQ2597X_EN_REGULATION_MASK, val); + + return ret; +} + +static int bq2597x_set_ibus_ucp_rise_th(struct bq2597x *bq, int th_ma) +{ + int ret; + u8 val; + + if (th_ma == 500) + val = BQ2597X_IBUS_UCP_RISE_500MA; + else + val = BQ2597X_IBUS_UCP_RISE_300MA; + + val <<= BQ2597X_IBUS_UCP_RISE_TH_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_2B, + BQ2597X_IBUS_UCP_RISE_TH_MASK, val); + + return ret; +} + +static int bq2597x_set_ss_timeout(struct bq2597x *bq, int timeout) +{ + int ret; + u8 val; + + switch (timeout) { + case 0: + val = BQ2597X_SS_TIMEOUT_DISABLE; + break; + case 12: + val = BQ2597X_SS_TIMEOUT_12P5MS; + break; + case 25: + val = BQ2597X_SS_TIMEOUT_25MS; + break; + case 50: + val = BQ2597X_SS_TIMEOUT_50MS; + break; + case 100: + val = BQ2597X_SS_TIMEOUT_100MS; + break; + case 400: + val = BQ2597X_SS_TIMEOUT_400MS; + break; + case 1500: + val = BQ2597X_SS_TIMEOUT_1500MS; + break; + case 100000: + val = BQ2597X_SS_TIMEOUT_100000MS; + break; + default: + val = BQ2597X_SS_TIMEOUT_DISABLE; + break; + } + + val <<= BQ2597X_SS_TIMEOUT_SET_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_2B, + BQ2597X_SS_TIMEOUT_SET_MASK, val); + + return ret; +} + +static int bq2597x_set_ibat_reg_th(struct bq2597x *bq, int th_ma) +{ + int ret; + u8 val; + + if (th_ma == 200) + val = BQ2597X_IBAT_REG_200MA; + else if (th_ma == 300) + val = BQ2597X_IBAT_REG_300MA; + else if (th_ma == 400) + val = BQ2597X_IBAT_REG_400MA; + else if (th_ma == 500) + val = BQ2597X_IBAT_REG_500MA; + else + val = BQ2597X_IBAT_REG_500MA; + + val <<= BQ2597X_IBAT_REG_SHIFT; + ret = bq2597x_update_bits(bq, BQ2597X_REG_2C, BQ2597X_IBAT_REG_MASK, + val); + + return ret; +} + +static int bq2597x_set_vbat_reg_th(struct bq2597x *bq, int th_mv) +{ + int ret; + u8 val; + + if (th_mv == 50) + val = BQ2597X_VBAT_REG_50MV; + else if (th_mv == 100) + val = BQ2597X_VBAT_REG_100MV; + else if (th_mv == 150) + val = BQ2597X_VBAT_REG_150MV; + else + val = BQ2597X_VBAT_REG_200MV; + + val <<= BQ2597X_VBAT_REG_SHIFT; + + ret = bq2597x_update_bits(bq, BQ2597X_REG_2C, BQ2597X_VBAT_REG_MASK, + val); + + return ret; +} + +#if 0 +static int bq2597x_check_reg_status(struct bq2597x *bq) +{ + int ret; + u8 val; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_2C, &val); + if (!ret) { + bq->vbat_reg = !!(val & BQ2597X_VBAT_REG_ACTIVE_STAT_MASK); + bq->ibat_reg = !!(val & BQ2597X_IBAT_REG_ACTIVE_STAT_MASK); + } + + return ret; +} +#endif + +static int bq2597x_get_work_mode(struct bq2597x *bq, int *mode) +{ + int ret; + u8 val; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0C, &val); + + if (ret) { + bq_err("Failed to read operation mode register\n"); + return ret; + } + + val = (val & BQ2597X_MS_MASK) >> BQ2597X_MS_SHIFT; + if (val == BQ2597X_MS_MASTER) + *mode = BQ25970_ROLE_MASTER; + else if (val == BQ2597X_MS_SLAVE) + *mode = BQ25970_ROLE_SLAVE; + else + *mode = BQ25970_ROLE_STDALONE; + + bq_info("work mode:%s\n", + *mode == BQ25970_ROLE_STDALONE ? + "Standalone" : + (*mode == BQ25970_ROLE_SLAVE ? "Slave" : "Master")); + return ret; +} + +static int bq2597x_detect_device(struct bq2597x *bq) +{ + int ret; + u8 data; + + ret = bq2597x_read_byte(bq, BQ2597X_REG_13, &data); + bq_err("bq2597x:addr0x13=0x%02x.\n", data); + if (ret == 0) { + bq->part_no = (data & BQ2597X_DEV_ID_MASK); + bq->part_no >>= BQ2597X_DEV_ID_SHIFT; + } + + return ret; +} + +static int bq2597x_parse_dt(struct bq2597x *bq, struct device *dev) +{ + int ret; + struct device_node *np = dev->of_node; + + bq->cfg = devm_kzalloc(dev, sizeof(struct bq2597x_cfg), GFP_KERNEL); + + if (!bq->cfg) + return -ENOMEM; + + bq->cfg->bat_ovp_disable = + of_property_read_bool(np, "ti,bq2597x,bat-ovp-disable"); + bq->cfg->bat_ocp_disable = + of_property_read_bool(np, "ti,bq2597x,bat-ocp-disable"); + bq->cfg->bat_ovp_alm_disable = + of_property_read_bool(np, "ti,bq2597x,bat-ovp-alarm-disable"); + bq->cfg->bat_ocp_alm_disable = + of_property_read_bool(np, "ti,bq2597x,bat-ocp-alarm-disable"); + bq->cfg->bus_ocp_disable = + of_property_read_bool(np, "ti,bq2597x,bus-ocp-disable"); + bq->cfg->bus_ovp_alm_disable = + of_property_read_bool(np, "ti,bq2597x,bus-ovp-alarm-disable"); + bq->cfg->bus_ocp_alm_disable = + of_property_read_bool(np, "ti,bq2597x,bus-ocp-alarm-disable"); + bq->cfg->bat_ucp_alm_disable = + of_property_read_bool(np, "ti,bq2597x,bat-ucp-alarm-disable"); + bq->cfg->bat_therm_disable = + of_property_read_bool(np, "ti,bq2597x,bat-therm-disable"); + bq->cfg->bus_therm_disable = + of_property_read_bool(np, "ti,bq2597x,bus-therm-disable"); + bq->cfg->die_therm_disable = + of_property_read_bool(np, "ti,bq2597x,die-therm-disable"); + + ret = of_property_read_u32(np, "ti,bq2597x,bat-ovp-threshold", + &bq->cfg->bat_ovp_th); + if (ret) { + bq_err("failed to read bat-ovp-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bat-ovp-alarm-threshold", + &bq->cfg->bat_ovp_alm_th); + if (ret) { + bq_err("failed to read bat-ovp-alarm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bat-ocp-threshold", + &bq->cfg->bat_ocp_th); + if (ret) { + bq_err("failed to read bat-ocp-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bat-ocp-alarm-threshold", + &bq->cfg->bat_ocp_alm_th); + if (ret) { + bq_err("failed to read bat-ocp-alarm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bus-ovp-threshold", + &bq->cfg->bus_ovp_th); + if (ret) { + bq_err("failed to read bus-ovp-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bus-ovp-alarm-threshold", + &bq->cfg->bus_ovp_alm_th); + if (ret) { + bq_err("failed to read bus-ovp-alarm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bus-ocp-threshold", + &bq->cfg->bus_ocp_th); + if (ret) { + bq_err("failed to read bus-ocp-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bus-ocp-alarm-threshold", + &bq->cfg->bus_ocp_alm_th); + if (ret) { + bq_err("failed to read bus-ocp-alarm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bat-ucp-alarm-threshold", + &bq->cfg->bat_ucp_alm_th); + if (ret) { + bq_err("failed to read bat-ucp-alarm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bat-therm-threshold", + &bq->cfg->bat_therm_th); + if (ret) { + bq_err("failed to read bat-therm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,bus-therm-threshold", + &bq->cfg->bus_therm_th); + if (ret) { + bq_err("failed to read bus-therm-threshold\n"); + return ret; + } + ret = of_property_read_u32(np, "ti,bq2597x,die-therm-threshold", + &bq->cfg->die_therm_th); + if (ret) { + bq_err("failed to read die-therm-threshold\n"); + return ret; + } + + ret = of_property_read_u32(np, "ti,bq2597x,ac-ovp-threshold", + &bq->cfg->ac_ovp_th); + if (ret) { + bq_err("failed to read ac-ovp-threshold\n"); + return ret; + } + + ret = of_property_read_u32(np, "ti,bq2597x,sense-resistor-mohm", + &bq->cfg->sense_r_mohm); + if (ret) { + bq_err("failed to read sense-resistor-mohm\n"); + return ret; + } + + return 0; +} + +static int bq2597x_init_protection(struct bq2597x *bq) +{ + int ret; + + ret = bq2597x_enable_batovp(bq, !bq->cfg->bat_ovp_disable); + bq_info("%s bat ovp %s\n", + bq->cfg->bat_ovp_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_batocp(bq, !bq->cfg->bat_ocp_disable); + bq_info("%s bat ocp %s\n", + bq->cfg->bat_ocp_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_batovp_alarm(bq, !bq->cfg->bat_ovp_alm_disable); + bq_info("%s bat ovp alarm %s\n", + bq->cfg->bat_ovp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_batocp_alarm(bq, !bq->cfg->bat_ocp_alm_disable); + bq_info("%s bat ocp alarm %s\n", + bq->cfg->bat_ocp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_batucp_alarm(bq, !bq->cfg->bat_ucp_alm_disable); + bq_info("%s bat ocp alarm %s\n", + bq->cfg->bat_ucp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_busovp_alarm(bq, !bq->cfg->bus_ovp_alm_disable); + bq_info("%s bus ovp alarm %s\n", + bq->cfg->bus_ovp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_busocp(bq, !bq->cfg->bus_ocp_disable); + bq_info("%s bus ocp %s\n", + bq->cfg->bus_ocp_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_busocp_alarm(bq, !bq->cfg->bus_ocp_alm_disable); + bq_info("%s bus ocp alarm %s\n", + bq->cfg->bus_ocp_alm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_bat_therm(bq, !bq->cfg->bat_therm_disable); + bq_info("%s bat therm %s\n", + bq->cfg->bat_therm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_bus_therm(bq, !bq->cfg->bus_therm_disable); + bq_info("%s bus therm %s\n", + bq->cfg->bus_therm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_enable_die_therm(bq, !bq->cfg->die_therm_disable); + bq_info("%s die therm %s\n", + bq->cfg->die_therm_disable ? "disable" : "enable", + !ret ? "successfullly" : "failed"); + + ret = bq2597x_set_batovp_th(bq, bq->cfg->bat_ovp_th); + bq_info("set bat ovp th %d %s\n", bq->cfg->bat_ovp_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_batovp_alarm_th(bq, bq->cfg->bat_ovp_alm_th); + bq_info("set bat ovp alarm threshold %d %s\n", bq->cfg->bat_ovp_alm_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_batocp_th(bq, bq->cfg->bat_ocp_th); + bq_info("set bat ocp threshold %d %s\n", bq->cfg->bat_ocp_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_batocp_alarm_th(bq, bq->cfg->bat_ocp_alm_th); + bq_info("set bat ocp alarm threshold %d %s\n", bq->cfg->bat_ocp_alm_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_busovp_th(bq, bq->cfg->bus_ovp_th); + bq_info("set bus ovp threshold %d %s\n", bq->cfg->bus_ovp_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_busovp_alarm_th(bq, bq->cfg->bus_ovp_alm_th); + bq_info("set bus ovp alarm threshold %d %s\n", bq->cfg->bus_ovp_alm_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_busocp_th(bq, bq->cfg->bus_ocp_th); + bq_info("set bus ocp threshold %d %s\n", bq->cfg->bus_ocp_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_busocp_alarm_th(bq, bq->cfg->bus_ocp_alm_th); + bq_info("set bus ocp alarm th %d %s\n", bq->cfg->bus_ocp_alm_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_batucp_alarm_th(bq, bq->cfg->bat_ucp_alm_th); + bq_info("set bat ucp threshold %d %s\n", bq->cfg->bat_ucp_alm_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_bat_therm_th(bq, bq->cfg->bat_therm_th); + bq_info("set die therm threshold %d %s\n", bq->cfg->bat_therm_th, + !ret ? "successfully" : "failed"); + ret = bq2597x_set_bus_therm_th(bq, bq->cfg->bus_therm_th); + bq_info("set bus therm threshold %d %s\n", bq->cfg->bus_therm_th, + !ret ? "successfully" : "failed"); + ret = bq2597x_set_die_therm_th(bq, bq->cfg->die_therm_th); + bq_info("set die therm threshold %d %s\n", bq->cfg->die_therm_th, + !ret ? "successfully" : "failed"); + + ret = bq2597x_set_acovp_th(bq, bq->cfg->ac_ovp_th); + bq_info("set ac ovp threshold %d %s\n", bq->cfg->ac_ovp_th, + !ret ? "successfully" : "failed"); + + return 0; +} + +static int bq2597x_init_adc(struct bq2597x *bq) +{ + bq2597x_set_adc_scanrate(bq, false); + bq2597x_set_adc_bits(bq, 13); + bq2597x_set_adc_average(bq, true); + bq2597x_set_adc_scan(bq, ADC_IBUS, true); + bq2597x_set_adc_scan(bq, ADC_VBUS, true); + bq2597x_set_adc_scan(bq, ADC_VOUT, false); + bq2597x_set_adc_scan(bq, ADC_VBAT, true); + bq2597x_set_adc_scan(bq, ADC_IBAT, true); + bq2597x_set_adc_scan(bq, ADC_TBUS, true); + bq2597x_set_adc_scan(bq, ADC_TBAT, true); + bq2597x_set_adc_scan(bq, ADC_TDIE, true); + bq2597x_set_adc_scan(bq, ADC_VAC, true); + + //bq2597x_enable_adc(bq, true); + + return 0; +} + +static int bq2597x_init_int_src(struct bq2597x *bq) +{ + int ret; + /*TODO:be careful ts bus and ts bat alarm bit mask is in + * fault mask register, so you need call + * bq2597x_set_fault_int_mask for tsbus and tsbat alarm + */ + ret = bq2597x_set_alarm_int_mask(bq, ADC_DONE | BAT_UCP_ALARM | + BAT_OVP_ALARM); + if (ret) { + bq_err("failed to set alarm mask:%d\n", ret); + return ret; + } +#if 0 + ret = bq2597x_set_fault_int_mask(bq, TS_BUS_FAULT); + if (ret) { + bq_err("failed to set fault mask:%d\n", ret); + return ret; + } +#endif + return ret; +} + +static int bq2597x_set_deglitch_long_time(struct bq2597x *bq) +{ + int ret; + u8 val_vbus_err_low_dg; + u8 val_ibus_low_dg; + u8 val; + + val_vbus_err_low_dg = BQ2597X_VBUS_ERR_LOW_DG_10MS; + val_vbus_err_low_dg <<= BQ2597X_VBUS_ERR_LOW_DG_SHIFT; + val_ibus_low_dg = BQ2597X_IBUS_LOW_DG_10US; + val_ibus_low_dg <<= BQ2597X_IBUS_LOW_DG_SHIFT; + val = val_vbus_err_low_dg | val_ibus_low_dg; + + ret = bq2597x_update_bits( + bq, BQ2597X_REG_2E, + BQ2597X_VBUS_ERR_LOW_DG_MASK | BQ2597X_IBUS_LOW_DG_MASK, val); + + return ret; +} + +static int bq2597x_init_regulation(struct bq2597x *bq) +{ + int ret; + + ret = bq2597x_set_ibat_reg_th(bq, 300); + if (ret) { + bq_err("set ibat reg err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_set_vbat_reg_th(bq, 100); + if (ret) { + bq_err("set vbat reg err, ret=%d\n", ret); + return ret; + } + + ret = bq2597x_set_vdrop_deglitch(bq, 5000); + if (ret) { + bq_err("set vdrop deglitch err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_set_vdrop_th(bq, 400); + if (ret) { + bq_err("set vdrop err, ret=%d\n", ret); + return ret; + } + + ret = bq2597x_enable_regulation(bq, false); + if (ret) { + bq_err("disable regulation err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_set_ibus_ucp_rise_th(bq, 500); + if (ret) { + bq_err("set ibus ucp rise err, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int bq2597x_init_device(struct bq2597x *bq) +{ + int ret; + + ret = bq2597x_enable_wdt(bq, false); + if (ret) { + bq_err("disable wdt err, ret=%d\n", ret); + return ret; + } + + ret = bq2597x_set_ss_timeout(bq, 100000); + if (ret) { + bq_err("set ss timeout err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_set_sense_resistor(bq, bq->cfg->sense_r_mohm); + if (ret) { + bq_err("set sense resistor err, ret=%d\n", ret); + return ret; + } + + ret = bq2597x_init_protection(bq); + if (ret) { + bq_err("init protection err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_init_adc(bq); + if (ret) { + bq_err("init adc err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_init_int_src(bq); + if (ret) { + bq_err("init int src err, ret=%d\n", ret); + return ret; + } + + ret = bq2597x_init_regulation(bq); + if (ret) { + bq_err("init regulation err, ret=%d\n", ret); + return ret; + } + ret = bq2597x_set_deglitch_long_time(bq); + if (ret) { + bq_err("set deglitch long time err, ret=%d\n", ret); + return ret; + } + + return 0; +} + +#if 0 +static int bq2597x_set_present(struct bq2597x *bq, bool present) +{ + bq->usb_present = present; + + if (present) + bq2597x_init_device(bq); + return 0; +} +#endif + +static ssize_t bq2597x_show_registers(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct bq2597x *bq = dev_get_drvdata(dev); + u8 addr; + u8 val; + u8 tmpbuf[300]; + int len; + int idx = 0; + int ret; + + idx = snprintf(buf, PAGE_SIZE, "%s:\n", "bq25970"); + for (addr = 0x0; addr <= 0x2B; addr++) { + ret = bq2597x_read_byte(bq, addr, &val); + if (ret == 0) { + len = snprintf(tmpbuf, PAGE_SIZE - idx, + "Reg[%.2X] = 0x%.2x\n", addr, val); + memcpy(&buf[idx], tmpbuf, len); + idx += len; + } + } + + return idx; +} + +static ssize_t bq2597x_store_register(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bq2597x *bq = dev_get_drvdata(dev); + int ret; + unsigned int reg; + unsigned int val; + + ret = sscanf(buf, "%x %x", ®, &val); + if (ret == 2 && reg <= 0x2B) + bq2597x_write_byte(bq, (unsigned char)reg, (unsigned char)val); + + return count; +} + +static DEVICE_ATTR(registers, 0660, bq2597x_show_registers, + bq2597x_store_register); + +static struct attribute *bq2597x_attributes[] = { + &dev_attr_registers.attr, + NULL, +}; + +static const struct attribute_group bq2597x_attr_group = { + .attrs = bq2597x_attributes, +}; + +#if 0 +static enum power_supply_property bq2597x_charger_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_STATUS, + + POWER_SUPPLY_PROP_TI_BATTERY_PRESENT, + POWER_SUPPLY_PROP_TI_VBUS_PRESENT, + POWER_SUPPLY_PROP_TI_BATTERY_VOLTAGE, + POWER_SUPPLY_PROP_TI_BATTERY_CURRENT, + POWER_SUPPLY_PROP_TI_BATTERY_TEMPERATURE, + POWER_SUPPLY_PROP_TI_BUS_VOLTAGE, + POWER_SUPPLY_PROP_TI_BUS_CURRENT, + POWER_SUPPLY_PROP_TI_BUS_TEMPERATURE, + POWER_SUPPLY_PROP_TI_DIE_TEMPERATURE, + POWER_SUPPLY_PROP_TI_ALARM_STATUS, + POWER_SUPPLY_PROP_TI_FAULT_STATUS, + POWER_SUPPLY_PROP_TI_REG_STATUS, + +}; + +static void bq2597x_check_alarm_status(struct bq2597x *bq); +static void bq2597x_check_fault_status(struct bq2597x *bq); + +static int bq2597x_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct bq2597x *bq = power_supply_get_drvdata(psy); + int result; + int ret; + u8 reg_val; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + bq2597x_check_charge_enabled(bq, &bq->charge_enabled); + val->intval = bq->charge_enabled; + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = 0; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = bq->usb_present; + break; + case POWER_SUPPLY_PROP_TI_BATTERY_PRESENT: + ret = bq2597x_read_byte(bq, BQ2597X_REG_0D, ®_val); + if (!ret) + bq->batt_present = !!(reg_val & VBAT_INSERT); + val->intval = bq->batt_present; + break; + case POWER_SUPPLY_PROP_TI_VBUS_PRESENT: + ret = bq2597x_read_byte(bq, BQ2597X_REG_0D, ®_val); + if (!ret) + bq->vbus_present = !!(reg_val & VBUS_INSERT); + val->intval = bq->vbus_present; + break; + case POWER_SUPPLY_PROP_TI_BATTERY_VOLTAGE: + ret = bq2597x_get_adc_data(bq, ADC_VBAT, &result); + if (!ret) + bq->vbat_volt = result; + + val->intval = bq->vbat_volt; + break; + case POWER_SUPPLY_PROP_TI_BATTERY_CURRENT: + ret = bq2597x_get_adc_data(bq, ADC_IBAT, &result); + if (!ret) + bq->ibat_curr = result; + + val->intval = bq->ibat_curr; + break; + case POWER_SUPPLY_PROP_TI_BATTERY_TEMPERATURE: + ret = bq2597x_get_adc_data(bq, ADC_TBAT, &result); + if (!ret) + bq->bat_temp = result; + + val->intval = bq->bat_temp; + break; + case POWER_SUPPLY_PROP_TI_BUS_VOLTAGE: + ret = bq2597x_get_adc_data(bq, ADC_VBUS, &result); + if (!ret) + bq->vbus_volt = result; + + val->intval = bq->vbus_volt; + break; + case POWER_SUPPLY_PROP_TI_BUS_CURRENT: + ret = bq2597x_get_adc_data(bq, ADC_IBUS, &result); + if (!ret) + bq->ibus_curr = result; + + val->intval = bq->ibus_curr; + break; + case POWER_SUPPLY_PROP_TI_BUS_TEMPERATURE: + ret = bq2597x_get_adc_data(bq, ADC_TBUS, &result); + if (!ret) + bq->bus_temp = result; + + val->intval = bq->bus_temp; + break; + case POWER_SUPPLY_PROP_TI_DIE_TEMPERATURE: + ret = bq2597x_get_adc_data(bq, ADC_TDIE, &result); + if (!ret) + bq->die_temp = result; + + val->intval = bq->die_temp; + break; + case POWER_SUPPLY_PROP_TI_ALARM_STATUS: + + bq2597x_check_alarm_status(bq); + + val->intval = ((bq->bat_ovp_alarm << BAT_OVP_ALARM_SHIFT) | + (bq->bat_ocp_alarm << BAT_OCP_ALARM_SHIFT) | + (bq->bat_ucp_alarm << BAT_UCP_ALARM_SHIFT) | + (bq->bus_ovp_alarm << BUS_OVP_ALARM_SHIFT) | + (bq->bus_ocp_alarm << BUS_OCP_ALARM_SHIFT) | + (bq->bat_therm_alarm << BAT_THERM_ALARM_SHIFT) | + (bq->bus_therm_alarm << BUS_THERM_ALARM_SHIFT) | + (bq->die_therm_alarm << DIE_THERM_ALARM_SHIFT)); + break; + + case POWER_SUPPLY_PROP_TI_FAULT_STATUS: + bq2597x_check_fault_status(bq); + + val->intval = ((bq->bat_ovp_fault << BAT_OVP_FAULT_SHIFT) | + (bq->bat_ocp_fault << BAT_OCP_FAULT_SHIFT) | + (bq->bus_ovp_fault << BUS_OVP_FAULT_SHIFT) | + (bq->bus_ocp_fault << BUS_OCP_FAULT_SHIFT) | + (bq->bat_therm_fault << BAT_THERM_FAULT_SHIFT) | + (bq->bus_therm_fault << BUS_THERM_FAULT_SHIFT) | + (bq->die_therm_fault << DIE_THERM_FAULT_SHIFT)); + break; + + case POWER_SUPPLY_PROP_TI_REG_STATUS: + bq2597x_check_reg_status(bq); + val->intval = (bq->vbat_reg << VBAT_REG_STATUS_SHIFT) | + (bq->ibat_reg << IBAT_REG_STATUS_SHIFT); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bq2597x_charger_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct bq2597x *bq = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + bq2597x_enable_charge(bq, val->intval); + bq2597x_check_charge_enabled(bq, &bq->charge_enabled); + bq_info("POWER_SUPPLY_PROP_CHARGING_ENABLED: %s\n", + val->intval ? "enable" : "disable"); + break; + case POWER_SUPPLY_PROP_PRESENT: + bq2597x_set_present(bq, !!val->intval); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bq2597x_charger_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + int ret; + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static int bq2597x_psy_register(struct bq2597x *bq) +{ + // int ret; + + bq->psy_cfg.drv_data = bq; + bq->psy_cfg.of_node = bq->dev->of_node; + + if (bq->mode == BQ25970_ROLE_MASTER) + bq->psy_desc.name = "bq2597x-master"; + else if (bq->mode == BQ25970_ROLE_SLAVE) + bq->psy_desc.name = "bq2597x-slave"; + else + bq->psy_desc.name = "bq2597x-standalone"; + + bq->psy_desc.type = POWER_SUPPLY_TYPE_MAINS; + bq->psy_desc.properties = bq2597x_charger_props; + bq->psy_desc.num_properties = ARRAY_SIZE(bq2597x_charger_props); + bq->psy_desc.get_property = bq2597x_charger_get_property; + bq->psy_desc.set_property = bq2597x_charger_set_property; + bq->psy_desc.property_is_writeable = bq2597x_charger_is_writeable; + + + bq->fc2_psy = devm_power_supply_register(bq->dev, + &bq->psy_desc, &bq->psy_cfg); + if (IS_ERR(bq->fc2_psy)) { + bq_err("failed to register fc2_psy:%d\n", ret); + return PTR_ERR(bq->fc2_psy); + } + + bq_info("%s power supply register successfully\n", bq->psy_desc.name); + + return 0; +} +#endif + +void bq2597x_dump_reg(struct bq2597x *bq) +{ + int ret; + u8 val; + u8 addr; + + for (addr = 0x00; addr < 0x2E; addr++) { + ret = bq2597x_read_byte(bq, addr, &val); + if (!ret) + bq_info("Reg[%02X] = 0x%02X\n", addr, val); + } +} +EXPORT_SYMBOL_GPL(bq2597x_dump_reg); + +bool bq2597x_charge_status_is_ok(struct bq2597x *bq) +{ + if (bq == NULL) { + pr_err("bq2597x is not ready\n"); + return true; + } + + if (bq->chg_alarm) { + bq_err("bq2597x charge alarm\n"); + bq->chg_alarm = false; + } + if (bq->chg_fault) { + bq_err("bq2597x charge fault\n"); + bq->chg_fault = false; + return false; + } + + return true; +} + +static void bq2597x_check_alarm_status(struct bq2597x *bq) +{ + int ret; + u8 flag = 0; + u8 stat = 0; + + mutex_lock(&bq->data_lock); + + ret = bq2597x_read_byte(bq, BQ2597X_REG_08, &flag); + if (!ret && (flag & BQ2597X_IBUS_UCP_FALL_FLAG_MASK)) + bq_dbg("UCP_FLAG =0x%02X\n", + !!(flag & BQ2597X_IBUS_UCP_FALL_FLAG_MASK)); + + ret = bq2597x_read_byte(bq, BQ2597X_REG_2D, &flag); + if (!ret && (flag & BQ2597X_VDROP_OVP_FLAG_MASK)) + bq_dbg("VDROP_OVP_FLAG =0x%02X\n", + !!(flag & BQ2597X_VDROP_OVP_FLAG_MASK)); + + /*read to clear alarm flag*/ + ret = bq2597x_read_byte(bq, BQ2597X_REG_0E, &flag); + if (!ret && flag) + bq_dbg("INT_FLAG =0x%02X\n", flag); + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0D, &stat); + if (!ret && stat != bq->prev_alarm) { + bq_dbg("INT_STAT = 0X%02x\n", stat); + bq->prev_alarm = stat; + bq->bat_ovp_alarm = !!(stat & BAT_OVP_ALARM); + if (bq->bat_ovp_alarm) + bq_err("BAT_OVP_ALARM\n"); + bq->bat_ocp_alarm = !!(stat & BAT_OCP_ALARM); + if (bq->bat_ocp_alarm) + bq_err("BAT_OCP_ALARM\n"); + bq->bus_ovp_alarm = !!(stat & BUS_OVP_ALARM); + if (bq->bus_ovp_alarm) + bq_err("BUS_OVP_ALARM\n"); + bq->bus_ocp_alarm = !!(stat & BUS_OCP_ALARM); + if (bq->bus_ocp_alarm) + bq_err("BUS_OCP_ALARM\n"); + bq->batt_present = !!(stat & VBAT_INSERT); + if (bq->batt_present) + bq_err("VBAT_INSERT\n"); + bq->vbus_present = !!(stat & VBUS_INSERT); + if (bq->vbus_present) + bq_err("VBUS_INSERT\n"); + bq->bat_ucp_alarm = !!(stat & BAT_UCP_ALARM); + if (bq->bat_ucp_alarm) + bq_err("BAT_UCP_ALARM\n"); + bq->chg_alarm = !!(stat & BQ_ALARM_MASK); + } + + ret = bq2597x_read_byte(bq, BQ2597X_REG_08, &stat); + if (!ret && (stat & 0x50)) { + bq_err("Reg[05]BUS_UCPOVP = 0x%02X\n", stat); + bq->chg_fault = true; + } + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0A, &stat); + if (!ret && (stat & 0x02)) { + bq_err("Reg[0A]CONV_OCP = 0x%02X\n", stat); + bq->chg_fault = true; + } + + mutex_unlock(&bq->data_lock); +} + +static void bq2597x_check_fault_status(struct bq2597x *bq) +{ + int ret; + u8 flag = 0; + u8 stat = 0; + bool changed = false; + + mutex_lock(&bq->data_lock); + + ret = bq2597x_read_byte(bq, BQ2597X_REG_10, &stat); + if (!ret && stat) + bq_err("FAULT_STAT = 0x%02X\n", stat); + + ret = bq2597x_read_byte(bq, BQ2597X_REG_11, &flag); + if (!ret && flag) + bq_err("FAULT_FLAG = 0x%02X\n", flag); + + if (!ret && flag != bq->prev_fault) { + changed = true; + bq->prev_fault = flag; + bq->bat_ovp_fault = !!(flag & BAT_OVP_FAULT); + if (bq->bat_ovp_fault) + bq_err("BAT_OVP_FAULT\n"); + bq->bat_ocp_fault = !!(flag & BAT_OCP_FAULT); + if (bq->bat_ocp_fault) + bq_err("BAT_OCP_FAULT\n"); + bq->bus_ovp_fault = !!(flag & BUS_OVP_FAULT); + if (bq->bus_ovp_fault) + bq_err("BUS_OVP_FAULT\n"); + bq->bus_ocp_fault = !!(flag & BUS_OCP_FAULT); + if (bq->bus_ocp_fault) + bq_err("BUS_OCP_FAULT\n"); + bq->bat_therm_fault = !!(flag & TS_BAT_FAULT); + if (bq->bat_therm_fault) + bq_err("TS_BAT_FAULT\n"); + bq->bus_therm_fault = !!(flag & TS_BUS_FAULT); + if (bq->bus_therm_fault) + bq_err("TS_BUS_FAULT\n"); + + bq->bat_therm_alarm = !!(flag & TBUS_TBAT_ALARM); + bq->bus_therm_alarm = !!(flag & TBUS_TBAT_ALARM); + if (bq->bus_therm_fault || bq->bat_therm_alarm) { + bq->chg_alarm = true; + bq_err("TBUS_TBAT_ALARM\n"); + } + bq->chg_fault = !!(flag & BQ_FAULT_MASK); + } + + mutex_unlock(&bq->data_lock); +} + +int bq2597x_ftm_test(struct bq2597x *bq) +{ + int ret; + u8 val; + + if (bq == NULL) { + pr_err("[FTM_TEST]bq2597x is not ready\n"); + return WLCHG_FTM_TEST_CP2_ERR; + } + + ret = bq2597x_read_byte(bq, BQ2597X_REG_0C, &val); + if (ret) { + bq_err("[FTM_TEST]bq2597x read 0x%02x err, rc=%d\n", BQ2597X_REG_0C, ret); + ret = WLCHG_FTM_TEST_CP2_ERR; + } else { + bq_info("[FTM_TEST]bq2597x 0x%02x=0x%02x\n", BQ2597X_REG_0C, val); + } + + return ret; +} + +/* + * interrupt does nothing, just info event chagne, other module could get info + * through power supply interface + */ +static void bq2597x_irq_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct bq2597x *bq = container_of(dwork, struct bq2597x, irq_int_work); + + mutex_lock(&bq->irq_complete); + bq->irq_waiting = true; + if (!bq->resume_completed) { + dev_dbg(bq->dev, "IRQ triggered before device-resume\n"); + if (!bq->irq_disabled) { + disable_irq_nosync(bq->client->irq); + bq->irq_disabled = true; + } + mutex_unlock(&bq->irq_complete); + return; + } + bq->irq_waiting = false; + /* TODO */ + bq2597x_check_alarm_status(bq); + bq2597x_check_fault_status(bq); + + bq2597x_dump_reg(bq); + + mutex_unlock(&bq->irq_complete); +} +static irqreturn_t bq2597x_charger_interrupt(int irq, void *dev_id) +{ + struct bq2597x *bq = dev_id; + + bq_dbg("INT OCCURED\n"); +#if 0 + mutex_lock(&bq->irq_complete); + bq->irq_waiting = true; + if (!bq->resume_completed) { + dev_dbg(bq->dev, "IRQ triggered before device-resume\n"); + if (!bq->irq_disabled) { + disable_irq_nosync(irq); + bq->irq_disabled = true; + } + mutex_unlock(&bq->irq_complete); + return IRQ_HANDLED; + } + bq->irq_waiting = false; +#if 0 + /* TODO */ + bq2597x_check_alarm_status(bq); + bq2597x_check_fault_status(bq); +#endif + +#if 0 + bq2597x_dump_reg(bq); +#endif + mutex_unlock(&bq->irq_complete); +#endif + // power_supply_changed(bq->fc2_psy); + schedule_delayed_work(&bq->irq_int_work, 0); + + return IRQ_HANDLED; +} + +static void determine_initial_status(struct bq2597x *bq) +{ + if (bq->client->irq) + bq2597x_charger_interrupt(bq->client->irq, bq); +} + +static int show_registers(struct seq_file *m, void *data) +{ + struct bq2597x *bq = m->private; + u8 addr; + int ret; + u8 val; + + for (addr = 0x0; addr <= 0x2B; addr++) { + ret = bq2597x_read_byte(bq, addr, &val); + if (!ret) + seq_printf(m, "Reg[%02X] = 0x%02X\n", addr, val); + } + //schedule_delayed_work(&get_reg_task_work, round_jiffies_relative(msecs_to_jiffies(500))); + return 0; +} + +static int reg_debugfs_open(struct inode *inode, struct file *file) +{ + struct bq2597x *bq = inode->i_private; + + return single_open(file, show_registers, bq); +} + +static const struct file_operations reg_debugfs_ops = { + .owner = THIS_MODULE, + .open = reg_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int enable_registers(struct seq_file *m, void *data) +{ + int ret = 0; + //struct bq2597x *bq = m->private; + ret = bq2597x_enable_charge_pump(true); + if (ret == 0) { + seq_printf(m, "enable bq2597x charge pump ok.\n"); + } else { + seq_printf(m, "enable bq2597x charge pump failed !!\n"); + } + return 0; +} + +static int enable_debugfs_open(struct inode *inode, struct file *file) +{ + struct bq2597x *bq = inode->i_private; + + return single_open(file, enable_registers, bq); +} + +static const struct file_operations enable_debugfs_ops = { + .owner = THIS_MODULE, + .open = enable_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_debugfs_entry(struct bq2597x *bq) +{ + if (bq->mode == BQ25970_ROLE_MASTER) + bq->debug_root = debugfs_create_dir("bq2597x-master", NULL); + else if (bq->mode == BQ25970_ROLE_SLAVE) + bq->debug_root = debugfs_create_dir("bq2597x-slave", NULL); + else + bq->debug_root = debugfs_create_dir("bq2597x-standalone", NULL); + + if (!bq->debug_root) + bq_err("Failed to create debug dir\n"); + + if (bq->debug_root) { + debugfs_create_file("registers", S_IFREG | S_IRUGO, + bq->debug_root, bq, ®_debugfs_ops); + + debugfs_create_x32("skip_reads", S_IFREG | S_IWUSR | S_IRUGO, + bq->debug_root, &(bq->skip_reads)); + debugfs_create_x32("skip_writes", S_IFREG | S_IWUSR | S_IRUGO, + bq->debug_root, &(bq->skip_writes)); + debugfs_create_file("enable", S_IFREG | S_IRUGO, bq->debug_root, + bq, &enable_debugfs_ops); + } +} + +static void get_reg_task_work_process(struct work_struct *work) +{ + u8 addr; + int ret; + u8 val; + static int cycle_cont; + struct bq2597x *bq = bq_pump; + + for (addr = 0x00; addr <= 0x2E; addr++) { + ret = bq2597x_read_byte(bq, addr, &val); + if (!ret) + bq_err("Reg[%02X] = 0x%02X\n", addr, val); + } + if (cycle_cont >= 2) { + cycle_cont = 0; + bq2597x_check_charge_enabled(bq, &bq->charge_enabled); + } + if (!bq->charge_enabled) { + bq2597x_enable_charge_pump(true); + } + cycle_cont++; + schedule_delayed_work(&get_reg_task_work, + round_jiffies_relative(msecs_to_jiffies(5000))); +} + +static int init_bq_irq(struct i2c_client *client, struct bq2597x *bq) +{ + int rc = 0; + struct pinctrl *pinctrl; + struct pinctrl_state *bq_irq_active; + + bq->irq_gpio = + of_get_named_gpio(client->dev.of_node, "qcom,bq_int-gpio", 0); + if (bq->irq_gpio < 0) { + pr_err("bq_irq_gpio not specified\n"); + return -EINVAL; + } else { + if (gpio_is_valid(bq->irq_gpio)) { + rc = gpio_request(bq->irq_gpio, "bq-irq-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", + bq->irq_gpio); + return rc; + } else { + pinctrl = devm_pinctrl_get(&client->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("get pinctrl fail\n"); + rc = IS_ERR_OR_NULL(pinctrl); + goto fail; + } + + bq_irq_active = pinctrl_lookup_state( + pinctrl, "bq_irq_active"); + if (IS_ERR_OR_NULL(bq_irq_active)) { + pr_err("get bq_irq_active fail\n"); + rc = IS_ERR_OR_NULL(bq_irq_active); + goto fail; + } + pinctrl_select_state(pinctrl, bq_irq_active); + client->irq = gpio_to_irq(bq->irq_gpio); + } + } + } + return 0; + +fail: + if (gpio_is_valid(bq->irq_gpio)) + gpio_free(bq->irq_gpio); + return rc; +} + +static struct of_device_id bq2597x_charger_match_table[] = { + { + .compatible = "ti,bq2597x-standalone", + .data = &bq2597x_mode_data[BQ25970_STDALONE], + }, + { + .compatible = "ti,bq2597x-master", + .data = &bq2597x_mode_data[BQ25970_MASTER], + }, + + { + .compatible = "ti,bq2597x-slave", + .data = &bq2597x_mode_data[BQ25970_SLAVE], + }, + {}, +}; +//MODULE_DEVICE_TABLE(of, bq2597x_charger_match_table); + +static int bq2597x_charger_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bq2597x *bq; + const struct of_device_id *match; + struct device_node *node = client->dev.of_node; + int ret; + + bq = devm_kzalloc(&client->dev, sizeof(struct bq2597x), GFP_KERNEL); + if (!bq) + return -ENOMEM; + + bq->dev = &client->dev; + + bq->client = client; + i2c_set_clientdata(client, bq); + + mutex_init(&bq->i2c_rw_lock); + mutex_init(&bq->data_lock); + mutex_init(&bq->charging_disable_lock); + mutex_init(&bq->irq_complete); + + bq->resume_completed = true; + bq->irq_waiting = false; + + ret = bq2597x_detect_device(bq); + if (ret) { + bq_err("No bq2597x device found!\n"); + return -ENODEV; + } + + match = of_match_node(bq2597x_charger_match_table, node); + if (match == NULL) { + bq_err("device tree match not found!\n"); + return -ENODEV; + } + + bq2597x_get_work_mode(bq, &bq->mode); + + if (bq->mode != *(int *)match->data) { + bq_err("device operation mode mismatch with dts configuration\n"); + return -EINVAL; + } + + ret = bq2597x_parse_dt(bq, &client->dev); + if (ret) + return ret; + + ret = bq2597x_init_device(bq); + if (ret) { + bq_err("Failed to init device\n"); + return ret; + } + +#if 0 + ret = bq2597x_psy_register(bq); + if (ret) + return ret; +#endif + + ret = init_bq_irq(client, bq); + if (ret) { + bq_err("bq irq init err, ret=%d\n", ret); + goto free_psy; + } + + INIT_DELAYED_WORK(&bq->irq_int_work, bq2597x_irq_work); + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, + bq2597x_charger_interrupt, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "bq2597x charger irq", bq); + if (ret < 0) { + bq_err("request irq for irq=%d failed, ret =%d\n", + client->irq, ret); + goto free_gpio; + } + enable_irq_wake(client->irq); + } + + device_init_wakeup(bq->dev, 1); + create_debugfs_entry(bq); + + ret = sysfs_create_group(&bq->dev->kobj, &bq2597x_attr_group); + if (ret) { + bq_err("failed to register sysfs. err: %d\n", ret); + goto free_gpio; + } + + determine_initial_status(bq); + + bq_info("bq2597x probe successfully, Part Num:%d\n!", bq->part_no); + INIT_DELAYED_WORK(&get_reg_task_work, get_reg_task_work_process); + //schedule_delayed_work(&get_reg_task_work, round_jiffies_relative(msecs_to_jiffies(5000))); + bq_pump = bq; + exchgpump_information_register(bq); + return 0; + +free_gpio: + if (gpio_is_valid(bq->irq_gpio)) + gpio_free(bq->irq_gpio); +free_psy: + power_supply_unregister(bq->fc2_psy); + return ret; +} + +static inline bool is_device_suspended(struct bq2597x *bq) +{ + return !bq->resume_completed; +} + +static int bq2597x_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bq2597x *bq = i2c_get_clientdata(client); + + mutex_lock(&bq->irq_complete); + bq->resume_completed = false; + mutex_unlock(&bq->irq_complete); + bq_err("Suspend successfully!"); + + return 0; +} + +static int bq2597x_suspend_noirq(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bq2597x *bq = i2c_get_clientdata(client); + + if (bq->irq_waiting) { + pr_err_ratelimited( + "Aborting suspend, an interrupt was detected while suspending\n"); + return -EBUSY; + } + return 0; +} + +static int bq2597x_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bq2597x *bq = i2c_get_clientdata(client); + + mutex_lock(&bq->irq_complete); + bq->resume_completed = true; + if (bq->irq_waiting) { + bq->irq_disabled = false; + enable_irq(client->irq); + mutex_unlock(&bq->irq_complete); + bq2597x_charger_interrupt(client->irq, bq); + } else { + mutex_unlock(&bq->irq_complete); + } + + // power_supply_changed(bq->fc2_psy); + bq_err("Resume successfully!"); + + return 0; +} +static int bq2597x_charger_remove(struct i2c_client *client) +{ + struct bq2597x *bq = i2c_get_clientdata(client); + + bq2597x_enable_adc(bq, false); + + power_supply_unregister(bq->fc2_psy); + + mutex_destroy(&bq->charging_disable_lock); + mutex_destroy(&bq->data_lock); + mutex_destroy(&bq->i2c_rw_lock); + mutex_destroy(&bq->irq_complete); + + if (gpio_is_valid(bq->irq_gpio)) + gpio_free(bq->irq_gpio); + + debugfs_remove_recursive(bq->debug_root); + + sysfs_remove_group(&bq->dev->kobj, &bq2597x_attr_group); + + return 0; +} + +static void bq2597x_charger_shutdown(struct i2c_client *client) +{ + struct bq2597x *bq = i2c_get_clientdata(client); + + bq_info("disable adc\n"); + bq2597x_enable_adc(bq, false); +} + +static const struct dev_pm_ops bq2597x_pm_ops = { + .resume = bq2597x_resume, + .suspend_noirq = bq2597x_suspend_noirq, + .suspend = bq2597x_suspend, +}; + +static const struct i2c_device_id bq2597x_charger_id[] = { + { "bq2597x-standalone", BQ25970_ROLE_STDALONE }, + { "bq2597x-master", BQ25970_ROLE_MASTER }, + { "bq2597x-slave", BQ25970_ROLE_SLAVE }, + {}, +}; + +static struct i2c_driver bq2597x_charger_driver = { + .driver = { + .name = "bq2597x-charger", + .owner = THIS_MODULE, + .of_match_table = bq2597x_charger_match_table, + .pm = &bq2597x_pm_ops, + }, + .id_table = bq2597x_charger_id, + + .probe = bq2597x_charger_probe, + .remove = bq2597x_charger_remove, + .shutdown = bq2597x_charger_shutdown, +}; + +module_i2c_driver(bq2597x_charger_driver); + +MODULE_DESCRIPTION("TI BQ2597x Charger Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Texas Instruments"); diff --git a/drivers/oneplus/power/supply/wlchg/bq2597x_charger.h b/drivers/oneplus/power/supply/wlchg/bq2597x_charger.h new file mode 100644 index 0000000000000000000000000000000000000000..99be2f366a3f95f5eeb2792dc293bfa443277835 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/bq2597x_charger.h @@ -0,0 +1,116 @@ +#ifndef __BQ2597X_CHARGER_H__ +#define __BQ2597X_CHARGER_H__ +enum { ADC_IBUS, + ADC_VBUS, + ADC_VAC, + ADC_VOUT, + ADC_VBAT, + ADC_IBAT, + ADC_TBUS, + ADC_TBAT, + ADC_TDIE, + ADC_MAX_NUM, +}; + +struct bq2597x { + struct device *dev; + struct i2c_client *client; + + int part_no; + int revision; + + int mode; + int irq_gpio; + + struct mutex data_lock; + struct mutex i2c_rw_lock; + struct mutex charging_disable_lock; + struct mutex irq_complete; + + bool irq_waiting; + bool irq_disabled; + bool resume_completed; + + bool batt_present; + bool vbus_present; + + bool usb_present; + bool charge_enabled; /* Register bit status */ + bool adc_enabled; + + /* ADC reading */ + int vbat_volt; + int vbus_volt; + int vout_volt; + int vac_volt; + + int ibat_curr; + int ibus_curr; + + int bat_temp; + int bus_temp; + int die_temp; + + /* alarm/fault status */ + bool bat_ovp_fault; + bool bat_ocp_fault; + bool bus_ovp_fault; + bool bus_ocp_fault; + bool bus_ucp_fault; + + bool bat_ovp_alarm; + bool bat_ocp_alarm; + bool bus_ovp_alarm; + bool bus_ocp_alarm; + + bool bat_ucp_alarm; + + bool bat_therm_alarm; + bool bus_therm_alarm; + bool die_therm_alarm; + + bool bat_therm_fault; + bool bus_therm_fault; + bool die_therm_fault; + + bool therm_shutdown_flag; + bool therm_shutdown_stat; + + bool vbat_reg; + bool ibat_reg; + + bool chg_alarm; + bool chg_fault; + + int prev_alarm; + int prev_fault; + + int chg_ma; + int chg_mv; + + int charge_state; + + struct bq2597x_cfg *cfg; + + int skip_writes; + int skip_reads; + + struct bq2597x_platform_data *platform_data; + + struct delayed_work monitor_work; + struct delayed_work irq_int_work; + + struct dentry *debug_root; + + struct power_supply_desc psy_desc; + struct power_supply_config psy_cfg; + struct power_supply *fc2_psy; +}; + +extern int bq2597x_enable_charge_pump(bool enable); +extern int bq2597x_check_charge_enabled(struct bq2597x *bq, bool *enabled); +extern void bq2597x_dump_reg(struct bq2597x *bq); +extern void exchgpump_information_register(struct bq2597x *bq); +bool bq2597x_charge_status_is_ok(struct bq2597x *bq); +int bq2597x_ftm_test(struct bq2597x *bq); +#endif diff --git a/drivers/oneplus/power/supply/wlchg/op_chargepump.c b/drivers/oneplus/power/supply/wlchg/op_chargepump.c new file mode 100644 index 0000000000000000000000000000000000000000..6d950066ef9bc82ba2d9d59dd674bc44da93849d --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_chargepump.c @@ -0,0 +1,901 @@ +/************************************************************************************ +** File: op_chargepump.c +** VENDOR_EDIT +** Copyright (C), 2008-2012, OP Mobile Comm Corp., Ltd +** +** Description: +** +** +** Version: 1.0 +** Date created: 21:03:46,09/04/2019 +** Author: Lin Shangbo +** +** --------------------------- Revision History: +*------------------------------------------------------------ +* Revision 1.0 +*2019-04-09 Lin Shangbo Created for new charger +************************************************************************************************************/ + +#include +#include + +#ifdef CONFIG_OP_CHARGER_MTK + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//#include + +extern void mt_power_off(void); +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#endif +#include +#include "op_chargepump.h" + +#define OP20A +struct chip_chargepump *chargepump_ic; +int chargepump_reg; + +#ifdef OP20A +#define REG_ADDR 0 +#define REG_DATA 1 +static int op20a_init_buf[2][5] = { + {0x08, 0x01, 0x02, 0x03, 0x00}, + {0xff, 0x02, 0x00, 0x00, 0xca}, +}; +#endif + +static DEFINE_MUTEX(chargepump_i2c_access); + +static int __chargepump_read_reg(int reg, int *returnData) +{ + int ret = 0; + struct chip_chargepump *chip = chargepump_ic; + + if (chip == NULL) { + chg_err("chargepump_ic is NULL!\n"); + return -ENODEV; + } + + ret = i2c_smbus_read_byte_data(chip->client, (unsigned char)reg); + if (ret < 0) { + chg_err("i2c read fail: can't read from %02x: %d\n", reg, ret); + return ret; + } else { + *returnData = ret; + } + + return 0; +} + +static int chargepump_read_reg(int reg, int *returnData) +{ + int ret = 0; + + mutex_lock(&chargepump_i2c_access); + ret = __chargepump_read_reg(reg, returnData); + mutex_unlock(&chargepump_i2c_access); + return ret; +} + +static int __chargepump_write_reg(int reg, int val) +{ + int ret = 0; + struct chip_chargepump *chip = chargepump_ic; + + if (chip == NULL) { + chg_err("chargepump_ic is NULL!\n"); + return -ENODEV; + } + + ret = i2c_smbus_write_byte_data(chip->client, reg, val); + if (ret < 0) { + chg_err("i2c write fail: can't write %02x to %02x: %d\n", val, + reg, ret); + return ret; + } + + return 0; +} + +static int chargepump_config_interface(int RegNum, int val, int MASK) +{ + int chargepump_reg = 0; + int ret = 0; + + mutex_lock(&chargepump_i2c_access); + + ret = __chargepump_read_reg(RegNum, &chargepump_reg); + + // chg_err(" Reg[%x]=0x%x\n", RegNum, chargepump_reg); + + chargepump_reg &= ~MASK; + chargepump_reg |= val; + + ret = __chargepump_write_reg(RegNum, chargepump_reg); + + // chg_err(" write Reg[%x]=0x%x\n", RegNum, chargepump_reg); + + __chargepump_read_reg(RegNum, &chargepump_reg); + + chg_err(" Check Reg[%x]=0x%x\n", RegNum, chargepump_reg); + + mutex_unlock(&chargepump_i2c_access); + + return ret; +} + +int chargepump_set_for_otg(char enable) +{ +#ifdef OP20A + return 0; +#else + int ret; + + chg_err(" chargepump_set_for_otg!\n"); + + if (chargepump_ic == NULL) { + chg_err(" chargepump_ic is NULL!\n"); + return -ENODEV; + } + + if (enable) { + ret = chargepump_config_interface(0x00, 0xFF, 0xFF); + if (ret) { + chg_err(" write reg 0x00 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x01, 0x40, 0xFF); + if (ret) { + chg_err(" write reg 0x01 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x02, 0xF9, 0xFF); + if (ret) { + chg_err(" write reg 0x02 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x03, 0x53, 0xFF); + if (ret) { + chg_err(" write reg 0x03 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x04, 0x01, 0xFF); + if (ret) { + chg_err(" write reg 0x04 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x06, 0x10, 0xFF); + if (ret) { + chg_err(" write reg 0x06 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x07, 0x78, 0xFF); + if (ret) { + chg_err(" write reg 0x07 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0xA7, 0xF9, 0xFF); + if (ret) { + chg_err(" write reg 0xA7 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x05, 0x61, 0xFF); + if (ret) { + chg_err(" write reg 0x05 error!\n"); + return ret; + } + } else { + ret = chargepump_config_interface(0x0A, 0x30, 0xFF); + if (ret) { + chg_err(" write reg 0x05 error!\n"); + return ret; + } + } + + return 0; +#endif +} + +int chargepump_hw_init(void) +{ +#ifdef OP20A + int i; +#endif + int ret; + + chg_err(" chargepump_hw_init!\n"); + + if (chargepump_ic == NULL) { + chg_err(" chargepump_ic is NULL!\n"); + return -ENODEV; + } + +#ifdef OP20A + for (i = 0; i < ARRAY_SIZE(op20a_init_buf[0]); i++) { + ret = chargepump_config_interface(op20a_init_buf[REG_ADDR][i], op20a_init_buf[REG_DATA][i], 0xFF); + if (ret) { + chg_err(" write reg 0x%02x error, ret=%d\n", op20a_init_buf[REG_ADDR][i], ret); + return ret; + } + msleep(20); + } +#else + ret = chargepump_config_interface(0x00, 0xFF, 0xFF); + if (ret) { + chg_err(" write reg 0x00 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x01, 0x40, 0xFF); + if (ret) { + chg_err(" write reg 0x01 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x02, 0xF9, 0xFF); + if (ret) { + chg_err(" write reg 0x02 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x03, 0x53, 0xFF); + if (ret) { + chg_err(" write reg 0x03 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x04, 0x01, 0xFF); + if (ret) { + chg_err(" write reg 0x04 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x06, 0x10, 0xFF); + if (ret) { + chg_err(" write reg 0x06 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x07, 0x78, 0xFF); + if (ret) { + chg_err(" write reg 0x07 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0xA7, 0xF9, 0xFF); + if (ret) { + chg_err(" write reg 0xA7 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x0A, 0x30, 0xFF); + if (ret) { + chg_err(" write reg 0x0A error!\n"); + return ret; + } + +#endif + return 0; +} + +int chargepump_check_config(void) +{ +#ifdef OP20A + int i, buf; + int ret; + + if (chargepump_ic == NULL) { + chg_err(" chargepump_ic is NULL!\n"); + return -ENODEV; + } + + for (i = 0; i < ARRAY_SIZE(op20a_init_buf[0]); i++) { + ret = chargepump_read_reg(op20a_init_buf[REG_ADDR][i], &buf); + if (ret) { + chg_err(" read reg 0x%02x error, ret=%d\n", op20a_init_buf[REG_ADDR][i], ret); + return ret; + } else { + if (buf != op20a_init_buf[REG_DATA][i]) { + chg_err("reg 0x%02x is not initialized\n", op20a_init_buf[REG_ADDR][i]); + return -EINVAL; + } + } + } +#endif + return 0; +} + +int chargepump_set_for_LDO(void) +{ +#ifndef OP20A + int ret; + + chg_err(" chargepump_set_for_LDO!\n"); + + ret = chargepump_config_interface(0x05, 0x61, 0xFF); + if (ret) { + chg_err(" write reg 0x05 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0xA7, 0xF9, 0xFF); + if (ret) { + chg_err(" write reg 0xA7 error!\n"); + return ret; + } + + ret = chargepump_config_interface(0x0A, 0x90, 0xFF); + if (ret) { + chg_err(" write reg 0x0A error!\n"); + return ret; + } +#endif + + return 0; +} + +void chargepump_set_chargepump_en_val(struct chip_chargepump *chip, int value) +{ + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: chargepump_ic not ready!\n", + __func__); + return; + } + + if (chip->chargepump_en_gpio <= 0) { + chg_err("chargepump_en_gpio not exist, return\n"); + return; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->chargepump_en_active) || + IS_ERR_OR_NULL(chip->chargepump_en_sleep) || + IS_ERR_OR_NULL(chip->chargepump_en_default)) { + chg_err("pinctrl null, return\n"); + return; + } + + if (value) { + gpio_direction_output(chip->chargepump_en_gpio, 1); + pinctrl_select_state(chip->pinctrl, + chip->chargepump_en_default); + } else { + gpio_direction_output(chip->chargepump_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, + chip->chargepump_en_default); + } + + chg_err("set value:%d, gpio_val:%d\n", value, + gpio_get_value(chip->chargepump_en_gpio)); +} + +int chargepump_enable(void) +{ + int ret = 0; + + chg_err(" chargepump_enable!\n"); + + if (chargepump_ic != NULL) { + chargepump_set_chargepump_en_val(chargepump_ic, 1); + schedule_delayed_work(&chargepump_ic->watch_dog_work, msecs_to_jiffies(1000)); + return ret; + } else { + chg_err(" chargepump_ic is NULL!\n"); + return -ENODEV; + } +} + +int chargepump_disable(void) +{ + chg_err(" chargepump_disable!\n"); + + if (chargepump_ic != NULL) { + chargepump_set_for_otg(0); + chargepump_set_chargepump_en_val(chargepump_ic, 0); + cancel_delayed_work_sync(&chargepump_ic->watch_dog_work); + return 0; + } else { + chg_err(" chargepump_ic is NULL!\n"); + return -ENODEV; + } +} + +int chargepump_disable_dwp(void) +{ + int ret; + + ret = chargepump_config_interface(0x00, 0xc2, 0xFF); + if (ret) + chg_err("can't disable dwp, rc=%d\n", ret); + + return ret; +} + +int chargepump_i2c_test(void) +{ + int reg_value = 0; + int rc; + +#ifdef OP20A + rc = chargepump_read_reg(0x04, ®_value); + if (rc) + chg_err(" chargepump read 0x04 err, rc=%d\n", rc); + else + chg_err(" chargepump 0x04=0X%02x\n", reg_value); +#else + rc = chargepump_read_reg(0x08, ®_value); + if (rc) { + chg_err(" chargepump read 0x08 err, rc=%d\n", rc); + return rc; + } + chg_err(" chargepump 0x08=0X%02x\n", reg_value); + + rc = chargepump_read_reg(0x09, ®_value); + if (rc) + chg_err(" chargepump read 0x09 err, rc=%d\n", rc); + else + chg_err(" chargepump 0x09=0X%02x\n", reg_value); +#endif + + return rc; +} + +int chargepump_hardware_init(void) +{ + return true; +} + +static int chargepump_en_gpio_init(struct chip_chargepump *chip) +{ + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: chip_chargepump not ready!\n", + __func__); + return -EINVAL; + } + + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + chg_err("get chargepump_en pinctrl fail\n"); + return -EINVAL; + } + + chip->chargepump_en_active = + pinctrl_lookup_state(chip->pinctrl, "cp_en_active"); + if (IS_ERR_OR_NULL(chip->chargepump_en_active)) { + chg_err("get chargepump_en_active fail\n"); + return -EINVAL; + } + + chip->chargepump_en_sleep = + pinctrl_lookup_state(chip->pinctrl, "cp_en_sleep"); + if (IS_ERR_OR_NULL(chip->chargepump_en_sleep)) { + chg_err("get chargepump_en_sleep fail\n"); + return -EINVAL; + } + + chip->chargepump_en_default = + pinctrl_lookup_state(chip->pinctrl, "cp_en_default"); + if (IS_ERR_OR_NULL(chip->chargepump_en_default)) { + chg_err("get chargepump_en_default fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->chargepump_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->chargepump_en_default); + + chg_err(", chargepump_en_gpio: %d \n", + gpio_get_value(chip->chargepump_en_gpio)); + + return 0; +} + +void __chargepump_show_registers(void) +{ + int addr; + int val; + int ret; + + for (addr = 0x0; addr <= 0x08; addr++) { + ret = chargepump_read_reg(addr, &val); + if (ret == 0) { + chg_err("wkcs: Reg[%.2X] = 0x%.2x\n", addr, val); + } + } +} + +static ssize_t chargepump_show_registers(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int addr; + int val; + ssize_t len; + int ret; + + len = 0; + for (addr = 0x0; addr <= 0x08; addr++) { + ret = chargepump_read_reg(addr, &val); + if (ret == 0) { + len += snprintf(buf + len, PAGE_SIZE - len, + "Reg[%.2X] = 0x%.2x\n", addr, val); + } + } + + return len; +} + +static DEVICE_ATTR(registers, 0660, chargepump_show_registers, NULL); + +static struct attribute *chargepump_attributes[] = { + &dev_attr_registers.attr, + NULL, +}; + +static const struct attribute_group chargepump_attr_group = { + .attrs = chargepump_attributes, +}; + +int chargepump_status_check(u8 *status) +{ + int ret; + int val; + + ret = chargepump_read_reg(CP_STATUS_ADDR, &val); + if (ret < 0) { + pr_err("can't read charge pump status, ret=%d\n", ret); + return ret; + } + *status = (u8)val; + + return ret; +} + +int chargepump_enable_dwp(struct chip_chargepump *chip, bool enable) +{ + int ret; + + if (enable) + ret = chargepump_config_interface(0x00, 0x18, 0x18); + else + ret = chargepump_config_interface(0x00, 0x00, 0x18); + + return ret; +} + +static int chargepump_gpio_init(struct chip_chargepump *chip) +{ + int rc = 0; + struct device_node *node = chip->dev->of_node; + + // Parsing gpio chargepump_en_gpio + chip->chargepump_en_gpio = + of_get_named_gpio(node, "qcom,cp_en-gpio", 0); + if (chip->chargepump_en_gpio < 0) { + pr_err("chip->chargepump_en_gpio not specified\n"); + return -EINVAL; + } else { + if (gpio_is_valid(chip->chargepump_en_gpio)) { + rc = gpio_request(chip->chargepump_en_gpio, + "qcom,cp_en-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", + chip->chargepump_en_gpio); + return rc; + } + } + rc = chargepump_en_gpio_init(chip); + if (rc) { + pr_err("chip->chargepump_en_gpio =%d\n", + chip->chargepump_en_gpio); + goto fail; + } + } + + return 0; + +fail: + if (gpio_is_valid(chip->chargepump_en_gpio)) + gpio_free(chip->chargepump_en_gpio); + return rc; +} + +static void watch_dog_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct chip_chargepump *chip = + container_of(dwork, struct chip_chargepump, watch_dog_work); + int ret; + + ret = __chargepump_write_reg(0x0a, 0x71); + if (ret < 0) { + pr_err("feeding the watch dog error, try again\n"); + ret = __chargepump_write_reg(0x0a, 0x71); + if (ret < 0) + pr_err("feeding the watch dog error again\n"); + } + + schedule_delayed_work(&chip->watch_dog_work, msecs_to_jiffies(100000)); +} + + +#if 0 +struct op_wpc_operations *cp_ops = { + .cp_hw_init = chargepump_hardware_init; + .cp_set_for_otg = chargepump_set_for_otg; + .cp_set_for_EPP = chargepump_hw_init; + .cp_set_for_LDO = chargepump_set_for_LDO; + .cp_enable = chargepump_enable; + +}; +#endif + +static int chargepump_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct chip_chargepump *chg_ic; + + chg_ic = devm_kzalloc(&client->dev, sizeof(struct chip_chargepump), + GFP_KERNEL); + if (!chg_ic) { + chg_err(" kzalloc() failed\n"); + return -ENOMEM; + } + + chg_debug(" call \n"); + chg_ic->client = client; + chg_ic->dev = &client->dev; + + chargepump_ic = chg_ic; + atomic_set(&chg_ic->chargepump_suspended, 0); + i2c_set_clientdata(client, chg_ic); + + chargepump_hardware_init(); + ret = chargepump_gpio_init(chg_ic); + if (ret) { + chg_err("gpio init err, ret=%d\n", ret); + return ret; + } + + INIT_DELAYED_WORK(&chg_ic->watch_dog_work, watch_dog_work); + + ret = sysfs_create_group(&chg_ic->dev->kobj, &chargepump_attr_group); + if (ret) { + pr_err("failed to register sysfs. err: %d\n", ret); + goto fail; + } + + chg_debug(" success\n"); + + return 0; + +fail: + if (gpio_is_valid(chg_ic->chargepump_en_gpio)) + gpio_free(chg_ic->chargepump_en_gpio); + return ret; +} + +static struct i2c_driver chargepump_i2c_driver; + +static int chargepump_driver_remove(struct i2c_client *client) +{ + struct chip_chargepump *chip = i2c_get_clientdata(client);; + + sysfs_remove_group(&client->dev.kobj, &chargepump_attr_group); + if (gpio_is_valid(chip->chargepump_en_gpio)) + gpio_free(chip->chargepump_en_gpio); + return 0; +} + +static unsigned long suspend_tm_sec; +static int get_current_time(unsigned long *now_tm_sec) +{ + struct rtc_time tm; + struct rtc_device *rtc = NULL; + int rc = 0; + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc == NULL) { + chg_err("%s: unable to open rtc device (%s)\n", __FILE__, + CONFIG_RTC_HCTOSYS_DEVICE); + return -EINVAL; + } + + rc = rtc_read_time(rtc, &tm); + if (rc) { + chg_err("Error reading rtc device (%s) : %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + rc = rtc_valid_tm(&tm); + if (rc) { + chg_err("Invalid RTC time (%s): %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + rtc_tm_to_time(&tm, now_tm_sec); + +close_time: + rtc_class_close(rtc); + return rc; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +static int chargepump_pm_resume(struct device *dev) +{ + unsigned long resume_tm_sec = 0; + unsigned long sleep_time = 0; + int rc = 0; + struct chip_chargepump *chip = chargepump_ic; + + if (!chip) { + return 0; + } + atomic_set(&chip->chargepump_suspended, 0); + rc = get_current_time(&resume_tm_sec); + if (rc || suspend_tm_sec == -1) { + chg_err("RTC read failed\n"); + sleep_time = 0; + } else { + sleep_time = resume_tm_sec - suspend_tm_sec; + } + /* + if (sleep_time < 0) { + sleep_time = 0; + } + */ + + return 0; +} + +static int chargepump_pm_suspend(struct device *dev) +{ + struct chip_chargepump *chip = chargepump_ic; + + if (!chip) { + return 0; + } + atomic_set(&chip->chargepump_suspended, 1); + if (get_current_time(&suspend_tm_sec)) { + chg_err("RTC read failed\n"); + suspend_tm_sec = -1; + } + return 0; +} + +static const struct dev_pm_ops chargepump_pm_ops = { + .resume = chargepump_pm_resume, + .suspend = chargepump_pm_suspend, +}; +#else +static int chargepump_resume(struct i2c_client *client) +{ + unsigned long resume_tm_sec = 0; + unsigned long sleep_time = 0; + int rc = 0; + struct chip_chargepump *chip = chargepump_ic; + + if (!chip) { + return 0; + } + atomic_set(&chip->chargepump_suspended, 0); + rc = get_current_time(&resume_tm_sec); + if (rc || suspend_tm_sec == -1) { + chg_err("RTC read failed\n"); + sleep_time = 0; + } else { + sleep_time = resume_tm_sec - suspend_tm_sec; + } + /* + if (sleep_time < 0) { + sleep_time = 0; + } + */ + + return 0; +} + +static int chargepump_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct chip_chargepump *chip = chargepump_ic; + + if (!chip) { + return 0; + } + atomic_set(&chip->chargepump_suspended, 1); + if (get_current_time(&suspend_tm_sec)) { + chg_err("RTC read failed\n"); + suspend_tm_sec = -1; + } + return 0; +} +#endif + +static void chargepump_reset(struct i2c_client *client) +{ +} + +/********************************************************** + * + * [platform_driver API] + * + *********************************************************/ + +static const struct of_device_id chargepump_match[] = { + { .compatible = "op,chgpump-charger" }, + {}, +}; + +static const struct i2c_device_id chargepump_id[] = { + { "chgpump-charger", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, chargepump_id); + +static struct i2c_driver chargepump_i2c_driver = { + .driver = + { + .name = "chgpump-charger", + .owner = THIS_MODULE, + .of_match_table = chargepump_match, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + .pm = &chargepump_pm_ops, +#endif + }, + .probe = chargepump_driver_probe, + .remove = chargepump_driver_remove, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) + .resume = chargepump_resume, + .suspend = chargepump_suspend, +#endif + .shutdown = chargepump_reset, + .id_table = chargepump_id, +}; + +module_i2c_driver(chargepump_i2c_driver); +MODULE_DESCRIPTION("Driver for chgpump chip"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:chargepump-charger"); diff --git a/drivers/oneplus/power/supply/wlchg/op_chargepump.h b/drivers/oneplus/power/supply/wlchg/op_chargepump.h new file mode 100644 index 0000000000000000000000000000000000000000..14c242444cbe3587d3ed35c094a3753d84e7f725 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_chargepump.h @@ -0,0 +1,57 @@ +/************************************************************************************ +** File: op_chargepump.c +** VENDOR_EDIT +** Copyright (C), 2008-2012, OP Mobile Comm Corp., Ltd +** +** Description: +** +** +** Version: 1.0 +** Date created: 21:03:46,09/04/2019 +** Author: Lin Shangbo +** +** --------------------------- Revision History: +*------------------------------------------------------------ +* Revision 1.0 2019-04-09 Lin +*Shangbo Created for new charger +************************************************************************************************************/ + +#ifndef __OP_CHARGEPUMP_H__ +#define __OP_CHARGEPUMP_H__ + +#define CP_STATUS_ADDR 0x04 +#define CP_NOT_REEADY 0 +#define CP_REEADY BIT(0) +#define CP_DWP BIT(1) +#define CP_OTP BIT(2) +#define CP_SWITCH_OCP BIT(3) +#define CP_CRP BIT(4) +#define CP_VOUT_OVP BIT(5) +#define CP_CLP BIT(6) +#define CP_VBUS_OVP BIT(7) + +struct chip_chargepump { + struct i2c_client *client; + struct device *dev; + struct pinctrl *pinctrl; + int chargepump_en_gpio; + struct pinctrl_state *chargepump_en_active; + struct pinctrl_state *chargepump_en_sleep; + struct pinctrl_state *chargepump_en_default; + atomic_t chargepump_suspended; + struct delayed_work watch_dog_work; +}; + +extern int chargepump_hw_init(void); +extern int chargepump_enable(void); +extern int chargepump_set_for_otg(char enable); +extern int chargepump_set_for_LDO(void); +extern int chargepump_disable(void); +void __chargepump_show_registers(void); +int chargepump_enable_dwp(struct chip_chargepump *chip, bool enable); +int chargepump_disable_dwp(void); +int chargepump_status_check(u8 *status); +int chargepump_i2c_test(void); +int chargepump_check_config(void); + +#endif diff --git a/drivers/oneplus/power/supply/wlchg/op_p9415.c b/drivers/oneplus/power/supply/wlchg/op_p9415.c new file mode 100644 index 0000000000000000000000000000000000000000..619f088d4d99005eb44955dfe137047fad89f18f --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_p9415.c @@ -0,0 +1,2510 @@ +#define pr_fmt(fmt) "WLCHG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "op_chargepump.h" +#include "bq2597x_charger.h" +#include "op_wlchg_rx.h" +#include "op_p9415.h" +#include "op_p9415_fw.h" +#include "op_wlchg_policy.h" +#include "smb5-lib.h" +#include "linux/oem/project_info.h" + +extern struct smb_charger *normal_charger; + +static bool charge_mode_startup; +static struct op_p9415_ic *g_p9415_chip; + +void op_set_wrx_en_value(int value); +void op_set_wrx_otg_value(int value); +extern int wlchg_get_usbin_val(void); +extern int wlchg_send_msg(enum WLCHG_MSG_TYPE type, char data, char remark); + +static DEFINE_MUTEX(p9415_i2c_access); + +#define P22X_ADD_COUNT 2 +#define p9415_MAX_I2C_READ_CNT 10 +static int __p9415_read_reg(struct op_p9415_ic *chip, int reg, char *returnData, + int count) +{ + /* We have 16-bit i2c addresses - care for endianness */ + char cmd_buf[2] = { reg >> 8, reg & 0xff }; + int ret = 0; + int i; + char val_buf[p9415_MAX_I2C_READ_CNT]; + + for (i = 0; i < count; i++) { + val_buf[i] = 0; + } + + ret = i2c_master_send(chip->client, cmd_buf, P22X_ADD_COUNT); + if (ret < P22X_ADD_COUNT) { + pr_err("i2c read error, reg: %x\n", reg); + return ret < 0 ? ret : -EIO; + } + + ret = i2c_master_recv(chip->client, val_buf, count); + if (ret < count) { + pr_err("i2c read error, reg: %x\n", reg); + return ret < 0 ? ret : -EIO; + } + + for (i = 0; i < count; i++) { + *(returnData + i) = val_buf[i]; + } + + return 0; +} + +static int __p9415_write_reg(struct op_p9415_ic *chip, int reg, int val) +{ + int ret; + unsigned char data[3] = { reg >> 8, reg & 0xff, val }; + + ret = i2c_master_send(chip->client, data, 3); + if (ret < 3) { + pr_err("%s: i2c write error, reg: %x\n", __func__, reg); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int p9415_write_reg_multi_byte(struct op_p9415_ic *chip, int reg, + const char *cbuf, int length) +{ + int ret; + int send_length; + unsigned char *data_w; + + send_length = length + 2; + data_w = kzalloc(send_length, GFP_KERNEL); + if (!data_w) { + pr_err("can't alloc memory!\n"); + return -EINVAL; + } + + data_w[0] = reg >> 8; + data_w[1] = reg & 0xff; + + memcpy(data_w + 2, cbuf, length); + + mutex_lock(&p9415_i2c_access); + + ret = i2c_master_send(chip->client, data_w, send_length); + if (ret < send_length) { + pr_err("%s: i2c write error, reg: %x\n", __func__, reg); + kfree(data_w); + mutex_unlock(&p9415_i2c_access); + return ret < 0 ? ret : -EIO; + } + + mutex_unlock(&p9415_i2c_access); + + kfree(data_w); + return 0; +} + +static int p9415_read_reg(struct op_p9415_ic *chip, int reg, char *returnData, + int count) +{ + int ret = 0; + + mutex_lock(&p9415_i2c_access); + ret = __p9415_read_reg(chip, reg, returnData, count); + mutex_unlock(&p9415_i2c_access); + return ret; +} + +int p9415_config_interface(struct op_p9415_ic *chip, int RegNum, int val, + int MASK) +{ + char p9415_reg = 0; + int ret = 0; + if (!chip) { + pr_err("op_p9415_ic not ready!\n"); + return -EINVAL; + } + + mutex_lock(&p9415_i2c_access); + ret = __p9415_read_reg(chip, RegNum, &p9415_reg, 1); + + p9415_reg &= ~MASK; + p9415_reg |= val; + + ret = __p9415_write_reg(chip, RegNum, p9415_reg); + + mutex_unlock(&p9415_i2c_access); + + return ret; +} + +static int p9415_get_idt_con_val(struct op_p9415_ic *chip) +{ + if (chip->idt_con_gpio <= 0) { + pr_err("idt_con_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->idt_con_active) || + IS_ERR_OR_NULL(chip->idt_con_sleep)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + return gpio_get_value(chip->idt_con_gpio); +} + +int p9415_get_idt_int_val(struct op_p9415_ic *chip) +{ + if (chip->idt_int_gpio <= 0) { + pr_err("idt_int_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->idt_int_active) || + IS_ERR_OR_NULL(chip->idt_int_sleep)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + return gpio_get_value(chip->idt_int_gpio); +} + +static int p9415_set_vbat_en_val(struct op_p9415_ic *chip, int value) +{ + + if (chip->vbat_en_gpio <= 0) { + pr_err("vbat_en_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->vbat_en_active) || + IS_ERR_OR_NULL(chip->vbat_en_sleep) || + IS_ERR_OR_NULL(chip->vbat_en_default)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + if (value) { + gpio_direction_output(chip->vbat_en_gpio, 1); + pinctrl_select_state(chip->pinctrl, chip->vbat_en_default); + } else { + gpio_direction_output(chip->vbat_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->vbat_en_sleep); + } + + pr_info("set value:%d, gpio_val:%d\n", value, + gpio_get_value(chip->vbat_en_gpio)); + return 0; +} + +static int p9415_get_vbat_en_val(struct op_p9415_ic *chip) +{ + if (chip->vbat_en_gpio <= 0) { + pr_err("vbat_en_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->vbat_en_active) || + IS_ERR_OR_NULL(chip->vbat_en_sleep) || + IS_ERR_OR_NULL(chip->vbat_en_default)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + return gpio_get_value(chip->vbat_en_gpio); +} + +static int p9415_booster_en_gpio_init(struct op_p9415_ic *chip) +{ + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: op_p9415_ic not ready!\n", + __func__); + return -EINVAL; + } + + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + pr_err("get pinctrl fail\n"); + return -EINVAL; + } + + //booster_en + chip->booster_en_active = + pinctrl_lookup_state(chip->pinctrl, "booster_en_active"); + if (IS_ERR_OR_NULL(chip->booster_en_active)) { + pr_err("get booster_en_active fail\n"); + return -EINVAL; + } + + chip->booster_en_sleep = + pinctrl_lookup_state(chip->pinctrl, "booster_en_sleep"); + if (IS_ERR_OR_NULL(chip->booster_en_sleep)) { + pr_err("get booster_en_sleep fail\n"); + return -EINVAL; + } + + chip->booster_en_default = + pinctrl_lookup_state(chip->pinctrl, "booster_en_default"); + if (IS_ERR_OR_NULL(chip->booster_en_default)) { + pr_err("get booster_en_default fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->booster_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->booster_en_sleep); + + pr_err("gpio_val:%d\n", gpio_get_value(chip->booster_en_gpio)); + + return 0; +} + +void p9415_set_booster_en_val(int value) +{ + struct op_p9415_ic *chip = g_p9415_chip; + + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: op_p9415_ic not ready!\n", + __func__); + return; + } + + if (chip->booster_en_gpio <= 0) { + pr_err("booster_en_gpio not exist, return\n"); + return; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->booster_en_active) || + IS_ERR_OR_NULL(chip->booster_en_sleep) || + IS_ERR_OR_NULL(chip->booster_en_default)) { + pr_err("pinctrl null, return\n"); + return; + } + + if (value) { + gpio_direction_output(chip->booster_en_gpio, 1); + pinctrl_select_state(chip->pinctrl, chip->booster_en_active); + } else { + gpio_direction_output(chip->booster_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->booster_en_sleep); + } + + pr_err("set value:%d, gpio_val:%d\n", value, + gpio_get_value(chip->booster_en_gpio)); +} + +int p9415_get_booster_en_val(struct op_p9415_ic *chip) +{ + if (chip->booster_en_gpio <= 0) { + pr_err("booster_en_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->booster_en_active) || + IS_ERR_OR_NULL(chip->booster_en_sleep) || + IS_ERR_OR_NULL(chip->booster_en_default)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + return gpio_get_value(chip->booster_en_gpio); +} + +static int p9415_idt_en_gpio_init(struct op_p9415_ic *chip) +{ + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: op_p9415_ic not ready!\n", + __func__); + return -EINVAL; + } + + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + pr_err("get pinctrl fail\n"); + return -EINVAL; + } + + //idt_en + chip->idt_en_active = + pinctrl_lookup_state(chip->pinctrl, "idt_en_active"); + if (IS_ERR_OR_NULL(chip->idt_en_active)) { + pr_err("get idt_en_active fail\n"); + return -EINVAL; + } + + chip->idt_en_sleep = + pinctrl_lookup_state(chip->pinctrl, "idt_en_sleep"); + if (IS_ERR_OR_NULL(chip->idt_en_sleep)) { + pr_err("get idt_en_sleep fail\n"); + return -EINVAL; + } + + chip->idt_en_default = + pinctrl_lookup_state(chip->pinctrl, "idt_en_default"); + if (IS_ERR_OR_NULL(chip->idt_en_default)) { + pr_err("get idt_en_default fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->idt_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->idt_en_sleep); + + pr_err("gpio_val:%d\n", gpio_get_value(chip->idt_en_gpio)); + + return 0; +} + +static int p9415_get_idt_en_val(struct op_p9415_ic *chip) +{ + if (chip->idt_en_gpio <= 0) { + pr_err("idt_en_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->idt_en_active) || + IS_ERR_OR_NULL(chip->idt_en_sleep) || + IS_ERR_OR_NULL(chip->idt_en_default)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + return gpio_get_value(chip->idt_en_gpio); +} + +static void p9415_set_idt_int_active(struct op_p9415_ic *chip) +{ + gpio_direction_input(chip->idt_int_gpio); // in + pinctrl_select_state(chip->pinctrl, chip->idt_int_active); // no_PULL +} + +static void p9415_set_idt_con_active(struct op_p9415_ic *chip) +{ + gpio_direction_input(chip->idt_con_gpio); // in + pinctrl_select_state(chip->pinctrl, chip->idt_con_active); // no_PULL +} + +static void p9415_idt_int_irq_init(struct op_p9415_ic *chip) +{ + chip->idt_int_irq = gpio_to_irq(chip->idt_int_gpio); + + pr_err("op-wlchg test %s chip->idt_int_irq[%d]\n", __func__, + chip->idt_int_irq); +} + +static void p9415_idt_con_irq_init(struct op_p9415_ic *chip) +{ + chip->idt_con_irq = gpio_to_irq(chip->idt_con_gpio); + pr_err("op-wlchg test %s chip->idt_con_irq[%d]\n", __func__, + chip->idt_con_irq); +} + +static int p9415_idt_con_gpio_init(struct op_p9415_ic *chip) +{ + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + pr_err("get pinctrl fail\n"); + return -EINVAL; + } + + //idt_con + chip->idt_con_active = + pinctrl_lookup_state(chip->pinctrl, "idt_connect_active"); + if (IS_ERR_OR_NULL(chip->idt_con_active)) { + pr_err("get idt_con_active fail\n"); + return -EINVAL; + } + + chip->idt_con_sleep = + pinctrl_lookup_state(chip->pinctrl, "idt_connect_sleep"); + if (IS_ERR_OR_NULL(chip->idt_con_sleep)) { + pr_err("get idt_con_sleep fail\n"); + return -EINVAL; + } + + chip->idt_con_default = + pinctrl_lookup_state(chip->pinctrl, "idt_connect_default"); + if (IS_ERR_OR_NULL(chip->idt_con_default)) { + pr_err("get idt_con_default fail\n"); + return -EINVAL; + } + + if (chip->idt_con_gpio > 0) { + gpio_direction_input(chip->idt_con_gpio); + } + + pinctrl_select_state(chip->pinctrl, chip->idt_con_active); + + return 0; +} + +static int p9415_idt_int_gpio_init(struct op_p9415_ic *chip) +{ + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: op_p9415_ic not ready!\n", + __func__); + return -EINVAL; + } + + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + pr_err("get pinctrl fail\n"); + return -EINVAL; + } + + //idt_int + chip->idt_int_active = + pinctrl_lookup_state(chip->pinctrl, "idt_int_active"); + if (IS_ERR_OR_NULL(chip->idt_int_active)) { + pr_err("get idt_int_active fail\n"); + return -EINVAL; + } + + chip->idt_int_sleep = + pinctrl_lookup_state(chip->pinctrl, "idt_int_sleep"); + if (IS_ERR_OR_NULL(chip->idt_int_sleep)) { + pr_err("get idt_int_sleep fail\n"); + return -EINVAL; + } + + chip->idt_int_default = + pinctrl_lookup_state(chip->pinctrl, "idt_int_default"); + if (IS_ERR_OR_NULL(chip->idt_int_default)) { + pr_err("get idt_int_default fail\n"); + return -EINVAL; + } + + if (chip->idt_int_gpio > 0) { + gpio_direction_input(chip->idt_int_gpio); + } + + pinctrl_select_state(chip->pinctrl, chip->idt_int_active); + + return 0; +} + +static int p9415_vbat_en_gpio_init(struct op_p9415_ic *chip) +{ + if (!chip) { + printk(KERN_ERR "[OP_CHG][%s]: op_p9415_ic not ready!\n", + __func__); + return -EINVAL; + } + + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + pr_err("get pinctrl fail\n"); + return -EINVAL; + } + + //vbat_en + chip->vbat_en_active = + pinctrl_lookup_state(chip->pinctrl, "vbat_en_active"); + if (IS_ERR_OR_NULL(chip->vbat_en_active)) { + pr_err("get vbat_en_active fail\n"); + return -EINVAL; + } + + chip->vbat_en_sleep = + pinctrl_lookup_state(chip->pinctrl, "vbat_en_sleep"); + if (IS_ERR_OR_NULL(chip->vbat_en_sleep)) { + pr_err("get vbat_en_sleep fail\n"); + return -EINVAL; + } + + chip->vbat_en_default = + pinctrl_lookup_state(chip->pinctrl, "vbat_en_default"); + if (IS_ERR_OR_NULL(chip->vbat_en_default)) { + pr_err("get vbat_en_default fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->vbat_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->vbat_en_sleep); + + return 0; +} + +static int p9415_set_idt_en_val(struct op_p9415_ic *chip, int value) // 0 active, 1 inactive +{ + + if (chip->idt_en_gpio <= 0) { + pr_err("idt_en_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->idt_en_active) || + IS_ERR_OR_NULL(chip->idt_en_sleep) || + IS_ERR_OR_NULL(chip->idt_en_default)) { + pr_err("pinctrl null, return\n"); + return -EINVAL; + } + + if (value) { + gpio_direction_output(chip->idt_en_gpio, 1); + pinctrl_select_state(chip->pinctrl, chip->idt_en_active); + } else { + gpio_direction_output(chip->idt_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->idt_en_default); + } + pr_info("set value:%d, gpio_val:%d\n", value, + gpio_get_value(chip->idt_en_gpio)); + return 0; +} + +static int p9415_get_vout(struct op_p9415_ic *chip, int *vout) +{ + char val_buf[2] = { 0, 0 }; + int temp; + int rc; + + rc = p9415_read_reg(chip, 0x003C, val_buf, 2); + if (rc) { + pr_err("read vout err, rc=%d\n", rc); + return rc; + } + temp = val_buf[0] | val_buf[1] << 8; + *vout = temp * 21000 / 4095; + + return 0; +} + +static int p9415_set_vout(struct op_p9415_ic *chip, int vout) +{ + char val_buf[2]; + int rc; + + val_buf[0] = vout & 0x00FF; + val_buf[1] = (vout & 0xFF00) >> 8; + + rc = p9415_write_reg_multi_byte(chip, 0x003E, val_buf, 2); + if (rc) { + pr_err("set vout err, rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int p9415_get_vrect(struct op_p9415_ic *chip, int *vrect) +{ + char val_buf[2] = { 0, 0 }; + int temp; + int rc; + + rc = p9415_read_reg(chip, 0x0040, val_buf, 2); + pr_debug("raw data:0x%02x, 0x%02x\n", val_buf[0], val_buf[1]); + if (rc) { + pr_err("read vrect err, rc=%d\n", rc); + return rc; + } + temp = val_buf[0] | val_buf[1] << 8; + *vrect = temp * 26250 / 4095; + + return 0; +} + +static int p9415_get_iout(struct op_p9415_ic *chip, int *iout) +{ + char val_buf[2] = { 0, 0 }; + int rc; + + rc = p9415_read_reg(chip, 0x0044, val_buf, 2); + pr_debug("raw data:0x%02x, 0x%02x\n", val_buf[0], val_buf[1]); + if (rc) { + pr_err("read iout err, rc=%d\n", rc); + return rc; + } + *iout = val_buf[0] | val_buf[1] << 8; + + return 0; +} + +static int p9415_get_trx_vol(struct op_p9415_ic *chip, int *vol) +{ + char val_buf[2] = { 0, 0 }; + int rc; + + rc = p9415_read_reg(chip, 0x0070, val_buf, 2); + pr_debug("raw data:0x%02x, 0x%02x\n", val_buf[0], val_buf[1]); + if (rc) { + pr_err("read trx vol err, rc=%d\n", rc); + return rc; + } + *vol = val_buf[0] | val_buf[1] << 8; + + return 0; +} + +static int p9415_get_trx_curr(struct op_p9415_ic *chip, int *curr) +{ + char val_buf[2] = { 0, 0 }; + int rc; + + rc = p9415_read_reg(chip, 0x006e, val_buf, 2); + if (rc) { + pr_err("read trx current err, rc=%d\n", rc); + return rc; + } + *curr = val_buf[0] | val_buf[1] << 8; + + return 0; +} + +static int p9415_get_cep_change_status(struct op_p9415_ic *chip) +{ + char val_buf[2] = { 0, 0 }; + static int pre_val; + int val; + int rc; + + rc = p9415_read_reg(chip, 0x0020, val_buf, 2); + if (rc) { + pr_err("Couldn't read cep change status, rc=%d\n", rc); + return rc; + } + val = val_buf[0] | val_buf[1] << 8; + + if (val != pre_val) { + pre_val = val; + return 0; + } else { + return -EINVAL; + } +} + +static int p9415_get_cep_val(struct op_p9415_ic *chip, int *val) +{ + int rc; + char temp = 0; + + rc = p9415_get_cep_change_status(chip); + if (rc) { + pr_info("cep val is not updated\n"); + return rc; + } + + rc = p9415_read_reg(chip, 0x0033, &temp, 1); + if (rc) { + pr_err("Couldn't read CEP, rc = %x\n", rc); + return rc; + } + *val = (signed char)temp; + + return rc; +} + + +static int p9415_get_cep_val_skip_check_update(struct op_p9415_ic *chip, int *val) +{ + int rc; + char temp = 0; + + rc = p9415_read_reg(chip, 0x0033, &temp, 1); + if (rc) { + pr_err("Couldn't read CEP, rc = %x\n", rc); + return rc; + } + *val = (signed char)temp; + + return rc; +} + +static int p9415_get_work_freq(struct op_p9415_ic *chip, int *val) +{ + int rc; + char temp; + + rc = p9415_read_reg(chip, 0x5e, &temp, 1); + if (rc) { + pr_err("Couldn't read rx freq val, rc = %d\n", rc); + return rc; + } + *val = (int)temp; + return rc; +} + +static int p9415_get_rx_run_mode(struct op_p9415_ic *chip, int *val) +{ + int rc; + char temp; + + rc = p9415_read_reg(chip, 0x0088, &temp, 1); + if (rc) { + pr_err("Couldn't read 0x0088 rc = %x\n",rc); + return rc; + } + if (temp == 0x31) { + pr_info("RX running in EPP!\n"); + *val = RX_RUNNING_MODE_EPP; + } else if (temp == 0x04) { + pr_info("RX running in BPP!\n"); + *val = RX_RUNNING_MODE_BPP; + } else{ + pr_info("RX running in Others!\n"); + *val = RX_RUNNING_MODE_OTHERS; + } + return 0; +} + +static int p9415_set_dcdc_enable(void) +{ + struct op_p9415_ic *chip = g_p9415_chip; + int rc; + + if (chip == NULL) { + pr_err("op_p9415_ic not exist, return\n"); + return -ENODEV; + } + + rc = p9415_config_interface(chip, 0xd4, 0x01, 0x01); + if (rc) + pr_err("set dcdc enable error, rc=%d\n", rc); + + return rc; +} + +static int p9415_set_trx_enable(struct op_p9415_ic *chip, bool enable) +{ + int rc; + + if (enable) + rc = p9415_config_interface(chip, 0x76, 0x01, 0xff); + else + rc = p9415_config_interface(chip, 0x76, 0x00, 0xff); + if (rc) + pr_err("can't %s trx, rc=%d\n", rc, enable ? "enable" : "disable"); + + return rc; +} + +static int p9415_ftm_test(struct op_p9415_ic *chip) +{ + int rc; + int err_no = 0; + char temp[4] = { 0, 0, 0, 0 }; + + if (normal_charger == NULL) { + pr_err("[FTM_TEST]smb_charger isn't ready!\n"); + return -ENODEV; + } + + if (wlchg_wireless_charge_start()) { + pr_err("[FTM_TEST]g_op_chip->charger_exist == 1, return!\n"); + return -EINVAL; + } + + if (wlchg_get_usbin_val() != 0) { + pr_err("[FTM_TEST]usb using, can't test\n"); + return -EINVAL; + } + + op_set_wrx_en_value(2); + msleep(20); + op_set_wrx_otg_value(1); + msleep(20); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_cl, + REVERSE_WIRELESS_CHARGE_CURR_LIMT); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_vol, + WIRELESS_CHARGE_FTM_TEST_VOL_LIMT); + // set pm8150b vbus out. + smblib_vbus_regulator_enable(normal_charger->vbus_vreg->rdev); + msleep(50); + rc = p9415_read_reg(chip, 0x001C, temp, 4); + if (rc) { + pr_err("[FTM_TEST]Couldn't read p9415 fw version, rc=%d\n", rc); + err_no |= WLCHG_FTM_TEST_RX_ERR; + } + pr_info("[FTM_TEST]p9415 fw: %02x %02x %02x %02x\n", temp[0], temp[1], temp[2], temp[3]); + + if (wlchg_get_usbin_val() != 0) { + pr_err("[FTM_TEST]usb_int status exception\n"); + err_no |= WLCHG_FTM_TEST_RX_ERR; + } + + rc = chargepump_i2c_test(); + if (rc) { + pr_err("[FTM_TEST]Couldn't get cp1 status, rc=%d\n", rc); + err_no |= WLCHG_FTM_TEST_CP1_ERR; + } + + // disable pm8150b vbus out. + smblib_vbus_regulator_disable(normal_charger->vbus_vreg->rdev); + msleep(20); + op_set_wrx_otg_value(0); + msleep(20); + if (!typec_is_otg_mode()) + op_set_wrx_en_value(0); + + return err_no; +} + +static int p9415_get_trx_status(struct op_p9415_ic *chip, int *status) +{ + int rc; + char temp; + + rc = p9415_read_reg(chip, 0x78, &temp, 1); + if (rc) { + pr_err("Couldn't read trx status, rc = %d\n", rc); + return rc; + } + *status = (int)temp; + + return rc; +} + +static int p9415_get_trx_err(struct op_p9415_ic *chip, int *err) +{ + int rc; + char temp; + + rc = p9415_read_reg(chip, 0x79, &temp, 1); + if (rc) { + pr_err("Couldn't read trx err code, rc = %d\n", rc); + return rc; + } + *err = (int)temp; + + return rc; +} + +static int p9415_get_headroom(struct op_p9415_ic *chip, int *val) +{ + int rc; + char temp; + + rc = p9415_read_reg(chip, 0x9e, &temp, 1); + if (rc) { + pr_err("Couldn't read headroom, rc = %d\n", rc); + return rc; + } + *val = (int)temp; + + return rc; +} + +static int p9415_set_headroom(struct op_p9415_ic *chip, int val) +{ + int rc; + + rc = p9415_config_interface(chip, 0x76, val, 0xff); + if (rc) + pr_err("can't set headroom, rc=%d\n", rc); + + return rc; +} + +static int p9415_get_prop(struct rx_chip_prop *prop, + enum rx_prop_type prop_type, + union rx_chip_propval *val) +{ + struct op_p9415_ic *chip = prop->private_data; + int temp = 0; + int rc = 0; + + switch (prop_type) { + case RX_PROP_VOUT: + rc = p9415_get_vout(chip, &temp); + val->intval = temp; + break; + case RX_PROP_VRECT: + rc = p9415_get_vrect(chip, &temp); + val->intval = temp; + break; + case RX_PROP_IOUT: + rc = p9415_get_iout(chip, &temp); + val->intval = temp; + break; + case RX_PROP_CEP: + rc = p9415_get_cep_val(chip, &temp); + val->intval = temp; + break; + case RX_PROP_CEP_SKIP_CHECK_UPDATE: + rc = p9415_get_cep_val_skip_check_update(chip, &temp); + val->intval = temp; + break; + case RX_PROP_WORK_FREQ: + rc = p9415_get_work_freq(chip, &temp); + val->intval = temp; + break; + case RX_PROP_TRX_STATUS: + rc = p9415_get_trx_status(chip, &temp); + val->intval = temp; + break; + case RX_PROP_TRX_ERROR_CODE: + rc = p9415_get_trx_err(chip, &temp); + val->intval = temp; + break; + case RX_PROP_TRX_VOL: + rc = p9415_get_trx_vol(chip, &temp); + val->intval = temp; + break; + case RX_PROP_TRX_CURR: + rc = p9415_get_trx_curr(chip, &temp); + val->intval = temp; + break; + case RX_PROP_RUN_MODE: + rc = p9415_get_rx_run_mode(chip, &temp); + val->intval = temp; + break; + case RX_PROP_FTM_TEST: + rc = p9415_ftm_test(chip); + if (rc < 0) + return rc; + val->intval = rc; + rc = 0; + break; + case RX_PROP_CHIP_SLEEP: + val->intval = p9415_get_vbat_en_val(chip); + break; + case RX_PROP_CHIP_EN: + val->intval = p9415_get_idt_en_val(chip); + break; + case RX_PROP_CHIP_CON: + val->intval = p9415_get_idt_con_val(chip); + break; + case RX_PROP_FW_UPDATING: + val->intval = chip->idt_fw_updating; + break; + case RX_PROP_HEADROOM: + rc = p9415_get_headroom(chip, &temp); + val->intval = temp; + break; + default: + return -EINVAL; + } + + if (rc < 0) { + pr_debug("Couldn't get prop %d rc = %d\n", prop_type, rc); + return -ENODATA; + } + + return 0; +} + +static int p9415_set_prop(struct rx_chip_prop *prop, + enum rx_prop_type prop_type, + union rx_chip_propval *val) +{ + struct op_p9415_ic *chip = prop->private_data; + int rc = 0; + + switch (prop_type) { + case RX_PROP_VOUT: + rc = p9415_set_vout(chip, val->intval); + break; + case RX_PROP_ENABLE_DCDC: + if (val->intval > 0) + rc = p9415_set_dcdc_enable(); + break; + case RX_PROP_CHIP_SLEEP: + rc = p9415_set_vbat_en_val(chip, val->intval); + break; + case RX_PROP_CHIP_EN: + rc = p9415_set_idt_en_val(chip, val->intval); + break; + case RX_PROP_TRX_ENABLE: + rc = p9415_set_trx_enable(chip, val->intval); + break; + case RX_PROP_HEADROOM: + rc = p9415_set_headroom(chip, val->intval); + break; + default: + pr_err("set prop %d is not supported\n", prop_type); + rc = -EINVAL; + break; + } + + return rc; +} + +static int p9415_send_msg(struct rx_chip_prop *prop, + enum rx_msg_type msg_type, + unsigned char msg) +{ + struct op_p9415_ic *chip = prop->private_data; + char write_data[2] = { 0, 0 }; + + if (msg_type == RX_MSG_LONG) { + write_data[0] = 0x10; + write_data[1] = 0x00; + p9415_write_reg_multi_byte(chip, 0x0038, write_data, 2); + + write_data[0] = 0x10; + write_data[1] = 0x00; + p9415_write_reg_multi_byte(chip, 0x0056, write_data, 2); + + write_data[0] = 0x20; + write_data[1] = 0x00; + p9415_write_reg_multi_byte(chip, 0x004E, write_data, 2); + } + + if (msg_type != RX_MSG_SHORT) { + p9415_config_interface(chip, 0x0050, 0x48, 0xFF); + p9415_config_interface(chip, 0x0051, msg, 0xFF); + p9415_config_interface(chip, 0x0052, (~msg), 0xFF); + p9415_config_interface(chip, 0x0053, 0xFF, 0xFF); + p9415_config_interface(chip, 0x0054, 0x00, 0xFF); + } else { + p9415_config_interface(chip, 0x0050, 0x18, 0xFF); + p9415_config_interface(chip, 0x0051, msg, 0xFF); + } + + p9415_config_interface(chip, 0x004E, 0x01, 0x01); //BIT0 + + return 0; +} + +static unsigned char p9415_calculate_checksum(const unsigned char *data, int len) +{ + unsigned char temp = 0; + + while(len--) + temp ^= *data++; + + pr_info("checksum = %d\n", temp); + return temp; +} + +static int p9415_send_match_q_parm(struct rx_chip_prop *prop, + unsigned char data) +{ + struct op_p9415_ic *chip = prop->private_data; + unsigned char buf[4] = {0x38, 0x48, 0x00, data}; + unsigned char checksum; + + checksum = p9415_calculate_checksum(buf, 4); + p9415_config_interface(chip, 0x0050, buf[0], 0xFF); + p9415_config_interface(chip, 0x0051, buf[1], 0xFF); + p9415_config_interface(chip, 0x0052, buf[2], 0xFF); + p9415_config_interface(chip, 0x0053, buf[3], 0xFF); + p9415_config_interface(chip, 0x0054, checksum, 0xFF); + + p9415_config_interface(chip, 0x004E, 0x01, 0x01); + + return 0; +} + +static int p9415_set_fod_parm(struct rx_chip_prop *prop, + const char data[]) +{ + struct op_p9415_ic *chip = prop->private_data; + int rc; + + rc = p9415_write_reg_multi_byte(chip, 0x0068, data, FOD_PARM_LENGTH); + if (rc < 0) + pr_err("set fod parameter error, rc=%d\n", rc); + + return rc; +} + +static void p9415_reset(struct rx_chip_prop *prop) +{ + int wpc_con_level = 0; + int wait_wpc_disconn_cnt = 0; + struct op_p9415_ic *chip = prop->private_data; + + wpc_con_level = p9415_get_idt_con_val(chip); + if (wpc_con_level == 1) { + p9415_set_vbat_en_val(chip, 1); + msleep(100); + + while (wait_wpc_disconn_cnt < 10) { + wpc_con_level = p9415_get_idt_con_val(chip); + if (wpc_con_level == 0) { + break; + } + msleep(150); + wait_wpc_disconn_cnt++; + } + chargepump_disable(); + } + return; +} + +static struct rx_chip_prop p9415_prop = { + .get_prop = p9415_get_prop, + .set_prop = p9415_set_prop, + .send_msg = p9415_send_msg, + .send_match_q_parm = p9415_send_match_q_parm, + .set_fod_parm = p9415_set_fod_parm, + .rx_reset = p9415_reset, +}; + +int p9415_init_registers(struct op_p9415_ic *chip) +{ + char write_data[2] = { 0, 0 }; + if (!chip) { + pr_err("op_p9415_ic not ready!\n"); + return -EINVAL; + } + + write_data[0] = 0x50; + write_data[1] = 0x00; + p9415_write_reg_multi_byte(chip, 0x0038, write_data, 2); + + write_data[0] = 0x30; + write_data[1] = 0x00; + p9415_write_reg_multi_byte(chip, 0x0056, write_data, 2); + + write_data[0] = 0x20; + write_data[1] = 0x00; + p9415_write_reg_multi_byte(chip, 0x004E, write_data, 2); + + return 0; +} + +static bool p9415_firmware_is_updating(struct op_p9415_ic *chip) +{ + return chip->idt_fw_updating; +} + +#ifdef NO_FW_UPGRADE_CRC +static int p9415_MTP(struct op_p9415_ic *chip, unsigned char *fw_buf, int fw_size) +{ + int rc; + int i, j; + unsigned char *fw_data; + unsigned char write_ack; + unsigned short int StartAddr; + unsigned short int CheckSum; + unsigned short int CodeLength; + + pr_err("--1--!\n"); + // configure the system + rc = __p9415_write_reg(chip, 0x3000, 0x5a); // write key + if (rc != 0) { + pr_err("Write 0x3000 reg error!\n"); + return rc; + } + + pr_err("--2--!\n"); + rc = __p9415_write_reg(chip, 0x3040, 0x10); // halt M0 + if (rc != 0) { + pr_err("Write 0x3000 reg error!\n"); + return rc; + } + + pr_err("--3--!\n"); + rc = p9415_write_reg_multi_byte( + chip, 0x1c00, MTPBootloader9320, + sizeof(MTPBootloader9320)); // load provided by IDT array + if (rc != 0) { + pr_err("Write 0x1c00 reg error!\n"); + return rc; + } + + pr_err("--4--!\n"); + rc = __p9415_write_reg(chip, 0x400, 0); // initialize buffer + if (rc != 0) { + pr_err("Write 0x400 reg error!\n"); + return rc; + } + + pr_err("--5--!\n"); + rc = __p9415_write_reg(chip, 0x3048, + 0x80); // map RAM address 0x1c00 to OTP 0x0000 + if (rc != 0) { + pr_err("Write 0x3048 reg error!\n"); + return rc; + } + + pr_err("--6--!\n"); + rc = __p9415_write_reg(chip, 0x3040, 0x80); // run M0 + // this global variable is used by the i2c driver to block ACK error message + + msleep(100); + + pr_err("The idt firmware size: %d!\n", fw_size); + + // program pages of 128 bytes + fw_data = kzalloc(144, GFP_KERNEL); + if (!fw_data) { + pr_err("can't alloc memory!\n"); + return -EINVAL; + } + + for (i = 0; i < fw_size; i += 128) { + pr_err("Begin to write chunk %d!\n", i); + + StartAddr = i; + CheckSum = StartAddr; + CodeLength = 128; + + memcpy(fw_data + 8, fw_buf + i, 128); + + j = fw_size - i; + if (j < 128) { + j = ((j + 15) / 16) * 16; + CodeLength = (unsigned short int)j; + } else { + j = 128; + } + + j -= 1; + for (; j >= 0; j--) { + CheckSum += fw_data[j + 8]; // add the non zero values + } + + CheckSum += CodeLength; // finish calculation of the check sum + + memcpy(fw_data + 2, (char *)&StartAddr, 2); + memcpy(fw_data + 4, (char *)&CodeLength, 2); + memcpy(fw_data + 6, (char *)&CheckSum, 2); + + rc = p9415_write_reg_multi_byte(chip, 0x400, fw_data, + ((CodeLength + 8 + 15) / 16) * + 16); + if (rc != 0) { + pr_err("ERROR: Write fw data error!\n"); + goto MTP_ERROR; + } + + rc = __p9415_write_reg(chip, 0x400, 0x01); + if (rc != 0) { + pr_err("ERROR: on OTP buffer validation\n"); + goto MTP_ERROR; + } + + do { + msleep(20); + + rc = p9415_read_reg(chip, 0x400, &write_ack, 1); + if (rc != 0) { + pr_err("ERROR: on reading OTP buffer status\n"); + goto MTP_ERROR; + } + } while ((write_ack & 0x01) != 0); + + // check status + if (write_ack != 2) { // not OK + if (write_ack == 4) { + pr_err("ERROR: WRITE ERR\n"); + } else if (write_ack == 8) { + pr_err("ERROR: CHECK SUM ERR\n"); + } else { + pr_err("ERROR: UNKNOWN ERR\n"); + } + + goto MTP_ERROR; + } + } + + // restore system + rc = __p9415_write_reg(chip, 0x3000, 0x5a); // write key + if (rc != 0) { + pr_err("Write 0x3000 reg error!\n"); + goto MTP_ERROR; + } + + rc = __p9415_write_reg(chip, 0x3048, 0x00); // remove code remapping + if (rc != 0) { + pr_err("Write 0x3048 reg error!\n"); + goto MTP_ERROR; + } + + pr_err("OTP Programming finished\n"); + + kfree(fw_data); + return 0; + +MTP_ERROR: + kfree(fw_data); + return -EINVAL; +} +#else +static int p9415_load_bootloader(struct op_p9415_ic *chip) +{ + int rc = 0; + // configure the system + rc = __p9415_write_reg(chip, 0x3000, 0x5a); // write key + if (rc != 0) { + pr_err("Write 0x3000 reg error!\n"); + return rc; + } + + rc = __p9415_write_reg(chip, 0x3004, 0x00); // set HS clock + if (rc != 0) { + pr_err("Write 0x3004 reg error!\n"); + return rc; + } + + rc = __p9415_write_reg(chip, 0x3008, 0x09); // set AHB clock + if (rc != 0) { + pr_err("Write 0x3008 reg error!\n"); + return rc; + } + + rc = __p9415_write_reg(chip, 0x300C, 0x05); // configure 1us pulse + if (rc != 0) { + pr_err("Write 0x300c reg error!\n"); + return rc; + } + + rc = __p9415_write_reg(chip, 0x300D, 0x1d); // configure 500ns pulse + if (rc != 0) { + pr_err("Write 0x300d reg error!\n"); + return rc; + } + + rc = __p9415_write_reg(chip, 0x3040, 0x11); // Enable MTP access via I2C + if (rc != 0) { + pr_err("Write 0x3040 reg error!\n"); + return rc; + } + + msleep(20); + + pr_err("-b-2--!\n"); + rc = __p9415_write_reg(chip, 0x3040, 0x10); // halt microcontroller M0 + if (rc != 0) { + pr_err("Write 0x3040 reg error!\n"); + return rc; + } + + pr_err("-b-3--!\n"); + rc = p9415_write_reg_multi_byte( + chip, 0x0800, MTPBootloader9320, + sizeof(MTPBootloader9320)); // load provided by IDT array + if (rc != 0) { + pr_err("Write 0x1c00 reg error!\n"); + return rc; + } + + pr_err("-b-4--!\n"); + rc = __p9415_write_reg(chip, 0x400, 0); // initialize buffer + if (rc != 0) { + pr_err("Write 0x400 reg error!\n"); + return rc; + } + + pr_err("-b-5--!\n"); + rc = __p9415_write_reg(chip, 0x3048, 0xD0); // map RAM address 0x1c00 to OTP 0x0000 + if (rc != 0) { + pr_err("Write 0x3048 reg error!\n"); + return rc; + } + + pr_err("-b-6--!\n"); + rc = __p9415_write_reg(chip, 0x3040, 0x80); // run M0 + + return 0; +} + +static int p9415_load_fw(struct op_p9415_ic *chip, unsigned char *fw_data, int CodeLength) +{ + unsigned char write_ack = 0; + int rc = 0; + + rc = p9415_write_reg_multi_byte(chip, 0x400, fw_data, + ((CodeLength + 8 + 15) / 16) * 16); + if (rc != 0) { + pr_err("ERROR: write multi byte data error!\n"); + goto LOAD_ERR; + } + rc = __p9415_write_reg(chip, 0x400, 0x01); + if (rc != 0) { + pr_err("ERROR: on OTP buffer validation\n"); + goto LOAD_ERR; + } + + do { + msleep(20); + rc = p9415_read_reg(chip, 0x401, &write_ack, 1); + if (rc != 0) { + pr_err("ERROR: on reading OTP buffer status\n"); + goto LOAD_ERR; + } + } while ((write_ack & 0x01) != 0); + + // check status + if (write_ack != 2) { // not OK + if (write_ack == 4) + pr_err("ERROR: WRITE ERR\n"); + else if (write_ack == 8) + pr_err("ERROR: CHECK SUM ERR\n"); + else + pr_err("ERROR: UNKNOWN ERR\n"); + + rc = -1; + } +LOAD_ERR: + return rc; +} + +static int p9415_MTP(struct op_p9415_ic *chip, unsigned char *fw_buf, int fw_size) +{ + int rc; + int i, j; + unsigned char *fw_data; + unsigned char write_ack; + unsigned short int StartAddr; + unsigned short int CheckSum; + unsigned short int CodeLength; + // pure fw size not contains last 128 bytes fw version. + int pure_fw_size = fw_size - 128; + + pr_err("--1--!\n"); + + rc = p9415_load_bootloader(chip); + if (rc != 0) { + pr_err("Update bootloader 1 error!\n"); + return rc; + } + + msleep(100); + + pr_err("The idt firmware size: %d!\n", fw_size); + + // program pages of 128 bytes + // 8-bytes header, 128-bytes data, 8-bytes padding to round to 16-byte boundary + fw_data = kzalloc(144, GFP_KERNEL); + if (!fw_data) { + pr_err("can't alloc memory!\n"); + return -EINVAL; + } + + //ERASE FW VERSION(the last 128 byte of the MTP) + memset(fw_data, 0x00, 144); + StartAddr = pure_fw_size; + CheckSum = StartAddr; + CodeLength = 128; + for (j = 127; j >= 0; j--) + CheckSum += fw_data[j + 8]; // add the non zero values. + + CheckSum += CodeLength; // finish calculation of the check sum + memcpy(fw_data + 2, (char *)&StartAddr, 2); + memcpy(fw_data + 4, (char *)&CodeLength, 2); + memcpy(fw_data + 6, (char *)&CheckSum, 2); + rc = p9415_load_fw(chip, fw_data, CodeLength); + if (rc < 0) { // not OK + pr_err("ERROR: erase fw version ERR\n"); + goto MTP_ERROR; + } + + // upgrade fw + memset(fw_data, 0x00, 144); + for (i = 0; i < pure_fw_size; i += 128) { + pr_err("Begin to write chunk %d!\n", i); + + StartAddr = i; + CheckSum = StartAddr; + CodeLength = 128; + + memcpy(fw_data + 8, fw_buf + i, 128); + + j = pure_fw_size - i; + if (j < 128) { + j = ((j + 15) / 16) * 16; + CodeLength = (unsigned short int)j; + } else { + j = 128; + } + + j -= 1; + for (; j >= 0; j--) + CheckSum += fw_data[j + 8]; // add the non zero values + + CheckSum += CodeLength; // finish calculation of the check sum + + memcpy(fw_data + 2, (char *)&StartAddr, 2); + memcpy(fw_data + 4, (char *)&CodeLength, 2); + memcpy(fw_data + 6, (char *)&CheckSum, 2); + + //typedef struct { // write to structure at address 0x400 + // u16 Status; + // u16 StartAddr; + // u16 CodeLength; + // u16 DataChksum; + // u8 DataBuf[128]; + //} P9220PgmStrType; + // read status is guaranteed to be != 1 at this point + + rc = p9415_load_fw(chip, fw_data, CodeLength); + if (rc < 0) { // not OK + pr_err("ERROR: write chunk %d ERR\n", i); + goto MTP_ERROR; + } + } + + msleep(100); + // disable pm8150b vbus out. + pr_info("disable pm8150b vbus out\n"); + smblib_vbus_regulator_disable(normal_charger->vbus_vreg->rdev); + msleep(3000); + // enable pm8150b vbus out. + pr_info("enable pm8150b vbus out\n"); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_cl, + WIRELESS_CHARGE_UPGRADE_CURR_LIMT); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_vol, + WIRELESS_CHARGE_UPGRADE_VOL_LIMT); + smblib_vbus_regulator_enable(normal_charger->vbus_vreg->rdev); + msleep(500); + + // Verify + rc = p9415_load_bootloader(chip); + if (rc != 0) { + pr_err("Update bootloader 2 error!\n"); + return rc; + } + msleep(100); + rc = __p9415_write_reg(chip, 0x402, 0x00); // write start address + if (rc != 0) { + pr_err("Write 0x402 reg error!\n"); + return rc; + } + rc = __p9415_write_reg(chip, 0x404, pure_fw_size & 0xff); // write FW length low byte + if (rc != 0) { + pr_err("Write 0x404 reg error!\n"); + return rc; + } + rc = __p9415_write_reg(chip, 0x405, (pure_fw_size >> 8) & 0xff); // write FW length high byte + if (rc != 0) { + pr_err("Write 0x405 reg error!\n"); + return rc; + } + + // write CRC from FW release package + fw_data[0] = fw_buf[pure_fw_size + 0x08]; + fw_data[1] = fw_buf[pure_fw_size + 0x09]; + p9415_write_reg_multi_byte(chip, 0x406, fw_data, 2); + + rc = __p9415_write_reg(chip, 0x400, 0x11); + if (rc != 0) { + pr_err("Write 0x406 reg error!\n"); + return rc; + } + do { + msleep(20); + rc = p9415_read_reg(chip, 0x401, &write_ack, 1); + if (rc != 0) { + pr_err("ERROR: on reading OTP buffer status\n"); + goto MTP_ERROR; + } + } while ((write_ack & 0x01) != 0); + // check status + if (write_ack != 2) { // not OK + if (write_ack == 4) + pr_err("ERROR: CRC WRITE ERR\n"); + else if (write_ack == 8) + pr_err("ERROR: CRC CHECK SUM ERR\n"); + else + pr_err("ERROR: CRC UNKNOWN ERR\n"); + + goto MTP_ERROR; + } + + memset(fw_data, 0x00, 144); + StartAddr = pure_fw_size; + CheckSum = StartAddr; + CodeLength = 128; + memcpy(fw_data + 8, fw_buf + StartAddr, 128); + j = 127; + for (; j >= 0; j--) + CheckSum += fw_data[j + 8]; // add the non zero values. + + CheckSum += CodeLength; // finish calculation of the check sum + memcpy(fw_data + 2, (char *)&StartAddr, 2); + memcpy(fw_data + 4, (char *)&CodeLength, 2); + memcpy(fw_data + 6, (char *)&CheckSum, 2); + + rc = p9415_load_fw(chip, fw_data, CodeLength); + if (rc < 0) { // not OK + pr_err("ERROR: erase fw version ERR\n"); + goto MTP_ERROR; + } + + // restore system + rc = __p9415_write_reg(chip, 0x3000, 0x5a); // write key + if (rc != 0) { + pr_err("Write 0x3000 reg error!\n"); + goto MTP_ERROR; + } + + rc = __p9415_write_reg(chip, 0x3048, 0x00); // remove code remapping + if (rc != 0) { + pr_err("Write 0x3048 reg error!\n"); + goto MTP_ERROR; + } + + pr_err("OTP Programming finished\n"); + + kfree(fw_data); + return 0; + +MTP_ERROR: + kfree(fw_data); + return -EINVAL; +} +#endif // NO_FW_UPGRADE_CRC + +static int p9415_check_idt_fw_update(struct op_p9415_ic *chip) +{ + static int idt_update_retry_cnt; + int rc = -1; + char temp[4] = { 0, 0, 0, 0 }; + unsigned char *fw_buf; + int fw_size; + char pre_hw_version[10] = {0}; + char new_hw_version[10] = {0}; + bool fw_upgrade_successful = false; +#ifndef NO_FW_UPGRADE_CRC + int fw_ver_start_addr = 0; +#endif + fw_buf = idt_firmware; + fw_size = ARRAY_SIZE(idt_firmware); + + pr_err(" check idt fw <><><><><><><><>\n"); + + if (normal_charger == NULL) { + pr_err(" smb chg isn't ready!\n"); + return rc; + } + + if (wlchg_wireless_working()) { + pr_err("p9415 is working, return!\n"); + chip->check_fw_update = true; + return 0; + } + + chip->idt_fw_updating = true; + // disable irq + disable_irq(chip->idt_con_irq); + disable_irq(chip->idt_int_irq); + + op_set_wrx_en_value(2); + msleep(20); + op_set_wrx_otg_value(1); + msleep(20); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_cl, + WIRELESS_CHARGE_UPGRADE_CURR_LIMT); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_vol, + WIRELESS_CHARGE_UPGRADE_VOL_LIMT); + // set pm8150b vbus out. + smblib_vbus_regulator_enable(normal_charger->vbus_vreg->rdev); + msleep(500); + + // get idt id. + rc = p9415_read_reg(chip, 0x5870, temp, 2); + pr_info(" ID= %02x %02x", temp[0], temp[1]); + if (!rc) + snprintf(chip->manu_name, 10, "IDTP9415"); + + rc = p9415_read_reg(chip, 0x001C, temp, 4); + if (rc) { + chg_err("Couldn't read 0x%04x rc = %x\n", 0x001C, rc); + chip->check_fw_update = false; + idt_update_retry_cnt++; + } else { + snprintf(pre_hw_version, 10, "%02x%02x%02x%02x", temp[3], + temp[2], temp[1], temp[0]); + chg_info("The idt fw version: %s\n", pre_hw_version); +#ifdef NO_FW_UPGRADE_CRC + snprintf(new_hw_version, 10, "%02x%02x%02x%02x", fw_buf[0x130F], + fw_buf[0x130E], fw_buf[0x130D], fw_buf[0x130C]); + chg_info("The new fw version: %s\n", new_hw_version); + + if ((temp[0] != fw_buf[0x130C]) || + (temp[1] != fw_buf[0x130D]) || + (temp[2] != fw_buf[0x130E]) || + (temp[3] != fw_buf[0x130F]) || + (idt_update_retry_cnt > 0)) { +#else + fw_ver_start_addr = fw_size - 128; + snprintf(new_hw_version, 10, "%02x%02x%02x%02x", + fw_buf[fw_ver_start_addr + 0x07], fw_buf[fw_ver_start_addr + 0x06], + fw_buf[fw_ver_start_addr + 0x05], fw_buf[fw_ver_start_addr + 0x04]); + chg_info("The new fw version: %s\n", new_hw_version); + + if ((temp[0] != fw_buf[fw_ver_start_addr + 0x04]) || + (temp[1] != fw_buf[fw_ver_start_addr + 0x05]) || + (temp[2] != fw_buf[fw_ver_start_addr + 0x06]) || + (temp[3] != fw_buf[fw_ver_start_addr + 0x07]) || + (idt_update_retry_cnt > 0)) { +#endif + pr_info("Need update the idt fw!\n"); + if (p9415_MTP(chip, fw_buf, fw_size) == 0) { + idt_update_retry_cnt = 0; + chip->check_fw_update = true; + fw_upgrade_successful = true; + } else { + chip->check_fw_update = false; + idt_update_retry_cnt++; + pr_err("p9415_MTP failed, Retry %d!\n", + idt_update_retry_cnt); + rc = -1; + } + } else { + pr_info("No Need update the idt fw!\n"); + fw_upgrade_successful = true; + chip->check_fw_update = true; + } + } + + if (idt_update_retry_cnt >= 5) { + pr_err("Retry more than 5 times, firmware upgrade failed\n"); + idt_update_retry_cnt = 0; + chip->check_fw_update = true; + rc = 0; + } + + msleep(100); + // disable pm8150b vbus out. + smblib_vbus_regulator_disable(normal_charger->vbus_vreg->rdev); + msleep(20); + op_set_wrx_otg_value(0); + msleep(20); + if (!typec_is_otg_mode()) + op_set_wrx_en_value(0); + + // enable irq + enable_irq(chip->idt_int_irq); + enable_irq(chip->idt_con_irq); + chip->idt_fw_updating = false; + + if (fw_upgrade_successful) + snprintf(chip->fw_id, 16, "0x%s", new_hw_version); + else + snprintf(chip->fw_id, 16, "0x%s", pre_hw_version); + push_component_info(WIRELESS_CHARGE, chip->fw_id, chip->manu_name); + + return rc; +} + +int p9415_upgrade_firmware(struct op_p9415_ic *chip, unsigned char *fw_buf, int fw_size) +{ + int rc = 0; + + if (normal_charger == NULL) { + pr_err("smb_charger isn't ready!\n"); + return -ENODEV; + } + + if (wlchg_wireless_working()) { + pr_err("p9415 is working, return!\n"); + return -EINVAL; + } + + if (wlchg_get_usbin_val() != 0) { + pr_err("usb using, can't update\n"); + return -EINVAL; + } + + chip->idt_fw_updating = true; + + op_set_wrx_en_value(2); + msleep(20); + op_set_wrx_otg_value(1); + msleep(20); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_cl, + WIRELESS_CHARGE_UPGRADE_CURR_LIMT); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_vol, + WIRELESS_CHARGE_UPGRADE_VOL_LIMT); + // set pm8150b vbus out. + smblib_vbus_regulator_enable(normal_charger->vbus_vreg->rdev); + msleep(500); + + rc = p9415_MTP(chip, fw_buf, fw_size); + if (rc != 0) { + pr_err("update error, rc=%d\n", rc); + } + + msleep(100); + // disable pm8150b vbus out. + smblib_vbus_regulator_disable(normal_charger->vbus_vreg->rdev); + msleep(20); + op_set_wrx_otg_value(0); + msleep(20); + if (!typec_is_otg_mode()) + op_set_wrx_en_value(0); + + chip->idt_fw_updating = false; + + return rc; +} + +static void p9415_commu_data_process(struct op_p9415_ic *chip) +{ + int rc = -1; + char temp[2] = { 0, 0 }; + char val_buf[6] = { 0, 0, 0, 0, 0, 0}; + struct rx_chip *rx_chip = chip->rx_chip; + + rc = p9415_read_reg(chip, P9415_STATUS_REG, temp, 2); + if (rc) { + pr_err("Couldn't read 0x%04x rc = %x\n", P9415_STATUS_REG, rc); + temp[0] = 0; + } else { + pr_info("read 0x0036 = 0x%02x 0x%02x\n", temp[0], temp[1]); + } + + if (temp[0] & P9415_LDO_ON_MASK) { + pr_info("<~WPC~> LDO is on, connected."); + if (p9415_firmware_is_updating(chip)) { + pr_err("firmware_is_updating is true, return directly."); + return; + } + wlchg_connect_callback_func(true); + chip->connected_ldo_on = true; + } + if (temp[0] & P9415_VOUT_ERR_MASK) { + pr_err("Vout residual voltage is too high\n"); + } + if (temp[0] & P9415_EVENT_MASK) { + rc = p9415_read_reg(chip, 0x0058, val_buf, 6); + if (rc) { + pr_err("Couldn't read 0x%04x rc = %x\n", 0x0058, rc); + } else { + pr_info("Received TX data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", + val_buf[0], val_buf[1], val_buf[2], val_buf[3], val_buf[4], val_buf[5]); + temp[0] = ~val_buf[2]; + temp[1] = ~val_buf[4]; + if ((val_buf[0] == 0x4F) && (val_buf[1] == temp[0]) && + (val_buf[3] == temp[1])) { + rc = wlchg_send_msg(WLCHG_MSG_CMD_RESULT, val_buf[3], val_buf[1]); + pr_info("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\n"); + pr_info("<~WPC~> Received TX command: 0x%02X, data: 0x%02X\n", + val_buf[1], val_buf[3]); + pr_info("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\n"); + if (rc < 0) { + pr_err("send cmd result err, try again\n"); + msleep(2); + wlchg_send_msg(WLCHG_MSG_CMD_RESULT, val_buf[3], val_buf[1]); + } + } else if (val_buf[0] == 0x5F) { + if (val_buf[5] == 0x04 && (val_buf[4] == 0x03 || val_buf[4] == 0x02)) { + pr_info("It's on OP Trx phone."); + rx_chip->on_op_trx = true; + } + rc = wlchg_send_msg(WLCHG_MSG_CMD_RESULT, 0, val_buf[0]); + if (rc < 0) { + pr_err("send cmd result err, try again\n"); + msleep(2); + wlchg_send_msg(WLCHG_MSG_CMD_RESULT, 0, val_buf[0]); + } + } + } + } + + wlchg_tx_callback(); + + p9415_config_interface(chip, 0x0036, 0x00, 0xFF); + p9415_config_interface(chip, 0x0037, 0x00, 0xFF); + p9415_config_interface(chip, 0x0056, 0x30, 0x30); + p9415_config_interface(chip, 0x004E, 0x20, 0x20); +} + +static void p9415_event_int_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_p9415_ic *chip = + container_of(dwork, struct op_p9415_ic, idt_event_int_work); + + p9415_commu_data_process(chip); +} + +static void p9415_connect_int_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_p9415_ic *chip = + container_of(dwork, struct op_p9415_ic, idt_connect_int_work); + + if (p9415_firmware_is_updating(chip) == true) { + pr_err("firmware_is_updating is true, return directly."); + return; + } + + msleep(50); + wlchg_connect_callback_func(false); + if (!charge_mode_startup && (get_boot_mode() == MSM_BOOT_MODE_CHARGE)) { + charge_mode_startup = true; + if (wlchg_get_usbin_val() == 1) + p9415_set_vbat_en_val(chip, 1); + else + schedule_delayed_work(&chip->idt_event_int_work, msecs_to_jiffies(500)); + } + if (p9415_get_idt_con_val(chip) == 1) { + pm_stay_awake(chip->dev); + cancel_delayed_work_sync(&chip->check_ldo_on_work); + schedule_delayed_work(&chip->check_ldo_on_work, p9415_CHECK_LDO_ON_DELAY); + chg_info("schedule delayed 2s work for check ldo on."); + } else { + pm_relax(chip->dev); + chip->connected_ldo_on = false; + } +} + +static void p9415_check_ldo_on_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_p9415_ic *chip = + container_of(dwork, struct op_p9415_ic, check_ldo_on_work); + + chg_info("connected_ldo_on is : %s", chip->connected_ldo_on ? "true" : "false"); + if ((!chip->connected_ldo_on) + && p9415_get_idt_con_val(chip) == 1) { + chg_err("Connect but no ldo on event irq, check again."); + p9415_commu_data_process(chip); + } +} + +static void p9415_idt_event_shedule_work(void) +{ + if (normal_charger == NULL) { + pr_err("smbchg not ready\n"); + return; + } + + if (!g_p9415_chip) { + pr_err(" p9415_chip is NULL\n"); + } else { + schedule_delayed_work(&g_p9415_chip->idt_event_int_work, 0); + } +} + +static void p9415_idt_connect_shedule_work(void) +{ + if (normal_charger == NULL) { + pr_err("smbchg not ready\n"); + return; + } + + if (!g_p9415_chip) { + pr_err(" p9415_chip is NULL\n"); + } else { + schedule_delayed_work(&g_p9415_chip->idt_connect_int_work, 0); + } +} + +static irqreturn_t irq_idt_event_int_handler(int irq, void *dev_id) +{ + pr_err(" op-wlchg test irq happened\n"); + p9415_idt_event_shedule_work(); + return IRQ_HANDLED; +} + +static irqreturn_t irq_idt_connect_int_handler(int irq, void *dev_id) +{ + p9415_idt_connect_shedule_work(); + return IRQ_HANDLED; +} + +static int p9415_idt_int_eint_register(struct op_p9415_ic *chip) +{ + int retval = 0; + + p9415_set_idt_int_active(chip); + retval = devm_request_irq(chip->dev, chip->idt_int_irq, + irq_idt_event_int_handler, + IRQF_TRIGGER_FALLING, "p9415_idt_int", + chip); //0X01:rising edge, 0x02:falling edge + if (retval < 0) { + pr_err("%s request idt_int irq failed.\n", __func__); + } + return retval; +} + +static int p9415_idt_con_eint_register(struct op_p9415_ic *chip) +{ + int retval = 0; + + pr_err("%s op-wlchg test start, irq happened\n", __func__); + p9415_set_idt_con_active(chip); + retval = devm_request_irq(chip->dev, chip->idt_con_irq, + irq_idt_connect_int_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "p9415_con_int", + chip); //0X01:rising edge, 0x02:falling edge + if (retval < 0) { + pr_err("%s request idt_con irq failed.\n", __func__); + } + return retval; +} + +static int p9415_gpio_init(struct op_p9415_ic *chip) +{ + int rc = 0; + struct device_node *node = chip->dev->of_node; + + if (!node) { + pr_err("device tree node missing\n"); + return -EINVAL; + } + + // Parsing gpio idt_int + chip->idt_int_gpio = of_get_named_gpio(node, "qcom,idt_int-gpio", 0); + if (chip->idt_int_gpio < 0) { + pr_err("chip->idt_int_gpio not specified\n"); + return -EINVAL; + } else { + if (gpio_is_valid(chip->idt_int_gpio)) { + rc = gpio_request(chip->idt_int_gpio, "idt-idt-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", chip->idt_int_gpio); + goto free_gpio_1; + } else { + rc = p9415_idt_int_gpio_init(chip); + if (rc) { + pr_err("unable to init idt_int_gpio:%d\n", chip->idt_int_gpio); + goto free_gpio_1; + } else { + p9415_idt_int_irq_init(chip); + rc = p9415_idt_int_eint_register(chip); + if (rc < 0) { + pr_err("Init idt event irq failed."); + goto free_gpio_1; + } else { + enable_irq_wake(chip->idt_int_irq); + } + } + } + } + chg_debug("chip->idt_int_gpio =%d\n", chip->idt_int_gpio); + } + + // Parsing gpio idt_connect + chip->idt_con_gpio = + of_get_named_gpio(node, "qcom,idt_connect-gpio", 0); + if (chip->idt_con_gpio < 0) { + pr_err("chip->idt_con_gpio not specified\n"); + rc = -EINVAL; + goto free_gpio_1; + } else { + if (gpio_is_valid(chip->idt_con_gpio)) { + rc = gpio_request(chip->idt_con_gpio, + "idt-connect-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", + chip->idt_con_gpio); + goto free_gpio_1; + } else { + rc = p9415_idt_con_gpio_init(chip); + if (rc) { + pr_err("unable to init idt_con_gpio:%d\n", chip->idt_con_gpio); + goto free_gpio_2; + } else { + p9415_idt_con_irq_init(chip); + rc = p9415_idt_con_eint_register(chip); + if (rc < 0) { + pr_err("Init idt connect irq failed."); + goto free_gpio_2; + } else { + enable_irq_wake(chip->idt_con_irq); + } + } + } + } + chg_debug("chip->idt_con_gpio =%d\n", chip->idt_con_gpio); + } + + // Parsing gpio vbat_en + chip->vbat_en_gpio = of_get_named_gpio(node, "qcom,vbat_en-gpio", 0); + if (chip->vbat_en_gpio < 0) { + pr_err("chip->vbat_en_gpio not specified\n"); + rc = -EINVAL; + goto free_gpio_2; + } else { + if (gpio_is_valid(chip->vbat_en_gpio)) { + rc = gpio_request(chip->vbat_en_gpio, "vbat-en-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", chip->vbat_en_gpio); + goto free_gpio_2; + } else { + rc = p9415_vbat_en_gpio_init(chip); + if (rc) { + pr_err("unable to init vbat_en_gpio:%d\n", chip->vbat_en_gpio); + goto free_gpio_3; + } + } + } + chg_debug("chip->vbat_en_gpio =%d\n", chip->vbat_en_gpio); + } + + // Parsing gpio booster_en -- not use now. + chip->booster_en_gpio = of_get_named_gpio(node, "qcom,booster_en-gpio", 0); + if (chip->booster_en_gpio < 0) { + pr_err("chip->booster_en_gpio not specified\n"); + //rc = -EINVAL; + //goto free_gpio_3; + } else { + if (gpio_is_valid(chip->booster_en_gpio)) { + rc = gpio_request(chip->booster_en_gpio, + "booster-en-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", + chip->booster_en_gpio); + goto free_gpio_3; + } else { + rc = p9415_booster_en_gpio_init(chip); + if (rc) { + pr_err("unable to init booster_en_gpio:%d\n", + chip->booster_en_gpio); + goto free_gpio_4; + } + } + } + chg_debug("chip->booster_en_gpio =%d\n", chip->booster_en_gpio); + } + + // Parsing gpio idt_en + chip->idt_en_gpio = of_get_named_gpio(node, "qcom,idt_en-gpio", 0); + if (chip->idt_en_gpio < 0) { + pr_err("chip->idt_en_gpio not specified\n"); + rc = -EINVAL; + goto free_gpio_4; + } else { + if (gpio_is_valid(chip->idt_en_gpio)) { + rc = gpio_request(chip->idt_en_gpio, "idt_en-gpio"); + if (rc) { + pr_err("unable to request gpio [%d]\n", chip->idt_en_gpio); + goto free_gpio_4; + } else { + rc = p9415_idt_en_gpio_init(chip); + if (rc) { + pr_err("unable to init idt_en_gpio:%d\n", chip->idt_en_gpio); + goto free_gpio_5; + } + } + } + chg_debug("chip->idt_en_gpio =%d\n", chip->idt_en_gpio); + } + + return 0; + +free_gpio_5: + if (gpio_is_valid(chip->idt_en_gpio)) + gpio_free(chip->idt_en_gpio); +free_gpio_4: + if (gpio_is_valid(chip->booster_en_gpio)) + gpio_free(chip->booster_en_gpio); +free_gpio_3: + if (gpio_is_valid(chip->vbat_en_gpio)) + gpio_free(chip->vbat_en_gpio); +free_gpio_2: + if (gpio_is_valid(chip->idt_con_gpio)) + gpio_free(chip->idt_con_gpio); +free_gpio_1: + if (gpio_is_valid(chip->idt_int_gpio)) + gpio_free(chip->idt_int_gpio); + return rc; +} + +static void p9415_update_work_process(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_p9415_ic *chip = + container_of(dwork, struct op_p9415_ic, p9415_update_work); + int rc = 0; + static int retrycount; + int boot_mode = get_boot_mode(); + + if (!chip) { + pr_err(" op_p9415_ic not ready!\n"); + return; + } + + if (boot_mode == MSM_BOOT_MODE_FACTORY) { + pr_err(" MSM_BOOT_MODE__FACTORY do not update\n"); + p9415_set_vbat_en_val(chip, 1); + msleep(500); + p9415_set_vbat_en_val(chip, 0); + return; + } + + pr_err(" p9415_update_work_process\n"); + + if (!chip->check_fw_update) { + if (wlchg_get_usbin_val() == 0) { + __pm_stay_awake(chip->update_fw_wake_lock); + rc = p9415_check_idt_fw_update(chip); + __pm_relax(chip->update_fw_wake_lock); + } else { + pr_err(" usb cable is in, retry later.!\n"); + p9415_set_vbat_en_val(chip, 1); + rc = -1; + } + if (rc) { + /* run again after interval */ + retrycount++; + schedule_delayed_work(&chip->p9415_update_work, p9415_UPDATE_INTERVAL); + pr_err("update fw failed, retry %d!", retrycount); + return; + } + } + + if (boot_mode != MSM_BOOT_MODE_CHARGE) { + p9415_set_vbat_en_val(chip, 1); + msleep(500); + p9415_set_vbat_en_val(chip, 0); + } +} + +#ifdef OP_DEBUG +#define UPGRADE_START 0 +#define UPGRADE_FW 1 +#define UPGRADE_END 2 +struct idt_fw_head { + u8 magic[4]; + int size; +}; +static ssize_t p9415_upgrade_firmware_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + u8 temp_buf[sizeof(struct idt_fw_head)]; + int rc = 0; + static u8 *fw_buf; + static int upgrade_step = UPGRADE_START; + static int fw_index; + static int fw_size; + struct idt_fw_head *fw_head; + struct i2c_client *client; + struct rx_chip *rx_chip; + struct op_p9415_ic *chip; + + client = container_of(dev, struct i2c_client, dev); + rx_chip = i2c_get_clientdata(client); + chip = rx_chip->prop->private_data; + +start: + switch (upgrade_step) { + case UPGRADE_START: + if (count < sizeof(struct idt_fw_head)) { + pr_err("image format error\n"); + return -EINVAL; + } + memset(temp_buf, 0, sizeof(struct idt_fw_head)); + memcpy(temp_buf, buf, sizeof(struct idt_fw_head)); + fw_head = (struct idt_fw_head *)temp_buf; + if (fw_head->magic[0] == 0x02 && fw_head->magic[1] == 0x00 && + fw_head->magic[2] == 0x03 && fw_head->magic[3] == 0x00) { + fw_size = fw_head->size; + fw_buf = kzalloc(fw_size, GFP_KERNEL); + if (fw_buf == NULL) { + pr_err("alloc fw_buf err\n"); + return -ENOMEM; + } + pr_err("image header verification succeeded, fw_size=%d\n", fw_size); + memcpy(fw_buf, buf + sizeof(struct idt_fw_head), count - sizeof(struct idt_fw_head)); + fw_index = count - sizeof(struct idt_fw_head); + pr_info("Receiving image, fw_size=%d, fw_index=%d\n", fw_size, fw_index); + if (fw_index >= fw_size) { + upgrade_step = UPGRADE_END; + goto start; + } else { + upgrade_step = UPGRADE_FW; + } + } else { + pr_err("image format error\n"); + return -EINVAL; + } + break; + case UPGRADE_FW: + memcpy(fw_buf + fw_index, buf, count); + fw_index += count; + pr_info("Receiving image, fw_size=%d, fw_index=%d\n", fw_size, fw_index); + if (fw_index >= fw_size) { + upgrade_step = UPGRADE_END; + goto start; + } + break; + case UPGRADE_END: + rc = p9415_upgrade_firmware(chip, fw_buf, fw_size); + kfree(fw_buf); + fw_buf = NULL; + upgrade_step = UPGRADE_START; + if (rc < 0) + return rc; + break; + default: + upgrade_step = UPGRADE_START; + pr_err("status error\n"); + if (fw_buf != NULL) { + kfree(fw_buf); + fw_buf = NULL; + } + break; + } + + return count; +} + +static DEVICE_ATTR(upgrade_firmware, S_IWUSR, NULL, p9415_upgrade_firmware_store); + +static struct attribute *p9415_sysfs_attrs[] = { + &dev_attr_upgrade_firmware.attr, + NULL +}; + +static struct attribute_group p9415_attribute_group = { + .attrs = p9415_sysfs_attrs +}; + +#endif + +static int p9415_driver_probe(struct platform_device *pdev) +{ + struct op_p9415_ic *chip; + int ret = 0; + + chg_debug(" call \n"); + + chip = devm_kzalloc(&pdev->dev, sizeof(struct op_p9415_ic), + GFP_KERNEL); + if (!chip) { + pr_err(" kzalloc() failed\n"); + return -ENOMEM; + } + + g_p9415_chip = chip; + chip->dev = &pdev->dev; + chip->client = container_of(chip->dev->parent, struct i2c_client, dev); + chip->rx_chip = i2c_get_clientdata(chip->client); + + platform_set_drvdata(pdev, chip); + +#ifdef OP_DEBUG + ret = sysfs_create_group(&chip->dev->parent->kobj, &p9415_attribute_group); + if (ret) + goto free_platform_drvdata; +#endif + + ret = p9415_gpio_init(chip); + if (ret) { + pr_err("p9415 gpio init error."); + goto free_sysfs_group; + } + + device_init_wakeup(chip->dev, true); + + p9415_prop.private_data = chip; + wlchg_rx_register_prop(chip->dev->parent, &p9415_prop); + + INIT_DELAYED_WORK(&chip->idt_event_int_work, p9415_event_int_func); + INIT_DELAYED_WORK(&chip->idt_connect_int_work, p9415_connect_int_func); + INIT_DELAYED_WORK(&chip->p9415_update_work, p9415_update_work_process); + INIT_DELAYED_WORK(&chip->check_ldo_on_work, p9415_check_ldo_on_func); + chip->update_fw_wake_lock = wakeup_source_register(chip->dev, "p9415_update_fw_wake_lock"); + + if (get_boot_mode() == MSM_BOOT_MODE_CHARGE) { + schedule_delayed_work(&chip->idt_connect_int_work, msecs_to_jiffies(5000)); + } else { + schedule_delayed_work(&chip->p9415_update_work, p9415_UPDATE_INTERVAL); + } + + chg_debug("call end\n"); + return 0; + +free_sysfs_group: +#ifdef OP_DEBUG + sysfs_remove_group(&chip->dev->parent->kobj, &p9415_attribute_group); +free_platform_drvdata: +#endif + platform_set_drvdata(pdev, NULL); + return ret; +} + +static int p9415_driver_remove(struct platform_device *pdev) +{ + struct op_p9415_ic *chip = platform_get_drvdata(pdev); + + if (gpio_is_valid(chip->idt_en_gpio)) + gpio_free(chip->idt_en_gpio); + if (gpio_is_valid(chip->booster_en_gpio)) + gpio_free(chip->booster_en_gpio); + if (gpio_is_valid(chip->vbat_en_gpio)) + gpio_free(chip->vbat_en_gpio); + if (gpio_is_valid(chip->idt_con_gpio)) + gpio_free(chip->idt_con_gpio); + if (gpio_is_valid(chip->idt_int_gpio)) + gpio_free(chip->idt_int_gpio); +#ifdef OP_DEBUG + sysfs_remove_group(&chip->dev->parent->kobj, &p9415_attribute_group); +#endif + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +static int p9415_pm_resume(struct device *dev) +{ + return 0; +} + +static int p9415_pm_suspend(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops p9415_pm_ops = { + .resume = p9415_pm_resume, + .suspend = p9415_pm_suspend, +}; +#else +static int p9415_resume(struct i2c_client *client) +{ + return 0; +} + +static int p9415_suspend(struct i2c_client *client, pm_message_t mesg) +{ + return 0; +} +#endif + +static const struct of_device_id p9415_match[] = { + { .compatible = "op,p9415-charger" }, + {}, +}; + +static struct platform_driver p9415_driver = { + .driver = { + .name = "p9415-charger", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(p9415_match), +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + .pm = &p9415_pm_ops, +#endif + }, + .probe = p9415_driver_probe, + .remove = p9415_driver_remove, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) + .resume = p9415_resume, + .suspend = p9415_suspend, +#endif +}; + +module_platform_driver(p9415_driver); +MODULE_DESCRIPTION("Driver for p9415 charger chip"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("p9415-charger"); diff --git a/drivers/oneplus/power/supply/wlchg/op_p9415.h b/drivers/oneplus/power/supply/wlchg/op_p9415.h new file mode 100644 index 0000000000000000000000000000000000000000..7e9d0d220e19f29068397905c29f853d61050b62 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_p9415.h @@ -0,0 +1,56 @@ +#ifndef __OP_P9415_H__ +#define __OP_P9415_H__ + +#define p9415_UPDATE_INTERVAL round_jiffies_relative(msecs_to_jiffies(5000)) +#define p9415_CHECK_LDO_ON_DELAY round_jiffies_relative(msecs_to_jiffies(2000)) + +#define P9415_STATUS_REG 0x0036 +#define P9415_VOUT_ERR_MASK BIT(3) +#define P9415_EVENT_MASK BIT(4) +#define P9415_LDO_ON_MASK BIT(6) + +struct op_p9415_ic { + struct i2c_client *client; + struct device *dev; + struct rx_chip *rx_chip; + + int idt_en_gpio; + int idt_con_gpio; + int idt_con_irq; + int idt_int_gpio; + int idt_int_irq; + int vbat_en_gpio; + int booster_en_gpio; + + bool idt_fw_updating; + bool check_fw_update; + bool connected_ldo_on; + + char fw_id[16]; + char manu_name[16]; + + struct pinctrl *pinctrl; + struct pinctrl_state *idt_en_active; + struct pinctrl_state *idt_en_sleep; + struct pinctrl_state *idt_en_default; + struct pinctrl_state *idt_con_active; + struct pinctrl_state *idt_con_sleep; + struct pinctrl_state *idt_con_default; + struct pinctrl_state *idt_int_active; + struct pinctrl_state *idt_int_sleep; + struct pinctrl_state *idt_int_default; + struct pinctrl_state *vbat_en_active; + struct pinctrl_state *vbat_en_sleep; + struct pinctrl_state *vbat_en_default; + struct pinctrl_state *booster_en_active; + struct pinctrl_state *booster_en_sleep; + struct pinctrl_state *booster_en_default; + + struct delayed_work p9415_update_work; + struct delayed_work idt_event_int_work; + struct delayed_work idt_connect_int_work; + struct delayed_work check_ldo_on_work; + struct wakeup_source *update_fw_wake_lock; +}; + +#endif \ No newline at end of file diff --git a/drivers/oneplus/power/supply/wlchg/op_p9415_fw.h b/drivers/oneplus/power/supply/wlchg/op_p9415_fw.h new file mode 100644 index 0000000000000000000000000000000000000000..0092c568420ea47c6f59812a7bb4d2ee1ab5ee49 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_p9415_fw.h @@ -0,0 +1,1662 @@ +#ifndef __OP_P922X_FW_H__ +#define __OP_P922X_FW_H__ + +/* MTP downloader code for powering P9415 at Vout */ +/* version: 0.7 */ +unsigned char MTPBootloader9320[] = { + 0x00, 0x02, 0x00, 0x20, 0x99, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0x02, 0xF8, 0x00, 0xF0, 0x30, 0xF8, 0x0C, 0xA0, 0x30, 0xC8, 0x08, 0x38, 0x24, 0x18, + 0x2D, 0x18, 0xA2, 0x46, 0x67, 0x1E, 0xAB, 0x46, 0x54, 0x46, 0x5D, 0x46, 0xAC, 0x42, 0x01, 0xD1, + 0x00, 0xF0, 0x22, 0xF8, 0x7E, 0x46, 0x0F, 0x3E, 0x0F, 0xCC, 0xB6, 0x46, 0x01, 0x26, 0x33, 0x42, + 0x00, 0xD0, 0xFB, 0x1A, 0xA2, 0x46, 0xAB, 0x46, 0x33, 0x43, 0x18, 0x47, 0xA8, 0x06, 0x00, 0x00, + 0xB8, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x10, 0x3A, 0x01, 0xD3, + 0x78, 0xC1, 0xFB, 0xD8, 0x52, 0x07, 0x00, 0xD3, 0x30, 0xC1, 0x00, 0xD5, 0x0B, 0x60, 0x70, 0x47, + 0x1F, 0xB5, 0x1F, 0xBD, 0x10, 0xB5, 0x10, 0xBD, 0x00, 0xF0, 0x09, 0xFB, 0x11, 0x46, 0xFF, 0xF7, + 0xF7, 0xFF, 0x00, 0xF0, 0x45, 0xFA, 0x00, 0xF0, 0x21, 0xFB, 0x03, 0xB4, 0xFF, 0xF7, 0xF2, 0xFF, + 0x03, 0xBC, 0x00, 0xF0, 0x27, 0xFB, 0x00, 0x00, 0x05, 0x48, 0x00, 0x47, 0xFE, 0xE7, 0xFE, 0xE7, + 0xFE, 0xE7, 0x00, 0x00, 0x03, 0x48, 0x04, 0x49, 0x02, 0x4A, 0x04, 0x4B, 0x70, 0x47, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x20, 0x60, 0x01, 0x00, 0x20, 0x60, 0x00, 0x00, 0x20, + 0xFE, 0xB5, 0x04, 0x46, 0x00, 0x20, 0x02, 0x90, 0x10, 0x20, 0x20, 0x40, 0x00, 0x28, 0x64, 0xD0, + 0x01, 0x20, 0xFA, 0x4E, 0x30, 0x80, 0x80, 0x1E, 0x30, 0x81, 0x01, 0x46, 0xF8, 0x4E, 0x31, 0x83, + 0x08, 0x0C, 0x70, 0x83, 0x00, 0x22, 0x44, 0xE0, 0xF6, 0x48, 0x40, 0x88, 0x80, 0x18, 0x83, 0xB2, + 0x01, 0x93, 0xD8, 0x13, 0x00, 0x28, 0x03, 0xD1, 0x01, 0x20, 0xC0, 0x03, 0x18, 0x43, 0x01, 0x90, + 0xEF, 0x48, 0xC2, 0x81, 0x03, 0x80, 0xEE, 0x4E, 0x01, 0x98, 0x70, 0x80, 0x01, 0x98, 0x05, 0x78, + 0xEA, 0x48, 0x85, 0x80, 0x30, 0x46, 0x85, 0x80, 0x30, 0x20, 0x20, 0x40, 0x10, 0x28, 0x07, 0xD1, + 0x00, 0xBF, 0xE6, 0x48, 0x00, 0x88, 0x40, 0x06, 0xC0, 0x0F, 0x00, 0x28, 0xF9, 0xD1, 0x1E, 0xE0, + 0x00, 0x20, 0x00, 0x90, 0x18, 0xE0, 0xC8, 0x0F, 0x07, 0x27, 0x00, 0x9E, 0xBE, 0x1B, 0x2F, 0x46, + 0x37, 0x41, 0xFE, 0x07, 0xF6, 0x0F, 0x70, 0x40, 0x00, 0x28, 0x01, 0xD0, 0xDE, 0x48, 0x00, 0xE0, + 0x00, 0x20, 0x4E, 0x00, 0x70, 0x40, 0x01, 0x46, 0xD9, 0x4E, 0x31, 0x83, 0x08, 0x0C, 0x70, 0x83, + 0x00, 0x98, 0x40, 0x1C, 0xC0, 0xB2, 0x00, 0x90, 0x00, 0x98, 0x07, 0x28, 0xE3, 0xDD, 0x50, 0x1C, + 0x82, 0xB2, 0xD4, 0x48, 0x80, 0x88, 0x90, 0x42, 0xB6, 0xDC, 0x30, 0x20, 0x20, 0x40, 0x10, 0x28, + 0x13, 0xD1, 0xCE, 0x48, 0x00, 0x89, 0xCE, 0x4E, 0x70, 0x82, 0xCC, 0x48, 0x00, 0x89, 0xCD, 0x4E, + 0xF6, 0x88, 0xB0, 0x42, 0x02, 0xD1, 0x00, 0x20, 0x02, 0x90, 0x2F, 0xE0, 0x01, 0x20, 0x02, 0x90, + 0xC6, 0x48, 0x00, 0x89, 0xC7, 0x4E, 0xF0, 0x80, 0x28, 0xE0, 0x88, 0xB2, 0xC5, 0x4E, 0xF6, 0x88, + 0xB0, 0x42, 0x01, 0xD1, 0x01, 0x20, 0x00, 0xE0, 0x00, 0x20, 0x0E, 0x02, 0x36, 0x0E, 0xC1, 0x4F, + 0x3F, 0x7A, 0xBE, 0x42, 0x01, 0xD1, 0x01, 0x26, 0x00, 0xE0, 0x00, 0x26, 0x30, 0x40, 0x0E, 0x0E, + 0xBC, 0x4F, 0x7F, 0x7A, 0xBE, 0x42, 0x01, 0xD1, 0x01, 0x26, 0x00, 0xE0, 0x00, 0x26, 0x30, 0x40, + 0x00, 0x28, 0x02, 0xD0, 0x00, 0x20, 0x02, 0x90, 0x08, 0xE0, 0x01, 0x20, 0x02, 0x90, 0xB5, 0x4E, + 0xF1, 0x80, 0x08, 0x02, 0x00, 0x0E, 0x30, 0x72, 0x08, 0x0E, 0x70, 0x72, 0x02, 0x98, 0xFE, 0xBD, + 0x10, 0xB5, 0x02, 0x46, 0xAE, 0x4B, 0x1B, 0x8A, 0x04, 0x24, 0x23, 0x43, 0xAC, 0x4C, 0x23, 0x82, + 0x00, 0x23, 0xAE, 0x4C, 0xA3, 0x81, 0x93, 0x00, 0x19, 0x60, 0xAD, 0x4B, 0x1B, 0x88, 0xA4, 0x14, + 0x23, 0x40, 0x18, 0x46, 0xA6, 0x4B, 0x1B, 0x8A, 0x04, 0x24, 0xA3, 0x43, 0xA4, 0x4C, 0x23, 0x82, + 0xA8, 0x4B, 0xA6, 0x4C, 0xA3, 0x81, 0x10, 0xBD, 0x10, 0xB5, 0x02, 0x46, 0xA0, 0x4B, 0x1B, 0x8A, + 0x02, 0x24, 0x23, 0x43, 0x9E, 0x4C, 0x23, 0x82, 0x00, 0x23, 0xA0, 0x4C, 0xA3, 0x81, 0x11, 0x70, + 0x9F, 0x4B, 0x1B, 0x88, 0xA4, 0x14, 0x23, 0x40, 0x18, 0x46, 0x99, 0x4B, 0x1B, 0x8A, 0x02, 0x24, + 0xA3, 0x43, 0x97, 0x4C, 0x23, 0x82, 0x9B, 0x4B, 0x98, 0x4C, 0xA3, 0x81, 0x10, 0xBD, 0xF1, 0xB5, + 0x88, 0xB0, 0x08, 0x9D, 0x00, 0x20, 0x00, 0x90, 0x91, 0x48, 0x00, 0x8A, 0x08, 0x21, 0x88, 0x43, + 0x8F, 0x49, 0x08, 0x82, 0x8F, 0x48, 0x00, 0x88, 0x00, 0x07, 0x00, 0x0F, 0x03, 0x90, 0x8D, 0x48, + 0x40, 0x88, 0x02, 0x90, 0x8B, 0x48, 0x80, 0x88, 0x01, 0x90, 0x01, 0x99, 0x02, 0x98, 0x40, 0x18, + 0x40, 0x1E, 0x80, 0xB2, 0x05, 0x90, 0x05, 0x98, 0xC0, 0x13, 0x00, 0x28, 0x04, 0xD1, 0x01, 0x21, + 0xC9, 0x03, 0x05, 0x98, 0x08, 0x43, 0x05, 0x90, 0x02, 0x98, 0x07, 0x90, 0x01, 0x99, 0x07, 0x98, + 0x40, 0x18, 0x80, 0xB2, 0x07, 0x90, 0x00, 0x27, 0x08, 0xE0, 0x7E, 0x48, 0x08, 0x30, 0xC1, 0x5D, + 0x07, 0x98, 0x08, 0x18, 0x80, 0xB2, 0x07, 0x90, 0x78, 0x1C, 0x87, 0xB2, 0x01, 0x98, 0x87, 0x42, + 0xF3, 0xDB, 0x77, 0x49, 0x07, 0x98, 0x48, 0x82, 0x76, 0x48, 0xC1, 0x88, 0x07, 0x98, 0x81, 0x42, + 0x73, 0xD1, 0x03, 0x98, 0x01, 0x28, 0x01, 0xD1, 0x00, 0x20, 0x0C, 0xE0, 0x03, 0x98, 0x03, 0x28, + 0x01, 0xD1, 0x04, 0x20, 0x07, 0xE0, 0x03, 0x98, 0x05, 0x28, 0x01, 0xD1, 0x24, 0x20, 0x02, 0xE0, + 0x6F, 0x48, 0x20, 0x30, 0x00, 0x89, 0x6E, 0x49, 0x20, 0x31, 0x08, 0x81, 0x00, 0x27, 0xBE, 0xE0, + 0x02, 0x98, 0xC0, 0x19, 0x80, 0xB2, 0x06, 0x90, 0x30, 0x0A, 0x66, 0x49, 0x08, 0x31, 0xC9, 0x5D, + 0x09, 0x06, 0x08, 0x43, 0x06, 0x46, 0x06, 0x9C, 0x61, 0x48, 0xC7, 0x81, 0x60, 0x49, 0x06, 0x98, + 0x08, 0x80, 0x30, 0x0C, 0xC8, 0x80, 0x8E, 0x80, 0x06, 0x98, 0xC0, 0x13, 0x00, 0x28, 0x03, 0xD1, + 0x89, 0x13, 0x06, 0x98, 0x08, 0x43, 0x04, 0x46, 0x04, 0x98, 0x00, 0x0A, 0x21, 0x78, 0x09, 0x06, + 0x08, 0x43, 0x04, 0x90, 0x56, 0x48, 0x44, 0x80, 0x04, 0x98, 0x00, 0x0C, 0x54, 0x49, 0x48, 0x81, + 0x04, 0x98, 0x08, 0x81, 0x03, 0x98, 0x01, 0x28, 0x02, 0xD0, 0x03, 0x98, 0x03, 0x28, 0x16, 0xD1, + 0x04, 0x98, 0x00, 0x0E, 0x31, 0x0E, 0x88, 0x42, 0x0D, 0xD0, 0x31, 0x0E, 0x20, 0x46, 0xFF, 0xF7, + 0x53, 0xFF, 0x00, 0x28, 0x08, 0xD1, 0x20, 0x78, 0x04, 0x90, 0x31, 0x0E, 0x04, 0x98, 0x81, 0x42, + 0x79, 0xD0, 0x68, 0x1C, 0x85, 0xB2, 0x76, 0xE0, 0x68, 0x1C, 0x85, 0xB2, 0x73, 0xE0, 0x03, 0x98, + 0x05, 0x28, 0x70, 0xD1, 0xA0, 0x07, 0x80, 0x0F, 0x00, 0x28, 0x07, 0xD1, 0x01, 0x20, 0x00, 0x90, + 0x3F, 0x48, 0x00, 0x8A, 0x08, 0x21, 0x08, 0x43, 0x3D, 0x49, 0x08, 0x82, 0x42, 0x49, 0x05, 0x98, + 0x08, 0x40, 0xA0, 0x42, 0x02, 0xD1, 0x01, 0x20, 0x01, 0xE0, 0x65, 0xE0, 0x00, 0x20, 0x05, 0x99, + 0x89, 0x07, 0x89, 0x0F, 0x03, 0x29, 0x01, 0xD0, 0x01, 0x21, 0x00, 0xE0, 0x00, 0x21, 0x08, 0x40, + 0x00, 0x28, 0x07, 0xD0, 0x00, 0x20, 0x00, 0x90, 0x31, 0x48, 0x00, 0x8A, 0x08, 0x21, 0x88, 0x43, + 0x2F, 0x49, 0x08, 0x82, 0x00, 0x98, 0x00, 0x28, 0x20, 0xD1, 0x31, 0x48, 0x20, 0x30, 0x00, 0x89, + 0x20, 0x21, 0x88, 0x43, 0x2E, 0x49, 0x20, 0x31, 0x08, 0x81, 0x08, 0x46, 0x00, 0x89, 0x04, 0x21, + 0x08, 0x43, 0x2B, 0x49, 0x20, 0x31, 0x08, 0x81, 0x31, 0x0E, 0x20, 0x46, 0xFF, 0xF7, 0x04, 0xFF, + 0x00, 0x28, 0x08, 0xD1, 0x20, 0x78, 0x04, 0x90, 0x31, 0x0E, 0x04, 0x98, 0x81, 0x42, 0x2A, 0xD0, + 0x68, 0x1C, 0x85, 0xB2, 0x27, 0xE0, 0x68, 0x1C, 0x85, 0xB2, 0x24, 0xE0, 0xA0, 0x07, 0x80, 0x0F, + 0x03, 0x28, 0x20, 0xD1, 0x1E, 0x48, 0x20, 0x30, 0x00, 0x89, 0x20, 0x21, 0x08, 0x43, 0x1C, 0x49, + 0x20, 0x31, 0x08, 0x81, 0x08, 0x46, 0x00, 0x89, 0x04, 0x21, 0x08, 0x43, 0x18, 0x49, 0x20, 0x31, + 0x08, 0x81, 0xA0, 0x10, 0x31, 0x46, 0xFF, 0xF7, 0xC3, 0xFE, 0x00, 0x28, 0x09, 0xD1, 0xA0, 0x10, + 0x80, 0x00, 0x00, 0x68, 0x04, 0x90, 0x04, 0x98, 0xB0, 0x42, 0x04, 0xD0, 0x28, 0x1D, 0x85, 0xB2, + 0x01, 0xE0, 0x28, 0x1D, 0x85, 0xB2, 0x0A, 0x48, 0x85, 0x81, 0x78, 0x1C, 0x87, 0xB2, 0x01, 0x98, + 0x87, 0x42, 0x00, 0xDA, 0x3C, 0xE7, 0x06, 0xE0, 0x06, 0x48, 0x80, 0x88, 0x40, 0x19, 0x85, 0xB2, + 0x01, 0x20, 0xC0, 0x03, 0x05, 0x43, 0x28, 0x46, 0x09, 0xB0, 0xF0, 0xBD, 0x00, 0x70, 0x00, 0x40, + 0x00, 0x05, 0x00, 0x20, 0x00, 0x04, 0x00, 0x20, 0xB7, 0x1D, 0xC1, 0x04, 0x40, 0x30, 0x00, 0x40, + 0x00, 0x5C, 0x00, 0x40, 0xFF, 0x1F, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x0C, 0xB5, 0x00, 0x21, + 0x01, 0x91, 0x10, 0xE0, 0x00, 0x21, 0x00, 0x91, 0x04, 0xE0, 0x69, 0x46, 0x09, 0x88, 0x49, 0x1C, + 0x8A, 0xB2, 0x00, 0x92, 0x69, 0x46, 0x09, 0x88, 0x02, 0x29, 0xF6, 0xDB, 0x69, 0x46, 0x89, 0x88, + 0x49, 0x1C, 0x8A, 0xB2, 0x01, 0x92, 0x69, 0x46, 0x89, 0x88, 0x81, 0x42, 0xEA, 0xDB, 0x0C, 0xBD, + 0x5A, 0x20, 0x53, 0x49, 0x08, 0x80, 0x05, 0x20, 0x88, 0x80, 0x04, 0x20, 0x08, 0x81, 0x51, 0x48, + 0x88, 0x81, 0x50, 0x20, 0xFF, 0xF7, 0xDA, 0xFF, 0x4F, 0x48, 0x4D, 0x49, 0x88, 0x82, 0x4F, 0x48, + 0x08, 0x82, 0x18, 0x20, 0x88, 0x83, 0x08, 0x46, 0x00, 0x8B, 0x17, 0x21, 0x49, 0x02, 0x08, 0x43, + 0x47, 0x49, 0x08, 0x83, 0x08, 0x46, 0x00, 0x8B, 0x2E, 0x21, 0x08, 0x43, 0x44, 0x49, 0x08, 0x83, + 0x05, 0x20, 0xFF, 0xF7, 0xC3, 0xFF, 0x42, 0x48, 0x80, 0x8B, 0x01, 0x21, 0x08, 0x43, 0x40, 0x49, + 0x88, 0x83, 0x32, 0x20, 0x42, 0x49, 0x08, 0x80, 0x94, 0x20, 0x42, 0x49, 0x08, 0x80, 0x15, 0x20, + 0x08, 0x80, 0x08, 0x46, 0x80, 0x8A, 0x60, 0x21, 0x88, 0x43, 0x3E, 0x49, 0x88, 0x82, 0x00, 0x20, + 0x3D, 0x49, 0x08, 0x80, 0x3D, 0x49, 0x08, 0x80, 0x48, 0x80, 0x00, 0x24, 0x00, 0x27, 0x01, 0x25, + 0x00, 0x26, 0x06, 0xE0, 0x00, 0x20, 0x71, 0x00, 0x39, 0x4A, 0x89, 0x18, 0x08, 0x80, 0x70, 0x1C, + 0x86, 0xB2, 0x10, 0x2E, 0xF6, 0xDB, 0x5A, 0xE0, 0x34, 0x48, 0x00, 0x88, 0xC0, 0x07, 0xC0, 0x0F, + 0x00, 0x28, 0x54, 0xD0, 0x31, 0x48, 0x00, 0x88, 0xC0, 0xB2, 0x30, 0x49, 0x08, 0x80, 0x5A, 0x20, + 0x30, 0x49, 0x08, 0x82, 0x00, 0x20, 0x26, 0x49, 0x60, 0x31, 0x08, 0x80, 0x2B, 0x48, 0x00, 0x88, + 0x11, 0x21, 0x08, 0x40, 0x01, 0x28, 0x27, 0xD1, 0x01, 0x25, 0x28, 0x48, 0x00, 0x88, 0xC0, 0xB2, + 0x29, 0x02, 0x08, 0x43, 0x25, 0x49, 0x08, 0x80, 0x25, 0x48, 0x00, 0x8A, 0x01, 0x21, 0x08, 0x43, + 0x23, 0x49, 0x08, 0x82, 0x00, 0x20, 0xFF, 0xF7, 0x3A, 0xFE, 0x04, 0x46, 0x20, 0x48, 0x00, 0x8A, + 0xA8, 0x43, 0x1F, 0x49, 0x08, 0x82, 0x60, 0x04, 0x40, 0x0C, 0xC0, 0x19, 0x87, 0xB2, 0x88, 0x13, + 0x20, 0x40, 0x00, 0x28, 0x01, 0xD0, 0x08, 0x20, 0x04, 0xE0, 0x00, 0x2C, 0x01, 0xD0, 0x04, 0x20, + 0x00, 0xE0, 0x02, 0x20, 0x05, 0x46, 0x11, 0xE0, 0x01, 0x25, 0x14, 0x48, 0x00, 0x88, 0xC0, 0xB2, + 0x29, 0x02, 0x08, 0x43, 0x11, 0x49, 0x08, 0x80, 0x08, 0x88, 0xFF, 0xF7, 0x41, 0xFD, 0x04, 0x46, + 0x00, 0x2C, 0x01, 0xD0, 0x08, 0x20, 0x00, 0xE0, 0x02, 0x20, 0x05, 0x46, 0x0B, 0x48, 0x47, 0x80, + 0x00, 0x88, 0xFE, 0x21, 0x08, 0x40, 0x29, 0x02, 0x08, 0x43, 0x08, 0x49, 0x08, 0x80, 0xA3, 0xE7, + 0x00, 0x30, 0x00, 0x40, 0x01, 0x04, 0x00, 0x00, 0x0A, 0x20, 0x00, 0x00, 0xFF, 0x07, 0x00, 0x00, + 0x40, 0x54, 0x00, 0x40, 0x00, 0x58, 0x00, 0x40, 0x40, 0x6C, 0x00, 0x40, 0x00, 0x04, 0x00, 0x20, + 0x00, 0x05, 0x00, 0x20, 0x40, 0x5C, 0x00, 0x40, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x75, 0x46, + 0x00, 0xF0, 0x24, 0xF8, 0xAE, 0x46, 0x05, 0x00, 0x69, 0x46, 0x53, 0x46, 0xC0, 0x08, 0xC0, 0x00, + 0x85, 0x46, 0x18, 0xB0, 0x20, 0xB5, 0xFF, 0xF7, 0xFD, 0xFC, 0x60, 0xBC, 0x00, 0x27, 0x49, 0x08, + 0xB6, 0x46, 0x00, 0x26, 0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5, 0xC0, 0xC5, + 0xC0, 0xC5, 0xC0, 0xC5, 0x40, 0x3D, 0x49, 0x00, 0x8D, 0x46, 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, + 0xC0, 0x46, 0xC0, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0xD8, 0xFC, 0x10, 0xBD, 0x00, 0x48, 0x70, 0x47, + 0x00, 0x00, 0x00, 0x20, 0x01, 0x49, 0x18, 0x20, 0xAB, 0xBE, 0xFE, 0xE7, 0x26, 0x00, 0x02, 0x00, + 0x70, 0x47, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, 0x01, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00 +}; + +// P9415-3_v4.3.5.41 +unsigned char idt_firmware[] = { /// 0x00 + 0x00, 0x08, 0x00, 0x20, 0xe9, 0x03, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, /// 0x10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, /// 0x30 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x40 + 0x1d, 0x11, 0x00, 0x00, 0x23, 0x11, 0x00, 0x00, 0x29, 0x11, 0x00, 0x00, 0x2f, 0x11, 0x00, 0x00, /// 0x50 + 0x35, 0x11, 0x00, 0x00, 0x3b, 0x11, 0x00, 0x00, 0x41, 0x11, 0x00, 0x00, 0x47, 0x11, 0x00, 0x00, /// 0x60 + 0x4d, 0x11, 0x00, 0x00, 0x53, 0x11, 0x00, 0x00, 0x59, 0x11, 0x00, 0x00, 0x5f, 0x11, 0x00, 0x00, /// 0x70 + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0x00, 0x20, 0x00, 0x68, 0x80, 0xf3, /// 0x80 + 0x08, 0x88, 0x70, 0x47, 0xf0, 0x48, 0x00, 0x21, 0x01, 0x72, 0x41, 0x72, 0x70, 0x47, 0x10, 0xb5, /// 0x90 + 0xed, 0x4b, 0x1a, 0x7a, 0x5c, 0x7a, 0x51, 0x1c, 0x09, 0x07, 0x09, 0x0f, 0x8c, 0x42, 0x01, 0xd1, /// 0xa0 + 0x01, 0x20, 0x10, 0xbd, 0xe9, 0x4c, 0x92, 0x00, 0x12, 0x19, 0xff, 0x32, 0x01, 0x32, 0x90, 0x60, /// 0xb0 + 0x19, 0x72, 0x00, 0x20, 0x10, 0xbd, 0xe5, 0x4e, 0x34, 0x46, 0xff, 0x34, 0x41, 0x34, 0x21, 0x7a, /// 0xc0 + 0x60, 0x7a, 0x81, 0x42, 0x01, 0xd1, 0x30, 0xbf, 0xf9, 0xe7, 0x81, 0x00, 0x89, 0x19, 0xff, 0x31, /// 0xd0 + 0x01, 0x31, 0x8d, 0x68, 0x00, 0x2d, 0x0c, 0xd0, 0x40, 0x1c, 0x00, 0x07, 0x00, 0x0f, 0x60, 0x72, /// 0xe0 + 0xa8, 0x47, 0x00, 0x28, 0xeb, 0xd0, 0x72, 0xb6, 0x28, 0x46, 0xff, 0xf7, 0xd0, 0xff, 0x62, 0xb6, /// 0xf0 + 0xe5, 0xe7, 0xff, 0xf7, 0xc7, 0xff, 0xe2, 0xe7, 0xd6, 0x49, 0xd5, 0x48, 0x08, 0x60, 0xff, 0xf7, /// 0x100 + 0xbc, 0xff, 0xd5, 0x4c, 0x5a, 0x20, 0x20, 0x70, 0x00, 0x25, 0x25, 0x71, 0x09, 0x20, 0x20, 0x72, /// 0x110 + 0xd2, 0x48, 0xa0, 0x81, 0xd1, 0x48, 0xfb, 0x38, 0xa0, 0x82, 0x63, 0x20, 0x00, 0x01, 0x20, 0x83, /// 0x120 + 0xa0, 0x8a, 0x61, 0x14, 0x08, 0x43, 0xa0, 0x82, 0x01, 0x26, 0x26, 0x82, 0x4d, 0x20, 0x00, 0x01, /// 0x130 + 0xa0, 0x83, 0x14, 0x20, 0x00, 0xf0, 0x9f, 0xfc, 0xa0, 0x8b, 0x08, 0x27, 0x38, 0x43, 0xa0, 0x83, /// 0x140 + 0x14, 0x20, 0x00, 0xf0, 0x98, 0xfc, 0xa0, 0x8b, 0x01, 0x21, 0x08, 0x43, 0xa0, 0x83, 0x14, 0x20, /// 0x150 + 0x00, 0xf0, 0x91, 0xfc, 0xa0, 0x8b, 0xb0, 0x43, 0xa0, 0x83, 0x14, 0x20, 0x00, 0xf0, 0x8b, 0xfc, /// 0x160 + 0xa0, 0x8b, 0x08, 0x21, 0x88, 0x43, 0xa0, 0x83, 0xbb, 0x49, 0x02, 0x20, 0x20, 0x31, 0x08, 0x76, /// 0x170 + 0xbb, 0x49, 0x8d, 0x80, 0xba, 0x4a, 0xbb, 0x49, 0x11, 0x80, 0x80, 0x21, 0x91, 0x81, 0xba, 0x4a, /// 0x180 + 0x94, 0x23, 0x13, 0x70, 0x15, 0x23, 0x13, 0x70, 0xb7, 0x4a, 0x20, 0x32, 0x13, 0x7c, 0x03, 0x43, /// 0x190 + 0x13, 0x74, 0x75, 0x20, 0xb2, 0x4a, 0x00, 0x02, 0x10, 0x82, 0xb4, 0x48, 0x01, 0x22, 0x02, 0x80, /// 0x1a0 + 0x81, 0x22, 0x02, 0x80, 0xaa, 0x4a, 0xb1, 0x48, 0x09, 0x32, 0x20, 0x30, 0x02, 0x80, 0xb0, 0x4a, /// 0x1b0 + 0x92, 0x78, 0x05, 0x2a, 0xaf, 0x4a, 0x92, 0x78, 0x00, 0xd2, 0x32, 0x43, 0x02, 0x71, 0xae, 0x4e, /// 0x1c0 + 0x01, 0x22, 0xb2, 0x83, 0x00, 0x88, 0xd2, 0x03, 0x10, 0x43, 0xa8, 0x4a, 0x20, 0x32, 0x10, 0x80, /// 0x1d0 + 0x03, 0x20, 0x50, 0x71, 0xa9, 0x48, 0x01, 0x22, 0x02, 0x74, 0x87, 0x82, 0xa6, 0x4a, 0x40, 0x20, /// 0x1e0 + 0x40, 0x3a, 0x10, 0x72, 0x20, 0x20, 0x10, 0x76, 0x15, 0x77, 0x02, 0x46, 0xa2, 0x48, 0x20, 0x38, /// 0x1f0 + 0x02, 0x70, 0x01, 0x71, 0x35, 0x83, 0xa0, 0x49, 0x20, 0x20, 0x20, 0x39, 0x08, 0x73, 0x08, 0x74, /// 0x200 + 0x08, 0x72, 0x9f, 0x48, 0x6a, 0x21, 0x01, 0x77, 0x99, 0x4c, 0x00, 0x20, 0xc0, 0x43, 0x40, 0x34, /// 0x210 + 0xe0, 0x82, 0x00, 0xf0, 0x6e, 0xfc, 0x30, 0x78, 0x40, 0x08, 0x40, 0x00, 0x30, 0x70, 0x30, 0x78, /// 0x220 + 0xfb, 0x21, 0x08, 0x40, 0x30, 0x70, 0x97, 0x48, 0x81, 0xb2, 0x97, 0x48, 0x00, 0xf0, 0x38, 0xfc, /// 0x230 + 0x30, 0x22, 0x96, 0x49, 0x96, 0x48, 0x00, 0xf0, 0x23, 0xfc, 0x26, 0x46, 0x0e, 0x20, 0x60, 0x36, /// 0x240 + 0xb0, 0x72, 0x07, 0x20, 0xf0, 0x73, 0x4b, 0x20, 0x00, 0x01, 0x00, 0xf0, 0x14, 0xfc, 0x91, 0x48, /// 0x250 + 0x01, 0x21, 0x01, 0x70, 0x81, 0x21, 0x01, 0x70, 0x3b, 0x21, 0x01, 0x71, 0x3f, 0x21, 0x01, 0x81, /// 0x260 + 0x21, 0x21, 0x01, 0x70, 0x00, 0xf0, 0x23, 0xfc, 0x00, 0xf0, 0xf4, 0xfb, 0x8a, 0x49, 0x06, 0x20, /// 0x270 + 0x08, 0x60, 0x78, 0x49, 0x80, 0x39, 0x08, 0x60, 0x88, 0x48, 0x01, 0x21, 0x01, 0x80, 0x03, 0x21, /// 0x280 + 0x01, 0x80, 0x41, 0x21, 0x01, 0x76, 0x86, 0x48, 0x00, 0xf0, 0x3c, 0xf9, 0x85, 0x4f, 0x3d, 0x71, /// 0x290 + 0x85, 0x48, 0x45, 0x72, 0x00, 0xf0, 0x90, 0xfe, 0x60, 0x73, 0x00, 0xf0, 0xca, 0xfb, 0x38, 0x7a, /// 0x2a0 + 0x80, 0x07, 0xfc, 0xd5, 0x7f, 0x49, 0x00, 0x20, 0x20, 0x31, 0x08, 0x70, 0x02, 0x20, 0x38, 0x72, /// 0x2b0 + 0x65, 0x49, 0x10, 0x22, 0x54, 0x31, 0x88, 0x18, 0x00, 0xf0, 0xe2, 0xfb, 0x0f, 0x22, 0x02, 0x21, /// 0x2c0 + 0x00, 0x20, 0x00, 0xf0, 0x07, 0xf9, 0x80, 0x03, 0x01, 0x0c, 0x69, 0x48, 0x02, 0x22, 0x80, 0x30, /// 0x2d0 + 0x81, 0x85, 0x11, 0x46, 0x01, 0x20, 0x00, 0xf0, 0xfd, 0xf8, 0x74, 0x49, 0x64, 0x4f, 0x48, 0x43, /// 0x2e0 + 0x63, 0x49, 0x00, 0x0c, 0xc0, 0x31, 0xc8, 0x82, 0x61, 0x7b, 0x60, 0x37, 0xc9, 0x07, 0x00, 0x29, /// 0x2f0 + 0x18, 0xd0, 0x6f, 0x49, 0x88, 0x42, 0x0b, 0xd2, 0x65, 0x48, 0x6e, 0x49, 0x81, 0x61, 0x00, 0xf0, /// 0x300 + 0x44, 0xfb, 0x01, 0xf0, 0x87, 0xf8, 0x50, 0x48, 0x4c, 0x30, 0x00, 0xf0, 0xfb, 0xf8, 0x0d, 0xe0, /// 0x310 + 0x01, 0x20, 0x78, 0x76, 0x03, 0xf0, 0xc4, 0xfb, 0x55, 0x49, 0x20, 0x20, 0x08, 0x87, 0x00, 0xf0, /// 0x320 + 0xd9, 0xfb, 0x03, 0xe0, 0x00, 0xf0, 0x44, 0xfb, 0x00, 0xf0, 0x89, 0xfb, 0x50, 0x4d, 0x09, 0x20, /// 0x330 + 0xe0, 0x35, 0xa8, 0x77, 0x0b, 0x20, 0x4c, 0x49, 0xe8, 0x77, 0x60, 0x31, 0x0a, 0x7d, 0x4c, 0x48, /// 0x340 + 0x02, 0x70, 0x0a, 0x7c, 0x42, 0x70, 0x09, 0x7e, 0x81, 0x70, 0x04, 0x21, 0xc1, 0x70, 0xff, 0x21, /// 0x350 + 0x02, 0x31, 0x41, 0x60, 0x04, 0x22, 0x58, 0x49, 0x1c, 0x30, 0x00, 0xf0, 0x98, 0xfb, 0x04, 0x22, /// 0x360 + 0x55, 0x49, 0x56, 0x48, 0x00, 0xf0, 0x93, 0xfb, 0x0e, 0x20, 0xa0, 0x72, 0x01, 0x24, 0xbc, 0x70, /// 0x370 + 0x28, 0x20, 0x68, 0x71, 0x00, 0xf0, 0x42, 0xfe, 0xb0, 0x73, 0x3e, 0x48, 0x81, 0x8b, 0x50, 0x48, /// 0x380 + 0x81, 0x42, 0x01, 0xd0, 0x00, 0xf0, 0x4a, 0xfe, 0x00, 0xf0, 0xcd, 0xf9, 0x30, 0x48, 0x46, 0x4a, /// 0x390 + 0xf5, 0x30, 0x40, 0x32, 0x90, 0x83, 0x10, 0x46, 0x20, 0x30, 0x2d, 0x4b, 0x00, 0x21, 0x01, 0x70, /// 0x3a0 + 0x9c, 0x3b, 0xd3, 0x83, 0x2b, 0x22, 0x42, 0x70, 0x46, 0x48, 0x04, 0x80, 0x34, 0x48, 0x04, 0x70, /// 0x3b0 + 0x81, 0x22, 0x02, 0x70, 0x0d, 0x22, 0x02, 0x70, 0x31, 0x4b, 0x95, 0x22, 0x20, 0x33, 0x1a, 0x80, /// 0x3c0 + 0xff, 0x22, 0x82, 0x82, 0x03, 0x22, 0x12, 0x02, 0x02, 0x82, 0x01, 0x71, 0x32, 0x49, 0x61, 0x20, /// 0x3d0 + 0x08, 0x60, 0x20, 0x49, 0x80, 0x39, 0x08, 0x60, 0x25, 0x48, 0x3b, 0x49, 0x01, 0x87, 0x2c, 0x48, /// 0x3e0 + 0x3a, 0x49, 0x41, 0x60, 0xff, 0xf7, 0x67, 0xfe, 0x08, 0x20, 0x00, 0xf0, 0x44, 0xfb, 0x1a, 0x48, /// 0x3f0 + 0x40, 0x30, 0x01, 0x78, 0x49, 0x06, 0xfc, 0xd4, 0xff, 0xf7, 0x7e, 0xfe, 0x30, 0xb5, 0x12, 0x4c, /// 0x400 + 0x1b, 0x4d, 0x40, 0x3c, 0x20, 0x68, 0x40, 0x1c, 0x80, 0x35, 0x20, 0x60, 0x28, 0x78, 0x80, 0x07, /// 0x410 + 0x04, 0xd4, 0x72, 0xb6, 0x60, 0x68, 0xff, 0xf7, 0x3a, 0xfe, 0x62, 0xb6, 0x28, 0x78, 0x40, 0x07, /// 0x420 + 0x0a, 0xd5, 0x09, 0x48, 0x20, 0x30, 0x81, 0x7d, 0xc0, 0x7d, 0x81, 0x42, 0x04, 0xd0, 0x72, 0xb6, /// 0x430 + 0x27, 0x48, 0xff, 0xf7, 0x2c, 0xfe, 0x62, 0xb6, 0x72, 0xb6, 0xe0, 0x6f, 0xff, 0xf7, 0x27, 0xfe, /// 0x440 + 0x62, 0xb6, 0x00, 0x20, 0x30, 0xbd, 0x00, 0x00, 0x70, 0x02, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, /// 0x450 + 0xff, 0x0f, 0x00, 0x00, 0x80, 0xe1, 0x00, 0xe0, 0x00, 0x30, 0x00, 0x40, 0x05, 0x1d, 0x00, 0x00, /// 0x460 + 0x00, 0x34, 0x00, 0x40, 0xf9, 0x09, 0x00, 0x00, 0x00, 0x58, 0x00, 0x40, 0x00, 0x38, 0x00, 0x40, /// 0x470 + 0x00, 0x00, 0x00, 0x20, 0x60, 0x67, 0x00, 0x00, 0x40, 0x6c, 0x00, 0x40, 0x60, 0x40, 0x00, 0x40, /// 0x480 + 0x00, 0x64, 0x00, 0x40, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0xc0, 0x14, 0x00, 0x00, /// 0x490 + 0x00, 0x01, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x40, 0x80, 0xe2, 0x00, 0xe0, 0x00, 0x44, 0x00, 0x40, /// 0x4a0 + 0xb8, 0x14, 0x00, 0x00, 0x00, 0x60, 0x00, 0x40, 0x70, 0x03, 0x00, 0x20, 0x20, 0x48, 0x01, 0x00, /// 0x4b0 + 0xdc, 0x05, 0x00, 0x00, 0x97, 0x12, 0x00, 0x00, 0x84, 0x5f, 0x00, 0x00, 0x44, 0x04, 0x00, 0x20, /// 0x4c0 + 0xff, 0xff, 0x00, 0x00, 0x00, 0x48, 0x00, 0x40, 0x07, 0x40, 0x00, 0x00, 0xfd, 0x12, 0x00, 0x00, /// 0x4d0 + 0xa9, 0x10, 0x00, 0x00, 0x70, 0xb5, 0x00, 0x23, 0x12, 0x07, 0x12, 0x0f, 0xfe, 0x4d, 0x0b, 0xe0, /// 0x4e0 + 0x44, 0x00, 0x64, 0x19, 0xff, 0x34, 0x81, 0x34, 0xa4, 0x8c, 0x26, 0x0b, 0x96, 0x42, 0x07, 0xd1, /// 0x4f0 + 0x24, 0x05, 0x24, 0x0d, 0xe3, 0x18, 0x40, 0x18, 0x08, 0x28, 0xf1, 0xd3, 0x18, 0x46, 0x70, 0xbd, /// 0x500 + 0xf6, 0x48, 0x70, 0xbd, 0x10, 0xb5, 0xf6, 0x4a, 0x00, 0x21, 0x11, 0x70, 0xf5, 0x4b, 0x01, 0x21, /// 0x510 + 0x59, 0x72, 0xf5, 0x49, 0x03, 0x88, 0x8b, 0x80, 0x43, 0x88, 0x0b, 0x81, 0x83, 0x88, 0x8b, 0x81, /// 0x520 + 0xc0, 0x88, 0x08, 0x82, 0xb4, 0x20, 0x10, 0x70, 0xee, 0x48, 0xac, 0x38, 0x10, 0x81, 0x07, 0x20, /// 0x530 + 0x90, 0x80, 0xeb, 0x48, 0x02, 0x22, 0x20, 0x38, 0x02, 0x72, 0x03, 0x79, 0x72, 0xb6, 0x13, 0x43, /// 0x540 + 0x03, 0x71, 0x62, 0xb6, 0x11, 0x20, 0x08, 0x80, 0x10, 0xbd, 0x01, 0x88, 0x42, 0x88, 0x51, 0x18, /// 0x550 + 0x82, 0x88, 0xc0, 0x88, 0x51, 0x18, 0x40, 0x18, 0xe4, 0x49, 0x00, 0x22, 0x8a, 0x5e, 0x80, 0x10, /// 0x560 + 0x80, 0x1a, 0x00, 0xd5, 0x00, 0x20, 0x70, 0x47, 0x01, 0x88, 0x42, 0x88, 0x51, 0x18, 0x82, 0x88, /// 0x570 + 0xc0, 0x88, 0x51, 0x18, 0x40, 0x18, 0x80, 0x10, 0x00, 0xd5, 0x00, 0x20, 0x70, 0x47, 0xf8, 0xb5, /// 0x580 + 0x09, 0x22, 0x04, 0x21, 0x00, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0xd6, 0x4d, 0xd2, 0x4e, 0x20, 0x35, /// 0x590 + 0xa9, 0x7b, 0x09, 0x27, 0x49, 0x00, 0xc0, 0x03, 0x89, 0x19, 0xbf, 0x01, 0x00, 0x0c, 0xc9, 0x19, /// 0x5a0 + 0x88, 0x82, 0x00, 0x22, 0x04, 0x21, 0x01, 0x20, 0xff, 0xf7, 0x94, 0xff, 0xa9, 0x7b, 0xc0, 0x03, /// 0x5b0 + 0x49, 0x00, 0x89, 0x19, 0x00, 0x0c, 0xc9, 0x19, 0x88, 0x84, 0x02, 0x22, 0x08, 0x21, 0x03, 0x20, /// 0x5c0 + 0xff, 0xf7, 0x88, 0xff, 0xa9, 0x7b, 0x03, 0x22, 0x49, 0x00, 0x89, 0x19, 0xc9, 0x19, 0x88, 0x83, /// 0x5d0 + 0x04, 0x21, 0x02, 0x20, 0xff, 0xf7, 0x7e, 0xff, 0xa9, 0x7b, 0x05, 0x22, 0x49, 0x00, 0xc0, 0x03, /// 0x5e0 + 0x89, 0x19, 0xd2, 0x01, 0x00, 0x0c, 0x89, 0x18, 0xc1, 0x4c, 0x48, 0x84, 0xa0, 0x69, 0x41, 0x00, /// 0x5f0 + 0x60, 0x69, 0xc2, 0x0f, 0x11, 0x43, 0xa1, 0x61, 0x41, 0x00, 0xa8, 0x7b, 0x42, 0x00, 0x92, 0x19, /// 0x600 + 0xd2, 0x19, 0x12, 0x7d, 0x40, 0x1c, 0xd2, 0x07, 0xd2, 0x0f, 0x11, 0x43, 0x80, 0x07, 0x80, 0x0f, /// 0x610 + 0x61, 0x61, 0xa8, 0x73, 0x28, 0x46, 0x0c, 0x38, 0xff, 0xf7, 0x97, 0xff, 0x21, 0x46, 0xa0, 0x31, /// 0x620 + 0x0e, 0x22, 0x8a, 0x56, 0x0d, 0x46, 0x80, 0x18, 0x80, 0xb2, 0x60, 0x3d, 0x28, 0x80, 0xa1, 0x78, /// 0x630 + 0x05, 0x29, 0x05, 0xd3, 0x3b, 0x21, 0x48, 0x43, 0x32, 0x21, 0x00, 0xf0, 0x05, 0xff, 0x28, 0x80, /// 0x640 + 0xa8, 0x48, 0x24, 0x30, 0xff, 0xf7, 0x81, 0xff, 0x80, 0xb2, 0x4b, 0x21, 0xc9, 0x00, 0x68, 0x87, /// 0x650 + 0x88, 0x42, 0x04, 0xd9, 0xa3, 0x48, 0x62, 0x30, 0xff, 0xf7, 0x77, 0xff, 0x68, 0x87, 0xa3, 0x48, /// 0x660 + 0xa0, 0x4b, 0x40, 0x30, 0x80, 0x8b, 0x9d, 0x49, 0x1c, 0x33, 0x88, 0x42, 0x18, 0x46, 0x0b, 0xd0, /// 0x670 + 0xff, 0xf7, 0x7a, 0xff, 0x81, 0xb2, 0x9b, 0x48, 0x40, 0x30, 0x42, 0x69, 0x80, 0x69, 0x51, 0x43, /// 0x680 + 0x08, 0x18, 0x00, 0x01, 0x00, 0x0c, 0x01, 0xe0, 0xff, 0xf7, 0x5f, 0xff, 0xa0, 0x87, 0x18, 0x46, /// 0x690 + 0xff, 0xf7, 0x5b, 0xff, 0x82, 0xb2, 0xff, 0x23, 0x01, 0x21, 0x25, 0x33, 0x49, 0x03, 0x95, 0x48, /// 0x6a0 + 0xa2, 0x87, 0x9a, 0x42, 0x02, 0xd9, 0x82, 0x8b, 0xd2, 0x07, 0x04, 0xd0, 0x82, 0x8a, 0x8a, 0x43, /// 0x6b0 + 0x82, 0x82, 0x00, 0x20, 0xf8, 0xbd, 0x82, 0x8a, 0x0a, 0x43, 0xf9, 0xe7, 0x70, 0xb5, 0x15, 0x22, /// 0x6c0 + 0x85, 0x49, 0x52, 0x01, 0x8c, 0x18, 0x00, 0x22, 0xa2, 0x56, 0x05, 0x24, 0xe4, 0x01, 0xff, 0x23, /// 0x6d0 + 0x09, 0x19, 0x78, 0x33, 0x89, 0x8b, 0x98, 0x42, 0x1f, 0xd9, 0x7f, 0x4b, 0xff, 0x26, 0x1c, 0x19, /// 0x6e0 + 0xe5, 0x8b, 0x15, 0x24, 0x64, 0x01, 0x1b, 0x19, 0x01, 0x24, 0xb8, 0x36, 0x1c, 0x57, 0xb0, 0x42, /// 0x6f0 + 0x02, 0xd3, 0x29, 0x46, 0x22, 0x46, 0x10, 0xe0, 0x06, 0x46, 0xff, 0x3e, 0x78, 0x3e, 0x4b, 0x1b, /// 0x700 + 0x73, 0x43, 0xdd, 0x17, 0xad, 0x0e, 0xeb, 0x18, 0x9b, 0x11, 0xa4, 0x1a, 0xc9, 0x1a, 0x74, 0x43, /// 0x710 + 0xe3, 0x17, 0x9b, 0x0e, 0x1b, 0x19, 0x9b, 0x11, 0x9a, 0x18, 0x48, 0x43, 0x00, 0x0b, 0x80, 0x18, /// 0x720 + 0x00, 0xd5, 0x00, 0x20, 0x70, 0xbd, 0xf8, 0xb5, 0x72, 0x48, 0x00, 0x8b, 0xff, 0x21, 0x80, 0x04, /// 0x730 + 0x80, 0x0e, 0x34, 0x31, 0x40, 0x1c, 0x48, 0x43, 0x67, 0x26, 0x44, 0x0a, 0x36, 0x02, 0xb0, 0x8a, /// 0x740 + 0x00, 0x90, 0x31, 0x8b, 0x45, 0x1a, 0x6c, 0x49, 0x20, 0x46, 0x48, 0x43, 0x29, 0x46, 0x00, 0xf0, /// 0x750 + 0x7b, 0xfe, 0x64, 0x4f, 0xc8, 0x22, 0x40, 0x37, 0x38, 0x80, 0x00, 0x98, 0x29, 0x46, 0x50, 0x43, /// 0x760 + 0x00, 0xf0, 0x88, 0xfe, 0xff, 0x21, 0x91, 0x31, 0x08, 0x1a, 0x78, 0x80, 0xf5, 0x8b, 0xf0, 0x8a, /// 0x770 + 0x62, 0x4a, 0x29, 0x1a, 0x20, 0x46, 0x50, 0x43, 0x00, 0xf0, 0x66, 0xfe, 0x80, 0xb2, 0xb8, 0x80, /// 0x780 + 0x23, 0x21, 0x68, 0x43, 0x61, 0x43, 0x00, 0xf0, 0x5f, 0xfe, 0x19, 0x21, 0x40, 0x09, 0x49, 0x01, /// 0x790 + 0x08, 0x1a, 0x00, 0xb2, 0x8d, 0x21, 0x48, 0x43, 0xc1, 0x17, 0x09, 0x0e, 0x08, 0x18, 0x00, 0x12, /// 0x7a0 + 0xf8, 0x80, 0xf8, 0xbd, 0x70, 0xb5, 0x04, 0x46, 0x52, 0x48, 0x00, 0x8b, 0x4d, 0x49, 0x80, 0x04, /// 0x7b0 + 0x4a, 0x7c, 0x80, 0x0e, 0x82, 0x42, 0x02, 0xd0, 0x48, 0x74, 0xff, 0xf7, 0xb4, 0xff, 0x49, 0x49, /// 0x7c0 + 0x4f, 0x48, 0x40, 0x31, 0x84, 0x42, 0x03, 0xd8, 0x02, 0x22, 0x08, 0x88, 0x8a, 0x5e, 0x1e, 0xe0, /// 0x7d0 + 0x4b, 0x48, 0x40, 0x30, 0x84, 0x42, 0x03, 0xd3, 0x06, 0x22, 0x88, 0x88, 0x8a, 0x5e, 0x16, 0xe0, /// 0x7e0 + 0x47, 0x48, 0x0b, 0x88, 0x40, 0x42, 0x22, 0x18, 0x88, 0x88, 0xc0, 0x1a, 0x50, 0x43, 0xc5, 0x17, /// 0x7f0 + 0xad, 0x0e, 0x28, 0x18, 0x80, 0x11, 0xc0, 0x18, 0x06, 0x25, 0x02, 0x23, 0x4d, 0x5f, 0xcb, 0x5e, /// 0x800 + 0xe9, 0x1a, 0x51, 0x43, 0xca, 0x17, 0x92, 0x0e, 0x51, 0x18, 0x89, 0x11, 0xca, 0x18, 0x44, 0x43, /// 0x810 + 0x20, 0x0c, 0x80, 0x18, 0x00, 0xd5, 0x00, 0x20, 0x70, 0xbd, 0xf8, 0xb5, 0x04, 0x22, 0x08, 0x21, /// 0x820 + 0x07, 0x20, 0xff, 0xf7, 0x57, 0xfe, 0x81, 0xb2, 0x31, 0x48, 0x40, 0x30, 0xc2, 0x88, 0x13, 0x01, /// 0x830 + 0x9a, 0x1a, 0x51, 0x18, 0x09, 0x03, 0x09, 0x0c, 0xc1, 0x80, 0x09, 0x22, 0x04, 0x21, 0x00, 0x20, /// 0x840 + 0xff, 0xf7, 0x48, 0xfe, 0x41, 0x08, 0x2a, 0x48, 0x0e, 0x22, 0xa0, 0x30, 0x82, 0x56, 0x28, 0x4c, /// 0x850 + 0x88, 0x18, 0x80, 0xb2, 0xc0, 0x34, 0x25, 0x4a, 0x20, 0x83, 0x00, 0x21, 0x51, 0x5e, 0x88, 0x42, /// 0x860 + 0x01, 0xdb, 0x40, 0x1a, 0x00, 0xe0, 0x00, 0x20, 0x80, 0xb2, 0x21, 0x49, 0x20, 0x83, 0x89, 0x78, /// 0x870 + 0x05, 0x29, 0x05, 0xd3, 0x3b, 0x21, 0x48, 0x43, 0x32, 0x21, 0x00, 0xf0, 0xe5, 0xfd, 0x20, 0x83, /// 0x880 + 0x00, 0x22, 0x04, 0x21, 0x01, 0x20, 0xff, 0xf7, 0x25, 0xfe, 0xc0, 0x03, 0x05, 0x0c, 0x12, 0x48, /// 0x890 + 0x11, 0x4e, 0xc0, 0x30, 0x81, 0x8d, 0x01, 0x20, 0x42, 0x00, 0x92, 0x19, 0xc0, 0x32, 0x92, 0x8d, /// 0x8a0 + 0x40, 0x1c, 0x51, 0x18, 0xc0, 0xb2, 0x89, 0xb2, 0x04, 0x28, 0xf5, 0xd3, 0x8f, 0x08, 0x28, 0x46, /// 0x8b0 + 0xff, 0xf7, 0x78, 0xff, 0xff, 0xf7, 0x02, 0xff, 0x04, 0x46, 0x38, 0x46, 0xff, 0xf7, 0x72, 0xff, /// 0x8c0 + 0xff, 0xf7, 0xfc, 0xfe, 0x03, 0x46, 0x04, 0x48, 0xe0, 0x30, 0x01, 0x7d, 0x49, 0x00, 0x89, 0x19, /// 0x8d0 + 0xc0, 0x31, 0x8d, 0x85, 0x01, 0x7d, 0x15, 0xe0, 0x30, 0x01, 0x00, 0x20, 0xff, 0xff, 0x00, 0x00, /// 0x8e0 + 0x20, 0x60, 0x00, 0x40, 0x70, 0x03, 0x00, 0x20, 0x00, 0x44, 0x00, 0x40, 0x20, 0x67, 0x00, 0x00, /// 0x8f0 + 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x40, 0x00, 0x6b, 0x03, 0x00, 0xc0, 0x24, 0x07, 0x00, /// 0x900 + 0xda, 0x02, 0x00, 0x00, 0x49, 0x1c, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x75, 0x7d, 0x26, 0x02, 0x46, /// 0x910 + 0xf6, 0x00, 0x32, 0x25, 0xf9, 0x49, 0xa0, 0x32, 0xb4, 0x42, 0x0d, 0xd9, 0x8e, 0x88, 0xf6, 0x43, /// 0x920 + 0xb6, 0x07, 0x09, 0xd0, 0x03, 0x20, 0x88, 0x80, 0x08, 0x88, 0xf8, 0x23, 0x98, 0x43, 0x38, 0x23, /// 0x930 + 0xc0, 0x30, 0x18, 0x43, 0x08, 0x80, 0x26, 0xe0, 0xf1, 0x4e, 0x36, 0x78, 0xf6, 0x06, 0x18, 0xd5, /// 0x940 + 0x8e, 0x88, 0x00, 0x2e, 0x15, 0xd0, 0x26, 0x46, 0xc8, 0x36, 0xb3, 0x42, 0x11, 0xd9, 0x64, 0x2c, /// 0x950 + 0x0f, 0xd2, 0x00, 0x23, 0x8b, 0x80, 0xeb, 0x49, 0x08, 0x23, 0x4b, 0x71, 0x0b, 0x88, 0x8c, 0x14, /// 0x960 + 0x23, 0x43, 0x0b, 0x80, 0xaa, 0x21, 0x81, 0x75, 0xe7, 0x48, 0xd5, 0x66, 0x00, 0x68, 0x10, 0x66, /// 0x970 + 0xf8, 0xbd, 0x83, 0x7d, 0x00, 0x2b, 0xfb, 0xd1, 0x89, 0x88, 0x00, 0x29, 0xf8, 0xd1, 0xc8, 0x2c, /// 0x980 + 0xf6, 0xd9, 0x55, 0x21, 0x81, 0x75, 0xd5, 0x66, 0xf8, 0xbd, 0xe0, 0x48, 0x01, 0x78, 0x42, 0x22, /// 0x990 + 0x11, 0x43, 0x01, 0x70, 0xde, 0x49, 0xc0, 0x14, 0x08, 0x60, 0xde, 0x49, 0x08, 0x60, 0x70, 0x47, /// 0x9a0 + 0x41, 0x18, 0x00, 0x22, 0x01, 0xe0, 0x02, 0x70, 0x40, 0x1c, 0x88, 0x42, 0xfb, 0xd3, 0x70, 0x47, /// 0x9b0 + 0xd3, 0x49, 0x00, 0x20, 0x40, 0x31, 0x08, 0x75, 0xd7, 0x49, 0x0a, 0x78, 0x52, 0x08, 0x52, 0x00, /// 0x9c0 + 0x0a, 0x70, 0x0a, 0x78, 0xfb, 0x23, 0x1a, 0x40, 0x0a, 0x70, 0xcd, 0x49, 0x40, 0x39, 0x48, 0x73, /// 0x9d0 + 0xca, 0x49, 0x88, 0x80, 0xc9, 0x4a, 0x40, 0x32, 0x10, 0x74, 0xd0, 0x48, 0x08, 0x80, 0xd0, 0x48, /// 0x9e0 + 0x82, 0x8b, 0x03, 0x15, 0x9a, 0x43, 0x82, 0x83, 0xce, 0x4a, 0x02, 0x82, 0x75, 0x22, 0x12, 0x02, /// 0x9f0 + 0x0a, 0x82, 0xcd, 0x49, 0x01, 0x83, 0xc3, 0x49, 0x81, 0x20, 0x20, 0x39, 0x08, 0x80, 0xc0, 0x48, /// 0xa00 + 0x0b, 0x21, 0x20, 0x30, 0x81, 0x72, 0x07, 0x21, 0xc1, 0x73, 0xbe, 0x48, 0xc7, 0x49, 0x01, 0x80, /// 0xa10 + 0xbb, 0x49, 0x80, 0x39, 0x8a, 0x78, 0xc6, 0x49, 0x05, 0x2a, 0x89, 0x78, 0x01, 0xd2, 0x01, 0x22, /// 0xa20 + 0x11, 0x43, 0x01, 0x71, 0xb9, 0x49, 0x09, 0x20, 0x08, 0x70, 0xb5, 0x48, 0x22, 0x21, 0x22, 0x38, /// 0xa30 + 0xb6, 0xe7, 0xc0, 0x48, 0x81, 0x21, 0x01, 0x80, 0x00, 0x21, 0x01, 0x80, 0x70, 0x47, 0x00, 0xb5, /// 0xa40 + 0xff, 0xf7, 0xf7, 0xff, 0xb0, 0x48, 0xbc, 0x49, 0x41, 0x60, 0x01, 0x68, 0x80, 0x30, 0x81, 0x66, /// 0xa50 + 0x00, 0x20, 0x00, 0xbd, 0xb9, 0x48, 0x00, 0x21, 0x01, 0x74, 0x41, 0x74, 0xb5, 0x48, 0x01, 0x21, /// 0xa60 + 0x01, 0x80, 0x01, 0x15, 0x81, 0x80, 0x0f, 0x21, 0x01, 0x80, 0x02, 0x22, 0x02, 0x81, 0x01, 0x83, /// 0xa70 + 0x04, 0x21, 0x81, 0x82, 0x70, 0x47, 0x00, 0xe0, 0x00, 0xbf, 0x40, 0x1e, 0xfc, 0xd2, 0x70, 0x47, /// 0xa80 + 0x82, 0x18, 0x01, 0xe0, 0x08, 0xc9, 0x08, 0xc0, 0x90, 0x42, 0xfb, 0xd3, 0x70, 0x47, 0x82, 0x18, /// 0xa90 + 0x03, 0xe0, 0x0b, 0x78, 0x03, 0x70, 0x40, 0x1c, 0x49, 0x1c, 0x90, 0x42, 0xf9, 0xd3, 0x70, 0x47, /// 0xaa0 + 0x41, 0x18, 0x00, 0x22, 0x00, 0xe0, 0x04, 0xc0, 0x88, 0x42, 0xfc, 0xd3, 0x70, 0x47, 0xa4, 0x48, /// 0xab0 + 0x01, 0x21, 0x01, 0x70, 0xa2, 0x4a, 0x05, 0x21, 0x40, 0x32, 0x11, 0x80, 0x00, 0x22, 0x02, 0x74, /// 0xac0 + 0x9f, 0x49, 0x20, 0x31, 0x0a, 0x74, 0x9f, 0x4a, 0x8a, 0x81, 0x13, 0x22, 0x0a, 0x70, 0x07, 0x21, /// 0xad0 + 0x01, 0x72, 0x70, 0x47, 0x8a, 0x49, 0x80, 0x39, 0xca, 0x8e, 0x02, 0x43, 0x08, 0x8f, 0x10, 0x40, /// 0xae0 + 0xc8, 0x86, 0x05, 0xd0, 0x8c, 0x48, 0x20, 0x38, 0x01, 0x7f, 0xfb, 0x22, 0x11, 0x40, 0x01, 0x77, /// 0xaf0 + 0x70, 0x47, 0x83, 0x4a, 0x80, 0x3a, 0x11, 0x46, 0x40, 0x31, 0xd0, 0x8e, 0xcb, 0x8a, 0x98, 0x43, /// 0xb00 + 0xd0, 0x86, 0x00, 0x22, 0xca, 0x82, 0x00, 0x28, 0x05, 0xd1, 0x83, 0x48, 0x20, 0x38, 0x01, 0x7f, /// 0xb10 + 0x04, 0x22, 0x11, 0x43, 0x01, 0x77, 0x70, 0x47, 0xfe, 0xb5, 0x78, 0x48, 0x00, 0x24, 0x80, 0x88, /// 0xb20 + 0x86, 0x49, 0x02, 0x07, 0x40, 0x39, 0xc8, 0x7d, 0x00, 0x2a, 0x06, 0xda, 0xc2, 0x07, 0x02, 0xd1, /// 0xb30 + 0x01, 0x22, 0x10, 0x43, 0xc8, 0x75, 0x02, 0x24, 0x0b, 0xe0, 0xc2, 0x07, 0x09, 0xd0, 0x71, 0x4a, /// 0xb40 + 0x20, 0x3a, 0x13, 0x8b, 0x05, 0x25, 0x2d, 0x02, 0x2b, 0x43, 0x13, 0x83, 0x40, 0x08, 0x40, 0x00, /// 0xb50 + 0xc8, 0x75, 0x73, 0x48, 0x80, 0x8b, 0x79, 0x4a, 0xc3, 0x04, 0x69, 0x48, 0x60, 0x32, 0x80, 0x38, /// 0xb60 + 0x80, 0x8e, 0x01, 0x90, 0xc1, 0x07, 0x0c, 0x20, 0xc9, 0x0f, 0x10, 0x56, 0x00, 0x2b, 0x06, 0xda, /// 0xb70 + 0x19, 0x28, 0x02, 0xdd, 0x01, 0x20, 0x04, 0x43, 0x07, 0xe0, 0x40, 0x1c, 0x03, 0xe0, 0x19, 0x23, /// 0xb80 + 0xd8, 0x42, 0x02, 0xdb, 0x40, 0x1e, 0x10, 0x73, 0x0c, 0x43, 0x6f, 0x48, 0x80, 0x89, 0x5c, 0x4e, /// 0xb90 + 0x4b, 0x21, 0x80, 0x3e, 0x35, 0x46, 0x40, 0x35, 0xef, 0x88, 0x80, 0x06, 0x4f, 0x43, 0x5a, 0x49, /// 0xba0 + 0x80, 0x0f, 0x20, 0x39, 0x20, 0x36, 0x00, 0x91, 0x00, 0x28, 0x07, 0xd1, 0x7d, 0x21, 0x38, 0x46, /// 0xbb0 + 0xc9, 0x00, 0x00, 0xf0, 0x49, 0xfc, 0xae, 0x38, 0x64, 0x28, 0x1e, 0xdd, 0x04, 0x20, 0x04, 0x43, /// 0xbc0 + 0x61, 0x48, 0x80, 0x89, 0x80, 0x06, 0x80, 0x0f, 0x07, 0xd1, 0x7d, 0x21, 0x38, 0x46, 0xc9, 0x00, /// 0xbd0 + 0x00, 0xf0, 0x3a, 0xfc, 0xae, 0x38, 0x6e, 0x28, 0x0f, 0xdd, 0xf0, 0x7e, 0x0b, 0x28, 0x08, 0xd0, /// 0xbe0 + 0x03, 0x28, 0x06, 0xd0, 0x05, 0x28, 0x04, 0xd0, 0x03, 0x20, 0xf0, 0x76, 0x00, 0x99, 0x00, 0x20, /// 0xbf0 + 0x48, 0x75, 0xe8, 0x89, 0x08, 0x21, 0x08, 0x43, 0xe8, 0x81, 0x41, 0x48, 0x47, 0x4a, 0x01, 0x6e, /// 0xc00 + 0xc3, 0x32, 0x60, 0x30, 0x91, 0x42, 0x1d, 0xdd, 0xaa, 0x88, 0x7d, 0x21, 0xc9, 0x00, 0x8a, 0x42, /// 0xc10 + 0x18, 0xd9, 0x01, 0x79, 0x49, 0x1c, 0xca, 0xb2, 0x02, 0x71, 0xf1, 0x7e, 0x05, 0x29, 0x13, 0xd0, /// 0xc20 + 0x43, 0x79, 0x9a, 0x42, 0x10, 0xd3, 0x01, 0x22, 0x14, 0x43, 0x0b, 0x29, 0x06, 0xd0, 0x03, 0x29, /// 0xc30 + 0x04, 0xd0, 0x00, 0x9a, 0x00, 0x21, 0x51, 0x75, 0x05, 0x21, 0xf1, 0x76, 0xe9, 0x89, 0x08, 0x22, /// 0xc40 + 0x11, 0x43, 0xe9, 0x81, 0x00, 0x21, 0x01, 0x71, 0x2d, 0x49, 0x01, 0x98, 0x80, 0x39, 0x40, 0x07, /// 0xc50 + 0x40, 0x0f, 0x60, 0x40, 0x06, 0xd0, 0x01, 0x9a, 0xd2, 0x08, 0xd2, 0x00, 0x22, 0x43, 0x8a, 0x86, /// 0xc60 + 0xff, 0xf7, 0x38, 0xff, 0xfe, 0xbd, 0x02, 0x46, 0x00, 0x20, 0x02, 0xe0, 0x13, 0x78, 0x58, 0x40, /// 0xc70 + 0x52, 0x1c, 0x49, 0x1e, 0xfa, 0xd2, 0x70, 0x47, 0x08, 0x22, 0x01, 0x21, 0x01, 0xe0, 0x09, 0x18, /// 0xc80 + 0x40, 0x08, 0x52, 0x1e, 0xfb, 0xd2, 0xc8, 0x07, 0xc0, 0x0f, 0x70, 0x47, 0xf8, 0xb5, 0x2f, 0x4c, /// 0xc90 + 0x00, 0x26, 0x20, 0x46, 0xff, 0x30, 0xa1, 0x30, 0x84, 0x46, 0x14, 0x30, 0x01, 0x27, 0xff, 0x34, /// 0xca0 + 0x35, 0x46, 0xc1, 0x34, 0x00, 0x90, 0x60, 0x7c, 0x00, 0x28, 0x0e, 0xd1, 0x60, 0x46, 0xa1, 0x7c, /// 0xcb0 + 0x00, 0x7d, 0x81, 0x42, 0x06, 0xd2, 0x01, 0x20, 0xb0, 0x40, 0x49, 0x1c, 0x05, 0x43, 0xa1, 0x74, /// 0xcc0 + 0xb6, 0x1c, 0x61, 0xe0, 0x00, 0x20, 0xa0, 0x74, 0x67, 0x74, 0x61, 0x7c, 0x20, 0x7c, 0x81, 0x42, /// 0xcd0 + 0x48, 0xd2, 0xa0, 0x7c, 0x00, 0x28, 0x48, 0xd0, 0x09, 0x28, 0x06, 0xd2, 0x00, 0x9a, 0x40, 0x1e, /// 0xce0 + 0x89, 0x5c, 0xc1, 0x40, 0xc8, 0x07, 0xc0, 0x0f, 0x3f, 0xe0, 0x09, 0x28, 0x30, 0xd0, 0xff, 0x22, /// 0xcf0 + 0x01, 0x20, 0xa2, 0x74, 0x49, 0x1c, 0x61, 0x74, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, /// 0xd00 + 0x80, 0x00, 0x00, 0x20, 0x20, 0x38, 0x00, 0x40, 0x30, 0x02, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x40, /// 0xd10 + 0x80, 0xe2, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe0, 0x40, 0x6c, 0x00, 0x40, 0x01, 0x09, 0x00, 0x00, /// 0xd20 + 0x00, 0x30, 0x00, 0x40, 0xff, 0x07, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x0b, 0x80, 0x00, 0x00, /// 0xd30 + 0x60, 0x67, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x40, 0x17, 0x43, 0x00, 0x00, 0x30, 0x03, 0x00, 0x20, /// 0xd40 + 0x00, 0x54, 0x00, 0x40, 0xe7, 0x03, 0x00, 0x00, 0x20, 0x48, 0x00, 0x40, 0x30, 0x01, 0x00, 0x20, /// 0xd50 + 0x00, 0x98, 0x08, 0x5c, 0xff, 0xf7, 0x90, 0xff, 0x61, 0x46, 0x09, 0x7d, 0x00, 0x29, 0x04, 0xd1, /// 0xd60 + 0x78, 0x40, 0x02, 0xe0, 0x60, 0x7f, 0xa7, 0x77, 0x78, 0x40, 0x61, 0x7f, 0x79, 0x40, 0x48, 0x40, /// 0xd70 + 0x60, 0x77, 0x40, 0x00, 0x08, 0x43, 0xb0, 0x40, 0x05, 0x43, 0xa0, 0x7c, 0xb6, 0x1c, 0x40, 0x1c, /// 0xd80 + 0xa0, 0x74, 0xa0, 0x7f, 0x01, 0x28, 0x01, 0xd0, 0x10, 0x2e, 0x8c, 0xd3, 0x76, 0x1e, 0x26, 0x77, /// 0xd90 + 0x65, 0x83, 0xf8, 0xbd, 0x70, 0xb5, 0x05, 0x46, 0x41, 0x1c, 0xa9, 0x48, 0xff, 0xf7, 0x63, 0xff, /// 0xda0 + 0xa8, 0x49, 0xa7, 0x4c, 0x49, 0x19, 0xff, 0x31, 0xa1, 0x31, 0x88, 0x75, 0x0b, 0x34, 0xed, 0x1c, /// 0xdb0 + 0x25, 0x74, 0x20, 0x7d, 0xe0, 0x74, 0x00, 0x20, 0x60, 0x74, 0xa0, 0x74, 0x60, 0x77, 0x02, 0x26, /// 0xdc0 + 0xa6, 0x77, 0xff, 0xf7, 0x63, 0xff, 0xa0, 0x48, 0x41, 0x79, 0x02, 0x29, 0x1b, 0xd3, 0x21, 0x46, /// 0xdd0 + 0xe0, 0x39, 0x89, 0x7d, 0xaa, 0x29, 0x16, 0xd0, 0x61, 0x7d, 0xdf, 0x22, 0x11, 0x40, 0x61, 0x75, /// 0xde0 + 0x05, 0x21, 0x41, 0x71, 0x01, 0x88, 0x82, 0x14, 0x11, 0x43, 0x01, 0x80, 0x97, 0x49, 0x0a, 0x8a, /// 0xdf0 + 0x0c, 0x23, 0x1a, 0x43, 0x0a, 0x82, 0x96, 0x4a, 0x96, 0x4b, 0xd2, 0x8f, 0x00, 0x21, 0x9a, 0x42, /// 0xe00 + 0x06, 0xd2, 0xc0, 0x22, 0x05, 0xe0, 0x61, 0x7d, 0x20, 0x22, 0x11, 0x43, 0x61, 0x75, 0xed, 0xe7, /// 0xe10 + 0x30, 0x22, 0xd3, 0x06, 0x01, 0xd5, 0xff, 0x21, 0x01, 0x31, 0x93, 0x06, 0x02, 0xd5, 0x01, 0x23, /// 0xe20 + 0x5b, 0x02, 0x19, 0x43, 0x03, 0x88, 0x03, 0x25, 0x2d, 0x02, 0xab, 0x43, 0x0b, 0x43, 0x01, 0x21, /// 0xe30 + 0xc9, 0x03, 0x0b, 0x43, 0x03, 0x80, 0x84, 0x4d, 0x87, 0x48, 0x20, 0x3d, 0xa8, 0x80, 0x2e, 0x81, /// 0xe40 + 0x00, 0x20, 0xc0, 0x43, 0xa8, 0x81, 0x00, 0x20, 0x51, 0x06, 0x00, 0xd5, 0x08, 0x20, 0x11, 0x06, /// 0xe50 + 0x01, 0xd5, 0x40, 0x21, 0x08, 0x43, 0x25, 0x21, 0x08, 0x43, 0x28, 0x80, 0x60, 0x8b, 0x28, 0x82, /// 0xe60 + 0x20, 0x7f, 0x28, 0x75, 0xff, 0xf7, 0x12, 0xff, 0xff, 0x20, 0x00, 0x02, 0xa8, 0x81, 0x70, 0xbd, /// 0xe70 + 0x7a, 0x49, 0x0a, 0x15, 0x8b, 0x8b, 0x02, 0x28, 0x01, 0xd8, 0x13, 0x43, 0x00, 0xe0, 0x93, 0x43, /// 0xe80 + 0x8b, 0x83, 0x00, 0x22, 0x70, 0x49, 0x03, 0x28, 0x01, 0xd2, 0x02, 0x28, 0x01, 0xd9, 0x4a, 0x71, /// 0xe90 + 0x05, 0xe0, 0x01, 0x28, 0x01, 0xd9, 0x01, 0x20, 0x00, 0xe0, 0x02, 0x20, 0x48, 0x71, 0x4a, 0x79, /// 0xea0 + 0x01, 0x20, 0x00, 0x03, 0x00, 0x2a, 0x0a, 0x88, 0x02, 0xd0, 0x02, 0x43, 0x0a, 0x80, 0x70, 0x47, /// 0xeb0 + 0x82, 0x43, 0xfb, 0xe7, 0x69, 0x4a, 0x10, 0x8b, 0x69, 0x4b, 0x80, 0x04, 0x81, 0x0e, 0x64, 0x48, /// 0xec0 + 0x40, 0x30, 0x80, 0x7a, 0x40, 0x1c, 0x58, 0x43, 0x00, 0x0a, 0x40, 0x1e, 0x3f, 0x28, 0x00, 0xdd, /// 0xed0 + 0x3f, 0x20, 0x81, 0x42, 0x00, 0xd2, 0x48, 0x1c, 0x11, 0x8b, 0x3f, 0x23, 0x1b, 0x02, 0x99, 0x43, /// 0xee0 + 0x00, 0x02, 0x01, 0x43, 0x11, 0x83, 0x59, 0x49, 0x08, 0x88, 0x07, 0x22, 0x12, 0x02, 0x90, 0x43, /// 0xef0 + 0x57, 0x4a, 0x60, 0x32, 0x92, 0x78, 0x52, 0x07, 0x52, 0x0d, 0x10, 0x43, 0x08, 0x80, 0x54, 0x48, /// 0xf00 + 0x58, 0x49, 0xc0, 0x8f, 0x88, 0x42, 0x01, 0xd9, 0x0b, 0x20, 0x00, 0xe0, 0x0e, 0x20, 0x50, 0x49, /// 0xf10 + 0xa0, 0x31, 0x88, 0x72, 0x4c, 0x49, 0x0a, 0x88, 0x52, 0x09, 0x52, 0x01, 0xcb, 0x13, 0x1a, 0x43, /// 0xf20 + 0x10, 0x43, 0x08, 0x80, 0x70, 0x47, 0xf8, 0xb5, 0x45, 0x4a, 0x41, 0x09, 0x0b, 0x32, 0x00, 0x29, /// 0xf30 + 0x0a, 0xd0, 0x20, 0x29, 0x01, 0xdb, 0x1f, 0x21, 0x06, 0xe0, 0x93, 0x7d, 0x8b, 0x42, 0x01, 0xda, /// 0xf40 + 0x49, 0x1e, 0x01, 0xe0, 0x8b, 0x42, 0x00, 0xdd, 0x91, 0x75, 0x41, 0x49, 0xcc, 0x8f, 0x46, 0x49, /// 0xf50 + 0x27, 0x46, 0x8c, 0x42, 0x00, 0xd9, 0x0c, 0x46, 0x60, 0x43, 0x44, 0x49, 0x00, 0xf0, 0x74, 0xfa, /// 0xf60 + 0x3b, 0x4e, 0x80, 0x36, 0xb1, 0x7c, 0x08, 0x1a, 0x3e, 0x49, 0x8f, 0x42, 0x06, 0xd8, 0x00, 0x28, /// 0xf70 + 0x04, 0xdb, 0xf1, 0x7c, 0x40, 0x43, 0x41, 0x43, 0x48, 0x11, 0x00, 0xe0, 0x00, 0x20, 0xf1, 0x8a, /// 0xf80 + 0x0d, 0x18, 0xb0, 0x8a, 0xa8, 0x42, 0x00, 0xd2, 0x05, 0x46, 0x39, 0x48, 0x87, 0x42, 0x01, 0xd9, /// 0xf90 + 0x0d, 0x25, 0x00, 0xe0, 0x19, 0x35, 0x2f, 0x49, 0x20, 0x03, 0x7d, 0x31, 0x40, 0x18, 0x49, 0x00, /// 0xfa0 + 0x00, 0xf0, 0x52, 0xfa, 0x1e, 0x21, 0x71, 0x56, 0x40, 0x19, 0x08, 0x18, 0x31, 0x49, 0x88, 0x42, /// 0xfb0 + 0x00, 0xd9, 0x08, 0x46, 0x30, 0x82, 0xf8, 0xbd, 0x21, 0x48, 0x21, 0x49, 0x10, 0xb5, 0xb5, 0x38, /// 0xfc0 + 0x2d, 0x4a, 0x5b, 0x31, 0x13, 0x78, 0x5b, 0x06, 0x02, 0xd4, 0x03, 0x68, 0x05, 0x2b, 0x01, 0xd3, /// 0xfd0 + 0x00, 0x20, 0x10, 0xbd, 0x0b, 0x78, 0x05, 0x2b, 0xf4, 0xd9, 0x19, 0x48, 0x0b, 0x30, 0x81, 0x8e, /// 0xfe0 + 0xc2, 0x8e, 0x51, 0x18, 0x02, 0x8f, 0x40, 0x8f, 0x51, 0x18, 0x41, 0x18, 0x23, 0x48, 0x00, 0xf0, /// 0xff0 + 0x2b, 0xfa, 0x17, 0x49, 0x40, 0x31, 0x08, 0x84, 0x01, 0x20, 0x10, 0xbd, 0x14, 0x48, 0x80, 0x78, /// 0x1000 + 0x05, 0x28, 0x02, 0xd3, 0x16, 0x49, 0x7e, 0x39, 0x01, 0xe0, 0x15, 0x49, 0x49, 0x1d, 0x1c, 0x48, /// 0x1010 + 0x02, 0x89, 0x89, 0x1a, 0x00, 0x22, 0x82, 0x5e, 0x88, 0x18, 0x70, 0x47, 0x18, 0x48, 0x10, 0xb5, /// 0x1020 + 0x40, 0x30, 0xc4, 0x8b, 0x80, 0x8b, 0x21, 0x1a, 0x16, 0x48, 0x00, 0xf0, 0x0d, 0xfa, 0x04, 0x49, /// 0x1030 + 0x15, 0x4a, 0xcb, 0x31, 0x48, 0x61, 0x60, 0x43, 0x10, 0x1a, 0x88, 0x61, 0x10, 0xbd, 0x00, 0x00, /// 0x1040 + 0xe5, 0x02, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, 0x20, 0x38, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, /// 0x1050 + 0x00, 0x00, 0x00, 0x20, 0xc8, 0x32, 0x00, 0x00, 0xdb, 0x05, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, /// 0x1060 + 0x55, 0x03, 0x00, 0x00, 0xe0, 0x2e, 0x00, 0x00, 0x1b, 0x4e, 0x00, 0x00, 0xa0, 0x86, 0x01, 0x00, /// 0x1070 + 0xbc, 0x34, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x70, 0x17, 0x00, /// 0x1080 + 0x20, 0x67, 0x00, 0x00, 0x00, 0xe0, 0x79, 0x00, 0x00, 0xd0, 0xb6, 0x00, 0x1e, 0x49, 0x1f, 0x4b, /// 0x1090 + 0x8a, 0x7d, 0x92, 0x00, 0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0xd0, 0x64, 0x88, 0x7d, 0x40, 0x1c, /// 0x10a0 + 0x40, 0x07, 0x40, 0x0f, 0x88, 0x75, 0x70, 0x47, 0x30, 0xb5, 0x19, 0x48, 0x01, 0x79, 0x89, 0x06, /// 0x10b0 + 0x28, 0xd4, 0x18, 0x49, 0x40, 0x22, 0x0a, 0x70, 0x80, 0x22, 0x0a, 0x74, 0x12, 0x4a, 0x13, 0x4d, /// 0x10c0 + 0xd4, 0x7d, 0xa3, 0x00, 0x5b, 0x19, 0xff, 0x33, 0x4d, 0x33, 0x0b, 0x83, 0x04, 0x23, 0x8b, 0x82, /// 0x10d0 + 0x01, 0x23, 0x0b, 0x72, 0x0d, 0x79, 0x72, 0xb6, 0x1d, 0x43, 0x0d, 0x71, 0x64, 0x1c, 0x61, 0x07, /// 0x10e0 + 0x49, 0x0f, 0xd1, 0x75, 0x05, 0x21, 0x51, 0x75, 0x62, 0xb6, 0x58, 0x21, 0x01, 0x77, 0xff, 0x21, /// 0x10f0 + 0x81, 0x82, 0x09, 0x49, 0x01, 0x82, 0x30, 0x21, 0x01, 0x71, 0x0f, 0x21, 0x01, 0x70, 0x01, 0x79, /// 0x1100 + 0x19, 0x43, 0x01, 0x71, 0x00, 0x20, 0x30, 0xbd, 0x90, 0x02, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, /// 0x1110 + 0x00, 0x64, 0x00, 0x40, 0x00, 0x60, 0x00, 0x40, 0xc6, 0x03, 0x00, 0x00, 0xa5, 0x48, 0x00, 0x68, /// 0x1120 + 0x00, 0x47, 0xa4, 0x48, 0x40, 0x68, 0x00, 0x47, 0xa2, 0x48, 0x80, 0x68, 0x00, 0x47, 0xa1, 0x48, /// 0x1130 + 0xc0, 0x68, 0x00, 0x47, 0x9f, 0x48, 0x00, 0x69, 0x00, 0x47, 0x9e, 0x48, 0x40, 0x69, 0x00, 0x47, /// 0x1140 + 0x9c, 0x48, 0x80, 0x69, 0x00, 0x47, 0x9b, 0x48, 0xc0, 0x69, 0x00, 0x47, 0x99, 0x48, 0x00, 0x6a, /// 0x1150 + 0x00, 0x47, 0x98, 0x48, 0x40, 0x6a, 0x00, 0x47, 0x96, 0x48, 0x80, 0x6a, 0x00, 0x47, 0x95, 0x48, /// 0x1160 + 0xc0, 0x6a, 0x00, 0x47, 0xf8, 0xb5, 0x94, 0x48, 0x02, 0x7a, 0x01, 0x79, 0x0a, 0x40, 0x02, 0x72, /// 0x1170 + 0xd1, 0x07, 0x19, 0xd0, 0x01, 0x79, 0x49, 0x08, 0x49, 0x00, 0x01, 0x71, 0x00, 0x21, 0x01, 0x74, /// 0x1180 + 0x01, 0x70, 0x8e, 0x4c, 0x65, 0x7d, 0x8e, 0x49, 0x02, 0x23, 0x05, 0x2d, 0x09, 0xd0, 0x0e, 0x79, /// 0x1190 + 0x04, 0x25, 0x2e, 0x43, 0x0e, 0x71, 0x0e, 0x8a, 0xc1, 0x27, 0xbf, 0x00, 0xbe, 0x43, 0x0e, 0x82, /// 0x11a0 + 0x65, 0x75, 0x0c, 0x79, 0x1c, 0x43, 0x0c, 0x71, 0x91, 0x07, 0x10, 0xd5, 0x01, 0x79, 0xfd, 0x22, /// 0x11b0 + 0x11, 0x40, 0x01, 0x71, 0x80, 0x48, 0x00, 0x24, 0x20, 0x30, 0x04, 0x70, 0x7f, 0x49, 0x10, 0x22, /// 0x11c0 + 0x34, 0x31, 0x88, 0x18, 0xff, 0xf7, 0x5c, 0xfc, 0x7c, 0x48, 0xe0, 0x30, 0x44, 0x72, 0xf8, 0xbd, /// 0x11d0 + 0xf8, 0xb5, 0x7b, 0x4c, 0xa0, 0x8a, 0x21, 0x8a, 0x08, 0x40, 0xff, 0x21, 0xa1, 0x82, 0xe6, 0x21, /// 0x11e0 + 0x06, 0x46, 0xff, 0x22, 0x0e, 0x40, 0x77, 0x4d, 0x6d, 0x32, 0x11, 0x1d, 0x52, 0x59, 0x49, 0x5b, /// 0x11f0 + 0xff, 0x35, 0x02, 0x23, 0x61, 0x35, 0x00, 0x2e, 0x23, 0xd0, 0xc4, 0x26, 0x30, 0x40, 0x00, 0x26, /// 0x1200 + 0x00, 0x28, 0x08, 0xd0, 0x20, 0x79, 0x18, 0x43, 0x20, 0x71, 0x20, 0x20, 0xff, 0xf7, 0x33, 0xfc, /// 0x1210 + 0x06, 0x20, 0x68, 0x75, 0x07, 0xe0, 0x68, 0x7d, 0x04, 0x28, 0x03, 0xd1, 0x20, 0x7b, 0x51, 0x18, /// 0x1220 + 0x20, 0x39, 0xc8, 0x77, 0x6e, 0x75, 0x0d, 0x20, 0x20, 0x70, 0x03, 0x20, 0x00, 0x02, 0x20, 0x82, /// 0x1230 + 0x26, 0x71, 0x61, 0x48, 0x06, 0x70, 0x06, 0x74, 0x01, 0x79, 0x49, 0x08, 0x49, 0x00, 0x01, 0x71, /// 0x1240 + 0xf8, 0xbd, 0x5e, 0x4e, 0xc7, 0x07, 0x20, 0x3e, 0x76, 0x8e, 0x00, 0x2f, 0x03, 0xd0, 0x30, 0x0a, /// 0x1250 + 0x20, 0x73, 0x6b, 0x75, 0xf8, 0xbd, 0xc0, 0x06, 0xfc, 0xd5, 0x68, 0x7d, 0x02, 0x28, 0x12, 0xd0, /// 0x1260 + 0x21, 0x20, 0x20, 0x71, 0xff, 0x20, 0xc3, 0x30, 0x20, 0x82, 0x53, 0x48, 0x40, 0x23, 0x03, 0x70, /// 0x1270 + 0x90, 0x23, 0x03, 0x74, 0x02, 0x83, 0x89, 0x1e, 0x81, 0x82, 0x01, 0x21, 0x01, 0x72, 0x02, 0x79, /// 0x1280 + 0x0a, 0x43, 0x02, 0x71, 0xf8, 0xbd, 0x26, 0x73, 0x03, 0x20, 0x68, 0x75, 0xf8, 0xbd, 0x4e, 0x49, /// 0x1290 + 0x81, 0x20, 0x08, 0x80, 0x70, 0x47, 0x10, 0xb5, 0x4b, 0x49, 0x0a, 0x8b, 0x0a, 0x83, 0x90, 0x06, /// 0x12a0 + 0x84, 0x0f, 0x46, 0x48, 0x01, 0x23, 0x60, 0x30, 0x00, 0x2c, 0x16, 0xd0, 0x84, 0x7f, 0x00, 0x22, /// 0x12b0 + 0x00, 0x2c, 0x0a, 0xd0, 0x43, 0x8b, 0x0b, 0x82, 0x03, 0x7f, 0x0b, 0x75, 0x01, 0x2c, 0x02, 0xd0, /// 0x12c0 + 0xff, 0xf7, 0xe4, 0xfc, 0x10, 0xbd, 0x82, 0x77, 0x10, 0xbd, 0x0b, 0x80, 0x02, 0x74, 0x3f, 0x48, /// 0x12d0 + 0x01, 0x8a, 0x0c, 0x22, 0x91, 0x43, 0x01, 0x82, 0x10, 0xbd, 0x05, 0x21, 0x09, 0x03, 0x0a, 0x42, /// 0x12e0 + 0xfa, 0xd0, 0xc1, 0x7d, 0x19, 0x43, 0xc1, 0x75, 0x10, 0xbd, 0x34, 0x48, 0x60, 0x38, 0x01, 0x68, /// 0x12f0 + 0x49, 0x1c, 0x01, 0x60, 0x36, 0x49, 0x07, 0x20, 0x08, 0x72, 0x70, 0x47, 0x10, 0xb5, 0x34, 0x4c, /// 0x1300 + 0x20, 0x7a, 0x80, 0x07, 0x02, 0xd5, 0x33, 0x48, 0xfe, 0xf7, 0xc1, 0xfe, 0x07, 0x20, 0x20, 0x72, /// 0x1310 + 0x10, 0xbd, 0x10, 0xb5, 0x30, 0x49, 0x8b, 0x89, 0x28, 0x48, 0x2a, 0x4c, 0xa0, 0x30, 0x02, 0x7c, /// 0x1320 + 0x52, 0x00, 0x12, 0x19, 0xff, 0x32, 0xc1, 0x32, 0x13, 0x86, 0x02, 0x7c, 0x52, 0x1c, 0x12, 0x07, /// 0x1330 + 0x12, 0x0f, 0x02, 0x74, 0x0f, 0x20, 0x08, 0x83, 0x10, 0xbd, 0x28, 0x49, 0x0f, 0x20, 0x08, 0x83, /// 0x1340 + 0x70, 0x47, 0x22, 0x48, 0x10, 0xb5, 0x40, 0x30, 0x81, 0x88, 0x09, 0x07, 0x0f, 0xd5, 0x81, 0x88, /// 0x1350 + 0x08, 0x22, 0x11, 0x43, 0x81, 0x80, 0x1d, 0x48, 0x81, 0x88, 0x89, 0x07, 0x07, 0xd5, 0x20, 0x4a, /// 0x1360 + 0x01, 0x21, 0xd1, 0x76, 0x81, 0x80, 0x15, 0x48, 0xaa, 0x21, 0x80, 0x38, 0x81, 0x75, 0x13, 0x48, /// 0x1370 + 0x20, 0x30, 0x00, 0x68, 0x00, 0x28, 0x00, 0xd0, 0x80, 0x47, 0x1a, 0x49, 0x0f, 0x20, 0x08, 0x76, /// 0x1380 + 0x10, 0xbd, 0x10, 0xb5, 0x18, 0x48, 0x01, 0x78, 0x49, 0x06, 0x03, 0xd5, 0x41, 0x21, 0x01, 0x70, /// 0x1390 + 0xff, 0xf7, 0x0e, 0xfb, 0x15, 0x48, 0x01, 0x79, 0xc9, 0x07, 0x01, 0xd0, 0x10, 0x21, 0x01, 0x71, /// 0x13a0 + 0x10, 0xbd, 0x13, 0x48, 0x81, 0x8a, 0x49, 0x06, 0x03, 0xd5, 0x81, 0x8a, 0x40, 0x22, 0x11, 0x43, /// 0x13b0 + 0x81, 0x82, 0x70, 0x47, 0x00, 0x01, 0x00, 0x20, 0x00, 0x60, 0x00, 0x40, 0x90, 0x02, 0x00, 0x20, /// 0x13c0 + 0x00, 0x64, 0x00, 0x40, 0x30, 0x01, 0x00, 0x20, 0x00, 0x38, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, /// 0x13d0 + 0x00, 0x54, 0x00, 0x40, 0xfd, 0x03, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x40, 0x00, 0x50, 0x00, 0x40, /// 0x13e0 + 0x90, 0x03, 0x00, 0x20, 0x00, 0x40, 0x00, 0x40, 0x00, 0x3c, 0x00, 0x40, 0x40, 0x30, 0x00, 0x40, /// 0x13f0 + 0x00, 0x48, 0x00, 0x40, 0x10, 0xb5, 0x06, 0x49, 0x0c, 0x22, 0x0a, 0x75, 0x19, 0x22, 0x4a, 0x75, /// 0x1400 + 0x88, 0x75, 0x10, 0x20, 0xa0, 0x31, 0xc8, 0x71, 0x01, 0x20, 0xff, 0xf7, 0xc3, 0xfc, 0x10, 0xbd, /// 0x1410 + 0xd0, 0x02, 0x00, 0x20, 0x10, 0xb5, 0x09, 0x48, 0x07, 0x49, 0x41, 0x60, 0x08, 0x49, 0xc1, 0x67, /// 0x1420 + 0x08, 0x22, 0x08, 0x49, 0x84, 0x30, 0xff, 0xf7, 0x2b, 0xfb, 0x04, 0x48, 0x08, 0x22, 0x05, 0x49, /// 0x1430 + 0x8c, 0x30, 0xff, 0xf7, 0x25, 0xfb, 0x10, 0xbd, 0x43, 0x18, 0x00, 0x00, 0x30, 0x02, 0x00, 0x20, /// 0x1440 + 0x09, 0x15, 0x00, 0x00, 0x74, 0x1c, 0x00, 0x00, 0x30, 0xb5, 0x0b, 0x46, 0x01, 0x46, 0x00, 0x20, /// 0x1450 + 0x20, 0x22, 0x01, 0x24, 0x09, 0xe0, 0x0d, 0x46, 0xd5, 0x40, 0x9d, 0x42, 0x05, 0xd3, 0x1d, 0x46, /// 0x1460 + 0x95, 0x40, 0x49, 0x1b, 0x25, 0x46, 0x95, 0x40, 0x40, 0x19, 0x15, 0x46, 0x52, 0x1e, 0x00, 0x2d, /// 0x1470 + 0xf1, 0xdc, 0x30, 0xbd, 0x70, 0xb5, 0x00, 0x24, 0x25, 0x46, 0x00, 0x28, 0x01, 0xda, 0x01, 0x24, /// 0x1480 + 0x40, 0x42, 0x00, 0x29, 0x01, 0xda, 0x01, 0x25, 0x49, 0x42, 0xff, 0xf7, 0xdd, 0xff, 0xac, 0x42, /// 0x1490 + 0x00, 0xd0, 0x40, 0x42, 0x00, 0x2c, 0x00, 0xd0, 0x49, 0x42, 0x70, 0xbd, 0x30, 0xb4, 0x74, 0x46, /// 0x14a0 + 0x64, 0x1e, 0x25, 0x78, 0x64, 0x1c, 0xab, 0x42, 0x00, 0xd2, 0x1d, 0x46, 0x63, 0x5d, 0x5b, 0x00, /// 0x14b0 + 0xe3, 0x18, 0x30, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0f, 0x02, 0x0f, 0x02, 0x0f, 0x02, 0x0f, 0x02, /// 0x14c0 + 0x65, 0x11, 0x00, 0x00, 0xeb, 0x12, 0x00, 0x00, 0x13, 0x13, 0x00, 0x00, 0x3b, 0x13, 0x00, 0x00, /// 0x14d0 + 0x79, 0x00, 0x00, 0x00, 0xd1, 0x11, 0x00, 0x00, 0x8f, 0x12, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, /// 0x14e0 + 0x79, 0x00, 0x00, 0x00, 0x43, 0x13, 0x00, 0x00, 0xa3, 0x13, 0x00, 0x00, 0x83, 0x13, 0x00, 0x00, /// 0x14f0 + 0xfd, 0x48, 0x32, 0x21, 0xc1, 0x66, 0x01, 0x46, 0x0a, 0x22, 0x40, 0x39, 0x8a, 0x72, 0x40, 0x39, /// 0x1500 + 0x09, 0x68, 0x32, 0x39, 0x01, 0x66, 0x70, 0x47, 0xf8, 0xb5, 0xff, 0xf7, 0x05, 0xfb, 0xf7, 0x4d, /// 0x1510 + 0xec, 0x89, 0x00, 0x2c, 0x27, 0xd0, 0x00, 0x26, 0xf5, 0x48, 0xee, 0x81, 0x21, 0x04, 0x04, 0xd5, /// 0x1520 + 0x01, 0x8d, 0x01, 0x22, 0x52, 0x02, 0x11, 0x43, 0x01, 0x85, 0xe1, 0x06, 0x04, 0xd5, 0x01, 0x8d, /// 0x1530 + 0xff, 0x22, 0x01, 0x32, 0x11, 0x43, 0x01, 0x85, 0xe1, 0x07, 0x08, 0x22, 0x00, 0x29, 0x04, 0xd0, /// 0x1540 + 0xea, 0x49, 0x40, 0x31, 0x4b, 0x78, 0x13, 0x43, 0x4b, 0x70, 0xa1, 0x05, 0x15, 0xd5, 0xe7, 0x49, /// 0x1550 + 0x20, 0x39, 0x8b, 0x79, 0x1b, 0x06, 0x08, 0xd5, 0x8e, 0x71, 0xce, 0x71, 0x01, 0x8d, 0x01, 0x22, /// 0x1560 + 0x11, 0x43, 0x01, 0x85, 0x09, 0xe0, 0x00, 0x20, 0xf8, 0xbd, 0x0b, 0x7b, 0x00, 0x2b, 0x03, 0x8d, /// 0x1570 + 0x0d, 0xd0, 0x20, 0x27, 0x3b, 0x43, 0x03, 0x85, 0xca, 0x71, 0xa0, 0x06, 0x01, 0xd5, 0xff, 0xf7, /// 0x1580 + 0xb8, 0xfa, 0x60, 0x06, 0x0b, 0xd5, 0x28, 0x7b, 0x5a, 0x28, 0x02, 0xd0, 0x07, 0xe0, 0x10, 0x27, /// 0x1590 + 0xf0, 0xe7, 0x68, 0x7b, 0x40, 0x21, 0x08, 0x43, 0x68, 0x73, 0xd6, 0x48, 0x80, 0x47, 0x20, 0x07, /// 0x15a0 + 0x01, 0xd5, 0xff, 0xf7, 0xa5, 0xff, 0x2e, 0x73, 0xdd, 0xe7, 0xcf, 0x48, 0x10, 0xb5, 0x80, 0x38, /// 0x15b0 + 0x04, 0x68, 0x80, 0x30, 0x01, 0x6e, 0xc2, 0x6e, 0x61, 0x1a, 0x91, 0x42, 0x19, 0xdb, 0xcb, 0x49, /// 0x15c0 + 0x20, 0x39, 0xca, 0x7e, 0x0b, 0x2a, 0x03, 0xd0, 0x03, 0x2a, 0x01, 0xd0, 0x05, 0x2a, 0x06, 0xd1, /// 0x15d0 + 0xc5, 0x4b, 0xa0, 0x3b, 0x59, 0x7d, 0x03, 0x29, 0x0b, 0xd8, 0x49, 0x1c, 0x59, 0x75, 0x83, 0x21, /// 0x15e0 + 0x89, 0x00, 0x04, 0x66, 0x81, 0x86, 0xc0, 0x48, 0x20, 0x30, 0x82, 0x75, 0x01, 0x20, 0xff, 0xf7, /// 0x15f0 + 0xd1, 0xfb, 0x10, 0xbd, 0xbd, 0x48, 0x10, 0xb5, 0x10, 0x22, 0xbf, 0x49, 0x50, 0x30, 0xff, 0xf7, /// 0x1600 + 0x3f, 0xfa, 0xba, 0x48, 0x10, 0x22, 0xbd, 0x49, 0x28, 0x30, 0xff, 0xf7, 0x39, 0xfa, 0xb8, 0x49, /// 0x1610 + 0xbb, 0x48, 0xc8, 0x87, 0xc0, 0x31, 0x08, 0x82, 0xff, 0x20, 0xba, 0x49, 0x06, 0x30, 0x08, 0x82, /// 0x1620 + 0x10, 0xbd, 0x10, 0xb5, 0xff, 0xf7, 0xe6, 0xff, 0xb0, 0x49, 0xf7, 0x22, 0x48, 0x7b, 0x10, 0x40, /// 0x1630 + 0x48, 0x73, 0x08, 0x46, 0xb4, 0x4a, 0x40, 0x30, 0xc2, 0x60, 0x82, 0x60, 0xaa, 0x48, 0xb3, 0x4a, /// 0x1640 + 0x80, 0x30, 0x42, 0x82, 0xff, 0x38, 0x01, 0x38, 0x02, 0x68, 0x80, 0x30, 0x82, 0x66, 0x42, 0x66, /// 0x1650 + 0xc3, 0x6e, 0xd2, 0x1a, 0x02, 0x66, 0x0e, 0x20, 0x88, 0x72, 0xa4, 0x48, 0x03, 0x21, 0x20, 0x30, /// 0x1660 + 0x81, 0x70, 0xa1, 0x48, 0x07, 0x21, 0x40, 0x38, 0x81, 0x72, 0x10, 0xbd, 0x10, 0xb5, 0xa8, 0x48, /// 0x1670 + 0x01, 0x88, 0x07, 0x22, 0x12, 0x02, 0x91, 0x43, 0x01, 0x80, 0x9c, 0x48, 0x08, 0x22, 0x41, 0x7b, /// 0x1680 + 0x11, 0x43, 0x41, 0x73, 0x0e, 0x21, 0x81, 0x72, 0x00, 0x21, 0x20, 0x30, 0x81, 0x70, 0x9a, 0x49, /// 0x1690 + 0x10, 0x22, 0x10, 0x31, 0x30, 0x30, 0xff, 0xf7, 0xf3, 0xf9, 0x98, 0x49, 0x93, 0x48, 0x10, 0x22, /// 0x16a0 + 0x10, 0x31, 0x28, 0x30, 0xff, 0xf7, 0xec, 0xf9, 0x98, 0x49, 0x90, 0x48, 0x8a, 0x31, 0x40, 0x30, /// 0x16b0 + 0x01, 0x82, 0x94, 0x4a, 0x97, 0x49, 0x11, 0x82, 0x8d, 0x4a, 0x97, 0x49, 0xd1, 0x87, 0xc0, 0x32, /// 0x16c0 + 0x11, 0x82, 0x96, 0x49, 0xc1, 0x60, 0x90, 0x49, 0x81, 0x60, 0x87, 0x48, 0x80, 0x30, 0x01, 0x67, /// 0x16d0 + 0x05, 0x21, 0xc0, 0x38, 0x81, 0x72, 0x10, 0xbd, 0x10, 0xb5, 0x83, 0x48, 0x90, 0x49, 0x41, 0x63, /// 0x16e0 + 0x41, 0x21, 0x49, 0x02, 0x01, 0x87, 0x80, 0x21, 0x20, 0x30, 0x81, 0x76, 0x05, 0x20, 0xff, 0xf7, /// 0x16f0 + 0x51, 0xfb, 0x10, 0xbd, 0x10, 0xb5, 0x7c, 0x48, 0x8a, 0x49, 0x41, 0x63, 0xcd, 0x21, 0x01, 0x87, /// 0x1700 + 0x89, 0x49, 0x20, 0x30, 0xca, 0x7b, 0x82, 0x76, 0x0a, 0x7c, 0xc2, 0x76, 0x49, 0x7c, 0x01, 0x77, /// 0x1710 + 0x07, 0x20, 0xff, 0xf7, 0x3f, 0xfb, 0x10, 0xbd, 0x10, 0xb5, 0x74, 0x49, 0x08, 0x88, 0xc0, 0x08, /// 0x1720 + 0xff, 0x28, 0x00, 0xd9, 0xff, 0x20, 0xc8, 0x72, 0xff, 0x22, 0x6f, 0x49, 0x0d, 0x32, 0x8a, 0x86, /// 0x1730 + 0x20, 0x31, 0x88, 0x75, 0x01, 0x20, 0xff, 0xf7, 0x2d, 0xfb, 0x10, 0xbd, 0x70, 0xb5, 0x6b, 0x4c, /// 0x1740 + 0x60, 0x8f, 0xff, 0xf7, 0x2f, 0xf8, 0xfe, 0xf7, 0xb9, 0xff, 0x05, 0x46, 0x20, 0x88, 0x77, 0x49, /// 0x1750 + 0x77, 0x4a, 0x48, 0x43, 0x66, 0x49, 0x89, 0x8f, 0x51, 0x43, 0x40, 0x1a, 0x64, 0x21, 0xff, 0xf7, /// 0x1760 + 0x89, 0xfe, 0x68, 0x43, 0xc1, 0x17, 0x09, 0x0d, 0x08, 0x18, 0x00, 0x13, 0x21, 0x46, 0x40, 0x31, /// 0x1770 + 0x08, 0x66, 0x70, 0xbd, 0xf8, 0xb5, 0x5d, 0x4d, 0x5d, 0x4c, 0x40, 0x35, 0x68, 0x78, 0x26, 0x46, /// 0x1780 + 0xc1, 0x06, 0x40, 0x36, 0xbf, 0x27, 0x00, 0x29, 0x0d, 0xda, 0xef, 0x21, 0x08, 0x40, 0x68, 0x70, /// 0x1790 + 0xa1, 0x8e, 0x01, 0x20, 0xc0, 0x02, 0x01, 0x43, 0xa1, 0x86, 0xff, 0xf7, 0x9b, 0xf9, 0x30, 0x7e, /// 0x17a0 + 0x1e, 0x28, 0x06, 0xd1, 0x0c, 0xe0, 0x31, 0x7e, 0x1e, 0x29, 0x0d, 0xd0, 0x20, 0x21, 0x08, 0x43, /// 0x17b0 + 0x68, 0x70, 0xa0, 0x8e, 0x10, 0x21, 0x08, 0x43, 0xa0, 0x86, 0x08, 0x46, 0xff, 0xf7, 0x8a, 0xf9, /// 0x17c0 + 0xa8, 0x78, 0x38, 0x40, 0xa8, 0x70, 0xf8, 0xbd, 0x48, 0x48, 0x80, 0x30, 0x01, 0x79, 0x4a, 0x06, /// 0x17d0 + 0xf6, 0xd5, 0x39, 0x40, 0x80, 0x22, 0x11, 0x43, 0x01, 0x71, 0xf1, 0xe7, 0x70, 0xb5, 0x55, 0x48, /// 0x17e0 + 0x00, 0x7e, 0x80, 0x07, 0x27, 0xd5, 0x53, 0x48, 0x20, 0x30, 0x01, 0x78, 0x49, 0x08, 0x49, 0x00, /// 0x17f0 + 0x01, 0x70, 0x3e, 0x48, 0x00, 0x25, 0x80, 0x30, 0x05, 0x75, 0x45, 0x48, 0x85, 0x80, 0x3b, 0x4c, /// 0x1800 + 0x40, 0x34, 0x20, 0x78, 0x01, 0x07, 0x4c, 0x48, 0x16, 0xd5, 0xff, 0xf7, 0x63, 0xf9, 0x20, 0x78, /// 0x1810 + 0xfd, 0x21, 0x08, 0x40, 0x21, 0x46, 0x20, 0x70, 0x60, 0x39, 0xc8, 0x7e, 0x0b, 0x28, 0x0a, 0xd0, /// 0x1820 + 0x03, 0x28, 0x08, 0xd0, 0x05, 0x28, 0x06, 0xd0, 0x2f, 0x48, 0xa0, 0x38, 0x45, 0x75, 0x0b, 0x20, /// 0x1830 + 0xc8, 0x76, 0xff, 0xf7, 0x5d, 0xfe, 0x70, 0xbd, 0xff, 0xf7, 0x4c, 0xf9, 0x02, 0x20, 0x20, 0x70, /// 0x1840 + 0xfe, 0xe7, 0xfe, 0xb5, 0x3d, 0x48, 0x01, 0x78, 0x49, 0x06, 0x04, 0xd5, 0x41, 0x21, 0x01, 0x70, /// 0x1850 + 0xff, 0xf7, 0xae, 0xf8, 0xec, 0xe1, 0x25, 0x4d, 0x68, 0x7b, 0xc0, 0x07, 0x43, 0xd0, 0xff, 0xf7, /// 0x1860 + 0xbd, 0xff, 0x2f, 0x46, 0x40, 0x37, 0xb8, 0x78, 0x40, 0x06, 0x01, 0xd5, 0xff, 0xf7, 0x82, 0xff, /// 0x1870 + 0x1f, 0x48, 0x33, 0x49, 0xc2, 0x8f, 0x60, 0x30, 0x8a, 0x42, 0x10, 0xd9, 0x1c, 0x49, 0x89, 0x78, /// 0x1880 + 0x05, 0x29, 0x01, 0xd3, 0x06, 0x21, 0x00, 0xe0, 0x05, 0x21, 0x81, 0x70, 0x16, 0x48, 0x16, 0x4e, /// 0x1890 + 0xc0, 0x30, 0x00, 0x90, 0x40, 0x7a, 0x40, 0x36, 0x00, 0x28, 0x02, 0xd0, 0x0c, 0xe0, 0x01, 0x21, /// 0x18a0 + 0xf3, 0xe7, 0x11, 0x48, 0x0c, 0x30, 0xfe, 0xf7, 0x2d, 0xfe, 0x30, 0x7c, 0x00, 0x28, 0x01, 0xd1, /// 0x18b0 + 0xfe, 0xf7, 0x65, 0xfe, 0xfe, 0xf7, 0xb1, 0xff, 0x68, 0x7b, 0x0c, 0x4c, 0xc1, 0x07, 0x1d, 0x48, /// 0x18c0 + 0x80, 0x34, 0x20, 0x30, 0x00, 0x29, 0x48, 0xd0, 0x09, 0x49, 0x18, 0x4a, 0x89, 0x8f, 0x5a, 0x3a, /// 0x18d0 + 0x91, 0x42, 0x04, 0xd3, 0x16, 0x4a, 0x21, 0x8b, 0x48, 0x3a, 0x91, 0x42, 0x32, 0xd2, 0x21, 0x7d, /// 0x18e0 + 0x49, 0x08, 0x49, 0x00, 0x2f, 0xe0, 0xa4, 0xe1, 0xb0, 0x02, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, /// 0x18f0 + 0x00, 0x00, 0x00, 0x20, 0x11, 0x06, 0x00, 0x20, 0x7c, 0x1c, 0x00, 0x00, 0xd4, 0x30, 0x00, 0x00, /// 0x1900 + 0x88, 0x13, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, 0x04, 0x0a, 0x0a, 0x00, 0xdc, 0x05, 0x00, 0x00, /// 0x1910 + 0x00, 0x34, 0x00, 0x40, 0xe3, 0x02, 0x00, 0x00, 0x28, 0x23, 0x00, 0x00, 0x31, 0x14, 0x14, 0x00, /// 0x1920 + 0x0c, 0x51, 0x0a, 0x00, 0x0c, 0x71, 0x12, 0x00, 0x20, 0x67, 0x00, 0x00, 0x41, 0x0a, 0x00, 0x00, /// 0x1930 + 0x34, 0x08, 0x00, 0x00, 0x20, 0x6c, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x40, /// 0x1940 + 0xe0, 0x2e, 0x00, 0x00, 0x21, 0x7d, 0xc9, 0x07, 0x01, 0x78, 0x02, 0xd0, 0x01, 0x22, 0x11, 0x43, /// 0x1950 + 0x01, 0xe0, 0x49, 0x08, 0x49, 0x00, 0x01, 0x70, 0x09, 0xe0, 0x01, 0x78, 0x49, 0x08, 0x49, 0x00, /// 0x1960 + 0x01, 0x70, 0x00, 0x20, 0x20, 0x75, 0x22, 0x21, 0xb2, 0x48, 0xff, 0xf7, 0x19, 0xf8, 0xff, 0xf7, /// 0x1970 + 0xe5, 0xfe, 0x7a, 0x78, 0xd0, 0x06, 0x11, 0xd5, 0xa0, 0x89, 0x41, 0x1c, 0xa1, 0x81, 0xad, 0x49, /// 0x1980 + 0x5e, 0x39, 0x4b, 0x8c, 0x98, 0x42, 0x09, 0xd9, 0xef, 0x20, 0x02, 0x40, 0x7a, 0x70, 0x8a, 0x8e, /// 0x1990 + 0x01, 0x20, 0x80, 0x02, 0x02, 0x43, 0x8a, 0x86, 0xff, 0xf7, 0x9c, 0xf8, 0x38, 0x78, 0xc1, 0x06, /// 0x19a0 + 0xa5, 0x48, 0x01, 0x90, 0x00, 0x29, 0x7d, 0xda, 0x38, 0x7a, 0x04, 0x28, 0x7a, 0xd1, 0xa1, 0x48, /// 0x19b0 + 0x21, 0x8a, 0x5e, 0x38, 0xc2, 0x8f, 0x91, 0x42, 0x7e, 0xd0, 0xa0, 0x4b, 0x9a, 0x42, 0x01, 0xd9, /// 0x19c0 + 0xc3, 0x87, 0x07, 0xe0, 0x9e, 0x4b, 0x9a, 0x42, 0x01, 0xd2, 0xc3, 0x87, 0x4d, 0xe0, 0x9d, 0x4b, /// 0x19d0 + 0x9a, 0x42, 0x4a, 0xd9, 0x9b, 0x4a, 0x91, 0x42, 0x47, 0xd2, 0x2a, 0x88, 0x9a, 0x4b, 0x9a, 0x42, /// 0x19e0 + 0x3a, 0xd3, 0x7d, 0x22, 0xc0, 0x8f, 0x52, 0x01, 0x8a, 0x18, 0x05, 0x46, 0x02, 0x92, 0x90, 0x42, /// 0x19f0 + 0x16, 0xd9, 0x0a, 0x20, 0x41, 0x43, 0x95, 0x48, 0x08, 0x18, 0x54, 0x21, 0xff, 0xf7, 0x24, 0xfd, /// 0x1a00 + 0x67, 0x21, 0x09, 0x02, 0x0e, 0x22, 0x8a, 0x56, 0x91, 0x49, 0x80, 0x18, 0x88, 0x42, 0x00, 0xd9, /// 0x1a10 + 0x08, 0x46, 0x01, 0x21, 0x08, 0x43, 0x8f, 0x49, 0x08, 0x82, 0x02, 0x98, 0x20, 0x82, 0x14, 0xe0, /// 0x1a20 + 0x0a, 0x21, 0x48, 0x43, 0x8c, 0x49, 0x40, 0x18, 0x54, 0x21, 0xff, 0xf7, 0x23, 0xfd, 0x67, 0x21, /// 0x1a30 + 0x09, 0x02, 0x0e, 0x22, 0x8a, 0x56, 0x86, 0x49, 0x80, 0x18, 0x88, 0x42, 0x00, 0xd9, 0x08, 0x46, /// 0x1a40 + 0x01, 0x21, 0x08, 0x43, 0x83, 0x49, 0x08, 0x82, 0x25, 0x82, 0x7a, 0x48, 0x10, 0x22, 0x83, 0x49, /// 0x1a50 + 0x0a, 0x30, 0xff, 0xf7, 0x15, 0xf8, 0x2c, 0xe0, 0x81, 0x48, 0x81, 0x42, 0x29, 0xd0, 0x20, 0x82, /// 0x1a60 + 0xff, 0x21, 0x7c, 0x48, 0x7e, 0x31, 0x01, 0x82, 0x23, 0xe0, 0xc5, 0x8f, 0x8d, 0x42, 0x08, 0xd2, /// 0x1a70 + 0x20, 0x8b, 0x7c, 0x4a, 0x7d, 0x21, 0x09, 0x01, 0x50, 0x43, 0x69, 0x18, 0x00, 0x0b, 0x81, 0x42, /// 0x1a80 + 0x17, 0xd3, 0x28, 0x46, 0x0a, 0x21, 0x48, 0x43, 0x73, 0x49, 0x40, 0x18, 0x54, 0x21, 0xff, 0xf7, /// 0x1a90 + 0xf1, 0xfc, 0x67, 0x21, 0x09, 0x02, 0x0e, 0x22, 0x8a, 0x56, 0x6d, 0x49, 0x80, 0x18, 0x88, 0x42, /// 0x1aa0 + 0x02, 0xd9, 0x00, 0xe0, 0x08, 0xe0, 0x08, 0x46, 0x01, 0x21, 0x08, 0x43, 0x69, 0x49, 0x08, 0x82, /// 0x1ab0 + 0x25, 0x82, 0x01, 0x99, 0x32, 0x20, 0xc8, 0x66, 0x30, 0x7c, 0x00, 0x28, 0x26, 0xd1, 0x6a, 0x48, /// 0x1ac0 + 0xf1, 0x7c, 0x05, 0x46, 0xff, 0x35, 0x41, 0x35, 0x28, 0x46, 0xc0, 0x30, 0x02, 0x90, 0x00, 0x29, /// 0x1ad0 + 0x1d, 0xd0, 0x49, 0x1e, 0xf1, 0x74, 0xa8, 0x7a, 0x04, 0x28, 0x17, 0xd3, 0x72, 0xb6, 0x63, 0x48, /// 0x1ae0 + 0xfe, 0xf7, 0xd5, 0xfa, 0x62, 0xb6, 0x30, 0x7d, 0xf1, 0x7c, 0x40, 0x1e, 0x81, 0x42, 0x0d, 0xd1, /// 0x1af0 + 0x02, 0x99, 0x00, 0x20, 0x08, 0x83, 0x88, 0x82, 0x70, 0x7d, 0x80, 0x06, 0x06, 0xd4, 0x5c, 0x48, /// 0x1b00 + 0x02, 0x21, 0x41, 0x71, 0x01, 0x88, 0x82, 0x14, 0x11, 0x43, 0x01, 0x80, 0x90, 0xe0, 0x00, 0x20, /// 0x1b10 + 0x70, 0x76, 0xa8, 0x7a, 0x03, 0x00, 0xff, 0xf7, 0xc1, 0xfc, 0x0b, 0x07, 0x8b, 0x47, 0x4c, 0x58, /// 0x1b20 + 0x70, 0x8b, 0x73, 0x76, 0x86, 0x89, 0x8b, 0x00, 0x42, 0x48, 0xff, 0x22, 0x5e, 0x38, 0x80, 0x8f, /// 0x1b30 + 0x01, 0x21, 0x25, 0x32, 0x49, 0x03, 0x08, 0x27, 0x90, 0x42, 0x20, 0xd9, 0x45, 0x4c, 0x01, 0x20, /// 0x1b40 + 0x20, 0x82, 0xa0, 0x8a, 0x08, 0x43, 0xa0, 0x82, 0x14, 0x20, 0xfe, 0xf7, 0x94, 0xff, 0xa0, 0x8b, /// 0x1b50 + 0x38, 0x43, 0xa0, 0x83, 0x14, 0x20, 0xfe, 0xf7, 0x8e, 0xff, 0xa0, 0x8b, 0x01, 0x21, 0x08, 0x43, /// 0x1b60 + 0xa0, 0x83, 0x14, 0x20, 0xfe, 0xf7, 0x87, 0xff, 0xa0, 0x8b, 0x40, 0x08, 0x40, 0x00, 0xa0, 0x83, /// 0x1b70 + 0x14, 0x20, 0xfe, 0xf7, 0x80, 0xff, 0xa0, 0x8b, 0xb8, 0x43, 0xa0, 0x83, 0x06, 0xe0, 0x35, 0x48, /// 0x1b80 + 0x82, 0x8b, 0xba, 0x43, 0x82, 0x83, 0x82, 0x8a, 0x8a, 0x43, 0x82, 0x82, 0x2a, 0x48, 0x80, 0x38, /// 0x1b90 + 0x00, 0x68, 0x1d, 0x28, 0x4c, 0xd9, 0x37, 0x75, 0x01, 0x99, 0x32, 0x20, 0xc8, 0x66, 0x02, 0x20, /// 0x1ba0 + 0xa8, 0x72, 0xff, 0xf7, 0xb9, 0xfd, 0x43, 0xe0, 0xff, 0xf7, 0xa4, 0xfd, 0x03, 0x20, 0xa8, 0x72, /// 0x1bb0 + 0x3e, 0xe0, 0x30, 0x20, 0xf8, 0x70, 0x1e, 0x20, 0x30, 0x75, 0xff, 0xf7, 0x8d, 0xfd, 0x04, 0x20, /// 0x1bc0 + 0xa8, 0x72, 0x00, 0x99, 0x01, 0x20, 0xc8, 0x71, 0x32, 0xe0, 0x00, 0x98, 0x00, 0x7a, 0xc0, 0x07, /// 0x1bd0 + 0x02, 0xd0, 0xff, 0xf7, 0x4b, 0xfd, 0x01, 0xe0, 0xff, 0xf7, 0x23, 0xfd, 0x15, 0x49, 0xff, 0x20, /// 0x1be0 + 0xf5, 0x30, 0x5e, 0x39, 0x48, 0x84, 0x00, 0x20, 0xb8, 0x64, 0x60, 0x71, 0xff, 0x20, 0x60, 0x30, /// 0x1bf0 + 0xe0, 0x81, 0xcd, 0x20, 0x00, 0x01, 0x08, 0x87, 0x1a, 0xe0, 0x01, 0xf0, 0x7f, 0xf9, 0x17, 0xe0, /// 0x1c00 + 0x01, 0xf0, 0x50, 0xf8, 0x14, 0xe0, 0x00, 0x98, 0x00, 0x7a, 0xc0, 0x07, 0x01, 0xd0, 0x09, 0x20, /// 0x1c10 + 0x00, 0xe0, 0x07, 0x20, 0xa8, 0x72, 0x08, 0x49, 0x00, 0x20, 0xe0, 0x31, 0xc8, 0x73, 0x02, 0x98, /// 0x1c20 + 0xb9, 0x68, 0x01, 0x67, 0x04, 0xe0, 0x00, 0xf0, 0x4c, 0xfb, 0x01, 0xe0, 0xff, 0xf7, 0xbd, 0xfc, /// 0x1c30 + 0x00, 0x20, 0xfe, 0xbd, 0x5e, 0x00, 0x00, 0x20, 0xb0, 0x02, 0x00, 0x20, 0x1b, 0x4e, 0x00, 0x00, /// 0x1c40 + 0xf8, 0x11, 0x00, 0x00, 0x28, 0x23, 0x00, 0x00, 0x7c, 0x05, 0x00, 0x00, 0xe0, 0x2e, 0x00, 0x00, /// 0x1c50 + 0xff, 0x07, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, 0xa0, 0x92, 0xff, 0xff, 0xf4, 0x30, 0x00, 0x00, /// 0x1c60 + 0x70, 0x17, 0x00, 0x00, 0x8a, 0x66, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, 0x5d, 0x20, 0x00, 0x00, /// 0x1c70 + 0x20, 0x38, 0x00, 0x40, 0x69, 0x60, 0x63, 0x02, 0x69, 0x60, 0x63, 0x24, 0xa8, 0x03, 0x19, 0x0c, /// 0x1c80 + 0xbb, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x06, 0x32, 0x04, /// 0x1c90 + 0x5d, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x01, 0xd2, /// 0x1ca0 + 0x01, 0x20, 0x70, 0x47, 0x80, 0x28, 0x03, 0xd2, 0x20, 0x38, 0x00, 0x11, 0x80, 0x1c, 0x70, 0x47, /// 0x1cb0 + 0xe0, 0x28, 0x03, 0xd2, 0x80, 0x38, 0xc0, 0x10, 0x08, 0x30, 0x70, 0x47, 0xe0, 0x38, 0x80, 0x10, /// 0x1cc0 + 0x14, 0x30, 0x70, 0x47, 0x41, 0x07, 0x89, 0x0f, 0x03, 0x29, 0x0b, 0xd1, 0x01, 0x07, 0x03, 0xd5, /// 0x1cd0 + 0x80, 0x09, 0x02, 0x28, 0x04, 0xd0, 0x05, 0xe0, 0x00, 0x09, 0x03, 0xd0, 0x0c, 0x28, 0x01, 0xd8, /// 0x1ce0 + 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x1e, 0x28, 0x08, 0xd0, 0xc1, 0x43, 0x09, 0x07, /// 0x1cf0 + 0x07, 0xd1, 0x01, 0x09, 0x06, 0x29, 0x04, 0xd2, 0x00, 0x06, 0x00, 0x0f, 0x01, 0xd0, 0x01, 0x20, /// 0x1d00 + 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x10, 0xb5, 0xfb, 0x48, 0xf7, 0x22, 0xc1, 0x79, 0x11, 0x40, /// 0x1d10 + 0xc1, 0x71, 0xf9, 0x49, 0x00, 0x20, 0x20, 0x39, 0x08, 0x85, 0x80, 0x20, 0xfe, 0xf7, 0xda, 0xfe, /// 0x1d20 + 0x10, 0xbd, 0xf8, 0xb5, 0xf5, 0x4a, 0x10, 0x7f, 0xff, 0xf7, 0xde, 0xff, 0xf4, 0x49, 0x87, 0x23, /// 0x1d30 + 0x09, 0x24, 0x9b, 0x00, 0xa4, 0x01, 0xcb, 0x18, 0x0e, 0x19, 0x00, 0x28, 0x18, 0xd0, 0xf0, 0x7b, /// 0x1d40 + 0x40, 0x1c, 0xc0, 0xb2, 0xf0, 0x73, 0x06, 0x28, 0x01, 0xd9, 0x06, 0x20, 0xf0, 0x73, 0xc2, 0xb2, /// 0x1d50 + 0xe9, 0x48, 0x19, 0x46, 0x38, 0x30, 0xfe, 0xf7, 0x9a, 0xfe, 0xe7, 0x48, 0x40, 0x22, 0x60, 0x30, /// 0x1d60 + 0x81, 0x78, 0x11, 0x43, 0x81, 0x70, 0xf0, 0x79, 0xef, 0x21, 0x08, 0x40, 0xf0, 0x71, 0xf8, 0xbd, /// 0x1d70 + 0xe1, 0x4c, 0x10, 0x7f, 0x20, 0x3c, 0x25, 0x46, 0x08, 0x27, 0x20, 0x35, 0x15, 0x28, 0x16, 0xd0, /// 0x1d80 + 0xff, 0xf7, 0xa0, 0xff, 0x01, 0x00, 0xdf, 0x48, 0x54, 0xd0, 0x11, 0x7f, 0xea, 0x79, 0xc9, 0x07, /// 0x1d90 + 0xd2, 0x07, 0xc9, 0x0f, 0xd2, 0x0f, 0x91, 0x42, 0x47, 0xd1, 0xeb, 0x7b, 0xf2, 0x7b, 0xaf, 0x7b, /// 0x1da0 + 0x99, 0x18, 0xb9, 0x42, 0x21, 0xd9, 0xe9, 0x73, 0x20, 0x8d, 0x02, 0x21, 0x3f, 0xe0, 0x50, 0x7f, /// 0x1db0 + 0x01, 0x06, 0x13, 0xd5, 0xe9, 0x79, 0x8a, 0x06, 0x92, 0x0f, 0x02, 0xd0, 0x20, 0x8d, 0x04, 0x21, /// 0x1dc0 + 0x35, 0xe0, 0x22, 0x8d, 0x40, 0x06, 0x3a, 0x43, 0x40, 0x0e, 0x22, 0x85, 0x40, 0x1c, 0xa8, 0x73, /// 0x1dd0 + 0x00, 0x20, 0xe8, 0x73, 0x48, 0x08, 0x40, 0x00, 0xe8, 0x71, 0xf8, 0xbd, 0x03, 0x28, 0x01, 0xd1, /// 0x1de0 + 0xff, 0xf7, 0x91, 0xff, 0x20, 0x8d, 0x38, 0x43, 0x22, 0xe0, 0xc4, 0x49, 0x18, 0x18, 0x1d, 0x31, /// 0x1df0 + 0xfe, 0xf7, 0x4d, 0xfe, 0xe8, 0x7b, 0xf1, 0x7b, 0x01, 0x22, 0x40, 0x18, 0xc1, 0xb2, 0xe9, 0x73, /// 0x1e00 + 0xe8, 0x79, 0x40, 0x23, 0x50, 0x40, 0xe8, 0x71, 0x22, 0x8d, 0x1a, 0x43, 0x22, 0x85, 0xbb, 0x4a, /// 0x1e10 + 0x32, 0x23, 0x80, 0x3a, 0xd3, 0x66, 0x05, 0x22, 0x32, 0x71, 0xaa, 0x7b, 0x91, 0x42, 0xdc, 0xd1, /// 0x1e20 + 0x10, 0x21, 0x08, 0x43, 0xe8, 0x71, 0x08, 0x46, 0x17, 0xe0, 0x20, 0x8d, 0x40, 0x21, 0x08, 0x43, /// 0x1e30 + 0x20, 0x85, 0xf8, 0xbd, 0xe9, 0x79, 0x89, 0x06, 0x89, 0x0f, 0xbf, 0xd1, 0x21, 0x8d, 0x39, 0x43, /// 0x1e40 + 0x21, 0x85, 0xf1, 0x7b, 0x49, 0x1c, 0xca, 0xb2, 0xaa, 0x73, 0x19, 0x46, 0xfe, 0xf7, 0x1f, 0xfe, /// 0x1e50 + 0xe8, 0x79, 0x20, 0x21, 0x08, 0x43, 0xe8, 0x71, 0x08, 0x46, 0xfe, 0xf7, 0x3b, 0xfe, 0xf8, 0xbd, /// 0x1e60 + 0xf8, 0xb5, 0xa5, 0x4c, 0x80, 0x27, 0x61, 0x7b, 0x22, 0x7b, 0x26, 0x46, 0x20, 0x3e, 0xe0, 0x79, /// 0x1e70 + 0x91, 0x42, 0x06, 0xd3, 0x31, 0x8d, 0xb9, 0x43, 0x31, 0x85, 0xf7, 0x21, 0x08, 0x40, 0xe0, 0x71, /// 0x1e80 + 0xf8, 0xbd, 0x52, 0x1a, 0xd5, 0xb2, 0x08, 0x2d, 0x00, 0xd9, 0x08, 0x25, 0x2a, 0x07, 0x13, 0x0e, /// 0x1e90 + 0x82, 0x07, 0x01, 0xd5, 0x07, 0x22, 0x00, 0xe0, 0x06, 0x22, 0x1a, 0x43, 0x02, 0x23, 0x58, 0x40, /// 0x1ea0 + 0xe0, 0x71, 0x96, 0x48, 0x20, 0x30, 0x02, 0x74, 0x95, 0x48, 0x2a, 0x46, 0x09, 0x18, 0x93, 0x48, /// 0x1eb0 + 0x31, 0x30, 0xfe, 0xf7, 0xec, 0xfd, 0x60, 0x7b, 0x32, 0x21, 0x40, 0x19, 0x60, 0x73, 0x30, 0x8d, /// 0x1ec0 + 0x38, 0x43, 0x30, 0x85, 0x8d, 0x48, 0x80, 0x38, 0xc1, 0x66, 0x8c, 0x49, 0x05, 0x20, 0x40, 0x31, /// 0x1ed0 + 0x08, 0x71, 0xf8, 0xbd, 0xf8, 0xb5, 0x89, 0x4c, 0x07, 0x46, 0x40, 0x34, 0xe0, 0x79, 0x00, 0x28, /// 0x1ee0 + 0x05, 0xd1, 0x00, 0x2f, 0x01, 0xd0, 0x02, 0x20, 0x00, 0xe0, 0x08, 0x20, 0xe0, 0x71, 0xc1, 0xb2, /// 0x1ef0 + 0xf8, 0x01, 0x83, 0x4b, 0x86, 0x46, 0x80, 0x48, 0xde, 0x1d, 0xff, 0x36, 0x20, 0x30, 0xfa, 0x36, /// 0x1f00 + 0x00, 0x89, 0x35, 0x8b, 0x00, 0x95, 0x09, 0x25, 0xad, 0x01, 0x5b, 0x19, 0x9d, 0x7b, 0x33, 0x7f, /// 0x1f10 + 0x8a, 0x07, 0x9c, 0x46, 0x00, 0x2a, 0x4b, 0xd0, 0x62, 0x46, 0x52, 0x08, 0x73, 0x46, 0x1a, 0x43, /// 0x1f20 + 0xd2, 0xb2, 0x32, 0x77, 0x00, 0x2d, 0x0a, 0xd0, 0x07, 0x2d, 0x10, 0xd3, 0xff, 0x2a, 0x11, 0xd0, /// 0x1f30 + 0x00, 0x2a, 0x38, 0xd0, 0x55, 0x2a, 0x38, 0xd0, 0xaa, 0x2a, 0x36, 0xd0, 0x82, 0xe0, 0x48, 0x21, /// 0x1f40 + 0x48, 0x43, 0x71, 0x49, 0xff, 0xf7, 0x80, 0xfa, 0x00, 0x99, 0x40, 0x18, 0x70, 0x83, 0x6d, 0x1c, /// 0x1f50 + 0xa5, 0x73, 0x81, 0xe0, 0x88, 0x07, 0x02, 0xd5, 0xff, 0xf7, 0x82, 0xff, 0x72, 0xe0, 0x66, 0x4d, /// 0x1f60 + 0x20, 0x3d, 0x6a, 0x8d, 0x00, 0x2a, 0x1c, 0xd0, 0xd0, 0x07, 0x02, 0xd0, 0xff, 0xf7, 0xcb, 0xfe, /// 0x1f70 + 0x11, 0xe0, 0x61, 0x48, 0x93, 0x06, 0xc1, 0x79, 0x00, 0x2b, 0x07, 0xda, 0x00, 0x22, 0x42, 0x73, /// 0x1f80 + 0xfd, 0x22, 0x11, 0x40, 0xc1, 0x71, 0xff, 0xf7, 0x6b, 0xff, 0x04, 0xe0, 0xd2, 0x06, 0x02, 0xd5, /// 0x1f90 + 0xf7, 0x22, 0x11, 0x40, 0xc1, 0x71, 0x28, 0x8d, 0x69, 0x8d, 0x88, 0x43, 0x28, 0x85, 0x00, 0x20, /// 0x1fa0 + 0x68, 0x85, 0x01, 0x20, 0x02, 0xe0, 0x02, 0x20, 0x00, 0xe0, 0x04, 0x20, 0x20, 0x72, 0x49, 0xe0, /// 0x1fb0 + 0xc9, 0x06, 0x49, 0x0f, 0x46, 0xd0, 0x51, 0x4a, 0x40, 0x32, 0xd1, 0x7b, 0x52, 0x7b, 0x00, 0x2d, /// 0x1fc0 + 0x13, 0xd0, 0x4e, 0x48, 0x1c, 0x30, 0x09, 0x2d, 0x25, 0xd0, 0x0a, 0x2d, 0x3c, 0xd3, 0x00, 0x2f, /// 0x1fd0 + 0x38, 0xd0, 0x00, 0x23, 0xa3, 0x73, 0x00, 0x2a, 0x25, 0xd0, 0x8a, 0x42, 0x27, 0xd9, 0x89, 0x1c, /// 0x1fe0 + 0xfe, 0xf7, 0x41, 0xfe, 0x00, 0x28, 0x26, 0xd0, 0x2c, 0xe0, 0x00, 0x2f, 0x2a, 0xd1, 0x01, 0x23, /// 0x1ff0 + 0xa3, 0x73, 0x00, 0x2a, 0x0c, 0xd0, 0x8a, 0x1a, 0x58, 0x21, 0x92, 0x1c, 0x4a, 0x43, 0x08, 0x32, /// 0x2000 + 0x50, 0x43, 0x41, 0x49, 0xff, 0xf7, 0x20, 0xfa, 0x00, 0x99, 0x40, 0x18, 0x70, 0x83, 0x23, 0xe0, /// 0x2010 + 0x60, 0x21, 0x48, 0x43, 0xf5, 0xe7, 0x0a, 0x21, 0xa1, 0x73, 0x10, 0x5c, 0xfe, 0xf7, 0x2c, 0xfe, /// 0x2020 + 0xb8, 0x42, 0x0f, 0xd0, 0x18, 0xe0, 0x60, 0x46, 0xff, 0xf7, 0x38, 0xfe, 0xe0, 0x73, 0x60, 0x7b, /// 0x2030 + 0x40, 0x1c, 0x60, 0x73, 0x10, 0xe0, 0xe0, 0x79, 0x40, 0x07, 0x01, 0xd5, 0x08, 0x20, 0xb5, 0xe7, /// 0x2040 + 0xff, 0xf7, 0x6f, 0xfe, 0x01, 0x20, 0xf8, 0xbd, 0x11, 0x5c, 0x73, 0x46, 0x49, 0x08, 0x19, 0x43, /// 0x2050 + 0x11, 0x54, 0xa0, 0x7b, 0x40, 0x1c, 0xa0, 0x73, 0x00, 0x20, 0xf8, 0xbd, 0xf8, 0xb5, 0x27, 0x4d, /// 0x2060 + 0x2a, 0x48, 0xa9, 0x8a, 0x2e, 0x46, 0x00, 0x27, 0x40, 0x3e, 0x81, 0x42, 0x09, 0xd1, 0x68, 0x8b, /// 0x2070 + 0x41, 0x1e, 0x69, 0x83, 0x03, 0xd3, 0x30, 0x7d, 0x40, 0x1e, 0xf0, 0x74, 0xed, 0xe0, 0xf7, 0x74, /// 0x2080 + 0xeb, 0xe0, 0x1e, 0x4c, 0x28, 0x8b, 0x40, 0x34, 0x00, 0x28, 0x06, 0xd1, 0x27, 0x72, 0x67, 0x73, /// 0x2090 + 0xa7, 0x73, 0x0f, 0x20, 0x68, 0x83, 0xfe, 0xf7, 0xdd, 0xfc, 0xa3, 0xe0, 0x41, 0x00, 0x18, 0x4a, /// 0x20a0 + 0x40, 0x1c, 0x89, 0x18, 0xff, 0x31, 0xc1, 0x31, 0x00, 0x07, 0x09, 0x8e, 0x00, 0x0f, 0x68, 0x74, /// 0x20b0 + 0xa8, 0x8a, 0x40, 0x1c, 0x80, 0xb2, 0xa8, 0x82, 0x03, 0x28, 0x2b, 0xd8, 0x01, 0x28, 0x06, 0xd0, /// 0x20c0 + 0xea, 0x8a, 0x51, 0x18, 0x89, 0xb2, 0xe9, 0x82, 0x03, 0x28, 0x05, 0xd1, 0x05, 0xe0, 0xef, 0x82, /// 0x20d0 + 0xe7, 0x72, 0xa7, 0x72, 0xa7, 0x74, 0xe7, 0x74, 0x84, 0xe0, 0x49, 0x1c, 0x06, 0x4a, 0x49, 0x08, /// 0x20e0 + 0xe9, 0x82, 0x20, 0x32, 0x00, 0x92, 0x11, 0x81, 0x09, 0x4a, 0x48, 0x08, 0x80, 0x18, 0xff, 0xf7, /// 0x20f0 + 0xab, 0xf9, 0x00, 0x9a, 0xd0, 0x83, 0x75, 0xe0, 0x20, 0x00, 0x00, 0x20, 0x30, 0x03, 0x00, 0x20, /// 0x2100 + 0x30, 0x01, 0x00, 0x20, 0xb0, 0x01, 0x00, 0x20, 0x70, 0x17, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, /// 0x2110 + 0x00, 0xdc, 0x05, 0x00, 0x52, 0x48, 0xc2, 0x7a, 0x06, 0x20, 0x93, 0x07, 0x9b, 0x0f, 0x98, 0x40, /// 0x2120 + 0x80, 0x1e, 0x52, 0x07, 0xea, 0x8a, 0x09, 0xd5, 0x13, 0x18, 0x8b, 0x42, 0x0f, 0xd3, 0x23, 0x7a, /// 0x2130 + 0x5b, 0x07, 0x2a, 0xd1, 0x10, 0x1a, 0x88, 0x42, 0x09, 0xd8, 0x26, 0xe0, 0x13, 0x1a, 0x8b, 0x42, /// 0x2140 + 0x05, 0xd8, 0x23, 0x7a, 0x5b, 0x07, 0x20, 0xd1, 0x10, 0x18, 0x88, 0x42, 0x1d, 0xd2, 0xe0, 0x7a, /// 0x2150 + 0x40, 0x1c, 0xc0, 0xb2, 0xe0, 0x72, 0x0a, 0x28, 0x53, 0xd8, 0xa0, 0x7c, 0x00, 0x28, 0x12, 0xd0, /// 0x2160 + 0xa0, 0x7a, 0x05, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x05, 0xe0, 0x02, 0x28, 0x0b, 0xd9, 0xe0, 0x7c, /// 0x2170 + 0x00, 0x28, 0x06, 0xd0, 0x01, 0x20, 0xff, 0xf7, 0xad, 0xfe, 0x00, 0x28, 0x41, 0xd1, 0xe7, 0x74, /// 0x2180 + 0x01, 0xe0, 0x01, 0x20, 0xe0, 0x74, 0xa7, 0x72, 0x2c, 0xe0, 0xa0, 0x7a, 0x40, 0x1c, 0xc0, 0xb2, /// 0x2190 + 0xa0, 0x72, 0xa1, 0x7c, 0x00, 0x29, 0x0c, 0xd0, 0xe1, 0x7c, 0x00, 0x29, 0x03, 0xd0, 0x05, 0x28, /// 0x21a0 + 0x0c, 0xd9, 0x01, 0x20, 0x02, 0xe0, 0x0a, 0x28, 0x08, 0xd9, 0x00, 0x20, 0xff, 0xf7, 0x92, 0xfe, /// 0x21b0 + 0x27, 0xe0, 0xe0, 0x7a, 0x02, 0x28, 0x01, 0xd9, 0x01, 0x20, 0xa0, 0x74, 0xe0, 0x7a, 0x05, 0x28, /// 0x21c0 + 0x01, 0xd9, 0x00, 0x20, 0x05, 0xe0, 0x02, 0x28, 0x0b, 0xd9, 0xe0, 0x7c, 0x00, 0x28, 0x06, 0xd0, /// 0x21d0 + 0x01, 0x20, 0xff, 0xf7, 0x7f, 0xfe, 0x00, 0x28, 0x13, 0xd1, 0xe7, 0x74, 0x01, 0xe0, 0x01, 0x20, /// 0x21e0 + 0xe0, 0x74, 0xe7, 0x72, 0x29, 0x7c, 0x68, 0x7c, 0x81, 0x42, 0x00, 0xd0, 0x56, 0xe7, 0x30, 0x7d, /// 0x21f0 + 0x40, 0x1e, 0xf0, 0x74, 0x28, 0x8b, 0x40, 0x1c, 0x80, 0xb2, 0x28, 0x83, 0x69, 0x8b, 0x88, 0x42, /// 0x2200 + 0x2b, 0xd9, 0xfe, 0xf7, 0x16, 0xfc, 0x00, 0x20, 0xc0, 0x43, 0xa8, 0x82, 0xe7, 0x71, 0x70, 0x7e, /// 0x2210 + 0x00, 0x28, 0x01, 0xd0, 0x16, 0x20, 0x00, 0xe0, 0x05, 0x20, 0x70, 0x76, 0x20, 0x7a, 0x00, 0x28, /// 0x2220 + 0x01, 0xd0, 0x70, 0x7e, 0x10, 0xe0, 0x68, 0x8b, 0x0f, 0x28, 0x04, 0xd9, 0x29, 0x8b, 0x40, 0x1a, /// 0x2230 + 0x71, 0x7e, 0x40, 0x18, 0x08, 0xe0, 0x28, 0x8b, 0x31, 0x7d, 0x02, 0x1d, 0x8a, 0x42, 0x02, 0xd2, /// 0x2240 + 0xc0, 0xb2, 0x08, 0x1a, 0x00, 0xe0, 0x04, 0x20, 0x68, 0x83, 0x28, 0x8b, 0x69, 0x8b, 0x42, 0x18, /// 0x2250 + 0x31, 0x7d, 0x8a, 0x42, 0x01, 0xd2, 0x08, 0x1a, 0x68, 0x83, 0x00, 0x20, 0xf8, 0xbd, 0x00, 0x00, /// 0x2260 + 0x80, 0x00, 0x00, 0x20, 0xf7, 0x49, 0xf8, 0x4a, 0x00, 0x20, 0x09, 0x6f, 0x92, 0x68, 0x06, 0xe0, /// 0x2270 + 0x0b, 0x46, 0x53, 0x40, 0x1b, 0x06, 0x00, 0xd0, 0x40, 0x1c, 0x09, 0x0a, 0x12, 0x0a, 0x0b, 0x46, /// 0x2280 + 0x13, 0x43, 0xf5, 0xd1, 0x70, 0x47, 0xef, 0x4a, 0x10, 0xb5, 0xf0, 0x4b, 0x80, 0x3a, 0x93, 0x86, /// 0x2290 + 0x20, 0x32, 0x90, 0x75, 0xd1, 0x75, 0x11, 0x46, 0x01, 0x20, 0xa0, 0x31, 0xc8, 0x71, 0x02, 0x20, /// 0x22a0 + 0xfe, 0xf7, 0x78, 0xfd, 0x10, 0xbd, 0xe7, 0x49, 0x10, 0xb5, 0xe9, 0x4a, 0x80, 0x39, 0x8a, 0x86, /// 0x22b0 + 0x20, 0x31, 0x88, 0x75, 0x04, 0x20, 0xa0, 0x31, 0xc8, 0x71, 0x01, 0x20, 0xfe, 0xf7, 0x6a, 0xfd, /// 0x22c0 + 0x10, 0xbd, 0xf8, 0xb5, 0x09, 0x21, 0xe3, 0x4b, 0xde, 0x4c, 0x89, 0x01, 0x5d, 0x18, 0x60, 0x34, /// 0x22d0 + 0xff, 0x33, 0xe0, 0x7b, 0xff, 0x33, 0x02, 0x26, 0xdb, 0x4a, 0x02, 0x33, 0x00, 0x28, 0x02, 0xd0, /// 0x22e0 + 0x01, 0x28, 0x0b, 0xd0, 0x3e, 0xe0, 0xd0, 0x79, 0xc0, 0x07, 0x05, 0xd0, 0x31, 0x20, 0xff, 0xf7, /// 0x22f0 + 0xda, 0xff, 0x01, 0x20, 0xe0, 0x73, 0xf8, 0xbd, 0xe6, 0x73, 0x0c, 0xe0, 0x28, 0x7a, 0x00, 0x07, /// 0x2300 + 0xfa, 0xd5, 0x18, 0x7f, 0x31, 0x28, 0xf7, 0xd1, 0x58, 0x7f, 0x10, 0x71, 0x98, 0x7f, 0x50, 0x71, /// 0x2310 + 0xd8, 0x7f, 0x90, 0x71, 0xf0, 0xe7, 0xe7, 0x7b, 0x78, 0x08, 0xf9, 0x07, 0x7f, 0x1c, 0xff, 0xb2, /// 0x2320 + 0xe7, 0x73, 0xbc, 0x46, 0xc8, 0x4f, 0x80, 0x3f, 0x00, 0x29, 0x0c, 0xd0, 0x29, 0x7a, 0xc9, 0x07, /// 0x2330 + 0x18, 0xd0, 0x39, 0x18, 0xc7, 0x4f, 0x80, 0x31, 0x38, 0x18, 0x13, 0x27, 0x7f, 0x01, 0x09, 0x7b, /// 0x2340 + 0xc0, 0x19, 0x01, 0x74, 0x0e, 0xe0, 0x3f, 0x18, 0x80, 0x37, 0x39, 0x7b, 0x3f, 0x7a, 0xb9, 0x42, /// 0x2350 + 0x05, 0xd0, 0xc2, 0x07, 0x00, 0xd1, 0x04, 0x20, 0xff, 0xf7, 0x95, 0xff, 0xf8, 0xbd, 0x60, 0x46, /// 0x2360 + 0x40, 0x1c, 0xe0, 0x73, 0xe0, 0x7b, 0x08, 0x28, 0xd5, 0xd3, 0x41, 0x1c, 0xe1, 0x73, 0x08, 0x28, /// 0x2370 + 0x06, 0xd0, 0x28, 0x7a, 0xc0, 0x07, 0x08, 0xd0, 0x18, 0x6f, 0x90, 0x60, 0xd6, 0x71, 0x06, 0xe0, /// 0x2380 + 0xff, 0xf7, 0x70, 0xff, 0xc1, 0xb2, 0x00, 0x20, 0xe6, 0xe7, 0x04, 0x20, 0xd0, 0x71, 0xad, 0x48, /// 0x2390 + 0x07, 0x21, 0xc0, 0x38, 0x81, 0x72, 0xf8, 0xbd, 0xaa, 0x48, 0x10, 0xb5, 0xae, 0x49, 0x80, 0x38, /// 0x23a0 + 0x41, 0x63, 0xa8, 0x49, 0x01, 0x20, 0x40, 0x31, 0xc8, 0x71, 0xfe, 0xf7, 0xf3, 0xfc, 0x10, 0xbd, /// 0x23b0 + 0xa4, 0x48, 0x10, 0xb5, 0xa9, 0x49, 0x80, 0x38, 0x81, 0x86, 0xa3, 0x48, 0x60, 0x38, 0x81, 0x7e, /// 0x23c0 + 0xa0, 0x48, 0x60, 0x38, 0x81, 0x75, 0x01, 0x20, 0xfe, 0xf7, 0xe4, 0xfc, 0x10, 0xbd, 0x9d, 0x48, /// 0x23d0 + 0x10, 0xb5, 0x20, 0x30, 0x00, 0x7c, 0xff, 0xf7, 0x61, 0xfc, 0x9a, 0x49, 0xc4, 0xb2, 0x30, 0x31, /// 0x23e0 + 0x08, 0x46, 0x62, 0x1c, 0x7b, 0x38, 0xfe, 0xf7, 0x52, 0xfb, 0x96, 0x48, 0x0c, 0x21, 0x60, 0x38, /// 0x23f0 + 0x01, 0x75, 0x20, 0x46, 0xfe, 0xf7, 0xce, 0xfc, 0x10, 0xbd, 0x92, 0x49, 0x10, 0xb5, 0x0c, 0x22, /// 0x2400 + 0x60, 0x39, 0x0a, 0x75, 0x15, 0x22, 0x4a, 0x75, 0x88, 0x75, 0x01, 0x20, 0xfe, 0xf7, 0xc2, 0xfc, /// 0x2410 + 0x10, 0xbd, 0x10, 0xb5, 0x8f, 0x48, 0x00, 0x78, 0xff, 0xf7, 0x40, 0xfc, 0x04, 0x46, 0x42, 0x1c, /// 0x2420 + 0x88, 0x48, 0x8c, 0x49, 0x4b, 0x38, 0xfe, 0xf7, 0x32, 0xfb, 0x86, 0x48, 0x0c, 0x21, 0x60, 0x38, /// 0x2430 + 0x01, 0x75, 0x20, 0x46, 0xfe, 0xf7, 0xae, 0xfc, 0x10, 0xbd, 0xf0, 0xb5, 0x82, 0x48, 0x01, 0x78, /// 0x2440 + 0x49, 0x06, 0x01, 0xd5, 0x00, 0x20, 0xf0, 0xbd, 0x01, 0x8a, 0x7f, 0x48, 0x40, 0x38, 0x00, 0x88, /// 0x2450 + 0x0b, 0x1a, 0x02, 0xd5, 0x01, 0x25, 0x59, 0x42, 0x01, 0xe0, 0x00, 0x25, 0x19, 0x46, 0x79, 0x48, /// 0x2460 + 0x04, 0x26, 0x60, 0x30, 0x42, 0x7e, 0x94, 0x08, 0x34, 0x1b, 0x4c, 0x43, 0x61, 0x09, 0x05, 0xd0, /// 0x2470 + 0x00, 0x2d, 0x01, 0xd0, 0x00, 0x24, 0x02, 0xe0, 0x02, 0x24, 0x00, 0xe0, 0x01, 0x24, 0x18, 0x26, /// 0x2480 + 0x86, 0x57, 0x02, 0x27, 0x7e, 0x40, 0x20, 0x27, 0xa6, 0x42, 0x05, 0xd1, 0x0f, 0x2a, 0x01, 0xd2, /// 0x2490 + 0x52, 0x1c, 0x0e, 0xe0, 0x87, 0x76, 0x0e, 0xe0, 0x86, 0x7e, 0x00, 0x2e, 0x0b, 0xd0, 0x76, 0x1e, /// 0x24a0 + 0x36, 0x06, 0x36, 0x0e, 0x86, 0x76, 0x06, 0xd1, 0x00, 0x2a, 0x04, 0xd0, 0xfc, 0x26, 0x52, 0x1e, /// 0x24b0 + 0x32, 0x40, 0x42, 0x76, 0xee, 0xe7, 0x04, 0x76, 0x00, 0x24, 0x00, 0x29, 0x0b, 0xd0, 0xc4, 0x75, /// 0x24c0 + 0x84, 0x75, 0x08, 0x22, 0x02, 0x75, 0x7f, 0x29, 0x00, 0xd9, 0x7f, 0x21, 0x00, 0x2d, 0x00, 0xd0, /// 0x24d0 + 0x49, 0x42, 0x48, 0xb2, 0xf0, 0xbd, 0x82, 0x7d, 0xd2, 0x18, 0x56, 0xb2, 0x86, 0x75, 0xc2, 0x7d, /// 0x24e0 + 0x52, 0x1c, 0xd3, 0xb2, 0xc3, 0x75, 0x9a, 0x07, 0xf0, 0xd1, 0x02, 0x7d, 0x96, 0x42, 0x02, 0xdd, /// 0x24f0 + 0x01, 0x21, 0x00, 0x25, 0x04, 0xe0, 0x57, 0x42, 0xbe, 0x42, 0x07, 0xda, 0x01, 0x21, 0x0d, 0x46, /// 0x2500 + 0x0c, 0x2b, 0x01, 0xd3, 0x52, 0x1c, 0x02, 0x75, 0x84, 0x75, 0xdc, 0xe7, 0xc4, 0x75, 0x43, 0x7d, /// 0x2510 + 0x5b, 0x1c, 0xdb, 0xb2, 0x43, 0x75, 0x20, 0x2b, 0xf6, 0xd9, 0x44, 0x75, 0x04, 0x2a, 0xf3, 0xd9, /// 0x2520 + 0x52, 0x1e, 0xf0, 0xe7, 0xf0, 0xb5, 0x48, 0x48, 0x4d, 0x49, 0x80, 0x38, 0x80, 0x8f, 0x46, 0x4e, /// 0x2530 + 0x48, 0x43, 0x8b, 0xb0, 0x00, 0x0c, 0x40, 0x3e, 0xb0, 0x87, 0x30, 0x88, 0x49, 0x49, 0x41, 0x43, /// 0x2540 + 0x09, 0x0c, 0xf1, 0x87, 0x48, 0x49, 0x88, 0x42, 0x05, 0xd2, 0x48, 0x48, 0x01, 0x8b, 0x3f, 0x22, /// 0x2550 + 0x12, 0x02, 0x91, 0x43, 0x01, 0x83, 0x3b, 0x4f, 0x3b, 0x4d, 0x40, 0x3f, 0x78, 0x7d, 0x80, 0x3d, /// 0x2560 + 0x42, 0x07, 0x3c, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x09, 0x91, 0x29, 0x46, 0x80, 0x31, 0x04, 0x46, /// 0x2570 + 0x07, 0x91, 0x13, 0x21, 0x49, 0x01, 0xff, 0x34, 0x40, 0x18, 0x81, 0x34, 0xa0, 0x35, 0x08, 0x90, /// 0x2580 + 0x00, 0x2a, 0x7b, 0xda, 0x70, 0x8f, 0xfe, 0xf7, 0x0d, 0xf9, 0x00, 0x90, 0xfe, 0xf7, 0x96, 0xf8, /// 0x2590 + 0xb0, 0x80, 0x07, 0x98, 0x00, 0x78, 0xc0, 0x07, 0x71, 0xd1, 0x00, 0x98, 0xfe, 0xf7, 0xc3, 0xfc, /// 0x25a0 + 0x28, 0x46, 0xa0, 0x38, 0xc1, 0x8f, 0x32, 0x48, 0x81, 0x42, 0x04, 0xd2, 0x13, 0x22, 0x52, 0x01, /// 0x25b0 + 0x05, 0x20, 0xc0, 0x01, 0x03, 0xe0, 0xff, 0x22, 0x61, 0x32, 0xff, 0x20, 0x81, 0x30, 0x84, 0x46, /// 0x25c0 + 0xb0, 0x88, 0x40, 0x28, 0x09, 0xd2, 0x2b, 0x4b, 0x9b, 0x88, 0x00, 0x2b, 0x05, 0xd0, 0x28, 0x4b, /// 0x25d0 + 0x99, 0x42, 0x02, 0xd3, 0x28, 0x4b, 0x99, 0x42, 0x08, 0xd3, 0x60, 0x28, 0x08, 0xd2, 0x25, 0x4b, /// 0x25e0 + 0x9b, 0x88, 0x00, 0x2b, 0x0f, 0xd0, 0x24, 0x4b, 0x99, 0x42, 0x0c, 0xd3, 0x00, 0x20, 0x53, 0xe0, /// 0x25f0 + 0x60, 0x28, 0x08, 0xd9, 0x90, 0x42, 0x06, 0xd2, 0x1e, 0x4b, 0x9b, 0x88, 0x01, 0x2b, 0x02, 0xd0, /// 0x2600 + 0x1d, 0x4b, 0x99, 0x42, 0x0a, 0xd3, 0x80, 0x28, 0x0c, 0xd9, 0x90, 0x42, 0x0a, 0xd2, 0x19, 0x4b, /// 0x2610 + 0x9b, 0x88, 0x01, 0x2b, 0x06, 0xd0, 0x18, 0x4b, 0x99, 0x42, 0x03, 0xd3, 0x15, 0x48, 0x01, 0x21, /// 0x2620 + 0x81, 0x80, 0x5e, 0xe0, 0x60, 0x45, 0x2e, 0xd9, 0x12, 0x4b, 0x99, 0x88, 0x03, 0x29, 0x2a, 0xd0, /// 0x2630 + 0x08, 0x98, 0xc0, 0x7e, 0x00, 0x28, 0x23, 0xd0, 0x08, 0x98, 0xc0, 0x7e, 0x08, 0x99, 0x40, 0x1e, /// 0x2640 + 0xc8, 0x76, 0x4e, 0xe0, 0x30, 0x03, 0x00, 0x20, 0x80, 0x00, 0x00, 0x20, 0x0c, 0x20, 0x00, 0x00, /// 0x2650 + 0x0c, 0x07, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, 0x0c, 0x09, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, /// 0x2660 + 0x80, 0x20, 0x05, 0x00, 0xa0, 0x68, 0x06, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, /// 0x2670 + 0x58, 0x1b, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, 0xc8, 0x32, 0x00, 0x00, 0x36, 0xe0, 0x32, 0xe0, /// 0x2680 + 0x03, 0x20, 0x98, 0x80, 0x2d, 0xe0, 0xfe, 0x49, 0x89, 0x88, 0x00, 0x29, 0x07, 0xd1, 0x90, 0x42, /// 0x2690 + 0x05, 0xd3, 0x60, 0x45, 0x03, 0xd8, 0x01, 0x20, 0xf9, 0x49, 0x88, 0x80, 0x21, 0xe0, 0xb8, 0x7d, /// 0x26a0 + 0xfe, 0xf7, 0xe6, 0xfb, 0xba, 0x7d, 0x0a, 0x2a, 0x01, 0xd2, 0x01, 0x20, 0x06, 0xe0, 0x0f, 0x2a, /// 0x26b0 + 0x01, 0xd3, 0x14, 0x2a, 0x01, 0xd2, 0x02, 0x20, 0x00, 0xe0, 0x03, 0x20, 0xf0, 0x49, 0x09, 0x88, /// 0x26c0 + 0xf8, 0x23, 0x99, 0x43, 0x83, 0x01, 0xc0, 0x00, 0x19, 0x43, 0x20, 0x30, 0x01, 0x43, 0xec, 0x48, /// 0x26d0 + 0x01, 0x80, 0xec, 0x48, 0x82, 0x72, 0xea, 0x48, 0x80, 0x89, 0x06, 0x21, 0x08, 0x43, 0xe8, 0x49, /// 0x26e0 + 0x88, 0x81, 0xfe, 0xf7, 0xe7, 0xfb, 0xff, 0xf7, 0xa8, 0xfe, 0x40, 0xe0, 0xff, 0xf7, 0xa5, 0xfe, /// 0x26f0 + 0x79, 0x7d, 0x8c, 0x46, 0x09, 0x07, 0x3a, 0xd4, 0x07, 0x99, 0xe3, 0x4b, 0x09, 0x8a, 0x99, 0x42, /// 0x2700 + 0x0f, 0xd8, 0x33, 0x88, 0x8b, 0x42, 0x06, 0xd8, 0x09, 0x99, 0xa3, 0x6e, 0x09, 0x68, 0xdf, 0x4a, /// 0x2710 + 0xc9, 0x1a, 0x91, 0x42, 0x03, 0xdb, 0x29, 0x7a, 0x10, 0x22, 0x11, 0x43, 0x0f, 0xe0, 0x37, 0x20, /// 0x2720 + 0x0e, 0xe0, 0x29, 0x7a, 0x8b, 0x07, 0x06, 0xd5, 0x09, 0x9b, 0xa2, 0x6e, 0x1b, 0x68, 0x9b, 0x1a, /// 0x2730 + 0xd6, 0x4a, 0x93, 0x42, 0x1b, 0xdb, 0x10, 0x22, 0x11, 0x43, 0x49, 0x08, 0x49, 0x00, 0x29, 0x72, /// 0x2740 + 0x29, 0x7a, 0x8a, 0x07, 0x13, 0xd4, 0xca, 0x06, 0x11, 0xd5, 0x08, 0x07, 0x03, 0xd5, 0xcd, 0x48, /// 0x2750 + 0xcf, 0x49, 0xa0, 0x38, 0x41, 0x82, 0x60, 0x46, 0x07, 0x21, 0x08, 0x43, 0x78, 0x75, 0x32, 0x20, /// 0x2760 + 0xe0, 0x66, 0x09, 0x98, 0x00, 0x68, 0x28, 0x38, 0x20, 0x66, 0x0b, 0xb0, 0xf0, 0xbd, 0xc5, 0x49, /// 0x2770 + 0x42, 0x1d, 0x60, 0x39, 0x0a, 0x2a, 0x02, 0xd9, 0x7a, 0x7d, 0x12, 0x07, 0x0a, 0xd5, 0x00, 0x22, /// 0x2780 + 0x8a, 0x71, 0x0a, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x52, 0x1e, 0x0a, 0x71, 0x09, 0xe0, 0x96, 0x22, /// 0x2790 + 0xe2, 0x66, 0x06, 0xe0, 0x32, 0x22, 0xe2, 0x66, 0x8a, 0x79, 0xff, 0x2a, 0x01, 0xd0, 0x52, 0x1c, /// 0x27a0 + 0x8a, 0x71, 0x2a, 0x7a, 0x94, 0x46, 0x12, 0x07, 0x15, 0xd5, 0x82, 0x1d, 0x0c, 0x2a, 0x06, 0xd8, /// 0x27b0 + 0x62, 0x46, 0x92, 0x07, 0x0b, 0xd5, 0x62, 0x46, 0x52, 0x08, 0x52, 0x00, 0x0a, 0xe0, 0xb1, 0x4a, /// 0x27c0 + 0x20, 0x3a, 0xd2, 0x7c, 0x03, 0x2a, 0x06, 0xd9, 0x62, 0x46, 0x92, 0x07, 0x03, 0xd4, 0x62, 0x46, /// 0x27d0 + 0xfb, 0x23, 0x1a, 0x40, 0x2a, 0x72, 0x07, 0x9a, 0x33, 0x88, 0x12, 0x8a, 0xff, 0x32, 0xd5, 0x32, /// 0x27e0 + 0x93, 0x42, 0x37, 0xd9, 0x0a, 0x7c, 0x0a, 0x2a, 0x03, 0xd3, 0x09, 0x98, 0x00, 0x68, 0x60, 0x66, /// 0x27f0 + 0xbb, 0xe7, 0x52, 0x1c, 0x0a, 0x74, 0xc3, 0x21, 0x89, 0x00, 0xa1, 0x86, 0xa5, 0x49, 0xc5, 0xb2, /// 0x2800 + 0x8d, 0x75, 0x00, 0x28, 0x01, 0xd0, 0x01, 0x20, 0x78, 0x76, 0xa2, 0x49, 0xc0, 0x39, 0x88, 0x7d, /// 0x2810 + 0x00, 0x28, 0x05, 0xd0, 0x08, 0x9a, 0x00, 0x20, 0xd0, 0x76, 0x32, 0x22, 0xe2, 0x66, 0x88, 0x75, /// 0x2820 + 0x01, 0x20, 0xfe, 0xf7, 0xb7, 0xfa, 0x9c, 0x48, 0x01, 0x8c, 0x49, 0x1c, 0x01, 0x84, 0x20, 0x30, /// 0x2830 + 0xc5, 0x74, 0x07, 0x98, 0x00, 0x78, 0x01, 0x07, 0x07, 0xd4, 0x71, 0x7b, 0x09, 0x07, 0x04, 0xd4, /// 0x2840 + 0x96, 0x49, 0x0a, 0x78, 0x04, 0x23, 0x1a, 0x43, 0x0a, 0x70, 0x08, 0x21, 0x08, 0x43, 0x07, 0x99, /// 0x2850 + 0x08, 0x70, 0x8a, 0xe7, 0x00, 0x22, 0xcd, 0xe7, 0x8f, 0x48, 0x10, 0xb5, 0x40, 0x30, 0x00, 0x7c, /// 0x2860 + 0xff, 0xf7, 0x1c, 0xfa, 0x04, 0x46, 0x42, 0x1c, 0x8b, 0x49, 0x8a, 0x48, 0x50, 0x31, 0x15, 0x30, /// 0x2870 + 0xfe, 0xf7, 0x0d, 0xf9, 0x87, 0x48, 0x0c, 0x21, 0x01, 0x75, 0x82, 0x49, 0x10, 0x20, 0x60, 0x39, /// 0x2880 + 0xc8, 0x71, 0x20, 0x46, 0xfe, 0xf7, 0x86, 0xfa, 0x10, 0xbd, 0xf0, 0xb5, 0x82, 0x4c, 0x89, 0xb0, /// 0x2890 + 0x80, 0x34, 0x20, 0x7e, 0x26, 0x46, 0x40, 0x1e, 0xc1, 0xb2, 0x7a, 0x48, 0x21, 0x76, 0x60, 0x38, /// 0x28a0 + 0x20, 0x36, 0x05, 0x90, 0x00, 0x29, 0x18, 0xd0, 0x7b, 0x4d, 0x9c, 0x20, 0x40, 0x5b, 0x40, 0x35, /// 0x28b0 + 0x08, 0x29, 0x40, 0xd3, 0x8a, 0x07, 0x0e, 0xd1, 0x62, 0x8b, 0x2b, 0x88, 0xd2, 0x18, 0x92, 0xb2, /// 0x28c0 + 0x62, 0x83, 0x6b, 0x8f, 0xc0, 0x18, 0x80, 0xb2, 0xa0, 0x83, 0x08, 0x29, 0x03, 0xd1, 0x11, 0x09, /// 0x28d0 + 0x61, 0x83, 0x00, 0x09, 0xa0, 0x83, 0x09, 0xb0, 0xf0, 0xbd, 0x02, 0x7a, 0x6e, 0x48, 0xfd, 0x21, /// 0x28e0 + 0xa0, 0x30, 0x00, 0x7a, 0xd3, 0x07, 0x01, 0x40, 0x00, 0x2b, 0x17, 0xd0, 0x02, 0x07, 0xf2, 0xd5, /// 0x28f0 + 0xc2, 0x07, 0x01, 0xd0, 0x40, 0x21, 0x0e, 0xe0, 0x82, 0x07, 0x01, 0xd5, 0x31, 0x72, 0xea, 0xe7, /// 0x2900 + 0x41, 0x07, 0x07, 0xd4, 0xf7, 0x21, 0x08, 0x40, 0x30, 0x72, 0x62, 0x48, 0x64, 0x49, 0x60, 0x30, /// 0x2910 + 0x41, 0x82, 0xe0, 0xe7, 0x80, 0x21, 0x08, 0x43, 0x30, 0x72, 0xdc, 0xe7, 0x92, 0x07, 0xda, 0xd5, /// 0x2920 + 0x02, 0x07, 0xd8, 0xd5, 0xc2, 0x07, 0xd6, 0xd1, 0x82, 0x07, 0xd4, 0xd5, 0x40, 0x06, 0xd2, 0xd5, /// 0x2930 + 0xbf, 0x20, 0x01, 0x40, 0xe2, 0xe7, 0x06, 0x29, 0xcd, 0xd8, 0xfd, 0xf7, 0x33, 0xff, 0xfd, 0xf7, /// 0x2940 + 0xbd, 0xfe, 0x07, 0x46, 0x60, 0x8b, 0x0b, 0x21, 0x09, 0x07, 0x40, 0x18, 0xfe, 0xf7, 0x9e, 0xfb, /// 0x2950 + 0x05, 0x21, 0x38, 0x46, 0x49, 0x07, 0x08, 0x43, 0xfe, 0xf7, 0x98, 0xfb, 0x4e, 0x48, 0x0d, 0x21, /// 0x2960 + 0x80, 0x8f, 0x09, 0x07, 0x40, 0x18, 0xfe, 0xf7, 0x91, 0xfb, 0x28, 0x89, 0x0f, 0x21, 0x09, 0x07, /// 0x2970 + 0x40, 0x18, 0xfe, 0xf7, 0x8b, 0xfb, 0x68, 0x8f, 0xfd, 0xf7, 0x14, 0xff, 0xfd, 0xf7, 0x9e, 0xfe, /// 0x2980 + 0x44, 0x49, 0x40, 0x09, 0x20, 0x31, 0x00, 0x28, 0x0a, 0xd0, 0x20, 0x28, 0x01, 0xd3, 0x1f, 0x20, /// 0x2990 + 0x06, 0xe0, 0x8a, 0x7d, 0x82, 0x42, 0x01, 0xd2, 0x40, 0x1e, 0x01, 0xe0, 0x82, 0x42, 0x00, 0xd9, /// 0x29a0 + 0x88, 0x75, 0x88, 0x7d, 0xfe, 0xf7, 0x64, 0xfa, 0x3e, 0x48, 0x01, 0x88, 0xc9, 0x04, 0x05, 0xd5, /// 0x29b0 + 0x40, 0x79, 0xc0, 0x06, 0xc0, 0x0e, 0xc1, 0x00, 0x08, 0x1a, 0xc7, 0x19, 0x60, 0x8b, 0x69, 0x21, /// 0x29c0 + 0x79, 0x43, 0x48, 0x43, 0x80, 0x0b, 0x00, 0x90, 0x00, 0x20, 0x60, 0x83, 0xa0, 0x83, 0x07, 0x21, /// 0x29d0 + 0x00, 0x98, 0x49, 0x07, 0x08, 0x43, 0xfe, 0xf7, 0x59, 0xfb, 0x33, 0x48, 0x80, 0x8b, 0xc0, 0x07, /// 0x29e0 + 0x13, 0xd0, 0x27, 0x48, 0x81, 0x88, 0xc9, 0x43, 0x8a, 0x07, 0x26, 0x49, 0x00, 0x2a, 0x14, 0xd0, /// 0x29f0 + 0x80, 0x88, 0xc0, 0x07, 0x1c, 0xd0, 0x28, 0x48, 0x2c, 0x4a, 0xc0, 0x8f, 0x90, 0x42, 0x02, 0xd2, /// 0x2a00 + 0x88, 0x7a, 0x09, 0x28, 0x03, 0xd2, 0x01, 0x20, 0x12, 0xe0, 0x07, 0x20, 0x10, 0xe0, 0x0f, 0x28, /// 0x2a10 + 0x01, 0xd2, 0x02, 0x20, 0x0c, 0xe0, 0x03, 0x20, 0x0a, 0xe0, 0x25, 0x48, 0x87, 0x42, 0x01, 0xd9, /// 0x2a20 + 0x05, 0x20, 0x05, 0xe0, 0x88, 0x7a, 0x11, 0x28, 0xf3, 0xd3, 0x14, 0x28, 0xf3, 0xd3, 0x04, 0x20, /// 0x2a30 + 0x60, 0x76, 0xc0, 0xb2, 0x18, 0x49, 0x42, 0x00, 0x53, 0x18, 0x60, 0x33, 0x19, 0x7a, 0x00, 0x9a, /// 0x2a40 + 0x51, 0x43, 0xca, 0x09, 0x0f, 0x49, 0x20, 0x39, 0x07, 0x28, 0x02, 0xd0, 0x09, 0x20, 0x18, 0x56, /// 0x2a50 + 0x51, 0xe0, 0x11, 0x48, 0x63, 0x8c, 0x6e, 0x30, 0x28, 0x2b, 0x03, 0xd0, 0x05, 0x27, 0xff, 0x02, /// 0x2a60 + 0xbb, 0x42, 0x4a, 0xd1, 0xeb, 0x8b, 0x7b, 0x3b, 0x07, 0x2b, 0x46, 0xd2, 0x33, 0x7a, 0x9b, 0x07, /// 0x2a70 + 0x43, 0xd5, 0xc0, 0x23, 0x5a, 0x43, 0x8b, 0x7c, 0xd2, 0x09, 0x04, 0x2b, 0x20, 0xd2, 0x19, 0xe0, /// 0x2a80 + 0x00, 0x34, 0x00, 0x40, 0xd0, 0x03, 0x00, 0x20, 0x92, 0x04, 0x00, 0x00, 0x88, 0x13, 0x00, 0x00, /// 0x2a90 + 0x6c, 0x07, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x40, 0x6c, 0x00, 0x40, /// 0x2aa0 + 0xdc, 0x05, 0x00, 0x00, 0x20, 0x38, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, 0x58, 0x1b, 0x00, 0x00, /// 0x2ab0 + 0x52, 0x03, 0x00, 0x00, 0x40, 0x7a, 0x0a, 0x25, 0x5b, 0x1c, 0x6b, 0x43, 0x58, 0x43, 0x00, 0xe0, /// 0x2ac0 + 0xfc, 0x48, 0x85, 0x18, 0x00, 0xd5, 0x00, 0x25, 0xfc, 0x4f, 0xfb, 0x4a, 0x38, 0x46, 0x95, 0x84, /// 0x2ad0 + 0xff, 0x30, 0x23, 0x7a, 0x81, 0x30, 0xff, 0x37, 0xa1, 0x37, 0x06, 0x90, 0x31, 0x2b, 0x0e, 0xd0, /// 0x2ae0 + 0x00, 0x20, 0x20, 0x76, 0xf6, 0x49, 0x90, 0x8f, 0x88, 0x42, 0x3a, 0xd8, 0xf5, 0x48, 0x85, 0x42, /// 0x2af0 + 0x49, 0xd9, 0x05, 0x46, 0x47, 0xe0, 0x0a, 0x23, 0xe0, 0xe7, 0x40, 0x7a, 0xfb, 0xe7, 0x01, 0x20, /// 0x2b00 + 0x20, 0x76, 0x05, 0x9a, 0xd0, 0x71, 0x30, 0x7a, 0x02, 0x07, 0x0b, 0xd5, 0x80, 0x07, 0x04, 0xd5, /// 0x2b10 + 0x88, 0x7c, 0x01, 0x26, 0x40, 0x1c, 0x88, 0x74, 0x05, 0xe0, 0xc8, 0x7c, 0x02, 0x26, 0x40, 0x1c, /// 0x2b20 + 0xc8, 0x74, 0x00, 0xe0, 0x00, 0x26, 0x20, 0x78, 0x00, 0x06, 0x00, 0xd5, 0x6d, 0x08, 0x03, 0x21, /// 0x2b30 + 0x28, 0x46, 0x89, 0x07, 0x08, 0x43, 0xfe, 0xf7, 0xa9, 0xfa, 0xa1, 0x7a, 0x7d, 0x20, 0xc0, 0x00, /// 0x2b40 + 0x41, 0x43, 0x28, 0x04, 0xfe, 0xf7, 0x80, 0xfc, 0xdf, 0x49, 0x88, 0x42, 0x00, 0xd9, 0x08, 0x46, /// 0x2b50 + 0x06, 0x99, 0xde, 0x4a, 0x8a, 0x86, 0xbe, 0x75, 0x01, 0x0a, 0xf9, 0x75, 0x38, 0x76, 0x03, 0x20, /// 0x2b60 + 0x21, 0xe0, 0xdb, 0x48, 0x85, 0x42, 0x00, 0xd9, 0x05, 0x46, 0xda, 0x48, 0xad, 0x08, 0x01, 0x8a, /// 0x2b70 + 0x09, 0x0a, 0x39, 0x29, 0x07, 0xd0, 0x01, 0x8a, 0xc9, 0xb2, 0x01, 0x82, 0x01, 0x8a, 0x39, 0x22, /// 0x2b80 + 0x12, 0x02, 0x11, 0x43, 0x01, 0x82, 0x03, 0x21, 0x28, 0x46, 0x89, 0x07, 0x08, 0x43, 0xfe, 0xf7, /// 0x2b90 + 0x7d, 0xfa, 0xc8, 0x49, 0xe8, 0x01, 0x6e, 0x39, 0xfe, 0xf7, 0x56, 0xfc, 0x06, 0x99, 0xce, 0x4a, /// 0x2ba0 + 0x8a, 0x86, 0xb8, 0x75, 0x01, 0x20, 0xfe, 0xf7, 0xf5, 0xf8, 0x94, 0xe6, 0xf8, 0xb5, 0xc2, 0x4d, /// 0x2bb0 + 0xca, 0x49, 0x40, 0x35, 0x28, 0x88, 0x48, 0x43, 0xc9, 0x49, 0x88, 0x42, 0x3a, 0xd8, 0xc9, 0x4a, /// 0x2bc0 + 0xc9, 0x4c, 0x51, 0x7d, 0xc8, 0x43, 0x83, 0x07, 0xbb, 0x48, 0x11, 0xd1, 0x86, 0x8f, 0xff, 0x27, /// 0x2bd0 + 0x25, 0x37, 0x63, 0x14, 0xbe, 0x42, 0x08, 0xd9, 0xa1, 0x8a, 0x19, 0x43, 0xa1, 0x82, 0x01, 0x8f, /// 0x2be0 + 0x08, 0x22, 0x11, 0x43, 0x01, 0x87, 0x10, 0x46, 0x59, 0xe0, 0xa6, 0x8a, 0x9e, 0x43, 0xa6, 0x82, /// 0x2bf0 + 0x49, 0x1e, 0xcb, 0xb2, 0xb0, 0x49, 0x53, 0x75, 0x9a, 0x07, 0x01, 0x26, 0xc0, 0x31, 0x00, 0x2a, /// 0x2c00 + 0x19, 0xda, 0x20, 0x8a, 0x48, 0x87, 0x80, 0xb2, 0xcb, 0x28, 0x01, 0xd9, 0xcb, 0x20, 0x20, 0x82, /// 0x2c10 + 0xa0, 0x8b, 0x08, 0x21, 0x08, 0x43, 0xa0, 0x83, 0x64, 0x20, 0xfd, 0xf7, 0x2c, 0xff, 0x68, 0x7b, /// 0x2c20 + 0x00, 0x07, 0x04, 0xd4, 0xb1, 0x48, 0x01, 0x78, 0x04, 0x22, 0x11, 0x43, 0x01, 0x70, 0xa0, 0x8b, /// 0x2c30 + 0x30, 0x43, 0xa0, 0x83, 0xf8, 0xbd, 0xa0, 0x49, 0xdd, 0x07, 0xc0, 0x31, 0x49, 0x8f, 0x3f, 0x23, /// 0x2c40 + 0x01, 0x27, 0x0a, 0x46, 0x1b, 0x02, 0x39, 0x43, 0x00, 0x2d, 0x11, 0xd0, 0xa8, 0x4d, 0xaa, 0x42, /// 0x2c50 + 0x00, 0xd9, 0x29, 0x46, 0x21, 0x82, 0x21, 0x8b, 0x01, 0x22, 0x99, 0x43, 0x12, 0x03, 0x89, 0x18, /// 0x2c60 + 0x21, 0x83, 0xc0, 0x8f, 0xa3, 0x49, 0x88, 0x42, 0xe4, 0xd2, 0x9a, 0x48, 0x86, 0x80, 0xf8, 0xbd, /// 0x2c70 + 0x21, 0x82, 0x21, 0x8b, 0x03, 0x22, 0x99, 0x43, 0x12, 0x03, 0x89, 0x18, 0x21, 0x83, 0xa1, 0x8b, /// 0x2c80 + 0x01, 0x22, 0x52, 0x02, 0x11, 0x43, 0xa1, 0x83, 0x8b, 0x49, 0x10, 0x23, 0x80, 0x31, 0x0a, 0x78, /// 0x2c90 + 0x1a, 0x43, 0x0a, 0x70, 0x81, 0x8e, 0x40, 0x22, 0x11, 0x43, 0x81, 0x86, 0x10, 0x46, 0xfd, 0xf7, /// 0x2ca0 + 0x19, 0xff, 0xf8, 0xbd, 0xf8, 0xb5, 0x8f, 0x48, 0x40, 0x7d, 0x80, 0x07, 0x02, 0xd0, 0xff, 0xf7, /// 0x2cb0 + 0x7d, 0xff, 0xf8, 0xbd, 0x80, 0x48, 0x80, 0x30, 0x01, 0x7e, 0x00, 0x29, 0x02, 0xd0, 0xff, 0xf7, /// 0x2cc0 + 0xe4, 0xfd, 0xf8, 0xbd, 0x87, 0x4e, 0x12, 0x24, 0xc0, 0x3e, 0x35, 0x46, 0x80, 0x35, 0x31, 0x68, /// 0x2cd0 + 0x6a, 0x6e, 0x8b, 0x1a, 0x2a, 0x46, 0x80, 0x32, 0x14, 0x5f, 0x94, 0x46, 0xa3, 0x42, 0x03, 0xdb, /// 0x2ce0 + 0x69, 0x66, 0x48, 0x21, 0x01, 0x76, 0xea, 0xe7, 0x2a, 0x6e, 0x7e, 0x4c, 0xeb, 0x6e, 0x8a, 0x1a, /// 0x2cf0 + 0x80, 0x34, 0x9a, 0x42, 0x42, 0xdb, 0x29, 0x66, 0x01, 0x78, 0x00, 0x27, 0x0b, 0x07, 0x6e, 0x49, /// 0x2d00 + 0x32, 0x22, 0x80, 0x31, 0x49, 0x78, 0x00, 0x2b, 0x14, 0xda, 0x0b, 0x07, 0x12, 0xd5, 0xf7, 0x23, /// 0x2d10 + 0x19, 0x40, 0x10, 0x23, 0x19, 0x43, 0x41, 0x70, 0x67, 0x48, 0xc0, 0x30, 0x87, 0x81, 0x80, 0x38, /// 0x2d20 + 0x00, 0x7c, 0x48, 0x28, 0x03, 0xd0, 0xea, 0x66, 0xff, 0xf7, 0x96, 0xfd, 0xf8, 0xbd, 0x5a, 0x20, /// 0x2d30 + 0xe8, 0x66, 0xf9, 0xe7, 0x8b, 0x06, 0x07, 0xd5, 0xdf, 0x23, 0x19, 0x40, 0x41, 0x70, 0xff, 0x20, /// 0x2d40 + 0xea, 0x66, 0xfe, 0xf7, 0x57, 0xfb, 0xf8, 0xbd, 0x5b, 0x48, 0x00, 0x8d, 0x00, 0x28, 0x0a, 0xd0, /// 0x2d50 + 0x60, 0x79, 0x07, 0x28, 0x07, 0xd2, 0xa0, 0x79, 0x0a, 0x28, 0x13, 0xd2, 0xff, 0xf7, 0x6d, 0xfb, /// 0x2d60 + 0xc0, 0x1d, 0x0e, 0x28, 0x0a, 0xd9, 0x67, 0x71, 0x20, 0x79, 0x00, 0x28, 0x01, 0xd0, 0x40, 0x1e, /// 0x2d70 + 0x20, 0x71, 0x30, 0x68, 0x28, 0x66, 0xff, 0xf7, 0xd5, 0xfb, 0xf8, 0xbd, 0x4e, 0x48, 0x00, 0x8d, /// 0x2d80 + 0x00, 0x28, 0xfa, 0xd0, 0x60, 0x79, 0x4c, 0x49, 0x40, 0x1c, 0x60, 0x71, 0x08, 0x8d, 0x0a, 0x46, /// 0x2d90 + 0x83, 0x06, 0x20, 0x32, 0x00, 0x2b, 0x36, 0xd0, 0xc7, 0x07, 0x01, 0x23, 0x00, 0x2f, 0x03, 0xd0, /// 0x2da0 + 0x4b, 0x85, 0xe3, 0x71, 0x03, 0x20, 0x43, 0xe0, 0x87, 0x07, 0x04, 0xd5, 0x02, 0x20, 0x48, 0x85, /// 0x2db0 + 0xe3, 0x71, 0x05, 0x20, 0x3c, 0xe0, 0x47, 0x07, 0x04, 0xd5, 0x04, 0x22, 0x90, 0x43, 0x08, 0x85, /// 0x2dc0 + 0x02, 0x20, 0x35, 0xe0, 0x07, 0x07, 0x04, 0xd5, 0x08, 0x22, 0x90, 0x43, 0x08, 0x85, 0x01, 0x20, /// 0x2dd0 + 0x2e, 0xe0, 0xc7, 0x06, 0x0c, 0xd5, 0x92, 0x79, 0x52, 0x06, 0x03, 0xd5, 0x10, 0x20, 0x48, 0x85, /// 0x2de0 + 0xe3, 0x71, 0x02, 0xe0, 0x10, 0x22, 0x90, 0x43, 0x08, 0x85, 0xff, 0xf7, 0x12, 0xfb, 0xf8, 0xbd, /// 0x2df0 + 0x87, 0x06, 0x08, 0xd5, 0x20, 0x20, 0x48, 0x85, 0xe3, 0x71, 0x10, 0x7b, 0x80, 0x21, 0x40, 0x1e, /// 0x2e00 + 0x08, 0x43, 0xc0, 0xb2, 0x14, 0xe0, 0xc0, 0x23, 0x03, 0x40, 0x1b, 0xd0, 0x40, 0x24, 0xc0, 0x2b, /// 0x2e10 + 0x05, 0xd1, 0xd3, 0x79, 0x5b, 0x07, 0x01, 0xd5, 0x40, 0x23, 0x00, 0xe0, 0x80, 0x23, 0x5b, 0x06, /// 0x2e20 + 0x09, 0xd5, 0xa0, 0x43, 0x08, 0x85, 0xd0, 0x79, 0xfb, 0x21, 0x08, 0x40, 0xd0, 0x71, 0x06, 0x20, /// 0x2e30 + 0xff, 0xf7, 0xe3, 0xfa, 0xf8, 0xbd, 0xd0, 0x79, 0x04, 0x21, 0x08, 0x43, 0xd0, 0x71, 0xff, 0xf7, /// 0x2e40 + 0xc6, 0xfa, 0xf8, 0xbd, 0xc2, 0x05, 0x06, 0xd5, 0xff, 0x22, 0x01, 0x32, 0x90, 0x43, 0x08, 0x85, /// 0x2e50 + 0xff, 0xf7, 0xae, 0xfa, 0xf8, 0xbd, 0x82, 0x05, 0xfc, 0xd5, 0x32, 0x68, 0x2b, 0x6e, 0xd3, 0x1a, /// 0x2e60 + 0x64, 0x2b, 0xf7, 0xda, 0x6b, 0x6e, 0x12, 0x24, 0x9b, 0x1a, 0x62, 0x46, 0x14, 0x5f, 0x1a, 0x19, /// 0x2e70 + 0xff, 0x23, 0x5f, 0x33, 0x9a, 0x42, 0xed, 0xdd, 0x01, 0x22, 0x52, 0x02, 0x90, 0x43, 0x08, 0x85, /// 0x2e80 + 0x18, 0x49, 0x08, 0x20, 0x80, 0x39, 0x88, 0x72, 0xff, 0xf7, 0x86, 0xfa, 0xf8, 0xbd, 0x15, 0x48, /// 0x2e90 + 0x10, 0xb5, 0x19, 0x49, 0x40, 0x38, 0x41, 0x63, 0x07, 0x48, 0x80, 0x30, 0xc1, 0x78, 0x11, 0x48, /// 0x2ea0 + 0x20, 0x38, 0xc1, 0x75, 0x0f, 0x49, 0x01, 0x20, 0x80, 0x31, 0xc8, 0x71, 0x02, 0x20, 0xfd, 0xf7, /// 0x2eb0 + 0x71, 0xff, 0x10, 0xbd, 0xf6, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, /// 0x2ec0 + 0x79, 0x06, 0x00, 0x00, 0xe8, 0x26, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x31, 0x00, 0x00, /// 0x2ed0 + 0x58, 0x98, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, 0x0c, 0x04, 0x00, 0x00, 0x41, 0x0a, 0x00, 0x00, /// 0x2ee0 + 0xff, 0x8f, 0x70, 0x00, 0xf0, 0x02, 0x00, 0x20, 0x00, 0x30, 0x00, 0x40, 0x40, 0x6c, 0x00, 0x40, /// 0x2ef0 + 0xe3, 0x02, 0x00, 0x00, 0x58, 0x1b, 0x00, 0x00, 0x0c, 0x22, 0x00, 0x00, 0xf0, 0xb5, 0x09, 0x21, /// 0x2f00 + 0x71, 0x4a, 0x89, 0x01, 0x6f, 0x4c, 0x51, 0x18, 0x0d, 0x7a, 0x20, 0x7e, 0x13, 0x21, 0x49, 0x01, /// 0x2f10 + 0xc3, 0x07, 0x52, 0x18, 0x87, 0xb0, 0x00, 0x2b, 0x0e, 0xd0, 0x00, 0x2d, 0x0c, 0xd1, 0xd1, 0x7b, /// 0x2f20 + 0x49, 0x1c, 0xc9, 0xb2, 0xd1, 0x73, 0x03, 0x29, 0x02, 0xd2, 0x40, 0x1e, 0x20, 0x76, 0x03, 0xe0, /// 0x2f30 + 0x40, 0x1c, 0x20, 0x76, 0x00, 0x20, 0xd0, 0x73, 0x62, 0x4e, 0x27, 0x7e, 0x40, 0x36, 0x30, 0x7f, /// 0x2f40 + 0x05, 0x90, 0x70, 0x7f, 0x01, 0x90, 0x61, 0x48, 0x01, 0x46, 0xa0, 0x31, 0x80, 0x30, 0x00, 0x91, /// 0x2f50 + 0xc1, 0x7b, 0x04, 0x91, 0x81, 0x7b, 0x02, 0x91, 0x41, 0x7b, 0x03, 0x7b, 0x03, 0x93, 0x3b, 0x00, /// 0x2f60 + 0xfe, 0xf7, 0x9c, 0xfa, 0x11, 0x0a, 0x0d, 0x13, 0x15, 0x1f, 0x23, 0x36, 0x3e, 0x43, 0x4a, 0x60, /// 0x2f70 + 0x68, 0x6d, 0x78, 0x7d, 0x82, 0xa9, 0xab, 0x00, 0xff, 0xf7, 0x89, 0xff, 0x9d, 0xe0, 0xa8, 0x07, /// 0x2f80 + 0x00, 0xd5, 0xfe, 0xe7, 0x00, 0x20, 0xd0, 0x73, 0x97, 0xe0, 0x30, 0x20, 0x0a, 0xe0, 0x05, 0x99, /// 0x2f90 + 0x30, 0x29, 0xf7, 0xd1, 0x00, 0x99, 0x01, 0x9b, 0x4b, 0x72, 0xf1, 0x8b, 0x49, 0xba, 0x41, 0x84, /// 0x2fa0 + 0xf0, 0xe7, 0x31, 0x20, 0xff, 0xf7, 0x7f, 0xf9, 0x87, 0xe0, 0x05, 0x9b, 0x31, 0x2b, 0xe9, 0xd1, /// 0x2fb0 + 0x01, 0x9d, 0x05, 0x71, 0xb3, 0x7f, 0x43, 0x71, 0xf6, 0x7f, 0x86, 0x71, 0x8d, 0x42, 0x02, 0xd2, /// 0x2fc0 + 0x8b, 0x42, 0x00, 0xd2, 0x43, 0x73, 0x02, 0x99, 0x8b, 0x42, 0xdb, 0xd2, 0x83, 0x73, 0xd9, 0xe7, /// 0x2fd0 + 0x00, 0x7a, 0x03, 0x99, 0x81, 0x42, 0x01, 0xd0, 0x02, 0x20, 0x35, 0xe0, 0x07, 0x20, 0x37, 0xe0, /// 0x2fe0 + 0xe8, 0x07, 0xcf, 0xd0, 0x03, 0x98, 0x10, 0x74, 0xcc, 0xe7, 0x40, 0x7a, 0x81, 0x42, 0x01, 0xd0, /// 0x2ff0 + 0x01, 0x20, 0x29, 0xe0, 0x09, 0x20, 0x2b, 0xe0, 0x34, 0x4b, 0xed, 0x07, 0x80, 0x33, 0x1b, 0x79, /// 0x3000 + 0x00, 0x2d, 0x09, 0xd0, 0x51, 0x74, 0x8b, 0x42, 0x00, 0xd2, 0x01, 0x71, 0x41, 0x8c, 0x27, 0x29, /// 0x3010 + 0xb8, 0xd1, 0x04, 0x21, 0x01, 0x71, 0xb5, 0xe7, 0x99, 0x42, 0xb3, 0xd9, 0x43, 0x73, 0x08, 0x20, /// 0x3020 + 0x20, 0x76, 0xaf, 0xe7, 0x80, 0x7a, 0x02, 0x99, 0x81, 0x42, 0x01, 0xd0, 0x04, 0x20, 0x0b, 0xe0, /// 0x3030 + 0x0b, 0x20, 0x0d, 0xe0, 0xe8, 0x07, 0xa5, 0xd0, 0x02, 0x98, 0x90, 0x74, 0xa2, 0xe7, 0xc0, 0x7a, /// 0x3040 + 0x04, 0x99, 0x81, 0x42, 0x03, 0xd0, 0x03, 0x20, 0xff, 0xf7, 0x1d, 0xf9, 0x35, 0xe0, 0x0d, 0x20, /// 0x3050 + 0x20, 0x76, 0x32, 0xe0, 0xe8, 0x07, 0x95, 0xd0, 0x04, 0x98, 0xd0, 0x74, 0x92, 0xe7, 0xff, 0xf7, /// 0x3060 + 0x01, 0xf9, 0xc1, 0xb2, 0x00, 0x20, 0xef, 0xe7, 0xe9, 0x07, 0x1d, 0xd0, 0x31, 0x6f, 0x81, 0x60, /// 0x3070 + 0xff, 0x20, 0xb7, 0x30, 0x70, 0x82, 0x13, 0x48, 0x12, 0x49, 0xc0, 0x38, 0x00, 0x68, 0x40, 0x39, /// 0x3080 + 0x02, 0x46, 0xff, 0x3a, 0x2d, 0x3a, 0x4a, 0x66, 0x88, 0x66, 0xca, 0x6e, 0x80, 0x1a, 0x08, 0x66, /// 0x3090 + 0x07, 0x20, 0x40, 0x39, 0x88, 0x72, 0x00, 0x99, 0x0f, 0x20, 0x08, 0x72, 0x0c, 0x48, 0x01, 0x78, /// 0x30a0 + 0x04, 0x22, 0x11, 0x43, 0x01, 0x70, 0x08, 0xe0, 0xa9, 0x07, 0x06, 0xd5, 0x80, 0x68, 0x30, 0x67, /// 0x30b0 + 0x00, 0x20, 0xd0, 0x73, 0x03, 0xe0, 0xfe, 0xf7, 0xb4, 0xfa, 0x20, 0x7e, 0x40, 0x1c, 0x20, 0x76, /// 0x30c0 + 0x07, 0xb0, 0xf0, 0xbd, 0xf0, 0x02, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, /// 0x30d0 + 0x40, 0x6c, 0x00, 0x40, 0x93, 0x3f, 0x93, 0x36, 0xa5, 0x26, 0xa5, 0x26, 0xa8, 0xe1, 0xaf, 0xc7, /// 0x30e0 + 0x14, 0x14, 0x00, 0x00, 0x8e, 0x5a, 0x8e, 0x48, 0x93, 0x18, 0x94, 0x16, 0x9a, 0xec, 0x9d, 0xd9, /// 0x30f0 + 0x14, 0x00, 0x01, 0x50, 0xac, 0x7f, 0xac, 0x7f, 0xac, 0x7f, 0x9a, 0x7d, 0x96, 0x7d, 0x96, 0x7d, /// 0x3100 + 0x14, 0x00, 0x01, 0x50, 0x01, 0x00, 0x01, 0x00, 0x4d, 0x61, 0x79, 0x20, 0x31, 0x33, 0x20, 0x32, /// 0x3110 + 0x30, 0x32, 0x30, 0x00, 0x31, 0x33, 0x3a, 0x33, 0x34, 0x3a, 0x35, 0x31, 0xf8, 0xb5, 0x72, 0xb6, /// 0x3120 + 0x50, 0x48, 0x4f, 0x49, 0x41, 0x60, 0x50, 0x49, 0x81, 0x67, 0x50, 0x49, 0xc1, 0x67, 0x50, 0x49, /// 0x3130 + 0x80, 0x30, 0x01, 0x60, 0x50, 0x49, 0x4f, 0x48, 0x50, 0x4c, 0x88, 0x61, 0x04, 0x20, 0x20, 0x84, /// 0x3140 + 0x62, 0xb6, 0xa0, 0x78, 0x26, 0x46, 0xe0, 0x36, 0x05, 0x28, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, /// 0x3150 + 0x06, 0x20, 0x70, 0x76, 0x01, 0xf0, 0x4a, 0xf8, 0x01, 0xf0, 0x3c, 0xf8, 0x48, 0x48, 0x47, 0x4f, /// 0x3160 + 0x00, 0x60, 0x40, 0x60, 0x20, 0x20, 0x20, 0x87, 0x01, 0x20, 0x60, 0x37, 0x38, 0x76, 0x00, 0x25, /// 0x3170 + 0x7d, 0x76, 0x20, 0x20, 0xfd, 0xf7, 0xae, 0xfc, 0xa5, 0x86, 0x3d, 0x46, 0x20, 0x3d, 0xff, 0x20, /// 0x3180 + 0x24, 0x30, 0xa8, 0x84, 0x11, 0x20, 0x40, 0x01, 0xe8, 0x84, 0x5b, 0x20, 0xb8, 0x76, 0xaf, 0x20, /// 0x3190 + 0xc0, 0x00, 0x68, 0x85, 0x2c, 0x46, 0x80, 0x34, 0xe2, 0x8a, 0x3a, 0x48, 0x82, 0x42, 0x04, 0xd9, /// 0x31a0 + 0x39, 0x49, 0xa9, 0x85, 0xff, 0x21, 0xe0, 0x31, 0x02, 0xe0, 0xff, 0x21, 0xa8, 0x85, 0xac, 0x31, /// 0x31b0 + 0x29, 0x85, 0x33, 0x49, 0x0f, 0x23, 0x78, 0x39, 0x0b, 0x71, 0xff, 0x23, 0x2f, 0x4f, 0x4b, 0x71, /// 0x31c0 + 0x32, 0x49, 0x80, 0x37, 0x79, 0x82, 0xb9, 0x82, 0x1e, 0x21, 0xb9, 0x76, 0xf9, 0x76, 0xff, 0x21, /// 0x31d0 + 0xf5, 0x31, 0xf9, 0x82, 0x05, 0x21, 0xb9, 0x77, 0xb3, 0x71, 0x82, 0x42, 0x01, 0xd9, 0x00, 0x20, /// 0x31e0 + 0x00, 0xe0, 0x01, 0x20, 0xe0, 0x77, 0xff, 0x20, 0x24, 0x30, 0x20, 0x85, 0x99, 0x20, 0xf0, 0x71, /// 0x31f0 + 0x33, 0x20, 0x30, 0x73, 0xff, 0x20, 0x90, 0x30, 0x60, 0x85, 0x01, 0x20, 0xb0, 0x73, 0x00, 0x20, /// 0x3200 + 0x30, 0x74, 0x02, 0x20, 0x70, 0x74, 0x04, 0x20, 0xb0, 0x74, 0x21, 0x4e, 0x16, 0x20, 0x14, 0x21, /// 0x3210 + 0x30, 0x5e, 0x71, 0x5e, 0x40, 0x1a, 0x28, 0x21, 0xfe, 0xf7, 0x2c, 0xf9, 0xa0, 0x77, 0x1b, 0x49, /// 0x3220 + 0xb0, 0x8a, 0xa0, 0x83, 0x88, 0x31, 0x61, 0x83, 0x00, 0x21, 0xe9, 0x85, 0x19, 0x49, 0x88, 0x42, /// 0x3230 + 0x03, 0xd1, 0x14, 0x20, 0xa0, 0x77, 0x18, 0x48, 0xa0, 0x83, 0x11, 0x48, 0xff, 0x22, 0x78, 0x38, /// 0x3240 + 0x01, 0x7b, 0x49, 0x08, 0x49, 0x00, 0x01, 0x73, 0x00, 0x21, 0x01, 0x72, 0x41, 0x73, 0x81, 0x73, /// 0x3250 + 0xcd, 0x32, 0xc2, 0x82, 0x81, 0x76, 0x29, 0x73, 0xe9, 0x81, 0x39, 0x70, 0xf8, 0xbd, 0x00, 0x00, /// 0x3260 + 0x17, 0x43, 0x00, 0x00, 0x30, 0x02, 0x00, 0x20, 0xb1, 0x3f, 0x00, 0x00, 0x87, 0x42, 0x00, 0x00, /// 0x3270 + 0xa7, 0x34, 0x00, 0x00, 0x19, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, /// 0x3280 + 0xe8, 0x04, 0x00, 0x20, 0x4c, 0x1d, 0x00, 0x00, 0xe0, 0x2e, 0x00, 0x00, 0xdc, 0x05, 0x00, 0x00, /// 0x3290 + 0x60, 0x67, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x26, 0x02, 0x00, 0x00, 0x70, 0xb5, 0x03, 0x46, /// 0x32a0 + 0xfa, 0x4a, 0x00, 0x20, 0x14, 0x24, 0x44, 0x43, 0xa4, 0x18, 0x50, 0x34, 0x25, 0x78, 0x00, 0x2d, /// 0x32b0 + 0x03, 0xd0, 0x40, 0x1c, 0x02, 0x28, 0xf5, 0xdb, 0x70, 0xbd, 0x0a, 0x46, 0x19, 0x46, 0x20, 0x46, /// 0x32c0 + 0xfd, 0xf7, 0xe5, 0xfb, 0xf1, 0x48, 0x0c, 0x34, 0xc1, 0x6f, 0xc4, 0x67, 0x78, 0x30, 0x03, 0xc4, /// 0x32d0 + 0x08, 0x3c, 0x0c, 0x60, 0x70, 0xbd, 0xf8, 0xb5, 0x15, 0x46, 0x2c, 0x22, 0x50, 0x43, 0xec, 0x4a, /// 0x32e0 + 0x0e, 0x46, 0x80, 0x18, 0x14, 0x22, 0x56, 0x43, 0x84, 0x19, 0x60, 0x68, 0xe9, 0x4f, 0x39, 0x68, /// 0x32f0 + 0x08, 0x1a, 0x08, 0x28, 0x03, 0xd9, 0x20, 0x1d, 0x28, 0x21, 0xfd, 0xf7, 0x51, 0xfb, 0x21, 0x7a, /// 0x3300 + 0x0a, 0x29, 0x37, 0xd2, 0x20, 0x7a, 0x00, 0x28, 0x09, 0xd1, 0x28, 0x46, 0xfe, 0xf7, 0xc6, 0xfc, /// 0x3310 + 0x80, 0x1c, 0xc0, 0xb2, 0x00, 0x2d, 0x2d, 0xd0, 0x0c, 0x28, 0x2b, 0xd8, 0xa0, 0x72, 0xdc, 0x49, /// 0x3320 + 0x20, 0x7a, 0x22, 0x18, 0x40, 0x1c, 0x20, 0x72, 0x95, 0x73, 0x60, 0x7a, 0x68, 0x40, 0x60, 0x72, /// 0x3330 + 0x20, 0x7a, 0xa2, 0x7a, 0x90, 0x42, 0x1b, 0xd1, 0x60, 0x7a, 0x00, 0x28, 0x18, 0xd1, 0x0d, 0x46, /// 0x3340 + 0xa1, 0x7a, 0x20, 0x46, 0x0e, 0x30, 0xff, 0xf7, 0xa9, 0xff, 0xd3, 0x48, 0x01, 0x78, 0x10, 0x22, /// 0x3350 + 0x51, 0x40, 0x01, 0x70, 0x00, 0x22, 0x70, 0x19, 0x02, 0x72, 0xab, 0x78, 0xfb, 0x21, 0x0b, 0x40, /// 0x3360 + 0xab, 0x70, 0x20, 0x30, 0x02, 0x75, 0xca, 0x48, 0x20, 0x30, 0x82, 0x7b, 0x0a, 0x40, 0x82, 0x73, /// 0x3370 + 0x38, 0x68, 0x60, 0x60, 0xf8, 0xbd, 0xf1, 0xb5, 0xc8, 0x48, 0x82, 0xb0, 0x00, 0x7b, 0x02, 0x99, /// 0x3380 + 0x85, 0x07, 0x2c, 0x22, 0xad, 0x0f, 0xc2, 0x48, 0x51, 0x43, 0x01, 0x2d, 0x47, 0xd0, 0x00, 0x22, /// 0x3390 + 0x42, 0x52, 0x46, 0x5a, 0x02, 0x9b, 0x2c, 0x24, 0xc1, 0x4a, 0x63, 0x43, 0xbc, 0x4c, 0x97, 0x7f, /// 0x33a0 + 0x1c, 0x19, 0xbe, 0x42, 0x02, 0xd3, 0xa3, 0x78, 0x5b, 0x07, 0x06, 0xd5, 0x40, 0x5a, 0xd1, 0x7f, /// 0x33b0 + 0x88, 0x42, 0x0a, 0xd3, 0xa0, 0x78, 0x40, 0x07, 0x07, 0xd5, 0xa0, 0x78, 0xfb, 0x21, 0x08, 0x40, /// 0x33c0 + 0xa0, 0x70, 0xa0, 0x78, 0x01, 0x21, 0x08, 0x43, 0xa0, 0x70, 0xa0, 0x78, 0xc0, 0x07, 0x01, 0xd0, /// 0x33d0 + 0x00, 0x2d, 0x27, 0xd0, 0xa0, 0x78, 0xc0, 0x07, 0x32, 0xd0, 0x01, 0x2d, 0x30, 0xd9, 0xa0, 0x78, /// 0x33e0 + 0x40, 0x08, 0x40, 0x00, 0xa0, 0x70, 0xa0, 0x78, 0x04, 0x21, 0x08, 0x43, 0xa0, 0x70, 0xa0, 0x78, /// 0x33f0 + 0x02, 0x2d, 0x1c, 0xd0, 0xfd, 0x21, 0x08, 0x40, 0xa0, 0x70, 0x20, 0x1d, 0x28, 0x21, 0xfd, 0xf7, /// 0x3400 + 0xcf, 0xfa, 0x20, 0x46, 0x18, 0x30, 0x28, 0x21, 0xfd, 0xf7, 0xca, 0xfa, 0x03, 0x2d, 0x11, 0xd0, /// 0x3410 + 0x01, 0x20, 0x40, 0x02, 0xa0, 0x81, 0x11, 0x20, 0x40, 0x02, 0x20, 0x84, 0xfe, 0xbd, 0x42, 0x5a, /// 0x3420 + 0x52, 0x1c, 0xb5, 0xe7, 0xa0, 0x78, 0x40, 0x08, 0x40, 0x00, 0xa0, 0x70, 0xfe, 0xbd, 0x02, 0x21, /// 0x3430 + 0x08, 0x43, 0xe1, 0xe7, 0x03, 0x20, 0x00, 0x02, 0xa0, 0x81, 0x23, 0x20, 0x00, 0x02, 0xec, 0xe7, /// 0x3440 + 0xa0, 0x78, 0x40, 0x07, 0xf2, 0xd5, 0xa0, 0x78, 0x80, 0x07, 0x01, 0xd5, 0x02, 0x20, 0x00, 0xe0, /// 0x3450 + 0x01, 0x20, 0x92, 0x4d, 0x00, 0x26, 0x00, 0x90, 0x14, 0x20, 0x70, 0x43, 0x27, 0x18, 0xb8, 0x89, /// 0x3460 + 0xa8, 0x83, 0xa9, 0x8b, 0x09, 0x20, 0x00, 0x03, 0x88, 0x43, 0x15, 0xd1, 0x38, 0x7a, 0x00, 0x28, /// 0x3470 + 0x0c, 0xd1, 0xa8, 0x8b, 0xc0, 0xb2, 0x03, 0x28, 0x08, 0xd1, 0x84, 0x48, 0x03, 0x22, 0x41, 0x8c, /// 0x3480 + 0x52, 0x03, 0x91, 0x42, 0x02, 0xd1, 0x83, 0x49, 0x09, 0x68, 0x01, 0x60, 0xa8, 0x8b, 0xf1, 0xb2, /// 0x3490 + 0xc2, 0xb2, 0x02, 0x98, 0xff, 0xf7, 0x1f, 0xff, 0xa8, 0x8b, 0xb8, 0x81, 0x00, 0x98, 0x76, 0x1c, /// 0x34a0 + 0x86, 0x42, 0xd9, 0xdb, 0xfe, 0xbd, 0x7d, 0x48, 0x10, 0xb5, 0x40, 0x38, 0x01, 0x7f, 0xff, 0x22, /// 0x34b0 + 0x02, 0x76, 0xc8, 0x07, 0xc0, 0x0f, 0x02, 0xd0, 0x00, 0x20, 0xff, 0xf7, 0x5c, 0xff, 0x00, 0x20, /// 0x34c0 + 0x10, 0xbd, 0x01, 0x21, 0x75, 0x48, 0xc9, 0x03, 0x40, 0x38, 0x01, 0x80, 0x73, 0x49, 0x0c, 0x22, /// 0x34d0 + 0x20, 0x31, 0x8a, 0x82, 0x73, 0x4b, 0xa5, 0x22, 0x1a, 0x80, 0x00, 0x22, 0x9a, 0x82, 0x01, 0x23, /// 0x34e0 + 0x0b, 0x74, 0x10, 0x21, 0x01, 0x80, 0x08, 0x21, 0x01, 0x71, 0x8d, 0x21, 0x01, 0x72, 0x60, 0x21, /// 0x34f0 + 0x01, 0x73, 0x6a, 0x49, 0x20, 0x39, 0x0a, 0x71, 0x6b, 0x4a, 0x8a, 0x83, 0x6b, 0x4a, 0x0a, 0x82, /// 0x3500 + 0x6b, 0x4a, 0x8a, 0x82, 0x6b, 0x4a, 0x0a, 0x83, 0x6b, 0x4a, 0x0a, 0x81, 0x8a, 0x81, 0x6b, 0x4a, /// 0x3510 + 0x41, 0x15, 0x11, 0x60, 0x6a, 0x4a, 0x11, 0x60, 0x0f, 0x21, 0x01, 0x82, 0xff, 0x21, 0x01, 0x76, /// 0x3520 + 0x70, 0x47, 0xff, 0x21, 0x10, 0xb5, 0x90, 0x31, 0x88, 0x42, 0x06, 0xd9, 0x64, 0x21, 0xfd, 0xf7, /// 0x3530 + 0x8b, 0xff, 0x0a, 0x21, 0x48, 0x43, 0x80, 0x1c, 0x00, 0xe0, 0x20, 0x20, 0xc1, 0xb2, 0x08, 0x02, /// 0x3540 + 0x08, 0x43, 0x56, 0x49, 0x20, 0x39, 0x08, 0x81, 0x88, 0x81, 0x10, 0xbd, 0x54, 0x49, 0x00, 0x22, /// 0x3550 + 0x60, 0x39, 0x4a, 0x76, 0x4d, 0x49, 0x88, 0x71, 0xca, 0x76, 0x02, 0x20, 0x08, 0x72, 0x4d, 0x48, /// 0x3560 + 0x00, 0x68, 0x08, 0x60, 0x70, 0x47, 0x01, 0x46, 0x48, 0x48, 0x10, 0xb5, 0x07, 0x22, 0x1c, 0x30, /// 0x3570 + 0xfd, 0xf7, 0x8d, 0xfa, 0x53, 0x49, 0xfb, 0x20, 0x08, 0x80, 0x44, 0x48, 0x0c, 0x21, 0x01, 0x72, /// 0x3580 + 0x44, 0x49, 0x09, 0x68, 0x01, 0x60, 0x46, 0x48, 0x08, 0x21, 0x80, 0x38, 0x01, 0x76, 0x20, 0x20, /// 0x3590 + 0xfd, 0xf7, 0xa0, 0xfa, 0x10, 0xbd, 0x01, 0x46, 0x3c, 0x48, 0x10, 0xb5, 0x07, 0x22, 0x21, 0x30, /// 0x35a0 + 0xfd, 0xf7, 0x75, 0xfa, 0x39, 0x48, 0x03, 0x21, 0x01, 0x72, 0x3a, 0x49, 0x09, 0x68, 0x01, 0x60, /// 0x35b0 + 0x10, 0xbd, 0x36, 0x48, 0x03, 0x21, 0x01, 0x72, 0x36, 0x49, 0x09, 0x68, 0x01, 0x60, 0x70, 0x47, /// 0x35c0 + 0x70, 0xb5, 0x08, 0x28, 0x2d, 0xd8, 0x36, 0x4d, 0x60, 0x3d, 0x68, 0x7e, 0x29, 0x46, 0x40, 0x1c, /// 0x35d0 + 0xc0, 0xb2, 0x68, 0x76, 0x80, 0x39, 0x09, 0x8c, 0x2c, 0x46, 0x40, 0x3c, 0x88, 0x42, 0x0e, 0xd3, /// 0x35e0 + 0xa0, 0x8e, 0x01, 0x21, 0x08, 0x43, 0xa0, 0x86, 0x20, 0x20, 0xfd, 0xf7, 0x73, 0xfa, 0x20, 0x46, /// 0x35f0 + 0x20, 0x30, 0x41, 0x7e, 0x80, 0x22, 0x11, 0x43, 0x41, 0x76, 0x00, 0xf0, 0x63, 0xfa, 0x68, 0x7e, /// 0x3600 + 0x01, 0x28, 0x0e, 0xd1, 0xe1, 0x8c, 0xa0, 0x8c, 0x08, 0x1a, 0xc2, 0x17, 0x92, 0x0f, 0x10, 0x18, /// 0x3610 + 0x80, 0x10, 0x08, 0x1a, 0x80, 0xb2, 0x1d, 0x4a, 0x60, 0x84, 0xff, 0x21, 0x51, 0x71, 0x00, 0xf0, /// 0x3620 + 0x87, 0xfa, 0x70, 0xbd, 0x70, 0xb5, 0xc3, 0x09, 0x01, 0xd0, 0xc0, 0x43, 0x40, 0x1c, 0x1b, 0x4a, /// 0x3630 + 0x04, 0x21, 0x20, 0x32, 0xc0, 0xb2, 0x91, 0x82, 0x19, 0x49, 0x00, 0x24, 0x60, 0x39, 0x4a, 0x7e, /// 0x3640 + 0x00, 0x2a, 0x13, 0xd0, 0x0a, 0x7e, 0x52, 0x1c, 0xd2, 0xb2, 0x0a, 0x76, 0x14, 0x2a, 0x00, 0xd9, /// 0x3650 + 0x4c, 0x76, 0x10, 0x4a, 0x00, 0x28, 0x15, 0x68, 0x0c, 0x4a, 0x15, 0x60, 0x08, 0xd0, 0x04, 0x28, /// 0x3660 + 0x0a, 0xd2, 0x00, 0x2b, 0x06, 0xd0, 0x00, 0x20, 0xc0, 0x43, 0x2e, 0xe0, 0x0c, 0x76, 0xf0, 0xe7, /// 0x3670 + 0x54, 0x72, 0x2b, 0xe0, 0x01, 0x20, 0x28, 0xe0, 0x09, 0x4c, 0xa0, 0x3c, 0x65, 0x8c, 0xa6, 0x8c, /// 0x3680 + 0xb5, 0x42, 0x29, 0xd1, 0x00, 0x2b, 0x1f, 0xd0, 0x80, 0x08, 0x33, 0xe0, 0x70, 0x04, 0x00, 0x20, /// 0x3690 + 0xe0, 0x03, 0x00, 0x20, 0x30, 0x02, 0x00, 0x20, 0x40, 0x6c, 0x00, 0x40, 0x40, 0x40, 0x00, 0x40, /// 0x36a0 + 0xe0, 0x00, 0x00, 0x20, 0x00, 0x74, 0x00, 0x40, 0x2c, 0x10, 0x00, 0x00, 0x1d, 0x26, 0x00, 0x00, /// 0x36b0 + 0x15, 0x1d, 0x00, 0x00, 0x0e, 0x15, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x80, 0xe2, 0x00, 0xe0, /// 0x36c0 + 0x00, 0xe1, 0x00, 0xe0, 0x00, 0x34, 0x00, 0x40, 0x40, 0x08, 0x50, 0x72, 0x48, 0x7f, 0x10, 0x28, /// 0x36d0 + 0x00, 0xd2, 0x40, 0x1c, 0x48, 0x77, 0x70, 0xbd, 0xe4, 0x8c, 0x64, 0x1b, 0x24, 0x12, 0x64, 0x1c, /// 0x36e0 + 0xa4, 0xb2, 0x10, 0x28, 0x00, 0xd9, 0x10, 0x20, 0x00, 0x2b, 0x05, 0xd0, 0x43, 0x08, 0x18, 0x18, /// 0x36f0 + 0xc0, 0xb2, 0x60, 0x43, 0x40, 0x42, 0xe8, 0xe7, 0x60, 0x43, 0xe6, 0xe7, 0xf0, 0xb5, 0x85, 0xb0, /// 0x3700 + 0xd9, 0x49, 0x00, 0x91, 0x08, 0x8e, 0xd9, 0x4a, 0xc9, 0x8d, 0x90, 0x42, 0x01, 0xd9, 0x01, 0x24, /// 0x3710 + 0x00, 0xe0, 0x00, 0x24, 0xd4, 0x4a, 0x63, 0x00, 0x40, 0x3a, 0x9b, 0x18, 0x80, 0x33, 0x12, 0x19, /// 0x3720 + 0x80, 0x32, 0x5b, 0x8a, 0xd0, 0x4d, 0x02, 0x93, 0x92, 0x7e, 0x40, 0x35, 0x04, 0x92, 0xea, 0x8a, /// 0x3730 + 0x01, 0x92, 0xaa, 0x7f, 0x03, 0x92, 0x48, 0x43, 0x05, 0xd0, 0x7d, 0x21, 0xc9, 0x00, 0xfd, 0xf7, /// 0x3740 + 0x99, 0xfe, 0x07, 0x46, 0x00, 0xe0, 0x00, 0x27, 0xc9, 0x48, 0x7d, 0x22, 0xc1, 0x79, 0x00, 0x7f, /// 0x3750 + 0x80, 0x06, 0x80, 0x0e, 0x50, 0x43, 0x41, 0x43, 0x4e, 0x09, 0x00, 0x2c, 0x00, 0xd0, 0x76, 0x00, /// 0x3760 + 0x01, 0x98, 0x87, 0x42, 0x06, 0xd9, 0x04, 0x99, 0x38, 0x1a, 0x48, 0x43, 0x64, 0x21, 0xfd, 0xf7, /// 0x3770 + 0x6b, 0xfe, 0x00, 0xe0, 0x00, 0x20, 0x38, 0x1a, 0x81, 0x1b, 0x02, 0x98, 0x81, 0x42, 0x09, 0xdc, /// 0x3780 + 0xbc, 0x48, 0x86, 0x42, 0x01, 0xd3, 0x00, 0x2c, 0x04, 0xd0, 0xbb, 0x48, 0x86, 0x42, 0x25, 0xd3, /// 0x3790 + 0x00, 0x2c, 0x23, 0xd0, 0xe8, 0x7f, 0x40, 0x1c, 0xc0, 0xb2, 0xe8, 0x77, 0x02, 0x9a, 0x92, 0x00, /// 0x37a0 + 0x8a, 0x42, 0x03, 0xda, 0x00, 0x2c, 0x01, 0xd1, 0x40, 0x1c, 0xe8, 0x77, 0xc1, 0xb2, 0x03, 0x98, /// 0x37b0 + 0x81, 0x42, 0x11, 0xd3, 0x00, 0x98, 0x01, 0x21, 0x80, 0x8e, 0x49, 0x03, 0x08, 0x43, 0x00, 0x99, /// 0x37c0 + 0x88, 0x86, 0x20, 0x20, 0xfd, 0xf7, 0x86, 0xf9, 0xa7, 0x48, 0x10, 0x22, 0x20, 0x30, 0x41, 0x7e, /// 0x37d0 + 0x11, 0x43, 0x41, 0x76, 0x00, 0xf0, 0x76, 0xf9, 0x05, 0xb0, 0xf0, 0xbd, 0x00, 0x20, 0xe8, 0x77, /// 0x37e0 + 0xfa, 0xe7, 0x70, 0xb5, 0xa2, 0x4d, 0xa0, 0x4c, 0xe8, 0x71, 0x40, 0x34, 0x21, 0x7f, 0x08, 0x30, /// 0x37f0 + 0x81, 0x42, 0x01, 0xd9, 0x00, 0x20, 0x60, 0x77, 0x9b, 0x48, 0xc0, 0x8e, 0x80, 0x06, 0x09, 0xd5, /// 0x3800 + 0x60, 0x7f, 0x06, 0x28, 0x06, 0xd9, 0x9a, 0x48, 0x20, 0x30, 0x40, 0x78, 0x00, 0x07, 0x01, 0xd0, /// 0x3810 + 0xff, 0xf7, 0x74, 0xff, 0xe8, 0x79, 0x20, 0x77, 0x70, 0xbd, 0x41, 0x1f, 0xc8, 0x29, 0x01, 0xd8, /// 0x3820 + 0x93, 0x49, 0xc8, 0x72, 0x70, 0x47, 0x70, 0xb5, 0x0c, 0x46, 0x41, 0x78, 0x61, 0x70, 0x05, 0x29, /// 0x3830 + 0x1b, 0xd0, 0x2f, 0x23, 0x8e, 0x4e, 0xc9, 0x29, 0x27, 0xd0, 0x8b, 0x4a, 0x8f, 0x48, 0x3f, 0x25, /// 0x3840 + 0xca, 0x29, 0x25, 0xd0, 0xcb, 0x29, 0x25, 0xd0, 0xcc, 0x29, 0x2b, 0xd0, 0x04, 0x29, 0x2b, 0xd0, /// 0x3850 + 0x06, 0x29, 0x2b, 0xd0, 0x07, 0x29, 0x2b, 0xd0, 0xce, 0x29, 0x2b, 0xd0, 0xc4, 0x29, 0x13, 0xd0, /// 0x3860 + 0x0b, 0x29, 0x11, 0xd1, 0x23, 0x70, 0x04, 0x20, 0x26, 0xe0, 0x5f, 0x20, 0x20, 0x70, 0x7e, 0x48, /// 0x3870 + 0x40, 0x38, 0x01, 0x7f, 0xa1, 0x70, 0x81, 0x8b, 0x09, 0x0a, 0xe1, 0x70, 0xc1, 0x69, 0x09, 0x0c, /// 0x3880 + 0x21, 0x71, 0xc0, 0x69, 0x00, 0x0e, 0x60, 0x71, 0x70, 0xbd, 0x23, 0x70, 0x70, 0x79, 0x13, 0xe0, /// 0x3890 + 0xd1, 0x8c, 0x00, 0xe0, 0x91, 0x8c, 0xfd, 0xf7, 0xd7, 0xfd, 0x25, 0x70, 0xa0, 0x70, 0x00, 0x0a, /// 0x38a0 + 0xe0, 0x70, 0x70, 0xbd, 0x11, 0x8d, 0xf6, 0xe7, 0x51, 0x8c, 0xf4, 0xe7, 0xd0, 0x8d, 0xf4, 0xe7, /// 0x38b0 + 0x10, 0x8e, 0xf2, 0xe7, 0x23, 0x70, 0x30, 0x79, 0xa0, 0x70, 0x70, 0xbd, 0x3e, 0xb5, 0x04, 0x46, /// 0x38c0 + 0x00, 0x78, 0xfe, 0xf7, 0xeb, 0xf9, 0x68, 0x48, 0x06, 0x22, 0x21, 0x46, 0x10, 0x30, 0xfd, 0xf7, /// 0x38d0 + 0xde, 0xf8, 0x00, 0x20, 0x69, 0x46, 0x08, 0x70, 0x20, 0x78, 0x18, 0x28, 0x0e, 0xd1, 0x20, 0x46, /// 0x38e0 + 0xff, 0xf7, 0xa1, 0xff, 0x68, 0x46, 0x00, 0x78, 0x00, 0x28, 0x07, 0xd0, 0xfe, 0xf7, 0xd6, 0xf9, /// 0x38f0 + 0x42, 0x1c, 0x5d, 0x48, 0x69, 0x46, 0x18, 0x30, 0xfd, 0xf7, 0xc9, 0xf8, 0x3e, 0xbd, 0xf8, 0xb5, /// 0x3900 + 0x5b, 0x4a, 0x04, 0x46, 0x58, 0x4b, 0x10, 0x7a, 0x10, 0x33, 0x21, 0x78, 0x0c, 0x28, 0x2e, 0xd0, /// 0x3910 + 0x01, 0x29, 0x0b, 0xd0, 0x51, 0x29, 0x14, 0xd0, 0x71, 0x29, 0x1d, 0xd0, 0x81, 0x29, 0x04, 0xd1, /// 0x3920 + 0x71, 0x28, 0x02, 0xd1, 0x60, 0x1c, 0xff, 0xf7, 0x44, 0xfe, 0xf8, 0xbd, 0x01, 0x28, 0xfc, 0xd1, /// 0x3930 + 0x06, 0x22, 0x21, 0x46, 0x18, 0x46, 0xfd, 0xf7, 0xaa, 0xf8, 0x60, 0x78, 0xff, 0xf7, 0x06, 0xfe, /// 0x3940 + 0xf8, 0xbd, 0x03, 0x28, 0xfc, 0xd1, 0x06, 0x22, 0x21, 0x46, 0x18, 0x46, 0xfd, 0xf7, 0x9f, 0xf8, /// 0x3950 + 0x60, 0x1c, 0xff, 0xf7, 0x08, 0xfe, 0xf8, 0xbd, 0x02, 0x28, 0xfc, 0xd1, 0x06, 0x22, 0x21, 0x46, /// 0x3960 + 0x18, 0x46, 0xfd, 0xf7, 0x94, 0xf8, 0x60, 0x1c, 0xff, 0xf7, 0x15, 0xfe, 0xf8, 0xbd, 0x08, 0x26, /// 0x3970 + 0x3d, 0x4d, 0x05, 0x29, 0x54, 0xd0, 0x08, 0xdc, 0x01, 0x29, 0x11, 0xd0, 0x02, 0x29, 0x38, 0xd0, /// 0x3980 + 0x03, 0x29, 0x3f, 0xd0, 0x04, 0x29, 0x08, 0xd1, 0x46, 0xe0, 0x06, 0x29, 0x4b, 0xd0, 0x51, 0x29, /// 0x3990 + 0x06, 0xd0, 0x71, 0x29, 0x04, 0xd0, 0x81, 0x29, 0x02, 0xd0, 0x20, 0x46, 0xff, 0xf7, 0x8e, 0xff, /// 0x39a0 + 0xe8, 0x8e, 0x00, 0x07, 0xe2, 0xd5, 0x28, 0x7e, 0xfe, 0xf7, 0x78, 0xf9, 0x04, 0x46, 0x0a, 0x28, /// 0x39b0 + 0x19, 0xd2, 0x2d, 0x48, 0x61, 0x1c, 0x18, 0x30, 0x07, 0x46, 0xfd, 0xf7, 0x54, 0xf9, 0x2a, 0x49, /// 0x39c0 + 0x40, 0x39, 0x09, 0x19, 0x40, 0x31, 0x48, 0x76, 0xa0, 0x1c, 0x82, 0xb2, 0x28, 0x48, 0x39, 0x46, /// 0x39d0 + 0x2c, 0x30, 0x07, 0x46, 0x00, 0xf0, 0xb3, 0xfd, 0x16, 0x20, 0x44, 0x43, 0x2e, 0x34, 0xa1, 0xb2, /// 0x39e0 + 0x38, 0x46, 0x00, 0xf0, 0x94, 0xfd, 0x00, 0x20, 0x28, 0x76, 0xe8, 0x8e, 0xb0, 0x43, 0xe8, 0x86, /// 0x39f0 + 0xf8, 0xbd, 0x06, 0x22, 0x21, 0x46, 0x18, 0x46, 0xfd, 0xf7, 0x49, 0xf8, 0x60, 0x78, 0xff, 0xf7, /// 0x3a00 + 0xdf, 0xfd, 0xcd, 0xe7, 0x60, 0x78, 0xff, 0xf7, 0x0d, 0xfe, 0x28, 0x7e, 0x00, 0x28, 0xc7, 0xd0, /// 0x3a10 + 0xe8, 0x8e, 0x30, 0x43, 0xe8, 0x86, 0xc3, 0xe7, 0x60, 0x78, 0xff, 0xf7, 0xe2, 0xfe, 0xbf, 0xe7, /// 0x3a20 + 0x60, 0x78, 0x90, 0x72, 0xbc, 0xe7, 0x60, 0x78, 0xff, 0xf7, 0xf7, 0xfe, 0xb8, 0xe7, 0xf8, 0xb5, /// 0x3a30 + 0x0f, 0x48, 0x0f, 0x4e, 0x80, 0x6f, 0x00, 0x27, 0x78, 0x36, 0x04, 0x68, 0x10, 0xe0, 0x05, 0x46, /// 0x3a40 + 0x06, 0xc8, 0x4a, 0x60, 0x08, 0x38, 0x11, 0x60, 0x07, 0x60, 0x0c, 0x3d, 0x47, 0x60, 0x28, 0x46, /// 0x3a50 + 0xff, 0xf7, 0x55, 0xff, 0x0a, 0x21, 0x28, 0x46, 0xfc, 0xf7, 0xa2, 0xff, 0x20, 0x46, 0x24, 0x68, /// 0x3a60 + 0xb0, 0x42, 0xec, 0xd1, 0xf8, 0xbd, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x64, 0x19, 0x00, 0x00, /// 0x3a70 + 0x70, 0x04, 0x00, 0x20, 0x28, 0x23, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x60, 0xea, 0x00, 0x00, /// 0x3a80 + 0x01, 0x21, 0x8b, 0x48, 0xc9, 0x03, 0x01, 0x80, 0x8a, 0x49, 0x49, 0x7e, 0xc9, 0x00, 0x49, 0x1c, /// 0x3a90 + 0x01, 0x80, 0x03, 0x21, 0x81, 0x80, 0x01, 0x88, 0x02, 0x22, 0x11, 0x43, 0x01, 0x80, 0x70, 0x47, /// 0x3aa0 + 0x01, 0x20, 0x83, 0x49, 0xc0, 0x03, 0x08, 0x80, 0x82, 0x48, 0x00, 0x21, 0x80, 0x38, 0x01, 0x76, /// 0x3ab0 + 0x20, 0x38, 0x42, 0x7b, 0x80, 0x23, 0x12, 0x09, 0x12, 0x01, 0x1a, 0x43, 0x42, 0x73, 0x7e, 0x48, /// 0x3ac0 + 0x01, 0x72, 0x70, 0x47, 0xf8, 0xb5, 0x7a, 0x4c, 0x00, 0x20, 0x20, 0x83, 0x79, 0x4b, 0x7a, 0x49, /// 0x3ad0 + 0x80, 0x3b, 0x08, 0x72, 0x02, 0x25, 0x1d, 0x76, 0x1a, 0x46, 0xc8, 0x76, 0x60, 0x32, 0xd6, 0x8a, /// 0x3ae0 + 0x76, 0x4f, 0xbe, 0x42, 0x00, 0xd8, 0x01, 0x20, 0xd0, 0x77, 0x75, 0x48, 0x00, 0x68, 0x08, 0x60, /// 0x3af0 + 0x74, 0x49, 0x04, 0x20, 0x88, 0x82, 0x20, 0x88, 0xa8, 0x43, 0x20, 0x80, 0x6d, 0x48, 0x72, 0x49, /// 0x3b00 + 0xa0, 0x38, 0x80, 0x8e, 0x08, 0x42, 0x0c, 0xd1, 0x01, 0x05, 0x0a, 0xd4, 0xc1, 0x04, 0x08, 0xd4, /// 0x3b10 + 0x41, 0x04, 0x06, 0xd4, 0x81, 0x04, 0x04, 0xd4, 0x00, 0x04, 0x02, 0xd4, 0x58, 0x7e, 0x01, 0x28, /// 0x3b20 + 0x01, 0xd1, 0xff, 0xf7, 0xbd, 0xff, 0x58, 0x21, 0x68, 0x48, 0xfc, 0xf7, 0x39, 0xff, 0xf8, 0xbd, /// 0x3b30 + 0xfe, 0xb5, 0x04, 0x46, 0x5f, 0x48, 0x65, 0x08, 0x20, 0x38, 0x02, 0x90, 0xc2, 0x7f, 0x20, 0x30, /// 0x3b40 + 0x00, 0x90, 0x60, 0x1e, 0x87, 0xb2, 0x01, 0x2a, 0x0b, 0xd0, 0xff, 0x20, 0x40, 0x1a, 0x68, 0x43, /// 0x3b50 + 0x00, 0x0a, 0x01, 0x90, 0x00, 0x98, 0x41, 0x7b, 0xa0, 0x1c, 0x86, 0xb2, 0x01, 0x29, 0x13, 0xd0, /// 0x3b60 + 0x27, 0xe0, 0x28, 0x46, 0x48, 0x43, 0x02, 0x0a, 0x51, 0x48, 0x01, 0x21, 0x20, 0x30, 0x81, 0x81, /// 0x3b70 + 0x05, 0x82, 0x85, 0x82, 0x07, 0x83, 0xa1, 0x1a, 0x4d, 0x4b, 0x49, 0x1e, 0x99, 0x83, 0xaa, 0x1a, /// 0x3b80 + 0x02, 0x80, 0x82, 0x80, 0x01, 0x81, 0x22, 0xe0, 0x49, 0x48, 0x01, 0x21, 0x20, 0x30, 0x81, 0x81, /// 0x3b90 + 0x05, 0x82, 0x85, 0x82, 0x07, 0x83, 0x81, 0x80, 0x06, 0x81, 0x45, 0x49, 0x89, 0x8b, 0x49, 0x1d, /// 0x3ba0 + 0x01, 0x80, 0x45, 0x49, 0x09, 0x79, 0xff, 0x31, 0x01, 0x31, 0x81, 0x83, 0x14, 0x20, 0xfc, 0xf7, /// 0x3bb0 + 0x62, 0xff, 0x3f, 0x48, 0x01, 0x21, 0x20, 0x30, 0x81, 0x81, 0x01, 0x9a, 0xaa, 0x1a, 0x02, 0x82, /// 0x3bc0 + 0x82, 0x82, 0x07, 0x83, 0x3a, 0x4a, 0x96, 0x83, 0x06, 0x80, 0x81, 0x80, 0x06, 0x81, 0x02, 0x98, /// 0x3bd0 + 0xc1, 0x7f, 0x00, 0x98, 0x41, 0x73, 0x0f, 0x20, 0x00, 0x03, 0x21, 0x46, 0x01, 0x43, 0x34, 0x48, /// 0x3be0 + 0x01, 0x83, 0x35, 0x48, 0x32, 0x49, 0x00, 0x79, 0x20, 0x31, 0xff, 0x30, 0x01, 0x30, 0x88, 0x83, /// 0x3bf0 + 0x20, 0x46, 0xff, 0xf7, 0x96, 0xfc, 0x2f, 0x48, 0xa0, 0x38, 0x44, 0x84, 0xfe, 0xbd, 0x34, 0x48, /// 0x3c00 + 0x01, 0x21, 0x01, 0x80, 0x05, 0x22, 0x02, 0x80, 0x82, 0x80, 0x01, 0x81, 0x08, 0x22, 0x82, 0x81, /// 0x3c10 + 0xff, 0x22, 0x02, 0x82, 0x2f, 0x4a, 0x11, 0x70, 0x04, 0x23, 0x13, 0x71, 0x4f, 0x22, 0x02, 0x80, /// 0x3c20 + 0x2b, 0x4a, 0x00, 0x23, 0x20, 0x32, 0x13, 0x80, 0x2b, 0x4b, 0x13, 0x80, 0x01, 0x75, 0x70, 0x47, /// 0x3c30 + 0x30, 0xb4, 0x21, 0x4a, 0x1f, 0x4b, 0x14, 0x7b, 0xa0, 0x3b, 0x11, 0x46, 0xe5, 0x07, 0x58, 0x8c, /// 0x3c40 + 0x49, 0x79, 0x00, 0x2d, 0x05, 0xd0, 0x63, 0x07, 0x2f, 0xd5, 0xfb, 0x23, 0x1c, 0x40, 0x14, 0x73, /// 0x3c50 + 0x29, 0xe0, 0x09, 0x24, 0x14, 0x57, 0x00, 0x2c, 0x27, 0xd0, 0x10, 0xdd, 0xff, 0x29, 0x02, 0xd0, /// 0x3c60 + 0x09, 0xd2, 0x49, 0x1c, 0x08, 0xe0, 0xd9, 0x8c, 0x88, 0x42, 0x01, 0xd2, 0x40, 0x1c, 0x00, 0xe0, /// 0x3c70 + 0x08, 0x46, 0x58, 0x84, 0x01, 0xe0, 0xff, 0x21, 0x51, 0x71, 0x64, 0x1e, 0x10, 0xe0, 0x9d, 0x8c, /// 0x3c80 + 0xa8, 0x42, 0x06, 0xd1, 0x14, 0x29, 0x01, 0xd9, 0x49, 0x1e, 0x00, 0xe0, 0x14, 0x21, 0x51, 0x71, /// 0x3c90 + 0x05, 0xe0, 0xa8, 0x42, 0x01, 0xd9, 0x40, 0x1e, 0x00, 0xe0, 0x28, 0x46, 0x58, 0x84, 0x64, 0x1c, /// 0x3ca0 + 0x54, 0x72, 0x51, 0x79, 0x58, 0x8c, 0x30, 0xbc, 0x42, 0xe7, 0x30, 0xbc, 0x70, 0x47, 0x00, 0x00, /// 0x3cb0 + 0x00, 0x34, 0x00, 0x40, 0xe0, 0x00, 0x00, 0x20, 0x70, 0x04, 0x00, 0x20, 0x4c, 0x1d, 0x00, 0x00, /// 0x3cc0 + 0x30, 0x02, 0x00, 0x20, 0x60, 0x40, 0x00, 0x40, 0x01, 0x04, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x20, /// 0x3cd0 + 0x00, 0x38, 0x00, 0x40, 0x00, 0x3c, 0x00, 0x40, 0x08, 0x80, 0x00, 0x00, 0xf0, 0xb5, 0xfe, 0x48, /// 0x3ce0 + 0x00, 0x22, 0x01, 0x7a, 0x01, 0x29, 0x01, 0xd0, 0x02, 0x76, 0xf0, 0xbd, 0xfb, 0x4c, 0x2e, 0x26, /// 0x3cf0 + 0xa6, 0x5f, 0xf9, 0x4b, 0xff, 0x27, 0xf5, 0x37, 0xf9, 0x49, 0x1b, 0x8a, 0xb5, 0xb2, 0xbe, 0x42, /// 0x3d00 + 0x03, 0xdc, 0xff, 0x24, 0x2d, 0x34, 0xa3, 0x42, 0x08, 0xd9, 0x06, 0x7e, 0x74, 0x1c, 0x04, 0x76, /// 0x3d10 + 0x03, 0x2e, 0x04, 0xd3, 0x02, 0x76, 0x8d, 0x80, 0xcb, 0x80, 0x00, 0xe0, 0x02, 0x76, 0x44, 0x7e, /// 0x3d20 + 0x66, 0x1c, 0x46, 0x76, 0x05, 0x2c, 0xe0, 0xd3, 0x42, 0x76, 0x0d, 0x81, 0x4b, 0x81, 0xf0, 0xbd, /// 0x3d30 + 0xf8, 0xb5, 0xe9, 0x48, 0xe9, 0x4c, 0x03, 0x7a, 0xea, 0x48, 0x00, 0x90, 0x40, 0x3c, 0x01, 0x68, /// 0x3d40 + 0xe5, 0x48, 0x25, 0x46, 0x00, 0x68, 0x26, 0x46, 0xe0, 0x35, 0x08, 0x1a, 0x60, 0x36, 0x40, 0x34, /// 0x3d50 + 0x03, 0x2b, 0x4c, 0xd0, 0x06, 0xdc, 0x00, 0x2b, 0x17, 0xd0, 0x01, 0x2b, 0x3e, 0xd0, 0x02, 0x2b, /// 0x3d60 + 0x33, 0xd1, 0x44, 0xe0, 0x0b, 0x2b, 0x42, 0xd0, 0x0c, 0x2b, 0x2e, 0xd1, 0xdb, 0x4f, 0xa9, 0x7b, /// 0x3d70 + 0x80, 0x37, 0x00, 0x29, 0x5c, 0xd0, 0xff, 0x21, 0x91, 0x31, 0x88, 0x42, 0x3c, 0xd9, 0x01, 0x22, /// 0x3d80 + 0xba, 0x74, 0xfd, 0xf7, 0x61, 0xfb, 0xc2, 0xb2, 0x39, 0xe0, 0x6a, 0x7e, 0xd6, 0x4b, 0xd2, 0x00, /// 0x3d90 + 0xd2, 0x1c, 0x1a, 0x80, 0xb2, 0x7e, 0x0a, 0x23, 0xcf, 0x4f, 0x5a, 0x43, 0x90, 0x42, 0x14, 0xd9, /// 0x3da0 + 0x00, 0x20, 0x78, 0x76, 0x30, 0x7e, 0x80, 0x07, 0x16, 0xd5, 0xa9, 0x79, 0x20, 0x8d, 0xff, 0xf7, /// 0x3db0 + 0xbf, 0xfe, 0xcd, 0x48, 0x01, 0x88, 0x02, 0x22, 0x11, 0x43, 0x01, 0x80, 0x39, 0x7b, 0xc9, 0x07, /// 0x3dc0 + 0x04, 0xd0, 0x0c, 0x21, 0x39, 0x72, 0xfb, 0x21, 0x01, 0x80, 0xf8, 0xbd, 0x00, 0x98, 0x00, 0x68, /// 0x3dd0 + 0x38, 0x60, 0x01, 0x20, 0x38, 0x72, 0xf8, 0xbd, 0x39, 0x60, 0xf8, 0xbd, 0x5a, 0x28, 0xfc, 0xd9, /// 0x3de0 + 0xa0, 0x8e, 0xc2, 0x49, 0x08, 0x40, 0xa0, 0x86, 0xff, 0xf7, 0x78, 0xff, 0x01, 0xe0, 0xaa, 0x28, /// 0x3df0 + 0xf3, 0xd9, 0xff, 0xf7, 0x67, 0xfe, 0xf8, 0xbd, 0xb8, 0x7c, 0x01, 0x28, 0x18, 0xd1, 0x00, 0x20, /// 0x3e00 + 0xb8, 0x74, 0x03, 0x2a, 0x00, 0xd3, 0x00, 0x22, 0xb4, 0x48, 0xb9, 0x49, 0x40, 0x38, 0x80, 0x18, /// 0x3e10 + 0xe0, 0x30, 0x00, 0x7c, 0x00, 0x02, 0x00, 0x1d, 0x88, 0x82, 0xaf, 0x4b, 0x60, 0x8c, 0xd9, 0x8a, /// 0x3e20 + 0x88, 0x42, 0x05, 0xd2, 0x02, 0x2a, 0x03, 0xd3, 0xff, 0x21, 0x59, 0x71, 0xff, 0xf7, 0x80, 0xfe, /// 0x3e30 + 0xa9, 0x4a, 0x10, 0x7b, 0xc0, 0x07, 0x16, 0xd1, 0x00, 0x98, 0x11, 0x68, 0x00, 0x68, 0x40, 0x1a, /// 0x3e40 + 0xac, 0x49, 0x88, 0x42, 0x0f, 0xd9, 0xa0, 0x8e, 0xff, 0x21, 0x01, 0x31, 0x08, 0x43, 0xa0, 0x86, /// 0x3e50 + 0x70, 0x7e, 0x40, 0x21, 0x08, 0x43, 0x70, 0x76, 0x10, 0x7a, 0x0c, 0x28, 0xc9, 0xd1, 0x20, 0x20, /// 0x3e60 + 0xfc, 0xf7, 0x38, 0xfe, 0xc5, 0xe7, 0xe0, 0x8e, 0xc0, 0x06, 0x12, 0xd5, 0xa0, 0x8f, 0x41, 0x1c, /// 0x3e70 + 0xa1, 0x87, 0xe1, 0x8f, 0x88, 0x42, 0xbe, 0xd9, 0xa0, 0x8e, 0x80, 0x21, 0x08, 0x43, 0xa0, 0x86, /// 0x3e80 + 0xff, 0xf7, 0x0e, 0xfe, 0x00, 0x20, 0xa0, 0x87, 0xe0, 0x8e, 0x10, 0x21, 0x88, 0x43, 0xe0, 0x86, /// 0x3e90 + 0xf8, 0xbd, 0x00, 0x23, 0xa3, 0x87, 0xf8, 0x8a, 0x97, 0x49, 0x88, 0x42, 0xf8, 0xd9, 0xf8, 0x7f, /// 0x3ea0 + 0x00, 0x28, 0x0d, 0xd0, 0x01, 0x28, 0xf3, 0xd1, 0x50, 0x79, 0x29, 0x7b, 0x88, 0x42, 0xef, 0xd8, /// 0x3eb0 + 0x78, 0x8d, 0x60, 0x84, 0xff, 0x21, 0x51, 0x71, 0xfb, 0x77, 0xff, 0xf7, 0x39, 0xfe, 0xf8, 0xbd, /// 0x3ec0 + 0x60, 0x8c, 0xff, 0x21, 0xe0, 0x31, 0x88, 0x42, 0xf9, 0xd3, 0x38, 0x8d, 0x60, 0x84, 0xe9, 0x79, /// 0x3ed0 + 0x51, 0x71, 0x01, 0x22, 0xfa, 0x77, 0xf0, 0xe7, 0x10, 0xb5, 0x88, 0x48, 0x80, 0x89, 0x80, 0x06, /// 0x3ee0 + 0x80, 0x0f, 0x12, 0xd0, 0x7d, 0x48, 0x81, 0x8e, 0x4a, 0x04, 0x0e, 0xd4, 0x01, 0x22, 0x92, 0x03, /// 0x3ef0 + 0x11, 0x43, 0x81, 0x86, 0x20, 0x20, 0xfc, 0xf7, 0xed, 0xfd, 0x78, 0x48, 0x20, 0x22, 0x20, 0x30, /// 0x3f00 + 0x41, 0x7e, 0x11, 0x43, 0x41, 0x76, 0xff, 0xf7, 0xdd, 0xfd, 0x10, 0xbd, 0x70, 0xb5, 0x73, 0x4c, /// 0x3f10 + 0x7b, 0x4a, 0x61, 0x8e, 0x26, 0x46, 0xa0, 0x8e, 0x6f, 0x4d, 0x20, 0x36, 0x91, 0x42, 0x10, 0xd2, /// 0x3f20 + 0xc1, 0x04, 0x28, 0xd4, 0x69, 0x7b, 0x4a, 0x1c, 0x6a, 0x73, 0x28, 0x29, 0x23, 0xd9, 0x01, 0x21, /// 0x3f30 + 0x09, 0x03, 0x08, 0x43, 0xa0, 0x86, 0x20, 0x20, 0xfc, 0xf7, 0xcc, 0xfd, 0x70, 0x7e, 0x08, 0x21, /// 0x3f40 + 0x0d, 0xe0, 0x00, 0x22, 0x6a, 0x73, 0xa3, 0x8d, 0x01, 0x22, 0xd2, 0x02, 0x99, 0x42, 0x0b, 0xd9, /// 0x3f50 + 0x10, 0x43, 0xa0, 0x86, 0x20, 0x20, 0xfc, 0xf7, 0xbd, 0xfd, 0x70, 0x7e, 0x04, 0x21, 0x08, 0x43, /// 0x3f60 + 0x70, 0x76, 0xff, 0xf7, 0xaf, 0xfd, 0x06, 0xe0, 0x62, 0x4e, 0x76, 0x42, 0x9b, 0x19, 0x99, 0x42, /// 0x3f70 + 0x01, 0xda, 0x90, 0x43, 0xa0, 0x86, 0x2e, 0x20, 0x20, 0x5e, 0x61, 0x8d, 0x88, 0x42, 0x04, 0xdc, /// 0x3f80 + 0x29, 0x8a, 0xe1, 0x22, 0xd2, 0x00, 0x91, 0x42, 0x04, 0xd9, 0x55, 0x49, 0xe2, 0x8d, 0x0a, 0x80, /// 0x3f90 + 0x2a, 0x8a, 0x4a, 0x80, 0x29, 0x7a, 0x01, 0x29, 0x09, 0xd8, 0xa1, 0x8e, 0x09, 0x04, 0x06, 0xd4, /// 0x3fa0 + 0xff, 0x21, 0xf5, 0x31, 0x88, 0x42, 0x02, 0xdd, 0x68, 0x7e, 0x40, 0x1c, 0x68, 0x76, 0x70, 0xbd, /// 0x3fb0 + 0xf8, 0xb5, 0x49, 0x48, 0x02, 0x22, 0xc1, 0x7c, 0x11, 0x43, 0xc1, 0x74, 0x09, 0x22, 0x02, 0x21, /// 0x3fc0 + 0x00, 0x20, 0xfc, 0xf7, 0x87, 0xfa, 0x4f, 0x49, 0x88, 0x42, 0x7d, 0xd0, 0x09, 0x22, 0x02, 0x21, /// 0x3fd0 + 0x00, 0x20, 0xfc, 0xf7, 0x7f, 0xfa, 0x84, 0x08, 0xa0, 0x01, 0x0a, 0x21, 0xfd, 0xf7, 0x34, 0xfa, /// 0x3fe0 + 0x3e, 0x4d, 0x80, 0xb2, 0x29, 0x46, 0x68, 0x86, 0x40, 0x39, 0x89, 0x78, 0x05, 0x29, 0x05, 0xd3, /// 0x3ff0 + 0x3b, 0x21, 0x48, 0x43, 0x32, 0x21, 0xfd, 0xf7, 0x27, 0xfa, 0x68, 0x86, 0x20, 0x46, 0x42, 0x4c, /// 0x4000 + 0x42, 0x4e, 0xa1, 0x7b, 0x09, 0x27, 0x49, 0x00, 0x89, 0x19, 0xbf, 0x01, 0xc9, 0x19, 0x88, 0x82, /// 0x4010 + 0x0b, 0x22, 0x04, 0x21, 0x01, 0x20, 0xfc, 0xf7, 0x5d, 0xfa, 0x3a, 0x49, 0x88, 0x42, 0x53, 0xd0, /// 0x4020 + 0x0b, 0x22, 0x04, 0x21, 0x01, 0x20, 0xfc, 0xf7, 0x55, 0xfa, 0x2c, 0x4b, 0x38, 0x49, 0x40, 0x08, /// 0x4030 + 0x80, 0x33, 0x48, 0x43, 0x9a, 0x8b, 0x00, 0x0b, 0x82, 0x42, 0x01, 0xd9, 0x00, 0x20, 0x07, 0xe0, /// 0x4040 + 0x99, 0x7f, 0x80, 0x1a, 0x5b, 0x8b, 0x33, 0x4a, 0x59, 0x43, 0x50, 0x43, 0xfd, 0xf7, 0xfc, 0xf9, /// 0x4050 + 0xa1, 0x7b, 0x49, 0x00, 0x89, 0x19, 0xc9, 0x19, 0x88, 0x84, 0x2b, 0x48, 0x20, 0x38, 0x81, 0x8c, /// 0x4060 + 0x01, 0x20, 0x42, 0x00, 0x93, 0x19, 0x09, 0x22, 0x92, 0x01, 0x9a, 0x18, 0x92, 0x8c, 0x40, 0x1c, /// 0x4070 + 0x51, 0x18, 0xc0, 0xb2, 0x89, 0xb2, 0x04, 0x28, 0xf3, 0xd3, 0x88, 0x08, 0xa8, 0x80, 0x16, 0x4f, /// 0x4080 + 0xe8, 0x85, 0xf9, 0x7b, 0x49, 0x1c, 0xc9, 0xb2, 0xf9, 0x73, 0x05, 0x29, 0x11, 0xd3, 0x00, 0x21, /// 0x4090 + 0xf9, 0x73, 0xb9, 0x8a, 0x08, 0x18, 0x80, 0xb2, 0xb8, 0x82, 0xb9, 0x7c, 0x49, 0x1c, 0xc9, 0xb2, /// 0x40a0 + 0xb9, 0x74, 0x0f, 0x29, 0x05, 0xd3, 0xfd, 0xf7, 0xcf, 0xf9, 0x38, 0x82, 0x00, 0x20, 0xb8, 0x74, /// 0x40b0 + 0xb8, 0x82, 0x02, 0x22, 0x08, 0x21, 0x03, 0x20, 0xfc, 0xf7, 0x0c, 0xfa, 0x11, 0x4f, 0xb8, 0x42, /// 0x40c0 + 0x51, 0xd0, 0x02, 0x22, 0x08, 0x21, 0x00, 0xe0, 0x4d, 0xe0, 0x03, 0x20, 0xfc, 0xf7, 0x02, 0xfa, /// 0x40d0 + 0x29, 0x21, 0x49, 0x03, 0x41, 0x43, 0x1f, 0xe0, 0x70, 0x04, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, /// 0x40e0 + 0xf0, 0x04, 0x00, 0x20, 0x30, 0x02, 0x00, 0x20, 0x00, 0x34, 0x00, 0x40, 0xfe, 0xc3, 0xff, 0xff, /// 0x40f0 + 0x60, 0x40, 0x00, 0x40, 0xdc, 0x05, 0x00, 0x00, 0x4c, 0x1d, 0x00, 0x00, 0x20, 0x48, 0x00, 0x40, /// 0x4100 + 0xd8, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x90, 0x03, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, /// 0x4110 + 0x34, 0x08, 0x00, 0x00, 0xa0, 0x86, 0x01, 0x00, 0x09, 0x0c, 0x29, 0x86, 0xa1, 0x7b, 0x49, 0x00, /// 0x4120 + 0x8a, 0x19, 0x09, 0x21, 0x89, 0x01, 0x51, 0x18, 0x88, 0x83, 0x04, 0x22, 0x08, 0x21, 0x07, 0x20, /// 0x4130 + 0xfc, 0xf7, 0xd0, 0xf9, 0xb8, 0x42, 0x16, 0xd0, 0x04, 0x22, 0x08, 0x21, 0x07, 0x20, 0xfc, 0xf7, /// 0x4140 + 0xc9, 0xf9, 0xa4, 0x49, 0x88, 0x42, 0x00, 0xd2, 0x08, 0x46, 0x4b, 0x21, 0x48, 0x43, 0x7d, 0x21, /// 0x4150 + 0xc9, 0x00, 0xfd, 0xf7, 0x79, 0xf9, 0xa0, 0x49, 0xae, 0x38, 0xc8, 0x76, 0xa0, 0x7b, 0x03, 0x28, /// 0x4160 + 0x03, 0xd3, 0x00, 0x20, 0x02, 0xe0, 0x00, 0x20, 0xf8, 0xbd, 0x40, 0x1c, 0xa0, 0x73, 0xff, 0xf7, /// 0x4170 + 0xcd, 0xfe, 0xff, 0xf7, 0xb1, 0xfe, 0xf6, 0xe7, 0x10, 0xb5, 0x98, 0x49, 0x01, 0x20, 0x48, 0x72, /// 0x4180 + 0x97, 0x49, 0x00, 0x20, 0x08, 0x70, 0x97, 0x48, 0x69, 0x22, 0x02, 0x71, 0x6b, 0x24, 0x44, 0x71, /// 0x4190 + 0x02, 0x72, 0x02, 0x23, 0x43, 0x72, 0x02, 0x73, 0x44, 0x73, 0x02, 0x74, 0x24, 0x22, 0x42, 0x74, /// 0x41a0 + 0xb4, 0x22, 0x0a, 0x70, 0x8d, 0x4a, 0xac, 0x3a, 0x0a, 0x81, 0x07, 0x22, 0x8a, 0x80, 0x8c, 0x49, /// 0x41b0 + 0x20, 0x39, 0x0b, 0x72, 0x0a, 0x79, 0x72, 0xb6, 0x1a, 0x43, 0x0a, 0x71, 0x89, 0x49, 0x62, 0xb6, /// 0x41c0 + 0x20, 0x31, 0x0a, 0x7a, 0xfb, 0x23, 0x1a, 0x40, 0x0a, 0x72, 0x01, 0x88, 0x10, 0x22, 0x11, 0x43, /// 0x41d0 + 0x01, 0x80, 0x10, 0xbd, 0x84, 0x49, 0x5a, 0x20, 0x08, 0x70, 0x83, 0x49, 0x20, 0x31, 0x08, 0x80, /// 0x41e0 + 0x82, 0x48, 0xc1, 0x7c, 0x49, 0x08, 0x49, 0x00, 0xc1, 0x74, 0x70, 0x47, 0x30, 0xb5, 0x7e, 0x48, /// 0x41f0 + 0x5a, 0x21, 0x01, 0x70, 0x81, 0x8a, 0x42, 0x14, 0x11, 0x43, 0x81, 0x82, 0x79, 0x49, 0x0a, 0x88, /// 0x4200 + 0x83, 0x14, 0x1a, 0x43, 0x0a, 0x80, 0x7a, 0x49, 0x01, 0x82, 0x7a, 0x49, 0x01, 0x83, 0x09, 0x21, /// 0x4210 + 0x01, 0x72, 0x79, 0x49, 0x81, 0x81, 0x79, 0x48, 0x01, 0x21, 0x01, 0x80, 0xff, 0x22, 0x82, 0x80, /// 0x4220 + 0x05, 0x22, 0x02, 0x81, 0x76, 0x4c, 0x84, 0x81, 0x07, 0x22, 0x02, 0x80, 0x73, 0x4b, 0x75, 0x4a, /// 0x4230 + 0x20, 0x33, 0x1a, 0x80, 0x68, 0x4a, 0x60, 0x3a, 0x95, 0x78, 0x73, 0x4a, 0x05, 0x2d, 0x92, 0x78, /// 0x4240 + 0x00, 0xd2, 0x0a, 0x43, 0x1a, 0x71, 0x04, 0x82, 0x00, 0x22, 0x02, 0x75, 0x6f, 0x48, 0x01, 0x81, /// 0x4250 + 0x61, 0x48, 0x80, 0x30, 0x40, 0x7e, 0xc2, 0x00, 0x6c, 0x48, 0x40, 0x38, 0xd2, 0x1c, 0x02, 0x80, /// 0x4260 + 0x81, 0x80, 0x30, 0x21, 0x81, 0x81, 0x30, 0xbd, 0x5b, 0x48, 0x10, 0xb5, 0x20, 0x38, 0x41, 0x7b, /// 0x4270 + 0x09, 0x09, 0x09, 0x01, 0x41, 0x73, 0xff, 0xf7, 0x03, 0xfc, 0xff, 0xf7, 0xc0, 0xfc, 0xff, 0xf7, /// 0x4280 + 0x20, 0xf9, 0x00, 0x20, 0x10, 0xbd, 0x70, 0xb5, 0x53, 0x4c, 0x00, 0x21, 0x20, 0x3c, 0xa0, 0x7b, /// 0x4290 + 0xe1, 0x81, 0x80, 0x06, 0x01, 0xd5, 0xfc, 0xf7, 0x2c, 0xfc, 0xe0, 0x8e, 0xc1, 0x07, 0x31, 0xd0, /// 0x42a0 + 0x40, 0x08, 0x40, 0x00, 0xe0, 0x86, 0x4c, 0x48, 0x01, 0x7e, 0x01, 0x29, 0x31, 0xd1, 0x02, 0x21, /// 0x42b0 + 0x4d, 0x4c, 0x01, 0x76, 0xa0, 0x8b, 0x08, 0x25, 0xa8, 0x43, 0xa0, 0x83, 0x64, 0x20, 0xfc, 0xf7, /// 0x42c0 + 0xda, 0xfb, 0xa0, 0x8b, 0x28, 0x43, 0xa0, 0x83, 0x64, 0x20, 0xfc, 0xf7, 0xd4, 0xfb, 0xa0, 0x8b, /// 0x42d0 + 0xa8, 0x43, 0xa0, 0x83, 0x64, 0x20, 0xfc, 0xf7, 0xce, 0xfb, 0xa0, 0x8b, 0x28, 0x43, 0xa0, 0x83, /// 0x42e0 + 0x64, 0x20, 0xfc, 0xf7, 0xc8, 0xfb, 0xa0, 0x8b, 0x11, 0x21, 0x08, 0x43, 0xa0, 0x83, 0xa0, 0x8b, /// 0x42f0 + 0x61, 0x15, 0x08, 0x43, 0xa0, 0x83, 0x46, 0x48, 0xfb, 0xf7, 0xc9, 0xfe, 0x20, 0x20, 0xfc, 0xf7, /// 0x4300 + 0xe9, 0xfb, 0x06, 0xe0, 0x41, 0x07, 0x04, 0xd5, 0x04, 0x21, 0x88, 0x43, 0xe0, 0x86, 0xff, 0xf7, /// 0x4310 + 0xc7, 0xfb, 0x00, 0x20, 0x70, 0xbd, 0xf8, 0xb5, 0x34, 0x4c, 0x20, 0x7b, 0x81, 0x07, 0x04, 0xd4, /// 0x4320 + 0x02, 0x21, 0x08, 0x43, 0x20, 0x73, 0xfe, 0xf7, 0xf9, 0xfe, 0x2b, 0x4f, 0x38, 0x7e, 0x81, 0x07, /// 0x4330 + 0x02, 0xd5, 0x21, 0x7a, 0x00, 0x29, 0x1b, 0xd1, 0x00, 0x07, 0x19, 0xd4, 0x00, 0x26, 0x35, 0x4d, /// 0x4340 + 0x13, 0xe0, 0x28, 0x78, 0x08, 0x21, 0x08, 0x43, 0x28, 0x70, 0x76, 0x1c, 0xff, 0x20, 0xb6, 0xb2, /// 0x4350 + 0xf5, 0x30, 0x86, 0x42, 0x06, 0xd3, 0x01, 0x20, 0x78, 0x76, 0x20, 0x20, 0xfc, 0xf7, 0xba, 0xfb, /// 0x4360 + 0xff, 0xf7, 0xb0, 0xfb, 0x14, 0x20, 0xfc, 0xf7, 0x86, 0xfb, 0x28, 0x78, 0x00, 0x07, 0xe8, 0xd4, /// 0x4370 + 0x20, 0x7a, 0x0e, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0xa5, 0xfb, 0xe0, 0x7c, 0xc1, 0x07, 0x08, 0xd0, /// 0x4380 + 0x81, 0x07, 0x06, 0xd5, 0x18, 0x4a, 0x03, 0x21, 0x20, 0x32, 0x11, 0x80, 0xfd, 0x21, 0x08, 0x40, /// 0x4390 + 0xe0, 0x74, 0x12, 0x48, 0x40, 0x7a, 0x00, 0x28, 0x03, 0xd1, 0xff, 0xf7, 0xed, 0xfe, 0xff, 0xf7, /// 0x43a0 + 0x07, 0xfe, 0xff, 0xf7, 0x44, 0xfb, 0xff, 0xf7, 0xc3, 0xfc, 0xff, 0xf7, 0x41, 0xfc, 0x0a, 0x48, /// 0x43b0 + 0x20, 0x38, 0xc1, 0x89, 0x4a, 0x06, 0x0a, 0xd5, 0x02, 0x7b, 0x5a, 0x2a, 0x07, 0xd1, 0x00, 0x22, /// 0x43c0 + 0x02, 0x73, 0x40, 0x22, 0x91, 0x43, 0xc1, 0x81, 0x41, 0x7b, 0x11, 0x43, 0x41, 0x73, 0x00, 0x20, /// 0x43d0 + 0xf8, 0xbd, 0x00, 0x00, 0x5a, 0x0a, 0x00, 0x00, 0x60, 0x00, 0x00, 0x20, 0x70, 0x03, 0x00, 0x20, /// 0x43e0 + 0x20, 0x60, 0x00, 0x40, 0x00, 0x44, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, 0x70, 0x04, 0x00, 0x20, /// 0x43f0 + 0xff, 0x07, 0x00, 0x00, 0x70, 0x30, 0x00, 0x00, 0x05, 0x1d, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40, /// 0x4400 + 0xff, 0xff, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x60, 0x67, 0x00, 0x00, 0x40, 0x34, 0x00, 0x40, /// 0x4410 + 0x69, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x40, 0x99, 0x48, 0x01, 0x8b, 0x89, 0x06, 0x02, 0xd5, /// 0x4420 + 0x98, 0x49, 0x01, 0x22, 0x0a, 0x72, 0x30, 0x21, 0x01, 0x83, 0x70, 0x47, 0x70, 0xb5, 0x96, 0x48, /// 0x4430 + 0x96, 0x4d, 0x41, 0x8c, 0x28, 0x46, 0xfd, 0xf7, 0x07, 0xf8, 0x91, 0x4a, 0x81, 0x21, 0x11, 0x80, /// 0x4440 + 0x01, 0x24, 0x14, 0x80, 0x35, 0x21, 0x11, 0x80, 0x07, 0x21, 0x91, 0x80, 0x14, 0x81, 0x80, 0x21, /// 0x4450 + 0x91, 0x81, 0x8f, 0x4a, 0xf9, 0x21, 0x11, 0x80, 0x03, 0x21, 0x91, 0x80, 0xff, 0x21, 0x11, 0x80, /// 0x4460 + 0xc1, 0x1c, 0x28, 0x46, 0xfc, 0xf7, 0xf0, 0xff, 0x89, 0x49, 0x40, 0x31, 0x08, 0x80, 0x88, 0x48, /// 0x4470 + 0x20, 0x30, 0x03, 0x8b, 0x83, 0x4a, 0x20, 0x32, 0x13, 0x81, 0x03, 0x89, 0x53, 0x81, 0x03, 0x8a, /// 0x4480 + 0x93, 0x81, 0x03, 0x88, 0xd3, 0x81, 0x03, 0x8b, 0x0a, 0x88, 0x52, 0x1e, 0x93, 0x42, 0x02, 0xdd, /// 0x4490 + 0x0a, 0x88, 0x52, 0x1e, 0x02, 0x83, 0x03, 0x88, 0x0a, 0x88, 0x52, 0x1e, 0x93, 0x42, 0x02, 0xdd, /// 0x44a0 + 0x0a, 0x88, 0x52, 0x1e, 0x02, 0x80, 0x03, 0x8a, 0x0a, 0x88, 0x52, 0x1e, 0x93, 0x42, 0x02, 0xdd, /// 0x44b0 + 0x0a, 0x88, 0x52, 0x1e, 0x02, 0x82, 0x03, 0x89, 0x0a, 0x88, 0x52, 0x1e, 0x93, 0x42, 0x02, 0xdd, /// 0x44c0 + 0x0a, 0x88, 0x52, 0x1e, 0x02, 0x81, 0x30, 0x20, 0x88, 0x80, 0x0c, 0x81, 0x70, 0xbd, 0x6d, 0x48, /// 0x44d0 + 0x6f, 0x49, 0x20, 0x30, 0x02, 0x89, 0x20, 0x31, 0x0a, 0x83, 0x42, 0x89, 0x0a, 0x81, 0x82, 0x89, /// 0x44e0 + 0x0a, 0x82, 0xc0, 0x89, 0x08, 0x80, 0x66, 0x48, 0x01, 0x21, 0x01, 0x80, 0x4b, 0x21, 0x01, 0x80, /// 0x44f0 + 0x67, 0x49, 0xfb, 0x20, 0x08, 0x80, 0x70, 0x47, 0x62, 0x4b, 0x00, 0x22, 0x1a, 0x72, 0x60, 0x4a, /// 0x4500 + 0x10, 0x82, 0x49, 0x1e, 0x11, 0x75, 0x18, 0x7a, 0x00, 0x28, 0xfc, 0xd0, 0x70, 0x47, 0x70, 0xb5, /// 0x4510 + 0x0c, 0x46, 0x05, 0x46, 0xff, 0xf7, 0x8a, 0xff, 0x08, 0xe0, 0x28, 0x88, 0x10, 0x2c, 0x0a, 0xd9, /// 0x4520 + 0x10, 0x21, 0xad, 0x1c, 0xff, 0xf7, 0xe8, 0xff, 0x10, 0x3c, 0xa4, 0xb2, 0x00, 0x2c, 0xf4, 0xd1, /// 0x4530 + 0xff, 0xf7, 0xcd, 0xff, 0x70, 0xbd, 0x21, 0x46, 0xff, 0xf7, 0xde, 0xff, 0xf8, 0xe7, 0xf0, 0xb5, /// 0x4540 + 0x00, 0x23, 0x02, 0x27, 0x1c, 0x46, 0x9e, 0x46, 0x1d, 0x46, 0x8b, 0x54, 0x05, 0xe0, 0x0e, 0x5d, /// 0x4550 + 0xed, 0xb2, 0x75, 0x40, 0x64, 0x1c, 0x8d, 0x54, 0xe4, 0xb2, 0x94, 0x42, 0xf7, 0xd3, 0x52, 0x1c, /// 0x4560 + 0x92, 0xb2, 0x94, 0x46, 0x00, 0x22, 0x47, 0x4d, 0x14, 0x46, 0x20, 0x3d, 0x56, 0x00, 0x76, 0x19, /// 0x4570 + 0x52, 0x1c, 0xd2, 0xb2, 0xb4, 0x85, 0x1c, 0x2a, 0xf8, 0xd3, 0x73, 0xe0, 0x00, 0x2b, 0x01, 0xd0, /// 0x4580 + 0x00, 0x23, 0x05, 0xe0, 0x02, 0x78, 0x03, 0x23, 0xbb, 0x40, 0x1a, 0x43, 0x02, 0x70, 0x01, 0x23, /// 0x4590 + 0xbf, 0x1c, 0xfa, 0xb2, 0x08, 0x2a, 0x01, 0xd1, 0x00, 0x22, 0x40, 0x1c, 0x00, 0x24, 0x0d, 0x78, /// 0x45a0 + 0xe5, 0x40, 0xef, 0x07, 0xff, 0x0f, 0x12, 0xd0, 0x00, 0x2b, 0x06, 0xd0, 0x03, 0x78, 0x02, 0x25, /// 0x45b0 + 0x95, 0x40, 0x2b, 0x43, 0x03, 0x70, 0x01, 0x23, 0x04, 0xe0, 0x05, 0x78, 0x01, 0x26, 0x96, 0x40, /// 0x45c0 + 0x35, 0x43, 0x05, 0x70, 0x75, 0x46, 0xed, 0x19, 0xed, 0xb2, 0xae, 0x46, 0x09, 0xe0, 0x00, 0x2b, /// 0x45d0 + 0x01, 0xd0, 0x00, 0x23, 0x05, 0xe0, 0x03, 0x78, 0x03, 0x25, 0x95, 0x40, 0x2b, 0x43, 0x03, 0x70, /// 0x45e0 + 0x01, 0x23, 0x92, 0x1c, 0xd2, 0xb2, 0x08, 0x2a, 0x01, 0xd1, 0x00, 0x22, 0x40, 0x1c, 0x64, 0x1c, /// 0x45f0 + 0xe4, 0xb2, 0x08, 0x2c, 0xd3, 0xd3, 0x74, 0x46, 0xe4, 0x07, 0x0d, 0xd0, 0x00, 0x2b, 0x05, 0xd0, /// 0x4600 + 0x03, 0x78, 0x02, 0x24, 0x94, 0x40, 0x23, 0x43, 0x03, 0x70, 0x0e, 0xe0, 0x04, 0x78, 0x01, 0x25, /// 0x4610 + 0x95, 0x40, 0x2c, 0x43, 0x04, 0x70, 0x09, 0xe0, 0x00, 0x2b, 0x01, 0xd0, 0x00, 0x23, 0x05, 0xe0, /// 0x4620 + 0x04, 0x78, 0x03, 0x23, 0x93, 0x40, 0x1c, 0x43, 0x04, 0x70, 0x01, 0x23, 0x92, 0x1c, 0xd2, 0xb2, /// 0x4630 + 0x08, 0x2a, 0x01, 0xd1, 0x00, 0x22, 0x40, 0x1c, 0x04, 0x78, 0x00, 0x2b, 0x05, 0xd0, 0x02, 0x23, /// 0x4640 + 0x93, 0x40, 0x1c, 0x43, 0x04, 0x70, 0x01, 0x23, 0x03, 0xe0, 0x01, 0x25, 0x95, 0x40, 0x2c, 0x43, /// 0x4650 + 0x04, 0x70, 0x92, 0x1c, 0xd7, 0xb2, 0x08, 0x2f, 0x01, 0xd1, 0x00, 0x27, 0x40, 0x1c, 0x00, 0x22, /// 0x4660 + 0x96, 0x46, 0x49, 0x1c, 0x62, 0x46, 0x54, 0x1e, 0xa4, 0xb2, 0xa4, 0x46, 0x00, 0x2a, 0x85, 0xd1, /// 0x4670 + 0x00, 0x2b, 0x04, 0xd1, 0x02, 0x78, 0x01, 0x21, 0xb9, 0x40, 0x0a, 0x43, 0x02, 0x70, 0xf0, 0xbd, /// 0x4680 + 0x00, 0x38, 0x00, 0x40, 0x90, 0x04, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, 0x60, 0xea, 0x00, 0x00, /// 0x4690 + 0x00, 0x34, 0x00, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x46a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x46b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x46c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x46d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x46e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x46f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4700 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4710 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4720 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4730 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4740 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4750 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4760 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4770 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4780 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4790 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x47a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x47b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x47c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x47d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x47e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x47f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4800 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4810 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4820 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4830 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4840 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4850 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4860 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4870 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4880 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4890 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x48a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x48b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x48c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x48d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x48e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x48f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4900 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4910 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4920 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4930 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4940 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4950 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4960 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4970 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4980 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4990 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x49a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x49b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x49c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x49d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x49e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x49f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4a90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4aa0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ab0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ac0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ad0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ae0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4af0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4b90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ba0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4bb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4bc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4bd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4be0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4bf0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4c90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ca0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4cb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4cc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4cd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ce0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4cf0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4d90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4da0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4db0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4dc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4dd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4de0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4df0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4e90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ea0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4eb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ec0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ed0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ee0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ef0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4f90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4fa0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4fb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4fc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4fd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4fe0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x4ff0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5000 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5010 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5020 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5030 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5040 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5050 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5060 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5070 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5080 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5090 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x50a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x50b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x50c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x50d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x50e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x50f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5100 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5110 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5120 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5130 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5140 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5150 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5160 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5170 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5180 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5190 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x51a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x51b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x51c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x51d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x51e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x51f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5200 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5210 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5220 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5230 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5240 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5250 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5260 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5270 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5280 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5290 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x52a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x52b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x52c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x52d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x52e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x52f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5300 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5310 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5320 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5330 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5340 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5350 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5360 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5370 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5380 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5390 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x53a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x53b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x53c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x53d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x53e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x53f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5400 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5410 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5420 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5430 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5440 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5450 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5460 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5470 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5480 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5490 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x54a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x54b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x54c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x54d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x54e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x54f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5500 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5510 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5520 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5530 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5540 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5550 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5560 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5570 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5580 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5590 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x55a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x55b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x55c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x55d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x55e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x55f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5600 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5610 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5620 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5630 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5640 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5650 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5660 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5670 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5680 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5690 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x56a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x56b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x56c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x56d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x56e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x56f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5700 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5710 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5720 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5730 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5740 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5750 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5760 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5770 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5780 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5790 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x57a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x57b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x57c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x57d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x57e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x57f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5800 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5810 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5820 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5830 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5840 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5850 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5860 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5870 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5880 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5890 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x58a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x58b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x58c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x58d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x58e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x58f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5900 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5910 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5920 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5930 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5940 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5950 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5960 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5970 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5980 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5990 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x59a0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x59b0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x59c0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x59d0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x59e0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x59f0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5a90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5aa0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ab0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ac0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ad0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ae0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5af0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5b90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ba0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5bb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5bc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5bd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5be0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5bf0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5c90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ca0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5cb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5cc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5cd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ce0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5cf0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5d90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5da0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5db0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5dc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5dd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5de0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5df0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e80 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5e90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ea0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5eb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ec0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ed0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ee0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ef0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f00 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f20 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f30 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f40 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f50 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f60 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f70 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f80 + 0x15, 0x94, 0x04, 0x00, 0x41, 0x05, 0x03, 0x04, 0xa7, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5f90 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5fa0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5fb0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5fc0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5fd0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5fe0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /// 0x5ff0 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; + +#endif diff --git a/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.c b/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.c new file mode 100644 index 0000000000000000000000000000000000000000..f6d82e2882879e654acc4d67c7359fa51df9fa5e --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.c @@ -0,0 +1,6249 @@ +#define pr_fmt(fmt) "WLCHG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "op_chargepump.h" +#include "bq2597x_charger.h" +#include "op_wlchg_rx.h" +#include "op_wlchg_policy.h" + +#include "smb5-lib.h" + +#define JEITA_VOTER "JEITA_VOTER" +#define STEP_VOTER "STEP_VOTER" +#define USER_VOTER "USER_VOTER" +#define DEF_VOTER "DEF_VOTER" +#define MAX_VOTER "MAX_VOTER" +#define EXIT_VOTER "EXIT_VOTER" +#define FFC_VOTER "FFC_VOTER" +#define CEP_VOTER "CEP_VOTER" +#define QUIET_VOTER "QUIET_VOTER" +#define BATT_VOL_VOTER "BATT_VOL_VOTER" +#define BATT_CURR_VOTER "BATT_CURR_VOTER" +#define SKIN_VOTER "SKIN_VOTER" +#define STARTUP_CEP_VOTER "STARTUP_CEP_VOTER" +#define HW_ERR_VOTER "HW_ERR_VOTER" +#define CURR_ERR_VOTER "CURR_ERR_VOTER" + +// pmic fcc vote +#define WLCH_VOTER "WLCH_VOTER" +#define WLCH_SKIN_VOTER "WLCH_SKIN_VOTER" + +#define BATT_TEMP_HYST 20 + +static struct op_chg_chip *g_op_chip; +static struct external_battery_gauge *exfg_instance; +static struct bq2597x *exchgpump_bq; +static struct rx_chip *g_rx_chip; +struct smb_charger *normal_charger; +static int reverse_charge_status = 0; +static int wpc_chg_quit_max_cnt; +/* + * Determine whether to delay the disappearance of the charging + * icon when charging is disconnected. + */ +static int chg_icon_update_delay = true; + +#ifdef OP_DEBUG +static bool force_epp; +static bool force_bpp; +static int proc_charge_pump_status; +static bool auto_mode = true; +#endif +static BLOCKING_NOTIFIER_HEAD(reverse_charge_chain); + +static bool enable_deviated_check; +module_param_named( + enable_deviated_check, enable_deviated_check, bool, 0600 +); + +void op_set_wrx_en_value(int value); +void op_set_wrx_otg_value(int value); +void op_set_dcdc_en_value(int value); +int wlchg_get_usbin_val(void); +static void update_wlchg_started(bool enabled); +static int wlchg_disable_batt_charge(struct op_chg_chip *chip, bool en); + +extern int bq2597x_get_adc_data(struct bq2597x *bq, int channel, int *result); +extern int bq2597x_enable_adc(struct bq2597x *bq, bool enable); +static int reverse_charge_notifier_call_chain(unsigned long val); + + +/*----For FCC/jeita----------------------------------------*/ +#define FCC_DEFAULT 200000 + +static int read_range_data_from_node(struct device_node *node, + const char *prop_str, struct op_range_data *ranges, + int max_threshold, u32 max_value) +{ + int rc = 0, i, length, per_tuple_length, tuples; + + if (!node || !prop_str || !ranges) { + pr_err("Invalid parameters passed\n"); + return -EINVAL; + } + + rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32)); + if (rc < 0) { + pr_err("Count %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + length = rc; + per_tuple_length = sizeof(struct op_range_data) / sizeof(u32); + if (length % per_tuple_length) { + pr_err("%s length (%d) should be multiple of %d\n", + prop_str, length, per_tuple_length); + return -EINVAL; + } + tuples = length / per_tuple_length; + + if (tuples > MAX_STEP_CHG_ENTRIES) { + pr_err("too many entries(%d), only %d allowed\n", + tuples, MAX_STEP_CHG_ENTRIES); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, prop_str, + (u32 *)ranges, length); + if (rc) { + pr_err("Read %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + for (i = 0; i < tuples; i++) { + if (ranges[i].low_threshold > + ranges[i].high_threshold) { + pr_err("%s thresholds should be in ascendant ranges\n", + prop_str); + rc = -EINVAL; + goto clean; + } + + if (ranges[i].low_threshold > max_threshold) + ranges[i].low_threshold = max_threshold; + if (ranges[i].high_threshold > max_threshold) + ranges[i].high_threshold = max_threshold; + if (ranges[i].curr_ua > max_value) + ranges[i].curr_ua = max_value; + } + + return tuples; +clean: + memset(ranges, 0, tuples * sizeof(struct op_range_data)); + return rc; +} + +static int read_temp_region_data_from_node(struct device_node *node, + const char *prop_str, int *addr) +{ + int rc = 0, length; + + if (!node || !prop_str || !addr) { + pr_err("Invalid parameters passed\n"); + return -EINVAL; + } + + rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32)); + if (rc < 0) { + pr_err("Count %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + length = rc; + + if (length > WLCHG_TEMP_REGION_MAX) { + pr_err("too many entries(%d), only %d allowed\n", + length, WLCHG_TEMP_REGION_MAX); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, prop_str, + (u32 *)addr, length); + if (rc) { + pr_err("Read %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + return rc; +} + +static int read_data_from_node(struct device_node *node, + const char *prop_str, int *addr, int len) +{ + int rc = 0, length; + + if (!node || !prop_str || !addr) { + pr_err("Invalid parameters passed\n"); + return -EINVAL; + } + + rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32)); + if (rc < 0) { + pr_err("Count %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + length = rc; + + if (length > len) { + pr_err("too many entries(%d), only %d allowed\n", length, len); + length = len; + } + + rc = of_property_read_u32_array(node, prop_str, + (u32 *)addr, length); + if (rc) { + pr_err("Read %s failed, rc=%d\n", prop_str, rc); + return rc; + } + + return rc; +} + +static int wireless_chg_init(struct op_chg_chip *chip) +{ + struct device_node *node = chip->dev->of_node; + struct charge_param *chg_param = &chip->chg_param; + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + int i; + int rc; + + rc = of_property_read_u32(node, "op,max-voltage-mv", &chg_param->batt_vol_max); + if (rc < 0) { + pr_err("max-voltage_uv reading failed, rc=%d\n", rc); + chg_param->batt_vol_max = 4550; + } + + rc = of_property_read_u32(node, "op,fastchg-curr-max-ma", &chg_param->fastchg_curr_max); + if (rc < 0) { + pr_err("fastchg-curr-max-ma reading failed, rc=%d\n", rc); + chg_param->fastchg_curr_max = 1500; + } + + rc = of_property_read_u32(node, "op,fastchg-curr-min-ma", &chg_param->fastchg_curr_min); + if (rc < 0) { + pr_err("fastchg-curr-min-ma reading failed, rc=%d\n", rc); + chg_param->fastchg_curr_min = 400; + } + + rc = of_property_read_u32(node, "op,fastchg-vol-entry-max-mv", &chg_param->fastchg_vol_entry_max); + if (rc < 0) { + pr_err("fastchg-vol-entry-max-mv reading failed, rc=%d\n", rc); + chg_param->fastchg_vol_entry_max = 4380; + } + + rc = of_property_read_u32(node, "op,fastchg-vol-normal-max-mv", &chg_param->fastchg_vol_normal_max); + if (rc < 0) { + pr_err("fastchg-vol-normal-max-mv reading failed, rc=%d\n", rc); + chg_param->fastchg_vol_normal_max = 4480; + } + + rc = of_property_read_u32(node, "op,fastchg-vol-hot-max-mv", &chg_param->fastchg_vol_hot_max); + if (rc < 0) { + pr_err("fastchg-vol-hot-max-mv reading failed, rc=%d\n", rc); + chg_param->fastchg_vol_hot_max = 4130; + } + + rc = of_property_read_u32(node, "op,fastchg-vol-min-mv", &chg_param->fastchg_vol_min); + if (rc < 0) { + pr_err("fastchg-vol-min-mv reading failed, rc=%d\n", rc); + chg_param->fastchg_vol_min = 3300; + } + + rc = of_property_read_u32(node, "op,fastchg-temp-max", &chg_param->fastchg_temp_max); + if (rc < 0) { + pr_err("fastchg-temp-max reading failed, rc=%d\n", rc); + chg_param->fastchg_temp_max = 440; + } + + rc = of_property_read_u32(node, "op,fastchg-temp-min", &chg_param->fastchg_temp_min); + if (rc < 0) { + pr_err("fastchg-temp-min reading failed, rc=%d\n", rc); + chg_param->fastchg_temp_min = 120; + } + + rc = of_property_read_u32(node, "op,fastchg-soc-max", &chg_param->fastchg_soc_max); + if (rc < 0) { + pr_err("fastchg-soc-max reading failed, rc=%d\n", rc); + chg_param->fastchg_soc_max = 85; + } + + rc = of_property_read_u32(node, "op,fastchg-soc-min", &chg_param->fastchg_soc_min); + if (rc < 0) { + pr_err("fastchg-soc-min reading failed, rc=%d\n", rc); + chg_param->fastchg_soc_min = 0; + } + + rc = of_property_read_u32(node, "op,fastchg-soc-mid", &chg_param->fastchg_soc_mid); + if (rc < 0) { + pr_err("fastchg-soc-mid reading failed, rc=%d\n", rc); + chg_param->fastchg_soc_mid = 75; + } + + rc = of_property_read_u32(node, "op,fastchg-discharge-curr-max", &chg_param->fastchg_discharge_curr_max); + if (rc < 0) { + pr_err("fastchg-discharge-curr-max reading failed, rc=%d\n", rc); + chg_param->fastchg_discharge_curr_max = 2000; + } + + rc = of_property_read_u32(node, "cold-bat-decidegc", &chg_param->BATT_TEMP_T0); + if (rc < 0) { + pr_err("cold-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T0 = -20; + } else { + chg_param->BATT_TEMP_T0 = 0 - chg_param->BATT_TEMP_T0; + } + + rc = of_property_read_u32(node, "little-cold-bat-decidegc", &chg_param->BATT_TEMP_T1); + if (rc < 0) { + pr_err("little-cold-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T1 = 0; + } + + rc = of_property_read_u32(node, "cool-bat-decidegc", &chg_param->BATT_TEMP_T2); + if (rc < 0) { + pr_err("cool-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T2 = 50; + } + + rc = of_property_read_u32(node, "little-cool-bat-decidegc", &chg_param->BATT_TEMP_T3); + if (rc < 0) { + pr_err("little-cool-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T3 = 120; + } + + rc = of_property_read_u32(node, "pre-normal-bat-decidegc", &chg_param->BATT_TEMP_T4); + if (rc < 0) { + pr_err("pre-normal-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T4 = 160; + } + + rc = of_property_read_u32(node, "warm-bat-decidegc", &chg_param->BATT_TEMP_T5); + if (rc < 0) { + pr_err("warm-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T5 = 440; + } + + rc = of_property_read_u32(node, "hot-bat-decidegc", &chg_param->BATT_TEMP_T6); + if (rc < 0) { + pr_err("hot-bat-decidegc reading failed, rc=%d\n", rc); + chg_param->BATT_TEMP_T6 = 500; + } + + chg_info("temp region: %d, %d, %d, %d, %d, %d, %d", + chg_param->BATT_TEMP_T0, chg_param->BATT_TEMP_T1, + chg_param->BATT_TEMP_T2, chg_param->BATT_TEMP_T3, + chg_param->BATT_TEMP_T4, chg_param->BATT_TEMP_T5, + chg_param->BATT_TEMP_T6); + + rc = read_temp_region_data_from_node(node, "op,epp-ibatmax-ma", chg_param->epp_ibatmax); + if (rc < 0) { + pr_err("Read op,epp-ibatmax-ma failed, rc=%d\n", rc); + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_COLD] = 0; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COLD] = 1000; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_COOL] = 2500; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COOL] = 2500; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_PRE_NORMAL] = 2500; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_NORMAL] = 2500; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_WARM] = 1500; + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_HOT] = 0; + } + chg_info("ibatmax-epp: %d, %d, %d, %d, %d, %d, %d, %d", + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_COLD], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COLD], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_COOL], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COOL], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_PRE_NORMAL], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_NORMAL], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_WARM], + chg_param->epp_ibatmax[WLCHG_BATT_TEMP_HOT]); + + rc = read_temp_region_data_from_node(node, "op,bpp-ibatmax-ma", chg_param->bpp_ibatmax); + if (rc < 0) { + pr_err("Read op,bpp-ibatmax-ma failed, rc=%d\n", rc); + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_COLD] = 0; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COLD] = 1000; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_COOL] = 1500; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COOL] = 1500; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_PRE_NORMAL] = 1500; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_NORMAL] = 1500; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_WARM] = 1500; + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_HOT] = 0; + } + chg_info("ibatmax-bpp: %d, %d, %d, %d, %d, %d, %d, %d", + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_COLD], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COLD], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_COOL], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_LITTLE_COOL], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_PRE_NORMAL], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_NORMAL], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_WARM], + chg_param->bpp_ibatmax[WLCHG_BATT_TEMP_HOT]); + + rc = read_temp_region_data_from_node(node, "op,epp-iclmax-ma", chg_param->epp_iclmax); + if (rc < 0) { + pr_err("Read op,epp-iclmax-ma failed, rc=%d\n", rc); + chg_param->epp_iclmax[WLCHG_BATT_TEMP_COLD] = 0; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_LITTLE_COLD] = 300; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_COOL] = 1100; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_LITTLE_COOL] = 1100; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_PRE_NORMAL] = 1100; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_NORMAL] = 1100; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_WARM] = 650; + chg_param->epp_iclmax[WLCHG_BATT_TEMP_HOT] = 0; + } + chg_info("iclmax-epp: %d, %d, %d, %d, %d, %d, %d, %d", + chg_param->epp_iclmax[WLCHG_BATT_TEMP_COLD], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_LITTLE_COLD], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_COOL], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_LITTLE_COOL], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_PRE_NORMAL], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_NORMAL], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_WARM], + chg_param->epp_iclmax[WLCHG_BATT_TEMP_HOT]); + + rc = read_temp_region_data_from_node(node, "op,bpp-iclmax-ma", chg_param->bpp_iclmax); + if (rc < 0) { + pr_err("Read op,bpp-iclmax-ma failed, rc=%d\n", rc); + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_COLD] = 0; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_LITTLE_COLD] = 500; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_COOL] = 1000; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_LITTLE_COOL] = 1000; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_PRE_NORMAL] = 1000; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_NORMAL] = 1000; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_WARM] = 1000; + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_HOT] = 0; + } + chg_info("iclmax-bpp: %d, %d, %d, %d, %d, %d, %d, %d", + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_COLD], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_LITTLE_COLD], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_COOL], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_LITTLE_COOL], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_PRE_NORMAL], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_NORMAL], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_WARM], + chg_param->bpp_iclmax[WLCHG_BATT_TEMP_HOT]); + + rc = read_temp_region_data_from_node(node, "vbatdet-mv", chg_param->vbatdet); + if (rc < 0) { + pr_err("Read vbatdet-mv failed, rc=%d\n", rc); + chg_param->vbatdet[WLCHG_BATT_TEMP_COLD] = 0; + chg_param->vbatdet[WLCHG_BATT_TEMP_LITTLE_COLD] = 3675; + chg_param->vbatdet[WLCHG_BATT_TEMP_COOL] = 4235; + chg_param->vbatdet[WLCHG_BATT_TEMP_LITTLE_COOL] = 4370; + chg_param->vbatdet[WLCHG_BATT_TEMP_PRE_NORMAL] = 4370; + chg_param->vbatdet[WLCHG_BATT_TEMP_NORMAL] = 4370; + chg_param->vbatdet[WLCHG_BATT_TEMP_WARM] = 4030; + chg_param->vbatdet[WLCHG_BATT_TEMP_HOT] = 0; + } + + rc = read_temp_region_data_from_node(node, "op,fastchg-ibatmax-ma", chg_param->fastchg_ibatmax); + if (rc < 0) { + pr_err("Read op,fastchg-ibatmax-ma failed, rc=%d\n", rc); + chg_param->fastchg_ibatmax[0] = 4000; + chg_param->fastchg_ibatmax[1] = 6000; + } + + rc = of_property_read_u32(node, "op,rx-freq-threshold", &chg_param->freq_threshold); + if (rc < 0) { + pr_err("op,rx-freq-threshold reading failed, rc=%d\n", rc); + chg_param->freq_threshold = 130; + } + + rc = of_property_read_u32(node, "cool-vbat-thr-mv", &chg_param->cool_vbat_thr_mv); + if (rc < 0) { + pr_err("cool-vbat-thr-mv reading failed, rc=%d\n", rc); + chg_param->cool_vbat_thr_mv = 4180; + } + + rc = of_property_read_u32(node, "cool-epp-ibat-ma", &chg_param->cool_epp_ibat_ma); + if (rc < 0) { + pr_err("cool-epp-ibat-ma reading failed, rc=%d\n", rc); + chg_param->cool_epp_ibat_ma = 1500; + } + + rc = of_property_read_u32(node, "cool-epp-icl-ma", &chg_param->cool_epp_icl_ma); + if (rc < 0) { + pr_err("cool-epp-icl-ma reading failed, rc=%d\n", rc); + chg_param->cool_epp_icl_ma = 650; + } + + rc = of_property_read_u32(node, "fastchg-skin-temp-max", &chg_param->fastchg_skin_temp_max); + if (rc < 0) { + pr_err("fastchg-skin-temp-max reading failed, rc=%d\n", rc); + chg_param->fastchg_skin_temp_max = 420; + } + + rc = of_property_read_u32(node, "fastchg-skin-temp-min", &chg_param->fastchg_skin_temp_min); + if (rc < 0) { + pr_err("fastchg-skin-temp-min reading failed, rc=%d\n", rc); + chg_param->fastchg_skin_temp_min = 400; + } + + rc = of_property_read_u32(node, "epp-skin-temp-max", &chg_param->epp_skin_temp_max); + if (rc < 0) { + pr_err("epp-skin-temp-max reading failed, rc=%d\n", rc); + chg_param->epp_skin_temp_max = 390; + } + + rc = of_property_read_u32(node, "epp-skin-temp-min", &chg_param->epp_skin_temp_min); + if (rc < 0) { + pr_err("epp-skin-temp-min reading failed, rc=%d\n", rc); + chg_param->epp_skin_temp_min = 370; + } + + rc = read_data_from_node(node, "op,epp-curr-step", + chg_param->epp_curr_step, EPP_CURR_STEP_MAX); + if (rc < 0) { + pr_err("Read op,epp-curr-step failed, rc=%d\n", rc); + chg_param->epp_curr_step[0] = 1100; // 10W + chg_param->epp_curr_step[1] = 550; // 5W + } + + chg_param->fastchg_fod_enable = of_property_read_bool(node, "op,fastchg-fod-enable"); + if (chg_param->fastchg_fod_enable) { + rc = of_property_read_u8(node, "op,fastchg-match-q", + &chg_param->fastchg_match_q); + if (rc < 0) { + pr_err("op,fastchg-match-q reading failed, rc=%d\n", rc); + chg_param->fastchg_match_q = 0x44; + } + + rc = of_property_read_u8_array(node, "op,fastchg-fod-parm", + (u8 *)&chg_param->fastchg_fod_parm, FOD_PARM_LENGTH); + if (rc < 0) { + chg_param->fastchg_fod_enable = false; + pr_err("Read op,fastchg-fod-parm failed, rc=%d\n", rc); + } + + rc = of_property_read_u8_array(node, "op,fastchg-fod-parm-startup", + (u8 *)&chg_param->fastchg_fod_parm_startup, FOD_PARM_LENGTH); + if (rc < 0) { + pr_err("Read op,fastchg-fod-parm failed, rc=%d\n", rc); + for (i = 0; i < FOD_PARM_LENGTH; i++) + chg_param->fastchg_fod_parm_startup[i] = + chg_param->fastchg_fod_parm[i]; + } + } + + rc = read_range_data_from_node(node, "op,fastchg-ffc_step", + chg_param->ffc_chg.ffc_step, + chg_param->BATT_TEMP_T5, + chg_param->fastchg_curr_max * 1000); + if (rc < 0) { + pr_err("Read op,fastchg-ffc_step failed, rc=%d\n", rc); + ffc_chg->ffc_step[0].low_threshold = 0; + ffc_chg->ffc_step[0].high_threshold = 405; + ffc_chg->ffc_step[0].curr_ua = 1500000; + ffc_chg->ffc_step[0].vol_max_mv = 4420; + ffc_chg->ffc_step[0].need_wait = 1; + + ffc_chg->ffc_step[1].low_threshold = 380; + ffc_chg->ffc_step[1].high_threshold = 420; + ffc_chg->ffc_step[1].curr_ua = 1000000; + ffc_chg->ffc_step[1].vol_max_mv = 4450; + ffc_chg->ffc_step[1].need_wait = 1; + + ffc_chg->ffc_step[2].low_threshold = 390; + ffc_chg->ffc_step[2].high_threshold = 420; + ffc_chg->ffc_step[2].curr_ua = 850000; + ffc_chg->ffc_step[2].vol_max_mv = 4480; + ffc_chg->ffc_step[2].need_wait = 1; + + ffc_chg->ffc_step[3].low_threshold = 400; + ffc_chg->ffc_step[3].high_threshold = 420; + ffc_chg->ffc_step[3].curr_ua =625000; + ffc_chg->ffc_step[3].vol_max_mv = 4480; + ffc_chg->ffc_step[3].need_wait = 0; + ffc_chg->max_step = 4; + } else { + ffc_chg->max_step = rc; + } + for(i = 0; i < ffc_chg->max_step; i++) { + if (ffc_chg->ffc_step[i].low_threshold > 0) + ffc_chg->allow_fallback[i] = true; + else + ffc_chg->allow_fallback[i] = false; + } + + return 0; +} +/*----For FCC/jeita-------------------end-----------------------------------------*/ +static void wlchg_set_rx_target_voltage(struct op_chg_chip *chip, int vol) +{ + if (chip->wlchg_status.adapter_type == ADAPTER_TYPE_UNKNOWN) + return; + + mutex_lock(&chip->chg_lock); + chip->wlchg_status.curr_limit_mode = false; + chip->wlchg_status.vol_set_ok = false; + chip->wlchg_status.vol_set_start = true; + if (vol > RX_VOLTAGE_MAX) { + chip->wlchg_status.target_vol = RX_VOLTAGE_MAX; + goto out; + } + if (chip->wlchg_status.charge_type == WPC_CHARGE_TYPE_FAST) { + if (vol < FASTCHG_MODE_VOL_MIN) { + chip->wlchg_status.target_vol = FASTCHG_MODE_VOL_MIN; + goto out; + } + } else { + if (vol < NORMAL_MODE_VOL_MIN) { + chip->wlchg_status.target_vol = NORMAL_MODE_VOL_MIN; + goto out; + } + } + chip->wlchg_status.target_vol = vol; +out: + chip->wlchg_status.charge_voltage = chip->wlchg_status.target_vol; + mutex_unlock(&chip->chg_lock); + chg_err("set targte_vol to %d\n", chip->wlchg_status.target_vol); + schedule_delayed_work(&chip->fastchg_curr_vol_work, 0); +} + +/* + * Set vout to the target voltage immediately, no need to set in fastchg_curr_vol_work. + */ +static void wlchg_set_rx_target_voltage_fast(struct op_chg_chip *chip, int vol) +{ + if (chip->wlchg_status.adapter_type == ADAPTER_TYPE_UNKNOWN) + return; + + mutex_lock(&chip->chg_lock); + chip->wlchg_status.curr_limit_mode = false; + chip->wlchg_status.vol_set_ok = false; + chip->wlchg_status.vol_set_start = true; + chip->wlchg_status.vol_set_fast = true; + if (vol > RX_VOLTAGE_MAX) { + chip->wlchg_status.target_vol = RX_VOLTAGE_MAX; + goto out; + } + if (chip->wlchg_status.charge_type == WPC_CHARGE_TYPE_FAST) { + if (vol < FASTCHG_MODE_VOL_MIN) { + chip->wlchg_status.target_vol = FASTCHG_MODE_VOL_MIN; + goto out; + } + } else { + if (vol < NORMAL_MODE_VOL_MIN) { + chip->wlchg_status.target_vol = NORMAL_MODE_VOL_MIN; + goto out; + } + } + chip->wlchg_status.target_vol = vol; +out: + chip->wlchg_status.charge_voltage = chip->wlchg_status.target_vol; + chip->wlchg_status.vol_set = chip->wlchg_status.target_vol; + wlchg_rx_set_vout(g_rx_chip, chip->wlchg_status.vol_set); + mutex_unlock(&chip->chg_lock); + chg_err("set targte_vol to %d\n", chip->wlchg_status.target_vol); + schedule_delayed_work(&chip->fastchg_curr_vol_work, 0); +} + +static int pmic_set_icl_current(int chg_current) +{ + if (normal_charger != NULL) { + chg_err("set usb_icl vote to %d mA\n", chg_current); + vote(normal_charger->usb_icl_votable, WIRED_CONN_VOTER, true, + chg_current * 1000); + return 0; + } + + return -EINVAL; +} + +void notify_pd_in_to_wireless(void) +{ + chg_info("PD adapter in."); + if (!g_op_chip) { + chg_err("<~WPC~> g_op_chip is NULL!\n"); + return; + } + g_op_chip->pd_charger_online = true; +} + +static int wlchg_set_rx_charge_current(struct op_chg_chip *chip, + int chg_current) +{ + if (chip != NULL && normal_charger != NULL) { + chg_err("<~WPC~> set charge current: %d\n", chg_current); + chip->wlchg_status.charge_current = chg_current; + cancel_delayed_work_sync(&chip->wlchg_fcc_stepper_work); + if (pmic_set_icl_current(chg_current) != 0) + return -EINVAL; + return 0; + } else { + return -EINVAL; + } +} + +static int wlchg_set_rx_charge_current_step(struct op_chg_chip *chip, + int chg_current) +{ + if (chip != NULL && normal_charger != NULL) { + chg_err("<~WPC~> set charge current: %d\n", chg_current); + chip->wlchg_status.charge_current = chg_current; + cancel_delayed_work_sync(&chip->wlchg_fcc_stepper_work); + schedule_delayed_work(&chip->wlchg_fcc_stepper_work, 0); + return 0; + } else { + return -EINVAL; + } +} + +static int wlch_fcc_vote_callback(struct votable *votable, void *data, + int icl_ua, const char *client) +{ + struct op_chg_chip *chip = data; + struct wpc_data *chg_status = &chip->wlchg_status; + + if (icl_ua < 0) + return 0; + + if (icl_ua / 1000 > chg_status->max_current) + icl_ua = chg_status->max_current * 1000; + + chg_status->target_curr = icl_ua / 1000; + chg_info("set target current to %d\n", chg_status->target_curr); + + if (!chip->wireless_psy) + chip->wireless_psy = power_supply_get_by_name("wireless"); + + if (chip->wireless_psy) + power_supply_changed(chip->wireless_psy); + + return 0; +} + +static int wlchg_fastchg_disable_vote_callback(struct votable *votable, void *data, + int disable, const char *client) +{ + struct op_chg_chip *chip = data; + struct wpc_data *chg_status = &chip->wlchg_status; + + chg_status->fastchg_disable = disable; + chg_info("%s wireless fast charge\n", disable ? "disable" : "enable"); + + return 0; +} + +static void wlchg_reset_variables(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + chip->pmic_high_vol = false; + + chg_status->charge_status = WPC_CHG_STATUS_DEFAULT; + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP1_STEP; + chg_status->charge_online = false; + chg_status->tx_online = false; + chg_status->tx_present = false; + chg_status->charge_done = false; + chg_status->charge_voltage = 0; + chg_status->charge_current = 0; + chg_status->temp_region = WLCHG_TEMP_REGION_MAX; + chg_status->wpc_dischg_status = WPC_DISCHG_STATUS_OFF; + chg_status->max_current = FASTCHG_CURR_30W_MAX_UA / 1000; + chg_status->target_curr = WPC_CHARGE_CURRENT_DEFAULT; + chg_status->target_vol = WPC_CHARGE_VOLTAGE_DEFAULT; + chg_status->vol_set = WPC_CHARGE_VOLTAGE_DEFAULT; + chg_status->curr_limit_mode = false; + chg_status->vol_set_ok = true; + chg_status->vol_set_start = false; + chg_status->vol_set_fast = false; + chg_status->curr_set_ok = true; + chg_status->startup_fast_chg = false; + chg_status->cep_err_flag = false; + chg_status->ffc_check = false; + chg_status->curr_need_dec = false; + chg_status->vol_not_step = false; //By default, voltage drop requires step + chg_status->is_power_changed = false; + chg_status->deviation_check_done = false; + chg_status->is_deviation = false; + chg_status->freq_check_count = 0; + chg_status->freq_thr_inc = false; + chg_status->wait_cep_stable = false; + chg_status->geted_tx_id = false; + chg_status->quiet_mode_enabled = false; + chg_status->quiet_mode_init = false; + chg_status->get_adapter_err = false; + chg_status->epp_working = false; + chg_status->adapter_msg_send = false; + chg_status->fastchg_disable = false; + chg_status->cep_timeout_adjusted = false; + chg_status->fastchg_restart = false; + chg_status->startup_fod_parm = false; + chg_status->adapter_type = ADAPTER_TYPE_UNKNOWN; + chg_status->charge_type = WPC_CHARGE_TYPE_DEFAULT; + chg_status->send_msg_timer = jiffies; + chg_status->cep_ok_wait_timeout = jiffies; + chg_status->fastchg_retry_timer = jiffies; + chg_status->epp_curr_step = 0; + chg_status->fastchg_curr_step = 0; + chg_status->fastchg_retry_count = 0; + chg_status->curr_err_count = 0; + + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + + chip->cmd_info.cmd = 0; + chip->cmd_info.cmd_type = 0; + chip->cmd_info.cmd_retry_count = 0; + chip->msg_info.type = 0; + chip->msg_info.data = 0; + chip->msg_info.remark = 0; + chip->wlchg_msg_ok = false; + + chip->wlchg_time_count = 0; + + atomic_set(&chip->hb_count, HEARTBEAT_COUNT_MAX); + + if (g_rx_chip != NULL) + wlchg_rx_reset_variables(g_rx_chip); + +#ifdef HW_TEST_EDITION + chip->w30w_time = 2; + chip->w30w_timeout = false; + chip->w30w_work_started = false; +#endif +} +#if 0 +static void op_wireless_set_otg_en_val(int value) +{ + //do nothing now; +} +#endif +static int wlchg_init_connected_task(struct op_chg_chip *chip) +{ + if (!chip->wlchg_status.charge_online) { + wlchg_reset_variables(chip); + chip->wlchg_status.charge_online = true; + } + + return 0; +} + +static int wlchg_deinit_after_disconnected(struct op_chg_chip *chip) +{ + wlchg_reset_variables(chip); + //chargepump_set_for_otg(0); + chargepump_disable(); + bq2597x_enable_charge_pump(false); + /* Resetting the RX chip when the wireless charging is disconnected */ + if (wlchg_get_usbin_val() == 0) { + if (!chip->disable_charge) { + wlchg_rx_set_chip_sleep(1); + msleep(100); + wlchg_rx_set_chip_sleep(0); + } + } + update_wlchg_started(false); + chip->wireless_type = POWER_SUPPLY_TYPE_UNKNOWN; + return 0; +} + +static int pmic_high_vol_en(struct op_chg_chip *chip, bool enable) +{ + if (normal_charger == NULL) { + chg_err("smbchg not ready\n"); + return -ENODEV; + } + + chip->pmic_high_vol = enable; + op_wireless_high_vol_en(enable); + + return 0; +} + +static int wlchg_disable_batt_charge(struct op_chg_chip *chip, bool en) +{ + if (chip->disable_batt_charge == en) + return 0; + + if (normal_charger == NULL) { + chg_err("smb charger is not ready\n"); + return -ENODEV; + } + + chg_info("%s battery wireless charge\n", en ? "disable" : "enable"); + chip->disable_batt_charge = en; + normal_charger->chg_disabled = en; + vote(normal_charger->chg_disable_votable, WLCH_VOTER, en, 0); + + return 0; +} + +#define WPC_DISCHG_WAIT_READY_EVENT \ + round_jiffies_relative(msecs_to_jiffies(200)) +#define WPC_DISCHG_WAIT_DEVICE_EVENT \ + round_jiffies_relative(msecs_to_jiffies(60 * 1000)) +#define WPC_DISCHG_POLL_STATUS_EVENT \ + round_jiffies_relative(msecs_to_jiffies(5000)) +#define WPC_DISCHG_WAIT_STATUS_EVENT \ + round_jiffies_relative(msecs_to_jiffies(500)) + +void wlchg_enable_tx_function(bool is_on) +{ + if ((!g_op_chip) || (!g_rx_chip)) { + chg_err("<~WPC~> Can't set rtx function!\n"); + return; + } + + if (wlchg_rx_fw_updating(g_rx_chip)) { + chg_err("<~WPC~> FW is updating, return!\n"); + return; + } + + mutex_lock(&g_op_chip->connect_lock); + if (is_on) { + chg_err("<~WPC~> Enable rtx function!\n"); + if (g_op_chip->wireless_mode != WIRELESS_MODE_NULL) { + chg_err("<~WPC~> Rtx is used, can't enable tx mode!\n"); + goto out; + } + g_op_chip->wlchg_status.tx_present = true; + + if (!g_op_chip->reverse_wlchg_wake_lock_on) { + chg_info("acquire reverse_wlchg_wake_lock\n"); + __pm_stay_awake(g_op_chip->reverse_wlchg_wake_lock); + g_op_chip->reverse_wlchg_wake_lock_on = true; + } else { + chg_err("reverse_wlchg_wake_lock is already stay awake."); + } + + op_set_wrx_en_value(2); + msleep(20); + op_set_wrx_otg_value(1); + msleep(20); + // set pm8150b vbus out. + smblib_vbus_regulator_enable(normal_charger->vbus_vreg->rdev); + // set pm8150b otg current to 1A. + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_cl, + REVERSE_WIRELESS_CHARGE_CURR_LIMT); + smblib_set_charge_param(normal_charger, &normal_charger->param.otg_vol, + REVERSE_WIRELESS_CHARGE_VOL_LIMT); + msleep(50); + + g_op_chip->wlchg_status.wpc_dischg_status = + WPC_DISCHG_STATUS_ON; + g_op_chip->wireless_mode = WIRELESS_MODE_TX; + cancel_delayed_work_sync(&g_op_chip->dischg_work); + schedule_delayed_work(&g_op_chip->dischg_work, + WPC_DISCHG_WAIT_READY_EVENT); + cancel_delayed_work_sync(&g_op_chip->tx_check_work); + schedule_delayed_work(&g_op_chip->tx_check_work, + msecs_to_jiffies(500)); + chg_err("<~WPC~> Enable rtx end!\n"); + } else { + chg_err("<~WPC~> Disable rtx function!\n"); + if (g_op_chip->wireless_mode != WIRELESS_MODE_TX) { + chg_err("<~WPC~> Rtx function is not enabled, needn't disable!\n"); + goto out; + } + g_op_chip->wlchg_status.tx_present = false; + cancel_delayed_work_sync(&g_op_chip->dischg_work); + g_op_chip->wireless_mode = WIRELESS_MODE_NULL; + if (g_op_chip->wireless_psy != NULL) + power_supply_changed(g_op_chip->wireless_psy); + g_op_chip->wlchg_status.wpc_dischg_status = + WPC_DISCHG_STATUS_OFF; + g_op_chip->wlchg_status.tx_online = false; + //insert the wire charge, disable tp noise mode. + if (g_op_chip->wlchg_status.wpc_dischg_status != WPC_DISCHG_IC_TRANSFER) { + if (reverse_charge_status) { + reverse_charge_notifier_call_chain(0); + reverse_charge_status = 0; + } + } + + // disable pm8150b vbus out. + smblib_vbus_regulator_disable(normal_charger->vbus_vreg->rdev); + msleep(20); + op_set_wrx_otg_value(0); + msleep(20); + if (!typec_is_otg_mode()) + op_set_wrx_en_value(0); + + if (g_op_chip->reverse_wlchg_wake_lock_on) { + chg_info("release reverse_wlchg_wake_lock\n"); + __pm_relax(g_op_chip->reverse_wlchg_wake_lock); + g_op_chip->reverse_wlchg_wake_lock_on = false; + } else { + chg_err("reverse_wlchg_wake_lock is already relax\n"); + } + + chg_err("<~WPC~> Disable rtx end!\n"); + } + if (g_op_chip->wireless_psy != NULL) + power_supply_changed(g_op_chip->wireless_psy); + +out: + mutex_unlock(&g_op_chip->connect_lock); +} + +int wlchg_enable_ftm(bool enable) +{ + chg_err("<~WPC~> start, enable[%d]!\n", enable); + + if (!g_op_chip) { + chg_err("<~WPC~> g_rx_chip is NULL!\n"); + return -EINVAL; + } + + g_op_chip->wlchg_status.ftm_mode = enable; + return 0; +} + +void exfg_information_register(struct external_battery_gauge *exfg) +{ + if (exfg_instance) { + exfg_instance = exfg; + chg_err("multiple battery gauge called\n"); + } else { + exfg_instance = exfg; + } +} +EXPORT_SYMBOL(exfg_information_register); + +void exchg_information_register(struct smb_charger *chg) +{ + if (normal_charger) { + normal_charger = chg; + chg_err("multiple exchg smb5 called\n"); + } else { + normal_charger = chg; + } +} +void exchgpump_information_register(struct bq2597x *bq) +{ + if (exchgpump_bq) { + exchgpump_bq = bq; + chg_err("multiple ex chargepump bq called\n"); + } else { + exchgpump_bq = bq; + } +} + +void exrx_information_register(struct rx_chip *chip) +{ + if (g_rx_chip) { + g_rx_chip = chip; + chg_err("multiple ex chargepump bq called\n"); + } else { + g_rx_chip = chip; + } +} + +static void update_wlchg_started(bool enabled) +{ + if (exfg_instance && exfg_instance->wlchg_started_status) + exfg_instance->wlchg_started_status(enabled); + + if (normal_charger) + normal_charger->wlchg_fast = enabled; +} + +bool wlchg_wireless_charge_start(void) +{ + if (!g_op_chip) { + return 0; + } + return g_op_chip->wlchg_status.charge_online; +} + +bool wlchg_wireless_working(void) +{ + bool working = false; + + if (!g_op_chip) { + chg_err("g_op_chip is null, not ready."); + return false; + } + working = g_op_chip->charger_exist + || g_op_chip->wlchg_status.tx_present; + return working; +} + +int wlchg_wireless_get_vout(void) +{ + if (!g_rx_chip) { + return 0; + } + return g_rx_chip->chg_data.vout; +} + +static char wireless_mode_name[][5] = { "NULL", "TX", "RX" }; + +char *wlchg_wireless_get_mode(struct op_chg_chip *chip) +{ + return wireless_mode_name[chip->wireless_mode]; +} + +static void check_batt_present(struct op_chg_chip *chip) +{ + if (exfg_instance) { + exfg_instance->set_allow_reading(true); + chip->batt_missing = !exfg_instance->is_battery_present(); + exfg_instance->set_allow_reading(false); + } +} + +static void fastchg_curr_control_en(struct op_chg_chip *chip, bool enable) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + + if (enable) { + chg_status->curr_limit_mode = true; + chg_status->curr_need_dec = false; + schedule_delayed_work(&chip->fastchg_curr_vol_work, 0); + } else { + chg_status->curr_limit_mode = false; + } +} + +static bool wlchg_check_charge_done(struct op_chg_chip *chip) +{ + union power_supply_propval pval = {0, }; + int rc; + + if (!chip->batt_psy) { + chip->batt_psy = power_supply_get_by_name("battery"); + if (!chip->batt_psy) { + chg_err("battery psy is not ready\n"); + return false; + } + } + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &pval); + if (rc < 0) { + pr_err("Couldn't get batt status, rc=%d\n", rc); + return false; + } + if (pval.intval == POWER_SUPPLY_STATUS_FULL) + return true; + + return false; +} + +static int wlchg_get_skin_temp(int *temp) +{ + int result; + int rc; + + if (normal_charger == NULL) { + chg_err("smb charge is not ready, exit\n"); + return -ENODEV; + } + if (normal_charger->iio.op_skin_therm_chan == NULL) { + chg_err("op_skin_therm_chan no found!\n"); + return -ENODATA; + } + + rc = iio_read_channel_processed( + normal_charger->iio.op_skin_therm_chan, + &result); + if (rc < 0) { + chg_err("Error in reading IIO channel data, rc=%d\n", rc); + return rc; + } + *temp = result / 100; + + return 0; +} + +#define FFC_STEP_UA 100000 +#define FFC_STEP_TIME_MS 1000 +static void wlchg_fcc_stepper_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, wlchg_fcc_stepper_work); + struct wpc_data *chg_status = &chip->wlchg_status; + const char *client_str; + int ffc_tmp; + int target_curr_ua; + + if (normal_charger == NULL) { + chg_err("smb charge is not ready, exit\n"); + return; + } + + if (!chg_status->charge_online) + return; + + target_curr_ua = chg_status->charge_current * 1000; + ffc_tmp = get_effective_result(normal_charger->usb_icl_votable); + if (target_curr_ua == ffc_tmp) + return; + if (target_curr_ua > ffc_tmp) { + ffc_tmp += FFC_STEP_UA; + if (ffc_tmp > target_curr_ua) + ffc_tmp = target_curr_ua; + } else { + ffc_tmp -= FFC_STEP_UA; + if (ffc_tmp < target_curr_ua) + ffc_tmp = target_curr_ua; + } + + chg_err("set usb_icl vote to %d mA\n", ffc_tmp / 1000); + vote(normal_charger->usb_icl_votable, WIRED_CONN_VOTER, true, ffc_tmp); + client_str = get_effective_client(normal_charger->usb_icl_votable); + if (strcmp(client_str, WIRED_CONN_VOTER)) { + vote(normal_charger->usb_icl_votable, WIRED_CONN_VOTER, true, target_curr_ua); + return; + } + if (ffc_tmp != target_curr_ua) + schedule_delayed_work(&chip->wlchg_fcc_stepper_work, + msecs_to_jiffies(FFC_STEP_TIME_MS)); +} + +static enum power_supply_property wlchg_wireless_props[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_TX_VOLTAGE_NOW, + POWER_SUPPLY_PROP_TX_CURRENT_NOW, + POWER_SUPPLY_PROP_CP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CP_CURRENT_NOW, + POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_WIRELESS_MODE, + POWER_SUPPLY_PROP_WIRELESS_TYPE, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, + POWER_SUPPLY_PROP_ICON_DELAY, +}; + +static int wlchg_wireless_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct op_chg_chip *chip = power_supply_get_drvdata(psy); + int tmp; + int rc = 0; + + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return -ENODEV; + } + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + if (chip->wireless_mode == WIRELESS_MODE_RX && + normal_charger != NULL) + val->intval = normal_charger->wireless_present; + else if (chip->wireless_mode == WIRELESS_MODE_TX) + val->intval = chip->wlchg_status.tx_present; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_ONLINE: + if (wlchg_wireless_charge_start() || chip->charger_exist) + val->intval = 1; + else + val->intval = 0; + + if (chip->wlchg_status.rx_ovp) + val->intval = 0; + + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (chip->wireless_mode == WIRELESS_MODE_RX) + val->intval = wlchg_wireless_get_vout() * 1000; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + if (chip->wireless_mode == WIRELESS_MODE_RX) + val->intval = chip->wlchg_status.target_vol * 1000; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + if (chip->wireless_mode == WIRELESS_MODE_RX) + val->intval = g_rx_chip->chg_data.iout * 1000; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CURRENT_MAX: + if (chip->wireless_mode == WIRELESS_MODE_RX) + val->intval = chip->wlchg_status.max_current * 1000; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_TX_VOLTAGE_NOW: + if (chip->wireless_mode == WIRELESS_MODE_TX) { + rc = wlchg_rx_get_tx_vol(g_rx_chip, &tmp); + if (rc) + val->intval = 0; + else + val->intval = tmp * 1000; + } else { + val->intval = 0; + } + break; + case POWER_SUPPLY_PROP_TX_CURRENT_NOW: + if (chip->wireless_mode == WIRELESS_MODE_TX) { + rc = wlchg_rx_get_tx_curr(g_rx_chip, &tmp); + if (rc) + val->intval = 0; + else + val->intval = tmp * 1000; + } else { + val->intval = 0; + } + break; + case POWER_SUPPLY_PROP_CP_VOLTAGE_NOW: + if (chip->wireless_mode == WIRELESS_MODE_RX) { + if (exchgpump_bq == NULL) + return -ENODEV; + bq2597x_get_adc_data(exchgpump_bq, ADC_VBUS, &tmp); + val->intval = tmp * 1000; + } else { + val->intval = 0; + } + break; + case POWER_SUPPLY_PROP_CP_CURRENT_NOW: + if (chip->wireless_mode == WIRELESS_MODE_RX) { + if (exchgpump_bq == NULL) + return -ENODEV; + bq2597x_get_adc_data(exchgpump_bq, ADC_IBUS, &tmp); + val->intval = tmp * 1000; + } else { + val->intval = 0; + } + break; + case POWER_SUPPLY_PROP_REAL_TYPE: + if (chip->wlchg_status.fastchg_display_delay) { + if (chip->wlchg_status.charge_online) { + if (chip->wlchg_status.is_deviation || + ((chip->wlchg_status.temp_region != WLCHG_BATT_TEMP_PRE_NORMAL) && + (chip->wlchg_status.temp_region != WLCHG_BATT_TEMP_NORMAL))) { + chip->wlchg_status.fastchg_display_delay = false; + } else { + val->intval = POWER_SUPPLY_TYPE_DASH; + break; + } + } else { + val->intval = POWER_SUPPLY_TYPE_DASH; + break; + } + } + switch (chip->wlchg_status.adapter_type) { + case ADAPTER_TYPE_FASTCHAGE_DASH: + case ADAPTER_TYPE_FASTCHAGE_WARP: + if (chip->wlchg_status.deviation_check_done && + ((chip->wlchg_status.temp_region == WLCHG_BATT_TEMP_PRE_NORMAL) || + (chip->wlchg_status.temp_region == WLCHG_BATT_TEMP_NORMAL))) + val->intval = POWER_SUPPLY_TYPE_DASH; + else + val->intval = POWER_SUPPLY_TYPE_UNKNOWN; + break; + case ADAPTER_TYPE_USB: + val->intval = POWER_SUPPLY_TYPE_USB; + break; + case ADAPTER_TYPE_NORMAL_CHARGE: + val->intval = POWER_SUPPLY_TYPE_USB_DCP; + break; + default: + val->intval = POWER_SUPPLY_TYPE_UNKNOWN; + break; + } + break; + case POWER_SUPPLY_PROP_WIRELESS_MODE: + val->strval = wlchg_wireless_get_mode(chip); + break; + case POWER_SUPPLY_PROP_WIRELESS_TYPE: + val->intval = chip->wireless_type; + break; + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: + val->intval = chip->disable_batt_charge; + break; + case POWER_SUPPLY_PROP_VBATDET: + tmp = chip->wlchg_status.temp_region; + if (chip->wireless_mode == WIRELESS_MODE_RX && + tmp < WLCHG_TEMP_REGION_MAX) { + val->intval = chip->chg_param.vbatdet[tmp]; + } else { + val->intval = 0; + } + break; + case POWER_SUPPLY_PROP_ICON_DELAY: + val->intval = chg_icon_update_delay; + break; + default: + return -EINVAL; + } + if (rc < 0) { + pr_debug("Couldn't get prop %d rc = %d\n", psp, rc); + return -ENODATA; + } + return 0; +} + +static int wlchg_wireless_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct op_chg_chip *chip = power_supply_get_drvdata(psy); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_MAX: + chip->wlchg_status.max_current = val->intval / 1000; + vote(chip->wlcs_fcc_votable, MAX_VOTER, true, val->intval); + rc = 0; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + vote(chip->wlcs_fcc_votable, USER_VOTER, true, val->intval); + rc = 0; + break; + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: + rc = wlchg_disable_batt_charge(chip, (bool)val->intval); + break; + case POWER_SUPPLY_PROP_ICON_DELAY: + chg_icon_update_delay = (bool)val->intval; + break; + default: + chg_err("set prop %d is not supported\n", psp); + rc = -EINVAL; + break; + } + + return rc; +} + +static int wlchg_wireless_prop_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + int rc; + + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_MAX: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: + case POWER_SUPPLY_PROP_ICON_DELAY: + rc = 1; + break; + default: + rc = 0; + break; + } + + return rc; +} + +static const struct power_supply_desc wireless_psy_desc = { + .name = "wireless", + .type = POWER_SUPPLY_TYPE_WIRELESS, + .properties = wlchg_wireless_props, + .num_properties = ARRAY_SIZE(wlchg_wireless_props), + .get_property = wlchg_wireless_get_prop, + .set_property = wlchg_wireless_set_prop, + .property_is_writeable = wlchg_wireless_prop_is_writeable, +}; + +static int wlchg_init_wireless_psy(struct op_chg_chip *chip) +{ + struct power_supply_config wireless_cfg = {}; + + wireless_cfg.drv_data = chip; + wireless_cfg.of_node = chip->dev->of_node; + chip->wireless_psy = devm_power_supply_register( + chip->dev, &wireless_psy_desc, &wireless_cfg); + if (IS_ERR(chip->wireless_psy)) { + chg_err("Couldn't register wireless power supply\n"); + return PTR_ERR(chip->wireless_psy); + } + + return 0; +} + +int wlchg_send_msg(enum WLCHG_MSG_TYPE type, char data, char remark) +{ + struct wlchg_msg_t *msg_info; + + if (g_op_chip == NULL) { + chg_err("wlchg is not ready\n"); + return -ENODEV; + } + + if (!g_op_chip->wlchg_msg_ok) { + mutex_lock(&g_op_chip->msg_lock); + if ((type == WLCHG_MSG_CHG_INFO) && (remark == WLCHG_ADAPTER_MSG)) + g_op_chip->wlchg_status.get_adapter_err = false; + msg_info = &g_op_chip->msg_info; + msg_info->data = data; + msg_info->type = type; + msg_info->remark = remark; + g_op_chip->wlchg_msg_ok = true; + mutex_unlock(&g_op_chip->msg_lock); + wake_up(&g_op_chip->read_wq); + } else { + chg_err("the previous message has not been sent successfully\n"); + return -EINVAL; + } + + return 0; +} + +static int wlchg_cmd_process(struct op_chg_chip *chip) +{ + struct cmd_info_t *cmd_info = &chip->cmd_info; + struct rx_chip_prop *prop; + struct wpc_data *chg_status = &chip->wlchg_status; + + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return -ENODEV; + } + + if (time_is_before_jiffies(chg_status->send_msg_timer)) { + prop = g_rx_chip->prop; + if (cmd_info->cmd != 0) { + if (cmd_info->cmd_retry_count != 0) { + chg_info("cmd:%d, %d, %d\n", cmd_info->cmd_type, cmd_info->cmd, cmd_info->cmd_retry_count); + prop->send_msg(prop, cmd_info->cmd_type, cmd_info->cmd); + if (cmd_info->cmd_retry_count > 0) + cmd_info->cmd_retry_count--; + } else { + wlchg_send_msg(WLCHG_MSG_CMD_ERR, 0, cmd_info->cmd); + cmd_info->cmd = 0; + } + } + chg_status->send_msg_timer = jiffies + HZ; + } + + return 0; +} + +static int wlchg_dev_open(struct inode *inode, struct file *filp) +{ + struct op_chg_chip *chip = container_of(filp->private_data, + struct op_chg_chip, wlchg_device); + + filp->private_data = chip; + pr_debug("%d,%d\n", imajor(inode), iminor(inode)); + return 0; +} + +static ssize_t wlchg_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct op_chg_chip *chip = filp->private_data; + struct wlchg_msg_t msg; + int ret = 0; + + mutex_lock(&chip->read_lock); + ret = wait_event_interruptible(chip->read_wq, chip->wlchg_msg_ok); + mutex_unlock(&chip->read_lock); + if (ret) + return ret; + if (!chip->wlchg_msg_ok) + chg_err("wlchg false wakeup,ret=%d\n", ret); + mutex_lock(&chip->msg_lock); + chip->wlchg_msg_ok = false; + msg.type = chip->msg_info.type; + msg.data = chip->msg_info.data; + msg.remark = chip->msg_info.remark; + if ((msg.type == WLCHG_MSG_CHG_INFO) && + (msg.remark == WLCHG_ADAPTER_MSG)) + chip->wlchg_status.adapter_msg_send = true; + mutex_unlock(&chip->msg_lock); + if (copy_to_user(buf, &msg, sizeof(struct wlchg_msg_t))) { + chg_err("failed to copy to user space\n"); + return -EFAULT; + } + + return ret; +} + +#define WLCHG_IOC_MAGIC 0xfe +#define WLCHG_NOTIFY_ADAPTER_TYPE _IOW(WLCHG_IOC_MAGIC, 1, int) +#define WLCHG_NOTIFY_ADAPTER_TYPE_ERR _IO(WLCHG_IOC_MAGIC, 2) +#define WLCHG_NOTIFY_CHARGE_TYPE _IOW(WLCHG_IOC_MAGIC, 3, int) +#define WLCHG_NOTIFY_CHARGE_TYPE_ERR _IO(WLCHG_IOC_MAGIC, 4) +#define WLCHG_NOTIFY_TX_ID _IO(WLCHG_IOC_MAGIC, 5) +#define WLCHG_NOTIFY_TX_ID_ERR _IO(WLCHG_IOC_MAGIC, 6) +#define WLCHG_NOTIFY_QUIET_MODE _IO(WLCHG_IOC_MAGIC, 7) +#define WLCHG_NOTIFY_QUIET_MODE_ERR _IO(WLCHG_IOC_MAGIC, 8) +#define WLCHG_NOTIFY_NORMAL_MODE _IO(WLCHG_IOC_MAGIC, 9) +#define WLCHG_NOTIFY_NORMAL_MODE_ERR _IO(WLCHG_IOC_MAGIC, 10) +#define WLCHG_NOTIFY_READY_FOR_EPP _IO(WLCHG_IOC_MAGIC, 11) +#define WLCHG_NOTIFY_WORKING_IN_EPP _IO(WLCHG_IOC_MAGIC, 12) +#define WLCHG_NOTIFY_HEARTBEAT _IO(WLCHG_IOC_MAGIC, 13) +#define WLCHG_NOTIFY_SET_CEP_TIMEOUT _IO(WLCHG_IOC_MAGIC, 14) +#define WLCHG_NOTIFY_SET_CEP_TIMEOUT_ERR _IO(WLCHG_IOC_MAGIC, 15) + +static long wlchg_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct op_chg_chip *chip = filp->private_data; + struct wpc_data *chg_status = &chip->wlchg_status; + + switch (cmd) { + case WLCHG_NOTIFY_ADAPTER_TYPE: + chg_status->adapter_type = arg; + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + if (chip->chg_param.fastchg_fod_enable && + (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH || + chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP)) + wlchg_rx_set_match_q_parm(g_rx_chip, chip->chg_param.fastchg_match_q); + chg_info("adapter type is %d\n", chg_status->adapter_type); + break; + case WLCHG_NOTIFY_ADAPTER_TYPE_ERR: + chg_status->get_adapter_err = true; + chg_err("get adapter type error\n"); + break; + case WLCHG_NOTIFY_CHARGE_TYPE: + chg_status->charge_type = arg; + chg_info("charge type is %d\n", arg); + if (chip->chg_param.fastchg_fod_enable && + chg_status->charge_type == WPC_CHARGE_TYPE_FAST) { + wlchg_rx_set_fod_parm(g_rx_chip, chip->chg_param.fastchg_fod_parm); + chg_status->startup_fod_parm = false; + chg_info("write fastchg fod parm\n"); + } + break; + case WLCHG_NOTIFY_CHARGE_TYPE_ERR: + chg_err("get charge type error\n"); + break; + case WLCHG_NOTIFY_TX_ID: + chg_status->geted_tx_id = true; + break; + case WLCHG_NOTIFY_TX_ID_ERR: + chg_status->geted_tx_id = true; + chg_err("get tx id error\n"); + break; + case WLCHG_NOTIFY_QUIET_MODE: + chg_status->quiet_mode_enabled = true; + chg_status->quiet_mode_init = true; + break; + case WLCHG_NOTIFY_QUIET_MODE_ERR: + chg_err("set quiet mode error\n"); + break; + case WLCHG_NOTIFY_NORMAL_MODE: + chg_status->quiet_mode_enabled = false; + chg_status->quiet_mode_init = true; + break; + case WLCHG_NOTIFY_NORMAL_MODE_ERR: + chg_err("set normal mode error\n"); + break; + case WLCHG_NOTIFY_SET_CEP_TIMEOUT: + chg_status->cep_timeout_adjusted = true; + break; + case WLCHG_NOTIFY_SET_CEP_TIMEOUT_ERR: + chg_err("set CEP TIMEOUT error\n"); + break; + case WLCHG_NOTIFY_READY_FOR_EPP: + chg_status->adapter_type = ADAPTER_TYPE_EPP; + break; + case WLCHG_NOTIFY_WORKING_IN_EPP: + chg_status->epp_working = true; + break; + case WLCHG_NOTIFY_HEARTBEAT: + pr_debug("heartbeat package\n"); + atomic_set(&chip->hb_count, HEARTBEAT_COUNT_MAX); + break; + default: + chg_err("bad ioctl %u\n", cmd); + } + + return 0; +} + +static ssize_t wlchg_dev_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct op_chg_chip *chip = filp->private_data; + struct cmd_info_t *cmd_info = &chip->cmd_info; + char temp_buf[3]; + + if (count != 3) { + chg_err("Data length error, len=%d\n", count); + return -EFAULT; + } + + if (copy_from_user(temp_buf, buf, count)) { + chg_err("failed to copy from user space\n"); + return -EFAULT; + } + + cmd_info->cmd = temp_buf[0]; + cmd_info->cmd_type = temp_buf[1]; + cmd_info->cmd_retry_count = (signed char)temp_buf[2]; + chg_info("cmd=%d, cmd_info=%d, retry_count=%d\n", cmd_info->cmd, + cmd_info->cmd_type, cmd_info->cmd_retry_count); + + return count; +} + +static const struct file_operations wlchg_dev_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wlchg_dev_write, + .read = wlchg_dev_read, + .open = wlchg_dev_open, + .unlocked_ioctl = wlchg_dev_ioctl, +}; + +/* Tbatt < -3C */ +static int handle_batt_temp_cold(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_COLD) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + if (normal_charger) { + vote(normal_charger->fcc_votable, WLCH_VOTER, true, 0); + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + wlchg_set_rx_charge_current(chip, 0); + chg_status->temp_region = WLCHG_BATT_TEMP_COLD; + chg_info("switch temp region to %d\n", chg_status->temp_region); + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0 + BATT_TEMP_HYST; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} + +/* -3C <= Tbatt <= 0C */ +static int handle_batt_temp_little_cold(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_LITTLE_COLD) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + chg_status->temp_region = WLCHG_BATT_TEMP_LITTLE_COLD; + chg_info("switch temp region to %d\n", chg_status->temp_region); + if (normal_charger) { + if (chip->pmic_high_vol) { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->epp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->epp_ibatmax[chg_status->temp_region] * 1000); + } else { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->bpp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->bpp_ibatmax[chg_status->temp_region] * 1000); + } + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1 + BATT_TEMP_HYST; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} + +/* 0C < Tbatt <= 5C*/ +static int handle_batt_temp_cool(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + static int pre_vbat; + static bool vbat_exce_thr; //vbat has exceeded the threshold + + if (((pre_vbat <= chg_param->cool_vbat_thr_mv) && + (chip->batt_volt > chg_param->cool_vbat_thr_mv)) || + ((pre_vbat > chg_param->cool_vbat_thr_mv) && + (chip->batt_volt <= chg_param->cool_vbat_thr_mv))) { + chg_info("battery voltage changes%d\n"); + chg_status->is_power_changed = true; + } + pre_vbat = chip->batt_volt; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_COOL) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + if (chg_status->temp_region != WLCHG_BATT_TEMP_COOL) + vbat_exce_thr = false; + chg_status->temp_region = WLCHG_BATT_TEMP_COOL; + chg_info("switch temp region to %d\n", chg_status->temp_region); + if (normal_charger) { + if (chip->pmic_high_vol) { + if ((!vbat_exce_thr && chip->batt_volt <= chg_param->cool_vbat_thr_mv) || + (vbat_exce_thr && chip->batt_volt <= chg_param->cool_vbat_thr_mv - 150)) { + vbat_exce_thr = false; + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->epp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->epp_ibatmax[chg_status->temp_region] * 1000); + } else { + vbat_exce_thr = true; + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->cool_epp_icl_ma * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->cool_epp_ibat_ma * 1000); + } + } else { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->bpp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->bpp_ibatmax[chg_status->temp_region] * 1000); + } + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2 + BATT_TEMP_HYST; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} +/* 5C < Tbatt <= 12C */ +static int handle_batt_temp_little_cool(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_LITTLE_COOL) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + chg_status->temp_region = WLCHG_BATT_TEMP_LITTLE_COOL; + chg_info("switch temp region to %d\n", chg_status->temp_region); + if (normal_charger) { + if (chip->pmic_high_vol) { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->epp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->epp_ibatmax[chg_status->temp_region] * 1000); + } else { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->bpp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->bpp_ibatmax[chg_status->temp_region] * 1000); + } + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3 + BATT_TEMP_HYST; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} + +/* 12C < Tbatt < 22C */ +static int handle_batt_temp_prenormal(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_PRE_NORMAL) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + chg_status->temp_region = WLCHG_BATT_TEMP_PRE_NORMAL; + chg_info("switch temp region to %d\n", chg_status->temp_region); + if (normal_charger) { + if (chip->pmic_high_vol) { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->epp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->epp_ibatmax[chg_status->temp_region] * 1000); + } else { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->bpp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->bpp_ibatmax[chg_status->temp_region] * 1000); + } + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + + if (chg_status->charge_status == WPC_CHG_STATUS_FAST_CHARGING_FROM_CHGPUMP) + vote(chip->wlcs_fcc_votable, JEITA_VOTER, true, FASTCHG_CURR_20W_MAX_UA); + else + vote(chip->wlcs_fcc_votable, JEITA_VOTER, false, 0); + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4 + BATT_TEMP_HYST; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} + +/* 15C < Tbatt < 45C */ +static int handle_batt_temp_normal(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_NORMAL) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + chg_status->temp_region = WLCHG_BATT_TEMP_NORMAL; + chg_info("switch temp region to %d\n", chg_status->temp_region); + if (normal_charger) { + if (chip->pmic_high_vol) { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->epp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->epp_ibatmax[chg_status->temp_region] * 1000); + } else { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->bpp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->bpp_ibatmax[chg_status->temp_region] * 1000); + } + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + + if (chg_status->charge_status == WPC_CHG_STATUS_FAST_CHARGING_FROM_CHGPUMP) + vote(chip->wlcs_fcc_votable, JEITA_VOTER, true, FASTCHG_CURR_30W_MAX_UA); + else + vote(chip->wlcs_fcc_votable, JEITA_VOTER, false, 0); + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} + +/* 45C <= Tbatt <= 55C */ +static int handle_batt_temp_warm(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_WARM) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + chg_status->temp_region = WLCHG_BATT_TEMP_WARM; + chg_info("switch temp region to %d\n", chg_status->temp_region); + if (normal_charger) { + if (chip->pmic_high_vol) { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->epp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->epp_ibatmax[chg_status->temp_region] * 1000); + } else { + vote(normal_charger->usb_icl_votable, WLCH_VOTER, true, + chg_param->bpp_iclmax[chg_status->temp_region] * 1000); + vote(normal_charger->fcc_votable, WLCH_VOTER, true, + chg_param->bpp_ibatmax[chg_status->temp_region] * 1000); + } + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5 - BATT_TEMP_HYST; + chg_param->mBattTempBoundT6 = chg_param->BATT_TEMP_T6; + } + + return 0; +} + +/* 55C < Tbatt */ +static int handle_batt_temp_hot(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if ((chg_status->temp_region != WLCHG_BATT_TEMP_HOT) || chg_status->is_power_changed) { + chg_status->is_power_changed = false; + if (normal_charger) { + vote(normal_charger->fcc_votable, WLCH_VOTER, true, 0); + } else { + chg_err("smb charge is not ready\n"); + return -ENODEV; + } + wlchg_set_rx_charge_current(chip, 0); + chg_status->temp_region = WLCHG_BATT_TEMP_HOT; + chg_info("switch temp region to %d\n", chg_status->temp_region); + + /* Update the temperature boundaries */ + chg_param->mBattTempBoundT0 = chg_param->BATT_TEMP_T0; + chg_param->mBattTempBoundT1 = chg_param->BATT_TEMP_T1; + chg_param->mBattTempBoundT2 = chg_param->BATT_TEMP_T2; + chg_param->mBattTempBoundT3 = chg_param->BATT_TEMP_T3; + chg_param->mBattTempBoundT4 = chg_param->BATT_TEMP_T4; + chg_param->mBattTempBoundT5 = chg_param->BATT_TEMP_T5; + chg_param->mBattTempBoundT6 = + chg_param->BATT_TEMP_T6 - BATT_TEMP_HYST; + } + + return 0; +} + +static int op_check_battery_temp(struct op_chg_chip *chip) +{ + int rc = -1; + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + enum WLCHG_TEMP_REGION_TYPE pre_temp_region; + + if (!wlchg_wireless_charge_start()) + return rc; + + if (chg_status->ftm_mode) { + chg_err("ftm mode, don't check temp region\n"); + return 0; + } + + pre_temp_region = chg_status->temp_region; + if (chip->temperature < chg_param->mBattTempBoundT0) /* COLD */ + rc = handle_batt_temp_cold(chip); + else if (chip->temperature >= chg_param->mBattTempBoundT0 && + chip->temperature < chg_param->mBattTempBoundT1) /* LITTLE_COLD */ + rc = handle_batt_temp_little_cold(chip); + else if (chip->temperature >= chg_param->mBattTempBoundT1 && + chip->temperature < chg_param->mBattTempBoundT2) /* COOL */ + rc = handle_batt_temp_cool(chip); + else if (chip->temperature >= chg_param->mBattTempBoundT2 && + chip->temperature < chg_param->mBattTempBoundT3) /* LITTLE_COOL */ + rc = handle_batt_temp_little_cool(chip); + else if (chip->temperature >= chg_param->mBattTempBoundT3 && + chip->temperature < chg_param->mBattTempBoundT4) /* PRE_NORMAL */ + rc = handle_batt_temp_prenormal(chip); + else if (chip->temperature >= chg_param->mBattTempBoundT4 && + chip->temperature < chg_param->mBattTempBoundT5) /* NORMAL */ + rc = handle_batt_temp_normal(chip); + else if (chip->temperature >= chg_param->mBattTempBoundT5 && + chip->temperature <= chg_param->mBattTempBoundT6) /* WARM */ + rc = handle_batt_temp_warm(chip); + else if (chip->temperature > chg_param->mBattTempBoundT6) /* HOT */ + rc = handle_batt_temp_hot(chip); + + if ((pre_temp_region < WLCHG_TEMP_REGION_MAX) && + (pre_temp_region != chg_status->temp_region)) { + chg_info("temp region changed, report event."); + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + } + return rc; +} + +static int pmic_chan_check_skin_temp(struct op_chg_chip *chip) +{ + int rc = -1; + int skin_temp; + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + static unsigned long wait_timeout; + + if (!wlchg_wireless_charge_start()) + return rc; + + if (chg_status->ftm_mode) { + chg_err("ftm mode, don't check temp region\n"); + return 0; + } + + if (wait_timeout == 0) + wait_timeout = jiffies - HZ; + + rc = wlchg_get_skin_temp(&skin_temp); + if (rc < 0) + skin_temp = DEFAULT_SKIN_TEMP; + + chg_info("skin temp = %d\n", skin_temp); + + if (!time_after(jiffies, wait_timeout)) + return 0; + + if (skin_temp >= chg_param->epp_skin_temp_max) { + if (chg_status->epp_curr_step >= EPP_CURR_STEP_MAX - 1) + return 0; + chg_status->epp_curr_step++; + chg_info("skin temp(=%d) too high\n", skin_temp); + vote(normal_charger->usb_icl_votable, WLCH_SKIN_VOTER, true, + chg_param->epp_curr_step[chg_status->epp_curr_step] * 1000); + wait_timeout = jiffies + 30 * HZ; + } else if (skin_temp <= chg_param->epp_skin_temp_min) { + if (chg_status->epp_curr_step < 1) { + if (is_client_vote_enabled(normal_charger->usb_icl_votable, WLCH_SKIN_VOTER)) + vote(normal_charger->usb_icl_votable, WLCH_SKIN_VOTER, false, 0); + return 0; + } + chg_status->epp_curr_step--; + chg_info("skin temp(=%d) reduce\n", skin_temp); + vote(normal_charger->usb_icl_votable, WLCH_SKIN_VOTER, true, + chg_param->epp_curr_step[chg_status->epp_curr_step] * 1000); + wait_timeout = jiffies + 30 * HZ; + } + + return 0; +} + +static int fastchg_check_skin_temp(struct op_chg_chip *chip) +{ + int rc = -1; + int skin_temp; + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + static unsigned long wait_timeout; + + if (!wlchg_wireless_charge_start()) + return rc; + + if (chg_status->ftm_mode) { + chg_err("ftm mode, don't check temp region\n"); + return 0; + } + + if (wait_timeout == 0) + wait_timeout = jiffies - HZ; + + rc = wlchg_get_skin_temp(&skin_temp); + if (rc < 0) + skin_temp = DEFAULT_SKIN_TEMP; + + pr_debug("skin temp = %d\n", skin_temp); + + if (!time_after(jiffies, wait_timeout)) + return 0; + + if (skin_temp >= chg_param->fastchg_skin_temp_max) { + chg_info("skin temp(%d) too high(above %d)\n", skin_temp, + chg_param->fastchg_skin_temp_max); + chg_status->fastchg_curr_step++; + + if (chg_status->fastchg_curr_step <= chg_status->fastchg_level) + chg_status->fastchg_curr_step = chg_status->fastchg_level + 1; + + if (chg_status->fastchg_curr_step >= ffc_chg->max_step) { + vote(chip->fastchg_disable_votable, SKIN_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + chg_err("fast charge on the last step, exit fast charge."); + return 0; + } + + vote(chip->wlcs_fcc_votable, SKIN_VOTER, true, + ffc_chg->ffc_step[chg_status->fastchg_curr_step].curr_ua); + wait_timeout = jiffies + 30 * HZ; + } else if (skin_temp <= chg_param->fastchg_skin_temp_min) { + if (chg_status->fastchg_curr_step <= chg_status->fastchg_level) + return 0; + chg_status->fastchg_curr_step--; + chg_info("skin temp(%d) reduce(below %d)\n", skin_temp, + chg_param->fastchg_skin_temp_min); + vote(chip->wlcs_fcc_votable, SKIN_VOTER, true, + ffc_chg->ffc_step[chg_status->fastchg_curr_step].curr_ua); + wait_timeout = jiffies + 30 * HZ; + } + + return 0; +} + +static void fastchg_ffc_param_init(struct op_chg_chip *chip) +{ + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + int i; + + for(i = 0; i < ffc_chg->max_step; i++) { + if (ffc_chg->ffc_step[i].low_threshold > 0) + ffc_chg->allow_fallback[i] = true; + else + ffc_chg->allow_fallback[i] = false; + } +} + +static int fastchg_err_check(struct op_chg_chip *chip) +{ + bool cp2_is_ok; + bool cp2_is_enabled; + u8 cp1_status = CP_REEADY; + struct wpc_data *chg_status = &chip->wlchg_status; + int ret; + + ret = chargepump_status_check(&cp1_status); + if (ret != 0) { + chg_err("read charge status err, ret=%d\n", ret); + return ret; + } + if (cp1_status != CP_REEADY) { + chg_err("charge pump 1 is err, status=%d\n", cp1_status); + chargepump_disable(); + if (chg_status->charge_current != 0) + wlchg_set_rx_charge_current(chip, 0); + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP1_STEP; + goto err; + } + + if (exchgpump_bq != NULL) { + bq2597x_check_charge_enabled(exchgpump_bq, &cp2_is_enabled); + cp2_is_ok = bq2597x_charge_status_is_ok(exchgpump_bq); + } + if (!cp2_is_enabled) { + chg_err("charge pump 2 is err\n"); + chg_status->fastchg_startup_step = FASTCHG_EN_PMIC_CHG_STEP; + goto err; + } + + return 0; + +err: + chg_status->startup_fast_chg = true; + chg_status->curr_limit_mode = false; + update_wlchg_started(false); + chg_status->charge_status = WPC_CHG_STATUS_INCREASE_VOLTAGE; + + return 1; +} + +static int fastchg_curr_filter(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + int bq_adc_ibus, iout; + bool cp_enabled = false; + int iout_shake = 0; + static int iout_pre; + + if (exchgpump_bq == NULL) { + chg_err("bq25970 is not ready\n"); + return -ENODEV; + } + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return -ENODEV; + } + + bq2597x_check_charge_enabled(exchgpump_bq, &cp_enabled); + if (!cp_enabled) { + iout_pre = 0; + return 0; + } + + iout = g_rx_chip->chg_data.iout; + if (iout_pre != 0) + iout_shake = iout - iout_pre; + bq2597x_get_adc_data(exchgpump_bq, ADC_IBUS, &bq_adc_ibus); + if ((iout > WPC_CHARGE_CURRENT_FASTCHG) && + ((abs(iout * 2 - bq_adc_ibus) > 500) || (abs(iout_shake) > 1000))) { + iout = bq_adc_ibus / 2; + chg_err("Iout exception, Iout=%d, Ibus=%d, Iout_shake=%d\n", + iout, bq_adc_ibus, iout_shake); + chg_status->curr_err_count++; + } else { + chg_status->curr_err_count = 0; + } + g_rx_chip->chg_data.iout = iout; + iout_pre = iout; + + if (chg_status->curr_err_count > FASTCHG_CURR_ERR_MAX) { + chg_err("Iout keeps abnormal, restart wireless charge\n"); + wlchg_rx_set_chip_sleep(1); + } + + return 0; +} + +static void fastchg_switch_next_step(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + u32 batt_vol_max = ffc_chg->ffc_step[chg_status->fastchg_level].vol_max_mv; + + if (ffc_chg->ffc_step[chg_status->fastchg_level].need_wait == 0) { + if (chip->batt_volt >= batt_vol_max) { + /* Must delay 1 sec and wait for the batt voltage to drop */ + ffc_chg->ffc_wait_timeout = jiffies + HZ * 5; + } else { + ffc_chg->ffc_wait_timeout = jiffies; + } + } else { + /* Delay 1 minute and wait for the temperature to drop */ + ffc_chg->ffc_wait_timeout = jiffies + HZ * 60; + } + + chg_status->fastchg_level++; + chg_info("switch to next level=%d\n", chg_status->fastchg_level); + if (chg_status->fastchg_level >= ffc_chg->max_step) { + if (chip->batt_volt >= batt_vol_max) { + chg_info("run normal charge ffc\n"); + chg_status->ffc_check = true; + } + } else { + chg_status->wait_cep_stable = true; + vote(chip->wlcs_fcc_votable, FFC_VOTER, true, + ffc_chg->ffc_step[chg_status->fastchg_level].curr_ua); + } + chg_status->fastchg_level_init_temp = chip->temperature; + if (chip->batt_volt >= batt_vol_max) { + ffc_chg->allow_fallback[chg_status->fastchg_level] = false; + if ((chg_status->temp_region == WLCHG_BATT_TEMP_PRE_NORMAL) && + (ffc_chg->ffc_step[chg_status->fastchg_level].curr_ua * 4 >= chg_param->fastchg_ibatmax[0])) { + ffc_chg->ffc_wait_timeout = jiffies; + } + } +} + +static void fastchg_switch_prev_step(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + + chg_status->fastchg_level--; + chg_info("switch to prev level=%d\n", chg_status->fastchg_level); + vote(chip->wlcs_fcc_votable, FFC_VOTER, true, + ffc_chg->ffc_step[chg_status->fastchg_level].curr_ua); + chg_status->fastchg_level_init_temp = 0; + ffc_chg->ffc_wait_timeout = jiffies; +} + +static void fastchg_temp_check(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + int batt_temp; + int def_curr_ua, ffc_curr_ua; + /* + * We want the temperature to drop when switching to a lower current range. + * If the temperature rises by 2 degrees before the next gear begins to + * detect temperature, then you should immediately switch to a lower gear. + */ + int temp_diff; + u32 batt_vol_max = ffc_chg->ffc_step[chg_status->fastchg_level].vol_max_mv; + + if (chg_status->temp_region != WLCHG_BATT_TEMP_PRE_NORMAL && + chg_status->temp_region != WLCHG_BATT_TEMP_NORMAL) { + chg_info("Abnormal battery temperature, exit fast charge\n"); + vote(chip->fastchg_disable_votable, FFC_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } + + batt_temp = chip->temperature; + def_curr_ua = get_client_vote(chip->wlcs_fcc_votable, JEITA_VOTER); + if (def_curr_ua <= 0) + def_curr_ua = get_client_vote(chip->wlcs_fcc_votable, DEF_VOTER); + else + def_curr_ua = min(get_client_vote(chip->wlcs_fcc_votable, DEF_VOTER), def_curr_ua); + ffc_curr_ua = ffc_chg->ffc_step[chg_status->fastchg_level].curr_ua; + if (chg_status->fastchg_level_init_temp != 0) + temp_diff = batt_temp - chg_status->fastchg_level_init_temp; + else + temp_diff = 0; + + pr_debug("battery temp = %d, vol = %d, level = %d, temp_diff = %d\n", + batt_temp, chip->batt_volt, chg_status->fastchg_level, temp_diff); + + if (chg_status->fastchg_level == 0) { + if (def_curr_ua < ffc_curr_ua) { + if ((chg_status->fastchg_level + 1) < ffc_chg->max_step) { + if (def_curr_ua < ffc_chg->ffc_step[chg_status->fastchg_level + 1].curr_ua) { + chg_info("target current too low, switch next step\n"); + fastchg_switch_next_step(chip); + ffc_chg->ffc_wait_timeout = jiffies; + return; + } + } else { + chg_info("target current too low, switch next step\n"); + fastchg_switch_next_step(chip); + ffc_chg->ffc_wait_timeout = jiffies; + return; + } + } + if ((batt_temp > ffc_chg->ffc_step[chg_status->fastchg_level].high_threshold) || + (chip->batt_volt >= batt_vol_max)) { + fastchg_switch_next_step(chip); + } + } else if (chg_status->fastchg_level >= ffc_chg->max_step) { // switch to pmic + vote(chip->fastchg_disable_votable, FFC_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } else { + if (def_curr_ua < ffc_curr_ua) { + if ((chg_status->fastchg_level + 1) < ffc_chg->max_step) { + if (def_curr_ua < ffc_chg->ffc_step[chg_status->fastchg_level + 1].curr_ua) { + chg_info("target current too low, switch next step\n"); + fastchg_switch_next_step(chip); + ffc_chg->ffc_wait_timeout = jiffies; + return; + } + } else { + chg_info("target current too low, switch next step\n"); + fastchg_switch_next_step(chip); + ffc_chg->ffc_wait_timeout = jiffies; + return; + } + } + if (chip->batt_volt >= chg_param->batt_vol_max) { + chg_info("batt voltage too high, switch next step\n"); + fastchg_switch_next_step(chip); + return; + } + if ((batt_temp < ffc_chg->ffc_step[chg_status->fastchg_level].low_threshold) && + ffc_chg->allow_fallback[chg_status->fastchg_level] && + (def_curr_ua > ffc_chg->ffc_step[chg_status->fastchg_level].curr_ua)) { + chg_info("target current too low, switch next step\n"); + fastchg_switch_prev_step(chip); + return; + } + if (time_after(jiffies, ffc_chg->ffc_wait_timeout) || (temp_diff > 200)) { + if ((batt_temp > ffc_chg->ffc_step[chg_status->fastchg_level].high_threshold) || + (chip->batt_volt >= batt_vol_max)) { + fastchg_switch_next_step(chip); + } + } + } +} + +void wlchg_check_term_charge(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status; + struct charge_param *chg_param; + int skin_temp = DEFAULT_SKIN_TEMP; + + if (chip == NULL) { + chg_err("op_chg_chip is not ready."); + return; + } + if (normal_charger == NULL) { + chg_err("smb charger is not ready."); + return; + } + + chg_status = &chip->wlchg_status; + chg_param = &chip->chg_param; + + if (!chg_status->cep_timeout_adjusted && chip->soc > chg_param->fastchg_soc_max) + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_CEP_TIMEOUT_MSG); + + wlchg_get_skin_temp(&skin_temp); + + if (wlchg_check_charge_done(chip)) { + chg_status->charge_done = true; + if (chg_status->charge_voltage != WPC_CHARGE_VOLTAGE_STOP_CHG) { + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_STOP_CHG); + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_STOP_CHG); + } + + if (!normal_charger->chg_disabled) { + chg_info("charge full, disable little current charge to battery."); + normal_charger->chg_disabled = true; + vote(normal_charger->chg_disable_votable, WLCH_VOTER, true, 0); + } + + if (!chg_status->quiet_mode_enabled && skin_temp < CHARGE_FULL_FAN_THREOD_LO) + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_QUIET_MODE_MSG); + if (chg_status->quiet_mode_enabled && !chip->quiet_mode_need + && skin_temp > CHARGE_FULL_FAN_THREOD_HI) + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_NORMAL_MODE_MSG); + } else { + chg_status->charge_done = false; + if (normal_charger->chg_disabled) { + chg_info("charge not full, restore charging."); + normal_charger->chg_disabled = false; + vote(normal_charger->chg_disable_votable, WLCH_VOTER, false, 0); + } + + if (chg_status->charge_voltage != WPC_CHARGE_VOLTAGE_EPP) { + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_EPP); + wlchg_set_rx_charge_current_step(chip, WPC_CHARGE_CURRENT_EPP); + } + + if (!chip->quiet_mode_need && chg_status->quiet_mode_enabled) + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_NORMAL_MODE_MSG); + + if (skin_temp < chg_param->fastchg_skin_temp_min + && is_client_vote_enabled(chip->fastchg_disable_votable, SKIN_VOTER)) { + vote(chip->fastchg_disable_votable, SKIN_VOTER, false, 0); + chg_info("skin temp is %d(below %d), restore fastcharge.", skin_temp, + chg_param->fastchg_skin_temp_min); + } + } +} + +static void wlchg_fastchg_restart_check(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct op_fastchg_ffc_step *ffc_chg = &chip->chg_param.ffc_chg; + + if (!chg_status->fastchg_disable) + return; + + if (is_client_vote_enabled(chip->fastchg_disable_votable, FFC_VOTER) && + (chip->temperature < (ffc_chg->ffc_step[ffc_chg->max_step - 1].high_threshold - BATT_TEMP_HYST))) { + vote(chip->fastchg_disable_votable, FFC_VOTER, false, 0); + chg_status->fastchg_level = ffc_chg->max_step - 1; + } + + if (is_client_vote_enabled(chip->fastchg_disable_votable, BATT_CURR_VOTER) && + (chip->icharging < 0)) + vote(chip->fastchg_disable_votable, BATT_CURR_VOTER, false, 0); + + if (is_client_vote_enabled(chip->fastchg_disable_votable, QUIET_VOTER) && + !chg_status->quiet_mode_enabled) + vote(chip->fastchg_disable_votable, QUIET_VOTER, false, 0); + + if (is_client_vote_enabled(chip->fastchg_disable_votable, STARTUP_CEP_VOTER) && + (chg_status->fastchg_retry_count < 10) && + time_is_before_jiffies(chg_status->fastchg_retry_timer)) + vote(chip->fastchg_disable_votable, STARTUP_CEP_VOTER, false, 0); +} + +#define CEP_ERR_MAX 3 +#define CEP_OK_MAX 10 +#define CEP_WAIT_MAX 20 +#define CEP_OK_TIMEOUT_MAX 60 +static void fastchg_cep_adj(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + signed char cep = 0; + int curr_ua, cep_curr_ua; + static int wait_cep_count; + static int cep_err_count; + static int cep_ok_count; + int rc; + + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return; + } + + rc = wlchg_rx_get_cep_skip_check_update(g_rx_chip, &cep); + if (rc) { + pr_err("can't get cep, rc=%d\n", rc); + return; + } + + if (!chg_status->wait_cep_stable) { + /* Insufficient energy only when CEP is positive */ + if (cep < 3) { + cep_ok_count++; + cep_err_count = 0; + if ((cep_ok_count >= CEP_OK_MAX) && + time_after(jiffies, chg_status->cep_ok_wait_timeout) && + is_client_vote_enabled(chip->wlcs_fcc_votable, CEP_VOTER)) { + chg_info("recovery charging current\n"); + cep_ok_count = 0; + chg_status->cep_err_flag = false; + chg_status->wait_cep_stable = true; + chg_status->cep_ok_wait_timeout = jiffies + CEP_OK_TIMEOUT_MAX * HZ; + wait_cep_count = 0; + vote(chip->wlcs_fcc_votable, CEP_VOTER, false, 0); + } + } else { + cep_ok_count = 0; + cep_err_count++; + if (cep_err_count >= CEP_ERR_MAX) { + chg_info("reduce charging current\n"); + cep_err_count = 0; + chg_status->cep_err_flag = true; + chg_status->wait_cep_stable = true; + wait_cep_count = 0; + if (is_client_vote_enabled(chip->wlcs_fcc_votable, CEP_VOTER)) + cep_curr_ua = get_client_vote(chip->wlcs_fcc_votable, CEP_VOTER); + else + cep_curr_ua = 0; + if ((cep_curr_ua > 0) && (cep_curr_ua <= FASTCHG_CURR_MIN_UA)){ + chg_info("Energy is too low, exit fast charge\n"); + vote(chip->fastchg_disable_votable, CEP_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } else { + curr_ua = g_rx_chip->chg_data.iout; + /* Target current is adjusted in 50ma steps*/ + curr_ua = (curr_ua - (curr_ua % CURR_ERR_MIN) - CURR_ERR_MIN) * 1000; + if (curr_ua < FASTCHG_CURR_MIN_UA) + curr_ua = FASTCHG_CURR_MIN_UA; + vote(chip->wlcs_fcc_votable, CEP_VOTER, true, curr_ua); + } + chg_status->cep_ok_wait_timeout = jiffies + CEP_OK_TIMEOUT_MAX * HZ; + } + } + } else { + if (wait_cep_count < CEP_WAIT_MAX) { + wait_cep_count++; + } else { + chg_status->wait_cep_stable = false; + wait_cep_count =0; + } + } +} + +static void fastchg_check_ibat(struct op_chg_chip *chip) +{ + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + + if (chip->icharging >= chg_param->fastchg_discharge_curr_max) { + chg_err("discharge current is too large, exit fast charge\n"); + vote(chip->fastchg_disable_votable, BATT_CURR_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } +} + +#define OP20A_ENABLE_VOL_MIN_MV 10000 +static int op20a_startup(struct op_chg_chip *chip) +{ + int ret; + u8 cp_status = 0; + int vout_mv = 0; + int try_num = 0; + + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return -ENODEV; + } + +retry: + if (try_num >= 40) + return -EAGAIN; + + ret = wlchg_rx_get_vout(g_rx_chip, &vout_mv); + if (ret < 0) { + try_num++; + goto retry; + } + if (vout_mv <= OP20A_ENABLE_VOL_MIN_MV) { + chg_err("rx vout(=%d) < %d, retry\n", vout_mv, OP20A_ENABLE_VOL_MIN_MV); + try_num++; + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_FASTCHG_INIT); + goto retry; + } + ret = chargepump_hw_init(); + if (ret < 0) { + chg_err("charge pump init error, rc=%d\n", ret); + try_num++; + goto retry; + } + ret = chargepump_enable(); + if (ret < 0) { + chg_err("charge pump enable error, rc=%d\n", ret); + try_num++; + goto retry; + } + ret = chargepump_status_check(&cp_status); + if (ret < 0) { + chg_err("charge pump enable error, rc=%d\n", ret); + goto disable_cp; + } + if (cp_status & (CP_DWP | CP_SWITCH_OCP | CP_CRP | CP_VOUT_OVP | CP_CLP | CP_VBUS_OVP)) { + chg_err("charge pump status error, status=0x%02x\n", cp_status); + goto disable_cp; + } + ret = chargepump_disable_dwp(); + if (ret < 0) + goto disable_cp; + ret = wlchg_rx_get_vout(g_rx_chip, &vout_mv); + if (ret < 0) + goto disable_cp; + if (vout_mv <= OP20A_ENABLE_VOL_MIN_MV) { + chg_err("rx vout(=%d) < %d, retry\n", vout_mv, OP20A_ENABLE_VOL_MIN_MV); + goto disable_cp; + } + ret = chargepump_status_check(&cp_status); + if (ret < 0) { + chg_err("charge pump enable error, rc=%d\n", ret); + goto disable_cp; + } + if (cp_status & (CP_SWITCH_OCP | CP_CRP | CP_VOUT_OVP | CP_CLP | CP_VBUS_OVP)) { + chg_err("charge pump status error, status=0x%02x\n", cp_status); + goto disable_cp; + } +wait_cp_enable: + mdelay(5); + ret = wlchg_rx_get_vout(g_rx_chip, &vout_mv); + if (ret < 0) + goto disable_cp; + if (vout_mv <= OP20A_ENABLE_VOL_MIN_MV) { + chg_err("rx vout(=%d) < %d, retry\n", vout_mv, OP20A_ENABLE_VOL_MIN_MV); + goto disable_cp; + } + ret = chargepump_status_check(&cp_status); + if (ret < 0) { + chg_err("charge pump enable error, rc=%d\n", ret); + goto disable_cp; + } + if (cp_status & (CP_SWITCH_OCP | CP_CRP | CP_VOUT_OVP | CP_CLP | CP_VBUS_OVP)) { + chg_err("charge pump status error, status=0x%02x\n", cp_status); + goto disable_cp; + } + if (cp_status & CP_REEADY) { + chg_info("charge pump successful start\n"); + return 0; + } + try_num++; + chg_err("charge pump status=0x%02x, try_num=%d\n", cp_status, try_num); + if (try_num < 40) + goto wait_cp_enable; + else + return -EAGAIN; + +disable_cp: + chargepump_disable(); + try_num++; + goto retry; +} + +#define CP1_STABILITY_THR 90 +static int fastchg_startup_process(struct op_chg_chip *chip) +{ + static int cp1_err_count; + static int cp2_err_count; + static int cep_err_count; + static int curr_err_count; + static int cp2_enabled_count; + int bq_adc_vbat = 0; + int bq_adc_vbus = 0; + int temp_value = 0; + int vout_mv; + u8 cp1_status; + bool cp2_is_enabled = false; + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + int ret; + + if (exchgpump_bq != NULL) { + bq2597x_get_adc_data(exchgpump_bq, ADC_VBAT, &bq_adc_vbat); + bq2597x_get_adc_data(exchgpump_bq, ADC_VBUS, &bq_adc_vbus); + } else { + chg_err("bq25970 err\n"); + return -ENODEV; + } + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return -ENODEV; + } + chg_err("<~WPC~> bq_adc_vbat=%d, bq_adc_vbus=%d\n", bq_adc_vbat, bq_adc_vbus); + ret = chargepump_status_check(&cp1_status); + if (ret != 0) { + chg_err("read charge status err, ret=%d\n", ret); + return ret; + } + if ((cp1_status != CP_REEADY) && (chg_status->fastchg_startup_step > FASTCHG_EN_CHGPUMP1_STEP)) { + chg_err("charge pump 1 is not ready, status=0x%02x\n", cp1_status); + __chargepump_show_registers(); + cp1_err_count++; + if (cp1_err_count > 10) { + chg_err("cp1 hw error\n"); + cp1_err_count = 0; + vote(chip->fastchg_disable_votable, HW_ERR_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } else { + chargepump_disable(); + if (chg_status->charge_current != 0) + wlchg_set_rx_charge_current(chip, 0); + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP1_STEP; + } + return 0; + } else { + if (chg_status->fastchg_startup_step != FASTCHG_EN_CHGPUMP1_STEP) + cp1_err_count = 0; + } + + if (chg_status->vol_set_ok || + (chg_status->fastchg_startup_step >= FASTCHG_EN_CHGPUMP2_STEP) || + (((chg_status->fastchg_startup_step == FASTCHG_WAIT_PMIC_STABLE_STEP) || + (chg_status->fastchg_startup_step == FASTCHG_SET_CHGPUMP2_VOL_AGAIN_STEP)) && + (bq_adc_vbus > (bq_adc_vbat * 2 + 150)))) { + chg_info("fastchg_startup_step:%d\n", chg_status->fastchg_startup_step); + if (chg_status->vol_set_ok) + cep_err_count = 0; + switch (chg_status->fastchg_startup_step) { + case FASTCHG_EN_CHGPUMP1_STEP: + if (g_rx_chip->chg_data.vout <= OP20A_ENABLE_VOL_MIN_MV) { + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_FASTCHG_INIT); + break; + } + ret = op20a_startup(chip); + if (ret) { + chg_err("cp1 hw error, rc=%d\n", ret); + cp1_err_count = 0; + vote(chip->fastchg_disable_votable, HW_ERR_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + break; + } + if (chip->ap_ctrl_dcdc) { + ret = wlchg_rx_enable_dcdc(g_rx_chip); + if (ret) { + chg_err("can't write enable dcdc cmd\n"); + break; + } + } + cp2_err_count = 0; + chg_status->fastchg_startup_step = FASTCHG_WAIT_CP1_STABLE_STEP; +#ifdef OP_DEBUG + if (!auto_mode) { + wlchg_set_rx_target_voltage(chip, 17000); + chg_status->charge_status = WPC_CHG_STATUS_BPP_WORKING; + break; + } +#endif + /* There can start to adjust the voltage directly */ + // break; + case FASTCHG_WAIT_CP1_STABLE_STEP: + ret = wlchg_rx_get_vout(g_rx_chip, &vout_mv); + if (ret) { + if (chg_status->charge_current != 0) + wlchg_set_rx_charge_current(chip, 0); + break; + } + + temp_value = vout_mv * CP1_STABILITY_THR / 200; + if (bq_adc_vbus > temp_value) { + if (chg_status->charge_current != WPC_CHARGE_CURRENT_WAIT_FAST) { + chg_info("enable pmic charge\n"); + pmic_high_vol_en(chip, true); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_WAIT_FAST); + } + chg_status->fastchg_startup_step = FASTCHG_SET_CHGPUMP2_VOL_STEP; + } else { + if (vout_mv >= WPC_CHARGE_VOLTAGE_OVP_MIN && chg_status->charge_current != 0) + wlchg_set_rx_charge_current(chip, 0); + chg_info("chargepump 1 is not ready, wait 100ms\n"); + break; + } + case FASTCHG_SET_CHGPUMP2_VOL_STEP: + temp_value = (g_op_chip->batt_volt * 4) + + (g_op_chip->batt_volt * 4 / 10) + 200; + wlchg_set_rx_target_voltage(chip, temp_value); + curr_err_count = 0; + chg_status->fastchg_startup_step = FASTCHG_WAIT_PMIC_STABLE_STEP; + break; + + case FASTCHG_WAIT_PMIC_STABLE_STEP: + if (g_rx_chip->chg_data.iout > 100) { + curr_err_count = 0; + cp2_enabled_count = 0; + chg_status->fastchg_startup_step = FASTCHG_SET_CHGPUMP2_VOL_AGAIN_STEP; + } else { + curr_err_count++; + if (curr_err_count > 100) { + curr_err_count = 0; + chg_err("pmic charging current is too small to start fast charge\n"); + //vote(chip->fastchg_disable_votable, CURR_ERR_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } + break; + } + case FASTCHG_SET_CHGPUMP2_VOL_AGAIN_STEP: + if (exchgpump_bq != NULL) { + bq2597x_check_charge_enabled(exchgpump_bq, &cp2_is_enabled); + if (cp2_is_enabled) { + if (cp2_enabled_count > 1) { + cp2_enabled_count = 0; + wlchg_set_rx_target_voltage(chip, g_rx_chip->chg_data.vout); + chg_status->fastchg_startup_step = + FASTCHG_CHECK_CHGPUMP2_AGAIN_STEP; + break; + } else { + cp2_enabled_count++; + } + } else { + cp2_enabled_count = 0; + } + temp_value = bq_adc_vbat * 2 + bq_adc_vbat * 2 / 10; + } else { + temp_value = chip->batt_volt * 2 + chip->batt_volt * 2 / 10; + } + if (bq_adc_vbus > (temp_value - 50) && + bq_adc_vbus < (temp_value + 150)) { + if (chg_status->vol_set_ok) + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP2_STEP; + else + break; + } else { + if ((bq_adc_vbus > (bq_adc_vbat * 2 + 150)) && + (bq_adc_vbus < temp_value) && + (cp2_enabled_count == 0)) { + chg_info("try enable cp2\n"); + bq2597x_enable_charge_pump(true); + } + + if (chg_status->vol_set_ok && !cp2_is_enabled) { + temp_value = (temp_value - bq_adc_vbus) * 2; + wlchg_set_rx_target_voltage(chip, g_rx_chip->chg_data.vout + temp_value); + chg_err("target_vol = %d\n", chg_status->target_vol); + } + break; + } + case FASTCHG_EN_CHGPUMP2_STEP: + bq2597x_enable_charge_pump(true); + chg_status->fastchg_startup_step = FASTCHG_CHECK_CHGPUMP2_STEP; + break; + case FASTCHG_CHECK_CHGPUMP2_STEP: + if (exchgpump_bq != NULL) + bq2597x_check_charge_enabled(exchgpump_bq, &cp2_is_enabled); + if (cp2_is_enabled) { + chg_status->fastchg_startup_step = FASTCHG_CHECK_CHGPUMP2_AGAIN_STEP; + } else { + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP2_STEP; + cp2_err_count++; + chg_info("enable chgpump try num: %d\n", cp2_err_count); + } + break; + case FASTCHG_CHECK_CHGPUMP2_AGAIN_STEP: + if (exchgpump_bq != NULL) + bq2597x_check_charge_enabled(exchgpump_bq, &cp2_is_enabled); + if (cp2_is_enabled) { + if (chip->chg_param.fastchg_fod_enable) { + wlchg_rx_set_fod_parm(g_rx_chip, chip->chg_param.fastchg_fod_parm); + chg_status->startup_fod_parm = false; + chg_info("write fastchg fod parm\n"); + } + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_FROM_CHGPUMP; + chip->wireless_type = POWER_SUPPLY_WIRELESS_TYPE_FAST; + if (chip->soc < chg_param->fastchg_soc_mid) { + if (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP) { + vote(chip->wlcs_fcc_votable, DEF_VOTER, true, FASTCHG_CURR_30W_MAX_UA); + vote(chip->wlcs_fcc_votable, MAX_VOTER, true, FASTCHG_CURR_30W_MAX_UA); + chg_status->max_current = FASTCHG_CURR_30W_MAX_UA / 1000; + } else { + vote(chip->wlcs_fcc_votable, DEF_VOTER, true, FASTCHG_CURR_15W_MAX_UA); + vote(chip->wlcs_fcc_votable, MAX_VOTER, true, FASTCHG_CURR_15W_MAX_UA); + chg_status->max_current = FASTCHG_CURR_15W_MAX_UA / 1000; + } + } else { + vote(chip->wlcs_fcc_votable, DEF_VOTER, true, FASTCHG_CURR_15W_MAX_UA); + vote(chip->wlcs_fcc_votable, MAX_VOTER, true, FASTCHG_CURR_15W_MAX_UA); + chg_status->max_current = FASTCHG_CURR_15W_MAX_UA / 1000; + } + vote(chip->wlcs_fcc_votable, EXIT_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, JEITA_VOTER, false, 0); + chg_status->startup_fast_chg = false; + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP1_STEP; + chg_status->fastchg_level_init_temp = 0; + chg_status->wait_cep_stable = true; + chg_status->fastchg_retry_count = 0; + chg_param->ffc_chg.ffc_wait_timeout = jiffies; + if (!chg_status->fastchg_restart) { + chg_status->fastchg_level = 0; + fastchg_ffc_param_init(chip); + chg_status->fastchg_restart = true; + } else { + vote(chip->wlcs_fcc_votable, FFC_VOTER, true, + chg_param->ffc_chg.ffc_step[chg_status->fastchg_level].curr_ua); + } + fastchg_curr_control_en(chip, true); + chg_info("enable chgpump success, try num: %d\n", cp2_err_count); + cp2_err_count = 0; + } else { + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP2_STEP; + cp2_err_count++; + chg_info("enable chgpump try num: %d\n", cp2_err_count); + } + break; + case FASTCHG_EN_PMIC_CHG_STEP: + temp_value = g_rx_chip->chg_data.vout * CP1_STABILITY_THR / 200; + if (bq_adc_vbus > temp_value) { + chg_info("enable pmic charge\n"); + pmic_high_vol_en(chip, true); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_WAIT_FAST); + curr_err_count = 0; + temp_value = g_op_chip->batt_volt * 4; + if (temp_value < chg_status->vol_set) + chg_status->vol_not_step = true; + wlchg_set_rx_target_voltage(chip, temp_value); + curr_err_count = 0; + chg_status->fastchg_startup_step = FASTCHG_WAIT_PMIC_STABLE_STEP; + } else { + if (chg_status->charge_current != 0) + wlchg_set_rx_charge_current(chip, 0); + chg_info("chargepump 1 is not ready, wait 100ms\n"); + } + break; + } + + if (cp2_err_count > 10) { + chg_err("can't enable chgpump, exit fastchg\n"); + cp2_err_count = 0; + vote(chip->fastchg_disable_votable, HW_ERR_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } + } + + if (!chg_status->vol_set_ok && + (chg_status->fastchg_startup_step < FASTCHG_EN_CHGPUMP2_STEP)) { + cep_err_count++; + if (cep_err_count > 300) { //30s + cep_err_count = 0; + chg_err("Cannot rise to target voltage, exit fast charge\n"); + chg_status->fastchg_retry_count++; + chg_status->fastchg_retry_timer = jiffies + 300 * HZ; //5 min + vote(chip->fastchg_disable_votable, STARTUP_CEP_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } + } + + return ret; +} + +static int wlchg_charge_status_process(struct op_chg_chip *chip) +{ + static bool wait_fast_chg; + static bool wlchg_status_abnormal; + int bq_adc_vbat = 0; + int work_freq; + int temp_val; + bool cp2_is_enabled; + //static int wait_cep_count; + struct rx_chip *rx_chip = g_rx_chip; + union power_supply_propval pval = {0, }; + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + struct cmd_info_t *cmd_info = &chip->cmd_info; + int rc; + + if (exchgpump_bq != NULL) { + if (exchgpump_bq->adc_enabled) { + bq2597x_get_adc_data(exchgpump_bq, ADC_VBAT, &bq_adc_vbat); + } else { + bq_adc_vbat = chip->batt_volt; + } + pr_debug("<~WPC~> bq_adc_vbat=%d\n", bq_adc_vbat); + } else { + chg_err("exchgpump_bq not ready\n"); + return -ENODEV; + } + + if (rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return -ENODEV; + } + + if (!chg_status->ftm_mode) { + if (chip->batt_missing) { + wlchg_rx_set_chip_sleep(1); + chg_err("battery miss\n"); + return 0; + } + + if (chg_status->temp_region == WLCHG_BATT_TEMP_COLD || + chg_status->temp_region == WLCHG_BATT_TEMP_HOT || + chg_status->rx_ovp) { + chg_err("<~WPC~> The temperature or voltage is abnormal, stop charge!\n"); + if (!wlchg_status_abnormal) { + wlchg_status_abnormal = true; + chargepump_disable(); + bq2597x_enable_charge_pump(false); + wlchg_rx_set_chip_sleep(1); + return 0; + } + if (chg_status->charge_current != WPC_CHARGE_CURRENT_ZERO) + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_ZERO); + + if (chg_status->charge_voltage != WPC_CHARGE_VOLTAGE_DEFAULT) { + chg_status->vol_not_step = true; + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_DEFAULT); + } + + chg_status->charge_status = WPC_CHG_STATUS_DEFAULT; + return 0; + } else { + wlchg_status_abnormal = false; + if (((chip->quiet_mode_need != chg_status->quiet_mode_enabled) || + !chg_status->quiet_mode_init) && + ((chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH) || + (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP)) && + (atomic_read(&chip->hb_count) > 0) && !chg_status->charge_done) { + if (chip->quiet_mode_need) { + // dock should in quiet mode, goto 10w. + chg_info("send msg to dock into quiet mode."); + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_QUIET_MODE_MSG); + if (chg_status->deviation_check_done) + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_QUIET; + else + chg_status->charge_status = WPC_CHG_STATUS_DEFAULT; + } else { + chg_info("send msg to dock restore normal mode."); + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_NORMAL_MODE_MSG); + } + } + + if (chip->disable_batt_charge && + (chg_status->charge_status != WPC_CHG_STATUS_WAIT_DISABLE_BATT_CHARGE) && + (chg_status->charge_status != WPC_CHG_STATUS_DISABLE_BATT_CHARGE)) { + if ((chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH || + chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP) && + (chg_status->charge_type == WPC_CHARGE_TYPE_FAST) && + chg_status->deviation_check_done) { + if (chip->chg_param.fastchg_fod_enable && chg_status->startup_fod_parm) { + wlchg_rx_set_fod_parm(g_rx_chip, chip->chg_param.fastchg_fod_parm); + chg_status->startup_fod_parm = false; + chg_info("write fastchg fod parm\n"); + } + pmic_high_vol_en(chip, true); + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_STOP_CHG); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_STOP_CHG); + chg_status->charge_status = WPC_CHG_STATUS_WAIT_DISABLE_BATT_CHARGE; + } + } + } + } + + switch (chg_status->charge_status) { + case WPC_CHG_STATUS_DEFAULT: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_DEFAULT..........\n"); +#ifndef IDT_LAB_TEST + if (!chg_status->adapter_msg_send && (atomic_read(&chip->hb_count) > 0)) { + chg_err("can't send adapter msg, try again\n"); + wlchg_send_msg(WLCHG_MSG_CHG_INFO, 5, WLCHG_ADAPTER_MSG); + break; + } +#endif + + if (chg_status->ftm_mode) { + if (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH || + chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP) { + chargepump_hw_init(); + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_FASTCHG; + } + break; + } + if (chg_status->charge_voltage != WPC_CHARGE_VOLTAGE_DEFAULT) { + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_DEFAULT); + pmic_high_vol_en(chip, false); + } + + if (chg_status->adapter_type == ADAPTER_TYPE_UNKNOWN) { + /* + * The energy here cannot be too small, otherwise it + * may affect unpacking when reverse charging. + */ + if (chg_status->charge_current != WPC_CHARGE_CURRENT_DEFAULT) + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_DEFAULT); + + if (wlchg_rx_get_run_mode(rx_chip) == RX_RUNNING_MODE_EPP) { + chg_err("<~WPC~> RX_RUNNING_MODE_EPP, Change to EPP charge\n"); + chg_status->epp_working = true; + chg_status->fastchg_display_delay = false; + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_EPP; + break; + } else if (wlchg_rx_get_run_mode(rx_chip) == RX_RUNNING_MODE_BPP) { +#ifndef IDT_LAB_TEST + if (!chg_status->get_adapter_err && cmd_info->cmd == 0) { + rc = wlchg_send_msg(WLCHG_MSG_CHG_INFO, 5, WLCHG_ADAPTER_MSG); + if (rc < 0) + break; + } + if (chg_status->get_adapter_err || (atomic_read(&chip->hb_count) <= 0)) { + wait_fast_chg = true; +#else + wait_fast_chg = false; +#endif + chg_err("<~WPC~> RX_RUNNING_MODE_BPP, Change to BPP charge\n"); + chg_status->fastchg_display_delay = false; + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_BPP; + break; +#ifndef IDT_LAB_TEST + } +#endif + } + } else { + if (chg_status->charge_current != WPC_CHARGE_CURRENT_DEFAULT) + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_DEFAULT); + +#ifdef OP_DEBUG + if (force_epp) { + chg_status->epp_working = true; + chg_status->adapter_type = + ADAPTER_TYPE_EPP; + } else if (force_bpp) { + chg_status->adapter_type = + ADAPTER_TYPE_NORMAL_CHARGE; + } +#endif + + if (!chg_status->deviation_check_done && + ((chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH) || + (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP))) { + if (!enable_deviated_check) { + chg_status->is_deviation = false; + goto freq_check_done; + } + + rc = wlchg_rx_get_work_freq(rx_chip, &work_freq); + if (rc != 0) { + chg_err("can't read rx work freq\n"); + return rc; + } + if (work_freq > chg_param->freq_threshold) { + chg_status->is_deviation = false; + chg_info("phone location is correct\n"); + } else { + chg_status->is_deviation = true; + chg_info("work_freq=%d\n", work_freq); + } +freq_check_done: + chg_status->deviation_check_done = true; + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + } + + chg_status->fastchg_display_delay = false; + chg_info("adapter = %d\n", chg_status->adapter_type); + switch (chg_status->adapter_type) { + case ADAPTER_TYPE_FASTCHAGE_DASH: + case ADAPTER_TYPE_FASTCHAGE_WARP: + if (!chip->quiet_mode_need) { + chg_status->charge_status = + WPC_CHG_STATUS_READY_FOR_FASTCHG; + } else { + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_QUIET; + } + break; + case ADAPTER_TYPE_EPP: + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_EPP; + break; + default: + chg_status->charge_status = + WPC_CHG_STATUS_READY_FOR_BPP; + break; + } + } + break; + + case WPC_CHG_STATUS_READY_FOR_BPP: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_READY_FOR_BPP..........\n"); +#ifndef IDT_LAB_TEST + if ((atomic_read(&chip->hb_count) > 0) && + (chg_status->adapter_type == ADAPTER_TYPE_UNKNOWN)) { + rc = wlchg_send_msg(WLCHG_MSG_CHG_INFO, 5, WLCHG_TX_ID_MSG); + if (rc) { + chg_err("send tx id msg err, tyr again\n"); + break; + } + } + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_DEFAULT); +#endif + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_DEFAULT); + chg_status->is_power_changed = true; + chg_status->charge_status = WPC_CHG_STATUS_BPP; + break; + + case WPC_CHG_STATUS_BPP: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_BPP..........\n"); +#ifndef IDT_LAB_TEST + if (!chg_status->geted_tx_id && + (chg_status->adapter_type == ADAPTER_TYPE_UNKNOWN) && + (atomic_read(&chip->hb_count) > 0)) + break; +#endif + if (rx_chip->on_op_trx) { + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_ON_TRX); + chg_info("It's on back of OP phone Trx, set current %d", WPC_CHARGE_CURRENT_ON_TRX); + } else { + wait_fast_chg = true; + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_BPP); + chg_info("It's on BPP dock, set current %d", WPC_CHARGE_CURRENT_BPP); +#ifndef IDT_LAB_TEST + if (atomic_read(&chip->hb_count) > 0) { + rc = wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_ADAPTER_MSG); + if (rc) { + chg_err("send adapter msg err, tyr again\n"); + break; + } + } +#endif + } + + chg_status->charge_status = + WPC_CHG_STATUS_BPP_WORKING; + chip->wireless_type = POWER_SUPPLY_WIRELESS_TYPE_BPP; + chg_status->startup_fast_chg = false; + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + break; + + case WPC_CHG_STATUS_BPP_WORKING: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_BPP_WORKING..........\n"); +#ifndef IDT_LAB_TEST + if (wait_fast_chg && ((chg_status->adapter_type != ADAPTER_TYPE_UNKNOWN) && + (chg_status->adapter_type != ADAPTER_TYPE_NORMAL_CHARGE))) { + wait_fast_chg = false; + chg_status->startup_fast_chg = true; + chg_status->charge_status = WPC_CHG_STATUS_DEFAULT; + chip->wireless_type = POWER_SUPPLY_TYPE_UNKNOWN; + } + if ((atomic_read(&chip->hb_count) > 0) && chip->heart_stop) { + rc = wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_ADAPTER_MSG); + if (rc) + chg_err("send adapter msg err, tyr again\n"); + else + chip->heart_stop = false; + } +#endif + break; + + case WPC_CHG_STATUS_READY_FOR_EPP: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_READY_FOR_EPP..........\n"); + pmic_high_vol_en(chip, true); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_DEFAULT); +#ifndef IDT_LAB_TEST + // EPP not send msg to dock, not adjust voltage. + wlchg_set_rx_target_voltage_fast(chip, WPC_CHARGE_VOLTAGE_EPP); + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_FASTCHAGE_MSG); +#endif + chg_status->is_power_changed = true; + chg_status->charge_status = WPC_CHG_STATUS_EPP; + break; + + case WPC_CHG_STATUS_EPP: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_EPP..........\n"); + if (chg_status->epp_working) { + if (chg_status->vol_set_ok) { + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_EPP); + chg_status->charge_status = + WPC_CHG_STATUS_EPP_WORKING; + chip->wireless_type = POWER_SUPPLY_WIRELESS_TYPE_EPP; + } + chg_status->startup_fast_chg = false; + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + } + break; + + case WPC_CHG_STATUS_EPP_WORKING: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_EPP_WORKING..........\n"); + pmic_chan_check_skin_temp(chip); + break; + + case WPC_CHG_STATUS_READY_FOR_QUIET: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_READY_FOR_QUIET..........\n"); + if (chg_status->quiet_mode_enabled) { + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + if (chg_status->charge_type != WPC_CHARGE_TYPE_FAST) { + wlchg_set_rx_target_voltage_fast(chip, WPC_CHARGE_VOLTAGE_EPP); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_WAIT_FAST); + rc = wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_FASTCHAGE_MSG); + if (rc) { + chg_err("send fast charge msg err, try again\n"); + break; + } + } + vote(chip->fastchg_disable_votable, QUIET_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } else { + if (!chip->quiet_mode_need) { + chg_err("quiet mode has been disabled, not waiting responds."); + chg_status->charge_status = WPC_CHG_STATUS_DEFAULT; + } + } + break; + + case WPC_CHG_STATUS_READY_FOR_FASTCHG: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_READY_FOR_FASTCHG..........\n"); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_WAIT_FAST); + wlchg_set_rx_target_voltage_fast(chip, WPC_CHARGE_VOLTAGE_FASTCHG_INIT); + pmic_high_vol_en(chip, true); + rc = wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_FASTCHAGE_MSG); + if (rc) { + chg_err("send fast charge msg err, try again\n"); + break; + } + if (chip->ap_ctrl_dcdc) + op_set_dcdc_en_value(1); + if (exchgpump_bq != NULL) { + chg_info("enable bq2597x adc."); + bq2597x_enable_adc(exchgpump_bq, true); + } + chg_status->is_power_changed = true; + chg_status->charge_status = + WPC_CHG_STATUS_WAITING_FOR_TX_INTO_FASTCHG; + break; + + case WPC_CHG_STATUS_WAITING_FOR_TX_INTO_FASTCHG: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_WAITING_FOR_TX_INTO_FASTCHG..........\n"); + if (chg_status->vol_set_ok && + (chg_status->charge_type == WPC_CHARGE_TYPE_FAST)) { + if (chg_status->ftm_mode) { + if (!chip->batt_psy) { + chip->batt_psy = power_supply_get_by_name("battery"); + if (!chip->batt_psy) { + chg_err("battery psy is not ready\n"); + break; + } + } + pval.intval = 0; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); + if (rc < 0) { + pr_err("Couldn't set input_suspend rc=%d\n", rc); + break; + } + chargepump_hw_init(); + rc = chargepump_check_config(); + if (rc) { + chg_err("charge pump status error\n"); + break; + } + chargepump_enable(); + chargepump_set_for_LDO(); + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_FTM); + chg_status->charge_status = + WPC_CHG_STATUS_READY_FOR_FTM; + } else { + if (((chg_status->temp_region == WLCHG_BATT_TEMP_PRE_NORMAL) || + (chg_status->temp_region == WLCHG_BATT_TEMP_NORMAL)) && + (chip->batt_volt > chg_param->fastchg_vol_min) && + (chip->batt_volt < chg_param->fastchg_vol_entry_max) && + (chip->soc >= chg_param->fastchg_soc_min) && + (chip->soc <= chg_param->fastchg_soc_max)) { + chg_status->fastchg_startup_step = FASTCHG_EN_CHGPUMP1_STEP; + chg_status->charge_status = WPC_CHG_STATUS_INCREASE_VOLTAGE; + if (chip->chg_param.fastchg_fod_enable) { + wlchg_rx_set_fod_parm(g_rx_chip, chip->chg_param.fastchg_fod_parm_startup); + chg_status->startup_fod_parm = true; + chg_info("write fastchg startup fod parm\n"); + } + } else { + if (chip->batt_volt >= chg_param->fastchg_vol_entry_max) + vote(chip->fastchg_disable_votable, BATT_VOL_VOTER, true, 0); + chg_err("batt_temp=%d, batt_volt=%d, soc=%d\n", + chip->temperature, chip->batt_volt, chip->soc); + chg_status->vol_not_step = true; + chg_status->startup_fast_chg = false; + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + } + } + } + chg_info("vol_set_ok=%d, charge_type=%d", chg_status->vol_set_ok, chg_status->charge_type); + break; + + case WPC_CHG_STATUS_INCREASE_VOLTAGE: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_INCREASE_VOLTAGE..........\n"); + if (chip->batt_volt >= chg_param->fastchg_vol_entry_max && + chg_status->fastchg_startup_step < FASTCHG_EN_CHGPUMP2_STEP) { + chg_err("battert voltage too high\n"); + chg_status->startup_fast_chg = false; + vote(chip->fastchg_disable_votable, BATT_VOL_VOTER, true, 0); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_EXIT; + break; + } + fastchg_startup_process(chip); + break; + + case WPC_CHG_STATUS_FAST_CHARGING_FROM_CHGPUMP: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_FAST_CHARGING_FROM_CHGPUMP..........\n"); + if (rx_chip->chg_data.iout > 500) { + if (chg_status->charge_current > WPC_CHARGE_CURRENT_ZERO) { + chg_err("<~WPC~> Iout > 500mA & ChargeCurrent > 200mA. Disable pmic\n"); + wlchg_set_rx_charge_current(chip, 0); + pmic_high_vol_en(chip, false); + update_wlchg_started(true); + } + } + + if (chg_status->is_deviation) { + temp_val = get_client_vote(chip->wlcs_fcc_votable, MAX_VOTER); + if (temp_val == FASTCHG_CURR_30W_MAX_UA) { + if (rx_chip->chg_data.iout > 1000) + chg_status->is_deviation = false; + } else { + if (rx_chip->chg_data.iout > 800) + chg_status->is_deviation = false; + } + } + + if (fastchg_err_check(chip) > 0) + break; + fastchg_temp_check(chip); + fastchg_check_skin_temp(chip); + fastchg_cep_adj(chip); + fastchg_check_ibat(chip); + +#ifdef HW_TEST_EDITION + if ((chip->icharging > 5600) && + (chip->w30w_work_started == false)) { + chip->w30w_work_started = true; + schedule_delayed_work( + &chip->w30w_timeout_work, + round_jiffies_relative(msecs_to_jiffies( + (chip->w30w_time) * 60 * 1000))); + } +#endif + break; + + case WPC_CHG_STATUS_FAST_CHARGING_EXIT: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_FAST_CHARGING_EXIT..........\n"); + if (chip->chg_param.fastchg_fod_enable && chg_status->startup_fod_parm && + chg_status->charge_type == WPC_CHARGE_TYPE_FAST) { + wlchg_rx_set_fod_parm(g_rx_chip, chip->chg_param.fastchg_fod_parm); + chg_status->startup_fod_parm = false; + chg_info("write fastchg fod parm\n"); + } + pmic_high_vol_en(chip, true); + wlchg_set_rx_target_voltage(chip, WPC_CHARGE_VOLTAGE_EPP); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_CHGPUMP_TO_CHARGER); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_WAIT_EXIT; + break; + + case WPC_CHG_STATUS_FAST_CHARGING_WAIT_EXIT: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_FAST_CHARGING_WAIT_EXIT..........\n"); + if (chg_status->vol_set_ok) { + update_wlchg_started(false); + chg_status->startup_fast_chg = false; + chg_status->is_power_changed = true; + chargepump_disable(); + bq2597x_enable_charge_pump(false); + wlchg_set_rx_charge_current_step(chip, WPC_CHARGE_CURRENT_EPP); + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_FFC; + if (!chg_status->cep_timeout_adjusted && chip->soc > chg_param->fastchg_soc_max) + wlchg_send_msg(WLCHG_MSG_CHG_INFO, -1, WLCHG_CEP_TIMEOUT_MSG); + } + break; + + case WPC_CHG_STATUS_FAST_CHARGING_FFC: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_FAST_CHARGING_FFC..........\n"); + if (chg_status->ffc_check) { + if (chg_status->temp_region == WLCHG_BATT_TEMP_NORMAL) { + wlchg_set_rx_charge_current_step(chip, WPC_CHARGE_CURRENT_EPP); + op_switch_normal_set(); + chg_status->ffc_check = false; + } else { + chg_err("battery temp = %d, can't run normal charge ffc\n", chip->temperature); + } + chg_status->is_power_changed = true; + chg_status->charge_status = WPC_CHG_STATUS_FAST_CHARGING_FROM_PMIC; + } else { + if (((chg_status->temp_region == WLCHG_BATT_TEMP_PRE_NORMAL) || + (chg_status->temp_region == WLCHG_BATT_TEMP_NORMAL)) && + (chip->batt_volt < chg_param->fastchg_vol_entry_max) && + (chip->soc >= chg_param->fastchg_soc_min) && + (chip->soc <= chg_param->fastchg_soc_max)) { + + if (chg_status->quiet_mode_enabled && + (chg_status->charge_type != WPC_CHARGE_TYPE_FAST)) { + chg_err("quiet mode, but dock hasn't into fast type."); + break; + } + wlchg_fastchg_restart_check(chip); + if (!chg_status->fastchg_disable) { + chg_status->is_power_changed = true; + chg_status->startup_fast_chg = true; + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_FASTCHG; + } + } else { + if (chip->batt_volt >= chg_param->fastchg_vol_entry_max) + vote(chip->fastchg_disable_votable, BATT_VOL_VOTER, true, 0); + } + + wlchg_check_term_charge(chip); + } + break; + + case WPC_CHG_STATUS_FAST_CHARGING_FROM_PMIC: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_FAST_CHARGING_FROM_PMIC..........\n"); + wlchg_check_term_charge(chip); + break; + + case WPC_CHG_STATUS_WAIT_DISABLE_BATT_CHARGE: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_WAIT_DISABLE_BATT_CHARGE..........\n"); + if (chg_status->vol_set_ok) { + update_wlchg_started(false); + chg_status->startup_fast_chg = false; + chg_status->is_power_changed = true; + chargepump_disable(); + bq2597x_enable_charge_pump(false); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_STOP_CHG); + chg_status->charge_status = WPC_CHG_STATUS_DISABLE_BATT_CHARGE; + } + break; + + case WPC_CHG_STATUS_DISABLE_BATT_CHARGE: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_DISABLE_BATT_CHARGE..........\n"); + if (!chip->disable_batt_charge) { + chg_status->startup_fast_chg = true; + chg_status->is_power_changed = true; + chg_status->charge_status = WPC_CHG_STATUS_DEFAULT; + } + break; + + case WPC_CHG_STATUS_READY_FOR_FTM: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_READY_FOR_FTM..........\n"); + if (chg_status->vol_set_ok) { + chg_status->startup_fast_chg = false; + bq2597x_enable_charge_pump(true); + msleep(500); + if (exchgpump_bq != NULL) + bq2597x_check_charge_enabled(exchgpump_bq, &cp2_is_enabled); + if (cp2_is_enabled) + chg_status->charge_status = WPC_CHG_STATUS_FTM_WORKING; + else + chg_err("wkcs: can't enable charge pump 2\n"); + } + break; + + case WPC_CHG_STATUS_FTM_WORKING: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_FTM_WORKING..........\n"); + if (exchgpump_bq != NULL) + bq2597x_check_charge_enabled(exchgpump_bq, &cp2_is_enabled); + if (!cp2_is_enabled) { + chg_err("wkcs: charge pump 2 err\n"); + chg_status->charge_status = WPC_CHG_STATUS_READY_FOR_FTM; + } + break; + + default: + chg_err("<~WPC~> ..........WPC_CHG_STATUS_ERROR..........\n"); + break; + } + + return 0; +} + +void wlchg_dischg_status(struct op_chg_chip *chip) +{ + char tx_status = 0, err_flag = 0; + int rc = 0; + static int trycount; + + if (g_rx_chip == NULL) { + chg_err("rc chip is not ready\n"); + return; + } + + rc = wlchg_rx_get_idt_rtx_status(g_rx_chip, &tx_status, &err_flag); + if (rc) { + chg_err("can't get trx status\n"); + return; + } + chg_err("<~WPC~>rtx func status:0x%02x, err:0x%02x, wpc_dischg_status[%d]\n", + tx_status, err_flag, chip->wlchg_status.wpc_dischg_status); + if (err_flag != 0) { + if (TRX_ERR_TX_RXAC & err_flag) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_RXAC; + } else if (TRX_ERR_TX_OCP & err_flag) { + //chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_OCP; + // not care + chg_err("ERR_TX_OCP error occurs."); + } else if (TRX_ERR_TX_OVP & err_flag) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_OVP; + } else if (TRX_ERR_TX_LVP & err_flag) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_LVP; + } else if (TRX_ERR_TX_FOD & err_flag) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_FOD; + } else if (TRX_ERR_TX_OTP & err_flag) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_OTP; + } else if (TRX_ERR_TX_CEPTIMEOUT & err_flag) { + //chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_CEPTIMEOUT; + // not care + chg_err("ERR_TX_CEPTIMEOUT error occurs."); + } else if (TRX_ERR_TX_RXEPT & err_flag) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_ERR_TX_RXEPT; + } + + if (chip->wlchg_status.wpc_dischg_status >= WPC_DISCHG_IC_ERR_TX_RXAC) { + chg_err("There is error-%d occurred, disable Trx func.", + chip->wlchg_status.wpc_dischg_status); + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_STATUS_OFF; + return; + } + } + + if (tx_status != 0) { + if (TRX_READY & tx_status) { + chip->wlchg_status.tx_online = false; + chip->wlchg_status.wpc_dischg_status = + WPC_DISCHG_IC_READY; + wlchg_rx_trx_enbale(g_rx_chip, true); + schedule_delayed_work(&chip->dischg_work, WPC_DISCHG_WAIT_READY_EVENT); + trycount = 0; + } else if (TRX_DIGITALPING & tx_status || + TRX_ANALOGPING & tx_status) { + chip->wlchg_status.tx_online = false; + if (WPC_DISCHG_IC_PING_DEVICE == + chip->wlchg_status.wpc_dischg_status) { + chg_err("<~WPC~>rtx func no device to be charged, 60s timeout, disable TRX!\n"); + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_STATUS_OFF; + } else { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_PING_DEVICE; + schedule_delayed_work(&chip->dischg_work, WPC_DISCHG_WAIT_DEVICE_EVENT); + chg_err("<~WPC~>rtx func waiting device 60s......\n"); + } + } else if (TRX_TRANSFER & tx_status) { + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_IC_TRANSFER; + chip->wlchg_status.tx_online = true; + // check status per 5s if in IC_TRANSFER. + schedule_delayed_work(&chip->dischg_work, WPC_DISCHG_POLL_STATUS_EVENT); + chg_err("<~WPC~>rtx func in discharging now, check status 5 seconds later!\n"); + } + if (chip->wireless_psy != NULL) { + if (exfg_instance != NULL) + exfg_instance->set_allow_reading(true); + power_supply_changed(chip->wireless_psy); + chg_info("reported status change event."); + } + } + + if (chip->wlchg_status.wpc_dischg_status == WPC_DISCHG_IC_TRANSFER) { + if (!reverse_charge_status) { + reverse_charge_notifier_call_chain(1); + reverse_charge_status = 1; + } + } + if (chip->wlchg_status.wpc_dischg_status != WPC_DISCHG_IC_TRANSFER) { + if (reverse_charge_status) { + reverse_charge_notifier_call_chain(0); + reverse_charge_status = 0; + } + } + if ((tx_status == 0) && (err_flag == 0)) { + // try again 5 times. + if (trycount++ >= 5) { + trycount = 0; + chip->wlchg_status.wpc_dischg_status = + WPC_DISCHG_STATUS_OFF; + } + schedule_delayed_work(&chip->dischg_work, WPC_DISCHG_WAIT_STATUS_EVENT); + } + + return; +} + +static void wlchg_dischg_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, dischg_work); + + chg_err("<~WPC~>rtx func wpc_dischg_status[%d]\n", + chip->wlchg_status.wpc_dischg_status); + wlchg_dischg_status(chip); + return; +} + +int wlchg_tx_callback(void) +{ + struct op_chg_chip *chip = g_op_chip; + if (chip == NULL) { + chg_err("g_op_chip not exist, return\n"); + return -ENODEV; + } + chg_err("rtx func chip->chg_data.wpc_dischg_status[%d]\n", + chip->wlchg_status.wpc_dischg_status); + if (chip->wlchg_status.wpc_dischg_status == WPC_DISCHG_STATUS_ON || + chip->wlchg_status.wpc_dischg_status == WPC_DISCHG_IC_READY || + chip->wlchg_status.wpc_dischg_status == + WPC_DISCHG_IC_PING_DEVICE || + chip->wlchg_status.wpc_dischg_status == + WPC_DISCHG_IC_TRANSFER) { + cancel_delayed_work_sync(&chip->dischg_work); + wlchg_dischg_status(chip); + } + return 0; +} + +int switch_to_otg_mode(bool enable) +{ + if (g_op_chip == NULL) { + chg_err("op_wireless_ic not exist, return\n"); + return -ENODEV; + } + + + if (enable) { + op_set_wrx_en_value(2); + } else { + if (g_op_chip->wireless_mode == WIRELESS_MODE_NULL) + op_set_wrx_en_value(0); + } + + return 0; +} + +static void wlchg_connect_func(struct op_chg_chip *chip) +{ + chg_err("<~WPC~> wpc dock has connected!>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + if (chip == NULL) { + chg_err("g_op_chip not ready\n"); + return; + } + if (normal_charger == NULL) { + chg_err("smbchg not ready\n"); + return; + } + if (g_rx_chip == NULL) { + chg_err("g_rx_chip not ready\n"); + return; + } + if (exfg_instance == NULL) { + chg_err("fuelgauger not ready\n"); + return; + } + + if (chip->wireless_mode != WIRELESS_MODE_TX) { + check_batt_present(chip); + if (chip->batt_missing) { + wlchg_rx_set_chip_sleep(1); + chg_err("battery miss\n"); + return; + } + + if (!chip->wlchg_wake_lock_on) { + chg_info("acquire wlchg_wake_lock\n"); + __pm_stay_awake(chip->wlchg_wake_lock); + chip->wlchg_wake_lock_on = true; + } else { + chg_err("wlchg_wake_lock is already stay awake."); + } + + chip->wireless_mode = WIRELESS_MODE_RX; + if (normal_charger != NULL) { + normal_charger->real_charger_type = + POWER_SUPPLY_TYPE_WIRELESS; + normal_charger->usb_psy_desc.type = + POWER_SUPPLY_TYPE_WIRELESS; + vote(normal_charger->usb_icl_votable, + SW_ICL_MAX_VOTER, true, PMIC_ICL_MAX); + } + wlchg_init_connected_task(chip); + op_set_wrx_en_value(2); + wlchg_rx_get_run_flag(g_rx_chip); + schedule_delayed_work(&chip->update_bat_info_work, 0); + schedule_delayed_work(&chip->wlchg_task_work, 0); + //schedule_delayed_work(&chip->fastchg_curr_vol_work, 0); + wlchg_set_rx_charge_current(chip, WPC_CHARGE_CURRENT_INIT_100MA); + chip->wlchg_status.startup_fast_chg = true; + wlchg_send_msg(WLCHG_MSG_CHG_INFO, 5, WLCHG_ADAPTER_MSG); + exfg_instance->set_allow_reading(true); + } else { + chg_info("reverse charge did not exit, wait 100ms\n"); + schedule_delayed_work(&chip->wlchg_connect_check_work, msecs_to_jiffies(100)); + } +} + +static void wlchg_disconnect_func(struct op_chg_chip *chip) +{ + union power_supply_propval pval = {0, }; + unsigned long delay_time; + int rc; + + if (chip->wlchg_status.curr_err_count > FASTCHG_CURR_ERR_MAX) + delay_time = jiffies + WLCHG_ACTIVE_DISCONNECT_DELAYED; + else + delay_time = jiffies + WLCHG_DISCONNECT_DELAYED; + chg_err("<~WPC~> wpc dock has disconnected!< < < < < < < < < < < < <\n"); + if (chip == NULL) { + chg_err("g_op_chip not exist, return\n"); + return; + } + + if (chip->wireless_mode != WIRELESS_MODE_TX) { + chip->wireless_mode = WIRELESS_MODE_NULL; + if (!typec_is_otg_mode()) + op_set_wrx_en_value(0); + } + if (chip->ap_ctrl_dcdc) + op_set_dcdc_en_value(0); + chip->wlchg_status.charge_online = false; + chip->disable_batt_charge = false; + if (((chip->wlchg_status.adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH) || + (chip->wlchg_status.adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP)) && + ((chip->wlchg_status.temp_region == WLCHG_BATT_TEMP_PRE_NORMAL) || + (chip->wlchg_status.temp_region == WLCHG_BATT_TEMP_NORMAL)) && + chip->wlchg_status.deviation_check_done) { + chip->wlchg_status.fastchg_display_delay = true; + } + cancel_delayed_work_sync(&chip->wlchg_task_work); + cancel_delayed_work_sync(&chip->update_bat_info_work); + cancel_delayed_work_sync(&chip->fastchg_curr_vol_work); + vote(chip->fastchg_disable_votable, QUIET_VOTER, false, 0); + vote(chip->fastchg_disable_votable, CEP_VOTER, false, 0); + vote(chip->fastchg_disable_votable, FFC_VOTER, false, 0); + vote(chip->fastchg_disable_votable, SKIN_VOTER, false, 0); + vote(chip->fastchg_disable_votable, BATT_VOL_VOTER, false, 0); + vote(chip->fastchg_disable_votable, BATT_CURR_VOTER, false, 0); + vote(chip->fastchg_disable_votable, STARTUP_CEP_VOTER, false, 0); + vote(chip->fastchg_disable_votable, HW_ERR_VOTER, false, 0); + vote(chip->fastchg_disable_votable, CURR_ERR_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, DEF_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, MAX_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, STEP_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, EXIT_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, FFC_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, JEITA_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, CEP_VOTER, false, 0); + vote(chip->wlcs_fcc_votable, SKIN_VOTER, false, 0); + wlchg_deinit_after_disconnected(chip); + if (normal_charger != NULL) { + // disable wireless vote client + vote(normal_charger->usb_icl_votable, WIRED_CONN_VOTER, false, 0); + vote(normal_charger->usb_icl_votable, WLCH_VOTER, false, 0); + vote(normal_charger->fcc_votable, WLCH_VOTER, false, 0); + vote(normal_charger->chg_disable_votable, WLCH_VOTER, false, 0); + vote(normal_charger->usb_icl_votable, WLCH_FFC_VOTER, false, 0); + vote(normal_charger->usb_icl_votable, WLCH_SKIN_VOTER, false, 0); + normal_charger->wireless_present = false; + // remove typec related icl vote + vote(normal_charger->usb_icl_votable, CHG_TERMINATION_VOTER, false, 0); + //wireless_present must before below func call. + pmic_high_vol_en(chip, false); + } + vote(chip->wlcs_fcc_votable, MAX_VOTER, true, 0); + if (chip->wlchg_status.dock_on) { + chip->wlchg_status.dock_on = false; + cancel_delayed_work_sync(&chip->charger_exit_work); + /* + * Here need to recalculate the time that needs to be delayed to + * compensate the time consumption from receiving the disconnect + * signal to running here. + */ + if (time_is_before_jiffies(delay_time) || !chg_icon_update_delay) + delay_time = 0; + else + delay_time = delay_time - jiffies; + schedule_delayed_work(&chip->charger_exit_work, delay_time); + } else { + if (chip->wlchg_wake_lock_on) { + chg_info("release wlchg_wake_lock\n"); + __pm_relax(chip->wlchg_wake_lock); + chip->wlchg_wake_lock_on = false; + } else { + chg_err("wlchg_wake_lock is already relax\n"); + } + } + + if (chip->wlchg_status.ftm_mode) { + if (!chip->batt_psy) { + chip->batt_psy = power_supply_get_by_name("battery"); + if (!chip->batt_psy) { + chg_err("battery psy is not ready\n"); + return; + } + } + pval.intval = 1; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval); + if (rc < 0) { + pr_err("Couldn't set input_suspend rc=%d\n", rc); + } + } +} + +int wlchg_connect_callback_func(bool ldo_on) +{ + struct op_chg_chip *chip = g_op_chip; + + if (chip == NULL) { + chg_err("g_op_chip not exist, return\n"); + return -ENODEV; + } + + mutex_lock(&chip->connect_lock); + if (wlchg_get_usbin_val() == 0 && wlchg_rx_get_chip_con() == 1) { + if (!(chip->wlchg_status.dock_on)) { + chg_err("report wlchg online."); + wlchg_set_rx_charge_current(chip, 0); + op_set_wrx_en_value(2); + chip->wlchg_status.dock_on = true; + chip->charger_exist = true; + if (normal_charger != NULL) + normal_charger->wireless_present = true; + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + } + if (ldo_on) { + chg_err("connected really."); + wlchg_connect_func(chip); + } + } else { + wlchg_disconnect_func(chip); + } + mutex_unlock(&chip->connect_lock); + + return 0; +} + +static void wlchg_connect_check_work(struct work_struct *work) +{ + wlchg_connect_callback_func(true); +} + +static void wlchg_usbin_int_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, usbin_int_work); + int level; + + if (!chip) { + chg_err("wlchg driver not ready\n"); + return; + } + + level = wlchg_get_usbin_val(); + msleep(50); + if (level != wlchg_get_usbin_val()) { + chg_err("Level duration is too short to ignore\n"); + return; + } + + if (normal_charger != NULL) + vote(normal_charger->awake_votable, WIRED_CONN_VOTER, true, 0); + + printk(KERN_ERR + "[OP_CHG][%s]: op-wlchg test level[%d], chip->otg_switch[%d]\n", + __func__, level, g_op_chip->otg_switch); + if (level == 1) { + if (normal_charger != NULL && normal_charger->wireless_present) { + normal_charger->wireless_present = false; + normal_charger->apsd_delayed = true; + } + wpc_chg_quit_max_cnt = 0; + wlchg_rx_set_chip_sleep(1); + if ((chip->wireless_mode == WIRELESS_MODE_NULL) && + !chip->wlchg_status.dock_on && + !chip->wlchg_status.tx_present) { + normal_charger->apsd_delayed = false; + vote(normal_charger->awake_votable, WIRED_CONN_VOTER, false, 0); + return; + } + msleep(100); + wlchg_enable_tx_function(false); + schedule_delayed_work(&chip->wait_wpc_chg_quit, 0); + } else { + if (!chip->disable_charge) + wlchg_rx_set_chip_sleep(0); + msleep(20); + wlchg_rx_set_chip_en(0); + if (g_op_chip->otg_switch) { + wlchg_enable_tx_function(true); + } + if (g_op_chip->pd_charger_online) + g_op_chip->pd_charger_online = false; + vote(normal_charger->awake_votable, WIRED_CONN_VOTER, false, 0); + return; + } + + if (normal_charger != NULL) { + if (get_prop_fast_chg_started(normal_charger)) { + chg_err("wkcs: is dash on, exit\n"); + normal_charger->apsd_delayed = false; + vote(normal_charger->awake_votable, WIRED_CONN_VOTER, false, 0); + return; + } + op_handle_usb_plugin(normal_charger); + msleep(100); + smblib_apsd_enable(normal_charger, true); + smblib_rerun_apsd_if_required(normal_charger); + msleep(50); + normal_charger->apsd_delayed = false; + vote(normal_charger->awake_votable, WIRED_CONN_VOTER, false, 0); + } + return; +} + +static void wlchg_usbin_int_shedule_work(void) +{ + if (normal_charger == NULL) { + chg_err("smbchg not ready\n"); + return; + } + + if (g_rx_chip == NULL) { + chg_err("g_rx_chip not ready\n"); + return; + } + + if (typec_is_otg_mode()) { + chg_err("wkcs: is otg mode, exit\n"); + return; + } + + if (!g_op_chip) { + chg_err(" g_rx_chip is NULL\n"); + } else { + cancel_delayed_work(&g_op_chip->usbin_int_work); + if (!g_op_chip->pd_charger_online) + schedule_delayed_work(&g_op_chip->usbin_int_work, 0); + else { + chg_info("PD is in, usbin irq work func delay 1 seconds run."); + schedule_delayed_work(&g_op_chip->usbin_int_work, WLCHG_PD_HARDRESET_WAIT_TIME); + } + } + chg_err("usbin irq happened\n"); +} + +static irqreturn_t irq_usbin_event_int_handler(int irq, void *dev_id) +{ + chg_err("op-wlchg test usbin_int.\n"); + wlchg_usbin_int_shedule_work(); + return IRQ_HANDLED; +} + +static void wlchg_set_usbin_int_active(struct op_chg_chip *chip) +{ + gpio_direction_input(chip->usbin_int_gpio); // in + pinctrl_select_state(chip->pinctrl, chip->usbin_int_active); // no_PULL +} + +static void wlchg_usbin_int_irq_init(struct op_chg_chip *chip) +{ + chip->usbin_int_irq = gpio_to_irq(chip->usbin_int_gpio); + + chg_err("op-wlchg test %s chip->usbin_int_irq[%d]\n", __func__, + chip->usbin_int_irq); +} + +static int wlchg_usbin_int_eint_register(struct op_chg_chip *chip) +{ + int retval = 0; + + wlchg_set_usbin_int_active(chip); + retval = devm_request_irq(chip->dev, chip->usbin_int_irq, + irq_usbin_event_int_handler, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "wlchg_usbin_int", chip); + if (retval < 0) { + chg_err("%s request usbin_int irq failed.\n", __func__); + } + return retval; +} + +static int wlchg_usbin_int_gpio_init(struct op_chg_chip *chip) +{ + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + chg_err("get pinctrl fail\n"); + return -EINVAL; + } + + //usbin_int + chip->usbin_int_active = + pinctrl_lookup_state(chip->pinctrl, "usbin_int_active"); + if (IS_ERR_OR_NULL(chip->usbin_int_active)) { + chg_err("get usbin_int_active fail\n"); + return -EINVAL; + } + + chip->usbin_int_sleep = + pinctrl_lookup_state(chip->pinctrl, "usbin_int_sleep"); + if (IS_ERR_OR_NULL(chip->usbin_int_sleep)) { + chg_err("get usbin_int_sleep fail\n"); + return -EINVAL; + } + + chip->usbin_int_default = + pinctrl_lookup_state(chip->pinctrl, "usbin_int_default"); + if (IS_ERR_OR_NULL(chip->usbin_int_default)) { + chg_err("get usbin_int_default fail\n"); + return -EINVAL; + } + + if (chip->usbin_int_gpio > 0) { + gpio_direction_input(chip->usbin_int_gpio); + } + + pinctrl_select_state(chip->pinctrl, chip->usbin_int_active); + + return 0; +} + +int wlchg_get_usbin_val(void) +{ + struct op_chg_chip *chip = g_op_chip; + + if (chip == NULL) { + chg_err("g_op_chip not exist, return\n"); + return -ENODEV; + } + + if (chip->usbin_int_gpio <= 0) { + chg_err("usbin_int_gpio not exist, return\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->usbin_int_active) || + IS_ERR_OR_NULL(chip->usbin_int_sleep)) { + chg_err("pinctrl null, return\n"); + return -EINVAL; + } + + if (typec_is_otg_mode()) + return 0; + return gpio_get_value(chip->usbin_int_gpio); +} + +static int wlchg_wrx_en_gpio_init(struct op_chg_chip *chip) +{ + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + chg_err("get pinctrl fail\n"); + return -EINVAL; + } + + //wrx_en + chip->wrx_en_active = + pinctrl_lookup_state(chip->pinctrl, "wrx_en_active"); + if (IS_ERR_OR_NULL(chip->wrx_en_active)) { + chg_err("get wrx_en_active fail\n"); + return -EINVAL; + } + + chip->wrx_en_sleep = + pinctrl_lookup_state(chip->pinctrl, "wrx_en_sleep"); + if (IS_ERR_OR_NULL(chip->wrx_en_sleep)) { + chg_err("get wrx_en_sleep fail\n"); + return -EINVAL; + } + + chip->wrx_en_default = + pinctrl_lookup_state(chip->pinctrl, "wrx_en_default"); + if (IS_ERR_OR_NULL(chip->wrx_en_default)) { + chg_err("get wrx_en_default fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->wrx_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->wrx_en_sleep); + + chg_err("gpio_val:%d\n", gpio_get_value(chip->wrx_en_gpio)); + + return 0; +} + +void op_set_wrx_en_value(int value) +{ + struct op_chg_chip *chip = g_op_chip; + + if (!chip) { + chg_err("op_chg_chip not ready, return\n"); + return; + } + + if (chip->wrx_en_gpio <= 0) { + chg_err("idt_en_gpio not exist, return\n"); + return; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->wrx_en_active) || + IS_ERR_OR_NULL(chip->wrx_en_sleep)) { + chg_err("pinctrl null, return\n"); + return; + } + + if (value == 2) { + gpio_direction_output(chip->wrx_en_gpio, 1); + pinctrl_select_state(chip->pinctrl, chip->wrx_en_active); + } else { + //gpio_direction_output(chip->wrx_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->wrx_en_sleep); + } + chg_err("set value:%d, gpio_val:%d\n", value, + gpio_get_value(chip->wrx_en_gpio)); +} + +static int wlchg_wrx_otg_gpio_init(struct op_chg_chip *chip) +{ + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + chg_err("get pinctrl fail\n"); + return -EINVAL; + } + + //wrx_otg + chip->wrx_otg_active = + pinctrl_lookup_state(chip->pinctrl, "wrx_otg_active"); + if (IS_ERR_OR_NULL(chip->wrx_otg_active)) { + chg_err("get wrx_otg_active fail\n"); + return -EINVAL; + } + + chip->wrx_otg_sleep = + pinctrl_lookup_state(chip->pinctrl, "wrx_otg_sleep"); + if (IS_ERR_OR_NULL(chip->wrx_otg_sleep)) { + chg_err("get wrx_otg_sleep fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->wrx_otg_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->wrx_otg_sleep); + + chg_err("gpio_val:%d\n", gpio_get_value(chip->wrx_otg_gpio)); + + return 0; +} + +void op_set_wrx_otg_value(int value) +{ + struct op_chg_chip *chip = g_op_chip; + + if (!chip) { + chg_err("op_chg_chip not ready, return\n"); + return; + } + + if (chip->wrx_otg_gpio <= 0) { + chg_err("wrx_otg_gpio not exist, return\n"); + return; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->wrx_otg_active) || + IS_ERR_OR_NULL(chip->wrx_otg_sleep)) { + chg_err("pinctrl null, return\n"); + return; + } + + if (value == 1) { + gpio_direction_output(chip->wrx_otg_gpio, 1); + pinctrl_select_state(chip->pinctrl, chip->wrx_otg_active); + } else { + gpio_direction_output(chip->wrx_otg_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->wrx_otg_sleep); + } + chg_err("set value:%d, gpio_val:%d\n", value, + gpio_get_value(chip->wrx_otg_gpio)); +} + +static int wlchg_dcdc_en_gpio_init(struct op_chg_chip *chip) +{ + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + chg_err("get pinctrl fail\n"); + return -EINVAL; + } + + chip->dcdc_en_active = + pinctrl_lookup_state(chip->pinctrl, "dcdc_en_active"); + if (IS_ERR_OR_NULL(chip->dcdc_en_active)) { + chg_err("get dcdc_en_active fail\n"); + return -EINVAL; + } + + chip->dcdc_en_sleep = + pinctrl_lookup_state(chip->pinctrl, "dcdc_en_sleep"); + if (IS_ERR_OR_NULL(chip->dcdc_en_sleep)) { + chg_err("get dcdc_en_sleep fail\n"); + return -EINVAL; + } + + chip->dcdc_en_default = + pinctrl_lookup_state(chip->pinctrl, "dcdc_en_default"); + if (IS_ERR_OR_NULL(chip->dcdc_en_default)) { + chg_err("get dcdc_en_default fail\n"); + return -EINVAL; + } + + gpio_direction_output(chip->dcdc_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->dcdc_en_sleep); + + chg_err("gpio_val:%d\n", gpio_get_value(chip->dcdc_en_gpio)); + + return 0; +} + +void op_set_dcdc_en_value(int value) +{ + struct op_chg_chip *chip = g_op_chip; + + if (!chip) { + chg_err("op_chg_chip not ready, return\n"); + return; + } + + if (chip->dcdc_en_gpio <= 0) { + chg_err("dcdc_en_gpio not exist, return\n"); + return; + } + + if (IS_ERR_OR_NULL(chip->pinctrl) || + IS_ERR_OR_NULL(chip->dcdc_en_active) || + IS_ERR_OR_NULL(chip->dcdc_en_sleep)) { + chg_err("pinctrl null, return\n"); + return; + } + + if (value == 1) { + gpio_direction_output(chip->dcdc_en_gpio, 1); + pinctrl_select_state(chip->pinctrl, chip->dcdc_en_active); + } else { + gpio_direction_output(chip->dcdc_en_gpio, 0); + pinctrl_select_state(chip->pinctrl, chip->dcdc_en_sleep); + } + chg_err("set value:%d\n", value); +} + +static int wlchg_gpio_init(struct op_chg_chip *chip) +{ + int rc = 0; + struct device_node *node = chip->dev->of_node; + + if (!node) { + chg_err("device tree node missing\n"); + return -EINVAL; + } + if (!chip) { + chg_err("op_chg_chip not ready!\n"); + return -EINVAL; + } + + // Parsing gpio usbin_int + chip->usbin_int_gpio = of_get_named_gpio(node, "qcom,usbin_int-gpio", 0); + if (chip->usbin_int_gpio < 0) { + chg_err("chip->usbin_int_gpio not specified\n"); + return -EINVAL; + } else { + if (gpio_is_valid(chip->usbin_int_gpio)) { + rc = gpio_request(chip->usbin_int_gpio, "usbin-int-gpio"); + if (rc) { + chg_err("unable to request gpio [%d]\n", chip->usbin_int_gpio); + return rc; + } else { + rc = wlchg_usbin_int_gpio_init(chip); + if (rc) { + chg_err("unable to init usbin_int_gpio:%d\n", chip->usbin_int_gpio); + goto free_gpio_1; + } else { + wlchg_usbin_int_irq_init(chip); + rc = wlchg_usbin_int_eint_register(chip); + if (rc < 0) { + chg_err("Init usbin irq failed."); + goto free_gpio_1; + } + } + } + } + + chg_err("chip->usbin_int_gpio =%d\n", chip->usbin_int_gpio); + } + + // Parsing gpio wrx_en + chip->wrx_en_gpio = of_get_named_gpio(node, "qcom,wrx_en-gpio", 0); + if (chip->wrx_en_gpio < 0) { + chg_err("chip->wrx_en_gpio not specified\n"); + rc = -EINVAL; + goto free_gpio_1; + } else { + if (gpio_is_valid(chip->wrx_en_gpio)) { + rc = gpio_request(chip->wrx_en_gpio, "wrx_en-gpio"); + if (rc) { + chg_err("unable to request gpio [%d]\n", chip->wrx_en_gpio); + goto free_gpio_1; + } else { + rc = wlchg_wrx_en_gpio_init(chip); + if (rc) { + chg_err("unable to init wrx_en_gpio:%d\n", chip->wrx_en_gpio); + goto free_gpio_2; + } + } + } + + chg_err("chip->wrx_en_gpio =%d\n", chip->wrx_en_gpio); + } + + // Parsing gpio wrx_otg + chip->wrx_otg_gpio = of_get_named_gpio(node, "qcom,wrx_otg-gpio", 0); + if (chip->wrx_otg_gpio < 0) { + chg_err("chip->idt_otg_gpio not specified\n"); + rc = -EINVAL; + goto free_gpio_2; + } else { + if (gpio_is_valid(chip->wrx_otg_gpio)) { + rc = gpio_request(chip->wrx_otg_gpio, "wrx_otg-gpio"); + if (rc) { + chg_err("unable to request gpio [%d]\n", chip->wrx_otg_gpio); + goto free_gpio_2; + } else { + rc = wlchg_wrx_otg_gpio_init(chip); + if (rc) { + chg_err("unable to init wrx_otg_gpio:%d\n", chip->wrx_otg_gpio); + goto free_gpio_3; + } + } + } + + chg_err("chip->wrx_otg_gpio =%d\n", chip->wrx_otg_gpio); + } + + if (chip->ap_ctrl_dcdc) { + // Parsing gpio dcdc_en + chip->dcdc_en_gpio = of_get_named_gpio(node, "qcom,dcdc_en-gpio", 0); + if (chip->dcdc_en_gpio < 0) { + chg_err("chip->dcdc_en_gpio not specified\n"); + rc = -EINVAL; + goto free_gpio_3; + } else { + if (gpio_is_valid(chip->dcdc_en_gpio)) { + rc = gpio_request(chip->dcdc_en_gpio, "dcdc_en-gpio"); + if (rc) { + chg_err("unable to request gpio [%d]\n", chip->dcdc_en_gpio); + goto free_gpio_3; + } else { + rc = wlchg_dcdc_en_gpio_init(chip); + if (rc) { + chg_err("unable to init dcdc_en_gpio:%d\n", chip->dcdc_en_gpio); + goto free_gpio_4; + } + } + } + chg_err("chip->dcdc_en_gpio =%d\n", chip->dcdc_en_gpio); + } + } + + return 0; + +free_gpio_4: + if (gpio_is_valid(chip->dcdc_en_gpio)) + gpio_free(chip->dcdc_en_gpio); +free_gpio_3: + if (gpio_is_valid(chip->wrx_otg_gpio)) + gpio_free(chip->wrx_otg_gpio); +free_gpio_2: + if (gpio_is_valid(chip->wrx_en_gpio)) + gpio_free(chip->wrx_en_gpio); +free_gpio_1: + if (gpio_is_valid(chip->usbin_int_gpio)) + gpio_free(chip->usbin_int_gpio); + return rc; +} + +static void op_wait_wpc_chg_quit_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, wait_wpc_chg_quit); + + int level; + int wpc_con_level = 0; + + level = wlchg_get_usbin_val(); + //printk(KERN_ERR "[OP_CHG][%s]: op-wlchg test wired_connect level[%d]\n", __func__, level); + if (level == 1) { + wpc_con_level = wlchg_rx_get_chip_con(); + printk(KERN_ERR + "[OP_CHG][%s]: op-wlchg test wpc_connect level[%d]\n", + __func__, wpc_con_level); + if (wpc_con_level == 0 || wpc_chg_quit_max_cnt >= 5) { + chargepump_disable(); + } else { + schedule_delayed_work(&chip->wait_wpc_chg_quit, + msecs_to_jiffies(500)); + wpc_chg_quit_max_cnt++; + } + } + return; +} + +static void op_check_wireless_ovp(struct op_chg_chip *chip) +{ + static int ov_count, nov_count; + int detect_time = 10; /* 10 x (100 or 500)ms = (1 or 5)s */ + struct wpc_data *chg_status = &chip->wlchg_status; + + if (chg_status->ftm_mode) + return; + + if (!chg_status->rx_ovp) { + if ((g_rx_chip->chg_data.vout > RX_FAST_SOFT_OVP_MV) || + (!(chg_status->charge_type == WPC_CHARGE_TYPE_FAST && + (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH || + chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP)) && + g_rx_chip->chg_data.vout > RX_EPP_SOFT_OVP_MV)) { + ov_count++; + chg_err("Rx vout is over voltage, ov_count=%d\n", ov_count); + if (detect_time <= ov_count) { + /* vchg continuous higher than safety */ + chg_err("charger is over voltage, stop charging\n"); + ov_count = 0; + chg_status->rx_ovp = true; + if (normal_charger != NULL) + normal_charger->chg_ovp = true; + } + if (nov_count != 0) + nov_count = 0; + } + } else { + if (g_rx_chip->chg_data.vout < RX_EPP_SOFT_OVP_MV - 100) { + nov_count++; + chg_err("Rx vout is back to ok, nov_count=%d\n", nov_count); + if (detect_time <= nov_count) { + chg_err("charger is normal.\n"); + nov_count = 0; + chg_status->rx_ovp = false; + if (normal_charger != NULL) + normal_charger->chg_ovp = false; + } + if (ov_count != 0) + ov_count = 0; + } + } +} + +static void wlchg_task_work_process(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, wlchg_task_work); + struct wpc_data *chg_status = &chip->wlchg_status; + + if (g_rx_chip == NULL) { + chg_err("rx chip is not ready\n"); + return; + } + + pr_debug("op-wlchg test charge_online[%d]\n", chg_status->charge_online); + + if (chg_status->charge_online) { +#ifdef IDT_LAB_TEST + if (wlchg_rx_get_run_mode(g_rx_chip) == RX_RUNNING_MODE_OTHERS) +#else + if (wlchg_rx_get_run_mode(g_rx_chip) != RX_RUNNING_MODE_EPP) +#endif + wlchg_cmd_process(chip); // func * + + /* wlchg server watchdog*/ + if (atomic_read(&chip->hb_count) > 0) { + atomic_dec(&chip->hb_count); + } else { + if (chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_DASH || + chg_status->adapter_type == ADAPTER_TYPE_FASTCHAGE_WARP) { + chip->heart_stop = true; + chg_err("wlchg service stops running and exits fast charging\n"); + wlchg_rx_set_chip_sleep(1); + return; + } + } + wlchg_send_msg(WLCHG_MSG_HEARTBEAT, 0, 0); //heartbeat packet + + op_check_battery_temp(chip); + mutex_lock(&chip->chg_lock); + wlchg_rx_get_vrect_iout(g_rx_chip); + fastchg_curr_filter(chip); + mutex_unlock(&chip->chg_lock); + op_check_wireless_ovp(chip); + wlchg_charge_status_process(chip); + + if (chg_status->charge_online) { + /* run again after interval */ + if ((chg_status->temp_region == WLCHG_BATT_TEMP_COLD || + chg_status->temp_region == WLCHG_BATT_TEMP_HOT) && + chg_status->charge_current == 0) { + schedule_delayed_work(&chip->wlchg_task_work, msecs_to_jiffies(5000)); + } else { + if (chg_status->startup_fast_chg) + schedule_delayed_work(&chip->wlchg_task_work, + msecs_to_jiffies(100)); + else + schedule_delayed_work(&chip->wlchg_task_work, + WLCHG_TASK_INTERVAL); + } + } + } +} + +#define RX_VOL_MAX 20000 +#define VOL_ADJUST_MAX 150 +#define IBAT_MAX_MA 6000 +static void curr_vol_check_process(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, fastchg_curr_vol_work); + struct wpc_data *chg_status = &chip->wlchg_status; + struct charge_param *chg_param = &chip->chg_param; + static bool wait_cep; + static int cep_err_count; + bool skip_cep_check = false; + int tmp_val; + int ibat_err; + int ibat_max; + int cep_flag; + + if (!chg_status->charge_online) + return; + if ((g_rx_chip != NULL) && (chg_status->adapter_type == ADAPTER_TYPE_UNKNOWN)) + return; + + mutex_lock(&chip->chg_lock); + wlchg_rx_get_vrect_iout(g_rx_chip); + fastchg_curr_filter(chip); + + if (chg_status->curr_limit_mode) { + if (chg_status->temp_region == WLCHG_BATT_TEMP_NORMAL) + ibat_max = chg_param->fastchg_ibatmax[1]; + else + ibat_max = chg_param->fastchg_ibatmax[0]; + + chg_info("Iout: target=%d, out=%d, ibat_max=%d, ibat=%d\n", + chg_status->target_curr, g_rx_chip->chg_data.iout, + ibat_max, chip->icharging); + + tmp_val = chg_status->target_curr - g_rx_chip->chg_data.iout; + ibat_err = ((ibat_max - abs(chip->icharging)) / 4) - (CURR_ERR_MIN / 2); + /* Prevent the voltage from increasing too much, ibat exceeds expectations */ + if ((ibat_err > -(CURR_ERR_MIN / 2)) && (ibat_err < 0) && (tmp_val > 0)) { + /* + * When ibat is greater than 5800mA, the current is not + * allowed to continue to increase, preventing fluctuations. + */ + tmp_val = 0; + } else { + tmp_val = tmp_val > ibat_err ? ibat_err : tmp_val; + } + cep_flag = wlchg_rx_get_cep_flag(g_rx_chip); + if (tmp_val < 0) { + if (cep_flag != 0) + cep_err_count++; + else + cep_err_count = 0; + if (!chg_status->curr_need_dec || cep_err_count >= CEP_ERR_MAX) { + skip_cep_check = true; + chg_status->curr_need_dec = true; + cep_err_count = 0; + } + } else { + cep_err_count = 0; + chg_status->curr_need_dec = false; + } + if (cep_flag == 0 || skip_cep_check) { + if (tmp_val > 0 || tmp_val < -CURR_ERR_MIN) { + if (tmp_val > 0) { + if (tmp_val > 200) + chg_status->vol_set += 200; + else if (tmp_val > 50) + chg_status->vol_set += 100; + else + chg_status->vol_set += 20; + } else { + if (tmp_val < -200) + chg_status->vol_set -= 200; + else if (tmp_val < -50) + chg_status->vol_set -= 100; + else + chg_status->vol_set -= 20; + } + if (chg_status->vol_set > RX_VOLTAGE_MAX) + chg_status->vol_set = RX_VOLTAGE_MAX; + if (chg_status->charge_type == WPC_CHARGE_TYPE_FAST) { + if (chg_status->vol_set < FASTCHG_MODE_VOL_MIN) { + chg_status->vol_set = FASTCHG_MODE_VOL_MIN; + } + } else { + if (chg_status->vol_set < NORMAL_MODE_VOL_MIN) { + chg_status->vol_set = NORMAL_MODE_VOL_MIN; + } + } + wlchg_rx_set_vout(g_rx_chip, chg_status->vol_set); + wait_cep = false; + } + } + } else { + if (!chg_status->vol_set_ok) { + chg_err("Vout: target=%d, set=%d, out=%d\n", chg_status->target_vol, + chg_status->vol_set, g_rx_chip->chg_data.vout); + if (chg_status->vol_set_start) { + if (!chg_status->vol_set_fast) + chg_status->vol_set = g_rx_chip->chg_data.vout; + else + chg_status->vol_set_fast = false; + chg_status->vol_set_start = false; + /* + * Refresh the CEP status to ensure that the CEP + * obtained next time is updated. + */ + (void)wlchg_rx_get_cep_flag(g_rx_chip); + wait_cep = false; + } + if (wait_cep) { + if (wlchg_rx_get_cep_flag(g_rx_chip) == 0) { + wait_cep = false; + if (chg_status->target_vol == chg_status->vol_set) { + chg_status->vol_set_ok = true; + mutex_unlock(&chip->chg_lock); + return; + } + } + } else { + if (chg_status->target_vol > chg_status->vol_set) { + tmp_val = chg_status->target_vol - chg_status->vol_set; + if (tmp_val > VOL_INC_STEP_MAX && chg_status->target_vol > VOL_ADJ_LIMIT) { + if (chg_status->vol_set < VOL_ADJ_LIMIT) { + chg_status->vol_set = VOL_ADJ_LIMIT; + } else { + chg_status->vol_set += VOL_INC_STEP_MAX; + } + } else { + chg_status->vol_set += tmp_val; + } + } else if (chg_status->target_vol < chg_status->vol_set) { + if (chg_status->vol_not_step) { + chg_status->vol_set = chg_status->target_vol; + chg_status->vol_not_step = false; + } else { + tmp_val = chg_status->vol_set - chg_status->target_vol; + tmp_val = tmp_val < VOL_DEC_STEP_MAX ? tmp_val : VOL_DEC_STEP_MAX; + chg_status->vol_set -= tmp_val; + } + } + wlchg_rx_set_vout(g_rx_chip, chg_status->vol_set); + wait_cep = true; + } + } else { + mutex_unlock(&chip->chg_lock); + return; + } + } + mutex_unlock(&chip->chg_lock); + + if (chg_status->charge_online) { + if (chg_status->curr_limit_mode) + schedule_delayed_work(&chip->fastchg_curr_vol_work, + msecs_to_jiffies(500)); + else + schedule_delayed_work(&chip->fastchg_curr_vol_work, + msecs_to_jiffies(100)); + } +} + +static void wlchg_tx_check_process(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, tx_check_work); + + if (chip->wireless_mode == WIRELESS_MODE_TX) { + if (chip->wlchg_status.dock_on) { + chg_err("wireless charger dock detected, exit reverse charge\n"); + chip->wlchg_status.wpc_dischg_status = WPC_DISCHG_STATUS_OFF; + } + chg_info("<~WPC~>rtx func wpc_dischg_status[%d]\n", + chip->wlchg_status.wpc_dischg_status); + + if (chip->wlchg_status.wpc_dischg_status == WPC_DISCHG_STATUS_OFF) { + g_op_chip->otg_switch = false; + wlchg_enable_tx_function(false); + } + schedule_delayed_work(&chip->tx_check_work, msecs_to_jiffies(500)); + } else { + chg_err("<~WPC~ wireless mode is %d, not TX, exit.", chip->wireless_mode); + } +} + +static void wlchg_check_charge_timeout(struct op_chg_chip *chip) +{ + if (chip == NULL) { + chg_err("op_chg_chip not ready."); + return; + } + if (normal_charger == NULL) { + chg_err("smb charger is not ready."); + return; + } + + if (chip->wlchg_status.ftm_mode) { + chg_info("It's ftm mode, return."); + return; + } + if (wlchg_check_charge_done(chip)) { + chg_info("battery is full, return."); + return; + } + if (chip->disable_batt_charge) { + chg_info("wireless charge is disabled, reset count and return."); + chip->wlchg_time_count = 0; + return; + } + + if (chip->wlchg_status.charge_online) + chip->wlchg_time_count++; + + if (chip->wlchg_time_count >= WLCHG_CHARGE_TIMEOUT) { + chg_info("wlchg timeout! stop chaging now.\n"); + wlchg_disable_batt_charge(chip, true); + normal_charger->time_out = true; + } +} + +static void exfg_update_batinfo(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, update_bat_info_work); + + if (chip->wlchg_status.charge_online && g_op_chip && + exfg_instance) { + g_op_chip->batt_volt = + exfg_instance->get_battery_mvolts() / 1000; + g_op_chip->icharging = + exfg_instance->get_average_current() / 1000; +#ifdef HW_TEST_EDITION + if (chip->w30w_timeout) { + g_op_chip->temperature = 320; //for test. + } else { + g_op_chip->temperature = 280; //for test. + } +#else + g_op_chip->temperature = + exfg_instance->get_battery_temperature(); +#endif + g_op_chip->soc = exfg_instance->get_battery_soc(); + g_op_chip->batt_missing = !exfg_instance->is_battery_present(); + chg_err("battery info: v=%d, i=%d, t=%d, soc=%d.", + g_op_chip->batt_volt, g_op_chip->icharging, + g_op_chip->temperature, g_op_chip->soc); + wlchg_check_charge_timeout(chip); + } + /* run again after interval */ + if (chip && chip->wlchg_status.charge_online) { + schedule_delayed_work(&chip->update_bat_info_work, + WLCHG_BATINFO_UPDATE_INTERVAL); + } +} +int register_reverse_charge_notifier(struct notifier_block *nb) +{ + if (!nb) + return -EINVAL; + + return blocking_notifier_chain_register(&reverse_charge_chain, nb); +} +EXPORT_SYMBOL(register_reverse_charge_notifier); + + +int unregister_reverse_charge_notifier(struct notifier_block *nb) +{ + if (!nb) + return -EINVAL; + + return blocking_notifier_chain_unregister(&reverse_charge_chain, nb); +} +EXPORT_SYMBOL(unregister_reverse_charge_notifier); + + +static int reverse_charge_notifier_call_chain(unsigned long val) +{ + return blocking_notifier_call_chain(&reverse_charge_chain, val, NULL); +} + +#ifdef HW_TEST_EDITION +static void w30w_timeout_work_process(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, w30w_timeout_work); + chip->w30w_timeout = true; +} +#endif + +static void wlchg_charger_offline(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct op_chg_chip *chip = + container_of(dwork, struct op_chg_chip, charger_exit_work); + if (wlchg_rx_get_chip_con() == 0) { + chg_err("report wlchg offline."); + chip->wlchg_status.fastchg_display_delay = false; + chip->charger_exist = false; + if (chip->wireless_psy != NULL) + power_supply_changed(chip->wireless_psy); + + + /* Waiting for frameworks liting on display. To avoid*/ + /* enter deep sleep(can't lit on) once relax wake_lock.*/ + msleep(100); + // check connect status again, make sure not recharge. + if (wlchg_rx_get_chip_con() == 0) { + if (chip->wlchg_wake_lock_on) { + chg_info("release wlchg_wake_lock\n"); + __pm_relax(chip->wlchg_wake_lock); + chip->wlchg_wake_lock_on = false; + } else { + chg_err("wlchg_wake_lock is already relax\n"); + } + } + } +} + +#ifdef OP_DEBUG +static ssize_t proc_wireless_voltage_rect_read(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + uint8_t ret = 0; + char page[10]; + int vrect = 0; + struct op_chg_chip *chip = g_op_chip; + + if (chip == NULL) { + chg_err("rx_chip not exist, return\n"); + return -ENODEV; + } + + if (atomic_read(&chip->suspended) == 1) { + return 0; + } + + vrect = g_rx_chip->chg_data.vrect; + + chg_err("%s: vrect = %d.\n", __func__, vrect); + snprintf(page, 10, "%d", vrect); + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_wireless_voltage_rect_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + return count; +} + +static const struct file_operations proc_wireless_voltage_rect_ops = { + .read = proc_wireless_voltage_rect_read, + .write = proc_wireless_voltage_rect_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_wireless_rx_voltage_read(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + char vol_string[8]; + int len = 0; + snprintf(vol_string, 8, "%d\n", + g_op_chip->wlchg_status.charge_voltage); + len = simple_read_from_buffer(buf, count, ppos, vol_string, strlen(vol_string)); + return len; +} +static ssize_t proc_wireless_rx_voltage_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + char vol_string[8] = {0}; + int vol = 0; + int len = count < 8 ? count : 8; + + if (g_op_chip == NULL) { + chg_err("%s: g_op_chip is not ready\n", __func__); + return -ENODEV; + } + + copy_from_user(vol_string, buf, len); + kstrtoint(vol_string, 0, &vol); + chg_err("set voltage: vol_string = %s, vol = %d.", vol_string, vol); + wlchg_set_rx_target_voltage(g_op_chip, vol); + return count; +} + +static const struct file_operations proc_wireless_rx_voltage = { + .read = proc_wireless_rx_voltage_read, + .write = proc_wireless_rx_voltage_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_wireless_current_out_read(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + uint8_t ret = 0; + char page[10]; + int iout = 0; + struct op_chg_chip *chip = g_op_chip; + + if ((chip == NULL) || (g_rx_chip == NULL)) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + if (atomic_read(&chip->suspended) == 1) { + return 0; + } + + iout = g_rx_chip->chg_data.iout; + + chg_err("%s: iout = %d.\n", __func__, iout); + snprintf(page, 10, "%d", iout); + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_wireless_current_out_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + char curr_string[8] = {0}; + int curr = 0; + int len = count < 8 ? count : 8; + + if (g_op_chip == NULL) { + chg_err("%s: g_op_chip is not ready\n", __func__); + return -ENODEV; + } + + copy_from_user(curr_string, buf, len); + kstrtoint(curr_string, 0, &curr); + chg_err("set current: curr_string = %s, curr = %d.", curr_string, curr); + if (curr >= 0 && curr <= 1500) { + vote(g_op_chip->wlcs_fcc_votable, MAX_VOTER, true, curr * 1000); + if (!(g_op_chip->wlchg_status.curr_limit_mode)) + fastchg_curr_control_en(g_op_chip, true); + } else { + chg_err("The target current should in (0,1500), not match."); + } + return count; +} + +static const struct file_operations proc_wireless_current_out_ops = { + .read = proc_wireless_current_out_read, + .write = proc_wireless_current_out_write, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif + +static ssize_t proc_wireless_ftm_mode_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[8]; + struct op_chg_chip *chip = g_op_chip; + ssize_t len; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + + memset(page, 0, 8); + if (chip->wlchg_status.ftm_mode) { + len = 7; + snprintf(page, len, "enable\n"); + } else { + len = 8; + snprintf(page, len, "disable\n"); + } + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static ssize_t proc_wireless_ftm_mode_write(struct file *file, + const char __user *buf, size_t len, + loff_t *lo) +{ + char buffer[5] = { 0 }; + int val; + + chg_err("%s: len[%d] start.\n", __func__, len); + if (len > 5) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, len)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + + chg_err("buffer=%s", buffer); + kstrtoint(buffer, 0, &val); + chg_err("val = %d", val); + + if (val == 1) { + chg_err("%s:ftm_mode enable\n", __func__); + wlchg_enable_ftm(true); + } else { + chg_err("%s:ftm_mode disable\n", __func__); + wlchg_enable_ftm(false); + } + chg_err("%s: end.\n", __func__); + + return len; +} + +static const struct file_operations proc_wireless_ftm_mode_ops = { + .read = proc_wireless_ftm_mode_read, + .write = proc_wireless_ftm_mode_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_wireless_tx_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[10]; + struct op_chg_chip *chip = g_op_chip; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return -ENODEV; + } + + if (chip->wireless_mode == WIRELESS_MODE_TX) { + if (chip->wlchg_status.tx_online) + snprintf(page, 10, "%s\n", "charging"); + else + snprintf(page, 10, "%s\n", "enable"); + } else + snprintf(page, 10, "%s\n", "disable"); + + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_wireless_tx_write(struct file *file, const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[5] = { 0 }; + struct op_chg_chip *chip = g_op_chip; + int val; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return -ENODEV; + } + + if (g_rx_chip == NULL) { + chg_err("%s: rx chip is not ready\n", __func__); + return -ENODEV; + } + + if (count > 5) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + + chg_err("buffer=%s", buffer); + kstrtoint(buffer, 0, &val); + chg_err("val = %d", val); + + if (val == 1) { + if (chip->wireless_mode == WIRELESS_MODE_NULL) { + if (wlchg_get_usbin_val() == 1) { + chg_err("USB cable is in, don't allow enter otg wireless charge."); + return -EFAULT; + } + if (wlchg_rx_fw_updating(g_rx_chip)) { + chg_err("<~WPC~> FW is updating, return!\n"); + return -EFAULT; + } + wlchg_reset_variables(chip); + wlchg_enable_tx_function(true); + } else { + return -EFAULT; + } + } else { + if (chip->wireless_mode == WIRELESS_MODE_TX) { + wlchg_enable_tx_function(false); + wlchg_reset_variables(chip); + } else { + return -EFAULT; + } + } + + return count; +} + +static const struct file_operations proc_wireless_tx_ops = { + .read = proc_wireless_tx_read, + .write = proc_wireless_tx_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_wireless_quiet_mode_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[7]; + int len = 0; + struct op_chg_chip *chip = g_op_chip; + struct wpc_data *chg_status; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return -ENODEV; + } + + chg_status = &chip->wlchg_status; + len = snprintf(page, 7, "%s\n", + (chg_status->quiet_mode_enabled && chip->quiet_mode_need) ? "true" : "false"); + ret = simple_read_from_buffer(buf, count, ppos, page, len); + return ret; +} + +static ssize_t proc_wireless_quiet_mode_write(struct file *file, const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[3] = { 0 }; + struct op_chg_chip *chip = g_op_chip; + int val; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return -ENODEV; + } + + if (count > 3) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + + chg_err("buffer=%s", buffer); + kstrtoint(buffer, 0, &val); + chg_err("val = %d", val); + chip->quiet_mode_need = (val == 1) ? true : false; + return count; +} + +static const struct file_operations proc_wireless_quiet_mode_ops = { + .read = proc_wireless_quiet_mode_read, + .write = proc_wireless_quiet_mode_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +#ifdef OP_DEBUG +static ssize_t proc_wireless_epp_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[6]; + struct op_chg_chip *chip = g_op_chip; + size_t len = 6; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + + memset(page, 0, 6); + if (force_epp) { + len = snprintf(page, len, "epp\n"); + } else if (force_bpp) { + len = snprintf(page, len, "bpp\n"); + } else if (!auto_mode) { + len = snprintf(page, len, "manu\n"); + } else { + len = snprintf(page, len, "auto\n"); + } + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static ssize_t proc_wireless_epp_write(struct file *file, + const char __user *buf, size_t count, + loff_t *lo) +{ + char buffer[5] = { 0 }; + int val = 0; + + chg_err("%s: len[%d] start.\n", __func__, count); + if (count > 5) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + chg_err("buffer=%s", buffer); + kstrtoint(buffer, 0, &val); + chg_err("val=%d", val); + if (val == 1) { + force_bpp = true; + force_epp = false; + auto_mode = true; + } else if (val == 2) { + force_bpp = false; + force_epp = true; + auto_mode = true; + } else if (val == 3) { + force_bpp = false; + force_epp = false; + auto_mode = false; + } else { + force_bpp = false; + force_epp = false; + auto_mode = true; + } + return count; +} + +static const struct file_operations proc_wireless_epp_ops = { + .read = proc_wireless_epp_read, + .write = proc_wireless_epp_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_wireless_charge_pump_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[6]; + struct op_chg_chip *chip = g_op_chip; + size_t len = 6; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + + memset(page, 0, 6); + len = snprintf(page, len, "%d\n", proc_charge_pump_status); + ret = simple_read_from_buffer(buf, count, ppos, page, len); + return ret; +} + +static ssize_t proc_wireless_charge_pump_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[2] = { 0 }; + int val = 0; + + chg_err("%s: len[%d] start.\n", __func__, count); + if (count > 2) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + chg_err("buffer=%s", buffer); + val = buffer[0] - '0'; + chg_err("val=%d", val); + if (val < 0 || val > 6) { + return -EINVAL; + } + switch (val) { + case 0: + chg_err("wkcs: disable all charge pump\n"); + chargepump_disable(); + bq2597x_enable_charge_pump(false); + break; + case 1: + chg_err("wkcs: disable charge pump 1\n"); + chargepump_disable(); + break; + case 2: + chg_err("wkcs: enable charge pump 1\n"); + chargepump_hw_init(); //enable chargepump + chargepump_enable(); + chargepump_set_for_LDO(); + break; + case 3: + chg_err("wkcs: disable charge pump 2\n"); + bq2597x_enable_charge_pump(false); + break; + case 4: + chg_err("wkcs: enable charge pump 2\n"); + bq2597x_enable_charge_pump(true); + break; + case 5: + wlchg_set_rx_charge_current(g_op_chip, 0); + pmic_high_vol_en(g_op_chip, false); + break; + case 6: + pmic_high_vol_en(g_op_chip, true); + wlchg_set_rx_charge_current(g_op_chip, 300); + break; + default: + chg_err("wkcs: invalid value."); + break; + } + proc_charge_pump_status = val; + return count; +} + +static const struct file_operations proc_wireless_charge_pump_ops = { + .read = proc_wireless_charge_pump_read, + .write = proc_wireless_charge_pump_write, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif + +static ssize_t proc_wireless_deviated_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[7]; + struct op_chg_chip *chip = g_op_chip; + size_t len = 7; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + + memset(page, 0, 7); + if (chip->wlchg_status.is_deviation) { + len = snprintf(page, len, "%s\n", "true"); + } else { + len = snprintf(page, len, "%s\n", "false"); + } + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static const struct file_operations proc_wireless_deviated_ops = { + .read = proc_wireless_deviated_read, + .write = NULL, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_wireless_rx_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[3]; + + if (g_op_chip == NULL) { + chg_err("<~WPC~> g_rx_chip is NULL!\n"); + return -ENODEV; + } + + + memset(page, 0, 3); + snprintf(page, 3, "%c\n", !g_op_chip->disable_charge ? '1' : '0'); + ret = simple_read_from_buffer(buf, count, ppos, page, 3); + + return ret; +} + +static ssize_t proc_wireless_rx_write(struct file *file, const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[5] = { 0 }; + struct op_chg_chip *chip = g_op_chip; + int val; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return -ENODEV; + } + + if (count > 5) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + + chg_err("buffer=%s", buffer); + kstrtoint(buffer, 0, &val); + chg_err("val = %d", val); + + if (val == 0) { + chip->disable_charge = true; + wlchg_rx_set_chip_sleep(1); + } else { + chip->disable_charge = false; + wlchg_rx_set_chip_sleep(0); + } + + return count; +} + +static const struct file_operations proc_wireless_rx_ops = { + .read = proc_wireless_rx_read, + .write = proc_wireless_rx_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_fast_skin_threld_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[16]; + int len = 16; + + if (g_op_chip == NULL) { + chg_err("<~WPC~> g_rx_chip is NULL!\n"); + return -ENODEV; + } + + + memset(page, 0, len); + len = snprintf(page, len, "Hi:%d,Lo:%d\n", + g_op_chip->chg_param.fastchg_skin_temp_max, + g_op_chip->chg_param.fastchg_skin_temp_min); + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static ssize_t proc_fast_skin_threld_write(struct file *file, const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[16] = { 0 }; + struct op_chg_chip *chip = g_op_chip; + int hi_val, lo_val; + int ret = 0; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return -ENODEV; + } + + if (count > 16) { + chg_err("input too many words."); + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + + chg_err("buffer=%s", buffer); + ret = sscanf(buffer, "%d %d", &hi_val, &lo_val); + chg_err("hi_val=%d, lo_val=%d", hi_val, lo_val); + + if (ret == 2) { + if (hi_val > lo_val) { + chip->chg_param.fastchg_skin_temp_max = hi_val; + chip->chg_param.fastchg_skin_temp_min = lo_val; + } else { + chg_err("hi_val not bigger than lo_val"); + return -EINVAL; + } + } else { + chg_err("need two decimal number."); + return -EINVAL; + } + + return count; +} + +static const struct file_operations proc_fast_skin_threld_ops = { + .read = proc_fast_skin_threld_read, + .write = proc_fast_skin_threld_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +#ifdef OP_DEBUG +static ssize_t proc_wireless_rx_freq_read(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + char string[8]; + int len = 0; + int rc; + struct charge_param *chg_param; + + if (g_op_chip == NULL) { + chg_err("wlchg driver is not ready\n"); + return -ENODEV; + } + chg_param = &g_op_chip->chg_param; + + memset(string, 0, 8); + + len = snprintf(string, 8, "%d\n", chg_param->freq_threshold); + rc = simple_read_from_buffer(buf, count, ppos, string, len); + return rc; +} +static ssize_t proc_wireless_rx_freq_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + char string[16]; + int freq = 0; + struct charge_param *chg_param; + + if (g_op_chip == NULL) { + chg_err("wlchg driver is not ready\n"); + return -ENODEV; + } + chg_param = &g_op_chip->chg_param; + + memset(string, 0, 16); + copy_from_user(string, buf, count); + chg_info("buf = %s, len = %d\n", string, count); + kstrtoint(string, 0, &freq); + chg_info("set freq threshold to %d\n", freq); + chg_param->freq_threshold = freq; + return count; +} + +static const struct file_operations proc_wireless_rx_freq_ops = { + .read = proc_wireless_rx_freq_read, + .write = proc_wireless_rx_freq_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_match_q_read(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + char string[8]; + int len = 0; + int rc; + struct charge_param *chg_param; + + if (g_op_chip == NULL) { + chg_err("wlchg driver is not ready\n"); + return -ENODEV; + } + chg_param = &g_op_chip->chg_param; + + memset(string, 0, 8); + + len = snprintf(string, 8, "%d\n", chg_param->fastchg_match_q); + rc = simple_read_from_buffer(buf, count, ppos, string, len); + return rc; +} +static ssize_t proc_match_q_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + char string[16]; + int match_q = 0; + struct charge_param *chg_param; + + if (g_op_chip == NULL) { + chg_err("wlchg driver is not ready\n"); + return -ENODEV; + } + chg_param = &g_op_chip->chg_param; + + memset(string, 0, 16); + copy_from_user(string, buf, count); + chg_info("buf = %s, len = %d\n", string, count); + kstrtoint(string, 0, &match_q); + chg_info("set match q to %d\n", match_q); + chg_param->fastchg_match_q = match_q; + return count; +} + +static const struct file_operations proc_match_q_ops = { + .read = proc_match_q_read, + .write = proc_match_q_write, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif + +static ssize_t proc_wireless_ftm_test_read(struct file *file, + char __user *buf, size_t count, + loff_t *ppos) +{ + char string[2] = {0, 0}; + int rc; + int err_no = 0; + + if (g_rx_chip == NULL) { + chg_err("[FTM_TEST]rc chip driver is not ready\n"); + return -ENODEV; + } + if (exchgpump_bq == NULL) { + chg_err("[FTM_TEST]bq2597x driver is not ready\n"); + err_no |= WLCHG_FTM_TEST_CP2_ERR; + } + + rc = wlchg_rx_ftm_test(g_rx_chip); + if (rc < 0) + return rc; + else if (rc > 0) + err_no |= rc; + rc = bq2597x_ftm_test(exchgpump_bq); + if (rc < 0) + return rc; + else if (rc > 0) + err_no |= WLCHG_FTM_TEST_CP2_ERR; + + snprintf(string, 2, "%d\n", err_no); + rc = simple_read_from_buffer(buf, count, ppos, string, 2); + + return rc; +} + +static const struct file_operations proc_wireless_ftm_test_ops = { + .read = proc_wireless_ftm_test_read, + .write = NULL, + .open = simple_open, + .owner = THIS_MODULE, +}; + +#ifdef HW_TEST_EDITION +static ssize_t proc_wireless_w30w_time_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + uint8_t ret = 0; + char page[32]; + struct op_chg_chip *chip = g_op_chip; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + + snprintf(page, 32, "w30w_time:%d minutes\n", chip->w30w_time); + ret = simple_read_from_buffer(buf, count, ppos, page, strlen(page)); + + return ret; +} + +static ssize_t proc_wireless_w30w_time_write(struct file *file, + const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[4] = { 0 }; + int timeminutes = 0; + struct op_chg_chip *chip = g_op_chip; + + if (chip == NULL) { + chg_err("%s: wlchg driver is not ready\n", __func__); + return 0; + } + + chg_err("%s: len[%d] start.\n", __func__, count); + if (count > 3) { + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + chg_err("%s: error.\n", __func__); + return -EFAULT; + } + chg_err("buffer=%s", buffer); + kstrtoint(buffer, 0, &timeminutes); + chg_err("set w30w_time = %dm", timeminutes); + if (timeminutes >= 0 && timeminutes <= 60) + chip->w30w_time = timeminutes; + chip->w30w_work_started = false; + chip->w30w_timeout = false; + return count; +} + +static const struct file_operations proc_wireless_w30w_time_ops = { + .read = proc_wireless_w30w_time_read, + .write = proc_wireless_w30w_time_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +#endif + +static int init_wireless_charge_proc(struct op_chg_chip *chip) +{ + int ret = 0; + struct proc_dir_entry *prEntry_da = NULL; + struct proc_dir_entry *prEntry_tmp = NULL; + + prEntry_da = proc_mkdir("wireless", NULL); + if (prEntry_da == NULL) { + chg_err("%s: Couldn't create wireless proc entry\n", + __func__); + return -ENOMEM; + } + + prEntry_tmp = proc_create_data("ftm_mode", 0664, prEntry_da, + &proc_wireless_ftm_mode_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("enable_tx", 0664, prEntry_da, + &proc_wireless_tx_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("quiet_mode", 0664, prEntry_da, + &proc_wireless_quiet_mode_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("deviated", 0664, prEntry_da, + &proc_wireless_deviated_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("enable_rx", 0664, prEntry_da, + &proc_wireless_rx_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("fast_skin_threld", 0664, prEntry_da, + &proc_fast_skin_threld_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc fast_skin_threld, %d\n", + __func__, __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("ftm_test", 0664, prEntry_da, + &proc_wireless_ftm_test_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + +#ifdef OP_DEBUG + prEntry_tmp = proc_create_data("voltage_rect", 0664, prEntry_da, + &proc_wireless_voltage_rect_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("rx_voltage", 0664, prEntry_da, + &proc_wireless_rx_voltage, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("current_out", 0664, prEntry_da, + &proc_wireless_current_out_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("epp_or_bpp", 0664, prEntry_da, + &proc_wireless_epp_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("charge_pump_en", 0664, prEntry_da, + &proc_wireless_charge_pump_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("rx_freq", 0664, prEntry_da, + &proc_wireless_rx_freq_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } + + prEntry_tmp = proc_create_data("match_q", 0664, prEntry_da, + &proc_match_q_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } +#endif + +#ifdef HW_TEST_EDITION + prEntry_tmp = proc_create_data("w30w_time", 0664, prEntry_da, + &proc_wireless_w30w_time_ops, chip); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + chg_err("%s: Couldn't create proc entry, %d\n", __func__, + __LINE__); + goto fail; + } +#endif + return 0; + +fail: + remove_proc_entry("wireless", NULL); + return ret; +} + +static int wlchg_driver_probe(struct platform_device *pdev) +{ + struct op_chg_chip *chip; + int ret = 0; + int boot_mode = 0; + + chg_debug(" call \n"); + + chip = devm_kzalloc(&pdev->dev, sizeof(struct op_chg_chip), + GFP_KERNEL); + if (!chip) { + chg_err(" g_op_chg chip is null, probe again \n"); + return -ENOMEM; + } + + chip->dev = &pdev->dev; + + chip->ap_ctrl_dcdc = of_property_read_bool(chip->dev->of_node, "op-ap_control_dcdc"); + chg_info("%s control dcdc\n", chip->ap_ctrl_dcdc ? "AP" : "RX"); + + ret = wlchg_gpio_init(chip); + if (ret) { + chg_err("Init wlchg gpio error."); + return ret; + } + + g_op_chip = chip; + + wlchg_reset_variables(chip); + chip->wlchg_status.dock_on = false; + + chip->wlchg_status.ftm_mode = false; + + ret = wlchg_init_wireless_psy(chip); + if (ret) { + chg_err("Init wireless psy error."); + goto free_gpio; + } + + INIT_DELAYED_WORK(&chip->usbin_int_work, wlchg_usbin_int_func); + INIT_DELAYED_WORK(&chip->wait_wpc_chg_quit, op_wait_wpc_chg_quit_work); + INIT_DELAYED_WORK(&chip->dischg_work, wlchg_dischg_work); + INIT_DELAYED_WORK(&chip->wlchg_task_work, wlchg_task_work_process); + INIT_DELAYED_WORK(&chip->update_bat_info_work, exfg_update_batinfo); + INIT_DELAYED_WORK(&chip->fastchg_curr_vol_work, curr_vol_check_process); + INIT_DELAYED_WORK(&chip->tx_check_work, wlchg_tx_check_process); + INIT_DELAYED_WORK(&chip->charger_exit_work, wlchg_charger_offline); + INIT_DELAYED_WORK(&chip->wlchg_connect_check_work, wlchg_connect_check_work); + INIT_DELAYED_WORK(&chip->wlchg_fcc_stepper_work, wlchg_fcc_stepper_work); +#ifdef HW_TEST_EDITION + INIT_DELAYED_WORK(&chip->w30w_timeout_work, w30w_timeout_work_process); +#endif + mutex_init(&chip->chg_lock); + mutex_init(&chip->connect_lock); + mutex_init(&chip->read_lock); + mutex_init(&chip->msg_lock); + + init_waitqueue_head(&chip->read_wq); + chip->wlchg_wake_lock = wakeup_source_register(chip->dev, "wlchg_wake_lock"); + chip->reverse_wlchg_wake_lock = wakeup_source_register(chip->dev, "reverse_wlchg_wake_lock"); + + ret = init_wireless_charge_proc(chip); + if (ret < 0) { + chg_err("Create wireless charge proc error."); + goto free_psy; + } + platform_set_drvdata(pdev, chip); + + chip->wlcs_fcc_votable = create_votable("WLCH_FCC", VOTE_MIN, + wlch_fcc_vote_callback, + chip); + if (IS_ERR(chip->wlcs_fcc_votable)) { + ret = PTR_ERR(chip->wlcs_fcc_votable); + chip->wlcs_fcc_votable = NULL; + goto free_proc; + } + + chip->fastchg_disable_votable = create_votable("WLCHG_FASTCHG_DISABLE", VOTE_SET_ANY, + wlchg_fastchg_disable_vote_callback, + chip); + if (IS_ERR(chip->fastchg_disable_votable)) { + ret = PTR_ERR(chip->fastchg_disable_votable); + chip->fastchg_disable_votable = NULL; + goto free_proc; + } + + ret = wireless_chg_init(chip); + if (ret < 0) { + pr_err("Couldn't init step and jieta char, ret = %d\n", ret); + goto free_proc; + } + + chip->wlchg_device.minor = MISC_DYNAMIC_MINOR; + chip->wlchg_device.name = "wlchg"; + chip->wlchg_device.fops = &wlchg_dev_fops; + ret = misc_register(&chip->wlchg_device); + if (ret) { + pr_err("%s : misc_register failed\n", __FILE__); + goto free_proc; + } + + boot_mode = get_boot_mode(); + if (boot_mode == MSM_BOOT_MODE_FACTORY) { + chg_info("wkcs: boot on FTM mode\n"); + chip->wlchg_status.ftm_mode = true; + } else { + chip->wlchg_status.ftm_mode = false; + } + + wlchg_rx_policy_register(chip); + + chg_debug(" call end\n"); + + return 0; + +free_proc: + remove_proc_entry("wireless", NULL); +free_psy: + power_supply_unregister(chip->wireless_psy); +free_gpio: + if (gpio_is_valid(chip->dcdc_en_gpio)) + gpio_free(chip->dcdc_en_gpio); + if (gpio_is_valid(chip->wrx_otg_gpio)) + gpio_free(chip->wrx_otg_gpio); + if (gpio_is_valid(chip->wrx_en_gpio)) + gpio_free(chip->wrx_en_gpio); + if (gpio_is_valid(chip->usbin_int_gpio)) + gpio_free(chip->usbin_int_gpio); + + return ret; +} + +static int wlchg_driver_remove(struct platform_device *pdev) +{ + struct op_chg_chip *chip = platform_get_drvdata(pdev); + + remove_proc_entry("wireless", NULL); + power_supply_unregister(chip->wireless_psy); + if (gpio_is_valid(chip->dcdc_en_gpio)) + gpio_free(chip->dcdc_en_gpio); + if (gpio_is_valid(chip->wrx_otg_gpio)) + gpio_free(chip->wrx_otg_gpio); + if (gpio_is_valid(chip->wrx_en_gpio)) + gpio_free(chip->wrx_en_gpio); + if (gpio_is_valid(chip->usbin_int_gpio)) + gpio_free(chip->usbin_int_gpio); + + return 0; +} + +/********************************************************** + * + * [platform_driver API] + * + *********************************************************/ + +static const struct of_device_id wlchg_match[] = { + { .compatible = "op,wireless-charger" }, + {}, +}; + +static struct platform_driver wlchg_driver = { + .driver = { + .name = "wireless-charger", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wlchg_match), + }, + .probe = wlchg_driver_probe, + .remove = wlchg_driver_remove, +}; + +module_platform_driver(wlchg_driver); +MODULE_DESCRIPTION("Driver for wireless charger"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.h b/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.h new file mode 100644 index 0000000000000000000000000000000000000000..27a2eaded7352b75921d446d60abac79c3100ae7 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_wlchg_policy.h @@ -0,0 +1,475 @@ +#ifndef __OP_POLICY_H__ +#define __OP_POLICY_H__ +#include +#include "bq2597x_charger.h" + +//#define HW_TEST_EDITION +//#define IDT_LAB_TEST +//#define OP_DEBUG + +#define WLCHG_TASK_INTERVAL round_jiffies_relative(msecs_to_jiffies(500)) +#define WLCHG_BATINFO_UPDATE_INTERVAL round_jiffies_relative(msecs_to_jiffies(1000)) +#define WLCHG_PD_HARDRESET_WAIT_TIME round_jiffies_relative(msecs_to_jiffies(1000)) +#define WLCHG_DISCONNECT_DELAYED msecs_to_jiffies(1500) +#define WLCHG_ACTIVE_DISCONNECT_DELAYED msecs_to_jiffies(5000) + +#define TEMPERATURE_STATUS_CHANGE_TIMEOUT 10 // about 10s +#define WPC_CHARGE_CURRENT_LIMIT_300MA 300 + +#define WLCHG_CHARGE_TIMEOUT 36000 // 10h + +#define PMIC_ICL_MAX 1100000 + +#define WPC_CHARGE_CURRENT_LIMIT_300MA 300 +#define WPC_CHARGE_CURRENT_ZERO 0 // 0mA +#define WPC_CHARGE_CURRENT_INIT_100MA 100 +#define WPC_CHARGE_CURRENT_200MA 200 +#define WPC_CHARGE_CURRENT_DEFAULT 500 // 500mA +#define WPC_CHARGE_CURRENT_ON_TRX 650 // 650mA +#define WPC_CHARGE_CURRENT_BPP 1000 // 1000mA +#define WPC_CHARGE_CURRENT_EPP 1100 +#define WPC_CHARGE_CURRENT_FASTCHG_INT 300 //400 +#define WPC_CHARGE_CURRENT_FASTCHG_END 700 // 300mA +#define WPC_CHARGE_CURRENT_FASTCHG_MID 800 // 800mA +#define WPC_CHARGE_CURRENT_FASTCHG 1500 // 1500mA +#define WPC_CHARGE_CURRENT_CHANGE_STEP_200MA 200 // 200mA +#define WPC_CHARGE_CURRENT_CHANGE_STEP_50MA 50 // 50mA +#define WPC_CHARGE_CURRENT_FFC_TO_CV 1000 // 1000mA +#define WPC_CHARGE_CURRENT_CHGPUMP_TO_CHARGER 300 +#define WPC_CHARGE_CURRENT_WAIT_FAST 300 +#define WPC_CHARGE_CURRENT_STOP_CHG 300 + +#define WPC_CHARGE_1250MA_UPPER_LIMIT 1480 /*1300*/ +#define WPC_CHARGE_1250MA_LOWER_LIMIT 1450 /*1200*/ +#define WPC_CHARGE_1A_UPPER_LIMIT 1050 +#define WPC_CHARGE_1A_LOWER_LIMIT 950 +#define WPC_CHARGE_800MA_UPPER_LIMIT 850 +#define WPC_CHARGE_800MA_LOWER_LIMIT 750 +#define WPC_CHARGE_600MA_UPPER_LIMIT 650 +#define WPC_CHARGE_600MA_LOWER_LIMIT 550 +#define WPC_CHARGE_500MA_UPPER_LIMIT 600 +#define WPC_CHARGE_500MA_LOWER_LIMIT 500 + +#define WPC_CHARGE_VOLTAGE_DEFAULT 5000 // 5V + +#define WPC_CHARGE_VOLTAGE_FASTCHG_INIT 11000 +#define WPC_CHARGE_VOLTAGE_STOP_CHG WPC_CHARGE_VOLTAGE_FASTCHG_INIT +#define WPC_CHARGE_VOLTAGE_OVP_MIN 12000 +#define WPC_CHARGE_VOLTAGE_FTM 17380 +#define WPC_CHARGE_VOLTAGE_FASTCHG WPC_CHARGE_VOLTAGE_DEFAULT // 12000 +#define WPC_CHARGE_VOLTAGE_FASTCHG_MAX (WPC_CHARGE_VOLTAGE_DEFAULT + 100) // 15000 +#define WPC_CHARGE_VOLTAGE_EPP 9000 + +#define WPC_CHARGE_VOLTAGE_CHGPUMP_MAX 20100 +#define WPC_CHARGE_VOLTAGE_CHGPUMP_MIN 5000 + +#define WPC_CHARGE_IOUT_HIGH_LEVEL 1050 // 1050mA +#define WPC_CHARGE_IOUT_LOW_LEVEL 950 // 950mA + +#define REVERSE_WIRELESS_CHARGE_CURR_LIMT 1500000 +#define WIRELESS_CHARGE_UPGRADE_CURR_LIMT 1500000 +#define REVERSE_WIRELESS_CHARGE_VOL_LIMT 5500000 +#define WIRELESS_CHARGE_FTM_TEST_VOL_LIMT 5000000 +#define WIRELESS_CHARGE_UPGRADE_VOL_LIMT 5000000 + +#define WPC_TERMINATION_CURRENT 200 +#define WPC_TERMINATION_VOLTAGE WPC_TERMINATION_VOLTAGE_DEFAULT +#define WPC_RECHARGE_VOLTAGE_OFFSET 200 +#define WPC_PRECHARGE_CURRENT 300 +#define WPC_CHARGER_INPUT_CURRENT_LIMIT_DEFAULT 1000 + +#define DCP_TERMINATION_CURRENT 600 +#define DCP_TERMINATION_VOLTAGE 4380 +#define DCP_RECHARGE_VOLTAGE_OFFSET 200 +#define DCP_PRECHARGE_CURRENT 300 +#define DCP_CHARGER_INPUT_CURRENT_LIMIT_DEFAULT 1000 +#define DCP_CHARGE_CURRENT_DEFAULT 1500 + +#define WPC_BATT_FULL_CNT 5 +#define WPC_RECHARGE_CNT 5 + +#define WPC_INCREASE_CURRENT_DELAY 2 +#define WPC_ADJUST_CV_DELAY 10 +#define WPC_CEP_NONZERO_DELAY 1 + +#define NORMAL_MODE_VOL_MIN WPC_CHARGE_VOLTAGE_DEFAULT +#define FASTCHG_MODE_VOL_MIN WPC_CHARGE_VOLTAGE_EPP +#define RX_VOLTAGE_MAX 20000 +#define FASTCHG_CURR_30W_MAX_UA 1500000 +#define FASTCHG_CURR_20W_MAX_UA 1000000 +#define FASTCHG_CURR_15W_MAX_UA 800000 +#define FASTCHG_CURR_MIN_UA 600000 +#define BATT_HOT_DECIDEGREE_MAX 600 +#define FASTCHG_EXIT_DECIDEGREE_MAX 450 +#define FASTCHG_EXIT_DECIDEGREE_MIN 0 +#define FASTCHG_EXIT_VOL_MAX_UV 4350000 + +#define RX_EPP_SOFT_OVP_MV 14000 +#define RX_FAST_SOFT_OVP_MV 22000 + +#define CURR_ERR_MIN 50 +#define VOL_SET_STEP 20 +#define VOL_INC_STEP_MAX 1000 +#define VOL_DEC_STEP_MAX 1000 +#define VOL_ADJ_LIMIT 14000 + +#define MAX_STEP_CHG_ENTRIES 8 + +#define ADAPTER_TYPE_UNKNOWN 0 +#define ADAPTER_TYPE_FASTCHAGE_DASH 1 +#define ADAPTER_TYPE_FASTCHAGE_WARP 2 +#define ADAPTER_TYPE_USB 3 +#define ADAPTER_TYPE_NORMAL_CHARGE 4 +#define ADAPTER_TYPE_EPP 5 + +#define WPC_CHARGE_TYPE_DEFAULT 0 +#define WPC_CHARGE_TYPE_FAST 1 +#define WPC_CHARGE_TYPE_USB 2 +#define WPC_CHARGE_TYPE_NORMAL 3 +#define WPC_CHARGE_TYPE_EPP 4 + +#define HEARTBEAT_COUNT_MAX 4 +#define EPP_CURR_STEP_MAX 2 + +#define FOD_PARM_LENGTH 12 + +#define DEFAULT_SKIN_TEMP 250 +#define CHARGE_FULL_FAN_THREOD_LO 350 +#define CHARGE_FULL_FAN_THREOD_HI 380 + +#define FASTCHG_CURR_ERR_MAX 5 + +enum { + WPC_CHG_STATUS_DEFAULT, + WPC_CHG_STATUS_READY_FOR_FASTCHG, + WPC_CHG_STATUS_WAITING_FOR_TX_INTO_FASTCHG, + WPC_CHG_STATUS_INCREASE_VOLTAGE, + WPC_CHG_STATUS_ADJUST_VOL_AFTER_INC_CURRENT, + WPC_CHG_STATUS_FAST_CHARGING_EXIT, + WPC_CHG_STATUS_FAST_CHARGING_WAIT_EXIT, + WPC_CHG_STATUS_STANDARD_CHARGING, + WPC_CHG_STATUS_FAST_CHARGING_FROM_CHGPUMP, + WPC_CHG_STATUS_FAST_CHARGING_FFC, + WPC_CHG_STATUS_FAST_CHARGING_FROM_PMIC, + WPC_CHG_STATUS_READY_FOR_EPP, + WPC_CHG_STATUS_EPP, + WPC_CHG_STATUS_EPP_WORKING, + WPC_CHG_STATUS_READY_FOR_BPP, + WPC_CHG_STATUS_BPP, + WPC_CHG_STATUS_BPP_WORKING, + WPC_CHG_STATUS_READY_FOR_FTM, + WPC_CHG_STATUS_FTM_WORKING, + WPC_CHG_STATUS_READY_FOR_QUIET, + WPC_CHG_STATUS_WAIT_DISABLE_BATT_CHARGE, + WPC_CHG_STATUS_DISABLE_BATT_CHARGE, +}; + +enum WLCHG_TEMP_REGION_TYPE { + WLCHG_BATT_TEMP_COLD = 0, + WLCHG_BATT_TEMP_LITTLE_COLD, + WLCHG_BATT_TEMP_COOL, + WLCHG_BATT_TEMP_LITTLE_COOL, + WLCHG_BATT_TEMP_PRE_NORMAL, + WLCHG_BATT_TEMP_NORMAL, + WLCHG_BATT_TEMP_WARM, + WLCHG_BATT_TEMP_HOT, + WLCHG_TEMP_REGION_MAX, +}; +typedef enum { + WPC_DISCHG_STATUS_OFF, + WPC_DISCHG_STATUS_ON, + WPC_DISCHG_IC_READY, + WPC_DISCHG_IC_PING_DEVICE, + WPC_DISCHG_IC_TRANSFER, + WPC_DISCHG_IC_ERR_TX_RXAC, + WPC_DISCHG_IC_ERR_TX_OCP, + WPC_DISCHG_IC_ERR_TX_OVP, + WPC_DISCHG_IC_ERR_TX_LVP, + WPC_DISCHG_IC_ERR_TX_FOD, + WPC_DISCHG_IC_ERR_TX_OTP, + WPC_DISCHG_IC_ERR_TX_CEPTIMEOUT, + WPC_DISCHG_IC_ERR_TX_RXEPT, + WPC_DISCHG_STATUS_UNKNOW, +} E_WPC_DISCHG_STATUS; + +enum FASTCHG_STARTUP_STEP { + FASTCHG_EN_CHGPUMP1_STEP, + FASTCHG_WAIT_CP1_STABLE_STEP, + FASTCHG_WAIT_PMIC_STABLE_STEP, + FASTCHG_SET_CHGPUMP2_VOL_STEP, + FASTCHG_SET_CHGPUMP2_VOL_AGAIN_STEP, + FASTCHG_EN_CHGPUMP2_STEP, + FASTCHG_CHECK_CHGPUMP2_STEP, + FASTCHG_CHECK_CHGPUMP2_AGAIN_STEP, + FASTCHG_EN_PMIC_CHG_STEP, +}; + +enum wlchg_msg_type { + WLCHG_NULL_MSG, + WLCHG_ADAPTER_MSG, + WLCHG_FASTCHAGE_MSG, + WLCHG_USB_CHARGE_MSG, + WLCHG_NORMAL_CHARGE_MSG, + WLCHG_NORMAL_MODE_MSG, + WLCHG_QUIET_MODE_MSG, + WLCHG_CEP_TIMEOUT_MSG, + WLCHG_TX_ID_MSG, +}; + +struct wlchg_msg_t { + char type; + char data; + char remark; +}; +struct cmd_info_t { + unsigned char cmd; + enum rx_msg_type cmd_type; + int cmd_retry_count; +}; + +struct wpc_data { + char charge_status; + enum FASTCHG_STARTUP_STEP fastchg_startup_step; + E_WPC_DISCHG_STATUS wpc_dischg_status; + bool charge_online; + bool dock_on; + bool tx_online; + bool tx_present; + bool charge_done; + int adapter_type; + int charge_type; + int charge_voltage; + int charge_current; + enum WLCHG_TEMP_REGION_TYPE temp_region; + int terminate_voltage; + int terminate_current; + int max_current; + int target_curr; + int target_vol; + int vol_set; + int fastchg_level; + // Record the initial temperature when switching to the next gear. + int fastchg_level_init_temp; + // Deviation detection + int freq_check_count; + int freq_sum; + int epp_curr_step; + int fastchg_curr_step; + int fastchg_retry_count; + int curr_err_count; + bool ftm_mode; + bool curr_limit_mode; + bool vol_set_ok; + bool curr_set_ok; + bool vol_set_start; + bool vol_set_fast; + bool startup_fast_chg; + bool cep_err_flag; + bool cep_check; + /* Exit fast charge, check ffc condition */ + bool ffc_check; + /* Record if the last current needs to drop */ + bool curr_need_dec; + bool vol_not_step; + bool is_power_changed; + /* + * When the battery voltage is greater than the maximum voltage + * entering the fast charge, it will no longer be allowed to enter + * the fast charge. + */ + bool is_deviation; + bool deviation_check_done; + bool freq_thr_inc; + bool wait_cep_stable; + + bool geted_tx_id; + bool quiet_mode_enabled; + bool quiet_mode_init; + bool get_adapter_err; + bool epp_working; + /* Indicates whether the message of getting adapter type was sent successfully */ + bool adapter_msg_send; + + unsigned long send_msg_timer; + unsigned long cep_ok_wait_timeout; + unsigned long fastchg_retry_timer; + bool rx_ovp; + bool fastchg_disable; + /* The disappearance of the wireless fast charge icon requires a delay */ + bool fastchg_display_delay; + bool cep_timeout_adjusted; + bool fastchg_restart; + bool startup_fod_parm; +}; + +struct op_range_data { + int low_threshold; + int high_threshold; + u32 curr_ua; + u32 vol_max_mv; + int need_wait; +}; + +struct op_fastchg_ffc_step { + int max_step; + struct op_range_data ffc_step[MAX_STEP_CHG_ENTRIES]; + bool allow_fallback[MAX_STEP_CHG_ENTRIES]; + unsigned long ffc_wait_timeout; +}; + +struct charge_param { + int fastchg_temp_min; + int fastchg_temp_max; + int fastchg_soc_min; + int fastchg_soc_max; + int fastchg_soc_mid; + int fastchg_curr_min; + int fastchg_curr_max; + int fastchg_vol_min; + int fastchg_vol_entry_max; + int fastchg_vol_normal_max; + int fastchg_vol_hot_max; + int fastchg_discharge_curr_max; + int batt_vol_max; + int BATT_TEMP_T0; + int BATT_TEMP_T1; + int BATT_TEMP_T2; + int BATT_TEMP_T3; + int BATT_TEMP_T4; + int BATT_TEMP_T5; + int BATT_TEMP_T6; + short mBattTempBoundT0; + short mBattTempBoundT1; + short mBattTempBoundT2; + short mBattTempBoundT3; + short mBattTempBoundT4; + short mBattTempBoundT5; + short mBattTempBoundT6; + int epp_ibatmax[WLCHG_TEMP_REGION_MAX]; + int bpp_ibatmax[WLCHG_TEMP_REGION_MAX]; + int epp_iclmax[WLCHG_TEMP_REGION_MAX]; + int bpp_iclmax[WLCHG_TEMP_REGION_MAX]; + int vbatdet[WLCHG_TEMP_REGION_MAX]; + int fastchg_ibatmax[2]; + int cool_vbat_thr_mv; + int cool_epp_ibat_ma; + int cool_epp_icl_ma; + int freq_threshold; + int fastchg_skin_temp_max; + int fastchg_skin_temp_min; + int epp_skin_temp_max; + int epp_skin_temp_min; + int epp_curr_step[EPP_CURR_STEP_MAX]; + bool fastchg_fod_enable; + unsigned char fastchg_match_q; + unsigned char fastchg_fod_parm[FOD_PARM_LENGTH]; + unsigned char fastchg_fod_parm_startup[FOD_PARM_LENGTH]; + struct op_fastchg_ffc_step ffc_chg; +}; + +enum wireless_mode { + WIRELESS_MODE_NULL, + WIRELESS_MODE_TX, + WIRELESS_MODE_RX, +}; + +struct op_chg_chip { + struct device *dev; + wait_queue_head_t read_wq; + struct miscdevice wlchg_device; + + bool charger_exist; + int temperature; + int batt_volt; + int batt_volt_max; + int batt_volt_min; + int icharging; + int soc; + bool otg_switch; + bool batt_missing; + bool disable_charge; + bool disable_batt_charge; + bool ap_ctrl_dcdc; + bool pmic_high_vol; + bool quiet_mode_need; + bool wlchg_wake_lock_on; + bool reverse_wlchg_wake_lock_on; + int wrx_en_gpio; + int wrx_otg_gpio; + int dcdc_en_gpio; + int usbin_int_gpio; + int usbin_int_irq; + bool pd_charger_online; + int wlchg_time_count; + struct pinctrl *pinctrl; + struct pinctrl_state *usbin_int_active; + struct pinctrl_state *usbin_int_sleep; + struct pinctrl_state *usbin_int_default; + struct pinctrl_state *wrx_en_active; + struct pinctrl_state *wrx_en_sleep; + struct pinctrl_state *wrx_en_default; + struct pinctrl_state *wrx_otg_active; + struct pinctrl_state *wrx_otg_sleep; + struct pinctrl_state *wrx_otg_default; + struct pinctrl_state *dcdc_en_active; + struct pinctrl_state *dcdc_en_sleep; + struct pinctrl_state *dcdc_en_default; + + struct wakeup_source *wlchg_wake_lock; + struct wakeup_source *reverse_wlchg_wake_lock; + + struct mutex chg_lock; + struct mutex connect_lock; + struct mutex read_lock; + struct mutex msg_lock; + + struct delayed_work wlchg_task_work; // for WPC + struct delayed_work update_bat_info_work; + struct delayed_work usbin_int_work; + struct delayed_work wait_wpc_chg_quit; + struct delayed_work dischg_work; // for WPC + struct delayed_work fastchg_curr_vol_work; + struct delayed_work tx_check_work; + struct delayed_work charger_exit_work; + struct delayed_work wlchg_connect_check_work; + struct delayed_work wlchg_fcc_stepper_work; + struct wpc_data wlchg_status; // for WPC + struct charge_param chg_param; + atomic_t suspended; +#ifdef HW_TEST_EDITION + int w30w_time; + bool w30w_timeout; + bool w30w_work_started; + struct delayed_work w30w_timeout_work; +#endif + struct power_supply *wireless_psy; + struct power_supply *batt_psy; + struct votable *wlcs_fcc_votable; + struct votable *fastchg_disable_votable; + enum power_supply_type wireless_type; + enum wireless_mode wireless_mode; + + bool wlchg_msg_ok; + bool heart_stop; + struct cmd_info_t cmd_info; + struct wlchg_msg_t msg_info; + + atomic_t hb_count; //heartbeat_count +}; + +extern void wlchg_rx_policy_register(struct op_chg_chip *op_wlchg); + +void wlchg_set_rtx_function(bool is_on); +bool wlchg_wireless_charge_start(void); +int wlchg_get_usbin_val(void); +void op_set_wrx_en_value(int value); +void op_set_wrx_otg_value(int value); +void op_set_dcdc_en_value(int value); +int wlchg_connect_callback_func(bool ldo_on); +int wlchg_tx_callback(void); +bool wlchg_wireless_working(void); +extern int register_reverse_charge_notifier(struct notifier_block *nb); +extern int unregister_reverse_charge_notifier(struct notifier_block *nb); + + +#endif diff --git a/drivers/oneplus/power/supply/wlchg/op_wlchg_rx.c b/drivers/oneplus/power/supply/wlchg/op_wlchg_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..4d71e07312f09d614e0ac618658e1bcd82a40367 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_wlchg_rx.c @@ -0,0 +1,634 @@ +#define pr_fmt(fmt) "WLCHG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "op_chargepump.h" +#include "op_wlchg_rx.h" +#include "op_wlchg_policy.h" +#include "smb5-lib.h" + +static struct rx_chip *g_rx_chip; +static struct op_chg_chip *g_op_chip; + +extern void exrx_information_register(struct rx_chip *chip); + +int wlchg_rx_set_vout(struct rx_chip *chip, int val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + pr_info("set rx chip vout to %d\n", val); + pval.intval = val; + rc = prop->set_prop(prop, RX_PROP_VOUT, &pval); + if (rc) { + pr_err("can't set rx chip vout, rc=%d\n", rc); + return rc; + } + chip->chg_data.charge_voltage = val; + + return 0; +} + +int wlchg_rx_get_vout(struct rx_chip *chip, int *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_VOUT, &pval); + if (rc) { + pr_err("can't get rx vout, rc=%d\n", rc); + *val = 0; + return rc; + } + + *val = pval.intval; + return 0; +} + +int wlchg_rx_set_match_q_parm(struct rx_chip *chip, unsigned char data) +{ + struct rx_chip_prop *prop; + int rc = 0; + + if (chip == NULL) { + pr_err("rx chip not ready\n"); + return -ENODEV; + } + + prop = chip->prop; + if (prop->send_match_q_parm) + rc = prop->send_match_q_parm(prop, data); + + return rc; +} + +int wlchg_rx_set_fod_parm(struct rx_chip *chip, const char data[]) +{ + struct rx_chip_prop *prop; + int rc = 0; + + if (chip == NULL) { + pr_err("rx chip not ready\n"); + return -ENODEV; + } + + prop = chip->prop; + if (prop->set_fod_parm) + rc = prop->set_fod_parm(prop, data); + + return rc; +} + +int wlchg_rx_ftm_test(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_FTM_TEST, &pval); + if (rc) + return rc; + return pval.intval; +} + +int wlchg_rx_get_vrect_iout(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_VOUT, &pval); + if (rc) { + pr_err("can't get rx vout, rc=%d\n", rc); + return rc; + } + chip->chg_data.vout = pval.intval; + + rc = prop->get_prop(prop, RX_PROP_VRECT, &pval); + if (rc) { + pr_err("can't get rx vrect, rc=%d\n", rc); + return rc; + } + chip->chg_data.vrect = pval.intval; + + rc = prop->get_prop(prop, RX_PROP_IOUT, &pval); + if (rc) { + pr_err("can't get rx iout, rc=%d\n", rc); + return rc; + } + chip->chg_data.iout = pval.intval; + + pr_info("vout:%d, vrect=%d, iout=%d\n", chip->chg_data.vout, + chip->chg_data.vrect, chip->chg_data.iout); + + return 0; +} + +int wlchg_rx_get_tx_vol(struct rx_chip *chip, int *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_TRX_VOL, &pval); + if (rc) { + pr_err("can't get trx voltage, rc=%d\n", rc); + return rc; + } + *val = pval.intval; + + return 0; +} + +int wlchg_rx_get_tx_curr(struct rx_chip *chip, int *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_TRX_CURR, &pval); + if (rc) { + pr_err("can't get trx current, rc=%d\n", rc); + return rc; + } + *val = pval.intval; + + return 0; +} + +int wlchg_rx_trx_enbale(struct rx_chip *chip, bool enable) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + pval.intval = enable; + rc = prop->set_prop(prop, RX_PROP_TRX_ENABLE, &pval); + if (rc) { + pr_err("can't %s trx, rc=%d\n", rc, enable ? "enable" : "disable"); + return rc; + } + + return 0; +} + +int wlchg_rx_get_cep(struct rx_chip *chip, signed char *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_CEP, &pval); + if (rc) { + pr_err("can't get cep, rc=%d\n", rc); + return rc; + } + *val = (signed char)pval.intval; + + return 0; +} + +int wlchg_rx_get_cep_skip_check_update(struct rx_chip *chip, signed char *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_CEP_SKIP_CHECK_UPDATE, &pval); + if (rc) { + pr_err("can't get cep, rc=%d\n", rc); + return rc; + } + *val = (signed char)pval.intval; + + return 0; +} + +int wlchg_rx_get_cep_flag(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_CEP, &pval); + if (rc) { + pr_err("can't get cep, rc=%d\n", rc); + return rc; + } + + pr_info("cep = %d\n", pval.intval); + if (abs(pval.intval) <= 2) + return 0; + + return -EINVAL; +} + +int wlchg_rx_get_cep_flag_skip_check_update(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_CEP_SKIP_CHECK_UPDATE, &pval); + if (rc) { + pr_err("can't get cep, rc=%d\n", rc); + return rc; + } + + pr_info("cep = %d\n", pval.intval); + if (abs(pval.intval) <= 2) + return 0; + + return -EINVAL; +} + +void wlchg_rx_get_run_flag(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_RUN_MODE, &pval); + if (rc) { + pr_err("can't get rx run flag, rc=%d\n", rc); + chip->chg_data.rx_runing_mode = RX_RUNNING_MODE_OTHERS; + return; + } + chip->chg_data.rx_runing_mode = pval.intval; +} + +int wlchg_rx_enable_dcdc(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + pval.intval = 1; + rc = prop->set_prop(prop, RX_PROP_ENABLE_DCDC, &pval); + if (rc) { + pr_err("can't enable dcdc, rc=%d\n", rc); + return rc; + } + + return 0; +} + +int wlchg_rx_get_headroom(struct rx_chip *chip, int *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_HEADROOM, &pval); + if (rc) { + pr_err("can't get headroom, rc=%d\n", rc); + return rc; + } + *val = pval.intval; + + return 0; +} + +int wlchg_rx_set_headroom(struct rx_chip *chip, int val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + pval.intval = val; + rc = prop->get_prop(prop, RX_PROP_HEADROOM, &pval); + if (rc) { + pr_err("can't set headroom, rc=%d\n", rc); + return rc; + } + + return 0; +} + +enum E_RX_MODE wlchg_rx_get_run_mode(struct rx_chip *chip) +{ + if (chip == NULL) { + chg_err("rx chip not ready, return\n"); + return RX_RUNNING_MODE_BPP; + } + + return chip->chg_data.rx_runing_mode; +} + +int wlchg_rx_get_work_freq(struct rx_chip *chip, int *val) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_WORK_FREQ, &pval); + if (rc) { + pr_err("can't get work freq, rc=%d\n", rc); + return rc; + } + *val = pval.intval; + + return 0; +} + +int wlchg_rx_set_chip_sleep(int val) +{ + struct rx_chip_prop *prop; + union rx_chip_propval pval = {0,}; + int rc; + + if (g_rx_chip == NULL) { + pr_err("rx chip is not ready\n"); + return -ENODEV; + } + + prop = g_rx_chip->prop; + pval.intval = val; + rc = prop->set_prop(prop, RX_PROP_CHIP_SLEEP, &pval); + if (rc) { + pr_err("can't set chip sleep, rc=%d\n", rc); + return rc; + } + + return 0; +} + +int wlchg_rx_get_chip_sleep(void) +{ + struct rx_chip_prop *prop; + union rx_chip_propval pval = {0,}; + int rc; + + if (g_rx_chip == NULL) { + pr_err("rx chip is not ready\n"); + return 0; + } + + prop = g_rx_chip->prop; + rc = prop->get_prop(prop, RX_PROP_CHIP_SLEEP, &pval); + if (rc) { + pr_err("can't get chip sleep val, rc=%d\n", rc); + return 0; + } + + return pval.intval; +} + +int wlchg_rx_set_chip_en(int val) +{ + struct rx_chip_prop *prop; + union rx_chip_propval pval = {0,}; + int rc; + + if (g_rx_chip == NULL) { + pr_err("rx chip is not ready\n"); + return -ENODEV; + } + + prop = g_rx_chip->prop; + pval.intval = val; + rc = prop->set_prop(prop, RX_PROP_CHIP_EN, &pval); + if (rc) { + pr_err("can't set chip enable, rc=%d\n", rc); + return rc; + } + + return 0; +} + +int wlchg_rx_get_chip_en(void) +{ + struct rx_chip_prop *prop; + union rx_chip_propval pval = {0,}; + int rc; + + if (g_rx_chip == NULL) { + pr_err("rx chip is not ready\n"); + return 0; + } + + prop = g_rx_chip->prop; + rc = prop->get_prop(prop, RX_PROP_CHIP_EN, &pval); + if (rc) { + pr_err("can't get chip sleep enable val, rc=%d\n", rc); + return 0; + } + + return pval.intval; +} + +int wlchg_rx_get_chip_con(void) +{ + struct rx_chip_prop *prop; + union rx_chip_propval pval = {0,}; + int rc; + + if (g_rx_chip == NULL) { + pr_err("rx chip is not ready\n"); + return 0; + } + + prop = g_rx_chip->prop; + rc = prop->get_prop(prop, RX_PROP_CHIP_CON, &pval); + if (rc) { + pr_err("can't get chip sleep con val, rc=%d\n", rc); + return 0; + } + + return pval.intval; +} + +bool wlchg_rx_fw_updating(struct rx_chip *chip) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_FW_UPDATING, &pval); + if (rc) { + pr_err("can't get fw update status, rc=%d\n", rc); + return false; + } + + return (bool)pval.intval; +} + +int wlchg_rx_get_idt_rtx_status(struct rx_chip *chip, char *status, char *err) +{ + struct rx_chip_prop *prop = chip->prop; + union rx_chip_propval pval = {0,}; + int rc; + + rc = prop->get_prop(prop, RX_PROP_TRX_STATUS, &pval); + if (rc) { + pr_err("can't get trx status, rc=%d\n", rc); + return rc; + } + *status = (char)pval.intval; + + rc = prop->get_prop(prop, RX_PROP_TRX_ERROR_CODE, &pval); + if (rc) { + pr_err("can't get trx err code, rc=%d\n", rc); + return rc; + } + *err = (char)pval.intval; + + return 0; +} + +void wlchg_rx_reset_variables(struct rx_chip *chip) +{ + chip->chg_data.charge_voltage = 0; + chip->chg_data.charge_current = 0; + chip->chg_data.vrect = 0; + chip->chg_data.vout = 0; + chip->chg_data.iout = 0; + chip->chg_data.rx_runing_mode = RX_RUNNING_MODE_BPP; + chip->on_op_trx = false; +} + +int wlchg_rx_register_prop(struct device *parent, struct rx_chip_prop *chip_prop) +{ + struct i2c_client *client; + static struct rx_chip *chip; + + client = container_of(parent, struct i2c_client, dev); + chip = i2c_get_clientdata(client); + chip->prop = chip_prop; + + return 0; +} + +void wlchg_rx_policy_register(struct op_chg_chip *op_wlchg) +{ + if (g_op_chip) { + g_op_chip = op_wlchg; + pr_err("multiple ex g_op_chip called\n"); + } else { + g_op_chip = op_wlchg; + } +} + +static int wlchg_rx_parse_dt(struct rx_chip *chip) +{ + return 0; +} + +static struct regmap_config wlchg_rx_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xFFFF, +}; + +static int wlchg_rx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rx_chip *chip; + int rc = 0; + + chip = devm_kzalloc(&client->dev, sizeof(struct rx_chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + g_rx_chip = chip; + chip->dev = &client->dev; + chip->regmap = devm_regmap_init_i2c(client, &wlchg_rx_regmap_config); + if (!chip->regmap) + return -ENODEV; + + i2c_set_clientdata(client, chip); + exrx_information_register(chip); + + rc = wlchg_rx_parse_dt(chip); + if (rc < 0) { + pr_err("Couldn't parse device tree rc=%d\n", rc); + goto cleanup; + } + + of_platform_populate(chip->dev->of_node, NULL, NULL, chip->dev); + pr_info("wlchg rx probe successful\n"); + return rc; + +cleanup: + i2c_set_clientdata(client, NULL); + return rc; +} + +static int wlchg_rx_remove(struct i2c_client *client) +{ + struct rx_chip *chip = i2c_get_clientdata(client); + + of_platform_depopulate(chip->dev); + i2c_set_clientdata(client, NULL); + return 0; +} + +static int wlchg_rx_suspend(struct device *dev) +{ + return 0; +} +static int wlchg_rx_resume(struct device *dev) +{ + return 0; +} +static int wlchg_rx_suspend_noirq(struct device *dev) +{ + return 0; +} + +static void wlchg_rx_reset(struct i2c_client *client) +{ + struct rx_chip *chip = i2c_get_clientdata(client); + struct rx_chip_prop *prop = chip->prop; + + prop->rx_reset(prop); + + return; +} + +static const struct dev_pm_ops wlchg_rx_pm_ops = { + .suspend = wlchg_rx_suspend, + .suspend_noirq = wlchg_rx_suspend_noirq, + .resume = wlchg_rx_resume, +}; + +static const struct of_device_id wlchg_rx_match_table[] = { + { .compatible = "op,wlchg-rx-chip", }, + { }, +}; + +static const struct i2c_device_id wlchg_rx_id[] = { + { "i2c-wlchg-rx", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, wlchg_rx_id); + +static struct i2c_driver wlchg_rx_driver = { + .driver = { + .name = "wlchg_rx", + .pm = &wlchg_rx_pm_ops, + .of_match_table = wlchg_rx_match_table, + }, + .probe = wlchg_rx_probe, + .remove = wlchg_rx_remove, + .shutdown = wlchg_rx_reset, + .id_table = wlchg_rx_id, +}; + +module_i2c_driver(wlchg_rx_driver); + +MODULE_LICENSE("GPL v2"); \ No newline at end of file diff --git a/drivers/oneplus/power/supply/wlchg/op_wlchg_rx.h b/drivers/oneplus/power/supply/wlchg/op_wlchg_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..3c4976c7d55fb54688aaa89226aa5943d2e75dd2 --- /dev/null +++ b/drivers/oneplus/power/supply/wlchg/op_wlchg_rx.h @@ -0,0 +1,145 @@ +#ifndef __OP_WLCHG_RX_H__ +#define __OP_WLCHG_RX_H__ + +#define RX_RESPONE_ADAPTER_TYPE 0xF1 +#define RX_RESPONE_INTO_FASTCHAGE 0xF2 +#define RX_RESPONE_INTO_USB_CHARGE 0xF3 +#define RX_RESPONE_INTO_NORMAL_CHARGER 0xF4 +#define RX_RESPONE_INTO_NORMAL_MODE 0xF5 +#define RX_RESPONE_INTO_QUIET_MODE 0xF6 +#define RX_RESPONE_GETED_TX_ID 0x5F +#define RX_COMMAND_READY_FOR_EPP 0xFA +#define RX_COMMAND_WORKING_IN_EPP 0xFB +#define RX_RESPONE_NULL 0x00 + +#define IOUT_AVERAGE_NUM 4 + +#define TRX_READY BIT(0) +#define TRX_DIGITALPING BIT(1) +#define TRX_ANALOGPING BIT(2) +#define TRX_TRANSFER BIT(3) + +#define TRX_ERR_TX_RXAC BIT(0) +#define TRX_ERR_TX_OCP BIT(1) +#define TRX_ERR_TX_OVP BIT(2) +#define TRX_ERR_TX_LVP BIT(3) +#define TRX_ERR_TX_FOD BIT(4) +#define TRX_ERR_TX_OTP BIT(5) +#define TRX_ERR_TX_CEPTIMEOUT BIT(6) +#define TRX_ERR_TX_RXEPT BIT(7) + +enum send_msg { + RX_INDENTIFY_ADAPTER_MSG, + RX_INTO_FASTCHAGE_MSG, + RX_INTO_USB_CHARGE_MSG, + RX_INTO_NORMAL_CHARGE_MSG, + RX_INTO_NORMAL_MODE_MSG, + RX_INTO_QUIET_MODE_MSG, + RX_GET_TX_ID_MSG, + RX_NULL_MSG, +}; + +enum E_RX_MODE { + RX_RUNNING_MODE_EPP, + RX_RUNNING_MODE_BPP, + RX_RUNNING_MODE_OTHERS, +}; + +union rx_chip_propval { + int intval; + const char *strval; + int64_t int64val; +}; + +enum rx_prop_type { + RX_PROP_VOUT, + RX_PROP_VRECT, + RX_PROP_IOUT, + RX_PROP_CEP, + RX_PROP_CEP_SKIP_CHECK_UPDATE, + RX_PROP_WORK_FREQ, + RX_PROP_TRX_ENABLE, + RX_PROP_TRX_STATUS, + RX_PROP_TRX_ERROR_CODE, + RX_PROP_TRX_VOL, + RX_PROP_TRX_CURR, + RX_PROP_RUN_MODE, + RX_PROP_ENABLE_DCDC, + RX_PROP_FTM_TEST, + RX_PROP_CHIP_SLEEP, + RX_PROP_CHIP_EN, + RX_PROP_CHIP_CON, + RX_PROP_FW_UPDATING, + RX_PROP_HEADROOM, +}; + +enum rx_msg_type { + RX_MSG_LONG, + RX_MSG_MEDIUM, + RX_MSG_SHORT, +}; + +struct rx_chip_prop { + void *private_data; + int (*get_prop)(struct rx_chip_prop *, enum rx_prop_type, union rx_chip_propval *); + int (*set_prop)(struct rx_chip_prop *, enum rx_prop_type, union rx_chip_propval *); + int (*send_msg)(struct rx_chip_prop *, enum rx_msg_type, unsigned char); + int (*send_match_q_parm)(struct rx_chip_prop *, unsigned char); + int (*set_fod_parm)(struct rx_chip_prop *, const char []); + void (*rx_reset)(struct rx_chip_prop *); +}; + +struct rx_data { + int send_message; + unsigned long send_msg_timer; + int charge_voltage; + int charge_current; + int vout; + int vrect; + int iout; + int iout_now; + enum E_RX_MODE rx_runing_mode; + bool check_fw_update; + bool idt_fw_updating; +}; + +struct rx_chip { + struct device *dev; + + bool on_op_trx; + + struct rx_chip_prop *prop; + struct regmap *regmap; + struct rx_data chg_data; +}; + +int wlchg_rx_register_prop(struct device *parent, struct rx_chip_prop *chip_prop); +int wlchg_rx_set_vout(struct rx_chip *chip, int val); +int wlchg_rx_get_vout(struct rx_chip *chip, int *val); +int wlchg_rx_ftm_test(struct rx_chip *chip); +int wlchg_rx_get_vrect_iout(struct rx_chip *chip); +int wlchg_rx_get_tx_vol(struct rx_chip *chip, int *val); +int wlchg_rx_get_tx_curr(struct rx_chip *chip, int *val); +int wlchg_rx_get_cep(struct rx_chip *chip, signed char *val); +int wlchg_rx_get_cep_skip_check_update(struct rx_chip *chip, signed char *val); +int wlchg_rx_get_cep_flag(struct rx_chip *chip); +int wlchg_rx_get_cep_flag_skip_check_update(struct rx_chip *chip); +void wlchg_rx_get_run_flag(struct rx_chip *chip); +int wlchg_rx_enable_dcdc(struct rx_chip *chip); +enum E_RX_MODE wlchg_rx_get_run_mode(struct rx_chip *chip); +int wlchg_rx_get_work_freq(struct rx_chip *chip, int *val); +int wlchg_rx_set_chip_sleep(int val); +int wlchg_rx_get_chip_sleep(void); +int wlchg_rx_set_chip_en(int val); +int wlchg_rx_get_chip_en(void); +int wlchg_rx_get_chip_con(void); +bool wlchg_rx_fw_updating(struct rx_chip *chip); +int wlchg_rx_get_idt_rtx_status(struct rx_chip *chip, char *status, char *err); +void wlchg_rx_reset_variables(struct rx_chip *chip); +int wlchg_rx_trx_enbale(struct rx_chip *chip, bool enable); +int wlchg_rx_get_headroom(struct rx_chip *chip, int *val); +int wlchg_rx_set_headroom(struct rx_chip *chip, int val); +int wlchg_rx_set_match_q_parm(struct rx_chip *chip, unsigned char data); +int wlchg_rx_set_fod_parm(struct rx_chip *chip, const char data[]); + +#endif diff --git a/drivers/oneplus/step_motor/Kconfig b/drivers/oneplus/step_motor/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..935b2d68e7579ade894cb06abcc671ccc345600f --- /dev/null +++ b/drivers/oneplus/step_motor/Kconfig @@ -0,0 +1,16 @@ +config STEP_MOTOR + tristate "Step motor driver for stspin220" + help + This option enable support for stspin220 step motor Driver. + +config DIGITAL_HALL_M1120 + tristate "digital hall m1120 Controler" + default n + help + Say Y here to enable m1120. + +config ONEPLUS_STEP_MOTOR + tristate "config oneplus step motor" + default n + help + Say Y to enable oneplus step motor. \ No newline at end of file diff --git a/drivers/oneplus/step_motor/Makefile b/drivers/oneplus/step_motor/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..612c68aebd37d982701dd7708de084ea8cba7ecb --- /dev/null +++ b/drivers/oneplus/step_motor/Makefile @@ -0,0 +1,8 @@ +subdir-ccflags-y += -Werror +subdir-ccflags-y += -Wno-unused-variable + +obj-$(ONEPLUS_STEP_MOTOR) += camera_motor_ic/ +obj-$(ONEPLUS_STEP_MOTOR) += digital_hall_ic/ + +obj-$(ONEPLUS_STEP_MOTOR) += oneplus_motor.o +obj-$(ONEPLUS_STEP_MOTOR) += oneplus_motor_notifier.o diff --git a/drivers/oneplus/step_motor/camera_motor_ic/Makefile b/drivers/oneplus/step_motor/camera_motor_ic/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..a6bd6ea67f24f29e194f7ec3966e0a7a58766131 --- /dev/null +++ b/drivers/oneplus/step_motor/camera_motor_ic/Makefile @@ -0,0 +1,3 @@ +#obj-$(CONFIG_CAMERA_MOTOR_DRV8834) += oneplus_drv8834.o +obj-y += oneplus_drv8834.o +#obj-y += oneplus_stspin220.o \ No newline at end of file diff --git a/drivers/oneplus/step_motor/camera_motor_ic/oneplus_drv8834.c b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_drv8834.c new file mode 100644 index 0000000000000000000000000000000000000000..ef424815a6967681fff4623f4e80084c7de5a8d1 --- /dev/null +++ b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_drv8834.c @@ -0,0 +1,824 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_drv8834.c +** +** Description: +** Definitions for m1120 motor driver ic drv8834. +** +**************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include + +#include "oneplus_drv8834.h" +#include "../oneplus_motor.h" + +static struct oneplus_mdrv_chip *g_the_chip = NULL; +static void drv8834_check_motor_type(struct oneplus_mdrv_chip *chip); + +static void drv8834_parse_dts(struct oneplus_mdrv_chip * chip) +{ + struct device_node *np = chip->dev->of_node; + int rc = 0; + + if (np == NULL) { + MOTOR_ERR("=====>lkh np == NULL \n"); + } + + chip->pctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR(chip->pctrl)) { + MOTOR_ERR("failed to get pinctrl\n"); + }; + + chip->pwm_dev = of_pwm_get(np, NULL); + + if (IS_ERR(chip->pwm_dev)) { + MOTOR_LOG("pwm_dev not specified \n"); + } else { + MOTOR_LOG("request pwm seccess\n"); + } + + chip->boost_gpio = of_get_named_gpio(np, "op,boost-en-pin", 0);//boost 5v + if (!gpio_is_valid(chip->boost_gpio)) { + MOTOR_LOG("md-boost-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->boost_gpio, "boost-en-pin"); + if (rc) + MOTOR_LOG("request md-boost-gpio gpio failed, rc=%d\n", rc); + } + + chip->step_gpio = of_get_named_gpio(np, "op,step-pin", 0);//step pwm + if (!gpio_is_valid(chip->step_gpio)) { + MOTOR_LOG("md-step-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->step_gpio, "step-pin"); + if (rc) + MOTOR_LOG("request md-step-gpio failed, rc=%d\n", rc); + //else + // gpio_set_value(chip->step_gpio, 0); + } + + chip->m0_gpio = of_get_named_gpio(np, "op,mode0-pin", 0);//mode0 + if (!gpio_is_valid(chip->m0_gpio)) { + MOTOR_LOG("md-m0-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->m0_gpio, "mode0-pin"); + if (rc) + MOTOR_LOG("request md-m0-gpio failed, rc=%d\n", rc); + else + gpio_set_value(chip->m0_gpio, 0); + } + + + chip->m1_gpio = of_get_named_gpio(np, "op,mode1-pin", 0);//mode1 + if (!gpio_is_valid(chip->m1_gpio)) { + MOTOR_LOG("md-m1-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->m1_gpio, "mode1-pin"); + if (rc) + MOTOR_LOG("request md-m1-gpio failed, rc=%d\n", rc); + else + gpio_set_value(chip->m1_gpio, 0); + } + + /*vref gpio not use by op*/ + chip->vref_gpio = of_get_named_gpio(np, "qcom,vref-gpio", 0); + if (!gpio_is_valid(chip->vref_gpio)) { + MOTOR_LOG("md-vref-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->vref_gpio, "vref-gpio"); + if (rc) + MOTOR_LOG("request md_vref-gpio gpio failed, rc=%d\n", rc); + else + gpio_set_value(chip->vref_gpio, 0); + } + + chip->sleep_gpio = of_get_named_gpio(np, "op,nsleep-pin", 0);//sleep + if (!gpio_is_valid(chip->sleep_gpio)) { + MOTOR_LOG("md-sleep-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->sleep_gpio, "nsleep-pin"); + if (rc) + MOTOR_LOG("request md-sleep-gpio gpio failed, rc=%d\n", rc); + else + gpio_set_value(chip->sleep_gpio, 0); + } + + /*sleep1 gpio not use by op*/ + chip->sleep1_gpio = of_get_named_gpio(np, "qcom,sleep1-gpio", 0); + if (!gpio_is_valid(chip->sleep1_gpio)) { + MOTOR_LOG("md-sleep-gpio1 gpio not specified\n"); + } else { + rc = gpio_request(chip->sleep1_gpio, "sleep-gpio1"); + if (rc) + MOTOR_LOG("request md-sleep-gpio1 gpio failed, rc=%d\n", rc); + else + gpio_set_value(chip->sleep1_gpio, 0); + } + + chip->dir_gpio = of_get_named_gpio(np, "op,dir-pin", 0);//dir + if (!gpio_is_valid(chip->dir_gpio)) { + MOTOR_LOG("md-dir-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->dir_gpio, "dir-gpio"); + if (rc) + MOTOR_LOG("request md-dir-gpio gpio failed, rc=%d\n", rc); + else + gpio_set_value(chip->dir_gpio, 0); + } + + /*dir switch gpio not use by op*/ + chip->dir_switch_gpio = of_get_named_gpio(np, "qcom,dir_switch-gpio", 0); + if (!gpio_is_valid(chip->dir_switch_gpio)) { + MOTOR_LOG("dir_switch_gpio not specified\n"); + } else { + rc = gpio_request(chip->dir_switch_gpio, "dir_switch-gpio"); + if (rc) + MOTOR_LOG("request dir-switch-gpio failed, rc=%d\n", rc); + } + + MOTOR_LOG("%d %d %d %d %d %d\n", chip->boost_gpio, chip->sleep_gpio, + chip->dir_gpio, chip->m0_gpio, chip->m1_gpio, chip->step_gpio); +} + +static int drv8834_init_dir_switch(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + if (chip->vref_dirswitch_on == false) + return ret;//op not use dir switch + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->dir_switch_state = pinctrl_lookup_state(chip->pctrl, "dir_switch_gpio_input_high"); + if (IS_ERR(chip->dir_switch_state)) { + ret = PTR_ERR(chip->dir_switch_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->dir_switch_state); + + msleep(10); + + chip->dir_switch = gpio_get_value(chip->dir_switch_gpio); + + chip->dir_switch_state = pinctrl_lookup_state(chip->pctrl, "dir_switch_gpio_input_low"); + if (IS_ERR(chip->dir_switch_state)) { + ret = PTR_ERR(chip->dir_switch_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + pinctrl_select_state(chip->pctrl,chip->dir_switch_state); + + return 0; + +} + +static int drv8834_init_pwm_config(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->pwm_state = pinctrl_lookup_state(chip->pctrl, "pwm_config"); + if (IS_ERR(chip->pwm_state)) { + ret = PTR_ERR(chip->pwm_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->pwm_state); + + return 0; + +} + +static int drv8834_init_boost(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->boost_state = pinctrl_lookup_state(chip->pctrl, "boost"); + if (IS_ERR(chip->boost_state)) { + ret = PTR_ERR(chip->boost_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->boost_state); + + return 0; + +} + +static int drv8834_init_m1_gpio(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->m1_state = pinctrl_lookup_state(chip->pctrl, "m1_gpio"); + if (IS_ERR(chip->m1_state)) { + ret = PTR_ERR(chip->m1_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->m1_state); + + return 0; + +} + +static int drv8834_init_sleep_gpio(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->sleep_state = pinctrl_lookup_state(chip->pctrl, "sleep_gpio"); + if (IS_ERR(chip->sleep_state)) { + ret = PTR_ERR(chip->sleep_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->sleep_state); + + return 0; + +} + +static int drv8834_init_dir_gpio(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->dir_state = pinctrl_lookup_state(chip->pctrl, "dir_gpio"); + if (IS_ERR(chip->dir_state)) { + ret = PTR_ERR(chip->dir_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->dir_state); + + return 0; + +} + +static int drv8834_change_m0_config(struct oneplus_mdrv_chip * chip ,int config) +{ + int ret = 0; + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + if (config == GPIO_MODE) { + chip->m0_state = pinctrl_lookup_state(chip->pctrl, "m0_gpio"); + if (IS_ERR(chip->m0_state)) { + ret = PTR_ERR(chip->m0_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->m0_state); + + } else { + chip->m0_state = pinctrl_lookup_state(chip->pctrl, "m0_high_impedance"); + if (IS_ERR(chip->m0_state)) { + ret = PTR_ERR(chip->m0_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->m0_state); + } + + return 0; +} + +static int drv8834_change_vref_config(struct oneplus_mdrv_chip * chip ,int config) +{ + int ret = 0; + + if (chip->vref_dirswitch_on == false) + return ret;//op not use vref config + + if (IS_ERR(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + if (config == GPIO_MODE) { + chip->vref_state = pinctrl_lookup_state(chip->pctrl, "vref_gpio"); + if (IS_ERR(chip->vref_state)) { + ret = PTR_ERR(chip->vref_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->vref_state); + + } else { + chip->vref_state = pinctrl_lookup_state(chip->pctrl, "vref_high_impedance"); + if (IS_ERR(chip->vref_state)) { + ret = PTR_ERR(chip->vref_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->vref_state); + } + + return 0; +} + +static int drv8834_hardware_init(struct oneplus_mdrv_chip * chip) +{ + int ret = 0; + + //init boost + ret = drv8834_init_boost(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_init_boost %d \n",ret); + return -EINVAL;; + } + if (gpio_is_valid(chip->boost_gpio)) + gpio_set_value(chip->boost_gpio, 0); + + + //config pwm for step-gpio + ret = drv8834_init_pwm_config(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_init_pwm_config %d \n",ret); + return -EINVAL; + } + + //config m1_gpio + ret = drv8834_init_m1_gpio(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_init_m1_gpio %d \n",ret); + return -EINVAL;; + } + + //config sleep_gpio + ret = drv8834_init_sleep_gpio(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_init_sleep_gpio %d \n",ret); + return -EINVAL;; + } + + //config m1_gpio + ret = drv8834_init_dir_gpio(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_init_dir_gpio %d \n",ret); + return -EINVAL;; + } + + //config m0_gpio as GPIO_MODE + ret = drv8834_change_m0_config(chip,GPIO_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_m0_config %d \n",ret); + return -EINVAL;; + } + + drv8834_check_motor_type(chip); + + MOTOR_LOG("motor_type=%d, vref_dirswitch_on=%d\n", + chip->motor_type, chip->vref_dirswitch_on); + + if (chip->vref_dirswitch_on) { + //config vref_gpio as GPIO_MODE + ret = drv8834_change_vref_config(chip, GPIO_MODE); + if (ret < 0) { + MOTOR_ERR("drv8834_change_vref_config %d\n", ret); + return -EINVAL; + } + + //config dir_switch _gpio + ret = drv8834_init_dir_switch(chip); + if (ret < 0) { + MOTOR_ERR("drv8834_init_dir_switch %d\n", ret); + return -EINVAL; + } + } + + return 0; + +} + +static int drv8834_set_power(int mode) +{ + static bool first_init = true; + + if (g_the_chip == NULL || IS_ERR(g_the_chip->pwm_dev)) { + MOTOR_LOG("g_the_chip null or pwm_dev not exist!\n"); + return -EINVAL; + } + + MOTOR_ERR("drv8834_set_power call mode: %d power on:%d\n",mode,MOTOR_POWER_ON); + + if (mode == MOTOR_POWER_ON) { + drv8834_init_pwm_config(g_the_chip); + if (first_init) { + first_init = false; + if (gpio_is_valid(g_the_chip->boost_gpio)) + /* boost should be always on*/ + gpio_set_value(g_the_chip->boost_gpio, 1); + msleep(10); + } + if (gpio_is_valid(g_the_chip->sleep_gpio)) + gpio_set_value(g_the_chip->sleep_gpio, 1); + } else { + if (gpio_is_valid(g_the_chip->sleep_gpio)) + gpio_set_value(g_the_chip->sleep_gpio, 0); + if (gpio_is_valid(g_the_chip->step_gpio)) + gpio_set_value(g_the_chip->step_gpio, 0); + if (gpio_is_valid(g_the_chip->dir_gpio)) + gpio_set_value(g_the_chip->dir_gpio, 0); + } + return 0; +} + +static int drv8834_set_direction(int dir) +{ + if (g_the_chip == NULL || !gpio_is_valid(g_the_chip->dir_gpio)) { + MOTOR_LOG("g_the_chip null or dir_gpio invalid\n"); + return -EINVAL; + } + + if (g_the_chip->motor_type == MOTOR_FI5) { // fi 5 motor op select + if (g_the_chip->dir_switch) { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 1); + } else { + gpio_set_value(g_the_chip->dir_gpio, 0); + } + } else { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 0); + } else { + gpio_set_value(g_the_chip->dir_gpio, 1); + } + } + } else { //fi 6 motor + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 1); + } else { + gpio_set_value(g_the_chip->dir_gpio, 0); + } + } + return 0; +} + +static int drv8834_set_working_mode (int mode) +{ + int ret = 0; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n "); + return -EINVAL; + } + + switch (mode) { + case MOTOR_MODE_FULL: + MOTOR_ERR("MOTOR_MODE_FULL call \n"); + ret = drv8834_change_vref_config(g_the_chip,GPIO_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_vref_config %d \n",ret); + return -EINVAL; + } + + ret = drv8834_change_m0_config(g_the_chip,GPIO_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_m0_config %d \n",ret); + return -EINVAL; + } + if (gpio_is_valid(g_the_chip->m0_gpio)) + gpio_set_value(g_the_chip->m0_gpio, 0); + if (gpio_is_valid(g_the_chip->m1_gpio)) + gpio_set_value(g_the_chip->m1_gpio, 0); + break; + case MOTOR_MODE_1_16: + MOTOR_ERR("MOTOR_MODE_1_16 call \n"); + ret = drv8834_change_vref_config(g_the_chip,HIGH_IMPEDANCE_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_vref_config %d \n",ret); + return -EINVAL; + } + + ret = drv8834_change_m0_config(g_the_chip,GPIO_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_m0_config %d \n",ret); + return -EINVAL; + } + if (gpio_is_valid(g_the_chip->m0_gpio)) + gpio_set_value(g_the_chip->m0_gpio, 1); + if (gpio_is_valid(g_the_chip->m1_gpio)) + gpio_set_value(g_the_chip->m1_gpio, 1); + break; + case MOTOR_MODE_1_32://go here + MOTOR_ERR("MOTOR_MODE_1_32 call \n"); + ret = drv8834_change_vref_config(g_the_chip,HIGH_IMPEDANCE_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_vref_config %d \n",ret); + return -EINVAL; + } + + ret = drv8834_change_m0_config(g_the_chip,HIGH_IMPEDANCE_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_m0_config %d \n",ret); + return -EINVAL; + } + + if (gpio_is_valid(g_the_chip->m1_gpio)) + gpio_set_value(g_the_chip->m1_gpio, 1); + break; + default: + MOTOR_ERR("MOTOR_MODE_default call \n"); + ret = drv8834_change_vref_config(g_the_chip,HIGH_IMPEDANCE_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_vref_config %d \n",ret); + return -EINVAL; + } + + ret = drv8834_change_m0_config(g_the_chip,HIGH_IMPEDANCE_MODE); + if (ret < 0){ + MOTOR_ERR("drv8834_change_m0_config %d \n",ret); + return -EINVAL; + } + + if (gpio_is_valid(g_the_chip->m1_gpio)) + gpio_set_value(g_the_chip->m1_gpio, 1); + break; + } + MOTOR_ERR("config change %d %d %d %d %d\n", + gpio_get_value(g_the_chip->sleep_gpio), + gpio_get_value(g_the_chip->step_gpio), + gpio_get_value(g_the_chip->m0_gpio), + gpio_get_value(g_the_chip->m1_gpio), + gpio_get_value(g_the_chip->dir_gpio)); + return 0; +} + + +static int drv8834_calculate_pwm_count(int L, int mode) +{ + int pwm_count = 0; + int mdmode = 0; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return 0; + } + switch (mode) { + case MOTOR_MODE_FULL: + mdmode = 1; + break; + case MOTOR_MODE_1_16: + mdmode = 16; + break; + case MOTOR_MODE_1_32: + mdmode = 32; + break; + default: + mdmode = 32; + break; + } + //PWM = (L*18.06*20*32 )/2.4 + pwm_count = (L * RATIO_B * RATIO_C *RATIO_D) / (RATIO_A * 100); + //pwm_count = (L * RATIO_B_FI_6 * RATIO_C *RATIO_D) / (RATIO_A * 100); + return pwm_count; +} + +static int drv8834_pwm_config(int duty_ns, int period_ns) +{ + int pwm_count = 0; + int mdmode = 0; + + if (g_the_chip == NULL) { + MOTOR_LOG("====>lkh g_the_chip null\n"); + return -EINVAL; + } + + if (IS_ERR(g_the_chip->pwm_dev)) { + MOTOR_LOG("======>lkh pwm_dev not exist!\n"); + return -EINVAL; + } + + MOTOR_LOG("duty_ns %d period_ns %d \n",duty_ns,period_ns); + + return pwm_config(g_the_chip->pwm_dev, duty_ns, period_ns); +} + +static int drv8834_pwm_enable(void) +{ + if (g_the_chip == NULL || IS_ERR(g_the_chip->pwm_dev)) { + MOTOR_LOG("g_the_chip null or pwm_dev not exist!\n"); + return -EINVAL; + } + + return pwm_enable(g_the_chip->pwm_dev); +} + +static int drv8834_pwm_disable(void) +{ + if (g_the_chip == NULL || IS_ERR(g_the_chip->pwm_dev)) { + MOTOR_LOG("g_the_chip null or pwm_dev not exist!\n"); + return -EINVAL; + } + + pwm_disable(g_the_chip->pwm_dev); + return 0; +} + +static int drv8834_get_motor_type(void) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return MOTOR_UNKNOWN; + } + + return g_the_chip->motor_type; +} + +static void drv8834_check_motor_type(struct oneplus_mdrv_chip *chip) +{ + /*if (is_project(ONEPLUS_17107) && get_PCB_Version() == HW_VERSION__12) { // fi 6 motor + chip->motor_type = MOTOR_FI6; + } else { //fi 5 motor + chip->motor_type = MOTOR_FI5; + } + */ + chip->motor_type = MOTOR_FI5; + MOTOR_LOG("motor_type %d \n",chip->motor_type); +} + +static int drv8834_get_all_config(int* config ,int count) +{ + if (g_the_chip == NULL || count > 6) { + MOTOR_LOG("g_the_chip null \n"); + return -EINVAL; + } + + config[0] = gpio_get_value(g_the_chip->sleep_gpio); + config[1] = gpio_get_value(g_the_chip->step_gpio); + config[2] = gpio_get_value(g_the_chip->m0_gpio); + config[3] = gpio_get_value(g_the_chip->m1_gpio); + config[4] = gpio_get_value(g_the_chip->dir_gpio); + + MOTOR_ERR("config change %d %d %d %d %d %d\n", config[0], config[1], + config[2], config[3], config[4]); + + return 0; +} + + +struct oneplus_motor_operations drv8834_ops = { + .set_power = drv8834_set_power, + .set_direction = drv8834_set_direction, + .set_working_mode = drv8834_set_working_mode, + .get_all_config = drv8834_get_all_config, + .calculate_pwm_count = drv8834_calculate_pwm_count, + .pwm_config = drv8834_pwm_config, + .pwm_enable = drv8834_pwm_enable, + .pwm_disable = drv8834_pwm_disable, + .get_motor_type = drv8834_get_motor_type, +}; + +static int drv8834_platform_probe(struct platform_device *pdev) +{ + struct oneplus_mdrv_chip *chip = NULL; + int ret = 0; + + MOTOR_LOG("call\n"); + + chip = devm_kzalloc(&pdev->dev,sizeof(struct oneplus_mdrv_chip), GFP_KERNEL); + if (!chip) { + MOTOR_ERR("kernel memory alocation was failed"); + return -ENOMEM; + } + + chip->dev = &pdev->dev; + chip->vref_dirswitch_on = false; + + drv8834_parse_dts(chip); + + ret = drv8834_hardware_init(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_hardware_init %d \n",ret); + //return -EINVAL;//not need return -22 keep go on + } + + oneplus_register_motor("drv8834",&drv8834_ops); + + g_the_chip = chip; + + MOTOR_LOG("success \n"); + return 0; +} + +static int drv8834_platform_remove(struct platform_device *pdev) +{ + if (g_the_chip) { + gpio_free(g_the_chip->boost_gpio); + gpio_free(g_the_chip->dir_gpio); + gpio_free(g_the_chip->m0_gpio); + gpio_free(g_the_chip->m1_gpio); + gpio_free(g_the_chip->sleep_gpio); + if (gpio_is_valid(g_the_chip->vref_gpio)) + gpio_free(g_the_chip->vref_gpio); + if (gpio_is_valid(g_the_chip->sleep1_gpio)) + gpio_free(g_the_chip->sleep1_gpio); + kfree(g_the_chip); + g_the_chip = NULL; + } + return 0; +} + +static const struct of_device_id of_motor_drv_match[] = { + { .compatible = "motor_drv-8834"}, + { .compatible = "oneplus,step-motor"}, + {}, +}; +MODULE_DEVICE_TABLE(of, of_motor_match); + +static struct platform_driver motor_drv_driver = { + .probe = drv8834_platform_probe, + .remove = drv8834_platform_remove, + .driver = { + .name = "drv8834", + .of_match_table = of_motor_drv_match, + }, +}; + +static int __init drv8834_init(void) +{ + MOTOR_LOG("call\n"); + platform_driver_register(&motor_drv_driver); + return 0; +} + +static void __exit drv8834_exit(void) +{ + MOTOR_LOG("call\n"); +} + +module_init(drv8834_init); +module_exit(drv8834_exit); +MODULE_DESCRIPTION("camera motor driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("mofei@oneplus.com"); + diff --git a/drivers/oneplus/step_motor/camera_motor_ic/oneplus_drv8834.h b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_drv8834.h new file mode 100644 index 0000000000000000000000000000000000000000..51301dde637317092c9d77b9881c081f2b52d105 --- /dev/null +++ b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_drv8834.h @@ -0,0 +1,50 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_drv8834.h +** +** Description: +** Definitions for m1120 motor driver ic drv8834. +** +**************************************************************************************/ +#ifndef __ONEPLUS_DRV8834_H__ +#define __ONEPLUS_DRV8834_H__ + +#define RATIO_A 24 //2.4 +#define RATIO_B 1806 //18.06 +#define RATIO_B_FI_6 354 //3.54 +#define RATIO_C 20 +#define RATIO_D 32 + +enum { + GPIO_MODE = 0, + HIGH_IMPEDANCE_MODE +}; + +struct oneplus_mdrv_chip { + struct device *dev; + struct pwm_device *pwm_dev; + struct pinctrl *pctrl; + struct pinctrl_state *pwm_state; + struct pinctrl_state *boost_state; + struct pinctrl_state *m0_state; + struct pinctrl_state *m1_state; + struct pinctrl_state *vref_state; + struct pinctrl_state *sleep_state; + struct pinctrl_state *dir_state; + struct pinctrl_state *dir_switch_state; + unsigned int boost_gpio; + unsigned int vref_gpio; + unsigned int sleep_gpio; + unsigned int sleep1_gpio; + unsigned int dir_gpio; + unsigned int m0_gpio; + unsigned int m1_gpio; + unsigned int step_gpio; + unsigned int dir_switch_gpio; + int dir_switch; + int motor_type; + bool vref_dirswitch_on; +}; + +#endif // __ONEPLUS_DRV8834_H__ + diff --git a/drivers/oneplus/step_motor/camera_motor_ic/oneplus_stspin220.c b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_stspin220.c new file mode 100755 index 0000000000000000000000000000000000000000..b506c48a243045812774c38360d5687f7dfe35bf --- /dev/null +++ b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_stspin220.c @@ -0,0 +1,668 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_stspin220.c +** +** Description: +** Definitions for m1120 motor driver ic stspin220. +** +**************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oneplus_stspin220.h" +#include "../oneplus_motor.h" + +static struct oneplus_sts_chip *g_the_chip = NULL; +static void stspin220_check_motor_type(struct oneplus_sts_chip *chip); +static int stspin220_set_working_mode (int mode); + +static void stspin220_parse_dts(struct oneplus_sts_chip * chip) +{ + struct device_node *np = chip->dev->of_node; + int rc = 0; + + chip->pctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pctrl)) { + MOTOR_ERR("failed to get pinctrl\n"); + }; + + chip->pwm_dev = of_pwm_get(np, NULL); + + if (IS_ERR_OR_NULL(chip->pwm_dev)) { + MOTOR_LOG("pwm_dev not specified \n"); + } else { + MOTOR_LOG("request pwm seccess\n"); + } + + chip->boost_gpio = of_get_named_gpio(np, "qcom,boost-gpio", 0); + if (!gpio_is_valid(chip->boost_gpio)) { + MOTOR_LOG("md-boost-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->boost_gpio, "boost-gpio"); + if (rc) + MOTOR_LOG("request md-boost-gpio gpio failed, rc=%d\n",rc); + } + + chip->step_gpio = of_get_named_gpio(np, "qcom,step-gpio", 0); + if (!gpio_is_valid(chip->step_gpio)) { + MOTOR_LOG("md-step-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->step_gpio, "step-gpio"); + if (rc) + MOTOR_LOG("request md-step-gpio failed, rc=%d\n",rc); + //else + // gpio_set_value(chip->step_gpio, 0); + } + + chip->sleep_gpio = of_get_named_gpio(np, "qcom,sleep-gpio", 0); + if (!gpio_is_valid(chip->sleep_gpio)) { + MOTOR_LOG("md-sleep-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->sleep_gpio, "sleep-gpio"); + if (rc) + MOTOR_LOG("request md-sleep-gpio gpio failed, rc=%d\n",rc); + else + gpio_set_value(chip->sleep_gpio, 0); + } + + chip->enable_gpio = of_get_named_gpio(np, "qcom,enable-gpio", 0); + if (!gpio_is_valid(chip->enable_gpio)) { + MOTOR_LOG("md-enable-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->enable_gpio, "enable-gpio"); + if (rc) + MOTOR_LOG("request md-enavle-gpio gpio failed, rc=%d\n",rc); + else + gpio_set_value(chip->enable_gpio, 0); + } + + + chip->sleep1_gpio = of_get_named_gpio(np, "qcom,sleep1-gpio", 0); + if (!gpio_is_valid(chip->sleep1_gpio)) { + MOTOR_LOG("md-sleep-gpio1 gpio not specified\n"); + } else { + rc = gpio_request(chip->sleep1_gpio, "sleep-gpio1"); + if (rc) + MOTOR_LOG("request md-sleep-gpio1 gpio failed, rc=%d\n",rc); + else + gpio_set_value(chip->sleep1_gpio, 0); + } + + chip->dir_gpio = of_get_named_gpio(np, "qcom,dir-gpio", 0); + if (!gpio_is_valid(chip->dir_gpio)) { + MOTOR_LOG("md-dir-gpio gpio not specified\n"); + } else { + rc = gpio_request(chip->dir_gpio, "dir-gpio"); + if (rc) + MOTOR_LOG("request md-dir-gpio gpio failed, rc=%d\n",rc); + else + gpio_set_value(chip->dir_gpio, 0); + } + + chip->dir_switch_gpio = of_get_named_gpio(np, "qcom,dir_switch-gpio", 0); + if (!gpio_is_valid(chip->dir_switch_gpio)) { + MOTOR_LOG("dir_switch_gpio not specified\n"); + } else { + rc = gpio_request(chip->dir_switch_gpio, "dir_switch-gpio"); + if (rc) + MOTOR_LOG("request md-m0-gpio failed, rc=%d\n",rc); + } + + MOTOR_LOG("%d %d %d %d %d %d %d\n",chip->boost_gpio,chip->sleep_gpio,chip->sleep1_gpio, + chip->dir_gpio,chip->step_gpio,chip->dir_switch_gpio,chip->enable_gpio); +} + +static int stspin220_init_dir_switch(struct oneplus_sts_chip * chip) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->dir_switch_state = pinctrl_lookup_state(chip->pctrl, "dir_switch_gpio_input_high"); + if (IS_ERR_OR_NULL(chip->dir_switch_state)) { + ret = PTR_ERR(chip->dir_switch_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->dir_switch_state); + + msleep(10); + + chip->dir_switch = gpio_get_value(chip->dir_switch_gpio); + + chip->dir_switch_state = pinctrl_lookup_state(chip->pctrl, "dir_switch_gpio_input_low"); + if (IS_ERR_OR_NULL(chip->dir_switch_state)) { + ret = PTR_ERR(chip->dir_switch_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + pinctrl_select_state(chip->pctrl,chip->dir_switch_state); + + return 0; + +} + +static int stspin220_init_pwm_config(struct oneplus_sts_chip * chip , int is_pwm_mode) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + if (is_pwm_mode) + chip->pwm_state = pinctrl_lookup_state(chip->pctrl, "pwm_config"); + else + chip->pwm_state = pinctrl_lookup_state(chip->pctrl, "pwm_config_as_gpio"); + if (IS_ERR_OR_NULL(chip->pwm_state)) { + ret = PTR_ERR(chip->pwm_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->pwm_state); + + return 0; + +} + +static int stspin220_init_boost(struct oneplus_sts_chip * chip) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->boost_state = pinctrl_lookup_state(chip->pctrl, "boost"); + if (IS_ERR_OR_NULL(chip->boost_state)) { + ret = PTR_ERR(chip->boost_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->boost_state); + + return 0; + +} + +static int stspin220_init_sleep_gpio(struct oneplus_sts_chip * chip) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->sleep_state = pinctrl_lookup_state(chip->pctrl, "sleep_gpio"); + if (IS_ERR_OR_NULL(chip->sleep_state)) { + ret = PTR_ERR(chip->sleep_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->sleep_state); + + return 0; + +} + +static int stspin220_init_dir_gpio(struct oneplus_sts_chip * chip) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->dir_state = pinctrl_lookup_state(chip->pctrl, "dir_gpio"); + if (IS_ERR_OR_NULL(chip->dir_state)) { + ret = PTR_ERR(chip->dir_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->dir_state); + + return 0; + +} + +static int stspin220_init_enable_gpio(struct oneplus_sts_chip * chip) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(chip->pctrl)) { + ret = PTR_ERR(chip->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + chip->enable_state = pinctrl_lookup_state(chip->pctrl, "enable_gpio"); + if (IS_ERR_OR_NULL(chip->enable_state)) { + ret = PTR_ERR(chip->enable_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(chip->pctrl,chip->enable_state); + + return 0; + +} + +static int stspin220_hardware_init(struct oneplus_sts_chip * chip) +{ + int ret = 0; + + //init boost + ret = stspin220_init_boost(chip); + if (ret < 0){ + MOTOR_ERR("stspin220_init_boost %d \n",ret); + return -EINVAL;; + } + gpio_set_value(chip->boost_gpio, 0); + + + //config pwm for step-gpio + ret = stspin220_init_pwm_config(chip,0); + if (ret < 0){ + MOTOR_ERR("stspin220_init_pwm_config %d \n",ret); + return -EINVAL; + } + + //config sleep_gpio + ret = stspin220_init_sleep_gpio(chip); + if (ret < 0){ + MOTOR_ERR("stspin220_init_sleep_gpio %d \n",ret); + return -EINVAL;; + } + + //config dir_gpio + ret = stspin220_init_dir_gpio(chip); + if (ret < 0){ + MOTOR_ERR("stspin220_init_dir_gpio %d \n",ret); + return -EINVAL;; + } + + //config dir_switch _gpio + ret = stspin220_init_dir_switch(chip); + if (ret < 0){ + MOTOR_ERR("drv8834_init_dir_switch %d \n",ret); + return -EINVAL;; + } + + //config enable_gpio _gpio + ret = stspin220_init_enable_gpio(chip); + if (ret < 0){ + MOTOR_ERR("stspin220_init_enable_gpio %d \n",ret); + return -EINVAL;; + } + + stspin220_check_motor_type(chip); + + return 0; + +} + +static int stspin220_set_power(int mode) +{ + static bool first_init = true; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n "); + return -EINVAL; + } + + MOTOR_ERR("stspin220_set_power call mode: %d power on:%d\n",mode,MOTOR_POWER_ON); + + if (mode == MOTOR_POWER_ON) { + stspin220_set_working_mode(MOTOR_MODE_1_32); + stspin220_init_pwm_config(g_the_chip,1); + if (first_init) { + first_init = false; + gpio_set_value(g_the_chip->boost_gpio, 1);//boost should be always on + msleep(10); + } + gpio_set_value(g_the_chip->enable_gpio, 1); + } else { + gpio_set_value(g_the_chip->sleep_gpio, 0); + gpio_set_value(g_the_chip->sleep1_gpio, 0); + gpio_set_value(g_the_chip->enable_gpio, 0); + } + return 0; +} + +static int stspin220_set_direction(int dir) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n "); + return -EINVAL; + } + + if (g_the_chip->motor_type == MOTOR_FI5) { // fi 5 motor + if (g_the_chip->dir_switch) { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 1); + } else { + gpio_set_value(g_the_chip->dir_gpio, 0); + } + } else { + if (is_project(ONEPLUS_17107)) { + if (get_PCB_Version() >= HW_VERSION__14) { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 1); + } else { + gpio_set_value(g_the_chip->dir_gpio, 0); + } + } else { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 0); + } else { + gpio_set_value(g_the_chip->dir_gpio, 1); + } + } + } else { + if (get_PCB_Version() >= HW_VERSION__11) { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 1); + } else { + gpio_set_value(g_the_chip->dir_gpio, 0); + } + } else { + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 0); + } else { + gpio_set_value(g_the_chip->dir_gpio, 1); + } + } + } + } + } else { //fi 6 motor + if (dir == MOTOR_UPWARD) { + gpio_set_value(g_the_chip->dir_gpio, 1); + } else { + gpio_set_value(g_the_chip->dir_gpio, 0); + } + } + return 0; +} + +static int stspin220_set_working_mode (int mode) +{ + int ret = 0; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n "); + return -EINVAL; + } + + gpio_set_value(g_the_chip->sleep_gpio, 0); + gpio_set_value(g_the_chip->sleep1_gpio, 0); + + switch (mode) { + case MOTOR_MODE_FULL: + MOTOR_ERR("MOTOR_MODE_FULL call \n"); + stspin220_init_pwm_config(g_the_chip,0); + gpio_set_value(g_the_chip->dir_gpio,0); + break; + case MOTOR_MODE_1_16: + MOTOR_ERR("MOTOR_MODE_1_16 call \n"); + stspin220_init_pwm_config(g_the_chip,0); + gpio_set_value(g_the_chip->dir_gpio,0); + break; + case MOTOR_MODE_1_32: + MOTOR_ERR("MOTOR_MODE_1_32 call \n"); + stspin220_init_pwm_config(g_the_chip,0); + gpio_set_value(g_the_chip->dir_gpio,0); + break; + default: + MOTOR_ERR("MOTOR_MODE_default call \n"); + stspin220_init_pwm_config(g_the_chip,0); + gpio_set_value(g_the_chip->dir_gpio,0); + break; + } + + gpio_set_value(g_the_chip->sleep_gpio, 1); + gpio_set_value(g_the_chip->sleep1_gpio, 1); + + MOTOR_ERR("config change %d %d %d\n", + gpio_get_value(g_the_chip->sleep_gpio), + gpio_get_value(g_the_chip->sleep1_gpio), + gpio_get_value(g_the_chip->dir_gpio)); + return 0; +} + + +static int stspin220_calculate_pwm_count(int L, int mode) +{ + int pwm_count = 0; + int mdmode = 0; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return 0; + } + switch (mode) { + case MOTOR_MODE_FULL: + mdmode = 1; + break; + case MOTOR_MODE_1_16: + mdmode = 16; + break; + case MOTOR_MODE_1_32: + mdmode = 32; + break; + default: + mdmode = 32; + break; + } + //PWM = (L*18.06*20*32 )/2.4 + pwm_count = (L * RATIO_B * RATIO_C *RATIO_D) / (RATIO_A * 100); + //pwm_count = (L * RATIO_B_FI_6 * RATIO_C *RATIO_D) / (RATIO_A * 100); + return pwm_count; +} + +static int stspin220_pwm_config(int duty_ns, int period_ns) +{ + int pwm_count = 0; + int mdmode = 0; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return -EINVAL; + } + + MOTOR_LOG("duty_ns %d period_ns %d \n",duty_ns,period_ns); + + return pwm_config(g_the_chip->pwm_dev, duty_ns, period_ns); +} + +static int stspin220_pwm_enable(void) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return -EINVAL; + } + + return pwm_enable(g_the_chip->pwm_dev); +} + +static int stspin220_pwm_disable(void) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return -EINVAL; + } + + pwm_disable(g_the_chip->pwm_dev); + return 0; +} + +static int stspin220_get_motor_type(void) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip null \n"); + return MOTOR_UNKNOWN; + } + + return g_the_chip->motor_type; +} + +static void stspin220_check_motor_type(struct oneplus_sts_chip *chip) +{ + if (get_PCB_Version() == HW_VERSION__12) { // fi 6 motor + chip->motor_type = MOTOR_FI6; + } else { //fi 5 motor + chip->motor_type = MOTOR_FI5; + } + + MOTOR_LOG("motor_type %d \n",chip->motor_type); +} + +static int stspin220_get_all_config(int* config ,int count) +{ + if (g_the_chip == NULL || count > 6) { + MOTOR_LOG("g_the_chip null \n"); + return -EINVAL; + } + + config[0] = gpio_get_value(g_the_chip->sleep_gpio); + config[1] = gpio_get_value(g_the_chip->step_gpio); + config[2] = gpio_get_value(g_the_chip->sleep1_gpio); + config[3] = gpio_get_value(g_the_chip->enable_gpio); + config[4] = gpio_get_value(g_the_chip->dir_gpio); + config[5] = g_the_chip->motor_type; + + MOTOR_ERR("config change %d %d %d %d %d %d\n",config[0],config[1],config[2], + config[3],config[4],config[5]); + + return 0; +} + + +struct oneplus_motor_operations stspin220_ops = { + .set_power = stspin220_set_power, + .set_direction = stspin220_set_direction, + .set_working_mode = stspin220_set_working_mode, + .get_all_config = stspin220_get_all_config, + .calculate_pwm_count = stspin220_calculate_pwm_count, + .pwm_config = stspin220_pwm_config, + .pwm_enable = stspin220_pwm_enable, + .pwm_disable = stspin220_pwm_disable, + .get_motor_type = stspin220_get_motor_type, +}; + +static int stspin220_platform_probe(struct platform_device *pdev) +{ + struct oneplus_sts_chip *chip = NULL; + int ret = 0; + + MOTOR_LOG("call\n"); + + chip = devm_kzalloc(&pdev->dev,sizeof(struct oneplus_sts_chip), GFP_KERNEL); + if (!chip) { + MOTOR_ERR("kernel memory alocation was failed"); + return -ENOMEM; + } + + chip->dev = &pdev->dev; + + stspin220_parse_dts(chip); + + ret = stspin220_hardware_init(chip); + if (ret < 0){ + MOTOR_ERR("stspin220_hardware_init %d \n",ret); + return -EINVAL;; + } + + oneplus_register_motor("stspin220",&stspin220_ops); + + g_the_chip = chip; + + MOTOR_LOG("success \n"); + return 0; +} + +static int stspin220_platform_remove(struct platform_device *pdev) +{ + if (g_the_chip) { + gpio_free(g_the_chip->boost_gpio); + gpio_free(g_the_chip->dir_gpio); + gpio_free(g_the_chip->enable_gpio); + gpio_free(g_the_chip->sleep_gpio); + gpio_free(g_the_chip->sleep1_gpio); + kfree(g_the_chip); + g_the_chip = NULL; + } + return 0; +} + +static const struct of_device_id of_motor_drv_match[] = { + { .compatible = "motor_drv-220"}, + {}, +}; +MODULE_DEVICE_TABLE(of, of_motor_match); + +static struct platform_driver motor_drv_driver = { + .probe = stspin220_platform_probe, + .remove = stspin220_platform_remove, + .driver = { + .name = "stspin220", + .of_match_table = of_motor_drv_match, + }, +}; + +static int __init stspin220_init(void) +{ + MOTOR_LOG("call\n"); + platform_driver_register(&motor_drv_driver); + return 0; +} + +static void __exit stspin220_exit(void) +{ + MOTOR_LOG("call\n"); +} + +module_init(stspin220_init); +module_exit(stspin220_exit); +MODULE_DESCRIPTION("camera motor driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("mofei@oneplus.com"); + diff --git a/drivers/oneplus/step_motor/camera_motor_ic/oneplus_stspin220.h b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_stspin220.h new file mode 100755 index 0000000000000000000000000000000000000000..1fb5a4b644d829e0e85b7576f15b722f982d3cb0 --- /dev/null +++ b/drivers/oneplus/step_motor/camera_motor_ic/oneplus_stspin220.h @@ -0,0 +1,45 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_drv8834.h +** +** Description: +** Definitions for m1120 motor driver ic drv8834. +** +**************************************************************************************/ +#ifndef __ONEPLUS_STSPIN220_H__ +#define __ONEPLUS_STSPIN220_H__ + +#define RATIO_A 24 //2.4 +#define RATIO_B 1806 //18.06 +#define RATIO_B_FI_6 354 //3.54 +#define RATIO_C 20 +#define RATIO_D 32 + +enum { + GPIO_MODE = 0, + HIGH_IMPEDANCE_MODE +}; + +struct oneplus_sts_chip { + struct device *dev; + struct pwm_device *pwm_dev; + struct pinctrl *pctrl; + struct pinctrl_state *pwm_state; + struct pinctrl_state *boost_state; + struct pinctrl_state *enable_state; + struct pinctrl_state *sleep_state; + struct pinctrl_state *dir_state; + struct pinctrl_state *dir_switch_state; + unsigned int boost_gpio; + unsigned int sleep_gpio; + unsigned int sleep1_gpio; + unsigned int dir_gpio; + unsigned int enable_gpio; + unsigned int step_gpio; + unsigned int dir_switch_gpio; + int dir_switch; + int motor_type; +}; + +#endif // __ONEPLUS_DRV8834_H__ + diff --git a/drivers/oneplus/step_motor/digital_hall_ic/Makefile b/drivers/oneplus/step_motor/digital_hall_ic/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..faa96e9e252ac2a707b66b8d57b8773576a0aaa8 --- /dev/null +++ b/drivers/oneplus/step_motor/digital_hall_ic/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += oneplus_m1120_up.o oneplus_m1120_down.o + + + diff --git a/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120.h b/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120.h new file mode 100644 index 0000000000000000000000000000000000000000..9b493134970ef99689244d33c0cbf5e630d7fb01 --- /dev/null +++ b/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120.h @@ -0,0 +1,165 @@ +/**************************************************************************************** +** Copyright (C), 2013-2018, ONEPLUS +** File : oneplus_m1120.c +** +** Description : +** Definitions for m1120 digital hall_up and hall_down sensor +** +****************************************************************************************/ +#ifndef __MXM1120_H__ +#define __MXM1120_H__ + +#include +#include + + /********************************************************************* + register map + **********************************************************************/ +#define M1120_REG_PERSINT (0x00) +#define M1120_VAL_PERSINT_COUNT(n) (n<<4) +#define M1120_VAL_PERSINT_INTCLR (0x01) +#define M1120_REG_INTSRS (0x01) +#define M1120_VAL_INTSRS_INT_ON (0x80) +#define M1120_DETECTION_MODE_INTERRUPT M1120_VAL_INTSRS_INT_ON +#define M1120_VAL_INTSRS_INT_OFF (0x00) +#define M1120_DETECTION_MODE_POLLING M1120_VAL_INTSRS_INT_OFF +#define M1120_VAL_INTSRS_INTTYPE_BESIDE (0x00) +#define M1120_VAL_INTSRS_INTTYPE_WITHIN (0x10) +#define M1120_VAL_INTSRS_SRS_10BIT_0_068mT (0x00) +#define M1120_VAL_INTSRS_SRS_10BIT_0_034mT (0x01) +#define M1120_VAL_INTSRS_SRS_10BIT_0_017mT (0x02) +#define M1120_VAL_INTSRS_SRS_10BIT_0_009mT (0x03) +#define M1120_VAL_INTSRS_SRS_10BIT_0_004mT (0x04) +#define M1120_VAL_INTSRS_SRS_8BIT_0_272mT (0x00) +#define M1120_VAL_INTSRS_SRS_8BIT_0_136mT (0x01) +#define M1120_VAL_INTSRS_SRS_8BIT_0_068mT (0x02) +#define M1120_VAL_INTSRS_SRS_8BIT_0_036mT (0x03) +#define M1120_VAL_INTSRS_SRS_8BIT_0_016mT (0x04) + +#define M1120_REG_LTHL (0x02) +/* [7:0] LTHL : low byte of low threshold value */ + +#define M1120_REG_LTHH (0x03) +/* [7:6] LTHH : high 2bits of low threshold value with sign */ + +#define M1120_REG_HTHL (0x04) +/* [7:0] HTHL : low byte of high threshold value */ + +#define M1120_REG_HTHH (0x05) +/* [7:6] HTHH : high 2bits of high threshold value with sign */ + +#define M1120_REG_I2CDIS (0x06) +#define M1120_VAL_I2CDISABLE (0x37) +/* [7:0] I2CDIS : disable i2c */ + +#define M1120_REG_SRST (0x07) +#define M1120_VAL_SRST_RESET (0x01) +/* [0] SRST = 1 : soft reset */ + +#define M1120_REG_OPF (0x08) +#define M1120_VAL_OPF_FREQ_20HZ (0x00) +#define M1120_VAL_OPF_FREQ_10HZ (0x10) +#define M1120_VAL_OPF_FREQ_6_7HZ (0x20) +#define M1120_VAL_OPF_FREQ_5HZ (0x30) +#define M1120_VAL_OPF_FREQ_80HZ (0x40) +#define M1120_VAL_OPF_FREQ_40HZ (0x50) +#define M1120_VAL_OPF_FREQ_26_7HZ (0x60) +#define M1120_VAL_OPF_EFRD_ON (0x08) +#define M1120_VAL_OPF_BIT_8 (0x02) +#define M1120_VAL_OPF_BIT_10 (0x00) +#define M1120_VAL_OPF_HSSON_ON (0x01) +#define M1120_VAL_OPF_HSSON_OFF (0x00) + +#define M1120_REG_DID (0x09) +#define M1120_VAL_DID (0x9C) +/* [7:0] DID : Device ID */ + +#define M1120_REG_INFO (0x0A) +/* [7:0] INFO : Information about IC */ + +#define M1120_REG_ASA (0x0B) +/* [7:0] ASA : Hall Sensor sensitivity adjustment */ + +#define M1120_REG_ST1 (0x10) +#define M1120_VAL_ST1_DRDY (0x01) +/* [4] INTM : status of interrupt mode + [1] BITM : status of resolution + [0] DRDY : status of data ready */ + +#define M1120_REG_HSL (0x11) +/* [7:0] HSL : low byte of hall sensor measurement data */ + +#define M1120_REG_HSH (0x12) +/* [7:6] HSL : high 2bits of hall sensor measurement data with sign */ + + + + /********************************************************************* + define specific parameters to use with step motor in front camera + **********************************************************************/ +#define M1120_DRIVER_NAME_UP "m1120_up" +#define M1120_DRIVER_NAME_DOWN "m1120_down" + +#define M1120_DETECTION_MODE M1120_DETECTION_MODE_INTERRUPT +#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_WITHIN +#define M1120_SENSITIVITY_TYPE M1120_VAL_INTSRS_SRS_10BIT_0_034mT +#define M1120_PERSISTENCE_COUNT (0x40) +#define M1120_OPERATION_FREQUENCY M1120_VAL_OPF_FREQ_80HZ +#define M1120_OPERATION_RESOLUTION M1120_VAL_OPF_BIT_10 + +#define M1120_DELAY_MAX (200) // ms +#define M1120_DELAY_MIN (20) // ms + +#define M1120_I2C_BUF_SIZE (17) +#define M1120_REG_NUM (15) + +//MagnaChip Hall Sensor power supply VDD 2.7V~3.6V, VIO 1.65~VDD +#define M1120_VDD_MIN_UV 2700000 +#define M1120_VDD_MAX_UV 3600000 +#define M1120_VIO_MIN_UV 1650000 +#define M1120_VIO_MAX_UV 3600000 + + /********************************************************************* + define struct data type + **********************************************************************/ +enum { + OPERATION_MODE_POWERDOWN, + OPERATION_MODE_MEASUREMENT, + OPERATION_MODE_FUSEROMACCESS +}; + +typedef union { + struct { + unsigned char persint; + unsigned char intsrs; + unsigned char lthl; + unsigned char lthh; + unsigned char hthl; + unsigned char hthh; + unsigned char i2cdis; + unsigned char srst; + unsigned char opf; + unsigned char did; + unsigned char info; + unsigned char asa; + unsigned char st1; + unsigned char hsl; + unsigned char hsh; + } map; + unsigned char array[M1120_REG_NUM]; +} m1120_reg_t; + +typedef struct { + struct i2c_client* client; + m1120_reg_t reg; + bool irq_enabled; + int power_vdd; + int irq; + int irq_gpio; + struct regulator* vdd; + bool power_enabled; + atomic_t device_enable; +} dhall_data_t; + +#endif // __MXM1120_H__ + diff --git a/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120_down.c b/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120_down.c new file mode 100644 index 0000000000000000000000000000000000000000..80159f7419ff8698a5ef30eefa6875fe5dffc5d5 --- /dev/null +++ b/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120_down.c @@ -0,0 +1,1003 @@ +/**************************************************************************************** +** Copyright (C), 2013-2018, ONEPLUS +** File : oneplus_m1120_down.c +** +** Description : +** Definitions for m1120 digital hall_down sensor, i2c address is 0x0D +** +****************************************************************************************/ + +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "oneplus_m1120.h" +#include "../oneplus_motor.h" + +/************************begin of declaration************************/ + +/************************static global variable************************/ +static DEFINE_MUTEX(m1120_down_i2c_mutex); +static DEFINE_MUTEX(m1120_down_device_enable_mutex); +static dhall_data_t *g_hall_data; + +/************************function about i2c************************/ +static int m1120_down_i2c_read_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len); +static int m1120_down_i2c_write_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len); +static void m1120_down_short_to_2byte(dhall_data_t* dhall_data, short x, u8 *hbyte, u8 *lbyte); +static short m1120_down_2byte_to_short(dhall_data_t* dhall_data, u8 hbyte, u8 lbyte); + +/************************internal interrupt function************************/ +static irqreturn_t m1120_down_irq_handler(int irq, void *dev_id); +static int m1120_down_clear_interrupt(dhall_data_t* dhall_data); + +/************************internal power control function************************/ +static int m1120_down_power_init(dhall_data_t *data); +static int m1120_down_power_ctl(dhall_data_t* dhall_data, bool on); +static int m1120_down_set_operation_mode(dhall_data_t* dhall_data, int mode); +//static int m1120_down_set_power(struct device *dev, bool on); +static bool m1120_down_get_enable(dhall_data_t* dhall_data); +static void m1120_down_set_enable(dhall_data_t* dhall_data, bool enable); + +/************interface implement for abstract control level************/ +static bool m1120_down_is_power_on(void); +static int m1120_down_parse_dt(dhall_data_t* pdata); +static int m1120_down_set_enable_state(bool enable); +static bool m1120_down_get_enable_state(void); +static int m1120_down_get_real_data(short *data); +static int m1120_down_get_abs_data( short *data); +static int m1120_down_set_detection_mode(u8 mode); +static int m1120_down_enable_irq(bool enable); +static int m1120_down_clear_irq(void); +static int m1120_down_get_irq_state(void); +static bool m1120_down_update_threshold(int position, short lowthd, short highthd); +static void m1120_down_dump_reg(u8* buf); +static int m1120_down_set_reg(int reg, int val); + +/************************init function************************/ +static int m1120_down_init_device(dhall_data_t* hall_data); +static int m1120_down_reset_device(dhall_data_t* dhall_data); +static int m1120_down_power_init(dhall_data_t* dhall_data); + +/************************end of declaration************************/ + + + /********************************************************************* + function about i2c + **********************************************************************/ +static int m1120_down_i2c_read_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = NULL; + struct i2c_msg msgs[2]={{0},{0}}; + dhall_data_t* p_hall_data = dhall_data; + + if (dhall_data == NULL) { + MOTOR_ERR("m1120_down_i2c_read_block, dhall_data == NULL \n"); + return -EINVAL; + } + client = dhall_data->client; + + if (!client) { + MOTOR_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + MOTOR_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&m1120_down_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len =1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len =len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, (sizeof(msgs) / sizeof(msgs[0]))); + + if (err < 0) { + MOTOR_ERR("i2c_transfer error: (%d %p %d) %d\n",addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&m1120_down_i2c_mutex); + + return err; + +} + +static int m1120_down_i2c_write_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[M1120_I2C_BUF_SIZE] ={0}; + struct i2c_client *client = NULL; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_down_i2c_write_block failed, p_hall_data == NULL \n"); + return -EINVAL; + } + client = p_hall_data->client; + + if (!client) { + MOTOR_ERR("client null \n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + MOTOR_ERR(" length %d exceeds %d \n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&m1120_down_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) { + buf[num++] = data[idx]; + } + + err = i2c_master_send(client, buf, num); + if (err < 0) { + MOTOR_ERR("send command error!! %d\n",err); + } + + //store reg written + if (len == 1) { + switch(addr){ + case M1120_REG_PERSINT: + p_hall_data->reg.map.persint = data[0]; + break; + case M1120_REG_INTSRS: + p_hall_data->reg.map.intsrs = data[0]; + break; + case M1120_REG_LTHL: + p_hall_data->reg.map.lthl = data[0]; + break; + case M1120_REG_LTHH: + p_hall_data->reg.map.lthh = data[0]; + break; + case M1120_REG_HTHL: + p_hall_data->reg.map.hthl = data[0]; + break; + case M1120_REG_HTHH: + p_hall_data->reg.map.hthh = data[0]; + break; + case M1120_REG_I2CDIS: + p_hall_data->reg.map.i2cdis = data[0]; + break; + case M1120_REG_SRST: + p_hall_data->reg.map.srst = data[0]; + break; + case M1120_REG_OPF: + p_hall_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&m1120_down_i2c_mutex); + return err; +} + +static void m1120_down_short_to_2byte(dhall_data_t* dhall_data, short x, u8 *hbyte, u8 *lbyte) +{ + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_down_short_to_2byte failed, p_hall_data == NULL \n"); + return ; + } + + if ((p_hall_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + //8 bit + if (x < -128) { + x = -128; + } else if(x > 127) { + x = 127; + } + + if (x >= 0) { + *lbyte = x & 0x7F; + } else { + *lbyte = ( (0x80 - (x*(-1))) & 0x7F ) | 0x80; + } + *hbyte = 0x00; + } else { + //10 bit + if (x < -512) { + x = -512; + } else if (x > 511) { + x = 511; + } + + if (x >=0 ) { + *lbyte = x & 0xFF; + *hbyte = (((x & 0x100) >> 8) & 0x01) << 6; + } else { + *lbyte = (0x0200 - (x*(-1))) & 0xFF; + *hbyte = ((((0x0200 - (x*(-1))) & 0x100) >> 8) << 6) | 0x80; + } + } +} + +static short m1120_down_2byte_to_short(dhall_data_t* dhall_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_down_2byte_to_short failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + if( (p_hall_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + //8 bit + x = lbyte & 0x7F; + if (lbyte & 0x80) { + x -= 0x80; + } + } else { + //10 bit + x = (((hbyte & 0x40) >> 6) << 8 ) | lbyte; + if (hbyte & 0x80) { + x -= 0x200; + } + } + + return x; +} + + /********************************************************************* + internal interrupt function + **********************************************************************/ +static irqreturn_t m1120_down_irq_handler(int irq, void *dev_id) +{ + MOTOR_LOG("call \n"); + + if (g_hall_data == NULL) { + MOTOR_ERR("m1120_down_irq_handler failed, g_hall_data == NULL \n"); + return -EINVAL; + } + + disable_irq_nosync(g_hall_data->irq); + oneplus_dhall_irq_handler(HALL_DOWN); + + return IRQ_HANDLED; +} + +static int m1120_down_clear_interrupt(dhall_data_t* dhall_data) +{ + int err = -1; + u8 data = 0x00; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("p_hall_data == NULL \n"); + return -EINVAL; + } + + data = p_hall_data->reg.map.persint | 0x01; + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_PERSINT, &data,1); + + return err; +} + + /********************************************************************* + internal power control function + **********************************************************************/ +static int m1120_down_power_ctl(dhall_data_t* dhall_data, bool on) +{ + int err = -1; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL ) { + MOTOR_ERR("m1120_down_set_enable failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + //we don't need to set vio power since S4A will always-on + if (!on && p_hall_data->power_enabled) { + err = regulator_disable(p_hall_data->vdd); + if (err) { + MOTOR_ERR("regulator vdd disable failed err=%d \n", err); + return err; + } + + p_hall_data->power_enabled = on; + } else if (on && !p_hall_data->power_enabled) { + err = regulator_enable(p_hall_data->vdd); + if (err) { + MOTOR_ERR("regulator vdd enable failed err=%d\n", err); + return err; + } + msleep(10); // wait 10ms + p_hall_data->power_enabled = on; + } else { + MOTOR_LOG("power on=%d. enabled=%d\n", on, p_hall_data->power_enabled); + } + + return err; +} + +// static int m1120_down_set_power(struct device *dev, bool on) +// { +// m1120_down_power_ctl(g_hall_data, on); + +// return 0; +// } + + +static int m1120_down_set_operation_mode(dhall_data_t* dhall_data, int mode) +{ + dhall_data_t* p_hall_data = dhall_data; + u8 opf = p_hall_data->reg.map.opf; + int err = -1; + + if (p_hall_data == NULL ) { + MOTOR_ERR("m1120_down_set_enable failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + switch (mode) { + case OPERATION_MODE_POWERDOWN: + opf &= (0xFF - M1120_VAL_OPF_HSSON_ON); + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_OPF, &opf, 1); + MOTOR_LOG("operation mode chnage to OPERATION_MODE_POWERDOWN"); + break; + + case OPERATION_MODE_MEASUREMENT: + opf &= (0xFF - M1120_VAL_OPF_EFRD_ON); + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_OPF, &opf, 1); + MOTOR_LOG("operation mode chnage to OPERATION_MODE_MEASUREMENT"); + break; + + case OPERATION_MODE_FUSEROMACCESS: + opf |= M1120_VAL_OPF_EFRD_ON; + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_OPF, &opf, 1); + MOTOR_LOG("operation mode chnage to OPERATION_MODE_FUSEROMACCESS"); + break; + + default : + MOTOR_ERR("unknow operation mode, mode : %d", mode); + } + + MOTOR_LOG("opf = ox%x \n", opf); + + return err; +} + +static bool m1120_down_get_enable(dhall_data_t* dhall_data) +{ + dhall_data_t* p_hall_data = dhall_data; + int enable = -1; + + if (p_hall_data == NULL ) { + MOTOR_ERR("m1120_down_set_enable failed, p_hall_data == NULL \n"); + return false; + } + mutex_lock(&m1120_down_device_enable_mutex); + + enable = atomic_read(&p_hall_data->device_enable); + + mutex_unlock(&m1120_down_device_enable_mutex); + + return enable > 0 ? true : false; +} + +//需è¦çœ‹çœ‹é€™å€‹æ€Žéº¼æž +static void m1120_down_set_enable(dhall_data_t* dhall_data, bool enable) +{ + dhall_data_t* p_hall_data = dhall_data; + int p_enable = enable ? 1 : 0; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_down_set_enable failed, p_hall_data == NULL || p_hall_data->client == NULL \n"); + return; + } + + mutex_lock(&m1120_down_device_enable_mutex);// add mutex for what ?? + MOTOR_LOG("m1120 down enable : %d\n", p_enable); + if (enable) { + //enable if state will be changed + if (!atomic_cmpxchg(&p_hall_data->device_enable, 0, 1)) { + m1120_down_set_operation_mode(p_hall_data, OPERATION_MODE_MEASUREMENT); + } + } else { + //disable if state will be changed + if (atomic_cmpxchg(&p_hall_data->device_enable, 1, 0)) { + m1120_down_set_operation_mode(p_hall_data, OPERATION_MODE_POWERDOWN); + } + } + atomic_set(&p_hall_data->device_enable, p_enable); + + mutex_unlock(&m1120_down_device_enable_mutex); +} + + /********************************************************************* + interface implement for onplus_motor.c + **********************************************************************/ +static bool m1120_down_get_enable_state(void) +{ + if (g_hall_data == NULL) { + MOTOR_LOG("m1120_down_get_enable_state failed, g_hall_data == NULL \n"); + return false; + } + + return m1120_down_get_enable(g_hall_data) ; +} + +static int m1120_down_set_enable_state(bool enable) +{ + if (g_hall_data == NULL) { + MOTOR_LOG("m1120_down_set_enable_state failed, g_hall_data == NULL \n"); + return false; + } + + MOTOR_LOG("set m1120_down enable : %d", enable ? 1 : 0); + m1120_down_set_enable(g_hall_data, enable); + + return 0; +} + +static bool m1120_down_is_power_on(void) +{ + if (g_hall_data == NULL) { + MOTOR_LOG("get m1120_down_is_power_on state failed, g_hall_data == NULL \n"); + return false; + } + + return g_hall_data->power_enabled > 0 ? true : false; +} +static int m1120_down_get_real_data(short* data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + + if(!g_hall_data) { + MOTOR_ERR("g_hall_data == NULL"); + return -1; + } + + //read data + err = m1120_down_i2c_read_block(g_hall_data, M1120_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + MOTOR_ERR("m1120_down get data fail, err : %d \n",err); + return err; + } + + //collect data + if (buf[0] & 0x01) { + value = m1120_down_2byte_to_short(g_hall_data, buf[2], buf[1]); + } else { + MOTOR_ERR("m1120: st1(0x%02X) is not DRDY.\n", buf[0]); + return -1; + } + + *data = value; + + MOTOR_LOG("value : %d", value); + return 0; +} + +static int m1120_down_get_abs_data(short* data) +{ + short value = 0; + int err = -1; + + err = m1120_down_get_real_data(&value); + if (err < 0) { + MOTOR_ERR("m1120_down get abs data filed, err : %d \n", err); + return err; + } + + + value = abs(value); + *data = value; + MOTOR_LOG("value : %d", value); + + return 0; +} + +static int m1120_down_set_detection_mode(u8 mode) +{ + u8 data = 0; + int err = 0; + + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + MOTOR_LOG("m1120 detection mode : %s, irq_enabled : %d\n", (mode == 0)? "POLLING":"INTERRUPT", g_hall_data->irq_enabled); + if(mode & DETECTION_MODE_INTERRUPT) { + if (!g_hall_data->irq_enabled) { + data = g_hall_data->reg.map.intsrs | M1120_DETECTION_MODE_INTERRUPT; + err = m1120_down_i2c_write_block(g_hall_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + MOTOR_ERR("config interupt fail, err : %d \n",err); + return err; + } + err = m1120_down_clear_interrupt(g_hall_data); + if (err < 0) { + MOTOR_ERR("clear interupt fail, err : %d \n",err); + return err; + } + + //requst irq + if (request_irq(g_hall_data->irq, &m1120_down_irq_handler, IRQ_TYPE_LEVEL_LOW, "m1120_down", (void *)g_hall_data->client)) { + MOTOR_ERR("IRQ LINE NOT AVAILABLE!! \n"); + return -EINVAL; + } + irq_set_irq_wake(g_hall_data->irq, 1); + + g_hall_data->irq_enabled = 1; + } + } else { + if (g_hall_data->irq_enabled) { + data = g_hall_data->reg.map.intsrs & (0xFF - M1120_DETECTION_MODE_INTERRUPT); + + err = m1120_down_i2c_write_block(g_hall_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + MOTOR_ERR("config interupt fail, err : %d \n",err); + return err; + } + + disable_irq(g_hall_data->irq); + free_irq(g_hall_data->irq, NULL); + + g_hall_data->irq_enabled = 0; + } + } + + return 0; +} +static int m1120_down_enable_irq(bool enable) +{ + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + if (enable) { + enable_irq(g_hall_data->irq); + } else { + disable_irq_nosync(g_hall_data->irq); + } + + return 0; +} + +static int m1120_down_clear_irq(void) +{ + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + m1120_down_clear_interrupt(g_hall_data); + return 0; +} + +static int m1120_down_get_irq_state(void) +{ + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + return ((g_hall_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static bool m1120_down_update_threshold(int position, short lowthd, short highthd) +{ + + u8 lthh, lthl, hthh, hthl; + int err = 0; + + if (g_hall_data == NULL) { + MOTOR_LOG("g_hall_data == NULL \n"); + return -EINVAL; + } + MOTOR_LOG("m1120_down ,low: %d, high :%d, intsrs : %d \n",lowthd, highthd, g_hall_data->reg.map.intsrs); + + err = m1120_down_clear_interrupt(g_hall_data); + + if (g_hall_data->reg.map.intsrs & M1120_VAL_INTSRS_INTTYPE_WITHIN) { + + m1120_down_short_to_2byte(g_hall_data, highthd, &hthh, &hthl); + m1120_down_short_to_2byte(g_hall_data, lowthd, <hh, <hl); + err |= m1120_down_i2c_write_block(g_hall_data, M1120_REG_HTHH,&hthh, 1); + err |= m1120_down_i2c_write_block(g_hall_data, M1120_REG_HTHL,&hthl, 1); + err |= m1120_down_i2c_write_block(g_hall_data, M1120_REG_LTHH,<hh, 1); + err |= m1120_down_i2c_write_block(g_hall_data, M1120_REG_LTHL,<hl, 1); + } + + if (err < 0) { + MOTOR_ERR("update threshold fail, err : %d\n",err); + return false; + } + + return true; +} + +static void m1120_down_dump_reg(u8* buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + if (g_hall_data == NULL) { + MOTOR_LOG("g_hall_data == NULL \n"); + return ; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = m1120_down_i2c_read_block(g_hall_data, i, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + + sprintf(_buf, "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + sprintf(buf, "%s\n", buffer); + MOTOR_LOG("%s \n",buf); + + return ; +} + +static int m1120_down_set_reg(int reg, int val) +{ + u8 data = (u8)val; + + MOTOR_LOG("reg : %d, val : %d", reg, val); + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + m1120_down_i2c_write_block(g_hall_data, (u8)reg, &data,1); + + return 0; +} + +struct oneplus_hall_operations m1120_down_ops = { + .name = "m1120_down", + .is_power_on = m1120_down_is_power_on, + .set_hall_enable_state = m1120_down_set_enable_state, + .get_hall_enable_state = m1120_down_get_enable_state, + .get_data_real = m1120_down_get_real_data, + .get_data_abs = m1120_down_get_abs_data, + .set_detection_mode = m1120_down_set_detection_mode, + .enable_irq = m1120_down_enable_irq, + .clear_irq = m1120_down_clear_irq, + .get_irq_state = m1120_down_get_irq_state, + .update_threshold = m1120_down_update_threshold, + .dump_regs = m1120_down_dump_reg, + .set_reg = m1120_down_set_reg +}; + + /********************************************************************* + init function + **********************************************************************/ +static int m1120_down_init_device(dhall_data_t* hall_data) +{ + int err = -1; + dhall_data_t* p_hall_data = hall_data; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_down_init_device failed, p_hall_data == NULL || p_hall_data->client == NULL"); + } + + // err = m1120_down_set_power(p_hall_data, true); + //mutex_lock(&m1120_down_device_enable_mutex); + //parameter init + atomic_set(&p_hall_data->device_enable, 0); + p_hall_data->irq_enabled = 0; + + //reset registers + err = m1120_down_reset_device(p_hall_data); + if (err < 0) { + MOTOR_ERR("m1120_down_init_device failed, err : %d \n", err); + return err; + } + //mutex_unlock(&m1120_down_device_enable_mutex); + MOTOR_LOG("initializing device was success! \n"); + + return 0; +} + +static int m1120_down_reset_device(dhall_data_t* dhall_data) +{ + int err = 0; + u8 id = 0xFF, data = 0x00; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_down_reset_device failed, p_hall_data == NULL || p_hall_data->client == NULL"); + return -EINVAL; + } + + // sw reset + data = M1120_VAL_SRST_RESET; + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_SRST, &data,1); + if (err < 0) { + MOTOR_ERR( "sw-reset failed, err : %d \n", err); + return err; + } + msleep(5); + MOTOR_LOG("wait 5ms after vdd power up \n"); + + // check device id + err = m1120_down_i2c_read_block(p_hall_data, M1120_REG_DID, &id, 1); + if (err < 0) + return err; + if (id != M1120_VAL_DID) { + MOTOR_ERR("current device id(0x%02X) is not M1120 device id(0x%02X) \n", id, M1120_VAL_DID); + return -ENXIO; + } + + //init persint + data = M1120_PERSISTENCE_COUNT; + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_PERSINT, &data,1); + if (err <0) { + MOTOR_ERR("cm1120_down_i2c_write_block error, data : %d \n", data); + return err; + } + //init intsrs + data = M1120_DETECTION_MODE | M1120_SENSITIVITY_TYPE; + if (data & M1120_DETECTION_MODE_INTERRUPT) { + data |= M1120_INTERRUPT_TYPE; + } + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + MOTOR_ERR("cm1120_down_i2c_write_block error, data : %d \n", data); + return err; + } + // init operation mode + data = M1120_OPERATION_FREQUENCY | M1120_OPERATION_RESOLUTION; + err = m1120_down_i2c_write_block(p_hall_data, M1120_REG_OPF, &data, 1); + if (err < 0) { + MOTOR_ERR("m1120_down_i2c_write_block error, data : %d \n", data); + return err; + } + + //set power on mode + m1120_down_set_enable(p_hall_data, true);//TO DO : set disable when boot finish??? + + return err; +} + +static int m1120_down_power_init(dhall_data_t* dhall_data) +{ + int err = -1; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_down_power_init failed, p_hall_data == NULL || p_hall_data->client == NULL"); + return -EINVAL; + } + + //we don't need to set vio power since S4A will always-on + p_hall_data->vdd = regulator_get(&p_hall_data->client->dev, "vdd"); + if (IS_ERR(p_hall_data->vdd)) { + err = PTR_ERR(p_hall_data->vdd); + MOTOR_ERR("regulator get vdd failed, err : %d \n", err); + return err; + } + + if (regulator_count_voltages(p_hall_data->vdd) > 0) { + err = regulator_set_voltage(p_hall_data->vdd, M1120_VDD_MIN_UV, M1120_VDD_MAX_UV); + if (err) { + MOTOR_ERR("regulator set vdd failed, err : %d \n", err); + goto reg_vdd_put; + } + } + + return 0; + +reg_vdd_put: + regulator_put(p_hall_data->vdd); + return err; +} + +static int m1120_down_parse_dt(dhall_data_t* dhall_data) +{ + struct device_node *np = NULL; + u32 temp_val; + int err; + dhall_data_t* p_hall_data = dhall_data; + + MOTOR_LOG("call"); + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_down_parse_dt failed, p_hall_data == NULL || p_hall_data->client == NULL"); + return -EINVAL; + } + + np = p_hall_data->client->dev.of_node; + + //gpio irq request + p_hall_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + MOTOR_LOG("irq_gpio : %d", p_hall_data->irq_gpio); + if (gpio_is_valid(p_hall_data->irq_gpio)) { + err = gpio_request(p_hall_data->irq_gpio, "m1120_down_irq"); + if (err) { + MOTOR_ERR("unable to request gpio : %d", p_hall_data->irq_gpio); + } else { + err = gpio_direction_input(dhall_data->irq_gpio); + msleep(50); + p_hall_data->irq = gpio_to_irq(dhall_data->irq_gpio); + MOTOR_LOG("gpio_to_irq success, irq : %d", p_hall_data->irq); + } + } + + return 0; +} +static int m1120_down_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + dhall_data_t* p_hall_data; + int err = 0; + + MOTOR_LOG("call"); + + //allocation memory for g_hall_data + p_hall_data = kzalloc(sizeof(dhall_data_t), GFP_KERNEL); + if (!p_hall_data) { + MOTOR_ERR("kernel memory alocation was failed \n"); + err = -ENOMEM; + goto error_0; + } + + //config i2c client + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + MOTOR_ERR("i2c_check_functionality was failed \n"); + err = -ENODEV; + goto error_1; + } + i2c_set_clientdata(client, p_hall_data); + p_hall_data->client = client; + g_hall_data = p_hall_data;//save in global val + + if (client->dev.of_node) { + MOTOR_LOG("use client->dev.of_node \n"); + err = m1120_down_parse_dt(p_hall_data); + if (err) { + MOTOR_LOG("failed to parse device tree, go to error_1 \n"); + err = -EINVAL; + goto error_1; + } + } else { + MOTOR_ERR("client->dev.of_node == NULL \n"); + goto error_0; + } + + //power init and set power on for device + p_hall_data->power_enabled = false; + err = m1120_down_power_init(p_hall_data); + if (err) { + MOTOR_ERR("failed to get sensor regulators \n"); + err = -EINVAL; + goto error_1; + } + err = m1120_down_power_ctl(p_hall_data, true); + if (err) { + MOTOR_ERR("failed to enable sensor power \n"); + err = -EINVAL; + goto error_1; + } + + //reset and init device + err = m1120_down_init_device(p_hall_data); + if (err) { + MOTOR_ERR("m1120_down_init_device failed, err : %d \n", err); + goto error_1; + } + MOTOR_LOG( "%s found", id->name); + MOTOR_LOG("%s initialized", M1120_DRIVER_NAME_DOWN); + + //register ops to abstract level + oneplus_register_dhall("m1120_down",&m1120_down_ops); + + MOTOR_LOG("i2c addr : %d \n", client->addr); + MOTOR_LOG("%s was probed \n", M1120_DRIVER_NAME_DOWN); + + return 0; + +error_1: + kfree(p_hall_data); + +error_0: + g_hall_data = NULL; + return err; +} + +static int m1120_down_i2c_drv_remove(struct i2c_client *client) +{ + dhall_data_t* p_hall_data = i2c_get_clientdata(client); + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_down_i2c_drv_remove failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + m1120_down_set_enable(p_hall_data, false); + kfree(p_hall_data); + + return 0; +} + +static const struct i2c_device_id m1120_down_i2c_drv_id_table[] = { + {"m1120_down", 0 }, + { } +}; + +static const struct of_device_id m1120_down_of_match[] = { + { .compatible = "magnachip,mxm1120,down", }, + { }, +}; + +static struct i2c_driver m1120_down_driver = { + .driver = { + .owner = THIS_MODULE, + .name = M1120_DRIVER_NAME_DOWN, + .of_match_table = m1120_down_of_match, + }, + .probe = m1120_down_i2c_drv_probe, + .remove = m1120_down_i2c_drv_remove, + .id_table = m1120_down_i2c_drv_id_table, + //.suspend = m1120_down_i2c_drv_suspend, + //.resume = m1120_down_i2c_drv_resume, +}; + +static int __init m1120_down_driver_init_down(void) +{ + int err = 0; + + err = i2c_add_driver(&m1120_down_driver); + MOTOR_LOG("err : %d \n", err); + return err; +} +module_init(m1120_down_driver_init_down); + +static void __exit m1120_down_driver_exit_down(void) +{ + MOTOR_LOG("call \n"); + i2c_del_driver(&m1120_down_driver); +} +module_exit(m1120_down_driver_exit_down); + + +MODULE_DESCRIPTION("M1120 hallswitch driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("quentin.lin@oneplus.com"); + diff --git a/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120_up.c b/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120_up.c new file mode 100644 index 0000000000000000000000000000000000000000..1171d93bd207c9e8c4925d5b1162ecf7fd1566d6 --- /dev/null +++ b/drivers/oneplus/step_motor/digital_hall_ic/oneplus_m1120_up.c @@ -0,0 +1,1013 @@ +/**************************************************************************************** +** Copyright (C), 2013-2018, ONEPLUS +** File : oneplus_m1120_up.c +** +** Description : +** Definitions for m1120 digital hall_up sensor, i2c address is 0x0C +** +****************************************************************************************/ + +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "oneplus_m1120.h" +#include "../oneplus_motor.h" + +/************************begin of declaration************************/ + +/************************static global variable************************/ +static DEFINE_MUTEX(m1120_up_i2c_mutex); +static DEFINE_MUTEX(m1120_up_device_enable_mutex); +static dhall_data_t *g_hall_data; + +/************************function about i2c************************/ +static int m1120_up_i2c_read_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len); +static int m1120_up_i2c_write_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len); +static void m1120_up_short_to_2byte(dhall_data_t* dhall_data, short x, u8 *hbyte, u8 *lbyte); +static short m1120_up_2byte_to_short(dhall_data_t* dhall_data, u8 hbyte, u8 lbyte); + +/************************internal interrupt function************************/ +static irqreturn_t m1120_up_irq_handler(int irq, void *dev_id); +static int m1120_up_clear_interrupt(dhall_data_t* dhall_data); + +/************************internal power control function************************/ +static int m1120_up_power_init(dhall_data_t *data); +static int m1120_up_power_ctl(dhall_data_t* dhall_data, bool on); +static int m1120_up_set_operation_mode(dhall_data_t* dhall_data, int mode); +//static int m1120_up_set_power(struct device *dev, bool on); +static bool m1120_up_get_enable(dhall_data_t* dhall_data); +static void m1120_up_set_enable(dhall_data_t* dhall_data, bool enable); + +/************interface implement for abstract control level************/ +static bool m1120_up_is_power_on(void); +static int m1120_up_parse_dt(dhall_data_t* pdata); +static int m1120_up_set_enable_state(bool enable); +static bool m1120_up_get_enable_state(void); +static int m1120_up_get_real_data(short *data); +static int m1120_up_get_abs_data( short *data); +static int m1120_up_set_detection_mode(u8 mode); +static int m1120_up_enable_irq(bool enable); +static int m1120_up_clear_irq(void); +static int m1120_up_get_irq_state(void); +static bool m1120_up_update_threshold(int position, short lowthd, short highthd); +static void m1120_up_dump_reg(u8* buf); +static int m1120_up_set_reg(int reg, int val); + +/************************init function************************/ +static int m1120_up_init_device(dhall_data_t* hall_data); +static int m1120_up_reset_device(dhall_data_t* dhall_data); +static int m1120_up_power_init(dhall_data_t* dhall_data); + +/************************end of declaration************************/ + + + /********************************************************************* + function about i2c + **********************************************************************/ +static int m1120_up_i2c_read_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = NULL; + struct i2c_msg msgs[2]={{0},{0}}; + dhall_data_t* p_hall_data = dhall_data; + + if (dhall_data == NULL) { + MOTOR_ERR("m1120_up_i2c_read_block, dhall_data == NULL \n"); + return -EINVAL; + } + client = dhall_data->client; + + if (!client) { + MOTOR_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + MOTOR_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&m1120_up_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len =1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len =len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, (sizeof(msgs) / sizeof(msgs[0]))); + + if (err < 0) { + MOTOR_ERR("i2c_transfer error: (%d %p %d) %d\n",addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&m1120_up_i2c_mutex); + + return err; + +} + +static int m1120_up_i2c_write_block(dhall_data_t* dhall_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[M1120_I2C_BUF_SIZE] ={0}; + struct i2c_client *client = NULL; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_up_i2c_write_block failed, p_hall_data == NULL \n"); + return -EINVAL; + } + client = p_hall_data->client; + + if (!client) { + MOTOR_ERR("client null \n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + MOTOR_ERR(" length %d exceeds %d \n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&m1120_up_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) { + buf[num++] = data[idx]; + } + + err = i2c_master_send(client, buf, num); + if (err < 0) { + MOTOR_ERR("send command error!! %d\n",err); + } + + //store reg written + if (len == 1) { + switch(addr){ + case M1120_REG_PERSINT: + p_hall_data->reg.map.persint = data[0]; + break; + case M1120_REG_INTSRS: + p_hall_data->reg.map.intsrs = data[0]; + break; + case M1120_REG_LTHL: + p_hall_data->reg.map.lthl = data[0]; + break; + case M1120_REG_LTHH: + p_hall_data->reg.map.lthh = data[0]; + break; + case M1120_REG_HTHL: + p_hall_data->reg.map.hthl = data[0]; + break; + case M1120_REG_HTHH: + p_hall_data->reg.map.hthh = data[0]; + break; + case M1120_REG_I2CDIS: + p_hall_data->reg.map.i2cdis = data[0]; + break; + case M1120_REG_SRST: + p_hall_data->reg.map.srst = data[0]; + break; + case M1120_REG_OPF: + p_hall_data->reg.map.opf = data[0]; + break; + } + } + mutex_unlock(&m1120_up_i2c_mutex); + return err; +} + +static void m1120_up_short_to_2byte(dhall_data_t* dhall_data, short x, u8 *hbyte, u8 *lbyte) +{ + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_up_short_to_2byte failed, p_hall_data == NULL \n"); + return ; + } + + if ((p_hall_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + //8 bit + if (x < -128) { + x = -128; + } else if(x > 127) { + x = 127; + } + + if (x >= 0) { + *lbyte = x & 0x7F; + } else { + *lbyte = ( (0x80 - (x*(-1))) & 0x7F ) | 0x80; + } + *hbyte = 0x00; + } else { + //10 bit + if (x < -512) { + x = -512; + } else if (x > 511) { + x = 511; + } + + if (x >=0 ) { + *lbyte = x & 0xFF; + *hbyte = (((x & 0x100) >> 8) & 0x01) << 6; + } else { + *lbyte = (0x0200 - (x*(-1))) & 0xFF; + *hbyte = ((((0x0200 - (x*(-1))) & 0x100) >> 8) << 6) | 0x80; + } + } +} + +static short m1120_up_2byte_to_short(dhall_data_t* dhall_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_up_2byte_to_short failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + if( (p_hall_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + //8 bit + x = lbyte & 0x7F; + if (lbyte & 0x80) { + x -= 0x80; + } + } else { + //10 bit + x = (((hbyte & 0x40) >> 6) << 8 ) | lbyte; + if (hbyte & 0x80) { + x -= 0x200; + } + } + + return x; +} + + /********************************************************************* + internal interrupt function + **********************************************************************/ +static irqreturn_t m1120_up_irq_handler(int irq, void *dev_id) +{ + MOTOR_LOG("call \n"); + + if (g_hall_data == NULL) { + MOTOR_ERR("m1120_up_irq_handler failed, g_hall_data == NULL \n"); + return -EINVAL; + } + + disable_irq_nosync(g_hall_data->irq); + oneplus_dhall_irq_handler(HALL_UP); + + return IRQ_HANDLED; +} + +static int m1120_up_clear_interrupt(dhall_data_t* dhall_data) +{ + int err = -1; + u8 data = 0x00; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL) { + MOTOR_ERR("p_hall_data == NULL \n"); + return -EINVAL; + } + + data = p_hall_data->reg.map.persint | 0x01; + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_PERSINT, &data,1); + + return err; +} + + /********************************************************************* + internal power control function + **********************************************************************/ +static int m1120_up_power_ctl(dhall_data_t* dhall_data, bool on) +{ + int err = -1; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL ) { + MOTOR_ERR("m1120_up_set_enable failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + //we don't need to set vio power since S4A will always-on + if (!on && p_hall_data->power_enabled) { + err = regulator_disable(p_hall_data->vdd); + if (err) { + MOTOR_ERR("regulator vdd disable failed err=%d \n", err); + return err; + } + + p_hall_data->power_enabled = on; + } else if (on && !p_hall_data->power_enabled) { + err = regulator_enable(p_hall_data->vdd); + if (err) { + MOTOR_ERR("regulator vdd enable failed err=%d\n", err); + return err; + } + msleep(10); // wait 10ms + p_hall_data->power_enabled = on; + } else { + MOTOR_LOG("power on=%d. enabled=%d\n", on, p_hall_data->power_enabled); + } + + return err; +} + +// static int m1120_up_set_power(struct device *dev, bool on) +// { +// m1120_up_power_ctl(g_hall_data, on); + +// return 0; +// } + + +static int m1120_up_set_operation_mode(dhall_data_t* dhall_data, int mode) +{ + dhall_data_t* p_hall_data = dhall_data; + u8 opf = p_hall_data->reg.map.opf; + int err = -1; + + if (p_hall_data == NULL ) { + MOTOR_ERR("m1120_up_set_enable failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + switch (mode) { + case OPERATION_MODE_POWERDOWN: + opf &= (0xFF - M1120_VAL_OPF_HSSON_ON); + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_OPF, &opf, 1); + MOTOR_LOG("operation mode chnage to OPERATION_MODE_POWERDOWN"); + break; + + case OPERATION_MODE_MEASUREMENT: + opf &= (0xFF - M1120_VAL_OPF_EFRD_ON); + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_OPF, &opf, 1); + MOTOR_LOG("operation mode chnage to OPERATION_MODE_MEASUREMENT"); + break; + + case OPERATION_MODE_FUSEROMACCESS: + opf |= M1120_VAL_OPF_EFRD_ON; + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_OPF, &opf, 1); + MOTOR_LOG("operation mode chnage to OPERATION_MODE_FUSEROMACCESS"); + break; + + default : + MOTOR_ERR("unknow operation mode, mode : %d", mode); + } + + MOTOR_LOG("opf = ox%x \n", opf); + + return err; +} + +static bool m1120_up_get_enable(dhall_data_t* dhall_data) +{ + dhall_data_t* p_hall_data = dhall_data; + int enable = -1; + + if (p_hall_data == NULL ) { + MOTOR_ERR("m1120_up_set_enable failed, p_hall_data == NULL \n"); + return false; + } + mutex_lock(&m1120_up_device_enable_mutex); + + enable = atomic_read(&p_hall_data->device_enable); + + mutex_unlock(&m1120_up_device_enable_mutex); + + return enable > 0 ? true : false; +} + +//需è¦çœ‹çœ‹é€™å€‹æ€Žéº¼æž +static void m1120_up_set_enable(dhall_data_t* dhall_data, bool enable) +{ + dhall_data_t* p_hall_data = dhall_data; + int p_enable = enable ? 1 : 0; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_up_set_enable failed, p_hall_data == NULL || p_hall_data->client == NULL \n"); + return; + } + MOTOR_LOG("1 \n "); + mutex_lock(&m1120_up_device_enable_mutex);// add mutex for what ?? + MOTOR_LOG("m1120_up enable : %d\n", p_enable); + if (enable) { + //enable if state will be changed + if (!atomic_cmpxchg(&p_hall_data->device_enable, 0, 1)) { + m1120_up_set_operation_mode(p_hall_data, OPERATION_MODE_MEASUREMENT); + } + } else { + //disable if state will be changed + if (atomic_cmpxchg(&p_hall_data->device_enable, 1, 0)) { + m1120_up_set_operation_mode(p_hall_data, OPERATION_MODE_POWERDOWN); + } + } + atomic_set(&p_hall_data->device_enable, p_enable); + MOTOR_LOG("end \n "); + mutex_unlock(&m1120_up_device_enable_mutex); +} + + /********************************************************************* + interface implement for onplus_motor.c + **********************************************************************/ +static bool m1120_up_get_enable_state(void) +{ + if (g_hall_data == NULL) { + MOTOR_LOG("m1120_up_get_enable_state failed, g_hall_data == NULL \n"); + return false; + } + + return m1120_up_get_enable(g_hall_data) ; +} + +static int m1120_up_set_enable_state(bool enable) +{ + if (g_hall_data == NULL) { + MOTOR_LOG("m1120_up_set_enable_state failed, g_hall_data == NULL \n"); + return false; + } + + MOTOR_LOG("set m1120_up enable : %d", enable ? 1 : 0); + m1120_up_set_enable(g_hall_data, enable); + + return 0; +} + +static bool m1120_up_is_power_on(void) +{ + if (g_hall_data == NULL) { + MOTOR_LOG("get m1120_up_is_power_on state failed, g_hall_data == NULL \n"); + return false; + } + + return g_hall_data->power_enabled > 0 ? true : false; +} +static int m1120_up_get_real_data(short* data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + + if(!g_hall_data) { + MOTOR_ERR("g_hall_data == NULL"); + return -1; + } + + //read data + err = m1120_up_i2c_read_block(g_hall_data, M1120_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + MOTOR_ERR("m1120_up get data fail, err : %d \n",err); + return err; + } + + //collect data + if (buf[0] & 0x01) { + value = m1120_up_2byte_to_short(g_hall_data, buf[2], buf[1]); + } else { + MOTOR_ERR("m1120: st1(0x%02X) is not DRDY.\n", buf[0]); + return -1; + } + + *data = value; + + MOTOR_LOG("value : %d", value); + return 0; +} + +static int m1120_up_get_abs_data(short* data) +{ + short value = 0; + int err = -1; + + err = m1120_up_get_real_data(&value); + if (err < 0) { + MOTOR_ERR("m1120_up get abs data filed, err : %d \n", err); + return err; + } + + value = abs(value); + *data = value; + + MOTOR_LOG("value : %d", value); + + return 0; +} + +static int m1120_up_set_detection_mode(u8 mode) +{ + u8 data = 0; + int err = 0; + + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + MOTOR_LOG("m1120 detection mode : %s, irq_enabled : %d\n", (mode == 0)? "POLLING":"INTERRUPT", g_hall_data->irq_enabled); + if(mode & DETECTION_MODE_INTERRUPT) { + if (!g_hall_data->irq_enabled) { + data = g_hall_data->reg.map.intsrs | M1120_DETECTION_MODE_INTERRUPT; + err = m1120_up_i2c_write_block(g_hall_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + MOTOR_ERR("config interupt fail, err : %d \n",err); + return err; + } + err = m1120_up_clear_interrupt(g_hall_data); + if (err < 0) { + MOTOR_ERR("clear interupt fail, err : %d \n",err); + return err; + } + + //requst irq + if (request_irq(g_hall_data->irq, &m1120_up_irq_handler, IRQ_TYPE_LEVEL_LOW, "m1120_up", (void *)g_hall_data->client)) { + MOTOR_ERR("IRQ LINE NOT AVAILABLE!! \n"); + return -EINVAL; + } + irq_set_irq_wake(g_hall_data->irq, 1); + + g_hall_data->irq_enabled = 1; + } + } else { + if (g_hall_data->irq_enabled) { + data = g_hall_data->reg.map.intsrs & (0xFF - M1120_DETECTION_MODE_INTERRUPT); + + err = m1120_up_i2c_write_block(g_hall_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + MOTOR_ERR("config interupt fail, err : %d \n",err); + return err; + } + + disable_irq(g_hall_data->irq); + free_irq(g_hall_data->irq, NULL); + + g_hall_data->irq_enabled = 0; + } + } + + return 0; +} +static int m1120_up_enable_irq(bool enable) +{ + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + if (enable) { + enable_irq(g_hall_data->irq); + } else { + disable_irq_nosync(g_hall_data->irq); + } + + return 0; +} + +static int m1120_up_clear_irq(void) +{ + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + m1120_up_clear_interrupt(g_hall_data); + return 0; +} + +static int m1120_up_get_irq_state(void) +{ + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + return ((g_hall_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static bool m1120_up_update_threshold(int position, short lowthd, short highthd) +{ + + u8 lthh, lthl, hthh, hthl; + int err = 0; + + if (g_hall_data == NULL) { + MOTOR_LOG("g_hall_data == NULL \n"); + return -EINVAL; + } + MOTOR_LOG("m1120_up ,low: %d, high :%d, intsrs : %d \n",lowthd, highthd, g_hall_data->reg.map.intsrs); + + err = m1120_up_clear_interrupt(g_hall_data); + + if (g_hall_data->reg.map.intsrs & M1120_VAL_INTSRS_INTTYPE_WITHIN) { + + m1120_up_short_to_2byte(g_hall_data, highthd, &hthh, &hthl); + m1120_up_short_to_2byte(g_hall_data, lowthd, <hh, <hl); + err |= m1120_up_i2c_write_block(g_hall_data, M1120_REG_HTHH,&hthh, 1); + err |= m1120_up_i2c_write_block(g_hall_data, M1120_REG_HTHL,&hthl, 1); + err |= m1120_up_i2c_write_block(g_hall_data, M1120_REG_LTHH,<hh, 1); + err |= m1120_up_i2c_write_block(g_hall_data, M1120_REG_LTHL,<hl, 1); + } + + if (err < 0) { + MOTOR_ERR("update threshold fail, err : %d\n",err); + return false; + } + + return true; +} + +static void m1120_up_dump_reg(u8* buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + if (g_hall_data == NULL) { + MOTOR_LOG("g_hall_data == NULL \n"); + return ; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = m1120_up_i2c_read_block(g_hall_data, i, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + + sprintf(_buf, "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + sprintf(buf, "%s\n", buffer); + MOTOR_LOG("%s \n",buf); + + return ; +} + +static int m1120_up_set_reg(int reg, int val) +{ + u8 data = (u8)val; + + MOTOR_LOG("reg : %d, val : %d", reg, val); + if(g_hall_data == NULL) { + MOTOR_ERR("g_hall_data == NULL"); + return -EINVAL; + } + + m1120_up_i2c_write_block(g_hall_data, (u8)reg, &data,1); + + return 0; +} + +struct oneplus_hall_operations m1120_up_ops = { + .name = "m1120_up", + .is_power_on = m1120_up_is_power_on, + .set_hall_enable_state = m1120_up_set_enable_state, + .get_hall_enable_state = m1120_up_get_enable_state, + .get_data_real = m1120_up_get_real_data, + .get_data_abs = m1120_up_get_abs_data, + .set_detection_mode = m1120_up_set_detection_mode, + .enable_irq = m1120_up_enable_irq, + .clear_irq = m1120_up_clear_irq, + .get_irq_state = m1120_up_get_irq_state, + .update_threshold = m1120_up_update_threshold, + .dump_regs = m1120_up_dump_reg, + .set_reg = m1120_up_set_reg +}; + + /********************************************************************* + init function + **********************************************************************/ +static int m1120_up_init_device(dhall_data_t* hall_data) +{ + int err = -1; + dhall_data_t* p_hall_data = hall_data; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_up_init_device failed, p_hall_data == NULL || p_hall_data->client == NULL"); + } + + //err = m1120_up_set_power(p_hall_data, true); + //mutex_lock(&m1120_up_device_enable_mutex); + + //parameter init + atomic_set(&p_hall_data->device_enable, 0); + p_hall_data->irq_enabled = 0; + + //reset registers + err = m1120_up_reset_device(p_hall_data); + if (err < 0) { + MOTOR_ERR("m1120_up_init_device failed, err : %d \n", err); + return err; + } + + //mutex_unlock(&m1120_up_device_enable_mutex); + + MOTOR_LOG("initializing device was success! \n"); + + return 0; +} + +static int m1120_up_reset_device(dhall_data_t* dhall_data) +{ + int err = 0; + u8 id = 0xFF, data = 0x00; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_up_reset_device failed, p_hall_data == NULL || p_hall_data->client == NULL"); + return -EINVAL; + } + + // sw reset + data = M1120_VAL_SRST_RESET; + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_SRST, &data,1); + if (err < 0) { + MOTOR_ERR( "sw-reset failed, err : %d \n", err); + return err; + } + msleep(5); + MOTOR_LOG("wait 5ms after vdd power up \n"); + + // check device id + err = m1120_up_i2c_read_block(p_hall_data, M1120_REG_DID, &id, 1); + MOTOR_LOG("1 \n"); + if (err < 0) + return err; + if (id != M1120_VAL_DID) { + MOTOR_ERR("current device id(0x%02X) is not M1120 device id(0x%02X) \n", id, M1120_VAL_DID); + return -ENXIO; + } + + //init persint + MOTOR_LOG("2 \n "); + data = M1120_PERSISTENCE_COUNT; + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_PERSINT, &data,1); + if (err <0) { + MOTOR_ERR("cm1120_up_i2c_write_block error, data : %d \n", data); + return err; + } + //init intsrs + MOTOR_LOG("3 \n "); + data = M1120_DETECTION_MODE | M1120_SENSITIVITY_TYPE; + if (data & M1120_DETECTION_MODE_INTERRUPT) { + data |= M1120_INTERRUPT_TYPE; + } + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + MOTOR_ERR("cm1120_up_i2c_write_block error, data : %d \n", data); + return err; + } + // init operation mode + MOTOR_LOG("4 \n "); + data = M1120_OPERATION_FREQUENCY | M1120_OPERATION_RESOLUTION; + err = m1120_up_i2c_write_block(p_hall_data, M1120_REG_OPF, &data, 1); + if (err < 0) { + MOTOR_ERR("cm1120_up_i2c_write_block error, data : %d \n", data); + return err; + } + + //set power on mode + //这边若ä¸è¡Œçš„è¯,釿–°æžçš„函数 + m1120_up_set_enable(p_hall_data, true);//TO DO : set disable when boot finish??? + MOTOR_LOG("5 \n "); + return err; +} + +static int m1120_up_power_init(dhall_data_t* dhall_data) +{ + int err = -1; + dhall_data_t* p_hall_data = dhall_data; + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_up_power_init failed, p_hall_data == NULL || p_hall_data->client == NULL"); + return -EINVAL; + } + + //we don't need to set vio power since S4A will always-on + p_hall_data->vdd = regulator_get(&p_hall_data->client->dev, "vdd"); + if (IS_ERR(p_hall_data->vdd)) { + err = PTR_ERR(p_hall_data->vdd); + MOTOR_ERR("regulator get vdd failed, err : %d \n", err); + return err; + } + + if (regulator_count_voltages(p_hall_data->vdd) > 0) { + err = regulator_set_voltage(p_hall_data->vdd, M1120_VDD_MIN_UV, M1120_VDD_MAX_UV); + if (err) { + MOTOR_ERR("regulator set vdd failed, err : %d \n", err); + goto reg_vdd_put; + } + } + + return 0; + +reg_vdd_put: + regulator_put(p_hall_data->vdd); + return err; +} + +static int m1120_up_parse_dt(dhall_data_t* dhall_data) +{ + struct device_node *np = NULL; + u32 temp_val; + int err; + dhall_data_t* p_hall_data = dhall_data; + + MOTOR_LOG("call"); + + if (p_hall_data == NULL || p_hall_data->client == NULL) { + MOTOR_ERR("m1120_up_parse_dt failed, p_hall_data == NULL || p_hall_data->client == NULL"); + // MOTOR_ERR("m1120_up_parse_dt failed, p_hall_data == NULL || p_hall_data->client == NULL || " + // "p_hall_data->client->dev == NULL || p_hall_data->client->dev->of_node == NULL"); + + return -EINVAL; + } + + np = p_hall_data->client->dev.of_node; + + //gpio irq request + p_hall_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + MOTOR_LOG("irq_gpio : %d", p_hall_data->irq_gpio); + if (gpio_is_valid(p_hall_data->irq_gpio)) { + err = gpio_request(p_hall_data->irq_gpio, "m1120_up_irq"); + if (err) { + MOTOR_ERR("unable to request gpio : %d", p_hall_data->irq_gpio); + } else { + err = gpio_direction_input(dhall_data->irq_gpio); + msleep(50); + p_hall_data->irq = gpio_to_irq(dhall_data->irq_gpio); + MOTOR_LOG("gpio_to_irq success, irq : %d", p_hall_data->irq); + } + } + + return 0; +} +static int m1120_up_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + dhall_data_t* p_hall_data; + int err = 0; + + MOTOR_LOG("call"); + + //allocation memory for g_hall_data + p_hall_data = kzalloc(sizeof(dhall_data_t), GFP_KERNEL); + if (!p_hall_data) { + MOTOR_ERR("kernel memory alocation was failed \n"); + err = -ENOMEM; + goto error_0; + } + + //config i2c client + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + MOTOR_ERR("i2c_check_functionality was failed \n"); + err = -ENODEV; + goto error_1; + } + i2c_set_clientdata(client, p_hall_data); + p_hall_data->client = client; + g_hall_data = p_hall_data;//save in global val + + if (client->dev.of_node) { + MOTOR_LOG("use client->dev.of_node \n"); + err = m1120_up_parse_dt(p_hall_data); + if (err) { + MOTOR_LOG("failed to parse device tree, go to error_1 \n"); + err = -EINVAL; + goto error_1; + } + } else { + MOTOR_ERR("client->dev.of_node == NULL \n"); + goto error_0; + } + + //power init and set power on for device + p_hall_data->power_enabled = false; + err = m1120_up_power_init(p_hall_data); + if (err) { + MOTOR_ERR("failed to get sensor regulators \n"); + err = -EINVAL; + goto error_1; + } + err = m1120_up_power_ctl(p_hall_data, true); + if (err) { + MOTOR_ERR("failed to enable sensor power \n"); + err = -EINVAL; + goto error_1; + } + + //reset and init device + err = m1120_up_init_device(p_hall_data); + if (err) { + MOTOR_ERR("m1120_up_init_device failed, err : %d \n", err); + goto error_1; + } + MOTOR_LOG( "%s found", id->name); + MOTOR_LOG("%s initialized", M1120_DRIVER_NAME_UP); + + //register ops to abstract level + oneplus_register_dhall("m1120_up",&m1120_up_ops); + + MOTOR_LOG("i2c addr : %d \n", client->addr); + MOTOR_LOG("%s was probed \n", M1120_DRIVER_NAME_UP); + + return 0; + +error_1: + kfree(p_hall_data); + +error_0: + g_hall_data = NULL; + return err; +} + +static int m1120_up_i2c_drv_remove(struct i2c_client *client) +{ + dhall_data_t* p_hall_data = i2c_get_clientdata(client); + + if (p_hall_data == NULL) { + MOTOR_ERR("m1120_up_i2c_drv_remove failed, p_hall_data == NULL \n"); + return -EINVAL; + } + + m1120_up_set_enable(p_hall_data, false); + kfree(p_hall_data); + + return 0; +} + +static const struct i2c_device_id m1120_up_i2c_drv_id_table[] = { + {"m1120_up", 0 }, + { } +}; + +static const struct of_device_id m1120_up_of_match[] = { + { .compatible = "magnachip,mxm1120,up", }, + { }, +}; + +static struct i2c_driver m1120_up_driver = { + .driver = { + .owner = THIS_MODULE, + .name = M1120_DRIVER_NAME_UP, + .of_match_table = m1120_up_of_match, + }, + .probe = m1120_up_i2c_drv_probe, + .remove = m1120_up_i2c_drv_remove, + .id_table = m1120_up_i2c_drv_id_table, + //.suspend = m1120_up_i2c_drv_suspend, + //.resume = m1120_up_i2c_drv_resume, +}; + +static int __init m1120_up_driver_init_up(void) +{ + int err = 0; + + err = i2c_add_driver(&m1120_up_driver); + MOTOR_LOG("err : %d \n", err); + return err; +} +module_init(m1120_up_driver_init_up); + +static void __exit m1120_up_driver_exit_up(void) +{ + MOTOR_LOG("call \n"); + i2c_del_driver(&m1120_up_driver); +} +module_exit(m1120_up_driver_exit_up); + +MODULE_DESCRIPTION("M1120 hallswitch driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("quentin.lin@oneplus.com"); + diff --git a/drivers/oneplus/step_motor/oneplus_motor.c b/drivers/oneplus/step_motor/oneplus_motor.c new file mode 100644 index 0000000000000000000000000000000000000000..1ba5c521cb899868918ad4978e766cf162efae1a --- /dev/null +++ b/drivers/oneplus/step_motor/oneplus_motor.c @@ -0,0 +1,3196 @@ +/**************************************************************************************** +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_motor.c +** +** Description: +** Definitions for m1120 camera motor control layer. +** +****************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#ifdef CONFIG_DRM_MSM +#include +#endif +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) +#include +#endif +#include "oneplus_motor.h" +#include "oneplus_motor_notifier.h" + +/************************static global variable************************/ +static struct oneplus_motor_chip* g_the_chip = NULL; +static DEFINE_MUTEX(motor_running_mutex); +static DEFINE_MUTEX(position_detect_mutex); +static DEFINE_MUTEX(motor_start_mutex); + +/************************fb_notifier************************/ +static void oneplus_motor_notify_state(unsigned long val); +static int fb_notifier_callback(struct notifier_block* nb, unsigned long event, void* data); + +/************************digital_hall control interface************************/ +bool oneplus_dhall_is_power_on(void); +static int oneplus_hall_set_enable_state(unsigned int id, bool enable); +static bool oneplus_hall_get_enable_state(unsigned int id); +static int oneplus_hall_get_abs_data(unsigned int id); +int oneplus_hall_get_real_data(unsigned int id); +int oneplus_dhall_set_detection_mode(unsigned int id, u8 mode); +static int oneplus_hall_enable_irq (unsigned int id, bool enable); +static int oneplus_hall_clear_irq (unsigned int id); +int oneplus_dhall_get_irq_state(unsigned int id); +static int oneplus_hall_update_threshold(unsigned int id, int position, short lowthd, short highthd); +void oneplus_dhall_dump_regs(unsigned int id, u8* buf); +int oneplus_dhall_set_reg(unsigned int id, int reg, int val); + +/************************step_motor control interface************************/ +static int oneplus_motor_set_power (motor_power mode); +static int oneplus_motor_set_direction (int dir); +static int oneplus_motor_set_working_mode (int mode); +//static int oneplus_motor_calculate_pwm_count(int L, int mode); +static int oneplus_motor_pwm_config(int duty_ns, int period_ns); +static int oneplus_motor_pwm_enable(void); +static int oneplus_motor_pwm_disable(void); +int oneplus_motor_get_all_config(int* config, int count); +int oneplus_get_motor_type(void); +void oneplus_set_md_mode_para(int motor_work_mode); + +/************************combine digital_hall and step_motor for logical process************************/ +static void manual_to_auto_down_work(struct work_struct* work); +static void oneplus_set_motor_speed(int speed); +static void oneplus_change_motor_speed(int speed); +static void oneplus_set_motor_direction(int direction); +static void oneplus_set_motor_move_state(int move_state); + +static bool oneplus_motor_run_check(struct oneplus_motor_chip* chip); +static void oneplus_motor_control(int on, int speed, int direction); +static void oneplus_motor_start(void); +static void oneplus_motor_stop(void); +static void oneplus_motor_downward(void); +static void motor_run_work(struct work_struct* work); +static void camera_position_detect_work(struct work_struct* work); +static void free_fall_irq_check_work_func(struct work_struct* work); +static int write_hall_data_to_file(short* hall_up_data, short* hall_down_data, int buf_len, int direction, bool append); +static enum hrtimer_restart motor_stop_timer_func(struct hrtimer* hrtimer); +static enum hrtimer_restart motor_speed_up_timer_func(struct hrtimer* hrtimer); +static enum alarmtimer_restart motor_reset_timer_func(struct alarm* alrm, ktime_t now); +static void oneplus_motor_set_awake(struct oneplus_motor_chip* chip, int id, bool awake); +static void report_position_state(struct oneplus_motor_chip* chip, camera_position_state_event state_event); + +static void oneplus_motor_irq_monitor(struct oneplus_motor_chip* chip); +static irqreturn_t oneplus_free_fall_detect_handler(int irq, void* dev_id); + +/************************node operation by MotorManagerService or user************************/ +//for normal use +static ssize_t motor_direction_store(struct device* pdev, struct device_attribute* attr, + const char* buf, size_t count); +static ssize_t motor_direction_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_enable_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t step_count_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t count); +static ssize_t step_count_show(struct device *dev,struct device_attribute *attr, char *buf); +static ssize_t save_hall_data_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t count); +static ssize_t save_hall_data_show(struct device *dev,struct device_attribute *attr, char *buf); +static ssize_t hall_data_show(struct device* dev,struct device_attribute* attr, char* buf); +static ssize_t motor_move_state_show(struct device* dev, struct device_attribute* attr, char* buf); + +static ssize_t hall_calibration_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t hall_calibration_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t stall_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t stall_steps_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_test_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_test_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t hall_irq_count_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_mode_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t motor_mode_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_manual2auto_switch_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_manual2auto_switch_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t motor_sw_switch_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t motor_sw_switch_show(struct device* dev, struct device_attribute* attr, char* buf); +//for special test +static ssize_t motor_force_move_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +///static ssize_t motor_stop_time_store(struct device* pdev, struct device_attribute* attr, +// const char* buff, size_t count); +//static ssize_t motor_stop_time_show(struct device* dev, struct device_attribute* attr, char* buf); +//static ssize_t motor_initial_time_store(struct device* pdev, struct device_attribute* attr, +// const char* buff, size_t count); +//static ssize_t motor_initial_time_show(struct device* dev, struct device_attribute* attr, char* buf); +//static ssize_t motor_initial_speed_store(struct device* pdev, struct device_attribute* attr, +// const char* buff, size_t count); +//static ssize_t motor_initial_speed_show(struct device* dev, struct device_attribute* attr, char* buf); +//static ssize_t motor_high_speed_store(struct device* pdev, struct device_attribute* attr, +// const char* buff, size_t count); +//static ssize_t motor_high_speed_show(struct device* dev, struct device_attribute* attr, char* buf); +//static ssize_t motor_high_speed_time_store(struct device* pdev, struct device_attribute* attr, +// const char* buff, size_t count); +//static ssize_t motor_high_speed_time_show(struct device* dev,struct device_attribute* attr, char* buf); +static ssize_t motor_slow_down_speed_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t motor_slow_down_speed_show(struct device* dev, struct device_attribute* attr, char* buf); +//not use +// static ssize_t motor_speed_change_switch_store(struct device* pdev, struct device_attribute* attr, +// const char* buff, size_t count); +// static ssize_t motor_speed_change_switch_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t hall_detect_switch_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t hall_detect_switch_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_all_config_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t motor_position_show(struct device* dev, struct device_attribute* attr, char* buf); +static ssize_t hall_all_reg_show(struct device* dev, struct device_attribute* attr, char* buf); + //save for compatibility +static ssize_t motor_change_speed_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t motor_speed_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count); +static ssize_t motor_speed_show(struct device* dev, struct device_attribute* attr, char* buf); + +/************************init function************************/ +static int oneplus_input_dev_init(struct oneplus_motor_chip* chip); +static int oneplus_motor_chip_init(struct oneplus_motor_chip* chip); +static void oneplus_motor_awake_init(struct oneplus_motor_chip* chip); +static void oneplus_motor_free_fall_register(struct oneplus_motor_chip* chip); +static void oneplus_motor_reset_check(struct oneplus_motor_chip* chip); +static void oneplus_parameter_init(struct oneplus_motor_chip* chip); +static int motor_platform_probe(struct platform_device* pdev); +static int motor_platform_remove(struct platform_device* pdev); +static int motor_platform_suspend(struct platform_device* pdev, pm_message_t state); +static int motor_platform_resume(struct platform_device* pdev); +static void motor_platform_shutdown(struct platform_device* pdev); + + +/********************************************************************* + fb_notifier +**********************************************************************/ +static void oneplus_motor_notify_state(unsigned long val) +{ + if (val < MOTOR_UP_EVENT || val > MOTOR_BLOCK_EVENT) + return; + + motor_notifier_call_chain(val); +} + +#ifdef CONFIG_DRM_MSM +static int fb_notifier_callback(struct notifier_block* nb, unsigned long event, void* data) +{ + int blank; + struct msm_drm_notifier* evdata = data; + + if (g_the_chip == NULL) { + return 0; + } + + if (!evdata || (evdata->id != 0)) + return 0; + + if (event == MSM_DRM_EARLY_EVENT_BLANK) { + blank =* (int* )(evdata->data); + if (blank == MSM_DRM_BLANK_UNBLANK) { + g_the_chip->led_on = true; + MOTOR_LOG("led_on %d\n", g_the_chip->led_on); + } else if (blank == MSM_DRM_BLANK_POWERDOWN) { + g_the_chip->led_on = false; + MOTOR_LOG("led_on %d \n", g_the_chip->led_on); + } else { + MOTOR_LOG("receives wrong data EARLY_BLANK:%d \n", blank); + } + } + + return 0; +} +#else +static int fb_notifier_callback(struct notifier_block* nb, unsigned long event, void* data) +{ + int blank; + struct fb_event* evdata = data; + + if (g_the_chip == NULL) { + return 0; + } + + if (evdata && evdata->data) { + if (event == FB_EVENT_BLANK) { + blank =* (int* )evdata->data; + if (blank == FB_BLANK_UNBLANK) { + g_the_chip->led_on = true; + MOTOR_LOG("led_on %d\n", g_the_chip->led_on); + } else if (blank == FB_BLANK_POWERDOWN) { + g_the_chip->led_on = false; + MOTOR_LOG("led_on %d\n", g_the_chip->led_on); + } + } + } + return 0; +} +#endif /*CONFIG_DRM_MSM*/ + +/********************************************************************* + digital_hall control interface +**********************************************************************/ +bool oneplus_dhall_is_power_on(void) +{ + if (g_the_chip == NULL || g_the_chip->hall_down_ops == NULL + || g_the_chip->hall_down_ops->is_power_on == NULL + || g_the_chip->hall_up_ops == NULL + || g_the_chip->hall_up_ops->is_power_on == NULL) { + + MOTOR_ERR("null pointer"); + + return false; + } else { + if (g_the_chip->hall_down_ops->is_power_on() && g_the_chip->hall_up_ops->is_power_on()) + return true; + else + return false; + } + +} + +static int oneplus_hall_set_enable_state(unsigned int id, bool enable) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id) { + case HALL_DOWN : + if(g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->set_hall_enable_state == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->set_hall_enable_state == NULL"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->set_hall_enable_state(enable); + } + case HALL_UP : + if(g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->set_hall_enable_state == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->set_hall_enable_state == NULL"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->set_hall_enable_state(enable); + } + default : + return -EINVAL; + } + + return -EINVAL; +} + +static bool oneplus_hall_get_enable_state(unsigned int id) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id) { + case HALL_DOWN : + if(g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_hall_enable_state == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_hall_enable_state == NULL"); + return false; + } else { + return g_the_chip->hall_down_ops->get_hall_enable_state(); + } + case HALL_UP : + if(g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_hall_enable_state == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_hall_enable_state == NULL"); + return false; + } else { + return g_the_chip->hall_up_ops->get_hall_enable_state(); + } + default : + return false; + } + + return false; +} + +static int oneplus_hall_get_abs_data(unsigned int id) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_data_abs == NULL) { + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_data_abs == NULL"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->get_data_abs(&g_the_chip->hall_down_data); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_data_abs == NULL) { + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_data_abs == NULL"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->get_data_abs(&g_the_chip->hall_up_data); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oneplus_hall_get_real_data(unsigned int id) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_data_real == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_data_real == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->get_data_real(&g_the_chip->hall_down_data); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_data_real == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_data_real == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->get_data_real(&g_the_chip->hall_up_data); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oneplus_dhall_set_detection_mode(unsigned int id, u8 mode) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->set_detection_mode == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->set_detection_mode == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->set_detection_mode(mode); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->set_detection_mode == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->set_detection_mode == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->set_detection_mode(mode); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + + +//should use in irq handle +int oneplus_hall_enable_irq (unsigned int id, bool enable) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->enable_irq == NULL){ + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->enable_irq == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->enable_irq(enable); + } + + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->enable_irq == NULL) { + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->enable_irq == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->enable_irq(enable); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oneplus_hall_clear_irq (unsigned int id) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + MOTOR_LOG("oneplus_hall_clear_irq \n"); + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->enable_irq == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->enable_irq == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->clear_irq(); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->enable_irq == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->enable_irq == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->clear_irq(); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oneplus_dhall_get_irq_state(unsigned int id) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_irq_state == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->get_irq_state == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->get_irq_state(); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_irq_state == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->get_irq_state == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->get_irq_state(); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +static int oneplus_hall_update_threshold(unsigned int id, int position, short lowthd, short highthd) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + MOTOR_LOG("lowthd : %d, highthd : %d, is_mag_positive : %d", lowthd, highthd, g_the_chip->is_mag_positive); + //mag is negative + if (!g_the_chip->is_mag_positive) { + if (highthd != 511 ) { + lowthd = -highthd; + highthd = 511; + } + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->update_threshold == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->update_threshold == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->update_threshold(position,lowthd,highthd); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->update_threshold == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->update_threshold == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->update_threshold(position,lowthd,highthd); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +void oneplus_dhall_dump_regs(unsigned int id, u8* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->dump_regs == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->dump_regs == NULL \n"); + return; + } else { + g_the_chip->hall_down_ops->dump_regs(buf); + } + break; + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->dump_regs == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->dump_regs == NULL \n"); + return; + } else { + g_the_chip->hall_up_ops->dump_regs(buf); + } + break; + default: + MOTOR_ERR("id : %d is not correct \n", id); + return; + + } + + return; +} + +int oneplus_dhall_set_reg(unsigned int id, int reg, int val) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return -EINVAL; + } + + switch (id){ + case HALL_DOWN: + if (g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->set_reg == NULL) { + + MOTOR_ERR("g_the_chip->hall_down_ops == NULL || g_the_chip->hall_down_ops->set_reg == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_down_ops->set_reg(reg,val); + } + case HALL_UP: + if (g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->set_reg == NULL) { + + MOTOR_ERR("g_the_chip->hall_up_ops == NULL || g_the_chip->hall_up_ops->set_reg == NULL \n"); + return -EINVAL; + } else { + return g_the_chip->hall_up_ops->set_reg(reg,val); + } + default: + MOTOR_ERR("id : %d is not correct \n", id); + return -EINVAL; + } + + return -EINVAL; +} + +/********************************************************************* + step_motor control interface +**********************************************************************/ +static int oneplus_motor_set_power(motor_power mode) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->set_power == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || set_power == NULL"); + return -EINVAL; + } else { + MOTOR_ERR("oneplus_motor_set_power\n"); + return g_the_chip->motor_ops->set_power(mode); + } +} + +static int oneplus_motor_set_direction (int dir) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops->set_direction == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops->set_direction == NULL"); + return -EINVAL; + } else { + return g_the_chip->motor_ops->set_direction(dir); + } +} + +static int oneplus_motor_set_working_mode (int mode) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->set_working_mode == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || set_working_mode == NULL"); + return -EINVAL; + } else { + return g_the_chip->motor_ops->set_working_mode(mode); + } + +} + +// static int oneplus_motor_calculate_pwm_count(int L, int mode) +// { +// if (g_the_chip == NULL || g_the_chip->motor_ops == NULL +// || g_the_chip->motor_ops->set_working_mode == NULL) { + +// MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || set_working_mode == NULL"); +// return 0; +// } else { +// return g_the_chip->motor_ops->calculate_pwm_count(L, mode); +// } + +// } + +static int oneplus_motor_pwm_config(int duty_ns, int period_ns) +{ + MOTOR_LOG("duty_ns : %d, period_ns : %d\n", duty_ns, period_ns); + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->calculate_pwm_count == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || calculate_pwm_count == NULL"); + return -EINVAL; + } else { + return g_the_chip->motor_ops->pwm_config(duty_ns, period_ns); + } + +} + +static int oneplus_motor_pwm_enable(void) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->pwm_enable == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || pwm_enable == NULL"); + return -EINVAL; + } else { + return g_the_chip->motor_ops->pwm_enable(); + } + +} + +static int oneplus_motor_pwm_disable(void) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->pwm_disable == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || pwm_disable == NULL"); + return -EINVAL; + } else { + return g_the_chip->motor_ops->pwm_disable(); + } + +} + +int oneplus_motor_get_all_config(int* config ,int count) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->get_all_config == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || get_all_config == NULL"); + return -EINVAL; + } else { + return g_the_chip->motor_ops->get_all_config(config,count); + } + +} + + +int oneplus_get_motor_type(void) +{ + if (g_the_chip == NULL || g_the_chip->motor_ops == NULL + || g_the_chip->motor_ops->get_motor_type == NULL) { + + MOTOR_ERR("g_the_chip == NULL || g_the_chip->motor_ops == NULL || get_motor_type == NULL"); + return MOTOR_UNKNOWN; + } else { + return g_the_chip->motor_ops->get_motor_type(); + } + +} + +static void oneplus_set_motor_work_mode_para(int motor_work_mode) +{ + int mode = 0; + static int mode_pre = -1; + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + if ((motor_work_mode >= MOTOR_MODE_FULL) && (motor_work_mode <= MOTOR_MODE_1_32)) { + if (mode_pre != motor_work_mode) { + mode_pre = motor_work_mode; + g_the_chip->motor_work_mode = motor_work_mode; + } else { + return;//working mode not change + } + } + + switch (g_the_chip->motor_work_mode) { + case MOTOR_MODE_FULL: + oneplus_motor_set_working_mode(MOTOR_MODE_FULL); + mode = 1; + break; + + case MOTOR_MODE_1_16: + oneplus_motor_set_working_mode(MOTOR_MODE_1_16); + mode = 16; + break; + case MOTOR_MODE_1_32: + oneplus_motor_set_working_mode(MOTOR_MODE_1_32); + mode = 32; + break; + default: + oneplus_motor_set_working_mode(MOTOR_MODE_1_32); + mode = 32; + break; + } + //default 32 + //g_the_chip->pwm_count = oneplus_motor_calculate_pwm_count(g_the_chip->whole_jonery_length, mode);//8.2mm + //g_the_chip->pwm_count = g_the_chip->pwm_count* 32 / 20; + // 0.5mm + //g_the_chip->speed_up_pwm_count = oneplus_motor_calculate_pwm_count(g_the_chip->speed_up_distance, mode); + // 2mm + //g_the_chip->speed_down_pwm_count = oneplus_motor_calculate_pwm_count(g_the_chip->speed_down_L, mode); + //MOTOR_LOG("pwm_count %d,whole_jonery_length %d, speed_up_pwm_count %d, mode %d\n", + // g_the_chip->pwm_count, g_the_chip->whole_jonery_length,mode); +} + +/********************************************************************* + combine digital_hall and step_motor for logical process +**********************************************************************/ +static void manual_to_auto_up_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct oneplus_motor_chip *chip = container_of(dwork, struct oneplus_motor_chip, up_work); + + oneplus_motor_set_awake(chip,HALL_DATA_LOCK,true);//dont sleep + oneplus_motor_irq_monitor(chip); + + MOTOR_LOG("call"); + if (atomic_read(&chip->in_suspend)) { + MOTOR_ERR("in_suspend delay 20 ms \n"); + queue_delayed_work(chip->manual2auto_wq, &chip->up_work, msecs_to_jiffies(20)); + return; + } + + oneplus_hall_update_threshold(HALL_DOWN, MID_STATE, 511, 511); + + oneplus_hall_clear_irq(HALL_DOWN); + + if (!chip->is_irq_abnormal) + oneplus_hall_enable_irq(HALL_DOWN, true); + + oneplus_motor_set_awake(chip, HALL_DATA_LOCK, false); +} + +static void manual_to_auto_down_work(struct work_struct* work) +{ + struct delayed_work* dwork = to_delayed_work(work); + struct oneplus_motor_chip* chip = container_of(dwork, struct oneplus_motor_chip, down_work); + + oneplus_motor_set_awake(chip,HALL_DATA_LOCK,true);//dont sleep + oneplus_motor_irq_monitor(chip); + + MOTOR_LOG("call \n"); + + if (atomic_read(&chip->in_suspend)) { + MOTOR_ERR("in_suspend delay 20 ms \n"); + queue_delayed_work(chip->manual2auto_wq,&chip->down_work,msecs_to_jiffies(20)); + return; + } + + oneplus_hall_update_threshold(HALL_UP, MID_STATE, 511, 511); + + if (chip->manual2auto_down_switch) { + if (!chip->motor_started) { + report_position_state(chip, MANUAL_TO_DOWN_EVENT); + oneplus_motor_downward(); + } + } + + oneplus_hall_clear_irq(HALL_UP); + + if (!chip->is_irq_abnormal) + oneplus_hall_enable_irq(HALL_UP, true); + + oneplus_motor_set_awake(chip, HALL_DATA_LOCK, false); + + return; +} + +static void oneplus_set_motor_speed(int speed) +{ + long long period_ns = 0; + unsigned long duty_ns = 0; + + + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + g_the_chip->motor_speed = speed; + + MOTOR_LOG("call, speed : %d , chip->motor_speed : %d \n", speed, g_the_chip->motor_speed); + + switch (g_the_chip->motor_speed) { + case MOTOR_SPEED0: + period_ns = 12000;// 80KHZ + break; + + case MOTOR_SPEED1: + period_ns = 15500;// 64KHZ + break; + + case MOTOR_SPEED2: + period_ns = 19531;// 51.2HZ + break; + + case MOTOR_SPEED3: + period_ns = 26041;// 38.4KHZ + break; + + case MOTOR_SPEED4: + period_ns = 31250;// 32KHZ + break; + + case MOTOR_SPEED5: + period_ns = 39062;// 25.6KHZ + break; + + case MOTOR_SPEED6: + period_ns = 44642;// 22.4KHZ + break; + + case MOTOR_SPEED7: + period_ns = 52083;// 19.2KHZ + break; + + case MOTOR_SPEED8: + period_ns = 60240;// 16.6KHZ + break; + + case MOTOR_SPEED9: + period_ns = 78125;// 12.8KHZ + break; + + case MOTOR_SPEED10: + period_ns = 104166;// 9.6KHZ + break; + + case MOTOR_SPEED11: + period_ns = 156250;// 6.4KHZ + break; + + case MOTOR_SPEED12: + period_ns = 312500;// 3.2KHZ + break; + + case MOTOR_SPEED13: + period_ns = 625000;// 1.6KHZ + break; + case MOTOR_SPEED_SPECIAL: + period_ns = 11161;//2800pps, only use in free fall + break; + + default: + period_ns = 12000;// 80KHZ. + break; + + } + + duty_ns = (unsigned long)(period_ns/2); + g_the_chip->pwm_duty = duty_ns; + g_the_chip->pwm_period = period_ns; + MOTOR_LOG("pwm_duty : %d, pwm_period : %d", g_the_chip->pwm_duty, g_the_chip->pwm_period); + + return; +} + +static void oneplus_change_motor_speed(int speed) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + if (g_the_chip->motor_speed == speed) { + MOTOR_LOG("speed not change"); + return; + } + + MOTOR_LOG("call, speed : %d , chip->motor_speed : %d \n", speed, g_the_chip->motor_speed); + + oneplus_set_motor_speed(speed); + + mutex_lock(&motor_running_mutex); + if (g_the_chip->motor_started) { + oneplus_motor_pwm_disable(); + oneplus_motor_pwm_config(g_the_chip->pwm_duty, g_the_chip->pwm_period); + oneplus_motor_pwm_enable(); + } + mutex_unlock(&motor_running_mutex); + + return; +} + +static void oneplus_set_motor_direction(int direction) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + if (direction >= 0) + g_the_chip->motor_direction = !!direction; +} + +static void oneplus_set_motor_move_state(int move_state) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + if ((move_state >= MOTOR_STOP) && (move_state <= MOTOR_DOWNWARD_STOP)) { + g_the_chip->move_state = move_state; + } +} + +static bool oneplus_motor_run_check(struct oneplus_motor_chip* chip) +{ + //TO DO : remove temporary, for debug + + if (chip->is_skip_pos_check) { + MOTOR_ERR("skip_pos_check \n"); + return true; + } + + if ((chip->position == PEAK_STATE) && (chip->motor_direction == MOTOR_UPWARD)) { + MOTOR_LOG("has been in up_state, return false\n"); + return false; + } else if ((chip->position == BOTTOM_STATE) && (chip->motor_direction == MOTOR_DOWN)) { + MOTOR_LOG("has been in down_state, return false\n"); + return false; + } + + MOTOR_LOG("oneplus_motor_run_check ok\n"); + return true; +} + +static void oneplus_motor_control(int on ,int speed ,int direction) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + MOTOR_LOG("on = %d, speed = %d, direction = %d, motor_switch : %d \n", + on, speed, direction, g_the_chip->motor_switch); + + if (on) { + + if (g_the_chip->motor_switch == 0) { + MOTOR_ERR("motor_switch == 0, would not set motor start \n"); + return; + } + if (!g_the_chip->motor_started) { + MOTOR_LOG("set motor_enable = 1"); + g_the_chip->motor_enable = 1; + + //enable hall + if (!g_the_chip->is_free_fall) { + if (!oneplus_hall_get_enable_state(HALL_DOWN)) + oneplus_hall_set_enable_state(HALL_DOWN, true); + + if (!oneplus_hall_get_enable_state(HALL_UP)) + oneplus_hall_set_enable_state(HALL_UP, true); + } + + + oneplus_set_motor_speed(speed); + oneplus_set_motor_direction(direction); + if (oneplus_motor_run_check(g_the_chip)) { + queue_work(g_the_chip->motor_run_work_wq, &g_the_chip->motor_work); + } + } + } else { + if (g_the_chip->motor_started) { + MOTOR_LOG("set motor_enable = 0"); + g_the_chip->motor_enable = 0; + queue_work(g_the_chip->motor_run_work_wq, &g_the_chip->motor_work); + } + } + + return; +} + +static void oneplus_motor_start(void) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip ==NULL \n"); + return; + } + + oneplus_motor_control(1, g_the_chip->motor_speed, g_the_chip->motor_direction); + + return; +} + +static void oneplus_motor_stop(void) +{ + int on = 0; + int speed = 0; + int direction = 0; + + MOTOR_LOG("call \n"); + oneplus_motor_control(on, speed, direction); + + return; +} + +static void oneplus_motor_downward(void) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return; + } + + oneplus_motor_control(1, g_the_chip->motor_speed, MOTOR_DOWN); +} + +static void motor_run_work(struct work_struct* work) +{ + struct oneplus_motor_chip* chip = container_of(work, struct oneplus_motor_chip, motor_work); + unsigned long intsecond = 0; + unsigned long nsecond = 0; + long long value = 0; + int err = 0; + + mutex_lock(&motor_running_mutex); + MOTOR_LOG("%s, motor_enable : %d, motor_started : %d", + __func__, chip->motor_enable, chip->motor_started); + + MOTOR_LOG("is_factory_mode : %d \n", chip->is_factory_mode); + + if (chip->motor_enable && (chip->motor_started == 0)) { + mutex_lock(&motor_start_mutex); + + MOTOR_LOG("start motor\n"); + + oneplus_motor_set_awake(chip,MOTOR_RUN_LOCK, true); + oneplus_motor_set_power(MOTOR_POWER_ON); + oneplus_motor_set_direction(chip->motor_direction); + + if (!g_the_chip->is_motor_test) { + if (chip->motor_direction == MOTOR_UPWARD) + oneplus_hall_update_threshold(HALL_DOWN, BOTTOM_STATE, 511, 511); + else if (chip->motor_direction == MOTOR_DOWN) + oneplus_hall_update_threshold(HALL_UP, BOTTOM_STATE, 511, 511); + } else if (chip->motor_direction == MOTOR_UPWARD) { + MOTOR_LOG("motor test, update hall down irq threshold"); + oneplus_hall_update_threshold(HALL_DOWN,BOTTOM_STATE,-512,chip->hall_down_irq_position); + } + + if (chip->is_free_fall) { + MOTOR_ERR("phone is falling, use special speed"); + oneplus_set_motor_speed(MOTOR_SPEED_SPECIAL); + } else if (chip->is_factory_mode == 1){ + oneplus_set_motor_speed(MOTOR_SPEED0);//calibrate mode + } else { + oneplus_set_motor_speed(MOTOR_SPEED10);//normal mode and step test mode + } + + err = oneplus_motor_pwm_config(chip->pwm_duty, chip->pwm_period); + if (err < 0) { + MOTOR_ERR("pwm_config failed, err : %d \n",err); + chip->motor_started = 0; + mutex_unlock(&motor_running_mutex); + mutex_unlock(&motor_start_mutex); + return; + } + + err = oneplus_motor_pwm_enable(); + if (err < 0) { + MOTOR_ERR("pwm_enable failed, err : %d \n",err); + chip->motor_started = 0; + mutex_unlock(&motor_running_mutex); + mutex_unlock(&motor_start_mutex); + return; + } + + if (chip->motor_direction == MOTOR_UPWARD) { + if (chip->is_factory_mode == 0) + report_position_state(chip, UPING_EVENT); + + oneplus_set_motor_move_state(MOTOR_UPWARD_ING); + } else if (chip->motor_direction == MOTOR_DOWN) { + if (chip->is_factory_mode == 0) + report_position_state(chip, DOWNING_EVENT); + + oneplus_set_motor_move_state(MOTOR_DOWNWARD_ING); + } + chip->motor_started = 1; + + + chip->camera_position_detect = true; + + do_gettimeofday(&chip->motor_start_time); + MOTOR_LOG("motor_start_time tv_sec : %lu, tv_usec : %lu \n", chip->motor_start_time.tv_sec, chip->motor_start_time.tv_usec); + + //calculate when the motor should stop + if (chip->is_factory_mode == 1) { + if (chip->motor_direction == 1) {//camera up + value = chip->camera_up_step_count * MOTOR_STOP_TIMEOUT; + + MOTOR_LOG("motor up, use step count, value : %d", value); + + nsecond = do_div(value, 1000000000);//value = value/1000000000 ,nsecond = value % 1000000000 + intsecond = (unsigned long) value; + + chip->whole_jonery_time = nsecond / 1000;//ns to ms + } else { + MOTOR_LOG("motor up, set timeout as 1s"); + value = 1000000000; + + nsecond = do_div(value, 1000000000); + intsecond = (unsigned long) value; + } + } else { + if (chip->motor_direction == 1) {//camera up + value = (chip->speed_up_pwm_count * chip->pwm_period)+ + ((chip->camera_up_step_count - chip->speed_up_pwm_count) * MOTOR_STOP_TIMEOUT); + + MOTOR_LOG("motor up, use step count, value : %d", value); + + nsecond = do_div(value, 1000000000);//value = value/1000000000 ,nsecond = value % 1000000000 + intsecond = (unsigned long) value; + + chip->whole_jonery_time = nsecond / 1000;//ns to ms + } else { //camera down + value = (chip->speed_up_pwm_count * chip->pwm_period)+ + ((chip->camera_up_step_count - chip->speed_up_pwm_count + 20 * 32) * MOTOR_STOP_TIMEOUT); + + MOTOR_LOG("motor up, use step count, value : %d", value); + + nsecond = do_div(value, 1000000000);//value = value/1000000000 ,nsecond = value % 1000000000 + intsecond = (unsigned long) value; + + chip->whole_jonery_time = nsecond / 1000;//ns to ms + } + } + + //else { + //MOTOR_LOG("motor up, set timeout as 1s"); + //value = 1000000000; + + //nsecond = do_div(value, 1000000000); + //intsecond = (unsigned long) value; + //} + + MOTOR_LOG("time value = %llu nsecond = %lu intsecond = %lu , whole_jonery_time : %lu \n", + value, nsecond, intsecond, chip->whole_jonery_time); + hrtimer_start(&chip->stop_timer, ktime_set(intsecond, nsecond), HRTIMER_MODE_REL); + + //calculate when the motor should speed up + value = chip->speed_up_pwm_count * chip->pwm_period; + nsecond = do_div(value, 1000000000);//value = value/1000000000 ,nsecond = value % 1000000000 + intsecond = (unsigned long) value; + MOTOR_LOG("time value = %llu nsecond = %lu intsecond = %lu, chip->speed_up_pwm_count = %d,chip->pwm_period = %d \n", + value, nsecond, intsecond, chip->speed_up_pwm_count, chip->pwm_period); + hrtimer_start(&chip->speed_up_timer, ktime_set(intsecond, nsecond), HRTIMER_MODE_REL); + mutex_unlock(&motor_start_mutex); + } else if (!chip->motor_enable && (chip->motor_started == 1)) { + MOTOR_LOG("stop motor \n"); + + oneplus_motor_pwm_disable(); + oneplus_motor_set_power(MOTOR_POWER_OFF); + + if (!chip->stop_timer_trigger) + hrtimer_cancel(&chip->stop_timer); + else + chip->stop_timer_trigger = 0; + + chip->motor_started = 0; + + if (chip->move_state == MOTOR_UPWARD_ING) { + oneplus_set_motor_move_state(MOTOR_UPWARD_STOP); + oneplus_hall_get_abs_data(HALL_UP); + MOTOR_LOG("move_state == MOTOR_UPWARD_ING, hall_up_data : %d, hall_up_irq_position : %d" + ,chip->hall_up_data, chip->hall_up_irq_position); + + if (chip->hall_up_data > chip->hall_up_irq_position) { + MOTOR_ERR("%s, position = PEAK_STATE", __func__); + chip->position = PEAK_STATE; + if (chip->is_factory_mode == 0) + report_position_state(chip, UP_NORMAL_EVENT); + + MOTOR_ERR("POS_NORMAL, hall_up_irq_count %d\n",chip->hall_up_irq_count); + chip->hall_up_irq_count = 0; + oneplus_motor_notify_state(MOTOR_UP_EVENT); + oneplus_hall_update_threshold(HALL_UP,PEAK_STATE,-512,chip->hall_up_irq_position); + } else if (!chip->force_move) { + chip->position = MID_STATE; + if (chip->is_factory_mode == 0) + report_position_state(chip, UP_ABNORMA_EVENT); + + MOTOR_ERR("POS_ABNORMAL %d %d\n",chip->hall_up_data ,chip->hall_up_irq_position); + oneplus_motor_notify_state(MOTOR_BLOCK_EVENT); + } else { + MOTOR_ERR("POS_ABNORMAL %d %d, but it is force_move mode, would not report \n", + chip->hall_up_data ,chip->hall_up_irq_position); + } + + } else if (chip->move_state == MOTOR_DOWNWARD_ING) { + oneplus_set_motor_move_state(MOTOR_DOWNWARD_STOP); + oneplus_hall_get_abs_data(HALL_DOWN); + MOTOR_LOG("move_state == MOTOR_DOWNWARD_ING, hall_down_data : %d, hall_down_irq_position : %d" + ,chip->hall_down_data, chip->hall_down_irq_position); + + if (chip->hall_down_data > chip->hall_down_irq_position) { + MOTOR_ERR("%s, position = BOTTOM_STATE", __func__); + chip->position = BOTTOM_STATE; + if (chip->is_factory_mode == 0) + report_position_state(chip, DOWN_NORMAL_EVENT); + + MOTOR_ERR("POS_NORMAL, hall_down_irq_count %d\n",chip->hall_down_irq_count); + chip->hall_down_irq_count = 0; + oneplus_motor_notify_state(MOTOR_DOWN_EVENT); + //oneplus_hall_update_threshold(HALL_DOWN,BOTTOM_STATE,-512,chip->hall_down_irq_position); + } else if (!chip->force_move){ + chip->position = MID_STATE; + if (chip->is_factory_mode == 0) + report_position_state(chip, DOWN_ABNORMAL_EVENT); + + MOTOR_ERR("POS_ABNORMAL %d %d \n",chip->hall_down_data ,chip->hall_down_irq_position); + oneplus_motor_notify_state(MOTOR_BLOCK_EVENT); + } else { + MOTOR_ERR("POS_ABNORMAL %d %d, but it is force_move mode, would not report \n", + chip->hall_down_data ,chip->hall_down_irq_position); + } + } + + //set motor starting speed after motor stop + oneplus_set_motor_speed(MOTOR_SPEED10); + + if (chip->save_hall_data_to_file) + chip->save_hall_data_to_file = false; + + if (chip->force_move) + chip->force_move = false;//reset to normal mode + + if (chip->is_free_fall) + chip->is_free_fall = false; + + //chip->slow_down_speed = MOTOR_SPEED11; + + //disable hall when down finish for save power + //remove temporary + // if (g_the_chip->motor_direction == MOTOR_DOWN && chip->position == BOTTOM_STATE) { + // if (oneplus_hall_get_enable_state(HALL_DOWN)) + // oneplus_hall_set_enable_state(HALL_DOWN, false); + + // if (oneplus_hall_get_enable_state(HALL_UP)) + // oneplus_hall_set_enable_state(HALL_UP, false); + // } + + oneplus_motor_set_awake(chip,MOTOR_RUN_LOCK,false); + + chip->camera_position_detect = false;//stop camera position detect + } + + mutex_unlock(&motor_running_mutex); +} + +static void free_fall_irq_check_work_func(struct work_struct* work) +{ + struct delayed_work* dwork = to_delayed_work(work); + struct oneplus_motor_chip* chip = container_of(dwork, struct oneplus_motor_chip, free_fall_irq_check_work); + + if (chip == NULL) { + MOTOR_ERR("free_fall_irq_check_work_func error, chip == NULL"); + return; + } + + MOTOR_LOG("free_fall_irq_times : %d, infrared_shut_down_state : %d \n", chip->free_fall_irq_times, chip->infrared_shut_down_state); + + if (chip->free_fall_irq_times == 1) { + g_the_chip->is_free_fall = true; + disable_irq_nosync(g_the_chip->free_fall_irq); + oneplus_motor_downward(); + enable_irq(g_the_chip->free_fall_irq); + + } else if (chip->free_fall_irq_times >= 2) { + MOTOR_LOG("infrared notify event, free_fall_irq_times : %d \n", chip->free_fall_irq_times); + chip->infrared_shut_down_state = 1; + + } else { + MOTOR_LOG("unknow event, free_fall_irq_times : %d \n", chip->free_fall_irq_times); + } + + chip->free_fall_irq_times = 0; + + return; +} +static void camera_position_detect_work(struct work_struct* work) +{ + int hall_delta_pre = 0; + int hall_delta = 0; + int delta_d = 0; + int hall_down_data_pre = 0; + int hall_up_data_pre = 0; + int speed_down = 0; + int should_stop_count = 0; + int up_stop_times = 0; + int down_stop_times = 0; + int abnormal_judge_time = 400000;//400ms default + int data_count = 0; + int deltad_range_low = -5; + int deltad_range_high = 5; + unsigned long enter_deltad_first_time = 0; + bool mag_noise = false; + bool append_to_line = false; + short hall_up_data[64] = {0}; + short hall_down_data[64] = {0}; + struct delayed_work* dwork = to_delayed_work(work); + struct oneplus_motor_chip* chip = container_of(dwork, struct oneplus_motor_chip, detect_work); + unsigned long distance_time = 0; + struct timeval current_time; + + + if (chip == NULL) { + MOTOR_ERR("camera_position_detect_work error, chip == NULL"); + return; + } + + mutex_lock(&position_detect_mutex); + mutex_lock(&motor_start_mutex); + oneplus_motor_set_awake(chip,POSITION_DETECT_LOCK,true);//should not be sleep during detecting + + if (chip->move_state == MOTOR_UPWARD_ING) + chip->stall_steps = chip->camera_up_step_count / 32; + else + chip->stall_steps = 0; + + deltad_range_low = 0 - chip->deltad_range; + deltad_range_high = chip->deltad_range; + chip->is_stall = 0; + chip->stall_mode = UNKNOW_MODE; + up_stop_times = 2; + down_stop_times = 1; + abnormal_judge_time = chip->whole_jonery_time * chip->begin_stop_detect_percent / 100; + MOTOR_LOG("motor_diretion : %d , move_state : %d motor_started : %d, abnormal_judge_time : %d\n", + chip->motor_direction, chip->move_state, chip->motor_started, abnormal_judge_time); + MOTOR_LOG("camera_down_slow_down_position_hall_down_data : %d, camera_down_slow_down_position_hall_up_data : %d\n", + chip->camera_down_slow_down_position_hall_down_data, chip->camera_down_slow_down_position_hall_up_data); + MOTOR_LOG("deltad_range_low : %d, deltad_range_high : %d \n", deltad_range_low, deltad_range_high); + MOTOR_LOG("stall_steps : %d, begin_stop_detect_percent : %d \n", chip->stall_steps, chip->begin_stop_detect_percent); + + oneplus_change_motor_speed(MOTOR_SPEED0); + + while (chip->camera_position_detect) { + hall_down_data_pre = chip->hall_down_data; + hall_up_data_pre = chip->hall_up_data; + oneplus_hall_get_abs_data(HALL_DOWN); + oneplus_hall_get_abs_data(HALL_UP); + hall_up_data[data_count] = chip->hall_down_data; + hall_down_data[data_count] = chip->hall_up_data; + data_count++; + + //may be mag noise or speed is very slow + if (chip->save_hall_data_to_file && data_count >= 60) { + MOTOR_LOG("may be mag noise!!!, data_count : %d", data_count); + mag_noise = true; + + write_hall_data_to_file(hall_up_data, hall_down_data, data_count, chip->motor_direction, false); + + data_count = 0; + memset(hall_up_data, 0, sizeof(hall_up_data)); + memset(hall_down_data, 0, sizeof(hall_down_data)); + } else if (data_count >= 60) { + MOTOR_LOG("may be mag noise!!!, data_count : %d", data_count); + data_count = 0; + } + + hall_delta = chip->hall_down_data - chip->hall_up_data; + delta_d = hall_delta - hall_delta_pre; + hall_delta_pre = hall_delta; + + MOTOR_LOG("dhall_down data : %d, dhall_up data : %d , hall_delta : %d, delta_d : %d \n", + chip->hall_down_data, chip->hall_up_data, hall_delta, delta_d); + + //if force_move mode, then we don't use brake mechanism mode, use time out mode + if (chip->force_move) { + mdelay(chip->position_detect_delay); + continue; + } + + //if free fall, then we don't use brake mechanism mode, use time out mode + if (chip->is_free_fall) { + MOTOR_ERR("phone is falling"); + mdelay(chip->position_detect_delay); + continue; + } + + //camera down + if ((chip->hall_down_data - chip->hall_up_data) > (chip->camera_down_slow_down_position_hall_down_data - chip->camera_down_slow_down_position_hall_up_data)) { + if ((chip->move_state == MOTOR_DOWNWARD_ING) && (speed_down == 0)) { + speed_down = 1; + oneplus_change_motor_speed(chip->slow_down_speed); + } + } + + do_gettimeofday(¤t_time); + distance_time = (current_time.tv_sec - chip->motor_start_time.tv_sec) * 1000000 + + (current_time.tv_usec - chip->motor_start_time.tv_usec); + MOTOR_LOG("distance_time : %d, current_time.tv_sec : %lu, current_time.tv_usec : %lu", + distance_time, (unsigned long)current_time.tv_sec, (unsigned long)current_time.tv_usec); + + //stop motor algo + MOTOR_LOG("should_stop_count : %d, is_stall : %d, up_stop_times : %d, down_stop_times : %d", + should_stop_count, chip->is_stall, up_stop_times, down_stop_times); + + if ((distance_time >= abnormal_judge_time) && (delta_d >= deltad_range_low) && (delta_d <= deltad_range_high)) { + should_stop_count ++; + + if (enter_deltad_first_time == 0) { + enter_deltad_first_time = distance_time; + } + MOTOR_LOG("enter deltad_range, enter_deltad_first_time :%lu", enter_deltad_first_time); + + } + + //when calibrate mode, motor down stop by hall, else stop by steps + if ((should_stop_count >= down_stop_times) && (chip->move_state == MOTOR_DOWNWARD_ING) + && (chip->is_factory_mode == 1)) { + oneplus_motor_stop(); + + break; + } else if ((should_stop_count >= up_stop_times) && (chip->move_state == MOTOR_UPWARD_ING)) { + chip->stall_mode = ENTER_DELTAD_RANGE_TWO_TIEMS; + chip->is_stall = 1; + chip->stall_steps = enter_deltad_first_time / 384;//(enter_deltad_first_time / 12) / 32; + MOTOR_LOG("should_stop_count >= up_stop_times, stall_steps : %d \n", chip->stall_steps); + } + + //anti-shake when motor down + MOTOR_LOG("hall_down_data_pre : %d, hall_down_data : %d \n", hall_down_data_pre, chip->hall_down_data); + if ( (distance_time >= abnormal_judge_time) && (chip->move_state == MOTOR_DOWNWARD_ING) && + (hall_down_data_pre > chip->hall_down_data) && (chip->is_factory_mode == 1)) { + + MOTOR_LOG("hall_down_data_pre > chip->hall_down_data, may be structure shake, stop motor"); + oneplus_motor_stop(); + break; + } + + //anti-shake when motor up + if ( (distance_time >= abnormal_judge_time) && (chip->move_state == MOTOR_UPWARD_ING) && + (hall_up_data_pre > chip->hall_up_data)) { + + MOTOR_LOG("hall_up_data_pre > chip->hall_up_data"); + + + if (enter_deltad_first_time != 0) { + chip->stall_steps = enter_deltad_first_time / 384;//(enter_deltad_first_time / 12) / 32; + chip->stall_mode = ENTER_DELTAD_AND_SHAKE; + } else { + chip->stall_steps = distance_time / 384;//(distance_time / 12) / 32; + chip->stall_mode = ONLY_SHAKE; + } + chip->is_stall = 1; + MOTOR_LOG("chip->stall_steps : %d, distance_time : %lu, enter_deltad_first_time : %lu \n", + chip->stall_steps, distance_time, enter_deltad_first_time); + break; + } + + mdelay(chip->position_detect_delay);//15ms + } + + oneplus_motor_set_awake(chip,POSITION_DETECT_LOCK,false); + + MOTOR_LOG("chip->stall_mode : %d \n", chip->stall_mode); + if (chip->save_hall_data_to_file && data_count > 0) { + append_to_line = mag_noise ? true : false; + write_hall_data_to_file(hall_up_data, hall_down_data, data_count, chip->motor_direction, append_to_line); + } + + mutex_unlock(&position_detect_mutex); + mutex_unlock(&motor_start_mutex); + + return; +} + +static int write_hall_data_to_file(short* hall_up_data, short* hall_down_data, int buf_len, int direction, bool append) +{ + int fd = -1; + int i = 0; + int data_num = 0; + char hall_data_bufs[1024] = {0};// 16 * 64 + char hall_data_buf[16] = {0}; + + if (hall_up_data == NULL || hall_down_data == NULL || buf_len < 1) { + MOTOR_ERR("write_hall_data_to_file failed, hall_up_data == NULL || hall_down_data == NULL || buf_len < 1"); + return -EINVAL; + } + + fd = sys_open("/sdcard/hall_data.csv", O_WRONLY | O_CREAT | O_APPEND, 0); + if (fd < 0) { + MOTOR_ERR("open log file /sdcard/hall_data.csv failed, fd : %d \n", fd); + return -1; + } + + data_num = buf_len > 60 ? 60 : buf_len; + if (!append) { + if (direction) + sys_write(fd, "1\n", 2);//up + else + sys_write(fd, "0\n", 2);//down + } + + for (i = 0; i < data_num; i++) { + memset(hall_data_buf, 0, sizeof(hall_data_buf)); + sprintf(hall_data_buf, "%d,", hall_up_data[i]); + strcat(hall_data_bufs, hall_data_buf); + } + strcat(hall_data_bufs, "\n"); + sys_write(fd, hall_data_bufs, strlen(hall_data_bufs)); + memset(hall_data_bufs, 0 , sizeof(hall_data_bufs)); + + for (i = 0; i < data_num; i++) { + memset(hall_data_buf, 0, sizeof(hall_data_buf)); + sprintf(hall_data_buf, "%d,", hall_down_data[i]); + strcat(hall_data_bufs, hall_data_buf); + } + strcat(hall_data_bufs, "\n"); + sys_write(fd, hall_data_bufs, strlen(hall_data_bufs)); + sys_write(fd, "\n", 1); + + sys_close(fd); + return 0; +} + +static enum hrtimer_restart motor_stop_timer_func(struct hrtimer* hrtimer) +{ + MOTOR_LOG("force_move : %d \n", g_the_chip->force_move); + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return HRTIMER_NORESTART; + } + + if (g_the_chip->force_move){ + MOTOR_LOG("force_move is enable, would not stop motor"); + return HRTIMER_NORESTART; + } + g_the_chip->stop_timer_trigger = 1; + + oneplus_motor_stop(); + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart motor_speed_up_timer_func(struct hrtimer* hrtimer) +{ + MOTOR_LOG("call \n"); + + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return HRTIMER_NORESTART; + } + + mod_delayed_work(system_highpri_wq, &g_the_chip->detect_work, 0); + + return HRTIMER_NORESTART; +} + +static enum alarmtimer_restart motor_reset_timer_func(struct alarm* alrm, ktime_t now) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return ALARMTIMER_NORESTART; + } + + MOTOR_LOG("hall_down_irq_count %d hall_up_irq_count %d \n",g_the_chip->hall_down_irq_count,g_the_chip->hall_up_irq_count); + + if ((g_the_chip->hall_down_irq_count >= MOTOR_IRQ_MONITOR_COUNT) || + (g_the_chip->hall_up_irq_count >= MOTOR_IRQ_MONITOR_COUNT)) { + MOTOR_ERR("irq abnormal,reset \n"); + g_the_chip->is_irq_abnormal = true; + g_the_chip->motor_switch = 0; + g_the_chip->hall_down_irq_count = 0; + g_the_chip->hall_up_irq_count = 0; + } + g_the_chip->irq_monitor_started = false; + + return ALARMTIMER_NORESTART; +} + +static void oneplus_motor_set_awake(struct oneplus_motor_chip* chip, int id ,bool awake) +{ + static int awake_count = 0; + static int wakelock_holder = 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + if (id >= MAX_LOCK) + return; + + if (awake && !awake_count) { + if (!(wakelock_holder & (1 << id))) {//this holder have not this lock now + wakelock_holder |= (1 << id); + awake_count ++; + wake_lock(&chip->suspend_lock); + MOTOR_LOG("awake \n"); + } + } else if (!awake && (awake_count == 1)) {//only one lock hold + if (wakelock_holder & (1 << id)) { + wakelock_holder &= ~(1 << id); + awake_count = 0; + wake_unlock(&chip->suspend_lock); + MOTOR_LOG("relax \n"); + } + } else if (!awake) { + if (awake_count != 0) { + if (wakelock_holder & (1 << id)) { + awake_count --; + wakelock_holder &= ~(1 << id); + } + } + } else { + if (!(wakelock_holder & (1 << id))) {//this holder have not this lock now + awake_count ++; + wakelock_holder |= (1 << id); + } + } + //MOTOR_LOG("awake_count %d wakelock_holder %d\n",awake_count,wakelock_holder); +#else + if (!chip->suspend_ws) + return; + + if (id >= MAX_LOCK) + return; + + if (awake && !awake_count) { + if (!(wakelock_holder & (1 << id))) {//this holder have not this lock now + wakelock_holder |= (1 << id); + awake_count ++; + __pm_stay_awake(chip->suspend_ws);//not alow system suspend + + MOTOR_LOG("awake \n"); + } + } else if (!awake && (awake_count == 1)) {//only one lock hold + if (wakelock_holder & (1 << id)) { + wakelock_holder &= ~(1 << id); + awake_count = 0; + __pm_relax(chip->suspend_ws); + MOTOR_LOG("relax \n"); + } + } else if (!awake) { + if (awake_count != 0) { + if (wakelock_holder & (1 << id)) { + awake_count --; + wakelock_holder &= ~(1 << id); + } + } + } else { + if (!(wakelock_holder & (1 << id))) {//this holder have not this lock now + awake_count ++; + wakelock_holder |= (1 << id); + } + } + MOTOR_LOG("awake_count %d wakelock_holder %d \n", awake_count, wakelock_holder); +#endif +} + +static void report_position_state(struct oneplus_motor_chip* chip, camera_position_state_event state_event) +{ + if (chip == NULL) { + MOTOR_ERR("chip == NULL \n"); + return; + } + + MOTOR_LOG("call, state_event : %d", state_event); + + switch (state_event) { + case MANUAL_TO_DOWN_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_MANUAL_TO_DOWN, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_MANUAL_TO_DOWN, 0); + input_sync(chip->input_dev); + break; + case UPING_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_UP, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_UP, 0); + input_sync(chip->input_dev); + break; + case UP_ABNORMA_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_UP_ABNORMAL, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_UP_ABNORMAL, 0); + input_sync(chip->input_dev); + break; + case UP_NORMAL_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_UP_NORMAL, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_UP_NORMAL, 0); + input_sync(chip->input_dev); + break; + case DOWNING_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_DOWN, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_DOWN, 0); + input_sync(chip->input_dev); + break; + case DOWN_ABNORMAL_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_DOWN_ABNORMAL, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_DOWN_ABNORMAL, 0); + input_sync(chip->input_dev); + break; + case DOWN_NORMAL_EVENT: + input_report_key(chip->input_dev, MOTOR_EVENT_DOWN_NORMAL, 1); + input_sync(chip->input_dev); + input_report_key(chip->input_dev, MOTOR_EVENT_DOWN_NORMAL, 0); + input_sync(chip->input_dev); + break; + default: + MOTOR_ERR("state_event (%d) is invalid, would not report \n", state_event); + break; + } + + return; +} + + +//note:work in irq context +int oneplus_dhall_irq_handler(unsigned int id) +{ + MOTOR_LOG("call, id : %d \n", id); + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip == NULL \n"); + return -EINVAL; + } + + if (id == HALL_UP) {//push camera + g_the_chip->hall_up_irq_count ++; + queue_delayed_work(g_the_chip->manual2auto_wq, &g_the_chip->down_work, 0); + } else if (id == HALL_DOWN){ + g_the_chip->hall_down_irq_count ++; + queue_delayed_work(g_the_chip->manual2auto_wq, &g_the_chip->up_work, 0); + } + + return 0; +} + +static void oneplus_motor_irq_monitor(struct oneplus_motor_chip* chip) +{ + if (!chip->irq_monitor_started) { + MOTOR_LOG("start \n"); + chip->irq_monitor_started = true; + alarm_start_relative(&chip->reset_timer, + ktime_set(MOTOR_IRQ_MONITOR_TIME / 1000, (MOTOR_IRQ_MONITOR_TIME % 1000)* 1000000)); + } +} + +static irqreturn_t oneplus_free_fall_detect_handler(int irq, void* dev_id) +{ + if (g_the_chip == NULL) { + MOTOR_LOG("g_the_chip ==NULL \n"); + return -EINVAL; + } + + g_the_chip->free_fall_irq_times++; + + + if (g_the_chip->free_fall_irq_times == 1) + mod_delayed_work(system_highpri_wq, &g_the_chip->free_fall_irq_check_work, msecs_to_jiffies(1)); + + // g_the_chip->is_free_fall = true; + // disable_irq_nosync(g_the_chip->free_fall_irq); + // oneplus_motor_downward(); + // enable_irq(g_the_chip->free_fall_irq); + + return IRQ_HANDLED; +} + +/********************************************************************* + node operation by MotorManagerService and user +**********************************************************************/ +static ssize_t motor_direction_store(struct device* pdev, struct device_attribute* attr, + const char* buf, size_t count) +{ + unsigned long direction = 0; + int err = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + err = sscanf(buf, "%lu", &direction); + MOTOR_LOG("direction : %d, motor_started : %d", direction,g_the_chip->motor_started); + if (g_the_chip->motor_started) { + MOTOR_ERR("g_the_chip->motor_started != 0\n"); + return count; + } + + if (err == 1) { + oneplus_set_motor_direction(direction); + } + + return count;; +} + +static ssize_t motor_direction_show(struct device* dev, + struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->motor_direction); +} + +static ssize_t motor_enable_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + unsigned long enable = 0; + + if (sscanf(buff, "%lu", &enable) == 1) { + MOTOR_ERR("motor_enable_store enable : %d\n", enable); + if (enable) { + MOTOR_ERR("oneplus_motor_start \n"); + oneplus_motor_start(); + } else { + MOTOR_ERR("oneplus_motor_stop \n"); + oneplus_motor_stop(); + } + } + + return count; +} + +static ssize_t step_count_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t count) +{ + unsigned long step_count = 0; + + MOTOR_LOG("call"); + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + + if (sscanf(buff, "%lu", &step_count) == 1) { + g_the_chip->camera_up_step_count = step_count * 32; + + MOTOR_LOG("would set step_count, step_count : %d, g_the_chip->step_count : %d \n", + step_count, g_the_chip->camera_up_step_count); + } else { + MOTOR_LOG("would not set step_count, step_count : %d", step_count); + } + + return count; +} + +static ssize_t step_count_show(struct device *dev,struct device_attribute *attr, char *buf) +{ + int step_count = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + + step_count = g_the_chip->camera_up_step_count / 32; + MOTOR_LOG("step_count : %d, camera_up_step_count / 32 : %d \n", step_count , g_the_chip->camera_up_step_count / 32 ); + return sprintf(buf, "%d\n",step_count); +} + +static ssize_t save_hall_data_store(struct device *pdev, struct device_attribute *attr, + const char *buff, size_t count) +{ + unsigned long save_hall_data_to_file = 0; + + MOTOR_LOG("call"); + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + + if (sscanf(buff, "%lu", &save_hall_data_to_file) == 1) { + g_the_chip->save_hall_data_to_file = save_hall_data_to_file > 0 ? true : false; + + MOTOR_LOG("would set save_hall_data_to_file, save_hall_data_to_file : %d, g_the_chip->save_hall_data_to_file : %d \n", + save_hall_data_to_file, g_the_chip->save_hall_data_to_file); + } else { + MOTOR_LOG("would not set step_count, save_hall_data_to_file : %d", save_hall_data_to_file); + } + + return count; +} + +static ssize_t save_hall_data_show(struct device *dev,struct device_attribute *attr, char *buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->save_hall_data_to_file); +} + +static ssize_t hall_data_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + + oneplus_hall_get_abs_data(HALL_DOWN); + oneplus_hall_get_abs_data(HALL_UP); + + MOTOR_LOG("hall_down_data %d hall_up_data %d \n", g_the_chip->hall_down_data, g_the_chip->hall_up_data); + + return sprintf(buf, "%d,%d\n", g_the_chip->hall_down_data, g_the_chip->hall_up_data); +} + +static ssize_t motor_move_state_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", -1); + } + + return sprintf(buf, "%d\n", g_the_chip->move_state); +} + +static ssize_t hall_calibration_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + int step_count = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n%d\n",-1,-1); + } + + step_count = g_the_chip->camera_up_step_count / 32; + return sprintf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n", + g_the_chip->hall_down_irq_position, + g_the_chip->hall_up_irq_position, + g_the_chip->camera_down_slow_down_position_hall_down_data, + g_the_chip->camera_down_slow_down_position_hall_up_data, + g_the_chip->camera_up_slow_down_position_hall_down_data, + g_the_chip->camera_up_slow_down_position_hall_up_data, + g_the_chip->bottom_position_hall_down_data, + g_the_chip->bottom_position_hall_up_data, + g_the_chip->peak_position_hall_down_data, + g_the_chip->peak_position_hall_up_data, + step_count); +} + +static ssize_t hall_calibration_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + int data[11] = {0}; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &data[0], &data[1], &data[2], &data[3], &data[4], &data[5], + &data[6], &data[7], &data[8], &data[9], &data[10]) == 11) { + + if (data[0] >= 0) + g_the_chip->hall_down_irq_position = data[0]; + if (data[1] >= 0) + g_the_chip->hall_up_irq_position = data[1]; + if (data[2] >= 0) + g_the_chip->camera_down_slow_down_position_hall_down_data = data[2]; + if (data[3] >= 0) + g_the_chip->camera_down_slow_down_position_hall_up_data = data[3]; + if (data[4] >= 0) + g_the_chip->camera_up_slow_down_position_hall_down_data = data[4]; + if (data[5] >= 0) + g_the_chip->camera_up_slow_down_position_hall_up_data = data[5]; + if (data[6] >= 0) + g_the_chip->bottom_position_hall_down_data = data[6]; + if (data[7] >= 0) + g_the_chip->bottom_position_hall_up_data = data[7]; + if (data[8] >= 0) + g_the_chip->peak_position_hall_down_data = data[8]; + if (data[9] >= 0) + g_the_chip->peak_position_hall_up_data = data[9]; + if (data[10] >= 0) + g_the_chip->camera_up_step_count = data[10] * 32; + + MOTOR_LOG("hall calibrate date : %d %d %d %d %d %d %d %d %d %d %d\n", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10]); + + if (g_the_chip->bottom_position_hall_down_data < 330) + g_the_chip->deltad_range = 5; + else + g_the_chip->deltad_range = 10; + + MOTOR_LOG("deltad_range : %d \n", g_the_chip->deltad_range); + + //oneplus_hall_update_threshold(HALL_DOWN, BOTTOM_STATE, HALL_DETECT_RANGE_LOW, g_the_chip->hall_down_irq_position); + } else { + MOTOR_ERR("fail\n"); + } + return count; + +} + +static ssize_t stall_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n",0);; + } + + MOTOR_LOG("is_stall %d\n",g_the_chip->is_stall); + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->is_stall); +} + +static ssize_t stall_steps_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n",0);; + } + + MOTOR_LOG("stall_steps %d\n",g_the_chip->stall_steps); + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->stall_steps); +} + +static ssize_t stall_mode_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n",0);; + } + + MOTOR_LOG("stall_mode %d\n",g_the_chip->stall_mode); + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->stall_mode); +} + +static ssize_t motor_test_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n",0);; + } + + MOTOR_LOG("is_motor_test %d\n",g_the_chip->is_motor_test); + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->is_motor_test); +} + +static ssize_t motor_test_store(struct device* pdev, struct device_attribute* attr, const char* buff, size_t count) +{ + int test = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%d", &test) == 1) { + g_the_chip->is_motor_test = test; + } + MOTOR_LOG("test %d ,is_motor_test %d\n", test, g_the_chip->is_motor_test); + + return count; +} + +static ssize_t hall_irq_count_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n%d\n",-1,-1); + } + + return sprintf(buf, "%d,%d\n",g_the_chip->hall_down_irq_count, g_the_chip->hall_up_irq_count); +} + +static ssize_t motor_mode_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + int mdmode = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (g_the_chip->motor_started) + return count; + + if (sscanf(buff, "%d", &mdmode) == 1) { + MOTOR_LOG("mdmode = %d \n", mdmode); + oneplus_set_motor_work_mode_para(mdmode); + } + + return count; +} + +static ssize_t motor_mode_show(struct device* dev, + struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->motor_work_mode); +} + +static ssize_t motor_manual2auto_switch_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + int manual2auto_switch = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n",0); + } + + if (g_the_chip->manual2auto_down_switch == 1) + manual2auto_switch = 1; + + return sprintf(buf, "%d\n",manual2auto_switch); +} + +static ssize_t motor_manual2auto_switch_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + int data[1] = {0}; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL\n"); + return count; + } + + if (sscanf(buff, "%d", &data[0]) == 1) { + g_the_chip->manual2auto_down_switch = data[0]; + MOTOR_LOG("data : %d \n", data[0]); + if (data[0] == 1) { + if (g_the_chip->position == PEAK_STATE) { + oneplus_hall_update_threshold(HALL_UP,MID_STATE, HALL_DETECT_RANGE_LOW, g_the_chip->hall_up_irq_position); + } else if (g_the_chip->position == BOTTOM_STATE) { + oneplus_hall_update_threshold(HALL_DOWN,MID_STATE, HALL_DETECT_RANGE_LOW, g_the_chip->hall_down_irq_position); + } + g_the_chip->is_skip_pos_check = 0; + } else { + g_the_chip->is_skip_pos_check = 1; + } + } else { + MOTOR_ERR("failed \n"); + } + + return count; +} + +static ssize_t motor_sw_switch_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + unsigned long sw_switch = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &sw_switch) == 1) { + g_the_chip->motor_switch = sw_switch; + } + + return count; +} + +static ssize_t motor_sw_switch_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->motor_switch); +} + +static ssize_t motor_force_move_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + unsigned long enable = 0; + + MOTOR_LOG("call, enable : %d"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &enable) == 1) { + if (enable) { + g_the_chip->force_move = true; + oneplus_motor_start(); + } else { + oneplus_motor_stop(); + } + } + + return count; +} + +static ssize_t hall_detect_switch_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + unsigned long sw_switch = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &sw_switch) == 1) { + if (sw_switch) + g_the_chip->hall_detect_switch = true; + else + g_the_chip->hall_detect_switch = false; + } + + return count; +} + +static ssize_t hall_detect_switch_show(struct device* dev, + struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->hall_detect_switch); +} + +static ssize_t motor_all_config_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + int config[6] = {0}; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + + oneplus_motor_get_all_config(config, 6); + + return snprintf(buf, PAGE_SIZE, "config {sleep : %d step : %d m0 : %d m1 : %d vref : %d dir : %d}\n", + config[0], config[1], config[2],config[3], config[4], config[5]); +} + +static ssize_t motor_position_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + int config[6] = {0}; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n",0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->position); +} + +static ssize_t hall_all_reg_show(struct device* dev, struct device_attribute* attr, char* buf) +{ + u8 _buf[1024] = {0}; + + oneplus_dhall_dump_regs(HALL_DOWN, _buf); + + return sprintf(buf, "%s\n", _buf); +} + +static ssize_t motor_change_speed_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + unsigned long speed = 0; + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &speed) == 1) { + oneplus_change_motor_speed(speed); + } + + return count; +} + +static ssize_t motor_speed_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long speed = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (g_the_chip->motor_started) + return count; + + if (sscanf(buff, "%lu", &speed) == 1) { + if (speed >=0 && speed <=14) { + g_the_chip->is_speed_set = true; + g_the_chip->test_speed = speed; + MOTOR_LOG("would set speed, test_speed : %d", g_the_chip->test_speed); + } else { + MOTOR_LOG("speed (%d) parameter is invalid, would not set speed", speed); + } + } + + return count; +} + +static ssize_t motor_speed_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->motor_speed); +} + +//slow down speed +static ssize_t motor_slow_down_speed_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long slow_down_speed = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &slow_down_speed) == 1) { + if (slow_down_speed >=0 && slow_down_speed <=14) { + g_the_chip->slow_down_speed = slow_down_speed; + MOTOR_LOG("would set slow_down_speed, slow_down_speed : %d", g_the_chip->slow_down_speed); + } else { + MOTOR_LOG("slow_down_speed (%d) parameter is invalid, would not set slow_down_speed", slow_down_speed); + } + } + + return count; +} + +static ssize_t motor_slow_down_speed_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->slow_down_speed); +} + +//deltad range +static ssize_t deltad_range_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long deltad_range = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &deltad_range) == 1) { + g_the_chip->deltad_range = deltad_range; + MOTOR_LOG("would set deltad_range, deltad_range : %d", g_the_chip->deltad_range); + } + + return count; +} + +static ssize_t deltad_range_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->deltad_range); +} + +static ssize_t begin_stop_detect_percent_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long begin_stop_detect_percent = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &begin_stop_detect_percent) == 1) { + g_the_chip->begin_stop_detect_percent = begin_stop_detect_percent; + MOTOR_LOG("would set begin_stop_detect_percent, begin_stop_detect_percent : %d", + g_the_chip->begin_stop_detect_percent); + } + MOTOR_LOG("begin_stop_detect_percent : %d", begin_stop_detect_percent); + + return count; +} + +static ssize_t begin_stop_detect_percent_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->begin_stop_detect_percent); +} + +static ssize_t factory_mode_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long is_factory_mode = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &is_factory_mode) == 1) { + g_the_chip->is_factory_mode = is_factory_mode; + MOTOR_LOG("would set is_factory_mode, is_factory_mode : %d", g_the_chip->is_factory_mode); + } + MOTOR_LOG("is_factory_mode : %d", is_factory_mode); + + return count; +} + +static ssize_t factory_mode_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->is_factory_mode); +} + +static ssize_t free_fall_irq_times_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long free_fall_irq_times = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &free_fall_irq_times) == 1) { + g_the_chip->free_fall_irq_times = free_fall_irq_times; + MOTOR_LOG("would set free_fall_irq_times, free_fall_irq_times : %d", g_the_chip->free_fall_irq_times); + } + MOTOR_LOG("free_fall_irq_times : %d", free_fall_irq_times); + + return count; +} + +static ssize_t free_fall_irq_times_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->free_fall_irq_times); +} + +static ssize_t infrared_shut_down_state_store(struct device* pdev, struct device_attribute* attr, + const char* buff, size_t count) +{ + + unsigned long infrared_shut_down_state = 0; + + MOTOR_LOG("call"); + + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return count; + } + + if (sscanf(buff, "%lu", &infrared_shut_down_state) == 1) { + g_the_chip->infrared_shut_down_state = infrared_shut_down_state; + MOTOR_LOG("would set infrared_shut_down_state, free_fall_irq_times : %d", g_the_chip->infrared_shut_down_state); + } + MOTOR_LOG("infrared_shut_down_state : %d", infrared_shut_down_state); + + return count; +} + +static ssize_t infrared_shut_down_state_show(struct device* dev,struct device_attribute* attr, char* buf) +{ + if (g_the_chip == NULL) { + MOTOR_ERR("g_the_chip == NULL \n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0);; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->infrared_shut_down_state); +} +static DEVICE_ATTR(direction, S_IRUGO | S_IWUSR, motor_direction_show, motor_direction_store); +static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, motor_speed_show, motor_speed_store); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, motor_mode_show, motor_mode_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, NULL, motor_enable_store); +static DEVICE_ATTR(step_count, S_IRUGO | S_IWUSR, step_count_show, step_count_store); +static DEVICE_ATTR(save_hall_data, S_IRUGO | S_IWUSR, save_hall_data_show, save_hall_data_store); +static DEVICE_ATTR(change_speed, S_IRUGO | S_IWUSR,NULL, motor_change_speed_store); +static DEVICE_ATTR(move_state, S_IRUGO | S_IWUSR, motor_move_state_show,NULL); +static DEVICE_ATTR(config, S_IRUGO | S_IWUSR, motor_all_config_show,NULL); +static DEVICE_ATTR(sw_switch, S_IRUGO | S_IWUSR, motor_sw_switch_show,motor_sw_switch_store); +//static DEVICE_ATTR(speed_change_switch, S_IRUGO | S_IWUSR, motor_speed_change_switch_show,motor_speed_change_switch_store); +static DEVICE_ATTR(position, S_IRUGO | S_IWUSR, motor_position_show,NULL); +static DEVICE_ATTR(manual2auto_switch, S_IRUGO | S_IWUSR, motor_manual2auto_switch_show,motor_manual2auto_switch_store); +static DEVICE_ATTR(motor_test, S_IRUGO | S_IWUSR, motor_test_show,motor_test_store); +static DEVICE_ATTR(hall_data, S_IRUGO | S_IWUSR,hall_data_show,NULL); +static DEVICE_ATTR(hall_reg, S_IRUGO | S_IWUSR,hall_all_reg_show,NULL); +static DEVICE_ATTR(hall_irq_count, S_IRUGO | S_IWUSR,hall_irq_count_show,NULL); +static DEVICE_ATTR(hall_calibration, S_IRUGO | S_IWUSR,hall_calibration_show,hall_calibration_store); +static DEVICE_ATTR(stall, S_IRUGO | S_IWUSR, stall_show, NULL); +static DEVICE_ATTR(stall_steps, S_IRUGO | S_IWUSR, stall_steps_show, NULL); +static DEVICE_ATTR(stall_mode, S_IRUGO | S_IWUSR, stall_mode_show, NULL); +static DEVICE_ATTR(hall_detect_switch, S_IRUGO | S_IWUSR,hall_detect_switch_show,hall_detect_switch_store); +static DEVICE_ATTR(force_move, S_IRUGO | S_IWUSR, NULL, motor_force_move_store); +//static DEVICE_ATTR(stop_time, S_IRUGO | S_IWUSR, motor_stop_time_show, motor_stop_time_store); +//static DEVICE_ATTR(initial_time, S_IRUGO | S_IWUSR, motor_initial_time_show, motor_initial_time_store); +//static DEVICE_ATTR(initial_speed, S_IRUGO | S_IWUSR, motor_initial_speed_show, motor_initial_speed_time_store); +//static DEVICE_ATTR(high_speed, S_IRUGO | S_IWUSR, motor_high_speed_show, motor_high_speed_store); +//static DEVICE_ATTR(high_speed_time, S_IRUGO | S_IWUSR, motor_high_speed_time_show, motor_high_speed_time_store); +static DEVICE_ATTR(slow_down_speed, S_IRUGO | S_IWUSR, motor_slow_down_speed_show, motor_slow_down_speed_store); +static DEVICE_ATTR(deltad_range, S_IRUGO | S_IWUSR, deltad_range_show, deltad_range_store); +static DEVICE_ATTR(begin_stop_detect_percent, S_IRUGO | S_IWUSR, begin_stop_detect_percent_show, begin_stop_detect_percent_store); +static DEVICE_ATTR(factory_mode, S_IRUGO | S_IWUSR, factory_mode_show, factory_mode_store); +static DEVICE_ATTR(free_fall_irq_times, S_IRUGO | S_IWUSR, free_fall_irq_times_show, free_fall_irq_times_store); +static DEVICE_ATTR(infrared_shut_down_state, S_IRUGO | S_IWUSR, infrared_shut_down_state_show, infrared_shut_down_state_store); + + +static struct attribute* __attributes[] = { + &dev_attr_direction.attr, + &dev_attr_speed.attr, + &dev_attr_mode.attr, + &dev_attr_enable.attr, + &dev_attr_step_count.attr, + &dev_attr_save_hall_data.attr, + &dev_attr_change_speed.attr, + &dev_attr_move_state.attr, + &dev_attr_config.attr, + &dev_attr_sw_switch.attr, + &dev_attr_position.attr, + &dev_attr_manual2auto_switch.attr, + &dev_attr_motor_test.attr, + &dev_attr_hall_data.attr, + &dev_attr_hall_reg.attr, + &dev_attr_hall_irq_count.attr, + &dev_attr_hall_calibration.attr, + &dev_attr_stall.attr, + &dev_attr_stall_steps.attr, + &dev_attr_stall_mode.attr, + &dev_attr_hall_detect_switch.attr, + &dev_attr_force_move.attr, + + // &dev_attr_stop_time.attr, + // &dev_attr_initial_time.attr, + // &dev_attr_initial_speed.attr, + // &dev_attr_high_speed.attr, + // &dev_attr_high_speed_time.attr, + &dev_attr_slow_down_speed.attr, + &dev_attr_deltad_range.attr, + &dev_attr_begin_stop_detect_percent.attr, + &dev_attr_factory_mode.attr, + &dev_attr_free_fall_irq_times.attr, + &dev_attr_infrared_shut_down_state.attr, + NULL +}; + +static struct attribute_group __attribute_group = { + .attrs = __attributes +}; + +/********************************************************************* + digital_hall and step_motor register ops function +**********************************************************************/ +int oneplus_register_dhall(const char* name, struct oneplus_hall_operations* ops) +{ + if(name == NULL || ops == NULL) { + MOTOR_ERR("name == NULL || ops == NULL, would not register digital hall \n"); + return -EINVAL; + } + + if (g_the_chip == NULL) { + struct oneplus_motor_chip* chip = kzalloc(sizeof(struct oneplus_motor_chip), GFP_KERNEL); + if (!chip) { + MOTOR_ERR("kzalloc err \n"); + return -ENOMEM; + } + oneplus_motor_chip_init(chip); + g_the_chip = chip; + + } + + MOTOR_LOG("name : %s\n", name); + + if (strcmp(name, "m1120_down") == 0) { + if (g_the_chip->hall_down_ops == NULL) { + g_the_chip->hall_down_ops = ops; + } else { + MOTOR_ERR("hall_down_ops has been registered \n"); + return -EINVAL; + } + } + + if (strcmp(name, "m1120_up") == 0) { + if (g_the_chip->hall_up_ops == NULL) { + g_the_chip->hall_up_ops = ops; + } else { + MOTOR_ERR("hall_up_ops has been registered \n"); + return -EINVAL; + } + } + + return 0; +} + +int oneplus_register_motor(const char* name, struct oneplus_motor_operations* ops) +{ + if(name == NULL || ops == NULL) { + MOTOR_ERR("name == NULL || ops == NULL, would not register step motor \n"); + return -EINVAL; + } + + MOTOR_LOG("motor name : %s \n", name); + if (g_the_chip == NULL) { + struct oneplus_motor_chip* chip = kzalloc(sizeof(struct oneplus_motor_chip), GFP_KERNEL); + if (!chip) { + MOTOR_ERR("kzalloc err \n"); + return -ENOMEM; + } + oneplus_motor_chip_init(chip); + g_the_chip = chip; + } + + if (g_the_chip->motor_ops == NULL) { + g_the_chip->motor_ops = ops; + } else { + MOTOR_ERR("motor_ops has been registered \n"); + return -EINVAL; + } + + return 0; +} + +/********************************************************************* + init function +**********************************************************************/ +static int oneplus_input_dev_init(struct oneplus_motor_chip* chip) +{ + struct input_dev* dev; + int err; + + dev = input_allocate_device(); + if (dev == NULL) { + MOTOR_ERR("input_allocate_device failed, dev == NULL \n"); + return -ENOMEM; + } + + dev->name = "motor"; + dev->id.bustype = BUS_I2C; + + set_bit(MOTOR_EVENT_TYPE, dev->evbit); + set_bit(MOTOR_EVENT_MANUAL_TO_DOWN, dev->keybit); + set_bit(MOTOR_EVENT_UP, dev->keybit); + set_bit(MOTOR_EVENT_UP_ABNORMAL, dev->keybit); + set_bit(MOTOR_EVENT_UP_NORMAL, dev->keybit); + set_bit(MOTOR_EVENT_DOWN, dev->keybit); + set_bit(MOTOR_EVENT_DOWN_ABNORMAL, dev->keybit); + set_bit(MOTOR_EVENT_DOWN_NORMAL, dev->keybit); + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + + MOTOR_ERR("input_register_device failed, err : %d \n", err); + return err; + } + + chip->input_dev = dev; + + return 0; +} + +static int oneplus_motor_chip_init(struct oneplus_motor_chip* chip) +{ + MOTOR_LOG("call \n"); + + if (chip == NULL) { + MOTOR_ERR("chip == NULL \n"); + return -EINVAL; + } + + //step motor property + chip->pwm_duty = 0; + chip->pwm_period = 0; + chip->motor_work_mode = MOTOR_MODE_1_32; + chip->motor_speed = MOTOR_SPEED0; + chip->motor_direction = MOTOR_UPWARD; + chip->motor_enable = false; + chip->pwm_count = 0; + chip->motor_started = false; + chip->motor_switch = true; + + //digital hall property + chip->hall_down_data = 0; + chip->hall_up_data = 0; + chip->hall_down_irq_count = 0; + chip->hall_up_irq_count = 0; + + //calibrate property + chip->hall_down_irq_position = HALL_DETECT_RANGE_HIGH; + chip->hall_up_irq_position = HALL_DETECT_RANGE_HIGH; + chip->camera_up_slow_down_position_hall_down_data = 0; + chip->camera_up_slow_down_position_hall_up_data = MOTOR_STOP_RETARD_VALUE; + chip->camera_down_slow_down_position_hall_down_data = MOTOR_STOP_RETARD_VALUE; + chip->camera_down_slow_down_position_hall_up_data = 0; + chip->is_stall = 0; + chip->stall_steps = 0; + chip->stall_mode = UNKNOW_MODE; + + //special test property + chip->is_motor_test = false; + chip->force_move = false; + chip->is_speed_set = false; + chip->is_factory_mode = 0; + chip->test_speed = MOTOR_SPEED0; + + //logical control property + atomic_set(&chip->in_suspend, 0); + chip->whole_jonery_time = 500000;//500ms default + + chip->whole_jonery_length = 82;//8.2mm, unuse + chip->begin_stop_detect_percent = 95;//95% default + chip->speed_up_distance = 5;//0.5mm + chip->speed_down_distance = 3;//0.3mm + chip->speed_up_pwm_count = 30 * 32;//75 step default + chip->camera_up_step_count = 1380 * 32;//1380 step default + chip->slow_down_speed = MOTOR_SPEED0; + chip->deltad_range = 5;//5 default + //chip->speed_down_pwm_count = 0; + chip->position_detect_delay = 15;//15ms + chip->camera_position_detect = false; + //chip->motor_start_time = 0; + chip->save_hall_data_to_file = false; + chip->hall_detect_switch = true; + chip->position = BOTTOM_STATE; + chip->move_state = MOTOR_STOP; + chip->is_skip_pos_check = false; + chip->manual2auto_down_switch = true; + chip->is_free_fall = false; + chip->free_fall_irq_times = 0; + chip->infrared_shut_down_state = 0; + chip->free_fall_gpio = 0; + chip->free_fall_irq = 0; + chip->irq_monitor_started = false; + chip->is_irq_abnormal = false; + chip->is_t0_structure = false; + chip->is_mag_positive = true; + chip->led_on = false; + + chip->dev = NULL; + chip->pctrl = NULL; + chip->free_fall_state = NULL; + chip->input_dev = NULL; + chip->manual2auto_wq = NULL; + chip->motor_run_work_wq = NULL; + chip->hall_up_ops = NULL; + chip->hall_down_ops = NULL; + chip->motor_ops = NULL; + + return 0; +} + +static void oneplus_motor_awake_init(struct oneplus_motor_chip* chip) +{ + if (chip == NULL) { + MOTOR_ERR("chip == NULL \n"); + return; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + wake_lock_init(&chip->suspend_lock, WAKE_LOCK_SUSPEND, "motor_wakelock"); +#else + chip->suspend_ws = wakeup_source_register("motor_wakelock"); +#endif +} + + +static void oneplus_motor_free_fall_register(struct oneplus_motor_chip* chip) +{ + struct device_node* np = NULL; + int err = 0; + + np = chip->dev->of_node; + + chip->pctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR(chip->pctrl)) { + MOTOR_ERR("failed to get pinctrl \n"); + return; + }; + + chip->free_fall_state = pinctrl_lookup_state(chip->pctrl, "free_fall_input"); + if (IS_ERR(chip->free_fall_state)) { + err = PTR_ERR(chip->free_fall_state); + MOTOR_ERR("pinctrl_lookup_state failed, err : %d \n", err); + return; + }; + + pinctrl_select_state(chip->pctrl,chip->free_fall_state); + chip->free_fall_gpio = of_get_named_gpio(np, "motor,irq-gpio", 0); + + if (!gpio_is_valid(chip->free_fall_gpio)) { + MOTOR_LOG("qcom,hall-power-gpio gpio not specified \n"); + } else { + err = gpio_request(chip->free_fall_gpio, "motor-irq-gpio"); + if (err) + MOTOR_LOG("request free_fall_gpio gpio failed, err : %d \n",err); + + err = gpio_direction_input(chip->free_fall_gpio); + msleep(50); + chip->free_fall_irq = gpio_to_irq(chip->free_fall_gpio); + + if (request_irq(chip->free_fall_irq, &oneplus_free_fall_detect_handler, IRQ_TYPE_EDGE_RISING, "free_fall", NULL)) { + MOTOR_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return; + } + irq_set_irq_wake(chip->free_fall_irq, 1); + } + + MOTOR_LOG("gpio %d irq:%d \n",chip->free_fall_gpio, chip->free_fall_irq); +} + +static void oneplus_motor_reset_check(struct oneplus_motor_chip* chip) +{ + oneplus_hall_get_abs_data(HALL_DOWN); + + MOTOR_LOG("hall0 data %d hall_down_irq_position %d \n", chip->hall_down_data, chip->hall_down_irq_position); + + if (chip->hall_down_data < 0) + chip->hall_down_data = 0 - chip->hall_down_data; + + if (chip->hall_down_data < chip->hall_down_irq_position) { + MOTOR_LOG("reset motor \n"); + oneplus_motor_downward(); + } + +} + +static void oneplus_parameter_init(struct oneplus_motor_chip* chip) +{ + u32 id = 0; + struct device_node* np = NULL; + int err = -1; + + if (chip == NULL || chip->dev == NULL) { + MOTOR_ERR("oneplus_parameter_init failed, chip == NULL || chip->dev == NULL"); + return; + } + + np = chip->dev->of_node; + err = of_property_read_u32(np, "structure,id", &id); + if (err && (err != -EINVAL)) { + MOTOR_ERR("get structure,id err : %d", err); + } else { + MOTOR_LOG("read structure,id success, id : %d", id); + if (id == 1) { + MOTOR_LOG("is T0 structure"); + chip->is_t0_structure = true; + } + } + + oneplus_hall_update_threshold(HALL_DOWN, BOTTOM_STATE, 511, 511); + oneplus_hall_update_threshold(HALL_UP, BOTTOM_STATE, 511, 511); + oneplus_dhall_set_detection_mode(HALL_DOWN, DETECTION_MODE_INTERRUPT); + oneplus_dhall_set_detection_mode(HALL_UP, DETECTION_MODE_INTERRUPT); + + oneplus_set_motor_work_mode_para(MOTOR_MODE_1_32); + + oneplus_set_motor_direction(MOTOR_UPWARD); + + oneplus_motor_awake_init(chip); + + + oneplus_hall_get_real_data(HALL_DOWN); + oneplus_hall_get_real_data(HALL_UP); + //save hall data + MOTOR_LOG("hall_down_data : %d, HALL_UP : %d", chip->hall_down_data, chip->hall_up_data); + if (chip->hall_down_data < 0) { + MOTOR_LOG("mag is negative"); + chip->is_mag_positive = false; + } + +} + +static int motor_platform_probe(struct platform_device* pdev) +{ + struct oneplus_motor_chip* chip = NULL; + struct proc_dir_entry* dir = NULL; + int err = 0; + + + MOTOR_LOG("call \n"); + + if (g_the_chip == NULL) { + chip = kzalloc(sizeof(struct oneplus_motor_chip), GFP_KERNEL); + if (!chip) { + MOTOR_ERR("kzalloc err \n"); + return -ENOMEM; + } + g_the_chip = chip; + } else { + chip = g_the_chip; + } + + chip->dev = &pdev->dev; + + if (chip->hall_up_ops == NULL || chip->hall_down_ops == NULL) { + MOTOR_ERR("no digital hall available \n"); + goto fail; + } + + if (chip->motor_ops == NULL) { + MOTOR_ERR("no motor driver available \n"); + goto fail; + } + //create + err = sysfs_create_group(&pdev->dev.kobj, &__attribute_group); + if(err) { + MOTOR_ERR("sysfs_create_group failed, err : %d \n", err); + goto sysfs_create_fail; + } + + + + err = oneplus_input_dev_init(chip); + if (err < 0) { + MOTOR_ERR("oneplus_input_dev_init failed, err : %d \n", err); + goto input_fail; + } + + chip->motor_run_work_wq = create_singlethread_workqueue("motor_run_work_wq"); + if (chip->motor_run_work_wq == NULL) { + MOTOR_ERR("create_singlethread_workqueue failed, motor_run_work_wq == NULL \n"); + goto input_fail; + } + + chip->manual2auto_wq = create_singlethread_workqueue("manual2auto_wq"); + if (!chip->manual2auto_wq) { + MOTOR_ERR("create_singlethread_workqueue failed, manual2auto_wq == NULL \n"); + goto input_fail; + } + + oneplus_motor_free_fall_register(chip); + + oneplus_parameter_init(chip); + + hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->stop_timer.function = motor_stop_timer_func; + + hrtimer_init(&chip->speed_up_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->speed_up_timer.function = motor_speed_up_timer_func; + + //INIT_WORK(&chip->motor_work, motor_run_work); + //INIT_WORK(&chip->manual_position_work,manual_position_detect_work);//zhe + + + alarm_init(&chip->reset_timer, ALARM_BOOTTIME, motor_reset_timer_func); + + INIT_DELAYED_WORK(&chip->detect_work, camera_position_detect_work); + INIT_DELAYED_WORK(&chip->up_work, manual_to_auto_up_work); + INIT_DELAYED_WORK(&chip->down_work, manual_to_auto_down_work); + INIT_DELAYED_WORK(&chip->free_fall_irq_check_work, free_fall_irq_check_work_func); + INIT_WORK(&chip->motor_work, motor_run_work); + + chip->fb_notify.notifier_call = fb_notifier_callback; + #ifdef CONFIG_DRM_MSM + msm_drm_register_client(&chip->fb_notify); + #else + fb_register_client(&chip->fb_notify); + #endif + + oneplus_motor_reset_check(g_the_chip); + + MOTOR_LOG("success. \n"); + return 0; + +input_fail: +sysfs_create_fail: +fail: + kfree(chip); + g_the_chip = NULL; + MOTOR_LOG("fail \n"); + return -EINVAL; +} + +static int motor_platform_remove(struct platform_device* pdev) +{ + if (g_the_chip) { + sysfs_remove_group(&pdev->dev.kobj, &__attribute_group); + input_unregister_device(g_the_chip->input_dev); + input_free_device(g_the_chip->input_dev); + kfree(g_the_chip); + g_the_chip = NULL; + } + return 0; +} + +static int motor_platform_suspend(struct platform_device* pdev, pm_message_t state) +{ + if (g_the_chip) { + atomic_set(&g_the_chip->in_suspend, 1); + } + return 0; +} + +static int motor_platform_resume(struct platform_device* pdev) +{ + if (g_the_chip) { + atomic_set(&g_the_chip->in_suspend, 0); + } + return 0; +} +static void motor_platform_shutdown(struct platform_device* pdev) +{ + MOTOR_LOG("call \n"); + if (g_the_chip) { + //when phone is power off, check if camera is outside + oneplus_motor_reset_check(g_the_chip); + } + return; +} + + +static const struct of_device_id of_motor_match[] = { + { .compatible = "oneplus-motor"}, + {}, +}; +MODULE_DEVICE_TABLE(of, of_motor_match); + +static struct platform_driver motor_platform_driver = { + .probe = motor_platform_probe, + .remove = motor_platform_remove, + .suspend = motor_platform_suspend, + .resume = motor_platform_resume, + .shutdown = motor_platform_shutdown, + .driver = { + .name = "oneplus_motor", + .of_match_table = of_motor_match, + }, +}; + +static int __init motor_platform_init(void) +{ + MOTOR_LOG("call \n"); + + platform_driver_register(&motor_platform_driver); + return 0; +} + +late_initcall(motor_platform_init); +MODULE_DESCRIPTION("camera motor platform driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("quentin.lin@oneplus.com"); diff --git a/drivers/oneplus/step_motor/oneplus_motor.h b/drivers/oneplus/step_motor/oneplus_motor.h new file mode 100644 index 0000000000000000000000000000000000000000..ac6c0c417f9ed9a433680c511a0420e9d6f768d2 --- /dev/null +++ b/drivers/oneplus/step_motor/oneplus_motor.h @@ -0,0 +1,273 @@ +/**************************************************************************************** +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_motor.h +** +** Description: +** Definitions for m1120 camera motor control layer. +** +****************************************************************************************/ +#ifndef __ONEPLUS_MOTOR__H +#define __ONEPLUS_MOTOR__H + +#include +#include + +#define MOTOR_TAG "[oneplus_motor] " +#define MOTOR_ERR(fmt, args...) printk(KERN_ERR MOTOR_TAG" %s : "fmt,__FUNCTION__,##args) +#define MOTOR_LOG(fmt, args...) printk(KERN_INFO MOTOR_TAG" %s : "fmt,__FUNCTION__,##args) + +//camera state event to report +#define MOTOR_EVENT_TYPE EV_KEY +#define MOTOR_EVENT_MANUAL_TO_DOWN KEY_F14 +#define MOTOR_EVENT_UP KEY_F15 +#define MOTOR_EVENT_UP_ABNORMAL KEY_F16 +#define MOTOR_EVENT_UP_NORMAL KEY_F17 +#define MOTOR_EVENT_DOWN KEY_F18 +#define MOTOR_EVENT_DOWN_ABNORMAL KEY_F19 +#define MOTOR_EVENT_DOWN_NORMAL KEY_F20 + +//position hall data +#define HALL_DETECT_RANGE_HIGH (150) +#define HALL_DETECT_RANGE_LOW (-512) +#define MOTOR_RESET_TIMER (500)//500ms +#define MOTOR_STOP_STAITC_POS_VALUE (10) +#define MOTOR_STOP_STAITC_NEG_VALUE (-10) +#define MOTOR_STOP_RETARD_VALUE (500) +//irq +#define MOTOR_IRQ_MONITOR_TIME (20)//20ms +#define MOTOR_IRQ_MONITOR_COUNT (8) + +#define MOTOR_STOP_TIMEOUT (12000) //80k + +typedef enum hall_id { + HALL_DOWN = 0, + HALL_UP, +} hall_id; + +enum dhall_detection_mode { + DETECTION_MODE_POLLING = 0, + DETECTION_MODE_INTERRUPT, + DETECTION_MODE_INVALID, +}; + +enum motor_type { + MOTOR_UNKNOWN = 0, + MOTOR_FI5, + MOTOR_FI6, +}; + +typedef enum motor_power { + MOTOR_POWER_OFF = 0, + MOTOR_POWER_ON, +} motor_power; + +typedef enum motor_direction_t { + MOTOR_DOWN = 0, + MOTOR_UPWARD, +} motor_direction_t; + +typedef enum camera_position_state_event { + MANUAL_TO_DOWN_EVENT = 0, + UPING_EVENT, + UP_ABNORMA_EVENT, + UP_NORMAL_EVENT, + DOWNING_EVENT, + DOWN_ABNORMAL_EVENT, + DOWN_NORMAL_EVENT +} camera_position_state_event; + +enum wakelock_id { + MOTOR_RUN_LOCK = 0, + HALL_DATA_LOCK, + POSITION_DETECT_LOCK, + MAX_LOCK +}; + +typedef enum motor_move_state { + MOTOR_STOP = 0,//never move after boot + MOTOR_UPWARD_ING,//motor is uping + MOTOR_DOWNWARD_ING,//motor down stop , may be abnormal + MOTOR_UPWARD_STOP,//motor up stop , may be abnormal + MOTOR_DOWNWARD_STOP//motor is downing +} motor_move_state; + +typedef enum camera_position { + PEAK_STATE, + BOTTOM_STATE, + MID_STATE, +} camera_position; + +typedef enum motor_stall_mode { + ENTER_DELTAD_RANGE_TWO_TIEMS = 0, + ENTER_DELTAD_AND_SHAKE, + ONLY_SHAKE, + UNKNOW_MODE, +} motor_stall_mode_t; + +typedef enum motor_work_mode { + MOTOR_MODE_FULL = 0, + MOTOR_MODE_1_2, + MOTOR_MODE_1_4, + MOTOR_MODE_1_8, + MOTOR_MODE_1_16, + MOTOR_MODE_1_32 +} motor_work_mode_t; + +typedef enum motor_speed_t { + MOTOR_SPEED0 = 0, //high 2500pps 80khz + MOTOR_SPEED1, // 2000pps 64khz + MOTOR_SPEED2, // 1600pps 51.2khz + MOTOR_SPEED3, // 1200pps 38.4khz + MOTOR_SPEED4, // 1000pps 32khz + MOTOR_SPEED5, // 800pps 25.6khz + MOTOR_SPEED6, // 700pps 22.4khz + MOTOR_SPEED7, // 600pps 19.2khz + MOTOR_SPEED8, // 518pps 16.6khz + MOTOR_SPEED9, // 400pps 12.8khz + MOTOR_SPEED10, // 300pps 9.6kkhz + MOTOR_SPEED11, // 200pps 6.4kkhz + MOTOR_SPEED12, // 100pps 3.2kkhz + MOTOR_SPEED13, //LOW 50pps 1.6khz + MOTOR_SPEED_SPECIAL //2800pps +} motor_speed_t; + + +struct oneplus_hall_operations { + const char* name; + bool (*is_power_on) (void); + int (*set_hall_enable_state) (bool enable); + bool (*get_hall_enable_state) (void); + int (*get_data_real) (short* data); + int (*get_data_abs) (short* data); + int (*set_detection_mode) (u8 mode); + int (*enable_irq) (bool enable); + int (*clear_irq) (void); + int (*get_irq_state) (void); + bool (*update_threshold) (int position, short lowthd, short highthd); + void (*dump_regs) (u8* buf); + int (*set_reg) (int reg, int val); +}; + +struct oneplus_motor_operations { + const char* name; + int (*set_power) (int mode); + int (*set_direction) (int dir); + int (*set_working_mode) (int mode); + int (*get_all_config)(int* config , int count); + int (*calculate_pwm_count) (int angle, int mode); + int (*pwm_config) (int duty_ns, int period_ns); + int (*pwm_enable) (void); + int (*pwm_disable) (void); + int (*get_motor_type) (void); +}; + +struct oneplus_motor_chip { + //step motor property + unsigned long pwm_duty; + unsigned long pwm_period; + motor_work_mode_t motor_work_mode; + motor_speed_t motor_speed; + motor_direction_t motor_direction; + bool motor_enable; + bool motor_started; + bool motor_switch; + + //digital hall property + short hall_down_data; + short hall_up_data; + int hall_down_irq_count; + int hall_up_irq_count; + short hall_down_irq_position; + short hall_up_irq_position; + + //calibrate property + short camera_up_slow_down_position_hall_down_data; + short camera_up_slow_down_position_hall_up_data; + short camera_down_slow_down_position_hall_down_data; + short camera_down_slow_down_position_hall_up_data; + short bottom_position_hall_down_data; + short bottom_position_hall_up_data; + short peak_position_hall_down_data; + short peak_position_hall_up_data; + int camera_up_step_count; + int is_stall; + int stall_steps; + motor_stall_mode_t stall_mode; + + //special test property + bool is_motor_test; + bool force_move; + bool is_speed_set; + int is_factory_mode;//0:normal, 1:calibrate, 2:step test + motor_speed_t test_speed; + + //logical control property + atomic_t in_suspend; + int pwm_count; + unsigned long whole_jonery_time; + int whole_jonery_length; + int begin_stop_detect_percent; + int speed_up_distance; + int speed_down_distance; + int speed_up_pwm_count; + int slow_down_speed; + int deltad_range; + //int speed_down_pwm_count; + bool camera_position_detect; + int position_detect_delay; + struct timeval motor_start_time; + bool save_hall_data_to_file; + bool hall_detect_switch; + camera_position position; + motor_move_state move_state; + bool is_skip_pos_check; + bool manual2auto_down_switch; + bool is_free_fall; + int free_fall_irq_times; + int infrared_shut_down_state; + unsigned int free_fall_gpio; + int free_fall_irq; + bool irq_monitor_started; + bool is_irq_abnormal; + bool is_t0_structure; + bool is_mag_positive; + bool led_on; + + + struct device* dev; + struct pinctrl* pctrl; + struct pinctrl_state* free_fall_state; + struct input_dev* input_dev; + struct workqueue_struct* manual2auto_wq; + struct workqueue_struct* motor_run_work_wq; + struct delayed_work detect_work; + struct delayed_work free_fall_irq_check_work; + struct work_struct motor_work; + struct delayed_work up_work; + struct delayed_work down_work; + struct hrtimer stop_timer; + bool stop_timer_trigger; + struct hrtimer speed_up_timer; + struct alarm reset_timer; + struct notifier_block fb_notify; + struct oneplus_hall_operations* hall_up_ops; + struct oneplus_hall_operations* hall_down_ops; + struct oneplus_motor_operations* motor_ops; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + struct wake_lock suspend_lock; +#else + struct wakeup_source* suspend_ws; +#endif + +}; + + +/************************digital_hall and step_motor register ops function************************/ +int oneplus_register_dhall(const char* name, struct oneplus_hall_operations* ops); +int oneplus_register_motor(const char* name, struct oneplus_motor_operations* ops); + +int oneplus_dhall_irq_handler(unsigned int id); + + +#endif diff --git a/drivers/oneplus/step_motor/oneplus_motor_notifier.c b/drivers/oneplus/step_motor/oneplus_motor_notifier.c new file mode 100755 index 0000000000000000000000000000000000000000..43c9c8eb0df8a86d8a115f85cb8052c5be75ab2d --- /dev/null +++ b/drivers/oneplus/step_motor/oneplus_motor_notifier.c @@ -0,0 +1,54 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_motor_notifier.c +** +** Description: +** Definitions for motor notifier. +** +**************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +static BLOCKING_NOTIFIER_HEAD(motor_chain); + +/** + * register_motor_notifier - register a client notifier + * @nb: notifier block to callback on events + */ +int register_motor_notifier(struct notifier_block *nb) +{ + if (!nb) + return -EINVAL; + + return blocking_notifier_chain_register(&motor_chain, nb); +} +EXPORT_SYMBOL(register_motor_notifier); + +/** + * unregister_motor_notifier - unregister a client notifier + * @nb: notifier block to callback on events + */ +int unregister_motor_notifier(struct notifier_block *nb) +{ + if (!nb) + return -EINVAL; + + return blocking_notifier_chain_unregister(&motor_chain, nb); +} +EXPORT_SYMBOL(unregister_motor_notifier); + +/** + * motor_notifier_call_chain - notify clients of sensor_events + * + */ +int motor_notifier_call_chain(unsigned long val) +{ + return blocking_notifier_call_chain(&motor_chain, val, NULL); +} +EXPORT_SYMBOL(motor_notifier_call_chain); diff --git a/drivers/oneplus/step_motor/oneplus_motor_notifier.h b/drivers/oneplus/step_motor/oneplus_motor_notifier.h new file mode 100755 index 0000000000000000000000000000000000000000..c665237b26c7f82771ad5c9f03068b085802788c --- /dev/null +++ b/drivers/oneplus/step_motor/oneplus_motor_notifier.h @@ -0,0 +1,25 @@ +/**************************************************************************************** +** Copyright (C), 2013-2018, ONEPLUS Mobile Comm Corp., Ltd +** File: oneplus_motor_notifier.H +** +** Description: +** Definitions for motor notifier. +** +****************************************************************************************/ + +#ifndef _ONEPLUS_MOTOR_NOTIFIER +#define _ONEPLUS_MOTOR_NOTIFIER + +#include + +enum motor_event { + MOTOR_UP_EVENT = 0, + MOTOR_DOWN_EVENT, + MOTOR_BLOCK_EVENT, +}; + +extern int register_motor_notifier(struct notifier_block *nb); +extern int unregister_motor_notifier(struct notifier_block *nb); +extern int motor_notifier_call_chain(unsigned long val); + +#endif //_ONEPLUS_MOTOR_NOTIFIER \ No newline at end of file diff --git a/drivers/oneplus/tri_state_key/Kconfig b/drivers/oneplus/tri_state_key/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..39a6c0a10218efd240f107c6ecbef39b39076318 --- /dev/null +++ b/drivers/oneplus/tri_state_key/Kconfig @@ -0,0 +1,14 @@ +config TRI_STATE_KEY + default y + tristate "switch Profiles by this triple key" + help + Say Y here if you want to enable the feature. + +config HALL_TRI_STATE_KEY + default n + tristate "switch Profiles by this triple key" + help + Say Y here if you want to enable the feature. + +source "drivers/oneplus/tri_state_key/hall_ic/Kconfig" +source "drivers/oneplus/tri_state_key/ist_hall_ic/Kconfig" diff --git a/drivers/oneplus/tri_state_key/Makefile b/drivers/oneplus/tri_state_key/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..ea128915a4560900b732ad95b0a3175030939cce --- /dev/null +++ b/drivers/oneplus/tri_state_key/Makefile @@ -0,0 +1,11 @@ +#obj-$(CONFIG_SENSOR_HALL_MXM1120) +=hall_ic/ +#obj-$(CONFIG_SENSOR_HALL_IST8801) +=ist_hall_ic/ +#obj-$(CONFIG_TRI_STATE_KEY) += tri_state_key.o +#obj-$(CONFIG_HALL_TRI_STATE_KEY) += oneplus_tri_key.o +ifeq ($(CONFIG_HALL_TRI_STATE_KEY),y) +obj-y +=hall_ic/ +obj-y +=ist_hall_ic/ +obj-y +=oneplus_tri_key.o +else +obj-y +=tri_state_key.o +endif diff --git a/drivers/oneplus/tri_state_key/hall_ic/Kconfig b/drivers/oneplus/tri_state_key/hall_ic/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..b6ce56cad6cebaef688e11875913bede08c8f271 --- /dev/null +++ b/drivers/oneplus/tri_state_key/hall_ic/Kconfig @@ -0,0 +1,5 @@ +config SENSOR_HALL_MXM1120 + tristate "digital hall m1120 Controler" + default n + help + Say Y here to enable m1120. \ No newline at end of file diff --git a/drivers/oneplus/tri_state_key/hall_ic/Makefile b/drivers/oneplus/tri_state_key/hall_ic/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..0ccb3ed6e88eea8283df47652fd2bd88d1db6962 --- /dev/null +++ b/drivers/oneplus/tri_state_key/hall_ic/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. + +#obj-$(CONFIG_SENSOR_HALL_MXM1120) += hall_mxm1120_up.o hall_mxm1120_down.o + +obj-y += hall_mxm1120_up.o hall_mxm1120_down.o +#mxm1120_down.o + + + diff --git a/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120.h b/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120.h new file mode 100644 index 0000000000000000000000000000000000000000..af2b467ad3373f7aac1804e78f0e710e4769c6db --- /dev/null +++ b/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120.h @@ -0,0 +1,308 @@ +#ifndef __MXM1120_H__ +#define __MXM1120_H__ + +#include +#include + +/* ********************************************************* */ +/* feature of ic revision */ +/* ********************************************************* */ +#define M1120_REV_0_2 (0x02) +#define M1120_REV_1_0 (0x10) +#define M1120_REV M1120_REV_1_0 +#define M1120_DRIVER_VERSION "Ver1.04-140226" +/* ********************************************************* */ + +/* ********************************************************* */ +/* property of driver */ +/* ********************************************************* */ +#define M1120_DRIVER_NAME_UP "hall_m1120_up" +#define M1120_DRIVER_NAME_MIDDLE "m1120_middle" +#define M1120_DRIVER_NAME_DOWN "hall_m1120_down" +#define M1120_IRQ_NAME "m1120-irq" +#define M1120_PATH "/dev/m1120" + +/* +SAD1 SAD0 == 00 0001100 R/W (7bits)0x0C (8bits)0x18 +SAD1 SAD0 == 01 0001101 R/W (7bits)0x0D (8bits)0x1A +SAD1 SAD0 == 10 0001110 R/W (7bits)0x0E (8bits)0x1C +SAD1 SAD0 == 11 0001111 R/W (7bits)0x0F (8bits)0x1E +*/ +#define M1120_SLAVE_ADDR (0x18) +/* ********************************************************* */ + +/* ********************************************************* */ +/* register map */ +/* ********************************************************* */ +#define M1120_REG_PERSINT (0x00) +#define M1120_VAL_PERSINT_COUNT(n) (n<<4) +#define M1120_VAL_PERSINT_INTCLR (0x01) + /* + [7:4] PERS : interrupt persistence count + [0] INTCLR = 1 : interrupt clear + */ +/* --------------------------------------------------------- */ +#define M1120_REG_INTSRS (0x01) +#define M1120_VAL_INTSRS_INT_ON (0x80) +#define M1120_DETECTION_MODE_INTERRUPT M1120_VAL_INTSRS_INT_ON +#define M1120_VAL_INTSRS_INT_OFF (0x00) +#define M1120_DETECTION_MODE_POLLING M1120_VAL_INTSRS_INT_OFF +#define M1120_VAL_INTSRS_INTTYPE_BESIDE (0x00) +#define M1120_VAL_INTSRS_INTTYPE_WITHIN (0x10) +#define M1120_VAL_INTSRS_SRS_10BIT_0_068mT (0x00) +#define M1120_VAL_INTSRS_SRS_10BIT_0_034mT (0x01) +#define M1120_VAL_INTSRS_SRS_10BIT_0_017mT (0x02) +#define M1120_VAL_INTSRS_SRS_10BIT_0_009mT (0x03) +#define M1120_VAL_INTSRS_SRS_10BIT_0_004mT (0x04) +#define M1120_VAL_INTSRS_SRS_8BIT_0_272mT (0x00) +#define M1120_VAL_INTSRS_SRS_8BIT_0_136mT (0x01) +#define M1120_VAL_INTSRS_SRS_8BIT_0_068mT (0x02) +#define M1120_VAL_INTSRS_SRS_8BIT_0_036mT (0x03) +#define M1120_VAL_INTSRS_SRS_8BIT_0_016mT (0x04) + /* + [7] INTON = 0 : disable interrupt + [7] INTON = 1 : enable interrupt + [4] INT_TYP = 0 : generate interrupt when raw data is beside range of threshold + [4] INT_TYP = 1 : generate interrupt when raw data is within range of threshold + [2:0] SRS : select sensitivity type when M1120_VAL_OPF_BIT_10 + 000 : 0.068 (mT/LSB) + 001 : 0.034 (mT/LSB) + 010 : 0.017 (mT/LSB) + 011 : 0.009 (mT/LSB) + 100 : 0.004 (mT/LSB) + 101 : 0.017 (mT/LSB) + 110 : 0.017 (mT/LSB) + 111 : 0.017 (mT/LSB) + [2:0] SRS : select sensitivity type when M1120_VAL_OPF_BIT_8 + 000 : 0.272 (mT/LSB) + 001 : 0.136 (mT/LSB) + 010 : 0.068 (mT/LSB) + 011 : 0.036 (mT/LSB) + 100 : 0.016 (mT/LSB) + 101 : 0.068 (mT/LSB) + 110 : 0.068 (mT/LSB) + 111 : 0.068 (mT/LSB) + */ +/* --------------------------------------------------------- */ +#define M1120_REG_LTHL (0x02) + /* + [7:0] LTHL : low byte of low threshold value + */ +/* --------------------------------------------------------- */ +#define M1120_REG_LTHH (0x03) + /* + [7:6] LTHH : high 2bits of low threshold value with sign + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HTHL (0x04) + /* + [7:0] HTHL : low byte of high threshold value + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HTHH (0x05) + /* + [7:6] HTHH : high 2bits of high threshold value with sign + */ +/* --------------------------------------------------------- */ +#define M1120_REG_I2CDIS (0x06) +#define M1120_VAL_I2CDISABLE (0x37) + /* + [7:0] I2CDIS : disable i2c + */ +/* --------------------------------------------------------- */ +#define M1120_REG_SRST (0x07) +#define M1120_VAL_SRST_RESET (0x01) + /* + [0] SRST = 1 : soft reset + */ +/* --------------------------------------------------------- */ +#define M1120_REG_OPF (0x08) +#define M1120_VAL_OPF_FREQ_20HZ (0x00) +#define M1120_VAL_OPF_FREQ_10HZ (0x10) +#define M1120_VAL_OPF_FREQ_6_7HZ (0x20) +#define M1120_VAL_OPF_FREQ_5HZ (0x30) +#define M1120_VAL_OPF_FREQ_80HZ (0x40) +#define M1120_VAL_OPF_FREQ_40HZ (0x50) +#define M1120_VAL_OPF_FREQ_26_7HZ (0x60) +#define M1120_VAL_OPF_EFRD_ON (0x08) +#define M1120_VAL_OPF_BIT_8 (0x02) +#define M1120_VAL_OPF_BIT_10 (0x00) +#define M1120_VAL_OPF_HSSON_ON (0x01) +#define M1120_VAL_OPF_HSSON_OFF (0x00) + /* + [6:4] OPF : operation frequency + 000 : 20 (Hz) + 001 : 10 (Hz) + 010 : 6.7 (Hz) + 011 : 5 (Hz) + 100 : 80 (Hz) + 101 : 40 (Hz) + 110 : 26.7 (Hz) + 111 : 20 (Hz) + [3] EFRD = 0 : keep data without accessing eFuse + [3] EFRD = 1 : update data after accessing eFuse + [1] BIT = 0 : 10 bit resolution + [1] BIT = 1 : 8 bit resolution + [0] HSSON = 0 : Off power down mode + [0] HSSON = 1 : On power down mode + + */ +/* --------------------------------------------------------- */ +#define M1120_REG_DID (0x09) +#define M1120_VAL_DID (0x9C) + /* + [7:0] DID : Device ID + */ +/* --------------------------------------------------------- */ +#define M1120_REG_INFO (0x0A) + /* + [7:0] INFO : Information about IC + */ +/* --------------------------------------------------------- */ +#define M1120_REG_ASA (0x0B) + /* + [7:0] ASA : Hall Sensor sensitivity adjustment + */ +/* --------------------------------------------------------- */ +#define M1120_REG_ST1 (0x10) +#define M1120_VAL_ST1_DRDY (0x01) + /* + [4] INTM : status of interrupt mode + [1] BITM : status of resolution + [0] DRDY : status of data ready + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HSL (0x11) + /* + [7:0] HSL : low byte of hall sensor measurement data + */ +/* --------------------------------------------------------- */ +#define M1120_REG_HSH (0x12) + /* + [7:6] HSL : high 2bits of hall sensor measurement data with sign + */ +/* ********************************************************* */ + + +/* ********************************************************* */ + + +/* ********************************************************* */ +/* ioctl command */ +/* ********************************************************* */ +#define M1120_IOCTL_BASE (0x80) +#define M1120_IOCTL_SET_ENABLE _IOW(M1120_IOCTL_BASE, 0x00, int) +#define M1120_IOCTL_GET_ENABLE _IOR(M1120_IOCTL_BASE, 0x01, int) +#define M1120_IOCTL_SET_DELAY _IOW(M1120_IOCTL_BASE, 0x02, int) +#define M1120_IOCTL_GET_DELAY _IOR(M1120_IOCTL_BASE, 0x03, int) +#define M1120_IOCTL_SET_CALIBRATION _IOW(M1120_IOCTL_BASE, 0x04, int*) +#define M1120_IOCTL_GET_CALIBRATED_DATA _IOR(M1120_IOCTL_BASE, 0x05, int*) +#define M1120_IOCTL_SET_INTERRUPT _IOW(M1120_IOCTL_BASE, 0x06, unsigned int) +#define M1120_IOCTL_GET_INTERRUPT _IOR(M1120_IOCTL_BASE, 0x07, unsigned int*) +#define M1120_IOCTL_SET_THRESHOLD_HIGH _IOW(M1120_IOCTL_BASE, 0x08, unsigned int) +#define M1120_IOCTL_GET_THRESHOLD_HIGH _IOR(M1120_IOCTL_BASE, 0x09, unsigned int*) +#define M1120_IOCTL_SET_THRESHOLD_LOW _IOW(M1120_IOCTL_BASE, 0x0A, unsigned int) +#define M1120_IOCTL_GET_THRESHOLD_LOW _IOR(M1120_IOCTL_BASE, 0x0B, unsigned int*) +#define M1120_IOCTL_SET_REG _IOW(M1120_IOCTL_BASE, 0x0C, int) +#define M1120_IOCTL_GET_REG _IOR(M1120_IOCTL_BASE, 0x0D, int) +/* ********************************************************* */ + + +/* ********************************************************* */ +/* event property */ +/* ********************************************************* */ +#define DEFAULT_EVENT_TYPE EV_ABS +#define DEFAULT_EVENT_CODE ABS_X +#define DEFAULT_EVENT_DATA_CAPABILITY_MIN (-32768) +#define DEFAULT_EVENT_DATA_CAPABILITY_MAX (32767) +/* ********************************************************* */ +/* delay property */ +/* ********************************************************* */ +#define M1120_DELAY_MAX (200) // ms +#define M1120_DELAY_MIN (20) // ms +#define M1120_DELAY_FOR_READY (10) // ms +/* ********************************************************* */ + + +/* ********************************************************* */ +/* data type for driver */ +/* ********************************************************* */ + +enum { + OPERATION_MODE_POWERDOWN, + OPERATION_MODE_MEASUREMENT, + OPERATION_MODE_FUSEROMACCESS +}; + +#define M1120_REG_NUM (15) +typedef union { + struct { + unsigned char persint; + unsigned char intsrs; + unsigned char lthl; + unsigned char lthh; + unsigned char hthl; + unsigned char hthh; + unsigned char i2cdis; + unsigned char srst; + unsigned char opf; + unsigned char did; + unsigned char info; + unsigned char asa; + unsigned char st1; + unsigned char hsl; + unsigned char hsh; + } map; + unsigned char array[M1120_REG_NUM]; +} m1120_reg_t; + +typedef struct { + struct mutex enable; + struct mutex data; +} m1120_mutex_t; + +typedef struct { + atomic_t enable; + atomic_t delay; + atomic_t debug; +} m1120_atomic_t; + +typedef struct { + int power_vi2c; + int power_vdd; + int interrupt_gpio; + int interrupt_irq; +} m1120_platform_data_t; + +typedef struct { + struct i2c_client *client; + struct input_dev *input_dev; + m1120_mutex_t mtx; + m1120_atomic_t atm; + m1120_reg_t reg; + bool irq_enabled; + int calibrated_data; + int last_data; + short thrhigh; + short thrlow; + bool irq_first; + + struct delayed_work work; + + int power_vi2c; + int power_vdd; + int igpio; + int int_en; + int irq; + int irq_gpio; + int use_hrtimer; + struct regulator *vdd; + struct regulator *vio; + int power_enabled; + struct wakeup_source *source; + +} m1120_data_t; +/* ********************************************************* */ + +#endif // __MXM1120_H__ + diff --git a/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120_down.c b/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120_down.c new file mode 100644 index 0000000000000000000000000000000000000000..61ea11e7f6c40f92b794cb252f43ee22f5843162 --- /dev/null +++ b/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120_down.c @@ -0,0 +1,1488 @@ +/* + * m1120.c - Linux kernel modules for hall switch + * + * Copyright (C) 2013 Seunghwan Park + * Copyright (C) 2014 MagnaChip Semiconductor. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hall_mxm1120.h" +#include "../oneplus_tri_key.h" + +//i2c address : 0X0D + +/***********************************************************/ +/*customer config*/ +/***********************************************************/ +#define M1120_DBG_ENABLE // for debugging +#define M1120_DETECTION_MODE M1120_DETECTION_MODE_INTERRUPT/*M1120_DETECTION_MODE_POLLING /James*/ +#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_BESIDE +//#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_WITHIN +#define M1120_SENSITIVITY_TYPE M1120_VAL_INTSRS_SRS_10BIT_0_068mT +#define M1120_PERSISTENCE_COUNT M1120_VAL_PERSINT_COUNT(15) +#define M1120_OPERATION_FREQUENCY M1120_VAL_OPF_FREQ_80HZ +#define M1120_OPERATION_RESOLUTION M1120_VAL_OPF_BIT_10 +#define M1120_DETECT_RANGE_HIGH (60)/*Need change via test.*/ +#define M1120_DETECT_RANGE_LOW (50)/*Need change via test.*/ +#define M1120_RESULT_STATUS_A (0x01) // result status A ----> ==180Degree. +#define M1120_RESULT_STATUS_B (0x02) // result status B ----> != 180Degree. +#define M1120_EVENT_TYPE EV_ABS // EV_KEY +#define M1120_EVENT_CODE ABS_X // KEY_F1 +#define M1120_EVENT_DATA_CAPABILITY_MIN (-32768) +#define M1120_EVENT_DATA_CAPABILITY_MAX (32767) + +/*MagnaChip Hall Sensor power supply VDD 2.7V~3.6V, VIO 1.65~VDD*/ +#define M1120_VDD_MIN_UV 2700000 +#define M1120_VDD_MAX_UV 3600000 +#define M1120_VIO_MIN_UV 1650000 +#define M1120_VIO_MAX_UV 3600000 + +/***********************************************************/ +/*debug macro*/ +/***********************************************************/ +#ifdef M1120_DBG_ENABLE +#define dbg(fmt, args...) printk("[M1120-DBG] %s(L%04d) : " fmt "\n", __func__, __LINE__, ##args) +#define dbgn(fmt, args...) printk(fmt, ##args) +#else +#define dbg(fmt, args...) +#define dbgn(fmt, args...) +#endif // M1120_DBG_ENABLE +#define dbg_func_in() dbg("[M1120-DBG-F.IN] %s", __func__) +#define dbg_func_out() dbg("[M1120-DBG-F.OUT] %s", __func__) +#define dbg_line() dbg("[LINE] %d(%s)", __LINE__, __func__) + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...) printk(KERN_ERR TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_LOG(fmt, args...) printk(KERN_INFO TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do{\ + if (LEVEL_DEBUG == tri_key_debug)\ + printk(KERN_INFO TRI_KEY_TAG " %s: " fmt, __FUNCTION__, ##args);\ + }while(0) + +/***********************************************************/ + + +/***********************************************************/ +/*error display macro*/ +/***********************************************************/ +#define mxerr(pdev, fmt, args...) \ + dev_err(pdev, "[M1120-ERR] %s(L%04d) : " fmt "\n", __func__, __LINE__, ##args) +#define mxinfo(pdev, fmt, args...) \ + dev_info(pdev, "[M1120-INFO] %s(L%04d) : " fmt "\n", __func__, __LINE__, ##args) +/***********************************************************/ + +/***********************************************************/ +/*static variable*/ +/***********************************************************/ +static m1120_data_t *p_m1120_data; +/***********************************************************/ + +/**********************************************************/ +/*statice global variable*/ +static DEFINE_MUTEX(hall_m1120_down_i2c_mutex); + +/***********************************************************/ +/*function protyps*/ +/***********************************************************/ +/*i2c interface*/ +static int m1120_i2c_read_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len); +static int m1120_i2c_write_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len); +static void m1120_short_to_2byte(m1120_data_t* m1120_data, short x, u8 *hbyte, u8 *lbyte); +static short m1120_2byte_to_short(m1120_data_t* m1120_data, u8 hbyte, u8 lbyte); +/*vdd / vid power control*/ +static int m1120_set_power(struct device *dev, bool on); + + +static int m1120_get_enable(struct device *dev); +static void m1120_set_enable(struct device *dev, int enable); +static int m1120_get_delay(struct device *dev); +static void m1120_set_delay(struct device *dev, int delay); +static int m1120_get_debug(struct device *dev); +static void m1120_set_debug(struct device *dev, int debug); +static int m1120_clear_interrupt(struct device *dev); +static int m1120_set_operation_mode(struct device *dev, int mode); +static int m1120_init_device(struct device *dev); +static int m1120_reset_device(struct device *dev); +static int m1120_power_ctl(m1120_data_t *data, bool on); +static int m1120_get_data( short *data); +/***********************************************************/ + + +/***********************************************************/ +/*functions for i2c interface*/ +/***********************************************************/ +#define M1120_I2C_BUF_SIZE (17) + + +static int m1120_i2c_read_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = NULL; + struct i2c_msg msgs[2]={{0},{0}}; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&hall_m1120_down_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len =1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len =len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, (sizeof(msgs) / sizeof(msgs[0]))); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n",addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&hall_m1120_down_i2c_mutex); + + return err; + +} + +static int m1120_i2c_write_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[M1120_I2C_BUF_SIZE] ={0}; + struct i2c_client *client = NULL; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&hall_m1120_down_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) { + buf[num++] = data[idx]; + } + + err = i2c_master_send(client, buf, num); + if (err < 0) { + TRI_KEY_ERR("send command error!! %d\n",err); + } + + //store reg written + if (len == 1) { + switch(addr){ + case M1120_REG_PERSINT: + m1120_data->reg.map.persint = data[0]; + break; + case M1120_REG_INTSRS: + m1120_data->reg.map.intsrs = data[0]; + break; + case M1120_REG_LTHL: + m1120_data->reg.map.lthl = data[0]; + break; + case M1120_REG_LTHH: + m1120_data->reg.map.lthh = data[0]; + break; + case M1120_REG_HTHL: + m1120_data->reg.map.hthl = data[0]; + break; + case M1120_REG_HTHH: + m1120_data->reg.map.hthh = data[0]; + break; + case M1120_REG_I2CDIS: + m1120_data->reg.map.i2cdis = data[0]; + break; + case M1120_REG_SRST: + m1120_data->reg.map.srst = data[0]; + break; + case M1120_REG_OPF: + m1120_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&hall_m1120_down_i2c_mutex); + return err; +} + +static void m1120_short_to_2byte(m1120_data_t* m1120_data, short x, u8 *hbyte, u8 *lbyte) +{ + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return ; + } + + if ((m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + if (x < -128) { + x = -128; + } else if(x > 127) { + x = 127; + } + + if (x >= 0) { + *lbyte = x & 0x7F; + } else { + *lbyte = ( (0x80 - (x*(-1))) & 0x7F ) | 0x80; + } + *hbyte = 0x00; + } else { + /* 10 bit resolution */ + if (x < -512) { + x = -512; + } else if (x > 511) { + x = 511; + } + + if (x >=0 ) { + *lbyte = x & 0xFF; + *hbyte = (((x & 0x100) >> 8) & 0x01) << 6; + } else { + *lbyte = (0x0200 - (x*(-1))) & 0xFF; + *hbyte = ((((0x0200 - (x*(-1))) & 0x100) >> 8) << 6) | 0x80; + } + } +} + + +static short m1120_2byte_to_short(m1120_data_t* m1120_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + + if( (m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + x = lbyte & 0x7F; + if (lbyte & 0x80) { + x -= 0x80; + } + } else { + /* 10 bit resolution */ + x = ( ( (hbyte & 0x40) >> 6) << 8 ) | lbyte; + if (hbyte & 0x80) { + x -= 0x200; + } + } + + return x; +} + +/***********************************************************/ + + + +/***********************************************************/ +/*vdd / vid power control*/ +/***********************************************************/ +static int m1120_set_power(struct device *dev, bool on) +{ + m1120_power_ctl(p_m1120_data, on); + + return 0; +} +/***********************************************************/ + + +static irqreturn_t m1120_down_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call \n"); + + if (!p_m1120_data) { + TRI_KEY_LOG("p_m1120_data NULL \n"); + return -EINVAL; + } + + disable_irq_nosync(p_m1120_data->irq); + __pm_wakeup_event(p_m1120_data->source, 2000); + oneplus_hall_irq_handler(1);//DHALL_1 DHALL_DOWN + + return IRQ_HANDLED; +} + + +static int m1120_get_enable(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + return atomic_read(&p_data->atm.enable); +} + + +static void m1120_set_enable(struct device *dev, int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); +// int delay = m1120_get_delay(dev); + + mutex_lock(&p_data->mtx.enable); + TRI_KEY_LOG("enable : %d\n", enable); + if (enable) { /*enable if state will be changed*/ + if (!atomic_cmpxchg(&p_data->atm.enable, 0, 1)) { + //m1120_set_detection_mode(dev, p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT); + //m1120_set_detection_mode(dev, p_data->reg.map.intsrs & M1120_DETECTION_MODE_POLLING); + m1120_set_operation_mode(&p_m1120_data->client->dev, OPERATION_MODE_MEASUREMENT); + /*if(!(p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT))*/ + // if (0) { + // schedule_delayed_work(&p_data->work, msecs_to_jiffies(delay)); + // } + } + } else { /*disable if state will be changed*/ + if (atomic_cmpxchg(&p_data->atm.enable, 1, 0)) { + //cancel_delayed_work_sync(&p_data->work); + m1120_set_operation_mode(&p_m1120_data->client->dev, OPERATION_MODE_POWERDOWN); + } + } + atomic_set(&p_data->atm.enable, enable); + + mutex_unlock(&p_data->mtx.enable); +} + +static int m1120_get_delay(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + int delay = 0; + + delay = atomic_read(&p_data->atm.delay); + + return delay; +} + +static void m1120_set_delay(struct device *dev, int delay) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + if (delay < M1120_DELAY_MIN) + delay = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, delay); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(dev)) { + if (!(p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT)) { + cancel_delayed_work_sync(&p_data->work); + schedule_delayed_work(&p_data->work, msecs_to_jiffies(delay)); + } + } + + mutex_unlock(&p_data->mtx.enable); +} + +static int m1120_get_debug(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + return atomic_read(&p_data->atm.debug); +} + +static void m1120_set_debug(struct device *dev, int debug) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + atomic_set(&p_data->atm.debug, debug); +} + +static int m1120_clear_interrupt(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + int ret = 0; + u8 data = 0x00; + + data = p_data->reg.map.persint | 0x01; + ret = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data,1); + + return ret; +} + +static int m1120_set_operation_mode(struct device *dev, int mode) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + u8 opf = p_data->reg.map.opf; + int err = -1; + + switch (mode) { + case OPERATION_MODE_POWERDOWN: + opf &= (0xFF - M1120_VAL_OPF_HSSON_ON); + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + mxinfo(&client->dev, "operation mode was chnaged to OPERATION_MODE_POWERDOWN"); + break; + case OPERATION_MODE_MEASUREMENT: + opf &= (0xFF - M1120_VAL_OPF_EFRD_ON); + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + + mxinfo(&client->dev, "operation mode was chnaged to OPERATION_MODE_MEASUREMENT"); + break; + case OPERATION_MODE_FUSEROMACCESS: + opf |= M1120_VAL_OPF_EFRD_ON; + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + mxinfo(&client->dev, "operation mode was chnaged to OPERATION_MODE_FUSEROMACCESS"); + break; + } + mxinfo(&client->dev, "opf = ox%x \n", opf); + return err; +} + +static int m1120_init_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + int err = -1; + + /*(1) vdd and vid power up*/ + err = m1120_set_power(dev, 1); + if (err) { + mxerr(&client->dev, "m1120 power-on was failed (%d)", err); + return err; + } + + /*(2) init variables*/ + atomic_set(&p_data->atm.enable, 0); + atomic_set(&p_data->atm.delay, M1120_DELAY_MIN); +#ifdef M1120_DBG_ENABLE + atomic_set(&p_data->atm.debug, 1); +#else + atomic_set(&p_data->atm.debug, 0); +#endif + p_data->calibrated_data = 0; + p_data->last_data = 0; + p_data->irq_enabled = 0; + p_data->irq_first = 1; + p_data->thrhigh = M1120_DETECT_RANGE_HIGH; + p_data->thrlow = M1120_DETECT_RANGE_LOW; + m1120_set_delay(&client->dev, M1120_DELAY_MAX); + m1120_set_debug(&client->dev, 0); + + /*(3) reset registers*/ + err = m1120_reset_device(dev); + if (err < 0) { + mxerr(&client->dev, "m1120_reset_device was failed (%d)", err); + return err; + } + + mxinfo(&client->dev, "initializing device was success"); + + return 0; +} + +static int m1120_reset_device(struct device *dev) +{ + int err = 0; + u8 id = 0xFF, data = 0x00; + + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + if ((p_data == NULL) || (p_data->client == NULL)) + return -ENODEV; + + /*(1) sw reset*/ + data = M1120_VAL_SRST_RESET; + err = m1120_i2c_write_block(p_data, M1120_REG_SRST, &data,1); + if (err < 0) { + mxerr(&client->dev, "sw-reset was failed(%d)", err); + return err; + } + msleep(5); + dbg("wait 5ms after vdd power up"); + + /*(2) check id*/ + err = m1120_i2c_read_block(p_data, M1120_REG_DID, &id, 1); + if (err < 0) + return err; + if (id != M1120_VAL_DID) { + mxerr(&client->dev, "current device id(0x%02X) is not M1120 device id(0x%02X)", id, M1120_VAL_DID); + return -ENXIO; + } + + /*(3) init variables*/ + /*(3-1) persint*/ + data = M1120_PERSISTENCE_COUNT; + err = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data,1); + if (err <0) { + mxerr(&client->dev, "cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-2) intsrs*/ + data = M1120_DETECTION_MODE | M1120_SENSITIVITY_TYPE; + if (data & M1120_DETECTION_MODE_INTERRUPT) { + data |= M1120_INTERRUPT_TYPE; + } + err = m1120_i2c_write_block(p_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + mxerr(&client->dev, "cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-3) opf*/ + data = M1120_OPERATION_FREQUENCY | M1120_OPERATION_RESOLUTION; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &data, 1); + if (err < 0) { + mxerr(&client->dev, "cm1120_i2c_write_block error, data : %d", data); + return err; + } + + /*(4) write variable to register*/ + // err = m1120_set_detection_mode(dev, M1120_DETECTION_MODE); + // if (err) { + // mxerr(&client->dev, "m1120_set_detection_mode was failed(%d)", err); + // return err; + // } + + + /*(5) set power-on mode*/ + err = m1120_set_operation_mode(dev, OPERATION_MODE_MEASUREMENT); + if (err < 0) { + mxerr(&client->dev, "m1120_set_detection_mode was failed(%d)", err); + return err; + } + + return err; +} + +/************************************************** + input device interface + **************************************************/ +static int m1120_input_dev_init(m1120_data_t *p_data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) { + return -ENOMEM; + } + dev->name = M1120_DRIVER_NAME_DOWN; + dev->id.bustype = BUS_I2C; + +#if (M1120_EVENT_TYPE == EV_ABS) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, ABS_MISC); + input_set_abs_params(dev, M1120_EVENT_CODE, M1120_EVENT_DATA_CAPABILITY_MIN, M1120_EVENT_DATA_CAPABILITY_MAX, 0, 0); +#elif (M1120_EVENT_TYPE == EV_KEY) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, M1120_EVENT_CODE); +#else +#error ("[ERR] M1120_EVENT_TYPE is not defined.") +#endif + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + + p_data->input_dev = dev; + + return 0; +} + +static void m1120_input_dev_terminate(m1120_data_t *p_data) +{ + struct input_dev *dev = p_data->input_dev; + + input_unregister_device(dev); + input_free_device(dev); +} + +/************************************************** + sysfs attributes + **************************************************/ +static ssize_t m1120_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%d\n", m1120_get_enable(dev)); +} + +static ssize_t m1120_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long enable = simple_strtoul(buf, NULL, 10); + + if ((enable == 0) || (enable == 1)) { + m1120_set_enable(dev, enable); + } + + return count; +} + +static ssize_t m1120_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%d\n", m1120_get_delay(dev)); +} + +static ssize_t m1120_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long delay = simple_strtoul(buf, NULL, 10); + + if (delay > M1120_DELAY_MAX) { + delay = M1120_DELAY_MAX; + } + + m1120_set_delay(dev, delay); + + return count; +} + +static ssize_t m1120_debug_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%d\n", m1120_get_debug(dev)); +} + +static ssize_t m1120_debug_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long debug = simple_strtoul(buf, NULL, 10); + + m1120_set_debug(dev, debug); + + return count; +} + +static ssize_t m1120_wake_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return 0; +} + +static ssize_t m1120_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + //struct i2c_client *client = to_i2c_client(dev); + //m1120_data_t *p_data = i2c_get_clientdata(client); + short raw = 0; + m1120_get_data(&raw); + return snprintf(buf, 10, "%d\n", raw); +} + + static int m1120_i2c_read(struct i2c_client *client, u8 reg, u8 *rdata, u8 len) +{ +#if 0////add by James. + int rc; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = rdata, + }, + }; + if (client == NULL) { + mxerr(&client->dev, "client is NULL"); + return -ENODEV; + } + rc = i2c_transfer(client->adapter, msg, 2); + if (rc < 0) { + mxerr(&client->dev, "i2c_transfer was failed(%d)", rc); + return rc; + } +#else +/*Add By James for i2c_smbus_read_i2c_block_data */ + i2c_smbus_read_i2c_block_data(client, reg, len, rdata); +#endif + return 0; +} + +static int m1120_i2c_get_reg(struct i2c_client *client, u8 reg, u8 *rdata) +{ + return m1120_i2c_read(client, reg, rdata, 1); +} + +static void m1120_get_reg(struct device *dev, int *regdata) +{ + struct i2c_client *client = to_i2c_client(dev); + int err; + u8 rega = (((*regdata) >> 8) & 0xFF); + u8 regd = 0; + err = m1120_i2c_get_reg(client, rega, ®d); + *regdata = 0; + *regdata |= (err == 0) ? 0x0000 : 0xFF00; + *regdata |= regd; +} + +static ssize_t m1120_dump_show(struct device *dev,struct device_attribute *attr, char *buf) +{ + int reg = 0; + int reg_l = M1120_REG_HSL; + int reg_h = M1120_REG_HSH; + int i = 0; + for (i = 0; i < 11; i++) { + reg = i<<8; + m1120_get_reg(&p_m1120_data->client->dev, ®); + printk(KERN_ERR"dkk: the reg 0x%02X value: 0x%02X\n", i, reg); + } + m1120_get_reg(&p_m1120_data->client->dev, ®_l); + printk(KERN_ERR"dkk: the reg_l is 0x%02X\n", (u8)(reg_l&0xFF)); + m1120_get_reg(&p_m1120_data->client->dev, ®_h); + printk(KERN_ERR"dkk: the reg_h is 0x%02X", (u8)(reg_h&0xFF)); + reg = ((reg_h&0xC0) << 2)|reg_l; + printk(KERN_ERR"dkk: the down hall reg measure is 0x%02X\n", reg); + return snprintf(buf, 10, "%d\n", reg); + //return 0; +} + + +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, m1120_enable_show, m1120_enable_store); +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP, m1120_delay_show, m1120_delay_store); +static DEVICE_ATTR(debug, S_IRUGO|S_IWUSR|S_IWGRP, m1120_debug_show, m1120_debug_store); +static DEVICE_ATTR(wake, S_IWUSR|S_IWGRP, NULL, m1120_wake_store); +static DEVICE_ATTR(rawdata, S_IRUGO|S_IWUSR|S_IWGRP, m1120_data_show, NULL); +static DEVICE_ATTR(dump, S_IRUGO|S_IWUSR|S_IWGRP, m1120_dump_show, NULL); + +static struct attribute *m1120_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_debug.attr, + &dev_attr_wake.attr, + &dev_attr_rawdata.attr, + &dev_attr_dump.attr, + NULL +}; + +static struct attribute_group m1120_attribute_group = { + .attrs = m1120_attributes +}; + +static int m1120_power_ctl(m1120_data_t *data, bool on) +{ + int ret = 0; + int err = 0; + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + dev_err(&data->client->dev, + "Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + dev_err(&data->client->dev, + "Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + dev_err(&data->client->dev, + "Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + msleep(8);////>=5ms OK. + ret = regulator_enable(data->vio); + if (ret) { + dev_err(&data->client->dev, + "Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + msleep(10); // wait 10ms + data->power_enabled = on; + } else { + dev_info(&data->client->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); + } + + return ret; +} + +static int m1120_power_init(m1120_data_t *data) +{ + int ret; + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + dev_err(&data->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + M1120_VDD_MIN_UV, + M1120_VDD_MAX_UV); + if (ret) { + dev_err(&data->client->dev, + "Regulator set failed vdd ret=%d\n", + ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + dev_err(&data->client->dev, + "Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + M1120_VIO_MIN_UV, + M1120_VIO_MAX_UV); + if (ret) { + dev_err(&data->client->dev, + "Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, M1120_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + + +static int tri_key_m1120_parse_dt(struct device *dev, + m1120_data_t *pdata) +{ + struct device_node *np = dev->of_node; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + u32 temp_val; + int rc; + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + dev_err(dev, " %s", __func__); + rc = of_property_read_u32(np, "magnachip,init-interval", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read init-interval\n"); + return rc; + } else { + if (temp_val < M1120_DELAY_MIN) + temp_val = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, temp_val); + } + + p_data->int_en = of_property_read_bool(np, "magnachip,use-interrupt"); + + p_data->igpio = of_get_named_gpio_flags(dev->of_node, + "magnachip,gpio-int", 0, NULL); + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + dev_err(dev, "irq_gpio : %d", p_data->irq_gpio); + + p_data->use_hrtimer = of_property_read_bool(np, "magnachip,use-hrtimer"); + key_pinctrl = devm_pinctrl_get(dev); + + if (IS_ERR_OR_NULL(key_pinctrl)) { + dev_err(dev, "Failed to get pinctrl\n"); + } + set_state = pinctrl_lookup_state(key_pinctrl, + "downhall_tri_state_key_active"); + if (IS_ERR_OR_NULL(set_state)) { + dev_err(dev, "Failed to lookup_state\n"); + } + + pinctrl_select_state(key_pinctrl,set_state); + + return 0; +} + +//interface implement for op_motor.c + +static int m1120_get_data( short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + + TRI_KEY_DEBUG(KERN_INFO "======> %s", __func__); + if(!p_m1120_data) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -1; + } + // (1) read data + err = m1120_i2c_read_block(p_m1120_data, M1120_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG(" fail %d \n",err); + return err; + } + + // (2) collect data + if (buf[0] & 0x01) { + value = m1120_2byte_to_short(p_m1120_data, buf[2], buf[1]); + } else { + TRI_KEY_DEBUG("m1120: st1(0x%02X) is not DRDY.\n", buf[0]); + return err; + } + *data = value; + TRI_KEY_DEBUG("up, value : %d\n", value); + return 0; +} + +static int m1120_enable_irq(bool enable) +{ + printk(KERN_INFO " %s", __func__); + + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + if (enable) { + enable_irq(p_m1120_data->irq); + } else { + disable_irq_nosync(p_m1120_data->irq); + } + + return 0; +} + +static int m1120_clear_irq() +{ + printk(KERN_INFO " %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_clear_interrupt(&p_m1120_data->client->dev); + return 0; +} + +static int m1120_get_irq_state() +{ + printk(KERN_INFO " %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + return ((p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static bool m1120_update_threshold(int position, short lowthd, short highthd) +{ + + u8 lthh, lthl, hthh, hthl; + int err = 0; + + printk(KERN_INFO " %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL \n"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120_down ,low:%d, high:%d \n",lowthd, highthd); + + err = m1120_clear_interrupt(&p_m1120_data->client->dev); + + //if (p_m1120_data->reg.map.intsrs & M1120_VAL_INTSRS_INTTYPE_BESIDE) { + if (p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + printk("dn hall m1120_update_threshold, lowthd=%d, highthd=%d.\n", lowthd, highthd); + m1120_short_to_2byte(p_m1120_data, highthd, &hthh, &hthl); + m1120_short_to_2byte(p_m1120_data, lowthd, <hh, <hl); + + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHH,&hthh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHL,&hthl, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHH,<hh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHL,<hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("tri_key:fail %d\n",err); + return false; + } else { + return true; + } + + return true; +} + +static void m1120_dump_reg(u8* buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + printk(KERN_INFO " %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL \n"); + return ; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = m1120_i2c_read_block(p_m1120_data, i, &val, 1); + if (err < 0) { + snprintf(buf, PAGE_SIZE, "read reg error!\n"); + return; + } + + snprintf(_buf, sizeof(_buf), "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + snprintf(buf, PAGE_SIZE, "%s\n", buffer); + TRI_KEY_LOG("%s \n",buf); + return; +} + +static bool m1120_is_power_on() +{ + printk(KERN_INFO " %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL \n"); + return false; + } + + return p_m1120_data->power_enabled > 0 ? true : false; +} + +static int m1120_set_detection_mode_1(u8 mode) +{ + u8 data = 0; + int err = 0; + + printk(KERN_INFO " %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120 down detection mode : %s\n", (mode == 0)? "POLLING":"INTERRUPT"); + + if(mode & DETECTION_MODE_INTERRUPT) { //interrupt mode + if (!p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs | M1120_DETECTION_MODE_INTERRUPT; + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1);// + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + err = m1120_clear_interrupt(&p_m1120_data->client->dev); + if (err < 0) { + TRI_KEY_ERR("clear interupt fail %d \n",err); + return err; + } + + /* requst irq */ + TRI_KEY_LOG("m1120 down enter irq handler \n"); + if (request_irq(p_m1120_data->irq, &m1120_down_irq_handler, IRQ_TYPE_LEVEL_LOW, + "hall_m1120_down",(void *)p_m1120_data->client)) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(p_m1120_data->irq, 1); + + p_m1120_data->irq_enabled = 1; + } + } else { // polling mode + if (p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs & (0xFF - M1120_DETECTION_MODE_INTERRUPT); + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + disable_irq(p_m1120_data->irq); + free_irq(p_m1120_data->irq, NULL); + + p_m1120_data->irq_enabled = 0; + } + } + + return 0; +} + +static int m1120_set_reg_1(int reg, int val) +{ + + u8 data = (u8)val; + + printk(KERN_INFO "%s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_i2c_write_block(p_m1120_data, (u8)reg, &data,1); + return 0; +} + +struct dhall_operations m1120_downs_ops = { + .get_data = m1120_get_data, + .enable_irq = m1120_enable_irq, + .clear_irq = m1120_clear_irq, + .get_irq_state = m1120_get_irq_state, + .set_detection_mode = m1120_set_detection_mode_1, + .update_threshold = m1120_update_threshold, + .dump_regs = m1120_dump_reg, + .set_reg = m1120_set_reg_1, + .is_power_on = m1120_is_power_on +}; +/************************************************** + i2c client + **************************************************/ + +static int tri_key_m1120_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + m1120_platform_data_t *p_platform; + m1120_data_t *p_data; + int err = 0; + + dbg_func_in(); + + + printk(KERN_INFO " allocation memory for p_m1120_data down %s\n", __func__); + /*(1) allocation memory for p_m1120_data*/ + p_data = kzalloc(sizeof(m1120_data_t), GFP_KERNEL); + if (!p_data) { + mxerr(&client->dev, "kernel memory alocation was failed"); + err = -ENOMEM; + goto error_0; + } + + printk(KERN_INFO " init mutex variable \n"); + /*(2) init mutex variable*/ + mutex_init(&p_data->mtx.enable); + mutex_init(&p_data->mtx.data); + p_data->power_enabled = false; + + printk(KERN_INFO " config i2c client %s\n", __func__); + /*(3) config i2c client*/ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + mxerr(&client->dev, "i2c_check_functionality was failed"); + err = -ENODEV; + goto error_1; + } + i2c_set_clientdata(client, p_data); + p_data->client = client; + p_m1120_data = p_data; + + if (client->dev.of_node) { + dev_err(&client->dev, "Use client->dev.of_node\n"); + err = tri_key_m1120_parse_dt(&client->dev, p_data); + if (err) { + dev_err(&client->dev, "Failed to parse device tree \n"); + err = -EINVAL; + goto error_1; + } + } else { + p_platform = client->dev.platform_data; + dev_err(&client->dev, "Use platform data \n"); + } + /*(5) setup interrupt gpio*/ + /*if (p_data->igpio != -1) { + err = gpio_request(p_data->igpio, "m1120_irq"); + if (err) { + mxerr(&client->dev, "gpio_request was failed(%d)", err); + goto error_1; + } + mxinfo(&client->dev, "gpio_request was success"); + err = gpio_direction_input(p_data->igpio); + if (err < 0) { + mxerr(&client->dev, "gpio_direction_input was failed(%d)", err); + goto error_2; + } + mxinfo(&client->dev, "gpio_direction_input was success"); + }*/ + + //pull pm8150 gpio_04 down + // err = set_gpio_state(&client->dev); + // if (err) { + // dev_err(&client->dev, "Failed to set gpio state\n"); + // } + //gpio irq request + if (gpio_is_valid(p_data->irq_gpio)) { + err = gpio_request(p_data->irq_gpio, "m1120_down_irq"); + if (err) { + mxerr(&client->dev, "unable to request gpio [%d]", p_data->irq_gpio); + } else { + err = gpio_direction_input(p_data->irq_gpio); + msleep(50); + p_data->irq = gpio_to_irq(p_data->irq_gpio); + mxerr(&client->dev, " irq : %d", p_data->irq); + } + + } + + err = m1120_power_init(p_data); + if (err) { + dev_err(&client->dev, "Failed to get sensor regulators\n"); + err = -EINVAL; + goto error_1; + } + err = m1120_power_ctl(p_data, true); + if (err) { + dev_err(&client->dev, "Failed to enable sensor power\n"); + err = -EINVAL; + goto error_1; + } + + + /*(6) reset and init device*/ + err = m1120_init_device(&p_data->client->dev); + if (err) { + mxerr(&client->dev, "m1120_init_device was failed(%d)", err); + goto error_1; + } + mxinfo(&client->dev, "%s was found", id->name); + + /*(7) config work function*/ + //INIT_DELAYED_WORK(&p_data->work, m1120_work_func); + + /*(8) init input device*/ + err = m1120_input_dev_init(p_data); + if (err) { + mxerr(&client->dev, "m1120_input_dev_init was failed(%d)", err); + goto error_1; + } + mxinfo(&client->dev, "%s was initialized", M1120_DRIVER_NAME_DOWN); + + /*(9) create sysfs group*/ + err = sysfs_create_group(&p_data->input_dev->dev.kobj, &m1120_attribute_group); + if (err) { + mxerr(&client->dev, "sysfs_create_group was failed(%d)", err); + goto error_3; + } + + /*(10) register misc device*/ + // err = misc_register(&m1120_misc_dev); + // if (err) { + // mxerr(&client->dev, "misc_register was failed(%d)", err); + // goto error_4; + // } + + /*(11) register ops to abstrace level*/ + oneplus_register_hall("hall_down", &m1120_downs_ops);//ÍùÆäÀï±ß×¢²áhall + p_m1120_data->source = wakeup_source_register(&client->dev, "hall_down"); + + printk(KERN_INFO " i2c addr : %d\n", client->addr); + + + + /*(12) imigrate p_data to p_m1120_data*/ + dbg("%s : %s was probed.\n", __func__, M1120_DRIVER_NAME_DOWN); + + return 0; + +//error_4: + // sysfs_remove_group(&p_data->input_dev->dev.kobj, &m1120_attribute_group); + +error_3: + m1120_input_dev_terminate(p_data); + + + +error_1: + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + kfree(p_data); + +error_0: + p_m1120_data = NULL; + return err; +} + +static int m1120_i2c_drv_remove(struct i2c_client *client) +{ + m1120_data_t *p_data = i2c_get_clientdata(client); + + m1120_set_enable(&client->dev, 0); + // misc_deregister(&m1120_misc_dev); + sysfs_remove_group(&p_data->input_dev->dev.kobj, &m1120_attribute_group); + m1120_input_dev_terminate(p_data); + if (p_data->igpio != -1) { + gpio_free(p_data->igpio); + } + kfree(p_data); + + return 0; +} + +/* +static int m1120_i2c_drv_suspend(struct i2c_client *client, pm_message_t mesg) +{ + m1120_data_t *p_data = i2c_get_clientdata(client); + + dbg_func_in(); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(&client->dev)) { + if (p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + m1120_set_operation_mode(&client->dev, OPERATION_MODE_MEASUREMENT); + } else { + cancel_delayed_work_sync(&p_data->work); + m1120_set_detection_mode(&client->dev, M1120_DETECTION_MODE_INTERRUPT); + } + } + + mutex_unlock(&p_data->mtx.enable); + + dbg_func_out(); + + return 0; +} + +static int m1120_i2c_drv_resume(struct i2c_client *client) +{ + m1120_data_t *p_data = i2c_get_clientdata(client); + + dbg_func_in(); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(&client->dev)) { + if (p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + m1120_set_detection_mode(&client->dev, M1120_DETECTION_MODE_POLLING); + schedule_delayed_work(&p_data->work, msecs_to_jiffies(m1120_get_delay(&client->dev))); + } + } + + mutex_unlock(&p_data->mtx.enable); + + dbg_func_out(); + + return 0; +} +*/ + +static const struct i2c_device_id m1120_i2c_drv_id_table[] = { + {"hall_m1120_down", 0 }, + { } +}; + + +static const struct of_device_id m1120_of_match[] = { + { .compatible = "tri_key_magnachip,tk_mxm1120,down", }, + { }, +}; + +static struct i2c_driver m1120_driver = { + .driver = { + .owner = THIS_MODULE, + .name = M1120_DRIVER_NAME_DOWN, + .of_match_table = m1120_of_match, + }, + .probe = tri_key_m1120_i2c_drv_probe, + .remove = m1120_i2c_drv_remove, + .id_table = m1120_i2c_drv_id_table, + //.suspend = m1120_i2c_drv_suspend, + //.resume = m1120_i2c_drv_resume, +}; + +static int __init tri_key_m1120_driver_init_down(void) +{ + int res = 0; + printk(KERN_INFO " log %s\n", __func__); + res = i2c_add_driver(&m1120_driver); + printk(KERN_INFO " log %s, res : %d\n", __func__, res); + return res;//i2c_add_driver(&m1120_driver); +} +module_init(tri_key_m1120_driver_init_down); + +static void __exit m1120_driver_exit_down(void) +{ + printk(KERN_INFO "%s\n", __func__); + i2c_del_driver(&m1120_driver); +} +module_exit(m1120_driver_exit_down); + +MODULE_AUTHOR("shpark "); +MODULE_VERSION(M1120_DRIVER_VERSION); +MODULE_DESCRIPTION("M1120 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120_up.c b/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120_up.c new file mode 100644 index 0000000000000000000000000000000000000000..174d292a822d440a13cc01a55a6b37a583fd024e --- /dev/null +++ b/drivers/oneplus/tri_state_key/hall_ic/hall_mxm1120_up.c @@ -0,0 +1,1480 @@ +/* + * m1120.c - Linux kernel modules for hall switch + * + * Copyright (C) 2013 Seunghwan Park + * Copyright (C) 2014 MagnaChip Semiconductor. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hall_mxm1120.h" +#include "../oneplus_tri_key.h" + +/***********************************************************/ +/*customer config*/ +/***********************************************************/ +#define M1120_DBG_ENABLE // for debugging +#define M1120_DETECTION_MODE M1120_DETECTION_MODE_INTERRUPT/*M1120_DETECTION_MODE_POLLING /James*/ +#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_BESIDE +//#define M1120_INTERRUPT_TYPE M1120_VAL_INTSRS_INTTYPE_WITHIN +#define M1120_SENSITIVITY_TYPE M1120_VAL_INTSRS_SRS_10BIT_0_068mT +#define M1120_PERSISTENCE_COUNT M1120_VAL_PERSINT_COUNT(15) +#define M1120_OPERATION_FREQUENCY M1120_VAL_OPF_FREQ_80HZ +#define M1120_OPERATION_RESOLUTION M1120_VAL_OPF_BIT_10 +#define M1120_DETECT_RANGE_HIGH (60)/*Need change via test.*/ +#define M1120_DETECT_RANGE_LOW (50)/*Need change via test.*/ +#define M1120_RESULT_STATUS_A (0x01) // result status A ----> ==180Degree. +#define M1120_RESULT_STATUS_B (0x02) // result status B ----> != 180Degree. +#define M1120_EVENT_TYPE EV_ABS // EV_KEY +#define M1120_EVENT_CODE ABS_X // KEY_F1 +#define M1120_EVENT_DATA_CAPABILITY_MIN (-32768) +#define M1120_EVENT_DATA_CAPABILITY_MAX (32767) + +/*MagnaChip Hall Sensor power supply VDD 2.7V~3.6V, VIO 1.65~VDD*/ +#define M1120_VDD_MIN_UV 2700000 +#define M1120_VDD_MAX_UV 3600000 +#define M1120_VIO_MIN_UV 1650000 +#define M1120_VIO_MAX_UV 3600000 + +/***********************************************************/ +/*debug macro*/ +/***********************************************************/ +#ifdef M1120_DBG_ENABLE +#define dbg(fmt, args...) printk("[M1120-DBG] %s(L%04d) : " fmt "\n", __func__, __LINE__, ##args) +#define dbgn(fmt, args...) printk(fmt, ##args) +#else +#define dbg(fmt, args...) +#define dbgn(fmt, args...) +#endif // M1120_DBG_ENABLE +#define dbg_func_in() dbg("[M1120-DBG-F.IN] %s", __func__) +#define dbg_func_out() dbg("[M1120-DBG-F.OUT] %s", __func__) +#define dbg_line() dbg("[LINE] %d(%s)", __LINE__, __func__) + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...) printk(KERN_ERR TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_LOG(fmt, args...) printk(KERN_INFO TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do{\ + if (LEVEL_DEBUG == tri_key_debug)\ + printk(KERN_INFO TRI_KEY_TAG " %s: " fmt, __FUNCTION__, ##args);\ + }while(0) + +/***********************************************************/ + + +/***********************************************************/ +/*error display macro*/ +/***********************************************************/ +#define mxerr(pdev, fmt, args...) \ + dev_err(pdev, "[M1120-ERR] %s(L%04d) : " fmt "\n", __func__, __LINE__, ##args) +#define mxinfo(pdev, fmt, args...) \ + dev_info(pdev, "[M1120-INFO] %s(L%04d) : " fmt "\n", __func__, __LINE__, ##args) +/***********************************************************/ + +/***********************************************************/ +/*static variable*/ +/***********************************************************/ +static m1120_data_t *p_m1120_data; +/***********************************************************/ + +/*static global variable */ +/**********************************************************/ +static DEFINE_MUTEX(hall_m1120_up_i2c_mutex); + +/***********************************************************/ +/*function protyps*/ +/***********************************************************/ +/*i2c interface*/ +static int m1120_i2c_read_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len); +static int m1120_i2c_write_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len); +static void m1120_short_to_2byte(m1120_data_t* m1120_data, short x, u8 *hbyte, u8 *lbyte); +static short m1120_2byte_to_short(m1120_data_t* m1120_data, u8 hbyte, u8 lbyte); +/*vdd / vid power control*/ +static int m1120_set_power(struct device *dev, bool on); + + +static int m1120_get_enable(struct device *dev); +static void m1120_set_enable(struct device *dev, int enable); +static int m1120_get_delay(struct device *dev); +static void m1120_set_delay(struct device *dev, int delay); +static int m1120_get_debug(struct device *dev); +static void m1120_set_debug(struct device *dev, int debug); +static int m1120_clear_interrupt(struct device *dev); +static int m1120_set_operation_mode(struct device *dev, int mode); +static int m1120_init_device(struct device *dev); +static int m1120_reset_device(struct device *dev); +static int m1120_power_ctl(m1120_data_t *data, bool on); +static int m1120_get_data( short *data); +/***********************************************************/ + + +/***********************************************************/ +/*functions for i2c interface*/ +/***********************************************************/ +#define M1120_I2C_BUF_SIZE (17) + + +static int m1120_i2c_read_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = NULL; + struct i2c_msg msgs[2]={{0},{0}}; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&hall_m1120_up_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len =1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len =len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, (sizeof(msgs) / sizeof(msgs[0]))); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n",addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&hall_m1120_up_i2c_mutex); + + return err; + +} + +static int m1120_i2c_write_block(m1120_data_t* m1120_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[M1120_I2C_BUF_SIZE] ={0}; + struct i2c_client *client = NULL; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + client = m1120_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= M1120_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, M1120_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&hall_m1120_up_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) { + buf[num++] = data[idx]; + } + + err = i2c_master_send(client, buf, num); + if (err < 0) { + TRI_KEY_ERR("send command error!! %d\n",err); + } + + //store reg written + if (len == 1) { + switch(addr){ + case M1120_REG_PERSINT: + m1120_data->reg.map.persint = data[0]; + break; + case M1120_REG_INTSRS: + m1120_data->reg.map.intsrs = data[0]; + break; + case M1120_REG_LTHL: + m1120_data->reg.map.lthl = data[0]; + break; + case M1120_REG_LTHH: + m1120_data->reg.map.lthh = data[0]; + break; + case M1120_REG_HTHL: + m1120_data->reg.map.hthl = data[0]; + break; + case M1120_REG_HTHH: + m1120_data->reg.map.hthh = data[0]; + break; + case M1120_REG_I2CDIS: + m1120_data->reg.map.i2cdis = data[0]; + break; + case M1120_REG_SRST: + m1120_data->reg.map.srst = data[0]; + break; + case M1120_REG_OPF: + m1120_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&hall_m1120_up_i2c_mutex); + return err; +} + +static void m1120_short_to_2byte(m1120_data_t* m1120_data, short x, u8 *hbyte, u8 *lbyte) +{ + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return ; + } + + if ((m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + if (x < -128) { + x = -128; + } else if(x > 127) { + x = 127; + } + + if (x >= 0) { + *lbyte = x & 0x7F; + } else { + *lbyte = ( (0x80 - (x*(-1))) & 0x7F ) | 0x80; + } + *hbyte = 0x00; + } else { + /* 10 bit resolution */ + if (x < -512) { + x = -512; + } else if (x > 511) { + x = 511; + } + + if (x >=0 ) { + *lbyte = x & 0xFF; + *hbyte = (((x & 0x100) >> 8) & 0x01) << 6; + } else { + *lbyte = (0x0200 - (x*(-1))) & 0xFF; + *hbyte = ((((0x0200 - (x*(-1))) & 0x100) >> 8) << 6) | 0x80; + } + } +} +/***********************************************************/ + + +static short m1120_2byte_to_short(m1120_data_t* m1120_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + + if (!m1120_data) { + TRI_KEY_ERR("m1120_data == NULL\n"); + return -EINVAL; + } + + if( (m1120_data->reg.map.opf & M1120_VAL_OPF_BIT_8) == M1120_VAL_OPF_BIT_8) { + /* 8 bit resolution */ + x = lbyte & 0x7F; + if (lbyte & 0x80) { + x -= 0x80; + } + } else { + /* 10 bit resolution */ + x = ( ( (hbyte & 0x40) >> 6) << 8 ) | lbyte; + if (hbyte & 0x80) { + x -= 0x200; + } + } + + return x; +} + +/***********************************************************/ +/*vdd / vid power control*/ +/***********************************************************/ +static int m1120_set_power(struct device *dev, bool on) +{ + m1120_power_ctl(p_m1120_data, on); + + return 0; +} +/***********************************************************/ + + +static irqreturn_t m1120_up_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call \n"); + + if (!p_m1120_data) { + TRI_KEY_LOG("p_m1120_data NULL \n"); + return -EINVAL; + } + + disable_irq_nosync(p_m1120_data->irq); + __pm_wakeup_event(p_m1120_data->source, 2000); + oneplus_hall_irq_handler(0);//DHALL_UP + + return IRQ_HANDLED; +} + + +static int m1120_get_enable(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + return atomic_read(&p_data->atm.enable); +} + + +static void m1120_set_enable(struct device *dev, int enable) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); +// int delay = m1120_get_delay(dev); + + mutex_lock(&p_data->mtx.enable); + TRI_KEY_LOG("enable : %d\n", enable); + if (enable) { /*enable if state will be changed*/ + if (!atomic_cmpxchg(&p_data->atm.enable, 0, 1)) { + //m1120_set_detection_mode(dev, p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT); + //m1120_set_detection_mode(dev, p_data->reg.map.intsrs & M1120_DETECTION_MODE_POLLING); + m1120_set_operation_mode(&p_m1120_data->client->dev, OPERATION_MODE_MEASUREMENT); + /*if(!(p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT))*/ + // if (0) { + // schedule_delayed_work(&p_data->work, msecs_to_jiffies(delay)); + // } + } + } else { /*disable if state will be changed*/ + if (atomic_cmpxchg(&p_data->atm.enable, 1, 0)) { + //cancel_delayed_work_sync(&p_data->work); + m1120_set_operation_mode(&p_m1120_data->client->dev, OPERATION_MODE_POWERDOWN); + } + } + atomic_set(&p_data->atm.enable, enable); + + mutex_unlock(&p_data->mtx.enable); +} + +static int m1120_get_delay(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + int delay = 0; + + delay = atomic_read(&p_data->atm.delay); + + return delay; +} + +static void m1120_set_delay(struct device *dev, int delay) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + if (delay < M1120_DELAY_MIN) + delay = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, delay); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(dev)) { + if (!(p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT)) { + cancel_delayed_work_sync(&p_data->work); + schedule_delayed_work(&p_data->work, msecs_to_jiffies(delay)); + } + } + + mutex_unlock(&p_data->mtx.enable); +} + +static int m1120_get_debug(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + return atomic_read(&p_data->atm.debug); +} + +static void m1120_set_debug(struct device *dev, int debug) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + atomic_set(&p_data->atm.debug, debug); +} + +static int m1120_clear_interrupt(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + int ret = 0; + u8 data = 0x00; + + data = p_data->reg.map.persint | 0x01; + ret = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data,1); + + return ret; +} + +static int m1120_set_operation_mode(struct device *dev, int mode) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + u8 opf = p_data->reg.map.opf; + int err = -1; + + switch (mode) { + case OPERATION_MODE_POWERDOWN: + opf &= (0xFF - M1120_VAL_OPF_HSSON_ON); + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + mxinfo(&client->dev, "operation mode was chnaged to OPERATION_MODE_POWERDOWN"); + break; + case OPERATION_MODE_MEASUREMENT: + opf &= (0xFF - M1120_VAL_OPF_EFRD_ON); + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + + mxinfo(&client->dev, "operation mode was chnaged to OPERATION_MODE_MEASUREMENT"); + break; + case OPERATION_MODE_FUSEROMACCESS: + opf |= M1120_VAL_OPF_EFRD_ON; + opf |= M1120_VAL_OPF_HSSON_ON; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &opf, 1); + mxinfo(&client->dev, "operation mode was chnaged to OPERATION_MODE_FUSEROMACCESS"); + break; + } + mxinfo(&client->dev, "opf = ox%x \n", opf); + return err; +} + +static int m1120_init_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + int err = -1; + + /*(1) vdd and vid power up*/ + err = m1120_set_power(dev, 1); + if (err) { + mxerr(&client->dev, "m1120 power-on was failed (%d)", err); + return err; + } + + /*(2) init variables*/ + atomic_set(&p_data->atm.enable, 0); + atomic_set(&p_data->atm.delay, M1120_DELAY_MIN); +#ifdef M1120_DBG_ENABLE + atomic_set(&p_data->atm.debug, 1); +#else + atomic_set(&p_data->atm.debug, 0); +#endif + p_data->calibrated_data = 0; + p_data->last_data = 0; + p_data->irq_enabled = 0; + p_data->irq_first = 1; + p_data->thrhigh = M1120_DETECT_RANGE_HIGH; + p_data->thrlow = M1120_DETECT_RANGE_LOW; + m1120_set_delay(&client->dev, M1120_DELAY_MAX); + m1120_set_debug(&client->dev, 0); + + /*(3) reset registers*/ + err = m1120_reset_device(dev); + if (err < 0) { + mxerr(&client->dev, "m1120_reset_device was failed (%d)", err); + return err; + } + + mxinfo(&client->dev, "initializing device was success"); + + return 0; +} + +static int m1120_reset_device(struct device *dev) +{ + int err = 0; + u8 id = 0xFF, data = 0x00; + + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + if ((p_data == NULL) || (p_data->client == NULL)) + return -ENODEV; + + /*(1) sw reset*/ + data = M1120_VAL_SRST_RESET; + err = m1120_i2c_write_block(p_data, M1120_REG_SRST, &data,1); + if (err < 0) { + mxerr(&client->dev, "sw-reset was failed(%d)", err); + return err; + } + msleep(5); + dbg("wait 5ms after vdd power up"); + + /*(2) check id*/ + err = m1120_i2c_read_block(p_data, M1120_REG_DID, &id, 1); + if (err < 0) + return err; + if (id != M1120_VAL_DID) { + mxerr(&client->dev, "current device id(0x%02X) is not M1120 device id(0x%02X)", id, M1120_VAL_DID); + return -ENXIO; + } + + /*(3) init variables*/ + /*(3-1) persint*/ + data = M1120_PERSISTENCE_COUNT; + err = m1120_i2c_write_block(p_data, M1120_REG_PERSINT, &data,1); + if (err <0) { + mxerr(&client->dev, "cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-2) intsrs*/ + data = M1120_DETECTION_MODE | M1120_SENSITIVITY_TYPE; + if (data & M1120_DETECTION_MODE_INTERRUPT) { + data |= M1120_INTERRUPT_TYPE; + } + err = m1120_i2c_write_block(p_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + mxerr(&client->dev, "cm1120_i2c_write_block error, data : %d", data); + return err; + } + /*(3-3) opf*/ + data = M1120_OPERATION_FREQUENCY | M1120_OPERATION_RESOLUTION; + err = m1120_i2c_write_block(p_data, M1120_REG_OPF, &data, 1); + if (err < 0) { + mxerr(&client->dev, "cm1120_i2c_write_block error, data : %d", data); + return err; + } + + /*(4) write variable to register*/ + // err = m1120_set_detection_mode(dev, M1120_DETECTION_MODE); + // if (err) { + // mxerr(&client->dev, "m1120_set_detection_mode was failed(%d)", err); + // return err; + // } + + + /*(5) set power-on mode*/ + err = m1120_set_operation_mode(dev, OPERATION_MODE_MEASUREMENT); + if (err < 0) { + mxerr(&client->dev, "m1120_set_detection_mode was failed(%d)", err); + return err; + } + + return err; +} + +/************************************************** + input device interface + **************************************************/ +static int m1120_input_dev_init(m1120_data_t *p_data) +{ + struct input_dev *dev; + int err; + + dev = input_allocate_device(); + if (!dev) { + return -ENOMEM; + } + dev->name = M1120_DRIVER_NAME_UP; + dev->id.bustype = BUS_I2C; + +#if (M1120_EVENT_TYPE == EV_ABS) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, ABS_MISC); + input_set_abs_params(dev, M1120_EVENT_CODE, M1120_EVENT_DATA_CAPABILITY_MIN, M1120_EVENT_DATA_CAPABILITY_MAX, 0, 0); +#elif (M1120_EVENT_TYPE == EV_KEY) + input_set_drvdata(dev, p_data); + input_set_capability(dev, M1120_EVENT_TYPE, M1120_EVENT_CODE); +#else +#error ("[ERR] M1120_EVENT_TYPE is not defined.") +#endif + + err = input_register_device(dev); + if (err < 0) { + input_free_device(dev); + return err; + } + + p_data->input_dev = dev; + + return 0; +} + +static void m1120_input_dev_terminate(m1120_data_t *p_data) +{ + struct input_dev *dev = p_data->input_dev; + + input_unregister_device(dev); + input_free_device(dev); +} + +/************************************************** + sysfs attributes + **************************************************/ +static ssize_t m1120_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%d\n", m1120_get_enable(dev)); +} + +static ssize_t m1120_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long enable = simple_strtoul(buf, NULL, 10); + + if ((enable == 0) || (enable == 1)) { + m1120_set_enable(dev, enable); + } + + return count; +} + +static ssize_t m1120_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%d\n", m1120_get_delay(dev)); +} + +static ssize_t m1120_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long delay = simple_strtoul(buf, NULL, 10); + + if (delay > M1120_DELAY_MAX) { + delay = M1120_DELAY_MAX; + } + + m1120_set_delay(dev, delay); + + return count; +} + +static ssize_t m1120_debug_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, 20, "%d\n", m1120_get_debug(dev)); +} + +static ssize_t m1120_debug_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long debug = simple_strtoul(buf, NULL, 10); + + m1120_set_debug(dev, debug); + + return count; +} + +static ssize_t m1120_wake_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return 0; +} + +static ssize_t m1120_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + //struct i2c_client *client = to_i2c_client(dev); + //m1120_data_t *p_data = i2c_get_clientdata(client); + short raw = 0; + m1120_get_data(&raw); + return snprintf(buf, 10, "%d\n", raw); +} + +static int m1120_i2c_read(struct i2c_client *client, u8 reg, u8 *rdata, u8 len) +{ +#if 0////add by James. + int rc; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = rdata, + }, + }; + if (client == NULL) { + mxerr(&client->dev, "client is NULL"); + return -ENODEV; + } + rc = i2c_transfer(client->adapter, msg, 2); + if (rc < 0) { + mxerr(&client->dev, "i2c_transfer was failed(%d)", rc); + return rc; + } +#else + /*Add By James for i2c_smbus_read_i2c_block_data */ + i2c_smbus_read_i2c_block_data(client, reg, len, rdata); +#endif + return 0; +} + +static int m1120_i2c_get_reg(struct i2c_client *client, u8 reg, u8 *rdata) +{ + return m1120_i2c_read(client, reg, rdata, 1); +} + +static void m1120_get_reg(struct device *dev, int *regdata) +{ + struct i2c_client *client = to_i2c_client(dev); + int err; + u8 rega = (((*regdata) >> 8) & 0xFF); + u8 regd = 0; + err = m1120_i2c_get_reg(client, rega, ®d); + *regdata = 0; + *regdata |= (err == 0) ? 0x0000 : 0xFF00; + *regdata |= regd; +} + +static ssize_t m1120_dump_show(struct device *dev,struct device_attribute *attr, char *buf) +{ + int reg = 0; + int reg_l = M1120_REG_HSL; + int reg_h = M1120_REG_HSH; + int i = 0; + for (i = 0; i < 11; i++) { + reg = i<<8; + m1120_get_reg(&p_m1120_data->client->dev, ®); + printk(KERN_ERR"dkk: the reg 0x%02X value: 0x%02X\n", i, reg); + } + m1120_get_reg(&p_m1120_data->client->dev, ®_l); + printk(KERN_ERR"dkk: the reg_l is 0x%02X\n", (u8)(reg_l&0xFF)); + m1120_get_reg(&p_m1120_data->client->dev, ®_h); + printk(KERN_ERR"dkk: the reg_h is 0x%02X", (u8)(reg_h&0xFF)); + reg = ((reg_h&0xC0) << 2)|reg_l; + printk(KERN_ERR"dkk: the down hall reg measure is 0x%02X\n", reg); + return snprintf(buf, 10, "%d\n", reg); +//return 0; + } + + +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP, m1120_enable_show, m1120_enable_store); +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP, m1120_delay_show, m1120_delay_store); +static DEVICE_ATTR(debug, S_IRUGO|S_IWUSR|S_IWGRP, m1120_debug_show, m1120_debug_store); +static DEVICE_ATTR(wake, S_IWUSR|S_IWGRP, NULL, m1120_wake_store); +static DEVICE_ATTR(rawdata, S_IRUGO|S_IWUSR|S_IWGRP, m1120_data_show, NULL); +static DEVICE_ATTR(dump, S_IRUGO|S_IWUSR|S_IWGRP, m1120_dump_show, NULL); + +static struct attribute *m1120_attributes[] = { + &dev_attr_enable.attr, + &dev_attr_delay.attr, + &dev_attr_debug.attr, + &dev_attr_wake.attr, + &dev_attr_rawdata.attr, + &dev_attr_dump.attr, + NULL +}; + +static struct attribute_group m1120_attribute_group = { + .attrs = m1120_attributes +}; + +static int m1120_power_ctl(m1120_data_t *data, bool on) +{ + int ret = 0; + int err = 0; + + if (!on && data->power_enabled) { + ret = regulator_disable(data->vdd); + if (ret) { + dev_err(&data->client->dev, + "Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + + ret = regulator_disable(data->vio); + if (ret) { + dev_err(&data->client->dev, + "Regulator vio disable failed ret=%d\n", ret); + err = regulator_enable(data->vdd); + return ret; + } + data->power_enabled = on; + } else if (on && !data->power_enabled) { + ret = regulator_enable(data->vdd); + if (ret) { + dev_err(&data->client->dev, + "Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + msleep(8);////>=5ms OK. + ret = regulator_enable(data->vio); + if (ret) { + dev_err(&data->client->dev, + "Regulator vio enable failed ret=%d\n", ret); + err = regulator_disable(data->vdd); + return ret; + } + msleep(10); // wait 10ms + data->power_enabled = on; + } else { + dev_info(&data->client->dev, + "Power on=%d. enabled=%d\n", + on, data->power_enabled); + } + + return ret; +} + +static int m1120_power_init(m1120_data_t *data) +{ + int ret; + + data->vdd = regulator_get(&data->client->dev, "vdd"); + if (IS_ERR(data->vdd)) { + ret = PTR_ERR(data->vdd); + dev_err(&data->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + return ret; + } + + if (regulator_count_voltages(data->vdd) > 0) { + ret = regulator_set_voltage(data->vdd, + M1120_VDD_MIN_UV, + M1120_VDD_MAX_UV); + if (ret) { + dev_err(&data->client->dev, + "Regulator set failed vdd ret=%d\n", + ret); + goto reg_vdd_put; + } + } + + data->vio = regulator_get(&data->client->dev, "vio"); + if (IS_ERR(data->vio)) { + ret = PTR_ERR(data->vio); + dev_err(&data->client->dev, + "Regulator get failed vio ret=%d\n", ret); + goto reg_vdd_set; + } + + if (regulator_count_voltages(data->vio) > 0) { + ret = regulator_set_voltage(data->vio, + M1120_VIO_MIN_UV, + M1120_VIO_MAX_UV); + if (ret) { + dev_err(&data->client->dev, + "Regulator set failed vio ret=%d\n", ret); + goto reg_vio_put; + } + } + + return 0; + +reg_vio_put: + regulator_put(data->vio); +reg_vdd_set: + if (regulator_count_voltages(data->vdd) > 0) + regulator_set_voltage(data->vdd, 0, M1120_VDD_MAX_UV); +reg_vdd_put: + regulator_put(data->vdd); + return ret; +} + + +static int tri_key_m1120_parse_dt(struct device *dev, + m1120_data_t *pdata) +{ + struct device_node *np = dev->of_node; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + u32 temp_val; + int rc; + struct i2c_client *client = to_i2c_client(dev); + m1120_data_t *p_data = i2c_get_clientdata(client); + + dev_err(dev, "======> %s", __func__); + rc = of_property_read_u32(np, "magnachip,init-interval", &temp_val); + if (rc && (rc != -EINVAL)) { + dev_err(dev, "Unable to read init-interval\n"); + return rc; + } else { + if (temp_val < M1120_DELAY_MIN) + temp_val = M1120_DELAY_MIN; + atomic_set(&p_data->atm.delay, temp_val); + } + + p_data->int_en = of_property_read_bool(np, "magnachip,use-interrupt"); + + p_data->igpio = of_get_named_gpio_flags(dev->of_node, + "magnachip,gpio-int", 0, NULL); + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + dev_err(dev, "irq_gpio : %d", p_data->irq_gpio); + + p_data->use_hrtimer = of_property_read_bool(np, "magnachip,use-hrtimer"); + + key_pinctrl = devm_pinctrl_get(dev); + + if (IS_ERR_OR_NULL(key_pinctrl)) { + dev_err(dev, "Failed to get pinctrl\n"); + } + set_state = pinctrl_lookup_state(key_pinctrl, + "uphall_tri_state_key_active"); + if (IS_ERR_OR_NULL(set_state)) { + dev_err(dev, "Failed to lookup_state\n"); + } + + pinctrl_select_state(key_pinctrl,set_state); + + + return 0; +} + +//interface implement for op_motor.c + +static int m1120_get_data( short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + + TRI_KEY_DEBUG(KERN_INFO "======> %s", __func__); + if(!p_m1120_data) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -1; + } + // (1) read data + err = m1120_i2c_read_block(p_m1120_data, M1120_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG(" fail %d \n",err); + return err; + } + + // (2) collect data + if (buf[0] & 0x01) { + value = m1120_2byte_to_short(p_m1120_data, buf[2], buf[1]); + } else { + TRI_KEY_DEBUG("m1120: st1(0x%02X) is not DRDY.\n", buf[0]); + return err; + } + *data = value; + TRI_KEY_DEBUG("up, value : %d\n", value); + return 0; +} + +static int m1120_enable_irq(bool enable) +{ + printk(KERN_INFO "======> %s", __func__); + + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + if (enable) { + enable_irq(p_m1120_data->irq); + } else { + disable_irq_nosync(p_m1120_data->irq); + } + + return 0; +} + +static int m1120_clear_irq() +{ + printk(KERN_INFO "======> %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_clear_interrupt(&p_m1120_data->client->dev); + return 0; +} + +static int m1120_get_irq_state() +{ + printk(KERN_INFO "======> %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + return ((p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static bool m1120_update_threshold(int position, short lowthd, short highthd) +{ + + u8 lthh, lthl, hthh, hthl; + int err = 0; + + printk(KERN_INFO "======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL \n"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120_up ,low:%d, high:%d \n",lowthd, highthd); + + err = m1120_clear_interrupt(&p_m1120_data->client->dev); + + //if (p_m1120_data->reg.map.intsrs & M1120_VAL_INTSRS_INTTYPE_BESIDE) { + if (p_m1120_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + printk("up hall m1120_update_threshold, lowthd=%d, highthd=%d.\n", lowthd, highthd); + m1120_short_to_2byte(p_m1120_data, highthd, &hthh, &hthl); + m1120_short_to_2byte(p_m1120_data, lowthd, <hh, <hl); + + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHH,&hthh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_HTHL,&hthl, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHH,<hh, 1); + err |= m1120_i2c_write_block(p_m1120_data, M1120_REG_LTHL,<hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("tri_key:fail %d\n",err); + return false; + } else { + return true; + } + + return true; +} + +static void m1120_dump_reg(u8* buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + printk(KERN_INFO "======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL \n"); + return ; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = m1120_i2c_read_block(p_m1120_data, i, &val, 1); + if (err < 0) { + snprintf(buf, PAGE_SIZE, "read reg error!\n"); + return; + } + + snprintf(_buf, sizeof(_buf), "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + snprintf(buf, PAGE_SIZE, "%s\n", buffer); + TRI_KEY_LOG("%s \n",buf); + return; +} + +static bool m1120_is_power_on() +{ + printk(KERN_INFO "======> %s", __func__); + if (p_m1120_data == NULL) { + TRI_KEY_LOG("p_m1120_data == NULL \n"); + return false; + } + + return p_m1120_data->power_enabled > 0 ? true : false; +} + +static int m1120_set_detection_mode_1(u8 mode) +{ + u8 data = 0; + int err = 0; + + printk(KERN_INFO "======> %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + TRI_KEY_LOG("m1120 up detection mode : %s\n", (mode == 0)? "POLLING":"INTERRUPT"); + + if(mode & DETECTION_MODE_INTERRUPT) { //interrupt mode + if (!p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs | M1120_DETECTION_MODE_INTERRUPT; + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1);// + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + err = m1120_clear_interrupt(&p_m1120_data->client->dev); + if (err < 0) { + TRI_KEY_ERR("clear interupt fail %d \n",err); + return err; + } + + /* requst irq */ + TRI_KEY_LOG("m1120 down enter irq handler\n"); + if (request_irq(p_m1120_data->irq, &m1120_up_irq_handler, IRQ_TYPE_LEVEL_LOW, + "hall_m1120_up",(void *)p_m1120_data->client)) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(p_m1120_data->irq, 1); + + p_m1120_data->irq_enabled = 1; + } + } else { // polling mode + if (p_m1120_data->irq_enabled) { + data = p_m1120_data->reg.map.intsrs & (0xFF - M1120_DETECTION_MODE_INTERRUPT); + + err = m1120_i2c_write_block(p_m1120_data, M1120_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + disable_irq(p_m1120_data->irq); + free_irq(p_m1120_data->irq, NULL); + + p_m1120_data->irq_enabled = 0; + } + } + + return 0; +} + +static int m1120_set_reg_1(int reg, int val) +{ + + u8 data = (u8)val; + + printk(KERN_INFO "======> %s", __func__); + if(p_m1120_data == NULL) { + TRI_KEY_ERR("p_m1120_data == NULL"); + return -EINVAL; + } + + m1120_i2c_write_block(p_m1120_data, (u8)reg, &data,1); + return 0; +} + +struct dhall_operations m1120_ups_ops = { + .get_data = m1120_get_data, + .enable_irq = m1120_enable_irq, + .clear_irq = m1120_clear_irq, + .get_irq_state = m1120_get_irq_state, + .set_detection_mode = m1120_set_detection_mode_1, + .update_threshold = m1120_update_threshold, + .dump_regs = m1120_dump_reg, + .set_reg = m1120_set_reg_1, + .is_power_on = m1120_is_power_on +}; + +/************************************************** + i2c client + **************************************************/ + +static int tri_key_m1120_i2c_drv_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + m1120_platform_data_t *p_platform; + m1120_data_t *p_data; + int err = 0; + + dbg_func_in(); + + printk(KERN_INFO "======> allocation memory for p_m1120_data up %s\n", __func__); + /*(1) allocation memory for p_m1120_data*/ + p_data = kzalloc(sizeof(m1120_data_t), GFP_KERNEL); + if (!p_data) { + mxerr(&client->dev, "kernel memory alocation was failed"); + err = -ENOMEM; + goto error_0; + } + + /*(2) init mutex variable*/ + mutex_init(&p_data->mtx.enable); + mutex_init(&p_data->mtx.data); + p_data->power_enabled = false; + printk(KERN_INFO "======> init mutex variable \n"); + /*(3) config i2c client*/ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + mxerr(&client->dev, "i2c_check_functionality was failed"); + err = -ENODEV; + goto error_1; + } + i2c_set_clientdata(client, p_data); + p_data->client = client; + p_m1120_data = p_data; + + if (client->dev.of_node) { + dev_err(&client->dev, "Use client->dev.of_node\n"); + err = tri_key_m1120_parse_dt(&client->dev, p_data); + if (err) { + dev_err(&client->dev, "Failed to parse device tree\n"); + err = -EINVAL; + goto error_1; + } + } else { + p_platform = client->dev.platform_data; + dev_err(&client->dev, "Use platform data\n"); + } + /*(5) setup interrupt gpio*/ + /*if (p_data->igpio != -1) { + err = gpio_request(p_data->igpio, "m1120_irq"); + if (err) { + mxerr(&client->dev, "gpio_request was failed(%d)", err); + goto error_1; + } + mxinfo(&client->dev, "gpio_request was success"); + err = gpio_direction_input(p_data->igpio); + if (err < 0) { + mxerr(&client->dev, "gpio_direction_input was failed(%d)", err); + goto error_2; + } + mxinfo(&client->dev, "gpio_direction_input was success"); + }*/ + + //pull pm8150 gpio_04 down + // err = set_gpio_state(&client->dev); + // if (err) { + // dev_err(&client->dev, "Failed to set gpio state\n"); + // } + //gpio irq request + if (gpio_is_valid(p_data->irq_gpio)) { + err = gpio_request(p_data->irq_gpio, "m1120_up_irq"); + if (err) { + mxerr(&client->dev, "unable to request gpio [%d]", p_data->irq_gpio); + } else { + err = gpio_direction_input(p_data->irq_gpio); + msleep(50); + p_data->irq = gpio_to_irq(p_data->irq_gpio); + mxerr(&client->dev, "======> irq : %d", p_data->irq); + } + + } + + err = m1120_power_init(p_data); + if (err) { + dev_err(&client->dev, "Failed to get sensor regulators\n"); + err = -EINVAL; + goto error_1; + } + err = m1120_power_ctl(p_data, true); + if (err) { + dev_err(&client->dev, "Failed to enable sensor power\n"); + err = -EINVAL; + goto error_1; + } + + + /*(6) reset and init device*/ + err = m1120_init_device(&p_data->client->dev); + if (err) { + mxerr(&client->dev, "m1120_init_device was failed(%d)", err); + goto error_1; + } + mxinfo(&client->dev, "%s was found", id->name); + + /*(7) config work function*/ + //INIT_DELAYED_WORK(&p_data->work, m1120_work_func); + + /*(8) init input device*/ + err = m1120_input_dev_init(p_data); + if (err) { + mxerr(&client->dev, "m1120_input_dev_init was failed(%d)", err); + goto error_1; + } + mxinfo(&client->dev, "%s was initialized", M1120_DRIVER_NAME_UP); + + /*(9) create sysfs group*/ + err = sysfs_create_group(&p_data->input_dev->dev.kobj, &m1120_attribute_group); + if (err) { + mxerr(&client->dev, "sysfs_create_group was failed(%d)", err); + goto error_3; + } + + /*(10) register misc device*/ + // err = misc_register(&m1120_misc_dev); + // if (err) { + // mxerr(&client->dev, "misc_register was failed(%d)", err); + // goto error_4; + // } + + /*(11) register ops to abstrace level*/ + oneplus_register_hall("hall_up",&m1120_ups_ops); + p_m1120_data->source = wakeup_source_register(&client->dev, "hall_up"); + + printk(KERN_INFO "======> i2c addr : %d\n", client->addr); + /*(12) imigrate p_data to p_m1120_data*/ + dbg("%s : %s was probed.\n", __func__, M1120_DRIVER_NAME_UP); + + return 0; + +//error_4: + // sysfs_remove_group(&p_data->input_dev->dev.kobj, &m1120_attribute_group); + +error_3: + m1120_input_dev_terminate(p_data); + + +error_1: + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + kfree(p_data); + +error_0: + p_m1120_data = NULL; + return err; +} + +static int m1120_i2c_drv_remove(struct i2c_client *client) +{ + m1120_data_t *p_data = i2c_get_clientdata(client); + + m1120_set_enable(&client->dev, 0); + // misc_deregister(&m1120_misc_dev); + sysfs_remove_group(&p_data->input_dev->dev.kobj, &m1120_attribute_group); + m1120_input_dev_terminate(p_data); + if (p_data->igpio != -1) { + gpio_free(p_data->igpio); + } + kfree(p_data); + + return 0; +} + +/* +static int m1120_i2c_drv_suspend(struct i2c_client *client, pm_message_t mesg) +{ + m1120_data_t *p_data = i2c_get_clientdata(client); + + dbg_func_in(); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(&client->dev)) { + if (p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + m1120_set_operation_mode(&client->dev, OPERATION_MODE_MEASUREMENT); + } else { + cancel_delayed_work_sync(&p_data->work); + m1120_set_detection_mode(&client->dev, M1120_DETECTION_MODE_INTERRUPT); + } + } + + mutex_unlock(&p_data->mtx.enable); + + dbg_func_out(); + + return 0; +} + +static int m1120_i2c_drv_resume(struct i2c_client *client) +{ + m1120_data_t *p_data = i2c_get_clientdata(client); + + dbg_func_in(); + + mutex_lock(&p_data->mtx.enable); + + if (m1120_get_enable(&client->dev)) { + if (p_data->reg.map.intsrs & M1120_DETECTION_MODE_INTERRUPT) { + m1120_set_detection_mode(&client->dev, M1120_DETECTION_MODE_POLLING); + schedule_delayed_work(&p_data->work, msecs_to_jiffies(m1120_get_delay(&client->dev))); + } + } + + mutex_unlock(&p_data->mtx.enable); + + dbg_func_out(); + + return 0; +} +*/ + +static const struct i2c_device_id m1120_i2c_drv_id_table[] = { + {"hall_m1120_up", 0 }, + { } +}; + + +static const struct of_device_id m1120_of_match[] = { + { .compatible = "tri_key_magnachip,tk_mxm1120,up", }, + { }, +}; + +static struct i2c_driver m1120_driver = { + .driver = { + .owner = THIS_MODULE, + .name = M1120_DRIVER_NAME_UP, + .of_match_table = m1120_of_match, + }, + .probe = tri_key_m1120_i2c_drv_probe, + .remove = m1120_i2c_drv_remove, + .id_table = m1120_i2c_drv_id_table, + //.suspend = m1120_i2c_drv_suspend, + //.resume = m1120_i2c_drv_resume, +}; + +static int __init tri_key_m1120_driver_init_up(void) +{ + int res = 0; + printk(KERN_INFO "======>log %s\n", __func__); + res = i2c_add_driver(&m1120_driver); + printk(KERN_INFO "======>log %s, res : %d\n", __func__, res); + return res; +} +module_init(tri_key_m1120_driver_init_up); + +static void __exit m1120_driver_exit_up(void) +{ + printk(KERN_INFO "%s\n", __func__); + i2c_del_driver(&m1120_driver); +} +module_exit(m1120_driver_exit_up); + +MODULE_AUTHOR("shpark "); +MODULE_VERSION(M1120_DRIVER_VERSION); +MODULE_DESCRIPTION("M1120 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/oneplus/tri_state_key/ist_hall_ic/Kconfig b/drivers/oneplus/tri_state_key/ist_hall_ic/Kconfig new file mode 100755 index 0000000000000000000000000000000000000000..25cc631d5312f1518175d9f3778b5147928f5ec1 --- /dev/null +++ b/drivers/oneplus/tri_state_key/ist_hall_ic/Kconfig @@ -0,0 +1,5 @@ +config SENSOR_HALL_IST8801 + tristate "digital hall ist8801 Controler" + default n + help + Say Y here to enable ist8801. \ No newline at end of file diff --git a/drivers/oneplus/tri_state_key/ist_hall_ic/Makefile b/drivers/oneplus/tri_state_key/ist_hall_ic/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..6aec5ef856fdba93b619d14b97f2e41649ad4061 --- /dev/null +++ b/drivers/oneplus/tri_state_key/ist_hall_ic/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the touchscreen drivers. +# + +# Each configuration option enables a list of files. + +#obj-$(CONFIG_SENSOR_HALL_IST8801) += hall_ist8801_up.o hall_ist8801_down.o + +obj-y += hall_ist8801_up.o hall_ist8801_down.o +#mxm1120_down.o + + + diff --git a/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801.h b/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801.h new file mode 100644 index 0000000000000000000000000000000000000000..6650eacf563dabce6fb8738d347fe8aa46010990 --- /dev/null +++ b/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801.h @@ -0,0 +1,304 @@ +#ifndef __IST8801_H__ +#define __IST8801_H__ + +#include +#include +#include + + +/* ********************************************************* */ +/* feature of ic revision */ +/* ********************************************************* */ +#define IST8801_REV_0_2 (0x02) +#define IST8801_REV_1_0 (0x10) +#define IST8801_REV IST8801_REV_1_0 +#define IST8801_DRIVER_VERSION "Ver1.00-190222" +/* ********************************************************* */ + + +/* +SAD1 SAD0 == 00 0001100 R/W (7bits)0x0C (8bits)0x18 +SAD1 SAD0 == 01 0001101 R/W (7bits)0x0D (8bits)0x1A +SAD1 SAD0 == 10 0001110 R/W (7bits)0x0E (8bits)0x1C +SAD1 SAD0 == 11 0001111 R/W (7bits)0x0F (8bits)0x1E +*/ +/* ********************************************************* */ + +/* ********************************************************* */ +/* register map */ +/* ********************************************************* */ +#define IST8801_REG_PERSINT (0x00) +#define IST8801_VAL_PERSINT_COUNT(n) (n<<4) + + /* + *[7:4] PERS : interrupt persistence count + *[0] INTCLR = 1 : interrupt clear + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_INTSRS (0x01) +#define IST8801_VAL_INTSRS_INT_ON (0x80) +#define IST8801_DETECTION_MODE_INTERRUPT IST8801_VAL_INTSRS_INT_ON +#define IST8801_VAL_INTSRS_INT_OFF (0x00) +#define IST8801_DETECTION_MODE_POLLING IST8801_VAL_INTSRS_INT_OFF +#define IST8801_VAL_INTSRS_INTTYPE_BESIDE (0x00) +#define IST8801_VAL_INTSRS_INTTYPE_WITHIN (0x10) +#define IST8801_VAL_INTSRS_ZGAIN (0x00) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_2 (0x01) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_4 (0x02) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_8 (0x03) +#define IST8801_VAL_INTSRS_ZGAIN_DIV_16 (0x04) + /* + *[7] INTON = 0 : disable interrupt + *[7] INTON = 1 : enable interrupt + *[4] INT_TYP = 0 : generate interrupt when raw data is beside range of threshold + *[4] INT_TYP = 1 : generate interrupt when raw data is within range of threshold + *[2:0] SRS : Sensitivity range and resolution : default 010 + *000 : GAIN= ZGAIN (Register 0x54) + *001 : GAIN= ZGAIN / 2 + *010 : GAIN= ZGAIN / 4 + *011 : GAIN= ZGAIN / 8 + *100 : GAIN= ZGAIN / 16 + *Others : GAIN= ZGAIN / 4 + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_LTHL (0x02) + /* + *[7:0] LTHL : low byte of low threshold value + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_LTHH (0x03) + /* + *[7:0] LTHH : high byte of low threshold value with sign + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_HTHL (0x04) + /* + *[7:0] HTHL : low byte of high threshold value + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_HTHH (0x05) + /* + *[7:0] HTHH : high bye of high threshold value with sign + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_I2CDIS (0x06) +#define IST8801_VAL_I2CDISABLE (0x37) + /* + *[7:0] I2CDIS : disable i2c + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_SRST (0x07) +#define IST8801_VAL_SRST_RESET (0x01) + /* + *[0] SRST = 1 : soft reset + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_OPF (0x08) +#define IST8801_VAL_OPF_STANDBY (0x00) +#define IST8801_VAL_OPF_FREQ_10HZ (0x10) +#define IST8801_VAL_OPF_FREQ_6_7HZ (0x20) +#define IST8801_VAL_OPF_FREQ_5HZ (0x30) +#define IST8801_VAL_OPF_FREQ_80HZ (0x40) +#define IST8801_VAL_OPF_FREQ_40HZ (0x50) +#define IST8801_VAL_OPF_FREQ_26_7HZ (0x60) +#define IST8801_VAL_OPF_FREQ_20HZ (0x70) +#define IST8801_VAL_OPF_SINGLE_MODE (0x80) +#define IST8801_VAL_OPF_FREQ_100HZ (0x90) +#define IST8801_VAL_OPF_FREQ_50HZ (0xA0) +#define IST8801_VAL_OPF_FREQ_1HZ (0xB0) +#define IST8801_VAL_OPF_FREQ_200HZ (0xC0) +#define IST8801_VAL_OPF_FREQ_250HZ (0xD0) +#define IST8801_VAL_OPF_FREQ_320HZ (0xE0) +#define IST8801_VAL_OPF_FREQ_500HZ (0xF0) + /* + [7:4] OPF : operation frequency + *00 : Standby mode + *10 : 10 (Hz) + *20 : 6.7 (Hz) + *30 : 5 (Hz) + *40 : 80 (Hz) + *50 : 40 (Hz) + *60 : 26.7 (Hz) + *70 : 20 (Hz) + *80 : Single mode + *90 : 100 (Hz) + *A0 : 50 (Hz) + *B0 : 1 (Hz) + *C0 : 200 (Hz) + *D0 : 250 (Hz) + *E0 : 320 (Hz) + *F0 : 500 (Hz) + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_DID (0x09) +#define IST8801_VAL_DID (0x81) + /* + *[7:0] DID : Device ID by OTP + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_ST1 (0x10) +#define IST8801_VAL_ST1_DRDY (0x01) + /* + *[4] INTM : status of interrupt mode + *[2] DORZ : 0 = no data overrun, 1 = data is overrun + *[0] DRDY : status of data ready + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_HSL (0x11) + /* + *[7:0] HSL : low byte of hall sensor measurement data + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_HSH (0x12) + /* + *[7:0] HSL : high byte of hall sensor measurement data with sign + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_TDATAL (0x13) + /* + *[7:6] HSL : Temperature Data, Low Byte + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_TDATAH (0x14) + /* + *[7:6] HSL : Temperature Data, High Byte + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_USR_ODR_L (0x1A) + /* + *[7:6] HSL : More User ODR Mode, Low Byte + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_USR_ODR_H (0x1B) + /* + *[7:6] HSL : More User ODR Mode, High Byte + */ +/* --------------------------------------------------------- */ +#define IST8801_REG_ACTION (0x20) + /* + *[1] ACTR : Action Register + */ +/* ********************************************************* */ + +/* --------------------------------------------------------- */ +#define IST8801_REG_CNTL2 (0x0D) +#define GAIN_1_TIME (0x0 << 5) +#define GAIN_2_TIME (0x1 << 5) //for 40mT +#define GAIN_4_TIME (0x2 << 5) //for 20mT +#define GAIN_8_TIME (0x3 << 5) //for 10mT +#define ADC_RES_15_BIT (0x1 << 1) +#define ADC_RES_14_BIT (0x2 << 1) +#define ADC_RES_13_BIT (0x3 << 1) +#define ADC_RES_12_BIT (0x4 << 1) +#define ADC_RES_11_BIT (0x5 << 1) +#define ADC_RES_10_BIT (0x6 << 1) +#define ADC_RES_9_BIT (0x7 << 1) +#define ADC_RES_8_BIT (0x8 << 1) +#define ADC_RES_16_BIT (0x9 << 1) //other + /* + *[6:5] GAIN : 1 times/2 times/4 times/8 times + *[4:1] ADC_RS : 15/14/13/12/11/10/9/8 bits + */ +/* ********************************************************* */ +#define IST8801_REG_IFCNTL (0x40) +/* ********************************************************* */ +#define IST8801_REG_GAINCNTL (0x54) +/* ********************************************************* */ +#define IST8801_REG_TSTCNTL (0x76) +/* ********************************************************* */ +#define IST8801_REG_OSRCNTL (0x6c) +/* ********************************************************* */ +#define IST8801_REG_INFO (0x87) +/* ********************************************************* */ +/* data type for driver */ +/* ********************************************************* */ + +enum { + OPERATION_MODE_POWERDOWN, + OPERATION_MODE_MEASUREMENT, + OPERATION_MODE_LOWPOWER_MEASUREMENT, + OPERATION_MODE_FUSEROMACCESS, + OPERATION_MODE_SUSPEND +}; + +struct hall_srs { + char name[12]; + uint8_t value; + bool bias; + uint32_t ratio; +}; + +/* ********************************************************* */ +/* Need to set parameter for ist8801 driver */ +/* ********************************************************* */ +#define CURRENT_LOAD_UA (100000)//100ma +#define IST8801_INTERRUPT_TYPE IST8801_VAL_INTSRS_INTTYPE_BESIDE +//#define IST8801_INTERRUPT_TYPE IST8801_VAL_INTSRS_INTTYPE_WITHIN +#define IST8801_PERSISTENCE_COUNT IST8801_VAL_PERSINT_COUNT(2) +#define IST8801_SENSITIVITY_TYPE 0 +#define IST8801_DETECTION_MODE IST8801_DETECTION_MODE_INTERRUPT +#define IST8801_REG_NUM (16) +#define FREQUENCY IST8801_VAL_OPF_FREQ_20HZ +#define LOWPOWER_FREQUENCY IST8801_VAL_OPF_FREQ_40HZ +//#define DYNAMIC_GAIN_ADC_BIT (GAIN_2_TIME | ADC_RES_12_BIT) +#define DYNAMIC_GAIN_ADC_BIT (GAIN_4_TIME | ADC_RES_10_BIT) +#define ENABLE_FILTER 0 +#define FILTER_MODE 0 // 0 for light , 1 for weight +#define DISABLE_TEMP_CONPEN 0 +/* ********************************************************* */ + +typedef union { + struct { + unsigned char persint; + unsigned char intsrs; + unsigned char lthl; + unsigned char lthh; + unsigned char hthl; + unsigned char hthh; + unsigned char i2cdis; + unsigned char srst; + unsigned char opf; + unsigned char did; + unsigned char info; + unsigned char asa; + unsigned char st1; + unsigned char hsl; + unsigned char hsh; + unsigned char range; + } map; + unsigned char array[IST8801_REG_NUM]; +} ist8801_reg_t; + +typedef struct { + struct i2c_client *client; + struct pinctrl *pctrl; + struct pinctrl_state *power_state; + struct pinctrl_state *irq_state; + ist8801_reg_t reg; + bool irq_enabled; + unsigned int id; + int calibrated_data; + int irq_source; + short value_30degree; + short value_70degree; + short thrhigh; + short thrlow; + bool last_state; + struct delayed_work work; + + struct regulator * power_1v8; + struct regulator * power_2v8; + int irq_gpio; + int irq; + unsigned int power_gpio; + bool is_power_on; + bool enable_hidden; + unsigned int bias_ratio; + uint8_t origin_gain; + uint8_t origin_osr; + uint8_t origin_info; + struct wakeup_source *source; +} ist8801_data_t; +/* ********************************************************* */ + +#endif /* __IST8801_H__ */ diff --git a/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801_down.c b/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801_down.c new file mode 100644 index 0000000000000000000000000000000000000000..8b1292040f6675f86ed02acf485fae4d36d8b3c7 --- /dev/null +++ b/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801_down.c @@ -0,0 +1,1171 @@ +/************************************************************************************ +** VENDOR_EDIT +** File: ist8801.c +** +** Description: +** Definitions for ist8801 digital hall chip. +** +** Version: 1.0 +**************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hall_ist8801.h" +#include "../oneplus_tri_key.h" + +#define IST8801_I2C_BUF_SIZE (17) + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...) printk(KERN_ERR TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_LOG(fmt, args...) printk(KERN_INFO TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do{\ + if (LEVEL_DEBUG == tri_key_debug)\ + printk(KERN_INFO TRI_KEY_TAG " %s: " fmt, __FUNCTION__, ##args);\ + }while(0) + + +static ist8801_data_t *g_ist8801_data; +//for otp info reg is 0x01 +static struct hall_srs ist8801_ranges_1[] = { + {"40mT", GAIN_2_TIME, false ,0}, + {"35mT", GAIN_2_TIME, false ,10}, + {"20mT", GAIN_2_TIME, false ,28}, + {"15mT", GAIN_4_TIME, false ,17}, + {"10mT", GAIN_8_TIME, false ,0}, +}; +//for otp info reg is else +static struct hall_srs ist8801_ranges_2[] = { + {"40mT", GAIN_2_TIME, false ,0}, + {"35mT", GAIN_2_TIME, false ,6}, + {"20mT", GAIN_2_TIME, false ,24}, + {"15mT", GAIN_4_TIME, false ,13}, + {"10mT", GAIN_8_TIME, false ,0}, +}; + + +static DEFINE_MUTEX(ist8801_i2c_mutex); +__attribute__((weak)) void ist8801_reconfig(ist8801_data_t *chip) {return;} + +static int ist8801_i2c_read_block(ist8801_data_t *ist8801_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = ist8801_data->client; + struct i2c_msg msgs[2]={{0},{0}}; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&ist8801_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len =1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len =len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, (sizeof(msgs) / sizeof(msgs[0]))); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n",addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&ist8801_i2c_mutex); + + return err; + +} + +static int ist8801_i2c_write_block(ist8801_data_t *ist8801_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[IST8801_I2C_BUF_SIZE] ={0}; + struct i2c_client *client = ist8801_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&ist8801_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) { + buf[num++] = data[idx]; + } + + //if add is 0x01 reg and don't set interrupt enable +// if(buf[0] == 0x01) { +// buf[1] &= 0x7f; +// } + err = i2c_master_send(client, buf, num); + if (err < 0) { + TRI_KEY_ERR("send command error!! %d\n",err); + } + + //store reg written + if (len == 1) { + switch(addr){ + case IST8801_REG_PERSINT: + ist8801_data->reg.map.persint = data[0]; + break; + case IST8801_REG_INTSRS: + ist8801_data->reg.map.intsrs = data[0]; + break; + case IST8801_REG_LTHL: + ist8801_data->reg.map.lthl = data[0]; + break; + case IST8801_REG_LTHH: + ist8801_data->reg.map.lthh = data[0]; + break; + case IST8801_REG_HTHL: + ist8801_data->reg.map.hthl = data[0]; + break; + case IST8801_REG_HTHH: + ist8801_data->reg.map.hthh = data[0]; + break; + case IST8801_REG_I2CDIS: + ist8801_data->reg.map.i2cdis = data[0]; + break; + case IST8801_REG_SRST: + ist8801_data->reg.map.srst = data[0]; + break; + case IST8801_REG_OPF: + ist8801_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&ist8801_i2c_mutex); + return err; +} + +static void ist8801_short_to_2byte(ist8801_data_t *ist8801_data, short x, u8 *hbyte, u8 *lbyte) +{ + unsigned short temp; + + if (x >= 0) { + temp = x; + } else { + temp = 65536 + x; + } + *lbyte = temp & 0x00ff; + *hbyte = (temp & 0xff00) >> 8; +} + +static short ist8801_2byte_to_short(ist8801_data_t *ist8801_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + x =(short) ((hbyte<<8) | lbyte); + + return x; +} +#if ENABLE_FILTER +static void moving_average_0(u8 *data_hi,u8 *data_lo,u8 mode) +{ + static int first_0 = 0; + int x,y; + static int temp_0= 0; + x= 0; + y = 0; + x = (int) ist8801_2byte_to_short(NULL,*data_hi,*data_lo); + + if(!first_0) { + if(mode == 0) { + y = x; + temp_0 = 4*x; + } else { + y = x; + temp_0 = 2*x; + } + } else { + if(mode == 0) { + temp_0 = (temp_0>>2) + 3*x; + y = temp_0 >> 2; + } else { + temp_0 = 2*x + temp_0; + y = temp_0 >> 2; + temp_0 = temp_0 >> 1; + } + } + + first_0 = 1; + + if(y > 32767) { + y = 32767; + } else if (y <= -32768) { + y = -32768; + } + + ist8801_short_to_2byte(NULL,(short) y,data_hi,data_lo); +} + +#endif + +static int ist8801_get_id(ist8801_data_t *ist8801_data) +{ + u8 data = 0; + ist8801_i2c_read_block(ist8801_data,IST8801_REG_DID,&data,1); + + TRI_KEY_LOG("id = 0x%x \n",data); + + return data; +} + +static int ist8801_get_data(short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + static short pre_value; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + // (1) read data + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG(" fail %d \n",err); + return err; + } + + // (2) collect data + if ((buf[0] & 0x01) | (buf[0] & 0x4)) { //buf[2] for data over run status +#if ENABLE_FILTER + moving_average_0(&buf[2],&buf[1],FILTER_MODE); +#endif + + value = ist8801_2byte_to_short(g_ist8801_data, buf[2], buf[1]); + } else { + TRI_KEY_DEBUG("ist8801: st1(0x%02X) is not DRDY.\n", buf[0]); + *data = pre_value; + return err; + } + + *data = value; + pre_value = value; + + return 0; +} + +static void ist8801_dump_reg(u8* buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = ist8801_i2c_read_block(g_ist8801_data, i, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + + sprintf(_buf, "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + + err = ist8801_i2c_read_block(g_ist8801_data, 0x54, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + sprintf(_buf, "reg 0x%x:0x%x\n", 0x54, val); + strcat(buffer, _buf); + + sprintf(buf, "%s\n", buffer); + TRI_KEY_LOG("%s \n",buf); +} + +static int ist8801_set_reg(int reg, int val) +{ + u8 data = (u8)val; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + ist8801_i2c_write_block(g_ist8801_data, (u8)reg, &data,1); + + return 0; +} + + +static bool ist8801_is_power_on() +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return false; + } + + return g_ist8801_data->is_power_on; +} +/* +static int ist8801_set_power_gpio_down(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->pctrl)) { + ret = PTR_ERR(ist8801_data->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + ist8801_data->power_state = pinctrl_lookup_state(ist8801_data->pctrl, "hall_power_down"); + if (IS_ERR_OR_NULL(ist8801_data->power_state)) { + ret = PTR_ERR(ist8801_data->power_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(ist8801_data->pctrl,ist8801_data->power_state); + + return 0; + +} + +static int ist8801_set_power_gpio_up(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->pctrl)) { + ret = PTR_ERR(ist8801_data->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + ist8801_data->power_state = pinctrl_lookup_state(ist8801_data->pctrl, "hall_power_up"); + if (IS_ERR_OR_NULL(ist8801_data->power_state)) { + ret = PTR_ERR(ist8801_data->power_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(ist8801_data->pctrl,ist8801_data->power_state); + + return 0; + +} +*/ + +/* vdd / vid power control */ +static int ist8801_set_power(ist8801_data_t *ist8801_data, bool on) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->power_2v8)) { + TRI_KEY_ERR("vdd_2v8 invalid\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(ist8801_data->power_1v8)) { + TRI_KEY_ERR("vdd1v8 invalid\n"); + return -EINVAL; + } + + if (on) { + //ist8801_set_power_gpio_up(ist8801_data); + + if (regulator_count_voltages(ist8801_data->power_2v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_2v8, 2856000, 3104000); + if (ret) { + TRI_KEY_LOG("Regulator set_vtg failed vdd ret=%d\n", ret); + return ret; + } + + ret = regulator_set_load(ist8801_data->power_2v8, CURRENT_LOAD_UA); + if (ret) { + TRI_KEY_LOG("Regulator set_vtg failed vdd ret=%d\n", ret); + return ret; + } + } + if (regulator_count_voltages(ist8801_data->power_1v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_1v8, 1800000, 1800000); + if (ret) { + TRI_KEY_LOG("Regulator set_vtg failed vcc_i2c ret=%d\n", ret); + return ret; + } + } + //enable the 2v8 power + ret = regulator_enable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + //should enable the 1v8 power + msleep(20); + //ist8801_set_power_gpio_down(ist8801_data); + + ret = regulator_enable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c enable failed ret=%d\n", ret); + regulator_disable(ist8801_data->power_2v8); + return ret; + } + + ist8801_data->is_power_on = true; + + } else { + ret = regulator_disable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c disable failed ret=%d\n", ret); + ret = regulator_enable(ist8801_data->power_2v8); + return ret; + } + + msleep(8); + ret = regulator_disable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + } + + return 0; +} +/* +static int ist8801_set_frequency(ist8801_data_t *ist8801_data,int frequency) +{ + int err = 0; + u8 rdata = 0; + u8 ifcntl = 0; + + ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &rdata,1); + + ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + rdata = frequency; + TRI_KEY_LOG("IST8801_REG_OPF register : 0x%x\n", rdata); + + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &rdata,1); + if(err < 0) { + TRI_KEY_LOG("set-opf was failed(%d)", err); + return err; + } + return 0; +} +*/ +static int ist8801_clear_interrupt(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + u8 data = ist8801_data->reg.map.persint | 0x01; + //MOTOR_LOG("step1:ist8801_clear_interrupt ist8801_data->reg.map.persint register : 0x%x,data:0x%x\n",ist8801_data->reg.map.persint,data); + + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_PERSINT,&data, 1); + + ist8801_data->reg.map.persint = ist8801_data->reg.map.persint & 0xfe; + data = ist8801_data->reg.map.persint; + //MOTOR_LOG("step2:ist8801_clear_interrupt ist8801_data->reg.map.persint register : 0x%x,data:0x%x\n",ist8801_data->reg.map.persint,data); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_PERSINT,&data, 1); + + return ret; +} + +/* +IST8801_ADC_BIT_NUM +8-bit:0x10 : threshold range: 127~-128 +9-bit:0x0e : threshold range: 255~-256 +10-bit:0x0c : threshold range: 511~-512 +11-bit:0x0a : threshold range: 1023~-1024 +12-bit:0x08 : threshold range: 2047~-2048 +13-bit:0x06 : threshold range: 4095~-4096 +14-bit:0x04 : threshold range: 8191~-8192 +15-bit:0x02 : threshold range: 16383~-16384 +16-bit: other : threshold range: 32767~-32768 +*/ +static bool ist8801_down_update_threshold(int position, short lowthd, short highthd) +{ + u8 lthh, lthl, hthh, hthl; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + TRI_KEY_LOG("low:%d, high:%d \n",lowthd, highthd); + + err = ist8801_clear_interrupt(g_ist8801_data); + + //if (g_ist8801_data->reg.map.intsrs & IST8801_VAL_INTSRS_INTTYPE_WITHIN) { + if (g_ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) { + ist8801_short_to_2byte(g_ist8801_data, highthd, &hthh, &hthl); + ist8801_short_to_2byte(g_ist8801_data, lowthd, <hh, <hl); + + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_HTHH, &hthh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_HTHL, &hthl, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_LTHH, <hh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_LTHL, <hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("fail %d\n",err); + return false; + } else { + return true; + } +} + +static int ist8801_set_operation_mode(ist8801_data_t *ist8801_data, int mode) +{ + u8 opf = 0; + u8 ifcntl = 0; + int ret = 0; + + switch(mode) { + case OPERATION_MODE_POWERDOWN: + opf = 0; + ifcntl = 0; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + //reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_POWERDOWN \n"); + break; + case OPERATION_MODE_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + //IST8801_REG_ACTION is 0x20 + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_ACTION, &opf,1); + + //delay for 5 ms + usleep_range(5000,5000); + + // set Standby mode + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + + // reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + opf = FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_MEASUREMENT \n"); + break; + case OPERATION_MODE_LOWPOWER_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + //IST8801_REG_ACTION is 0x20 + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_ACTION, &opf,1); + //delay for 5 ms + usleep_range(5000,5000); + + // set Standby mode + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + + // reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + opf = LOWPOWER_FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_LOWPOWER_MEASUREMENT \n"); + break; + + case OPERATION_MODE_SUSPEND : + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + + //reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + opf = 0x02; + TRI_KEY_ERR("opf = 0x%x\n", opf); + //IST8801_REG_ACTION is 0x20 + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_ACTION, &opf,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_SUSPEND \n"); + + //delay for 5 ms + usleep_range(5000,5000); + break; + } + + TRI_KEY_ERR("opf = 0x%x\n", opf); + + return ret; +} + + +/* functions for interrupt handler */ +static irqreturn_t ist8801_down_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call \n"); + + if (!g_ist8801_data) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + disable_irq_nosync(g_ist8801_data->irq); + __pm_wakeup_event(g_ist8801_data->source, 2000); + oneplus_hall_irq_handler(1); + + return IRQ_HANDLED; +} + +static int ist8801_setup_eint(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (gpio_is_valid(ist8801_data->irq_gpio)) { + ret = gpio_request(ist8801_data->irq_gpio, "ist8801_down_irq"); + if (ret) { + TRI_KEY_LOG("unable to request gpio [%d]\n", ist8801_data->irq_gpio); + return -EINVAL; + } else { + ret = gpio_direction_input(ist8801_data->irq_gpio); + msleep(50); + ist8801_data->irq = gpio_to_irq(ist8801_data->irq_gpio); + } + } + TRI_KEY_ERR("GPIO %d irq:%d \n",ist8801_data->irq_gpio, ist8801_data->irq); + + return 0; +} + +static int ist8801_set_detection_mode(u8 mode) +{ + u8 data = 0; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + TRI_KEY_LOG("ist8801 detection mode : %s\n", (mode == 0)? "POLLING":"INTERRUPT"); + + if(mode & DETECTION_MODE_INTERRUPT) { //interrupt mode + if (!g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs | IST8801_DETECTION_MODE_INTERRUPT; + err = ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + err = ist8801_clear_interrupt(g_ist8801_data); + if (err < 0) { + TRI_KEY_ERR("clear interupt fail %d \n",err); + return err; + } + + /* requst irq */ + if ((err = request_threaded_irq(g_ist8801_data->irq, NULL, + &ist8801_down_irq_handler, IRQ_TYPE_LEVEL_LOW | IRQF_ONESHOT, + "ist8801_down",(void *)g_ist8801_data->client)) < 0) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(g_ist8801_data->irq, 1); + + g_ist8801_data->irq_enabled = 1; + } + } else { // polling mode + if (g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs & (0xFF - IST8801_DETECTION_MODE_INTERRUPT); + + err = ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + disable_irq(g_ist8801_data->irq); + free_irq(g_ist8801_data->irq, NULL); + + g_ist8801_data->irq_enabled = 0; + } + } + + return 0; +} + +static int ist8801_enable_irq(bool enable) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + if (enable) { + enable_irq(g_ist8801_data->irq); + } else { + disable_irq_nosync(g_ist8801_data->irq); + + } + return 0; +} + +static int ist8801_clear_irq() +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + ist8801_clear_interrupt(g_ist8801_data); + + return 0; +} + +static int ist8801_get_irq_state() +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + return ((g_ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static void ist8801_set_sensitivity(char *value) +{ + int i = 0; + uint8_t rwdata; + struct hall_srs *srs = NULL,*ist8801_ranges = NULL; + int len1 = 0,len2 = 0,len = 0; + uint8_t temp_opf,err; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return; + } + + + len1 = sizeof(ist8801_ranges_1)/sizeof(struct hall_srs); + len2 = sizeof(ist8801_ranges_2)/sizeof(struct hall_srs); + + if (0x01 == g_ist8801_data->origin_info) { + len = len1; + ist8801_ranges = ist8801_ranges_1; + } else { + len = len2; + ist8801_ranges = ist8801_ranges_2; + } + + for (i = 0; i < len; i++) { + srs = &ist8801_ranges[i]; + if (!strncmp(srs->name, value, strlen(srs->name))) + break; + else + srs = NULL; + } + + if (!srs) { + TRI_KEY_ERR("%s not match\n", value); + return; + } + //backup the data of IST8801_REG_OPF + temp_opf = 0x00; + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_OPF, &temp_opf,1); + + //write IST8801_REG_OPF to 0x00 + rwdata = 0x00; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); + + //reset state machine + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_IFCNTL, &rwdata,1); + rwdata |= 0x04; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_IFCNTL, &rwdata, 1); + + //Just change dynamic range and keep bit resolution + //(DYNAMIC_GAIN_ADC_BIT & 0x1E) -> clean up the dynamic field + // srs->value | (DYNAMIC_GAIN_ADC_BIT & 0x1E) -> update the dynamic field setting + rwdata = ((DYNAMIC_GAIN_ADC_BIT & 0x1E) | srs->value); + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("set sensitivity IST8801_REG_CNTL2 = 0x%x \n",rwdata); + + //check the IST8801_REG_CNTL2 data + rwdata = 0; + ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_CNTL2 = 0x%x \n",rwdata); + + //compensate reg 0x54 + rwdata = ((uint8_t) srs->ratio) + g_ist8801_data->origin_gain; + TRI_KEY_LOG("set sensitivity IST8801_REG_GAINCNTL = %d \n",rwdata); + + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_GAINCNTL, &rwdata, 1); + + //check data is correct + rwdata = 0; + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_GAINCNTL, &rwdata,1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_GAINCNTL = %d \n",rwdata); + + //recovery IST8801_REG_OPF + rwdata = temp_opf; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); +} +/* +IST8801_ADC_BIT_NUM +8-bit:0x10 +9-bit:0x0e +10-bit:0x0c +11-bit:0x0a +12-bit:0x08 +13-bit:0x06 +14-bit:0x04 +15-bit:0x02 +16-bit: other +*/ +static int ist8801_reset_device(ist8801_data_t *ist8801_data) +{ + int err = 0; + u8 data =0; + + data = IST8801_VAL_SRST_RESET; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_SRST, &data,1); + + if (err < 0) { + TRI_KEY_ERR("sw-reset failed(%d)", err); + return err; + } + msleep(20); // wait 20ms + + err = ist8801_i2c_read_block(ist8801_data, IST8801_REG_DID, &data,1); + if (err < 0) { + TRI_KEY_ERR("read IST8801_REG_DID failed(%d)", err); + return err; + } + if (data!= IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02X) is not IST8801 device id(0x%02X)",data,IST8801_VAL_DID); + // TODO: unitl DID defined + //return -ENXIO; + } + + //Disable TST PAD voltage + data = 0x04; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_TSTCNTL, &data,1); + + //Setting osr data = 4 + data = 0x05; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OSRCNTL, &data,1); + + //backup the gain data + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_GAINCNTL, &data,1); + ist8801_data->origin_gain = data; + + TRI_KEY_LOG("ist8801_data->origin_gain = %d \n",ist8801_data->origin_gain); + + //backup the osr data + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_OSRCNTL, &data,1); + ist8801_data->origin_osr = data; + + TRI_KEY_LOG("ist8801_data->origin_osr = %d \n",ist8801_data->origin_osr); + + //backup the info data + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_INFO, &data,1); + ist8801_data->origin_info = data; + + TRI_KEY_LOG("ist8801_data->origin_info = %d \n",ist8801_data->origin_info); + + ist8801_data->reg.map.persint = IST8801_PERSISTENCE_COUNT; + data = ist8801_data->reg.map.persint; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_PERSINT, &data,1); + + + ist8801_data->reg.map.intsrs = IST8801_DETECTION_MODE | ist8801_data->reg.map.range; + if (ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) { + ist8801_data->reg.map.intsrs |= IST8801_INTERRUPT_TYPE; + } + + data = ist8801_data->reg.map.intsrs; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_INTSRS, &data,1); + +#if DISABLE_TEMP_CONPEN + data = 0x01; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &data,1); + if (err < 0) { + TRI_KEY_ERR("IST8801_REG_IFCNTL failed(%d)", err); + return err; + } +#endif + err = ist8801_set_operation_mode(ist8801_data, OPERATION_MODE_MEASUREMENT); + if (err < 0) { + TRI_KEY_ERR("ist8801_set_operation_mode was failed(%d)", err); + return err; + } + + return err; +} + +static int ist8801_parse_dts(struct device *dev, ist8801_data_t *p_data) +{ + struct device_node *np = dev->of_node; + int rc = 0; + uint32_t data_range; + uint32_t value; + +// of_property_read_u32(np,"dhall,id",&p_data->id); +/* + p_data->power_gpio = of_get_named_gpio(np, "qcom,hall-power-gpio", 0); + if (!gpio_is_valid(p_data->power_gpio)) { + MOTOR_LOG("qcom,hall-power-gpio gpio not specified\n"); + } else { + rc = gpio_request(p_data->power_gpio, "hall-power-gpio"); + if (rc) { + MOTOR_LOG("request hall-power gpio failed, rc=%d\n",rc); + goto err; + } + } +*/ + rc = of_property_read_u32(np, "data-range", &data_range); + if (rc) { + p_data->reg.map.range = IST8801_SENSITIVITY_TYPE; + TRI_KEY_LOG("data-range is not specified, use default value:0x%x\n", p_data->reg.map.range); + } else { + p_data->reg.map.range = (uint8_t)data_range; + TRI_KEY_LOG("data-range is 0x%x\n", p_data->reg.map.range); + } + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + + p_data->power_2v8 = regulator_get(&p_data->client->dev, "vdd"); + if (IS_ERR_OR_NULL(p_data->power_2v8)) { + TRI_KEY_ERR("Regulator get failed vdd_2v8\n"); + goto err; + } + + p_data->power_1v8 = regulator_get(&p_data->client->dev, "vio"); + if (IS_ERR_OR_NULL(p_data->power_1v8)) { + TRI_KEY_ERR("Regulator get failed vcc_1v8\n"); + goto err; + } + + p_data->pctrl = devm_pinctrl_get(&p_data->client->dev); + if (IS_ERR_OR_NULL(p_data->pctrl)) { + TRI_KEY_ERR("failed to get pinctrl\n"); + goto err; + } + + p_data->irq_state = pinctrl_lookup_state(p_data->pctrl, "ist8801_hall_down_active"); + if (IS_ERR_OR_NULL(p_data->irq_state)) { + rc = PTR_ERR(p_data->irq_state); + TRI_KEY_ERR("pinctrl_lookup_state, err:%d\n", rc); + goto err; + } else { + pinctrl_select_state(p_data->pctrl,p_data->irq_state); + } + + p_data->enable_hidden = of_property_read_bool(np, "hall,bias_support"); + if (p_data->enable_hidden) { + rc = of_property_read_u32(np, "hall,bias-ratio", &value); + if (rc) { + p_data->bias_ratio = 100; + } else { + p_data->bias_ratio = value; + } + } + return 0; +err: + return rc; +}; + +struct dhall_operations ist8801_down_ops = { + .get_data = ist8801_get_data, + .enable_irq = ist8801_enable_irq, + .clear_irq = ist8801_clear_irq, + .get_irq_state = ist8801_get_irq_state, + .set_detection_mode = ist8801_set_detection_mode, + .update_threshold = ist8801_down_update_threshold, + .dump_regs = ist8801_dump_reg, + .set_reg = ist8801_set_reg, + .is_power_on = ist8801_is_power_on, + .set_sensitivity = ist8801_set_sensitivity, + +}; + +static int ist8801_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + ist8801_data_t *p_data = NULL; + u8 dev_id = 0xFF; + int err = 0; +// client->addr = 0x0C; + TRI_KEY_LOG("call \n"); + + p_data = devm_kzalloc(&client->dev,sizeof(ist8801_data_t), GFP_KERNEL); + if (!p_data) { + TRI_KEY_ERR("kernel memory alocation was failed \n"); + return -ENOMEM; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + TRI_KEY_LOG("i2c unsupported\n"); + return -EOPNOTSUPP; + } + i2c_set_clientdata(client, p_data); + p_data->client = client; + g_ist8801_data = p_data; + if (client->dev.of_node) { + err = ist8801_parse_dts(&client->dev, p_data); + if (err) { + TRI_KEY_ERR("failed to parse device tree\n"); + } + } + ist8801_reconfig(p_data); + + err = ist8801_set_power(p_data,1); + dev_id = ist8801_get_id(p_data); + if (dev_id != IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02x) is not ist8801 device id(0x%02x) \n", dev_id, IST8801_VAL_DID); + goto fail; + } + + err = ist8801_reset_device(p_data); + if (err < 0) { + TRI_KEY_ERR("ist8801_reset_device fail \n"); + goto fail; + } + + err = ist8801_setup_eint(p_data); + + oneplus_register_hall("hall_down",&ist8801_down_ops); + g_ist8801_data->source = wakeup_source_register(&client->dev, "hall_down"); + + ist8801_set_sensitivity("40mT"); + + TRI_KEY_LOG("success. \n"); + return 0; +fail: + TRI_KEY_LOG("fail. \n"); + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + devm_kfree(&client->dev,p_data); + return -ENXIO; +} + +static int ist8801_i2c_remove(struct i2c_client *client) +{ + return 0; +} +/* +static int ist8801_i2c_suspend(struct device *dev) +{ + int ret = 0 ; + + if (g_ist8801_data != NULL ) + ret = ist8801_set_operation_mode(g_ist8801_data,OPERATION_MODE_LOWPOWER_MEASUREMENT); + + return 0; +} + +static int ist8801_i2c_resume(struct device *dev) +{ + int ret = 0 ; + + if (g_ist8801_data != NULL ) + ret = ist8801_set_operation_mode(g_ist8801_data,OPERATION_MODE_MEASUREMENT); + + return 0; +} +*/ +static const struct of_device_id ist8801_match[] = { + { .compatible = "oneplus,hall-ist8801,down"}, + {}, +}; + +static const struct i2c_device_id ist8801_id[] = { + {"hall_ist8801_down", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, ist8801_id); +/* +static const struct dev_pm_ops ist8801_pm_ops = { + .suspend = ist8801_i2c_suspend, + .resume = ist8801_i2c_resume, +}; +*/ +static struct i2c_driver ist8801_i2c_down_driver = { + .driver = { + .name = "hall-ist8801-down", + .of_match_table = ist8801_match, + //.pm = &ist8801_pm_ops, + }, + .probe = ist8801_i2c_probe, + .remove = ist8801_i2c_remove, + .id_table = ist8801_id, +}; + +static int __init ist8801_down_init(void) +{ + TRI_KEY_LOG("call\n"); + i2c_add_driver(&ist8801_i2c_down_driver); + return 0; +} +module_init(ist8801_down_init); + +static void __exit ist8801_down_exit(void) +{ + TRI_KEY_LOG("call\n"); + i2c_del_driver(&ist8801_i2c_down_driver); +} + +module_exit(ist8801_down_exit); + +MODULE_DESCRIPTION("ist8801 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801_up.c b/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801_up.c new file mode 100644 index 0000000000000000000000000000000000000000..5d267b7b806dedbb6c94336fea07ed545e6d6acb --- /dev/null +++ b/drivers/oneplus/tri_state_key/ist_hall_ic/hall_ist8801_up.c @@ -0,0 +1,1173 @@ +/************************************************************************************ +** VENDOR_EDIT +** File: ist8801.c +** +** Description: +** Definitions for ist8801 digital hall chip. +** +** Version: 1.0 +**************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hall_ist8801.h" +#include "../oneplus_tri_key.h" + +#define IST8801_I2C_BUF_SIZE (17) + +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...) printk(KERN_ERR TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_LOG(fmt, args...) printk(KERN_INFO TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do{\ + if (LEVEL_DEBUG == tri_key_debug)\ + printk(KERN_INFO TRI_KEY_TAG " %s: " fmt, __FUNCTION__, ##args);\ + }while(0) + + +static ist8801_data_t *g_ist8801_data; +//for otp info reg is 0x01 +static struct hall_srs ist8801_ranges_1[] = { + {"40mT", GAIN_2_TIME, false ,0}, + {"35mT", GAIN_2_TIME, false ,10}, + {"20mT", GAIN_2_TIME, false ,28}, + {"15mT", GAIN_4_TIME, false ,17}, + {"10mT", GAIN_8_TIME, false ,0}, +}; +//for otp info reg is else +static struct hall_srs ist8801_ranges_2[] = { + {"40mT", GAIN_2_TIME, false ,0}, + {"35mT", GAIN_2_TIME, false ,6}, + {"20mT", GAIN_2_TIME, false ,24}, + {"15mT", GAIN_4_TIME, false ,13}, + {"10mT", GAIN_8_TIME, false ,0}, +}; + + +static DEFINE_MUTEX(ist8801_i2c_mutex); +__attribute__((weak)) void ist8801_reconfig(ist8801_data_t *chip) {return;} + +static int ist8801_i2c_read_block(ist8801_data_t *ist8801_data, u8 addr, u8 *data, u8 len) +{ + u8 reg_addr = addr; + int err = 0; + struct i2c_client *client = ist8801_data->client; + struct i2c_msg msgs[2]={{0},{0}}; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + mutex_lock(&ist8801_i2c_mutex); + + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len =1; + msgs[0].buf = ®_addr; + + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len =len; + msgs[1].buf = data; + + err = i2c_transfer(client->adapter, msgs, (sizeof(msgs) / sizeof(msgs[0]))); + + if (err < 0) { + TRI_KEY_ERR("i2c_transfer error: (%d %p %d) %d\n",addr, data, len, err); + err = -EIO; + } else { + err = 0; + } + mutex_unlock(&ist8801_i2c_mutex); + + return err; + +} + +static int ist8801_i2c_write_block(ist8801_data_t *ist8801_data, u8 addr, u8 *data, u8 len) +{ + int err = 0; + int idx = 0; + int num = 0; + char buf[IST8801_I2C_BUF_SIZE] ={0}; + struct i2c_client *client = ist8801_data->client; + + if (!client) { + TRI_KEY_ERR("client null\n"); + return -EINVAL; + } else if (len >= IST8801_I2C_BUF_SIZE) { + TRI_KEY_ERR(" length %d exceeds %d\n", len, IST8801_I2C_BUF_SIZE); + return -EINVAL; + } + + mutex_lock(&ist8801_i2c_mutex); + + buf[num++] = addr; + for (idx = 0; idx < len; idx++) { + buf[num++] = data[idx]; + } + + //if add is 0x01 reg and don't set interrupt enable +// if(buf[0] == 0x01) { +// buf[1] &= 0x7f; +// } + err = i2c_master_send(client, buf, num); + if (err < 0) { + TRI_KEY_ERR("send command error!! %d\n",err); + } + + //store reg written + if (len == 1) { + switch(addr){ + case IST8801_REG_PERSINT: + ist8801_data->reg.map.persint = data[0]; + break; + case IST8801_REG_INTSRS: + ist8801_data->reg.map.intsrs = data[0]; + break; + case IST8801_REG_LTHL: + ist8801_data->reg.map.lthl = data[0]; + break; + case IST8801_REG_LTHH: + ist8801_data->reg.map.lthh = data[0]; + break; + case IST8801_REG_HTHL: + ist8801_data->reg.map.hthl = data[0]; + break; + case IST8801_REG_HTHH: + ist8801_data->reg.map.hthh = data[0]; + break; + case IST8801_REG_I2CDIS: + ist8801_data->reg.map.i2cdis = data[0]; + break; + case IST8801_REG_SRST: + ist8801_data->reg.map.srst = data[0]; + break; + case IST8801_REG_OPF: + ist8801_data->reg.map.opf = data[0]; + break; + } + } + + mutex_unlock(&ist8801_i2c_mutex); + return err; +} + +static void ist8801_short_to_2byte(ist8801_data_t *ist8801_data, short x, u8 *hbyte, u8 *lbyte) +{ + unsigned short temp; + + if (x >= 0) { + temp = x; + } else { + temp = 65536 + x; + } + *lbyte = temp & 0x00ff; + *hbyte = (temp & 0xff00) >> 8; +} + +static short ist8801_2byte_to_short(ist8801_data_t *ist8801_data, u8 hbyte, u8 lbyte) +{ + short x = 0; + x =(short) ((hbyte<<8) | lbyte); + + return x; +} +#if ENABLE_FILTER +static void moving_average_1(u8 *data_hi,u8 *data_lo,u8 mode) +{ + static int first_1 = 0; + int x,y; + static int temp_1= 0; + x= 0; + y = 0; + x = (int) ist8801_2byte_to_short(NULL,*data_hi,*data_lo); + + if(!first_1) { + if(mode == 0) { + y = x; + temp_1 = 4*x; + } else { + y = x; + temp_1 = 2*x; + } + } else { + if(mode == 0) { + temp_1 = (temp_1>>2) + 3*x; + y = temp_1 >> 2; + } else { + temp_1 = 2*x + temp_1; + y = temp_1 >> 2; + temp_1 = temp_1 >> 1; + } + } + + first_1 = 1; + + if(y > 32767) { + y = 32767; + } else if (y <= -32768) { + y = -32768; + } + + ist8801_short_to_2byte(NULL,(short) y,data_hi,data_lo); +} + +#endif + +static int ist8801_get_id(ist8801_data_t *ist8801_data) +{ + u8 data = 0; + ist8801_i2c_read_block(ist8801_data,IST8801_REG_DID,&data,1); + + TRI_KEY_LOG("id = 0x%x \n",data); + + return data; +} + +static int ist8801_get_data(short *data) +{ + int err = 0; + u8 buf[3] = {0}; + short value = 0; + static short pre_value; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + // (1) read data + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_ST1, buf, sizeof(buf)); + if (err < 0) { + TRI_KEY_LOG(" fail %d \n",err); + return err; + } + + // (2) collect data + if ((buf[0] & 0x01) | (buf[0] & 0x4)) { //buf[2] for data over run status +#if ENABLE_FILTER + moving_average_1(&buf[2],&buf[1],FILTER_MODE); +#endif + + value = ist8801_2byte_to_short(g_ist8801_data, buf[2], buf[1]); + } else { + TRI_KEY_DEBUG("ist8801: st1(0x%02X) is not DRDY.\n", buf[0]); + *data = pre_value; + return err; + } + + *data = value; + pre_value = value; + + return 0; +} + +static void ist8801_dump_reg(u8* buf) +{ + int i, err; + u8 val; + u8 buffer[512] = {0}; + u8 _buf[20] = {0}; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return; + } + + for (i = 0; i <= 0x12; i++) { + memset(_buf, 0, sizeof(_buf)); + + err = ist8801_i2c_read_block(g_ist8801_data, i, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + + sprintf(_buf, "reg 0x%x:0x%x\n", i, val); + strcat(buffer, _buf); + } + + err = ist8801_i2c_read_block(g_ist8801_data, 0x54, &val, 1); + if (err < 0) { + sprintf(buf, "read reg error!\n"); + return; + } + sprintf(_buf, "reg 0x%x:0x%x\n", 0x54, val); + strcat(buffer, _buf); + + sprintf(buf, "%s\n", buffer); + TRI_KEY_LOG("%s \n",buf); +} + +static int ist8801_set_reg(int reg, int val) +{ + u8 data = (u8)val; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + ist8801_i2c_write_block(g_ist8801_data, (u8)reg, &data,1); + + return 0; +} + + +static bool ist8801_is_power_on() +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return false; + } + + return g_ist8801_data->is_power_on; +} +/* +static int ist8801_set_power_gpio_down(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->pctrl)) { + ret = PTR_ERR(ist8801_data->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + ist8801_data->power_state = pinctrl_lookup_state(ist8801_data->pctrl, "hall_power_down"); + if (IS_ERR_OR_NULL(ist8801_data->power_state)) { + ret = PTR_ERR(ist8801_data->power_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(ist8801_data->pctrl,ist8801_data->power_state); + + return 0; + +} + +static int ist8801_set_power_gpio_up(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->pctrl)) { + ret = PTR_ERR(ist8801_data->pctrl); + MOTOR_ERR("failed to get pinctrl\n"); + return ret; + }; + + ist8801_data->power_state = pinctrl_lookup_state(ist8801_data->pctrl, "hall_power_up"); + if (IS_ERR_OR_NULL(ist8801_data->power_state)) { + ret = PTR_ERR(ist8801_data->power_state); + MOTOR_ERR("pinctrl_lookup_state, err:%d\n", ret); + return ret; + }; + + pinctrl_select_state(ist8801_data->pctrl,ist8801_data->power_state); + + return 0; + +} +*/ + +/* vdd / vid power control */ +static int ist8801_set_power(ist8801_data_t *ist8801_data, bool on) +{ + int ret = 0; + + if (IS_ERR_OR_NULL(ist8801_data->power_2v8)) { + TRI_KEY_ERR("vdd_2v8 invalid\n"); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(ist8801_data->power_1v8)) { + TRI_KEY_ERR("vdd1v8 invalid\n"); + return -EINVAL; + } + + if (on) { + //ist8801_set_power_gpio_up(ist8801_data); + + if (regulator_count_voltages(ist8801_data->power_2v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_2v8, 2856000, 3104000); + if (ret) { + TRI_KEY_LOG("Regulator set_vtg failed vdd ret=%d\n", ret); + return ret; + } + + ret = regulator_set_load(ist8801_data->power_2v8, CURRENT_LOAD_UA); + if (ret) { + TRI_KEY_LOG("Regulator set_vtg failed vdd ret=%d\n", ret); + return ret; + } + } + if (regulator_count_voltages(ist8801_data->power_1v8) > 0) { + ret = regulator_set_voltage(ist8801_data->power_1v8, 1800000, 1800000); + if (ret) { + TRI_KEY_LOG("Regulator set_vtg failed vcc_i2c ret=%d\n", ret); + return ret; + } + } + //enable the 2v8 power + ret = regulator_enable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd enable failed ret=%d\n", ret); + return ret; + } + + //should enable the 1v8 power + msleep(20); + //ist8801_set_power_gpio_down(ist8801_data); + + ret = regulator_enable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c enable failed ret=%d\n", ret); + regulator_disable(ist8801_data->power_2v8); + return ret; + } + + ist8801_data->is_power_on = true; + + } else { + ret = regulator_disable(ist8801_data->power_1v8); + if (ret) { + TRI_KEY_LOG("Regulator vcc_i2c disable failed ret=%d\n", ret); + ret = regulator_enable(ist8801_data->power_2v8); + return ret; + } + + msleep(8); + ret = regulator_disable(ist8801_data->power_2v8); + if (ret) { + TRI_KEY_LOG("Regulator vdd disable failed ret=%d\n", ret); + return ret; + } + } + + return 0; +} +/* +static int ist8801_set_frequency(ist8801_data_t *ist8801_data,int frequency) +{ + int err = 0; + u8 rdata = 0; + u8 ifcntl = 0; + + ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &rdata,1); + + ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + rdata = frequency; + TRI_KEY_LOG("IST8801_REG_OPF register : 0x%x\n", rdata); + + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &rdata,1); + if(err < 0) { + TRI_KEY_LOG("set-opf was failed(%d)", err); + return err; + } + return 0; +} +*/ +static int ist8801_clear_interrupt(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + u8 data = ist8801_data->reg.map.persint | 0x01; + //MOTOR_LOG("step1:ist8801_clear_interrupt ist8801_data->reg.map.persint register : 0x%x,data:0x%x\n",ist8801_data->reg.map.persint,data); + + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_PERSINT,&data, 1); + + ist8801_data->reg.map.persint = ist8801_data->reg.map.persint & 0xfe; + data = ist8801_data->reg.map.persint; + //MOTOR_LOG("step2:ist8801_clear_interrupt ist8801_data->reg.map.persint register : 0x%x,data:0x%x\n",ist8801_data->reg.map.persint,data); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_PERSINT,&data, 1); + + return ret; +} + +/* +IST8801_ADC_BIT_NUM +8-bit:0x10 : threshold range: 127~-128 +9-bit:0x0e : threshold range: 255~-256 +10-bit:0x0c : threshold range: 511~-512 +11-bit:0x0a : threshold range: 1023~-1024 +12-bit:0x08 : threshold range: 2047~-2048 +13-bit:0x06 : threshold range: 4095~-4096 +14-bit:0x04 : threshold range: 8191~-8192 +15-bit:0x02 : threshold range: 16383~-16384 +16-bit: other : threshold range: 32767~-32768 +*/ +static bool ist8801_up_update_threshold(int position, short lowthd, short highthd) +{ + u8 lthh, lthl, hthh, hthl; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + TRI_KEY_LOG("low:%d, high:%d \n",lowthd, highthd); + + err = ist8801_clear_interrupt(g_ist8801_data); + +// if (g_ist8801_data->reg.map.intsrs & IST8801_VAL_INTSRS_INTTYPE_WITHIN) { + if (g_ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) { + + ist8801_short_to_2byte(g_ist8801_data, highthd, &hthh, &hthl); + ist8801_short_to_2byte(g_ist8801_data, lowthd, <hh, <hl); + + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_HTHH, &hthh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_HTHL, &hthl, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_LTHH, <hh, 1); + err |= ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_LTHL, <hl, 1); + } + + if (err < 0) { + TRI_KEY_ERR("fail %d\n",err); + return false; + } else { + return true; + } +} + +static int ist8801_set_operation_mode(ist8801_data_t *ist8801_data, int mode) +{ + u8 opf = 0; + int ret = 0; + u8 ifcntl = 0; + + switch(mode) { + case OPERATION_MODE_POWERDOWN: + opf = 0; + ifcntl = 0; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + //reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_POWERDOWN \n"); + break; + case OPERATION_MODE_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + //IST8801_REG_ACTION is 0x20 + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_ACTION, &opf,1); + + //delay for 5 ms + usleep_range(5000,5000); + + // set Standby mode + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + + // reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + opf = FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_MEASUREMENT \n"); + break; + case OPERATION_MODE_LOWPOWER_MEASUREMENT: + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + //IST8801_REG_ACTION is 0x20 + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_ACTION, &opf,1); + //delay for 5 ms + usleep_range(5000,5000); + + //set Standby mode + opf = 0x00; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + + //reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + opf = LOWPOWER_FREQUENCY; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_LOWPOWER_MEASUREMENT \n"); + break; + + case OPERATION_MODE_SUSPEND : + opf = 0x00; + TRI_KEY_ERR("opf = 0x%x\n", opf); + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OPF, &opf,1); + + //reset state machine + ret = ist8801_i2c_read_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + ifcntl |= 0x04; + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_IFCNTL, &ifcntl,1); + + opf = 0x02; + TRI_KEY_ERR("opf = 0x%x\n", opf); + //IST8801_REG_ACTION is 0x20 + ret = ist8801_i2c_write_block(ist8801_data, IST8801_REG_ACTION, &opf,1); + TRI_KEY_ERR("operation mode :OPERATION_MODE_SUSPEND \n"); + + //delay for 5 ms + usleep_range(5000,5000); + break; + } + + TRI_KEY_ERR("opf = 0x%x\n", opf); + + return ret; +} + + +/* functions for interrupt handler */ +static irqreturn_t ist8801_up_irq_handler(int irq, void *dev_id) +{ + TRI_KEY_LOG("call \n"); + + if (!g_ist8801_data) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + disable_irq_nosync(g_ist8801_data->irq); + __pm_wakeup_event(g_ist8801_data->source, 2000); + oneplus_hall_irq_handler(0); + + return IRQ_HANDLED; +} + +static int ist8801_setup_eint(ist8801_data_t *ist8801_data) +{ + int ret = 0; + + if (gpio_is_valid(ist8801_data->irq_gpio)) { + ret = gpio_request(ist8801_data->irq_gpio, "ist8801_up_irq"); + if (ret) { + TRI_KEY_LOG("unable to request gpio [%d]\n", ist8801_data->irq_gpio); + return -EINVAL; + } else { + ret = gpio_direction_input(ist8801_data->irq_gpio); + msleep(50); + ist8801_data->irq = gpio_to_irq(ist8801_data->irq_gpio); + } + } + TRI_KEY_ERR("GPIO %d irq:%d \n",ist8801_data->irq_gpio, ist8801_data->irq); + + return 0; +} + +static int ist8801_set_detection_mode(u8 mode) +{ + u8 data = 0; + int err = 0; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + TRI_KEY_LOG("ist8801 detection mode : %s\n", (mode == 0)? "POLLING":"INTERRUPT"); + + if(mode & DETECTION_MODE_INTERRUPT) { //interrupt mode + if (!g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs | IST8801_DETECTION_MODE_INTERRUPT; + err = ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + err = ist8801_clear_interrupt(g_ist8801_data); + if (err < 0) { + TRI_KEY_ERR("clear interupt fail %d \n",err); + return err; + } + + /* requst irq */ + if ((err = request_threaded_irq(g_ist8801_data->irq, NULL, + &ist8801_up_irq_handler, IRQ_TYPE_LEVEL_LOW | IRQF_ONESHOT, + "ist8801_up",(void *)g_ist8801_data->client)) < 0) { + TRI_KEY_ERR("IRQ LINE NOT AVAILABLE!!\n"); + return -EINVAL; + } + irq_set_irq_wake(g_ist8801_data->irq, 1); + + g_ist8801_data->irq_enabled = 1; + } + } else { // polling mode + if (g_ist8801_data->irq_enabled) { + data = g_ist8801_data->reg.map.intsrs & (0xFF - IST8801_DETECTION_MODE_INTERRUPT); + + err = ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_INTSRS, &data, 1); + if (err < 0) { + TRI_KEY_ERR("config interupt fail %d \n",err); + return err; + } + + disable_irq(g_ist8801_data->irq); + free_irq(g_ist8801_data->irq, NULL); + + g_ist8801_data->irq_enabled = 0; + } + } + + return 0; +} + +static int ist8801_enable_irq(bool enable) +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + if (enable) { + enable_irq(g_ist8801_data->irq); + } else { + disable_irq_nosync(g_ist8801_data->irq); + + } + return 0; +} + +static int ist8801_clear_irq() +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + ist8801_clear_interrupt(g_ist8801_data); + + return 0; +} + +static int ist8801_get_irq_state() +{ + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return -EINVAL; + } + + return ((g_ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) ? 1 : 0); +} + +static void ist8801_set_sensitivity(char *value) +{ + int i = 0; + uint8_t rwdata; + struct hall_srs *srs = NULL,*ist8801_ranges = NULL; + int len1 = 0,len2 = 0,len = 0; + uint8_t temp_opf,err; + + if (g_ist8801_data == NULL) { + TRI_KEY_LOG("g_ist8801_data NULL \n"); + return; + } + + + len1 = sizeof(ist8801_ranges_1)/sizeof(struct hall_srs); + len2 = sizeof(ist8801_ranges_2)/sizeof(struct hall_srs); + + if (0x01 == g_ist8801_data->origin_info) { + len = len1; + ist8801_ranges = ist8801_ranges_1; + } else { + len = len2; + ist8801_ranges = ist8801_ranges_2; + } + + for (i = 0; i < len; i++) { + srs = &ist8801_ranges[i]; + if (!strncmp(srs->name, value, strlen(srs->name))) + break; + else + srs = NULL; + } + + if (!srs) { + TRI_KEY_ERR("%s not match\n", value); + return; + } + //backup the data of IST8801_REG_OPF + temp_opf = 0x00; + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_OPF, &temp_opf,1); + + //write IST8801_REG_OPF to 0x00 + rwdata = 0x00; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); + + //reset state machine + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_IFCNTL, &rwdata,1); + rwdata |= 0x04; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_IFCNTL, &rwdata, 1); + + //Just change dynamic range and keep bit resolution + //(DYNAMIC_GAIN_ADC_BIT & 0x1E) -> clean up the dynamic field + // srs->value | (DYNAMIC_GAIN_ADC_BIT & 0x1E) -> update the dynamic field setting + rwdata = ((DYNAMIC_GAIN_ADC_BIT & 0x1E) | srs->value); + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("set sensitivity IST8801_REG_CNTL2 = 0x%x \n",rwdata); + + //check the IST8801_REG_CNTL2 data + rwdata = 0; + ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_CNTL2, &rwdata, 1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_CNTL2 = 0x%x \n",rwdata); + + //compensate reg 0x54 + rwdata = ((uint8_t) srs->ratio) + g_ist8801_data->origin_gain; + TRI_KEY_LOG("set sensitivity IST8801_REG_GAINCNTL = %d \n",rwdata); + + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_GAINCNTL, &rwdata, 1); + + //check data is correct + rwdata = 0; + err = ist8801_i2c_read_block(g_ist8801_data, IST8801_REG_GAINCNTL, &rwdata,1); + + TRI_KEY_LOG("get sensitivity IST8801_REG_GAINCNTL = %d \n",rwdata); + + //recovery IST8801_REG_OPF + rwdata = temp_opf; + ist8801_i2c_write_block(g_ist8801_data, IST8801_REG_OPF, &rwdata, 1); +} +/* +IST8801_ADC_BIT_NUM +8-bit:0x10 +9-bit:0x0e +10-bit:0x0c +11-bit:0x0a +12-bit:0x08 +13-bit:0x06 +14-bit:0x04 +15-bit:0x02 +16-bit: other +*/ +static int ist8801_reset_device(ist8801_data_t *ist8801_data) +{ + int err = 0; + u8 data =0; + + data = IST8801_VAL_SRST_RESET; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_SRST, &data,1); + + if (err < 0) { + TRI_KEY_ERR("sw-reset failed(%d)", err); + return err; + } + msleep(20); // wait 20ms + + err = ist8801_i2c_read_block(ist8801_data, IST8801_REG_DID, &data,1); + if (err < 0) { + TRI_KEY_ERR("read IST8801_REG_DID failed(%d)", err); + return err; + } + if (data!= IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02X) is not IST8801 device id(0x%02X)",data,IST8801_VAL_DID); + // TODO: unitl DID defined + //return -ENXIO; + } + + //Disable TST PAD voltage + data = 0x04; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_TSTCNTL, &data,1); + + //Setting osr data = 4 + data = 0x05; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_OSRCNTL, &data,1); + + //backup the gain data + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_GAINCNTL, &data,1); + ist8801_data->origin_gain = data; + + TRI_KEY_LOG("ist8801_data->origin_gain = %d \n",ist8801_data->origin_gain); + + //backup the osr data + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_OSRCNTL, &data,1); + ist8801_data->origin_osr = data; + + TRI_KEY_LOG("ist8801_data->origin_osr = %d \n",ist8801_data->origin_osr); + + //backup the info data + data = 0x00; + ist8801_i2c_read_block(ist8801_data, IST8801_REG_INFO, &data,1); + ist8801_data->origin_info = data; + + TRI_KEY_LOG("ist8801_data->origin_info = %d \n",ist8801_data->origin_info); + + ist8801_data->reg.map.persint = IST8801_PERSISTENCE_COUNT; + data = ist8801_data->reg.map.persint; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_PERSINT, &data,1); + + + ist8801_data->reg.map.intsrs = IST8801_DETECTION_MODE | ist8801_data->reg.map.range; + if (ist8801_data->reg.map.intsrs & IST8801_DETECTION_MODE_INTERRUPT) { + ist8801_data->reg.map.intsrs |= IST8801_INTERRUPT_TYPE; + } + + data = ist8801_data->reg.map.intsrs; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_INTSRS, &data,1); + +#if DISABLE_TEMP_CONPEN + data = 0x01; + err = ist8801_i2c_write_block(ist8801_data, IST8801_REG_CHIP_TEST, &data,1); + if (err < 0) { + TRI_KEY_ERR("IST8801_REG_CHIP_TEST failed(%d)", err); + return err; + } +#endif + err = ist8801_set_operation_mode(ist8801_data, OPERATION_MODE_MEASUREMENT); + if (err < 0) { + TRI_KEY_ERR("ist8801_set_operation_mode was failed(%d)", err); + return err; + } + + return err; +} + +static int ist8801_parse_dts(struct device *dev, ist8801_data_t *p_data) +{ + struct device_node *np = dev->of_node; + int rc = 0; + uint32_t data_range; + uint32_t value; + +// of_property_read_u32(np,"dhall,id",&p_data->id); +/* + p_data->power_gpio = of_get_named_gpio(np, "qcom,hall-power-gpio", 0); + if (!gpio_is_valid(p_data->power_gpio)) { + MOTOR_LOG("qcom,hall-power-gpio gpio not specified\n"); + } else { + rc = gpio_request(p_data->power_gpio, "hall-power-gpio"); + if (rc) { + MOTOR_LOG("request hall-power gpio failed, rc=%d\n",rc); + goto err; + } + } +*/ + rc = of_property_read_u32(np, "data-range", &data_range); + if (rc) { + p_data->reg.map.range = IST8801_SENSITIVITY_TYPE; + TRI_KEY_LOG("data-range is not specified, use default value:0x%x\n", p_data->reg.map.range); + } else { + p_data->reg.map.range = (uint8_t)data_range; + TRI_KEY_LOG("data-range is 0x%x\n", p_data->reg.map.range); + } + + p_data->irq_gpio = of_get_named_gpio(np, "dhall,irq-gpio", 0); + + p_data->power_2v8 = regulator_get(&p_data->client->dev, "vdd"); + if (IS_ERR_OR_NULL(p_data->power_2v8)) { + TRI_KEY_ERR("Regulator get failed vdd_2v8\n"); + goto err; + } + + p_data->power_1v8 = regulator_get(&p_data->client->dev, "vio"); + if (IS_ERR_OR_NULL(p_data->power_1v8)) { + TRI_KEY_ERR("Regulator get failed vcc_1v8\n"); + goto err; + } + + p_data->pctrl = devm_pinctrl_get(&p_data->client->dev); + if (IS_ERR_OR_NULL(p_data->pctrl)) { + TRI_KEY_ERR("failed to get pinctrl\n"); + goto err; + } + + p_data->irq_state = pinctrl_lookup_state(p_data->pctrl, "ist8801_hall_up_active"); + if (IS_ERR_OR_NULL(p_data->irq_state)) { + rc = PTR_ERR(p_data->irq_state); + TRI_KEY_ERR("pinctrl_lookup_state, err:%d\n", rc); + goto err; + } else { + pinctrl_select_state(p_data->pctrl,p_data->irq_state); + } + + p_data->enable_hidden = of_property_read_bool(np, "hall,bias_support"); + if (p_data->enable_hidden) { + rc = of_property_read_u32(np, "hall,bias-ratio", &value); + if (rc) { + p_data->bias_ratio = 100; + } else { + p_data->bias_ratio = value; + } + } + return 0; +err: + return rc; +}; + +struct dhall_operations ist8801_up_ops = { + .get_data = ist8801_get_data, + .enable_irq = ist8801_enable_irq, + .clear_irq = ist8801_clear_irq, + .get_irq_state = ist8801_get_irq_state, + .set_detection_mode = ist8801_set_detection_mode, + .update_threshold = ist8801_up_update_threshold, + .dump_regs = ist8801_dump_reg, + .set_reg = ist8801_set_reg, + .is_power_on = ist8801_is_power_on, + .set_sensitivity = ist8801_set_sensitivity, + +}; + +static int ist8801_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + ist8801_data_t *p_data = NULL; + u8 dev_id = 0xFF; + int err = 0; +// client->addr = 0x0C; + TRI_KEY_LOG("call \n"); + + p_data = devm_kzalloc(&client->dev,sizeof(ist8801_data_t), GFP_KERNEL); + if (!p_data) { + TRI_KEY_ERR("kernel memory alocation was failed \n"); + return -ENOMEM; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + TRI_KEY_LOG("i2c unsupported\n"); + return -EOPNOTSUPP; + } + i2c_set_clientdata(client, p_data); + p_data->client = client; + g_ist8801_data = p_data; + if (client->dev.of_node) { + err = ist8801_parse_dts(&client->dev, p_data); + if (err) { + TRI_KEY_ERR("failed to parse device tree\n"); + } + } + ist8801_reconfig(p_data); + + err = ist8801_set_power(p_data,1); + + dev_id = ist8801_get_id(p_data); + if (dev_id != IST8801_VAL_DID) { + TRI_KEY_ERR("current device id(0x%02x) is not ist8801 device id(0x%02x) \n", dev_id, IST8801_VAL_DID); + goto fail; + } + + err = ist8801_reset_device(p_data); + if (err < 0) { + TRI_KEY_ERR("ist8801_reset_device fail \n"); + goto fail; + } + + err = ist8801_setup_eint(p_data); + + oneplus_register_hall("hall_up",&ist8801_up_ops); + g_ist8801_data->source = wakeup_source_register(&client->dev, "hall_up"); + + ist8801_set_sensitivity("40mT"); + + TRI_KEY_LOG("success. \n"); + return 0; +fail: + TRI_KEY_LOG("fail. \n"); + if (gpio_is_valid(p_data->irq_gpio)) + gpio_free(p_data->irq_gpio); + + devm_kfree(&client->dev,p_data); + return -ENXIO; +} + +static int ist8801_i2c_remove(struct i2c_client *client) +{ + return 0; +} +/* +static int ist8801_i2c_suspend(struct device *dev) +{ + int ret = 0 ; + + if (g_ist8801_data != NULL ) + ret = ist8801_set_operation_mode(g_ist8801_data,OPERATION_MODE_LOWPOWER_MEASUREMENT); + + return 0; +} + +static int ist8801_i2c_resume(struct device *dev) +{ + int ret = 0 ; + + if (g_ist8801_data != NULL ) + ret = ist8801_set_operation_mode(g_ist8801_data,OPERATION_MODE_MEASUREMENT); + + return 0; +} +*/ +static const struct of_device_id ist8801_match[] = { + { .compatible = "oneplus,hall-ist8801,up"}, + {}, +}; + +static const struct i2c_device_id ist8801_id[] = { + {"hall_ist8801_up", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, ist8801_id); +/* +static const struct dev_pm_ops ist8801_pm_ops = { + //.suspend = ist8801_i2c_suspend, + //.resume = ist8801_i2c_resume, +}; +*/ +static struct i2c_driver ist8801_i2c_up_driver = { + .driver = { + .name = "hall-ist8801-up", + .of_match_table = ist8801_match, + //.pm = &ist8801_pm_ops, + }, + .probe = ist8801_i2c_probe, + .remove = ist8801_i2c_remove, + .id_table = ist8801_id, +}; + +static int __init ist8801_up_init(void) +{ + TRI_KEY_LOG("call\n"); + i2c_add_driver(&ist8801_i2c_up_driver); + return 0; +} +module_init(ist8801_up_init); + +static void __exit ist8801_up_exit(void) +{ + TRI_KEY_LOG("call\n"); + i2c_del_driver(&ist8801_i2c_up_driver); +} + +module_exit(ist8801_up_exit); + +MODULE_DESCRIPTION("ist8801 hallswitch driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/oneplus/tri_state_key/oneplus_tri_key.c b/drivers/oneplus/tri_state_key/oneplus_tri_key.c new file mode 100755 index 0000000000000000000000000000000000000000..2a1f80ba9d9f8f0a97ac9f4681c7d3566ed53009 --- /dev/null +++ b/drivers/oneplus/tri_state_key/oneplus_tri_key.c @@ -0,0 +1,1450 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, Oneplus Mobile Comm Corp., Ltd +** File: oneplus_tri_key.c +** +** Description: +** Definitions for m1120 tri_state_key data process. +** +** Version: 1.0 +**************************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) +#include +#endif +#include "oneplus_tri_key.h" +#include "../../extcon/extcon.h" +#define TRI_KEY_TAG "[tri_state_key] " +#define TRI_KEY_ERR(fmt, args...) printk(KERN_ERR TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_LOG(fmt, args...) printk(KERN_INFO TRI_KEY_TAG" %s : "fmt, __FUNCTION__, ##args) +#define TRI_KEY_DEBUG(fmt, args...)\ + do{\ + if (LEVEL_DEBUG == tri_key_debug)\ + printk(KERN_INFO TRI_KEY_TAG " %s: " fmt, __FUNCTION__, ##args);\ + }while(0) +enum { + MODE_UNKNOWN, + MODE_MUTE, + MODE_DO_NOT_DISTURB, + MODE_NORMAL, + MODE_MAX_NUM + } tri_mode; + + +unsigned int tristate_extcon_tab[] = { + MODE_MUTE, + MODE_DO_NOT_DISTURB, + MODE_NORMAL, + }; + +static struct hrtimer tri_key_timer; +struct work_struct tri_key_timeout_work; + +static BLOCKING_NOTIFIER_HEAD(tp_delta_print_chain); + +static struct extcon_dev_data *g_the_chip = NULL; +static int last_d0 = 0; +static int last_d1 = 0; +static int last_position = -1; +static int last_interf = -1; +static int interf_count; +static int time = 1; +unsigned int tri_key_debug = 0; +//static int up_buf[20] = {0}; +//static int down_buf[20] = {0}; + +static short tol0 = 15; +static short tol1 = 15; +static short tol2 = 22; +static short up_mid_tol = 15; +static short up_tolerance = 15; +static short down_tolerance = 15; +static short mid_down_tol = 15; +static float position_distance_degree = 0.2; +static float position_degree = 0.4; +static float side_position_degree = 1.1; +static short up_mid_distance = 0; +static short mid_down_distance = 0; +static short calib_UpValueSum = 0, calib_MdValueSum = 0, calib_DnValueSum = 0; +static short calib_UpValueMin = 0, calib_MdValueMin = 0, calib_DnValueMin = 0; +static short calib_dnHall_UM_distance = 0, calib_dnHall_MD_distance = 0; +static short calib_upHall_UM_distance = 0, calib_upHall_MD_distance = 0; +static short calib_upHall_UD_distance = 0, calib_dnHall_UD_distance = 0; + +static int tp_delta_print_notifier_call_chain(unsigned long val); + +int register_tp_delta_print_notifier(struct notifier_block *nb) +{ + if (!nb) + return -EINVAL; + + return blocking_notifier_chain_register(&tp_delta_print_chain, nb); +} +EXPORT_SYMBOL(register_tp_delta_print_notifier); + +int unregister_tp_delta_print_notifier(struct notifier_block *nb) +{ + if (!nb) + return -EINVAL; + + return blocking_notifier_chain_unregister(&tp_delta_print_chain, nb); +} +EXPORT_SYMBOL(unregister_tp_delta_print_notifier); + +static int tp_delta_print_notifier_call_chain(unsigned long val) +{ + return blocking_notifier_call_chain(&tp_delta_print_chain, val, NULL); +} + +int oneplus_register_hall(const char *name, struct dhall_operations *ops) +{ + if (!name || !ops) { + TRI_KEY_ERR("name is NULL or ops is NULL, would not register digital hall \n"); + return -EINVAL; + } + + if (!g_the_chip) { + struct extcon_dev_data *chip = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!chip) { + TRI_KEY_ERR("kzalloc err \n"); + return -ENOMEM; + } + g_the_chip = chip; + } + TRI_KEY_LOG("name : %s\n", name); + if (strcmp(name, "hall_down") == 0) { + TRI_KEY_LOG("name == hall_down"); + if (!g_the_chip->dhall_down_ops) { + if (ops) { + g_the_chip->dhall_down_ops = ops; + g_the_chip->d_name = name; + } else { + TRI_KEY_ERR("dhall_down_ops NULL \n"); + return -EINVAL; + } + } else { + TRI_KEY_ERR("dhall_down_ops has been register \n"); + return -EINVAL; + } + } + if (strcmp(name, "hall_up") == 0) { + TRI_KEY_LOG("name == hall_up"); + if (!g_the_chip->dhall_up_ops) { + if (ops) { + g_the_chip->dhall_up_ops = ops; + g_the_chip->d_name = name; + } else { + TRI_KEY_ERR("dhall_up_ops NULL \n"); + return -EINVAL; + } + } else { + TRI_KEY_ERR("dhall_up_ops has been register \n"); + return -EINVAL; + } + } + + return 0; +} + +void oneplus_hall_disable_irq(bool enable) +{ + oneplus_hall_clear_irq(DHALL_0); + oneplus_hall_clear_irq(DHALL_1); + + g_the_chip->dhall_down_ops->enable_irq(enable); + g_the_chip->dhall_up_ops->enable_irq(enable); +} + +int oneplus_hall_enable_irq (unsigned int id, bool enable) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->enable_irq) { + return -EINVAL; + } else { + oneplus_hall_clear_irq(DHALL_0); + oneplus_hall_clear_irq(DHALL_1); + return g_the_chip->dhall_down_ops->enable_irq(enable); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->enable_irq) { + return -EINVAL; + } else { + oneplus_hall_clear_irq(DHALL_0); + oneplus_hall_clear_irq(DHALL_1); + return g_the_chip->dhall_up_ops->enable_irq(enable); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oneplus_hall_clear_irq (unsigned int id) +{ + if (!g_the_chip) + return -EINVAL; + + TRI_KEY_DEBUG("dhall_clear_irq\n"); + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->enable_irq) { + return -EINVAL; + } else { + return g_the_chip->dhall_down_ops->clear_irq(); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->enable_irq) { + return -EINVAL; + } else { + return g_the_chip->dhall_up_ops->clear_irq(); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + + return -EINVAL; +} + +int oneplus_hall_get_data(unsigned int id) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->get_data) { + return -EINVAL; + } else { + return g_the_chip->dhall_down_ops->get_data(&g_the_chip->dhall_data0); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->get_data) { + return -EINVAL; + } else { + return g_the_chip->dhall_up_ops->get_data(&g_the_chip->dhall_data1); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + +} + +bool oneplus_hall_update_threshold(unsigned int id, int position, short lowthd, short highthd) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->update_threshold) { + return false; + } else { + return g_the_chip->dhall_down_ops->update_threshold(position, lowthd, highthd); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->update_threshold) { + return false; + } else { + return g_the_chip->dhall_up_ops->update_threshold(position, lowthd, highthd); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + +} + +int oneplus_hall_set_detection_mode(unsigned int id, u8 mode) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->set_detection_mode) { + return -EINVAL; + } else { + return g_the_chip->dhall_down_ops->set_detection_mode(mode); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->set_detection_mode) { + return -EINVAL; + } else { + return g_the_chip->dhall_up_ops->set_detection_mode(mode); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + +} + +int oneplus_hall_get_irq_state(unsigned int id) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->get_irq_state) { + return -EINVAL; + } else { + return g_the_chip->dhall_down_ops->get_irq_state(); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->get_irq_state) { + return -EINVAL; + } else { + return g_the_chip->dhall_up_ops->get_irq_state(); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + +} + + + +void oneplus_hall_dump_regs(unsigned int id, u8 *buf) +{ + if (!g_the_chip) + return; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->dump_regs) { + return; + } else { + g_the_chip->dhall_down_ops->dump_regs(buf); + } + break; + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->dump_regs) { + return; + } else { + g_the_chip->dhall_up_ops->dump_regs(buf); + } + break; + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return; + } +} + +int oneplus_hall_set_reg(unsigned int id, int reg, int val) +{ + if (!g_the_chip) + return -EINVAL; + + switch (id) { + case DHALL_0: + if (!g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->set_reg) { + return -EINVAL; + } else { + return g_the_chip->dhall_down_ops->set_reg(reg, val); + } + case DHALL_1: + if (!g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->set_reg) { + return -EINVAL; + } else { + return g_the_chip->dhall_up_ops->set_reg(reg, val); + } + default: + TRI_KEY_ERR("id : %d is not correct\n", id); + return -EINVAL; + } + +} + +bool oneplus_hall_is_power_on(void) +{ + if (!g_the_chip || !g_the_chip->dhall_down_ops || !g_the_chip->dhall_down_ops->is_power_on + || !g_the_chip->dhall_up_ops || !g_the_chip->dhall_up_ops->is_power_on) { + return false; + } else { + if (g_the_chip->dhall_down_ops->is_power_on() || g_the_chip->dhall_up_ops->is_power_on()) + return true; + else + return false; + } + +} +static void reboot_get_position(struct extcon_dev_data *chip) +{ + short delta; + short up_data1; + short down_data1; + if (chip->dhall_data1 < 0 || chip->dhall_data0 < 0) { + up_data1 = -chip->dhall_data1; + down_data1 = -chip->dhall_data0; + delta = up_data1 - down_data1; + } else + delta = chip->dhall_data1 - chip->dhall_data0; + if (delta > 30) + chip->position = UP_STATE; + else if (-delta > 30) + chip->position = DOWN_STATE; + else + chip->position = MID_STATE; + last_position = chip->position; +} + +static int interf_get_position(struct extcon_dev_data *chip) +{ + short delta0; + short delta1; + delta0 = chip->dhall_data0 - last_d0; + delta1 = chip->dhall_data1 - last_d1; + TRI_KEY_LOG("tri_key: delta0 is %d ,delta1 is %d,last_postion is %d\n", + delta0, delta1, last_position); + if ((delta1 > calib_upHall_UM_distance - tol0 && + delta1 < calib_upHall_UM_distance + tol0) && + (delta0 > calib_dnHall_UM_distance - tol0 && + delta0 < calib_dnHall_UM_distance + tol0)) { + if (last_position == MID_STATE) + return UP_STATE; + } + if ((delta1 > calib_upHall_UD_distance - tol0 && + delta1 < calib_upHall_UD_distance + tol0) && + (delta0 > calib_dnHall_UD_distance - tol0 && + delta0 < calib_dnHall_UD_distance + tol0)) + return UP_STATE; + if ((delta1 > -calib_upHall_MD_distance - tol0 && + delta1 < -calib_upHall_MD_distance + tol0) && + (delta0 > -calib_dnHall_MD_distance - tol0 && + delta0 < -calib_dnHall_MD_distance + tol0)) { + if (last_position == MID_STATE) + return DOWN_STATE; + } + if ((delta1 > -calib_upHall_UD_distance - tol0 && + delta1 < -calib_upHall_UD_distance + tol0) && + (delta0 > -calib_dnHall_UD_distance - tol0 && + delta0 < -calib_dnHall_UD_distance + tol0)) + return DOWN_STATE; + if ((delta1 > -calib_upHall_UM_distance - tol0 && + delta1 < -calib_upHall_UM_distance + tol0) && + (delta0 > -calib_dnHall_UM_distance - tol0 && + delta0 < -calib_dnHall_UM_distance + tol0)) { + if (last_position == UP_STATE) + return MID_STATE; + } + if ((delta1 > calib_upHall_MD_distance - tol0 && + delta1 < calib_upHall_MD_distance + tol0) && + (delta0 > calib_dnHall_MD_distance - tol0 && + delta0 < calib_dnHall_MD_distance + tol0)) { + if (last_position == DOWN_STATE) + return MID_STATE; + } + return -EINVAL; + +} + +static int get_position(struct extcon_dev_data *chip) +{ + short diff; + diff = chip->dhall_data1 - chip->dhall_data0; + if (chip->dhall_data0 > 0) { + if (diff > calib_UpValueMin - up_mid_tol && diff < calib_UpValueMin + up_tolerance) + chip->position = UP_STATE; + if (calib_MdValueMin < 0) { + if (diff > calib_MdValueMin - mid_down_tol && diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (diff > calib_MdValueMin - mid_down_tol && diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (diff > calib_DnValueMin - down_tolerance && diff < calib_DnValueMin + mid_down_tol) + chip->position = DOWN_STATE; + } else { + if (diff > calib_UpValueMin - up_tolerance && diff < calib_UpValueMin + up_mid_tol) + chip->position = UP_STATE; + if (calib_MdValueMin < 0) { + if (diff > calib_MdValueMin - mid_down_tol && diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (diff > calib_MdValueMin - mid_down_tol && diff < calib_MdValueMin + up_mid_tol) + chip->position = MID_STATE; + } + if (diff > calib_DnValueMin - mid_down_tol && diff < calib_DnValueMin + down_tolerance) + chip->position = DOWN_STATE; + } + return 0; +} + +static int judge_interference(struct extcon_dev_data *chip) +{ + short delta; + short sum; + + delta = chip->dhall_data1 - chip->dhall_data0; + TRI_KEY_LOG("tri_key:delta is %d\n", delta); + sum = chip->dhall_data0 + chip->dhall_data1; + TRI_KEY_LOG("tri_key:sum is %d\n", sum); + if (chip->dhall_data1 > 0) {//the hall data is positive number + if (delta > calib_UpValueMin - up_mid_tol && delta < calib_UpValueMin + up_tolerance) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_UpValueMin, calib_UpValueSum); + if (sum < calib_UpValueSum - tol2 || sum > calib_UpValueSum + tol2) { + chip->interf = 1; + chip->state = 1; + } else { + chip->interf = 0; + chip->state = 1; + } + return 0; + } + if (calib_MdValueMin < 0) { + if (delta > calib_MdValueMin - mid_down_tol && delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("tri_key:calibMin:%d,calib_Sum:%d\n", calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (delta > calib_MdValueMin - mid_down_tol && delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (delta > calib_DnValueMin - down_tolerance && delta < calib_DnValueMin + up_mid_tol) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_DnValueMin, calib_DnValueSum); + + if (sum < calib_DnValueSum - tol2 || sum > calib_DnValueSum + tol2) { + chip->interf = 1; + chip->state = 3; + } else { + chip->interf = 0; + chip->state = 3; + } + return 0; + } + chip->interf = 1; + chip->state = 0; + } else {//the hall data is negative number + if (delta > calib_UpValueMin - up_tolerance && delta < calib_UpValueMin + up_mid_tol) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_UpValueMin, calib_UpValueSum); + + if (sum < calib_UpValueSum - tol2 || sum > calib_UpValueSum + tol2) { + chip->interf = 1; + chip->state = 1; + } else { + chip->interf = 0; + chip->state = 1; + } + return 0; + } + if (calib_MdValueMin < 0) { + if (delta > calib_MdValueMin - mid_down_tol && delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (calib_MdValueMin > 0 || calib_MdValueMin == 0) { + if (delta > calib_MdValueMin - mid_down_tol && delta < calib_MdValueMin + up_mid_tol) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_MdValueMin, calib_MdValueSum); + + if (sum > calib_MdValueSum + tol2 || sum < calib_MdValueSum - tol2) { + chip->interf = 1; + chip->state = 2; + } else { + chip->interf = 0; + chip->state = 2; + } + return 0; + } + } + if (delta > calib_DnValueMin - mid_down_tol && delta < calib_DnValueMin + down_tolerance) { + TRI_KEY_LOG("tri_key:calib_Min:%d,calib_Sum:%d\n", calib_DnValueMin, calib_DnValueSum); + + if (sum < calib_DnValueSum - tol2 || sum > calib_DnValueSum + tol2) { + chip->interf = 1; + chip->state = 3; + } else { + chip->interf = 0; + chip->state = 3; + } + return 0; + } + chip->interf = 1; + chip->state = 0; + } + return -EINVAL; + +} + + +static int oneplus_get_data(struct extcon_dev_data *chip) +{ + int res = 0; + + res = oneplus_hall_get_data(DHALL_0); + if (res < 0) + TRI_KEY_LOG("tri_key:get DHALL_0 data failed,res =%d\n", res); + res = oneplus_hall_get_data(DHALL_1); + if (res < 0) { + TRI_KEY_LOG("tri_key:get DHALL_1 data failed,res =%d\n", res); + } + + return res; +} + +static int reupdata_threshold(struct extcon_dev_data *chip) +{ + int res = 0; + int tolen = 22; + switch (chip->position) { + case UP_STATE: + res = oneplus_hall_update_threshold(DHALL_1, UP_STATE, + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + res = oneplus_hall_update_threshold(DHALL_0, UP_STATE, + -500, 500); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold up:low:%d,high: %d\n", + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + oneplus_hall_clear_irq(DHALL_1); + oneplus_hall_clear_irq(DHALL_0); + break; + case MID_STATE: + if (chip->dhall_data0 < 0 || chip->dhall_data1 < 0) { + res = oneplus_hall_update_threshold(DHALL_1, MID_STATE, + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold up:low:%d,high:%d\n", + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + } else { + res = oneplus_hall_update_threshold(DHALL_1, MID_STATE, + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold up:low:%d,high:%d\n", + chip->dhall_data1-tolen, chip->dhall_data1+tolen); + } + oneplus_hall_clear_irq(DHALL_1); + if (chip->dhall_data0 < 0 || chip->dhall_data1 < 0) { + res = oneplus_hall_update_threshold(DHALL_0, MID_STATE, + chip->dhall_data0-tolen, chip->dhall_data0+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold down:low:%d,high:%d\n", + chip->dhall_data0-tolen, chip->dhall_data0+tolen); + } else { + res = oneplus_hall_update_threshold(DHALL_0, MID_STATE, + chip->dhall_data0-tolen, chip->dhall_data0+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold down:low:%d,high:%d\n", + chip->dhall_data0-tolen, chip->dhall_data0+tolen); + } + oneplus_hall_clear_irq(DHALL_0); + break; + case DOWN_STATE: + res = oneplus_hall_update_threshold(DHALL_0, DOWN_STATE, + chip->dhall_data0-tolen, chip->dhall_data0+tolen); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + TRI_KEY_LOG("tri_key:updata_threshold down:low:%d,high:%d\n", + chip->dhall_data0-tolen, chip->dhall_data0+tolen); + res = oneplus_hall_update_threshold(DHALL_1, DOWN_STATE, + -500, 500); + if (res < 0) { + TRI_KEY_LOG("updata_threshold fail:%d\n", res); + goto fail; + } + + oneplus_hall_clear_irq(DHALL_0); + oneplus_hall_clear_irq(DHALL_1); + break; + } +fail: + last_d0 = chip->dhall_data0; + last_d1 = chip->dhall_data1; + last_interf = chip->interf; + TRI_KEY_LOG("tri_key:last_d0 is %d ,last_d1 is %d\n", last_d0, last_d1); + oneplus_hall_clear_irq(DHALL_0); + oneplus_hall_clear_irq(DHALL_1); + return res; +} + +static void report_key_value(struct extcon_dev_data *chip) +{ + tp_delta_print_notifier_call_chain(1); + + if (chip->position == DOWN_STATE) { + extcon_set_state_sync(chip->edev, 1, 0); + extcon_set_state_sync(chip->edev, 2, 1); + extcon_set_state_sync(chip->edev, 3, 1); + chip->state = 3; + TRI_KEY_LOG("tri_key: report down key successful!\n"); + } + if (chip->position == UP_STATE) { //near up hall + extcon_set_state_sync(chip->edev, 1, 1); + extcon_set_state_sync(chip->edev, 2, 1); + extcon_set_state_sync(chip->edev, 3, 0); + chip->state = 1; + TRI_KEY_LOG("tri_key: report up key successful!\n"); + } + if (chip->position == MID_STATE) { + extcon_set_state_sync(chip->edev, 1, 1); + extcon_set_state_sync(chip->edev, 2, 0); + extcon_set_state_sync(chip->edev, 3, 1); + chip->state = 2; + TRI_KEY_LOG("tri_key: report mid key successful!\n"); + } else + TRI_KEY_LOG("no report\n"); +} + +static int report_calibration_location(struct extcon_dev_data *chip) +{ + oneplus_get_data(chip); + get_position(chip); + reupdata_threshold(chip); + if (chip->position == last_position) { + TRI_KEY_LOG("no report\n"); + goto err; + } else + report_key_value(chip); + last_position = chip->position; + return 0; +err: + return -EINVAL; +} + +static int judge_calibration_data(struct extcon_dev_data *chip) +{ + if (calib_UpValueMin == 0 || calib_UpValueSum == 0 || + calib_MdValueSum == 0 || calib_DnValueMin == 0 || calib_DnValueSum == 0) { + oneplus_get_data(chip); + reboot_get_position(chip); + if (chip->position == UP_STATE) { + calib_UpValueMin = chip->dhall_data1 - chip->dhall_data0; + calib_UpValueSum = chip->dhall_data1 + chip->dhall_data0; + TRI_KEY_LOG("UP_MIN is%d,UP_SUM is %d\n", calib_UpValueMin, calib_UpValueSum); + } + if (chip->position == MID_STATE){ + calib_MdValueMin = chip->dhall_data1 - chip->dhall_data0; + calib_MdValueSum = chip->dhall_data1 + chip->dhall_data0; + TRI_KEY_LOG("MID_MIN is%d,MID_SUM is %d\n", calib_MdValueMin, calib_MdValueSum); + } + if (chip->position == DOWN_STATE){ + calib_DnValueMin = chip->dhall_data1 - chip->dhall_data0; + calib_DnValueSum = chip->dhall_data1 + chip->dhall_data0; + TRI_KEY_LOG("UP_MIN is%d,UP_SUM is %d\n", calib_DnValueMin, calib_DnValueSum); + } + report_key_value(chip); + reupdata_threshold(chip); + return -1; + } + return 0; +} + + +//note:work in irq context +int oneplus_hall_irq_handler(unsigned int id) +{ + TRI_KEY_LOG("%d tri_key:call :%s\n", id, __func__); + if (!g_the_chip) { + TRI_KEY_LOG("g_the_chip null\n "); + return -EINVAL; + } else { + schedule_work(&g_the_chip->dwork); + } + return IRQ_HANDLED; +} + + +static void tri_key_dev_work(struct work_struct *work) +{ + struct extcon_dev_data *chip = container_of(work, + struct extcon_dev_data, dwork); + int res = 0; + int position = -1; + int diff0 = 0; + int diff1 = 0; + int count = 0; + int dhall0_sum = 0; + int dhall1_sum = 0; + int aver0 = 0; + int aver1 = 0; + ktime_t starttime, endtime; + u64 usecs64; + int usecs; + + mutex_lock(&chip->mtx); +//disable irq first +// oneplus_hall_disable_irq(0); + + starttime = ktime_get(); + msleep(50); + res = judge_calibration_data(chip); + if (res < 0) + goto FINAL; + +//get data + res = oneplus_get_data(chip); + if (res < 0) { + TRI_KEY_LOG("tri_key:get hall data failed!\n"); + goto fail; + } + TRI_KEY_LOG("tri_key:data1 is %d, data0 is %d\n", + chip->dhall_data1, chip->dhall_data0); + +//judge interference + res = judge_interference(chip); + TRI_KEY_LOG("tri_key:chip->interf is %d ,chip->state is %d\n", + chip->interf, chip->state); + if (!last_interf && chip->interf) { + msleep(200); + oneplus_get_data(chip); + TRI_KEY_LOG("tri_key:data1 is %d, data0 is %d\n", + chip->dhall_data1, chip->dhall_data0); + + judge_interference(chip); + } +//get position + if (!chip->interf) { + hrtimer_cancel(&tri_key_timer); + time = 1; + if (!last_interf) { + interf_count = 0; + get_position(chip); + TRI_KEY_LOG("tri_key:the position is %d\n", chip->position); + } else { + msleep(150); + oneplus_get_data(chip); + judge_interference(chip); + if (chip->interf) + goto FINAL; + else + get_position(chip); + } + } + else { + hrtimer_cancel(&tri_key_timer); + TRI_KEY_LOG("tri_key:time0 is %d\n", time); + hrtimer_start(&tri_key_timer, ktime_set(time, 0), + HRTIMER_MODE_REL); + while (count < 4) { + msleep(35); + oneplus_hall_get_data(DHALL_0); + oneplus_hall_get_data(DHALL_1); + dhall0_sum += chip->dhall_data0; + dhall1_sum += chip->dhall_data1; + count++; + } + aver0 = dhall0_sum / 4; + aver1 = dhall1_sum / 4; + if (!last_interf) {//from no interference to constant interference + diff0 = aver0 - chip->dhall_data0; + diff1 = aver1 - chip->dhall_data1; + TRI_KEY_LOG("tri_key:diff0 is %d,diff1 is %d\n", + diff0, diff1); + if ((diff0 > -10 && diff0 < 10) && (diff1 > -10 && diff1 < 10)) { + chip->position = last_position; + goto UPDATA_HTRES; + } else {//inconstant interference + last_interf = chip->interf; + goto FINAL; + } + } + diff0 = aver0 - chip->dhall_data0; + diff1 = aver1 - chip->dhall_data1; + TRI_KEY_LOG("tri_key:diff0 is %d,diff1 is %d\n", + diff0, diff1); + +//inconstantly interference + if ((diff0 < -10 || diff0 > 10) && + (diff1 < -10 || diff1 > 10)) { + interf_count++; + if (interf_count == 15) { + TRI_KEY_LOG("tri_key:count = 15,msleep 5s\n"); + msleep(5000); + interf_count = 0; + goto FINAL; + } + TRI_KEY_LOG("tri_key:inconstantlt interference\n"); + //last_interf = chip->interf; + reupdata_threshold(chip); + goto FINAL; + } + + chip->dhall_data0 = aver0; + chip->dhall_data1 = aver1; + position = interf_get_position(chip); + if (position == -22) { + TRI_KEY_LOG("tri_key:get position failed\n"); + } + else + chip->position = position; + } + TRI_KEY_LOG("tri_key:t_diff0 is %d,t_diff1 is %d\n", + chip->dhall_data0 - last_d0, chip->dhall_data1 - last_d1); +//updata threshold +UPDATA_HTRES: + res = reupdata_threshold(chip); + if (res < 0) { + TRI_KEY_LOG("tri_key:updata_threshold failed!\n"); + goto fail; + } + +// report key value + if (chip->position == last_position) + goto FINAL; + else { + report_key_value(chip); + last_position = chip->position; + endtime = ktime_get(); + usecs64 = ktime_to_ns(ktime_sub(endtime, starttime)); + do_div(usecs64, NSEC_PER_USEC); + usecs = usecs64; + if (usecs == 0) + usecs = 1; + TRI_KEY_LOG("report key after %ld.%03ld msecs\n", + usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); + } +fail: + if (res < 0) + TRI_KEY_LOG("tri_key:dev_work failed,res =%d\n", res); +FINAL: + oneplus_hall_disable_irq(1);//enable irq + + TRI_KEY_LOG("%s achieve\n", __func__); + mutex_unlock(&chip->mtx); +} + +static ssize_t dhall_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + //int fb = -1; + //short hall_up_data[128] = {0}; + //short hall_down_data[128] = {0}; + //char hall_data_bufs[512] = {0}; + //char hall_data_buf[16] = {0}; + //int data_count = 0; + //int i = 0; + //int up_sum = 0; + //int down_sum = 0; + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + + oneplus_hall_get_data(DHALL_0); + oneplus_hall_get_data(DHALL_1); +//save hall data +/* hall_up_data[data_count] = g_the_chip->dhall_data0; + hall_down_data[data_count] = g_the_chip->dhall_data1; + data_count++; + fd = sys_open("/sdcard/trikey_hall_data.csv", O_WRONLY | O_CREAT | O_APPEND, 0); + if (fd < 0) { + MOTOR_ERR("open log file /sdcard/hall_data.csv failed.\n"); + } + if (fd >= 0) { +// if (g_the_chip->state) +// sys_write(fd, "1\n", 2); +// else //interference +// sys_write(fd, "0\n", 2); + for (i = 0; i < data_count; i++) { + memset(hall_data_buf, 0, sizeof(hall_data_buf)); + sprintf(hall_data_buf, "%d, ", hall_up_data[i]); + strcat(hall_data_bufs, hall_data_buf); + } + strcat(hall_data_bufs, "\n"); + sys_write(fd, hall_data_bufs, strlen(hall_data_bufs)); + memset(hall_data_bufs, 0 , sizeof(hall_data_bufs)); + + for (i = 0; i < data_count; i++) { + memset(hall_data_buf, 0, sizeof(hall_data_buf)); + sprintf(hall_data_buf, "%d,", hall_down_data[i]); + strcat(hall_data_bufs, hall_data_buf); + } + strcat(hall_data_bufs, "\n"); + sys_write(fd, hall_data_bufs, strlen(hall_data_bufs)); + sys_write(fd, "\n", 1); + sys_close(fd); + } +*/ + + return snprintf(buf, PAGE_SIZE, "%d, %d\n", + g_the_chip->dhall_data0, g_the_chip->dhall_data1); +} + + +static ssize_t tri_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + //int position =-1; + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + return snprintf(buf, PAGE_SIZE, "%d\n", 0); + } + oneplus_hall_get_data(DHALL_0); + oneplus_hall_get_data(DHALL_1); +// judge_interference(g_the_chip); + //position = get_position(g_the_chip); + + return snprintf(buf, PAGE_SIZE, "%d\n", g_the_chip->state); +} + +static enum hrtimer_restart tri_key_status_timeout(struct hrtimer *timer) +{ + schedule_work(&tri_key_timeout_work); + return HRTIMER_NORESTART; +} + +static void tri_key_timeout_work_func(struct work_struct *work) +{ + oneplus_get_data(g_the_chip); + judge_interference(g_the_chip); + if (g_the_chip->interf) { + time = time * 2; + TRI_KEY_LOG("tri_key:time1 is %d\n", time); + if (time > 2) + time = 2; + } + else { + get_position(g_the_chip); + if (g_the_chip->position == last_position) + return; + reupdata_threshold(g_the_chip); + report_key_value(g_the_chip); + last_position = g_the_chip->position; + time = 1; + } + return; +} + + +static short Sum(short value0, short value1) +{ + short sum = 0; + sum = value0 + value1; + return sum; +} +static short Minus(short value0, short value1) +{ + short minus = 0; + minus = value0 - value1; + return minus; +} + +void initialCalibValue(short calib_dnHall_UpV, short calib_dnHall_MdV, + short calib_dnHall_DnV, short calib_upHall_UpV, + short calib_upHall_MdV, short calib_upHall_DnV) +{ + calib_UpValueSum = Sum(calib_dnHall_UpV,calib_upHall_UpV); + calib_MdValueSum = Sum(calib_dnHall_MdV,calib_upHall_MdV); + calib_DnValueSum = Sum(calib_dnHall_DnV,calib_upHall_DnV); + calib_UpValueMin = Minus(calib_upHall_UpV,calib_dnHall_UpV); + calib_MdValueMin = Minus(calib_upHall_MdV,calib_dnHall_MdV); + calib_DnValueMin = Minus(calib_upHall_DnV,calib_dnHall_DnV); + calib_upHall_UM_distance = Minus(calib_upHall_UpV, calib_upHall_MdV); + calib_upHall_MD_distance = Minus(calib_upHall_MdV, calib_upHall_DnV); + calib_dnHall_UM_distance = Minus(calib_dnHall_UpV, calib_dnHall_MdV); + calib_dnHall_MD_distance = Minus(calib_dnHall_MdV, calib_dnHall_DnV); + calib_upHall_UD_distance = Minus(calib_upHall_UpV, calib_upHall_DnV); + calib_dnHall_UD_distance = Minus(calib_dnHall_UpV, calib_dnHall_DnV); + if (g_the_chip->project_info){ + up_mid_tol = (short)(abs(calib_UpValueMin - calib_MdValueMin) * position_degree); + up_tolerance = (short)(abs(calib_UpValueMin - calib_MdValueMin) * side_position_degree); + mid_down_tol = (short)(abs(calib_MdValueMin - calib_DnValueMin) * position_degree); + down_tolerance = (short)(abs(calib_MdValueMin - calib_DnValueMin) * side_position_degree); + up_mid_distance = (short)(abs(calib_UpValueMin - calib_MdValueMin) * position_distance_degree); + mid_down_distance = (short)(abs(calib_MdValueMin - calib_DnValueMin) * position_distance_degree); + } + TRI_KEY_LOG("Upmin:%d, Mdmin:%d, Dnmin:%d, up_mid_tol:%d, mid_down_tol:%d\n", + calib_UpValueMin, calib_MdValueMin, calib_DnValueMin, up_mid_tol,mid_down_tol); +} + + +static ssize_t hall_data_calib_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + return snprintf(buf, PAGE_SIZE, "%d\n%d\n",-1,-1); + } + return snprintf(buf, PAGE_SIZE, "%d,%d,%d,%d,%d,%d,%d,%d\n", + g_the_chip->dnHall_UpV, g_the_chip->upHall_UpV, + g_the_chip->dnHall_MdV, g_the_chip->upHall_MdV, + g_the_chip->dnHall_DnV, g_the_chip->upHall_DnV, + up_mid_tol, mid_down_tol); +} + +static ssize_t hall_data_calib_store(struct device *pdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int data[6] = {0}; + char temp[35] = {0}; + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + return count; + } + strlcpy(temp, buf, sizeof(temp)); + TRI_KEY_LOG("temp is %s:\n", temp); + if (sscanf(temp, "%d,%d,%d,%d,%d,%d", &data[0], &data[1], &data[2], + &data[3], &data[4], &data[5]) == 6) { + g_the_chip->dnHall_UpV = data[0]; + g_the_chip->upHall_UpV = data[1]; + g_the_chip->dnHall_MdV = data[2]; + g_the_chip->upHall_MdV = data[3]; + g_the_chip->dnHall_DnV = data[4]; + g_the_chip->upHall_DnV = data[5]; + TRI_KEY_ERR("data[%d %d %d %d %d %d]\n", data[0], data[1], + data[2], data[3], data[4], data[5]); + } else { + TRI_KEY_ERR("fail\n"); + } + initialCalibValue(g_the_chip->dnHall_UpV, g_the_chip->dnHall_MdV, + g_the_chip->dnHall_DnV, g_the_chip->upHall_UpV, + g_the_chip->upHall_MdV, g_the_chip->upHall_DnV); + report_calibration_location(g_the_chip); + return count; +} +static ssize_t hall_dump_regs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 _buf[1024] = {0}; + + if (!g_the_chip) { + TRI_KEY_ERR("g_the_chip null\n"); + return 0; + } + + oneplus_hall_dump_regs(1, _buf); + return sprintf(buf, "%s\n %s\n", _buf); +} +static ssize_t hall_debug_info_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + int tmp = 0; + char buffer[4] = {0}; + + if (count > 2) + return count; + strlcpy(buffer, buf, sizeof(buffer)); + if (1 == sscanf(buffer, "%d", &tmp)) { + tri_key_debug = tmp; + } else { + TRI_KEY_DEBUG("invalid content: '%s', length = %zd\n", buf, count); + } + + return count; +} +static ssize_t hall_debug_info_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", tri_key_debug); +} + +static ssize_t hall_set_value_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", tol1); +} + +static ssize_t hall_set_value_store(struct device *pdev, struct device_attribute *attr, const char *buf, size_t count) +{ + int tmp = 0; + char buffer[4] = {0}; + + strlcpy(buffer, buf, sizeof(buffer)); + TRI_KEY_LOG("buffer is %s\n", buffer); + if (sscanf(buffer, "%d", &tmp) == 1) { + tol1 = tmp; + TRI_KEY_LOG("tol1 is %d\n", tol1); + } + else + TRI_KEY_ERR("invalid content: %s, length = %zd\n", buf, count); + + return count; +} +static ssize_t hall_clear_irq_store(struct device *pdev, struct device_attribute *attr, const char *buf, size_t count) +{ + int tmp = 0; + char buffer[4] = {0}; + + strlcpy(buffer, buf, sizeof(buffer)); + TRI_KEY_LOG("buffer is %s\n", buffer); + if (sscanf(buffer, "%d", &tmp) == 1) { + oneplus_hall_clear_irq(0); + oneplus_hall_clear_irq(1); + TRI_KEY_LOG("%s\n", __func__); + } + else + TRI_KEY_ERR("invalid content: %s, length = %zd\n", buf, count); + + return count; +} +static ssize_t hall_enable_irq_store(struct device *pdev, struct device_attribute *attr, const char *buf, size_t count) +{ + int tmp = 0; + char buffer[4] = {0}; + + strlcpy(buffer, buf, sizeof(buffer)); + TRI_KEY_LOG("buffer is %s\n", buffer); + if (sscanf(buffer, "%d", &tmp) == 1) { + oneplus_hall_enable_irq(0, tmp); + oneplus_hall_enable_irq(1, tmp); + TRI_KEY_LOG("%s\n", __func__); + } + else + TRI_KEY_ERR("invalid content: %s, length = %zd\n", buf, count); + + return count; +} + +static DEVICE_ATTR(hall_data, S_IRUGO | S_IWUSR, dhall_data_show, NULL); +static DEVICE_ATTR(tri_state, S_IRUGO | S_IWUSR, tri_state_show, NULL); +static DEVICE_ATTR(hall_data_calib, 0644, + hall_data_calib_show, hall_data_calib_store); +static DEVICE_ATTR(hall_dump_regs, 0644, hall_dump_regs_show, NULL); +static DEVICE_ATTR(hall_debug_info, 0644,hall_debug_info_show, hall_debug_info_store); +static DEVICE_ATTR(hall_set_value, 0644, hall_set_value_show, hall_set_value_store); +static DEVICE_ATTR(hall_clear_irq, 0644, NULL, hall_clear_irq_store); +static DEVICE_ATTR(hall_enable_irq, 0644, NULL, hall_enable_irq_store); + +static struct attribute *tri_key_attributes[] = { + &dev_attr_tri_state.attr, + &dev_attr_hall_data.attr, + &dev_attr_hall_data_calib.attr, + &dev_attr_hall_dump_regs.attr, + &dev_attr_hall_debug_info.attr, + &dev_attr_hall_set_value.attr, + &dev_attr_hall_clear_irq.attr, + &dev_attr_hall_enable_irq.attr, + NULL +}; + + +static struct attribute_group tri_key_attribute_group = { + .attrs = tri_key_attributes +}; + +static int tri_key_platform_probe(struct platform_device *pdev) +{ + struct extcon_dev_data *chip = NULL; + int err = 0; + int res = 0; + //int hall_value_min = 0; + struct device_node *np; + + np = pdev->dev.of_node; + TRI_KEY_LOG("call %s\n", __func__); + + if (!g_the_chip) { + chip = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!chip) { + TRI_KEY_ERR("kzalloc err\n"); + return -ENOMEM; + } + g_the_chip = chip; + } else { + chip = g_the_chip; + } + mutex_init(&chip->mtx); + chip->dev = &pdev->dev; + chip->project_info = of_property_read_bool(np, "project_info"); + TRI_KEY_LOG("project_info is %d\n", chip->project_info); + err = sysfs_create_group(&pdev->dev.kobj, &tri_key_attribute_group); + if (err) { + TRI_KEY_ERR("tri_key:sysfs_create_group was failed(%d)\n", err); + goto sysfs_create_fail; + } + + if (0 && (!chip->dhall_up_ops || !chip->dhall_down_ops)) { + TRI_KEY_ERR("no dhall available\n"); + goto fail; + } +// extcon registration + chip->edev = devm_extcon_dev_allocate(chip->dev, tristate_extcon_tab); + chip->edev->name = "tri_state_key"; + err = devm_extcon_dev_register(chip->dev, chip->edev); + + if (err < 0) { + TRI_KEY_ERR("%s register extcon dev failed\n", __func__); + goto err_extcon_dev_register; + } + + INIT_WORK(&chip->dwork, tri_key_dev_work); + hrtimer_init(&tri_key_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + tri_key_timer.function = tri_key_status_timeout; + INIT_WORK(&tri_key_timeout_work, tri_key_timeout_work_func); +//get data when reboot + res = oneplus_get_data(chip); + if (res < 0) { + TRI_KEY_LOG("tri_key:get hall data failed!\n"); + goto fail; + } + TRI_KEY_LOG("tri_key:data1 is %d, data0 is %d\n", + chip->dhall_data1, chip->dhall_data0); + +//get position when reboot + reboot_get_position(chip); +//set threshold when reboot; + err = reupdata_threshold(chip); + if (err < 1) { + TRI_KEY_ERR("%s reupdata_threshold failed\n", __func__); + goto fail; + } +//report key value + report_key_value(chip); + last_position = chip->position; + err = oneplus_hall_set_detection_mode(DHALL_0, DETECTION_MODE_INTERRUPT); + TRI_KEY_LOG("tri_key:set 0 detection mode\n"); + if (err < 0) { + TRI_KEY_ERR("%s set HALL0 detection mode failed %d\n", + __func__, err); + goto fail; + } + err = oneplus_hall_set_detection_mode(DHALL_1, DETECTION_MODE_INTERRUPT); + TRI_KEY_LOG("tri_key:set 1 detection mode\n"); + if (err < 0) { + TRI_KEY_ERR("%s set HALL1 detection mode failed %d\n", __func__, err); + goto fail; + } + TRI_KEY_LOG("%s probe success.\n", __func__); + return 0; + +fail: + kfree(chip); + g_the_chip = NULL; + TRI_KEY_LOG("fail\n"); + return -EINVAL; +sysfs_create_fail: + sysfs_remove_group(&pdev->dev.kobj, &tri_key_attribute_group); + +err_extcon_dev_register: + devm_extcon_dev_unregister(chip->dev, chip->edev); + TRI_KEY_LOG("fail\n"); + return -EINVAL; + +} + +static int tri_key_platform_remove(struct platform_device *pdev) +{ + if (g_the_chip) { + cancel_work_sync(&g_the_chip->dwork); + extcon_dev_unregister(g_the_chip->edev); + kfree(g_the_chip); + g_the_chip = NULL; + } + return 0; +} + +static const struct of_device_id tristate_dev_of_match[] = { + { .compatible = "oneplus,hall_tri_state_key"}, + {}, +}; +MODULE_DEVICE_TABLE(of, of_motor_match); + +static struct platform_driver tri_key_platform_driver = { + .probe = tri_key_platform_probe, + .remove = tri_key_platform_remove, + .driver = { + .name = "tri-state-key", + .of_match_table = tristate_dev_of_match, + }, +}; + +static int __init tri_key_platform_init(void) +{ + int res = 0; + TRI_KEY_LOG("call : %s\n", __func__); + res = platform_driver_register(&tri_key_platform_driver); + if (res < 0) + TRI_KEY_LOG("%s failed\n", __func__); + return res; +} + +module_init(tri_key_platform_init); + +static void __exit tri_key_platform_exit(void) +{ + platform_driver_unregister(&tri_key_platform_driver); +} +module_exit(tri_key_platform_exit); +MODULE_DESCRIPTION("oem tri_state_key driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/oneplus/tri_state_key/oneplus_tri_key.h b/drivers/oneplus/tri_state_key/oneplus_tri_key.h new file mode 100755 index 0000000000000000000000000000000000000000..5f6e249abc3bd83c7d7d5b85ec07365175ad89e2 --- /dev/null +++ b/drivers/oneplus/tri_state_key/oneplus_tri_key.h @@ -0,0 +1,131 @@ +/************************************************************************************ +** Copyright (C), 2013-2018, Oneplus Mobile Comm Corp., Ltd +** File: oneplus_tri_key.h +** +** Description: +** Definitions for m1120 tri_state_key data process. +** +** Version: 1.0 +**************************************************************************************/ + +#include +#include + +/* +#define MODE_MUTE 1 +#define MODE_DO_NOT_DISTURB 2 +#define MODE_NORMAL 3 +*/ +typedef enum debug_level { + LEVEL_BASIC, + LEVEL_DEBUG, +}tri_key_debug_level; + +enum dhall_id { + DHALL_0 = 0, + DHALL_1, +}; +// enum dhall_id { +// DHALL_DOWN = 0, +// DHALL_UP, +// }; + +enum dhall_detection_mode { + DETECTION_MODE_POLLING = 0, + DETECTION_MODE_INTERRUPT, + DETECTION_MODE_INVALID, +}; + +enum motor_direction { + MOTOR_DOWN = 0, + MOTOR_UPWARD, +}; + +enum tri_key_position { + UP_STATE, + DOWN_STATE, + MID_STATE, +}; + +extern unsigned int tristate_extcon_tab[]; +extern unsigned int tri_key_debug; + +typedef struct { + short data0; + short data1; +} dhall_data_t; + +struct dhall_operations { + int (*get_data) (short *data); + int (*set_detection_mode) (u8 mode); + int (*enable_irq) (bool enable); + int (*clear_irq) (void); + int (*get_irq_state) (void); + bool (*update_threshold) (int position, short lowthd, short highthd); + void (*dump_regs) (u8 *buf); + int (*set_reg) (int reg, int val); + bool (*is_power_on) (void); + void (*set_sensitivity) (char *data); +}; + + struct extcon_dev_data { + + struct work_struct dwork; + struct extcon_dev *edev; //change 1 + struct device *dev; + struct timer_list s_timer; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + struct delayed_work up_work; + struct delayed_work down_work; + struct dhall_operations *dhall_up_ops; + struct dhall_operations *dhall_down_ops; + struct mutex mtx; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)) + //struct wake_lock suspend_lock; +#else + //struct wakeup_source *suspend_ws; +#endif + const char *d_name; + const char *m_name; + int position; + int last_position; + int project_info; //just for kebat project + int interf;//interference + short state; + short dhall_data0; + short dhall_data1; + short dnHall_UpV; + short dnHall_MdV; + short dnHall_DnV; + short upHall_UpV; + short upHall_MdV; + short upHall_DnV; + //short dnHall_UpV_pre; + //short dnHall_MdV_pre; + //short dnHall_DnV_pre; + //short upHall_UpV_pre; + //short upHall_MdV_pre; + //short upHall_DnV_pre; + int manual2auto_up_switch; + int manual2auto_down_switch; + int irq; + //bool irq_monitor_started; + //bool is_irq_abnormal; +}; + +extern int register_tp_delta_print_notifier(struct notifier_block *nb); +extern int unregister_tp_delta_print_notifier(struct notifier_block *nb); +extern int oneplus_register_hall(const char *name, struct dhall_operations *ops); +//dhall control api +extern int oneplus_hall_get_data(unsigned int id); +extern int oneplus_hall_set_detection_mode(unsigned int id, u8 mode); +extern int oneplus_hall_enable_irq (unsigned int id, bool enable); +extern int oneplus_hall_clear_irq (unsigned int id); +extern int oneplus_hall_irq_handler(unsigned int id); +extern int oneplus_hall_get_irq_state(unsigned int id); +extern void oneplus_hall_dump_regs(unsigned int id, u8 *buf); +extern int oneplus_hall_set_reg(unsigned int id, int reg, int val); +extern bool oneplus_hall_update_threshold(unsigned int id, int position, short lowthd, short highthd); +extern bool oneplus_hall_is_power_on(void); +extern int aw8697_op_haptic_stop(void); diff --git a/drivers/oneplus/tri_state_key/tri_state_key.c b/drivers/oneplus/tri_state_key/tri_state_key.c new file mode 100644 index 0000000000000000000000000000000000000000..34466410f09dd57f50b0770a5207055bee96e4b7 --- /dev/null +++ b/drivers/oneplus/tri_state_key/tri_state_key.c @@ -0,0 +1,391 @@ +/* + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include "../../extcon/extcon.h" +//#include + +#define DRV_NAME "tri_state_key" +#define KEY_LOG(fmt, args...) printk(KERN_INFO DRV_NAME" %s : "fmt, __FUNCTION__, ##args) +/* + * + * KEY1(GPIO1) KEY2(GPIO92) + * pin1 connect to pin4 0 1 | MUTE + * pin2 connect to pin5 1 1 | Do Not Disturb + * pin4 connect to pin3 1 0 | Normal + */ +enum { + MODE_UNKNOWN, + MODE_MUTE, + MODE_DO_NOT_DISTURB, + MODE_NORMAL, + MODE_MAX_NUM + } tri_mode_t; + +static const unsigned int tristate_extcon_tab[] = { + MODE_MUTE, + MODE_DO_NOT_DISTURB, + MODE_NORMAL, + EXTCON_NONE, +}; + +struct extcon_dev_data { + int irq_key3; + int irq_key2; + int irq_key1; + int key1_gpio; + int key2_gpio; + int key3_gpio; + + struct regulator *vdd_io; + + struct work_struct work; + struct extcon_dev *edev; //change 1 + struct device *dev; + + struct timer_list s_timer; + struct pinctrl *key_pinctrl; + struct pinctrl_state *set_state; + +}; + +static struct extcon_dev_data *extcon_data; +static DEFINE_MUTEX(sem); +static int set_gpio_by_pinctrl(void) +{ + return pinctrl_select_state(extcon_data->key_pinctrl, + extcon_data->set_state); +} +/*op add to fix GCE-7551 begin*/ +//extern int aw8697_op_haptic_stop(void); +/*op add to fix GCE-7551 end*/ + +static void extcon_dev_work(struct work_struct *work) +{ + int key[3] = {0, 0, 0}; + /*op add to fix ISTRACKING-34823 begin*/ + static int pre_key0, pre_key1, pre_key2; + /*op add to fix ISTRACKING-34823 end*/ + /*hw 13 use special tri state key no use key2*/ + //hw_version=get_hw_version(); + key[0] = gpio_get_value(extcon_data->key1_gpio); + key[1] = gpio_get_value(extcon_data->key2_gpio); + key[2] = gpio_get_value(extcon_data->key3_gpio); + KEY_LOG("key[0]=%d,key[1]=%d,key[2]=%d\n", + key[0], key[1], key[2]); + /*op add to fix ISTRACKING-34823 begin*/ + if (!key[0] || !key[1] || !key[2]) { + if (pre_key0 == key[0] && pre_key1 == key[1] + && pre_key2 == key[2]) { + pre_key0 = key[0]; + pre_key1 = key[1]; + pre_key2 = key[2]; + return; + } + } + /*op add to fix ISTRACKING-34823 end*/ + /*op add to fix GCE-7551 begin*/ + if (key[0] && key[1] && key[2]) { + KEY_LOG("key[0]=%d,key[1]=%d,key[2]=%d***pre_key0=%d, pre_key1=%d, pre_key2=%d\n", + key[0], key[1], key[2],pre_key0,pre_key1,pre_key2); + if (pre_key0 ==1 && pre_key1==1 && pre_key2 == 0) + return; + if (pre_key0 && pre_key1 && pre_key2) { + KEY_LOG("Debounce timeout: Set the extconstate to 0,1,1\n"); + extcon_set_state_sync(extcon_data->edev, 1, 0); + extcon_set_state_sync(extcon_data->edev, 2, 1); + extcon_set_state_sync(extcon_data->edev, 3, 1); + } else { + mod_timer(&extcon_data->s_timer, jiffies + HZ/5); + pre_key0 = key[0]; + pre_key1 = key[1]; + pre_key2 = key[2]; + KEY_LOG("Wait for debounce timeout\n"); + } + return; + } else { + if (!del_timer(&extcon_data->s_timer)) + KEY_LOG("timer already expired for Floating state\n"); + } + if (!key[0] && !key[1] && !key[2]) + return; + if (!key[0] && !key[1] && key[2]) + return; + if (!key[0] && key[1] && !key[2]) + return; + if (key[0] && !key[1] && !key[2]) + return; + /*op add to fix GCE-7551 end*/ + extcon_set_state_sync( + extcon_data->edev, 1, key[0]); + extcon_set_state_sync( + extcon_data->edev, 2, key[1]); + extcon_set_state_sync( + extcon_data->edev, 3, key[2]); + /*op add to fix GCE-7551 begin*/ + //if (!key[2] || !key[1]) + // aw8697_op_haptic_stop(); + /*op add to fix GCE-7551 end*/ + /*op add to fix ISTRACKING-34823 begin*/ + if (!key[0] || !key[1] || !key[2]) { + pre_key0 = key[0]; + pre_key1 = key[1]; + pre_key2 = key[2]; + } + /*op add to fix ISTRACKING-34823 end*/ +} + + +static irqreturn_t extcon_dev_interrupt(int irq, void *_dev) +{ + schedule_work(&extcon_data->work); + return IRQ_HANDLED; +} + +static void timer_handle(struct timer_list *t) +{ + schedule_work(&extcon_data->work); +} + +#ifdef CONFIG_OF +static int extcon_dev_get_devtree_pdata(struct device *dev) +{ + struct device_node *node; + + node = dev->of_node; + if (!node) + return -EINVAL; + + extcon_data->key3_gpio = + of_get_named_gpio(node, "tristate,gpio_key3", 0); + if ((!gpio_is_valid(extcon_data->key3_gpio))) + return -EINVAL; + KEY_LOG("extcon_data->key3_gpio=%d\n", extcon_data->key3_gpio); + + extcon_data->key2_gpio = + of_get_named_gpio(node, "tristate,gpio_key2", 0); + if ((!gpio_is_valid(extcon_data->key2_gpio))) + return -EINVAL; + KEY_LOG("extcon_data->key2_gpio=%d\n", extcon_data->key2_gpio); + + extcon_data->key1_gpio = + of_get_named_gpio(node, "tristate,gpio_key1", 0); + if ((!gpio_is_valid(extcon_data->key1_gpio))) + return -EINVAL; + KEY_LOG("extcon_data->key1_gpio=%d\n", extcon_data->key1_gpio); + + return 0; +} +#else +static inline int +extcon_dev_get_devtree_pdata(struct device *dev) +{ + KEY_LOG("inline function\n"); + return 0; +} +#endif + +static int tristate_dev_probe(struct platform_device *pdev) +{ + struct device *dev; + int ret = 0; + KEY_LOG("SYSY\n"); + KEY_LOG("TRI_STATE_KEY :******************PROBE CALL****\n"); + dev = &pdev->dev; + + extcon_data = kzalloc(sizeof(struct extcon_dev_data), GFP_KERNEL); + if (!extcon_data) + return -ENOMEM; + + extcon_data->dev = dev; + + + extcon_data->key_pinctrl = devm_pinctrl_get(extcon_data->dev); + + if (IS_ERR_OR_NULL(extcon_data->key_pinctrl)) { + KEY_LOG("Failed to get pinctrl\n"); + goto err_extcon_dev_register; + } + extcon_data->set_state = pinctrl_lookup_state(extcon_data->key_pinctrl, + "pmx_tri_state_key_active"); + if (IS_ERR_OR_NULL(extcon_data->set_state)) { + KEY_LOG("Failed to lookup_state\n"); + goto err_extcon_dev_register; + } + + set_gpio_by_pinctrl(); + + ret = extcon_dev_get_devtree_pdata(dev); + if (ret) { + KEY_LOG("parse device tree fail!!!\n"); + goto err_extcon_dev_register; + } + + + /* extcon registration */ + extcon_data->edev = + devm_extcon_dev_allocate(extcon_data->dev, tristate_extcon_tab); + extcon_data->edev->name = DRV_NAME; + + ret = devm_extcon_dev_register(extcon_data->dev, extcon_data->edev); + if (ret < 0) + goto err_extcon_dev_register; + + //config irq gpio and request irq + ret = gpio_request(extcon_data->key1_gpio, "tristate_key1"); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(extcon_data->key1_gpio); + if (ret < 0) + goto err_set_gpio_input; + + extcon_data->irq_key1 = gpio_to_irq(extcon_data->key1_gpio); + if (extcon_data->irq_key1 < 0) { + ret = extcon_data->irq_key1; + goto err_detect_irq_num_failed; + } + + ret = request_irq(extcon_data->irq_key1, extcon_dev_interrupt, + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + "tristate_key1", extcon_data); + if (ret < 0) + goto err_request_irq; + + ret = gpio_request(extcon_data->key2_gpio, + "tristate_key2"); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(extcon_data->key2_gpio); + if (ret < 0) + goto err_set_gpio_input; + + extcon_data->irq_key2 = gpio_to_irq(extcon_data->key2_gpio); + if (extcon_data->irq_key2 < 0) { + ret = extcon_data->irq_key2; + goto err_detect_irq_num_failed; + } + + ret = request_irq(extcon_data->irq_key2, extcon_dev_interrupt, + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + "tristate_key2", extcon_data); + if (ret < 0) + goto err_request_irq; + + ret = gpio_request(extcon_data->key3_gpio, + "tristate_key3"); + if (ret < 0) + goto err_request_gpio; + + ret = gpio_direction_input(extcon_data->key3_gpio); + if (ret < 0) + goto err_set_gpio_input; + + extcon_data->irq_key3 = gpio_to_irq(extcon_data->key3_gpio); + if (extcon_data->irq_key3 < 0) { + ret = extcon_data->irq_key3; + goto err_detect_irq_num_failed; + } + + ret = request_irq(extcon_data->irq_key3, extcon_dev_interrupt, + IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, + "tristate_key3", extcon_data); + if (ret < 0) + goto err_request_irq; + + INIT_WORK(&extcon_data->work, extcon_dev_work); + + //init_timer(&extcon_data->s_timer); + __init_timer(&extcon_data->s_timer, timer_handle, 0); + //extcon_data->s_timer.function = &timer_handle; + extcon_data->s_timer.expires = jiffies + 5*HZ; + + add_timer(&extcon_data->s_timer); + + enable_irq_wake(extcon_data->irq_key1); + enable_irq_wake(extcon_data->irq_key2); + enable_irq_wake(extcon_data->irq_key3); + + return 0; + +err_request_gpio: + devm_extcon_dev_unregister(extcon_data->dev, extcon_data->edev); +err_request_irq: +err_detect_irq_num_failed: +err_set_gpio_input: + gpio_free(extcon_data->key2_gpio); + gpio_free(extcon_data->key1_gpio); + gpio_free(extcon_data->key3_gpio); +err_extcon_dev_register: + kfree(extcon_data); + + return ret; +} + +static int tristate_dev_remove(struct platform_device *pdev) +{ + cancel_work_sync(&extcon_data->work); + gpio_free(extcon_data->key1_gpio); + gpio_free(extcon_data->key2_gpio); + gpio_free(extcon_data->key3_gpio); + extcon_dev_unregister(extcon_data->edev); + kfree(extcon_data); + + return 0; +} +#ifdef CONFIG_OF +static const struct of_device_id tristate_dev_of_match[] = { + { .compatible = "oneplus,tri-state-key", }, + { }, +}; +MODULE_DEVICE_TABLE(of, tristate_dev_of_match); +#endif + +static struct platform_driver tristate_dev_driver = { + .probe = tristate_dev_probe, + .remove = tristate_dev_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tristate_dev_of_match, + }, +}; +static int __init oem_tristate_init(void) +{ + return platform_driver_register(&tristate_dev_driver); +} +module_init(oem_tristate_init); + +static void __exit oem_tristate_exit(void) +{ + platform_driver_unregister(&tristate_dev_driver); +} +module_exit(oem_tristate_exit); +MODULE_DESCRIPTION("oem tri_state_key driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/oneplus/vibrator/Kconfig b/drivers/oneplus/vibrator/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..44a5c5a1f8102ade240f8ca53ae8a87f1a358080 --- /dev/null +++ b/drivers/oneplus/vibrator/Kconfig @@ -0,0 +1,6 @@ +config AW8697_HAPTIC + tristate "Haptic driver for awinic aw8697 series" + depends on I2C + help + This option enables support for aw8697 series Haptic Driver. + comment "LED Triggers" diff --git a/drivers/oneplus/vibrator/Makefile b/drivers/oneplus/vibrator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..75c2b031c64ff9bbcb0534734f0935266a895ee3 --- /dev/null +++ b/drivers/oneplus/vibrator/Makefile @@ -0,0 +1,2 @@ +#for AWINIC AW8697 Haptic +obj-$(CONFIG_AW8697_HAPTIC) += aw8697.o diff --git a/drivers/oneplus/vibrator/aw8697.c b/drivers/oneplus/vibrator/aw8697.c new file mode 100644 index 0000000000000000000000000000000000000000..aec539a7f65febb0fc92f055eec8384d3404845c --- /dev/null +++ b/drivers/oneplus/vibrator/aw8697.c @@ -0,0 +1,6254 @@ +/* + * aw8697.c aw8697 haptic module + * + * Version: v1.3.3 + * + * Copyright (c) 2018 AWINIC Technology CO., LTD + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "aw8697.h" +#include "aw8697_reg.h" +#include "aw8697_config.h" +#include +#include + +#include +#include +#include + + +/****************************************************** + * + * Marco + * + ******************************************************/ +#define AW8697_I2C_NAME "aw8697_haptic" +#define AW8697_HAPTIC_NAME "awinic_haptic" + +#define AW8697_VERSION "v1.4.2" + +#define AWINIC_RAM_UPDATE_DELAY + +#define AW_I2C_RETRIES 10 +#define AW_I2C_RETRY_DELAY 2 +#define AW_READ_CHIPID_RETRIES 5 +#define AW_READ_CHIPID_RETRY_DELAY 2 +#define AW8697_MAX_DSP_START_TRY_COUNT 10 +#define AWINIC_READ_BIN_FLEXBALLY + +#define AW8697_MAX_FIRMWARE_LOAD_CNT 20 +#define OP_AW_DEBUG +#define OP_OCS_CALIBRATION_T_LENGTH 3500000 + +#define PM_QOS_VALUE_VB 200 +struct pm_qos_request pm_qos_req_vb; +#define RTP_INIT_OVERSTEP_THR 8192 + +#define SCORE_MODE +#ifdef SCORE_MODE +#define FIRST_SCOREMODE +//#define SECOND_SCOREMODE +#else +#define AISCAN_CTRL +#endif + +#define TRUST_LEVEL 5 +#define ABS(x) ((x) < 0 ? (-x) : (x)) + +#ifdef CONFIG_ARCH_LITO +#define AW8697_LONG_INDEX_HEAD 94 +#define FACTORY_MODE_AT_MODE_RTP_NUMBER 119 +#else +#define AW8697_LONG_INDEX_HEAD 100 +#define FACTORY_MODE_AT_MODE_RTP_NUMBER 125 +#endif + +#define HAL_FACTORY_MODE_NORMAL_RTP_NUMBER 888 +#define HAL_FACTORY_MODE_HIGH_TEMP_RTP_NUMBER 777 +/***************************************************** +* +* Macro for common code +* +******************************************************/ +#ifdef CONFIG_ARCH_LITO + #define FACTORY_MODE_EFFECT_NUMBER 84 +#else + #define FACTORY_MODE_EFFECT_NUMBER 89 +#endif + +#ifdef CONFIG_ARCH_LITO + #define HAPTIC_REAL_F0_1 227 + #define HAPTIC_REAL_F0_2 227 + #define HAPTIC_REAL_F0_3 228 + #define HAPTIC_REAL_F0_4 229 + #define HAPTIC_REAL_F0_5 230 + #define HAPTIC_REAL_F0_6 230 + #define HAPTIC_REAL_F0_7 230 + #define HAPTIC_REAL_F0_8 231 + #define HAPTIC_REAL_F0_9 232 + #define HAPTIC_REAL_F0_10 233 + #define HAPTIC_REAL_F0_11 234 +#else + #define HAPTIC_REAL_F0_1 160 + #define HAPTIC_REAL_F0_2 162 + #define HAPTIC_REAL_F0_3 164 + #define HAPTIC_REAL_F0_4 166 + #define HAPTIC_REAL_F0_5 168 + #define HAPTIC_REAL_F0_6 170 + #define HAPTIC_REAL_F0_7 172 + #define HAPTIC_REAL_F0_8 174 + #define HAPTIC_REAL_F0_9 176 + #define HAPTIC_REAL_F0_10 178 + #define HAPTIC_REAL_F0_11 180 +#endif + + +/* add haptic audio tp mask */ +//extern struct shake_point record_point[10]; +/* add haptic audio tp mask end */ +/****************************************************** + * + * variable + * + ******************************************************/ +#define AW8697_RTP_NAME_MAX 64 +static char aw8697_ram_name[5][30] = { +{"aw8697_haptic_166.bin"}, +{"aw8697_haptic_168.bin"}, +{"aw8697_haptic_170.bin"}, +{"aw8697_haptic_172.bin"}, +{"aw8697_haptic_174.bin"}, +}; +static char aw8697_rtp_name[][AW8697_RTP_NAME_MAX] = { + {"aw8697_rtp.bin"}, + {"ringtone_Alacrity_RTP.bin"}, + {"ring_Amenity_RTP.bin"}, + {"ringtone_Blues_RTP.bin"}, + {"ring_Bounce_RTP.bin"}, + {"ring_Calm_RTP.bin"}, + {"ringtone_Cloud_RTP.bin"}, + {"ringtone_Cyclotron_RTP.bin"}, + {"ringtone_Distinct_RTP.bin"}, + {"ringtone_Dynamic_RTP.bin"}, + {"ringtone_Echo_RTP.bin"}, + {"ringtone_Expect_RTP.bin"}, + {"ringtone_Fanatical_RTP.bin"}, + {"ringtone_Funky_RTP.bin"}, + {"ringtone_Guitar_RTP.bin"}, + {"ringtone_Harping_RTP.bin"}, + {"ringtone_Highlight_RTP.bin"}, + {"ringtone_Idyl_RTP.bin"}, + {"ringtone_Innocence_RTP.bin"}, + {"ringtone_Journey_RTP.bin"}, + {"ringtone_Joyous_RTP.bin"}, + {"ring_Lazy_RTP.bin"}, + {"ringtone_Marimba_RTP.bin"}, + {"ring_Mystical_RTP.bin"}, + {"ringtone_Old_telephone_RTP.bin"}, + {"ringtone_Oneplus_tune_RTP.bin"}, + {"ringtone_Rhythm_RTP.bin"}, + {"ringtone_Optimistic_RTP.bin"}, + {"ringtone_Piano_RTP.bin"}, + {"ring_Whirl_RTP.bin"}, +#ifdef CONFIG_ARCH_LITO + {"ring_Crimson_RTP.bin"}, + {"ring_Curious_RTP.bin"}, + {"ring_Imperfections_RTP.bin"}, + {"ring_The_Essence_RTP.bin"}, +#endif + {"VZW_Alrwave_RTP.bin"}, + {"t-jingle_RTP.bin"}, +#ifndef CONFIG_ARCH_LITO + {"ringtone_Eager.bin"}, + {"ringtone_Ebullition.bin"}, + {"ringtone_Friendship.bin"}, + {"ringtone_Jazz_life_RTP.bin"}, + {"ringtone_Sun_glittering_RTP.bin"}, +#endif + {"notif_Allay_RTP.bin"},//notify + {"notif_Allusion_RTP.bin"}, + {"notif_Amiable_RTP.bin"}, + {"notif_Blare_RTP.bin"}, + {"notif_Blissful_RTP.bin"}, + {"notif_Brisk_RTP.bin"}, + {"notif_Bubble_RTP.bin"}, + {"notif_Cheerful_RTP.bin"}, + {"notif_Clear_RTP.bin"}, + {"notif_Comely_RTP.bin"}, + {"notif_Cozy_RTP.bin"}, + {"notif_Ding_RTP.bin"}, + {"notif_Effervesce_RTP.bin"}, + {"notif_Elegant_RTP.bin"}, + {"notif_Free_RTP.bin"}, + {"notif_Hallucination_RTP.bin"}, + {"notif_Inbound_RTP.bin"}, + {"notif_Light_RTP.bin"}, + {"notif_Meet_RTP.bin"}, + {"notif_Naivety_RTP.bin"}, + {"notif_Quickly_RTP.bin"}, + {"notif_Rhythm_RTP.bin"}, + {"notif_Surprise_RTP.bin"}, + {"notif_Twinkle_RTP.bin"}, + {"Version_Alert_RTP.bin"}, +#ifdef CONFIG_ARCH_LITO + {"notif_Glint_RTP.bin"}, +#endif + {"alarm_Alarm_clock_RTP.bin"},//alarm + {"alarm_Beep_RTP.bin"}, + {"alarm_Breeze_RTP.bin"}, + {"alarm_Dawn_RTP.bin"}, + {"alarm_Dream_RTP.bin"}, + {"alarm_Fluttering_RTP.bin"}, + {"alarm_Flyer_RTP.bin"}, + {"alarm_Interesting_RTP.bin"}, + {"alarm_Leisurely_RTP.bin"}, + {"alarm_Memory_RTP.bin"}, + {"alarm_Relieved_RTP.bin"}, + {"alarm_Ripple_RTP.bin"}, + {"alarm_Slowly_RTP.bin"}, + {"alarm_spring_RTP.bin"}, + {"alarm_Stars_RTP.bin"}, + {"alarm_Surging_RTP.bin"}, + {"alarm_tactfully_RTP.bin"}, + {"alarm_The_wind_RTP.bin"}, + {"alarm_Walking_in_the_rain_RTP.bin"}, +#ifdef CONFIG_ARCH_LITO + {"alarm_Dawn_RTP.bin"}, +#else + {"Audition_RTP.bin"}, + {"In_game_alarm_RTP.bin"}, + {"In_game_ringtone_RTP.bin"}, + {"In_game_sms_RTP.bin"}, + {"Rock_RTP.bin"}, + {"Wake_up_samurai_RTP.bin"}, +#endif + {"shuntai24k_rtp.bin"}, + {"wentai24k_rtp.bin"}, + {"agingtest_160hz_RTP.bin"}, + {"agingtest_162hz_RTP.bin"}, + {"agingtest_164hz_RTP.bin"}, + {"agingtest_166hz_RTP.bin"}, + {"agingtest_168hz_RTP.bin"}, + {"agingtest_170hz_RTP.bin"}, + {"agingtest_172hz_RTP.bin"}, + {"agingtest_174hz_RTP.bin"}, + {"agingtest_176hz_RTP.bin"}, + {"agingtest_178hz_RTP.bin"}, + {"agingtest_180hz_RTP.bin"}, + {"20ms_RTP.bin"},//AW8697_LONG_INDEX_HEAD index 4 + {"40ms_RTP.bin"}, + {"60ms_RTP.bin"}, + {"80ms_RTP.bin"}, + {"100ms_RTP.bin"}, + {"120ms_RTP.bin"}, + {"140ms_RTP.bin"}, + {"160ms_RTP.bin"}, + {"180ms_RTP.bin"}, + {"200ms_RTP.bin"}, + {"220ms_RTP.bin"}, + {"240ms_RTP.bin"}, + {"260ms_RTP.bin"}, + {"280ms_RTP.bin"}, + {"300ms_RTP.bin"}, + {"320ms_RTP.bin"}, + {"340ms_RTP.bin"}, + {"360ms_RTP.bin"}, + {"380ms_RTP.bin"}, + {"400ms_RTP.bin"}, + {"420ms_RTP.bin"}, + {"440ms_RTP.bin"}, + {"460ms_RTP.bin"}, + {"480ms_RTP.bin"}, + {"500ms_RTP.bin"}, + {"AT500ms_RTP.bin"}, +}; + +enum { + FACTORY_MODE_160HZ_EFFECTION = FACTORY_MODE_EFFECT_NUMBER, + FACTORY_MODE_162HZ_EFFECTION, + FACTORY_MODE_164HZ_EFFECTION, + FACTORY_MODE_166HZ_EFFECTION, + FACTORY_MODE_168HZ_EFFECTION, + FACTORY_MODE_170HZ_EFFECTION, + FACTORY_MODE_172HZ_EFFECTION, + FACTORY_MODE_174HZ_EFFECTION, + FACTORY_MODE_176HZ_EFFECTION, + FACTORY_MODE_178HZ_EFFECTION, + FACTORY_MODE_180HZ_EFFECTION, +}; + +struct aw8697_container *aw8697_rtp; +struct aw8697 *g_aw8697; +static int aw8697_haptic_get_f0(struct aw8697 *aw8697); +static bool check_factory_mode(void); +extern void msm_cpuidle_set_sleep_disable(bool disable); + +/****************************************************** + * + * functions + * + ******************************************************/ +static void aw8697_interrupt_clear(struct aw8697 *aw8697); +static int aw8697_haptic_trig_enable_config(struct aw8697 *aw8697); + +#define get_abs(a) ((a)>=0? (a) : (-(a))) + /****************************************************** + * + * aw8697 i2c write/read + * + ******************************************************/ +static int aw8697_i2c_write(struct aw8697 *aw8697, + unsigned char reg_addr, unsigned char reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while(cnt < AW_I2C_RETRIES) { + ret = i2c_smbus_write_byte_data(aw8697->i2c, reg_addr, reg_data); + if(ret < 0) { + pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt, ret); + } else { + break; + } + cnt ++; + usleep_range(AW_I2C_RETRY_DELAY * 1000, + AW_I2C_RETRY_DELAY * 1000 + 500); + } + return ret; +} + +static int aw8697_i2c_read(struct aw8697 *aw8697, + unsigned char reg_addr, unsigned char *reg_data) +{ + int ret = -1; + unsigned char cnt = 0; + + while(cnt < AW_I2C_RETRIES) { + ret = i2c_smbus_read_byte_data(aw8697->i2c, reg_addr); + if(ret < 0) { + pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt, + ret); + } else { + *reg_data = ret; + break; + } + cnt ++; + usleep_range(AW_I2C_RETRY_DELAY * 1000, + AW_I2C_RETRY_DELAY * 1000 + 500); + } + + return ret; +} + +static int aw8697_i2c_write_bits(struct aw8697 *aw8697, + unsigned char reg_addr, unsigned int mask, unsigned char reg_data) +{ + unsigned char reg_val = 0; + + aw8697_i2c_read(aw8697, reg_addr, ®_val); + reg_val &= mask; + reg_val |= reg_data; + aw8697_i2c_write(aw8697, reg_addr, reg_val); + + return 0; +} + +static int aw8697_i2c_writes(struct aw8697 *aw8697, + unsigned char reg_addr, unsigned char *buf, unsigned int len) +{ + int ret = -1; + unsigned char *data; + + data = kmalloc(len+1, GFP_KERNEL); + if (data == NULL) { + pr_err("%s: can not allocate memory\n", __func__); + return -ENOMEM; + } + + data[0] = reg_addr; + memcpy(&data[1], buf, len); + + ret = i2c_master_send(aw8697->i2c, data, len+1); + if (ret < 0) { + pr_err("%s: i2c master send error\n", __func__); + } + + kfree(data); + + return ret; +} + +/***************************************************** + * + * ram update + * + *****************************************************/ +static void aw8697_rtp_loaded(const struct firmware *cont, void *context) +{ + struct aw8697 *aw8697 = context; + pr_info("%s enter\n", __func__); + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, aw8697_rtp_name[aw8697->rtp_file_num]); + release_firmware(cont); + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, aw8697_rtp_name[aw8697->rtp_file_num], + cont ? cont->size : 0); + + /* aw8697 rtp update */ + mutex_lock(&aw8697->rtp_lock); + aw8697_rtp = vmalloc(cont->size+sizeof(int)); + if (!aw8697_rtp) { + release_firmware(cont); + mutex_unlock(&aw8697->rtp_lock); + pr_err("%s: Error allocating memory\n", __func__); + return; + } + aw8697_rtp->len = cont->size; + pr_info("%s: rtp size = %d\n", __func__, aw8697_rtp->len); + memcpy(aw8697_rtp->data, cont->data, cont->size); + release_firmware(cont); + mutex_unlock(&aw8697->rtp_lock); + + aw8697->rtp_init = 1; + pr_info("%s: rtp update complete\n", __func__); +} + +static int aw8697_rtp_update(struct aw8697 *aw8697) +{ + pr_info("%s enter\n", __func__); + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8697_rtp_name[aw8697->rtp_file_num], aw8697->dev, GFP_KERNEL, + aw8697, aw8697_rtp_loaded); +} + + + static void aw8697_container_update(struct aw8697 *aw8697, + struct aw8697_container *aw8697_cont) +{ + int i = 0; + unsigned int shift = 0; + + pr_info("%s enter\n", __func__); + + mutex_lock(&aw8697->lock); + + aw8697->ram.baseaddr_shift = 2; + aw8697->ram.ram_shift = 4; + + /* RAMINIT Enable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + + /* base addr */ + shift = aw8697->ram.baseaddr_shift; + aw8697->ram.base_addr = (unsigned int)((aw8697_cont->data[0+shift]<<8) | + (aw8697_cont->data[1+shift])); + pr_info("%s: base_addr=0x%4x\n", __func__, aw8697->ram.base_addr); + + aw8697_i2c_write(aw8697, AW8697_REG_BASE_ADDRH, aw8697_cont->data[0+shift]); + aw8697_i2c_write(aw8697, AW8697_REG_BASE_ADDRL, aw8697_cont->data[1+shift]); + + aw8697_i2c_write(aw8697, AW8697_REG_FIFO_AEH, + (unsigned char)((aw8697->ram.base_addr>>1)>>8)); /*1/2 FIFO*/ + aw8697_i2c_write(aw8697, AW8697_REG_FIFO_AEL, + (unsigned char)((aw8697->ram.base_addr>>1)&0x00FF));/*1/2 FIFO*/ + aw8697_i2c_write(aw8697, AW8697_REG_FIFO_AFH, + (unsigned char)((aw8697->ram.base_addr-(aw8697->ram.base_addr>>2))>>8)); + aw8697_i2c_write(aw8697, AW8697_REG_FIFO_AFL, + (unsigned char)((aw8697->ram.base_addr-(aw8697->ram.base_addr>>2))&0x00FF)); + + /* ram */ + shift = aw8697->ram.baseaddr_shift; + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRH, aw8697_cont->data[0+shift]); + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRL, aw8697_cont->data[1+shift]); + shift = aw8697->ram.ram_shift; + for(i=shift; ilen; i++) { + aw8697_i2c_write(aw8697, AW8697_REG_RAMDATA, aw8697_cont->data[i]); + } + + /* RAMINIT Disable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + + mutex_unlock(&aw8697->lock); + + pr_info("%s exit\n", __func__); +} + + +static void aw8697_ram_loaded(const struct firmware *cont, void *context) +{ + struct aw8697 *aw8697 = context; + struct aw8697_container *aw8697_fw; + int i = 0; + unsigned short check_sum = 0; + #ifdef AWINIC_READ_BIN_FLEXBALLY + static unsigned char load_count =0; + int ram_timer_val = 1000; + load_count++; + #endif + + pr_info("%s enter\n", __func__); + + if (!cont) { + pr_err("%s: failed to read %s\n", __func__, aw8697_ram_name[aw8697->ram_bin_index]); + release_firmware(cont); + #ifdef AWINIC_READ_BIN_FLEXBALLY + if(load_count <=20) + { + schedule_delayed_work(&aw8697->ram_work, msecs_to_jiffies(ram_timer_val)); + pr_info("%s:start hrtimer:load_count%d\n", __func__, load_count); + } + #endif + return; + } + + pr_info("%s: loaded %s - size: %zu\n", __func__, aw8697_ram_name[aw8697->ram_bin_index], + cont ? cont->size : 0); + /* check sum */ + for(i=2; isize; i++) { + check_sum += cont->data[i]; + } + if(check_sum != (unsigned short)((cont->data[0]<<8)|(cont->data[1]))) { + pr_err("%s: check sum err: check_sum=0x%04x\n", __func__, check_sum); + return; + } else { + pr_info("%s: check sum pass : 0x%04x\n", __func__, check_sum); + aw8697->ram.check_sum = check_sum; + } + + /* aw8697 ram update */ + aw8697_fw = kzalloc(cont->size+sizeof(int), GFP_KERNEL); + if (!aw8697_fw) { + release_firmware(cont); + pr_err("%s: Error allocating memory\n", __func__); + return; + } + aw8697_fw->len = cont->size; + memcpy(aw8697_fw->data, cont->data, cont->size); + release_firmware(cont); + + aw8697_container_update(aw8697, aw8697_fw); + + aw8697->ram.len = aw8697_fw->len; + + kfree(aw8697_fw); + + aw8697->ram_init = 1; + pr_info("%s: fw update complete\n", __func__); + aw8697_rtp_update(aw8697); +} + +static int aw8697_ram_update(struct aw8697 *aw8697) +{ + aw8697->ram_init = 0; + aw8697->rtp_init = 0; + + pr_info("%s:aw8697->haptic_real_f0:%d\n", __func__,aw8697->haptic_real_f0); + if (aw8697->haptic_real_f0 <167) + aw8697->ram_bin_index = 0; + else if(aw8697->haptic_real_f0 <169) + aw8697->ram_bin_index = 1; + else if(aw8697->haptic_real_f0 <171) + aw8697->ram_bin_index = 2; + else if(aw8697->haptic_real_f0 <173) + aw8697->ram_bin_index = 3; + else + aw8697->ram_bin_index = 4; + pr_info("%s:haptic bin name %s \n", __func__,aw8697_ram_name[aw8697->ram_bin_index]); + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + aw8697_ram_name[aw8697->ram_bin_index], aw8697->dev, GFP_KERNEL, + aw8697, aw8697_ram_loaded); +} + +#ifdef AWINIC_RAM_UPDATE_DELAY +static void aw8697_ram_work_routine(struct work_struct *work) +{ + struct aw8697 *aw8697 = container_of(work, struct aw8697, ram_work.work); + + pr_info("%s enter\n", __func__); + aw8697_ram_update(aw8697); +} +#endif + +static int aw8697_ram_init(struct aw8697 *aw8697) +{ + +#ifdef AWINIC_RAM_UPDATE_DELAY + int ram_timer_val = 1000; + aw8697->haptic_real_f0 = AW8697_HAPTIC_F0_PRE/10; + + INIT_DELAYED_WORK(&aw8697->ram_work, aw8697_ram_work_routine); + schedule_delayed_work(&aw8697->ram_work, msecs_to_jiffies(ram_timer_val)); +#else + aw8697_ram_update(aw8697); +#endif + return 0; +} + +/***************************************************** + * + * haptic control + * + *****************************************************/ +static int aw8697_haptic_softreset(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + + aw8697_i2c_write(aw8697, AW8697_REG_ID, 0xAA); + usleep_range(3000, 3500); + return 0; +} + +static int aw8697_haptic_active(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_WORK_MODE_MASK, AW8697_BIT_SYSCTRL_ACTIVE); + aw8697_interrupt_clear(aw8697); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_UVLO_MASK, AW8697_BIT_SYSINTM_UVLO_EN); + return 0; +} + +static int aw8697_haptic_play_mode(struct aw8697 *aw8697, unsigned char play_mode) +{ + pr_debug("%s enter\n", __func__); + + switch(play_mode) { + case AW8697_HAPTIC_STANDBY_MODE: + aw8697->play_mode = AW8697_HAPTIC_STANDBY_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_UVLO_MASK, AW8697_BIT_SYSINTM_UVLO_OFF); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_WORK_MODE_MASK, AW8697_BIT_SYSCTRL_STANDBY); + break; + case AW8697_HAPTIC_RAM_MODE: + aw8697->play_mode = AW8697_HAPTIC_RAM_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8697_haptic_active(aw8697); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_ENABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK&AW8697_BIT_SYSCTRL_WORK_MODE_MASK, + AW8697_BIT_SYSCTRL_BST_MODE_BOOST|AW8697_BIT_SYSCTRL_STANDBY); + aw8697_haptic_active(aw8697); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + } + usleep_range(2000, 2500); + break; + case AW8697_HAPTIC_RAM_LOOP_MODE: + aw8697->play_mode = AW8697_HAPTIC_RAM_LOOP_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_DISABLE); + } + if (check_factory_mode()) + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_ENABLE); + aw8697_haptic_active(aw8697); + if (check_factory_mode()) + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + break; + case AW8697_HAPTIC_RTP_MODE: + aw8697->play_mode = AW8697_HAPTIC_RTP_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_RTP); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RTP_DISABLE); + } + aw8697_haptic_active(aw8697); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RTP_ENABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK&AW8697_BIT_SYSCTRL_WORK_MODE_MASK, + AW8697_BIT_SYSCTRL_BST_MODE_BOOST|AW8697_BIT_SYSCTRL_STANDBY); + aw8697_haptic_active(aw8697); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + } + usleep_range(2000, 2500); + break; + case AW8697_HAPTIC_TRIG_MODE: + aw8697->play_mode = AW8697_HAPTIC_TRIG_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8697_haptic_active(aw8697); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_ENABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK&AW8697_BIT_SYSCTRL_WORK_MODE_MASK, + AW8697_BIT_SYSCTRL_BST_MODE_BOOST|AW8697_BIT_SYSCTRL_STANDBY); + aw8697_haptic_active(aw8697); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + } + usleep_range(2000, 2500); + break; + case AW8697_HAPTIC_CONT_MODE: + aw8697->play_mode = AW8697_HAPTIC_CONT_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_CONT); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + if(aw8697->auto_boost) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_RAM_MASK, AW8697_BIT_BST_AUTO_BST_RAM_DISABLE); + } + aw8697_haptic_active(aw8697); + break; + default: + dev_err(aw8697->dev, "%s: play mode %d err", + __func__, play_mode); + break; + } + return 0; +} +/*OP add for juge rtp on begin*/ +static int aw8697_haptic_juge_RTP_is_going_on(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + unsigned char rtp_state = 0; + static unsigned char pre_reg_val; + + aw8697_i2c_read(aw8697, AW8697_REG_SYSCTRL, ®_val); + if((reg_val&AW8697_BIT_SYSCTRL_PLAY_MODE_RTP)&&(!(reg_val&AW8697_BIT_SYSCTRL_STANDBY))) + rtp_state = 1;/*is going on*/ + if (pre_reg_val != reg_val) + pr_debug("%sAW8697_REG_SYSCTRL 0x04==%02x rtp_state=%d\n", __func__,reg_val,rtp_state); + pre_reg_val = reg_val; + if (aw8697->rtp_routine_on) { + pr_debug("%s:rtp_routine_on\n", __func__); + rtp_state = 1;/*is going on*/ + } + aw8697->rtp_on = (bool)rtp_state; + return rtp_state; +} +/*OP add for juge rtp on begin*/ + +static int aw8697_haptic_play_go(struct aw8697 *aw8697, bool flag) +{ + pr_debug("%s enter\n", __func__); + if (!flag) { + do_gettimeofday(&aw8697->current_time); + aw8697->interval_us = (aw8697->current_time.tv_sec-aw8697->pre_enter_time.tv_sec) * 1000000 + + (aw8697->current_time.tv_usec-aw8697->pre_enter_time.tv_usec); + if (aw8697->interval_us < 2000) { + pr_info("aw8697->interval_us t=%ld\n",aw8697->interval_us); + mdelay(2); + } + } + if (flag == true) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_GO, + AW8697_BIT_GO_MASK, AW8697_BIT_GO_ENABLE); + do_gettimeofday(&aw8697->pre_enter_time); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_GO, + AW8697_BIT_GO_MASK, AW8697_BIT_GO_DISABLE); + } + return 0; +} + +static int aw8697_haptic_stop_delay(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + unsigned int cnt = 60; + + while(cnt--) { + aw8697_i2c_read(aw8697, AW8697_REG_GLB_STATE, ®_val); + if((reg_val&0x0f) == 0x00) { + return 0; + } + usleep_range(2000, 2500); + pr_info("%s wait for standby, reg glb_state=0x%02x\n", + __func__, reg_val); + } + pr_err("%s do not enter standby automatically\n", __func__); + + return 0; +} + +int aw8697_op_haptic_stop(void) +{ + pr_debug("%s enter\n", __func__); + if (g_aw8697 == NULL) + return 0; + mutex_lock(&g_aw8697->lock); + if (g_aw8697) { + aw8697_haptic_play_go(g_aw8697, false); + aw8697_haptic_stop_delay(g_aw8697); + aw8697_haptic_play_mode(g_aw8697, AW8697_HAPTIC_STANDBY_MODE); + } + mutex_unlock(&g_aw8697->lock); + + return 0; +} +static void aw8697_haptic_upload_lra(struct aw8697 *aw8697, unsigned int flag); + +static int aw8697_haptic_stop(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); +#ifdef OP_AW_DEBUG + do_gettimeofday(&aw8697->t_stop); +#endif + + aw8697_haptic_play_go(aw8697, false); + aw8697_haptic_stop_delay(aw8697); + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_STANDBY_MODE); + aw8697_haptic_upload_lra(aw8697, 1); + return 0; +} + +static int aw8697_haptic_start(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + aw8697_haptic_play_go(aw8697, true); +#ifdef OP_AW_DEBUG + do_gettimeofday(&aw8697->t_start); + aw8697->game_microsecond = (aw8697->t_start.tv_sec-aw8697->t_stop.tv_sec) * 1000000 + + (aw8697->t_start.tv_usec-aw8697->t_stop.tv_usec); + pr_debug("%s: haptic_audio_delay=%dus\n", __func__, aw8697->game_microsecond); +#endif + return 0; +} + +static int aw8697_haptic_set_wav_seq(struct aw8697 *aw8697, + unsigned char wav, unsigned char seq) +{ + aw8697_i2c_write(aw8697, AW8697_REG_WAVSEQ1+wav, + seq); + return 0; +} + +static int aw8697_haptic_set_wav_loop(struct aw8697 *aw8697, + unsigned char wav, unsigned char loop) +{ + unsigned char tmp = 0; + + if(wav%2) { + tmp = loop<<0; + aw8697_i2c_write_bits(aw8697, AW8697_REG_WAVLOOP1+(wav/2), + AW8697_BIT_WAVLOOP_SEQNP1_MASK, tmp); + } else { + tmp = loop<<4; + aw8697_i2c_write_bits(aw8697, AW8697_REG_WAVLOOP1+(wav/2), + AW8697_BIT_WAVLOOP_SEQN_MASK, tmp); + } + + return 0; +} + +static int aw8697_haptic_set_repeat_wav_seq(struct aw8697 *aw8697, unsigned char seq) +{ + aw8697_haptic_set_wav_seq(aw8697, 0x00, seq); + aw8697_haptic_set_wav_loop(aw8697, 0x00, AW8697_BIT_WAVLOOP_INIFINITELY); + + return 0; +} + + +static int aw8697_haptic_set_bst_vol(struct aw8697 *aw8697, unsigned char bst_vol) +{ + if(bst_vol & 0xe0) { + bst_vol = 0x1f; + } + aw8697_i2c_write_bits(aw8697, AW8697_REG_BSTDBG4, + AW8697_BIT_BSTDBG4_BSTVOL_MASK, (bst_vol<<1)); + return 0; +} + +static int aw8697_haptic_set_bst_peak_cur(struct aw8697 *aw8697, unsigned char peak_cur) +{ + peak_cur &= AW8697_BSTCFG_PEAKCUR_LIMIT; + aw8697_i2c_write_bits(aw8697, AW8697_REG_BSTCFG, + AW8697_BIT_BSTCFG_PEAKCUR_MASK, peak_cur); + return 0; +} + +static int aw8697_haptic_set_gain(struct aw8697 *aw8697, unsigned char gain) +{ + aw8697_i2c_write(aw8697, AW8697_REG_DATDBG, gain); + return 0; +} + +static int aw8697_haptic_set_pwm(struct aw8697 *aw8697, unsigned char mode) +{ + switch(mode) { + case AW8697_PWM_48K: + aw8697_i2c_write_bits(aw8697, AW8697_REG_PWMDBG, + AW8697_BIT_PWMDBG_PWM_MODE_MASK, AW8697_BIT_PWMDBG_PWM_48K); + break; + case AW8697_PWM_24K: + aw8697_i2c_write_bits(aw8697, AW8697_REG_PWMDBG, + AW8697_BIT_PWMDBG_PWM_MODE_MASK, AW8697_BIT_PWMDBG_PWM_24K); + break; + case AW8697_PWM_12K: + aw8697_i2c_write_bits(aw8697, AW8697_REG_PWMDBG, + AW8697_BIT_PWMDBG_PWM_MODE_MASK, AW8697_BIT_PWMDBG_PWM_12K); + break; + default: + break; + } + return 0; +} + +static int aw8697_haptic_play_wav_seq(struct aw8697 *aw8697, unsigned char flag) +{ + pr_debug("%s enter\n", __func__); + + if(flag) { + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_RAM_MODE); + aw8697_haptic_start(aw8697); + } + return 0; +} + +static int aw8697_haptic_play_repeat_seq(struct aw8697 *aw8697, unsigned char flag) +{ + pr_debug("%s enter\n", __func__); + if(flag) { + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_RAM_LOOP_MODE); + aw8697_haptic_start(aw8697); + } + + return 0; +} + +static int aw8697_haptic_swicth_motorprotect_config(struct aw8697 *aw8697, unsigned char addr, unsigned char val) +{ + pr_debug("%s enter\n", __func__); + if(addr == 1) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_PROTECT_MASK, AW8697_BIT_DETCTRL_PROTECT_SHUTDOWN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_PWMPRC, + AW8697_BIT_PWMPRC_PRC_MASK, AW8697_BIT_PWMPRC_PRC_ENABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_PRLVL, + AW8697_BIT_PRLVL_PR_MASK, AW8697_BIT_PRLVL_PR_ENABLE); + } else if (addr == 0) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_PROTECT_MASK, AW8697_BIT_DETCTRL_PROTECT_NO_ACTION); + aw8697_i2c_write_bits(aw8697, AW8697_REG_PWMPRC, + AW8697_BIT_PWMPRC_PRC_MASK, AW8697_BIT_PWMPRC_PRC_DISABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_PRLVL, + AW8697_BIT_PRLVL_PR_MASK, AW8697_BIT_PRLVL_PR_DISABLE); + } else if (addr == 0x2d){ + aw8697_i2c_write_bits(aw8697, AW8697_REG_PWMPRC, + AW8697_BIT_PWMPRC_PRCTIME_MASK, val); + }else if (addr == 0x3e){ + aw8697_i2c_write_bits(aw8697, AW8697_REG_PRLVL, + AW8697_BIT_PRLVL_PRLVL_MASK, val); + }else if (addr == 0x3f){ + aw8697_i2c_write_bits(aw8697, AW8697_REG_PRTIME, + AW8697_BIT_PRTIME_PRTIME_MASK, val); + } else{ + /*nothing to do;*/ + } + return 0; +} + +/***************************************************** + * + * os calibration + * + *****************************************************/ +static int aw8697_haptic_os_calibration(struct aw8697 *aw8697) +{ + unsigned int cont = 2000; + unsigned char reg_val = 0; + pr_debug("%s enter\n", __func__); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_DIAG_GO_MASK, AW8697_BIT_DETCTRL_DIAG_GO_ENABLE); + while(1){ + aw8697_i2c_read(aw8697, AW8697_REG_DETCTRL, ®_val); + if((reg_val & 0x01) == 0 || cont ==0) + break; + cont--; + } + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + return 0; +} +/***************************************************** + * + * trig config + * + *****************************************************/ +static int aw8697_haptic_trig_param_init(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + + aw8697->trig[0].enable = AW8697_TRG1_ENABLE; + aw8697->trig[0].default_level = AW8697_TRG1_DEFAULT_LEVEL; + aw8697->trig[0].dual_edge = AW8697_TRG1_DUAL_EDGE; + aw8697->trig[0].frist_seq = AW8697_TRG1_FIRST_EDGE_SEQ; + aw8697->trig[0].second_seq = AW8697_TRG1_SECOND_EDGE_SEQ; + + aw8697->trig[1].enable = AW8697_TRG2_ENABLE; + aw8697->trig[1].default_level = AW8697_TRG2_DEFAULT_LEVEL; + aw8697->trig[1].dual_edge = AW8697_TRG2_DUAL_EDGE; + aw8697->trig[1].frist_seq = AW8697_TRG2_FIRST_EDGE_SEQ; + aw8697->trig[1].second_seq = AW8697_TRG2_SECOND_EDGE_SEQ; + + aw8697->trig[2].enable = AW8697_TRG3_ENABLE; + aw8697->trig[2].default_level = AW8697_TRG3_DEFAULT_LEVEL; + aw8697->trig[2].dual_edge = AW8697_TRG3_DUAL_EDGE; + aw8697->trig[2].frist_seq = AW8697_TRG3_FIRST_EDGE_SEQ; + aw8697->trig[2].second_seq = AW8697_TRG3_SECOND_EDGE_SEQ; + + return 0; +} +static int aw8697_haptic_trig_param_config(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + + if(aw8697->trig[0].default_level) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG1_POLAR_MASK, AW8697_BIT_TRGCFG1_TRG1_POLAR_NEG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG1_POLAR_MASK, AW8697_BIT_TRGCFG1_TRG1_POLAR_POS); + } + if(aw8697->trig[1].default_level) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG2_POLAR_MASK, AW8697_BIT_TRGCFG1_TRG2_POLAR_NEG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG2_POLAR_MASK, AW8697_BIT_TRGCFG1_TRG2_POLAR_POS); + } + if(aw8697->trig[2].default_level) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG3_POLAR_MASK, AW8697_BIT_TRGCFG1_TRG3_POLAR_NEG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG3_POLAR_MASK, AW8697_BIT_TRGCFG1_TRG3_POLAR_POS); + } + + if(aw8697->trig[0].dual_edge) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG1_EDGE_MASK, AW8697_BIT_TRGCFG1_TRG1_EDGE_POS_NEG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG1_EDGE_MASK, AW8697_BIT_TRGCFG1_TRG1_EDGE_POS); + } + if(aw8697->trig[1].dual_edge) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG2_EDGE_MASK, AW8697_BIT_TRGCFG1_TRG2_EDGE_POS_NEG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG2_EDGE_MASK, AW8697_BIT_TRGCFG1_TRG2_EDGE_POS); + } + if(aw8697->trig[2].dual_edge) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG3_EDGE_MASK, AW8697_BIT_TRGCFG1_TRG3_EDGE_POS_NEG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG1, + AW8697_BIT_TRGCFG1_TRG3_EDGE_MASK, AW8697_BIT_TRGCFG1_TRG3_EDGE_POS); + } + + if(aw8697->trig[0].frist_seq) { + aw8697_i2c_write(aw8697, AW8697_REG_TRG1_WAV_P, aw8697->trig[0].frist_seq); + } + if(aw8697->trig[0].second_seq && aw8697->trig[0].dual_edge) { + aw8697_i2c_write(aw8697, AW8697_REG_TRG1_WAV_N, aw8697->trig[0].second_seq); + } + if(aw8697->trig[1].frist_seq) { + aw8697_i2c_write(aw8697, AW8697_REG_TRG2_WAV_P, aw8697->trig[1].frist_seq); + } + if(aw8697->trig[1].second_seq && aw8697->trig[1].dual_edge) { + aw8697_i2c_write(aw8697, AW8697_REG_TRG2_WAV_N, aw8697->trig[1].second_seq); + } + if(aw8697->trig[2].frist_seq) { + aw8697_i2c_write(aw8697, AW8697_REG_TRG3_WAV_P, aw8697->trig[1].frist_seq); + } + if(aw8697->trig[2].second_seq && aw8697->trig[2].dual_edge) { + aw8697_i2c_write(aw8697, AW8697_REG_TRG3_WAV_N, aw8697->trig[1].second_seq); + } + + return 0; +} + +static int aw8697_haptic_trig_enable_config(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG2, + AW8697_BIT_TRGCFG2_TRG1_ENABLE_MASK, aw8697->trig[0].enable); + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG2, + AW8697_BIT_TRGCFG2_TRG2_ENABLE_MASK, aw8697->trig[1].enable); + aw8697_i2c_write_bits(aw8697, AW8697_REG_TRG_CFG2, + AW8697_BIT_TRGCFG2_TRG3_ENABLE_MASK, aw8697->trig[2].enable); + return 0; +} +static int aw8697_haptic_auto_boost_config(struct aw8697 *aw8697, unsigned char flag) +{ + aw8697->auto_boost = flag; + if(flag) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_AUTOSW_MASK, AW8697_BIT_BST_AUTO_BST_AUTOMATIC_BOOST); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_BST_AUTO, + AW8697_BIT_BST_AUTO_BST_AUTOSW_MASK, AW8697_BIT_BST_AUTO_BST_MANUAL_BOOST); + } + return 0; +} + +/***************************************************** + * + * vbat mode + * + *****************************************************/ +static int aw8697_haptic_cont_vbat_mode(struct aw8697 *aw8697, unsigned char flag) +{ + if(flag == AW8697_HAPTIC_CONT_VBAT_HW_COMP_MODE) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_ADCTEST, + AW8697_BIT_ADCTEST_VBAT_MODE_MASK, AW8697_BIT_ADCTEST_VBAT_HW_COMP); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_ADCTEST, + AW8697_BIT_ADCTEST_VBAT_MODE_MASK, AW8697_BIT_ADCTEST_VBAT_SW_COMP); + } + return 0; +} + +static int aw8697_haptic_get_vbat(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + unsigned int cont = 2000; + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_VBAT_GO_MASK, AW8697_BIT_DETCTRL_VABT_GO_ENABLE); + + while(1){ + aw8697_i2c_read(aw8697, AW8697_REG_DETCTRL, ®_val); + if((reg_val & 0x02) == 0 || cont == 0) + break; + cont--; + } + + aw8697_i2c_read(aw8697, AW8697_REG_VBATDET, ®_val); + aw8697->vbat = 6100 * reg_val / 256; + if(aw8697->vbat > AW8697_VBAT_MAX) { + aw8697->vbat = AW8697_VBAT_MAX; + pr_debug("%s vbat max limit = %dmV\n", __func__, aw8697->vbat); + } + if(aw8697->vbat < AW8697_VBAT_MIN) { + aw8697->vbat = AW8697_VBAT_MIN; + pr_debug("%s vbat min limit = %dmV\n", __func__, aw8697->vbat); + } + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + + return 0; +} + +static int aw8697_haptic_ram_vbat_comp(struct aw8697 *aw8697, bool flag) +{ + int temp_gain = 0; + + if(flag) { + if(aw8697->ram_vbat_comp == AW8697_HAPTIC_RAM_VBAT_COMP_ENABLE) { + aw8697_haptic_get_vbat(aw8697); + temp_gain = aw8697->gain * AW8697_VBAT_REFER / aw8697->vbat; + if(temp_gain > (128*AW8697_VBAT_REFER/AW8697_VBAT_MIN)) { + temp_gain = 128*AW8697_VBAT_REFER/AW8697_VBAT_MIN; + pr_debug("%s gain limit=%d\n", __func__, temp_gain); + } + aw8697_haptic_set_gain(aw8697, temp_gain); + } else { + aw8697_haptic_set_gain(aw8697, aw8697->gain); + } + } else { + aw8697_haptic_set_gain(aw8697, aw8697->gain); + } + + return 0; +} + +/***************************************************** + * + * f0 + * + *****************************************************/ +static int aw8697_haptic_set_f0_preset(struct aw8697 *aw8697) +{ + unsigned int f0_reg = 0; + + pr_debug("%s enter\n", __func__); + + f0_reg = 1000000000/(aw8697->f0_pre*AW8697_HAPTIC_F0_COEFF); + aw8697_i2c_write(aw8697, AW8697_REG_F_PRE_H, (unsigned char)((f0_reg>>8)&0xff)); + aw8697_i2c_write(aw8697, AW8697_REG_F_PRE_L, (unsigned char)((f0_reg>>0)&0xff)); + + return 0; +} + +static int haptic_read_f0_count_go(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + ret = aw8697_i2c_read(aw8697, AW8697_REG_F_LRA_CONT_H, ®_val); + f0_reg = (reg_val<<8); + ret = aw8697_i2c_read(aw8697, AW8697_REG_F_LRA_CONT_L, ®_val); + f0_reg |= (reg_val<<0); + if (!f0_reg) { + pr_info("%s not get f0 because f0_reg value is 0!\n",__func__); + return 0; + } + f0_tmp = 1000000000/(f0_reg*AW8697_HAPTIC_F0_COEFF); + aw8697->f0 = (unsigned int)f0_tmp; + aw8697->f0 += 30; + return 0; +} + +static int haptic_read_f0_count_default(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + ret = aw8697_i2c_read(aw8697, AW8697_REG_F_LRA_F0_H, ®_val); + f0_reg = (reg_val<<8); + ret = aw8697_i2c_read(aw8697, AW8697_REG_F_LRA_F0_L, ®_val); + f0_reg |= (reg_val<<0); + if (!f0_reg) { + pr_info("%s not get f0 because f0_reg vaule is 0\n", __func__); + return 0; + } + f0_tmp = 1000000000/(f0_reg*AW8697_HAPTIC_F0_COEFF); + aw8697->f0 = (unsigned int)f0_tmp; + return 0; +} + +static int aw8697_haptic_read_f0(struct aw8697 *aw8697) +{ + + pr_debug("%s enter\n", __func__); + if (aw8697->count_go) { + haptic_read_f0_count_go(aw8697); + } else { + haptic_read_f0_count_default(aw8697); + } + pr_info("%s f0=%d\n", __func__, aw8697->f0); + + return 0; +} + +static int aw8697_haptic_read_cont_f0(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_reg = 0; + unsigned long f0_tmp = 0; + + pr_debug("%s enter\n", __func__); + + ret = aw8697_i2c_read(aw8697, AW8697_REG_F_LRA_CONT_H, ®_val); + f0_reg = (reg_val<<8); + ret = aw8697_i2c_read(aw8697, AW8697_REG_F_LRA_CONT_L, ®_val); + f0_reg |= (reg_val<<0); + if (!f0_reg) { + pr_info("%s not get f0 because f0_reg vaule is 0\n", __func__); + return 0; + } + f0_tmp = 1000000000/(f0_reg*AW8697_HAPTIC_F0_COEFF); + aw8697->cont_f0 = (unsigned int)f0_tmp; + pr_info("%s f0=%d\n", __func__, aw8697->cont_f0); + + return 0; +} + +static int aw8697_haptic_read_beme(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char reg_val = 0; + + ret = aw8697_i2c_read(aw8697, AW8697_REG_WAIT_VOL_MP, ®_val); + aw8697->max_pos_beme = (reg_val<<0); + ret = aw8697_i2c_read(aw8697, AW8697_REG_WAIT_VOL_MN, ®_val); + aw8697->max_neg_beme = (reg_val<<0); + + pr_info("%s max_pos_beme=%d\n", __func__, aw8697->max_pos_beme); + pr_info("%s max_neg_beme=%d\n", __func__, aw8697->max_neg_beme); + + return 0; +} + +static int aw8697_haptic_read_bemf(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int bemf = 0; + + ret = aw8697_i2c_read(aw8697, AW8697_REG_BEMF_VOL_H, ®_val); + bemf |= (reg_val<<8); + ret = aw8697_i2c_read(aw8697, AW8697_REG_BEMF_VOL_L, ®_val); + bemf |= (reg_val<<0); + + pr_info("%s bemf=%d\n", __func__, bemf); + + return 0; +} + + + +/***************************************************** + * + * rtp + * + *****************************************************/ +static void aw8697_haptic_set_rtp_aei(struct aw8697 *aw8697, bool flag) +{ + if(flag) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_FF_AE_MASK, AW8697_BIT_SYSINTM_FF_AE_EN); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_FF_AE_MASK, AW8697_BIT_SYSINTM_FF_AE_OFF); + } +} + +static unsigned char aw8697_haptic_rtp_get_fifo_afi(struct aw8697 *aw8697) +{ + unsigned char ret = 0; + unsigned char reg_val = 0; + + if(aw8697->osc_cali_flag==1){ + aw8697_i2c_read(aw8697, AW8697_REG_SYSST, ®_val); + reg_val &= AW8697_BIT_SYSST_FF_AFS; + ret = reg_val>>3; + }else{ + aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + reg_val &= AW8697_BIT_SYSINT_FF_AFI; + ret = reg_val>>3; + } + + return ret; +} + +/***************************************************** + * + * rtp + * + *****************************************************/ +static int aw8697_haptic_rtp_init(struct aw8697 *aw8697) +{ + unsigned int buf_len = 0; + unsigned char reg_val = 0; + + pr_info("%s enter\n", __func__); + msm_cpuidle_set_sleep_disable(true); + aw8697->rtp_cnt = 0; + + mutex_lock(&aw8697->rtp_lock); + while((!aw8697_haptic_rtp_get_fifo_afi(aw8697)) && + (aw8697->play_mode == AW8697_HAPTIC_RTP_MODE)) { + pr_info("%s rtp cnt = %d\n", __func__, aw8697->rtp_cnt); + if ((aw8697->rtp_cnt < aw8697->ram.base_addr)) {//first frame rtp_cnt is 0 + if((aw8697_rtp->len-aw8697->rtp_cnt) < (aw8697->ram.base_addr)) { + buf_len = aw8697_rtp->len-aw8697->rtp_cnt;//rtp len less than fifo space,buf len is rtp cnt + } else { + buf_len = (aw8697->ram.base_addr);//first frame buf len is fifo space + } + } else if((aw8697_rtp->len-aw8697->rtp_cnt) < (aw8697->ram.base_addr>>2)) { + buf_len = aw8697_rtp->len-aw8697->rtp_cnt; + } else { + buf_len = (aw8697->ram.base_addr>>2); + } + aw8697_i2c_writes(aw8697, AW8697_REG_RTP_DATA, + &aw8697_rtp->data[aw8697->rtp_cnt], buf_len); + aw8697->rtp_cnt += buf_len; + aw8697_i2c_read(aw8697, AW8697_REG_GLB_STATE, ®_val); + if (aw8697->rtp_cnt == aw8697_rtp->len + || !buf_len + || (!(reg_val & 0x0f) && (aw8697->rtp_cnt >= RTP_INIT_OVERSTEP_THR))) { + pr_info("%s: rtp complete,buf_len:%d,reg_val:0x%x\n", + __func__, buf_len, reg_val); + aw8697->rtp_cnt = 0; + aw8697->rtp_is_playing = 0; + mutex_unlock(&aw8697->rtp_lock); + msm_cpuidle_set_sleep_disable(false); + return 0; + } + } + mutex_unlock(&aw8697->rtp_lock); + + if(aw8697->play_mode == AW8697_HAPTIC_RTP_MODE) { + aw8697_haptic_set_rtp_aei(aw8697, true); + } + + pr_info("%s exit\n", __func__); + msm_cpuidle_set_sleep_disable(false); + return 0; +} +static void aw8697_haptic_upload_lra(struct aw8697 *aw8697, unsigned int flag) +{ + switch (flag) { + case 1: + pr_debug("%s f0_cali_lra=%d\n", __func__, aw8697->f0_calib_data); + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, + (char)aw8697->f0_calib_data); + break; + case 2: + pr_debug("%s rtp_cali_lra=%d\n", __func__, aw8697->lra_calib_data); + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, + (char)aw8697->lra_calib_data); + break; + default: + break; + } +} +static int aw8697_clock_OSC_trim_calibration(unsigned long int theory_time, unsigned long int real_time) +{ + unsigned int real_code = 0; + unsigned int LRA_TRIM_CODE = 0; + unsigned int DFT_LRA_TRIM_CODE = 0; + unsigned int Not_need_cali_threshold = 10;/*0.1 percent not need calibrate*/ + + if(theory_time == real_time ) { + pr_info("aw_osctheory_time == real_time:%ld theory_time = %ld not need to cali\n",real_time,theory_time); + return 0; + } else if(theory_time < real_time ){ + if((real_time - theory_time) > (theory_time/50 )) + { + pr_info("aw_osc(real_time - theory_time) > (theory_time/50 ) not to cali\n"); + return DFT_LRA_TRIM_CODE; + } + + if ((real_time - theory_time) < (Not_need_cali_threshold*theory_time/10000)) + { + pr_info("aw_oscmicrosecond:%ld theory_time = %ld not need to cali\n",real_time,theory_time); + return DFT_LRA_TRIM_CODE; + } + + real_code = ((real_time - theory_time)* 4000) / theory_time; + real_code = ((real_code%10 < 5)? 0 : 1) + real_code/10; + real_code = 32 + real_code; + } else if(theory_time > real_time){ + if(( theory_time - real_time) > (theory_time/50 )) + { + pr_info("aw_osc(( theory_time - real_time) > (theory_time/50 )) not to cali \n"); + return DFT_LRA_TRIM_CODE; + } + if ((theory_time - real_time) < (Not_need_cali_threshold*theory_time/10000)) + { + pr_info("aw_oscmicrosecond:%ld theory_time = %ld not need to cali\n",real_time,theory_time); + return DFT_LRA_TRIM_CODE; + } + real_code = ((theory_time - real_time)* 4000) / theory_time ; + real_code = ((real_code%10 < 5)? 0 : 1) + real_code/10; + real_code = 32 - real_code; + } + if (real_code>31) + LRA_TRIM_CODE = real_code -32; + else + LRA_TRIM_CODE = real_code +32; + pr_info("aw_oscmicrosecond:%ld theory_time = %ld real_code =0X%02X LRA_TRIM_CODE 0X%02X\n",real_time,theory_time,real_code,LRA_TRIM_CODE); + + return LRA_TRIM_CODE; +} + +static int aw8697_rtp_trim_lra_calibration(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + unsigned int fre_val = 0; + unsigned int theory_time = 0; + unsigned int lra_rtim_code = 0; + + aw8697_i2c_read(aw8697, AW8697_REG_PWMDBG, ®_val); + fre_val = (reg_val & 0x006f )>> 5; + + if(fre_val == 3) + theory_time = (aw8697->rtp_len / 12000) * 1000000; /*12K */ + if(fre_val == 2) + theory_time = (aw8697->rtp_len / 24000) * 1000000; /*24K */ + if(fre_val == 1 || fre_val == 0) + theory_time = (aw8697->rtp_len / 48000) * 1000000; /*48K */ + + printk("microsecond:%ld theory_time = %d\n",aw8697->microsecond,theory_time); + + lra_rtim_code = aw8697_clock_OSC_trim_calibration(theory_time,aw8697->microsecond); + if (lra_rtim_code >= 0) { + aw8697->lra_calib_data = lra_rtim_code; + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, (char)lra_rtim_code); + } + return 0; +} +static unsigned char aw8697_haptic_osc_read_int(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + aw8697_i2c_read(aw8697, AW8697_REG_DBGSTAT, ®_val); + return reg_val; +} +static int aw8697_rtp_osc_calibration(struct aw8697 *aw8697) +{ + const struct firmware *rtp_file; + int ret = -1; + unsigned int buf_len = 0; + unsigned char osc_int_state = 0; + aw8697->rtp_cnt = 0; + aw8697->timeval_flags = 1; + aw8697->osc_cali_flag =1; + + pr_info("%s enter\n", __func__); + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8697_rtp_name[/*aw8697->rtp_file_num*/ 0], + aw8697->dev); + if(ret < 0) + { + pr_err("%s: failed to read %s\n", __func__, + aw8697_rtp_name[/*aw8697->rtp_file_num*/ 0]); + return ret; + } + /*op add stop,for irq interrupt during calibrate*/ + aw8697_haptic_stop(aw8697); + aw8697_haptic_upload_lra(aw8697, 2); + aw8697->rtp_init = 0; + mutex_lock(&aw8697->rtp_lock); + vfree(aw8697_rtp); + aw8697_rtp = vmalloc(rtp_file->size+sizeof(int)); + if (!aw8697_rtp) { + release_firmware(rtp_file); + mutex_unlock(&aw8697->rtp_lock); + pr_err("%s: error allocating memory\n", __func__); + return -1; + } + aw8697_rtp->len = rtp_file->size; + aw8697->rtp_len = rtp_file->size; + pr_info("%s: rtp file [%s] size = %d\n", __func__, + aw8697_rtp_name[/*aw8697->rtp_file_num*/ 0], aw8697_rtp->len); + memcpy(aw8697_rtp->data, rtp_file->data, rtp_file->size); + release_firmware(rtp_file); + mutex_unlock(&aw8697->rtp_lock); + + /* gain */ + aw8697_haptic_ram_vbat_comp(aw8697, false); + + /* rtp mode config */ + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_RTP_MODE); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_DBGCTRL, + AW8697_BIT_DBGCTRL_INT_MODE_MASK, AW8697_BIT_DBGCTRL_INT_MODE_EDGE); + disable_irq(gpio_to_irq(aw8697->irq_gpio)); + /* haptic start */ + aw8697_haptic_start(aw8697); + pm_qos_add_request(&pm_qos_req_vb, PM_QOS_CPU_DMA_LATENCY, PM_QOS_VALUE_VB); + while(1) { + if(!aw8697_haptic_rtp_get_fifo_afi(aw8697)) { + pr_info("%s !aw8697_haptic_rtp_get_fifo_afi done aw8697->rtp_cnt= %d \n", __func__,aw8697->rtp_cnt); + mutex_lock(&aw8697->rtp_lock); + if((aw8697_rtp->len-aw8697->rtp_cnt) < (aw8697->ram.base_addr>>2)) + buf_len = aw8697_rtp->len-aw8697->rtp_cnt; + else + buf_len = (aw8697->ram.base_addr>>2); + if (aw8697->rtp_cnt != aw8697_rtp->len) { + if(aw8697->timeval_flags ==1) { + do_gettimeofday(&aw8697->start); + aw8697->timeval_flags = 0; + } + aw8697_i2c_writes(aw8697, AW8697_REG_RTP_DATA,&aw8697_rtp->data[aw8697->rtp_cnt], buf_len); + aw8697->rtp_cnt += buf_len; + } + mutex_unlock(&aw8697->rtp_lock); + } + osc_int_state = aw8697_haptic_osc_read_int(aw8697); + if(osc_int_state&AW8697_BIT_SYSINT_DONEI) { + do_gettimeofday(&aw8697->end); + pr_info("%s vincent playback done aw8697->rtp_cnt= %d \n", __func__,aw8697->rtp_cnt); + break; + } + + do_gettimeofday(&aw8697->end); + aw8697->microsecond = (aw8697->end.tv_sec - aw8697->start.tv_sec)*1000000 + + (aw8697->end.tv_usec - aw8697->start.tv_usec); + if (aw8697->microsecond > OP_OCS_CALIBRATION_T_LENGTH) { + pr_info("%s vincent time out aw8697->rtp_cnt %d osc_int_state %02x\n", __func__,aw8697->rtp_cnt, osc_int_state); + break; + } + } + pm_qos_remove_request(&pm_qos_req_vb); + enable_irq(gpio_to_irq(aw8697->irq_gpio)); + + aw8697->osc_cali_flag =0; + aw8697->microsecond = (aw8697->end.tv_sec - aw8697->start.tv_sec)*1000000 + + (aw8697->end.tv_usec - aw8697->start.tv_usec); + /*calibration osc*/ + pr_info("%s 2018_microsecond:%ld \n",__func__,aw8697->microsecond); + pr_info("%s exit\n", __func__); + return 0; +} + +static int aw8697_haptic_osc_set_default_trim(struct aw8697 *aw8697) +{ + pr_info("%s enter\n", __func__); + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA,AW8697_TRIM_DEFAULT); + return 0; +} + +static void aw8697_op_clean_status(struct aw8697 *aw8697) +{ + aw8697->audio_ready = false; + aw8697->haptic_ready = false; + aw8697->pre_haptic_number = 0; + aw8697->rtp_routine_on = 0; + aw8697->rtp_on = 0; + aw8697->rtp_is_playing = 0; + aw8697->sin_add_flag = 0; + pr_info("%s enter\n", __FUNCTION__); +} + +#define RTP_500MS_FIRST_SINE_PLACE 141 +#define ONE_SINE_DATA_LENGHT 141 +#define ONE_SINE_DATA_TIME 588//5.88ms +unsigned char one_sine_data[] = { + 0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x08,0x09,0x0a,0x0b,0x0b,0x0c, + 0x0d,0x0d,0x0e,0x0f,0x0f,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x13, + 0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x14,0x13,0x13,0x13,0x13,0x12,0x12,0x12,0x11, + 0x11,0x10,0x10,0x0f,0x0e,0x0e,0x0d,0x0d,0x0c,0x0b,0x0a,0x0a,0x09,0x08,0x07,0x06, + 0x05,0x05,0x04,0x03,0x02,0x01,0x00,0x00,0xff,0xfe,0xfd,0xfd,0xfc,0xfb,0xfa,0xf9, + 0xf8,0xf7,0xf7,0xf6,0xf5,0xf4,0xf4,0xf3,0xf2,0xf2,0xf1,0xf0,0xf0,0xef,0xef,0xef, + 0xee,0xee,0xed,0xed,0xed,0xed,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xed, + 0xed,0xed,0xed,0xee,0xee,0xef,0xef,0xf0,0xf0,0xf1,0xf1,0xf2,0xf2,0xf3,0xf4,0xf4, + 0xf5,0xf6,0xf7,0xf8,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,0xff, +}; + +static void aw8697_update_sin_rtp_data(struct aw8697 *aw8697) +{ + aw8697->sin_num = ((aw8697->duration-500)*100/ONE_SINE_DATA_TIME) + 1; + aw8697->sin_data_lenght = (size_t)(aw8697->sin_num * ONE_SINE_DATA_LENGHT); + //pr_err("%s %d sinnum: %d sin_data_lenght: %d\n", __func__,__LINE__,aw8697->sin_num,aw8697->sin_data_lenght); +} + +static void aw8697_update_rtp_data(struct aw8697 *aw8697, const struct firmware *rtp_file) +{ + int i = 0; + size_t data_location = 0; + unsigned char *temp_rtp_data = NULL; + + temp_rtp_data = vmalloc(aw8697_rtp->len); + if (temp_rtp_data == NULL ) { + pr_err("%s: vmalloc memory fail\n", __func__); + return; + } + memset(temp_rtp_data, 0x00, aw8697_rtp->len); + // start signal data + memcpy(temp_rtp_data, rtp_file->data, RTP_500MS_FIRST_SINE_PLACE); + data_location += RTP_500MS_FIRST_SINE_PLACE; + // add sin_num sine data + for (i = 1; i <= aw8697->sin_num; i++) { + memcpy(temp_rtp_data + data_location, one_sine_data, ONE_SINE_DATA_LENGHT); + data_location += ONE_SINE_DATA_LENGHT; + } + + // other rtp data + memcpy(temp_rtp_data + data_location, rtp_file->data + RTP_500MS_FIRST_SINE_PLACE, rtp_file->size-RTP_500MS_FIRST_SINE_PLACE); + + // cp to aw8697_rtp + memcpy(aw8697_rtp->data, temp_rtp_data, aw8697_rtp->len); + + vfree(temp_rtp_data); +} + + +static void aw8697_rtp_work_routine(struct work_struct *work) +{ + const struct firmware *rtp_file; + int ret = -1; + struct aw8697 *aw8697 = container_of(work, struct aw8697, rtp_work); + + pr_info("%s enter,aw8697->rtp_file_num:%d\n", __func__,aw8697->rtp_file_num); + if (aw8697->rtp_file_num == 0) { + pr_info("rtp_file_num return\n"); + aw8697->rtp_is_playing = 0; + return; + } + aw8697->rtp_routine_on = 1; + /* fw loaded */ + ret = request_firmware(&rtp_file, + aw8697_rtp_name[aw8697->rtp_file_num], + aw8697->dev); + if(ret < 0) + { + pr_err("%s: failed to read %s\n", __func__, + aw8697_rtp_name[aw8697->rtp_file_num]); + aw8697->rtp_routine_on = 0; + aw8697->rtp_is_playing = 0; + return; + } + aw8697->rtp_init = 0; + mutex_lock(&aw8697->rtp_lock); + vfree(aw8697_rtp); + if (aw8697->sin_add_flag == 1) { + aw8697_update_sin_rtp_data(aw8697); + aw8697_rtp = vmalloc(rtp_file->size + aw8697->sin_data_lenght + sizeof(int)); + aw8697_rtp->len = rtp_file->size + aw8697->sin_data_lenght; + } else { + aw8697_rtp = vmalloc(rtp_file->size+sizeof(int)); + aw8697_rtp->len = rtp_file->size; + } + + if (!aw8697_rtp) { + release_firmware(rtp_file); + pr_err("%s: error allocating memory\n", __func__); + aw8697_op_clean_status(aw8697); + aw8697->rtp_routine_on = 0; + aw8697->rtp_is_playing = 0; + mutex_unlock(&aw8697->rtp_lock); + return; + } + //aw8697_rtp->len = rtp_file->size; + pr_info("%s: rtp file [%s] size = %d\n", __func__, + aw8697_rtp_name[aw8697->rtp_file_num], aw8697_rtp->len); + if (aw8697->sin_add_flag == 1) { + aw8697_update_rtp_data(aw8697, rtp_file); + aw8697->sin_add_flag = 0; + } else + memcpy(aw8697_rtp->data, rtp_file->data, rtp_file->size); + mutex_unlock(&aw8697->rtp_lock); + release_firmware(rtp_file); + + mutex_lock(&aw8697->lock); + aw8697->rtp_init = 1; + aw8697_haptic_upload_lra(aw8697, 2); + /* gain */ + aw8697_haptic_ram_vbat_comp(aw8697, false); + + /* rtp mode config */ + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_RTP_MODE); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_DBGCTRL, + AW8697_BIT_DBGCTRL_INT_MODE_MASK, AW8697_BIT_DBGCTRL_INT_MODE_EDGE); + /* haptic start */ + aw8697_haptic_start(aw8697); + aw8697_haptic_rtp_init(aw8697); + mutex_unlock(&aw8697->lock); + aw8697->rtp_routine_on = 0; +} + +/***************************************************** + * + * haptic - audio + * + *****************************************************/ +static int aw8697_haptic_audio_tp_list_match(struct shake_point *pt_info, struct haptic_audio_trust_zone *p_tmp) +{ + if ((pt_info->x+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W > p_tmp->x) && + (pt_info->x < p_tmp->x+p_tmp->w+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W) && + (pt_info->y+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H> p_tmp->y) && + (pt_info->y < p_tmp->y+p_tmp->h+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H)) { + +#ifdef SECOND_SCOREMODE + //p_tmp->level = (p_tmp->level < TRUST_LEVEL) ? (++p_tmp->level) : p_tmp->level; + if(p_tmp->level >= TRUST_LEVEL){ + return 1; + }else{ + return 2; + } +#else + return 1; +#endif + } else { + return 0; + } +} + +static int aw8697_haptic_audio_tz_list_match(struct haptic_audio_trust_zone *p_tmp, struct trust_zone_info *p_tmp_new) +{ + int match = 0; + int deta_x = 0; + int deta_y = 0; + int deta_x_w = 0; + int deta_y_h = 0; + unsigned int h = (p_tmp->h > p_tmp_new->h) ? p_tmp_new->h : p_tmp->h; + unsigned int w = (p_tmp->w > p_tmp_new->w) ? p_tmp_new->w : p_tmp->w; + + deta_x = p_tmp->x - p_tmp_new->x; + deta_y = p_tmp->y - p_tmp_new->y; + deta_x_w = (p_tmp->x+p_tmp->w)-(p_tmp_new->x+p_tmp_new->w); + deta_y_h = (p_tmp->y+p_tmp->h)-(p_tmp_new->y+p_tmp_new->h); + + if((ABS(deta_x)x,p_tmp->y,p_tmp->x+p_tmp->w,p_tmp->y+p_tmp->h,p_tmp_new->x, + p_tmp_new->y,p_tmp_new->x+p_tmp_new->w,p_tmp_new->y+p_tmp_new->h,deta_x,deta_y,deta_x_w,deta_y_h); + return match; +} + +static int aw8697_haptic_audio_tz_list_show(struct haptic_audio *haptic_audio) +{ + struct haptic_audio_trust_zone *p_tmp = NULL; + unsigned int i = 0; + + list_for_each_entry(p_tmp, &haptic_audio->list, list) { + pr_debug("%s: tz[%02d]: [%01d, %04d, %04d, %04d, %04d]\n", + __func__, i, p_tmp->level, p_tmp->x, p_tmp->y, + p_tmp->w, p_tmp->h); + i++; + + } + return 0; +} + +static int aw8697_haptic_audio_tz_score_list_clear(struct haptic_audio *haptic_audio) +{ + struct haptic_audio_trust_zone *p_tmp = NULL; + struct haptic_audio_trust_zone *p_tmp_bak = NULL; + + list_for_each_entry_safe(p_tmp, p_tmp_bak, &(haptic_audio->score_list), list) { + list_del(&p_tmp->list); + kfree(p_tmp); + } + + return 0; +} + +static int aw8697_haptic_audio_tz_list_insert( + struct haptic_audio *haptic_audio, struct trust_zone_info *tz_info) +{ + struct haptic_audio_trust_zone *p_new = NULL; + + pr_debug("%s: enter\n", __func__); + + p_new = (struct haptic_audio_trust_zone *)kzalloc( + sizeof(struct haptic_audio_trust_zone), GFP_KERNEL); + if (p_new == NULL ) { + pr_err("%s: kzalloc memory fail\n", __func__); + return -1; + } + + /* update new list info */ + p_new->level = tz_info->level; + p_new->cnt = haptic_audio->tz_cnt_thr * 2; + p_new->x = tz_info->x; + p_new->y = tz_info->y; + p_new->w = tz_info->w; + p_new->h = tz_info->h; + p_new->dirty = 0; + + INIT_LIST_HEAD(&(p_new->list)); + +#ifdef SECOND_SCOREMODE + list_add(&(p_new->list), &(haptic_audio->list)); + haptic_audio->tz_num = haptic_audio->tz_num +1; +#else + if(haptic_audio->tz_init){ + list_add(&(p_new->list), &(haptic_audio->score_list)); + haptic_audio->tz_num += 1; + pr_debug("%s scorelist_num = %d\n", __func__, haptic_audio->tz_num); + }else + list_add(&(p_new->list), &(haptic_audio->list)); +#endif + + return 0; +} + +static int aw8697_haptic_audio_ctr_list_insert( + struct haptic_audio *haptic_audio, struct haptic_ctr *haptic_ctr) +{ + struct haptic_ctr *p_new = NULL; + + p_new = (struct haptic_ctr *)kzalloc( + sizeof(struct haptic_ctr), GFP_KERNEL); + if (p_new == NULL ) { + pr_err("%s: kzalloc memory fail\n", __func__); + return -1; + } + /* update new list info */ + p_new->cnt = haptic_ctr->cnt; + p_new->cmd = haptic_ctr->cmd; + p_new->play = haptic_ctr->play; + p_new->wavseq = haptic_ctr->wavseq; + p_new->loop = haptic_ctr->loop; + p_new->gain = haptic_ctr->gain; + + INIT_LIST_HEAD(&(p_new->list)); + list_add(&(p_new->list), &(haptic_audio->ctr_list)); + + return 0; +} + + +static int aw8697_haptic_audio_ctr_list_clear(struct haptic_audio *haptic_audio) +{ + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, &(haptic_audio->ctr_list), list) { + list_del(&p_ctr->list); + kfree(p_ctr); + } + + return 0; +} + +static int aw8697_fb_notifier_callback_tp(struct notifier_block *self, unsigned long event, void *data) +{ + struct aw8697 *aw8697 = container_of(self, struct aw8697, fb_notif); + struct tp *tp = &(aw8697->haptic_audio.tp); + int i = 0; + int *blank; + struct fb_event *evdata = data; + struct haptic_audio *haptic_audio = NULL; + struct haptic_audio_trust_zone *p_tmp = NULL; + + haptic_audio = &(aw8697->haptic_audio); + + blank = evdata->data; + pr_debug("%s: tp event = %ld, blank = %d\n", __func__, event, *blank); + i= *blank; +#if 0 + if (event == 11) { + pr_debug("%s: tp down\n", __func__); + pr_debug("%s: tp record_point_down[%d].status = %d\n", __func__, i, record_point[i].status); + if((AW8697_HAPTIC_TP_ST_PRESS == record_point[i].status) && + (record_point[i].status != tp->id[i].pt_info.status)) { + tp->id[i].pt_info.status = record_point[i].status; + tp->id[i].tp_flag = AW8697_HAPTIC_TP_PRESS; + tp->id[i].press_flag = AW8697_HAPTIC_TP_PRESS; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].no_play_cnt = 0; + do_gettimeofday(&tp->id[i].t_press); + pr_info("%s: tp_press_release: status=%d, flag=%d", __func__, tp->id[i].pt_info.status, tp->id[i].tp_flag); + } + } + if (event == 10) { + pr_debug("%s: tp up\n", __func__); + pr_debug("%s: tp record_point_up[%d].status = %d\n", __func__, i, record_point[i].status); + if((AW8697_HAPTIC_TP_ST_RELEASE == record_point[i].status) && + (record_point[i].status != tp->id[i].pt_info.status)) { + tp->id[i].pt_info.status = record_point[i].status; + tp->id[i].tp_flag = AW8697_HAPTIC_TP_RELEASE; + tp->id[i].release_flag = AW8697_HAPTIC_TP_RELEASE; + do_gettimeofday(&tp->id[i].t_release); + pr_info("%s: tp_press_release: status=%d, flag=%d", __func__, tp->id[i].pt_info.status, tp->id[i].tp_flag); + } + } +#endif + if (event == 0) { + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + if ((tp->id[i].pt_info.x+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W > p_tmp->x) && + (tp->id[i].pt_info.x < p_tmp->x+p_tmp->w+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W) && + (tp->id[i].pt_info.y+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H > p_tmp->y) && + (tp->id[i].pt_info.y < p_tmp->y+p_tmp->h+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H)) { + pr_debug("%s: tp input point[%d, %04d, %04d] up is in the ai trust zone[%d, %04d, %04d, %04d, %04d]\n", + __func__, tp->id[i].pt_info.id, tp->id[i].pt_info.x, tp->id[i].pt_info.y, + p_tmp->level, p_tmp->x, p_tmp->y, p_tmp->w, p_tmp->h); + if(tp->virtual_id == i) { + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.id = tp->id[i].pt_info.id; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.x = tp->id[i].pt_info.x; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.y = tp->id[i].pt_info.y; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.status = AW8697_HAPTIC_TP_ST_RELEASE; + tp->id[AW8697_HAPTIC_TP_ID_MAX].tp_flag = AW8697_HAPTIC_TP_RELEASE; + tp->id[AW8697_HAPTIC_TP_ID_MAX].release_flag = AW8697_HAPTIC_TP_RELEASE; + do_gettimeofday(&tp->id[AW8697_HAPTIC_TP_ID_MAX].t_release); + } + break; + } + } + tp->id[i].pt_info.status = AW8697_HAPTIC_TP_ST_RELEASE; + tp->id[i].tp_flag = AW8697_HAPTIC_TP_RELEASE; + tp->id[i].release_flag = AW8697_HAPTIC_TP_RELEASE; + do_gettimeofday(&tp->id[i].t_release); + + pr_debug("%s: tp input point[%d, %04d, %04d] up to [%d, %04d, %04d] \n", + __func__, i, tp->id[i].pt_info.x, tp->id[i].pt_info.y, + i, tp->id[i].pt_info.x, tp->id[i].pt_info.y); + } + + return 0; +} + +#ifdef OP_AW_DEBUG +static int aw8697_haptic_audio_init(struct aw8697 *aw8697) +{ + unsigned int i = 0; + + pr_debug("%s enter\n", __func__); + + aw8697_haptic_set_wav_seq(aw8697, 0x01, 0x00); + + for (i=0; ihaptic_audio.tp.id[i].tp_flag = AW8697_HAPTIC_TP_NULL; + //aw8697->haptic_audio.tp.id[i].press_flag = AW8697_HAPTIC_TP_NULL; + //aw8697->haptic_audio.tp.id[i].release_flag = AW8697_HAPTIC_TP_NULL; + //aw8697->haptic_audio.tp.id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NULL; + aw8697->haptic_audio.tp.id[i].tp_ai_match_flag = 1; + aw8697->haptic_audio.tp.id[i].no_play_cnt = 0; + } + //aw8697->haptic_audio.tp.play_flag = AW8697_HAPTIC_TP_PLAY_NULL; + //aw8697->haptic_audio.tp.press_flag = AW8697_HAPTIC_TP_NULL; + //aw8697->haptic_audio.tp.tp_ai_match_flag = 0; + //aw8697->haptic_audio.tp.tp_ai_check_flag = 0; + aw8697->haptic_audio.tp.hap_match_without_tz_cnt = 0; + aw8697->haptic_audio.uevent_report_flag = 0; + aw8697->haptic_audio.hap_cnt_outside_tz = 0; + return 0; +} + +static int aw8697_haptic_audio_off(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + + mutex_lock(&aw8697->lock); + aw8697_haptic_set_gain(aw8697, 0x80); + aw8697_haptic_stop(aw8697); + aw8697->gun_type = 0xff; + aw8697->bullet_nr =0; + aw8697->gun_mode =0; + aw8697_haptic_audio_ctr_list_clear(&aw8697->haptic_audio); + mutex_unlock(&aw8697->lock); + + return 0; +} + +static int aw8697_haptic_audio_stop(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); +#ifdef OP_AW_DEBUG + do_gettimeofday(&aw8697->t_stop); +#endif + + aw8697_haptic_play_go(aw8697, false); + aw8697_haptic_stop_delay(aw8697); + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_STANDBY_MODE); + + return 0; +} + + + +static int aw8697_haptic_audio_play_cfg(struct aw8697 *aw8697) +{ + pr_debug("%s enter\n", __func__); + + aw8697->play_mode = AW8697_HAPTIC_RAM_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_RAM); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_UVLO_MASK, AW8697_BIT_SYSINTM_UVLO_OFF); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_WORK_MODE_MASK, AW8697_BIT_SYSCTRL_ACTIVE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + + return 0; +} +#endif +static enum hrtimer_restart aw8697_haptic_audio_timer_func(struct hrtimer *timer) +{ + struct aw8697 *aw8697 = container_of(timer, struct aw8697, haptic_audio.timer); + + pr_debug("%s enter\n", __func__); + schedule_work(&aw8697->haptic_audio.work); + + hrtimer_start(&aw8697->haptic_audio.timer, + ktime_set(aw8697->haptic_audio.timer_val/1000000, + (aw8697->haptic_audio.timer_val%1000000)*1000), + HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +static void aw8697_haptic_audio_work_routine(struct work_struct *work) +{ + struct aw8697 *aw8697 = container_of(work, struct aw8697, haptic_audio.work); + struct tp *tp = &(aw8697->haptic_audio.tp); + struct haptic_audio *haptic_audio = NULL; + struct haptic_audio_trust_zone *p_tmp = NULL; + struct haptic_audio_trust_zone *p_tmp_r = NULL; + struct haptic_audio_trust_zone *p_tmp_l = NULL; + struct haptic_ctr *p_ctr = NULL; + struct haptic_ctr *p_ctr_bak = NULL; + struct timeval tmp_time; + unsigned int press_delay = 0; + unsigned int release_delay = 0; + unsigned int tp_touch_play_flag = 0; + unsigned int i = 0; + unsigned int touch_vibrator_id = 0; + unsigned int ctr_list_flag = 0; + unsigned int ctr_list_input_cnt = 0; + unsigned int ctr_list_output_cnt = 0; + unsigned int ctr_list_diff_cnt = 0; + unsigned int ctr_list_del_cnt = 0; + unsigned int tp_ai_match_id = 0; + unsigned int x_thr = aw8697->haptic_audio.tp_size.x>>1; + + /*OP add for juge rtp on begin*/ + int rtp_is_going_on = 0; + int match_re = 0, dirty = 0; + + pr_debug("%s enter\n", __func__); + /*OP add for juge rtp on end*/ + + haptic_audio = &(aw8697->haptic_audio); + + mutex_lock(&aw8697->haptic_audio.lock); + memset(&aw8697->haptic_audio.ctr, 0, + sizeof(struct haptic_ctr)); + ctr_list_flag = 0; + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, &(haptic_audio->ctr_list), list) { + ctr_list_flag = 1; + break; + } + if(ctr_list_flag == 0) { + pr_debug("%s: ctr list empty\n", __func__); + } + if(ctr_list_flag == 1) { + list_for_each_entry_safe(p_ctr, p_ctr_bak, &(haptic_audio->ctr_list), list) { + ctr_list_input_cnt = p_ctr->cnt; + break; + } + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, &(haptic_audio->ctr_list), list) { + ctr_list_output_cnt = p_ctr->cnt; + break; + } + if(ctr_list_input_cnt > ctr_list_output_cnt) { + ctr_list_diff_cnt = ctr_list_input_cnt - ctr_list_output_cnt; + } + if(ctr_list_input_cnt < ctr_list_output_cnt) { + ctr_list_diff_cnt = 32 + ctr_list_input_cnt - ctr_list_output_cnt; + } + if(ctr_list_diff_cnt > 2) { + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, &(haptic_audio->ctr_list), list) { + if((p_ctr->play == 0) && + (AW8697_HAPTIC_CMD_ENABLE == (AW8697_HAPTIC_CMD_HAPTIC & p_ctr->cmd))) { + list_del(&p_ctr->list); + kfree(p_ctr); + ctr_list_del_cnt ++; + } + if(ctr_list_del_cnt == ctr_list_diff_cnt) { + break; + } + } + } + + } + + /* get the last data from list */ + list_for_each_entry_safe_reverse(p_ctr, p_ctr_bak, &(haptic_audio->ctr_list), list) { + aw8697->haptic_audio.ctr.cnt = p_ctr->cnt; + aw8697->haptic_audio.ctr.cmd = p_ctr->cmd; + aw8697->haptic_audio.ctr.play = p_ctr->play; + aw8697->haptic_audio.ctr.wavseq = p_ctr->wavseq; + aw8697->haptic_audio.ctr.loop = p_ctr->loop; + aw8697->haptic_audio.ctr.gain = p_ctr->gain; + list_del(&p_ctr->list); + kfree(p_ctr); + break; + } + if(aw8697->haptic_audio.ctr.play) { + pr_debug("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, + aw8697->haptic_audio.ctr.cnt, + aw8697->haptic_audio.ctr.cmd, + aw8697->haptic_audio.ctr.play, + aw8697->haptic_audio.ctr.wavseq, + aw8697->haptic_audio.ctr.loop, + aw8697->haptic_audio.ctr.gain); + } + + /* rtp mode jump */ + rtp_is_going_on = aw8697_haptic_juge_RTP_is_going_on(aw8697); + if (rtp_is_going_on) { + mutex_unlock(&aw8697->haptic_audio.lock); + return; + } + /* haptic play with tp adjust info */ + if(AW8697_HAPTIC_CMD_TP == + (aw8697->haptic_audio.ctr.cmd & AW8697_HAPTIC_CMD_SYS)) { + do_gettimeofday(&tmp_time); + for(i=0; iid[i].press_flag) { + press_delay = (tmp_time.tv_sec-tp->id[i].t_press.tv_sec)*1000000 + + (tmp_time.tv_usec-tp->id[i].t_press.tv_usec); + } + if(AW8697_HAPTIC_TP_RELEASE == tp->id[i].release_flag) { + release_delay = (tmp_time.tv_sec-tp->id[i].t_release.tv_sec)*1000000 + + (tmp_time.tv_usec-tp->id[i].t_release.tv_usec); + } + if(tp->id[i].press_flag || tp->id[i].release_flag) { + pr_debug("%s: id[%d]: press_flag=%d, press_delay=%dus, release_flag=%d, release_delaly=%dus\n", + __func__, i, tp->id[i].press_flag, press_delay, tp->id[i].release_flag, release_delay); + } + /* adjust tp play with tp press delay and tp release delay */ + if(AW8697_HAPTIC_PLAY_ENABLE == aw8697->haptic_audio.ctr.play) { + if(AW8697_HAPTIC_TP_PRESS == tp->id[i].press_flag) { + if(AW8697_HAPTIC_TP_PLAY_NULL == tp->id[i].play_flag) { + if(press_delay > tp->press_delay_max) { + /* no play time > tp-play delay max time */ + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NOMORE; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + if(i == AW8697_HAPTIC_TP_ID_MAX) { + tp->id[i].pt_info.status = AW8697_HAPTIC_TP_ST_RELEASE; + tp->id[i].pt_info.touch_flag = AW8697_HAPTIC_TP_TOUCH_INVAIL; + tp->id[i].tp_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].no_play_cnt = 0; + //tp->id[i].press_no_vibrate_flag = 0; + } + if(tp->id[i].press_no_vibrate_flag == 0) + tp->id[i].press_no_vibrate_flag = 2; + } else { + if(press_delay > tp->press_delay_min) { + /* tp-play delay min time < no play time < tp-play delay max time */ + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_ENABLE; + tp->id[i].press_no_vibrate_flag = 1; + } else { + /* no play time < tp-play delay min time */ + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NOMORE; + if(tp->id[i].press_no_vibrate_flag == 0) + tp->id[i].press_no_vibrate_flag = 2; + } + } + } else if(AW8697_HAPTIC_TP_PLAY_ENABLE == tp->id[i].play_flag) { + } + pr_debug("%s: %d: id[%d]:play_flag=%d, press_flag=%d, release_flag=%d, press_no_vibrate_flag=%d, no_play_cnt=%d\n", + __func__, __LINE__, i, tp->id[i].play_flag, tp->id[i].press_flag, tp->id[i].release_flag, + tp->id[i].press_no_vibrate_flag, tp->id[i].no_play_cnt); + } + if(AW8697_HAPTIC_TP_RELEASE == tp->id[i].release_flag) { + if(release_delay > tp->release_delay_max) { + /* tp release time > 3-continue-time play time*/ + if(AW8697_HAPTIC_TP_PLAY_ENABLE == tp->id[i].play_flag) { + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NOMORE; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + if(i == AW8697_HAPTIC_TP_ID_MAX) { + tp->id[i].pt_info.status = AW8697_HAPTIC_TP_ST_RELEASE; + tp->id[i].pt_info.touch_flag = AW8697_HAPTIC_TP_TOUCH_INVAIL; + tp->id[i].tp_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].no_play_cnt = 0; + //tp->id[i].press_no_vibrate_flag = 0; + } + if(tp->id[i].press_no_vibrate_flag == 0) + tp->id[i].press_no_vibrate_flag = 2; + } else { + } + } + pr_debug("%s: %d: id[%d]:play_flag=%d, press_flag=%d, release_flag=%d, press_no_vibrate_flag=%d, no_play_cnt=%d\n", + __func__, __LINE__, i, tp->id[i].play_flag, tp->id[i].press_flag, tp->id[i].release_flag, + tp->id[i].press_no_vibrate_flag, tp->id[i].no_play_cnt); + } + tp->id[i].no_play_cnt = 0; + } else if(AW8697_HAPTIC_PLAY_NULL == aw8697->haptic_audio.ctr.play) { + if(AW8697_HAPTIC_TP_PRESS == tp->id[i].press_flag) { + if(AW8697_HAPTIC_TP_PLAY_ENABLE == tp->id[i].play_flag) { + tp->id[i].no_play_cnt ++; + if(tp->id[i].no_play_cnt > tp->no_play_cnt_max) { + /* no play cnt > play interal time */ + tp->id[i].no_play_cnt = tp->no_play_cnt_max; + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NULL; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + if(i == AW8697_HAPTIC_TP_ID_MAX) { + tp->id[i].pt_info.status = AW8697_HAPTIC_TP_ST_RELEASE; + tp->id[i].pt_info.touch_flag = AW8697_HAPTIC_TP_TOUCH_INVAIL; + tp->id[i].tp_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + //tp->id[i].press_no_vibrate_flag = 0; + } + if(tp->id[i].press_no_vibrate_flag == 0) + tp->id[i].press_no_vibrate_flag = 2; + } else { + } + } else { + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NULL; + } + pr_debug("%s: %d: id[%d]:play_flag=%d, press_flag=%d, release_flag=%d, press_no_vibrate_flag=%d, no_play_cnt=%d\n", + __func__, __LINE__, i, tp->id[i].play_flag, tp->id[i].press_flag, tp->id[i].release_flag, + tp->id[i].press_no_vibrate_flag, tp->id[i].no_play_cnt); + } + if(AW8697_HAPTIC_TP_RELEASE == tp->id[i].release_flag) { + /* tp release time > 3-continue-time play time*/ + if(release_delay > tp->release_delay_max) { + tp->id[i].play_flag = AW8697_HAPTIC_TP_PLAY_NULL; + tp->id[i].press_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].release_flag = AW8697_HAPTIC_TP_NULL; + tp->id[i].tp_ai_match_flag = 1; + if(tp->id[i].press_no_vibrate_flag == 0) + tp->id[i].press_no_vibrate_flag = 2; + tp->tp_ai_check_flag = 0; + } else { + } + pr_debug("%s: %d: id[%d]:play_flag=%d, press_flag=%d, release_flag=%d, press_no_vibrate_flag=%d, no_play_cnt=%d\n", + __func__, __LINE__, i, tp->id[i].play_flag, tp->id[i].press_flag, tp->id[i].release_flag, + tp->id[i].press_no_vibrate_flag, tp->id[i].no_play_cnt); + } + } else { + } + } + + /* adjust tp play enable */ + tp->play_flag = AW8697_HAPTIC_TP_PLAY_NULL; + for(i=0; iid[i].play_flag) { + tp_touch_play_flag = AW8697_HAPTIC_TP_PLAY_ENABLE; + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + match_re = aw8697_haptic_audio_tp_list_match(&(tp->id[i].pt_info), p_tmp); + if (match_re == 1) { + tp->play_flag = AW8697_HAPTIC_TP_PLAY_ENABLE; + touch_vibrator_id = i; + pr_debug("%s: tp input point[%d, %04d, %04d] is in the ai trust zone[%d, %04d, %04d, %04d, %04d]\n", + __func__, i, tp->id[i].pt_info.x, tp->id[i].pt_info.y, + p_tmp->level, p_tmp->x, p_tmp->y, p_tmp->w, p_tmp->h); + break; + } else if (match_re == 2) { + if(!dirty) + p_tmp->dirty = 1; + dirty = 1; + break; + } + } + } +#ifdef SECOND_SCOREMODE + if(tp->play_flag == AW8697_HAPTIC_TP_PLAY_ENABLE && dirty == 1) { + break; + } +#else + if(tp->play_flag == AW8697_HAPTIC_TP_PLAY_ENABLE) { + break; + } +#endif + } + if(tp->play_flag) { + pr_debug("%s: tp.play_flag with tp =%d, touch_vibrator_id=%d\n", __func__, tp->play_flag, touch_vibrator_id); + } + + /* haptic play cnt outside trust zone over limit, restart ai scan */ + tp->tp_ai_match_flag = 1; + for(i=0; iid[i].tp_ai_match_flag); + if(tp->id[i].tp_ai_match_flag == 0) { + tp->tp_ai_match_flag = 0; + tp_ai_match_id = i; + break; + } + + } + pr_debug("%s: tp_ai_match_flag=%d, tp_ai_check_flag=%d, tz_high_num=%d, tp_touch_play_flag=%d, tp->last_play_flag=%d, hap_cnt_outside_tz=%d\n", + __func__, tp->tp_ai_match_flag, tp->tp_ai_check_flag, + haptic_audio->tz_high_num, tp_touch_play_flag, tp->last_play_flag, haptic_audio->hap_cnt_outside_tz); + + /* restart ai scan when tz_high_num=2 */ + if ((tp->tp_ai_match_flag == 0) && + (tp->tp_ai_check_flag == 1)) { + if ((AW8697_HAPTIC_TP_PLAY_ENABLE == tp_touch_play_flag) && + (AW8697_HAPTIC_TP_PLAY_NULL == tp->play_flag)) { +#ifdef FIRST_SCOREMODE + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + if ((p_tmp->level >= TRUST_LEVEL) && (p_tmp->x < x_thr)) { + p_tmp_r = p_tmp; + } else if ((p_tmp->level >= TRUST_LEVEL) && (p_tmp->x >= x_thr)) { + p_tmp_l = p_tmp; + } + } + + for(i=0; iid[i].play_flag) { + list_for_each_entry(p_tmp, &(haptic_audio->score_list), list) { + if (aw8697_haptic_audio_tp_list_match(&(tp->id[i].pt_info), p_tmp)) + { + p_tmp->level = (p_tmp->level < TRUST_LEVEL) ? (++p_tmp->level) : TRUST_LEVEL; + } + } + } + } + + list_for_each_entry(p_tmp, &(haptic_audio->score_list), list) { + if (p_tmp->level >= TRUST_LEVEL) { + if(p_tmp->x < x_thr) { + if (p_tmp_r) { + list_del(&p_tmp_r->list); + kfree(p_tmp_r); + haptic_audio->tz_num -= 1; + pr_debug("%s scorelist_num = %d\n", __func__, haptic_audio->tz_num); + } + }else{ + if (p_tmp_l) { + list_del(&p_tmp_l->list); + kfree(p_tmp_l); + haptic_audio->tz_num -= 1; + pr_debug("%s scorelist_num = %d\n", __func__, haptic_audio->tz_num); + } + } + list_del(&p_tmp->list); + list_add(&p_tmp->list,&(haptic_audio->list)); + pr_debug("p_tmp->level >= TRUST_LEVEL\n"); + break; + } + } +#endif + tp->tp_ai_check_flag = 0; + tp->id[tp_ai_match_id].tp_ai_match_flag = 1; + } else { + if (tp->id[touch_vibrator_id].press_no_vibrate_flag == 2) { + tp->tp_ai_check_flag = 0; + } + } + } + + if(AW8697_HAPTIC_PLAY_ENABLE == aw8697->haptic_audio.ctr.play) { + tp->last_play_flag = tp->play_flag; + } + /* clear all id tp flag */ + for(i=0; iid[i].tp_flag = AW8697_HAPTIC_TP_NULL; + } + } else { + for(i=0; iid[i].tp_flag = AW8697_HAPTIC_TP_NULL; + } + } + mutex_unlock(&aw8697->haptic_audio.lock); + + /* aw8697 haptic play control */ + if(AW8697_HAPTIC_CMD_ENABLE == + (AW8697_HAPTIC_CMD_HAPTIC & aw8697->haptic_audio.ctr.cmd)) { + if(AW8697_HAPTIC_PLAY_ENABLE == aw8697->haptic_audio.ctr.play) { + pr_info("%s: haptic_audio_play_start\n", __func__); + if(AW8697_HAPTIC_CMD_TP == (AW8697_HAPTIC_CMD_SYS & aw8697->haptic_audio.ctr.cmd) && + (AW8697_HAPTIC_TP_PLAY_ENABLE != tp->play_flag)) { + pr_info("%s: cancel haptic with tp event\n", __func__); + } else { + pr_info("%s: normal haptic with tp event\n", __func__); + mutex_lock(&aw8697->lock); + aw8697_haptic_audio_stop(aw8697); + aw8697_haptic_audio_play_cfg(aw8697); + + aw8697_haptic_set_wav_seq(aw8697, 0x00, + aw8697->haptic_audio.ctr.wavseq); + + aw8697_haptic_set_wav_loop(aw8697, 0x00, + aw8697->haptic_audio.ctr.loop); + + aw8697_haptic_set_gain(aw8697, + aw8697->haptic_audio.ctr.gain); + aw8697_haptic_set_bst_vol(aw8697, 0x5); + aw8697_haptic_start(aw8697); + mutex_unlock(&aw8697->lock); + } + } else if(AW8697_HAPTIC_PLAY_STOP == aw8697->haptic_audio.ctr.play) { + mutex_lock(&aw8697->lock); + aw8697_haptic_audio_stop(aw8697); + mutex_unlock(&aw8697->lock); + } else if(AW8697_HAPTIC_PLAY_GAIN == aw8697->haptic_audio.ctr.play) { + mutex_lock(&aw8697->lock); + aw8697_haptic_set_gain(aw8697, + aw8697->haptic_audio.ctr.gain); + mutex_unlock(&aw8697->lock); + } + } +} + +static ssize_t aw8697_gun_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8697->gun_type); +} + +static ssize_t aw8697_gun_type_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8697->lock); + aw8697->gun_type = val; + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_bullet_nr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8697->bullet_nr); +} + +static ssize_t aw8697_bullet_nr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8697->lock); + aw8697->bullet_nr = val; + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_gun_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8697->gun_mode); +} + +static ssize_t aw8697_gun_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + pr_debug("%s: value=%d\n", __FUNCTION__, val); + + mutex_lock(&aw8697->lock); + aw8697->gun_mode = val; + mutex_unlock(&aw8697->lock); + return count; +} + +/***************************************************** + * + * haptic cont + * + *****************************************************/ +static int aw8697_haptic_cont(struct aw8697 *aw8697) +{ + pr_info("%s enter\n", __func__); + + /* work mode */ + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_CONT_MODE); + /* preset f0 */ + aw8697->f0_pre = aw8697->f0; + aw8697_haptic_set_f0_preset(aw8697); + /* lpf */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_DATCTRL, + AW8697_BIT_DATCTRL_FC_MASK, AW8697_BIT_DATCTRL_FC_1000HZ); + aw8697_i2c_write_bits(aw8697, AW8697_REG_DATCTRL, + AW8697_BIT_DATCTRL_LPF_ENABLE_MASK, AW8697_BIT_DATCTRL_LPF_ENABLE); + /* cont config */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_ZC_DETEC_MASK, AW8697_BIT_CONT_CTRL_ZC_DETEC_ENABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_WAIT_PERIOD_MASK, AW8697_BIT_CONT_CTRL_WAIT_1PERIOD); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_MODE_MASK, AW8697_BIT_CONT_CTRL_BY_GO_SIGNAL); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8697_CONT_PLAYBACK_MODE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_F0_DETECT_MASK, AW8697_BIT_CONT_CTRL_F0_DETECT_DISABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_O2C_MASK, AW8697_BIT_CONT_CTRL_O2C_DISABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_AUTO_BRK_MASK, AW8697_BIT_CONT_CTRL_AUTO_BRK_ENABLE); + /* TD time */ + aw8697_i2c_write(aw8697, AW8697_REG_TD_H, (unsigned char)(aw8697->cont_td>>8)); + aw8697_i2c_write(aw8697, AW8697_REG_TD_L, (unsigned char)(aw8697->cont_td>>0)); + aw8697_i2c_write(aw8697, AW8697_REG_TSET, 0x12); + /* zero cross */ + aw8697_i2c_write(aw8697, AW8697_REG_ZC_THRSH_H, (unsigned char)(aw8697->cont_zc_thr>>8)); + aw8697_i2c_write(aw8697, AW8697_REG_ZC_THRSH_L, (unsigned char)(aw8697->cont_zc_thr>>0)); + /* bemf */ + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHH_H, 0x10); + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHH_L, 0x08); + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHL_H, 0x03); + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHL_L, 0xf8); + aw8697_i2c_write_bits(aw8697, AW8697_REG_BEMF_NUM, + AW8697_BIT_BEMF_NUM_BRK_MASK, aw8697->cont_num_brk); + aw8697_i2c_write(aw8697, AW8697_REG_TIME_NZC, 0x23); /* 35*171us=5.985ms*/ + /* f0 driver level */ + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL, aw8697->cont_drv_lvl); + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL_OV, aw8697->cont_drv_lvl_ov); + /* cont play go */ + aw8697_haptic_play_go(aw8697, true); + + return 0; +} + +static int haptic_get_f0_defalut(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + unsigned int t_f0_trace_ms = 0; + unsigned int f0_cali_cnt = 50; + unsigned char f0_pre_num = 0; + unsigned char f0_wait_num = 0; + unsigned char f0_repeat_num = 0; + unsigned char f0_trace_num = 0; + unsigned int t_f0_ms = 0; + pr_info("%s enter\n", __func__); + + aw8697->f0 = aw8697->f0_pre; + /* f0 calibrate work mode */ + aw8697_haptic_stop(aw8697); + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, 0); + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_CONT_MODE); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8697_BIT_CONT_CTRL_OPEN_PLAYBACK); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_F0_DETECT_MASK, AW8697_BIT_CONT_CTRL_F0_DETECT_ENABLE); + + /* LPF */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_DATCTRL, + AW8697_BIT_DATCTRL_FC_MASK, AW8697_BIT_DATCTRL_FC_1000HZ); + aw8697_i2c_write_bits(aw8697, AW8697_REG_DATCTRL, + AW8697_BIT_DATCTRL_LPF_ENABLE_MASK, AW8697_BIT_DATCTRL_LPF_ENABLE); + + /* LRA OSC Source */ + if(aw8697->f0_cali_flag == AW8697_HAPTIC_CALI_F0) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_LRA_SRC_MASK, AW8697_BIT_ANACTRL_LRA_SRC_REG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_LRA_SRC_MASK, AW8697_BIT_ANACTRL_LRA_SRC_EFUSE); + } + + /* preset f0 */ + aw8697_haptic_set_f0_preset(aw8697); + + /* beme config */ + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHH_H, 0x10); + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHH_L, 0x08); + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHL_H, 0x03); + aw8697_i2c_write(aw8697, AW8697_REG_BEMF_VTHL_L, 0xf8); + + /* f0 driver level */ + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL, aw8697->cont_drv_lvl); + + /* f0 trace parameter */ + f0_pre_num = 0x05; + f0_wait_num = 0x03; + f0_repeat_num = 0x02; + f0_trace_num = 0x0f; + aw8697_i2c_write(aw8697, AW8697_REG_NUM_F0_1, (f0_pre_num<<4)|(f0_wait_num<<0)); + aw8697_i2c_write(aw8697, AW8697_REG_NUM_F0_2, (f0_repeat_num<<0)); + aw8697_i2c_write(aw8697, AW8697_REG_NUM_F0_3, (f0_trace_num<<0)); + + /* clear aw8697 interrupt */ + ret = aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + + /* play go and start f0 calibration */ + aw8697_haptic_play_go(aw8697, true); + + /* f0 trace time */ + t_f0_ms = 1000*10/aw8697->f0_pre; + t_f0_trace_ms = + t_f0_ms * (f0_pre_num + f0_wait_num + + (f0_trace_num + f0_wait_num) * (f0_repeat_num - 1)); + usleep_range(t_f0_trace_ms * 1000, t_f0_trace_ms * 1000 + 500); + + for(i=0; if0 = aw8697->f0_pre; + + /* f0 calibrate work mode */ + aw8697_haptic_stop(aw8697); + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, 0); + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_CONT_MODE); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_MODE_MASK, AW8697_BIT_CONT_CTRL_BY_DRV_TIME); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8697_BIT_CONT_CTRL_OPEN_PLAYBACK); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_EN_CLOSE_MASK, AW8697_BIT_CONT_CTRL_CLOSE_PLAYBACK); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_F0_DETECT_MASK, AW8697_BIT_CONT_CTRL_F0_DETECT_DISABLE); + aw8697_i2c_write_bits(aw8697, AW8697_REG_CONT_CTRL, + AW8697_BIT_CONT_CTRL_AUTO_BRK_MASK, AW8697_BIT_CONT_CTRL_AUTO_BRK_DISABLE); + + /* LRA OSC Source */ + if(aw8697->f0_cali_flag == AW8697_HAPTIC_CALI_F0) { + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_LRA_SRC_MASK, AW8697_BIT_ANACTRL_LRA_SRC_REG); + } else { + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_LRA_SRC_MASK, AW8697_BIT_ANACTRL_LRA_SRC_EFUSE); + } + + /* f0 driver level */ + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL, 0x61); + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL_OV, 0x61); + + /* TD time */ + aw8697_i2c_write(aw8697, AW8697_REG_TD_H, 0x00); + aw8697_i2c_write(aw8697, AW8697_REG_TD_L, 0xe5); + aw8697_i2c_write(aw8697, AW8697_REG_TSET, 0x48); + + /* drive time */ + aw8697_i2c_write(aw8697, AW8697_REG_DRV_TIME, 0xFE); + + /* preset f0 */ + aw8697_haptic_set_f0_preset(aw8697); + + /* clear aw8697 interrupt */ + ret = aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + + /* play go and start f0 calibration */ + aw8697_haptic_play_go(aw8697, true); + + /* f0 trace time */ + t_f0_trace_ms = 0xfe * 684 / 1000; + msleep(t_f0_trace_ms); + + for(i=0; icount_go) + ret = haptic_get_f0_count_go(aw8697); + else + ret = haptic_get_f0_defalut(aw8697); + + aw8697->haptic_real_f0 = aw8697->f0/10; + return ret; +} + +static int aw8697_haptic_f0_calibration(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char reg_val = 0; + unsigned int f0_limit = 0; + char f0_cali_lra = 0; + int f0_cali_step = 0; + int f0_dft_step = 0; + + pr_info("%s enter\n", __func__); + + aw8697->f0_cali_flag = AW8697_HAPTIC_CALI_F0; + if(aw8697_haptic_get_f0(aw8697)) { + pr_err("%s get f0 error, user defafult f0\n", __func__); + } else { + /* max and min limit */ + f0_limit = aw8697->f0; + if(aw8697->f0*100 < AW8697_HAPTIC_F0_PRE*(100-AW8697_HAPTIC_F0_CALI_PERCEN)) { + f0_limit = AW8697_HAPTIC_F0_PRE*(100-AW8697_HAPTIC_F0_CALI_PERCEN)/100; + } + if(aw8697->f0*100 > AW8697_HAPTIC_F0_PRE*(100+AW8697_HAPTIC_F0_CALI_PERCEN)) { + f0_limit = AW8697_HAPTIC_F0_PRE*(100+AW8697_HAPTIC_F0_CALI_PERCEN)/100; + } + /* calculate cali step */ + f0_cali_step = 10000*((int)f0_limit-(int)aw8697->f0_pre)/((int)f0_limit*25); + pr_debug("%s f0_cali_step=%d\n", __func__, f0_cali_step); + + /* get default cali step */ + aw8697_i2c_read(aw8697, AW8697_REG_TRIM_LRA, ®_val); + if(reg_val & 0x20) { + f0_dft_step = reg_val - 0x40; + } else { + f0_dft_step = reg_val; + } + pr_debug("%s f0_dft_step=%d\n", __func__, f0_dft_step); + + /* get new cali step */ + f0_cali_step += f0_dft_step; + pr_debug("%s f0_cali_step=%d\n", __func__, f0_cali_step); + + if(f0_cali_step > 31) { + f0_cali_step = 31; + } else if(f0_cali_step < -32) { + f0_cali_step = -32; + } + f0_cali_lra = (char)f0_cali_step; + pr_debug("%s f0_cali_lra=%d\n", __func__, f0_cali_lra); + + /* get cali step complement code*/ + if(f0_cali_lra < 0) { + f0_cali_lra += 0x40; + } + pr_debug("%s reg f0_cali_lra=%d\n", __func__, f0_cali_lra); + + aw8697->f0_calib_data = (int)f0_cali_lra; + + /* update cali step */ + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, (char)f0_cali_lra); + aw8697_i2c_read(aw8697, AW8697_REG_TRIM_LRA, ®_val); + pr_info("%s final trim_lra=0x%02x\n", __func__, reg_val); + } + + /* restore default work mode */ + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_STANDBY_MODE); + aw8697->play_mode = AW8697_HAPTIC_RAM_MODE; + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_PLAY_MODE_MASK, AW8697_BIT_SYSCTRL_PLAY_MODE_RAM); + aw8697_haptic_stop(aw8697); + + return ret; +} + +/***************************************************** + * + * haptic fops + * + *****************************************************/ +static int aw8697_file_open(struct inode *inode, struct file *file) +{ + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + file->private_data = (void*)g_aw8697; + + return 0; +} + +static int aw8697_file_release(struct inode *inode, struct file *file) +{ + file->private_data = (void*)NULL; + + module_put(THIS_MODULE); + + return 0; +} + +static long aw8697_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct aw8697 *aw8697 = (struct aw8697 *)file->private_data; + + int ret = 0; + + dev_info(aw8697->dev, "%s: cmd=0x%x, arg=0x%lx\n", + __func__, cmd, arg); + + mutex_lock(&aw8697->lock); + + if(_IOC_TYPE(cmd) != AW8697_HAPTIC_IOCTL_MAGIC) { + dev_err(aw8697->dev, "%s: cmd magic err\n", + __func__); + return -EINVAL; + } + + switch (cmd) { + default: + dev_err(aw8697->dev, "%s, unknown cmd\n", __func__); + break; + } + + mutex_unlock(&aw8697->lock); + + return ret; +} + +static ssize_t aw8697_file_read(struct file* filp, char* buff, size_t len, loff_t* offset) +{ + struct aw8697 *aw8697 = (struct aw8697 *)filp->private_data; + int ret = 0; + int i = 0; + unsigned char reg_val = 0; + unsigned char *pbuff = NULL; + + mutex_lock(&aw8697->lock); + + dev_info(aw8697->dev, "%s: len=%zu\n", __func__, len); + + switch(aw8697->fileops.cmd) + { + case AW8697_HAPTIC_CMD_READ_REG: + pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL); + if(pbuff != NULL) { + for(i=0; ifileops.reg+i, ®_val); + pbuff[i] = reg_val; + } + for(i=0; idev, "%s: pbuff[%d]=0x%02x\n", + __func__, i, pbuff[i]); + } + ret = copy_to_user(buff, pbuff, len); + if(ret) { + dev_err(aw8697->dev, "%s: copy to user fail\n", __func__); + } + kfree(pbuff); + } else { + dev_err(aw8697->dev, "%s: alloc memory fail\n", __func__); + } + break; + default: + dev_err(aw8697->dev, "%s, unknown cmd %d \n", __func__, aw8697->fileops.cmd); + break; + } + + mutex_unlock(&aw8697->lock); + + + return len; +} + +static ssize_t aw8697_file_write(struct file* filp, const char* buff, size_t len, loff_t* off) +{ + struct aw8697 *aw8697 = (struct aw8697 *)filp->private_data; + int i = 0; + int ret = 0; + unsigned char *pbuff = NULL; + + pbuff = (unsigned char *)kzalloc(len, GFP_KERNEL); + if(pbuff == NULL) { + dev_err(aw8697->dev, "%s: alloc memory fail\n", __func__); + return len; + } + ret = copy_from_user(pbuff, buff, len); + if(ret) { + kfree(pbuff); + dev_err(aw8697->dev, "%s: copy from user fail\n", __func__); + return len; + } + + for(i=0; idev, "%s: pbuff[%d]=0x%02x\n", + __func__, i, pbuff[i]); + } + + mutex_lock(&aw8697->lock); + + aw8697->fileops.cmd = pbuff[0]; + + switch(aw8697->fileops.cmd) + { + case AW8697_HAPTIC_CMD_READ_REG: + if(len == 2) { + aw8697->fileops.reg = pbuff[1]; + } else { + dev_err(aw8697->dev, "%s: read cmd len %zu err\n", __func__, len); + } + break; + case AW8697_HAPTIC_CMD_WRITE_REG: + if(len > 2) { + for(i=0; idev, "%s: write reg0x%02x=0x%02x\n", + __func__, pbuff[1]+i, pbuff[i+2]); + aw8697_i2c_write(aw8697, pbuff[1]+i, pbuff[2+i]); + } + } else { + dev_err(aw8697->dev, "%s: write cmd len %zu err\n", __func__, len); + } + break; + default: + dev_err(aw8697->dev, "%s, unknown cmd %d \n", __func__, aw8697->fileops.cmd); + break; + } + + mutex_unlock(&aw8697->lock); + + if(pbuff != NULL) { + kfree(pbuff); + } + return len; +} + +static struct file_operations fops = +{ + .owner = THIS_MODULE, + .read = aw8697_file_read, + .write = aw8697_file_write, + .unlocked_ioctl = aw8697_file_unlocked_ioctl, + .open = aw8697_file_open, + .release = aw8697_file_release, +}; + +static struct miscdevice aw8697_haptic_misc = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = AW8697_HAPTIC_NAME, + .fops = &fops, +}; + +static bool check_factory_mode(void) +{ + int boot_mode = get_boot_mode(); + + if (boot_mode == MSM_BOOT_MODE_RF + || boot_mode == MSM_BOOT_MODE_FACTORY) + return true; + else + return false; +} + +static int aw8697_haptic_init(struct aw8697 *aw8697) +{ + int ret = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + struct tp *tp = &(aw8697->haptic_audio.tp); + + pr_info("%s enter\n", __func__); + + ret = misc_register(&aw8697_haptic_misc); + if(ret) { + dev_err(aw8697->dev, "%s: misc fail: %d\n", __func__, ret); + return ret; + } + + /* haptic audio */ + aw8697->haptic_audio.delay_val = 1; + aw8697->haptic_audio.timer_val = 21318; + INIT_LIST_HEAD(&(aw8697->haptic_audio.ctr_list)); + + hrtimer_init(&aw8697->haptic_audio.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8697->haptic_audio.timer.function = aw8697_haptic_audio_timer_func; + INIT_WORK(&aw8697->haptic_audio.work, aw8697_haptic_audio_work_routine); + + mutex_init(&aw8697->haptic_audio.lock); + + aw8697->haptic_audio.tp.press_delay_min = 1; + aw8697->haptic_audio.tp.press_delay_max = 500000; + aw8697->haptic_audio.tp.release_delay_max = 600000; + aw8697->haptic_audio.tp.no_play_cnt_max = 230; + for(i=0; iid[i].pt_info.status = 0; + } + + aw8697->gun_type = 0xff; + aw8697->bullet_nr = 0x00; + aw8697->gun_mode = 0x00; + INIT_LIST_HEAD(&(aw8697->haptic_audio.list)); + INIT_LIST_HEAD(&(aw8697->haptic_audio.score_list)); + aw8697->haptic_audio.tp_size.x = 3120; + aw8697->haptic_audio.tp_size.y = 1440; + aw8697->haptic_audio.tz_cnt_thr = 3; + aw8697->haptic_audio.tz_cnt_max = 10; + aw8697->haptic_audio.hap_cnt_max_outside_tz = 5; + + aw8697_op_clean_status(aw8697); + + /* haptic init */ + mutex_lock(&aw8697->lock); + /*For haptic test 90mA in AT begin*/ + aw8697->activate_mode = AW8697_HAPTIC_ACTIVATE_RAM_MODE; + aw8697_haptic_set_wav_loop(aw8697, aw8697->loop[0x00], 0xff); + if (check_factory_mode()) { + aw8697_haptic_set_bst_vol(aw8697, 0x09); + aw8697_haptic_set_gain(aw8697, 0x80); + } else { + aw8697_haptic_set_bst_vol(aw8697, 0x11); + aw8697_haptic_set_gain(aw8697, 0x80); + } + aw8697_haptic_set_repeat_wav_seq(aw8697, 10); + /*For haptic test 90mA in AT end*/ + ret = aw8697_i2c_read(aw8697, AW8697_REG_WAVSEQ1, ®_val); + aw8697->index = reg_val & 0x7F; + ret = aw8697_i2c_read(aw8697, AW8697_REG_DATDBG, ®_val); + aw8697->gain = reg_val & 0xFF; + ret = aw8697_i2c_read(aw8697, AW8697_REG_BSTDBG4, ®_val); + aw8697->vmax = (reg_val>>1)&0x1F; + for(i=0; iseq[i] = reg_val; + } + + aw8697_haptic_play_mode(aw8697, AW8697_HAPTIC_STANDBY_MODE); + + aw8697_haptic_set_pwm(aw8697, AW8697_PWM_24K); + + aw8697_i2c_write(aw8697, AW8697_REG_BSTDBG1, 0x30); + aw8697_i2c_write(aw8697, AW8697_REG_BSTDBG2, 0xeb); + aw8697_i2c_write(aw8697, AW8697_REG_BSTDBG3, 0xd4); + aw8697_i2c_write(aw8697, AW8697_REG_TSET, 0x12); + aw8697_i2c_write(aw8697, AW8697_REG_R_SPARE, 0x68); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANADBG, + AW8697_BIT_ANADBG_IOC_MASK, AW8697_BIT_ANADBG_IOC_4P65A); + /*OP over current limmit set to max begin*/ + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANADBG, + AW8697_BIT_ANADBG_IOC_OCDT_MASK, AW8697_BIT_ANADBG_IOC_OCDT_150NS); + /*OP over current limmit set to max end*/ + aw8697_haptic_set_bst_peak_cur(aw8697, AW8697_DEFAULT_PEAKCUR); + aw8697_haptic_swicth_motorprotect_config(aw8697, 0x00, 0x00); + aw8697_haptic_auto_boost_config(aw8697, false); + + aw8697_haptic_trig_param_init(aw8697); + aw8697_haptic_trig_param_config(aw8697); + + aw8697_haptic_os_calibration(aw8697); + if (aw8697->count_go) { + aw8697_haptic_cont_vbat_mode(aw8697, + AW8697_HAPTIC_CONT_VBAT_SW_COMP_MODE); + } else { + aw8697_haptic_cont_vbat_mode(aw8697, + AW8697_HAPTIC_CONT_VBAT_HW_COMP_MODE); + } + aw8697->ram_vbat_comp = AW8697_HAPTIC_RAM_VBAT_COMP_ENABLE; + aw8697_haptic_set_wav_seq(aw8697, 0x01, 0x00); + mutex_unlock(&aw8697->lock); + + /* f0 calibration */ + mutex_lock(&aw8697->lock); + aw8697->f0_pre = AW8697_HAPTIC_F0_PRE; + aw8697->cont_drv_lvl = AW8697_HAPTIC_CONT_DRV_LVL; + aw8697->cont_drv_lvl_ov = AW8697_HAPTIC_CONT_DRV_LVL_OV; + aw8697->cont_td = AW8697_HAPTIC_CONT_TD; + aw8697->cont_zc_thr = AW8697_HAPTIC_CONT_ZC_THR; + aw8697->cont_num_brk = AW8697_HAPTIC_CONT_NUM_BRK; + mutex_unlock(&aw8697->lock); + + return ret; +} + + + +/***************************************************** + * + * vibrator + * + *****************************************************/ +#ifdef TIMED_OUTPUT +static int aw8697_vibrator_get_time(struct timed_output_dev *dev) +{ + struct aw8697 *aw8697 = container_of(dev, struct aw8697, to_dev); + + if (hrtimer_active(&aw8697->timer)) { + ktime_t r = hrtimer_get_remaining(&aw8697->timer); + return ktime_to_ms(r); + } + + return 0; +} + +static void aw8697_vibrator_enable( struct timed_output_dev *dev, int value) +{ + struct aw8697 *aw8697 = container_of(dev, struct aw8697, to_dev); + unsigned char reg_val = 0; + + mutex_lock(&aw8697->lock); + + pr_debug("%s enter\n", __func__); + /*RTP mode do not allow other vibrate begign*/ + if(aw8697->play_mode == AW8697_HAPTIC_RTP_MODE) + { + aw8697_i2c_read(aw8697, AW8697_REG_GLB_STATE, ®_val); + if((reg_val&0x0f) != 0x00) { + mutex_unlock(&aw8697->lock); + pr_info("%s RTP on && not stop,return\n", __func__); + return; + } + } + /*RTP mode do not allow other vibrate end*/ + + aw8697_haptic_stop(aw8697); + + if (value > 0) { + aw8697_haptic_ram_vbat_comp(aw8697, false); + aw8697_haptic_play_wav_seq(aw8697, value); + } + + mutex_unlock(&aw8697->lock); + + pr_debug("%s exit\n", __func__); +} + +#else +static enum led_brightness aw8697_haptic_brightness_get(struct led_classdev *cdev) +{ + struct aw8697 *aw8697 = + container_of(cdev, struct aw8697, cdev); + + return aw8697->amplitude; +} + +static void aw8697_haptic_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ + struct aw8697 *aw8697 = + container_of(cdev, struct aw8697, cdev); + int rtp_is_going_on = 0; + static int val_pre; + + /*OP add for juge rtp on begin*/ + rtp_is_going_on = aw8697_haptic_juge_RTP_is_going_on(aw8697); + if (rtp_is_going_on) + return; + if (!aw8697->ram_init) + return; + if (aw8697->amplitude != val_pre) + pr_info("%s enter,level:%d\n", __func__, level); + /*OP add for juge rtp on end*/ + aw8697->amplitude = level; + val_pre = aw8697->amplitude; + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + if (aw8697->amplitude > 0) { + /*aw8697_haptic_ram_vbat_comp(aw8697, false);*/ + aw8697_haptic_play_wav_seq(aw8697, aw8697->amplitude); + } + mutex_unlock(&aw8697->lock); +} +#endif + +static ssize_t aw8697_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8697->state); +} + +static ssize_t aw8697_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8697_duration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ktime_t time_rem; + s64 time_ms = 0; + + if (hrtimer_active(&aw8697->timer)) { + time_rem = hrtimer_get_remaining(&aw8697->timer); + time_ms = ktime_to_ms(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", time_ms); +} + +static ssize_t aw8697_duration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + static unsigned int val_pre; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + if (val_pre != val) + pr_info("%s:val:%d\n", __func__, val); + val_pre = val; + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + + aw8697->duration = val; + + return count; +} + +static ssize_t aw8697_activate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", aw8697->state); +} + +static ssize_t aw8697_activate_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + int rtp_is_going_on = 0; + static unsigned int val_pre; + + /*OP add for juge rtp on begin*/ + rtp_is_going_on = aw8697_haptic_juge_RTP_is_going_on(aw8697); + if (rtp_is_going_on && aw8697->rtp_is_playing) + return count; + if (!aw8697->ram_init) + return count; + /*OP add for juge rtp on end*/ + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val != 0 && val != 1) + return count; + if (val_pre != val) + pr_info("%s: value=%d\n", __FUNCTION__, val); + val_pre = val; + mutex_lock(&aw8697->lock); +/*for type Android OS's vibrator 20181225 begin*/ +/*set mode as RAM*/ + aw8697->activate_mode = AW8697_HAPTIC_ACTIVATE_RAM_MODE; +/*set ram_vbat_comp*/ + /*aw8697->ram_vbat_comp = AW8697_HAPTIC_RAM_VBAT_COMP_ENABLE;*/ +/*set wave number,index*/ + if (check_factory_mode() && aw8697->count_go) + aw8697->index = 19;/* index 19sine 170hz*/ + else + aw8697->index = 10;/*sine 170hz*/ + aw8697_haptic_set_repeat_wav_seq(aw8697, aw8697->index); +/*for type Android OS's vibrator 20181225 end*/ + if (val == 0) + mdelay(10); +#ifdef CONFIG_ARCH_LITO + hrtimer_cancel(&aw8697->timer); + aw8697->state = val; + mutex_unlock(&aw8697->lock); + schedule_work(&aw8697->vibrator_work); +#else + aw8697->state = val; + if (val == 0) { + aw8697_haptic_stop(aw8697); + aw8697_haptic_set_rtp_aei(aw8697, false); + aw8697_interrupt_clear(aw8697); + aw8697->sin_add_flag = 0; + pr_info("%s: value=%d\n", __FUNCTION__, val); + } else { + if (check_factory_mode()) { + aw8697->rtp_file_num = FACTORY_MODE_AT_MODE_RTP_NUMBER;//Number for AT vibration + aw8697->sin_add_flag = 0; + } else { + if (aw8697->duration <= 500) { + aw8697->sin_add_flag = 0; + val = (aw8697->duration - 1)/20; + aw8697->rtp_file_num = val+AW8697_LONG_INDEX_HEAD; + } else { + aw8697->sin_add_flag = 1; + val = 25;//aw8697->duration/20 = 500/20 + aw8697->rtp_file_num = 113; + } + } + pr_info("%s: aw8697->rtp_file_num=%d\n", __FUNCTION__, aw8697->rtp_file_num); + aw8697_haptic_stop(aw8697); + aw8697_haptic_set_rtp_aei(aw8697, false); + aw8697_interrupt_clear(aw8697); + queue_work(system_highpri_wq, &aw8697->rtp_work); + } + mutex_unlock(&aw8697->lock); +#endif + return count; +} + +static ssize_t aw8697_activate_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "activate_mode=%d\n", aw8697->activate_mode); +} + +static ssize_t aw8697_activate_mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + if (!aw8697->ram_init) + return count; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + pr_info("%s:val:%d\n", __func__, val); + mutex_lock(&aw8697->lock); + aw8697->activate_mode = val; + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_index_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned char reg_val = 0; + aw8697_i2c_read(aw8697, AW8697_REG_WAVSEQ1, ®_val); + aw8697->index = reg_val; + + return snprintf(buf, PAGE_SIZE, "%d\n", aw8697->index); +} + +static ssize_t aw8697_index_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + static unsigned int val_pre; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + if (val_pre != val) + pr_info("%s: value=%d\n", __FUNCTION__, val); + val_pre = val; + mutex_lock(&aw8697->lock); + aw8697->index = val; + aw8697_haptic_set_repeat_wav_seq(aw8697, aw8697->index); + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_vmax_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8697->vmax); +} + +static ssize_t aw8697_vmax_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + static unsigned int val_pre; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + if (!aw8697->ram_init) + return count; + if (val_pre != val) + pr_info("%s: value=%d\n", __FUNCTION__, val); + val_pre = val; + mutex_lock(&aw8697->lock); + aw8697->vmax = val; + aw8697_haptic_set_bst_vol(aw8697, aw8697->vmax); + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + + return snprintf(buf, PAGE_SIZE, "0x%02x\n", aw8697->gain); +} + +static ssize_t aw8697_gain_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + static unsigned int val_pre; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + if (!aw8697->ram_init) + return count; + if (val_pre != val) + pr_info("%s: value=%d\n", __FUNCTION__, val); + val_pre = val; + mutex_lock(&aw8697->lock); + aw8697->gain = val; + aw8697_haptic_set_gain(aw8697, aw8697->gain); + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_seq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for(i=0; iseq[i] |= reg_val; + } + return count; +} + +static ssize_t aw8697_seq_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[2] = {0, 0}; + + if (!aw8697->ram_init) + return count; + + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + pr_debug("%s: seq%d=0x%x\n", __FUNCTION__, databuf[0], databuf[1]); + mutex_lock(&aw8697->lock); + aw8697->seq[databuf[0]] = (unsigned char)databuf[1]; + aw8697_haptic_set_wav_seq(aw8697, (unsigned char)databuf[0], + aw8697->seq[databuf[0]]); + mutex_unlock(&aw8697->lock); + } + return count; +} + +static ssize_t aw8697_loop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + size_t count = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + + for(i=0; iloop[i*2+0] = (reg_val>>4)&0x0F; + aw8697->loop[i*2+1] = (reg_val>>0)&0x0F; + + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d loop: 0x%02x\n", i*2+1, aw8697->loop[i*2+0]); + count += snprintf(buf+count, PAGE_SIZE-count, + "seq%d loop: 0x%02x\n", i*2+2, aw8697->loop[i*2+1]); + } + return count; +} + +static ssize_t aw8697_loop_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[2] = {0, 0}; + + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + pr_debug("%s: seq%d loop=0x%x\n", __FUNCTION__, databuf[0], databuf[1]); + mutex_lock(&aw8697->lock); + aw8697->loop[databuf[0]] = (unsigned char)databuf[1]; + aw8697_haptic_set_wav_loop(aw8697, (unsigned char)databuf[0], + aw8697->loop[databuf[0]]); + mutex_unlock(&aw8697->lock); + } + + return count; +} + +static ssize_t aw8697_reg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + for(i = 0; i < AW8697_REG_MAX; i ++) { + if(!(aw8697_reg_access[i]®_RD_ACCESS)) + continue; + aw8697_i2c_read(aw8697, i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val); + } + return len; +} + +static ssize_t aw8697_reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[2] = {0, 0}; + + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw8697_i2c_write(aw8697, (unsigned char)databuf[0], (unsigned char)databuf[1]); + } + + return count; +} + +static ssize_t aw8697_rtp_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "rtp play: %d\n", aw8697->rtp_cnt); + + return len; +} +#define AUDIO_READY_STATUS 1024 + +static ssize_t aw8697_rtp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + int rtp_is_going_on = 0; + + if (!aw8697->ram_init) + return count; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) { + pr_info("%s: kstrtouint fail\n", __FUNCTION__); + return rc; + } + pr_info("%s: rtp[%d]\n", __FUNCTION__,val); + + /*OP add for juge rtp on begin*/ + rtp_is_going_on = aw8697_haptic_juge_RTP_is_going_on(aw8697); + if (rtp_is_going_on && (val == AUDIO_READY_STATUS)) + { + pr_info("%s: seem audio status rtp[%d]\n", __FUNCTION__,val); + return count; + } + /*OP add for juge rtp on end*/ + + if (!aw8697->haptic_ready && (val == AUDIO_READY_STATUS)) { + pr_info("%s: invalid audio ready\n", __FUNCTION__); + return count; + } + if (val == HAL_FACTORY_MODE_NORMAL_RTP_NUMBER) + val = FACTORY_MODE_EFFECT_NUMBER; + if (val == HAL_FACTORY_MODE_HIGH_TEMP_RTP_NUMBER) + val = FACTORY_MODE_EFFECT_NUMBER; + if (val != FACTORY_MODE_EFFECT_NUMBER + && val != 0 + && !aw8697->ignore_sync) { + if (val == AUDIO_READY_STATUS) + aw8697->audio_ready = true; + else + aw8697->haptic_ready = true; + + pr_info("%s:audio[%d]and haptic[%d] ready\n", __FUNCTION__, + aw8697->audio_ready, aw8697->haptic_ready); + if (aw8697->haptic_ready && !aw8697->audio_ready) { + aw8697->pre_haptic_number = val; + } + if (!aw8697->audio_ready || !aw8697->haptic_ready) { + return count; + } + } + if (val == AUDIO_READY_STATUS && aw8697->pre_haptic_number) { + pr_info("pre_haptic_number:%d\n",aw8697->pre_haptic_number); + val = aw8697->pre_haptic_number; + } + if (!val) { + aw8697_op_clean_status(aw8697); + } + aw8697->audio_ready = false; + aw8697->haptic_ready = false; + aw8697->pre_haptic_number = 0; + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + aw8697_haptic_set_rtp_aei(aw8697, false); + aw8697_interrupt_clear(aw8697); + if (val < (sizeof(aw8697_rtp_name)/AW8697_RTP_NAME_MAX)) { + if (val == FACTORY_MODE_EFFECT_NUMBER) { + if (aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_1) + aw8697->rtp_file_num = FACTORY_MODE_160HZ_EFFECTION; + else if (aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_2) + aw8697->rtp_file_num = FACTORY_MODE_162HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_3) + aw8697->rtp_file_num = FACTORY_MODE_164HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_4) + aw8697->rtp_file_num = FACTORY_MODE_166HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_5) + aw8697->rtp_file_num = FACTORY_MODE_168HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_6) + aw8697->rtp_file_num =FACTORY_MODE_170HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_7) + aw8697->rtp_file_num = FACTORY_MODE_172HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_8) + aw8697->rtp_file_num = FACTORY_MODE_174HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_9) + aw8697->rtp_file_num = FACTORY_MODE_176HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_10) + aw8697->rtp_file_num = FACTORY_MODE_178HZ_EFFECTION; + else if(aw8697->haptic_real_f0 <= HAPTIC_REAL_F0_11) + aw8697->rtp_file_num = FACTORY_MODE_180HZ_EFFECTION; + else + aw8697->rtp_file_num = FACTORY_MODE_170HZ_EFFECTION; + } else { + aw8697->rtp_file_num = val; + } + if(val) { + aw8697->rtp_is_playing = 1; + queue_work(system_highpri_wq, &aw8697->rtp_work); + } + } else { + pr_err("%s: rtp_file_num 0x%02x over max value \n", __func__, aw8697->rtp_file_num); + } + mutex_unlock(&aw8697->lock); + + return count; +} + +static ssize_t aw8697_ram_update_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "sram update mode\n"); + return len; +} + +static ssize_t aw8697_ram_update_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if(val) { + aw8697_ram_update(aw8697); + } + return count; +} + +static ssize_t aw8697_f0_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + + mutex_lock(&aw8697->lock); + aw8697->f0_cali_flag = AW8697_HAPTIC_CALI_F0; + aw8697_haptic_get_f0(aw8697); + aw8697->haptic_real_f0 = aw8697->f0/10; + mutex_unlock(&aw8697->lock); + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->f0/10); + return len; +} + +static ssize_t aw8697_f0_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + aw8697->haptic_real_f0 = val; + pr_info("aw8697->haptic_real_f0:%d\n", aw8697->haptic_real_f0); + return count; +} + +static ssize_t aw8697_f0_cali_data_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->f0_calib_data); + return len; +} + +static ssize_t aw8697_f0_cali_data_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + aw8697->f0_calib_data = val; + pr_info("aw8697->haptic_real_f0:%d\n", aw8697->f0_calib_data); + return count; +} + +static ssize_t aw8697_cali_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->haptic_real_f0); + return len; +} + +static ssize_t aw8697_cali_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + pr_info("%s:val:%d\n", __func__, val); + if(val) { + mutex_lock(&aw8697->lock); + aw8697_haptic_f0_calibration(aw8697); + mutex_unlock(&aw8697->lock); + } + return count; +} +#define RESISTANCE_ABNORMAL_THR 5 + +static ssize_t aw8697_short_check_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + ssize_t len = 0; + bool short_circuit = 0; + unsigned char reg_val = 0; + + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + + + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_HD_PD_MASK, AW8697_BIT_ANACTRL_HD_HZ_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_D2SCFG, + AW8697_BIT_D2SCFG_CLK_ADC_MASK, AW8697_BIT_D2SCFG_CLK_ASC_1P5MHZ); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_RL_OS_MASK, AW8697_BIT_DETCTRL_RL_DETECT); + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_DIAG_GO_MASK, AW8697_BIT_DETCTRL_DIAG_GO_ENABLE); + usleep_range(3000, 3500); + aw8697_i2c_read(aw8697, AW8697_REG_RLDET, ®_val); + aw8697->lra = 298 * reg_val; + if (aw8697->lra/100 < RESISTANCE_ABNORMAL_THR) + short_circuit = true; + pr_info("aw8697_short_check aw8697->lra/100 :%d\n", aw8697->lra/100 ); + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_HD_PD_MASK, AW8697_BIT_ANACTRL_HD_PD_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_D2SCFG, + AW8697_BIT_D2SCFG_CLK_ADC_MASK, AW8697_BIT_D2SCFG_CLK_ASC_6MHZ); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + mutex_unlock(&aw8697->lock); + if (short_circuit) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", -1); + return len; + } else { + mutex_lock(&aw8697->lock); + aw8697_i2c_write(aw8697, AW8697_REG_SYSINTM, 0x9f); + aw8697_haptic_set_wav_seq(aw8697, 0x01, 0x00); + aw8697_haptic_set_wav_loop(aw8697, 0, 0); + aw8697_haptic_stop(aw8697); + aw8697_haptic_play_wav_seq(aw8697, 1); + mutex_unlock(&aw8697->lock); + usleep_range(200000, 205000); + aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + aw8697_i2c_write(aw8697, AW8697_REG_SYSINTM, 0xb9); + pr_info("aw8697_short_check 0x02:0x%x\n", reg_val); + short_circuit = reg_val & AW8697_BIT_SYSINT_OCDI; + if (short_circuit) { + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", -1); + return len; + } + } + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", 0); + return len; +} + +static ssize_t aw8697_short_check_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8697_ignore_sync_tore(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + static unsigned int val_pre; + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + if (val_pre != val) + pr_info("%s:val:%d\n", __func__, val); + val_pre = val; + aw8697->ignore_sync = val; + return count; +} + +static ssize_t aw8697_ignore_sync_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + + return snprintf(buf, PAGE_SIZE, "%lld\n", aw8697->ignore_sync); +} + +static ssize_t aw8697_cont_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + aw8697_haptic_read_cont_f0(aw8697); + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697 cont f0 = %d\n", aw8697->cont_f0); + return len; +} + +static ssize_t aw8697_cont_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + pr_info("%s:val:%d\n", __func__, val); + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + if(val) { + aw8697_haptic_cont(aw8697); + } + mutex_unlock(&aw8697->lock); + return count; +} + + +static ssize_t aw8697_cont_td_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697 cont delay time = 0x%04x\n", aw8697->cont_td); + return len; +} + +static ssize_t aw8697_cont_td_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[1] = {0}; + if(1 == sscanf(buf, "%x", &databuf[0])) { + aw8697->cont_td = databuf[0]; + aw8697_i2c_write(aw8697, AW8697_REG_TD_H, (unsigned char)(databuf[0]>>8)); + aw8697_i2c_write(aw8697, AW8697_REG_TD_L, (unsigned char)(databuf[0]>>0)); + } + return count; +} + +static ssize_t aw8697_cont_drv_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697 cont drv level = %d\n", aw8697->cont_drv_lvl); + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697 cont drv level overdrive= %d\n", aw8697->cont_drv_lvl_ov); + return len; +} + +static ssize_t aw8697_cont_drv_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[2] = {0, 0}; + if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) { + aw8697->cont_drv_lvl = databuf[0]; + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL, aw8697->cont_drv_lvl); + aw8697->cont_drv_lvl_ov = databuf[1]; + aw8697_i2c_write(aw8697, AW8697_REG_DRV_LVL_OV, aw8697->cont_drv_lvl_ov); + } + return count; +} + +static ssize_t aw8697_cont_num_brk_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697 cont break num = %d\n", aw8697->cont_num_brk); + return len; +} + +static ssize_t aw8697_cont_num_brk_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[1] = {0}; + if(1 == sscanf(buf, "%d", &databuf[0])) { + aw8697->cont_num_brk = databuf[0]; + if(aw8697->cont_num_brk > 7) { + aw8697->cont_num_brk = 7; + } + aw8697_i2c_write_bits(aw8697, AW8697_REG_BEMF_NUM, + AW8697_BIT_BEMF_NUM_BRK_MASK, aw8697->cont_num_brk); + } + return count; +} + +static ssize_t aw8697_cont_zc_thr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697 cont zero cross thr = 0x%04x\n", aw8697->cont_zc_thr); + return len; +} + +static ssize_t aw8697_cont_zc_thr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[1] = {0}; + if(1 == sscanf(buf, "%x", &databuf[0])) { + aw8697->cont_zc_thr = databuf[0]; + aw8697_i2c_write(aw8697, AW8697_REG_ZC_THRSH_H, (unsigned char)(databuf[0]>>8)); + aw8697_i2c_write(aw8697, AW8697_REG_ZC_THRSH_L, (unsigned char)(databuf[0]>>0)); + } + return count; +} + +static ssize_t aw8697_vbat_monitor_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + aw8697_haptic_get_vbat(aw8697); + len += snprintf(buf+len, PAGE_SIZE-len, "vbat=%dmV\n", aw8697->vbat); + mutex_unlock(&aw8697->lock); + + return len; +} + +static ssize_t aw8697_vbat_monitor_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8697_lra_resistance_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + unsigned char reg_val = 0; + + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BYPASS); + + + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_HD_PD_MASK, AW8697_BIT_ANACTRL_HD_HZ_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_D2SCFG, + AW8697_BIT_D2SCFG_CLK_ADC_MASK, AW8697_BIT_D2SCFG_CLK_ASC_1P5MHZ); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_RL_OS_MASK, AW8697_BIT_DETCTRL_RL_DETECT); + aw8697_i2c_write_bits(aw8697, AW8697_REG_DETCTRL, + AW8697_BIT_DETCTRL_DIAG_GO_MASK, AW8697_BIT_DETCTRL_DIAG_GO_ENABLE); + usleep_range(3000, 3500); + aw8697_i2c_read(aw8697, AW8697_REG_RLDET, ®_val); + aw8697->lra = 298 * reg_val; + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->lra/100); + + + aw8697_i2c_write_bits(aw8697, AW8697_REG_ANACTRL, + AW8697_BIT_ANACTRL_HD_PD_MASK, AW8697_BIT_ANACTRL_HD_PD_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_D2SCFG, + AW8697_BIT_D2SCFG_CLK_ADC_MASK, AW8697_BIT_D2SCFG_CLK_ASC_6MHZ); + + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_BST_MODE_MASK, AW8697_BIT_SYSCTRL_BST_MODE_BOOST); + mutex_unlock(&aw8697->lock); + + return len; +} + +static ssize_t aw8697_lra_resistance_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t aw8697_auto_boost_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "auto_boost=%d\n", aw8697->auto_boost); + return len; +} + + +static ssize_t aw8697_auto_boost_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + pr_info("%s:val:%d\n", __func__, val); + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + aw8697_haptic_auto_boost_config(aw8697, val); + mutex_unlock(&aw8697->lock); + + return count; +} + +static ssize_t aw8697_prctmode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + unsigned char reg_val = 0; + + aw8697_i2c_read(aw8697, AW8697_REG_RLDET, ®_val); + + len += snprintf(buf+len, PAGE_SIZE-len, "prctmode=%d\n", reg_val&0x20); + return len; +} + + +static ssize_t aw8697_prctmode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + #ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); + #else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + #endif + unsigned int databuf[2] = {0, 0}; + unsigned int addr=0; + unsigned int val=0; + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + addr = databuf[0]; + val=databuf[1]; + mutex_lock(&aw8697->lock); + aw8697_haptic_swicth_motorprotect_config(aw8697, addr, val); + mutex_unlock(&aw8697->lock); + } + return count; +} +static ssize_t aw8697_trig_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + unsigned char i = 0; + for(i=0; itrig[i].enable, aw8697->trig[i].default_level, aw8697->trig[i].dual_edge, + aw8697->trig[i].frist_seq, aw8697->trig[i].second_seq); + } + + return len; +} + +static ssize_t aw8697_trig_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + #ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); + #else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + #endif + unsigned int databuf[6] = {0}; + if(sscanf(buf, "%d %d %d %d %d %d", + &databuf[0], &databuf[1], &databuf[2], &databuf[3], &databuf[4], &databuf[5])) { + pr_info("%s: %d, %d, %d, %d, %d, %d\n", __func__, + databuf[0], databuf[1], databuf[2], databuf[3], databuf[4], databuf[5]); + if(databuf[0] > 3) { + databuf[0] = 3; + } + if(databuf[0] > 0) { + databuf[0] -= 1; + } + aw8697->trig[databuf[0]].enable = databuf[1]; + aw8697->trig[databuf[0]].default_level = databuf[2]; + aw8697->trig[databuf[0]].dual_edge = databuf[3]; + aw8697->trig[databuf[0]].frist_seq = databuf[4]; + aw8697->trig[databuf[0]].second_seq = databuf[5]; + mutex_lock(&aw8697->lock); + aw8697_haptic_trig_param_config(aw8697); + aw8697_haptic_trig_enable_config(aw8697); + mutex_unlock(&aw8697->lock); + } + return count; +} + +static ssize_t aw8697_ram_vbat_comp_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "ram_vbat_comp=%d\n", aw8697->ram_vbat_comp); + + return len; +} + + +static ssize_t aw8697_ram_vbat_comp_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8697->lock); + if(val) { + aw8697->ram_vbat_comp = AW8697_HAPTIC_RAM_VBAT_COMP_ENABLE; + } else { + aw8697->ram_vbat_comp = AW8697_HAPTIC_RAM_VBAT_COMP_DISABLE; + } + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_haptic_osc_data_show(struct device *dev, struct device_attribute *attr, +char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->lra_calib_data); + + return len; +} + + +static ssize_t aw8697_osc_data_store(struct device *dev, struct device_attribute *attr, +const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + unsigned int val = 0; + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + pr_info("%s: vqal:\n", __func__, val); + if (rc < 0) + return rc; + mutex_lock(&aw8697->lock); + pr_info("%s: val:%d\n", __func__, val); + if(val) + aw8697_i2c_write(aw8697, AW8697_REG_TRIM_LRA, (char)val); + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_osc_cali_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + ssize_t len = 0; + + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->microsecond); + return len; +} + +static ssize_t aw8697_osc_cali_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int val = 0; + + int rc = 0; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + mutex_lock(&aw8697->lock); + if(val == 3){ + aw8697_haptic_osc_set_default_trim(aw8697); + aw8697->lra_calib_data = 0; + aw8697_rtp_osc_calibration(aw8697); + aw8697_rtp_trim_lra_calibration(aw8697); + } + if(val == 1) + aw8697_rtp_osc_calibration(aw8697); + + mutex_unlock(&aw8697->lock); + return count; +} + +static ssize_t aw8697_haptic_audio_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "%d\n", aw8697->haptic_audio.ctr.cnt); + return len; +} + +static ssize_t aw8697_haptic_audio_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[6] = {0}; + struct haptic_ctr *hap_ctr = NULL; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + if (!aw8697->ram_init) + return count; + if(6 == sscanf(buf, "%d %d %d %d %d %d", &databuf[0], &databuf[1], &databuf[2], + &databuf[3], &databuf[4], &databuf[5])) { + if (databuf[2]) { + pr_debug("%s: cnt=%d, cmd=%d, play=%d, wavseq=%d, loop=%d, gain=%d\n", + __func__, databuf[0], databuf[1], databuf[2], databuf[3], + databuf[4], databuf[5]); + } + + hap_ctr = (struct haptic_ctr *)kzalloc( + sizeof(struct haptic_ctr), GFP_KERNEL); + if (hap_ctr== NULL ) { + pr_err("%s: kzalloc memory fail\n", __func__); + return count; + } + mutex_lock(&aw8697->haptic_audio.lock); + hap_ctr->cnt = (unsigned char)databuf[0]; + hap_ctr->cmd = (unsigned char)databuf[1]; + hap_ctr->play = (unsigned char)databuf[2]; + hap_ctr->wavseq = (unsigned char)databuf[3]; + hap_ctr->loop = (unsigned char)databuf[4]; + hap_ctr->gain = (unsigned char)databuf[5]; + aw8697_haptic_audio_ctr_list_insert(&aw8697->haptic_audio, hap_ctr); + + if(hap_ctr->cmd == 0xff) { + pr_debug("%s: haptic_audio stop\n", __func__); + if(hrtimer_active(&aw8697->haptic_audio.timer)) { + pr_debug("%s: cancel haptic_audio_timer\n", __func__); + hrtimer_cancel(&aw8697->haptic_audio.timer); + aw8697->haptic_audio.ctr.cnt = 0; + aw8697_haptic_audio_off(aw8697); + } + } else { + if(hrtimer_active(&aw8697->haptic_audio.timer)) { + } else { + pr_debug("%s: start haptic_audio_timer\n", __func__); + aw8697_haptic_audio_init(aw8697); + hrtimer_start(&aw8697->haptic_audio.timer, + ktime_set(aw8697->haptic_audio.delay_val/1000000, + (aw8697->haptic_audio.delay_val%1000000)*1000), + HRTIMER_MODE_REL); + } + } + mutex_unlock(&aw8697->haptic_audio.lock); + kfree(hap_ctr); + } + return count; +} + + +static ssize_t aw8697_haptic_audio_time_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "haptic_audio.delay_val=%dus\n", aw8697->haptic_audio.delay_val); + len += snprintf(buf+len, PAGE_SIZE-len, "haptic_audio.timer_val=%dus\n", aw8697->haptic_audio.timer_val); + return len; +} + +static ssize_t aw8697_haptic_audio_time_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[2] = {0}; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) { + aw8697->haptic_audio.delay_val = databuf[0]; + aw8697->haptic_audio.timer_val = databuf[1]; + } + return count; +} + +static ssize_t aw8697_haptic_audio_tp_time_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + struct tp *tp = &(aw8697->haptic_audio.tp); + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "tp->press_delay_min=%dus\n", tp->press_delay_min); + len += snprintf(buf+len, PAGE_SIZE-len, "tp->press_delay_max=%dus\n", tp->press_delay_max); + len += snprintf(buf+len, PAGE_SIZE-len, "tp->release_delay_max=%dus\n", tp->release_delay_max); + len += snprintf(buf+len, PAGE_SIZE-len, "tp->no_play_cnt_max=%d\n", tp->no_play_cnt_max); + return len; +} + +static ssize_t aw8697_haptic_audio_tp_time_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[4] = {0}; + struct tp *tp = &(aw8697->haptic_audio.tp); + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + if(4 == sscanf(buf, "%d %d %d %d", &databuf[0], &databuf[1], &databuf[2], &databuf[3])) { + tp->press_delay_min = databuf[0]; + tp->press_delay_max = databuf[1]; + tp->release_delay_max = databuf[2]; + tp->no_play_cnt_max= databuf[3]; + pr_info("tp->press_delay_min=%dus\n", tp->press_delay_min); + pr_info("tp->press_delay_max=%dus\n", tp->press_delay_max); + pr_info("tp->release_delay_max=%dus\n", tp->release_delay_max); + pr_info("tp->no_play_cnt_max=%dus\n", tp->no_play_cnt_max); + } + return count; +} + + +static ssize_t aw8697_haptic_audio_tp_input_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + //struct timed_output_dev *to_dev = dev_get_drvdata(dev); + //struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + //struct led_classdev *cdev = dev_get_drvdata(dev); + //struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + return len; +} + +static ssize_t aw8697_haptic_audio_tp_input_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + struct tp_input_info tp_input; + struct tp *tp = &(aw8697->haptic_audio.tp); + struct haptic_audio *haptic_audio = NULL; + struct haptic_audio_trust_zone *p_tmp = NULL; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + haptic_audio = &(aw8697->haptic_audio); + + if (count != sizeof(struct tp_input_info)) { + pr_err("%s: unmatch buf len, node_len=%d, struct len=%d\n", + __func__, count, sizeof(struct tp_input_info)); + return count; + } + + memcpy(&tp_input, buf, sizeof(struct tp_input_info)); + pr_debug("%s: id[%d]: status=%d, x=%d, y=%d\n", + __func__, tp_input.id, tp_input.status, tp_input.x, tp_input.y); + + mutex_lock(&aw8697->haptic_audio.lock); + if((AW8697_HAPTIC_TP_ST_PRESS == tp_input.status) && + (tp_input.status != tp->id[tp_input.id].pt_info.status)) { + tp->tp_ai_check_flag = 1; + tp->id[tp_input.id].tp_ai_match_flag = 0; + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + if ((tp_input.x+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W > p_tmp->x) && + (tp_input.x < p_tmp->x+p_tmp->w+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W) && + (tp_input.y+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H > p_tmp->y) && + (tp_input.y < p_tmp->y+p_tmp->h+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H)) { + pr_debug("%s: tp input point[%d, %04d, %04d] is in the ai trust zone[%d, %04d, %04d, %04d, %04d]\n", + __func__, tp_input.id, tp_input.x, tp_input.y, + p_tmp->level, p_tmp->x, p_tmp->y, p_tmp->w, p_tmp->h); + tp->id[tp_input.id].tp_ai_match_flag = 1; + do_gettimeofday(&tp->id[AW8697_HAPTIC_TP_ID_MAX].t_press); + tp->virtual_id = tp_input.id; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.id = tp_input.id; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.x = tp_input.x; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.y = tp_input.y; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.status = tp_input.status; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.touch_flag = AW8697_HAPTIC_TP_TOUCH_VAIL; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.touch_outside_tz_flag = AW8697_HAPTIC_TP_TOUCH_VAIL; + tp->id[AW8697_HAPTIC_TP_ID_MAX].tp_flag = AW8697_HAPTIC_TP_PRESS; + tp->id[AW8697_HAPTIC_TP_ID_MAX].press_flag = AW8697_HAPTIC_TP_PRESS; + tp->id[AW8697_HAPTIC_TP_ID_MAX].release_flag = AW8697_HAPTIC_TP_NULL; + tp->id[AW8697_HAPTIC_TP_ID_MAX].no_play_cnt = 0; + tp->id[AW8697_HAPTIC_TP_ID_MAX].press_no_vibrate_flag = 0; + break; + } + } + if (tp->id[tp_input.id].tp_ai_match_flag == 0) { + pr_debug("%s: tp input point[%d, %04d, %04d] is out the trust zone\n", + __func__, tp_input.id, tp_input.x, tp_input.y); + } + tp->id[tp_input.id].pt_info.id = tp_input.id; + tp->id[tp_input.id].pt_info.x = tp_input.x; + tp->id[tp_input.id].pt_info.y = tp_input.y; + tp->id[tp_input.id].pt_info.status = tp_input.status; + tp->id[tp_input.id].pt_info.touch_flag = AW8697_HAPTIC_TP_TOUCH_VAIL; + tp->id[tp_input.id].pt_info.touch_outside_tz_flag = AW8697_HAPTIC_TP_TOUCH_VAIL; + tp->id[tp_input.id].tp_flag = AW8697_HAPTIC_TP_PRESS; + tp->id[tp_input.id].press_flag = AW8697_HAPTIC_TP_PRESS; + tp->id[tp_input.id].release_flag = AW8697_HAPTIC_TP_NULL; + tp->id[tp_input.id].no_play_cnt = 0; + tp->id[tp_input.id].press_no_vibrate_flag = 0; + do_gettimeofday(&tp->id[tp_input.id].t_press); + pr_debug("%s: tp_press_release: status=%d, flag=%d", + __func__, tp->id[tp_input.id].pt_info.status, tp->id[tp_input.id].tp_flag); + } + + if((AW8697_HAPTIC_TP_ST_RELEASE == tp_input.status) && + (tp_input.status != tp->id[tp_input.id].pt_info.status)) { + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + if ((tp->id[tp_input.id].pt_info.x+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W > p_tmp->x) && + (tp->id[tp_input.id].pt_info.x < p_tmp->x+p_tmp->w+AW8697_HAPTIC_AI_X_JITTER*p_tmp->w/AW8697_HAPTIC_AI_X_DFT_W) && + (tp->id[tp_input.id].pt_info.y+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H > p_tmp->y) && + (tp->id[tp_input.id].pt_info.y < p_tmp->y+p_tmp->h+AW8697_HAPTIC_AI_Y_JITTER*p_tmp->h/AW8697_HAPTIC_AI_Y_DFT_H)) { + pr_debug("%s: tp input point[%d, %04d, %04d] up is in the ai trust zone[%d, %04d, %04d, %04d, %04d]\n", + __func__, tp->id[tp_input.id].pt_info.id, tp->id[tp_input.id].pt_info.x, tp->id[tp_input.id].pt_info.y, + p_tmp->level, p_tmp->x, p_tmp->y, p_tmp->w, p_tmp->h); + if(tp->virtual_id == tp_input.id) { + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.id = tp->id[tp_input.id].pt_info.id; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.x = tp->id[tp_input.id].pt_info.x; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.y = tp->id[tp_input.id].pt_info.y; + tp->id[AW8697_HAPTIC_TP_ID_MAX].pt_info.status = tp_input.status; + tp->id[AW8697_HAPTIC_TP_ID_MAX].tp_flag = AW8697_HAPTIC_TP_RELEASE; + tp->id[AW8697_HAPTIC_TP_ID_MAX].release_flag = AW8697_HAPTIC_TP_RELEASE; + do_gettimeofday(&tp->id[AW8697_HAPTIC_TP_ID_MAX].t_release); + } + break; + } + } + tp->id[tp_input.id].pt_info.status = tp_input.status; + tp->id[tp_input.id].tp_flag = AW8697_HAPTIC_TP_RELEASE; + tp->id[tp_input.id].release_flag = AW8697_HAPTIC_TP_RELEASE; + do_gettimeofday(&tp->id[tp_input.id].t_release); + pr_debug("%s: tp input point[%d, %04d, %04d] up to [%d, %04d, %04d] \n", + __func__, tp_input.id, tp->id[tp_input.id].pt_info.x, tp->id[tp_input.id].pt_info.y, + tp_input.id, tp_input.x, tp_input.y); + pr_debug("%s: tp_press_release: status=%d, flag=%d", + __func__, tp->id[tp_input.id].pt_info.status, tp->id[tp_input.id].tp_flag); + } + mutex_unlock(&aw8697->haptic_audio.lock); + + return count; +} + +static ssize_t aw8697_haptic_audio_ai_input_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + struct haptic_audio *haptic_audio = NULL; + struct haptic_audio_trust_zone *p_tmp = NULL; + char *p_ai_data = NULL; + ssize_t len = 0; + int i = 0; + uint8_t ai_tz_num = 0; + + mutex_lock(&aw8697->haptic_audio.lock); + haptic_audio = &(aw8697->haptic_audio); + ai_tz_num = 0; + + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + ai_tz_num ++; + } + pr_debug("%s: ai_tz_num=%d\n", __func__, ai_tz_num); + + p_ai_data = (char *) kzalloc(sizeof(uint8_t) + ai_tz_num * sizeof(struct ai_trust_zone), GFP_KERNEL); + if (!p_ai_data) { + pr_err("%s: p_ai_data error allocating memory\n", __func__); + mutex_unlock(&aw8697->haptic_audio.lock); + return len; + } + + memcpy(&p_ai_data[len], &ai_tz_num, sizeof(ai_tz_num)); + len += sizeof(ai_tz_num); + + list_for_each_entry(p_tmp, &(haptic_audio->list), list) { + haptic_audio->output_tz_info[i].level = p_tmp->level; + haptic_audio->output_tz_info[i].x = p_tmp->x; + haptic_audio->output_tz_info[i].y = p_tmp->y; + haptic_audio->output_tz_info[i].w = p_tmp->w; + haptic_audio->output_tz_info[i].h = p_tmp->h; + memcpy(&p_ai_data[len], &haptic_audio->output_tz_info[i], sizeof(struct trust_zone_info)); + len += sizeof(struct trust_zone_info); + pr_debug("%s: trust zone [%d]: level=%d, x=%d, y=%d, w=%d, h=%d\n", + __func__, i, haptic_audio->output_tz_info[i].level, + haptic_audio->output_tz_info[i].x, haptic_audio->output_tz_info[i].y, + haptic_audio->output_tz_info[i].w, haptic_audio->output_tz_info[i].h); + i ++; + } + memcpy(buf, p_ai_data, len); + + kfree(p_ai_data); + mutex_unlock(&aw8697->haptic_audio.lock); + + return len; +} + +static ssize_t aw8697_haptic_audio_ai_input_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + int ret = -1; + unsigned int i = 0; + int match = 0; + struct ai_trust_zone *ai_tz = NULL; + struct trust_zone_info *ai_tz_info = NULL; + struct haptic_audio *haptic_audio = NULL; + struct haptic_audio_trust_zone *p_tmp = NULL; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + haptic_audio = &(aw8697->haptic_audio); + + if (count != sizeof(struct ai_trust_zone)) { + pr_err("%s: unmatch buf len, node_len=%d, struct len=%d\n", + __func__, count, sizeof(struct ai_trust_zone)); + return count; + } + + mutex_lock(&aw8697->haptic_audio.lock); + ai_tz = kzalloc(sizeof(struct ai_trust_zone), GFP_KERNEL); + if (!ai_tz) { + pr_err("%s: ai_tz error allocating memory\n", __func__); + mutex_unlock(&aw8697->haptic_audio.lock); + return count; + } + memcpy(ai_tz, buf, sizeof(struct ai_trust_zone)); + pr_debug("%s: ai_tz num=%d\n", __func__, ai_tz->num); + + ai_tz_info = kzalloc(ai_tz->num * sizeof(struct trust_zone_info), GFP_KERNEL); + if (!ai_tz_info) { + pr_err("%s: ai_tz_info error allocating memory\n", __func__); + kfree(ai_tz); + mutex_unlock(&aw8697->haptic_audio.lock); + return count; + } + ret = copy_from_user(ai_tz_info, ai_tz->tz_info, ai_tz->num * sizeof(struct trust_zone_info)); + if (ret) { + kfree(ai_tz_info); + kfree(ai_tz); + dev_err(aw8697->dev, "%s: copy from user fail\n", __func__); + mutex_unlock(&aw8697->haptic_audio.lock); + return count; + } + + aw8697->haptic_audio.tz_high_num = 2; + aw8697->haptic_audio.hap_cnt_outside_tz = 0; +#ifndef SCORE_MODE + /* clear unused list link */ + aw8697_haptic_audio_tz_list_clear(&aw8697->haptic_audio); +#endif + + if(haptic_audio->tz_num >= 5) { + haptic_audio->tz_num = 0; + aw8697_haptic_audio_tz_score_list_clear(haptic_audio); + } + + for (i=0; inum; i++) { + pr_debug("%s: trust zone [%d]: level=%d, x=%d, y=%d, w=%d, h=%d\n", + __func__, i, ai_tz_info[i].level, + ai_tz_info[i].x, ai_tz_info[i].y, + ai_tz_info[i].w, ai_tz_info[i].h); + match = 0; + + if(haptic_audio->tz_init) + ai_tz_info[i].level = 0; + else + ai_tz_info[i].level = TRUST_LEVEL; + + if(haptic_audio->tz_init){ + list_for_each_entry(p_tmp, &haptic_audio->list, list) { + if(aw8697_haptic_audio_tz_list_match(p_tmp,&ai_tz_info[i])){ + match = 1; + break; + } + } + if(match) + continue; + } + + if(haptic_audio->tz_init){ + list_for_each_entry(p_tmp, &haptic_audio->score_list, list) { + if(aw8697_haptic_audio_tz_list_match(p_tmp,&ai_tz_info[i])){ + match = 1; + break; + } + } + } + if(match != 1) + aw8697_haptic_audio_tz_list_insert(haptic_audio, &ai_tz_info[i]); + } + haptic_audio->tz_init = 1; + aw8697_haptic_audio_tz_list_show(haptic_audio); + + kfree(ai_tz_info); + kfree(ai_tz); + + mutex_unlock(&aw8697->haptic_audio.lock); + return count; +} + +static ssize_t aw8697_haptic_audio_tp_size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + struct haptic_audio_tp_size *tp_size = NULL; + ssize_t len = 0; + + tp_size = &(aw8697->haptic_audio.tp_size); + + len += snprintf(buf+len, PAGE_SIZE-len, "tp_size: x=%04d, y=%04d\n", tp_size->x, tp_size->y); + + return len; +} + +static ssize_t aw8697_haptic_audio_tp_size_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + struct haptic_audio_tp_size *tp_size = NULL; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + tp_size = &(aw8697->haptic_audio.tp_size); + + if (count != sizeof(struct haptic_audio_tp_size)) { + pr_err("%s: unmatch buf len, node_len=%d, struct len=%d\n", + __func__, count, sizeof(struct haptic_audio_tp_size)); + return count; + } + + memcpy(tp_size, buf, sizeof(struct haptic_audio_tp_size)); + pr_info("%s: tp_size: x=%d, y=%d\n", + __func__, tp_size->x, tp_size->y); + + + return count; +} + +static ssize_t aw8697_haptic_audio_tz_cnt_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "tz_cnt_thr=%d\n", aw8697->haptic_audio.tz_cnt_thr); + len += snprintf(buf+len, PAGE_SIZE-len, "tz_cnt_max=%d\n", aw8697->haptic_audio.tz_cnt_max); + return len; +} + +static ssize_t aw8697_haptic_audio_tz_cnt_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[2] = {0}; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + if(2 == sscanf(buf, "%d %d", &databuf[0], &databuf[1])) { + aw8697->haptic_audio.tz_cnt_thr = databuf[0]; + aw8697->haptic_audio.tz_cnt_max = databuf[1]; + } + return count; +} + + +static ssize_t aw8697_haptic_audio_hap_cnt_max_outside_tz_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + ssize_t len = 0; + len += snprintf(buf+len, PAGE_SIZE-len, "hap_cnt_max_outside_tz=%d\n", aw8697->haptic_audio.hap_cnt_max_outside_tz); + return len; +} + +static ssize_t aw8697_haptic_audio_hap_cnt_max_outside_tz_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + unsigned int databuf[1] = {0}; + + if (aw8697->rtp_on) + return count; + if (!aw8697->ram_init) + return count; + + if(1 == sscanf(buf, "%d", &databuf[0])) { + aw8697->haptic_audio.hap_cnt_max_outside_tz = databuf[0]; + } + return count; +} + +static int aw8697_i2c_reads(struct aw8697 *aw8697, + unsigned char reg_addr, unsigned char *buf, unsigned int len) +{ + int ret = -1; + + ret = i2c_smbus_write_byte(aw8697->i2c, reg_addr); + if (ret) { + pr_err("%s: couldn't send request, ret=%d\n", + __func__, ret); + return ret; + } + ret = i2c_master_recv(aw8697->i2c, buf, len); + if (ret != len) { + pr_err("%s: couldn't read registers, return %d bytes\n", + __func__, ret); + return ret; + } + return ret; +} + +static ssize_t aw8697_haptic_ram_test_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#ifdef TIMED_OUTPUT + struct timed_output_dev *to_dev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(to_dev, struct aw8697, to_dev); +#else + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); +#endif + struct aw8697_container *aw8697_ramtest; + int i, j= 0; + unsigned int val = 0; + int rc = 0; + unsigned int start_addr; + unsigned int tmp_len,retries; + char *pbuf = NULL; + + pr_info("%s enter\n", __func__); + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + start_addr = 0; + aw8697->ram_test_flag_0 = 0; + aw8697->ram_test_flag_1 = 0; + aw8697->ram_test_result = 0; + tmp_len = 1024; /*1K*/ + retries= 8; /*tmp_len * retries =8*1024*/ + aw8697_ramtest = kzalloc(tmp_len*sizeof(char) +sizeof(int), GFP_KERNEL); + if (!aw8697_ramtest) { + pr_err("%s: error allocating memory\n", __func__); + return count ; + } + pbuf = kzalloc(tmp_len*sizeof(char), GFP_KERNEL); + if (!pbuf) { + pr_err("%s: Error allocating memory\n", __func__); + return count; + } + mutex_lock(&aw8697->lock); + disable_irq(gpio_to_irq(aw8697->irq_gpio)); + aw8697_ramtest->len = tmp_len; + if (val == 1){ + /* RAMINIT Enable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + for (j = 0;j < retries;j++){ + /*test 1 start*/ + memset(aw8697_ramtest->data, 0xff, aw8697_ramtest->len); + memset(pbuf, 0x00, aw8697_ramtest->len); + /* write ram 1 test */ + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRH, start_addr >> 8); + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRL, start_addr & 0x00FF); + + aw8697_i2c_writes(aw8697, AW8697_REG_RAMDATA, + aw8697_ramtest->data, aw8697_ramtest->len); + /* read ram 1 test */ + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRH, start_addr>>8); + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRL, start_addr&0x00FF); + aw8697_i2c_reads(aw8697, AW8697_REG_RAMDATA, pbuf, aw8697_ramtest->len); + for(i = 0;i < aw8697_ramtest->len;i++) { + if(pbuf[i] != 0xff ) + aw8697->ram_test_flag_1++; + } + /*test 1 end*/ + /*test 0 start*/ + memset(aw8697_ramtest->data, 0x00, aw8697_ramtest->len); + memset(pbuf, 0xff, aw8697_ramtest->len); + /* write ram 0 test */ + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRH, start_addr>>8); + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRL, start_addr&0x00FF); + aw8697_i2c_writes(aw8697, AW8697_REG_RAMDATA, + aw8697_ramtest->data, aw8697_ramtest->len); + /* read ram 0 test */ + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRH, start_addr>>8); + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRL, start_addr&0x00FF); + + aw8697_i2c_reads(aw8697, AW8697_REG_RAMDATA, pbuf, aw8697_ramtest->len); + + for (i = 0;i < aw8697_ramtest->len;i++) { + if (pbuf[i] != 0) + aw8697->ram_test_flag_0++; + } + /*test 0 end*/ + start_addr += tmp_len; + } + /* RAMINIT Disable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + } + kfree(aw8697_ramtest); + kfree(pbuf); + pbuf = NULL; + aw8697->ram_test_result = !aw8697->ram_test_flag_0 && !aw8697->ram_test_flag_1; + aw8697_ram_update(aw8697); + enable_irq(gpio_to_irq(aw8697->irq_gpio)); + mutex_unlock(&aw8697->lock); + pr_info("ram_test_flag_0:%d,ram_test_flag_1:%d\n", + aw8697->ram_test_flag_0, aw8697->ram_test_flag_1); + pr_info("%s exit\n", __func__); + return count; +} + +static ssize_t aw8697_haptic_ram_test_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct aw8697 *aw8697 = container_of(cdev, struct aw8697, cdev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "%d\n", aw8697->ram_test_result); + return len; +} + +static DEVICE_ATTR(state, S_IWUSR | S_IRUGO, aw8697_state_show, aw8697_state_store); +static DEVICE_ATTR(duration, S_IWUSR | S_IRUGO, aw8697_duration_show, aw8697_duration_store); +static DEVICE_ATTR(activate, S_IWUSR | S_IRUGO, aw8697_activate_show, aw8697_activate_store); +static DEVICE_ATTR(activate_mode, S_IWUSR | S_IRUGO, aw8697_activate_mode_show, aw8697_activate_mode_store); +static DEVICE_ATTR(index, S_IWUSR | S_IRUGO, aw8697_index_show, aw8697_index_store); +static DEVICE_ATTR(vmax, S_IWUSR | S_IRUGO, aw8697_vmax_show, aw8697_vmax_store); +static DEVICE_ATTR(gain, S_IWUSR | S_IRUGO, aw8697_gain_show, aw8697_gain_store); +static DEVICE_ATTR(seq, S_IWUSR | S_IRUGO, aw8697_seq_show, aw8697_seq_store); +static DEVICE_ATTR(loop, S_IWUSR | S_IRUGO, aw8697_loop_show, aw8697_loop_store); +static DEVICE_ATTR(register, S_IWUSR | S_IRUGO, aw8697_reg_show, aw8697_reg_store); +static DEVICE_ATTR(rtp, S_IWUSR | S_IRUGO, aw8697_rtp_show, aw8697_rtp_store); +static DEVICE_ATTR(ram_update, S_IWUSR | S_IRUGO, aw8697_ram_update_show, aw8697_ram_update_store); +static DEVICE_ATTR(rf_hz, S_IWUSR | S_IRUGO, aw8697_f0_show, aw8697_f0_store); +static DEVICE_ATTR(f0_cali_data, S_IWUSR | S_IRUGO, aw8697_f0_cali_data_show, aw8697_f0_cali_data_store); +static DEVICE_ATTR(cali, S_IWUSR | S_IRUGO, aw8697_cali_show, aw8697_cali_store); +static DEVICE_ATTR(short_circuit_check, S_IWUSR | S_IRUGO, aw8697_short_check_show, aw8697_short_check_store); +static DEVICE_ATTR(ignore_store, S_IWUSR | S_IRUGO, aw8697_ignore_sync_show, aw8697_ignore_sync_tore); +static DEVICE_ATTR(cont, S_IWUSR | S_IRUGO, aw8697_cont_show, aw8697_cont_store); +static DEVICE_ATTR(cont_td, S_IWUSR | S_IRUGO, aw8697_cont_td_show, aw8697_cont_td_store); +static DEVICE_ATTR(cont_drv, S_IWUSR | S_IRUGO, aw8697_cont_drv_show, aw8697_cont_drv_store); +static DEVICE_ATTR(cont_num_brk, S_IWUSR | S_IRUGO, aw8697_cont_num_brk_show, aw8697_cont_num_brk_store); +static DEVICE_ATTR(cont_zc_thr, S_IWUSR | S_IRUGO, aw8697_cont_zc_thr_show, aw8697_cont_zc_thr_store); +static DEVICE_ATTR(vbat_monitor, S_IWUSR | S_IRUGO, aw8697_vbat_monitor_show, aw8697_vbat_monitor_store); +static DEVICE_ATTR(lra_resistance, S_IWUSR | S_IRUGO, aw8697_lra_resistance_show, aw8697_lra_resistance_store); +static DEVICE_ATTR(auto_boost, S_IWUSR | S_IRUGO, aw8697_auto_boost_show, aw8697_auto_boost_store); +static DEVICE_ATTR(prctmode, S_IWUSR | S_IRUGO, aw8697_prctmode_show, aw8697_prctmode_store); +static DEVICE_ATTR(trig, S_IWUSR | S_IRUGO, aw8697_trig_show, aw8697_trig_store); +static DEVICE_ATTR(ram_vbat_comp, S_IWUSR | S_IRUGO, aw8697_ram_vbat_comp_show, aw8697_ram_vbat_comp_store); +static DEVICE_ATTR(osc_cali, S_IWUSR | S_IRUGO, aw8697_osc_cali_show, aw8697_osc_cali_store); +static DEVICE_ATTR(haptic_audio, S_IWUSR | S_IRUGO, aw8697_haptic_audio_show, aw8697_haptic_audio_store); +static DEVICE_ATTR(haptic_audio_time, S_IWUSR | S_IRUGO, aw8697_haptic_audio_time_show, aw8697_haptic_audio_time_store); +static DEVICE_ATTR(haptic_audio_tp_time, S_IWUSR | S_IRUGO, aw8697_haptic_audio_tp_time_show, aw8697_haptic_audio_tp_time_store); +static DEVICE_ATTR(haptic_audio_tp_input, S_IWUSR | S_IRUGO, aw8697_haptic_audio_tp_input_show, aw8697_haptic_audio_tp_input_store); +static DEVICE_ATTR(haptic_audio_ai_input, S_IWUSR | S_IRUGO, aw8697_haptic_audio_ai_input_show, aw8697_haptic_audio_ai_input_store); +static DEVICE_ATTR(haptic_audio_tp_size, S_IWUSR | S_IRUGO, aw8697_haptic_audio_tp_size_show, aw8697_haptic_audio_tp_size_store); +static DEVICE_ATTR(haptic_audio_tz_cnt, S_IWUSR | S_IRUGO, aw8697_haptic_audio_tz_cnt_show, aw8697_haptic_audio_tz_cnt_store); +static DEVICE_ATTR(haptic_audio_hap_cnt_max_outside_tz, S_IWUSR | S_IRUGO, aw8697_haptic_audio_hap_cnt_max_outside_tz_show, aw8697_haptic_audio_hap_cnt_max_outside_tz_store); +static DEVICE_ATTR(haptic_osc_data, S_IWUSR | S_IRUGO, aw8697_haptic_osc_data_show, aw8697_osc_data_store); +static DEVICE_ATTR(ram_test, S_IWUSR | S_IRUGO, aw8697_haptic_ram_test_show, aw8697_haptic_ram_test_store); +static DEVICE_ATTR(gun_type, S_IWUSR | S_IRUGO, aw8697_gun_type_show, aw8697_gun_type_store); +static DEVICE_ATTR(bullet_nr, S_IWUSR | S_IRUGO, aw8697_bullet_nr_show, aw8697_bullet_nr_store); +static DEVICE_ATTR(gun_mode, S_IWUSR | S_IRUGO, aw8697_gun_mode_show, aw8697_gun_mode_store); + +static struct attribute *aw8697_vibrator_attributes[] = { + &dev_attr_state.attr, + &dev_attr_duration.attr, + &dev_attr_activate.attr, + &dev_attr_activate_mode.attr, + &dev_attr_index.attr, + &dev_attr_vmax.attr, + &dev_attr_gain.attr, + &dev_attr_seq.attr, + &dev_attr_loop.attr, + &dev_attr_register.attr, + &dev_attr_rtp.attr, + &dev_attr_ram_update.attr, + &dev_attr_rf_hz.attr, + &dev_attr_f0_cali_data.attr, + &dev_attr_cali.attr, + &dev_attr_short_circuit_check.attr, + &dev_attr_ignore_store.attr, + &dev_attr_cont.attr, + &dev_attr_cont_td.attr, + &dev_attr_cont_drv.attr, + &dev_attr_cont_num_brk.attr, + &dev_attr_cont_zc_thr.attr, + &dev_attr_vbat_monitor.attr, + &dev_attr_lra_resistance.attr, + &dev_attr_auto_boost.attr, + &dev_attr_prctmode.attr, + &dev_attr_trig.attr, + &dev_attr_ram_vbat_comp.attr, + &dev_attr_osc_cali.attr, + &dev_attr_haptic_audio.attr, + &dev_attr_haptic_audio_time.attr, + &dev_attr_haptic_audio_tp_time.attr, + &dev_attr_haptic_audio_tp_input.attr, + &dev_attr_haptic_audio_ai_input.attr, + &dev_attr_haptic_audio_tp_size.attr, + &dev_attr_haptic_audio_tz_cnt.attr, + &dev_attr_haptic_audio_hap_cnt_max_outside_tz.attr, + &dev_attr_haptic_osc_data.attr, + &dev_attr_ram_test.attr, + &dev_attr_gun_type.attr, + &dev_attr_bullet_nr.attr, + &dev_attr_gun_mode.attr, + NULL +}; + +static struct attribute_group aw8697_vibrator_attribute_group = { + .attrs = aw8697_vibrator_attributes +}; + +static enum hrtimer_restart aw8697_vibrator_timer_func(struct hrtimer *timer) +{ + struct aw8697 *aw8697 = container_of(timer, struct aw8697, timer); + + pr_debug("%s enter\n", __func__); + aw8697->state = 0; + schedule_work(&aw8697->vibrator_work); + return HRTIMER_NORESTART; +} + +static void aw8697_vibrator_work_routine(struct work_struct *work) +{ + struct aw8697 *aw8697 = container_of(work, struct aw8697, vibrator_work); + unsigned val = 0; + pr_debug("%s enter\n", __func__); + + mutex_lock(&aw8697->lock); + if (aw8697->state) { + if (aw8697->pm_awake == false) { + __pm_stay_awake(aw8697->vibrator_on); + aw8697->pm_awake = true; + pr_info("aw8697->pm_awake:%d\n", aw8697->pm_awake); + } + } else { + if (aw8697->pm_awake) { + __pm_relax(aw8697->vibrator_on); + aw8697->pm_awake = false; + pr_info("aw8697->pm_awake:%d\n", aw8697->pm_awake); + } + } + aw8697_haptic_stop(aw8697); + if (aw8697->state) { + if (aw8697->activate_mode == AW8697_HAPTIC_ACTIVATE_RAM_MODE) { + if (check_factory_mode()) + aw8697_haptic_ram_vbat_comp(aw8697, false); + else + aw8697_haptic_ram_vbat_comp(aw8697, true); + aw8697_haptic_ram_vbat_comp(aw8697, true); + aw8697_haptic_play_repeat_seq(aw8697, true); + } else if(aw8697->activate_mode == AW8697_HAPTIC_ACTIVATE_CONT_MODE) { + aw8697_haptic_cont(aw8697); + } else { + } + val = aw8697->duration; + /* run ms timer */ + hrtimer_start(&aw8697->timer, + ktime_set(val / 1000, (val % 1000) * 1000000), + HRTIMER_MODE_REL); + } + mutex_unlock(&aw8697->lock); +} + +static int aw8697_vibrator_init(struct aw8697 *aw8697) +{ + int ret = 0; + + pr_info("%s enter\n", __func__); + +#ifdef TIMED_OUTPUT + aw8697->to_dev.name = "vibrator"; + aw8697->to_dev.get_time = aw8697_vibrator_get_time; + aw8697->to_dev.enable = aw8697_vibrator_enable; + + ret = timed_output_dev_register(&(aw8697->to_dev)); + if ( ret < 0){ + dev_err(aw8697->dev, "%s: fail to create timed output dev\n", + __func__); + return ret; + } + ret = sysfs_create_group(&aw8697->to_dev.dev->kobj, &aw8697_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8697->dev, "%s error creating sysfs attr files\n", __func__); + return ret; + } +#else + aw8697->cdev.name = "vibrator"; + aw8697->cdev.brightness_get = aw8697_haptic_brightness_get; + aw8697->cdev.brightness_set = aw8697_haptic_brightness_set; + + ret = devm_led_classdev_register(&aw8697->i2c->dev, &aw8697->cdev); + if (ret < 0){ + dev_err(aw8697->dev, "%s: fail to create led dev\n", + __func__); + return ret; + } + ret = sysfs_create_group(&aw8697->cdev.dev->kobj, &aw8697_vibrator_attribute_group); + if (ret < 0) { + dev_err(aw8697->dev, "%s error creating sysfs attr files\n", __func__); + return ret; + } +#endif + aw8697->vibrator_on = wakeup_source_register(aw8697->dev, "aw_stay_awake"); + hrtimer_init(&aw8697->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + aw8697->timer.function = aw8697_vibrator_timer_func; + INIT_WORK(&aw8697->vibrator_work, aw8697_vibrator_work_routine); + + INIT_WORK(&aw8697->rtp_work, aw8697_rtp_work_routine); + + mutex_init(&aw8697->lock); + mutex_init(&aw8697->rtp_lock); + + return 0; +} + + + + +/****************************************************** + * + * irq + * + ******************************************************/ +static void aw8697_interrupt_clear(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + pr_info("%s enter\n", __func__); + aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); +} + +static void aw8697_interrupt_setup(struct aw8697 *aw8697) +{ + unsigned char reg_val = 0; + + pr_info("%s enter\n", __func__); + + aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + pr_info("%s: reg SYSINT=0x%x\n", __func__, reg_val); + + /* edge int mode */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_DBGCTRL, + AW8697_BIT_DBGCTRL_INT_MODE_MASK, AW8697_BIT_DBGCTRL_INT_MODE_EDGE); + + /* int enable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_BSTERR_MASK, AW8697_BIT_SYSINTM_BSTERR_OFF); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_OV_MASK, AW8697_BIT_SYSINTM_OV_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_UVLO_MASK, AW8697_BIT_SYSINTM_UVLO_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_OCD_MASK, AW8697_BIT_SYSINTM_OCD_EN); + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSINTM, + AW8697_BIT_SYSINTM_OT_MASK, AW8697_BIT_SYSINTM_OT_EN); +} + +static irqreturn_t aw8697_irq(int irq, void *data) +{ + struct aw8697 *aw8697 = data; + unsigned char reg_val = 0; + unsigned char dbg_val = 0; + unsigned int buf_len = 0; + + pr_debug("%s enter\n", __func__); + msm_cpuidle_set_sleep_disable(true); + + aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + pr_debug("%s: reg SYSINT=0x%x\n", __func__, reg_val); + aw8697_i2c_read(aw8697, AW8697_REG_DBGSTAT, &dbg_val); + pr_debug("%s: reg DBGSTAT=0x%x\n", __func__, dbg_val); + + if(reg_val & AW8697_BIT_SYSINT_OVI) { + aw8697_op_clean_status(aw8697); + pr_err("%s chip ov int error\n", __func__); + } + if(reg_val & AW8697_BIT_SYSINT_UVLI) { + aw8697_op_clean_status(aw8697); + pr_err("%s chip uvlo int error\n", __func__); + } + if(reg_val & AW8697_BIT_SYSINT_OCDI) { + aw8697_op_clean_status(aw8697); + pr_err("%s chip over current int error\n", __func__); + } + if(reg_val & AW8697_BIT_SYSINT_OTI) { + aw8697_op_clean_status(aw8697); + pr_err("%s chip over temperature int error\n", __func__); + } + if(reg_val & AW8697_BIT_SYSINT_DONEI) { + aw8697_op_clean_status(aw8697); + pr_info("%s chip playback done\n", __func__); + } + + if(reg_val & AW8697_BIT_SYSINT_FF_AEI) { + pr_debug("%s: aw8697 rtp fifo almost empty int\n", __func__); + if(aw8697->rtp_init) { + while((!aw8697_haptic_rtp_get_fifo_afi(aw8697)) && + (aw8697->play_mode == AW8697_HAPTIC_RTP_MODE)) { + mutex_lock(&aw8697->rtp_lock); + pr_debug("%s: aw8697 rtp mode fifo update, cnt=%d\n", + __func__, aw8697->rtp_cnt); + if (!aw8697_rtp) { + pr_info("%s:aw8697_rtp is null break\n", + __func__); + mutex_unlock(&aw8697->rtp_lock); + break; + } + if((aw8697_rtp->len-aw8697->rtp_cnt) < (aw8697->ram.base_addr>>2)) { + buf_len = aw8697_rtp->len-aw8697->rtp_cnt; + } else { + buf_len = (aw8697->ram.base_addr>>2); + } + aw8697_i2c_writes(aw8697, AW8697_REG_RTP_DATA, + &aw8697_rtp->data[aw8697->rtp_cnt], buf_len); + aw8697->rtp_cnt += buf_len; + if (aw8697->rtp_cnt == aw8697_rtp->len) { + aw8697_op_clean_status(aw8697); + pr_info("%s: rtp update complete\n", __func__); + aw8697_haptic_set_rtp_aei(aw8697, false); + aw8697->rtp_cnt = 0; + aw8697->rtp_init = 0; + aw8697->rtp_is_playing = 0; + mutex_unlock(&aw8697->rtp_lock); + break; + } + mutex_unlock(&aw8697->rtp_lock); + } + } else { + pr_err("%s: aw8697 rtp init = %d, init error\n", __func__, aw8697->rtp_init); + } + } + + if(reg_val & AW8697_BIT_SYSINT_FF_AFI) { + pr_debug("%s: aw8697 rtp mode fifo full empty\n", __func__); + } + + if(aw8697->play_mode != AW8697_HAPTIC_RTP_MODE) { + aw8697_haptic_set_rtp_aei(aw8697, false); + } + + aw8697_i2c_read(aw8697, AW8697_REG_SYSINT, ®_val); + pr_debug("%s: reg SYSINT=0x%x\n", __func__, reg_val); + aw8697_i2c_read(aw8697, AW8697_REG_SYSST, ®_val); + pr_debug("%s: reg SYSST=0x%x\n", __func__, reg_val); + msm_cpuidle_set_sleep_disable(false); + + pr_debug("%s exit\n", __func__); + + return IRQ_HANDLED; +} + +/***************************************************** + * + * device tree + * + *****************************************************/ +static int aw8697_parse_dt(struct device *dev, struct aw8697 *aw8697, + struct device_node *np) { + aw8697->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (aw8697->reset_gpio < 0) { + dev_err(dev, "%s: no reset gpio provided, will not HW reset device\n", __func__); + return -1; + } else { + dev_info(dev, "%s: reset gpio provided ok\n", __func__); + } + aw8697->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (aw8697->irq_gpio < 0) { + dev_err(dev, "%s: no irq gpio provided.\n", __func__); + } else { + dev_info(dev, "%s: irq gpio provided ok.\n", __func__); + } + aw8697->count_go = of_property_read_bool(np, + "op,count_go"); + pr_info("aw8697->count_go:%d\n", aw8697->count_go); + return 0; +} + +static int aw8697_hw_reset(struct aw8697 *aw8697) +{ + pr_info("%s enter\n", __func__); + + if (aw8697 && gpio_is_valid(aw8697->reset_gpio)) { + gpio_set_value_cansleep(aw8697->reset_gpio, 0); + usleep_range(1000, 2000); + gpio_set_value_cansleep(aw8697->reset_gpio, 1); + usleep_range(3500, 4000); + } else { + if (aw8697) + dev_err(aw8697->dev, "%s: failed\n", __func__); + } + return 0; +} + + +/***************************************************** + * + * check chip id + * + *****************************************************/ +static int aw8697_read_chipid(struct aw8697 *aw8697) +{ + int ret = -1; + unsigned char cnt = 0; + unsigned char reg = 0; + + while(cnt < AW_READ_CHIPID_RETRIES) { + /* hardware reset */ + aw8697_hw_reset(aw8697); + + ret = aw8697_i2c_read(aw8697, AW8697_REG_ID, ®); + if (ret < 0) { + dev_err(aw8697->dev, "%s: failed to read register AW8697_REG_ID: %d\n", __func__, ret); + return -EINVAL; + } + switch (reg) { + case AW8697_CHIPID: + pr_info("%s aw8697 detected\n", __func__); + aw8697->chipid = AW8697_CHIPID; + aw8697_haptic_softreset(aw8697); + return 0; + default: + pr_info("%s unsupported device revision (0x%x)\n", __func__, reg ); + break; + } + cnt ++; + + usleep_range(AW_READ_CHIPID_RETRY_DELAY * 1000, + AW_READ_CHIPID_RETRY_DELAY * 1000 + 500); + } + + return -EINVAL; +} + +/****************************************************** + * + * sys group attribute: reg + * + ******************************************************/ +static ssize_t aw8697_i2c_reg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8697 *aw8697 = dev_get_drvdata(dev); + + unsigned int databuf[2] = {0, 0}; + + if(2 == sscanf(buf, "%x %x", &databuf[0], &databuf[1])) { + aw8697_i2c_write(aw8697, (unsigned char)databuf[0], (unsigned char)databuf[1]); + } + + return count; +} + +static ssize_t aw8697_i2c_reg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8697 *aw8697 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned char i = 0; + unsigned char reg_val = 0; + for(i = 0; i < AW8697_REG_MAX; i ++) { + if(!(aw8697_reg_access[i]®_RD_ACCESS)) + continue; + aw8697_i2c_read(aw8697, i, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, "reg:0x%02x=0x%02x \n", i, reg_val); + } + return len; +} +static ssize_t aw8697_i2c_ram_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw8697 *aw8697 = dev_get_drvdata(dev); + + unsigned int databuf[1] = {0}; + + if(1 == sscanf(buf, "%x", &databuf[0])) { + if(1 == databuf[0]) { + aw8697_ram_update(aw8697); + } + } + + return count; +} + +static ssize_t aw8697_i2c_ram_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct aw8697 *aw8697 = dev_get_drvdata(dev); + ssize_t len = 0; + unsigned int i = 0; + unsigned char reg_val = 0; + + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + mutex_unlock(&aw8697->lock); + /* RAMINIT Enable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_EN); + + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRH, (unsigned char)(aw8697->ram.base_addr>>8)); + aw8697_i2c_write(aw8697, AW8697_REG_RAMADDRL, (unsigned char)(aw8697->ram.base_addr&0x00ff)); + len += snprintf(buf+len, PAGE_SIZE-len, "aw8697_haptic_ram:\n"); + for(i=0; iram.len; i++) { + aw8697_i2c_read(aw8697, AW8697_REG_RAMDATA, ®_val); + len += snprintf(buf+len, PAGE_SIZE-len, "0x%02x,", reg_val); + } + len += snprintf(buf+len, PAGE_SIZE-len, "\n"); + /* RAMINIT Disable */ + aw8697_i2c_write_bits(aw8697, AW8697_REG_SYSCTRL, + AW8697_BIT_SYSCTRL_RAMINIT_MASK, AW8697_BIT_SYSCTRL_RAMINIT_OFF); + + return len; +} + +static DEVICE_ATTR(reg, S_IWUSR | S_IRUGO, aw8697_i2c_reg_show, aw8697_i2c_reg_store); +static DEVICE_ATTR(ram, S_IWUSR | S_IRUGO, aw8697_i2c_ram_show, aw8697_i2c_ram_store); + +static struct attribute *aw8697_attributes[] = { + &dev_attr_reg.attr, + &dev_attr_ram.attr, + NULL +}; + +static struct attribute_group aw8697_attribute_group = { + .attrs = aw8697_attributes +}; + +static int aw8697_pinctrl(struct aw8697 *aw8697) +{ + + aw8697->pinctrl = devm_pinctrl_get(aw8697->dev); + if (IS_ERR_OR_NULL(aw8697->pinctrl)) { + dev_err(aw8697->dev, + "Unable to acquire pinctrl\n"); + aw8697->pinctrl = NULL; + return -EINVAL; + } + + aw8697->pinctrl_state_active = pinctrl_lookup_state(aw8697->pinctrl, "default"); + if (IS_ERR_OR_NULL(aw8697->pinctrl_state_active)) { + dev_err(aw8697->dev, + "Can not lookup default\n"); + devm_pinctrl_put(aw8697->pinctrl); + aw8697->pinctrl = NULL; + return PTR_ERR(aw8697->pinctrl_state_active); + } + + if (pinctrl_select_state(aw8697->pinctrl, + aw8697->pinctrl_state_active) < 0) + dev_err(aw8697->dev, "pinctrl set default fail\n"); + + return 0; + +} + + +/****************************************************** + * + * i2c driver + * + ******************************************************/ +static int aw8697_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct aw8697 *aw8697; + struct device_node *np = i2c->dev.of_node; + int irq_flags = 0; + int ret = -1; + + pr_info("%s enter\n", __func__); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + aw8697 = devm_kzalloc(&i2c->dev, sizeof(struct aw8697), GFP_KERNEL); + if (aw8697 == NULL) + return -ENOMEM; + + aw8697->dev = &i2c->dev; + aw8697->i2c = i2c; + + i2c_set_clientdata(i2c, aw8697); + + /* aw8697 rst & int */ + if (np) { + ret = aw8697_parse_dt(&i2c->dev, aw8697, np); + if (ret) { + dev_err(&i2c->dev, "%s: failed to parse device tree node\n", __func__); + goto err_parse_dt; + } + } else { + aw8697->reset_gpio = -1; + aw8697->irq_gpio = -1; + } + + if (gpio_is_valid(aw8697->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8697->reset_gpio, + GPIOF_OUT_INIT_LOW, "aw8697_rst"); + if (ret){ + dev_err(&i2c->dev, "%s: rst request failed\n", __func__); + goto err_reset_gpio_request; + } + } + + if (gpio_is_valid(aw8697->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, aw8697->irq_gpio, + GPIOF_DIR_IN, "aw8697_int"); + if (ret){ + dev_err(&i2c->dev, "%s: int request failed\n", __func__); + goto err_irq_gpio_request; + } + } + + /* aw8697 chip id */ + ret = aw8697_read_chipid(aw8697); + if (ret < 0) { + dev_err(&i2c->dev, "%s: aw8697_read_chipid failed ret=%d\n", __func__, ret); + goto err_id; + } + aw8697_pinctrl(aw8697); + /* aw8697 irq */ + if (gpio_is_valid(aw8697->irq_gpio) && + !(aw8697->flags & AW8697_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + aw8697_interrupt_setup(aw8697); + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(aw8697->irq_gpio), + NULL, aw8697_irq, irq_flags, + "aw8697", aw8697); + if (ret != 0) { + dev_err(&i2c->dev, "%s: failed to request IRQ %d: %d\n", + __func__, gpio_to_irq(aw8697->irq_gpio), ret); + goto err_irq; + } + } else { + dev_info(&i2c->dev, "%s skipping IRQ registration\n", __func__); + /* disable feature support if gpio was invalid */ + aw8697->flags |= AW8697_FLAG_SKIP_INTERRUPTS; + } + + dev_set_drvdata(&i2c->dev, aw8697); + + ret = sysfs_create_group(&i2c->dev.kobj, &aw8697_attribute_group); + if (ret < 0) { + dev_info(&i2c->dev, "%s error creating sysfs attr files\n", __func__); + goto err_sysfs; + } + + g_aw8697 = aw8697; + + aw8697_vibrator_init(aw8697); + + aw8697_haptic_init(aw8697); + + aw8697_ram_init(aw8697); + +/* add haptic audio tp mask */ + aw8697->fb_notif.notifier_call = aw8697_fb_notifier_callback_tp; + ret = msm_drm_register_client(&aw8697->fb_notif); + if (ret) + pr_info("Unable to register fb_notifier: %d\n", ret); +/* add haptic audio tp mask end */ + pr_info("%s probe completed successfully!\n", __func__); + + return 0; + +err_sysfs: + devm_free_irq(&i2c->dev, gpio_to_irq(aw8697->irq_gpio), aw8697); +err_irq: +err_id: + if (gpio_is_valid(aw8697->irq_gpio)) + devm_gpio_free(&i2c->dev, aw8697->irq_gpio); +err_irq_gpio_request: + if (gpio_is_valid(aw8697->reset_gpio)) + devm_gpio_free(&i2c->dev, aw8697->reset_gpio); +err_reset_gpio_request: +err_parse_dt: + devm_kfree(&i2c->dev, aw8697); + aw8697 = NULL; + return ret; +} + +static int aw8697_i2c_remove(struct i2c_client *i2c) +{ + struct aw8697 *aw8697 = i2c_get_clientdata(i2c); + + pr_info("%s enter\n", __func__); + + sysfs_remove_group(&i2c->dev.kobj, &aw8697_attribute_group); + + devm_free_irq(&i2c->dev, gpio_to_irq(aw8697->irq_gpio), aw8697); + if (gpio_is_valid(aw8697->irq_gpio)) + devm_gpio_free(&i2c->dev, aw8697->irq_gpio); + if (gpio_is_valid(aw8697->reset_gpio)) + devm_gpio_free(&i2c->dev, aw8697->reset_gpio); + devm_kfree(&i2c->dev, aw8697); + aw8697 = NULL; + + return 0; +} + +static int __maybe_unused aw8697_suspend(struct device *dev) +{ + int ret = 0; + + struct aw8697 *aw8697 = dev_get_drvdata(dev); + mutex_lock(&aw8697->lock); + aw8697_haptic_stop(aw8697); + mutex_unlock(&aw8697->lock); + + return ret; +} + +static int __maybe_unused aw8697_resume(struct device *dev) +{ + + int ret = 0; + + return ret; +} + + +static SIMPLE_DEV_PM_OPS(aw8697_pm_ops, aw8697_suspend, aw8697_resume); +static const struct i2c_device_id aw8697_i2c_id[] = { + { AW8697_I2C_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw8697_i2c_id); + +static struct of_device_id aw8697_dt_match[] = { + { .compatible = "awinic,aw8697_haptic" }, + { }, +}; + +static struct i2c_driver aw8697_i2c_driver = { + .driver = { + .name = AW8697_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw8697_dt_match), + .pm = &aw8697_pm_ops, + }, + .probe = aw8697_i2c_probe, + .remove = aw8697_i2c_remove, + .id_table = aw8697_i2c_id, +}; + + +static int __init aw8697_i2c_init(void) +{ + int ret = 0; + + pr_info("aw8697 driver version %s\n", AW8697_VERSION); + + ret = i2c_add_driver(&aw8697_i2c_driver); + if(ret){ + pr_err("fail to add aw8697 device into i2c\n"); + return ret; + } + + return 0; +} +module_init(aw8697_i2c_init); + + +static void __exit aw8697_i2c_exit(void) +{ + i2c_del_driver(&aw8697_i2c_driver); +} +module_exit(aw8697_i2c_exit); + + +MODULE_DESCRIPTION("AW8697 Haptic Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/vibrator/aw8697.h b/drivers/oneplus/vibrator/aw8697.h new file mode 100644 index 0000000000000000000000000000000000000000..f8004114c7e360dce397a01cfd7e851635d9880d --- /dev/null +++ b/drivers/oneplus/vibrator/aw8697.h @@ -0,0 +1,556 @@ +#ifndef _AW8697_H_ +#define _AW8697_H_ + +/********************************************************* + * + * kernel version + * + ********************************************************/ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 4, 1) +#define TIMED_OUTPUT +#endif + +/********************************************************* + * + * aw8697.h + * + ********************************************************/ +#include +#include +#include +#include +#include +#include +#ifdef TIMED_OUTPUT +#include <../../../drivers/staging/android/timed_output.h> +#else +#include +#endif + +/********************************************************* + * + * marco + * + ********************************************************/ +#define MAX_I2C_BUFFER_SIZE 65536 + +#define AW8697_REG_MAX 0xff + +#define AW8697_SEQUENCER_SIZE 8 +#define AW8697_SEQUENCER_LOOP_SIZE 4 + +#define AW8697_RTP_I2C_SINGLE_MAX_NUM 512 + +#define HAPTIC_MAX_TIMEOUT 10000 + +#define AW8697_VBAT_REFER 4200 +#define AW8697_VBAT_MIN 3000 +#define AW8697_VBAT_MAX 4500 +/* motor config */ +#define LRA_0619 + +#ifdef LRA_0619 +#ifdef CONFIG_ARCH_LITO +#define AW8697_HAPTIC_F0_PRE 2350 /* 235Hz*/ +#define AW8697_HAPTIC_CONT_DRV_LVL 100 /* value*6.1/256*/ +#define AW8697_HAPTIC_CONT_DRV_LVL_OV 100 /* value*6.1/256*/ +#else +#define AW8697_HAPTIC_F0_PRE 1700 /* 170Hz*/ +#define AW8697_HAPTIC_CONT_DRV_LVL 54 /* value*6.1/256*/ +#define AW8697_HAPTIC_CONT_DRV_LVL_OV 54 /* value*6.1/256*/ +#endif +#define AW8697_HAPTIC_F0_CALI_PERCEN 7 /* -7%~7%*/ +#define AW8697_HAPTIC_CONT_TD 0x009a +#define AW8697_HAPTIC_CONT_ZC_THR 0x0ff1 +#define AW8697_HAPTIC_CONT_NUM_BRK 3 +#endif + +#ifdef LRA_0832 +#define AW8697_HAPTIC_F0_PRE 2350 /* 170Hz*/ +#define AW8697_HAPTIC_F0_CALI_PERCEN 7 /* -7%~7%*/ +#define AW8697_HAPTIC_CONT_DRV_LVL 125 /* 125*6.1/256=2.98v*/ +#define AW8697_HAPTIC_CONT_DRV_LVL_OV 155 /*155*6.1/256=3.69v*/ +#define AW8697_HAPTIC_CONT_TD 0x006c +#define AW8697_HAPTIC_CONT_ZC_THR 0x0ff1 +#define AW8697_HAPTIC_CONT_NUM_BRK 3 +#endif + + +#define AW8697_HAPTIC_F0_COEFF 260 /*2.604167*/ + + +/* trig config */ +#define AW8697_TRIG_NUM 3 +#define AW8697_TRG1_ENABLE 1 +#define AW8697_TRG2_ENABLE 1 +#define AW8697_TRG3_ENABLE 1 +/* + * trig default high level + * ___________ _________________ + * | | + * | | + * |___________| + * first edge + * second edge + * + * + * trig default low level + * ___________ + * | | + * | | + * __________| |_________________ + * first edge + * second edge + */ +#define AW8697_TRG1_DEFAULT_LEVEL 1 // 1: high level; 0: low level +#define AW8697_TRG2_DEFAULT_LEVEL 1 // 1: high level; 0: low level +#define AW8697_TRG3_DEFAULT_LEVEL 1 // 1: high level; 0: low level + +#define AW8697_TRG1_DUAL_EDGE 1 // 1: dual edge; 0: first edge +#define AW8697_TRG2_DUAL_EDGE 1 // 1: dual edge; 0: first edge +#define AW8697_TRG3_DUAL_EDGE 1 // 1: dual edge; 0: first edge + +#define AW8697_TRG1_FIRST_EDGE_SEQ 1 // trig1: first edge waveform seq +#define AW8697_TRG1_SECOND_EDGE_SEQ 2 // trig1: second edge waveform seq +#define AW8697_TRG2_FIRST_EDGE_SEQ 1 // trig2: first edge waveform seq +#define AW8697_TRG2_SECOND_EDGE_SEQ 2 // trig2: second edge waveform seq +#define AW8697_TRG3_FIRST_EDGE_SEQ 1 // trig3: first edge waveform seq +#define AW8697_TRG3_SECOND_EDGE_SEQ 2 // trig3: second edge waveform seq + + +#if AW8697_TRG1_ENABLE +#define AW8697_TRG1_DEFAULT_ENABLE AW8697_BIT_TRGCFG2_TRG1_ENABLE +#else +#define AW8697_TRG1_DEFAULT_ENABLE AW8697_BIT_TRGCFG2_TRG1_DISABLE +#endif + +#if AW8697_TRG2_ENABLE +#define AW8697_TRG2_DEFAULT_ENABLE AW8697_BIT_TRGCFG2_TRG2_ENABLE +#else +#define AW8697_TRG2_DEFAULT_ENABLE AW8697_BIT_TRGCFG2_TRG2_DISABLE +#endif + +#if AW8697_TRG3_ENABLE +#define AW8697_TRG3_DEFAULT_ENABLE AW8697_BIT_TRGCFG2_TRG3_ENABLE +#else +#define AW8697_TRG3_DEFAULT_ENABLE AW8697_BIT_TRGCFG2_TRG3_DISABLE +#endif + +#if AW8697_TRG1_DEFAULT_LEVEL +#define AW8697_TRG1_DEFAULT_POLAR AW8697_BIT_TRGCFG1_TRG1_POLAR_POS +#else +#define AW8697_TRG1_DEFAULT_POLAR AW8697_BIT_TRGCFG1_TRG1_POLAR_NEG +#endif + +#if AW8697_TRG2_DEFAULT_LEVEL +#define AW8697_TRG2_DEFAULT_POLAR AW8697_BIT_TRGCFG1_TRG2_POLAR_POS +#else +#define AW8697_TRG2_DEFAULT_POLAR AW8697_BIT_TRGCFG1_TRG2_POLAR_NEG +#endif + +#if AW8697_TRG3_DEFAULT_LEVEL +#define AW8697_TRG3_DEFAULT_POLAR AW8697_BIT_TRGCFG1_TRG3_POLAR_POS +#else +#define AW8697_TRG3_DEFAULT_POLAR AW8697_BIT_TRGCFG1_TRG3_POLAR_NEG +#endif + +#if AW8697_TRG1_DUAL_EDGE +#define AW8697_TRG1_DEFAULT_EDGE AW8697_BIT_TRGCFG1_TRG1_EDGE_POS_NEG +#else +#define AW8697_TRG1_DEFAULT_EDGE AW8697_BIT_TRGCFG1_TRG1_EDGE_POS +#endif + +#if AW8697_TRG2_DUAL_EDGE +#define AW8697_TRG2_DEFAULT_EDGE AW8697_BIT_TRGCFG1_TRG2_EDGE_POS_NEG +#else +#define AW8697_TRG2_DEFAULT_EDGE AW8697_BIT_TRGCFG1_TRG2_EDGE_POS +#endif + +#if AW8697_TRG3_DUAL_EDGE +#define AW8697_TRG3_DEFAULT_EDGE AW8697_BIT_TRGCFG1_TRG3_EDGE_POS_NEG +#else +#define AW8697_TRG3_DEFAULT_EDGE AW8697_BIT_TRGCFG1_TRG3_EDGE_POS +#endif +enum aw8697_flags { + AW8697_FLAG_NONR = 0, + AW8697_FLAG_SKIP_INTERRUPTS = 1, +}; + +enum aw8697_haptic_read_write { + AW8697_HAPTIC_CMD_READ_REG = 0, + AW8697_HAPTIC_CMD_WRITE_REG = 1, +}; + + +enum aw8697_haptic_work_mode { + AW8697_HAPTIC_STANDBY_MODE = 0, + AW8697_HAPTIC_RAM_MODE = 1, + AW8697_HAPTIC_RTP_MODE = 2, + AW8697_HAPTIC_TRIG_MODE = 3, + AW8697_HAPTIC_CONT_MODE = 4, + AW8697_HAPTIC_RAM_LOOP_MODE = 5, +}; + +enum aw8697_haptic_bst_mode { + AW8697_HAPTIC_BYPASS_MODE = 0, + AW8697_HAPTIC_BOOST_MODE = 1, +}; + +enum aw8697_haptic_activate_mode { + AW8697_HAPTIC_ACTIVATE_RAM_MODE = 0, + AW8697_HAPTIC_ACTIVATE_CONT_MODE = 1, +}; + + +enum aw8697_haptic_cont_vbat_comp_mode { + AW8697_HAPTIC_CONT_VBAT_SW_COMP_MODE = 0, + AW8697_HAPTIC_CONT_VBAT_HW_COMP_MODE = 1, +}; + +enum aw8697_haptic_ram_vbat_comp_mode { + AW8697_HAPTIC_RAM_VBAT_COMP_DISABLE = 0, + AW8697_HAPTIC_RAM_VBAT_COMP_ENABLE = 1, +}; + +enum aw8697_haptic_f0_flag { + AW8697_HAPTIC_LRA_F0 = 0, + AW8697_HAPTIC_CALI_F0 = 1, +}; + +enum aw8697_haptic_pwm_mode { + AW8697_PWM_48K = 0, + AW8697_PWM_24K = 1, + AW8697_PWM_12K = 2, +}; + + +enum aw8697_haptic_play { + AW8697_HAPTIC_PLAY_NULL = 0, + AW8697_HAPTIC_PLAY_ENABLE = 1, + AW8697_HAPTIC_PLAY_STOP = 2, + AW8697_HAPTIC_PLAY_GAIN = 8, +}; + +enum aw8697_haptic_cmd { + AW8697_HAPTIC_CMD_NULL = 0, + AW8697_HAPTIC_CMD_ENABLE = 1, + AW8697_HAPTIC_CMD_HAPTIC = 0x0f, + AW8697_HAPTIC_CMD_TP = 0x10, + AW8697_HAPTIC_CMD_SYS = 0xf0, + AW8697_HAPTIC_CMD_STOP = 255, +}; + +enum aw8697_haptic_tp_flag { + AW8697_HAPTIC_TP_NULL = 0, + AW8697_HAPTIC_TP_PRESS = 1, + AW8697_HAPTIC_TP_PRESS_HOLD = 2, + AW8697_HAPTIC_TP_RELEASE = 3, + AW8697_HAPTIC_TP_RELEASE_HOLD = 4, +}; + +enum aw8697_haptic_tp_staus { + AW8697_HAPTIC_TP_ST_RELEASE = 0, + AW8697_HAPTIC_TP_ST_PRESS = 1, +}; + +enum aw8697_haptic_tp_play_flag { + AW8697_HAPTIC_TP_PLAY_NULL = 0, + AW8697_HAPTIC_TP_PLAY_ENABLE = 1, + AW8697_HAPTIC_TP_PLAY_NOMORE= 2, +}; + + +enum aw8697_haptic_tp_touch_flag { + AW8697_HAPTIC_TP_TOUCH_INVAIL = 0, + AW8697_HAPTIC_TP_TOUCH_VAIL = 1, +}; + +#define AW8697_HAPTIC_TP_ID_MAX 10 + + +#define AW8697_HAPTIC_AI_X_JITTER 20 +#define AW8697_HAPTIC_AI_Y_JITTER 20 +#define AW8697_HAPTIC_AI_X_DFT_W 200 +#define AW8697_HAPTIC_AI_Y_DFT_H 200 + + +enum aw8697_haptic_tz_level { + AW8697_HAPTIC_TZ_LEVEL_LOW = 0, + AW8697_HAPTIC_TZ_LEVEL_HIGH = 1, +}; + +/********************************************************* + * + * struct + * + ********************************************************/ +struct tp_input_info { + uint8_t id; + uint8_t status; + uint16_t x; + uint16_t y; +}; + +struct trust_zone_info { + uint8_t level; + uint16_t x; + uint16_t y; + uint16_t w; + uint16_t h; +}; + +struct ai_trust_zone { + uint8_t num; + struct trust_zone_info *tz_info; +}; + + +struct haptic_audio_trust_zone { + uint8_t level;//tz score + uint8_t cnt; + uint8_t dirty; + uint16_t x; + uint16_t y; + uint16_t w; + uint16_t h; + struct list_head list; +}; + +struct haptic_audio_tp_size { + uint16_t x; + uint16_t y; +}; + +struct shake_point { + uint8_t id; + uint16_t x; + uint16_t y; + uint8_t status; + uint8_t touch_flag; + uint8_t touch_outside_tz_flag; +}; + + +struct fileops { + unsigned char cmd; + unsigned char reg; + unsigned char ram_addrh; + unsigned char ram_addrl; +}; + +struct ram { + unsigned int len; + unsigned int check_sum; + unsigned int base_addr; + unsigned char version; + unsigned char ram_shift; + unsigned char baseaddr_shift; +}; + +struct haptic_ctr{ + unsigned char cnt; + unsigned char cmd; + unsigned char play; + unsigned char wavseq; + unsigned char loop; + unsigned char gain; + struct list_head list; +}; + +struct tp_id{ + struct shake_point pt_info; + unsigned char tp_flag; + unsigned char press_flag; + unsigned char release_flag; + struct timeval t_press; + struct timeval t_release; + unsigned char play_flag; + unsigned int no_play_cnt; + unsigned char tp_ai_match_flag; + unsigned char press_no_vibrate_flag; + unsigned char release_no_vibrate_flag; +}; + +struct tp{ + struct tp_id id[AW8697_HAPTIC_TP_ID_MAX+1]; + unsigned char id_index; + unsigned char virtual_id; + unsigned int press_delay_min; + unsigned int press_delay_max; + unsigned int release_delay_max; + unsigned char play_flag; + unsigned char last_play_flag; + unsigned char press_flag; + unsigned char tp_ai_match_flag; + unsigned char tp_ai_check_flag; + unsigned char hap_match_without_tz_cnt; + unsigned int no_play_cnt_max; +}; + +struct haptic_audio{ + struct mutex lock; + struct hrtimer timer; + struct work_struct work; + int delay_val; + int timer_val; + struct haptic_ctr ctr; + struct list_head ctr_list; + struct tp tp; + struct list_head list; + struct list_head score_list; + struct haptic_audio_tp_size tp_size; + struct trust_zone_info output_tz_info[10]; + int tz_num; + int tz_high_num; + int tz_cnt_thr; + int tz_cnt_max; + int tz_init; + unsigned int uevent_report_flag; + unsigned int hap_cnt_outside_tz; + unsigned int hap_cnt_max_outside_tz; +}; + +struct trig{ + unsigned char enable; + unsigned char default_level; + unsigned char dual_edge; + unsigned char frist_seq; + unsigned char second_seq; +}; + +struct aw8697 { + struct regmap *regmap; + struct i2c_client *i2c; + struct device *dev; + struct input_dev *input; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct mutex lock; + struct hrtimer timer; + struct work_struct vibrator_work; + struct work_struct rtp_work; + struct delayed_work ram_work; + struct timeval current_time; + struct timeval pre_enter_time; + struct wakeup_source *vibrator_on; +#ifdef TIMED_OUTPUT + struct timed_output_dev to_dev; +#else + struct led_classdev cdev; +#endif + struct fileops fileops; + struct ram ram; + bool pm_awake; + bool haptic_ready; + bool audio_ready; + bool ignore_sync; + int pre_haptic_number; + bool rtp_on; + int rtp_is_playing; + struct timeval start,end; + unsigned int timeval_flags; + unsigned int osc_cali_flag; + unsigned long int microsecond; + unsigned int sys_frequency; + unsigned int rtp_len; + unsigned int lra_calib_data; + unsigned int f0_calib_data; + + int reset_gpio; + int irq_gpio; + + unsigned char hwen_flag; + unsigned char flags; + unsigned char chipid; + + unsigned char play_mode; + + unsigned char activate_mode; + unsigned char auto_boost; + + int state; + int duration; + int amplitude; + int index; + int vmax; + int gain; + + unsigned char seq[AW8697_SEQUENCER_SIZE]; + unsigned char loop[AW8697_SEQUENCER_SIZE]; + + unsigned int rtp_cnt; + unsigned int rtp_file_num; + + unsigned char rtp_init; + unsigned char ram_init; + unsigned char rtp_routine_on; + + unsigned int f0; + unsigned int f0_pre; + unsigned int cont_f0; + unsigned int cont_td; + unsigned int cont_zc_thr; + unsigned char cont_drv_lvl; + unsigned char cont_drv_lvl_ov; + unsigned char cont_num_brk; + unsigned char max_pos_beme; + unsigned char max_neg_beme; + unsigned char f0_cali_flag; + + unsigned char ram_vbat_comp; + unsigned int vbat; + unsigned int lra; + unsigned int ram_bin_index; + unsigned int haptic_real_f0; + unsigned int ram_test_flag_0; + unsigned int ram_test_flag_1; + unsigned int ram_test_result; + bool count_go; + + struct trig trig[AW8697_TRIG_NUM]; + struct haptic_audio haptic_audio; + struct mutex rtp_lock; + struct timeval t_stop; + struct timeval t_start; + unsigned int game_microsecond; + unsigned int interval_us; + struct notifier_block fb_notif;/*register to control tp report*/ + unsigned int sin_num; + size_t sin_data_lenght; + unsigned int sin_add_flag; + unsigned int gun_type; + unsigned int bullet_nr; + unsigned int gun_mode; +}; + +struct aw8697_container{ + int len; + unsigned char data[]; +}; + + +/********************************************************* + * + * ioctl + * + ********************************************************/ +struct aw8697_seq_loop { + unsigned char loop[AW8697_SEQUENCER_SIZE]; +}; + +struct aw8697_que_seq { + unsigned char index[AW8697_SEQUENCER_SIZE]; +}; + + +#define AW8697_HAPTIC_IOCTL_MAGIC 'h' + +#define AW8697_HAPTIC_SET_QUE_SEQ _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 1, struct aw8697_que_seq*) +#define AW8697_HAPTIC_SET_SEQ_LOOP _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 2, struct aw8697_seq_loop*) +#define AW8697_HAPTIC_PLAY_QUE_SEQ _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 3, unsigned int) +#define AW8697_HAPTIC_SET_BST_VOL _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 4, unsigned int) +#define AW8697_HAPTIC_SET_BST_PEAK_CUR _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 5, unsigned int) +#define AW8697_HAPTIC_SET_GAIN _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 6, unsigned int) +#define AW8697_HAPTIC_PLAY_REPEAT_SEQ _IOWR(AW8697_HAPTIC_IOCTL_MAGIC, 7, unsigned int) +#endif + diff --git a/drivers/oneplus/vibrator/aw8697_config.h b/drivers/oneplus/vibrator/aw8697_config.h new file mode 100644 index 0000000000000000000000000000000000000000..f16adc7434926d0c776c802853a1d9075c986197 --- /dev/null +++ b/drivers/oneplus/vibrator/aw8697_config.h @@ -0,0 +1,12 @@ +#ifndef __AW8697_CONFIG_H__ +#define __AW8697_CONFIG_H__ + +#define AW8697_CHIPID 0x97 + +#define AW8697_BSTCFG_PEAKCUR_LIMIT 0x07 +#define AW8697_DEFAULT_PEAKCUR AW8697_BSTCFG_PEAKCUR_LIMIT /* origin value: AW8697_BIT_BSTCFG_PEAKCUR_3P5A*/ + +#define AW8697_CONT_PLAYBACK_MODE AW8697_BIT_CONT_CTRL_CLOSE_PLAYBACK + + +#endif diff --git a/drivers/oneplus/vibrator/aw8697_reg.h b/drivers/oneplus/vibrator/aw8697_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..3f6f9db5787c056b5cea4c034f0d2920a135b321 --- /dev/null +++ b/drivers/oneplus/vibrator/aw8697_reg.h @@ -0,0 +1,545 @@ +#ifndef _AW8697_REG_H_ +#define _AW8697_REG_H_ + +/******************************************** + * Register List + *******************************************/ +#define AW8697_REG_ID 0x00 +#define AW8697_REG_SYSST 0x01 +#define AW8697_REG_SYSINT 0x02 +#define AW8697_REG_SYSINTM 0x03 +#define AW8697_REG_SYSCTRL 0x04 +#define AW8697_REG_GO 0x05 +#define AW8697_REG_RTP_DATA 0x06 +#define AW8697_REG_WAVSEQ1 0x07 +#define AW8697_REG_WAVSEQ2 0x08 +#define AW8697_REG_WAVSEQ3 0x09 +#define AW8697_REG_WAVSEQ4 0x0a +#define AW8697_REG_WAVSEQ5 0x0b +#define AW8697_REG_WAVSEQ6 0x0c +#define AW8697_REG_WAVSEQ7 0x0d +#define AW8697_REG_WAVSEQ8 0x0e +#define AW8697_REG_WAVLOOP1 0x0f +#define AW8697_REG_WAVLOOP2 0x10 +#define AW8697_REG_WAVLOOP3 0x11 +#define AW8697_REG_WAVLOOP4 0x12 +#define AW8697_REG_MAIN_LOOP 0x13 +#define AW8697_REG_TRG1_WAV_P 0x14 +#define AW8697_REG_TRG2_WAV_P 0x15 +#define AW8697_REG_TRG3_WAV_P 0x16 +#define AW8697_REG_TRG1_WAV_N 0x17 +#define AW8697_REG_TRG2_WAV_N 0x18 +#define AW8697_REG_TRG3_WAV_N 0x19 +#define AW8697_REG_TRG_PRIO 0x1a +#define AW8697_REG_TRG_CFG1 0x1b +#define AW8697_REG_TRG_CFG2 0x1c +#define AW8697_REG_DBGCTRL 0x20 +#define AW8697_REG_BASE_ADDRH 0x21 +#define AW8697_REG_BASE_ADDRL 0x22 +#define AW8697_REG_FIFO_AEH 0x23 +#define AW8697_REG_FIFO_AEL 0x24 +#define AW8697_REG_FIFO_AFH 0x25 +#define AW8697_REG_FIFO_AFL 0x26 +#define AW8697_REG_WAKE_DLY 0x27 +#define AW8697_REG_START_DLY 0x28 +#define AW8697_REG_END_DLY_H 0x29 +#define AW8697_REG_END_DLY_L 0x2a +#define AW8697_REG_DATCTRL 0x2b +#define AW8697_REG_PWMDEL 0x2c +#define AW8697_REG_PWMPRC 0x2d +#define AW8697_REG_PWMDBG 0x2e +#define AW8697_REG_LDOCTRL 0x2f +#define AW8697_REG_DBGSTAT 0x30 +#define AW8697_REG_BSTDBG1 0x31 +#define AW8697_REG_BSTDBG2 0x32 +#define AW8697_REG_BSTDBG3 0x33 +#define AW8697_REG_BSTCFG 0x34 +#define AW8697_REG_ANADBG 0x35 +#define AW8697_REG_ANACTRL 0x36 +#define AW8697_REG_CPDBG 0x37 +#define AW8697_REG_GLBDBG 0x38 +#define AW8697_REG_DATDBG 0x39 +#define AW8697_REG_BSTDBG4 0x3a +#define AW8697_REG_BSTDBG5 0x3b +#define AW8697_REG_BSTDBG6 0x3c +#define AW8697_REG_HDRVDBG 0x3d +#define AW8697_REG_PRLVL 0x3e +#define AW8697_REG_PRTIME 0x3f +#define AW8697_REG_RAMADDRH 0x40 +#define AW8697_REG_RAMADDRL 0x41 +#define AW8697_REG_RAMDATA 0x42 +#define AW8697_REG_GLB_STATE 0x46 +#define AW8697_REG_BST_AUTO 0x47 +#define AW8697_REG_CONT_CTRL 0x48 +#define AW8697_REG_F_PRE_H 0x49 +#define AW8697_REG_F_PRE_L 0x4a +#define AW8697_REG_TD_H 0x4b +#define AW8697_REG_TD_L 0x4c +#define AW8697_REG_TSET 0x4d +#define AW8697_REG_TRIM_LRA 0x5b +#define AW8697_REG_R_SPARE 0x5d +#define AW8697_REG_D2SCFG 0x5e +#define AW8697_REG_DETCTRL 0x5f +#define AW8697_REG_RLDET 0x60 +#define AW8697_REG_OSDET 0x61 +#define AW8697_REG_VBATDET 0x62 +#define AW8697_REG_TESTDET 0x63 +#define AW8697_REG_DETLO 0x64 +#define AW8697_REG_BEMFDBG 0x65 +#define AW8697_REG_ADCTEST 0x66 +#define AW8697_REG_BEMFTEST 0x67 +#define AW8697_REG_F_LRA_F0_H 0x68 +#define AW8697_REG_F_LRA_F0_L 0x69 +#define AW8697_REG_F_LRA_CONT_H 0x6a +#define AW8697_REG_F_LRA_CONT_L 0x6b +#define AW8697_REG_WAIT_VOL_MP 0x6d +#define AW8697_REG_WAIT_VOL_MN 0x6f +#define AW8697_REG_BEMF_VOL_H 0x70 +#define AW8697_REG_BEMF_VOL_L 0x71 +#define AW8697_REG_ZC_THRSH_H 0x72 +#define AW8697_REG_ZC_THRSH_L 0x73 +#define AW8697_REG_BEMF_VTHH_H 0x74 +#define AW8697_REG_BEMF_VTHH_L 0x75 +#define AW8697_REG_BEMF_VTHL_H 0x76 +#define AW8697_REG_BEMF_VTHL_L 0x77 +#define AW8697_REG_BEMF_NUM 0x78 +#define AW8697_REG_DRV_TIME 0x79 +#define AW8697_REG_TIME_NZC 0x7a +#define AW8697_REG_DRV_LVL 0x7b +#define AW8697_REG_DRV_LVL_OV 0x7c +#define AW8697_REG_NUM_F0_1 0x7d +#define AW8697_REG_NUM_F0_2 0x7e +#define AW8697_REG_NUM_F0_3 0x7f + + + + +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS 0 +#define REG_RD_ACCESS 1 << 0 +#define REG_WR_ACCESS 1 << 1 + +const unsigned char aw8697_reg_access[AW8697_REG_MAX]={ + [AW8697_REG_ID ] = REG_RD_ACCESS, + [AW8697_REG_SYSST ] = REG_RD_ACCESS, + [AW8697_REG_SYSINT ] = REG_RD_ACCESS, + [AW8697_REG_SYSINTM ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_SYSCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_GO ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_RTP_DATA ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ1 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ2 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ3 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ4 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ5 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ6 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ7 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVSEQ8 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVLOOP1 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVLOOP2 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVLOOP3 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAVLOOP4 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_MAIN_LOOP ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG1_WAV_P ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG2_WAV_P ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG3_WAV_P ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG1_WAV_N ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG2_WAV_N ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG3_WAV_N ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG_PRIO ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG_CFG1 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRG_CFG2 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DBGCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BASE_ADDRH ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BASE_ADDRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_FIFO_AEH ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_FIFO_AEL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_FIFO_AFH ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_FIFO_AFL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAKE_DLY ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_START_DLY ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_END_DLY_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_END_DLY_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DATCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_PWMDEL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_PWMPRC ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_PWMDBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_LDOCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DBGSTAT ] = REG_RD_ACCESS, + [AW8697_REG_BSTDBG1 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BSTDBG2 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BSTDBG3 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BSTCFG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_ANADBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_ANACTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_CPDBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_GLBDBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DATDBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BSTDBG4 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BSTDBG5 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BSTDBG6 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_HDRVDBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_PRLVL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_PRTIME ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_RAMADDRH ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_RAMADDRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_RAMDATA ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_GLB_STATE ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BST_AUTO ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_CONT_CTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_F_PRE_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_F_PRE_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TD_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TD_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TSET ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TRIM_LRA ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_R_SPARE ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_D2SCFG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DETCTRL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_RLDET ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_OSDET ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_VBATDET ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TESTDET ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DETLO ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMFDBG ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_ADCTEST ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMFTEST ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_F_LRA_F0_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_F_LRA_F0_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_F_LRA_CONT_H] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_F_LRA_CONT_L] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAIT_VOL_MP ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_WAIT_VOL_MN ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_VOL_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_VOL_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_ZC_THRSH_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_ZC_THRSH_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_VTHH_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_VTHH_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_VTHL_H ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_VTHL_L ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_BEMF_NUM ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DRV_TIME ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_TIME_NZC ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DRV_LVL ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_DRV_LVL_OV ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_NUM_F0_1 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_NUM_F0_2 ] = REG_RD_ACCESS|REG_WR_ACCESS, + [AW8697_REG_NUM_F0_3 ] = REG_RD_ACCESS|REG_WR_ACCESS, +}; + + +/****************************************************** + * Register Detail + *****************************************************/ +/* SYSST*/ +#define AW8697_BIT_SYSST_BSTERRS (1<<7) +#define AW8697_BIT_SYSST_OVS (1<<6) +#define AW8697_BIT_SYSST_UVLS (1<<5) +#define AW8697_BIT_SYSST_FF_AES (1<<4) +#define AW8697_BIT_SYSST_FF_AFS (1<<3) +#define AW8697_BIT_SYSST_OCDS (1<<2) +#define AW8697_BIT_SYSST_OTS (1<<1) +#define AW8697_BIT_SYSST_DONES (1<<0) + +/* SYSINT*/ +#define AW8697_BIT_SYSINT_BSTERRI (1<<7) +#define AW8697_BIT_SYSINT_OVI (1<<6) +#define AW8697_BIT_SYSINT_UVLI (1<<5) +#define AW8697_BIT_SYSINT_FF_AEI (1<<4) +#define AW8697_BIT_SYSINT_FF_AFI (1<<3) +#define AW8697_BIT_SYSINT_OCDI (1<<2) +#define AW8697_BIT_SYSINT_OTI (1<<1) +#define AW8697_BIT_SYSINT_DONEI (1<<0) + +/*SYSINTM*/ +#define AW8697_BIT_SYSINTM_BSTERR_MASK (~(1<<7)) +#define AW8697_BIT_SYSINTM_BSTERR_OFF (1<<7) +#define AW8697_BIT_SYSINTM_BSTERR_EN (0<<7) +#define AW8697_BIT_SYSINTM_OV_MASK (~(1<<6)) +#define AW8697_BIT_SYSINTM_OV_OFF (1<<6) +#define AW8697_BIT_SYSINTM_OV_EN (0<<6) +#define AW8697_BIT_SYSINTM_UVLO_MASK (~(1<<5)) +#define AW8697_BIT_SYSINTM_UVLO_OFF (1<<5) +#define AW8697_BIT_SYSINTM_UVLO_EN (0<<5) +#define AW8697_BIT_SYSINTM_FF_AE_MASK (~(1<<4)) +#define AW8697_BIT_SYSINTM_FF_AE_OFF (1<<4) +#define AW8697_BIT_SYSINTM_FF_AE_EN (0<<4) +#define AW8697_BIT_SYSINTM_FF_AF_MASK (~(1<<3)) +#define AW8697_BIT_SYSINTM_FF_AF_OFF (1<<3) +#define AW8697_BIT_SYSINTM_FF_AF_EN (0<<3) +#define AW8697_BIT_SYSINTM_OCD_MASK (~(1<<2)) +#define AW8697_BIT_SYSINTM_OCD_OFF (1<<2) +#define AW8697_BIT_SYSINTM_OCD_EN (0<<2) +#define AW8697_BIT_SYSINTM_OT_MASK (~(1<<1)) +#define AW8697_BIT_SYSINTM_OT_OFF (1<<1) +#define AW8697_BIT_SYSINTM_OT_EN (0<<1) +#define AW8697_BIT_SYSINTM_DONE_MASK (~(1<<0)) +#define AW8697_BIT_SYSINTM_DONE_OFF (1<<0) +#define AW8697_BIT_SYSINTM_DONE_EN (0<<0) + +/*SYSCTRL*/ +#define AW8697_BIT_SYSCTRL_WAVDAT_MODE_MASK (~(3<<6)) +#define AW8697_BIT_SYSCTRL_WAVDAT_MODE_4X (3<<6) +#define AW8697_BIT_SYSCTRL_WAVDAT_MODE_2X (0<<6) +#define AW8697_BIT_SYSCTRL_WAVDAT_MODE_1X (1<<6) +#define AW8697_BIT_SYSCTRL_RAMINIT_MASK (~(1<<5)) +#define AW8697_BIT_SYSCTRL_RAMINIT_EN (1<<5) +#define AW8697_BIT_SYSCTRL_RAMINIT_OFF (0<<5) +#define AW8697_BIT_SYSCTRL_PLAY_MODE_MASK (~(3<<2)) +#define AW8697_BIT_SYSCTRL_PLAY_MODE_CONT (2<<2) +#define AW8697_BIT_SYSCTRL_PLAY_MODE_RTP (1<<2) +#define AW8697_BIT_SYSCTRL_PLAY_MODE_RAM (0<<2) +#define AW8697_BIT_SYSCTRL_BST_MODE_MASK (~(1<<1)) +#define AW8697_BIT_SYSCTRL_BST_MODE_BOOST (1<<1) +#define AW8697_BIT_SYSCTRL_BST_MODE_BYPASS (0<<1) +#define AW8697_BIT_SYSCTRL_WORK_MODE_MASK (~(1<<0)) +#define AW8697_BIT_SYSCTRL_STANDBY (1<<0) +#define AW8697_BIT_SYSCTRL_ACTIVE (0<<0) + +/*GO*/ +#define AW8697_BIT_GO_MASK (~(1<<0)) +#define AW8697_BIT_GO_ENABLE (1<<0) +#define AW8697_BIT_GO_DISABLE (0<<0) + +/* WAVSEQ1*/ +#define AW8697_BIT_WAVSEQ1_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ1_WAV_FRM_SEQ1_MASK (~(127<<0)) + +/* WAVSEQ2*/ +#define AW8697_BIT_WAVSEQ2_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ2_WAV_FRM_SEQ2_MASK (~(127<<0)) + +/* WAVSEQ3*/ +#define AW8697_BIT_WAVSEQ3_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ3_WAV_FRM_SEQ3_MASK (~(127<<0)) + +/* WAVSEQ4*/ +#define AW8697_BIT_WAVSEQ4_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ4_WAV_FRM_SEQ4_MASK (~(127<<0)) + +/* WAVSEQ5*/ +#define AW8697_BIT_WAVSEQ5_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ5_WAV_FRM_SEQ5_MASK (~(127<<0)) + +/* WAVSEQ6*/ +#define AW8697_BIT_WAVSEQ6_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ6_WAV_FRM_SEQ6_MASK (~(127<<0)) + +/* WAVSEQ7*/ +#define AW8697_BIT_WAVSEQ7_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ7_WAV_FRM_SEQ7_MASK (~(127<<0)) + +/* WAVSEQ8*/ +#define AW8697_BIT_WAVSEQ8_WAIT (1<<7) +#define AW8697_BIT_WAVSEQ8_WAV_FRM_SEQ8_MASK (~(127<<0)) + +/* WAVLOOP*/ +#define AW8697_BIT_WAVLOOP_SEQN_MASK (~(15<<4)) +#define AW8697_BIT_WAVLOOP_SEQNP1_MASK (~(15<<0)) +#define AW8697_BIT_WAVLOOP_INIFINITELY (15<<0) + +/* WAVLOOP1*/ +#define AW8697_BIT_WAVLOOP1_SEQ1_MASK (~(15<<4)) +#define AW8697_BIT_WAVLOOP1_SEQ2_MASK (~(15<<0)) + +/* WAVLOOP2*/ +#define AW8697_BIT_WAVLOOP2_SEQ3_MASK (~(15<<4)) +#define AW8697_BIT_WAVLOOP2_SEQ4_MASK (~(15<<0)) + +/* WAVLOOP3*/ +#define AW8697_BIT_WAVLOOP3_SEQ5_MASK (~(15<<4)) +#define AW8697_BIT_WAVLOOP3_SEQ6_MASK (~(15<<0)) + +/* WAVLOOP4*/ +#define AW8697_BIT_WAVLOOP4_SEQ7_MASK (~(15<<4)) +#define AW8697_BIT_WAVLOOP4_SEQ8_MASK (~(15<<0)) + + +/* PLAYPRIO*/ +#define AW8697_BIT_PLAYPRIO_GO_MASK (~(3<<6)) +#define AW8697_BIT_PLAYPRIO_TRIG3_MASK (~(3<<4)) +#define AW8697_BIT_PLAYPRIO_TRIG2_MASK (~(3<<2)) +#define AW8697_BIT_PLAYPRIO_TRIG1_MASK (~(3<<0)) + +/* TRGCFG1*/ +#define AW8697_BIT_TRGCFG1_TRG3_POLAR_MASK (~(1<<5)) +#define AW8697_BIT_TRGCFG1_TRG3_POLAR_NEG (1<<5) +#define AW8697_BIT_TRGCFG1_TRG3_POLAR_POS (0<<5) +#define AW8697_BIT_TRGCFG1_TRG3_EDGE_MASK (~(1<<4)) +#define AW8697_BIT_TRGCFG1_TRG3_EDGE_POS (1<<4) +#define AW8697_BIT_TRGCFG1_TRG3_EDGE_POS_NEG (0<<4) +#define AW8697_BIT_TRGCFG1_TRG2_POLAR_MASK (~(1<<3)) +#define AW8697_BIT_TRGCFG1_TRG2_POLAR_NEG (1<<3) +#define AW8697_BIT_TRGCFG1_TRG2_POLAR_POS (0<<3) +#define AW8697_BIT_TRGCFG1_TRG2_EDGE_MASK (~(1<<2)) +#define AW8697_BIT_TRGCFG1_TRG2_EDGE_POS (1<<2) +#define AW8697_BIT_TRGCFG1_TRG2_EDGE_POS_NEG (0<<2) +#define AW8697_BIT_TRGCFG1_TRG1_POLAR_MASK (~(1<<1)) +#define AW8697_BIT_TRGCFG1_TRG1_POLAR_NEG (1<<1) +#define AW8697_BIT_TRGCFG1_TRG1_POLAR_POS (0<<1) +#define AW8697_BIT_TRGCFG1_TRG1_EDGE_MASK (~(1<<0)) +#define AW8697_BIT_TRGCFG1_TRG1_EDGE_POS (1<<0) +#define AW8697_BIT_TRGCFG1_TRG1_EDGE_POS_NEG (0<<0) + +/* TRGCFG2*/ +#define AW8697_BIT_TRGCFG2_TRG3_ENABLE_MASK (~(1<<2)) +#define AW8697_BIT_TRGCFG2_TRG3_ENABLE (1<<2) +#define AW8697_BIT_TRGCFG2_TRG3_DISABLE (0<<2) +#define AW8697_BIT_TRGCFG2_TRG2_ENABLE_MASK (~(1<<1)) +#define AW8697_BIT_TRGCFG2_TRG2_ENABLE (1<<1) +#define AW8697_BIT_TRGCFG2_TRG2_DISABLE (0<<1) +#define AW8697_BIT_TRGCFG2_TRG1_ENABLE_MASK (~(1<<0)) +#define AW8697_BIT_TRGCFG2_TRG1_ENABLE (1<<0) +#define AW8697_BIT_TRGCFG2_TRG1_DISABLE (0<<0) + +/* DBGCTRL*/ +#define AW8697_BIT_DBGCTRL_INT_EDGE_MODE_MASK (~(1<<3)) +#define AW8697_BIT_DBGCTRL_INT_EDGE_MODE_POS (1<<3) +#define AW8697_BIT_DBGCTRL_INT_EDGE_MODE_BOTH (0<<3) +#define AW8697_BIT_DBGCTRL_INT_MODE_MASK (~(1<<2)) +#define AW8697_BIT_DBGCTRL_INT_MODE_EDGE (1<<2) +#define AW8697_BIT_DBGCTRL_INT_MODE_LEVEL (0<<2) + +/* DATCTRL*/ +#define AW8697_BIT_DATCTRL_FC_MASK (~(1<<6)) +#define AW8697_BIT_DATCTRL_FC_1000HZ (3<<6) +#define AW8697_BIT_DATCTRL_FC_800HZ (3<<6) +#define AW8697_BIT_DATCTRL_FC_600HZ (1<<6) +#define AW8697_BIT_DATCTRL_FC_400HZ (0<<6) +#define AW8697_BIT_DATCTRL_LPF_ENABLE_MASK (~(1<<5)) +#define AW8697_BIT_DATCTRL_LPF_ENABLE (1<<5) +#define AW8697_BIT_DATCTRL_LPF_DISABLE (0<<5) +#define AW8697_BIT_DATCTRL_WAKEMODE_ENABLE_MASK (~(1<<0)) +#define AW8697_BIT_DATCTRL_WAKEMODE_ENABLE (1<<0) +#define AW8697_BIT_DATCTRL_WAKEMODE_DISABLE (0<<0) + +/* PWMPRC*/ +#define AW8697_BIT_PWMPRC_PRC_MASK (~(1<<7)) +#define AW8697_BIT_PWMPRC_PRC_ENABLE (1<<7) +#define AW8697_BIT_PWMPRC_PRC_DISABLE (0<<7) +#define AW8697_BIT_PWMPRC_PRCTIME_MASK (~(0x7f<<0)) + +/* PWMDBG*/ +#define AW8697_BIT_PWMDBG_PWM_MODE_MASK (~(3<<5)) +#define AW8697_BIT_PWMDBG_PWM_12K (3<<5) +#define AW8697_BIT_PWMDBG_PWM_24K (2<<5) +#define AW8697_BIT_PWMDBG_PWM_48K (0<<5) + +// BSTCFG: reg0x34 +#define AW8697_BIT_BSTCFG_PEAKCUR_MASK (~(7<<0)) +#define AW8697_BIT_BSTCFG_PEAKCUR_4A (7<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_3P75A (6<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_3P5A (5<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_3P25A (4<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_3A (3<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_2P5A (2<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_2A (1<<0) +#define AW8697_BIT_BSTCFG_PEAKCUR_1P5A (0<<0) +/* PRLVL*/ +// ANADBG: reg0x35 +#define AW8697_BIT_ANADBG_IOC_MASK (~(3<<2)) +#define AW8697_BIT_ANADBG_IOC_4P65A (3<<2) +#define AW8697_BIT_ANADBG_IOC_4P15A (2<<2) +#define AW8697_BIT_ANADBG_IOC_3P65A (1<<2) +#define AW8697_BIT_ANADBG_IOC_3P15A (0<<2) +/*FOR OVER CURRENT*/ +#define AW8697_BIT_ANADBG_IOC_OCDT_MASK (~(3<<0)) + +#define AW8697_BIT_ANADBG_IOC_OCDT_150NS (3<<0) +// ANACTRL: reg0x36 +#define AW8697_BIT_ANACTRL_LRA_SRC_MASK (~(1<<5)) +#define AW8697_BIT_ANACTRL_LRA_SRC_REG (1<<5) +#define AW8697_BIT_ANACTRL_LRA_SRC_EFUSE (0<<5) +#define AW8697_BIT_ANACTRL_HD_PD_MASK (~(1<<3)) +#define AW8697_BIT_ANACTRL_HD_PD_EN (1<<3) +#define AW8697_BIT_ANACTRL_HD_HZ_EN (0<<3) +// BSTDBG4: reg0x3a +#define AW8697_BIT_BSTDBG4_BSTVOL_MASK (~(31<<1)) +#define AW8697_BIT_PRLVL_PR_MASK (~(1<<7)) +#define AW8697_BIT_PRLVL_PR_ENABLE (1<<7) +#define AW8697_BIT_PRLVL_PR_DISABLE (0<<7) +#define AW8697_BIT_PRLVL_PRLVL_MASK (~(0x7f<<0)) + +/*PRTIME*/ +#define AW8697_BIT_PRTIME_PRTIME_MASK (~(0xff<<0)) + +/* BST_AUTO*/ +#define AW8697_BIT_BST_AUTO_BST_AUTOSW_MASK (~(1<<2)) +#define AW8697_BIT_BST_AUTO_BST_AUTOMATIC_BOOST (1<<2) +#define AW8697_BIT_BST_AUTO_BST_MANUAL_BOOST (0<<2) +#define AW8697_BIT_BST_AUTO_BST_RTP_MASK (~(1<<1)) +#define AW8697_BIT_BST_AUTO_BST_RTP_ENABLE (1<<1) +#define AW8697_BIT_BST_AUTO_BST_RTP_DISABLE (0<<1) +#define AW8697_BIT_BST_AUTO_BST_RAM_MASK (~(1<<0)) +#define AW8697_BIT_BST_AUTO_BST_RAM_ENABLE (1<<0) +#define AW8697_BIT_BST_AUTO_BST_RAM_DISABLE (0<<0) + +/* CONT_CTRL*/ +#define AW8697_BIT_CONT_CTRL_ZC_DETEC_MASK (~(1<<7)) +#define AW8697_BIT_CONT_CTRL_ZC_DETEC_ENABLE (1<<7) +#define AW8697_BIT_CONT_CTRL_ZC_DETEC_DISABLE (0<<7) +#define AW8697_BIT_CONT_CTRL_WAIT_PERIOD_MASK (~(3<<5)) +#define AW8697_BIT_CONT_CTRL_WAIT_8PERIOD (3<<5) +#define AW8697_BIT_CONT_CTRL_WAIT_4PERIOD (2<<5) +#define AW8697_BIT_CONT_CTRL_WAIT_2PERIOD (1<<5) +#define AW8697_BIT_CONT_CTRL_WAIT_1PERIOD (0<<5) +#define AW8697_BIT_CONT_CTRL_MODE_MASK (~(1<<4)) +#define AW8697_BIT_CONT_CTRL_BY_DRV_TIME (1<<4) +#define AW8697_BIT_CONT_CTRL_BY_GO_SIGNAL (0<<4) +#define AW8697_BIT_CONT_CTRL_EN_CLOSE_MASK (~(1<<3)) +#define AW8697_BIT_CONT_CTRL_CLOSE_PLAYBACK (1<<3) +#define AW8697_BIT_CONT_CTRL_OPEN_PLAYBACK (0<<3) +#define AW8697_BIT_CONT_CTRL_F0_DETECT_MASK (~(1<<2)) +#define AW8697_BIT_CONT_CTRL_F0_DETECT_ENABLE (1<<2) +#define AW8697_BIT_CONT_CTRL_F0_DETECT_DISABLE (0<<2) +#define AW8697_BIT_CONT_CTRL_O2C_MASK (~(1<<1)) +#define AW8697_BIT_CONT_CTRL_O2C_ENABLE (1<<1) +#define AW8697_BIT_CONT_CTRL_O2C_DISABLE (0<<1) +#define AW8697_BIT_CONT_CTRL_AUTO_BRK_MASK (~(1<<0)) +#define AW8697_BIT_CONT_CTRL_AUTO_BRK_ENABLE (1<<0) +#define AW8697_BIT_CONT_CTRL_AUTO_BRK_DISABLE (0<<0) + +#define AW8697_BIT_D2SCFG_CLK_ADC_MASK (~(7<<5)) +#define AW8697_BIT_D2SCFG_CLK_ASC_0P09375MHZ (7<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_0P1875MHZ (6<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_0P375MHZ (5<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_0P75MHZ (4<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_1P5MHZ (3<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_3MHZ (2<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_6MHZ (1<<5) +#define AW8697_BIT_D2SCFG_CLK_ASC_12MHZ (0<<5) + +/* DETCTRL*/ +#define AW8697_BIT_DETCTRL_RL_OS_MASK (~(1<<6)) +#define AW8697_BIT_DETCTRL_RL_DETECT (1<<6) +#define AW8697_BIT_DETCTRL_OS_DETECT (0<<6) +#define AW8697_BIT_DETCTRL_PROTECT_MASK (~(1<<5)) +#define AW8697_BIT_DETCTRL_PROTECT_NO_ACTION (1<<5) +#define AW8697_BIT_DETCTRL_PROTECT_SHUTDOWN (0<<5) +#define AW8697_BIT_DETCTRL_ADO_SLOT_MODE_MASK (~(1<<4)) +#define AW8697_BIT_DETCTRL_ADO_SLOT_MODE_ENABLE (1<<4) +#define AW8697_BIT_DETCTRL_ADO_SLOT_MODE_DISABLE (0<<4) +#define AW8697_BIT_DETCTRL_VBAT_GO_MASK (~(1<<1)) +#define AW8697_BIT_DETCTRL_VABT_GO_ENABLE (1<<1) +#define AW8697_BIT_DETCTRL_VBAT_GO_DISBALE (0<<1) +#define AW8697_BIT_DETCTRL_DIAG_GO_MASK (~(1<<0)) +#define AW8697_BIT_DETCTRL_DIAG_GO_ENABLE (1<<0) +#define AW8697_BIT_DETCTRL_DIAG_GO_DISABLE (0<<0) + + +/* VBAT MODE*/ +#define AW8697_BIT_ADCTEST_VBAT_MODE_MASK (~(1<<6)) +#define AW8697_BIT_ADCTEST_VBAT_HW_COMP (1<<6) +#define AW8697_BIT_ADCTEST_VBAT_SW_COMP (0<<6) + +/* BSTCFG*/ +#define AW8697_BIT_BEMF_NUM_BRK_MASK (~(15<<0)) +#define AW8697_TRIM_MASK (~(3<<6)) +#define AW8697_TRIM_DEFAULT (0x00) + + + +#endif diff --git a/drivers/oneplus/vl53L1/Kbuild b/drivers/oneplus/vl53L1/Kbuild new file mode 100755 index 0000000000000000000000000000000000000000..a4a62d819181f98b029d5736f4866de3cbe6177d --- /dev/null +++ b/drivers/oneplus/vl53L1/Kbuild @@ -0,0 +1,30 @@ +# +# Kbuild for the vl53L1 drivers. +# + +ccflags-y += -I$(src)/inc -I$(src)/ipp -I$(src) +ccflags-y += -Itechpack/camera/drivers/cam_sensor_module/cam_cci + +# define this environment variable if you want to compile driver for an old +# kernel +ifdef OLD_NETLINK_API +ccflags-y += -DOLD_NETLINK_API +endif + +ifdef VL53L1_LOG_ENABLE +ccflags-y += -DVL53L1_LOG_ENABLE +endif + +obj-$(CONFIG_STMVL53L1) += stmvl53l1.o +stmvl53l1-objs := stmvl53l1_module.o stmvl53l1_module-i2c.o stmvl53l1_module-cci.o +stmvl53l1-objs += stmvl53l1_i2c.o stmvl53l1_ipp_nl.o stmvl53l1_log.o +stmvl53l1-objs += src/vl53l1_api.o src/vl53l1_api_core.o +stmvl53l1-objs += src/vl53l1_api_strings.o src/vl53l1_error_strings.o +stmvl53l1-objs += src/vl53l1_core.o src/vl53l1_register_funcs.o +stmvl53l1-objs += src/vl53l1_api_preset_modes.o +stmvl53l1-objs += src/vl53l1_api_calibration.o +stmvl53l1-objs += src/vl53l1_silicon_core.o +stmvl53l1-objs += src/vl53l1_zone_presets.o src/vl53l1_nvm.o +stmvl53l1-objs += src/vl53l1_api_debug.o src/vl53l1_core_support.o +stmvl53l1-objs += src/vl53l1_wait.o ipp/ipp_linux.o +stmvl53l1-objs += src/vl53l1_nvm_debug.o diff --git a/drivers/oneplus/vl53L1/Kconfig b/drivers/oneplus/vl53L1/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..45fb25b20c1afc307467c723a671fbec7615cbe1 --- /dev/null +++ b/drivers/oneplus/vl53L1/Kconfig @@ -0,0 +1,10 @@ +config STMVL53L1 + tristate "STM VL53L1 Proximity support" + depends on I2C=y + default y + help + Say Y here if you want to use STMicroelectronics's vl53L1 TOF AF sensor + through I2C interface. + + To compile this driver as a module, choose M here: the + module will be called stmvl53l1. diff --git a/drivers/oneplus/vl53L1/Makefile b/drivers/oneplus/vl53L1/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..4dd06f8d49f8d39e9d778e00425c29a30a2eee56 --- /dev/null +++ b/drivers/oneplus/vl53L1/Makefile @@ -0,0 +1,12 @@ +ifneq ($(KERNELRELEASE),) +include Kbuild + +else +KDIR ?= /lib/modules/`uname -r`/build + +default: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD +clean: + CONFIG_STMVL53L1=m $(MAKE) -C $(KDIR) M=$$PWD clean + +endif \ No newline at end of file diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_api.h b/drivers/oneplus/vl53L1/inc/vl53l1_api.h new file mode 100755 index 0000000000000000000000000000000000000000..fb24dfb0baaadc9d788cdee16824b8a8710759af --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_api.h @@ -0,0 +1,1432 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +#ifndef _VL53L1_API_H_ +#define _VL53L1_API_H_ + +#include "vl53l1_api_strings.h" +#include "vl53l1_api_core.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(VL53L1DevDataGet) +#warning "PALDevDataGet is deprecated define VL53L1DevDataGet instead" +#define VL53L1DevDataGet(Dev, field) (Dev->Data.field) +#endif + +#if !defined(VL53L1DevDataSet) +#warning "PALDevDataSet is deprecated define VL53L1DevDataSet instead" +#define VL53L1DevDataSet(Dev, field, data) ((Dev->Data.field) = (data)) +#endif + +/** @defgroup VL53L1_cut11_group VL53L1 cut1.1 Function Definition + * @brief VL53L1 cut1.1 Function Definition + * @{ + */ + +/** @defgroup VL53L1_general_group VL53L1 General Functions + * @brief General functions and definitions + * @{ + */ + +/** + * @brief Return the VL53L1 driver Version + * + * @note This function doesn't access to the device + * + * @param pVersion Rer to current driver Version + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion); + +/** + * @brief Reads the Product Revision for a for given Device + * This function can be used to distinguish cut1.0 from cut1.1. + * + * @param Dev Device Handle + * @param pProductRevisionMajor Pointer to Product Revision Major + * for a given Device + * @param pProductRevisionMinor Pointer to Product Revision Minor + * for a given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor); + +/** + * @brief Reads the Device information for given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVL53L1_DeviceInfo Pointer to current device info for a given + * Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo); + +/** + * @brief Human readable Range Status string for a given RangeStatus + * + * @note This function doesn't access to the device + * + * @param RangeStatus The RangeStatus code as stored on + * @a VL53L1_RangingMeasurementData_t + * @param pRangeStatusString The returned RangeStatus string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Human readable error string for driver error status + * + * @note This function doesn't access to the device + * + * @param PalErrorCode The error code as stored on @a VL53L1_Error + * @param pPalErrorString The error string corresponding to the + * PalErrorCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Human readable driver State string + * + * @note This function doesn't access to the device + * + * @param PalStateCode The State code as stored on @a VL53L1_State + * @param pPalStateString The State string corresponding to the + * PalStateCode. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString); + +/** + * @brief Reads the internal state of the driver for a given Device + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pPalState Pointer to current state of the PAL for a + * given Device + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, + VL53L1_State *pPalState); + + + +/** @} VL53L1_general_group */ + +/** @defgroup VL53L1_init_group VL53L1 Init Functions + * @brief VL53L1 Init Functions + * @{ + */ + +/** + * @brief Set new device address + * + * After completion the device will answer to the new address programmed. + * This function should be called when several devices are used in parallel + * before start programming the sensor. + * When a single device us used, there is no need to call this function. + * + * When it is requested for multi devices system this function MUST be called + * prior to VL53L1_DataInit() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param DeviceAddress The new Device address + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, + uint8_t DeviceAddress); + +/** + * + * @brief One time device initialization + * + * To be called once and only once after device is brought out of reset + * (Chip enable) and booted see @a VL53L1_WaitDeviceBooted() + * + * @par Function Description + * When not used after a fresh device "power up" or reset, it may return + * @a #VL53L1_ERROR_CALIBRATION_WARNING meaning wrong calibration data + * may have been fetched from device that can result in ranging offset error\n + * If application cannot execute device reset or need to run VL53L1_DataInit + * multiple time then it must ensure proper offset calibration saving and + * restore on its own by using @a VL53L1_GetOffsetCalibrationData() on first + * power up and then @a VL53L1_SetOffsetCalibrationData() in all subsequent init + * This function will change the VL53L1_State from VL53L1_STATE_POWERDOWN to + * VL53L1_STATE_WAIT_STATICINIT. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev); + + +/** + * @brief Do basic device init (and eventually patch loading) + * This function will change the VL53L1_State from + * VL53L1_STATE_WAIT_STATICINIT to VL53L1_STATE_IDLE. + * In this stage all default setting will be applied. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev); + +/** + * @brief Wait for device booted after chip enable (hardware standby) + * This function can be run only when VL53L1_State is VL53L1_STATE_POWERDOWN. + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev); + + +/** @} VL53L1_init_group */ + +/** @defgroup VL53L1_parameters_group VL53L1 Parameters Functions + * @brief Functions used to prepare and setup the device + * @{ + */ + +/** + * @brief Set a new Preset Mode + * @par Function Description + * Set device to a new Operating Mode (High speed ranging, Multi objects ...) + * + * @note This function doesn't Access to the device + * + * @warning This function change the timing budget to 16 ms and the inter- + * measurement period to 1000 ms. Also the VL53L1_DISTANCEMODE_LONG is used. + * + * @param Dev Device Handle + * @param PresetMode New Preset mode to apply + *
Valid values are: + */ +/** + * @li VL53L1_PRESETMODE_MULTIZONES_SCANNING + * @li VL53L1_PRESETMODE_RANGING + * @li VL53L1_PRESETMODE_AUTONOMOUS + * @li VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * @li VL53L1_PRESETMODE_LITE_RANGING + * @li VL53L1_PRESETMODE_OLT + */ +/** + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when PresetMode is + * not in the supported list + */ +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode); + +/** + * @brief Get current Preset Mode + * @par Function Description + * Get actual mode of the device(ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pPresetMode Pointer to current apply mode value + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode is not in the supported list + */ +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode); + + +/** + * @brief Set the distance mode + * @par Function Description + * Set the distance mode to be used for the next ranging.
+ * The modes Short, Medium and Long are used to optimize the ranging accuracy + * in a specific range of distance.
The user select one of these modes to + * select the distance range.
+ * Two additional modes are supported: AUTO and AUTO_LITE the difference between + * these modes is the following.
+ * The mode AUTO take into account both the ranging distance (RangeMilliMeter) + * and the dmax distance (DmaxMilliMeter).
The algorithm uses the ranging + * distance when the range status is ok and uses the dmax distance when the + * range status is not ok.
+ * The AUTO_LITE take into account only the ranging distance, so nothing is done + * in case of range error i.e. the distance mode will not be changed. + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param DistanceMode Distance mode to apply valid values are: + * @li VL53L1_DISTANCEMODE_SHORT + * @li VL53L1_DISTANCEMODE_MEDIUM + * @li VL53L1_DISTANCEMODE_LONG + * @li VL53L1_DISTANCEMODE_AUTO_LITE + * @li VL53L1_DISTANCEMODE_AUTO + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when DistanceMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode); + +/** + * @brief Get the distance mode + * @par Function Description + * Get the distance mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pDistanceMode Pointer to Distance mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode); + + +/** + * @brief Set the output mode + * @par Function Description + * Set the output mode to be used for the next ranging. The output mode is used + * to select, in case of multiple objects, which one will be used in + * function @a VL53L1_GetRangingMeasurementData(). + * VL53L1_SetOutputMode also sets the object used by automatic + * distance mode algorithm when @a VL53L1_SetDistanceMode() is + * set to automatic mode. + * + * @note This function doesn't Access to the device + * + * @warning This function should be called after @a VL53L1_SetPresetMode(). + + * @param Dev Device Handle + * @param OutputMode Output mode to apply valid values are: + * @li VL53L1_OUTPUTMODE_NEAREST + * @li VL53L1_OUTPUTMODE_STRONGEST + * + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when OutputMode + * is not in the supported list + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode); + +/** + * @brief Get the output mode + * @par Function Description + * Get the output mode used for the next ranging. + * + * @param Dev Device Handle + * @param *pOutputMode Pointer to Output mode + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode); + + +/** + * @brief Set Ranging Timing Budget in microseconds + * + * @par Function Description + * Defines the maximum time allowed by the user to the device to run a + * full ranging sequence for the current mode (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param MeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error timing parameter not + * supported. + * The maximum accepted value for the + * computed timing budget is 10 seconds + * the minimum value depends on the preset + * mode selected. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +/** + * @brief Get Ranging Timing Budget in microseconds + * + * @par Function Description + * Returns the programmed the maximum time allowed by the user to the + * device to run a full ranging sequence for the current mode + * (ranging, histogram, ASL ...) + * + * @param Dev Device Handle + * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds( + VL53L1_DEV Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + + +/** + * Program continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @param Dev Device Handle + * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms. + * this value should be greater than the duration set in + * @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() to ensure smooth ranging + * operation. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t InterMeasurementPeriodMilliSeconds); + +/** + * Get continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * + * @param Dev Device Handle + * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed + * Inter-Measurement Period in milliseconds. + * @return VL53L1_ERROR_NONE + */ +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds( + VL53L1_DEV Dev, uint32_t *pInterMeasurementPeriodMilliSeconds); + +/** + * @brief target reflectance for Dmax setting + * @par Function Description + * Allow user to set the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param DmaxReflectance Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS in case input value is not in range + * from 0 to 100. Note that this is a fix point value so the max value is + * 100 * 65536. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance); + +/** + * @brief Get target reflectance for Dmax + * @par Function Description + * Retrieves the value for target reflectance @ 940nm to calculate the + * ambient DMAX values for. Set to 50% by default by @a VL53L1_DataInit() + * + * @param Dev Device Handle + * @param pDmaxReflectance pointer to Reflectance % in 16.16 fixed point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance); +/** + * @brief Set function for ambient Dmax mode + * + * + * @param Dev Device Handle + * @param DmaxMode DMAX mode to be used in ranging + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode); + +/** + * @brief Get function for ambient Dmax mode + * + * @param Dev Device Handle + * @param pDmaxMode output pointer to DMAX mode currently in use + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode); + +/** @} VL53L1_parameters_group */ + + +/** @defgroup VL53L1_limitcheck_group VL53L1 Limit Check Functions + * @brief Functions used for the Limit checks + * @{ + */ + + + +/** + * @brief Get the number of the check limit managed by a given Device + * + * @par Function Description + * This function give the number of the check limit managed by the Device + * + * @param pNumberOfLimitCheck Pointer to the number of check limit. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfLimitCheck( + uint16_t *pNumberOfLimitCheck); + +/** + * @brief Return a description string for a given limit check number + * + * @par Function Description + * This function returns a description string for a given limit check number. + * The limit check is identified with the LimitCheckId. + * + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckString Pointer to the description string of + * the given check limit. Shall be defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString); + +/** + * @brief Return a the Status of the specified check limit + * + * @par Function Description + * This function returns the Status of the specified check limit. + * The value indicate if the check is fail or not. + * The limit check is identified with the LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckStatus Pointer to the + Limit Check Status of the given check limit. + * LimitCheckStatus : + * 0 the check is not fail or not enabled + * 1 the check if fail + * + *

    + *
  • VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: the sigma indicate the quality + * of the measure. The more it is little the better it is. + * The status is 1 when current sigma is greater then the limit.
  • + *
  • VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: the signal rate indicate + * the strength of the returned signal. The more it is big the better it is. + * The status is 1 when current signal is lower then the limit.
  • + *

+ * + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus); + +/** + * @brief Enable/Disable a specific limit check + * + * @par Function Description + * This function Enable/Disable a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckEnable + * @li set LimitCheckEnable=1 enables the LimitCheckId limit + * @li set LimitCheckEnable=0 disables the LimitCheckId limit + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable); + +/** + * @brief Get specific limit check enable state + * + * @par Function Description + * This function get the enable state of a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckEnable Pointer to the check limit enable + * value. + * @li if 1 the check limit corresponding to LimitCheckId is Enabled + * @li if 0 the check limit corresponding to LimitCheckId is disabled + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + +/** + * @brief Set a specific limit check value + * + * @par Function Description + * This function set a specific limit check value. + * The limit check is identified with the LimitCheckId. + * + * @note Note that the value written with that function will not be applied if + * the limit is not enabled. In other words this function will not enable the + * limit but change only the value. In case the limit is not enabled the value + * is saved internally and applied with VL53L1_SetLimitCheckEnable. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param LimitCheckValue Limit check Value for a given + * LimitCheckId + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t LimitCheckValue); + +/** + * @brief Get a specific limit check value + * + * @par Function Description + * This function get a specific limit check value from device then it updates + * internal values and check enables. + * The limit check is identified with the LimitCheckId. + * + * @note This function get the current value from device if zero then the value + * returned is the one stored by the user, but in that case the check is store + * as disabled. If the value from device is not zero, this is returned and set + * into the memory at the same way that user call VL53L1_SetLimitCheckValue() + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckValue Pointer to Limit + * check Value for a given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckValue); + +/** + * @brief Get the current value of the signal used for the limit check + * + * @par Function Description + * This function get a the current value of the signal used for the limit check. + * To obtain the latest value you should run a valid ranging before. + * The value reported is linked to the limit check identified with the + * LimitCheckId. + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL53L1_GetNumberOfLimitCheck() ). + * @param pLimitCheckCurrent Pointer to current Value for a + * given LimitCheckId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, + uint16_t LimitCheckId, FixPoint1616_t *pLimitCheckCurrent); + +/** @} VL53L1_limitcheck_group */ + + + +/** @defgroup VL53L1_ROI_group VL53L1 ROI Functions + * @brief Functions used to select ROIs + * @{ + */ + +/** + * @brief Get the Maximum number of ROI Zones managed by the Device + * + * @par Function Description + * Get Maximum number of ROI Zones managed by the Device. + * + * @note The number of Zone depends on the preset mode used so to have the + * right number this function should be call after @a VL53L1_SetPresetMode() + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pMaxNumberOfROI Pointer to the Maximum Number + * of ROI Zones value. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI); +/** + * @brief Set the ROI to be used for ranging + * + * @par Function Description + * The user defined ROIs are rectangles described as per the following system + * from the Top Left corner to the Bottom Right corner. + *
Minimal ROI size is 4x4 spads + * @image html roi_coord.png + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** + * @brief Get the ROI managed by the Device + * + * @par Function Description + * Get the ROI managed by the Device + * + * @param Dev Device Handle + * @param pRoiConfig Pointer to the Structure containing all the + * ROI to be used. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig); + +/** @} VL53L1_ROI_group */ + +/* \internal */ +/** @defgroup VL53L1_sequencestep_group VL53L1 Sequence Step Functions + * @brief Functions used to select Steps done on each ranging + * @{ + */ + +/** + * @brief Gets number of sequence steps managed by the API. + * + * @par Function Description + * This function retrieves the number of sequence steps currently managed + * by the API + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pNumberOfSequenceSteps Out parameter reporting the number of + * sequence steps. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps); + +/** + * @brief Gets the name of a given sequence step. + * + * @par Function Description + * This function retrieves the name of sequence steps corresponding to + * SequenceStepId. + * + * @note This function doesn't Accesses the device + * + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepsString Pointer to Info string. Shall be + * defined as char buf[VL53L1_MAX_STRING_LENGTH] + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepsInfo( + VL53L1_SequenceStepId SequenceStepId, char *pSequenceStepsString); + + + +/** + * @brief Sets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function enables/disables a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param SequenceStepEnabled Demanded state {0=Off,1=On} + * is enabled. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function retrieves the state of a requested sequence step, i.e. on/off. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepEnabled Out parameter reporting if the sequence step + * is enabled {0=Off,1=On}. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled); + + +/** @} VL53L1_sequencestep_group */ +/* \endinternal */ + + + +/** @defgroup VL53L1_measurement_group VL53L1 Measurement Functions + * @brief Functions used for the measurements + * @{ + */ + +/** + * @brief Start device measurement + * + * @details Started measurement will depend on preset parameters set through + * @a VL53L1_SetPreseMode() + * This function will change the VL53L1_State from VL53L1_STATE_IDLE to + * VL53L1_STATE_RUNNING. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED This error occurs when + * PresetMode programmed with @a VL53L1_SetPresetMode + * @return VL53L1_ERROR_TIME_OUT Time out on start measurement + * @return VL53L1_ERROR_INVALID_PARAMS This error might occur in timed mode + * when inter measurement period is smaller or too close to the timing budget. + * In such case measurements are not started and user must correct the timings + * passed to @a VL53L1_SetMeasurementTimingBudgetMicroSeconds() and + * @a VL53L1_SetInterMeasurementPeriodMilliSeconds() functions. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Stop device measurement + * + * @details Will set the device in standby mode at end of current measurement\n + * Not necessary in single mode as device shall return automatically + * in standby mode at end of measurement. + * This function will change the VL53L1_State from VL53L1_STATE_RUNNING + * to VL53L1_STATE_IDLE. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev); + +/** + * @brief Clear the Interrupt flag and start new measurement + * * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev); + +/** + * @brief Return Measurement Data Ready + * + * @par Function Description + * This function indicate that a measurement data is ready. + * This function is used for non-blocking capture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementDataReady Pointer to Measurement Data Ready. + * 0 = data not ready, 1 = data ready + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady); + +/** + * @brief Wait for measurement data ready. + * Blocking function. + * Note that the timeout is given by: + * VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS defined in def.h + * + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_TIME_OUT In case of timeout + */ +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev); + + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + */ +/** + * @warning this function will return only the first ROI data and only the + * first object. For multi objects or multi ROI use: + * @a Vl53L1_GetMultiRangingData. + * In case of RANGING only one output is given, this can + * be selected with the help of @a VL53L1_SetOutputMode() + * In case of MULTIZONES_SCANNING and error will be raised because not + * supported in that function. + */ +/** + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_MODE_NOT_SUPPORTED in case of MULTIZONES_SCANNING + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Retrieve all ROI's measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + * @warning USER should take care about @a VL53L1_GetNumberOfROI() + * before get data. + * Bare driver will fill a NumberOfROI times the corresponding data + * structure used in the measurement function. + * + * @warning USER must call @a VL53L1_ClearInterruptAndStartMeasurement() prior + * to call again this function + * + * @note This function Access to the device + * + * @note The first valid value returned by this function will have a range + * status equal to VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK which means that + * the data is valid but no wrap around check have been done. User should take + * care about that. + * + * @param Dev Device Handle + * @param pMultiRangingData Pointer to the data structure to fill up. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData); + +/** + * @brief Get Additional Data + * + * @par Function Description + * This function is used to get lld debugging data on the last histogram + * measurement. shall be called when a new measurement is ready (interrupt or + * positive VL53L1_GetMeasurementDataReady() polling) and before a call to + * VL53L1_ClearInterruptAndStartMeasurement(). Depending on the PresetMode + * currently set parts of the returned data structure may be not relevant. + * + * @param Dev Device Handle + * @param pAdditionalData Pointer to Additional data + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData); + + +/** @} VL53L1_measurement_group */ + +/** @defgroup VL53L1_Calibration_group VL53L1 Calibration Functions + * @brief Functions used for Calibration + * @{ + */ + + +/** + * @brief Set Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to improve the performance of the device. It permit to + * change a particular value used for a timeout or a threshold or a constant + * in an algorithm. The function will change the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param TuningParameterValue Tuning Parameter Value + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue); + +/** + * @brief Get Tuning Parameter value for a given parameter ID + * + * @par Function Description + * This function is used to get the value of the parameter + * identified by an unique ID. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param TuningParameterId Tuning Parameter ID + * @param pTuningParameterValue Pointer to Tuning Parameter Value + * for a given TuningParameterId. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue); + +/** + * @brief Performs Reference Spad Management + * + * @par Function Description + * The reference SPAD initialization procedure determines the minimum amount + * of reference spads to be enables to achieve a target reference signal rate + * and should be performed once during initialization. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev); + +/** + * @brief Enable/Disable dynamic Xtalk compensation feature + * + * Enable/Disable dynamic Xtalk compensation (aka smudge correction). + * + * @param Dev Device Handle + * @param Mode Set the smudge correction mode + * See ::VL53L1_SmudgeCorrectionModes + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode); + +/** + * @brief Enable/Disable Cross talk compensation feature + * + * Enable/Disable Cross Talk correction. + * + * @param Dev Device Handle + * @param XTalkCompensationEnable Cross talk compensation + * to be set 0 = disabled or 1 = enabled. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, +uint8_t XTalkCompensationEnable); + +/** + * @brief Get Cross talk compensation rate enable + * + * Get if the Cross Talk is Enabled or Disabled. + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pXTalkCompensationEnable Pointer to the Cross talk compensation + * state 0=disabled or 1 = enabled + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable); + + +/** + * @brief Perform XTalk Calibration + * + * @details Perform a XTalk calibration of the Device. + * This function will launch a ranging measurement, if interrupts + * are enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the XTalk compensation + * and it will enable the cross talk before exit. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalibrationOption Select the Calibration to be run : + * @param CalibrationOption + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET the calibration uses current + * preset and distance mode without altering them.
+ * User must call @a VL53L1_SetPresetMode() with VL53L1_PRESETMODE_AUTONOMOUS, + * VL53L1_PRESETMODE_LITE_RANGING or VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS + * parameter prior to launch calibration + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. during this calibration mode no object must be put below a 80cm + * distance from the target + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI the calibration sets appropriate + * preset and distance mode and thus override existing ones
+ * User must call @a VL53L1_SetPresetMode() again after calibration to set the + * desired one. + * The ROI settings must define a single 16x16 ROI before to launch this + * function. + * The calibration uses a target which should be located at least @60cm from the + * device. The actual location of the target shall be passed + * through the bare driver tuning parameters table + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption); + +/** + * @brief Define the mode to be used for the offset calibration + * + * Define the mode to be used for the offset calibration. This function should + * be called before run the @a VL53L1_PerformOffsetCalibration() + * + * @param Dev Device Handle + * @param OffsetCalibrationMode Offset Calibration Mode valid values are: + * @li VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * @li VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * @li VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode); + +/** + * @brief Define the mode to be used for the offset correction + * + * Define the mode to be used for the offset correction. + * + * @param Dev Device Handle + * @param OffsetCorrectionMode Offset Correction Mode valid values are: + * @li VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode); + + +/** + * @brief Perform Offset Calibration + * + * @details Perform a Offset calibration of the Device. + * This function will launch a ranging measurement, if interrupts are + * enabled interrupts will be done. + * This function will program a new value for the Offset calibration value + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * @param CalReflectancePercent Calibration Target reflectance @ 940nm + * in percentage. + * + * @return VL53L1_ERROR_NONE + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, + FixPoint1616_t CalReflectancePercent); + +/** + * @brief Perform Offset simple Calibration + * + * @details Perform a very simple offset calibration of the Device. + * This function will launch few ranging measurements and computes offset + * calibration. The preset mode and the distance mode MUST be set by the + * application before to call this function. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * + * @return VL53L1_ERROR_NONE + * @return VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL the calibration failed by + * lack of valid measurements + * @return VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH means that the target + * distance combined to the number of loops performed in the calibration lead to + * an internal overflow. Try to reduce the distance of the target (140 mm) + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter); + +/** + * @brief Sets the Calibration Data. + * + * @par Function Description + * This function set all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData Pointer to Calibration data to be set. + * @return VL53L1_ERROR_NONE Success + * @return VL53L1_ERROR_INVALID_PARAMS pCalibrationData points to an older + * version of the inner structure. Need for support to convert its content. + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Gets the Calibration Data. + * + * @par Function Description + * This function get all the Calibration Data issued from the functions + * @a VL53L1_PerformRefSpadManagement(), @a VL53L1_PerformXTalkCalibration, + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pCalibrationData pointer where to store Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData); + +/** + * @brief Sets the Zone Calibration Data. + * + * @par Function Description + * This function set all the Zone nCalibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() in multi zone + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData Pointer to Zone Calibration data to be + * set. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); + +/** + * @brief Gets the Zone Calibration Data. + * + * @par Function Description + * This function get all the Zone Calibration Data issued from the functions + * @a VL53L1_PerformOffsetCalibration() + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param *pZoneCalibrationData pointer where to store Zone Calibration + * data. + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData); +/** + * @brief Gets the optical center. + * + * @par Function Description + * This function get the optical center issued from the nvm set at FTM stage + * expressed in the same coordinate system as the ROI are + * + * @note This function doesn't Accesses the device + * + * @param Dev Device Handle + * @param pOpticalCenterX pointer to the X position of center + * in 16.16 fix point + * @param pOpticalCenterY pointer to the Y position of center + * in 16.16 fix point + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY); + +/** @} VL53L1_Calibration_group */ + +/** @defgroup VL53L1_Thresholds_group VL53L1 IRQ Triggered events Functions + * @brief Functions used to configure interrupt to be triggered only when + * a measurement satisfies some thresholds parameters + * @{ + */ + +/** + * @brief Configure the interrupt config, from the given structure + * + * @param[in] Dev : Device Handle + * @param[in] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + +/** + * @brief Retrieves the interrupt config structure currently programmed + * into the API + * + * @param[in] Dev : Device Handle + * @param[out] pConfig : pointer to configuration structure + */ + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig); + + +/** @} VL53L1_Thresholds_group */ + + +/** @} VL53L1_cut11_group */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_API_H_ */ diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_api_calibration.h b/drivers/oneplus/vl53L1/inc/vl53l1_api_calibration.h new file mode 100755 index 0000000000000000000000000000000000000000..01c9aeb2b8a2c7be10c0b39282554183c43cefa1 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_api_calibration.h @@ -0,0 +1,596 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_CALIBRATION_H_ +#define _VL53L1_API_CALIBRATION_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_ref_spad_char(VL53L1_DEV Dev, + VL53L1_Error * pcal_status); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode); + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pxtalk_results, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status); + + + + + + + + + + + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_api_core.h b/drivers/oneplus/vl53L1/inc/vl53l1_api_core.h new file mode 100755 index 0000000000000000000000000000000000000000..eb3122cb05169194d2ec6e9322c0d0e0f5e94d3c --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_api_core.h @@ -0,0 +1,1941 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_CORE_H_ +#define _VL53L1_API_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pversion); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us); + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level); + + + + + + + + + + + + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_result_level, + VL53L1_range_results_t *prange_results); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode); + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *phist_data); + + + + + + + + + + + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults); + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg); + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ); + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf); + + + + + + + + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode); + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cor_mode); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order); + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_api_debug.h b/drivers/oneplus/vl53L1/inc/vl53l1_api_debug.h new file mode 100755 index 0000000000000000000000000000000000000000..46239a784864b141e57223661fc7bcf8a5bcb791 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_api_debug.h @@ -0,0 +1,756 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_DEBUG_H_ +#define _VL53L1_API_DEBUG_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_nvm_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata); + +#ifdef VL53L1_LOG_ENABLE + + + + + + + + + + + + +void VL53L1_signed_fixed_point_sprintf( + int32_t fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer); + + + + + + + + + + + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags); + + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_api_preset_modes.h b/drivers/oneplus/vl53L1/inc/vl53l1_api_preset_modes.h new file mode 100755 index 0000000000000000000000000000000000000000..e5e166aa221460da71db144c798f6efafe7ebfdc --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_api_preset_modes.h @@ -0,0 +1,1637 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_API_PRESET_MODES_H_ +#define _VL53L1_API_PRESET_MODES_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata); + + + + + + + + + + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata); + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata); + + + + + + + + + + + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + + + + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic); + + + + + + + + + + + + + + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_api_strings.h b/drivers/oneplus/vl53L1/inc/vl53l1_api_strings.h new file mode 100755 index 0000000000000000000000000000000000000000..051fcb2b000cf8868e6dd3ec5e1940024a2a6a06 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_api_strings.h @@ -0,0 +1,210 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_api_strings.h + * @brief VL53L1 API function declarations for decoding error codes to a + * text strings + */ + + +#ifndef VL53L1_API_STRINGS_H_ +#define VL53L1_API_STRINGS_H_ + +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * @brief Generates a string for the input device range status code + * + * @param[in] RangeStatus : Device Range AStatus Code + * @param[out] pRangeStatusString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Generates an error string for the input PAL error code + * + * @param[in] PalErrorCode : PAL Error Code + * @param[out] pPalErrorString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + +/** + * @brief Generates a string for the input PAL State code + * + * @param[in] PalStateCode : PAL State Code + * @param[out] pPalStateString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString); + + +/** + * @brief Generates a string for the sequence step Id + * + * @param[in] SequenceStepId : Sequence Step Id + * @param[out] pSequenceStepsString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString); + +/** + * @brief Generates a string for the limit check Id + * + * @param[in] LimitCheckId : Limit check Id + * @param[out] pLimitCheckString : pointer to character buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString); + +#ifndef VL53L1_USE_EMPTY_STRING + #define VL53L1_STRING_DEVICE_INFO_NAME0 "VL53L1 cut1.0" + #define VL53L1_STRING_DEVICE_INFO_NAME1 "VL53L1 cut1.1" + #define VL53L1_STRING_DEVICE_INFO_TYPE "VL53L1" + + /* Range Status */ + #define VL53L1_STRING_RANGESTATUS_NONE "No Update" + #define VL53L1_STRING_RANGESTATUS_RANGEVALID "Range Valid" + #define VL53L1_STRING_RANGESTATUS_SIGMA "Sigma Fail" + #define VL53L1_STRING_RANGESTATUS_SIGNAL "Signal Fail" + #define VL53L1_STRING_RANGESTATUS_MINRANGE "Min Range Fail" + #define VL53L1_STRING_RANGESTATUS_PHASE "Phase Fail" + #define VL53L1_STRING_RANGESTATUS_HW "Hardware Fail" + + + /* Range Status */ + #define VL53L1_STRING_STATE_POWERDOWN "POWERDOWN State" + #define VL53L1_STRING_STATE_WAIT_STATICINIT \ + "Wait for staticinit State" + #define VL53L1_STRING_STATE_STANDBY "STANDBY State" + #define VL53L1_STRING_STATE_IDLE "IDLE State" + #define VL53L1_STRING_STATE_RUNNING "RUNNING State" + #define VL53L1_STRING_STATE_RESET "RESET State" + #define VL53L1_STRING_STATE_UNKNOWN "UNKNOWN State" + #define VL53L1_STRING_STATE_ERROR "ERROR State" + + + + /* Check Enable */ + #define VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \ + "SIGMA FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \ + "SIGNAL RATE FINAL RANGE" + #define VL53L1_STRING_CHECKENABLE_SIGNAL_MIN_CLIP \ + "SIGNAL MIN CLIP" + #define VL53L1_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \ + "RANGE IGNORE THRESHOLD" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_HIGH \ + "RANGE PHASE HIGH" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_LOW \ + "RANGE PHASE LOW" + #define VL53L1_STRING_CHECKENABLE_RANGE_PHASE_CONSISTENCY \ + "RANGE PHASE CONSISTENCY" + + /* Sequence Step */ + #define VL53L1_STRING_SEQUENCESTEP_VHV "VHV" + #define VL53L1_STRING_SEQUENCESTEP_PHASECAL "PHASE CAL" + #define VL53L1_STRING_SEQUENCESTEP_REFPHASE "REF PHASE" + #define VL53L1_STRING_SEQUENCESTEP_DSS1 "DSS1" + #define VL53L1_STRING_SEQUENCESTEP_DSS2 "DSS2" + #define VL53L1_STRING_SEQUENCESTEP_MM1 "MM1" + #define VL53L1_STRING_SEQUENCESTEP_MM2 "MM2" + #define VL53L1_STRING_SEQUENCESTEP_RANGE "RANGE" +#endif /* VL53L1_USE_EMPTY_STRING */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_core.h b/drivers/oneplus/vl53L1/inc/vl53l1_core.h new file mode 100755 index 0000000000000000000000000000000000000000..fa6dc8925a558371e0132f3aa2ad4854310dfe73 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_core.h @@ -0,0 +1,1919 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_CORE_H_ +#define _VL53L1_CORE_H_ + +#include "vl53l1_platform.h" +#include "vl53l1_core_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + +void VL53L1_init_version( + VL53L1_DEV Dev); + + + + + + + + + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState ll_state); + + + + + + + + + + + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev); + + + + + + + + + + + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev); + + + + + + + + + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer); + + + + + + + + + + + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata); + + + + + + + + + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata); + + + + + + + + + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata); + + + + + + + + + + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata); + + + + + + + + + + + + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset); + + + + + + + + + + + + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer); + + + + + + + + + + + + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009); + + + + + + + + + + + + + + + + + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult); + + + + + + + + + + + + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + + + + + + + + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us); + + + + + + + + + + + + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us); + + + + + + + + + + + + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us); + + + + + + + + + + + +uint16_t VL53L1_encode_timeout( + uint32_t timeout_mclks); + + + + + + + + + + + + +uint32_t VL53L1_decode_timeout( + uint16_t encoded_timeout); + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming); + + + + + + + + + + + + +uint8_t VL53L1_encode_vcsel_period( + uint8_t VL53L1_p_031); + + + + + + + + + + + + + + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes); + + + + + + + + + + + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata); + + + + + + + + + + + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm); + + + + + + + + + + + + + + + + + + + + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data); + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape); + + + + + + + + + + + + + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta); + + + + + + + + + + + + + + + + + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask); + + + + + + + + + + + + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number); + + + + + + + + + + + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight); + + + + + + + + + + + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size); + + + + + + + + + + + + + + + + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur); + + + + + + + + + + + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col); + + + + + + + + + + + + + + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads); + + + + + + + + + + + + + + + + + + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads); + + + + + + + + + + + + + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val + ); + + + + + + + + + + + + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev); + + + + + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist + ); + + + + + + + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low); + + + + + + + + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates); + + + + + + + + + + + + + + + + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ); + + + + + + + + + + + + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev); + + + + + + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_core_support.h b/drivers/oneplus/vl53L1/inc/vl53l1_core_support.h new file mode 100755 index 0000000000000000000000000000000000000000..0b117491d6ce54ecd46d0e7ee299f021bc0b6021 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_core_support.h @@ -0,0 +1,414 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_CORE_SUPPORT_H_ +#define _VL53L1_CORE_SUPPORT_H_ + +#include "vl53l1_types.h" +#include "vl53l1_hist_structs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + + + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t periods_elapsed_mclks); + + + + + + + + + + + + + + + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration); + + + + + + + + + + + + + +uint32_t VL53L1_isqrt( + uint32_t num); + + + + + + + + + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + + + + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency); + + + + + + + + + + + + + + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us); + + + + + + + + + + + + + + + + + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value); + + + + + + + + + + + + + + + + + + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm); + + + + + + + + + + + + +uint8_t VL53L1_decode_vcsel_period( + uint8_t vcsel_period_reg); + + + + + + + + + + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist); + + + + + + + + + + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol); + + + + + + + + + + + + + + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata); + + + + + + + + + + + + + + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_def.h b/drivers/oneplus/vl53L1/inc/vl53l1_def.h new file mode 100755 index 0000000000000000000000000000000000000000..abdd4a83ca8a537240d579bb573ff0c121a26fca --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_def.h @@ -0,0 +1,848 @@ +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_def.h + * + * @brief Type definitions for VL53L1 API. + * + */ + + +#ifndef _VL53L1_DEF_H_ +#define _VL53L1_DEF_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup VL53L1_globaldefine_group VL53L1 Defines + * @brief VL53L1 Defines + * @{ + */ + + +/** VL53L1 IMPLEMENTATION major version */ +#define VL53L1_IMPLEMENTATION_VER_MAJOR 6 +/** VL53L1 IMPLEMENTATION minor version */ +#define VL53L1_IMPLEMENTATION_VER_MINOR 0 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_SUB 1 +/** VL53L1 IMPLEMENTATION sub version */ +#define VL53L1_IMPLEMENTATION_VER_REVISION 2003 + +/**************************************** + * PRIVATE define do not edit + ****************************************/ + +/** @brief Defines the parameters of the Get Version Functions + */ +typedef struct { + uint32_t revision; /*!< revision number */ + uint8_t major; /*!< major number */ + uint8_t minor; /*!< minor number */ + uint8_t build; /*!< build number */ +} VL53L1_Version_t; + + +#define VL53L1_DEVINFO_STRLEN 32 + +/** @brief Defines the parameters of the Get Device Info Functions + */ +typedef struct { + char Name[VL53L1_DEVINFO_STRLEN]; + /*!< Name of the Device e.g. Left_Distance */ + char Type[VL53L1_DEVINFO_STRLEN]; + /*!< Type of the Device e.g VL53L1 */ + char ProductId[VL53L1_DEVINFO_STRLEN]; + /*!< Product Identifier String + * @warning Not yet implemented + */ + uint8_t ProductType; + /*!< Product Type, VL53L1 = 1, VL53L1 = 2*/ + uint8_t ProductRevisionMajor; + /*!< Product revision major */ + uint8_t ProductRevisionMinor; + /*!< Product revision minor */ +} VL53L1_DeviceInfo_t; + + + +/** @defgroup VL53L1_define_PresetModes_group Defines Preset modes + * Defines all possible preset modes for the device + * @{ + */ +typedef uint8_t VL53L1_PresetModes; + +#define VL53L1_PRESETMODE_RANGING ((VL53L1_PresetModes) 1) +#define VL53L1_PRESETMODE_MULTIZONES_SCANNING ((VL53L1_PresetModes) 2) +#define VL53L1_PRESETMODE_AUTONOMOUS ((VL53L1_PresetModes) 3) +#define VL53L1_PRESETMODE_LITE_RANGING ((VL53L1_PresetModes) 4) +#define VL53L1_PRESETMODE_OLT ((VL53L1_PresetModes) 7) +#define VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS ((VL53L1_PresetModes) 8) +#define VL53L1_PRESETMODE_PROXY_RANGING_MODE ((VL53L1_PresetModes) 9) + +/** default preset ranging mode */ +//songyt test replace VL53L1_PRESETMODE_RANGING +#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + + /* ... Modes to be added depending on device */ +/** @} VL53L1_define_PresetModes_group */ + + +/** @defgroup VL53L1_define_DistanceModes_group Defines Distance modes + * Defines all possible Distance modes for the device + * @{ + */ +typedef uint8_t VL53L1_DistanceModes; + +#define VL53L1_DISTANCEMODE_SHORT ((VL53L1_DistanceModes) 1) +#define VL53L1_DISTANCEMODE_MEDIUM ((VL53L1_DistanceModes) 2) +#define VL53L1_DISTANCEMODE_LONG ((VL53L1_DistanceModes) 3) +/** @} VL53L1_define_DistanceModes_group */ + +/** @defgroup VL53L1_define_OutputModes_group Defines Output modes + * Defines all possible Output modes for the device + * @{ + */ +typedef uint8_t VL53L1_OutputModes; + +#define VL53L1_OUTPUTMODE_NEAREST ((VL53L1_OutputModes) 1) +#define VL53L1_OUTPUTMODE_STRONGEST ((VL53L1_OutputModes) 2) + +/** @} VL53L1_define_OutputModes_group */ + +/** @defgroup VL53L1_define_XtalkCal_group Defines Xtalk Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_XtalkCalibrationModes; + +#define VL53L1_XTALKCALIBRATIONMODE_NO_TARGET \ + ((VL53L1_OffsetCalibrationModes) 0) +/*!< To perform Xtalk calibration with no target below 80 cm */ +#define VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET \ + ((VL53L1_OffsetCalibrationModes) 1) +/*!< To perform Xtalk calibration with one target */ +#define VL53L1_XTALKCALIBRATIONMODE_FULL_ROI \ + ((VL53L1_OffsetCalibrationModes) 2) +/*!< To perform Xtalk calibration based on histogram with full ROI */ + +/** @} VL53L1_define_XtalkCal_group */ + +/** @defgroup VL53L1_define_OffsetCal_group Defines Offset Calibration modes + * Defines all possible Offset Calibration modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCalibrationModes; + +#define VL53L1_OFFSETCALIBRATIONMODE_STANDARD \ + ((VL53L1_OffsetCalibrationModes) 1) +#define VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY \ + ((VL53L1_OffsetCalibrationModes) 2) +#define VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE \ + ((VL53L1_OffsetCalibrationModes) 3) + +/** @} VL53L1_define_OffsetCal_group */ + +/** @defgroup VL53L1_define_DeviceDmaxModes_group Defines Dmax source modes + * Defines all possible sources for Dmax calibration for the device + * @{ + */ +typedef uint8_t VL53L1_DeviceDmaxModes; + +#define VL53L1_DMAXMODE_FMT_CAL_DATA ((VL53L1_DeviceDmaxModes) 1) +#define VL53L1_DMAXMODE_CUSTCAL_DATA ((VL53L1_DeviceDmaxModes) 2) +#define VL53L1_DMAXMODE_PER_ZONE_CAL_DATA ((VL53L1_DeviceDmaxModes) 3) + +/** @} VL53L1_define_DeviceDmaxModes_group */ + +/** @defgroup VL53L1_define_OffsetCorrectionModesBD_group + * Device Offset Correction Mode + * + * @brief Defines all possible offset correction modes for the device + * @{ + */ +typedef uint8_t VL53L1_OffsetCorrectionModes; + +#define VL53L1_OFFSETCORRECTIONMODE_STANDARD ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE_PERZONE ((VL53L1_OffsetCorrectionMode) 2) + +/** @} VL53L1_define_OffsetCorrectionModesBD_group */ + +/** @defgroup VL53L1_define_RoiStatus_group Defines Roi Status + * Defines the read status mode + * @{ + */ +typedef uint8_t VL53L1_RoiStatus; + +#define VL53L1_ROISTATUS_NOT_VALID ((VL53L1_RoiStatus) 0) +#define VL53L1_ROISTATUS_VALID_NOT_LAST ((VL53L1_RoiStatus) 1) +#define VL53L1_ROISTATUS_VALID_LAST ((VL53L1_RoiStatus) 2) +/** @} VL53L1_define_RoiStatus_group */ + + +/** @defgroup VL53L1_CheckEnable_group Check Enable list + * @brief Check Enable code + * + * Define used to specify the LimitCheckId. + * Use @a VL53L1_GetLimitCheckInfo() to get the string. + * @{ + */ + +#define VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE 0 +#define VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1 + +#define VL53L1_CHECKENABLE_NUMBER_OF_CHECKS 2 + +/** @} end of VL53L1_CheckEnable_group */ + + +/** @defgroup VL53L1_ThresholdMode_gropup Detection Functionality + * @brief Defines the different functionalities for the detection feature + * @{ + */ +typedef uint8_t VL53L1_ThresholdMode; + +#define VL53L1_THRESHOLD_CROSSED_LOW \ + ((VL53L1_ThresholdMode) 0) + /*!< Trigger interrupt if value < thresh_low */ +#define VL53L1_THRESHOLD_CROSSED_HIGH \ + ((VL53L1_ThresholdMode) 1) + /*!< Trigger interrupt if value > thresh_high */ +#define VL53L1_THRESHOLD_OUT_OF_WINDOW \ + ((VL53L1_ThresholdMode) 2) + /*!< Trigger interrupt if value < thresh_low OR value > thresh_high */ +#define VL53L1_THRESHOLD_IN_WINDOW \ + ((VL53L1_ThresholdMode) 3) + /*!< Trigger interrupt if value > thresh_low AND value < thresh_high */ + +/** @} end of VL53L1_ThresholdMode_gropup */ + +/** @brief Defines parameters for Distance detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + uint16_t High; /*!< Distance threshold high limit in mm */ + uint16_t Low; /*!< Distance threshold low limit in mm */ +} VL53L1_DistanceThreshold_t; + +/** @brief Defines parameters for Signal rate detection Thresholds configuration + */ +typedef struct { + VL53L1_ThresholdMode CrossMode; + FixPoint1616_t High; /*!< Signal rate threshold high limit */ + FixPoint1616_t Low; /*!< Signal rate threshold low limit */ +} VL53L1_RateThreshold_t; + +/** @defgroup VL53L1_DetectionMode_group Gpio Functionality + * @brief Defines conditions leading to device's IT on GPIO + * @{ + */ +typedef uint8_t VL53L1_DetectionMode; + +#define VL53L1_DETECTION_NORMAL_RUN \ + ((VL53L1_DetectionMode) 0) + /*!< Trigger interrupt on new measurement regardless of threshold + * just like after a VL53L1_SetPresetMode() call + */ +#define VL53L1_DETECTION_DISTANCE_ONLY \ + ((VL53L1_DetectionMode) 1) + /*!< Trigger interrupt if "threshold event" occurs on distance */ +#define VL53L1_DETECTION_RATE_ONLY \ + ((VL53L1_DetectionMode) 2) + /*!< Trigger interrupt if "threshold event" occurs on signal rate */ +#define VL53L1_DETECTION_DISTANCE_AND_RATE \ + ((VL53L1_DetectionMode) 3) + /*!< Trigger interrupt if "threshold event" occurs on distance AND rate + */ +#define VL53L1_DETECTION_DISTANCE_OR_RATE \ + ((VL53L1_DetectionMode) 4) + /*!< Trigger interrupt if "threshold event" occurs on distance OR rate + */ + +/** @} end of VL53L1_DetectionMode_group */ + +/** @brief Defines parameters for User/object Detection configuration + */ +typedef struct { + VL53L1_DetectionMode DetectionMode; /*!< See #VL53L1_DetectionMode*/ + uint8_t IntrNoTarget; /*!< 1 to trigger IT in case of no target found */ + VL53L1_DistanceThreshold_t Distance; /*!< limits in mm */ + VL53L1_RateThreshold_t Rate;/*!< limits in FixPoint1616_t */ +} VL53L1_DetectionConfig_t; + + +/** @brief Defines all parameters for the device + */ +typedef struct { + VL53L1_PresetModes PresetMode; + /*!< Defines the operating mode to be used for the next measure */ + VL53L1_OutputModes OutputMode; + /*!< Defines the Output mode to be used for the next measure */ + VL53L1_DistanceModes DistanceMode; + /*!< Defines the operating mode to be used for the next measure */ + uint32_t MeasurementTimingBudgetMicroSeconds; + /*!< Defines the allowed total time for a single measurement */ + uint8_t LimitChecksEnable[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check enable for this device. */ + uint8_t LimitChecksStatus[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Status of the check linked to last + * measurement. + */ + FixPoint1616_t LimitChecksValue[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check value for this device */ + FixPoint1616_t LimitChecksCurrent[VL53L1_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array stores all the Limit Check current value from latest + * ranging + */ +} VL53L1_DeviceParameters_t; + + +/** @defgroup VL53L1_define_State_group Defines the current status of the device + * Defines the current status of the device + * @{ + */ + +typedef uint8_t VL53L1_State; + +#define VL53L1_STATE_POWERDOWN ((VL53L1_State) 0) + /*!< Device is in HW reset */ +#define VL53L1_STATE_WAIT_STATICINIT ((VL53L1_State) 1) + /*!< Device is initialized and wait for static initialization */ +#define VL53L1_STATE_STANDBY ((VL53L1_State) 2) + /*!< Device is in Low power Standby mode */ +#define VL53L1_STATE_IDLE ((VL53L1_State) 3) + /*!< Device has been initialized and ready to do measurements */ +#define VL53L1_STATE_RUNNING ((VL53L1_State) 4) + /*!< Device is performing measurement */ +#define VL53L1_STATE_RESET ((VL53L1_State) 5) + /*!< Soft reset has been run on Device */ +#define VL53L1_STATE_UNKNOWN ((VL53L1_State) 98) + /*!< Device is in unknown state and need to be rebooted */ +#define VL53L1_STATE_ERROR ((VL53L1_State) 99) + /*!< Device is in error state and need to be rebooted */ + +/** @} VL53L1_define_State_group */ + +/** @defgroup VL53L1_define_Smudge_Mode_group Defines smudge correction modes + * Defines the smudge correction modes + * @{ + */ + +typedef uint8_t VL53L1_SmudgeCorrectionModes; + +#define VL53L1_SMUDGE_CORRECTION_NONE ((VL53L1_SmudgeCorrectionModes) 0) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_CONTINUOUS ((VL53L1_SmudgeCorrectionModes) 1) + /*!< Smudge correction is applied continously accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_SINGLE ((VL53L1_SmudgeCorrectionModes) 2) + /*!< Smudge correction is applied only once accross the rangings */ +#define VL53L1_SMUDGE_CORRECTION_DEBUG ((VL53L1_SmudgeCorrectionModes) 3) + /*!< Smudge detection is applied continously but Xtalk values are not + * updated automatically within the driver + */ + +/** @} VL53L1_define_Smudge_Correction_Mode_group */ + + +/** + * @struct VL53L1_RangingMeasurementData_t + * @brief Single Range measurement data. + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_RangingMeasurementData_t; + +/** + * @struct VL53L1_TargetRangeData_t + * @brief One Range measurement data for each target. + */ +typedef struct { + uint8_t RangeQualityLevel; + /*!< indicate a quality level in percentage from 0 to 100 + * @warning Not yet implemented + */ + + int16_t RangeMaxMilliMeter; + /*!< Tells what is the maximum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + int16_t RangeMinMilliMeter; + /*!< Tells what is the minimum detection distance of the object + * in current setup and environment conditions (Filled when + * applicable) + */ + + FixPoint1616_t SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of target + * reflectance. + */ + + FixPoint1616_t AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point + * value, which is effectively a measure of the ambien + * t light. + */ + + FixPoint1616_t SigmaMilliMeter; + /*!< Return the Sigma value in millimeter */ + + int16_t RangeMilliMeter; + /*!< range distance in millimeter. This should be between + * RangeMinMilliMeter and RangeMaxMilliMeter + */ + + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a + * RangeMilliMeter + RangeFractionalPart/256. + * @warning Not yet implemented + */ + + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device + * dependent. Value = 0 means value is valid. + */ +} VL53L1_TargetRangeData_t; +/** + * @struct VL53L1_MultiRangingData_t + * @brief Structure for storing the set of range results for a single ROI + * + */ +typedef struct { + uint32_t TimeStamp; + /*!< 32-bit time stamp. + * @warning Not yet implemented + */ + + uint8_t StreamCount; + /*!< 8-bit Stream Count. */ + + uint8_t RoiNumber; + /*!< Denotes on which ROI the range data is related to. */ + uint8_t NumberOfObjectsFound; + /*!< Indicate the number of objects found in the current ROI. + * This is used to know how many ranging data should be get. + * NumberOfObjectsFound is in the range 0 to + * VL53L1_MAX_RANGE_RESULTS. + */ + VL53L1_RoiStatus RoiStatus; + /*!< Indicate if the data read is valid or not or if this is + * the last valid data in the ROI. + */ + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + /*!< Range data each target distance */ + uint8_t HasXtalkValueChanged; + /*!< set to 1 if a new Xtalk value has been computed whilst + * smudge correction mode enable by with + * VL53L1_SmudgeCorrectionEnable() function is either + * VL53L1_SMUDGE_CORRECTION_CONTINUOUS or + * VL53L1_SMUDGE_CORRECTION_SINGLE. + */ + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. + * To obtain Real value it should be divided by 256 + */ + int16_t DmaxMilliMeter; + /*!< range Dmax distance in millimeter. + */ + VL53L1_DistanceModes RecommendedDistanceMode; + /*!< suggestion for a better distance mode choice to improve + * range accuracy. + */ +} VL53L1_MultiRangingData_t; + + +/** @brief Defines User Zone(ROI) parameters + * + */ +typedef struct { + + uint8_t TopLeftX; /*!< Top Left x coordinate: 0-15 range */ + uint8_t TopLeftY; /*!< Top Left y coordinate: 0-15 range */ + uint8_t BotRightX; /*!< Bot Right x coordinate: 0-15 range */ + uint8_t BotRightY; /*!< Bot Right y coordinate: 0-15 range */ + +} VL53L1_UserRoi_t; + + +/** @brief Defines ROI configuration parameters + * + * Support up a max of 16 zones, Each Zone has the same size + * + */ +typedef struct { + + uint8_t NumberOfRoi; /*!< Number of Rois defined*/ + + VL53L1_UserRoi_t UserRois[VL53L1_MAX_USER_ZONES]; + /*!< List of Rois */ + +} VL53L1_RoiConfig_t; + +/** + * @struct VL53L1_CustomerNvmManaged_t + * + */ + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + uint8_t global_config__spad_enables_ref_1; + uint8_t global_config__spad_enables_ref_2; + uint8_t global_config__spad_enables_ref_3; + uint8_t global_config__spad_enables_ref_4; + uint8_t global_config__spad_enables_ref_5; + uint8_t global_config__ref_en_start_select; + uint8_t ref_spad_man__num_requested_ref_spads; + uint8_t ref_spad_man__ref_location; + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + uint16_t ref_spad_char__total_rate_target_mcps; + int16_t algo__part_to_part_range_offset_mm; + int16_t mm_config__inner_offset_mm; + int16_t mm_config__outer_offset_mm; +} VL53L1_CustomerNvmManaged_t; + +/** + * @struct VL53L1_CalibrationData_t + * @brief Structure for storing the Calibration Data + * + */ + +typedef struct { + + uint32_t struct_version; + VL53L1_CustomerNvmManaged_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + +} VL53L1_CalibrationData_t; + +#define VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION 0x10 +/** VL53L1 additional Calibration Data struct version final struct version + * is given by adding it to VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + */ + +#define VL53L1_CALIBRATION_DATA_STRUCT_VERSION \ + (VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION + \ + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION) +/* VL53L1 Calibration Data struct version */ + +/** + * @struct VL53L1_AdditionalData_t + * @brief Structure for storing the Additional Data + * + */ +typedef VL53L1_additional_data_t VL53L1_AdditionalData_t; + +/** + * @struct VL53L1_ZoneCalibrationData_t + * @brief Structure for storing the Zone Calibration Data + * + */ +typedef VL53L1_zone_calibration_results_t VL53L1_ZoneCalibrationData_t; + +/** @defgroup VL53L1_define_SequenceStepId_group Defines the SequenceStep + * Defines the the sequence steps performed during ranging.. + * @{ + */ +typedef uint8_t VL53L1_SequenceStepId; + +#define VL53L1_SEQUENCESTEP_VHV ((VL53L1_SequenceStepId) 0) +/*!>12)&0xFFFF) +#define VL53L1_FIXPOINT44TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<12) + +#define VL53L1_FIXPOINT1616TOFIXPOINT72(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT72TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT97(Value) \ + (uint16_t)((Value>>9)&0xFFFF) +#define VL53L1_FIXPOINT97TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<9) + +#define VL53L1_FIXPOINT1616TOFIXPOINT88(Value) \ + (uint16_t)((Value>>8)&0xFFFF) +#define VL53L1_FIXPOINT88TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT412(Value) \ + (uint16_t)((Value>>4)&0xFFFF) +#define VL53L1_FIXPOINT412TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<4) + +#define VL53L1_FIXPOINT1616TOFIXPOINT313(Value) \ + (uint16_t)((Value>>3)&0xFFFF) +#define VL53L1_FIXPOINT313TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<3) + +#define VL53L1_FIXPOINT1616TOFIXPOINT08(Value) \ + (uint8_t)((Value>>8)&0x00FF) +#define VL53L1_FIXPOINT08TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<8) + +#define VL53L1_FIXPOINT1616TOFIXPOINT53(Value) \ + (uint8_t)((Value>>13)&0x00FF) +#define VL53L1_FIXPOINT53TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<13) + +#define VL53L1_FIXPOINT1616TOFIXPOINT102(Value) \ + (uint16_t)((Value>>14)&0x0FFF) +#define VL53L1_FIXPOINT102TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT142(Value) \ + (uint16_t)((Value>>14)&0xFFFF) +#define VL53L1_FIXPOINT142TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<14) + +#define VL53L1_FIXPOINT1616TOFIXPOINT160(Value) \ + (uint16_t)((Value>>16)&0xFFFF) +#define VL53L1_FIXPOINT160TOFIXPOINT1616(Value) \ + (FixPoint1616_t)((uint32_t)Value<<16) + +#define VL53L1_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \ + (uint16_t)lsb) + +#ifndef SUPPRESS_UNUSED_WARNING +#define SUPPRESS_UNUSED_WARNING(x) ((void) (x)) +#endif + +/** @} VL53L1_define_GeneralMacro_group */ + +/** @} VL53L1_globaldefine_group */ + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_DEF_H_ */ diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_dmax_structs.h b/drivers/oneplus/vl53L1/inc/vl53l1_dmax_structs.h new file mode 100755 index 0000000000000000000000000000000000000000..5b4d9b7f20e369f90058189d98e8d586f32655c2 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_dmax_structs.h @@ -0,0 +1,210 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_DMAX_STRUCTS_H_ +#define _VL53L1_DMAX_STRUCTS_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define VL53L1_MAX_AMBIENT_DMAX_VALUES 5 + + + + + + + + + + + + +typedef struct { + + + + + uint16_t ref__actual_effective_spads; + + + uint16_t ref__peak_signal_count_rate_mcps; + + + uint16_t ref__distance_mm; + + + uint16_t ref_reflectance_pc; + + + + + + + uint16_t coverglass_transmission; + + + +} VL53L1_dmax_calibration_data_t; + + + + + + + + + + +typedef struct { + + + + + uint8_t signal_thresh_sigma; + + + uint8_t ambient_thresh_sigma; + + + int32_t min_ambient_thresh_events; + + + int32_t signal_total_events_limit; + + + + uint16_t target_reflectance_for_dmax_calc[ + VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + + uint16_t max_effective_spads; + + + + + + + uint16_t dss_config__target_total_rate_mcps; + + + uint8_t dss_config__aperture_attenuation; + + + +} VL53L1_hist_gen3_dmax_config_t; + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_error_codes.h b/drivers/oneplus/vl53L1/inc/vl53l1_error_codes.h new file mode 100755 index 0000000000000000000000000000000000000000..1bf727eaf5609c469983f387de6fcadf923437e2 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_error_codes.h @@ -0,0 +1,273 @@ +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +/** + * @file vl53l1_error_codes.h + * + * @brief Error Code definitions for VL53L1 API. + * + */ + +#ifndef _VL53L1_ERROR_CODES_H_ +#define _VL53L1_ERROR_CODES_H_ + +#include "vl53l1_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + **************************************** + * PRIVATE define do not edit + *************************************** + */ + +/* + * @defgroup VL53L1_define_Error_group Error and Warning code returned by API + * The following DEFINE are used to identify the PAL ERROR + * @{ + */ + +typedef int8_t VL53L1_Error; + +#define VL53L1_ERROR_NONE ((VL53L1_Error) 0) +#define VL53L1_ERROR_CALIBRATION_WARNING ((VL53L1_Error) - 1) + /*!< Warning invalid calibration data may be in used + * \a VL53L1_InitData() + * \a VL53L1_GetOffsetCalibrationData + * \a VL53L1_SetOffsetCalibrationData + */ +#define VL53L1_ERROR_MIN_CLIPPED ((VL53L1_Error) - 2) + /*!< Warning parameter passed was clipped to min before to be applied */ + +#define VL53L1_ERROR_UNDEFINED ((VL53L1_Error) - 3) + /*!< Unqualified error */ +#define VL53L1_ERROR_INVALID_PARAMS ((VL53L1_Error) - 4) + /*!< Parameter passed is invalid or out of range */ +#define VL53L1_ERROR_NOT_SUPPORTED ((VL53L1_Error) - 5) + /*!< Function is not supported in current mode or configuration */ +#define VL53L1_ERROR_RANGE_ERROR ((VL53L1_Error) - 6) + /*!< Device report a ranging error interrupt status */ +#define VL53L1_ERROR_TIME_OUT ((VL53L1_Error) - 7) + /*!< Aborted due to time out */ +#define VL53L1_ERROR_MODE_NOT_SUPPORTED ((VL53L1_Error) - 8) + /*!< Asked mode is not supported by the device */ +#define VL53L1_ERROR_BUFFER_TOO_SMALL ((VL53L1_Error) - 9) + /*!< ... */ +#define VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL ((VL53L1_Error) - 10) + /*!< Supplied buffer is larger than I2C supports */ +#define VL53L1_ERROR_GPIO_NOT_EXISTING ((VL53L1_Error) - 11) + /*!< User tried to setup a non-existing GPIO pin */ +#define VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((VL53L1_Error) - 12) + /*!< unsupported GPIO functionality */ +#define VL53L1_ERROR_CONTROL_INTERFACE ((VL53L1_Error) - 13) + /*!< error reported from IO functions */ +#define VL53L1_ERROR_INVALID_COMMAND ((VL53L1_Error) - 14) + /*!< The command is not allowed in the current device state + * (power down) + */ +#define VL53L1_ERROR_DIVISION_BY_ZERO ((VL53L1_Error) - 15) + /*!< In the function a division by zero occurs */ +#define VL53L1_ERROR_REF_SPAD_INIT ((VL53L1_Error) - 16) + /*!< Error during reference SPAD initialization */ +#define VL53L1_ERROR_GPH_SYNC_CHECK_FAIL ((VL53L1_Error) - 17) + /*!< GPH sync interrupt check fail - API out of sync with device*/ +#define VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 18) + /*!< Stream count check fail - API out of sync with device */ +#define VL53L1_ERROR_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 19) + /*!< GPH ID check fail - API out of sync with device */ +#define VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL ((VL53L1_Error) - 20) + /*!< Zone dynamic config stream count check failed - API out of sync */ +#define VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL ((VL53L1_Error) - 21) + /*!< Zone dynamic config GPH ID check failed - API out of sync */ + +#define VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL ((VL53L1_Error) - 22) + /*!< Thrown when run_xtalk_extraction fn has 0 succesful samples + * when using the full array to sample the xtalk. In this case there is + * not enough information to generate new Xtalk parm info. The function + * will exit and leave the current xtalk parameters unaltered + */ +#define VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL ((VL53L1_Error) - 23) + /*!< Thrown when run_xtalk_extraction fn has found that the + * avg sigma estimate of the full array xtalk sample is > than the + * maximal limit allowed. In this case the xtalk sample is too noisy for + * measurement. The function will exit and leave the current xtalk + * parameters unaltered. + */ + + +#define VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 24) + /*!< Thrown if there one of stages has no valid offset calibration + * samples. A fatal error calibration not valid + */ +#define VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL ((VL53L1_Error) - 25) + /*!< Thrown if there one of stages has zero effective SPADS + * Traps the case when MM1 SPADs is zero. + * A fatal error calibration not valid + */ +#define VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL ((VL53L1_Error) - 26) + /*!< Thrown if then some of the zones have no valid samples + * A fatal error calibration not valid + */ + +#define VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH ((VL53L1_Error) - 27) + /*!< Thrown if the tuning file key table version does not match with + * expected value. The driver expects the key table version to match + * the compiled default version number in the define + * #VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT + */ + +#define VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS ((VL53L1_Error) - 28) + /*!< Thrown if there are less than 5 good SPADs are available. */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH ((VL53L1_Error) - 29) + /*!< Thrown if the final reference rate is greater than + * the upper reference rate limit - default is 40 Mcps. + * Implies a minimum Q3 (x10) SPAD (5) selected + */ +#define VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW ((VL53L1_Error) - 30) + /*!< Thrown if the final reference rate is less than + * the lower reference rate limit - default is 10 Mcps. + * Implies maximum Q1 (x1) SPADs selected + */ + + +#define VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES ((VL53L1_Error) - 31) + /*!< Thrown if there is less than the requested number of + * valid samples. + */ +#define VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 32) + /*!< Thrown if the offset calibration range sigma estimate is greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 33) + /*!< Thrown when VL53L1_run_offset_calibration() peak rate is greater + * than that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ +#define VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW ((VL53L1_Error) - 34) + /*!< Thrown when VL53L1_run_offset_calibration() when one of stages + * range has less that 5.0 effective SPADS. This is the recommended + * min value to yield a stable offset + */ + + +#define VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES ((VL53L1_Error) - 35) + /*!< Thrown if one of more of the zones have less than + * the requested number of valid samples + */ +#define VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH ((VL53L1_Error) - 36) + /*!< Thrown if one or more zones have sigma estimate value greater + * than 8.0 mm. This is the recommended min value to yield a stable + * offset measurement + */ +#define VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH ((VL53L1_Error) - 37) + /*!< Thrown if one of more zones have peak rate higher than + * that 50.0Mcps. This is the recommended max rate to avoid + * pile-up influencing the offset measurement + */ + + +#define VL53L1_WARNING_XTALK_MISSING_SAMPLES ((VL53L1_Error) - 38) + /*!< Thrown to notify that some of the xtalk samples did not yield + * valid ranging pulse data while attempting to measure + * the xtalk signal in vl53l1_run_xtalk_extract(). This can signify any + * of the zones are missing samples, for further debug information the + * xtalk_results struct should be referred to. This warning is for + * notification only, xtalk pulse and shape have still been generated + */ +#define VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT ((VL53L1_Error) - 39) + /*!< Thrown to notify that some of teh xtalk samples used for gradient + * generation did not yield valid ranging pulse data while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded no successful samples. + * xtalk_results struct should be referred to for further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ +#define VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT ((VL53L1_Error) - 40) + /*!< Thrown to notify that some of the xtalk samples used for gradient + * generation did not pass the sigma limit check while attempting to + * measure the xtalk signal in vl53l1_run_xtalk_extract(). This can + * signify that any one of the zones 0-3 yielded an avg sigma_mm + * value > the limit. The xtalk_results struct should be referred to for + * further debug info. + * This warning is for notification only, the xtalk pulse and shape + * have still been generated. + */ + +#define VL53L1_ERROR_NOT_IMPLEMENTED ((VL53L1_Error) - 41) + /*!< Tells requested functionality has not been implemented yet or + * not compatible with the device + */ +#define VL53L1_ERROR_PLATFORM_SPECIFIC_START ((VL53L1_Error) - 60) + /*!< Tells the starting code for platform */ +/** @} VL53L1_define_Error_group */ + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL53L1_ERROR_CODES_H_ */ diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_error_exceptions.h b/drivers/oneplus/vl53L1/inc/vl53l1_error_exceptions.h new file mode 100755 index 0000000000000000000000000000000000000000..0b2db2ba0e280d02a49800f34a12854724ce8519 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_error_exceptions.h @@ -0,0 +1,126 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_ERROR_EXCEPTIONS_H_ +#define _VL53L1_ERROR_EXCEPTIONS_H_ + +#define IGNORE_DIVISION_BY_ZERO 0 + +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL 0 +#define IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN 0 +#define IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN 0 + +#define IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH 0 +#define IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW 0 + +#define IGNORE_OFFSET_CAL_MISSING_SAMPLES 0 +#define IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_RATE_TOO_HIGH 0 +#define IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW 0 + +#define IGNORE_ZONE_CAL_MISSING_SAMPLES 0 +#define IGNORE_ZONE_CAL_SIGMA_TOO_HIGH 0 +#define IGNORE_ZONE_CAL_RATE_TOO_HIGH 0 + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_error_strings.h b/drivers/oneplus/vl53L1/inc/vl53l1_error_strings.h new file mode 100755 index 0000000000000000000000000000000000000000..02cba46adb534697db669c3e294ff1133f8fa870 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_error_strings.h @@ -0,0 +1,244 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef VL53L1_ERROR_STRINGS_H_ +#define VL53L1_ERROR_STRINGS_H_ + +#include "vl53l1_error_codes.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_pal_error_string( + VL53L1_Error PalErrorCode, + char *pPalErrorString); + + +#ifndef VL53L1_USE_EMPTY_STRING + + + + #define VL53L1_STRING_ERROR_NONE \ + "No Error" + #define VL53L1_STRING_ERROR_CALIBRATION_WARNING \ + "Calibration Warning Error" + #define VL53L1_STRING_ERROR_MIN_CLIPPED \ + "Min clipped error" + #define VL53L1_STRING_ERROR_UNDEFINED \ + "Undefined error" + #define VL53L1_STRING_ERROR_INVALID_PARAMS \ + "Invalid parameters error" + #define VL53L1_STRING_ERROR_NOT_SUPPORTED \ + "Not supported error" + #define VL53L1_STRING_ERROR_RANGE_ERROR \ + "Range error" + #define VL53L1_STRING_ERROR_TIME_OUT \ + "Time out error" + #define VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED \ + "Mode not supported error" + #define VL53L1_STRING_ERROR_BUFFER_TOO_SMALL \ + "Buffer too small" + #define VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL \ + "Comms Buffer too small" + #define VL53L1_STRING_ERROR_GPIO_NOT_EXISTING \ + "GPIO not existing" + #define VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \ + "GPIO funct not supported" + #define VL53L1_STRING_ERROR_CONTROL_INTERFACE \ + "Control Interface Error" + #define VL53L1_STRING_ERROR_INVALID_COMMAND \ + "Invalid Command Error" + #define VL53L1_STRING_ERROR_DIVISION_BY_ZERO \ + "Division by zero Error" + #define VL53L1_STRING_ERROR_REF_SPAD_INIT \ + "Reference Spad Init Error" + #define VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL \ + "GPH Sync Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL \ + "Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL \ + "GPH ID Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL \ + "Zone Stream Count Check Fail - API out of sync" + #define VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL \ + "Zone GPH ID Check Fail - API out of sync" + + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL \ + "No Xtalk using full array - Xtalk Extract Fail" + #define VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL \ + "Xtalk does not meet required VL53L1_p_011 limit - Xtalk Extract Fail" + + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL \ + "Offset Cal - one of more stages with no valid samples - fatal" + #define VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL \ + "Offset Cal - one of more stages with no SPADS enables - fatal" + #define VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL \ + "Zone Cal - one of more zones with no valid samples - fatal" + + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS \ + "Ref SPAD Char - Not Enough Good SPADs" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH \ + "Ref SPAD Char - Final Ref Rate too high" + #define VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW \ + "Ref SPAD Char - Final Ref Rate too low" + + #define VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES \ + "Offset Cal - Less than the requested number of valid samples" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH \ + "Offset Cal - Sigma estimate value too high - offset not stable" + #define VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH \ + "Offset Cal - Rate too high - in pile up" + #define VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW \ + "Offset Cal - Insufficient SPADs - offset may not be stable" + + #define VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES \ + "Zone Cal - One or more zone with less than requested valid samples" + #define VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH \ + "Zone Cal - One of more zones the VL53L1_p_011 estimate too high" + #define VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH \ + "Zone Cal - One of more zones with rate too high - in pile up" + + #define VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT \ + "Xtalk - Gradient sample num = 0" + #define VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT \ + "Xtalk - Gradient Sigma > Limit" + #define VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES \ + "Xtalk - Some missing and invalid samples" + + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD \ + "Device Firmware too old" + #define VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW \ + "Device Firmware too new" + #define VL53L1_STRING_ERROR_UNIT_TEST_FAIL \ + "Unit Test Fail" + #define VL53L1_STRING_ERROR_FILE_READ_FAIL \ + "File Read Fail" + #define VL53L1_STRING_ERROR_FILE_WRITE_FAIL \ + "File Write Fail" + + #define VL53L1_STRING_ERROR_NOT_IMPLEMENTED \ + "Not implemented error" + #define VL53L1_STRING_UNKNOW_ERROR_CODE \ + "Unknown Error Code" + +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_hist_char.h b/drivers/oneplus/vl53L1/inc/vl53l1_hist_char.h new file mode 100755 index 0000000000000000000000000000000000000000..25d84d16240a575864e61aae632df90c983ecc1a --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_hist_char.h @@ -0,0 +1,176 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_CHAR_H_ +#define _VL53L1_HIST_CHAR_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay); + + + + + + + + + + + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_hist_map.h b/drivers/oneplus/vl53L1/inc/vl53l1_hist_map.h new file mode 100755 index 0000000000000000000000000000000000000000..952dd16d601991598d2f247a3562536a98a99e1c --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_hist_map.h @@ -0,0 +1,156 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_MAP_H_ +#define _VL53L1_HIST_MAP_H_ + +#include "vl53l1_register_map.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_0 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_1 \ + VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS + +#define VL53L1_HISTOGRAM_CONFIG__OPCODE_SEQUENCE_2 \ + VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM + +#define VL53L1_HISTOGRAM_CONFIG__AMB_THRESH_HIGH \ + VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS + + + + + +#define VL53L1_RESULT__HISTOGRAM_BIN_0_2 0x008E +#define VL53L1_RESULT__HISTOGRAM_BIN_0_1 0x008F +#define VL53L1_RESULT__HISTOGRAM_BIN_0_0 0x0090 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_2 0x00D3 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_1 0x00D4 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0 0x00D5 + +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB 0x00D9 +#define VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB 0x00DA + + + + +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES \ + (VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - \ + VL53L1_RESULT__INTERRUPT_STATUS + 1) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_hist_structs.h b/drivers/oneplus/vl53L1/inc/vl53l1_hist_structs.h new file mode 100755 index 0000000000000000000000000000000000000000..48909e091ec3a5c7083e5ba9ee5207aff3f00a30 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_hist_structs.h @@ -0,0 +1,515 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_HIST_STRUCTS_H_ +#define _VL53L1_HIST_STRUCTS_H_ + +#include "vl53l1_ll_device.h" +#include "vl53l1_dmax_structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_MAX_BIN_SEQUENCE_LENGTH 6 +#define VL53L1_MAX_BIN_SEQUENCE_CODE 15 +#define VL53L1_HISTOGRAM_BUFFER_SIZE 24 +#define VL53L1_XTALK_HISTO_BINS 12 + + + + + + + + +typedef struct { + + uint8_t histogram_config__spad_array_selection; + + uint8_t histogram_config__low_amb_even_bin_0_1; + uint8_t histogram_config__low_amb_even_bin_2_3; + uint8_t histogram_config__low_amb_even_bin_4_5; + + uint8_t histogram_config__low_amb_odd_bin_0_1; + uint8_t histogram_config__low_amb_odd_bin_2_3; + uint8_t histogram_config__low_amb_odd_bin_4_5; + + uint8_t histogram_config__mid_amb_even_bin_0_1; + uint8_t histogram_config__mid_amb_even_bin_2_3; + uint8_t histogram_config__mid_amb_even_bin_4_5; + + uint8_t histogram_config__mid_amb_odd_bin_0_1; + uint8_t histogram_config__mid_amb_odd_bin_2; + uint8_t histogram_config__mid_amb_odd_bin_3_4; + uint8_t histogram_config__mid_amb_odd_bin_5; + + uint8_t histogram_config__user_bin_offset; + + uint8_t histogram_config__high_amb_even_bin_0_1; + uint8_t histogram_config__high_amb_even_bin_2_3; + uint8_t histogram_config__high_amb_even_bin_4_5; + + uint8_t histogram_config__high_amb_odd_bin_0_1; + uint8_t histogram_config__high_amb_odd_bin_2_3; + uint8_t histogram_config__high_amb_odd_bin_4_5; + + uint16_t histogram_config__amb_thresh_low; + + + + uint16_t histogram_config__amb_thresh_high; + + + + +} VL53L1_histogram_config_t; + + + + + + + + + +typedef struct { + + VL53L1_HistAlgoSelect hist_algo_select; + + + + VL53L1_HistTargetOrder hist_target_order; + + + + + + uint8_t filter_woi0; + + + + uint8_t filter_woi1; + + + + + VL53L1_HistAmbEstMethod hist_amb_est_method; + + + uint8_t ambient_thresh_sigma0; + + + + uint8_t ambient_thresh_sigma1; + + + + + + uint16_t ambient_thresh_events_scaler; + + + + + + + int32_t min_ambient_thresh_events; + + + uint16_t noise_threshold; + + + + int32_t signal_total_events_limit; + + + uint8_t sigma_estimator__sigma_ref_mm; + + + uint16_t sigma_thresh; + + + int16_t range_offset_mm; + + + uint16_t gain_factor; + + + + uint8_t valid_phase_low; + + + + uint8_t valid_phase_high; + + + + uint8_t algo__consistency_check__phase_tolerance; + + + + uint8_t algo__consistency_check__event_sigma; + + + + + + + uint16_t algo__consistency_check__event_min_spad_count; + + + + + + + uint16_t algo__consistency_check__min_max_tolerance; + + + + uint8_t algo__crosstalk_compensation_enable; + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + + + + uint8_t algo__crosstalk_detect_event_sigma; + + + + + + + uint16_t algo__crosstalk_detect_min_max_tolerance; + + + + +} VL53L1_hist_post_process_config_t; + + + + + + + +typedef struct { + + + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + + uint8_t zone_id; + + + uint32_t time_stamp; + + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_023; + + + uint8_t VL53L1_p_024; + + + + uint8_t number_of_ambient_bins; + + + + uint8_t bin_seq[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + + uint8_t bin_rep[VL53L1_MAX_BIN_SEQUENCE_LENGTH]; + + + + + int32_t bin_data[VL53L1_HISTOGRAM_BUFFER_SIZE]; + + + + uint8_t result__interrupt_status; + + + uint8_t result__range_status; + + + uint8_t result__report_status; + + + uint8_t result__stream_count; + + + uint16_t result__dss_actual_effective_spads; + + + + uint16_t phasecal_result__reference_phase; + + + uint8_t phasecal_result__vcsel_start; + + + uint8_t cal_config__vcsel_start; + + + uint16_t vcsel_width; + + + uint8_t VL53L1_p_009; + + + uint16_t VL53L1_p_019; + + + uint32_t total_periods_elapsed; + + + + uint32_t peak_duration_us; + + + uint32_t woi_duration_us; + + + + int32_t min_bin_value; + + + int32_t max_bin_value; + + + + uint16_t zero_distance_phase; + + + uint8_t number_of_ambient_samples; + + + int32_t ambient_events_sum; + + + int32_t VL53L1_p_004; + + + + uint8_t roi_config__user_roi_centre_spad; + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + +} VL53L1_histogram_bin_data_t; + + + + + + + + +typedef struct { + + + + uint8_t zone_id; + + + uint32_t time_stamp; + + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_023; + + + uint8_t VL53L1_p_024; + + + uint32_t bin_data[VL53L1_XTALK_HISTO_BINS]; + + + + + uint16_t phasecal_result__reference_phase; + + + uint8_t phasecal_result__vcsel_start; + + + uint8_t cal_config__vcsel_start; + + + uint16_t vcsel_width; + + + uint16_t VL53L1_p_019; + + + uint16_t zero_distance_phase; + + + +} VL53L1_xtalk_histogram_shape_t; + + + + + + + + +typedef struct { + + + + VL53L1_xtalk_histogram_shape_t xtalk_shape; + + + VL53L1_histogram_bin_data_t xtalk_hist_removed; + +} VL53L1_xtalk_histogram_data_t; + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_ll_def.h b/drivers/oneplus/vl53L1/inc/vl53l1_ll_def.h new file mode 100755 index 0000000000000000000000000000000000000000..7e599ca26e0f50c4a71d89ac9a14e851ed7b0c05 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_ll_def.h @@ -0,0 +1,2715 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_LL_DEF_H_ +#define _VL53L1_LL_DEF_H_ + +#include "vl53l1_error_codes.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_platform_user_config.h" +#include "vl53l1_platform_user_defines.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_dmax_structs.h" +#include "vl53l1_error_exceptions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR 1 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_MINOR 1 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_SUB 48 + + +#define VL53L1_LL_API_IMPLEMENTATION_VER_REVISION 12221 + +#define VL53L1_LL_API_IMPLEMENTATION_VER_STRING "1.1.48.12221" + + + +#define VL53L1_FIRMWARE_VER_MINIMUM 398 +#define VL53L1_FIRMWARE_VER_MAXIMUM 400 + + + + + + + +#define VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION 0xECAB0102 + + + + + + +#define VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION 0xECAE0101 + + + + + + +#define VL53L1_MAX_XTALK_RANGE_RESULTS 5 + + + + + + +#define VL53L1_MAX_OFFSET_RANGE_RESULTS 3 + + + + + +#define VL53L1_NVM_MAX_FMT_RANGE_DATA 4 + + + +#define VL53L1_NVM_PEAK_RATE_MAP_SAMPLES 25 + + +#define VL53L1_NVM_PEAK_RATE_MAP_WIDTH 5 + + +#define VL53L1_NVM_PEAK_RATE_MAP_HEIGHT 5 + + + + + + + + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD ((VL53L1_Error) - 80) + + +#define VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW ((VL53L1_Error) - 85) + + +#define VL53L1_ERROR_UNIT_TEST_FAIL ((VL53L1_Error) - 90) + + +#define VL53L1_ERROR_FILE_READ_FAIL ((VL53L1_Error) - 95) + + +#define VL53L1_ERROR_FILE_WRITE_FAIL ((VL53L1_Error) - 96) + + + + + + + + + + + + +typedef struct { + uint32_t ll_revision; + + uint8_t ll_major; + + uint8_t ll_minor; + + uint8_t ll_build; + +} VL53L1_ll_version_t; + + + + + + +typedef struct { + + uint8_t device_test_mode; + + uint8_t VL53L1_p_009; + + uint32_t timeout_us; + + uint16_t target_count_rate_mcps; + + + uint16_t min_count_rate_limit_mcps; + + + uint16_t max_count_rate_limit_mcps; + + + +} VL53L1_refspadchar_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint8_t num_of_samples; + + + int16_t algo__crosstalk_extract_min_valid_range_mm; + + + int16_t algo__crosstalk_extract_max_valid_range_mm; + + + uint16_t algo__crosstalk_extract_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_extract_max_sigma_mm; + + + + + +} VL53L1_xtalkextract_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t phasecal_config_timeout_us; + + + + uint32_t range_config_timeout_us; + + + + uint32_t mm_config_timeout_us; + + + + + uint8_t pre_num_of_samples; + + + + uint8_t mm1_num_of_samples; + + + + uint8_t mm2_num_of_samples; + + + + +} VL53L1_offsetcal_config_t; + + + + + + +typedef struct { + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t phasecal_config_timeout_us; + + + + uint32_t mm_config_timeout_us; + + + + uint32_t range_config_timeout_us; + + + + uint16_t phasecal_num_of_samples; + + + + uint16_t zone_num_of_samples; + + + + +} VL53L1_zonecal_config_t; + + + + + + + +typedef struct { + + VL53L1_DeviceSscArray array_select; + + + + + uint8_t VL53L1_p_009; + + + uint8_t vcsel_start; + + + uint8_t vcsel_width; + + + uint32_t timeout_us; + + + uint16_t rate_limit_mcps; + + + + + +} VL53L1_ssc_config_t; + + + + + + +typedef struct { + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + uint32_t nvm_default__crosstalk_compensation_plane_offset_kcps; + + + int16_t nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + + uint8_t global_crosstalk_compensation_enable; + + + int16_t histogram_mode_crosstalk_margin_kcps; + + + + + + + int16_t lite_mode_crosstalk_margin_kcps; + + + + + + + uint8_t crosstalk_range_ignore_threshold_mult; + + + uint16_t crosstalk_range_ignore_threshold_rate_mcps; + + + + + int16_t algo__crosstalk_detect_min_valid_range_mm; + + + int16_t algo__crosstalk_detect_max_valid_range_mm; + + + uint16_t algo__crosstalk_detect_max_valid_rate_kcps; + + + + uint16_t algo__crosstalk_detect_max_sigma_mm; + + + + + + +} VL53L1_xtalk_config_t; + + + + + + + + + + + + +typedef struct { + + + uint16_t tp_tuning_parm_version; + + + + uint16_t tp_tuning_parm_key_table_version; + + + + + uint16_t tp_tuning_parm_lld_version; + + + + + uint8_t tp_init_phase_rtn_lite_long; + + + + + uint8_t tp_init_phase_rtn_lite_med; + + + + + uint8_t tp_init_phase_rtn_lite_short; + + + + + uint8_t tp_init_phase_ref_lite_long; + + + + + uint8_t tp_init_phase_ref_lite_med; + + + + + uint8_t tp_init_phase_ref_lite_short; + + + + + + uint8_t tp_init_phase_rtn_hist_long; + + + + + uint8_t tp_init_phase_rtn_hist_med; + + + + + uint8_t tp_init_phase_rtn_hist_short; + + + + + uint8_t tp_init_phase_ref_hist_long; + + + + + uint8_t tp_init_phase_ref_hist_med; + + + + + uint8_t tp_init_phase_ref_hist_short; + + + + + + uint8_t tp_consistency_lite_phase_tolerance; + + + + + uint8_t tp_phasecal_target; + + + + + uint16_t tp_cal_repeat_rate; + + + + + uint8_t tp_lite_min_clip; + + + + + + uint16_t tp_lite_long_sigma_thresh_mm; + + + + + uint16_t tp_lite_med_sigma_thresh_mm; + + + + + uint16_t tp_lite_short_sigma_thresh_mm; + + + + + + uint16_t tp_lite_long_min_count_rate_rtn_mcps; + + + + + uint16_t tp_lite_med_min_count_rate_rtn_mcps; + + + + + uint16_t tp_lite_short_min_count_rate_rtn_mcps; + + + + + + uint8_t tp_lite_sigma_est_pulse_width_ns; + + + + uint8_t tp_lite_sigma_est_amb_width_ns; + + + + uint8_t tp_lite_sigma_ref_mm; + + + + uint8_t tp_lite_seed_cfg; + + + + uint8_t tp_timed_seed_cfg; + + + + + uint8_t tp_lite_quantifier; + + + + uint8_t tp_lite_first_order_select; + + + + + uint16_t tp_dss_target_lite_mcps; + + + + uint16_t tp_dss_target_histo_mcps; + + + + uint16_t tp_dss_target_histo_mz_mcps; + + + + uint16_t tp_dss_target_timed_mcps; + + + + uint16_t tp_dss_target_very_short_mcps; + + + + + uint32_t tp_phasecal_timeout_lite_us; + + + + uint32_t tp_phasecal_timeout_hist_long_us; + + + + uint32_t tp_phasecal_timeout_hist_med_us; + + + + uint32_t tp_phasecal_timeout_hist_short_us; + + + + + uint32_t tp_phasecal_timeout_mz_long_us; + + + + uint32_t tp_phasecal_timeout_mz_med_us; + + + + uint32_t tp_phasecal_timeout_mz_short_us; + + + + uint32_t tp_phasecal_timeout_timed_us; + + + + + uint32_t tp_mm_timeout_lite_us; + + + + uint32_t tp_mm_timeout_histo_us; + + + + uint32_t tp_mm_timeout_mz_us; + + + + uint32_t tp_mm_timeout_timed_us; + + + + uint32_t tp_mm_timeout_lpa_us; + + + + + uint32_t tp_range_timeout_lite_us; + + + + uint32_t tp_range_timeout_histo_us; + + + + uint32_t tp_range_timeout_mz_us; + + + + uint32_t tp_range_timeout_timed_us; + + + + uint32_t tp_range_timeout_lpa_us; + + + + +} VL53L1_tuning_parm_storage_t; + + + + + + + + +typedef struct { + + uint8_t x_centre; + + uint8_t y_centre; + + +} VL53L1_optical_centre_t; + + + + + + + +typedef struct { + + uint8_t x_centre; + + uint8_t y_centre; + + uint8_t width; + + uint8_t height; + + +} VL53L1_user_zone_t; + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + uint8_t active_zones; + + + + + + + + + +VL53L1_histogram_config_t multizone_hist_cfg; + + VL53L1_user_zone_t user_zones[VL53L1_MAX_USER_ZONES]; + + + + uint8_t bin_config[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_config_t; + + + + + + + + + +typedef struct { + + + + VL53L1_GPIO_Interrupt_Mode intr_mode_distance; + + + + VL53L1_GPIO_Interrupt_Mode intr_mode_rate; + + + + + + uint8_t intr_new_measure_ready; + + + + uint8_t intr_no_target; + + + + + + + uint8_t intr_combined_mode; + + + + + + + + + + + uint16_t threshold_distance_high; + + + + uint16_t threshold_distance_low; + + + + uint16_t threshold_rate_high; + + + + uint16_t threshold_rate_low; + +} VL53L1_GPIO_interrupt_config_t; + + + + + + + + + + + + +typedef struct { + + + + + + + uint8_t vhv_loop_bound; + + + + uint8_t is_low_power_auto_mode; + + + + + uint8_t low_power_auto_range_count; + + + + uint8_t saved_interrupt_config; + + + + uint8_t saved_vhv_init; + + + + uint8_t saved_vhv_timeout; + + + + uint8_t first_run_phasecal_result; + + + + uint32_t dss__total_rate_per_spad_mcps; + + + + uint16_t dss__required_spads; + +} VL53L1_low_power_auto_data_t; + + + + + + + + + + + + + + + +typedef struct { + + + + uint8_t smudge_corr_enabled; + + + + uint8_t smudge_corr_apply_enabled; + + + + uint8_t smudge_corr_single_apply; + + + + + + + uint16_t smudge_margin; + + + + uint32_t noise_margin; + + + + + uint32_t user_xtalk_offset_limit; + + + + + uint8_t user_xtalk_offset_limit_hi; + + + + + uint32_t sample_limit; + + + + + uint32_t single_xtalk_delta; + + + + + uint32_t averaged_xtalk_delta; + + + + + uint32_t smudge_corr_clip_limit; + + + + + uint32_t smudge_corr_ambient_threshold; + + + + + + + + + + + + + + + uint8_t scaler_calc_method; + + + + + + + int16_t x_gradient_scaler; + + + + + + + int16_t y_gradient_scaler; + + + + + + + uint8_t user_scaler_set; + + + + + uint32_t nodetect_ambient_threshold; + + + + + uint32_t nodetect_sample_limit; + + + + + uint32_t nodetect_xtalk_offset; + + + + + uint16_t nodetect_min_range_mm; + + +} VL53L1_smudge_corrector_config_t; + + + + + + + + + +typedef struct { + + + + uint32_t current_samples; + + + + uint32_t required_samples; + + + + uint64_t accumulator; + + + + uint32_t nodetect_counter; + +} VL53L1_smudge_corrector_internals_t; + + + + + + + + + +typedef struct { + + + + + + + + + uint8_t smudge_corr_valid; + + + + uint8_t smudge_corr_clipped; + + + + + + + + + uint8_t single_xtalk_delta_flag; + + + + + + + + + uint8_t averaged_xtalk_delta_flag; + + + + uint8_t sample_limit_exceeded_flag; + + + + + + + uint8_t gradient_zero_flag; + + + + uint8_t new_xtalk_applied_flag; + + + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + +} VL53L1_smudge_corrector_data_t; + + + + + + + + + + + +typedef struct { + + + + + uint8_t range_id; + + + uint32_t time_stamp; + + + uint8_t VL53L1_p_015; + + + uint8_t VL53L1_p_022; + + + uint8_t VL53L1_p_025; + + + uint8_t VL53L1_p_026; + + + uint8_t VL53L1_p_016; + + + uint8_t VL53L1_p_027; + + + + uint16_t width; + + + uint8_t VL53L1_p_030; + + + + + uint16_t fast_osc_frequency; + + + uint16_t zero_distance_phase; + + + uint16_t VL53L1_p_006; + + + + uint32_t total_periods_elapsed; + + + + uint32_t peak_duration_us; + + + + uint32_t woi_duration_us; + + + + + + + + uint32_t VL53L1_p_020; + + + uint32_t VL53L1_p_021; + + + + int32_t VL53L1_p_013; + + + + + + + + uint16_t peak_signal_count_rate_mcps; + + + uint16_t avg_signal_count_rate_mcps; + + + uint16_t ambient_count_rate_mcps; + + + uint16_t total_rate_per_spad_mcps; + + + uint32_t VL53L1_p_012; + + + + + + + uint16_t VL53L1_p_005; + + + + + + + uint16_t VL53L1_p_028; + + + + uint16_t VL53L1_p_014; + + + uint16_t VL53L1_p_029; + + + + + + + + int16_t min_range_mm; + + + + + + int16_t median_range_mm; + + + + + int16_t max_range_mm; + + + + + + + + + + uint8_t range_status; + +} VL53L1_range_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + + uint8_t stream_count; + + + + int16_t VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + + + + + int16_t wrap_dmax_mm; + + + + uint8_t device_status; + + + + uint8_t max_results; + + + + uint8_t active_results; + + + VL53L1_range_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + VL53L1_range_data_t xmonitor; + + + VL53L1_smudge_corrector_data_t smudge_corrector_data; + + + + +} VL53L1_range_results_t; + + + + + + + + + + +typedef struct { + + uint8_t no_of_samples; + + + uint32_t rate_per_spad_kcps_sum; + + + + uint32_t rate_per_spad_kcps_avg; + + + int32_t signal_total_events_sum; + + + + int32_t signal_total_events_avg; + + + + uint32_t sigma_mm_sum; + + + + uint32_t sigma_mm_avg; + + + uint32_t median_phase_sum; + + + + + uint32_t median_phase_avg; + + + + +} VL53L1_xtalk_range_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_Error cal_status; + + + uint8_t num_of_samples_status; + + + + + + + + + uint8_t zero_samples_status; + + + + + + + + + uint8_t max_sigma_status; + + + + + + + + + + + + + + + + + + + uint8_t max_results; + + + + uint8_t active_results; + + + + VL53L1_xtalk_range_data_t + VL53L1_p_002[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + VL53L1_histogram_bin_data_t central_histogram_sum; + + + + VL53L1_histogram_bin_data_t central_histogram_avg; + + + + uint8_t central_histogram__window_start; + + + + uint8_t central_histogram__window_end; + + + + VL53L1_histogram_bin_data_t + histogram_avg_1[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + VL53L1_histogram_bin_data_t + histogram_avg_2[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + VL53L1_histogram_bin_data_t + xtalk_avg[VL53L1_MAX_XTALK_RANGE_RESULTS]; + + + + +} VL53L1_xtalk_range_results_t; + + + + + + + + + + + +typedef struct { + + uint8_t preset_mode; + + + uint8_t dss_config__roi_mode_control; + + + uint16_t dss_config__manual_effective_spads_select; + + + uint8_t no_of_samples; + + + uint32_t effective_spads; + + + uint32_t peak_rate_mcps; + + + uint32_t VL53L1_p_005; + + + int32_t median_range_mm; + + + + int32_t range_mm_offset; + + + +} VL53L1_offset_range_data_t; + + + + + + + + + + +typedef struct { + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + VL53L1_Error cal_status; + + + uint8_t cal_report; + + + uint8_t max_results; + + + + uint8_t active_results; + + + VL53L1_offset_range_data_t + VL53L1_p_002[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + + +} VL53L1_offset_range_results_t; + + + + + + + + + + + + +typedef struct { + + uint16_t result__mm_inner_actual_effective_spads; + + + uint16_t result__mm_outer_actual_effective_spads; + + + uint16_t result__mm_inner_peak_signal_count_rtn_mcps; + + + uint16_t result__mm_outer_peak_signal_count_rtn_mcps; + + + +} VL53L1_additional_offset_cal_data_t; + + + + + + + + + + + + + +typedef struct { + + uint32_t VL53L1_p_020; + + + uint32_t VL53L1_p_021; + + + + uint16_t VL53L1_p_014; + + + uint8_t range_status; + + + +} VL53L1_object_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + VL53L1_DeviceState rd_device_state; + + + uint8_t zone_id; + + + uint8_t stream_count; + + + uint8_t max_objects; + + + + uint8_t active_objects; + + + VL53L1_object_data_t VL53L1_p_002[VL53L1_MAX_RANGE_RESULTS]; + + + + VL53L1_object_data_t xmonitor; + + + +} VL53L1_zone_objects_t; + + + + + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_objects_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_results_t; + + + + + + + + + +typedef struct { + + VL53L1_DeviceState rd_device_state; + + + + uint8_t number_of_ambient_bins; + + + + + uint16_t result__dss_actual_effective_spads; + + + uint8_t VL53L1_p_009; + + + uint32_t total_periods_elapsed; + + + + int32_t ambient_events_sum; + + + +} VL53L1_zone_hist_info_t; + + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_hist_info_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_histograms_t; + + + + + + + + + +typedef struct { + + uint32_t no_of_samples; + + + uint32_t effective_spads; + + + uint32_t peak_rate_mcps; + + + uint32_t VL53L1_p_014; + + + uint32_t VL53L1_p_005; + + + + int32_t median_range_mm; + + + + int32_t range_mm_offset; + + + +} VL53L1_zone_calibration_data_t; + + + + + + + + + + + +typedef struct { + + uint32_t struct_version; + + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + uint16_t phasecal_result__reference_phase; + + + uint16_t zero_distance_phase; + + + VL53L1_Error cal_status; + + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_calibration_data_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_calibration_results_t; + + + + + + + + + + + + + +typedef struct { + + int16_t cal_distance_mm; + + + uint16_t cal_reflectance_pc; + + + uint16_t max_samples; + + + uint16_t width; + + + uint16_t height; + + + uint16_t peak_rate_mcps[VL53L1_NVM_PEAK_RATE_MAP_SAMPLES]; + + + +} VL53L1_cal_peak_rate_map_t; + + + + + + + + + +typedef struct { + + uint8_t expected_stream_count; + + + uint8_t expected_gph_id; + + + uint8_t dss_mode; + + + uint16_t dss_requested_effective_spad_count; + + + + uint8_t seed_cfg; + + + uint8_t initial_phase_seed; + + + + uint8_t roi_config__user_roi_centre_spad; + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + +} VL53L1_zone_private_dyn_cfg_t; + + + + + + + + + +typedef struct { + + uint8_t max_zones; + + + + uint8_t active_zones; + + + VL53L1_zone_private_dyn_cfg_t VL53L1_p_002[VL53L1_MAX_USER_ZONES]; + + + +} VL53L1_zone_private_dyn_cfgs_t; + + + + + + + + + +typedef struct { + + uint32_t algo__crosstalk_compensation_plane_offset_kcps; + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + +} VL53L1_xtalk_calibration_results_t; + + + + + + + + +typedef struct { + + + + uint32_t sample_count; + + + + uint32_t pll_period_mm; + + + + uint32_t peak_duration_us_sum; + + + + uint32_t effective_spad_count_sum; + + + + uint32_t zero_distance_phase_sum; + + + + uint32_t zero_distance_phase_avg; + + + + int32_t event_scaler_sum; + + + + int32_t event_scaler_avg; + + + + int32_t signal_events_sum; + + + + uint32_t xtalk_rate_kcps_per_spad; + + + + int32_t xtalk_start_phase; + + + + int32_t xtalk_end_phase; + + + + int32_t xtalk_width_phase; + + + + int32_t target_start_phase; + + + + int32_t target_end_phase; + + + + int32_t target_width_phase; + + + + int32_t effective_width; + + + + int32_t event_scaler; + + + + uint8_t VL53L1_p_015; + + + + uint8_t VL53L1_p_016; + + + + uint8_t target_start; + + + + int32_t max_shape_value; + + + + int32_t bin_data_sums[VL53L1_XTALK_HISTO_BINS]; + +} VL53L1_hist_xtalk_extract_data_t; + + + + + + + + + + +typedef struct { + + uint16_t standard_ranging_gain_factor; + + + uint16_t histogram_ranging_gain_factor; + + + +} VL53L1_gain_calibration_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_DeviceState cfg_device_state; + + + uint8_t cfg_stream_count; + + + + uint8_t cfg_internal_stream_count; + + + uint8_t cfg_internal_stream_count_val; + + + uint8_t cfg_gph_id; + + + uint8_t cfg_timing_status; + + + uint8_t cfg_zone_id; + + + + VL53L1_DeviceState rd_device_state; + + + uint8_t rd_stream_count; + + + uint8_t rd_internal_stream_count; + + + uint8_t rd_internal_stream_count_val; + + + uint8_t rd_gph_id; + + + uint8_t rd_timing_status; + + + uint8_t rd_zone_id; + + + +} VL53L1_ll_driver_state_t; + + + + + + + + + + +typedef struct { + + uint8_t wait_method; + + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + VL53L1_DeviceMeasurementModes measurement_mode; + + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + + VL53L1_DeviceDmaxMode dmax_mode; + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint32_t inter_measurement_period_ms; + + + uint16_t dss_config__target_total_rate_mcps; + + + + uint32_t fw_ready_poll_duration_ms; + + + uint8_t fw_ready; + + + uint8_t debug_mode; + + + + + + VL53L1_ll_version_t version; + + + + VL53L1_ll_driver_state_t ll_state; + + + + VL53L1_GPIO_interrupt_config_t gpio_interrupt_config; + + + + VL53L1_customer_nvm_managed_t customer; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_user_zone_t mm_roi; + VL53L1_optical_centre_t optical_centre; + VL53L1_zone_config_t zone_cfg; + + + + VL53L1_tuning_parm_storage_t tuning_parms; + + + + uint8_t rtn_good_spads[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + VL53L1_refspadchar_config_t refspadchar; + VL53L1_ssc_config_t ssc_cfg; + VL53L1_hist_post_process_config_t histpostprocess; + VL53L1_hist_gen3_dmax_config_t dmax_cfg; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_offsetcal_config_t offsetcal_cfg; + VL53L1_zonecal_config_t zonecal_cfg; + + + + VL53L1_static_nvm_managed_t stat_nvm; + VL53L1_histogram_config_t hist_cfg; + VL53L1_static_config_t stat_cfg; + VL53L1_general_config_t gen_cfg; + VL53L1_timing_config_t tim_cfg; + VL53L1_dynamic_config_t dyn_cfg; + VL53L1_system_control_t sys_ctrl; + VL53L1_system_results_t sys_results; + VL53L1_nvm_copy_data_t nvm_copy_data; + + + + VL53L1_histogram_bin_data_t hist_data; + VL53L1_histogram_bin_data_t hist_xtalk; + + + + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + VL53L1_xtalk_calibration_results_t xtalk_cal; + VL53L1_hist_xtalk_extract_data_t xtalk_extract; + + + + VL53L1_offset_range_results_t offset_results; + + + + VL53L1_core_results_t core_results; + VL53L1_debug_results_t dbg_results; + + VL53L1_smudge_corrector_config_t smudge_correct_config; + + + VL53L1_smudge_corrector_internals_t smudge_corrector_internals; + + + + + + + + VL53L1_low_power_auto_data_t low_power_auto_data; + + + +#ifdef PAL_EXTENDED + + + VL53L1_patch_results_t patch_results; + VL53L1_shadow_core_results_t shadow_core_results; + VL53L1_shadow_system_results_t shadow_sys_results; + VL53L1_prev_shadow_core_results_t prev_shadow_core_results; + VL53L1_prev_shadow_system_results_t prev_shadow_sys_results; +#endif + +} VL53L1_LLDriverData_t; + + + + + + + + + + +typedef struct { + + + + VL53L1_range_results_t range_results; + + + + VL53L1_zone_private_dyn_cfgs_t zone_dyn_cfgs; + + + + VL53L1_zone_results_t zone_results; + VL53L1_zone_histograms_t zone_hists; + VL53L1_zone_calibration_results_t zone_cal; + +} VL53L1_LLDriverResults_t; + + + + + + + + + + +typedef struct { + + uint32_t struct_version; + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_optical_centre_t optical_centre; + VL53L1_xtalk_histogram_data_t xtalkhisto; + VL53L1_gain_calibration_data_t gain_cal; + VL53L1_cal_peak_rate_map_t cal_peak_rate_map; + +} VL53L1_calibration_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_xtalkextract_config_t xtalk_extract_cfg; + VL53L1_xtalk_config_t xtalk_cfg; + VL53L1_histogram_bin_data_t hist_data; + VL53L1_xtalk_histogram_data_t xtalk_shapes; + VL53L1_xtalk_range_results_t xtalk_results; + +} VL53L1_xtalk_debug_data_t; + + + + + + + + + + +typedef struct { + + VL53L1_customer_nvm_managed_t customer; + VL53L1_dmax_calibration_data_t fmt_dmax_cal; + VL53L1_dmax_calibration_data_t cust_dmax_cal; + VL53L1_additional_offset_cal_data_t add_off_cal_data; + VL53L1_offset_range_results_t offset_results; + +} VL53L1_offset_debug_data_t; + + + + + + + + + + +typedef struct { + uint16_t vl53l1_tuningparm_version; + uint16_t vl53l1_tuningparm_key_table_version; + uint16_t vl53l1_tuningparm_lld_version; + uint8_t vl53l1_tuningparm_hist_algo_select; + uint8_t vl53l1_tuningparm_hist_target_order; + uint8_t vl53l1_tuningparm_hist_filter_woi_0; + uint8_t vl53l1_tuningparm_hist_filter_woi_1; + uint8_t vl53l1_tuningparm_hist_amb_est_method; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_0; + uint8_t vl53l1_tuningparm_hist_amb_thresh_sigma_1; + int32_t vl53l1_tuningparm_hist_min_amb_thresh_events; + uint16_t vl53l1_tuningparm_hist_amb_events_scaler; + uint16_t vl53l1_tuningparm_hist_noise_threshold; + int32_t vl53l1_tuningparm_hist_signal_total_events_limit; + uint8_t vl53l1_tuningparm_hist_sigma_est_ref_mm; + uint16_t vl53l1_tuningparm_hist_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_hist_gain_factor; + uint8_t vl53l1_tuningparm_consistency_hist_phase_tolerance; + uint16_t vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm; + uint8_t vl53l1_tuningparm_consistency_hist_event_sigma; + uint16_t vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_histo_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_histo_short_range; + int16_t vl53l1_tuningparm_xtalk_detect_min_valid_range_mm; + int16_t vl53l1_tuningparm_xtalk_detect_max_valid_range_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_max_sigma_mm; + uint16_t vl53l1_tuningparm_xtalk_detect_min_max_tolerance; + uint16_t vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps; + uint8_t vl53l1_tuningparm_xtalk_detect_event_sigma; + int16_t vl53l1_tuningparm_hist_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_consistency_lite_phase_tolerance; + uint8_t vl53l1_tuningparm_phasecal_target; + uint16_t vl53l1_tuningparm_lite_cal_repeat_rate; + uint16_t vl53l1_tuningparm_lite_ranging_gain_factor; + uint8_t vl53l1_tuningparm_lite_min_clip_mm; + uint16_t vl53l1_tuningparm_lite_long_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_med_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_short_sigma_thresh_mm; + uint16_t vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps; + uint16_t vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps; + uint8_t vl53l1_tuningparm_lite_sigma_est_pulse_width; + uint8_t vl53l1_tuningparm_lite_sigma_est_amb_width_ns; + uint8_t vl53l1_tuningparm_lite_sigma_ref_mm; + uint8_t vl53l1_tuningparm_lite_rit_mult; + uint8_t vl53l1_tuningparm_lite_seed_config; + uint8_t vl53l1_tuningparm_lite_quantifier; + uint8_t vl53l1_tuningparm_lite_first_order_select; + int16_t vl53l1_tuningparm_lite_xtalk_margin_kcps; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_rtn_lite_short_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_long_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_med_range; + uint8_t vl53l1_tuningparm_initial_phase_ref_lite_short_range; + uint8_t vl53l1_tuningparm_timed_seed_config; + uint8_t vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_0; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_1; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_2; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_3; + uint16_t vl53l1_tuningparm_dmax_cfg_reflectance_array_4; + uint8_t vl53l1_tuningparm_vhv_loopbound; + uint8_t vl53l1_tuningparm_refspadchar_device_test_mode; + uint8_t vl53l1_tuningparm_refspadchar_vcsel_period; + uint32_t vl53l1_tuningparm_refspadchar_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_refspadchar_target_count_rate_mcps; + uint16_t vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps; + uint16_t vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps; + uint8_t vl53l1_tuningparm_xtalk_extract_num_of_samples; + int16_t vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm; + int16_t vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm; + uint16_t vl53l1_tuningparm_xtalk_extract_dss_rate_mcps; + uint32_t vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us; + uint16_t vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps; + uint16_t vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm; + uint32_t vl53l1_tuningparm_xtalk_extract_dss_timeout_us; + uint32_t vl53l1_tuningparm_xtalk_extract_bin_timeout_us; + uint16_t vl53l1_tuningparm_offset_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_offset_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_mm_timeout_us; + uint32_t vl53l1_tuningparm_offset_cal_range_timeout_us; + uint8_t vl53l1_tuningparm_offset_cal_pre_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm1_samples; + uint8_t vl53l1_tuningparm_offset_cal_mm2_samples; + uint16_t vl53l1_tuningparm_zone_cal_dss_rate_mcps; + uint32_t vl53l1_tuningparm_zone_cal_phasecal_timeout_us; + uint32_t vl53l1_tuningparm_zone_cal_dss_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_phasecal_num_samples; + uint32_t vl53l1_tuningparm_zone_cal_range_timeout_us; + uint16_t vl53l1_tuningparm_zone_cal_zone_num_samples; + uint8_t vl53l1_tuningparm_spadmap_vcsel_period; + uint8_t vl53l1_tuningparm_spadmap_vcsel_start; + uint16_t vl53l1_tuningparm_spadmap_rate_limit_mcps; + uint16_t vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps; + uint16_t vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps; + uint32_t vl53l1_tuningparm_lite_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_long_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_med_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_short_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_phasecal_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lite_range_config_timeout_us; + uint32_t vl53l1_tuningparm_ranging_range_config_timeout_us; + uint32_t vl53l1_tuningparm_mz_range_config_timeout_us; + uint32_t vl53l1_tuningparm_timed_range_config_timeout_us; + uint16_t vl53l1_tuningparm_dynxtalk_smudge_margin; + uint32_t vl53l1_tuningparm_dynxtalk_noise_margin; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit; + uint8_t vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi; + uint32_t vl53l1_tuningparm_dynxtalk_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_single_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta; + uint32_t vl53l1_tuningparm_dynxtalk_clip_limit; + uint8_t vl53l1_tuningparm_dynxtalk_scaler_calc_method; + int16_t vl53l1_tuningparm_dynxtalk_xgradient_scaler; + int16_t vl53l1_tuningparm_dynxtalk_ygradient_scaler; + uint8_t vl53l1_tuningparm_dynxtalk_user_scaler_set; + uint8_t vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply; + uint32_t vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_sample_limit; + uint32_t vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps; + uint16_t vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm; + uint8_t vl53l1_tuningparm_lowpowerauto_vhv_loop_bound; + uint32_t vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us; + uint32_t vl53l1_tuningparm_lowpowerauto_range_config_timeout_us; + uint16_t vl53l1_tuningparm_very_short_dss_rate_mcps; +} VL53L1_tuning_parameters_t; + + + + + + + + + + + + +typedef struct { + + uint16_t target_reflectance_for_dmax[VL53L1_MAX_AMBIENT_DMAX_VALUES]; + +} VL53L1_dmax_reflectance_array_t; + + + + + + + + + + + + + + +typedef struct { + + uint8_t spad_type; + + + uint16_t VL53L1_p_023; + + + uint16_t rate_data[VL53L1_NO_OF_SPAD_ENABLES]; + + + uint16_t no_of_values; + + + uint8_t fractional_bits; + + + uint8_t error_status; + + + +} VL53L1_spad_rate_data_t; + + + + + + + + + + + + + + +typedef struct { + + VL53L1_DevicePresetModes preset_mode; + + + VL53L1_DeviceZonePreset zone_preset; + + + VL53L1_DeviceMeasurementModes measurement_mode; + + + VL53L1_OffsetCalibrationMode offset_calibration_mode; + + + VL53L1_OffsetCorrectionMode offset_correction_mode; + + + VL53L1_DeviceDmaxMode dmax_mode; + + + + uint32_t phasecal_config_timeout_us; + + + uint32_t mm_config_timeout_us; + + + uint32_t range_config_timeout_us; + + + uint32_t inter_measurement_period_ms; + + + uint16_t dss_config__target_total_rate_mcps; + + + + VL53L1_histogram_bin_data_t VL53L1_p_010; + + + +} VL53L1_additional_data_t; + + + + + + + + + + +#define SUPPRESS_UNUSED_WARNING(x) \ + ((void) (x)) + + +#define IGNORE_STATUS(__FUNCTION_ID__, __ERROR_STATUS_CHECK__, __STATUS__) \ + do { \ + DISABLE_WARNINGS(); \ + if (__FUNCTION_ID__) { \ + if (__STATUS__ == __ERROR_STATUS_CHECK__) { \ + __STATUS__ = VL53L1_ERROR_NONE; \ + WARN_OVERRIDE_STATUS(__FUNCTION_ID__); \ + } \ + } \ + ENABLE_WARNINGS(); \ + } \ + while (0) + +#define VL53L1_COPYSTRING(str, ...) \ + (strncpy(str, ##__VA_ARGS__, VL53L1_MAX_STRING_LENGTH-1)) + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_ll_device.h b/drivers/oneplus/vl53L1/inc/vl53l1_ll_device.h new file mode 100755 index 0000000000000000000000000000000000000000..900c7df606cb23ad81df928c93aef92162b131dd --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_ll_device.h @@ -0,0 +1,1286 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_LL_DEVICE_H_ +#define _VL53L1_LL_DEVICE_H_ + +#include "vl53l1_types.h" +#include "vl53l1_platform_user_config.h" + +#define VL53L1_I2C 0x01 +#define VL53L1_SPI 0x00 + + + + + + + + + + + + + +typedef uint8_t VL53L1_WaitMethod; + +#define VL53L1_WAIT_METHOD_BLOCKING ((VL53L1_WaitMethod) 0) +#define VL53L1_WAIT_METHOD_NON_BLOCKING ((VL53L1_WaitMethod) 1) + + + + + + + + + + +typedef uint8_t VL53L1_DeviceState; + +#define VL53L1_DEVICESTATE_POWERDOWN ((VL53L1_DeviceState) 0) +#define VL53L1_DEVICESTATE_HW_STANDBY ((VL53L1_DeviceState) 1) +#define VL53L1_DEVICESTATE_FW_COLDBOOT ((VL53L1_DeviceState) 2) +#define VL53L1_DEVICESTATE_SW_STANDBY ((VL53L1_DeviceState) 3) +#define VL53L1_DEVICESTATE_RANGING_DSS_AUTO ((VL53L1_DeviceState) 4) +#define VL53L1_DEVICESTATE_RANGING_DSS_MANUAL ((VL53L1_DeviceState) 5) +#define VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC ((VL53L1_DeviceState) 6) +#define VL53L1_DEVICESTATE_RANGING_GATHER_DATA ((VL53L1_DeviceState) 7) +#define VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA ((VL53L1_DeviceState) 8) + +#define VL53L1_DEVICESTATE_UNKNOWN ((VL53L1_DeviceState) 98) +#define VL53L1_DEVICESTATE_ERROR ((VL53L1_DeviceState) 99) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceZonePreset; + +#define VL53L1_DEVICEZONEPRESET_NONE \ + ((VL53L1_DeviceZonePreset) 0) + +#define VL53L1_DEVICEZONEPRESET_XTALK_PLANAR \ + ((VL53L1_DeviceZonePreset) 1) +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16 \ + ((VL53L1_DeviceZonePreset) 2) +#define VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8 \ + ((VL53L1_DeviceZonePreset) 3) +#define VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16 \ + ((VL53L1_DeviceZonePreset) 4) +#define VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8 \ + ((VL53L1_DeviceZonePreset) 5) +#define VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 6) +#define VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 7) +#define VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 8) +#define VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5 \ + ((VL53L1_DeviceZonePreset) 9) +#define VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4 \ + ((VL53L1_DeviceZonePreset) 10) + +#define VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8 \ + ((VL53L1_DeviceZonePreset) 11) + +#define VL53L1_DEVICEZONEPRESET_CUSTOM \ + ((VL53L1_DeviceZonePreset) 255) + + + + + + + + + + + +typedef uint8_t VL53L1_DevicePresetModes; + +#define VL53L1_DEVICEPRESETMODE_NONE \ + ((VL53L1_DevicePresetModes) 0) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING \ + ((VL53L1_DevicePresetModes) 1) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 2) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 3) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 4) +#define VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 5) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING \ + ((VL53L1_DevicePresetModes) 6) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 7) +#define VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 8) +#define VL53L1_DEVICEPRESETMODE_NEAR_FARRANGING \ + ((VL53L1_DevicePresetModes) 9) +#define VL53L1_DEVICEPRESETMODE_QUADRANT_RANGING \ + ((VL53L1_DevicePresetModes) 10) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING \ + ((VL53L1_DevicePresetModes) 11) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING \ + ((VL53L1_DevicePresetModes) 12) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION \ + ((VL53L1_DevicePresetModes) 13) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR \ + ((VL53L1_DevicePresetModes) 14) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1 \ + ((VL53L1_DevicePresetModes) 15) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2 \ + ((VL53L1_DevicePresetModes) 16) +#define VL53L1_DEVICEPRESETMODE_OLT \ + ((VL53L1_DevicePresetModes) 17) +#define VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING \ + ((VL53L1_DevicePresetModes) 18) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY \ + ((VL53L1_DevicePresetModes) 19) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1 \ + ((VL53L1_DevicePresetModes) 20) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2 \ + ((VL53L1_DevicePresetModes) 21) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL \ + ((VL53L1_DevicePresetModes) 22) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL \ + ((VL53L1_DevicePresetModes) 23) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE \ + ((VL53L1_DevicePresetModes) 24) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 25) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 26) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 27) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 28) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 29) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 30) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 31) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 32) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 33) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1 \ + ((VL53L1_DevicePresetModes) 34) +#define VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2 \ + ((VL53L1_DevicePresetModes) 35) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 36) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE \ + ((VL53L1_DevicePresetModes) 37) +#define VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE \ + ((VL53L1_DevicePresetModes) 38) +#define VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE \ + ((VL53L1_DevicePresetModes) 39) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceMeasurementModes; + +#define VL53L1_DEVICEMEASUREMENTMODE_STOP \ + ((VL53L1_DeviceMeasurementModes) 0x00) +#define VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT \ + ((VL53L1_DeviceMeasurementModes) 0x10) +#define VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK \ + ((VL53L1_DeviceMeasurementModes) 0x20) +#define VL53L1_DEVICEMEASUREMENTMODE_TIMED \ + ((VL53L1_DeviceMeasurementModes) 0x40) +#define VL53L1_DEVICEMEASUREMENTMODE_ABORT \ + ((VL53L1_DeviceMeasurementModes) 0x80) + + + + + + + + + + + +typedef uint8_t VL53L1_OffsetCalibrationMode; + +#define VL53L1_OFFSETCALIBRATIONMODE__NONE \ + ((VL53L1_OffsetCalibrationMode) 0) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD \ + ((VL53L1_OffsetCalibrationMode) 1) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM \ + ((VL53L1_OffsetCalibrationMode) 2) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 3) +#define VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY \ + ((VL53L1_OffsetCalibrationMode) 4) +#define VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE \ + ((VL53L1_OffsetCalibrationMode) 5) + + + + + + + + + + + +typedef uint8_t VL53L1_OffsetCorrectionMode; + +#define VL53L1_OFFSETCORRECTIONMODE__NONE \ + ((VL53L1_OffsetCorrectionMode) 0) +#define VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 1) +#define VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS \ + ((VL53L1_OffsetCorrectionMode) 2) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceDmaxMode; + +#define VL53L1_DEVICEDMAXMODE__NONE \ + ((VL53L1_DeviceDmaxMode) 0) +#define VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 1) +#define VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 2) +#define VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA \ + ((VL53L1_DeviceDmaxMode) 3) + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceSequenceConfig; + +#define VL53L1_DEVICESEQUENCECONFIG_VHV \ + ((VL53L1_DeviceSequenceConfig) 0) +#define VL53L1_DEVICESEQUENCECONFIG_PHASECAL \ + ((VL53L1_DeviceSequenceConfig) 1) +#define VL53L1_DEVICESEQUENCECONFIG_REFERENCE_PHASE \ + ((VL53L1_DeviceSequenceConfig) 2) +#define VL53L1_DEVICESEQUENCECONFIG_DSS1 \ + ((VL53L1_DeviceSequenceConfig) 3) +#define VL53L1_DEVICESEQUENCECONFIG_DSS2 \ + ((VL53L1_DeviceSequenceConfig) 4) +#define VL53L1_DEVICESEQUENCECONFIG_MM1 \ + ((VL53L1_DeviceSequenceConfig) 5) +#define VL53L1_DEVICESEQUENCECONFIG_MM2 \ + ((VL53L1_DeviceSequenceConfig) 6) +#define VL53L1_DEVICESEQUENCECONFIG_RANGE \ + ((VL53L1_DeviceSequenceConfig) 7) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceInterruptPolarity; + +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_HIGH \ + ((VL53L1_DeviceInterruptPolarity) 0x00) +#define VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0x10) +#define VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK \ + ((VL53L1_DeviceInterruptPolarity) 0xEF) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceGpioMode; + +#define VL53L1_DEVICEGPIOMODE_OUTPUT_CONSTANT_ZERO \ + ((VL53L1_DeviceGpioMode) 0x00) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x01) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_TIMIER_INTERRUPTS \ + ((VL53L1_DeviceGpioMode) 0x02) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_MODE_INTERRUPT_STATUS \ + ((VL53L1_DeviceGpioMode) 0x03) +#define VL53L1_DEVICEGPIOMODE_OUTPUT_SLOW_OSCILLATOR_CLOCK \ + ((VL53L1_DeviceGpioMode) 0x04) +#define VL53L1_DEVICEGPIOMODE_BIT_MASK \ + ((VL53L1_DeviceGpioMode) 0x0F) +#define VL53L1_DEVICEGPIOMODE_CLEAR_MASK \ + ((VL53L1_DeviceGpioMode) 0xF0) + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceError; + +#define VL53L1_DEVICEERROR_NOUPDATE \ + ((VL53L1_DeviceError) 0) + + +#define VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \ + ((VL53L1_DeviceError) 1) +#define VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \ + ((VL53L1_DeviceError) 2) +#define VL53L1_DEVICEERROR_NOVHVVALUEFOUND \ + ((VL53L1_DeviceError) 3) +#define VL53L1_DEVICEERROR_MSRCNOTARGET \ + ((VL53L1_DeviceError) 4) +#define VL53L1_DEVICEERROR_RANGEPHASECHECK \ + ((VL53L1_DeviceError) 5) +#define VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK \ + ((VL53L1_DeviceError) 6) +#define VL53L1_DEVICEERROR_PHASECONSISTENCY \ + ((VL53L1_DeviceError) 7) +#define VL53L1_DEVICEERROR_MINCLIP \ + ((VL53L1_DeviceError) 8) +#define VL53L1_DEVICEERROR_RANGECOMPLETE \ + ((VL53L1_DeviceError) 9) +#define VL53L1_DEVICEERROR_ALGOUNDERFLOW \ + ((VL53L1_DeviceError) 10) +#define VL53L1_DEVICEERROR_ALGOOVERFLOW \ + ((VL53L1_DeviceError) 11) +#define VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD \ + ((VL53L1_DeviceError) 12) +#define VL53L1_DEVICEERROR_USERROICLIP \ + ((VL53L1_DeviceError) 13) +#define VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS \ + ((VL53L1_DeviceError) 14) +#define VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET \ + ((VL53L1_DeviceError) 15) +#define VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET \ + ((VL53L1_DeviceError) 16) +#define VL53L1_DEVICEERROR_MULTCLIPFAIL \ + ((VL53L1_DeviceError) 17) +#define VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY \ + ((VL53L1_DeviceError) 18) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK \ + ((VL53L1_DeviceError) 19) +#define VL53L1_DEVICEERROR_EVENTCONSISTENCY \ + ((VL53L1_DeviceError) 20) +#define VL53L1_DEVICEERROR_MINSIGNALEVENTCHECK \ + ((VL53L1_DeviceError) 21) +#define VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE \ + ((VL53L1_DeviceError) 22) + + + +#define VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS \ + ((VL53L1_DeviceError) 23) + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceReportStatus; + +#define VL53L1_DEVICEREPORTSTATUS_NOUPDATE \ + ((VL53L1_DeviceReportStatus) 0) + + +#define VL53L1_DEVICEREPORTSTATUS_ROI_SETUP \ + ((VL53L1_DeviceReportStatus) 1) +#define VL53L1_DEVICEREPORTSTATUS_VHV \ + ((VL53L1_DeviceReportStatus) 2) +#define VL53L1_DEVICEREPORTSTATUS_PHASECAL \ + ((VL53L1_DeviceReportStatus) 3) +#define VL53L1_DEVICEREPORTSTATUS_REFERENCE_PHASE \ + ((VL53L1_DeviceReportStatus) 4) +#define VL53L1_DEVICEREPORTSTATUS_DSS1 \ + ((VL53L1_DeviceReportStatus) 5) +#define VL53L1_DEVICEREPORTSTATUS_DSS2 \ + ((VL53L1_DeviceReportStatus) 6) +#define VL53L1_DEVICEREPORTSTATUS_MM1 \ + ((VL53L1_DeviceReportStatus) 7) +#define VL53L1_DEVICEREPORTSTATUS_MM2 \ + ((VL53L1_DeviceReportStatus) 8) +#define VL53L1_DEVICEREPORTSTATUS_RANGE \ + ((VL53L1_DeviceReportStatus) 9) +#define VL53L1_DEVICEREPORTSTATUS_HISTOGRAM \ + ((VL53L1_DeviceReportStatus) 10) + + + + + + + + + + +typedef uint8_t VL53L1_DeviceDssMode; + +#define VL53L1_DEVICEDSSMODE__DISABLED \ + ((VL53L1_DeviceDssMode) 0) +#define VL53L1_DEVICEDSSMODE__TARGET_RATE \ + ((VL53L1_DeviceDssMode) 1) +#define VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS \ + ((VL53L1_DeviceDssMode) 2) +#define VL53L1_DEVICEDSSMODE__BLOCK_SELECT \ + ((VL53L1_DeviceDssMode) 3) + + + + + + + + + + + + +typedef uint8_t VL53L1_HistAlgoSelect; + +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN1 \ + ((VL53L1_HistAlgoSelect) 1) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN2 \ + ((VL53L1_HistAlgoSelect) 2) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN3 \ + ((VL53L1_HistAlgoSelect) 3) +#define VL53L1_HIST_ALGO_SELECT__PW_HIST_GEN4 \ + ((VL53L1_HistAlgoSelect) 4) + + + + + + + + + + + +typedef uint8_t VL53L1_HistTargetOrder; + +#define VL53L1_HIST_TARGET_ORDER__INCREASING_DISTANCE \ + ((VL53L1_HistTargetOrder) 1) +#define VL53L1_HIST_TARGET_ORDER__STRONGEST_FIRST \ + ((VL53L1_HistTargetOrder) 2) + + + + + + + + + + + +typedef uint8_t VL53L1_HistAmbEstMethod; + +#define VL53L1_HIST_AMB_EST_METHOD__AMBIENT_BINS \ + ((VL53L1_HistAmbEstMethod) 1) +#define VL53L1_HIST_AMB_EST_METHOD__THRESHOLDED_BINS \ + ((VL53L1_HistAmbEstMethod) 2) + + + + + + + + + + + + +typedef uint8_t VL53L1_HistXtalkCompEnable; + +#define VL53L1_HIST_XTALK_COMP__DIS \ + ((VL53L1_HistXtalkCompEnable) 0) +#define VL53L1_HIST_XTALK_COMP__EN \ + ((VL53L1_HistXtalkCompEnable) 1) + + + + + + + + + +typedef uint8_t VL53L1_DeviceConfigLevel; + +#define VL53L1_DEVICECONFIGLEVEL_SYSTEM_CONTROL \ + ((VL53L1_DeviceConfigLevel) 0) + + +#define VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 1) + + +#define VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 2) + + + +#define VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 3) + + + +#define VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 4) + + + +#define VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS \ + ((VL53L1_DeviceConfigLevel) 5) + + + +#define VL53L1_DEVICECONFIGLEVEL_FULL \ + ((VL53L1_DeviceConfigLevel) 6) + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceResultsLevel; + +#define VL53L1_DEVICERESULTSLEVEL_SYSTEM_RESULTS \ + ((VL53L1_DeviceResultsLevel) 0) + + +#define VL53L1_DEVICERESULTSLEVEL_UPTO_CORE \ + ((VL53L1_DeviceResultsLevel) 1) + + +#define VL53L1_DEVICERESULTSLEVEL_FULL \ + ((VL53L1_DeviceResultsLevel) 2) + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceTestMode; + +#define VL53L1_DEVICETESTMODE_NONE \ + ((VL53L1_DeviceTestMode) 0x00) + + +#define VL53L1_DEVICETESTMODE_NVM_ZERO \ + ((VL53L1_DeviceTestMode) 0x01) + + +#define VL53L1_DEVICETESTMODE_NVM_COPY \ + ((VL53L1_DeviceTestMode) 0x02) + + +#define VL53L1_DEVICETESTMODE_PATCH \ + ((VL53L1_DeviceTestMode) 0x03) + + +#define VL53L1_DEVICETESTMODE_DCR \ + ((VL53L1_DeviceTestMode) 0x04) + + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_OFF \ + ((VL53L1_DeviceTestMode) 0x05) + + + +#define VL53L1_DEVICETESTMODE_LCR_VCSEL_ON \ + ((VL53L1_DeviceTestMode) 0x06) + + + +#define VL53L1_DEVICETESTMODE_SPOT_CENTRE_LOCATE \ + ((VL53L1_DeviceTestMode) 0x07) + + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_WITH_PRE_VHV \ + ((VL53L1_DeviceTestMode) 0x08) + + +#define VL53L1_DEVICETESTMODE_REF_SPAD_CHAR_ONLY \ + ((VL53L1_DeviceTestMode) 0x09) + + + + + + + + + + + + + +typedef uint8_t VL53L1_DeviceSscArray; + +#define VL53L1_DEVICESSCARRAY_RTN ((VL53L1_DeviceSscArray) 0x00) + + +#define VL53L1_DEVICETESTMODE_REF ((VL53L1_DeviceSscArray) 0x01) + + + + + + + + + + + + + +#define VL53L1_RETURN_ARRAY_ONLY 0x01 + + +#define VL53L1_REFERENCE_ARRAY_ONLY 0x10 + + +#define VL53L1_BOTH_RETURN_AND_REFERENCE_ARRAYS 0x11 + + +#define VL53L1_NEITHER_RETURN_AND_REFERENCE_ARRAYS 0x00 + + + + + + + + + + + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH 0x00 + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_LOW 0x10 + + +#define VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK 0x10 + + + + + + + + + + + + +#define VL53L1_POLLING_DELAY_US 1000 + + +#define VL53L1_SOFTWARE_RESET_DURATION_US 100 + + +#define VL53L1_FIRMWARE_BOOT_TIME_US 1200 + + + +#define VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US 250 + + + + +#define VL53L1_SPAD_ARRAY_WIDTH 16 + + +#define VL53L1_SPAD_ARRAY_HEIGHT 16 + + +#define VL53L1_NVM_SIZE_IN_BYTES 512 + + +#define VL53L1_NO_OF_SPAD_ENABLES 256 + + +#define VL53L1_RTN_SPAD_BUFFER_SIZE 32 + + +#define VL53L1_REF_SPAD_BUFFER_SIZE 6 + + +#define VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS 256 + + +#define VL53L1_RANGING_WINDOW_VCSEL_PERIODS 2048 + + +#define VL53L1_MACRO_PERIOD_VCSEL_PERIODS \ + (VL53L1_AMBIENT_WINDOW_VCSEL_PERIODS + \ + VL53L1_RANGING_WINDOW_VCSEL_PERIODS) + + +#define VL53L1_MAX_ALLOWED_PHASE 0xFFFF + + + +#define VL53L1_RTN_SPAD_UNITY_TRANSMISSION 0x0100 + + +#define VL53L1_RTN_SPAD_APERTURE_TRANSMISSION 0x0038 + + + + + +#define VL53L1_SPAD_TOTAL_COUNT_MAX ((0x01 << 29) - 1) + + +#define VL53L1_SPAD_TOTAL_COUNT_RES_THRES (0x01 << 24) + + +#define VL53L1_COUNT_RATE_INTERNAL_MAX ((0x01 << 24) - 1) + + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR 299704 + + +#define VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 (299704 >> 3) + + + + + + + + + + + + + + + + +typedef uint8_t VL53L1_ZoneConfig_BinConfig_select; + +#define VL53L1_ZONECONFIG_BINCONFIG__LOWAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 1) +#define VL53L1_ZONECONFIG_BINCONFIG__MIDAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 2) +#define VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB \ + ((VL53L1_ZoneConfig_BinConfig_select) 3) + + + + + + + + + + +typedef uint8_t VL53L1_GPIO_Interrupt_Mode; + +#define VL53L1_GPIOINTMODE_LEVEL_LOW \ + ((VL53L1_GPIO_Interrupt_Mode) 0) + + +#define VL53L1_GPIOINTMODE_LEVEL_HIGH \ + ((VL53L1_GPIO_Interrupt_Mode) 1) + + +#define VL53L1_GPIOINTMODE_OUT_OF_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 2) + + +#define VL53L1_GPIOINTMODE_IN_WINDOW \ + ((VL53L1_GPIO_Interrupt_Mode) 3) + + + + + + + + + + + + + +typedef uint16_t VL53L1_TuningParms; + +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PUBLIC_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS) + +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS) +#define VL53L1_TUNINGPARMS_LLD_PRIVATE_MAX_ADDRESS \ + ((VL53L1_TuningParms) VL53L1_TUNINGPARMS_LLD_PRIVATE_MIN_ADDRESS) + +#define VL53L1_TUNINGPARM_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 0)) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 1)) +#define VL53L1_TUNINGPARM_LLD_VERSION \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 2)) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 3)) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 4)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 5)) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 6)) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 7)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 8)) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 9)) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 10)) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 11)) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 12)) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 13)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 14)) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 15)) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 16)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 17)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 18)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 19)) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 20)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 21)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 22)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 23)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 24)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 25)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 26)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 27)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 28)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 29)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 30)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 31)) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 32)) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 33)) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 34)) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 35)) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 36)) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 37)) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 38)) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 39)) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 40)) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 41)) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 42)) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 43)) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 44)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 45)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 46)) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 47)) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 48)) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 49)) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 50)) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 51)) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 52)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 53)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 54)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 55)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 56)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 57)) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 58)) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 59)) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 60)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 61)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 62)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 63)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 64)) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4 \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 65)) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 66)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 67)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 68)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 69)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 70)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 71)) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 72)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 73)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 74)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 75)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 76)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 77)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 78)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 79)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 80)) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 81)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 82)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 83)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 84)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 85)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 86)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 87)) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 88)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 89)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 90)) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 91)) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 92)) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 93)) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 94)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 95)) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 96)) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 97)) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 98)) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 99)) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 100)) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 101)) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 102)) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 103)) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 104)) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 105)) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 106)) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 107)) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 108)) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 109)) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 110)) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 111)) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 112)) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 113)) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 114)) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 115)) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 116)) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 117)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 118)) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 119)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 120)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 121)) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 122)) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 123)) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 124)) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 125)) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 126)) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 127)) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 128)) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 129)) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 130)) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 131)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 132)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 133)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 134)) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 135)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 136)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 137)) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 138)) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS \ +((VL53L1_TuningParms) (VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS + 139)) + + + + + + +#endif + + + + + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_nvm.h b/drivers/oneplus/vl53L1/inc/vl53l1_nvm.h new file mode 100755 index 0000000000000000000000000000000000000000..53ccad1c112e60749c282d5c166ef013e93b9604 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_nvm.h @@ -0,0 +1,459 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_H_ +#define _VL53L1_NVM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VL53L1_NVM_POWER_UP_DELAY_US 50 +#define VL53L1_NVM_READ_TRIGGER_DELAY_US 5 + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata); + + + + + + + + + + + + + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data); + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_nvm_debug.h b/drivers/oneplus/vl53L1/inc/vl53l1_nvm_debug.h new file mode 100755 index 0000000000000000000000000000000000000000..0524c0c169f52e72d3e47d83b13a93fa3e9bfc53 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_nvm_debug.h @@ -0,0 +1,202 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_DEBUG_H_ +#define _VL53L1_NVM_DEBUG_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_nvm_structs.h" + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef VL53L1_LOG_ENABLE + + + + + + + + + + + + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + + + + + + + + + + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags); + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_nvm_map.h b/drivers/oneplus/vl53L1/inc/vl53l1_nvm_map.h new file mode 100755 index 0000000000000000000000000000000000000000..15b5e12766654d549f8e5ab830acaa0f4f6f9295 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_nvm_map.h @@ -0,0 +1,3254 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_MAP_H_ +#define _VL53L1_NVM_MAP_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODEL_ID 0x0008 + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODULE_TYPE 0x000C + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__REVISION_ID 0x000D + + + + + + + + + + + + + + + +#define VL53L1_NVM__IDENTIFICATION__MODULE_ID 0x000E + + + + + + + + + + + + + + + +#define VL53L1_NVM__I2C_VALID 0x0010 + + + + + + + + + + + + + + + +#define VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS 0x0011 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY 0x0014 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX 0x0016 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__FAST_OSC_FREQ_SET 0x0017 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION 0x0018 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY 0x001C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX 0x001E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FAST_OSC_FREQ_SET 0x001F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION 0x0020 + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG_UNLOCK 0x0028 + + + + + + + + + + + + + + + +#define VL53L1_NVM__REF_SELVDDPIX 0x0029 + + + + + + + + + + + + + + + +#define VL53L1_NVM__REF_SELVQUENCH 0x002A + + + + + + + + + + + + + + + +#define VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL 0x002B + + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x002C + + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__COUNT_THRESH 0x002D + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__OFFSET 0x002E + + + + + + + + + + + + + + + +#define VL53L1_NVM__VHV_CONFIG__INIT 0x002F + + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL 0x0030 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL 0x0031 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL 0x0032 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__MULT_LL 0x0034 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LL 0x0035 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD 0x0038 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD 0x0039 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD 0x003A + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__MULT_LD 0x003C + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY__CLIP_LD 0x003D + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY_LOCK_BYTE 0x0040 + + + + + + + + + + + + + + + +#define VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE 0x0044 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_ 0x0048 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_1_ 0x0049 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_2_ 0x004A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_3_ 0x004B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_4_ 0x004C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_5_ 0x004D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_6_ 0x004E + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_7_ 0x004F + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_8_ 0x0050 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_9_ 0x0051 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_10_ 0x0052 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_11_ 0x0053 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_12_ 0x0054 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_13_ 0x0055 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_14_ 0x0056 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_15_ 0x0057 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_16_ 0x0058 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_17_ 0x0059 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_18_ 0x005A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_19_ 0x005B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_20_ 0x005C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_21_ 0x005D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_22_ 0x005E + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_23_ 0x005F + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_24_ 0x0060 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_25_ 0x0061 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_26_ 0x0062 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_27_ 0x0063 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_28_ 0x0064 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_29_ 0x0065 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_30_ 0x0066 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_RTN_31_ 0x0067 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_ 0x0068 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_1_ 0x0069 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_2_ 0x006A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_3_ 0x006B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_4_ 0x006C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_5_ 0x006D + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_ 0x0070 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_1_ 0x0071 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_2_ 0x0072 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_3_ 0x0073 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_4_ 0x0074 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_5_ 0x0075 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_ 0x0078 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_1_ 0x0079 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_2_ 0x007A + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_3_ 0x007B + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_4_ 0x007C + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_5_ 0x007D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_ 0x0080 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_1_ 0x0081 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_2_ 0x0082 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_3_ 0x0083 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_4_ 0x0084 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_5_ 0x0085 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_6_ 0x0086 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_7_ 0x0087 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_8_ 0x0088 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_9_ 0x0089 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_10_ 0x008A + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_11_ 0x008B + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_12_ 0x008C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_13_ 0x008D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_14_ 0x008E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_15_ 0x008F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_16_ 0x0090 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_17_ 0x0091 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_18_ 0x0092 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_19_ 0x0093 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_20_ 0x0094 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_21_ 0x0095 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_22_ 0x0096 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_23_ 0x0097 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_24_ 0x0098 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_25_ 0x0099 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_26_ 0x009A + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_27_ 0x009B + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_28_ 0x009C + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_29_ 0x009D + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_30_ 0x009E + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_RTN_31_ 0x009F + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_ 0x00A0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_1_ 0x00A1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_2_ 0x00A2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_3_ 0x00A3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_4_ 0x00A4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_5_ 0x00A5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_ 0x00A8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_1_ 0x00A9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_2_ 0x00AA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_3_ 0x00AB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_4_ 0x00AC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_5_ 0x00AD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_ 0x00B0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_1_ 0x00B1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_2_ 0x00B2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_3_ 0x00B3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_4_ 0x00B4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_5_ 0x00B5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x00B8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE 0x00B9 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00BC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION 0x00BD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM 0x00C0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM 0x00C2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00C4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00C8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00CA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00CC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00CE + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00CF + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED 0x00E0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS 0x00E4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD 0x00E8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION 0x00E9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM 0x00EC + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM 0x00EE + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x00F0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x00F4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS \ + 0x00F6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS \ + 0x00F8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0 0x00FA + + + + + + + + + + + + + + + +#define VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1 0x00FB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_0 0x01DC + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_1 0x01DD + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_2 0x01DE + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_3 0x01DF + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_4 0x01E0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_5 0x01E1 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_6 0x01E2 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_7 0x01E3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_8 0x01E4 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_9 0x01E5 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_10 0x01E6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_11 0x01E7 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_12 0x01E8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_13 0x01E9 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_14 0x01EA + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__FGC__BYTE_15 0x01EB + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR 0x01EC + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__MAP_MAJOR_MINOR 0x01ED + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__YEAR_MONTH 0x01EE + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE 0x01EF + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TIME 0x01F0 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__TESTER_ID 0x01F2 + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__SITE_ID 0x01F3 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR 0x01F4 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR 0x01F5 + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__TESTER_ID 0x01F6 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_0 0x01F8 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_1 0x01F9 + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_2 0x01FA + + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_3 0x01FB + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_4 0x01FC + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__LOT__BYTE_5 0x01FD + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__WAFER 0x01FD + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__XCOORD 0x01FE + + + + + + + + + + + + + + + +#define VL53L1_NVM__EWS__YCOORD 0x01FF + + + + + + + + + + + + + + + + +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX 0x00B8 +#define VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE 4 + +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX 0x015C +#define VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE 56 + +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX 0x0194 +#define VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE 8 + +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE 0x019C +#define VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK 0x01AC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK 0x01BC +#define VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT 0x01CC +#define VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES 16 + + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_nvm_structs.h b/drivers/oneplus/vl53L1/inc/vl53l1_nvm_structs.h new file mode 100755 index 0000000000000000000000000000000000000000..4f9504034bc4952dd5536d25cbde6ec667a1fcdc --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_nvm_structs.h @@ -0,0 +1,809 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_NVM_STRUCTS_H_ +#define _VL53L1_NVM_STRUCTS_H_ + + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "vl53l1_platform.h" +#include "vl53l1_ll_def.h" + + + + + + + + + + +typedef struct { + + uint16_t result__actual_effective_rtn_spads; + + + uint8_t ref_spad_array__num_requested_ref_spads; + + + uint8_t ref_spad_array__ref_location; + + + uint16_t result__peak_signal_count_rate_rtn_mcps; + + + uint16_t result__ambient_count_rate_rtn_mcps; + + + uint16_t result__peak_signal_count_rate_ref_mcps; + + + uint16_t result__ambient_count_rate_ref_mcps; + + + uint16_t measured_distance_mm; + + + uint16_t measured_distance_stdev_mm; + + + +} VL53L1_decoded_nvm_fmt_range_data_t; + + + + + + + + + + +typedef struct { + + char nvm__fmt__fgc[19]; + + + uint8_t nvm__fmt__test_program_major; + + + + + + uint8_t nvm__fmt__test_program_minor; + + + + + + uint8_t nvm__fmt__map_major; + + + + + + uint8_t nvm__fmt__map_minor; + + + + + + uint8_t nvm__fmt__year; + + + + + + uint8_t nvm__fmt__month; + + + + + + uint8_t nvm__fmt__day; + + + + + + uint8_t nvm__fmt__module_date_phase; + + + + + + uint16_t nvm__fmt__time; + + + + + + uint8_t nvm__fmt__tester_id; + + + + + + uint8_t nvm__fmt__site_id; + + + + + + uint8_t nvm__ews__test_program_major; + + + + + + uint8_t nvm__ews__test_program_minor; + + + + + + uint8_t nvm__ews__probe_card_major; + + + + + + uint8_t nvm__ews__probe_card_minor; + + + + + + uint8_t nvm__ews__tester_id; + + + + + + + char nvm__ews__lot[8]; + + + uint8_t nvm__ews__wafer; + + + + + + uint8_t nvm__ews__xcoord; + + + + + + uint8_t nvm__ews__ycoord; + + + + + +} VL53L1_decoded_nvm_fmt_info_t; + + + + + + + + + + +typedef struct { + + uint8_t nvm__ews__test_program_major; + + + + + + uint8_t nvm__ews__test_program_minor; + + + + + + uint8_t nvm__ews__probe_card_major; + + + + + + uint8_t nvm__ews__probe_card_minor; + + + + + + uint8_t nvm__ews__tester_id; + + + + + + + char nvm__ews__lot[8]; + + + uint8_t nvm__ews__wafer; + + + + + + uint8_t nvm__ews__xcoord; + + + + + + uint8_t nvm__ews__ycoord; + + + + + + +} VL53L1_decoded_nvm_ews_info_t; + + + + + + + + + + +typedef struct { + uint8_t nvm__identification_model_id; + + + + + + uint8_t nvm__identification_module_type; + + + + + + uint8_t nvm__identification_revision_id; + + + + + + uint16_t nvm__identification_module_id; + + + + + + uint8_t nvm__i2c_valid; + + + + + + uint8_t nvm__i2c_device_address_ews; + + + + + + uint16_t nvm__ews__fast_osc_frequency; + + + + + + uint8_t nvm__ews__fast_osc_trim_max; + + + + + + uint8_t nvm__ews__fast_osc_freq_set; + + + + + + uint16_t nvm__ews__slow_osc_calibration; + + + + + + uint16_t nvm__fmt__fast_osc_frequency; + + + + + + uint8_t nvm__fmt__fast_osc_trim_max; + + + + + + uint8_t nvm__fmt__fast_osc_freq_set; + + + + + + uint16_t nvm__fmt__slow_osc_calibration; + + + + + + uint8_t nvm__vhv_config_unlock; + + + + + + uint8_t nvm__ref_selvddpix; + + + + + + uint8_t nvm__ref_selvquench; + + + + + + uint8_t nvm__regavdd1v2_sel; + + + + + + uint8_t nvm__regdvdd1v2_sel; + + + + + + uint8_t nvm__vhv_timeout__macrop; + + + + + + uint8_t nvm__vhv_loop_bound; + + + + + + uint8_t nvm__vhv_count_threshold; + + + + + + uint8_t nvm__vhv_offset; + + + + + + uint8_t nvm__vhv_init_enable; + + + + + + uint8_t nvm__vhv_init_value; + + + + + + uint8_t nvm__laser_safety_vcsel_trim_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_max_ll; + + + + + + uint8_t nvm__laser_safety_mult_ll; + + + + + + uint8_t nvm__laser_safety_clip_ll; + + + + + + uint8_t nvm__laser_safety_vcsel_trim_ld; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_ld; + + + + + + uint8_t nvm__laser_safety_vcsel_selion_max_ld; + + + + + + uint8_t nvm__laser_safety_mult_ld; + + + + + + uint8_t nvm__laser_safety_clip_ld; + + + + + + uint8_t nvm__laser_safety_lock_byte; + + + + + + uint8_t nvm__laser_safety_unlock_byte; + + + + + + uint8_t nvm__ews__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__ews__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_rtn[VL53L1_RTN_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc1[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc2[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__spad_enables_ref__loc3[VL53L1_REF_SPAD_BUFFER_SIZE]; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_centre_spad; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_x_size; + + + + + + uint8_t nvm__fmt__roi_config__mode_roi_y_size; + + + + + + uint8_t nvm__fmt__ref_spad_apply__num_requested_ref_spad; + + + + + + uint8_t nvm__fmt__ref_spad_man__ref_location; + + + + + + uint16_t nvm__fmt__mm_config__inner_offset_mm; + + + + + + uint16_t nvm__fmt__mm_config__outer_offset_mm; + + + + + + uint16_t nvm__fmt__algo_part_to_part_range_offset_mm; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + uint16_t nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_0; + + + + + + uint8_t nvm__fmt__spare__host_config__nvm_config_spare_1; + + + + + + uint8_t nvm__customer_space_programmed; + + + + + + uint8_t nvm__cust__i2c_device_address; + + + + + + uint8_t nvm__cust__ref_spad_apply__num_requested_ref_spad; + + + + + + uint8_t nvm__cust__ref_spad_man__ref_location; + + + + + + uint16_t nvm__cust__mm_config__inner_offset_mm; + + + + + + uint16_t nvm__cust__mm_config__outer_offset_mm; + + + + + + uint16_t nvm__cust__algo_part_to_part_range_offset_mm; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_plane_offset_kcps; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + uint16_t nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_0; + + + + + + uint8_t nvm__cust__spare__host_config__nvm_config_spare_1; + + + + + + + VL53L1_optical_centre_t fmt_optical_centre; + VL53L1_cal_peak_rate_map_t fmt_peak_rate_map; + VL53L1_additional_offset_cal_data_t fmt_add_offset_data; + + VL53L1_decoded_nvm_fmt_range_data_t + fmt_range_data[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + VL53L1_decoded_nvm_fmt_info_t fmt_info; + VL53L1_decoded_nvm_ews_info_t ews_info; + +} VL53L1_decoded_nvm_data_t; + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_preset_setup.h b/drivers/oneplus/vl53L1/inc/vl53l1_preset_setup.h new file mode 100755 index 0000000000000000000000000000000000000000..2a93fe70f3307940cef921539eba6b8697529fdf --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_preset_setup.h @@ -0,0 +1,110 @@ + +/****************************************************************************** + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + + ****************************************************************************** + + 'STMicroelectronics Proprietary license' + + ******************************************************************************* + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + + ******************************************************************************* + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones mentioned above : + + ******************************************************************************* + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + ******************************************************************************* + */ + +#ifndef _VL53L1_PRESET_SETUP_H_ +#define _VL53L1_PRESET_SETUP_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* indexes for the bare driver tuning setting API function */ +enum VL53L1_Tuning_t { + VL53L1_TUNING_VERSION = 0, + VL53L1_TUNING_PROXY_MIN, + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID, + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT, + + VL53L1_TUNING_MAX_TUNABLE_KEY +}; + +/* default values for the tuning settings parameters */ +#define TUNING_VERSION 0x0004 + +#define TUNING_PROXY_MIN -30 /* min distance in mm */ +#define TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM 600 +/* Target distance in mm for single target Xtalk */ +#define TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER 50 +/* Number of sample used for single target Xtalk */ +#define TUNING_MIN_AMBIENT_DMAX_VALID 8 +/* Minimum ambient level to state the Dmax returned by the device is valid */ +#define TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER 5 +/* Maximum loops to perform simple offset calibration */ +#define TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM 600 +/* Target distance in mm for target Xtalk from Bins method*/ +#define TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT 3 +/* Number of loops done during the simple offset calibration*/ + +/* the following table should actually be defined as static and shall be part + * of the VL53L1_StaticInit() function code + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL53L1_PRESET_SETUP_H_ */ diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_register_funcs.h b/drivers/oneplus/vl53L1/inc/vl53l1_register_funcs.h new file mode 100755 index 0000000000000000000000000000000000000000..37f492699c463d723131b9a40905257e3b9dea26 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_register_funcs.h @@ -0,0 +1,1694 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_FUNCS_H_ +#define _VL53L1_REGISTER_FUNCS_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata); + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_register_map.h b/drivers/oneplus/vl53L1/inc/vl53l1_register_map.h new file mode 100755 index 0000000000000000000000000000000000000000..5b73b703b45396654532585ae439a587613c8326 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_register_map.h @@ -0,0 +1,13151 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_MAP_H_ +#define _VL53L1_REGISTER_MAP_H_ + + + + + + + +#define VL53L1_SOFT_RESET 0x0000 + + + + + + + +#define VL53L1_I2C_SLAVE__DEVICE_ADDRESS 0x0001 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VDDPIX 0x0002 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VHV_REF_SEL_VQUENCH 0x0003 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REG_AVDD1V2_SEL 0x0004 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM 0x0005 + + + + + + + + + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY 0x0006 + + + + + + + + + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_HI 0x0006 + + + + + + + +#define VL53L1_OSC_MEASURED__FAST_OSC__FREQUENCY_LO 0x0007 + + + + + + + +#define VL53L1_VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND 0x0008 + + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__COUNT_THRESH 0x0009 + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__OFFSET 0x000A + + + + + + + + + + + + + + + +#define VL53L1_VHV_CONFIG__INIT 0x000B + + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 0x000D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_1 0x000E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_2 0x000F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_3 0x0010 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_4 0x0011 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_5 0x0012 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__REF_EN_START_SELECT 0x0013 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS 0x0014 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_MAN__REF_LOCATION 0x0015 + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS 0x0016 + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_HI 0x0016 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS_LO 0x0017 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS 0x0018 + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_HI 0x0018 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS_LO 0x0019 + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS 0x001A + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_HI 0x001A + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS_LO 0x001B + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS 0x001C + + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_HI 0x001C + + + + + + + +#define VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS_LO 0x001D + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM 0x001E + + + + + + + + + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_HI 0x001E + + + + + + + +#define VL53L1_ALGO__PART_TO_PART_RANGE_OFFSET_MM_LO 0x001F + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM 0x0020 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_HI 0x0020 + + + + + + + +#define VL53L1_MM_CONFIG__INNER_OFFSET_MM_LO 0x0021 + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM 0x0022 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_HI 0x0022 + + + + + + + +#define VL53L1_MM_CONFIG__OUTER_OFFSET_MM_LO 0x0023 + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS 0x0024 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_HI 0x0024 + + + + + + + +#define VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS_LO 0x0025 + + + + + + + +#define VL53L1_DEBUG__CTRL 0x0026 + + + + + + + + + + + + + + + +#define VL53L1_TEST_MODE__CTRL 0x0027 + + + + + + + + + + + + + + + +#define VL53L1_CLK_GATING__CTRL 0x0028 + + + + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__CTRL 0x0029 + + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__NUM_NVM_WORDS 0x002A + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__START_ADDRESS 0x002B + + + + + + + + + + + + + + + +#define VL53L1_HOST_IF__STATUS 0x002C + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_HV__CONFIG 0x002D + + + + + + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_HV__EXTSUP_CONFIG 0x002E + + + + + + + + + + + + + + + +#define VL53L1_GPIO_HV_PAD__CTRL 0x002F + + + + + + + + + + + + + + + + +#define VL53L1_GPIO_HV_MUX__CTRL 0x0030 + + + + + + + + + + + + + + + + +#define VL53L1_GPIO__TIO_HV_STATUS 0x0031 + + + + + + + + + + + + + + + + +#define VL53L1_GPIO__FIO_HV_STATUS 0x0032 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__SPAD_SEL_PSWIDTH 0x0033 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_PULSE_WIDTH_OFFSET 0x0034 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__CONFIG_CTRL 0x0035 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_PULSE_WIDTH_NS 0x0036 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__EFFECTIVE_AMBIENT_WIDTH_NS 0x0037 + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR__SIGMA_REF_MM 0x0038 + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CROSSTALK_COMPENSATION_VALID_HEIGHT_MM 0x0039 + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_0 0x003A + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_1 0x003B + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS 0x003C + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_HI 0x003C + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_THRESHOLD_MCPS_LO 0x003D + + + + + + + +#define VL53L1_ALGO__RANGE_IGNORE_VALID_HEIGHT_MM 0x003E + + + + + + + + + + + + + + + +#define VL53L1_ALGO__RANGE_MIN_CLIP 0x003F + + + + + + + + + + + + + + + + +#define VL53L1_ALGO__CONSISTENCY_CHECK__TOLERANCE 0x0040 + + + + + + + + + + + + + + + +#define VL53L1_SPARE_HOST_CONFIG__STATIC_CONFIG_SPARE_2 0x0041 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__RESET_STAGES_MSB 0x0042 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__RESET_STAGES_LSB 0x0043 + + + + + + + + + + + + + + + + +#define VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE 0x0044 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__STREAM_DIVIDER 0x0045 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_CONFIG_GPIO 0x0046 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__VCSEL_START 0x0047 + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE 0x0048 + + + + + + + + + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_HI 0x0048 + + + + + + + +#define VL53L1_CAL_CONFIG__REPEAT_RATE_LO 0x0049 + + + + + + + +#define VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH 0x004A + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP 0x004B + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__TARGET 0x004C + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_CONFIG__OVERRIDE 0x004D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__ROI_MODE_CONTROL 0x004F + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH 0x0050 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_HI 0x0050 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_HIGH_LO 0x0051 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW 0x0052 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_HI 0x0052 + + + + + + + +#define VL53L1_SYSTEM__THRESH_RATE_LOW_LO 0x0053 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0054 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0054 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0055 + + + + + + + +#define VL53L1_DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0056 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__APERTURE_ATTENUATION 0x0057 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MAX_SPADS_LIMIT 0x0058 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CONFIG__MIN_SPADS_LIMIT 0x0059 + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI 0x005A + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_LO 0x005B + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_HI 0x005C + + + + + + + + + + + + + + + +#define VL53L1_MM_CONFIG__TIMEOUT_MACROP_B_LO 0x005D + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x005E + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x005F + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A 0x0060 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0061 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0062 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VCSEL_PERIOD_B 0x0063 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH 0x0064 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_HI 0x0064 + + + + + + + +#define VL53L1_RANGE_CONFIG__SIGMA_THRESH_LO 0x0065 + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0066 + + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0066 + + + + + + + +#define VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0067 + + + + + + + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_LOW 0x0068 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_CONFIG__VALID_PHASE_HIGH 0x0069 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD 0x006C + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_3 0x006C + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_2 0x006D + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_1 0x006E + + + + + + + +#define VL53L1_SYSTEM__INTERMEASUREMENT_PERIOD_0 0x006F + + + + + + + +#define VL53L1_SYSTEM__FRACTIONAL_ENABLE 0x0070 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 0x0071 + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH 0x0072 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH_HI 0x0072 + + + + + + + +#define VL53L1_SYSTEM__THRESH_HIGH_LO 0x0073 + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW 0x0074 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW_HI 0x0074 + + + + + + + +#define VL53L1_SYSTEM__THRESH_LOW_LO 0x0075 + + + + + + + +#define VL53L1_SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x0076 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__SEED_CONFIG 0x0077 + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__WOI_SD0 0x0078 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__WOI_SD1 0x0079 + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD0 0x007A + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__INITIAL_PHASE_SD1 0x007B + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_1 0x007C + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__FIRST_ORDER_SELECT 0x007D + + + + + + + + + + + + + + + + +#define VL53L1_SD_CONFIG__QUANTIFIER 0x007E + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x007F + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x0080 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__SEQUENCE_CONFIG 0x0081 + + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD 0x0082 + + + + + + + + + + + + + + + + +#define VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE 0x0083 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__STREAM_COUNT_CTRL 0x0084 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__ENABLE 0x0085 + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_CLEAR 0x0086 + + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__MODE_START 0x0087 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__INTERRUPT_STATUS 0x0088 + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__RANGE_STATUS 0x0089 + + + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__REPORT_STATUS 0x008A + + + + + + + + + + + + + + + +#define VL53L1_RESULT__STREAM_COUNT 0x008B + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x008C + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x008C + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x008D + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x008E + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x008E + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x008F + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0090 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0090 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0091 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0 0x0092 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0_HI 0x0092 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD0_LO 0x0093 + + + + + + + +#define VL53L1_RESULT__PHASE_SD0 0x0094 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PHASE_SD0_HI 0x0094 + + + + + + + +#define VL53L1_RESULT__PHASE_SD0_LO 0x0095 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0096 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0096 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0097 + + + + + + + +#define VL53L1_PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0098 + + + + + + + + + + + + + +#define VL53L1__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0098 + + + + + + + +#define VL53L1___PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0099 + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009A + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009A + + + + + + + +#define VL53L1_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009B + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x009C + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x009C + + + + + + + +#define VL53L1_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x009D + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x009E + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x009E + + + + + + + +#define VL53L1_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x009F + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x00A0 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x00A0 + + + + + + + +#define VL53L1_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x00A1 + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x00A2 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x00A2 + + + + + + + +#define VL53L1_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x00A3 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x00A4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x00A4 + + + + + + + +#define VL53L1_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x00A5 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1 0x00A6 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1_HI 0x00A6 + + + + + + + +#define VL53L1_RESULT__SIGMA_SD1_LO 0x00A7 + + + + + + + +#define VL53L1_RESULT__PHASE_SD1 0x00A8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__PHASE_SD1_HI 0x00A8 + + + + + + + +#define VL53L1_RESULT__PHASE_SD1_LO 0x00A9 + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x00AA + + + + + + + + + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x00AA + + + + + + + +#define VL53L1_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x00AB + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1 0x00AC + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1_HI 0x00AC + + + + + + + +#define VL53L1_RESULT__SPARE_0_SD1_LO 0x00AD + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1 0x00AE + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1_HI 0x00AE + + + + + + + +#define VL53L1_RESULT__SPARE_1_SD1_LO 0x00AF + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1 0x00B0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1_HI 0x00B0 + + + + + + + +#define VL53L1_RESULT__SPARE_2_SD1_LO 0x00B1 + + + + + + + +#define VL53L1_RESULT__SPARE_3_SD1 0x00B2 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__THRESH_INFO 0x00B3 + + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x00B4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x00B4 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x00B5 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x00B6 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x00B7 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x00B8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x00B8 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x00B9 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x00BA + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x00BB + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x00BC + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x00BC + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x00BD + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x00BE + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x00BF + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x00C0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x00C0 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x00C1 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x00C2 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x00C3 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x00C4 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x00C4 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x00C5 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x00C6 + + + + + + + +#define VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x00C7 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x00C8 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x00C8 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x00C9 + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x00CA + + + + + + + +#define VL53L1_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x00CB + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x00CC + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x00CC + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x00CD + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x00CE + + + + + + + +#define VL53L1_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x00CF + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x00D0 + + + + + + + + + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x00D0 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x00D1 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x00D2 + + + + + + + +#define VL53L1_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x00D3 + + + + + + + +#define VL53L1_RESULT_CORE__SPARE_0 0x00D4 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE 0x00D6 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x00D6 + + + + + + + +#define VL53L1_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x00D7 + + + + + + + +#define VL53L1_PHASECAL_RESULT__VCSEL_START 0x00D8 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS 0x00D9 + + + + + + + + + + + + + + + +#define VL53L1_REF_SPAD_CHAR_RESULT__REF_LOCATION 0x00DA + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__COLDBOOT_STATUS 0x00DB + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__SEARCH_RESULT 0x00DC + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__LATEST_SETTING 0x00DD + + + + + + + + + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL 0x00DE + + + + + + + + + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_HI 0x00DE + + + + + + + +#define VL53L1_RESULT__OSC_CALIBRATE_VAL_LO 0x00DF + + + + + + + +#define VL53L1_ANA_CONFIG__POWERDOWN_GO1 0x00E0 + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REF_BG_CTRL 0x00E1 + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__REGDVDD1V2_CTRL 0x00E2 + + + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__OSC_SLOW_CTRL 0x00E3 + + + + + + + + + + + + + + + + + +#define VL53L1_TEST_MODE__STATUS 0x00E4 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__SYSTEM_STATUS 0x00E5 + + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__MODE_STATUS 0x00E6 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__SECONDARY_MODE_STATUS 0x00E7 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER 0x00E8 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_HI 0x00E8 + + + + + + + +#define VL53L1_FIRMWARE__CAL_REPEAT_RATE_COUNTER_LO 0x00E9 + + + + + + + +#define VL53L1_FIRMWARE__HISTOGRAM_BIN 0x00EA + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH 0x00EC + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_HI 0x00EC + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_HIGH_LO 0x00ED + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW 0x00EE + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_HI 0x00EE + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_LOW_LO 0x00EF + + + + + + + +#define VL53L1_GPH__SYSTEM__ENABLE_XTALK_PER_QUADRANT 0x00F0 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SPARE_0 0x00F1 + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__WOI_SD0 0x00F2 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__WOI_SD1 0x00F3 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD0 0x00F4 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__INITIAL_PHASE_SD1 0x00F5 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__FIRST_ORDER_SELECT 0x00F6 + + + + + + + + + + + + + + + + +#define VL53L1_GPH__SD_CONFIG__QUANTIFIER 0x00F7 + + + + + + + + + + + + + + + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_CENTRE_SPAD 0x00F8 + + + + + + + + + + + + + + + +#define VL53L1_GPH__ROI_CONFIG__USER_ROI_REQUESTED_GLOBAL_XY_SIZE 0x00F9 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__SEQUENCE_CONFIG 0x00FA + + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__GPH_ID 0x00FB + + + + + + + + + + + + + + + +#define VL53L1_SYSTEM__INTERRUPT_SET 0x00FC + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__ENABLES 0x00FD + + + + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__CLEAR 0x00FE + + + + + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_MANAGER__STATUS 0x00FF + + + + + + + + + + + + + + + + + + + +#define VL53L1_MCU_TO_HOST_BANK__WR_ACCESS_EN 0x0100 + + + + + + + + + + + + + + + +#define VL53L1_POWER_MANAGEMENT__GO1_RESET_STATUS 0x0101 + + + + + + + + + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO 0x0102 + + + + + + + + + + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_CTRL 0x0103 + + + + + + + + + + + + + + + + + + +#define VL53L1_PLL_PERIOD_US 0x0104 + + + + + + + + + + + + + + + +#define VL53L1_PLL_PERIOD_US_3 0x0104 + + + + + + + +#define VL53L1_PLL_PERIOD_US_2 0x0105 + + + + + + + +#define VL53L1_PLL_PERIOD_US_1 0x0106 + + + + + + + +#define VL53L1_PLL_PERIOD_US_0 0x0107 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT 0x0108 + + + + + + + + + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_3 0x0108 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_2 0x0109 + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_1 0x010A + + + + + + + +#define VL53L1_INTERRUPT_SCHEDULER__DATA_OUT_0 0x010B + + + + + + + +#define VL53L1_NVM_BIST__COMPLETE 0x010C + + + + + + + + + + + + + + + +#define VL53L1_NVM_BIST__STATUS 0x010D + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODEL_ID 0x010F + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_TYPE 0x0110 + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__REVISION_ID 0x0111 + + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID 0x0112 + + + + + + + + + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID_HI 0x0112 + + + + + + + +#define VL53L1_IDENTIFICATION__MODULE_ID_LO 0x0113 + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__TRIM_MAX 0x0114 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__FAST_OSC__FREQ_SET 0x0115 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_TRIM 0x0116 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_SELION 0x0117 + + + + + + + + + + + + + + + +#define VL53L1_ANA_CONFIG__VCSEL_SELION_MAX 0x0118 + + + + + + + + + + + + + + + +#define VL53L1_PROTECTED_LASER_SAFETY__LOCK_BIT 0x0119 + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__KEY 0x011A + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__KEY_RO 0x011B + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__CLIP 0x011C + + + + + + + + + + + + + + + +#define VL53L1_LASER_SAFETY__MULT 0x011D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_0 0x011E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_1 0x011F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_2 0x0120 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_3 0x0121 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_4 0x0122 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_5 0x0123 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_6 0x0124 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_7 0x0125 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_8 0x0126 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_9 0x0127 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_10 0x0128 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_11 0x0129 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_12 0x012A + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_13 0x012B + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_14 0x012C + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_15 0x012D + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_16 0x012E + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_17 0x012F + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_18 0x0130 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_19 0x0131 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_20 0x0132 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_21 0x0133 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_22 0x0134 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_23 0x0135 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_24 0x0136 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_25 0x0137 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_26 0x0138 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_27 0x0139 + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_28 0x013A + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_29 0x013B + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_30 0x013C + + + + + + + + + + + + + + + +#define VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_RTN_31 0x013D + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__MODE_ROI_CENTRE_SPAD 0x013E + + + + + + + + + + + + + + + +#define VL53L1_ROI_CONFIG__MODE_ROI_XY_SIZE 0x013F + + + + + + + + + + + + + + + +#define VL53L1_GO2_HOST_BANK_ACCESS__OVERRIDE 0x0300 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND 0x0400 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_3 0x0400 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_2 0x0401 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_1 0x0402 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLICAND_0 0x0403 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER 0x0404 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_3 0x0404 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_2 0x0405 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_1 0x0406 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__MULTIPLIER_0 0x0407 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI 0x0408 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_3 0x0408 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_2 0x0409 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_1 0x040A + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_HI_0 0x040B + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO 0x040C + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_3 0x040C + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_2 0x040D + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_1 0x040E + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__PRODUCT_LO_0 0x040F + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__START 0x0410 + + + + + + + +#define VL53L1_MCU_UTIL_MULTIPLIER__STATUS 0x0411 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__START 0x0412 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__STATUS 0x0413 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND 0x0414 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_3 0x0414 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_2 0x0415 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_1 0x0416 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVIDEND_0 0x0417 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR 0x0418 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_3 0x0418 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_2 0x0419 + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_1 0x041A + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__DIVISOR_0 0x041B + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT 0x041C + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_3 0x041C + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_2 0x041D + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_1 0x041E + + + + + + + +#define VL53L1_MCU_UTIL_DIVIDER__QUOTIENT_0 0x041F + + + + + + + +#define VL53L1_TIMER0__VALUE_IN 0x0420 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_3 0x0420 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_2 0x0421 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_1 0x0422 + + + + + + + +#define VL53L1_TIMER0__VALUE_IN_0 0x0423 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN 0x0424 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_3 0x0424 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_2 0x0425 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_1 0x0426 + + + + + + + +#define VL53L1_TIMER1__VALUE_IN_0 0x0427 + + + + + + + +#define VL53L1_TIMER0__CTRL 0x0428 + + + + + + + +#define VL53L1_TIMER1__CTRL 0x0429 + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_0 0x042C + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_1 0x042D + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_2 0x042E + + + + + + + + + + + + + + + +#define VL53L1_MCU_GENERAL_PURPOSE__GP_3 0x042F + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__CONFIG 0x0430 + + + + + + + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE 0x0432 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_HI 0x0432 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__OFFSET_CORRECTED_RANGE_LO 0x0433 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4 0x0434 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_3 0x0434 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_2 0x0435 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_1 0x0436 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_4_0 0x0437 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC 0x0438 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_HI 0x0438 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_DURATION_PRE_CALC_LO 0x0439 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_VCSEL_PERIOD 0x043C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_5 0x043D + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS 0x043E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_HI 0x043E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_TOTAL_PERIODS_LO 0x043F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE 0x0440 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_3 0x0440 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_2 0x0441 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_1 0x0442 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ACCUM_PHASE_0 0x0443 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS 0x0444 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_3 0x0444 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_2 0x0445 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_1 0x0446 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_SIGNAL_EVENTS_0 0x0447 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS 0x0448 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_3 0x0448 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_2 0x0449 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_1 0x044A + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_AMBIENT_EVENTS_0 0x044B + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6 0x044C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_HI 0x044C + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_6_LO 0x044D + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD 0x044E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_HI 0x044E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__ALGO_ADJUST_VCSEL_PERIOD_LO 0x044F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS 0x0450 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_HI 0x0450 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__NUM_SPADS_LO 0x0451 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT 0x0452 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_HI 0x0452 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PHASE_OUTPUT_LO 0x0453 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS 0x0454 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_3 0x0454 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_2 0x0455 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_1 0x0456 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__RATE_PER_SPAD_MCPS_0 0x0457 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_7 0x0458 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_8 0x0459 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS 0x045A + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_HI 0x045A + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_MCPS_LO 0x045B + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS 0x045C + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_HI 0x045C + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AVG_SIGNAL_RATE_MCPS_LO 0x045D + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS 0x045E + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_HI 0x045E + + + + + + + +#define VL53L1_MCU_RANGE_CALC__AMBIENT_RATE_MCPS_LO 0x045F + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK 0x0460 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK_HI 0x0460 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__XTALK_LO 0x0461 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__CALC_STATUS 0x0462 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__DEBUG 0x0463 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS 0x0464 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_HI 0x0464 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__PEAK_SIGNAL_RATE_XTALK_CORR_MCPS_LO 0x0465 + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_0 0x0468 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_1 0x0469 + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_2 0x046A + + + + + + + + + + + + + + + +#define VL53L1_MCU_RANGE_CALC__SPARE_3 0x046B + + + + + + + + + + + + + + + +#define VL53L1_PATCH__CTRL 0x0470 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES 0x0472 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES_HI 0x0472 + + + + + + + +#define VL53L1_PATCH__JMP_ENABLES_LO 0x0473 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES 0x0474 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES_HI 0x0474 + + + + + + + +#define VL53L1_PATCH__DATA_ENABLES_LO 0x0475 + + + + + + + +#define VL53L1_PATCH__OFFSET_0 0x0476 + + + + + + + +#define VL53L1_PATCH__OFFSET_0_HI 0x0476 + + + + + + + +#define VL53L1_PATCH__OFFSET_0_LO 0x0477 + + + + + + + +#define VL53L1_PATCH__OFFSET_1 0x0478 + + + + + + + +#define VL53L1_PATCH__OFFSET_1_HI 0x0478 + + + + + + + +#define VL53L1_PATCH__OFFSET_1_LO 0x0479 + + + + + + + +#define VL53L1_PATCH__OFFSET_2 0x047A + + + + + + + +#define VL53L1_PATCH__OFFSET_2_HI 0x047A + + + + + + + +#define VL53L1_PATCH__OFFSET_2_LO 0x047B + + + + + + + +#define VL53L1_PATCH__OFFSET_3 0x047C + + + + + + + +#define VL53L1_PATCH__OFFSET_3_HI 0x047C + + + + + + + +#define VL53L1_PATCH__OFFSET_3_LO 0x047D + + + + + + + +#define VL53L1_PATCH__OFFSET_4 0x047E + + + + + + + +#define VL53L1_PATCH__OFFSET_4_HI 0x047E + + + + + + + +#define VL53L1_PATCH__OFFSET_4_LO 0x047F + + + + + + + +#define VL53L1_PATCH__OFFSET_5 0x0480 + + + + + + + +#define VL53L1_PATCH__OFFSET_5_HI 0x0480 + + + + + + + +#define VL53L1_PATCH__OFFSET_5_LO 0x0481 + + + + + + + +#define VL53L1_PATCH__OFFSET_6 0x0482 + + + + + + + +#define VL53L1_PATCH__OFFSET_6_HI 0x0482 + + + + + + + +#define VL53L1_PATCH__OFFSET_6_LO 0x0483 + + + + + + + +#define VL53L1_PATCH__OFFSET_7 0x0484 + + + + + + + +#define VL53L1_PATCH__OFFSET_7_HI 0x0484 + + + + + + + +#define VL53L1_PATCH__OFFSET_7_LO 0x0485 + + + + + + + +#define VL53L1_PATCH__OFFSET_8 0x0486 + + + + + + + +#define VL53L1_PATCH__OFFSET_8_HI 0x0486 + + + + + + + +#define VL53L1_PATCH__OFFSET_8_LO 0x0487 + + + + + + + +#define VL53L1_PATCH__OFFSET_9 0x0488 + + + + + + + +#define VL53L1_PATCH__OFFSET_9_HI 0x0488 + + + + + + + +#define VL53L1_PATCH__OFFSET_9_LO 0x0489 + + + + + + + +#define VL53L1_PATCH__OFFSET_10 0x048A + + + + + + + +#define VL53L1_PATCH__OFFSET_10_HI 0x048A + + + + + + + +#define VL53L1_PATCH__OFFSET_10_LO 0x048B + + + + + + + +#define VL53L1_PATCH__OFFSET_11 0x048C + + + + + + + +#define VL53L1_PATCH__OFFSET_11_HI 0x048C + + + + + + + +#define VL53L1_PATCH__OFFSET_11_LO 0x048D + + + + + + + +#define VL53L1_PATCH__OFFSET_12 0x048E + + + + + + + +#define VL53L1_PATCH__OFFSET_12_HI 0x048E + + + + + + + +#define VL53L1_PATCH__OFFSET_12_LO 0x048F + + + + + + + +#define VL53L1_PATCH__OFFSET_13 0x0490 + + + + + + + +#define VL53L1_PATCH__OFFSET_13_HI 0x0490 + + + + + + + +#define VL53L1_PATCH__OFFSET_13_LO 0x0491 + + + + + + + +#define VL53L1_PATCH__OFFSET_14 0x0492 + + + + + + + +#define VL53L1_PATCH__OFFSET_14_HI 0x0492 + + + + + + + +#define VL53L1_PATCH__OFFSET_14_LO 0x0493 + + + + + + + +#define VL53L1_PATCH__OFFSET_15 0x0494 + + + + + + + +#define VL53L1_PATCH__OFFSET_15_HI 0x0494 + + + + + + + +#define VL53L1_PATCH__OFFSET_15_LO 0x0495 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0 0x0496 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0_HI 0x0496 + + + + + + + +#define VL53L1_PATCH__ADDRESS_0_LO 0x0497 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1 0x0498 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1_HI 0x0498 + + + + + + + +#define VL53L1_PATCH__ADDRESS_1_LO 0x0499 + + + + + + + +#define VL53L1_PATCH__ADDRESS_2 0x049A + + + + + + + +#define VL53L1_PATCH__ADDRESS_2_HI 0x049A + + + + + + + +#define VL53L1_PATCH__ADDRESS_2_LO 0x049B + + + + + + + +#define VL53L1_PATCH__ADDRESS_3 0x049C + + + + + + + +#define VL53L1_PATCH__ADDRESS_3_HI 0x049C + + + + + + + +#define VL53L1_PATCH__ADDRESS_3_LO 0x049D + + + + + + + +#define VL53L1_PATCH__ADDRESS_4 0x049E + + + + + + + +#define VL53L1_PATCH__ADDRESS_4_HI 0x049E + + + + + + + +#define VL53L1_PATCH__ADDRESS_4_LO 0x049F + + + + + + + +#define VL53L1_PATCH__ADDRESS_5 0x04A0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_5_HI 0x04A0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_5_LO 0x04A1 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6 0x04A2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6_HI 0x04A2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_6_LO 0x04A3 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7 0x04A4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7_HI 0x04A4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_7_LO 0x04A5 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8 0x04A6 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8_HI 0x04A6 + + + + + + + +#define VL53L1_PATCH__ADDRESS_8_LO 0x04A7 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9 0x04A8 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9_HI 0x04A8 + + + + + + + +#define VL53L1_PATCH__ADDRESS_9_LO 0x04A9 + + + + + + + +#define VL53L1_PATCH__ADDRESS_10 0x04AA + + + + + + + +#define VL53L1_PATCH__ADDRESS_10_HI 0x04AA + + + + + + + +#define VL53L1_PATCH__ADDRESS_10_LO 0x04AB + + + + + + + +#define VL53L1_PATCH__ADDRESS_11 0x04AC + + + + + + + +#define VL53L1_PATCH__ADDRESS_11_HI 0x04AC + + + + + + + +#define VL53L1_PATCH__ADDRESS_11_LO 0x04AD + + + + + + + +#define VL53L1_PATCH__ADDRESS_12 0x04AE + + + + + + + +#define VL53L1_PATCH__ADDRESS_12_HI 0x04AE + + + + + + + +#define VL53L1_PATCH__ADDRESS_12_LO 0x04AF + + + + + + + +#define VL53L1_PATCH__ADDRESS_13 0x04B0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_13_HI 0x04B0 + + + + + + + +#define VL53L1_PATCH__ADDRESS_13_LO 0x04B1 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14 0x04B2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14_HI 0x04B2 + + + + + + + +#define VL53L1_PATCH__ADDRESS_14_LO 0x04B3 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15 0x04B4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15_HI 0x04B4 + + + + + + + +#define VL53L1_PATCH__ADDRESS_15_LO 0x04B5 + + + + + + + +#define VL53L1_SPI_ASYNC_MUX__CTRL 0x04C0 + + + + + + + +#define VL53L1_CLK__CONFIG 0x04C4 + + + + + + + + + + + + + + + +#define VL53L1_GPIO_LV_MUX__CTRL 0x04CC + + + + + + + + + + + + + + + + +#define VL53L1_GPIO_LV_PAD__CTRL 0x04CD + + + + + + + + + + + + + + + +#define VL53L1_PAD_I2C_LV__CONFIG 0x04D0 + + + + + + + +#define VL53L1_PAD_STARTUP_MODE__VALUE_RO_GO1 0x04D4 + + + + + + + + + + + + + + + +#define VL53L1_HOST_IF__STATUS_GO1 0x04D5 + + + + + + + + + + + + + + + +#define VL53L1_MCU_CLK_GATING__CTRL 0x04D8 + + + + + + + + + + + + + + + + + + +#define VL53L1_TEST__BIST_ROM_CTRL 0x04E0 + + + + + + + +#define VL53L1_TEST__BIST_ROM_RESULT 0x04E1 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG 0x04E2 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_HI 0x04E2 + + + + + + + +#define VL53L1_TEST__BIST_ROM_MCU_SIG_LO 0x04E3 + + + + + + + +#define VL53L1_TEST__BIST_RAM_CTRL 0x04E4 + + + + + + + +#define VL53L1_TEST__BIST_RAM_RESULT 0x04E5 + + + + + + + +#define VL53L1_TEST__TMC 0x04E8 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD 0x04F0 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_HI 0x04F0 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MIN_THRESHOLD_LO 0x04F1 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD 0x04F2 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_HI 0x04F2 + + + + + + + +#define VL53L1_TEST__PLL_BIST_MAX_THRESHOLD_LO 0x04F3 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT 0x04F4 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_HI 0x04F4 + + + + + + + +#define VL53L1_TEST__PLL_BIST_COUNT_OUT_LO 0x04F5 + + + + + + + +#define VL53L1_TEST__PLL_BIST_GONOGO 0x04F6 + + + + + + + +#define VL53L1_TEST__PLL_BIST_CTRL 0x04F7 + + + + + + + +#define VL53L1_RANGING_CORE__DEVICE_ID 0x0680 + + + + + + + +#define VL53L1_RANGING_CORE__REVISION_ID 0x0681 + + + + + + + +#define VL53L1_RANGING_CORE__CLK_CTRL1 0x0683 + + + + + + + +#define VL53L1_RANGING_CORE__CLK_CTRL2 0x0684 + + + + + + + +#define VL53L1_RANGING_CORE__WOI_1 0x0685 + + + + + + + +#define VL53L1_RANGING_CORE__WOI_REF_1 0x0686 + + + + + + + +#define VL53L1_RANGING_CORE__START_RANGING 0x0687 + + + + + + + +#define VL53L1_RANGING_CORE__LOW_LIMIT_1 0x0690 + + + + + + + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_1 0x0691 + + + + + + + +#define VL53L1_RANGING_CORE__LOW_LIMIT_REF_1 0x0692 + + + + + + + +#define VL53L1_RANGING_CORE__HIGH_LIMIT_REF_1 0x0693 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_MSB 0x0694 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_1_LSB 0x0695 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_MSB 0x0696 + + + + + + + +#define VL53L1_RANGING_CORE__QUANTIFIER_REF_1_LSB 0x0697 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_MSB 0x0698 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_1_LSB 0x0699 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_MSB 0x069A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_OFFSET_REF_1_LSB 0x069B + + + + + + + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_1 0x069C + + + + + + + +#define VL53L1_RANGING_CORE__FILTER_STRENGTH_REF_1 0x069D + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_MSB 0x069E + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_1_LSB 0x069F + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_MSB 0x06A0 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_EVENT_LIMIT_REF_1_LSB 0x06A1 + + + + + + + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_MSB 0x06A4 + + + + + + + +#define VL53L1_RANGING_CORE__TIMEOUT_OVERALL_PERIODS_LSB 0x06A5 + + + + + + + +#define VL53L1_RANGING_CORE__INVERT_HW 0x06A6 + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_HW 0x06A7 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_HW_VALUE 0x06A8 + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_CONTINUOUS_AMBIENT 0x06A9 + + + + + + + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_FILTER 0x06AA + + + + + + + +#define VL53L1_RANGING_CORE__TEST_PHASE_SELECT_TO_TIMING_GEN 0x06AB + + + + + + + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_1 0x06AC + + + + + + + +#define VL53L1_RANGING_CORE__INITIAL_PHASE_VALUE_REF_1 0x06AD + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_UP_IN 0x06AE + + + + + + + +#define VL53L1_RANGING_CORE__FORCE_DN_IN 0x06AF + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_1 0x06B0 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_UP_VALUE_REF_1 0x06B1 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_1 0x06B2 + + + + + + + +#define VL53L1_RANGING_CORE__STATIC_DN_VALUE_REF_1 0x06B3 + + + + + + + +#define VL53L1_RANGING_CORE__MONITOR_UP_DN 0x06B4 + + + + + + + +#define VL53L1_RANGING_CORE__INVERT_UP_DN 0x06B5 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_1 0x06B6 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_2 0x06B7 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_3 0x06B8 + + + + + + + +#define VL53L1_RANGING_CORE__OSC_1 0x06B9 + + + + + + + +#define VL53L1_RANGING_CORE__PLL_1 0x06BB + + + + + + + +#define VL53L1_RANGING_CORE__PLL_2 0x06BC + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_1 0x06BD + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_3 0x06BF + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_4 0x06C0 + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_5 0x06C1 + + + + + + + +#define VL53L1_RANGING_CORE__REGAVDD1V2 0x06C3 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_1 0x06C4 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_2 0x06C5 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_3 0x06C6 + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX_SEL1 0x06C9 + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX_SEL2 0x06CA + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX 0x06CB + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_OUT_TESTMUX 0x06CC + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE 0x06CD + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2 0x06CE + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT 0x06CF + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT_1 0x06D0 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT_2 0x06D1 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_PS 0x06D2 + + + + + + + +#define VL53L1_RANGING_CORE__LASER_SAFETY_2 0x06D4 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__MODE 0x0780 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PDN 0x0781 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PROGN 0x0782 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__READN 0x0783 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB 0x0784 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_LSB 0x0785 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_MSB 0x0786 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_RISE_LSB 0x0787 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_MSB 0x0788 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__HV_FALL_LSB 0x0789 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__TST 0x078A + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__TESTREAD 0x078B + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_MMM 0x078C + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LMM 0x078D + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLM 0x078E + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAIN_LLL 0x078F + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM 0x0790 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LMM 0x0791 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLM 0x0792 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_LLL 0x0793 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__ADDR 0x0794 + + + + + + + +#define VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_ECC 0x0795 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_0 0x0796 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_1 0x0797 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_2 0x0798 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_3 0x0799 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_4 0x079A + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_5 0x079B + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_6 0x079C + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_7 0x079D + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_8 0x079E + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_9 0x079F + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_10 0x07A0 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_11 0x07A1 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_12 0x07A2 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_13 0x07A3 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_14 0x07A4 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_15 0x07A5 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_16 0x07A6 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_17 0x07A7 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_SHIFT_EN 0x07BA + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_DISABLE_CTRL 0x07BB + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_EN_SHIFT_OUT_DEBUG 0x07BC + + + + + + + +#define VL53L1_RANGING_CORE__SPI_MODE 0x07BD + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_DIR 0x07BE + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD 0x0880 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_START 0x0881 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STOP 0x0882 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_1 0x0885 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STATUS 0x088D + + + + + + + +#define VL53L1_RANGING_CORE__STATUS 0x0980 + + + + + + + +#define VL53L1_RANGING_CORE__LASER_CONTINUITY_STATE 0x0981 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_MMM 0x0982 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LMM 0x0983 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LLM 0x0984 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_1_LLL 0x0985 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_MMM 0x0986 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LMM 0x0987 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLM 0x0988 + + + + + + + +#define VL53L1_RANGING_CORE__RANGE_REF_1_LLL 0x0989 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_MMM 0x098A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LMM 0x098B + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLM 0x098C + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_1_LLL 0x098D + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_MMM 0x098E + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LMM 0x098F + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLM 0x0990 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_1_LLL 0x0991 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_MMM 0x0992 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LMM 0x0993 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLM 0x0994 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_1_LLL 0x0995 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_MM 0x0996 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LM 0x0997 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_1_LL 0x0998 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_MM 0x0999 + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LM 0x099A + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_LL 0x099B + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_MMM 0x099C + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LMM 0x099D + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLM 0x099E + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_WINDOW_EVENTS_REF_1_LLL 0x099F + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_MMM 0x09A0 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LMM 0x09A1 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLM 0x09A2 + + + + + + + +#define VL53L1_RANGING_CORE__RANGING_TOTAL_EVENTS_REF_1_LLL 0x09A3 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_MMM 0x09A4 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LMM 0x09A5 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLM 0x09A6 + + + + + + + +#define VL53L1_RANGING_CORE__SIGNAL_TOTAL_EVENTS_REF_1_LLL 0x09A7 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_MM 0x09A8 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LM 0x09A9 + + + + + + + +#define VL53L1_RANGING_CORE__TOTAL_PERIODS_ELAPSED_REF_1_LL 0x09AA + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_MM 0x09AB + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LM 0x09AC + + + + + + + +#define VL53L1_RANGING_CORE__AMBIENT_MISMATCH_REF_LL 0x09AD + + + + + + + +#define VL53L1_RANGING_CORE__GPIO_CONFIG__A0 0x0A00 + + + + + + + +#define VL53L1_RANGING_CORE__RESET_CONTROL__A0 0x0A01 + + + + + + + +#define VL53L1_RANGING_CORE__INTR_MANAGER__A0 0x0A02 + + + + + + + +#define VL53L1_RANGING_CORE__POWER_FSM_TIME_OSC__A0 0x0A06 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_ATEST__A0 0x0A07 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_PERIOD_CLIPPED__A0 0x0A08 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_STOP_CLIPPED__A0 0x0A09 + + + + + + + +#define VL53L1_RANGING_CORE__CALIB_2__A0 0x0A0A + + + + + + + +#define VL53L1_RANGING_CORE__STOP_CONDITION__A0 0x0A0B + + + + + + + +#define VL53L1_RANGING_CORE__STATUS_RESET__A0 0x0A0C + + + + + + + +#define VL53L1_RANGING_CORE__READOUT_CFG__A0 0x0A0D + + + + + + + +#define VL53L1_RANGING_CORE__WINDOW_SETTING__A0 0x0A0E + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_DELAY__A0 0x0A1A + + + + + + + +#define VL53L1_RANGING_CORE__REFERENCE_2__A0 0x0A1B + + + + + + + +#define VL53L1_RANGING_CORE__REGAVDD1V2__A0 0x0A1D + + + + + + + +#define VL53L1_RANGING_CORE__TST_MUX__A0 0x0A1F + + + + + + + +#define VL53L1_RANGING_CORE__CUSTOM_FE_2__A0 0x0A20 + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__A0 0x0A21 + + + + + + + +#define VL53L1_RANGING_CORE__CPUMP_1__A0 0x0A22 + + + + + + + +#define VL53L1_RANGING_CORE__SPARE_REGISTER__A0 0x0A23 + + + + + + + +#define VL53L1_RANGING_CORE__VCSEL_CONT_STAGE5_BYPASS__A0 0x0A24 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_18 0x0A25 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_19 0x0A26 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_20 0x0A27 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_21 0x0A28 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_22 0x0A29 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_23 0x0A2A + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_24 0x0A2B + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_25 0x0A2C + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_26 0x0A2D + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_27 0x0A2E + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_28 0x0A2F + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_29 0x0A30 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_30 0x0A31 + + + + + + + +#define VL53L1_RANGING_CORE__RET_SPAD_EN_31 0x0A32 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_0__EWOK 0x0A33 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_1__EWOK 0x0A34 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_2__EWOK 0x0A35 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_3__EWOK 0x0A36 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_4__EWOK 0x0A37 + + + + + + + +#define VL53L1_RANGING_CORE__REF_SPAD_EN_5__EWOK 0x0A38 + + + + + + + +#define VL53L1_RANGING_CORE__REF_EN_START_SELECT 0x0A39 + + + + + + + +#define VL53L1_RANGING_CORE__REGDVDD1V2_ATEST__EWOK 0x0A41 + + + + + + + +#define VL53L1_SOFT_RESET_GO1 0x0B00 + + + + + + + +#define VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV 0x0E00 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS 0x0ED0 + + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__RANGE_STATUS 0x0ED1 + + + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__REPORT_STATUS 0x0ED2 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__STREAM_COUNT 0x0ED3 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0ED4 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0ED4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0ED5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0ED6 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0ED6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0ED7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0ED8 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0ED8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0ED9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0 0x0EDA + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_HI 0x0EDA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD0_LO 0x0EDB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0 0x0EDC + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_HI 0x0EDC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD0_LO 0x0EDD + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0EDE + + + + + + + + + + + + + + + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0EDE + + + + + + + +#define VL53L1_PREV__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0EDF + + + + + + + +#define VL53L1_PREV__PEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0EE0 + + + + + + + + + + + + + + + + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0EE0 + + + + + + + +#define VL53L1_PPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0EE1 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE2 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE2 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE3 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0EE4 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0EE4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0EE5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0EE6 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0EE6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0EE7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0EE8 + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0EE8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0EE9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0EEA + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0EEA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0EEB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0EEC + + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0EEC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0EED + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1 0x0EEE + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_HI 0x0EEE + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SIGMA_SD1_LO 0x0EEF + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1 0x0EF0 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_HI 0x0EF0 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__PHASE_SD1_LO 0x0EF1 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0EF2 + + + + + + + + + + + + + + + + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0EF2 + + + + + + + +#define VL53L1_PFINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0EF3 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1 0x0EF4 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_HI 0x0EF4 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_0_SD1_LO 0x0EF5 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1 0x0EF6 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_HI 0x0EF6 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_1_SD1_LO 0x0EF7 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1 0x0EF8 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_HI 0x0EF8 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_2_SD1_LO 0x0EF9 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1 0x0EFA + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_HI 0x0EFA + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT__SPARE_3_SD1_LO 0x0EFB + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0EFC + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0EFC + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0EFD + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0EFE + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0EFF + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0F00 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0F00 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0F01 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0F02 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0F03 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0F04 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0F04 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0F05 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0F06 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0F07 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0F08 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0F08 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0F09 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0F0A + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0F0B + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0F0C + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0F0C + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0F0D + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0F0E + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0F0F + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0F10 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0F10 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0F11 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0F12 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0F13 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0F14 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0F14 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0F15 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0F16 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0F17 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0F18 + + + + + + + + + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0F18 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0F19 + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0F1A + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0F1B + + + + + + + +#define VL53L1_PREV_SHADOW_RESULT_CORE__SPARE_0 0x0F1C + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DEBUG_STATUS 0x0F20 + + + + + + + + + + + + + + + +#define VL53L1_RESULT__DEBUG_STAGE 0x0F21 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH 0x0F24 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_HI 0x0F24 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH_LO 0x0F25 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW 0x0F26 + + + + + + + + + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_HI 0x0F26 + + + + + + + +#define VL53L1_GPH__SYSTEM__THRESH_RATE_LOW_LO 0x0F27 + + + + + + + +#define VL53L1_GPH__SYSTEM__INTERRUPT_CONFIG_GPIO 0x0F28 + + + + + + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL 0x0F2F + + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT 0x0F30 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_HI 0x0F30 + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_EFFECTIVE_SPADS_SELECT_LO 0x0F31 + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MANUAL_BLOCK_SELECT 0x0F32 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MAX_SPADS_LIMIT 0x0F33 + + + + + + + + + + + + + + + +#define VL53L1_GPH__DSS_CONFIG__MIN_SPADS_LIMIT 0x0F34 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI 0x0F36 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_LO 0x0F37 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_HI 0x0F38 + + + + + + + + + + + + + + + +#define VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_B_LO 0x0F39 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_HI 0x0F3A + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_A_LO 0x0F3B + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_A 0x0F3C + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VCSEL_PERIOD_B 0x0F3D + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_HI 0x0F3E + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__TIMEOUT_MACROP_B_LO 0x0F3F + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH 0x0F40 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_HI 0x0F40 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__SIGMA_THRESH_LO 0x0F41 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS 0x0F42 + + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_HI 0x0F42 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS_LO 0x0F43 + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_LOW 0x0F44 + + + + + + + + + + + + + + + +#define VL53L1_GPH__RANGE_CONFIG__VALID_PHASE_HIGH 0x0F45 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV 0x0F46 + + + + + + + + + + + + + + + +#define VL53L1_FIRMWARE__INTERNAL_STREAM_COUNTER_VAL 0x0F47 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__ROI_CTRL 0x0F54 + + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_1 0x0F55 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_2 0x0F56 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_3 0x0F57 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_4 0x0F58 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_5 0x0F59 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_6 0x0F5A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__SPARE_7 0x0F5B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_0 0x0F5C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_1 0x0F5D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_2 0x0F5E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_3 0x0F5F + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_4 0x0F60 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_5 0x0F61 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_6 0x0F62 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_7 0x0F63 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_8 0x0F64 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_9 0x0F65 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_10 0x0F66 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_11 0x0F67 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_12 0x0F68 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_13 0x0F69 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_14 0x0F6A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_15 0x0F6B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_16 0x0F6C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_17 0x0F6D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_18 0x0F6E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_19 0x0F6F + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_20 0x0F70 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_21 0x0F71 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_22 0x0F72 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_23 0x0F73 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_24 0x0F74 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_25 0x0F75 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_26 0x0F76 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_27 0x0F77 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_28 0x0F78 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_29 0x0F79 + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_30 0x0F7A + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_SPAD_EN_31 0x0F7B + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_0 0x0F7C + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__USER_ROI_1 0x0F7D + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__MODE_ROI_0 0x0F7E + + + + + + + + + + + + + + + +#define VL53L1_DSS_CALC__MODE_ROI_1 0x0F7F + + + + + + + + + + + + + + + +#define VL53L1_SIGMA_ESTIMATOR_CALC__SPARE_0 0x0F80 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS 0x0F82 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_HI 0x0F82 + + + + + + + +#define VL53L1_VHV_RESULT__PEAK_SIGNAL_RATE_MCPS_LO 0x0F83 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF 0x0F84 + + + + + + + + + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_3 0x0F84 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_2 0x0F85 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_1 0x0F86 + + + + + + + +#define VL53L1_VHV_RESULT__SIGNAL_TOTAL_EVENTS_REF_0 0x0F87 + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF 0x0F88 + + + + + + + + + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_HI 0x0F88 + + + + + + + +#define VL53L1_PHASECAL_RESULT__PHASE_OUTPUT_REF_LO 0x0F89 + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD 0x0F8A + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_HI 0x0F8A + + + + + + + +#define VL53L1_DSS_RESULT__TOTAL_RATE_PER_SPAD_LO 0x0F8B + + + + + + + +#define VL53L1_DSS_RESULT__ENABLED_BLOCKS 0x0F8C + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS 0x0F8E + + + + + + + + + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_HI 0x0F8E + + + + + + + +#define VL53L1_DSS_RESULT__NUM_REQUESTED_SPADS_LO 0x0F8F + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE 0x0F92 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_HI 0x0F92 + + + + + + + +#define VL53L1_MM_RESULT__INNER_INTERSECTION_RATE_LO 0x0F93 + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE 0x0F94 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_HI 0x0F94 + + + + + + + +#define VL53L1_MM_RESULT__OUTER_COMPLEMENT_RATE_LO 0x0F95 + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET 0x0F96 + + + + + + + + + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_HI 0x0F96 + + + + + + + +#define VL53L1_MM_RESULT__TOTAL_OFFSET_LO 0x0F97 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS 0x0F98 + + + + + + + + + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_3 0x0F98 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_2 0x0F99 + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_1 0x0F9A + + + + + + + +#define VL53L1_XTALK_CALC__XTALK_FOR_ENABLED_SPADS_0 0x0F9B + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS 0x0F9C + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_3 0x0F9C + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_2 0x0F9D + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_1 0x0F9E + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_USER_ROI_KCPS_0 0x0F9F + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS 0x0FA0 + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_3 0x0FA0 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_2 0x0FA1 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_1 0x0FA2 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_INNER_ROI_KCPS_0 0x0FA3 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS 0x0FA4 + + + + + + + + + + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_3 0x0FA4 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_2 0x0FA5 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_1 0x0FA6 + + + + + + + +#define VL53L1_XTALK_RESULT__AVG_XTALK_MM_OUTER_ROI_KCPS_0 0x0FA7 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE 0x0FA8 + + + + + + + + + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_3 0x0FA8 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_2 0x0FA9 + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_1 0x0FAA + + + + + + + +#define VL53L1_RANGE_RESULT__ACCUM_PHASE_0 0x0FAB + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE 0x0FAC + + + + + + + + + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_HI 0x0FAC + + + + + + + +#define VL53L1_RANGE_RESULT__OFFSET_CORRECTED_RANGE_LO 0x0FAD + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START 0x0FAE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__INTERRUPT_STATUS 0x0FB0 + + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__RANGE_STATUS 0x0FB1 + + + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__REPORT_STATUS 0x0FB2 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__STREAM_COUNT 0x0FB3 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FB4 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FB4 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FB5 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FB6 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FB6 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FB7 + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0 0x0FB8 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_HI 0x0FB8 + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD0_LO 0x0FB9 + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0 0x0FBA + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_HI 0x0FBA + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD0_LO 0x0FBB + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0 0x0FBC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_HI 0x0FBC + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD0_LO 0x0FBD + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0 0x0FBE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_HI 0x0FBE + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD0_LO 0x0FBF + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0 0x0FC0 + + + + + + + + + + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_HI 0x0FC0 + + + + + + + +#define VL53L1_SHPEAK_SIGNAL_COUNT_RATE_CROSSTALK_CORRECTED_MCPS_SD0_LO 0x0FC1 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC2 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC2 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_INNER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC3 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0 0x0FC4 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_HI 0x0FC4 + + + + + + + +#define VL53L1_SHADOW_RESULT__MM_OUTER_ACTUAL_EFFECTIVE_SPADS_SD0_LO 0x0FC5 + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0 0x0FC6 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_HI 0x0FC6 + + + + + + + +#define VL53L1_SHADOW_RESULT__AVG_SIGNAL_COUNT_RATE_MCPS_SD0_LO 0x0FC7 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1 0x0FC8 + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_HI 0x0FC8 + + + + + + + +#define VL53L1_SHADOW_RESULT__DSS_ACTUAL_EFFECTIVE_SPADS_SD1_LO 0x0FC9 + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1 0x0FCA + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_HI 0x0FCA + + + + + + + +#define VL53L1_SHADOW_RESULT__PEAK_SIGNAL_COUNT_RATE_MCPS_SD1_LO 0x0FCB + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1 0x0FCC + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_HI 0x0FCC + + + + + + + +#define VL53L1_SHADOW_RESULT__AMBIENT_COUNT_RATE_MCPS_SD1_LO 0x0FCD + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1 0x0FCE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_HI 0x0FCE + + + + + + + +#define VL53L1_SHADOW_RESULT__SIGMA_SD1_LO 0x0FCF + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1 0x0FD0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_HI 0x0FD0 + + + + + + + +#define VL53L1_SHADOW_RESULT__PHASE_SD1_LO 0x0FD1 + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1 0x0FD2 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_HI 0x0FD2 + + + + + + + +#define VL53L1_SHADOW_RESULT__FINAL_CROSSTALK_CORRECTED_RANGE_MM_SD1_LO 0x0FD3 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1 0x0FD4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_HI 0x0FD4 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_0_SD1_LO 0x0FD5 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1 0x0FD6 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_HI 0x0FD6 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_1_SD1_LO 0x0FD7 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1 0x0FD8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_HI 0x0FD8 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_2_SD1_LO 0x0FD9 + + + + + + + +#define VL53L1_SHADOW_RESULT__SPARE_3_SD1 0x0FDA + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT__THRESH_INFO 0x0FDB + + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 0x0FDC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_3 0x0FDC + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_2 0x0FDD + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_1 0x0FDE + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0_0 0x0FDF + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0 0x0FE0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_3 0x0FE0 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_2 0x0FE1 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_1 0x0FE2 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD0_0 0x0FE3 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0 0x0FE4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_3 0x0FE4 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_2 0x0FE5 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_1 0x0FE6 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD0_0 0x0FE7 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0 0x0FE8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_3 0x0FE8 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_2 0x0FE9 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_1 0x0FEA + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD0_0 0x0FEB + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1 0x0FEC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_3 0x0FEC + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_2 0x0FED + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_1 0x0FEE + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD1_0 0x0FEF + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1 0x0FF0 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_3 0x0FF0 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_2 0x0FF1 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_1 0x0FF2 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__RANGING_TOTAL_EVENTS_SD1_0 0x0FF3 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1 0x0FF4 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_3 0x0FF4 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_2 0x0FF5 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_1 0x0FF6 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SIGNAL_TOTAL_EVENTS_SD1_0 0x0FF7 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1 0x0FF8 + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_3 0x0FF8 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_2 0x0FF9 + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_1 0x0FFA + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__TOTAL_PERIODS_ELAPSED_SD1_0 0x0FFB + + + + + + + +#define VL53L1_SHADOW_RESULT_CORE__SPARE_0 0x0FFC + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_HI 0x0FFE + + + + + + + + + + + + + + + +#define VL53L1_SHADOW_PHASECAL_RESULT__REFERENCE_PHASE_LO 0x0FFF + + + + + + + + + + + + + + + + + + + + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_register_settings.h b/drivers/oneplus/vl53L1/inc/vl53l1_register_settings.h new file mode 100755 index 0000000000000000000000000000000000000000..767367f08217b81e7995e412be78433a5cd1d68c --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_register_settings.h @@ -0,0 +1,274 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_SETTINGS_H_ +#define _VL53L1_REGISTER_SETTINGS_H_ + + + + + + + + + + + + + + + + +#define VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO 0x00 +#define VL53L1_DEVICESCHEDULERMODE_STREAMING 0x01 +#define VL53L1_DEVICESCHEDULERMODE_HISTOGRAM 0x02 + + + + + + + + + + + +#define VL53L1_DEVICEREADOUTMODE_SINGLE_SD (0x00 << 2) +#define VL53L1_DEVICEREADOUTMODE_DUAL_SD (0x01 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_READOUT (0x02 << 2) +#define VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL (0x03 << 2) + + + + + + + + + + + + + + + + + + + +#define VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK 0xF0 +#define VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK 0x0F + +#define VL53L1_GROUPEDPARAMETERHOLD_ID_MASK 0x02 + + + + +#define VL53L1_EWOK_I2C_DEV_ADDR_DEFAULT 0x29 + + +#define VL53L1_OSC_FREQUENCY 0x00 +#define VL53L1_OSC_TRIM_DEFAULT 0x00 +#define VL53L1_OSC_FREQ_SET_DEFAULT 0x00 + +#define VL53L1_RANGE_HISTOGRAM_REF 0x08 +#define VL53L1_RANGE_HISTOGRAM_RET 0x10 +#define VL53L1_RANGE_HISTOGRAM_BOTH 0x18 +#define VL53L1_RANGE_HISTOGRAM_INIT 0x20 +#define VL53L1_RANGE_VHV_INIT 0x40 + + + +#define VL53L1_RESULT_RANGE_STATUS 0x1F + + + +#define VL53L1_SYSTEM__SEED_CONFIG__MANUAL 0x00 +#define VL53L1_SYSTEM__SEED_CONFIG__STANDARD 0x01 +#define VL53L1_SYSTEM__SEED_CONFIG__EVEN_UPDATE_ONLY 0x02 + + + +#define VL53L1_INTERRUPT_CONFIG_LEVEL_LOW 0x00 +#define VL53L1_INTERRUPT_CONFIG_LEVEL_HIGH 0x01 +#define VL53L1_INTERRUPT_CONFIG_OUT_OF_WINDOW 0x02 +#define VL53L1_INTERRUPT_CONFIG_IN_WINDOW 0x03 +#define VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY 0x20 + + + +#define VL53L1_CLEAR_RANGE_INT 0x01 +#define VL53L1_CLEAR_ERROR_INT 0x02 + + + +#define VL53L1_SEQUENCE_VHV_EN 0x01 +#define VL53L1_SEQUENCE_PHASECAL_EN 0x02 +#define VL53L1_SEQUENCE_REFERENCE_PHASE_EN 0x04 +#define VL53L1_SEQUENCE_DSS1_EN 0x08 +#define VL53L1_SEQUENCE_DSS2_EN 0x10 +#define VL53L1_SEQUENCE_MM1_EN 0x20 +#define VL53L1_SEQUENCE_MM2_EN 0x40 +#define VL53L1_SEQUENCE_RANGE_EN 0x80 + + + +#define VL53L1_DSS_CONTROL__ROI_SUBTRACT 0x20 +#define VL53L1_DSS_CONTROL__ROI_INTERSECT 0x10 + +#define VL53L1_DSS_CONTROL__MODE_DISABLED 0x00 +#define VL53L1_DSS_CONTROL__MODE_TARGET_RATE 0x01 +#define VL53L1_DSS_CONTROL__MODE_EFFSPADS 0x02 +#define VL53L1_DSS_CONTROL__MODE_BLOCKSELECT 0x03 + + + + + + + + + + +#define VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD 0x45 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_ARRAY_ONLY 0x05 +#define VL53L1_RANGING_CORE__SPAD_READOUT__REFERENCE_ARRAY_ONLY 0x55 +#define VL53L1_RANGING_CORE__SPAD_READOUT__RETURN_SPLIT_ARRAY 0x25 +#define VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES 0xF5 + + +#define VL53L1_LASER_SAFETY__KEY_VALUE 0x6C + + + + + + + + + + +#define VL53L1_RANGE_STATUS__RANGE_STATUS_MASK 0x1F +#define VL53L1_RANGE_STATUS__MAX_THRESHOLD_HIT_MASK 0x20 +#define VL53L1_RANGE_STATUS__MIN_THRESHOLD_HIT_MASK 0x40 +#define VL53L1_RANGE_STATUS__GPH_ID_RANGE_STATUS_MASK 0x80 + + + + + + + + + +#define VL53L1_INTERRUPT_STATUS__INT_STATUS_MASK 0x07 +#define VL53L1_INTERRUPT_STATUS__INT_ERROR_STATUS_MASK 0x18 +#define VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK 0x20 + + + + + +#endif + + + + + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_register_structs.h b/drivers/oneplus/vl53L1/inc/vl53l1_register_structs.h new file mode 100755 index 0000000000000000000000000000000000000000..c5d70adf68f20d41573eb59ec730a4fc02f09731 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_register_structs.h @@ -0,0 +1,4872 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_REGISTER_STRUCTS_H_ +#define _VL53L1_REGISTER_STRUCTS_H_ + +#include "vl53l1_types.h" +#include "vl53l1_register_map.h" + +#define VL53L1_STATIC_NVM_MANAGED_I2C_INDEX \ + VL53L1_I2C_SLAVE__DEVICE_ADDRESS +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX \ + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0 +#define VL53L1_STATIC_CONFIG_I2C_INDEX \ + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS +#define VL53L1_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE +#define VL53L1_TIMING_CONFIG_I2C_INDEX \ + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_DYNAMIC_CONFIG_I2C_INDEX \ + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0 +#define VL53L1_SYSTEM_CONTROL_I2C_INDEX \ + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE +#define VL53L1_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_RESULT__INTERRUPT_STATUS +#define VL53L1_CORE_RESULTS_I2C_INDEX \ + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_DEBUG_RESULTS_I2C_INDEX \ + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE +#define VL53L1_NVM_COPY_DATA_I2C_INDEX \ + VL53L1_IDENTIFICATION__MODEL_ID +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 +#define VL53L1_PATCH_DEBUG_I2C_INDEX \ + VL53L1_RESULT__DEBUG_STATUS +#define VL53L1_GPH_GENERAL_CONFIG_I2C_INDEX \ + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH +#define VL53L1_GPH_STATIC_CONFIG_I2C_INDEX \ + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL +#define VL53L1_GPH_TIMING_CONFIG_I2C_INDEX \ + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI +#define VL53L1_FW_INTERNAL_I2C_INDEX \ + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV +#define VL53L1_PATCH_RESULTS_I2C_INDEX \ + VL53L1_DSS_CALC__ROI_CTRL +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START +#define VL53L1_SHADOW_CORE_RESULTS_I2C_INDEX \ + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0 + +#define VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES 11 +#define VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES 23 +#define VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES 32 +#define VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES 22 +#define VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES 23 +#define VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES 18 +#define VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES 5 +#define VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES 56 +#define VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES 49 +#define VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 44 +#define VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 +#define VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES 2 +#define VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES 5 +#define VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES 6 +#define VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES 16 +#define VL53L1_FW_INTERNAL_I2C_SIZE_BYTES 2 +#define VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES 90 +#define VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES 82 +#define VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES 33 + + + + + + + + + + + + +typedef struct { + uint8_t i2c_slave__device_address; + + + + + + + + + + + uint8_t ana_config__vhv_ref_sel_vddpix; + + + + + + + + + + + uint8_t ana_config__vhv_ref_sel_vquench; + + + + + + + + + + + uint8_t ana_config__reg_avdd1v2_sel; + + + + + + + + + + + uint8_t ana_config__fast_osc__trim; + + + + + + + + + + + uint16_t osc_measured__fast_osc__frequency; + + + + + + + + + + + uint8_t vhv_config__timeout_macrop_loop_bound; + + + + + + + + + + + + uint8_t vhv_config__count_thresh; + + + + + + + + + + + uint8_t vhv_config__offset; + + + + + + + + + + + uint8_t vhv_config__init; + + + + + + + + + + + +} VL53L1_static_nvm_managed_t; + + + + + + + + + + + + +typedef struct { + uint8_t global_config__spad_enables_ref_0; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_1; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_2; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_3; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_4; + + + + + + + + + + + uint8_t global_config__spad_enables_ref_5; + + + + + + + + + + + uint8_t global_config__ref_en_start_select; + + + + + + + + + + + uint8_t ref_spad_man__num_requested_ref_spads; + + + + + + + + + + + uint8_t ref_spad_man__ref_location; + + + + + + + + + + + uint16_t algo__crosstalk_compensation_plane_offset_kcps; + + + + + + + + + + + int16_t algo__crosstalk_compensation_x_plane_gradient_kcps; + + + + + + + + + + + int16_t algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + + + + + + + uint16_t ref_spad_char__total_rate_target_mcps; + + + + + + + + + + + int16_t algo__part_to_part_range_offset_mm; + + + + + + + + + + + int16_t mm_config__inner_offset_mm; + + + + + + + + + + + int16_t mm_config__outer_offset_mm; + + + + + + + + + + +} VL53L1_customer_nvm_managed_t; + + + + + + + + + + + + +typedef struct { + uint16_t dss_config__target_total_rate_mcps; + + + + + + + + + + + uint8_t debug__ctrl; + + + + + + + + + + + uint8_t test_mode__ctrl; + + + + + + + + + + + uint8_t clk_gating__ctrl; + + + + + + + + + + + + + + uint8_t nvm_bist__ctrl; + + + + + + + + + + + + uint8_t nvm_bist__num_nvm_words; + + + + + + + + + + + uint8_t nvm_bist__start_address; + + + + + + + + + + + uint8_t host_if__status; + + + + + + + + + + + uint8_t pad_i2c_hv__config; + + + + + + + + + + + + + + + + uint8_t pad_i2c_hv__extsup_config; + + + + + + + + + + + uint8_t gpio_hv_pad__ctrl; + + + + + + + + + + + + uint8_t gpio_hv_mux__ctrl; + + + + + + + + + + + + uint8_t gpio__tio_hv_status; + + + + + + + + + + + + uint8_t gpio__fio_hv_status; + + + + + + + + + + + uint8_t ana_config__spad_sel_pswidth; + + + + + + + + + + + uint8_t ana_config__vcsel_pulse_width_offset; + + + + + + + + + + + uint8_t ana_config__fast_osc__config_ctrl; + + + + + + + + + + + uint8_t sigma_estimator__effective_pulse_width_ns; + + + + + + + + + + + uint8_t sigma_estimator__effective_ambient_width_ns; + + + + + + + + + + + uint8_t sigma_estimator__sigma_ref_mm; + + + + + + + + + + + uint8_t algo__crosstalk_compensation_valid_height_mm; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_0; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_1; + + + + + + + + + + + uint16_t algo__range_ignore_threshold_mcps; + + + + + + + + + + + uint8_t algo__range_ignore_valid_height_mm; + + + + + + + + + + + uint8_t algo__range_min_clip; + + + + + + + + + + + + uint8_t algo__consistency_check__tolerance; + + + + + + + + + + + uint8_t spare_host_config__static_config_spare_2; + + + + + + + + + + + uint8_t sd_config__reset_stages_msb; + + + + + + + + + + + uint8_t sd_config__reset_stages_lsb; + + + + + + + + + + + +} VL53L1_static_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph_config__stream_count_update_value; + + + + + + + + + + + uint8_t global_config__stream_divider; + + + + + + + + + + + uint8_t system__interrupt_config_gpio; + + + + + + + + + + + + + + + + uint8_t cal_config__vcsel_start; + + + + + + + + + + + uint16_t cal_config__repeat_rate; + + + + + + + + + + + uint8_t global_config__vcsel_width; + + + + + + + + + + + uint8_t phasecal_config__timeout_macrop; + + + + + + + + + + + uint8_t phasecal_config__target; + + + + + + + + + + + uint8_t phasecal_config__override; + + + + + + + + + + + uint8_t dss_config__roi_mode_control; + + + + + + + + + + + + uint16_t system__thresh_rate_high; + + + + + + + + + + + uint16_t system__thresh_rate_low; + + + + + + + + + + + uint16_t dss_config__manual_effective_spads_select; + + + + + + + + + + + uint8_t dss_config__manual_block_select; + + + + + + + + + + + uint8_t dss_config__aperture_attenuation; + + + + + + + + + + + uint8_t dss_config__max_spads_limit; + + + + + + + + + + + uint8_t dss_config__min_spads_limit; + + + + + + + + + + +} VL53L1_general_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t mm_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t mm_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t range_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t range_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t range_config__vcsel_period_a; + + + + + + + + + + + uint8_t range_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t range_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t range_config__vcsel_period_b; + + + + + + + + + + + uint16_t range_config__sigma_thresh; + + + + + + + + + + + uint16_t range_config__min_count_rate_rtn_limit_mcps; + + + + + + + + + + + uint8_t range_config__valid_phase_low; + + + + + + + + + + + uint8_t range_config__valid_phase_high; + + + + + + + + + + + uint32_t system__intermeasurement_period; + + + + + + + + + + + uint8_t system__fractional_enable; + + + + + + + + + + +} VL53L1_timing_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t system__grouped_parameter_hold_0; + + + + + + + + + + + + uint16_t system__thresh_high; + + + + + + + + + + + uint16_t system__thresh_low; + + + + + + + + + + + uint8_t system__enable_xtalk_per_quadrant; + + + + + + + + + + + uint8_t system__seed_config; + + + + + + + + + + + + uint8_t sd_config__woi_sd0; + + + + + + + + + + + uint8_t sd_config__woi_sd1; + + + + + + + + + + + uint8_t sd_config__initial_phase_sd0; + + + + + + + + + + + uint8_t sd_config__initial_phase_sd1; + + + + + + + + + + + uint8_t system__grouped_parameter_hold_1; + + + + + + + + + + + + uint8_t sd_config__first_order_select; + + + + + + + + + + + + uint8_t sd_config__quantifier; + + + + + + + + + + + uint8_t roi_config__user_roi_centre_spad; + + + + + + + + + + + uint8_t roi_config__user_roi_requested_global_xy_size; + + + + + + + + + + + uint8_t system__sequence_config; + + + + + + + + + + + + + + + + + + uint8_t system__grouped_parameter_hold; + + + + + + + + + + + +} VL53L1_dynamic_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t power_management__go1_power_force; + + + + + + + + + + + uint8_t system__stream_count_ctrl; + + + + + + + + + + + uint8_t firmware__enable; + + + + + + + + + + + uint8_t system__interrupt_clear; + + + + + + + + + + + + uint8_t system__mode_start; + + + + + + + + + + + + + + + +} VL53L1_system_control_t; + + + + + + + + + + + + +typedef struct { + uint8_t result__interrupt_status; + + + + + + + + + + + + + uint8_t result__range_status; + + + + + + + + + + + + + + uint8_t result__report_status; + + + + + + + + + + + uint8_t result__stream_count; + + + + + + + + + + + uint16_t result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__sigma_sd0; + + + + + + + + + + + uint16_t result__phase_sd0; + + + + + + + + + + + uint16_t result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t result__sigma_sd1; + + + + + + + + + + + uint16_t result__phase_sd1; + + + + + + + + + + + uint16_t result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t result__spare_0_sd1; + + + + + + + + + + + uint16_t result__spare_1_sd1; + + + + + + + + + + + uint16_t result__spare_2_sd1; + + + + + + + + + + + uint8_t result__spare_3_sd1; + + + + + + + + + + + uint8_t result__thresh_info; + + + + + + + + + + + +} VL53L1_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t result_core__spare_0; + + + + + + + + + + +} VL53L1_core_results_t; + + + + + + + + + + + + +typedef struct { + uint16_t phasecal_result__reference_phase; + + + + + + + + + + + uint8_t phasecal_result__vcsel_start; + + + + + + + + + + + uint8_t ref_spad_char_result__num_actual_ref_spads; + + + + + + + + + + + uint8_t ref_spad_char_result__ref_location; + + + + + + + + + + + uint8_t vhv_result__coldboot_status; + + + + + + + + + + + uint8_t vhv_result__search_result; + + + + + + + + + + + uint8_t vhv_result__latest_setting; + + + + + + + + + + + uint16_t result__osc_calibrate_val; + + + + + + + + + + + uint8_t ana_config__powerdown_go1; + + + + + + + + + + + + uint8_t ana_config__ref_bg_ctrl; + + + + + + + + + + + + uint8_t ana_config__regdvdd1v2_ctrl; + + + + + + + + + + + + + uint8_t ana_config__osc_slow_ctrl; + + + + + + + + + + + + + uint8_t test_mode__status; + + + + + + + + + + + uint8_t firmware__system_status; + + + + + + + + + + + + uint8_t firmware__mode_status; + + + + + + + + + + + uint8_t firmware__secondary_mode_status; + + + + + + + + + + + uint16_t firmware__cal_repeat_rate_counter; + + + + + + + + + + + uint16_t gph__system__thresh_high; + + + + + + + + + + + uint16_t gph__system__thresh_low; + + + + + + + + + + + uint8_t gph__system__enable_xtalk_per_quadrant; + + + + + + + + + + + uint8_t gph__spare_0; + + + + + + + + + + + + + uint8_t gph__sd_config__woi_sd0; + + + + + + + + + + + uint8_t gph__sd_config__woi_sd1; + + + + + + + + + + + uint8_t gph__sd_config__initial_phase_sd0; + + + + + + + + + + + uint8_t gph__sd_config__initial_phase_sd1; + + + + + + + + + + + uint8_t gph__sd_config__first_order_select; + + + + + + + + + + + + uint8_t gph__sd_config__quantifier; + + + + + + + + + + + uint8_t gph__roi_config__user_roi_centre_spad; + + + + + + + + + + + uint8_t gph__roi_config__user_roi_requested_global_xy_size; + + + + + + + + + + + uint8_t gph__system__sequence_config; + + + + + + + + + + + + + + + + + + uint8_t gph__gph_id; + + + + + + + + + + + uint8_t system__interrupt_set; + + + + + + + + + + + + uint8_t interrupt_manager__enables; + + + + + + + + + + + + + + + uint8_t interrupt_manager__clear; + + + + + + + + + + + + + + + uint8_t interrupt_manager__status; + + + + + + + + + + + + + + + uint8_t mcu_to_host_bank__wr_access_en; + + + + + + + + + + + uint8_t power_management__go1_reset_status; + + + + + + + + + + + uint8_t pad_startup_mode__value_ro; + + + + + + + + + + + + uint8_t pad_startup_mode__value_ctrl; + + + + + + + + + + + + + + uint32_t pll_period_us; + + + + + + + + + + + uint32_t interrupt_scheduler__data_out; + + + + + + + + + + + uint8_t nvm_bist__complete; + + + + + + + + + + + uint8_t nvm_bist__status; + + + + + + + + + + +} VL53L1_debug_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t identification__model_id; + + + + + + + + + + + uint8_t identification__module_type; + + + + + + + + + + + uint8_t identification__revision_id; + + + + + + + + + + + + uint16_t identification__module_id; + + + + + + + + + + + uint8_t ana_config__fast_osc__trim_max; + + + + + + + + + + + uint8_t ana_config__fast_osc__freq_set; + + + + + + + + + + + uint8_t ana_config__vcsel_trim; + + + + + + + + + + + uint8_t ana_config__vcsel_selion; + + + + + + + + + + + uint8_t ana_config__vcsel_selion_max; + + + + + + + + + + + uint8_t protected_laser_safety__lock_bit; + + + + + + + + + + + uint8_t laser_safety__key; + + + + + + + + + + + uint8_t laser_safety__key_ro; + + + + + + + + + + + uint8_t laser_safety__clip; + + + + + + + + + + + uint8_t laser_safety__mult; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_0; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_1; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_2; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_3; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_4; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_5; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_6; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_7; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_8; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_9; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_10; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_11; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_12; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_13; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_14; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_15; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_16; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_17; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_18; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_19; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_20; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_21; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_22; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_23; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_24; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_25; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_26; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_27; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_28; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_29; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_30; + + + + + + + + + + + uint8_t global_config__spad_enables_rtn_31; + + + + + + + + + + + uint8_t roi_config__mode_roi_centre_spad; + + + + + + + + + + + uint8_t roi_config__mode_roi_xy_size; + + + + + + + + + + +} VL53L1_nvm_copy_data_t; + + + + + + + + + + + + +typedef struct { + uint8_t prev_shadow_result__interrupt_status; + + + + + + + + + + + + + uint8_t prev_shadow_result__range_status; + + + + + + + + + + + + + + uint8_t prev_shadow_result__report_status; + + + + + + + + + + + uint8_t prev_shadow_result__stream_count; + + + + + + + + + + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__sigma_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__phase_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t + psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t prev_shadow_result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__sigma_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__phase_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_0_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_1_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_2_sd1; + + + + + + + + + + + uint16_t prev_shadow_result__spare_3_sd1; + + + + + + + + + + +} VL53L1_prev_shadow_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t prev_shadow_result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t prev_shadow_result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t prev_shadow_result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t prev_shadow_result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t prev_shadow_result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t prev_shadow_result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t prev_shadow_result_core__spare_0; + + + + + + + + + + +} VL53L1_prev_shadow_core_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t result__debug_status; + + + + + + + + + + + uint8_t result__debug_stage; + + + + + + + + + + +} VL53L1_patch_debug_t; + + + + + + + + + + + + +typedef struct { + uint16_t gph__system__thresh_rate_high; + + + + + + + + + + + uint16_t gph__system__thresh_rate_low; + + + + + + + + + + + uint8_t gph__system__interrupt_config_gpio; + + + + + + + + + + + + + + + +} VL53L1_gph_general_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph__dss_config__roi_mode_control; + + + + + + + + + + + + uint16_t gph__dss_config__manual_effective_spads_select; + + + + + + + + + + + uint8_t gph__dss_config__manual_block_select; + + + + + + + + + + + uint8_t gph__dss_config__max_spads_limit; + + + + + + + + + + + uint8_t gph__dss_config__min_spads_limit; + + + + + + + + + + +} VL53L1_gph_static_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t gph__mm_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t gph__mm_config__timeout_macrop_b_lo; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_a_hi; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_a_lo; + + + + + + + + + + + uint8_t gph__range_config__vcsel_period_a; + + + + + + + + + + + uint8_t gph__range_config__vcsel_period_b; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_b_hi; + + + + + + + + + + + uint8_t gph__range_config__timeout_macrop_b_lo; + + + + + + + + + + + uint16_t gph__range_config__sigma_thresh; + + + + + + + + + + + uint16_t gph__range_config__min_count_rate_rtn_limit_mcps; + + + + + + + + + + + uint8_t gph__range_config__valid_phase_low; + + + + + + + + + + + uint8_t gph__range_config__valid_phase_high; + + + + + + + + + + +} VL53L1_gph_timing_config_t; + + + + + + + + + + + + +typedef struct { + uint8_t firmware__internal_stream_count_div; + + + + + + + + + + + uint8_t firmware__internal_stream_counter_val; + + + + + + + + + + +} VL53L1_fw_internal_t; + + + + + + + + + + + + +typedef struct { + uint8_t dss_calc__roi_ctrl; + + + + + + + + + + + + uint8_t dss_calc__spare_1; + + + + + + + + + + + uint8_t dss_calc__spare_2; + + + + + + + + + + + uint8_t dss_calc__spare_3; + + + + + + + + + + + uint8_t dss_calc__spare_4; + + + + + + + + + + + uint8_t dss_calc__spare_5; + + + + + + + + + + + uint8_t dss_calc__spare_6; + + + + + + + + + + + uint8_t dss_calc__spare_7; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_0; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_1; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_2; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_3; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_4; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_5; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_6; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_7; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_8; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_9; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_10; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_11; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_12; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_13; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_14; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_15; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_16; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_17; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_18; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_19; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_20; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_21; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_22; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_23; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_24; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_25; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_26; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_27; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_28; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_29; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_30; + + + + + + + + + + + uint8_t dss_calc__user_roi_spad_en_31; + + + + + + + + + + + uint8_t dss_calc__user_roi_0; + + + + + + + + + + + uint8_t dss_calc__user_roi_1; + + + + + + + + + + + uint8_t dss_calc__mode_roi_0; + + + + + + + + + + + uint8_t dss_calc__mode_roi_1; + + + + + + + + + + + uint8_t sigma_estimator_calc__spare_0; + + + + + + + + + + + uint16_t vhv_result__peak_signal_rate_mcps; + + + + + + + + + + + uint32_t vhv_result__signal_total_events_ref; + + + + + + + + + + + uint16_t phasecal_result__phase_output_ref; + + + + + + + + + + + uint16_t dss_result__total_rate_per_spad; + + + + + + + + + + + uint8_t dss_result__enabled_blocks; + + + + + + + + + + + uint16_t dss_result__num_requested_spads; + + + + + + + + + + + uint16_t mm_result__inner_intersection_rate; + + + + + + + + + + + uint16_t mm_result__outer_complement_rate; + + + + + + + + + + + uint16_t mm_result__total_offset; + + + + + + + + + + + uint32_t xtalk_calc__xtalk_for_enabled_spads; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_user_roi_kcps; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_mm_inner_roi_kcps; + + + + + + + + + + + uint32_t xtalk_result__avg_xtalk_mm_outer_roi_kcps; + + + + + + + + + + + uint32_t range_result__accum_phase; + + + + + + + + + + + uint16_t range_result__offset_corrected_range; + + + + + + + + + + +} VL53L1_patch_results_t; + + + + + + + + + + + + +typedef struct { + uint8_t shadow_phasecal_result__vcsel_start; + + + + + + + + + + + uint8_t shadow_result__interrupt_status; + + + + + + + + + + + + + uint8_t shadow_result__range_status; + + + + + + + + + + + + + + uint8_t shadow_result__report_status; + + + + + + + + + + + uint8_t shadow_result__stream_count; + + + + + + + + + + + uint16_t shadow_result__dss_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__ambient_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__sigma_sd0; + + + + + + + + + + + uint16_t shadow_result__phase_sd0; + + + + + + + + + + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd0; + + + + + + + + + + + uint16_t + shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__mm_inner_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__mm_outer_actual_effective_spads_sd0; + + + + + + + + + + + uint16_t shadow_result__avg_signal_count_rate_mcps_sd0; + + + + + + + + + + + uint16_t shadow_result__dss_actual_effective_spads_sd1; + + + + + + + + + + + uint16_t shadow_result__peak_signal_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t shadow_result__ambient_count_rate_mcps_sd1; + + + + + + + + + + + uint16_t shadow_result__sigma_sd1; + + + + + + + + + + + uint16_t shadow_result__phase_sd1; + + + + + + + + + + + uint16_t shadow_result__final_crosstalk_corrected_range_mm_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_0_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_1_sd1; + + + + + + + + + + + uint16_t shadow_result__spare_2_sd1; + + + + + + + + + + + uint8_t shadow_result__spare_3_sd1; + + + + + + + + + + + uint8_t shadow_result__thresh_info; + + + + + + + + + + + + uint8_t shadow_phasecal_result__reference_phase_hi; + + + + + + + + + + + uint8_t shadow_phasecal_result__reference_phase_lo; + + + + + + + + + + +} VL53L1_shadow_system_results_t; + + + + + + + + + + + + +typedef struct { + uint32_t shadow_result_core__ambient_window_events_sd0; + + + + + + + + + + + uint32_t shadow_result_core__ranging_total_events_sd0; + + + + + + + + + + + int32_t shadow_result_core__signal_total_events_sd0; + + + + + + + + + + + uint32_t shadow_result_core__total_periods_elapsed_sd0; + + + + + + + + + + + uint32_t shadow_result_core__ambient_window_events_sd1; + + + + + + + + + + + uint32_t shadow_result_core__ranging_total_events_sd1; + + + + + + + + + + + int32_t shadow_result_core__signal_total_events_sd1; + + + + + + + + + + + uint32_t shadow_result_core__total_periods_elapsed_sd1; + + + + + + + + + + + uint8_t shadow_result_core__spare_0; + + + + + + + + + + +} VL53L1_shadow_core_results_t; + + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_silicon_core.h b/drivers/oneplus/vl53L1/inc/vl53l1_silicon_core.h new file mode 100755 index 0000000000000000000000000000000000000000..f9eea814d65f70f1683ab0a8b9abac838f886065 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_silicon_core.h @@ -0,0 +1,134 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_SILICON_CORE_H_ +#define _VL53L1_SILICON_CORE_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_tuning_parm_defaults.h b/drivers/oneplus/vl53L1/inc/vl53l1_tuning_parm_defaults.h new file mode 100755 index 0000000000000000000000000000000000000000..119d67e0b17eb342f0840e153f59b75ab501d28b --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_tuning_parm_defaults.h @@ -0,0 +1,410 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_TUNING_PARM_DEFAULTS_H_ +#define _VL53L1_TUNING_PARM_DEFAULTS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + +#define VL53L1_TUNINGPARM_VERSION_DEFAULT \ +((uint16_t) 27) +#define VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT \ +((uint16_t) 14) +#define VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT \ +((uint16_t) 12180) +#define VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT \ +((uint8_t) 4) +#define VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT \ +((uint8_t) 112) +#define VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT \ +((int32_t) 16) +#define VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT \ +((uint16_t) 4157) +#define VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT \ +((int32_t) 100) +#define VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 160) +#define VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT \ +((uint16_t) 1987) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT \ +((uint16_t) 250) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT \ +((uint16_t) 2048) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 5) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT \ +((int16_t) -50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT \ +((int16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT \ +((uint16_t) 50) +#define VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 64000) +#define VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT \ +((uint8_t) 80) +#define VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 512) +#define VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT \ +((uint8_t) 33) +#define VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT \ +((uint16_t) 0) +#define VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT \ +((uint16_t) 2011) +#define VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT \ +((uint16_t) 60) +#define VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT \ +((uint16_t) 128) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT \ +((uint8_t) 16) +#define VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT \ +((uint8_t) 64) +#define VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT \ +((uint8_t) 2) +#define VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT \ +((int16_t) 0) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT \ +((uint8_t) 14) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT \ +((uint8_t) 10) +#define VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT \ +((uint8_t) 6) +#define VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT \ +((uint8_t) 1) +#define VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT \ +((uint8_t) 32) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT \ +((uint16_t) 15) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT \ +((uint16_t) 52) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT \ +((uint16_t) 200) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT \ +((uint16_t) 364) +#define VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT \ +((uint16_t) 400) +#define VL53L1_TUNINGPARM_VHV_LOOPBOUND_DEFAULT \ +((uint8_t) 129) +#define VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 11) +#define VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 1280) +#define VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT \ +((uint8_t) 7) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT \ +((int16_t) -70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT \ +((int16_t) 70) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT \ +((uint16_t) 64000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT \ +((uint16_t) 140) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT \ +((uint32_t) 10000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT \ +((uint8_t) 8) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT \ +((uint8_t) 40) +#define VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT \ +((uint8_t) 9) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT \ +((uint16_t) 16) +#define VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT \ +((uint16_t) 8) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT \ +((uint8_t) 18) +#define VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT \ +((uint8_t) 15) +#define VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT \ +((uint16_t) 12) +#define VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 5120) +#define VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT \ +((uint16_t) 2560) +#define VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 15000) +#define VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 9000) +#define VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 6000) +#define VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1000) +#define VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2000) +#define VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 63000) +#define VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 2500) +#define VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 13000) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT \ +((uint16_t) 512) +#define VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT \ +((uint32_t) 500) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT \ +((uint32_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 200) +#define VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT \ +((uint32_t) 10240) +#define VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT \ +((uint32_t) 4096) +#define VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT \ +((uint32_t) 1046528) +#define VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT \ +((int16_t) 256) +#define VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT \ +((uint8_t) 0) +#define VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT \ +((uint32_t) 1280) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT \ +((uint32_t) 57671680) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT \ +((uint32_t) 10) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT \ +((uint32_t) 2048) +#define VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT \ +((uint16_t) 900) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT \ +((uint8_t) 3) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 1) +#define VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT \ +((uint32_t) 8000) +#define VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT \ +((uint16_t) 10240) + + +#ifdef __cplusplus +} +#endif + +#endif + + + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_wait.h b/drivers/oneplus/vl53L1/inc/vl53l1_wait.h new file mode 100755 index 0000000000000000000000000000000000000000..eb19e3b9bcb4652b54eca1efed49eeddaf27445e --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_wait.h @@ -0,0 +1,319 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_WAIT_H_ +#define _VL53L1_WAIT_H_ + +#include "vl53l1_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev); + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready); + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms); + + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/inc/vl53l1_zone_presets.h b/drivers/oneplus/vl53L1/inc/vl53l1_zone_presets.h new file mode 100755 index 0000000000000000000000000000000000000000..34f3652f0a950b1865c51656b7f49706ec6ccf97 --- /dev/null +++ b/drivers/oneplus/vl53L1/inc/vl53l1_zone_presets.h @@ -0,0 +1,183 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifndef _VL53L1_ZONE_PRESETS_H_ +#define _VL53L1_ZONE_PRESETS_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + + + + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata); + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg); + + + + + + + + + + + + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/drivers/oneplus/vl53L1/ipp/ipp_linux.c b/drivers/oneplus/vl53L1/ipp/ipp_linux.c new file mode 100755 index 0000000000000000000000000000000000000000..7b8c5b76e2a1c90a7f8b68cbacbba63cd7eeab13 --- /dev/null +++ b/drivers/oneplus/vl53L1/ipp/ipp_linux.c @@ -0,0 +1,343 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file ipp_linux.c kernel side implementation of vl53l1 protected processing + * + * @date Sep 1, 2016 + * @author : imaging + * + * @ingroup ipp_dev + */ + +#include "stmvl53l1.h" + +#define IPP_ERR_CODE (VL53L1_ERROR_PLATFORM_SPECIFIC_START-1) + +static int stmvl53l1_ipp_do_wrapper(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout, int payload_out) +{ + int rc; + + if (data->ipp.buzy) { + vl53l1_errmsg("try exec new ipp but still buzy on previous"); + /* TODO shall we discard it and push new ? */ + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pin->payload > IPP_WORK_MAX_PAYLOAD); + stmvl531_ipp_tim_start(data); + rc = stmvl53l1_ipp_do(data, pin, pout); + if (rc != 0) { + vl53l1_errmsg("stmvl53l1_ipp_do err %d\n", rc); + rc = IPP_ERR_CODE; + goto done; + } + //vl53l1_dbgmsg("ipp ok \n"); + /* check what we got back if valid answer error etc */ + if (pout->status) { + vl53l1_errmsg("ipp error status %d from user", pout->status); + if (pout->status >= stmvl53l1_ipp_status_proc_code) + rc = pout->status & (stmvl53l1_ipp_status_proc_code-1); + else + rc = IPP_ERR_CODE; + goto done; + } + WARN_ON(pout->payload > IPP_WORK_MAX_PAYLOAD); + if (pout->payload != payload_out) { + /* bad formated answer */ + vl53l1_errmsg("bad payload %d != %d in ipp work back", + pout->payload, payload_out); + rc = IPP_ERR_CODE; + goto done; + } + stmvl531_ipp_tim_stop(data); + /*stmvl531_ipp_stat(data, "ipp #%5x to=%3d fm=%3d in %5ld us", + pin->xfer_id, pin->payload, + pout->payload, + stmvl531_ipp_time(data));*/ + + rc = 0; +done: + + return rc; +} + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + VL53L1_range_results_t *presults) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_range_results_t *presults_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 5); + IPP_SET_ARG_PTR(pin->data, 0, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 2, ppost_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + IPP_SET_ARG_PTR(pin->data, 4, pxtalk); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_cal_hist; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, presults_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(presults, presults_ipp, sizeof(*presults)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + int16_t *pambient_dmax_mm_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 4); + IPP_SET_ARG(pin->data, 0, target_reflectance); + IPP_SET_ARG_PTR(pin->data, 1, pdmax_cal); + IPP_SET_ARG_PTR(pin->data, 2, pdmax_cfg); + IPP_SET_ARG_PTR(pin->data, 3, pbins); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_hist_ambient_dmax; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pambient_dmax_mm_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pambient_dmax_mm, pambient_dmax_mm_ipp, + sizeof(*pambient_dmax_mm)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_xtalk_histogram_data_t *pxtalk_shape_ipp; + VL53L1_xtalk_calibration_results_t *pxtalk_cal_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 1); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_ranges); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_xtalk_calibration; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 2); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_shape_ipp); + IPP_OUT_ARG_PTR(pout->data, 1, pxtalk_cal_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_shape, pxtalk_shape_ipp, sizeof(*pxtalk_shape)); + memcpy(pxtalk_cal, pxtalk_cal_ipp, sizeof(*pxtalk_cal)); + + rc = 0; +done: + + return rc; +} + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples) +{ + struct stmvl53l1_data *data = (struct stmvl53l1_data *) + container_of(dev, struct stmvl53l1_data, stdev); + struct ipp_work_t *pout = &data->ipp.work_out; + struct ipp_work_t *pin = &data->ipp.work; + int rc; + VL53L1_histogram_bin_data_t *pxtalk_avg_samples_ipp; + + IPP_SERIALIZE_VAR; + + /* setup pin */ + IPP_SERIALIZE_START(pin->data, 3); + IPP_SET_ARG_PTR(pin->data, 0, pxtalk_results); + IPP_SET_ARG(pin->data, 1, expected_target_distance_mm); + IPP_SET_ARG(pin->data, 2, higher_reflectance); + pin->payload = IPP_SERIALIZE_PAYLAOD(); + pin->process_no = stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples; + + /* setup pout */ + IPP_SERIALIZE_START(pout->data, 1); + IPP_OUT_ARG_PTR(pout->data, 0, pxtalk_avg_samples_ipp); + + /* do ipp */ + rc = stmvl53l1_ipp_do_wrapper(data, pin, pout, IPP_SERIALIZE_PAYLAOD()); + if (rc) + goto done; + + /* copy output */ + memcpy(pxtalk_avg_samples, pxtalk_avg_samples_ipp, + sizeof(*pxtalk_avg_samples)); + + rc = 0; +done: + + return rc; +} diff --git a/drivers/oneplus/vl53L1/src/vl53l1_api.c b/drivers/oneplus/vl53L1/src/vl53l1_api.c new file mode 100755 index 0000000000000000000000000000000000000000..bb49c457224e4635f79be3c7e13fcbd5d3e09daa --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_api.c @@ -0,0 +1,3716 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_api.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_core.h" +#include "vl53l1_api_calibration.h" +#include "vl53l1_wait.h" +#include "vl53l1_preset_setup.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_api_core.h" +#include "vl53l1_nvm.h" + + + +#define ZONE_CHECK VL53L1_MAX_USER_ZONES + +#if ZONE_CHECK < 5 +#error Must define at least 5 zones in MAX_USER_ZONES constant +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, \ + fmt, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE +#define trace_print(level, ...) trace_print_module_function(\ + VL53L1_TRACE_MODULE_API, level, VL53L1_TRACE_FUNCTION_NONE, \ + ##__VA_ARGS__) +#endif + +#ifndef MIN +#define MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2)) +#endif +#ifndef MAX +#define MAX(v1, v2) ((v1) < (v2) ? (v2) : (v1)) +#endif + +#define DMAX_REFLECTANCE_IDX 2 + + + + + + + +#define LOWPOWER_AUTO_VHV_LOOP_DURATION_US 245 +#define LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING 1448 +#define LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING 2100 + +#define FDA_MAX_TIMING_BUDGET_US 550000 + + + + + + + + + +static int32_t BDTable[VL53L1_TUNING_MAX_TUNABLE_KEY] = { + TUNING_VERSION, + TUNING_PROXY_MIN, + TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM, + TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER, + TUNING_MIN_AMBIENT_DMAX_VALID, + TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER, + TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM, + TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT +}; + + + +static VL53L1_Error SingleTargetXTalkCalibration(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint32_t sum_ranging = 0; + uint32_t sum_spads = 0; + FixPoint1616_t sum_signalRate = 0; + FixPoint1616_t total_count = 0; + uint8_t xtalk_meas = 0; + uint8_t xtalk_measmax = + BDTable[VL53L1_TUNING_SINGLE_TARGET_XTALK_SAMPLE_NUMBER]; + VL53L1_RangingMeasurementData_t RMData; + FixPoint1616_t xTalkStoredMeanSignalRate; + FixPoint1616_t xTalkStoredMeanRange; + FixPoint1616_t xTalkStoredMeanRtnSpads; + uint32_t xTalkStoredMeanRtnSpadsAsInt; + uint32_t xTalkCalDistanceAsInt; + FixPoint1616_t XTalkCompensationRateMegaCps; + uint32_t signalXTalkTotalPerSpad; + VL53L1_PresetModes PresetMode; + VL53L1_CalibrationData_t CalibrationData; + VL53L1_CustomerNvmManaged_t *pC; + + + LOG_FUNCTION_START(""); + + + + + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode != VL53L1_PRESETMODE_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) && + (PresetMode != VL53L1_PRESETMODE_LITE_RANGING)) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + goto ENDFUNC; + } + + + + Status = VL53L1_disable_xtalk_compensation(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_StartMeasurement(Dev); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + + + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + + sum_ranging = 0; + sum_spads = 0; + sum_signalRate = 0; + total_count = 0; + for (xtalk_meas = 0; xtalk_meas < xtalk_measmax; xtalk_meas++) { + VL53L1_WaitMeasurementDataReady(Dev); + VL53L1_GetRangingMeasurementData(Dev, &RMData); + VL53L1_ClearInterruptAndStartMeasurement(Dev); + if (RMData.RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + sum_ranging += RMData.RangeMilliMeter; + sum_signalRate += RMData.SignalRateRtnMegaCps; + sum_spads += RMData.EffectiveSpadRtnCount / 256; + total_count++; + } + } + Status = VL53L1_StopMeasurement(Dev); + + if (total_count > 0) { + + + xTalkStoredMeanSignalRate = sum_signalRate / total_count; + xTalkStoredMeanRange = (FixPoint1616_t)(sum_ranging << 16); + xTalkStoredMeanRange /= total_count; + xTalkStoredMeanRtnSpads = (FixPoint1616_t)(sum_spads << 16); + xTalkStoredMeanRtnSpads /= total_count; + + + + + + + + + + + + + + xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads + + 0x8000) >> 16; + + + + + + + xTalkCalDistanceAsInt = ((uint32_t)BDTable[ + VL53L1_TUNING_SINGLE_TARGET_XTALK_TARGET_DISTANCE_MM]); + if (xTalkStoredMeanRtnSpadsAsInt == 0 || + xTalkCalDistanceAsInt == 0 || + xTalkStoredMeanRange >= (xTalkCalDistanceAsInt << 16)) { + XTalkCompensationRateMegaCps = 0; + } else { + + + + + + + signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) / + xTalkStoredMeanRtnSpadsAsInt; + + + + + + + + signalXTalkTotalPerSpad *= (((uint32_t)1 << 16) - + (xTalkStoredMeanRange / xTalkCalDistanceAsInt)); + + + + XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad + + 0x8000) >> 16; + } + + + Status = VL53L1_GetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pC = &CalibrationData.customer; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)(1000 * ((XTalkCompensationRateMegaCps + + ((uint32_t)1<<6)) >> (16-9))); + + Status = VL53L1_SetCalibrationData(Dev, &CalibrationData); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_enable_xtalk_compensation(Dev); + + } else + + + Status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + + + +static VL53L1_Error CheckValidRectRoi(VL53L1_UserRoi_t ROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if ((ROI.TopLeftX > 15) || (ROI.TopLeftY > 15) || + (ROI.BotRightX > 15) || (ROI.BotRightY > 15)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if ((ROI.TopLeftX > ROI.BotRightX) || (ROI.TopLeftY < ROI.BotRightY)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_GPIO_Interrupt_Mode ConvertModeToLLD(VL53L1_Error *pStatus, + VL53L1_ThresholdMode CrossMode) +{ + VL53L1_GPIO_Interrupt_Mode Mode; + + switch (CrossMode) { + case VL53L1_THRESHOLD_CROSSED_LOW: + Mode = VL53L1_GPIOINTMODE_LEVEL_LOW; + break; + case VL53L1_THRESHOLD_CROSSED_HIGH: + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + break; + case VL53L1_THRESHOLD_OUT_OF_WINDOW: + Mode = VL53L1_GPIOINTMODE_OUT_OF_WINDOW; + break; + case VL53L1_THRESHOLD_IN_WINDOW: + Mode = VL53L1_GPIOINTMODE_IN_WINDOW; + break; + default: + + + Mode = VL53L1_GPIOINTMODE_LEVEL_HIGH; + *pStatus = VL53L1_ERROR_INVALID_PARAMS; + } + return Mode; +} + +static VL53L1_ThresholdMode ConvertModeFromLLD(VL53L1_Error *pStatus, + VL53L1_GPIO_Interrupt_Mode CrossMode) +{ + VL53L1_ThresholdMode Mode; + + switch (CrossMode) { + case VL53L1_GPIOINTMODE_LEVEL_LOW: + Mode = VL53L1_THRESHOLD_CROSSED_LOW; + break; + case VL53L1_GPIOINTMODE_LEVEL_HIGH: + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + break; + case VL53L1_GPIOINTMODE_OUT_OF_WINDOW: + Mode = VL53L1_THRESHOLD_OUT_OF_WINDOW; + break; + case VL53L1_GPIOINTMODE_IN_WINDOW: + Mode = VL53L1_THRESHOLD_IN_WINDOW; + break; + default: + + + Mode = VL53L1_THRESHOLD_CROSSED_HIGH; + *pStatus = VL53L1_ERROR_UNDEFINED; + } + return Mode; +} + + + + +VL53L1_Error VL53L1_GetVersion(VL53L1_Version_t *pVersion) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pVersion->major = VL53L1_IMPLEMENTATION_VER_MAJOR; + pVersion->minor = VL53L1_IMPLEMENTATION_VER_MINOR; + pVersion->build = VL53L1_IMPLEMENTATION_VER_SUB; + + pVersion->revision = VL53L1_IMPLEMENTATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetProductRevision(VL53L1_DEV Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + revision_id = pLLData->nvm_copy_data.identification__revision_id; + *pProductRevisionMajor = 1; + *pProductRevisionMinor = (revision_id & 0xF0) >> 4; + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetDeviceInfo(VL53L1_DEV Dev, + VL53L1_DeviceInfo_t *pVL53L1_DeviceInfo) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t revision_id; + VL53L1_LLDriverData_t *pLLData; + + LOG_FUNCTION_START(""); + + pLLData = VL53L1DevStructGetLLDriverHandle(Dev); + + strncpy(pVL53L1_DeviceInfo->ProductId, "", + VL53L1_DEVINFO_STRLEN-1); + pVL53L1_DeviceInfo->ProductType = + pLLData->nvm_copy_data.identification__module_type; + + revision_id = pLLData->nvm_copy_data.identification__revision_id; + pVL53L1_DeviceInfo->ProductRevisionMajor = 1; + pVL53L1_DeviceInfo->ProductRevisionMinor = (revision_id & 0xF0) >> 4; + +#ifndef VL53L1_USE_EMPTY_STRING + if (pVL53L1_DeviceInfo->ProductRevisionMinor == 0) + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME0, + VL53L1_DEVINFO_STRLEN-1); + else + strncpy(pVL53L1_DeviceInfo->Name, + VL53L1_STRING_DEVICE_INFO_NAME1, + VL53L1_DEVINFO_STRLEN-1); + strncpy(pVL53L1_DeviceInfo->Type, + VL53L1_STRING_DEVICE_INFO_TYPE, + VL53L1_DEVINFO_STRLEN-1); +#else + pVL53L1_DeviceInfo->Name[0] = 0; + pVL53L1_DeviceInfo->Type[0] = 0; +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_range_status_string(RangeStatus, + pRangeStatusString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalErrorString(VL53L1_Error PalErrorCode, + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_error_string(PalErrorCode, pPalErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalStateString(VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_pal_state_string(PalStateCode, pPalStateString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetPalState(VL53L1_DEV Dev, VL53L1_State *pPalState) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPalState = VL53L1DevDataGet(Dev, PalState); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +VL53L1_Error VL53L1_SetDeviceAddress(VL53L1_DEV Dev, uint8_t DeviceAddress) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_WrByte(Dev, VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + DeviceAddress / 2); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_DataInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t i; + + LOG_FUNCTION_START(""); + + + +#ifdef USE_I2C_2V8 + Status = VL53L1_RdByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, &i); + if (Status == VL53L1_ERROR_NONE) { + i = (i & 0xfe) | 0x01; + Status = VL53L1_WrByte(Dev, VL53L1_PAD_I2C_HV__EXTSUP_CONFIG, + i); + } +#endif + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_data_init(Dev, 1); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_WAIT_STATICINIT); + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, + VL53L1_PRESETMODE_RANGING); + } + + + + for (i = 0; i < VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL53L1_ERROR_NONE) + Status |= VL53L1_SetLimitCheckEnable(Dev, i, 1); + else + break; + + } + + + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_SetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + (FixPoint1616_t)(18 * 65536)); + } + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_SetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (FixPoint1616_t)(25 * 65536 / 100)); + + + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_StaticInit(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t measurement_mode; + + LOG_FUNCTION_START(""); + + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + VL53L1DevDataSet(Dev, LLData.measurement_mode, measurement_mode); + + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + VL53L1_DISTANCEMODE_LONG); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitDeviceBooted(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_poll_for_boot_completion(Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + +static VL53L1_Error ComputeDevicePresetMode( + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + VL53L1_DevicePresetModes *pDevicePresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + uint8_t DistIdx; + VL53L1_DevicePresetModes LightModes[3] = { + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING, + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes RangingModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE}; + + VL53L1_DevicePresetModes ScanningModes[3] = { + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE}; + + VL53L1_DevicePresetModes TimedModes[3] = { + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING, + VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE}; + + VL53L1_DevicePresetModes LowPowerTimedModes[3] = { + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE, + VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE}; + + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + + switch (DistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + DistIdx = 0; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + DistIdx = 1; + break; + default: + DistIdx = 2; + } + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + *pDevicePresetMode = LightModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_RANGING: + *pDevicePresetMode = RangingModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + *pDevicePresetMode = ScanningModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + *pDevicePresetMode = TimedModes[DistIdx]; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + *pDevicePresetMode = LowPowerTimedModes[DistIdx]; + break; + case VL53L1_PRESETMODE_OLT: + *pDevicePresetMode = VL53L1_DEVICEPRESETMODE_OLT; + break; + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + *pDevicePresetMode = + VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE; + break; + + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + return Status; +} + +static VL53L1_Error SetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes PresetMode, + VL53L1_DistanceModes DistanceMode, + uint32_t inter_measurement_period_ms) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DevicePresetModes device_preset_mode; + uint8_t measurement_mode; + uint16_t dss_config__target_total_rate_mcps; + uint32_t phasecal_config_timeout_us; + uint32_t mm_config_timeout_us; + uint32_t lld_range_config_timeout_us; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_TIMED; + else + measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + + Status = ComputeDevicePresetMode(PresetMode, DistanceMode, + &device_preset_mode); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_preset_mode_timing_cfg(Dev, + device_preset_mode, + &dss_config__target_total_rate_mcps, + &phasecal_config_timeout_us, + &mm_config_timeout_us, + &lld_range_config_timeout_us); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_preset_mode( + Dev, + device_preset_mode, + dss_config__target_total_rate_mcps, + phasecal_config_timeout_us, + mm_config_timeout_us, + lld_range_config_timeout_us, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.measurement_mode, + measurement_mode); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, CurrentParameters.PresetMode, PresetMode); + + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, + VL53L1_OUTPUTMODE_NEAREST); + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetPresetMode(VL53L1_DEV Dev, VL53L1_PresetModes PresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DistanceModes DistanceMode = VL53L1_DISTANCEMODE_LONG; + + LOG_FUNCTION_START("%d", (int)PresetMode); + + + + Status = VL53L1_low_power_auto_data_init(Dev); + + if (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + DistanceMode = VL53L1_DISTANCEMODE_SHORT; + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + 1000); + + if (Status == VL53L1_ERROR_NONE) { + if ((PresetMode == VL53L1_PRESETMODE_LITE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_AUTONOMOUS) || + (PresetMode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 41000); + else + + + Status = VL53L1_SetMeasurementTimingBudgetMicroSeconds( + Dev, 33333); + } + + if (Status == VL53L1_ERROR_NONE) { + + + Status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, + 1000); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetPresetMode(VL53L1_DEV Dev, + VL53L1_PresetModes *pPresetMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes DistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint32_t inter_measurement_period_ms; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + uint32_t PhaseCalTimeoutUs; + VL53L1_zone_config_t zone_config; + + LOG_FUNCTION_START("%d", (int)DistanceMode); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + + + + + if ((PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) && + (DistanceMode != VL53L1_DISTANCEMODE_SHORT)) + return VL53L1_ERROR_INVALID_PARAMS; + if ((DistanceMode != VL53L1_DISTANCEMODE_SHORT) && + (DistanceMode != VL53L1_DISTANCEMODE_MEDIUM) && + (DistanceMode != VL53L1_DISTANCEMODE_LONG)) + return VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_zone_config(Dev, &zone_config); + + inter_measurement_period_ms = VL53L1DevDataGet(Dev, + LLData.inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, &PhaseCalTimeoutUs, + &MmTimeoutUs, &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + Status = SetPresetMode(Dev, + PresetMode, + DistanceMode, + inter_measurement_period_ms); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, CurrentParameters.DistanceMode, + DistanceMode); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_set_timeouts_us(Dev, PhaseCalTimeoutUs, + MmTimeoutUs, TimingBudget); + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, LLData.range_config_timeout_us, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_config); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDistanceMode(VL53L1_DEV Dev, + VL53L1_DistanceModes *pDistanceMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pDistanceMode = VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes OutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if ((OutputMode != VL53L1_OUTPUTMODE_NEAREST) && + (OutputMode != VL53L1_OUTPUTMODE_STRONGEST)) + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + else + VL53L1DevDataSet(Dev, CurrentParameters.OutputMode, OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOutputMode(VL53L1_DEV Dev, + VL53L1_OutputModes *pOutputMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pOutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t MeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled; + uint8_t Mm2Enabled; + uint32_t TimingGuard; + uint32_t divisor; + uint32_t TimingBudget; + uint32_t MmTimeoutUs; + VL53L1_PresetModes PresetMode; + uint32_t PhaseCalTimeoutUs; + uint32_t vhv; + int32_t vhv_loops; + uint32_t FDAMaxTimingBudgetUs = FDA_MAX_TIMING_BUDGET_US; + + LOG_FUNCTION_START(""); + + + + if (MeasurementTimingBudgetMicroSeconds > 10000000) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + } + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &TimingBudget); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + TimingGuard = 0; + divisor = 1; + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 5000; + else + TimingGuard = 1000; + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + TimingGuard = 26600; + else + TimingGuard = 21600; + divisor = 2; + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + FDAMaxTimingBudgetUs *= 2; + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + divisor = 2; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + TimingGuard = 1700; + divisor = 6; + break; + + case VL53L1_PRESETMODE_OLT: + TimingGuard = MmTimeoutUs + 5000; + break; + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + + if (MeasurementTimingBudgetMicroSeconds <= TimingGuard) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget = (MeasurementTimingBudgetMicroSeconds + - TimingGuard); + } + + if (Status == VL53L1_ERROR_NONE) { + if (TimingBudget > FDAMaxTimingBudgetUs) + Status = VL53L1_ERROR_INVALID_PARAMS; + else { + TimingBudget /= divisor; + Status = VL53L1_set_timeouts_us( + Dev, + PhaseCalTimeoutUs, + MmTimeoutUs, + TimingBudget); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, + LLData.range_config_timeout_us, + TimingBudget); + } + } + if (Status == VL53L1_ERROR_NONE) { + VL53L1DevDataSet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementTimingBudgetMicroSeconds(VL53L1_DEV Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Mm1Enabled = 0; + uint8_t Mm2Enabled = 0; + uint32_t MmTimeoutUs = 0; + uint32_t RangeTimeoutUs = 0; + uint32_t MeasTimingBdg = 0; + uint32_t PhaseCalTimeoutUs = 0; + VL53L1_PresetModes PresetMode; + uint32_t TimingGuard; + uint32_t vhv; + int32_t vhv_loops; + + LOG_FUNCTION_START(""); + + *pMeasurementTimingBudgetMicroSeconds = 0; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM1, &Mm1Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetSequenceStepEnable(Dev, + VL53L1_SEQUENCESTEP_MM2, &Mm2Enabled); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_timeouts_us(Dev, + &PhaseCalTimeoutUs, + &MmTimeoutUs, + &RangeTimeoutUs); + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + + switch (PresetMode) { + case VL53L1_PRESETMODE_LITE_RANGING: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = RangeTimeoutUs + 5000; + else + MeasTimingBdg = RangeTimeoutUs + 1000; + + break; + + case VL53L1_PRESETMODE_AUTONOMOUS: + if ((Mm1Enabled == 1) || (Mm2Enabled == 1)) + MeasTimingBdg = 2 * RangeTimeoutUs + 26600; + else + MeasTimingBdg = 2 * RangeTimeoutUs + 21600; + + break; + + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + vhv = LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + VL53L1_get_tuning_parm(Dev, + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND, + &vhv_loops); + if (vhv_loops > 0) { + vhv += vhv_loops * + LOWPOWER_AUTO_VHV_LOOP_DURATION_US; + } + TimingGuard = LOWPOWER_AUTO_OVERHEAD_BEFORE_A_RANGING + + LOWPOWER_AUTO_OVERHEAD_BETWEEN_A_B_RANGING + + vhv; + MeasTimingBdg = 2 * RangeTimeoutUs + TimingGuard; + break; + + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_PROXY_RANGING_MODE: + MeasTimingBdg = (6 * RangeTimeoutUs) + 1700; + break; + + case VL53L1_PRESETMODE_OLT: + MeasTimingBdg = RangeTimeoutUs + MmTimeoutUs + 5000; + break; + default: + + + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + } + } + if (Status == VL53L1_ERROR_NONE) + *pMeasurementTimingBudgetMicroSeconds = MeasTimingBdg; + + LOG_FUNCTION_END(Status); + return Status; +} + + + +VL53L1_Error VL53L1_SetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t InterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + + + adjustedIMP = InterMeasurementPeriodMilliSeconds; + adjustedIMP += (adjustedIMP * 64) / 1000; + + + Status = VL53L1_set_inter_measurement_period_ms(Dev, + adjustedIMP); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetInterMeasurementPeriodMilliSeconds(VL53L1_DEV Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t adjustedIMP; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_inter_measurement_period_ms(Dev, &adjustedIMP); + + + adjustedIMP -= (adjustedIMP * 64) / 1000; + *pInterMeasurementPeriodMilliSeconds = adjustedIMP; + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t DmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + + LOG_FUNCTION_START(""); + + if (DmaxReflectance > 100*65536) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_dmax_reflectance_values(Dev, + &dmax_reflectances); + + if (Status == VL53L1_ERROR_NONE) { + dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX] = + VL53L1_FIXPOINT1616TOFIXPOINT72(DmaxReflectance); + Status = VL53L1_set_dmax_reflectance_values(Dev, + &dmax_reflectances); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetDmaxReflectance(VL53L1_DEV Dev, + FixPoint1616_t *pDmaxReflectance) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_dmax_reflectance_array_t dmax_reflectances; + uint16_t r; + + LOG_FUNCTION_START(""); + Status = VL53L1_get_dmax_reflectance_values(Dev, &dmax_reflectances); + if (Status == VL53L1_ERROR_NONE) { + r = dmax_reflectances.target_reflectance_for_dmax[ + DMAX_REFLECTANCE_IDX]; + *pDmaxReflectance = VL53L1_FIXPOINT72TOFIXPOINT1616(r); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes DmaxMode) +{ + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + switch (DmaxMode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + break; + case VL53L1_DMAXMODE_CUSTCAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA; + break; + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + dmax_mode = VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_dmax_mode(Dev, dmax_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetDmaxMode(VL53L1_DEV Dev, + VL53L1_DeviceDmaxModes *pDmaxMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_DeviceDmaxMode dmax_mode; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_dmax_mode(Dev, &dmax_mode); + if (Status == VL53L1_ERROR_NONE) { + switch (dmax_mode) { + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_FMT_CAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_CUSTCAL_DATA; + break; + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + *pDmaxMode = VL53L1_DMAXMODE_PER_ZONE_CAL_DATA; + break; + default: + + + *pDmaxMode = VL53L1_ERROR_NOT_IMPLEMENTED; + break; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfLimitCheck = VL53L1_CHECKENABLE_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckInfo(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_limit_check_info(LimitCheckId, + pLimitCheckString); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckStatus(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckStatus) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + LimitCheckId, Temp8); + *pLimitCheckStatus = Temp8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetLimitValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t value) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t tmpuint16; + + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT142(value); + VL53L1_set_lite_sigma_threshold(Dev, tmpuint16); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + tmpuint16 = VL53L1_FIXPOINT1616TOFIXPOINT97(value); + VL53L1_set_lite_min_count_rate(Dev, tmpuint16); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t LimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + + if (LimitCheckEnable == 0) + TempFix1616 = 0; + else + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, TempFix1616); + + Status = SetLimitValue(Dev, LimitCheckId, TempFix1616); + } + + if (Status == VL53L1_ERROR_NONE) + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, + LimitCheckId, + ((LimitCheckEnable == 0) ? 0 : 1)); + + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckEnable(VL53L1_DEV Dev, uint16_t LimitCheckId, + uint8_t *pLimitCheckEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + *pLimitCheckEnable = 0; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, Temp8); + *pLimitCheckEnable = Temp8; + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t LimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t LimitChecksEnable; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, + LimitChecksEnable); + + if (LimitChecksEnable == 0) { + + + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } else { + + Status = SetLimitValue(Dev, LimitCheckId, + LimitCheckValue); + + if (Status == VL53L1_ERROR_NONE) { + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, + LimitCheckId, LimitCheckValue); + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetLimitCheckValue(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint16_t MinCountRate; + FixPoint1616_t TempFix1616; + uint16_t SigmaThresh; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + Status = VL53L1_get_lite_sigma_threshold(Dev, &SigmaThresh); + TempFix1616 = VL53L1_FIXPOINT142TOFIXPOINT1616(SigmaThresh); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + Status = VL53L1_get_lite_min_count_rate(Dev, &MinCountRate); + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616(MinCountRate); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) { + + if (TempFix1616 == 0) { + + + VL53L1_GETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 0); + } else { + *pLimitCheckValue = TempFix1616; + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 1); + } + } + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetLimitCheckCurrent(VL53L1_DEV Dev, uint16_t LimitCheckId, + FixPoint1616_t *pLimitCheckCurrent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + FixPoint1616_t TempFix1616 = 0; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL53L1_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL53L1_ERROR_INVALID_PARAMS; + } else { + VL53L1_GETARRAYPARAMETERFIELD(Dev, LimitChecksCurrent, + LimitCheckId, TempFix1616); + *pLimitCheckCurrent = TempFix1616; + } + + LOG_FUNCTION_END(Status); + return Status; + +} + + + + + + + + + + +VL53L1_Error VL53L1_GetMaxNumberOfROI(VL53L1_DEV Dev, + uint8_t *pMaxNumberOfROI) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + *pMaxNumberOfROI = VL53L1_MAX_USER_ZONES; + else + *pMaxNumberOfROI = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_PresetModes PresetMode; + uint8_t MaxNumberOfROI = 1; + VL53L1_zone_config_t zone_cfg; + VL53L1_UserRoi_t CurrROI; + uint8_t i; + uint8_t x_centre; + uint8_t y_centre; + uint8_t width, height; + + LOG_FUNCTION_START(""); + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) + MaxNumberOfROI = VL53L1_MAX_USER_ZONES; + + if ((pRoiConfig->NumberOfRoi > MaxNumberOfROI) || + (pRoiConfig->NumberOfRoi < 1)) + Status = VL53L1_ERROR_INVALID_PARAMS; + + if (Status == VL53L1_ERROR_NONE) { + + + + zone_cfg.max_zones = MaxNumberOfROI; + zone_cfg.active_zones = pRoiConfig->NumberOfRoi - 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + CurrROI = pRoiConfig->UserRois[i]; + + + + + + + + + + Status = CheckValidRectRoi(CurrROI); + if (Status != VL53L1_ERROR_NONE) + break; + + x_centre = (CurrROI.BotRightX + CurrROI.TopLeftX + 1) + / 2; + y_centre = (CurrROI.TopLeftY + CurrROI.BotRightY + 1) + / 2; + width = (CurrROI.BotRightX - CurrROI.TopLeftX); + height = (CurrROI.TopLeftY - CurrROI.BotRightY); + if ((width < 3) || (height < 3)) { + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + zone_cfg.user_zones[i].x_centre = x_centre; + zone_cfg.user_zones[i].y_centre = y_centre; + zone_cfg.user_zones[i].width = width; + zone_cfg.user_zones[i].height = height; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_zone_config(Dev, &zone_cfg); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetROI(VL53L1_DEV Dev, + VL53L1_RoiConfig_t *pRoiConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_zone_config_t zone_cfg; + uint8_t i; + uint8_t TopLeftX; + uint8_t TopLeftY; + uint8_t BotRightX; + uint8_t BotRightY; + + LOG_FUNCTION_START(""); + + VL53L1_get_zone_config(Dev, &zone_cfg); + + pRoiConfig->NumberOfRoi = zone_cfg.active_zones + 1; + + for (i = 0; i < pRoiConfig->NumberOfRoi; i++) { + TopLeftX = (2 * zone_cfg.user_zones[i].x_centre - + zone_cfg.user_zones[i].width) >> 1; + TopLeftY = (2 * zone_cfg.user_zones[i].y_centre + + zone_cfg.user_zones[i].height) >> 1; + BotRightX = (2 * zone_cfg.user_zones[i].x_centre + + zone_cfg.user_zones[i].width) >> 1; + BotRightY = (2 * zone_cfg.user_zones[i].y_centre - + zone_cfg.user_zones[i].height) >> 1; + pRoiConfig->UserRois[i].TopLeftX = TopLeftX; + pRoiConfig->UserRois[i].TopLeftY = TopLeftY; + pRoiConfig->UserRois[i].BotRightX = BotRightX; + pRoiConfig->UserRois[i].BotRightY = BotRightY; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + +VL53L1_Error VL53L1_GetNumberOfSequenceSteps(VL53L1_DEV Dev, + uint8_t *pNumberOfSequenceSteps) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); + + *pNumberOfSequenceSteps = VL53L1_SEQUENCESTEP_NUMBER_OF_ITEMS; + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetSequenceStepsInfo(VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_steps_info( + SequenceStepId, + pSequenceStepsString); + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_SetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t SequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint32_t MeasurementTimingBudgetMicroSeconds; + + LOG_FUNCTION_START(""); + + + + + + + Status = VL53L1_set_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + SequenceStepEnabled); + + + + if (Status == VL53L1_ERROR_NONE) { + + + + MeasurementTimingBudgetMicroSeconds = VL53L1DevDataGet(Dev, + CurrentParameters.MeasurementTimingBudgetMicroSeconds); + + VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + + return Status; +} + + +VL53L1_Error VL53L1_GetSequenceStepEnable(VL53L1_DEV Dev, + VL53L1_SequenceStepId SequenceStepId, uint8_t *pSequenceStepEnabled) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_sequence_config_bit(Dev, + (VL53L1_DeviceSequenceConfig)SequenceStepId, + pSequenceStepEnabled); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + + + + + +VL53L1_Error VL53L1_StartMeasurement(VL53L1_DEV Dev) +{ +#define TIMED_MODE_TIMING_GUARD_MILLISECONDS 4 + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + VL53L1_State CurrPalState; + VL53L1_Error lStatus; + uint32_t MTBus, IMPms; + + LOG_FUNCTION_START(""); + + CurrPalState = VL53L1DevDataGet(Dev, PalState); + switch (CurrPalState) { + case VL53L1_STATE_IDLE: + Status = VL53L1_ERROR_NONE; + break; + case VL53L1_STATE_POWERDOWN: + case VL53L1_STATE_WAIT_STATICINIT: + case VL53L1_STATE_STANDBY: + case VL53L1_STATE_RUNNING: + case VL53L1_STATE_RESET: + case VL53L1_STATE_UNKNOWN: + case VL53L1_STATE_ERROR: + Status = VL53L1_ERROR_INVALID_COMMAND; + break; + default: + Status = VL53L1_ERROR_UNDEFINED; + } + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + + + + if ((Status == VL53L1_ERROR_NONE) && + (DeviceMeasurementMode == VL53L1_DEVICEMEASUREMENTMODE_TIMED)) { + lStatus = VL53L1_GetMeasurementTimingBudgetMicroSeconds(Dev, + &MTBus); + + + MTBus /= 1000; + lStatus = VL53L1_GetInterMeasurementPeriodMilliSeconds(Dev, + &IMPms); + + + SUPPRESS_UNUSED_WARNING(lStatus); + if (IMPms < MTBus + TIMED_MODE_TIMING_GUARD_MILLISECONDS) + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_init_and_start_range( + Dev, + DeviceMeasurementMode, + VL53L1_DEVICECONFIGLEVEL_FULL); + + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_RUNNING); + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_StopMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_stop_range(Dev); + + + + if (Status == VL53L1_ERROR_NONE) + VL53L1DevDataSet(Dev, PalState, VL53L1_STATE_IDLE); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_ClearInterruptAndStartMeasurement(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t DeviceMeasurementMode; + + LOG_FUNCTION_START(""); + + DeviceMeasurementMode = VL53L1DevDataGet(Dev, LLData.measurement_mode); + + Status = VL53L1_clear_interrupt_and_enable_next_range(Dev, + DeviceMeasurementMode); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetMeasurementDataReady(VL53L1_DEV Dev, + uint8_t *pMeasurementDataReady) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_is_new_data_ready(Dev, pMeasurementDataReady); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_WaitMeasurementDataReady(VL53L1_DEV Dev) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + Status = VL53L1_poll_for_range_completion(Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + LOG_FUNCTION_END(Status); + return Status; +} + +static void GenNewPresetMode(int16_t RefRange, + VL53L1_DistanceModes InternalDistanceMode, + VL53L1_DistanceModes *pNewDistanceMode) +{ + uint16_t HRLI = 600; + uint16_t HRLH = 700; + uint16_t MRLI = 1400; + uint16_t MRLH = 1500; + + switch (InternalDistanceMode) { + case VL53L1_DISTANCEMODE_SHORT: + + + + + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange > HRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + case VL53L1_DISTANCEMODE_MEDIUM: + + + + + + if (RefRange > MRLH) + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + else if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + break; + default: + + + + + + + if (RefRange < HRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_SHORT; + else if (RefRange < MRLI) + *pNewDistanceMode = VL53L1_DISTANCEMODE_MEDIUM; + break; + } +} + +static void CheckAndChangeDistanceMode(VL53L1_DEV Dev, + VL53L1_TargetRangeData_t *pRangeData, + int16_t Ambient100DmaxMm, + VL53L1_DistanceModes *pNewDistanceMode +) +{ + VL53L1_DistanceModes DistanceMode; + uint8_t RangeStatus = pRangeData->RangeStatus; + uint8_t DmaxValid; + int32_t MinAmbient = BDTable[VL53L1_TUNING_MIN_AMBIENT_DMAX_VALID]; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + int32_t tmpint32; + + + + switch (RangeStatus) { + case VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL: + case VL53L1_RANGESTATUS_WRAP_TARGET_FAIL: + case VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE: + case VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL: + case VL53L1_RANGESTATUS_SYNCRONISATION_INT: + case VL53L1_RANGESTATUS_NONE: + return; + default: + + + break; + } + + DmaxValid = 1; + tmpint32 = pdev->hist_data.VL53L1_p_004; + if (tmpint32 < MinAmbient) + DmaxValid = 0; + + DistanceMode = VL53L1DevDataGet(Dev, + CurrentParameters.DistanceMode); + + *pNewDistanceMode = DistanceMode; + + if (RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + GenNewPresetMode(pRangeData->RangeMilliMeter, + DistanceMode, pNewDistanceMode); + else { + if (DmaxValid) + GenNewPresetMode(Ambient100DmaxMm, + DistanceMode, pNewDistanceMode); + else + *pNewDistanceMode = VL53L1_DISTANCEMODE_LONG; + } +} + +static uint8_t ComputeRQL(uint8_t active_results, + uint8_t FilteredRangeStatus, + VL53L1_range_data_t *presults_data) +{ + int16_t T_Wide = 150; + int16_t SRL = 300; + uint16_t SRAS = 30; + FixPoint1616_t RAS; + FixPoint1616_t SRQL; + FixPoint1616_t GI = 7713587; + + FixPoint1616_t GGm = 3198157; + + FixPoint1616_t LRAP = 6554; + + FixPoint1616_t partial; + uint8_t finalvalue; + uint8_t returnvalue; + + if (active_results == 0) + returnvalue = 0; + else if (((presults_data->max_range_mm - + presults_data->min_range_mm) >= T_Wide) || + (FilteredRangeStatus == VL53L1_DEVICEERROR_PHASECONSISTENCY)) + returnvalue = 50; + else { + if (presults_data->median_range_mm < SRL) + RAS = SRAS * 65536; + else + RAS = LRAP * presults_data->median_range_mm; + + + + if (RAS != 0) { + partial = (GGm * presults_data->VL53L1_p_005); + partial = partial + (RAS >> 1); + partial = partial / RAS; + partial = partial * 65536; + if (partial <= GI) + SRQL = GI - partial; + else + SRQL = 50 * 65536; + } else + SRQL = 100 * 65536; + + finalvalue = (uint8_t)(SRQL >> 16); + returnvalue = MAX(50, MIN(100, finalvalue)); + } + + return returnvalue; +} + + +static uint8_t ConvertStatusLite(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY: + RangeStatus = VL53L1_RANGESTATUS_SYNCRONISATION_INT; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_MSRCNOTARGET: + RangeStatus = VL53L1_RANGESTATUS_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGEIGNORETHRESHOLD: + RangeStatus = VL53L1_RANGESTATUS_XTALK_SIGNAL_FAIL; + break; + case VL53L1_DEVICEERROR_MINCLIP: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MIN_RANGE_CLIPPED; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + + +static uint8_t ConvertStatusHisto(uint8_t FilteredRangeStatus) +{ + uint8_t RangeStatus; + + switch (FilteredRangeStatus) { + case VL53L1_DEVICEERROR_RANGEPHASECHECK: + RangeStatus = VL53L1_RANGESTATUS_OUTOFBOUNDS_FAIL; + break; + case VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK: + RangeStatus = VL53L1_RANGESTATUS_SIGMA_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_NO_WRAP_CHECK_FAIL; + break; + case VL53L1_DEVICEERROR_PHASECONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS: + RangeStatus = VL53L1_RANGESTATUS_TARGET_PRESENT_LACK_OF_SIGNAL; + break; + case VL53L1_DEVICEERROR_EVENTCONSISTENCY: + RangeStatus = VL53L1_RANGESTATUS_WRAP_TARGET_FAIL; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID_MERGED_PULSE; + break; + case VL53L1_DEVICEERROR_RANGECOMPLETE: + RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + break; + default: + RangeStatus = VL53L1_RANGESTATUS_NONE; + } + + return RangeStatus; +} + +static VL53L1_Error SetSimpleData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_RangingMeasurementData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + pRangeData->TimeStamp = presults_data->time_stamp; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + pRangeData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static VL53L1_Error SetTargetData(VL53L1_DEV Dev, + uint8_t active_results, uint8_t device_status, + VL53L1_range_data_t *presults_data, + VL53L1_TargetRangeData_t *pRangeData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t FilteredRangeStatus; + uint8_t SigmaLimitflag; + uint8_t SignalLimitflag; + uint8_t Temp8Enable; + uint8_t Temp8; + FixPoint1616_t AmbientRate; + FixPoint1616_t SignalRate; + FixPoint1616_t TempFix1616; + FixPoint1616_t LimitCheckValue; + VL53L1_PresetModes PresetMode; + int16_t Range; + + FilteredRangeStatus = presults_data->range_status & 0x1F; + + pRangeData->RangeQualityLevel = ComputeRQL(active_results, + FilteredRangeStatus, + presults_data); + + SignalRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + pRangeData->SignalRateRtnMegaCps + = SignalRate; + + AmbientRate = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->ambient_count_rate_mcps); + pRangeData->AmbientRateRtnMegaCps = AmbientRate; + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + + pRangeData->SigmaMilliMeter = TempFix1616; + + pRangeData->RangeMilliMeter = presults_data->median_range_mm; + pRangeData->RangeMaxMilliMeter = presults_data->max_range_mm; + pRangeData->RangeMinMilliMeter = presults_data->min_range_mm; + + pRangeData->RangeFractionalPart = 0; + + + + switch (device_status) { + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_HARDWARE_FAIL; + break; + case VL53L1_DEVICEERROR_USERROICLIP: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_MIN_RANGE_FAIL; + break; + default: + pRangeData->RangeStatus = VL53L1_RANGESTATUS_RANGE_VALID; + } + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (active_results == 0)) { + pRangeData->RangeStatus = VL53L1_RANGESTATUS_NONE; + pRangeData->SignalRateRtnMegaCps = 0; + pRangeData->SigmaMilliMeter = 0; + pRangeData->RangeMilliMeter = 8191; + pRangeData->RangeMaxMilliMeter = 8191; + pRangeData->RangeMinMilliMeter = 8191; + } + + if (pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + if ((PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE)) + pRangeData->RangeStatus = + ConvertStatusHisto(FilteredRangeStatus); + else + pRangeData->RangeStatus = + ConvertStatusLite(FilteredRangeStatus); + } + + + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->VL53L1_p_005); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + TempFix1616); + + TempFix1616 = VL53L1_FIXPOINT97TOFIXPOINT1616( + presults_data->peak_signal_count_rate_mcps); + VL53L1_SETARRAYPARAMETERFIELD(Dev, + LimitChecksCurrent, VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + TempFix1616); + + + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckValue); + + SigmaLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_SIGMATHRESHOLDCHECK) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SigmaLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + + + VL53L1_GetLimitCheckValue(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &LimitCheckValue); + + SignalLimitflag = (FilteredRangeStatus == + VL53L1_DEVICEERROR_MSRCNOTARGET) + ? 1 : 0; + + VL53L1_GetLimitCheckEnable(Dev, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &Temp8Enable); + + Temp8 = ((Temp8Enable == 1) && (SignalLimitflag == 1)) ? 1 : 0; + VL53L1_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, Temp8); + + Range = pRangeData->RangeMilliMeter; + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) && + (Range < 0)) { + if (Range < BDTable[VL53L1_TUNING_PROXY_MIN]) + pRangeData->RangeStatus = + VL53L1_RANGESTATUS_RANGE_INVALID; + else + pRangeData->RangeMilliMeter = 0; + } + + return Status; +} + +static uint8_t GetOutputDataIndex(VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + uint8_t i; + uint8_t index = 0; + VL53L1_OutputModes OutputMode; + + OutputMode = VL53L1DevDataGet(Dev, CurrentParameters.OutputMode); + + + + + if (OutputMode == VL53L1_OUTPUTMODE_NEAREST) + return 0; + + + + + + for (i = 1; i < presults->active_results; i++) { + if (presults->VL53L1_p_002[i].peak_signal_count_rate_mcps > + presults->VL53L1_p_002[index].peak_signal_count_rate_mcps) + index = i; + } + + return index; +} + +VL53L1_Error VL53L1_GetRangingMeasurementData(VL53L1_DEV Dev, + VL53L1_RangingMeasurementData_t *pRangingMeasurementData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_range_results_t results; + VL53L1_range_results_t *presults = &results; + VL53L1_range_data_t *presults_data; + VL53L1_PresetModes PresetMode; + uint8_t index = 0; + + LOG_FUNCTION_START(""); + + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) { + Status = VL53L1_ERROR_MODE_NOT_SUPPORTED; + LOG_FUNCTION_END(Status); + return Status; + } + + + + memset(pRangingMeasurementData, 0xFF, + sizeof(VL53L1_RangingMeasurementData_t)); + + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + if (Status == VL53L1_ERROR_NONE) { + pRangingMeasurementData->StreamCount = presults->stream_count; + + + + + + index = GetOutputDataIndex(Dev, presults); + presults_data = &(presults->VL53L1_p_002[index]); + Status = SetSimpleData(Dev, presults->active_results, + presults->device_status, + presults_data, + pRangingMeasurementData); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +static VL53L1_Error SetMeasurementData(VL53L1_DEV Dev, + VL53L1_range_results_t *presults, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + uint8_t i; + uint8_t iteration; + VL53L1_TargetRangeData_t *pRangeData; + VL53L1_range_data_t *presults_data; + int16_t dmax_min; + VL53L1_Error Status = VL53L1_ERROR_NONE; + uint8_t Furthest_idx = 0; + int16_t Furthest_range = 0; + uint8_t ActiveResults; + + pMultiRangingData->NumberOfObjectsFound = presults->active_results; + pMultiRangingData->RoiNumber = presults->zone_id; + pMultiRangingData->HasXtalkValueChanged = + presults->smudge_corrector_data.new_xtalk_applied_flag; + dmax_min = MIN(presults->wrap_dmax_mm, + presults->VL53L1_p_007[DMAX_REFLECTANCE_IDX]); + pMultiRangingData->DmaxMilliMeter = dmax_min; + + + + + + pMultiRangingData->TimeStamp = 0; + + pMultiRangingData->StreamCount = presults->stream_count; + + pMultiRangingData->RecommendedDistanceMode = + VL53L1DevDataGet(Dev, CurrentParameters.DistanceMode); + ActiveResults = presults->active_results; + if (ActiveResults < 1) + + + + + iteration = 1; + else + iteration = ActiveResults; + for (i = 0; i < iteration; i++) { + pRangeData = &(pMultiRangingData->RangeData[i]); + + presults_data = &(presults->VL53L1_p_002[i]); + if (Status == VL53L1_ERROR_NONE) + Status = SetTargetData(Dev, ActiveResults, + presults->device_status, + presults_data, + pRangeData); + + pMultiRangingData->EffectiveSpadRtnCount = + presults_data->VL53L1_p_006; + + if ((pRangeData->RangeStatus == VL53L1_RANGESTATUS_RANGE_VALID) + && (pRangeData->RangeMilliMeter > Furthest_range)) { + Furthest_range = pRangeData->RangeMilliMeter; + Furthest_idx = i; + } + + } + + + if ((Status == VL53L1_ERROR_NONE) && (ActiveResults > 0)) { + pRangeData = &(pMultiRangingData->RangeData[Furthest_idx]); + CheckAndChangeDistanceMode(Dev, pRangeData, + presults->VL53L1_p_007[VL53L1_MAX_AMBIENT_DMAX_VALUES-1], + &pMultiRangingData->RecommendedDistanceMode); + } + + + return Status; +} + +VL53L1_Error VL53L1_GetMultiRangingData(VL53L1_DEV Dev, + VL53L1_MultiRangingData_t *pMultiRangingData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_range_results_t results; + VL53L1_range_results_t *presults = &results; + + LOG_FUNCTION_START(""); + + + + memset(pMultiRangingData, 0xFF, + sizeof(VL53L1_MultiRangingData_t)); + + + + Status = VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + presults); + + + if (Status == VL53L1_ERROR_NONE) { + + switch (presults->rd_device_state) { + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_NOT_LAST; + break; + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_VALID_LAST; + break; + default: + pMultiRangingData->RoiStatus = + VL53L1_ROISTATUS_NOT_VALID; + } + + Status = SetMeasurementData(Dev, + presults, + pMultiRangingData); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetAdditionalData(VL53L1_DEV Dev, + VL53L1_AdditionalData_t *pAdditionalData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_additional_data(Dev, pAdditionalData); + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_SetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t TuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + if (TuningParameterId == + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS) + return VL53L1_ERROR_INVALID_PARAMS; + + + if (TuningParameterId >= 32768) + Status = VL53L1_set_tuning_parm(Dev, + TuningParameterId, + TuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + BDTable[TuningParameterId] = TuningParameterValue; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetTuningParameter(VL53L1_DEV Dev, + uint16_t TuningParameterId, int32_t *pTuningParameterValue) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (TuningParameterId >= 32768) + Status = VL53L1_get_tuning_parm(Dev, + TuningParameterId, + pTuningParameterValue); + else { + if (TuningParameterId < VL53L1_TUNING_MAX_TUNABLE_KEY) + *pTuningParameterValue = BDTable[TuningParameterId]; + else + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformRefSpadManagement(VL53L1_DEV Dev) +{ +#ifdef VL53L1_NOCALIB + VL53L1_Error Status = VL53L1_ERROR_NOT_SUPPORTED; + + SUPPRESS_UNUSED_WARNING(Dev); + + LOG_FUNCTION_START(""); +#else + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error RawStatus; + uint8_t dcrbuffer[24]; + uint8_t *commbuf; + uint8_t numloc[2] = {5, 3}; + VL53L1_LLDriverData_t *pdev; + VL53L1_customer_nvm_managed_t *pc; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + pc = &pdev->customer; + + if (Status == VL53L1_ERROR_NONE) { + PresetMode = VL53L1DevDataGet(Dev, + CurrentParameters.PresetMode); + Status = VL53L1_run_ref_spad_char(Dev, &RawStatus); + + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_SetPresetMode(Dev, PresetMode); + } + + if (Status == VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH) { + + + + + Status = VL53L1_read_nvm_raw_data(Dev, + (uint8_t)(0xA0 >> 2), + (uint8_t)(24 >> 2), + dcrbuffer); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + numloc, 2); + + if (Status == VL53L1_ERROR_NONE) { + pc->ref_spad_man__num_requested_ref_spads = numloc[0]; + pc->ref_spad_man__ref_location = numloc[1]; + } + + if (Status == VL53L1_ERROR_NONE) + commbuf = &dcrbuffer[16]; + + + + + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WriteMulti(Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + commbuf, 6); + + if (Status == VL53L1_ERROR_NONE) { + pc->global_config__spad_enables_ref_0 = commbuf[0]; + pc->global_config__spad_enables_ref_1 = commbuf[1]; + pc->global_config__spad_enables_ref_2 = commbuf[2]; + pc->global_config__spad_enables_ref_3 = commbuf[3]; + pc->global_config__spad_enables_ref_4 = commbuf[4]; + pc->global_config__spad_enables_ref_5 = commbuf[5]; + } + + + } + +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SmudgeCorrectionEnable(VL53L1_DEV Dev, + VL53L1_SmudgeCorrectionModes Mode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error s1 = VL53L1_ERROR_NONE; + VL53L1_Error s2 = VL53L1_ERROR_NONE; + VL53L1_Error s3 = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (Mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + s1 = VL53L1_dynamic_xtalk_correction_disable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_SINGLE: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_enable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_enable(Dev); + break; + case VL53L1_SMUDGE_CORRECTION_DEBUG: + s1 = VL53L1_dynamic_xtalk_correction_enable(Dev); + s2 = VL53L1_dynamic_xtalk_correction_apply_disable(Dev); + s3 = VL53L1_dynamic_xtalk_correction_single_apply_disable(Dev); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + break; + } + + if (Status == VL53L1_ERROR_NONE) { + Status = s1; + if (Status == VL53L1_ERROR_NONE) + Status = s2; + if (Status == VL53L1_ERROR_NONE) + Status = s3; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t XTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (XTalkCompensationEnable == 0) + Status = VL53L1_disable_xtalk_compensation(Dev); + else + Status = VL53L1_enable_xtalk_compensation(Dev); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetXTalkCompensationEnable(VL53L1_DEV Dev, + uint8_t *pXTalkCompensationEnable) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + VL53L1_get_xtalk_compensation_enable( + Dev, + pXTalkCompensationEnable); + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_PerformXTalkCalibration(VL53L1_DEV Dev, + uint8_t CalibrationOption) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + int16_t CalDistanceMm; + VL53L1_xtalk_calibration_results_t xtalk; + + LOG_FUNCTION_START(""); + + switch (CalibrationOption) { + case VL53L1_XTALKCALIBRATIONMODE_NO_TARGET: + Status = VL53L1_run_xtalk_extraction(Dev, &UnfilteredStatus); + + + if (Status == VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL) + VL53L1_xtalk_cal_data_init(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET: + Status = SingleTargetXTalkCalibration(Dev); + break; + case VL53L1_XTALKCALIBRATIONMODE_FULL_ROI: + CalDistanceMm = (int16_t) + BDTable[VL53L1_TUNING_XTALK_FULL_ROI_TARGET_DISTANCE_MM]; + Status = VL53L1_run_hist_xtalk_extraction(Dev, CalDistanceMm, + &UnfilteredStatus); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + + if (Status == VL53L1_ERROR_NONE) { + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + xtalk.algo__crosstalk_compensation_plane_offset_kcps); + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCalibrationMode(VL53L1_DEV Dev, + VL53L1_OffsetCalibrationModes OffsetCalibrationMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCalibrationMode offset_cal_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCalibrationMode == VL53L1_OFFSETCALIBRATIONMODE_STANDARD) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY; + } else if (OffsetCalibrationMode == + VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + offset_cal_mode = + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_calibration_mode(Dev, + offset_cal_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetOffsetCorrectionMode(VL53L1_DEV Dev, + VL53L1_OffsetCorrectionModes OffsetCorrectionMode) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_OffsetCorrectionMode offset_cor_mode; + + LOG_FUNCTION_START(""); + + if (OffsetCorrectionMode == VL53L1_OFFSETCORRECTIONMODE_STANDARD) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + } else if (OffsetCorrectionMode == + VL53L1_OFFSETCORRECTIONMODE_PERZONE) { + offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS; + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_set_offset_correction_mode(Dev, + offset_cor_mode); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter, FixPoint1616_t CalReflectancePercent) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_Error UnfilteredStatus; + VL53L1_OffsetCalibrationMode offset_cal_mode; + uint16_t CalReflectancePercent_int; + + + VL53L1_DevicePresetModes device_preset_mode; + VL53L1_DeviceZonePreset zone_preset; + VL53L1_zone_config_t zone_cfg; + + LOG_FUNCTION_START(""); + + CalReflectancePercent_int = + VL53L1_FIXPOINT1616TOFIXPOINT72(CalReflectancePercent); + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_get_offset_calibration_mode(Dev, + &offset_cal_mode); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + + if ((offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD) || + (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY + )) { + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_offset_calibration( + Dev, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else if (offset_cal_mode == + VL53L1_OFFSETCALIBRATIONMODE__PER_ZONE) { + device_preset_mode = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE; + zone_preset = VL53L1_DEVICEZONEPRESET_CUSTOM; + + Status = VL53L1_get_zone_config(Dev, &zone_cfg); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_run_zone_calibration( + Dev, + device_preset_mode, + zone_preset, + &zone_cfg, + (int16_t)CalDistanceMilliMeter, + CalReflectancePercent_int, + &UnfilteredStatus); + + } else { + Status = VL53L1_ERROR_INVALID_PARAMS; + } + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_PerformOffsetSimpleCalibration(VL53L1_DEV Dev, + int32_t CalDistanceMilliMeter) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + int32_t sum_ranging; + uint8_t offset_meas; + int16_t Max, UnderMax, OverMax, Repeat; + int32_t total_count, inloopcount; + int32_t IncRounding; + int16_t meanDistance_mm; + int16_t offset; + VL53L1_RangingMeasurementData_t RangingMeasurementData; + VL53L1_LLDriverData_t *pdev; + uint8_t goodmeas; + VL53L1_Error SmudgeStatus = VL53L1_ERROR_NONE; + uint8_t smudge_corr_en; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + SmudgeStatus = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + + Repeat = BDTable[VL53L1_TUNING_SIMPLE_OFFSET_CALIBRATION_REPEAT]; + Max = BDTable[ + VL53L1_TUNING_MAX_SIMPLE_OFFSET_CALIBRATION_SAMPLE_NUMBER]; + UnderMax = 1 + (Max / 2); + OverMax = Max + (Max / 2); + sum_ranging = 0; + total_count = 0; + + while ((Repeat > 0) && (Status == VL53L1_ERROR_NONE)) { + Status = VL53L1_StartMeasurement(Dev); + + + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + + + inloopcount = 0; + offset_meas = 0; + while ((Status == VL53L1_ERROR_NONE) && (inloopcount < Max) && + (offset_meas < OverMax)) { + Status = VL53L1_WaitMeasurementDataReady(Dev); + if (Status == VL53L1_ERROR_NONE) + Status = VL53L1_GetRangingMeasurementData(Dev, + &RangingMeasurementData); + goodmeas = (RangingMeasurementData.RangeStatus == + VL53L1_RANGESTATUS_RANGE_VALID); + if ((Status == VL53L1_ERROR_NONE) && goodmeas) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + inloopcount++; + } + Status = VL53L1_ClearInterruptAndStartMeasurement(Dev); + offset_meas++; + } + total_count += inloopcount; + + + + if (inloopcount < UnderMax) + Status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + + VL53L1_StopMeasurement(Dev); + + Repeat--; + + } + + + if ((SmudgeStatus == VL53L1_ERROR_NONE) && (smudge_corr_en == 1)) + SmudgeStatus = VL53L1_dynamic_xtalk_correction_enable(Dev); + + + if ((sum_ranging < 0) || + (sum_ranging > ((int32_t) total_count * 0xffff))) { + Status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + } + + if ((Status == VL53L1_ERROR_NONE) && (total_count > 0)) { + IncRounding = total_count / 2; + meanDistance_mm = (int16_t)((sum_ranging + IncRounding) + / total_count); + offset = (int16_t)CalDistanceMilliMeter - meanDistance_mm; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + pdev->customer.mm_config__inner_offset_mm = offset; + pdev->customer.mm_config__outer_offset_mm = offset; + + Status = VL53L1_set_customer_nvm_managed(Dev, + &(pdev->customer)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_SetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_calibration_data_t cal_data; + uint32_t x; + VL53L1_xtalk_calibration_results_t xtalk; + + LOG_FUNCTION_START(""); + + cal_data.struct_version = pCalibrationData->struct_version - + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + + + + + memcpy( + &(cal_data.fmt_dmax_cal), + &(pCalibrationData->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(cal_data.cust_dmax_cal), + &(pCalibrationData->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + + memcpy( + &(cal_data.add_off_cal_data), + &(pCalibrationData->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(cal_data.optical_centre), + &(pCalibrationData->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(cal_data.xtalkhisto), + &(pCalibrationData->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(cal_data.gain_cal), + &(pCalibrationData->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(cal_data.cal_peak_rate_map), + &(pCalibrationData->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + pC = &pCalibrationData->customer; + x = pC->algo__crosstalk_compensation_plane_offset_kcps; + cal_data.customer.algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)(x&0x0000FFFF); + + cal_data.customer.global_config__spad_enables_ref_0 = + pC->global_config__spad_enables_ref_0; + cal_data.customer.global_config__spad_enables_ref_1 = + pC->global_config__spad_enables_ref_1; + cal_data.customer.global_config__spad_enables_ref_2 = + pC->global_config__spad_enables_ref_2; + cal_data.customer.global_config__spad_enables_ref_3 = + pC->global_config__spad_enables_ref_3; + cal_data.customer.global_config__spad_enables_ref_4 = + pC->global_config__spad_enables_ref_4; + cal_data.customer.global_config__spad_enables_ref_5 = + pC->global_config__spad_enables_ref_5; + cal_data.customer.global_config__ref_en_start_select = + pC->global_config__ref_en_start_select; + cal_data.customer.ref_spad_man__num_requested_ref_spads = + pC->ref_spad_man__num_requested_ref_spads; + cal_data.customer.ref_spad_man__ref_location = + pC->ref_spad_man__ref_location; + cal_data.customer.algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + cal_data.customer.algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + cal_data.customer.ref_spad_char__total_rate_target_mcps = + pC->ref_spad_char__total_rate_target_mcps; + cal_data.customer.algo__part_to_part_range_offset_mm = + pC->algo__part_to_part_range_offset_mm; + cal_data.customer.mm_config__inner_offset_mm = + pC->mm_config__inner_offset_mm; + cal_data.customer.mm_config__outer_offset_mm = + pC->mm_config__outer_offset_mm; + + Status = VL53L1_set_part_to_part_data(Dev, &cal_data); + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + xtalk.algo__crosstalk_compensation_plane_offset_kcps = x; + + + Status = VL53L1_set_tuning_parm(Dev, + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS, + x); + + + + Status = VL53L1_set_current_xtalk_settings(Dev, &xtalk); + +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetCalibrationData(VL53L1_DEV Dev, + VL53L1_CalibrationData_t *pCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t cal_data; + VL53L1_CustomerNvmManaged_t *pC; + VL53L1_customer_nvm_managed_t *pC2; + VL53L1_xtalk_calibration_results_t xtalk; + uint32_t tmp; + VL53L1_PresetModes PresetMode; + + LOG_FUNCTION_START(""); + + + + Status = VL53L1_get_part_to_part_data(Dev, &cal_data); + + pCalibrationData->struct_version = cal_data.struct_version + + VL53L1_ADDITIONAL_CALIBRATION_DATA_STRUCT_VERSION; + + + + memcpy( + &(pCalibrationData->fmt_dmax_cal), + &(cal_data.fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->cust_dmax_cal), + &(cal_data.cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->add_off_cal_data), + &(cal_data.add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pCalibrationData->optical_centre), + &(cal_data.optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(pCalibrationData->xtalkhisto), + &(cal_data.xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + memcpy( + &(pCalibrationData->gain_cal), + &(cal_data.gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pCalibrationData->cal_peak_rate_map), + &(cal_data.cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + pC = &pCalibrationData->customer; + pC2 = &cal_data.customer; + pC->global_config__spad_enables_ref_0 = + pC2->global_config__spad_enables_ref_0; + pC->global_config__spad_enables_ref_1 = + pC2->global_config__spad_enables_ref_1; + pC->global_config__spad_enables_ref_2 = + pC2->global_config__spad_enables_ref_2; + pC->global_config__spad_enables_ref_3 = + pC2->global_config__spad_enables_ref_3; + pC->global_config__spad_enables_ref_4 = + pC2->global_config__spad_enables_ref_4; + pC->global_config__spad_enables_ref_5 = + pC2->global_config__spad_enables_ref_5; + pC->global_config__ref_en_start_select = + pC2->global_config__ref_en_start_select; + pC->ref_spad_man__num_requested_ref_spads = + pC2->ref_spad_man__num_requested_ref_spads; + pC->ref_spad_man__ref_location = + pC2->ref_spad_man__ref_location; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC2->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->ref_spad_char__total_rate_target_mcps = + pC2->ref_spad_char__total_rate_target_mcps; + pC->algo__part_to_part_range_offset_mm = + pC2->algo__part_to_part_range_offset_mm; + pC->mm_config__inner_offset_mm = + pC2->mm_config__inner_offset_mm; + pC->mm_config__outer_offset_mm = + pC2->mm_config__outer_offset_mm; + + pC->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)( + pC2->algo__crosstalk_compensation_plane_offset_kcps); + + + PresetMode = VL53L1DevDataGet(Dev, CurrentParameters.PresetMode); + + if ((PresetMode == VL53L1_PRESETMODE_RANGING) || + (PresetMode == VL53L1_PRESETMODE_MULTIZONES_SCANNING) || + (PresetMode == VL53L1_PRESETMODE_PROXY_RANGING_MODE) + ) { + + Status = VL53L1_get_current_xtalk_settings(Dev, &xtalk); + + if (Status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + tmp = xtalk.algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = tmp; + tmp = xtalk.algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = tmp; + } +ENDFUNC: + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_SetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_set_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; + +} + +VL53L1_Error VL53L1_GetZoneCalibrationData(VL53L1_DEV Dev, + VL53L1_ZoneCalibrationData_t *pZoneCalibrationData) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_zone_calibration_data(Dev, pZoneCalibrationData); + + LOG_FUNCTION_END(Status); + return Status; +} + +VL53L1_Error VL53L1_GetOpticalCenter(VL53L1_DEV Dev, + FixPoint1616_t *pOpticalCenterX, + FixPoint1616_t *pOpticalCenterY) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_calibration_data_t CalibrationData; + + LOG_FUNCTION_START(""); + + *pOpticalCenterX = 0; + *pOpticalCenterY = 0; + Status = VL53L1_get_part_to_part_data(Dev, &CalibrationData); + if (Status == VL53L1_ERROR_NONE) { + *pOpticalCenterX = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.x_centre); + *pOpticalCenterY = VL53L1_FIXPOINT44TOFIXPOINT1616( + CalibrationData.optical_centre.y_centre); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + + + +VL53L1_Error VL53L1_SetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ +#define BADTHRESBOUNDS(T) \ + (((T.CrossMode == VL53L1_THRESHOLD_OUT_OF_WINDOW) || \ + (T.CrossMode == VL53L1_THRESHOLD_IN_WINDOW)) && (T.Low > T.High)) + + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + uint16_t g; + FixPoint1616_t gain, high1616, low1616; + VL53L1_LLDriverData_t *pdev; + + LOG_FUNCTION_START(""); + + pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + if (Status == VL53L1_ERROR_NONE) { + if (pConfig->DetectionMode == VL53L1_DETECTION_NORMAL_RUN) { + Cfg.intr_new_measure_ready = 1; + Status = VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + } else { + if (BADTHRESBOUNDS(pConfig->Distance)) + Status = VL53L1_ERROR_INVALID_PARAMS; + if ((Status == VL53L1_ERROR_NONE) && + (BADTHRESBOUNDS(pConfig->Rate))) + Status = VL53L1_ERROR_INVALID_PARAMS; + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_new_measure_ready = 0; + Cfg.intr_no_target = pConfig->IntrNoTarget; + + + + g = pdev->gain_cal.standard_ranging_gain_factor; + + + gain = (FixPoint1616_t) ((uint32_t)g << 5); + high1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.High << 16); + low1616 = (FixPoint1616_t) ((uint32_t) + pConfig->Distance.Low << 16); + + + high1616 = (high1616 + 32768) / gain; + low1616 = (low1616 + 32768) / gain; + Cfg.threshold_distance_high = (uint16_t) + (high1616 & 0xFFFF); + Cfg.threshold_distance_low = (uint16_t) + (low1616 & 0xFFFF); + + + Cfg.threshold_rate_high = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.High); + Cfg.threshold_rate_low = + VL53L1_FIXPOINT1616TOFIXPOINT97( + pConfig->Rate.Low); + + Cfg.intr_mode_distance = ConvertModeToLLD( + &Status, + pConfig->Distance.CrossMode); + if (Status == VL53L1_ERROR_NONE) + Cfg.intr_mode_rate = ConvertModeToLLD( + &Status, + pConfig->Rate.CrossMode); + } + + + + if (Status == VL53L1_ERROR_NONE) { + Cfg.intr_combined_mode = 1; + switch (pConfig->DetectionMode) { + case VL53L1_DETECTION_DISTANCE_ONLY: + Cfg.threshold_rate_high = 0; + Cfg.threshold_rate_low = 0; + break; + case VL53L1_DETECTION_RATE_ONLY: + Cfg.threshold_distance_high = 0; + Cfg.threshold_distance_low = 0; + break; + case VL53L1_DETECTION_DISTANCE_OR_RATE: + + + + + break; + case VL53L1_DETECTION_DISTANCE_AND_RATE: + Cfg.intr_combined_mode = 0; + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } + } + + if (Status == VL53L1_ERROR_NONE) + Status = + VL53L1_set_GPIO_interrupt_config_struct(Dev, + Cfg); + + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +VL53L1_Error VL53L1_GetThresholdConfig(VL53L1_DEV Dev, + VL53L1_DetectionConfig_t *pConfig) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + VL53L1_GPIO_interrupt_config_t Cfg; + + LOG_FUNCTION_START(""); + + Status = VL53L1_get_GPIO_interrupt_config(Dev, &Cfg); + + if (Status != VL53L1_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + pConfig->IntrNoTarget = Cfg.intr_no_target; + pConfig->Distance.High = Cfg.threshold_distance_high; + pConfig->Distance.Low = Cfg.threshold_distance_low; + pConfig->Rate.High = + VL53L1_FIXPOINT97TOFIXPOINT1616( + Cfg.threshold_rate_high); + pConfig->Rate.Low = + VL53L1_FIXPOINT97TOFIXPOINT1616(Cfg.threshold_rate_low); + pConfig->Distance.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_distance); + if (Status == VL53L1_ERROR_NONE) + pConfig->Rate.CrossMode = + ConvertModeFromLLD(&Status, Cfg.intr_mode_rate); + + if (Cfg.intr_new_measure_ready == 1) { + pConfig->DetectionMode = VL53L1_DETECTION_NORMAL_RUN; + } else { + + + if (Status == VL53L1_ERROR_NONE) { + if (Cfg.intr_combined_mode == 0) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_AND_RATE; + else { + if ((Cfg.threshold_distance_high == 0) && + (Cfg.threshold_distance_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_RATE_ONLY; + else if ((Cfg.threshold_rate_high == 0) && + (Cfg.threshold_rate_low == 0)) + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_ONLY; + else + pConfig->DetectionMode = + VL53L1_DETECTION_DISTANCE_OR_RATE; + } + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + + + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_api_calibration.c b/drivers/oneplus/vl53L1/src/vl53l1_api_calibration.c new file mode 100755 index 0000000000000000000000000000000000000000..b3b1a98a20ae83212a312cde19d4fc39574c14e4 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_api_calibration.c @@ -0,0 +1,2765 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_api_calibration.h" + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_api_debug.h" +#endif + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_run_ref_spad_char( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[6]; + + VL53L1_refspadchar_config_t *prefspadchar = &(pdev->refspadchar); + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_ref_spad_char_config( + Dev, + prefspadchar->VL53L1_p_009, + prefspadchar->timeout_us, + prefspadchar->target_count_rate_mcps, + prefspadchar->max_count_rate_limit_mcps, + prefspadchar->min_count_rate_limit_mcps, + pdev->stat_nvm.osc_measured__fast_osc__frequency); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_run_device_test( + Dev, + prefspadchar->device_test_mode); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->dbg_results.ref_spad_char_result__num_actual_ref_spads = + comms_buffer[0]; + pdev->dbg_results.ref_spad_char_result__ref_location = + comms_buffer[1]; + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.ref_spad_man__num_requested_ref_spads = + comms_buffer[0]; + pdev->customer.ref_spad_man__ref_location = + comms_buffer[1]; + } + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__SPARE_0_SD1, + comms_buffer, + 6); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + 6); + + if (status == VL53L1_ERROR_NONE) { + pdev->customer.global_config__spad_enables_ref_0 = + comms_buffer[0]; + pdev->customer.global_config__spad_enables_ref_1 = + comms_buffer[1]; + pdev->customer.global_config__spad_enables_ref_2 = + comms_buffer[2]; + pdev->customer.global_config__spad_enables_ref_3 = + comms_buffer[3]; + pdev->customer.global_config__spad_enables_ref_4 = + comms_buffer[4]; + pdev->customer.global_config__spad_enables_ref_5 = + comms_buffer[5]; + } + +#ifdef VL53L1_LOG_ENABLE + + + if (status == VL53L1_ERROR_NONE) + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_ref_spad_char():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_REF_SPAD_CHAR); +#endif + + if (status == VL53L1_ERROR_NONE) { + + switch (pdev->sys_results.result__range_status) { + + case VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS: + status = VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH; + break; + + case VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET: + status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW; + break; + } + } + + + + + + + *pcal_status = status; + + + + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW, + VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW, + status); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_xtalk_extraction( + VL53L1_DEV Dev, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + + + + + + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + uint8_t results_invalid = 0; + + uint8_t i = 0; + uint16_t tmp16 = 0; + + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_START(""); + + + + + + + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_avg)); + + VL53L1_init_histogram_bin_data_struct( + 0, + (uint16_t)VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->xtalk_results.central_histogram_sum)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR, + + + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + + + 100); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_xtalk_compensation(Dev); + + + + + + + pdev->xtalk_results.max_results = VL53L1_MAX_XTALK_RANGE_RESULTS; + pdev->xtalk_results.active_results = pdev->zone_cfg.active_zones+1; + + + + + pdev->xtalk_results.central_histogram__window_start = 0xFF; + pdev->xtalk_results.central_histogram__window_end = 0x00; + + pdev->xtalk_results.num_of_samples_status = 0x00; + pdev->xtalk_results.zero_samples_status = 0x00; + pdev->xtalk_results.max_sigma_status = 0x00; + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + pdev->xtalk_results.VL53L1_p_002[i].no_of_samples = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].signal_total_events_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].rate_per_spad_kcps_avg = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg = 0; + + + pdev->xtalk_results.VL53L1_p_002[i].median_phase_sum = 0; + pdev->xtalk_results.VL53L1_p_002[i].median_phase_avg = 0; + + + } + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_get_and_avg_xtalk_samples( + Dev, + + + pX->num_of_samples, + + + measurement_mode, + + + pX->algo__crosstalk_extract_max_valid_range_mm, + pX->algo__crosstalk_extract_min_valid_range_mm, + pX->algo__crosstalk_extract_max_valid_rate_kcps, + + + 0x0, + + 0x4, + + &(pdev->xtalk_results), + &(pdev->xtalk_results.central_histogram_sum), + &(pdev->xtalk_results.central_histogram_avg)); + } + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + if ((pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) || + (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + ((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm + << 5))) + results_invalid = 0x01; + + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "pdev->xtalk_results", + VL53L1_TRACE_MODULE_CORE); +#endif + + if ((status == VL53L1_ERROR_NONE) && (results_invalid == 0)) { + + status = + VL53L1_ipp_xtalk_calibration_process_data( + Dev, + &(pdev->xtalk_results), + &(pdev->xtalk_shapes), + &(pdev->xtalk_cal)); + + if (status == VL53L1_ERROR_NONE) { + + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + + + } + + + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_xtalk_compensation(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < pdev->xtalk_results.max_results; i++) { + + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples != + + + pX->num_of_samples) { + + + pdev->xtalk_results.num_of_samples_status = + pdev->xtalk_results.num_of_samples_status | + (1 << i); + } + + + if (pdev->xtalk_results.VL53L1_p_002[i].no_of_samples == + 0x00) { + pdev->xtalk_results.zero_samples_status = + pdev->xtalk_results.zero_samples_status | + (1 << i); + } + + + + + + + + + + + + + tmp16 = pX->algo__crosstalk_extract_max_sigma_mm; + if (pdev->xtalk_results.VL53L1_p_002[i].sigma_mm_avg > + ((uint32_t)tmp16 << 5)) { + pdev->xtalk_results.max_sigma_status = + pdev->xtalk_results.max_sigma_status | + (1 << i); + } + + + } + } + + + + + + + + + + + + + + if (results_invalid > 0) { + + + if (pdev->xtalk_results.VL53L1_p_002[4].no_of_samples == 0) { + status = VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL; + } else { + + + + if (pdev->xtalk_results.VL53L1_p_002[4].sigma_mm_avg > + (((uint32_t)pX->algo__crosstalk_extract_max_sigma_mm) + << 5)) { + status = + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL; + } + + + } + } else { + + + if (pdev->xtalk_results.zero_samples_status != 0x00) { + status = VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.max_sigma_status != 0x00) { + status = + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT; + } else { + if (pdev->xtalk_results.num_of_samples_status != + 0x00) + status = + VL53L1_WARNING_XTALK_MISSING_SAMPLES; + } + } + } + + + + + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + + + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_NO_SAMPLE_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_SIGMA_LIMIT_FOR_GRADIENT_WARN, + VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT, + status); + + IGNORE_STATUS( + IGNORE_XTALK_EXTRACTION_MISSING_SAMPLES_WARN, + VL53L1_WARNING_XTALK_MISSING_SAMPLES, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_extract_config( + &(pdev->xtalk_extract_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_extract_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "run_xtalk_extraction():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_range_results( + &(pdev->xtalk_results), + "run_xtalk_extraction():pdev->lldata.xtalk_results.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_and_avg_xtalk_samples( + VL53L1_DEV Dev, + uint8_t num_of_samples, + uint8_t measurement_mode, + int16_t xtalk_filter_thresh_max_mm, + int16_t xtalk_filter_thresh_min_mm, + uint16_t xtalk_max_valid_rate_kcps, + uint8_t xtalk_result_id, + uint8_t xtalk_histo_id, + VL53L1_xtalk_range_results_t *pXR, + VL53L1_histogram_bin_data_t *psum_histo, + VL53L1_histogram_bin_data_t *pavg_histo) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + +#ifdef VL53L1_LOG_ENABLE + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); +#endif + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *prs = &range_results; + + VL53L1_range_data_t *prange_data; + VL53L1_xtalk_range_data_t *pxtalk_range_data; + + uint8_t i = 0; + uint8_t j = 0; + uint8_t zone_id = 0; + uint8_t final_zone = pdev->zone_cfg.active_zones+1; + uint8_t valid_result; + + uint8_t smudge_corr_en = 0; + + + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + for (i = 0; i <= (final_zone*num_of_samples); i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prs); + + + + + + + if (status == VL53L1_ERROR_NONE && + pdev->ll_state.rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + zone_id = pdev->ll_state.rd_zone_id + xtalk_result_id; + prange_data = &(prs->VL53L1_p_002[0]); + + + + if (prs->active_results > 1) { + for (j = 1; + j < prs->active_results; j++) { + if (prs->VL53L1_p_002[j].median_range_mm + < + prange_data->median_range_mm) + prange_data = + &(prs->VL53L1_p_002[j]); + + } + } + + pxtalk_range_data = &(pXR->VL53L1_p_002[zone_id]); + + + + + if ((prs->active_results > 0) && + (prange_data->median_range_mm < + xtalk_filter_thresh_max_mm) && + (prange_data->median_range_mm > + xtalk_filter_thresh_min_mm) && + (prange_data->VL53L1_p_012 < + (uint32_t)(xtalk_max_valid_rate_kcps * 16))) + valid_result = 1; + else + valid_result = 0; + + if (valid_result == 1) { + + pxtalk_range_data->no_of_samples++; + + pxtalk_range_data->rate_per_spad_kcps_sum += + prange_data->VL53L1_p_012; + + pxtalk_range_data->signal_total_events_sum += + prange_data->VL53L1_p_013; + + pxtalk_range_data->sigma_mm_sum += + (uint32_t)prange_data->VL53L1_p_005; + + + + + pxtalk_range_data->median_phase_sum += + (uint32_t)prange_data->VL53L1_p_014; + + + + + + + + + + + } + + if ((valid_result == 1) && (zone_id >= 4)) { + status = VL53L1_sum_histogram_data( + &(pdev->hist_data), + psum_histo); + + + + + + if (prange_data->VL53L1_p_015 < + pXR->central_histogram__window_start) + pXR->central_histogram__window_start = + prange_data->VL53L1_p_015; + + + + if (prange_data->VL53L1_p_016 > + pXR->central_histogram__window_end) + pXR->central_histogram__window_end = + prange_data->VL53L1_p_016; + + } + + } + + + + + + + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_range_results( + &(pres->range_results), + "pres->range_results.", + VL53L1_TRACE_MODULE_CORE); + } +#endif + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + + + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + + for (i = 0; i < (pdev->zone_cfg.active_zones+1); i++) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[i+xtalk_result_id]); + + if (pxtalk_range_data->no_of_samples > 0) { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum / + (int32_t)pxtalk_range_data->no_of_samples; + + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum / + (uint32_t)pxtalk_range_data->no_of_samples; + + + + + } else { + pxtalk_range_data->rate_per_spad_kcps_avg = + pxtalk_range_data->rate_per_spad_kcps_sum; + pxtalk_range_data->signal_total_events_avg = + pxtalk_range_data->signal_total_events_sum; + pxtalk_range_data->sigma_mm_avg = + pxtalk_range_data->sigma_mm_sum; + + + + + pxtalk_range_data->median_phase_avg = + pxtalk_range_data->median_phase_sum; + + + + } + } + + + + + memcpy(pavg_histo, &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + + + + if (status == VL53L1_ERROR_NONE) { + + pxtalk_range_data = &(pXR->VL53L1_p_002[xtalk_histo_id]); + + status = VL53L1_avg_histogram_data( + pxtalk_range_data->no_of_samples, + psum_histo, + pavg_histo); + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_run_offset_calibration( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_DevicePresetModes device_preset_modes[ + VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *prange_results = &range_results; + VL53L1_range_data_t *pRData = NULL; + VL53L1_offset_range_data_t *pfs = NULL; + VL53L1_general_config_t *pG = &(pdev->gen_cfg); + VL53L1_additional_offset_cal_data_t *pAO = &(pdev->add_off_cal_data); + + uint8_t i = 0; + uint8_t m = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + uint16_t manual_effective_spads = + pG->dss_config__manual_effective_spads_select; + + uint8_t num_of_samples[VL53L1_MAX_OFFSET_RANGE_RESULTS]; + + uint8_t smudge_corr_en = 0; + + LOG_FUNCTION_START(""); + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL; + break; + + default: + device_preset_modes[0] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + device_preset_modes[1] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL; + device_preset_modes[2] = + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL; + break; + } + + + + + + num_of_samples[0] = pdev->offsetcal_cfg.pre_num_of_samples; + num_of_samples[1] = pdev->offsetcal_cfg.mm1_num_of_samples; + num_of_samples[2] = pdev->offsetcal_cfg.mm2_num_of_samples; + + + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + pdev->offset_results.active_results = 1; + + break; + + default: + + pdev->customer.mm_config__inner_offset_mm = 0; + pdev->customer.mm_config__outer_offset_mm = 0; + pdev->offset_results.active_results = + VL53L1_MAX_OFFSET_RANGE_RESULTS; + + break; + } + + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.cal_distance_mm = cal_distance_mm; + pdev->offset_results.cal_reflectance_pc = cal_reflectance_pc; + + for (m = 0; m < VL53L1_MAX_OFFSET_RANGE_RESULTS; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + pfs->preset_mode = 0; + pfs->no_of_samples = 0; + pfs->effective_spads = 0; + pfs->peak_rate_mcps = 0; + pfs->VL53L1_p_005 = 0; + pfs->median_range_mm = 0; + } + + + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + status = VL53L1_dynamic_xtalk_correction_disable(Dev); + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + pfs->preset_mode = device_preset_modes[m]; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_modes[m], + + + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps, + pdev->offsetcal_cfg.phasecal_config_timeout_us, + pdev->offsetcal_cfg.mm_config_timeout_us, + pdev->offsetcal_cfg.range_config_timeout_us, + + + 100); + + pG->dss_config__manual_effective_spads_select = + manual_effective_spads; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= (num_of_samples[m]+2); i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + + + + pRData = &(prange_results->VL53L1_p_002[0]); + + if ((prange_results->active_results > 0 && + prange_results->stream_count > 1) && + (pRData->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + + pfs->no_of_samples++; + pfs->effective_spads += + (uint32_t)pRData->VL53L1_p_006; + pfs->peak_rate_mcps += + (uint32_t)pRData->peak_signal_count_rate_mcps; + pfs->VL53L1_p_005 += + (uint32_t)pRData->VL53L1_p_005; + pfs->median_range_mm += + (int32_t)pRData->median_range_mm; + + pfs->dss_config__roi_mode_control = + pG->dss_config__roi_mode_control; + pfs->dss_config__manual_effective_spads_select = + pG->dss_config__manual_effective_spads_select; + + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + if (pfs->no_of_samples > 0) { + + pfs->effective_spads += (pfs->no_of_samples/2); + pfs->effective_spads /= pfs->no_of_samples; + + pfs->peak_rate_mcps += (pfs->no_of_samples/2); + pfs->peak_rate_mcps /= pfs->no_of_samples; + + pfs->VL53L1_p_005 += (pfs->no_of_samples/2); + pfs->VL53L1_p_005 /= pfs->no_of_samples; + + pfs->median_range_mm += (pfs->no_of_samples/2); + pfs->median_range_mm /= pfs->no_of_samples; + + pfs->range_mm_offset = (int32_t)cal_distance_mm; + pfs->range_mm_offset -= pfs->median_range_mm; + + + + if (pfs->preset_mode == + VL53L1_DEVICEPRESETMODE_STANDARD_RANGING) + manual_effective_spads = + (uint16_t)pfs->effective_spads; + } + } + + + + + switch (pdev->offset_calibration_mode) { + + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY: + case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__HISTOGRAM_PRE_RANGE_ONLY: + + + + pdev->customer.mm_config__inner_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm += + (int16_t)pdev->offset_results.VL53L1_p_002[0].range_mm_offset; + break; + + default: + + + pdev->customer.mm_config__inner_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[1].range_mm_offset; + pdev->customer.mm_config__outer_offset_mm = + (int16_t)pdev->offset_results.VL53L1_p_002[2].range_mm_offset; + pdev->customer.algo__part_to_part_range_offset_mm = 0; + + + + + + pAO->result__mm_inner_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].effective_spads; + pAO->result__mm_outer_actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].effective_spads; + + pAO->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[1].peak_rate_mcps; + pAO->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[2].peak_rate_mcps; + + break; + } + + + + + + + + pdev->cust_dmax_cal.ref__actual_effective_spads = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].effective_spads; + pdev->cust_dmax_cal.ref__peak_signal_count_rate_mcps = + (uint16_t)pdev->offset_results.VL53L1_p_002[0].peak_rate_mcps; + + + + pdev->cust_dmax_cal.ref__distance_mm = cal_distance_mm * 16; + + pdev->cust_dmax_cal.ref_reflectance_pc = cal_reflectance_pc; + pdev->cust_dmax_cal.coverglass_transmission = 0x0100; + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + + + + + + if (status == VL53L1_ERROR_NONE) { + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + } + + + + + + + + + for (m = 0; m < pdev->offset_results.active_results; m++) { + + pfs = &(pdev->offset_results.VL53L1_p_002[m]); + + if (status == VL53L1_ERROR_NONE) { + + pdev->offset_results.cal_report = m; + + if (pfs->no_of_samples < num_of_samples[m]) + status = + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES; + + + + + + + if (m == 0 && pfs->VL53L1_p_005 > + ((uint32_t)VL53L1_OFFSET_CAL_MAX_SIGMA_MM << 5)) + status = + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH; + + if (pfs->peak_rate_mcps > + VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH; + + if (pfs->dss_config__manual_effective_spads_select < + VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS) + status = + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW; + + if (pfs->dss_config__manual_effective_spads_select == 0) + status = + VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL; + + if (pfs->no_of_samples == 0) + status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL; + } + } + + + + + + + pdev->offset_results.cal_status = status; + *pcal_status = pdev->offset_results.cal_status; + + + + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_MISSING_SAMPLES, + VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_offset_calibration():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "run_offset_calibration():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "run_offset_calibration():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "run_offset_calibration():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + + VL53L1_print_offset_range_results( + &(pdev->offset_results), + "run_offset_calibration():pdev->lldata.offset_results.", + VL53L1_TRACE_MODULE_OFFSET_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_phasecal_average( + VL53L1_DEV Dev, + uint8_t measurement_mode, + uint8_t phasecal_result__vcsel_start, + uint16_t phasecal_num_of_samples, + VL53L1_range_results_t *prange_results, + uint16_t *pphasecal_result__reference_phase, + uint16_t *pzero_distance_phase) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint16_t i = 0; + uint16_t m = 0; + uint32_t samples = 0; + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + uint32_t phasecal_result__reference_phase = 0; + uint32_t zero_distance_phase = 0; + + + + + for (m = 0; m < phasecal_num_of_samples; m++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + for (i = 0; i <= 1; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + + if (status == VL53L1_ERROR_NONE) { + + samples++; + + + + + + + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period( + pdev->hist_data.VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + VL53L1_p_017 += + (2048 * + (uint32_t)phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * + (uint32_t)pdev->hist_data.cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + phasecal_result__reference_phase += (uint32_t)( + pdev->hist_data.phasecal_result__reference_phase); + + zero_distance_phase += (uint32_t)VL53L1_p_017; + } + } + + + + + if (status == VL53L1_ERROR_NONE && samples > 0) { + + phasecal_result__reference_phase += (samples >> 1); + phasecal_result__reference_phase /= samples; + + zero_distance_phase += (samples >> 1); + zero_distance_phase /= samples; + + *pphasecal_result__reference_phase = + (uint16_t)phasecal_result__reference_phase; + *pzero_distance_phase = + (uint16_t)zero_distance_phase; + } + + return status; +} + + +VL53L1_Error VL53L1_run_zone_calibration( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + VL53L1_DeviceZonePreset zone_preset, + VL53L1_zone_config_t *pzone_cfg, + int16_t cal_distance_mm, + uint16_t cal_reflectance_pc, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *pRR = &range_results; + VL53L1_range_data_t *prange_data = NULL; + VL53L1_zone_calibration_data_t *pzone_data = NULL; + + uint16_t i = 0; + uint16_t m = 0; + + uint8_t z = 0; + uint8_t measurement_mode = + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + VL53L1_OffsetCorrectionMode offset_cor_mode = + VL53L1_OFFSETCORRECTIONMODE__NONE; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_preset_mode( + Dev, + device_preset_mode, + + + pdev->zonecal_cfg.dss_config__target_total_rate_mcps, + pdev->zonecal_cfg.phasecal_config_timeout_us, + pdev->zonecal_cfg.mm_config_timeout_us, + pdev->zonecal_cfg.range_config_timeout_us, + + + 100); + + + + + if (zone_preset == VL53L1_DEVICEZONEPRESET_CUSTOM) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_config( + Dev, + pzone_cfg); + + } else if (zone_preset != VL53L1_DEVICEZONEPRESET_NONE) { + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_zone_preset( + Dev, + zone_preset); + } + + + + + + + pres->zone_cal.preset_mode = device_preset_mode; + pres->zone_cal.zone_preset = zone_preset; + + + pres->zone_cal.cal_distance_mm = cal_distance_mm * 16; + pres->zone_cal.cal_reflectance_pc = cal_reflectance_pc; + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = pdev->zone_cfg.active_zones + 1; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_014 = 0; + pres->zone_cal.VL53L1_p_002[i].VL53L1_p_005 = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pres->zone_cal.phasecal_result__reference_phase = 0; + pres->zone_cal.zero_distance_phase = 0; + + + + + + + + status = + VL53L1_get_offset_correction_mode( + Dev, + &offset_cor_mode); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + VL53L1_OFFSETCORRECTIONMODE__NONE); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + + + + + m = (pdev->zonecal_cfg.zone_num_of_samples + 2) * + (uint16_t)pres->zone_cal.active_zones; + + + + for (i = 0; i <= m; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_range_completion(Dev); + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + pRR); + + + + + + + + + + prange_data = &(pRR->VL53L1_p_002[0]); + + if (pRR->active_results > 0 && + i > (uint16_t)pres->zone_cal.active_zones) { + + if (prange_data->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + + pres->zone_cal.phasecal_result__reference_phase + = + pdev->hist_data.phasecal_result__reference_phase + ; + pres->zone_cal.zero_distance_phase = + pdev->hist_data.zero_distance_phase; + + pzone_data = + &(pres->zone_cal.VL53L1_p_002[pRR->zone_id]); + pzone_data->no_of_samples++; + pzone_data->effective_spads += + (uint32_t)prange_data->VL53L1_p_006; + pzone_data->peak_rate_mcps += (uint32_t)( + prange_data->peak_signal_count_rate_mcps); + pzone_data->VL53L1_p_014 += + (uint32_t)prange_data->VL53L1_p_014; + pzone_data->VL53L1_p_005 += + (uint32_t)prange_data->VL53L1_p_005; + pzone_data->median_range_mm += + (int32_t)prange_data->median_range_mm; + + } + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs(Dev, 1000); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_phasecal_average( + Dev, + measurement_mode, + pdev->hist_data.phasecal_result__vcsel_start, + + + pdev->zonecal_cfg.phasecal_num_of_samples, + + + pRR, + &(pres->zone_cal.phasecal_result__reference_phase), + &(pres->zone_cal.zero_distance_phase)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_offset_correction_mode( + Dev, + offset_cor_mode); + + + + + if (status == VL53L1_ERROR_NONE) { + + for (z = 0; z < pres->zone_cal.active_zones; z++) { + + pzone_data = &(pres->zone_cal.VL53L1_p_002[z]); + + + + if (pzone_data->no_of_samples > 0) { + + pzone_data->effective_spads += + (pzone_data->no_of_samples/2); + pzone_data->effective_spads /= + pzone_data->no_of_samples; + + pzone_data->peak_rate_mcps += + (pzone_data->no_of_samples/2); + pzone_data->peak_rate_mcps /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_014 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_014 /= + pzone_data->no_of_samples; + + pzone_data->VL53L1_p_005 += + (pzone_data->no_of_samples/2); + pzone_data->VL53L1_p_005 /= + pzone_data->no_of_samples; + + + + + + + + pzone_data->median_range_mm = + VL53L1_range_maths( + pdev->stat_nvm.osc_measured__fast_osc__frequency + , (uint16_t)pzone_data->VL53L1_p_014, + pres->zone_cal.zero_distance_phase, + 2, + + 0x0800, + + 0); + + + pzone_data->range_mm_offset = + ((int32_t)cal_distance_mm) * 4; + pzone_data->range_mm_offset -= + pzone_data->median_range_mm; + + + + if (pzone_data->no_of_samples < + pdev->zonecal_cfg.zone_num_of_samples) + status = + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES; + + + + if (pzone_data->VL53L1_p_005 > + ((uint32_t)VL53L1_ZONE_CAL_MAX_SIGMA_MM + << 5)) + status = + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH; + + if (pzone_data->peak_rate_mcps > + VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS) + status = + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH; + + } else { + status = VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL; + } + } + } + + + + + + + pres->zone_cal.cal_status = status; + *pcal_status = pres->zone_cal.cal_status; + + + + + IGNORE_STATUS( + IGNORE_ZONE_CAL_MISSING_SAMPLES, + VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_SIGMA_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH, + status); + + IGNORE_STATUS( + IGNORE_ZONE_CAL_RATE_TOO_HIGH, + VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH, + status); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_zone_calibration_results( + &(pres->zone_cal), + "run_zone_calibration():pdev->llresults.zone_cal.", + VL53L1_TRACE_MODULE_OFFSET_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_spad_rate_map( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode, + VL53L1_DeviceSscArray array_select, + uint32_t ssc_config_timeout_us, + VL53L1_spad_rate_data_t *pspad_rate_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) { + pdev->ssc_cfg.array_select = array_select; + pdev->ssc_cfg.timeout_us = ssc_config_timeout_us; + status = + VL53L1_set_ssc_config( + Dev, + &(pdev->ssc_cfg), + pdev->stat_nvm.osc_measured__fast_osc__frequency); + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_run_device_test( + Dev, + device_test_mode); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_spad_rate_data( + Dev, + pspad_rate_data); + + if (device_test_mode == VL53L1_DEVICETESTMODE_LCR_VCSEL_ON) + pspad_rate_data->fractional_bits = 7; + else + pspad_rate_data->fractional_bits = 15; + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + +#ifdef VL53L1_LOG_ENABLE + + + + if (status == VL53L1_ERROR_NONE) { + VL53L1_print_spad_rate_data( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + VL53L1_print_spad_rate_map( + pspad_rate_data, + "run_spad_rate_map():", + VL53L1_TRACE_MODULE_SPAD_RATE_MAP); + } +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_device_test( + VL53L1_DEV Dev, + VL53L1_DeviceTestMode device_test_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[2]; + uint8_t gpio_hv_mux__ctrl = 0; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_RdByte( + Dev, + VL53L1_GPIO_HV_MUX__CTRL, + &gpio_hv_mux__ctrl); + + if (status == VL53L1_ERROR_NONE) + pdev->stat_cfg.gpio_hv_mux__ctrl = gpio_hv_mux__ctrl; + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_start_test( + Dev, + device_test_mode); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_test_completion(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__RANGE_STATUS, + comms_buffer, + 2); + + if (status == VL53L1_ERROR_NONE) { + pdev->sys_results.result__range_status = comms_buffer[0]; + pdev->sys_results.result__report_status = comms_buffer[1]; + } + + + + + pdev->sys_results.result__range_status &= + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + if (status == VL53L1_ERROR_NONE) { + trace_print( + VL53L1_TRACE_LEVEL_INFO, + " Device Test Complete:\n\t%-32s = %3u\n\t%-32s = %3u\n", + "result__range_status", + pdev->sys_results.result__range_status, + "result__report_status", + pdev->sys_results.result__report_status); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_clear_interrupt(Dev); + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_start_test( + Dev, + 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_xtalk_extract_data_init( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + int32_t lb = 0; + + pxtalk_data->sample_count = 0U; + pxtalk_data->pll_period_mm = 0U; + pxtalk_data->peak_duration_us_sum = 0U; + pxtalk_data->effective_spad_count_sum = 0U; + pxtalk_data->zero_distance_phase_sum = 0U; + pxtalk_data->zero_distance_phase_avg = 0U; + pxtalk_data->event_scaler_sum = 0U; + pxtalk_data->event_scaler_avg = 4096U; + pxtalk_data->signal_events_sum = 0; + pxtalk_data->xtalk_rate_kcps_per_spad = 0U; + pxtalk_data->VL53L1_p_015 = 0U; + pxtalk_data->VL53L1_p_016 = 0U; + pxtalk_data->target_start = 0U; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) + pxtalk_data->bin_data_sums[lb] = 0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_update( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_hist_xtalk_extract_calc_window( + target_distance_mm, + target_width_oversize, + phist_bins, + pxtalk_data); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_hist_xtalk_extract_calc_event_sums( + phist_bins, + pxtalk_data); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_fini( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_calibration_results_t *pxtalk_cal, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_xtalk_calibration_results_t *pX = pxtalk_cal; + + LOG_FUNCTION_START(""); + + if (pxtalk_data->sample_count > 0) { + + + + pxtalk_data->event_scaler_avg = pxtalk_data->event_scaler_sum; + pxtalk_data->event_scaler_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->event_scaler_avg /= pxtalk_data->sample_count; + + + + + + + status = + VL53L1_hist_xtalk_extract_calc_rate_per_spad( + pxtalk_data); + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + pxtalk_data->zero_distance_phase_avg = + pxtalk_data->zero_distance_phase_sum; + pxtalk_data->zero_distance_phase_avg += + (pxtalk_data->sample_count >> 1); + pxtalk_data->zero_distance_phase_avg /= + pxtalk_data->sample_count; + + + + status = + VL53L1_hist_xtalk_extract_calc_shape( + pxtalk_data, + pxtalk_shape); + + + + + + + + + + + + pxtalk_shape->phasecal_result__vcsel_start = + phist_bins->phasecal_result__vcsel_start; + pxtalk_shape->cal_config__vcsel_start = + phist_bins->cal_config__vcsel_start; + pxtalk_shape->vcsel_width = + phist_bins->vcsel_width; + pxtalk_shape->VL53L1_p_019 = + phist_bins->VL53L1_p_019; + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pxtalk_data->xtalk_rate_kcps_per_spad; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps + = 0U; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps + = 0U; + + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_run_hist_xtalk_extraction( + VL53L1_DEV Dev, + int16_t cal_distance_mm, + VL53L1_Error *pcal_status) +{ + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalkextract_config_t *pX = &(pdev->xtalk_extract_cfg); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pXC = &(pdev->xtalk_cal); + + + + + + + uint8_t smudge_corr_en = 0; + uint8_t i = 0; + uint8_t measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + + + + VL53L1_range_results_t range_results; + VL53L1_range_results_t *prange_results = &range_results; + + LOG_FUNCTION_START(""); + + + + + VL53L1_hist_xtalk_extract_data_init( + &(pdev->xtalk_extract)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_preset_mode( + Dev, + VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE, + pX->dss_config__target_total_rate_mcps, + pX->phasecal_config_timeout_us, + pX->mm_config_timeout_us, + pX->range_config_timeout_us, + 100); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_disable_xtalk_compensation( + Dev); + } + + + + + smudge_corr_en = pdev->smudge_correct_config.smudge_corr_enabled; + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_dynamic_xtalk_correction_disable(Dev); + } + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS); + + + + + for (i = 0; i <= pX->num_of_samples; i++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_range_completion(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_device_results( + Dev, + VL53L1_DEVICERESULTSLEVEL_FULL, + prange_results); + + + + + + + if (status == VL53L1_ERROR_NONE && + pdev->ll_state.rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + status = + VL53L1_hist_xtalk_extract_update( + cal_distance_mm, + 4, + + &(pdev->hist_data), + &(pdev->xtalk_extract)); + } + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_firmware_ready(Dev); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_clear_interrupt_and_enable_next_range( + Dev, + measurement_mode); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_stop_range(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_xtalk_extract_fini( + &(pdev->hist_data), + &(pdev->xtalk_extract), + &(pdev->xtalk_cal), + &(pdev->xtalk_shapes.xtalk_shape)); + + + + + + if (status == VL53L1_ERROR_NONE) { + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pXC->algo__crosstalk_compensation_y_plane_gradient_kcps; + pC->algo__crosstalk_compensation_plane_offset_kcps = + pXC->algo__crosstalk_compensation_plane_offset_kcps; + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_xtalk_compensation(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + if (smudge_corr_en == 1) + status = VL53L1_dynamic_xtalk_correction_enable(Dev); + + + + + + + pdev->xtalk_results.cal_status = status; + *pcal_status = pdev->xtalk_results.cal_status; + + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "run_xtalk_extraction():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_config( + &(pdev->xtalk_cfg), + "run_xtalk_extraction():pdev->lldata.xtalk_cfg.", + VL53L1_TRACE_MODULE_XTALK_DATA); + + VL53L1_print_xtalk_histogram_data( + &(pdev->xtalk_shapes), + "pdev->lldata.xtalk_shapes.", + VL53L1_TRACE_MODULE_XTALK_DATA); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_api_core.c b/drivers/oneplus/vl53L1/src/vl53l1_api_core.c new file mode 100755 index 0000000000000000000000000000000000000000..8ae39b0fe6328e03b4aed2b022c4ccfbe47f0aa4 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_api_core.c @@ -0,0 +1,7438 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_ipp.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_hist_map.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_api_core.h" +#include "vl53l1_tuning_parm_defaults.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_api_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#define VL53L1_MAX_I2C_XFER_SIZE 256 + +VL53L1_Error VL53L1_get_version( + VL53L1_DEV Dev, + VL53L1_ll_version_t *pdata) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_init_version(Dev); + + memcpy(pdata, &(pdev->version), sizeof(VL53L1_ll_version_t)); + + return VL53L1_ERROR_NONE; +} + + +VL53L1_Error VL53L1_get_device_firmware_version( + VL53L1_DEV Dev, + uint16_t *pfw_version) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_RdWord( + Dev, + VL53L1_MCU_GENERAL_PURPOSE__GP_0, + pfw_version); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_data_init( + VL53L1_DEV Dev, + uint8_t read_p2p_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + + VL53L1_zone_objects_t *pobjects; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_UNKNOWN); + + pres->range_results.max_results = VL53L1_MAX_RANGE_RESULTS; + pres->range_results.active_results = 0; + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = 0; + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pobjects = &(pres->zone_results.VL53L1_p_002[i]); + pobjects->xmonitor.VL53L1_p_020 = 0; + pobjects->xmonitor.VL53L1_p_021 = 0; + pobjects->xmonitor.VL53L1_p_014 = 0; + pobjects->xmonitor.range_status = + VL53L1_DEVICEERROR_NOUPDATE; + } + + + + + pres->zone_hists.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_hists.active_zones = 0; + + + + + pres->zone_cal.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_cal.active_zones = 0; + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pres->zone_cal.VL53L1_p_002[i].no_of_samples = 0; + pres->zone_cal.VL53L1_p_002[i].effective_spads = 0; + pres->zone_cal.VL53L1_p_002[i].peak_rate_mcps = 0; + pres->zone_cal.VL53L1_p_002[i].median_range_mm = 0; + pres->zone_cal.VL53L1_p_002[i].range_mm_offset = 0; + } + + pdev->wait_method = VL53L1_WAIT_METHOD_BLOCKING; + pdev->preset_mode = VL53L1_DEVICEPRESETMODE_STANDARD_RANGING; + pdev->zone_preset = VL53L1_DEVICEZONEPRESET_NONE; + pdev->measurement_mode = VL53L1_DEVICEMEASUREMENTMODE_STOP; + + pdev->offset_calibration_mode = + VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD; + pdev->offset_correction_mode = + VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS; + pdev->dmax_mode = + VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA; + + pdev->phasecal_config_timeout_us = 1000; + pdev->mm_config_timeout_us = 2000; + pdev->range_config_timeout_us = 13000; + pdev->inter_measurement_period_ms = 100; + pdev->dss_config__target_total_rate_mcps = 0x0A00; + pdev->debug_mode = 0x00; + + pdev->offset_results.max_results = VL53L1_MAX_OFFSET_RANGE_RESULTS; + pdev->offset_results.active_results = 0; + + + + + + pdev->gain_cal.standard_ranging_gain_factor = + VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR_DEFAULT; + pdev->gain_cal.histogram_ranging_gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + + + VL53L1_init_version(Dev); + + + + + + + + + + + if (read_p2p_data > 0 && status == VL53L1_ERROR_NONE) + + status = VL53L1_read_p2p_data(Dev); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_refspadchar_config_struct( + &(pdev->refspadchar)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_ssc_config_struct( + &(pdev->ssc_cfg)); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_xtalk_config_struct( + &(pdev->customer), + &(pdev->xtalk_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_xtalk_extract_config_struct( + &(pdev->xtalk_extract_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_offset_cal_config_struct( + &(pdev->offsetcal_cfg)); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_zone_cal_config_struct( + &(pdev->zonecal_cfg)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_hist_post_process_config_struct( + pdev->xtalk_cfg.global_crosstalk_compensation_enable, + &(pdev->histpostprocess)); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_hist_gen3_dmax_config_struct( + &(pdev->dmax_cfg)); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_init_tuning_parm_storage_struct( + &(pdev->tuning_parms)); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_set_preset_mode( + Dev, + pdev->preset_mode, + pdev->dss_config__target_total_rate_mcps, + + pdev->phasecal_config_timeout_us, + pdev->mm_config_timeout_us, + pdev->range_config_timeout_us, + pdev->inter_measurement_period_ms); + + + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_data)); + + VL53L1_init_histogram_bin_data_struct( + 0, + VL53L1_HISTOGRAM_BUFFER_SIZE, + &(pdev->hist_xtalk)); + + + + VL53L1_init_xtalk_bin_data_struct( + 0, + VL53L1_XTALK_HISTO_BINS, + &(pdev->xtalk_shapes.xtalk_shape)); + + + + + + VL53L1_xtalk_cal_data_init( + Dev + ); + + + + + + VL53L1_dynamic_xtalk_correction_data_init( + Dev + ); + + + + + + VL53L1_low_power_auto_data_init( + Dev + ); + +#ifdef VL53L1_LOG_ENABLE + + + + + VL53L1_print_static_nvm_managed( + &(pdev->stat_nvm), + "data_init():pdev->lldata.stat_nvm.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_customer_nvm_managed( + &(pdev->customer), + "data_init():pdev->lldata.customer.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_nvm_copy_data( + &(pdev->nvm_copy_data), + "data_init():pdev->lldata.nvm_copy_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->fmt_dmax_cal), + "data_init():pdev->lldata.fmt_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_dmax_calibration_data( + &(pdev->cust_dmax_cal), + "data_init():pdev->lldata.cust_dmax_cal.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_additional_offset_cal_data( + &(pdev->add_off_cal_data), + "data_init():pdev->lldata.add_off_cal_data.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_user_zone( + &(pdev->mm_roi), + "data_init():pdev->lldata.mm_roi.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_optical_centre( + &(pdev->optical_centre), + "data_init():pdev->lldata.optical_centre.", + VL53L1_TRACE_MODULE_DATA_INIT); + + VL53L1_print_cal_peak_rate_map( + &(pdev->cal_peak_rate_map), + "data_init():pdev->lldata.cal_peak_rate_map.", + VL53L1_TRACE_MODULE_DATA_INIT); + +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_p2p_data( + VL53L1_DEV Dev) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_additional_offset_cal_data_t *pCD = &(pdev->add_off_cal_data); + + VL53L1_decoded_nvm_fmt_range_data_t fmt_rrd; + + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_get_static_nvm_managed( + Dev, + &(pdev->stat_nvm)); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_get_customer_nvm_managed( + Dev, + &(pdev->customer)); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_get_nvm_copy_data( + Dev, + &(pdev->nvm_copy_data)); + + + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + } + + + + + if (status == VL53L1_ERROR_NONE) { + pHP->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_optical_centre( + Dev, + &(pdev->optical_centre)); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_read_nvm_cal_peak_rate_map( + Dev, + &(pdev->cal_peak_rate_map)); + + + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_additional_offset_cal_data( + Dev, + &(pdev->add_off_cal_data)); + + + + + + + if (pCD->result__mm_inner_peak_signal_count_rtn_mcps == 0 && + pCD->result__mm_outer_peak_signal_count_rtn_mcps == 0) { + + pCD->result__mm_inner_peak_signal_count_rtn_mcps + = 0x0080; + + pCD->result__mm_outer_peak_signal_count_rtn_mcps + = 0x0180; + + + + + + VL53L1_calc_mm_effective_spads( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + 0xC7, + + 0xFF, + &(pdev->rtn_good_spads[0]), + VL53L1_RTN_SPAD_APERTURE_TRANSMISSION, + &(pCD->result__mm_inner_actual_effective_spads), + &(pCD->result__mm_outer_actual_effective_spads)); + } + } + + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_read_nvm_fmt_range_results_data( + Dev, + VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK, + &fmt_rrd); + + if (status == VL53L1_ERROR_NONE) { + pdev->fmt_dmax_cal.ref__actual_effective_spads = + fmt_rrd.result__actual_effective_rtn_spads; + pdev->fmt_dmax_cal.ref__peak_signal_count_rate_mcps = + fmt_rrd.result__peak_signal_count_rate_rtn_mcps; + pdev->fmt_dmax_cal.ref__distance_mm = + fmt_rrd.measured_distance_mm; + + + + + + + if (pdev->cal_peak_rate_map.cal_reflectance_pc != 0) { + pdev->fmt_dmax_cal.ref_reflectance_pc = + pdev->cal_peak_rate_map.cal_reflectance_pc; + } else { + pdev->fmt_dmax_cal.ref_reflectance_pc = 0x0014; + } + + + + pdev->fmt_dmax_cal.coverglass_transmission = 0x0100; + } + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_RdWord( + Dev, + VL53L1_RESULT__OSC_CALIBRATE_VAL, + &(pdev->dbg_results.result__osc_calibrate_val)); + + + + + + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency < 0x1000) { + trace_print( + VL53L1_TRACE_LEVEL_WARNING, + "\nInvalid %s value (0x%04X) - forcing to 0x%04X\n\n", + "pdev->stat_nvm.osc_measured__fast_osc__frequency", + pdev->stat_nvm.osc_measured__fast_osc__frequency, + 0xBCCC); + pdev->stat_nvm.osc_measured__fast_osc__frequency = 0xBCCC; + } + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_get_mode_mitigation_roi( + Dev, + &(pdev->mm_roi)); + + + + + + + if (pdev->optical_centre.x_centre == 0 && + pdev->optical_centre.y_centre == 0) { + pdev->optical_centre.x_centre = + pdev->mm_roi.x_centre << 4; + pdev->optical_centre.y_centre = + pdev->mm_roi.y_centre << 4; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_software_reset( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x00); + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitUs( + Dev, + VL53L1_SOFTWARE_RESET_DURATION_US); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_SOFT_RESET, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_wait_for_boot_completion(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint32_t tempu32; + + LOG_FUNCTION_START(""); + + if (pcal_data->struct_version != + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION) { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + if (status == VL53L1_ERROR_NONE) { + + + + memcpy( + &(pdev->customer), + &(pcal_data->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + memcpy( + &(pdev->add_off_cal_data), + &(pcal_data->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pdev->fmt_dmax_cal), + &(pcal_data->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pdev->cust_dmax_cal), + &(pcal_data->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pdev->xtalk_shapes), + &(pcal_data->xtalkhisto), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(pdev->gain_cal), + &(pcal_data->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pdev->cal_peak_rate_map), + &(pcal_data->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + + + + + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pN->algo__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pN->algo__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pN->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + if (pC->global_crosstalk_compensation_enable == 0x00) { + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + } else { + tempu32 = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + + + + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_part_to_part_data( + VL53L1_DEV Dev, + VL53L1_calibration_data_t *pcal_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_customer_nvm_managed_t *pCN = &(pcal_data->customer); + + LOG_FUNCTION_START(""); + + pcal_data->struct_version = + VL53L1_LL_CALIBRATION_DATA_STRUCT_VERSION; + + + + memcpy( + &(pcal_data->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + + + + + + if (pC->algo__crosstalk_compensation_plane_offset_kcps > 0xFFFF) { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + 0xFFFF; + } else { + pCN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)pC->algo__crosstalk_compensation_plane_offset_kcps; + } + pCN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pCN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + memcpy( + &(pcal_data->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pcal_data->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + + + memcpy( + &(pcal_data->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + + + memcpy( + &(pcal_data->optical_centre), + &(pdev->optical_centre), + sizeof(VL53L1_optical_centre_t)); + + + + memcpy( + &(pcal_data->xtalkhisto), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + + + memcpy( + &(pcal_data->gain_cal), + &(pdev->gain_cal), + sizeof(VL53L1_gain_calibration_data_t)); + + + + memcpy( + &(pcal_data->cal_peak_rate_map), + &(pdev->cal_peak_rate_map), + sizeof(VL53L1_cal_peak_rate_map_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t inter_measurement_period_ms) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + pdev->tim_cfg.system__intermeasurement_period = + inter_measurement_period_ms * + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_inter_measurement_period_ms( + VL53L1_DEV Dev, + uint32_t *pinter_measurement_period_ms) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->dbg_results.result__osc_calibrate_val == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) + *pinter_measurement_period_ms = + pdev->tim_cfg.system__intermeasurement_period / + (uint32_t)pdev->dbg_results.result__osc_calibrate_val; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timeouts_us( + VL53L1_DEV Dev, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + pdev->phasecal_config_timeout_us = phasecal_config_timeout_us; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + + status = + VL53L1_calc_timeout_register_values( + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us, + pdev->stat_nvm.osc_measured__fast_osc__frequency, + &(pdev->gen_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timeouts_us( + VL53L1_DEV Dev, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (pdev->stat_nvm.osc_measured__fast_osc__frequency == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + + if (status == VL53L1_ERROR_NONE) { + + + + macro_period_us = + VL53L1_calc_macro_period_us( + pdev->stat_nvm.osc_measured__fast_osc__frequency, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + + *pphasecal_config_timeout_us = + VL53L1_calc_timeout_us( + (uint32_t)pdev->gen_cfg.phasecal_config__timeout_macrop, + macro_period_us); + + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.mm_config__timeout_macrop_a_lo; + + *pmm_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + + + + timeout_encoded = + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_hi; + timeout_encoded = (timeout_encoded << 8) + + (uint16_t)pdev->tim_cfg.range_config__timeout_macrop_a_lo; + + *prange_config_timeout_us = + VL53L1_calc_decoded_timeout_us( + timeout_encoded, + macro_period_us); + + pdev->phasecal_config_timeout_us = *pphasecal_config_timeout_us; + pdev->mm_config_timeout_us = *pmm_config_timeout_us; + pdev->range_config_timeout_us = *prange_config_timeout_us; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t cal_config__repeat_period) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->gen_cfg.cal_config__repeat_rate = cal_config__repeat_period; + + return status; + +} + + +VL53L1_Error VL53L1_get_calibration_repeat_period( + VL53L1_DEV Dev, + uint16_t *pcal_config__repeat_period) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pcal_config__repeat_period = pdev->gen_cfg.cal_config__repeat_rate; + + return status; + +} + + +VL53L1_Error VL53L1_set_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t value) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + uint8_t clr_mask = 0xFF - bit_mask; + uint8_t bit_value = value & bit_mask; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) { + bit_mask = 0x01 << bit_id; + bit_value = bit_value << bit_id; + clr_mask = 0xFF - bit_mask; + } + + pdev->dyn_cfg.system__sequence_config = + (pdev->dyn_cfg.system__sequence_config & clr_mask) | + bit_value; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; + +} + + +VL53L1_Error VL53L1_get_sequence_config_bit( + VL53L1_DEV Dev, + VL53L1_DeviceSequenceConfig bit_id, + uint8_t *pvalue) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t bit_mask = 0x01; + + if (bit_id <= VL53L1_DEVICESEQUENCECONFIG_RANGE) { + + if (bit_id > 0) + bit_mask = 0x01 << bit_id; + + *pvalue = + pdev->dyn_cfg.system__sequence_config & bit_mask; + + if (bit_id > 0) + *pvalue = *pvalue >> bit_id; + + } else { + status = VL53L1_ERROR_INVALID_PARAMS; + } + + return status; +} + + +VL53L1_Error VL53L1_set_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity interrupt_polarity) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->stat_cfg.gpio_hv_mux__ctrl = + (pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_CLEAR_MASK) | + (interrupt_polarity & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK); + + return status; + +} + + +VL53L1_Error VL53L1_set_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->refspadchar.device_test_mode = pdata->device_test_mode; + pdev->refspadchar.VL53L1_p_009 = pdata->VL53L1_p_009; + pdev->refspadchar.timeout_us = pdata->timeout_us; + pdev->refspadchar.target_count_rate_mcps = + pdata->target_count_rate_mcps; + pdev->refspadchar.min_count_rate_limit_mcps = + pdata->min_count_rate_limit_mcps; + pdev->refspadchar.max_count_rate_limit_mcps = + pdata->max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_refspadchar_config_struct( + VL53L1_DEV Dev, + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdata->device_test_mode = pdev->refspadchar.device_test_mode; + pdata->VL53L1_p_009 = pdev->refspadchar.VL53L1_p_009; + pdata->timeout_us = pdev->refspadchar.timeout_us; + pdata->target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + pdata->min_count_rate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + pdata->max_count_rate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t range_ignore_thresh_mult, + uint16_t range_ignore_threshold_mcps) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + range_ignore_threshold_mcps; + + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + range_ignore_thresh_mult; + + return status; + +} + +VL53L1_Error VL53L1_get_range_ignore_threshold( + VL53L1_DEV Dev, + uint8_t *prange_ignore_thresh_mult, + uint16_t *prange_ignore_threshold_mcps_internal, + uint16_t *prange_ignore_threshold_mcps_current) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *prange_ignore_thresh_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + *prange_ignore_threshold_mcps_current = + pdev->stat_cfg.algo__range_ignore_threshold_mcps; + + *prange_ignore_threshold_mcps_internal = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + + return status; + +} + + + +VL53L1_Error VL53L1_get_interrupt_polarity( + VL53L1_DEV Dev, + VL53L1_DeviceInterruptPolarity *pinterrupt_polarity) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + *pinterrupt_polarity = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTPOLARITY_BIT_MASK; + + return status; + +} + + +VL53L1_Error VL53L1_set_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + VL53L1_encode_row_col( + puser_zone->y_centre, + puser_zone->x_centre, + &(pdev->dyn_cfg.roi_config__user_roi_centre_spad)); + + + + VL53L1_encode_zone_size( + puser_zone->width, + puser_zone->height, + &(pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size)); + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_user_zone( + VL53L1_DEV Dev, + VL53L1_user_zone_t *puser_zone) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + VL53L1_decode_row_col( + pdev->dyn_cfg.roi_config__user_roi_centre_spad, + &(puser_zone->y_centre), + &(puser_zone->x_centre)); + + + + VL53L1_decode_zone_size( + pdev->dyn_cfg.roi_config__user_roi_requested_global_xy_size, + &(puser_zone->width), + &(puser_zone->height)); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_get_mode_mitigation_roi( + VL53L1_DEV Dev, + VL53L1_user_zone_t *pmm_roi) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t x = 0; + uint8_t y = 0; + uint8_t xy_size = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_decode_row_col( + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + &y, + &x); + + pmm_roi->x_centre = x; + pmm_roi->y_centre = y; + + + + + + + + + + + xy_size = pdev->nvm_copy_data.roi_config__mode_roi_xy_size; + + pmm_roi->height = xy_size >> 4; + pmm_roi->width = xy_size & 0x0F; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy(&(pdev->zone_cfg.user_zones), &(pzone_cfg->user_zones), + sizeof(pdev->zone_cfg.user_zones)); + + + + pdev->zone_cfg.max_zones = pzone_cfg->max_zones; + pdev->zone_cfg.active_zones = pzone_cfg->active_zones; + + status = VL53L1_init_zone_config_histogram_bins(&pdev->zone_cfg); + + + + + + + + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_zone_config( + VL53L1_DEV Dev, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy(pzone_cfg, &(pdev->zone_cfg), sizeof(VL53L1_zone_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_get_preset_mode_timing_cfg( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t *pdss_config__target_total_rate_mcps, + uint32_t *pphasecal_config_timeout_us, + uint32_t *pmm_config_timeout_us, + uint32_t *prange_config_timeout_us) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_OLT: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + *pdss_config__target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + *pphasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + *pmm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + *prange_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_preset_mode( + VL53L1_DEV Dev, + VL53L1_DevicePresetModes device_preset_mode, + uint16_t dss_config__target_total_rate_mcps, + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint32_t inter_measurement_period_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_hist_post_process_config_t *phistpostprocess = + &(pdev->histpostprocess); + + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_histogram_config_t *phistogram = &(pdev->hist_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_tuning_parm_storage_t *ptuning_parms = &(pdev->tuning_parms); + VL53L1_low_power_auto_data_t *plpadata = + &(pdev->low_power_auto_data); + + LOG_FUNCTION_START(""); + + + + pdev->preset_mode = device_preset_mode; + pdev->mm_config_timeout_us = mm_config_timeout_us; + pdev->range_config_timeout_us = range_config_timeout_us; + pdev->inter_measurement_period_ms = inter_measurement_period_ms; + + + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + + + switch (device_preset_mode) { + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING: + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL: + status = VL53L1_preset_mode_standard_ranging_mm1_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL: + status = VL53L1_preset_mode_standard_ranging_mm2_cal( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING: + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE: + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE: + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING: + status = VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM1: + status = VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_WITH_MM2: + status = VL53L1_preset_mode_histogram_ranging_with_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM1_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_MM2_CAL: + status = VL53L1_preset_mode_histogram_ranging_mm2_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE: + status = VL53L1_preset_mode_histogram_multizone( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_multizone_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MULTIZONE_LONG_RANGE: + status = VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_REF_ARRAY: + status = VL53L1_preset_mode_histogram_ranging_ref( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_RANGING_SHORT_TIMING: + status = VL53L1_preset_mode_histogram_ranging_short_timing( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE: + status = VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM1: + status = VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_LONG_RANGE_MM2: + status = VL53L1_preset_mode_histogram_long_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE: + status = VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM1: + status = VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_MEDIUM_RANGE_MM2: + status = VL53L1_preset_mode_histogram_medium_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM1: + status = VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_SHORT_RANGE_MM2: + status = VL53L1_preset_mode_histogram_short_range_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_CHARACTERISATION: + status = VL53L1_preset_mode_histogram_characterisation( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_PLANAR: + status = VL53L1_preset_mode_histogram_xtalk_planar( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM1: + status = VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_HISTOGRAM_XTALK_MM2: + status = VL53L1_preset_mode_histogram_xtalk_mm2( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_OLT: + status = VL53L1_preset_mode_olt( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_SINGLESHOT_RANGING: + status = VL53L1_preset_mode_singleshot_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE: + status = VL53L1_preset_mode_low_power_auto_short_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE: + status = VL53L1_preset_mode_low_power_auto_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + case VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE: + status = VL53L1_preset_mode_low_power_auto_long_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg, + plpadata); + break; + + + case VL53L1_DEVICEPRESETMODE_SPECIAL_HISTOGRAM_SHORT_RANGE: + status = VL53L1_preset_mode_special_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + + + + if (status == VL53L1_ERROR_NONE) { + + pstatic->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + pdev->dss_config__target_total_rate_mcps = + dss_config__target_total_rate_mcps; + + } + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_timeouts_us( + Dev, + phasecal_config_timeout_us, + mm_config_timeout_us, + range_config_timeout_us); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_set_inter_measurement_period_ms( + Dev, + inter_measurement_period_ms); + + + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_zone_preset( + VL53L1_DEV Dev, + VL53L1_DeviceZonePreset zone_preset) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + + LOG_FUNCTION_START(""); + + + + pdev->zone_preset = zone_preset; + + + + + switch (zone_preset) { + + case VL53L1_DEVICEZONEPRESET_XTALK_PLANAR: + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_16X16: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 8, 1, 1, + + 15, 15, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_1X2_SIZE_16X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 4, 8, 2, + + 15, 7, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X1_SIZE_8X16: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 8, 1, 1, + + 7, 15, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_2X2_SIZE_8X8: + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_3X3_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 2, 5, 3, + + 2, 5, 3, + + 4, 4, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_4X4_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 4, 4, + + 2, 4, 4, + + 3, 3, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_5X5_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 3, 5, + + 2, 3, 5, + + 3, 3, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_11X11_SIZE_5X5: + status = + VL53L1_init_zone_config_structure( + 3, 1, 11, + + 3, 1, 11, + + 4, 4, + + pzone_cfg); + break; + + case VL53L1_DEVICEZONEPRESET_13X13_SIZE_4X4: + status = + VL53L1_init_zone_config_structure( + 2, 1, 13, + + 2, 1, 13, + + 3, 3, + + pzone_cfg); + + break; + + case VL53L1_DEVICEZONEPRESET_1X1_SIZE_4X4_POS_8X8: + status = + VL53L1_init_zone_config_structure( + 8, 1, 1, + + 8, 1, 1, + + 3, 3, + + pzone_cfg); + break; + + } + + + + + + + + + + + if (pzone_cfg->active_zones == 0) + pdev->gen_cfg.global_config__stream_divider = 0; + else if (pzone_cfg->active_zones < VL53L1_MAX_USER_ZONES) + pdev->gen_cfg.global_config__stream_divider = + pzone_cfg->active_zones + 1; + else + pdev->gen_cfg.global_config__stream_divider = + VL53L1_MAX_USER_ZONES + 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_enable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint32_t tempu32; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + + tempu32 = VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->lite_mode_crosstalk_margin_kcps); + if (tempu32 > 0xFFFF) + tempu32 = 0xFFFF; + + pN->algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)tempu32; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps + = pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps + = pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + pC->global_crosstalk_compensation_enable = 0x01; + + pHP->algo__crosstalk_compensation_enable = + pC->global_crosstalk_compensation_enable; + + + + + + if (status == VL53L1_ERROR_NONE) { + pC->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->algo__crosstalk_compensation_x_plane_gradient_kcps, + pC->algo__crosstalk_compensation_y_plane_gradient_kcps, + pC->crosstalk_range_ignore_threshold_mult); +} + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + + LOG_FUNCTION_END(status); + + return status; + +} + +void VL53L1_get_xtalk_compensation_enable( + VL53L1_DEV Dev, + uint8_t *pcrosstalk_compensation_enable) +{ + + + + + + + + + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + *pcrosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + +} + + +VL53L1_Error VL53L1_get_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t *pxtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pxtalk_margin = pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_xtalk_margin_kcps( + VL53L1_DEV Dev, + int16_t xtalk_margin) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = xtalk_margin; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_restore_xtalk_nvm_default( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + + LOG_FUNCTION_START(""); + + pC->algo__crosstalk_compensation_plane_offset_kcps = + pC->nvm_default__crosstalk_compensation_plane_offset_kcps; + pC->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + pC->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_disable_xtalk_compensation( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + LOG_FUNCTION_START(""); + + + + pN->algo__crosstalk_compensation_plane_offset_kcps = + 0x00; + + pN->algo__crosstalk_compensation_x_plane_gradient_kcps = + 0x00; + + pN->algo__crosstalk_compensation_y_plane_gradient_kcps = + 0x00; + + + + + pdev->xtalk_cfg.global_crosstalk_compensation_enable = 0x00; + + pHP->algo__crosstalk_compensation_enable = + pdev->xtalk_cfg.global_crosstalk_compensation_enable; + + + + + if (status == VL53L1_ERROR_NONE) { + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps = + 0x0000; + } + + + + + if (status == VL53L1_ERROR_NONE) { + + status = + VL53L1_set_customer_nvm_managed( + Dev, + &(pdev->customer)); + } + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t *pphase_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + + LOG_FUNCTION_START(""); + + *pphase_consistency = + pHP->algo__consistency_check__phase_tolerance; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_phase_consistency( + VL53L1_DEV Dev, + uint8_t phase_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__phase_tolerance = + phase_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t *pevent_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pevent_consistency = + pdev->histpostprocess.algo__consistency_check__event_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_event_consistency( + VL53L1_DEV Dev, + uint8_t event_consistency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.algo__consistency_check__event_sigma = + event_consistency; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t *pamb_thresh_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pamb_thresh_sigma = + pdev->histpostprocess.ambient_thresh_sigma1; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_histogram_ambient_threshold_sigma( + VL53L1_DEV Dev, + uint8_t amb_thresh_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.ambient_thresh_sigma1 = + amb_thresh_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t *plite_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_sigma = + pdev->tim_cfg.range_config__sigma_thresh; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_sigma_threshold( + VL53L1_DEV Dev, + uint16_t lite_sigma) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__sigma_thresh = lite_sigma; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t *plite_mincountrate) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *plite_mincountrate = + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_lite_min_count_rate( + VL53L1_DEV Dev, + uint16_t lite_mincountrate) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->tim_cfg.range_config__min_count_rate_rtn_limit_mcps = + lite_mincountrate; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t *pmax_valid_range_mm, + int16_t *pmin_valid_range_mm, + uint16_t *pmax_valid_rate_kcps, + uint16_t *pmax_sigma_mm) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pmax_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + *pmin_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + *pmax_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + *pmax_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_xtalk_detect_config( + VL53L1_DEV Dev, + int16_t max_valid_range_mm, + int16_t min_valid_range_mm, + uint16_t max_valid_rate_kcps, + uint16_t max_sigma_mm) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + max_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + min_valid_range_mm; + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + max_valid_rate_kcps; + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + max_sigma_mm; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder *phist_target_order) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *phist_target_order = + pdev->histpostprocess.hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_target_order_mode( + VL53L1_DEV Dev, + VL53L1_HistTargetOrder hist_target_order) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->histpostprocess.hist_target_order = hist_target_order; + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_get_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdmax_reflectances->target_reflectance_for_dmax[i] = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_set_dmax_reflectance_values( + VL53L1_DEV Dev, + VL53L1_dmax_reflectance_array_t *pdmax_reflectances) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + pdev->dmax_cfg.target_reflectance_for_dmax_calc[i] = + pdmax_reflectances->target_reflectance_for_dmax[i]; + } + + LOG_FUNCTION_END(status); + + return status; + +} + +VL53L1_Error VL53L1_get_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t *pvhv_loopbound) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound / 4; + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_loopbound( + VL53L1_DEV Dev, + uint8_t vhv_loopbound) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (vhv_loopbound * 4); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_get_vhv_config( + VL53L1_DEV Dev, + uint8_t *pvhv_init_en, + uint8_t *pvhv_init_value) +{ + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pvhv_init_en = (pdev->stat_nvm.vhv_config__init & 0x80) >> 7; + *pvhv_init_value = + (pdev->stat_nvm.vhv_config__init & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_set_vhv_config( + VL53L1_DEV Dev, + uint8_t vhv_init_en, + uint8_t vhv_init_value) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->stat_nvm.vhv_config__init = + ((vhv_init_en & 0x01) << 7) + + (vhv_init_value & 0x7F); + + LOG_FUNCTION_END(status); + + return status; + +} + + + +VL53L1_Error VL53L1_init_and_start_range( + VL53L1_DEV Dev, + uint8_t measurement_mode, + VL53L1_DeviceConfigLevel device_config_level) +{ + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_static_nvm_managed_t *pstatic_nvm = &(pdev->stat_nvm); + VL53L1_customer_nvm_managed_t *pcustomer_nvm = &(pdev->customer); + VL53L1_static_config_t *pstatic = &(pdev->stat_cfg); + VL53L1_general_config_t *pgeneral = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptiming = &(pdev->tim_cfg); + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + VL53L1_system_control_t *psystem = &(pdev->sys_ctrl); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + + uint8_t *pbuffer = &buffer[0]; + uint16_t i = 0; + uint16_t i2c_index = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + pdev->measurement_mode = measurement_mode; + + + + + psystem->system__mode_start = + (psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + measurement_mode; + + + + + + + status = + VL53L1_set_user_zone( + Dev, + &(pdev->zone_cfg.user_zones[pdev->ll_state.cfg_zone_id])); + + + + + + if (pdev->zone_cfg.active_zones > 0) { + status = + VL53L1_set_zone_dss_config( + Dev, + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]) + ); + } + + + + + + + if (((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == 0x00) && + (pdev->xtalk_cfg.global_crosstalk_compensation_enable + == 0x01)) { + pdev->stat_cfg.algo__range_ignore_threshold_mcps = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_rate_mcps; + } + + + + + + + + + if (pdev->low_power_auto_data.low_power_auto_range_count == 0xFF) + pdev->low_power_auto_data.low_power_auto_range_count = 0x0; + + + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 0)) { + + + pdev->low_power_auto_data.saved_interrupt_config = + pdev->gen_cfg.system__interrupt_config_gpio; + + + pdev->gen_cfg.system__interrupt_config_gpio = 1 << 5; + + + if ((pdev->dyn_cfg.system__sequence_config & ( + VL53L1_SEQUENCE_MM1_EN | VL53L1_SEQUENCE_MM2_EN)) == + 0x0) { + pN->algo__part_to_part_range_offset_mm = + (pN->mm_config__outer_offset_mm << 2); + } else { + pN->algo__part_to_part_range_offset_mm = 0x0; + } + + + + if (device_config_level < + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS) { + device_config_level = + VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS; + } + } + + if ((pdev->low_power_auto_data.is_low_power_auto_mode == 1) && + (pdev->low_power_auto_data.low_power_auto_range_count == 1)) { + + + pdev->gen_cfg.system__interrupt_config_gpio = + pdev->low_power_auto_data.saved_interrupt_config; + + + + device_config_level = VL53L1_DEVICECONFIGLEVEL_FULL; + } + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_save_cfg_data(Dev); + + + + + + + switch (device_config_level) { + case VL53L1_DEVICECONFIGLEVEL_FULL: + i2c_index = VL53L1_STATIC_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS: + i2c_index = VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS: + i2c_index = VL53L1_STATIC_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS: + i2c_index = VL53L1_GENERAL_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS: + i2c_index = VL53L1_TIMING_CONFIG_I2C_INDEX; + break; + case VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS: + i2c_index = VL53L1_DYNAMIC_CONFIG_I2C_INDEX; + break; + default: + i2c_index = VL53L1_SYSTEM_CONTROL_I2C_INDEX; + break; + } + + + + + i2c_buffer_size_bytes = + (VL53L1_SYSTEM_CONTROL_I2C_INDEX + + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) - + i2c_index; + + + + + pbuffer = &buffer[0]; + for (i = 0; i < i2c_buffer_size_bytes; i++) + *pbuffer++ = 0; + + + + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_nvm_managed( + pstatic_nvm, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CUSTOMER_NVM_MANAGED_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_customer_nvm_managed( + pcustomer_nvm, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_STATIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_STATIC_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_static_config( + pstatic, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_GENERAL_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_general_config( + pgeneral, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_TIMING_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_TIMING_CONFIG_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_timing_config( + ptiming, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (device_config_level >= VL53L1_DEVICECONFIGLEVEL_DYNAMIC_ONWARDS && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DYNAMIC_CONFIG_I2C_INDEX - i2c_index; + + + + if ((psystem->system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) { + pdynamic->system__grouped_parameter_hold_0 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold_1 = + pstate->cfg_gph_id | 0x01; + pdynamic->system__grouped_parameter_hold = + pstate->cfg_gph_id; + } + status = + VL53L1_i2c_encode_dynamic_config( + pdynamic, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_SYSTEM_CONTROL_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_encode_system_control( + psystem, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes]); + } + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_WriteMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_rd_state(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_update_ll_driver_cfg_state(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_stop_range( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + + + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK) | + VL53L1_DEVICEMEASUREMENTMODE_ABORT; + + status = VL53L1_set_system_control( + Dev, + &pdev->sys_ctrl); + + + + pdev->sys_ctrl.system__mode_start = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_STOP_MASK); + + + + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + + + + V53L1_init_zone_results_structure( + pdev->zone_cfg.active_zones+1, + &(pres->zone_results)); + + + + V53L1_init_zone_dss_configs(Dev); + + + + if (pdev->low_power_auto_data.is_low_power_auto_mode == 1) + VL53L1_low_power_auto_data_stop_range(Dev); + + return status; +} + + +VL53L1_Error VL53L1_get_measurement_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + + VL53L1_system_results_t *psystem_results = &(pdev->sys_results); + VL53L1_core_results_t *pcore_results = &(pdev->core_results); + VL53L1_debug_results_t *pdebug_results = &(pdev->dbg_results); + + uint16_t i2c_index = VL53L1_SYSTEM_RESULTS_I2C_INDEX; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t i2c_buffer_size_bytes = 0; + + LOG_FUNCTION_START(""); + + + + + switch (device_results_level) { + case VL53L1_DEVICERESULTSLEVEL_FULL: + i2c_buffer_size_bytes = + (VL53L1_DEBUG_RESULTS_I2C_INDEX + + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + case VL53L1_DEVICERESULTSLEVEL_UPTO_CORE: + i2c_buffer_size_bytes = + (VL53L1_CORE_RESULTS_I2C_INDEX + + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) - + i2c_index; + break; + default: + i2c_buffer_size_bytes = + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES; + break; + } + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_ReadMulti( + Dev, + i2c_index, + buffer, + (uint32_t)i2c_buffer_size_bytes); + + + + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_FULL && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_DEBUG_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pdebug_results); + } + + if (device_results_level >= VL53L1_DEVICERESULTSLEVEL_UPTO_CORE && + status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = + VL53L1_CORE_RESULTS_I2C_INDEX - i2c_index; + + status = + VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + pcore_results); + } + + if (status == VL53L1_ERROR_NONE) { + + i2c_buffer_offset_bytes = 0; + status = + VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + &buffer[i2c_buffer_offset_bytes], + psystem_results); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_device_results( + VL53L1_DEV Dev, + VL53L1_DeviceResultsLevel device_results_level, + VL53L1_range_results_t *prange_results) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_range_results_t *presults = + &(pres->range_results); + VL53L1_zone_objects_t *pobjects = + &(pres->zone_results.VL53L1_p_002[0]); + VL53L1_ll_driver_state_t *pstate = + &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = + &(pdev->zone_cfg); + VL53L1_zone_hist_info_t *phist_info = + &(pres->zone_hists.VL53L1_p_002[0]); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalk_config_t *pC = &(pdev->xtalk_cfg); + VL53L1_low_power_auto_data_t *pL = &(pdev->low_power_auto_data); + VL53L1_histogram_bin_data_t *pHD = &(pdev->hist_data); + VL53L1_customer_nvm_managed_t *pN = &(pdev->customer); + VL53L1_zone_histograms_t *pZH = &(pres->zone_hists); + + uint8_t i; + uint8_t tmp8; + uint8_t zid; + + LOG_FUNCTION_START(""); + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) + == VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) { + + + + + + + status = VL53L1_get_histogram_bin_data( + Dev, + &(pdev->hist_data)); + + + + + + + + if (status == VL53L1_ERROR_NONE && + pHD->number_of_ambient_bins == 0) { + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_copy_and_scale_ambient_info( + &(pZH->VL53L1_p_002[zid]), + &(pdev->hist_data)); + } + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + pHP->gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + pHP->algo__crosstalk_compensation_plane_offset_kcps = + VL53L1_calc_crosstalk_plane_offset_with_margin( + pC->algo__crosstalk_compensation_plane_offset_kcps, + pC->histogram_mode_crosstalk_margin_kcps); + + pHP->algo__crosstalk_compensation_x_plane_gradient_kcps = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + pHP->algo__crosstalk_compensation_y_plane_gradient_kcps = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdev->dmax_cfg.ambient_thresh_sigma = + pHP->ambient_thresh_sigma1; + pdev->dmax_cfg.min_ambient_thresh_events = + pHP->min_ambient_thresh_events; + pdev->dmax_cfg.signal_total_events_limit = + pHP->signal_total_events_limit; + pdev->dmax_cfg.dss_config__target_total_rate_mcps = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + pdev->dmax_cfg.dss_config__aperture_attenuation = + pdev->gen_cfg.dss_config__aperture_attenuation; + + pHP->algo__crosstalk_detect_max_valid_range_mm = + pC->algo__crosstalk_detect_max_valid_range_mm; + pHP->algo__crosstalk_detect_min_valid_range_mm = + pC->algo__crosstalk_detect_min_valid_range_mm; + pHP->algo__crosstalk_detect_max_valid_rate_kcps = + pC->algo__crosstalk_detect_max_valid_rate_kcps; + pHP->algo__crosstalk_detect_max_sigma_mm = + pC->algo__crosstalk_detect_max_sigma_mm; + + + + + VL53L1_copy_rtn_good_spads_to_buffer( + &(pdev->nvm_copy_data), + &(pdev->rtn_good_spads[0])); + + + + + switch (pdev->offset_correction_mode) { + + case VL53L1_OFFSETCORRECTIONMODE__MM1_MM2_OFFSETS: + tmp8 = pdev->gen_cfg.dss_config__aperture_attenuation; + + VL53L1_hist_combine_mm1_mm2_offsets( + pN->mm_config__inner_offset_mm, + pN->mm_config__outer_offset_mm, + pdev->nvm_copy_data.roi_config__mode_roi_centre_spad, + pdev->nvm_copy_data.roi_config__mode_roi_xy_size, + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->add_off_cal_data), + &(pdev->rtn_good_spads[0]), + (uint16_t)tmp8, + &(pHP->range_offset_mm)); + break; + case VL53L1_OFFSETCORRECTIONMODE__PER_ZONE_OFFSETS: + zid = pdev->ll_state.rd_zone_id; + pHP->range_offset_mm = (int16_t)( + pres->zone_cal.VL53L1_p_002[zid].range_mm_offset); + break; + default: + pHP->range_offset_mm = 0; + break; + + } + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + VL53L1_calc_max_effective_spads( + pHD->roi_config__user_roi_centre_spad, + pHD->roi_config__user_roi_requested_global_xy_size, + &(pdev->rtn_good_spads[0]), + (uint16_t)pdev->gen_cfg.dss_config__aperture_attenuation, + &(pdev->dmax_cfg.max_effective_spads)); + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->dmax_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_ipp_hist_process_data( + Dev, + pdmax_cal, + &(pdev->dmax_cfg), + &(pdev->histpostprocess), + &(pdev->hist_data), + &(pdev->xtalk_shapes), + presults); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + status = VL53L1_hist_wrap_dmax( + &(pdev->histpostprocess), + &(pdev->hist_data), + &(presults->wrap_dmax_mm)); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_phase_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + presults); + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + zid = pdev->ll_state.rd_zone_id; + status = VL53L1_hist_xmonitor_consistency_check( + Dev, + &(pZH->VL53L1_p_002[zid]), + &(pres->zone_results.VL53L1_p_002[zid]), + &(presults->xmonitor)); + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + + zid = pdev->ll_state.rd_zone_id; + pZH->max_zones = VL53L1_MAX_USER_ZONES; + pZH->active_zones = + pdev->zone_cfg.active_zones+1; + pHD->zone_id = zid; + + if (zid < + pres->zone_results.max_zones) { + + phist_info = + &(pZH->VL53L1_p_002[zid]); + + phist_info->rd_device_state = + pHD->rd_device_state; + + phist_info->number_of_ambient_bins = + pHD->number_of_ambient_bins; + + phist_info->result__dss_actual_effective_spads = + pHD->result__dss_actual_effective_spads; + + phist_info->VL53L1_p_009 = + pHD->VL53L1_p_009; + + phist_info->total_periods_elapsed = + pHD->total_periods_elapsed; + + phist_info->ambient_events_sum = + pHD->ambient_events_sum; + } + + + + + + + + if (status != VL53L1_ERROR_NONE) + goto UPDATE_DYNAMIC_CONFIG; + + VL53L1_hist_copy_results_to_sys_and_core( + &(pdev->hist_data), + presults, + &(pdev->sys_results), + &(pdev->core_results)); + + + + + + +UPDATE_DYNAMIC_CONFIG: + if (pzone_cfg->active_zones > 0) { + if (pstate->rd_device_state != + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_dynamic_zone_update( + Dev, presults); + } + } + + + + + + for (i = 0; i < VL53L1_MAX_USER_ZONES; i++) { + pzone_cfg->bin_config[i] = + ((pdev->ll_state.cfg_internal_stream_count) + & 0x01) ? + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB : + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_multizone_hist_bins_update(Dev); + + } + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_dynamic_xtalk_correction_corrector(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_histogram_bin_data( + &(pdev->hist_data), + "get_device_results():pdev->lldata.hist_data.", + VL53L1_TRACE_MODULE_HISTOGRAM_DATA); +#endif + + } else { + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_get_measurement_results( + Dev, + device_results_level); + + if (status == VL53L1_ERROR_NONE) + VL53L1_copy_sys_and_core_results_to_range_results( + (int32_t)pdev->gain_cal.standard_ranging_gain_factor, + &(pdev->sys_results), + &(pdev->core_results), + presults); + + + + + + if (pL->is_low_power_auto_mode == 1) { + + + + if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 0)) { + + status = + VL53L1_low_power_auto_setup_manual_calibration( + Dev); + pL->low_power_auto_range_count = 1; + } else if ((status == VL53L1_ERROR_NONE) && + (pL->low_power_auto_range_count == 1)) { + pL->low_power_auto_range_count = 2; + } + + + + if ((pL->low_power_auto_range_count != 0xFF) && + (status == VL53L1_ERROR_NONE)) { + status = VL53L1_low_power_auto_update_DSS( + Dev); + } + } + + + } + + + + presults->cfg_device_state = pdev->ll_state.cfg_device_state; + presults->rd_device_state = pdev->ll_state.rd_device_state; + presults->zone_id = pdev->ll_state.rd_zone_id; + + if (status == VL53L1_ERROR_NONE) { + + + + pres->zone_results.max_zones = VL53L1_MAX_USER_ZONES; + pres->zone_results.active_zones = pdev->zone_cfg.active_zones+1; + zid = pdev->ll_state.rd_zone_id; + + if (zid < pres->zone_results.max_zones) { + + pobjects = + &(pres->zone_results.VL53L1_p_002[zid]); + + pobjects->cfg_device_state = + presults->cfg_device_state; + pobjects->rd_device_state = presults->rd_device_state; + pobjects->zone_id = presults->zone_id; + pobjects->stream_count = presults->stream_count; + + + + + pobjects->xmonitor.VL53L1_p_020 = + presults->xmonitor.VL53L1_p_020; + pobjects->xmonitor.VL53L1_p_021 = + presults->xmonitor.VL53L1_p_021; + pobjects->xmonitor.VL53L1_p_014 = + presults->xmonitor.VL53L1_p_014; + pobjects->xmonitor.range_status = + presults->xmonitor.range_status; + + pobjects->max_objects = presults->max_results; + pobjects->active_objects = presults->active_results; + + for (i = 0; i < presults->active_results; i++) { + pobjects->VL53L1_p_002[i].VL53L1_p_020 = + presults->VL53L1_p_002[i].VL53L1_p_020; + pobjects->VL53L1_p_002[i].VL53L1_p_021 = + presults->VL53L1_p_002[i].VL53L1_p_021; + pobjects->VL53L1_p_002[i].VL53L1_p_014 = + presults->VL53L1_p_002[i].VL53L1_p_014; + pobjects->VL53L1_p_002[i].range_status = + presults->VL53L1_p_002[i].range_status; + } + + + + } + } + + + + + memcpy( + prange_results, + presults, + sizeof(VL53L1_range_results_t)); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_check_ll_driver_rd_state(Dev); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_range_results( + presults, + "get_device_results():pdev->llresults.range_results.", + VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt_and_enable_next_range( + VL53L1_DEV Dev, + uint8_t measurement_mode) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_init_and_start_range( + Dev, + measurement_mode, + VL53L1_DEVICECONFIGLEVEL_GENERAL_ONWARDS); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_bin_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + + VL53L1_static_nvm_managed_t *pstat_nvm = &(pdev->stat_nvm); + VL53L1_static_config_t *pstat_cfg = &(pdev->stat_cfg); + VL53L1_general_config_t *pgen_cfg = &(pdev->gen_cfg); + VL53L1_timing_config_t *ptim_cfg = &(pdev->tim_cfg); + VL53L1_range_results_t *presults = &(pres->range_results); + + uint8_t buffer[VL53L1_MAX_I2C_XFER_SIZE]; + uint8_t *pbuffer = &buffer[0]; + uint8_t bin_23_0 = 0x00; + uint16_t bin = 0; + uint16_t i2c_buffer_offset_bytes = 0; + uint16_t encoded_timeout = 0; + + uint32_t pll_period_us = 0; + uint32_t periods_elapsed_tmp = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX, + pbuffer, + VL53L1_HISTOGRAM_BIN_DATA_I2C_SIZE_BYTES); + + + + + + + pdata->result__interrupt_status = *(pbuffer + 0); + pdata->result__range_status = *(pbuffer + 1); + pdata->result__report_status = *(pbuffer + 2); + pdata->result__stream_count = *(pbuffer + 3); + pdata->result__dss_actual_effective_spads = + VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + + + + + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + + pdata->phasecal_result__reference_phase = + VL53L1_i2c_decode_uint16_t(2, pbuffer); + + i2c_buffer_offset_bytes = + VL53L1_PHASECAL_RESULT__VCSEL_START - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pdata->phasecal_result__vcsel_start = buffer[i2c_buffer_offset_bytes]; + + + + + pdev->dbg_results.phasecal_result__reference_phase = + pdata->phasecal_result__reference_phase; + pdev->dbg_results.phasecal_result__vcsel_start = + pdata->phasecal_result__vcsel_start; + + + + + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_MSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 = buffer[i2c_buffer_offset_bytes] << 2; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0_LSB - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + bin_23_0 += buffer[i2c_buffer_offset_bytes]; + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_23_0 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + buffer[i2c_buffer_offset_bytes] = bin_23_0; + + + + + + + + i2c_buffer_offset_bytes = + VL53L1_RESULT__HISTOGRAM_BIN_0_2 - + VL53L1_HISTOGRAM_BIN_DATA_I2C_INDEX; + + pbuffer = &buffer[i2c_buffer_offset_bytes]; + for (bin = 0; bin < VL53L1_HISTOGRAM_BUFFER_SIZE; bin++) { + pdata->bin_data[bin] = + (int32_t)VL53L1_i2c_decode_uint32_t(3, pbuffer); + pbuffer += 3; + } + + + + pdata->zone_id = pdev->ll_state.rd_zone_id; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = VL53L1_HISTOGRAM_BUFFER_SIZE; + + pdata->cal_config__vcsel_start = pgen_cfg->cal_config__vcsel_start; + + + + + pdata->vcsel_width = + ((uint16_t)pgen_cfg->global_config__vcsel_width) << 4; + pdata->vcsel_width += + (uint16_t)pstat_cfg->ana_config__vcsel_pulse_width_offset; + + + + pdata->VL53L1_p_019 = + pstat_nvm->osc_measured__fast_osc__frequency; + + + + + VL53L1_hist_get_bin_sequence_config(Dev, pdata); + + + + + + + if (pdev->ll_state.rd_timing_status == 0) { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_a_hi << 8) + + ptim_cfg->range_config__timeout_macrop_a_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_a; + } else { + + encoded_timeout = + (ptim_cfg->range_config__timeout_macrop_b_hi << 8) + + ptim_cfg->range_config__timeout_macrop_b_lo; + pdata->VL53L1_p_009 = ptim_cfg->range_config__vcsel_period_b; + } + + + + + pdata->number_of_ambient_bins = 0; + + for (i = 0; i < 6; i++) { + if ((pdata->bin_seq[i] & 0x07) == 0x07) + pdata->number_of_ambient_bins = + pdata->number_of_ambient_bins + 0x04; + } + + pdata->total_periods_elapsed = + VL53L1_decode_timeout(encoded_timeout); + + + + + + + + pll_period_us = + VL53L1_calc_pll_period_us(pdata->VL53L1_p_019); + + + + + periods_elapsed_tmp = pdata->total_periods_elapsed + 1; + + + + + + + pdata->peak_duration_us = + VL53L1_duration_maths( + pll_period_us, + (uint32_t)pdata->vcsel_width, + VL53L1_RANGING_WINDOW_VCSEL_PERIODS, + periods_elapsed_tmp); + + pdata->woi_duration_us = 0; + + + + + VL53L1_hist_calc_zero_distance_phase(pdata); + + + + + + + VL53L1_hist_estimate_ambient_from_ambient_bins(pdata); + + + + + pdata->cfg_device_state = pdev->ll_state.cfg_device_state; + pdata->rd_device_state = pdev->ll_state.rd_device_state; + + + + + pzone_dyn_cfg = &(pres->zone_dyn_cfgs.VL53L1_p_002[pdata->zone_id]); + + pdata->roi_config__user_roi_centre_spad = + pzone_dyn_cfg->roi_config__user_roi_centre_spad; + pdata->roi_config__user_roi_requested_global_xy_size = + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size; + + + + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + + switch (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (pdata->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + status = VL53L1_ERROR_RANGE_ERROR; + + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_sys_and_core_results_to_range_results( + int32_t gain_factor, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore, + VL53L1_range_results_t *presults) +{ + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + int32_t range_mm = 0; + uint32_t tmpu32 = 0; + uint16_t rpscr_crosstalk_corrected_mcps_sd0; + uint16_t rmmo_effective_spads_sd0; + uint16_t rmmi_effective_spads_sd0; + + LOG_FUNCTION_START(""); + + + + + presults->zone_id = 0; + presults->stream_count = psys->result__stream_count; + presults->wrap_dmax_mm = 0; + presults->max_results = VL53L1_MAX_RANGE_RESULTS; + presults->active_results = 1; + rpscr_crosstalk_corrected_mcps_sd0 = + psys->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0; + rmmo_effective_spads_sd0 = + psys->result__mm_outer_actual_effective_spads_sd0; + rmmi_effective_spads_sd0 = + psys->result__mm_inner_actual_effective_spads_sd0; + + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) + presults->VL53L1_p_007[i] = 0; + + pdata = &(presults->VL53L1_p_002[0]); + + for (i = 0; i < 2; i++) { + + pdata->range_id = i; + pdata->time_stamp = 0; + + if ((psys->result__stream_count == 0) && + ((psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) == + VL53L1_DEVICEERROR_RANGECOMPLETE)) { + pdata->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK; + } else { + pdata->range_status = + psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + } + + pdata->VL53L1_p_015 = 0; + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_025 = 0; + pdata->VL53L1_p_026 = 0; + pdata->VL53L1_p_016 = 0; + pdata->VL53L1_p_027 = 0; + + switch (i) { + + case 0: + if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM1) + pdata->VL53L1_p_006 = + rmmi_effective_spads_sd0; + else if (psys->result__report_status == + VL53L1_DEVICEREPORTSTATUS_MM2) + pdata->VL53L1_p_006 = + rmmo_effective_spads_sd0; + else + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd0; + + pdata->peak_signal_count_rate_mcps = + rpscr_crosstalk_corrected_mcps_sd0; + pdata->avg_signal_count_rate_mcps = + psys->result__avg_signal_count_rate_mcps_sd0; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd0; + + + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd0 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd0; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd0); + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd0; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd0; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd0; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd0; + + break; + case 1: + + pdata->VL53L1_p_006 = + psys->result__dss_actual_effective_spads_sd1; + pdata->peak_signal_count_rate_mcps = + psys->result__peak_signal_count_rate_mcps_sd1; + pdata->avg_signal_count_rate_mcps = + 0xFFFF; + pdata->ambient_count_rate_mcps = + psys->result__ambient_count_rate_mcps_sd1; + + + + + + + tmpu32 = ((uint32_t)psys->result__sigma_sd1 << 5); + if (tmpu32 > 0xFFFF) + tmpu32 = 0xFFFF; + + pdata->VL53L1_p_005 = (uint16_t)tmpu32; + + + + + pdata->VL53L1_p_014 = + psys->result__phase_sd1; + + range_mm = (int32_t)( + psys->result__final_crosstalk_corrected_range_mm_sd1); + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + pdata->median_range_mm = (int16_t)range_mm; + + pdata->VL53L1_p_021 = + pcore->result_core__ranging_total_events_sd1; + pdata->VL53L1_p_013 = + pcore->result_core__signal_total_events_sd1; + pdata->total_periods_elapsed = + pcore->result_core__total_periods_elapsed_sd1; + pdata->VL53L1_p_020 = + pcore->result_core__ambient_window_events_sd1; + + break; + } + + + + + + pdata->VL53L1_p_028 = pdata->VL53L1_p_014; + pdata->VL53L1_p_029 = pdata->VL53L1_p_014; + pdata->min_range_mm = pdata->median_range_mm; + pdata->max_range_mm = pdata->median_range_mm; + + pdata++; + } + + + + + + + presults->device_status = VL53L1_DEVICEERROR_NOUPDATE; + + + + + + + + + switch (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK) { + + case VL53L1_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + case VL53L1_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + case VL53L1_DEVICEERROR_NOVHVVALUEFOUND: + case VL53L1_DEVICEERROR_USERROICLIP: + case VL53L1_DEVICEERROR_MULTCLIPFAIL: + + presults->device_status = (psys->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK); + + presults->VL53L1_p_002[0].range_status = + VL53L1_DEVICEERROR_NOUPDATE; + break; + + } + + LOG_FUNCTION_END(0); +} + + +VL53L1_Error VL53L1_set_zone_dss_config( + VL53L1_DEV Dev, + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + LOG_FUNCTION_START(""); + + if (pstate->cfg_device_state == + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL) { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_EFFSPADS; + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pzone_dyn_cfg->dss_requested_effective_spad_count; + } else { + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_calc_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + int16_t *pambient_dmax_mm) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_dmax_calibration_data_t dmax_cal; + VL53L1_dmax_calibration_data_t *pdmax_cal = &dmax_cal; + + LOG_FUNCTION_START(""); + + + + + + + status = + VL53L1_get_dmax_calibration_data( + Dev, + pdev->debug_mode, + pdev->ll_state.rd_zone_id, + pdmax_cal); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ipp_hist_ambient_dmax( + Dev, + target_reflectance, + &(pdev->fmt_dmax_cal), + &(pdev->dmax_cfg), + &(pdev->hist_data), + pambient_dmax_mm); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_Interrupt_Mode intr_mode_distance, + VL53L1_GPIO_Interrupt_Mode intr_mode_rate, + uint8_t intr_new_measure_ready, + uint8_t intr_no_target, + uint8_t intr_combined_mode, + uint16_t thresh_distance_high, + uint16_t thresh_distance_low, + uint16_t thresh_rate_high, + uint16_t thresh_rate_low + ) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + + pintconf->intr_mode_distance = intr_mode_distance; + pintconf->intr_mode_rate = intr_mode_rate; + pintconf->intr_new_measure_ready = intr_new_measure_ready; + pintconf->intr_no_target = intr_no_target; + pintconf->intr_combined_mode = intr_combined_mode; + pintconf->threshold_distance_high = thresh_distance_high; + pintconf->threshold_distance_low = thresh_distance_low; + pintconf->threshold_rate_high = thresh_rate_high; + pintconf->threshold_rate_low = thresh_rate_low; + + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_interrupt_config_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t intconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_GPIO_interrupt_config_t *pintconf = + &(pdev->gpio_interrupt_config); + + LOG_FUNCTION_START(""); + + + + memcpy(pintconf, &(intconf), sizeof(VL53L1_GPIO_interrupt_config_t)); + + + + pdev->gen_cfg.system__interrupt_config_gpio = + VL53L1_encode_GPIO_interrupt_config(pintconf); + + + + status = VL53L1_set_GPIO_thresholds_from_struct( + Dev, + pintconf); + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_get_GPIO_interrupt_config( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + + pdev->gpio_interrupt_config = VL53L1_decode_GPIO_interrupt_config( + pdev->gen_cfg.system__interrupt_config_gpio); + + + + + + pdev->gpio_interrupt_config.threshold_distance_high = + pdev->dyn_cfg.system__thresh_high; + pdev->gpio_interrupt_config.threshold_distance_low = + pdev->dyn_cfg.system__thresh_low; + + pdev->gpio_interrupt_config.threshold_rate_high = + pdev->gen_cfg.system__thresh_rate_high; + pdev->gpio_interrupt_config.threshold_rate_low = + pdev->gen_cfg.system__thresh_rate_low; + + if (pintconf == &(pdev->gpio_interrupt_config)) { + + + } else { + + + + memcpy(pintconf, &(pdev->gpio_interrupt_config), + sizeof(VL53L1_GPIO_interrupt_config_t)); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dmax_mode = dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_mode( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode *pdmax_mode) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *pdmax_mode = pdev->dmax_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dmax_calibration_data( + VL53L1_DEV Dev, + VL53L1_DeviceDmaxMode dmax_mode, + uint8_t zone_id, + VL53L1_dmax_calibration_data_t *pdmax_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + switch (dmax_mode) { + + case VL53L1_DEVICEDMAXMODE__PER_ZONE_CAL_DATA: + pdmax_cal->ref__actual_effective_spads = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].effective_spads; + pdmax_cal->ref__peak_signal_count_rate_mcps = + (uint16_t)pres->zone_cal.VL53L1_p_002[zone_id].peak_rate_mcps; + pdmax_cal->ref__distance_mm = + pres->zone_cal.cal_distance_mm; + pdmax_cal->ref_reflectance_pc = + pres->zone_cal.cal_reflectance_pc; + pdmax_cal->coverglass_transmission = 0x0100; + break; + + case VL53L1_DEVICEDMAXMODE__CUST_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + case VL53L1_DEVICEDMAXMODE__FMT_CAL_DATA: + memcpy( + pdmax_cal, + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + break; + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdev->dmax_cfg), + pdmax_cfg, + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_hist_dmax_config( + VL53L1_DEV Dev, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pdmax_cfg, + &(pdev->dmax_cfg), + sizeof(VL53L1_hist_gen3_dmax_config_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode offset_cal_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_calibration_mode = offset_cal_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_calibration_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCalibrationMode *poffset_cal_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cal_mode = pdev->offset_calibration_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode offset_cor_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->offset_correction_mode = offset_cor_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_correction_mode( + VL53L1_DEV Dev, + VL53L1_OffsetCorrectionMode *poffset_cor_mode) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + *poffset_cor_mode = pdev->offset_correction_mode; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_set_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + if (pzone_cal->struct_version != + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION) + status = VL53L1_ERROR_INVALID_PARAMS; + + + if (status == VL53L1_ERROR_NONE) + + + memcpy( + &(pres->zone_cal), + pzone_cal, + sizeof(VL53L1_zone_calibration_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_zone_calibration_data( + VL53L1_DEV Dev, + VL53L1_zone_calibration_results_t *pzone_cal) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pzone_cal, + &(pres->zone_cal), + sizeof(VL53L1_zone_calibration_results_t)); + + pzone_cal->struct_version = + VL53L1_LL_ZONE_CALIBRATION_DATA_STRUCT_VERSION; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_tuning_debug_data( + VL53L1_DEV Dev, + VL53L1_tuning_parameters_t *ptun_data) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + ptun_data->vl53l1_tuningparm_version = + pdev->tuning_parms.tp_tuning_parm_version; + + ptun_data->vl53l1_tuningparm_key_table_version = + pdev->tuning_parms.tp_tuning_parm_key_table_version; + + + ptun_data->vl53l1_tuningparm_lld_version = + pdev->tuning_parms.tp_tuning_parm_lld_version; + + ptun_data->vl53l1_tuningparm_hist_algo_select = + pHP->hist_algo_select; + + ptun_data->vl53l1_tuningparm_hist_target_order = + pHP->hist_target_order; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_0 = + pHP->filter_woi0; + + ptun_data->vl53l1_tuningparm_hist_filter_woi_1 = + pHP->filter_woi1; + + ptun_data->vl53l1_tuningparm_hist_amb_est_method = + pHP->hist_amb_est_method; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_0 = + pHP->ambient_thresh_sigma0; + + ptun_data->vl53l1_tuningparm_hist_amb_thresh_sigma_1 = + pHP->ambient_thresh_sigma1; + + ptun_data->vl53l1_tuningparm_hist_min_amb_thresh_events = + pHP->min_ambient_thresh_events; + + ptun_data->vl53l1_tuningparm_hist_amb_events_scaler = + pHP->ambient_thresh_events_scaler; + + ptun_data->vl53l1_tuningparm_hist_noise_threshold = + pHP->noise_threshold; + + ptun_data->vl53l1_tuningparm_hist_signal_total_events_limit = + pHP->signal_total_events_limit; + + ptun_data->vl53l1_tuningparm_hist_sigma_est_ref_mm = + pHP->sigma_estimator__sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_hist_sigma_thresh_mm = + pHP->sigma_thresh; + + ptun_data->vl53l1_tuningparm_hist_gain_factor = + pdev->gain_cal.histogram_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_consistency_hist_phase_tolerance = + pHP->algo__consistency_check__phase_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_min_max_tolerance_mm = + pHP->algo__consistency_check__min_max_tolerance; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma = + pHP->algo__consistency_check__event_sigma; + + ptun_data->vl53l1_tuningparm_consistency_hist_event_sigma_min_spad_limit + = pHP->algo__consistency_check__event_min_spad_count; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_long_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_med_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_histo_short_range = + pdev->tuning_parms.tp_init_phase_rtn_hist_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_long_range = + pdev->tuning_parms.tp_init_phase_ref_hist_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_med_range = + pdev->tuning_parms.tp_init_phase_ref_hist_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_histo_short_range = + pdev->tuning_parms.tp_init_phase_ref_hist_short; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_range_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_sigma_mm = + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_detect_min_max_tolerance = + pHP->algo__crosstalk_detect_min_max_tolerance; + + ptun_data->vl53l1_tuningparm_xtalk_detect_max_valid_rate_kcps = + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_detect_event_sigma = + pHP->algo__crosstalk_detect_event_sigma; + + ptun_data->vl53l1_tuningparm_hist_xtalk_margin_kcps = + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_consistency_lite_phase_tolerance = + pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + + ptun_data->vl53l1_tuningparm_phasecal_target = + pdev->tuning_parms.tp_phasecal_target; + + ptun_data->vl53l1_tuningparm_lite_cal_repeat_rate = + pdev->tuning_parms.tp_cal_repeat_rate; + + ptun_data->vl53l1_tuningparm_lite_ranging_gain_factor = + pdev->gain_cal.standard_ranging_gain_factor; + + ptun_data->vl53l1_tuningparm_lite_min_clip_mm = + pdev->tuning_parms.tp_lite_min_clip; + + ptun_data->vl53l1_tuningparm_lite_long_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_med_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_short_sigma_thresh_mm = + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + + ptun_data->vl53l1_tuningparm_lite_long_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_med_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_short_min_count_rate_rtn_mcps = + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_pulse_width = + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_est_amb_width_ns = + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + + ptun_data->vl53l1_tuningparm_lite_sigma_ref_mm = + pdev->tuning_parms.tp_lite_sigma_ref_mm; + + ptun_data->vl53l1_tuningparm_lite_rit_mult = + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + + ptun_data->vl53l1_tuningparm_lite_seed_config = + pdev->tuning_parms.tp_lite_seed_cfg; + + ptun_data->vl53l1_tuningparm_lite_quantifier = + pdev->tuning_parms.tp_lite_quantifier; + + ptun_data->vl53l1_tuningparm_lite_first_order_select = + pdev->tuning_parms.tp_lite_first_order_select; + + ptun_data->vl53l1_tuningparm_lite_xtalk_margin_kcps = + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_long_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_med_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_rtn_lite_short_range = + pdev->tuning_parms.tp_init_phase_rtn_lite_short; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_long_range = + pdev->tuning_parms.tp_init_phase_ref_lite_long; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_med_range = + pdev->tuning_parms.tp_init_phase_ref_lite_med; + + ptun_data->vl53l1_tuningparm_initial_phase_ref_lite_short_range = + pdev->tuning_parms.tp_init_phase_ref_lite_short; + + ptun_data->vl53l1_tuningparm_timed_seed_config = + pdev->tuning_parms.tp_timed_seed_cfg; + + ptun_data->vl53l1_tuningparm_dmax_cfg_signal_thresh_sigma = + pdev->dmax_cfg.signal_thresh_sigma; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_0 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_1 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_2 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_3 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + + ptun_data->vl53l1_tuningparm_dmax_cfg_reflectance_array_4 = + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + + ptun_data->vl53l1_tuningparm_vhv_loopbound = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + ptun_data->vl53l1_tuningparm_refspadchar_device_test_mode = + pdev->refspadchar.device_test_mode; + + ptun_data->vl53l1_tuningparm_refspadchar_vcsel_period = + pdev->refspadchar.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_refspadchar_phasecal_timeout_us = + pdev->refspadchar.timeout_us; + + ptun_data->vl53l1_tuningparm_refspadchar_target_count_rate_mcps = + pdev->refspadchar.target_count_rate_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_min_countrate_limit_mcps = + pdev->refspadchar.min_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_refspadchar_max_countrate_limit_mcps = + pdev->refspadchar.max_count_rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_num_of_samples = + pXC->num_of_samples; + + ptun_data->vl53l1_tuningparm_xtalk_extract_min_filter_thresh_mm = + pXC->algo__crosstalk_extract_min_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_filter_thresh_mm = + pXC->algo__crosstalk_extract_max_valid_range_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_rate_mcps = + pXC->dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_phasecal_timeout_us = + pXC->phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_max_valid_rate_kcps = + pXC->algo__crosstalk_extract_max_valid_rate_kcps; + + ptun_data->vl53l1_tuningparm_xtalk_extract_sigma_threshold_mm = + pXC->algo__crosstalk_extract_max_sigma_mm; + + ptun_data->vl53l1_tuningparm_xtalk_extract_dss_timeout_us = + pXC->mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_xtalk_extract_bin_timeout_us = + pXC->range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_dss_rate_mcps = + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_offset_cal_phasecal_timeout_us = + pdev->offsetcal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_mm_timeout_us = + pdev->offsetcal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_range_timeout_us = + pdev->offsetcal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_offset_cal_pre_samples = + pdev->offsetcal_cfg.pre_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm1_samples = + pdev->offsetcal_cfg.mm1_num_of_samples; + + ptun_data->vl53l1_tuningparm_offset_cal_mm2_samples = + pdev->offsetcal_cfg.mm2_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_rate_mcps = + pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_timeout_us = + pdev->zonecal_cfg.phasecal_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_dss_timeout_us = + pdev->zonecal_cfg.mm_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_phasecal_num_samples = + pdev->zonecal_cfg.phasecal_num_of_samples; + + ptun_data->vl53l1_tuningparm_zone_cal_range_timeout_us = + pdev->zonecal_cfg.range_config_timeout_us; + + ptun_data->vl53l1_tuningparm_zone_cal_zone_num_samples = + pdev->zonecal_cfg.zone_num_of_samples; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_period = + pdev->ssc_cfg.VL53L1_p_009; + + ptun_data->vl53l1_tuningparm_spadmap_vcsel_start = + pdev->ssc_cfg.vcsel_start; + + ptun_data->vl53l1_tuningparm_spadmap_rate_limit_mcps = + pdev->ssc_cfg.rate_limit_mcps; + + ptun_data->vl53l1_tuningparm_lite_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_lite_mcps; + + ptun_data->vl53l1_tuningparm_ranging_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mcps; + + ptun_data->vl53l1_tuningparm_mz_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + + ptun_data->vl53l1_tuningparm_timed_dss_config_target_total_rate_mcps = + pdev->tuning_parms.tp_dss_target_timed_mcps; + + ptun_data->vl53l1_tuningparm_lite_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + + ptun_data->vl53l1_tuningparm_ranging_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + + ptun_data->vl53l1_tuningparm_ranging_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + + ptun_data->vl53l1_tuningparm_mz_long_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + + ptun_data->vl53l1_tuningparm_mz_med_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + + ptun_data->vl53l1_tuningparm_mz_short_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + + ptun_data->vl53l1_tuningparm_timed_phasecal_config_timeout_us = + pdev->tuning_parms.tp_phasecal_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_lite_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lite_us; + + ptun_data->vl53l1_tuningparm_ranging_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_histo_us; + + ptun_data->vl53l1_tuningparm_mz_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_mz_us; + + ptun_data->vl53l1_tuningparm_timed_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_timed_us; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_margin = + pdev->smudge_correct_config.smudge_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_noise_margin = + pdev->smudge_correct_config.noise_margin; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit = + pdev->smudge_correct_config.user_xtalk_offset_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_offset_limit_hi = + pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + + ptun_data->vl53l1_tuningparm_dynxtalk_sample_limit = + pdev->smudge_correct_config.sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_single_xtalk_delta = + pdev->smudge_correct_config.single_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_averaged_xtalk_delta = + pdev->smudge_correct_config.averaged_xtalk_delta; + + ptun_data->vl53l1_tuningparm_dynxtalk_clip_limit = + pdev->smudge_correct_config.smudge_corr_clip_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_scaler_calc_method = + pdev->smudge_correct_config.scaler_calc_method; + + ptun_data->vl53l1_tuningparm_dynxtalk_xgradient_scaler = + pdev->smudge_correct_config.x_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_ygradient_scaler = + pdev->smudge_correct_config.y_gradient_scaler; + + ptun_data->vl53l1_tuningparm_dynxtalk_user_scaler_set = + pdev->smudge_correct_config.user_scaler_set; + + ptun_data->vl53l1_tuningparm_dynxtalk_smudge_cor_single_apply = + pdev->smudge_correct_config.smudge_corr_single_apply; + + ptun_data->vl53l1_tuningparm_dynxtalk_xtalk_amb_threshold = + pdev->smudge_correct_config.smudge_corr_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_amb_threshold_kcps = + pdev->smudge_correct_config.nodetect_ambient_threshold; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_sample_limit = + pdev->smudge_correct_config.nodetect_sample_limit; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_xtalk_offset_kcps = + pdev->smudge_correct_config.nodetect_xtalk_offset; + + ptun_data->vl53l1_tuningparm_dynxtalk_nodetect_min_range_mm = + pdev->smudge_correct_config.nodetect_min_range_mm; + + ptun_data->vl53l1_tuningparm_lowpowerauto_vhv_loop_bound = + pdev->low_power_auto_data.vhv_loop_bound; + + ptun_data->vl53l1_tuningparm_lowpowerauto_mm_config_timeout_us = + pdev->tuning_parms.tp_mm_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_lowpowerauto_range_config_timeout_us = + pdev->tuning_parms.tp_range_timeout_lpa_us; + + ptun_data->vl53l1_tuningparm_very_short_dss_rate_mcps = + pdev->tuning_parms.tp_dss_target_very_short_mcps; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_get_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t *ptuning_parm_value) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_version; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_key_table_version; + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_tuning_parm_lld_version; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + *ptuning_parm_value = + (int32_t)pHP->hist_algo_select; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + *ptuning_parm_value = + (int32_t)pHP->hist_target_order; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + *ptuning_parm_value = + (int32_t)pHP->filter_woi0; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + *ptuning_parm_value = + (int32_t)pHP->filter_woi1; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + *ptuning_parm_value = + (int32_t)pHP->hist_amb_est_method; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma0; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_sigma1; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + *ptuning_parm_value = + (int32_t)pHP->min_ambient_thresh_events; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + *ptuning_parm_value = + (int32_t)pHP->ambient_thresh_events_scaler; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + *ptuning_parm_value = + (int32_t)pHP->noise_threshold; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->signal_total_events_limit; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_estimator__sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pHP->sigma_thresh; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.histogram_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__phase_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__min_max_tolerance; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_sigma; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + *ptuning_parm_value = + (int32_t)pHP->algo__consistency_check__event_min_spad_count; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_hist_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_hist_short; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_min_max_tolerance; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = (int32_t)( + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps); + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + *ptuning_parm_value = + (int32_t)pHP->algo__crosstalk_detect_event_sigma; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_consistency_lite_phase_tolerance; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_target; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_cal_repeat_rate; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + *ptuning_parm_value = + (int32_t)pdev->gain_cal.standard_ranging_gain_factor; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_min_clip; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_long_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_short_sigma_thresh_mm; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + *ptuning_parm_value = (int32_t)( + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps); + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_sigma_ref_mm; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_seed_cfg; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_quantifier; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_lite_first_order_select; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + *ptuning_parm_value = + (int32_t)pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_rtn_lite_short; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_long; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_med; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_init_phase_ref_lite_short; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_timed_seed_cfg; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.signal_thresh_sigma; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[0]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[1]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[2]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[3]; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + *ptuning_parm_value = + (int32_t)pdev->dmax_cfg.target_reflectance_for_dmax_calc[4]; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + *ptuning_parm_value = + (int32_t)pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.device_test_mode; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.timeout_us; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.target_count_rate_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.min_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->refspadchar.max_count_rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + *ptuning_parm_value = + (int32_t)pXC->num_of_samples; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_min_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_range_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pXC->dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_valid_rate_kcps; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + *ptuning_parm_value = + (int32_t)pXC->algo__crosstalk_extract_max_sigma_mm; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pXC->range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.pre_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm1_num_of_samples; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->offsetcal_cfg.mm2_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.dss_config__target_total_rate_mcps; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.mm_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.phasecal_num_of_samples; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.range_config_timeout_us; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + *ptuning_parm_value = + (int32_t)pdev->zonecal_cfg.zone_num_of_samples; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.VL53L1_p_009; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.vcsel_start; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + *ptuning_parm_value = + (int32_t)pdev->ssc_cfg.rate_limit_mcps; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_lite_mcps; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mcps; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_histo_mz_mcps; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_timed_mcps; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_long_us; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_med_us; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_hist_short_us; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_long_us; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_med_us; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_mz_short_us; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_phasecal_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lite_us; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_histo_us; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_mz_us; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_timed_us; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.noise_margin; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_xtalk_offset_limit_hi; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.single_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.averaged_xtalk_delta; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_clip_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.scaler_calc_method; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.x_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.y_gradient_scaler; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.user_scaler_set; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.smudge_corr_single_apply; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + *ptuning_parm_value = (int32_t)( + pdev->smudge_correct_config.smudge_corr_ambient_threshold); + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_ambient_threshold; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_sample_limit; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_xtalk_offset; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + *ptuning_parm_value = + (int32_t)pdev->smudge_correct_config.nodetect_min_range_mm; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + *ptuning_parm_value = + (int32_t)pdev->low_power_auto_data.vhv_loop_bound; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_mm_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_range_timeout_lpa_us; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + *ptuning_parm_value = + (int32_t)pdev->tuning_parms.tp_dss_target_very_short_mcps; + break; + + + default: + *ptuning_parm_value = 0x7FFFFFFF; + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_set_tuning_parm( + VL53L1_DEV Dev, + VL53L1_TuningParms tuning_parm_key, + int32_t tuning_parm_value) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_hist_post_process_config_t *pHP = &(pdev->histpostprocess); + VL53L1_xtalkextract_config_t *pXC = &(pdev->xtalk_extract_cfg); + + LOG_FUNCTION_START(""); + + switch (tuning_parm_key) { + + case VL53L1_TUNINGPARM_VERSION: + pdev->tuning_parms.tp_tuning_parm_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_KEY_TABLE_VERSION: + pdev->tuning_parms.tp_tuning_parm_key_table_version = + (uint16_t)tuning_parm_value; + + + + + + + + + + + if ((uint16_t)tuning_parm_value + != VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT) + status = VL53L1_ERROR_TUNING_PARM_KEY_MISMATCH; + + break; + case VL53L1_TUNINGPARM_LLD_VERSION: + pdev->tuning_parms.tp_tuning_parm_lld_version = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_ALGO_SELECT: + pHP->hist_algo_select = + (VL53L1_HistAlgoSelect)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_TARGET_ORDER: + pHP->hist_target_order = + (VL53L1_HistTargetOrder)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_0: + pHP->filter_woi0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_FILTER_WOI_1: + pHP->filter_woi1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD: + pHP->hist_amb_est_method = + (VL53L1_HistAmbEstMethod)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0: + pHP->ambient_thresh_sigma0 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1: + pHP->ambient_thresh_sigma1 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS: + pHP->min_ambient_thresh_events = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER: + pHP->ambient_thresh_events_scaler = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD: + pHP->noise_threshold = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT: + pHP->signal_total_events_limit = + (int32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM: + pHP->sigma_estimator__sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM: + pHP->sigma_thresh = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_GAIN_FACTOR: + pdev->gain_cal.histogram_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE: + pHP->algo__consistency_check__phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM: + pHP->algo__consistency_check__min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA: + pHP->algo__consistency_check__event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT: + pHP->algo__consistency_check__event_min_spad_count = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_hist_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM: + pdev->xtalk_cfg.algo__crosstalk_detect_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE: + pHP->algo__crosstalk_detect_min_max_tolerance = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS: + pdev->xtalk_cfg.algo__crosstalk_detect_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA: + pHP->algo__crosstalk_detect_event_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.histogram_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE: + pdev->tuning_parms.tp_consistency_lite_phase_tolerance = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_PHASECAL_TARGET: + pdev->tuning_parms.tp_phasecal_target = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE: + pdev->tuning_parms.tp_cal_repeat_rate = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGING_GAIN_FACTOR: + pdev->gain_cal.standard_ranging_gain_factor = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM: + pdev->tuning_parms.tp_lite_min_clip = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_long_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_med_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM: + pdev->tuning_parms.tp_lite_short_sigma_thresh_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_long_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_med_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS: + pdev->tuning_parms.tp_lite_short_min_count_rate_rtn_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH: + pdev->tuning_parms.tp_lite_sigma_est_pulse_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS: + pdev->tuning_parms.tp_lite_sigma_est_amb_width_ns = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM: + pdev->tuning_parms.tp_lite_sigma_ref_mm = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RIT_MULT: + pdev->xtalk_cfg.crosstalk_range_ignore_threshold_mult = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_SEED_CONFIG: + pdev->tuning_parms.tp_lite_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_QUANTIFIER: + pdev->tuning_parms.tp_lite_quantifier = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT: + pdev->tuning_parms.tp_lite_first_order_select = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS: + pdev->xtalk_cfg.lite_mode_crosstalk_margin_kcps = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_rtn_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_long = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_med = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE: + pdev->tuning_parms.tp_init_phase_ref_lite_short = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_SEED_CONFIG: + pdev->tuning_parms.tp_timed_seed_cfg = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA: + pdev->dmax_cfg.signal_thresh_sigma = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[0] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[1] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[2] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[3] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4: + pdev->dmax_cfg.target_reflectance_for_dmax_calc[4] = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VHV_LOOPBOUND: + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE: + pdev->refspadchar.device_test_mode = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD: + pdev->refspadchar.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US: + pdev->refspadchar.timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS: + pdev->refspadchar.target_count_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.min_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS: + pdev->refspadchar.max_count_rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES: + pXC->num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_min_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM: + pXC->algo__crosstalk_extract_max_valid_range_mm = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS: + pXC->dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US: + pXC->phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS: + pXC->algo__crosstalk_extract_max_valid_rate_kcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM: + pXC->algo__crosstalk_extract_max_sigma_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US: + pXC->mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US: + pXC->range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS: + pdev->offsetcal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US: + pdev->offsetcal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US: + pdev->offsetcal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US: + pdev->offsetcal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES: + pdev->offsetcal_cfg.pre_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES: + pdev->offsetcal_cfg.mm1_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES: + pdev->offsetcal_cfg.mm2_num_of_samples = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS: + pdev->zonecal_cfg.dss_config__target_total_rate_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US: + pdev->zonecal_cfg.phasecal_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US: + pdev->zonecal_cfg.mm_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES: + pdev->zonecal_cfg.phasecal_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US: + pdev->zonecal_cfg.range_config_timeout_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES: + pdev->zonecal_cfg.zone_num_of_samples = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD: + pdev->ssc_cfg.VL53L1_p_009 = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_VCSEL_START: + pdev->ssc_cfg.vcsel_start = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS: + pdev->ssc_cfg.rate_limit_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_lite_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_histo_mz_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_timed_mcps = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_hist_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_long_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_med_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_mz_short_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_phasecal_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lite_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_histo_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_mz_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_timed_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN: + pdev->smudge_correct_config.smudge_margin = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN: + pdev->smudge_correct_config.noise_margin = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT: + pdev->smudge_correct_config.user_xtalk_offset_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI: + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT: + pdev->smudge_correct_config.sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA: + pdev->smudge_correct_config.single_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA: + pdev->smudge_correct_config.averaged_xtalk_delta = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT: + pdev->smudge_correct_config.smudge_corr_clip_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_SCALER_CALC_METHOD: + pdev->smudge_correct_config.scaler_calc_method = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER: + pdev->smudge_correct_config.x_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER: + pdev->smudge_correct_config.y_gradient_scaler = + (int16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET: + pdev->smudge_correct_config.user_scaler_set = + (uint8_t)tuning_parm_value; + break; + + case VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY: + pdev->smudge_correct_config.smudge_corr_single_apply = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD: + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS: + pdev->smudge_correct_config.nodetect_ambient_threshold = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT: + pdev->smudge_correct_config.nodetect_sample_limit = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS: + pdev->smudge_correct_config.nodetect_xtalk_offset = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM: + pdev->smudge_correct_config.nodetect_min_range_mm = + (uint16_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND: + pdev->low_power_auto_data.vhv_loop_bound = + (uint8_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_mm_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US: + pdev->tuning_parms.tp_range_timeout_lpa_us = + (uint32_t)tuning_parm_value; + break; + case VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS: + pdev->tuning_parms.tp_dss_target_very_short_mcps = + (uint16_t)tuning_parm_value; + break; + + + default: + status = VL53L1_ERROR_INVALID_PARAMS; + break; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_apply_enabled = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_enable( + VL53L1_DEV Dev + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_single_apply_disable( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.smudge_corr_single_apply = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_set_scalers( + VL53L1_DEV Dev, + int16_t x_scaler_in, + int16_t y_scaler_in, + uint8_t user_scaler_set_in + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->smudge_correct_config.x_gradient_scaler = x_scaler_in; + pdev->smudge_correct_config.y_gradient_scaler = y_scaler_in; + pdev->smudge_correct_config.user_scaler_set = user_scaler_set_in; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + +VL53L1_Error VL53L1_get_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pxtalk->algo__crosstalk_compensation_plane_offset_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps; + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps; + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps = + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + + + + + +VL53L1_Error VL53L1_set_current_xtalk_settings( + VL53L1_DEV Dev, + VL53L1_xtalk_calibration_results_t *pxtalk + ) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->xtalk_cfg.algo__crosstalk_compensation_plane_offset_kcps = + pxtalk->algo__crosstalk_compensation_plane_offset_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_x_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdev->xtalk_cfg.algo__crosstalk_compensation_y_plane_gradient_kcps = + pxtalk->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + LOG_FUNCTION_END(status); + + return status; + +} + + + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_api_debug.c b/drivers/oneplus/vl53L1/src/vl53l1_api_debug.c new file mode 100755 index 0000000000000000000000000000000000000000..46f7f0daa5d3f64167ff0408bf01fc2732aaf2e2 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_api_debug.c @@ -0,0 +1,3629 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm.h" +#include "vl53l1_core.h" +#include "vl53l1_api_debug.h" + +#ifdef VL53L1_LOG_ENABLE +#include "vl53l1_nvm_debug.h" +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_decode_calibration_data_buffer( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_calibration_data_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (sizeof(VL53L1_calibration_data_t) > buf_size) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + memcpy(pdata, pbuffer, sizeof(VL53L1_calibration_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_debug_data( + VL53L1_DEV Dev, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_read_nvm(Dev, 0, pdata); + +#ifdef VL53L1_LOG_ENABLE + if (status == VL53L1_ERROR_NONE) + VL53L1_print_decoded_nvm_data( + pdata, + "get_nvm_debug_data():pnvm_info.", + VL53L1_TRACE_MODULE_NVM_DATA); +#endif + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_histogram_debug_data( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + pdata, + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_additional_data( + VL53L1_DEV Dev, + VL53L1_additional_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdata->preset_mode = pdev->preset_mode; + pdata->zone_preset = pdev->zone_preset; + pdata->measurement_mode = pdev->measurement_mode; + pdata->offset_calibration_mode = pdev->offset_calibration_mode; + pdata->offset_correction_mode = pdev->offset_correction_mode; + pdata->dmax_mode = pdev->dmax_mode; + + pdata->phasecal_config_timeout_us = pdev->phasecal_config_timeout_us; + pdata->mm_config_timeout_us = pdev->mm_config_timeout_us; + pdata->range_config_timeout_us = pdev->range_config_timeout_us; + pdata->inter_measurement_period_ms = pdev->inter_measurement_period_ms; + pdata->dss_config__target_total_rate_mcps = + pdev->dss_config__target_total_rate_mcps; + + + + + status = + VL53L1_get_histogram_debug_data( + Dev, + &(pdata->VL53L1_p_010)); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + +VL53L1_Error VL53L1_get_xtalk_debug_data( + VL53L1_DEV Dev, + VL53L1_xtalk_debug_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->xtalk_cfg), + &(pdev->xtalk_cfg), + sizeof(VL53L1_xtalk_config_t)); + + memcpy( + &(pdata->hist_data), + &(pdev->hist_data), + sizeof(VL53L1_histogram_bin_data_t)); + + memcpy( + &(pdata->xtalk_shapes), + &(pdev->xtalk_shapes), + sizeof(VL53L1_xtalk_histogram_data_t)); + + memcpy( + &(pdata->xtalk_results), + &(pdev->xtalk_results), + sizeof(VL53L1_xtalk_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_offset_debug_data( + VL53L1_DEV Dev, + VL53L1_offset_debug_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + memcpy( + &(pdata->customer), + &(pdev->customer), + sizeof(VL53L1_customer_nvm_managed_t)); + + memcpy( + &(pdata->fmt_dmax_cal), + &(pdev->fmt_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->cust_dmax_cal), + &(pdev->cust_dmax_cal), + sizeof(VL53L1_dmax_calibration_data_t)); + + memcpy( + &(pdata->add_off_cal_data), + &(pdev->add_off_cal_data), + sizeof(VL53L1_additional_offset_cal_data_t)); + + memcpy( + &(pdata->offset_results), + &(pdev->offset_results), + sizeof(VL53L1_offset_range_results_t)); + + LOG_FUNCTION_END(status); + + return status; +} + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_signed_fixed_point_sprintf( + int32_t signed_fp_value, + uint8_t frac_bits, + uint16_t buf_size, + char *pbuffer) +{ + + + + + + uint32_t fp_value = 0; + uint32_t unity_fp_value = 0; + uint32_t sign_bit = 0; + uint32_t int_part = 0; + uint32_t frac_part = 0; + uint32_t dec_points = 0; + uint32_t dec_scaler = 0; + uint32_t dec_part = 0; + + uint64_t tmp_long_int = 0; + + char fmt[VL53L1_MAX_STRING_LENGTH]; + + SUPPRESS_UNUSED_WARNING(buf_size); + + + + + sign_bit = signed_fp_value >> 31; + + if (sign_bit > 0) { + fp_value = 0x80000000 - + (0x7FFFFFFF & (uint32_t)signed_fp_value); + } else + fp_value = (uint32_t)signed_fp_value; + + int_part = fp_value >> frac_bits; + unity_fp_value = 0x01 << frac_bits; + frac_part = fp_value & (unity_fp_value-1); + + + + + + dec_points = 2; + dec_scaler = 100; + + while (dec_scaler < unity_fp_value) { + dec_points++; + dec_scaler *= 10; + } + + + + if (sign_bit > 0) + sprintf(fmt, "-%%u.%%0%uu", dec_points); + else + sprintf(fmt, "%%u.%%0%uu", dec_points); + + + + + + tmp_long_int = (uint64_t)frac_part * (uint64_t)dec_scaler; + tmp_long_int += (uint64_t)unity_fp_value/2; + + tmp_long_int = do_division_u(tmp_long_int, (uint64_t)unity_fp_value); + + dec_part = (uint32_t)tmp_long_int; + + + + sprintf( + pbuffer, + fmt, + int_part, + dec_part); +} + + +void VL53L1_print_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "i2c_slave__device_address", + pdata->i2c_slave__device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vddpix", + pdata->ana_config__vhv_ref_sel_vddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vhv_ref_sel_vquench", + pdata->ana_config__vhv_ref_sel_vquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__reg_avdd1v2_sel", + pdata->ana_config__reg_avdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim", + pdata->ana_config__fast_osc__trim); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->osc_measured__fast_osc__frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "osc_measured__fast_osc__frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__timeout_macrop_loop_bound", + pdata->vhv_config__timeout_macrop_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__count_thresh", + pdata->vhv_config__count_thresh); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__offset", + pdata->vhv_config__offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "vhv_config__init", + pdata->vhv_config__init); +} + + +void VL53L1_print_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_0", + pdata->global_config__spad_enables_ref_0); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_1", + pdata->global_config__spad_enables_ref_1); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_2", + pdata->global_config__spad_enables_ref_2); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_3", + pdata->global_config__spad_enables_ref_3); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_4", + pdata->global_config__spad_enables_ref_4); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_ref_5", + pdata->global_config__spad_enables_ref_5); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__ref_en_start_select", + pdata->global_config__ref_en_start_select); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__num_requested_ref_spads", + pdata->ref_spad_man__num_requested_ref_spads); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_man__ref_location", + pdata->ref_spad_man__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_spad_char__total_rate_target_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_spad_char__total_rate_target_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__part_to_part_range_offset_mm", + fp_text); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__inner_offset_mm", + pdata->mm_config__inner_offset_mm); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "mm_config__outer_offset_mm", + pdata->mm_config__outer_offset_mm); +} + + +void VL53L1_print_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__model_id", + pdata->identification__model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_type", + pdata->identification__module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__revision_id", + pdata->identification__revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "identification__module_id", + pdata->identification__module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__trim_max", + pdata->ana_config__fast_osc__trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__fast_osc__freq_set", + pdata->ana_config__fast_osc__freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_trim", + pdata->ana_config__vcsel_trim); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion", + pdata->ana_config__vcsel_selion); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ana_config__vcsel_selion_max", + pdata->ana_config__vcsel_selion_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "protected_laser_safety__lock_bit", + pdata->protected_laser_safety__lock_bit); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key", + pdata->laser_safety__key); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__key_ro", + pdata->laser_safety__key_ro); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__clip", + pdata->laser_safety__clip); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "laser_safety__mult", + pdata->laser_safety__mult); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_0", + pdata->global_config__spad_enables_rtn_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_1", + pdata->global_config__spad_enables_rtn_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_2", + pdata->global_config__spad_enables_rtn_2); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_3", + pdata->global_config__spad_enables_rtn_3); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_4", + pdata->global_config__spad_enables_rtn_4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_5", + pdata->global_config__spad_enables_rtn_5); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_6", + pdata->global_config__spad_enables_rtn_6); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_7", + pdata->global_config__spad_enables_rtn_7); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_8", + pdata->global_config__spad_enables_rtn_8); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_9", + pdata->global_config__spad_enables_rtn_9); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_10", + pdata->global_config__spad_enables_rtn_10); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_11", + pdata->global_config__spad_enables_rtn_11); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_12", + pdata->global_config__spad_enables_rtn_12); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_13", + pdata->global_config__spad_enables_rtn_13); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_14", + pdata->global_config__spad_enables_rtn_14); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_15", + pdata->global_config__spad_enables_rtn_15); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_16", + pdata->global_config__spad_enables_rtn_16); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_17", + pdata->global_config__spad_enables_rtn_17); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_18", + pdata->global_config__spad_enables_rtn_18); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_19", + pdata->global_config__spad_enables_rtn_19); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_20", + pdata->global_config__spad_enables_rtn_20); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_21", + pdata->global_config__spad_enables_rtn_21); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_22", + pdata->global_config__spad_enables_rtn_22); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_23", + pdata->global_config__spad_enables_rtn_23); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_24", + pdata->global_config__spad_enables_rtn_24); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_25", + pdata->global_config__spad_enables_rtn_25); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_26", + pdata->global_config__spad_enables_rtn_26); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_27", + pdata->global_config__spad_enables_rtn_27); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_28", + pdata->global_config__spad_enables_rtn_28); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_29", + pdata->global_config__spad_enables_rtn_29); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_30", + pdata->global_config__spad_enables_rtn_30); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_config__spad_enables_rtn_31", + pdata->global_config__spad_enables_rtn_31); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "roi_config__mode_roi_centre_spad", + pdata->roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__mode_roi_xy_size", + pdata->roi_config__mode_roi_xy_size); +} + + +void VL53L1_print_histogram_bin_data( + VL53L1_histogram_bin_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_bins", + pdata->number_of_ambient_bins); + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_seq[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_seq[i]); + } + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) { + sprintf(ppre_text, "%sbin_rep[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->bin_rep[i]); + } + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %d\n", + ppre_text, + pdata->bin_data[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__interrupt_status", + pdata->result__interrupt_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__range_status", + pdata->result__range_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__report_status", + pdata->result__report_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__stream_count", + pdata->result__stream_count); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__dss_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__dss_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_009", + pdata->VL53L1_p_009); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "min_bin_value", + pdata->min_bin_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_bin_value", + pdata->max_bin_value); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "number_of_ambient_samples", + pdata->number_of_ambient_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "ambient_events_sum", + pdata->ambient_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_004", + pdata->VL53L1_p_004); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_centre_spad", + pdata->roi_config__user_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%02X\n", + pprefix, + "roi_config__user_roi_requested_global_xy_size", + pdata->roi_config__user_roi_requested_global_xy_size); +} + + +void VL53L1_print_xtalk_histogram_shape_data( + VL53L1_xtalk_histogram_shape_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_023", + pdata->VL53L1_p_023); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_024", + pdata->VL53L1_p_024); + + for (i = 0; i < pdata->VL53L1_p_024; i++) { + + sprintf(ppre_text, "%sbin_data[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->bin_data[i], + 10, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + } + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_result__vcsel_start", + pdata->phasecal_result__vcsel_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_config__vcsel_start", + pdata->cal_config__vcsel_start); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->vcsel_width, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "vcsel_width", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_019, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_019", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); +} + + +void VL53L1_print_xtalk_histogram_data( + VL53L1_xtalk_histogram_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + + + sprintf(ppre_text, "%sxtalk_shape.", pprefix); + VL53L1_print_xtalk_histogram_shape_data( + &(pdata->xtalk_shape), + ppre_text, trace_flags); + + + + sprintf(ppre_text, "%sxtalk_hist_removed.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->xtalk_hist_removed), + ppre_text, trace_flags); +} + + +void VL53L1_print_range_data( + VL53L1_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_id", + pdata->range_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "time_stamp", + pdata->time_stamp); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->VL53L1_p_015); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_022", + pdata->VL53L1_p_022); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_025", + pdata->VL53L1_p_025); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_026", + pdata->VL53L1_p_026); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->VL53L1_p_016); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_027", + pdata->VL53L1_p_027); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->width, + 4, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "width", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_030", + pdata->VL53L1_p_030); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->fast_osc_frequency, + 12, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "fast_osc_frequency", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_006, + 8, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "actual_effective_spad", + fp_text); + + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "total_periods_elapsed", + pdata->total_periods_elapsed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "peak_duration_us", + pdata->peak_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "woi_duration_us", + pdata->woi_duration_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_020", + pdata->VL53L1_p_020); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_021", + pdata->VL53L1_p_021); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "VL53L1_p_013", + pdata->VL53L1_p_013); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->avg_signal_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "avg_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ambient_count_rate_mcps, + 7, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ambient_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->total_rate_per_spad_mcps, + 13, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "total_rate_per_spad_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_012, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_012", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_028, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_028", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_029, + 11, VL53L1_MAX_STRING_LENGTH, fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_029", + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "min_range_mm", + pdata->min_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "max_range_mm", + pdata->max_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_status", + pdata->range_status); +} + + +void VL53L1_print_range_results( + VL53L1_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cfg_device_state", + pdata->cfg_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "rd_device_state", + pdata->rd_device_state); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_id", + pdata->zone_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "stream_count", + pdata->stream_count); + + for (i = 0; i < VL53L1_MAX_AMBIENT_DMAX_VALUES; i++) { + sprintf( + ppre_text, + "%sambient_dmax_mm[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->VL53L1_p_007[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "device_status", + pdata->device_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "wrap_dmax_mm", + pdata->wrap_dmax_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_range_data( + &pdata->VL53L1_p_002[i], + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%sxmonitor.", pprefix); + VL53L1_print_range_data( + &pdata->xmonitor, + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_range_results( + VL53L1_offset_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_report", + pdata->cal_report); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_offset_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + + +void VL53L1_print_offset_range_data( + VL53L1_offset_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dss_config__roi_mode_control", + pdata->dss_config__roi_mode_control); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__manual_effective_spads_select, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__manual_effective_spads_select", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "median_range_mm", + pdata->median_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "range_mm_offset", + pdata->range_mm_offset); +} + + +void VL53L1_print_cal_peak_rate_map( + VL53L1_cal_peak_rate_map_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + uint8_t x = 0; + uint8_t y = 0; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_distance_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_samples", + pdata->max_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); + + i = 0; + for (y = 0; y < pdata->height; y++) { + for (x = 0; x < pdata->width; x++) { + + sprintf(ppre_text, "%speak_rate_mcps[%u]", pprefix, i); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps[i], + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %s\n", + ppre_text, + fp_text); + + i++; + } + } +} + +void VL53L1_print_additional_data( + VL53L1_additional_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "measurement_mode", + pdata->measurement_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_calibration_mode", + pdata->offset_calibration_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "offset_correction_mode", + pdata->offset_correction_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "dmax_mode", + pdata->dmax_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "inter_measurement_period_ms", + pdata->inter_measurement_period_ms); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + sprintf(ppre_text, "%s VL53L1_p_010.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->VL53L1_p_010, + ppre_text, trace_flags); + + +} + + +void VL53L1_print_additional_offset_cal_data( + VL53L1_additional_offset_cal_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_inner_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_inner_peak_signal_count_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__mm_outer_peak_signal_count_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__mm_outer_peak_signal_count_rtn_mcps", + fp_text); +} + + +void VL53L1_print_gain_calibration_data( + VL53L1_gain_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->standard_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "standard_ranging_gain_factor", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_ranging_gain_factor, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_ranging_gain_factor", + fp_text); +} + + +void VL53L1_print_zone_calibration_data( + VL53L1_zone_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->peak_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "peak_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_014, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_014", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->VL53L1_p_005, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "VL53L1_p_005", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->median_range_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "median_range_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->range_mm_offset, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "range_mm_offset", + fp_text); +} + + +void VL53L1_print_zone_calibration_results( + VL53L1_zone_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "preset_mode", + pdata->preset_mode); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_preset", + pdata->zone_preset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_distance_mm", + pdata->cal_distance_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->cal_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "cal_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->phasecal_result__reference_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "phasecal_result__reference_phase", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->zero_distance_phase, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "zero_distance_phase", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_zone_calibration_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } +} + +void VL53L1_print_xtalk_range_results( + VL53L1_xtalk_range_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + uint8_t i = 0; + + VL53L1_histogram_bin_data_t *pbin_data; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "cal_status", + pdata->cal_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples_status", + pdata->num_of_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zero_samples_status", + pdata->zero_samples_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_sigma_status", + pdata->max_sigma_status); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_results", + pdata->max_results); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_results", + pdata->active_results); + + for (i = 0; i < pdata->active_results; i++) { + sprintf(ppre_text, "%sdata[%u].", pprefix, i); + VL53L1_print_xtalk_range_data( + &(pdata->VL53L1_p_002[i]), + ppre_text, trace_flags); + } + + sprintf(ppre_text, "%scentral_histogram_sum.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_sum, + ppre_text, trace_flags); + + sprintf(ppre_text, "%scentral_histogram_avg.", pprefix); + VL53L1_print_histogram_bin_data( + &pdata->central_histogram_avg, + ppre_text, trace_flags); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_015", + pdata->central_histogram__window_start); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "VL53L1_p_016", + pdata->central_histogram__window_end); + + pbin_data = &(pdata->histogram_avg_1[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_1[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->histogram_avg_2[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%shistogram_avg_2[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } + + pbin_data = &(pdata->xtalk_avg[0]); + + for (i = 0; i < 5; i++) { + sprintf(ppre_text, "%sxtalk_avg[%u].", pprefix, i); + VL53L1_print_histogram_bin_data( + pbin_data, + ppre_text, trace_flags); + pbin_data++; + } +} + + +void VL53L1_print_xtalk_range_data( + VL53L1_xtalk_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "no_of_samples", + pdata->no_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_sum", + pdata->signal_total_events_sum); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "signal_total_events_avg", + pdata->signal_total_events_avg); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_sum, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_sum", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->rate_per_spad_kcps_avg, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "rate_per_spad_kcps_avg", + fp_text); +} + + +void VL53L1_print_xtalk_calibration_results( + VL53L1_xtalk_calibration_results_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); +} + + +void VL53L1_print_xtalk_config( + VL53L1_xtalk_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + int16_t tmpi16; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_x_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + tmpi16 = pdata->algo__crosstalk_compensation_y_plane_gradient_kcps; + VL53L1_signed_fixed_point_sprintf( + (int32_t)tmpi16, + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "global_crosstalk_compensation_enable", + pdata->global_crosstalk_compensation_enable); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->histogram_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "histogram_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->lite_mode_crosstalk_margin_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "lite_mode_crosstalk_margin_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_mult, + 5, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_mult", + fp_text); + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->crosstalk_range_ignore_threshold_rate_mcps, + 13, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "crosstalk_range_ignore_threshold_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_max_valid_range_mm", + pdata->algo__crosstalk_detect_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_detect_min_valid_range_mm", + pdata->algo__crosstalk_detect_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_valid_rate_kcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_detect_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_detect_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_xtalk_extract_config( + VL53L1_xtalkextract_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "num_of_samples", + pdata->num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_max_valid_range_mm", + pdata->algo__crosstalk_extract_max_valid_range_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "algo__crosstalk_extract_min_valid_range_mm", + pdata->algo__crosstalk_extract_min_valid_range_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_valid_rate_kcps, + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_valid_rate_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->algo__crosstalk_extract_max_sigma_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "algo__crosstalk_extract_max_sigma_mm", + fp_text); + +} + + +void VL53L1_print_zone_cal_config( + VL53L1_zonecal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm_config_timeout_us", + pdata->mm_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_num_of_samples", + pdata->phasecal_num_of_samples); + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "zone_num_of_samples", + pdata->zone_num_of_samples); + +} + +void VL53L1_print_offset_cal_config( + VL53L1_offsetcal_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->dss_config__target_total_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "dss_config__target_total_rate_mcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "phasecal_config_timeout_us", + pdata->phasecal_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "range_config_timeout_us", + pdata->range_config_timeout_us); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "pre_num_of_samples", + pdata->pre_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm1_num_of_samples", + pdata->mm1_num_of_samples); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "mm2_num_of_samples", + pdata->mm2_num_of_samples); + + +} + + +void VL53L1_print_dmax_calibration_data( + VL53L1_dmax_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__actual_effective_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__actual_effective_spads", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__peak_signal_count_rate_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__peak_signal_count_rate_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref__distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref__distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->ref_reflectance_pc, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "ref_reflectance_pc", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->coverglass_transmission, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "coverglass_transmission", + fp_text); +} + + +void VL53L1_print_calibration_data( + VL53L1_calibration_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = 0x%08X\n", + pprefix, + "struct_version", + pdata->struct_version); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soptical_centre.", pprefix); + VL53L1_print_optical_centre( + &(pdata->optical_centre), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalkhisto.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalkhisto), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_gain_calibration_data( + &(pdata->gain_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scal_peak_rate_map.", pprefix); + VL53L1_print_cal_peak_rate_map( + &(pdata->cal_peak_rate_map), + ppre_text, trace_flags); +} + + +void VL53L1_print_xtalk_debug_data( + VL53L1_xtalk_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_cfg.", pprefix); + VL53L1_print_xtalk_config( + &(pdata->xtalk_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_extract_cfg.", pprefix); + VL53L1_print_xtalk_extract_config( + &(pdata->xtalk_extract_cfg), + ppre_text, trace_flags); + + sprintf(ppre_text, "%shist_data.", pprefix); + VL53L1_print_histogram_bin_data( + &(pdata->hist_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sxtalk_shapes.", pprefix); + VL53L1_print_xtalk_histogram_data( + &(pdata->xtalk_shapes), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sgain_cal.", pprefix); + VL53L1_print_xtalk_range_results( + &(pdata->xtalk_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_offset_debug_data( + VL53L1_offset_debug_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + sprintf(ppre_text, "%scustomer.", pprefix); + VL53L1_print_customer_nvm_managed( + &(pdata->customer), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sfmt_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->fmt_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%scust_dmax_cal.", pprefix); + VL53L1_print_dmax_calibration_data( + &(pdata->cust_dmax_cal), + ppre_text, trace_flags); + + sprintf(ppre_text, "%sadd_off_cal_data.", pprefix); + VL53L1_print_additional_offset_cal_data( + &(pdata->add_off_cal_data), + ppre_text, trace_flags); + + sprintf(ppre_text, "%soffset_results.", pprefix); + VL53L1_print_offset_range_results( + &(pdata->offset_results), + ppre_text, trace_flags); +} + + +void VL53L1_print_zone_config( + VL53L1_zone_config_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "max_zones", + pdata->max_zones); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "active_zones", + pdata->active_zones); + + for (i = 0; i < pdata->active_zones; i++) { + sprintf(ppre_text, "%suser_zones[%u].", pprefix, i); + VL53L1_print_user_zone( + &pdata->user_zones[i], + ppre_text, + trace_flags); + } +} + + +void VL53L1_print_optical_centre( + VL53L1_optical_centre_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->x_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "x_centre", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->y_centre, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "y_centre", + fp_text); +} + + +void VL53L1_print_user_zone( + VL53L1_user_zone_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "x_centre", + pdata->x_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "y_centre", + pdata->y_centre); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "width", + pdata->width); + + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "height", + pdata->height); +} + + +void VL53L1_print_spad_rate_data( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + uint16_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8s,%4s,%4s, %s\n", + pprefix, + "spad_no", + "row", + "col", + "peak_rate_mcps"); + + for (spad_no = 0; spad_no < pspad_rates->no_of_values; spad_no++) { + + + + VL53L1_decode_row_col( + (uint8_t)spad_no, + &row, + &col); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%8u,%4u,%4u, %s\n", + pprefix, + spad_no, + row, + col, + fp_text); + } +} + + +void VL53L1_print_spad_rate_map( + VL53L1_spad_rate_data_t *pspad_rates, + char *pprefix, + uint32_t trace_flags) +{ + + + + + + + uint8_t spad_no = 0; + uint8_t row = 0; + uint8_t col = 0; + + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4s", + pprefix, + " "); + + for (col = 0; col < VL53L1_SPAD_ARRAY_WIDTH; col++) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8u", + col); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + + + + for (row = 0; row < VL53L1_SPAD_ARRAY_HEIGHT; row++) { + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%4u", + pprefix, + row); + + for (col = 0; col < VL53L1_SPAD_ARRAY_HEIGHT; col++) { + + + + + VL53L1_encode_row_col( + row, + col, + &spad_no); + + + + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pspad_rates->rate_data[spad_no], + pspad_rates->fractional_bits, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + + + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + ",%8s", + fp_text); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + } +} + + +#endif + + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_api_preset_modes.c b/drivers/oneplus/vl53L1/src/vl53l1_api_preset_modes.c new file mode 100755 index 0000000000000000000000000000000000000000..e00f48830d2d5327a39ca2e5039c7771eeead201 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_api_preset_modes.c @@ -0,0 +1,4927 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_zone_presets.h" +#include "vl53l1_core.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_tuning_parm_defaults.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_refspadchar_config_struct( + VL53L1_refspadchar_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + pdata->device_test_mode = + VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT; + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT; + pdata->timeout_us = + VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT; + pdata->target_count_rate_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT; + pdata->min_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT; + pdata->max_count_rate_limit_mcps = + VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_ssc_config_struct( + VL53L1_ssc_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + pdata->array_select = VL53L1_DEVICESSCARRAY_RTN; + + + + pdata->VL53L1_p_009 = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT; + + + + pdata->vcsel_start = + VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT; + + + + pdata->vcsel_width = 0x02; + + + + pdata->timeout_us = 36000; + + + + + + + pdata->rate_limit_mcps = + VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_xtalk_config_struct( + VL53L1_customer_nvm_managed_t *pnvm, + VL53L1_xtalk_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + + pdata->algo__crosstalk_compensation_plane_offset_kcps = + pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + + pdata->nvm_default__crosstalk_compensation_plane_offset_kcps = + (uint32_t)pnvm->algo__crosstalk_compensation_plane_offset_kcps; + pdata->nvm_default__crosstalk_compensation_x_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps; + pdata->nvm_default__crosstalk_compensation_y_plane_gradient_kcps = + pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps; + + pdata->histogram_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_HIST_XTALK_MARGIN_KCPS_DEFAULT; + pdata->lite_mode_crosstalk_margin_kcps = + VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT; + + + + + pdata->crosstalk_range_ignore_threshold_mult = + VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT; + + if ((pdata->algo__crosstalk_compensation_plane_offset_kcps == 0x00) + && (pdata->algo__crosstalk_compensation_x_plane_gradient_kcps + == 0x00) + && (pdata->algo__crosstalk_compensation_y_plane_gradient_kcps + == 0x00)) + pdata->global_crosstalk_compensation_enable = 0x00; + else + pdata->global_crosstalk_compensation_enable = 0x01; + + + if ((status == VL53L1_ERROR_NONE) && + (pdata->global_crosstalk_compensation_enable == 0x01)) { + pdata->crosstalk_range_ignore_threshold_rate_mcps = + VL53L1_calc_range_ignore_threshold( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + pdata->crosstalk_range_ignore_threshold_mult); + } else { + pdata->crosstalk_range_ignore_threshold_rate_mcps = 0; + } + + + + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_xtalk_extract_config_struct( + VL53L1_xtalkextract_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_RATE_MCPS_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_DSS_TIMEOUT_US_DEFAULT; + + + pdata->num_of_samples = + VL53L1_TUNINGPARM_XTALK_EXTRACT_NUM_OF_SAMPLES_DEFAULT; + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_XTALK_EXTRACT_BIN_TIMEOUT_US_DEFAULT; + + + + + + + pdata->algo__crosstalk_extract_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MIN_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_FILTER_THRESH_MM_DEFAULT; + pdata->algo__crosstalk_extract_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_EXTRACT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_extract_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_EXTRACT_SIGMA_THRESHOLD_MM_DEFAULT; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_offset_cal_config_struct( + VL53L1_offsetcal_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT; + + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT; + + + + + + + pdata->pre_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT; + pdata->mm1_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT; + pdata->mm2_num_of_samples = + VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_init_zone_cal_config_struct( + VL53L1_zonecal_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + pdata->dss_config__target_total_rate_mcps = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_RATE_MCPS_DEFAULT; + + + pdata->phasecal_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_TIMEOUT_US_DEFAULT; + + + pdata->range_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_RANGE_TIMEOUT_US_DEFAULT; + + + pdata->mm_config_timeout_us = + VL53L1_TUNINGPARM_ZONE_CAL_DSS_TIMEOUT_US_DEFAULT; + + + + + + + pdata->phasecal_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_PHASECAL_NUM_SAMPLES_DEFAULT; + pdata->zone_num_of_samples = + VL53L1_TUNINGPARM_ZONE_CAL_ZONE_NUM_SAMPLES_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_post_process_config_struct( + uint8_t xtalk_compensation_enable, + VL53L1_hist_post_process_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pdata->hist_algo_select = + VL53L1_TUNINGPARM_HIST_ALGO_SELECT_DEFAULT; + + + + + pdata->hist_target_order = + VL53L1_TUNINGPARM_HIST_TARGET_ORDER_DEFAULT; + + + + + pdata->filter_woi0 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_0_DEFAULT; + + pdata->filter_woi1 = + VL53L1_TUNINGPARM_HIST_FILTER_WOI_1_DEFAULT; + + + + + pdata->hist_amb_est_method = + VL53L1_TUNINGPARM_HIST_AMB_EST_METHOD_DEFAULT; + + pdata->ambient_thresh_sigma0 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_0_DEFAULT; + + pdata->ambient_thresh_sigma1 = + VL53L1_TUNINGPARM_HIST_AMB_THRESH_SIGMA_1_DEFAULT; + + + + + pdata->ambient_thresh_events_scaler = + VL53L1_TUNINGPARM_HIST_AMB_EVENTS_SCALER_DEFAULT; + + + + pdata->min_ambient_thresh_events = + VL53L1_TUNINGPARM_HIST_MIN_AMB_THRESH_EVENTS_DEFAULT; + + + pdata->noise_threshold = + VL53L1_TUNINGPARM_HIST_NOISE_THRESHOLD_DEFAULT; + + + pdata->signal_total_events_limit = + VL53L1_TUNINGPARM_HIST_SIGNAL_TOTAL_EVENTS_LIMIT_DEFAULT; + + pdata->sigma_estimator__sigma_ref_mm = + VL53L1_TUNINGPARM_HIST_SIGMA_EST_REF_MM_DEFAULT; + + + + + + + + + + + + + + + pdata->sigma_thresh = + VL53L1_TUNINGPARM_HIST_SIGMA_THRESH_MM_DEFAULT; + + pdata->range_offset_mm = 0; + + + pdata->gain_factor = + VL53L1_TUNINGPARM_HIST_GAIN_FACTOR_DEFAULT; + + + + + + + + + + + + + + + + pdata->valid_phase_low = 0x08; + pdata->valid_phase_high = 0x88; + + + + + + + + + + pdata->algo__consistency_check__phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_PHASE_TOLERANCE_DEFAULT; + + + + + + + + + + pdata->algo__consistency_check__event_sigma = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_DEFAULT; + + + + pdata->algo__consistency_check__event_min_spad_count = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_EVENT_SIGMA_MIN_SPAD_LIMIT_DEFAULT; + + + + + + pdata->algo__consistency_check__min_max_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_HIST_MIN_MAX_TOLERANCE_MM_DEFAULT; + + + + pdata->algo__crosstalk_compensation_enable = xtalk_compensation_enable; + + + + + + + + + + + + pdata->algo__crosstalk_detect_min_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_range_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RANGE_MM_DEFAULT; + pdata->algo__crosstalk_detect_max_valid_rate_kcps = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_VALID_RATE_KCPS_DEFAULT; + pdata->algo__crosstalk_detect_max_sigma_mm = + VL53L1_TUNINGPARM_XTALK_DETECT_MAX_SIGMA_MM_DEFAULT; + + + + + + + + + + + + + + pdata->algo__crosstalk_detect_event_sigma = + VL53L1_TUNINGPARM_XTALK_DETECT_EVENT_SIGMA_DEFAULT; + + + + + + pdata->algo__crosstalk_detect_min_max_tolerance = + VL53L1_TUNINGPARM_XTALK_DETECT_MIN_MAX_TOLERANCE_DEFAULT; + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_dmax_calibration_data_struct( + VL53L1_dmax_calibration_data_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pdata->ref__actual_effective_spads = 0x5F2D; + + + pdata->ref__peak_signal_count_rate_mcps = 0x0844; + + + pdata->ref__distance_mm = 0x08A5; + + + + + pdata->ref_reflectance_pc = 0x0014; + + + + pdata->coverglass_transmission = 0x0100; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_tuning_parm_storage_struct( + VL53L1_tuning_parm_storage_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + pdata->tp_tuning_parm_version = + VL53L1_TUNINGPARM_VERSION_DEFAULT; + pdata->tp_tuning_parm_key_table_version = + VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT; + pdata->tp_tuning_parm_lld_version = + VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT; + pdata->tp_init_phase_rtn_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_lite_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_rtn_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_long = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_LONG_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_med = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_MED_RANGE_DEFAULT; + pdata->tp_init_phase_ref_hist_short = + VL53L1_TUNINGPARM_INITIAL_PHASE_REF_HISTO_SHORT_RANGE_DEFAULT; + pdata->tp_consistency_lite_phase_tolerance = + VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT; + pdata->tp_phasecal_target = + VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT; + pdata->tp_cal_repeat_rate = + VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT; + pdata->tp_lite_min_clip = + VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT; + pdata->tp_lite_long_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_med_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_short_sigma_thresh_mm = + VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT; + pdata->tp_lite_long_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_med_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_short_min_count_rate_rtn_mcps = + VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT; + pdata->tp_lite_sigma_est_pulse_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT; + pdata->tp_lite_sigma_est_amb_width_ns = + VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT; + pdata->tp_lite_sigma_ref_mm = + VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT; + pdata->tp_lite_seed_cfg = + VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT; + pdata->tp_timed_seed_cfg = + VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT; + pdata->tp_lite_quantifier = + VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT; + pdata->tp_lite_first_order_select = + VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT; + + + + + + + pdata->tp_dss_target_lite_mcps = + VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mcps = + VL53L1_TUNINGPARM_RANGING_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_histo_mz_mcps = + VL53L1_TUNINGPARM_MZ_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_dss_target_timed_mcps = + VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT; + pdata->tp_phasecal_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_long_us = + VL53L1_TUNINGPARM_RANGING_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_med_us = + VL53L1_TUNINGPARM_RANGING_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_hist_short_us = + VL53L1_TUNINGPARM_RANGING_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_long_us = + VL53L1_TUNINGPARM_MZ_LONG_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_med_us = + VL53L1_TUNINGPARM_MZ_MED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_mz_short_us = + VL53L1_TUNINGPARM_MZ_SHORT_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_phasecal_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_mm_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lite_us = + VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_histo_us = + VL53L1_TUNINGPARM_RANGING_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_mz_us = + VL53L1_TUNINGPARM_MZ_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_timed_us = + VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + + + + pdata->tp_mm_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT; + pdata->tp_range_timeout_lpa_us = + VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT; + + pdata->tp_dss_target_very_short_mcps = + VL53L1_TUNINGPARM_VERY_SHORT_DSS_RATE_MCPS_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_hist_gen3_dmax_config_struct( + VL53L1_hist_gen3_dmax_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdata->dss_config__target_total_rate_mcps = 0x1400; + pdata->dss_config__aperture_attenuation = 0x38; + + pdata->signal_thresh_sigma = + VL53L1_TUNINGPARM_DMAX_CFG_SIGNAL_THRESH_SIGMA_DEFAULT; + pdata->ambient_thresh_sigma = 0x70; + pdata->min_ambient_thresh_events = 16; + pdata->signal_total_events_limit = 100; + pdata->max_effective_spads = 0xFFFF; + + + + + + + + + + + + pdata->target_reflectance_for_dmax_calc[0] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_0_DEFAULT; + pdata->target_reflectance_for_dmax_calc[1] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_1_DEFAULT; + pdata->target_reflectance_for_dmax_calc[2] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_2_DEFAULT; + pdata->target_reflectance_for_dmax_calc[3] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_3_DEFAULT; + pdata->target_reflectance_for_dmax_calc[4] = + VL53L1_TUNINGPARM_DMAX_CFG_REFLECTANCE_ARRAY_4_DEFAULT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x0A00; + pstatic->debug__ctrl = 0x00; + pstatic->test_mode__ctrl = 0x00; + pstatic->clk_gating__ctrl = 0x00; + pstatic->nvm_bist__ctrl = 0x00; + pstatic->nvm_bist__num_nvm_words = 0x00; + pstatic->nvm_bist__start_address = 0x00; + pstatic->host_if__status = 0x00; + pstatic->pad_i2c_hv__config = 0x00; + pstatic->pad_i2c_hv__extsup_config = 0x00; + + + + + + + pstatic->gpio_hv_pad__ctrl = 0x00; + + + + + + + + + pstatic->gpio_hv_mux__ctrl = + VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW | + VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS; + + pstatic->gpio__tio_hv_status = 0x02; + pstatic->gpio__fio_hv_status = 0x00; + pstatic->ana_config__spad_sel_pswidth = 0x02; + pstatic->ana_config__vcsel_pulse_width_offset = 0x08; + pstatic->ana_config__fast_osc__config_ctrl = 0x00; + + pstatic->sigma_estimator__effective_pulse_width_ns = + ptuning_parms->tp_lite_sigma_est_pulse_width_ns; + pstatic->sigma_estimator__effective_ambient_width_ns = + ptuning_parms->tp_lite_sigma_est_amb_width_ns; + pstatic->sigma_estimator__sigma_ref_mm = + ptuning_parms->tp_lite_sigma_ref_mm; + + + pstatic->algo__crosstalk_compensation_valid_height_mm = 0x01; + pstatic->spare_host_config__static_config_spare_0 = 0x00; + pstatic->spare_host_config__static_config_spare_1 = 0x00; + + pstatic->algo__range_ignore_threshold_mcps = 0x0000; + + + + pstatic->algo__range_ignore_valid_height_mm = 0xff; + pstatic->algo__range_min_clip = + ptuning_parms->tp_lite_min_clip; + + + + + + + pstatic->algo__consistency_check__tolerance = + ptuning_parms->tp_consistency_lite_phase_tolerance; + pstatic->spare_host_config__static_config_spare_2 = 0x00; + pstatic->sd_config__reset_stages_msb = 0x00; + pstatic->sd_config__reset_stages_lsb = 0x00; + + pgeneral->gph_config__stream_count_update_value = 0x00; + pgeneral->global_config__stream_divider = 0x00; + pgeneral->system__interrupt_config_gpio = + VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY; + pgeneral->cal_config__vcsel_start = 0x0B; + + + + + + + + + pgeneral->cal_config__repeat_rate = + ptuning_parms->tp_cal_repeat_rate; + pgeneral->global_config__vcsel_width = 0x02; + + + pgeneral->phasecal_config__timeout_macrop = 0x0D; + + + pgeneral->phasecal_config__target = + ptuning_parms->tp_phasecal_target; + pgeneral->phasecal_config__override = 0x00; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__TARGET_RATE; + + + pgeneral->system__thresh_rate_high = 0x0000; + pgeneral->system__thresh_rate_low = 0x0000; + + + pgeneral->dss_config__manual_effective_spads_select = 0x8C00; + pgeneral->dss_config__manual_block_select = 0x00; + + + + + + + + + pgeneral->dss_config__aperture_attenuation = 0x38; + pgeneral->dss_config__max_spads_limit = 0xFF; + pgeneral->dss_config__min_spads_limit = 0x01; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x1a; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x20; + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0xCC; + + + ptiming->range_config__vcsel_period_a = 0x0B; + + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xF5; + + + ptiming->range_config__vcsel_period_b = 0x09; + + + + + + + + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_med_sigma_thresh_mm; + + + + + + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_med_min_count_rate_rtn_mcps; + + + + + + + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x78; + ptiming->system__intermeasurement_period = 0x00000000; + ptiming->system__fractional_enable = 0x00; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + phistogram->histogram_config__low_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__low_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__low_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__low_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__low_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__low_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__mid_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__mid_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__mid_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__mid_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__mid_amb_odd_bin_2 = 0x02; + phistogram->histogram_config__mid_amb_odd_bin_3_4 = 0x43; + phistogram->histogram_config__mid_amb_odd_bin_5 = 0x05; + + phistogram->histogram_config__user_bin_offset = 0x00; + + phistogram->histogram_config__high_amb_even_bin_0_1 = 0x07; + phistogram->histogram_config__high_amb_even_bin_2_3 = 0x21; + phistogram->histogram_config__high_amb_even_bin_4_5 = 0x43; + + phistogram->histogram_config__high_amb_odd_bin_0_1 = 0x10; + phistogram->histogram_config__high_amb_odd_bin_2_3 = 0x32; + phistogram->histogram_config__high_amb_odd_bin_4_5 = 0x54; + + phistogram->histogram_config__amb_thresh_low = 0xFFFF; + phistogram->histogram_config__amb_thresh_high = 0xFFFF; + + phistogram->histogram_config__spad_array_selection = 0x00; + + + + + + + + + pzone_cfg->max_zones = VL53L1_MAX_USER_ZONES; + pzone_cfg->active_zones = 0x00; + pzone_cfg->user_zones[0].height = 0x0f; + pzone_cfg->user_zones[0].width = 0x0f; + pzone_cfg->user_zones[0].x_centre = 0x08; + pzone_cfg->user_zones[0].y_centre = 0x08; + + + + + pdynamic->system__grouped_parameter_hold_0 = 0x01; + + pdynamic->system__thresh_high = 0x0000; + pdynamic->system__thresh_low = 0x0000; + pdynamic->system__enable_xtalk_per_quadrant = 0x00; + pdynamic->system__seed_config = + ptuning_parms->tp_lite_seed_cfg; + + + + pdynamic->sd_config__woi_sd0 = 0x0B; + + + pdynamic->sd_config__woi_sd1 = 0x09; + + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_med; + + pdynamic->system__grouped_parameter_hold_1 = 0x01; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pdynamic->sd_config__first_order_select = + ptuning_parms->tp_lite_first_order_select; + pdynamic->sd_config__quantifier = + ptuning_parms->tp_lite_quantifier; + + + + + + + pdynamic->roi_config__user_roi_centre_spad = 0xC7; + + + pdynamic->roi_config__user_roi_requested_global_xy_size = 0xFF; + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + pdynamic->system__grouped_parameter_hold = 0x02; + + + + + + psystem->system__stream_count_ctrl = 0x00; + psystem->firmware__enable = 0x01; + psystem->system__interrupt_clear = + VL53L1_CLEAR_RANGE_INT; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_STREAMING | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x07; + ptiming->range_config__vcsel_period_b = 0x05; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_short_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_short_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0x38; + + + + + + + + pdynamic->sd_config__woi_sd0 = 0x07; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_short; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x0F; + ptiming->range_config__vcsel_period_b = 0x0D; + ptiming->range_config__sigma_thresh = + ptuning_parms->tp_lite_long_sigma_thresh_mm; + ptiming->range_config__min_count_rate_rtn_limit_mcps = + ptuning_parms->tp_lite_long_min_count_rate_rtn_mcps; + ptiming->range_config__valid_phase_low = 0x08; + ptiming->range_config__valid_phase_high = 0xB8; + + + + + + + + pdynamic->sd_config__woi_sd0 = 0x0F; + pdynamic->sd_config__woi_sd1 = 0x0D; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_lite_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_lite_long; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_timed_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + + + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x01; + ptiming->range_config__timeout_macrop_a_lo = 0x84; + + + ptiming->range_config__timeout_macrop_b_hi = 0x01; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x97; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xB1; + + ptiming->system__intermeasurement_period = 0x00000600; + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_TIMED; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging_short_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg, + VL53L1_low_power_auto_data_t *plpadata) +{ + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_timed_ranging_long_range( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_config_low_power_auto_mode( + pgeneral, + pdynamic, + plpadata + ); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_singleshot_ranging( + + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pdynamic->system__grouped_parameter_hold = 0x00; + + + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0xB1; + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0xD4; + + pdynamic->system__seed_config = + ptuning_parms->tp_timed_seed_cfg; + + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | + VL53L1_DEVICEREADOUTMODE_SINGLE_SD | + VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0B; + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x20; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1A; + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x28; + + + + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x21; + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_with_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging_with_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm1_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+0, 8+1, 8+2, 8+3, 8+4, 8+5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_mm2_cal( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging_mm1_cal( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_short_timing( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + pstatic->dss_config__target_total_rate_mcps = 0x1400; + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x04; + ptiming->range_config__vcsel_period_b = 0x03; + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x42; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x42; + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x52; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x66; + + pgeneral->cal_config__vcsel_start = 0x04; + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xa4; + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 0, 1, 2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + + 0, 1, 2, 3, 4, 5, + + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x0b; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x1b; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x22; + + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x0B; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_long; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_long; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x88; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + 8+0, 8+1, 8+2, 3, 4, 5, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_long_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 0, 1, 2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x05; + ptiming->range_config__vcsel_period_b = 0x07; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x36; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x28; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x44; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x33; + + + + + pgeneral->cal_config__vcsel_start = 0x05; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x05; + pdynamic->sd_config__woi_sd1 = 0x07; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_med; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_med; + + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x48; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 1, 2, 2, + 8+0, 8+1, 8+2, 1, 2, 3, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_medium_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 0, 1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x03; + ptiming->range_config__vcsel_period_b = 0x05; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x52; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x37; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x66; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x44; + + + + + pgeneral->cal_config__vcsel_start = 0x03; + + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x03; + pdynamic->sd_config__woi_sd1 = 0x05; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + + + + + phistpostprocess->valid_phase_low = 0x08; + phistpostprocess->valid_phase_high = 0x28; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + + + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_special_histogram_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 1, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x02; + ptiming->range_config__vcsel_period_b = 0x03; + + + + + pgeneral->cal_config__vcsel_start = 0x00; + + + + + + pgeneral->phasecal_config__target = 0x31; + + + + + pdynamic->sd_config__woi_sd0 = 0x02; + pdynamic->sd_config__woi_sd1 = 0x03; + pdynamic->sd_config__initial_phase_sd0 = + ptuning_parms->tp_init_phase_rtn_hist_short; + pdynamic->sd_config__initial_phase_sd1 = + ptuning_parms->tp_init_phase_ref_hist_short; + + + + + + + + + phistpostprocess->valid_phase_low = 0x10; + phistpostprocess->valid_phase_high = 0x18; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 7, 0, 1, 1, 1, + 8+0, 8+1, 1, 1, 2, 2, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_short_range_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_preset_mode_histogram_characterisation( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + pstatic->debug__ctrl = 0x01; + psystem->power_management__go1_power_force = 0x01; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_RANGE_EN; + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_SPLIT_MANUAL | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_planar( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_multizone_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_zone_preset_xtalk_planar( + pgeneral, + pzone_cfg); + + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + + VL53L1_init_histogram_config_structure( + 7, 0, 1, 2, 3, 4, + 7, 0, 1, 2, 3, 4, + phistogram); + + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 7, 0, 1, 2, 3, 4, + + 7, 0, 1, 2, 3, 4, + + &(pzone_cfg->multizone_hist_cfg)); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm1( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + + + VL53L1_init_histogram_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + phistogram); + + + + + + + VL53L1_init_histogram_multizone_config_structure( + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + 8+7, 8+0, 8+1, 8+2, 8+3, 8+4, + &(pzone_cfg->multizone_hist_cfg)); + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + + + + + + + ptiming->range_config__vcsel_period_a = 0x09; + ptiming->range_config__vcsel_period_b = 0x09; + + + + + + + ptiming->mm_config__timeout_macrop_a_hi = 0x00; + ptiming->mm_config__timeout_macrop_a_lo = 0x21; + ptiming->mm_config__timeout_macrop_b_hi = 0x00; + ptiming->mm_config__timeout_macrop_b_lo = 0x21; + + + + + ptiming->range_config__timeout_macrop_a_hi = 0x00; + ptiming->range_config__timeout_macrop_a_lo = 0x29; + ptiming->range_config__timeout_macrop_b_hi = 0x00; + ptiming->range_config__timeout_macrop_b_lo = 0x29; + + + + + pgeneral->cal_config__vcsel_start = 0x09; + + + + + + + + + + + + + + pgeneral->phasecal_config__timeout_macrop = 0xF5; + + + + + pdynamic->sd_config__woi_sd0 = 0x09; + pdynamic->sd_config__woi_sd1 = 0x09; + pdynamic->sd_config__initial_phase_sd0 = 0x09; + pdynamic->sd_config__initial_phase_sd1 = 0x06; + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM1_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + + + psystem->system__mode_start = + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM | + VL53L1_DEVICEREADOUTMODE_DUAL_SD | + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_xtalk_mm2( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_xtalk_mm1( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + VL53L1_SEQUENCE_DSS2_EN | + VL53L1_SEQUENCE_MM2_EN | + VL53L1_SEQUENCE_RANGE_EN; + + + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_medium_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_short_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_short_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg) + ); + } + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_preset_mode_histogram_multizone_long_range( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_long_range( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + status = + VL53L1_init_zone_config_structure( + 4, 8, 2, + + 4, 8, 2, + + 7, 7, + + pzone_cfg); + + pgeneral->global_config__stream_divider = + pzone_cfg->active_zones + 1; + + + + + + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_histogram_multizone_initial_bin_config( + pzone_cfg, + phistogram, + &(pzone_cfg->multizone_hist_cfg)); + } + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_preset_mode_olt( + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_preset_mode_standard_ranging( + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) + + + psystem->system__stream_count_ctrl = 0x01; + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_hist_cfg_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic) +{ + + + + + + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(pgeneral); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + pstatic->sd_config__reset_stages_lsb = + phistogram->histogram_config__user_bin_offset; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + pdynamic->system__thresh_high = + phistogram->histogram_config__amb_thresh_low; + + pdynamic->system__thresh_low = + phistogram->histogram_config__amb_thresh_high; + + pdynamic->system__enable_xtalk_per_quadrant = + phistogram->histogram_config__spad_array_selection; + + LOG_FUNCTION_END(0); + +} + +void VL53L1_copy_hist_bins_to_static_cfg( + VL53L1_histogram_config_t *phistogram, + VL53L1_static_config_t *pstatic, + VL53L1_timing_config_t *ptiming) +{ + + + + + + + LOG_FUNCTION_START(""); + + pstatic->sigma_estimator__effective_pulse_width_ns = + phistogram->histogram_config__high_amb_even_bin_0_1; + pstatic->sigma_estimator__effective_ambient_width_ns = + phistogram->histogram_config__high_amb_even_bin_2_3; + pstatic->sigma_estimator__sigma_ref_mm = + phistogram->histogram_config__high_amb_even_bin_4_5; + + pstatic->algo__crosstalk_compensation_valid_height_mm = + phistogram->histogram_config__high_amb_odd_bin_0_1; + + pstatic->spare_host_config__static_config_spare_0 = + phistogram->histogram_config__high_amb_odd_bin_2_3; + pstatic->spare_host_config__static_config_spare_1 = + phistogram->histogram_config__high_amb_odd_bin_4_5; + + pstatic->algo__range_ignore_threshold_mcps = + (((uint16_t)phistogram->histogram_config__mid_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__mid_amb_even_bin_2_3; + + pstatic->algo__range_ignore_valid_height_mm = + phistogram->histogram_config__mid_amb_even_bin_4_5; + pstatic->algo__range_min_clip = + phistogram->histogram_config__mid_amb_odd_bin_0_1; + pstatic->algo__consistency_check__tolerance = + phistogram->histogram_config__mid_amb_odd_bin_2; + + pstatic->spare_host_config__static_config_spare_2 = + phistogram->histogram_config__mid_amb_odd_bin_3_4; + pstatic->sd_config__reset_stages_msb = + phistogram->histogram_config__mid_amb_odd_bin_5; + + ptiming->range_config__sigma_thresh = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_0_1) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_even_bin_2_3; + + ptiming->range_config__min_count_rate_rtn_limit_mcps = + (((uint16_t)phistogram->histogram_config__low_amb_even_bin_4_5) + << 8) + + (uint16_t)phistogram->histogram_config__low_amb_odd_bin_0_1; + + ptiming->range_config__valid_phase_low = + phistogram->histogram_config__low_amb_odd_bin_2_3; + ptiming->range_config__valid_phase_high = + phistogram->histogram_config__low_amb_odd_bin_4_5; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_preset_mode_histogram_ranging_ref( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_static_config_t *pstatic, + VL53L1_histogram_config_t *phistogram, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_system_control_t *psystem, + VL53L1_tuning_parm_storage_t *ptuning_parms, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_preset_mode_histogram_ranging( + phistpostprocess, + pstatic, + phistogram, + pgeneral, + ptiming, + pdynamic, + psystem, + ptuning_parms, + pzone_cfg); + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + phistogram->histogram_config__spad_array_selection = 0x01; + + + + + VL53L1_copy_hist_cfg_to_static_cfg( + phistogram, + pstatic, + pgeneral, + ptiming, + pdynamic); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_api_strings.c b/drivers/oneplus/vl53L1/src/vl53l1_api_strings.c new file mode 100755 index 0000000000000000000000000000000000000000..70266e4418a797756c6e98078cd618dc6f9af2d2 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_api_strings.c @@ -0,0 +1,334 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_api_core.h" +#include "vl53l1_api_strings.h" +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, fmt, \ + ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_range_status_string( + uint8_t RangeStatus, + char *pRangeStatusString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pRangeStatusString, ""); +#else + switch (RangeStatus) { + case 0: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_RANGEVALID); + break; + case 1: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGMA); + break; + case 2: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_SIGNAL); + break; + case 3: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_MINRANGE); + break; + case 4: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_PHASE); + break; + case 5: + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_HW); + break; + + default: + + VL53L1_COPYSTRING(pRangeStatusString, + VL53L1_STRING_RANGESTATUS_NONE); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_get_pal_state_string( + VL53L1_State PalStateCode, + char *pPalStateString) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalStateString, ""); +#else + switch (PalStateCode) { + case VL53L1_STATE_POWERDOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_POWERDOWN); + break; + case VL53L1_STATE_WAIT_STATICINIT: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_WAIT_STATICINIT); + break; + case VL53L1_STATE_STANDBY: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_STANDBY); + break; + case VL53L1_STATE_IDLE: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_IDLE); + break; + case VL53L1_STATE_RUNNING: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RUNNING); + break; + case VL53L1_STATE_RESET: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_RESET); + break; + case VL53L1_STATE_UNKNOWN: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + break; + case VL53L1_STATE_ERROR: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_ERROR); + break; + + default: + VL53L1_COPYSTRING(pPalStateString, + VL53L1_STRING_STATE_UNKNOWN); + } +#endif + + LOG_FUNCTION_END(status); + return status; +} + +VL53L1_Error VL53L1_get_sequence_steps_info( + VL53L1_SequenceStepId SequenceStepId, + char *pSequenceStepsString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pSequenceStepsString, ""); +#else + switch (SequenceStepId) { + case VL53L1_SEQUENCESTEP_VHV: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_VHV); + break; + case VL53L1_SEQUENCESTEP_PHASECAL: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_PHASECAL); + break; + case VL53L1_SEQUENCESTEP_REFPHASE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS1); + break; + case VL53L1_SEQUENCESTEP_DSS2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_DSS2); + break; + case VL53L1_SEQUENCESTEP_MM1: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM1); + break; + case VL53L1_SEQUENCESTEP_MM2: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_MM2); + break; + case VL53L1_SEQUENCESTEP_RANGE: + VL53L1_COPYSTRING(pSequenceStepsString, + VL53L1_STRING_SEQUENCESTEP_RANGE); + break; + default: + Status = VL53L1_ERROR_INVALID_PARAMS; + } +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + +VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId, + char *pLimitCheckString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pLimitCheckString, ""); +#else + switch (LimitCheckId) { + case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE); + break; + case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE); + break; + default: + VL53L1_COPYSTRING(pLimitCheckString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } +#endif + + LOG_FUNCTION_END(Status); + return Status; +} + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_core.c b/drivers/oneplus/vl53L1/src/vl53l1_core.c new file mode 100755 index 0000000000000000000000000000000000000000..6d1fa6c3117fd8e557e30409b9b43a648d5041aa --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_core.c @@ -0,0 +1,5888 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_funcs.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_structs.h" +#include "vl53l1_api_preset_modes.h" +#include "vl53l1_core.h" +#include "vl53l1_tuning_parm_defaults.h" + + + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +void VL53L1_init_version( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->version.ll_major = VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR; + pdev->version.ll_minor = VL53L1_LL_API_IMPLEMENTATION_VER_MINOR; + pdev->version.ll_build = VL53L1_LL_API_IMPLEMENTATION_VER_SUB; + pdev->version.ll_revision = VL53L1_LL_API_IMPLEMENTATION_VER_REVISION; +} + + +void VL53L1_init_ll_driver_state( + VL53L1_DEV Dev, + VL53L1_DeviceState device_state) +{ + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + pstate->cfg_device_state = device_state; + pstate->cfg_stream_count = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + + pstate->rd_device_state = device_state; + pstate->rd_stream_count = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + +} + + +VL53L1_Error VL53L1_update_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + + + + + LOG_FUNCTION_START(""); + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + } else { + + + + + + + if (pstate->rd_stream_count == 0xFF) + pstate->rd_stream_count = 0x80; + else + pstate->rd_stream_count++; + + + + + + status = VL53L1_update_internal_stream_counters(Dev, + pstate->rd_stream_count, + &(pstate->rd_internal_stream_count), + &(pstate->rd_internal_stream_count_val)); + + + + + + + pstate->rd_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + + switch (pstate->rd_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + + if ((pdev->dyn_cfg.system__grouped_parameter_hold & + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK) > 0) { + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC; + } else { + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + } + + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + + break; + + case VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC: + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_zone_id = 0; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_GATHER_DATA: + pstate->rd_zone_id++; + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + + break; + + case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA: + pstate->rd_zone_id = 0; + pstate->rd_timing_status ^= 0x01; + + if (pstate->rd_zone_id >= + pdev->zone_cfg.active_zones) + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA; + else + pstate->rd_device_state = + VL53L1_DEVICESTATE_RANGING_GATHER_DATA; + break; + + default: + pstate->rd_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->rd_stream_count = 0; + pstate->rd_internal_stream_count = 0; + pstate->rd_internal_stream_count_val = 0; + pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->rd_timing_status = 0; + pstate->rd_zone_id = 0; + break; + } + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_check_ll_driver_rd_state( + VL53L1_DEV Dev) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_system_results_t *psys_results = &(pdev->sys_results); + VL53L1_histogram_bin_data_t *phist_data = &(pdev->hist_data); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t device_range_status = 0; + uint8_t device_stream_count = 0; + uint8_t device_gph_id = 0; + uint8_t histogram_mode = 0; + uint8_t expected_stream_count = 0; + uint8_t expected_gph_id = 0; + + LOG_FUNCTION_START(""); + + + + + + device_range_status = + psys_results->result__range_status & + VL53L1_RANGE_STATUS__RANGE_STATUS_MASK; + + device_stream_count = psys_results->result__stream_count; + + + + + histogram_mode = + (pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM) == + VL53L1_DEVICESCHEDULERMODE_HISTOGRAM; + + + + device_gph_id = (psys_results->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + if (histogram_mode) + device_gph_id = (phist_data->result__interrupt_status & + VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4; + + + + + if (!((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) == + VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK)) + goto ENDFUNC; + + + + + + + + + + + + + + + if (pstate->rd_device_state == + VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) { + + if (histogram_mode == 0) { + if (device_range_status != + VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY) + status = + VL53L1_ERROR_GPH_SYNC_CHECK_FAIL; + + } + } else { + if (pstate->rd_stream_count != device_stream_count) + status = VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL; + + + + + + if (pstate->rd_gph_id != device_gph_id) + status = VL53L1_ERROR_GPH_ID_CHECK_FAIL; + + + + + + + + + + + + + + + + + + + + + + expected_stream_count = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_stream_count; + expected_gph_id = + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id; + + + + + + + if (expected_stream_count != device_stream_count) { + + + + + + if (!((pdev->zone_cfg.active_zones == 0) && + (device_stream_count == 255))) + status = + VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL; + + + + + + + + + + + + + + + + + + + } + + + + + + + if (expected_gph_id != device_gph_id) + status = VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL; + + + + + + + + + + + } + + + + + + + + + + + + + + +ENDFUNC: + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_update_ll_driver_cfg_state( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t prev_cfg_zone_id; + uint8_t prev_cfg_gph_id; + uint8_t prev_cfg_stream_count; + + LOG_FUNCTION_START(""); + + + + + + + + + if ((pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) { + + pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + prev_cfg_zone_id = 0; + prev_cfg_gph_id = 0; + prev_cfg_stream_count = 0; + + } else { + + + + + prev_cfg_gph_id = pstate->cfg_gph_id; + prev_cfg_zone_id = pstate->cfg_zone_id; + prev_cfg_stream_count = pstate->cfg_stream_count; + + + + + + + if (pstate->cfg_stream_count == 0xFF) + pstate->cfg_stream_count = 0x80; + else + pstate->cfg_stream_count++; + + + + + + status = VL53L1_update_internal_stream_counters( + Dev, + pstate->cfg_stream_count, + &(pstate->cfg_internal_stream_count), + &(pstate->cfg_internal_stream_count_val)); + + + + + + + pstate->cfg_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + + + + + + + switch (pstate->cfg_device_state) { + + case VL53L1_DEVICESTATE_SW_STANDBY: + pstate->cfg_zone_id = 1; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + pstate->cfg_stream_count = 1; + + if (pdev->gen_cfg.global_config__stream_divider == 0) { + pstate->cfg_internal_stream_count = 1; + pstate->cfg_internal_stream_count_val = 0; + } else { + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 1; + } + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_AUTO; + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_AUTO: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + + + + + + + if (pdev->zone_cfg.active_zones > 0) { + pstate->cfg_device_state = + VL53L1_DEVICESTATE_RANGING_DSS_MANUAL; + } + } + break; + + case VL53L1_DEVICESTATE_RANGING_DSS_MANUAL: + pstate->cfg_zone_id++; + if (pstate->cfg_zone_id > + pdev->zone_cfg.active_zones) { + pstate->cfg_zone_id = 0; + pstate->cfg_timing_status ^= 0x01; + } + break; + + default: + pstate->cfg_device_state = + VL53L1_DEVICESTATE_SW_STANDBY; + pstate->cfg_stream_count = 0; + pstate->cfg_internal_stream_count = 0; + pstate->cfg_internal_stream_count_val = 0; + pstate->cfg_gph_id = + VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + pstate->cfg_timing_status = 0; + pstate->cfg_zone_id = 0; + break; + } + } + + + + + + if (pdev->zone_cfg.active_zones == 0) { + + + + + + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count - 1; + + pZ->VL53L1_p_002[pstate->rd_zone_id].expected_gph_id = + prev_cfg_gph_id ^ VL53L1_GROUPEDPARAMETERHOLD_ID_MASK; + } else { + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_stream_count + = prev_cfg_stream_count; + pZ->VL53L1_p_002[prev_cfg_zone_id].expected_gph_id = + prev_cfg_gph_id; + } + + + + + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_copy_rtn_good_spads_to_buffer( + VL53L1_nvm_copy_data_t *pdata, + uint8_t *pbuffer) +{ + + + + + + *(pbuffer + 0) = pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 1) = pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 2) = pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 3) = pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 4) = pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 5) = pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 6) = pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 7) = pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 8) = pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 9) = pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 10) = pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 11) = pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 12) = pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 13) = pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 14) = pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 15) = pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 16) = pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 17) = pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 18) = pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 19) = pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 20) = pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 21) = pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 22) = pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 23) = pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 24) = pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 25) = pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 26) = pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 27) = pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 28) = pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 29) = pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 30) = pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 31) = pdata->global_config__spad_enables_rtn_31; +} + + +void VL53L1_init_system_results( + VL53L1_system_results_t *pdata) +{ + + + + + + + pdata->result__interrupt_status = 0xFF; + pdata->result__range_status = 0xFF; + pdata->result__report_status = 0xFF; + pdata->result__stream_count = 0xFF; + + pdata->result__dss_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd0 = 0xFFFF; + pdata->result__sigma_sd0 = 0xFFFF; + pdata->result__phase_sd0 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd0 = 0xFFFF; + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + 0xFFFF; + pdata->result__mm_inner_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__mm_outer_actual_effective_spads_sd0 = 0xFFFF; + pdata->result__avg_signal_count_rate_mcps_sd0 = 0xFFFF; + + pdata->result__dss_actual_effective_spads_sd1 = 0xFFFF; + pdata->result__peak_signal_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__ambient_count_rate_mcps_sd1 = 0xFFFF; + pdata->result__sigma_sd1 = 0xFFFF; + pdata->result__phase_sd1 = 0xFFFF; + pdata->result__final_crosstalk_corrected_range_mm_sd1 = 0xFFFF; + pdata->result__spare_0_sd1 = 0xFFFF; + pdata->result__spare_1_sd1 = 0xFFFF; + pdata->result__spare_2_sd1 = 0xFFFF; + pdata->result__spare_3_sd1 = 0xFF; + +} + + +void V53L1_init_zone_results_structure( + uint8_t active_zones, + VL53L1_zone_results_t *pdata) +{ + + + + + uint8_t z = 0; + VL53L1_zone_objects_t *pobjects; + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + pdata->active_zones = active_zones; + + for (z = 0; z < pdata->max_zones; z++) { + pobjects = &(pdata->VL53L1_p_002[z]); + pobjects->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pobjects->max_objects = VL53L1_MAX_RANGE_RESULTS; + pobjects->active_objects = 0; + } +} + +void V53L1_init_zone_dss_configs( + VL53L1_DEV Dev) +{ + + + + + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + uint8_t z = 0; + uint8_t max_zones = VL53L1_MAX_USER_ZONES; + VL53L1_zone_private_dyn_cfgs_t *pdata = &(pres->zone_dyn_cfgs); + + for (z = 0; z < max_zones; z++) { + pdata->VL53L1_p_002[z].dss_mode = + VL53L1_DSS_CONTROL__MODE_TARGET_RATE; + pdata->VL53L1_p_002[z].dss_requested_effective_spad_count = 0; + } +} + + +void VL53L1_init_histogram_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + + + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__low_amb_odd_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__low_amb_odd_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__high_amb_even_bin_2_3 = + pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__high_amb_even_bin_4_5 = + pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__high_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 = + pdata->histogram_config__low_amb_odd_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 = + pdata->histogram_config__low_amb_odd_bin_4_5; + + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + + pdata->histogram_config__spad_array_selection = 0x00; + +} + +void VL53L1_init_histogram_multizone_config_structure( + uint8_t even_bin0, + uint8_t even_bin1, + uint8_t even_bin2, + uint8_t even_bin3, + uint8_t even_bin4, + uint8_t even_bin5, + uint8_t odd_bin0, + uint8_t odd_bin1, + uint8_t odd_bin2, + uint8_t odd_bin3, + uint8_t odd_bin4, + uint8_t odd_bin5, + VL53L1_histogram_config_t *pdata) +{ + + + + + + + + pdata->histogram_config__low_amb_even_bin_0_1 = + (even_bin1 << 4) + even_bin0; + pdata->histogram_config__low_amb_even_bin_2_3 = + (even_bin3 << 4) + even_bin2; + pdata->histogram_config__low_amb_even_bin_4_5 = + (even_bin5 << 4) + even_bin4; + + pdata->histogram_config__low_amb_odd_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__low_amb_odd_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__low_amb_odd_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_even_bin_0_1 = + pdata->histogram_config__low_amb_even_bin_0_1; + pdata->histogram_config__mid_amb_even_bin_2_3 + = pdata->histogram_config__low_amb_even_bin_2_3; + pdata->histogram_config__mid_amb_even_bin_4_5 + = pdata->histogram_config__low_amb_even_bin_4_5; + + pdata->histogram_config__mid_amb_odd_bin_0_1 + = pdata->histogram_config__low_amb_odd_bin_0_1; + pdata->histogram_config__mid_amb_odd_bin_2 = odd_bin2; + pdata->histogram_config__mid_amb_odd_bin_3_4 = + (odd_bin4 << 4) + odd_bin3; + pdata->histogram_config__mid_amb_odd_bin_5 = odd_bin5; + + pdata->histogram_config__user_bin_offset = 0x00; + + pdata->histogram_config__high_amb_even_bin_0_1 = + (odd_bin1 << 4) + odd_bin0; + pdata->histogram_config__high_amb_even_bin_2_3 = + (odd_bin3 << 4) + odd_bin2; + pdata->histogram_config__high_amb_even_bin_4_5 = + (odd_bin5 << 4) + odd_bin4; + + pdata->histogram_config__high_amb_odd_bin_0_1 + = pdata->histogram_config__high_amb_even_bin_0_1; + pdata->histogram_config__high_amb_odd_bin_2_3 + = pdata->histogram_config__high_amb_even_bin_2_3; + pdata->histogram_config__high_amb_odd_bin_4_5 + = pdata->histogram_config__high_amb_even_bin_4_5; + + + + + pdata->histogram_config__amb_thresh_low = 0xFFFF; + pdata->histogram_config__amb_thresh_high = 0xFFFF; + + + + + pdata->histogram_config__spad_array_selection = 0x00; +} + + +void VL53L1_init_xtalk_bin_data_struct( + uint32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_xtalk_histogram_shape_t *pdata) +{ + + + + + + + uint16_t i = 0; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_019 = 0; + + pdata->zero_distance_phase = 0; + + for (i = 0; i < VL53L1_XTALK_HISTO_BINS; i++) { + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + } +} + + +void VL53L1_i2c_encode_uint16_t( + uint16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + uint16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint16_t VL53L1_i2c_decode_uint16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint16_t)*pbuffer++; + + return value; +} + + +void VL53L1_i2c_encode_int16_t( + int16_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + int16_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int16_t VL53L1_i2c_decode_int16_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + int16_t value = 0x00; + + + + if (*pbuffer >= 0x80) + value = 0xFFFF; + + while (count-- > 0) + value = (value << 8) | (int16_t)*pbuffer++; + + return value; +} + +void VL53L1_i2c_encode_uint32_t( + uint32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +uint32_t VL53L1_i2c_decode_uint32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint32_t value = 0x00; + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + return value; +} + + +uint32_t VL53L1_i2c_decode_with_mask( + uint16_t count, + uint8_t *pbuffer, + uint32_t bit_mask, + uint32_t down_shift, + uint32_t offset) +{ + + + + + + + uint32_t value = 0x00; + + + + while (count-- > 0) + value = (value << 8) | (uint32_t)*pbuffer++; + + + + value = value & bit_mask; + if (down_shift > 0) + value = value >> down_shift; + + + + value = value + offset; + + return value; +} + + +void VL53L1_i2c_encode_int32_t( + int32_t ip_value, + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + uint16_t i = 0; + int32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + + for (i = 0; i < count; i++) { + pbuffer[count-i-1] = (uint8_t)(VL53L1_p_002 & 0x00FF); + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + +int32_t VL53L1_i2c_decode_int32_t( + uint16_t count, + uint8_t *pbuffer) +{ + + + + + + + int32_t value = 0x00; + + + + if (*pbuffer >= 0x80) + value = 0xFFFFFFFF; + + while (count-- > 0) + value = (value << 8) | (int32_t)*pbuffer++; + + return value; +} + + +VL53L1_Error VL53L1_start_test( + VL53L1_DEV Dev, + uint8_t test_mode__ctrl) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) { + + status = VL53L1_WrByte( + Dev, + VL53L1_TEST_MODE__CTRL, + test_mode__ctrl); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_firmware_enable_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.firmware__enable = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_FIRMWARE__ENABLE, + pdev->sys_ctrl.firmware__enable); + + return status; +} + +VL53L1_Error VL53L1_enable_firmware( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_firmware( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_firmware_enable_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_powerforce_register( + VL53L1_DEV Dev, + uint8_t value) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + pdev->sys_ctrl.power_management__go1_power_force = value; + + status = VL53L1_WrByte( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + pdev->sys_ctrl.power_management__go1_power_force); + + return status; +} + + +VL53L1_Error VL53L1_enable_powerforce( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x01); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_powerforce( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_powerforce_register(Dev, 0x00); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_clear_interrupt( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->sys_ctrl.system__interrupt_clear = VL53L1_CLEAR_RANGE_INT; + + status = VL53L1_WrByte( + Dev, + VL53L1_SYSTEM__INTERRUPT_CLEAR, + pdev->sys_ctrl.system__interrupt_clear); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_force_shadow_stream_count_to_zero( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_SHADOW_RESULT__STREAM_COUNT, + 0x00); + } + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + return status; +} + + +uint32_t VL53L1_calc_macro_period_us( + uint16_t fast_osc_frequency, + uint8_t VL53L1_p_009) +{ + + + + + + + + + uint32_t pll_period_us = 0; + uint8_t VL53L1_p_031 = 0; + uint32_t macro_period_us = 0; + + LOG_FUNCTION_START(""); + + + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + VL53L1_p_031 = VL53L1_decode_vcsel_period(VL53L1_p_009); + + + + + + + + + + + + + + + macro_period_us = + (uint32_t)VL53L1_MACRO_PERIOD_VCSEL_PERIODS * + pll_period_us; + macro_period_us = macro_period_us >> 6; + + macro_period_us = macro_period_us * (uint32_t)VL53L1_p_031; + macro_period_us = macro_period_us >> 6; + + + + + + + + + + + + + + LOG_FUNCTION_END(0); + + return macro_period_us; +} + + +uint16_t VL53L1_calc_range_ignore_threshold( + uint32_t central_rate, + int16_t x_gradient, + int16_t y_gradient, + uint8_t rate_mult) +{ + + + + + + + + + + + + + + + + int32_t range_ignore_thresh_int = 0; + uint16_t range_ignore_thresh_kcps = 0; + int32_t central_rate_int = 0; + int16_t x_gradient_int = 0; + int16_t y_gradient_int = 0; + + LOG_FUNCTION_START(""); + + + + + central_rate_int = ((int32_t)central_rate * (1 << 4)) / (1000); + + if (x_gradient < 0) + x_gradient_int = x_gradient * -1; + + if (y_gradient < 0) + y_gradient_int = y_gradient * -1; + + + + + + + + + range_ignore_thresh_int = (8 * x_gradient_int * 4) + + (8 * y_gradient_int * 4); + + + + + range_ignore_thresh_int = range_ignore_thresh_int / 1000; + + + + + range_ignore_thresh_int = range_ignore_thresh_int + central_rate_int; + + + + + range_ignore_thresh_int = (int32_t)rate_mult * range_ignore_thresh_int; + + range_ignore_thresh_int = (range_ignore_thresh_int + (1<<4)) / (1<<5); + + + + + if (range_ignore_thresh_int > 0xFFFF) + range_ignore_thresh_kcps = 0xFFFF; + else + range_ignore_thresh_kcps = (uint16_t)range_ignore_thresh_int; + + + + + + + + LOG_FUNCTION_END(0); + + return range_ignore_thresh_kcps; +} + + +uint32_t VL53L1_calc_timeout_mclks( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + ((timeout_us << 12) + (macro_period_us>>1)) / + macro_period_us; + + LOG_FUNCTION_END(0); + + return timeout_mclks; +} + + +uint16_t VL53L1_calc_encoded_timeout( + uint32_t timeout_us, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_calc_timeout_mclks(timeout_us, macro_period_us); + + timeout_encoded = + VL53L1_encode_timeout(timeout_mclks); + + + + + + + + + + + LOG_FUNCTION_END(0); + + return timeout_encoded; +} + + +uint32_t VL53L1_calc_timeout_us( + uint32_t timeout_mclks, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_us = 0; + uint64_t tmp = 0; + + LOG_FUNCTION_START(""); + + tmp = (uint64_t)timeout_mclks * (uint64_t)macro_period_us; + tmp += 0x00800; + tmp = tmp >> 12; + + timeout_us = (uint32_t)tmp; + + + + + + + + + + + + LOG_FUNCTION_END(0); + + return timeout_us; +} + +uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin( + uint32_t plane_offset_kcps, + int16_t margin_offset_kcps) +{ + uint32_t plane_offset_with_margin = 0; + int32_t plane_offset_kcps_temp = 0; + + LOG_FUNCTION_START(""); + + plane_offset_kcps_temp = + (int32_t)plane_offset_kcps + + (int32_t)margin_offset_kcps; + + if (plane_offset_kcps_temp < 0) + plane_offset_kcps_temp = 0; + else + if (plane_offset_kcps_temp > 0x3FFFF) + plane_offset_kcps_temp = 0x3FFFF; + + plane_offset_with_margin = (uint32_t) plane_offset_kcps_temp; + + LOG_FUNCTION_END(0); + + return plane_offset_with_margin; + +} + +uint32_t VL53L1_calc_decoded_timeout_us( + uint16_t timeout_encoded, + uint32_t macro_period_us) +{ + + + + + + + + + + + uint32_t timeout_mclks = 0; + uint32_t timeout_us = 0; + + LOG_FUNCTION_START(""); + + timeout_mclks = + VL53L1_decode_timeout(timeout_encoded); + + timeout_us = + VL53L1_calc_timeout_us(timeout_mclks, macro_period_us); + + LOG_FUNCTION_END(0); + + return timeout_us; +} + + +uint16_t VL53L1_encode_timeout(uint32_t timeout_mclks) +{ + + + + + + uint16_t encoded_timeout = 0; + uint32_t ls_byte = 0; + uint16_t ms_byte = 0; + + if (timeout_mclks > 0) { + ls_byte = timeout_mclks - 1; + + while ((ls_byte & 0xFFFFFF00) > 0) { + ls_byte = ls_byte >> 1; + ms_byte++; + } + + encoded_timeout = (ms_byte << 8) + + (uint16_t) (ls_byte & 0x000000FF); + } + + return encoded_timeout; +} + + +uint32_t VL53L1_decode_timeout(uint16_t encoded_timeout) +{ + + + + + + + uint32_t timeout_macro_clks = 0; + + timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) + << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; + + return timeout_macro_clks; +} + + +VL53L1_Error VL53L1_calc_timeout_register_values( + uint32_t phasecal_config_timeout_us, + uint32_t mm_config_timeout_us, + uint32_t range_config_timeout_us, + uint16_t fast_osc_frequency, + VL53L1_general_config_t *pgeneral, + VL53L1_timing_config_t *ptiming) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + if (fast_osc_frequency == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_a); + + + + timeout_mclks = + VL53L1_calc_timeout_mclks( + phasecal_config_timeout_us, + macro_period_us); + + + + if (timeout_mclks > 0xFF) + timeout_mclks = 0xFF; + + pgeneral->phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_a_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_a_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + ptiming->range_config__vcsel_period_b); + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + mm_config_timeout_us, + macro_period_us); + + ptiming->mm_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->mm_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + + + + timeout_encoded = VL53L1_calc_encoded_timeout( + range_config_timeout_us, + macro_period_us); + + ptiming->range_config__timeout_macrop_b_hi = + (uint8_t)((timeout_encoded & 0xFF00) >> 8); + ptiming->range_config__timeout_macrop_b_lo = + (uint8_t) (timeout_encoded & 0x00FF); + } + + LOG_FUNCTION_END(0); + + return status; + +} + + +uint8_t VL53L1_encode_vcsel_period(uint8_t VL53L1_p_031) +{ + + + + + + + uint8_t vcsel_period_reg = 0; + + vcsel_period_reg = (VL53L1_p_031 >> 1) - 1; + + return vcsel_period_reg; +} + + +uint32_t VL53L1_decode_unsigned_integer( + uint8_t *pbuffer, + uint8_t no_of_bytes) +{ + + + + + + uint8_t i = 0; + uint32_t decoded_value = 0; + + for (i = 0; i < no_of_bytes; i++) + decoded_value = (decoded_value << 8) + (uint32_t)pbuffer[i]; + + return decoded_value; +} + + +void VL53L1_encode_unsigned_integer( + uint32_t ip_value, + uint8_t no_of_bytes, + uint8_t *pbuffer) +{ + + + + + + uint8_t i = 0; + uint32_t VL53L1_p_002 = 0; + + VL53L1_p_002 = ip_value; + for (i = 0; i < no_of_bytes; i++) { + pbuffer[no_of_bytes-i-1] = VL53L1_p_002 & 0x00FF; + VL53L1_p_002 = VL53L1_p_002 >> 8; + } +} + + +VL53L1_Error VL53L1_hist_copy_and_scale_ambient_info( + VL53L1_zone_hist_info_t *pidata, + VL53L1_histogram_bin_data_t *podata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t VL53L1_p_008 = 0; + int64_t tmpi = 0; + int64_t tmpo = 0; + + LOG_FUNCTION_START(""); + + + if (pidata->result__dss_actual_effective_spads == 0) { + status = VL53L1_ERROR_DIVISION_BY_ZERO; + } else { + if (pidata->number_of_ambient_bins > 0 && + podata->number_of_ambient_bins == 0) { + + + + + + + + + + + tmpo = 1 + (int64_t)podata->total_periods_elapsed; + tmpo *= + (int64_t)podata->result__dss_actual_effective_spads; + + tmpi = 1 + (int64_t)pidata->total_periods_elapsed; + tmpi *= + (int64_t)pidata->result__dss_actual_effective_spads; + + VL53L1_p_008 = tmpo * + (int64_t)pidata->ambient_events_sum; + VL53L1_p_008 += (tmpi/2); + + + + + VL53L1_p_008 = do_division_s(VL53L1_p_008, tmpi); + + podata->ambient_events_sum = (int32_t)VL53L1_p_008; + + + + + + + podata->VL53L1_p_004 = + podata->ambient_events_sum; + podata->VL53L1_p_004 += + ((int32_t)pidata->number_of_ambient_bins / 2); + podata->VL53L1_p_004 /= + (int32_t)pidata->number_of_ambient_bins; + } + } + + LOG_FUNCTION_END(0); + + return status; +} + + +void VL53L1_hist_get_bin_sequence_config( + VL53L1_DEV Dev, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t amb_thresh_low = 0; + int32_t amb_thresh_high = 0; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + amb_thresh_low = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_low; + amb_thresh_high = 1024 * + (int32_t)pdev->hist_cfg.histogram_config__amb_thresh_high; + + + + + + + + + + + if ((pdev->ll_state.rd_stream_count & 0x01) == 0) { + + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_4_5 & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_2_3 & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_even_bin_0_1 & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_even_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_even_bin_0_1 + & 0x0F; + } + + } else { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_5 + & 0x0F; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_3_4 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_2 & + 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__mid_amb_odd_bin_0_1 + & 0x0F; + + if (pdata->ambient_events_sum > amb_thresh_high) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__high_amb_odd_bin_0_1 + & 0x0F; + } + + if (pdata->ambient_events_sum < amb_thresh_low) { + pdata->bin_seq[5] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + >> 4; + pdata->bin_seq[4] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_4_5 + & 0x0F; + pdata->bin_seq[3] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + >> 4; + pdata->bin_seq[2] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_2_3 + & 0x0F; + pdata->bin_seq[1] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + >> 4; + pdata->bin_seq[0] = + pdev->hist_cfg.histogram_config__low_amb_odd_bin_0_1 + & 0x0F; + } + } + + + + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_hist_phase_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_results_t *prange_curr) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t lc = 0; + uint8_t p = 0; + + uint16_t phase_delta = 0; + uint16_t phase_tolerance = 0; + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + + + + uint8_t event_sigma; + uint16_t event_min_spad_count; + uint16_t min_max_tolerance; + uint8_t pht; + + VL53L1_DeviceError range_status = 0; + + LOG_FUNCTION_START(""); + + event_sigma = + pdev->histpostprocess.algo__consistency_check__event_sigma; + event_min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + min_max_tolerance = + pdev->histpostprocess.algo__consistency_check__min_max_tolerance; + + + + pht = pdev->histpostprocess.algo__consistency_check__phase_tolerance; + phase_tolerance = (uint16_t)pht; + phase_tolerance = phase_tolerance << 8; + + + + + if (prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_GATHER_DATA && + prange_prev->rd_device_state != + VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA) + return status; + + + + + if (phase_tolerance == 0) + return status; + + for (lc = 0; lc < prange_curr->active_results; lc++) { + + if (!((prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) || + (prange_curr->VL53L1_p_002[lc].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK))) + continue; + + + + + + + + + if (prange_prev->active_objects == 0) + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PREV_RANGE_NO_TARGETS; + else + prange_curr->VL53L1_p_002[lc].range_status = + VL53L1_DEVICEERROR_PHASECONSISTENCY; + + + + + + + + + + + for (p = 0; p < prange_prev->active_objects; p++) { + + if (prange_curr->VL53L1_p_002[lc].VL53L1_p_014 > + prange_prev->VL53L1_p_002[p].VL53L1_p_014) { + phase_delta = + prange_curr->VL53L1_p_002[lc].VL53L1_p_014 - + prange_prev->VL53L1_p_002[p].VL53L1_p_014; + } else { + phase_delta = + prange_prev->VL53L1_p_002[p].VL53L1_p_014 - + prange_curr->VL53L1_p_002[lc].VL53L1_p_014; + } + + if (phase_delta < phase_tolerance) { + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_hist_events_consistency_check( + event_sigma, + event_min_spad_count, + phist_prev, + &(prange_prev->VL53L1_p_002[p]), + &(prange_curr->VL53L1_p_002[lc]), + &events_tolerance, + &events_delta, + &range_status); + + + + + + + + + + if (status == VL53L1_ERROR_NONE && + range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) + status = + VL53L1_hist_merged_pulse_check( + min_max_tolerance, + &(prange_curr->VL53L1_p_002[lc]), + &range_status); + + prange_curr->VL53L1_p_002[lc].range_status = + range_status; + } + } + + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_hist_events_consistency_check( + uint8_t event_sigma, + uint16_t min_effective_spad_count, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_object_data_t *prange_prev, + VL53L1_range_data_t *prange_curr, + int32_t *pevents_tolerance, + int32_t *pevents_delta, + VL53L1_DeviceError *prange_status) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int64_t tmpp = 0; + int64_t tmpc = 0; + int64_t events_scaler = 0; + int64_t events_scaler_sq = 0; + int64_t c_signal_events = 0; + int64_t c_sig_noise_sq = 0; + int64_t c_amb_noise_sq = 0; + int64_t p_amb_noise_sq = 0; + + int32_t p_signal_events = 0; + uint32_t noise_sq_sum = 0; + + + + + if (event_sigma == 0) { + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + return status; + } + + + + + tmpp = 1 + (int64_t)phist_prev->total_periods_elapsed; + tmpp *= (int64_t)phist_prev->result__dss_actual_effective_spads; + + + + + tmpc = 1 + (int64_t)prange_curr->total_periods_elapsed; + tmpc *= (int64_t)prange_curr->VL53L1_p_006; + + + + + events_scaler = tmpp * 4096; + events_scaler += (tmpc/2); + events_scaler = do_division_s(events_scaler, tmpc); + + events_scaler_sq = events_scaler * events_scaler; + events_scaler_sq += 2048; + events_scaler_sq /= 4096; + + + + + c_signal_events = (int64_t)prange_curr->VL53L1_p_021; + c_signal_events -= (int64_t)prange_curr->VL53L1_p_020; + c_signal_events *= (int64_t)events_scaler; + c_signal_events += 2048; + c_signal_events /= 4096; + + c_sig_noise_sq = (int64_t)events_scaler_sq; + c_sig_noise_sq *= (int64_t)prange_curr->VL53L1_p_021; + c_sig_noise_sq += 2048; + c_sig_noise_sq /= 4096; + + c_amb_noise_sq = (int64_t)events_scaler_sq; + c_amb_noise_sq *= (int64_t)prange_curr->VL53L1_p_020; + c_amb_noise_sq += 2048; + c_amb_noise_sq /= 4096; + + + + c_amb_noise_sq += 2; + c_amb_noise_sq /= 4; + + + + + + + + p_amb_noise_sq = + (int64_t)prange_prev->VL53L1_p_020; + + + + p_amb_noise_sq += 2; + p_amb_noise_sq /= 4; + + noise_sq_sum = + (uint32_t)prange_prev->VL53L1_p_021 + + (uint32_t)c_sig_noise_sq + + (uint32_t)p_amb_noise_sq + + (uint32_t)c_amb_noise_sq; + + *pevents_tolerance = + (int32_t)VL53L1_isqrt(noise_sq_sum * 16); + + *pevents_tolerance *= (int32_t)event_sigma; + *pevents_tolerance += 32; + *pevents_tolerance /= 64; + + p_signal_events = (int32_t)prange_prev->VL53L1_p_021; + p_signal_events -= (int32_t)prange_prev->VL53L1_p_020; + + if ((int32_t)c_signal_events > p_signal_events) + *pevents_delta = + (int32_t)c_signal_events - p_signal_events; + else + *pevents_delta = + p_signal_events - (int32_t)c_signal_events; + + if (*pevents_delta > *pevents_tolerance && + prange_curr->VL53L1_p_006 > min_effective_spad_count) + *prange_status = VL53L1_DEVICEERROR_EVENTCONSISTENCY; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_merged_pulse_check( + int16_t min_max_tolerance_mm, + VL53L1_range_data_t *pdata, + VL53L1_DeviceError *prange_status) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int16_t delta_mm = 0; + + if (pdata->max_range_mm > pdata->min_range_mm) + delta_mm = + pdata->max_range_mm - pdata->min_range_mm; + else + delta_mm = + pdata->min_range_mm - pdata->max_range_mm; + + if (min_max_tolerance_mm > 0 && + delta_mm > min_max_tolerance_mm) + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE_MERGED_PULSE; + else + *prange_status = VL53L1_DEVICEERROR_RANGECOMPLETE; + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_xmonitor_consistency_check( + VL53L1_DEV Dev, + VL53L1_zone_hist_info_t *phist_prev, + VL53L1_zone_objects_t *prange_prev, + VL53L1_range_data_t *prange_curr) +{ + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + int32_t events_delta = 0; + int32_t events_tolerance = 0; + uint8_t event_sigma; + uint16_t min_spad_count; + + event_sigma = pdev->histpostprocess.algo__crosstalk_detect_event_sigma; + min_spad_count = + pdev->histpostprocess.algo__consistency_check__event_min_spad_count; + + if (prange_curr->range_status == VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_curr->range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_curr->range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + if (prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE_NO_WRAP_CHECK || + prange_prev->xmonitor.range_status == + VL53L1_DEVICEERROR_EVENTCONSISTENCY) { + + prange_curr->range_status = + VL53L1_DEVICEERROR_RANGECOMPLETE; + + status = + VL53L1_hist_events_consistency_check( + event_sigma, + min_spad_count, + phist_prev, + &(prange_prev->xmonitor), + prange_curr, + &events_tolerance, + &events_delta, + &(prange_curr->range_status)); + + } + } + + return status; +} + + + + + +VL53L1_Error VL53L1_hist_wrap_dmax( + VL53L1_hist_post_process_config_t *phistpostprocess, + VL53L1_histogram_bin_data_t *pcurrent, + int16_t *pwrap_dmax_mm) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t pll_period_mm = 0; + uint32_t wrap_dmax_phase = 0; + uint32_t range_mm = 0; + + LOG_FUNCTION_START(""); + + *pwrap_dmax_mm = 0; + + + if (pcurrent->VL53L1_p_019 != 0) { + + + + + pll_period_mm = + VL53L1_calc_pll_period_mm( + pcurrent->VL53L1_p_019); + + + + + wrap_dmax_phase = + (uint32_t)phistpostprocess->valid_phase_high << 8; + + + + + + range_mm = wrap_dmax_phase * pll_period_mm; + range_mm = (range_mm + (1<<14)) >> 15; + + *pwrap_dmax_mm = (int16_t)range_mm; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +void VL53L1_hist_combine_mm1_mm2_offsets( + int16_t mm1_offset_mm, + int16_t mm2_offset_mm, + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + VL53L1_additional_offset_cal_data_t *pcal_data, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + int16_t *prange_offset_mm) +{ + + + + + + + + + + + + + + + + uint16_t max_mm_inner_effective_spads = 0; + uint16_t max_mm_outer_effective_spads = 0; + uint16_t mm_inner_effective_spads = 0; + uint16_t mm_outer_effective_spads = 0; + + uint32_t scaled_mm1_peak_rate_mcps = 0; + uint32_t scaled_mm2_peak_rate_mcps = 0; + + int32_t tmp0 = 0; + int32_t tmp1 = 0; + + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + 0xC7, + + 0xFF, + pgood_spads, + aperture_attenuation, + &max_mm_inner_effective_spads, + &max_mm_outer_effective_spads); + + + + + VL53L1_calc_mm_effective_spads( + encoded_mm_roi_centre, + encoded_mm_roi_size, + encoded_zone_centre, + encoded_zone_size, + pgood_spads, + aperture_attenuation, + &mm_inner_effective_spads, + &mm_outer_effective_spads); + + + + + scaled_mm1_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_inner_peak_signal_count_rtn_mcps; + scaled_mm1_peak_rate_mcps *= (uint32_t)mm_inner_effective_spads; + scaled_mm1_peak_rate_mcps /= (uint32_t)max_mm_inner_effective_spads; + + scaled_mm2_peak_rate_mcps = + (uint32_t)pcal_data->result__mm_outer_peak_signal_count_rtn_mcps; + scaled_mm2_peak_rate_mcps *= (uint32_t)mm_outer_effective_spads; + scaled_mm2_peak_rate_mcps /= (uint32_t)max_mm_outer_effective_spads; + + + + + tmp0 = ((int32_t)mm1_offset_mm * (int32_t)scaled_mm1_peak_rate_mcps); + tmp0 += ((int32_t)mm2_offset_mm * (int32_t)scaled_mm2_peak_rate_mcps); + + tmp1 = (int32_t)scaled_mm1_peak_rate_mcps + + (int32_t)scaled_mm2_peak_rate_mcps; + + + + + + + if (tmp1 != 0) + tmp0 = (tmp0 * 4) / tmp1; + + *prange_offset_mm = (int16_t)tmp0; + +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_window( + int16_t target_distance_mm, + uint16_t target_width_oversize, + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pxtalk_data->pll_period_mm = + VL53L1_calc_pll_period_mm(phist_bins->VL53L1_p_019); + + + + pxtalk_data->xtalk_width_phase = + (int32_t)phist_bins->vcsel_width * 128; + pxtalk_data->target_width_phase = + pxtalk_data->xtalk_width_phase + + (int32_t)target_width_oversize * 128; + + + + + + + + pxtalk_data->xtalk_start_phase = + (int32_t)phist_bins->zero_distance_phase - + (pxtalk_data->xtalk_width_phase / 2); + pxtalk_data->xtalk_end_phase = + (int32_t)pxtalk_data->xtalk_start_phase + + pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->xtalk_start_phase < 0) + pxtalk_data->xtalk_start_phase = 0; + + + + + + + + + pxtalk_data->VL53L1_p_015 = + (uint8_t)(pxtalk_data->xtalk_start_phase / 2048); + + + + pxtalk_data->VL53L1_p_016 = + (uint8_t)((pxtalk_data->xtalk_end_phase + 2047) / 2048); + + + + + + + + pxtalk_data->target_start_phase = + (int32_t)target_distance_mm * 2048 * 16; + pxtalk_data->target_start_phase += + ((int32_t)pxtalk_data->pll_period_mm / 2); + pxtalk_data->target_start_phase /= (int32_t)pxtalk_data->pll_period_mm; + pxtalk_data->target_start_phase += + (int32_t)phist_bins->zero_distance_phase; + + + + + + + pxtalk_data->target_start_phase -= + (pxtalk_data->target_width_phase / 2); + pxtalk_data->target_end_phase = + (int32_t)pxtalk_data->target_start_phase + + pxtalk_data->target_width_phase; + + if (pxtalk_data->target_start_phase < 0) + pxtalk_data->target_start_phase = 0; + + + + pxtalk_data->target_start = + (uint8_t)(pxtalk_data->target_start_phase / 2048); + + + + if (pxtalk_data->VL53L1_p_016 > (pxtalk_data->target_start-1)) + pxtalk_data->VL53L1_p_016 = pxtalk_data->target_start-1; + + + + pxtalk_data->effective_width = + (2048 * ((int32_t)pxtalk_data->VL53L1_p_016+1)); + pxtalk_data->effective_width -= pxtalk_data->xtalk_start_phase; + + + + + + if (pxtalk_data->effective_width > pxtalk_data->xtalk_width_phase) + pxtalk_data->effective_width = pxtalk_data->xtalk_width_phase; + + if (pxtalk_data->effective_width < 1) + pxtalk_data->effective_width = 1; + + + + pxtalk_data->event_scaler = pxtalk_data->xtalk_width_phase * 1000; + pxtalk_data->event_scaler += (pxtalk_data->effective_width / 2); + pxtalk_data->event_scaler /= pxtalk_data->effective_width; + + + + + + if (pxtalk_data->event_scaler < 1000) + pxtalk_data->event_scaler = 1000; + + if (pxtalk_data->event_scaler > 4000) + pxtalk_data->event_scaler = 4000; + + + + pxtalk_data->event_scaler_sum += pxtalk_data->event_scaler; + + + + pxtalk_data->peak_duration_us_sum += + (uint32_t)phist_bins->peak_duration_us; + + + + pxtalk_data->effective_spad_count_sum += + (uint32_t)phist_bins->result__dss_actual_effective_spads; + + + + pxtalk_data->zero_distance_phase_sum += + (uint32_t)phist_bins->zero_distance_phase; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_event_sums( + VL53L1_histogram_bin_data_t *phist_bins, + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t lb = 0; + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + for (lb = pxtalk_data->VL53L1_p_015; + lb <= pxtalk_data->VL53L1_p_016; + lb++) { + + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + + pxtalk_data->signal_events_sum += phist_bins->bin_data[i]; + pxtalk_data->signal_events_sum -= + phist_bins->VL53L1_p_004; + } + + + + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS && + lb < phist_bins->VL53L1_p_024; lb++) { + + + + i = (lb + phist_bins->number_of_ambient_bins + + phist_bins->VL53L1_p_024) % + phist_bins->VL53L1_p_024; + + + + pxtalk_data->bin_data_sums[lb] += phist_bins->bin_data[i]; + pxtalk_data->bin_data_sums[lb] -= + phist_bins->VL53L1_p_004; + } + + pxtalk_data->sample_count += 1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_rate_per_spad( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint64_t tmp64_0 = 0; + uint64_t tmp64_1 = 0; + uint64_t xtalk_per_spad = 0; + + LOG_FUNCTION_START(""); + + + + + + + + + + + + + + + + + + tmp64_0 = + ((uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->sample_count * + (uint64_t)pxtalk_data->event_scaler_avg * 256U) << 9U; + tmp64_1 = + (uint64_t)pxtalk_data->effective_spad_count_sum * + (uint64_t)pxtalk_data->peak_duration_us_sum; + + + + + if (tmp64_1 > 0U) { + + + tmp64_0 = tmp64_0 + (tmp64_1 >> 1U); + xtalk_per_spad = do_division_u(tmp64_0, tmp64_1); + } else { + xtalk_per_spad = (uint64_t)tmp64_0; + } + + pxtalk_data->xtalk_rate_kcps_per_spad = (uint32_t)xtalk_per_spad; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_extract_calc_shape( + VL53L1_hist_xtalk_extract_data_t *pxtalk_data, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + int32_t lb = 0; + uint64_t total_events = 0U; + uint64_t tmp64_0 = 0U; + int32_t remaining_area = 1024; + + LOG_FUNCTION_START(""); + + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg; + pxtalk_shape->phasecal_result__reference_phase = + (uint16_t)pxtalk_data->zero_distance_phase_avg + (3*2048); + + + + + if (pxtalk_data->signal_events_sum > 0) + total_events = + (uint64_t)pxtalk_data->signal_events_sum * + (uint64_t)pxtalk_data->event_scaler_avg; + else + total_events = 1; + + + + remaining_area = 1024; + pxtalk_data->max_shape_value = 0; + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + + if ((lb < (int32_t)pxtalk_data->VL53L1_p_015 || + lb > (int32_t)pxtalk_data->VL53L1_p_016) || + pxtalk_data->bin_data_sums[lb] < 0) { + + + + + + + if (remaining_area > 0 && remaining_area < 1024) { + if (remaining_area > + pxtalk_data->max_shape_value) { + pxtalk_shape->bin_data[lb] = + (uint32_t)pxtalk_data->max_shape_value; + remaining_area -= + pxtalk_data->max_shape_value; + } else { + pxtalk_shape->bin_data[lb] = + (uint32_t)remaining_area; + remaining_area = 0; + } + } else { + pxtalk_shape->bin_data[lb] = 0; + } + + } else { + + + + + tmp64_0 = + (uint64_t)pxtalk_data->bin_data_sums[lb] + * 1024U * 1000U; + tmp64_0 += (total_events >> 1); + tmp64_0 = do_division_u(tmp64_0, total_events); + if (tmp64_0 > 0xFFFFU) + tmp64_0 = 0xFFFFU; + + pxtalk_shape->bin_data[lb] = (uint32_t)tmp64_0; + + + + + + if ((int32_t)pxtalk_shape->bin_data[lb] > + pxtalk_data->max_shape_value) + pxtalk_data->max_shape_value = + (int32_t)pxtalk_shape->bin_data[lb]; + + remaining_area -= (int32_t)pxtalk_shape->bin_data[lb]; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_hist_xtalk_shape_model( + uint16_t events_per_bin, + uint16_t pulse_centre, + uint16_t pulse_width, + VL53L1_xtalk_histogram_shape_t *pxtalk_shape) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t phase_start = 0; + uint32_t phase_stop = 0; + uint32_t phase_bin = 0; + + uint32_t bin_start = 0; + uint32_t bin_stop = 0; + + uint32_t lb = 0; + uint16_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + + pxtalk_shape->VL53L1_p_022 = 0; + pxtalk_shape->VL53L1_p_023 = VL53L1_XTALK_HISTO_BINS; + pxtalk_shape->VL53L1_p_024 = VL53L1_XTALK_HISTO_BINS; + + pxtalk_shape->zero_distance_phase = pulse_centre; + pxtalk_shape->phasecal_result__reference_phase = + pulse_centre + (3*2048); + + + + if (pulse_centre > (pulse_width >> 1)) + phase_start = (uint32_t)pulse_centre - + ((uint32_t)pulse_width >> 1); + else + phase_start = 0; + + phase_stop = (uint32_t)pulse_centre + + ((uint32_t)pulse_width >> 1); + + + + bin_start = (phase_start / 2048); + bin_stop = (phase_stop / 2048); + + for (lb = 0; lb < VL53L1_XTALK_HISTO_BINS; lb++) { + VL53L1_p_008 = 0; + + + + if (lb == bin_start && lb == bin_stop) { + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + phase_stop - phase_start); + + } else if (lb > bin_start && lb < bin_stop) { + + + + VL53L1_p_008 = events_per_bin; + + } else if (lb == bin_start) { + + + + phase_bin = (lb + 1) * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_bin - phase_start)); + + } else if (lb == bin_stop) { + + + + phase_bin = lb * 2048; + VL53L1_p_008 = + VL53L1_hist_xtalk_shape_model_interp( + events_per_bin, + (phase_stop - phase_bin)); + } + + pxtalk_shape->bin_data[lb] = VL53L1_p_008; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +uint16_t VL53L1_hist_xtalk_shape_model_interp( + uint16_t events_per_bin, + uint32_t phase_delta) +{ + + + + + + + + + + uint32_t VL53L1_p_008 = 0; + + LOG_FUNCTION_START(""); + + + + VL53L1_p_008 = (uint32_t)events_per_bin * phase_delta; + VL53L1_p_008 += 1024; + VL53L1_p_008 /= 2048; + + + + if (VL53L1_p_008 > 0xFFFFU) + VL53L1_p_008 = 0xFFFFU; + + LOG_FUNCTION_END(0); + + return (uint16_t)VL53L1_p_008; +} + + +void VL53L1_spad_number_to_byte_bit_index( + uint8_t spad_number, + uint8_t *pbyte_index, + uint8_t *pbit_index, + uint8_t *pbit_mask) +{ + + + + + + + + + + + *pbyte_index = spad_number >> 3; + *pbit_index = spad_number & 0x07; + *pbit_mask = 0x01 << *pbit_index; + +} + + +void VL53L1_encode_row_col( + uint8_t row, + uint8_t col, + uint8_t *pspad_number) +{ + + + + + + if (row > 7) + *pspad_number = 128 + (col << 3) + (15-row); + else + *pspad_number = ((15-col) << 3) + row; + +} + + +void VL53L1_decode_zone_size( + uint8_t encoded_xy_size, + uint8_t *pwidth, + uint8_t *pheight) +{ + + + + + + + + + + + + *pheight = encoded_xy_size >> 4; + *pwidth = encoded_xy_size & 0x0F; + +} + + +void VL53L1_encode_zone_size( + uint8_t width, + uint8_t height, + uint8_t *pencoded_xy_size) +{ + + + + + + + + + + + *pencoded_xy_size = (height << 4) + width; + +} + + +void VL53L1_decode_zone_limits( + uint8_t encoded_xy_centre, + uint8_t encoded_xy_size, + int16_t *px_ll, + int16_t *py_ll, + int16_t *px_ur, + int16_t *py_ur) +{ + + + + + + + + + + uint8_t x_centre = 0; + uint8_t y_centre = 0; + uint8_t width = 0; + uint8_t height = 0; + + + + + VL53L1_decode_row_col( + encoded_xy_centre, + &y_centre, + &x_centre); + + VL53L1_decode_zone_size( + encoded_xy_size, + &width, + &height); + + + + + *px_ll = (int16_t)x_centre - ((int16_t)width + 1) / 2; + if (*px_ll < 0) + *px_ll = 0; + + *px_ur = *px_ll + (int16_t)width; + if (*px_ur > (VL53L1_SPAD_ARRAY_WIDTH-1)) + *px_ur = VL53L1_SPAD_ARRAY_WIDTH-1; + + *py_ll = (int16_t)y_centre - ((int16_t)height + 1) / 2; + if (*py_ll < 0) + *py_ll = 0; + + *py_ur = *py_ll + (int16_t)height; + if (*py_ur > (VL53L1_SPAD_ARRAY_HEIGHT-1)) + *py_ur = VL53L1_SPAD_ARRAY_HEIGHT-1; +} + + +uint8_t VL53L1_is_aperture_location( + uint8_t row, + uint8_t col) +{ + + + + + + uint8_t is_aperture = 0; + uint8_t mod_row = row % 4; + uint8_t mod_col = col % 4; + + if (mod_row == 0 && mod_col == 2) + is_aperture = 1; + + if (mod_row == 2 && mod_col == 0) + is_aperture = 1; + + return is_aperture; +} + + +void VL53L1_calc_max_effective_spads( + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmax_effective_spads) +{ + + + + + + + int16_t x = 0; + int16_t y = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + + + + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + + + + + *pmax_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + + + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + *pmax_effective_spads += + aperture_attenuation; + else + *pmax_effective_spads += 0x0100; + + } + } + } +} + + +void VL53L1_calc_mm_effective_spads( + uint8_t encoded_mm_roi_centre, + uint8_t encoded_mm_roi_size, + uint8_t encoded_zone_centre, + uint8_t encoded_zone_size, + uint8_t *pgood_spads, + uint16_t aperture_attenuation, + uint16_t *pmm_inner_effective_spads, + uint16_t *pmm_outer_effective_spads) +{ + + + + + + + + int16_t x = 0; + int16_t y = 0; + + int16_t mm_x_ll = 0; + int16_t mm_y_ll = 0; + int16_t mm_x_ur = 0; + int16_t mm_y_ur = 0; + + int16_t zone_x_ll = 0; + int16_t zone_y_ll = 0; + int16_t zone_x_ur = 0; + int16_t zone_y_ur = 0; + + uint8_t spad_number = 0; + uint8_t byte_index = 0; + uint8_t bit_index = 0; + uint8_t bit_mask = 0; + + uint8_t is_aperture = 0; + uint16_t spad_attenuation = 0; + + + + + VL53L1_decode_zone_limits( + encoded_mm_roi_centre, + encoded_mm_roi_size, + &mm_x_ll, + &mm_y_ll, + &mm_x_ur, + &mm_y_ur); + + VL53L1_decode_zone_limits( + encoded_zone_centre, + encoded_zone_size, + &zone_x_ll, + &zone_y_ll, + &zone_x_ur, + &zone_y_ur); + + + + + + + + + + *pmm_inner_effective_spads = 0; + *pmm_outer_effective_spads = 0; + + for (y = zone_y_ll; y <= zone_y_ur; y++) { + for (x = zone_x_ll; x <= zone_x_ur; x++) { + + + + + VL53L1_encode_row_col( + (uint8_t)y, + (uint8_t)x, + &spad_number); + + + + + + + + + VL53L1_spad_number_to_byte_bit_index( + spad_number, + &byte_index, + &bit_index, + &bit_mask); + + + + + if ((pgood_spads[byte_index] & bit_mask) > 0) { + + + + is_aperture = VL53L1_is_aperture_location( + (uint8_t)y, + (uint8_t)x); + + if (is_aperture > 0) + spad_attenuation = aperture_attenuation; + else + spad_attenuation = 0x0100; + + + + + + + + if (x >= mm_x_ll && x <= mm_x_ur && + y >= mm_y_ll && y <= mm_y_ur) + *pmm_inner_effective_spads += + spad_attenuation; + else + *pmm_outer_effective_spads += + spad_attenuation; + } + } + } +} + + +void VL53L1_hist_copy_results_to_sys_and_core( + VL53L1_histogram_bin_data_t *pbins, + VL53L1_range_results_t *phist, + VL53L1_system_results_t *psys, + VL53L1_core_results_t *pcore) +{ + + + + + + uint8_t i = 0; + + VL53L1_range_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + + VL53L1_init_system_results(psys); + + + + + psys->result__interrupt_status = pbins->result__interrupt_status; + psys->result__range_status = phist->active_results; + psys->result__report_status = pbins->result__report_status; + psys->result__stream_count = pbins->result__stream_count; + + pdata = &(phist->VL53L1_p_002[0]); + + for (i = 0; i < phist->active_results; i++) { + + switch (i) { + case 0: + psys->result__dss_actual_effective_spads_sd0 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd0 = + pdata->peak_signal_count_rate_mcps; + psys->result__avg_signal_count_rate_mcps_sd0 = + pdata->avg_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd0 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd0 = pdata->VL53L1_p_005; + psys->result__phase_sd0 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd0 = + (uint16_t)pdata->median_range_mm; + + psys->result__phase_sd1 = pdata->zero_distance_phase; + + pcore->result_core__ranging_total_events_sd0 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd0 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd0 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd0 = + pdata->VL53L1_p_020; + + break; + case 1: + psys->result__dss_actual_effective_spads_sd1 = + pdata->VL53L1_p_006; + psys->result__peak_signal_count_rate_mcps_sd1 = + pdata->peak_signal_count_rate_mcps; + psys->result__ambient_count_rate_mcps_sd1 = + pdata->ambient_count_rate_mcps; + + psys->result__sigma_sd1 = pdata->VL53L1_p_005; + psys->result__phase_sd1 = pdata->VL53L1_p_014; + + psys->result__final_crosstalk_corrected_range_mm_sd1 = + (uint16_t)pdata->median_range_mm; + + pcore->result_core__ranging_total_events_sd1 = + pdata->VL53L1_p_021; + pcore->result_core__signal_total_events_sd1 = + pdata->VL53L1_p_013; + pcore->result_core__total_periods_elapsed_sd1 = + pdata->total_periods_elapsed; + pcore->result_core__ambient_window_events_sd1 = + pdata->VL53L1_p_020; + break; + } + + pdata++; + } + + LOG_FUNCTION_END(0); + +} + + +VL53L1_Error VL53L1_sum_histogram_data( + VL53L1_histogram_bin_data_t *phist_input, + VL53L1_histogram_bin_data_t *phist_output) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t smallest_bin_num = 0; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) { + + if (phist_output->VL53L1_p_024 >= + phist_input->VL53L1_p_024) + smallest_bin_num = phist_input->VL53L1_p_024; + else + smallest_bin_num = phist_output->VL53L1_p_024; + } + + + + + + + + + if (status == VL53L1_ERROR_NONE) + + for (i = 0; i < smallest_bin_num; i++) + + + phist_output->bin_data[i] += phist_input->bin_data[i]; + + if (status == VL53L1_ERROR_NONE) + + phist_output->VL53L1_p_004 += + phist_input->VL53L1_p_004; + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_avg_histogram_data( + uint8_t no_of_samples, + VL53L1_histogram_bin_data_t *phist_sum, + VL53L1_histogram_bin_data_t *phist_avg) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + + LOG_FUNCTION_START(""); + + + + + + + + + if (status == VL53L1_ERROR_NONE) { + + for (i = 0; i < phist_sum->VL53L1_p_024; i++) { + + + + + if (no_of_samples > 0) + phist_avg->bin_data[i] = + phist_sum->bin_data[i] / + (int32_t)no_of_samples; + else + phist_avg->bin_data[i] = phist_sum->bin_data[i]; + } + } + + if (status == VL53L1_ERROR_NONE) { + + if (no_of_samples > 0) + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004 / + (int32_t)no_of_samples; + else + phist_avg->VL53L1_p_004 = + phist_sum->VL53L1_p_004; + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_save_cfg_data( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + + VL53L1_zone_private_dyn_cfg_t *pzone_dyn_cfg; + VL53L1_dynamic_config_t *pdynamic = &(pdev->dyn_cfg); + + LOG_FUNCTION_START(""); + + pzone_dyn_cfg = + &(pres->zone_dyn_cfgs.VL53L1_p_002[pdev->ll_state.cfg_zone_id]); + + pzone_dyn_cfg->expected_stream_count = + pdev->ll_state.cfg_stream_count; + + pzone_dyn_cfg->expected_gph_id = + pdev->ll_state.cfg_gph_id; + + pzone_dyn_cfg->roi_config__user_roi_centre_spad = + pdynamic->roi_config__user_roi_centre_spad; + + pzone_dyn_cfg->roi_config__user_roi_requested_global_xy_size = + pdynamic->roi_config__user_roi_requested_global_xy_size; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_dynamic_zone_update( + VL53L1_DEV Dev, + VL53L1_range_results_t *presults) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = + VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_zone_private_dyn_cfgs_t *pZ = &(pres->zone_dyn_cfgs); + + uint8_t zone_id = pdev->ll_state.rd_zone_id; + uint8_t i; + uint16_t max_total_rate_per_spads; + uint16_t target_rate = + pdev->stat_cfg.dss_config__target_total_rate_mcps; + uint32_t temp = 0xFFFF; +#ifdef VL53L1_LOG_ENABLE + uint16_t eff_spad_cnt = + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count; +#endif + + LOG_FUNCTION_START(""); + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = 0; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: peak signal count rate mcps:"); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "%u actual effective spads: %u\n", + presults->VL53L1_p_002[0].peak_signal_count_rate_mcps, + presults->VL53L1_p_002[0].VL53L1_p_006); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: active results: %u\n", + presults->active_results); + + max_total_rate_per_spads = + presults->VL53L1_p_002[0].total_rate_per_spad_mcps; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: max total rate per spad at start: %u\n", + max_total_rate_per_spads); + + for (i = 1; i < presults->active_results; i++) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone total rate per spad: zone_id: %u,", + i); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "total rate per spad: %u\n", + presults->VL53L1_p_002[i].total_rate_per_spad_mcps); + + if (presults->VL53L1_p_002[i].total_rate_per_spad_mcps > + max_total_rate_per_spads) + max_total_rate_per_spads = + presults->VL53L1_p_002[i].total_rate_per_spad_mcps; + + } + + if (max_total_rate_per_spads == 0) { + + + + + + temp = 0xFFFF; + } else { + + + + + + temp = target_rate << 14; + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 1: temp: %u\n", + temp); + + + + + + temp = temp / max_total_rate_per_spads; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 2: temp: %u\n", + temp); + + + + + + if (temp > 0xFFFF) + temp = 0xFFFF; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: 3: temp: %u\n", + temp); + } + + pZ->VL53L1_p_002[zone_id].dss_requested_effective_spad_count = + (uint16_t)temp; + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " DYNZONEUPDATE: zone_id: %u, target_rate: %u,", + zone_id, + target_rate); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "max_total_rate_per_spads: %u, requested_spads: %u\n", + max_total_rate_per_spads, + eff_spad_cnt); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_multizone_hist_bins_update( + VL53L1_DEV Dev) +{ + + + + + + + + + + + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state); + VL53L1_zone_config_t *pzone_cfg = &(pdev->zone_cfg); + VL53L1_histogram_config_t *phist_cfg = &(pdev->hist_cfg); + VL53L1_histogram_config_t *pmulti_hist = + &(pzone_cfg->multizone_hist_cfg); + + uint8_t next_range_is_odd_timing = (pstate->cfg_stream_count) % 2; + + LOG_FUNCTION_START(""); + + + + + + if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting LOWAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB timing\n"); + if (!next_range_is_odd_timing) { + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB EVEN timing\n"); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting MIDAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } + } else if (pzone_cfg->bin_config[pdev->ll_state.cfg_zone_id] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + if (!next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB EVEN timing\n" + ); + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + if (next_range_is_odd_timing) { + trace_print (VL53L1_TRACE_LEVEL_DEBUG, + " HISTBINCONFIGUPDATE: Setting HIGHAMB ODD timing\n"); + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + } + + + + + + + if (status == VL53L1_ERROR_NONE) { + + VL53L1_copy_hist_bins_to_static_cfg( + phist_cfg, + &(pdev->stat_cfg), + &(pdev->tim_cfg)); + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + + + + + + + + + +VL53L1_Error VL53L1_update_internal_stream_counters( + VL53L1_DEV Dev, + uint8_t external_stream_count, + uint8_t *pinternal_stream_count, + uint8_t *pinternal_stream_count_val) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t stream_divider; + + VL53L1_LLDriverData_t *pdev = + VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + stream_divider = pdev->gen_cfg.global_config__stream_divider; + + if (stream_divider == 0) { + + + + + + + *pinternal_stream_count = external_stream_count; + + } else if (*pinternal_stream_count_val == (stream_divider-1)) { + + + + + + if (*pinternal_stream_count == 0xFF) + *pinternal_stream_count = 0x80; + else + *pinternal_stream_count = *pinternal_stream_count + 1; + + + + + + *pinternal_stream_count_val = 0; + + } else { + + + + + + *pinternal_stream_count_val = *pinternal_stream_count_val + 1; + } + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "UPDINTSTREAMCOUNT internal_steam_count: %d,", + *pinternal_stream_count); + + trace_print(VL53L1_TRACE_LEVEL_DEBUG, + "internal_stream_count_val: %d, divider: %d\n", + *pinternal_stream_count_val, + stream_divider); + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + +VL53L1_Error VL53L1_set_histogram_multizone_initial_bin_config( + VL53L1_zone_config_t *pzone_cfg, + VL53L1_histogram_config_t *phist_cfg, + VL53L1_histogram_config_t *pmulti_hist) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__LOWAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__low_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__low_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__low_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__MIDAMB) { + + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__mid_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__mid_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__mid_amb_even_bin_4_5; + } else if (pzone_cfg->bin_config[0] == + VL53L1_ZONECONFIG_BINCONFIG__HIGHAMB) { + phist_cfg->histogram_config__low_amb_even_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_even_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_even_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + phist_cfg->histogram_config__low_amb_odd_bin_0_1 = + pmulti_hist->histogram_config__high_amb_even_bin_0_1; + phist_cfg->histogram_config__low_amb_odd_bin_2_3 = + pmulti_hist->histogram_config__high_amb_even_bin_2_3; + phist_cfg->histogram_config__low_amb_odd_bin_4_5 = + pmulti_hist->histogram_config__high_amb_even_bin_4_5; + } + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +uint8_t VL53L1_encode_GPIO_interrupt_config( + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + uint8_t system__interrupt_config; + + system__interrupt_config = pintconf->intr_mode_distance; + system__interrupt_config |= ((pintconf->intr_mode_rate) << 2); + system__interrupt_config |= ((pintconf->intr_new_measure_ready) << 5); + system__interrupt_config |= ((pintconf->intr_no_target) << 6); + system__interrupt_config |= ((pintconf->intr_combined_mode) << 7); + + return system__interrupt_config; +} + + + + + + +VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config( + uint8_t system__interrupt_config) +{ + VL53L1_GPIO_interrupt_config_t intconf; + + intconf.intr_mode_distance = system__interrupt_config & 0x03; + intconf.intr_mode_rate = (system__interrupt_config >> 2) & 0x03; + intconf.intr_new_measure_ready = (system__interrupt_config >> 5) & 0x01; + intconf.intr_no_target = (system__interrupt_config >> 6) & 0x01; + intconf.intr_combined_mode = (system__interrupt_config >> 7) & 0x01; + + + + intconf.threshold_rate_low = 0; + intconf.threshold_rate_high = 0; + intconf.threshold_distance_low = 0; + intconf.threshold_distance_high = 0; + + return intconf; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_distance_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->dyn_cfg.system__thresh_high = threshold_high; + pdev->dyn_cfg.system__thresh_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_rate_threshold( + VL53L1_DEV Dev, + uint16_t threshold_high, + uint16_t threshold_low) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->gen_cfg.system__thresh_rate_high = threshold_high; + pdev->gen_cfg.system__thresh_rate_low = threshold_low; + + LOG_FUNCTION_END(status); + return status; +} + + + + + + +VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct( + VL53L1_DEV Dev, + VL53L1_GPIO_interrupt_config_t *pintconf) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = VL53L1_set_GPIO_distance_threshold( + Dev, + pintconf->threshold_distance_high, + pintconf->threshold_distance_low); + + if (status == VL53L1_ERROR_NONE) { + status = + VL53L1_set_GPIO_rate_threshold( + Dev, + pintconf->threshold_rate_high, + pintconf->threshold_rate_low); + } + + LOG_FUNCTION_END(status); + return status; +} + + +VL53L1_Error VL53L1_set_ref_spad_char_config( + VL53L1_DEV Dev, + uint8_t vcsel_period_a, + uint32_t phasecal_timeout_us, + uint16_t total_rate_target_mcps, + uint16_t max_count_rate_rtn_limit_mcps, + uint16_t min_count_rate_rtn_limit_mcps, + uint16_t fast_osc_frequency) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t buffer[2]; + + uint32_t macro_period_us = 0; + uint32_t timeout_mclks = 0; + + LOG_FUNCTION_START(""); + + + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + vcsel_period_a); + + + + + + + timeout_mclks = phasecal_timeout_us << 12; + timeout_mclks = timeout_mclks + (macro_period_us>>1); + timeout_mclks = timeout_mclks / macro_period_us; + + if (timeout_mclks > 0xFF) + pdev->gen_cfg.phasecal_config__timeout_macrop = 0xFF; + else + pdev->gen_cfg.phasecal_config__timeout_macrop = + (uint8_t)timeout_mclks; + + pdev->tim_cfg.range_config__vcsel_period_a = vcsel_period_a; + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = + VL53L1_WrByte( + Dev, + VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP, + pdev->gen_cfg.phasecal_config__timeout_macrop); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A, + pdev->tim_cfg.range_config__vcsel_period_a); + + + + + + + + buffer[0] = pdev->tim_cfg.range_config__vcsel_period_a; + buffer[1] = pdev->tim_cfg.range_config__vcsel_period_a; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + + + + + pdev->customer.ref_spad_char__total_rate_target_mcps = + total_rate_target_mcps; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS, + total_rate_target_mcps); + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__SIGMA_THRESH, + max_count_rate_rtn_limit_mcps); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrWord( + Dev, + VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS, + min_count_rate_rtn_limit_mcps); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_ssc_config( + VL53L1_DEV Dev, + VL53L1_ssc_config_t *pssc_cfg, + uint16_t fast_osc_frequency) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[5]; + + uint32_t macro_period_us = 0; + uint16_t timeout_encoded = 0; + + LOG_FUNCTION_START(""); + + + + + + macro_period_us = + VL53L1_calc_macro_period_us( + fast_osc_frequency, + pssc_cfg->VL53L1_p_009); + + + + + + timeout_encoded = + VL53L1_calc_encoded_timeout( + pssc_cfg->timeout_us, + macro_period_us); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_CAL_CONFIG__VCSEL_START, + pssc_cfg->vcsel_start); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH, + pssc_cfg->vcsel_width); + + + + + buffer[0] = (uint8_t)((timeout_encoded & 0x0000FF00) >> 8); + buffer[1] = (uint8_t) (timeout_encoded & 0x000000FF); + buffer[2] = pssc_cfg->VL53L1_p_009; + buffer[3] = (uint8_t)((pssc_cfg->rate_limit_mcps & 0x0000FF00) >> 8); + buffer[4] = (uint8_t) (pssc_cfg->rate_limit_mcps & 0x000000FF); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI, + buffer, + 5); + + + + + + + + buffer[0] = pssc_cfg->VL53L1_p_009; + buffer[1] = pssc_cfg->VL53L1_p_009; + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WriteMulti( + Dev, + VL53L1_SD_CONFIG__WOI_SD0, + buffer, + 2); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WrByte( + Dev, + VL53L1_NVM_BIST__CTRL, + pssc_cfg->array_select); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_spad_rate_data( + VL53L1_DEV Dev, + VL53L1_spad_rate_data_t *pspad_rates) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + int i = 0; + + uint8_t VL53L1_p_002[512]; + uint8_t *pdata = &VL53L1_p_002[0]; + + LOG_FUNCTION_START(""); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_ReadMulti( + Dev, + VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV, + pdata, + 512); + + + + pdata = &VL53L1_p_002[0]; + for (i = 0; i < VL53L1_NO_OF_SPAD_ENABLES; i++) { + pspad_rates->rate_data[i] = + (uint16_t)VL53L1_decode_unsigned_integer(pdata, 2); + pdata += 2; + } + + + + + pspad_rates->VL53L1_p_023 = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->no_of_values = VL53L1_NO_OF_SPAD_ENABLES; + pspad_rates->fractional_bits = 15; + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_required_samples( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + + VL53L1_range_results_t *presults = &(pres->range_results); + VL53L1_range_data_t *pxmonitor = &(presults->xmonitor); + + uint32_t peak_duration_us = pxmonitor->peak_duration_us; + + uint64_t temp64a; + uint64_t temp64z; + + LOG_FUNCTION_START(""); + + temp64a = pxmonitor->VL53L1_p_021 + + pxmonitor->VL53L1_p_020; + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + temp64a = do_division_u((temp64a * 1000), peak_duration_us); + + temp64z = pconfig->noise_margin * pxmonitor->VL53L1_p_006; + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + temp64a = temp64a * 1000 * 256; + temp64a = do_division_u(temp64a, temp64z); + + pint->required_samples = (uint32_t)temp64a; + + + + if (pint->required_samples < 2) + pint->required_samples = 2; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + VL53L1_DEV Dev, + uint32_t xtalk_offset_out, + VL53L1_smudge_corrector_config_t *pconfig, + VL53L1_smudge_corrector_data_t *pout, + uint8_t add_smudge, + uint8_t soft_update + ) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + int16_t x_gradient_scaler; + int16_t y_gradient_scaler; + uint32_t orig_xtalk_offset; + int16_t orig_x_gradient; + int16_t orig_y_gradient; + int32_t itemp32; + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + VL53L1_xtalk_calibration_results_t *pC = &(pdev->xtalk_cal); + + LOG_FUNCTION_START(""); + + + + if (add_smudge == 1) { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out + + (uint32_t)pconfig->smudge_margin; + } else { + pout->algo__crosstalk_compensation_plane_offset_kcps = + (uint32_t)xtalk_offset_out; + } + + + + orig_xtalk_offset = + pX->nvm_default__crosstalk_compensation_plane_offset_kcps; + + orig_x_gradient = + pX->nvm_default__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pX->nvm_default__crosstalk_compensation_y_plane_gradient_kcps; + + if (((pconfig->user_scaler_set == 0) + || (pconfig->scaler_calc_method == 1)) && + (pC->algo__crosstalk_compensation_plane_offset_kcps + != 0)) { + + + orig_xtalk_offset = + pC->algo__crosstalk_compensation_plane_offset_kcps; + + orig_x_gradient = + pC->algo__crosstalk_compensation_x_plane_gradient_kcps; + + orig_y_gradient = + pC->algo__crosstalk_compensation_y_plane_gradient_kcps; + } + + + + if ((pconfig->user_scaler_set == 0) && (orig_x_gradient == 0)) + pout->gradient_zero_flag |= 0x01; + + if ((pconfig->user_scaler_set == 0) && (orig_y_gradient == 0)) + pout->gradient_zero_flag |= 0x02; + + + + + + + if (orig_xtalk_offset == 0) + orig_xtalk_offset = 1; + + + + + if (pconfig->user_scaler_set == 1) { + x_gradient_scaler = pconfig->x_gradient_scaler; + y_gradient_scaler = pconfig->y_gradient_scaler; + } else { + + + + + x_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_x_gradient) << 6), + orig_xtalk_offset); + pconfig->x_gradient_scaler = x_gradient_scaler; + y_gradient_scaler = (int16_t)do_division_s( + (((int32_t)orig_y_gradient) << 6), + orig_xtalk_offset); + pconfig->y_gradient_scaler = y_gradient_scaler; + } + + + + + if (pconfig->scaler_calc_method == 0) { + + + + + + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + x_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)( + pout->algo__crosstalk_compensation_plane_offset_kcps * + y_gradient_scaler); + itemp32 = itemp32 >> 6; + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } else if (pconfig->scaler_calc_method == 1) { + + + + + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 16)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_x_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_x_plane_gradient_kcps = + (int16_t)itemp32; + + itemp32 = (int32_t)(orig_xtalk_offset - + pout->algo__crosstalk_compensation_plane_offset_kcps); + itemp32 = (int32_t)(do_division_s(itemp32, 80)); + itemp32 = itemp32 << 2; + itemp32 = itemp32 + (int32_t)(orig_y_gradient); + if (itemp32 > 0xFFFF) + itemp32 = 0xFFFF; + + pout->algo__crosstalk_compensation_y_plane_gradient_kcps = + (int16_t)itemp32; + } + + + + if (pconfig->smudge_corr_apply_enabled == 1 && + (soft_update != 1) + ) { + + + pout->new_xtalk_applied_flag = 1; + + + + pX->algo__crosstalk_compensation_plane_offset_kcps = + pout->algo__crosstalk_compensation_plane_offset_kcps; + pX->algo__crosstalk_compensation_x_plane_gradient_kcps = + pout->algo__crosstalk_compensation_x_plane_gradient_kcps; + pX->algo__crosstalk_compensation_y_plane_gradient_kcps = + pout->algo__crosstalk_compensation_y_plane_gradient_kcps; + + + + if (pconfig->smudge_corr_single_apply == 1) { + + + pconfig->smudge_corr_apply_enabled = 0; + pconfig->smudge_corr_single_apply = 0; + } + } + + + + if (soft_update != 1) + pout->smudge_corr_valid = 1; + + LOG_FUNCTION_END(status); + + return status; +} + +#define CONT_CONTINUE 0 +#define CONT_NEXT_LOOP 1 +#define CONT_RESET 2 +VL53L1_Error VL53L1_dynamic_xtalk_correction_corrector( + VL53L1_DEV Dev + ) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + VL53L1_smudge_corrector_config_t *pconfig = + &(pdev->smudge_correct_config); + VL53L1_smudge_corrector_internals_t *pint = + &(pdev->smudge_corrector_internals); + VL53L1_smudge_corrector_data_t *pout = + &(pres->range_results.smudge_corrector_data); + VL53L1_range_results_t *pR = &(pres->range_results); + VL53L1_xtalk_config_t *pX = &(pdev->xtalk_cfg); + + uint8_t run_smudge_detection = 0; + uint8_t run_nodetect = 0; + uint8_t ambient_check = 0; + int32_t itemp32 = 0; + uint64_t utemp64 = 0; + uint8_t continue_processing = CONT_CONTINUE; + uint32_t xtalk_offset_out = 0; + uint32_t xtalk_offset_in = 0; + uint32_t current_xtalk = 0; + uint32_t smudge_margin_adjusted = 0; + uint8_t i = 0; + uint8_t nodetect_index = 0; + uint16_t amr; + + uint32_t cco; + + + + LOG_FUNCTION_START(""); + + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + + + ambient_check = (pconfig->smudge_corr_ambient_threshold == 0) || + (pconfig->smudge_corr_ambient_threshold > + ((uint32_t)pR->xmonitor.ambient_count_rate_mcps)); + + + + + run_smudge_detection = (pconfig->smudge_corr_enabled == 1) && + ambient_check && + (pR->xmonitor.range_status + == VL53L1_DEVICEERROR_RANGECOMPLETE); + + + + + if ((pR->xmonitor.range_status + != VL53L1_DEVICEERROR_RANGECOMPLETE) && + (pconfig->smudge_corr_enabled == 1)) { + + + run_nodetect = 2; + for (i = 0; i < pR->active_results; i++) { + if (pR->VL53L1_p_002[i].range_status == + VL53L1_DEVICEERROR_RANGECOMPLETE) { + if (pR->VL53L1_p_002[i].median_range_mm + <= + pconfig->nodetect_min_range_mm) { + run_nodetect = 0; + } else { + if (run_nodetect == 2) { + run_nodetect = 1; + nodetect_index = i; + } + } + } + } + + if (run_nodetect == 2) + + + run_nodetect = 0; + + amr = + pR->VL53L1_p_002[nodetect_index].ambient_count_rate_mcps; + + if (run_nodetect == 1) { + + + + + + + + utemp64 = 1000 * ((uint64_t)amr); + + + + utemp64 = utemp64 << 9; + + + + if (utemp64 < pconfig->nodetect_ambient_threshold) + run_nodetect = 1; + else + run_nodetect = 0; + + } + } + + + if (run_smudge_detection == 1) { + + + pint->nodetect_counter = 0; + + + + VL53L1_dynamic_xtalk_correction_calc_required_samples(Dev); + + + + xtalk_offset_in = + pR->xmonitor.VL53L1_p_012; + + + + cco = pX->algo__crosstalk_compensation_plane_offset_kcps; + current_xtalk = ((uint32_t)cco) << 2; + + + + smudge_margin_adjusted = + ((uint32_t)(pconfig->smudge_margin)) << 2; + + + + itemp32 = xtalk_offset_in - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + + if (itemp32 > ((int32_t)pconfig->single_xtalk_delta)) { + if ((int32_t)xtalk_offset_in > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) { + pout->single_xtalk_delta_flag = 1; + } else { + pout->single_xtalk_delta_flag = 2; + } + } + + + + pint->current_samples = pint->current_samples + 1; + + + + if (pint->current_samples > pconfig->sample_limit) { + pout->sample_limit_exceeded_flag = 1; + continue_processing = CONT_RESET; + } else { + + pint->accumulator = pint->accumulator + + xtalk_offset_in; + } + + if (pint->current_samples < pint->required_samples) + continue_processing = CONT_NEXT_LOOP; + + + + xtalk_offset_out = + (uint32_t)(do_division_u(pint->accumulator, + pint->current_samples)); + + + + itemp32 = xtalk_offset_out - current_xtalk + + smudge_margin_adjusted; + + if (itemp32 < 0) + itemp32 = itemp32 * (-1); + + if (continue_processing == CONT_CONTINUE && + (itemp32 >= ((int32_t)(pconfig->averaged_xtalk_delta))) + ) { + if ((int32_t)xtalk_offset_out > + ((int32_t)current_xtalk - + (int32_t)smudge_margin_adjusted)) + pout->averaged_xtalk_delta_flag = 1; + else + pout->averaged_xtalk_delta_flag = 2; + } + + if (continue_processing == CONT_CONTINUE && + (itemp32 < ((int32_t)(pconfig->averaged_xtalk_delta))) + ) + + + continue_processing = CONT_RESET; + + + + + pout->smudge_corr_clipped = 0; + if ((continue_processing == CONT_CONTINUE) && + (pconfig->smudge_corr_clip_limit != 0)) { + if (xtalk_offset_out > + pconfig->smudge_corr_clip_limit) { + pout->smudge_corr_clipped = 1; + continue_processing = CONT_RESET; + } + } + + + + + + if (pconfig->user_xtalk_offset_limit_hi && + (xtalk_offset_out > + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + + if ((pconfig->user_xtalk_offset_limit_hi == 0) && + (xtalk_offset_out < + pconfig->user_xtalk_offset_limit)) + xtalk_offset_out = + pconfig->user_xtalk_offset_limit; + + + + + xtalk_offset_out = xtalk_offset_out >> 2; + if (xtalk_offset_out > 0x3FFFF) + xtalk_offset_out = 0x3FFFF; + + + + if (continue_processing == CONT_CONTINUE) { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + + 0 + + ); + + + + continue_processing = CONT_RESET; + } else { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 1, + + 1 + + ); + } + + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + + } + + continue_processing = CONT_CONTINUE; + if (run_nodetect == 1) { + + + pint->nodetect_counter += 1; + + + + if (pint->nodetect_counter < pconfig->nodetect_sample_limit) + continue_processing = CONT_NEXT_LOOP; + + + + xtalk_offset_out = (uint32_t)(pconfig->nodetect_xtalk_offset); + + if (continue_processing == CONT_CONTINUE) { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + + 0 + + ); + + + + pout->smudge_corr_valid = 2; + + + + continue_processing = CONT_RESET; + } else { + + + VL53L1_dynamic_xtalk_correction_calc_new_xtalk( + Dev, + xtalk_offset_out, + pconfig, + pout, + 0, + + 1 + + ); + } + + + + if (continue_processing == CONT_RESET) { + pint->accumulator = 0; + pint->current_samples = 0; + pint->nodetect_counter = 0; + } + } + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + VL53L1_LLDriverResults_t *pres = VL53L1DevStructGetLLResultsHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdev->smudge_correct_config.smudge_corr_enabled = 1; + pdev->smudge_correct_config.smudge_corr_apply_enabled = 1; + pdev->smudge_correct_config.smudge_corr_single_apply = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_COR_SINGLE_APPLY_DEFAULT; + + pdev->smudge_correct_config.smudge_margin = + VL53L1_TUNINGPARM_DYNXTALK_SMUDGE_MARGIN_DEFAULT; + pdev->smudge_correct_config.noise_margin = + VL53L1_TUNINGPARM_DYNXTALK_NOISE_MARGIN_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_DEFAULT; + pdev->smudge_correct_config.user_xtalk_offset_limit_hi = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_OFFSET_LIMIT_HI_DEFAULT; + pdev->smudge_correct_config.sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.single_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_SINGLE_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.averaged_xtalk_delta = + VL53L1_TUNINGPARM_DYNXTALK_AVERAGED_XTALK_DELTA_DEFAULT; + pdev->smudge_correct_config.smudge_corr_clip_limit = + VL53L1_TUNINGPARM_DYNXTALK_CLIP_LIMIT_DEFAULT; + pdev->smudge_correct_config.smudge_corr_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_XTALK_AMB_THRESHOLD_DEFAULT; + pdev->smudge_correct_config.scaler_calc_method = + 0; + + pdev->smudge_correct_config.x_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_XGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.y_gradient_scaler = + VL53L1_TUNINGPARM_DYNXTALK_YGRADIENT_SCALER_DEFAULT; + pdev->smudge_correct_config.user_scaler_set = + VL53L1_TUNINGPARM_DYNXTALK_USER_SCALER_SET_DEFAULT; + pdev->smudge_correct_config.nodetect_ambient_threshold = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_AMB_THRESHOLD_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_sample_limit = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_SAMPLE_LIMIT_DEFAULT; + pdev->smudge_correct_config.nodetect_xtalk_offset = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_XTALK_OFFSET_KCPS_DEFAULT; + pdev->smudge_correct_config.nodetect_min_range_mm = + VL53L1_TUNINGPARM_DYNXTALK_NODETECT_MIN_RANGE_MM_DEFAULT; + + + + pdev->smudge_corrector_internals.current_samples = 0; + pdev->smudge_corrector_internals.required_samples = 0; + pdev->smudge_corrector_internals.accumulator = 0; + pdev->smudge_corrector_internals.nodetect_counter = 0; + + + + VL53L1_dynamic_xtalk_correction_output_init(pres); + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_dynamic_xtalk_correction_output_init( + VL53L1_LLDriverResults_t *pres + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_smudge_corrector_data_t *pdata; + + LOG_FUNCTION_START(""); + + + + pdata = &(pres->range_results.smudge_corrector_data); + + pdata->smudge_corr_valid = 0; + pdata->smudge_corr_clipped = 0; + pdata->single_xtalk_delta_flag = 0; + pdata->averaged_xtalk_delta_flag = 0; + pdata->sample_limit_exceeded_flag = 0; + pdata->gradient_zero_flag = 0; + pdata->new_xtalk_applied_flag = 0; + + pdata->algo__crosstalk_compensation_plane_offset_kcps = 0; + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_xtalk_cal_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + pdev->xtalk_cal.algo__crosstalk_compensation_plane_offset_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_x_plane_gradient_kcps = 0; + pdev->xtalk_cal.algo__crosstalk_compensation_y_plane_gradient_kcps = 0; + + LOG_FUNCTION_END(status); + + return status; +} + + + + + + + + +VL53L1_Error VL53L1_low_power_auto_data_init( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + pdev->low_power_auto_data.vhv_loop_bound = + VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT; + pdev->low_power_auto_data.is_low_power_auto_mode = 0; + pdev->low_power_auto_data.low_power_auto_range_count = 0; + pdev->low_power_auto_data.saved_interrupt_config = 0; + pdev->low_power_auto_data.saved_vhv_init = 0; + pdev->low_power_auto_data.saved_vhv_timeout = 0; + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_data_stop_range( + VL53L1_DEV Dev + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + + + + + pdev->low_power_auto_data.low_power_auto_range_count = 0xFF; + + pdev->low_power_auto_data.first_run_phasecal_result = 0; + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0; + pdev->low_power_auto_data.dss__required_spads = 0; + + + + if (pdev->low_power_auto_data.saved_vhv_init != 0) + pdev->stat_nvm.vhv_config__init = + pdev->low_power_auto_data.saved_vhv_init; + if (pdev->low_power_auto_data.saved_vhv_timeout != 0) + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + pdev->low_power_auto_data.saved_vhv_timeout; + + + + pdev->gen_cfg.phasecal_config__override = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_config_low_power_auto_mode( + VL53L1_general_config_t *pgeneral, + VL53L1_dynamic_config_t *pdynamic, + VL53L1_low_power_auto_data_t *plpadata + ) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + plpadata->is_low_power_auto_mode = 1; + + + + plpadata->low_power_auto_range_count = 0; + + + + pdynamic->system__sequence_config = + VL53L1_SEQUENCE_VHV_EN | + VL53L1_SEQUENCE_PHASECAL_EN | + VL53L1_SEQUENCE_DSS1_EN | + + + + + + + VL53L1_SEQUENCE_RANGE_EN; + + + + pgeneral->dss_config__manual_effective_spads_select = 200 << 8; + pgeneral->dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration( + VL53L1_DEV Dev) +{ + + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + pdev->low_power_auto_data.saved_vhv_init = + pdev->stat_nvm.vhv_config__init; + pdev->low_power_auto_data.saved_vhv_timeout = + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound; + + + + pdev->stat_nvm.vhv_config__init &= 0x7F; + + + pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound = + (pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) + + (pdev->low_power_auto_data.vhv_loop_bound << 2); + + + pdev->gen_cfg.phasecal_config__override = 0x01; + pdev->low_power_auto_data.first_run_phasecal_result = + pdev->dbg_results.phasecal_result__vcsel_start; + pdev->gen_cfg.cal_config__vcsel_start = + pdev->low_power_auto_data.first_run_phasecal_result; + + LOG_FUNCTION_END(status); + + return status; +} + +VL53L1_Error VL53L1_low_power_auto_update_DSS( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + VL53L1_system_results_t *pS = &(pdev->sys_results); + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint32_t utemp32a; + + LOG_FUNCTION_START(""); + + + + + + + utemp32a = + pS->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 + + pS->result__ambient_count_rate_mcps_sd0; + + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + + + utemp32a = utemp32a << 16; + + + + if (pdev->sys_results.result__dss_actual_effective_spads_sd0 == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + + utemp32a = utemp32a / + pdev->sys_results.result__dss_actual_effective_spads_sd0; + + + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = + utemp32a; + + + + + utemp32a = pdev->stat_cfg.dss_config__target_total_rate_mcps << + 16; + + + + if (pdev->low_power_auto_data.dss__total_rate_per_spad_mcps + == 0) + status = VL53L1_ERROR_DIVISION_BY_ZERO; + else { + + + + utemp32a = utemp32a / + pdev->low_power_auto_data.dss__total_rate_per_spad_mcps; + + + + if (utemp32a > 0xFFFF) + utemp32a = 0xFFFF; + + + + pdev->low_power_auto_data.dss__required_spads = + (uint16_t)utemp32a; + + + + pdev->gen_cfg.dss_config__manual_effective_spads_select + = pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + } + + } + + if (status == VL53L1_ERROR_DIVISION_BY_ZERO) { + + + + + + + pdev->low_power_auto_data.dss__required_spads = 0x8000; + + + + pdev->gen_cfg.dss_config__manual_effective_spads_select = + pdev->low_power_auto_data.dss__required_spads; + pdev->gen_cfg.dss_config__roi_mode_control = + VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS; + + + + status = VL53L1_ERROR_NONE; + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_core_support.c b/drivers/oneplus/vl53L1/src/vl53l1_core_support.c new file mode 100755 index 0000000000000000000000000000000000000000..8a8947b6cfe203f13a5dde9d20d862d2871fe61f --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_core_support.c @@ -0,0 +1,938 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core_support.h" +#include "vl53l1_platform_user_data.h" +#include "vl53l1_platform_user_defines.h" + + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +uint32_t VL53L1_calc_pll_period_us( + uint16_t fast_osc_frequency) +{ + + + + + + + + + + + + + + + uint32_t pll_period_us = 0; + + LOG_FUNCTION_START(""); + + pll_period_us = (0x01 << 30) / fast_osc_frequency; + + + + + + + + LOG_FUNCTION_END(0); + + return pll_period_us; +} + + +uint32_t VL53L1_duration_maths( + uint32_t pll_period_us, + uint32_t vcsel_parm_pclks, + uint32_t window_vclks, + uint32_t elapsed_mclks) +{ + + + + + + + + + + + uint64_t tmp_long_int = 0; + uint32_t duration_us = 0; + + + + + + + duration_us = window_vclks * pll_period_us; + + + + + + duration_us = duration_us >> 12; + + + + tmp_long_int = (uint64_t)duration_us; + + + + + + + duration_us = elapsed_mclks * vcsel_parm_pclks; + + + + + + duration_us = duration_us >> 4; + + + + + + tmp_long_int = tmp_long_int * (uint64_t)duration_us; + + + + + + tmp_long_int = tmp_long_int >> 12; + + + + if (tmp_long_int > 0xFFFFFFFF) + tmp_long_int = 0xFFFFFFFF; + + duration_us = (uint32_t)tmp_long_int; + + return duration_us; +} + + +uint32_t VL53L1_events_per_spad_maths( + int32_t VL53L1_p_013, + uint16_t num_spads, + uint32_t duration) +{ + uint64_t total_hist_counts = 0; + uint64_t xtalk_per_spad = 0; + uint32_t rate_per_spad_kcps = 0; + + + + + + + + + + + + + + + + + + uint64_t dividend = ((uint64_t)VL53L1_p_013 + * 1000 * 256); + + total_hist_counts = do_division_u(dividend, (uint64_t)num_spads); + + + + + if (duration > 0) { + + + + + + + + + uint64_t dividend = (((uint64_t)(total_hist_counts << 11)) + + ((uint64_t)duration / 2)); + + xtalk_per_spad = do_division_u(dividend, (uint64_t)duration); + } else { + xtalk_per_spad = (uint64_t)(total_hist_counts << 11); + } + + rate_per_spad_kcps = (uint32_t)xtalk_per_spad; + + return rate_per_spad_kcps; +} + + +uint32_t VL53L1_isqrt(uint32_t num) +{ + + + + + + + + + uint32_t res = 0; + uint32_t bit = 1 << 30; + + + + + while (bit > num) + bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else { + res >>= 1; + } + bit >>= 2; + } + + return res; +} + + +void VL53L1_hist_calc_zero_distance_phase( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint32_t period = 0; + uint32_t VL53L1_p_017 = 0; + + LOG_FUNCTION_START(""); + + period = 2048 * + (uint32_t)VL53L1_decode_vcsel_period(pdata->VL53L1_p_009); + + VL53L1_p_017 = period; + VL53L1_p_017 += (uint32_t)pdata->phasecal_result__reference_phase; + VL53L1_p_017 += (2048 * (uint32_t)pdata->phasecal_result__vcsel_start); + VL53L1_p_017 -= (2048 * (uint32_t)pdata->cal_config__vcsel_start); + + VL53L1_p_017 = VL53L1_p_017 % period; + + pdata->zero_distance_phase = (uint16_t)VL53L1_p_017; + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_estimate_ambient_from_thresholded_bins( + int32_t ambient_threshold_sigma, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + + + + uint8_t bin = 0; + int32_t VL53L1_p_032 = 0; + + LOG_FUNCTION_START(""); + + + + + + + VL53L1_hist_find_min_max_bin_values(pdata); + + + + + + + + VL53L1_p_032 = + (int32_t)VL53L1_isqrt((uint32_t)pdata->min_bin_value); + VL53L1_p_032 *= ambient_threshold_sigma; + VL53L1_p_032 += 0x07; + VL53L1_p_032 = VL53L1_p_032 >> 4; + VL53L1_p_032 += pdata->min_bin_value; + + + + + + + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) + if (pdata->bin_data[bin] < VL53L1_p_032) { + pdata->ambient_events_sum += pdata->bin_data[bin]; + pdata->number_of_ambient_samples++; + } + + + + + + + if (pdata->number_of_ambient_samples > 0) { + pdata->VL53L1_p_004 = + pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_samples/2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_samples; + } + + LOG_FUNCTION_END(0); +} + + +void VL53L1_hist_remove_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + + uint8_t bin = 0; + uint8_t lc = 0; + uint8_t i = 0; + + + + + if ((pdata->bin_seq[0] & 0x07) == 0x07) { + + i = 0; + for (lc = 0; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + if ((pdata->bin_seq[lc] & 0x07) != 0x07) { + pdata->bin_seq[i] = pdata->bin_seq[lc]; + pdata->bin_rep[i] = pdata->bin_rep[lc]; + i++; + } + } + + + + + + + for (lc = i; lc < VL53L1_MAX_BIN_SEQUENCE_LENGTH; lc++) { + pdata->bin_seq[lc] = VL53L1_MAX_BIN_SEQUENCE_CODE + 1; + pdata->bin_rep[lc] = 0; + } + } + + if (pdata->number_of_ambient_bins > 0) { + + + + for (bin = pdata->number_of_ambient_bins; + bin < pdata->VL53L1_p_023; bin++) { + pdata->bin_data[bin-pdata->number_of_ambient_bins] = + pdata->bin_data[bin]; + } + + + + pdata->VL53L1_p_024 = + pdata->VL53L1_p_024 - + pdata->number_of_ambient_bins; + pdata->number_of_ambient_bins = 0; + } +} + + +uint32_t VL53L1_calc_pll_period_mm( + uint16_t fast_osc_frequency) +{ + + + + + + + uint32_t pll_period_us = 0; + uint32_t pll_period_mm = 0; + + LOG_FUNCTION_START(""); + + + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + + + + + + + pll_period_mm = + VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 * + (pll_period_us >> 2); + + + + pll_period_mm = (pll_period_mm + (0x01<<15)) >> 16; + + LOG_FUNCTION_END(0); + + return pll_period_mm; +} + + +uint16_t VL53L1_rate_maths( + int32_t VL53L1_p_008, + uint32_t time_us) +{ + + + + + + + + + + + + + uint32_t tmp_int = 0; + uint32_t frac_bits = 7; + uint16_t rate_mcps = 0; + + + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_MAX) + tmp_int = VL53L1_SPAD_TOTAL_COUNT_MAX; + else if (VL53L1_p_008 > 0) + tmp_int = (uint32_t)VL53L1_p_008; + + + + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + frac_bits = 3; + else + frac_bits = 7; + + + + + + + + if (time_us > 0) + tmp_int = ((tmp_int << frac_bits) + (time_us / 2)) / time_us; + + + + + + if (VL53L1_p_008 > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) + tmp_int = tmp_int << 4; + + + + + + + + if (tmp_int > 0xFFFF) + tmp_int = 0xFFFF; + + rate_mcps = (uint16_t)tmp_int; + + return rate_mcps; +} + + +uint16_t VL53L1_rate_per_spad_maths( + uint32_t frac_bits, + uint32_t peak_count_rate, + uint16_t num_spads, + uint32_t max_output_value) +{ + + uint32_t tmp_int = 0; + + + + uint16_t rate_per_spad = 0; + + + + + + + + + + if (num_spads > 0) { + tmp_int = (peak_count_rate << 8) << frac_bits; + tmp_int = (tmp_int + + ((uint32_t)num_spads / 2)) / + (uint32_t)num_spads; + } else { + tmp_int = ((peak_count_rate) << frac_bits); + } + + + + + if (tmp_int > max_output_value) + tmp_int = max_output_value; + + rate_per_spad = (uint16_t)tmp_int; + + return rate_per_spad; +} + + +int32_t VL53L1_range_maths( + uint16_t fast_osc_frequency, + uint16_t VL53L1_p_017, + uint16_t zero_distance_phase, + uint8_t fractional_bits, + int32_t gain_factor, + int32_t range_offset_mm) +{ + + + + + + uint32_t pll_period_us = 0; + + int64_t tmp_long_int = 0; + int32_t range_mm = 0; + int32_t range_mm_10 = 0; + + + + + pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency); + + + + + + + + + + + tmp_long_int = (int64_t)VL53L1_p_017 - (int64_t)zero_distance_phase; + + + + + + + + + + + tmp_long_int = tmp_long_int * (int64_t)pll_period_us; + + + + + + + tmp_long_int = tmp_long_int / (0x01 << 9); + + + + + + + + + + + + tmp_long_int = tmp_long_int * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8; + + + + + + + tmp_long_int = tmp_long_int / (0x01 << 22); + + + + range_mm = (int32_t)tmp_long_int + range_offset_mm; + + + + range_mm *= gain_factor; + range_mm += 0x0400; + range_mm /= 0x0800; + + + + if (fractional_bits == 0) { + range_mm_10 = range_mm * 10; + range_mm_10 = range_mm_10 / (0x01 << 2); + if ((range_mm_10 % 10) < 5) + range_mm = (int16_t)(range_mm_10 / 10); + else + range_mm = (int16_t)(range_mm_10 / 10 + 1); + } else if (fractional_bits == 1) + range_mm = range_mm / (0x01 << 1); + + return range_mm; +} + + +uint8_t VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg) +{ + + + + + + + uint8_t VL53L1_p_031 = 0; + + VL53L1_p_031 = (vcsel_period_reg + 1) << 1; + + return VL53L1_p_031; +} + + +void VL53L1_copy_xtalk_bin_data_to_histogram_data_struct( + VL53L1_xtalk_histogram_shape_t *pxtalk, + VL53L1_histogram_bin_data_t *phist) +{ + + + + + + + phist->cal_config__vcsel_start = + pxtalk->cal_config__vcsel_start; + phist->VL53L1_p_019 = + pxtalk->VL53L1_p_019; + phist->VL53L1_p_022 = + pxtalk->VL53L1_p_022; + + phist->phasecal_result__reference_phase = + pxtalk->phasecal_result__reference_phase; + phist->phasecal_result__vcsel_start = + pxtalk->phasecal_result__vcsel_start; + + phist->vcsel_width = + pxtalk->vcsel_width; + phist->zero_distance_phase = + pxtalk->zero_distance_phase; + + phist->zone_id = pxtalk->zone_id; + phist->VL53L1_p_023 = pxtalk->VL53L1_p_023; + phist->time_stamp = pxtalk->time_stamp; +} + + +void VL53L1_init_histogram_bin_data_struct( + int32_t bin_value, + uint16_t VL53L1_p_024, + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint16_t i = 0; + + pdata->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + pdata->rd_device_state = VL53L1_DEVICESTATE_SW_STANDBY; + + pdata->zone_id = 0; + pdata->time_stamp = 0; + + pdata->VL53L1_p_022 = 0; + pdata->VL53L1_p_023 = VL53L1_HISTOGRAM_BUFFER_SIZE; + pdata->VL53L1_p_024 = (uint8_t)VL53L1_p_024; + pdata->number_of_ambient_bins = 0; + + pdata->result__interrupt_status = 0; + pdata->result__range_status = 0; + pdata->result__report_status = 0; + pdata->result__stream_count = 0; + + pdata->result__dss_actual_effective_spads = 0; + pdata->phasecal_result__reference_phase = 0; + pdata->phasecal_result__vcsel_start = 0; + pdata->cal_config__vcsel_start = 0; + + pdata->vcsel_width = 0; + pdata->VL53L1_p_009 = 0; + pdata->VL53L1_p_019 = 0; + pdata->total_periods_elapsed = 0; + + pdata->min_bin_value = 0; + pdata->max_bin_value = 0; + + pdata->zero_distance_phase = 0; + pdata->number_of_ambient_samples = 0; + pdata->ambient_events_sum = 0; + pdata->VL53L1_p_004 = 0; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_seq[i] = (uint8_t)i; + + for (i = 0; i < VL53L1_MAX_BIN_SEQUENCE_LENGTH; i++) + pdata->bin_rep[i] = 1; + + + for (i = 0; i < VL53L1_HISTOGRAM_BUFFER_SIZE; i++) + if (i < VL53L1_p_024) + pdata->bin_data[i] = bin_value; + else + pdata->bin_data[i] = 0; + + +} + + +void VL53L1_decode_row_col( + uint8_t spad_number, + uint8_t *prow, + uint8_t *pcol) +{ + + + + + + + + if (spad_number > 127) { + *prow = 8 + ((255-spad_number) & 0x07); + *pcol = (spad_number-128) >> 3; + } else { + *prow = spad_number & 0x07; + *pcol = (127-spad_number) >> 3; + } +} + + +void VL53L1_hist_find_min_max_bin_values( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + for (bin = 0; bin < pdata->VL53L1_p_024; bin++) { + + if (bin == 0 || pdata->min_bin_value >= pdata->bin_data[bin]) + pdata->min_bin_value = pdata->bin_data[bin]; + + if (bin == 0 || pdata->max_bin_value <= pdata->bin_data[bin]) + pdata->max_bin_value = pdata->bin_data[bin]; + + } + + LOG_FUNCTION_END(0); + +} + + +void VL53L1_hist_estimate_ambient_from_ambient_bins( + VL53L1_histogram_bin_data_t *pdata) +{ + + + + + + + uint8_t bin = 0; + + LOG_FUNCTION_START(""); + + if (pdata->number_of_ambient_bins > 0) { + + pdata->number_of_ambient_samples = + pdata->number_of_ambient_bins; + + + + + pdata->ambient_events_sum = 0; + for (bin = 0; bin < pdata->number_of_ambient_bins; bin++) + pdata->ambient_events_sum += pdata->bin_data[bin]; + + pdata->VL53L1_p_004 = pdata->ambient_events_sum; + pdata->VL53L1_p_004 += + ((int32_t)pdata->number_of_ambient_bins / 2); + pdata->VL53L1_p_004 /= + (int32_t)pdata->number_of_ambient_bins; + + } + + LOG_FUNCTION_END(0); +} + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_error_strings.c b/drivers/oneplus/vl53L1/src/vl53l1_error_strings.c new file mode 100755 index 0000000000000000000000000000000000000000..e8e9920e4a368eca206ee6672b1624b3d67148f0 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_error_strings.c @@ -0,0 +1,334 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_error_codes.h" +#include "vl53l1_error_strings.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_ll_def.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, \ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_get_pal_error_string( +#ifndef VL53L1_USE_EMPTY_STRING + VL53L1_Error PalErrorCode, +#endif + char *pPalErrorString) +{ + VL53L1_Error Status = VL53L1_ERROR_NONE; + +#ifdef VL53L1_USE_EMPTY_STRING + SUPPRESS_UNUSED_WARNING(PalErrorCode); +#endif + + LOG_FUNCTION_START(""); + +#ifdef VL53L1_USE_EMPTY_STRING + VL53L1_COPYSTRING(pPalErrorString, ""); +#else + + switch (PalErrorCode) { + case VL53L1_ERROR_NONE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NONE); + break; + case VL53L1_ERROR_CALIBRATION_WARNING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CALIBRATION_WARNING); + break; + case VL53L1_ERROR_MIN_CLIPPED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MIN_CLIPPED); + break; + case VL53L1_ERROR_UNDEFINED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNDEFINED); + break; + case VL53L1_ERROR_INVALID_PARAMS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_PARAMS); + break; + case VL53L1_ERROR_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_SUPPORTED); + break; + case VL53L1_ERROR_RANGE_ERROR: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_RANGE_ERROR); + break; + case VL53L1_ERROR_TIME_OUT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_TIME_OUT); + break; + case VL53L1_ERROR_MODE_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED); + break; + case VL53L1_ERROR_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL); + break; + case VL53L1_ERROR_GPIO_NOT_EXISTING: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_NOT_EXISTING); + break; + case VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED); + break; + case VL53L1_ERROR_CONTROL_INTERFACE: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_CONTROL_INTERFACE); + break; + case VL53L1_ERROR_INVALID_COMMAND: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_INVALID_COMMAND); + break; + case VL53L1_ERROR_DIVISION_BY_ZERO: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DIVISION_BY_ZERO); + break; + case VL53L1_ERROR_REF_SPAD_INIT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_REF_SPAD_INIT); + break; + case VL53L1_ERROR_GPH_SYNC_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL); + break; + case VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL); + break; + case VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL); + break; + + case VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL); + break; + case VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL); + break; + + case VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL); + break; + case VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL); + break; + case VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL); + break; + + case VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW); + break; + + case VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES); + break; + case VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH); + break; + case VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH); + break; + + case VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH); + break; + case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW); + break; + + case VL53L1_WARNING_XTALK_MISSING_SAMPLES: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES); + break; + case VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT); + break; + case VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT); + break; + + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD); + break; + case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW); + break; + case VL53L1_ERROR_UNIT_TEST_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_UNIT_TEST_FAIL); + break; + case VL53L1_ERROR_FILE_READ_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_READ_FAIL); + break; + case VL53L1_ERROR_FILE_WRITE_FAIL: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_FILE_WRITE_FAIL); + break; + case VL53L1_ERROR_NOT_IMPLEMENTED: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_ERROR_NOT_IMPLEMENTED); + break; + default: + VL53L1_COPYSTRING(pPalErrorString, + VL53L1_STRING_UNKNOW_ERROR_CODE); + } + +#endif + + LOG_FUNCTION_END(Status); + + return Status; +} + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_hist_char.c b/drivers/oneplus/vl53L1/src/vl53l1_hist_char.c new file mode 100755 index 0000000000000000000000000000000000000000..5f13482e28e576ccfc22b52a8aac2c0c73f28de7 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_hist_char.c @@ -0,0 +1,282 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include + +#include + + + + + + + +#include "vl53l1_core.h" +#include "vl53l1_register_settings.h" +#include "vl53l1_hist_char.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_HISTOGRAM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_HISTOGRAM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_HISTOGRAM,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_set_calib_config( + VL53L1_DEV Dev, + uint8_t vcsel_delay__a0, + uint8_t calib_1, + uint8_t calib_2, + uint8_t calib_3, + uint8_t calib_2__a0, + uint8_t spad_readout) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[3]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_enable_powerforce(Dev); + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__VCSEL_DELAY__A0, + vcsel_delay__a0); + } + + + + + if (status == VL53L1_ERROR_NONE) { + + + + + + + + comms_buffer[0] = calib_1; + comms_buffer[1] = calib_2; + comms_buffer[2] = calib_3; + + status = VL53L1_WriteMulti( + Dev, + VL53L1_RANGING_CORE__CALIB_1, + comms_buffer, + 3); + } + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CALIB_2__A0, + calib_2__a0); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__SPAD_READOUT, + spad_readout); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + + +VL53L1_Error VL53L1_set_hist_calib_pulse_delay( + VL53L1_DEV Dev, + uint8_t calib_delay) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x01, + + calib_delay, + + 0x04, + + 0x08, + + 0x14, + + VL53L1_RANGING_CORE__SPAD_READOUT__CALIB_PULSES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_disable_calib_pulse_delay( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + status = + VL53L1_set_calib_config( + Dev, + 0x00, + + 0x00, + + 0x00, + + 0x00, + + 0x00, + + VL53L1_RANGING_CORE__SPAD_READOUT__STANDARD); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_nvm.c b/drivers/oneplus/vl53L1/src/vl53l1_nvm.c new file mode 100755 index 0000000000000000000000000000000000000000..1a0175fa6a3f151a60fc7d3fc667c52e3af8a53c --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_nvm.c @@ -0,0 +1,1751 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef _MSC_VER +#define snprintf _snprintf +#endif + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_map.h" +#include "vl53l1_nvm.h" + + + + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_NVM, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_nvm_enable( + VL53L1_DEV Dev, + uint16_t nvm_ctrl_pulse_width, + int32_t nvm_power_up_delay_us) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_powerforce(Dev); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_ENABLE_POWERFORCE_SETTLING_TIME_US); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x01); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__CLK_CTRL1, + 0x05); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + nvm_power_up_delay_us); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__MODE, + 0x01); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrWord( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PULSE_WIDTH_MSB, + nvm_ctrl_pulse_width); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_read( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pdata) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t nvm_addr = 0; + + LOG_FUNCTION_START(""); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "nvm_addr", nvm_addr, nvm_addr); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%-12s = 0x%02X (%3u)\n", + "count", count, count); + + for (nvm_addr = start_address; + nvm_addr < (start_address+count) ; nvm_addr++) { + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__ADDR, + nvm_addr); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x00); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WaitUs( + Dev, + VL53L1_NVM_READ_TRIGGER_DELAY_US); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__DATAOUT_MMM, + pdata, + 4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "NVM address : 0x%02X = 0x%02X%02X%02X%02X\n", + nvm_addr, *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); + + + + + pdata = pdata + 4; + + + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_nvm_disable( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__READN, + 0x01); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WrByte( + Dev, + VL53L1_RANGING_CORE__NVM_CTRL__PDN, + 0x00); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_powerforce(Dev); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_format_decode( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_data_t *pdata) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i = 0; + uint8_t *ptmp = NULL; + int pptmp[VL53L1_NVM_MAX_FMT_RANGE_DATA]; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__identification_model_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODEL_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_module_type = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_TYPE, + 0x000000FF, + 0, + 0); + pdata->nvm__identification_revision_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__IDENTIFICATION__REVISION_ID, + 0x0000000F, + 0, + 0); + pdata->nvm__identification_module_id = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__IDENTIFICATION__MODULE_ID, + 0x0000FFFF, + 0, + 0); + pdata->nvm__i2c_valid = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_VALID, + 0x000000FF, + 0, + 0); + pdata->nvm__i2c_device_address_ews = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__EWS__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__ews__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__ews__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__ews__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__fmt__fast_osc_frequency = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__OSC_MEASURED__FAST_OSC_FREQUENCY, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__fast_osc_trim_max = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_TRIM_MAX, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fast_osc_freq_set = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FAST_OSC_FREQ_SET, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__slow_osc_calibration = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__SLOW_OSC_CALIBRATION, + 0x000003FF, + 0, + 0); + pdata->nvm__vhv_config_unlock = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG_UNLOCK, + 0x000000FF, + 0, + 0); + pdata->nvm__ref_selvddpix = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVDDPIX, + 0x0000000F, + 0, + 0); + pdata->nvm__ref_selvquench = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REF_SELVQUENCH, + 0x00000078, + 3, + 0); + pdata->nvm__regavdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x0000000C, + 2, + 0); + pdata->nvm__regdvdd1v2_sel = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__REGAVDD1V2_SEL_REGDVDD1V2_SEL, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_timeout__macrop = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x00000003, + 0, + 0); + pdata->nvm__vhv_loop_bound = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__VHV_CONFIG__TIMEOUT_MACROP_LOOP_BOUND, + 0x000000FC, + 2, + 0); + pdata->nvm__vhv_count_threshold = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__COUNT_THRESH, + 0x000000FF, + 0, + 0); + pdata->nvm__vhv_offset = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__OFFSET, + 0x0000003F, + 0, + 0); + pdata->nvm__vhv_init_enable = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x00000080, + 7, + 0); + pdata->nvm__vhv_init_value = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__VHV_CONFIG__INIT, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LL, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ll = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LL, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_trim_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_TRIM_LD, + 0x00000007, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_vcsel_selion_max_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__VCSEL_SELION_MAX_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_mult_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__MULT_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_clip_ld = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY__CLIP_LD, + 0x0000003F, + 0, + 0); + pdata->nvm__laser_safety_lock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_LOCK_BYTE, + 0x000000FF, + 0, + 0); + pdata->nvm__laser_safety_unlock_byte = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__LASER_SAFETY_UNLOCK_BYTE, + 0x000000FF, + 0, + 0); + + + + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__EWS__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__ews__spad_enables_ref__loc3[i] = *ptmp++; + + + + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_RTN_0_; + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_rtn[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC1_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc1[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC2_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc2[i] = *ptmp++; + + ptmp = pbuffer + VL53L1_NVM__FMT__SPAD_ENABLES_REF__LOC3_0_; + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) + pdata->nvm__fmt__spad_enables_ref__loc3[i] = *ptmp++; + + + pdata->nvm__fmt__roi_config__mode_roi_centre_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_CENTRE_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__roi_config__mode_roi_x_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__roi_config__mode_roi_y_size = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__ROI_CONFIG__MODE_ROI_XY_SIZE, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__fmt__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__FMT__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__FMT__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + pdata->nvm__customer_space_programmed = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUSTOMER_NVM_SPACE_PROGRAMMED, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__i2c_device_address = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__I2C_SLAVE__DEVICE_ADDRESS, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__REF_SPAD_APPLY__NUM_REQUESTED_REF_SPAD, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__ref_spad_man__ref_location = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__REF_SPAD_MAN__REF_LOCATION, + 0x00000003, + 0, + 0); + pdata->nvm__cust__mm_config__inner_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__INNER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__mm_config__outer_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__CUST__MM_CONFIG__OUTER_OFFSET_MM, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo_part_to_part_range_offset_mm = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__PART_TO_PART_RANGE_OFFSET_MM, + 0x00000FFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_X_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + + VL53L1_NVM__CUST__ALGO__CROSSTALK_COMPENSATION_Y_PLANE_GRADIENT_KCPS, + 0x0000FFFF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_0 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_0, + 0x000000FF, + 0, + 0); + pdata->nvm__cust__spare__host_config__nvm_config_spare_1 = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + + VL53L1_NVM__CUST__SPARE_HOST_CONFIG__NVM_CONFIG_SPARE_1, + 0x000000FF, + 0, + 0); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + buf_size, + pbuffer + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX, + &(pdata->fmt_optical_centre)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + buf_size, + pbuffer + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX, + &(pdata->fmt_peak_rate_map)); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_additional_offset_cal_data( + buf_size, + pbuffer + + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX, + &(pdata->fmt_add_offset_data)); + + + + + pptmp[0] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_MM_PRE_RANGE; + pptmp[1] = VL53L1_NVM__FMT__RANGE_RESULTS__140MM_DARK; + pptmp[2] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_DARK; + pptmp[3] = VL53L1_NVM__FMT__RANGE_RESULTS__400MM_AMBIENT; + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + buf_size, + pbuffer + pptmp[i], + &(pdata->fmt_range_data[i])); + } + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_info( + buf_size, + pbuffer, + &(pdata->fmt_info)); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_ews_info( + buf_size, + pbuffer, + &(pdata->ews_info)); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_nvm_decode_optical_centre( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_optical_centre_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint16_t tmp = 0; + + if (buf_size < VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + + + + + tmp = 0x0100; + tmp -= (uint16_t)*(pbuffer + 2); + if (tmp > 0x0FF) + tmp = 0; + + pdata->x_centre = (uint8_t)tmp; + pdata->y_centre = *(pbuffer + 3); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_cal_peak_rate_map( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_cal_peak_rate_map_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t *ptmp = NULL; + uint8_t i = 0; + + if (buf_size < VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->cal_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->cal_reflectance_pc = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + pdata->cal_reflectance_pc = + pdata->cal_reflectance_pc >> 6; + + pdata->max_samples = VL53L1_NVM_PEAK_RATE_MAP_SAMPLES; + pdata->width = VL53L1_NVM_PEAK_RATE_MAP_WIDTH; + pdata->height = VL53L1_NVM_PEAK_RATE_MAP_HEIGHT; + + ptmp = pbuffer + 4; + for (i = 0 ; i < VL53L1_NVM_PEAK_RATE_MAP_SAMPLES ; i++) { + pdata->peak_rate_mcps[i] = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, ptmp); + ptmp += 2; + } + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_additional_offset_cal_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_additional_offset_cal_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__mm_inner_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->result__mm_outer_actual_effective_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 2); + + pdata->result__mm_inner_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__mm_outer_peak_signal_count_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_range_results_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_range_data_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->result__actual_effective_rtn_spads = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer); + + pdata->ref_spad_array__num_requested_ref_spads = + *(pbuffer+2); + + pdata->ref_spad_array__ref_location = + *(pbuffer+3); + + pdata->result__peak_signal_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 4); + + pdata->result__ambient_count_rate_rtn_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 6); + + pdata->result__peak_signal_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 8); + + pdata->result__ambient_count_rate_ref_mcps = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 10); + + pdata->measured_distance_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 12); + + pdata->measured_distance_stdev_mm = + (uint16_t)VL53L1_i2c_decode_uint16_t(2, pbuffer + 14); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_fmt_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_fmt_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__fmt__fgc[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_0, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[1] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_1, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[2] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_2 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_3 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_4 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[5] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_5 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[6] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[7] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_6, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[8] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_7, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[9] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_8, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[10] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_9 - 1, + 0x000003F8, + 3, + 0); + pdata->nvm__fmt__fgc[11] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_10 - 1, + 0x000007F0, + 4, + 0); + pdata->nvm__fmt__fgc[12] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_11 - 1, + 0x00000FE0, + 5, + 0); + pdata->nvm__fmt__fgc[13] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_12 - 1, + 0x00001FC0, + 6, + 0); + pdata->nvm__fmt__fgc[14] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13 - 1, + 0x00003F80, + 7, + 0); + pdata->nvm__fmt__fgc[15] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_13, + 0x0000007F, + 0, + 0); + pdata->nvm__fmt__fgc[16] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_14, + 0x000000FE, + 1, + 0); + pdata->nvm__fmt__fgc[17] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__FGC__BYTE_15, + 0x000001FC, + 2, + 0); + pdata->nvm__fmt__fgc[18] = 0x00; + + pdata->nvm__fmt__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__map_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__fmt__map_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__MAP_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__fmt__year = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x000000F0, + 4, + 0); + pdata->nvm__fmt__month = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__YEAR_MONTH, + 0x0000000F, + 0, + 0); + pdata->nvm__fmt__day = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x000000F8, + 3, + 0); + pdata->nvm__fmt__module_date_phase = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__DAY_MODULE_DATE_PHASE, + 0x00000007, + 0, + 0); + pdata->nvm__fmt__time = + (uint16_t)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__FMT__TIME, + 0x0000FFFF, + 0, + 0); + pdata->nvm__fmt__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__fmt__site_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__FMT__SITE_ID, + 0x000000FF, + 0, + 0); + + return status; +} + + +VL53L1_Error VL53L1_nvm_decode_ews_info( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_decoded_nvm_ews_info_t *pdata) +{ + + VL53L1_Error status = VL53L1_ERROR_NONE; + + if (buf_size < VL53L1_NVM_SIZE_IN_BYTES) + return VL53L1_ERROR_BUFFER_TOO_SMALL; + + pdata->nvm__ews__test_program_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x000000E0, + 5, + 0); + pdata->nvm__ews__test_program_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TEST_PROGRAM_MAJOR_MINOR, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__probe_card_major = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x000000F0, + 4, + 0); + pdata->nvm__ews__probe_card_minor = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__PROBE_CARD_MAJOR_MINOR, + 0x0000000F, + 0, + 0); + pdata->nvm__ews__tester_id = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__TESTER_ID, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__lot[0] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_0, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[1] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_1 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[2] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2 - 1, + 0x00000FC0, + 6, + 32); + pdata->nvm__ews__lot[3] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_2, + 0x0000003F, + 0, + 32); + pdata->nvm__ews__lot[4] = + (char)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_3, + 0x000000FC, + 2, + 32); + pdata->nvm__ews__lot[5] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_4 - 1, + 0x000003F0, + 4, + 32); + pdata->nvm__ews__lot[6] = + (char)VL53L1_i2c_decode_with_mask( + 2, + pbuffer + VL53L1_NVM__EWS__LOT__BYTE_5 - 1, + 0x00000FC0, + 6, + 32); + + pdata->nvm__ews__lot[7] = 0x00; + + pdata->nvm__ews__wafer = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__WAFER, + 0x0000001F, + 0, + 0); + pdata->nvm__ews__xcoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__XCOORD, + 0x000000FF, + 0, + 0); + pdata->nvm__ews__ycoord = + (uint8_t)VL53L1_i2c_decode_with_mask( + 1, + pbuffer + VL53L1_NVM__EWS__YCOORD, + 0x000000FF, + 0, + 0); + + return status; + +} + + +void VL53L1_nvm_format_encode( + VL53L1_decoded_nvm_data_t *pnvm_info, + uint8_t *pnvm_data) +{ + SUPPRESS_UNUSED_WARNING(pnvm_info); + SUPPRESS_UNUSED_WARNING(pnvm_data); +} + + +VL53L1_Error VL53L1_read_nvm_raw_data( + VL53L1_DEV Dev, + uint8_t start_address, + uint8_t count, + uint8_t *pnvm_raw_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_nvm_enable( + Dev, + 0x0004, + VL53L1_NVM_POWER_UP_DELAY_US); + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_read( + Dev, + start_address, + count, + pnvm_raw_data); + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_disable(Dev); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm( + VL53L1_DEV Dev, + uint8_t nvm_format, + VL53L1_decoded_nvm_data_t *pnvm_info) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM_SIZE_IN_BYTES]; + + LOG_FUNCTION_START(""); + + SUPPRESS_UNUSED_WARNING(nvm_format); + + + + + status = VL53L1_read_nvm_raw_data( + Dev, + 0, + VL53L1_NVM_SIZE_IN_BYTES >> 2, + nvm_data); + + + + + + + + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_format_decode( + VL53L1_NVM_SIZE_IN_BYTES, + nvm_data, + pnvm_info); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_optical_centre( + VL53L1_DEV Dev, + VL53L1_optical_centre_t *pcentre) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE + >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_optical_centre( + VL53L1_NVM__FMT__OPTICAL_CENTRE_DATA_SIZE, + nvm_data, + pcentre); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_cal_peak_rate_map( + VL53L1_DEV Dev, + VL53L1_cal_peak_rate_map_t *pcal_data) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_INDEX + >> 2), + (uint8_t)(VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE + >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_cal_peak_rate_map( + VL53L1_NVM__FMT__CAL_PEAK_RATE_MAP_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_read_nvm_additional_offset_cal_data( + VL53L1_DEV Dev, + VL53L1_additional_offset_cal_data_t *pcal_data) +{ + + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE]; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_INDEX >> 2), + (uint8_t)( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_nvm_decode_additional_offset_cal_data( + VL53L1_NVM__FMT__ADDITIONAL_OFFSET_CAL_DATA_SIZE, + nvm_data, + pcal_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_read_nvm_fmt_range_results_data( + VL53L1_DEV Dev, + uint16_t range_results_select, + VL53L1_decoded_nvm_fmt_range_data_t *prange_data) +{ + + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + + + uint8_t nvm_data[2*VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_read_nvm_raw_data( + Dev, + (uint8_t)(range_results_select >> 2), + (uint8_t)(VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES >> 2), + nvm_data); + + + + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_nvm_decode_fmt_range_results_data( + VL53L1_NVM__FMT__RANGE_RESULTS__SIZE_BYTES, + nvm_data, + prange_data); + + LOG_FUNCTION_END(status); + + return status; + +} + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_nvm_debug.c b/drivers/oneplus/vl53L1/src/vl53l1_nvm_debug.c new file mode 100755 index 0000000000000000000000000000000000000000..b1acfd144577c8d68774f81b6166ccf323ef77c7 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_nvm_debug.c @@ -0,0 +1,1126 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_register_map.h" +#include "vl53l1_api_debug.h" +#include "vl53l1_nvm_structs.h" +#include "vl53l1_nvm_debug.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_NVM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_NVM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_NVM,\ + status, fmt, ##__VA_ARGS__) + +#define trace_print(level, ...) \ + _LOG_TRACE_PRINT(trace_flags, \ + level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__) + +#ifdef VL53L1_LOG_ENABLE + +void VL53L1_print_nvm_raw_data( + uint8_t *pnvm_raw_data, + uint32_t trace_flags) +{ + + + + + + int i = 0; + + LOG_FUNCTION_START(""); + + for (i = 0 ; i < VL53L1_NVM_SIZE_IN_BYTES ; i++) { + if (i % 4 == 0) + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n NVM Addr 0x%02X : 0x", + i/4); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%02X", + *pnvm_raw_data++); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "\n"); + + LOG_FUNCTION_END(0); +} + + +void VL53L1_print_decoded_nvm_data( + VL53L1_decoded_nvm_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + char pre_text[VL53L1_MAX_STRING_LENGTH]; + char *ppre_text = &(pre_text[0]); + + uint8_t i = 0; + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_model_id", + pdata->nvm__identification_model_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_type", + pdata->nvm__identification_module_type); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_revision_id", + pdata->nvm__identification_revision_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__identification_module_id", + pdata->nvm__identification_module_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_valid", + pdata->nvm__i2c_valid); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__i2c_device_address_ews", + pdata->nvm__i2c_device_address_ews); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__ews__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__ews__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_trim_max", + pdata->nvm__ews__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__fast_osc_freq_set", + pdata->nvm__ews__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__slow_osc_calibration", + pdata->nvm__ews__slow_osc_calibration); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__fast_osc_frequency, + 12, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__fast_osc_frequency", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_trim_max", + pdata->nvm__fmt__fast_osc_trim_max); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__fast_osc_freq_set", + pdata->nvm__fmt__fast_osc_freq_set); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__slow_osc_calibration", + pdata->nvm__fmt__slow_osc_calibration); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_config_unlock", + pdata->nvm__vhv_config_unlock); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvddpix", + pdata->nvm__ref_selvddpix); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ref_selvquench", + pdata->nvm__ref_selvquench); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regavdd1v2_sel", + pdata->nvm__regavdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__regdvdd1v2_sel", + pdata->nvm__regdvdd1v2_sel); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_timeout__macrop", + pdata->nvm__vhv_timeout__macrop); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_loop_bound", + pdata->nvm__vhv_loop_bound); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_count_threshold", + pdata->nvm__vhv_count_threshold); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_offset", + pdata->nvm__vhv_offset); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_enable", + pdata->nvm__vhv_init_enable); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__vhv_init_value", + pdata->nvm__vhv_init_value); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ll", + pdata->nvm__laser_safety_vcsel_trim_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ll", + pdata->nvm__laser_safety_vcsel_selion_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ll", + pdata->nvm__laser_safety_vcsel_selion_max_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ll", + pdata->nvm__laser_safety_mult_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ll", + pdata->nvm__laser_safety_clip_ll); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_trim_ld", + pdata->nvm__laser_safety_vcsel_trim_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_ld", + pdata->nvm__laser_safety_vcsel_selion_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_vcsel_selion_max_ld", + pdata->nvm__laser_safety_vcsel_selion_max_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_mult_ld", + pdata->nvm__laser_safety_mult_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_clip_ld", + pdata->nvm__laser_safety_clip_ld); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_lock_byte", + pdata->nvm__laser_safety_lock_byte); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__laser_safety_unlock_byte", + pdata->nvm__laser_safety_unlock_byte); + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__ews__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__ews__spad_enables_ref__loc3[i]); + } + + + + + + for (i = 0 ; i < VL53L1_RTN_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_rtn[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_rtn[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc1[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc1[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc2[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc2[i]); + } + + for (i = 0 ; i < VL53L1_REF_SPAD_BUFFER_SIZE ; i++) { + sprintf( + ppre_text, + "%snvm__fmt__spad_enables_ref__loc3[%u]", + pprefix, i); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s = %u\n", + ppre_text, + pdata->nvm__fmt__spad_enables_ref__loc3[i]); + } + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_centre_spad", + pdata->nvm__fmt__roi_config__mode_roi_centre_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_x_size", + pdata->nvm__fmt__roi_config__mode_roi_x_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__roi_config__mode_roi_y_size", + pdata->nvm__fmt__roi_config__mode_roi_y_size); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__fmt__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__ref_spad_man__ref_location", + pdata->nvm__fmt__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__inner_offset_mm", + pdata->nvm__fmt__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__fmt__mm_config__outer_offset_mm", + pdata->nvm__fmt__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__fmt__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__fmt__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_0", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__spare__host_config__nvm_config_spare_1", + pdata->nvm__fmt__spare__host_config__nvm_config_spare_1); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__customer_space_programmed", + pdata->nvm__customer_space_programmed); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__i2c_device_address", + pdata->nvm__cust__i2c_device_address); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_apply__num_requested_ref_spad", + pdata->nvm__cust__ref_spad_apply__num_requested_ref_spad); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__ref_spad_man__ref_location", + pdata->nvm__cust__ref_spad_man__ref_location); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__inner_offset_mm", + pdata->nvm__cust__mm_config__inner_offset_mm); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %d\n", + pprefix, + "nvm__cust__mm_config__outer_offset_mm", + pdata->nvm__cust__mm_config__outer_offset_mm); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->nvm__cust__algo_part_to_part_range_offset_mm, + 2, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo_part_to_part_range_offset_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_plane_offset_kcps), + 9, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_plane_offset_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_x_plane_gradient_kcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)( + pdata->nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps), + 11, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "nvm__cust__algo__crosstalk_compensation_y_plane_gradient_kcps", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_0", + pdata->nvm__cust__spare__host_config__nvm_config_spare_0); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__cust__spare__host_config__nvm_config_spare_1", + pdata->nvm__cust__spare__host_config__nvm_config_spare_1); + + + + + sprintf( + ppre_text, + "%sfmt_optical_centre.", pprefix); + + VL53L1_print_optical_centre( + &(pdata->fmt_optical_centre), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + sprintf( + ppre_text, + "%sfmt_peak_rate_map.", pprefix); + + VL53L1_print_cal_peak_rate_map( + &(pdata->fmt_peak_rate_map), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + sprintf( + ppre_text, + "%sfmt_add_offset_data.", + pprefix); + + VL53L1_print_additional_offset_cal_data( + &(pdata->fmt_add_offset_data), + ppre_text, + VL53L1_TRACE_MODULE_NVM_DATA); + + + + + for (i = 0 ; i < VL53L1_NVM_MAX_FMT_RANGE_DATA ; i++) { + sprintf( + ppre_text, + "%sfmt_range_data[%u].", + pprefix, i); + + VL53L1_print_decoded_nvm_fmt_range_data( + &(pdata->fmt_range_data[i]), + ppre_text, + trace_flags); + } + + sprintf( + ppre_text, + "%sfmt_info.", + pprefix); + + VL53L1_print_decoded_nvm_fmt_info( + &(pdata->fmt_info), + ppre_text, + trace_flags); + + sprintf( + ppre_text, + "%sews_info.", + pprefix); + + VL53L1_print_decoded_nvm_ews_info( + &(pdata->ews_info), + ppre_text, + trace_flags); +} + + +void VL53L1_print_decoded_nvm_fmt_range_data( + VL53L1_decoded_nvm_fmt_range_data_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + char fp_text[VL53L1_MAX_STRING_LENGTH]; + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__actual_effective_rtn_spads, + 8, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__actual_effective_rtn_spads", + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__num_requested_ref_spads", + pdata->ref_spad_array__num_requested_ref_spads); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "ref_spad_array__ref_location", + pdata->ref_spad_array__ref_location); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__peak_signal_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_rtn_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_rtn_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__peak_signal_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "result__peak_signal_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->result__ambient_count_rate_ref_mcps, + 7, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "result__ambient_count_rate_ref_mcps", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (int32_t)pdata->measured_distance_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_mm", + fp_text); + + VL53L1_signed_fixed_point_sprintf( + (uint32_t)pdata->measured_distance_stdev_mm, + 4, + VL53L1_MAX_STRING_LENGTH, + fp_text); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %s\n", + pprefix, + "measured_distance_stdev_mm", + fp_text); +} + + +void VL53L1_print_decoded_nvm_fmt_info( + VL53L1_decoded_nvm_fmt_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__fmt__fgc", + pdata->nvm__fmt__fgc); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_major", + pdata->nvm__fmt__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__test_program_minor", + pdata->nvm__fmt__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_major", + pdata->nvm__fmt__map_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__map_minor", + pdata->nvm__fmt__map_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__year", + pdata->nvm__fmt__year); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__month", + pdata->nvm__fmt__month); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__day", + pdata->nvm__fmt__day); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__module_date_phase", + pdata->nvm__fmt__module_date_phase); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__time", + pdata->nvm__fmt__time); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__tester_id", + pdata->nvm__fmt__tester_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__fmt__site_id", + pdata->nvm__fmt__site_id); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_major", + pdata->nvm__ews__test_program_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__test_program_minor", + pdata->nvm__ews__test_program_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_major", + pdata->nvm__ews__probe_card_major); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__probe_card_minor", + pdata->nvm__ews__probe_card_minor); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__tester_id", + pdata->nvm__ews__tester_id); +} + + +void VL53L1_print_decoded_nvm_ews_info( + VL53L1_decoded_nvm_ews_info_t *pdata, + char *pprefix, + uint32_t trace_flags) +{ + trace_print(VL53L1_TRACE_LEVEL_INFO, + "%s%s = \"%s\"\n", + pprefix, + "nvm__ews__lot", + pdata->nvm__ews__lot); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__wafer", + pdata->nvm__ews__wafer); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__xcoord", + pdata->nvm__ews__xcoord); + + trace_print( + VL53L1_TRACE_LEVEL_INFO, + "%s%s = %u\n", + pprefix, + "nvm__ews__ycoord", + pdata->nvm__ews__ycoord); +} + +#endif + + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_register_funcs.c b/drivers/oneplus/vl53L1/src/vl53l1_register_funcs.c new file mode 100755 index 0000000000000000000000000000000000000000..21d886e8ae77af67dfae11fb62230bc57c1de49b --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_register_funcs.c @@ -0,0 +1,4596 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_core.h" +#include "vl53l1_register_map.h" +#include "vl53l1_register_structs.h" +#include "vl53l1_register_funcs.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_REGISTERS, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_REGISTERS, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_REGISTERS,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_i2c_encode_static_nvm_managed( + VL53L1_static_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->i2c_slave__device_address & 0x7F; + *(pbuffer + 1) = + pdata->ana_config__vhv_ref_sel_vddpix & 0xF; + *(pbuffer + 2) = + pdata->ana_config__vhv_ref_sel_vquench & 0x7F; + *(pbuffer + 3) = + pdata->ana_config__reg_avdd1v2_sel & 0x3; + *(pbuffer + 4) = + pdata->ana_config__fast_osc__trim & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->osc_measured__fast_osc__frequency, + 2, + pbuffer + 5); + *(pbuffer + 7) = + pdata->vhv_config__timeout_macrop_loop_bound; + *(pbuffer + 8) = + pdata->vhv_config__count_thresh; + *(pbuffer + 9) = + pdata->vhv_config__offset & 0x3F; + *(pbuffer + 10) = + pdata->vhv_config__init; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->i2c_slave__device_address = + (*(pbuffer + 0)) & 0x7F; + pdata->ana_config__vhv_ref_sel_vddpix = + (*(pbuffer + 1)) & 0xF; + pdata->ana_config__vhv_ref_sel_vquench = + (*(pbuffer + 2)) & 0x7F; + pdata->ana_config__reg_avdd1v2_sel = + (*(pbuffer + 3)) & 0x3; + pdata->ana_config__fast_osc__trim = + (*(pbuffer + 4)) & 0x7F; + pdata->osc_measured__fast_osc__frequency = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 5)); + pdata->vhv_config__timeout_macrop_loop_bound = + (*(pbuffer + 7)); + pdata->vhv_config__count_thresh = + (*(pbuffer + 8)); + pdata->vhv_config__offset = + (*(pbuffer + 9)) & 0x3F; + pdata->vhv_config__init = + (*(pbuffer + 10)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_static_nvm_managed( + pdata, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_nvm_managed( + VL53L1_DEV Dev, + VL53L1_static_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_I2C_SLAVE__DEVICE_ADDRESS, + comms_buffer, + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_nvm_managed( + VL53L1_STATIC_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_customer_nvm_managed( + VL53L1_customer_nvm_managed_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->global_config__spad_enables_ref_0; + *(pbuffer + 1) = + pdata->global_config__spad_enables_ref_1; + *(pbuffer + 2) = + pdata->global_config__spad_enables_ref_2; + *(pbuffer + 3) = + pdata->global_config__spad_enables_ref_3; + *(pbuffer + 4) = + pdata->global_config__spad_enables_ref_4; + *(pbuffer + 5) = + pdata->global_config__spad_enables_ref_5 & 0xF; + *(pbuffer + 6) = + pdata->global_config__ref_en_start_select; + *(pbuffer + 7) = + pdata->ref_spad_man__num_requested_ref_spads & 0x3F; + *(pbuffer + 8) = + pdata->ref_spad_man__ref_location & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->algo__crosstalk_compensation_plane_offset_kcps, + 2, + pbuffer + 9); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps, + 2, + pbuffer + 11); + VL53L1_i2c_encode_int16_t( + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps, + 2, + pbuffer + 13); + VL53L1_i2c_encode_uint16_t( + pdata->ref_spad_char__total_rate_target_mcps, + 2, + pbuffer + 15); + VL53L1_i2c_encode_int16_t( + pdata->algo__part_to_part_range_offset_mm & 0x1FFF, + 2, + pbuffer + 17); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__inner_offset_mm, + 2, + pbuffer + 19); + VL53L1_i2c_encode_int16_t( + pdata->mm_config__outer_offset_mm, + 2, + pbuffer + 21); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_customer_nvm_managed( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->global_config__spad_enables_ref_0 = + (*(pbuffer + 0)); + pdata->global_config__spad_enables_ref_1 = + (*(pbuffer + 1)); + pdata->global_config__spad_enables_ref_2 = + (*(pbuffer + 2)); + pdata->global_config__spad_enables_ref_3 = + (*(pbuffer + 3)); + pdata->global_config__spad_enables_ref_4 = + (*(pbuffer + 4)); + pdata->global_config__spad_enables_ref_5 = + (*(pbuffer + 5)) & 0xF; + pdata->global_config__ref_en_start_select = + (*(pbuffer + 6)); + pdata->ref_spad_man__num_requested_ref_spads = + (*(pbuffer + 7)) & 0x3F; + pdata->ref_spad_man__ref_location = + (*(pbuffer + 8)) & 0x3; + pdata->algo__crosstalk_compensation_plane_offset_kcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 9)); + pdata->algo__crosstalk_compensation_x_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 11)); + pdata->algo__crosstalk_compensation_y_plane_gradient_kcps = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 13)); + pdata->ref_spad_char__total_rate_target_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 15)); + pdata->algo__part_to_part_range_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 17)) & 0x1FFF; + pdata->mm_config__inner_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 19)); + pdata->mm_config__outer_offset_mm = + (VL53L1_i2c_decode_int16_t(2, pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_customer_nvm_managed( + pdata, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_customer_nvm_managed( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0, + comms_buffer, + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_customer_nvm_managed( + VL53L1_CUSTOMER_NVM_MANAGED_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_static_config( + VL53L1_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__target_total_rate_mcps, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->debug__ctrl & 0x1; + *(pbuffer + 3) = + pdata->test_mode__ctrl & 0xF; + *(pbuffer + 4) = + pdata->clk_gating__ctrl & 0xF; + *(pbuffer + 5) = + pdata->nvm_bist__ctrl & 0x1F; + *(pbuffer + 6) = + pdata->nvm_bist__num_nvm_words & 0x7F; + *(pbuffer + 7) = + pdata->nvm_bist__start_address & 0x7F; + *(pbuffer + 8) = + pdata->host_if__status & 0x1; + *(pbuffer + 9) = + pdata->pad_i2c_hv__config; + *(pbuffer + 10) = + pdata->pad_i2c_hv__extsup_config & 0x1; + *(pbuffer + 11) = + pdata->gpio_hv_pad__ctrl & 0x3; + *(pbuffer + 12) = + pdata->gpio_hv_mux__ctrl & 0x1F; + *(pbuffer + 13) = + pdata->gpio__tio_hv_status & 0x3; + *(pbuffer + 14) = + pdata->gpio__fio_hv_status & 0x3; + *(pbuffer + 15) = + pdata->ana_config__spad_sel_pswidth & 0x7; + *(pbuffer + 16) = + pdata->ana_config__vcsel_pulse_width_offset & 0x1F; + *(pbuffer + 17) = + pdata->ana_config__fast_osc__config_ctrl & 0x1; + *(pbuffer + 18) = + pdata->sigma_estimator__effective_pulse_width_ns; + *(pbuffer + 19) = + pdata->sigma_estimator__effective_ambient_width_ns; + *(pbuffer + 20) = + pdata->sigma_estimator__sigma_ref_mm; + *(pbuffer + 21) = + pdata->algo__crosstalk_compensation_valid_height_mm; + *(pbuffer + 22) = + pdata->spare_host_config__static_config_spare_0; + *(pbuffer + 23) = + pdata->spare_host_config__static_config_spare_1; + VL53L1_i2c_encode_uint16_t( + pdata->algo__range_ignore_threshold_mcps, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->algo__range_ignore_valid_height_mm; + *(pbuffer + 27) = + pdata->algo__range_min_clip; + *(pbuffer + 28) = + pdata->algo__consistency_check__tolerance & 0xF; + *(pbuffer + 29) = + pdata->spare_host_config__static_config_spare_2; + *(pbuffer + 30) = + pdata->sd_config__reset_stages_msb & 0xF; + *(pbuffer + 31) = + pdata->sd_config__reset_stages_lsb; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_config__target_total_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->debug__ctrl = + (*(pbuffer + 2)) & 0x1; + pdata->test_mode__ctrl = + (*(pbuffer + 3)) & 0xF; + pdata->clk_gating__ctrl = + (*(pbuffer + 4)) & 0xF; + pdata->nvm_bist__ctrl = + (*(pbuffer + 5)) & 0x1F; + pdata->nvm_bist__num_nvm_words = + (*(pbuffer + 6)) & 0x7F; + pdata->nvm_bist__start_address = + (*(pbuffer + 7)) & 0x7F; + pdata->host_if__status = + (*(pbuffer + 8)) & 0x1; + pdata->pad_i2c_hv__config = + (*(pbuffer + 9)); + pdata->pad_i2c_hv__extsup_config = + (*(pbuffer + 10)) & 0x1; + pdata->gpio_hv_pad__ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->gpio_hv_mux__ctrl = + (*(pbuffer + 12)) & 0x1F; + pdata->gpio__tio_hv_status = + (*(pbuffer + 13)) & 0x3; + pdata->gpio__fio_hv_status = + (*(pbuffer + 14)) & 0x3; + pdata->ana_config__spad_sel_pswidth = + (*(pbuffer + 15)) & 0x7; + pdata->ana_config__vcsel_pulse_width_offset = + (*(pbuffer + 16)) & 0x1F; + pdata->ana_config__fast_osc__config_ctrl = + (*(pbuffer + 17)) & 0x1; + pdata->sigma_estimator__effective_pulse_width_ns = + (*(pbuffer + 18)); + pdata->sigma_estimator__effective_ambient_width_ns = + (*(pbuffer + 19)); + pdata->sigma_estimator__sigma_ref_mm = + (*(pbuffer + 20)); + pdata->algo__crosstalk_compensation_valid_height_mm = + (*(pbuffer + 21)); + pdata->spare_host_config__static_config_spare_0 = + (*(pbuffer + 22)); + pdata->spare_host_config__static_config_spare_1 = + (*(pbuffer + 23)); + pdata->algo__range_ignore_threshold_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->algo__range_ignore_valid_height_mm = + (*(pbuffer + 26)); + pdata->algo__range_min_clip = + (*(pbuffer + 27)); + pdata->algo__consistency_check__tolerance = + (*(pbuffer + 28)) & 0xF; + pdata->spare_host_config__static_config_spare_2 = + (*(pbuffer + 29)); + pdata->sd_config__reset_stages_msb = + (*(pbuffer + 30)) & 0xF; + pdata->sd_config__reset_stages_lsb = + (*(pbuffer + 31)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_static_config( + pdata, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_static_config( + VL53L1_DEV Dev, + VL53L1_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CONFIG__TARGET_TOTAL_RATE_MCPS, + comms_buffer, + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_static_config( + VL53L1_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_general_config( + VL53L1_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph_config__stream_count_update_value; + *(pbuffer + 1) = + pdata->global_config__stream_divider; + *(pbuffer + 2) = + pdata->system__interrupt_config_gpio; + *(pbuffer + 3) = + pdata->cal_config__vcsel_start & 0x7F; + VL53L1_i2c_encode_uint16_t( + pdata->cal_config__repeat_rate & 0xFFF, + 2, + pbuffer + 4); + *(pbuffer + 6) = + pdata->global_config__vcsel_width & 0x7F; + *(pbuffer + 7) = + pdata->phasecal_config__timeout_macrop; + *(pbuffer + 8) = + pdata->phasecal_config__target; + *(pbuffer + 9) = + pdata->phasecal_config__override & 0x1; + *(pbuffer + 11) = + pdata->dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_high, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_rate_low, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->dss_config__manual_effective_spads_select, + 2, + pbuffer + 16); + *(pbuffer + 18) = + pdata->dss_config__manual_block_select; + *(pbuffer + 19) = + pdata->dss_config__aperture_attenuation; + *(pbuffer + 20) = + pdata->dss_config__max_spads_limit; + *(pbuffer + 21) = + pdata->dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph_config__stream_count_update_value = + (*(pbuffer + 0)); + pdata->global_config__stream_divider = + (*(pbuffer + 1)); + pdata->system__interrupt_config_gpio = + (*(pbuffer + 2)); + pdata->cal_config__vcsel_start = + (*(pbuffer + 3)) & 0x7F; + pdata->cal_config__repeat_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)) & 0xFFF; + pdata->global_config__vcsel_width = + (*(pbuffer + 6)) & 0x7F; + pdata->phasecal_config__timeout_macrop = + (*(pbuffer + 7)); + pdata->phasecal_config__target = + (*(pbuffer + 8)); + pdata->phasecal_config__override = + (*(pbuffer + 9)) & 0x1; + pdata->dss_config__roi_mode_control = + (*(pbuffer + 11)) & 0x7; + pdata->system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->dss_config__manual_block_select = + (*(pbuffer + 18)); + pdata->dss_config__aperture_attenuation = + (*(pbuffer + 19)); + pdata->dss_config__max_spads_limit = + (*(pbuffer + 20)); + pdata->dss_config__min_spads_limit = + (*(pbuffer + 21)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_general_config( + pdata, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_general_config( + VL53L1_DEV Dev, + VL53L1_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH_CONFIG__STREAM_COUNT_UPDATE_VALUE, + comms_buffer, + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_general_config( + VL53L1_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_timing_config( + VL53L1_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 8) = + pdata->range_config__timeout_macrop_b_lo; + *(pbuffer + 9) = + pdata->range_config__vcsel_period_b & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->range_config__valid_phase_high; + VL53L1_i2c_encode_uint32_t( + pdata->system__intermeasurement_period, + 4, + pbuffer + 18); + *(pbuffer + 22) = + pdata->system__fractional_enable & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->range_config__timeout_macrop_b_hi = + (*(pbuffer + 7)) & 0xF; + pdata->range_config__timeout_macrop_b_lo = + (*(pbuffer + 8)); + pdata->range_config__vcsel_period_b = + (*(pbuffer + 9)) & 0x3F; + pdata->range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->range_config__valid_phase_high = + (*(pbuffer + 15)); + pdata->system__intermeasurement_period = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 18)); + pdata->system__fractional_enable = + (*(pbuffer + 22)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_timing_config( + pdata, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_timing_config( + VL53L1_DEV Dev, + VL53L1_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_timing_config( + VL53L1_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_dynamic_config( + VL53L1_dynamic_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->system__grouped_parameter_hold_0 & 0x3; + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_high, + 2, + pbuffer + 1); + VL53L1_i2c_encode_uint16_t( + pdata->system__thresh_low, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 6) = + pdata->system__seed_config & 0x7; + *(pbuffer + 7) = + pdata->sd_config__woi_sd0; + *(pbuffer + 8) = + pdata->sd_config__woi_sd1; + *(pbuffer + 9) = + pdata->sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 10) = + pdata->sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 11) = + pdata->system__grouped_parameter_hold_1 & 0x3; + *(pbuffer + 12) = + pdata->sd_config__first_order_select & 0x3; + *(pbuffer + 13) = + pdata->sd_config__quantifier & 0xF; + *(pbuffer + 14) = + pdata->roi_config__user_roi_centre_spad; + *(pbuffer + 15) = + pdata->roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 16) = + pdata->system__sequence_config; + *(pbuffer + 17) = + pdata->system__grouped_parameter_hold & 0x3; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_dynamic_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->system__grouped_parameter_hold_0 = + (*(pbuffer + 0)) & 0x3; + pdata->system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->system__enable_xtalk_per_quadrant = + (*(pbuffer + 5)) & 0x1; + pdata->system__seed_config = + (*(pbuffer + 6)) & 0x7; + pdata->sd_config__woi_sd0 = + (*(pbuffer + 7)); + pdata->sd_config__woi_sd1 = + (*(pbuffer + 8)); + pdata->sd_config__initial_phase_sd0 = + (*(pbuffer + 9)) & 0x7F; + pdata->sd_config__initial_phase_sd1 = + (*(pbuffer + 10)) & 0x7F; + pdata->system__grouped_parameter_hold_1 = + (*(pbuffer + 11)) & 0x3; + pdata->sd_config__first_order_select = + (*(pbuffer + 12)) & 0x3; + pdata->sd_config__quantifier = + (*(pbuffer + 13)) & 0xF; + pdata->roi_config__user_roi_centre_spad = + (*(pbuffer + 14)); + pdata->roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 15)); + pdata->system__sequence_config = + (*(pbuffer + 16)); + pdata->system__grouped_parameter_hold = + (*(pbuffer + 17)) & 0x3; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_dynamic_config( + pdata, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_dynamic_config( + VL53L1_DEV Dev, + VL53L1_dynamic_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_SYSTEM__GROUPED_PARAMETER_HOLD_0, + comms_buffer, + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_dynamic_config( + VL53L1_DYNAMIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_control( + VL53L1_system_control_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->power_management__go1_power_force & 0x1; + *(pbuffer + 1) = + pdata->system__stream_count_ctrl & 0x1; + *(pbuffer + 2) = + pdata->firmware__enable & 0x1; + *(pbuffer + 3) = + pdata->system__interrupt_clear & 0x3; + *(pbuffer + 4) = + pdata->system__mode_start; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_control( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->power_management__go1_power_force = + (*(pbuffer + 0)) & 0x1; + pdata->system__stream_count_ctrl = + (*(pbuffer + 1)) & 0x1; + pdata->firmware__enable = + (*(pbuffer + 2)) & 0x1; + pdata->system__interrupt_clear = + (*(pbuffer + 3)) & 0x3; + pdata->system__mode_start = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_system_control( + pdata, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_control( + VL53L1_DEV Dev, + VL53L1_system_control_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE, + comms_buffer, + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_control( + VL53L1_SYSTEM_CONTROL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_system_results( + VL53L1_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->result__range_status; + *(pbuffer + 2) = + pdata->result__report_status & 0xF; + *(pbuffer + 3) = + pdata->result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->result__spare_2_sd1, + 2, + pbuffer + 40); + *(pbuffer + 42) = + pdata->result__spare_3_sd1; + *(pbuffer + 43) = + pdata->result__thresh_info; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->result__range_status = + (*(pbuffer + 1)); + pdata->result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->result__stream_count = + (*(pbuffer + 3)); + pdata->result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->result__spare_3_sd1 = + (*(pbuffer + 42)); + pdata->result__thresh_info = + (*(pbuffer + 43)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_system_results( + pdata, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_system_results( + VL53L1_DEV Dev, + VL53L1_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_system_results( + VL53L1_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_core_results( + VL53L1_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_core_results( + pdata, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_core_results( + VL53L1_DEV Dev, + VL53L1_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_core_results( + VL53L1_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_debug_results( + VL53L1_debug_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__reference_phase, + 2, + pbuffer + 0); + *(pbuffer + 2) = + pdata->phasecal_result__vcsel_start & 0x7F; + *(pbuffer + 3) = + pdata->ref_spad_char_result__num_actual_ref_spads & 0x3F; + *(pbuffer + 4) = + pdata->ref_spad_char_result__ref_location & 0x3; + *(pbuffer + 5) = + pdata->vhv_result__coldboot_status & 0x1; + *(pbuffer + 6) = + pdata->vhv_result__search_result & 0x3F; + *(pbuffer + 7) = + pdata->vhv_result__latest_setting & 0x3F; + VL53L1_i2c_encode_uint16_t( + pdata->result__osc_calibrate_val & 0x3FF, + 2, + pbuffer + 8); + *(pbuffer + 10) = + pdata->ana_config__powerdown_go1 & 0x3; + *(pbuffer + 11) = + pdata->ana_config__ref_bg_ctrl & 0x3; + *(pbuffer + 12) = + pdata->ana_config__regdvdd1v2_ctrl & 0xF; + *(pbuffer + 13) = + pdata->ana_config__osc_slow_ctrl & 0x7; + *(pbuffer + 14) = + pdata->test_mode__status & 0x1; + *(pbuffer + 15) = + pdata->firmware__system_status & 0x3; + *(pbuffer + 16) = + pdata->firmware__mode_status; + *(pbuffer + 17) = + pdata->firmware__secondary_mode_status; + VL53L1_i2c_encode_uint16_t( + pdata->firmware__cal_repeat_rate_counter & 0xFFF, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_high, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_low, + 2, + pbuffer + 24); + *(pbuffer + 26) = + pdata->gph__system__enable_xtalk_per_quadrant & 0x1; + *(pbuffer + 27) = + pdata->gph__spare_0 & 0x7; + *(pbuffer + 28) = + pdata->gph__sd_config__woi_sd0; + *(pbuffer + 29) = + pdata->gph__sd_config__woi_sd1; + *(pbuffer + 30) = + pdata->gph__sd_config__initial_phase_sd0 & 0x7F; + *(pbuffer + 31) = + pdata->gph__sd_config__initial_phase_sd1 & 0x7F; + *(pbuffer + 32) = + pdata->gph__sd_config__first_order_select & 0x3; + *(pbuffer + 33) = + pdata->gph__sd_config__quantifier & 0xF; + *(pbuffer + 34) = + pdata->gph__roi_config__user_roi_centre_spad; + *(pbuffer + 35) = + pdata->gph__roi_config__user_roi_requested_global_xy_size; + *(pbuffer + 36) = + pdata->gph__system__sequence_config; + *(pbuffer + 37) = + pdata->gph__gph_id & 0x1; + *(pbuffer + 38) = + pdata->system__interrupt_set & 0x3; + *(pbuffer + 39) = + pdata->interrupt_manager__enables & 0x1F; + *(pbuffer + 40) = + pdata->interrupt_manager__clear & 0x1F; + *(pbuffer + 41) = + pdata->interrupt_manager__status & 0x1F; + *(pbuffer + 42) = + pdata->mcu_to_host_bank__wr_access_en & 0x1; + *(pbuffer + 43) = + pdata->power_management__go1_reset_status & 0x1; + *(pbuffer + 44) = + pdata->pad_startup_mode__value_ro & 0x3; + *(pbuffer + 45) = + pdata->pad_startup_mode__value_ctrl & 0x3F; + VL53L1_i2c_encode_uint32_t( + pdata->pll_period_us & 0x3FFFF, + 4, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->interrupt_scheduler__data_out, + 4, + pbuffer + 50); + *(pbuffer + 54) = + pdata->nvm_bist__complete & 0x1; + *(pbuffer + 55) = + pdata->nvm_bist__status & 0x1; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_debug_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->phasecal_result__reference_phase = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->phasecal_result__vcsel_start = + (*(pbuffer + 2)) & 0x7F; + pdata->ref_spad_char_result__num_actual_ref_spads = + (*(pbuffer + 3)) & 0x3F; + pdata->ref_spad_char_result__ref_location = + (*(pbuffer + 4)) & 0x3; + pdata->vhv_result__coldboot_status = + (*(pbuffer + 5)) & 0x1; + pdata->vhv_result__search_result = + (*(pbuffer + 6)) & 0x3F; + pdata->vhv_result__latest_setting = + (*(pbuffer + 7)) & 0x3F; + pdata->result__osc_calibrate_val = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)) & 0x3FF; + pdata->ana_config__powerdown_go1 = + (*(pbuffer + 10)) & 0x3; + pdata->ana_config__ref_bg_ctrl = + (*(pbuffer + 11)) & 0x3; + pdata->ana_config__regdvdd1v2_ctrl = + (*(pbuffer + 12)) & 0xF; + pdata->ana_config__osc_slow_ctrl = + (*(pbuffer + 13)) & 0x7; + pdata->test_mode__status = + (*(pbuffer + 14)) & 0x1; + pdata->firmware__system_status = + (*(pbuffer + 15)) & 0x3; + pdata->firmware__mode_status = + (*(pbuffer + 16)); + pdata->firmware__secondary_mode_status = + (*(pbuffer + 17)); + pdata->firmware__cal_repeat_rate_counter = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)) & 0xFFF; + pdata->gph__system__thresh_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->gph__system__thresh_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->gph__system__enable_xtalk_per_quadrant = + (*(pbuffer + 26)) & 0x1; + pdata->gph__spare_0 = + (*(pbuffer + 27)) & 0x7; + pdata->gph__sd_config__woi_sd0 = + (*(pbuffer + 28)); + pdata->gph__sd_config__woi_sd1 = + (*(pbuffer + 29)); + pdata->gph__sd_config__initial_phase_sd0 = + (*(pbuffer + 30)) & 0x7F; + pdata->gph__sd_config__initial_phase_sd1 = + (*(pbuffer + 31)) & 0x7F; + pdata->gph__sd_config__first_order_select = + (*(pbuffer + 32)) & 0x3; + pdata->gph__sd_config__quantifier = + (*(pbuffer + 33)) & 0xF; + pdata->gph__roi_config__user_roi_centre_spad = + (*(pbuffer + 34)); + pdata->gph__roi_config__user_roi_requested_global_xy_size = + (*(pbuffer + 35)); + pdata->gph__system__sequence_config = + (*(pbuffer + 36)); + pdata->gph__gph_id = + (*(pbuffer + 37)) & 0x1; + pdata->system__interrupt_set = + (*(pbuffer + 38)) & 0x3; + pdata->interrupt_manager__enables = + (*(pbuffer + 39)) & 0x1F; + pdata->interrupt_manager__clear = + (*(pbuffer + 40)) & 0x1F; + pdata->interrupt_manager__status = + (*(pbuffer + 41)) & 0x1F; + pdata->mcu_to_host_bank__wr_access_en = + (*(pbuffer + 42)) & 0x1; + pdata->power_management__go1_reset_status = + (*(pbuffer + 43)) & 0x1; + pdata->pad_startup_mode__value_ro = + (*(pbuffer + 44)) & 0x3; + pdata->pad_startup_mode__value_ctrl = + (*(pbuffer + 45)) & 0x3F; + pdata->pll_period_us = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 46)) & 0x3FFFF; + pdata->interrupt_scheduler__data_out = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 50)); + pdata->nvm_bist__complete = + (*(pbuffer + 54)) & 0x1; + pdata->nvm_bist__status = + (*(pbuffer + 55)) & 0x1; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_debug_results( + pdata, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_debug_results( + VL53L1_DEV Dev, + VL53L1_debug_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_PHASECAL_RESULT__REFERENCE_PHASE, + comms_buffer, + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_debug_results( + VL53L1_DEBUG_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_nvm_copy_data( + VL53L1_nvm_copy_data_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->identification__model_id; + *(pbuffer + 1) = + pdata->identification__module_type; + *(pbuffer + 2) = + pdata->identification__revision_id; + VL53L1_i2c_encode_uint16_t( + pdata->identification__module_id, + 2, + pbuffer + 3); + *(pbuffer + 5) = + pdata->ana_config__fast_osc__trim_max & 0x7F; + *(pbuffer + 6) = + pdata->ana_config__fast_osc__freq_set & 0x7; + *(pbuffer + 7) = + pdata->ana_config__vcsel_trim & 0x7; + *(pbuffer + 8) = + pdata->ana_config__vcsel_selion & 0x3F; + *(pbuffer + 9) = + pdata->ana_config__vcsel_selion_max & 0x3F; + *(pbuffer + 10) = + pdata->protected_laser_safety__lock_bit & 0x1; + *(pbuffer + 11) = + pdata->laser_safety__key & 0x7F; + *(pbuffer + 12) = + pdata->laser_safety__key_ro & 0x1; + *(pbuffer + 13) = + pdata->laser_safety__clip & 0x3F; + *(pbuffer + 14) = + pdata->laser_safety__mult & 0x3F; + *(pbuffer + 15) = + pdata->global_config__spad_enables_rtn_0; + *(pbuffer + 16) = + pdata->global_config__spad_enables_rtn_1; + *(pbuffer + 17) = + pdata->global_config__spad_enables_rtn_2; + *(pbuffer + 18) = + pdata->global_config__spad_enables_rtn_3; + *(pbuffer + 19) = + pdata->global_config__spad_enables_rtn_4; + *(pbuffer + 20) = + pdata->global_config__spad_enables_rtn_5; + *(pbuffer + 21) = + pdata->global_config__spad_enables_rtn_6; + *(pbuffer + 22) = + pdata->global_config__spad_enables_rtn_7; + *(pbuffer + 23) = + pdata->global_config__spad_enables_rtn_8; + *(pbuffer + 24) = + pdata->global_config__spad_enables_rtn_9; + *(pbuffer + 25) = + pdata->global_config__spad_enables_rtn_10; + *(pbuffer + 26) = + pdata->global_config__spad_enables_rtn_11; + *(pbuffer + 27) = + pdata->global_config__spad_enables_rtn_12; + *(pbuffer + 28) = + pdata->global_config__spad_enables_rtn_13; + *(pbuffer + 29) = + pdata->global_config__spad_enables_rtn_14; + *(pbuffer + 30) = + pdata->global_config__spad_enables_rtn_15; + *(pbuffer + 31) = + pdata->global_config__spad_enables_rtn_16; + *(pbuffer + 32) = + pdata->global_config__spad_enables_rtn_17; + *(pbuffer + 33) = + pdata->global_config__spad_enables_rtn_18; + *(pbuffer + 34) = + pdata->global_config__spad_enables_rtn_19; + *(pbuffer + 35) = + pdata->global_config__spad_enables_rtn_20; + *(pbuffer + 36) = + pdata->global_config__spad_enables_rtn_21; + *(pbuffer + 37) = + pdata->global_config__spad_enables_rtn_22; + *(pbuffer + 38) = + pdata->global_config__spad_enables_rtn_23; + *(pbuffer + 39) = + pdata->global_config__spad_enables_rtn_24; + *(pbuffer + 40) = + pdata->global_config__spad_enables_rtn_25; + *(pbuffer + 41) = + pdata->global_config__spad_enables_rtn_26; + *(pbuffer + 42) = + pdata->global_config__spad_enables_rtn_27; + *(pbuffer + 43) = + pdata->global_config__spad_enables_rtn_28; + *(pbuffer + 44) = + pdata->global_config__spad_enables_rtn_29; + *(pbuffer + 45) = + pdata->global_config__spad_enables_rtn_30; + *(pbuffer + 46) = + pdata->global_config__spad_enables_rtn_31; + *(pbuffer + 47) = + pdata->roi_config__mode_roi_centre_spad; + *(pbuffer + 48) = + pdata->roi_config__mode_roi_xy_size; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_nvm_copy_data( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->identification__model_id = + (*(pbuffer + 0)); + pdata->identification__module_type = + (*(pbuffer + 1)); + pdata->identification__revision_id = + (*(pbuffer + 2)); + pdata->identification__module_id = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 3)); + pdata->ana_config__fast_osc__trim_max = + (*(pbuffer + 5)) & 0x7F; + pdata->ana_config__fast_osc__freq_set = + (*(pbuffer + 6)) & 0x7; + pdata->ana_config__vcsel_trim = + (*(pbuffer + 7)) & 0x7; + pdata->ana_config__vcsel_selion = + (*(pbuffer + 8)) & 0x3F; + pdata->ana_config__vcsel_selion_max = + (*(pbuffer + 9)) & 0x3F; + pdata->protected_laser_safety__lock_bit = + (*(pbuffer + 10)) & 0x1; + pdata->laser_safety__key = + (*(pbuffer + 11)) & 0x7F; + pdata->laser_safety__key_ro = + (*(pbuffer + 12)) & 0x1; + pdata->laser_safety__clip = + (*(pbuffer + 13)) & 0x3F; + pdata->laser_safety__mult = + (*(pbuffer + 14)) & 0x3F; + pdata->global_config__spad_enables_rtn_0 = + (*(pbuffer + 15)); + pdata->global_config__spad_enables_rtn_1 = + (*(pbuffer + 16)); + pdata->global_config__spad_enables_rtn_2 = + (*(pbuffer + 17)); + pdata->global_config__spad_enables_rtn_3 = + (*(pbuffer + 18)); + pdata->global_config__spad_enables_rtn_4 = + (*(pbuffer + 19)); + pdata->global_config__spad_enables_rtn_5 = + (*(pbuffer + 20)); + pdata->global_config__spad_enables_rtn_6 = + (*(pbuffer + 21)); + pdata->global_config__spad_enables_rtn_7 = + (*(pbuffer + 22)); + pdata->global_config__spad_enables_rtn_8 = + (*(pbuffer + 23)); + pdata->global_config__spad_enables_rtn_9 = + (*(pbuffer + 24)); + pdata->global_config__spad_enables_rtn_10 = + (*(pbuffer + 25)); + pdata->global_config__spad_enables_rtn_11 = + (*(pbuffer + 26)); + pdata->global_config__spad_enables_rtn_12 = + (*(pbuffer + 27)); + pdata->global_config__spad_enables_rtn_13 = + (*(pbuffer + 28)); + pdata->global_config__spad_enables_rtn_14 = + (*(pbuffer + 29)); + pdata->global_config__spad_enables_rtn_15 = + (*(pbuffer + 30)); + pdata->global_config__spad_enables_rtn_16 = + (*(pbuffer + 31)); + pdata->global_config__spad_enables_rtn_17 = + (*(pbuffer + 32)); + pdata->global_config__spad_enables_rtn_18 = + (*(pbuffer + 33)); + pdata->global_config__spad_enables_rtn_19 = + (*(pbuffer + 34)); + pdata->global_config__spad_enables_rtn_20 = + (*(pbuffer + 35)); + pdata->global_config__spad_enables_rtn_21 = + (*(pbuffer + 36)); + pdata->global_config__spad_enables_rtn_22 = + (*(pbuffer + 37)); + pdata->global_config__spad_enables_rtn_23 = + (*(pbuffer + 38)); + pdata->global_config__spad_enables_rtn_24 = + (*(pbuffer + 39)); + pdata->global_config__spad_enables_rtn_25 = + (*(pbuffer + 40)); + pdata->global_config__spad_enables_rtn_26 = + (*(pbuffer + 41)); + pdata->global_config__spad_enables_rtn_27 = + (*(pbuffer + 42)); + pdata->global_config__spad_enables_rtn_28 = + (*(pbuffer + 43)); + pdata->global_config__spad_enables_rtn_29 = + (*(pbuffer + 44)); + pdata->global_config__spad_enables_rtn_30 = + (*(pbuffer + 45)); + pdata->global_config__spad_enables_rtn_31 = + (*(pbuffer + 46)); + pdata->roi_config__mode_roi_centre_spad = + (*(pbuffer + 47)); + pdata->roi_config__mode_roi_xy_size = + (*(pbuffer + 48)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_nvm_copy_data( + pdata, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_nvm_copy_data( + VL53L1_DEV Dev, + VL53L1_nvm_copy_data_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_ReadMulti( + Dev, + VL53L1_IDENTIFICATION__MODEL_ID, + comms_buffer, + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_nvm_copy_data( + VL53L1_NVM_COPY_DATA_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_system_results( + VL53L1_prev_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->prev_shadow_result__interrupt_status & 0x3F; + *(pbuffer + 1) = + pdata->prev_shadow_result__range_status; + *(pbuffer + 2) = + pdata->prev_shadow_result__report_status & 0xF; + *(pbuffer + 3) = + pdata->prev_shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 4); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__sigma_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__phase_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_0_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_1_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_2_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->prev_shadow_result__spare_3_sd1, + 2, + pbuffer + 42); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result__interrupt_status = + (*(pbuffer + 0)) & 0x3F; + pdata->prev_shadow_result__range_status = + (*(pbuffer + 1)); + pdata->prev_shadow_result__report_status = + (*(pbuffer + 2)) & 0xF; + pdata->prev_shadow_result__stream_count = + (*(pbuffer + 3)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 4)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->prev_shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->prev_shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->psr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->prev_shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->prev_shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->prev_shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->prev_shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->prev_shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->prev_shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->prev_shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->prev_shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->prev_shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->prev_shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->prev_shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->prev_shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->prev_shadow_result__spare_3_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_prev_shadow_system_results( + pdata, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT__INTERRUPT_STATUS, + comms_buffer, + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_system_results( + VL53L1_PREV_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_prev_shadow_core_results( + VL53L1_prev_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->prev_shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->prev_shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->prev_shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_prev_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->prev_shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->prev_shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->prev_shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->prev_shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->prev_shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->prev_shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->prev_shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->prev_shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_prev_shadow_core_results( + pdata, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_prev_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_prev_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_PREV_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_prev_shadow_core_results( + VL53L1_PREV_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_debug( + VL53L1_patch_debug_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->result__debug_status; + *(pbuffer + 1) = + pdata->result__debug_stage; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_debug( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->result__debug_status = + (*(pbuffer + 0)); + pdata->result__debug_stage = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_patch_debug( + pdata, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_debug( + VL53L1_DEV Dev, + VL53L1_patch_debug_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_RESULT__DEBUG_STATUS, + comms_buffer, + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_debug( + VL53L1_PATCH_DEBUG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_general_config( + VL53L1_gph_general_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_high, + 2, + pbuffer + 0); + VL53L1_i2c_encode_uint16_t( + pdata->gph__system__thresh_rate_low, + 2, + pbuffer + 2); + *(pbuffer + 4) = + pdata->gph__system__interrupt_config_gpio; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_general_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__system__thresh_rate_high = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 0)); + pdata->gph__system__thresh_rate_low = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 2)); + pdata->gph__system__interrupt_config_gpio = + (*(pbuffer + 4)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_general_config( + pdata, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_general_config( + VL53L1_DEV Dev, + VL53L1_gph_general_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__SYSTEM__THRESH_RATE_HIGH, + comms_buffer, + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_general_config( + VL53L1_GPH_GENERAL_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_static_config( + VL53L1_gph_static_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__dss_config__roi_mode_control & 0x7; + VL53L1_i2c_encode_uint16_t( + pdata->gph__dss_config__manual_effective_spads_select, + 2, + pbuffer + 1); + *(pbuffer + 3) = + pdata->gph__dss_config__manual_block_select; + *(pbuffer + 4) = + pdata->gph__dss_config__max_spads_limit; + *(pbuffer + 5) = + pdata->gph__dss_config__min_spads_limit; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_static_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__dss_config__roi_mode_control = + (*(pbuffer + 0)) & 0x7; + pdata->gph__dss_config__manual_effective_spads_select = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 1)); + pdata->gph__dss_config__manual_block_select = + (*(pbuffer + 3)); + pdata->gph__dss_config__max_spads_limit = + (*(pbuffer + 4)); + pdata->gph__dss_config__min_spads_limit = + (*(pbuffer + 5)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_static_config( + pdata, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_static_config( + VL53L1_DEV Dev, + VL53L1_gph_static_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__DSS_CONFIG__ROI_MODE_CONTROL, + comms_buffer, + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_static_config( + VL53L1_GPH_STATIC_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_gph_timing_config( + VL53L1_gph_timing_config_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->gph__mm_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 1) = + pdata->gph__mm_config__timeout_macrop_a_lo; + *(pbuffer + 2) = + pdata->gph__mm_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 3) = + pdata->gph__mm_config__timeout_macrop_b_lo; + *(pbuffer + 4) = + pdata->gph__range_config__timeout_macrop_a_hi & 0xF; + *(pbuffer + 5) = + pdata->gph__range_config__timeout_macrop_a_lo; + *(pbuffer + 6) = + pdata->gph__range_config__vcsel_period_a & 0x3F; + *(pbuffer + 7) = + pdata->gph__range_config__vcsel_period_b & 0x3F; + *(pbuffer + 8) = + pdata->gph__range_config__timeout_macrop_b_hi & 0xF; + *(pbuffer + 9) = + pdata->gph__range_config__timeout_macrop_b_lo; + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__sigma_thresh, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->gph__range_config__min_count_rate_rtn_limit_mcps, + 2, + pbuffer + 12); + *(pbuffer + 14) = + pdata->gph__range_config__valid_phase_low; + *(pbuffer + 15) = + pdata->gph__range_config__valid_phase_high; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_gph_timing_config( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->gph__mm_config__timeout_macrop_a_hi = + (*(pbuffer + 0)) & 0xF; + pdata->gph__mm_config__timeout_macrop_a_lo = + (*(pbuffer + 1)); + pdata->gph__mm_config__timeout_macrop_b_hi = + (*(pbuffer + 2)) & 0xF; + pdata->gph__mm_config__timeout_macrop_b_lo = + (*(pbuffer + 3)); + pdata->gph__range_config__timeout_macrop_a_hi = + (*(pbuffer + 4)) & 0xF; + pdata->gph__range_config__timeout_macrop_a_lo = + (*(pbuffer + 5)); + pdata->gph__range_config__vcsel_period_a = + (*(pbuffer + 6)) & 0x3F; + pdata->gph__range_config__vcsel_period_b = + (*(pbuffer + 7)) & 0x3F; + pdata->gph__range_config__timeout_macrop_b_hi = + (*(pbuffer + 8)) & 0xF; + pdata->gph__range_config__timeout_macrop_b_lo = + (*(pbuffer + 9)); + pdata->gph__range_config__sigma_thresh = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->gph__range_config__min_count_rate_rtn_limit_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->gph__range_config__valid_phase_low = + (*(pbuffer + 14)); + pdata->gph__range_config__valid_phase_high = + (*(pbuffer + 15)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_gph_timing_config( + pdata, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_gph_timing_config( + VL53L1_DEV Dev, + VL53L1_gph_timing_config_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_GPH__MM_CONFIG__TIMEOUT_MACROP_A_HI, + comms_buffer, + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_gph_timing_config( + VL53L1_GPH_TIMING_CONFIG_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_fw_internal( + VL53L1_fw_internal_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->firmware__internal_stream_count_div; + *(pbuffer + 1) = + pdata->firmware__internal_stream_counter_val; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_fw_internal( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_FW_INTERNAL_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->firmware__internal_stream_count_div = + (*(pbuffer + 0)); + pdata->firmware__internal_stream_counter_val = + (*(pbuffer + 1)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_fw_internal( + pdata, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_fw_internal( + VL53L1_DEV Dev, + VL53L1_fw_internal_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_FW_INTERNAL_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_FIRMWARE__INTERNAL_STREAM_COUNT_DIV, + comms_buffer, + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_fw_internal( + VL53L1_FW_INTERNAL_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_patch_results( + VL53L1_patch_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->dss_calc__roi_ctrl & 0x3; + *(pbuffer + 1) = + pdata->dss_calc__spare_1; + *(pbuffer + 2) = + pdata->dss_calc__spare_2; + *(pbuffer + 3) = + pdata->dss_calc__spare_3; + *(pbuffer + 4) = + pdata->dss_calc__spare_4; + *(pbuffer + 5) = + pdata->dss_calc__spare_5; + *(pbuffer + 6) = + pdata->dss_calc__spare_6; + *(pbuffer + 7) = + pdata->dss_calc__spare_7; + *(pbuffer + 8) = + pdata->dss_calc__user_roi_spad_en_0; + *(pbuffer + 9) = + pdata->dss_calc__user_roi_spad_en_1; + *(pbuffer + 10) = + pdata->dss_calc__user_roi_spad_en_2; + *(pbuffer + 11) = + pdata->dss_calc__user_roi_spad_en_3; + *(pbuffer + 12) = + pdata->dss_calc__user_roi_spad_en_4; + *(pbuffer + 13) = + pdata->dss_calc__user_roi_spad_en_5; + *(pbuffer + 14) = + pdata->dss_calc__user_roi_spad_en_6; + *(pbuffer + 15) = + pdata->dss_calc__user_roi_spad_en_7; + *(pbuffer + 16) = + pdata->dss_calc__user_roi_spad_en_8; + *(pbuffer + 17) = + pdata->dss_calc__user_roi_spad_en_9; + *(pbuffer + 18) = + pdata->dss_calc__user_roi_spad_en_10; + *(pbuffer + 19) = + pdata->dss_calc__user_roi_spad_en_11; + *(pbuffer + 20) = + pdata->dss_calc__user_roi_spad_en_12; + *(pbuffer + 21) = + pdata->dss_calc__user_roi_spad_en_13; + *(pbuffer + 22) = + pdata->dss_calc__user_roi_spad_en_14; + *(pbuffer + 23) = + pdata->dss_calc__user_roi_spad_en_15; + *(pbuffer + 24) = + pdata->dss_calc__user_roi_spad_en_16; + *(pbuffer + 25) = + pdata->dss_calc__user_roi_spad_en_17; + *(pbuffer + 26) = + pdata->dss_calc__user_roi_spad_en_18; + *(pbuffer + 27) = + pdata->dss_calc__user_roi_spad_en_19; + *(pbuffer + 28) = + pdata->dss_calc__user_roi_spad_en_20; + *(pbuffer + 29) = + pdata->dss_calc__user_roi_spad_en_21; + *(pbuffer + 30) = + pdata->dss_calc__user_roi_spad_en_22; + *(pbuffer + 31) = + pdata->dss_calc__user_roi_spad_en_23; + *(pbuffer + 32) = + pdata->dss_calc__user_roi_spad_en_24; + *(pbuffer + 33) = + pdata->dss_calc__user_roi_spad_en_25; + *(pbuffer + 34) = + pdata->dss_calc__user_roi_spad_en_26; + *(pbuffer + 35) = + pdata->dss_calc__user_roi_spad_en_27; + *(pbuffer + 36) = + pdata->dss_calc__user_roi_spad_en_28; + *(pbuffer + 37) = + pdata->dss_calc__user_roi_spad_en_29; + *(pbuffer + 38) = + pdata->dss_calc__user_roi_spad_en_30; + *(pbuffer + 39) = + pdata->dss_calc__user_roi_spad_en_31; + *(pbuffer + 40) = + pdata->dss_calc__user_roi_0; + *(pbuffer + 41) = + pdata->dss_calc__user_roi_1; + *(pbuffer + 42) = + pdata->dss_calc__mode_roi_0; + *(pbuffer + 43) = + pdata->dss_calc__mode_roi_1; + *(pbuffer + 44) = + pdata->sigma_estimator_calc__spare_0; + VL53L1_i2c_encode_uint16_t( + pdata->vhv_result__peak_signal_rate_mcps, + 2, + pbuffer + 46); + VL53L1_i2c_encode_uint32_t( + pdata->vhv_result__signal_total_events_ref, + 4, + pbuffer + 48); + VL53L1_i2c_encode_uint16_t( + pdata->phasecal_result__phase_output_ref, + 2, + pbuffer + 52); + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__total_rate_per_spad, + 2, + pbuffer + 54); + *(pbuffer + 56) = + pdata->dss_result__enabled_blocks; + VL53L1_i2c_encode_uint16_t( + pdata->dss_result__num_requested_spads, + 2, + pbuffer + 58); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__inner_intersection_rate, + 2, + pbuffer + 62); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__outer_complement_rate, + 2, + pbuffer + 64); + VL53L1_i2c_encode_uint16_t( + pdata->mm_result__total_offset, + 2, + pbuffer + 66); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_calc__xtalk_for_enabled_spads & 0xFFFFFF, + 4, + pbuffer + 68); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_user_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 72); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 76); + VL53L1_i2c_encode_uint32_t( + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps & 0xFFFFFF, + 4, + pbuffer + 80); + VL53L1_i2c_encode_uint32_t( + pdata->range_result__accum_phase, + 4, + pbuffer + 84); + VL53L1_i2c_encode_uint16_t( + pdata->range_result__offset_corrected_range, + 2, + pbuffer + 88); + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_patch_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->dss_calc__roi_ctrl = + (*(pbuffer + 0)) & 0x3; + pdata->dss_calc__spare_1 = + (*(pbuffer + 1)); + pdata->dss_calc__spare_2 = + (*(pbuffer + 2)); + pdata->dss_calc__spare_3 = + (*(pbuffer + 3)); + pdata->dss_calc__spare_4 = + (*(pbuffer + 4)); + pdata->dss_calc__spare_5 = + (*(pbuffer + 5)); + pdata->dss_calc__spare_6 = + (*(pbuffer + 6)); + pdata->dss_calc__spare_7 = + (*(pbuffer + 7)); + pdata->dss_calc__user_roi_spad_en_0 = + (*(pbuffer + 8)); + pdata->dss_calc__user_roi_spad_en_1 = + (*(pbuffer + 9)); + pdata->dss_calc__user_roi_spad_en_2 = + (*(pbuffer + 10)); + pdata->dss_calc__user_roi_spad_en_3 = + (*(pbuffer + 11)); + pdata->dss_calc__user_roi_spad_en_4 = + (*(pbuffer + 12)); + pdata->dss_calc__user_roi_spad_en_5 = + (*(pbuffer + 13)); + pdata->dss_calc__user_roi_spad_en_6 = + (*(pbuffer + 14)); + pdata->dss_calc__user_roi_spad_en_7 = + (*(pbuffer + 15)); + pdata->dss_calc__user_roi_spad_en_8 = + (*(pbuffer + 16)); + pdata->dss_calc__user_roi_spad_en_9 = + (*(pbuffer + 17)); + pdata->dss_calc__user_roi_spad_en_10 = + (*(pbuffer + 18)); + pdata->dss_calc__user_roi_spad_en_11 = + (*(pbuffer + 19)); + pdata->dss_calc__user_roi_spad_en_12 = + (*(pbuffer + 20)); + pdata->dss_calc__user_roi_spad_en_13 = + (*(pbuffer + 21)); + pdata->dss_calc__user_roi_spad_en_14 = + (*(pbuffer + 22)); + pdata->dss_calc__user_roi_spad_en_15 = + (*(pbuffer + 23)); + pdata->dss_calc__user_roi_spad_en_16 = + (*(pbuffer + 24)); + pdata->dss_calc__user_roi_spad_en_17 = + (*(pbuffer + 25)); + pdata->dss_calc__user_roi_spad_en_18 = + (*(pbuffer + 26)); + pdata->dss_calc__user_roi_spad_en_19 = + (*(pbuffer + 27)); + pdata->dss_calc__user_roi_spad_en_20 = + (*(pbuffer + 28)); + pdata->dss_calc__user_roi_spad_en_21 = + (*(pbuffer + 29)); + pdata->dss_calc__user_roi_spad_en_22 = + (*(pbuffer + 30)); + pdata->dss_calc__user_roi_spad_en_23 = + (*(pbuffer + 31)); + pdata->dss_calc__user_roi_spad_en_24 = + (*(pbuffer + 32)); + pdata->dss_calc__user_roi_spad_en_25 = + (*(pbuffer + 33)); + pdata->dss_calc__user_roi_spad_en_26 = + (*(pbuffer + 34)); + pdata->dss_calc__user_roi_spad_en_27 = + (*(pbuffer + 35)); + pdata->dss_calc__user_roi_spad_en_28 = + (*(pbuffer + 36)); + pdata->dss_calc__user_roi_spad_en_29 = + (*(pbuffer + 37)); + pdata->dss_calc__user_roi_spad_en_30 = + (*(pbuffer + 38)); + pdata->dss_calc__user_roi_spad_en_31 = + (*(pbuffer + 39)); + pdata->dss_calc__user_roi_0 = + (*(pbuffer + 40)); + pdata->dss_calc__user_roi_1 = + (*(pbuffer + 41)); + pdata->dss_calc__mode_roi_0 = + (*(pbuffer + 42)); + pdata->dss_calc__mode_roi_1 = + (*(pbuffer + 43)); + pdata->sigma_estimator_calc__spare_0 = + (*(pbuffer + 44)); + pdata->vhv_result__peak_signal_rate_mcps = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 46)); + pdata->vhv_result__signal_total_events_ref = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 48)); + pdata->phasecal_result__phase_output_ref = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 52)); + pdata->dss_result__total_rate_per_spad = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 54)); + pdata->dss_result__enabled_blocks = + (*(pbuffer + 56)); + pdata->dss_result__num_requested_spads = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 58)); + pdata->mm_result__inner_intersection_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 62)); + pdata->mm_result__outer_complement_rate = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 64)); + pdata->mm_result__total_offset = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 66)); + pdata->xtalk_calc__xtalk_for_enabled_spads = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 68)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_user_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 72)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_inner_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 76)) & 0xFFFFFF; + pdata->xtalk_result__avg_xtalk_mm_outer_roi_kcps = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 80)) & 0xFFFFFF; + pdata->range_result__accum_phase = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 84)); + pdata->range_result__offset_corrected_range = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 88)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_patch_results( + pdata, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_patch_results( + VL53L1_DEV Dev, + VL53L1_patch_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_DSS_CALC__ROI_CTRL, + comms_buffer, + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_patch_results( + VL53L1_PATCH_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_system_results( + VL53L1_shadow_system_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + *(pbuffer + 0) = + pdata->shadow_phasecal_result__vcsel_start; + *(pbuffer + 2) = + pdata->shadow_result__interrupt_status & 0x3F; + *(pbuffer + 3) = + pdata->shadow_result__range_status; + *(pbuffer + 4) = + pdata->shadow_result__report_status & 0xF; + *(pbuffer + 5) = + pdata->shadow_result__stream_count; + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd0, + 2, + pbuffer + 6); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd0, + 2, + pbuffer + 8); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd0, + 2, + pbuffer + 10); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd0, + 2, + pbuffer + 12); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd0, + 2, + pbuffer + 14); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0, + 2, + pbuffer + 16); + VL53L1_i2c_encode_uint16_t( + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0, + 2, + pbuffer + 18); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_inner_actual_effective_spads_sd0, + 2, + pbuffer + 20); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__mm_outer_actual_effective_spads_sd0, + 2, + pbuffer + 22); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__avg_signal_count_rate_mcps_sd0, + 2, + pbuffer + 24); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__dss_actual_effective_spads_sd1, + 2, + pbuffer + 26); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__peak_signal_count_rate_mcps_sd1, + 2, + pbuffer + 28); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__ambient_count_rate_mcps_sd1, + 2, + pbuffer + 30); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__sigma_sd1, + 2, + pbuffer + 32); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__phase_sd1, + 2, + pbuffer + 34); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1, + 2, + pbuffer + 36); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_0_sd1, + 2, + pbuffer + 38); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_1_sd1, + 2, + pbuffer + 40); + VL53L1_i2c_encode_uint16_t( + pdata->shadow_result__spare_2_sd1, + 2, + pbuffer + 42); + *(pbuffer + 44) = + pdata->shadow_result__spare_3_sd1; + *(pbuffer + 45) = + pdata->shadow_result__thresh_info; + *(pbuffer + 80) = + pdata->shadow_phasecal_result__reference_phase_hi; + *(pbuffer + 81) = + pdata->shadow_phasecal_result__reference_phase_lo; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_system_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_phasecal_result__vcsel_start = + (*(pbuffer + 0)); + pdata->shadow_result__interrupt_status = + (*(pbuffer + 2)) & 0x3F; + pdata->shadow_result__range_status = + (*(pbuffer + 3)); + pdata->shadow_result__report_status = + (*(pbuffer + 4)) & 0xF; + pdata->shadow_result__stream_count = + (*(pbuffer + 5)); + pdata->shadow_result__dss_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 6)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 8)); + pdata->shadow_result__ambient_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 10)); + pdata->shadow_result__sigma_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 12)); + pdata->shadow_result__phase_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 14)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 16)); + pdata->shr__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 18)); + pdata->shadow_result__mm_inner_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 20)); + pdata->shadow_result__mm_outer_actual_effective_spads_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 22)); + pdata->shadow_result__avg_signal_count_rate_mcps_sd0 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 24)); + pdata->shadow_result__dss_actual_effective_spads_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 26)); + pdata->shadow_result__peak_signal_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 28)); + pdata->shadow_result__ambient_count_rate_mcps_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 30)); + pdata->shadow_result__sigma_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 32)); + pdata->shadow_result__phase_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 34)); + pdata->shadow_result__final_crosstalk_corrected_range_mm_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 36)); + pdata->shadow_result__spare_0_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 38)); + pdata->shadow_result__spare_1_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 40)); + pdata->shadow_result__spare_2_sd1 = + (VL53L1_i2c_decode_uint16_t(2, pbuffer + 42)); + pdata->shadow_result__spare_3_sd1 = + (*(pbuffer + 44)); + pdata->shadow_result__thresh_info = + (*(pbuffer + 45)); + pdata->shadow_phasecal_result__reference_phase_hi = + (*(pbuffer + 80)); + pdata->shadow_phasecal_result__reference_phase_lo = + (*(pbuffer + 81)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_shadow_system_results( + pdata, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_system_results( + VL53L1_DEV Dev, + VL53L1_shadow_system_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_PHASECAL_RESULT__VCSEL_START, + comms_buffer, + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_system_results( + VL53L1_SHADOW_SYSTEM_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_i2c_encode_shadow_core_results( + VL53L1_shadow_core_results_t *pdata, + uint16_t buf_size, + uint8_t *pbuffer) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd0, + 4, + pbuffer + 0); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd0, + 4, + pbuffer + 4); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd0, + 4, + pbuffer + 8); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd0, + 4, + pbuffer + 12); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ambient_window_events_sd1, + 4, + pbuffer + 16); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__ranging_total_events_sd1, + 4, + pbuffer + 20); + VL53L1_i2c_encode_int32_t( + pdata->shadow_result_core__signal_total_events_sd1, + 4, + pbuffer + 24); + VL53L1_i2c_encode_uint32_t( + pdata->shadow_result_core__total_periods_elapsed_sd1, + 4, + pbuffer + 28); + *(pbuffer + 32) = + pdata->shadow_result_core__spare_0; + LOG_FUNCTION_END(status); + + + return status; +} + + +VL53L1_Error VL53L1_i2c_decode_shadow_core_results( + uint16_t buf_size, + uint8_t *pbuffer, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (buf_size < VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES) + return VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL; + + pdata->shadow_result_core__ambient_window_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 0)); + pdata->shadow_result_core__ranging_total_events_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 4)); + pdata->shadow_result_core__signal_total_events_sd0 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 8)); + pdata->shadow_result_core__total_periods_elapsed_sd0 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 12)); + pdata->shadow_result_core__ambient_window_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 16)); + pdata->shadow_result_core__ranging_total_events_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 20)); + pdata->shadow_result_core__signal_total_events_sd1 = + (VL53L1_i2c_decode_int32_t(4, pbuffer + 24)); + pdata->shadow_result_core__total_periods_elapsed_sd1 = + (VL53L1_i2c_decode_uint32_t(4, pbuffer + 28)); + pdata->shadow_result_core__spare_0 = + (*(pbuffer + 32)); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_set_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_i2c_encode_shadow_core_results( + pdata, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_WriteMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_get_shadow_core_results( + VL53L1_DEV Dev, + VL53L1_shadow_core_results_t *pdata) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t comms_buffer[VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES]; + + LOG_FUNCTION_START(""); + + if (status == VL53L1_ERROR_NONE) + + status = VL53L1_disable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_ReadMulti( + Dev, + VL53L1_SHADOW_RESULT_CORE__AMBIENT_WINDOW_EVENTS_SD0, + comms_buffer, + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_enable_firmware(Dev); + + if (status == VL53L1_ERROR_NONE) + status = VL53L1_i2c_decode_shadow_core_results( + VL53L1_SHADOW_CORE_RESULTS_I2C_SIZE_BYTES, + comms_buffer, + pdata); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_silicon_core.c b/drivers/oneplus/vl53L1/src/vl53l1_silicon_core.c new file mode 100755 index 0000000000000000000000000000000000000000..2c3112b841bd1aca7d20373ea0ff97a448780bcc --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_silicon_core.c @@ -0,0 +1,187 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform.h" +#include "vl53l1_register_map.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_is_firmware_ready_silicon( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t comms_buffer[5]; + + LOG_FUNCTION_START(""); + + + + + status = VL53L1_ReadMulti( + Dev, + VL53L1_INTERRUPT_MANAGER__ENABLES, + comms_buffer, + 5); + + if (status != VL53L1_ERROR_NONE) + goto ENDFUNC; + + pdev->dbg_results.interrupt_manager__enables = + comms_buffer[0]; + pdev->dbg_results.interrupt_manager__clear = + comms_buffer[1]; + pdev->dbg_results.interrupt_manager__status = + comms_buffer[2]; + pdev->dbg_results.mcu_to_host_bank__wr_access_en = + comms_buffer[3]; + pdev->dbg_results.power_management__go1_reset_status = + comms_buffer[4]; + + if ((pdev->sys_ctrl.power_management__go1_power_force & 0x01) + == 0x01) { + + if (((pdev->dbg_results.interrupt_manager__enables & + 0x1F) == 0x1F) && + ((pdev->dbg_results.interrupt_manager__clear + & 0x1F) == 0x1F)) + *pready = 0x01; + else + *pready = 0x00; + + } else { + + + + if ((pdev->dbg_results.power_management__go1_reset_status + & 0x01) == 0x00) + *pready = 0x01; + else + *pready = 0x00; + } + + +ENDFUNC: + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_wait.c b/drivers/oneplus/vl53L1/src/vl53l1_wait.c new file mode 100755 index 0000000000000000000000000000000000000000..083e53d584a3afee0df0395cb5eaa018bcc4ef31 --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_wait.c @@ -0,0 +1,621 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform.h" +#include "vl53l1_core.h" +#include "vl53l1_silicon_core.h" +#include "vl53l1_wait.h" +#include "vl53l1_register_settings.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \ + fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_wait_for_boot_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_boot_completion( + Dev, + VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_boot_complete( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; + +} + + +VL53L1_Error VL53L1_wait_for_firmware_ready( + VL53L1_DEV Dev) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t fw_ready = 0; + uint8_t mode_start = 0; + + LOG_FUNCTION_START(""); + + + + + + mode_start = + pdev->sys_ctrl.system__mode_start & + VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK; + + + + + + + + if ((mode_start == VL53L1_DEVICEMEASUREMENTMODE_TIMED) || + (mode_start == VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT)) { + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_firmware_ready( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + fw_ready = 0; + while (fw_ready == 0x00 && status == + VL53L1_ERROR_NONE) { + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_range_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_wait_for_test_completion( + VL53L1_DEV Dev) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t data_ready = 0; + + LOG_FUNCTION_START(""); + + if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) { + + + + + status = + VL53L1_poll_for_range_completion( + Dev, + VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS); + + } else { + + + + + data_ready = 0; + while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) { + status = VL53L1_is_new_data_ready( + Dev, + &data_ready); + + if (status == VL53L1_ERROR_NONE) { + status = VL53L1_WaitMs( + Dev, + VL53L1_POLLING_DELAY_MS); + } + } + } + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_is_boot_complete( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t firmware__system_status = 0; + + LOG_FUNCTION_START(""); + + + + + status = + VL53L1_RdByte( + Dev, + VL53L1_FIRMWARE__SYSTEM_STATUS, + &firmware__system_status); + + + + + + + if ((firmware__system_status & 0x01) == 0x01) { + *pready = 0x01; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_SW_STANDBY); + } else { + *pready = 0x00; + VL53L1_init_ll_driver_state( + Dev, + VL53L1_DEVICESTATE_FW_COLDBOOT); + } + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_firmware_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + LOG_FUNCTION_START(""); + + status = VL53L1_is_firmware_ready_silicon( + Dev, + pready); + + pdev->fw_ready = *pready; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_is_new_data_ready( + VL53L1_DEV Dev, + uint8_t *pready) +{ + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t gpio__tio_hv_status = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + + + + status = VL53L1_RdByte( + Dev, + VL53L1_GPIO__TIO_HV_STATUS, + &gpio__tio_hv_status); + + + + + if ((gpio__tio_hv_status & 0x01) == interrupt_ready) + *pready = 0x01; + else + *pready = 0x00; + + LOG_FUNCTION_END(status); + + return status; +} + + + + +VL53L1_Error VL53L1_poll_for_boot_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + + + status = VL53L1_WaitUs( + Dev, + VL53L1_FIRMWARE_BOOT_TIME_US); + + if (status == VL53L1_ERROR_NONE) + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_FIRMWARE__SYSTEM_STATUS, + 0x01, + 0x01, + VL53L1_POLLING_DELAY_MS); + + if (status == VL53L1_ERROR_NONE) + VL53L1_init_ll_driver_state(Dev, VL53L1_DEVICESTATE_SW_STANDBY); + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_firmware_ready( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint32_t start_time_ms = 0; + uint32_t current_time_ms = 0; + int32_t poll_delay_ms = VL53L1_POLLING_DELAY_MS; + uint8_t fw_ready = 0; + + + + + VL53L1_GetTickCount(&start_time_ms); + + pdev->fw_ready_poll_duration_ms = 0; + + + + + while ((status == VL53L1_ERROR_NONE) && + (pdev->fw_ready_poll_duration_ms < timeout_ms) && + (fw_ready == 0)) { + + status = VL53L1_is_firmware_ready( + Dev, + &fw_ready); + + if (status == VL53L1_ERROR_NONE && + fw_ready == 0 && + poll_delay_ms > 0) { + status = VL53L1_WaitMs( + Dev, + poll_delay_ms); + } + + + + + + + VL53L1_GetTickCount(¤t_time_ms); + + pdev->fw_ready_poll_duration_ms = + current_time_ms - start_time_ms; + } + + if (fw_ready == 0 && status == VL53L1_ERROR_NONE) + status = VL53L1_ERROR_TIME_OUT; + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_poll_for_range_completion( + VL53L1_DEV Dev, + uint32_t timeout_ms) +{ + + + + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev); + + uint8_t gpio__mux_active_high_hv = 0; + uint8_t interrupt_ready = 0; + + LOG_FUNCTION_START(""); + + gpio__mux_active_high_hv = + pdev->stat_cfg.gpio_hv_mux__ctrl & + VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK; + + if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH) + interrupt_ready = 0x01; + else + interrupt_ready = 0x00; + + status = + VL53L1_WaitValueMaskEx( + Dev, + timeout_ms, + VL53L1_GPIO__TIO_HV_STATUS, + interrupt_ready, + 0x01, + VL53L1_POLLING_DELAY_MS); + + LOG_FUNCTION_END(status); + + return status; +} + + diff --git a/drivers/oneplus/vl53L1/src/vl53l1_zone_presets.c b/drivers/oneplus/vl53L1/src/vl53l1_zone_presets.c new file mode 100755 index 0000000000000000000000000000000000000000..e35f395a233f4e0685143a380fa87b02ca28210c --- /dev/null +++ b/drivers/oneplus/vl53L1/src/vl53l1_zone_presets.c @@ -0,0 +1,253 @@ + +/******************************************************************************* + * Copyright (c) 2017, STMicroelectronics - All Rights Reserved + + This file is part of VL53L1 Core and is dual licensed, + either 'STMicroelectronics + Proprietary license' + or 'BSD 3-clause "New" or "Revised" License' , at your option. + +******************************************************************************** + + 'STMicroelectronics Proprietary license' + +******************************************************************************** + + License terms: STMicroelectronics Proprietary in accordance with licensing + terms at www.st.com/sla0081 + + STMicroelectronics confidential + Reproduction and Communication of this document is strictly prohibited unless + specifically authorized in writing by STMicroelectronics. + + +******************************************************************************** + + Alternatively, VL53L1 Core may be distributed under the terms of + 'BSD 3-clause "New" or "Revised" License', in which case the following + provisions apply instead of the ones + mentioned above : + +******************************************************************************** + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +******************************************************************************** + +*/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include "vl53l1_ll_def.h" +#include "vl53l1_ll_device.h" +#include "vl53l1_platform_log.h" +#include "vl53l1_zone_presets.h" + + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE,\ + status, fmt, ##__VA_ARGS__) + + +VL53L1_Error VL53L1_init_zone_config_structure( + uint8_t x_off, + uint8_t x_inc, + uint8_t x_zones, + uint8_t y_off, + uint8_t y_inc, + uint8_t y_zones, + uint8_t width, + uint8_t height, + VL53L1_zone_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t x = 0; + uint8_t y = 0; + uint16_t i = 0; + + LOG_FUNCTION_START(""); + + pdata->max_zones = VL53L1_MAX_USER_ZONES; + + i = 0; + + for (x = 0 ; x < x_zones ; x++) { + for (y = 0 ; y < y_zones ; y++) { + + if (i < VL53L1_MAX_USER_ZONES) { + + pdata->active_zones = (uint8_t)i; + pdata->user_zones[i].height = height; + pdata->user_zones[i].width = width; + pdata->user_zones[i].x_centre = + x_off + (x * x_inc); + pdata->user_zones[i].y_centre = + y_off + (y * y_inc); + } + + i++; + } + } + + status = VL53L1_init_zone_config_histogram_bins(pdata); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_zone_preset_xtalk_planar( + VL53L1_general_config_t *pgeneral, + VL53L1_zone_config_t *pzone_cfg) +{ + + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + LOG_FUNCTION_START(""); + + + + + + + pgeneral->global_config__stream_divider = 0x05; + + + + pzone_cfg->active_zones = 0x04; + + pzone_cfg->user_zones[0].height = 15; + pzone_cfg->user_zones[0].width = 7; + pzone_cfg->user_zones[0].x_centre = 4; + pzone_cfg->user_zones[0].y_centre = 8; + + pzone_cfg->user_zones[1].height = 15; + pzone_cfg->user_zones[1].width = 7; + pzone_cfg->user_zones[1].x_centre = 12; + pzone_cfg->user_zones[1].y_centre = 8; + + pzone_cfg->user_zones[2].height = 7; + pzone_cfg->user_zones[2].width = 15; + pzone_cfg->user_zones[2].x_centre = 8; + pzone_cfg->user_zones[2].y_centre = 4; + + pzone_cfg->user_zones[3].height = 7; + pzone_cfg->user_zones[3].width = 15; + pzone_cfg->user_zones[3].x_centre = 8; + pzone_cfg->user_zones[3].y_centre = 12; + + + + + pzone_cfg->user_zones[4].height = 15; + pzone_cfg->user_zones[4].width = 15; + pzone_cfg->user_zones[4].x_centre = 8; + pzone_cfg->user_zones[4].y_centre = 8; + + status = VL53L1_init_zone_config_histogram_bins(pzone_cfg); + + + LOG_FUNCTION_END(status); + + return status; +} + + +VL53L1_Error VL53L1_init_zone_config_histogram_bins( + VL53L1_zone_config_t *pdata) +{ + + + + + + VL53L1_Error status = VL53L1_ERROR_NONE; + + uint8_t i; + + LOG_FUNCTION_START(""); + + for (i = 0; i < pdata->max_zones; i++) + pdata->bin_config[i] = VL53L1_ZONECONFIG_BINCONFIG__LOWAMB; + + LOG_FUNCTION_END(status); + + return status; +} + diff --git a/drivers/oneplus/vl53L1/st,stmvl53l1.txt b/drivers/oneplus/vl53L1/st,stmvl53l1.txt new file mode 100755 index 0000000000000000000000000000000000000000..3f81932590c235b37623945be36530e66db84c45 --- /dev/null +++ b/drivers/oneplus/vl53L1/st,stmvl53l1.txt @@ -0,0 +1,26 @@ +StMicroelectronis vl53l1 + +Requires properties: +- compatible: must be "st,stmvl53l1". +- reg: I2C address of the chip. +- xsdn-gpio: gpio number connected to vl53l1 reset pin. + +Optional properties: +- intr-gpio: gpio number connected to vl53l1 irq pin. +- vdd: a phandle for the regulator supplying power for vl53l1. +- pwren-gpio: gpio number use to control vl53l1 power. + +Example: + &i2c1 { + /* ... */ + + stmvl53l1: stmvl53l1@29 { + compatible = "st,stmvl53l1"; + reg = <0x29>; + xsdn-gpio = <19>; + pwren-gpio = <12>; + intr-gpio = <16>; + }; + + /* ... */ + }; diff --git a/drivers/oneplus/vl53L1/stmvl53l1-i2c.h b/drivers/oneplus/vl53L1/stmvl53l1-i2c.h new file mode 100755 index 0000000000000000000000000000000000000000..6e88cb533de47ce46b7f11f58fa9fd02deff39b3 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1-i2c.h @@ -0,0 +1,117 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** @file stmvl53l1-i2c.h + * Linux kernel i2c/cci wrapper for ST VL53L1 sensor i2c interface + **/ + +#ifndef STMVL53L1_I2C_H +#define STMVL53L1_I2C_H +#include +#include "stmvl53l1.h" + +struct i2c_data { + struct i2c_client *client; + /** back link to driver for interrupt and clean-up */ + struct stmvl53l1_data *vl53l1_data; + + /* reference counter */ + struct kref ref; + + /*!< if null no regulator use for power ctrl */ + struct regulator *vdd; + struct regulator *xsd; + + /*!< power enable gpio number + * + * if -1 no gpio if vdd not avl pwr is not controllable + */ + int pwren_gpio; + + /*!< xsdn reset (low active) gpio number to device + * + * -1 mean none assume no "resetable" + */ + int xsdn_gpio; + + /*!< intr gpio number to device + * + * intr is active/low negative edge by default + * + * -1 mean none assume use polling + * @warning if the dev tree and intr gpio is require please adapt code + */ + int intr_gpio; + + /*!< device boot i2c register address + * + * boot_reg is the value of device i2c address after it is bring out + * of reset. + */ + int boot_reg; + + /*!< is set if above irq gpio got acquired */ + struct i2d_data_flags_t { + unsigned pwr_owned:1; /*!< set if pwren gpio is owned*/ + unsigned xsdn_owned:1; /*!< set if sxdn gpio is owned*/ + unsigned intr_owned:1; /*!< set if intr gpio is owned*/ + unsigned intr_started:1; /*!< set if irq is hanlde */ + } io_flag; + + /** the irq vectore assigned to gpio + * -1 if no irq hanled + */ + int irq; + + struct msgtctrl_t { + unsigned unhandled_irq_vec:1; + } msg_flag; +}; + +#ifdef USE_CAMERA_CCI +int __init stmvl53l1_init_cci(void); +void __exit stmvl53l1_exit_cci(void*); +int stmvl53l1_enable_pinctrl(void); +int stmvl53l1_disable_pinctrl(void); +#else +int stmvl53l1_init_i2c(void); +void __exit stmvl53l1_exit_i2c(void *arg); +#endif +int stmvl53l1_power_up_i2c(void *arg); +int stmvl53l1_power_down_i2c(void *arg); +int stmvl53l1_reset_release_i2c(void *arg); +int stmvl53l1_reset_hold_i2c(void *arg); +void stmvl53l1_clean_up_i2c(void); +int stmvl53l1_start_intr(void *object, int *poll_mode); +void *stmvl53l1_get(void *arg); +void stmvl53l1_put(void *arg); + +#endif /* STMVL53L1_I2C_H */ diff --git a/drivers/oneplus/vl53L1/stmvl53l1.h b/drivers/oneplus/vl53L1/stmvl53l1.h new file mode 100755 index 0000000000000000000000000000000000000000..25f14fc467cc57c0311fe4e734c21867b9ab8bbf --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1.h @@ -0,0 +1,391 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file stmvl53l1.h header for vl53l1 sensor driver + */ +#ifndef STMVL53L1_H +#define STMVL53L1_H + +#include +#include +#include +#include +#include + +#include "vl53l1_api.h" + +/** + * IPP adapt + */ +#ifdef DEBUG +# define IPP_PRINT(...) printk(__VA_ARGS__) +#else +# define IPP_PRINT(...) (void)0 +#endif + +#include "stmvl53l1_ipp.h" +#include "stmvl53l1_if.h" + +/** + * Configure the Netlink-id use + */ +#define STMVL531_CFG_NETLINK_USER 31 + +#define STMVL53L1_MAX_CCI_XFER_SZ 256 +#define STMVL53L1_DRV_NAME "stmvl53l1" + +/** + * configure usage of regulator device from device tree info + * to enable/disable sensor power + * see module-i2c or module-cci file + */ +/* define CFG_STMVL53L1_HAVE_REGULATOR */ + +#define DRIVER_VERSION "13.0.1" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * Configure max number of device the driver can support + */ +#define STMVL53L1_CFG_MAX_DEV 2 +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ +#if 1 +#define DEBUG 1 +#endif +#if 1 +#define FORCE_CONSOLE_DEBUG +#endif + +extern int stmvl53l1_enable_debug; + +#ifdef DEBUG +# ifdef FORCE_CONSOLE_DEBUG +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_info("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +# else +#define vl53l1_dbgmsg(str, ...) do { \ + if (stmvl53l1_enable_debug) \ + pr_debug("%s: " str, __func__, ##__VA_ARGS__); \ +} while (0) +# endif +#else +# define vl53l1_dbgmsg(...) (void)0 +#endif + +/** + * set to 0 1 activate or not debug from work (data interrupt/polling) + */ +#define WORK_DEBUG 0 +#if WORK_DEBUG +# define work_dbg(msg, ...)\ + printk("[D WK53L1] :" msg "\n", ##__VA_ARGS__) +#else +# define work_dbg(...) (void)0 +#endif + +#define vl53l1_info(str, args...) \ + pr_info("%s: " str "\n", __func__, ##args) + +#define vl53l1_errmsg(str, args...) \ + pr_err("%s: " str, __func__, ##args) + +#define vl53l1_wanrmsg(str, args...) \ + pr_warn("%s: " str, __func__, ##args) + +/* turn off poll log if not defined */ +#ifndef STMVL53L1_LOG_POLL_TIMING +# define STMVL53L1_LOG_POLL_TIMING 0 +#endif +/* turn off cci log timing if not defined */ +#ifndef STMVL53L1_LOG_CCI_TIMING +# define STMVL53L1_LOG_CCI_TIMING 0 +#endif + +/**@} */ /* ingroup mod_dbg*/ + +#include +#include +#include + +/** if set to 1 enable ipp execution timing (if debug enabled) + * @ingroup vl53l1_mod_dbg + */ +#define IPP_LOG_TIMING 1 + +struct ipp_data_t { + struct ipp_work_t work; + struct ipp_work_t work_out; + int test_n; + /*!< buzy state 0 is idle + *any other value do not try to use (state value defined in source) + */ + int buzy; + int waited_xfer_id; + /*!< when buzy is set that is the id we are expecting + * note that value 0 is reserved and stand for "not waiting" + * as such never id 0 will be in any round trip exchange + * it's ok for daemon to use 0 in "ping" when it identify himself + */ + int status; /** if that is not 0 do not look at out work data */ + wait_queue_head_t waitq; + /*!< ipp caller are put in that queue wait while job is posted to user + * @warning ipp and dev mutex will be released before waiting + * see @ref ipp_abort + */ +#if IPP_LOG_TIMING + struct timeval start_tv, stop_tv; +#endif +}; + +struct stmvl53l1_waiters { + struct list_head list; + pid_t pid; +}; + +/* + * driver data structs + */ +struct stmvl53l1_data { + int id; /*!< multiple device id 0 based*/ + char name[64]; /*!< misc device name */ + + VL53L1_DevData_t stdev; /*!ipp.stop_tv) +# define stmvl531_ipp_tim_start(data)\ + do_gettimeofday(&data->ipp.start_tv) +# define stmvl531_ipp_time(data)\ + stmvl53l1_tv_dif(&data->ipp.start_tv, &data->ipp.stop_tv) +# define stmvl531_ipp_stat(data, fmt, ...)\ + vl53l1_dbgmsg("IPPSTAT " fmt "\n", ##__VA_ARGS__) +#else +# define stmvl531_ipp_tim_stop(data) (void)0 +# define stmvl531_ipp_tim_start(data) (void)0 +# define stmvl531_ipp_stat(...) (void)0 +#endif +}; + + +/** + * timeval diff in us + * + * @param pstart_tv + * @param pstop_tv + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv); + + +/** + * The device table list table is update as device get added + * we do not support adding removing device mutiple time ! + * use for clean "unload" purpose + */ +extern struct stmvl53l1_data *stmvl53l1_dev_table[]; + +int stmvl53l1_setup(struct stmvl53l1_data *data); +void stmvl53l1_cleanup(struct stmvl53l1_data *data); +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data); +#endif +int stmvl53l1_intr_handler(struct stmvl53l1_data *data); + + +/** + * request ipp to abort or stop + * + * require dev work_mutex held + * + * @warning because the "waiting" work can't be aborted we must wake it up + * it will happen and at some later time not earlier than release of lock + * if after lock release we have a new request to start the race may not be + * handled correctly + * + * @param data the device + * @return 0 if no ipp got canceled, @warning this is maybe not grant we + * can't re-sched "dev work" and re-run the worker back + */ +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data); + +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, struct ipp_work_t *work_in, + struct ipp_work_t *work_out); + +/** + * per device netlink init + * @param data + * @return + */ +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data); +/** + * per device ipp netlink cleaning + * @param data + * @return + */ +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data); + +/** + * Module init for netlink + * @return 0 on success + */ +int stmvl53l1_ipp_init(void); + +/** + * Module exit for netlink + * @return 0 on success + */ +void stmvl53l1_ipp_exit(void); + +/** + * enable and start ipp exhange + * @param n_dev number of device to run on + * @param data dev struct + * @return 0 on success + */ +int stmvl53l1_ipp_enable(int n_dev, struct stmvl53l1_data *data); + + +/* + * function pointer structs + */ + + + +#endif /* STMVL53L1_H */ diff --git a/drivers/oneplus/vl53L1/stmvl53l1_i2c.c b/drivers/oneplus/vl53L1/stmvl53l1_i2c.c new file mode 100755 index 0000000000000000000000000000000000000000..bd21dc8cfa20bbfbc0628d9be9b7e3f3a2678d5e --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_i2c.c @@ -0,0 +1,399 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_i2c.c vl53l1 linux native i2c interface + * + */ +#include "stmvl53l1.h" +#include "stmvl53l1-i2c.h" +#include +#include "cam_cci_ctrl_interface.h" + + +#if STMVL53L1_LOG_POLL_TIMING +/** + * helper to elapse time in polling + * @param ptv pointer to start time_val + + */ +# define poll_timing_log(ptv) \ + vl53l1_dbgmsg("poll in %d us\n", tv_elapsed_us(ptv)) +#else +# define poll_timing_log(...) (void)0 +#endif + +#if STMVL53L1_LOG_CCI_TIMING +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ + +/** + * compute elapsed time in in micro sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in micro seconde + */ +static uint32_t tv_elapsed_us(struct timeval *tv) +{ + struct timeval now; + + do_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - + tv->tv_usec); +} + +# define cci_access_var struct timeval cci_log_start_tv +# define cci_access_start()\ + do_gettimeofday(&cci_log_start_tv) +# define cci_access_over(fmt, ...) \ + vl53l1_dbgmsg("cci_timing %d us" fmt "\n", \ + tv_elapsed_us(&cci_log_start_tv), ##__VA_ARGS__) +#else +# define cci_access_var +# define cci_access_start(...) (void)0 +# define cci_access_over(...) (void)0 +#endif + +#ifdef STMVL53L1_DEBUG_I2C +# define i2c_debug(fmt, ...) vl53l1_dbgmsg(fmt, ##__VA_ARGS__) +#else +# define i2c_debug(fmt, ...) (void)0 +#endif + +VL53L1_Error VL53L1_GetTickCount(uint32_t *ptime_ms) +{ + (void)ptime_ms; + BUG_ON(1); +} + +/** + * compute elapsed time in in milli sec based on do_gettimeofday + * @param tv pointer to start time_val + * @return time elapsed in milli seconde + */ +static uint32_t tv_elapsed_ms(struct timeval *tv) +{ + struct timeval now; + + do_gettimeofday(&now); + return (now.tv_sec - tv->tv_sec) * 1000 + + (now.tv_usec - tv->tv_usec) / 1000; +} + +#ifndef USE_CAMERA_CCI +static int cci_write(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[STMVL53L1_MAX_CCI_XFER_SZ + 2]; + struct i2c_msg msg; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + /* copy write data to buffer after index */ + memcpy(buffer + 2, data, len); + /* set i2c msg */ + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buffer; + msg.len = len + 2; + + rc = i2c_transfer(client->adapter, &msg, 1); + if (rc != 1) { + vl53l1_errmsg("wr i2c_transfer err:%d, index 0x%x len %d\n", + rc, index, len); + } + cci_access_over("rd status %d long %d ", rc != 1, len); + return rc != 1; +} + +static int cci_read(struct stmvl53l1_data *dev, int index, + uint8_t *data, uint16_t len) +{ + uint8_t buffer[2]; + struct i2c_msg msg[2]; + struct i2c_data *i2c_client_obj = (struct i2c_data *)dev->client_object; + struct i2c_client *client = (struct i2c_client *)i2c_client_obj->client; + int rc; + + cci_access_var; + if (len > STMVL53L1_MAX_CCI_XFER_SZ || len == 0) { + vl53l1_errmsg("invalid len %d\n", len); + return -1; + } + cci_access_start(); + + /* build up little endian index in buffer */ + buffer[0] = (index >> 8) & 0xFF; + buffer[1] = (index >> 0) & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; /* Write */ + msg[0].buf = buffer; + msg[0].len = 2; + /* read part of the i2c transaction */ + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD | client->flags; + msg[1].buf = data; + msg[1].len = len; + + rc = i2c_transfer(client->adapter, msg, 2); + if (rc != 2) { + pr_err("%s: i2c_transfer :%d, @%x index 0x%x len %d\n", + __func__, rc, client->addr, index, len); + + } + cci_access_over(" wr len %d status %d", rc != 2, len); + return rc != 2; +} +#endif +VL53L1_Error VL53L1_WrByte(VL53L1_DEV pdev, uint16_t index, uint8_t data) +{ + struct stmvl53l1_data *dev; + struct camera_cci_transfer ccit; + dev = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_WRITE; + ccit.addr = index; + ccit.data = &data; + ccit.count = 1; + return cam_cci_control_interface(&ccit); +#else + return cci_write(dev, index, &data, 1); +#endif +} + +VL53L1_Error VL53L1_RdByte(VL53L1_DEV pdev, uint16_t index, uint8_t *pdata) +{ + struct stmvl53l1_data *dev; + struct camera_cci_transfer ccit; + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = pdata; + ccit.count = 1; + return cam_cci_control_interface(&ccit); +#else + return cci_read(dev, index, pdata, 1) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +VL53L1_Error VL53L1_WrWord(VL53L1_DEV pdev, uint16_t index, uint16_t data) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + /* Split 16-bit word into MS and L* stmvl53l1 FlightSense sensor */ + + buffer[0] = (uint8_t) (data >> 8); + buffer[1] = (uint8_t) (data & 0x00FF); + i2c_debug(" @%x d= %x => [ %x , %x ] ", index, data, buffer[0], + buffer[1]); + status = VL53L1_WriteMulti(pdev, index, buffer, 2); + + return status; +} + +VL53L1_Error VL53L1_RdWord(VL53L1_DEV pdev, uint16_t index, uint16_t *pdata) +{ + VL53L1_Error status; + uint8_t buffer[2]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 2); + + *pdata = ((uint16_t) buffer[0] << 8) + (uint16_t) buffer[1]; + + return status; +} + +VL53L1_Error VL53L1_WrDWord(VL53L1_DEV pdev, uint16_t index, uint32_t data) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + /* Split 32-bit word into MS ... LS bytes */ + buffer[0] = (uint8_t) (data >> 24); + buffer[1] = (uint8_t) ((data & 0x00FF0000) >> 16); + buffer[2] = (uint8_t) ((data & 0x0000FF00) >> 8); + buffer[3] = (uint8_t) (data & 0x000000FF); + + status = VL53L1_WriteMulti(pdev, index, buffer, 4); + + return status; +} + +VL53L1_Error VL53L1_RdDWord(VL53L1_DEV pdev, uint16_t index, uint32_t *pdata) +{ + VL53L1_Error status = VL53L1_ERROR_NONE; + uint8_t buffer[4]; + + status = VL53L1_ReadMulti(pdev, index, buffer, 4); + + *pdata = ((uint32_t) buffer[0] << 24) + ((uint32_t) buffer[1] << 16) + + ((uint32_t) buffer[2] << 8) + (uint32_t) buffer[3]; + + return status; +} + +VL53L1_Error VL53L1_WriteMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; + struct camera_cci_transfer ccit; + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_WRITE; + ccit.addr = index; + ccit.data = pdata; + ccit.count = count; + return cam_cci_control_interface(&ccit); +#else + return cci_write(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +VL53L1_Error VL53L1_ReadMulti(VL53L1_DEV pdev, uint16_t index, + uint8_t *pdata, uint32_t count) +{ + struct stmvl53l1_data *dev; + struct camera_cci_transfer ccit; + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = pdata; + ccit.count = count; + return cam_cci_control_interface(&ccit); +#else + return cci_read(dev, index, pdata, count) ? + VL53L1_ERROR_CONTROL_INTERFACE : VL53L1_ERROR_NONE; +#endif +} + +static int is_time_over(struct timeval *tv, uint32_t msec) +{ + return tv_elapsed_ms(tv) >= msec; +} + +VL53L1_Error VL53L1_WaitValueMaskEx(VL53L1_DEV pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, uint32_t poll_delay_ms) +{ + struct timeval start_tv; + struct stmvl53l1_data *dev; + int rc, time_over; + uint8_t rd_val; + struct camera_cci_transfer ccit; + + dev = (struct stmvl53l1_data *) container_of(pdev, + struct stmvl53l1_data, stdev); + + do_gettimeofday(&start_tv); + do { +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_READ; + ccit.addr = index; + ccit.data = &rd_val; + ccit.count = 1; + rc = cam_cci_control_interface(&ccit); +#else + rc = cci_read(dev, index, &rd_val, 1); +#endif + if (rc) + return VL53L1_ERROR_CONTROL_INTERFACE; + if ((rd_val & mask) == value) { + poll_timing_log(&start_tv); + return VL53L1_ERROR_NONE; + } + vl53l1_dbgmsg("poll @%x %x & %d != %x", index, + rd_val, mask, value); + time_over = is_time_over(&start_tv, timeout_ms); + if (!time_over) + msleep(poll_delay_ms); + } while (!time_over); + vl53l1_errmsg("time over %d ms", timeout_ms); + return VL53L1_ERROR_TIME_OUT; +} + +VL53L1_Error VL53L1_WaitUs(VL53L1_DEV pdev, int32_t wait_us) +{ + struct stmvl53l1_data *data; + + data = (struct stmvl53l1_data *)container_of(pdev, + struct stmvl53l1_data, + stdev); + + if (!data->is_delay_allowed) + return VL53L1_ERROR_PLATFORM_SPECIFIC_START; + + /* follow Documentation/timers/timers-howto.txt recommendations */ + if (wait_us < 10) + udelay(wait_us); + else if (wait_us < 20000) + usleep_range(wait_us, wait_us + 1); + else + msleep(wait_us / 1000); + + return VL53L1_ERROR_NONE; +} + +VL53L1_Error VL53L1_WaitMs(VL53L1_DEV pdev, int32_t wait_ms) +{ + return VL53L1_WaitUs(pdev, wait_ms * 1000); +} diff --git a/drivers/oneplus/vl53L1/stmvl53l1_if.h b/drivers/oneplus/vl53L1/stmvl53l1_if.h new file mode 100755 index 0000000000000000000000000000000000000000..1e3fe358625509f60dbf6518489414a95ccd7433 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_if.h @@ -0,0 +1,671 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +/** + * @file stmvl53l1_if.h vl53l1 kernel driver user interface + * + * @note to use this header in a user space application it requires + * all st bare/ll driver platform wrapper files (for data struct def) + * this files (types etc ..) shall be same or compliant with bar driver version + * used in the kernel module + */ + +#ifndef STMVL53L1_IF_H +#define STMVL53L1_IF_H + + +#include "vl53l1_def.h" +/** + * @addtogroup vl53l1_ioctl + * @{ + */ + +/** + * misc device name for ioctl device + * + * for mutli instance all device 2nd and next instance are basic name +"1"+"2" + * @li stmvl53l1_ranging + * @li stmvl53l1_ranging1 + * @li stmvl53l1_ranging2 + */ +#define VL53L1_MISC_DEV_NAME "stmvl53l1_ranging" +/** + * register data use for simple/single ranging data @ref VL53L1_IOCTL_GETDATAS + * + * @warning this definition is subject to change ! + */ +#define stmvl531_range_data_t VL53L1_RangingMeasurementData_t + +/** + * parameter name in @ref stmvl53l1_parameter when using + * @ref VL53L1_IOCTL_PARAMETER + */ +enum __stmv53l1_parameter_name_e { + VL53L1_XTALKENABLE_PAR = 2, + /*!< VL53L1_XTALKENABLE_PAR enable/disable crosstalk compensation\n + * valid value : + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @warning mode can only be set while not ranging + */ + + VL53L1_DEVICEMODE_PAR = 6, + /*!< DEVICEMODE_PAR set ranging mode  \n + * valid mode value : + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * @li 8 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low power autonomous + * mode + * + * @warning mode can only be set while not ranging + */ + + VL53L1_POLLDELAY_PAR = 10, + /*!< set the polling delay (msec)\n + * + * @note apply only when operates in polling mode as no effect + * otherwise + */ + VL53L1_TIMINGBUDGET_PAR = 11, + /*!< VL53L1_TIMINGBUDGET_PAR + * @ref stmvl53l1_parameter.value field is timing budget in micro second + */ + + VL53L1_DISTANCEMODE_PAR = 12, + /*!< VL53L1_DISTANCEMODE_PAR + * valid distance mode value : + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_OUTPUTMODE_PAR = 13, + /*!< VL53L1_OUTPUTMODE_PAR + * valid output mode value : + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @warning distance mode can only be set while not ranging + */ + + VL53L1_FORCEDEVICEONEN_PAR = 14, + /*!< VL53L1_FORCEDEVICEONEN_PAR + * This parameter will control if device is put under reset when + * stopped. + * valid force device on value : + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + */ + + VL53L1_LASTERROR_PAR = 15, + /*!< VL53L1_LASTERROR_PAR + * This is a read only parameter. It will return last device internal + * error. It's valid only after an ioctl/sysfs return an -EIO error. + */ + + VL53L1_OFFSETCORRECTIONMODE_PAR = 16, + /*!< VL53L1_OFFSETCORRECTIONMODE_PAR + * This parameter will define which mode to use for the offset + * correction. + * valid force device on value : + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @warning offset correction mode can only be set while not ranging + */ + + VL53L1_OPTICALCENTER_PAR = 17, + /*!< VL53L1_OPTICALCENTER_PAR + * This is a read only parameter. It will return optical center issued + * from the nvm set at FTM stage. value will contain X position of + * center. value2 will contain Y position of center. + * Return values have FixPoint1616_t type. + */ + + VL53L1_DMAXREFLECTANCE_PAR = 18, + /*!< VL53L1_DMAXREFLECTANCE_PAR + * This parameter will define target reflectance @ 940nm used to + * calculate the ambient DMAX. Parameter is of type FixPoint1616_t. + * + * @warning dmax reflectance can only be be set while not ranging + */ + + VL53L1_DMAXMODE_PAR = 19, + /*!< VL53L1_DMAXMODE_PAR + * This parameter will select Dmax mode. + * valid Dmax mode value : + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @warning Dmax mode can only be set while not ranging + */ + + VL53L1_TUNING_PAR = 20, + /*!< VL53L1_DMAXMODE_PAR + * This parameter is a write only parameter. It will allow to provide + * low level layer with a configuration parameter. + * value will be use as a key parameter. + * value2 will be use as value parameter. + * + * @warning those configuration parameter settings are only allowed + * before device is start once. + */ + + VL53L1_SMUDGECORRECTIONMODE_PAR = 21, + /*!< VL53L1_SMUDGECORRECTIONMODE_PAR + * This parameter will control if smudge correction is enable and how + * crosstalk values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + */ + + VL53L1_ISXTALKVALUECHANGED_PAR = 22, + /*!< VL53L1_ISXTALKCHANGED_PAR + * This is a read only parameter. It will return if Xtalk value has + * been updated while ranging. This parameter is reset each time device + * start to range. + * @li 0 Xtalk values has not been changed. + * @li 1 Xtalk values has been changed. + */ +}; +#define stmv53l1_parameter_name_e enum __stmv53l1_parameter_name_e + +/** + * parameter structure use in @ref VL53L1_IOCTL_PARAMETER + */ +struct stmvl53l1_parameter { + uint32_t is_read; /*!< [in] 1: Get 0: Set*/ + /*!< [in] parameter to set/get + * see @ref stmv53l1_parameter_name_e + */ + stmv53l1_parameter_name_e name; + int32_t value; /*!< [in/out] value to set /get */ + int32_t value2; /*!< [in/out] optional 2nd value */ + int32_t status; /*!< [out] status of the operation */ +}; + + +/** + * roi structure use as @ref VL53L1_IOCTL_ROI arg + * + * see @ref stmvl53l1_roi_full_t for easy to use type variable declaration + * required + */ +struct stmvl53l1_roi_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + /*! roi data and count type use in @ VL53L1_IOCTL_ROI */ + struct roi_cfg_t { + uint8_t NumberOfRoi; + /*!< [in/out] Number of Rois to set/get + * + * on set :\n + * [in] number of roi to set + * @note 0 set can be used to return to device default roi usage + * + * on get :\n + * [in] max number provided\n + * [out] number of ROI copied back to user\n + * @warning 0 will not return any roi datas! + */ + VL53L1_UserRoi_t UserRois[1]; + /*!< roi data array length definition is 1 but + * NumberOfRoi+ FirstRoiToScan in array are required + * and will be effectively copy to/from user space + * + * @sa stmvl53l1_roi_full_t + */ + } roi_cfg /*! [in/out] roi data and count */; +}; + +/** + * full roi struct use in @ref VL53L1_IOCTL_ROI arg + * + * this definition make easier variable declaration with the max roi storage + * capabilities. + * + * @sa stmvl53l1_roi_t for field details + */ +struct stmvl53l1_roi_full_t { + int32_t is_read; + /*!< specify roi transfer direction \n + * @li 0 to get roi + * @li !0 to set roi + */ + VL53L1_RoiConfig_t roi_cfg; + /*!< roi data array of max length but only requested copy to/from user + * space effectively used + * see @a stmvl53l1_roi_t::roi_cfg for details + */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + VL53L1_CalibrationData_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** + * Opaque structure use to hold content of zone offset calibration result. + */ +#define stmvl531_zone_calibration_data_t \ + struct _stmvl531_zone_calibration_data_t + +struct _stmvl531_zone_calibration_data_t { + uint32_t id; + VL53L1_ZoneCalibrationData_t data; +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_ZONE_CALIBRATION_DATA + */ +struct stmvl53l1_ioctl_zone_calibration_data_t { + int32_t is_read; /*!< [in] 1: Get 0: Set*/ + stmvl531_zone_calibration_data_t data; + /*!< [in/out] data to set /get. Caller + * should consider this structure as an opaque one + */ +}; + +/** Select reference spad calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1, param2 and param3 not use + */ +#define VL53L1_CALIBRATION_REF_SPAD 0 + +/** Select crosstalk calibration in @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * + * param1 is calibration method. param2 and param3 not use. + * @li VL53L1_XTALKCALIBRATIONMODE_NO_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_SINGLE_TARGET + * @li VL53L1_XTALKCALIBRATIONMODE_FULL_ROI + */ +#define VL53L1_CALIBRATION_CROSSTALK 1 + +/** Select offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is either: + * - VL53L1_OFFSETCALIBRATIONMODE_STANDARD + * - VL53L1_OFFSETCALIBRATIONMODE_PRERANGE_ONLY + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE (deprecated) + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE usage is deprecated. Per + * zone offset calibration should use VL53L1_CALIBRATION_OFFSET_PER_ZONE + * instead. + */ +#define VL53L1_CALIBRATION_OFFSET 2 + +/** Select offset calibration per zone @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is offset calibration mode. Parameter is: + * - VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE + * param2 is target distance in mm. + * param3 is target reflectance in percent. Parameter is of type FixPoint1616_t. + * + * Note that region of interest should be defined by a prior call to + * VL53L1_IOCTL_ROI before calling VL53L1_IOCTL_PERFORM_CALIBRATION / + * VL53L1_CALIBRATION_OFFSET combinaison. + */ +#define VL53L1_CALIBRATION_OFFSET_PER_ZONE 3 + +/** Select simple offset calibration @ref VL53L1_IOCTL_PERFORM_CALIBRATION. + * param1 is target distance in mm. + * param2 and param3 are not used + */ +#define VL53L1_CALIBRATION_OFFSET_SIMPLE 4 + +/** + * parameter structure use in @ref VL53L1_IOCTL_PERFORM_CALIBRATION + */ +struct stmvl53l1_ioctl_perform_calibration_t { + uint32_t calibration_type; + /*!< [in] select which calibration to do : + * @li @ref VL53L1_CALIBRATION_REF_SPAD + * @li @ref VL53L1_CALIBRATION_CROSSTALK + * @li @ref VL53L1_CALIBRATION_OFFSET + * @li @ref VL53L1_CALIBRATION_OFFSET_SIMPLE + * @li @ref VL53L1_CALIBRATION_OFFSET_PER_ZONE + */ + uint32_t param1; + /*!< [in] first param. Usage depends on calibration_type */ + uint32_t param2; + /*!< [in] second param. Usage depends on calibration_type */ + uint32_t param3; + /*!< [in] third param. Usage depends on calibration_type */ +}; + +/** + * parameter structure use in @ref VL53L1_IOCTL_AUTONOMOUS_CONFIG + */ +struct stmvl53l1_autonomous_config_t { + int32_t is_read; + /*!< [in] 1: Get 0: Set*/ + uint32_t pollingTimeInMs; + /*!< [in/out] interval between two measure in ms */ + VL53L1_DetectionConfig_t config; + /*!< [int/out] autonomous mode configuration structure */ +}; + +/* + * IOCTL definitions + */ + + +/** + * Start ranging (no argument) + * + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute with no consideration of sysfs path. + * + * @return : + * @li 0 on success + * @li -EBUSY if already started + * @li -ENXIO failed to change i2c address change after reset release + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * example user land : + @code + int smtvl53l1_start(int fd){error + int rc; + rc= ioctl(fd, VL53L1_IOCTL_START,NULL); + if( rc ){ + if( errno == EBUSY){ + //the device is already started + ioctl_warn("already started"); + return EBUSY; + } + } + if( rc ){ + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} + @endcode +*/ + +#define VL53L1_IOCTL_START _IO('p', 0x01) + +/** + * stop ranging (no argument) + + * @note sysfs and ioctl control are assumed mutual exclusive use + * control from ioctl execute action with no consideration of sysfs path. + * + * @return + * @li 0 on success + * @li -EBUSY if it was already + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + * + * c example userland : + @code +int smtvl53l1_stop(int fd){ + int rc; + rc= ioctl(fd, VL53L1_IOCTL_STOP,NULL); + if( rc ){ + if( errno == EBUSY ){ + ioctl_warn("already stopped"); + return errno; + } + ioctl_error("%d %s", rc,strerror(errno)); + } + return rc; +} +@endcode + */ +#define VL53L1_IOCTL_STOP _IO('p', 0x05) + +/** + * get single ranging data @sa for multi zone/objet + * + * retrieve the last range data available form the device + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV. Device has been removed. + * + * @warning this ioctl will not wait for a new range sample acquisition + * it will return what available at time it get called . Hence same data maybe + * returned many time when doing fast polling.\n + * End user must inspect the data structure (time stamp etc )to find about it\n + * Despite it's non "waiting" nature this ioctl may still block/sleep shortly + * to ensure race free usage acquiring mutex and/or locks. + */ +#define VL53L1_IOCTL_GETDATAS \ + _IOWR('p', 0x0b, stmvl531_range_data_t) + +/** + * set or get parameter + * + * @param parameter in/out @ref stmvl53l1_parameter + * @sa stmv53l1_parameter_name_e + * + * for get if ioctl fail do not check for out params it is not valid + * for set theirs not copy back only see ioctl status, errno to get error case + * + * @return 0 on success else o, error check errno + * @li -ENODEV. Device has been removed. + * + * @note a set parameter may not be absorbed straight aways ! + */ +#define VL53L1_IOCTL_PARAMETER \ + _IOWR('p', 0x0d, struct stmvl53l1_parameter) + + +/** + * set/get roi + * + * shall only be use while device is stopped (EBUSY error otherwise) + * setting 0 rois stand for "disable user define roi usage, use device default" + * + * @param roi_cfg [in/out] type @ref stmvl53l1_roi_t and + * @ref stmvl53l1_roi_full_t + * @note when getting roi the returned roi cnt is set to available number + * of roi in driver but at most requested number or available one + * will be set in returned structure + * @warning the coordinate system is not usual image x,y (y down)but traditional + * ecludian x,y (y up) + * + * @warning once defined the user roi is kept alive until unset by user . + * User shall update roi when required (mode change etc ..)\n + * To return to default unset roi by setting none, device will return to default + * at next start + * + * @note roi validity is only checked at start ranging , as such invalid roi set + * can make start to fail + * + * @return 0 on success , see errno for error detail + * @li EBUSY when trying to set roi while ranging + * @li ENODEV never device get started and trying to get more rois than set + * @li other errno code could be ll driver specific + */ +#define VL53L1_IOCTL_ROI\ + _IOWR('p', 0x0e, struct stmvl53l1_roi_t) + +/** + * Get multi object/zone ranging data + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA\ + _IOR('p', 0x0f, VL53L1_MultiRangingData_t) + +/** + * get single ranging data @sa for multi zone/objet + * + * this call is equivalent to VL53L1_IOCTL_GETDATAS but will block until + * new data are available since previous call. + * + * @param in/out data struct ptr of type @ref stmvl531_range_data_t + * it may come in but is out as of now + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + */ +#define VL53L1_IOCTL_GETDATAS_BLOCKING\ + _IOWR('p', 0x10, stmvl531_range_data_t) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA but will block until + * new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_BLOCKING\ + _IOR('p', 0x11, VL53L1_MultiRangingData_t) + +/** + * Get / set calibration data + * + * this call allow client to either read calibration data after calibration + * has been performed to store them in the host filesystem or push calibration + * data before ranging at each start-up. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * use this after either VL53L1_CALIBRATION_REF_SPAD, + * VL53L1_CALIBRATION_CROSSTALK or VL53L1_CALIBRATION_OFFSET. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_calibration_data_t) + +/** + * Get / set zone calibration data + * + * this call allow client to either read zone calibration data after calibration + * has been performed to store them in the host filesystem or push zone + * calibration data before ranging at each start-up. + * + * use this after VL53L1_CALIBRATION_OFFSET_PER_ZONE calibration. + * + * @param [in/out] data struct ptr of type + * @ref stmvl53l1_ioctl_zone_calibration_data_t. Caller should consider it as an + * opaque structure. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to set calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_ZONE_CALIBRATION_DATA\ + _IOWR('p', 0x12, struct stmvl53l1_ioctl_zone_calibration_data_t) + +/** + * perform calibration squence according to calibration_type + * + * this call is attended to be used during factory calibration. You select + * calibration to issue using calibration_type. + * + * @param [in] data struct ptr of type + * @ref stmvl53l1_ioctl_perform_calibration_t. + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copied + * @li -EBUSY when trying to perform calibration data while ranging + * @li -EIO. Read last_error to get device error code + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_PERFORM_CALIBRATION\ + _IOW('p', 0x13, struct stmvl53l1_ioctl_perform_calibration_t) + +/** + * set/get configure autonomous mode parameters + * + * Allow to get or set autonomous configuration. Change it only when device + * is stopped otherwise you will receive an EBUSY error. + * + * @param stmvl53l1_autonomous_config_t [in/out] + * + * @note autonomous config validity is only checked at start ranging , as such + * invalid autonomous config set can make start to fail. + * + * @return 0 on success , see errno for error detail + * @li -EFAULT failed to copy from/to configuration. + * @li -EBUSY when trying to change configuration while ranging. + * @li -ENODEV. Device has been removed. + */ +#define VL53L1_IOCTL_AUTONOMOUS_CONFIG\ + _IOWR('p', 0x14, struct stmvl53l1_autonomous_config_t) + +/** @} */ /* ioctl group */ +#endif /* STMVL53L1_IF_H */ diff --git a/drivers/oneplus/vl53L1/stmvl53l1_internal_if.h b/drivers/oneplus/vl53L1/stmvl53l1_internal_if.h new file mode 100755 index 0000000000000000000000000000000000000000..5a4c004c1ffdf930b8d75eb2c37854fd49ecadb2 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_internal_if.h @@ -0,0 +1,120 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +#ifndef STMVL53L1_INTERNAL_IF_H +#define STMVL53L1_INTERNAL_IF_H + +#include "vl53l1_def.h" + +/* interface definition move in this file is not supposed to be use by a normal + * client. It's only here for internal testing purpose. + */ + +/* structure and ioctl that allow raw access to vl53l1 register */ +struct stmvl53l1_register { + uint32_t is_read; /*!< type of the access 1: read 0: write*/ + uint32_t index; /*!< register index */ + uint32_t cnt; /*!< register size shall be 1 to n */ + int32_t status; /*!< operation status 0 ok else error */ + + union reg_data_t { + uint8_t b; /*!< single data byte*/ + uint16_t w; /*!< single data word (16 bits)*/ + uint32_t dw; /*!< single data dword (32 bits)*/ + /*!< any size byte array + * @note only effectively used array size is needed and will be + * set/used another possible register definition is + * @ref stmvl53l1_register_flexi + */ + uint8_t bytes[256]; + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by + * @ref VL53L1_IOCTL_REGISTER + */ + } data; +}; + +struct stmvl53l1_register_flexi { + uint32_t is_read; /*!< [in] type of the access 1: read 0: write*/ + uint32_t index; /*!< [in] register index */ + uint32_t cnt; /*!< [în] register size shall be 1 to n */ + int32_t status; /*!< [out] operation status 0 ok else error */ + uint8_t data[]; /*!< [in/out] flexible array size data */ + /*!< data only *@warning device is big endian and + * no endianess adaptation is performed by @ref VL53L1_IOCTL_REGISTER + */ +}; + +#define VL53L1_IOCTL_REGISTER _IOWR('p', 0x0c, struct stmvl53l1_register) + +struct stmvl53l1_data_with_additional { + VL53L1_MultiRangingData_t data; + VL53L1_AdditionalData_t additional_data; +}; + +/** + * Get multi object/zone ranging data with additional data for debug + * + * this call is non blocking and will return what available internally + * in all case (veen error) + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL\ + _IOR('p', 0x15, struct stmvl53l1_data_with_additional) + +/** + * Get multi object/zone ranging data + * + * this call is equivalent to VL53L1_IOCTL_MZ_DATA_ADDITIONAL but will block + * until new data are available since previous call. + * + * @param [out] multi zone range @ref VL53L1_MultiRangingData_t always update + * but -EFAULT error case + * + * @return 0 on success else o, error check errno + * @li -EFAULT fault in cpy to f/m user out range data not copyed + * @li -ENOEXEC active mode is not mutli-zone + * @li -ENODEV device is not ranging or device has been removed. + * @li -ERESTARTSYS interrupt while sleeping. + * as in that case MZ data may not be fully valid + */ +#define VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\ + _IOR('p', 0x16, struct stmvl53l1_data_with_additional) + +#endif diff --git a/drivers/oneplus/vl53L1/stmvl53l1_ipp.h b/drivers/oneplus/vl53L1/stmvl53l1_ipp.h new file mode 100755 index 0000000000000000000000000000000000000000..31e75a196debba451f083318150fe30392e2ddd1 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_ipp.h @@ -0,0 +1,386 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_ipp.h + * + * helper to serialize de-serialize data in ipp exchange between user/kernel + * + * @date Sep 2, 2016 + * @author imaging + */ + +#ifndef _STMVL53L1_IPP_H_ +#define _STMVL53L1_IPP_H_ + +#include "vl53l1_types.h" + + +/** @ingroup ipp_dev + * @{ + */ + +/** + * @defgroup ipp_serialize ST IPP serialization helper + * + * to use the dump help you lust define first a few extra "specific" + * + * @li IPP_PRINT(fmt,..) with typical printf/printk interface + */ + /** @{ */ +/** + * generic data type to serialized scalar and offset for pointer + * + * serialized data can be seen as a first array of n ipp_art_t + * where each input are arg value for scaler type + * and an offset with respect to the ipp_arg base array where the data + * + * @note if all ipp argument can fit on 32 bit then ipp_arg_t is best set as + * a 32 bit base type '(i e uint32_t) to save space + * on 64 bit cpu it can remain 64 bit type to get better alignment + */ +typedef uint64_t ipp_arg_t; + +/** + * set to the cpu structure alignment and packing constrain + * + * all serialized argument passed by pointer will be stored with + * this memory align constrain + * + * + * @note if target cpu is ok to access unaligned data or less constrain ie 64 + * bit data align 32 are ok then it can be set to 4 to save space in data + * packing and copy\n + * We may be over constraining in many cases as a struct is only required to + * be aligned on i'st biggest item size + * + * @warning it must be a 2 power of 2 (& operation instead of mudulo used in + * align calculation) + * @warning using 8 byte constrain require that the @a ipp_arg_t is already + * aligned on that constrain + */ +#define IPP_ALIGN_REQ 8 + +/** + * set x to it's nearest aligned offset (not that 0 is fine as a valid offset + * than will not be up aligned to next align chunk ) + */ +#define IPP_ALIGN_OFFSET(x) (((x)+(IPP_ALIGN_REQ-1)) & (~(IPP_ALIGN_REQ-1))) + +/** + * declare variable needed for ipp serialization + */ +#define IPP_SERIALIZE_VAR int ipp_offset +/** + * Put in function start to init the serialization coding + * + * @param ipp_args buffer for data serialization + * @param n_args is the total number of argument scalar and ptr to serialized + * dot not count out only arg that will be returned + * + * it define local var "ipp_offset" used to accumulate all input args that must + * be serialize. It reserve header room in the buffer to place for scalar args + * and offset for args ptr copy + * + * args pass by pointer must be serialized by @ref IPP_SET_ARG_PTR in order they + * are declare\n + * scalar args can be serialized in any order with @ref IPP_SET_ARG + * + * scalar args that can't be cast to basic @ref ipp_arg_t shall be serialized + * Manually or using a macro similar to ptr that can be pass by copy + * + *@note @ref IPP_SERIALIZE_VAR must be use first + * @code + * int ipp_to _ser(int arg0, struct st_t *pdata1){ + * char *local var; + * ipp_arg_t args[256]; + * IPP_SERIALIZE_START(2); + * IPP_SET_ARG(args, 0, arg0); + * IPP_SET_ARG_PTR(args, 1, pdata); + * do_one_ipp(args); + * } + * @endcode + * + */ +#define IPP_SERIALIZE_START(ipp_args, n_args)\ + (ipp_offset = IPP_ALIGN_OFFSET((char *)(&ipp_args[n_args]) - \ + (char *)ipp_args)) + +/** + * @brief Serialize scalar argument + * + * serialized arg number n into ipp_args\n + * can be used in any order + * + * @param ipp_args the args buffer + * @param n 0 base arg number + * @param v the scalar argument variable + * @warning usable only for scalar type that can be copy on a ipp_arg_t + */ +#define IPP_SET_ARG(ipp_args, n, v) memcpy(&ipp_args[n], &v, sizeof(v)) + +/** + * @brief Serialize an arg passed by pointer + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize + * @param pdata argument it must be a type like struct x_t * int [n] etc ... + * that size is given by size of and and be copied by a single memcpy + */ +#define IPP_SET_ARG_PTR(ipp_args, n, pdata)\ + do {\ + ipp_args[n] = ipp_offset;\ + memcpy(((char *)ipp_args) + ipp_offset, pdata, sizeof(*pdata));\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + sizeof(*pdata));\ + } while (0) + +/** + * serialize out get ptr for pdata + * + * @note it does not cpy data just set ptr and update the offset + * @warning to be use in order + * + * @param ipp_args the arg ptr array + * @param n the arg number to serialize (unused) + * @param pdata init to ptr in ipp_args type is used for offset computation + * @warning to use sequential in order agr are serialized + */ +#define IPP_OUT_ARG_PTR(ipp_args, n, pdata)\ + do {\ + pdata = (void *)(((char *)ipp_args) + ipp_offset);\ + ipp_offset = IPP_ALIGN_OFFSET(ipp_offset + \ + (int)sizeof(*pdata));\ + } while (0) + + +/** + * @brief ipp get payload + * + * @return paylaod at time used \n + * when all done it's overall out payload + * + * require @ref IPP_SERIALIZE_VAR and @ref IPP_SERIALIZE_START used first\n + * best use after all @ref IPP_OUT_ARG_PTR or @ref IPP_SET_ARG_PTR done to get + * full payload + **/ +#define IPP_SERIALIZE_PAYLAOD() (ipp_offset + IPP_WORK_HDR_SIZE) + +/** + * de-serialize and argument that was passed by value + * @param ipp_args the args array + * @param n the 0 base argument number + * @param v argument it must be exact type + * + * + * @code + * f_deserialize(ipp_arg_t args[]) + * { + * // f_ser is like (uint16_t arg0, struct s_arg_t * arg1, int arg2) + * uint16_t arg0; + * void * parg1; + * int arg2; + * + * IPP_GET_ARG( args, 0, arg0) + * IPP_GET_ARG( args, 2, arg2) + * } + * @endcode + */ +#define IPP_GET_ARG(ipp_args, n, v) memcpy(&v, &ipp_args[n], sizeof(v)) + + +/** + * de-serialize an argument passed by pointer + * + * @param ipp_args the serialized argument array + * @param n 0 base argument number + * @param p ptr to arg to be set + * + * @note unlike serializing de-serializing pointer args data can be done in any + * order + * + * @code + * struct some_struct_t *parg2; + * IPP_GET_ARG_PTR(args,2,parg2); + * @endcode + */ +#define IPP_GET_ARG_PTR(ipp_args, n, p) (p = (void *)((char *)ipp_args + \ + ipp_args[n])) + + + + +/** + * debug macro to pint out all serialized args + * + * Implementation shall define IPP_PRINT_FUNC function to use + */ +#define IPP_PRINT_ARGS(ipp_args, n) \ + do {\ + int i;\ + for (i = 0; i < n; i++)\ + IPP_PRINT("arg#%d/%d is %8d 0x%08x\n", i, n,\ + ipp_args[i], ipp_args[i]);\ + IPP_PRINT("used data size %d\n", ipp_offset);\ + } while (0) + + +/** + * processing code type of proccesing + * + * used in @a ipp_work_t::process_no + */ +enum stmvl53l1_ipp_proccesing_e { + stmvl53l1_ipp_ping = 0, + /*!< stmvl53l1_ipp_ping + * @li can be sent by driver to check client is alive + * @li daemon sent it to identify and register himself to the driver + */ + stmvl53l1_ipp_cal_hist = 1, + /*!< stmvl53l1_ipp_cal_hist process cal hist*/ + + stmvl53l1_ipp_xtalk_calibration = 2, + /*!< stmvl53l1_ipp_xtalk_calibration process crosstalk calibration data + */ + + stmvl53l1_ipp_hist_ambient_dmax = 3, + /*!< stmvl53l1_ipp_hist_ambient_dmax process ambient dmac calculation + * from histogram + */ + + stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples = 4, + /*!< stmvl53l1_ipp_generate_dual_reflectance_xtalk_samples process + * Xtalk data from dual reflectance histogram data + */ + + /** keep last*/ + stmvl53l1_ipp_max /*!< stmvl53l1_ipp_max */ +}; + +/** + * status use on @a ipp_work_t::status + */ +enum stmvl53l1_ipp_status_e { + stmvl53l1_ipp_status_ok = 0, /*!< ok work done */ + stmvl53l1_ipp_status_inv_id, /*!< dev id not supported or invalid */ + stmvl53l1_ipp_status_inv_proc, + /*!< process_no asked not supported or not implemented */ + stmvl53l1_ipp_status_inv_payload, + /*!< data payload for asked processing incorrect*/ + + stmvl53l1_ipp_status_proc_code = 0x100, + /*!< the lowest 8 bit is the error code form the processing */ +}; + +/** + * Ipp work (job) struct + * + * containing header with sequenc control information plus serialized data + */ +struct ipp_work_t { + int8_t dev_id; /*!< [in]/[out] device id */ + /*!< Identify the work do be run see @a stmvl53l1_ipp_proccesing_e */ + uint8_t process_no; + /*!< [out] status from daemon */ + int16_t status; + /*!< [in/out] unique xfer id */ + uint32_t xfer_id; + /*!< [in/out] effective data length including header*/ + uint32_t payload; + +/** max IPP data payload (not including header) + * + * we substract size of of item above + * must be lesss than one netlink packet + */ +#define MAX_IPP_DATA ((4096-4*3)/8) + ipp_arg_t data[MAX_IPP_DATA]; /*!< [in][out] */ +}; + +/** + * size of header only message ( no payload) + * require \#include in user land + */ +#define IPP_WORK_HDR_SIZE (offsetof(struct ipp_work_t, data[0])) +/** + * max payload per ipp transfer + */ +#define IPP_WORK_MAX_PAYLOAD sizeof(struct ipp_work_t) + +/** copy ipp header from src to dest + * + * used to prepare return work using incoming work header + * @param dest dest work ptr + * @param src src work ptr + */ +#define IPP_CPY_HEADER(dest, src) memcpy(dest, src, IPP_WORK_HDR_SIZE) + +/** + * dump in human readble way ipp struct + * + * @note require IPP_PRINT macro + * + * @param pw ipp_work struct to dump + * @param max_data max amount of data to be dump + * @param max_dev max number of dev (for check) + */ +static inline void ipp_dump_work(struct ipp_work_t *pw, uint32_t max_data, + int max_dev) +{ + uint32_t data_cnt; + uint32_t i; + uint8_t *pbdata; + + (void)max_dev; /* avoid warning when not used */ + (void)pbdata; /*avoid warning in case no print no use*/ + + IPP_PRINT("dev #%d (%s)\n", pw->dev_id, pw->dev_id < max_dev ? + "ok" : "bad"); + IPP_PRINT("process #%d (%s)\n", pw->process_no, + pw->process_no < stmvl53l1_ipp_max ? "ok" : "bad"); + IPP_PRINT("status %d\n", pw->status); + IPP_PRINT("Xfer id 0x%08X payload %d bytes (%s)\n", pw->xfer_id, + pw->payload, + pw->payload > IPP_WORK_MAX_PAYLOAD ? "invalid" : "ok"); + data_cnt = pw->payload > IPP_WORK_MAX_PAYLOAD ? + IPP_WORK_MAX_PAYLOAD : pw->payload; + data_cnt = data_cnt > max_data ? max_data : data_cnt; + for (i = 0, pbdata = (uint8_t *)pw->data; i < data_cnt; i++) { + if (i%16 == 0) + IPP_PRINT("\n%4X\t", i); + IPP_PRINT("%02X ", pbdata[i]); + } + IPP_PRINT("\n"); +} + +/** @} */ /* ingroup helper */ + +/** @} */ /* ingroup ipp_dev */ +#endif /* _STMVL53L1_IPP_H_ */ diff --git a/drivers/oneplus/vl53L1/stmvl53l1_ipp_nl.c b/drivers/oneplus/vl53L1/stmvl53l1_ipp_nl.c new file mode 100755 index 0000000000000000000000000000000000000000..af4dc93bf0cc399c4bfc76f7fe168ef14777c9f3 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_ipp_nl.c @@ -0,0 +1,383 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_ipp_nl.c vl53l1 ipp proxy over netlink kernel side + */ +#include +#include +#include +#include +#include + +#include "stmvl53l1.h" + +#include "vl53l1_platform_ipp.h" +#include "stmvl53l1_ipp.h" + +#define IPP_DEBUG 1 +#ifndef IPP_DEBUG +# define _ipp_dump_work(...) (void)0 +#else +# define _ipp_dump_work(...) ipp_dump_work(__VA_ARGS__) +#endif + +#define IPP_STATE_PENDING 1 +#define IPP_STATE_COMPLETED 2 +#define IPP_STATE_CANCELED 4 + +#define IPP_TIMEOUT_MS 100 + +/** the single netlink strut use by all instance + * @note is NULL until set + */ +static struct sock *nl_sk; + +static DEFINE_MUTEX(ipp_mutex); + +/** + * current registered daemon pid + * @note default value 0 or later 1 is kind of invalid and will require + * user space to connect before we can send any packet + */ +static int daemon_pid; + +/** + * next xfer_id (shared other all dev) + * no direct us used @@ref get_next_xfer_id (will get lock) + * @note default to 0 what is "reserved" + */ +static int next_xfer_id; + + +#define ipp_err(fmt, ...) pr_err("STMVL53L1 IPP Err in %s %d :" fmt "\n", \ + __func__, __LINE__, ##__VA_ARGS__) + +#define ipp_warn(fmt, ...) pr_warn("STMVL53L1 IPP wng in %s %d : "fmt"\n",\ + __func__, __LINE__, ##__VA_ARGS__) + +#if 0 +# define ipp_dbg(fmt, ...) pr_info("IPP %s %d " fmt "\n",\ + __func__, __LINE__, ##__VA_ARGS__) +#else +# define ipp_dbg(...) (void)0 +#endif + +/** + * get and managed increment of next xfer_id + * @note will get ipp_mutex + * @return the xfer_id to be used + */ +static int get_next_xfer_id(void) +{ + mutex_lock(&ipp_mutex); + next_xfer_id++; + /*0 is reserved skip it*/ + if (next_xfer_id == 0) + next_xfer_id = 1; + mutex_unlock(&ipp_mutex); + + return next_xfer_id; +} + +static int send_client_msg(void *msg_data, int msg_size) +{ + int rc; + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + void *nl_data; + + ipp_dbg("to send %d byte", msg_size); + skb_out = nlmsg_new(msg_size, 0); + if (!skb_out) { + ipp_err("nlmsg_new fail\n"); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); + NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */ + + nl_data = nlmsg_data(nlh); /*get data ptr from header*/ + memcpy(nl_data, msg_data, msg_size); + + /* FIXME do we real need to lock to send a data other nl_sk ? */ + mutex_lock(&ipp_mutex); + rc = nlmsg_unicast(nl_sk, skb_out, daemon_pid); + if (rc < 0) + ipp_err("fail to send data size %d to pid %d\n", + msg_size, daemon_pid); + /* stat can be done here in else case */ + mutex_unlock(&ipp_mutex); + + return rc; +} + +/* + * ipp lock is held ping already handled + */ +int ipp_in_process(struct ipp_work_t *pwork) +{ + struct stmvl53l1_data *data; + + ipp_dbg("enter"); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, STMVL53L1_CFG_MAX_DEV); + + /* work id check already done */ + data = stmvl53l1_dev_table[pwork->dev_id]; + ipp_dbg("to lock "); + /* Release now useless ipp_mutex for below work since we may deadlock + * with irq path. + */ + mutex_unlock(&ipp_mutex); + mutex_lock(&data->work_mutex); + if (data->ipp.buzy == IPP_STATE_PENDING) { + /* if it was already handled ignore it */ + if (data->ipp.waited_xfer_id == pwork->xfer_id) { + /* ok that is what we are expecting back */ + memcpy(&data->ipp.work_out, pwork, pwork->payload); + data->ipp.buzy |= IPP_STATE_COMPLETED; + ipp_dbg("to wake ipp waiter as buzy state %d", + data->ipp.buzy); + wake_up(&data->ipp.waitq); + goto done_lock; + } + } + /* either not waiting any more or not the expected id drop it */ + ipp_err("dev #%d ippp buzy %d xfer id %d rcv id %d droping it", + data->id, data->ipp.buzy, data->ipp.waited_xfer_id, + pwork->xfer_id); +done_lock: + mutex_unlock(&data->work_mutex); + mutex_lock(&ipp_mutex); + + return 0; +} + +int stmvl53l1_ipp_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = data->ipp.buzy; + ipp_dbg("#%d to stop buzy %d", data->id, data->ipp.buzy); + if (data->ipp.buzy) { + /* set invalid wait id to discard canceled job when back */ + data->ipp.waited_xfer_id = 0; + data->ipp.buzy |= IPP_STATE_CANCELED|IPP_STATE_COMPLETED; + ipp_dbg("#%dto wake up worker", data->id); + /* wake up worker or abort the thread */ + wake_up(&data->ipp.waitq); + } + + return rc; +} + +/* + * ipp and dev lock are held + * release and re-grabbed here + */ +int stmvl53l1_ipp_do(struct stmvl53l1_data *data, + struct ipp_work_t *pin, struct ipp_work_t *pout) +{ + int xfer_id; + int rc; + bool has_timeout; + + ipp_dbg("enter"); + + xfer_id = get_next_xfer_id(); + /* set xfer and device dependent part of the work */ + pin->dev_id = data->id; + pin->xfer_id = xfer_id; + data->ipp.waited_xfer_id = xfer_id; + /* try to do it */ + rc = send_client_msg(pin, pin->payload); + /* shall we retry if fail to send for some time or number of try ? */ + if (rc < 0) { + rc = -1; + ipp_err("fail to send msg %d", rc); + } else if (data->ipp.buzy == 0) { + /* send ok put the ipp on buzy state while locked */ + data->ipp.buzy = IPP_STATE_PENDING; + /* unlock now that state is marked buzy */ + mutex_unlock(&data->work_mutex); + + /* put task to wait for completion */ + ipp_dbg("to wait"); + has_timeout = !wait_event_timeout(data->ipp.waitq, + (data->ipp.buzy != IPP_STATE_PENDING), + msecs_to_jiffies(IPP_TIMEOUT_MS)); + + /* relock the main lock */ + mutex_lock(&data->work_mutex); + + rc = (data->ipp.buzy & IPP_STATE_CANCELED) || has_timeout ? + -1 : 0; + if (rc) { + ipp_dbg("waking up with from canceled/timeout ipp"); + } else { + /* return status from the ipp itself */ + ipp_dbg("ip back with status %d", data->ipp.status); + rc = data->ipp.status; + } + data->ipp.buzy = 0;/* buzy clear but locked so safe */ + } else { + ipp_dbg("buzy still not zero %d", data->ipp.buzy); + rc = -1; + } + + +/* done_lock: */ + return rc; +} + + +static void stmvl53l1_nl_recv_msg(struct sk_buff *skb_in) +{ + int pid_chg = 0; + int pid; + struct nlmsghdr *nlh; + struct ipp_work_t *pwork; + + ipp_dbg("Entering"); + + nlh = (struct nlmsghdr *)skb_in->data; + pid = nlh->nlmsg_pid; /*pid of sending process */ + + pwork = nlmsg_data(nlh); + if (pwork->payload < IPP_WORK_HDR_SIZE || + pwork->payload > IPP_WORK_MAX_PAYLOAD){ + /* invalid header size */ + ipp_err("invalid msg header size %d", pwork->payload); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + return; + } + + mutex_lock(&ipp_mutex); + + if ((pwork->dev_id >= STMVL53L1_CFG_MAX_DEV) || (pwork->dev_id < 0)) { + ipp_err("invalid dev id on msg %d", pwork->dev_id); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + + if (pwork->process_no == stmvl53l1_ipp_ping) { + /* in that case the payload must be exact status size only + * if not it is a badly format message or bad message + */ + if (pwork->payload != IPP_WORK_HDR_SIZE) { + ipp_err("invalid ping msg size %d!=%zu ", + pwork->payload, IPP_WORK_HDR_SIZE); + _ipp_dump_work(pwork, IPP_WORK_MAX_PAYLOAD, + STMVL53L1_CFG_MAX_DEV); + goto done_locked; + } + /* if pid was not set or change resent all ongoing ipp */ + if (pid != daemon_pid) + ipp_warn("pid chg %d => %d\n", daemon_pid, pid); + else + ipp_dbg("got ping fm pid %d\n", daemon_pid); + daemon_pid = pid; + pid_chg = 1; + } else { + ipp_in_process(pwork); + } + done_locked: + mutex_unlock(&ipp_mutex); +} + +int stmvl53l1_ipp_setup(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&ipp_mutex); + + data->ipp.buzy = 0; + init_waitqueue_head(&data->ipp.waitq); + ipp_dbg("now %d dev daemon pid is %d", STMVL53L1_CFG_MAX_DEV, + daemon_pid); + rc = 0; + + mutex_unlock(&ipp_mutex); + + return rc; +} + +void stmvl53l1_ipp_cleanup(struct stmvl53l1_data *data) +{ + /* nothink to do */ +} + +#if !defined(OLD_NETLINK_API) +struct netlink_kernel_cfg cfg = { + .input = stmvl53l1_nl_recv_msg +}; +#endif + +static int netlink_protocol_type = STMVL531_CFG_NETLINK_USER; + +module_param(netlink_protocol_type, int, 0444); +MODULE_PARM_DESC(netlink_protocol_type, + "select netlink protocol type for ipp communications"); + +int stmvl53l1_ipp_init(void) +{ + mutex_init(&ipp_mutex); + daemon_pid = 1; /* pid 1 is safe should not be use for user space */ + +#if defined(OLD_NETLINK_API) + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + 0, + stmvl53l1_nl_recv_msg, + NULL, + THIS_MODULE); +#else + nl_sk = netlink_kernel_create(&init_net, + netlink_protocol_type, + &cfg); +#endif + + return nl_sk ? 0 : -1; +} + + +void stmvl53l1_ipp_exit(void) +{ + if (nl_sk != NULL) { + vl53l1_dbgmsg("releasing netlink socket"); + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } +} + + diff --git a/drivers/oneplus/vl53L1/stmvl53l1_log.c b/drivers/oneplus/vl53L1/stmvl53l1_log.c new file mode 100755 index 0000000000000000000000000000000000000000..ecedcb446ddaf5cdc019f218aa0369a417d52111 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_log.c @@ -0,0 +1,78 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * This is implementation of low level driver trace support + */ +#include +#include + +#include "stmvl53l1.h" + +#ifdef VL53L1_LOG_ENABLE + +static bool trace_function; +static int trace_module; +static int trace_level; + +module_param(trace_function, bool, 0644); +MODULE_PARM_DESC(trace_function, + "allow tracing of low level function entry and exit"); + +module_param(trace_module, int, 0644); +MODULE_PARM_DESC(trace_module, + "control tracing of low level per module"); + +module_param(trace_level, int, 0644); +MODULE_PARM_DESC(trace_level, + "control tracing of low level per level"); + +void log_trace_print(uint32_t module, uint32_t level, uint32_t function, + const char *format, ...) +{ + va_list args; + + if (function && !trace_function) + return; + + if (!(module & trace_module)) + return; + + if (level > trace_level) + return; + + va_start(args, format); + vprintk(format, args); + va_end(args); +} + +#endif diff --git a/drivers/oneplus/vl53L1/stmvl53l1_module-cci.c b/drivers/oneplus/vl53L1/stmvl53l1_module-cci.c new file mode 100755 index 0000000000000000000000000000000000000000..8c4e99582c9116d08958f6e7a0c8ecc19d4042ac --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_module-cci.c @@ -0,0 +1,274 @@ +/* +* Copyright (c) 2016, STMicroelectronics - All Rights Reserved +* +* License terms: BSD 3-clause "New" or "Revised" License. +* +* 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. +* +* 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. Neither the name of the copyright holder nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" +struct stmvl53l1_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; +}; + +struct stmvl53l1_pinctrl_info stmvl53l1_pinctrl; + +extern int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data); +extern void stmvl53l1_release_gpios(struct i2c_data *i2c_data); + +static int stmvl53l1_request_pinctrl(struct device *dev) +{ + struct stmvl53l1_pinctrl_info *device_pctrl = &stmvl53l1_pinctrl; + device_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) { + vl53l1_errmsg("Pinctrl not available"); + device_pctrl->pinctrl = NULL; + return 0; + } + device_pctrl->gpio_state_active = + pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_default"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) { + vl53l1_errmsg("Failed to get the active state pinctrl handle"); + device_pctrl->gpio_state_active = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_suspend + = pinctrl_lookup_state(device_pctrl->pinctrl, + "laser_suspend"); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) { + vl53l1_errmsg("Failed to get the suspend state pinctrl handle"); + device_pctrl->gpio_state_suspend = NULL; + return -EINVAL; + } + return 0; +} + +int stmvl53l1_enable_pinctrl(void) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_active) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_active); + vl53l1_errmsg("enable pinctrl rc=%d\n", rc); + } + + return rc; +} + +int stmvl53l1_disable_pinctrl(void) +{ + int rc = 0; + + if (stmvl53l1_pinctrl.pinctrl && + stmvl53l1_pinctrl.gpio_state_suspend) { + rc = pinctrl_select_state(stmvl53l1_pinctrl.pinctrl, + stmvl53l1_pinctrl.gpio_state_suspend); + vl53l1_errmsg("disable pinctrl rc=%d\n", rc); + } + + return rc; + +} + +int stmvl53l1_release_pinctrl(struct device *dev) +{ + if (stmvl53l1_pinctrl.pinctrl) + devm_pinctrl_put(stmvl53l1_pinctrl.pinctrl); + stmvl53l1_pinctrl.pinctrl = NULL; + + return 0; +} + +static int32_t stmvl53l1_probe_cci( + struct platform_device *pdev) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", pdev->name, pdev->id); + + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + //i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; + rc = stmvl53l1_parse_tree(&(pdev->dev), i2c_data); + if (rc) + goto done_freemem; + + rc = stmvl53l1_request_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fail to request pinctrl,rc = %d", rc); + goto done_freemem; + } + rc = stmvl53l1_enable_pinctrl(); + if (rc){ + vl53l1_errmsg("fail to enable pinctrl,rc = %d", rc); + goto release_gpios; + } + + platform_set_drvdata(pdev, vl53l1_data); + //vl53l1_data->plat_dev = pdev; + + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + kfree(vl53l1_data); + kfree(i2c_data); + + return 0; +} + +static int32_t stmvl53l1_remove_cci(struct platform_device *pdev) +{ + int rc = 0; + struct stmvl53l1_data *data = platform_get_drvdata(pdev); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + + rc = stmvl53l1_disable_pinctrl(); + if (rc){ + vl53l1_errmsg("fatal,fail to disable pinctrl,rc = %d", rc); + } + rc = stmvl53l1_release_pinctrl(&(pdev->dev)); + if (rc){ + vl53l1_errmsg("fatal,fail to release pinctrl,rc = %d", rc); + } + + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static const struct of_device_id stmvl53l1_driver_dt_match[] = { + {.compatible = "st,stmvl53l1"}, + {} +}; + +MODULE_DEVICE_TABLE(of, stmvl53l1_driver_dt_match); + +static struct platform_driver stmvl53l1_platform_driver = { + .probe = stmvl53l1_probe_cci, + .driver = { + .name = "st,stmvl53l1", + .owner = THIS_MODULE, + .of_match_table = stmvl53l1_driver_dt_match, + }, + .remove = stmvl53l1_remove_cci, +}; + +int __init stmvl53l1_init_cci(void) +{ + int32_t rc = 0; + vl53l1_dbgmsg("enter\n"); + rc = platform_driver_register(&stmvl53l1_platform_driver); + if (rc < 0) { + vl53l1_dbgmsg("platform_driver_register fail\n"); + return rc; + } + + return rc; +} + +void __exit stmvl53l1_exit_cci(void* obj) +{ + vl53l1_dbgmsg("enter\n"); + platform_driver_unregister(&stmvl53l1_platform_driver); +} + diff --git a/drivers/oneplus/vl53L1/stmvl53l1_module-i2c.c b/drivers/oneplus/vl53L1/stmvl53l1_module-i2c.c new file mode 100755 index 0000000000000000000000000000000000000000..0e619422dc2a23d541459f0ccdc2ae693ca294f3 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_module-i2c.c @@ -0,0 +1,909 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file stmvl53l1_module-i2c.c + * + * implement STM VL53L1 module interface i2c wrapper + control + * using linux native i2c + gpio + reg api + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * power specific includes + */ +#include +#include +#include +#include +#include +#include + +#include "stmvl53l1-i2c.h" +#include "stmvl53l1.h" +#include "cam_cci_ctrl_interface.h" + +#define STMVL53L1_SLAVE_ADDR (0x52>>1) +#define IGNORE_IRQ 1 //songyt add +/** @ingroup drv_port + * @{ + */ + +/** + * control specific debug message echo + * + * Set to 0/1 do not remove + * + * most dbg warn err messages goes true main driver macro + * this one permit some specific debug without activating all main dbg + */ +#define MODI2C_DEBUG 0 + +/* + * mutex to handle device i2c address changes. It allow to avoid multiple + * device active with same i2c addresses at the same time. Note that we don't + * support case where boot_reg has the same value as a final i2c address of + * another device. + */ +static DEFINE_MUTEX(dev_addr_change_mutex); + +/** + * i2c client assigned to our driver + * + * this is use for stm test purpose as we fake client create and regstration + * we stores the i2c client for release in clean-up overwise we wan't reload + * the module multiple time + * + * in a normal dev tree prod system this is not required + */ +static struct i2c_client *stm_test_i2c_client; + +/* + * pi3: + * insmod stmvl53l1.ko force_device=1 adapter_nb=1 xsdn_gpio_nb=19 + * intr_gpio_nb=16 pwren_gpio_nb=12 + * + * panda + * insmod stmvl53l1.ko force_device=1 adapter_nb=4 xsdn_gpio_nb=56 + * intr_gpio_nb=59 pwren_gpio_nb=55 +*/ + +static int force_device; +static int adapter_nb = -1; +static int xsdn_gpio_nb = -1; +static int pwren_gpio_nb = -1; +static int intr_gpio_nb = -1; + +module_param(force_device, int, 0000); +MODULE_PARM_DESC(force_device, "force device insertion at module init"); + +module_param(adapter_nb, int, 0000); +MODULE_PARM_DESC(adapter_nb, "i2c adapter to use"); + +module_param(xsdn_gpio_nb, int, 0000); +MODULE_PARM_DESC(xsdn_gpio_nb, "select gpio numer to use for vl53l1 reset"); + +module_param(pwren_gpio_nb, int, 0000); +MODULE_PARM_DESC(pwren_gpio_nb, "select gpio numer to use for vl53l1 power"); + +module_param(intr_gpio_nb, int, 0000); +MODULE_PARM_DESC(intr_gpio_nb, "select gpio numer to use for vl53l1 interrupt"); + +/** + * warn message + * + * @warning use only in scope where i2c_data ptr is present + **/ +#define modi2c_warn(fmt, ...)\ + dev_WARN(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + +/** + * err message + * + * @warning use only in scope where i2c_data ptr is present + */ +#define modi2c_err(fmt, ...)\ + dev_err(&i2c_data->client->dev, fmt, ##__VA_ARGS__) + + + +#if MODI2C_DEBUG +# define modi2c_dbg(fmt, ...)\ + pr_devel("%s "fmt"\n", __func__, ##__VA_ARGS__) +#else +# define modi2c_dbg(...) (void)0 +#endif + +static int insert_device(void) +{ + int ret = 0; + struct i2c_adapter *adapter; + struct i2c_board_info info = { + .type = "stmvl53l1", + .addr = STMVL53L1_SLAVE_ADDR, + }; + + memset(&info, 0, sizeof(info)); + strcpy(info.type, "stmvl53l1"); + info.addr = STMVL53L1_SLAVE_ADDR; + adapter = i2c_get_adapter(adapter_nb); + if (!adapter) { + ret = -EINVAL; + goto done; + } + stm_test_i2c_client = i2c_new_device(adapter, &info); + if (!stm_test_i2c_client) + ret = -EINVAL; + +done: + return ret; +} + +static int get_xsdn(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.xsdn_owned = 0; + if (i2c_data->xsdn_gpio == -1) { + vl53l1_errmsg("reset gpio is required"); + rc = -ENODEV; + goto no_gpio; + } + + vl53l1_dbgmsg("request xsdn_gpio %d", i2c_data->xsdn_gpio); + rc = gpio_request(i2c_data->xsdn_gpio, "vl53l1_xsdn"); + if (rc) { + vl53l1_errmsg("fail to acquire xsdn %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->xsdn_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure xsdn as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.xsdn_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_xsdn(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.xsdn_owned) { + vl53l1_dbgmsg("release xsdn_gpio %d", i2c_data->xsdn_gpio); + gpio_free(i2c_data->xsdn_gpio); + i2c_data->io_flag.xsdn_owned = 0; + i2c_data->xsdn_gpio = -1; + } + i2c_data->xsdn_gpio = -1; +} + +static int get_pwren(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.pwr_owned = 0; + if (i2c_data->pwren_gpio == -1) { + vl53l1_wanrmsg("pwren gpio disable"); + goto no_gpio; + } + + vl53l1_dbgmsg("request pwren_gpio %d", i2c_data->pwren_gpio); + rc = gpio_request(i2c_data->pwren_gpio, "vl53l1_pwren"); + if (rc) { + vl53l1_errmsg("fail to acquire pwren %d", rc); + goto request_failed; + } + + rc = gpio_direction_output(i2c_data->pwren_gpio, 0); + if (rc) { + vl53l1_errmsg("fail to configure pwren as output %d", rc); + goto direction_failed; + } + i2c_data->io_flag.pwr_owned = 1; + + return rc; + +direction_failed: + gpio_free(i2c_data->xsdn_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_pwren(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.pwr_owned) { + vl53l1_dbgmsg("release pwren_gpio %d", i2c_data->pwren_gpio); + gpio_free(i2c_data->pwren_gpio); + i2c_data->io_flag.pwr_owned = 0; + i2c_data->pwren_gpio = -1; + } + i2c_data->pwren_gpio = -1; +} + +static int get_intr(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + + i2c_data->io_flag.intr_owned = 0; + if (i2c_data->intr_gpio == -1) { + vl53l1_wanrmsg("no interrupt gpio"); + goto no_gpio; + } + + vl53l1_dbgmsg("request intr_gpio %d", i2c_data->intr_gpio); + rc = gpio_request(i2c_data->intr_gpio, "vl53l1_intr"); + if (rc) { + vl53l1_errmsg("fail to acquire intr %d", rc); + goto request_failed; + } + + rc = gpio_direction_input(i2c_data->intr_gpio); + if (rc) { + vl53l1_errmsg("fail to configure intr as input %d", rc); + goto direction_failed; + } + + i2c_data->irq = gpio_to_irq(i2c_data->intr_gpio); + if (i2c_data->irq < 0) { + vl53l1_errmsg("fail to map GPIO: %d to interrupt:%d\n", + i2c_data->intr_gpio, i2c_data->irq); + goto irq_failed; + } + i2c_data->io_flag.intr_owned = 1; + + return rc; + +irq_failed: +direction_failed: + gpio_free(i2c_data->intr_gpio); + +request_failed: +no_gpio: + return rc; +} + +static void put_intr(struct i2c_data *i2c_data) +{ + if (i2c_data->io_flag.intr_owned) { + if (i2c_data->io_flag.intr_started) { + free_irq(i2c_data->irq, i2c_data); + i2c_data->io_flag.intr_started = 0; + } + vl53l1_dbgmsg("release intr_gpio %d", i2c_data->intr_gpio); + gpio_free(i2c_data->intr_gpio); + i2c_data->io_flag.intr_owned = 0; + } + i2c_data->intr_gpio = -1; +} + +/** + * parse dev tree for all platform specific input + */ +int stmvl53l1_parse_tree(struct device *dev, struct i2c_data *i2c_data) +{ + int rc = 0; + enum of_gpio_flags flags; + /* if force device is in use then gpio nb comes from module param else + * we use devicetree. + */ + i2c_data->vdd = NULL; + i2c_data->xsd = NULL; + i2c_data->pwren_gpio = -1; + i2c_data->xsdn_gpio = -1; + i2c_data->intr_gpio = -1; + i2c_data->boot_reg = STMVL53L1_SLAVE_ADDR; + if (force_device) { + i2c_data->xsdn_gpio = xsdn_gpio_nb; + i2c_data->pwren_gpio = pwren_gpio_nb; + i2c_data->intr_gpio = intr_gpio_nb; + } else if (dev->of_node) { + /* power : either vdd or pwren_gpio. try reulator first */ + i2c_data->vdd = regulator_get(dev, "laser_vdd"); + if (IS_ERR(i2c_data->vdd) || i2c_data->vdd == NULL) { + i2c_data->vdd = NULL; + vl53l1_wanrmsg( + "no laser_vdd, fatal."); + } + i2c_data->xsd = regulator_get(dev, "laser_xsd"); + if (IS_ERR(i2c_data->xsd) || i2c_data->xsd == NULL) { + i2c_data->xsd = NULL; + vl53l1_wanrmsg( + "no laser_xsd, fatal."); + } + i2c_data->pwren_gpio = of_get_named_gpio_flags(dev->of_node, "pwren-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->pwren_gpio)) { + vl53l1_dbgmsg("pwren-gpio %d", + i2c_data->pwren_gpio); + } else { + vl53l1_wanrmsg( + "no regulator, nor power gpio => power ctrl disabled"); + i2c_data->pwren_gpio = -1; + } + i2c_data->xsdn_gpio = of_get_named_gpio_flags(dev->of_node, "xsdn-gpio", 0, + &flags); + if (gpio_is_valid(i2c_data->xsdn_gpio)) { + vl53l1_dbgmsg("xsdn-gpio %d", + i2c_data->xsdn_gpio); + } else { + vl53l1_wanrmsg("Unable to find xsdn-gpio %d", + i2c_data->xsdn_gpio); + i2c_data->xsdn_gpio = -1; + } +#if IGNORE_IRQ + i2c_data->intr_gpio = -1; + vl53l1_dbgmsg("do not use intr-gpio!"); +#else + i2c_data->intr_gpio = of_get_named_gpio_flags(dev->of_node, "intr-gpio", 0,&flags); + if (gpio_is_valid(i2c_data->intr_gpio)) { + vl53l1_dbgmsg("intr-gpio %d", + i2c_data->intr_gpio); + } else { + vl53l1_wanrmsg("Unable to find intr-gpio %d", + i2c_data->intr_gpio); + i2c_data->intr_gpio = -1; + } +#endif + } + + /* configure gpios */ + rc = get_xsdn(dev, i2c_data); + if (rc) + goto no_xsdn; + if(i2c_data->pwren_gpio != -1){ + rc = get_pwren(dev, i2c_data); + if (rc) + goto no_pwren; + } + rc = get_intr(dev, i2c_data); + if (rc){ + vl53l1_errmsg("get_intr failed."); + goto no_intr; + } + return rc; + +no_intr: +#if IGNORE_IRQ + return 0; +#else + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); +#endif +no_pwren: + if (i2c_data->xsd) { + regulator_put(i2c_data->xsd); + i2c_data->xsd = NULL; + } + + put_xsdn(i2c_data); +no_xsdn: + return rc; +} + +void stmvl53l1_release_gpios(struct i2c_data *i2c_data) +{ + if (i2c_data->xsd) { + regulator_put(i2c_data->xsd); + i2c_data->xsd = NULL; + } + put_xsdn(i2c_data); + if (i2c_data->vdd) { + regulator_put(i2c_data->vdd); + i2c_data->vdd = NULL; + } + put_pwren(i2c_data); + put_intr(i2c_data); +} + +static int stmvl53l1_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct stmvl53l1_data *vl53l1_data = NULL; + struct i2c_data *i2c_data = NULL; + + vl53l1_dbgmsg("Enter %s : 0x%02x\n", client->name, client->addr); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + rc = -EIO; + return rc; + } + + vl53l1_data = kzalloc(sizeof(struct stmvl53l1_data), GFP_KERNEL); + if (!vl53l1_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l1_data) { + vl53l1_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + if (!vl53l1_data) + goto done_freemem; + i2c_data = (struct i2c_data *)vl53l1_data->client_object; + } + i2c_data->client = client; + i2c_data->vl53l1_data = vl53l1_data; + i2c_data->irq = -1 ; /* init to no irq */ + + /* parse and configure hardware */ + rc = stmvl53l1_parse_tree(&i2c_data->client->dev, i2c_data); + if (rc) + goto done_freemem; + + /* setup device name */ + /* vl53l1_data->dev_name = dev_name(&client->dev); */ + + /* setup client data */ + i2c_set_clientdata(client, vl53l1_data); + + /* end up by core driver setup */ + rc = stmvl53l1_setup(vl53l1_data); + if (rc) + goto release_gpios; + vl53l1_dbgmsg("End\n"); + + kref_init(&i2c_data->ref); + + return rc; + +release_gpios: + stmvl53l1_release_gpios(i2c_data); + +done_freemem: + /* kfree safe against NULL */ + kfree(vl53l1_data); + kfree(i2c_data); + + return -1; +} + +static int stmvl53l1_remove(struct i2c_client *client) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(client); + struct i2c_data *i2c_data = (struct i2c_data *)data->client_object; + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* main driver cleanup */ + stmvl53l1_cleanup(data); + + /* release gpios */ + stmvl53l1_release_gpios(i2c_data); + + mutex_unlock(&data->work_mutex); + + stmvl53l1_put(data->client_object); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int stmvl53l1_suspend(struct device *dev) +{ + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + mutex_lock(&data->work_mutex); + /* Stop ranging */ + stmvl53l1_pm_suspend_stop(data); + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_resume(struct device *dev) +{ +#if 0 + struct stmvl53l1_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + vl53l1_dbgmsg("Enter\n"); + + mutex_lock(&data->work_mutex); + + /* do nothing user will restart measurements */ + + mutex_unlock(&data->work_mutex); + + vl53l1_dbgmsg("End\n"); +#else + vl53l1_dbgmsg("Enter\n"); + vl53l1_dbgmsg("End\n"); +#endif + return 0; +} +#endif + + +static SIMPLE_DEV_PM_OPS(stmvl53l1_pm_ops, stmvl53l1_suspend, stmvl53l1_resume); + +static const struct i2c_device_id stmvl53l1_id[] = { + { STMVL53L1_DRV_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); + +static const struct of_device_id st_stmvl53l1_dt_match[] = { + { .compatible = "st,"STMVL53L1_DRV_NAME, }, + { }, +}; + +static struct i2c_driver stmvl53l1_driver = { + .driver = { + .name = STMVL53L1_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l1_dt_match, + .pm = &stmvl53l1_pm_ops, + }, + .probe = stmvl53l1_probe, + .remove = stmvl53l1_remove, + .id_table = stmvl53l1_id, + +}; + +/** + * give power to device + * + * @param object the i2c layer object + * @return + */ +int stmvl53l1_power_up_i2c(void *object) +{ + int rc = 0; + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + + /* turn on power */ + if (data->vdd) { + rc = regulator_enable(data->vdd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } + if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + if (data->xsd) { + rc = regulator_enable(data->xsd); + if (rc) { + vl53l1_errmsg("fail to turn on regulator"); + return rc; + } + } + if (data->xsdn_gpio != -1) { + gpio_set_value(data->xsdn_gpio, 1); + vl53l1_info("slow power on"); + } else + vl53l1_wanrmsg("no power control"); + + + return rc; +} + +/** + * remove power to device (reset it) + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_power_down_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + int rc = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* turn off power */ + if (data->vdd) { + rc = regulator_disable(data->vdd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } + if (data->pwren_gpio != -1) { + gpio_set_value(data->pwren_gpio, 0); + } + + if (data->xsd) { + rc = regulator_disable(data->xsd); + if (rc) + vl53l1_errmsg("reg disable failed. rc=%d\n", + rc); + } + if (data->xsdn_gpio != -1) { + gpio_set_value(data->xsdn_gpio, 0); + } + + vl53l1_dbgmsg("power off"); + + vl53l1_dbgmsg("End\n"); + + return rc; +} + +static int handle_i2c_address_device_change_lock(struct i2c_data *data) +{ + return 0; +} + +/* reset release will also handle device address change. It will avoid state + * where multiple stm53l1 are bring out of reset at the same time with the + * same boot address. + * Note that we don't manage case where boot_reg has the same value as a final + * i2c address of another device. This case is not supported and will lead + * to unpredictable behavior. + */ +static int release_reset(struct i2c_data *data) +{ + //struct i2c_client *client = (struct i2c_client *) data->client; + int rc = 0; + bool is_address_change = false;//client->addr != data->boot_reg;//songyt modify + + if (is_address_change) + mutex_lock(&dev_addr_change_mutex); + //vl53l1_dbgmsg("reset xsdn pin to 1\n"); + gpio_set_value(data->xsdn_gpio, 1); + if (is_address_change) { + rc = handle_i2c_address_device_change_lock(data); + if (rc){ + gpio_set_value(data->xsdn_gpio, 0); + //vl53l1_dbgmsg("reset xsdn pin to 0\n"); + } + } + + if (is_address_change) + mutex_unlock(&dev_addr_change_mutex); + + return rc; +} + +/** + * release device reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_release_i2c(void *i2c_object) +{ + int rc; + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + rc = release_reset(data); + if (rc) + goto error; + + /* and now wait for device end of boot */ + data->vl53l1_data->is_delay_allowed = true; + rc = VL53L1_WaitDeviceBooted(&data->vl53l1_data->stdev); + data->vl53l1_data->is_delay_allowed = false; + if (rc) { + gpio_set_value(data->xsdn_gpio, 0); + vl53l1_errmsg("boot fail with error %d,change xsdn pin to 0", rc); + data->vl53l1_data->last_error = rc; + rc = -EIO; + } + +error: + vl53l1_dbgmsg("End\n"); + + return rc; +} + +/** + * put device under reset + * + * @param i2c_object the i2c layer object + * @return 0 on success + */ +int stmvl53l1_reset_hold_i2c(void *i2c_object) +{ + struct i2c_data *data = (struct i2c_data *) i2c_object; + + vl53l1_dbgmsg("Enter\n"); + + gpio_set_value(data->xsdn_gpio, 0); + + vl53l1_dbgmsg("End\n"); + + return 0; +} + +int stmvl53l1_init_i2c(void) +{ + int ret = 0; + + vl53l1_dbgmsg("Enter\n"); + + /* register as a i2c client device */ + ret = i2c_add_driver(&stmvl53l1_driver); + if (ret) + vl53l1_errmsg("%d erro ret:%d\n", __LINE__, ret); + + if (!ret && force_device) + ret = insert_device(); + + if (ret) + i2c_del_driver(&stmvl53l1_driver); + + vl53l1_dbgmsg("End with rc:%d\n", ret); + + return ret; +} + + +void stmvl53l1_clean_up_i2c(void) +{ + if (stm_test_i2c_client) { + vl53l1_dbgmsg("to unregister i2c client\n"); + i2c_unregister_device(stm_test_i2c_client); + } +} + +static irqreturn_t stmvl53l1_irq_handler_i2c(int vec, void *info) +{ + struct i2c_data *i2c_data = (struct i2c_data *)info; + + if (i2c_data->irq == vec) { + modi2c_dbg("irq"); + stmvl53l1_intr_handler(i2c_data->vl53l1_data); + modi2c_dbg("over"); + } else { + if (!i2c_data->msg_flag.unhandled_irq_vec) { + modi2c_warn("unmatching vec %d != %d\n", + vec, i2c_data->irq); + i2c_data->msg_flag.unhandled_irq_vec = 1; + } + } + + return IRQ_HANDLED; +} + +/** + * enable and start intr handling + * + * @param object our i2c_data specific object + * @param poll_mode [in/out] set to force mode clear to use irq + * @return 0 on success and set ->poll_mode if it faill ranging wan't start + */ +int stmvl53l1_start_intr(void *object, int *poll_mode) +{ + struct i2c_data *i2c_data; + int rc; + + i2c_data = (struct i2c_data *)object; + /* irq and gpio acquire config done in parse_tree */ + if (i2c_data->irq < 0) { + /* the i2c tree as no intr force polling mode */ + *poll_mode = -1; + return 0; + } + /* clear irq warning report enabe it again for this session */ + i2c_data->msg_flag.unhandled_irq_vec = 0; + /* if started do no nothing */ + if (i2c_data->io_flag.intr_started) { + /* nothing to do */ + *poll_mode = 0; + return 0; + } + + vl53l1_dbgmsg("to register_irq:%d\n", i2c_data->irq); + rc = request_threaded_irq(i2c_data->irq, NULL, + stmvl53l1_irq_handler_i2c, + IRQF_TRIGGER_FALLING|IRQF_ONESHOT, + "vl53l1_interrupt", + (void *)i2c_data); + if (rc) { + vl53l1_errmsg("fail to req threaded irq rc=%d\n", rc); + *poll_mode = 0; + } else { + vl53l1_dbgmsg("irq %d now handled\n", i2c_data->irq); + i2c_data->io_flag.intr_started = 1; + *poll_mode = 0; + } + return rc; +} + +void *stmvl53l1_get(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_get(&data->ref); + vl53l1_dbgmsg("End\n"); + + return object; +} + +static void memory_release(struct kref *kref) +{ + struct i2c_data *data = container_of(kref, struct i2c_data, ref); + + vl53l1_dbgmsg("Enter\n"); + kfree(data->vl53l1_data); + kfree(data); + vl53l1_dbgmsg("End\n"); +} + +void stmvl53l1_put(void *object) +{ + struct i2c_data *data = (struct i2c_data *) object; + + vl53l1_dbgmsg("Enter\n"); + kref_put(&data->ref, memory_release); + vl53l1_dbgmsg("End\n"); +} + +void __exit stmvl53l1_exit_i2c(void *i2c_object) +{ + vl53l1_dbgmsg("Enter\n"); + i2c_del_driver(&stmvl53l1_driver); + vl53l1_dbgmsg("End\n"); +} diff --git a/drivers/oneplus/vl53L1/stmvl53l1_module.c b/drivers/oneplus/vl53L1/stmvl53l1_module.c new file mode 100755 index 0000000000000000000000000000000000000000..12203da232b9b91864a3c224ec03910c5deccfc2 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_module.c @@ -0,0 +1,4296 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file /stmvl53l1_module.c vl53l1_module ST VL53L1 linux kernel module + * + * main file + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * API includes + */ + +#include "stmvl53l1.h" +#include "cam_cci_ctrl_interface.h" +#include "stmvl53l1-i2c.h" +#include "stmvl53l1_ipp.h" + +#include "stmvl53l1_if.h" /* our device interface to user space */ +#include "stmvl53l1_internal_if.h" + +/* + * include default tuning file + */ +#include "stmvl53l1_tunings.h" + +/** @ingroup vl53l1_config + * @{ + */ +/** + * default polling period delay in millisecond + * + * It can be set at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + * + * @note apply only for device operating in polling mode only + */ +#define STMVL53L1_CFG_POLL_DELAY_MS 30 + +/** + * default timing budget in microsecond + * + * Can be change at run time via @ref vl53l1_ioctl or @ref sysfs_attrib + */ +#define STMVL53L1_CFG_TIMING_BUDGET_US 30000 //songyt test 16000 + +/** default preset ranging mode */ +//#define STMVL53L1_CFG_DEFAULT_MODE VL53L1_PRESETMODE_RANGING + +/** default distance mode */ +#define STMVL53L1_CFG_DEFAULT_DISTANCE_MODE VL53L1_DISTANCEMODE_LONG + +/** default crosstalk enable */ +#define STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE 0 + +/** default output mode */ +#define STMVL53L1_CFG_DEFAULT_OUTPUT_MODE VL53L1_OUTPUTMODE_NEAREST + +#define STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE \ + VL53L1_OFFSETCORRECTIONMODE_STANDARD + +/** default Dmax mode */ +#define STMVL53L1_CFG_DEFAULT_DMAX_MODE VL53L1_DMAXMODE_CUSTCAL_DATA //VL53L1_DMAXMODE_FMT_CAL_DATA songyt + +/** default smudge correction enable value */ +#define STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE \ + VL53L1_SMUDGE_CORRECTION_NONE + +/** @} */ /* ingroup vl53l1_config */ + +/** @ingroup vl53l1_mod_dbg + * @{ + */ + +/** + * activate dump of roi in roi ctrl operation + * + * @note uses @a vl53l1_dbgmsg for output so make sure to enable debug + * to get roi dump + */ +#define STMVL53L1_CFG_ROI_DEBUG 1 //songyt 0 to 1 + +/** @} */ /* ingroup vl53l1_mod_dbg*/ + +/* #define DEBUG_TIME_LOG */ + + +#ifdef DEBUG_TIME_LOG +struct timeval start_tv, stop_tv; +#endif + +/* Set default value to 1 to allow to see module insertion debug messages */ +int stmvl53l1_enable_debug = 1; + +#define VL53L1_INPUT_DEVICE_NAME "STM VL53L1 proximity sensor" + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +static int stmvl53l1_open(struct inode *inode, struct file *file); +static int stmvl53l1_release(struct inode *inode, struct file *file); +static int ctrl_start(struct stmvl53l1_data *data); +static int ctrl_stop(struct stmvl53l1_data *data); + +static bool force_device_on_en_default = false;//songyt change true to false + +module_param(force_device_on_en_default, bool, 0444); +MODULE_PARM_DESC(force_device_on_en_default, + "select whether force_device_on_en is true or false by default"); + +/* boilerplate for integer parameter */ +#define IMPLEMENT_PARAMETER_INTEGER(sysfs_name, info_name)\ +static ssize_t stmvl53l1_show_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ + param = data->sysfs_name; \ + mutex_unlock(&data->work_mutex);; \ +\ + return scnprintf(buf, PAGE_SIZE, "%d\n", param); \ +} \ +\ +static ssize_t stmvl53l1_store_##sysfs_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct stmvl53l1_data *data = dev_get_drvdata(dev); \ + int rc; \ + int param; \ +\ + mutex_lock(&data->work_mutex); \ +\ + if (kstrtoint(buf, 0, ¶m)) { \ + vl53l1_errmsg("invalid syntax in %s", buf); \ + rc = -EINVAL; \ + } else \ + rc = stmvl53l1_set_##sysfs_name(data, param); \ +\ + mutex_unlock(&data->work_mutex); \ +\ + return rc ? rc : count; \ +} \ +\ +static int ctrl_param_##sysfs_name(struct stmvl53l1_data *data, \ + struct stmvl53l1_parameter *param) \ +{ \ + int rc; \ +\ + if (param->is_read) { \ + param->value = data->sysfs_name; \ + param->status = 0; \ + vl53l1_dbgmsg("get " info_name " %d", param->value); \ + rc = 0; \ + } else { \ + rc = stmvl53l1_set_##sysfs_name(data, param->value); \ + vl53l1_dbgmsg("rc %d req %d now %d", rc, \ + param->value, data->sysfs_name); \ + } \ +\ + return rc; \ +} + +/** + * module interface struct + * interface to platform speficic device handling , concern power/reset ... + */ +struct stmvl53l1_module_fn_t { + int (*init)(void); /*!< init */ + /** + * clean up job + * @param data module specific data ptr + */ + void (*deinit)(void *data); + /** + * give device power + * @param data specific module storage ptr + * @return 0 on sucess + */ + int (*power_up)(void *data); + /** + * power down TOFO also stop intr + */ + int (*power_down)(void *data); + /* + * release reset so device start. + */ + int (*reset_release)(void *data); + /* + * put device under reset. + */ + int (*reset_hold)(void *data); + + /** + * enable interrupt + * + * @param object : interface speficic ptr + * @note "module specfic ptr is data->client_object + * @return 0 on success else error then drievr wan't start ranging! + * if no interrupt or it can't be hooked but still to operated in poll + * mode then return 0 and force data->poll_mode + * might have to clear poll_mode exlplcilty if to operate in real intr + * mode as pool mode + * is the default + */ + int (*start_intr)(void *object, int *poll_mode); + + void (*clean_up)(void); /*!< optional can be void */ + + /* increment reference counter */ + void *(*get)(void *object); + + /* decrement reference counter and deallocate memory when zero */ + void (*put)(void *object); +}; + +/** i2c module interface*/ +static struct stmvl53l1_module_fn_t stmvl53l1_module_func_tbl = { +#ifdef USE_CAMERA_CCI + .init = stmvl53l1_init_cci, + .deinit = stmvl53l1_exit_cci, +#else + .init = stmvl53l1_init_i2c, + .deinit = stmvl53l1_exit_i2c, +#endif + .power_up = stmvl53l1_power_up_i2c, + .power_down = stmvl53l1_power_down_i2c, + .reset_release = stmvl53l1_reset_release_i2c, + .reset_hold = stmvl53l1_reset_hold_i2c, + .clean_up = stmvl53l1_clean_up_i2c, + .start_intr = stmvl53l1_start_intr, + .get = stmvl53l1_get, + .put = stmvl53l1_put, +}; +static bool ipp_inited = false; + + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * INPUT Subsys interface + */ + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data); + +/* + * Mutex to handle device id add/removal + */ +static DEFINE_MUTEX(dev_table_mutex); + +/** + * in-used device LUT + * we need this as the message reception from netlink message can't + * associate directly to a device instance that is as we look up id + * to device data structure + */ +struct stmvl53l1_data *stmvl53l1_dev_table[STMVL53L1_CFG_MAX_DEV]; + +/** + * Misc device device operations + */ +static const struct file_operations stmvl53l1_ranging_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = stmvl53l1_ioctl, + .open = stmvl53l1_open, + .release = stmvl53l1_release, + /* .flush = stmvl53l0_flush, */ +}; + +static int store_last_error(struct stmvl53l1_data *data, int rc) +{ + data->last_error = rc; + + return -EIO; +} + +static int allocate_dev_id(void) +{ + int i; + + mutex_lock(&dev_table_mutex); + + for (i = 0; i < STMVL53L1_CFG_MAX_DEV; i++) + if (!stmvl53l1_dev_table[i]) + break; + i = i < STMVL53L1_CFG_MAX_DEV ? i : -1; + + mutex_unlock(&dev_table_mutex); + + return i; +} + +static void deallocate_dev_id(int id) +{ + mutex_lock(&dev_table_mutex); + + stmvl53l1_dev_table[id] = NULL; + + mutex_unlock(&dev_table_mutex); +} + +/* helpers to manage reader list for blockint ioctl */ +/* call them with lock */ +static void empty_and_free_list(struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + struct stmvl53l1_waiters *tmp; + + list_for_each_entry_safe(waiter, tmp, head, list) { + list_del(&waiter->list); + kfree(waiter); + } +} + +static int add_reader(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *new_waiter; + + new_waiter = kmalloc(sizeof(struct stmvl53l1_waiters), GFP_KERNEL); + if (!new_waiter) + return -ENOMEM; + new_waiter->pid = pid; + list_add(&new_waiter->list, head); + + return 0; +} + +static bool is_pid_in_list(pid_t pid, struct list_head *head) +{ + struct stmvl53l1_waiters *waiter; + + list_for_each_entry(waiter, head, list) + if (waiter->pid == pid) + return true; + + return false; +} + +static void wake_up_data_waiters(struct stmvl53l1_data *data) +{ + empty_and_free_list(&data->simple_data_reader_list); + empty_and_free_list(&data->mz_data_reader_list); + wake_up(&data->waiter_for_data); +} + +static void stmvl53l1_insert_flush_events_lock(struct stmvl53l1_data *data) +{ + while (data->flush_todo_counter) { + data->flushCount++; + input_report_abs(data->input_dev_ps, ABS_GAS, data->flushCount); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Sensor HAL Flush Count = %u\n", + data->flushCount); + data->flush_todo_counter--; + } +} + +static int reset_release(struct stmvl53l1_data *data) +{ + int rc; + struct camera_cci_transfer ccit; + + if (!data->reset_state) + return 0; +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_INIT; + cam_cci_control_interface(&ccit); +#endif + + rc = stmvl53l1_module_func_tbl.reset_release(data->client_object); + if (rc){ + vl53l1_errmsg("reset release fail rc=%d try to release cci\n", rc); +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_RELEASE; + cam_cci_control_interface(&ccit); +#endif + }else + data->reset_state = 0; + + return rc; +} + +static int reset_hold(struct stmvl53l1_data *data) +{ + int rc; + struct camera_cci_transfer ccit; + + if (data->reset_state) + return 0; + + if (data->force_device_on_en) + return 0; + + rc = stmvl53l1_module_func_tbl.reset_hold(data->client_object); + if (!rc) + data->reset_state = 1; +#ifdef USE_CAMERA_CCI + memset(&ccit,0,sizeof(ccit)); + ccit.cmd = CAMERA_CCI_RELEASE; + cam_cci_control_interface(&ccit); +#endif + + return rc; +} + +#ifdef DEBUG_TIME_LOG +static void stmvl53l0_DebugTimeGet(struct timeval *ptv) +{ + do_gettimeofday(ptv); +} + +#endif + +/** + * + * @param pstart_tv time val starting point + * @param pstop_tv time val end point + * @return time dif in usec + */ +long stmvl53l1_tv_dif(struct timeval *pstart_tv, struct timeval *pstop_tv) +{ + long total_sec, total_usec; + + total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec; + total_usec = (pstop_tv->tv_usec - pstart_tv->tv_usec); + + return total_sec*1000000+total_usec; +} + +#if STMVL53L1_CFG_ROI_DEBUG +static void dump_roi(VL53L1_UserRoi_t *rois, uint32_t n) +{ + uint32_t i; + + vl53l1_dbgmsg("roi dump %d roi:\n", n); + for (i = 0; i < n ; i++) { + vl53l1_dbgmsg("ROI#%02d %2d %2d %2d %2d\n", (int)i, + (int)rois[i].TopLeftX, (int)rois[i].TopLeftY, + (int)rois[i].BotRightX, (int)rois[i].BotRightY); + } +} +#else +# define dump_roi(...) (void)0 +#endif + +static int setup_tunings(struct stmvl53l1_data *data) +{ + int rc = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tunings); i++) { + rc = VL53L1_SetTuningParameter(&data->stdev, tunings[i][0], + tunings[i][1]); + if (rc) { + rc = store_last_error(data, rc); + break; + } + } + + return rc; +} + +/** + * + * @param data device data + * @return non 0 if current "preset mode" is a multi zone one + */ +static int is_mz_mode(struct stmvl53l1_data *data) +{ + return data->preset_mode == VL53L1_PRESETMODE_RANGING || + data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING; +} + +static void kill_mz_data(VL53L1_MultiRangingData_t *pdata) +{ + int i; + + memset(pdata, 0, sizeof(*pdata)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + pdata->RangeData[i].RangeStatus = VL53L1_RANGESTATUS_NONE; + pdata->RoiStatus = VL53L1_ROISTATUS_NOT_VALID; +} + +static void stmvl53l1_setup_auto_config(struct stmvl53l1_data *data) +{ + /* default config is detect object below 300mm with 1s period */ + data->auto_pollingTimeInMs = 1000; + data->auto_config.DetectionMode = VL53L1_DETECTION_DISTANCE_ONLY; + data->auto_config.IntrNoTarget = 0; + data->auto_config.Distance.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Distance.High = 1000; + data->auto_config.Distance.Low = 300; + data->auto_config.Rate.CrossMode = VL53L1_THRESHOLD_CROSSED_LOW; + data->auto_config.Rate.High = 0; + data->auto_config.Rate.Low = 0; +} + +static uint32_t stmvl53l1_compute_hash(VL53L1_RoiConfig_t *roi_cfg) +{ + return jhash(roi_cfg->UserRois, + roi_cfg->NumberOfRoi * sizeof(VL53L1_UserRoi_t), + roi_cfg->NumberOfRoi); +} + +static int stmvl53l1_check_calibration_id(struct stmvl53l1_data *data) +{ + uint32_t roi_id; + int rc; + + if (data->offset_correction_mode != VL53L1_OFFSETCORRECTIONMODE_PERZONE) + return 0; + if (data->current_roi_id == 0) + return 0; + + roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + rc = roi_id == data->current_roi_id ? 0 : -EINVAL; + + if (rc) + vl53l1_errmsg( + "Mismatch in zone calibration data 0x%08x != 0x%08x", + roi_id, data->current_roi_id); + + return rc; +} + +/** + * send params to sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_sendparams(struct stmvl53l1_data *data) +{ + int rc; + + /* activated stored or last request defined mode */ + rc = VL53L1_SetPresetMode(&data->stdev, data->preset_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode %d fail %d", + data->preset_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = VL53L1_SetXTalkCompensationEnable(&data->stdev, + data->crosstalk_enable); + if (rc) { + vl53l1_errmsg("VL53L1_SetXTalkCompensationEnable %d fail %d", + data->crosstalk_enable, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply distance mode only in lite and standard ranging */ + rc = VL53L1_SetDistanceMode(&data->stdev, data->distance_mode); + if (rc) { + vl53l1_errmsg("VL53L1_SetDistanceMode %d fail %d", + data->distance_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + + /* apply timing budget */ + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + data->timing_budget); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", + data->timing_budget, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("timing budget @%d\n", data->timing_budget); + + /* apply offset correction mode */ + rc = VL53L1_SetOffsetCorrectionMode(&data->stdev, + data->offset_correction_mode); + if (rc) { + vl53l1_errmsg("offset correction mode %d fail %d", + data->offset_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("offset correction mode @%d\n", + data->offset_correction_mode); + + /* check zone calibration vs roi */ + rc = stmvl53l1_check_calibration_id(data); + if (rc) + goto done; + + /* apply Dmax reflectance */ + rc = VL53L1_SetDmaxReflectance(&data->stdev, data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("dmax relectance %d fail %d", + data->dmax_reflectance, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax reflectance @%d\n", data->dmax_reflectance); + + /* apply Dmax mode */ + rc = VL53L1_SetDmaxMode(&data->stdev, data->dmax_mode); + if (rc) { + vl53l1_errmsg("dmax mode %d fail %d", data->dmax_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("dmax mode @%d\n", data->dmax_mode); + + /* apply smudge correction enable */ + rc = VL53L1_SmudgeCorrectionEnable(&data->stdev, + data->smudge_correction_mode); + if (rc) { + vl53l1_errmsg("smudge correction mode %d fail %d", + data->smudge_correction_mode, rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("smudge correction mode @%d\n", + data->smudge_correction_mode); + + /* apply roi if any set */ + //songyt add default range roi + if(data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING + /*|| data->preset_mode == VL53L1_PRESETMODE_RANGING*/){ + data->roi_cfg.NumberOfRoi = 4; + data->roi_cfg.UserRois[0].TopLeftX = 0; + data->roi_cfg.UserRois[0].TopLeftY = 15; + data->roi_cfg.UserRois[0].BotRightX = 7; + data->roi_cfg.UserRois[0].BotRightY = 8; + + data->roi_cfg.UserRois[1].TopLeftX = 8; + data->roi_cfg.UserRois[1].TopLeftY = 15; + data->roi_cfg.UserRois[1].BotRightX = 15; + data->roi_cfg.UserRois[1].BotRightY = 8; + + data->roi_cfg.UserRois[2].TopLeftX = 0; + data->roi_cfg.UserRois[2].TopLeftY = 7; + data->roi_cfg.UserRois[2].BotRightX = 7; + data->roi_cfg.UserRois[2].BotRightY = 0; + + data->roi_cfg.UserRois[3].TopLeftX = 8; + data->roi_cfg.UserRois[3].TopLeftY = 7; + data->roi_cfg.UserRois[3].BotRightX = 15; + data->roi_cfg.UserRois[3].BotRightY = 0; + }else{ + data->roi_cfg.NumberOfRoi = 0; + } + //end + dump_roi(data->roi_cfg.UserRois, data->roi_cfg.NumberOfRoi); + if (data->roi_cfg.NumberOfRoi) { + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + vl53l1_dbgmsg("#%d custom ROI set status\n", + data->roi_cfg.NumberOfRoi); + } else { + vl53l1_dbgmsg("using default ROI\n"); + } + + /* set autonomous mode configuration */ + if ((data->preset_mode == VL53L1_PRESETMODE_AUTONOMOUS) || + (data->preset_mode == VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)) { + rc = VL53L1_SetInterMeasurementPeriodMilliSeconds(&data->stdev, + data->auto_pollingTimeInMs); + if (rc) { + vl53l1_errmsg("Fail to set auto period %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = VL53L1_SetThresholdConfig(&data->stdev, + &data->auto_config); + if (rc) { + vl53l1_errmsg("Fail to set auto config %d\n", rc); + rc = store_last_error(data, rc); + goto done; + } + } + +done: + + return rc; +} + +/** + * start sensor + * + * @warning must be used if only stopped + * @param data device data + * @return 0 on sucess + */ +static int stmvl53l1_start(struct stmvl53l1_data *data) +{ + int rc; + + data->is_first_irq = true; + data->is_data_valid = false; + data->is_xtalk_value_changed = false; + stmvl53l1_enable_pinctrl(); + stmvl53l1_module_func_tbl.power_up(data->client_object); + rc = reset_release(data); + if (rc) + goto done; + + /* full setup when out of reset or power up */ + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit @%d fail %d\n", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + /* init the timing */ + do_gettimeofday(&data->start_tv); + data->meas.start_tv = data->start_tv; + /* init the ranging data => kill the previous ranging mz data */ + kill_mz_data(&data->meas.multi_range_data); + /* kill the single ranging data */ + memset(&data->meas.single_range_data, 0, + sizeof(VL53L1_RangingMeasurementData_t)); + + data->allow_hidden_start_stop = false; + /* kick off ranging */ + rc = VL53L1_StartMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StartMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + goto done; + } + + data->meas.cnt = 0; + data->meas.err_cnt = 0; + data->meas.err_tot = 0; + data->meas.poll_cnt = 0; + data->meas.intr = 0; + data->enable_sensor = 1; + + if (data->poll_mode) { + /* kick off the periodical polling work */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } +done: + data->is_first_start_done = true; + + return rc; +} + +/** + * stop sensor + * + * work lock must be held + * @warning to be used if only started! + */ +static int stmvl53l1_stop(struct stmvl53l1_data *data) +{ + int rc; + + rc = VL53L1_StopMeasurement(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StopMeasurement @%d fail %d", + __LINE__, rc); + rc = store_last_error(data, rc); + } + /* put device under reset */ + /* do we ask explicit intr stop or just use stop */ + reset_hold(data); + + data->enable_sensor = 0; + if (data->poll_mode) { + /* cancel periodical polling work */ + cancel_delayed_work(&data->dwork); + } + + /* if we are in ipp waiting mode then abort it */ + stmvl53l1_ipp_stop(data); + /* wake up all waiters */ + /* they will receive -ENODEV error */ + wake_up_data_waiters(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + stmvl53l1_disable_pinctrl(); + + return rc; +} + +/* + * SysFS support + */ +static ssize_t stmvl53l1_show_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enable_sensor); +} + +static ssize_t stmvl53l1_store_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc = 0; + unsigned long val; + + rc = kstrtoul(buf, 10, &val); + if (rc) { + vl53l1_errmsg("enable sensor syntax in %s\n", buf); + return -EINVAL; + } + if (val == 1) { + rc = ctrl_start(data); + } else if (val == 0) { + rc = ctrl_stop(data); + } else { + //TODO: Remove this workaround after investigation + //see Codex - 479397 for details + vl53l1_dbgmsg("Unclog Input sub-system\n"); + /* Unclog the input device sub-system */ + input_report_abs(data->input_dev_ps, ABS_HAT0X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT0Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT1Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT2Y, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3X, -1); + input_report_abs(data->input_dev_ps, ABS_HAT3Y, -1); + input_report_abs(data->input_dev_ps, ABS_WHEEL, -1); + input_report_abs(data->input_dev_ps, ABS_BRAKE, -1); + input_report_abs(data->input_dev_ps, ABS_GAS, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_X, -1); + input_report_abs(data->input_dev_ps, ABS_TILT_Y, -1); + input_report_abs(data->input_dev_ps, ABS_TOOL_WIDTH, -1); + input_report_abs(data->input_dev_ps, ABS_DISTANCE, -1); + input_report_abs(data->input_dev_ps, ABS_THROTTLE, -1); + input_report_abs(data->input_dev_ps, ABS_RUDDER, -1); + input_report_abs(data->input_dev_ps, ABS_MISC, -1); + input_report_abs(data->input_dev_ps, ABS_VOLUME, + -1); + input_sync(data->input_dev_ps); + vl53l1_dbgmsg("Unclog the input sub-system\n"); + rc = 0; + } + + vl53l1_dbgmsg("End\n"); + + return rc ? rc : count; +} + +/** + * sysfs attribute "enable_ps_sensor" [rd/wr] + * + * @li read show the current enable state + * @li write set the new state value "0" put sensor off "1" put it on + * + * @return 0 on success , EINVAL if fail to start + * + * @warning their's no check and assume exclusive usage of sysfs and ioctl\n + * Sensor will be put on/off disregard of any setup done by the ioctl channel. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_ps_sensor, + stmvl53l1_store_enable_ps_sensor); + +static int stmvl53l1_set_poll_delay_ms(struct stmvl53l1_data *data, int delay) +{ + int rc = 0; + + if (delay <= 0) + rc = -EINVAL; + else + data->poll_delay_ms = delay; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(poll_delay_ms, "poll delay ms") + +/** + * sysfs attribute "poll_delay_ms" [rd/wr] + * + * @li read show the current polling delay in millisecond + * @li write set the new polling delay in millisecond + * + * @note apply only if device is in polling mode\n + * for best performances (minimal delay and cpu load ) set it to the device + * period operating period +1 millis + + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_poll_delay_ms, + stmvl53l1_store_poll_delay_ms); + +/* Timing Budget */ +static int stmvl53l1_set_timing_budget(struct stmvl53l1_data *data, int timing) +{ + int rc = 0; + + if (timing <= 0) { + vl53l1_errmsg("invalid timing valid %d\n", timing); + rc = -EINVAL; + } else if (data->enable_sensor) { + rc = VL53L1_SetMeasurementTimingBudgetMicroSeconds(&data->stdev, + timing); + if (rc) { + vl53l1_errmsg("SetTimingBudget %d fail %d", timing, rc); + rc = store_last_error(data, rc); + } else + data->timing_budget = timing; + } else + data->timing_budget = timing; + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(timing_budget, "timing budget") + +/** + * sysfs "timing_budget" [rd/wr] + * + * set or get the ranging timing budget in microsecond + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(timing_budget, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_timing_budget, + stmvl53l1_store_timing_budget); + + +static ssize_t stmvl53l1_show_roi(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int i; + int n; + + + mutex_lock(&data->work_mutex); + if (data->roi_cfg.NumberOfRoi == 0) { + /* none define by user */ + /* we could get what stored but may not even be default */ + n = scnprintf(buf, PAGE_SIZE, "device default\n"); + } else { + for (i = 0, n = 0; i < data->roi_cfg.NumberOfRoi; i++) { + n += scnprintf(buf+n, PAGE_SIZE-n, "%d %d %d %d%c", + data->roi_cfg.UserRois[i].TopLeftX, + data->roi_cfg.UserRois[i].TopLeftY, + data->roi_cfg.UserRois[i].BotRightX, + data->roi_cfg.UserRois[i].BotRightY, + i == data->roi_cfg.NumberOfRoi-1 ? + '\n' : ','); + } + } + mutex_unlock(&data->work_mutex); + return n; +} + + +static const char str_roi_ranging[] = "ERROR can't set roi while ranging\n"; + +static ssize_t stmvl53l1_store_roi(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_UserRoi_t rois[VL53L1_MAX_USER_ZONES]; + int rc; + + mutex_lock(&data->work_mutex); + if (data->enable_sensor) { + vl53l1_errmsg(" cant set roi now\n"); + rc = -EBUSY; + } else { + int n, n_roi = 0; + const char *pc = buf; + int tlx, tly, brx, bry; + + while (n_roi < VL53L1_MAX_USER_ZONES && pc != NULL + && *pc != 0 && *pc != '\n') { + n = sscanf(pc, "%d %d %d %d", &tlx, &tly, &brx, &bry); + if (n == 4) { + rois[n_roi].TopLeftX = tlx; + rois[n_roi].TopLeftY = tly; + rois[n_roi].BotRightX = brx; + rois[n_roi].BotRightY = bry; + n_roi++; + } else { + vl53l1_errmsg( +"wrong roi #%d syntax around %s of %s", n_roi, pc, buf); + n_roi = -1; + break; + } + /* find next roi separator */ + pc = strchr(pc, ','); + if (pc) + pc++; + } + /*if any set them */ + if (n_roi >= 0) { + if (n_roi) + memcpy(data->roi_cfg.UserRois, rois, + n_roi*sizeof(rois[0])); + data->roi_cfg.NumberOfRoi = n_roi; + dump_roi(data->roi_cfg.UserRois, + data->roi_cfg.NumberOfRoi); + rc = count; + } else { + rc = -EINVAL; + } + } + mutex_unlock(&data->work_mutex); + vl53l1_dbgmsg("ret %d count %d\n", rc, (int)count); + + return rc; +} + +/** + * sysfs attribute "roi" [rd/wr] + * + * @li read show the current user customized roi setting + * @li write set user custom roi, it can only be done while not ranging. + * + * syntax for set input roi + * @li "[tlx tly brx bry,]\n" repeat n time require will set the n roi + * @li "\n" will reset + * + * @warning roi coordinate is not image x,y(down) but euclidian x,y(up) + * + * @warning roi validity is only check at next range start + * @warning user is responsible to set appropriate number an roi before each + * mode change + * @note roi can be return to default by setting none "" + * + *@code + * >#to set 2x roi + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * >echo $? + * 0 + * >cat /sys/class/input6/roi + * "0 15 15 0,0 8 8 0" + * #to cancel user define roi" + * >echo "" > /sys/class/input1/roi + * >echo $? + * 0 + * >echo "1" > /sys/class/input6/enable_ps_senspor + * #try to set roi while ranging + * >echo "0 15 15 0, 0 8 8 0" > /sys/class/input6/roi + * [58451.912109] stmvl53l1_store_roi: cant set roi now + * >echo $? + * 1 + *@endcode + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(roi, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_roi, + stmvl53l1_store_roi); + + +static int stmvl53l1_set_preset_mode(struct stmvl53l1_data *data, int mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change mode while ranging\n"); + rc = -EBUSY; + } else { + switch (mode) { + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + data->preset_mode = mode; + vl53l1_dbgmsg("preset mode %d\n", mode); + break; + default: + vl53l1_errmsg("invalid mode %d\n", mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(preset_mode, "preset mode") + +/** + * sysfs attribute "mode " [rd/wr] + * + * set the mode value can only be used while: not ranging + * @li 1 @a VL53L1_PRESETMODE_RANGING default ranging + * @li 2 @a VL53L1_PRESETMODE_MULTIZONES_SCANNING multiple zone + * @li 3 @a VL53L1_PRESETMODE_AUTONOMOUS autonomous mode + * @li 4 @a VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS low Power autonomous mode + * @li 5 @a VL53L1_PRESETMODE_LITE_RANGING low mips ranging mode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_preset_mode, + stmvl53l1_store_preset_mode); + +static int stmvl53l1_set_distance_mode(struct stmvl53l1_data *data, + int distance_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change distance mode while ranging\n"); + rc = -EBUSY; + } else { + switch (distance_mode) { + case VL53L1_DISTANCEMODE_SHORT: + case VL53L1_DISTANCEMODE_MEDIUM: + case VL53L1_DISTANCEMODE_LONG: + data->distance_mode = distance_mode; + vl53l1_dbgmsg("distance mode %d\n",distance_mode); + break; + default: + vl53l1_errmsg("invalid distance mode %d\n", + distance_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(distance_mode, "distance mode") + +/** + * sysfs attribute " distance mode" [rd/wr] + * + * set the distance mode value can only be used while: not ranging + * @li 1 @a VL53L1_DISTANCEMODE_SHORT + * @li 2 @a VL53L1_DISTANCEMODE_MEDIUM + * @li 3 @a VL53L1_DISTANCEMODE_LONG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(distance_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_distance_mode, + stmvl53l1_store_distance_mode); + +static int stmvl53l1_set_crosstalk_enable(struct stmvl53l1_data *data, + int crosstalk_enable) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change crosstalk enable while ranging\n"); + rc = -EBUSY; + } else if (crosstalk_enable == 0 || crosstalk_enable == 1) { + data->crosstalk_enable = crosstalk_enable; + } else { + vl53l1_errmsg("invalid crosstalk enable %d\n", + crosstalk_enable); + rc = -EINVAL; + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(crosstalk_enable, "crosstalk enable") + +/** + * sysfs attribute " crosstalk enable" [rd/wr] + * + * control if crosstalk compensation is eanble or not + * @li 0 disable crosstalk compensation + * @li 1 enable crosstalk compensation + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(crosstalk_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_crosstalk_enable, + stmvl53l1_store_crosstalk_enable); + +static int stmvl53l1_set_output_mode(struct stmvl53l1_data *data, + int output_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change output mode while ranging\n"); + rc = -EBUSY; + } else { + switch (output_mode) { + case VL53L1_OUTPUTMODE_NEAREST: + case VL53L1_OUTPUTMODE_STRONGEST: + data->output_mode = output_mode; + vl53l1_dbgmsg("output mode %d\n", output_mode); + break; + default: + vl53l1_errmsg("invalid output mode %d\n", output_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(output_mode, "output mode") + +/** + * sysfs attribute " output mode" [rd/wr] + * + * set the output mode value can only be used while: not ranging + * @li 1 @a VL53L1_OUTPUTMODE_NEAREST + * @li 2 @a VL53L1_OUTPUTMODE_STRONGEST + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(output_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_output_mode, + stmvl53l1_store_output_mode); + + +static int stmvl53l1_set_force_device_on_en(struct stmvl53l1_data *data, + int force_device_on_en) +{ + int rc; + + if (force_device_on_en != 0 && force_device_on_en != 1) { + vl53l1_errmsg("invalid force_device_on_en mode %d\n", + force_device_on_en); + return -EINVAL; + } + + data->force_device_on_en = force_device_on_en; + + /* don't update reset if sensor is enable */ + if (data->enable_sensor) + return 0; + + /* ok update reset according force_device_on_en value */ + if (force_device_on_en){ + rc = reset_release(data); + vl53l1_dbgmsg("force_device_on_en.\n"); + }else{ + vl53l1_dbgmsg("force_device_on_en disable.\n"); + rc = reset_hold(data); + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(force_device_on_en, "force device on enable") + +/** + * sysfs attribute " force_device_on_enable" [rd/wr] + * + * Control if device is put under reset when stopped. + * @li 0 feature is disable. Device is put under reset when stopped. + * @li 1 feature is enable. Device is not put under reset when stopped. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(force_device_on_enable, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_force_device_on_en, + stmvl53l1_store_force_device_on_en); + +static int stmvl53l1_set_offset_correction_mode(struct stmvl53l1_data *data, + int offset_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change offset correction mode while ranging\n"); + rc = -EBUSY; + } else { + switch (offset_correction_mode) { + case VL53L1_OFFSETCORRECTIONMODE_STANDARD: + case VL53L1_OFFSETCORRECTIONMODE_PERZONE: + data->offset_correction_mode = offset_correction_mode; + break; + default: + vl53l1_errmsg("invalid offset correction mode %d\n", + offset_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(offset_correction_mode, "offset correction mode") + +/** + * sysfs attribute " offset_correction_mode" [rd/wr] + * + * Control which offset correction is apply on result. can only be used + * while: not ranging + * @li 1 @a VL53L1_OFFSETCORRECTIONMODE_STANDARD + * @li 2 @a VL53L1_OFFSETCORRECTIONMODE_PERZONE + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(offset_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_offset_correction_mode, + stmvl53l1_store_offset_correction_mode); + +static ssize_t stmvl53l1_do_flush(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + mutex_lock(&data->work_mutex); + + data->flush_todo_counter++; + if (data->enable_sensor == 0) + stmvl53l1_insert_flush_events_lock(data); + + mutex_unlock(&data->work_mutex); + + return count; +} + +static DEVICE_ATTR(do_flush, 0660/*S_IWUGO | S_IRUGO*/, + NULL, + stmvl53l1_do_flush); + +static ssize_t stmvl53l1_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", stmvl53l1_enable_debug); +} + +static ssize_t stmvl53l1_store_enable_debug(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int enable_debug; + int rc = 0; + + if (kstrtoint(buf, 0, &enable_debug)) { + vl53l1_errmsg("invalid syntax in %s", buf); + rc = -EINVAL; + } else + stmvl53l1_enable_debug = enable_debug; + + return rc ? rc : count; +} + +/** + * sysfs attribute " debug enable" [rd/wr] + * + * dynamic control of vl53l1_dbgmsg messages. Note that in any case your code + * must be enable with DEBUG in stmvl53l1.h at compile time. + * @li 0 disable vl53l1_dbgmsg messages + * @li 1 enable vl53l1_dbgmsg messages + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(enable_debug, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_enable_debug, + stmvl53l1_store_enable_debug); + +static ssize_t display_FixPoint1616(char *buf, size_t size, FixPoint1616_t fix) +{ + uint32_t msb = fix >> 16; + uint32_t lsb = fix & 0xffff; + + lsb = (lsb * 1000000ULL + 32768) / 65536; + + return scnprintf(buf, size, "%d.%06d", msb, (uint32_t) lsb); +} + +static ssize_t stmvl53l1_show_autonomous_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += scnprintf(&buf[res], PAGE_SIZE, "%d %d %d %d %d %d %d ", + data->auto_pollingTimeInMs, + data->auto_config.DetectionMode, + data->auto_config.IntrNoTarget, + data->auto_config.Distance.CrossMode, + data->auto_config.Distance.High, + data->auto_config.Distance.Low, + data->auto_config.Rate.CrossMode); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.High); + + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->auto_config.Rate.Low); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static const char *parse_integer(const char *buf, int *res) +{ + int rc; + + while (*buf == ' ') + buf++; + rc = sscanf(buf, "%d ", res); + if (!rc) + return NULL; + + return strchr(buf, ' '); +} + +static bool is_float_format(const char *buf, bool is_last) +{ + char *dot = strchr(buf, '.'); + char *space_or_eos = strchr(buf, is_last ? '\0' : ' '); + + if (!space_or_eos) + return !!dot; + if (!dot) + return false; + + return dot < space_or_eos ? true : false; +} + +static int parse_FixPoint16x16_lsb(const char *lsb_char) +{ + int lsb = 0; + int digit_nb = 0; + + /* parse at most 6 digits */ + lsb_char++; + while (isdigit(*lsb_char) && digit_nb < 6) { + lsb = lsb * 10 + (*lsb_char - '0'); + lsb_char++; + digit_nb++; + } + while (digit_nb++ < 6) + lsb = lsb * 10; + + return div64_s64(lsb * 65536ULL + 500000, 1000000); +} + +/* parse next fix point value and return a pointer to next blank or newline + * character according to is_last parameter. + * parse string must have digit for integer part (something like '.125' will + * return an error) or an error will be return. Only the first 6 digit of the + * decimal part will be parsed. + */ +static const char *parse_FixPoint16x16(const char *buf, FixPoint1616_t *res, + bool is_last) +{ + bool is_float; + int msb; + int lsb = 0; + int rc; + + while (*buf == ' ') + buf++; + is_float = is_float_format(buf, is_last); + + /* scan msb */ + rc = sscanf(buf, "%d ", &msb); + if (!rc) + return NULL; + /* then lsb if present */ + if (is_float) + lsb = parse_FixPoint16x16_lsb(strchr(buf, '.')); + *res = (msb << 16) + lsb; + + return strchr(buf, is_last ? '\0' : ' '); +} + +static ssize_t stmvl53l1_store_autonomous_config(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int pollingTimeInMs, DetectionMode, IntrNoTarget; + int d_CrossMode, d_High, d_Low; + int r_CrossMode; + FixPoint1616_t r_High, r_Low; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + if (data->enable_sensor) + goto busy; + + buf = parse_integer(buf, &pollingTimeInMs); + if (!buf) + goto invalid; + buf = parse_integer(buf, &DetectionMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &IntrNoTarget); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_CrossMode); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_High); + if (!buf) + goto invalid; + buf = parse_integer(buf, &d_Low); + if (!buf) + goto invalid; + buf = parse_integer(buf, &r_CrossMode); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_High, false); + if (!buf) + goto invalid; + buf = parse_FixPoint16x16(buf, &r_Low, true); + if (!buf) + goto invalid; + + data->auto_pollingTimeInMs = pollingTimeInMs; + data->auto_config.DetectionMode = DetectionMode; + data->auto_config.IntrNoTarget = IntrNoTarget; + data->auto_config.Distance.CrossMode = d_CrossMode; + data->auto_config.Distance.High = d_High; + data->auto_config.Distance.Low = d_Low; + data->auto_config.Rate.CrossMode = r_CrossMode; + data->auto_config.Rate.High = r_High; + data->auto_config.Rate.Low = r_Low; + + mutex_unlock(&data->work_mutex); + + return count; + +busy: + vl53l1_errmsg("can't change config while ranging"); + rc = -EBUSY; + goto error; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute " autonomous_config" [rd/wr] + * + * Will set/get autonomous configuration using sysfs. + * + * format is the following : + * + * + * + *@code + * > echo "1000 1 0 0 1000 300 0 2.2 1.001" > autonomous_config + *@endcode + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(autonomous_config, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_autonomous_config, + stmvl53l1_store_autonomous_config); + +static ssize_t stmvl53l1_show_last_error_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", data->last_error); +} + +/** + * sysfs attribute " last_error" [rd] + * + * Will get last internal error using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(last_error, 0440/*S_IRUGO*/, + stmvl53l1_show_last_error_config, + NULL); + +static ssize_t stmvl53l1_show_optical_center_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_x); + res += scnprintf(&buf[res], PAGE_SIZE - res, " "); + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->optical_offset_y); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(optical_center, 0440/*S_IRUGO*/, + stmvl53l1_show_optical_center_config, + NULL); + +static int stmvl53l1_set_dmax_reflectance(struct stmvl53l1_data *data, + int dmax_reflectance) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg( + "can't change dmax reflectance while ranging\n"); + rc = -EBUSY; + } else + data->dmax_reflectance = dmax_reflectance; + + return rc; +} + +static ssize_t stmvl53l1_show_dmax_reflectance(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + ssize_t res = 0; + + res += display_FixPoint1616(&buf[res], PAGE_SIZE - res, + data->dmax_reflectance); + + res += scnprintf(&buf[res], PAGE_SIZE - res, "\n"); + + return res; +} + +static ssize_t stmvl53l1_store_dmax_reflectance(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + FixPoint1616_t dmax_reflectance; + const char *buf_ori = buf; + int rc; + + mutex_lock(&data->work_mutex); + + buf = parse_FixPoint16x16(buf, &dmax_reflectance, true); + if (!buf) + goto invalid; + rc = stmvl53l1_set_dmax_reflectance(data, dmax_reflectance); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax in %s", buf_ori); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "dmax_reflectance" [rd/wr] + * + * target reflectance use for calculate the ambient DMAX. can only be used + * while: not ranging + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_reflectance, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_reflectance, + stmvl53l1_store_dmax_reflectance); + +static int stmvl53l1_set_dmax_mode(struct stmvl53l1_data *data, + int dmax_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change dmax mode while ranging\n"); + rc = -EBUSY; + } else { + switch (dmax_mode) { + case VL53L1_DMAXMODE_FMT_CAL_DATA: + case VL53L1_DMAXMODE_CUSTCAL_DATA: + case VL53L1_DMAXMODE_PER_ZONE_CAL_DATA: + data->dmax_mode = dmax_mode; + break; + default: + vl53l1_errmsg("invalid dmax mode %d\n", dmax_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(dmax_mode, "dmax mode") + +/** + * sysfs attribute " dmax mode" [rd/wr] + * + * set the dmax mode value can only be used while: not ranging + * @li 1 @a VL53L1_DMAXMODE_FMT_CAL_DATA + * @li 2 @a VL53L1_DMAXMODE_CUSTCAL_DATA + * @li 3 @a VL53L1_DMAXMODE_PER_ZONE_CAL_DATA + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(dmax_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_dmax_mode, + stmvl53l1_store_dmax_mode); + +static int stmvl53l1_set_tuning(struct stmvl53l1_data *data, int key, + int value) +{ + int rc; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change tuning params while ranging\n"); + return -EBUSY; + } + + if (data->is_calibrating) { + vl53l1_errmsg("can't change tuning params while calibrating\n"); + return -EBUSY; + } + + if (key & ~0xffff) + return -EINVAL; + + vl53l1_dbgmsg("trying to set %d with key %d", value, key); + + rc = VL53L1_SetTuningParameter(&data->stdev, key, value); + if (rc) + rc = store_last_error(data, rc); + + return rc; +} + +static ssize_t stmvl53l1_store_tuning(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int key; + int value; + int n; + int rc; + + mutex_lock(&data->work_mutex); + + n = sscanf(buf, "%d %d", &key, &value); + if (n != 2) { + rc = -EINVAL; + goto error; + } + rc = stmvl53l1_set_tuning(data, key, value); + if (rc) + goto error; + + mutex_unlock(&data->work_mutex); + + return count; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * sysfs attribute "tuning" [wr] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning, 0220/*S_IWUGO */, + NULL, + stmvl53l1_store_tuning); + +static int stmvl53l1_display_tuning_key(struct stmvl53l1_data *data, char *buf, + int *pos, int key) +{ + int rc = 0; + int value = 0; + int sz; + + rc = VL53L1_GetTuningParameter(&data->stdev, key, &value); + if (rc) + return 0; + + sz = snprintf(&buf[*pos], PAGE_SIZE - *pos, "%d %d\n", key, value); + if (sz >= PAGE_SIZE - *pos) + return -ENOSPC; /* FIXME : another better error ? */ + + *pos += sz; + + return 0; +} + +static ssize_t stmvl53l1_show_tuning_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + const int max_tuning_key = 65535; + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + int i; + int pos = 0; + + mutex_lock(&data->work_mutex); + + for (i = 0; i < max_tuning_key; ++i) { + rc = stmvl53l1_display_tuning_key(data, buf, &pos, i); + if (rc) + break; + } + + mutex_unlock(&data->work_mutex); + + return rc ? rc : pos; +} + +/** + * sysfs attribute "tuning_status" [rd] + * + * write a tuning parameter. Two integer parameters are given. First one + * is a key that specify which tuning parameter is update. Other one is the + * value which is write. + * + * writing a tuning parameter is only allowed before the first start. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(tuning_status, 0440/*S_IRUGO */, + stmvl53l1_show_tuning_status, + NULL); + +static int stmvl53l1_set_smudge_correction_mode(struct stmvl53l1_data *data, + int smudge_correction_mode) +{ + int rc = 0; + + if (data->enable_sensor) { + vl53l1_errmsg("can't change smudge corr mode while ranging\n"); + rc = -EBUSY; + } else { + switch (smudge_correction_mode) { + case VL53L1_SMUDGE_CORRECTION_NONE: + case VL53L1_SMUDGE_CORRECTION_CONTINUOUS: + case VL53L1_SMUDGE_CORRECTION_SINGLE: + case VL53L1_SMUDGE_CORRECTION_DEBUG: + data->smudge_correction_mode = smudge_correction_mode; + break; + default: + vl53l1_errmsg("invalid smudge correction mode %d\n", + smudge_correction_mode); + rc = -EINVAL; + break; + } + } + + return rc; +} + +IMPLEMENT_PARAMETER_INTEGER(smudge_correction_mode, "smudge correction mode") + +/** + * sysfs attribute " smudge_correction_mode" [rd/wr] + * + * This parameter will control if smudge correction is enable and how crosstalk + * values are updated. + * @li 0 @a VL53L1_SMUDGE_CORRECTION_NONE + * @li 1 @a VL53L1_SMUDGE_CORRECTION_CONTINUOUS + * @li 2 @a VL53L1_SMUDGE_CORRECTION_SINGLE + * @li 3 @a VL53L1_SMUDGE_CORRECTION_DEBUG + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(smudge_correction_mode, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l1_show_smudge_correction_mode, + stmvl53l1_store_smudge_correction_mode); + +static ssize_t stmvl53l1_show_is_xtalk_value_changed_config(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int param; + + mutex_lock(&data->work_mutex); + param = data->is_xtalk_value_changed; + mutex_unlock(&data->work_mutex); + + return scnprintf(buf, PAGE_SIZE, "%d\n", param); +} + +/** + * sysfs attribute " optical_center" [rd] + * + * Will get optical_center using sysfs. + * + * @ingroup sysfs_attrib + */ +static DEVICE_ATTR(is_xtalk_value_changed, 0440/*S_IRUGO*/, + stmvl53l1_show_is_xtalk_value_changed_config, + NULL); + +static struct attribute *stmvl53l1_attributes[] = { + &dev_attr_enable_ps_sensor.attr, + &dev_attr_set_delay_ms.attr, + &dev_attr_timing_budget.attr, + &dev_attr_roi.attr, + &dev_attr_mode.attr, + &dev_attr_do_flush.attr, + &dev_attr_distance_mode.attr, + &dev_attr_crosstalk_enable.attr, + &dev_attr_enable_debug.attr, + &dev_attr_output_mode.attr, + &dev_attr_force_device_on_enable.attr, + &dev_attr_autonomous_config.attr, + &dev_attr_last_error.attr, + &dev_attr_offset_correction_mode.attr, + &dev_attr_optical_center.attr, + &dev_attr_dmax_reflectance.attr, + &dev_attr_dmax_mode.attr, + &dev_attr_tuning.attr, + &dev_attr_tuning_status.attr, + &dev_attr_smudge_correction_mode.attr, + &dev_attr_is_xtalk_value_changed.attr, + NULL +}; + +static const struct attribute_group stmvl53l1_attr_group = { + .attrs = stmvl53l1_attributes, +}; + +static ssize_t stmvl53l1_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + VL53L1_CalibrationData_t calib; + int rc; + void *src = (void *) &calib; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* sanity check */ + if (off < 0 || off >= sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + /* got current calibration data */ + memset(&calib, 0, sizeof(calib)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + /* copy to buffer */ + if (off + count > sizeof(VL53L1_CalibrationData_t)) + count = sizeof(VL53L1_CalibrationData_t) - off; + memcpy(buf, src + off, count); + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto error; + } + + /* we only support one time write */ + if (off != 0 || count != sizeof(VL53L1_CalibrationData_t)) + goto invalid; + + rc = VL53L1_SetCalibrationData(&data->stdev, + (VL53L1_CalibrationData_t *) buf); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_calib_data_attr = { + .attr = { + .name = "calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(VL53L1_CalibrationData_t), + .read = stmvl53l1_calib_data_read, + .write = stmvl53l1_calib_data_write, +}; + +static ssize_t stmvl53l1_zone_calib_data_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *src = (void *) &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* sanity check */ + if (off < 0 || off >= sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + /* got current zone calibration data */ + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto error; + } + data->calib.data.id = data->current_roi_id; + + /* copy to buffer */ + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + count = sizeof(stmvl531_zone_calibration_data_t) - off; + memcpy(buf, src + off, count); + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static ssize_t stmvl53l1_zone_calib_data_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct stmvl53l1_data *data = dev_get_drvdata(dev); + int rc; + void *dst = &data->calib.data; + + mutex_lock(&data->work_mutex); + + vl53l1_dbgmsg("off = %lld / count = %d", off, count); + + /* implementation if quite fragile. We suppose successive access. We + * trigger set on last byte write if amount is exact. + */ + if (off < 0 || off >= sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + if (off + count > sizeof(stmvl531_zone_calibration_data_t)) + goto invalid; + + memcpy(dst + off, buf, count); + if (off + count == sizeof(stmvl531_zone_calibration_data_t)) { + vl53l1_dbgmsg("trigger zone calib setting"); + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &data->calib.data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto error; + } + data->current_roi_id = data->calib.data.id; + } + + mutex_unlock(&data->work_mutex); + + return count; + +invalid: + vl53l1_errmsg("invalid syntax"); + rc = -EINVAL; + goto error; + +error: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static struct bin_attribute stmvl53l1_zone_calib_data_attr = { + .attr = { + .name = "zone_calibration_data", + .mode = 0660/*S_IWUGO | S_IRUGO*/, + }, + .size = sizeof(stmvl531_zone_calibration_data_t), + .read = stmvl53l1_zone_calib_data_read, + .write = stmvl53l1_zone_calib_data_write, +}; + +static int ctrl_reg_access(struct stmvl53l1_data *data, void *p) +{ + struct stmvl53l1_register reg; + size_t total_byte; + int rc; + + if (data->is_device_remove) + return -ENODEV; + + total_byte = offsetof(struct stmvl53l1_register, data.b); + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + + if (reg.cnt > STMVL53L1_MAX_CCI_XFER_SZ) { + vl53l1_errmsg("reg len %d > size limit\n", reg.cnt); + return -EINVAL; + } + + total_byte = offsetof(struct stmvl53l1_register, data.bytes[reg.cnt]); + /* for write get the effective data part of the structure */ + if (!reg.is_read) { + if (copy_from_user(®, p, total_byte)) { + vl53l1_errmsg(" data cpy fail\n"); + return -EFAULT; + } + } + + /* put back to user only needed amount of data */ + if (!reg.is_read) { + rc = VL53L1_WriteMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + /* for write only write back status no data */ + total_byte = offsetof(struct stmvl53l1_register, data.b); + vl53l1_dbgmsg("wr %x %d bytes statu %d\n", + reg.index, reg.cnt, rc); + if (rc) + rc = store_last_error(data, rc); + } else { + rc = VL53L1_ReadMulti(&data->stdev, (uint16_t)reg.index, + reg.data.bytes, reg.cnt); + reg.status = rc; + vl53l1_dbgmsg("rd %x %d bytes status %d\n", + reg.index, reg.cnt, rc); + /* if fail do not copy back data only status */ + if (rc) { + total_byte = offsetof(struct stmvl53l1_register, + data.b); + rc = store_last_error(data, rc); + } + /* else the total byte is already the full pay-load with data */ + } + + if (copy_to_user(p, ®, total_byte)) { + vl53l1_errmsg("%d, fail\n", __LINE__); + return -EFAULT; + } + return rc; +} + + +/* + * + */ +static int ctrl_start(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + + vl53l1_dbgmsg(" state = %d\n", data->enable_sensor); + + /* turn on tof sensor only if it's not already started */ + if (data->enable_sensor == 0 && !data->is_calibrating) { + /* to start */ + rc = stmvl53l1_start(data); + } else{ + rc = -EBUSY; + } + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * no lock version of ctrl_stop (mutex shall be held) + * + * @warning exist only for use in device exit to ensure "locked and started" + * may also beuse in soem erro handling when mutex is already locked + * @return 0 on success and was running >0 if already off <0 on error + */ +static int _ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter state = %d\n", data->enable_sensor); + /* be sure waiters are woken */ + data->is_data_valid = true; + /* turn on tof sensor only if it's not enabled by other client */ + if (data->enable_sensor == 1) { + /* to stop */ + rc = stmvl53l1_stop(data); + } else { + vl53l1_dbgmsg("already off did nothing\n"); + rc = 0; + } + stmvl53l1_insert_flush_events_lock(data); + vl53l1_dbgmsg(" final state = %d\n", data->enable_sensor); + + return rc; +} + +/** + * get work lock and stop sensor + * + * see @ref _ctrl_stop + * + * @param data device + * @return 0 on success EBUSY if arleady off + */ +static int ctrl_stop(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + if (data->enable_sensor) + rc = _ctrl_stop(data); + else + rc = -EBUSY; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_getdata(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(p, + &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static bool is_new_data_for_me(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + return data->is_data_valid && !is_pid_in_list(pid, head); +} + +static bool sleep_for_data_condition(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + bool res; + + mutex_lock(&data->work_mutex); + res = is_new_data_for_me(data, pid, head); + mutex_unlock(&data->work_mutex); + + return res; +} + +static int sleep_for_data(struct stmvl53l1_data *data, pid_t pid, + struct list_head *head) +{ + int rc; + + mutex_unlock(&data->work_mutex); + if(data->preset_mode == VL53L1_PRESETMODE_LITE_RANGING){ + rc = wait_event_killable(data->waiter_for_data, + sleep_for_data_condition(data, pid, head)); + }else{ + rc = wait_event_killable_timeout(data->waiter_for_data, + sleep_for_data_condition(data, pid, head),HZ);//songyt change to timeoutable.1 second. + } + mutex_lock(&data->work_mutex); + + return data->enable_sensor ? rc : -ENODEV; +} + +static int ctrl_getdata_blocking(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + /* If device not ranging then exit on error */ + if (data->is_device_remove || !data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->simple_data_reader_list)) + rc = sleep_for_data(data, pid, &data->simple_data_reader_list); + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(p, &data->meas.single_range_data, + sizeof(stmvl531_range_data_t)); + if (rc) + goto done; + rc = add_reader(pid, &data->simple_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_common(struct stmvl53l1_data *data, void __user *p, + bool is_additional) +{ + struct stmvl53l1_data_with_additional __user *d = p; + int rc; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) { + vl53l1_dbgmsg("copy to user fail %d", rc); + rc = -EFAULT; + goto done; + } + } + if (!data->enable_sensor) + rc = -ENODEV; + else if (!is_mz_mode(data)) + rc = -ENOEXEC; + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_mz_data_blocking_common(struct stmvl53l1_data *data, + void __user *p, bool is_additional) +{ + int rc = 0; + struct stmvl53l1_data_with_additional __user *d = p; + pid_t pid = current->pid; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* mode 2 or 3 */ + if (!is_mz_mode(data)) { + rc = -ENOEXEC; + goto done; + } + /* If device not ranging then exit on error */ + if (!data->enable_sensor) { + rc = -ENODEV; + goto done; + } + /* sleep if data already read */ + if (!is_new_data_for_me(data, pid, &data->mz_data_reader_list)) + rc = sleep_for_data(data, pid, &data->mz_data_reader_list);//songyt test + if (rc) + goto done; + + /* unless we got interrupted we return data to user and note read */ + rc = copy_to_user(&d->data, &data->meas.multi_range_data, + sizeof(VL53L1_MultiRangingData_t)); + if (rc) + goto done; + if (is_additional) { + rc = copy_to_user(&d->additional_data, + &data->meas.additional_data, + sizeof(VL53L1_AdditionalData_t)); + if (rc) + goto done; + } + rc = add_reader(pid, &data->mz_data_reader_list); + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +/** + * Get multi zone data + * @param data + * @param p [out] user ptr to @ref VL53L1_MultiRangingData_t structure\n + * is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, false); +} + +static int ctrl_mz_data_blocking(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, false); +} + +/** + * Get multi zone data with histogram debug data + * @param data + * @param p [out] user ptr to @ref struct stmvl53l1_data_with_additional + * structure is always set but on EFAULT error + * + * @return + * @li 0 on success + * @li ENODEV if not ranging + * @li ENOEXEC not in multi zone mode + * @li EFAULT copy to user error + */ +static int ctrl_mz_data_additional(struct stmvl53l1_data *data, void __user *p) +{ + return ctrl_mz_data_common(data, p, true); +} + +static int ctrl_mz_data_blocking_additional(struct stmvl53l1_data *data, + void __user *p) +{ + return ctrl_mz_data_blocking_common(data, p, true); +} + +static int ctrl_param_last_error(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->last_error; + param->status = 0; + vl53l1_dbgmsg("get last error %d", param->value); + rc = 0; + } else { + rc = -EINVAL; + } + + return rc; +} + +static int ctrl_param_optical_center(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->optical_offset_x; + param->value2 = data->optical_offset_y; + + return 0; +} + +static int ctrl_param_dmax_reflectance(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + int rc; + + if (param->is_read) { + param->value = data->dmax_reflectance; + param->status = 0; + vl53l1_dbgmsg("get dmax reflectance %d", param->value); + rc = 0; + } else { + rc = stmvl53l1_set_dmax_reflectance(data, param->value); + vl53l1_dbgmsg("rc %d req %d now %d", rc, + param->value, data->dmax_reflectance); + } + + return rc; +} + +static int ctrl_param_tuning(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (param->is_read) + return -EINVAL; + + return stmvl53l1_set_tuning(data, param->value, param->value2); +} + +static int ctrl_param_is_xtalk_value_changed(struct stmvl53l1_data *data, + struct stmvl53l1_parameter *param) +{ + if (!param->is_read) + return -EINVAL; + + param->value = data->is_xtalk_value_changed; + + return 0; +} + +/** + * handle ioctl set param mode + * + * @param data + * @param p + * @return 0 on success + */ +static int ctrl_params(struct stmvl53l1_data *data, void __user *p) +{ + int rc, rc2; + struct stmvl53l1_parameter param; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(¶m, p, sizeof(param)); + param.status = 0; + if (rc) { + rc = -EFAULT; + goto done; /* no need for status in user struct */ + } + switch (param.name) { + case VL53L1_POLLDELAY_PAR: + rc = ctrl_param_poll_delay_ms(data, ¶m); + break; + case VL53L1_TIMINGBUDGET_PAR: + rc = ctrl_param_timing_budget(data, ¶m); + break; + case VL53L1_DEVICEMODE_PAR: + rc = ctrl_param_preset_mode(data, ¶m); + break; + case VL53L1_DISTANCEMODE_PAR: + rc = ctrl_param_distance_mode(data, ¶m); + break; + case VL53L1_XTALKENABLE_PAR: + rc = ctrl_param_crosstalk_enable(data, ¶m); + break; + case VL53L1_OUTPUTMODE_PAR: + rc = ctrl_param_output_mode(data, ¶m); + break; + case VL53L1_FORCEDEVICEONEN_PAR: + rc = ctrl_param_force_device_on_en(data, ¶m); + break; + case VL53L1_LASTERROR_PAR: + rc = ctrl_param_last_error(data, ¶m); + break; + case VL53L1_OFFSETCORRECTIONMODE_PAR: + rc = ctrl_param_offset_correction_mode(data, ¶m); + break; + case VL53L1_OPTICALCENTER_PAR: + rc = ctrl_param_optical_center(data, ¶m); + break; + case VL53L1_DMAXREFLECTANCE_PAR: + rc = ctrl_param_dmax_reflectance(data, ¶m); + break; + case VL53L1_DMAXMODE_PAR: + rc = ctrl_param_dmax_mode(data, ¶m); + break; + case VL53L1_TUNING_PAR: + rc = ctrl_param_tuning(data, ¶m); + break; + case VL53L1_SMUDGECORRECTIONMODE_PAR: + rc = ctrl_param_smudge_correction_mode(data, ¶m); + break; + case VL53L1_ISXTALKVALUECHANGED_PAR: + rc = ctrl_param_is_xtalk_value_changed(data, ¶m); + break; + default: + vl53l1_errmsg("unknown or unsupported %d\n", param.name); + rc = -EINVAL; + } + /* copy back (status at least ) to user */ + if (param.is_read && rc == 0) { + rc2 = copy_to_user(p, ¶m, sizeof(param)); + if (rc2) { + rc = -EFAULT; /* kill prev status if that fail */ + vl53l1_errmsg("copy to user fail %d\n", rc); + } + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +/** + * implement set/get roi ioctl + * @param data device + * @param p user space ioctl arg ptr + * @return 0 on success <0 errno code + * @li -EINVAL invalid number of roi + * @li -EBUSY when trying to set roi while ranging + * @li -EFAULT if cpy to/fm user fail for requested number of roi + */ +static int ctrl_roi(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + int roi_cnt; + struct stmvl53l1_roi_full_t rois; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* copy fixed part of args at first */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[0])); + if (rc) { + rc = -EFAULT; + goto done; + } + /* check no of roi limit is ok */ + roi_cnt = rois.roi_cfg.NumberOfRoi; + if (roi_cnt > VL53L1_MAX_USER_ZONES) { + vl53l1_errmsg("invalid roi spec cnt=%d > %d", + rois.roi_cfg.NumberOfRoi, + VL53L1_MAX_USER_ZONES); + rc = -EINVAL; + goto done; + } + + if (rois.is_read) { + int cpy_size; + + roi_cnt = MIN(rois.roi_cfg.NumberOfRoi, + data->roi_cfg.NumberOfRoi); + cpy_size = offsetof(VL53L1_RoiConfig_t, UserRois[roi_cnt]); + /* copy from local to user only effective part requested */ + rc = copy_to_user(&((struct stmvl53l1_roi_full_t *)p)->roi_cfg, + &data->roi_cfg, cpy_size); + vl53l1_dbgmsg("return %d of %d\n", roi_cnt, + data->roi_cfg.NumberOfRoi); + } else { + /* SET check cnt roi is ok */ + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set roi while ranging\n"); + goto done; + } + /* get full data that required from user */ + rc = copy_from_user(&rois, p, + offsetof(struct stmvl53l1_roi_full_t, + roi_cfg.UserRois[roi_cnt])); + if (rc) { + vl53l1_errmsg("get %d roi fm user fail", roi_cnt); + rc = -EFAULT; + goto done; + } + dump_roi(data->roi_cfg.UserRois, data->roi_cfg.NumberOfRoi); + /* we may ask ll driver to check but check is mode dependent + * and so we could get erroneous error back + */ + memcpy(&data->roi_cfg, &rois.roi_cfg, sizeof(data->roi_cfg)); + } +done: + mutex_unlock(&data->work_mutex); + return rc; +} + +static int ctrl_autonomous_config(struct stmvl53l1_data *data, void __user *p) +{ + int rc = 0; + struct stmvl53l1_autonomous_config_t full; + + mutex_lock(&data->work_mutex); + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + /* first copy all data */ + rc = copy_from_user(&full, p, sizeof(full)); + if (rc) { + rc = -EFAULT; + goto done; + } + + if (full.is_read) { + full.pollingTimeInMs = data->auto_pollingTimeInMs; + full.config = data->auto_config; + rc = copy_to_user(p, &full, sizeof(full)); + if (rc) + rc = -EFAULT; + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't change config while ranging\n"); + goto done; + } + data->auto_pollingTimeInMs = full.pollingTimeInMs; + data->auto_config = full.config; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_calibration_data(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_calibration_data_t calib; + int data_offset = offsetof(struct stmvl53l1_ioctl_calibration_data_t, + data); + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(&calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib.is_read) { + memset(&calib.data, 0, sizeof(calib.data)); + rc = VL53L1_GetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + goto done; + } + rc = copy_to_user(p + data_offset, &calib.data, + sizeof(calib.data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib.data, p + data_offset, + sizeof(calib.data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetCalibrationData(&data->stdev, &calib.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetCalibrationData fail %d", rc); + rc = store_last_error(data, rc); + } + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_zone_calibration_data(struct stmvl53l1_data *data, + void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_zone_calibration_data_t *calib; + int data_offset = + offsetof(struct stmvl53l1_ioctl_zone_calibration_data_t, data); + + mutex_lock(&data->work_mutex); + + calib = &data->calib; + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + rc = copy_from_user(calib, p, data_offset); + if (rc) { + vl53l1_errmsg("fail to detect read or write %d", rc); + rc = -EFAULT; + goto done; + } + + if (calib->is_read) { + memset(&calib->data, 0, sizeof(calib->data)); + rc = VL53L1_GetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_GetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + calib->data.id = data->current_roi_id; + rc = copy_to_user(p + data_offset, &calib->data, + sizeof(calib->data)); + } else { + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't set calib data while ranging\n"); + goto done; + } + rc = copy_from_user(&calib->data, p + data_offset, + sizeof(calib->data)); + if (rc) { + vl53l1_errmsg("fail to copy calib data"); + rc = -EFAULT; + goto done; + } + rc = VL53L1_SetZoneCalibrationData(&data->stdev, + &calib->data.data); + if (rc) { + vl53l1_errmsg("VL53L1_SetZoneCalibrationData fail %d", + rc); + rc = store_last_error(data, rc); + goto done; + } + data->current_roi_id = calib->data.id; + } + +done: + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int ctrl_perform_calibration_ref_spad_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = VL53L1_PerformRefSpadManagement(&data->stdev); + + if (rc) { + vl53l1_errmsg("VL53L1_PerformRefSpadManagement fail => %d", rc); + rc = store_last_error(data, rc); + } + + return rc; +} + +static int ctrl_perform_calibration_crosstalk_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc = 0; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformXTalkCalibration(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_PerformXTalkCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_zone_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* first sanity check */ + if (calib->param1 != VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) { + vl53l1_errmsg("invalid param1"); + rc = -EINVAL; + goto done; + } + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* set mode to multi zone to allow roi settings */ + rc = VL53L1_SetPresetMode(&data->stdev, + VL53L1_PRESETMODE_MULTIZONES_SCANNING); + if (rc) { + vl53l1_errmsg("VL53L1_SetPresetMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* setup roi */ + rc = VL53L1_SetROI(&data->stdev, &data->roi_cfg); + if (rc) { + vl53l1_errmsg("VL53L1_SetROI fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + + /* save roi hash for later use */ + data->current_roi_id = stmvl53l1_compute_hash(&data->roi_cfg); + +done: + return rc; +} + +static int ctrl_perform_calibration_offset_lock(struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* for legacy purpose we still support mz */ + if (calib->param1 == VL53L1_OFFSETCALIBRATIONMODE_MULTI_ZONE) + return ctrl_perform_zone_calibration_offset_lock(data, calib); + + /* setup offset calibration mode */ + rc = VL53L1_SetOffsetCalibrationMode(&data->stdev, calib->param1); + if (rc) { + vl53l1_errmsg("VL53L1_SetOffsetCalibrationMode fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + rc = VL53L1_PerformOffsetCalibration(&data->stdev, calib->param2, + calib->param3); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg("VL53L1_PerformOffsetCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_simple_calibration_offset_lock( + struct stmvl53l1_data *data, + struct stmvl53l1_ioctl_perform_calibration_t *calib) +{ + int rc; + + /* finally perform calibration */ + /* allow delay add after stop in VL53L1_run__calibration */ + data->is_delay_allowed = 1; + + rc = stmvl53l1_sendparams(data); + if (rc) + goto done; + + rc = VL53L1_PerformOffsetSimpleCalibration(&data->stdev, calib->param1); + data->is_delay_allowed = 0; + if (rc) { + vl53l1_errmsg( + "VL53L1_PerformOffsetSimpleCalibration fail => %d", rc); + rc = store_last_error(data, rc); + } + +done: + return rc; +} + +static int ctrl_perform_calibration(struct stmvl53l1_data *data, void __user *p) +{ + int rc; + struct stmvl53l1_ioctl_perform_calibration_t calib; + + mutex_lock(&data->work_mutex); + + if (data->is_device_remove) { + rc = -ENODEV; + goto done; + } + data->is_calibrating = true; + rc = copy_from_user(&calib, p, sizeof(calib)); + if (rc) { + rc = -EFAULT; + goto done; + } + if (data->enable_sensor) { + rc = -EBUSY; + vl53l1_errmsg("can't perform calibration while ranging\n"); + goto done; + } + vl53l1_info("cali power on");//songyt add + stmvl53l1_module_func_tbl.power_up(data->client_object); + + rc = reset_release(data); + if (rc) + goto done; + + rc = VL53L1_StaticInit(&data->stdev); + if (rc) { + vl53l1_errmsg("VL53L1_StaticInit fail => %d", rc); + rc = store_last_error(data, rc); + goto done; + } + + switch (calib.calibration_type) { + case VL53L1_CALIBRATION_REF_SPAD: + rc = ctrl_perform_calibration_ref_spad_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_CROSSTALK: + rc = ctrl_perform_calibration_crosstalk_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET: + rc = ctrl_perform_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_SIMPLE: + rc = ctrl_perform_simple_calibration_offset_lock(data, + &calib); + break; + case VL53L1_CALIBRATION_OFFSET_PER_ZONE: + rc = ctrl_perform_zone_calibration_offset_lock(data, + &calib); + break; + default: + rc = -EINVAL; + break; + } + + reset_hold(data); + vl53l1_info("cali power down");//songyt add + stmvl53l1_module_func_tbl.power_down(data->client_object); + +done: + data->is_calibrating = false; + data->is_first_start_done = true; + mutex_unlock(&data->work_mutex); + + return rc; +} + +static int stmvl53l1_ioctl_handler( + struct stmvl53l1_data *data, + unsigned int cmd, unsigned long arg, + void __user *p) +{ + int rc = 0; + + if (!data) + return -EINVAL; + + switch (cmd) { + + case VL53L1_IOCTL_START: + vl53l1_dbgmsg("VL53L1_IOCTL_START\n"); + rc = ctrl_start(data); + break; + + case VL53L1_IOCTL_STOP: + vl53l1_dbgmsg("VL53L1_IOCTL_STOP\n"); + rc = ctrl_stop(data); + break; + + case VL53L1_IOCTL_GETDATAS: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS\n"); */ + rc = ctrl_getdata(data, p); + break; + + case VL53L1_IOCTL_GETDATAS_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_GETDATAS_BLOCKING\n"); */ + rc = ctrl_getdata_blocking(data, p); + break; + + /* Register tool */ + case VL53L1_IOCTL_REGISTER: + vl53l1_dbgmsg("VL53L1_IOCTL_REGISTER\n"); + rc = ctrl_reg_access(data, p); + break; + + case VL53L1_IOCTL_PARAMETER: + vl53l1_dbgmsg("VL53L1_IOCTL_PARAMETER\n"); + rc = ctrl_params(data, p); + break; + + case VL53L1_IOCTL_ROI: + vl53l1_dbgmsg("VL53L1_IOCTL_ROI\n"); + rc = ctrl_roi(data, p); + break; + case VL53L1_IOCTL_MZ_DATA: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA\n"); */ + rc = ctrl_mz_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_BLOCKING\n"); */ + rc = ctrl_mz_data_blocking(data, p); + break; + case VL53L1_IOCTL_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_CALIBRATION_DATA\n"); + rc = ctrl_calibration_data(data, p); + break; + case VL53L1_IOCTL_PERFORM_CALIBRATION: + vl53l1_dbgmsg("VL53L1_IOCTL_PERFORM_CALIBRATION\n"); + rc = ctrl_perform_calibration(data, p); + break; + case VL53L1_IOCTL_AUTONOMOUS_CONFIG: + vl53l1_dbgmsg("VL53L1_IOCTL_AUTONOMOUS_CONFIG\n"); + rc = ctrl_autonomous_config(data, p); + break; + case VL53L1_IOCTL_ZONE_CALIBRATION_DATA: + vl53l1_dbgmsg("VL53L1_IOCTL_ZONE_CALIBRATION_DATA\n"); + rc = ctrl_zone_calibration_data(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL\n"); */ + rc = ctrl_mz_data_additional(data, p); + break; + case VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING: + /* vl53l1_dbgmsg("VL53L1_IOCTL_MZ_DATA_ADDITIONAL_BLOCKING\n"); + */ + rc = ctrl_mz_data_blocking_additional(data, p); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + + + +static int stmvl53l1_open(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.get(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + +static int stmvl53l1_release(struct inode *inode, struct file *file) +{ + struct stmvl53l1_data *data = container_of(file->private_data, + struct stmvl53l1_data, miscdev); + + vl53l1_dbgmsg("Start\n"); + stmvl53l1_module_func_tbl.put(data->client_object); + vl53l1_dbgmsg("End\n"); + + return 0; +} + + +/** max number or error per measure too abort */ +#define stvm531_get_max_meas_err(...) 3 +/** max number or error per stream too abort */ +#define stvm531_get_max_stream_err(...) 6 + +static void detect_xtalk_value_change(struct stmvl53l1_data *data, + VL53L1_MultiRangingData_t *meas) +{ + data->is_xtalk_value_changed = meas->HasXtalkValueChanged ? true : + data->is_xtalk_value_changed; +} + +/** + * handle data retrieval and dispatch + * + * work lock must be held + * + * called form work or interrupt thread it must be a blocable context ! + * @param data the device + */ +static void stmvl53l1_on_newdata_event(struct stmvl53l1_data *data) +{ + int rc; + VL53L1_RangingMeasurementData_t *pmsinglerange; + VL53L1_MultiRangingData_t *pmrange; + VL53L1_MultiRangingData_t *tmprange; + VL53L1_TargetRangeData_t RangeData[VL53L1_MAX_RANGE_RESULTS]; + VL53L1_RangingMeasurementData_t singledata; + long ts_msec; + int i; + + do_gettimeofday(&data->meas.comp_tv); + ts_msec = stmvl53l1_tv_dif(&data->start_tv, &data->meas.comp_tv)/1000; + + pmrange = &data->meas.multi_range_data; + tmprange = &data->meas.tmp_range_data; + pmsinglerange = &data->meas.single_range_data; + + memcpy(&singledata, pmsinglerange, + sizeof(VL53L1_RangingMeasurementData_t)); + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) + memcpy(&RangeData[i], &pmrange->RangeData[i], + sizeof(VL53L1_TargetRangeData_t)); + + data->meas.intr++; + + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + rc = VL53L1_GetRangingMeasurementData(&data->stdev, + pmsinglerange); + /* In case of VL53L1_RANGESTATUS_NONE we prefer to return + * the previous ranging values along that error status + */ + if (pmsinglerange->RangeStatus == VL53L1_RANGESTATUS_NONE) { + memcpy(pmsinglerange, &singledata, + sizeof(VL53L1_RangingMeasurementData_t)); + pmsinglerange->RangeStatus = VL53L1_RANGESTATUS_NONE; + } + break; + case VL53L1_PRESETMODE_RANGING: + case VL53L1_PRESETMODE_MULTIZONES_SCANNING: + /* IMPORTANT : during VL53L1_GetMultiRangingData() call + * work_mutex is release during ipp. This is why we use + * tmp_range_data which is not access somewhere else. When we are + * back we then copy tmp_range_data in multi_range_data. + */ + + rc = VL53L1_GetMultiRangingData(&data->stdev, + &data->meas.tmp_range_data); + + /* be sure we got VL53L1_RANGESTATUS_NONE for object 0 if we got + * invalid roi or no object. So if client read data using + * VL53L1_IOCTL_GETDATAS we got correct status. + */ + if (tmprange->RoiStatus == VL53L1_ROISTATUS_NOT_VALID || + tmprange->NumberOfObjectsFound == 0) + tmprange->RangeData[0].RangeStatus = + VL53L1_RANGESTATUS_NONE; + + memcpy(pmrange, tmprange, sizeof(VL53L1_MultiRangingData_t)); + + /* In case of VL53L1_RANGESTATUS_NONE we prefer to return + * the previous ranging values along that error status + */ + /*AmbientRate issue: Output ranging data even no target is detected + for (i = 0; i < VL53L1_MAX_RANGE_RESULTS; i++) { + if (pmrange->RangeData[i].RangeStatus == + VL53L1_RANGESTATUS_NONE) { + memcpy(&pmrange->RangeData[i], &RangeData[i], + sizeof(VL53L1_TargetRangeData_t)); + pmrange->RangeData[i].RangeStatus = + VL53L1_RANGESTATUS_NONE; + } + }*/ + + /* got histogram debug data in case user want it later on */ + if (!rc) + rc = VL53L1_GetAdditionalData(&data->stdev, + &data->meas.additional_data); + detect_xtalk_value_change(data, pmrange); + break; + default: + /* that must be some bug or data corruption stop now */ + rc = -1; + vl53l1_errmsg("unsorted mode %d=>stop\n", data->preset_mode); + _ctrl_stop(data); + } + /* check if not stopped yet + * as we may have been unlocked we must re-check + */ + if (data->enable_sensor == 0) { + vl53l1_dbgmsg("at meas #%d we got stopped\n", data->meas.cnt); + return; + } + if (rc) { + vl53l1_errmsg("VL53L1_GetRangingMeasurementData @%d %d", + __LINE__, rc); + data->meas.err_cnt++; + data->meas.err_tot++; + if (data->meas.err_cnt > stvm531_get_max_meas_err(data) || + data->meas.err_tot > stvm531_get_max_stream_err(data)) { + vl53l1_errmsg("on #%d %d err %d tot stop", + data->meas.cnt, data->meas.err_cnt, + data->meas.err_tot); + _ctrl_stop(data); + } + return; + } + + /* FIXME: remove when implemented by ll or bare driver */ + pmrange->TimeStamp = ts_msec; + pmsinglerange->TimeStamp = ts_msec; + for (i = 1; i < pmrange->NumberOfObjectsFound; i++) + pmrange->TimeStamp = ts_msec; + + data->meas.cnt++; +#if 0 + vl53l1_dbgmsg("#%3d %2d poll ts %5d status=%d obj cnt=%d\n", + data->meas.cnt, + data->meas.poll_cnt, + pmrange->TimeStamp, + pmrange->RangeData[0].RangeStatus, + pmrange->NumberOfObjectsFound); + vl53l1_dbgmsg( +"meas m#%04d i#%04d p#%04d in %d ms data range status %d range %d\n", + (int)data->meas.cnt, + (int)data->meas.intr, + (int)data->meas.poll_cnt, + (int)stmvl53l1_tv_dif(&data->meas.start_tv, + &data->meas.comp_tv)/1000, + (int)data->meas.range_data.RangeStatus, + (int)data->meas.range_data.RangeMilliMeter); +#endif + /* ready that is not always on each new data event */ + + /* mark data as valid from now */ + data->is_data_valid = true; + + /* wake up sleeping client */ + wake_up_data_waiters(data); + + /* push data to input subsys and only and make val for ioctl*/ + stmvl53l1_input_push_data(data); + stmvl53l1_insert_flush_events_lock(data); + + /* roll time now data got used */ + data->meas.start_tv = data->meas.comp_tv; + data->meas.poll_cnt = 0; + data->meas.err_cnt = 0; +} + + +/** + * * handle interrupt/pusdo irq by polling handling + * + * work lock must be held + * + * @param data driver + * @return 0 on success + */ +static int stmvl53l1_intr_process(struct stmvl53l1_data *data) +{ + uint8_t data_rdy; + int rc = 0; + struct timeval tv_now; + + if (!data->enable_sensor) + goto done; + + data->meas.poll_cnt++; + rc = VL53L1_GetMeasurementDataReady(&data->stdev, &data_rdy); + if (rc) { + vl53l1_errmsg("GetMeasurementDataReady @%d %d, fail\n", + __LINE__, rc); + /* too many successive fail => stop but do not try to do any new + * i/o + */ + goto stop_io; + } + + if (!data_rdy) { + /* FIXME this part to completely skip + * if using interrupt and sure we have + * no false interrupt to handle or no to do any timing check + */ + long poll_us; + + do_gettimeofday(&tv_now); + poll_us = stmvl53l1_tv_dif(&data->meas.start_tv, &tv_now); + if (poll_us > data->timing_budget*4) { + vl53l1_errmsg("we're polling %ld ms too long\n", + poll_us/1000); + /* fixme stop or just warn ? */ + goto stop_io; + } + /* keep trying it could be intr with no processing */ + work_dbg("intr with no data rdy"); + goto done; + } + /* we have data to handle */ + /* first irq after reset has no data so we skip it */ + if (data->is_first_irq) { + data->is_first_irq = false; + + if (data->preset_mode == + VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS) { + /* + * If VL53L1_GetRangingMeasurementData() + * is not called after + * for the first ranging measurement, + * the thresholds do not seem + * to work for ALP mode + */ + VL53L1_RangingMeasurementData_t RangingMeasurementData; + + /* printk("Test Workaround for ALP mode\n"); */ + VL53L1_GetRangingMeasurementData(&data->stdev, + &RangingMeasurementData); + } + + } else + stmvl53l1_on_newdata_event(data); + /* enable_sensor could change on event handling check again */ + if (data->enable_sensor) { + /* clear interrupt and continue ranging */ + work_dbg("intr clr"); + /* In autonomous mode, bare driver will trigger stop/start + * sequence. In that case it wall call platform delay functions. + * So allow delay in VL53L1_ClearInterruptAndStartMeasurement() + * call. + */ + data->is_delay_allowed = data->allow_hidden_start_stop; + rc = VL53L1_ClearInterruptAndStartMeasurement(&data->stdev); + data->is_delay_allowed = 0; + if (rc) { + /* go to stop but stop any new i/o for dbg */ + vl53l1_errmsg("Cltr intr restart fail %d\n", rc); + goto stop_io; + } + } +done: + return rc; +stop_io: + /* too many successive fail take action => stop but do not try to do + * any new i/o + */ + vl53l1_errmsg("GetDatardy fail stop\n"); + _ctrl_stop(data); + return rc; + +} + +static void stmvl53l1_work_handler(struct work_struct *work) +{ + struct stmvl53l1_data *data; + + data = container_of(work, struct stmvl53l1_data, dwork.work); + work_dbg("enter"); + mutex_lock(&data->work_mutex); + stmvl53l1_intr_process(data); + if (data->poll_mode && data->enable_sensor) { + /* re-sched ourself */ + schedule_delayed_work(&data->dwork, + msecs_to_jiffies(data->poll_delay_ms)); + } + mutex_unlock(&data->work_mutex); +} + +static void stmvl53l1_input_push_data_singleobject(struct stmvl53l1_data *data) +{ + struct input_dev *input = data->input_dev_ps; + VL53L1_RangingMeasurementData_t *meas = &data->meas.single_range_data; + FixPoint1616_t LimitCheckCurrent; + VL53L1_Error st = VL53L1_ERROR_NONE; + + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + vl53l1_dbgmsg("Sensor HAL in Lite ranging mode not yet updated\n"); + vl53l1_dbgmsg("******* FIXME!!! ************\n"); + + /* Do not send the events till this if fixed properly */ + return; + + input_report_abs(input, ABS_DISTANCE, (meas->RangeMilliMeter + 5) / 10); + input_report_abs(input, ABS_HAT0X, meas->TimeStamp / 1000); + input_report_abs(input, ABS_HAT0Y, (meas->TimeStamp % 1000) * 1000); + input_report_abs(input, ABS_HAT1X, meas->RangeMilliMeter); + input_report_abs(input, ABS_HAT1Y, meas->RangeStatus); + input_report_abs(input, ABS_HAT2X, meas->SignalRateRtnMegaCps); + input_report_abs(input, ABS_HAT2Y, meas->AmbientRateRtnMegaCps); + input_report_abs(input, ABS_HAT3X, meas->SigmaMilliMeter); + st = VL53L1_GetLimitCheckCurrent(&data->stdev, + VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE, &LimitCheckCurrent); + if (st == VL53L1_ERROR_NONE) + input_report_abs(input, ABS_WHEEL, LimitCheckCurrent); + input_report_abs(input, ABS_TILT_Y, meas->EffectiveSpadRtnCount); + input_report_abs(input, ABS_TOOL_WIDTH, meas->RangeQualityLevel); + + input_sync(input); +} + +static void stmvl53l1_input_push_data_multiobject(struct stmvl53l1_data *data) +{ + VL53L1_MultiRangingData_t *mmeas = &data->meas.multi_range_data; + int i; + int rc; + VL53L1_TargetRangeData_t *meas_array[4]; + VL53L1_CalibrationData_t calibration_data; + struct timeval tv; + struct input_dev *input = data->input_dev_ps; + + do_gettimeofday(&tv); + + for (i = 0; i < 4; i++) + meas_array[i] = &mmeas->RangeData[i]; + + /************************************************************* + * INPUT EVENT CODE L1/L3 Data + ABS_HAT0X Time in Sec(32) + ABS_HAT0Y Time in uSec(32) + ABS_HAT1X Obj0_Distance(16) : Obj0_Sigma(16) + ABS_HAT1Y Obj0_MinRange(16) : Obj0_MaxRange(16) + ABS_HAT2X Obj1_Distance(16) : Obj1_Sigma(16) + ABS_HAT2Y Obj1_ MinRange (16) : Obj1_ MaxRange (16) + ABS_HAT3X Obj0_SignalRate_Spad(32) + ABS_HAT3Y Obj1_SignalRate_Spad(32) + ABS_WHEEL AmbientRate(32) + ABS_BRAKE EffectiveSpadRtnCount(16):RangeStatus_1(8): + Range_status_0(8) + ABS_TILT_X XtalkChange(8) :StreamCount(8) : + NumberofObjects(2) : RoiNumber(4) : + RoiStatus(2) + ABS_TILT_Y DMAX + ABS_TOOL_WIDTH XtalkValue + ABS_DISTANCE + ABS_THROTTLE + ABS_RUDDER + ABS_MISC + ABS_VOLUME + ************************************************************/ + + rc = VL53L1_GetCalibrationData(&data->stdev, &calibration_data); + if (rc) { + //This should not happen + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + return; + } + + //ABS_HAT0X - Time in Sec(32) + + input_report_abs(input, ABS_HAT0X, tv.tv_sec); + //vl53l1_dbgmsg("ABS_HAT0X : %ld, %zu\n", tv.tv_sec, sizeof(tv.tv_sec)); + //ABS_HAT0Y - Time in uSec(32) + //REVISIT : The following code may cause loss of data due to + //8 bytes to 32 bits conversion + input_report_abs(input, ABS_HAT0Y, tv.tv_usec); + //vl53l1_dbgmsg("ABS_HAT0Y : %ld\n", tv.tv_usec); + + if (mmeas->NumberOfObjectsFound == 0) { + //ABS_TILT_X XtalkChange(8) :StreamCount(8) : + //Number of Objects(2) : RoiNumber(4) : RoiStatus(2) + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + /*vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + );*/ + + + //ABS_TILT_Y DMAX + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + //vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + //ABS_TOOL_WIDTH + input_report_abs(input, ABS_TOOL_WIDTH, + calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + //vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n", + // calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + + + input_sync(input); + return; + } + + //ABS_HAT1X - Obj0_Distance(16) : Obj0_Sigma(16) + input_report_abs(input, ABS_HAT1X, meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536)); + /*vl53l1_dbgmsg("ABS_HAT1X : 0x%X(%d:%d)\n", + meas_array[0]->RangeMilliMeter << 16 + | (meas_array[0]->SigmaMilliMeter/65536), + meas_array[0]->RangeMilliMeter, + (meas_array[0]->SigmaMilliMeter/65536));*/ + + //ABS_HAT1Y - Obj0_MinRange(16) : Obj0_MaxRange(16) + input_report_abs(input, ABS_HAT1Y, + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter); + + /*vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[0]->RangeMinMilliMeter << 16 + | meas_array[0]->RangeMaxMilliMeter, + meas_array[0]->RangeMinMilliMeter, + meas_array[0]->RangeMaxMilliMeter);*/ + + if (mmeas->NumberOfObjectsFound > 1) { + //ABS_HAT2X - Obj1_Distance(16) : Obj1_Sigma(16) + input_report_abs(input, ABS_HAT2X, + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536)); + /*vl53l1_dbgmsg("ABS_HAT2X : 0x%x(%d:%d)\n", + meas_array[1]->RangeMilliMeter << 16 + | (meas_array[1]->SigmaMilliMeter/65536), + meas_array[1]->RangeMilliMeter, + (meas_array[1]->SigmaMilliMeter/65536));*/ + + //ABS_HAT2Y - Obj1_ MinRange (16) : Obj1_ MaxRange (16) + input_report_abs(input, ABS_HAT2Y, + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter); + + /*vl53l1_dbgmsg("ABS_HAT1Y : 0x%X(%d:%d)\n", + meas_array[1]->RangeMinMilliMeter << 16 + | meas_array[1]->RangeMaxMilliMeter, + meas_array[1]->RangeMinMilliMeter, + meas_array[1]->RangeMaxMilliMeter);*/ + + } + + // ABS_HAT3X - Obj0_SignalRate_Spad(32) + input_report_abs(input, ABS_HAT3X, + meas_array[0]->SignalRateRtnMegaCps); + //vl53l1_dbgmsg("ABS_HAT3X : SignalRateRtnMegaCps_0(%d)\n", + // meas_array[0]->SignalRateRtnMegaCps); + if (mmeas->NumberOfObjectsFound > 1) { + //ABS_HAT3Y - Obj1_SignalRate_Spad(32) + input_report_abs(input, ABS_HAT3Y, + meas_array[1]->SignalRateRtnMegaCps); + // vl53l1_dbgmsg("ABS_HAT3Y : SignalRateRtnMegaCps_1(%d)\n", + // meas_array[1]->SignalRateRtnMegaCps); + } + //ABS_WHEEL - AmbientRate(32) + input_report_abs(input, ABS_WHEEL, + meas_array[0]->AmbientRateRtnMegaCps); + //vl53l1_dbgmsg("ABS_WHEEL : AmbRate = %d\n", + // meas_array[0]->AmbientRateRtnMegaCps); + + + //ABS_BRAKE - EffectiveSpadRtnCount(16):RangeStatus_3(1): + //Range_status_2(0) + input_report_abs(input, ABS_BRAKE, + mmeas->EffectiveSpadRtnCount << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus); + + /*vl53l1_dbgmsg("ABS_BRAKE : (%d):(%d):(%d)\n", + mmeas->EffectiveSpadRtnCount, + meas_array[1]->RangeStatus, + meas_array[0]->RangeStatus); + + vl53l1_dbgmsg("ABS_BRAKE : 0x%X\n", + (mmeas->EffectiveSpadRtnCount & 0xFFFF) << 16 + | ((meas_array[1]->RangeStatus) << 8) + | meas_array[0]->RangeStatus);*/ + //ABS_TILT_X XtalkChange(8) :StreamCount(8) : + //Number of Objects(2) : RoiNumber(4) : RoiStatus(2) + //On maint2 driver, the max possible range status value is 14. + //Revisit If this changes in future + input_report_abs(input, ABS_TILT_X, + (mmeas->HasXtalkValueChanged << 16) + | (mmeas->StreamCount << 8) + | ((mmeas->NumberOfObjectsFound & 0x3) << 6) + | ((mmeas->RoiNumber & 0xF) << 2) + | (mmeas->RoiStatus & 0x3)); + /*vl53l1_dbgmsg("ABS_TILT_X :(%d):(%d):(%d):(%d):(%d)\n", + mmeas->HasXtalkValueChanged, + mmeas->StreamCount, + mmeas->NumberOfObjectsFound, + mmeas->RoiNumber, + mmeas->RoiStatus + );*/ + //ABS_TILT_Y DMAX + input_report_abs(input, ABS_TILT_Y, mmeas->DmaxMilliMeter); + //vl53l1_dbgmsg("ABS_TILT_Y DMAX = %d\n", mmeas->DmaxMilliMeter); + + //ABS_TOOL_WIDTH + input_report_abs(input, ABS_TOOL_WIDTH, + calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + //vl53l1_dbgmsg("ABS_TOOL_WIDTH Xtalk = %d\n\n", + // calibration_data.customer.algo__crosstalk_compensation_plane_offset_kcps); + input_sync(input); +} + +static void stmvl53l1_input_push_data(struct stmvl53l1_data *data) +{ + /* use get data method based on active mode */ + switch (data->preset_mode) { + case VL53L1_PRESETMODE_LITE_RANGING: + case VL53L1_PRESETMODE_AUTONOMOUS: + case VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS: + stmvl53l1_input_push_data_singleobject(data); + break; + default: + /* VL53L1_PRESETMODE_RANGING: + * VL53L1_PRESETMODE_MULTIZONES_SCANNING: + */ + stmvl53l1_input_push_data_multiobject(data); + } +} + +static int stmvl53l1_input_setup(struct stmvl53l1_data *data) +{ + int rc; + struct input_dev *idev; + /* Register to Input Device */ + idev = input_allocate_device(); + if (idev == NULL) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_err; + } + /* setup all event */ + set_bit(EV_ABS, idev->evbit); + + input_set_abs_params(idev, ABS_DISTANCE, 0, 0xff, 0, 0); + + input_set_abs_params(idev, ABS_HAT0X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT0Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT1Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT2Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_HAT3Y, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_WHEEL, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_TILT_Y, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_BRAKE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TILT_X, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_TOOL_WIDTH, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_THROTTLE, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_RUDDER, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_MISC, 0, 0xffffffff, 0, 0); + + input_set_abs_params(idev, ABS_VOLUME, 0, 0xffffffff, 0, 0); + input_set_abs_params(idev, ABS_GAS, 0, 0xffffffff, 0, 0); + + idev->name = "STM VL53L1 proximity sensor"; + rc = input_register_device(idev); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_free_dev_ps; + } + /* setup drv data */ + input_set_drvdata(idev, data); + data->input_dev_ps = idev; + return 0; + + +exit_free_dev_ps: + input_free_device(data->input_dev_ps); +exit_err: + return rc; +} + +/** + * handler to be called by interface module on interrupt + * + * managed poll/irq filtering in case poll/irq can be soft forced + * and the module side still fire interrupt + * + * @param data + * @return 0 if all ok else for error + */ +int stmvl53l1_intr_handler(struct stmvl53l1_data *data) +{ + int rc; + + mutex_lock(&data->work_mutex); + + /* handle it only if if we are not stopped */ + if (data->enable_sensor) { + rc = stmvl53l1_intr_process(data); + } else { + /* it's likely race/last unhandled interrupt after + * stop. + * Such dummy irq also occured during offset and crosstalk + * calibration procedures. + */ + vl53l1_dbgmsg("got intr but not on (dummy or calibration)\n"); + rc = 0; + } + + mutex_unlock(&data->work_mutex); + return rc; +} + + +/** + * One time device setup + * + * call by bus (i2c/cci) level probe to finalize non bus related device setup + * + * @param data The device data + * @return 0 on success + */ +int stmvl53l1_setup(struct stmvl53l1_data *data) +{ + int rc = 0; + VL53L1_DeviceInfo_t dev_info; + + vl53l1_dbgmsg("Enter\n"); + + /* acquire an id */ + data->id = allocate_dev_id(); + if (data->id < 0) { + vl53l1_errmsg("too many device already created"); + return -1; + } + vl53l1_dbgmsg("Dev id %d is @%p\n", data->id, data); + stmvl53l1_dev_table[data->id] = data; + + /* init mutex */ + /* mutex_init(&data->update_lock); */ + mutex_init(&data->work_mutex); + + /* init work handler */ + INIT_DELAYED_WORK(&data->dwork, stmvl53l1_work_handler); + + /* init ipp side */ + stmvl53l1_ipp_setup(data); + + data->force_device_on_en = force_device_on_en_default; + data->reset_state = 1; + data->is_calibrating = false; + data->last_error = VL53L1_ERROR_NONE; + data->is_device_remove = false; + + rc = stmvl53l1_module_func_tbl.power_up(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error rc %d\n", __LINE__, rc); + goto exit_ipp_cleanup; + } + rc = reset_release(data); + if (rc) + goto exit_ipp_cleanup; + + rc = stmvl53l1_input_setup(data); + if (rc) + goto exit_ipp_cleanup; + + /* init blocking ioctl stuff */ + INIT_LIST_HEAD(&data->simple_data_reader_list); + INIT_LIST_HEAD(&data->mz_data_reader_list); + init_waitqueue_head(&data->waiter_for_data); + data->is_data_valid = false; + + /* Register sysfs hooks under input dev */ + rc = sysfs_create_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + if (rc) { + rc = -ENOMEM; + vl53l1_errmsg("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + + data->enable_sensor = 0; + + data->poll_delay_ms = STMVL53L1_CFG_POLL_DELAY_MS; + data->timing_budget = STMVL53L1_CFG_TIMING_BUDGET_US; + data->preset_mode = STMVL53L1_CFG_DEFAULT_MODE; + //songyt add default range roi + if(data->preset_mode == VL53L1_PRESETMODE_MULTIZONES_SCANNING + /*|| data->preset_mode == VL53L1_PRESETMODE_RANGING*/){ + data->roi_cfg.NumberOfRoi = 4; + data->roi_cfg.UserRois[0].TopLeftX = 0; + data->roi_cfg.UserRois[0].TopLeftY = 15; + data->roi_cfg.UserRois[0].BotRightX = 7; + data->roi_cfg.UserRois[0].BotRightY = 8; + + data->roi_cfg.UserRois[1].TopLeftX = 8; + data->roi_cfg.UserRois[1].TopLeftY = 15; + data->roi_cfg.UserRois[1].BotRightX = 15; + data->roi_cfg.UserRois[1].BotRightY = 8; + + data->roi_cfg.UserRois[2].TopLeftX = 0; + data->roi_cfg.UserRois[2].TopLeftY = 7; + data->roi_cfg.UserRois[2].BotRightX = 7; + data->roi_cfg.UserRois[2].BotRightY = 0; + + data->roi_cfg.UserRois[3].TopLeftX = 8; + data->roi_cfg.UserRois[3].TopLeftY = 7; + data->roi_cfg.UserRois[3].BotRightX = 15; + data->roi_cfg.UserRois[3].BotRightY = 0; + }else{ + data->roi_cfg.NumberOfRoi = 0; + } + //end + data->distance_mode = STMVL53L1_CFG_DEFAULT_DISTANCE_MODE; + data->crosstalk_enable = STMVL53L1_CFG_DEFAULT_CROSSTALK_ENABLE; + data->output_mode = STMVL53L1_CFG_DEFAULT_OUTPUT_MODE; + data->offset_correction_mode = + STMVL53L1_CFG_DEFAULT_OFFSET_CORRECTION_MODE; + stmvl53l1_setup_auto_config(data); + data->dmax_mode = STMVL53L1_CFG_DEFAULT_DMAX_MODE; + data->smudge_correction_mode = + STMVL53L1_CFG_DEFAULT_SMUDGE_CORRECTION_MODE; + data->current_roi_id = 0; + data->is_xtalk_value_changed = false; + + data->is_delay_allowed = true; + /* need to be done once */ + rc = VL53L1_DataInit(&data->stdev); + data->is_delay_allowed = false; + if (rc) { + vl53l1_errmsg("VL53L1_DataInit %d\n", rc); + goto exit_unregister_dev_ps; + } + + rc = VL53L1_GetDeviceInfo(&data->stdev, &dev_info); + if (rc) { + vl53l1_errmsg("VL53L1_GetDeviceInfo %d\n", rc); + goto exit_unregister_dev_ps; + } + vl53l1_errmsg("device name %s\ntype %s\n", + dev_info.Name, dev_info.Type); + + /* get managed data here */ + rc = VL53L1_GetDmaxReflectance(&data->stdev, &data->dmax_reflectance); + if (rc) { + vl53l1_errmsg("VL53L1_GetDmaxReflectance %d\n", rc); + goto exit_unregister_dev_ps; + } + rc = VL53L1_GetOpticalCenter(&data->stdev, &data->optical_offset_x, + &data->optical_offset_y); + if (rc) { + vl53l1_errmsg("VL53L1_GetOpticalCenter %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* set tuning from stmvl53l1_tunings.h */ + rc = setup_tunings(data); + if (rc) { + vl53l1_errmsg("setup_tunings %d\n", rc); + goto exit_unregister_dev_ps; + } + + /* if working in interrupt ask intr to enable and hook the handler */ + data->poll_mode = 0; + rc = stmvl53l1_module_func_tbl.start_intr(data->client_object, + &data->poll_mode); + if (rc < 0) { + vl53l1_errmsg("can't start no intr\n"); + goto exit_unregister_dev_ps; + } + + data->is_first_irq = true; + data->is_first_start_done = false; + data->is_delay_allowed = false; + + /* to register as a misc device */ + data->miscdev.minor = MISC_DYNAMIC_MINOR; + /* multiple dev name use id in name but 1st */ + if (data->id == 0) + strcpy(data->name, VL53L1_MISC_DEV_NAME); + else + sprintf(data->name, "%s%d", VL53L1_MISC_DEV_NAME, data->id); + + data->miscdev.name = data->name; + data->miscdev.fops = &stmvl53l1_ranging_fops; + vl53l1_errmsg("Misc device registration name:%s\n", data->miscdev.name); + rc = misc_register(&data->miscdev); + if (rc != 0) { + vl53l1_errmsg("misc dev reg fail\n"); + goto exit_unregister_dev_ps; + } + /* bring back device under reset */ + reset_hold(data); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error1 power_down rc %d\n", __LINE__, rc); + } + stmvl53l1_disable_pinctrl(); + return 0; + +exit_unregister_dev_ps: + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + input_unregister_device(data->input_dev_ps); +exit_ipp_cleanup: + stmvl53l1_ipp_cleanup(data); + rc = stmvl53l1_module_func_tbl.power_down(data->client_object); + if (rc) { + vl53l1_errmsg("%d,error2 power_down rc %d\n", __LINE__, rc); + } + + return rc; +} + + +void stmvl53l1_cleanup(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("enter\n"); + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + if (data->input_dev_ps) { + vl53l1_dbgmsg("to remove sysfs group\n"); + sysfs_remove_group(&data->input_dev_ps->dev.kobj, + &stmvl53l1_attr_group); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_calib_data_attr); + sysfs_remove_bin_file(&data->input_dev_ps->dev.kobj, + &stmvl53l1_zone_calib_data_attr); + + vl53l1_dbgmsg("to unregister input dev\n"); + input_unregister_device(data->input_dev_ps); + } + + if (!IS_ERR(data->miscdev.this_device) && + data->miscdev.this_device != NULL) { + vl53l1_dbgmsg("to unregister misc dev\n"); + misc_deregister(&data->miscdev); + } + stmvl53l1_ipp_cleanup(data); + /* be sure device is put under reset */ + data->force_device_on_en = false; + reset_hold(data); + stmvl53l1_module_func_tbl.power_down(data->client_object); + vl53l1_dbgmsg("done\n"); + deallocate_dev_id(data->id); + data->is_device_remove = true; +} + +#ifdef CONFIG_PM_SLEEP +void stmvl53l1_pm_suspend_stop(struct stmvl53l1_data *data) +{ + int rc; + + vl53l1_dbgmsg("Enter\n"); + + rc = _ctrl_stop(data); + if (rc < 0) + vl53l1_errmsg("stop failed %d aborting anyway\n", rc); + + vl53l1_dbgmsg("done\n"); +} +#endif + +static long stmvl53l1_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + struct stmvl53l1_data *data = + container_of(file->private_data, + struct stmvl53l1_data, miscdev); + ret = stmvl53l1_ioctl_handler(data, cmd, arg, (void __user *)arg); + return ret; +} + +static int __init stmvl53l1_init(void) +{ + int rc = 0; + rc = stmvl53l1_ipp_init(); + vl53l1_dbgmsg("Enter,rc=%d\n",rc); + if (rc){ + stmvl53l1_ipp_exit(); + return rc; + } + ipp_inited = true; + return rc; +} + +static int __init stmvl53l1_late_init(void) +{ + int rc = 0; + + vl53l1_dbgmsg("Enter,rc=%d\n",rc); + rc = 0; + if (rc) + goto done; + /* i2c/cci client specific init function */ + rc = stmvl53l1_module_func_tbl.init(); + if (rc){ + if(ipp_inited) + stmvl53l1_ipp_exit(); + ipp_inited = false; + } +done: + vl53l1_dbgmsg("End %d\n", rc); + + return rc; +} + +static void __exit stmvl53l1_exit(void) +{ + vl53l1_dbgmsg("Enter\n"); + stmvl53l1_module_func_tbl.deinit(NULL); + if (stmvl53l1_module_func_tbl.clean_up != NULL) + stmvl53l1_module_func_tbl.clean_up(); + if(ipp_inited) + stmvl53l1_ipp_exit(); + vl53l1_dbgmsg("End\n"); +} + +/* MODULE_DEVICE_TABLE(i2c, stmvl53l1_id); */ +MODULE_AUTHOR("STMicroelectronics Imaging Division"); +MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(stmvl53l1_init); +late_initcall(stmvl53l1_late_init); +module_exit(stmvl53l1_exit); diff --git a/drivers/oneplus/vl53L1/stmvl53l1_tunings.h b/drivers/oneplus/vl53L1/stmvl53l1_tunings.h new file mode 100755 index 0000000000000000000000000000000000000000..6a92a3b2c3c23040e0495a3781740004237c5b33 --- /dev/null +++ b/drivers/oneplus/vl53L1/stmvl53l1_tunings.h @@ -0,0 +1,42 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/* + * THIS IS A GENERATED FILE + */ + +#ifndef STMVL53L1_TUNINGS_H +#define STMVL53L1_TUNINGS_H + +static const int tunings[][2] = { +}; + +#endif /* STMVL53L1_TUNINGS_H */ diff --git a/drivers/oneplus/vl53L1/vl53l1_platform.h b/drivers/oneplus/vl53L1/vl53l1_platform.h new file mode 100755 index 0000000000000000000000000000000000000000..742e25aa66dadfd71d913e0bc851ff94e3de5cf5 --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform.h @@ -0,0 +1,444 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_H_ +#define _VL53L1_PLATFORM_H_ + +#include "vl53l1_ll_def.h" +#include "vl53l1_platform_log.h" + +#define VL53L1_IPP_API +#include "vl53l1_platform_ipp_imports.h" +#include "vl53l1_platform_user_data.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform.h + * + * @brief All end user OS/platform/application porting + */ + + + +/** + * @brief Initialise platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] comms_type : selects between I2C and SPI + * @param[in] comms_speed_khz : unsigned short containing the I2C speed in kHz + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsInitialise( + VL53L1_Dev_t *pdev, + uint8_t comms_type, + uint16_t comms_speed_khz); + + +/** + * @brief Close platform comms. + * + * @param[in] pdev : pointer to device structure (device handle) + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_CommsClose( + VL53L1_Dev_t *pdev); + + +/** + * @brief Writes the supplied byte buffer to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] pdata : pointer to uint8_t (byte) buffer containing the data + * to be written + * @param[in] count : number of bytes in the supplied byte buffer + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WriteMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Reads the requested number of bytes from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to the uint8_t (byte) buffer to store read + * data + * @param[in] count : number of bytes to read + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ReadMulti( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata, + uint32_t count); + + +/** + * @brief Writes a single byte to the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint8_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t data); + + +/** + * @brief Writes a single word (16-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uin16_t data value write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t data); + + +/** + * @brief Writes a single dword (32-bit unsigned) to the device + * + * Manages the big-endian nature of the device register map + * (first byte written is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[in] data : uint32_t data value to write + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WrDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t data); + + + +/** + * @brief Reads a single byte from the device + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index + * @param[out] pdata : pointer to uint8_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + * + */ + +VL53L1_Error VL53L1_RdByte( + VL53L1_Dev_t *pdev, + uint16_t index, + uint8_t *pdata); + + +/** + * @brief Reads a single word (16-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint16_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint16_t *pdata); + + +/** + * @brief Reads a single dword (32-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] index : uint16_t register index value + * @param[out] pdata : pointer to uint32_t data value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_RdDWord( + VL53L1_Dev_t *pdev, + uint16_t index, + uint32_t *pdata); + + + +/** + * @brief Implements a programmable wait in us + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_us : integer wait in micro seconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitUs( + VL53L1_Dev_t *pdev, + int32_t wait_us); + + +/** + * @brief Implements a programmable wait in ms + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] wait_ms : integer wait in milliseconds + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitMs( + VL53L1_Dev_t *pdev, + int32_t wait_ms); + + +/** + * @brief Get the frequency of the timer used for ranging results time stamps + * + * @param[out] ptimer_freq_hz : pointer for timer frequency + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerFrequency(int32_t *ptimer_freq_hz); + +/** + * @brief Get the timer value in units of timer_freq_hz (see + * VL53L1_get_timestamp_frequency()) + * + * @param[out] ptimer_count : pointer for timer count value + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTimerValue(int32_t *ptimer_count); + + +/** + * @brief Set the mode of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param mode - an identifier specifying the requested mode - defined per + * platform + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetMode(uint8_t pin, uint8_t mode); + + +/** + * @brief Set the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param value - a value to set on the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioSetValue(uint8_t pin, uint8_t value); + + +/** + * @brief Get the value of a specified GPIO pin + * + * @param pin - an identifier specifying the pin being modified - defined per + * platform + * + * @param pvalue - a value retrieved from the GPIO pin - typically 0 or 1 + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioGetValue(uint8_t pin, uint8_t *pvalue); + + +/** + * @brief Sets and clears the XShutdown pin on the Ewok + * + * @param value - the value for xshutdown - 0 = in reset, 1 = operational + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioXshutdown(uint8_t value); + + +/** + * @brief Sets and clears the Comms Mode pin (NCS) on the Ewok + * + * @param value - the value for comms select - 0 = I2C, 1 = SPI + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioCommsSelect(uint8_t value); + + +/** + * @brief Enables and disables the power to the Ewok module + * + * @param value - the state of the power supply - 0 = power off, 1 = power on + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioPowerEnable(uint8_t value); + +/** + * @brief Enables callbacks to the supplied funtion pointer when Ewok interrupts + * ocurr + * + * @param function - a function callback supplies by the caller, for interrupt + * notification + * @param edge_type - falling edge or rising edge interrupt detection + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptEnable(void (*function)(void), + uint8_t edge_type); + + +/** + * @brief Disables the callback on Ewok interrupts + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GpioInterruptDisable(void); + + +/* + * @brief Gets current system tick count in [ms] + * + * @return time_ms : current time in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_GetTickCount( + uint32_t *ptime_ms); + + +/** + * @brief Register "wait for value" polling routine + * + * Port of the V2WReg Script function WaitValueMaskEx() + * + * @param[in] pdev : pointer to device structure (device handle) + * @param[in] timeout_ms : timeout in [ms] + * @param[in] index : uint16_t register index value + * @param[in] value : value to wait for + * @param[in] mask : mask to be applied before comparison with value + * @param[in] poll_delay_ms : polling delay been each read transaction in [ms] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_WaitValueMaskEx( + VL53L1_Dev_t *pdev, + uint32_t timeout_ms, + uint16_t index, + uint8_t value, + uint8_t mask, + uint32_t poll_delay_ms); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/vl53l1_platform_ipp.h b/drivers/oneplus/vl53L1/vl53l1_platform_ipp.h new file mode 100755 index 0000000000000000000000000000000000000000..b187272fe7b335bc81064c928eb98722b71247bd --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform_ipp.h @@ -0,0 +1,188 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_IPP_H_ +#define _VL53L1_PLATFORM_IPP_H_ + +#include "vl53l1_ll_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * @file vl53l1_platform_ipp.h + * + * @brief EwokPlus25 IPP Wrapper Functions + */ + +/** + * @brief IPP Wrapper call for histogram post processing + * + * + * @param[in] Dev : Device handle + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] ppost_cfg : VL53L1_hist_post_process_config_t + * @param[in] pbins : Input histogram raw bin data + * @param[in] pxtalk : Cross talk histogram data + * @param[out] presults : Output VL53L1_range_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_process_data( + VL53L1_DEV Dev, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_hist_post_process_config_t *ppost_cfg, + VL53L1_histogram_bin_data_t *pbins, + VL53L1_xtalk_histogram_data_t *pxtalk, + VL53L1_range_results_t *presults); + + +/** + * @brief IPP Wrapper call for histogram ambient dmax calc + * + * The target reflectance in percent for the DMAX calculation + * is set by target_reflectance input + * + * The fixed point format is 7.2 + * + * @param[in] Dev : Device handle + * @param[in] target_reflectance : target reflectance to report ambient DMAX + * Percentage in 7.2 fixed point format + * @param[in] pdmax_cal : DMAX calibration data + * @param[in] pdmax_cfg : DMAX configuration data + * @param[in] pbins : Input histogram raw bin data + * @param[out] pambient_dmax_mm : Output ambient DMAX distance in [mm] + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_ambient_dmax( + VL53L1_DEV Dev, + uint16_t target_reflectance, + VL53L1_dmax_calibration_data_t *pdmax_cal, + VL53L1_hist_gen3_dmax_config_t *pdmax_cfg, + VL53L1_histogram_bin_data_t *pbins, + int16_t *pambient_dmax_mm); + + +/** + * @brief IPP Wrapper call for xtalk calibration post processing + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_ranges : Input VL53L1_xtalk_range_results_t + * Must contain 5 ranges, 4 quadrants + 1 + * full FoV + * @param[out] pxtalk_shape : Output normalised Cross talk histogram + * shape + * @param[out] pxtalk_cal : Output VL53L1_xtalk_calibration_results_t + * structure + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_xtalk_calibration_process_data( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_ranges, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_xtalk_calibration_results_t *pxtalk_cal); + + +/** + * @brief IPP Wrapper call for applying histogram xtalk correction + * + * @param[in] Dev : Device handle + * @param[in] pcustomer : Pointer to input customer data structure + * @param[in] pdyn_cfg : Pointer to input dynamic parameters + * structure + * @param[in] pxtalk_shape : Pointer to input normalised xtalk + * histogram shape + * @param[in] pip_hist_data : Pointer to input histogram data struct + * @param[out] pop_hist_data : Pointer to output xtalk corrected + * histogram data struct + * @param[out] pxtalk_count_data : Pointer to output xtalk histogram + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_hist_xtalk_correction( + VL53L1_DEV Dev, + VL53L1_customer_nvm_managed_t *pcustomer, + VL53L1_dynamic_config_t *pdyn_cfg, + VL53L1_xtalk_histogram_data_t *pxtalk_shape, + VL53L1_histogram_bin_data_t *pip_hist_data, + VL53L1_histogram_bin_data_t *pop_hist_data, + VL53L1_histogram_bin_data_t *pxtalk_count_data); + +/** + * @brief IPP Wrapper call for Generating Xtalk data from dual reflectance + * histogram data + * + * @param[in] Dev : Device handle + * @param[in] pxtalk_results : Pointer to xtalk_results structure + * containing dual reflectance + * histogram data + * @param[in] expected_target_distance_mm : User input of true target distance + * @param[in] higher_reflectance : User input detailing which + * histogram data 1 or 2 has the + * highest reflectance. + * @param[out] pxtalk_avg_samples : Pointer to output xtalk histogram + * data + * + * @return VL53L1_ERROR_NONE Success + * @return "Other error code" See ::VL53L1_Error + */ + +VL53L1_Error VL53L1_ipp_generate_dual_reflectance_xtalk_samples( + VL53L1_DEV Dev, + VL53L1_xtalk_range_results_t *pxtalk_results, + uint16_t expected_target_distance_mm, + uint8_t higher_reflectance, + VL53L1_histogram_bin_data_t *pxtalk_avg_samples); + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/vl53l1_platform_ipp_imports.h b/drivers/oneplus/vl53L1/vl53l1_platform_ipp_imports.h new file mode 100755 index 0000000000000000000000000000000000000000..b7700a9190898ad93274c52b6a43b4432d9422bc --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform_ipp_imports.h @@ -0,0 +1,36 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_IPP_IMPORTS_H_ +#define _VL53L1_PLATFORM_IPP_IMPORTS_H_ + +#endif diff --git a/drivers/oneplus/vl53L1/vl53l1_platform_log.h b/drivers/oneplus/vl53L1/vl53l1_platform_log.h new file mode 100755 index 0000000000000000000000000000000000000000..357e0abb97731cb62a6ce4e4dbbad2627b7b0b76 --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform_log.h @@ -0,0 +1,177 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file vl53l1_platform_log.h + * + * @brief EwokPlus25 platform logging function definition + */ + + +#ifndef _VL53L1_PLATFORM_LOG_H_ +#define _VL53L1_PLATFORM_LOG_H_ + +#include + +#ifdef VL53L1_LOG_ENABLE + #include "vl53l1_platform_user_config.h" + + #ifdef _MSC_VER + # define EWOKPLUS_EXPORTS __declspec(dllexport) + #else + # define EWOKPLUS_EXPORTS + #endif + + #include "vl53l1_types.h" + + #ifdef __cplusplus + extern "C" { + #endif + + #include + + /** + * @brief Set the level, output and specific functions for module + * logging. + * + * + * @param filename - full path of output log file, NULL for print to + * stdout + * + * @param modules - Module or None or All to trace + * VL53L1_TRACE_MODULE_NONE + * VL53L1_TRACE_MODULE_API + * VL53L1_TRACE_MODULE_CORE + * VL53L1_TRACE_MODULE_TUNING + * VL53L1_TRACE_MODULE_CHARACTERISATION + * VL53L1_TRACE_MODULE_PLATFORM + * VL53L1_TRACE_MODULE_ALL + * + * @param level - trace level + * VL53L1_TRACE_LEVEL_NONE + * VL53L1_TRACE_LEVEL_ERRORS + * VL53L1_TRACE_LEVEL_WARNING + * VL53L1_TRACE_LEVEL_INFO + * VL53L1_TRACE_LEVEL_DEBUG + * VL53L1_TRACE_LEVEL_ALL + * VL53L1_TRACE_LEVEL_IGNORE + * + * @param functions - function level to trace; + * VL53L1_TRACE_FUNCTION_NONE + * VL53L1_TRACE_FUNCTION_I2C + * VL53L1_TRACE_FUNCTION_ALL + * + * @return status - always VL53L1_ERROR_NONE + * + */ + + #define VL53L1_TRACE_LEVEL_NONE 0x00000000 + #define VL53L1_TRACE_LEVEL_ERRORS 0x00000001 + #define VL53L1_TRACE_LEVEL_WARNING 0x00000002 + #define VL53L1_TRACE_LEVEL_INFO 0x00000004 + #define VL53L1_TRACE_LEVEL_DEBUG 0x00000008 + #define VL53L1_TRACE_LEVEL_ALL 0x00000010 + #define VL53L1_TRACE_LEVEL_IGNORE 0x00000020 + + #define VL53L1_TRACE_FUNCTION_NONE 0x00000000 + #define VL53L1_TRACE_FUNCTION_I2C 0x00000001 + #define VL53L1_TRACE_FUNCTION_ALL 0x7fffffff + + #define VL53L1_TRACE_MODULE_NONE 0x00000000 + #define VL53L1_TRACE_MODULE_API 0x00000001 + #define VL53L1_TRACE_MODULE_CORE 0x00000002 + #define VL53L1_TRACE_MODULE_PROTECTED 0x00000004 + #define VL53L1_TRACE_MODULE_HISTOGRAM 0x00000008 + #define VL53L1_TRACE_MODULE_REGISTERS 0x00000010 + #define VL53L1_TRACE_MODULE_PLATFORM 0x00000020 + #define VL53L1_TRACE_MODULE_NVM 0x00000040 + #define VL53L1_TRACE_MODULE_CALIBRATION_DATA 0x00000080 + #define VL53L1_TRACE_MODULE_NVM_DATA 0x00000100 + #define VL53L1_TRACE_MODULE_HISTOGRAM_DATA 0x00000200 + #define VL53L1_TRACE_MODULE_RANGE_RESULTS_DATA 0x00000400 + #define VL53L1_TRACE_MODULE_XTALK_DATA 0x00000800 + #define VL53L1_TRACE_MODULE_OFFSET_DATA 0x00001000 + #define VL53L1_TRACE_MODULE_DATA_INIT 0x00002000 + #define VL53L1_TRACE_MODULE_REF_SPAD_CHAR 0x00004000 + #define VL53L1_TRACE_MODULE_SPAD_RATE_MAP 0x00008000 + #ifdef PAL_EXTENDED + #define VL53L1_TRACE_MODULE_SPAD 0x01000000 + #define VL53L1_TRACE_MODULE_FMT 0x02000000 + #define VL53L1_TRACE_MODULE_UTILS 0x04000000 + #define VL53L1_TRACE_MODULE_BENCH_FUNCS 0x08000000 + #endif + #define VL53L1_TRACE_MODULE_CUSTOMER_API 0x40000000 + #define VL53L1_TRACE_MODULE_ALL 0x7fffffff + + extern void log_trace_print(uint32_t module, uint32_t level, + uint32_t function, const char *format, ...); + + #define _LOG_TRACE_PRINT_FMT(module, level, function, format, ...) \ + log_trace_print(module, level, function, \ + KERN_INFO " " format, ##__VA_ARGS__) + #define _LOG_TRACE_PRINT(module, level, function, ...) \ + _LOG_TRACE_PRINT_FMT(module, level, function, ##__VA_ARGS__) + #define _LOG_FUNCTION_START(module, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s "fmt"\n", __func__, ##__VA_ARGS__) + #define _LOG_FUNCTION_END(module, status, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d\n", __func__, status) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) \ + log_trace_print(module, VL53L1_TRACE_LEVEL_NONE, \ + VL53L1_TRACE_FUNCTION_ALL, \ + KERN_INFO " %s %d"fmt"\n", __func__, status, \ + ##__VA_ARGS__) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + + #define _LOG_STRING_BUFFER(x) char x[VL53L1_MAX_STRING_LENGTH] + + #ifdef __cplusplus + } + #endif + +#else /* VL53L1_LOG_ENABLE - no logging */ + #include "vl53l1_platform_user_config.h" + + #define _LOG_TRACE_PRINT(module, level, function, ...) + #define _LOG_FUNCTION_START(module, fmt, ...) + #define _LOG_FUNCTION_END(module, status, ...) + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) + #define _LOG_GET_TRACE_FUNCTIONS() 0 + #define _LOG_SET_TRACE_FUNCTIONS(functions) + #define _LOG_STRING_BUFFER(x) + +#endif /* VL53L1_LOG_ENABLE */ + +#endif /* _VL53L1_PLATFORM_LOG_H_ */ diff --git a/drivers/oneplus/vl53L1/vl53l1_platform_user_config.h b/drivers/oneplus/vl53L1/vl53l1_platform_user_config.h new file mode 100755 index 0000000000000000000000000000000000000000..396d25762a5d341e9d9a742bda336dcea93f65bf --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform_user_config.h @@ -0,0 +1,117 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + +/** + * @file vl53l1_platform_user_config.h + * + * @brief EwokPlus compile time user modifiable configuration + */ + + +#ifndef _VL53L1_PLATFORM_USER_CONFIG_H_ +#define _VL53L1_PLATFORM_USER_CONFIG_H_ + +#define VL53L1_BYTES_PER_WORD 2 +#define VL53L1_BYTES_PER_DWORD 4 + +/* Define polling delays */ +#define VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS 500 +#define VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS 2000 +#define VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS 60000 + +#define VL53L1_POLLING_DELAY_MS 1 + +/* Define LLD TuningParms Page Base Address + * - Part of Patch_AddedTuningParms_11761 + */ +#define VL53L1_TUNINGPARM_PUBLIC_PAGE_BASE_ADDRESS 0x8000 +#define VL53L1_TUNINGPARM_PRIVATE_PAGE_BASE_ADDRESS 0xC000 + +#define VL53L1_GAIN_FACTOR__STANDARD_DEFAULT 0x0800 + /*!< Default standard ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.980 = 0x07D7 + */ +#define VL53L1_GAIN_FACTOR__HISTOGRAM_DEFAULT 0x0800 + /*!< Default histogram ranging gain correction factor + * 1.11 format. 1.0 = 0x0800, 0.975 = 0x07CC + */ + + +#define VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS 0x0500 + /*!< Lower Limit for the MM1 effective SPAD count during offset + * calibration Format 8.8 0x0500 -> 5.0 effective SPADs + */ + +#define VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Limit for the pre range preak rate during offset + * calibration Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_OFFSET_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during offset calibration + * Check applies to pre-range, mm1 and mm2 ranges + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_ZONE_CAL_MAX_PRE_PEAK_RATE_MCPS 0x1900 + /*!< Max Peak Rate Limit for the during zone calibration + * Format 9.7 0x1900 -> 50.0 Mcps. + * If larger then in pile up + */ + +#define VL53L1_ZONE_CAL_MAX_SIGMA_MM 0x0040 + /*!< Max sigma estimate limit during zone calibration + * Format 14.2 0x0040 -> 16.0mm. + */ + + +#define VL53L1_XTALK_EXTRACT_MAX_SIGMA_MM 0x008C + /*!< Max Sigma value allowed for a successful xtalk extraction + * Format 14.2 0x008C -> 35.0 mm. + */ + + +#define VL53L1_MAX_USER_ZONES 169 + /*!< Max number of user Zones - maximal limitation from + * FW stream divide - value of 254 + */ + +#define VL53L1_MAX_RANGE_RESULTS 4 + /*!< Sets the maximum number of targets distances the histogram + * post processing can generate + */ + +#define VL53L1_MAX_STRING_LENGTH 512 + +#endif /* _VL53L1_PLATFORM_USER_CONFIG_H_ */ + diff --git a/drivers/oneplus/vl53L1/vl53l1_platform_user_data.h b/drivers/oneplus/vl53L1/vl53l1_platform_user_data.h new file mode 100755 index 0000000000000000000000000000000000000000..41da1dda1235f29fa5f317f3e7aee72cae4ff8a8 --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform_user_data.h @@ -0,0 +1,63 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_USER_DATA_H_ +#define _VL53L1_PLATFORM_USER_DATA_H_ + +#include "vl53l1_ll_def.h" + +#include +#include "vl53l1_def.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define VL53L1_Dev_t VL53L1_DevData_t +#define VL53L1_DEV VL53L1_DevData_t * + +#define VL53L1DevDataGet(Dev, field) (Dev->field) +#define VL53L1DevDataSet(Dev, field, data) ((Dev->field) = (data)) + +#define VL53L1DevStructGetLLDriverHandle(Dev) (&VL53L1DevDataGet(Dev, LLData)) +#define VL53L1DevStructGetLLResultsHandle(Dev) (&VL53L1DevDataGet(Dev,\ + llresults)) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/vl53l1_platform_user_defines.h b/drivers/oneplus/vl53L1/vl53l1_platform_user_defines.h new file mode 100755 index 0000000000000000000000000000000000000000..731c48341756a632ed396303a316f7a99aea347d --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_platform_user_defines.h @@ -0,0 +1,92 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ + + +#ifndef _VL53L1_PLATFORM_USER_DEFINES_H_ +#define _VL53L1_PLATFORM_USER_DEFINES_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __KERNEL__ +#include +#endif + +/** + * @file vl53l1_platform_user_defines.h + * + * @brief All end user OS/platform/application definitions + */ + + +/** + * @def do_division_u + * @brief customer supplied division operation - 64-bit unsigned + * + * @param dividend unsigned 64-bit numerator + * @param divisor unsigned 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_u(dividend, divisor) div64_u64(dividend, divisor) +#else +#define do_division_u(dividend, divisor) (dividend / divisor) +#endif + +/** + * @def do_division_s + * @brief customer supplied division operation - 64-bit signed + * + * @param dividend signed 64-bit numerator + * @param divisor signed 64-bit denominator + */ +#ifdef __KERNEL__ +#define do_division_s(dividend, divisor) div64_s64(dividend, divisor) +#else +#define do_division_s(dividend, divisor) (dividend / divisor) +#endif + +#define WARN_OVERRIDE_STATUS(__X__)\ + trace_print(VL53L1_TRACE_LEVEL_WARNING, #__X__) + + +#define DISABLE_WARNINGS() +#define ENABLE_WARNINGS() + + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/oneplus/vl53L1/vl53l1_types.h b/drivers/oneplus/vl53L1/vl53l1_types.h new file mode 100755 index 0000000000000000000000000000000000000000..3d78e25592046029e98a55d2811cb8b5e15aed2f --- /dev/null +++ b/drivers/oneplus/vl53L1/vl53l1_types.h @@ -0,0 +1,46 @@ +/************************************************************************** + * Copyright (c) 2016, STMicroelectronics - All Rights Reserved + + License terms: BSD 3-clause "New" or "Revised" License. + + 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. + + 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. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ +/** + * @file vl53l1_types.h + * @brief VL53L1 types definition + */ + +#ifndef _VL53L1_TYPES_H_ +#define _VL53L1_TYPES_H_ + +#include +/** use where fractional values are expected + * + * Given a floating point value f it's .16 bit point is (int)(f*(1<<16)) + */ +typedef uint32_t FixPoint1616_t; + +#endif /* VL53L1_TYPES_H_ */ diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index f8ce0eac1ae8af537e27d6883069cc4488c0fb3b..008e44316fcd6f578fc3fd016f7a1d21470b5dd5 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -571,8 +571,15 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; unsigned i; - for (i = 0; i < chip->ngpio; i++, gpio++) + for (i = 0; i < chip->ngpio; i++, gpio++) { + /* Skip the gpio's which are protected by TZ */ + /* Refer QUPAC_Access.c in TZ code */ + if (i == 0 || i == 1 || i == 2 || i == 3 || + i == 59 || i == 60 || i == 61 || i == 62) { + continue; + } msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); + } } #else diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index acc50865aa4e021ec2c5341408c6a21e00d99c1d..29f10c526bf7122c0ed848057934bf42fdf5a01c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3940,8 +3940,8 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, * Dont enable ipa_status for APQ, since MDM IPA * has IPA >= 4.5 with DPLv3. */ - if (ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ && - ipa3_is_mhip_offload_enabled()) + if ((ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ && + ipa3_is_mhip_offload_enabled()) || (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5)) sys->ep->status.status_en = false; else sys->ep->status.status_en = true; diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index c1b0799963e624d20f10ef6138fd40d83b96a77d..017b42c9e0c01115dfac6d19f4daceca6800292c 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -26,6 +26,7 @@ #include #include #include +#include #define EMERGENCY_DLOAD_MAGIC1 0x322A4F99 #define EMERGENCY_DLOAD_MAGIC2 0xC67E4350 @@ -132,6 +133,11 @@ static struct kobj_type reset_ktype = { .sysfs_ops = &reset_sysfs_ops, }; +int oem_get_download_mode(void) +{ + return download_mode && (dload_type & SCM_DLOAD_FULLDUMP); +} + static int panic_prep_restart(struct notifier_block *this, unsigned long event, void *ptr) { @@ -186,6 +192,16 @@ static bool get_dload_mode(void) return dload_mode_enabled; } +void oem_force_minidump_mode(void) +{ + if (dload_type == SCM_DLOAD_FULLDUMP) { + pr_err("force minidump mode\n"); + dload_type = SCM_DLOAD_MINIDUMP; + set_dload_mode(dload_type); + __raw_writel(EMMC_DLOAD_TYPE, dload_type_addr); + } +} + static void enable_emergency_dload_mode(void) { int ret; @@ -520,6 +536,24 @@ static void msm_restart_prepare(const char *cmd) qpnp_pon_set_restart_reason( PON_RESTART_REASON_KEYS_CLEAR); __raw_writel(0x7766550a, restart_reason); + } else if (!strcmp(cmd, "sbllowmemtest")) { + pr_info("[op aging mem test] lunch ddr sbllowmemtest!!comm: %s, pid: %d\n" + , current->comm, current->pid); + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SBL_DDR_CUS); + __raw_writel(0x7766550b, restart_reason); + } else if (!strcmp(cmd, "sblmemtest")) {//op factory aging test + pr_info("[op aging mem test] lunch ddr sblmemtest!!comm: %s, pid: %d\n" + , current->comm, current->pid); + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_SBL_DDRTEST); + __raw_writel(0x7766550b, restart_reason); + } else if (!strcmp(cmd, "usermemaging")) { + pr_info("[op aging mem test] lunch ddr usermemaging!!comm: %s, pid: %d\n" + , current->comm, current->pid); + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_MEM_AGING); + __raw_writel(0x7766550b, restart_reason); } else if (!strncmp(cmd, "oem-", 4)) { unsigned long code; int ret; @@ -530,6 +564,12 @@ static void msm_restart_prepare(const char *cmd) restart_reason); } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); + } else if (!strncmp(cmd, "rf", 2)) { + qpnp_pon_set_restart_reason(PON_RESTART_REASON_RF); + __raw_writel(RF_MODE, restart_reason); + } else if (!strncmp(cmd, "ftm", 3)) { + qpnp_pon_set_restart_reason(PON_RESTART_REASON_FACTORY); + __raw_writel(FACTORY_MODE, restart_reason); } else { __raw_writel(0x77665501, restart_reason); } diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index cc439fd89d8dda469c52795bcc59074245b1cec8..359c70c094dd1a251f01a137f23950bc392bd94c 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -40,3 +40,7 @@ static inline int power_supply_create_triggers(struct power_supply *psy) static inline void power_supply_remove_triggers(struct power_supply *psy) {} #endif /* CONFIG_LEDS_TRIGGERS */ + +#ifdef CONFIG_F2FS_OF2FS +extern int f2fs_battery_notifier_call_chain(unsigned long val, void *v); +#endif diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 633e006b398433a593d98c263a076a3978601d27..7e446583407d067fd265bc7cb8fd8cf56386773f 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -24,6 +24,10 @@ #include #include "power_supply.h" +#ifdef CONFIG_HOUSTON +#include +#endif + /* exported for the APM Power driver, APM emulation */ struct class *power_supply_class; EXPORT_SYMBOL_GPL(power_supply_class); @@ -98,6 +102,9 @@ static void power_supply_changed_work(struct work_struct *work) power_supply_update_leds(psy); atomic_notifier_call_chain(&power_supply_notifier, PSY_EVENT_PROP_CHANGED, psy); +#ifdef CONFIG_F2FS_OF2FS + f2fs_battery_notifier_call_chain(PSY_EVENT_PROP_CHANGED, psy); +#endif kobject_uevent(&psy->dev.kobj, KOBJ_CHANGE); spin_lock_irqsave(&psy->changed_lock, flags); } @@ -944,6 +951,10 @@ __power_supply_register(struct device *parent, &psy->deferred_register_work, POWER_SUPPLY_DEFERRED_REGISTER_TIME); +#ifdef CONFIG_HOUSTON + ht_register_power_supply(psy); +#endif + return psy; create_triggers_failed: diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index bcacfd977d143d07e7b3709efda7c16b01e4e02b..0f68946ed7ee2c46873773432ccb32600f2b9c76 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -45,9 +45,15 @@ static const char * const power_supply_type_text[] = { "USB_DCP", "USB_CDP", "USB_ACA", "USB_C", "USB_PD", "USB_PD_DRP", "BrickID", "USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT", - "BMS", "Parallel", "Main", "USB_C_UFP", "USB_C_DFP", + "BMS", "Parallel", "Main", "Wipower", "USB_C_UFP", "USB_C_DFP", "Charge_Pump", +/* @bsp, 2019/07/05 Battery & Charging porting */ + "DASH", "BPP", "EPP", "FAST", }; +/* @bsp, 2019/07/05 Battery & Charging porting */ + static const char *const cc_orientation_text[] = { + "Unknown", "cc1", "cc2" + }; static const char * const power_supply_usb_type_text[] = { "Unknown", "SDP", "DCP", "CDP", "ACA", "C", @@ -202,6 +208,11 @@ static ssize_t power_supply_show_property(struct device *dev, ret = sprintf(buf, "%s\n", power_supply_usbc_pr_text[value.intval]); break; +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION: + ret = snprintf(buf, sizeof(buf), "%s\n", + cc_orientation_text[value.intval]); + break; case POWER_SUPPLY_PROP_TYPEC_SRC_RP: ret = sprintf(buf, "%s\n", power_supply_typec_src_rp_text[value.intval]); @@ -283,10 +294,34 @@ static ssize_t power_supply_store_property(struct device *dev, static struct device_attribute power_supply_attrs[] = { /* Properties of type `int' */ POWER_SUPPLY_ATTR(status), +/* @bsp, 2018/07/13 Battery & Charging porting */ + POWER_SUPPLY_ATTR(set_allow_read_extern_fg_iic), + POWER_SUPPLY_ATTR(cc_to_cv_point), + POWER_SUPPLY_ATTR(chg_protect_status), + POWER_SUPPLY_ATTR(fastchg_status_is_ok), + POWER_SUPPLY_ATTR(fastchg_status), + POWER_SUPPLY_ATTR(fastchg_starting), + POWER_SUPPLY_ATTR(cutoff_volt_with_charger), + POWER_SUPPLY_ATTR(update_lcd_is_off), + POWER_SUPPLY_ATTR(check_usb_unplug), + POWER_SUPPLY_ATTR(otg_switch), + POWER_SUPPLY_ATTR(hw_detect), + POWER_SUPPLY_ATTR(switch_dash), + POWER_SUPPLY_ATTR(notify_charger_set_parameter), + POWER_SUPPLY_ATTR(fg_capacity), + POWER_SUPPLY_ATTR(fg_current_now), + POWER_SUPPLY_ATTR(fg_voltage_now), + POWER_SUPPLY_ATTR(is_aging_test), + POWER_SUPPLY_ATTR(connecter_temp1), + POWER_SUPPLY_ATTR(connecter_temp2), + POWER_SUPPLY_ATTR(connect_disable), + POWER_SUPPLY_ATTR(bq_soc), + POWER_SUPPLY_ATTR(oem_cc_orientation), POWER_SUPPLY_ATTR(charge_type), POWER_SUPPLY_ATTR(health), POWER_SUPPLY_ATTR(present), POWER_SUPPLY_ATTR(online), + POWER_SUPPLY_ATTR(swarp_online), POWER_SUPPLY_ATTR(authentic), POWER_SUPPLY_ATTR(technology), POWER_SUPPLY_ATTR(cycle_count), @@ -375,6 +410,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(temp_cold), POWER_SUPPLY_ATTR(temp_hot), POWER_SUPPLY_ATTR(system_temp_level), + POWER_SUPPLY_ATTR(battery_health), + POWER_SUPPLY_ATTR(op_disable_charge), + POWER_SUPPLY_ATTR(remaining_capacity), POWER_SUPPLY_ATTR(resistance), POWER_SUPPLY_ATTR(resistance_capacitive), POWER_SUPPLY_ATTR(resistance_id), diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index ec45b7d1c502dab0b83666a08773d805d20ec015..1e7b40ef914824bde41b56df15547348fb4185d0 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -951,6 +951,7 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data, if (!chip->main_psy) return 0; + pr_info("total_fcc_ua=%d\n", total_fcc_ua); if (!chip->cp_disable_votable) chip->cp_disable_votable = find_votable("CP_DISABLE"); @@ -1221,7 +1222,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, return 0; pval.intval = fv_uv; - + pr_info("fv_uv=%d\n", fv_uv); rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); if (rc < 0) { diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 51076762985f29161451ba007d7e3551d60124c4..38bc7b7a1a6197a311db6f16dec53ce4b4894c41 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -133,6 +133,7 @@ struct qpnp_qg { bool qg_device_open; bool profile_loaded; bool battery_missing; + bool iskebab; bool data_ready; bool suspend_data; bool vbat_low; @@ -145,6 +146,7 @@ struct qpnp_qg { bool fvss_active; bool tcss_active; bool bass_active; + bool use_external_fg; int charge_status; int charge_type; int chg_iterm_ma; diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index cbcd05aa30815e6e1373efeb1acc0a9055485a0e..e2ec64c9d1c93fb8ecdbc71eeba4283861ef4a72 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -36,8 +36,18 @@ #include "qg-soc.h" #include "qg-battery-profile.h" #include "qg-defs.h" +/* @bsp, 2019/07/05 Battery & Charging porting */ +#include static int qg_debug_mask; +/* @bsp, 2019/07/05 Battery & Charging porting */ +static void oem_update_cc_cv_setpoint(struct qpnp_qg *chip, + int cv_float_point); +static void oneplus_set_allow_read_iic(struct qpnp_qg *chip, + bool status); +static void oneplus_set_lcd_off_status(struct qpnp_qg *chip, + bool status); +static struct external_battery_gauge *external_fg; static int qg_esr_mod_count = 30; static ssize_t esr_mod_count_show(struct device *dev, struct device_attribute @@ -60,6 +70,27 @@ static ssize_t esr_mod_count_store(struct device *dev, } static DEVICE_ATTR_RW(esr_mod_count); +/* @bsp, 2019/07/05 Battery & Charging porting */ +void external_battery_gauge_register( + struct external_battery_gauge *batt_gauge) +{ + if (external_fg) { + external_fg = batt_gauge; + pr_err("multiple battery gauge called\n"); + } else + external_fg = batt_gauge; +} +EXPORT_SYMBOL(external_battery_gauge_register); + +void external_battery_gauge_unregister( + struct external_battery_gauge *batt_gauge) +{ + external_fg = NULL; +} +EXPORT_SYMBOL(external_battery_gauge_unregister); +/* @bsp, 2019/07/05 Battery & Charging porting */ +#define OP_SW_DEFAULT_ID 200000 + static int qg_esr_count = 3; static ssize_t esr_count_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -257,15 +288,6 @@ static void qg_notify_charger(struct qpnp_qg *chip) if (!chip->profile_loaded) return; - prop.intval = chip->bp.float_volt_uv; - rc = power_supply_set_property(chip->batt_psy, - POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop); - if (rc < 0) { - pr_err("Failed to set voltage_max property on batt_psy, rc=%d\n", - rc); - return; - } - prop.intval = chip->bp.fastchg_curr_ma * 1000; rc = power_supply_set_property(chip->batt_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop); @@ -1735,8 +1757,12 @@ static int qg_store_cycle_count(void *data, u16 *buf, int id, int length) #define DEFAULT_BATT_TYPE "Unknown Battery" #define MISSING_BATT_TYPE "Missing Battery" #define DEBUG_BATT_TYPE "Debug Board" +#define OP_AVACI_BATT_TYPE "OP_4115mAh" + static const char *qg_get_battery_type(struct qpnp_qg *chip) { + return OP_AVACI_BATT_TYPE; + if (chip->battery_missing) return MISSING_BATT_TYPE; @@ -2093,6 +2119,17 @@ static int qg_psy_set_property(struct power_supply *psy, int rc = 0; switch (psp) { +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CC_TO_CV_POINT: + oem_update_cc_cv_setpoint(chip, pval->intval); + break; + case POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC: + oneplus_set_allow_read_iic(chip, pval->intval); + break; + case POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF: + oneplus_set_lcd_off_status(chip, pval->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: if (chip->dt.cl_disable) { pr_warn("Capacity learning disabled!\n"); @@ -2137,6 +2174,7 @@ static int qg_psy_set_property(struct power_supply *psy, return 0; } +#define DEFALUT_BATT_TEMP 250 static int qg_psy_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *pval) @@ -2149,7 +2187,15 @@ static int qg_psy_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: - rc = qg_get_battery_capacity(chip, &pval->intval); +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (!get_extern_fg_regist_done()) + pval->intval = get_prop_pre_shutdown_soc(); + else if (chip->use_external_fg && external_fg + && external_fg->get_battery_soc) + pval->intval = external_fg->get_battery_soc(); + else + pval->intval = 50; + break; case POWER_SUPPLY_PROP_CAPACITY_RAW: pval->intval = chip->sys_soc; @@ -2158,23 +2204,63 @@ static int qg_psy_get_property(struct power_supply *psy, rc = qg_get_battery_capacity_real(chip, &pval->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - rc = qg_get_battery_voltage(chip, &pval->intval); +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (chip->use_external_fg && external_fg + && external_fg->get_battery_mvolts) + pval->intval = external_fg->get_battery_mvolts(); + else + pval->intval = 4000000; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = qg_get_battery_current(chip, &pval->intval); +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (chip->use_external_fg && external_fg + && external_fg->get_average_current) + pval->intval = external_fg->get_average_current(); + else + pval->intval = 0; break; case POWER_SUPPLY_PROP_VOLTAGE_OCV: rc = qg_sdam_read(SDAM_OCV_UV, &pval->intval); break; case POWER_SUPPLY_PROP_TEMP: - rc = qg_get_battery_temp(chip, &pval->intval); + if (!get_extern_fg_regist_done() + && get_extern_bq_present()) + pval->intval = DEFALUT_BATT_TEMP; + else if ((chip->use_external_fg && external_fg) + && external_fg->get_battery_temperature) { + pval->intval = external_fg->get_battery_temperature(); + } else + pval->intval = 250; + break; +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_FG_CAPACITY: + rc = qg_get_battery_capacity(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_FG_VOLTAGE_NOW: + if (chip->battery_missing) + pval->intval = 3700000; + else + rc = qg_get_battery_voltage(chip, &pval->intval); break; + case POWER_SUPPLY_PROP_FG_CURRENT_NOW: + rc = qg_get_battery_current(chip, &pval->intval); + break; + case POWER_SUPPLY_PROP_BQ_SOC: + if (chip->use_external_fg && external_fg + && external_fg->get_batt_bq_soc) + pval->intval = external_fg->get_batt_bq_soc(); + else + pval->intval = 50; + break; + case POWER_SUPPLY_PROP_RESISTANCE_ID: pval->intval = chip->batt_id_ohm; break; case POWER_SUPPLY_PROP_DEBUG_BATTERY: pval->intval = is_debug_batt_id(chip); break; + case POWER_SUPPLY_PROP_BATTERY_HEALTH: + pval->intval = -EINVAL; case POWER_SUPPLY_PROP_RESISTANCE: rc = qg_sdam_read(SDAM_RBAT_MOHM, &pval->intval); if (!rc) @@ -2208,17 +2294,39 @@ static int qg_psy_get_property(struct power_supply *psy, rc = qg_get_charge_counter(chip, &pval->intval); break; case POWER_SUPPLY_PROP_CHARGE_FULL: - if (!chip->dt.cl_disable && chip->dt.cl_feedback_on) + if (!get_extern_fg_regist_done() && get_extern_bq_present()) + pval->intval = -EINVAL; + else if (chip->use_external_fg && external_fg + && external_fg->get_batt_full_chg_capacity) + pval->intval = + external_fg->get_batt_full_chg_capacity() * 1000; + else { rc = qg_get_learned_capacity(chip, &temp); + if (!rc) + pval->intval = (int)temp; + } + break; + case POWER_SUPPLY_PROP_REMAINING_CAPACITY: + if (!get_extern_fg_regist_done() && get_extern_bq_present()) + pval->intval = DEFALUT_BATT_TEMP; + else if (chip->use_external_fg && external_fg + && external_fg->get_batt_remaining_capacity) + pval->intval = + external_fg->get_batt_remaining_capacity(); else - rc = qg_get_nominal_capacity((int *)&temp, 250, true); - if (!rc) - pval->intval = (int)temp; + pval->intval = -EINVAL; break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - rc = qg_get_nominal_capacity((int *)&temp, 250, true); - if (!rc) - pval->intval = (int)temp; + if (!get_extern_fg_regist_done() && get_extern_bq_present()) + pval->intval = -EINVAL; + else if (chip->use_external_fg && external_fg && external_fg->get_batt_full_chg_capacity) { + temp = external_fg->get_batt_full_chg_capacity(); + pval->intval = 1000 * temp; + } else { + rc = qg_get_nominal_capacity((int *)&temp, 250, true); + if (!rc) + pval->intval = -EINVAL; + } break; case POWER_SUPPLY_PROP_CYCLE_COUNTS: rc = get_cycle_counts(chip->counter, &pval->strval); @@ -2232,7 +2340,15 @@ static int qg_psy_get_property(struct power_supply *psy, rc = ttf_get_time_to_full(chip->ttf, &pval->intval); break; case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: - rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + if (chip->iskebab) { + if (chip->use_external_fg && external_fg + && external_fg->get_time_to_full) + rc = external_fg->get_time_to_full(); + if (rc >= 0) + pval->intval = rc; + } else + rc = ttf_get_time_to_full(chip->ttf, &pval->intval); + pval->intval = pval->intval > 0 ? pval->intval : 1; break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: rc = ttf_get_time_to_empty(chip->ttf, &pval->intval); @@ -2290,6 +2406,9 @@ static int qg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_SOH: case POWER_SUPPLY_PROP_FG_RESET: case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC: + return 1; default: break; @@ -2336,6 +2455,11 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_SCALE_MODE_EN, POWER_SUPPLY_PROP_BATT_AGE_LEVEL, POWER_SUPPLY_PROP_FG_TYPE, +/* @bsp, 2019/07/05 Battery & Charging porting */ + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, + POWER_SUPPLY_PROP_BQ_SOC, + POWER_SUPPLY_PROP_BATTERY_HEALTH, + POWER_SUPPLY_PROP_REMAINING_CAPACITY, }; static const struct power_supply_desc qg_psy_desc = { @@ -4259,7 +4383,6 @@ static int qg_parse_dt(struct qpnp_qg *chip) chip->dt.vbatt_empty_cold_mv = DEFAULT_VBATT_EMPTY_COLD_MV; else chip->dt.vbatt_empty_cold_mv = temp; - rc = of_property_read_u32(node, "qcom,cold-temp-threshold", &temp); if (rc < 0) chip->dt.cold_temp_threshold = DEFAULT_COLD_TEMP_THRESHOLD; @@ -4409,6 +4532,8 @@ static int qg_parse_dt(struct qpnp_qg *chip) } chip->dt.bass_enable = of_property_read_bool(node, "qcom,bass-enable"); + chip->iskebab = of_property_read_bool(node, "oem,iskebab"); + pr_info("iskebab=%d\n", chip->iskebab); chip->dt.multi_profile_load = of_property_read_bool(node, "qcom,multi-profile-load"); @@ -4665,6 +4790,33 @@ static const struct dev_pm_ops qpnp_qg_pm_ops = { .resume = qpnp_qg_resume, }; +/* @bsp, 2019/07/05 Battery & Charging porting */ +static void oem_update_cc_cv_setpoint( + struct qpnp_qg *chip, int cv_float_point) +{ + /* TODO: write CC_CV_SETPOINT_REG */ +} + +static void oneplus_set_allow_read_iic(struct qpnp_qg *chip, + bool status) +{ + if (chip->use_external_fg && external_fg + && external_fg->set_allow_reading) + external_fg->set_allow_reading(status); + else + pr_info("set allow read extern fg iic fail\n"); +} + +static void oneplus_set_lcd_off_status(struct qpnp_qg *chip, + bool status) +{ + if (chip->use_external_fg && external_fg + && external_fg->set_lcd_off_status) + external_fg->set_lcd_off_status(status); + else + pr_info("set lcd off status fail\n"); +} + static int qpnp_qg_probe(struct platform_device *pdev) { int rc = 0, soc = 0, nom_cap_uah; @@ -4679,6 +4831,7 @@ static int qpnp_qg_probe(struct platform_device *pdev) pr_err("Parent regmap is unavailable\n"); return -ENXIO; } + chip->use_external_fg = true; /* ADC for BID & THERM */ chip->batt_id_chan = iio_channel_get(&pdev->dev, "batt-id"); diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 8a9c98ec73b5b55a6f9830bb1f486462b7684f06..e2cabb4255b88e086c01753f86af635563385df2 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -3,6 +3,9 @@ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ +/* @bsp, 2019/07/05 Battery & Charging porting */ +#define pr_fmt(fmt) "SMB2: %s: " fmt, __func__ + #include #include #include @@ -20,10 +23,22 @@ #include #include #include +/* @bsp, 2019/07/05 Battery & Charging porting */ +#include +#include +#include +#include +#include + +//#include #include "smb5-reg.h" #include "smb5-lib.h" #include "schgm-flash.h" +/* USB ADC gpio channel names to read from DTSI */ +#define USB_TEM1_ADC_CHANNEL_NAME "usb_tem1_adc" +#define USB_TEM2_ADC_CHANNEL_NAME "usb_tem2_adc" + static struct smb_params smb5_pmi632_params = { .fcc = { .name = "fast charge current", @@ -227,7 +242,42 @@ struct smb5 { struct smb_dt_props dt; }; +/* @bsp, 20180713 Battery & Charging porting */ +static int smbchg_cutoff_volt_with_charger = 3240; +struct smb_charger *g_chip; +static const struct file_operations proc_ship_mode_operations; +module_param_named( + cutoff_volt_with_charger, + smbchg_cutoff_volt_with_charger, + int, 0600); + +#define OF_PROP_READ(node, dt_property, prop, retval, optional) \ +do { \ + if (retval) \ + break; \ + if (optional) \ + prop = -EINVAL; \ + \ + retval = of_property_read_u32(node, \ + dt_property, \ + &prop); \ + \ + if ((retval == -EINVAL) && optional) \ + retval = 0; \ + else if (retval) \ + pr_err("Error reading " #dt_property \ + " property rc = %d\n", rc); \ +} while (0) + +#ifdef CONFIG_OP_DEBUG_CHG +static int __debug_mask = PR_OP_DEBUG; +#else static int __debug_mask; +#endif +module_param_named( + debug_mask, __debug_mask, int, 0600 +); + static ssize_t pd_disabled_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -286,6 +336,31 @@ static struct attribute *smb5_attrs[] = { }; ATTRIBUTE_GROUPS(smb5); +static int __usb_connector_temp; +module_param_named( + usb_connector_temp, __usb_connector_temp, int, 0644 +); + +static int __usb_interval_temp; +module_param_named( + usb_interval_temp, __usb_interval_temp, int, 0644 +); + +static int __disable_connector_protect; +module_param_named( + disable_connector_protect, __disable_connector_protect, int, 0644 +); + +static int __call_on; +module_param_named( + call_on, __call_on, int, 0644 +); + +static int __video_call_on; +module_param_named( + video_call_on, __video_call_on, int, 0644 +); + enum { BAT_THERM = 0, MISC_THERM, @@ -443,6 +518,14 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) { int rc = 0, byte_len; struct smb_charger *chg = &chip->chg; +/* @bsp, 2018/07/26 Enable external stm6620 ship mode*/ + enum of_gpio_flags flags; + int retval = 0; // only for OF_PROP_READ(); + + if (!node) { + pr_err("device tree node missing\n"); + return -EINVAL; + } of_property_read_u32(node, "qcom,sec-charger-config", &chip->dt.sec_charger_config); @@ -454,8 +537,423 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) chip->dt.sec_charger_config == POWER_SUPPLY_CHARGER_SEC_PL || chip->dt.sec_charger_config == POWER_SUPPLY_CHARGER_SEC_CP_PL; - chg->step_chg_enabled = of_property_read_bool(node, - "qcom,step-charging-enable"); +/*read ffc param*/ + OF_PROP_READ(node, "ffc-pre-normal-decidegc", + chg->FFC_TEMP_T1, retval, 1); + OF_PROP_READ(node, "ffc-normal-decidegc", + chg->FFC_TEMP_T2, retval, 1); + OF_PROP_READ(node, "ffc-warm-decidegc", + chg->FFC_TEMP_T3, retval, 1); + OF_PROP_READ(node, "ffc-normal-fcc-ma", + chg->FFC_NOR_FCC, retval, 1); + OF_PROP_READ(node, "ffc-warm-fcc-ma", + chg->FFC_WARM_FCC, retval, 1); + OF_PROP_READ(node, "ffc-normal-cutoff-ma", + chg->FFC_NORMAL_CUTOFF, retval, 1); + OF_PROP_READ(node, "ffc-warm-cutoff-ma", + chg->FFC_WARM_CUTOFF, retval, 1); + OF_PROP_READ(node, "ffc-full-vbat-mv", + chg->FFC_VBAT_FULL, retval, 1); + pr_info("T1:%d, T2:%d, T3:%d, fcc1:%d, fcc1:%d, cut1:%d, cut2:%d,full:%d\n", + chg->FFC_TEMP_T1, chg->FFC_TEMP_T2, chg->FFC_TEMP_T3, + chg->FFC_NOR_FCC, chg->FFC_WARM_FCC, chg->FFC_NORMAL_CUTOFF, + chg->FFC_WARM_CUTOFF, chg->FFC_VBAT_FULL); + +/* @bsp, 2019/07/05 Battery & Charging porting */ + /* read ibatmax setting for different temp regions */ + OF_PROP_READ(node, "ibatmax-little-cold-ma", + chg->ibatmax[BATT_TEMP_LITTLE_COLD], retval, 1); + OF_PROP_READ(node, "ibatmax-cool-ma", + chg->ibatmax[BATT_TEMP_COOL], retval, 1); + OF_PROP_READ(node, "ibatmax-little-cool-ma", + chg->ibatmax[BATT_TEMP_LITTLE_COOL], retval, 1); + OF_PROP_READ(node, "ibatmax-pre-normal-ma", + chg->ibatmax[BATT_TEMP_PRE_NORMAL], retval, 1); + OF_PROP_READ(node, "ibatmax-normal-ma", + chg->ibatmax[BATT_TEMP_NORMAL], retval, 1); + OF_PROP_READ(node, "ibatmax-warm-ma", + chg->ibatmax[BATT_TEMP_WARM], retval, 1); + + /* read vbatmax setting for different temp regions */ + OF_PROP_READ(node, "vbatmax-little-cold-mv", + chg->vbatmax[BATT_TEMP_LITTLE_COLD], retval, 1); + OF_PROP_READ(node, "vbatmax-cool-mv", + chg->vbatmax[BATT_TEMP_COOL], retval, 1); + OF_PROP_READ(node, "vbatmax-little-cool-mv", + chg->vbatmax[BATT_TEMP_LITTLE_COOL], retval, 1); + OF_PROP_READ(node, "vbatmax-pre-normal-mv", + chg->vbatmax[BATT_TEMP_PRE_NORMAL], retval, 1); + OF_PROP_READ(node, "vbatmax-normal-mv", + chg->vbatmax[BATT_TEMP_NORMAL], retval, 1); + OF_PROP_READ(node, "vbatmax-warm-mv", + chg->vbatmax[BATT_TEMP_WARM], retval, 1); + + /* read vbatdet setting for different temp regions */ + OF_PROP_READ(node, "vbatdet-little-cold-mv", + chg->vbatdet[BATT_TEMP_LITTLE_COLD], retval, 1); + OF_PROP_READ(node, "vbatdet-cool-mv", + chg->vbatdet[BATT_TEMP_COOL], retval, 1); + OF_PROP_READ(node, "vbatdet-little-cool-mv", + chg->vbatdet[BATT_TEMP_LITTLE_COOL], retval, 1); + OF_PROP_READ(node, "vbatdet-pre-normal-mv", + chg->vbatdet[BATT_TEMP_PRE_NORMAL], retval, 1); + OF_PROP_READ(node, "vbatdet-normal-mv", + chg->vbatdet[BATT_TEMP_NORMAL], retval, 1); + OF_PROP_READ(node, "vbatdet-warm-mv", + chg->vbatdet[BATT_TEMP_WARM], retval, 1); + OF_PROP_READ(node, "little-cool-vbat-thr-mv", + chg->temp_littel_cool_voltage, retval, 1); + if (chg->temp_littel_cool_voltage < 0) + chg->temp_littel_cool_voltage = 4180; + OF_PROP_READ(node, "cool-vbat-thr-mv", + chg->temp_cool_voltage, retval, 1); + if (chg->temp_cool_voltage < 0) + chg->temp_cool_voltage = 4180; + OF_PROP_READ(node, "ibatmax-little-cool-thr-ma", + chg->temp_littel_cool_current, retval, 1); + if (chg->temp_littel_cool_current < 0) + chg->temp_littel_cool_current = 2000; + OF_PROP_READ(node, "ibatmax-cool-thr-ma", + chg->temp_cool_current, retval, 1); + if (chg->temp_cool_current < 0) + chg->temp_cool_current = 1140; + /* read temp region settings */ + OF_PROP_READ(node, "cold-bat-decidegc", + chg->BATT_TEMP_T0, retval, 1); + chg->BATT_TEMP_T0 = 0 - chg->BATT_TEMP_T0; + OF_PROP_READ(node, "little-cold-bat-decidegc", + chg->BATT_TEMP_T1, retval, 1); + OF_PROP_READ(node, "cool-bat-decidegc", + chg->BATT_TEMP_T2, retval, 1); + OF_PROP_READ(node, "little-cool-bat-decidegc", + chg->BATT_TEMP_T3, retval, 1); + OF_PROP_READ(node, "pre-normal-bat-decidegc", + chg->BATT_TEMP_T4, retval, 1); + OF_PROP_READ(node, "warm-bat-decidegc", + chg->BATT_TEMP_T5, retval, 1); + OF_PROP_READ(node, "hot-bat-decidegc", + chg->BATT_TEMP_T6, retval, 1); + chg->pd_not_supported = of_property_read_bool(node, + "disable-pd"); + + chg->check_batt_full_by_sw = of_property_read_bool(node, + "op,sw-check-full-enable"); + rc = of_property_read_u32(node, + "op,sw-iterm-ma", + &chg->sw_iterm_ma); + if (rc < 0) + chg->sw_iterm_ma = 150; + pr_info("sw_iterm_ma=%d,check_batt_full_by_sw=%d", + chg->sw_iterm_ma, chg->check_batt_full_by_sw); + rc = of_property_read_u32(node, + "op,little_cold_term_current", + &chg->little_cold_iterm_ma); + pr_info("little_cold_iterm_ma=%d", chg->little_cold_iterm_ma); +/* otg-icl set 1A if battery lower than 15%*/ + chg->OTG_ICL_CTRL = of_property_read_bool(node, + "op,otg-icl-ctrl-enable"); + OF_PROP_READ(node, "otg-low-battery-thr", + chg->OTG_LOW_BAT, retval, 1); + if (retval < 0) + chg->OTG_LOW_BAT = -EINVAL; + OF_PROP_READ(node, "otg-low-bat-icl-thr", + chg->OTG_LOW_BAT_ICL, retval, 1); + if (retval < 0) + chg->OTG_LOW_BAT_ICL = -EINVAL; + OF_PROP_READ(node, "otg-normal-bat-icl-thr", + chg->OTG_NORMAL_BAT_ICL, retval, 1); + if (retval < 0) + chg->OTG_NORMAL_BAT_ICL = -EINVAL; + pr_info("OTG_ICL:enable:%d,CapThr:%d,LowThr:%d,NorThr:%d\n", + chg->OTG_ICL_CTRL, + chg->OTG_LOW_BAT, + chg->OTG_LOW_BAT_ICL, + chg->OTG_NORMAL_BAT_ICL); +/* @bsp, 2018/07/26 enable stm6620 sheepmode */ + chg->shipmode_en = of_get_named_gpio_flags(node, + "op,stm-ctrl-gpio", 0, &flags); + chg->vbus_ctrl = of_get_named_gpio_flags(node, + "op,vbus-ctrl-gpio", 0, &flags); + chg->plug_irq = of_get_named_gpio_flags(node, + "op,usb-check", 0, &flags); +/* @bsp, 2019/06/28 vph sel set disable */ + chg->vph_sel_disable = of_property_read_bool(node, + "vph-sel-disable"); + /* read other settings */ + OF_PROP_READ(node, "qcom,cutoff-voltage-with-charger", + smbchg_cutoff_volt_with_charger, retval, 1); + chg->chg_enabled = !(of_property_read_bool(node, + "qcom,charging-disabled")); + + pr_info("T0=%d, T1=%d, T2=%d, T3=%d, T4=%d, T5=%d, T6=%d\n", + chg->BATT_TEMP_T0, chg->BATT_TEMP_T1, chg->BATT_TEMP_T2, + chg->BATT_TEMP_T3, chg->BATT_TEMP_T4, chg->BATT_TEMP_T5, + chg->BATT_TEMP_T6); + pr_info("BATT_TEMP_LITTLE_COLD=%d, %d, %d\n", + chg->ibatmax[BATT_TEMP_LITTLE_COLD], + chg->vbatmax[BATT_TEMP_LITTLE_COLD], + chg->vbatdet[BATT_TEMP_LITTLE_COLD]); + pr_info("BATT_TEMP_COOL=%d, %d, %d\n", + chg->ibatmax[BATT_TEMP_COOL], + chg->vbatmax[BATT_TEMP_COOL], + chg->vbatdet[BATT_TEMP_COOL]); + pr_info("BATT_TEMP_LITTLE_COOL=%d, %d, %d\n", + chg->ibatmax[BATT_TEMP_LITTLE_COOL], + chg->vbatmax[BATT_TEMP_LITTLE_COOL], + chg->vbatdet[BATT_TEMP_LITTLE_COOL]); + pr_info("BATT_TEMP_PRE_NORMAL=%d, %d, %d\n", + chg->ibatmax[BATT_TEMP_PRE_NORMAL], + chg->vbatmax[BATT_TEMP_PRE_NORMAL], + chg->vbatdet[BATT_TEMP_PRE_NORMAL]); + pr_info("BATT_TEMP_NORMAL=%d, %d, %d\n", + chg->ibatmax[BATT_TEMP_NORMAL], + chg->vbatmax[BATT_TEMP_NORMAL], + chg->vbatdet[BATT_TEMP_NORMAL]); + pr_info("BATT_TEMP_WARM=%d, %d, %d\n", + chg->ibatmax[BATT_TEMP_WARM], + chg->vbatmax[BATT_TEMP_WARM], + chg->vbatdet[BATT_TEMP_WARM]); + pr_info("cutoff_volt_with_charger=%d, disable-pd=%d\n", + smbchg_cutoff_volt_with_charger, chg->pd_disabled); + + OF_PROP_READ(node, "op,fv-offset-voltage-mv", + chg->fv_offset_voltage_mv, retval, 1); + if (chg->fv_offset_voltage_mv <= 0) + chg->fv_offset_voltage_mv = + FV_OFFSET_VOLTAGE; + pr_info("fv_offset_voltage_mv=%d\n", + chg->fv_offset_voltage_mv); + + OF_PROP_READ(node, "op,normal-check-interval-period", + chg->normal_check_interval_period, retval, 1); + if (chg->normal_check_interval_period <= 0) + chg->normal_check_interval_period = + NORMAL_CHECK_INTERVAL_PERIOD; + pr_info("normal_check_interval_period=%d\n", + chg->normal_check_interval_period); + + OF_PROP_READ(node, "op,fast-check-interval-period", + chg->fast_check_interval_period, retval, 1); + if (chg->fast_check_interval_period <= 0) + chg->fast_check_interval_period = + FAST_CHECK_INTERVAL_PERIOD; + pr_info("fast_check_interval_period=%d\n", + chg->fast_check_interval_period); + + OF_PROP_READ(node, "op,fast-check-threshold-temp", + chg->fast_check_threshold_temp, retval, 1); + if (chg->fast_check_threshold_temp <= 0) + chg->fast_check_threshold_temp = + FAST_CHECK_THRESHOLD_TEMP; + pr_info("fast_check_threshold_temp=%d\n", + chg->fast_check_threshold_temp); + + OF_PROP_READ(node, "op,high-temp-short-check-timeout", + chg->high_temp_short_check_timeout, retval, 1); + if (chg->high_temp_short_check_timeout <= 0) + chg->high_temp_short_check_timeout = + HIGH_TEMP_SHORT_CHECK_TIMEOUT; + pr_info("high_temp_short_check_timeout=%d\n", + chg->high_temp_short_check_timeout); + + OF_PROP_READ(node, "op,first-protect-connecter-temp", + chg->first_protect_connecter_temp, retval, 1); + if (chg->first_protect_connecter_temp <= 0) + chg->first_protect_connecter_temp = + FIRST_PROTECT_CONNECTER_TEMP; + pr_info("first_protect_connecter_temp=%d\n", + chg->first_protect_connecter_temp); + + OF_PROP_READ(node, "op,second-protect-connecter-temp", + chg->second_protect_connecter_temp, retval, 1); + if (chg->second_protect_connecter_temp <= 0) + chg->second_protect_connecter_temp = + SECOND_PROTECT_CONNECTER_TEMP; + pr_info("second_protect_connecter_temp=%d\n", + chg->second_protect_connecter_temp); + + OF_PROP_READ(node, "op,second-protect-interval-temp", + chg->second_protect_interval_temp, retval, 1); + if (chg->second_protect_interval_temp <= 0) + chg->second_protect_interval_temp = + SECOND_PROTECT_INTERVAL_TEMP; + pr_info("second_protect_interval_temp=%d\n", + chg->second_protect_interval_temp); + + OF_PROP_READ(node, "op,third-protect-rise-rate", + chg->third_protect_rise_rate, retval, 1); + if (chg->third_protect_rise_rate <= 0) + chg->third_protect_rise_rate = + THIRD_PROTECT_RISE_RATE; + pr_info("third_protect_rise_rate=%d\n", + chg->third_protect_rise_rate); + + OF_PROP_READ(node, "op,third-protect-loop-temp", + chg->third_protect_loop_temp, retval, 1); + if (chg->third_protect_loop_temp <= 0) + chg->third_protect_loop_temp = + THIRD_PROTECT_LOOP_TEMP; + pr_info("third_protect_loop_temp=%d\n", + chg->third_protect_loop_temp); + + OF_PROP_READ(node, "op,third-protect-interval-temp", + chg->third_protect_interval_temp, retval, 1); + if (chg->third_protect_interval_temp <= 0) + chg->third_protect_interval_temp = + THIRD_PROTECT_INTERVAL_TEMP; + pr_info("third_protect_interval_temp=%d\n", + chg->third_protect_interval_temp); + + OF_PROP_READ(node, "op,third-protect-base-temp", + chg->third_protect_base_temp, retval, 1); + if (chg->third_protect_base_temp <= 0) + chg->third_protect_base_temp = + THIRD_PROTECT_BASE_TEMP; + pr_info("third_protect_base_temp=%d\n", + chg->third_protect_base_temp); + + // Skin therm thresholds when display OFF + OF_PROP_READ(node, "op,skin-thermal-high-threshold-disp-off", + chg->skin_thermal_high_threshold_disp_off, retval, 1); + if (chg->skin_thermal_high_threshold_disp_off <= 0) + chg->skin_thermal_high_threshold_disp_off = + SKIN_THERMAL_HIGH; + pr_info("skin_thermal_high_threshold_disp_off=%d\n", + chg->skin_thermal_high_threshold_disp_off); + + OF_PROP_READ(node, "op,skin-thermal-pre-high-threshold-disp-off", + chg->skin_thermal_pre_high_threshold_disp_off, + retval, 1); + if (chg->skin_thermal_pre_high_threshold_disp_off <= 0) + chg->skin_thermal_pre_high_threshold_disp_off = + SKIN_THERMAL_PRE_HIGH; + pr_info("skin_thermal_pre_high_threshold_disp_off=%d\n", + chg->skin_thermal_pre_high_threshold_disp_off); + + OF_PROP_READ(node, "op,skin-thermal-medium-threshold-disp-off", + chg->skin_thermal_medium_threshold_disp_off, + retval, 1); + if (chg->skin_thermal_medium_threshold_disp_off <= 0) + chg->skin_thermal_medium_threshold_disp_off = + SKIN_THERMAL_MEDIUM; + pr_info("skin_thermal_medium_threshold_disp_off=%d\n", + chg->skin_thermal_medium_threshold_disp_off); + + OF_PROP_READ(node, "op,skin-thermal-normal-threshold-disp-off", + chg->skin_thermal_normal_threshold_disp_off, + retval, 1); + if (chg->skin_thermal_normal_threshold_disp_off <= 0) + chg->skin_thermal_normal_threshold_disp_off = + SKIN_THERMAL_NORMAL; + pr_info("skin_thermal_normal_threshold_disp_off=%d\n", + chg->skin_thermal_normal_threshold_disp_off); + + // Skin therm thresholds when display ON + OF_PROP_READ(node, "op,skin-thermal-high-threshold-disp-on", + chg->skin_thermal_high_threshold_disp_on, + retval, 1); + if (chg->skin_thermal_high_threshold_disp_on <= 0) + chg->skin_thermal_high_threshold_disp_on = + SKIN_THERMAL_HIGH; + pr_info("skin_thermal_high_threshold_disp_on=%d\n", + chg->skin_thermal_high_threshold_disp_on); + + OF_PROP_READ(node, "op,skin-thermal-pre-high-threshold-disp-on", + chg->skin_thermal_pre_high_threshold_disp_on, + retval, 1); + if (chg->skin_thermal_pre_high_threshold_disp_on <= 0) + chg->skin_thermal_pre_high_threshold_disp_on = + SKIN_THERMAL_PRE_HIGH; + pr_info("skin_thermal_pre_high_threshold_disp_on=%d\n", + chg->skin_thermal_pre_high_threshold_disp_on); + + OF_PROP_READ(node, "op,skin-thermal-little-high-threshold-disp-on", + chg->skin_thermal_little_high_threshold_disp_on, + retval, 1); + if (chg->skin_thermal_little_high_threshold_disp_on <= 0) + chg->skin_thermal_little_high_threshold_disp_on = + SKIN_THERMAL_LITTLE_HIGH; + pr_info("skin_thermal_little_high_threshold_disp_on=%d\n", + chg->skin_thermal_high_threshold_disp_on); + + OF_PROP_READ(node, "op,skin-thermal-pre-little-high-threshold-disp-on", + chg->skin_thermal_pre_little_high_threshold_disp_on, + retval, 1); + if (chg->skin_thermal_pre_little_high_threshold_disp_on <= 0) + chg->skin_thermal_pre_little_high_threshold_disp_on = + SKIN_THERMAL_PRE_LITTLE_HIGH; + pr_info("skin_thermal_pre_little_high_threshold_disp_on=%d\n", + chg->skin_thermal_pre_little_high_threshold_disp_on); + + OF_PROP_READ(node, "op,skin-thermal-medium-threshold-disp-on", + chg->skin_thermal_medium_threshold_disp_on, + retval, 1); + if (chg->skin_thermal_medium_threshold_disp_on <= 0) + chg->skin_thermal_medium_threshold_disp_on = + SKIN_THERMAL_MEDIUM; + pr_info("skin_thermal_medium_threshold_disp_on=%d\n", + chg->skin_thermal_medium_threshold_disp_on); + + OF_PROP_READ(node, "op,skin-thermal-normal-threshold-disp-on", + chg->skin_thermal_normal_threshold_disp_on, + retval, 1); + if (chg->skin_thermal_normal_threshold_disp_on <= 0) + chg->skin_thermal_normal_threshold_disp_on = + SKIN_THERMAL_NORMAL; + pr_info("skin_thermal_normal_threshold_disp_on=%d\n", + chg->skin_thermal_normal_threshold_disp_on); + + chg->enable_dash_current_adjust = of_property_read_bool(node, + "op,enable-dash-current-dynamic-adjust"); + pr_info("enable_dash_current_adjust=%d\n", + chg->enable_dash_current_adjust); + + OF_PROP_READ(node, "op,pd-skin-thermal-high-threshold", + chg->pd_skin_thermal_high_threshold, retval, 1); + if (chg->pd_skin_thermal_high_threshold <= 0) + chg->pd_skin_thermal_high_threshold = + SKIN_THERMAL_HIGH; + pr_info("pd_skin_thermal_high_threshold=%d\n", + chg->pd_skin_thermal_high_threshold); + + OF_PROP_READ(node, "op,pd-skin-thermal-normal-threshold", + chg->pd_skin_thermal_normal_threshold, retval, 1); + if (chg->pd_skin_thermal_normal_threshold <= 0) + chg->pd_skin_thermal_normal_threshold = + SKIN_THERMAL_NORMAL; + pr_info("pd_skin_thermal_normal_threshold=%d\n", + chg->pd_skin_thermal_normal_threshold); + + OF_PROP_READ(node, "op,pd-skin-thermal-medium-threshold", + chg->pd_skin_thermal_medium_threshold, retval, 1); + if (chg->pd_skin_thermal_medium_threshold <= 0) + chg->pd_skin_thermal_medium_threshold = + SKIN_THERMAL_MEDIUM; + pr_info("pd_skin_thermal_medium_threshold=%d\n", + chg->pd_skin_thermal_medium_threshold); + + OF_PROP_READ(node, "op,pd-skin-thermal-pre-high-threshold", + chg->pd_skin_thermal_pre_high_threshold, retval, 1); + if (chg->pd_skin_thermal_pre_high_threshold <= 0) + chg->pd_skin_thermal_pre_high_threshold = + SKIN_THERMAL_PRE_HIGH; + pr_info("pd_skin_thermal_pre_high_threshold=%d\n", + chg->pd_skin_thermal_pre_high_threshold); + + chg->enable_pd_current_adjust = of_property_read_bool(node, + "op,enable-pd-current-dynamic-adjust"); + pr_info("enable_pd_current_adjust=%d\n", + chg->enable_pd_current_adjust); + + OF_PROP_READ(node, "op,full-count-sw-numb", + chg->full_count_sw_num, retval, 1); + if (chg->full_count_sw_num <= 0) + chg->full_count_sw_num = + FULL_COUNT_SW_NUM; + pr_info("full_count_sw_num=%d\n", + chg->full_count_sw_num); + /* disable step_chg */ + chg->step_chg_enabled = false; chg->typec_legacy_use_rp_icl = of_property_read_bool(node, "qcom,typec-legacy-rp-icl"); @@ -481,6 +979,39 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) chip->dt.no_battery = of_property_read_bool(node, "qcom,batteryless-platform"); + rc = of_property_read_u32(node, + "qcom,fcc-max-ua", &chip->dt.batt_profile_fcc_ua); + if (rc < 0) + chip->dt.batt_profile_fcc_ua = -EINVAL; + + rc = of_property_read_u32(node, + "qcom,fv-max-uv", &chip->dt.batt_profile_fv_uv); + if (rc < 0) + chip->dt.batt_profile_fv_uv = -EINVAL; + + rc = of_property_read_u32(node, + "qcom,usb-icl-ua", &chip->dt.usb_icl_ua); + if (rc < 0) + chip->dt.usb_icl_ua = -EINVAL; + + rc = of_property_read_u32(node, + "qcom,otg-cl-ua", &chg->otg_cl_ua); + if (rc < 0) + chg->otg_cl_ua = (chip->chg.chg_param.smb_version == + PMI632_SUBTYPE) ? MICRO_1PA : MICRO_3PA; + + rc = of_property_read_u32(node, "qcom,chg-term-src", + &chip->dt.term_current_src); + if (rc < 0) + chip->dt.term_current_src = ITERM_SRC_UNSPECIFIED; + + rc = of_property_read_u32(node, "qcom,chg-term-current-ma", + &chip->dt.term_current_thresh_hi_ma); + + if (chip->dt.term_current_src == ITERM_SRC_ADC) + rc = of_property_read_u32(node, "qcom,chg-term-base-current-ma", + &chip->dt.term_current_thresh_lo_ma); + if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) { chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len, GFP_KERNEL); @@ -545,9 +1076,61 @@ static int smb5_parse_dt_misc(struct smb5 *chip, struct device_node *node) if (rc < 0) chg->otg_delay_ms = OTG_DEFAULT_DEGLITCH_TIME_MS; +/* @bsp 2019/07/05 add usb connector temp detect and wr*/ + rc = of_property_match_string(node, "io-channel-names", + USB_TEM1_ADC_CHANNEL_NAME); + + if (rc >= 0) { + chg->iio.op_connector_temp_chan = iio_channel_get(chg->dev, + USB_TEM1_ADC_CHANNEL_NAME); + if (IS_ERR(chg->iio.op_connector_temp_chan)) { + rc = PTR_ERR(chg->iio.op_connector_temp_chan); + if (rc != -EPROBE_DEFER) + dev_err(chg->dev, + "op_connector_temp_chan channel unavailable,%ld\n", + rc); + chg->iio.op_connector_temp_chan = NULL; + return rc; + } + } + + rc = of_property_match_string(node, "io-channel-names", + USB_TEM2_ADC_CHANNEL_NAME); + if (rc >= 0) { + chg->iio.op_connector_temp_chan_sec = iio_channel_get(chg->dev, + USB_TEM2_ADC_CHANNEL_NAME); + if (IS_ERR(chg->iio.op_connector_temp_chan_sec)) { + rc = PTR_ERR(chg->iio.op_connector_temp_chan_sec); + if (rc != -EPROBE_DEFER) + dev_err(chg->dev, + "op_connector_temp_chan_sec channel unavailable,%ld\n", + rc); + chg->iio.op_connector_temp_chan_sec = NULL; + return rc; + } + } + + rc = of_property_match_string(node, "io-channel-names", + "skin_therm"); + if (rc >= 0) { + chg->iio.op_skin_therm_chan = iio_channel_get(chg->dev, + "skin_therm"); + if (IS_ERR(chg->iio.op_skin_therm_chan)) { + rc = PTR_ERR(chg->iio.op_skin_therm_chan); + if (rc != -EPROBE_DEFER) + dev_err(chg->dev, + "op_skin_therm_chan channel unavailable,%ld\n", + rc); + chg->iio.op_skin_therm_chan = NULL; + return rc; + } + } + chg->fcc_stepper_enable = of_property_read_bool(node, "qcom,fcc-stepping-enable"); - + /* @bsp 2018/12/15 use the usbin_v_chan with low voltage charger */ + chg->low_voltage_charger = of_property_read_bool(node, + "op,low-voltage-charger"); if (chg->uusb_moisture_protection_capable) chg->uusb_moisture_protection_enabled = of_property_read_bool(node, @@ -623,10 +1206,17 @@ static int smb5_parse_dt_adc_channels(struct smb_charger *chg) if (rc < 0) return rc; - rc = smblib_get_iio_channel(chg, "usb_in_voltage", - &chg->iio.usbin_v_chan); - if (rc < 0) - return rc; + if (!chg->iio.mid_chan || chg->low_voltage_charger) { + rc = smblib_get_iio_channel(chg, "usb_in_voltage", + &chg->iio.usbin_v_chan); + if (rc < 0) + return rc; + + if (!chg->iio.usbin_v_chan) { + dev_err(chg->dev, "No voltage channel defined"); + return -EINVAL; + } + } rc = smblib_get_iio_channel(chg, "chg_temp", &chg->iio.temp_chan); if (rc < 0) @@ -796,11 +1386,11 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) return rc; - rc = smb5_parse_dt_adc_channels(chg); + rc = smb5_parse_dt_misc(chip, node); if (rc < 0) return rc; - rc = smb5_parse_dt_misc(chip, node); + rc = smb5_parse_dt_adc_channels(chg); if (rc < 0) return rc; @@ -844,6 +1434,7 @@ static int smb5_set_prop_comp_clamp_level(struct smb_charger *chg, static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_SWARP_ONLINE, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_PD_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_MAX, @@ -851,6 +1442,10 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, +/* @bsp, 2019/07/05 Battery & Charging porting */ + POWER_SUPPLY_PROP_OTG_SWITCH, + POWER_SUPPLY_PROP_HW_DETECT, + POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_LOW_POWER, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, @@ -900,6 +1495,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_ONLINE: rc = smblib_get_usb_online(chg, val); break; + case POWER_SUPPLY_PROP_SWARP_ONLINE: + val->intval = chg->swarp_online; + break; case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: rc = smblib_get_prop_usb_voltage_max_design(chg, val); break; @@ -930,11 +1528,24 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_TYPEC_MODE: rc = smblib_get_usb_prop_typec_mode(chg, val); break; +/* @bsp, 2019/07/05 Add otg switch */ + case POWER_SUPPLY_PROP_OTG_SWITCH: + val->intval = chg->otg_switch; + break; + case POWER_SUPPLY_PROP_HW_DETECT: + val->intval = chg->hw_detect; + break; + case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: rc = smblib_get_prop_typec_power_role(chg, val); break; case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION: - rc = smblib_get_prop_typec_cc_orientation(chg, val); +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION: + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) + val->intval = 0; + else + rc = smblib_get_prop_typec_cc_orientation(chg, val); break; case POWER_SUPPLY_PROP_TYPEC_SRC_RP: rc = smblib_get_prop_typec_select_rp(chg, val); @@ -1049,6 +1660,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, val->intval = (buff[1] << 8 | buff[0]) * 1038; } break; + case POWER_SUPPLY_PROP_DISCONNECT_PD: + val->intval = chg->disconnect_pd; + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -1076,6 +1690,11 @@ static int smb5_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PD_CURRENT_MAX: rc = smblib_set_prop_pd_current_max(chg, val); break; +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_OTG_SWITCH: + rc = vote(chg->otg_toggle_votable, USER_VOTER, + val->intval, 0); + break; case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: rc = smblib_set_prop_typec_power_role(chg, val); break; @@ -1097,6 +1716,7 @@ static int smb5_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CTM_CURRENT_MAX: rc = vote(chg->usb_icl_votable, CTM_VOTER, val->intval >= 0, val->intval); + pr_info("POWER_SUPPLY_PROP_CTM_CURRENT_MAX:%d\n", val->intval); break; case POWER_SUPPLY_PROP_PR_SWAP: rc = smblib_set_prop_pr_swap_in_progress(chg, val); @@ -1156,6 +1776,8 @@ static int smb5_usb_prop_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_OTG_SWITCH: case POWER_SUPPLY_PROP_CTM_CURRENT_MAX: case POWER_SUPPLY_PROP_CONNECTOR_HEALTH: case POWER_SUPPLY_PROP_THERM_ICL_LIMIT: @@ -1226,8 +1848,11 @@ static int smb5_usb_port_get_prop(struct power_supply *psy, break; if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) || + (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM) || + (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) - && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) + && ((chg->real_charger_type == POWER_SUPPLY_TYPE_USB) || + (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP))) val->intval = 1; else val->intval = 0; @@ -1697,6 +2322,19 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, +/* @bsp, 2019/07/05 Battery & Charging porting */ + POWER_SUPPLY_PROP_FASTCHG_IS_OK, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHG_PROTECT_STATUS, + POWER_SUPPLY_PROP_FASTCHG_STATUS, + POWER_SUPPLY_PROP_FASTCHG_STARTING, + POWER_SUPPLY_CUTOFF_VOLT_WITH_CHARGER, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, + POWER_SUPPLY_PROP_IS_AGING_TEST, + POWER_SUPPLY_PROP_CONNECTER_TEMP_ONE, + POWER_SUPPLY_PROP_CONNECTER_TEMP_TWO, + POWER_SUPPLY_PROP_CONNECT_DISABLE, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, @@ -1728,6 +2366,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, }; #define DEBUG_ACCESSORY_TEMP_DECIDEGC 250 @@ -1740,7 +2379,11 @@ static int smb5_batt_get_prop(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: - rc = smblib_get_prop_batt_status(chg, val); +/* @bsp, 2019/07/05 Battery & Charging porting */ + val->intval = get_prop_batt_status(chg); + break; + case POWER_SUPPLY_PROP_FASTCHG_IS_OK: + val->intval = get_prop_fastchg_is_ok(chg)?1:0; break; case POWER_SUPPLY_PROP_HEALTH: rc = smblib_get_prop_batt_health(chg, val); @@ -1757,6 +2400,43 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_get_prop_batt_capacity(chg, val); break; +/* @bsp, 2019/07/05 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CHARGE_NOW: + rc = smblib_get_prop_usb_voltage_now(chg, val); + break; + case POWER_SUPPLY_PROP_CHG_PROTECT_STATUS: + val->intval = get_prop_chg_protect_status(chg); + break; + case POWER_SUPPLY_PROP_FASTCHG_STATUS: + val->intval = get_prop_fastchg_status(chg); + break; + case POWER_SUPPLY_CUTOFF_VOLT_WITH_CHARGER: + val->intval = smbchg_cutoff_volt_with_charger; + break; + case POWER_SUPPLY_PROP_FASTCHG_STARTING: + val->intval = op_get_fastchg_ing(chg); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = chg->chg_enabled; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: + rc = smblib_get_prop_input_current_limited(chg, val); + break; + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: + val->intval = chg->chg_disabled; + break; + case POWER_SUPPLY_PROP_IS_AGING_TEST: + val->intval = chg->is_aging_test; + break; + case POWER_SUPPLY_PROP_CONNECTER_TEMP_ONE: + val->intval = chg->connecter_temp_1; + break; + case POWER_SUPPLY_PROP_CONNECTER_TEMP_TWO: + val->intval = chg->connecter_temp_2; + break; + case POWER_SUPPLY_PROP_CONNECT_DISABLE: + val->intval = chg->disconnect_vbus; + break; case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: rc = smblib_get_prop_system_temp_level(chg, val); break; @@ -1816,6 +2496,8 @@ static int smb5_batt_get_prop(struct power_supply *psy, else rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val); + if (0) + rc = smblib_get_prop_batt_temp(chg, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -1910,6 +2592,92 @@ static int smb5_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: rc = smblib_set_prop_system_temp_level(chg, val); break; +/* @bsp, 2019/07/06 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CHECK_USB_UNPLUG: + if (chg->vbus_present && !chg->dash_present) + update_dash_unplug_status(); + break; + case POWER_SUPPLY_PROP_SWITCH_DASH: + rc = check_allow_switch_dash(chg, val); + break; + case POWER_SUPPLY_PROP_FASTCHG_IS_OK: + rc = 0; + break; + case POWER_SUPPLY_PROP_START_DPDM_RECOVERY: + rc = smblib_start_dpdm_recovery(chg, val->intval); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: + pr_info("set iusb %d mA\n", val->intval); + if (__debug_mask == PR_OP_DEBUG + || val->intval == 2000000 || val->intval == 1700000 + || val->intval == 1500000 || val->intval == 1000000) + op_usb_icl_set(chg, val->intval); + break; + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: + vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, + (bool)val->intval, 0); + if (val->intval) { + switch_mode_to_normal(); + op_set_fast_chg_allow(chg, false); + } + chg->chg_disabled = (bool)val->intval; + pr_info("user set disable chg %d\n", val->intval); + break; + case POWER_SUPPLY_PROP_CONNECT_DISABLE: + op_disconnect_vbus(chg, (bool)val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + rc = smblib_set_prop_chg_voltage(chg, val); + break; + case POWER_SUPPLY_PROP_TEMP: + rc = smblib_set_prop_batt_temp(chg, val); + break; + case POWER_SUPPLY_PROP_CHG_PROTECT_STATUS: + rc = smblib_set_prop_chg_protect_status(chg, val); + break; + case POWER_SUPPLY_PROP_NOTIFY_CHARGER_SET_PARAMETER: + rc = smblib_set_prop_charge_parameter_set(chg); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + if (!val->intval) { + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + switch_mode_to_normal(); + op_set_fast_chg_allow(chg, false); + } + } + rc = vote(chg->usb_icl_votable, USER_VOTER, + !val->intval, 0); + rc = vote(chg->dc_suspend_votable, USER_VOTER, + !val->intval, 0); + chg->chg_enabled = (bool)val->intval; + chg->chg_disabled = !(bool)val->intval; + if (chg->chg_enabled) { + if (!chg->chg_wake_lock_on && chg->vbus_present) { + pr_info("acquire chg_wake_lock\n"); + __pm_stay_awake(chg->chg_wake_lock); + chg->chg_wake_lock_on = true; + } else { + pr_err("chg_wake_lock is already stay awake,vbus_present:%d\n", + chg->vbus_present); + } + } else { + if (chg->chg_wake_lock_on) { + pr_info("release chg_wake_lock\n"); + __pm_relax(chg->chg_wake_lock); + chg->chg_wake_lock_on = false; + } else { + pr_err("chg_wake_lock is already relax."); + } + if (chg->usb_enum_status == false) + op_release_usb_lock(); + } + break; + case POWER_SUPPLY_PROP_IS_AGING_TEST: + chg->is_aging_test = (bool)val->intval; + __debug_mask = PR_OP_DEBUG; + pr_info("user set is_aging_test:%d\n", chg->is_aging_test); + break; case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_set_prop_batt_capacity(chg, val); break; @@ -2002,12 +2770,22 @@ static int smb5_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_SUSPEND: case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: case POWER_SUPPLY_PROP_CAPACITY: +/* @bsp, 2019/07/06 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_CHG_PROTECT_STATUS: + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: + case POWER_SUPPLY_PROP_IS_AGING_TEST: + case POWER_SUPPLY_PROP_CONNECT_DISABLE: + case POWER_SUPPLY_PROP_FASTCHG_IS_OK: case POWER_SUPPLY_PROP_PARALLEL_DISABLE: case POWER_SUPPLY_PROP_DP_DM: case POWER_SUPPLY_PROP_RERUN_AICL: case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: case POWER_SUPPLY_PROP_DIE_HEALTH: + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: return 1; default: break; @@ -2139,6 +2917,7 @@ static int smb5_configure_typec(struct smb_charger *chg) { union power_supply_propval pval = {0, }; int rc; + u8 stat; u8 val = 0; rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val); @@ -2195,14 +2974,34 @@ static int smb5_configure_typec(struct smb_charger *chg) } } + /* add to fix huawei cable compatible issue */ + rc = smblib_write(chg, DEBUG_ACCESS_SNK_CFG_REG, 0x7); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't write DEBUG_ACCESS_SNK_CFG_REG rc=%d\n", rc); + return rc; + } + /* Use simple write to clear interrupts */ - rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, 0); + /* For GCE-2351 issue Debug patch Set 0x155E[3]=1 + * TYPEC_CCOUT_DETACH_INT_EN + */ + rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, + TYPEC_CCOUT_DETACH_INT_EN_BIT); if (rc < 0) { dev_err(chg->dev, "Couldn't configure Type-C interrupts rc=%d\n", rc); return rc; } + rc = smblib_read(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, &stat); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure Type-C interrupts rc=%d\n", rc); + } + pr_info("TYPE_C_INTERRUPT_EN_CFG_1_REG:0x%02x=0x%02x\n", + TYPE_C_INTERRUPT_EN_CFG_1_REG, stat); + val = chg->lpd_disabled ? 0 : TYPEC_WATER_DETECTION_INT_EN_BIT; /* Use simple write to enable only required interrupts */ rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, @@ -2213,7 +3012,27 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } +/* @bsp, 2018/07/13 Add otg switch */ + if (chg->otg_switch) { + rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, + EN_TRY_SNK_BIT, EN_TRY_SNK_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't enable try.snk rc=%d\n", rc); + return rc; + } + chg->typec_try_mode |= EN_TRY_SNK_BIT; + } else { + rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, + EN_SNK_ONLY_BIT, EN_SNK_ONLY_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't enable snk.only rc=%d\n", rc); + return rc; + } + } /* enable try.snk and clear force sink for DRP mode */ +/* rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, EN_TRY_SNK_BIT | EN_SNK_ONLY_BIT, EN_TRY_SNK_BIT); @@ -2223,6 +3042,7 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } chg->typec_try_mode |= EN_TRY_SNK_BIT; +*/ /* For PD capable targets configure VCONN for software control */ if (!chg->pd_not_supported) { @@ -2695,6 +3515,11 @@ static int smb5_init_hw(struct smb5 *chip) smblib_get_charge_param(chg, &chg->param.usb_icl, &chg->default_icl_ua); +/* @bsp, 2019/07/05 Battery & Charging porting */ + pr_info("vbat_max=%d, ibat_max=%d, iusb_max=%d\n", + chg->batt_profile_fv_uv, + chg->batt_profile_fcc_ua, chip->dt.usb_icl_ua); + smblib_get_charge_param(chg, &chg->param.aicl_5v_threshold, &chg->default_aicl_5v_threshold_mv); chg->aicl_5v_threshold_mv = chg->default_aicl_5v_threshold_mv; @@ -2761,7 +3586,15 @@ static int smb5_init_hw(struct smb5 *chip) pr_err("Couldn't disable ICL override rc=%d\n", rc); return rc; } - +/* @bsp, 2019/07/05 Battery & Charging porting */ + vote(chg->usb_icl_votable, + DEFAULT_VOTER, !chg->chg_enabled, 0); + vote(chg->dc_suspend_votable, + DEFAULT_VOTER, !chg->chg_enabled, 0); + smblib_set_charge_param(chg, &chg->param.fcc, + chg->ibatmax[BATT_TEMP_NORMAL] * 1000); + smblib_set_charge_param(chg, &chg->param.fv, + chg->vbatmax[BATT_TEMP_NORMAL] * 1000); /* set OTG current limit */ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, chg->otg_cl_ua); if (rc < 0) { @@ -2774,10 +3607,6 @@ static int smb5_init_hw(struct smb5 *chip) DEFAULT_VOTER, chip->dt.no_battery, 0); vote(chg->dc_suspend_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); - vote(chg->fcc_votable, HW_LIMIT_VOTER, - chip->dt.batt_profile_fcc_ua > 0, chip->dt.batt_profile_fcc_ua); - vote(chg->fv_votable, HW_LIMIT_VOTER, - chip->dt.batt_profile_fv_uv > 0, chip->dt.batt_profile_fv_uv); vote(chg->fcc_votable, BATT_PROFILE_VOTER, chg->batt_profile_fcc_ua > 0, chg->batt_profile_fcc_ua); @@ -2789,6 +3618,19 @@ static int smb5_init_hw(struct smb5 *chip) vote(chg->usb_icl_votable, HW_LIMIT_VOTER, chg->hw_max_icl_ua > 0, chg->hw_max_icl_ua); +/* @bsp, 2018/07/13 Battery & Charging porting */ + /* disable HVDCP */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT, 0); + if (rc < 0) + dev_err(chg->dev, "Couldn't disable HVDCP rc=%d\n", rc); + + /* aicl rerun time */ + rc = smblib_masked_write(chg, AICL_RERUN_TIME_CFG_REG, + BIT(0)|BIT(1), 0); + if (rc < 0) + dev_err(chg->dev, "Couldn't set aicl rerunTimerc=%d\n", rc); + /* Initialize DC peripheral configurations */ rc = smb5_init_dc_peripheral(chg); if (rc < 0) @@ -3470,6 +4312,347 @@ static void smb5_create_debugfs(struct smb5 *chip) #endif +/* @bsp, 2019/07/06 Battery & Charging porting */ +#ifdef CONFIG_PROC_FS +static ssize_t write_ship_mode(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + + if (count) { + g_chip->ship_mode = true; + pr_err(" * * * XCB * * * write ship mode\n"); + } + return count; +} + +static const struct file_operations proc_ship_mode_operations = { + .write = write_ship_mode, + .llseek = noop_llseek, +}; +#endif + +/* @bsp, 2020/06/05 Battery & Charging add for skin_thermal online config */ +static ssize_t proc_skin_thresh_disp_off_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + char page[64]; + int len = 64; + struct smb_charger *chg = g_chip; + + if (chg == NULL) { + pr_err("smb driver is not ready"); + return -ENODEV; + } + + memset(page, 0, len); + len = snprintf(page, len, "Hi:%d,pre-Hi:%d,Med:%d,Nor:%d\n", + chg->skin_thermal_high_threshold_disp_off, + chg->skin_thermal_pre_high_threshold_disp_off, + chg->skin_thermal_medium_threshold_disp_off, + chg->skin_thermal_normal_threshold_disp_off); + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static ssize_t proc_skin_thresh_disp_off_write(struct file *file, const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[32] = { 0 }; + struct smb_charger *chg = g_chip; + int hi_val, pre_hi_val, med_val, nor_val; + int ret = 0; + + if (chg == NULL) { + pr_err("smb driver is not ready"); + return -ENODEV; + } + + if (count > 32) { + pr_err("input too many words."); + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + pr_err("copy parameter from user error.\n"); + return -EFAULT; + } + + pr_info("buffer=%s", buffer); + ret = sscanf(buffer, "%d %d %d %d", &hi_val, &pre_hi_val, &med_val, &nor_val); + pr_err("hi_val=%d, pre_hi_val=%d, med_val=%d, nor_val=%d", + hi_val, pre_hi_val, med_val, nor_val); + + if (ret == 4) { + if ((hi_val >= pre_hi_val) && + (pre_hi_val > med_val) && + (med_val >= nor_val)) { + chg->skin_thermal_high_threshold_disp_off = hi_val; + chg->skin_thermal_pre_high_threshold_disp_off = pre_hi_val; + chg->skin_thermal_medium_threshold_disp_off = med_val; + chg->skin_thermal_normal_threshold_disp_off = nor_val; + } else { + pr_err("val not bigger one by one."); + return -EINVAL; + } + } else { + pr_err("need four decimal number."); + return -EINVAL; + } + + return count; +} + +static const struct file_operations proc_skin_thresh_disp_off_ops = { + .read = proc_skin_thresh_disp_off_read, + .write = proc_skin_thresh_disp_off_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t proc_skin_thresh_disp_on_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int ret = 0; + char page[100]; + int len = 100; + struct smb_charger *chg = g_chip; + + if (chg == NULL) { + pr_err("smb driver is not ready"); + return -ENODEV; + } + + memset(page, 0, len); + len = snprintf(page, len, "Hi:%d,pre-Hi:%d,Litt-Hi:%d,pre-Litt-Hi:%d,Med:%d,Nor:%d\n", + chg->skin_thermal_high_threshold_disp_on, + chg->skin_thermal_pre_high_threshold_disp_on, + chg->skin_thermal_little_high_threshold_disp_on, + chg->skin_thermal_pre_little_high_threshold_disp_on, + chg->skin_thermal_medium_threshold_disp_on, + chg->skin_thermal_normal_threshold_disp_on); + ret = simple_read_from_buffer(buf, count, ppos, page, len); + + return ret; +} + +static ssize_t proc_skin_thresh_disp_on_write(struct file *file, const char __user *buf, + size_t count, loff_t *lo) +{ + char buffer[48] = { 0 }; + struct smb_charger *chg = g_chip; + int hi_val, pre_hi_val, little_hi_val, pre_little_hi_val, med_val, nor_val; + int ret = 0; + + if (chg == NULL) { + pr_err("smb driver is not ready"); + return -ENODEV; + } + + if (count > 48) { + pr_err("input too many words."); + return -EFAULT; + } + + if (copy_from_user(buffer, buf, count)) { + pr_err("copy parameter from user error.\n"); + return -EFAULT; + } + + pr_info("buffer=%s", buffer); + ret = sscanf(buffer, "%d %d %d %d %d %d", + &hi_val, &pre_hi_val, + &little_hi_val, &pre_little_hi_val, + &med_val, &nor_val); + pr_err("hi_val=%d, pre_hi_val=%d, little_hi_val=%d, pre_little_hi_val=%d,med_val=%d, nor_val=%d", + hi_val, pre_hi_val, little_hi_val, pre_little_hi_val, med_val, nor_val); + + if (ret == 6) { + if ((hi_val >= pre_hi_val) && + (little_hi_val >= pre_little_hi_val) && + (pre_hi_val > pre_little_hi_val) && + (pre_little_hi_val > med_val) && + (med_val >= nor_val)) { + chg->skin_thermal_high_threshold_disp_on = hi_val; + chg->skin_thermal_pre_high_threshold_disp_on = pre_hi_val; + chg->skin_thermal_little_high_threshold_disp_on = little_hi_val; + chg->skin_thermal_pre_little_high_threshold_disp_on = pre_little_hi_val; + chg->skin_thermal_medium_threshold_disp_on = med_val; + chg->skin_thermal_normal_threshold_disp_on = nor_val; + } else { + pr_err("val not bigger one by one."); + return -EINVAL; + } + } else { + pr_err("need 6 decimal number."); + return -EINVAL; + } + + return count; +} + +static const struct file_operations proc_skin_thresh_disp_on_ops = { + .read = proc_skin_thresh_disp_on_read, + .write = proc_skin_thresh_disp_on_write, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static int create_skin_thermal_proc(void) +{ + struct proc_dir_entry *skin_threshold_dir; + + skin_threshold_dir = proc_mkdir("skin_temp_thrd", NULL); + if (!skin_threshold_dir) { + pr_err("proc create skin_temp_thrd failed"); + return -EINVAL; + } + + if (!proc_create("fastchg_thd", 0644, skin_threshold_dir, &proc_skin_thresh_disp_on_ops)) + pr_err("Failed to register fastchg_thd proc interface\n"); + + if (!proc_create("fastchg_lcdoff_thd", 0644, skin_threshold_dir, &proc_skin_thresh_disp_off_ops)) + pr_err("Failed to register fastchg_lcdoff_thd proc interface\n"); + + return 0; +} + +/* @bsp, 2018/07/26 Enable external stm6620 ship mode*/ +static int op_ship_mode_gpio_request(struct smb_charger *chip) +{ + int rc; + + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + dev_err(chip->dev, + "Unable to acquire pinctrl\n"); + chip->pinctrl = NULL; + return -EINVAL; + } + + chip->ship_mode_default = + pinctrl_lookup_state(chip->pinctrl, "op_ship_mode_default"); + if (IS_ERR_OR_NULL(chip->ship_mode_default)) { + dev_err(chip->dev, + "Can not lookup ship_mode_default\n"); + devm_pinctrl_put(chip->pinctrl); + chip->pinctrl = NULL; + return PTR_ERR(chip->ship_mode_default); + } + + if (pinctrl_select_state(chip->pinctrl, + chip->ship_mode_default) < 0) + dev_err(chip->dev, "pinctrl set ship_mode_default fail\n"); + + if (gpio_is_valid(chip->shipmode_en)) { + rc = gpio_request(chip->shipmode_en, "stm6620_ctrl"); + if (rc) { + pr_err("gpio_request failed for %d rc=%d\n", + chip->shipmode_en, rc); + return -EINVAL; + } + gpio_direction_output(chip->shipmode_en, 0); + + pr_info("ship_mode_gpio_request default mode success!\n"); + } + + return 0; + +} + +/* @bsp 2018/07/30 add usb connector temp detect and wr*/ +void requset_vbus_ctrl_gpio(struct smb_charger *chg) +{ + int ret; + + if (!gpio_is_valid(chg->vbus_ctrl)) + return; + ret = gpio_request(chg->vbus_ctrl, "VbusCtrl"); + if (ret) + pr_err("request failed,gpio:%d ret=%d\n", chg->vbus_ctrl, ret); +} + +static int op_config_usb_temperature_adc(struct smb_charger *chip) +{ + if (IS_ERR_OR_NULL(chip->pinctrl)) { + chip->pinctrl = devm_pinctrl_get(chip->dev); + if (IS_ERR_OR_NULL(chip->pinctrl)) { + dev_err(chip->dev, + "Unable to acquire pinctrl\n"); + chip->pinctrl = NULL; + return -EINVAL; + } + } + + chip->usb_temperature_default = + pinctrl_lookup_state(chip->pinctrl, "op_usb_temp_adc_default"); + if (IS_ERR_OR_NULL(chip->usb_temperature_default)) { + dev_err(chip->dev, + "Can not lookup op_usb_temp_adc_default\n"); + devm_pinctrl_put(chip->pinctrl); + chip->pinctrl = NULL; + return PTR_ERR(chip->usb_temperature_default); + } + + if (pinctrl_select_state(chip->pinctrl, + chip->usb_temperature_default) < 0) + dev_err(chip->dev, "pinctrl set op_usb_temp_adc_default fail\n"); + + chip->usb_temperature_sec = + pinctrl_lookup_state(chip->pinctrl, "op_usb_temp_adc_sec"); + if (IS_ERR_OR_NULL(chip->usb_temperature_sec)) { + dev_err(chip->dev, + "Can not lookup op_usb_temp_adc_sec\n"); + devm_pinctrl_put(chip->pinctrl); + chip->pinctrl = NULL; + return PTR_ERR(chip->usb_temperature_sec); + } + + if (pinctrl_select_state(chip->pinctrl, + chip->usb_temperature_sec) < 0) + dev_err(chip->dev, "pinctrl set op_usb_temp_adc_sec fail\n"); + return 0; +} + +/*usb connector hw auto detection*/ +static irqreturn_t op_usb_plugin_irq_handler(int irq, void *dev_id) +{ + schedule_work(&g_chip->otg_switch_work); + return IRQ_HANDLED; +} + +static void request_plug_irq(struct smb_charger *chip) +{ + int ret; + + if (!gpio_is_valid(chip->plug_irq)) + return; + ret = gpio_request(chip->plug_irq, "op_usb_plug"); + if (ret) { + pr_err("request failed,gpio:%d ret=%d\n", chip->plug_irq, ret); + return; + } + gpio_direction_input(chip->plug_irq); + ret = request_irq(gpio_to_irq(chip->plug_irq), + op_usb_plugin_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "op_usb_plug", chip); + if (ret < 0) { + pr_err("request usb_plug irq failed.\n"); + return; + } + enable_irq_wake(gpio_to_irq(chip->plug_irq)); + pr_info("request usb_plug irq success\n"); + /*connect with usb cable when reboot, give a vote 1*/ + if (!gpio_get_value(chip->plug_irq)) { + pr_info("%s:reboot time hw detect gpio low, vote 1\n", + __func__); + vote(chip->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); + chip->hw_detect = 1; + } +} + static int smb5_show_charger_status(struct smb5 *chip) { struct smb_charger *chg = &chip->chg; @@ -3548,16 +4731,26 @@ static int smb5_probe(struct platform_device *pdev) struct smb5 *chip; struct smb_charger *chg; int rc = 0; + struct msm_bus_scale_pdata *pdata; + union power_supply_propval val; + int usb_present; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chg = &chip->chg; +/* @bsp, 2019/07/06 Battery & Charging porting */ + g_chip = chg; chg->dev = &pdev->dev; chg->debug_mask = &__debug_mask; chg->pd_disabled = 0; chg->weak_chg_icl_ua = 500000; + chg->usb_connector_temp = &__usb_connector_temp; + chg->usb_interval_temp = &__usb_interval_temp; + chg->disable_connector_protect = &__disable_connector_protect; + chg->call_on = &__call_on; + chg->video_call_on = &__video_call_on; chg->mode = PARALLEL_MASTER; chg->irq_info = smb5_irqs; chg->die_health = -EINVAL; @@ -3600,6 +4793,16 @@ static int smb5_probe(struct platform_device *pdev) /* set driver data before resources request it */ platform_set_drvdata(pdev, chip); +/* @bsp, 2019/07/06 Fix abnormal animation */ + op_charge_info_init(chg); +if (0) { + pdata = msm_bus_cl_get_pdata(pdev); + if (!pdata) + pr_err("GPIO** failed get_pdata client_id\n"); + else + chg->bus_client = msm_bus_scale_register_client(pdata); +} + /* extcon registration */ chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable); if (IS_ERR(chg->extcon)) { @@ -3738,10 +4941,43 @@ static int smb5_probe(struct platform_device *pdev) goto free_irq; } +/* @bsp, 2019/07/06 Battery & Charging porting */ +#ifdef CONFIG_PROC_FS + if (!proc_create("ship_mode", 0644, NULL, &proc_ship_mode_operations)) + pr_err("Failed to register proc interface\n"); +#endif + + rc = create_skin_thermal_proc(); + if (rc < 0) + pr_err("create skin thermal threshold proc failed."); + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + pr_err("Couldn't get usb present rc=%d\n", rc); + goto cleanup; + } + usb_present = val.intval; + + if (usb_present) { + schedule_delayed_work(&chg->non_standard_charger_check_work, + msecs_to_jiffies(TIME_1000MS)); + chg->boot_usb_present = true; + } + if (!usb_present && chg->vbus_present) + op_handle_usb_plugin(chg); + device_init_wakeup(chg->dev, true); - pr_info("QPNP SMB5 probed successfully\n"); +/* @bsp, 2019/07/05 Battery & Charging porting */ + op_ship_mode_gpio_request(chg); +/* add usb connector temp detect and wr*/ + requset_vbus_ctrl_gpio(chg); + op_config_usb_temperature_adc(chg); +/*usb connector hw auto detection*/ + request_plug_irq(chg); + //check_factory_mode_disable_charge(chg); + pr_info("QPNP SMB5 probed successfully yfb\n"); return rc; free_irq: @@ -3770,11 +5006,47 @@ static int smb5_remove(struct platform_device *pdev) return 0; } +/* @bsp, 2019/07/05 Battery & Charging porting */ +static void stm6620_enter_ship_mode(struct smb_charger *chg) +{ + int i; + + for (i = 0; i < 5; i++) { + gpio_set_value(chg->shipmode_en, 1); + usleep_range(4000, 4001); + gpio_set_value(chg->shipmode_en, 0); + usleep_range(4000, 4001); + } +} + static void smb5_shutdown(struct platform_device *pdev) { struct smb5 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; +/* @bsp, 2019/07/05 Battery & Charging porting */ +#ifdef CONFIG_PROC_FS + pr_info("smbchg_shutdown\n"); + + if (chg->ship_mode) { + pr_info("smbchg_shutdown enter ship_mode\n"); + /* Enable external stm6620 ship mode */ + if (gpio_is_valid(chg->shipmode_en)) { + vote(chg->usb_icl_votable, + DEFAULT_VOTER, true, 0); + stm6620_enter_ship_mode(chg); + } else { + smblib_masked_write(chg, SHIP_MODE_REG, + SHIP_MODE_EN_BIT, SHIP_MODE_EN_BIT); + } + clean_backup_soc_ex(); + msleep(1000); + pr_err("after 1s\n"); + while (1) + ; + } +#endif + /* disable all interrupts */ smb5_disable_interrupts(chg); diff --git a/drivers/power/supply/qcom/smb1398-charger.c b/drivers/power/supply/qcom/smb1398-charger.c index 196b99402de35d4e8fce6a3d647b0606116fc186..b2500485e2703f413a453b1aefa8ce0495ad361e 100644 --- a/drivers/power/supply/qcom/smb1398-charger.c +++ b/drivers/power/supply/qcom/smb1398-charger.c @@ -2014,6 +2014,7 @@ static int smb1398_div2_cp_hw_init(struct smb1398_chip *chip) return rc; } +#define DIV2_CP_MIN_ILIM_UA 1000000 static int smb1398_div2_cp_parse_dt(struct smb1398_chip *chip) { int rc = 0; @@ -2036,9 +2037,14 @@ static int smb1398_div2_cp_parse_dt(struct smb1398_chip *chip) return rc; } - chip->div2_cp_min_ilim_ua = 750000; of_property_read_u32(chip->dev->of_node, "qcom,div2-cp-min-ilim-ua", &chip->div2_cp_min_ilim_ua); + /* + * Set minimum allowed ilim configuration to 1A for DIV2_CP + * operation. + */ + if (chip->div2_cp_min_ilim_ua < DIV2_CP_MIN_ILIM_UA) + chip->div2_cp_min_ilim_ua = DIV2_CP_MIN_ILIM_UA; chip->max_cutoff_soc = 85; of_property_read_u32(chip->dev->of_node, "qcom,max-cutoff-soc", diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 7818896c62c90ad1cc5885b8841e88a78e3e818a..2a44dedae14d80a4cd2cbc0902a8712086e545db 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -2,6 +2,11 @@ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. */ +/* @bsp, 2019/07/06 Battery & Charging porting */ +#define pr_fmt(fmt) "SMBLIB: %s: " fmt, __func__ + +#define CONFIG_MSM_RDM_NOTIFY +#undef CONFIG_FB #include #include @@ -19,7 +24,95 @@ #include "schgm-flash.h" #include "step-chg-jeita.h" #include "storm-watch.h" -#include "schgm-flash.h" + +/* @bsp, 2019/07/06 Battery & Charging porting */ +#include +#include +#include +#include +#include +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_MSM_RDM_NOTIFY) +#include +/* @bsp, 2019/10/22 add new panel node for PD charging */ +#include +#include +#endif /*CONFIG_FB*/ +#include +#include +/* @bsp 2018/07/30 add usb connector temp detect and wr*/ +#include +#include +#include + +#define SOC_INVALID 0x7E +#define SOC_DATA_REG_0 0x88D /* PON_XVDD_RB_SPARE_REG */ +#define SOC_FLAG_REG 0x88D +#define HEARTBEAT_INTERVAL_MS 6000 +#define CHG_TIMEOUT_COUNT 6000 /* 10hr */ +#define CHG_SOFT_OVP_MV 5800 +#define BATT_SOFT_OVP_MV 4500 +#define CHG_SOFT_UVP_MV 4300 +#define CHG_VOLTAGE_NORMAL 5000 +#define BATT_REMOVE_TEMP -400 +#define BATT_TEMP_HYST 20 +#define DASH_VALID_TEMP_LOW_THRESHOLD 125 +#define DASH_VALID_TEMP_HIG_THRESHOLD 430 + +#define PDO_SELECTION_INTERVAL_MS 5000 + +struct smb_charger *g_chg; +struct regmap *pm_regmap; + +static struct external_battery_gauge *fast_charger; +static int op_charging_en(struct smb_charger *chg, bool en); +static bool set_prop_fast_switch_to_normal_false(struct smb_charger *chg); + +static void op_battery_temp_region_set(struct smb_charger *chg, + enum temp_region_type batt_temp_region); +static void set_usb_switch(struct smb_charger *chg, bool enable); +static void op_handle_usb_removal(struct smb_charger *chg); +static bool get_prop_fast_switch_to_normal(struct smb_charger *chg); +static int get_prop_batt_temp(struct smb_charger *chg); +static int get_prop_batt_capacity(struct smb_charger *chg); +static int get_prop_batt_current_now(struct smb_charger *chg); +static int get_prop_batt_voltage_now(struct smb_charger *chg); +static int set_property_on_fg(struct smb_charger *chg, + enum power_supply_property prop, int val); +static int set_dash_charger_present(int status); +static enum temp_region_type + op_battery_temp_region_get(struct smb_charger *chg); +static int get_prop_fg_capacity(struct smb_charger *chg); +static int get_prop_fg_current_now(struct smb_charger *chg); +static int get_prop_fg_voltage_now(struct smb_charger *chg); +static void op_check_charger_collapse(struct smb_charger *chg); +static int op_set_collapse_fet(struct smb_charger *chg, bool on); +static int op_check_battery_temp(struct smb_charger *chg); +/* add usb connector temp detect and wr*/ +static int get_usb_temp(struct smb_charger *chg); +static void op_clean_dash_status(void); +/* avoid abnormal icl set after switch fast charge to normal charge begin*/ +static void op_typec_state_change_irq_handler(void); +/* @bsp, add to check enumeration status after boot */ +static int sys_boot_complete; +static int usb_enum_check(const char *val, const struct kernel_param *kp); +static enum batt_status_type op_battery_status_get(struct smb_charger *chg); + +/* @bsp, 2020/08/04, add to detect SVID */ +static void op_register_pps_work(struct work_struct *work); +static void pps_usbpd_connect_cb(struct usbpd_svid_handler *hdlr, + bool peer_usb_comm); +static void pps_usbpd_disconnect_cb(struct usbpd_svid_handler *hdlr); +static struct op_pps op_pps_chg; + +static bool is_usb_present(struct smb_charger *chg); +static void op_chek_apsd_done_work(struct work_struct *work); + +module_param_call(sys_boot_complete, usb_enum_check, param_get_int, + &sys_boot_complete, 0644); +MODULE_PARM_DESC(sys_boot_complete, "sys_boot_complete"); #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ @@ -40,8 +133,21 @@ || typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) \ && (!chg->typec_legacy || chg->typec_legacy_use_rp_icl)) +static bool lcd_status; + static void update_sw_icl_max(struct smb_charger *chg, int pst); static int smblib_get_prop_typec_mode(struct smb_charger *chg); +enum oem_dddboot_mode { + MSM_BOOT_MODE__NORMAL, + MSM_BOOT_MODE__FASTBOOT, + MSM_BOOT_MODE__RECOVERY, + MSM_BOOT_MODE__AGING, + MSM_BOOT_MODE__FACTORY, + MSM_BOOT_MODE__RF, + MSM_BOOT_MODE__WLAN, + MSM_BOOT_MODE__MOS, + MSM_BOOT_MODE__CHARGE, +}; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val) { @@ -371,6 +477,37 @@ static void smblib_notify_usb_host(struct smb_charger *chg, bool enable) extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable); } +/* @bsp, 2018/07/13 Battery & Charging porting */ +#define DEFAULT_SDP_MA 500 +#define DEFAULT_CDP_MA 1500 +#define DEFAULT_DCP_MA 2000 +#define DEFAULT_AGAING_CHG_MA 1500 +int op_rerun_apsd(struct smb_charger *chg) +{ + union power_supply_propval val; + int rc; + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return rc; + } + + if (!val.intval) + return 0; + /* rerun APSD */ + pr_info("OP Reruning APSD type\n"); + chg->switch_on_fastchg = false; + rc = smblib_masked_write(chg, CMD_APSD_REG, + APSD_RERUN_BIT, + APSD_RERUN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't rerun APSD rc = %d\n", rc); + return rc; + } + return 0; +} + /******************** * REGISTER GETTERS * ********************/ @@ -513,7 +650,8 @@ static const struct apsd_result smblib_apsd_results[] = { [FLOAT] = { .name = "FLOAT", .bit = FLOAT_CHARGER_BIT, - .pst = POWER_SUPPLY_TYPE_USB_FLOAT +/* @bsp, 2019/07/05 Battery & Charging porting */ + .pst = POWER_SUPPLY_TYPE_USB_DCP }, [HVDCP2] = { .name = "HVDCP2", @@ -539,10 +677,11 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) return result; } smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat); - - if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT)) +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT)) { + pr_info("APSD_DTC_STATUS_DONE_BIT is 0\n"); return result; - + } rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n", @@ -550,6 +689,7 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) return result; } stat &= APSD_RESULT_STATUS_MASK; + pr_err("APSD_RESULT_STATUS = 0x%02x\n", stat); for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) { if (smblib_apsd_results[i].bit == stat) @@ -721,6 +861,21 @@ int smblib_set_charge_param(struct smb_charger *chg, int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; +/* @bsp, 2019/07/06 Battery & Charging porting */ + int boot_mode = 0; + + boot_mode = get_boot_mode(); + pr_info("suspend=%d\n", suspend); + + if (!suspend) { + if (boot_mode == MSM_BOOT_MODE__RF + || boot_mode == MSM_BOOT_MODE__FACTORY) { + pr_info("RF/WLAN,ingnore suspend=%d,keep charge disable!\n", + suspend); + return 0; + } + } + if (suspend) vote(chg->icl_irq_disable_votable, USB_SUSPEND_VOTER, true, 0); @@ -741,6 +896,8 @@ int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; +/* @bsp, 2019/07/06 Battery & Charging porting */ + pr_info("%d\n", suspend); rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT, suspend ? DCIN_SUSPEND_BIT : 0); @@ -1085,23 +1242,20 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) { const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); - /* if PD is active, APSD is disabled so won't have a valid result */ - if (chg->pd_active) { - chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; - } else if (chg->qc3p5_detected) { - chg->real_charger_type = POWER_SUPPLY_TYPE_USB_HVDCP_3P5; +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (chg->dash_on) { + chg->real_charger_type = POWER_SUPPLY_TYPE_DASH; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_DASH; } else { - /* - * Update real charger type only if its not FLOAT - * detected as as SDP - */ - if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT && - chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) - chg->real_charger_type = apsd_result->pst; + chg->usb_psy_desc.type = apsd_result->pst; + /* if PD is active, APSD is disabled so won't have a valid result */ + chg->real_charger_type = chg->pd_active ? + POWER_SUPPLY_TYPE_USB_PD : apsd_result->pst; } - smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d QC3P5=%d\n", - apsd_result->name, chg->pd_active, chg->qc3p5_detected); + smblib_err(chg, "APSD=%s PD=%d dash_on=%d real_charger_type=%d\n", + apsd_result->name, chg->pd_active, + chg->dash_on, chg->real_charger_type); return apsd_result; } @@ -1214,8 +1368,7 @@ static void smblib_uusb_removal(struct smb_charger *chg) /* reset both usbin current and voltage votes */ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); - vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - is_flash_active(chg) ? SDP_CURRENT_UA : SDP_100_MA); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_CURRENT_UA); vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0); vote(chg->usb_icl_votable, CHG_TERMINATION_VOTER, false, 0); @@ -1410,6 +1563,63 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return rc; } +/* @bsp, 2019/07/05 Battery & Charging porting */ +void op_bus_vote(int disable) +{ + int ret; + + if (!g_chg) + return; + + ret = msm_bus_scale_client_update_request(g_chg->bus_client, disable); + + if (ret) { + pr_err("%s: failed: bus_client_handle=0x%x, vote=%d, err=%d\n", + __func__, g_chg->bus_client, disable, ret); + } + pr_info("enable =%d\n", disable); +} + +int op_usb_icl_set(struct smb_charger *chg, int icl_ua) +{ + int rc = 0; + bool override; + + pr_info("icl_ua=%d\n", icl_ua); + + disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq); + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + icl_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc); + goto enable_icl_changed_interrupt; + } + + /* determine if override needs to be enforced */ + override = true; + /* enforce override */ + rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, + USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0); + + rc = smblib_icl_override(chg, SW_OVERRIDE_HC_MODE); + if (rc < 0) { + smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc); + goto enable_icl_changed_interrupt; + } + + /* unsuspend after configuring current and override */ + rc = smblib_set_usb_suspend(chg, false); + if (rc < 0) { + smblib_err(chg, "Couldn't resume input rc=%d\n", rc); + goto enable_icl_changed_interrupt; + } + +enable_icl_changed_interrupt: + enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq); + + return rc; +} + int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { int rc = 0; @@ -1417,6 +1627,9 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) /* suspend if 25mA or less is requested */ bool suspend = (icl_ua <= USBIN_25MA); + /* @bsp, 2019/07/05 Battery & Charging porting */ + pr_info("icl_ua=%d\n", icl_ua); + if (chg->chg_param.smb_version == PMI632_SUBTYPE) schgm_flash_torch_priority(chg, suspend ? TORCH_BOOST_MODE : TORCH_BUCK_MODE); @@ -1425,7 +1638,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) if (smblib_get_prop_typec_mode(chg) == POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY) return 0; - +/* @bsp, 2019/07/05 Battery & Charging porting */ if (suspend) return smblib_set_usb_suspend(chg, true); @@ -1437,6 +1650,14 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) && (chg->typec_legacy || chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) { +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (chg->non_std_chg_present) { + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + icl_ua); + icl_override = HW_AUTO_MODE; + } else + rc = set_sdp_current(chg, icl_ua); + rc = set_sdp_current(chg, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc); @@ -1669,11 +1890,33 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } +/*usb connector hw auto detection*/ +static int smblib_otg_toggle_vote_callback(struct votable *votable, + void *data, int value, const char *client) +{ + struct smb_charger *chg = data; + int rc = 0; + + if (value < 0) + value = 0; + + rc = op_set_prop_otg_switch(chg, (bool)value); + if (rc < 0) { + smblib_err(chg, "Can not set otg switch,value=%d, rc=%d\n", + value, rc); + return rc; + } + + return rc; +} + static int smblib_awake_vote_callback(struct votable *votable, void *data, int awake, const char *client) { struct smb_charger *chg = data; +/* @bsp, 2019/07/05 Battery & Charging porting */ + pr_info("set awake=%d\n", awake); if (awake) pm_stay_awake(chg->dev); else @@ -1688,6 +1931,8 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data, struct smb_charger *chg = data; int rc; +/* @bsp, 2019/07/05 Battery & Charging porting */ + pr_err("set chg_disable=%d\n", chg_disable); rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG, CHARGING_ENABLE_CMD_BIT, chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT); @@ -2179,9 +2424,8 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg, int smblib_get_prop_batt_health(struct smb_charger *chg, union power_supply_propval *val) { - union power_supply_propval pval; int rc; - int effective_fv_uv; + u8 stat; rc = smblib_read(chg, BATTERY_CHARGER_STATUS_2_REG, &stat); @@ -2194,22 +2438,8 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - rc = smblib_get_prop_from_bms(chg, - POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); - if (!rc) { - /* - * If Vbatt is within 40mV above Vfloat, then don't - * treat it as overvoltage. - */ - effective_fv_uv = get_effective_result_locked( - chg->fv_votable); - if (pval.intval >= effective_fv_uv + 40000) { - val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n", - pval.intval, effective_fv_uv); - goto done; - } - } +/* @bsp, 2019/07/05 Battery & Charging porting */ + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } rc = smblib_read(chg, BATTERY_CHARGER_STATUS_7_REG, &stat); @@ -2229,7 +2459,6 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, else val->intval = POWER_SUPPLY_HEALTH_GOOD; -done: return rc; } @@ -2312,6 +2541,24 @@ int smblib_get_prop_batt_iterm(struct smb_charger *chg, return rc; } +/* @bsp, 2019/07/05 Battery & Charging porting */ +int smblib_get_prop_batt_temp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + if (chg->use_fake_temp) { + val->intval = chg->fake_temp; + return 0; + } + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_TEMP, val); + return rc; +} int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) @@ -2339,7 +2586,7 @@ int smblib_get_batt_current_now(struct smb_charger *chg, rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CURRENT_NOW, val); if (!rc) - val->intval *= (-1); + val->intval *= 1; return rc; } @@ -2372,6 +2619,141 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg, return rc; } +/* @bsp, 2018/07/13 Battery & Charging porting */ +int op_set_prop_otg_switch(struct smb_charger *chg, + bool enable) +{ + int rc = 0; + u8 power_role; + u8 ctrl = 0; + bool pre_otg_switch; + int i = 0; + + pre_otg_switch = chg->otg_switch; + chg->otg_switch = enable; + + if (chg->otg_switch == pre_otg_switch) + return rc; + + pr_info("set otg_switch=%d\n", chg->otg_switch); + if (chg->otg_switch) + power_role = EN_TRY_SNK_BIT; + else + power_role = EN_SNK_ONLY_BIT; + + for (i = 0; i < 10; i++) { + rc = smblib_masked_write(chg, + TYPE_C_MODE_CFG_REG, + TYPEC_POWER_ROLE_CMD_MASK, power_role); + if (rc < 0) { + smblib_err(chg, "Couldn't write 0x%02x to 0x1544 rc=%d\n", + power_role, rc); + return rc; + } + usleep_range(30000, 31000); + ctrl = 0; + rc = smblib_read(chg, + TYPE_C_MODE_CFG_REG, &ctrl); + if (rc < 0) { + smblib_err(chg, "Couldn't read err=%d\n", rc); + return rc; + } + if ((power_role == EN_TRY_SNK_BIT) && (ctrl & EN_TRY_SNK_BIT)) + break; + if ((power_role == EN_SNK_ONLY_BIT) && (ctrl & EN_SNK_ONLY_BIT)) + break; + } + pr_info("retry time = %d,ctrl = %d\n", i, ctrl); + if (i == 10) + pr_err("retry time over\n"); + + return rc; + +} + +int smblib_start_dpdm_recovery(struct smb_charger *chg, bool enable) +{ + int rc = 0; + + pr_err("enter >>>, enable:%d\n", enable); + if (enable) { + if (is_usb_present(chg)) { + pr_err("Start recovering charger..!!"); + if (chg->dpdm_reg && chg->dpdm_enabled) { + pr_err("locking dpdm mutex"); + mutex_lock(&chg->dpdm_lock); + + pr_err("Disable DPDM regulator"); + rc = regulator_disable(chg->dpdm_reg); + if (rc < 0) + pr_err("fail to disable dpdm reg rc=%d", + rc); + + msleep(50); + + pr_err("Enable DPDM regulator"); + rc = regulator_enable(chg->dpdm_reg); + if (rc < 0) + pr_err("fail to enable dpdm reg rc=%d", + rc); + + pr_err("unlocking dpdm mutex"); + mutex_unlock(&chg->dpdm_lock); + pr_err("set USB switch to false before APSD rerun"); + set_usb_switch(chg, false); + pr_err("Start APSD rerun"); + rc = smblib_masked_write(chg, CMD_APSD_REG, + APSD_RERUN_BIT, + APSD_RERUN_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't rerun APSD rc = %d\n", rc); + } + } + } else { + pr_err("Stop recovering charger..!!"); + } + + pr_err("<<< exit, rc=%d\n", rc); + return rc; +} + +int smblib_set_prop_chg_voltage(struct smb_charger *chg, + const union power_supply_propval *val) +{ + chg->fake_chgvol = val->intval; + chg->use_fake_chgvol = true; + power_supply_changed(chg->batt_psy); + + return 0; +} + +int smblib_set_prop_batt_temp(struct smb_charger *chg, + const union power_supply_propval *val) +{ + chg->fake_temp = val->intval; + chg->use_fake_temp = true; + power_supply_changed(chg->batt_psy); + + return 0; +} + +int smblib_set_prop_chg_protect_status(struct smb_charger *chg, + const union power_supply_propval *val) +{ + chg->fake_protect_sts = val->intval; + chg->use_fake_protect_sts = true; + power_supply_changed(chg->batt_psy); + + return 0; +} + +int smblib_set_prop_charge_parameter_set(struct smb_charger *chg) +{ + chg->is_power_changed = true; + op_check_battery_temp(chg); + return 0; +} + int smblib_set_prop_batt_capacity(struct smb_charger *chg, const union power_supply_propval *val) { @@ -2466,6 +2848,11 @@ int smblib_run_aicl(struct smb_charger *chg, int type) return rc; smblib_dbg(chg, PR_MISC, "re-running AICL\n"); +/* @bsp, 2019/07/05 Battery & Charging porting */ +/* @bsp enable aicl_rerun before rerurn aicl */ + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + USBIN_AICL_PERIODIC_RERUN_EN_BIT, + USBIN_AICL_PERIODIC_RERUN_EN_BIT); stat = (type == RERUN_AICL) ? RERUN_AICL_BIT : RESTART_AICL_BIT; rc = smblib_masked_write(chg, AICL_CMD_REG, stat, stat); @@ -3276,6 +3663,17 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, return rc; } +/* @bsp, 2019/07/05 Battery & Charging porting */ +/* @bsp, Fix power off charging loop */ + if (chg->vbus_present) { + val->intval = true; + return rc; + } + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + val->intval = true; + return rc; + } if (is_client_vote_enabled_locked(chg->usb_icl_votable, CHG_TERMINATION_VOTER)) { rc = smblib_get_prop_usb_present(chg, val); @@ -3306,13 +3704,17 @@ int smblib_get_usb_online(struct smb_charger *chg, goto exit; if (((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) || + (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM) || + (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) || (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) - && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) + && ((chg->real_charger_type == POWER_SUPPLY_TYPE_USB) || + (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_CDP))) val->intval = 0; else val->intval = 1; - if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN) + if (chg->real_charger_type == POWER_SUPPLY_TYPE_UNKNOWN && + !chg->pd_active) val->intval = 0; exit: @@ -3406,7 +3808,8 @@ static int smblib_estimate_adaptor_voltage(struct smb_charger *chg, val->intval = MICRO_5V; break; } - +/* @bsp, 2019/07/05 Battery & Charging porting */ + val->intval = val->intval / 1000; return 0; } @@ -3428,8 +3831,10 @@ static int smblib_read_mid_voltage_chan(struct smb_charger *chg, * If MID voltage < 1V, it is unreliable. * Figure out voltage from registers and calculations. */ +/* @bsp, 2019/07/05 Battery & Charging porting */ if (val->intval < 1000000) - return smblib_estimate_adaptor_voltage(chg, val); + smblib_estimate_adaptor_voltage(chg, val); + val->intval = val->intval / 1000; return 0; } @@ -3442,11 +3847,13 @@ static int smblib_read_usbin_voltage_chan(struct smb_charger *chg, if (!chg->iio.usbin_v_chan) return -ENODATA; +/* @bsp, Vbus switch uV to mV*/ rc = iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval); if (rc < 0) { smblib_err(chg, "Couldn't read USBIN channel rc=%d\n", rc); return rc; } + val->intval = val->intval / 1000; return 0; } @@ -3487,6 +3894,13 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, goto restore_adc_config; } + /* usb not present */ + if (!pval.intval) { + val->intval = 0; + //return 0; + goto unlock; + } + /* * Skip reading voltage only if USB is not present and we are not in * OTG mode. @@ -3507,7 +3921,9 @@ int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, * to occur randomly in the USBIN channel, particularly at high * voltages. */ - if (chg->chg_param.smb_version == PM8150B_SUBTYPE) +/* @bsp use the usbin_v_chan with low voltage charger */ + if (chg->chg_param.smb_version == PM8150B_SUBTYPE && pval.intval + && !chg->low_voltage_charger) rc = smblib_read_mid_voltage_chan(chg, val); else rc = smblib_read_usbin_voltage_chan(chg, val); @@ -3579,6 +3995,8 @@ bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) goto cleanup; } + pr_info("r_sbu1:(%d)uv, r_thr:(%d)uv\n", r_sbu1, r_thr); + if (r_sbu1 < r_thr) { ret = true; goto cleanup; @@ -3597,6 +4015,8 @@ bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) goto cleanup; } + pr_info("r_sbu1:(%d)uv, r_thr:(%d)uv\n", r_sbu1, r_thr); + if (r_sbu2 < r_thr) ret = true; cleanup: @@ -3694,6 +4114,11 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) switch (stat & DETECTED_SRC_TYPE_MASK) { case SNK_RP_STD_BIT: + /* @bsp add to fix huawei cable compatible issue + * to handle RP_RP bit6 to detect as source + * instead of DAM + */ + case SNK_DAM_500MA_BIT: return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; case SNK_RP_1P5_BIT: return POWER_SUPPLY_TYPEC_SOURCE_MEDIUM; @@ -3701,7 +4126,6 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) return POWER_SUPPLY_TYPEC_SOURCE_HIGH; case SNK_RP_SHORT_BIT: return POWER_SUPPLY_TYPEC_NON_COMPLIANT; - case SNK_DAM_500MA_BIT: case SNK_DAM_1500MA_BIT: case SNK_DAM_3000MA_BIT: return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY; @@ -3730,6 +4154,8 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg) switch (stat & DETECTED_SNK_TYPE_MASK) { case AUDIO_ACCESS_RA_RA_BIT: +/* @bsp, 2019/07/05 Battery & Charging porting */ + chg->is_audio_adapter = true; return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER; case SRC_DEBUG_ACCESS_BIT: return POWER_SUPPLY_TYPEC_SINK_DEBUG_ACCESSORY; @@ -3766,7 +4192,8 @@ static int smblib_get_prop_typec_mode(struct smb_charger *chg) inline int smblib_get_usb_prop_typec_mode(struct smb_charger *chg, union power_supply_propval *val) { - if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB || + chg->disconnect_pd) val->intval = POWER_SUPPLY_TYPEC_NONE; else val->intval = chg->typec_mode; @@ -4212,19 +4639,30 @@ int smblib_get_prop_connector_health(struct smb_charger *chg) return POWER_SUPPLY_HEALTH_COOL; } +#define PD_PANELON_CURRENT_UA 2000000 +#define PD_PANELOFF_CURRENT_UA 2000000 +#define DCP_PANELOFF_CURRENT_UA 2000000 static int get_rp_based_dcp_current(struct smb_charger *chg, int typec_mode) { int rp_ua; switch (typec_mode) { case POWER_SUPPLY_TYPEC_SOURCE_HIGH: - rp_ua = TYPEC_HIGH_CURRENT_UA; + /* @bsp add to set pd charging current 2.0A when panel on */ + if (chg->oem_lcd_is_on) + rp_ua = PD_PANELON_CURRENT_UA; + else + rp_ua = PD_PANELOFF_CURRENT_UA; break; case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM: case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT: /* fall through */ default: - rp_ua = DCP_CURRENT_UA; +/* add to set DCP charging current 2.0A when panel off */ + if (chg->oem_lcd_is_on) + rp_ua = DCP_CURRENT_UA; + else + rp_ua = DCP_PANELOFF_CURRENT_UA; } return rp_ua; @@ -4248,6 +4686,12 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg, rc = -EPERM; } + /* @bsp add to set pd charging current 2.0A when panel on */ + if (chg->oem_lcd_is_on) { + rc = vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, PD_PANELON_CURRENT_UA); + } + return rc; } @@ -4342,6 +4786,8 @@ int smblib_set_prop_sdp_current_max(struct smb_charger *chg, union power_supply_propval pval; int rc = 0; +/* @bsp, 2019/07/05 Battery & Charging porting */ + pr_err("set usb current_max=%d\n", val->intval); if (!chg->pd_active) { rc = smblib_get_prop_usb_present(chg, &pval); if (rc < 0) { @@ -4507,6 +4953,9 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, smblib_err(chg, "power role %d not supported\n", val->intval); return -EINVAL; } +/* @bsp, 2019/07/05 Add otg switch */ + if (!chg->otg_switch) + power_role = EN_SNK_ONLY_BIT; rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, TYPEC_POWER_ROLE_CMD_MASK | TYPEC_TRY_MODE_MASK, @@ -4597,6 +5046,7 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg, return rc; } +#define PD_FCC_CURRENT_UA 3800000 int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val) { @@ -4604,21 +5054,38 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, int rc = 0; int sec_charger, typec_mode; + int temp_region = 0; /* * Ignore repetitive notification while PD is active, which * is caused by hard reset. */ - if (chg->pd_active && chg->pd_active == val->intval) + if (chg->pd_active && chg->pd_active == val->intval) { + op_usbpd_send_svdm(USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY, + SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); + cancel_delayed_work(&chg->pdo_select_check_work); + schedule_delayed_work(&chg->pdo_select_check_work, + msecs_to_jiffies(2000)); return 0; + } chg->pd_active = val->intval; + if (chg->swarp_online && chg->switch_on_fastchg) + return 0; + smblib_apsd_enable(chg, !chg->pd_active); update_sw_icl_max(chg, apsd->pst); if (chg->pd_active) { + + smblib_set_prop_charge_parameter_set(chg); + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_COLD + && temp_region != BATT_TEMP_HOT) { + op_charging_en(chg, true); + } vote(chg->limited_irq_disable_votable, CHARGER_TYPE_VOTER, false, 0); vote(chg->hdc_irq_disable_votable, CHARGER_TYPE_VOTER, @@ -4633,6 +5100,21 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + /* + * @bsp add to fix wrong charging current when boot with + * pd cable connected, clear apsd current result. + */ + vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); + vote(chg->fcc_votable, HW_LIMIT_VOTER, false, 0); + vote(chg->usb_icl_votable, DCP_VOTER, false, 0); + //vote(chg->fcc_votable, DEFAULT_VOTER, + // true, PD_FCC_CURRENT_UA); + vote(chg->fcc_votable, BATT_PROFILE_VOTER, false, 0); + + /* @bsp, add to set allow read extern fg IIC */ + set_property_on_fg(chg, + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, true); + /* * For PPS, Charge Pump is preferred over parallel charger if * present. @@ -4646,6 +5128,19 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, dev_err(chg->dev, "Couldn't enable secondary charger rc=%d\n", rc); } + + /* @bsp, 2020/08/04, add to detect SVID */ + op_usbpd_send_svdm(USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY, + SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); + pr_info("PPS type, Discover SVID!\n"); + + // Schedule PDO selction for 9V2A + schedule_delayed_work(&chg->pdo_select_check_work, + msecs_to_jiffies(2000)); + + /* @bsp, 2019/12/20 add pd skin thermal check */ + schedule_delayed_work(&chg->pd_current_check_work, + msecs_to_jiffies(200)); } else { vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->limited_irq_disable_votable, CHARGER_TYPE_VOTER, @@ -5116,6 +5611,20 @@ irqreturn_t chg_state_change_irq_handler(int irq, void *data) } stat = stat & BATTERY_CHARGER_STATUS_MASK; +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (stat == TERMINATE_CHARGE) { + /* charge done, disable charge in software also */ + chg->chg_done = true; + pr_info("TERMINATE_CHARGE: chg_done: CAP=%d (Q:%d), VBAT=%d (Q:%d), IBAT=%d (Q:%d), BAT_TEMP=%d\n", + get_prop_batt_capacity(chg), + get_prop_fg_capacity(chg), + get_prop_batt_voltage_now(chg) / 1000, + get_prop_fg_voltage_now(chg) / 1000, + get_prop_batt_current_now(chg) / 1000, + get_prop_fg_current_now(chg) / 1000, + get_prop_batt_temp(chg)); + op_charging_en(chg, false); + } if (chg->wa_flags & CHG_TERMINATION_WA) smblib_eval_chg_termination(chg, stat); @@ -5166,6 +5675,12 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) int rc; u8 stat = 0, max_pulses = 0; +/* @bsp, 2019/07/05 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return IRQ_HANDLED; + } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if ((chg->wa_flags & WEAK_ADAPTER_WA) @@ -5236,6 +5751,8 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) wdata = &chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data->storm_data; reset_storm_count(wdata); +/* @bsp, 2019/07/05 Battery & Charging porting */ + smblib_err(chg, "DEBUG: RESET STORM COUNT FOR POWER_OK\n"); /* Workaround for non-QC2.0-compliant chargers follows */ if (!chg->qc2_unsupported_voltage && @@ -5289,6 +5806,40 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) return IRQ_HANDLED; } +/* @bsp, 2019/07/06 Battery & Charging porting */ +char dump_val[2048]; +static inline void op_dump_reg(struct smb_charger *chip, + u16 addr_start, u16 addr_end) +{ + u8 reg = 0; + u16 addr; + char reg_val[19]; + int rc; + + memset(dump_val, 0, sizeof(dump_val)); + for (addr = addr_start; addr <= addr_end; addr++) { + memset(reg_val, 0, sizeof(reg_val)); + rc = smblib_read(chip, addr, ®); + if (rc < 0) + smblib_err(chip, "op_dump_reg read error rc=%d\n", + rc); + scnprintf(reg_val, + sizeof(reg_val), "%x=%0x;", addr, reg); + strlcat(dump_val, reg_val, sizeof(dump_val)); + } + pr_info("%s\n", dump_val); +} + +static void op_dump_regs(struct smb_charger *chip) +{ + u16 addr, count; + + count = 0x80; + for (addr = 0x1000; addr <= 0x1700; addr += count) + op_dump_reg(chip, addr, (addr + count)); +} + + #define USB_WEAK_INPUT_UA 1400000 #define ICL_CHANGE_DELAY_MS 1000 irqreturn_t icl_change_irq_handler(int irq, void *data) @@ -5463,6 +6014,16 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; +/* @bsp, 2019/07/05 Battery & Charging porting */ + bool last_vbus_present; + + last_vbus_present = chg->vbus_present; + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return; + } + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); @@ -5470,11 +6031,36 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) } vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); + /* @bsp add for wake lock check*/ + chg->vbus_present = vbus_rising; + if (last_vbus_present != chg->vbus_present) { + if (chg->vbus_present) { + if (!chg->chg_wake_lock_on) { + pr_info("acquire chg_wake_lock\n"); + __pm_stay_awake(chg->chg_wake_lock); + chg->chg_wake_lock_on = true; + } else { + pr_err("chg_wake_lock is already stay awake."); + } + } else { + if (chg->chg_wake_lock_on) { + pr_info("release chg_wake_lock\n"); + __pm_relax(chg->chg_wake_lock); + chg->chg_wake_lock_on = false; + } else { + pr_err("chg_wake_lock is already relax."); + } + } + } if (vbus_rising) { /* Remove FCC_STEPPER 1.5A init vote to allow FCC ramp up */ if (chg->fcc_stepper_enable) vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); + /* @bsp add to fix some pd temp not update issue */ + if (gpio_is_valid(chg->vbus_ctrl)) + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(200)); } else { if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; @@ -5493,6 +6079,13 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) if (chg->fcc_stepper_enable) vote(chg->fcc_votable, FCC_STEPPER_VOTER, true, 1500000); + /* @bsp, fix the suspend current issue */ + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + /* @bsp add for wake lock check*/ + if (last_vbus_present != chg->vbus_present) + op_handle_usb_removal(chg); } power_supply_changed(chg->usb_psy); @@ -5509,6 +6102,17 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; +/* @bsp, 2019/07/05 Battery & Charging porting */ + union power_supply_propval vbus_val; + bool last_vbus_present; + + last_vbus_present = chg->vbus_present; + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return; + } + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); @@ -5519,6 +6123,27 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) smblib_set_opt_switcher_freq(chg, vbus_rising ? chg->chg_freq.freq_5V : chg->chg_freq.freq_removal); +/* @bsp, 2019/07/05 Battery & Charging porting */ + chg->vbus_present = vbus_rising; + if (last_vbus_present != chg->vbus_present) { + if (chg->vbus_present) { + if (!chg->chg_wake_lock_on) { + pr_info("acquire chg_wake_lock\n"); + __pm_stay_awake(chg->chg_wake_lock); + chg->chg_wake_lock_on = true; + } else { + pr_err("chg_wake_lock is already stay awake."); + } + } else { + if (chg->chg_wake_lock_on) { + pr_info("release chg_wake_lock\n"); + __pm_relax(chg->chg_wake_lock); + chg->chg_wake_lock_on = false; + } else { + pr_err("chg_wake_lock is already relax."); + } + } + } if (vbus_rising) { cancel_delayed_work_sync(&chg->pr_swap_detach_work); vote(chg->awake_votable, DETACH_DETECT_VOTER, false, 0); @@ -5526,6 +6151,17 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); +/* @bsp, 2019/07/06 Battery & Charging porting */ + if (chg->charger_collpse) { + op_set_collapse_fet(chg, 0); + chg->charger_collpse = false; + } + chg->switch_on_fastchg = false; + schedule_delayed_work(&chg->op_check_apsd_work, + msecs_to_jiffies(TIME_1000MS)); + if (gpio_is_valid(chg->vbus_ctrl)) + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(200)); /* Enable SW Thermal regulation */ rc = smblib_set_sw_thermal_regulation(chg, true); if (rc < 0) @@ -5595,7 +6231,9 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); - +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (last_vbus_present != chg->vbus_present) + op_handle_usb_removal(chg); smblib_update_usb_type(chg); } @@ -5608,13 +6246,29 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) power_supply_changed(chg->usb_psy); smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n", vbus_rising ? "attached" : "detached"); -} - -irqreturn_t usb_plugin_irq_handler(int irq, void *data) +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (!vbus_rising) { + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("V fail rc=%d\n", rc); + } else { + if (vbus_val.intval > 3000) { + pr_err("unplg,Vbus=%d", vbus_val.intval); + op_dump_regs(chg); + } + } + } + pr_err("IRQ: %s\n", + vbus_rising ? "attached" : "detached"); +} + +irqreturn_t usb_plugin_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + if (chg->count_run) + chg->count_run = 0; if (chg->pd_hard_reset) smblib_usb_plugin_hard_reset_locked(chg); else @@ -5623,6 +6277,15 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data) return IRQ_HANDLED; } +/* @bsp, 2019/07/05 Battery & Charging porting */ +void op_handle_usb_plugin(struct smb_charger *chg) +{ + mutex_lock(&chg->smb_lock); + smblib_usb_plugin_locked(chg); + op_typec_state_change_irq_handler(); + mutex_unlock(&chg->smb_lock); +} + static void smblib_handle_slow_plugin_timeout(struct smb_charger *chg, bool rising) { @@ -5759,12 +6422,10 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) * enumeration is done. */ if (!is_client_vote_enabled(chg->usb_icl_votable, - USB_PSY_VOTER)) { - /* if flash is active force 500mA */ + USB_PSY_VOTER)) +/* @bsp, 2019/07/05 Battery & Charging porting */ vote(chg->usb_icl_votable, USB_PSY_VOTER, true, - is_flash_active(chg) ? - SDP_CURRENT_UA : SDP_100_MA); - } + 500000); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); break; case POWER_SUPPLY_TYPE_USB_CDP: @@ -5772,21 +6433,20 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) CDP_CURRENT_UA); break; case POWER_SUPPLY_TYPE_USB_DCP: +/* @bsp, 2019/07/05 Battery & Charging porting */ rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); break; case POWER_SUPPLY_TYPE_USB_FLOAT: - /* - * limit ICL to 100mA, the USB driver will enumerate to check - * if this is a SDP and appropriately set the current - */ +/* @bsp, 2019/07/05 Battery & Charging porting */ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - SDP_100_MA); + 1500000); break; case POWER_SUPPLY_TYPE_UNKNOWN: default: +/* @bsp, 2019/07/05 Battery & Charging porting */ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - SDP_100_MA); + SDP_CURRENT_UA); break; } } @@ -5794,6 +6454,8 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; +/* @bsp, 2019/07/05 Battery & Charging porting */ + int temp_region = 0, current_limit_ua = 0; if (!rising) return; @@ -5816,6 +6478,64 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) break; } +/* @bsp, 2019/07/05 Battery & Charging porting */ + if ((apsd_result->bit) == SDP_CHARGER_BIT) + current_limit_ua = DEFAULT_SDP_MA*1000; + else if ((apsd_result->bit) == CDP_CHARGER_BIT) + current_limit_ua = DEFAULT_CDP_MA*1000; + else if ((apsd_result->bit) == DCP_CHARGER_BIT) + current_limit_ua = DEFAULT_DCP_MA*1000; + else if ((apsd_result->bit) == FLOAT_CHARGER_BIT) { + if (chg->usb_type_redet_done) + current_limit_ua = DEFAULT_DCP_MA*1000; + else + current_limit_ua = TYPEC_DEFAULT_CURRENT_UA*1000; + } else if ((apsd_result->bit) == OCP_CHARGER_BIT) + current_limit_ua = DEFAULT_DCP_MA*1000; + else + current_limit_ua = DEFAULT_DCP_MA*1000; + + if (chg->is_aging_test) + current_limit_ua = DEFAULT_AGAING_CHG_MA*1000; + vote(chg->usb_icl_votable, + DCP_VOTER, true, current_limit_ua); + vote(chg->usb_icl_votable, + USB_PSY_VOTER, true, current_limit_ua); + + smblib_set_prop_charge_parameter_set(chg); + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_COLD + && temp_region != BATT_TEMP_HOT) { + op_charging_en(chg, true); + } + + pr_info("apsd result=0x%x, name=%s, psy_type=%d\n", + apsd_result->bit, apsd_result->name, apsd_result->pst); + pr_info("apsd done,current_now=%d\n", + (get_prop_batt_current_now(chg) / 1000)); + if (!chg->fastchg_switch_disable) { + if (apsd_result->bit == DCP_CHARGER_BIT + || apsd_result->bit == OCP_CHARGER_BIT) { + schedule_delayed_work(&chg->check_switch_dash_work, + msecs_to_jiffies(50)); + } + } else { + if (!chg->usb_type_redet_done) { + if (!chg->boot_usb_present && chg->probe_done) + schedule_delayed_work(&chg->re_det_work, + msecs_to_jiffies(TIME_1000MS)); + } else { + schedule_delayed_work( + &chg->non_standard_charger_check_work, + msecs_to_jiffies(TIME_1000MS)); + } + } + chg->op_apsd_done = true; + + /* set allow read extern fg IIC */ + set_property_on_fg(chg, + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, true); + smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n", apsd_result->name); } @@ -5827,6 +6547,13 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) int rc = 0; u8 stat; +/* @bsp, 2019/07/05 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (g_chg->dash_on || chg->switch_on_fastchg) { + pr_err("return directly because dash is dash_on\n"); + return IRQ_HANDLED; + } + /* PD session is ongoing, ignore BC1.2 and QC detection */ if (chg->pd_active) return IRQ_HANDLED; @@ -5836,6 +6563,9 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc); return IRQ_HANDLED; } +/* @bsp, 2018/07/16 Battery & Charging porting */ + pr_info("APSD_STATUS=0x%02x\n", stat); + smblib_dbg(chg, PR_INTERRUPT, "APSD_STATUS = 0x%02x\n", stat); if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) @@ -5984,7 +6714,9 @@ static void typec_src_fault_condition_cfg(struct smb_charger *chg, bool src) static void typec_sink_insertion(struct smb_charger *chg) { int rc; - +/* @bsp, 2019/07/05 Battery & Charging porting */ + if (!chg->is_audio_adapter) + vote(chg->usb_icl_votable, OTG_VOTER, true, 0); typec_src_fault_condition_cfg(chg, true); rc = smblib_set_charge_param(chg, &chg->param.freq_switcher, chg->chg_freq.freq_above_otg_threshold); @@ -6177,6 +6909,7 @@ static void typec_sink_removal(struct smb_charger *chg) { int rc; + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); typec_src_fault_condition_cfg(chg, false); rc = smblib_set_charge_param(chg, &chg->param.freq_switcher, chg->chg_freq.freq_removal); @@ -6188,6 +6921,8 @@ static void typec_sink_removal(struct smb_charger *chg) smblib_notify_usb_host(chg, false); chg->otg_present = false; } +/* @bsp, 2019/07/05 Battery & Charging porting */ + chg->is_audio_adapter = false; } static void typec_src_removal(struct smb_charger *chg) @@ -6226,12 +6961,14 @@ static void typec_src_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); /* reset input current limit voters */ - vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - is_flash_active(chg) ? SDP_CURRENT_UA : SDP_100_MA); +/* @bsp, 2019/07/05 Battery & Charging porting */ +/* @bsp, set icl 500mA after charger removed */ + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, 500000); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, DCP_VOTER, false, 0); vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); vote(chg->usb_icl_votable, CTM_VOTER, false, 0); vote(chg->usb_icl_votable, HVDCP2_ICL_VOTER, false, 0); vote(chg->usb_icl_votable, CHG_TERMINATION_VOTER, false, 0); @@ -6441,11 +7178,43 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } +/* @bsp, avoid abnormal icl set after switch to normal charge */ +static void op_typec_state_change_irq_handler(void) +{ + int typec_mode; + + if (g_chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { + smblib_dbg(g_chg, PR_INTERRUPT, + "Ignoring for micro USB\n"); + return; + } + + typec_mode = smblib_get_prop_typec_mode(g_chg); + if (typec_mode != g_chg->typec_mode) { + smblib_handle_rp_change(g_chg, typec_mode); + g_chg->typec_mode = typec_mode; + } + + smblib_dbg(g_chg, PR_INTERRUPT, + "%s: cc-state-change; Type-C %s detected\n", + __func__, + smblib_typec_mode_name[g_chg->typec_mode]); + + power_supply_changed(g_chg->usb_psy); +} + irqreturn_t typec_state_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; int typec_mode; +/* @bsp, 2019/07/05 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_info("chg->dash_on = %d update typec state!\n", + chg->dash_on); + return IRQ_HANDLED; + } if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { smblib_dbg(chg, PR_INTERRUPT, @@ -6493,6 +7262,14 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); +/* @bsp, 2018/07/13 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return IRQ_HANDLED; + } + + rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", @@ -6917,9 +7694,17 @@ irqreturn_t switcher_power_ok_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; - struct storm_watch *wdata = &irq_data->storm_data; int rc, usb_icl; u8 stat; +/* @bsp, 2019/07/05 Battery & Charging porting */ + union power_supply_propval vbus_val; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return IRQ_HANDLED; + } if (!(chg->wa_flags & BOOST_BACK_WA)) return IRQ_HANDLED; @@ -6939,32 +7724,18 @@ irqreturn_t switcher_power_ok_irq_handler(int irq, void *data) return IRQ_HANDLED; if (is_storming(&irq_data->storm_data)) { - /* This could be a weak charger reduce ICL */ - if (!is_client_vote_enabled(chg->usb_icl_votable, - WEAK_CHARGER_VOTER)) { - smblib_err(chg, - "Weak charger detected: voting %dmA ICL\n", - chg->weak_chg_icl_ua / 1000); - vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER, - true, chg->weak_chg_icl_ua); - /* - * reset storm data and set the storm threshold - * to 3 for reverse boost detection. - */ - update_storm_count(wdata, BOOST_BACK_STORM_COUNT); - } else { - smblib_err(chg, - "Reverse boost detected: voting 0mA to suspend input\n"); - vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0); - vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0); - /* - * Remove the boost-back vote after a delay, to avoid - * permanently suspending the input if the boost-back - * condition is unintentionally hit. - */ - schedule_delayed_work(&chg->bb_removal_work, - msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS)); - } +/* @bsp, 2019/07/05 Battery & Charging porting */ +/*Use the setting of 0x1380 and 0x1365 is useful*/ + smblib_err(chg, "Reverse boost detected\n"); + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) + pr_err("fail to read usb_voltage rc=%d\n", rc); + else if (vbus_val.intval >= 2500) + pr_err("vbus_val.intval=%d\n", vbus_val.intval); + chg->revert_boost_trigger = true; + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0); + schedule_delayed_work(&chg->recovery_suspend_work, + msecs_to_jiffies(TIME_100MS)); } return IRQ_HANDLED; @@ -6983,7 +7754,8 @@ irqreturn_t wdog_snarl_irq_handler(int irq, void *data) schedule_delayed_work(&chg->thermal_regulation_work, 0); } - power_supply_changed(chg->batt_psy); + if (chg->step_chg_enabled) + power_supply_changed(chg->batt_psy); return IRQ_HANDLED; } @@ -7000,6 +7772,9 @@ irqreturn_t wdog_bark_irq_handler(int irq, void *data) if (rc < 0) smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc); + if (chg->step_chg_enabled) + power_supply_changed(chg->batt_psy); + return IRQ_HANDLED; } @@ -7034,192 +7809,3760 @@ irqreturn_t temp_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static void smblib_usbov_dbc_work(struct work_struct *work) +/* @bsp, 2019/07/05 Battery & Charging porting START */ +static void op_get_aicl_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, - usbov_dbc_work.work); + get_aicl_work); + int rc, settled_ua; - smblib_dbg(chg, PR_MISC, "Resetting USBOV debounce\n"); - chg->dbc_usbov = false; - vote(chg->awake_votable, USBOV_DBC_VOTER, false, 0); + rc = smblib_get_charge_param(chg, &chg->param.icl_stat, + &settled_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc); + return; + } + + pr_err("AICL result=%dmA\n", settled_ua / 1000); } -#define USB_OV_DBC_PERIOD_MS 1000 -irqreturn_t usbin_ov_irq_handler(int irq, void *data) +/* @bsp 2018/07/30 add usb connector temp detect */ +#define THIRD_LOOP_ENTER_MINI_THRESHOLD 35 +#define THIRD_LOOP_ENTER_MAX_THRESHOLD 60 +#define THIRD_INTERVAL_MINI_THRESHOLD 8 +#define THIRD_INTERVAL_MAX_THRESHOLD 20 +static void op_connecter_temp_check_work(struct work_struct *work) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; - u8 stat; - int rc; + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, connecter_check_work); + int batt_temp = 0, interval_temp = 0; + int i = 0, loop_enter_temp = 0, third_interval_temp = 0; - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + if (!chg->vbus_present) + return; - if (!(chg->wa_flags & USBIN_OV_WA)) - return IRQ_HANDLED; + chg->connecter_temp = get_usb_temp(chg); + batt_temp = get_prop_batt_temp(chg)/10; + interval_temp = chg->connecter_temp - batt_temp; - rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); - return IRQ_HANDLED; - } + /* online config*/ + if ((*chg->usb_connector_temp >= THIRD_LOOP_ENTER_MINI_THRESHOLD) && + (*chg->usb_connector_temp <= THIRD_LOOP_ENTER_MAX_THRESHOLD)) + loop_enter_temp = *chg->usb_connector_temp; + else + loop_enter_temp = chg->third_protect_loop_temp; - /* - * On specific PMICs, OV IRQ triggers for very small duration in - * interim periods affecting charging status reflection. In order to - * differentiate between OV IRQ glitch and real OV_IRQ, add a debounce - * period for evaluation. - */ - if (stat & USBIN_OV_RT_STS_BIT) { - chg->dbc_usbov = true; - vote(chg->awake_votable, USBOV_DBC_VOTER, true, 0); - schedule_delayed_work(&chg->usbov_dbc_work, - msecs_to_jiffies(USB_OV_DBC_PERIOD_MS)); - } else { - cancel_delayed_work_sync(&chg->usbov_dbc_work); - chg->dbc_usbov = false; - vote(chg->awake_votable, USBOV_DBC_VOTER, false, 0); + if ((*chg->usb_interval_temp >= THIRD_INTERVAL_MINI_THRESHOLD) && + (*chg->usb_interval_temp <= THIRD_INTERVAL_MAX_THRESHOLD)) + third_interval_temp = *chg->usb_interval_temp; + else + third_interval_temp = chg->third_protect_interval_temp; + + if (!chg->count_run) {/*count run state keep count_total not change*/ + if (chg->connecter_temp >= + chg->fast_check_threshold_temp) {// 33 + chg->count_total = + chg->high_temp_short_check_timeout / chg->fast_check_interval_period; + smblib_dbg(chg, PR_FAST_DEBUG, "> %d! chg->count_total:%d", + chg->fast_check_threshold_temp, + chg->count_total); + } else { + chg->count_total = + chg->high_temp_short_check_timeout / chg->normal_check_interval_period; + smblib_dbg(chg, PR_FAST_DEBUG, "<= %d! chg->count_total:%d", + chg->fast_check_threshold_temp, + chg->count_total); + } } - smblib_dbg(chg, PR_MISC, "USBOV debounce status %d\n", - chg->dbc_usbov); - return IRQ_HANDLED; -} + smblib_dbg(chg, PR_FAST_DEBUG, "connecter_temp:%d,batt_temp:%d,interval_temp:%d,count_total:%d,count_run:%d,connector_short:%d\n", + chg->connecter_temp, + batt_temp, + interval_temp, + chg->count_total, + chg->count_run, + chg->connector_short); + /*error:EOC bit not set! cause connector_temp=125 other 75*/ + if (chg->connecter_temp == 125 || chg->connecter_temp == 75) { + for (i = 0; i <= 9; i++) { + msleep(100); + smblib_dbg(chg, PR_FAST_DEBUG, + "EOC error!temp abormal delay count:%d\n", + i); + } + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(100)); + return; /*rerun check again*/ + } + + if (chg->connecter_temp >= + chg->first_protect_connecter_temp) { /* >=60 */ + pr_info("connecter_temp=%d,connector_short=%d\n", + chg->connecter_temp, + chg->connector_short); + op_disconnect_vbus(chg, true); + } else {/*20<= ? < 60*/ + if ((interval_temp >= chg->second_protect_interval_temp) + && (chg->connecter_temp >= + chg->second_protect_connecter_temp)) { + /*interval > 14 && connecter > 45*/ + pr_info("interval_temp=%d,connecter_temp=%d\n", + interval_temp, + chg->connecter_temp); + op_disconnect_vbus(chg, true); + return; + } else if (((interval_temp >= third_interval_temp) && + (chg->connecter_temp >= chg->third_protect_base_temp)) || + (chg->connecter_temp >= loop_enter_temp)) { + /*interval >=8 && connecter >=20 or connecter >= 40 enter*/ + if (chg->count_run <= chg->count_total) { + /*time out count*/ + if (chg->count_run == 0) + chg->pre_temp = chg->connecter_temp; + + /* time out check MAX=count_total*/ + if (chg->count_run > 0) { + chg->current_temp = chg->connecter_temp; + /* 3 degree per 1.5 senconds*/ + if ((chg->current_temp - + chg->pre_temp) >= + chg->third_protect_rise_rate) { + chg->connector_short = true; + pr_info("cout_run=%d,short=%d\n", + chg->count_run, + chg->connector_short); + op_disconnect_vbus(chg, true); + return; + } + } -/************** - * Additional USB PSY getters/setters - * that call interrupt functions - ***************/ + chg->count_run++;/*count ++*/ -int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, - union power_supply_propval *val) -{ - val->intval = chg->pr_swap_in_progress; - return 0; + if (chg->count_run > chg->count_total) { + chg->count_run = 0; + smblib_dbg(chg, PR_FAST_DEBUG, "count reset!\n"); + } + } + } else {/*connecter <20 or connecter < 40 && interval < 8*/ + if (chg->count_run)/* high temp cold down count reset.*/ + chg->count_run = 0; + smblib_dbg(chg, PR_FAST_DEBUG, + "chg->dash_on:%d,connecter_temp:%d\n", + chg->dash_on, + chg->connecter_temp); + } + } + + if (chg->connecter_temp < chg->fast_check_threshold_temp) + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(chg->normal_check_interval_period)); + else if ((chg->connecter_temp >= chg->fast_check_threshold_temp) + && (chg->connecter_temp < chg->first_protect_connecter_temp)) + /*time need optimize depend on test*/ + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(chg->fast_check_interval_period)); + else + smblib_dbg(chg, PR_FAST_DEBUG, "connecter_temp:%d\n", + chg->connecter_temp); } -#define DETACH_DETECT_DELAY_MS 20 -int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, - const union power_supply_propval *val) +#define CONNECTER_RECOVERY_CHECK_INTERVAL 3000 //ms +static void op_connecter_recovery_charge_work(struct work_struct *work) { - int rc; - u8 stat = 0, orientation; + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, connecter_recovery_work); + int batt_temp = 0, interval_temp = 0; - smblib_dbg(chg, PR_MISC, "Requested PR_SWAP %d\n", val->intval); - chg->pr_swap_in_progress = val->intval; + if (!chg->disconnect_vbus) + return; - /* check for cable removal during pr_swap */ - if (!chg->pr_swap_in_progress) { - cancel_delayed_work_sync(&chg->pr_swap_detach_work); - vote(chg->awake_votable, DETACH_DETECT_VOTER, true, 0); - schedule_delayed_work(&chg->pr_swap_detach_work, - msecs_to_jiffies(DETACH_DETECT_DELAY_MS)); + chg->connecter_temp = get_usb_temp(chg); + batt_temp = get_prop_batt_temp(chg)/10; + interval_temp = chg->connecter_temp - batt_temp; + + pr_info("disconnect_vbus=%d, hw_detect=%d", + chg->disconnect_vbus, chg->hw_detect); + pr_info("connecter_temp=%d, interval_temp=%d", + chg->connecter_temp, interval_temp); + + if ((chg->hw_detect == 0) && + (chg->connecter_temp <= 50) && + (interval_temp <= 10)) { + pr_info("Recovery Charge!\n"); + op_disconnect_vbus(chg, false); + chg->connector_short = false; + return; } - rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, - REDUCE_TCCDEBOUNCE_TO_2MS_BIT, - val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0); - if (rc < 0) - smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc); - - rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, - BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT, - val->intval ? BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT : 0); - if (rc < 0) - smblib_err(chg, "Couldn't set exit state cfg rc=%d\n", rc); + schedule_delayed_work(&chg->connecter_recovery_work, + msecs_to_jiffies(CONNECTER_RECOVERY_CHECK_INTERVAL)); +} - if (chg->pr_swap_in_progress) { - rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", - rc); - } +static void pdo_selection_check_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, pdo_select_check_work); + int retval = 0; + static int pdo_select_retry_count; - orientation = - stat & CC_ORIENTATION_BIT ? TYPEC_CCOUT_VALUE_BIT : 0; - rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, - TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT - | TYPEC_CCOUT_VALUE_BIT, - TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT - | orientation); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", - rc); + if (chg->pd_active) { + retval = op_pdo_select(9000, 2000); + if (retval == 0) { + pr_err("%s(): pdo selection to 9V2A is successful\n", + __func__); + pdo_select_retry_count = 0; + } else { + pr_err("%s(): pdo selection to 9V2A fail:%d, ret=%d\n", + __func__, retval, pdo_select_retry_count); + // Schedule pdo selection after 5 sec and stop + // if failed 3 times + if (pdo_select_retry_count++ < 3) + schedule_delayed_work(&chg->pdo_select_check_work, + msecs_to_jiffies(PDO_SELECTION_INTERVAL_MS)); } - } else { - rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, - TYPEC_CCOUT_SRC_BIT, 0); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", - rc); - return rc; + // Add check for third party PD+Fastcharger or PD+Superfast charger + if (!chg->swarp_online && + (pdo_select_retry_count == 0 || pdo_select_retry_count >= 3)) { + cancel_delayed_work(&chg->check_switch_dash_work); + schedule_delayed_work(&chg->check_switch_dash_work, msecs_to_jiffies(1000)); } + } +} - /* enable DRP */ - rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, - TYPEC_POWER_ROLE_CMD_MASK, 0); - if (rc < 0) { - smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); - return rc; - } - chg->power_role = POWER_SUPPLY_TYPEC_PR_DUAL; - smblib_dbg(chg, PR_MISC, "restore power role: %d\n", - chg->power_role); +/* @bsp, 2019/12/20 add pd skin thermal check */ +#define PD_CALLON_CURRENT_UA 800000 +#define PD_SKIN_THERMAL_NORMAL_CURRENT_UA 2000000 +#define PD_SKIN_THERMAL_MEDIUM_CURRENT_UA 1500000 +#define PD_SKIN_THERMAL_HIGH_CURRENT_UA 1000000 +#define PD_CHECK_INTERVAL_PERIOD 5000 +static void pd_skin_thermal_check_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, pd_current_check_work); + bool is_call_on; + bool is_skin_temp_high; + bool is_skin_temp_medium; + int ua, icl; + + if (!chg->pd_active || chg->dash_present || chg->swarp_online) + return; + + is_call_on = check_call_on_status(); + is_skin_temp_high = check_skin_thermal_high(); + is_skin_temp_medium = check_skin_thermal_medium(); + if (is_call_on) + ua = PD_CALLON_CURRENT_UA; + else if (is_skin_temp_high) + ua = PD_SKIN_THERMAL_HIGH_CURRENT_UA; + else if (is_skin_temp_medium) + ua = PD_SKIN_THERMAL_MEDIUM_CURRENT_UA; + else + ua = PD_SKIN_THERMAL_NORMAL_CURRENT_UA; + + icl = get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER); + if (ua != icl) { + pr_info("skin_thermal_temp=(%d), is_skin_thermal_medium(%d), is_skin_thermal_high(%d)\n", + chg->skin_thermal_temp, + chg->is_skin_thermal_medium, + chg->is_skin_thermal_high); + vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, ua); } - return 0; + schedule_delayed_work(&chg->pd_current_check_work, + msecs_to_jiffies(PD_CHECK_INTERVAL_PERIOD)); } -/*************** - * Work Queues * - ***************/ -static void smblib_pr_lock_clear_work(struct work_struct *work) +/* @bsp, 2020/08/04, add to detect SVID */ +static void pps_usbpd_connect_cb(struct usbpd_svid_handler *hdlr, + bool peer_usb_comm) { - struct smb_charger *chg = container_of(work, struct smb_charger, - pr_lock_clear_work.work); + struct smb_charger *chg = g_chg; - spin_lock(&chg->typec_pr_lock); - if (chg->pr_lock_in_progress) { - smblib_dbg(chg, PR_MISC, "restore type-c interrupts\n"); - smblib_typec_irq_config(chg, true); - chg->pr_lock_in_progress = false; + chg->swarp_online = 1; + op_set_fast_chg_allow(chg, false); + + if (chg->chg_enabled) { + if (!chg->fastchg_switch_disable && !chg->dash_present) { + cancel_delayed_work(&chg->check_switch_dash_work); + schedule_delayed_work(&chg->check_switch_dash_work, msecs_to_jiffies(500)); + } } - spin_unlock(&chg->typec_pr_lock); + pr_info("SWARP adapter connected!\n"); } -static void smblib_pr_swap_detach_work(struct work_struct *work) +static void pps_usbpd_disconnect_cb(struct usbpd_svid_handler *hdlr) { - struct smb_charger *chg = container_of(work, struct smb_charger, - pr_swap_detach_work.work); - int rc; - u8 stat; + struct smb_charger *chg = g_chg; - rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read STATE_MACHINE_STS rc=%d\n", rc); - goto out; - } - smblib_dbg(chg, PR_REGISTER, "STATE_MACHINE_STS %x\n", stat); - if (!(stat & TYPEC_ATTACH_DETACH_STATE_BIT)) { - rc = smblib_request_dpdm(chg, false); - if (rc < 0) - smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + chg->swarp_online = 0; + pr_info("SWARP adapter disconnected!\n"); +} - if (chg->typec_port) - typec_partner_unregister(chg); +static void op_register_pps_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, register_pps_work); + struct op_pps *swarp_pps = &op_pps_chg; + int rc = 0; + const char *pd_phandle = "qcom,op-pps-usbpd-detection"; + struct usbpd *pd = NULL; + + pd = devm_usbpd_get_by_phandle(chg->dev, pd_phandle); + if (IS_ERR(pd)) { + pr_err("op pps usbpd phandle failed (%ld)\n", PTR_ERR(pd)); + rc = PTR_ERR(pd); + schedule_delayed_work(&chg->register_pps_work, msecs_to_jiffies(1000)); + } else { + swarp_pps->pd = pd; + swarp_pps->svid_handler.svid = OP_SVID; + swarp_pps->svid_handler.vdm_received = NULL; + swarp_pps->svid_handler.connect = pps_usbpd_connect_cb; + swarp_pps->svid_handler.svdm_received = NULL; + swarp_pps->svid_handler.disconnect = pps_usbpd_disconnect_cb; + rc = usbpd_register_svid(swarp_pps->pd, &swarp_pps->svid_handler); + if (rc) + pr_err("pps pd registration failed\n"); + pr_err("pps pd registration success\n"); } -out: - vote(chg->awake_votable, DETACH_DETECT_VOTER, false, 0); + } -static void smblib_uusb_otg_work(struct work_struct *work) +irqreturn_t smblib_handle_aicl_done(int irq, void *data) { - struct smb_charger *chg = container_of(work, struct smb_charger, - uusb_otg_work.work); - int rc; - u8 stat; - bool otg; + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; - rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat); + cancel_work_sync(&chg->get_aicl_work); + schedule_work(&chg->get_aicl_work); + + return IRQ_HANDLED; +} + +int op_get_aicl_result(struct smb_charger *chg) +{ + int icl_ma, rc; + + rc = smblib_get_charge_param(chg, + &chg->param.icl_stat, &icl_ma); + if (rc < 0) { + pr_err("Couldn't get ICL status rc=%d\n", rc); + return -EINVAL; + } + + pr_info("AICL result=%d\n", icl_ma); + return icl_ma; +} +static bool op_get_fast_chg_status_is_ok(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->fast_chg_status_is_ok) + return fast_charger->fast_chg_status_is_ok(); + pr_err("no fast_charger register found\n"); + return true; +} + +static int get_property_from_fg(struct smb_charger *chg, + enum power_supply_property prop, int *val) +{ + int rc; + union power_supply_propval ret = {0, }; + + if (!chg->bms_psy) + chg->bms_psy = power_supply_get_by_name("bms"); + + if (chg->bms_psy) { + rc = power_supply_get_property(chg->bms_psy, prop, &ret); + if (rc) { + pr_err("bms psy doesn't support reading prop %d rc = %d\n", + prop, rc); + return rc; + } + *val = ret.intval; + } else { + pr_err("no bms psy found\n"); + return -EINVAL; + } + + return rc; +} + +static int set_property_on_fg(struct smb_charger *chg, + enum power_supply_property prop, int val) +{ + int rc; + union power_supply_propval ret = {0, }; + + if (!chg->bms_psy) + chg->bms_psy = power_supply_get_by_name("bms"); + + if (chg->bms_psy) { + ret.intval = val; + rc = power_supply_set_property(chg->bms_psy, prop, &ret); + if (rc) + pr_err("bms psy does not allow updating prop %d rc = %d\n", + prop, rc); + } else { + pr_err("no bms psy found\n"); + return -EINVAL; + } + + return rc; +} + +static int op_charging_en(struct smb_charger *chg, bool en) +{ + int rc; + + pr_info("enable=%d\n", en); + if (chg->chg_disabled && en) { + pr_info("chg_disabled just return\n"); + return 0; + } + + rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG, + CHARGING_ENABLE_CMD_BIT, + en ? CHARGING_ENABLE_CMD_BIT : 0); + if (rc < 0) { + pr_err("Couldn't %s charging rc=%d\n", + en ? "enable" : "disable", rc); + return rc; + } + + return 0; +} + +static bool is_usb_present(struct smb_charger *chg) +{ + int rc = 0; + u8 stat; + + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + pr_err("Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); + return rc; + } + pr_debug("TYPE_C_STATUS_4 = 0x%02x\n", stat); + return (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); +} + +static bool op_get_fast_low_temp_full(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->get_fast_low_temp_full) + return fast_charger->get_fast_low_temp_full(); + pr_err("no fast_charger register found\n"); + return false; +} + +static bool get_fastchg_firmware_updated_status(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->get_fastchg_firmware_already_updated) + return fast_charger->get_fastchg_firmware_already_updated(); + pr_err("no fast_charger register found\n"); + return false; +} + +static bool get_prop_fast_switch_to_normal(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->fast_switch_to_normal) + return fast_charger->fast_switch_to_normal(); + pr_err("no fast_charger register found\n"); + return false; +} + +bool is_fastchg_allowed(struct smb_charger *chg) +{ + int temp; + static int pre_temp; + static bool pre_switch_to_normal; + bool low_temp_full, switch_to_normal, fw_updated; + + temp = get_prop_batt_temp(chg); + low_temp_full = op_get_fast_low_temp_full(chg); + fw_updated = get_fastchg_firmware_updated_status(chg); + + if (!chg->chg_enabled) + return false; + if (chg->chg_disabled) + return false; + if (!fw_updated) + return false; + if (chg->usb_enum_status) + return false; + if (temp < DASH_VALID_TEMP_LOW_THRESHOLD + || temp > DASH_VALID_TEMP_HIG_THRESHOLD) { + if (temp != pre_temp) + pr_err("temp=%d is not allow to switch fastchg\n", + temp); + pre_temp = temp; + return false; + } + + switch_to_normal = get_prop_fast_switch_to_normal(chg); + if (pre_switch_to_normal != switch_to_normal) + pr_info("switch_to_normal =%d\n", switch_to_normal); + if (switch_to_normal) + return false; + + return true; +} + +void op_switch_normal_set(void) +{ + bool support_4p45; + + if (!g_chg) + return; + + support_4p45 = get_4p45_battery_support(); + pr_info("switch_normal_set,support_4p45:%d\n", + support_4p45); + + vote(g_chg->usb_icl_votable, + DCP_VOTER, true, 2000 * 1000); + if (support_4p45) + vote(g_chg->fv_votable, + DEFAULT_VOTER, true, 4550 * 1000); + else + vote(g_chg->fv_votable, + DEFAULT_VOTER, true, 4500 * 1000); + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, 1400 * 1000); + g_chg->ffc_status = FFC_FAST; +} + +bool get_oem_charge_done_status(void) +{ +#ifdef CONFIG_OP_DEBUG_CHG + return false; +#else + if (!g_chg || g_chg->is_aging_test) + return false; +#endif + return (g_chg->chg_done || g_chg->recharge_status); +} +static bool ff_force; + +static void op_handle_usb_removal(struct smb_charger *chg) +{ + op_set_fast_chg_allow(chg, false); + set_prop_fast_switch_to_normal_false(chg); + set_usb_switch(chg, false); + set_dash_charger_present(false); + op_clean_dash_status(); + ff_force = 0; + + chg->chg_ovp = false; + chg->dash_on = false; + chg->fastchg_switch_disable = false; + chg->chg_done = false; + chg->time_out = false; + chg->recharge_status = false; + chg->usb_enum_status = false; + chg->non_std_chg_present = false; + chg->usb_type_redet_done = false; + chg->boot_usb_present = false; + chg->revert_boost_trigger = false; + chg->is_audio_adapter = false; + chg->ffc_status = FFC_DEFAULT; + chg->non_stand_chg_current = 0; + chg->non_stand_chg_count = 0; + chg->redet_count = 0; + chg->dump_count = 0; + chg->swarp_online = 0; + chg->op_apsd_done = 0; + chg->ck_dash_count = 0; + chg->re_trigr_dash_done = 0; + chg->recovery_boost_count = 0; + chg->ck_unplug_count = 0; + chg->count_run = 0; + chg->chg_disabled = 0; + chg->disable_normal_chg_for_dash = false; + chg->fastchg_present_wait_count = 0; + chg->check_high_vbat_chg_count = 0; + vote(chg->fcc_votable, + DEFAULT_VOTER, true, SDP_CURRENT_UA); + vote(chg->chg_disable_votable, + FORCE_RECHARGE_VOTER, false, 0); + vote(chg->usb_icl_votable, + AICL_RERUN_VOTER, false, 0); + op_battery_temp_region_set(chg, BATT_TEMP_INVALID); +} + +int update_dash_unplug_status(void) +{ + int rc; + union power_supply_propval vbus_val; + + rc = smblib_get_prop_usb_voltage_now(g_chg, &vbus_val); + if (rc < 0) + pr_err("failed to read usb_voltage rc=%d\n", rc); + else if (vbus_val.intval <= 2500) { + op_handle_usb_plugin(g_chg); + smblib_update_usb_type(g_chg); + power_supply_changed(g_chg->usb_psy); + } + + return 0; +} +#define USBIN_AICL_RERUN_EN_BIT BIT(4) + +void op_check_charger_collapse_rerun_aicl(void) +{ + int rc; + + rc = smblib_masked_write(g_chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT + |USBIN_AICL_START_AT_MAX_BIT + | USBIN_AICL_ADC_EN_BIT + |USBIN_AICL_RERUN_EN_BIT, USBIN_AICL_RERUN_EN_BIT); + if (rc < 0) + dev_err(g_chg->dev, + "Couldn't configure AICL rc=%d\n", rc); + smblib_run_aicl(g_chg, RERUN_AICL); + smblib_err(g_chg, "%s done\n", __func__); +} +static int op_set_collapse_fet(struct smb_charger *chg, bool on) +{ + int rc = 0; + u8 stat; + + rc = smblib_masked_write(chg, USBIN_5V_AICL_THRESHOLD_CFG_REG, + BIT(0) | BIT(1), on ? 0 : BIT(0) | BIT(1)); + if (rc < 0) { + smblib_err(chg, "Couldn't write %s to 0x%x rc=%d\n", + on ? "on" : "off", USBIN_5V_AICL_THRESHOLD_CFG_REG, rc); + return rc; + } + + rc = smblib_read(chg, USBIN_5V_AICL_THRESHOLD_CFG_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read 0x%x rc=%d\n", + USBIN_5V_AICL_THRESHOLD_CFG_REG, rc); + return rc; + } + pr_info("USBIN_5V_AICL_THRESHOLD_CFG_REG(0x%x)=0x%x\n", + USBIN_5V_AICL_THRESHOLD_CFG_REG, stat); + + rc = smblib_masked_write(chg, USBIN_CONT_AICL_THRESHOLD_CFG_REG, + BIT(0) | BIT(1), on ? 0 : BIT(0) | BIT(1)); + if (rc < 0) { + smblib_err(chg, "Couldn't write %s to 0x%x rc=%d\n", + on ? "on" : "off", USBIN_CONT_AICL_THRESHOLD_CFG_REG, + rc); + return rc; + } + + rc = smblib_read(chg, USBIN_CONT_AICL_THRESHOLD_CFG_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read 0x%x rc=%d\n", + USBIN_CONT_AICL_THRESHOLD_CFG_REG, rc); + return rc; + } + pr_info("USBIN_CONT_AICL_THRESHOLD_CFG_REG(0x%x)=0x%x\n", + USBIN_CONT_AICL_THRESHOLD_CFG_REG, stat); + + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT + | USBIN_HV_COLLAPSE_RESPONSE_BIT + | USBIN_LV_COLLAPSE_RESPONSE_BIT + | USBIN_AICL_PERIODIC_RERUN_EN_BIT, + on ? 0 : SUSPEND_ON_COLLAPSE_USBIN_BIT + | USBIN_HV_COLLAPSE_RESPONSE_BIT + | USBIN_LV_COLLAPSE_RESPONSE_BIT); + if (rc < 0) { + smblib_err(chg, + "Couldn't write %s to 0x%x rc=%d\n", + on ? "on" : "off", USBIN_AICL_OPTIONS_CFG_REG, rc); + return rc; + } + + rc = smblib_read(chg, USBIN_AICL_OPTIONS_CFG_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read 0x%x rc=%d\n", + USBIN_AICL_OPTIONS_CFG_REG, rc); + return rc; + } + pr_info("USBIN_AICL_OPTIONS_CFG_REG(0x%x)=0x%x\n", + USBIN_AICL_OPTIONS_CFG_REG, stat); + + rc = smblib_masked_write(chg, USBIN_LOAD_CFG_REG, BIT(0) + | BIT(1), on ? 0 : BIT(0) | BIT(1)); + if (rc < 0) { + smblib_err(chg, "Couldn't write %s to 0x%x rc=%d\n", + on ? "on" : "off", USBIN_LOAD_CFG_REG, rc); + return rc; + } + + rc = smblib_read(chg, USBIN_LOAD_CFG_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read 0x%x rc=%d\n", + USBIN_LOAD_CFG_REG, rc); + return rc; + } + pr_info("USBIN_LOAD_CFG_REG(0x%x)=0x%x\n", + USBIN_LOAD_CFG_REG, stat); + + return rc; +} + +int op_handle_switcher_power_ok(void) +{ + int rc; + u8 stat; + union power_supply_propval vbus_val; + + if (!g_chg) + return 0; + if (!(g_chg->wa_flags & BOOST_BACK_WA)) + return 0; + rc = smblib_read(g_chg, POWER_PATH_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(g_chg, + "Couldn't read POWER_PATH_STATUS rc=%d\n", rc); + return 0; + } + smblib_err(g_chg, "POWER_PATH_STATUS stat=0x%x\n", stat); + + if ((stat & USE_USBIN_BIT) && + get_effective_result(g_chg->usb_icl_votable) + < USBIN_25MA) + return 0; + + if (stat & USE_DCIN_BIT) + return 0; + usleep_range(50000, 50002); + rc = smblib_get_prop_usb_voltage_now(g_chg, &vbus_val); + if (rc < 0) { + pr_err("fail to read usb_voltage rc=%d\n", rc); + } else if (vbus_val.intval >= 2500) { + op_dump_regs(g_chg); + pr_err("vbus_val.intval=%d\n", vbus_val.intval); + vote(g_chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0); + schedule_delayed_work(&g_chg->recovery_suspend_work, + msecs_to_jiffies(TIME_100MS)); + smblib_err(g_chg, "OP Reverse boost detected\n"); + } + + return 0; +} + +int op_contrl(int enable, bool check_power_ok) +{ + pr_info("en=%d\n", enable); + if (!g_chg) + return 0; + if (enable) { + if (check_power_ok) + op_handle_switcher_power_ok(); + } else { + op_set_collapse_fet(g_chg, enable); + } + return 0; +} + +int get_prop_fast_adapter_update(struct smb_charger *chg) +{ + int update_status; + + if (fast_charger && fast_charger->get_adapter_update) + update_status = fast_charger->get_adapter_update(); + else { + pr_err("no fast_charger register found\n"); + update_status = ADAPTER_FW_UPDATE_NONE; + } + return update_status; +} + +bool get_prop_fast_chg_started(struct smb_charger *chg) +{ + if (get_prop_fast_adapter_update(chg) + == ADAPTER_FW_NEED_UPDATE) + return true; + + if (fast_charger && fast_charger->fast_chg_started) + return fast_charger->fast_chg_started(); + pr_err("no fast_charger register found\n"); + return false; +} + +void update_fast_switch_off_status(void) +{ + if (g_chg->switch_on_fastchg) + g_chg->switch_on_fastchg = false; + pr_info("switch_on_fastchg is(%d)\n", + g_chg->switch_on_fastchg); +} + +void update_disconnect_pd_status(bool en) +{ + if (g_chg == NULL) { + pr_err("smbchg not found\n"); + return; + } + + g_chg->disconnect_pd = en; + power_supply_changed(g_chg->usb_psy); + pr_info("disconnect_pd is(%d)\n", g_chg->disconnect_pd); +} + +static bool set_prop_fast_switch_to_normal_false(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->set_switch_to_noraml_false) + return fast_charger->set_switch_to_noraml_false(); + pr_err("no fast_charger register found\n"); + return false; +} + +bool op_get_fastchg_ing(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->get_fast_chg_ing) + return fast_charger->get_fast_chg_ing(); + pr_err("no fast_charger register found\n"); + return false; +} + +bool op_set_fast_chg_allow(struct smb_charger *chg, bool enable) +{ + if (fast_charger && fast_charger->set_fast_chg_allow) + return fast_charger->set_fast_chg_allow(enable); + pr_err("no fast_charger register found\n"); + return false; +} + +static void op_clean_dash_status(void) +{ + if (fast_charger && fast_charger->clean) + return fast_charger->clean(); + pr_err("no fast_charger register found\n"); +} + +static bool op_get_fast_chg_allow(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->get_fast_chg_allow) + return fast_charger->get_fast_chg_allow(); + pr_err("no fast_charger register found\n"); + return false; +} + +static bool op_is_usb_switch_on(struct smb_charger *chg) +{ + if (fast_charger && fast_charger->is_usb_switch_on) + return fast_charger->is_usb_switch_on(); + + pr_err("no fast_charger register found\n"); + return false; +} + +static enum batt_status_type op_battery_status_get(struct smb_charger *chg) +{ + return chg->battery_status; +} + +static enum temp_region_type op_battery_temp_region_get(struct smb_charger *chg) +{ + return chg->mBattTempRegion; +} + +int fuelgauge_battery_temp_region_get(void) +{ + if (!g_chg) + return BATT_TEMP_NORMAL; + + return op_battery_temp_region_get(g_chg); +} + +static void op_battery_status_set(struct smb_charger *chg, + enum batt_status_type battery_status) +{ + chg->battery_status = battery_status; +} + +static void op_battery_temp_region_set(struct smb_charger *chg, + enum temp_region_type batt_temp_region) +{ + chg->mBattTempRegion = batt_temp_region; + pr_err("set temp_region=%d\n", chg->mBattTempRegion); + if (batt_temp_region == BATT_TEMP_INVALID) { + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + } +} + +static void set_prop_batt_health(struct smb_charger *chg, int batt_health) +{ + chg->batt_health = batt_health; +} + +static void set_usb_switch(struct smb_charger *chg, bool enable) +{ + int retrger_time; + + if (!fast_charger) { + pr_err("no fast_charger register found\n"); + return; + } + if (enable) { + pr_err("switch on fastchg\n"); + chg->switch_on_fastchg = true; + chg->disconnect_pd = true; + if (chg->boot_usb_present && chg->re_trigr_dash_done) { + vote(chg->usb_icl_votable, AICL_RERUN_VOTER, + true, 0); + usleep_range(500000, 510000); + vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); + vote(chg->usb_icl_votable, AICL_RERUN_VOTER, + true, DEFAULT_DCP_MA*1000); + } + set_mcu_active(0); + usleep_range(10000, 10002); + usb_sw_gpio_set(1); + usleep_range(10000, 10002); + mcu_en_gpio_set(0); + if (chg->boot_usb_present) + retrger_time = TIME_3S; + else + retrger_time = TIME_200MS; + if (!chg->re_trigr_dash_done) + schedule_delayed_work(&chg->rechk_sw_dsh_work, + msecs_to_jiffies(retrger_time)); + } else { + pr_err("switch off fastchg\n"); + chg->switch_on_fastchg = false; + update_disconnect_pd_status(false); + usb_sw_gpio_set(0); + mcu_en_gpio_set(1); + } +} + +static void switch_fast_chg(struct smb_charger *chg) +{ + bool fastchg_allowed, is_allowed; + static bool pre_fastchg_allowed, pre_is_allowed; + + mutex_lock(&chg->sw_dash_lock); + if (op_is_usb_switch_on(chg)) { + mutex_unlock(&chg->sw_dash_lock); + pr_info("dash alrady switched\n"); + return; + } + if (!is_usb_present(chg)) { + mutex_unlock(&chg->sw_dash_lock); + pr_info("dash usb is not present\n"); + return; + } + + fastchg_allowed = op_get_fast_chg_allow(chg); + if (pre_fastchg_allowed != fastchg_allowed) { + pre_fastchg_allowed = fastchg_allowed; + pr_info("fastchg_allowed = %d\n", fastchg_allowed); + } + if (!fastchg_allowed) { + is_allowed = is_fastchg_allowed(chg); + if (pre_is_allowed != is_allowed) { + pre_is_allowed = is_allowed; + pr_info("is_allowed = %d\n", is_allowed); + } + pr_info("is_allowed = %d\n", is_allowed); + if (is_allowed) { + set_usb_switch(chg, true); + op_set_fast_chg_allow(chg, true); + } + } + mutex_unlock(&chg->sw_dash_lock); +} + +static void op_re_kick_allowed_voltage(struct smb_charger *chg) +{ + const struct apsd_result *apsd_result; + + if (!is_usb_present(chg)) + return; + + apsd_result = smblib_get_apsd_result(chg); + if (apsd_result->bit == SDP_CHARGER_BIT) + return; + + pr_info("re-kick allowed voltage\n"); + smblib_set_usb_pd_allowed_voltage(chg, MICRO_9V, MICRO_9V); + msleep(500); + smblib_set_usb_pd_allowed_voltage(chg, MICRO_5V, MICRO_5V); +} + +static void op_re_kick_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + re_kick_work.work); + + if (chg->vbus_present) { + op_re_kick_allowed_voltage(chg); + schedule_delayed_work(&chg->check_switch_dash_work, + msecs_to_jiffies(500)); + } +} + +static void op_usb_remove_check_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + unplug_check_work.work); + + if (!chg->vbus_present) { + chg->ck_unplug_count = 0; + return; + } + if (chg->ck_unplug_count >= 4) { + pr_info("op usb remove checked\n"); + update_dash_unplug_status(); + } else { + chg->ck_unplug_count++; + schedule_delayed_work(&chg->unplug_check_work, + msecs_to_jiffies(TIME_100MS)); + } +} + +static void retrigger_dash_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + rechk_sw_dsh_work.work); + pr_debug("chg->ck_dash_count=%d\n", chg->ck_dash_count); + if (chg->usb_enum_status) + return; + if (chg->dash_present) { + chg->ck_dash_count = 0; + return; + } + if (!chg->vbus_present) { + chg->ck_dash_count = 0; + return; + } + if (chg->chg_disabled) { + chg->ck_dash_count = 0; + return; + } + if (chg->ck_dash_count == DASH_CHECK_COUNT) { + pr_info("retrger dash\n"); + chg->re_trigr_dash_done = true; + set_usb_switch(chg, false); + set_usb_switch(chg, true); + } else if (chg->ck_dash_count == 2 * DASH_CHECK_COUNT) { + set_usb_switch(chg, false); + } else if (chg->ck_dash_count > 2 * DASH_CHECK_COUNT) { + chg->ck_dash_count = 0; + chg->fastchg_switch_disable = true; + cancel_delayed_work(&chg->pdo_select_check_work); + schedule_delayed_work(&chg->pdo_select_check_work, + msecs_to_jiffies(2000)); + return; + } + + chg->ck_dash_count++; + schedule_delayed_work(&chg->rechk_sw_dsh_work, + msecs_to_jiffies(TIME_200MS)); +} + +static void op_check_high_vbat_chg_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + op_check_high_vbat_chg_work.work); + union power_supply_propval vbus_val; + int rc, temp_region, soc, ibat; + const struct apsd_result *apsd_result; + + pr_info("chg->check_high_vbat_chg_count=%d\n", chg->check_high_vbat_chg_count); + soc = get_prop_batt_capacity(chg); + if (chg->usb_enum_status || + chg->chg_done || + chg->chg_disabled || + !chg->chg_enabled || + chg->is_aging_test) { + chg->check_high_vbat_chg_count = 0; + return; + } + temp_region = op_battery_temp_region_get(chg); + if (temp_region == BATT_TEMP_COLD + || temp_region == BATT_TEMP_HOT) { + chg->check_high_vbat_chg_count = 0; + return; + } + apsd_result = smblib_update_usb_type(chg); + if (apsd_result->bit == SDP_CHARGER_BIT + || apsd_result->bit == CDP_CHARGER_BIT) { + chg->check_high_vbat_chg_count = 0; + return; + } + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + chg->check_high_vbat_chg_count = 0; + pr_info("failed to read usb_voltage rc=%d\n", rc); + return; + } + if (vbus_val.intval < 2500) { + pr_info("vbus less 2.5v\n"); + chg->check_high_vbat_chg_count = 0; + return; + } + ibat = get_prop_batt_current_now(chg); + if (ibat < 0) { + chg->check_high_vbat_chg_count = 0; + pr_info("Ibat is %d\n", ibat); + return; + } + if (chg->check_high_vbat_chg_count > 100) { + pr_info("recovery charge\n"); + chg->check_high_vbat_chg_count = 0; + vote(chg->usb_icl_votable, CHG_RECOVERY_VOTER, + true, 0); + op_charging_en(chg, false); + msleep(1000); + vote(chg->usb_icl_votable, CHG_RECOVERY_VOTER, + false, 0); + op_charging_en(chg, true); + } else { + chg->check_high_vbat_chg_count++; + schedule_delayed_work(&chg->op_check_high_vbat_chg_work, + msecs_to_jiffies(400)); + } +} + +static void op_chek_apsd_done_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + op_check_apsd_work.work); + union power_supply_propval vbus_val; + int rc; + const struct apsd_result *apsd_result; + + pr_debug("chg->ck_apsd_count=%d\n", chg->ck_apsd_count); + if (chg->usb_enum_status || chg->op_apsd_done || chg->pd_active) { + pr_info("usb_enum_status or apsd_done or pd_active set, so return"); + chg->ck_apsd_count = 0; + return; + } + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + chg->ck_apsd_count = 0; + pr_info("failed to read usb_voltage rc=%d\n", rc); + return; + } + if (vbus_val.intval < 2500) { + pr_info("vbus less 2.5v\n"); + chg->ck_apsd_count = 0; + return; + } + apsd_result = smblib_get_apsd_result(chg); + if (apsd_result->bit) { + chg->ck_apsd_count = 0; + return; + } + + if (chg->ck_apsd_count >= APSD_CHECK_COUTNT) { + pr_info("apsd done error\n"); + chg->ck_apsd_count = 0; + op_dump_regs(chg); + op_rerun_apsd(chg); + } else { + chg->ck_apsd_count++; + schedule_delayed_work(&chg->op_check_apsd_work, + msecs_to_jiffies(TIME_1000MS)); + } +} + +static void op_recovery_usb_suspend_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + recovery_suspend_work.work); + int effect_result; + + if (chg->recovery_boost_count >= BOOST_BACK_COUNT + || (!is_usb_present(chg))) { + pr_info("recovery revert boost\n"); + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0); + if (is_usb_present(chg)) { + effect_result = + get_effective_result(chg->usb_icl_votable); + pr_info("effect_result=%d\n", effect_result); + if (effect_result + > DEFAULT_AGAING_CHG_MA*1000) { + vote(chg->usb_icl_votable, DCP_VOTER, + true, (effect_result - USBIN_150MA)); + smblib_run_aicl(chg, RERUN_AICL); + } + } + msleep(1000); + chg->revert_boost_trigger = false; + } else { + chg->recovery_boost_count++; + schedule_delayed_work(&chg->recovery_suspend_work, + msecs_to_jiffies(TIME_100MS)); + } +} + +static void op_check_allow_switch_dash_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, check_switch_dash_work); + const struct apsd_result *apsd_result; + + if (!is_usb_present(chg)) + return; + if (chg->usb_enum_status) + return; + if (chg->fastchg_switch_disable) + return; + + if (chg->pd_active) { + switch_fast_chg(chg); + return; + } + + apsd_result = smblib_get_apsd_result(chg); + if (((apsd_result->bit != SDP_CHARGER_BIT + && apsd_result->bit != CDP_CHARGER_BIT) + && apsd_result->bit) + || chg->non_std_chg_present) + switch_fast_chg(chg); +} + +int check_allow_switch_dash(struct smb_charger *chg, + const union power_supply_propval *val) +{ + if (val->intval < 0) + return -EINVAL; + + schedule_delayed_work(&chg->check_switch_dash_work, + msecs_to_jiffies(500)); + return 0; +} + +#define DEFAULT_WALL_CHG_MA 1800 +static int set_dash_charger_present(int status) +{ + int charger_present; + bool pre_dash_present; + + if (g_chg) { + pre_dash_present = g_chg->dash_present; + charger_present = is_usb_present(g_chg); + g_chg->dash_present = status && charger_present; + if (g_chg->dash_present && !pre_dash_present) { + pr_err("set dash online\n"); + g_chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_DASH; + vote(g_chg->usb_icl_votable, PD_VOTER, true, + DEFAULT_WALL_CHG_MA * 1000); + } + if (g_chg->dash_present) { + g_chg->real_charger_type = POWER_SUPPLY_TYPE_DASH; + g_chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_DASH; + } + power_supply_changed(g_chg->batt_psy); + pr_info("dash_present = %d, charger_present = %d\n", + g_chg->dash_present, charger_present); + } else { + pr_err("set dash charger present error\n"); + } + + return 0; +} + +/*yangfb@bsp, 20181023 icl set 1A if battery lower than 15%*/ +static void op_otg_icl_contrl(struct smb_charger *chg) +{ + int cap, rc; + static int icl_pre, icl; + + if (!chg->OTG_ICL_CTRL) + return; + cap = get_prop_batt_capacity(chg); + if (cap <= chg->OTG_LOW_BAT) { + icl = chg->OTG_LOW_BAT_ICL; + } else if (cap > chg->OTG_LOW_BAT + && icl_pre == chg->OTG_LOW_BAT_ICL) { + icl = chg->OTG_NORMAL_BAT_ICL; + } + + if (icl_pre == icl) + return; + pr_info("cap=%d,icl=%d,icl_pre=%d\n", cap, icl, icl_pre); + rc = smblib_set_charge_param(chg, &chg->param.otg_cl, + icl); + if (rc < 0) + smblib_err(chg, "Couldn't set otg icl rc=%d\n", rc); + icl_pre = icl; +} + +#ifndef CONFIG_OP_DEBUG_CHG +static void op_check_charge_timeout(struct smb_charger *chg) +{ + static int batt_status, count; + + if (chg->chg_done || chg->is_aging_test) + return; + + batt_status = get_prop_batt_status(chg); + if (chg->vbus_present + && batt_status == POWER_SUPPLY_STATUS_CHARGING) + count++; + else + count = 0; + + if (count > CHG_TIMEOUT_COUNT) { + pr_err("chg timeout! stop chaging now\n"); + op_charging_en(chg, false); + chg->time_out = true; + } +} +#endif + +static int get_prop_batt_present(struct smb_charger *chg) +{ + int rc; + u8 stat; + + rc = smblib_read(chg, BATIF_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + pr_err("Couldn't read BATIF_INT_RT_STS rc=%d\n", rc); + return rc; + } + + return !(stat & (BAT_THERM_OR_ID_MISSING_RT_STS_BIT + | BAT_TERMINAL_MISSING_RT_STS_BIT)); +} + +#define DEFAULT_BATT_CAPACITY 50 +static int get_prop_batt_capacity(struct smb_charger *chg) +{ + int capacity, rc; + + if (chg->fake_capacity >= 0) + return chg->fake_capacity; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_CAPACITY, &capacity); + if (rc) { + pr_err("Couldn't get capacity rc=%d\n", rc); + capacity = DEFAULT_BATT_CAPACITY; + } + + return capacity; +} + +#define DEFAULT_BATT_TEMP 200 +static int get_prop_batt_temp(struct smb_charger *chg) +{ + int temp, rc; + + if (chg->use_fake_temp) + return chg->fake_temp; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_TEMP, &temp); + if (rc) { + pr_err("Couldn't get temperature rc=%d\n", rc); + temp = DEFAULT_BATT_TEMP; + } + + return temp; +} + +#define DEFAULT_BATT_CURRENT_NOW 0 +static int get_prop_batt_current_now(struct smb_charger *chg) +{ + int ua, rc; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_CURRENT_NOW, &ua); + if (rc) { + pr_err("Couldn't get current rc=%d\n", rc); + ua = DEFAULT_BATT_CURRENT_NOW; + } + + return ua; +} + +#define DEFAULT_BATT_VOLTAGE_NOW 0 +static int get_prop_batt_voltage_now(struct smb_charger *chg) +{ + int uv, rc; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_VOLTAGE_NOW, &uv); + if (rc) { + pr_err("Couldn't get voltage rc=%d\n", rc); + uv = DEFAULT_BATT_VOLTAGE_NOW; + } + + return uv; +} + +static int get_prop_fg_capacity(struct smb_charger *chg) +{ + int capacity = 0, rc; + + if (chg->fake_capacity >= 0) + return chg->fake_capacity; + + rc = get_property_from_fg(chg, + POWER_SUPPLY_PROP_FG_CAPACITY, &capacity); + if (rc) { + pr_err("Couldn't get capacity rc=%d\n", rc); + capacity = DEFAULT_BATT_CAPACITY; + } + + return capacity; +} + +static int get_prop_fg_current_now(struct smb_charger *chg) +{ + int ua = 0, rc; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_FG_CURRENT_NOW, &ua); + if (rc) { + pr_err("Couldn't get current rc=%d\n", rc); + ua = DEFAULT_BATT_CURRENT_NOW; + } + + return ua; +} + +static int get_prop_fg_voltage_now(struct smb_charger *chg) +{ + int uv, rc; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_FG_VOLTAGE_NOW, &uv); + if (rc) { + pr_err("Couldn't get voltage rc=%d\n", rc); + uv = DEFAULT_BATT_VOLTAGE_NOW; + } + + return uv; +} + +int get_prop_batt_status(struct smb_charger *chg) +{ + int capacity, batt_status, rc; + enum temp_region_type temp_region; + union power_supply_propval pval = {0, }; + + temp_region = op_battery_temp_region_get(chg); + capacity = get_prop_batt_capacity(chg); + chg->dash_on = get_prop_fast_chg_started(chg); + if ((chg->chg_done || chg->recharge_status) + && (temp_region == BATT_TEMP_COOL + || temp_region == BATT_TEMP_LITTLE_COOL + || temp_region == BATT_TEMP_PRE_NORMAL + || temp_region == BATT_TEMP_NORMAL) + && capacity == 100) { + return POWER_SUPPLY_STATUS_FULL; + } else if (chg->dash_on && chg->dash_present) { + return POWER_SUPPLY_STATUS_CHARGING; + } + if (chg->revert_boost_trigger && chg->vbus_present) + return POWER_SUPPLY_STATUS_CHARGING; + + rc = smblib_get_prop_batt_status(chg, &pval); + if (rc) + batt_status = 0; + else + batt_status = pval.intval; + + return batt_status; +} + +int op_get_batt_status(struct smb_charger *chg, + union power_supply_propval *val) +{ + union power_supply_propval pval = {0, }; + bool usb_online, dc_online; + u8 stat; + int rc, suspend = 0; + + if (chg->fake_chg_status_on_debug_batt) { + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_DEBUG_BATTERY, &pval); + if (rc < 0) { + pr_err_ratelimited("Couldn't get debug battery prop rc=%d\n", + rc); + } else if (pval.intval == 1) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; + } + } + + rc = smblib_get_prop_batt_health(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get batt health rc=%d\n", rc); + return rc; + } + /* + * The charger status register shows charging even though the battery + * is discharging when the over voltage condition is hit. Report power + * supply state as NOT_CHARGING when the battery health reports + * over voltage. + */ + if (pval.intval == POWER_SUPPLY_HEALTH_OVERVOLTAGE) { + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + return 0; + } + + if (chg->dbc_usbov) { + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, + "Couldn't get usb present prop rc=%d\n", rc); + return rc; + } + + rc = smblib_get_usb_suspend(chg, &suspend); + if (rc < 0) { + smblib_err(chg, + "Couldn't get usb suspend rc=%d\n", rc); + return rc; + } + + /* + * Report charging as long as USBOV is not debounced and + * charging path is un-suspended. + */ + if (pval.intval && !suspend) { + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return 0; + } + } + + rc = smblib_get_prop_usb_online(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb online property rc=%d\n", + rc); + return rc; + } + usb_online = (bool)pval.intval; + + rc = smblib_get_prop_dc_online(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get dc online property rc=%d\n", + rc); + return rc; + } + dc_online = (bool)pval.intval; + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", + rc); + return rc; + } + stat = stat & BATTERY_CHARGER_STATUS_MASK; + + if (!usb_online && !dc_online) { + switch (stat) { + case TERMINATE_CHARGE: + case INHIBIT_CHARGE: + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + default: + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + break; + } + return rc; + } + + switch (stat) { + case TRICKLE_CHARGE: + case PRE_CHARGE: + case FULLON_CHARGE: + case TAPER_CHARGE: + val->intval = POWER_SUPPLY_STATUS_CHARGING; + break; + case TERMINATE_CHARGE: + case INHIBIT_CHARGE: + val->intval = POWER_SUPPLY_STATUS_FULL; + break; + case DISABLE_CHARGE: + case PAUSE_CHARGE: + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + default: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + break; + } + + if (is_charging_paused(chg)) { + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return 0; + } + + /* + * If charge termination WA is active and has suspended charging, then + * continue reporting charging status as FULL. + */ + if (is_client_vote_enabled_locked(chg->usb_icl_votable, + CHG_TERMINATION_VOTER)) { + val->intval = POWER_SUPPLY_STATUS_FULL; + return 0; + } + + if (val->intval != POWER_SUPPLY_STATUS_CHARGING) + return 0; + + if (!usb_online && dc_online + && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) { + val->intval = POWER_SUPPLY_STATUS_FULL; + return 0; + } + + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", + rc); + return rc; + } + + stat &= ENABLE_TRICKLE_BIT | ENABLE_PRE_CHARGING_BIT | + ENABLE_FULLON_MODE_BIT; + + if (!stat) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + + return 0; +} + +int get_charging_status(void) +{ + int rc; + union power_supply_propval pval = {0, }; + + if (!g_chg) + return POWER_SUPPLY_STATUS_DISCHARGING; + + rc = op_get_batt_status(g_chg, &pval); + if (rc) + return POWER_SUPPLY_STATUS_UNKNOWN; + + return pval.intval; +} + +void set_chg_ibat_vbat_max( + struct smb_charger *chg, int ibat, int vfloat) +{ + enum temp_region_type temp_region; + + pr_err("set ibatmax=%d and set vbatmax=%d\n", + ibat, vfloat); + if (chg->ffc_status != FFC_DEFAULT) + return; + vote(chg->fv_votable, + DEFAULT_VOTER, true, vfloat * 1000); + temp_region = op_battery_temp_region_get(chg); + if (chg->pd_active && temp_region == BATT_TEMP_NORMAL) { + vote(chg->fcc_votable, + DEFAULT_VOTER, true, PD_FCC_CURRENT_UA); + } else { + vote(chg->fcc_votable, + DEFAULT_VOTER, true, ibat * 1000); + } + + /* set cc to cv 100mv lower than vfloat */ + set_property_on_fg(chg, POWER_SUPPLY_PROP_CC_TO_CV_POINT, vfloat - 100); +} + +static void op_temp_region_charging_en(struct smb_charger *chg, int vbatmax) +{ + int vbat_mv = 0; + + vbat_mv = get_prop_batt_voltage_now(chg) / 1000; + pr_info("%s vbat_mv =%d\n", __func__, vbat_mv); + if (vbat_mv < vbatmax) + return; + op_charging_en(chg, false); + chg->chg_done = true; +} + +/* Tbatt < -3C */ +static int handle_batt_temp_cold(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_COLD || chg->is_power_changed) { + pr_err("triggered\n"); + chg->is_power_changed = false; + + op_charging_en(chg, false); + op_battery_temp_region_set(chg, BATT_TEMP_COLD); + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0 + BATT_TEMP_HYST; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_COLD); + } + + return 0; +} + +/* -3C <= Tbatt <= 0C */ +static int handle_batt_temp_little_cold(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + + if (chg->chg_ovp) + return 0; + + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_LITTLE_COLD + || chg->is_power_changed || chg->recharge_pending) { + pr_err("triggered\n"); + chg->recharge_pending = false; + chg->is_power_changed = false; + + if (temp_region == BATT_TEMP_HOT || + temp_region == BATT_TEMP_COLD) + op_charging_en(chg, true); + op_battery_temp_region_set(chg, BATT_TEMP_LITTLE_COLD); + op_temp_region_charging_en(chg, + chg->vbatmax[BATT_TEMP_LITTLE_COLD]); + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_LITTLE_COLD], + chg->vbatmax[BATT_TEMP_LITTLE_COLD]); + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1 + BATT_TEMP_HYST; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + } + + return 0; +} + +/* 0C < Tbatt <= 5C*/ +static int handle_batt_temp_cool(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + int vbat_mv; + + if (chg->chg_ovp) + return 0; + + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_COOL + || chg->is_power_changed || chg->recharge_pending) { + pr_err("triggered\n"); + chg->recharge_pending = false; + chg->is_power_changed = false; + + if (temp_region == BATT_TEMP_HOT || + temp_region == BATT_TEMP_COLD) + op_charging_en(chg, true); + op_battery_temp_region_set(chg, BATT_TEMP_COOL); + vbat_mv = get_prop_batt_voltage_now(chg) / 1000; + if (vbat_mv > chg->temp_cool_voltage) { + set_chg_ibat_vbat_max(chg, chg->temp_cool_current, + chg->vbatmax[BATT_TEMP_COOL]); + chg->temp_littel_cool_set_current_0_point_25c = false; + } else { + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_COOL], + chg->vbatmax[BATT_TEMP_COOL]); + chg->temp_littel_cool_set_current_0_point_25c = true; + } + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2 + BATT_TEMP_HYST; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + } + + return 0; +} +/* 5C < Tbatt <= 12C */ +static int handle_batt_temp_little_cool(struct smb_charger *chg) +{ + int temp_region, vbat_mv; + + if (chg->chg_ovp) + return 0; + + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_LITTLE_COOL + || chg->is_power_changed || chg->recharge_pending) { + pr_err("triggered\n"); + chg->recharge_pending = false; + chg->is_power_changed = false; + + if (temp_region == BATT_TEMP_HOT || + temp_region == BATT_TEMP_COLD) + op_charging_en(chg, true); + op_battery_temp_region_set(chg, BATT_TEMP_LITTLE_COOL); + vbat_mv = get_prop_batt_voltage_now(chg) / 1000; + if (vbat_mv > chg->temp_littel_cool_voltage) { + set_chg_ibat_vbat_max(chg, + chg->temp_littel_cool_current, + chg->vbatmax[BATT_TEMP_LITTLE_COOL]); + chg->temp_littel_cool_set_current_0_point_25c = false; + } else { + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_LITTLE_COOL], + chg->vbatmax[BATT_TEMP_LITTLE_COOL]); + chg->temp_littel_cool_set_current_0_point_25c = true; + } + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3 + BATT_TEMP_HYST; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + } + + return 0; +} + +/* 12C < Tbatt < 16C */ +static int handle_batt_temp_prenormal(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + + if (chg->chg_ovp) + return 0; + + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_PRE_NORMAL + || chg->is_power_changed || chg->recharge_pending) { + pr_err("triggered\n"); + chg->recharge_pending = false; + chg->is_power_changed = false; + + if (temp_region == BATT_TEMP_HOT || + temp_region == BATT_TEMP_COLD) + op_charging_en(chg, true); + op_battery_temp_region_set(chg, BATT_TEMP_PRE_NORMAL); + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_PRE_NORMAL], + chg->vbatmax[BATT_TEMP_PRE_NORMAL]); + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4 + BATT_TEMP_HYST; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + } + + return 0; +} + +/* 16C < Tbatt < 45C */ +static int handle_batt_temp_normal(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + + if (chg->chg_ovp) + return 0; + + temp_region = op_battery_temp_region_get(chg); + if ((temp_region != BATT_TEMP_NORMAL) + || chg->is_power_changed || chg->recharge_pending) { + pr_err("triggered\n"); + chg->recharge_pending = false; + chg->is_power_changed = false; + + if (temp_region == BATT_TEMP_HOT || + temp_region == BATT_TEMP_COLD) + op_charging_en(chg, true); + op_battery_temp_region_set(chg, BATT_TEMP_NORMAL); + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_NORMAL], + chg->vbatmax[BATT_TEMP_NORMAL]); + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + } + + return 0; +} + +/* 45C <= Tbatt <= 55C */ +static int handle_batt_temp_warm(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + + if (chg->chg_ovp) + return 0; + + temp_region = op_battery_temp_region_get(chg); + if ((temp_region != BATT_TEMP_WARM) + || chg->is_power_changed || chg->recharge_pending) { + pr_err("triggered\n"); + chg->is_power_changed = false; + chg->recharge_pending = false; + + if (temp_region == BATT_TEMP_HOT || + temp_region == BATT_TEMP_COLD) + op_charging_en(chg, true); + op_battery_temp_region_set(chg, BATT_TEMP_WARM); + op_temp_region_charging_en(chg, + chg->vbatmax[BATT_TEMP_WARM]); + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_WARM], + chg->vbatmax[BATT_TEMP_WARM]); + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5 - BATT_TEMP_HYST; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + } + + return 0; +} + +/* 55C < Tbatt */ +static int handle_batt_temp_hot(struct smb_charger *chg) +{ + enum temp_region_type temp_region; + + temp_region = op_battery_temp_region_get(chg); + if ((temp_region != BATT_TEMP_HOT) + || chg->is_power_changed) { + pr_err("triggered\n"); + chg->is_power_changed = false; + op_charging_en(chg, false); + op_battery_temp_region_set(chg, BATT_TEMP_HOT); + + /* Update the temperature boundaries */ + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = + chg->BATT_TEMP_T6 - BATT_TEMP_HYST; + /* from hot to warm */ + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_OVERHEAT); + } + + return 0; +} + +static int op_check_battery_temp(struct smb_charger *chg) +{ + int temp, rc = -1; + + if (!chg->vbus_present) + return rc; + temp = get_prop_batt_temp(chg); + + if (temp < chg->mBattTempBoundT0) /* COLD */ + rc = handle_batt_temp_cold(chg); + else if (temp >= chg->mBattTempBoundT0 && + temp < chg->mBattTempBoundT1) /* LITTLE_COLD */ + rc = handle_batt_temp_little_cold(chg); + else if (temp >= chg->mBattTempBoundT1 && + temp < chg->mBattTempBoundT2) /* COOL */ + rc = handle_batt_temp_cool(chg); + else if (temp >= chg->mBattTempBoundT2 && + temp < chg->mBattTempBoundT3) /* LITTLE_COOL */ + rc = handle_batt_temp_little_cool(chg); + else if (temp >= chg->mBattTempBoundT3 && + temp < chg->mBattTempBoundT4) /* PRE_NORMAL */ + rc = handle_batt_temp_prenormal(chg); + else if (temp >= chg->mBattTempBoundT4 && + temp < chg->mBattTempBoundT5) /* NORMAL */ + rc = handle_batt_temp_normal(chg); + else if (temp >= chg->mBattTempBoundT5 && + temp <= chg->mBattTempBoundT6) /* WARM */ + rc = handle_batt_temp_warm(chg); + else if (temp > chg->mBattTempBoundT6) /* HOT */ + rc = handle_batt_temp_hot(chg); + + return rc; +} + +void op_charge_info_init(struct smb_charger *chg) +{ + op_battery_temp_region_set(chg, BATT_TEMP_NORMAL); + + chg->mBattTempBoundT0 = chg->BATT_TEMP_T0; + chg->mBattTempBoundT1 = chg->BATT_TEMP_T1; + chg->mBattTempBoundT2 = chg->BATT_TEMP_T2; + chg->mBattTempBoundT3 = chg->BATT_TEMP_T3; + chg->mBattTempBoundT4 = chg->BATT_TEMP_T4; + chg->mBattTempBoundT5 = chg->BATT_TEMP_T5; + chg->mBattTempBoundT6 = chg->BATT_TEMP_T6; + chg->chg_ovp = false; + chg->is_power_changed = false; + chg->chg_done = false; + chg->recharge_pending = false; + chg->recharge_status = false; + chg->temp_littel_cool_set_current_0_point_25c = false; + chg->oem_lcd_is_on = false; + chg->time_out = false; + chg->battery_status = BATT_STATUS_GOOD; + chg->disable_normal_chg_for_dash = false; + chg->fastchg_switch_disable = false; + chg->usb_enum_status = false; + chg->non_std_chg_present = false; + chg->is_audio_adapter = false; + chg->init_irq_done = false; +} + +static int op_handle_battery_uovp(struct smb_charger *chg) +{ + pr_err("vbat is over voltage, stop charging\n"); + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_OVERVOLTAGE); + op_charging_en(chg, false); + + return 0; +} + +static int op_handle_battery_restore_from_uovp(struct smb_charger *chg) +{ + pr_err("vbat is back to normal, start charging\n"); + /* restore charging form battery ovp */ + op_charging_en(chg, true); + set_prop_batt_health(chg, POWER_SUPPLY_HEALTH_GOOD); + + return 0; +} + +static void op_check_battery_uovp(struct smb_charger *chg) +{ + int vbat_mv = 0; + enum batt_status_type battery_status_pre; + + if (!chg->vbus_present) + return; + + battery_status_pre = op_battery_status_get(chg); + vbat_mv = get_prop_batt_voltage_now(chg) / 1000; + pr_debug("bat vol:%d\n", vbat_mv); + if (vbat_mv > BATT_SOFT_OVP_MV) { + if (battery_status_pre == BATT_STATUS_GOOD) { + pr_err("BATTERY_SOFT_OVP_VOLTAGE\n"); + op_battery_status_set(chg, BATT_STATUS_BAD); + op_handle_battery_uovp(chg); + } + } else { + if (battery_status_pre == BATT_STATUS_BAD) { + pr_err("battery_restore_from_uovp\n"); + op_battery_status_set(chg, BATT_STATUS_GOOD); + op_handle_battery_restore_from_uovp(chg); + } + } + +} +int op_get_charg_en(struct smb_charger *chg, int *chg_enabled) +{ + int rc = 0; + u8 temp; + + rc = smblib_read(chg, CHARGING_ENABLE_CMD_REG, &temp); + if (rc < 0) { + smblib_err(chg, "Couldn't read chg en rc=%d\n", rc); + return rc; + } + *chg_enabled = temp & CHARGING_ENABLE_CMD_BIT; + + return rc; +} + +static void op_check_charger_collapse(struct smb_charger *chg) +{ + int rc, is_usb_supend, curr, chg_en; + u8 stat = 0, chger_stat = 0, pwer_source_stats = 0; + + if (!chg->vbus_present) + return; + if (chg->dash_present) + return; + rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &chger_stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", + rc); + } + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &pwer_source_stats); + if (rc < 0) { + smblib_err(chg, "Couldn't read AICL_STATUS_REG rc=%d\n", + rc); + } + smblib_get_usb_suspend(chg, &is_usb_supend); + op_get_charg_en(chg, &chg_en); + pr_debug("chger_stat=0x%x, aicl_stats =0x%x, chg_en =%d\n", + chger_stat, pwer_source_stats, chg_en); + curr = get_prop_batt_current_now(chg) / 1000; + stat = !chg->chg_done + && !is_usb_supend + && (curr > 20) + && chg_en + && ((ZERO_CHARGE_CURRENT_BIT & chger_stat) + || (pwer_source_stats == 0x72)); + + if (stat && !chg->charger_collpse) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + SUSPEND_ON_COLLAPSE_USBIN_BIT + |USBIN_AICL_START_AT_MAX_BIT + |USBIN_AICL_ADC_EN_BIT + |USBIN_AICL_PERIODIC_RERUN_EN_BIT, + USBIN_AICL_PERIODIC_RERUN_EN_BIT); + if (rc < 0) + dev_err(chg->dev, + "Couldn't configure AICL rc=%d\n", rc); + smblib_run_aicl(chg, RERUN_AICL); + chg->charger_collpse = true; + schedule_delayed_work(&chg->op_re_set_work, + msecs_to_jiffies(TIME_1000MS)); + smblib_err(chg, "op check charger collapse done\n"); + } +} + +static void op_check_charger_uovp(struct smb_charger *chg, int vchg_mv) +{ + static int over_volt_count, not_over_volt_count; + static bool uovp_satus, pre_uovp_satus; + int detect_time = 3; /* 3 x 6s = 18s */ + + if (!chg->vbus_present) + return; + + if (chg->pd_active) + return; + + pr_err("charger_voltage=%d charger_ovp=%d pd_active=%d\n", + vchg_mv, chg->chg_ovp, chg->pd_active); + + if (chg->pd_active) + return; + + if (!chg->chg_ovp) { + if (vchg_mv > CHG_SOFT_OVP_MV || vchg_mv <= CHG_SOFT_UVP_MV) { + pr_err("charger is over voltage, count=%d\n", + over_volt_count); + uovp_satus = true; + if (pre_uovp_satus) + over_volt_count++; + else + over_volt_count = 0; + + pr_err("uovp_satus=%d,pre_uovp_satus=%d,over_volt_count=%d\n", + uovp_satus, pre_uovp_satus, over_volt_count); + if (detect_time <= over_volt_count) { + /* vchg continuous higher than 5.8v */ + pr_err("charger is over voltage, stop charging\n"); + op_charging_en(chg, false); + chg->chg_ovp = true; + } + } + } else { + if (vchg_mv < CHG_SOFT_OVP_MV - 100 + && vchg_mv > CHG_SOFT_UVP_MV + 100) { + uovp_satus = false; + if (!pre_uovp_satus) + not_over_volt_count++; + else + not_over_volt_count = 0; + + pr_err("uovp_satus=%d, pre_uovp_satus=%d,not_over_volt_count=%d\n", + uovp_satus, pre_uovp_satus, + not_over_volt_count); + if (detect_time <= not_over_volt_count) { + /* vchg continuous lower than 5.7v */ + pr_err("charger voltage is back to normal\n"); + op_charging_en(chg, true); + chg->chg_ovp = false; + op_check_battery_temp(chg); + smblib_run_aicl(chg, RERUN_AICL); + } + } + } + pre_uovp_satus = uovp_satus; +} + +static void op_dcdc_vph_track_sel(struct smb_charger *chg) +{ + int rc = 0; + + pr_debug("lcd_is_on:%d\n", chg->oem_lcd_is_on); + + if (chg->vbus_present && chg->chg_done && !chg->vph_sel_disable) { + if (chg->oem_lcd_is_on && !chg->vph_set_flag) { + pr_info("vbus present,LCD on set dcdc vph 300mv\n"); + /* config the DCDC_VPH_TRACK_SEL 300mv */ + rc = smblib_masked_write(chg, DCDC_VPH_TRACK_SEL, + VPH_TRACK_SEL_MASK, SEL_200MV); + if (rc < 0) + pr_err("Couldn't set DCDC_VPH_TRACK_SEL rc=%d\n", + rc); + chg->vph_set_flag = true; + } else if (!chg->oem_lcd_is_on && chg->vph_set_flag) { + pr_info("vbus present,LCD off set dcdc vph 100mv\n"); + /* config the DCDC_VPH_TRACK_SEL 100mv */ + rc = smblib_masked_write(chg, DCDC_VPH_TRACK_SEL, + VPH_TRACK_SEL_MASK, 0); + if (rc < 0) + pr_err("Couldn't set DCDC_VPH_TRACK_SEL rc=%d\n", + rc); + chg->vph_set_flag = false; + } + } +} + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct smb_charger *chip = + container_of(self, struct smb_charger, fb_notif); + + if (evdata && evdata->data && chip) { + if (event == FB_EVENT_BLANK) { + blank = evdata->data; + if (*blank == FB_BLANK_UNBLANK) { + if (!chip->oem_lcd_is_on) + set_property_on_fg(chip, + POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF, 0); + chip->oem_lcd_is_on = true; + } else if (*blank == FB_BLANK_POWERDOWN) { + if (chip->oem_lcd_is_on != false) + set_property_on_fg(chip, + POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF, 1); + chip->oem_lcd_is_on = false; + } + } + + } + + return 0; +} +#elif defined(CONFIG_MSM_RDM_NOTIFY) +static int msm_drm_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct drm_panel_notifier *evdata = data; + struct smb_charger *chip = + container_of(self, struct smb_charger, msm_drm_notifier); + int *blank; + int typec_mode; + int rp_ua; + + if ((evdata == NULL) || (event != DRM_PANEL_EARLY_EVENT_BLANK)) + return 0; + + typec_mode = smblib_get_prop_typec_mode(chip); + if (evdata && evdata->data && chip) { + blank = evdata->data; + if (*blank == DRM_PANEL_BLANK_UNBLANK || + *blank == DRM_PANEL_BLANK_UNBLANK_CHARGE) { + if (!chip->oem_lcd_is_on) + set_property_on_fg(chip, + POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF, 0); + chip->oem_lcd_is_on = true; + op_dcdc_vph_track_sel(chip); + } else if (*blank == DRM_PANEL_BLANK_POWERDOWN || + *blank == DRM_PANEL_BLANK_POWERDOWN_CHARGE) { + if (chip->oem_lcd_is_on != false) + set_property_on_fg(chip, + POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF, 1); + chip->oem_lcd_is_on = false; + op_dcdc_vph_track_sel(chip); + } + /* add to set pd charging current 2.0A when panel on */ + if (typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH || + typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM || + typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { + rp_ua = get_rp_based_dcp_current(chip, typec_mode); + if (!chip->pd_active) { + vote(chip->usb_icl_votable, + SW_ICL_MAX_VOTER, true, rp_ua); + } + } + } + + return 0; +} +#endif + +static void ffc_exit(struct smb_charger *chg) +{ + int icharging, batt_volt, temp; + + if (chg->ffc_status == FFC_DEFAULT) { + chg->ffc_count = 0; + return; + } + batt_volt = get_prop_batt_voltage_now(chg) / 1000; + icharging = get_prop_batt_current_now(chg) / 1000; + temp = get_prop_batt_temp(chg); + + if (chg->ffc_status == FFC_NOR_TAPER + || chg->ffc_status == FFC_WARM_TAPER) { + if (temp > chg->FFC_TEMP_T1 + && temp < chg->FFC_TEMP_T2) { + chg->ffc_status = FFC_NOR_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_NOR_FCC * 1000); + } else if (temp >= chg->FFC_TEMP_T2 + && temp < chg->FFC_TEMP_T3) { + chg->ffc_status = FFC_WARM_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_WARM_FCC * 1000); + } else { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } + } + + if (chg->ffc_status == FFC_FAST) { + if (batt_volt >= chg->FFC_VBAT_FULL) + chg->ffc_count++; + else + chg->ffc_count = 0; + if (chg->ffc_count >= 2) { + chg->ffc_count = 0; + chg->ffc_status = FFC_TAPER; + pr_info("ffc one done\n"); + } + } else if (chg->ffc_status == FFC_TAPER) { + if (temp > chg->FFC_TEMP_T1 + && temp < chg->FFC_TEMP_T2) { + chg->ffc_status = FFC_NOR_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_NOR_FCC * 1000); + } else if (temp >= chg->FFC_TEMP_T2 + && temp < chg->FFC_TEMP_T3) { + chg->ffc_status = FFC_WARM_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_WARM_FCC * 1000); + } else { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } + } else if (chg->ffc_status == FFC_NOR_TAPER) { + if (icharging <= (-1)*chg->FFC_NORMAL_CUTOFF + && (batt_volt >= chg->FFC_VBAT_FULL)) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } else if (icharging > (-1)*chg->FFC_NORMAL_CUTOFF) + chg->ffc_count++; + else + chg->ffc_count = 0; + if (chg->ffc_count >= 2) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + pr_info("ffc nor taper done\n"); + } + } else if (chg->ffc_status == FFC_WARM_TAPER) { + if (icharging <= (-1)*chg->FFC_WARM_CUTOFF + && (batt_volt >= chg->FFC_VBAT_FULL)) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } else if (icharging > (-1)*chg->FFC_WARM_CUTOFF) + chg->ffc_count++; + else + chg->ffc_count = 0; + if (chg->ffc_count >= 2) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + pr_info("ffc normal taper done\n"); + } + } else if (chg->ffc_status == FFC_IDLE) { + chg->ffc_count++; + op_charging_en(chg, false); + if (chg->ffc_count > 5) { + chg->ffc_status = FFC_DEFAULT; + smblib_set_prop_charge_parameter_set(chg); + op_charging_en(chg, true); + } + } else { + chg->ffc_count = 0; + chg->ffc_status = FFC_DEFAULT; + } +} + +#define FULL_COUNTS_SW 5 +#define FULL_COUNTS_HW 3 + +static bool op_check_vbat_is_full_by_sw(struct smb_charger *chg) +{ + static bool ret_sw; + static bool ret_hw; + static int vbat_counts_sw; + static int vbat_counts_hw; + int vbatt_full_vol_sw; + int vbatt_full_vol_hw; + int term_current; + int tbatt_status, icharging, batt_volt; + + if (!chg->check_batt_full_by_sw) + return false; + if (chg->ffc_status != FFC_DEFAULT) + return false; + if (!chg->vbus_present) { + vbat_counts_sw = 0; + vbat_counts_hw = 0; + ret_sw = false; + ret_hw = false; + return false; + } + + tbatt_status = op_battery_temp_region_get(chg); + vbatt_full_vol_hw = chg->vbatmax[tbatt_status]; + if (tbatt_status == BATT_TEMP_LITTLE_COLD) + vbatt_full_vol_sw = + chg->vbatmax[tbatt_status] - chg->fv_offset_voltage_mv; + else if (tbatt_status == BATT_TEMP_COOL) + vbatt_full_vol_sw = + chg->vbatmax[tbatt_status] - chg->fv_offset_voltage_mv; + else if (tbatt_status == BATT_TEMP_LITTLE_COOL) + vbatt_full_vol_sw = + chg->vbatmax[tbatt_status] - chg->fv_offset_voltage_mv; + else if (tbatt_status == BATT_TEMP_PRE_NORMAL) + vbatt_full_vol_sw = + chg->vbatmax[tbatt_status] - chg->fv_offset_voltage_mv; + else if (tbatt_status == BATT_TEMP_NORMAL) + vbatt_full_vol_sw = + chg->vbatmax[tbatt_status] - chg->fv_offset_voltage_mv; + else if (tbatt_status == BATT_TEMP_WARM) + vbatt_full_vol_sw = + chg->vbatmax[tbatt_status] - chg->fv_offset_voltage_mv; + else { + vbat_counts_sw = 0; + vbat_counts_hw = 0; + ret_sw = 0; + ret_hw = 0; + return false; + } + if (chg->little_cold_iterm_ma > 0 + && (tbatt_status == BATT_TEMP_LITTLE_COLD)) + term_current = chg->little_cold_iterm_ma; + else + term_current = chg->sw_iterm_ma; + + batt_volt = get_prop_batt_voltage_now(chg) / 1000; + icharging = get_prop_batt_current_now(chg) / 1000; + /* use SW Vfloat to check */ + if (batt_volt > vbatt_full_vol_sw) { + if (icharging < 0 && (icharging * -1) <= term_current) { + vbat_counts_sw++; + if (vbat_counts_sw > FULL_COUNTS_SW * + chg->full_count_sw_num) { + vbat_counts_sw = 0; + ret_sw = true; + } + } else if (icharging >= 0) { + vbat_counts_sw++; + if (vbat_counts_sw > FULL_COUNTS_SW * 2) { + vbat_counts_sw = 0; + ret_sw = true; + pr_info("Batt full by sw when charging>=0\n"); + } + } else { + vbat_counts_sw = 0; + ret_sw = false; + } + } else { + vbat_counts_sw = 0; + ret_sw = false; + } + + /* use HW Vfloat to check */ + if (batt_volt >= vbatt_full_vol_hw + 18) { + vbat_counts_hw++; + if (vbat_counts_hw >= FULL_COUNTS_HW) { + vbat_counts_hw = 0; + ret_hw = true; + } + } else { + vbat_counts_hw = 0; + ret_hw = false; + } + + if (ret_sw == true || ret_hw == true) { + pr_info("[BATTERY] Battery full by sw[%s] !!\n", + (ret_sw == true) ? "S" : "H"); + ret_sw = ret_hw = false; + return true; + } else { + return false; + } +} + +void checkout_term_current(struct smb_charger *chg) +{ + bool chg_full; + + if (chg->chg_done) + return; + chg_full = op_check_vbat_is_full_by_sw(chg); + if (chg_full) { + chg->chg_done = true; + op_charging_en(chg, false); + op_dcdc_vph_track_sel(chg); + pr_info("chg_done:CAP=%d (Q:%d),VBAT=%d (Q:%d),IBAT=%d (Q:%d),BAT_TEMP=%d\n", + get_prop_batt_capacity(chg), + get_prop_fg_capacity(chg), + get_prop_batt_voltage_now(chg) / 1000, + get_prop_fg_voltage_now(chg) / 1000, + get_prop_batt_current_now(chg) / 1000, + get_prop_fg_current_now(chg) / 1000, + get_prop_batt_temp(chg)); + } +} + + +static int usb_enum_check(const char *val, const struct kernel_param *kp) +{ + const struct apsd_result *apsd_result; + struct smb_charger *chg = g_chg; + unsigned long usb_sw_reset = 0; + int ret = 0; + + pr_info("Check usb enum when boot\n"); + if (chg->usb_enum_status) + return 0; + + ret = kstrtoul(val, 10, &usb_sw_reset); + if (ret) + return ret; + + if (!usb_sw_reset || !is_usb_present(chg)) + return 0; + + apsd_result = smblib_get_apsd_result(chg); + if ((apsd_result->bit) != SDP_CHARGER_BIT && + (apsd_result->bit) != CDP_CHARGER_BIT) + return 0; + + pr_info("usb don't enum for longtime in boot\n"); + op_handle_usb_removal(chg); + chg->non_stand_chg_count = 0; + schedule_delayed_work(&chg->re_det_work, + msecs_to_jiffies(TIME_1000MS)); + schedule_delayed_work( + &chg->non_standard_charger_check_work, + msecs_to_jiffies(TIME_1000MS)); + + return 0; +} + +static void check_non_standard_charger_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, non_standard_charger_check_work); + + bool charger_present; + const struct apsd_result *apsd_result; + int aicl_result, rc; + + pr_debug("chg->non_stand_chg_count=%d\n", + chg->non_stand_chg_count); + + charger_present = is_usb_present(chg); + if (!charger_present) { + pr_info("chk_non_std_chger,charger_present\n"); + chg->non_stand_chg_count = 0; + return; + } + if (chg->usb_enum_status) { + pr_info("chk_non_std_chger,usb_enum_status\n"); + chg->non_stand_chg_count = 0; + return; + } + if (!chg->chg_enabled) { + pr_info("chg_enabled is false\n"); + chg->non_stand_chg_count = 0; + return; + } + if (chg->non_stand_chg_count + >= NON_STANDARD_CHARGER_CHECK_S) { + apsd_result = smblib_update_usb_type(chg); + if (apsd_result->bit == DCP_CHARGER_BIT + || apsd_result->bit == OCP_CHARGER_BIT) + return; + if (!chg->chg_enabled) + return; + rc = smblib_run_aicl(chg, RERUN_AICL); + if (rc < 0) + smblib_err(chg, "Couldn't re-run AICL rc=%d\n", rc); + msleep(500); + aicl_result = op_get_aicl_result(chg); + chg->non_stand_chg_current = aicl_result; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP; + if (chg->is_aging_test) + op_usb_icl_set(chg, DEFAULT_AGAING_CHG_MA*1000); + else if (aicl_result >= 700*1000) + op_usb_icl_set(chg, aicl_result - 200*1000); + else + op_usb_icl_set(chg, 1200*1000); + power_supply_changed(chg->batt_psy); + chg->is_power_changed = true; + chg->non_std_chg_present = true; + pr_err("non-standard_charger detected,aicl_result=%d\n", + aicl_result); + } else { + chg->non_stand_chg_count++; + schedule_delayed_work( + &chg->non_standard_charger_check_work, + msecs_to_jiffies(TIME_1000MS)); + } +} + +static void smbchg_re_det_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + re_det_work.work); + + pr_debug("chg->redet_count=%d\n", chg->redet_count); + if (chg->usb_enum_status) { + pr_info("re_det, usb_enum_status\n"); + chg->redet_count = 0; + return; + } + if (!chg->vbus_present) { + pr_info("re_det, vbus_no_present\n"); + chg->redet_count = 0; + return; + } + + if (chg->redet_count >= REDET_COUTNT) { + op_rerun_apsd(chg); + chg->usb_type_redet_done = true; + } else { + chg->redet_count++; + schedule_delayed_work(&chg->re_det_work, + msecs_to_jiffies(TIME_1000MS)); + } +} + +static void op_recovery_set_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + op_re_set_work.work); + int rc = 0; + + pr_debug("chg->reset_count=%d\n", chg->reset_count); + if (!chg->charger_collpse) { + chg->reset_count = 0; + return; + } + if (!chg->vbus_present) { + chg->reset_count = 0; + return; + } + + if (chg->reset_count >= 13) { + + pr_err("op_set_collapse_fet\n"); + rc = smblib_write(chg, USBIN_AICL_OPTIONS_CFG_REG, 0xc7); + if (rc < 0) + smblib_err(chg, + "Couldn't enable OTG regulator rc=%d\n", rc); + chg->charger_collpse = false; + chg->reset_count = 0; + } else { + chg->reset_count++; + schedule_delayed_work(&chg->op_re_set_work, + msecs_to_jiffies(TIME_1000MS)); + } +} + +void aging_test_check_aicl(struct smb_charger *chg) +{ + int aicl_result = 0, vbat = 0; + + if (chg->usb_enum_status) + return; + vbat = get_prop_fg_voltage_now(chg) / 1000; + aicl_result = op_get_aicl_result(chg); + if (aicl_result < 800*1000) { + if (vbat < 4000) { + pr_info("set icl 900mA\n"); + vote(chg->usb_icl_votable, AICL_RERUN_VOTER, + true, 900*1000); + vote(chg->usb_icl_votable, AICL_RERUN_VOTER, false, 0); + } + } +} + +static void handle_dash_skin_therm_temp(struct smb_charger *chg) +{ + // Store the current lcd status to use it for skin thermal handling + // and also use the same status while controlling charge current to + // be in sync + lcd_status = chg->oem_lcd_is_on; + if (!lcd_status) { // LCD Off + // Skin therm high + if (!chg->is_skin_thermal_high) { + if (chg->skin_thermal_temp >= + chg->skin_thermal_high_threshold_disp_off) { // >=42 + chg->is_skin_thermal_high = true; + chg->is_skin_thermal_medium = false; + } + } else { + if (chg->skin_thermal_temp < + chg->skin_thermal_pre_high_threshold_disp_off) { // < 38 + chg->is_skin_thermal_medium = true; + chg->is_skin_thermal_high = false; + } + } + + // Skin thermal medium + if (!chg->is_skin_thermal_medium) { + if (!chg->is_skin_thermal_high && + chg->skin_thermal_temp >= + chg->skin_thermal_medium_threshold_disp_off) { // >=39 + chg->is_skin_thermal_medium = true; + } + } else { + if (chg->skin_thermal_temp < + chg->skin_thermal_normal_threshold_disp_off) { // <37 + chg->is_skin_thermal_medium = false; + } + } + } else { // LCD On + // Skin therm high + if (!chg->is_skin_thermal_high) { + if (chg->skin_thermal_temp >= + chg->skin_thermal_high_threshold_disp_on) { // >=40 + chg->is_skin_thermal_high = true; + chg->is_skin_thermal_little_high = false; + } + } else { + if (chg->skin_thermal_temp < + chg->skin_thermal_pre_high_threshold_disp_on) { // < 39 + chg->is_skin_thermal_little_high = true; + chg->is_skin_thermal_high = false; + } + } + + // Skin therm little high + if (!chg->is_skin_thermal_little_high) { + if (!chg->is_skin_thermal_high && + chg->skin_thermal_temp >= + chg->skin_thermal_little_high_threshold_disp_on) { // >= 38 + chg->is_skin_thermal_little_high = true; + chg->is_skin_thermal_medium = false; + } + } else { + if (chg->skin_thermal_temp < + chg->skin_thermal_pre_little_high_threshold_disp_on) { // 37 + chg->is_skin_thermal_medium = true; + chg->is_skin_thermal_little_high = false; + } + } + + // Skin thermal medium + if (!chg->is_skin_thermal_medium) { + if (!chg->is_skin_thermal_little_high && + !chg->is_skin_thermal_high && + chg->skin_thermal_temp >= + chg->skin_thermal_medium_threshold_disp_on) { // >=36 + chg->is_skin_thermal_medium = true; + } + } else { + if (chg->skin_thermal_temp < + chg->skin_thermal_normal_threshold_disp_on) { // <35 + chg->is_skin_thermal_medium = false; + } + } + } +} + +#define SKIN_THERMAL_DEFAULT_TEMP 25 +static int op_get_skin_thermal_temp(struct smb_charger *chg) +{ + int ret = 0, result = 0, thermal_temp = 0; + int batt_temp = 0; + + if (chg->iio.op_skin_therm_chan) { + ret = iio_read_channel_processed( + chg->iio.op_skin_therm_chan, + &result); + if (ret < 0) { + smblib_err(chg, "Error in reading IIO channel data, rc=%d\n", + ret); + return ret; + } + thermal_temp = result/1000; + if ((thermal_temp >= 0) && + (thermal_temp <= 60)) //filter to valid value + chg->skin_thermal_temp = thermal_temp; + else + chg->skin_thermal_temp = SKIN_THERMAL_DEFAULT_TEMP; + } else { + pr_err("op_skin_therm_chan no found!\n"); + return -ENODATA; + } + + // Battery temperature in deci degrees + batt_temp = get_prop_batt_temp(chg)/10; + if (chg->pd_active) { // PD charging skin therm + if (!chg->is_skin_thermal_high && + (chg->skin_thermal_temp >= + chg->pd_skin_thermal_medium_threshold) && // 39 + batt_temp < 40) { + chg->is_skin_thermal_medium = true; + chg->is_skin_thermal_high = false; + } else if (chg->is_skin_thermal_medium && + (chg->skin_thermal_temp < + chg->pd_skin_thermal_normal_threshold) && // 38 + batt_temp < 40) + chg->is_skin_thermal_medium = false; + + if ((chg->skin_thermal_temp >= + chg->pd_skin_thermal_high_threshold) || //40 + batt_temp >= 40) { + chg->is_skin_thermal_high = true; + chg->is_skin_thermal_medium = false; + } else if (chg->is_skin_thermal_high && + (chg->skin_thermal_temp < + chg->pd_skin_thermal_pre_high_threshold) && // 39 + batt_temp < 40) { + chg->is_skin_thermal_high = false; + chg->is_skin_thermal_medium = true; + } + } else { // Dash charging skin therm + handle_dash_skin_therm_temp(chg); + } + pr_info("skin_thermal_temp=(%d),pd_active(%d)\n", + chg->skin_thermal_temp, + chg->pd_active); + pr_info("SKIN THERM LEVEL: HIGH:%d, LITTLE_HIGH:%d MEDIUM:%d\n", + chg->is_skin_thermal_high, + chg->is_skin_thermal_little_high, + chg->is_skin_thermal_medium); + + return chg->skin_thermal_temp; +} + +bool check_skin_thermal_high(void) +{ + int thermal_temp; + + if (!g_chg->enable_dash_current_adjust) + return false; + + if (g_chg->pd_active && !g_chg->enable_pd_current_adjust) + return false; + + thermal_temp = op_get_skin_thermal_temp(g_chg); + if (thermal_temp >= 0) + return g_chg->is_skin_thermal_high; + else + return false; +} + +bool check_skin_thermal_warm(void) +{ + int thermal_temp; + + if (!g_chg->enable_dash_current_adjust) + return false; + + if (g_chg->pd_active && !g_chg->enable_pd_current_adjust) + return false; + + thermal_temp = op_get_skin_thermal_temp(g_chg); + if (thermal_temp >= 0) + return g_chg->is_skin_thermal_little_high; + else + return false; +} + +bool check_skin_thermal_medium(void) +{ + int thermal_temp; + + if (!g_chg->enable_dash_current_adjust) + return false; + + if (g_chg->pd_active && !g_chg->enable_pd_current_adjust) + return false; + + thermal_temp = op_get_skin_thermal_temp(g_chg); + if (thermal_temp >= 0) + return g_chg->is_skin_thermal_medium; + else + return false; +} + +bool check_call_on_status(void) +{ + bool is_call_on = false; + + if (!g_chg->enable_dash_current_adjust) + return false; + + if (g_chg->pd_active && !g_chg->enable_pd_current_adjust) + return false; + + is_call_on = *g_chg->call_on; + pr_info("is_call_on=(%d)\n", is_call_on); + + return is_call_on; +} + +bool check_video_call_on_status(void) +{ + bool is_video_call_on = false; + + if (!g_chg->enable_dash_current_adjust) + return false; + + if (g_chg->pd_active && !g_chg->enable_pd_current_adjust) + return false; + + is_video_call_on = *g_chg->video_call_on; + pr_info("is_video_call_on=(%d)\n", is_video_call_on); + + return is_video_call_on; +} + +bool check_lcd_on_status(void) +{ + pr_info("LCD status=(%d)\n", lcd_status); + return lcd_status; +} + +/* @bsp 2018/07/30 add usb connector temp detect and wr*/ +#define USB_CONNECTOR_DEFAULT_TEMP 25 +static int get_usb_temp(struct smb_charger *chg) +{ + int ret, i, result, temp = 0, step_value = 0, temp_1 = 0, temp_2 = 0; + + if (chg->iio.op_connector_temp_chan) { + ret = iio_read_channel_processed( + chg->iio.op_connector_temp_chan, + &result); + if (ret < 0) { + smblib_err(chg, "Error in reading IIO channel data, rc=%d\n", + ret); + return USB_CONNECTOR_DEFAULT_TEMP; + } + chg->connecter_voltage = result/1000; + } else { + pr_err("op_connector_temp_chan no found!\n"); + return USB_CONNECTOR_DEFAULT_TEMP; + } + for (i = ARRAY_SIZE(con_volt_30k) - 1; i >= 0; i--) { + if (con_volt_30k[i] >= chg->connecter_voltage) + break; + else if (i == 0) + break; + } + + smblib_dbg(chg, PR_FAST_DEBUG, "connecter(vol:%d,temp:%d),Ibatt:%d,batt_temp:%d\n", + chg->connecter_voltage, con_temp_30k[i], + get_prop_batt_current_now(chg) / 1000, + get_prop_batt_temp(chg) / 10); + + smblib_dbg(chg, PR_FAST_DEBUG, "connector_voltage_01:%04dmv,connector_temp_01:%03d\n", + chg->connecter_voltage, + con_temp_30k[i]); + temp_1 = con_temp_30k[i]; + chg->connecter_temp_1 = temp_1; + + if (chg->iio.op_connector_temp_chan_sec) { + ret = iio_read_channel_processed( + chg->iio.op_connector_temp_chan_sec, + &result); + chg->connecter_voltage = result/1000; + } else { + pr_err("op_connector_temp_chan no found!\n"); + return -ENODATA; + } + for (i = ARRAY_SIZE(con_volt_30k) - 1; i >= 0; i--) { + if (con_volt_30k[i] >= chg->connecter_voltage) + break; + else if (i == 0) + break; + } + + smblib_dbg(chg, PR_FAST_DEBUG, "connector_voltage_02:%04dmv,connector_temp_02:%03d\n", + chg->connecter_voltage, + con_temp_30k[i]); + temp_2 = con_temp_30k[i]; + chg->connecter_temp_2 = temp_2; + + if (temp_1 >= temp_2) + temp = temp_1; + else + temp = temp_2; + + step_value = temp - chg->connecter_temp; + + /*WR for temperature value(70~85) and steep filter, use last value*/ + if (((temp >= 70) && (temp <= 85)) || (step_value >= 10)) { + chg->filter_count++; + if (chg->filter_count <= 3) { + pr_info("con_temp=(%d) pre_temp=(%d) filter_count(%d),filter not report!\n", + temp, + chg->connecter_temp, + chg->filter_count); + return chg->connecter_temp; + } + chg->filter_count = 0; + } else + chg->filter_count = 0; + + return temp; +} + +void op_disconnect_vbus(struct smb_charger *chg, bool enable) +{ + char *recovered[2] = { "USB_CONTAMINANT=RECOVERED", NULL }; + char *detected[2] = { "USB_CONTAMINANT=DETECTED", NULL }; + + if (*chg->disable_connector_protect) { + pr_info("disable usb connector protect, return!\n"); + return; + } +#ifdef CONFIG_OP_DEBUG_CHG +/* *#806# aging test not need Vbus disconnect feature*/ + return; +#else + if (chg->is_aging_test) + return; +#endif + if (!gpio_is_valid(chg->vbus_ctrl)) + return; + if (!enable) { + gpio_set_value(chg->vbus_ctrl, 0); + chg->disconnect_vbus = false; + kobject_uevent_env(&chg->dev->kobj, KOBJ_CHANGE, recovered); + pr_info("usb connecter cool(%d), Vbus connected! Sent uevent %s\n", + chg->connecter_temp, recovered[0]); + return; + } + kobject_uevent_env(&chg->dev->kobj, KOBJ_CHANGE, detected); + pr_info("usb connecter hot(%d),Vbus disconnected! Sent uevent %s\n", + chg->connecter_temp, detected[0]); + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + switch_mode_to_normal(); + op_set_fast_chg_allow(chg, false); + } + smblib_set_usb_suspend(chg, true); + msleep(20); + gpio_set_value(chg->vbus_ctrl, 1); + chg->disconnect_vbus = true; + + /* CC set sink only mode */ + vote(chg->otg_toggle_votable, HOT_PROTECT_VOTER, 0, 0); + + /* Charge recovery monitor */ + schedule_delayed_work(&chg->connecter_recovery_work, + msecs_to_jiffies(1000)); +} + +/*usb connector hw auto detection*/ +static void op_otg_switch(struct work_struct *work) +{ + bool usb_pluged; + static bool pre_usb_pluged; + + if (!g_chg) + return; + usb_pluged = gpio_get_value(g_chg->plug_irq) ? false : true; + if (usb_pluged == pre_usb_pluged) { + pr_info("same status,return;usb_present:%d\n", usb_pluged); + /* @bsp, add to disable CC detection after OTG detached */ + if (usb_pluged) + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); + else + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 0, 0); + return; + } + pr_info("%s,usb_present:%d\n", __func__, usb_pluged); + if (usb_pluged) { + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); + g_chg->hw_detect = 1; + } else { + /* For GCE-2351 issue Debug patch, do not set cc mode to + * sink-only mode when type-c disconnect + */ + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 0, 0); + g_chg->hw_detect = 0; + schedule_delayed_work(&g_chg->unplug_check_work, + msecs_to_jiffies(TIME_200MS)); + } + pr_info("%s:hw_detect=%d\n", __func__, g_chg->hw_detect); + pre_usb_pluged = usb_pluged; +} +static void op_check_charger_wakup_source(struct smb_charger *chg, int vchg_mv) +{ + + struct wakeup_source *ws; + + ws = chg->chg_wake_lock; + if (chg->vbus_present) + return; + if (ws->active && vchg_mv <= 200) { + pr_info("%s release chg_wake_lock\n", __func__); + __pm_relax(chg->chg_wake_lock); + } +} + +static void op_heartbeat_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, heartbeat_work); + enum temp_region_type temp_region; + bool charger_present = 0; + bool fast_charging = 0; + static int vbat_mv; + union power_supply_propval vbus_val = {0, }; + int rc; + +/*yangfb@bsp, 20181023 icl set 1A if battery lower than 15%*/ + op_otg_icl_contrl(chg); +#ifndef CONFIG_OP_DEBUG_CHG + op_check_charge_timeout(chg); +#endif + +#ifdef CONFIG_OP_DEBUG_CHG + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("failed to read usb_voltage rc=%d\n", rc); + vbus_val.intval = CHG_VOLTAGE_NORMAL; + } +#endif + charger_present = is_usb_present(chg); + if (!charger_present) + goto out; + /* charger present */ + power_supply_changed(chg->batt_psy); + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + if (chg->chg_disabled) { + set_usb_switch(chg, false); + goto out; + } + switch_fast_chg(chg); + pr_info("fast chg started, usb_switch=%d\n", + op_is_usb_switch_on(chg)); + /* add for disable normal charge */ + fast_charging = op_get_fastchg_ing(chg); + if (fast_charging) { + if (!chg->disable_normal_chg_for_dash) + op_charging_en(chg, false); + chg->disable_normal_chg_for_dash = true; + chg->fastchg_present_wait_count = 0; + } + goto out; + } else { + if (chg->disable_normal_chg_for_dash) { + chg->fastchg_present_wait_count++; + if (chg->fastchg_present_wait_count >= FULL_DELAY_COUNT) { + chg->disable_normal_chg_for_dash = false; + op_charging_en(chg, true); + chg->fastchg_present_wait_count = 0; + schedule_delayed_work(&chg->op_check_high_vbat_chg_work, + msecs_to_jiffies(TIME_1000MS)); + } + } + schedule_delayed_work(&chg->check_switch_dash_work, + msecs_to_jiffies(100)); + } + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("failed to read usb_voltage rc=%d\n", rc); + vbus_val.intval = CHG_VOLTAGE_NORMAL; + } + op_check_charger_wakup_source(chg, vbus_val.intval); + op_check_charger_uovp(chg, vbus_val.intval); + op_check_battery_uovp(chg); + if (vbus_val.intval > 4500) + op_check_charger_collapse(chg); + + vbat_mv = get_prop_batt_voltage_now(chg) / 1000; + temp_region = op_battery_temp_region_get(chg); + if (temp_region == BATT_TEMP_LITTLE_COOL + || temp_region == BATT_TEMP_COOL) { + if (vbat_mv > chg->temp_littel_cool_voltage + && chg->temp_littel_cool_set_current_0_point_25c) { + chg->is_power_changed = true; + } else if (vbat_mv < chg->temp_littel_cool_voltage - 200 + && !chg->temp_littel_cool_set_current_0_point_25c) { + chg->is_power_changed = true; + } + } + ffc_exit(chg); + + checkout_term_current(chg); + if (!chg->chg_ovp && chg->chg_done + && temp_region > BATT_TEMP_COLD + && temp_region < BATT_TEMP_HOT + && chg->vbatdet[temp_region] >= vbat_mv) { + chg->chg_done = false; + chg->recharge_pending = true; + chg->recharge_status = true; + + op_charging_en(chg, true); + pr_debug("temp_region=%d, recharge_pending\n", temp_region); + } + + if (!chg->chg_ovp && chg->battery_status == BATT_STATUS_GOOD + && !chg->time_out) { + op_check_battery_temp(chg); + } +#ifdef CONFIG_OP_DEBUG_CHG + chg->dump_count++; + if (chg->dump_count == 600) { + chg->dump_count = 0; + if ((get_prop_batt_current_now(chg) / 1000) > 0) { + op_dump_regs(chg); + aging_test_check_aicl(chg); + } + } +#else + if (chg->is_aging_test) { + chg->dump_count++; + if (chg->dump_count == 600) { + chg->dump_count = 0; + if ((get_prop_batt_current_now(chg) / 1000) > 0) { + op_dump_regs(chg); + aging_test_check_aicl(chg); + } + } + } + +#endif +out: + smblib_dbg(chg, PR_OP_DEBUG, "CAP=%d (Q:%d), VBAT=%d (Q:%d), IBAT=%d (Q:%d), BAT_TEMP=%d, CONNECTOR_TEMP=%d, CHG_TYPE=%d, VBUS=%d AICL:%d\n", + get_prop_batt_capacity(chg), + get_prop_fg_capacity(chg), + get_prop_batt_voltage_now(chg) / 1000, + get_prop_fg_voltage_now(chg) / 1000, + get_prop_batt_current_now(chg) / 1000, + get_prop_fg_current_now(chg) / 1000, + get_prop_batt_temp(chg), + chg->connecter_temp, + chg->usb_psy_desc.type, + vbus_val.intval, + op_get_aicl_result(chg)); + /*update time 6s*/ + schedule_delayed_work(&chg->heartbeat_work, + round_jiffies_relative(msecs_to_jiffies + (HEARTBEAT_INTERVAL_MS))); +} + +static int op_read(struct smb_charger *chg, u16 addr, u8 *val) +{ + unsigned int temp = 0; + int rc = 0; + + pr_info("%s enter,temp:0x%x rc:0x%x\n", __func__, temp, rc); + if (pm_regmap) { + rc = regmap_read(pm_regmap, addr, &temp); + if (rc >= 0) + *val = (u8)temp; + } + pr_info("%s end,temp:0x%x,rc:0x%x\n", __func__, temp, rc); + return rc; +} + +static int op_write(struct smb_charger *chg, u16 addr, u8 val) +{ + int rc = 0; + + if (pm_regmap) + rc = regmap_write(pm_regmap, addr, val); + return rc; +} + + +/*Modify for backup soc Begin */ +int op_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val) +{ + int rc = 0; + + if (pm_regmap) + rc = regmap_update_bits(pm_regmap, addr, mask, val); + else + pr_err("pm_pon is NULL\n"); + return rc; +} + +void op_write_backup_flag(struct smb_charger *chg, bool bk_flag) +{ + int rc = 0; + + rc = op_masked_write(chg, SOC_FLAG_REG, + BIT(0), bk_flag ? BIT(0):0); + if (rc) { + pr_err("failed to clean PM addr[0x%x], rc=%d\n", + SOC_FLAG_REG, rc); + } +} + +int op_read_backup_flag(struct smb_charger *chg) +{ + u8 flag = 0; + int rc = 0; + + pr_info("%s enter,flag:0x%x,rc:0x%x\n", __func__, flag, rc); + rc = op_read(chg, SOC_FLAG_REG, &flag); + if (rc) { + pr_err("failed to read PM addr[0x%x], rc=%d\n", + SOC_FLAG_REG, rc); + return 0; + } + pr_info("%s end,flag:0x%x,rc:0x%x\n", __func__, flag, rc); + flag = flag & BIT(0); + return flag; +} + +static int load_data(struct smb_charger *chip) +{ + u8 stored_soc = 0; + int rc = 0, shutdown_soc = 0; + + if (!chip) { + pr_err("chip is NULL !\n"); + return SOC_INVALID; + } + if (!op_read_backup_flag(chip)) + return SOC_INVALID; + rc = op_read(chip, SOC_DATA_REG_0, &stored_soc); + if (rc) { + pr_err("failed to read addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + return SOC_INVALID; + } + + shutdown_soc = (stored_soc >> 1); /* get data from bit1~bit7 */ + pr_info("stored_soc[0x%x], shutdown_soc[%d]\n", + stored_soc, shutdown_soc); + return shutdown_soc; +} + +int load_soc(void) +{ + int soc = 0; + + soc = load_data(g_chg); + if (soc == SOC_INVALID || soc < 0 || soc > 100) + return -EINVAL; + return soc; +} + +static void clear_backup_soc(struct smb_charger *chip) +{ + int rc = 0; + u8 soc_temp = 0; + + rc = op_write(chip, SOC_DATA_REG_0, soc_temp); + if (rc) + pr_err("failed to clean addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + op_write_backup_flag(chip, false); +} + +void clean_backup_soc_ex(void) +{ + if (g_chg) + clear_backup_soc(g_chg); +} + +static void backup_soc(struct smb_charger *chip, int soc) +{ + int rc = 0; + u8 invalid_soc = SOC_INVALID; + u8 soc_temp = (soc << 1); /* store data in bit1~bit7 */ + + if (!chip || soc < 0 || soc > 100) { + pr_err("chip or soc invalid, store an invalid soc\n"); + if (chip) { + rc = op_write(chip, SOC_DATA_REG_0, invalid_soc); + if (rc) + pr_err("failed to write addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + } + return; + } + + pr_err("backup soc[%d]\n", soc); + rc = op_write(chip, SOC_DATA_REG_0, soc_temp); + if (rc) + pr_err("failed to write addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + op_write_backup_flag(chip, true); +} + +bool get_prop_fastchg_is_ok(struct smb_charger *chg) +{ + if (chg) + return op_get_fast_chg_status_is_ok(chg); + return true; +} + +void backup_soc_ex(int soc) +{ + if (g_chg) + backup_soc(g_chg, soc); +} +/* Modify for backup soc End*/ + +enum chg_protect_status_type { + PROTECT_CHG_OVP = 1, /* 1: VCHG > 5.8V */ + PROTECT_BATT_MISSING, /* 2: battery missing */ + PROTECT_CHG_OVERTIME, /* 3: charge overtime */ + PROTECT_BATT_OVP, /* 4: vbat >= 4.5 */ + PROTECT_BATT_TEMP_REGION__HOT,/* 5: 55 < t */ + PROTECT_BATT_TEMP_REGION_COLD,/* 6: t <= -3 */ + PROTECT_BATT_TEMP_REGION_LITTLE_COLD, /* 7: -3 < t <= 0 */ + PROTECT_BATT_TEMP_REGION_COOL,/* 8: 0 < t <= 5 */ + PROTECT_BATT_TEMP_REGION_WARM,/* 9: 45 < t <= 55 */ + PROTECT_INVALID_CHARGER/*10:invalid charger or slow charger*/ +}; + +int get_prop_chg_protect_status(struct smb_charger *chg) +{ + int temp = 0, rc = 0; + bool batt_present = 0; + enum temp_region_type temp_region; + union power_supply_propval vbus_val; + + if (chg->use_fake_protect_sts) + return chg->fake_protect_sts; + + if (!is_usb_present(chg)) + return 0; + + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("failed to read usb_voltage rc=%d\n", rc); + vbus_val.intval = CHG_VOLTAGE_NORMAL; + } + + temp = get_prop_batt_temp(chg); + batt_present = get_prop_batt_present(chg); + temp_region = op_battery_temp_region_get(chg); + if (chg->chg_ovp && vbus_val.intval >= CHG_SOFT_OVP_MV - 100) + return PROTECT_CHG_OVP; + else if (!batt_present || BATT_REMOVE_TEMP > temp) + return PROTECT_BATT_MISSING; + else if (chg->battery_status == BATT_STATUS_BAD) + return PROTECT_BATT_OVP; + else if (true == chg->time_out) + return PROTECT_CHG_OVERTIME; + else if (temp_region == BATT_TEMP_HOT) + return PROTECT_BATT_TEMP_REGION__HOT; + else if (temp_region == BATT_TEMP_COLD) + return PROTECT_BATT_TEMP_REGION_COLD; + else if (temp_region == BATT_TEMP_LITTLE_COLD + && (chg->chg_done || chg->recharge_status)) + return PROTECT_BATT_TEMP_REGION_LITTLE_COLD; + else if (temp_region == BATT_TEMP_WARM + && (chg->chg_done || chg->recharge_status)) + return PROTECT_BATT_TEMP_REGION_WARM; + else + return 0; +} + +bool get_prop_fastchg_status(struct smb_charger *chg) +{ + int capacity = 0; + + if (chg->dash_present) + return true; + + if (chg->hvdcp_present) { + capacity = get_prop_batt_capacity(chg); + if (capacity >= 1 && capacity <= 85) + return true; + } + + return false; +} + +static struct notify_dash_event notify_unplug_event = { + .notify_event = update_dash_unplug_status, + .op_contrl = op_contrl, + .notify_dash_charger_present + = set_dash_charger_present, +}; + +void op_pm8998_regmap_register(struct regmap *regmap) +{ + if (pm_regmap) { + pm_regmap = regmap; + pr_err("multiple battery gauge called\n"); + } else { + pm_regmap = regmap; + } +} + +void fastcharge_information_register(struct external_battery_gauge *fast_chg) +{ + if (fast_charger) { + fast_charger = fast_chg; + pr_err("multiple battery gauge called\n"); + } else { + fast_charger = fast_chg; + } +} +EXPORT_SYMBOL(fastcharge_information_register); + +void fastcharge_information_unregister(struct external_battery_gauge *fast_chg) +{ + fast_charger = NULL; +} +EXPORT_SYMBOL(fastcharge_information_unregister); + +static int notify_usb_enumeration_function(int status) +{ + pr_info("status=%d\n", status); + g_chg->usb_enum_status = status; + + return g_chg->usb_enum_status; +} + +static struct notify_usb_enumeration_status usb_enumeration = { + .notify_usb_enumeration = notify_usb_enumeration_function, +}; +/* @bsp, 2018/07/13 Battery & Charging porting ENDIF*/ + +static void smblib_usbov_dbc_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + usbov_dbc_work.work); + + smblib_dbg(chg, PR_MISC, "Resetting USBOV debounce\n"); + chg->dbc_usbov = false; + vote(chg->awake_votable, USBOV_DBC_VOTER, false, 0); +} + +#define USB_OV_DBC_PERIOD_MS 1000 +irqreturn_t usbin_ov_irq_handler(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + u8 stat; + int rc; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + if (!(chg->wa_flags & USBIN_OV_WA)) + return IRQ_HANDLED; + + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); + return IRQ_HANDLED; + } + + /* + * On specific PMICs, OV IRQ triggers for very small duration in + * interim periods affecting charging status reflection. In order to + * differentiate between OV IRQ glitch and real OV_IRQ, add a debounce + * period for evaluation. + */ + if (stat & USBIN_OV_RT_STS_BIT) { + chg->dbc_usbov = true; + vote(chg->awake_votable, USBOV_DBC_VOTER, true, 0); + schedule_delayed_work(&chg->usbov_dbc_work, + msecs_to_jiffies(USB_OV_DBC_PERIOD_MS)); + } else { + cancel_delayed_work_sync(&chg->usbov_dbc_work); + chg->dbc_usbov = false; + vote(chg->awake_votable, USBOV_DBC_VOTER, false, 0); + } + + smblib_dbg(chg, PR_MISC, "USBOV debounce status %d\n", + chg->dbc_usbov); + return IRQ_HANDLED; +} + +/************** + * Additional USB PSY getters/setters + * that call interrupt functions + ***************/ + +int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = chg->pr_swap_in_progress; + return 0; +} + +#define DETACH_DETECT_DELAY_MS 20 +int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc; + u8 stat = 0, orientation; + + smblib_dbg(chg, PR_MISC, "Requested PR_SWAP %d\n", val->intval); + chg->pr_swap_in_progress = val->intval; + + /* check for cable removal during pr_swap */ + if (!chg->pr_swap_in_progress) { + cancel_delayed_work_sync(&chg->pr_swap_detach_work); + vote(chg->awake_votable, DETACH_DETECT_VOTER, true, 0); + schedule_delayed_work(&chg->pr_swap_detach_work, + msecs_to_jiffies(DETACH_DETECT_DELAY_MS)); + } + + rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, + REDUCE_TCCDEBOUNCE_TO_2MS_BIT, + val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0); + if (rc < 0) + smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc); + + rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, + BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT, + val->intval ? BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT : 0); + if (rc < 0) + smblib_err(chg, "Couldn't set exit state cfg rc=%d\n", rc); + + if (chg->pr_swap_in_progress) { + rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", + rc); + } + + orientation = + stat & CC_ORIENTATION_BIT ? TYPEC_CCOUT_VALUE_BIT : 0; + rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, + TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT + | TYPEC_CCOUT_VALUE_BIT, + TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT + | orientation); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", + rc); + } + } else { + rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, + TYPEC_CCOUT_SRC_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", + rc); + return rc; + } + + /* not to enable DRP after OTG detached */ + if (!chg->hw_detect) + return 0; + + /* enable DRP */ + rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, + TYPEC_POWER_ROLE_CMD_MASK, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); + return rc; + } + chg->power_role = POWER_SUPPLY_TYPEC_PR_DUAL; + smblib_dbg(chg, PR_MISC, "restore power role: %d\n", + chg->power_role); + } + + return 0; +} + +/*************** + * Work Queues * + ***************/ +static void smblib_pr_lock_clear_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + pr_lock_clear_work.work); + + spin_lock(&chg->typec_pr_lock); + if (chg->pr_lock_in_progress) { + smblib_dbg(chg, PR_MISC, "restore type-c interrupts\n"); + smblib_typec_irq_config(chg, true); + chg->pr_lock_in_progress = false; + } + spin_unlock(&chg->typec_pr_lock); +} + +static void smblib_pr_swap_detach_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + pr_swap_detach_work.work); + int rc; + u8 stat; + + rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read STATE_MACHINE_STS rc=%d\n", rc); + goto out; + } + smblib_dbg(chg, PR_REGISTER, "STATE_MACHINE_STS %x\n", stat); + if (!(stat & TYPEC_ATTACH_DETACH_STATE_BIT)) { + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + + if (chg->typec_port) + typec_partner_unregister(chg); + } +out: + vote(chg->awake_votable, DETACH_DETECT_VOTER, false, 0); +} + +static void smblib_uusb_otg_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + uusb_otg_work.work); + int rc; + u8 stat; + bool otg; + + rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_3 rc=%d\n", rc); goto out; @@ -7294,6 +11637,36 @@ static void pl_update_work(struct work_struct *work) POWER_SUPPLY_CP_NONE, false); } +/* @bsp, 2019/10/22 add for PD charging */ +static void smblib_panel_register_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + panel_register_work.work); + int rc; + + pr_err("Register panel notifer for PD charging.\n"); +#if defined(CONFIG_FB) + chg->fb_notif.notifier_call = fb_notifier_callback; + + rc = fb_register_client(&chg->fb_notif); + if (rc) + pr_err("Unable to register fb_notifier: %d\n", rc); +#elif defined(CONFIG_MSM_RDM_NOTIFY) + chg->msm_drm_notifier.notifier_call = msm_drm_notifier_callback; + if (lcd_active_panel) { + rc = drm_panel_notifier_register(lcd_active_panel, + &chg->msm_drm_notifier); + if (rc) { + pr_err("Smb unable to register notifier: %d\n", rc); + } else { + pr_err("register notifier drm panel success!"); + } + } else { + schedule_delayed_work(&chg->panel_register_work, msecs_to_jiffies(2000)); + } +#endif /*CONFIG_FB*/ +} + static void clear_hdc_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, @@ -7953,6 +12326,15 @@ static int smblib_create_votables(struct smb_charger *chg) chg->dc_suspend_votable = NULL; return rc; } +/* @bsp, 2019/07/05 Battery & Charging porting */ +/*usb connector hw auto detection*/ + chg->otg_toggle_votable = create_votable("OTG_TOGGLE", VOTE_SET_ANY, + smblib_otg_toggle_vote_callback, + chg); + if (IS_ERR(chg->otg_toggle_votable)) { + rc = PTR_ERR(chg->otg_toggle_votable); + return rc; + } chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY, smblib_awake_vote_callback, @@ -8019,6 +12401,10 @@ static void smblib_destroy_votables(struct smb_charger *chg) { if (chg->dc_suspend_votable) destroy_votable(chg->dc_suspend_votable); +/* @bsp, 2019/07/05 Battery & Charging porting */ +/*usb connector hw auto detection*/ + if (chg->otg_toggle_votable) + destroy_votable(chg->otg_toggle_votable); if (chg->usb_icl_votable) destroy_votable(chg->usb_icl_votable); if (chg->awake_votable) @@ -8035,6 +12421,10 @@ static void smblib_iio_deinit(struct smb_charger *chg) iio_channel_release(chg->iio.usbin_i_chan); if (!IS_ERR_OR_NULL(chg->iio.temp_chan)) iio_channel_release(chg->iio.temp_chan); +/* @bsp, 2019/07/05 Battery & Charging porting */ +/* @bsp add usb connector temp detect and wr*/ + if (!IS_ERR_OR_NULL(chg->iio.op_connector_temp_chan)) + iio_channel_release(chg->iio.op_connector_temp_chan); if (!IS_ERR_OR_NULL(chg->iio.sbux_chan)) iio_channel_release(chg->iio.sbux_chan); if (!IS_ERR_OR_NULL(chg->iio.vph_v_chan)) @@ -8057,16 +12447,69 @@ int smblib_init(struct smb_charger *chg) mutex_init(&chg->smb_lock); mutex_init(&chg->irq_status_lock); mutex_init(&chg->dcin_aicl_lock); + +/* @bsp, 2019/07/05 Battery & Charging porting */ + mutex_init(&chg->write_lock); + mutex_init(&chg->sw_dash_lock); mutex_init(&chg->dpdm_lock); + spin_lock_init(&chg->typec_pr_lock); + INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_update_work, pl_update_work); INIT_WORK(&chg->jeita_update_work, jeita_update_work); INIT_WORK(&chg->dcin_aicl_work, dcin_aicl_work); + +/* @bsp, 2019/07/05 Battery & Charging porting */ + /* @bsp, 2019/10/22 Add for PD charging */ + INIT_DELAYED_WORK(&chg->panel_register_work, + smblib_panel_register_work); + INIT_DELAYED_WORK(&chg->rechk_sw_dsh_work, retrigger_dash_work); + INIT_DELAYED_WORK(&chg->re_kick_work, op_re_kick_work); + INIT_DELAYED_WORK(&chg->unplug_check_work, op_usb_remove_check_work); + INIT_DELAYED_WORK(&chg->op_check_apsd_work, op_chek_apsd_done_work); + INIT_DELAYED_WORK(&chg->recovery_suspend_work, + op_recovery_usb_suspend_work); + INIT_DELAYED_WORK(&chg->op_check_high_vbat_chg_work, + op_check_high_vbat_chg_work); + INIT_DELAYED_WORK(&chg->check_switch_dash_work, + op_check_allow_switch_dash_work); + INIT_DELAYED_WORK(&chg->heartbeat_work, + op_heartbeat_work); + INIT_DELAYED_WORK(&chg->non_standard_charger_check_work, + check_non_standard_charger_work); + INIT_DELAYED_WORK(&chg->re_det_work, smbchg_re_det_work); + INIT_DELAYED_WORK(&chg->op_re_set_work, op_recovery_set_work); + INIT_WORK(&chg->get_aicl_work, op_get_aicl_work); + /*usb connector hw auto detection*/ + INIT_WORK(&chg->otg_switch_work, op_otg_switch); + INIT_DELAYED_WORK(&chg->connecter_check_work, + op_connecter_temp_check_work); + INIT_DELAYED_WORK(&chg->connecter_recovery_work, + op_connecter_recovery_charge_work); + INIT_DELAYED_WORK(&chg->pd_current_check_work, + pd_skin_thermal_check_work); + INIT_DELAYED_WORK(&chg->pdo_select_check_work, + pdo_selection_check_work); + schedule_delayed_work(&chg->heartbeat_work, + msecs_to_jiffies(HEARTBEAT_INTERVAL_MS)); + schedule_delayed_work(&chg->panel_register_work, + msecs_to_jiffies(2000)); + if (gpio_is_valid(chg->vbus_ctrl)) + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(200)); + notify_dash_unplug_register(¬ify_unplug_event); + chg->chg_wake_lock = wakeup_source_register(chg->dev, "chg_wake_lock"); + g_chg = chg; + regsister_notify_usb_enumeration_status(&usb_enumeration); + INIT_WORK(&chg->cp_status_change_work, smblib_cp_status_change_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); +/* @bsp, 2019/07/05 Battery & Charging porting */ + op_set_collapse_fet(chg, false); + INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); INIT_DELAYED_WORK(&chg->lpd_ra_open_work, smblib_lpd_ra_open_work); @@ -8083,11 +12526,16 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->role_reversal_check, smblib_typec_role_check_work); + /* @bsp, 2020/08/04, add to detect SVID */ + INIT_DELAYED_WORK(&chg->register_pps_work, op_register_pps_work); + schedule_delayed_work(&chg->register_pps_work, msecs_to_jiffies(2000)); + if (chg->wa_flags & CHG_TERMINATION_WA) { INIT_WORK(&chg->chg_termination_work, smblib_chg_termination_work); if (alarmtimer_get_rtcdev()) { + pr_info("chg_termination_alarm\n"); alarm_init(&chg->chg_termination_alarm, ALARM_BOOTTIME, chg_termination_alarm_cb); } else { @@ -8101,6 +12549,7 @@ int smblib_init(struct smb_charger *chg) smblib_moisture_protection_work); if (alarmtimer_get_rtcdev()) { + pr_info("moisture_protection_alarm\n"); alarm_init(&chg->moisture_protection_alarm, ALARM_BOOTTIME, moisture_protection_alarm_cb); } else { @@ -8128,6 +12577,7 @@ int smblib_init(struct smb_charger *chg) chg->typec_irq_en = true; chg->cp_topo = -EINVAL; chg->dr_mode = TYPEC_PORT_DRP; + chg->chg_wake_lock_on = false; switch (chg->mode) { case PARALLEL_MASTER: @@ -8233,6 +12683,10 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->bb_removal_work); cancel_delayed_work_sync(&chg->lpd_ra_open_work); cancel_delayed_work_sync(&chg->lpd_detach_work); +/* @bsp, 2019/07/05 Battery & Charging porting */ +/* @bsp, 20170330 Fix system crash */ + if (chg->nb.notifier_call) + power_supply_unreg_notifier(&chg->nb); cancel_delayed_work_sync(&chg->thermal_regulation_work); cancel_delayed_work_sync(&chg->usbov_dbc_work); cancel_delayed_work_sync(&chg->role_reversal_check); @@ -8248,8 +12702,28 @@ int smblib_deinit(struct smb_charger *chg) smblib_err(chg, "Unsupported mode %d\n", chg->mode); return -EINVAL; } - +/* @bsp, 2019/07/05 Battery & Charging porting */ + notify_dash_unplug_unregister(¬ify_unplug_event); smblib_iio_deinit(chg); return 0; } + +// Temperature control center is not supported in 7250, +// Adding stub function to just return invalid value to align with fastcharge driver +int __attribute__((weak)) +op_get_cool_down_value(void) +{ + return -EINVAL; +} + +void __attribute__((weak)) op_pd_config_switch_normal(void) +{ +} + +#ifdef OP_SWARP_SUPPORTED +void __attribute__((weak)) op_warp_config_for_swarp(void) +{ + // Stub functions to be compatible with common code +} +#endif diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 8ee11fb3a3b28ae56d5976d2d76e28f15c45d4d8..5eadb38ba9ba4381e8f432d5334cebb23c788ee2 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -17,6 +17,9 @@ #include #include "storm-watch.h" #include "battery.h" +/* @bsp, 2019/07/05 Battery & Charging porting */ +#include +#include enum print_reason { PR_INTERRUPT = BIT(0), @@ -25,8 +28,51 @@ enum print_reason { PR_PARALLEL = BIT(3), PR_OTG = BIT(4), PR_WLS = BIT(5), +/* @bsp, 2019/07/05 Battery & Charging porting */ + PR_OP_DEBUG = BIT(6), + PR_FAST_DEBUG = BIT(7), }; +/* @bsp, 2019/07/05 Battery & Charging porting */ +#define BATT_TYPE_FCC_VOTER "BATT_TYPE_FCC_VOTER" +#define PSY_ICL_VOTER "PSY_ICL_VOTER" +#define TEMP_REGION_MAX 9 +#define NON_STANDARD_CHARGER_CHECK_S 100 +#define TIME_1000MS 1000 +#define REDET_COUTNT 5 +#define APSD_CHECK_COUTNT 15 +#define DASH_CHECK_COUNT 40 +#define BOOST_BACK_COUNT 2 +#define TIME_200MS 200 +#define TIME_100MS 100 +#define TIME_3S 3000 +#define NORMAL_CHECK_INTERVAL_PERIOD 300 /*ms*/ +#define FAST_CHECK_INTERVAL_PERIOD 100 /*ms*/ +#define FAST_CHECK_THRESHOLD_TEMP 45 +#define HIGH_TEMP_SHORT_CHECK_TIMEOUT 1500 /*ms*/ +#define FIRST_PROTECT_CONNECTER_TEMP 60 +#define SECOND_PROTECT_CONNECTER_TEMP 45 +#define SECOND_PROTECT_INTERVAL_TEMP 15 +#define THIRD_PROTECT_RISE_RATE 3 +#define THIRD_PROTECT_LOOP_TEMP 40 +#define THIRD_PROTECT_INTERVAL_TEMP 15 +#define THIRD_PROTECT_BASE_TEMP 20 +#define FV_OFFSET_VOLTAGE 70 + +#define SKIN_THERMAL_HIGH 41 +#define SKIN_THERMAL_PRE_HIGH 39 +#define SKIN_THERMAL_LITTLE_HIGH 40 +#define SKIN_THERMAL_PRE_LITTLE_HIGH 39 +#define SKIN_THERMAL_MEDIUM 38 +#define SKIN_THERMAL_NORMAL 36 +#define FULL_COUNT_SW_NUM 1 + +#define HW_DETECT_VOTER "HW_DETECT_VOTER" +#define OTG_VOTER "OTG_VOTER" + +#define HW_DETECT_VOTER "HW_DETECT_VOTER" +#define HOT_PROTECT_VOTER "HOT_PROTECT_VOTER" +#define OTG_VOTER "OTG_VOTER" #define DEFAULT_VOTER "DEFAULT_VOTER" #define USER_VOTER "USER_VOTER" #define PD_VOTER "PD_VOTER" @@ -81,10 +127,14 @@ enum print_reason { #define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" #define OVERHEAT_LIMIT_VOTER "OVERHEAT_LIMIT_VOTER" #define TYPEC_SWAP_VOTER "TYPEC_SWAP_VOTER" +#define CHG_RECOVERY_VOTER "CHG_RECOVERY_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 +#define FULL_DELAY_COUNT 10 + + #define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL) #define ITERM_LIMITS_PMI632_MA 5000 @@ -365,6 +415,10 @@ struct smb_iio { struct iio_channel *mid_chan; struct iio_channel *batt_i_chan; struct iio_channel *connector_temp_chan; +/* @bsp 2018/07/30 add usb connector temp detect and wr */ + struct iio_channel *op_connector_temp_chan; + struct iio_channel *op_connector_temp_chan_sec; + struct iio_channel *op_skin_therm_chan; struct iio_channel *sbux_chan; struct iio_channel *vph_v_chan; struct iio_channel *die_temp_chan; @@ -381,13 +435,18 @@ struct smb_charger { struct smb_iio iio; int *debug_mask; int pd_disabled; + int *usb_connector_temp; + int *usb_interval_temp; + int *disable_connector_protect; + int *call_on; + int *video_call_on; enum smb_mode mode; struct smb_chg_freq chg_freq; int otg_delay_ms; int weak_chg_icl_ua; u32 sdam_base; bool pd_not_supported; - + int swarp_online; /* locks */ struct mutex smb_lock; struct mutex ps_change_lock; @@ -397,12 +456,22 @@ struct smb_charger { struct mutex adc_lock; struct mutex dpdm_lock; struct mutex typec_lock; +/* @bsp, 2019/07/05 Battery & Charging porting */ + struct mutex write_lock; + struct mutex sw_dash_lock; +/* @bsp, Enable external stm6620 ship mode */ + struct pinctrl_state *ship_mode_default; + struct pinctrl_state *usb_temperature_default; + struct pinctrl_state *usb_temperature_sec; + struct pinctrl *pinctrl; /* power supplies */ struct power_supply *batt_psy; struct power_supply *usb_psy; struct power_supply *dc_psy; struct power_supply *bms_psy; +/* @bsp, 2019/07/05 Battery & Charging porting */ + struct power_supply_desc usb_psy_desc; struct power_supply *usb_main_psy; struct power_supply *usb_port_psy; struct power_supply *wls_psy; @@ -411,6 +480,12 @@ struct smb_charger { /* notifiers */ struct notifier_block nb; +/* @bsp, 2019/07/06 Battery & Charging porting */ +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_MSM_RDM_NOTIFY) + struct notifier_block msm_drm_notifier; +#endif /* parallel charging */ struct parallel_params pl; @@ -432,6 +507,8 @@ struct smb_charger { /* votables */ struct votable *dc_suspend_votable; +/* @bsp, usb connector hw auto detection */ + struct votable *otg_toggle_votable; struct votable *fcc_votable; struct votable *fcc_main_votable; struct votable *fv_votable; @@ -458,6 +535,30 @@ struct smb_charger { struct work_struct dcin_aicl_work; struct work_struct cp_status_change_work; struct delayed_work ps_change_timeout_work; +/* @bsp, 2019/07/05 Battery & Charging porting */ + /* @bsp, 2019/10/22 Add for PD charging */ + struct delayed_work panel_register_work; + struct delayed_work rechk_sw_dsh_work; + struct delayed_work op_check_high_vbat_chg_work; + struct delayed_work re_kick_work; + struct delayed_work unplug_check_work; + struct delayed_work recovery_suspend_work; + struct delayed_work check_switch_dash_work; + struct delayed_work non_standard_charger_check_work; + struct delayed_work heartbeat_work; + struct delayed_work re_det_work; + struct delayed_work op_re_set_work; + struct delayed_work op_check_apsd_work; + struct work_struct get_aicl_work; + struct delayed_work connecter_check_work; + struct delayed_work connecter_recovery_work; + struct delayed_work pd_current_check_work; + struct delayed_work pdo_select_check_work; + /* @bsp, 2020/08/04, add to detect SVID */ + struct delayed_work register_pps_work; + struct work_struct otg_switch_work; + struct wakeup_source *chg_wake_lock; + struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; struct delayed_work pl_enable_work; @@ -500,6 +601,125 @@ struct smb_charger { bool typec_role_swap_failed; /* cached status */ +/* @bsp, 2019/07/05 Battery & Charging porting */ + int BATT_TEMP_T0; + int BATT_TEMP_T1; + int BATT_TEMP_T2; + int BATT_TEMP_T3; + int BATT_TEMP_T4; + int BATT_TEMP_T5; + int BATT_TEMP_T6; + int batt_health; + int ibatmax[TEMP_REGION_MAX]; + int vbatmax[TEMP_REGION_MAX]; + int vbatdet[TEMP_REGION_MAX]; + int temp_littel_cool_voltage; + int temp_littel_cool_current; + int temp_cool_voltage; + int temp_cool_current; + int fake_chgvol; + int fake_temp; + int fake_protect_sts; + int non_stand_chg_current; + int non_stand_chg_count; + int redet_count; + int reset_count; + int dump_count; + int fastchg_present_wait_count; + int ck_apsd_count; + int ck_dash_count; + int ck_unplug_count; + int check_high_vbat_chg_count; + int recovery_boost_count; + int op_icl_val; + int plug_irq; + int hw_detect; + bool otg_switch; + bool use_fake_chgvol; + bool use_fake_temp; + bool use_fake_protect_sts; + bool vbus_present; + bool hvdcp_present; + bool dash_present; + bool charger_collpse; + bool usb_enum_status; + bool non_std_chg_present; + bool usb_type_redet_done; + bool time_out; + bool disable_normal_chg_for_dash; + bool ship_mode; + bool dash_on; + bool fastchg_switch_disable; + bool chg_disabled; + bool chg_ovp; + bool is_power_changed; + bool recharge_pending; + bool recharge_status; + bool temp_littel_cool_set_current_0_point_25c; + bool oem_lcd_is_on; + bool chg_enabled; + bool op_apsd_done; + bool re_trigr_dash_done; + bool boot_usb_present; + bool init_irq_done; + bool is_aging_test; + bool revert_boost_trigger; + bool switch_on_fastchg; + bool probe_done; + bool disconnect_pd; + int ffc_count; + int FFC_TEMP_T1; + int FFC_TEMP_T2; + int FFC_TEMP_T3; + int FFC_NOR_FCC; + int FFC_WARM_FCC; + int FFC_NORMAL_CUTOFF; + int FFC_WARM_CUTOFF; + int FFC_VBAT_FULL; + enum ffc_step ffc_status; + enum temp_region_type mBattTempRegion; + enum batt_status_type battery_status; + short mBattTempBoundT0; + short mBattTempBoundT1; + short mBattTempBoundT2; + short mBattTempBoundT3; + short mBattTempBoundT4; + short mBattTempBoundT5; + short mBattTempBoundT6; + uint32_t bus_client; + bool is_audio_adapter; + int fv_offset_voltage_mv; + int normal_check_interval_period; + int fast_check_interval_period; + int fast_check_threshold_temp; + int high_temp_short_check_timeout; + int first_protect_connecter_temp; + int second_protect_connecter_temp; + int second_protect_interval_temp; + int third_protect_rise_rate; + int third_protect_loop_temp; + int third_protect_interval_temp; + int third_protect_base_temp; + // Skin therm thresholds when display is OFF + int skin_thermal_high_threshold_disp_off; + int skin_thermal_pre_high_threshold_disp_off; + int skin_thermal_medium_threshold_disp_off; + int skin_thermal_normal_threshold_disp_off; + // Skin therm thresholds when display is ON + int skin_thermal_high_threshold_disp_on; + int skin_thermal_pre_high_threshold_disp_on; + int skin_thermal_little_high_threshold_disp_on; + int skin_thermal_pre_little_high_threshold_disp_on; + int skin_thermal_medium_threshold_disp_on; + int skin_thermal_normal_threshold_disp_on; + bool enable_dash_current_adjust; + int pd_skin_thermal_high_threshold; + int pd_skin_thermal_pre_high_threshold; + int pd_skin_thermal_medium_threshold; + int pd_skin_thermal_normal_threshold; + bool enable_pd_current_adjust; + int full_count_sw_num; + bool system_suspend_supported; int boost_threshold_ua; int system_temp_level; @@ -519,6 +739,39 @@ struct smb_charger { bool fake_chg_status_on_debug_batt; int default_icl_ua; int otg_cl_ua; + +/* @bsp, 2019/07/05 Battery & Charging porting */ + int sw_iterm_ma; + int little_cold_iterm_ma; + bool check_batt_full_by_sw; +/*@bsp, icl set 1A if battery lower than 15%*/ + bool OTG_ICL_CTRL; + int OTG_LOW_BAT; + int OTG_LOW_BAT_ICL; + int OTG_NORMAL_BAT_ICL; +/* @bsp, add the external ship-mode and connecter temp detect start*/ + int shipmode_en; + int connecter_temp; + int connecter_temp_1; + int connecter_temp_2; + int count_total; + int count_run; + int filter_count; + int pre_temp; + int current_temp; + bool connector_short; + int connecter_voltage; + int skin_thermal_temp; + bool is_skin_thermal_high; + bool is_skin_thermal_little_high; + bool is_skin_thermal_medium; + int disconnect_vbus; + int vbus_ctrl; + bool low_voltage_charger; +/* @bsp, add the external ship-mode and connecter temp detect end*/ + bool vph_sel_disable; + bool vph_set_flag; + bool uusb_apsd_rerun_done; bool typec_present; int fake_input_current_limited; @@ -615,8 +868,61 @@ struct smb_charger { int dcin_uv_count; ktime_t dcin_uv_last_time; int last_wls_vout; + bool chg_wake_lock_on; }; +/* @bsp, 2020/08/04, add to detect SVID */ +struct op_pps { + struct usbpd *pd; + struct usbpd_svid_handler svid_handler; +}; + +/* @bsp, 2019/07/05 Battery & Charging porting */ +int smblib_set_prop_charge_parameter_set(struct smb_charger *chg); +extern void set_mcu_en_gpio_value(int value); +extern void set_mcu_active(int value); +extern void usb_sw_gpio_set(int value); +extern bool op_set_fast_chg_allow(struct smb_charger *chg, bool enable); +extern bool get_prop_fast_chg_started(struct smb_charger *chg); +extern void mcu_en_gpio_set(int value); +extern void switch_mode_to_normal(void); +extern struct smb_charger *g_chg; +/* @bsp, 2019/10/21 add new panel node for PD charging */ +extern struct drm_panel *lcd_active_panel; + +/* @bsp, 2020/04/26 add to support pd pdo selection */ +extern int op_pdo_select(int vbus_mv, int ibus_ma); +/* @bsp, 2020/08/04, add to detect SVID */ +extern int op_usbpd_send_svdm(u16 svid, u8 cmd, + enum usbpd_svdm_cmd_type cmd_type, int obj_pos, + const u32 *vdos, int num_vdos); +/* @bsp, 2019/07/05 Battery & Charging porting */ +void op_bus_vote(int disable); +int get_prop_fast_adapter_update(struct smb_charger *chg); +void op_handle_usb_plugin(struct smb_charger *chg); +int op_rerun_apsd(struct smb_charger *chg); +irqreturn_t smblib_handle_aicl_done(int irq, void *data); +void op_charge_info_init(struct smb_charger *chg); +int update_dash_unplug_status(void); +int get_prop_batt_status(struct smb_charger *chg); +int get_prop_chg_protect_status(struct smb_charger *chg); +int op_set_prop_otg_switch(struct smb_charger *chg, + bool enalbe); +int check_allow_switch_dash(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_prop_chg_voltage(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_prop_batt_temp(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_prop_chg_protect_status(struct smb_charger *chg, + const union power_supply_propval *val); +bool op_get_fastchg_ing(struct smb_charger *chg); +bool get_prop_fastchg_status(struct smb_charger *chg); +int op_usb_icl_set(struct smb_charger *chg, int icl_ua); +int op_get_aicl_result(struct smb_charger *chg); +bool get_prop_fastchg_is_ok(struct smb_charger *chg); +void op_disconnect_vbus(struct smb_charger *chg, bool enable); + int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val); int smblib_write(struct smb_charger *chg, u16 addr, u8 val); @@ -698,6 +1004,8 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_batt_temp(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -836,7 +1144,9 @@ int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val); int smblib_get_irq_status(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_qc3_main_icl_offset(struct smb_charger *chg, int *offset_ua); +int smblib_start_dpdm_recovery(struct smb_charger *chg, bool enable); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); +extern void op_release_usb_lock(void); #endif /* __SMB5_CHARGER_H */ diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 311e810c31c0d344c9d10df6250c3ebb043672bf..7d2df35a4c08c1474b3038293d43c1d090ded99e 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -28,6 +28,11 @@ * CHGR Peripheral Registers * ********************************/ #define BATTERY_CHARGER_STATUS_1_REG (CHGR_BASE + 0x06) +/* @bsp, 2019/07/05 Battery & Charging porting */ +#define BVR_INITIAL_RAMP_BIT BIT(7) +#define ZERO_CHARGE_CURRENT_BIT BIT(6) +#define STEP_CHARGING_STATUS_SHIFT 3 +#define STEP_CHARGING_STATUS_MASK GENMASK(5, 3) #define BATTERY_CHARGER_STATUS_MASK GENMASK(2, 0) enum { INHIBIT_CHARGE = 0, @@ -150,6 +155,13 @@ enum { #define DCDC_OTG_CFG_REG (DCDC_BASE + 0x53) #define OTG_EN_SRC_CFG_BIT BIT(1) +/* @bsp, 2019/07/05 Battery & Charging porting */ +/*DCDC_VPH_TRACK_SEL*/ +#define DCDC_VPH_TRACK_SEL (DCDC_BASE + 0x89) +#define VPH_TRACK_SEL_MASK GENMASK(1, 0) +#define SEL_200MV BIT(0) +#define SEL_300MV BIT(1) + #define OTG_FAULT_CONDITION_CFG_REG (DCDC_BASE + 0x56) #define USBIN_MID_COMP_FAULT_EN_BIT BIT(5) #define USBIN_COLLAPSE_FAULT_EN_BIT BIT(4) @@ -304,6 +316,20 @@ enum { #define SUSPEND_ON_COLLAPSE_USBIN_BIT BIT(7) #define USBIN_AICL_PERIODIC_RERUN_EN_BIT BIT(4) #define USBIN_AICL_ADC_EN_BIT BIT(3) +/* @bsp 2019/07/05 add for porting & charge */ +#define SUSPEND_ON_COLLAPSE_USBIN_BIT BIT(7) +#define USBIN_AICL_HDC_EN_BIT BIT(6) +#define USBIN_AICL_START_AT_MAX_BIT BIT(5) +#define USBIN_AICL_EN_BIT BIT(2) +#define USBIN_HV_COLLAPSE_RESPONSE_BIT BIT(1) +#define USBIN_LV_COLLAPSE_RESPONSE_BIT BIT(0) + +#define USBIN_5V_AICL_THRESHOLD_CFG_REG (USBIN_BASE + 0x81) +#define USBIN_5V_AICL_THRESHOLD_CFG_MASK GENMASK(2, 0) + +#define USBIN_CONT_AICL_THRESHOLD_CFG_REG (USBIN_BASE + 0x84) +#define USBIN_CONT_AICL_THRESHOLD_CFG_MASK GENMASK(5, 0) + #define USBIN_AICL_EN_BIT BIT(2) #define USB_ENG_SSUPPLY_USB2_REG (USBIN_BASE + 0xC0) @@ -336,6 +362,7 @@ enum { #define TYPE_C_SNK_STATUS_REG (TYPEC_BASE + 0x06) #define DETECTED_SRC_TYPE_MASK GENMASK(6, 0) #define SNK_DAM_MASK GENMASK(6, 4) +/* add to fix huawei cable compatible issue */ #define SNK_DAM_500MA_BIT BIT(6) #define SNK_DAM_1500MA_BIT BIT(5) #define SNK_DAM_3000MA_BIT BIT(4) @@ -356,6 +383,9 @@ enum { #define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09) #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) +/* add to fix huawei cable compatible issue */ +#define DEBUG_ACCESS_SNK_CFG_REG (TYPEC_BASE + 0x4A) + #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) #define TYPEC_WATER_DETECTION_STATUS_BIT BIT(7) #define SNK_SRC_MODE_BIT BIT(6) @@ -380,7 +410,8 @@ enum { #define TYPEC_TRY_MODE_MASK GENMASK(4, 3) #define EN_TRY_SNK_BIT BIT(4) #define EN_TRY_SRC_BIT BIT(3) -#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) +/* @bsp, 2019/07/05 Battery & Charging porting */ +#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(4, 0) #define EN_SRC_ONLY_BIT BIT(2) #define EN_SNK_ONLY_BIT BIT(1) #define TYPEC_DISABLE_CMD_BIT BIT(0) diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c index a2e9bf95918a2e9fec60850cb08b55e2081dfa1a..35c08078e67809c651df369bbd4b85fc987fbaea 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.c +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -229,7 +229,7 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) u32 max_fv_uv, max_fcc_ma; const char *batt_type_str; const __be32 *handle; - int batt_id_ohms, rc; + int batt_id_ohms, rc, hysteresis[2] = {0}; union power_supply_propval prop = {0, }; handle = of_get_property(chip->dev->of_node, @@ -297,7 +297,8 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) chip->step_chg_config->param.psy_prop = POWER_SUPPLY_PROP_CAPACITY; chip->step_chg_config->param.prop_name = "SOC"; - chip->step_chg_config->param.hysteresis = 0; + chip->step_chg_config->param.rise_hys = 0; + chip->step_chg_config->param.fall_hys = 0; } chip->ocv_based_step_chg = @@ -306,7 +307,8 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) chip->step_chg_config->param.psy_prop = POWER_SUPPLY_PROP_VOLTAGE_OCV; chip->step_chg_config->param.prop_name = "OCV"; - chip->step_chg_config->param.hysteresis = 0; + chip->step_chg_config->param.rise_hys = 0; + chip->step_chg_config->param.fall_hys = 0; chip->step_chg_config->param.use_bms = true; } @@ -317,7 +319,8 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) chip->step_chg_config->param.psy_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; chip->step_chg_config->param.prop_name = "VBAT_AVG"; - chip->step_chg_config->param.hysteresis = 0; + chip->step_chg_config->param.rise_hys = 0; + chip->step_chg_config->param.fall_hys = 0; chip->step_chg_config->param.use_bms = true; } @@ -344,6 +347,15 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) chip->sw_jeita_cfg_valid = false; } + rc = of_property_read_u32_array(profile_node, + "qcom,step-jeita-hysteresis", hysteresis, 2); + if (!rc) { + chip->jeita_fcc_config->param.rise_hys = hysteresis[0]; + chip->jeita_fcc_config->param.fall_hys = hysteresis[1]; + pr_debug("jeita-fcc-hys: rise_hys=%u, fall_hys=%u\n", + hysteresis[0], hysteresis[1]); + } + rc = read_range_data_from_node(profile_node, "qcom,jeita-fv-ranges", chip->jeita_fv_config->fv_cfg, @@ -403,9 +415,8 @@ static void get_config_work(struct work_struct *work) } -static int get_val(struct range_data *range, int hysteresis, int current_index, - int threshold, - int *new_index, int *val) +static int get_val(struct range_data *range, int rise_hys, int fall_hys, + int current_index, int threshold, int *new_index, int *val) { int i; @@ -463,7 +474,8 @@ static int get_val(struct range_data *range, int hysteresis, int current_index, * of our current index. */ if (*new_index == current_index + 1) { - if (threshold < range[*new_index].low_threshold + hysteresis) { + if (threshold < + (range[*new_index].low_threshold + rise_hys)) { /* * Stay in the current index, threshold is not higher * by hysteresis amount @@ -472,7 +484,8 @@ static int get_val(struct range_data *range, int hysteresis, int current_index, *val = range[current_index].value; } } else if (*new_index == current_index - 1) { - if (threshold > range[*new_index].high_threshold - hysteresis) { + if (threshold > + range[*new_index].high_threshold - fall_hys) { /* * stay in the current index, threshold is not lower * by hysteresis amount @@ -502,7 +515,7 @@ static void taper_fcc_step_chg(struct step_chg_info *chip, int index, vote(chip->fcc_votable, STEP_CHG_VOTER, true, target_fcc); } else if (current_voltage > (chip->step_chg_config->fcc_cfg[index - 1].high_threshold + - chip->step_chg_config->param.hysteresis)) { + chip->step_chg_config->param.rise_hys)) { /* * Ramp down FCC in pre-configured steps till the current index * FCC configuration is reached, whenever the step charging @@ -515,7 +528,7 @@ static void taper_fcc_step_chg(struct step_chg_info *chip, int index, chip->step_chg_config->fcc_cfg[index - 1].value) && (current_voltage > chip->step_chg_config->fcc_cfg[index - 1].low_threshold + - chip->step_chg_config->param.hysteresis)) { + chip->step_chg_config->param.fall_hys)) { /* * In case the step charging index switch to the next higher * index without FCCs saturation for the previous index, ramp @@ -566,7 +579,8 @@ static int handle_step_chg_config(struct step_chg_info *chip) current_index = chip->step_index; rc = get_val(chip->step_chg_config->fcc_cfg, - chip->step_chg_config->param.hysteresis, + chip->step_chg_config->param.rise_hys, + chip->step_chg_config->param.fall_hys, chip->step_index, pval.intval, &chip->step_index, @@ -651,7 +665,8 @@ static int handle_jeita(struct step_chg_info *chip) } rc = get_val(chip->jeita_fcc_config->fcc_cfg, - chip->jeita_fcc_config->param.hysteresis, + chip->jeita_fcc_config->param.rise_hys, + chip->jeita_fcc_config->param.fall_hys, chip->jeita_fcc_index, pval.intval, &chip->jeita_fcc_index, @@ -668,7 +683,8 @@ static int handle_jeita(struct step_chg_info *chip) vote(chip->fcc_votable, JEITA_VOTER, fcc_ua ? true : false, fcc_ua); rc = get_val(chip->jeita_fv_config->fv_cfg, - chip->jeita_fv_config->param.hysteresis, + chip->jeita_fv_config->param.rise_hys, + chip->jeita_fv_config->param.fall_hys, chip->jeita_fv_index, pval.intval, &chip->jeita_fv_index, @@ -862,7 +878,8 @@ int qcom_step_chg_init(struct device *dev, chip->step_chg_config->param.psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; chip->step_chg_config->param.prop_name = "VBATT"; - chip->step_chg_config->param.hysteresis = 100000; + chip->step_chg_config->param.rise_hys = 100000; + chip->step_chg_config->param.fall_hys = 100000; chip->jeita_fcc_config = devm_kzalloc(dev, sizeof(struct jeita_fcc_cfg), GFP_KERNEL); @@ -873,10 +890,12 @@ int qcom_step_chg_init(struct device *dev, chip->jeita_fcc_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP; chip->jeita_fcc_config->param.prop_name = "BATT_TEMP"; - chip->jeita_fcc_config->param.hysteresis = 10; + chip->jeita_fcc_config->param.rise_hys = 10; + chip->jeita_fcc_config->param.fall_hys = 10; chip->jeita_fv_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP; chip->jeita_fv_config->param.prop_name = "BATT_TEMP"; - chip->jeita_fv_config->param.hysteresis = 10; + chip->jeita_fv_config->param.rise_hys = 10; + chip->jeita_fv_config->param.fall_hys = 10; INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->get_config_work, get_config_work); diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h index 285528f6af9422ed63038a6c73963f3bcd18665a..138602a66e9f5f8884d91bf8c326d2207bebbaca 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.h +++ b/drivers/power/supply/qcom/step-chg-jeita.h @@ -11,7 +11,8 @@ struct step_chg_jeita_param { u32 psy_prop; char *prop_name; - int hysteresis; + int rise_hys; + int fall_hys; bool use_bms; }; diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index a4e5d57a12b99e39c02cca16904567c1afa8debd..fe17d3e4d63deedef9ddb7405a6cd67ca7013772 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1999,6 +1999,17 @@ static void qcom_glink_cancel_rx_work(struct qcom_glink *glink) kfree(dcmd); } +/* Modify for glink name */ +struct g_sub_name { + const char *g_name; + const char *s_name; +} sub_name[] = { + {"adsp", "glink-adsp"}, + {"cdsp", "glink-cdsp"}, + {"modem", "glink-modem"}, + {"npu", "glink-npu"}, +}; + struct qcom_glink *qcom_glink_native_probe(struct device *dev, unsigned long features, struct qcom_glink_pipe *rx, @@ -2010,6 +2021,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, int size; int irq; int ret; + /* Modify for glink name */ + int i; glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL); if (!glink) @@ -2074,6 +2087,22 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, goto unregister; } + /* Modify for glink name */ + for (i = 0; i < ARRAY_SIZE(sub_name); i++) { + if (strcmp(sub_name[i].g_name, glink->name) == 0) { + ret = devm_request_irq(dev, irq, + qcom_glink_native_intr, + IRQF_NO_SUSPEND | IRQF_SHARED, + sub_name[i].s_name, glink); + + if (ret) { + dev_err(dev, "failed to request IRQ\n"); + goto unregister; + } + break; + } + } + glink->irq = irq; size = of_property_count_u32_elems(dev->of_node, "cpu-affinity"); diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 40fefd9c38b186e301ccbd75764d142e5a6695d3..57da57fc2d7bb1b443dc73d5e004cea11521f81b 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -13,6 +13,8 @@ #include #include +static bool print_cureent_time; + /* RTC Register offsets from RTC CTRL REG */ #define PM8XXX_ALARM_CTRL_OFFSET 0x01 #define PM8XXX_RTC_WRITE_OFFSET 0x02 @@ -182,6 +184,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) unsigned int reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + static int is_first_time = 1; rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); if (rc) { @@ -213,10 +216,21 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(secs, tm); + if (is_first_time) { + /* print timestamp for debug */ + dev_err(dev, "rtc timestamp = %lu\n", secs); + is_first_time = 0; + } + dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", secs, tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_mday, tm->tm_mon, tm->tm_year); - + if (print_cureent_time) { + print_cureent_time = false; + dev_info(dev, "current time:secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", + secs, tm->tm_hour, tm->tm_min, tm->tm_sec, + tm->tm_mday, tm->tm_mon, tm->tm_year); + } return 0; } @@ -228,13 +242,28 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned long secs, irq_flags; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + static u8 pre_value_0, pre_value_1, pre_value_2, pre_value_3; + static int alarm_en_pre; rtc_tm_to_time(&alarm->time, &secs); - for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { value[i] = secs & 0xFF; secs >>= 8; } + if (value[0] != pre_value_0 || value[1] != pre_value_1 + || value[2] != pre_value_2 || value[3] != pre_value_3) { + dev_info(dev, "val[0] = 0x%x, val[1] = 0x%x, val[2] = 0x%x, val[3] = 0x%x\n", + value[0], value[1], value[2], value[3]); + dev_info(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", + alarm->time.tm_hour, alarm->time.tm_min, + alarm->time.tm_sec, alarm->time.tm_mday, + alarm->time.tm_mon, alarm->time.tm_year); + print_cureent_time = true; + } + pre_value_0 = value[0]; + pre_value_1 = value[1]; + pre_value_2 = value[2]; + pre_value_3 = value[3]; spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); @@ -259,6 +288,9 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) dev_err(dev, "Write to RTC alarm control register failed\n"); goto rtc_rw_fail; } + if (alarm_en_pre != alarm->enabled) + dev_info(dev, "alarm->enabled:%d\n", alarm->enabled); + alarm_en_pre = alarm->enabled; dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", alarm->time.tm_hour, alarm->time.tm_min, diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index f1aae8beff9ecf0ece86dba95464bf8ca773d00f..c47682113d41dfac67ccf5e8e8ef5af7c0a1aa89 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -148,3 +148,28 @@ config SCSI_UFS_CRYPTO_QTI Enable Vendor Crypto Engine Support in UFS Enabling this allows kernel to use UFS crypto operations defined and implemented by QTI. + +config UFSFEATURE + bool "UFS feature activate" + depends on SCSI_UFSHCD + ---help--- + UFS feature activate such as hpb, tw and etc. + +config UFSHPB + bool "UFSHPB" + depends on SCSI_UFSHCD && UFSFEATURE + ---help--- + UFS HPB Feature Enable + +config UFSTW + bool "UFSTW" + depends on SCSI_UFSHCD && UFSFEATURE + ---help--- + UFS TW Feature Enable + +config UFSTW_IGNORE_GUARANTEE_BIT + bool "UFSTW_IGNORE_GUARANTEE_BIT" + default n + depends on SCSI_UFSHCD && UFSFEATURE && UFSTW + ---help--- + ignore the guarantee bit[31] of dTurboWriteBufferLifeTimeEst for PoC diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index e7294e6f42a31afd35868d5e0636481eec88f3a3..fde454ce18579bbeb9018b6e88263ccc8744dcf2 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -6,6 +6,9 @@ obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o obj-$(CONFIG_SCSI_UFS_QCOM_ICE) += ufs-qcom-ice.o obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o ufshcd-core-objs := ufshcd.o ufs-sysfs.o +obj-$(CONFIG_UFSFEATURE) += ufsfeature.o +obj-$(CONFIG_UFSHPB) += ufshpb.o +obj-$(CONFIG_UFSTW) += ufstw.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index cededde98be3e7993f59558760bbde4433185cdd..08b2868fa4bb95104d9fd69a3782afab4caa75ce 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -166,6 +166,14 @@ enum unit_desc_param { UNIT_DESC_PARAM_CTX_CAPABILITIES = 0x20, UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22, UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS = 0x29, +#if defined(CONFIG_UFSHPB) + UNIT_DESC_HPB_LU_MAX_ACTIVE_REGIONS = 0x23, + UNIT_DESC_HPB_LU_PIN_REGION_START_OFFSET = 0x25, + UNIT_DESC_HPB_LU_NUM_PIN_REGIONS = 0x27, +#endif +#if defined(CONFIG_UFSTW) + UNIT_DESC_TW_LU_MAX_BUF_SIZE = 0x29, +#endif }; /* Device descriptor parameters offsets in bytes*/ @@ -205,6 +213,17 @@ enum device_desc_param { DEVICE_DESC_PARAM_PSA_MAX_DATA = 0x25, DEVICE_DESC_PARAM_PSA_TMT = 0x29, DEVICE_DESC_PARAM_PRDCT_REV = 0x2A, +#if defined(CONFIG_UFSHPB) + DEVICE_DESC_PARAM_HPB_VER = 0x40, +#endif +#if defined(CONFIG_UFSFEATURE) + DEVICE_DESC_PARAM_EX_FEAT_SUP = 0x4F, +#endif +#if defined(CONFIG_UFSTW) + DEVICE_DESC_PARAM_TW_RETURN_TO_USER = 0x53, + DEVICE_DESC_PARAM_TW_BUF_TYPE = 0x54, + DEVICE_DESC_PARAM_TW_VER = 0x55, +#endif DEVICE_DESC_PARAM_EXT_UFS_FEATURE_SUP = 0x4F, DEVICE_DESC_PARAM_WB_US_RED_EN = 0x53, DEVICE_DESC_PARAM_WB_TYPE = 0x54, @@ -258,6 +277,20 @@ enum geometry_desc_param { GEOMETRY_DESC_PARAM_WB_BUFF_CAP_ADJ = 0x54, GEOMETRY_DESC_PARAM_WB_SUP_RED_TYPE = 0x55, GEOMETRY_DESC_PARAM_WB_SUP_WB_TYPE = 0x56, +#if defined(CONFIG_UFSHPB) + GEOMETRY_DESC_HPB_REGION_SIZE = 0x48, + GEOMETRY_DESC_HPB_NUMBER_LU = 0x49, + GEOMETRY_DESC_HPB_SUBREGION_SIZE = 0x4A, + GEOMETRY_DESC_HPB_DEVICE_MAX_ACTIVE_REGIONS = 0x4B, +#endif +#if defined(CONFIG_UFSTW) + GEOMETRY_DESC_TW_MAX_SIZE = 0x4F, + GEOMETRY_DESC_TW_NUMBER_LU = 0x53, + GEOMETRY_DESC_TW_CAP_ADJ_FAC = 0x54, + GEOMETRY_DESC_TW_SUPPORT_USER_REDUCTION_TYPES = 0x55, + GEOMETRY_DESC_TW_SUPPORT_BUF_TYPE = 0x56, + GEOMETRY_DESC_TW_GROUP_NUM_CAP = 0x57, +#endif }; /* Health descriptor parameters offsets in bytes*/ @@ -310,6 +343,9 @@ enum power_desc_param_offset { enum { MASK_EE_STATUS = 0xFFFF, MASK_EE_URGENT_BKOPS = (1 << 2), +#if defined(CONFIG_UFSTW) + MASK_EE_TW = (1 << 5), +#endif }; /* Background operation status */ diff --git a/drivers/scsi/ufs/ufsfeature.c b/drivers/scsi/ufs/ufsfeature.c new file mode 100644 index 0000000000000000000000000000000000000000..aba482f847ef00ee47285795a7131c5a929ca430 --- /dev/null +++ b/drivers/scsi/ufs/ufsfeature.c @@ -0,0 +1,738 @@ +/* + * Universal Flash Storage Feature Support + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * 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. + * See the COPYING file in the top-level directory or visit + * + * + * 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. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include + +#include "ufsfeature.h" +#include "ufshcd.h" + +#if defined(CONFIG_UFSHPB) +#include "ufshpb.h" +#endif + +#define QUERY_REQ_TIMEOUT 1500 /* msec */ + +static inline void ufsf_init_query(struct ufs_hba *hba, + struct ufs_query_req **request, + struct ufs_query_res **response, + enum query_opcode opcode, u8 idn, + u8 index, u8 selector) +{ + *request = &hba->dev_cmd.query.request; + *response = &hba->dev_cmd.query.response; + memset(*request, 0, sizeof(struct ufs_query_req)); + memset(*response, 0, sizeof(struct ufs_query_res)); + (*request)->upiu_req.opcode = opcode; + (*request)->upiu_req.idn = idn; + (*request)->upiu_req.index = index; + (*request)->upiu_req.selector = selector; +} + +/* + * ufs feature common functions. + */ +int ufsf_query_flag(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, u8 index, bool *flag_res) +{ + struct ufs_query_req *request = NULL; + struct ufs_query_res *response = NULL; + int err; + + BUG_ON(!hba); + + ufshcd_hold_all(hba); + mutex_lock(&hba->dev_cmd.lock); + + /* + * Init the query response and request parameters + */ + ufsf_init_query(hba, &request, &response, opcode, idn, index, + UFSFEATURE_SELECTOR); + + switch (opcode) { + case UPIU_QUERY_OPCODE_SET_FLAG: + case UPIU_QUERY_OPCODE_CLEAR_FLAG: + case UPIU_QUERY_OPCODE_TOGGLE_FLAG: + request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; + break; + case UPIU_QUERY_OPCODE_READ_FLAG: + request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; + if (!flag_res) { + /* No dummy reads */ + dev_err(hba->dev, "%s: Invalid argument for read request\n", + __func__); + err = -EINVAL; + goto out_unlock; + } + break; + default: + dev_err(hba->dev, + "%s: Expected query flag opcode but got = %d\n", + __func__, opcode); + err = -EINVAL; + goto out_unlock; + } + + /* Send query request */ + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); + if (err) { + dev_err(hba->dev, + "%s: Sending flag query for idn %d failed, err = %d\n", + __func__, idn, err); + goto out_unlock; + } + + if (flag_res) + *flag_res = (be32_to_cpu(response->upiu_res.value) & + MASK_QUERY_UPIU_FLAG_LOC) & 0x1; + +out_unlock: + mutex_unlock(&hba->dev_cmd.lock); + ufshcd_release_all(hba); + return err; +} + +int ufsf_query_flag_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, u8 idx, bool *flag_res) +{ + int ret; + int retries; + + for (retries = 0; retries < UFSF_QUERY_REQ_RETRIES; retries++) { + ret = ufsf_query_flag(hba, opcode, idn, idx, flag_res); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + if (ret) + dev_err(hba->dev, + "%s: query flag, opcode %d, idn %d, failed with error %d after %d retires\n", + __func__, opcode, idn, ret, retries); + return ret; +} + +int ufsf_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 idx, u32 *attr_val) +{ + int ret; + int retries; + + for (retries = 0; retries < UFSF_QUERY_REQ_RETRIES; retries++) { + ret = ufshcd_query_attr(hba, opcode, idn, idx, + UFSFEATURE_SELECTOR, attr_val); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + if (ret) + dev_err(hba->dev, + "%s: query attr, opcode %d, idn %d, failed with error %d after %d retires\n", + __func__, opcode, idn, ret, retries); + return ret; +} + +static int ufsf_read_desc(struct ufs_hba *hba, u8 desc_id, u8 desc_index, + u8 selector, u8 *desc_buf, u32 size) +{ + int err = 0; + + pm_runtime_get_sync(hba->dev); + + err = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + desc_id, desc_index, + selector, + desc_buf, &size); + if (err) + ERR_MSG("reading Device Desc failed. err = %d", err); + + pm_runtime_put_sync(hba->dev); + + return err; +} + +static int ufsf_read_dev_desc(struct ufsf_feature *ufsf, u8 selector) +{ + u8 desc_buf[UFSF_QUERY_DESC_DEVICE_MAX_SIZE]; + int ret; + + ret = ufsf_read_desc(ufsf->hba, QUERY_DESC_IDN_DEVICE, 0, selector, + desc_buf, UFSF_QUERY_DESC_DEVICE_MAX_SIZE); + if (ret) + return ret; + + ufsf->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU]; + INIT_INFO("device lu count %d", ufsf->num_lu); + + INIT_INFO("sel=%u length=%u(0x%x) bSupport=0x%.2x, extend=0x%.2x_%.2x", + selector, desc_buf[DEVICE_DESC_PARAM_LEN], + desc_buf[DEVICE_DESC_PARAM_LEN], + desc_buf[DEVICE_DESC_PARAM_UFS_FEAT], + desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP+2], + desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP+3]); + +#if defined(CONFIG_UFSHPB) + ufshpb_get_dev_info(&ufsf->hpb_dev_info, desc_buf); +#endif + +#if defined(CONFIG_UFSTW) + ufstw_get_dev_info(&ufsf->tw_dev_info, desc_buf); +#endif + return 0; +} + +static int ufsf_read_geo_desc(struct ufsf_feature *ufsf, u8 selector) +{ + u8 geo_buf[UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE]; + int ret; + + ret = ufsf_read_desc(ufsf->hba, QUERY_DESC_IDN_GEOMETRY, 0, selector, + geo_buf, UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE); + if (ret) + return ret; + +#if defined(CONFIG_UFSHPB) + if (ufsf->hpb_dev_info.hpb_device) + ufshpb_get_geo_info(&ufsf->hpb_dev_info, geo_buf); +#endif + +#if defined(CONFIG_UFSTW) + if (ufsf->tw_dev_info.tw_device) + ufstw_get_geo_info(&ufsf->tw_dev_info, geo_buf); +#endif + return 0; +} + +static int ufsf_read_unit_desc(struct ufsf_feature *ufsf, int lun, u8 selector) +{ + u8 unit_buf[UFSF_QUERY_DESC_UNIT_MAX_SIZE]; + int lu_enable, ret = 0; + + ret = ufsf_read_desc(ufsf->hba, QUERY_DESC_IDN_UNIT, lun, selector, + unit_buf, UFSF_QUERY_DESC_UNIT_MAX_SIZE); + if (ret) { + ERR_MSG("read unit desc failed. ret %d", ret); + goto out; + } + + lu_enable = unit_buf[UNIT_DESC_PARAM_LU_ENABLE]; + if (!lu_enable) + return 0; + +#if defined(CONFIG_UFSHPB) + if (ufsf->hpb_dev_info.hpb_device) { + ret = ufshpb_get_lu_info(ufsf, lun, unit_buf); + if (ret == -ENOMEM) + goto out; + } +#endif + +#if defined(CONFIG_UFSTW) + if (ufsf->tw_dev_info.tw_device) { + ret = ufstw_get_lu_info(ufsf, lun, unit_buf); + if (ret == -ENOMEM) + goto out; + } +#endif +out: + return ret; +} + +int is_samsung_feature(struct ufs_hba *hba) +{ + int is_samsung_feature = 0; + struct Scsi_Host *shost; + struct scsi_device *sdev; + + shost = hba->host; + shost_for_each_device(sdev, shost) { + if ((strncmp(sdev->vendor, "SAMSUNG", 7) == 0) + && ((strncmp(sdev->rev, "0500", 4) == 0) + || (strncmp(sdev->rev, "1500", 4) == 0))) + is_samsung_feature = 1; + } + return is_samsung_feature; +} + +void ufsf_device_check(struct ufs_hba *hba) +{ + struct ufsf_feature *ufsf = &hba->ufsf; + int ret, lun; + u32 status; + + ufsf->slave_conf_cnt = 0; + + ufsf->hba = hba; + + if (!is_samsung_feature(hba)) { +#if defined(CONFIG_UFSHPB) + ufsf->ufshpb_state = HPB_FAILED; +#endif +#if defined(CONFIG_UFSTW) + ufsf->tw_dev_info.tw_device = false; + atomic_set(&ufsf->tw_state, TW_FAILED); +#endif + return; + } + + ufshcd_query_attr(ufsf->hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS, 0, 0, &status); + INIT_INFO("UFS FEATURE SELECTOR Dev %d - D/D %d", status, + UFSFEATURE_SELECTOR); + + ret = ufsf_read_dev_desc(ufsf, UFSFEATURE_SELECTOR); + if (ret) + return; + + ret = ufsf_read_geo_desc(ufsf, UFSFEATURE_SELECTOR); + if (ret) + return; + + seq_scan_lu(lun) { + ret = ufsf_read_unit_desc(ufsf, lun, UFSFEATURE_SELECTOR); + if (ret == -ENOMEM) + goto out_free_mem; + } + + return; +out_free_mem: +#if defined(CONFIG_UFSHPB) + seq_scan_lu(lun) + kfree(ufsf->ufshpb_lup[lun]); + + /* don't call init handler */ + ufsf->ufshpb_state = HPB_FAILED; +#endif +#if defined(CONFIG_UFSTW) + seq_scan_lu(lun) + kfree(ufsf->tw_lup[lun]); + + ufsf->tw_dev_info.tw_device = false; + atomic_set(&ufsf->tw_state, TW_FAILED); +#endif +} + +static void ufsf_print_query_buf(unsigned char *field, int size) +{ + unsigned char buf[255]; + int count = 0; + int i; + + count += snprintf(buf, 8, "(0x00):"); + + for (i = 0; i < size; i++) { + count += snprintf(buf + count, 4, " %.2X", field[i]); + + if ((i + 1) % 16 == 0) { + buf[count] = '\n'; + buf[count + 1] = '\0'; + printk(buf); + count = 0; + count += snprintf(buf, 8, "(0x%.2X):", i + 1); + } else if ((i + 1) % 4 == 0) + count += snprintf(buf + count, 3, " :"); + } + buf[count] = '\n'; + buf[count + 1] = '\0'; + printk(buf); +} + +inline int ufsf_check_query(__u32 opcode) +{ + return (opcode & 0xffff0000) >> 16 == UFSFEATURE_QUERY_OPCODE; +} + +int ufsf_query_ioctl(struct ufsf_feature *ufsf, int lun, void __user *buffer, + struct ufs_ioctl_query_data *ioctl_data, u8 selector) +{ + unsigned char *kernel_buf; + int opcode; + int err = 0; + int index = 0; + int length = 0; + int buf_len = 0; + + opcode = ioctl_data->opcode & 0xffff; + + INFO_MSG("op %u idn %u sel %u size %u(0x%X)", opcode, ioctl_data->idn, + selector, ioctl_data->buf_size, ioctl_data->buf_size); + + buf_len = (ioctl_data->idn == QUERY_DESC_IDN_STRING) ? + IOCTL_DEV_CTX_MAX_SIZE : QUERY_DESC_MAX_SIZE; + + kernel_buf = kzalloc(buf_len, GFP_KERNEL); + if (!kernel_buf) { + err = -ENOMEM; + goto out; + } + + switch (opcode) { + case UPIU_QUERY_OPCODE_WRITE_DESC: + err = copy_from_user(kernel_buf, buffer + + sizeof(struct ufs_ioctl_query_data), + ioctl_data->buf_size); + INFO_MSG("buf size %d", ioctl_data->buf_size); + ufsf_print_query_buf(kernel_buf, ioctl_data->buf_size); + if (err) + goto out_release_mem; + break; + + case UPIU_QUERY_OPCODE_READ_DESC: + switch (ioctl_data->idn) { + case QUERY_DESC_IDN_UNIT: + if (!ufs_is_valid_unit_desc_lun(lun)) { + ERR_MSG("No unit descriptor for lun 0x%x", lun); + err = -EINVAL; + goto out_release_mem; + } + index = lun; + INFO_MSG("read lu desc lun: %d", index); + break; + + case QUERY_DESC_IDN_STRING: +#if defined(CONFIG_UFSHPB) + if (!ufs_is_valid_unit_desc_lun(lun)) { + ERR_MSG("No unit descriptor for lun 0x%x", lun); + err = -EINVAL; + goto out_release_mem; + } + err = ufshpb_issue_req_dev_ctx(ufsf->ufshpb_lup[lun], + kernel_buf, + ioctl_data->buf_size); + if (err < 0) + goto out_release_mem; + + goto copy_buffer; +#endif + case QUERY_DESC_IDN_DEVICE: + case QUERY_DESC_IDN_GEOMETRY: + case QUERY_DESC_IDN_CONFIGURATION: + break; + + default: + ERR_MSG("invalid idn %d", ioctl_data->idn); + err = -EINVAL; + goto out_release_mem; + } + break; + default: + ERR_MSG("invalid opcode %d", opcode); + err = -EINVAL; + goto out_release_mem; + } + + length = ioctl_data->buf_size; + + err = ufshcd_query_descriptor_retry(ufsf->hba, opcode, ioctl_data->idn, + index, selector, kernel_buf, + &length); + if (err) + goto out_release_mem; + +#if defined(CONFIG_UFSHPB) +copy_buffer: +#endif + if (opcode == UPIU_QUERY_OPCODE_READ_DESC) { + err = copy_to_user(buffer, ioctl_data, + sizeof(struct ufs_ioctl_query_data)); + if (err) + ERR_MSG("Failed copying back to user."); + + err = copy_to_user(buffer + sizeof(struct ufs_ioctl_query_data), + kernel_buf, ioctl_data->buf_size); + if (err) + ERR_MSG("Fail: copy rsp_buffer to user space."); + } +out_release_mem: + kfree(kernel_buf); +out: + return err; +} + +inline bool ufsf_is_valid_lun(int lun) +{ + return lun < UFS_UPIU_MAX_GENERAL_LUN; +} + +inline int ufsf_get_ee_status(struct ufs_hba *hba, u32 *status) +{ + return ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_EE_STATUS, 0, status); +} + +/* + * Wrapper functions for ufshpb. + */ +#if defined(CONFIG_UFSHPB) +inline int ufsf_hpb_prepare_pre_req(struct ufsf_feature *ufsf, + struct scsi_cmnd *cmd, int lun) +{ + if (ufsf->ufshpb_state == HPB_PRESENT) + return ufshpb_prepare_pre_req(ufsf, cmd, lun); + return -ENODEV; +} + +inline int ufsf_hpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag) +{ + if (ufsf->ufshpb_state == HPB_PRESENT) + return ufshpb_prepare_add_lrbp(ufsf, add_tag); + return -ENODEV; +} + +inline void ufsf_hpb_end_pre_req(struct ufsf_feature *ufsf, + struct request *req) +{ + ufshpb_end_pre_req(ufsf, req); +} + +inline void ufsf_hpb_change_lun(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) +{ + int ctx_lba = LI_EN_32(lrbp->cmd->cmnd + 2); + + if (ufsf->ufshpb_state == HPB_PRESENT && + ufsf->issue_ioctl == true && ctx_lba == READ10_DEBUG_LBA) { + lrbp->lun = READ10_DEBUG_LUN; + INFO_MSG("lun 0x%X lba 0x%X", lrbp->lun, ctx_lba); + } +} + +inline void ufsf_hpb_prep_fn(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) +{ + if (ufsf->ufshpb_state == HPB_PRESENT + && ufsf->issue_ioctl == false) + ufshpb_prep_fn(ufsf, lrbp); +} + +inline void ufsf_hpb_noti_rb(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + if (ufsf->ufshpb_state == HPB_PRESENT) + ufshpb_rsp_upiu(ufsf, lrbp); +} + +inline void ufsf_hpb_reset_lu(struct ufsf_feature *ufsf) +{ + ufsf->ufshpb_state = HPB_RESET; + schedule_work(&ufsf->ufshpb_reset_work); +} + +inline void ufsf_hpb_reset_host(struct ufsf_feature *ufsf) +{ + if (ufsf->ufshpb_state == HPB_PRESENT) + ufsf->ufshpb_state = HPB_RESET; +} + +inline void ufsf_hpb_init(struct ufsf_feature *ufsf) +{ + if (ufsf->hpb_dev_info.hpb_device && + ufsf->ufshpb_state == HPB_NEED_INIT) { + INIT_WORK(&ufsf->ufshpb_init_work, ufshpb_init_handler); + schedule_work(&ufsf->ufshpb_init_work); + } +} + +inline void ufsf_hpb_reset(struct ufsf_feature *ufsf) +{ + if (ufsf->hpb_dev_info.hpb_device && + ufsf->ufshpb_state == HPB_RESET) + schedule_work(&ufsf->ufshpb_reset_work); +} + +inline void ufsf_hpb_suspend(struct ufsf_feature *ufsf) +{ + if (ufsf->ufshpb_state == HPB_PRESENT) + ufshpb_suspend(ufsf); +} + +inline void ufsf_hpb_resume(struct ufsf_feature *ufsf) +{ + if (ufsf->ufshpb_state == HPB_PRESENT) + ufshpb_resume(ufsf); +} + +inline void ufsf_hpb_release(struct ufsf_feature *ufsf) +{ + ufshpb_release(ufsf, HPB_NEED_INIT); +} + +inline void ufsf_hpb_set_init_state(struct ufsf_feature *ufsf) +{ + ufsf->ufshpb_state = HPB_NEED_INIT; +} +#else +inline int ufsf_hpb_prepare_pre_req(struct ufsf_feature *ufsf, + struct scsi_cmnd *cmd, int lun) +{ + return 0; +} + +inline int ufsf_hpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag) +{ + return 0; +} + +inline void ufsf_hpb_end_pre_req(struct ufsf_feature *ufsf, + struct request *req) {} +inline void ufsf_hpb_change_lun(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) {} +inline void ufsf_hpb_prep_fn(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) {} +inline void ufsf_hpb_noti_rb(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) {} +inline void ufsf_hpb_reset_lu(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_reset_host(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_init(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_reset(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_suspend(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_resume(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_release(struct ufsf_feature *ufsf) {} +inline void ufsf_hpb_set_init_state(struct ufsf_feature *ufsf) {} +#endif + +/* + * Wrapper functions for ufstw. + */ + +#if defined(CONFIG_UFSTW) +inline void ufsf_tw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + ufstw_prep_fn(ufsf, lrbp); +} + +inline void ufsf_tw_init(struct ufsf_feature *ufsf) +{ + INIT_INFO("init start.. tw_state %d", + atomic_read(&ufsf->tw_state)); + + if (ufsf->tw_dev_info.tw_device && + atomic_read(&ufsf->tw_state) == TW_NEED_INIT) { + INIT_WORK(&ufsf->tw_init_work, ufstw_init_work_fn); + schedule_work(&ufsf->tw_init_work); + } +} + +inline void ufsf_tw_reset(struct ufsf_feature *ufsf) +{ + INIT_INFO("reset start.. tw_state %d", + atomic_read(&ufsf->tw_state)); + + if (ufsf->tw_dev_info.tw_device && + atomic_read(&ufsf->tw_state) == TW_RESET) + schedule_delayed_work(&ufsf->tw_reset_work, + msecs_to_jiffies(0)); +} + +inline void ufsf_tw_suspend(struct ufsf_feature *ufsf) +{ + if (atomic_read(&ufsf->tw_state) == TW_PRESENT) + ufstw_suspend(ufsf); +} + +inline void ufsf_tw_resume(struct ufsf_feature *ufsf) +{ + if (atomic_read(&ufsf->tw_state) == TW_PRESENT) + ufstw_resume(ufsf); +} + +inline void ufsf_tw_release(struct ufsf_feature *ufsf) +{ + ufstw_release(&ufsf->tw_kref); +} + +inline void ufsf_tw_set_init_state(struct ufsf_feature *ufsf) +{ + atomic_set(&ufsf->tw_state, TW_NEED_INIT); +} + +inline void ufsf_tw_reset_lu(struct ufsf_feature *ufsf) +{ + INFO_MSG("run reset_lu.. tw_state(%d) -> TW_RESET", + atomic_read(&ufsf->tw_state)); + atomic_set(&ufsf->tw_state, TW_RESET); + schedule_delayed_work(&ufsf->tw_reset_work, msecs_to_jiffies(0)); +} + +inline void ufsf_tw_reset_host(struct ufsf_feature *ufsf) +{ + INFO_MSG("run reset_host.. tw_state(%d) -> TW_RESET", + atomic_read(&ufsf->tw_state)); + if (atomic_read(&ufsf->tw_state) == TW_PRESENT) + atomic_set(&ufsf->tw_state, TW_RESET); +} + +inline void ufsf_tw_ee_handler(struct ufsf_feature *ufsf) +{ + u32 status = 0; + int err; + + if (ufsf->tw_debug && (atomic_read(&ufsf->tw_state) != TW_PRESENT)) { + ERR_MSG("tw_state %d", atomic_read(&ufsf->tw_state)); + return; + } + + if ((atomic_read(&ufsf->tw_state) == TW_PRESENT) + && (ufsf->tw_ee_mode == TW_EE_MODE_AUTO)) { + err = ufsf_get_ee_status(ufsf->hba, &status); + if (err) { + dev_err(ufsf->hba->dev, + "%s: failed to get tw ee status %d\n", + __func__, err); + return; + } + if (status & MASK_EE_TW) + ufstw_ee_handler(ufsf); + } +} +#else +inline void ufsf_tw_prep_fn(struct ufsf_feature *ufsf, + struct ufshcd_lrb *lrbp) {} +inline void ufsf_tw_init(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_reset(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_suspend(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_resume(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_release(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_set_init_state(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_reset_lu(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_reset_host(struct ufsf_feature *ufsf) {} +inline void ufsf_tw_ee_handler(struct ufsf_feature *ufsf) {} +#endif diff --git a/drivers/scsi/ufs/ufsfeature.h b/drivers/scsi/ufs/ufsfeature.h new file mode 100644 index 0000000000000000000000000000000000000000..4ce679db50f041a3217e6976fd39b1586ac3809b --- /dev/null +++ b/drivers/scsi/ufs/ufsfeature.h @@ -0,0 +1,210 @@ +/* + * Universal Flash Storage Feature Support + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * 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. + * See the COPYING file in the top-level directory or visit + * + * + * 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. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSFEATURE_H_ +#define _UFSFEATURE_H_ + +#include "ufs.h" +#include "../../../include/uapi/scsi/ufs/ioctl.h" + +#if defined(CONFIG_UFSHPB) +#include "ufshpb.h" +#endif +#include + +#if defined(CONFIG_UFSTW) +#include "ufstw.h" +#endif + +/* Constant value*/ +#define SECTOR 512 +#define BLOCK 4096 +#define SECTORS_PER_BLOCK (BLOCK / SECTOR) +#define BITS_PER_DWORD 32 + +#define IOCTL_DEV_CTX_MAX_SIZE OS_PAGE_SIZE +#define OS_PAGE_SIZE 4096 +#define OS_PAGE_SHIFT 12 + +#define UFSF_QUERY_REQ_RETRIES 1 + +/* Description */ +#define UFSF_QUERY_DESC_DEVICE_MAX_SIZE 0x57 +#define UFSF_QUERY_DESC_CONFIGURAION_MAX_SIZE 0xE2 +#define UFSF_QUERY_DESC_UNIT_MAX_SIZE 0x2D +#define UFSF_QUERY_DESC_GEOMETRY_MAX_SIZE 0x58 + +#define UFSFEATURE_SELECTOR 0x01 + +/* Extended UFS Feature Support */ +#define UFSF_EFS_TURBO_WRITE 0x100 + +/* query_flag */ +#define MASK_QUERY_UPIU_FLAG_LOC 0xFF + +/* BIG -> LI */ +#define LI_EN_16(x) be16_to_cpu(*(__be16 *)(x)) +#define LI_EN_32(x) be32_to_cpu(*(__be32 *)(x)) +#define LI_EN_64(x) be64_to_cpu(*(__be64 *)(x)) + +/* LI -> BIG */ +#define GET_BYTE_0(num) (((num) >> 0) & 0xff) +#define GET_BYTE_1(num) (((num) >> 8) & 0xff) +#define GET_BYTE_2(num) (((num) >> 16) & 0xff) +#define GET_BYTE_3(num) (((num) >> 24) & 0xff) +#define GET_BYTE_4(num) (((num) >> 32) & 0xff) +#define GET_BYTE_5(num) (((num) >> 40) & 0xff) +#define GET_BYTE_6(num) (((num) >> 48) & 0xff) +#define GET_BYTE_7(num) (((num) >> 56) & 0xff) + +#define INFO_MSG(msg, args...) printk(KERN_INFO "%s:%d " msg "\n", \ + __func__, __LINE__, ##args) +#define INIT_INFO(msg, args...) INFO_MSG(msg, ##args) +#define RELEASE_INFO(msg, args...) INFO_MSG(msg, ##args) +#define SYSFS_INFO(msg, args...) INFO_MSG(msg, ##args) +#define ERR_MSG(msg, args...) printk(KERN_ERR "%s:%d " msg "\n", \ + __func__, __LINE__, ##args) +#define WARNING_MSG(msg, args...) printk(KERN_WARNING "%s:%d " msg "\n", \ + __func__, __LINE__, ##args) + +#define seq_scan_lu(lun) for (lun = 0; lun < UFS_UPIU_MAX_GENERAL_LUN; lun++) + +#define TMSG(ufsf, lun, msg, args...) \ + do { if (ufsf->sdev_ufs_lu[lun] && \ + ufsf->sdev_ufs_lu[lun]->request_queue) \ + blk_add_trace_msg( \ + ufsf->sdev_ufs_lu[lun]->request_queue, \ + msg, ##args); \ + } while (0) \ + +struct ufsf_lu_desc { + /* Common info */ + int lu_enable; /* 03h bLUEnable */ + int lu_queue_depth; /* 06h lu queue depth info*/ + int lu_logblk_size; /* 0Ah bLogicalBlockSize. default 0x0C = 4KB */ + u64 lu_logblk_cnt; /* 0Bh qLogicalBlockCount. */ + +#if defined(CONFIG_UFSHPB) + u16 lu_max_active_hpb_rgns; /* 23h:24h wLUMaxActiveHPBRegions */ + u16 lu_hpb_pinned_rgn_startidx; /* 25h:26h wHPBPinnedRegionStartIdx */ + u16 lu_num_hpb_pinned_rgns; /* 27h:28h wNumHPBPinnedRegions */ + int lu_hpb_pinned_end_offset; +#endif +#if defined(CONFIG_UFSTW) + unsigned int tw_lu_buf_size; +#endif +}; + +struct ufsf_feature { + struct ufs_hba *hba; + int num_lu; + int slave_conf_cnt; + struct scsi_device *sdev_ufs_lu[UFS_UPIU_MAX_GENERAL_LUN]; +#if defined(CONFIG_UFSHPB) + struct ufshpb_dev_info hpb_dev_info; + struct ufshpb_lu *ufshpb_lup[UFS_UPIU_MAX_GENERAL_LUN]; + struct work_struct ufshpb_init_work; + struct work_struct ufshpb_reset_work; + struct work_struct ufshpb_eh_work; + wait_queue_head_t wait_hpb; + int ufshpb_state; + struct kref ufshpb_kref; + bool issue_ioctl; +#endif +#if defined(CONFIG_UFSTW) + struct ufstw_dev_info tw_dev_info; + struct ufstw_lu *tw_lup[UFS_UPIU_MAX_GENERAL_LUN]; + struct work_struct tw_init_work; + struct delayed_work tw_reset_work; + wait_queue_head_t tw_wait; + atomic_t tw_state; + struct kref tw_kref; + + /* turbo write exception event control */ + bool tw_ee_mode; + + /* for debug */ + bool tw_debug; +#endif +}; + +struct ufs_hba; +struct ufshcd_lrb; + +int is_samsung_feature(struct ufs_hba *hba); +void ufsf_device_check(struct ufs_hba *hba); +int ufsf_check_query(__u32 opcode); +int ufsf_query_ioctl(struct ufsf_feature *ufsf, int lun, void __user *buffer, + struct ufs_ioctl_query_data *ioctl_data, + u8 selector); +int ufsf_query_flag_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, u8 idx, bool *flag_res); +int ufsf_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 idx, u32 *attr_val); +bool ufsf_is_valid_lun(int lun); +int ufsf_get_ee_status(struct ufs_hba *hba, u32 *status); + +/* for hpb */ +int ufsf_hpb_prepare_pre_req(struct ufsf_feature *ufsf, struct scsi_cmnd *cmd, + int lun); +int ufsf_hpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag); +void ufsf_hpb_end_pre_req(struct ufsf_feature *ufsf, struct request *req); +void ufsf_hpb_change_lun(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_hpb_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_hpb_noti_rb(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_hpb_reset_lu(struct ufsf_feature *ufsf); +void ufsf_hpb_reset_host(struct ufsf_feature *ufsf); +void ufsf_hpb_init(struct ufsf_feature *ufsf); +void ufsf_hpb_reset(struct ufsf_feature *ufsf); +void ufsf_hpb_suspend(struct ufsf_feature *ufsf); +void ufsf_hpb_resume(struct ufsf_feature *ufsf); +void ufsf_hpb_release(struct ufsf_feature *ufsf); +void ufsf_hpb_set_init_state(struct ufsf_feature *ufsf); + +/* for tw*/ +void ufsf_tw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufsf_tw_init(struct ufsf_feature *ufsf); +void ufsf_tw_reset(struct ufsf_feature *ufsf); +int ufsf_tw_check_flush(struct ufsf_feature *ufsf); +void ufsf_tw_suspend(struct ufsf_feature *ufsf); +void ufsf_tw_resume(struct ufsf_feature *ufsf); +void ufsf_tw_release(struct ufsf_feature *ufsf); +void ufsf_tw_set_init_state(struct ufsf_feature *ufsf); +void ufsf_tw_reset_lu(struct ufsf_feature *ufsf); +void ufsf_tw_reset_host(struct ufsf_feature *ufsf); +void ufsf_tw_ee_handler(struct ufsf_feature *ufsf); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 23a04274d21ceb630cebb58162b402d2dd2132d9..d70cfdf89c69c4a1dd82ed5b60f7207d0b13ce55 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -50,6 +50,8 @@ #include "ufs-sysfs.h" #include "ufs-debugfs.h" #include "ufs-qcom.h" +#include +#include static bool ufshcd_wb_sup(struct ufs_hba *hba); static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable); @@ -58,6 +60,181 @@ static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba); static bool ufshcd_wb_is_buf_flush_needed(struct ufs_hba *hba); static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set); +/* ufs slot status */ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +unsigned long ufs_outstanding; +#endif + +static int err_state; +static void ufsproc_set_err_state(struct ufs_hba *hba) +{ + err_state = true; +} + +static int proc_err_state_show(struct seq_file *file, void *data) +{ + seq_printf(file, "%d\n", err_state); + + return 0; +} + +static int proc_err_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_err_state_show, inode->i_private); +} + +static const struct file_operations proc_err_state_fops = { + .open = proc_err_state_open, + .read = seq_read, +}; + +static int proc_show_hba_show(struct seq_file *file, void *data) +{ + struct ufs_hba *hba = PDE_DATA(file_inode(file->file)); + + seq_printf(file, "hba->outstanding_tasks = 0x%x\n", + (u32)hba->outstanding_tasks); + seq_printf(file, "hba->outstanding_reqs = 0x%x\n", + (u32)hba->outstanding_reqs); + + seq_printf(file, "hba->capabilities = 0x%x\n", hba->capabilities); + seq_printf(file, "hba->nutrs = %d\n", hba->nutrs); + seq_printf(file, "hba->nutmrs = %d\n", hba->nutmrs); + seq_printf(file, "hba->ufs_version = 0x%x\n", hba->ufs_version); + seq_printf(file, "hba->irq = 0x%x\n", hba->irq); + seq_printf(file, "hba->auto_bkops_enabled = %d\n", + hba->auto_bkops_enabled); + + seq_printf(file, "hba->ufshcd_state = 0x%x\n", hba->ufshcd_state); + seq_printf(file, "hba->clk_gating.state = 0x%x\n", + hba->clk_gating.state); + seq_printf(file, "hba->eh_flags = 0x%x\n", hba->eh_flags); + seq_printf(file, "hba->intr_mask = 0x%x\n", hba->intr_mask); + seq_printf(file, "hba->ee_ctrl_mask = 0x%x\n", hba->ee_ctrl_mask); + + /* HBA Errors */ + seq_printf(file, "hba->errors = 0x%x\n", hba->errors); + seq_printf(file, "hba->uic_error = 0x%x\n", hba->uic_error); + seq_printf(file, "hba->saved_err = 0x%x\n", hba->saved_err); + seq_printf(file, "hba->saved_uic_err = 0x%x\n", hba->saved_uic_err); + + seq_printf(file, "power_mode_change_cnt = %d\n", + hba->ufs_stats.power_mode_change_cnt); + seq_printf(file, "hibern8_exit_cnt = %d\n", + hba->ufs_stats.hibern8_exit_cnt); + + seq_printf(file, "pa_err_cnt_total = %d\n", + hba->ufs_stats.pa_err_cnt_total); + seq_printf(file, "pa_lane_0_err_cnt = %d\n", + hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LANE_0]); + seq_printf(file, "pa_lane_1_err_cnt = %d\n", + hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LANE_1]); + seq_printf(file, "pa_line_reset_err_cnt = %d\n", + hba->ufs_stats.pa_err_cnt[UFS_EC_PA_LINE_RESET]); + seq_printf(file, "dl_err_cnt_total = %d\n", + hba->ufs_stats.dl_err_cnt_total); + seq_printf(file, "dl_nac_received_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_NAC_RECEIVED]); + seq_printf(file, "dl_tcx_replay_timer_expired_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_TCx_REPLAY_TIMER_EXPIRED]); + seq_printf(file, "dl_afcx_request_timer_expired_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_AFCx_REQUEST_TIMER_EXPIRED]); + seq_printf(file, "dl_fcx_protection_timer_expired_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_FCx_PROTECT_TIMER_EXPIRED]); + seq_printf(file, "dl_crc_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_CRC_ERROR]); + seq_printf(file, "dll_rx_buffer_overflow_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_RX_BUFFER_OVERFLOW]); + seq_printf(file, "dl_max_frame_length_exceeded_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_MAX_FRAME_LENGTH_EXCEEDED]); + seq_printf(file, "dl_wrong_sequence_number_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_WRONG_SEQUENCE_NUMBER]); + seq_printf(file, "dl_afc_frame_syntax_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_AFC_FRAME_SYNTAX_ERROR]); + seq_printf(file, "dl_nac_frame_syntax_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_NAC_FRAME_SYNTAX_ERROR]); + seq_printf(file, "dl_eof_syntax_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_EOF_SYNTAX_ERROR]); + seq_printf(file, "dl_frame_syntax_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_FRAME_SYNTAX_ERROR]); + seq_printf(file, "dl_bad_ctrl_symbol_type_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_BAD_CTRL_SYMBOL_TYPE]); + seq_printf(file, "dl_pa_init_err_cnt = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_PA_INIT_ERROR]); + seq_printf(file, "dl_pa_error_ind_received = %d\n", + hba->ufs_stats.dl_err_cnt[UFS_EC_DL_PA_ERROR_IND_RECEIVED]); + seq_printf(file, "dme_err_cnt = %d\n", hba->ufs_stats.dme_err_cnt); + + return 0; +} + +static int proc_show_hba_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_show_hba_show, inode->i_private); +} + +static const struct file_operations proc_show_hba_fops = { + .open = proc_show_hba_open, + .read = seq_read, +}; + +static void ufs_add_procfs(struct ufs_hba *hba) +{ + struct proc_dir_entry *pdentry, *de; + + if (!hba) { + pr_err("%s: NULL hba, exiting\n", __func__); + return; + } + + pdentry = proc_mkdir(dev_name(hba->dev), + NULL); + + if (IS_ERR(pdentry)) + /* Don't complain -- procfs just isn't enabled */ + goto err_no_root; + if (!pdentry) { + /* + * Complain -- procfs is enabled, but it failed to + * create the directory + */ + dev_err(hba->dev, + "%s: NULL procfs root directory, exiting\n", __func__); + goto err_no_root; + } + + de = proc_create("err_state", 0400, + pdentry, &proc_err_state_fops); + if (!de) { + dev_err(hba->dev, "%s: failed to create err_state in procfs\n", + __func__); + goto err; + } + + de = proc_create_data("show_hba", 0400, + pdentry, &proc_show_hba_fops, hba); + if (!de) { + dev_err(hba->dev, "%s: failed to create show_hba in procfs\n", + __func__); + goto err_state; + } + + return; + +err_state: + remove_proc_entry("err_state", pdentry); +err: + remove_proc_entry(dev_name(hba->dev), NULL); + pdentry = NULL; +err_no_root: + dev_err(hba->dev, "%s: failed to initialize procfs\n", __func__); +} + +static void ufs_remove_procfs(struct ufs_hba *hba) +{ + remove_proc_entry(dev_name(hba->dev), NULL); +} + #ifdef CONFIG_DEBUG_FS static int ufshcd_tag_req_type(struct request *rq) @@ -80,6 +257,7 @@ static int ufshcd_tag_req_type(struct request *rq) static void ufshcd_update_error_stats(struct ufs_hba *hba, int type) { ufsdbg_set_err_state(hba); + ufsproc_set_err_state(hba); if (type < UFS_ERR_MAX) hba->ufs_stats.err_stats[type]++; } @@ -483,8 +661,16 @@ static int ufshcd_disable_clocks(struct ufs_hba *hba, bool is_gating_context); static int ufshcd_disable_clocks_keep_link_active(struct ufs_hba *hba, bool is_gating_context); +#if defined(CONFIG_UFSFEATURE) +void ufshcd_hold_all(struct ufs_hba *hba); +#else static void ufshcd_hold_all(struct ufs_hba *hba); +#endif +#if defined(CONFIG_UFSFEATURE) +void ufshcd_release_all(struct ufs_hba *hba); +#else static void ufshcd_release_all(struct ufs_hba *hba); +#endif static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused); static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba); static inline void ufshcd_save_tstamp_of_last_dme_cmd(struct ufs_hba *hba); @@ -492,8 +678,6 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba); static void ufshcd_resume_clkscaling(struct ufs_hba *hba); static void ufshcd_suspend_clkscaling(struct ufs_hba *hba); static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba); -static void ufshcd_hold_all(struct ufs_hba *hba); -static void ufshcd_release_all(struct ufs_hba *hba); static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba); static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba); static int ufshcd_devfreq_target(struct device *dev, @@ -2657,7 +2841,11 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) * * Return 0 on success, non-zero on failure. */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async) +#else static int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async) +#endif { int rc = 0; unsigned long flags; @@ -2993,13 +3181,21 @@ static void ufshcd_exit_hibern8_on_idle(struct ufs_hba *hba) device_remove_file(hba->dev, &hba->hibern8_on_idle.enable_attr); } +#if defined (CONFIG_UFSFEATURE) +void ufshcd_hold_all(struct ufs_hba *hba) +#else static void ufshcd_hold_all(struct ufs_hba *hba) +#endif { ufshcd_hold(hba, false); ufshcd_hibern8_hold(hba, false); } +#if defined (CONFIG_UFSFEATURE) +void ufshcd_release_all(struct ufs_hba *hba) +#else static void ufshcd_release_all(struct ufs_hba *hba) +#endif { ufshcd_hibern8_release(hba, false); ufshcd_release(hba, false); @@ -3216,8 +3412,10 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) else ret = -ETIMEDOUT; - if (ret) + if (ret) { ufsdbg_set_err_state(hba); + ufsproc_set_err_state(hba); + } ufshcd_dme_cmd_log(hba, "dme_cmpl_1", hba->active_uic_cmd->command); @@ -3298,7 +3496,11 @@ ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) * * Returns 0 in case of success, non-zero value in case of failure */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#else static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#endif { struct ufshcd_sg_entry *prd; struct scatterlist *sg; @@ -3569,7 +3771,11 @@ static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * @hba: per adapter instance * @lrbp: pointer to local reference block */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#else static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) +#endif { u32 upiu_flags; int ret = 0; @@ -3581,6 +3787,11 @@ static int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) lrbp->command_type = UTP_CMD_TYPE_UFS_STORAGE; if (likely(lrbp->cmd)) { +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_change_lun(&hba->ufsf, lrbp); + ufsf_tw_prep_fn(&hba->ufsf, lrbp); + ufsf_hpb_prep_fn(&hba->ufsf, lrbp); +#endif ret = ufshcd_prepare_req_desc_hdr(hba, lrbp, &upiu_flags, lrbp->cmd->sc_data_direction); ufshcd_prepare_utp_scsi_cmd_upiu(lrbp, upiu_flags); @@ -3672,6 +3883,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) int tag; int err = 0; bool has_read_lock = false; +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + struct scsi_cmnd *pre_cmd; + struct ufshcd_lrb *add_lrbp; + int add_tag; + int pre_req_err = -EBUSY; + int lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun); +#endif hba = shost_priv(host); @@ -3782,6 +4000,27 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) if (ufshcd_is_hibern8_on_idle_allowed(hba)) WARN_ON(hba->hibern8_on_idle.state != HIBERN8_EXITED); +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + add_tag = ufsf_hpb_prepare_pre_req(&hba->ufsf, cmd, lun); + if (add_tag == -EAGAIN) { + clear_bit_unlock(tag, &hba->lrb_in_use); + err = SCSI_MLQUEUE_HOST_BUSY; + ufshcd_release_all(hba); + goto out; + } + + if (add_tag < 0) { + hba->lrb[tag].hpb_ctx_id = MAX_HPB_CONTEXT_ID; + goto send_orig_cmd; + } + + add_lrbp = &hba->lrb[add_tag]; + + pre_req_err = ufsf_hpb_prepare_add_lrbp(&hba->ufsf, add_tag); + if (pre_req_err) + hba->lrb[tag].hpb_ctx_id = MAX_HPB_CONTEXT_ID; +send_orig_cmd: +#endif /* Vote PM QoS for the request */ ufshcd_vops_pm_qos_req_start(hba, cmd->request); @@ -3834,9 +4073,24 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) /* issue command to the controller */ spin_lock_irqsave(hba->host->host_lock, flags); +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + if (!pre_req_err) { + ufshcd_vops_setup_xfer_req(hba, add_tag, (add_lrbp->cmd ? true : false)); + ufshcd_send_command(hba, add_tag); + pre_req_err = -EBUSY; + atomic64_inc(&hba->ufsf.ufshpb_lup[add_lrbp->lun]->pre_req_cnt); + } +#endif ufshcd_vops_setup_xfer_req(hba, tag, (lrbp->cmd ? true : false)); err = ufshcd_send_command(hba, tag); + +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /* Add for monitor ufs driver io time */ + ufs_outstanding = hba->outstanding_reqs; + cmd->request->ufs_io_start = ktime_get(); +#endif + if (err) { spin_unlock_irqrestore(hba->host->host_lock, flags); scsi_dma_unmap(lrbp->cmd); @@ -3853,6 +4107,18 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) out_unlock: spin_unlock_irqrestore(hba->host->host_lock, flags); out: +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + if (!pre_req_err) { + pre_cmd = add_lrbp->cmd; + scsi_dma_unmap(pre_cmd); + add_lrbp->cmd = NULL; + clear_bit_unlock(add_tag, &hba->lrb_in_use); + ufshcd_release_all(hba); + ufshcd_vops_pm_qos_req_end(hba, pre_cmd->request, true); + ufshcd_complete_lrbp_crypto(hba, pre_cmd, add_lrbp); + ufsf_hpb_end_pre_req(&hba->ufsf, pre_cmd->request); + } +#endif if (has_read_lock) ufshcd_put_read_lock(hba); return err; @@ -3988,8 +4254,10 @@ static int ufshcd_wait_for_dev_cmd(struct ufs_hba *hba, ufshcd_outstanding_req_clear(hba, lrbp->task_tag); } - if (err) + if (err) { ufsdbg_set_err_state(hba); + ufsproc_set_err_state(hba); + } return err; } @@ -4041,8 +4309,13 @@ static inline void ufshcd_put_dev_cmd_tag(struct ufs_hba *hba, int tag) * NOTE: Since there is only one available tag for device management commands, * it is expected you hold the hba->dev_cmd.lock mutex. */ +#if defined(CONFIG_UFSFEATURE) +int ufshcd_exec_dev_cmd(struct ufs_hba *hba, + enum dev_cmd_type cmd_type, int timeout) +#else static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, int timeout) +#endif { struct ufshcd_lrb *lrbp; int err; @@ -4616,6 +4889,120 @@ int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); } +int ufshcd_read_geometry_desc(struct ufs_hba *hba, u8 *buf, u32 size) +{ + return ufshcd_read_desc(hba, QUERY_DESC_IDN_GEOMETRY, 0, buf, size); +} + +static int ufs_get_capacity_info(struct ufs_hba *hba, u64 *pcapacity) +{ + int err; + u8 geometry_buf[QUERY_DESC_GEOMETRY_DEF_SIZE]; + + err = ufshcd_read_geometry_desc(hba, geometry_buf, + QUERY_DESC_GEOMETRY_DEF_SIZE); + + if (err) + goto out; + + *pcapacity = (u64)geometry_buf[0x04] << 56 | + (u64)geometry_buf[0x04 + 1] << 48 | + (u64)geometry_buf[0x04 + 2] << 40 | + (u64)geometry_buf[0x04 + 3] << 32 | + (u64)geometry_buf[0x04 + 4] << 24 | + (u64)geometry_buf[0x04 + 5] << 16 | + (u64)geometry_buf[0x04 + 6] << 8 | + (u64)geometry_buf[0x04 + 7]; + + +out: + return err; +} + +static char *ufs_get_capacity_size(u64 capacity) +{ + if (capacity == 0x1D62000) { //16G + return "16G"; + } else if (capacity == 0x3B9E000) { //32G + return "32G"; + } else if (capacity == 0x7734000) { //64G + return "64G"; + } else if (capacity == 0xEE60000) { //128G + return "128G"; + } else if (capacity == 0xEE64000) { //128G V4 + return "128G"; + } else if (capacity == 0x1DCBC000) { + return "256G"; + } else { + return "0G"; + } +} + +char ufs_vendor_and_rev[32] = {'\0'}; +char ufs_product_id[32] = {'\0'}; +int ufs_fill_info(struct ufs_hba *hba) +{ + int err = 0; + u64 ufs_capacity = 0; + char ufs_vendor[9] = {'\0'}; + char ufs_rev[6] = {'\0'}; + + /* Error Handle: Before filling ufs info, we must confirm sdev_ufs_device structure is not NULL*/ + if (!hba->sdev_ufs_device) { + dev_err(hba->dev, "%s:hba->sdev_ufs_device is NULL!\n", __func__); + goto out; + } + + /* Copy UFS info from host controller structure (ex:vendor name, firmware revision) */ + if (!hba->sdev_ufs_device->vendor) { + dev_err(hba->dev, "%s: UFS vendor info is NULL\n", __func__); + strlcpy(ufs_vendor, "UNKNOWN", 7); + } else { + strlcpy(ufs_vendor, hba->sdev_ufs_device->vendor, + sizeof(ufs_vendor)-1); + } + + if (!hba->sdev_ufs_device->rev) { + dev_err(hba->dev, "%s: UFS firmware info is NULL\n", __func__); + strlcpy(ufs_rev, "NONE", 4); + } else { + strlcpy(ufs_rev, hba->sdev_ufs_device->rev, sizeof(ufs_rev)-1); + } + + if (!hba->sdev_ufs_device->model) { + dev_err(hba->dev, "%s: UFS product id info is NULL\n", __func__); + strlcpy(ufs_product_id, "UNKNOWN", 7); + } else { + strlcpy(ufs_product_id, hba->sdev_ufs_device->model, 11); + strlcat(ufs_product_id, "_", sizeof(ufs_product_id)); + if (hba->ufsf.ufshpb_lup[0]) + strlcat(ufs_product_id, "H", sizeof(ufs_product_id)); + if (hba->ufsf.tw_lup[0]) + strlcat(ufs_product_id, "T ", sizeof(ufs_product_id)); + } + + /* Get UFS storage size*/ + err = ufs_get_capacity_info(hba, &ufs_capacity); + if (err) { + dev_err(hba->dev, "%s: Failed getting capacity info\n", __func__); + goto out; + } + + /* Combine vendor name with firmware revision */ + strlcat(ufs_vendor_and_rev, ufs_vendor, sizeof(ufs_vendor_and_rev)); + if (strncmp(ufs_vendor, "MICRON", 6) != 0) { + strlcat(ufs_vendor_and_rev, " ", sizeof(ufs_vendor_and_rev)); + strlcat(ufs_vendor_and_rev, ufs_get_capacity_size(ufs_capacity), sizeof(ufs_vendor_and_rev)); + } + strlcat(ufs_vendor_and_rev, " ", sizeof(ufs_vendor_and_rev)); + strlcat(ufs_vendor_and_rev, ufs_rev, sizeof(ufs_vendor_and_rev)); + + push_component_info(UFS, ufs_product_id, ufs_vendor_and_rev); +out: + return err; + +} + /** * ufshcd_read_string_desc - read string descriptor * @hba: pointer to adapter instance @@ -5208,6 +5595,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) out: if (ret) { ufsdbg_set_err_state(hba); + ufsproc_set_err_state(hba); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); ufshcd_print_host_regs(hba); @@ -5686,9 +6074,11 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba) } /* poll for max. 1000 iterations for fDeviceInit flag to clear */ - for (i = 0; i < 1000 && !err && flag_res; i++) + for (i = 0; i < 1500 && !err && flag_res; i++) { err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, QUERY_FLAG_IDN_FDEVICEINIT, &flag_res); + usleep_range(1000, 1100); // 1ms sleep + } if (err) dev_err(hba->dev, @@ -6194,7 +6584,16 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) { struct ufs_hba *hba = shost_priv(sdev->host); struct request_queue *q = sdev->request_queue; +#if defined(CONFIG_UFSFEATURE) + struct ufsf_feature *ufsf = &hba->ufsf; + if (ufsf_is_valid_lun(sdev->lun)) { + ufsf->sdev_ufs_lu[sdev->lun] = sdev; + ufsf->slave_conf_cnt++; + printk(KERN_ERR "%s: ufsfeature set lun %d sdev %p q %p\n", + __func__, (int)sdev->lun, sdev, sdev->request_queue); + } +#endif blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX); @@ -6367,6 +6766,11 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) &hba->eeh_work)) pm_runtime_get_noresume(hba->dev); } + +#if defined(CONFIG_UFSFEATURE) + if (scsi_status == SAM_STAT_GOOD) + ufsf_hpb_noti_rb(&hba->ufsf, lrbp); +#endif break; case UPIU_TRANSACTION_REJECT_UPIU: /* TODO: handle Reject UPIU Response */ @@ -6419,8 +6823,10 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) } if ((host_byte(result) == DID_ERROR) || - (host_byte(result) == DID_ABORT)) + (host_byte(result) == DID_ABORT)) { ufsdbg_set_err_state(hba); + ufsproc_set_err_state(hba); + } return result; } @@ -6531,6 +6937,13 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, __ufshcd_release(hba, false); __ufshcd_hibern8_release(hba, false); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /* add latency_hist node for ufs latency calculate in sysfs. */ + if (cmd->request) + cmd->request->flash_io_latency = ktime_us_delta(ktime_get(), + cmd->request->ufs_io_start); +#endif + /* Do not touch lrbp after scsi done */ cmd->scsi_done(cmd); } else if (lrbp->command_type == UTP_CMD_TYPE_DEV_MANAGE || @@ -6671,14 +7084,19 @@ static int ufshcd_disable_ee(struct ufs_hba *hba, u16 mask) { int err = 0; u32 val; + int sel = 0; if (!(hba->ee_ctrl_mask & mask)) goto out; val = hba->ee_ctrl_mask & ~mask; val &= MASK_EE_STATUS; +#ifdef CONFIG_UFSFEATURE + if (is_samsung_feature(hba)) + sel = 1; +#endif err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val); + QUERY_ATTR_IDN_EE_CONTROL, 0, sel, &val); if (!err) hba->ee_ctrl_mask &= ~mask; out: @@ -6699,14 +7117,19 @@ static int ufshcd_enable_ee(struct ufs_hba *hba, u16 mask) { int err = 0; u32 val; + int sel = 0; if (hba->ee_ctrl_mask & mask) goto out; val = hba->ee_ctrl_mask | mask; val &= MASK_EE_STATUS; +#ifdef CONFIG_UFSFEATURE + if (is_samsung_feature(hba)) + sel = 1; +#endif err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, - QUERY_ATTR_IDN_EE_CONTROL, 0, 0, &val); + QUERY_ATTR_IDN_EE_CONTROL, 0, sel, &val); if (!err) hba->ee_ctrl_mask |= mask; out: @@ -7111,6 +7534,9 @@ static void ufshcd_exception_event_handler(struct work_struct *work) if (status & MASK_EE_URGENT_BKOPS) ufshcd_bkops_exception_event_handler(hba); +#if defined(CONFIG_UFSFEATURE) + ufsf_tw_ee_handler(&hba->ufsf); +#endif out: ufshcd_scsi_unblock_requests(hba); /* @@ -7243,6 +7669,7 @@ static void ufshcd_err_handler(struct work_struct *work) spin_lock_irqsave(hba->host->host_lock, flags); ufsdbg_set_err_state(hba); + ufsproc_set_err_state(hba); if (hba->ufshcd_state == UFSHCD_STATE_RESET) goto out; @@ -7905,6 +8332,10 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) out: hba->req_abort_count = 0; if (!err) { +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_reset_lu(&hba->ufsf); + ufsf_tw_reset_lu(&hba->ufsf); +#endif err = SUCCESS; } else { dev_err(hba->dev, "%s: failed with err %d\n", __func__, err); @@ -8133,6 +8564,10 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) ufshcd_hba_stop(hba, false); hba->silence_err_logs = true; ufshcd_complete_requests(hba); +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_reset_host(&hba->ufsf); + ufsf_tw_reset_host(&hba->ufsf); +#endif hba->silence_err_logs = false; spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -9196,6 +9631,11 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) } scsi_scan_host(hba->host); +#if defined(CONFIG_UFSFEATURE) + ufsf_device_check(hba); + ufsf_hpb_init(&hba->ufsf); + ufsf_tw_init(&hba->ufsf); +#endif pm_runtime_put_sync(hba->dev); } @@ -9215,9 +9655,18 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) ufshcd_hba_exit(hba); } +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_reset(&hba->ufsf); + ufsf_tw_reset(&hba->ufsf); +#endif + trace_ufshcd_init(dev_name(hba->dev), ret, ktime_to_us(ktime_sub(ktime_get(), start)), hba->curr_dev_pwr_mode, hba->uic_link_state); + + if (!ret) + ufs_fill_info(hba); + return ret; } @@ -9312,6 +9761,14 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) goto out_release_mem; } +#if defined(CONFIG_UFSFEATURE) + if (ufsf_check_query(ioctl_data->opcode)) { + err = ufsf_query_ioctl(&hba->ufsf, lun, buffer, ioctl_data, + UFSFEATURE_SELECTOR); + goto out_release_mem; + } +#endif + /* verify legal parameters & send query */ switch (ioctl_data->opcode) { case UPIU_QUERY_OPCODE_READ_DESC: @@ -10371,6 +10828,11 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto out; +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_suspend(&hba->ufsf); + ufsf_tw_suspend(&hba->ufsf); +#endif + /* * If we can't transition into any of the low power modes * just gate the clocks. @@ -10501,6 +10963,11 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) hba->clk_gating.is_suspended = false; ufshcd_release_all(hba); ufshcd_crypto_resume(hba, pm_op); + +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_resume(&hba->ufsf); + ufsf_tw_resume(&hba->ufsf); +#endif out: hba->pm_op_in_progress = 0; @@ -10624,6 +11091,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_resume(&hba->ufsf); + ufsf_tw_resume(&hba->ufsf); +#endif + /* Set Auto-Hibernate timer if supported */ ufshcd_set_auto_hibern8_timer(hba); @@ -10903,6 +11375,10 @@ EXPORT_SYMBOL(ufshcd_shutdown); */ void ufshcd_remove(struct ufs_hba *hba) { +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_release(&hba->ufsf); + ufsf_tw_release(&hba->ufsf); +#endif ufs_sysfs_remove_nodes(hba->dev); scsi_remove_host(hba->host); /* disable interrupts */ @@ -10919,6 +11395,7 @@ void ufshcd_remove(struct ufs_hba *hba) } ufshcd_hba_exit(hba); ufsdbg_remove_debugfs(hba); + ufs_remove_procfs(hba); } EXPORT_SYMBOL_GPL(ufshcd_remove); @@ -11196,9 +11673,14 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_cmd_log_init(hba); +#if defined(CONFIG_UFSFEATURE) + ufsf_hpb_set_init_state(&hba->ufsf); + ufsf_tw_set_init_state(&hba->ufsf); +#endif async_schedule(ufshcd_async_scan, hba); ufsdbg_add_debugfs(hba); + ufs_add_procfs(hba); ufs_sysfs_add_nodes(hba->dev); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 2a6b30d8e6635e0bdcda9ba59ea4a0be378133cb..a5efa2189fc502462e90c04700a213dd9fe461d3 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -76,6 +76,10 @@ #include "ufs.h" #include "ufshci.h" +#if defined(CONFIG_UFSFEATURE) +#include "ufsfeature.h" +#endif + #define UFSHCD "ufshcd" #define UFSHCD_DRIVER_VERSION "0.3" @@ -231,6 +235,10 @@ struct ufshcd_lrb { #endif /* CONFIG_SCSI_UFS_CRYPTO */ bool req_abort_skip; + +#if defined(CONFIG_UFSFEATURE) && defined(CONFIG_UFSHPB) + int hpb_ctx_id; +#endif }; /** @@ -1102,6 +1110,10 @@ struct ufs_hba { bool phy_init_g4; bool force_g4; + +#if defined(CONFIG_UFSFEATURE) + struct ufsf_feature ufsf; +#endif bool wb_enabled; #ifdef CONFIG_SCSI_UFS_CRYPTO @@ -1393,6 +1405,15 @@ u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba); void ufshcd_scsi_block_requests(struct ufs_hba *hba); void ufshcd_scsi_unblock_requests(struct ufs_hba *hba); +#if defined(CONFIG_UFSFEATURE) +int ufshcd_exec_dev_cmd(struct ufs_hba *hba, + enum dev_cmd_type cmd_type, int timeout); +int ufshcd_hibern8_hold(struct ufs_hba *hba, bool async); +void ufshcd_hold_all(struct ufs_hba *hba); +void ufshcd_release_all(struct ufs_hba *hba); +int ufshcd_comp_scsi_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); +int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp); +#endif /* Wrapper functions for safely calling variant operations */ static inline const char *ufshcd_get_var_name(struct ufs_hba *hba) diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c new file mode 100644 index 0000000000000000000000000000000000000000..a1e46739bbdc6568cfbc27b347a370f5f7675d43 --- /dev/null +++ b/drivers/scsi/ufs/ufshpb.c @@ -0,0 +1,3688 @@ +/* + * Universal Flash Storage Host Performance Booster + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * 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. + * See the COPYING file in the top-level directory or visit + * + * + * 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. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include "ufshcd.h" +#include "ufshpb.h" +#include "ufshcd-crypto.h" + +#define UFSHCD_REQ_SENSE_SIZE 18 + +/* + * define global constants + */ +static int sects_per_blk_shift; +static int bits_per_dword_shift; +static int bits_per_dword_mask; +static int bits_per_byte_shift; + +static int ufshpb_create_sysfs(struct ufsf_feature *ufsf, + struct ufshpb_lu *hpb); +static int ufshpb_remove_sysfs(struct ufshpb_lu *hpb); + +static inline void +ufshpb_get_pos_from_lpn(struct ufshpb_lu *hpb, unsigned long lpn, int *rgn_idx, + int *srgn_idx, int *offset) +{ + int rgn_offset; + + *rgn_idx = lpn >> hpb->entries_per_rgn_shift; + rgn_offset = lpn & hpb->entries_per_rgn_mask; + *srgn_idx = rgn_offset >> hpb->entries_per_srgn_shift; + *offset = rgn_offset & hpb->entries_per_srgn_mask; +} + +inline int ufshpb_valid_srgn(struct ufshpb_region *rgn, + struct ufshpb_subregion *srgn) +{ + return rgn->rgn_state != HPBREGION_INACTIVE && + srgn->srgn_state == HPBSUBREGION_CLEAN; +} + +/* Must be held hpb_lock */ +static bool ufshpb_ppn_dirty_check(struct ufshpb_lu *hpb, unsigned long lpn, + int transfer_len) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + unsigned long cur_lpn = lpn; + int rgn_idx, srgn_idx, srgn_offset, find_size; + int scan_cnt = transfer_len; + + do { + ufshpb_get_pos_from_lpn(hpb, cur_lpn, &rgn_idx, &srgn_idx, + &srgn_offset); + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + if (!ufshpb_valid_srgn(rgn, srgn)) + return true; + + if (!srgn->mctx || !srgn->mctx->ppn_dirty) + return true; + + if (hpb->entries_per_srgn < srgn_offset + scan_cnt) { + find_size = hpb->entries_per_srgn - srgn_offset; + scan_cnt -= find_size; + } else { + find_size = srgn_offset + scan_cnt; + scan_cnt = 0; + } + + srgn_offset = + find_next_bit((unsigned long *)srgn->mctx->ppn_dirty, + hpb->entries_per_srgn, srgn_offset); + + if (srgn_offset < hpb->entries_per_srgn) + return srgn_offset < find_size; + + cur_lpn += find_size; + } while (scan_cnt); + + return false; +} + +static void ufshpb_set_read16_cmd(struct ufshpb_lu *hpb, + struct ufshcd_lrb *lrbp, + unsigned long long ppn, + unsigned int transfer_len) +{ + unsigned char *cdb = lrbp->cmd->cmnd; + + cdb[0] = READ_16; + cdb[2] = lrbp->cmd->cmnd[2]; + cdb[3] = lrbp->cmd->cmnd[3]; + cdb[4] = lrbp->cmd->cmnd[4]; + cdb[5] = lrbp->cmd->cmnd[5]; + cdb[6] = GET_BYTE_7(ppn); + cdb[7] = GET_BYTE_6(ppn); + cdb[8] = GET_BYTE_5(ppn); + cdb[9] = GET_BYTE_4(ppn); + cdb[10] = GET_BYTE_3(ppn); + cdb[11] = GET_BYTE_2(ppn); + cdb[12] = GET_BYTE_1(ppn); + cdb[13] = GET_BYTE_0(ppn); + + if (lrbp->hpb_ctx_id < MAX_HPB_CONTEXT_ID) + cdb[14] = (1 << 7) | lrbp->hpb_ctx_id; + else + cdb[14] = UFSHPB_GROUP_NUMBER; + + cdb[15] = transfer_len; + + lrbp->cmd->cmd_len = MAX_CDB_SIZE; +} + +/* called with hpb_lock (irq) */ +static inline void +ufshpb_set_dirty_bits(struct ufshpb_lu *hpb, struct ufshpb_region *rgn, + struct ufshpb_subregion *srgn, int dword, int offset, + unsigned int cnt) +{ + const unsigned long mask = ((1UL << cnt) - 1) & 0xffffffff; + + if (rgn->rgn_state == HPBREGION_INACTIVE) + return; + + BUG_ON(!srgn->mctx); + srgn->mctx->ppn_dirty[dword] |= (mask << offset); +} + +static inline void ufshpb_get_bit_offset(struct ufshpb_lu *hpb, int srgn_offset, + int *dword, int *offset) +{ + *dword = srgn_offset >> bits_per_dword_shift; + *offset = srgn_offset & bits_per_dword_mask; +} + +static void ufshpb_set_dirty(struct ufshpb_lu *hpb, struct ufshcd_lrb *lrbp, + int rgn_idx, int srgn_idx, int srgn_offset) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + int cnt, bit_cnt, bit_dword, bit_offset; + + cnt = blk_rq_sectors(lrbp->cmd->request) >> sects_per_blk_shift; + ufshpb_get_bit_offset(hpb, srgn_offset, &bit_dword, &bit_offset); + + do { + bit_cnt = min(cnt, BITS_PER_DWORD - bit_offset); + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + ufshpb_set_dirty_bits(hpb, rgn, srgn, bit_dword, bit_offset, + bit_cnt); + + bit_offset = 0; + bit_dword++; + + if (bit_dword == hpb->dwords_per_srgn) { + bit_dword = 0; + srgn_idx++; + + if (srgn_idx == hpb->srgns_per_rgn) { + srgn_idx = 0; + rgn_idx++; + } + } + cnt -= bit_cnt; + } while (cnt); + + BUG_ON(cnt < 0); +} + +static inline bool ufshpb_is_read_cmd(struct scsi_cmnd *cmd) +{ + if (cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_16) + return true; + + return false; +} + +static inline bool ufshpb_is_write_discard_lrbp(struct ufshcd_lrb *lrbp) +{ + if (lrbp->cmd->cmnd[0] == WRITE_10 || lrbp->cmd->cmnd[0] == WRITE_16 || + lrbp->cmd->cmnd[0] == UNMAP) + return true; + + return false; +} + +static unsigned long long ufshpb_get_ppn(struct ufshpb_map_ctx *mctx, int pos, + int *error) +{ + unsigned long long *ppn_table; + struct page *page = NULL; + int index, offset; + + index = pos / HPB_ENTREIS_PER_OS_PAGE; + offset = pos % HPB_ENTREIS_PER_OS_PAGE; + + page = mctx->m_page[index]; + if (!page) { + *error = -ENOMEM; + ERR_MSG("mctx %p cannot get m_page", mctx); + return 0; + } + + ppn_table = page_address(page); + if (!ppn_table) { + *error = -ENOMEM; + ERR_MSG("mctx %p cannot get ppn_table vm", mctx); + return 0; + } + + return ppn_table[offset]; +} + +static inline int ufshpb_lu_get(struct ufshpb_lu *hpb) +{ + if (!hpb || hpb->ufsf->ufshpb_state != HPB_PRESENT) + return -ENODEV; + + kref_get(&hpb->ufsf->ufshpb_kref); + return 0; +} + +static inline void ufshpb_schedule_error_handler(struct kref *kref) +{ + struct ufsf_feature *ufsf; + + ufsf = container_of(kref, struct ufsf_feature, ufshpb_kref); + schedule_work(&ufsf->ufshpb_eh_work); +} + +static inline void ufshpb_lu_put(struct ufshpb_lu *hpb) +{ + kref_put(&hpb->ufsf->ufshpb_kref, ufshpb_schedule_error_handler); +} + +static void ufshpb_failed(struct ufshpb_lu *hpb, const char *f) +{ + ERR_MSG("ufshpb_driver failed. function (%s)", f); + hpb->ufsf->ufshpb_state = HPB_FAILED; + ufshpb_lu_put(hpb); +} + +static inline void ufshpb_put_pre_req(struct ufshpb_lu *hpb, + struct ufshpb_req *pre_req) +{ + list_add_tail(&pre_req->list_req, &hpb->lh_pre_req_free); + hpb->num_inflight_pre_req--; +} + +static struct ufshpb_req *ufshpb_get_pre_req(struct ufshpb_lu *hpb) +{ + struct ufshpb_req *pre_req; + + if (hpb->num_inflight_pre_req >= hpb->throttle_pre_req) { + HPB_DEBUG(hpb, "pre_req throttle. inflight %d throttle %d", + hpb->num_inflight_pre_req, hpb->throttle_pre_req); + return NULL; + } + + pre_req = list_first_entry_or_null(&hpb->lh_pre_req_free, + struct ufshpb_req, + list_req); + if (!pre_req) { + HPB_DEBUG(hpb, "There is no pre_req"); + return NULL; + } + + list_del_init(&pre_req->list_req); + hpb->num_inflight_pre_req++; + + return pre_req; +} + +static void ufshpb_pre_req_compl_fn(struct request *req, blk_status_t error) +{ + struct ufshpb_req *pre_req = (struct ufshpb_req *)req->end_io_data; + struct ufshpb_lu *hpb = pre_req->hpb; + unsigned long flags; + struct scsi_sense_hdr sshdr; + + if (error) { + ERR_MSG("error number %d", error); + scsi_normalize_sense(pre_req->sense, SCSI_SENSE_BUFFERSIZE, + &sshdr); + ERR_MSG("code %x sense_key %x asc %x ascq %x", + sshdr.response_code, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + ERR_MSG("byte4 %x byte5 %x byte6 %x additional_len %x", + sshdr.byte4, sshdr.byte5, + sshdr.byte6, sshdr.additional_length); + } + + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_pre_req(pre_req->hpb, pre_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + ufshpb_lu_put(pre_req->hpb); +} + +static int ufshpb_prep_entry(struct ufshpb_req *pre_req, + struct page *page) +{ + struct ufshpb_lu *hpb = pre_req->hpb; + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + unsigned long long *addr; + unsigned long long entry_ppn = 0; + unsigned long lpn = pre_req->wb.lpn; + int rgn_idx, srgn_idx, srgn_offset; + int i, error = 0; + unsigned long flags; + + addr = page_address(page); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + for (i = 0; i < pre_req->wb.len; i++, lpn++) { + ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, + &srgn_offset); + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + if (!ufshpb_valid_srgn(rgn, srgn)) + goto mctx_error; + + if (!srgn->mctx) + goto mctx_error; + + entry_ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + if (error) + goto mctx_error; + + addr[i] = entry_ppn; + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return 0; +mctx_error: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return -ENOMEM; +} + +static int ufshpb_pre_req_add_bio_page(struct request_queue *q, + struct ufshpb_req *pre_req) +{ + struct page *page = pre_req->wb.m_page; + struct bio *bio = pre_req->bio; + int ret; + + BUG_ON(!page); + + bio_reset(bio); + + ret = ufshpb_prep_entry(pre_req, page); + if (ret) + return ret; + + ret = bio_add_pc_page(q, bio, page, OS_PAGE_SIZE, 0); + if (ret != OS_PAGE_SIZE) { + ERR_MSG("bio_add_pc_page fail: %d", ret); + return -ENOMEM; + } + + return 0; +} + +static void ufshpb_init_cmd_errh(struct scsi_cmnd *cmd) +{ + cmd->serial_number = 0; + scsi_set_resid(cmd, 0); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + if (cmd->cmd_len == 0) + cmd->cmd_len = scsi_command_size(cmd->cmnd); +} + +static void ufshpb_pre_req_done(struct scsi_cmnd *cmd) +{ + blk_complete_request(cmd->request); +} + +static inline unsigned long ufshpb_get_lpn(struct request *rq) +{ + return blk_rq_pos(rq) / SECTORS_PER_BLOCK; +} + +static inline unsigned int ufshpb_get_len(struct request *rq) +{ + return blk_rq_sectors(rq) / SECTORS_PER_BLOCK; +} + +static inline unsigned int ufshpb_is_unaligned(struct request *rq) +{ + return blk_rq_sectors(rq) % SECTORS_PER_BLOCK; +} + +static inline int ufshpb_issue_ctx_id_ticket(struct ufshpb_lu *hpb) +{ + int hpb_ctx_id; + + hpb->ctx_id_ticket++; + if (hpb->ctx_id_ticket >= MAX_HPB_CONTEXT_ID) + hpb->ctx_id_ticket = 0; + hpb_ctx_id = hpb->ctx_id_ticket; + + return hpb_ctx_id; +} + +static inline void ufshpb_set_write_buf_cmd(unsigned char *cdb, + unsigned long lpn, unsigned int len, + int hpb_ctx_id) +{ + int len_byte = len * HPB_ENTRY_SIZE; + + cdb[0] = UFSHPB_WRITE_BUFFER; + cdb[1] = UFSHPB_WRITE_BUFFER_ID; + cdb[2] = GET_BYTE_3(lpn); + cdb[3] = GET_BYTE_2(lpn); + cdb[4] = GET_BYTE_1(lpn); + cdb[5] = GET_BYTE_0(lpn); + cdb[6] = (1 << 7) | hpb_ctx_id; + cdb[7] = GET_BYTE_1(len_byte); + cdb[8] = GET_BYTE_0(len_byte); + cdb[9] = 0x00; /* Control = 0x00 */ +} + +static void ufshpb_mimic_scsi_release_buffers(struct scsi_cmnd *cmd) +{ + if (cmd->sdb.table.nents) + sg_free_table_chained(&cmd->sdb.table, false); + + memset(&cmd->sdb, 0, sizeof(cmd->sdb)); + + if (scsi_prot_sg_count(cmd)) + sg_free_table_chained(&cmd->prot_sdb->table, false); +} + +static inline void ufshpb_mimic_scsi_dispatch_cmd(struct scsi_cmnd *cmd) +{ + atomic_inc(&cmd->device->iorequest_cnt); + + scsi_log_send(cmd); + + cmd->scsi_done = ufshpb_pre_req_done; +} + +static int ufshpb_mimic_scsi_request_fn(struct ufshpb_lu *hpb, + struct request *req) +{ + struct request_queue *q = req->q; + struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost = sdev->host; + struct scsi_cmnd *cmd; + unsigned long flags; + unsigned int busy; + int ret = 0; + + spin_lock_irqsave(q->queue_lock, flags); + req->rq_flags |= RQF_STARTED; + + ret = q->prep_rq_fn(q, req); + if (unlikely(ret != BLKPREP_OK)) { + HPB_DEBUG(hpb, "scsi_prep_fn is fail"); + ret = -EIO; + goto prep_err; + } + cmd = req->special; + if (unlikely(!cmd)) + BUG(); + + busy = atomic_inc_return(&sdev->device_busy) - 1; + if (busy >= sdev->queue_depth) { + ret = -EAGAIN; + goto finish_cmd; + } + + /* lh_pre_req_free list is dummy head for blk_dequeue_request() */ + list_add_tail(&req->queuelist, &hpb->lh_pre_req_dummy); + ret = blk_queue_start_tag(q, req); + if (ret) { + list_del_init(&req->queuelist); + ret = -EAGAIN; + goto finish_cmd; + } + spin_unlock_irqrestore(q->queue_lock, flags); + + /* + * UFS device has multi luns, so starget is not used. + * In case of UFS, starget->can_queue <= 0. + */ + if (unlikely(scsi_target(sdev)->can_queue > 0)) + atomic_inc(&scsi_target(sdev)->target_busy); + atomic_inc(&shost->host_busy); + + ufshpb_init_cmd_errh(cmd); + + ufshpb_mimic_scsi_dispatch_cmd(cmd); + + return ret; +finish_cmd: + ufshpb_mimic_scsi_release_buffers(cmd); + scsi_put_command(cmd); + put_device(&sdev->sdev_gendev); + req->special = NULL; + atomic_dec(&sdev->device_busy); +prep_err: + spin_unlock_irqrestore(q->queue_lock, flags); + return ret; +} + +static int ufshpb_set_pre_req(struct ufshpb_lu *hpb, struct scsi_cmnd *cmd, + struct ufshpb_req *pre_req, int hpb_ctx_id) +{ + struct scsi_device *sdev = cmd->device; + struct request_queue *q = sdev->request_queue; + struct request *req; + struct scsi_request *rq; + struct scsi_cmnd *scmd; + struct bio *bio = pre_req->bio; + int ret = 0; + + pre_req->hpb = hpb; + pre_req->wb.lpn = ufshpb_get_lpn(cmd->request); + pre_req->wb.len = ufshpb_get_len(cmd->request); + ret = ufshpb_pre_req_add_bio_page(q, pre_req); + if (ret) + return ret; + + req = pre_req->req; + + /* + * blk_init_rl() -> alloc_request_size(). + * q->init_rq_fn = scsi_old_init_rq behavior. + */ + scmd = (struct scsi_cmnd *)(req + 1); + memset(scmd, 0, sizeof(*scmd)); + scmd->sense_buffer = pre_req->sense; + scmd->req.sense = scmd->sense_buffer; + + /* blk_get_request behavior */ + blk_rq_init(q, req); + q->initialize_rq_fn(req); + + /* 1. request setup */ + blk_rq_append_bio(req, &bio); + req->cmd_flags = REQ_OP_WRITE | REQ_SYNC | REQ_OP_SCSI_OUT; + req->rq_flags = RQF_QUIET | RQF_PREEMPT; + req->timeout = msecs_to_jiffies(30000); + req->end_io_data = (void *)pre_req; + req->end_io = ufshpb_pre_req_compl_fn; + + /* 2. scsi_request setup */ + rq = scsi_req(req); + ufshpb_set_write_buf_cmd(rq->cmd, pre_req->wb.lpn, pre_req->wb.len, + hpb_ctx_id); + rq->cmd_len = scsi_command_size(rq->cmd); + + ret = ufshpb_mimic_scsi_request_fn(hpb, req); + + return ret; +} + +static bool ufshpb_is_support_chunk(int transfer_len) +{ + return transfer_len <= HPB_MULTI_CHUNK_HIGH; +} + +static int ufshpb_check_pre_req_cond(struct ufshpb_lu *hpb, + struct scsi_cmnd *cmd) +{ + struct request *rq = cmd->request; + unsigned long flags; + unsigned int transfer_len; + unsigned int lpn; + + if (!ufshpb_is_read_cmd(cmd)) + return -EINVAL; + + if (ufshpb_is_unaligned(rq)) + return -EINVAL; + + transfer_len = ufshpb_get_len(rq); + if (!transfer_len) + return -EINVAL; + + if (!ufshpb_is_support_chunk(transfer_len)) + return -EINVAL; + + /* + * WRITE_BUFFER CMD support 36K (len=9) ~ 512K (len=128) default. + * it is possible to change range of transfer_len through sysfs. + */ + if (transfer_len < hpb->pre_req_min_tr_len || + transfer_len > hpb->pre_req_max_tr_len) + return -EINVAL; + + lpn = ufshpb_get_lpn(cmd->request); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (ufshpb_ppn_dirty_check(hpb, lpn, transfer_len)) { + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + return 0; +} + +void ufshpb_end_pre_req(struct ufsf_feature *ufsf, struct request *req) +{ + struct scsi_cmnd *scmd = (struct scsi_cmnd *)(req + 1); + + set_host_byte(scmd, DID_OK); + + scmd->scsi_done(scmd); +} + +int ufshpb_prepare_pre_req(struct ufsf_feature *ufsf, struct scsi_cmnd *cmd, + int lun) +{ + struct ufs_hba *hba = ufsf->hba; + struct ufshpb_lu *hpb; + struct ufshpb_req *pre_req; + struct ufshcd_lrb *add_lrbp; + struct ufshcd_lrb *orig_lrbp = &hba->lrb[cmd->request->tag]; + struct scsi_cmnd *pre_cmd; + unsigned long flags; + int add_tag, hpb_ctx_id; + int ret = 0; + + /* WKLU could not be HPB-LU */ + if (!ufsf_is_valid_lun(lun)) + return -ENODEV; + + hpb = ufsf->ufshpb_lup[lun]; + ret = ufshpb_lu_get(hpb); + if (ret) + return ret; + + if (hpb->force_disable) { + ret = -ENODEV; + goto put_hpb; + } + + ret = ufshpb_check_pre_req_cond(hpb, cmd); + if (ret) + goto put_hpb; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + pre_req = ufshpb_get_pre_req(hpb); + if (!pre_req) { + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + ret = -ENOMEM; + goto put_hpb; + } + + hpb_ctx_id = ufshpb_issue_ctx_id_ticket(hpb); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + ret = ufshpb_set_pre_req(hpb, cmd, pre_req, hpb_ctx_id); + if (ret) + goto put_pre_req; + + add_tag = pre_req->req->tag; + if (test_and_set_bit_lock(add_tag, &hba->lrb_in_use)) { + ufshpb_end_pre_req(ufsf, pre_req->req); + return -EIO; + } + + add_lrbp = &hba->lrb[add_tag]; + WARN_ON(add_lrbp->cmd); + + pre_cmd = pre_req->req->special; + add_lrbp->cmd = pre_cmd; + add_lrbp->sense_bufflen = UFSHCD_REQ_SENSE_SIZE; + add_lrbp->sense_buffer = pre_cmd->sense_buffer; + add_lrbp->task_tag = add_tag; + add_lrbp->lun = lun; + add_lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false; + add_lrbp->req_abort_skip = false; + + orig_lrbp->hpb_ctx_id = hpb_ctx_id; + + return add_tag; +put_pre_req: + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_pre_req(hpb, pre_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +put_hpb: + ufshpb_lu_put(hpb); + return ret; +} + +int ufshpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag) +{ + struct ufs_hba *hba = ufsf->hba; + struct ufshcd_lrb *add_lrbp; + struct scsi_cmnd *pre_cmd; + int err = 0; + + add_lrbp = &hba->lrb[add_tag]; + + pre_cmd = add_lrbp->cmd; + + err = ufshcd_hold(hba, true); + if (err) + goto hold_err; + + err = ufshcd_hibern8_hold(hba, true); + if (err) { + ufshcd_release(hba, true); + goto hold_err; + } + + /* Vote PM QoS for the pre_req */ + ufshcd_vops_pm_qos_req_start(hba, pre_cmd->request); + + err = ufshcd_comp_scsi_upiu(hba, add_lrbp); + if (err) + goto map_err; + + err = ufshcd_map_sg(hba, add_lrbp); + if (err) + goto map_err; + + err = ufshcd_prepare_lrbp_crypto(hba, pre_cmd, add_lrbp); + if (err) + goto crypto_err; + + return 0; +crypto_err: + scsi_dma_unmap(pre_cmd); +map_err: + ufshcd_vops_pm_qos_req_end(hba, pre_cmd->request, true); + ufshcd_release_all(hba); +hold_err: + add_lrbp->cmd = NULL; + clear_bit_unlock(add_tag, &hba->lrb_in_use); + ufsf_hpb_end_pre_req(&hba->ufsf, pre_cmd->request); + return -EIO; +} + +/* routine : READ10 -> HPB_READ */ +void ufshpb_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + struct ufshpb_lu *hpb; + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + struct request *rq; + unsigned long long ppn = 0; + unsigned long lpn, flags; + int transfer_len = TRANSFER_LEN; + int rgn_idx, srgn_idx, srgn_offset, ret, error = 0; + + /* WKLU could not be HPB-LU */ + if (!lrbp || !ufsf_is_valid_lun(lrbp->lun)) + return; + + if (!ufshpb_is_write_discard_lrbp(lrbp) && + !ufshpb_is_read_cmd(lrbp->cmd)) + return; + + rq = lrbp->cmd->request; + hpb = ufsf->ufshpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (ret) + return; + + if (hpb->force_disable) { + if (ufshpb_is_read_cmd(lrbp->cmd)) + TMSG(ufsf, hpb->lun, "%llu + %u READ_10", + (unsigned long long) blk_rq_pos(rq), + (unsigned int) blk_rq_sectors(rq)); + goto put_hpb; + } + + lpn = ufshpb_get_lpn(rq); + ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, &srgn_offset); + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + /* + * If cmd type is WRITE, bitmap set to dirty. + */ + if (ufshpb_is_write_discard_lrbp(lrbp)) { + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (rgn->rgn_state == HPBREGION_INACTIVE) { + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto put_hpb; + } + ufshpb_set_dirty(hpb, lrbp, rgn_idx, srgn_idx, srgn_offset); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto put_hpb; + } + + if (!ufshpb_is_read_cmd(lrbp->cmd)) + goto put_hpb; + + if (ufshpb_is_unaligned(rq)) { + TMSG_CMD(hpb, "READ_10 not aligned 4KB", rq, rgn_idx, srgn_idx); + goto put_hpb; + } + + transfer_len = ufshpb_get_len(rq); + if (!transfer_len) + goto put_hpb; + + if (!ufshpb_is_support_chunk(transfer_len)) { + TMSG_CMD(hpb, "READ_10 doesn't support chunk size", + rq, rgn_idx, srgn_idx); + goto put_hpb; + } + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (ufshpb_ppn_dirty_check(hpb, lpn, transfer_len)) { + atomic64_inc(&hpb->miss); + TMSG_CMD(hpb, "READ_10 E_D", rq, rgn_idx, srgn_idx); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto put_hpb; + } + + ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + if (error) { + ERR_MSG("get_ppn failed.. err %d region %d subregion %d", + error, rgn_idx, srgn_idx); + ufshpb_lu_put(hpb); + goto wakeup_ee_worker; + } + + ufshpb_set_read16_cmd(hpb, lrbp, ppn, transfer_len); + TMSG(ufsf, hpb->lun, "%llu + %u HPB_READ %d - %d context_id %d", + (unsigned long long) blk_rq_pos(lrbp->cmd->request), + (unsigned int) blk_rq_sectors(lrbp->cmd->request), rgn_idx, + srgn_idx, lrbp->hpb_ctx_id); + + atomic64_inc(&hpb->hit); +put_hpb: + ufshpb_lu_put(hpb); + return; +wakeup_ee_worker: + ufshpb_failed(hpb, __func__); +} + +static inline void ufshpb_put_map_req(struct ufshpb_lu *hpb, + struct ufshpb_req *map_req) +{ + list_add_tail(&map_req->list_req, &hpb->lh_map_req_free); + hpb->num_inflight_map_req--; +} + +static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb) +{ + struct ufshpb_req *map_req; + + if (hpb->num_inflight_map_req >= hpb->throttle_map_req) { + HPB_DEBUG(hpb, "map_req throttle. inflight %d throttle %d", + hpb->num_inflight_map_req, hpb->throttle_map_req); + return NULL; + } + + map_req = list_first_entry_or_null(&hpb->lh_map_req_free, + struct ufshpb_req, list_req); + if (!map_req) { + HPB_DEBUG(hpb, "There is no map_req"); + return NULL; + } + + list_del_init(&map_req->list_req); + hpb->num_inflight_map_req++; + + return map_req; +} + +static int ufshpb_clean_dirty_bitmap(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_region *rgn; + + BUG_ON(!srgn->mctx); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + if (rgn->rgn_state == HPBREGION_INACTIVE) { + HPB_DEBUG(hpb, "%d - %d evicted", srgn->rgn_idx, + srgn->srgn_idx); + return -EINVAL; + } + + memset(srgn->mctx->ppn_dirty, 0x00, + hpb->entries_per_srgn >> bits_per_byte_shift); + + return 0; +} + +static void ufshpb_clean_active_subregion(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_region *rgn; + + BUG_ON(!srgn->mctx); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + if (rgn->rgn_state == HPBREGION_INACTIVE) { + HPB_DEBUG(hpb, "%d - %d evicted", srgn->rgn_idx, + srgn->srgn_idx); + return; + } + srgn->srgn_state = HPBSUBREGION_CLEAN; +} + +static void ufshpb_error_active_subregion(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_region *rgn; + + BUG_ON(!srgn->mctx); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + if (rgn->rgn_state == HPBREGION_INACTIVE) { + ERR_MSG("%d - %d evicted", srgn->rgn_idx, srgn->srgn_idx); + return; + } + srgn->srgn_state = HPBSUBREGION_DIRTY; +} + +static void ufshpb_check_ppn(struct ufshpb_lu *hpb, int rgn_idx, int srgn_idx, + struct ufshpb_map_ctx *mctx, const char *str) +{ + int error = 0; + unsigned long long val[2]; + + BUG_ON(!mctx); + + val[0] = ufshpb_get_ppn(mctx, 0, &error); + if (!error) + val[1] = ufshpb_get_ppn(mctx, hpb->entries_per_srgn - 1, + &error); + if (error) + val[0] = val[1] = 0; + + HPB_DEBUG(hpb, "%s READ BUFFER %d - %d ( %llx ~ %llx )", str, rgn_idx, + srgn_idx, val[0], val[1]); +} + +static void ufshpb_map_compl_process(struct ufshpb_req *map_req) +{ + struct ufshpb_lu *hpb = map_req->hpb; + struct ufshpb_subregion *srgn; + unsigned long flags; + + srgn = hpb->rgn_tbl[map_req->rb.rgn_idx].srgn_tbl + + map_req->rb.srgn_idx; + + if (hpb->debug) + ufshpb_check_ppn(hpb, srgn->rgn_idx, srgn->srgn_idx, srgn->mctx, + "COMPL"); + + TMSG(hpb->ufsf, hpb->lun, "Noti: C RB %d - %d", map_req->rb.rgn_idx, + map_req->rb.srgn_idx); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_clean_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +} + +static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx, + int srgn_idx) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + list_del_init(&rgn->list_inact_rgn); + + if (list_empty(&srgn->list_act_srgn)) + list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn); +} + +static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int rgn_idx) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + int srgn_idx; + + rgn = hpb->rgn_tbl + rgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + list_del_init(&srgn->list_act_srgn); + } + + if (list_empty(&rgn->list_inact_rgn)) + list_add_tail(&rgn->list_inact_rgn, &hpb->lh_inact_rgn); +} + +static int ufshpb_map_req_error(struct ufshpb_req *map_req) +{ + struct ufshpb_lu *hpb = map_req->hpb; + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + struct scsi_sense_hdr sshdr; + unsigned long flags; + + rgn = hpb->rgn_tbl + map_req->rb.rgn_idx; + srgn = rgn->srgn_tbl + map_req->rb.srgn_idx; + + scsi_normalize_sense(map_req->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); + + ERR_MSG("code %x sense_key %x asc %x ascq %x", sshdr.response_code, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + ERR_MSG("byte4 %x byte5 %x byte6 %x additional_len %x", sshdr.byte4, + sshdr.byte5, sshdr.byte6, sshdr.additional_length); + + if (sshdr.sense_key != ILLEGAL_REQUEST) + return 0; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (rgn->rgn_state == HPBREGION_PINNED) { + if (sshdr.asc == 0x06 && sshdr.ascq == 0x01) { + HPB_DEBUG(hpb, "retry pinned rb %d - %d", + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + list_add_tail(&map_req->list_req, + &hpb->lh_map_req_retry); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + schedule_delayed_work(&hpb->ufshpb_retry_work, + msecs_to_jiffies(RETRY_DELAY_MS)); + return -EAGAIN; + } + HPB_DEBUG(hpb, "pinned rb %d - %d(dirty)", + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + ufshpb_error_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + } else { + ufshpb_error_active_subregion(hpb, srgn); + + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + ufshpb_update_inactive_info(hpb, map_req->rb.rgn_idx); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + HPB_DEBUG(hpb, "Non-pinned rb %d will be inactive", + map_req->rb.rgn_idx); + + schedule_work(&hpb->ufshpb_task_workq); + } + + return 0; +} + +static inline void ufshpb_mimic_blk_pm_put_request(struct request *rq) +{ + if (rq->q->dev && !(rq->rq_flags & RQF_PM) && !--rq->q->nr_pending) + pm_runtime_mark_last_busy(rq->q->dev); +} + +/* routine : map_req compl */ +static void ufshpb_map_req_compl_fn(struct request *req, blk_status_t error) +{ + struct ufshpb_req *map_req = (struct ufshpb_req *) req->end_io_data; + struct ufshpb_lu *hpb = map_req->hpb; + unsigned long flags; + int ret; + +#ifdef CONFIG_PM + ufshpb_mimic_blk_pm_put_request(req); +#endif + if (hpb->ufsf->ufshpb_state != HPB_PRESENT) + goto free_map_req; + + if (error) { + ERR_MSG("COMP_NOTI: RB number %d ( %d - %d )", error, + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + ret = ufshpb_map_req_error(map_req); + if (ret) + goto retry_map_req; + } else + ufshpb_map_compl_process(map_req); + +free_map_req: + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_map_req(map_req->hpb, map_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +retry_map_req: + scsi_device_put(hpb->ufsf->sdev_ufs_lu[hpb->lun]); + ufshpb_lu_put(hpb); +} + +static inline int ufshpb_get_scsi_device(struct ufs_hba *hba, + struct scsi_device *sdev) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(hba->host->host_lock, flags); + ret = scsi_device_get(sdev); + if (!ret && !scsi_device_online(sdev)) { + spin_unlock_irqrestore(hba->host->host_lock, flags); + scsi_device_put(sdev); + WARNING_MSG("scsi_device_get failed.. ret %d", ret); + return -ENODEV; + } + spin_unlock_irqrestore(hba->host->host_lock, flags); + + return 0; +} + +static int ufshpb_execute_dev_ctx_req(struct ufshpb_lu *hpb, unsigned char *cdb, + void *buf, int len) +{ + struct scsi_sense_hdr sshdr; + struct scsi_device *sdev; + struct ufsf_feature *ufsf = hpb->ufsf; + int ret = 0; + + sdev = ufsf->sdev_ufs_lu[hpb->lun]; + if (!sdev) { + WARNING_MSG("cannot find scsi_device"); + return -ENODEV; + } + + ret = ufshpb_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + ufsf->issue_ioctl = true; + + ret = scsi_execute(sdev, cdb, DMA_FROM_DEVICE, buf, len, NULL, &sshdr, + msecs_to_jiffies(30000), 3, 0, 0, NULL); + + ufsf->issue_ioctl = false; + + scsi_device_put(sdev); + + return ret; +} + +static inline void ufshpb_set_read_dev_ctx(unsigned char *cdb, int lba, int len) +{ + cdb[0] = READ_10; + cdb[1] = 0x02; + cdb[2] = GET_BYTE_3(lba); + cdb[3] = GET_BYTE_2(lba); + cdb[4] = GET_BYTE_1(lba); + cdb[5] = GET_BYTE_0(lba); + cdb[6] = GET_BYTE_2(len); + cdb[7] = GET_BYTE_1(len); + cdb[8] = GET_BYTE_0(len); +} + +int ufshpb_issue_req_dev_ctx(struct ufshpb_lu *hpb, unsigned char *buf, + int buf_len) +{ + unsigned char cdb[10] = { 0 }; + int cmd_len = buf_len >> OS_PAGE_SHIFT; + int ret = 0; + + ufshpb_set_read_dev_ctx(cdb, READ10_DEBUG_LBA, cmd_len); + + ret = ufshpb_execute_dev_ctx_req(hpb, cdb, buf, buf_len); + + if (ret < 0) + ERR_MSG("failed with err %d", ret); + + return ret; +} + +static inline void ufshpb_set_read_buf_cmd(unsigned char *cdb, int rgn_idx, + int srgn_idx, int srgn_mem_size) +{ + cdb[0] = UFSHPB_READ_BUFFER; + cdb[1] = UFSHPB_READ_BUFFER_ID; + cdb[2] = GET_BYTE_1(rgn_idx); + cdb[3] = GET_BYTE_0(rgn_idx); + cdb[4] = GET_BYTE_1(srgn_idx); + cdb[5] = GET_BYTE_0(srgn_idx); + cdb[6] = GET_BYTE_2(srgn_mem_size); + cdb[7] = GET_BYTE_1(srgn_mem_size); + cdb[8] = GET_BYTE_0(srgn_mem_size); + cdb[9] = 0x00; +} + +static int ufshpb_map_req_add_bio_page(struct ufshpb_lu *hpb, + struct request_queue *q, struct bio *bio, + struct ufshpb_map_ctx *mctx) +{ + struct page *page = NULL; + int i, ret = 0; + + bio_reset(bio); + + for (i = 0; i < hpb->mpages_per_srgn; i++) { + /* virt_to_page(p + (OS_PAGE_SIZE * i)); */ + page = mctx->m_page[i]; + if (!page) + return -ENOMEM; + + ret = bio_add_pc_page(q, bio, page, hpb->mpage_bytes, 0); + + if (ret != hpb->mpage_bytes) { + ERR_MSG("bio_add_pc_page fail: %d", ret); + return -ENOMEM; + } + } + + return 0; +} + +static int ufshpb_execute_map_req(struct ufshpb_lu *hpb, + struct scsi_device *sdev, + struct ufshpb_req *map_req) +{ + struct request_queue *q = sdev->request_queue; + struct request *req; + struct scsi_request *rq; + struct scsi_cmnd *scmd; + struct bio *bio = map_req->bio; + int ret; + + ret = ufshpb_map_req_add_bio_page(hpb, q, bio, map_req->rb.mctx); + if (ret) + return ret; + + req = map_req->req; + + /* + * blk_init_rl() -> alloc_request_size(). + * q->init_rq_fn = scsi_old_init_rq behavior. + */ + scmd = (struct scsi_cmnd *)(req + 1); + memset(scmd, 0, sizeof(*scmd)); + scmd->sense_buffer = map_req->sense; + scmd->req.sense = scmd->sense_buffer; + + /* blk_get_request behavior */ + blk_rq_init(q, req); + q->initialize_rq_fn(req); + + /* 1. request setup */ + blk_rq_append_bio(req, &bio); /* req->__data_len is setted */ + req->cmd_flags = REQ_OP_READ | REQ_OP_SCSI_IN; + req->rq_flags = RQF_QUIET | RQF_PREEMPT; + req->timeout = msecs_to_jiffies(30000); + req->end_io_data = (void *)map_req; + + /* 2. scsi_request setup */ + rq = scsi_req(req); + ufshpb_set_read_buf_cmd(rq->cmd, map_req->rb.rgn_idx, + map_req->rb.srgn_idx, hpb->srgn_mem_size); + rq->cmd_len = scsi_command_size(rq->cmd); + + if (hpb->debug) + ufshpb_check_ppn(hpb, map_req->rb.rgn_idx, map_req->rb.srgn_idx, + map_req->rb.mctx, "ISSUE"); + + TMSG(hpb->ufsf, hpb->lun, "Noti: I RB %d - %d", map_req->rb.rgn_idx, + map_req->rb.srgn_idx); + + blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_map_req_compl_fn); + + atomic64_inc(&hpb->map_req_cnt); + + return 0; +} + +static int ufshpb_issue_map_req(struct ufshpb_lu *hpb, + struct ufshpb_req *map_req) +{ + struct scsi_device *sdev; + struct ufsf_feature *ufsf = hpb->ufsf; + int ret = 0; + + sdev = ufsf->sdev_ufs_lu[hpb->lun]; + if (!sdev) { + WARNING_MSG("cannot find scsi_device"); + return -ENODEV; + } + + ret = ufshpb_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + ret = ufshpb_execute_map_req(hpb, sdev, map_req); + if (ret) + scsi_device_put(sdev); + + return ret; +} + +static inline void ufshpb_set_map_req(struct ufshpb_lu *hpb, int rgn_idx, + int srgn_idx, struct ufshpb_map_ctx *mctx, + struct ufshpb_req *map_req) +{ + map_req->hpb = hpb; + map_req->rb.rgn_idx = rgn_idx; + map_req->rb.srgn_idx = srgn_idx; + map_req->rb.mctx = mctx; + map_req->rb.lun = hpb->lun; +} + +static struct ufshpb_map_ctx *ufshpb_get_map_ctx(struct ufshpb_lu *hpb, + int *err) +{ + struct ufshpb_map_ctx *mctx; + + mctx = list_first_entry_or_null(&hpb->lh_map_ctx_free, + struct ufshpb_map_ctx, list_table); + if (mctx) { + list_del_init(&mctx->list_table); + hpb->debug_free_table--; + return mctx; + } + *err = -ENOMEM; + return NULL; +} + +static inline void ufshpb_add_lru_info(struct victim_select_info *lru_info, + struct ufshpb_region *rgn) +{ + rgn->rgn_state = HPBREGION_ACTIVE; + list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn); + atomic64_inc(&lru_info->active_cnt); +} + +static inline int ufshpb_add_region(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct victim_select_info *lru_info; + int srgn_idx; + int err = 0; + + lru_info = &hpb->lru_info; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + struct ufshpb_subregion *srgn; + + srgn = rgn->srgn_tbl + srgn_idx; + + srgn->mctx = ufshpb_get_map_ctx(hpb, &err); + if (!srgn->mctx) { + HPB_DEBUG(hpb, "get mctx err %d srgn %d free_table %d", + err, srgn_idx, hpb->debug_free_table); + goto out; + } + + srgn->srgn_state = HPBSUBREGION_DIRTY; + } + HPB_DEBUG(hpb, "\x1b[44m\x1b[32m E->active region: %d \x1b[0m", + rgn->rgn_idx); + TMSG(hpb->ufsf, hpb->lun, "Noti: ACT RG: %d", rgn->rgn_idx); + + ufshpb_add_lru_info(lru_info, rgn); +out: + return err; +} + +static inline void ufshpb_put_map_ctx(struct ufshpb_lu *hpb, + struct ufshpb_map_ctx *mctx) +{ + list_add(&mctx->list_table, &hpb->lh_map_ctx_free); + hpb->debug_free_table++; +} + +static inline void ufshpb_purge_active_subregion(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn, + int state) +{ + if (state == HPBSUBREGION_UNUSED) { + ufshpb_put_map_ctx(hpb, srgn->mctx); + srgn->mctx = NULL; + } + + srgn->srgn_state = state; +} + +static inline void ufshpb_cleanup_lru_info(struct victim_select_info *lru_info, + struct ufshpb_region *rgn) +{ + list_del_init(&rgn->list_lru_rgn); + rgn->rgn_state = HPBREGION_INACTIVE; + atomic64_dec(&lru_info->active_cnt); +} + +static void __ufshpb_evict_region(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct victim_select_info *lru_info; + struct ufshpb_subregion *srgn; + int srgn_idx; + + lru_info = &hpb->lru_info; + + HPB_DEBUG(hpb, "\x1b[41m\x1b[33m C->EVICT region: %d \x1b[0m", + rgn->rgn_idx); + TMSG(hpb->ufsf, hpb->lun, "Noti: EVIC RG: %d", rgn->rgn_idx); + + ufshpb_cleanup_lru_info(lru_info, rgn); + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + ufshpb_purge_active_subregion(hpb, srgn, HPBSUBREGION_UNUSED); + } +} + +static void ufshpb_hit_lru_info(struct victim_select_info *lru_info, + struct ufshpb_region *rgn) +{ + switch (lru_info->selection_type) { + case LRU: + list_move_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn); + break; + default: + break; + } +} + +/* + * Must be held hpb_lock before call this func. + */ +static int ufshpb_check_issue_state_srgns(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct ufshpb_subregion *srgn; + int srgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + if (srgn->srgn_state == HPBSUBREGION_ISSUED) + return -EPERM; + } + return 0; +} + +static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb) +{ + struct victim_select_info *lru_info = &hpb->lru_info; + struct ufshpb_region *rgn; + struct ufshpb_region *victim_rgn = NULL; + + switch (lru_info->selection_type) { + case LRU: + list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) { + if (!rgn) + break; + + if (ufshpb_check_issue_state_srgns(hpb, rgn)) + continue; + + victim_rgn = rgn; + break; + } + break; + default: + break; + } + + return victim_rgn; +} + +static int ufshpb_evict_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn) +{ + unsigned long flags; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (rgn->rgn_state == HPBREGION_PINNED) { + /* + * Pinned active-block should not drop-out. + * But if so, it would treat error as critical, + * and it will run ufshpb_eh_work + */ + WARNING_MSG("pinned active-block drop-out error"); + goto out; + } + + if (!list_empty(&rgn->list_lru_rgn)) { + if (ufshpb_check_issue_state_srgns(hpb, rgn)) + goto evict_fail; + + __ufshpb_evict_region(hpb, rgn); + } +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return 0; +evict_fail: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return -EPERM; +} + +static inline struct +ufshpb_rsp_field *ufshpb_get_hpb_rsp(struct ufshcd_lrb *lrbp) +{ + return (struct ufshpb_rsp_field *)&lrbp->ucd_rsp_ptr->sr.sense_data_len; +} + +static int ufshpb_prepare_map_req(struct ufshpb_lu *hpb, + struct ufshpb_subregion *srgn) +{ + struct ufshpb_req *map_req; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + + if (srgn->srgn_state == HPBSUBREGION_ISSUED) { + ret = -EAGAIN; + goto unlock_out; + } + + map_req = ufshpb_get_map_req(hpb); + if (!map_req) { + ret = -ENOMEM; + goto unlock_out; + } + + srgn->srgn_state = HPBSUBREGION_ISSUED; + + ret = ufshpb_clean_dirty_bitmap(hpb, srgn); + if (ret) { + ufshpb_put_map_req(hpb, map_req); + goto unlock_out; + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + ufshpb_set_map_req(hpb, srgn->rgn_idx, srgn->srgn_idx, + srgn->mctx, map_req); + + ret = ufshpb_lu_get(hpb); + if (ret) { + WARNING_MSG("warning: ufshpb_lu_get failed.. %d", ret); + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_map_req(hpb, map_req); + goto unlock_out; + } + + ret = ufshpb_issue_map_req(hpb, map_req); + if (ret) { + ERR_MSG("issue map_req failed. [%d-%d] err %d", + srgn->rgn_idx, srgn->srgn_idx, ret); + ufshpb_lu_put(hpb); + goto wakeup_ee_worker; + } + return ret; +unlock_out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return ret; +wakeup_ee_worker: + ufshpb_failed(hpb, __func__); + return ret; +} + +static int ufshpb_load_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn) +{ + struct ufshpb_region *victim_rgn; + struct victim_select_info *lru_info = &hpb->lru_info; + unsigned long flags; + int ret = 0; + + /* + * if already region is added to lru_list, + * just initiate the information of lru. + * because the region already has the map ctx. + * (!list_empty(&rgn->list_region) == region->state=active...) + */ + spin_lock_irqsave(&hpb->hpb_lock, flags); + if (!list_empty(&rgn->list_lru_rgn)) { + ufshpb_hit_lru_info(lru_info, rgn); + goto out; + } + + if (rgn->rgn_state == HPBREGION_INACTIVE) { + if (atomic64_read(&lru_info->active_cnt) + == lru_info->max_lru_active_cnt) { + victim_rgn = ufshpb_victim_lru_info(hpb); + if (!victim_rgn) { + HPB_DEBUG(hpb, "UFSHPB victim_rgn is NULL"); + ret = -ENOMEM; + goto out; + } + TMSG(hpb->ufsf, hpb->lun, "Noti: VT RG %d", + victim_rgn->rgn_idx); + HPB_DEBUG(hpb, "LRU MAX(=%ld). victim choose %d", + atomic64_read(&lru_info->active_cnt), + victim_rgn->rgn_idx); + + __ufshpb_evict_region(hpb, victim_rgn); + } + + ret = ufshpb_add_region(hpb, rgn); + if (ret) { + ERR_MSG("UFSHPB memory allocation failed"); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + goto wake_up_ee_worker; + } + } +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return ret; +wake_up_ee_worker: + ufshpb_failed(hpb, __func__); + return ret; +} + +static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb, + struct ufshpb_rsp_field *rsp_field) +{ + int num, rgn_idx, srgn_idx; + + /* + * If active rgn = inactive rgn, choose inactive rgn. + * So, active process -> inactive process + */ + spin_lock(&hpb->rsp_list_lock); + for (num = 0; num < rsp_field->active_rgn_cnt; num++) { + rgn_idx = be16_to_cpu(rsp_field->hpb_active_field[num].active_rgn); + srgn_idx = be16_to_cpu(rsp_field->hpb_active_field[num].active_srgn); + + HPB_DEBUG(hpb, "act num: %d, region: %d, subregion: %d", + num + 1, rgn_idx, srgn_idx); + ufshpb_update_active_info(hpb, rgn_idx, srgn_idx); + atomic64_inc(&hpb->rb_active_cnt); + } + + for (num = 0; num < rsp_field->inactive_rgn_cnt; num++) { + rgn_idx = be16_to_cpu(rsp_field->hpb_inactive_field[num]); + HPB_DEBUG(hpb, "inact num: %d, region: %d", num + 1, rgn_idx); + ufshpb_update_inactive_info(hpb, rgn_idx); + atomic64_inc(&hpb->rb_inactive_cnt); + } + spin_unlock(&hpb->rsp_list_lock); + + TMSG(hpb->ufsf, hpb->lun, "Noti: #ACT %u, #INACT %u", + rsp_field->active_rgn_cnt, rsp_field->inactive_rgn_cnt); + + schedule_work(&hpb->ufshpb_task_workq); +} + +static inline int ufshpb_may_field_valid(struct ufshcd_lrb *lrbp, + struct ufshpb_rsp_field *rsp_field) +{ + if (be16_to_cpu(rsp_field->sense_data_len) != DEV_SENSE_SEG_LEN || + rsp_field->desc_type != DEV_DES_TYPE || + rsp_field->additional_len != DEV_ADDITIONAL_LEN || + rsp_field->hpb_type == HPB_RSP_NONE || + rsp_field->active_rgn_cnt > MAX_ACTIVE_NUM || + rsp_field->inactive_rgn_cnt > MAX_INACTIVE_NUM || + (!rsp_field->active_rgn_cnt && !rsp_field->inactive_rgn_cnt)) + return -EINVAL; + + if (!ufsf_is_valid_lun(lrbp->lun)) { + ERR_MSG("LU(%d) is not supported", lrbp->lun); + return -EINVAL; + } + + return 0; +} + +static bool ufshpb_is_empty_rsp_lists(struct ufshpb_lu *hpb) +{ + bool ret = true; + unsigned long flags; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + if (!list_empty(&hpb->lh_inact_rgn) || !list_empty(&hpb->lh_act_srgn)) + ret = false; + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + return ret; +} + +/* routine : isr (ufs) */ +void ufshpb_rsp_upiu(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + struct ufshpb_lu *hpb; + struct ufshpb_rsp_field *rsp_field; + int data_seg_len, ret; + + data_seg_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) + & MASK_RSP_UPIU_DATA_SEG_LEN; + + if (!data_seg_len) { + bool do_workq = false; + + if (!ufsf_is_valid_lun(lrbp->lun)) + return; + + hpb = ufsf->ufshpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (ret) + return; + + do_workq = !ufshpb_is_empty_rsp_lists(hpb); + if (do_workq) + schedule_work(&hpb->ufshpb_task_workq); + + goto put_hpb; + } + + rsp_field = ufshpb_get_hpb_rsp(lrbp); + + if (ufshpb_may_field_valid(lrbp, rsp_field)) { + WARN_ON(rsp_field->additional_len != DEV_ADDITIONAL_LEN); + return; + } + + hpb = ufsf->ufshpb_lup[lrbp->lun]; + ret = ufshpb_lu_get(hpb); + if (ret) { + WARNING_MSG("warning: ufshpb_lu_get failed %d..", ret); + return; + } + + if (hpb->force_map_req_disable) + goto put_hpb; + + HPB_DEBUG(hpb, "**** HPB Noti %u LUN %u Seg-Len %u, #ACT %u, #INACT %u", + rsp_field->hpb_type, lrbp->lun, + be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & + MASK_RSP_UPIU_DATA_SEG_LEN, rsp_field->active_rgn_cnt, + rsp_field->inactive_rgn_cnt); + atomic64_inc(&hpb->rb_noti_cnt); + + switch (rsp_field->hpb_type) { + case HPB_RSP_REQ_REGION_UPDATE: + WARN_ON(data_seg_len != DEV_DATA_SEG_LEN); + ufshpb_rsp_req_region_update(hpb, rsp_field); + goto put_hpb; + default: + HPB_DEBUG(hpb, "hpb_type is not available : %d", + rsp_field->hpb_type); + goto put_hpb; + } + +put_hpb: + ufshpb_lu_put(hpb); +} + +static int ufshpb_execute_map_req_wait(struct ufshpb_lu *hpb, + unsigned char *cmd, + struct ufshpb_subregion *srgn) +{ + struct ufsf_feature *ufsf = hpb->ufsf; + struct scsi_device *sdev; + struct request_queue *q; + struct request *req; + struct scsi_request *rq; + struct bio *bio; + struct scsi_sense_hdr sshdr; + unsigned long flags; + int ret = 0; + + sdev = ufsf->sdev_ufs_lu[hpb->lun]; + if (!sdev) { + WARNING_MSG("cannot find scsi_device"); + return -ENODEV; + } + + q = sdev->request_queue; + + ret = ufshpb_get_scsi_device(ufsf->hba, sdev); + if (ret) + return ret; + + req = blk_get_request(q, REQ_OP_SCSI_IN, BLK_MQ_REQ_PREEMPT); + if (IS_ERR(req)) { + WARNING_MSG("cannot get request"); + ret = -EIO; + goto sdev_put_out; + } + + bio = bio_kmalloc(GFP_KERNEL, hpb->mpages_per_srgn); + if (!bio) { + ret = -ENOMEM; + goto req_put_out; + } + + ret = ufshpb_map_req_add_bio_page(hpb, q, bio, srgn->mctx); + if (ret) + goto mem_free_out; + + /* 1. request setup*/ + blk_rq_append_bio(req, &bio); /* req->__data_len */ + req->timeout = msecs_to_jiffies(30000); + req->cmd_flags |= REQ_OP_READ; + req->rq_flags |= RQF_QUIET | RQF_PREEMPT; + + /* 2. scsi_request setup */ + rq = scsi_req(req); + rq->cmd_len = scsi_command_size(cmd); + memcpy(rq->cmd, cmd, rq->cmd_len); + + blk_execute_rq(q, NULL, req, 1); + if (rq->result) { + ret = -EIO; + scsi_normalize_sense(rq->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); + ERR_MSG("code %x sense_key %x asc %x ascq %x", + sshdr.response_code, sshdr.sense_key, sshdr.asc, + sshdr.ascq); + ERR_MSG("byte4 %x byte5 %x byte6 %x additional_len %x", + sshdr.byte4, sshdr.byte5, sshdr.byte6, + sshdr.additional_length); + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_error_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + } +mem_free_out: + bio_put(bio); +req_put_out: + blk_put_request(req); +sdev_put_out: + scsi_device_put(sdev); + return ret; +} + +static int ufshpb_issue_map_req_from_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_subregion *srgn; + unsigned long flags; + int ret; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + + while ((srgn = list_first_entry_or_null(&hpb->lh_pinned_srgn, + struct ufshpb_subregion, + list_act_srgn))) { + unsigned char cmd[10] = { 0 }; + + list_del_init(&srgn->list_act_srgn); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + ufshpb_set_read_buf_cmd(cmd, srgn->rgn_idx, srgn->srgn_idx, + hpb->srgn_mem_size); + + if (hpb->debug) + ufshpb_check_ppn(hpb, srgn->rgn_idx, srgn->srgn_idx, + srgn->mctx, "ISSUE"); + + TMSG(hpb->ufsf, hpb->lun, "Noti: I RB %d - %d", + srgn->rgn_idx, srgn->srgn_idx); + + ret = ufshpb_execute_map_req_wait(hpb, cmd, srgn); + if (ret < 0) { + ERR_MSG("region %d sub %d failed with err %d", + srgn->rgn_idx, srgn->srgn_idx, ret); + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + if (list_empty(&srgn->list_act_srgn)) + list_add(&srgn->list_act_srgn, + &hpb->lh_pinned_srgn); + continue; + } + + TMSG(hpb->ufsf, hpb->lun, "Noti: C RB %d - %d", + srgn->rgn_idx, srgn->srgn_idx); + + if (hpb->debug) + ufshpb_check_ppn(hpb, srgn->rgn_idx, srgn->srgn_idx, + srgn->mctx, "COMPL"); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_clean_active_subregion(hpb, srgn); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + } + + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + return 0; +} + +static void ufshpb_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + int ret; + + hpb = container_of(work, struct ufshpb_lu, ufshpb_work); + HPB_DEBUG(hpb, "worker start for pinned region"); + + if (!list_empty(&hpb->lh_pinned_srgn)) { + ret = ufshpb_issue_map_req_from_list(hpb); + /* + * if its function failed at init time, + * ufshpb-device will request map-req, + * so it is not critical-error, and just finish work-handler + */ + if (ret) + HPB_DEBUG(hpb, "failed map-issue. ret %d", ret); + } + + HPB_DEBUG(hpb, "worker end"); +} + +static int ufshpb_check_pm(struct ufshpb_lu *hpb) +{ + struct ufs_hba *hba = hpb->ufsf->hba; + + if (hba->pm_op_in_progress || + hba->curr_dev_pwr_mode != UFS_ACTIVE_PWR_MODE) { + INFO_MSG("hba current power state %d pm_progress %d", + hba->curr_dev_pwr_mode, + hba->pm_op_in_progress); + return -ENODEV; + } + return 0; +} + +static void ufshpb_retry_work_handler(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + struct delayed_work *dwork = to_delayed_work(work); + struct ufshpb_req *map_req, *next; + unsigned long flags; + int ret = 0; + + LIST_HEAD(retry_list); + + hpb = container_of(dwork, struct ufshpb_lu, ufshpb_retry_work); + + if (ufshpb_check_pm(hpb)) + return; + + ret = ufshpb_lu_get(hpb); + if (ret) { + WARNING_MSG("warning: ufshpb_lu_get failed %d..", ret); + return; + } + + HPB_DEBUG(hpb, "retry worker start"); + + spin_lock_irqsave(&hpb->hpb_lock, flags); + list_splice_init(&hpb->lh_map_req_retry, &retry_list); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + + list_for_each_entry_safe(map_req, next, &retry_list, list_req) { + list_del_init(&map_req->list_req); + + ret = ufshpb_lu_get(hpb); + if (ret) { + WARNING_MSG("warning: ufshpb_lu_get failed %d..", ret); + spin_lock_irqsave(&hpb->hpb_lock, flags); + ufshpb_put_map_req(hpb, map_req); + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + continue; + } + + ret = ufshpb_issue_map_req(hpb, map_req); + if (ret) { + ERR_MSG("issue map_req failed. [%d-%d] err %d", + map_req->rb.rgn_idx, map_req->rb.srgn_idx, ret); + ufshpb_lu_put(hpb); + goto wakeup_ee_worker; + } + } + HPB_DEBUG(hpb, "worker end"); + ufshpb_lu_put(hpb); + return; +wakeup_ee_worker: + ufshpb_lu_put(hpb); + ufshpb_failed(hpb, __func__); +} + +static void ufshpb_add_starved_list(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn, + struct list_head *starved_list) +{ + struct ufshpb_subregion *srgn; + int srgn_idx; + + if (!list_empty(&rgn->list_inact_rgn)) + return; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + if (!list_empty(&srgn->list_act_srgn)) + return; + } + + list_add_tail(&rgn->list_inact_rgn, starved_list); +} + +static void ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_region *rgn; + unsigned long flags; + int ret; + LIST_HEAD(starved_list); + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + while ((rgn = list_first_entry_or_null(&hpb->lh_inact_rgn, + struct ufshpb_region, + list_inact_rgn))) { + list_del_init(&rgn->list_inact_rgn); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + ret = ufshpb_evict_region(hpb, rgn); + if (ret) { + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + ufshpb_add_starved_list(hpb, rgn, &starved_list); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + } + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + } + + list_splice(&starved_list, &hpb->lh_inact_rgn); + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); +} + +static void ufshpb_add_active_list(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn, + struct ufshpb_subregion *srgn) +{ + if (!list_empty(&rgn->list_inact_rgn)) + return; + + if (!list_empty(&srgn->list_act_srgn)) { + list_move(&srgn->list_act_srgn, &hpb->lh_act_srgn); + return; + } + + list_add(&srgn->list_act_srgn, &hpb->lh_act_srgn); +} + +static void ufshpb_run_active_subregion_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + while ((srgn = list_first_entry_or_null(&hpb->lh_act_srgn, + struct ufshpb_subregion, + list_act_srgn))) { + list_del_init(&srgn->list_act_srgn); + + if (hpb->force_map_req_disable) { + HPB_DEBUG(hpb, "map_req disabled"); + continue; + } + + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); + + rgn = hpb->rgn_tbl + srgn->rgn_idx; + + ret = ufshpb_load_region(hpb, rgn); + if (ret) + break; + + ret = ufshpb_prepare_map_req(hpb, srgn); + if (ret) + break; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + } + + if (ret) { + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + ufshpb_add_active_list(hpb, rgn, srgn); + } + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); +} + +static void ufshpb_task_workq_fn(struct work_struct *work) +{ + struct ufshpb_lu *hpb; + int ret; + + hpb = container_of(work, struct ufshpb_lu, ufshpb_task_workq); + ret = ufshpb_lu_get(hpb); + if (ret) { + WARNING_MSG("warning: ufshpb_lu_get failed %d..", ret); + return; + } + + ufshpb_run_inactive_region_list(hpb); + ufshpb_run_active_subregion_list(hpb); + + ufshpb_lu_put(hpb); +} + +static void ufshpb_init_constant(void) +{ + sects_per_blk_shift = ffs(BLOCK) - ffs(SECTOR); + INIT_INFO("sects_per_blk_shift: %u %u", sects_per_blk_shift, + ffs(SECTORS_PER_BLOCK) - 1); + + bits_per_dword_shift = ffs(BITS_PER_DWORD) - 1; + bits_per_dword_mask = BITS_PER_DWORD - 1; + INIT_INFO("bits_per_dword %u shift %u mask 0x%X", BITS_PER_DWORD, + bits_per_dword_shift, bits_per_dword_mask); + + bits_per_byte_shift = ffs(BITS_PER_BYTE) - 1; + INIT_INFO("bits_per_byte %u shift %u", BITS_PER_BYTE, + bits_per_byte_shift); +} + +static inline void ufshpb_map_req_mempool_remove(struct ufshpb_lu *hpb) +{ + int i; + + for (i = 0; i < hpb->qd; i++) { + kfree(hpb->map_req[i].req); + bio_put(hpb->map_req[i].bio); + } + + kfree(hpb->map_req); +} + +static inline void ufshpb_pre_req_mempool_remove(struct ufshpb_lu *hpb) +{ + int i; + + for (i = 0; i < hpb->qd; i++) { + kfree(hpb->pre_req[i].req); + bio_put(hpb->pre_req[i].bio); + __free_page(hpb->pre_req[i].wb.m_page); + } + + kfree(hpb->pre_req); +} + +static void ufshpb_table_mempool_remove(struct ufshpb_lu *hpb) +{ + struct ufshpb_map_ctx *mctx, *next; + int i; + + /* + * the mctx in the lh_map_ctx_free has been allocated completely. + */ + list_for_each_entry_safe(mctx, next, &hpb->lh_map_ctx_free, + list_table) { + for (i = 0; i < hpb->mpages_per_srgn; i++) + __free_page(mctx->m_page[i]); + + vfree(mctx->ppn_dirty); + kfree(mctx->m_page); + kfree(mctx); + hpb->alloc_mctx--; + } +} + +/* + * this function doesn't need to hold lock due to be called in init. + * (hpb_lock, rsp_list_lock, etc..) + */ +static int ufshpb_init_pinned_active_region(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + struct ufshpb_subregion *srgn; + int srgn_idx, j; + int err = 0; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + + srgn->mctx = ufshpb_get_map_ctx(hpb, &err); + if (err) { + ERR_MSG("get mctx err %d srgn %d free_table %d", + err, srgn_idx, hpb->debug_free_table); + goto release; + } + + srgn->srgn_state = HPBSUBREGION_ISSUED; + ufshpb_clean_dirty_bitmap(hpb, srgn); + list_add_tail(&srgn->list_act_srgn, &hpb->lh_pinned_srgn); + } + + rgn->rgn_state = HPBREGION_PINNED; + + return 0; + +release: + for (j = 0; j < srgn_idx; j++) { + srgn = rgn->srgn_tbl + j; + ufshpb_put_map_ctx(hpb, srgn->mctx); + } + + return err; +} + +static inline bool ufshpb_is_pinned_region(struct ufshpb_lu *hpb, int rgn_idx) +{ + if (hpb->lu_pinned_end_offset != -1 && + rgn_idx >= hpb->lu_pinned_rgn_startidx && + rgn_idx <= hpb->lu_pinned_end_offset) + return true; + + return false; +} + +static inline void ufshpb_init_jobs(struct ufshpb_lu *hpb) +{ + INIT_WORK(&hpb->ufshpb_work, ufshpb_work_handler); + INIT_DELAYED_WORK(&hpb->ufshpb_retry_work, ufshpb_retry_work_handler); + INIT_WORK(&hpb->ufshpb_task_workq, ufshpb_task_workq_fn); +} + +static inline void ufshpb_cancel_jobs(struct ufshpb_lu *hpb) +{ + cancel_work_sync(&hpb->ufshpb_work); + cancel_delayed_work_sync(&hpb->ufshpb_retry_work); + cancel_work_sync(&hpb->ufshpb_task_workq); +} + +static void ufshpb_init_subregion_tbl(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + int srgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + struct ufshpb_subregion *srgn = rgn->srgn_tbl + srgn_idx; + + INIT_LIST_HEAD(&srgn->list_act_srgn); + + srgn->rgn_idx = rgn->rgn_idx; + srgn->srgn_idx = srgn_idx; + srgn->srgn_state = HPBSUBREGION_UNUSED; + } +} + +static inline int ufshpb_alloc_subregion_tbl(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn, + int srgn_cnt) +{ + rgn->srgn_tbl = + kzalloc(sizeof(struct ufshpb_subregion) * srgn_cnt, GFP_KERNEL); + if (!rgn->srgn_tbl) + return -ENOMEM; + + rgn->srgn_cnt = srgn_cnt; + return 0; +} + +static int ufshpb_table_mempool_init(struct ufshpb_lu *hpb) +{ + struct ufshpb_map_ctx *mctx = NULL; + int i, j, k; + + INIT_LIST_HEAD(&hpb->lh_map_ctx_free); + + hpb->alloc_mctx = hpb->lu_max_active_rgns * hpb->srgns_per_rgn; + + for (i = 0; i < hpb->alloc_mctx; i++) { + mctx = kmalloc(sizeof(struct ufshpb_map_ctx), GFP_KERNEL); + if (!mctx) + goto release_mem; + + mctx->m_page = + kzalloc(sizeof(struct page *) * hpb->mpages_per_srgn, + GFP_KERNEL); + if (!mctx->m_page) + goto release_mem; + + mctx->ppn_dirty = + vzalloc(hpb->entries_per_srgn >> bits_per_byte_shift); + if (!mctx->ppn_dirty) + goto release_mem; + + for (j = 0; j < hpb->mpages_per_srgn; j++) { + mctx->m_page[j] = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!mctx->m_page[j]) { + for (k = 0; k < j; k++) + __free_page(mctx->m_page[k]); + goto release_mem; + } + } + + INIT_LIST_HEAD(&mctx->list_table); + list_add(&mctx->list_table, &hpb->lh_map_ctx_free); + + hpb->debug_free_table++; + } + + INIT_INFO("The number of mctx = %d. debug_free_table %d", + hpb->alloc_mctx, hpb->debug_free_table); + return 0; +release_mem: + /* + * mctxs already added in lh_map_ctx_free will be removed + * in the caller function. + */ + if (mctx) { + kfree(mctx->m_page); + vfree(mctx->ppn_dirty); + kfree(mctx); + } + return -ENOMEM; +} + +static int +ufshpb_map_req_mempool_init(struct ufshpb_lu *hpb) +{ + struct scsi_device *sdev; + struct request_queue *q; + struct ufshpb_req *map_req = NULL; + int qd = hpb->qd; + int i, j; + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + q = sdev->request_queue; + + INIT_LIST_HEAD(&hpb->lh_map_req_free); + INIT_LIST_HEAD(&hpb->lh_map_req_retry); + + hpb->map_req = kzalloc(sizeof(struct ufshpb_req) * qd, GFP_KERNEL); + if (!hpb->map_req) + goto release_mem; + + /* + * q->cmd_size: sizeof(struct scsi_cmd) + shost->hostt->cmd_size + */ + for (i = 0; i < qd; i++) { + map_req = hpb->map_req + i; + INIT_LIST_HEAD(&map_req->list_req); + map_req->req = kzalloc(sizeof(struct request) + q->cmd_size, + GFP_KERNEL); + if (!map_req->req) { + for (j = 0; j < i; j++) + kfree(hpb->map_req[j].req); + goto release_mem; + } + + map_req->bio = bio_kmalloc(GFP_KERNEL, hpb->mpages_per_srgn); + if (!map_req->bio) { + kfree(hpb->map_req[i].req); + for (j = 0; j < i; j++) { + kfree(hpb->map_req[j].req); + bio_put(hpb->map_req[j].bio); + } + goto release_mem; + } + list_add_tail(&map_req->list_req, &hpb->lh_map_req_free); + } + + return 0; +release_mem: + kfree(hpb->map_req); + return -ENOMEM; +} + +static int +ufshpb_pre_req_mempool_init(struct ufshpb_lu *hpb) +{ + struct scsi_device *sdev; + struct request_queue *q; + struct ufshpb_req *pre_req = NULL; + int qd = hpb->qd; + int i, j; + + INIT_LIST_HEAD(&hpb->lh_pre_req_free); + INIT_LIST_HEAD(&hpb->lh_pre_req_dummy); + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + q = sdev->request_queue; + + hpb->pre_req = kzalloc(sizeof(struct ufshpb_req) * qd, GFP_KERNEL); + if (!hpb->pre_req) + goto release_mem; + + /* + * q->cmd_size: sizeof(struct scsi_cmd) + shost->hostt->cmd_size + */ + for (i = 0; i < qd; i++) { + pre_req = hpb->pre_req + i; + INIT_LIST_HEAD(&pre_req->list_req); + pre_req->req = kzalloc(sizeof(struct request) + q->cmd_size, + GFP_KERNEL); + if (!pre_req->req) { + for (j = 0; j < i; j++) + kfree(hpb->pre_req[j].req); + goto release_mem; + } + + pre_req->bio = bio_kmalloc(GFP_KERNEL, 1); + if (!pre_req->bio) { + kfree(hpb->pre_req[i].req); + for (j = 0; j < i; j++) { + kfree(hpb->pre_req[j].req); + bio_put(hpb->pre_req[j].bio); + } + goto release_mem; + } + + pre_req->wb.m_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!pre_req->wb.m_page) { + kfree(hpb->pre_req[i].req); + bio_put(hpb->pre_req[i].bio); + for (j = 0; j < i; j++) { + kfree(hpb->pre_req[j].req); + bio_put(hpb->pre_req[j].bio); + __free_page(hpb->pre_req[j].wb.m_page); + } + goto release_mem; + } + list_add_tail(&pre_req->list_req, &hpb->lh_pre_req_free); + } + + return 0; +release_mem: + kfree(hpb->pre_req); + return -ENOMEM; +} + +static void ufshpb_find_lu_qd(struct ufshpb_lu *hpb) +{ + struct scsi_device *sdev; + struct ufs_hba *hba; + + sdev = hpb->ufsf->sdev_ufs_lu[hpb->lun]; + hba = hpb->ufsf->hba; + + /* + * ufshcd_slave_alloc(sdev) -> ufshcd_set_queue_depth(sdev) + * a lu-queue-depth compared with lu_info and hba->nutrs + * is selected in ufshcd_set_queue_depth() + */ + hpb->qd = sdev->queue_depth; + INIT_INFO("lu %d queue_depth %d", hpb->lun, hpb->qd); + if (!hpb->qd) { + hpb->qd = hba->nutrs; + INIT_INFO("lu_queue_depth is 0. we use device's queue info."); + INIT_INFO("hba->nutrs = %d", hba->nutrs); + } + + hpb->throttle_map_req = hpb->qd; + hpb->throttle_pre_req = hpb->qd; + hpb->num_inflight_map_req = 0; + hpb->num_inflight_pre_req = 0; +} + +static void ufshpb_init_lu_constant(struct ufshpb_dev_info *hpb_dev_info, + struct ufshpb_lu *hpb) +{ + unsigned long long rgn_unit_size, rgn_mem_size; + int entries_per_rgn; + + hpb->debug = false; + + ufshpb_find_lu_qd(hpb); + + /* for pre_req */ + hpb->pre_req_min_tr_len = HPB_MULTI_CHUNK_LOW; + hpb->pre_req_max_tr_len = HPB_MULTI_CHUNK_HIGH; + hpb->ctx_id_ticket = 0; + + /* From descriptors */ + rgn_unit_size = (unsigned long long) + SECTOR * (0x01 << hpb_dev_info->hpb_rgn_size); + rgn_mem_size = rgn_unit_size / BLOCK * HPB_ENTRY_SIZE; + + hpb->srgn_unit_size = (unsigned long long) + SECTOR * (0x01 << hpb_dev_info->hpb_srgn_size); + hpb->srgn_mem_size = + hpb->srgn_unit_size / BLOCK * HPB_ENTRY_SIZE; + + hpb->hpb_ver = hpb_dev_info->hpb_ver; + + /* relation : lu <-> region <-> sub region <-> entry */ + entries_per_rgn = rgn_mem_size / HPB_ENTRY_SIZE; + hpb->entries_per_srgn = hpb->srgn_mem_size / HPB_ENTRY_SIZE; + hpb->srgns_per_rgn = rgn_mem_size / hpb->srgn_mem_size; + + /* + * regions_per_lu = (lu_num_blocks * 4096) / region_unit_size + * = (lu_num_blocks * HPB_ENTRY_SIZE) / region_mem_size + */ + hpb->rgns_per_lu = + ((unsigned long long)hpb->lu_num_blocks + + (rgn_mem_size / HPB_ENTRY_SIZE) - 1) + / (rgn_mem_size / HPB_ENTRY_SIZE); + hpb->srgns_per_lu = + ((unsigned long long)hpb->lu_num_blocks + + (hpb->srgn_mem_size / HPB_ENTRY_SIZE) - 1) + / (hpb->srgn_mem_size / HPB_ENTRY_SIZE); + + /* mempool info */ + hpb->mpage_bytes = OS_PAGE_SIZE; + hpb->mpages_per_srgn = hpb->srgn_mem_size / hpb->mpage_bytes; + + /* Bitmask Info. */ + hpb->dwords_per_srgn = hpb->entries_per_srgn / BITS_PER_DWORD; + hpb->entries_per_rgn_shift = ffs(entries_per_rgn) - 1; + hpb->entries_per_rgn_mask = entries_per_rgn - 1; + hpb->entries_per_srgn_shift = ffs(hpb->entries_per_srgn) - 1; + hpb->entries_per_srgn_mask = hpb->entries_per_srgn - 1; + + INIT_INFO("===== From Device Descriptor! ====="); + INIT_INFO("hpb_region_size = %d, hpb_subregion_size = %d", + hpb_dev_info->hpb_rgn_size, + hpb_dev_info->hpb_srgn_size); + INIT_INFO("===== Constant Values(LU) ====="); + INIT_INFO("region_unit_size = %lld, region_mem_size %lld", + rgn_unit_size, rgn_mem_size); + INIT_INFO("subregion_unit_size = %lld, subregion_mem_size %d", + hpb->srgn_unit_size, hpb->srgn_mem_size); + + INIT_INFO("lu_num_blocks = %d", hpb->lu_num_blocks); + INIT_INFO("regions_per_lu = %d, subregions_per_lu = %d", + hpb->rgns_per_lu, hpb->srgns_per_lu); + + INIT_INFO("subregions_per_region = %d", hpb->srgns_per_rgn); + INIT_INFO("entries_per_region %u shift %u mask 0x%X", + entries_per_rgn, hpb->entries_per_rgn_shift, + hpb->entries_per_rgn_mask); + INIT_INFO("entries_per_subregion %u shift %u mask 0x%X", + hpb->entries_per_srgn, hpb->entries_per_srgn_shift, + hpb->entries_per_srgn_mask); + INIT_INFO("mpages_per_subregion : %d", hpb->mpages_per_srgn); + INIT_INFO("==================================="); +} + +static int ufshpb_lu_hpb_init(struct ufsf_feature *ufsf, int lun) +{ + struct ufshpb_lu *hpb = ufsf->ufshpb_lup[lun]; + struct ufshpb_region *rgn_table, *rgn; + struct ufshpb_subregion *srgn; + int rgn_idx, srgn_idx, total_srgn_cnt, srgn_cnt, i, ret = 0; + bool do_work_handler = false; + + ufshpb_init_lu_constant(&ufsf->hpb_dev_info, hpb); + + rgn_table = kzalloc(sizeof(struct ufshpb_region) * hpb->rgns_per_lu, + GFP_KERNEL); + if (!rgn_table) { + ret = -ENOMEM; + goto out; + } + + INIT_INFO("active_region_table bytes: %lu", + (sizeof(struct ufshpb_region) * hpb->rgns_per_lu)); + + hpb->rgn_tbl = rgn_table; + + spin_lock_init(&hpb->hpb_lock); + spin_lock_init(&hpb->rsp_list_lock); + + /* init lru information */ + INIT_LIST_HEAD(&hpb->lru_info.lh_lru_rgn); + hpb->lru_info.selection_type = LRU; + + INIT_LIST_HEAD(&hpb->lh_pinned_srgn); + INIT_LIST_HEAD(&hpb->lh_act_srgn); + INIT_LIST_HEAD(&hpb->lh_inact_rgn); + + INIT_LIST_HEAD(&hpb->lh_map_ctx_free); + + ufshpb_init_jobs(hpb); + + ret = ufshpb_map_req_mempool_init(hpb); + if (ret) { + ERR_MSG("map_req_mempool init fail!"); + goto release_rgn_table; + } + + ret = ufshpb_pre_req_mempool_init(hpb); + if (ret) { + ERR_MSG("pre_req_mempool init fail!"); + goto release_map_req_mempool; + } + + ret = ufshpb_table_mempool_init(hpb); + if (ret) { + ERR_MSG("ppn table mempool init fail!"); + ufshpb_table_mempool_remove(hpb); + goto release_pre_req_mempool; + } + + total_srgn_cnt = hpb->srgns_per_lu; + INIT_INFO("total_subregion_count: %d", total_srgn_cnt); + for (rgn_idx = 0, srgn_cnt = 0; rgn_idx < hpb->rgns_per_lu; + rgn_idx++, total_srgn_cnt -= srgn_cnt) { + rgn = rgn_table + rgn_idx; + rgn->rgn_idx = rgn_idx; + + INIT_LIST_HEAD(&rgn->list_inact_rgn); + + /* init lru region information*/ + INIT_LIST_HEAD(&rgn->list_lru_rgn); + + srgn_cnt = min(total_srgn_cnt, hpb->srgns_per_rgn); + + ret = ufshpb_alloc_subregion_tbl(hpb, rgn, srgn_cnt); + if (ret) + goto release_srgns; + ufshpb_init_subregion_tbl(hpb, rgn); + + if (ufshpb_is_pinned_region(hpb, rgn_idx)) { + ret = ufshpb_init_pinned_active_region(hpb, rgn); + if (ret) + goto release_srgns; + + do_work_handler = true; + } else { + rgn->rgn_state = HPBREGION_INACTIVE; + } + } + + if (total_srgn_cnt != 0) { + ERR_MSG("error total_subregion_count: %d", + total_srgn_cnt); + goto release_srgns; + } + + if (do_work_handler) + schedule_work(&hpb->ufshpb_work); + + /* + * even if creating sysfs failed, ufshpb could run normally. + * so we don't deal with error handling + */ + ufshpb_create_sysfs(ufsf, hpb); + + return 0; +release_srgns: + for (i = 0; i < rgn_idx; i++) { + rgn = rgn_table + i; + if (rgn->srgn_tbl) { + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; + srgn_idx++) { + srgn = rgn->srgn_tbl + srgn_idx; + if (srgn->mctx) + ufshpb_put_map_ctx(hpb, srgn->mctx); + } + kfree(rgn->srgn_tbl); + } + } + + ufshpb_table_mempool_remove(hpb); +release_pre_req_mempool: + ufshpb_pre_req_mempool_remove(hpb); +release_map_req_mempool: + ufshpb_map_req_mempool_remove(hpb); +release_rgn_table: + kfree(rgn_table); +out: + return ret; +} + +static inline int ufshpb_version_check(struct ufshpb_dev_info *hpb_dev_info) +{ + INIT_INFO("Support HPB Spec : Driver = %.4X Device = %.4X", + UFSHPB_VER, hpb_dev_info->hpb_ver); + + INIT_INFO("HPB Driver Version : %.4X", UFSHPB_DD_VER); + + if (hpb_dev_info->hpb_ver != UFSHPB_VER) { + ERR_MSG("ERROR: HPB Spec Version mismatch. So HPB disabled."); + return -ENODEV; + } + return 0; +} + +void ufshpb_get_dev_info(struct ufshpb_dev_info *hpb_dev_info, u8 *desc_buf) +{ + int ret; + + hpb_dev_info->hpb_device = false; + + if (desc_buf[DEVICE_DESC_PARAM_UFS_FEAT] & UFS_FEATURE_SUPPORT_HPB_BIT) + INIT_INFO("bUFSFeaturesSupport: HPB is set"); + else { + INIT_INFO("bUFSFeaturesSupport: HPB not support"); + return; + } + + hpb_dev_info->hpb_ver = LI_EN_16(desc_buf + DEVICE_DESC_PARAM_HPB_VER); + + ret = ufshpb_version_check(hpb_dev_info); + if (!ret) + hpb_dev_info->hpb_device = true; +} + +void ufshpb_get_geo_info(struct ufshpb_dev_info *hpb_dev_info, u8 *geo_buf) +{ + hpb_dev_info->hpb_number_lu = geo_buf[GEOMETRY_DESC_HPB_NUMBER_LU]; + if (hpb_dev_info->hpb_number_lu == 0) { + ERR_MSG("Don't have a lu for hpb."); + hpb_dev_info->hpb_device = false; + return; + } + + hpb_dev_info->hpb_rgn_size = geo_buf[GEOMETRY_DESC_HPB_REGION_SIZE]; + hpb_dev_info->hpb_srgn_size = geo_buf[GEOMETRY_DESC_HPB_SUBREGION_SIZE]; + hpb_dev_info->hpb_device_max_active_rgns = + LI_EN_16(geo_buf + GEOMETRY_DESC_HPB_DEVICE_MAX_ACTIVE_REGIONS); + + INIT_INFO("[48] bHPBRegionSiz %u", hpb_dev_info->hpb_rgn_size); + INIT_INFO("[49] bHPBNumberLU %u", hpb_dev_info->hpb_number_lu); + INIT_INFO("[4A] bHPBSubRegionSize %u", hpb_dev_info->hpb_srgn_size); + INIT_INFO("[4B:4C] wDeviceMaxActiveHPBRegions %u", + hpb_dev_info->hpb_device_max_active_rgns); + + ufshpb_init_constant(); +} + +int ufshpb_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *unit_buf) +{ + struct ufsf_lu_desc lu_desc; + struct ufshpb_lu *hpb; + + lu_desc.lu_enable = unit_buf[UNIT_DESC_PARAM_LU_ENABLE]; + lu_desc.lu_queue_depth = unit_buf[UNIT_DESC_PARAM_LU_Q_DEPTH]; + lu_desc.lu_logblk_size = unit_buf[UNIT_DESC_PARAM_LOGICAL_BLK_SIZE]; + lu_desc.lu_logblk_cnt = + LI_EN_64(unit_buf + UNIT_DESC_PARAM_LOGICAL_BLK_COUNT); + lu_desc.lu_max_active_hpb_rgns = + LI_EN_16(unit_buf + UNIT_DESC_HPB_LU_MAX_ACTIVE_REGIONS); + lu_desc.lu_hpb_pinned_rgn_startidx = + LI_EN_16(unit_buf + UNIT_DESC_HPB_LU_PIN_REGION_START_OFFSET); + lu_desc.lu_num_hpb_pinned_rgns = + LI_EN_16(unit_buf + UNIT_DESC_HPB_LU_NUM_PIN_REGIONS); + + if (lu_desc.lu_num_hpb_pinned_rgns > 0) { + lu_desc.lu_hpb_pinned_end_offset = + lu_desc.lu_hpb_pinned_rgn_startidx + + lu_desc.lu_num_hpb_pinned_rgns - 1; + } else + lu_desc.lu_hpb_pinned_end_offset = -1; + + INIT_INFO("LUN(%d) [0A] bLogicalBlockSize %d", + lun, lu_desc.lu_logblk_size); + INIT_INFO("LUN(%d) [0B] qLogicalBlockCount %llu", + lun, lu_desc.lu_logblk_cnt); + INIT_INFO("LUN(%d) [03] bLuEnable %d", lun, lu_desc.lu_enable); + INIT_INFO("LUN(%d) [06] bLuQueueDepth %d", lun, lu_desc.lu_queue_depth); + INIT_INFO("LUN(%d) [23:24] wLUMaxActiveHPBRegions %d", + lun, lu_desc.lu_max_active_hpb_rgns); + INIT_INFO("LUN(%d) [25:26] wHPBPinnedRegionStartIdx %d", + lun, lu_desc.lu_hpb_pinned_rgn_startidx); + INIT_INFO("LUN(%d) [27:28] wNumHPBPinnedRegions %d", + lun, lu_desc.lu_num_hpb_pinned_rgns); + INIT_INFO("LUN(%d) PINNED Start %d End %d", + lun, lu_desc.lu_hpb_pinned_rgn_startidx, + lu_desc.lu_hpb_pinned_end_offset); + + ufsf->ufshpb_lup[lun] = NULL; + + if (lu_desc.lu_enable == 0x02) { + ufsf->ufshpb_lup[lun] = kzalloc(sizeof(struct ufshpb_lu), + GFP_KERNEL); + if (!ufsf->ufshpb_lup[lun]) + return -ENOMEM; + + hpb = ufsf->ufshpb_lup[lun]; + hpb->ufsf = ufsf; + hpb->lun = lun; + hpb->lu_num_blocks = lu_desc.lu_logblk_cnt; + hpb->lu_max_active_rgns = lu_desc.lu_max_active_hpb_rgns; + hpb->lru_info.max_lru_active_cnt = + lu_desc.lu_max_active_hpb_rgns - + lu_desc.lu_num_hpb_pinned_rgns; + hpb->lu_pinned_rgn_startidx = + lu_desc.lu_hpb_pinned_rgn_startidx; + hpb->lu_pinned_end_offset = lu_desc.lu_hpb_pinned_end_offset; + } else { + INIT_INFO("===== LU %d is hpb-disabled.", lun); + return -ENODEV; + } + + return 0; +} + +static void ufshpb_error_handler(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + + ufsf = container_of(work, struct ufsf_feature, ufshpb_eh_work); + + WARNING_MSG("driver has failed. but UFSHCD can run without UFSHPB"); + WARNING_MSG("UFSHPB will be removed from the kernel"); + + ufshpb_release(ufsf, HPB_FAILED); +} + +static int ufshpb_init(struct ufsf_feature *ufsf) +{ + int lun, ret; + int hpb_enabled_lun = 0; + + seq_scan_lu(lun) { + if (!ufsf->ufshpb_lup[lun]) + continue; + + /* + * HPB need info about request queue in order to issue + * RB-CMD for pinned region. + */ + if (!ufsf->sdev_ufs_lu[lun]) { + WARNING_MSG("warn: lun %d don't have scsi_device", lun); + continue; + } + + ret = ufshpb_lu_hpb_init(ufsf, lun); + if (ret) { + if (ret == -ENODEV) + continue; + else + goto out_free_mem; + } + hpb_enabled_lun++; + } + + if (hpb_enabled_lun == 0) { + ERR_MSG("No UFSHPB LU to init"); + ret = -ENODEV; + goto out_free_mem; + } + + INIT_WORK(&ufsf->ufshpb_reset_work, ufshpb_reset_handler); + INIT_WORK(&ufsf->ufshpb_eh_work, ufshpb_error_handler); + + kref_init(&ufsf->ufshpb_kref); + ufsf->ufshpb_state = HPB_PRESENT; + ufsf->issue_ioctl = false; + + seq_scan_lu(lun) + if (ufsf->ufshpb_lup[lun]) + INFO_MSG("UFSHPB LU %d working", lun); + + return 0; +out_free_mem: + seq_scan_lu(lun) + kfree(ufsf->ufshpb_lup[lun]); + + ufsf->ufshpb_state = HPB_FAILED; + return ret; +} + +static void ufshpb_drop_retry_list(struct ufshpb_lu *hpb) +{ + struct ufshpb_req *map_req, *next; + unsigned long flags; + + if (list_empty(&hpb->lh_map_req_retry)) + return; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + list_for_each_entry_safe(map_req, next, &hpb->lh_map_req_retry, + list_req) { + INFO_MSG("drop map_req %p ( %d - %d )", map_req, + map_req->rb.rgn_idx, map_req->rb.srgn_idx); + + list_del_init(&map_req->list_req); + + ufshpb_put_map_req(hpb, map_req); + } + spin_unlock_irqrestore(&hpb->hpb_lock, flags); +} + +static void ufshpb_drop_rsp_lists(struct ufshpb_lu *hpb) +{ + struct ufshpb_region *rgn, *next_rgn; + struct ufshpb_subregion *srgn, *next_srgn; + unsigned long flags; + + spin_lock_irqsave(&hpb->rsp_list_lock, flags); + list_for_each_entry_safe(rgn, next_rgn, &hpb->lh_inact_rgn, + list_inact_rgn) { + list_del_init(&rgn->list_inact_rgn); + } + + list_for_each_entry_safe(srgn, next_srgn, &hpb->lh_act_srgn, + list_act_srgn) { + list_del_init(&srgn->list_act_srgn); + } + spin_unlock_irqrestore(&hpb->rsp_list_lock, flags); +} + +static void ufshpb_destroy_subregion_tbl(struct ufshpb_lu *hpb, + struct ufshpb_region *rgn) +{ + int srgn_idx; + + for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) { + struct ufshpb_subregion *srgn; + + srgn = rgn->srgn_tbl + srgn_idx; + srgn->srgn_state = HPBSUBREGION_UNUSED; + + ufshpb_put_map_ctx(hpb, srgn->mctx); + } + + kfree(rgn->srgn_tbl); +} + +static void ufshpb_destroy_region_tbl(struct ufshpb_lu *hpb) +{ + int rgn_idx; + + RELEASE_INFO("Start"); + + for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { + struct ufshpb_region *rgn; + + rgn = hpb->rgn_tbl + rgn_idx; + if (rgn->rgn_state == HPBREGION_PINNED || + rgn->rgn_state == HPBREGION_ACTIVE) { + rgn->rgn_state = HPBREGION_INACTIVE; + + ufshpb_destroy_subregion_tbl(hpb, rgn); + } + } + + ufshpb_table_mempool_remove(hpb); + kfree(hpb->rgn_tbl); + + RELEASE_INFO("End"); +} + +void ufshpb_release(struct ufsf_feature *ufsf, int state) +{ + struct ufshpb_lu *hpb; + int lun; + + RELEASE_INFO("start release"); + ufsf->ufshpb_state = HPB_FAILED; + + RELEASE_INFO("kref count %d", + atomic_read(&ufsf->ufshpb_kref.refcount.refs)); + + seq_scan_lu(lun) { + hpb = ufsf->ufshpb_lup[lun]; + + RELEASE_INFO("lun %d %p", lun, hpb); + + ufsf->ufshpb_lup[lun] = NULL; + + if (!hpb) + continue; + + ufshpb_cancel_jobs(hpb); + + ufshpb_destroy_region_tbl(hpb); + if (hpb->alloc_mctx != 0) + WARNING_MSG("warning: alloc_mctx %d", hpb->alloc_mctx); + + ufshpb_map_req_mempool_remove(hpb); + + ufshpb_pre_req_mempool_remove(hpb); + + ufshpb_remove_sysfs(hpb); + + kfree(hpb); + } + + ufsf->ufshpb_state = state; + + RELEASE_INFO("end release"); +} + +static void ufshpb_reset(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->ufshpb_lup[lun]; + if (hpb) { + INFO_MSG("UFSHPB lun %d reset", lun); + ufshpb_cancel_jobs(hpb); + ufshpb_drop_retry_list(hpb); + ufshpb_drop_rsp_lists(hpb); + } + } + + ufsf->ufshpb_state = HPB_PRESENT; +} + +static inline int ufshpb_wait_kref_init_value(struct ufsf_feature *ufsf) +{ + return (atomic_read(&ufsf->ufshpb_kref.refcount.refs) == 1); +} + +void ufshpb_reset_handler(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + int ret; + + ufsf = container_of(work, struct ufsf_feature, ufshpb_reset_work); + + init_waitqueue_head(&ufsf->wait_hpb); + + ret = wait_event_timeout(ufsf->wait_hpb, + ufshpb_wait_kref_init_value(ufsf), + msecs_to_jiffies(15000)); + if (ret == 0) + ERR_MSG("UFSHPB kref is not init_value(=1). kref count = %d", + atomic_read(&ufsf->ufshpb_kref.refcount.refs)); + + INIT_INFO("HPB_RESET_START"); + + ufshpb_reset(ufsf); +} + +static inline int ufshpb_probe_lun_done(struct ufsf_feature *ufsf) +{ + return (ufsf->num_lu == ufsf->slave_conf_cnt); +} + +void ufshpb_init_handler(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + int ret; + + ufsf = container_of(work, struct ufsf_feature, ufshpb_init_work); + + init_waitqueue_head(&ufsf->wait_hpb); + + ret = wait_event_timeout(ufsf->wait_hpb, + ufshpb_probe_lun_done(ufsf), + msecs_to_jiffies(10000)); + if (ret == 0) + ERR_MSG("Probing LU is not fully complete."); + + INIT_INFO("HPB_INIT_START"); + + ret = ufshpb_init(ufsf); + if (ret) + ERR_MSG("UFSHPB driver init failed. err %d", ret); +} + +void ufshpb_suspend(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->ufshpb_lup[lun]; + if (hpb) { + ufshpb_cancel_jobs(hpb); + } + } +} + +void ufshpb_resume(struct ufsf_feature *ufsf) +{ + struct ufshpb_lu *hpb; + int lun; + + seq_scan_lu(lun) { + hpb = ufsf->ufshpb_lup[lun]; + if (hpb) { + bool do_workq = false; + bool do_retry_work = false; + + do_workq = !ufshpb_is_empty_rsp_lists(hpb); + do_retry_work = + !list_empty_careful(&hpb->lh_map_req_retry); + + if (do_workq) + schedule_work(&hpb->ufshpb_task_workq); + if (do_retry_work) + schedule_delayed_work(&hpb->ufshpb_retry_work, + msecs_to_jiffies(100)); + } + } +} + +static void ufshpb_stat_init(struct ufshpb_lu *hpb) +{ + atomic64_set(&hpb->hit, 0); + atomic64_set(&hpb->miss, 0); + atomic64_set(&hpb->rb_noti_cnt, 0); + atomic64_set(&hpb->rb_active_cnt, 0); + atomic64_set(&hpb->rb_inactive_cnt, 0); + atomic64_set(&hpb->map_req_cnt, 0); + atomic64_set(&hpb->pre_req_cnt, 0); +} + +/* SYSFS functions */ +static ssize_t ufshpb_sysfs_prep_disable_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "force_hpb_read_disable %d\n", + hpb->force_disable); + + SYSFS_INFO("%s", buf); + return ret; +} + +static ssize_t ufshpb_sysfs_prep_disable_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + if (value == 1) + hpb->force_disable = true; + else if (value == 0) + hpb->force_disable = false; + + SYSFS_INFO("force_hpb_read_disable %d", hpb->force_disable); + + return cnt; +} + +static ssize_t ufshpb_sysfs_map_disable_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "force_map_req_disable %d\n", + hpb->force_map_req_disable); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_map_disable_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long value; + + if (kstrtoul(buf, 0, &value)) + return -EINVAL; + + if (value > 1) + return -EINVAL; + + if (value == 1) + hpb->force_map_req_disable = true; + else if (value == 0) + hpb->force_map_req_disable = false; + + SYSFS_INFO("force_map_req_disable %d", hpb->force_map_req_disable); + + return cnt; +} + +static ssize_t ufshpb_sysfs_throttle_map_req_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "throttle_map_req %d\n", + hpb->throttle_map_req); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_throttle_map_req_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long throttle_map_req; + + if (kstrtoul(buf, 0, &throttle_map_req)) + return -EINVAL; + + hpb->throttle_map_req = (int)throttle_map_req; + + SYSFS_INFO("throttle_map_req %d", hpb->throttle_map_req); + + return cnt; +} + +static ssize_t ufshpb_sysfs_throttle_pre_req_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "throttle_pre_req %d\n", + hpb->throttle_pre_req); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_throttle_pre_req_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long throttle_pre_req; + + if (kstrtoul(buf, 0, &throttle_pre_req)) + return -EINVAL; + + hpb->throttle_pre_req = (int)throttle_pre_req; + + SYSFS_INFO("throttle_pre_req %d", hpb->throttle_pre_req); + + return cnt; +} + +static ssize_t ufshpb_sysfs_pre_req_min_tr_len_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d", hpb->pre_req_min_tr_len); + SYSFS_INFO("pre_req min transfer len %d", hpb->pre_req_min_tr_len); + + return ret; +} + +static ssize_t ufshpb_sysfs_pre_req_min_tr_len_store(struct ufshpb_lu *hpb, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0) + val = 0; + + if (hpb->pre_req_max_tr_len < val || val < HPB_MULTI_CHUNK_LOW) + SYSFS_INFO("value is wrong. pre_req transfer len %d ~ %d\n", + HPB_MULTI_CHUNK_LOW, hpb->pre_req_max_tr_len); + else + hpb->pre_req_min_tr_len = val; + + SYSFS_INFO("pre_req min transfer len %d", hpb->pre_req_min_tr_len); + + return count; +} + +static ssize_t ufshpb_sysfs_pre_req_max_tr_len_show(struct ufshpb_lu *hpb, + char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "%d", hpb->pre_req_max_tr_len); + SYSFS_INFO("pre_req max transfer len %d", hpb->pre_req_max_tr_len); + + return ret; +} + +static ssize_t ufshpb_sysfs_pre_req_max_tr_len_store(struct ufshpb_lu *hpb, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (hpb->pre_req_min_tr_len > val || val > HPB_MULTI_CHUNK_HIGH) + SYSFS_INFO("value is wrong. pre_req transfer len %d ~ %d\n", + hpb->pre_req_min_tr_len, HPB_MULTI_CHUNK_HIGH); + else + hpb->pre_req_max_tr_len = val; + + SYSFS_INFO("pre_req max transfer len %d", hpb->pre_req_max_tr_len); + + return count; +} + +static ssize_t ufshpb_sysfs_debug_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "debug %d\n", hpb->debug); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_debug_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long debug; + + if (kstrtoul(buf, 0, &debug)) + return -EINVAL; + + if (debug >= 1) + hpb->debug = 1; + else + hpb->debug = 0; + + SYSFS_INFO("debug %d", hpb->debug); + + return cnt; +} + +static ssize_t ufshpb_sysfs_version_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret; + + ret = snprintf(buf, PAGE_SIZE, "HPB version %.4X D/D version %.4X\n", + hpb->hpb_ver, UFSHPB_DD_VER); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_hit_show(struct ufshpb_lu *hpb, char *buf) +{ + long long hit_cnt; + int ret; + + hit_cnt = atomic64_read(&hpb->hit); + + ret = snprintf(buf, PAGE_SIZE, "hit_count %lld\n", hit_cnt); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_miss_show(struct ufshpb_lu *hpb, char *buf) +{ + long long miss_cnt; + int ret; + + miss_cnt = atomic64_read(&hpb->miss); + + ret = snprintf(buf, PAGE_SIZE, "miss_count %lld\n", miss_cnt); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_map_req_show(struct ufshpb_lu *hpb, char *buf) +{ + long long rb_noti_cnt, rb_active_cnt, rb_inactive_cnt, map_req_cnt; + int ret; + + rb_noti_cnt = atomic64_read(&hpb->rb_noti_cnt); + rb_active_cnt = atomic64_read(&hpb->rb_active_cnt); + rb_inactive_cnt = atomic64_read(&hpb->rb_inactive_cnt); + map_req_cnt = atomic64_read(&hpb->map_req_cnt); + + ret = snprintf(buf, PAGE_SIZE, + "rb_noti %lld ACT %lld INACT %lld map_req_count %lld\n", + rb_noti_cnt, rb_active_cnt, rb_inactive_cnt, + map_req_cnt); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_pre_req_show(struct ufshpb_lu *hpb, char *buf) +{ + long long pre_req_cnt; + int ret; + + pre_req_cnt = atomic64_read(&hpb->pre_req_cnt); + + ret = snprintf(buf, PAGE_SIZE, "pre_req_count %lld\n", pre_req_cnt); + + SYSFS_INFO("%s", buf); + + return ret; +} + +static ssize_t ufshpb_sysfs_region_stat_show(struct ufshpb_lu *hpb, char *buf) +{ + int ret, pin_cnt = 0, act_cnt = 0, inact_cnt = 0, rgn_idx; + enum HPBREGION_STATE state; + + for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) { + state = hpb->rgn_tbl[rgn_idx].rgn_state; + if (state == HPBREGION_PINNED) + pin_cnt++; + else if (state == HPBREGION_ACTIVE) + act_cnt++; + else if (state == HPBREGION_INACTIVE) + inact_cnt++; + } + + ret = snprintf(buf, PAGE_SIZE, + "Total %d pinned %d active %d inactive %d\n", + hpb->rgns_per_lu, pin_cnt, act_cnt, inact_cnt); + + return ret; +} + +static ssize_t ufshpb_sysfs_count_reset_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long debug; + + if (kstrtoul(buf, 0, &debug)) + return -EINVAL; + + SYSFS_INFO("Stat Init"); + + ufshpb_stat_init(hpb); + + return cnt; +} + +static ssize_t ufshpb_sysfs_info_lba_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + struct ufshpb_region *rgn; + struct ufshpb_subregion *srgn; + unsigned long long ppn = 0; + unsigned long value, lpn, flags; + int rgn_idx, srgn_idx, srgn_offset, error = 0; + + if (kstrtoul(buf, 0, &value)) { + ERR_MSG("kstrtoul error"); + return -EINVAL; + } + + if (value > hpb->lu_num_blocks * SECTORS_PER_BLOCK) { + ERR_MSG("value %lu > lu_num_blocks %d error", + value, hpb->lu_num_blocks); + return -EINVAL; + } + + lpn = value / SECTORS_PER_BLOCK; + + ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, &srgn_offset); + + rgn = hpb->rgn_tbl + rgn_idx; + srgn = rgn->srgn_tbl + srgn_idx; + + spin_lock_irqsave(&hpb->hpb_lock, flags); + SYSFS_INFO("lba %lu lpn %lu region %d state %d subregion %d state %d", + value, lpn, rgn_idx, rgn->rgn_state, srgn_idx, + srgn->srgn_state); + + if (!ufshpb_valid_srgn(rgn, srgn)) { + SYSFS_INFO("[region %d subregion %d] has not valid hpb info.", + rgn_idx, srgn_idx); + goto out; + } + + if (!srgn->mctx) { + SYSFS_INFO("mctx is NULL"); + goto out; + } + + ppn = ufshpb_get_ppn(srgn->mctx, srgn_offset, &error); + if (error) { + SYSFS_INFO("getting ppn is fail from a page."); + goto out; + } + + SYSFS_INFO("ppn %llx is_dirty %d", ppn, + ufshpb_ppn_dirty_check(hpb, lpn, 1)); +out: + spin_unlock_irqrestore(&hpb->hpb_lock, flags); + return cnt; +} + +static ssize_t ufshpb_sysfs_info_region_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long rgn_idx; + int srgn_idx; + + if (kstrtoul(buf, 0, &rgn_idx)) + return -EINVAL; + + if (rgn_idx >= hpb->rgns_per_lu) + ERR_MSG("error region %ld max %d", rgn_idx, hpb->rgns_per_lu); + else { + SYSFS_INFO("(region state : PINNED=%d ACTIVE=%d INACTIVE=%d)", + HPBREGION_PINNED, HPBREGION_ACTIVE, + HPBREGION_INACTIVE); + + SYSFS_INFO("region %ld state %d", rgn_idx, + hpb->rgn_tbl[rgn_idx].rgn_state); + + for (srgn_idx = 0; srgn_idx < hpb->rgn_tbl[rgn_idx].srgn_cnt; + srgn_idx++) { + SYSFS_INFO("--- subregion %d state %d", srgn_idx, + hpb->rgn_tbl[rgn_idx].srgn_tbl[srgn_idx].srgn_state); + } + } + + return cnt; +} + +static ssize_t ufshpb_sysfs_ufshpb_release_store(struct ufshpb_lu *hpb, + const char *buf, size_t cnt) +{ + unsigned long value; + + SYSFS_INFO("start release function"); + + if (kstrtoul(buf, 0, &value)) { + ERR_MSG("kstrtoul error"); + return -EINVAL; + } + + if (value == 0xab) { + SYSFS_INFO("magic number %lu release start", value); + goto err_out; + } else + SYSFS_INFO("wrong magic number %lu", value); + + return cnt; +err_out: + SYSFS_INFO("ref_cnt %d", + atomic_read(&hpb->ufsf->ufshpb_kref.refcount.refs)); + ufshpb_failed(hpb, __func__); + + return cnt; +} + +static struct ufshpb_sysfs_entry ufshpb_sysfs_entries[] = { + __ATTR(hpb_read_disable, 0644, + ufshpb_sysfs_prep_disable_show, ufshpb_sysfs_prep_disable_store), + __ATTR(map_cmd_disable, 0644, + ufshpb_sysfs_map_disable_show, ufshpb_sysfs_map_disable_store), + __ATTR(throttle_map_req, 0644, + ufshpb_sysfs_throttle_map_req_show, + ufshpb_sysfs_throttle_map_req_store), + __ATTR(throttle_pre_req, 0644, + ufshpb_sysfs_throttle_pre_req_show, + ufshpb_sysfs_throttle_pre_req_store), + __ATTR(pre_req_min_tr_len, 0644, + ufshpb_sysfs_pre_req_min_tr_len_show, + ufshpb_sysfs_pre_req_min_tr_len_store), + __ATTR(pre_req_max_tr_len, 0644, + ufshpb_sysfs_pre_req_max_tr_len_show, + ufshpb_sysfs_pre_req_max_tr_len_store), + __ATTR(debug, 0644, + ufshpb_sysfs_debug_show, ufshpb_sysfs_debug_store), + __ATTR(hpb_version, 0444, ufshpb_sysfs_version_show, NULL), + __ATTR(hit_count, 0444, ufshpb_sysfs_hit_show, NULL), + __ATTR(miss_count, 0444, ufshpb_sysfs_miss_show, NULL), + __ATTR(map_req_count, 0444, ufshpb_sysfs_map_req_show, NULL), + __ATTR(pre_req_count, 0444, ufshpb_sysfs_pre_req_show, NULL), + __ATTR(region_stat_count, 0444, ufshpb_sysfs_region_stat_show, NULL), + __ATTR(count_reset, 0200, NULL, ufshpb_sysfs_count_reset_store), + __ATTR(get_info_from_lba, 0200, NULL, ufshpb_sysfs_info_lba_store), + __ATTR(get_info_from_region, 0200, NULL, + ufshpb_sysfs_info_region_store), + __ATTR(release, 0200, NULL, ufshpb_sysfs_ufshpb_release_store), + __ATTR_NULL +}; + +static ssize_t ufshpb_attr_show(struct kobject *kobj, struct attribute *attr, + char *page) +{ + struct ufshpb_sysfs_entry *entry; + struct ufshpb_lu *hpb; + ssize_t error; + + entry = container_of(attr, struct ufshpb_sysfs_entry, attr); + hpb = container_of(kobj, struct ufshpb_lu, kobj); + + if (!entry->show) + return -EIO; + + mutex_lock(&hpb->sysfs_lock); + error = entry->show(hpb, page); + mutex_unlock(&hpb->sysfs_lock); + return error; +} + +static ssize_t ufshpb_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t len) +{ + struct ufshpb_sysfs_entry *entry; + struct ufshpb_lu *hpb; + ssize_t error; + + entry = container_of(attr, struct ufshpb_sysfs_entry, attr); + hpb = container_of(kobj, struct ufshpb_lu, kobj); + + if (!entry->store) + return -EIO; + + mutex_lock(&hpb->sysfs_lock); + error = entry->store(hpb, page, len); + mutex_unlock(&hpb->sysfs_lock); + return error; +} + +static const struct sysfs_ops ufshpb_sysfs_ops = { + .show = ufshpb_attr_show, + .store = ufshpb_attr_store, +}; + +static struct kobj_type ufshpb_ktype = { + .sysfs_ops = &ufshpb_sysfs_ops, + .release = NULL, +}; + +static int ufshpb_create_sysfs(struct ufsf_feature *ufsf, struct ufshpb_lu *hpb) +{ + struct device *dev = ufsf->hba->dev; + struct ufshpb_sysfs_entry *entry; + int err; + + hpb->sysfs_entries = ufshpb_sysfs_entries; + + ufshpb_stat_init(hpb); + + kobject_init(&hpb->kobj, &ufshpb_ktype); + mutex_init(&hpb->sysfs_lock); + + INIT_INFO("ufshpb creates sysfs lu %d %p dev->kobj %p", hpb->lun, + &hpb->kobj, &dev->kobj); + + err = kobject_add(&hpb->kobj, kobject_get(&dev->kobj), + "ufshpb_lu%d", hpb->lun); + if (!err) { + for (entry = hpb->sysfs_entries; entry->attr.name != NULL; + entry++) { + INIT_INFO("ufshpb_lu%d sysfs attr creates: %s", + hpb->lun, entry->attr.name); + if (sysfs_create_file(&hpb->kobj, &entry->attr)) + break; + } + INIT_INFO("ufshpb_lu%d sysfs adds uevent", hpb->lun); + kobject_uevent(&hpb->kobj, KOBJ_ADD); + } + + return err; +} + +static int ufshpb_remove_sysfs(struct ufshpb_lu *hpb) +{ + struct ufshpb_sysfs_entry *entry; + + for (entry = hpb->sysfs_entries; entry->attr.name != NULL; + entry++) { + INIT_INFO("ufshpb_lu%d sysfs attr removes: %s", + hpb->lun, entry->attr.name); + sysfs_remove_file(&hpb->kobj, &entry->attr); + } + kobject_uevent(&hpb->kobj, KOBJ_REMOVE); + + INIT_INFO("ufshpb removes sysfs lu %d %p ", hpb->lun, &hpb->kobj); + kobject_del(&hpb->kobj); + + return 0; +} diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h new file mode 100644 index 0000000000000000000000000000000000000000..8fa52d1d5741f00474862391fc566a7612d504c0 --- /dev/null +++ b/drivers/scsi/ufs/ufshpb.h @@ -0,0 +1,324 @@ +/* + * Universal Flash Storage Host Performance Booster + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * 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. + * See the COPYING file in the top-level directory or visit + * + * + * 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. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSHPB_H_ +#define _UFSHPB_H_ + +#include +#include +#include +#include +#include +#include + +#include "../../../block/blk.h" +#include "../scsi_priv.h" + +/* Version info*/ +#define UFSHPB_VER 0x0200 +#define UFSHPB_DD_VER 0x0221 + +/* Constant value*/ +#define MAX_ACTIVE_NUM 2 +#define MAX_INACTIVE_NUM 2 + +#define HPB_ENTRY_SIZE 0x08 +#define HPB_ENTREIS_PER_OS_PAGE (OS_PAGE_SIZE / HPB_ENTRY_SIZE) + +#define RETRY_DELAY_MS 5000 + +/* HPB Support Chunk Size */ +#define HPB_MULTI_CHUNK_LOW 9 +#define HPB_MULTI_CHUNK_HIGH 128 + +#define MAX_HPB_CONTEXT_ID 0x7f + +/* Description */ +#define UFS_FEATURE_SUPPORT_HPB_BIT 0x80 + +/* Response UPIU types */ +#define HPB_RSP_NONE 0x00 +#define HPB_RSP_REQ_REGION_UPDATE 0x01 + +/* Vender defined OPCODE */ +#define UFSHPB_READ_BUFFER 0xF9 +#define UFSHPB_WRITE_BUFFER 0xFA + +#define UFSHPB_GROUP_NUMBER 0x11 +#define UFSHPB_READ_BUFFER_ID 0x01 +#define UFSHPB_WRITE_BUFFER_ID 0x02 +#define TRANSFER_LEN 0x01 + +#define DEV_DATA_SEG_LEN 0x14 +#define DEV_SENSE_SEG_LEN 0x12 +#define DEV_DES_TYPE 0x80 +#define DEV_ADDITIONAL_LEN 0x10 + +/* For read10 debug */ +#define READ10_DEBUG_LUN 0x7F +#define READ10_DEBUG_LBA 0x48504230 + +/* + * UFSHPB DEBUG + */ + +#define HPB_DEBUG(hpb, msg, args...) \ + do { if (hpb->debug) \ + printk(KERN_ERR "%s:%d " msg "\n", \ + __func__, __LINE__, ##args); \ + } while (0) + +#define TMSG_CMD(hpb, msg, rq, rgn, srgn) \ + do { if (hpb->ufsf->sdev_ufs_lu[hpb->lun] && \ + hpb->ufsf->sdev_ufs_lu[hpb->lun]->request_queue) \ + blk_add_trace_msg( \ + hpb->ufsf->sdev_ufs_lu[hpb->lun]->request_queue,\ + "%llu + %u " msg " %d - %d", \ + (unsigned long long) blk_rq_pos(rq), \ + (unsigned int) blk_rq_sectors(rq), rgn, srgn); \ + } while (0) + +enum UFSHPB_STATE { + HPB_PRESENT = 1, + HPB_FAILED = -2, + HPB_NEED_INIT = 0, + HPB_RESET = -3, +}; + +enum HPBREGION_STATE { + HPBREGION_INACTIVE, HPBREGION_ACTIVE, HPBREGION_PINNED, +}; + +enum HPBSUBREGION_STATE { + HPBSUBREGION_UNUSED, + HPBSUBREGION_DIRTY, + HPBSUBREGION_CLEAN, + HPBSUBREGION_ISSUED, +}; + +struct ufshpb_dev_info { + bool hpb_device; + int hpb_number_lu; + int hpb_ver; + int hpb_rgn_size; + int hpb_srgn_size; + int hpb_device_max_active_rgns; +}; + +struct ufshpb_active_field { + __be16 active_rgn; + __be16 active_srgn; +}; + +struct ufshpb_rsp_field { + __be16 sense_data_len; + u8 desc_type; + u8 additional_len; + u8 hpb_type; + u8 reserved; + u8 active_rgn_cnt; + u8 inactive_rgn_cnt; + struct ufshpb_active_field hpb_active_field[2]; + __be16 hpb_inactive_field[2]; +}; + +struct ufshpb_map_ctx { + struct page **m_page; + unsigned int *ppn_dirty; + + struct list_head list_table; +}; + +struct ufshpb_subregion { + struct ufshpb_map_ctx *mctx; + enum HPBSUBREGION_STATE srgn_state; + int rgn_idx; + int srgn_idx; + + /* below information is used by rsp_list */ + struct list_head list_act_srgn; +}; + +struct ufshpb_region { + struct ufshpb_subregion *srgn_tbl; + enum HPBREGION_STATE rgn_state; + int rgn_idx; + int srgn_cnt; + + /* below information is used by rsp_list */ + struct list_head list_inact_rgn; + + /* below information is used by lru */ + struct list_head list_lru_rgn; +}; + +struct ufshpb_req { + struct request *req; + struct bio *bio; + struct ufshpb_lu *hpb; + struct list_head list_req; + void (*end_io)(struct request *rq, int err); + void *end_io_data; + char sense[SCSI_SENSE_BUFFERSIZE]; + + union { + struct { + struct ufshpb_map_ctx *mctx; + unsigned int rgn_idx; + unsigned int srgn_idx; + unsigned int lun; + } rb; + struct { + struct page *m_page; + unsigned int len; + unsigned long lpn; + } wb; + }; +}; + +enum selection_type { + LRU = 1, +}; + +struct victim_select_info { + int selection_type; + struct list_head lh_lru_rgn; + int max_lru_active_cnt; /* supported hpb #region - pinned #region */ + atomic64_t active_cnt; +}; + +struct ufshpb_lu { + struct ufsf_feature *ufsf; + int lun; + int qd; + struct ufshpb_region *rgn_tbl; + + spinlock_t hpb_lock; + + struct ufshpb_req *map_req; + int num_inflight_map_req; + int throttle_map_req; + struct list_head lh_map_req_free; + struct list_head lh_map_req_retry; + struct list_head lh_map_ctx_free; + + spinlock_t rsp_list_lock; + struct list_head lh_pinned_srgn; + struct list_head lh_act_srgn; + struct list_head lh_inact_rgn; + + struct kobject kobj; + struct mutex sysfs_lock; + struct ufshpb_sysfs_entry *sysfs_entries; + + struct ufshpb_req *pre_req; + int num_inflight_pre_req; + int throttle_pre_req; + struct list_head lh_pre_req_free; + struct list_head lh_pre_req_dummy; /* dummy for blk_start_requests() */ + int ctx_id_ticket; + int pre_req_min_tr_len; + int pre_req_max_tr_len; + + struct work_struct ufshpb_work; + struct delayed_work ufshpb_retry_work; + struct work_struct ufshpb_task_workq; + + /* for selecting victim */ + struct victim_select_info lru_info; + + int hpb_ver; + int lu_max_active_rgns; + int lu_pinned_rgn_startidx; + int lu_pinned_end_offset; + int lu_num_pinned_rgns; + int srgns_per_lu; + int rgns_per_lu; + int srgns_per_rgn; + int srgn_mem_size; + int entries_per_rgn_shift; + int entries_per_rgn_mask; + int entries_per_srgn; + int entries_per_srgn_shift; + int entries_per_srgn_mask; + int dwords_per_srgn; + unsigned long long srgn_unit_size; + int mpage_bytes; + int mpages_per_srgn; + int lu_num_blocks; + + /* for debug */ + int alloc_mctx; + int debug_free_table; + bool force_disable; + bool force_map_req_disable; + bool debug; + atomic64_t hit; + atomic64_t miss; + atomic64_t rb_noti_cnt; + atomic64_t rb_active_cnt; + atomic64_t rb_inactive_cnt; + atomic64_t map_req_cnt; + atomic64_t pre_req_cnt; +}; + +struct ufshpb_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct ufshpb_lu *hpb, char *buf); + ssize_t (*store)(struct ufshpb_lu *hpb, const char *, size_t); +}; + +struct ufs_hba; +struct ufshcd_lrb; + +int ufshpb_prepare_pre_req(struct ufsf_feature *ufsf, struct scsi_cmnd *cmd, + int lun); +int ufshpb_prepare_add_lrbp(struct ufsf_feature *ufsf, int add_tag); +void ufshpb_end_pre_req(struct ufsf_feature *ufsf, struct request *req); +void ufshpb_get_dev_info(struct ufshpb_dev_info *hpb_dev_info, u8 *desc_buf); +void ufshpb_get_geo_info(struct ufshpb_dev_info *hpb_dev_info, u8 *geo_buf); +int ufshpb_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *unit_buf); +void ufshpb_init_handler(struct work_struct *work); +void ufshpb_reset_handler(struct work_struct *work); +void ufshpb_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufshpb_rsp_upiu(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufshpb_release(struct ufsf_feature *ufsf, int state); +int ufshpb_issue_req_dev_ctx(struct ufshpb_lu *hpb, unsigned char *buf, + int buf_length); +void ufshpb_resume(struct ufsf_feature *ufsf); +void ufshpb_suspend(struct ufsf_feature *ufsf); +#endif /* End of Header */ diff --git a/drivers/scsi/ufs/ufstw.c b/drivers/scsi/ufs/ufstw.c new file mode 100644 index 0000000000000000000000000000000000000000..51957a9eb8715e7c1b35dc3c6bcf47aa17f425f2 --- /dev/null +++ b/drivers/scsi/ufs/ufstw.c @@ -0,0 +1,1594 @@ +/* + * Universal Flash Storage Turbo Write + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * 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. + * See the COPYING file in the top-level directory or visit + * + * + * 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. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#include + +#include "ufshcd.h" +#include "ufstw.h" + +static int ufstw_create_sysfs(struct ufsf_feature *ufsf, struct ufstw_lu *tw); +static int ufstw_clear_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res); +static int ufstw_read_lu_attr(struct ufstw_lu *tw, u8 idn, u32 *attr_val); + +static inline void ufstw_lu_get(struct ufstw_lu *tw) +{ + kref_get(&tw->ufsf->tw_kref); +} + +static inline void ufstw_lu_put(struct ufstw_lu *tw) +{ + kref_put(&tw->ufsf->tw_kref, ufstw_release); +} + +static inline bool ufstw_is_write_lrbp(struct ufshcd_lrb *lrbp) +{ + if (lrbp->cmd->cmnd[0] == WRITE_10 || lrbp->cmd->cmnd[0] == WRITE_16) + return true; + + return false; +} + +static int ufstw_switch_mode(struct ufstw_lu *tw, int tw_mode) +{ + int ret = 0; + + atomic_set(&tw->tw_mode, tw_mode); + if (tw->tw_enable) + ret = ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, + &tw->tw_enable); + return ret; +} + +static void ufstw_switch_disable_mode(struct ufstw_lu *tw) +{ + WARNING_MSG("dTurboWriteBUfferLifeTImeEst 0x%X", tw->tw_lifetime_est); + WARNING_MSG("tw-mode will change to disable-mode.."); + + mutex_lock(&tw->mode_lock); + ufstw_switch_mode(tw, TW_MODE_DISABLED); + mutex_unlock(&tw->mode_lock); +} + +static void ufstw_lifetime_work_fn(struct work_struct *work) +{ + struct ufstw_lu *tw; + + tw = container_of(work, struct ufstw_lu, tw_lifetime_work); + + ufstw_lu_get(tw); + + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + INFO_MSG("tw_state != TW_PRESENT (%d)", + atomic_read(&tw->ufsf->tw_state)); + goto out; + } + + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, + &tw->tw_lifetime_est)) + goto out; + +#if defined(CONFIG_UFSTW_IGNORE_GUARANTEE_BIT) + if (tw->tw_lifetime_est & MASK_UFSTW_LIFETIME_NOT_GUARANTEE) { + WARNING_MSG("warn: lun %d - dTurboWriteBufferLifeTimeEst[31] == 1", tw->lun); + WARNING_MSG("Device not guarantee the lifetime of Turbo Write Buffer"); + WARNING_MSG("but we will ignore them for PoC"); + } +#else + if (tw->tw_lifetime_est & MASK_UFSTW_LIFETIME_NOT_GUARANTEE) { + WARNING_MSG("warn: lun %d - dTurboWriteBufferLifeTimeEst[31] == 1", tw->lun); + WARNING_MSG("Device not guarantee the lifetime of Turbo Write Buffer"); + WARNING_MSG("So tw_mode change to disable_mode"); + goto tw_disable; + } +#endif + if ((tw->tw_lifetime_est & ~MASK_UFSTW_LIFETIME_NOT_GUARANTEE) + < UFSTW_MAX_LIFETIME_VALUE) + goto out; + else + goto tw_disable; +tw_disable: + ufstw_switch_disable_mode(tw); +out: + ufstw_lu_put(tw); +} + +void ufstw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp) +{ + struct ufstw_lu *tw; + + if (!lrbp || !ufsf_is_valid_lun(lrbp->lun)) + return; + + if (!ufstw_is_write_lrbp(lrbp)) + return; + + tw = ufsf->tw_lup[lrbp->lun]; + if (!tw) + return; + + if (atomic_read(&tw->tw_mode) == TW_MODE_DISABLED) + return; + + if (!tw->tw_enable) + return; + + spin_lock_bh(&tw->lifetime_lock); + tw->stat_write_sec += blk_rq_sectors(lrbp->cmd->request); + + if (tw->stat_write_sec > UFSTW_LIFETIME_SECT) { + tw->stat_write_sec = 0; + spin_unlock_bh(&tw->lifetime_lock); + schedule_work(&tw->tw_lifetime_work); + return; + } + + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[tw->lun]->request_queue, + "%s:%d tw_lifetime_work %u", + __func__, __LINE__, tw->stat_write_sec); + spin_unlock_bh(&tw->lifetime_lock); +} + +static int ufstw_read_lu_attr(struct ufstw_lu *tw, u8 idn, u32 *attr_val) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err; + u32 val; + + pm_runtime_get_sync(hba->dev); + + ufstw_lu_get(tw); + err = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, idn, + (u8)tw->lun, &val); + if (err) { + ERR_MSG("read attr [0x%.2X] failed...err %d", idn, err); + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + return err; + } + + *attr_val = val; + + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[tw->lun]->request_queue, + "%s:%d IDN %s (%d)", __func__, __LINE__, + idn == QUERY_ATTR_IDN_TW_FLUSH_STATUS ? "TW_FLUSH_STATUS" : + idn == QUERY_ATTR_IDN_TW_BUF_SIZE ? "TW_BUF_SIZE" : + idn == QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST ? "TW_BUF_LIFETIME_EST" : + "UNKNOWN", idn); + + TW_DEBUG(tw->ufsf, "tw_attr LUN(%d) [0x%.2X] %u", tw->lun, idn, + *attr_val); + + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + + return 0; +} + +static int ufstw_set_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err; + + pm_runtime_get_sync(hba->dev); + ufstw_lu_get(tw); + + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, idn, + (u8)tw->lun, NULL); + if (err) { + ERR_MSG("set flag [0x%.2X] failed...err %d", idn, err); + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + return err; + } + + *flag_res = true; + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[tw->lun]->request_queue, + "%s:%d IDN %s (%d)", __func__, __LINE__, + idn == QUERY_FLAG_IDN_TW_EN ? "TW_EN" : + idn == QUERY_FLAG_IDN_TW_BUF_FLUSH_EN ? "FLUSH_EN" : + idn == QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN ? + "HIBERN_EN" : "UNKNOWN", idn); + + TW_DEBUG(tw->ufsf, "tw_flag LUN(%d) [0x%.2X] %u", tw->lun, idn, + *flag_res); + + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + + return 0; +} + +static int ufstw_clear_lu_flag(struct ufstw_lu *tw, u8 idn, bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err; + + pm_runtime_get_sync(hba->dev); + ufstw_lu_get(tw); + + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG, idn, + (u8)tw->lun, NULL); + if (err) { + ERR_MSG("clear flag [0x%.2X] failed...err%d", idn, err); + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + return err; + } + + *flag_res = false; + + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[tw->lun]->request_queue, + "%s:%d IDN %s (%d)", __func__, __LINE__, + idn == QUERY_FLAG_IDN_TW_EN ? "TW_EN" : + idn == QUERY_FLAG_IDN_TW_BUF_FLUSH_EN ? "FLUSH_EN" : + idn == QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN ? "HIBERN_EN" : + "UNKNOWN", idn); + + TW_DEBUG(tw->ufsf, "tw_flag LUN(%d) [0x%.2X] %u", tw->lun, idn, + *flag_res); + + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + return 0; +} + +static inline int ufstw_read_lu_flag(struct ufstw_lu *tw, u8 idn, + bool *flag_res) +{ + struct ufs_hba *hba = tw->ufsf->hba; + int err; + bool val; + + /* + * Prevent to issue read-lu-flag query request during tw-reset-state. + * If not, tw-flag could be cleard, even though the tw-flag was set + */ + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + ERR_MSG("tw_state(%d) error", + atomic_read(&tw->ufsf->tw_state)); + return -ENODEV; + } + + pm_runtime_get_sync(hba->dev); + ufstw_lu_get(tw); + + err = ufsf_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, idn, + (u8)tw->lun, &val); + if (err) { + ERR_MSG("read flag [0x%.2X] failed...err%d", idn, err); + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + return err; + } + + *flag_res = val; + + TW_DEBUG(tw->ufsf, "tw_flag LUN(%d) [0x%.2X] %u", tw->lun, idn, + *flag_res); + + ufstw_lu_put(tw); + pm_runtime_put_sync(hba->dev); + return 0; + +} + +/* device level (ufsf) */ +static int ufstw_auto_ee(struct ufsf_feature *ufsf) +{ + struct ufs_hba *hba = ufsf->hba; + u16 mask = MASK_EE_TW; + u32 val; + int err = 0; + + pm_runtime_get_sync(hba->dev); + + if (hba->ee_ctrl_mask & mask) + goto out; + + val = hba->ee_ctrl_mask | mask; + val &= 0xFFFF; /* 2 bytes */ + err = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_EE_CONTROL, 0, &val); + if (err) { + ERR_MSG("failed to enable exception event err%d", err); + goto out; + } + + hba->ee_ctrl_mask |= mask; + ufsf->tw_ee_mode = TW_EE_MODE_AUTO; + + TW_DEBUG(ufsf, "turbo_write_exception_event_enable"); +out: + pm_runtime_put_sync(hba->dev); + return err; +} + +/* device level (ufsf) */ +static int ufstw_disable_ee(struct ufsf_feature *ufsf) +{ + struct ufs_hba *hba = ufsf->hba; + u16 mask = MASK_EE_TW; + int err = 0; + u32 val; + + pm_runtime_get_sync(hba->dev); + + if (!(hba->ee_ctrl_mask & mask)) + goto out; + + val = hba->ee_ctrl_mask & ~mask; + val &= 0xFFFF; /* 2 bytes */ + err = ufsf_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_EE_CONTROL, 0, &val); + if (err) { + ERR_MSG("failed to disable exception event err%d", err); + goto out; + } + + hba->ee_ctrl_mask &= ~mask; + ufsf->tw_ee_mode = TW_EE_MODE_DISABLE; + + TW_DEBUG(ufsf, "turbo_write_exeception_event_disable"); +out: + pm_runtime_put_sync(hba->dev); + return err; +} + +static void ufstw_flush_work_fn(struct work_struct *dwork) +{ + struct ufs_hba *hba; + struct ufstw_lu *tw; + bool need_resched = false; + + tw = container_of(dwork, struct ufstw_lu, tw_flush_work.work); + + TW_DEBUG(tw->ufsf, "start flush worker"); + + ufstw_lu_get(tw); + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + ERR_MSG("tw_state != TW_PRESENT (%d)", + atomic_read(&tw->ufsf->tw_state)); + ufstw_lu_put(tw); + return; + } + + hba = tw->ufsf->hba; + if (tw->next_q && time_before(jiffies, tw->next_q)) { + if (schedule_delayed_work(&tw->tw_flush_work, + tw->next_q - jiffies)) + pm_runtime_get_noresume(hba->dev); + ufstw_lu_put(tw); + return; + } + + pm_runtime_get_sync(hba->dev); + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_BUF_SIZE, + &tw->tw_available_buffer_size)) + goto error_put; + + mutex_lock(&tw->flush_lock); + + if (tw->tw_flush_during_hibern_enter && + tw->tw_available_buffer_size >= tw->flush_th_max) { + TW_DEBUG(tw->ufsf, "flush_disable QR (%d, %d)", + tw->lun, tw->tw_available_buffer_size); + + if (ufstw_clear_lu_flag(tw, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter)) + goto error_unlock; + tw->next_q = 0; + need_resched = false; + } else if (tw->tw_available_buffer_size < tw->flush_th_max) { + if (tw->tw_flush_during_hibern_enter) { + need_resched = true; + } else if (tw->tw_available_buffer_size <= tw->flush_th_min) { + TW_DEBUG(tw->ufsf, "flush_enable QR (%d, %d)", + tw->lun, tw->tw_available_buffer_size); + if (ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter)) + goto error_unlock; + need_resched = true; + } else { + need_resched = false; + } + } + mutex_unlock(&tw->flush_lock); + + pm_runtime_put_noidle(hba->dev); + pm_runtime_put(hba->dev); + + if (need_resched) { + tw->next_q = + jiffies + msecs_to_jiffies(UFSTW_FLUSH_CHECK_PERIOD_MS); + if (schedule_delayed_work(&tw->tw_flush_work, + msecs_to_jiffies(UFSTW_FLUSH_CHECK_PERIOD_MS))) + pm_runtime_get_noresume(hba->dev); + } + ufstw_lu_put(tw); + return; +error_unlock: + mutex_unlock(&tw->flush_lock); +error_put: + pm_runtime_put_noidle(hba->dev); + pm_runtime_put(hba->dev); + + if (tw->next_q) { + tw->next_q = + jiffies + msecs_to_jiffies(UFSTW_FLUSH_CHECK_PERIOD_MS); + if (schedule_delayed_work(&tw->tw_flush_work, + msecs_to_jiffies(UFSTW_FLUSH_CHECK_PERIOD_MS))) + pm_runtime_get_noresume(hba->dev); + } + ufstw_lu_put(tw); +} + +void ufstw_error_handler(struct ufsf_feature *ufsf) +{ + ERR_MSG("tw_state : %d -> %d", atomic_read(&ufsf->tw_state), TW_FAILED); + atomic_set(&ufsf->tw_state, TW_FAILED); + dump_stack(); + kref_put(&ufsf->tw_kref, ufstw_release); +} + +void ufstw_ee_handler(struct ufsf_feature *ufsf) +{ + struct ufs_hba *hba; + int lun; + + hba = ufsf->hba; + + seq_scan_lu(lun) { + if (!ufsf->tw_lup[lun]) + continue; + + if (!ufsf->sdev_ufs_lu[lun]) { + WARNING_MSG("warn: lun %d don't have scsi_device", lun); + continue; + } + + ufstw_lu_get(ufsf->tw_lup[lun]); + if (!delayed_work_pending(&ufsf->tw_lup[lun]->tw_flush_work)) { + ufsf->tw_lup[lun]->next_q = jiffies; + if (schedule_delayed_work(&ufsf->tw_lup[lun]->tw_flush_work, + msecs_to_jiffies(0))) + pm_runtime_get_noresume(hba->dev); + } + ufstw_lu_put(ufsf->tw_lup[lun]); + } +} + +static inline void ufstw_init_dev_jobs(struct ufsf_feature *ufsf) +{ + INIT_INFO("INIT_WORK(tw_reset_work)"); + INIT_DELAYED_WORK(&ufsf->tw_reset_work, ufstw_reset_work_fn); +} + +static inline void ufstw_init_lu_jobs(struct ufstw_lu *tw) +{ + INIT_INFO("INIT_DELAYED_WORK(tw_flush_work) ufstw_lu%d", tw->lun); + INIT_DELAYED_WORK(&tw->tw_flush_work, ufstw_flush_work_fn); + INIT_INFO("INIT_WORK(tw_lifetime_work)"); + INIT_WORK(&tw->tw_lifetime_work, ufstw_lifetime_work_fn); +} + +static inline void ufstw_cancel_lu_jobs(struct ufstw_lu *tw) +{ + int ret; + + ret = cancel_delayed_work_sync(&tw->tw_flush_work); + ret = cancel_work_sync(&tw->tw_lifetime_work); +} + +static inline int ufstw_version_check(struct ufstw_dev_info *tw_dev_info) +{ + INIT_INFO("Support TW Spec : Driver = %.4X, Device = %.4X", + UFSTW_VER, tw_dev_info->tw_ver); + + INIT_INFO("TW Driver Version : %.4X", UFSTW_DD_VER); + + if (tw_dev_info->tw_ver != UFSTW_VER) { + ERR_MSG("ERROR: TW Spec Version mismatch. So TW disabled."); + return -ENODEV; + } + return 0; +} + +void ufstw_get_dev_info(struct ufstw_dev_info *tw_dev_info, u8 *desc_buf) +{ + tw_dev_info->tw_device = false; + + if (UFSF_EFS_TURBO_WRITE + & LI_EN_32(&desc_buf[DEVICE_DESC_PARAM_EX_FEAT_SUP])) + INIT_INFO("bUFSExFeaturesSupport: TW support"); + else { + INIT_INFO("bUFSExFeaturesSupport: TW not support"); + return; + } + tw_dev_info->tw_buf_no_reduct = + desc_buf[DEVICE_DESC_PARAM_TW_RETURN_TO_USER]; + tw_dev_info->tw_buf_type = desc_buf[DEVICE_DESC_PARAM_TW_BUF_TYPE]; + + tw_dev_info->tw_ver = LI_EN_16(&desc_buf[DEVICE_DESC_PARAM_TW_VER]); + + if (!ufstw_version_check(tw_dev_info)) + tw_dev_info->tw_device = true; + + INFO_MSG("tw_dev [53] bTurboWriteBufferNoUserSpaceReductionEn %u", + tw_dev_info->tw_buf_no_reduct); + INFO_MSG("tw_dev [54] bTurboWriteBufferType %u", + tw_dev_info->tw_buf_type); +} + +void ufstw_get_geo_info(struct ufstw_dev_info *tw_dev_info, u8 *geo_buf) +{ + tw_dev_info->tw_number_lu = geo_buf[GEOMETRY_DESC_TW_NUMBER_LU]; + if (tw_dev_info->tw_number_lu == 0) { + ERR_MSG("Turbo Write is not supported"); + tw_dev_info->tw_device = false; + return; + } + + INFO_MSG("tw_geo [4F:52] dTurboWriteBufferMaxNAllocUnits %u", + LI_EN_32(&geo_buf[GEOMETRY_DESC_TW_MAX_SIZE])); + INFO_MSG("tw_geo [53] bDeviceMaxTurboWriteLUs %u", + tw_dev_info->tw_number_lu); + INFO_MSG("tw_geo [54] bTurboWriteBufferCapAdjFac %u", + geo_buf[GEOMETRY_DESC_TW_CAP_ADJ_FAC]); + INFO_MSG("tw_geo [55] bSupportedTurboWriteBufferUserSpaceReductionTypes %u", + geo_buf[GEOMETRY_DESC_TW_SUPPORT_USER_REDUCTION_TYPES]); + INFO_MSG("tw_geo [56] bSupportedTurboWriteBufferTypes %u", + geo_buf[GEOMETRY_DESC_TW_SUPPORT_BUF_TYPE]); +} + +int ufstw_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *lu_buf) +{ + struct ufsf_lu_desc lu_desc; + struct ufstw_lu *tw; + + lu_desc.tw_lu_buf_size = + LI_EN_32(&lu_buf[UNIT_DESC_TW_LU_MAX_BUF_SIZE]); + + ufsf->tw_lup[lun] = NULL; + + if (lu_desc.tw_lu_buf_size) { + ufsf->tw_lup[lun] = + kzalloc(sizeof(struct ufstw_lu), GFP_KERNEL); + if (!ufsf->tw_lup[lun]) + return -ENOMEM; + + tw = ufsf->tw_lup[lun]; + tw->ufsf = ufsf; + tw->lun = lun; + INIT_INFO("tw_lu LUN(%d) [29:2C] dLUNumTurboWriteBufferAllocUnits %u", + lun, lu_desc.tw_lu_buf_size); + } else { + INIT_INFO("tw_lu LUN(%d) [29:2C] dLUNumTurboWriteBufferAllocUnits %u", + lun, lu_desc.tw_lu_buf_size); + INIT_INFO("===== LUN(%d) is TurboWrite-disabled.", lun); + return -ENODEV; + } + + return 0; +} + +static inline void ufstw_print_lu_flag_attr(struct ufstw_lu *tw) +{ + INFO_MSG("tw_flag LUN(%d) [%u] fTurboWriteEn %u", tw->lun, + QUERY_FLAG_IDN_TW_EN, tw->tw_enable); + INFO_MSG("tw_flag LUN(%d) [%u] fTurboWriteBufferFlushEn %u", tw->lun, + QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, tw->tw_flush_enable); + INFO_MSG("tw_flag LUN(%d) [%u] fTurboWriteBufferFlushDuringHibernateEnter %u", + tw->lun, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + tw->tw_flush_during_hibern_enter); + + INFO_MSG("tw_attr LUN(%d) [%u] flush_status %u", tw->lun, + QUERY_ATTR_IDN_TW_FLUSH_STATUS, tw->tw_flush_status); + INFO_MSG("tw_attr LUN(%d) [%u] buffer_size %u", tw->lun, + QUERY_ATTR_IDN_TW_BUF_SIZE, tw->tw_available_buffer_size); + INFO_MSG("tw_attr LUN(%d) [%d] bufffer_lifetime %u(0x%X)", + tw->lun, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, + tw->tw_lifetime_est, tw->tw_lifetime_est); +} + +static inline void ufstw_lu_update(struct ufstw_lu *tw) +{ + ufstw_lu_get(tw); + + /* Flag */ + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, &tw->tw_enable)) + goto error_put; + + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->tw_flush_enable)) + goto error_put; + + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter)) + goto error_put; + + /* Attribute */ + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_FLUSH_STATUS, + &tw->tw_flush_status)) + goto error_put; + + if (ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_BUF_SIZE, + &tw->tw_available_buffer_size)) + goto error_put; + + ufstw_read_lu_attr(tw, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST, + &tw->tw_lifetime_est); +error_put: + ufstw_lu_put(tw); +} + +static void ufstw_lu_init(struct ufsf_feature *ufsf, int lun) +{ + struct ufstw_lu *tw = ufsf->tw_lup[lun]; + + ufstw_lu_get(tw); + tw->ufsf = ufsf; + + mutex_init(&tw->flush_lock); + mutex_init(&tw->mode_lock); + spin_lock_init(&tw->lifetime_lock); + + tw->stat_write_sec = 0; + atomic_set(&tw->active_cnt, 0); + + tw->flush_th_min = UFSTW_FLUSH_WORKER_TH_MIN; + tw->flush_th_max = UFSTW_FLUSH_WORKER_TH_MAX; + + /* for Debug */ + ufstw_init_lu_jobs(tw); + + if (ufstw_create_sysfs(ufsf, tw)) + INIT_INFO("sysfs init fail. but tw could run normally."); + + /* Read Flag, Attribute */ + ufstw_lu_update(tw); + +#if defined(CONFIG_UFSTW_IGNORE_GUARANTEE_BIT) + if (tw->tw_lifetime_est & MASK_UFSTW_LIFETIME_NOT_GUARANTEE) { + WARNING_MSG("warn: lun %d - dTurboWriteBufferLifeTimeEst[31] == 1", lun); + WARNING_MSG("Device not guarantee the lifetime of Turbo Write Buffer"); + WARNING_MSG("but we will ignore them for PoC"); + } +#else + if (tw->tw_lifetime_est & MASK_UFSTW_LIFETIME_NOT_GUARANTEE) { + WARNING_MSG("warn: lun %d - dTurboWriteBufferLifeTimeEst[31] == 1", lun); + WARNING_MSG("Device not guarantee the lifetime of Turbo Write Buffer"); + WARNING_MSG("So tw_mode change to disable_mode"); + goto tw_disable; + } +#endif + if ((tw->tw_lifetime_est & ~MASK_UFSTW_LIFETIME_NOT_GUARANTEE) + < UFSTW_MAX_LIFETIME_VALUE) { + atomic_set(&tw->tw_mode, TW_MODE_MANUAL); + goto out; + } else + goto tw_disable; + +tw_disable: + ufstw_switch_disable_mode(tw); +out: + ufstw_print_lu_flag_attr(tw); + ufstw_lu_put(tw); +} + +void ufstw_init(struct ufsf_feature *ufsf) +{ + int lun; + unsigned int tw_enabled_lun = 0; + + kref_init(&ufsf->tw_kref); + seq_scan_lu(lun) { + if (!ufsf->tw_lup[lun]) + continue; + + if (!ufsf->sdev_ufs_lu[lun]) { + WARNING_MSG("warn: lun %d don't have scsi_device", lun); + continue; + } + + ufstw_lu_init(ufsf, lun); + + ufsf->sdev_ufs_lu[lun]->request_queue->turbo_write_dev = true; + + INIT_INFO("UFSTW LU %d working", lun); + tw_enabled_lun++; + } + + if (tw_enabled_lun == 0) { + ERR_MSG("ERROR: tw_enabled_lun == 0. So TW disabled."); + goto out_free_mem; + } + + if (tw_enabled_lun > ufsf->tw_dev_info.tw_number_lu) { + ERR_MSG("ERROR: dev_info(bDeviceMaxTurboWriteLUs) mismatch. So TW disabled."); + goto out_free_mem; + } + + /* + * Initialize Device Level... + */ + ufstw_disable_ee(ufsf); + ufstw_init_dev_jobs(ufsf); + ufsf->tw_debug = false; + atomic_set(&ufsf->tw_state, TW_PRESENT); + return; +out_free_mem: + seq_scan_lu(lun) + kfree(ufsf->tw_lup[lun]); + + ufsf->tw_dev_info.tw_device = false; + atomic_set(&ufsf->tw_state, TW_FAILED); +} + +static inline int ufstw_probe_lun_done(struct ufsf_feature *ufsf) +{ + return (ufsf->num_lu == ufsf->slave_conf_cnt); +} + +void ufstw_init_work_fn(struct work_struct *work) +{ + struct ufsf_feature *ufsf; + int ret; + + ufsf = container_of(work, struct ufsf_feature, tw_init_work); + + init_waitqueue_head(&ufsf->tw_wait); + + ret = wait_event_timeout(ufsf->tw_wait, + ufstw_probe_lun_done(ufsf), + msecs_to_jiffies(10000)); + if (ret == 0) { + ERR_MSG("Probing LU is not fully completed."); + return; + } + + INIT_INFO("TW_INIT_START"); + + ufstw_init(ufsf); +} + +void ufstw_suspend(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + int ret; + + ret = flush_delayed_work(&ufsf->tw_reset_work); + TW_DEBUG(ufsf, "flush_delayed_work(tw_reset_work) = %d", ret); + + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + if (!tw) + continue; + + ufstw_lu_get(tw); + ufstw_cancel_lu_jobs(tw); + ufstw_lu_put(tw); + } +} + +void ufstw_resume(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + if (!tw) + continue; + + ufstw_lu_get(tw); + TW_DEBUG(ufsf, "ufstw_lu %d resume", lun); + if (tw->next_q) { + TW_DEBUG(ufsf, + "ufstw_lu %d flush_worker reschedule...", lun); + if (schedule_delayed_work(&tw->tw_flush_work, + (tw->next_q - jiffies))) + pm_runtime_get_noresume(ufsf->hba->dev); + } + ufstw_lu_put(tw); + } +} + +void ufstw_release(struct kref *kref) +{ + struct ufsf_feature *ufsf; + struct ufstw_lu *tw; + int lun; + int ret; + + dump_stack(); + ufsf = container_of(kref, struct ufsf_feature, tw_kref); + RELEASE_INFO("start release"); + + RELEASE_INFO("tw_state : %d -> %d", atomic_read(&ufsf->tw_state), + TW_FAILED); + atomic_set(&ufsf->tw_state, TW_FAILED); + + RELEASE_INFO("kref count %d", + atomic_read(&ufsf->tw_kref.refcount.refs)); + + ret = cancel_delayed_work_sync(&ufsf->tw_reset_work); + RELEASE_INFO("cancel_delayed_work_sync(tw_reset_work) = %d", ret); + + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + + RELEASE_INFO("ufstw_lu%d %p", lun, tw); + + ufsf->tw_lup[lun] = NULL; + + if (!tw) + continue; + + ufstw_cancel_lu_jobs(tw); + tw->next_q = 0; + + ret = kobject_uevent(&tw->kobj, KOBJ_REMOVE); + RELEASE_INFO("kobject error %d", ret); + + kobject_del(&tw->kobj); + + kfree(tw); + } + + RELEASE_INFO("end release"); +} + +static void ufstw_reset(struct ufsf_feature *ufsf) +{ + struct ufstw_lu *tw; + int lun; + int ret; + + if (atomic_read(&ufsf->tw_state) == TW_FAILED) { + ERR_MSG("tw_state == TW_FAILED(%d)", + atomic_read(&ufsf->tw_state)); + return; + } + + if (atomic_read(&ufsf->tw_state) == TW_PRESENT) { + ERR_MSG("tw_state is PRESENT(%d)", + atomic_read(&ufsf->tw_state)); + return; + } + + seq_scan_lu(lun) { + tw = ufsf->tw_lup[lun]; + TW_DEBUG(ufsf, "reset tw[%d]=%p", lun, tw); + if (!tw) + continue; + + INFO_MSG("ufstw_lu%d reset", lun); + + ufstw_lu_get(tw); + + /* + * if host_self_blocked == 1, ufs driver running devfreq jobs, + * If so then, defer turbo-write-flag update + * until finishing devfreq jobs. It can prevent deadlock + * between ufshcd_devfreq_scale and ufsf_query_flag + */ + if (ufsf->hba->host->host_self_blocked) { + INFO_MSG("retry reset until disabled blocked"); + goto out; + } + + ufstw_cancel_lu_jobs(tw); + + if (atomic_read(&tw->tw_mode) == TW_MODE_MANUAL && + tw->tw_enable) { + ret = ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, + &tw->tw_enable); + if (ret) + goto out; + } + + if (tw->tw_flush_enable) { + ret = ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->tw_flush_enable); + if (ret) + goto out; + } + + if (tw->tw_flush_during_hibern_enter) { + ret = ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter); + if (ret) + goto out; + } + + if (tw->next_q) { + TW_DEBUG(ufsf, + "ufstw_lu %d flush_worker reschedule...", lun); + if (schedule_delayed_work(&tw->tw_flush_work, + (tw->next_q - jiffies))) + pm_runtime_get_noresume(ufsf->hba->dev); + } + ufstw_lu_put(tw); + } + + if (ufsf->tw_ee_mode) + ufstw_auto_ee(ufsf); + + atomic_set(&ufsf->tw_state, TW_PRESENT); + INFO_MSG("reset complete.. tw_state %d", atomic_read(&ufsf->tw_state)); + return; +out: + /* + * If device reset occurs while issuing query request, + * ufstw_set_lu_flag() function could be failed. + * In this case tw-reset-worker will run again, + * so just exit this function. + * If not, we will schedule tw-reset-worker explicitly + */ + ufstw_lu_put(tw); + INFO_MSG("reset retry.. tw_state %d work_pending %d", + atomic_read(&ufsf->tw_state), + delayed_work_pending(&ufsf->tw_reset_work)); + if (!delayed_work_pending(&ufsf->tw_reset_work)) { + INFO_MSG("schedule tw_reset_work"); + schedule_delayed_work(&ufsf->tw_reset_work, msecs_to_jiffies(500)); + } +} + +static inline int ufstw_wait_kref_init_value(struct ufsf_feature *ufsf) +{ + return (atomic_read(&ufsf->tw_kref.refcount.refs) == 1); +} + +void ufstw_reset_work_fn(struct work_struct *dwork) +{ + struct ufsf_feature *ufsf; + int ret; + + ufsf = container_of(dwork, struct ufsf_feature, tw_reset_work.work); + TW_DEBUG(ufsf, "reset tw_kref.refcount=%d", + atomic_read(&ufsf->tw_kref.refcount.refs)); + + init_waitqueue_head(&ufsf->tw_wait); + + ret = wait_event_timeout(ufsf->tw_wait, + ufstw_wait_kref_init_value(ufsf), + msecs_to_jiffies(15000)); + if (ret == 0) { + ERR_MSG("UFSTW kref is not init_value(=1). kref count = %d ret = %d. So, TW_RESET_FAIL", + atomic_read(&ufsf->tw_kref.refcount.refs), ret); + return; + } + + INIT_INFO("TW_RESET_START"); + + ufstw_reset(ufsf); +} + +/* protected by mutex mode_lock */ +static void __active_turbo_write(struct ufstw_lu *tw, int do_work) +{ + if (atomic_read(&tw->tw_mode) != TW_MODE_FS) + return; + + blk_add_trace_msg(tw->ufsf->sdev_ufs_lu[tw->lun]->request_queue, + "%s:%d do_work %d active_cnt %d", + __func__, __LINE__, do_work, + atomic_read(&tw->active_cnt)); + + if (do_work == TW_FLAG_ENABLE_SET && !tw->tw_enable) + ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, &tw->tw_enable); + else if (do_work == TW_FLAG_ENABLE_CLEAR && tw->tw_enable) + ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, &tw->tw_enable); +} + +static void ufstw_active_turbo_write(struct request_queue *q, bool on) +{ + struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost; + struct ufs_hba *hba; + struct ufstw_lu *tw; + int do_work = TW_FLAG_ENABLE_NONE; + u64 lun; + + lun = sdev->lun; + if (lun >= UFS_UPIU_MAX_GENERAL_LUN) + return; + + shost = sdev->host; + hba = shost_priv(shost); + tw = hba->ufsf.tw_lup[lun]; + if (!tw) + return; + + ufstw_lu_get(tw); + if (on) { + if (atomic_inc_return(&tw->active_cnt) == 1) + do_work = TW_FLAG_ENABLE_SET; + } else { + if (atomic_dec_return(&tw->active_cnt) == 0) + do_work = TW_FLAG_ENABLE_CLEAR; + } + + blk_add_trace_msg(q, "%s:%d on %d active cnt %d do_work %d state %d mode %d", + __func__, __LINE__, on, atomic_read(&tw->active_cnt), + do_work, atomic_read(&tw->ufsf->tw_state), + atomic_read(&tw->tw_mode)); + + if (!do_work) + goto out; + + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + WARNING_MSG("tw_state %d.. cannot enable turbo_write..", + atomic_read(&tw->ufsf->tw_state)); + goto out; + } + + if (atomic_read(&tw->tw_mode) != TW_MODE_FS) + goto out; + + mutex_lock(&tw->mode_lock); + __active_turbo_write(tw, do_work); + mutex_unlock(&tw->mode_lock); +out: + ufstw_lu_put(tw); +} + +void bdev_set_turbo_write(struct block_device *bdev) +{ + struct request_queue *q = bdev->bd_queue; + + blk_add_trace_msg(q, "%s:%d turbo_write_dev %d\n", + __func__, __LINE__, q->turbo_write_dev); + + if (q->turbo_write_dev) + ufstw_active_turbo_write(bdev->bd_queue, true); +} + +void bdev_clear_turbo_write(struct block_device *bdev) +{ + struct request_queue *q = bdev->bd_queue; + + blk_add_trace_msg(q, "%s:%d turbo_write_dev %d\n", + __func__, __LINE__, q->turbo_write_dev); + + if (q->turbo_write_dev) + ufstw_active_turbo_write(bdev->bd_queue, false); +} + +/* sysfs function */ +static ssize_t ufstw_sysfs_show_ee_mode(struct ufstw_lu *tw, char *buf) +{ + SYSFS_INFO("TW_ee_mode %d", tw->ufsf->tw_ee_mode); + + return snprintf(buf, PAGE_SIZE, "%d", tw->ufsf->tw_ee_mode); +} + +static ssize_t ufstw_sysfs_store_ee_mode(struct ufstw_lu *tw, + const char *buf, size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + SYSFS_INFO("ee_mode cannot change, because current state is not TW_PRESENT (%d)..", + atomic_read(&tw->ufsf->tw_state)); + return -EINVAL; + } + + if (val >= TW_EE_MODE_NUM) { + SYSFS_INFO("wrong input.. your input %lu", val); + return -EINVAL; + } + + if (val) + ufstw_auto_ee(tw->ufsf); + else + ufstw_disable_ee(tw->ufsf); + + SYSFS_INFO("TW_ee_mode %d", tw->ufsf->tw_ee_mode); + + return count; +} + +static ssize_t ufstw_sysfs_show_flush_during_hibern_enter(struct ufstw_lu *tw, + char *buf) +{ + int ret; + + mutex_lock(&tw->flush_lock); + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter)) { + mutex_unlock(&tw->flush_lock); + return -EINVAL; + } + + SYSFS_INFO("TW_flush_during_hibern_enter %d", + tw->tw_flush_during_hibern_enter); + ret = snprintf(buf, PAGE_SIZE, "%d", tw->tw_flush_during_hibern_enter); + + mutex_unlock(&tw->flush_lock); + return ret; +} + +static ssize_t ufstw_sysfs_store_flush_during_hibern_enter(struct ufstw_lu *tw, + const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + SYSFS_INFO("tw_mode cannot change, because current state is not TW_PRESENT (%d)..", + atomic_read(&tw->ufsf->tw_state)); + return -EINVAL; + } + + mutex_lock(&tw->flush_lock); + if (tw->ufsf->tw_ee_mode == TW_EE_MODE_AUTO) { + SYSFS_INFO("flush_during_hibern_enable cannot change on auto ee_mode"); + mutex_unlock(&tw->flush_lock); + return -EINVAL; + } + + if (val) { + if (ufstw_set_lu_flag(tw, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter)) { + mutex_unlock(&tw->flush_lock); + return -EINVAL; + } + } else { + if (ufstw_clear_lu_flag(tw, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN, + &tw->tw_flush_during_hibern_enter)) { + mutex_unlock(&tw->flush_lock); + return -EINVAL; + } + } + + SYSFS_INFO("TW_flush_during_hibern_enter %d", + tw->tw_flush_during_hibern_enter); + mutex_unlock(&tw->flush_lock); + + return count; +} + +static ssize_t ufstw_sysfs_show_flush_enable(struct ufstw_lu *tw, char *buf) +{ + int ret; + + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->tw_flush_enable)) + return -EINVAL; + + SYSFS_INFO("TW_flush_enable %d", tw->tw_flush_enable); + + ret = snprintf(buf, PAGE_SIZE, "%d", tw->tw_flush_enable); + + return ret; +} + +static ssize_t ufstw_sysfs_store_flush_enable(struct ufstw_lu *tw, + const char *buf, size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + SYSFS_INFO("tw_mode cannot change, because current tw-state is not TW_PRESENT..(state:%d)..", + atomic_read(&tw->ufsf->tw_state)); + return -EINVAL; + } + + if (tw->ufsf->tw_ee_mode == TW_EE_MODE_AUTO) { + SYSFS_INFO("flush_enable cannot change on auto ee_mode"); + return -EINVAL; + } + + if (val) { + if (ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->tw_flush_enable)) + return -EINVAL; + } else { + if (ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_TW_BUF_FLUSH_EN, + &tw->tw_flush_enable)) + return -EINVAL; + } + + SYSFS_INFO("TW_flush_enable %d", tw->tw_flush_enable); + + return count; +} + +static ssize_t ufstw_sysfs_show_debug(struct ufstw_lu *tw, char *buf) +{ + SYSFS_INFO("debug %d", tw->ufsf->tw_debug); + + return snprintf(buf, PAGE_SIZE, "%d", tw->ufsf->tw_debug); +} + +static ssize_t ufstw_sysfs_store_debug(struct ufstw_lu *tw, const char *buf, + size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val) + tw->ufsf->tw_debug = true; + else + tw->ufsf->tw_debug = false; + + SYSFS_INFO("debug %d", tw->ufsf->tw_debug); + + return count; +} + +static ssize_t ufstw_sysfs_show_flush_th_min(struct ufstw_lu *tw, char *buf) +{ + SYSFS_INFO("flush_th_min%d", tw->flush_th_min); + + return snprintf(buf, PAGE_SIZE, "%d", tw->flush_th_min); +} + +static ssize_t ufstw_sysfs_store_flush_th_min(struct ufstw_lu *tw, + const char *buf, size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0 || val > 10) { + SYSFS_INFO("input value is wrong.. your input %lu", val); + return -EINVAL; + } + + if (tw->flush_th_max <= val) { + SYSFS_INFO("input value could not be greater than flush_th_max.."); + SYSFS_INFO("your input %lu, flush_th_max %u", + val, tw->flush_th_max); + return -EINVAL; + } + + tw->flush_th_min = val; + SYSFS_INFO("flush_th_min %u", tw->flush_th_min); + + return count; +} + +static ssize_t ufstw_sysfs_show_flush_th_max(struct ufstw_lu *tw, char *buf) +{ + SYSFS_INFO("flush_th_max %d", tw->flush_th_max); + + return snprintf(buf, PAGE_SIZE, "%d", tw->flush_th_max); +} + +static ssize_t ufstw_sysfs_store_flush_th_max(struct ufstw_lu *tw, + const char *buf, size_t count) +{ + unsigned long val; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val < 0 || val > 10) { + SYSFS_INFO("input value is wrong.. your input %lu", val); + return -EINVAL; + } + + if (tw->flush_th_min >= val) { + SYSFS_INFO("input value could not be less than flush_th_min.."); + SYSFS_INFO("your input %lu, flush_th_min %u", + val, tw->flush_th_min); + return -EINVAL; + } + + tw->flush_th_max = val; + SYSFS_INFO("flush_th_max %u", tw->flush_th_max); + + return count; +} + +static ssize_t ufstw_sysfs_show_version(struct ufstw_lu *tw, char *buf) +{ + SYSFS_INFO("TW version %.4X D/D version %.4X", + tw->ufsf->tw_dev_info.tw_ver, UFSTW_DD_VER); + + return snprintf(buf, PAGE_SIZE, "TW version %.4X DD version %.4X", + tw->ufsf->tw_dev_info.tw_ver, UFSTW_DD_VER); +} + +static ssize_t ufstw_sysfs_show_debug_active_cnt(struct ufstw_lu *tw, char *buf) +{ + SYSFS_INFO("debug active cnt %d", + atomic_read(&tw->active_cnt)); + + return snprintf(buf, PAGE_SIZE, "active_cnt %d", + atomic_read(&tw->active_cnt)); +} + +/* SYSFS DEFINE */ +#define define_sysfs_ro(_name) __ATTR(_name, 0444,\ + ufstw_sysfs_show_##_name, NULL), +#define define_sysfs_rw(_name) __ATTR(_name, 0644,\ + ufstw_sysfs_show_##_name, \ + ufstw_sysfs_store_##_name), + +#define define_sysfs_attr_r_function(_name, _IDN) \ +static ssize_t ufstw_sysfs_show_##_name(struct ufstw_lu *tw, char *buf) \ +{ \ + if (ufstw_read_lu_attr(tw, _IDN, &tw->tw_##_name))\ + return -EINVAL;\ + SYSFS_INFO("TW_"#_name" : %u (0x%X)", tw->tw_##_name, tw->tw_##_name); \ + return snprintf(buf, PAGE_SIZE, "%u", tw->tw_##_name); \ +} + +/* SYSFS FUNCTION */ +define_sysfs_attr_r_function(flush_status, QUERY_ATTR_IDN_TW_FLUSH_STATUS) +define_sysfs_attr_r_function(available_buffer_size, QUERY_ATTR_IDN_TW_BUF_SIZE) +define_sysfs_attr_r_function(lifetime_est, QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST) + +static ssize_t ufstw_sysfs_show_tw_enable(struct ufstw_lu *tw, char *buf) +{ + if (ufstw_read_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, &tw->tw_enable)) + return -EINVAL; + + SYSFS_INFO("TW_enable: %u (0x%X)", tw->tw_enable, tw->tw_enable); + return snprintf(buf, PAGE_SIZE, "%u", tw->tw_enable); +} + +static ssize_t ufstw_sysfs_store_tw_enable(struct ufstw_lu *tw, const char *buf, + size_t count) +{ + unsigned long val; + ssize_t ret = count; + + if (kstrtoul(buf, 0, &val)) + return -EINVAL; + + if (val > 2) { + SYSFS_INFO("wrong mode number.. your input %lu", val); + return -EINVAL; + } + + mutex_lock(&tw->mode_lock); + if (atomic_read(&tw->tw_mode) == TW_MODE_DISABLED) { + SYSFS_INFO("all turbo write life time is exhausted.."); + SYSFS_INFO("you could not change this value.."); + goto out; + } + + if (atomic_read(&tw->tw_mode) != TW_MODE_MANUAL) { + SYSFS_INFO("cannot set tw_enable.. current %s (%d) mode..", + atomic_read(&tw->tw_mode) == TW_MODE_FS ? + "TW_MODE_FS" : "UNKNOWN", + atomic_read(&tw->tw_mode)); + ret = -EINVAL; + goto out; + } + + if (val) { + if (ufstw_set_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, + &tw->tw_enable)) { + ret = -EINVAL; + goto out; + } + } else { + if (ufstw_clear_lu_flag(tw, QUERY_FLAG_IDN_TW_EN, + &tw->tw_enable)) { + ret = -EINVAL; + goto out; + } + } +out: + mutex_unlock(&tw->mode_lock); + SYSFS_INFO("TW_enable : %u (0x%X)", tw->tw_enable, tw->tw_enable); + return ret; +} + +static ssize_t ufstw_sysfs_show_tw_mode(struct ufstw_lu *tw, char *buf) +{ + int tw_mode = atomic_read(&tw->tw_mode); + + SYSFS_INFO("TW_mode %s %d", + tw_mode == TW_MODE_MANUAL ? "manual" : + tw_mode == TW_MODE_FS ? "fs" : "unknown", tw_mode); + return snprintf(buf, PAGE_SIZE, "%d", tw_mode); +} + +static ssize_t ufstw_sysfs_store_tw_mode(struct ufstw_lu *tw, const char *buf, + size_t count) +{ + int tw_mode; + + if (kstrtouint(buf, 0, &tw_mode)) + return -EINVAL; + + if (atomic_read(&tw->ufsf->tw_state) != TW_PRESENT) { + SYSFS_INFO("tw_mode cannot change, because current state is not TW_PRESENT (%d)..", + atomic_read(&tw->ufsf->tw_state)); + return -EINVAL; + } + + if (tw_mode >= TW_MODE_NUM || + tw_mode == TW_MODE_DISABLED) { + SYSFS_INFO("wrong mode number.. your input %d", tw_mode); + return -EINVAL; + } + + mutex_lock(&tw->mode_lock); + if (atomic_read(&tw->tw_mode) == TW_MODE_DISABLED) { + SYSFS_INFO("all turbo write life time is exhausted.."); + SYSFS_INFO("you could not change this value.."); + count = -EINVAL; + goto out; + } + + if (tw_mode == atomic_read(&tw->tw_mode)) + goto out; + + count = (ssize_t) ufstw_switch_mode(tw, tw_mode); +out: + mutex_unlock(&tw->mode_lock); + SYSFS_INFO("TW_mode: %d", atomic_read(&tw->tw_mode)); + return count; +} + +static struct ufstw_sysfs_entry ufstw_sysfs_entries[] = { + /* tw mode select */ + define_sysfs_rw(tw_mode) + + /* Flag */ + define_sysfs_rw(tw_enable) + define_sysfs_rw(flush_enable) + define_sysfs_rw(flush_during_hibern_enter) + + /* Attribute */ + define_sysfs_rw(ee_mode) + define_sysfs_ro(flush_status) + define_sysfs_ro(available_buffer_size) + define_sysfs_ro(lifetime_est) + + /* debug */ + define_sysfs_rw(debug) + define_sysfs_ro(debug_active_cnt) + + /* support */ + define_sysfs_rw(flush_th_max) + define_sysfs_rw(flush_th_min) + + /* device level */ + define_sysfs_ro(version) + __ATTR_NULL +}; + +static ssize_t ufstw_attr_show(struct kobject *kobj, struct attribute *attr, + char *page) +{ + struct ufstw_sysfs_entry *entry; + struct ufstw_lu *tw; + ssize_t error; + + entry = container_of(attr, struct ufstw_sysfs_entry, attr); + tw = container_of(kobj, struct ufstw_lu, kobj); + if (!entry->show) + return -EIO; + + ufstw_lu_get(tw); + mutex_lock(&tw->sysfs_lock); + error = entry->show(tw, page); + mutex_unlock(&tw->sysfs_lock); + ufstw_lu_put(tw); + return error; +} + +static ssize_t ufstw_attr_store(struct kobject *kobj, struct attribute *attr, + const char *page, size_t length) +{ + struct ufstw_sysfs_entry *entry; + struct ufstw_lu *tw; + ssize_t error; + + entry = container_of(attr, struct ufstw_sysfs_entry, attr); + tw = container_of(kobj, struct ufstw_lu, kobj); + + if (!entry->store) + return -EIO; + + ufstw_lu_get(tw); + mutex_lock(&tw->sysfs_lock); + error = entry->store(tw, page, length); + mutex_unlock(&tw->sysfs_lock); + ufstw_lu_put(tw); + return error; +} + +static const struct sysfs_ops ufstw_sysfs_ops = { + .show = ufstw_attr_show, + .store = ufstw_attr_store, +}; + +static struct kobj_type ufstw_ktype = { + .sysfs_ops = &ufstw_sysfs_ops, + .release = NULL, +}; + +static int ufstw_create_sysfs(struct ufsf_feature *ufsf, struct ufstw_lu *tw) +{ + struct device *dev = ufsf->hba->dev; + struct ufstw_sysfs_entry *entry; + int err; + + ufstw_lu_get(tw); + tw->sysfs_entries = ufstw_sysfs_entries; + + kobject_init(&tw->kobj, &ufstw_ktype); + mutex_init(&tw->sysfs_lock); + + INIT_INFO("ufstw creates sysfs ufstw_lu(%d) %p dev->kobj %p", + tw->lun, &tw->kobj, &dev->kobj); + + err = kobject_add(&tw->kobj, kobject_get(&dev->kobj), + "ufstw_lu%d", tw->lun); + if (!err) { + for (entry = tw->sysfs_entries; entry->attr.name != NULL; + entry++) { + INIT_INFO("ufstw_lu%d sysfs attr creates: %s", + tw->lun, entry->attr.name); + if (sysfs_create_file(&tw->kobj, &entry->attr)) + break; + } + INIT_INFO("ufstw_lu%d sysfs adds uevent", tw->lun); + kobject_uevent(&tw->kobj, KOBJ_ADD); + } + ufstw_lu_put(tw); + return err; +} diff --git a/drivers/scsi/ufs/ufstw.h b/drivers/scsi/ufs/ufstw.h new file mode 100644 index 0000000000000000000000000000000000000000..9f8886a3a4bd670e06eb30580110ab342e7f1588 --- /dev/null +++ b/drivers/scsi/ufs/ufstw.h @@ -0,0 +1,165 @@ +/* + * Universal Flash Storage tw Write + * + * Copyright (C) 2017-2018 Samsung Electronics Co., Ltd. + * + * Authors: + * Yongmyung Lee + * Jinyoung Choi + * + * 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. + * See the COPYING file in the top-level directory or visit + * + * + * 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. + * + * This program is provided "AS IS" and "WITH ALL FAULTS" and + * without warranty of any kind. You are solely responsible for + * determining the appropriateness of using and distributing + * the program and assume all risks associated with your exercise + * of rights with respect to the program, including but not limited + * to infringement of third party rights, the risks and costs of + * program errors, damage to or loss of data, programs or equipment, + * and unavailability or interruption of operations. Under no + * circumstances will the contributor of this Program be liable for + * any damages of any kind arising from your use or distribution of + * this program. + * + * The Linux Foundation chooses to take subject only to the GPLv2 + * license terms, and distributes only under these terms. + */ + +#ifndef _UFSTW_H_ +#define _UFSTW_H_ + +#include +#include +#include +#include +#include + +#include "../../../block/blk.h" + +#define UFSTW_VER 0x0101 +#define UFSTW_DD_VER 0x0111 + +#define UFSTW_FLUSH_CHECK_PERIOD_MS 1000 +#define UFSTW_FLUSH_WORKER_TH_MIN 3 +#define UFSTW_FLUSH_WORKER_TH_MAX 8 +#define UFSTW_LIFETIME_SECT 2097152 /* 1GB */ +#define UFSTW_MAX_LIFETIME_VALUE 0x0B +#define MASK_UFSTW_LIFETIME_NOT_GUARANTEE 0x80000000 + +/* + * UFSTW DEBUG + */ +#define TW_DEBUG(ufsf, msg, args...) \ + do { if (ufsf->tw_debug) \ + printk(KERN_ERR "%s:%d " msg "\n", \ + __func__, __LINE__, ##args); \ + } while (0) + +enum UFSTW_STATE { + TW_NEED_INIT = 0, + TW_PRESENT = 1, + TW_FAILED = -2, + TW_RESET = -3, +}; + +enum { + TW_MODE_DISABLED, + TW_MODE_MANUAL, + TW_MODE_FS, + TW_MODE_NUM +}; + +enum { + TW_EE_MODE_DISABLE, + TW_EE_MODE_AUTO, + TW_EE_MODE_NUM +}; + +enum { + TW_FLAG_ENABLE_NONE = 0, + TW_FLAG_ENABLE_CLEAR = 1, + TW_FLAG_ENABLE_SET = 2, +}; + +struct ufstw_dev_info { + bool tw_device; + + /* from Device Descriptor */ + u16 tw_ver; + u8 tw_buf_no_reduct; + u8 tw_buf_type; + + /* from Geometry Descriptor */ + u8 tw_number_lu; +}; + +struct ufstw_lu { + struct ufsf_feature *ufsf; + + int lun; + + /* Flags */ + bool tw_flush_enable; + bool tw_flush_during_hibern_enter; + struct mutex flush_lock; + + /* lifetiem estimated */ + unsigned int tw_lifetime_est; + spinlock_t lifetime_lock; + u32 stat_write_sec; + struct work_struct tw_lifetime_work; + + /* Attributes */ + unsigned int tw_flush_status; + unsigned int tw_available_buffer_size; + + /* mode manual/fs */ + atomic_t tw_mode; + bool tw_enable; + atomic_t active_cnt; + struct mutex mode_lock; + + /* Worker */ + struct delayed_work tw_flush_work; + unsigned long next_q; + unsigned int flush_th_max; + unsigned int flush_th_min; + + /* for sysfs */ + struct kobject kobj; + struct mutex sysfs_lock; + struct ufstw_sysfs_entry *sysfs_entries; +}; + +struct ufstw_sysfs_entry { + struct attribute attr; + ssize_t (*show)(struct ufstw_lu *tw, char *buf); + ssize_t (*store)(struct ufstw_lu *tw, const char *buf, size_t count); +}; + +struct ufshcd_lrb; + +void ufstw_get_dev_info(struct ufstw_dev_info *tw_dev_info, u8 *desc_buf); +void ufstw_get_geo_info(struct ufstw_dev_info *tw_dev_info, u8 *geo_buf); +int ufstw_get_lu_info(struct ufsf_feature *ufsf, int lun, u8 *lu_buf); +void ufstw_init(struct ufsf_feature *ufsf); +void ufstw_prep_fn(struct ufsf_feature *ufsf, struct ufshcd_lrb *lrbp); +void ufstw_init_work_fn(struct work_struct *work); +void ufstw_ee_handler(struct ufsf_feature *ufsf); +void ufstw_error_handler(struct ufsf_feature *ufsf); +void ufstw_reset_work_fn(struct work_struct *work); +void ufstw_suspend(struct ufsf_feature *ufsf); +void ufstw_resume(struct ufsf_feature *ufsf); +void ufstw_release(struct kref *kref); + +#endif /* End of Header */ diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index e0794357b2bb1c050ef25f0c2b344f57e4344125..79fbb57728c3a53a225c5e6c6bdfeae29f66deab 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -46,6 +46,9 @@ #include #include "icnss_private.h" #include "icnss_qmi.h" +#include +static u32 fw_version; +static u32 fw_version_ext; #define MAX_PROP_SIZE 32 #define NUM_LOG_PAGES 10 @@ -1159,6 +1162,29 @@ static int icnss_driver_event_server_exit(void *data) return 0; } +/* Initial and show wlan firmware build version */ +void cnss_set_fw_version(u32 version, u32 ext) +{ + fw_version = version; + fw_version_ext = ext; +} +EXPORT_SYMBOL(cnss_set_fw_version); + +static ssize_t cnss_version_information_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (!penv) + return -ENODEV; + return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u.%u\n", + (fw_version & 0xf0000000) >> 28, + (fw_version & 0xf000000) >> 24, (fw_version & 0xf00000) >> 20, + fw_version & 0x7fff, (fw_version_ext & 0xf0000000) >> 28); +} + +static DEVICE_ATTR(cnss_version_information, 0444, + cnss_version_information_show, NULL); + + static int icnss_call_driver_probe(struct icnss_priv *priv) { int ret = 0; @@ -3845,9 +3871,10 @@ static int icnss_probe(struct platform_device *pdev) if (ret) icnss_pr_err("Failed to init platform device wakeup source, err = %d\n", ret); - penv = priv; - + device_create_file(&penv->pdev->dev, + &dev_attr_cnss_version_information); + push_component_info(WCN, "WCN3998-1", "QualComm"); init_completion(&priv->unblock_shutdown); icnss_pr_info("Platform driver probed successfully\n"); @@ -3874,6 +3901,9 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); + device_remove_file(&penv->pdev->dev, + &dev_attr_cnss_version_information); + icnss_sysfs_destroy(penv); complete_all(&penv->unblock_shutdown); diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c index da575edfb04d50bad6d4fd8e78ff818e01bbcfb3..77d1e2d92308c24fdf7540014f1c27f91a786947 100644 --- a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c +++ b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c @@ -12,6 +12,7 @@ #include #include #include +#include #define BOOT_CMD 1 #define IMAGE_UNLOAD_CMD 0 @@ -60,6 +61,13 @@ static int cdsp_loader_do(struct platform_device *pdev) goto fail; } + if (get_boot_mode() == MSM_BOOT_MODE_FACTORY) { + dev_dbg(&pdev->dev, + "%s: do not load CDSP image in factory mode.\n", + __func__); + goto fail; + } + rc = of_property_read_string(pdev->dev.of_node, "qcom,proc-img-to-load", &img_name); diff --git a/drivers/soc/qcom/qmp-debugfs-client.c b/drivers/soc/qcom/qmp-debugfs-client.c index 6bc411d40477156302a5690d4edfd622336a2c84..732c88baf5d5a500736f18e44bf5383151d748c4 100644 --- a/drivers/soc/qcom/qmp-debugfs-client.c +++ b/drivers/soc/qcom/qmp-debugfs-client.c @@ -26,6 +26,72 @@ static struct mbox_client *cl; static DEFINE_MUTEX(qmp_debugfs_mutex); +#ifdef CONFIG_CONTROL_CENTER +#define DDR_CONFIG_SIZE 7 +#define DDR_BUFFER_SIZE 64 +struct ddr_config { + char buf[DDR_BUFFER_SIZE]; + size_t len; +} ddr_config[DDR_CONFIG_SIZE] = { + { "{class:ddr, res:fixed, val: 200}", 32 }, + { "{class:ddr, res:fixed, val: 547}", 32 }, + { "{class:ddr, res:fixed, val: 768}", 32 }, + { "{class:ddr, res:fixed, val: 1017}", 33 }, + { "{class:ddr, res:fixed, val: 1555}", 33 }, + { "{class:ddr, res:fixed, val: 1804}", 33 }, + { "{class:ddr, res:fixed, val: 2092}", 33 }, +}; + +void aop_lock_ddr_freq(int config) +{ + int target = 0; + static struct qmp_debugfs_data data; + + mutex_lock(&qmp_debugfs_mutex); + + switch (config) { + case 0: + break; + case 200: + target = 0; + break; + case 547: + target = 1; + break; + case 768: + target = 2; + break; + case 1017: + target = 3; + break; + case 1555: + target = 4; + break; + case 1804: + target = 5; + break; + case 2092: + target = 6; + break; + default: + pr_warn("config not match: %d\n", config); + mutex_unlock(&qmp_debugfs_mutex); + return; + } + + memset(&data, 0, sizeof(struct qmp_debugfs_data)); + memcpy(&data.buf, ddr_config[target].buf, ddr_config[target].len); + data.buf[ddr_config[target].len] = '\0'; + data.pkt.size = (ddr_config[target].len + 0x3) & ~0x3; + data.pkt.data = data.buf; + + if (mbox_send_message(chan, &(data.pkt)) < 0) + pr_err("Failed to send qmp request\n"); + + mutex_unlock(&qmp_debugfs_mutex); +} +#endif + static ssize_t aop_msg_write(struct file *file, const char __user *userstr, size_t len, loff_t *pos) { diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c index 079ec84890fcd5aa84de29a70ae04a5f1b570dbe..805cfc9f2ca04064c9a85bbb0d044dd044da364c 100644 --- a/drivers/soc/qcom/rpm_stats.c +++ b/drivers/soc/qcom/rpm_stats.c @@ -15,6 +15,10 @@ #include #include #include +#include +#include +#include +#include "rpmh_master_stat.h" #define RPM_STATS_NUM_REC 2 #define MSM_ARCH_TIMER_FREQ 19200000 @@ -55,6 +59,7 @@ struct msm_rpm_stats_data { #endif }; +struct dentry *debugfs_root; struct msm_rpmstats_kobj_attr { struct kobject *kobj; @@ -77,6 +82,96 @@ static inline u64 get_time_in_msec(u64 counter) return counter; } +static inline u32 msm_rpmstats_read_long_register(void __iomem *regbase, + int index, int offset) +{ + return readl_relaxed(regbase + offset + + index * sizeof(struct msm_rpm_stats_data)); +} + +static inline u64 msm_rpmstats_read_quad_register(void __iomem *regbase, + int index, int offset) +{ + u64 dst; + + memcpy_fromio(&dst, + regbase + offset + index * sizeof(struct msm_rpm_stats_data), + 8); + return dst; +} + +#define TIMEOUT_FOR_DUMP (3*60*60) +#define SUBSYSTEM_COUNT 9 +static struct msm_rpmstats_platform_data *pdata; +void rpmhstats_statistics(void) +{ + void __iomem *reg; + static struct msm_rpm_stats_data data[RPM_STATS_NUM_REC]; + int i; + u32 new_count; + u64 time_since_last_mode; + static u64 time; + u64 time_in_last_mode; + u64 actual_last_sleep; + + reg = ioremap_nocache(pdata->phys_addr_base, + pdata->phys_size); + if (!reg) { + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return; + } + + for (i = 0; i < pdata->num_records; i++) { + if (time != 0) { + new_count = msm_rpmstats_read_long_register(reg, i, + offsetof(struct msm_rpm_stats_data, count)); + if (new_count == data[i].count) { + time_since_last_mode = arch_counter_get_cntvct() - data->last_exited_at; + time_since_last_mode = get_time_in_sec(time_since_last_mode); + if (time_since_last_mode > TIMEOUT_FOR_DUMP) { + time_in_last_mode = data->last_exited_at - data->last_entered_at; + time_in_last_mode = get_time_in_msec(time_in_last_mode); + actual_last_sleep = get_time_in_msec(data->accumulated); + pr_err("Count:%d\n\ttime in last mode(msec):%llu\n" + "time since last mode(sec):%llu\nactual last sleep(msec):%llu\n\n", + data->count, time_in_last_mode, + time_since_last_mode, actual_last_sleep); + //get subsystem stats + if (get_apps_stats(false) == false) { + pr_err("The issue is because APPS"); + continue; + } else { + get_subsystem_stats(false); + panic("Because RPMH without entering PC"); + } + } else if (arch_counter_get_cntvct() - time > TIMEOUT_FOR_DUMP) + time = 0; + } else if (arch_counter_get_cntvct() - time > TIMEOUT_FOR_DUMP) + time = 0; + } else { + time = arch_counter_get_cntvct(); + data[i].stat_type = msm_rpmstats_read_long_register(reg, i, + offsetof(struct msm_rpm_stats_data, + stat_type)); + data[i].count = msm_rpmstats_read_long_register(reg, i, + offsetof(struct msm_rpm_stats_data, count)); + data[i].last_entered_at = msm_rpmstats_read_quad_register(reg, + i, offsetof(struct msm_rpm_stats_data, + last_entered_at)); + data[i].last_exited_at = msm_rpmstats_read_quad_register(reg, + i, offsetof(struct msm_rpm_stats_data, + last_exited_at)); + data[i].accumulated = msm_rpmstats_read_quad_register(reg, + i, offsetof(struct msm_rpm_stats_data, + accumulated)); + get_apps_stats(true); + get_subsystem_stats(true); + } + } +} + static inline int msm_rpmstats_append_data_to_buf(char *buf, struct msm_rpm_stats_data *data, int buflength) { @@ -111,24 +206,6 @@ static inline int msm_rpmstats_append_data_to_buf(char *buf, #endif } -static inline u32 msm_rpmstats_read_long_register(void __iomem *regbase, - int index, int offset) -{ - return readl_relaxed(regbase + offset + - index * sizeof(struct msm_rpm_stats_data)); -} - -static inline u64 msm_rpmstats_read_quad_register(void __iomem *regbase, - int index, int offset) -{ - u64 dst; - - memcpy_fromio(&dst, - regbase + offset + index * sizeof(struct msm_rpm_stats_data), - 8); - return dst; -} - static inline int msm_rpmstats_copy_stats( struct msm_rpmstats_private_data *prvdata) { @@ -167,79 +244,110 @@ static inline int msm_rpmstats_copy_stats( return length; } -static ssize_t rpmstats_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +#ifdef CONFIG_DEBUG_FS +static int rpmh_stats_show(struct seq_file *s, void *data) { + struct msm_rpmstats_private_data prvdata; struct msm_rpmstats_platform_data *pdata = NULL; - ssize_t length; - pdata = GET_PDATA_OF_ATTR(attr); + pdata = s->private; prvdata.reg_base = ioremap_nocache(pdata->phys_addr_base, pdata->phys_size); if (!prvdata.reg_base) { - pr_err("ERROR could not ioremap start=%pa, len=%u\n", - &pdata->phys_addr_base, pdata->phys_size); + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); return -EBUSY; } prvdata.read_idx = prvdata.len = 0; prvdata.platform_data = pdata; - prvdata.num_records = pdata->num_records; + prvdata.num_records = RPM_STATS_NUM_REC; if (prvdata.read_idx < prvdata.num_records) prvdata.len = msm_rpmstats_copy_stats(&prvdata); - length = scnprintf(buf, prvdata.len, "%s", prvdata.buf); - iounmap(prvdata.reg_base); - return length; + seq_printf(s, "%s", prvdata.buf); + return 0; } -static int msm_rpmstats_create_sysfs(struct platform_device *pdev, - struct msm_rpmstats_platform_data *pd) +static int rpmh_stats_open(struct inode *inode, struct file *file) { - struct kobject *rpmstats_kobj = NULL; - struct msm_rpmstats_kobj_attr *rpms_ka = NULL; - int ret = 0; - - rpmstats_kobj = kobject_create_and_add("system_sleep", power_kobj); - if (!rpmstats_kobj) { - pr_err("Cannot create rpmstats kobject\n"); - ret = -ENOMEM; - goto fail; - } + return single_open(file, rpmh_stats_show, inode->i_private); +} - rpms_ka = kzalloc(sizeof(*rpms_ka), GFP_KERNEL); - if (!rpms_ka) { - kobject_put(rpmstats_kobj); - ret = -ENOMEM; - goto fail; - } +#endif - rpms_ka->kobj = rpmstats_kobj; +static const struct file_operations rpmh_stats_fops = { +#ifdef CONFIG_DEBUG_FS + .open = rpmh_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +#endif +}; - sysfs_attr_init(&rpms_ka->ka.attr); - rpms_ka->pd = pd; - rpms_ka->ka.attr.mode = 0444; - rpms_ka->ka.attr.name = "stats"; - rpms_ka->ka.show = rpmstats_show; - rpms_ka->ka.store = NULL; +static const struct file_operations rpmh_master_stats_fops = { +#ifdef CONFIG_DEBUG_FS + .open = rpmh_master_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +#endif +}; - ret = sysfs_create_file(rpmstats_kobj, &rpms_ka->ka.attr); - platform_set_drvdata(pdev, rpms_ka); +static ssize_t stats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct msm_rpmstats_private_data prvdata; -fail: - return ret; + prvdata.reg_base = ioremap_nocache(pdata->phys_addr_base, + pdata->phys_size); + + if (!prvdata.reg_base) { + pr_err("%s: ERROR could not ioremap start=%pa, len=%u\n", + __func__, &pdata->phys_addr_base, + pdata->phys_size); + return -EBUSY; + } + + prvdata.read_idx = prvdata.len = 0; + prvdata.platform_data = pdata; + prvdata.num_records = RPM_STATS_NUM_REC; + + if (prvdata.read_idx < prvdata.num_records) + prvdata.len = msm_rpmstats_copy_stats(&prvdata); + + return snprintf(buf, 480, "%s", prvdata.buf); } +static struct kobj_attribute stats_attribute = +__ATTR_RO(stats); + +static struct kobj_attribute master_stats_attribute = +__ATTR_RO(master_stats); + +static struct attribute *rpmh_attrs[] = { + &stats_attribute.attr, + &master_stats_attribute.attr, + NULL, +}; + +static struct attribute_group rpmh_attr_group = { + .name = "rpmh", + .attrs = rpmh_attrs, +}; + static int msm_rpmstats_probe(struct platform_device *pdev) { - struct msm_rpmstats_platform_data *pdata; + //struct msm_rpmstats_platform_data *pdata; struct resource *res = NULL, *offset = NULL; u32 offset_addr = 0; void __iomem *phys_ptr = NULL; char *key; + int ret; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -270,7 +378,19 @@ static int msm_rpmstats_probe(struct platform_device *pdev) if (of_property_read_u32(pdev->dev.of_node, key, &pdata->num_records)) pdata->num_records = RPM_STATS_NUM_REC; - msm_rpmstats_create_sysfs(pdev, pdata); + debugfs_root = debugfs_create_dir("rpmh", NULL); + if (!debugfs_root) { + pr_err("%s: Cannot create rpmh dir\n", __func__); + return -ENOMEM; + } + + debugfs_create_file("stats", 0444, debugfs_root, pdata, + &rpmh_stats_fops); + + debugfs_create_file("master_stats", 0444, debugfs_root, NULL, + &rpmh_master_stats_fops); + + ret = sysfs_create_group(power_kobj, &rpmh_attr_group); return 0; } diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index daffd30d37e2db62383ff3065636b575e48f407c..807bd9a1f6c801f11602987c4550a84f2c36d62f 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -462,8 +462,8 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) do { ret = tcs_write(drv, msg); if (ret == -EBUSY) { - pr_info_ratelimited("DRV:%s TCS Busy, retrying RPMH message send: addr=%#x\n", - drv->name, msg->cmds[0].addr); + pr_devel_ratelimited("DRV:%s TCS Busy, retrying RPMH message send: addr=%#x\n", + drv->name, msg->cmds[0].addr); udelay(10); } } while (ret == -EBUSY); diff --git a/drivers/soc/qcom/rpmh_master_stat.c b/drivers/soc/qcom/rpmh_master_stat.c index d4418baaa1aba66e60d30b4e8a329e97934e1452..c17ecf02097b9837f3429bb92105c806acff9d56 100644 --- a/drivers/soc/qcom/rpmh_master_stat.c +++ b/drivers/soc/qcom/rpmh_master_stat.c @@ -18,12 +18,16 @@ #include #include #include +#include +#include +#include #include "rpmh_master_stat.h" #define UNIT_DIST 0x14 #define REG_VALID 0x0 #define REG_DATA_LO 0x4 #define REG_DATA_HI 0x8 +#define SUBSYSTEM_COUNT 9 #define GET_ADDR(REG, UNIT_NO) (REG + (UNIT_DIST * UNIT_NO)) @@ -95,11 +99,11 @@ static void __iomem *rpmh_unit_base; static DEFINE_MUTEX(rpmh_stats_mutex); -static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, +static void msm_rpmh_master_stats_print_data(struct seq_file *s, struct msm_rpmh_master_stats *record, const char *name) { - uint64_t accumulated_duration = record->accumulated_duration; + uint64_t temp_accumulated_duration = record->accumulated_duration; /* * If a master is in sleep when reading the sleep stats from SMEM * adjust the accumulated sleep duration to show actual sleep time. @@ -107,50 +111,110 @@ static ssize_t msm_rpmh_master_stats_print_data(char *prvbuf, ssize_t length, * the purpose of computing battery utilization. */ if (record->last_entered > record->last_exited) - accumulated_duration += + temp_accumulated_duration += (arch_counter_get_cntvct() - record->last_entered); - return scnprintf(prvbuf, length, "%s\n\tVersion:0x%x\n" + seq_printf(s, "%s\n\tVersion:0x%x\n" "\tSleep Count:0x%x\n" "\tSleep Last Entered At:0x%llx\n" "\tSleep Last Exited At:0x%llx\n" "\tSleep Accumulated Duration:0x%llx\n\n", - name, record->version_id, record->counts, - record->last_entered, record->last_exited, - accumulated_duration); + name, record->version_id, + record->counts, record->last_entered, + record->last_exited, temp_accumulated_duration); } -static ssize_t msm_rpmh_master_stats_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +static bool get_pc_stats(bool start, struct msm_rpmh_master_stats *new_record, int i) +{ + static struct msm_rpmh_master_stats record[SUBSYSTEM_COUNT]; + + if (i < SUBSYSTEM_COUNT) { + if (start == true) { + record[i].counts = new_record->counts; + record[i].last_entered = new_record->last_entered; + record[i].last_exited = new_record->last_exited; + record[i].accumulated_duration = new_record->accumulated_duration; + } else { + if (record[i].counts == new_record->counts && + new_record->last_exited > new_record->last_entered) { + if (i == (SUBSYSTEM_COUNT - 1)) + pr_err("Name:APPS"); + else + pr_err("Name:%s", rpmh_masters[i].master_name); + pr_err("\tSleep Count:0x%x\n" + "\tSleep Last Entered At:0x%llx\n" + "\tSleep Last Exited At:0x%llx\n" + "\tSleep Accumulated Duration:0x%llx\n\n", + record[i].counts, record[i].last_entered, + record[i].last_exited, + new_record->accumulated_duration - record[i].accumulated_duration); + return false; + } + } + } + + return true; +} +bool get_apps_stats(bool start) +{ + if (get_pc_stats(start, &apss_master_stats, (SUBSYSTEM_COUNT - 1)) == false) + return false; + + return true; +} + +bool get_subsystem_stats(bool start) { - ssize_t length; int i = 0; + size_t size = 0; struct msm_rpmh_master_stats *record = NULL; - mutex_lock(&rpmh_stats_mutex); + for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) { + if (i < (SUBSYSTEM_COUNT - 1)) { + record = (struct msm_rpmh_master_stats *) qcom_smem_get( + rpmh_masters[i].pid, + rpmh_masters[i].smem_id, &size); + if (!IS_ERR_OR_NULL(record)) + if (get_pc_stats(start, record, i) == false) + return false; + } + } - /* First Read APSS master stats */ + return true; +} + +static int rpmh_master_stats_show(struct seq_file *s, void *data) +{ + int i = 0; + struct msm_rpmh_master_stats *record = NULL; - length = msm_rpmh_master_stats_print_data(buf, PAGE_SIZE, - &apss_master_stats, "APSS"); + mutex_lock(&rpmh_stats_mutex); + /* First Read APSS master stats */ + msm_rpmh_master_stats_print_data(s, &apss_master_stats, + "APSS"); - /* Read SMEM data written by other masters */ + /* + * Read SMEM data written by masters + */ for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) { record = (struct msm_rpmh_master_stats *) qcom_smem_get( rpmh_masters[i].pid, rpmh_masters[i].smem_id, NULL); - if (!IS_ERR_OR_NULL(record) && (PAGE_SIZE - length > 0)) - length += msm_rpmh_master_stats_print_data( - buf + length, PAGE_SIZE - length, - record, - rpmh_masters[i].master_name); + if (!IS_ERR_OR_NULL(record)) + msm_rpmh_master_stats_print_data(s, record, + rpmh_masters[i].master_name); } mutex_unlock(&rpmh_stats_mutex); - return length; + return 0; +} + +int rpmh_master_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, rpmh_master_stats_show, inode->i_private); } static inline void msm_rpmh_apss_master_stats_update( @@ -195,66 +259,84 @@ void msm_rpmh_master_stats_update(void) } EXPORT_SYMBOL(msm_rpmh_master_stats_update); -static int msm_rpmh_master_stats_probe(struct platform_device *pdev) +ssize_t master_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - struct rpmh_master_stats_prv_data *prvdata = NULL; - struct kobject *rpmh_master_stats_kobj = NULL; - int ret = -ENOMEM; - - prvdata = devm_kzalloc(&pdev->dev, sizeof(*prvdata), GFP_KERNEL); - if (!prvdata) - return ret; - - rpmh_master_stats_kobj = kobject_create_and_add( - "rpmh_stats", - power_kobj); - if (!rpmh_master_stats_kobj) - return ret; - - prvdata->kobj = rpmh_master_stats_kobj; - - sysfs_attr_init(&prvdata->ka.attr); - prvdata->ka.attr.mode = 0444; - prvdata->ka.attr.name = "master_stats"; - prvdata->ka.show = msm_rpmh_master_stats_show; - prvdata->ka.store = NULL; - - ret = sysfs_create_file(prvdata->kobj, &prvdata->ka.attr); - if (ret) { - pr_err("sysfs_create_file failed\n"); - goto fail_sysfs; + int i = 0; + size_t size = 0; + struct msm_rpmh_master_stats *record = NULL; + char stats_buf[1024]; + uint64_t temp_accumulated_duration = 0; + + mutex_lock(&rpmh_stats_mutex); + + /* First Read APSS master stats */ + + temp_accumulated_duration = apss_master_stats.accumulated_duration; + + if (apss_master_stats.last_entered > apss_master_stats.last_exited) + temp_accumulated_duration += + (arch_counter_get_cntvct() + - apss_master_stats.last_entered); + + snprintf(stats_buf, sizeof(stats_buf), + "APSS\n\tVersion:0x%x\n" + "\tSleep Count:0x%x\n" + "\tSleep Last Entered At:0x%llx\n" + "\tSleep Last Exited At:0x%llx\n" + "\tSleep Accumulated Duration:0x%llx\n\n", + apss_master_stats.version_id, + apss_master_stats.counts, apss_master_stats.last_entered, + apss_master_stats.last_exited, temp_accumulated_duration); + /* + * Read SMEM data written by masters + */ + + for (i = 0; i < ARRAY_SIZE(rpmh_masters); i++) { + record = (struct msm_rpmh_master_stats *) qcom_smem_get( + rpmh_masters[i].pid, + rpmh_masters[i].smem_id, &size); + if (!IS_ERR_OR_NULL(record)) { + temp_accumulated_duration = record->accumulated_duration; + + if (record->last_entered > record->last_exited) + temp_accumulated_duration += + (arch_counter_get_cntvct() + - record->last_entered); + + snprintf(stats_buf + strlen(stats_buf), sizeof(stats_buf), + "%s\n\tVersion:0x%x\n" + "\tSleep Count:0x%x\n" + "\tSleep Last Entered At:0x%llx\n" + "\tSleep Last Exited At:0x%llx\n" + "\tSleep Accumulated Duration:0x%llx\n\n", + rpmh_masters[i].master_name, record->version_id, + record->counts, record->last_entered, + record->last_exited, temp_accumulated_duration); + } } + mutex_unlock(&rpmh_stats_mutex); + + return snprintf(buf, sizeof(stats_buf), "%s", stats_buf); +} + +static int msm_rpmh_master_stats_probe(struct platform_device *pdev) +{ rpmh_unit_base = of_iomap(pdev->dev.of_node, 0); if (!rpmh_unit_base) { pr_err("Failed to get rpmh_unit_base\n"); - ret = -ENOMEM; - goto fail_iomap; + return -ENOMEM; } apss_master_stats.version_id = 0x1; - platform_set_drvdata(pdev, prvdata); - return ret; - -fail_iomap: - sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); -fail_sysfs: - kobject_put(prvdata->kobj); - return ret; + + return 0; } static int msm_rpmh_master_stats_remove(struct platform_device *pdev) { - struct rpmh_master_stats_prv_data *prvdata; - - prvdata = (struct rpmh_master_stats_prv_data *) - platform_get_drvdata(pdev); - - sysfs_remove_file(prvdata->kobj, &prvdata->ka.attr); - kobject_put(prvdata->kobj); - platform_set_drvdata(pdev, NULL); iounmap(rpmh_unit_base); - rpmh_unit_base = NULL; return 0; } diff --git a/drivers/soc/qcom/rpmh_master_stat.h b/drivers/soc/qcom/rpmh_master_stat.h index 72c1a5fe6138ea49b8afdbcb399af437c714747e..99d51032a495c1f9e57f5e656bb12ed3e0eb20c3 100644 --- a/drivers/soc/qcom/rpmh_master_stat.h +++ b/drivers/soc/qcom/rpmh_master_stat.h @@ -12,3 +12,8 @@ void msm_rpmh_master_stats_update(void); static inline void msm_rpmh_master_stats_update(void) {} #endif +extern bool get_apps_stats(bool start); +extern bool get_subsystem_stats(bool start); +extern void rpmhstats_statistics(void); +extern int rpmh_master_stats_open(struct inode *inode, struct file *file); +extern ssize_t master_stats_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 3da5a978d9f6c1ffe1a01ee9d98e1209c9f40957..29d1e6b595a0efb52ff70f4b58431ac647b690db 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -23,7 +23,7 @@ #define SERVREG_LOC_SERVICE_INSTANCE_ID 1 #define QMI_SERVREG_LOC_SERVER_INITIAL_TIMEOUT 2000 -#define QMI_SERVREG_LOC_SERVER_TIMEOUT 2000 +#define QMI_SERVREG_LOC_SERVER_TIMEOUT 3000 #define INITIAL_TIMEOUT 100000 #define LOCATOR_SERVICE_TIMEOUT 300000 @@ -270,19 +270,11 @@ static int init_service_locator(void) SERVREG_LOC_SERVICE_VERS_V01, SERVREG_LOC_SERVICE_INSTANCE_ID); - rc = wait_for_completion_interruptible_timeout( - &service_locator.service_available, - msecs_to_jiffies(LOCATOR_SERVICE_TIMEOUT)); + rc = wait_for_completion_interruptible(&service_locator.service_available); if (rc < 0) { pr_err("Wait for locator service interrupted by signal\n"); goto inited; } - if (!rc) { - pr_err("%s: wait for locator service timed out\n", __func__); - service_timedout = true; - rc = -ETIME; - goto inited; - } service_inited = true; mutex_unlock(&service_init_mutex); diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c index eeae932ab91ebad708d019e3bee63d765cfd6c4b..5786052de90cc321141e93ee01aa807d1f0455bf 100644 --- a/drivers/soc/qcom/smp2p_sleepstate.c +++ b/drivers/soc/qcom/smp2p_sleepstate.c @@ -14,8 +14,8 @@ #define PROC_AWAKE_ID 12 /* 12th bit */ #define AWAKE_BIT BIT(PROC_AWAKE_ID) -static struct qcom_smem_state *state; static struct wakeup_source *notify_ws; +struct qcom_smem_state *qstate; /** * sleepstate_pm_notifier() - PM notifier callback function. @@ -31,11 +31,11 @@ static int sleepstate_pm_notifier(struct notifier_block *nb, { switch (event) { case PM_SUSPEND_PREPARE: - qcom_smem_state_update_bits(state, AWAKE_BIT, 0); + //qcom_smem_state_update_bits(state, AWAKE_BIT, 0); break; case PM_POST_SUSPEND: - qcom_smem_state_update_bits(state, AWAKE_BIT, AWAKE_BIT); + //qcom_smem_state_update_bits(state, AWAKE_BIT, AWAKE_BIT); break; } @@ -60,10 +60,10 @@ static int smp2p_sleepstate_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; - state = qcom_smem_state_get(&pdev->dev, 0, &ret); - if (IS_ERR(state)) - return PTR_ERR(state); - qcom_smem_state_update_bits(state, AWAKE_BIT, AWAKE_BIT); + qstate = qcom_smem_state_get(&pdev->dev, 0, &ret); + if (IS_ERR(qstate)) + return PTR_ERR(qstate); + qcom_smem_state_update_bits(qstate, AWAKE_BIT, AWAKE_BIT); ret = register_pm_notifier(&sleepstate_pm_nb); if (ret) { diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index e3ab1c4b28e53ab7090b831167802f82ef0a9a64..9092afcf12258d07f87d04d595157d57ee53466b 100644 --- a/drivers/soc/qcom/spss_utils.c +++ b/drivers/soc/qcom/spss_utils.c @@ -1202,7 +1202,7 @@ static int spss_probe(struct platform_device *pdev) if (ret < 0) return ret; - pr_info("Initialization completed ok, firmware_name [%s].\n", + pr_info("Initialization completed finish, firmware_name [%s].\n", firmware_name); iar_nb = kzalloc(sizeof(*iar_nb), GFP_KERNEL); diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index e979abd14ee36eb777d957a12fdfbcefea16ab0d..b0cf71357f4d9824e336eddc8cf0d405e4cee749 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -24,6 +24,7 @@ #include #include +#include #include "peripheral-loader.h" @@ -798,7 +799,7 @@ static struct pil_reset_ops pil_ops_trusted = { static void log_failure_reason(const struct pil_tz_data *d) { size_t size; - char *smem_reason, reason[MAX_SSR_REASON_LEN]; + char *smem_reason, reason[MAX_SSR_REASON_LEN], *function_name; const char *name = d->subsys_desc.name; if (d->smem_id == -1) @@ -816,7 +817,11 @@ static void log_failure_reason(const struct pil_tz_data *d) } strlcpy(reason, smem_reason, min(size, (size_t)MAX_SSR_REASON_LEN)); + function_name = parse_function_builtin_return_address((unsigned long) + __builtin_return_address(0)); + save_dump_reason_to_smem(reason, function_name); pr_err("%s subsystem failure reason: %s.\n", name, reason); + subsys_store_crash_reason(d->subsys, reason); } static int subsys_shutdown(const struct subsys_desc *subsys, bool force_stop) @@ -975,7 +980,7 @@ static void clear_pbl_done(struct pil_tz_data *d) pr_err("PBL error status spare2 register: 0x%08x\n", rmb_err_spare2); } else { - pr_info("PBL_DONE - 1st phase loading [%s] completed ok\n", + pr_info("PBL_DONE - 1st phase loading [%s] completed finish\n", d->subsys_desc.name); } __raw_writel(BIT(d->bits_arr[PBL_DONE]), d->irq_clear); @@ -986,7 +991,7 @@ static void clear_err_ready(struct pil_tz_data *d) pr_debug("Subsystem error services up received from %s\n", d->subsys_desc.name); - pr_info("SW_INIT_DONE - 2nd phase loading [%s] completed ok\n", + pr_info("SW_INIT_DONE - 2nd phase loading [%s] completed finish\n", d->subsys_desc.name); __raw_writel(BIT(d->bits_arr[ERR_READY]), d->irq_clear); diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 69f7aa599ee0be1c19a7788022c57d447c3da9e7..2c8278ee4a78bfe7bb151838fe105b294dc58e65 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -35,6 +35,10 @@ #include #include "peripheral-loader.h" +#include +#include +#include +#include #define DISABLE_SSR 0x9889deed /* If set to 0x9889deed, call to subsystem_restart_dev() returns immediately */ @@ -194,6 +198,7 @@ struct subsys_device { int id; int restart_level; int crash_count; + char crash_reason[256]; struct subsys_soc_restart_order *restart_order; bool do_ramdump_on_put; struct cdev char_dev; @@ -253,6 +258,13 @@ static ssize_t crash_count_show(struct device *dev, } static DEVICE_ATTR_RO(crash_count); +static ssize_t crash_reason_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", to_subsys(dev)->crash_reason); +} +static DEVICE_ATTR_RO(crash_reason); + static ssize_t restart_level_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -379,10 +391,44 @@ void subsys_default_online(struct subsys_device *dev) } EXPORT_SYMBOL(subsys_default_online); +static void subsys_send_uevent_notify(struct subsys_desc *desc, int crash_count) +{ + char *envp[4]; + struct subsys_device *dev; + + if (!desc) + return; + + dev = find_subsys_device(desc->name); + if (!dev) + return; + + envp[0] = kasprintf(GFP_KERNEL, "SUBSYSTEM=%s", desc->name); + envp[1] = kasprintf(GFP_KERNEL, "CRASHCOUNT=%d", crash_count); + envp[2] = kasprintf(GFP_KERNEL, "CRASHREASON=%s", dev->crash_reason); + envp[3] = NULL; + kobject_uevent_env(&desc->dev->kobj, KOBJ_CHANGE, envp); + pr_err("%s %s %s\n", envp[0], envp[1], envp[2]); + kfree(envp[2]); + kfree(envp[1]); + kfree(envp[0]); +} + +void subsys_store_crash_reason(struct subsys_device *dev, char *reason) +{ + if (dev == NULL) + return; + + if (reason != NULL) + strlcpy(dev->crash_reason, reason, sizeof(dev->crash_reason)); +} +EXPORT_SYMBOL(subsys_store_crash_reason); + static struct attribute *subsys_attrs[] = { &dev_attr_name.attr, &dev_attr_state.attr, &dev_attr_crash_count.attr, + &dev_attr_crash_reason.attr, &dev_attr_restart_level.attr, &dev_attr_firmware_name.attr, &dev_attr_system_debug.attr, @@ -748,6 +794,7 @@ static int subsystem_shutdown(struct subsys_device *dev, void *data) subsys_set_state(dev, SUBSYS_OFFLINE); disable_all_irqs(dev); + subsys_send_uevent_notify(dev->desc, dev->crash_count); return 0; } @@ -831,6 +878,107 @@ struct subsys_device *find_subsys_device(const char *str) } EXPORT_SYMBOL(find_subsys_device); +static int val; +static int restart_level;/*system original val*/ +struct delayed_work op_restart_modem_work; + +static ssize_t proc_restart_level_all_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + ssize_t len = 0; + + len = copy_to_user(puser_buf, val?"1":"0", 1); + pr_info("the restart level switch is:%d\n", val); + return len; +} + +static ssize_t proc_restart_level_all_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + char subsysname[][15] = { + "ipa_fws", + "modem", + "adsp", + "cdsp", + "venus", + "npu", + "a620_zap" + }; + int i = 0; + char temp[2] = {0}; + struct subsys_device *subsys; + int rc; + + if (copy_from_user(temp, puser_buf, 1)) + return -EFAULT; + + rc = kstrtoint(temp, 0, &val); + if (rc != 0) + return -EINVAL; + + cancel_delayed_work_sync(&op_restart_modem_work); + + for (i = 0; i < ARRAY_SIZE(subsysname); i++) { + subsys = find_subsys_device(subsysname[i]); + if (subsys) { + if (val == 1) + subsys->restart_level = RESET_SOC; + else + subsys->restart_level = RESET_SUBSYS_COUPLED; + } + } + pr_info("write the restart level switch to :%d\n", val); + return count; +} + +static const struct file_operations restart_level_all_operations = { + .read = proc_restart_level_all_read, + .write = proc_restart_level_all_write, +}; + +static void init_restart_level_all_node(void) +{ + if (!proc_create("restart_level_all", 0644, NULL, + &restart_level_all_operations)){ + pr_err("%s : Failed to register proc interface\n", __func__); + } +} + +static void op_restart_modem_work_fun(struct work_struct *work) +{ + struct subsys_device *subsys = find_subsys_device("modem"); + + if (!subsys) + return; + subsys->restart_level = restart_level; + pr_err("%s:level=%d\n", __func__, subsys->restart_level); +} + +int op_restart_modem_init(void) +{ + INIT_DELAYED_WORK(&op_restart_modem_work, op_restart_modem_work_fun); + return 0; +} + +int op_restart_modem(void) +{ + struct subsys_device *subsys = find_subsys_device("modem"); + + if (!subsys) + return -ENODEV; + pr_err("%s:level=%d\n", __func__, subsys->restart_level); + restart_level = subsys->restart_level; + subsys->restart_level = RESET_SUBSYS_COUPLED; + if (subsystem_restart("modem") == -ENODEV) + pr_err("%s: SSR call failed\n", __func__); + + schedule_delayed_work(&op_restart_modem_work, + msecs_to_jiffies(10*1000)); + return 0; +} +EXPORT_SYMBOL(op_restart_modem); + static int subsys_start(struct subsys_device *subsys) { int ret; @@ -1209,6 +1357,51 @@ static void device_restart_work_hdlr(struct work_struct *work) dev->desc->name); } +static ssize_t force_rst_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *lo) +{ + char read_buf[4] = {0}; + struct subsys_device *subsys = find_subsys_device("modem"); + + if (!subsys) + return 0; + + if (copy_from_user(read_buf, buf, 1)) { + pr_err("%s: failed to copy from user.\n", __func__); + return count; + } + + pr_info("%s: %s\n", __func__, read_buf); + + if (!strncmp(read_buf, "2", 1)) + panic("force modem crash"); + + if (!strncmp(read_buf, "1", 1)) { + pr_err("force to reset modem\n"); + op_restart_modem(); + } + + return count; +} + +static ssize_t force_rst_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos) +{ + return count; +} + +static const struct file_operations modem_force_rst_fops = { + .write = force_rst_write, + .read = force_rst_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + + int subsystem_restart_dev(struct subsys_device *dev) { const char *name; @@ -1910,6 +2103,7 @@ struct subsys_device *subsys_register(struct subsys_desc *desc) goto err_setup_irqs; } + op_restart_modem_init(); return subsys; err_setup_irqs: if (subsys->desc->edge) @@ -1981,6 +2175,7 @@ static struct notifier_block panic_nb = { static int __init subsys_restart_init(void) { int ret; + struct proc_dir_entry *d_entry = NULL; ssr_wq = alloc_workqueue("ssr_wq", WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 0); @@ -2002,6 +2197,12 @@ static int __init subsys_restart_init(void) if (ret) goto err_soc; + init_restart_level_all_node(); + + d_entry = proc_create_data("force_reset", 0664, NULL, &modem_force_rst_fops, NULL); + if (!d_entry) + goto err_soc; + return 0; err_soc: diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index d844c3144e02556c5968038ca6a3b69ea0b9a741..23e00ee441afdd4a4ddd918dc6908eb5422b9d80 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -34,6 +34,9 @@ #define CREATE_TRACE_POINTS #include #include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif #include "ion.h" #include "ion_secure_util.h" @@ -95,6 +98,17 @@ static void ion_buffer_add(struct ion_device *dev, rb_insert_color(&buffer->node, &dev->buffers); } +#ifdef CONFIG_ONEPLUS_HEALTHINFO +static atomic_long_t ion_total_size; +static bool ion_cnt_enable = true; +unsigned long ion_total(void) +{ + if (!ion_cnt_enable) + return 0; + return (unsigned long)atomic_long_read(&ion_total_size); +} +#endif + /* this function should only be called while dev->lock is held */ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, struct ion_device *dev, @@ -162,6 +176,11 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, mutex_unlock(&dev->buffer_lock); atomic_long_add(len, &heap->total_allocated); atomic_long_add(len, &total_heap_bytes); + +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (ion_cnt_enable) + atomic_long_add(buffer->size, &ion_total_size); +#endif return buffer; err1: @@ -177,6 +196,10 @@ void ion_buffer_destroy(struct ion_buffer *buffer) pr_warn_ratelimited("ION client likely missing a call to dma_buf_kunmap or dma_buf_vunmap\n"); buffer->heap->ops->unmap_kernel(buffer->heap, buffer); } +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (ion_cnt_enable) + atomic_long_sub(buffer->size, &ion_total_size); +#endif buffer->heap->ops->free(buffer); kfree(buffer); } diff --git a/drivers/staging/android/ion/ion.h b/drivers/staging/android/ion/ion.h index da143d3e49fbc2994576e4a098ffded99e1e130a..cbfc7243ff8232703ea52fac399bf47fdb193c96 100644 --- a/drivers/staging/android/ion/ion.h +++ b/drivers/staging/android/ion/ion.h @@ -257,6 +257,10 @@ struct ion_heap { void *unused); }; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +unsigned long ion_total(void); +#endif + /** * ion_buffer_cached - this ion buffer is cached * @buffer: buffer diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index 5b86c5fbbe4169753ba28cf90e164c4d17ce3562..29bda5d0908b118a3d10c2dba879a3b720f2b3d2 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -70,6 +70,10 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, static void ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { mutex_lock(&pool->mutex); +#ifdef CONFIG_ONEPLUS_HEALTHINFO + zone_page_state_add(1L << pool->order, page_zone(page), + NR_IONCACHE_PAGES); +#endif if (PageHighMem(page)) { list_add_tail(&page->lru, &pool->high_items); pool->high_count++; @@ -121,6 +125,11 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) pool->low_count--; } +#ifdef CONFIG_ONEPLUS_HEALTHINFO + zone_page_state_add(-(1L << pool->order), page_zone(page), + NR_IONCACHE_PAGES); +#endif + atomic_dec(&pool->count); list_del(&page->lru); nr_total_pages -= 1 << pool->order; diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 4b40dfcfcd0f4d2d8cfcb57f96293eee95e04f05..bad51711872403184193c839ce918e34a5901636 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -209,6 +209,15 @@ config THERMAL_EMULATION because userland can easily disable the thermal policy by simply flooding this sysfs node with low temperature values. +config HORAE_THERMAL_SHELL + bool "Horae shell temp driver" + default y + help + Provide three thermal zones (front, frame and back) to get real shell temp. + /sys/class/thermal/thermal_zoneX/type + /sys/class/thermal/thermal_zoneY/type + /sys/class/thermal/thermal_zoneZ/type + config HISI_THERMAL tristate "Hisilicon thermal driver" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 2162f70e829c5aa4537ee469922ce888fe9f20c4..3dfede47a5ead9b738e16075e6b0c8608d44c0d1 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -63,4 +63,4 @@ obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o obj-$(CONFIG_THERMAL_TSENS) += msm-tsens.o tsens2xxx.o tsens-dbg.o tsens-mtc.o tsens1xxx.o tsens-calib.o - +obj-$(CONFIG_HORAE_THERMAL_SHELL) += horae_shell_temp.o diff --git a/drivers/thermal/horae_shell_temp.c b/drivers/thermal/horae_shell_temp.c new file mode 100644 index 0000000000000000000000000000000000000000..277b9c38e309526622487388c58d72d98bbbe9dc --- /dev/null +++ b/drivers/thermal/horae_shell_temp.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 , Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_HOUSTON +#include +#endif + +enum { + SHELL_FRONT = 0, + SHELL_FRAME, + SHELL_BACK, + SHELL_MAX, +}; + +static DEFINE_IDA(shell_temp_ida); +static DEFINE_SPINLOCK(horae_lock); +static int shell_temp[SHELL_MAX]; + +struct horae_shell_temp { + struct thermal_zone_device *tzd; + int shell_id; +}; + +static const struct of_device_id horae_shell_of_match[] = { + { .compatible = "oneplus,shell-temp" }, + {}, +}; + +static int horae_get_shell_temp(struct thermal_zone_device *tz, + int *temp) +{ + struct horae_shell_temp *hst; + + if (!temp || !tz) + return -EINVAL; + + hst = tz->devdata; + *temp = shell_temp[hst->shell_id]; + return 0; +} + +struct thermal_zone_device_ops shell_thermal_zone_ops = { + .get_temp = horae_get_shell_temp, +}; + +static int horae_shell_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dev_node = dev->of_node; + struct thermal_zone_device *tz_dev; + struct horae_shell_temp *hst; + int ret = 0; + int result; + + if (!of_device_is_available(dev_node)) { + pr_err("shell-temp dev not found\n"); + return -ENODEV; + } + + hst = kzalloc(sizeof(struct horae_shell_temp), GFP_KERNEL); + if (!hst) + return -ENOMEM; + + result = ida_simple_get(&shell_temp_ida, 0, 0, GFP_KERNEL); + if (result < 0) { + pr_err("genernal horae id failed\n"); + ret = -EINVAL; + goto err_free_mem; + } + + hst->shell_id = result; + + tz_dev = thermal_zone_device_register(dev_node->name, + 0, 0, hst, &shell_thermal_zone_ops, NULL, 0, 0); + if (IS_ERR_OR_NULL(tz_dev)) { + pr_err("register thermal zone for shell failed\n"); + ret = -ENODEV; + goto err_remove_id; + } +#ifdef CONFIG_HOUSTON + ht_register_thermal_zone_device(tz_dev); +#endif + hst->tzd = tz_dev; + + platform_set_drvdata(pdev, hst); + + return 0; + +err_remove_id: + ida_simple_remove(&shell_temp_ida, result); +err_free_mem: + kfree(hst); + return ret; +} + +static int horae_shell_remove(struct platform_device *pdev) +{ + struct horae_shell_temp *hst = platform_get_drvdata(pdev); + + if (hst) { + platform_set_drvdata(pdev, NULL); + thermal_zone_device_unregister(hst->tzd); + kfree(hst); + } + + return 0; +} + +static struct platform_driver horae_shell_platdrv = { + .driver = { + .name = "horae-shell-temp", + .owner = THIS_MODULE, + .of_match_table = horae_shell_of_match, + }, + .probe = horae_shell_probe, + .remove = horae_shell_remove, +}; + +#define BUF_LEN 256 +static ssize_t proc_shell_write(struct file *filp, const char __user *buf, + size_t count, loff_t *pos) +{ + int ret, temp, len; + unsigned int index = 0; + char tmp[BUF_LEN + 1]; + unsigned long flags; + + + if (count == 0) + return 0; + + len = count > BUF_LEN ? BUF_LEN : count; + + ret = copy_from_user(tmp, buf, len); + if (ret) { + pr_err("copy_from_user failed, ret=%d\n", ret); + return count; + } + + if (tmp[len - 1] == '\n') + tmp[len - 1] = '\0'; + else + tmp[len] = '\0'; + + ret = sscanf(tmp, "%d %d", &index, &temp); + if (ret < 2) { + pr_err("write failed, ret=%d\n", ret); + return count; + } + + if (index >= SHELL_MAX) { + pr_err("write invalid para\n"); + return count; + } + + spin_lock_irqsave(&horae_lock, flags); + shell_temp[index] = temp; + spin_unlock_irqrestore(&horae_lock, flags); + + return count; +} + +static const struct file_operations proc_shell_fops = { + .write = proc_shell_write, +}; + +static int __init horae_shell_init(void) +{ + struct proc_dir_entry *shell_proc_entry; + + shell_proc_entry = proc_create("shell-temp", 0664, NULL, &proc_shell_fops); + if (!shell_proc_entry) { + pr_err("shell-temp proc create failed\n"); + return -EINVAL; + } + + spin_lock_init(&horae_lock); + + return platform_driver_register(&horae_shell_platdrv); +} + +static void __exit horae_shell_exit(void) +{ + platform_driver_unregister(&horae_shell_platdrv); +} + + +module_init(horae_shell_init); +module_exit(horae_shell_exit); diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index d79e32fd291f5f4d3c54db78e520e1c6ed3076eb..14d0ef051e0f85d965a8137a9c6183337cb3258a 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -16,6 +16,10 @@ #include "thermal_core.h" #include "qcom/qti_virtual_sensor.h" +#ifdef CONFIG_HOUSTON +#include +#endif + LIST_HEAD(tsens_device_list); static int tsens_get_temp(void *data, int *temp) @@ -222,6 +226,11 @@ static int tsens_thermal_zone_register(struct tsens_device *tmdev) sensor_missing++; continue; } + +#ifdef CONFIG_HOUSTON + ht_register_thermal_zone_device(tmdev->sensor[i].tzd); +#endif + } else { pr_debug("Sensor not enabled:%d\n", i); } diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 2f74de504146bd0c380beb2b8b9235320924e68b..f80c4bf05b43dc6a60cf49168ad7015d6e233271 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -20,6 +20,10 @@ #include "thermal_core.h" +#ifdef CONFIG_HOUSTON +#include +#endif + /*** Private data structures to represent thermal device tree data ***/ /** @@ -1501,6 +1505,9 @@ int __init of_parse_thermal_zones(void) /* attempting to build remaining zones still */ continue; } +#ifdef CONFIG_HOUSTON + ht_register_thermal_zone_device(zone); +#endif tz->tzd = zone; } of_node_put(np); diff --git a/drivers/thermal/qcom/adc-tm.c b/drivers/thermal/qcom/adc-tm.c index b6359dd946da132ce0f3947b4b7c5dabe88095bf..f9a4c13fc8981f3c29e9c2d2fd85d4dfb31333a6 100644 --- a/drivers/thermal/qcom/adc-tm.c +++ b/drivers/thermal/qcom/adc-tm.c @@ -14,6 +14,10 @@ #include #include "adc-tm.h" +#ifdef CONFIG_HOUSTON +#include +#endif + LIST_HEAD(adc_tm_device_list); static int adc_tm_get_temp(void *data, int *temp) @@ -118,6 +122,11 @@ static int adc_tm_register_tzd(struct adc_tm_chip *adc_tm, int dt_chan_num, continue; } adc_tm->sensor[i].tzd = tzd; + +#ifdef CONFIG_HOUSTON + ht_register_thermal_zone_device(adc_tm->sensor[i].tzd); +#endif + } else adc_tm->sensor[i].tzd = NULL; } diff --git a/drivers/thermal/qcom/bcl_soc.c b/drivers/thermal/qcom/bcl_soc.c index a375f43ee2a5bd55b57155f2feb7fe806d134b0c..9e5036e5bc052da097b2196214c99c43e93afd6f 100644 --- a/drivers/thermal/qcom/bcl_soc.c +++ b/drivers/thermal/qcom/bcl_soc.c @@ -29,6 +29,7 @@ struct bcl_device { bool irq_enabled; struct thermal_zone_device *tz_dev; struct thermal_zone_of_device_ops ops; + struct work_struct bcl_usb_work; }; static struct bcl_device *bcl_perph; @@ -102,11 +103,48 @@ static void bcl_evaluate_soc(struct work_struct *work) mutex_unlock(&bcl_perph->state_trans_lock); } +/* + * When low soc, bcl set 2 perf cores to isolation, + * insert usb recover the perf cores. + */ +static void bcl_usb_process(struct work_struct *work) +{ + static struct power_supply *usb_psy; + union power_supply_propval ret = {0,}; + int err = 0; + + if (!usb_psy) + usb_psy = power_supply_get_by_name("usb"); + if (usb_psy) { + err = power_supply_get_property(usb_psy, + POWER_SUPPLY_PROP_PRESENT, &ret); + if (err) { + pr_err("USB status get error:%d\n", + err); + return; + } + if (ret.intval == 1) { + bcl_perph->tz_dev->ops->set_trip_temp( + bcl_perph->tz_dev, 1, 0); + thermal_zone_device_update(bcl_perph->tz_dev, + THERMAL_EVENT_UNSPECIFIED); + } else { + bcl_perph->tz_dev->ops->set_trip_temp( + bcl_perph->tz_dev, 1, 15); + thermal_zone_device_update(bcl_perph->tz_dev, + THERMAL_EVENT_UNSPECIFIED); + } + } +} + static int battery_supply_callback(struct notifier_block *nb, unsigned long event, void *data) { struct power_supply *psy = data; + if (!strcmp(psy->desc->name, "usb")) + schedule_work(&bcl_perph->bcl_usb_work); + if (strcmp(psy->desc->name, "battery")) return NOTIFY_OK; schedule_work(&bcl_perph->soc_eval_work); @@ -118,6 +156,7 @@ static int bcl_soc_remove(struct platform_device *pdev) { power_supply_unreg_notifier(&bcl_perph->psy_nb); flush_work(&bcl_perph->soc_eval_work); + flush_work(&bcl_perph->bcl_usb_work); if (bcl_perph->tz_dev) thermal_zone_of_sensor_unregister(&pdev->dev, bcl_perph->tz_dev); @@ -137,14 +176,7 @@ static int bcl_soc_probe(struct platform_device *pdev) bcl_perph->ops.get_temp = bcl_read_soc; bcl_perph->ops.set_trips = bcl_set_soc; INIT_WORK(&bcl_perph->soc_eval_work, bcl_evaluate_soc); - bcl_perph->psy_nb.notifier_call = battery_supply_callback; - ret = power_supply_reg_notifier(&bcl_perph->psy_nb); - if (ret < 0) { - pr_err("soc notifier registration error. defer. err:%d\n", - ret); - ret = -EPROBE_DEFER; - goto bcl_soc_probe_exit; - } + INIT_WORK(&bcl_perph->bcl_usb_work, bcl_usb_process); bcl_perph->tz_dev = thermal_zone_of_sensor_register(&pdev->dev, 0, bcl_perph, &bcl_perph->ops); if (IS_ERR(bcl_perph->tz_dev)) { @@ -155,6 +187,14 @@ static int bcl_soc_probe(struct platform_device *pdev) goto bcl_soc_probe_exit; } thermal_zone_device_update(bcl_perph->tz_dev, THERMAL_DEVICE_UP); + bcl_perph->psy_nb.notifier_call = battery_supply_callback; + ret = power_supply_reg_notifier(&bcl_perph->psy_nb); + if (ret < 0) { + pr_err("soc notifier registration error. defer. err:%d\n", + ret); + ret = -EPROBE_DEFER; + goto bcl_soc_probe_exit; + } schedule_work(&bcl_perph->soc_eval_work); dev_set_drvdata(&pdev->dev, bcl_perph); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 5ba494e5fddc15507aef6c8630134dca30556675..e7e664db54388ff2baf6b83b320527e511984130 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -22,10 +22,12 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include +#include #include "thermal_core.h" #include "thermal_hwmon.h" @@ -34,6 +36,9 @@ MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL v2"); #define THERMAL_MAX_ACTIVE 16 +#define THERMAL_MAX_MASK (1UL<<8) +#define THERMAL_TRIP_POINT (1UL<<7) +#define THERMAL_TEMP_MASK 0x7F static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_cdev_ida); @@ -53,6 +58,10 @@ static struct thermal_governor *def_governor; static struct workqueue_struct *thermal_passive_wq; +static struct thermal_zone_device *msm_tz, *skin_tz; +static struct thermal_zone_device *xo_mmw1_tz, *modem_mmw2_tz; +static struct thermal_zone_device *modem_skin_tz, *pa1_mmw0_tz; + /* * Governor section: set of functions to handle thermal governors * @@ -1323,7 +1332,33 @@ thermal_zone_device_register(const char *type, int trips, int mask, /* A new thermal zone needs to be updated anyway. */ atomic_set(&tz->need_update, 1); - dev_set_name(&tz->device, "thermal_zone%d", tz->id); + /*To unify the common skin thermal node that readable easier. + * Use + * /sys/class/thermal/msm-therm/ and /sys/class/thermal/skin-therm/ + * instead of + * /sys/class/thermal/thermal_zone84/ and + * /sys/class/thermal/thermal_zone94 + */ + if (strcmp(tz->type, "skin-therm") == 0) { + dev_set_name(&tz->device, tz->type); + skin_tz = tz; + } else if (strcmp(tz->type, "msm-therm") == 0) { + dev_set_name(&tz->device, tz->type); + msm_tz = tz; + } else if (strcmp(tz->type, "camera-flash-therm") == 0) { + dev_set_name(&tz->device, tz->type); + } else + dev_set_name(&tz->device, "thermal_zone%d", tz->id); + + if (strcmp(tz->type, "xo-therm-usr") == 0) + xo_mmw1_tz = tz; + else if (strcmp(tz->type, "modem-mmw2-usr") == 0) + modem_mmw2_tz = tz; + else if (strcmp(tz->type, "mmw-pa1-usr") == 0) + pa1_mmw0_tz = tz; + else if (strcmp(tz->type, "skin-therm-usr") == 0) + modem_skin_tz = tz; + result = device_register(&tz->device); if (result) goto remove_device_groups; @@ -1620,6 +1655,124 @@ static struct notifier_block thermal_pm_nb = { .notifier_call = thermal_pm_notify, }; +static int update_thermal_target(struct thermal_zone_device *tz, unsigned long val, int thermal_type) +{ + int ret = -1; + int temperature = 0, trip = 0; + static bool adjust; + + pr_info("%s::val = %ul, thermal_type = %d\n", __func__, val, thermal_type); + + if (val > THERMAL_MAX_MASK - 1) { + pr_err("%s: The input parameter is illegal, val = %ul\n", __func__, val); + return -EINVAL; + } + + if (!tz->ops->set_trip_temp) { + pr_err("%s: set_trip_temp is NULL!\n", __func__); + return -EINVAL; + } + + trip = (val & THERMAL_TRIP_POINT) >> 7; + temperature = THERMAL_TEMP_MASK & val; + + pr_err("%s: trip = %d, temp = %d\n", __func__, trip, temperature); + + if (temperature < 30) { + pr_err("%s: temp trip is too small!!\n", __func__); + return -EPERM; + } + + if (((temperature > 86) && (thermal_type == 0))|((temperature > 61) && (thermal_type == 1))) { + pr_err("%s: temp trip is too larger!!\n", __func__); + return -EPERM; + } + + ret = tz->ops->set_trip_temp(tz, trip, temperature*1000); + if (ret) + return ret; + + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + if (get_rf_version() == 13 && thermal_type == 1 && trip == 1) { + ret = tz->ops->set_trip_temp(tz, (trip+1), (temperature + 2)*1000); + if (ret) + return ret; + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + if ((temperature + 2) > 51) { + ret = tz->ops->set_trip_temp(tz, (trip+2), (temperature + 3)*1000); + if (ret) + return ret; + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + adjust = 1; + } else if (adjust) { + ret = tz->ops->set_trip_temp(tz, (trip+2), (temperature + 4)*1000); + if (ret) + return ret; + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + adjust = 0; + } + } + + pr_notice("%s: update_thermal config successful\n", __func__); + return ret; +} + +static int modem_skin_thermal_qos_handler(struct notifier_block *b, unsigned long val, void *v) +{ + return update_thermal_target(modem_skin_tz, val, 0); +} + +static struct notifier_block modem_skin_thermal_qos_notifier = { + .notifier_call = modem_skin_thermal_qos_handler, +}; + +static int pa1_mmw0_thermal_qos_handler(struct notifier_block *b, unsigned long val, void *v) +{ + return update_thermal_target(pa1_mmw0_tz, val, 0); +} + +static struct notifier_block pa1_mmw0_thermal_qos_notifier = { + .notifier_call = pa1_mmw0_thermal_qos_handler, +}; + +static int xo_mmw1_thermal_qos_handler(struct notifier_block *b, unsigned long val, void *v) +{ + return update_thermal_target(xo_mmw1_tz, val, 0); +} + +static struct notifier_block xo_mmw1_thermal_qos_notifier = { + .notifier_call = xo_mmw1_thermal_qos_handler, +}; + +static int modem_mmw2_qos_handler(struct notifier_block *b, unsigned long val, void *v) +{ + return update_thermal_target(modem_mmw2_tz, val, 0); +} + +static struct notifier_block modem_mmw2_qos_notifier = { + .notifier_call = modem_mmw2_qos_handler, +}; + +static int msm_thermal_qos_handler(struct notifier_block *b, unsigned long val, void *v) +{ + return update_thermal_target(msm_tz, val, 0); +} + +static struct notifier_block msm_thermal_qos_notifier = { + .notifier_call = msm_thermal_qos_handler, +}; + +static int skin_thermal_qos_handler(struct notifier_block *b, unsigned long val, void *v) +{ + return update_thermal_target(skin_tz, val, 1); +} + +static struct notifier_block skin_thermal_qos_notifier = { + .notifier_call = skin_thermal_qos_handler, +}; + static int __init thermal_init(void) { int result; @@ -1651,6 +1804,14 @@ static int __init thermal_init(void) pr_warn("Thermal: Can not register suspend notifier, return %d\n", result); + /*Power Teams add dynamic thermal qos notify. */ + pm_qos_add_notifier(PM_QOS_MSM_THERMAL, &msm_thermal_qos_notifier); + pm_qos_add_notifier(PM_QOS_SKIN_THERMAL, &skin_thermal_qos_notifier); + pm_qos_add_notifier(PM_QOS_MODEM_SKIN_THERMAL, &modem_skin_thermal_qos_notifier); + pm_qos_add_notifier(PM_QOS_MMW1_THERMAL, &xo_mmw1_thermal_qos_notifier); + pm_qos_add_notifier(PM_QOS_MMW0_THERMAL, &pa1_mmw0_thermal_qos_notifier); + pm_qos_add_notifier(PM_QOS_MMW2_THERMAL, &modem_mmw2_qos_notifier); + return 0; exit_zone_parse: diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index c1f18d2fcda47205ca07b6f0494102c047b47baa..7974b61acc47b111f21de6a874fcb8afc293d241 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -25,6 +25,7 @@ #include #include #include +#include /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG (0x22C) @@ -144,6 +145,20 @@ ipc_log_string(ctx, x); \ } while (0) + +/*we use dynamic add console , so we can't use */ +/*__init __exit, this will cause can't find func*/ +#ifdef __init +#undef __init +#endif + +#ifdef __exit +#undef __exit +#endif + +#define __init +#define __exit + #define DMA_RX_BUF_SIZE (2048) #define UART_CONSOLE_RX_WM (2) @@ -2938,7 +2953,7 @@ static const struct uart_ops msm_geni_serial_pops = { static const struct of_device_id msm_geni_device_tbl[] = { #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) - { .compatible = "qcom,msm-geni-console", + { .compatible = "qcom,msm-geni-console-oem", .data = (void *)&msm_geni_console_driver}, #endif { .compatible = "qcom,msm-geni-serial-hs", @@ -2946,6 +2961,26 @@ static const struct of_device_id msm_geni_device_tbl[] = { {}, }; +struct oemconsole { + bool default_console; + bool console_initialized; +}; + +static struct oemconsole oem_console = { + .default_console = false, + .console_initialized = false, +}; + +static int __init parse_console_config(char *str) +{ + if (str != NULL) + oem_console.default_console = true; + return 0; +} +early_param("console", parse_console_config); +static int msm_serial_oem_pinctrl_init(void); +static int oem_msm_geni_serial_init(void); + static int msm_geni_serial_get_ver_info(struct uart_port *uport) { int hw_ver, ret = 0; @@ -2997,7 +3032,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev) int ret = 0; int line; struct msm_geni_serial_port *dev_port; - struct uart_port *uport; + struct uart_port *uport = NULL; struct resource *res; struct uart_driver *drv; const struct of_device_id *id; @@ -3038,12 +3073,16 @@ static int msm_geni_serial_probe(struct platform_device *pdev) ret = PTR_ERR(dev_port); dev_err(&pdev->dev, "Invalid line %d(%d)\n", line, ret); - goto exit_geni_serial_probe; + return ret; } dev_port->is_console = is_console; uport = &dev_port->uport; - + if (!uport) { + dev_err(&pdev->dev, "%s: uart %s device not found\n", __func__, + is_console ? "console" : "serial"); + return -ENODEV; + } /* Don't allow 2 drivers to access the same port */ if (uport->private_data) { ret = -ENODEV; @@ -3437,12 +3476,32 @@ static const struct dev_pm_ops msm_geni_serial_pm_ops = { .resume_noirq = msm_geni_serial_sys_resume_noirq, }; +static const struct of_device_id msm_geni_device_tbl_oem_hs[] = { + { .compatible = "qcom,msm-geni-serial-hs"}, + {}, +}; + static struct platform_driver msm_geni_serial_platform_driver = { .remove = msm_geni_serial_remove, .probe = msm_geni_serial_probe, .driver = { .name = "msm_geni_serial", - .of_match_table = msm_geni_device_tbl, + .of_match_table = msm_geni_device_tbl_oem_hs, + .pm = &msm_geni_serial_pm_ops, + }, +}; + +static const struct of_device_id msm_geni_device_tbl_oem_console[] = { + { .compatible = "qcom,msm-geni-console-oem",}, + {}, +}; + +static struct platform_driver msm_oem_console = { + .remove = msm_geni_serial_remove, + .probe = msm_geni_serial_probe, + .driver = { + .name = "msm_geni_serial_oem", + .of_match_table = msm_geni_device_tbl_oem_console, .pm = &msm_geni_serial_pm_ops, }, }; @@ -3474,10 +3533,6 @@ static int __init msm_geni_serial_init(void) msm_geni_console_port.uport.line = i; } - ret = console_register(&msm_geni_console_driver); - if (ret) - return ret; - ret = uart_register_driver(&msm_geni_serial_hs_driver); if (ret) { uart_unregister_driver(&msm_geni_console_driver); @@ -3493,6 +3548,11 @@ static int __init msm_geni_serial_init(void) pr_info("%s: Driver initialized\n", __func__); + if (oem_console.default_console == 1) + oem_msm_geni_serial_init(); + else + msm_serial_oem_pinctrl_init(); + return ret; } module_init(msm_geni_serial_init); @@ -3505,6 +3565,104 @@ static void __exit msm_geni_serial_exit(void) } module_exit(msm_geni_serial_exit); +static int oem_msm_geni_serial_init(void) +{ + int ret = 0; + + pr_err("%s console_initialized=%d\n", + __func__, oem_console.console_initialized); + + if (oem_console.console_initialized != 1) { + oem_console.console_initialized = 1; + ret = console_register(&msm_geni_console_driver); + if (ret) + return ret; + + ret = platform_driver_register(&msm_oem_console); + if (ret) { + console_unregister(&msm_geni_console_driver); + return ret; + } + pr_info("%s: initialized", __func__); + } + return ret; +} + +static int msm_serial_pinctrl_probe(struct platform_device *pdev) +{ + + struct pinctrl *pinctrl = NULL; + struct pinctrl_state *set_state = NULL; + struct device *dev = &pdev->dev; + + pr_err("%s\n", __func__); + pinctrl = devm_pinctrl_get(dev); + + if (pinctrl != NULL) { + + set_state = pinctrl_lookup_state( + pinctrl, "uart_pinctrl_deactive"); + + if (set_state != NULL) + pinctrl_select_state(pinctrl, set_state); + + devm_pinctrl_put(pinctrl); + } + return 0; +} +static int msm_serial_pinctrl_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id oem_serial_pinctrl_of_match[] = { + { .compatible = "oem,oem_serial_pinctrl" }, + {} +}; + +static struct platform_driver msm_platform_serial_pinctrl_driver = { + .remove = msm_serial_pinctrl_remove, + .probe = msm_serial_pinctrl_probe, + .driver = { + .name = "oem_serial_pinctrl", + .of_match_table = oem_serial_pinctrl_of_match, + }, +}; + +static int msm_serial_oem_pinctrl_init(void) +{ + int ret = 0; + + pr_err("%s\n", __func__); + + ret = platform_driver_register(&msm_platform_serial_pinctrl_driver); + + return ret; +} +EXPORT_SYMBOL(msm_serial_oem_pinctrl_init); + +#define SERIAL_CMDLINE "ttyMSM0,115200n8" +char oem_force_cmdline_str[60]; + +int msm_serial_oem_init(void) +{ + int ret = 0; + + pr_err("%s\n", __func__); + + memcpy(oem_force_cmdline_str, SERIAL_CMDLINE, sizeof(SERIAL_CMDLINE)); + force_oem_console_setup(&oem_force_cmdline_str[0]); + oem_msm_geni_serial_init(); + return ret; +} +EXPORT_SYMBOL(msm_serial_oem_init); + +void msm_serial_oem_exit(void) +{ + pr_err("%s\n", __func__); + msm_geni_serial_exit(); +} +EXPORT_SYMBOL(msm_serial_oem_exit); MODULE_DESCRIPTION("Serial driver for GENI based QTI serial cores"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("tty:msm_geni_geni_serial"); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 60c2ec4daf75b44a22a42771683ad60aa599fcdd..88e2d2c64769722d2cba0ca21ade66b61732b264 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1804,6 +1804,14 @@ static int autosuspend_check(struct usb_device *udev) * or else their drivers don't support autosuspend * and so they are permanently active. */ +/* @bsp, 2019/09/18 usb & PD porting */ +/* Avoid crash due to broken fs on otg */ + if (!intf) { + dev_err(&udev->dev, "%s intf is NULL\n", + __func__); + return -EIO; + } + if (intf->dev.power.disable_depth) continue; if (atomic_read(&intf->dev.power.usage_count) > 0) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ed408f40017feba694d9e911c17689a5f92977ab..ef9bd803cd2eacea114a8b3b1164e8908ae6e331 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4446,6 +4446,7 @@ static int hub_set_address(struct usb_device *udev, int devnum) return retval; } +#if 0 /* * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM * when they're plugged into a USB 2.0 port, but they don't work when LPM is @@ -4466,12 +4467,17 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) if (hub) connect_type = hub->ports[udev->portnum - 1]->connect_type; +/* @bsp, 2019/09/18 usb & PD porting */ + if (!udev->bos) + return; + if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { udev->usb2_hw_lpm_allowed = 1; usb_enable_usb2_hardware_lpm(udev); } } +#endif static int hub_enable_device(struct usb_device *udev) { @@ -4835,7 +4841,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); - hub_set_initial_usb2_lpm_policy(udev); + /* hub_set_initial_usb2_lpm_policy(udev); */ fail: if (retval) { hub_port_disable(hub, port1, 0); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 6a76e997cb1a4c05585964a1d5a58a9a60ae2380..0a46ce1cbaee19963bd433c8a634ea9b0f373314 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -588,12 +588,13 @@ void usb_sg_cancel(struct usb_sg_request *io) int i, retval; spin_lock_irqsave(&io->lock, flags); - if (io->status) { + if (io->status || io->count == 0) { spin_unlock_irqrestore(&io->lock, flags); return; } /* shut everything down */ io->status = -ECONNRESET; + io->count++; /* Keep the request alive until we're done */ spin_unlock_irqrestore(&io->lock, flags); for (i = io->entries - 1; i >= 0; --i) { @@ -607,6 +608,12 @@ void usb_sg_cancel(struct usb_sg_request *io) dev_warn(&io->dev->dev, "%s, unlink --> %d\n", __func__, retval); } + + spin_lock_irqsave(&io->lock, flags); + io->count--; + if (!io->count) + complete(&io->complete); + spin_unlock_irqrestore(&io->lock, flags); } EXPORT_SYMBOL_GPL(usb_sg_cancel); diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index f4fea34555510e3ddc354667026aab78e8eabf09..c1d23684c1ed7935b491c98f3acaf7f3f8dd3ff3 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -71,6 +71,8 @@ #define CGCTL_REG (QSCRATCH_REG_OFFSET + 0x28) #define PWR_EVNT_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x58) #define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C) +/* @bsp, 2019/09/18 usb & PD porting */ +#define QSCRATCH_USB30_STS_REG (QSCRATCH_REG_OFFSET + 0xF8) #define PWR_EVNT_POWERDOWN_IN_P3_MASK BIT(2) #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) @@ -119,6 +121,8 @@ #define DWC3_GEVNTADRHI_EVNTADRHI_GSI_IDX(n) (n << 16) #define DWC3_GEVENT_TYPE_GSI 0x3 +struct dwc3_msm *g_mdwc; + enum usb_gsi_reg { GENERAL_CFG_REG, DBL_ADDR_L, @@ -353,6 +357,7 @@ struct dwc3_msm { u64 dummy_gsi_db; dma_addr_t dummy_gsi_db_dma; int orientation_override; + bool awake_status; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -2279,6 +2284,7 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) { + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); unsigned long timeout; u32 reg = 0; @@ -2306,8 +2312,19 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) if (reg & PWR_EVNT_LPM_IN_L2_MASK) break; } - if (!(reg & PWR_EVNT_LPM_IN_L2_MASK)) - dev_err(mdwc->dev, "could not transition HS PHY to L2\n"); + if (!(reg & PWR_EVNT_LPM_IN_L2_MASK)) { + dbg_event(0xFF, "PWR_EVNT_LPM", + dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG)); + dbg_event(0xFF, "QUSB_STS", + dwc3_msm_read_reg(mdwc->base, QSCRATCH_USB30_STS_REG)); + /* Mark fatal error for host mode or USB bus suspend case */ + if (mdwc->in_host_mode || (mdwc->vbus_active + && mdwc->drd_state == DRD_STATE_PERIPHERAL_SUSPEND)) { + queue_work(mdwc->dwc3_wq, &mdwc->resume_work); + dev_err(mdwc->dev, "could not transition HS PHY to L2\n"); + return -EBUSY; + } + } /* Clear L2 event bit */ dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, @@ -2647,6 +2664,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse) pm_wakeup_event(mdwc->dev, mdwc->lpm_to_suspend_delay); } else { pm_relax(mdwc->dev); + g_mdwc->awake_status = false; } atomic_set(&dwc->in_lpm, 1); @@ -2704,6 +2722,7 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) } pm_stay_awake(mdwc->dev); + g_mdwc->awake_status = true; if (mdwc->in_host_mode && mdwc->max_rh_port_speed == USB_SPEED_HIGH) dwc3_msm_update_bus_bw(mdwc, BUS_VOTE_SVS); @@ -3642,6 +3661,17 @@ static int dwc_dpdm_cb(struct notifier_block *nb, unsigned long evt, void *p) return NOTIFY_OK; } + +void op_release_usb_lock(void) +{ + dev_info(g_mdwc->dev, "%s enter\n", __func__); + if (g_mdwc->awake_status) { + dev_info(g_mdwc->dev, "%s relese lock\n", __func__); + pm_relax(g_mdwc->dev); + g_mdwc->awake_status = false; + } +} + static int dwc3_msm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node, *dwc3_node; @@ -3672,7 +3702,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) pr_err("%s: Unable to create workqueue dwc3_wq\n", __func__); return -ENOMEM; } - + g_mdwc = mdwc; /* * Create an ordered freezable workqueue for sm_work so that it gets * scheduled only after pm_resume has happened completely. This helps @@ -4181,8 +4211,8 @@ static void msm_dwc3_perf_vote_work(struct work_struct *w) static unsigned long last_irq_cnt; bool in_perf_mode = false; - if (dwc->irq_cnt - last_irq_cnt >= PM_QOS_THRESHOLD) - in_perf_mode = true; + /* if (dwc->irq_cnt - last_irq_cnt >= PM_QOS_THRESHOLD) */ + in_perf_mode = true; pr_debug("%s: in_perf_mode:%u, interrupts in last sample:%lu\n", __func__, in_perf_mode, (dwc->irq_cnt - last_irq_cnt)); @@ -4559,7 +4589,6 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA) return 0; } - /** * dwc3_otg_sm_work - workqueue function. * @@ -4646,7 +4675,9 @@ static void dwc3_otg_sm_work(struct work_struct *w) mdwc->drd_state = DRD_STATE_PERIPHERAL; work = 1; } else { - dwc3_msm_gadget_vbus_draw(mdwc, 0); +/* @bsp, 2019/09/18 usb & PD porting */ +/* Add to fix Can not charge in aging test */ + //dwc3_msm_gadget_vbus_draw(mdwc, 0); dev_dbg(mdwc->dev, "Cable disconnected\n"); } break; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 1b70b8da2a7208e8337faa0e59becd346323df02..9ea1f5105674ec553a583dfcabc49fcae1529525 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -27,6 +27,23 @@ #include "debug.h" #include "gadget.h" #include "io.h" +/* @bsp, 20170112 Add usb enumeration status */ +#include + +static struct notify_usb_enumeration_status + *usb_enumeration_status = NULL; + +void regsister_notify_usb_enumeration_status( + struct notify_usb_enumeration_status *status) +{ + if (usb_enumeration_status) { + usb_enumeration_status = status; + pr_err("multiple usb_enumeration_status called\n"); + } else { + usb_enumeration_status = status; + } +} +EXPORT_SYMBOL(regsister_notify_usb_enumeration_status); static bool enable_dwc3_u1u2; module_param(enable_dwc3_u1u2, bool, 0644); @@ -841,6 +858,11 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) ret = dwc3_ep0_handle_feature(dwc, ctrl, 1); break; case USB_REQ_SET_ADDRESS: +/* @bsp, 20170112 Add usb enumeration status */ + if (usb_enumeration_status + && usb_enumeration_status->notify_usb_enumeration) { + usb_enumeration_status->notify_usb_enumeration(true); + } ret = dwc3_ep0_set_address(dwc, ctrl); break; case USB_REQ_SET_CONFIGURATION: diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e9ea382b36f35cd5722de081ee54b4ea9313911e..62387a1c406e4b522a2fd9f9e1d82245df935a1b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2162,7 +2162,6 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) if (dwc->revision >= DWC3_REVISION_194A) reg &= ~DWC3_DCTL_KEEP_CONNECT; - dwc3_event_buffers_setup(dwc); __dwc3_gadget_start(dwc); @@ -2992,14 +2991,7 @@ static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep, static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req) { - /* - * For OUT direction, host may send less than the setup - * length. Return true for all OUT requests. - */ - if (!req->direction) - return true; - - return req->request.actual == req->request.length; + return req->num_pending_sgs == 0; } static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, @@ -3034,8 +3026,7 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep, req->request.actual = req->request.length - req->remaining; - if (!dwc3_gadget_ep_request_completed(req) || - req->num_pending_sgs) { + if (!dwc3_gadget_ep_request_completed(req)) { __dwc3_gadget_kick_transfer(dep); goto out; } @@ -3423,8 +3414,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc->b_suspend = false; dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_OTG_EVENT, 0); - usb_gadget_vbus_draw(&dwc->gadget, 100); - dwc3_reset_gadget(dwc); reg = dwc3_readl(dwc->regs, DWC3_DCTL); @@ -3837,8 +3826,6 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, if (dwc->gadget.state >= USB_STATE_CONFIGURED) dwc3_gadget_suspend_interrupt(dwc, event->event_info); - else - usb_gadget_vbus_draw(&dwc->gadget, 2); } break; case DWC3_DEVICE_EVENT_SOF: @@ -4011,6 +3998,14 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) if (!count) return IRQ_NONE; + if (count > evt->length) { + dev_err(dwc->dev, "HUGE_EVCNT(%d)", count); + dbg_event(0xFF, "HUGE_EVCNT", count); + evt->lpos = (evt->lpos + count) % DWC3_EVENT_BUFFERS_SIZE; + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); + return IRQ_HANDLED; + } + evt->count = count; evt->flags |= DWC3_EVENT_PENDING; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index a316b9a59eb6449d6758cc72d820b5bce001743c..7c440073ef52440e0c16547bf51527ffcbdecb76 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1736,12 +1736,9 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) cdev->desc.bcdUSB = cpu_to_le16(0x0320); cdev->desc.bMaxPacketSize0 = 9; } else { - cdev->desc.bcdUSB = cpu_to_le16(0x0210); + cdev->desc.bcdUSB = cpu_to_le16(0x0200); } } else { - if (gadget->lpm_capable) - cdev->desc.bcdUSB = cpu_to_le16(0x0201); - else cdev->desc.bcdUSB = cpu_to_le16(0x0200); } @@ -2418,7 +2415,6 @@ void composite_suspend(struct usb_gadget *gadget) cdev->suspended = 1; spin_unlock_irqrestore(&cdev->lock, flags); - usb_gadget_vbus_draw(gadget, 2); } void composite_resume(struct usb_gadget *gadget) diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c index 8124af33b7383b394974ae666ae5c230585653a9..d4e75bf95c28c88806f02cb5513ada11aa56fde0 100644 --- a/drivers/usb/gadget/function/f_audio_source.c +++ b/drivers/usb/gadget/function/f_audio_source.c @@ -570,14 +570,38 @@ static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt); + if (!alt) { + usb_ep_disable(audio->in_ep); + return 0; + } + ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep); - if (ret) + if (ret) { + audio->in_ep->desc = NULL; + pr_err("config_ep fail for audio ep ret %d\n", ret); + return ret; + } + ret = usb_ep_enable(audio->in_ep); + if (ret) { + audio->in_ep->desc = NULL; + pr_err("failed to enable audio ret %d\n", ret); return ret; + } - usb_ep_enable(audio->in_ep); return 0; } +/* + * Because the data interface supports multiple altsettings, + * this audio_source function *MUST* implement a get_alt() method. + */ +static int audio_get_alt(struct usb_function *f, unsigned int intf) +{ + struct audio_dev *audio = func_to_audio(f); + + return audio->in_ep->enabled ? 1 : 0; +} + static void audio_disable(struct usb_function *f) { struct audio_dev *audio = func_to_audio(f); @@ -841,6 +865,7 @@ static struct audio_dev _audio_dev = { .bind = audio_bind, .unbind = audio_unbind, .set_alt = audio_set_alt, + .get_alt = audio_get_alt, .setup = audio_setup, .disable = audio_disable, .free_func = audio_free_func, diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 511d46db60497bfc7561eda80b274cdc64dfe11e..7a9c00eaa9950085f5edcac3d221351dfcfd37a1 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -643,12 +643,21 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) ffs_log("state %d setup_state %d flags %lu opened %d", ffs->state, ffs->setup_state, ffs->flags, atomic_read(&ffs->opened)); +/* @bsp, 2019/09/218 usb & PD porting */ +/* Add log to check ep0 status */ + if (atomic_read(&ffs->opened)) { + pr_err("ep0 is already opened!\n"); + return -EBUSY; + } - if (unlikely(ffs->state == FFS_CLOSING)) + if (unlikely(ffs->state == FFS_CLOSING)) { + pr_err("FFS_CLOSING!\n"); return -EBUSY; + } file->private_data = ffs; ffs_data_opened(ffs); + pr_info("ep0_open success!\n"); return 0; } diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 8bce7ce0eaaa4871c4d12adf25f6e6b7bd72c870..e6e3e2dbdeb288d1c481be0f32426e3a858a22b0 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -228,6 +228,8 @@ /*------------------------------------------------------------------------*/ +/* @BSP, 2019/09/21, CD-ROM and VID customized */ +#define PAGE_CACHE_SIZE PAGE_SIZE #define FSG_DRIVER_DESC "Mass Storage Function" #define FSG_DRIVER_VERSION "2009/09/11" @@ -1181,6 +1183,250 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) return 8; } +/* @BSP, 2019/09/21, CD-ROM and VID customized */ +static void _lba_to_msf(u8 *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} + +static int _read_toc_raw(struct fsg_common *common, + struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + u8 *buf = (u8 *) bh->buf; + u8 *q; + int len; + int msf = common->cmnd[1] & 0x02; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + + if (msf) { + *q++ = 0; /* reserved */ + _lba_to_msf(q, curlun->num_sectors); + q += 3; + } else { + put_unaligned_be32(curlun->num_sectors, q); + q += 4; + } + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + + if (msf) { + *q++ = 0; + _lba_to_msf(q, 0); + q += 3; + } else { + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } + + len = q - buf; + put_unaligned_be16(len - 2, buf); + + return len; +} + +static void cd_data_to_raw(u8 *buf, int lba) +{ + /* sync bytes */ + buf[0] = 0x00; + memset(buf + 1, 0xff, 10); + buf[11] = 0x00; + buf += 12; + + /* MSF */ + _lba_to_msf(buf, lba); + buf[3] = 0x01; /* mode 1 data */ + buf += 4; + + /* data */ + buf += 2048; + + /* XXX: ECC not computed */ + memset(buf, 0, 288); +} + +static int do_read_cd(struct fsg_common *common) +{ + struct fsg_lun *curlun = common->curlun; + struct fsg_buffhd *bh; + int rc; + u32 lba; + u32 amount_left; + u32 nb_sectors, transfer_request; + loff_t file_offset, file_offset_tmp; + unsigned int amount; + unsigned int partial_page; + ssize_t nread; + + nb_sectors = (common->cmnd[6] << 16) | + (common->cmnd[7] << 8) | common->cmnd[8]; + lba = get_unaligned_be32(&common->cmnd[2]); + + if (nb_sectors == 0) + return 0; + + if (lba >= curlun->num_sectors) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + return -EINVAL; + } + + transfer_request = common->cmnd[9]; + if ((transfer_request & 0xf8) == 0xf8) { + file_offset = ((loff_t) lba) << 11; + /* read all data - 2352 byte */ + amount_left = 2352; + } else { + file_offset = ((loff_t) lba) << 9; + /* Carry out the file reads */ + amount_left = common->data_size_from_cmnd; + } + + if (unlikely(amount_left == 0)) + return -EIO; /* No default reply */ + + for (;;) { + /* + * Figure out how much we need to read: + * Try to read the remaining amount. + * But don't read more than the buffer size. + * And don't try to read past the end of the file. + * Finally, if we're not at a page boundary, don't read past + * the next page. + * If this means reading 0 then we were asked to read past + * the end of file. + */ + amount = min(amount_left, FSG_BUFLEN); + amount = min((loff_t) amount, + curlun->file_length - file_offset); + partial_page = file_offset & (PAGE_CACHE_SIZE - 1); + if (partial_page > 0) + amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - + partial_page); + + /* Wait for the next buffer to become available */ + bh = common->next_buffhd_to_fill; + while (bh->state != BUF_STATE_EMPTY) { + rc = sleep_thread(common, true, bh); + if (rc) + return rc; + } + + /* + * If we were asked to read past the end of file, + * end with an empty buffer. + */ + if (amount == 0) { + curlun->sense_data = + SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + bh->inreq->length = 0; + bh->state = BUF_STATE_FULL; + break; + } + + /* Perform the read */ + file_offset_tmp = file_offset; + if ((transfer_request & 0xf8) == 0xf8) { + nread = vfs_read(curlun->filp, + ((char __user *)bh->buf)+16, + amount, &file_offset_tmp); + } else { + nread = vfs_read(curlun->filp, + (char __user *)bh->buf, + amount, &file_offset_tmp); + } + VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, + (unsigned long long) file_offset, + (int) nread); + if (signal_pending(current)) + return -EINTR; + + if (nread < 0) { + LDBG(curlun, "error in file read: %d\n", + (int) nread); + nread = 0; + } else if (nread < amount) { + LDBG(curlun, "partial file read: %d/%u\n", + (int) nread, amount); + nread -= (nread & 511); /* Round down to a block */ + } + file_offset += nread; + amount_left -= nread; + common->residue -= nread; + bh->inreq->length = nread; + bh->state = BUF_STATE_FULL; + + /* If an error occurred, report it and its position */ + if (nread < amount) { + curlun->sense_data = SS_UNRECOVERED_READ_ERROR; + curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; + break; + } + + if (amount_left == 0) + break; /* No more left to read */ + + /* Send this buffer and go read some more */ + if (!start_in_transfer(common, bh)) + return -EIO; + common->next_buffhd_to_fill = bh->next; + } + + if ((transfer_request & 0xf8) == 0xf8) + cd_data_to_raw(bh->buf, lba); + + return -EIO; /* No default reply */ +} + static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) { struct fsg_lun *curlun = common->curlun; @@ -1188,12 +1434,19 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) int start_track = common->cmnd[6]; u8 *buf = (u8 *)bh->buf; +/* @BSP, 2019/09/21, CD-ROM and VID customized */ + int format = (common->cmnd[9] & 0xC0) >> 6; + if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ start_track > 1) { curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } +/* @BSP, 2019/09/21, CD-ROM and VID customized */ + if (format == 2) + return _read_toc_raw(common, bh); + memset(buf, 0, 20); buf[1] = (20-2); /* TOC data length */ buf[2] = 1; /* First track number */ @@ -1931,12 +2184,25 @@ static int do_scsi_command(struct fsg_common *common) goto unknown_cmnd; common->data_size_from_cmnd = get_unaligned_be16(&common->cmnd[7]); + +/* @BSP, 2019/09/21, CD-ROM and VID customized */ reply = check_command(common, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, + (0xf<<6) | (1<<1), 1, "READ TOC"); if (reply == 0) reply = do_read_toc(common, bh); break; +/* @BSP, 2019/09/21, CD-ROM and VID customized */ + case READ_CD: + common->data_size_from_cmnd = ((common->cmnd[6] << 16) + | (common->cmnd[7] << 8) + | (common->cmnd[8])) << 9; + reply = check_command(common, 12, DATA_DIR_TO_HOST, + (0xf<<2) | (7<<7), 1, + "READ CD"); + if (reply == 0) + reply = do_read_cd(common); + break; case READ_FORMAT_CAPACITIES: common->data_size_from_cmnd = @@ -2219,18 +2485,6 @@ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) } } - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; - } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - - /* allow usb LPM after eps are disabled */ - usb_gadget_autopm_put_async(common->gadget); common->fsg = NULL; wake_up(&common->fsg_wait); } @@ -2242,28 +2496,6 @@ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) common->fsg = new_fsg; fsg = common->fsg; - /* Enable the endpoints */ - rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in); - if (rc) - goto reset; - rc = usb_ep_enable(fsg->bulk_in); - if (rc) - goto reset; - fsg->bulk_in->driver_data = common; - fsg->bulk_in_enabled = 1; - - rc = config_ep_by_speed(common->gadget, &(fsg->function), - fsg->bulk_out); - if (rc) - goto reset; - rc = usb_ep_enable(fsg->bulk_out); - if (rc) - goto reset; - fsg->bulk_out->driver_data = common; - fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - /* Allocate the requests */ for (i = 0; i < common->fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; @@ -2294,19 +2526,68 @@ static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct fsg_dev *fsg = fsg_from_func(f); + int rc; /* prevents usb LPM until thread runs to completion */ usb_gadget_autopm_get_async(fsg->common->gadget); + /* Enable the endpoints */ + + rc = config_ep_by_speed(fsg->common->gadget, &(fsg->function), + fsg->bulk_in); + + if (rc) + goto err_exit; + rc = usb_ep_enable(fsg->bulk_in); + if (rc) + goto err_exit; + fsg->bulk_in->driver_data = fsg->common; + fsg->bulk_in_enabled = 1; + + rc = config_ep_by_speed(fsg->common->gadget, &(fsg->function), + fsg->bulk_out); + if (rc) + goto reset_bulk_int; + rc = usb_ep_enable(fsg->bulk_out); + if (rc) + goto reset_bulk_int; + fsg->bulk_out->driver_data = fsg->common; + fsg->bulk_out_enabled = 1; + fsg->common->bulk_out_maxpacket = + usb_endpoint_maxp(fsg->bulk_out->desc); + clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); + __raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE, fsg); return USB_GADGET_DELAYED_STATUS; + +reset_bulk_int: + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in->driver_data = NULL; + fsg->bulk_in_enabled = 0; +err_exit: + return rc; } static void fsg_disable(struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in->driver_data = NULL; + fsg->bulk_in_enabled = 0; + } + + if (fsg->bulk_out_enabled) { + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out->driver_data = NULL; + fsg->bulk_out_enabled = 0; + } + __raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE, NULL); + /* allow usb LPM after eps are disabled */ + usb_gadget_autopm_put_async(fsg->common->gadget); } @@ -2865,6 +3146,10 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, ? "File-CD Gadget" : "File-Stor Gadget"), i); +/* @BSP, 2019/09/21, CD-ROM and VID customized */ + snprintf(common->inquiry_string, + sizeof(common->inquiry_string), + "%s", "OnePlus Device Driver"); } EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); @@ -3373,6 +3658,9 @@ static struct usb_function_instance *fsg_alloc_inst(void) memset(&config, 0, sizeof(config)); config.removable = true; +/* enable cdrom config to read usb_driver.iso in PC;CD-ROM and VID customized*/ + config.cdrom = true; + config.ro = true; rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", (const char **)&opts->func_inst.group.cg_item.ci_name); if (rc) diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index 80ff811b6b1a1262693fe1a1081c97a105fd64b9..2738c1bebcce6cab304dfe0bd76a8adc3056cade 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "configfs.h" @@ -55,6 +56,8 @@ ipc_log_string(_mtp_ipc_log, "%s: " fmt, __func__, ##__VA_ARGS__) #endif +static bool mtp_receive_flag; + #define MTP_RX_BUFFER_INIT_SIZE 1048576 #define MTP_TX_BUFFER_INIT_SIZE 1048576 #define MTP_BULK_BUFFER_SIZE 16384 @@ -62,6 +65,20 @@ #define MAX_INST_NAME_LEN 40 #define MTP_MAX_FILE_SIZE 0xFFFFFFFFL +/* @bsp, 2019/09/18 usb & PD porting */ +/* OP fix device crash when setting MTP as usb mode use fixed memory */ +#define MTP_TX_BUFFER_BASE 0xCC300000 +#define MTP_RX_BUFFER_BASE 0xCCB00000 +#define MTP_INTR_BUFFER_BASE 0xCCD00000 + +static int mtpBufferOffset; +static bool useFixAddr; +enum buf_type { + TX_BUFFER = 0, + RX_BUFFER, + INTR_BUFFER, +}; + /* String IDs */ #define INTERFACE_STRING_INDEX 0 @@ -92,6 +109,9 @@ #define DRIVER_NAME "mtp" #define MAX_ITERATION 100 +/* values for qos requests */ +#define FILE_LENGTH (10 * 1024 * 1024) +#define PM_QOS_TIMEOUT 3000000 unsigned int mtp_rx_req_len = MTP_RX_BUFFER_INIT_SIZE; module_param(mtp_rx_req_len, uint, 0644); @@ -103,6 +123,12 @@ unsigned int mtp_tx_reqs = MTP_TX_REQ_MAX; module_param(mtp_tx_reqs, uint, 0644); static const char mtp_shortname[] = DRIVER_NAME "_usb"; +static struct pm_qos_request little_cpu_mtp_freq; +static struct pm_qos_request devfreq_mtp_request; +static struct pm_qos_request big_cpu_mtp_freq; +static struct pm_qos_request big_plus_cpu_mtp_freq; +static struct delayed_work cpu_freq_qos_work; +static struct workqueue_struct *cpu_freq_qos_queue; struct mtp_dev { struct usb_function function; @@ -160,9 +186,9 @@ static struct usb_interface_descriptor mtp_interface_desc = { .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bNumEndpoints = 3, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, - .bInterfaceProtocol = 0, + .bInterfaceClass = USB_CLASS_STILL_IMAGE, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 1, }; static struct usb_interface_descriptor ptp_interface_desc = { @@ -400,7 +426,10 @@ static inline struct mtp_dev *func_to_mtp(struct usb_function *f) return container_of(f, struct mtp_dev, function); } -static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) +/* OP fix device crash when setting MTP as usb mode use fixed memory */ +static struct usb_request *mtp_request_new(struct usb_ep *ep, + int buffer_size, enum buf_type type) + { struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); @@ -408,19 +437,43 @@ static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) return NULL; /* now allocate buffers for the requests */ - req->buf = kmalloc(buffer_size, GFP_KERNEL); + if (useFixAddr) { + if (type == TX_BUFFER) + req->buf = __va(MTP_TX_BUFFER_BASE + mtpBufferOffset); + else if (type == RX_BUFFER) + req->buf = __va(MTP_RX_BUFFER_BASE + mtpBufferOffset); + else + req->buf = __va(MTP_INTR_BUFFER_BASE + mtpBufferOffset); + } else + req->buf = kmalloc(buffer_size, GFP_KERNEL); + memset(req->buf, 0, buffer_size); if (!req->buf) { usb_ep_free_request(ep, req); return NULL; } + if (useFixAddr) { + if (buffer_size == INTR_BUFFER_SIZE) + mtpBufferOffset += 0x40; /* alignment */ + else + mtpBufferOffset += buffer_size; + } + return req; } static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) { if (req) { - kfree(req->buf); + /* + * OP fix device crash when setting MTP as usb mode + * use fixed memory + */ + if (useFixAddr) { + req->buf = NULL; + mtpBufferOffset = 0; + } else + kfree(req->buf); usb_ep_free_request(ep, req); } } @@ -499,6 +552,7 @@ static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) if (req->status != 0 && dev->state != STATE_OFFLINE) dev->state = STATE_ERROR; + mtp_log("sent event, put back request\n"); mtp_req_put(dev, &dev->intr_idle, req); wake_up(&dev->intr_wq); @@ -544,9 +598,24 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, dev->ep_intr = ep; retry_tx_alloc: + /* OP fix device crash when setting MTP as usb mode use fixed memory */ + if (mtp_tx_req_len == MTP_TX_BUFFER_INIT_SIZE + && mtp_rx_req_len == MTP_RX_BUFFER_INIT_SIZE + && mtp_tx_reqs == MTP_TX_REQ_MAX) + useFixAddr = true; + else + useFixAddr = false; + pr_info("useFixAddr:%s\n", useFixAddr ? "true" : "false"); + mtpBufferOffset = 0; + /* now allocate requests for our endpoints */ for (i = 0; i < mtp_tx_reqs; i++) { - req = mtp_request_new(dev->ep_in, mtp_tx_req_len); + /* + * OP fix device crash when setting MTP as usb mode + * use fixed memory + */ + req = mtp_request_new(dev->ep_in, + mtp_tx_req_len, TX_BUFFER); if (!req) { if (mtp_tx_req_len <= MTP_BULK_BUFFER_SIZE) goto fail; @@ -570,8 +639,11 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, mtp_rx_req_len = MTP_BULK_BUFFER_SIZE; retry_rx_alloc: + /* OP fix device crash when setting MTP as usb mode use fixed memory */ + mtpBufferOffset = 0; for (i = 0; i < RX_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_out, mtp_rx_req_len); + req = mtp_request_new(dev->ep_out, + mtp_rx_req_len, RX_BUFFER); if (!req) { if (mtp_rx_req_len <= MTP_BULK_BUFFER_SIZE) goto fail; @@ -583,13 +655,17 @@ static int mtp_create_bulk_endpoints(struct mtp_dev *dev, req->complete = mtp_complete_out; dev->rx_req[i] = req; } + /* OP fix device crash when setting MTP as usb mode use fixed memory */ + mtpBufferOffset = 0; for (i = 0; i < INTR_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE); + req = mtp_request_new(dev->ep_intr, + INTR_BUFFER_SIZE, INTR_BUFFER); if (!req) goto fail; req->complete = mtp_complete_intr; mtp_req_put(dev, &dev->intr_idle, req); } + mtpBufferOffset = 0; return 0; @@ -692,8 +768,11 @@ static ssize_t mtp_read(struct file *fp, char __user *buf, mtp_log("rx %pK %d\n", req, req->actual); xfer = (req->actual < count) ? req->actual : count; r = xfer; - if (copy_to_user(buf, req->buf, xfer)) - r = -EFAULT; + if (dev->ep_out->enabled) { + if (copy_to_user(buf, req->buf, xfer)) + r = -EFAULT; + } else + r = -EIO; } else r = -EIO; @@ -827,6 +906,22 @@ static void send_file_work(struct work_struct *data) mtp_log("(%lld %lld)\n", offset, count); + if (dev->xfer_file_length >= FILE_LENGTH) { + pm_qos_update_request(&devfreq_mtp_request, MAX_CPUFREQ - 1); + pm_qos_update_request(&little_cpu_mtp_freq, MAX_CPUFREQ); + pm_qos_update_request(&big_cpu_mtp_freq, MAX_CPUFREQ); + pm_qos_update_request(&big_plus_cpu_mtp_freq, MAX_CPUFREQ); + } else { + pm_qos_update_request_timeout(&devfreq_mtp_request, + MAX_CPUFREQ - 1, PM_QOS_TIMEOUT); + pm_qos_update_request_timeout(&little_cpu_mtp_freq, + MAX_CPUFREQ, PM_QOS_TIMEOUT); + pm_qos_update_request_timeout(&big_cpu_mtp_freq, + MAX_CPUFREQ, PM_QOS_TIMEOUT); + pm_qos_update_request_timeout(&big_plus_cpu_mtp_freq, + MAX_CPUFREQ, PM_QOS_TIMEOUT); + } + if (dev->xfer_send_header) { hdr_size = sizeof(struct mtp_data_header); count += hdr_size; @@ -914,6 +1009,12 @@ static void send_file_work(struct work_struct *data) if (req) mtp_req_put(dev, &dev->tx_idle, req); + if (dev->xfer_file_length >= FILE_LENGTH) { + pm_qos_update_request(&devfreq_mtp_request, MIN_CPUFREQ); + pm_qos_update_request(&little_cpu_mtp_freq, MIN_CPUFREQ); + pm_qos_update_request(&big_cpu_mtp_freq, MIN_CPUFREQ); + pm_qos_update_request(&big_plus_cpu_mtp_freq, MIN_CPUFREQ); + } mtp_log("returning %d state:%d\n", r, dev->state); /* write the result */ dev->xfer_result = r; @@ -943,6 +1044,14 @@ static void receive_file_work(struct work_struct *data) if (!IS_ALIGNED(count, dev->ep_out->maxpacket)) mtp_log("- count(%lld) not multiple of mtu(%d)\n", count, dev->ep_out->maxpacket); + + if (delayed_work_pending(&cpu_freq_qos_work)) + cancel_delayed_work(&cpu_freq_qos_work); + + pm_qos_update_request(&devfreq_mtp_request, MAX_CPUFREQ - 1); + pm_qos_update_request(&little_cpu_mtp_freq, MAX_CPUFREQ); + pm_qos_update_request(&big_cpu_mtp_freq, MAX_CPUFREQ); + pm_qos_update_request(&big_plus_cpu_mtp_freq, MAX_CPUFREQ); mutex_lock(&dev->read_mutex); if (dev->state == STATE_OFFLINE) { r = -EIO; @@ -1032,11 +1141,22 @@ static void receive_file_work(struct work_struct *data) } fail: mutex_unlock(&dev->read_mutex); + + queue_delayed_work(cpu_freq_qos_queue, &cpu_freq_qos_work, + msecs_to_jiffies(1000)*3); + mtp_log("returning %d\n", r); /* write the result */ dev->xfer_result = r; smp_wmb(); } +static void update_qos_request(struct work_struct *data) +{ + pm_qos_update_request(&devfreq_mtp_request, MIN_CPUFREQ); + pm_qos_update_request(&little_cpu_mtp_freq, MIN_CPUFREQ); + pm_qos_update_request(&big_cpu_mtp_freq, MIN_CPUFREQ); + pm_qos_update_request(&big_plus_cpu_mtp_freq, MIN_CPUFREQ); +} static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) { @@ -1053,7 +1173,7 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) ret = wait_event_interruptible_timeout(dev->intr_wq, (req = mtp_req_get(dev, &dev->intr_idle)), - msecs_to_jiffies(1000)); + msecs_to_jiffies(32)); if (!req) return -ETIME; @@ -1122,20 +1242,38 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned int code, dev->xfer_send_header = 0; } else { work = &dev->receive_file_work; + pm_qos_update_request(&devfreq_mtp_request, MAX_CPUFREQ - 1); + pm_qos_update_request(&little_cpu_mtp_freq, MAX_CPUFREQ); + pm_qos_update_request(&big_cpu_mtp_freq, MAX_CPUFREQ); + pm_qos_update_request(&big_plus_cpu_mtp_freq, MAX_CPUFREQ); + msm_cpuidle_set_sleep_disable(true); + mtp_receive_flag = true; } /* We do the file transfer on a work queue so it will run * in kernel context, which is necessary for vfs_read and * vfs_write to use our buffers in the kernel address space. */ + dev->xfer_result = 0; queue_work(dev->wq, work); /* wait for operation to complete */ flush_workqueue(dev->wq); - fput(filp); - + if (mtp_receive_flag) { + mtp_receive_flag = false; + pm_qos_update_request_timeout(&devfreq_mtp_request, + MAX_CPUFREQ - 1, PM_QOS_TIMEOUT); + pm_qos_update_request_timeout(&little_cpu_mtp_freq, + MAX_CPUFREQ, PM_QOS_TIMEOUT); + pm_qos_update_request_timeout(&big_cpu_mtp_freq, + MAX_CPUFREQ, PM_QOS_TIMEOUT); + pm_qos_update_request_timeout(&big_plus_cpu_mtp_freq, + MAX_CPUFREQ, PM_QOS_TIMEOUT); + msm_cpuidle_set_sleep_disable(false); + } /* read the result */ smp_rmb(); ret = dev->xfer_result; + fput(filp); fail: spin_lock_irq(&dev->lock); @@ -1277,6 +1415,10 @@ static int mtp_release(struct inode *ip, struct file *fp) { printk(KERN_INFO "mtp_release\n"); + if (mtp_receive_flag) { + mtp_receive_flag = false; + msm_cpuidle_set_sleep_disable(false); + } mtp_unlock(&_mtp_dev->open_excl); return 0; } @@ -1706,6 +1848,16 @@ static int __mtp_setup(struct mtp_instance *fi_mtp) INIT_WORK(&dev->send_file_work, send_file_work); INIT_WORK(&dev->receive_file_work, receive_file_work); + cpu_freq_qos_queue = create_singlethread_workqueue("f_mtp_qos"); + INIT_DELAYED_WORK(&cpu_freq_qos_work, update_qos_request); + pm_qos_add_request(&little_cpu_mtp_freq, PM_QOS_C0_CPUFREQ_MIN, + MIN_CPUFREQ); + pm_qos_add_request(&devfreq_mtp_request, PM_QOS_DEVFREQ_MIN, + MIN_CPUFREQ); + pm_qos_add_request(&big_cpu_mtp_freq, PM_QOS_C1_CPUFREQ_MIN, + MIN_CPUFREQ); + pm_qos_add_request(&big_plus_cpu_mtp_freq, PM_QOS_C2_CPUFREQ_MIN, + MIN_CPUFREQ); _mtp_dev = dev; ret = misc_register(&mtp_device); @@ -1716,6 +1868,11 @@ static int __mtp_setup(struct mtp_instance *fi_mtp) return 0; err2: + pm_qos_remove_request(&big_plus_cpu_mtp_freq); + pm_qos_remove_request(&big_cpu_mtp_freq); + pm_qos_remove_request(&little_cpu_mtp_freq); + pm_qos_remove_request(&devfreq_mtp_request); + destroy_workqueue(cpu_freq_qos_queue); destroy_workqueue(dev->wq); err1: _mtp_dev = NULL; @@ -1738,6 +1895,11 @@ static void mtp_cleanup(void) return; mtp_debugfs_remove(); + pm_qos_remove_request(&big_plus_cpu_mtp_freq); + pm_qos_remove_request(&big_cpu_mtp_freq); + pm_qos_remove_request(&little_cpu_mtp_freq); + pm_qos_remove_request(&devfreq_mtp_request); + destroy_workqueue(cpu_freq_qos_queue); misc_deregister(&mtp_device); destroy_workqueue(dev->wq); _mtp_dev = NULL; @@ -1855,6 +2017,11 @@ static int mtp_ctrlreq_configfs(struct usb_function *f, static void mtp_free(struct usb_function *f) { /*NO-OP: no function specific resource allocation in mtp_alloc*/ +/* @bsp, 2019/09/18 usb & PD porting */ + struct mtp_instance *fi_mtp; + + fi_mtp = container_of(f->fi, struct mtp_instance, func_inst); + fi_mtp->func_inst.f = NULL; } struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi, diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 4e944c04be419d601b814306fe05d0ec197acd19..eacd81847e6f4ba7f4a34c10ca8d5c7410907f04 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -650,6 +650,8 @@ int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) goto out; } +/* @bsp, 2019/09/18 usb & PD porting */ + pr_info("%s USB setting current is %umA\n", __func__, mA); ret = gadget->ops->vbus_draw(gadget, mA); if (!ret) gadget->mA = mA; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 5a27091f252433307fd95b8a214db0f939e66b32..1fc8c7b39cd7128f049285a1119ecb72bb830586 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -17,6 +17,13 @@ #include "xhci.h" #include "xhci-trace.h" #include "xhci-debugfs.h" +/* @bsp, 2019/09/18 usb & PD porting */ +/* Disable hw-lpm for some u-disk */ +#include + +static bool usb2_lpm_disable = 1; +module_param(usb2_lpm_disable, bool, 0644); +MODULE_PARM_DESC(usb2_lpm_disable, "DISABLE USB2 LPM"); /* * Allocates a generic ring segment from the ring pool, sets the dma address, @@ -2314,7 +2321,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xHCI 1.0: support USB2 software lpm"); xhci->sw_lpm_support = 1; - if (temp & XHCI_HLC) { +/* @bsp, Disable hw-lpm for some u-disk */ + if (!usb2_lpm_disable && (temp & XHCI_HLC)) { xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xHCI 1.0: support USB2 hardware lpm"); xhci->hw_lpm_support = 1; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 20ea7f5cb044d490962dce518c17119b07edcdaa..fb0c92ce8c3a39f875cba051944f62fdee533e1c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2751,6 +2751,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) ret = IRQ_HANDLED; goto out; } +/* @bsp, 2019/09/18 usb & PD porting */ +/* Abort suspend when interrupt is pending */ + if (status & STS_HCE) + xhci_warn(xhci, "WARNING: Host controller Error\n"); if (!(status & STS_EINT)) goto out; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3892106807affb54bbc3f4d97f7728bec9461dc9..bca37848a12d5a7b3532bbf27a3cb44abf3f4599 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -138,7 +138,10 @@ int xhci_halt(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, 2 * XHCI_MAX_HALT_USEC); if (ret) { - xhci_warn(xhci, "Host halt failed, %d\n", ret); +/* @bsp, 2019/09/18 usb & PD porting */ + xhci_warn(xhci, + "Host not halted after %u ms. ret=%d\n", + XHCI_MAX_HALT_USEC, ret); return ret; } xhci->xhc_state |= XHCI_STATE_HALTED; @@ -1043,6 +1046,20 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; } +/* @bsp, 2019/09/18 usb & PD porting */ + if ((readl_relaxed(&xhci->op_regs->status) & STS_EINT) || + (readl_relaxed(&xhci->op_regs->status) & STS_PORT)) { + xhci_warn(xhci, "WARN: xHC EINT/PCD set status:%x\n", + readl_relaxed(&xhci->op_regs->status)); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + /* step 4: set Run/Stop bit */ + command = readl_relaxed(&xhci->op_regs->command); + command |= CMD_RUN; + writel_relaxed(command, &xhci->op_regs->command); + spin_unlock_irq(&xhci->lock); + return -EBUSY; + } xhci_clear_command_ring(xhci); /* step 3: save registers */ diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6692263ae9d4730be6fdb0e24f39090023c6d2fb..3f2e15207de8d650e0d9993923242e098dfc07f4 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -21,6 +21,11 @@ #include #include #include "usbpd.h" +/* @bsp, 2019/09/18 usb & PD porting */ +/* To start USB stack for USB3.1 compliance testing */ +static bool usb_compliance_mode; +module_param(usb_compliance_mode, bool, 0644); +MODULE_PARM_DESC(usb_compliance_mode, "USB3.1 compliance testing"); enum usbpd_state { PE_UNKNOWN, @@ -402,6 +407,9 @@ struct usbpd { bool peer_usb_comm; bool peer_pr_swap; bool peer_dr_swap; +/* @bsp, 2019/09/18 usb & PD porting */ + bool oem_bypass; + bool periph_direct; u32 sink_caps[7]; int num_sink_caps; @@ -415,6 +423,8 @@ struct usbpd { int bat_voltage_max; enum power_supply_typec_mode typec_mode; +/* @bsp, 2019/09/18 usb & PD porting */ + enum power_supply_type psy_type; enum power_supply_typec_power_role forced_pr; bool vbus_present; @@ -478,6 +488,8 @@ struct usbpd { u32 battery_sts_dobj; }; +static struct usbpd *pd_p; + static LIST_HEAD(_usbpd); /* useful for debugging */ static const unsigned int usbpd_extcon_cable[] = { @@ -1399,10 +1411,11 @@ EXPORT_SYMBOL(usbpd_vdm_in_suspend); static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos, u16 vdm_hdr) { - int ret, i; + int i; u16 svid, *psvid; u8 cmd = SVDM_HDR_CMD(vdm_hdr); struct usbpd_svid_handler *handler; + u32 op_svid; switch (cmd) { case USBPD_SVDM_DISCOVER_IDENTITY: @@ -1414,16 +1427,21 @@ static void handle_vdm_resp_ack(struct usbpd *pd, u32 *vdos, u8 num_vdos, break; } - if (ID_HDR_PRODUCT_TYPE(vdos[0]) == ID_HDR_PRODUCT_VPD) { - usbpd_dbg(&pd->dev, "VPD detected turn off vbus\n"); + /* @bsp, 2020/08/04, add to detect SVID */ + if (num_vdos == 3) { + op_svid = vdos[0] & 0xffff; - if (pd->vbus_enabled) { - ret = regulator_disable(pd->vbus); - if (ret) - usbpd_err(&pd->dev, "Err disabling vbus (%d)\n", - ret); - else - pd->vbus_enabled = false; + usbpd_info(&pd->dev, "OP SVID discovered: 0x%04x\n", op_svid); + if (op_svid == OP_SVID) { + handler = find_svid_handler(pd, op_svid); + if (handler) { + usbpd_info(&pd->dev, "op_svid SVID: 0x%04x connected\n", + handler->svid); + handler->connect(handler, + pd->peer_usb_comm); + handler->discovered = true; + break; + } } } @@ -1598,7 +1616,16 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) switch (cmd_type) { case SVDM_CMD_TYPE_INITIATOR: if (cmd != USBPD_SVDM_ATTENTION) { - if (pd->spec_rev == USBPD_REV_30) { +/* @bsp, 2019/09/18 usb & PD porting */ +/* Add to fix power role switch issue when connect MAC */ +// if (pd->spec_rev == USBPD_REV_30) { +// ret = pd_send_msg(pd, MSG_NOT_SUPPORTED, NULL, +// 0, SOP_MSG); +// if (ret) +// usbpd_set_state(pd, PE_SEND_SOFT_RESET); + if ((cmd == USBPD_SVDM_DISCOVER_SVIDS) + && (pd->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH)) { + usbpd_info(&pd->dev, "not supported send svid."); ret = pd_send_msg(pd, MSG_NOT_SUPPORTED, NULL, 0, SOP_MSG); if (ret) @@ -1939,9 +1966,14 @@ static void vconn_swap(struct usbpd *pd) pd->vconn_enabled = true; + /* add for pd+swarp adapter compatibility */ + pd_phy_update_frame_filter(FRAME_FILTER_EN_SOP | + FRAME_FILTER_EN_HARD_RESET); + /* pd_phy_update_frame_filter(FRAME_FILTER_EN_SOP | FRAME_FILTER_EN_SOPI | FRAME_FILTER_EN_HARD_RESET); + */ /* * Small delay to ensure Vconn has ramped up. This is well @@ -2028,8 +2060,10 @@ static inline void rx_msg_cleanup(struct usbpd *pd) /* For PD 3.0, check SinkTxOk before allowing initiating AMS */ static inline bool is_sink_tx_ok(struct usbpd *pd) { - if (pd->spec_rev == USBPD_REV_30) - return pd->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; +/* @bsp, 2019/09/18 usb & PD porting */ +/* Add to fix power role switch issue when connect MAC */ +// if (pd->spec_rev == USBPD_REV_30) +// return pd->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH; return true; } @@ -2109,8 +2143,11 @@ static int usbpd_startup_common(struct usbpd *pd, phy_params->data_role = pd->current_dr; phy_params->power_role = pd->current_pr; + /* add for pd+swarp adapter compatibility. */ + /* if (pd->vconn_enabled) phy_params->frame_filter_val |= FRAME_FILTER_EN_SOPI; + */ ret = pd_phy_open(phy_params); if (ret) { @@ -2319,15 +2356,21 @@ static void enter_state_src_negotiate_capability(struct usbpd *pd) usbpd_err(&pd->dev, "Invalid request: %08x\n", pd->rdo); - if (pd->in_explicit_contract) - usbpd_set_state(pd, PE_SRC_READY); - else - /* - * bypass PE_SRC_Capability_Response and - * PE_SRC_Wait_New_Capabilities in this - * implementation for simplicity. - */ - usbpd_set_state(pd, PE_SRC_SEND_CAPABILITIES); +/* @bsp, 2019/09/18 usb & PD porting */ +/* handle pixel-sink connect failed issue */ + if (pd->oem_bypass) { + usbpd_info(&pd->dev, "oem bypass invalid request!\n"); + } else { + if (pd->in_explicit_contract) + usbpd_set_state(pd, PE_SRC_READY); + else + /* + * bypass PE_SRC_Capability_Response and + * PE_SRC_Wait_New_Capabilities in this + * implementation for simplicity. + */ + usbpd_set_state(pd, PE_SRC_SEND_CAPABILITIES); + } return; } @@ -2481,9 +2524,21 @@ static void handle_state_src_ready(struct usbpd *pd, struct rx_msg *rx_msg) static void enter_state_hard_reset(struct usbpd *pd) { union power_supply_propval val = {0}; + bool disconnect_pd; + int ret; + + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_DISCONNECT_PD, &val); + if (ret) { + usbpd_err(&pd->dev, "Unable to read USB DISCONNECT_PD: %d\n", ret); + disconnect_pd = false; + } else { + disconnect_pd = val.intval; + } /* are we still connected? */ - if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE) { + if (pd->typec_mode == POWER_SUPPLY_TYPEC_NONE || disconnect_pd) { + pd->typec_mode = POWER_SUPPLY_TYPEC_NONE; pd->current_pr = PR_NONE; kick_sm(pd, 0); return; @@ -2781,6 +2836,7 @@ static void handle_state_snk_select_capability(struct usbpd *pd, } pd->selected_pdo = pd->requested_pdo; + usbpd_info(&pd->dev, "Pdo select successfully!!\n"); } else if (IS_CTRL(rx_msg, MSG_REJECT) || IS_CTRL(rx_msg, MSG_WAIT)) { if (pd->in_explicit_contract) @@ -2821,6 +2877,7 @@ static void handle_state_snk_transition_sink(struct usbpd *pd, power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); + usbpd_info(&pd->dev, "Requested current: %d\n", pd->requested_current); usbpd_set_state(pd, PE_SNK_READY); } else { /* timed out; go to hard reset */ @@ -3066,6 +3123,7 @@ static void handle_snk_ready_tx(struct usbpd *pd, struct rx_msg *rx_msg) kick_sm(pd, SENDER_RESPONSE_TIME); } else if (pd->send_request) { pd->send_request = false; + usbpd_info(&pd->dev, "Sink ready state, select cap!!"); usbpd_set_state(pd, PE_SNK_SELECT_CAPABILITY); } else if (pd->send_pr_swap) { pd->send_pr_swap = false; @@ -3678,8 +3736,13 @@ static int usbpd_process_typec_mode(struct usbpd *pd, typec_mode == POWER_SUPPLY_TYPEC_SINK ? "" : " (powered)"); - if (pd->current_pr == PR_SRC) +/* @bsp, 2019/09/18 usb & PD porting */ + usbpd_info(&pd->dev, "primary current_pr = %d\n", + pd->current_pr); + if (pd->current_pr == PR_SRC) { + pr_err("pd->current_pr == PR_SRC PR no change return!\n"); return 0; + } pd->current_pr = PR_SRC; break; @@ -3709,6 +3772,15 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (ptr != pd->usb_psy || evt != PSY_EVENT_PROP_CHANGED) return 0; + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_DISCONNECT_PD, &val); + if (ret) { + usbpd_err(&pd->dev, "Unable to read USB DISCONNECT_PD: %d\n", ret); + return ret; + } + if (val.intval) + return 0; + ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_TYPEC_MODE, &val); if (ret) { @@ -3725,9 +3797,13 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) ret); return ret; } +/* @bsp, 2019/09/18 usb & PD porting */ +/* add to start USB stack for USB3.1 compliance testing */ + if (usb_compliance_mode) + pd->periph_direct = true; /* Don't proceed if PE_START=0; start USB directly if needed */ - if (!val.intval && !pd->pd_connected && + if (pd->periph_direct && !val.intval && !pd->pd_connected && typec_mode >= POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE, &val); @@ -3739,8 +3815,9 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (val.intval == POWER_SUPPLY_TYPE_USB || val.intval == POWER_SUPPLY_TYPE_USB_CDP || - val.intval == POWER_SUPPLY_TYPE_USB_FLOAT) { - usbpd_dbg(&pd->dev, "typec mode:%d type:%d\n", + val.intval == POWER_SUPPLY_TYPE_USB_FLOAT || + usb_compliance_mode) { + usbpd_info(&pd->dev, "typec mode:%d type:%d\n", typec_mode, val.intval); pd->typec_mode = typec_mode; queue_work(pd->wq, &pd->start_periph_work); @@ -3783,8 +3860,18 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) pd->typec_mode = typec_mode; - usbpd_dbg(&pd->dev, "typec mode:%d present:%d orientation:%d\n", - typec_mode, pd->vbus_present, +/* @bsp, 2019/09/18 usb & PD porting */ + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_REAL_TYPE, &val); + if (ret) { + usbpd_err(&pd->dev, "Unable to read USB TYPE: %d\n", ret); + return ret; + } + + pd->psy_type = val.intval; + + usbpd_err(&pd->dev, "typec mode:%d present:%d type:%d orientation:%d\n", + typec_mode, pd->vbus_present, pd->psy_type, usbpd_get_plug_orientation(pd)); ret = usbpd_process_typec_mode(pd, typec_mode); @@ -4186,10 +4273,18 @@ static ssize_t select_pdo_store(struct device *dev, struct usbpd *pd = dev_get_drvdata(dev); int src_cap_id; int pdo, uv = 0, ua = 0; - int ret; + int ret = 0; mutex_lock(&pd->swap_lock); + usbpd_info(&pd->dev, "%s:, Current vol: %d, Request vol: %d\n", + __func__, pd->current_voltage, pd->requested_voltage); + if (pd->current_voltage == 9000000 && + (pd->current_voltage == pd->requested_voltage)) { + usbpd_err(&pd->dev, "Same voltage level, return!\n"); + goto out; + } + /* Only allowed if we are already in explicit sink contract */ if (pd->current_state != PE_SNK_READY) { usbpd_err(&pd->dev, "Cannot select new PDO yet\n"); @@ -4198,6 +4293,8 @@ static ssize_t select_pdo_store(struct device *dev, } ret = sscanf(buf, "%d %d %d %d", &src_cap_id, &pdo, &uv, &ua); + usbpd_info(&pd->dev, "PD: src_cap_id: %d, pdo: %d, uv: %d, ua: %d!\n", + src_cap_id, pdo, uv, ua); if (ret != 2 && ret != 4) { usbpd_err(&pd->dev, "Must specify [ ]\n"); ret = -EINVAL; @@ -4603,6 +4700,98 @@ static void usbpd_release(struct device *dev) static int num_pd_instances; +/* @bsp, 2020/08/04, add to detect SVID */ +int op_usbpd_send_svdm(u16 svid, u8 cmd, enum usbpd_svdm_cmd_type cmd_type, + int obj_pos, const u32 *vdos, int num_vdos) +{ + struct usbpd *pd = pd_p; + u32 svdm_hdr = SVDM_HDR(svid, 0, obj_pos, cmd_type, cmd); + + usbpd_info(&pd->dev, "Send svdm!! svid:%x cmd:%x cmd_type:%x svdm_hdr:%x\n", + svid, cmd, cmd_type, svdm_hdr); + return usbpd_send_vdm(pd, svdm_hdr, vdos, num_vdos); +} +EXPORT_SYMBOL(op_usbpd_send_svdm); + +/* @bsp, 2020/04/26 add to support pd pdo selection */ +int op_pdo_select(int vbus_mv, int ibus_ma) +{ + + int i = 0; + int rc = 0; + u32 pdo = 0; + struct usbpd *pd = pd_p; + + for (i = 0; i < ARRAY_SIZE(pd->received_pdos); i++) { + pdo = pd->received_pdos[i]; + if (vbus_mv == PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 || pdo == 0) + break; + } + + mutex_lock(&pd->swap_lock); + + /* Only allowed if we are already in explicit sink contract */ + if (pd->current_state != PE_SNK_READY || !is_sink_tx_ok(pd)) { + usbpd_err(&pd->dev, "%s: cannot select new pdo yet\n", __func__); + rc = -EBUSY; + goto out; + } + + if (i > 7) { + usbpd_err(&pd->dev, "%s: inval pdo[0x%x]\n", __func__, pdo); + rc = -EINVAL; + goto out; + } + + if (vbus_mv != PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50) { + if (i > 0) { + usbpd_err(&pd->dev, "%s: can not find vbus_mv[%d], the last pdos[%d]=[%d]\n", + __func__, vbus_mv, i - 1, + PD_SRC_PDO_FIXED_VOLTAGE(pd->received_pdos[i - 1]) * 50); + } else { + usbpd_err(&pd->dev, "%s: can not find vbus_mv[%d], pdos0=[%d]\n", + __func__, vbus_mv, + PD_SRC_PDO_FIXED_VOLTAGE(pd->received_pdos[i]) * 50); + } + rc = -EINVAL; + goto out; + } + + rc = pd_select_pdo(pd, i + 1, vbus_mv * 1000, ibus_ma * 1000); + if (rc) { + usbpd_err(&pd->dev, "%s: pd_select_pdo fail, rc=%d\n", __func__, rc); + goto out; + } + + reinit_completion(&pd->is_ready); + pd->send_request = true; + kick_sm(pd, 0); + + /* wait for operation to complete */ + if (!wait_for_completion_timeout(&pd->is_ready, msecs_to_jiffies(1000))) { + usbpd_err(&pd->dev, "%s: pdo[%d], vbus_mv[%d], ibus_ma[%d] request timed out\n", + __func__, i, vbus_mv, ibus_ma); + rc = -ETIMEDOUT; + goto out; + } + + /* determine if request was accepted/rejected */ + if (pd->selected_pdo != pd->requested_pdo || + pd->current_voltage != pd->requested_voltage) { + usbpd_err(&pd->dev, "%s: request rejected\n", __func__); + rc = -EINVAL; + } + +out: + usbpd_info(&pd->dev, "PDO: %d, vbus_mv: %d, ibus_ma: %d, cvol: %d, rvol: %d\n", + i, vbus_mv, ibus_ma, pd->current_voltage, pd->requested_voltage); + pd->send_request = false; + mutex_unlock(&pd->swap_lock); + return rc; +} +EXPORT_SYMBOL(op_pdo_select); + + /** * usbpd_create - Create a new instance of USB PD protocol/policy engine * @parent - parent device to associate with @@ -4623,6 +4812,7 @@ struct usbpd *usbpd_create(struct device *parent) if (!pd) return ERR_PTR(-ENOMEM); + pd_p = pd; device_initialize(&pd->dev); pd->dev.class = &usbpd_class; pd->dev.parent = parent; @@ -4767,6 +4957,10 @@ struct usbpd *usbpd_create(struct device *parent) } } +/* @bsp, 2019/09/18 usb & PD porting */ +/* handle pixel-sink connect failed issue */ + pd->oem_bypass = true; + pd->periph_direct = false; pd->current_pr = PR_NONE; pd->current_dr = DR_NONE; list_add_tail(&pd->instance, &_usbpd); diff --git a/drivers/usb/phy/phy-msm-snps-hs.c b/drivers/usb/phy/phy-msm-snps-hs.c index ffc7350d6850be39a7a895ca37bbdbad356b6cd5..083958fe20e2c1b06e35c9330de735a64b9c97c9 100644 --- a/drivers/usb/phy/phy-msm-snps-hs.c +++ b/drivers/usb/phy/phy-msm-snps-hs.c @@ -83,6 +83,23 @@ #define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */ #define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */ +/* Add to tune USB2.0 eye diagram */ +unsigned int USB2_phy_tune; +module_param(USB2_phy_tune, uint, 0644); +MODULE_PARM_DESC(USB2_phy_tune, "QUSB PHY v2 TUNE"); + +unsigned int USB2_phy_tune1; +module_param(USB2_phy_tune1, uint, 0644); +MODULE_PARM_DESC(USB2_phy_tune1, "QUSB PHY v2 TUNE1"); + +unsigned int USB2_phy_tune2; +module_param(USB2_phy_tune2, uint, 0644); +MODULE_PARM_DESC(USB2_phy_tune2, "QUSB PHY v2 TUNE2"); + +unsigned int USB2_phy_tune3; +module_param(USB2_phy_tune3, uint, 0644); +MODULE_PARM_DESC(USB2_phy_tune3, "QUSB PHY v2 TUNE3"); + struct msm_hsphy { struct usb_phy phy; void __iomem *base; @@ -388,6 +405,26 @@ static int msm_hsphy_init(struct usb_phy *uphy) if (phy->param_override_seq) hsusb_phy_write_seq(phy->base, phy->param_override_seq, phy->param_override_seq_cnt, 0); + /* add to tune USB 2.0 eye diagram */ + if (USB2_phy_tune) { + writel_relaxed(USB2_phy_tune, + phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X0); + } + + if (USB2_phy_tune1) { + writel_relaxed(USB2_phy_tune1, + phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X1); + } + + if (USB2_phy_tune2) { + writel_relaxed(USB2_phy_tune2, + phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X2); + } + + if (USB2_phy_tune3) { + writel_relaxed(USB2_phy_tune3, + phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X3); + } if (phy->pre_emphasis) { u8 val = TXPREEMPAMPTUNE0(phy->pre_emphasis) & @@ -430,7 +467,7 @@ static int msm_hsphy_init(struct usb_phy *uphy) PARAM_OVRD_MASK, phy->param_ovrd3); } - dev_dbg(uphy->dev, "x0:%08x x1:%08x x2:%08x x3:%08x\n", + dev_err(uphy->dev, "x0:%08x x1:%08x x2:%08x x3:%08x\n", readl_relaxed(phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X0), readl_relaxed(phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X1), readl_relaxed(phy->base + USB2PHY_USB_PHY_PARAMETER_OVERRIDE_X2), diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 6fc8d44a3c2368f3d591d94d1b2cea4abe5cecca..fb5d919bb0f0b746cd89742eeb86647c6918c0f9 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1378,7 +1378,9 @@ void typec_set_pwr_opmode(struct typec_port *port, { struct device *partner_dev; - if (port->pwr_opmode == opmode) + if ((port->pwr_opmode == opmode) || + (opmode < TYPEC_PWR_MODE_USB) || + (opmode > TYPEC_PWR_MODE_MAX)) return; port->pwr_opmode = opmode; diff --git a/fs/Kconfig b/fs/Kconfig index b8d003f02b765d48392a232b4afd895d55af9eb7..ae25bc95917619314e3224fceb71d07ff2a7af32 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -138,6 +138,8 @@ menu "DOS/FAT/NT Filesystems" source "fs/fat/Kconfig" source "fs/ntfs/Kconfig" +source "fs/exfat/Kconfig" + endmenu endif # BLOCK diff --git a/fs/Makefile b/fs/Makefile index 9d1caea038f6c496342fa8a946726710cb454a7f..982fc6747d6f80499bfa5afab4e0709c3e047aa1 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -132,3 +132,4 @@ obj-y += exofs/ # Multiple modules obj-$(CONFIG_CEPH_FS) += ceph/ obj-$(CONFIG_PSTORE) += pstore/ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ +obj-$(CONFIG_EXFAT_FS) += exfat/ diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index e7fd0b5b9234e64fb7d2e3b93289be83d7fd3d10..975dd0dbc25274096d131e7bdf2c7b6e03cc5f0c 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1766,7 +1766,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, (!regset->active || regset->active(t->task, regset) > 0)) { int ret; size_t size = regset_size(t->task, regset); - void *data = kmalloc(size, GFP_KERNEL); + void *data = kzalloc(size, GFP_KERNEL); if (unlikely(!data)) return 0; ret = regset->get(t->task, regset, diff --git a/fs/direct-io.c b/fs/direct-io.c index 715e699af7b5efc38ffa19454bc1db8869f2bbda..9c50ba0c11345e373887409f37b83474ec8dfb79 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -37,6 +37,9 @@ #include #include #include +#ifdef CONFIG_CGROUP_IOLIMIT +#include +#endif #include /* @@ -1005,6 +1008,15 @@ static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, unsigned this_chunk_blocks; /* # of blocks */ unsigned u; +#ifdef CONFIG_CGROUP_IOLIMIT + if (iolimit_enable) { + if (dio->op == REQ_OP_WRITE) + io_write_bandwidth_control(PAGE_SIZE); + else + io_read_bandwidth_control(PAGE_SIZE); + } +#endif + if (sdio->blocks_available == 0) { /* * Need to go and map some more disk diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 4760c2b7ea84eb1c15cac6c7849ac844d7ff2478..7802b120262d21805db8f925dbffb72870c28613 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1817,10 +1817,17 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, } spin_unlock_irq(&ep->wq.lock); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + current->in_epoll = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ if (!freezable_schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) timed_out = 1; - +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + current->in_epoll = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ spin_lock_irq(&ep->wq.lock); } @@ -1892,9 +1899,11 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) * not already there, and calling reverse_path_check() * during ep_insert(). */ - if (list_empty(&epi->ffd.file->f_tfile_llink)) + if (list_empty(&epi->ffd.file->f_tfile_llink)) { + get_file(epi->ffd.file); list_add(&epi->ffd.file->f_tfile_llink, &tfile_check_list); + } } } mutex_unlock(&ep->mtx); @@ -1938,6 +1947,7 @@ static void clear_tfile_check_list(void) file = list_first_entry(&tfile_check_list, struct file, f_tfile_llink); list_del_init(&file->f_tfile_llink); + fput(file); } INIT_LIST_HEAD(&tfile_check_list); } @@ -2093,13 +2103,13 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, mutex_lock(&epmutex); if (is_file_epoll(tf.file)) { error = -ELOOP; - if (ep_loop_check(ep, tf.file) != 0) { - clear_tfile_check_list(); + if (ep_loop_check(ep, tf.file) != 0) goto error_tgt_fput; - } - } else + } else { + get_file(tf.file); list_add(&tf.file->f_tfile_llink, &tfile_check_list); + } mutex_lock_nested(&ep->mtx, 0); if (is_file_epoll(tf.file)) { tep = tf.file->private_data; @@ -2123,8 +2133,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, error = ep_insert(ep, &epds, tf.file, fd, full_check); } else error = -EEXIST; - if (full_check) - clear_tfile_check_list(); break; case EPOLL_CTL_DEL: if (epi) @@ -2147,8 +2155,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, mutex_unlock(&ep->mtx); error_tgt_fput: - if (full_check) + if (full_check) { + clear_tfile_check_list(); mutex_unlock(&epmutex); + } fdput(tf); error_fput: diff --git a/fs/exec.c b/fs/exec.c index aa9d20cbd689b50ffe17a068b908eae1e00a422e..b82a8a475337f37c5f37086744350e55105791a5 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -71,6 +71,7 @@ #include "internal.h" #include +#include int suid_dumpable = 0; @@ -1240,6 +1241,7 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) task_lock(tsk); trace_task_rename(tsk, buf); strlcpy(tsk->comm, buf, sizeof(tsk->comm)); + im_wmi(tsk); task_unlock(tsk); perf_event_comm(tsk, exec); } @@ -1699,6 +1701,8 @@ static int exec_binprm(struct linux_binprm *bprm) ptrace_event(PTRACE_EVENT_EXEC, old_vpid); proc_exec_connector(current); } + if (strcmp(current->comm, "surfaceflinger") == 0) + current->compensate_need = 2; return ret; } diff --git a/fs/exfat/Kconfig b/fs/exfat/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..78b32aa2ca19652168d34eadd74211814e5f7582 --- /dev/null +++ b/fs/exfat/Kconfig @@ -0,0 +1,39 @@ +config EXFAT_FS + tristate "exFAT fs support" + select NLS + help + This adds support for the exFAT file system. + +config EXFAT_DISCARD + bool "enable discard support" + depends on EXFAT_FS + default y + +config EXFAT_DELAYED_SYNC + bool "enable delayed sync" + depends on EXFAT_FS + default n + +config EXFAT_KERNEL_DEBUG + bool "enable kernel debug features via ioctl" + depends on EXFAT_FS + default n + +config EXFAT_DEBUG_MSG + bool "print debug messages" + depends on EXFAT_FS + default n + +config EXFAT_DEFAULT_CODEPAGE + int "Default codepage for exFAT" + default 437 + depends on EXFAT_FS + help + This option should be set to the codepage of your exFAT filesystems. + +config EXFAT_DEFAULT_IOCHARSET + string "Default iocharset for exFAT" + default "utf8" + depends on EXFAT_FS + help + Set this to the default input/output character set you'd like exFAT to use. diff --git a/fs/exfat/LICENSE b/fs/exfat/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1 --- /dev/null +++ b/fs/exfat/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/fs/exfat/Makefile b/fs/exfat/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..711ed87f991b4c039e6f7b1c3679f85bdc17966b --- /dev/null +++ b/fs/exfat/Makefile @@ -0,0 +1,54 @@ +# +# Makefile for Linux FAT12/FAT16/FAT32(VFAT)/FAT64(ExFAT) filesystem driver. +# + +ifneq ($(KERNELRELEASE),) +# call from kernel build system + +obj-$(CONFIG_EXFAT_FS) += exfat.o + +exfat-objs := exfat_core.o exfat_super.o exfat_api.o exfat_blkdev.o exfat_cache.o \ + exfat_data.o exfat_bitmap.o exfat_nls.o exfat_oal.o exfat_upcase.o + +else +# external module build + +EXTRA_FLAGS += -I$(PWD) + +# +# KDIR is a path to a directory containing kernel source. +# It can be specified on the command line passed to make to enable the module to +# be built and installed for a kernel other than the one currently running. +# By default it is the path to the symbolic link created when +# the current kernel's modules were installed, but +# any valid path to the directory in which the target kernel's source is located +# can be provided on the command line. +# +KDIR ?= /lib/modules/$(shell uname -r)/build +MDIR ?= /lib/modules/$(shell uname -r) +PWD := $(shell pwd) +PWD := $(shell pwd) + +export CONFIG_EXFAT_FS := m + +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean + +help: + $(MAKE) -C $(KDIR) M=$(PWD) help + +install: exfat.ko + rm -f ${MDIR}/kernel/fs/exfat/exfat.ko + install -m644 -b -D exfat.ko ${MDIR}/kernel/fs/exfat/exfat.ko + depmod -aq + +uninstall: + rm -rf ${MDIR}/kernel/fs/exfat + depmod -aq + +endif + +.PHONY : all clean install uninstall diff --git a/fs/exfat/README.md b/fs/exfat/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b4ac4b073f00681e7dd3114e32e4d4c9307f46f5 --- /dev/null +++ b/fs/exfat/README.md @@ -0,0 +1,99 @@ +exfat-nofuse +============ + +Linux non-fuse read/write kernel driver for the exFAT, FAT12, FAT16 and vfat (FAT32) file systems.
+Originally ported from Android kernel v3.0. + +Kudos to ksv1986 for the mutex patch!
+Thanks to JackNorris for being awesome and providing the clear_inode() patch.
+
+Big thanks to lqs for completing the driver!
+Big thanks to benpicco for fixing 3.11.y compatibility!
+Fixing the >= 5.0 compatibility.
+Added Debian DKMS support packaging. + +Special thanks to github user AndreiLux for spreading the word about the leak!
+ + +Installing as a stand-alone module: +==================================== + + make + sudo make install + +To load the driver manually, run this as root: + + modprobe exfat + +You may also specify custom toolchains by using CROSS_COMPILE flag, in my case: +>CROSS_COMPILE=../dorimanx-SG2-I9100-Kernel/android-toolchain/bin/arm-eabi- + +Installing as a part of the kernel: +====================================== + +Let's take [linux] as the path to your kernel source dir... + + cd [linux] + cp -rvf exfat-nofuse [linux]/fs/exfat + +edit [linux]/fs/Kconfig +``` + menu "DOS/FAT/NT Filesystems" + + source "fs/fat/Kconfig" + +source "fs/exfat/Kconfig" + source "fs/ntfs/Kconfig" + endmenu +``` + + +edit [linux]/fs/Makefile +``` + obj-$(CONFIG_FAT_FS) += fat/ + +obj-$(CONFIG_EXFAT_FS) += exfat/ + obj-$(CONFIG_BFS_FS) += bfs/ +``` + + cd [linux] + make menuconfig + +Go to: +> File systems > DOS/FAT/NT +> check exfat as MODULE (M) +> (437) Default codepage for exFAT +> (utf8) Default iocharset for exFAT + +> ESC to main menu +> Save an Alternate Configuration File +> ESC ESC + +build your kernel + +Have fun. + + +Installing as a DKMS module: +================================= + +You can have even more fun with exfat-nofuse by installing it as a DKMS module has the main advantage of being auto-compiled (and thus, possibly surviving) between kernel upgrades. + +First, get dkms. On Ubuntu this should be: + + sudo apt install dkms + +Then copy the root of this repository to /usr/share: + + sudo cp -R . /usr/src/exfat-1.2.11 (or whatever version number declared on dkms.conf is) + sudo dkms add -m exfat -v 1.2.11 + +Build and load the module: + + sudo dkms build -m exfat -v 1.2.11 + sudo dkms install -m exfat -v 1.2.11 + +Now you have a proper dkms module that will work for a long time... hopefully. + + + +Free Software for the Free Minds! +================================= diff --git a/fs/exfat/dkms.conf b/fs/exfat/dkms.conf new file mode 100644 index 0000000000000000000000000000000000000000..77a47cdcaf8120596762448db0dadf28f3b65ce4 --- /dev/null +++ b/fs/exfat/dkms.conf @@ -0,0 +1,7 @@ +PACKAGE_NAME="exfat" +PACKAGE_VERSION="1.2.11" +MAKE="KDIR=/lib/modules/$kernelver/build MDIR=/lib/modules/$kernelver make" +CLEAN="make clean" +BUILT_MODULE_NAME[0]="exfat" +AUTOINSTALL="yes" +DEST_MODULE_LOCATION="/extra" diff --git a/fs/exfat/exfat-km.mk b/fs/exfat/exfat-km.mk new file mode 100644 index 0000000000000000000000000000000000000000..4e3ef07b36ece539fd14f6afbd0089bd1b495b51 --- /dev/null +++ b/fs/exfat/exfat-km.mk @@ -0,0 +1,11 @@ +EXFAT_FOLDER ?= external/exfat-nofuse + +EXFAT_MODULE: + make clean -C $(EXFAT_FOLDER) KDIR=$(KERNEL_OUT) + make -j8 -C $(EXFAT_FOLDER) ARCH=arm KDIR=$(KERNEL_OUT) \ + $(if $(ARM_CROSS_COMPILE),$(ARM_CROSS_COMPILE),$(KERNEL_CROSS_COMPILE)) + mv $(EXFAT_FOLDER)/exfat.ko $(KERNEL_MODULES_OUT) + $(if $(ARM_EABI_TOOLCHAIN),$(ARM_EABI_TOOLCHAIN)/arm-eabi-strip, \ + $(KERNEL_TOOLCHAIN_PATH)strip) --strip-unneeded $(KERNEL_MODULES_OUT)/exfat.ko + +TARGET_KERNEL_MODULES += EXFAT_MODULE diff --git a/fs/exfat/exfat_api.c b/fs/exfat/exfat_api.c new file mode 100644 index 0000000000000000000000000000000000000000..32b29f0dd8d949b6f16a8d8cf0d6fff5f7e9475d --- /dev/null +++ b/fs/exfat/exfat_api.c @@ -0,0 +1,528 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_api.c */ +/* PURPOSE : exFAT API Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include + +#include "exfat_version.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +extern struct semaphore z_sem; + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Function Declarations */ +/*----------------------------------------------------------------------*/ + +/*======================================================================*/ +/* Global Function Definitions */ +/* - All functions for global use have same return value format, */ +/* that is, FFS_SUCCESS on success and several FS error code on */ +/* various error condition. */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* exFAT Filesystem Init & Exit Functions */ +/*----------------------------------------------------------------------*/ + +int FsInit(void) +{ + return ffsInit(); +} + +int FsShutdown(void) +{ + return ffsShutdown(); +} + +/*----------------------------------------------------------------------*/ +/* Volume Management Functions */ +/*----------------------------------------------------------------------*/ + +/* FsMountVol : mount the file system volume */ +int FsMountVol(struct super_block *sb) +{ + int err; + + sm_P(&z_sem); + + err = buf_init(sb); + if (!err) + err = ffsMountVol(sb); + else + buf_shutdown(sb); + + sm_V(&z_sem); + + return err; +} /* end of FsMountVol */ + +/* FsUmountVol : unmount the file system volume */ +int FsUmountVol(struct super_block *sb) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&z_sem); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsUmountVol(sb); + buf_shutdown(sb); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + sm_V(&z_sem); + + return err; +} /* end of FsUmountVol */ + +/* FsGetVolInfo : get the information of a file system volume */ +int FsGetVolInfo(struct super_block *sb, VOL_INFO_T *info) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (info == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsGetVolInfo(sb, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsGetVolInfo */ + +/* FsSyncVol : synchronize a file system volume */ +int FsSyncVol(struct super_block *sb, int do_sync) +{ + int err; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsSyncVol(sb, do_sync); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsSyncVol */ + + +/*----------------------------------------------------------------------*/ +/* File Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* FsCreateFile : create a file */ +int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsLookupFile(inode, path, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsLookupFile */ + +/* FsCreateFile : create a file */ +int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsCreateFile(inode, path, mode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsCreateFile */ + +int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* check the validity of pointer parameters */ + if (buffer == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsReadFile(inode, fid, buffer, count, rcount); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadFile */ + +int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* check the validity of pointer parameters */ + if (buffer == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsWriteFile(inode, fid, buffer, count, wcount); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsWriteFile */ + +/* FsTruncateFile : resize the file length */ +int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + DPRINTK("FsTruncateFile entered (inode %p size %llu)\n", inode, new_size); + + err = ffsTruncateFile(inode, old_size, new_size); + + DPRINTK("FsTruncateFile exitted (%d)\n", err); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsTruncateFile */ + +/* FsMoveFile : move(rename) a old file into a new file */ +int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +{ + int err; + struct super_block *sb = old_parent_inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsMoveFile(old_parent_inode, fid, new_parent_inode, new_dentry); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsMoveFile */ + +/* FsRemoveFile : remove a file */ +int FsRemoveFile(struct inode *inode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsRemoveFile(inode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsRemoveFile */ + +/* FsSetAttr : set the attribute of a given file */ +int FsSetAttr(struct inode *inode, u32 attr) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsSetAttr(inode, attr); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsSetAttr */ + +/* FsReadStat : get the information of a given file */ +int FsReadStat(struct inode *inode, DIR_ENTRY_T *info) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsGetStat(inode, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadStat */ + +/* FsWriteStat : set the information of a given file */ +int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + DPRINTK("FsWriteStat entered (inode %p info %p\n", inode, info); + + err = ffsSetStat(inode, info); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + DPRINTK("FsWriteStat exited (%d)\n", err); + + return err; +} /* end of FsWriteStat */ + +/* FsMapCluster : return the cluster number in the given cluster offset */ +int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (clu == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsMapCluster(inode, clu_offset, clu); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsMapCluster */ + +/*----------------------------------------------------------------------*/ +/* Directory Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* FsCreateDir : create(make) a directory */ +int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if ((fid == NULL) || (path == NULL) || (*path == '\0')) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsCreateDir(inode, path, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsCreateDir */ + +/* FsReadDir : read a directory entry from the opened directory */ +int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of pointer parameters */ + if (dir_entry == NULL) + return FFS_ERROR; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsReadDir(inode, dir_entry); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsReadDir */ + +/* FsRemoveDir : remove a directory */ +int FsRemoveDir(struct inode *inode, FILE_ID_T *fid) +{ + int err; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of the given file id */ + if (fid == NULL) + return FFS_INVALIDFID; + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + err = ffsRemoveDir(inode, fid); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return err; +} /* end of FsRemoveDir */ + +EXPORT_SYMBOL(FsMountVol); +EXPORT_SYMBOL(FsUmountVol); +EXPORT_SYMBOL(FsGetVolInfo); +EXPORT_SYMBOL(FsSyncVol); +EXPORT_SYMBOL(FsLookupFile); +EXPORT_SYMBOL(FsCreateFile); +EXPORT_SYMBOL(FsReadFile); +EXPORT_SYMBOL(FsWriteFile); +EXPORT_SYMBOL(FsTruncateFile); +EXPORT_SYMBOL(FsMoveFile); +EXPORT_SYMBOL(FsRemoveFile); +EXPORT_SYMBOL(FsSetAttr); +EXPORT_SYMBOL(FsReadStat); +EXPORT_SYMBOL(FsWriteStat); +EXPORT_SYMBOL(FsMapCluster); +EXPORT_SYMBOL(FsCreateDir); +EXPORT_SYMBOL(FsReadDir); +EXPORT_SYMBOL(FsRemoveDir); + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG +/* FsReleaseCache: Release FAT & buf cache */ +int FsReleaseCache(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* acquire the lock for file system critical section */ + sm_P(&p_fs->v_sem); + + FAT_release_all(sb); + buf_release_all(sb); + + /* release the lock for file system critical section */ + sm_V(&p_fs->v_sem); + + return 0; +} +/* FsReleaseCache */ + +EXPORT_SYMBOL(FsReleaseCache); +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ diff --git a/fs/exfat/exfat_api.h b/fs/exfat/exfat_api.h new file mode 100644 index 0000000000000000000000000000000000000000..84bdf612a1e66cdaa5c05cc7ed8caccd31e60147 --- /dev/null +++ b/fs/exfat/exfat_api.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_api.h */ +/* PURPOSE : Header File for exFAT API Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_API_H +#define _EXFAT_API_H + +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define EXFAT_SUPER_MAGIC (0x2011BAB0L) +#define EXFAT_ROOT_INO 1 + +/* FAT types */ +#define FAT12 0x01 /* FAT12 */ +#define FAT16 0x0E /* Win95 FAT16 (LBA) */ +#define FAT32 0x0C /* Win95 FAT32 (LBA) */ +#define EXFAT 0x07 /* exFAT */ + +/* file name lengths */ +#define MAX_CHARSET_SIZE 3 /* max size of multi-byte character */ +#define MAX_PATH_DEPTH 15 /* max depth of path name */ +#define MAX_NAME_LENGTH 256 /* max len of file name including NULL */ +#define MAX_PATH_LENGTH 260 /* max len of path name including NULL */ +#define DOS_NAME_LENGTH 11 /* DOS file name length excluding NULL */ +#define DOS_PATH_LENGTH 80 /* DOS path name length excluding NULL */ + +/* file attributes */ +#define ATTR_NORMAL 0x0000 +#define ATTR_READONLY 0x0001 +#define ATTR_HIDDEN 0x0002 +#define ATTR_SYSTEM 0x0004 +#define ATTR_VOLUME 0x0008 +#define ATTR_SUBDIR 0x0010 +#define ATTR_ARCHIVE 0x0020 +#define ATTR_SYMLINK 0x0040 +#define ATTR_EXTEND 0x000F +#define ATTR_RWMASK 0x007E + +/* file creation modes */ +#define FM_REGULAR 0x00 +#define FM_SYMLINK 0x40 + +/* return values */ +#define FFS_SUCCESS 0 +#define FFS_MEDIAERR 1 +#define FFS_FORMATERR 2 +#define FFS_MOUNTED 3 +#define FFS_NOTMOUNTED 4 +#define FFS_ALIGNMENTERR 5 +#define FFS_SEMAPHOREERR 6 +#define FFS_INVALIDPATH 7 +#define FFS_INVALIDFID 8 +#define FFS_NOTFOUND 9 +#define FFS_FILEEXIST 10 +#define FFS_PERMISSIONERR 11 +#define FFS_NOTOPENED 12 +#define FFS_MAXOPENED 13 +#define FFS_FULL 14 +#define FFS_EOF 15 +#define FFS_DIRBUSY 16 +#define FFS_MEMORYERR 17 +#define FFS_NAMETOOLONG 18 +#define FFS_ERROR 19 + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct { + u16 Year; + u16 Month; + u16 Day; + u16 Hour; + u16 Minute; + u16 Second; + u16 MilliSecond; +} DATE_TIME_T; + +typedef struct { + u32 Offset; /* start sector number of the partition */ + u32 Size; /* in sectors */ +} PART_INFO_T; + +typedef struct { + u32 SecSize; /* sector size in bytes */ + u32 DevSize; /* block device size in sectors */ +} DEV_INFO_T; + +typedef struct { + u32 FatType; + u32 ClusterSize; + u32 NumClusters; + u32 FreeClusters; + u32 UsedClusters; +} VOL_INFO_T; + +/* directory structure */ +typedef struct { + u32 dir; + s32 size; + u8 flags; +} CHAIN_T; + +/* file id structure */ +typedef struct { + CHAIN_T dir; + s32 entry; + u32 type; + u32 attr; + u32 start_clu; + u64 size; + u8 flags; + s64 rwoffset; + s32 hint_last_off; + u32 hint_last_clu; +} FILE_ID_T; + +typedef struct { + char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE]; + char ShortName[DOS_NAME_LENGTH + 2]; /* used only for FAT12/16/32, not used for exFAT */ + u32 Attr; + u64 Size; + u32 NumSubdirs; + DATE_TIME_T CreateTimestamp; + DATE_TIME_T ModifyTimestamp; + DATE_TIME_T AccessTimestamp; +} DIR_ENTRY_T; + +/*======================================================================*/ +/* */ +/* API FUNCTION DECLARATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* file system initialization & shutdown functions */ + int FsInit(void); + int FsShutdown(void); + +/* volume management functions */ + int FsMountVol(struct super_block *sb); + int FsUmountVol(struct super_block *sb); + int FsGetVolInfo(struct super_block *sb, VOL_INFO_T *info); + int FsSyncVol(struct super_block *sb, int do_sync); + +/* file management functions */ + int FsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); + int FsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); + int FsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); + int FsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); + int FsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); + int FsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); + int FsRemoveFile(struct inode *inode, FILE_ID_T *fid); + int FsSetAttr(struct inode *inode, u32 attr); + int FsReadStat(struct inode *inode, DIR_ENTRY_T *info); + int FsWriteStat(struct inode *inode, DIR_ENTRY_T *info); + int FsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); + +/* directory management functions */ + int FsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); + int FsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry); + int FsRemoveDir(struct inode *inode, FILE_ID_T *fid); + +/* debug functions */ +s32 FsReleaseCache(struct super_block *sb); + +#endif /* _EXFAT_API_H */ diff --git a/fs/exfat/exfat_bitmap.c b/fs/exfat/exfat_bitmap.c new file mode 100644 index 0000000000000000000000000000000000000000..b0672dd073fcfddbc4be448145aec74b39959982 --- /dev/null +++ b/fs/exfat/exfat_bitmap.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_global.c */ +/* PURPOSE : exFAT Miscellaneous Functions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_bitmap.h" + +/*----------------------------------------------------------------------*/ +/* Bitmap Manipulation Functions */ +/*----------------------------------------------------------------------*/ + +#define BITMAP_LOC(v) ((v) >> 3) +#define BITMAP_SHIFT(v) ((v) & 0x07) + +s32 exfat_bitmap_test(u8 *bitmap, int i) +{ + u8 data; + + data = bitmap[BITMAP_LOC(i)]; + if ((data >> BITMAP_SHIFT(i)) & 0x01) + return 1; + return 0; +} /* end of Bitmap_test */ + +void exfat_bitmap_set(u8 *bitmap, int i) +{ + bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i)); +} /* end of Bitmap_set */ + +void exfat_bitmap_clear(u8 *bitmap, int i) +{ + bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i)); +} /* end of Bitmap_clear */ diff --git a/fs/exfat/exfat_bitmap.h b/fs/exfat/exfat_bitmap.h new file mode 100644 index 0000000000000000000000000000000000000000..4f482c7b28ccc6ab1f1a97fffc931faf2cd22fea --- /dev/null +++ b/fs/exfat/exfat_bitmap.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_global.h */ +/* PURPOSE : Header File for exFAT Global Definitions & Misc Functions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_BITMAP_H +#define _EXFAT_BITMAP_H + +#include + +/*======================================================================*/ +/* */ +/* LIBRARY FUNCTION DECLARATIONS -- OTHER UTILITY FUNCTIONS */ +/* (DO NOT CHANGE THIS PART !!) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* Bitmap Manipulation Functions */ +/*----------------------------------------------------------------------*/ + +s32 exfat_bitmap_test(u8 *bitmap, int i); +void exfat_bitmap_set(u8 *bitmap, int i); +void exfat_bitmap_clear(u8 *bitmpa, int i); + +#endif /* _EXFAT_BITMAP_H */ diff --git a/fs/exfat/exfat_blkdev.c b/fs/exfat/exfat_blkdev.c new file mode 100644 index 0000000000000000000000000000000000000000..eaccfd84e9f9bf12ec2adaa8251d9915563c3986 --- /dev/null +++ b/fs/exfat/exfat_blkdev.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_blkdev.c */ +/* PURPOSE : exFAT Block Device Driver Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include "exfat_config.h" +#include "exfat_blkdev.h" +#include "exfat_data.h" +#include "exfat_api.h" +#include "exfat_super.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*======================================================================*/ +/* Function Definitions */ +/*======================================================================*/ + +s32 bdev_init(void) +{ + return FFS_SUCCESS; +} + +s32 bdev_shutdown(void) +{ + return FFS_SUCCESS; +} + +s32 bdev_open(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bd->opened) + return FFS_SUCCESS; + + p_bd->sector_size = bdev_logical_block_size(sb->s_bdev); + p_bd->sector_size_bits = ilog2(p_bd->sector_size); + p_bd->sector_size_mask = p_bd->sector_size - 1; + p_bd->num_sectors = i_size_read(sb->s_bdev->bd_inode) >> p_bd->sector_size_bits; + + p_bd->opened = TRUE; + + return FFS_SUCCESS; +} + +s32 bdev_close(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (!p_bd->opened) + return FFS_SUCCESS; + + p_bd->opened = FALSE; + return FFS_SUCCESS; +} + +s32 bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, u32 num_secs, s32 read) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + if (*bh) + __brelse(*bh); + + if (read) + *bh = __bread(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); + else + *bh = __getblk(sb->s_bdev, secno, num_secs << p_bd->sector_size_bits); + + if (*bh) + return FFS_SUCCESS; + + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return FFS_MEDIAERR; +} + +s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u32 num_secs, s32 sync) +{ + s32 count; + struct buffer_head *bh2; + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + if (secno == bh->b_blocknr) { + lock_buffer(bh); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + if (sync && (sync_dirty_buffer(bh) != 0)) + return FFS_MEDIAERR; + } else { + count = num_secs << p_bd->sector_size_bits; + + bh2 = __getblk(sb->s_bdev, secno, count); + + if (bh2 == NULL) + goto no_bh; + + lock_buffer(bh2); + memcpy(bh2->b_data, bh->b_data, count); + set_buffer_uptodate(bh2); + mark_buffer_dirty(bh2); + unlock_buffer(bh2); + if (sync && (sync_dirty_buffer(bh2) != 0)) { + __brelse(bh2); + goto no_bh; + } + __brelse(bh2); + } + + return FFS_SUCCESS; + +no_bh: + WARN(!p_fs->dev_ejected, + "[EXFAT] No bh, device seems wrong or to be ejected.\n"); + + return FFS_MEDIAERR; +} + +s32 bdev_sync(struct super_block *sb) +{ + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + struct exfat_sb_info *sbi = EXFAT_SB(sb); + long flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_ERROR_RW) + return FFS_MEDIAERR; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + if (!p_bd->opened) + return FFS_MEDIAERR; + + return sync_blockdev(sb->s_bdev); +} diff --git a/fs/exfat/exfat_blkdev.h b/fs/exfat/exfat_blkdev.h new file mode 100644 index 0000000000000000000000000000000000000000..3363b591caebca468554b32b9cdd0b91e492dcca --- /dev/null +++ b/fs/exfat/exfat_blkdev.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_blkdev.h */ +/* PURPOSE : Header File for exFAT Block Device Driver Glue Layer */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_BLKDEV_H +#define _EXFAT_BLKDEV_H + +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Non-Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct __BD_INFO_T { + s32 sector_size; /* in bytes */ + s32 sector_size_bits; + s32 sector_size_mask; + s32 num_sectors; /* total number of sectors in this block device */ + bool opened; /* opened or not */ +} BD_INFO_T; + +/*----------------------------------------------------------------------*/ +/* External Variable Declarations */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 bdev_init(void); +s32 bdev_shutdown(void); +s32 bdev_open(struct super_block *sb); +s32 bdev_close(struct super_block *sb); +s32 bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh, u32 num_secs, s32 read); +s32 bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh, u32 num_secs, s32 sync); +s32 bdev_sync(struct super_block *sb); + +#endif /* _EXFAT_BLKDEV_H */ diff --git a/fs/exfat/exfat_cache.c b/fs/exfat/exfat_cache.c new file mode 100644 index 0000000000000000000000000000000000000000..4130102e373929de339c563ca95652a1db2ab73c --- /dev/null +++ b/fs/exfat/exfat_cache.c @@ -0,0 +1,784 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_cache.c */ +/* PURPOSE : exFAT Cache Manager */ +/* (FAT Cache & Buffer Cache) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Sung-Kwan Kim] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" + +#include "exfat_cache.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +#define sm_P(s) +#define sm_V(s) + +static s32 __FAT_read(struct super_block *sb, u32 loc, u32 *content); +static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content); + +static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, sector_t sec); +static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, sector_t sec); +static void FAT_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp); +static void FAT_cache_remove_hash(BUF_CACHE_T *bp); + +static u8 *__buf_getblk(struct super_block *sb, sector_t sec); + +static BUF_CACHE_T *buf_cache_find(struct super_block *sb, sector_t sec); +static BUF_CACHE_T *buf_cache_get(struct super_block *sb, sector_t sec); +static void buf_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp); +static void buf_cache_remove_hash(BUF_CACHE_T *bp); + +static void push_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void push_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void move_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list); +static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list); + +/*======================================================================*/ +/* Cache Initialization Functions */ +/*======================================================================*/ + +s32 buf_init(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + int i; + + /* LRU list */ + p_fs->FAT_cache_lru_list.next = p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list; + + for (i = 0; i < FAT_CACHE_SIZE; i++) { + p_fs->FAT_cache_array[i].drv = -1; + p_fs->FAT_cache_array[i].sec = ~0; + p_fs->FAT_cache_array[i].flag = 0; + p_fs->FAT_cache_array[i].buf_bh = NULL; + p_fs->FAT_cache_array[i].prev = p_fs->FAT_cache_array[i].next = NULL; + push_to_mru(&(p_fs->FAT_cache_array[i]), &p_fs->FAT_cache_lru_list); + } + + p_fs->buf_cache_lru_list.next = p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list; + + for (i = 0; i < BUF_CACHE_SIZE; i++) { + p_fs->buf_cache_array[i].drv = -1; + p_fs->buf_cache_array[i].sec = ~0; + p_fs->buf_cache_array[i].flag = 0; + p_fs->buf_cache_array[i].buf_bh = NULL; + p_fs->buf_cache_array[i].prev = p_fs->buf_cache_array[i].next = NULL; + push_to_mru(&(p_fs->buf_cache_array[i]), &p_fs->buf_cache_lru_list); + } + + /* HASH list */ + for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) { + p_fs->FAT_cache_hash_list[i].drv = -1; + p_fs->FAT_cache_hash_list[i].sec = ~0; + p_fs->FAT_cache_hash_list[i].hash_next = p_fs->FAT_cache_hash_list[i].hash_prev = &(p_fs->FAT_cache_hash_list[i]); + } + + for (i = 0; i < FAT_CACHE_SIZE; i++) + FAT_cache_insert_hash(sb, &(p_fs->FAT_cache_array[i])); + + for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) { + p_fs->buf_cache_hash_list[i].drv = -1; + p_fs->buf_cache_hash_list[i].sec = ~0; + p_fs->buf_cache_hash_list[i].hash_next = p_fs->buf_cache_hash_list[i].hash_prev = &(p_fs->buf_cache_hash_list[i]); + } + + for (i = 0; i < BUF_CACHE_SIZE; i++) + buf_cache_insert_hash(sb, &(p_fs->buf_cache_array[i])); + + return FFS_SUCCESS; +} /* end of buf_init */ + +s32 buf_shutdown(struct super_block *sb) +{ + return FFS_SUCCESS; +} /* end of buf_shutdown */ + +/*======================================================================*/ +/* FAT Read/Write Functions */ +/*======================================================================*/ + +/* in : sb, loc + * out: content + * returns 0 on success + * -1 on error + */ +s32 FAT_read(struct super_block *sb, u32 loc, u32 *content) +{ + s32 ret; + + sm_P(&f_sem); + + ret = __FAT_read(sb, loc, content); + + sm_V(&f_sem); + + return ret; +} /* end of FAT_read */ + +s32 FAT_write(struct super_block *sb, u32 loc, u32 content) +{ + s32 ret; + + sm_P(&f_sem); + + ret = __FAT_write(sb, loc, content); + + sm_V(&f_sem); + + return ret; +} /* end of FAT_write */ + +static s32 __FAT_read(struct super_block *sb, u32 loc, u32 *content) +{ + s32 off; + u32 _content; + sector_t sec; + u8 *fat_sector, *fat_entry; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_fs->vol_type == FAT12) { + sec = p_fs->FAT1_start_sector + ((loc + (loc >> 1)) >> p_bd->sector_size_bits); + off = (loc + (loc >> 1)) & p_bd->sector_size_mask; + + if (off == (p_bd->sector_size-1)) { + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + _content = (u32) fat_sector[off]; + + fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + + _content |= (u32) fat_sector[0] << 8; + } else { + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + _content = GET16(fat_entry); + } + + if (loc & 1) + _content >>= 4; + + _content &= 0x00000FFF; + + if (_content >= CLUSTER_16(0x0FF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else if (p_fs->vol_type == FAT16) { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-1)); + off = (loc << 1) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + _content = GET16_A(fat_entry); + + _content &= 0x0000FFFF; + + if (_content >= CLUSTER_16(0xFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else if (p_fs->vol_type == FAT32) { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + _content = GET32_A(fat_entry); + + _content &= 0x0FFFFFFF; + + if (_content >= CLUSTER_32(0x0FFFFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } else { + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + _content = GET32_A(fat_entry); + + if (_content >= CLUSTER_32(0xFFFFFFF8)) { + *content = CLUSTER_32(~0); + return 0; + } else { + *content = CLUSTER_32(_content); + return 0; + } + } + + *content = CLUSTER_32(~0); + return 0; +} /* end of __FAT_read */ + +static s32 __FAT_write(struct super_block *sb, u32 loc, u32 content) +{ + s32 off; + sector_t sec; + u8 *fat_sector, *fat_entry; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_fs->vol_type == FAT12) { + + content &= 0x00000FFF; + + sec = p_fs->FAT1_start_sector + ((loc + (loc >> 1)) >> p_bd->sector_size_bits); + off = (loc + (loc >> 1)) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + if (loc & 1) { /* odd */ + + content <<= 4; + + if (off == (p_bd->sector_size-1)) { + fat_sector[off] = (u8)(content | (fat_sector[off] & 0x0F)); + FAT_modify(sb, sec); + + fat_sector = FAT_getblk(sb, ++sec); + if (!fat_sector) + return -1; + + fat_sector[0] = (u8)(content >> 8); + } else { + fat_entry = &(fat_sector[off]); + content |= GET16(fat_entry) & 0x000F; + + SET16(fat_entry, content); + } + } else { /* even */ + fat_sector[off] = (u8)(content); + + if (off == (p_bd->sector_size-1)) { + fat_sector[off] = (u8)(content); + FAT_modify(sb, sec); + + fat_sector = FAT_getblk(sb, ++sec); + fat_sector[0] = (u8)((fat_sector[0] & 0xF0) | (content >> 8)); + } else { + fat_entry = &(fat_sector[off]); + content |= GET16(fat_entry) & 0xF000; + + SET16(fat_entry, content); + } + } + } + + else if (p_fs->vol_type == FAT16) { + + content &= 0x0000FFFF; + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-1)); + off = (loc << 1) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + SET16_A(fat_entry, content); + } + + else if (p_fs->vol_type == FAT32) { + + content &= 0x0FFFFFFF; + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + content |= GET32_A(fat_entry) & 0xF0000000; + + SET32_A(fat_entry, content); + } + + else { /* p_fs->vol_type == EXFAT */ + + sec = p_fs->FAT1_start_sector + (loc >> (p_bd->sector_size_bits-2)); + off = (loc << 2) & p_bd->sector_size_mask; + + fat_sector = FAT_getblk(sb, sec); + if (!fat_sector) + return -1; + + fat_entry = &(fat_sector[off]); + + SET32_A(fat_entry, content); + } + + FAT_modify(sb, sec); + return 0; +} /* end of __FAT_write */ + +u8 *FAT_getblk(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = FAT_cache_find(sb, sec); + if (bp != NULL) { + move_to_mru(bp, &p_fs->FAT_cache_lru_list); + return bp->buf_bh->b_data; + } + + bp = FAT_cache_get(sb, sec); + + FAT_cache_remove_hash(bp); + + bp->drv = p_fs->drv; + bp->sec = sec; + bp->flag = 0; + + FAT_cache_insert_hash(sb, bp); + + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + FAT_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->FAT_cache_lru_list); + return NULL; + } + + return bp->buf_bh->b_data; +} /* end of FAT_getblk */ + +void FAT_modify(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + bp = FAT_cache_find(sb, sec); + if (bp != NULL) + sector_write(sb, sec, bp->buf_bh, 0); +} /* end of FAT_modify */ + +void FAT_release_all(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&f_sem); + + bp = p_fs->FAT_cache_lru_list.next; + while (bp != &p_fs->FAT_cache_lru_list) { + if (bp->drv == p_fs->drv) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + } + bp = bp->next; + } + + sm_V(&f_sem); +} /* end of FAT_release_all */ + +void FAT_sync(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&f_sem); + + bp = p_fs->FAT_cache_lru_list.next; + while (bp != &p_fs->FAT_cache_lru_list) { + if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { + sync_dirty_buffer(bp->buf_bh); + bp->flag &= ~(DIRTYBIT); + } + bp = bp->next; + } + + sm_V(&f_sem); +} /* end of FAT_sync */ + +static BUF_CACHE_T *FAT_cache_find(struct super_block *sb, sector_t sec) +{ + s32 off; + BUF_CACHE_T *bp, *hp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1); + + hp = &(p_fs->FAT_cache_hash_list[off]); + for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { + if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + + WARN(!bp->buf_bh, "[EXFAT] FAT_cache has no bh. " + "It will make system panic.\n"); + + touch_buffer(bp->buf_bh); + return bp; + } + } + return NULL; +} /* end of FAT_cache_find */ + +static BUF_CACHE_T *FAT_cache_get(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = p_fs->FAT_cache_lru_list.prev; + + + move_to_mru(bp, &p_fs->FAT_cache_lru_list); + return bp; +} /* end of FAT_cache_get */ + +static void FAT_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp) +{ + s32 off; + BUF_CACHE_T *hp; + FS_INFO_T *p_fs; + + p_fs = &(EXFAT_SB(sb)->fs_info); + off = (bp->sec + (bp->sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE-1); + + hp = &(p_fs->FAT_cache_hash_list[off]); + bp->hash_next = hp->hash_next; + bp->hash_prev = hp; + hp->hash_next->hash_prev = bp; + hp->hash_next = bp; +} /* end of FAT_cache_insert_hash */ + +static void FAT_cache_remove_hash(BUF_CACHE_T *bp) +{ + (bp->hash_prev)->hash_next = bp->hash_next; + (bp->hash_next)->hash_prev = bp->hash_prev; +} /* end of FAT_cache_remove_hash */ + +/*======================================================================*/ +/* Buffer Read/Write Functions */ +/*======================================================================*/ + +u8 *buf_getblk(struct super_block *sb, sector_t sec) +{ + u8 *buf; + + sm_P(&b_sem); + + buf = __buf_getblk(sb, sec); + + sm_V(&b_sem); + + return buf; +} /* end of buf_getblk */ + +static u8 *__buf_getblk(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = buf_cache_find(sb, sec); + if (bp != NULL) { + move_to_mru(bp, &p_fs->buf_cache_lru_list); + return bp->buf_bh->b_data; + } + + bp = buf_cache_get(sb, sec); + + buf_cache_remove_hash(bp); + + bp->drv = p_fs->drv; + bp->sec = sec; + bp->flag = 0; + + buf_cache_insert_hash(sb, bp); + + if (sector_read(sb, sec, &(bp->buf_bh), 1) != FFS_SUCCESS) { + buf_cache_remove_hash(bp); + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + bp->buf_bh = NULL; + + move_to_lru(bp, &p_fs->buf_cache_lru_list); + return NULL; + } + + return bp->buf_bh->b_data; + +} /* end of __buf_getblk */ + +void buf_modify(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + sector_write(sb, sec, bp->buf_bh, 0); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", + (unsigned long long)sec); + + sm_V(&b_sem); +} /* end of buf_modify */ + +void buf_lock(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + bp->flag |= LOCKBIT; + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", + (unsigned long long)sec); + + sm_V(&b_sem); +} /* end of buf_lock */ + +void buf_unlock(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) + bp->flag &= ~(LOCKBIT); + + WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", + (unsigned long long)sec); + + sm_V(&b_sem); +} /* end of buf_unlock */ + +void buf_release(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = buf_cache_find(sb, sec); + if (likely(bp != NULL)) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + + move_to_lru(bp, &p_fs->buf_cache_lru_list); + } + + sm_V(&b_sem); +} /* end of buf_release */ + +void buf_release_all(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = p_fs->buf_cache_lru_list.next; + while (bp != &p_fs->buf_cache_lru_list) { + if (bp->drv == p_fs->drv) { + bp->drv = -1; + bp->sec = ~0; + bp->flag = 0; + + if (bp->buf_bh) { + __brelse(bp->buf_bh); + bp->buf_bh = NULL; + } + } + bp = bp->next; + } + + sm_V(&b_sem); +} /* end of buf_release_all */ + +void buf_sync(struct super_block *sb) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + sm_P(&b_sem); + + bp = p_fs->buf_cache_lru_list.next; + while (bp != &p_fs->buf_cache_lru_list) { + if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) { + sync_dirty_buffer(bp->buf_bh); + bp->flag &= ~(DIRTYBIT); + } + bp = bp->next; + } + + sm_V(&b_sem); +} /* end of buf_sync */ + +static BUF_CACHE_T *buf_cache_find(struct super_block *sb, sector_t sec) +{ + s32 off; + BUF_CACHE_T *bp, *hp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + off = (sec + (sec >> p_fs->sectors_per_clu_bits)) & (BUF_CACHE_HASH_SIZE - 1); + + hp = &(p_fs->buf_cache_hash_list[off]); + for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) { + if ((bp->drv == p_fs->drv) && (bp->sec == sec)) { + touch_buffer(bp->buf_bh); + return bp; + } + } + return NULL; +} /* end of buf_cache_find */ + +static BUF_CACHE_T *buf_cache_get(struct super_block *sb, sector_t sec) +{ + BUF_CACHE_T *bp; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + bp = p_fs->buf_cache_lru_list.prev; + while (bp->flag & LOCKBIT) + bp = bp->prev; + + + move_to_mru(bp, &p_fs->buf_cache_lru_list); + return bp; +} /* end of buf_cache_get */ + +static void buf_cache_insert_hash(struct super_block *sb, BUF_CACHE_T *bp) +{ + s32 off; + BUF_CACHE_T *hp; + FS_INFO_T *p_fs; + + p_fs = &(EXFAT_SB(sb)->fs_info); + off = (bp->sec + (bp->sec >> p_fs->sectors_per_clu_bits)) & (BUF_CACHE_HASH_SIZE-1); + + hp = &(p_fs->buf_cache_hash_list[off]); + bp->hash_next = hp->hash_next; + bp->hash_prev = hp; + hp->hash_next->hash_prev = bp; + hp->hash_next = bp; +} /* end of buf_cache_insert_hash */ + +static void buf_cache_remove_hash(BUF_CACHE_T *bp) +{ + (bp->hash_prev)->hash_next = bp->hash_next; + (bp->hash_next)->hash_prev = bp->hash_prev; +} /* end of buf_cache_remove_hash */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +static void push_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->next = list->next; + bp->prev = list; + list->next->prev = bp; + list->next = bp; +} /* end of buf_cache_push_to_mru */ + +static void push_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev = list->prev; + bp->next = list; + list->prev->next = bp; + list->prev = bp; +} /* end of buf_cache_push_to_lru */ + +static void move_to_mru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev->next = bp->next; + bp->next->prev = bp->prev; + push_to_mru(bp, list); +} /* end of buf_cache_move_to_mru */ + +static void move_to_lru(BUF_CACHE_T *bp, BUF_CACHE_T *list) +{ + bp->prev->next = bp->next; + bp->next->prev = bp->prev; + push_to_lru(bp, list); +} /* end of buf_cache_move_to_lru */ diff --git a/fs/exfat/exfat_cache.h b/fs/exfat/exfat_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..540e31681d047078022555432889c6052aee88d0 --- /dev/null +++ b/fs/exfat/exfat_cache.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_cache.h */ +/* PURPOSE : Header File for exFAT Cache Manager */ +/* (FAT Cache & Buffer Cache) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Sung-Kwan Kim] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_CACHE_H +#define _EXFAT_CACHE_H + +#include +#include +#include "exfat_config.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define LOCKBIT 0x01 +#define DIRTYBIT 0x02 + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct __BUF_CACHE_T { + struct __BUF_CACHE_T *next; + struct __BUF_CACHE_T *prev; + struct __BUF_CACHE_T *hash_next; + struct __BUF_CACHE_T *hash_prev; + s32 drv; + sector_t sec; + u32 flag; + struct buffer_head *buf_bh; +} BUF_CACHE_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 buf_init(struct super_block *sb); +s32 buf_shutdown(struct super_block *sb); +s32 FAT_read(struct super_block *sb, u32 loc, u32 *content); +s32 FAT_write(struct super_block *sb, u32 loc, u32 content); +u8 *FAT_getblk(struct super_block *sb, sector_t sec); +void FAT_modify(struct super_block *sb, sector_t sec); +void FAT_release_all(struct super_block *sb); +void FAT_sync(struct super_block *sb); +u8 *buf_getblk(struct super_block *sb, sector_t sec); +void buf_modify(struct super_block *sb, sector_t sec); +void buf_lock(struct super_block *sb, sector_t sec); +void buf_unlock(struct super_block *sb, sector_t sec); +void buf_release(struct super_block *sb, sector_t sec); +void buf_release_all(struct super_block *sb); +void buf_sync(struct super_block *sb); + +#endif /* _EXFAT_CACHE_H */ diff --git a/fs/exfat/exfat_config.h b/fs/exfat/exfat_config.h new file mode 100644 index 0000000000000000000000000000000000000000..33c6525e449bdf059a220cbb2286bf02cae1cc22 --- /dev/null +++ b/fs/exfat/exfat_config.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_config.h */ +/* PURPOSE : Header File for exFAT Configuable Policies */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_CONFIG_H +#define _EXFAT_CONFIG_H + +/*======================================================================*/ +/* */ +/* FFS CONFIGURATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* Feature Config */ +/*----------------------------------------------------------------------*/ +#ifndef CONFIG_EXFAT_DISCARD +#define CONFIG_EXFAT_DISCARD 1 /* mount option -o discard support */ +#endif + +#ifndef CONFIG_EXFAT_DELAYED_SYNC +#define CONFIG_EXFAT_DELAYED_SYNC 0 +#endif + +#ifndef CONFIG_EXFAT_KERNEL_DEBUG +#define CONFIG_EXFAT_KERNEL_DEBUG 1 /* kernel debug features via ioctl */ +#endif + +#ifndef CONFIG_EXFAT_DEBUG_MSG +#define CONFIG_EXFAT_DEBUG_MSG 0 /* debugging message on/off */ +#endif + +#ifndef CONFIG_EXFAT_DEFAULT_CODEPAGE +#define CONFIG_EXFAT_DEFAULT_CODEPAGE 437 +#define CONFIG_EXFAT_DEFAULT_IOCHARSET "utf8" +#endif + +#endif /* _EXFAT_CONFIG_H */ diff --git a/fs/exfat/exfat_core.c b/fs/exfat/exfat_core.c new file mode 100644 index 0000000000000000000000000000000000000000..7c4d3c2d1980e56994cf0224ff78f3ec5c29e8c2 --- /dev/null +++ b/fs/exfat/exfat_core.c @@ -0,0 +1,5143 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_core.c */ +/* PURPOSE : exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include +#include + +#include "exfat_bitmap.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +#include +#include + +static void __set_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 1; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 1; +#endif +} + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +extern u8 uni_upcase[]; + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE]; + +static char *reserved_names[] = { + "AUX ", "CON ", "NUL ", "PRN ", + "COM1 ", "COM2 ", "COM3 ", "COM4 ", + "COM5 ", "COM6 ", "COM7 ", "COM8 ", "COM9 ", + "LPT1 ", "LPT2 ", "LPT3 ", "LPT4 ", + "LPT5 ", "LPT6 ", "LPT7 ", "LPT8 ", "LPT9 ", + NULL +}; + +static u8 free_bit[] = { + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 0 ~ 19 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /* 20 ~ 39 */ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 40 ~ 59 */ + 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 ~ 79 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /* 80 ~ 99 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */ + 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */ + 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */ + 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */ + 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */ + 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */ + 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 240 ~ 254 */ +}; + +static u8 used_bit[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /* 0 ~ 19 */ + 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /* 20 ~ 39 */ + 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /* 40 ~ 59 */ + 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 60 ~ 79 */ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /* 80 ~ 99 */ + 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */ + 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */ + 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */ + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */ + 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */ + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */ + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */ + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /* 240 ~ 255 */ +}; + +/*======================================================================*/ +/* Global Function Definitions */ +/*======================================================================*/ + +/* ffsInit : roll back to the initial state of the file system */ +s32 ffsInit(void) +{ + s32 ret; + + ret = bdev_init(); + if (ret) + return ret; + + ret = fs_init(); + if (ret) + return ret; + + return FFS_SUCCESS; +} /* end of ffsInit */ + +/* ffsShutdown : make free all memory-alloced global buffers */ +s32 ffsShutdown(void) +{ + s32 ret; + ret = fs_shutdown(); + if (ret) + return ret; + + ret = bdev_shutdown(); + if (ret) + return ret; + + return FFS_SUCCESS; +} /* end of ffsShutdown */ + +/* ffsMountVol : mount the file system volume */ +s32 ffsMountVol(struct super_block *sb) +{ + int i, ret; + PBR_SECTOR_T *p_pbr; + struct buffer_head *tmp_bh = NULL; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + printk("[EXFAT] trying to mount...\n"); + + sm_init(&p_fs->v_sem); + p_fs->dev_ejected = FALSE; + + /* open the block device */ + if (bdev_open(sb)) + return FFS_MEDIAERR; + + if (p_bd->sector_size < sb->s_blocksize) + return FFS_MEDIAERR; + if (p_bd->sector_size > sb->s_blocksize) + sb_set_blocksize(sb, p_bd->sector_size); + + /* read Sector 0 */ + if (sector_read(sb, 0, &tmp_bh, 1) != FFS_SUCCESS) + return FFS_MEDIAERR; + + p_fs->PBR_sector = 0; + + p_pbr = (PBR_SECTOR_T *) tmp_bh->b_data; + + /* check the validity of PBR */ + if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) { + brelse(tmp_bh); + bdev_close(sb); + return FFS_FORMATERR; + } + + /* fill fs_stuct */ + for (i = 0; i < 53; i++) + if (p_pbr->bpb[i]) + break; + + if (i < 53) { + if (GET16(p_pbr->bpb+11)) /* num_fat_sectors */ + ret = fat16_mount(sb, p_pbr); + else + ret = fat32_mount(sb, p_pbr); + } else { + ret = exfat_mount(sb, p_pbr); + } + + brelse(tmp_bh); + + if (ret) { + bdev_close(sb); + return ret; + } + + if (p_fs->vol_type == EXFAT) { + ret = load_alloc_bitmap(sb); + if (ret) { + bdev_close(sb); + return ret; + } + ret = load_upcase_table(sb); + if (ret) { + free_alloc_bitmap(sb); + bdev_close(sb); + return ret; + } + } + + if (p_fs->dev_ejected) { + if (p_fs->vol_type == EXFAT) { + free_upcase_table(sb); + free_alloc_bitmap(sb); + } + bdev_close(sb); + return FFS_MEDIAERR; + } + + printk("[EXFAT] mounted successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsMountVol */ + +/* ffsUmountVol : umount the file system volume */ +s32 ffsUmountVol(struct super_block *sb) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + printk("[EXFAT] trying to unmount...\n"); + + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); + + if (p_fs->vol_type == EXFAT) { + free_upcase_table(sb); + free_alloc_bitmap(sb); + } + + FAT_release_all(sb); + buf_release_all(sb); + + /* close the block device */ + bdev_close(sb); + + if (p_fs->dev_ejected) { + printk("[EXFAT] unmounted with media errors. " + "device's already ejected.\n"); + return FFS_MEDIAERR; + } + + printk("[EXFAT] unmounted successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsUmountVol */ + +/* ffsGetVolInfo : get the information of a file system volume */ +s32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->used_clusters == (u32) ~0) + p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb); + + info->FatType = p_fs->vol_type; + info->ClusterSize = p_fs->cluster_size; + info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */ + info->UsedClusters = p_fs->used_clusters; + info->FreeClusters = info->NumClusters - info->UsedClusters; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsGetVolInfo */ + +/* ffsSyncVol : synchronize all file system volumes */ +s32 ffsSyncVol(struct super_block *sb, s32 do_sync) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* synchronize the file system */ + fs_sync(sb, do_sync); + fs_set_vol_flags(sb, VOL_CLEAN); + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSyncVol */ + +/*----------------------------------------------------------------------*/ +/* File Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* ffsLookupFile : lookup a file */ +s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + CHAIN_T dir; + UNI_NAME_T uni_name; + DOS_NAME_T dos_name; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + DPRINTK("ffsLookupFile entered\n"); + + /* check the validity of directory name in the given pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries, &dos_name); + if (ret) + return ret; + + /* search the file name for directories */ + dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries, &dos_name, TYPE_ALL); + if (dentry < -1) + return FFS_NOTFOUND; + + fid->dir.dir = dir.dir; + fid->dir.size = dir.size; + fid->dir.flags = dir.flags; + fid->entry = dentry; + + if (dentry == -1) { + fid->type = TYPE_DIR; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + fid->attr = ATTR_SUBDIR; + fid->flags = 0x01; + fid->size = 0; + fid->start_clu = p_fs->root_dir; + } else { + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &dir, dentry, ES_2_ENTRIES, &ep); + if (!es) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &dir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + fid->type = p_fs->fs_func->get_entry_type(ep); + fid->rwoffset = 0; + fid->hint_last_off = -1; + fid->attr = p_fs->fs_func->get_entry_attr(ep); + + fid->size = p_fs->fs_func->get_entry_size(ep2); + if ((fid->type == TYPE_FILE) && (fid->size == 0)) { + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->start_clu = CLUSTER_32(~0); + } else { + fid->flags = p_fs->fs_func->get_entry_flag(ep2); + fid->start_clu = p_fs->fs_func->get_entry_clu0(ep2); + } + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + DPRINTK("ffsLookupFile exited successfully\n"); + + return FFS_SUCCESS; +} /* end of ffsLookupFile */ + +/* ffsCreateFile : create a file */ +s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid) +{ + s32 ret/*, dentry*/; + CHAIN_T dir; + UNI_NAME_T uni_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + /* check the validity of directory name in the given pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* create a new file */ + ret = create_file(inode, &dir, &uni_name, mode, fid); + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsCreateFile */ + +/* ffsReadFile : read data from a opened file */ +s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount) +{ + s32 offset, sec_offset, clu_offset; + u32 clu; + sector_t LogSector; + u64 oneblkread, read_bytes; + struct buffer_head *tmp_bh = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + + if (count > (fid->size - fid->rwoffset)) + count = fid->size - fid->rwoffset; + + if (count == 0) { + if (rcount != NULL) + *rcount = 0; + return FFS_EOF; + } + + read_bytes = 0; + + while (count > 0) { + clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + clu = fid->start_clu; + + if (fid->flags == 0x03) { + clu += clu_offset; + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu = fid->hint_last_clu; + } + + while (clu_offset > 0) { + /* clu = FAT_read(sb, clu); */ + if (FAT_read(sb, clu, &clu) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = clu; + + offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */ + sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + offset &= p_bd->sector_size_mask; /* byte offset in sector */ + + LogSector = START_SECTOR(clu) + sec_offset; + + oneblkread = (u64)(p_bd->sector_size - offset); + if (oneblkread > count) + oneblkread = count; + + if ((offset == 0) && (oneblkread == p_bd->sector_size)) { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) buffer)+read_bytes, ((char *) tmp_bh->b_data), (s32) oneblkread); + } else { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) buffer)+read_bytes, ((char *) tmp_bh->b_data)+offset, (s32) oneblkread); + } + count -= oneblkread; + read_bytes += oneblkread; + fid->rwoffset += oneblkread; + } + brelse(tmp_bh); + +err_out: + /* set the size of read bytes */ + if (rcount != NULL) + *rcount = read_bytes; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsReadFile */ + +/* ffsWriteFile : write data into a opened file */ +s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount) +{ + s32 modified = FALSE, offset, sec_offset, clu_offset; + s32 num_clusters, num_alloc, num_alloced = (s32) ~0; + u32 clu, last_clu; + sector_t LogSector, sector = 0; + u64 oneblkwrite, write_bytes; + CHAIN_T new_clu; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct buffer_head *tmp_bh = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + + if (count == 0) { + if (wcount != NULL) + *wcount = 0; + return FFS_SUCCESS; + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + if (fid->size == 0) + num_clusters = 0; + else + num_clusters = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + + write_bytes = 0; + + while (count > 0) { + clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + clu = last_clu = fid->start_clu; + + if (fid->flags == 0x03) { + if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + clu = CLUSTER_32(~0); + else + clu += clu_offset; + } + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu = fid->hint_last_clu; + } + + while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { + last_clu = clu; + /* clu = FAT_read(sb, clu); */ + if (FAT_read(sb, clu, &clu) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + + if (clu == CLUSTER_32(~0)) { + num_alloc = (s32)((count-1) >> p_fs->cluster_size_bits) + 1; + new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1; + new_clu.size = 0; + new_clu.flags = fid->flags; + + /* (1) allocate a chain of clusters */ + num_alloced = p_fs->fs_func->alloc_cluster(sb, num_alloc, &new_clu); + if (num_alloced == 0) + break; + else if (num_alloced < 0) + return FFS_MEDIAERR; + + /* (2) append to the FAT chain */ + if (last_clu == CLUSTER_32(~0)) { + if (new_clu.flags == 0x01) + fid->flags = 0x01; + fid->start_clu = new_clu.dir; + modified = TRUE; + } else { + if (new_clu.flags != fid->flags) { + exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters); + fid->flags = 0x01; + modified = TRUE; + } + if (new_clu.flags == 0x01) + FAT_write(sb, last_clu, new_clu.dir); + } + + num_clusters += num_alloced; + clu = new_clu.dir; + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = clu; + + offset = (s32)(fid->rwoffset & (p_fs->cluster_size-1)); /* byte offset in cluster */ + sec_offset = offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + offset &= p_bd->sector_size_mask; /* byte offset in sector */ + + LogSector = START_SECTOR(clu) + sec_offset; + + oneblkwrite = (u64)(p_bd->sector_size - offset); + if (oneblkwrite > count) + oneblkwrite = count; + + if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) { + if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS) + goto err_out; + memcpy(((char *) tmp_bh->b_data), ((char *) buffer)+write_bytes, (s32) oneblkwrite); + if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) { + brelse(tmp_bh); + goto err_out; + } + } else { + if ((offset > 0) || ((fid->rwoffset+oneblkwrite) < fid->size)) { + if (sector_read(sb, LogSector, &tmp_bh, 1) != FFS_SUCCESS) + goto err_out; + } else { + if (sector_read(sb, LogSector, &tmp_bh, 0) != FFS_SUCCESS) + goto err_out; + } + + memcpy(((char *) tmp_bh->b_data)+offset, ((char *) buffer)+write_bytes, (s32) oneblkwrite); + if (sector_write(sb, LogSector, tmp_bh, 0) != FFS_SUCCESS) { + brelse(tmp_bh); + goto err_out; + } + } + + count -= oneblkwrite; + write_bytes += oneblkwrite; + fid->rwoffset += oneblkwrite; + + fid->attr |= ATTR_ARCHIVE; + + if (fid->size < fid->rwoffset) { + fid->size = fid->rwoffset; + modified = TRUE; + } + } + + brelse(tmp_bh); + + /* (3) update the direcoty entry */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + goto err_out; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + goto err_out; + ep2 = ep; + } + + p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); + p_fs->fs_func->set_entry_attr(ep, fid->attr); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + + if (modified) { + if (p_fs->fs_func->get_entry_flag(ep2) != fid->flags) + p_fs->fs_func->set_entry_flag(ep2, fid->flags); + + if (p_fs->fs_func->get_entry_size(ep2) != fid->size) + p_fs->fs_func->set_entry_size(ep2, fid->size); + + if (p_fs->fs_func->get_entry_clu0(ep2) != fid->start_clu) + p_fs->fs_func->set_entry_clu0(ep2, fid->start_clu); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + } + + if (p_fs->vol_type == EXFAT) { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + +err_out: + /* set the size of written bytes */ + if (wcount != NULL) + *wcount = write_bytes; + + if (num_alloced == 0) + return FFS_FULL; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsWriteFile */ + +/* ffsTruncateFile : resize the file length */ +s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) +{ + s32 num_clusters; + u32 last_clu = CLUSTER_32(0); + sector_t sector = 0; + CHAIN_T clu; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + ENTRY_SET_CACHE_T *es = NULL; + + /* check if the given file ID is opened */ + if (fid->type != TYPE_FILE) + return FFS_PERMISSIONERR; + + if (fid->size != old_size) { + printk(KERN_ERR "[EXFAT] truncate : can't skip it because of " + "size-mismatch(old:%lld->fid:%lld).\n" + ,old_size, fid->size); + } + + if (old_size <= new_size) + return FFS_SUCCESS; + + fs_set_vol_flags(sb, VOL_DIRTY); + + clu.dir = fid->start_clu; + clu.size = (s32)((old_size-1) >> p_fs->cluster_size_bits) + 1; + clu.flags = fid->flags; + + if (new_size > 0) { + num_clusters = (s32)((new_size-1) >> p_fs->cluster_size_bits) + 1; + + if (clu.flags == 0x03) { + clu.dir += num_clusters; + } else { + while (num_clusters > 0) { + last_clu = clu.dir; + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + num_clusters--; + } + } + + clu.size -= num_clusters; + } + + fid->size = new_size; + fid->attr |= ATTR_ARCHIVE; + if (new_size == 0) { + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->start_clu = CLUSTER_32(~0); + } + + /* (1) update the directory entry */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + p_fs->fs_func->set_entry_time(ep, tm_current(&tm), TM_MODIFY); + p_fs->fs_func->set_entry_attr(ep, fid->attr); + + p_fs->fs_func->set_entry_size(ep2, new_size); + if (new_size == 0) { + p_fs->fs_func->set_entry_flag(ep2, 0x01); + p_fs->fs_func->set_entry_clu0(ep2, CLUSTER_32(0)); + } + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + /* (2) cut off from the FAT chain */ + if (last_clu != CLUSTER_32(0)) { + if (fid->flags == 0x01) + FAT_write(sb, last_clu, CLUSTER_32(~0)); + } + + /* (3) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu, 0); + + /* hint information */ + fid->hint_last_off = -1; + if (fid->rwoffset > fid->size) + fid->rwoffset = fid->size; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsTruncateFile */ + +static void update_parent_info(FILE_ID_T *fid, struct inode *parent_inode) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info); + FILE_ID_T *parent_fid = &(EXFAT_I(parent_inode)->fid); + + if (unlikely((parent_fid->flags != fid->dir.flags) + || (parent_fid->size != (fid->dir.size<cluster_size_bits)) + || (parent_fid->start_clu != fid->dir.dir))) { + + fid->dir.dir = parent_fid->start_clu; + fid->dir.flags = parent_fid->flags; + fid->dir.size = ((parent_fid->size + (p_fs->cluster_size-1)) + >> p_fs->cluster_size_bits); + } +} + +/* ffsMoveFile : move(rename) a old file into a new file */ +s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry) +{ + s32 ret; + s32 dentry; + CHAIN_T olddir, newdir; + CHAIN_T *p_dir = NULL; + UNI_NAME_T uni_name; + DENTRY_T *ep; + struct super_block *sb = old_parent_inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + u8 *new_path = (u8 *) new_dentry->d_name.name; + struct inode *new_inode = new_dentry->d_inode; + int num_entries; + FILE_ID_T *new_fid = NULL; + s32 new_entry = 0; + + /* check the validity of pointer parameters */ + if ((new_path == NULL) || (*new_path == '\0')) + return FFS_ERROR; + + update_parent_info(fid, old_parent_inode); + + olddir.dir = fid->dir.dir; + olddir.size = fid->dir.size; + olddir.flags = fid->dir.flags; + + dentry = fid->entry; + + /* check if the old file is "." or ".." */ + if (p_fs->vol_type != EXFAT) { + if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) + return FFS_PERMISSIONERR; + } + + ep = get_entry_in_dir(sb, &olddir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + + if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) + return FFS_PERMISSIONERR; + + /* check whether new dir is existing directory and empty */ + if (new_inode) { + u32 entry_type; + + ret = FFS_MEDIAERR; + new_fid = &EXFAT_I(new_inode)->fid; + + update_parent_info(new_fid, new_parent_inode); + + p_dir = &(new_fid->dir); + new_entry = new_fid->entry; + ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); + if (!ep) + goto out; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if (entry_type == TYPE_DIR) { + CHAIN_T new_clu; + new_clu.dir = new_fid->start_clu; + new_clu.size = (s32)((new_fid->size-1) >> p_fs->cluster_size_bits) + 1; + new_clu.flags = new_fid->flags; + + if (!is_dir_empty(sb, &new_clu)) + return FFS_FILEEXIST; + } + } + + /* check the validity of directory name in the given new pathname */ + ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + if (olddir.dir == newdir.dir) + ret = rename_file(new_parent_inode, &olddir, dentry, &uni_name, fid); + else + ret = move_file(new_parent_inode, &olddir, dentry, &newdir, &uni_name, fid); + + if ((ret == FFS_SUCCESS) && new_inode) { + /* delete entries of new_dir */ + ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); + if (!ep) + goto out; + + num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, new_entry, ep); + if (num_entries < 0) + goto out; + p_fs->fs_func->delete_dir_entry(sb, p_dir, new_entry, 0, num_entries+1); + } +out: +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsMoveFile */ + +/* ffsRemoveFile : remove a file */ +s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid) +{ + s32 dentry; + CHAIN_T dir, clu_to_free; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + dir.dir = fid->dir.dir; + dir.size = fid->dir.size; + dir.flags = fid->dir.flags; + + dentry = fid->entry; + + ep = get_entry_in_dir(sb, &dir, dentry, NULL); + if (!ep) + return FFS_MEDIAERR; + + if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) + return FFS_PERMISSIONERR; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* (1) update the directory entry */ + remove_file(inode, &dir, dentry); + + clu_to_free.dir = fid->start_clu; + clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu_to_free.flags = fid->flags; + + /* (2) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu_to_free, 0); + + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsRemoveFile */ + +/* ffsSetAttr : set the attribute of a given file */ +s32 ffsSetAttr(struct inode *inode, u32 attr) +{ + u32 type; + sector_t sector = 0; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + ENTRY_SET_CACHE_T *es = NULL; + + if (fid->attr == attr) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + /* get the directory entry of given file */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + } + + type = p_fs->fs_func->get_entry_type(ep); + + if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) || + ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) { + s32 err; + if (p_fs->dev_ejected) + err = FFS_MEDIAERR; + else + err = FFS_ERROR; + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + return err; + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* set the file attribute */ + fid->attr = attr; + p_fs->fs_func->set_entry_attr(ep, attr); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSetAttr */ + +/* ffsGetStat : get the information of a given file */ +s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info) +{ + sector_t sector = 0; + s32 count; + CHAIN_T dir; + UNI_NAME_T uni_name; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + ENTRY_SET_CACHE_T *es = NULL; + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + + DPRINTK("ffsGetStat entered\n"); + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + info->Attr = ATTR_SUBDIR; + memset((char *) &info->CreateTimestamp, 0, sizeof(DATE_TIME_T)); + memset((char *) &info->ModifyTimestamp, 0, sizeof(DATE_TIME_T)); + memset((char *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + strcpy(info->ShortName, "."); + strcpy(info->Name, "."); + + dir.dir = p_fs->root_dir; + dir.flags = 0x01; + + if (p_fs->root_dir == CLUSTER_32(0)) /* FAT16 root_dir */ + info->Size = p_fs->dentries_in_root << DENTRY_SIZE_BITS; + else + info->Size = count_num_clusters(sb, &dir) << p_fs->cluster_size_bits; + + count = count_dos_name_entries(sb, &dir, TYPE_DIR); + if (count < 0) + return FFS_MEDIAERR; + info->NumSubdirs = count; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + /* get the directory entry of given file or directory */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_2_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + buf_lock(sb, sector); + } + + /* set FILE_INFO structure using the acquired DENTRY_T */ + info->Attr = p_fs->fs_func->get_entry_attr(ep); + + p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); + info->CreateTimestamp.Year = tm.year; + info->CreateTimestamp.Month = tm.mon; + info->CreateTimestamp.Day = tm.day; + info->CreateTimestamp.Hour = tm.hour; + info->CreateTimestamp.Minute = tm.min; + info->CreateTimestamp.Second = tm.sec; + info->CreateTimestamp.MilliSecond = 0; + + p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); + info->ModifyTimestamp.Year = tm.year; + info->ModifyTimestamp.Month = tm.mon; + info->ModifyTimestamp.Day = tm.day; + info->ModifyTimestamp.Hour = tm.hour; + info->ModifyTimestamp.Minute = tm.min; + info->ModifyTimestamp.Second = tm.sec; + info->ModifyTimestamp.MilliSecond = 0; + + memset((char *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + + *(uni_name.name) = 0x0; + /* XXX this is very bad for exfat cuz name is already included in es. + API should be revised */ + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry, uni_name.name); + if (*(uni_name.name) == 0x0 && p_fs->vol_type != EXFAT) + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1); + nls_uniname_to_cstring(sb, info->Name, &uni_name); + + if (p_fs->vol_type == EXFAT) { + info->NumSubdirs = 2; + } else { + buf_unlock(sb, sector); + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0); + nls_uniname_to_cstring(sb, info->ShortName, &uni_name); + info->NumSubdirs = 0; + } + + info->Size = p_fs->fs_func->get_entry_size(ep2); + + if (p_fs->vol_type == EXFAT) + release_entry_set(es); + + if (is_dir) { + dir.dir = fid->start_clu; + dir.flags = 0x01; + + if (info->Size == 0) + info->Size = (u64) count_num_clusters(sb, &dir) << p_fs->cluster_size_bits; + + count = count_dos_name_entries(sb, &dir, TYPE_DIR); + if (count < 0) + return FFS_MEDIAERR; + info->NumSubdirs += count; + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + DPRINTK("ffsGetStat exited successfully\n"); + return FFS_SUCCESS; +} /* end of ffsGetStat */ + +/* ffsSetStat : set the information of a given file */ +s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info) +{ + sector_t sector = 0; + TIMESTAMP_T tm; + DENTRY_T *ep, *ep2; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0; + + if (is_dir) { + if ((fid->dir.dir == p_fs->root_dir) && + (fid->entry == -1)) { + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + return FFS_SUCCESS; + } + } + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* get the directory entry of given file or directory */ + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + ep2 = ep+1; + } else { + /* for other than exfat */ + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + ep2 = ep; + } + + + p_fs->fs_func->set_entry_attr(ep, info->Attr); + + /* set FILE_INFO structure using the acquired DENTRY_T */ + tm.sec = info->CreateTimestamp.Second; + tm.min = info->CreateTimestamp.Minute; + tm.hour = info->CreateTimestamp.Hour; + tm.day = info->CreateTimestamp.Day; + tm.mon = info->CreateTimestamp.Month; + tm.year = info->CreateTimestamp.Year; + p_fs->fs_func->set_entry_time(ep, &tm, TM_CREATE); + + tm.sec = info->ModifyTimestamp.Second; + tm.min = info->ModifyTimestamp.Minute; + tm.hour = info->ModifyTimestamp.Hour; + tm.day = info->ModifyTimestamp.Day; + tm.mon = info->ModifyTimestamp.Month; + tm.year = info->ModifyTimestamp.Year; + p_fs->fs_func->set_entry_time(ep, &tm, TM_MODIFY); + + + p_fs->fs_func->set_entry_size(ep2, info->Size); + + if (p_fs->vol_type != EXFAT) { + buf_modify(sb, sector); + } else { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsSetStat */ + +s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) +{ + s32 num_clusters, num_alloced, modified = FALSE; + u32 last_clu; + sector_t sector = 0; + CHAIN_T new_clu; + DENTRY_T *ep; + ENTRY_SET_CACHE_T *es = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; + + if (EXFAT_I(inode)->mmu_private == 0) + num_clusters = 0; + else + num_clusters = (s32)((EXFAT_I(inode)->mmu_private-1) >> p_fs->cluster_size_bits) + 1; + + *clu = last_clu = fid->start_clu; + + if (fid->flags == 0x03) { + if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { + last_clu += clu_offset - 1; + + if (clu_offset == num_clusters) + *clu = CLUSTER_32(~0); + else + *clu += clu_offset; + } + } else { + /* hint information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + *clu = fid->hint_last_clu; + } + + while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) { + last_clu = *clu; + if (FAT_read(sb, *clu, clu) == -1) + return FFS_MEDIAERR; + clu_offset--; + } + } + + if (*clu == CLUSTER_32(~0)) { + fs_set_vol_flags(sb, VOL_DIRTY); + + new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) : last_clu+1; + new_clu.size = 0; + new_clu.flags = fid->flags; + + /* (1) allocate a cluster */ + num_alloced = p_fs->fs_func->alloc_cluster(sb, 1, &new_clu); + if (num_alloced < 0) + return FFS_MEDIAERR; + else if (num_alloced == 0) + return FFS_FULL; + + /* (2) append to the FAT chain */ + if (last_clu == CLUSTER_32(~0)) { + if (new_clu.flags == 0x01) + fid->flags = 0x01; + fid->start_clu = new_clu.dir; + modified = TRUE; + } else { + if (new_clu.flags != fid->flags) { + exfat_chain_cont_cluster(sb, fid->start_clu, num_clusters); + fid->flags = 0x01; + modified = TRUE; + } + if (new_clu.flags == 0x01) + FAT_write(sb, last_clu, new_clu.dir); + } + + num_clusters += num_alloced; + *clu = new_clu.dir; + + if (p_fs->vol_type == EXFAT) { + es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, ES_ALL_ENTRIES, &ep); + if (es == NULL) + return FFS_MEDIAERR; + /* get stream entry */ + ep++; + } + + /* (3) update directory entry */ + if (modified) { + if (p_fs->vol_type != EXFAT) { + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + if (!ep) + return FFS_MEDIAERR; + } + + if (p_fs->fs_func->get_entry_flag(ep) != fid->flags) + p_fs->fs_func->set_entry_flag(ep, fid->flags); + + if (p_fs->fs_func->get_entry_clu0(ep) != fid->start_clu) + p_fs->fs_func->set_entry_clu0(ep, fid->start_clu); + + if (p_fs->vol_type != EXFAT) + buf_modify(sb, sector); + } + + if (p_fs->vol_type == EXFAT) { + update_dir_checksum_with_entry_set(sb, es); + release_entry_set(es); + } + + /* add number of new blocks to inode */ + inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9); + } + + /* hint information */ + fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); + fid->hint_last_clu = *clu; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsMapCluster */ + +/*----------------------------------------------------------------------*/ +/* Directory Operation Functions */ +/*----------------------------------------------------------------------*/ + +/* ffsCreateDir : create(make) a directory */ +s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid) +{ + s32 ret/*, dentry*/; + CHAIN_T dir; + UNI_NAME_T uni_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + DPRINTK("ffsCreateDir entered\n"); + + /* check the validity of directory name in the given old pathname */ + ret = resolve_path(inode, path, &dir, &uni_name); + if (ret) + return ret; + + fs_set_vol_flags(sb, VOL_DIRTY); + + ret = create_dir(inode, &dir, &uni_name, fid); + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return ret; +} /* end of ffsCreateDir */ + +/* ffsReadDir : read a directory entry from the opened directory */ +s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_entry) +{ + int i, dentry, clu_offset; + s32 dentries_per_clu, dentries_per_clu_bits = 0; + u32 type; + sector_t sector; + CHAIN_T dir, clu; + UNI_NAME_T uni_name; + TIMESTAMP_T tm; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + /* check if the given file ID is opened */ + if (fid->type != TYPE_DIR) + return FFS_PERMISSIONERR; + + if (fid->entry == -1) { + dir.dir = p_fs->root_dir; + dir.flags = 0x01; + } else { + dir.dir = fid->start_clu; + dir.size = (s32)(fid->size >> p_fs->cluster_size_bits); + dir.flags = fid->flags; + } + + dentry = (s32) fid->rwoffset; + + if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + + if (dentry == dentries_per_clu) { + clu.dir = CLUSTER_32(~0); + } else { + clu.dir = dir.dir; + clu.size = dir.size; + clu.flags = dir.flags; + } + } else { + dentries_per_clu = p_fs->dentries_per_clu; + dentries_per_clu_bits = ilog2(dentries_per_clu); + + clu_offset = dentry >> dentries_per_clu_bits; + clu.dir = dir.dir; + clu.size = dir.size; + clu.flags = dir.flags; + + if (clu.flags == 0x03) { + clu.dir += clu_offset; + clu.size -= clu_offset; + } else { + /* hint_information */ + if ((clu_offset > 0) && (fid->hint_last_off > 0) && + (clu_offset >= fid->hint_last_off)) { + clu_offset -= fid->hint_last_off; + clu.dir = fid->hint_last_clu; + } + + while (clu_offset > 0) { + /* clu.dir = FAT_read(sb, clu.dir); */ + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + + clu_offset--; + } + } + } + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */ + i = dentry % dentries_per_clu; + else + i = dentry & (dentries_per_clu-1); + + for ( ; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, §or); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) + break; + + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + buf_lock(sb, sector); + dir_entry->Attr = p_fs->fs_func->get_entry_attr(ep); + + p_fs->fs_func->get_entry_time(ep, &tm, TM_CREATE); + dir_entry->CreateTimestamp.Year = tm.year; + dir_entry->CreateTimestamp.Month = tm.mon; + dir_entry->CreateTimestamp.Day = tm.day; + dir_entry->CreateTimestamp.Hour = tm.hour; + dir_entry->CreateTimestamp.Minute = tm.min; + dir_entry->CreateTimestamp.Second = tm.sec; + dir_entry->CreateTimestamp.MilliSecond = 0; + + p_fs->fs_func->get_entry_time(ep, &tm, TM_MODIFY); + dir_entry->ModifyTimestamp.Year = tm.year; + dir_entry->ModifyTimestamp.Month = tm.mon; + dir_entry->ModifyTimestamp.Day = tm.day; + dir_entry->ModifyTimestamp.Hour = tm.hour; + dir_entry->ModifyTimestamp.Minute = tm.min; + dir_entry->ModifyTimestamp.Second = tm.sec; + dir_entry->ModifyTimestamp.MilliSecond = 0; + + memset((char *) &dir_entry->AccessTimestamp, 0, sizeof(DATE_TIME_T)); + + *(uni_name.name) = 0x0; + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry, uni_name.name); + if (*(uni_name.name) == 0x0 && p_fs->vol_type != EXFAT) + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x1); + nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name); + buf_unlock(sb, sector); + + if (p_fs->vol_type == EXFAT) { + ep = get_entry_in_dir(sb, &clu, i+1, NULL); + if (!ep) + return FFS_MEDIAERR; + } else { + get_uni_name_from_dos_entry(sb, (DOS_DENTRY_T *) ep, &uni_name, 0x0); + nls_uniname_to_cstring(sb, dir_entry->ShortName, &uni_name); + } + + dir_entry->Size = p_fs->fs_func->get_entry_size(ep); + + /* hint information */ + if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + } else { + fid->hint_last_off = dentry >> dentries_per_clu_bits; + fid->hint_last_clu = clu.dir; + } + + fid->rwoffset = (s64) ++dentry; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; + } + + if (dir.dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + /* clu.dir = FAT_read(sb, clu.dir); */ + if (FAT_read(sb, clu.dir, &(clu.dir)) == -1) + return FFS_MEDIAERR; + } + } + + *(dir_entry->Name) = '\0'; + + fid->rwoffset = (s64) ++dentry; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsReadDir */ + +/* ffsRemoveDir : remove a directory */ +s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid) +{ + s32 dentry; + CHAIN_T dir, clu_to_free; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + dir.dir = fid->dir.dir; + dir.size = fid->dir.size; + dir.flags = fid->dir.flags; + + dentry = fid->entry; + + /* check if the file is "." or ".." */ + if (p_fs->vol_type != EXFAT) { + if ((dir.dir != p_fs->root_dir) && (dentry < 2)) + return FFS_PERMISSIONERR; + } + + clu_to_free.dir = fid->start_clu; + clu_to_free.size = (s32)((fid->size-1) >> p_fs->cluster_size_bits) + 1; + clu_to_free.flags = fid->flags; + + if (!is_dir_empty(sb, &clu_to_free)) + return FFS_FILEEXIST; + + fs_set_vol_flags(sb, VOL_DIRTY); + + /* (1) update the directory entry */ + remove_file(inode, &dir, dentry); + + /* (2) free the clusters */ + p_fs->fs_func->free_cluster(sb, &clu_to_free, 1); + + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + fid->flags = (p_fs->vol_type == EXFAT)? 0x03: 0x01; + +#ifdef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, 0); + fs_set_vol_flags(sb, VOL_CLEAN); +#endif + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + return FFS_SUCCESS; +} /* end of ffsRemoveDir */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +/* + * File System Management Functions + */ + +s32 fs_init(void) +{ + /* critical check for system requirement on size of DENTRY_T structure */ + if (sizeof(DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(DOS_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(EXT_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(FILE_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(STRM_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(NAME_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(BMAP_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(CASE_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + if (sizeof(VOLM_DENTRY_T) != DENTRY_SIZE) + return FFS_ALIGNMENTERR; + + return FFS_SUCCESS; +} /* end of fs_init */ + +s32 fs_shutdown(void) +{ + return FFS_SUCCESS; +} /* end of fs_shutdown */ + +void fs_set_vol_flags(struct super_block *sb, u32 new_flag) +{ + PBR_SECTOR_T *p_pbr; + BPBEX_T *p_bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->vol_flag == new_flag) + return; + + p_fs->vol_flag = new_flag; + + if (p_fs->vol_type == EXFAT) { + if (p_fs->pbr_bh == NULL) { + if (sector_read(sb, p_fs->PBR_sector, &(p_fs->pbr_bh), 1) != FFS_SUCCESS) + return; + } + + p_pbr = (PBR_SECTOR_T *) p_fs->pbr_bh->b_data; + p_bpb = (BPBEX_T *) p_pbr->bpb; + SET16(p_bpb->vol_flags, (u16) new_flag); + + /* XXX duyoung + what can we do here? (cuz fs_set_vol_flags() is void) */ + if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh))) + sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1); + else + sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0); + } +} /* end of fs_set_vol_flags */ + +void fs_sync(struct super_block *sb, s32 do_sync) +{ + if (do_sync) + bdev_sync(sb); +} /* end of fs_sync */ + +void fs_error(struct super_block *sb) +{ + struct exfat_mount_options *opts = &EXFAT_SB(sb)->options; + + if (opts->errors == EXFAT_ERRORS_PANIC) + panic("[EXFAT] Filesystem panic from previous error\n"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) + else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & SB_RDONLY)) { + sb->s_flags |= SB_RDONLY; +#else + else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) { + sb->s_flags |= MS_RDONLY; +#endif + printk(KERN_ERR "[EXFAT] Filesystem has been set read-only\n"); + } +} + +/* + * Cluster Management Functions + */ + +s32 clear_cluster(struct super_block *sb, u32 clu) +{ + sector_t s, n; + s32 ret = FFS_SUCCESS; + struct buffer_head *tmp_bh = NULL; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */ + s = p_fs->root_start_sector; + n = p_fs->data_start_sector; + } else { + s = START_SECTOR(clu); + n = s + p_fs->sectors_per_clu; + } + + for (; s < n; s++) { + ret = sector_read(sb, s, &tmp_bh, 0); + if (ret != FFS_SUCCESS) + return ret; + + memset((char *) tmp_bh->b_data, 0x0, p_bd->sector_size); + ret = sector_write(sb, s, tmp_bh, 0); + if (ret != FFS_SUCCESS) + break; + } + + brelse(tmp_bh); + return ret; +} /* end of clear_cluster */ + +s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain) +{ + int i, num_clusters = 0; + u32 new_clu, last_clu = CLUSTER_32(~0), read_clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + new_clu = p_chain->dir; + if (new_clu == CLUSTER_32(~0)) + new_clu = p_fs->clu_srch_ptr; + else if (new_clu >= p_fs->num_clusters) + new_clu = 2; + + __set_sb_dirty(sb); + + p_chain->dir = CLUSTER_32(~0); + + for (i = 2; i < p_fs->num_clusters; i++) { + if (FAT_read(sb, new_clu, &read_clu) != 0) + return -1; + + if (read_clu == CLUSTER_32(0)) { + if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) + return -1; + num_clusters++; + + if (p_chain->dir == CLUSTER_32(~0)) + p_chain->dir = new_clu; + else { + if (FAT_write(sb, last_clu, new_clu) < 0) + return -1; + } + + last_clu = new_clu; + + if ((--num_alloc) == 0) { + p_fs->clu_srch_ptr = new_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + return num_clusters; + } + } + if ((++new_clu) >= p_fs->num_clusters) + new_clu = 2; + } + + p_fs->clu_srch_ptr = new_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + return num_clusters; +} /* end of fat_alloc_cluster */ + +s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain) +{ + s32 num_clusters = 0; + u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + hint_clu = p_chain->dir; + if (hint_clu == CLUSTER_32(~0)) { + hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr-2); + if (hint_clu == CLUSTER_32(~0)) + return 0; + } else if (hint_clu >= p_fs->num_clusters) { + hint_clu = 2; + p_chain->flags = 0x01; + } + + __set_sb_dirty(sb); + + p_chain->dir = CLUSTER_32(~0); + + while ((new_clu = test_alloc_bitmap(sb, hint_clu-2)) != CLUSTER_32(~0)) { + if (new_clu != hint_clu) { + if (p_chain->flags == 0x03) { + exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters); + p_chain->flags = 0x01; + } + } + + if (set_alloc_bitmap(sb, new_clu-2) != FFS_SUCCESS) + return -1; + + num_clusters++; + + if (p_chain->flags == 0x01) { + if (FAT_write(sb, new_clu, CLUSTER_32(~0)) < 0) + return -1; + } + + if (p_chain->dir == CLUSTER_32(~0)) { + p_chain->dir = new_clu; + } else { + if (p_chain->flags == 0x01) { + if (FAT_write(sb, last_clu, new_clu) < 0) + return -1; + } + } + last_clu = new_clu; + + if ((--num_alloc) == 0) { + p_fs->clu_srch_ptr = hint_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return num_clusters; + } + + hint_clu = new_clu + 1; + if (hint_clu >= p_fs->num_clusters) { + hint_clu = 2; + + if (p_chain->flags == 0x03) { + exfat_chain_cont_cluster(sb, p_chain->dir, num_clusters); + p_chain->flags = 0x01; + } + } + } + + p_fs->clu_srch_ptr = hint_clu; + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters += num_clusters; + + p_chain->size += num_clusters; + return num_clusters; +} /* end of exfat_alloc_cluster */ + +void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse) +{ + s32 num_clusters = 0; + u32 clu, prev; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + int i; + sector_t sector; + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return; + __set_sb_dirty(sb); + clu = p_chain->dir; + + if (p_chain->size <= 0) + return; + + do { + if (p_fs->dev_ejected) + break; + + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + prev = clu; + if (FAT_read(sb, clu, &clu) == -1) + break; + + if (FAT_write(sb, prev, CLUSTER_32(0)) < 0) + break; + num_clusters++; + + } while (clu != CLUSTER_32(~0)); + + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters -= num_clusters; +} /* end of fat_free_cluster */ + +void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse) +{ + s32 num_clusters = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + int i; + sector_t sector; + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return; + + if (p_chain->size <= 0) { + printk(KERN_ERR "[EXFAT] free_cluster : skip free-req clu:%u, " + "because of zero-size truncation\n" + ,p_chain->dir); + return; + } + + __set_sb_dirty(sb); + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + do { + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) + break; + clu++; + + num_clusters++; + } while (num_clusters < p_chain->size); + } else { + do { + if (p_fs->dev_ejected) + break; + + if (do_relse) { + sector = START_SECTOR(clu); + for (i = 0; i < p_fs->sectors_per_clu; i++) + buf_release(sb, sector+i); + } + + if (clr_alloc_bitmap(sb, clu-2) != FFS_SUCCESS) + break; + + if (FAT_read(sb, clu, &clu) == -1) + break; + num_clusters++; + } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0))); + } + + if (p_fs->used_clusters != (u32) ~0) + p_fs->used_clusters -= num_clusters; +} /* end of exfat_free_cluster */ + +u32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain) +{ + u32 clu, next; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + clu += p_chain->size - 1; + } else { + while ((FAT_read(sb, clu, &next) == 0) && (next != CLUSTER_32(~0))) { + if (p_fs->dev_ejected) + break; + clu = next; + } + } + + return clu; +} /* end of find_last_cluster */ + +s32 count_num_clusters(struct super_block *sb, CHAIN_T *p_chain) +{ + int i, count = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0))) + return 0; + + clu = p_chain->dir; + + if (p_chain->flags == 0x03) { + count = p_chain->size; + } else { + for (i = 2; i < p_fs->num_clusters; i++) { + count++; + if (FAT_read(sb, clu, &clu) != 0) + return 0; + if (clu == CLUSTER_32(~0)) + break; + } + } + + return count; +} /* end of count_num_clusters */ + +s32 fat_count_used_clusters(struct super_block *sb) +{ + int i, count = 0; + u32 clu; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = 2; i < p_fs->num_clusters; i++) { + if (FAT_read(sb, i, &clu) != 0) + break; + if (clu != CLUSTER_32(0)) + count++; + } + + return count; +} /* end of fat_count_used_clusters */ + +s32 exfat_count_used_clusters(struct super_block *sb) +{ + int i, map_i, map_b, count = 0; + u8 k; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + map_i = map_b = 0; + + for (i = 2; i < p_fs->num_clusters; i += 8) { + k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); + count += used_bit[k]; + + if ((++map_b) >= p_bd->sector_size) { + map_i++; + map_b = 0; + } + } + + return count; +} /* end of exfat_count_used_clusters */ + +void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len) +{ + if (len == 0) + return; + + while (len > 1) { + if (FAT_write(sb, chain, chain+1) < 0) + break; + chain++; + len--; + } + FAT_write(sb, chain, CLUSTER_32(~0)); +} /* end of exfat_chain_cont_cluster */ + +/* + * Allocation Bitmap Management Functions + */ + +s32 load_alloc_bitmap(struct super_block *sb) +{ + int i, j, ret; + u32 map_size; + u32 type; + sector_t sector; + CHAIN_T clu; + BMAP_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu.dir = p_fs->root_dir; + clu.flags = 0x01; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < p_fs->dentries_per_clu; i++) { + ep = (BMAP_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if (type != TYPE_BITMAP) + continue; + + if (ep->flags == 0x0) { + p_fs->map_clu = GET32_A(ep->start_clu); + map_size = (u32) GET64_A(ep->size); + + p_fs->map_sectors = ((map_size-1) >> p_bd->sector_size_bits) + 1; + + p_fs->vol_amap = (struct buffer_head **) kmalloc(sizeof(struct buffer_head *) * p_fs->map_sectors, GFP_KERNEL); + if (p_fs->vol_amap == NULL) + return FFS_MEMORYERR; + + sector = START_SECTOR(p_fs->map_clu); + + for (j = 0; j < p_fs->map_sectors; j++) { + p_fs->vol_amap[j] = NULL; + ret = sector_read(sb, sector+j, &(p_fs->vol_amap[j]), 1); + if (ret != FFS_SUCCESS) { + /* release all buffers and free vol_amap */ + i = 0; + while (i < j) + brelse(p_fs->vol_amap[i++]); + + if (p_fs->vol_amap) + kfree(p_fs->vol_amap); + p_fs->vol_amap = NULL; + return ret; + } + } + + p_fs->pbr_bh = NULL; + return FFS_SUCCESS; + } + } + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + + return FFS_FORMATERR; +} /* end of load_alloc_bitmap */ + +void free_alloc_bitmap(struct super_block *sb) +{ + int i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + brelse(p_fs->pbr_bh); + + for (i = 0; i < p_fs->map_sectors; i++) + __brelse(p_fs->vol_amap[i]); + + if (p_fs->vol_amap) + kfree(p_fs->vol_amap); + p_fs->vol_amap = NULL; +} /* end of free_alloc_bitmap */ + +s32 set_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, b; + sector_t sector; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + i = clu >> (p_bd->sector_size_bits + 3); + b = clu & ((p_bd->sector_size << 3) - 1); + + sector = START_SECTOR(p_fs->map_clu) + i; + + exfat_bitmap_set((u8 *) p_fs->vol_amap[i]->b_data, b); + + return sector_write(sb, sector, p_fs->vol_amap[i], 0); +} /* end of set_alloc_bitmap */ + +s32 clr_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, b; + sector_t sector; +#ifdef CONFIG_EXFAT_DISCARD + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_mount_options *opts = &sbi->options; + int ret; +#endif /* CONFIG_EXFAT_DISCARD */ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + i = clu >> (p_bd->sector_size_bits + 3); + b = clu & ((p_bd->sector_size << 3) - 1); + + sector = START_SECTOR(p_fs->map_clu) + i; + + exfat_bitmap_clear((u8 *) p_fs->vol_amap[i]->b_data, b); + + return sector_write(sb, sector, p_fs->vol_amap[i], 0); + +#ifdef CONFIG_EXFAT_DISCARD + if (opts->discard) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits)); +#else + ret = sb_issue_discard(sb, START_SECTOR(clu), (1 << p_fs->sectors_per_clu_bits), GFP_NOFS, 0); +#endif + if (ret == -EOPNOTSUPP) { + printk(KERN_WARNING "discard not supported by device, disabling"); + opts->discard = 0; + } + } +#endif /* CONFIG_EXFAT_DISCARD */ +} /* end of clr_alloc_bitmap */ + +u32 test_alloc_bitmap(struct super_block *sb, u32 clu) +{ + int i, map_i, map_b; + u32 clu_base, clu_free; + u8 k, clu_mask; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu_base = (clu & ~(0x7)) + 2; + clu_mask = (1 << (clu - clu_base + 2)) - 1; + + map_i = clu >> (p_bd->sector_size_bits + 3); + map_b = (clu >> 3) & p_bd->sector_size_mask; + + for (i = 2; i < p_fs->num_clusters; i += 8) { + k = *(((u8 *) p_fs->vol_amap[map_i]->b_data) + map_b); + if (clu_mask > 0) { + k |= clu_mask; + clu_mask = 0; + } + if (k < 0xFF) { + clu_free = clu_base + free_bit[k]; + if (clu_free < p_fs->num_clusters) + return clu_free; + } + clu_base += 8; + + if (((++map_b) >= p_bd->sector_size) || (clu_base >= p_fs->num_clusters)) { + if ((++map_i) >= p_fs->map_sectors) { + clu_base = 2; + map_i = 0; + } + map_b = 0; + } + } + + return CLUSTER_32(~0); +} /* end of test_alloc_bitmap */ + +void sync_alloc_bitmap(struct super_block *sb) +{ + int i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_fs->vol_amap == NULL) + return; + + for (i = 0; i < p_fs->map_sectors; i++) + sync_dirty_buffer(p_fs->vol_amap[i]); +} /* end of sync_alloc_bitmap */ + +/* + * Upcase table Management Functions + */ +s32 __load_upcase_table(struct super_block *sb, sector_t sector, u32 num_sectors, u32 utbl_checksum) +{ + int i, ret = FFS_ERROR; + u32 j; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + struct buffer_head *tmp_bh = NULL; + sector_t end_sector = num_sectors + sector; + + u8 skip = FALSE; + u32 index = 0; + u16 uni = 0; + u16 **upcase_table; + + u32 checksum = 0; + + upcase_table = p_fs->vol_utbl = (u16 **) kmalloc(UTBL_COL_COUNT * sizeof(u16 *), GFP_KERNEL); + if (upcase_table == NULL) + return FFS_MEMORYERR; + memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); + + while (sector < end_sector) { + ret = sector_read(sb, sector, &tmp_bh, 1); + if (ret != FFS_SUCCESS) { + DPRINTK("sector read (0x%llX)fail\n", (unsigned long long)sector); + goto error; + } + sector++; + + for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) { + uni = GET16(((u8 *) tmp_bh->b_data)+i); + + checksum = ((checksum & 1) ? 0x80000000 : 0) + (checksum >> 1) + *(((u8 *) tmp_bh->b_data)+i); + checksum = ((checksum & 1) ? 0x80000000 : 0) + (checksum >> 1) + *(((u8 *) tmp_bh->b_data)+(i+1)); + + if (skip) { + DPRINTK("skip from 0x%X ", index); + index += uni; + DPRINTK("to 0x%X (amount of 0x%X)\n", index, uni); + skip = FALSE; + } else if (uni == index) + index++; + else if (uni == 0xFFFF) + skip = TRUE; + else { /* uni != index , uni != 0xFFFF */ + u16 col_index = get_col_index(index); + + if (upcase_table[col_index] == NULL) { + DPRINTK("alloc = 0x%X\n", col_index); + upcase_table[col_index] = (u16 *) kmalloc(UTBL_ROW_COUNT * sizeof(u16), GFP_KERNEL); + if (upcase_table[col_index] == NULL) { + ret = FFS_MEMORYERR; + goto error; + } + + for (j = 0; j < UTBL_ROW_COUNT; j++) + upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; + } + + upcase_table[col_index][get_row_index(index)] = uni; + index++; + } + } + } + if (index >= 0xFFFF && utbl_checksum == checksum) { + if (tmp_bh) + brelse(tmp_bh); + return FFS_SUCCESS; + } + ret = FFS_ERROR; +error: + if (tmp_bh) + brelse(tmp_bh); + free_upcase_table(sb); + return ret; +} + +s32 __load_default_upcase_table(struct super_block *sb) +{ + int i, ret = FFS_ERROR; + u32 j; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + u8 skip = FALSE; + u32 index = 0; + u16 uni = 0; + u16 **upcase_table; + + upcase_table = p_fs->vol_utbl = (u16 **) kmalloc(UTBL_COL_COUNT * sizeof(u16 *), GFP_KERNEL); + if (upcase_table == NULL) + return FFS_MEMORYERR; + memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); + + for (i = 0; index <= 0xFFFF && i < NUM_UPCASE*2; i += 2) { + uni = GET16(uni_upcase + i); + if (skip) { + DPRINTK("skip from 0x%X ", index); + index += uni; + DPRINTK("to 0x%X (amount of 0x%X)\n", index, uni); + skip = FALSE; + } else if (uni == index) + index++; + else if (uni == 0xFFFF) + skip = TRUE; + else { /* uni != index , uni != 0xFFFF */ + u16 col_index = get_col_index(index); + + if (upcase_table[col_index] == NULL) { + DPRINTK("alloc = 0x%X\n", col_index); + upcase_table[col_index] = (u16 *) kmalloc(UTBL_ROW_COUNT * sizeof(u16), GFP_KERNEL); + if (upcase_table[col_index] == NULL) { + ret = FFS_MEMORYERR; + goto error; + } + + for (j = 0; j < UTBL_ROW_COUNT; j++) + upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j; + } + + upcase_table[col_index][get_row_index(index)] = uni; + index++; + } + } + + if (index >= 0xFFFF) + return FFS_SUCCESS; + +error: + /* FATAL error: default upcase table has error */ + free_upcase_table(sb); + return ret; +} + +s32 load_upcase_table(struct super_block *sb) +{ + int i; + u32 tbl_clu, tbl_size; + sector_t sector; + u32 type, num_sectors; + CHAIN_T clu; + CASE_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + clu.dir = p_fs->root_dir; + clu.flags = 0x01; + + if (p_fs->dev_ejected) + return FFS_MEDIAERR; + + while (clu.dir != CLUSTER_32(~0)) { + for (i = 0; i < p_fs->dentries_per_clu; i++) { + ep = (CASE_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if (type != TYPE_UPCASE) + continue; + + tbl_clu = GET32_A(ep->start_clu); + tbl_size = (u32) GET64_A(ep->size); + + sector = START_SECTOR(tbl_clu); + num_sectors = ((tbl_size-1) >> p_bd->sector_size_bits) + 1; + if (__load_upcase_table(sb, sector, num_sectors, GET32_A(ep->checksum)) != FFS_SUCCESS) + break; + else + return FFS_SUCCESS; + } + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + /* load default upcase table */ + return __load_default_upcase_table(sb); +} /* end of load_upcase_table */ + +void free_upcase_table(struct super_block *sb) +{ + u32 i; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + u16 **upcase_table; + + upcase_table = p_fs->vol_utbl; + for (i = 0; i < UTBL_COL_COUNT; i++) { + if (upcase_table[i]) + kfree(upcase_table[i]); + } + + if (p_fs->vol_utbl) + kfree(p_fs->vol_utbl); + p_fs->vol_utbl = NULL; +} /* end of free_upcase_table */ + +/* + * Directory Entry Management Functions + */ + +u32 fat_get_entry_type(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + if (*(ep->name) == 0x0) + return TYPE_UNUSED; + + else if (*(ep->name) == 0xE5) + return TYPE_DELETED; + + else if (ep->attr == ATTR_EXTEND) + return TYPE_EXTEND; + + else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_VOLUME) + return TYPE_VOLUME; + + else if ((ep->attr & (ATTR_SUBDIR|ATTR_VOLUME)) == ATTR_SUBDIR) + return TYPE_DIR; + + return TYPE_FILE; +} /* end of fat_get_entry_type */ + +u32 exfat_get_entry_type(DENTRY_T *p_entry) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + if (ep->type == 0x0) { + return TYPE_UNUSED; + } else if (ep->type < 0x80) { + return TYPE_DELETED; + } else if (ep->type == 0x80) { + return TYPE_INVALID; + } else if (ep->type < 0xA0) { + if (ep->type == 0x81) { + return TYPE_BITMAP; + } else if (ep->type == 0x82) { + return TYPE_UPCASE; + } else if (ep->type == 0x83) { + return TYPE_VOLUME; + } else if (ep->type == 0x85) { + if (GET16_A(ep->attr) & ATTR_SUBDIR) + return TYPE_DIR; + else + return TYPE_FILE; + } + return TYPE_CRITICAL_PRI; + } else if (ep->type < 0xC0) { + if (ep->type == 0xA0) + return TYPE_GUID; + else if (ep->type == 0xA1) + return TYPE_PADDING; + else if (ep->type == 0xA2) + return TYPE_ACLTAB; + return TYPE_BENIGN_PRI; + } else if (ep->type < 0xE0) { + if (ep->type == 0xC0) + return TYPE_STREAM; + else if (ep->type == 0xC1) + return TYPE_EXTEND; + else if (ep->type == 0xC2) + return TYPE_ACL; + return TYPE_CRITICAL_SEC; + } + + return TYPE_BENIGN_SEC; +} /* end of exfat_get_entry_type */ + +void fat_set_entry_type(DENTRY_T *p_entry, u32 type) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + if (type == TYPE_UNUSED) + *(ep->name) = 0x0; + + else if (type == TYPE_DELETED) + *(ep->name) = 0xE5; + + else if (type == TYPE_EXTEND) + ep->attr = ATTR_EXTEND; + + else if (type == TYPE_DIR) + ep->attr = ATTR_SUBDIR; + + else if (type == TYPE_FILE) + ep->attr = ATTR_ARCHIVE; + + else if (type == TYPE_SYMLINK) + ep->attr = ATTR_ARCHIVE | ATTR_SYMLINK; +} /* end of fat_set_entry_type */ + +void exfat_set_entry_type(DENTRY_T *p_entry, u32 type) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + if (type == TYPE_UNUSED) { + ep->type = 0x0; + } else if (type == TYPE_DELETED) { + ep->type &= ~0x80; + } else if (type == TYPE_STREAM) { + ep->type = 0xC0; + } else if (type == TYPE_EXTEND) { + ep->type = 0xC1; + } else if (type == TYPE_BITMAP) { + ep->type = 0x81; + } else if (type == TYPE_UPCASE) { + ep->type = 0x82; + } else if (type == TYPE_VOLUME) { + ep->type = 0x83; + } else if (type == TYPE_DIR) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_SUBDIR); + } else if (type == TYPE_FILE) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_ARCHIVE); + } else if (type == TYPE_SYMLINK) { + ep->type = 0x85; + SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK); + } +} /* end of exfat_set_entry_type */ + +u32 fat_get_entry_attr(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return (u32) ep->attr; +} /* end of fat_get_entry_attr */ + +u32 exfat_get_entry_attr(DENTRY_T *p_entry) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + return (u32) GET16_A(ep->attr); +} /* end of exfat_get_entry_attr */ + +void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + ep->attr = (u8) attr; +} /* end of fat_set_entry_attr */ + +void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr) +{ + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + SET16_A(ep->attr, (u16) attr); +} /* end of exfat_set_entry_attr */ + +u8 fat_get_entry_flag(DENTRY_T *p_entry) +{ + return 0x01; +} /* end of fat_get_entry_flag */ + +u8 exfat_get_entry_flag(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return ep->flags; +} /* end of exfat_get_entry_flag */ + +void fat_set_entry_flag(DENTRY_T *p_entry, u8 flags) +{ +} /* end of fat_set_entry_flag */ + +void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flags) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + ep->flags = flags; +} /* end of exfat_set_entry_flag */ + +u32 fat_get_entry_clu0(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return ((u32) GET16_A(ep->start_clu_hi) << 16) | GET16_A(ep->start_clu_lo); +} /* end of fat_get_entry_clu0 */ + +u32 exfat_get_entry_clu0(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return GET32_A(ep->start_clu); +} /* end of exfat_get_entry_clu0 */ + +void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); + SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); +} /* end of fat_set_entry_clu0 */ + +void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + SET32_A(ep->start_clu, start_clu); +} /* end of exfat_set_entry_clu0 */ + +u64 fat_get_entry_size(DENTRY_T *p_entry) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + return (u64) GET32_A(ep->size); +} /* end of fat_get_entry_size */ + +u64 exfat_get_entry_size(DENTRY_T *p_entry) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + return GET64_A(ep->valid_size); +} /* end of exfat_get_entry_size */ + +void fat_set_entry_size(DENTRY_T *p_entry, u64 size) +{ + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + SET32_A(ep->size, (u32) size); +} /* end of fat_set_entry_size */ + +void exfat_set_entry_size(DENTRY_T *p_entry, u64 size) +{ + STRM_DENTRY_T *ep = (STRM_DENTRY_T *) p_entry; + SET64_A(ep->valid_size, size); + SET64_A(ep->size, size); +} /* end of exfat_set_entry_size */ + +void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t = 0x00, d = 0x21; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + switch (mode) { + case TM_CREATE: + t = GET16_A(ep->create_time); + d = GET16_A(ep->create_date); + break; + case TM_MODIFY: + t = GET16_A(ep->modify_time); + d = GET16_A(ep->modify_date); + break; + } + + tp->sec = (t & 0x001F) << 1; + tp->min = (t >> 5) & 0x003F; + tp->hour = (t >> 11); + tp->day = (d & 0x001F); + tp->mon = (d >> 5) & 0x000F; + tp->year = (d >> 9); +} /* end of fat_get_entry_time */ + +void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t = 0x00, d = 0x21; + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + switch (mode) { + case TM_CREATE: + t = GET16_A(ep->create_time); + d = GET16_A(ep->create_date); + break; + case TM_MODIFY: + t = GET16_A(ep->modify_time); + d = GET16_A(ep->modify_date); + break; + case TM_ACCESS: + t = GET16_A(ep->access_time); + d = GET16_A(ep->access_date); + break; + } + + tp->sec = (t & 0x001F) << 1; + tp->min = (t >> 5) & 0x003F; + tp->hour = (t >> 11); + tp->day = (d & 0x001F); + tp->mon = (d >> 5) & 0x000F; + tp->year = (d >> 9); +} /* end of exfat_get_entry_time */ + +void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t, d; + DOS_DENTRY_T *ep = (DOS_DENTRY_T *) p_entry; + + t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); + d = (tp->year << 9) | (tp->mon << 5) | tp->day; + + switch (mode) { + case TM_CREATE: + SET16_A(ep->create_time, t); + SET16_A(ep->create_date, d); + break; + case TM_MODIFY: + SET16_A(ep->modify_time, t); + SET16_A(ep->modify_date, d); + break; + } +} /* end of fat_set_entry_time */ + +void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode) +{ + u16 t, d; + FILE_DENTRY_T *ep = (FILE_DENTRY_T *) p_entry; + + t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1); + d = (tp->year << 9) | (tp->mon << 5) | tp->day; + + switch (mode) { + case TM_CREATE: + SET16_A(ep->create_time, t); + SET16_A(ep->create_date, d); + break; + case TM_MODIFY: + SET16_A(ep->modify_time, t); + SET16_A(ep->modify_date, d); + break; + case TM_ACCESS: + SET16_A(ep->access_time, t); + SET16_A(ep->access_date, d); + break; + } +} /* end of exfat_set_entry_time */ + +s32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size) +{ + sector_t sector; + DOS_DENTRY_T *dos_ep; + + dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!dos_ep) + return FFS_MEDIAERR; + + init_dos_entry(dos_ep, type, start_clu); + buf_modify(sb, sector); + + return FFS_SUCCESS; +} /* end of fat_init_dir_entry */ + +s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size) +{ + sector_t sector; + u8 flags; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + + flags = (type == TYPE_FILE) ? 0x01 : 0x03; + + /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */ + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return FFS_MEDIAERR; + + strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, §or); + if (!strm_ep) + return FFS_MEDIAERR; + + init_file_entry(file_ep, type); + buf_modify(sb, sector); + + init_strm_entry(strm_ep, flags, start_clu, size); + buf_modify(sb, sector); + + return FFS_SUCCESS; +} /* end of exfat_init_dir_entry */ + +s32 fat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i; + sector_t sector; + u8 chksum; + u16 *uniname = p_uniname->name; + DOS_DENTRY_T *dos_ep; + EXT_DENTRY_T *ext_ep; + + dos_ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!dos_ep) + return FFS_MEDIAERR; + + dos_ep->lcase = p_dosname->name_case; + memcpy(dos_ep->name, p_dosname->name, DOS_NAME_LENGTH); + buf_modify(sb, sector); + + if ((--num_entries) > 0) { + chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); + + for (i = 1; i < num_entries; i++) { + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ext_ep) + return FFS_MEDIAERR; + + init_ext_entry(ext_ep, i, chksum, uniname); + buf_modify(sb, sector); + uniname += 13; + } + + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ext_ep) + return FFS_MEDIAERR; + + init_ext_entry(ext_ep, i+0x40, chksum, uniname); + buf_modify(sb, sector); + } + + return FFS_SUCCESS; +} /* end of fat_init_ext_entry */ + +s32 exfat_init_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i; + sector_t sector; + u16 *uniname = p_uniname->name; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + NAME_DENTRY_T *name_ep; + + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return FFS_MEDIAERR; + + file_ep->num_ext = (u8)(num_entries - 1); + buf_modify(sb, sector); + + strm_ep = (STRM_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+1, §or); + if (!strm_ep) + return FFS_MEDIAERR; + + strm_ep->name_len = p_uniname->name_len; + SET16_A(strm_ep->name_hash, p_uniname->name_hash); + buf_modify(sb, sector); + + for (i = 2; i < num_entries; i++) { + name_ep = (NAME_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry+i, §or); + if (!name_ep) + return FFS_MEDIAERR; + + init_name_entry(name_ep, uniname); + buf_modify(sb, sector); + uniname += 15; + } + + update_dir_checksum(sb, p_dir, entry); + + return FFS_SUCCESS; +} /* end of exfat_init_ext_entry */ + +void init_dos_entry(DOS_DENTRY_T *ep, u32 type, u32 start_clu) +{ + TIMESTAMP_T tm, *tp; + + fat_set_entry_type((DENTRY_T *) ep, type); + SET16_A(ep->start_clu_lo, CLUSTER_16(start_clu)); + SET16_A(ep->start_clu_hi, CLUSTER_16(start_clu >> 16)); + SET32_A(ep->size, 0); + + tp = tm_current(&tm); + fat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); + fat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); + SET16_A(ep->access_date, 0); + ep->create_time_ms = 0; +} /* end of init_dos_entry */ + +void init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uniname) +{ + int i; + u8 end = FALSE; + + fat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND); + ep->order = (u8) order; + ep->sysid = 0; + ep->checksum = chksum; + SET16_A(ep->start_clu, 0); + + for (i = 0; i < 10; i += 2) { + if (!end) { + SET16(ep->unicode_0_4+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16(ep->unicode_0_4+i, 0xFFFF); + } + } + + for (i = 0; i < 12; i += 2) { + if (!end) { + SET16_A(ep->unicode_5_10+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16_A(ep->unicode_5_10+i, 0xFFFF); + } + } + + for (i = 0; i < 4; i += 2) { + if (!end) { + SET16_A(ep->unicode_11_12+i, *uniname); + if (*uniname == 0x0) + end = TRUE; + else + uniname++; + } else { + SET16_A(ep->unicode_11_12+i, 0xFFFF); + } + } +} /* end of init_ext_entry */ + +void init_file_entry(FILE_DENTRY_T *ep, u32 type) +{ + TIMESTAMP_T tm, *tp; + + exfat_set_entry_type((DENTRY_T *) ep, type); + + tp = tm_current(&tm); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_CREATE); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_MODIFY); + exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS); + ep->create_time_ms = 0; + ep->modify_time_ms = 0; + ep->access_time_ms = 0; +} /* end of init_file_entry */ + +void init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size) +{ + exfat_set_entry_type((DENTRY_T *) ep, TYPE_STREAM); + ep->flags = flags; + SET32_A(ep->start_clu, start_clu); + SET64_A(ep->valid_size, size); + SET64_A(ep->size, size); +} /* end of init_strm_entry */ + +void init_name_entry(NAME_DENTRY_T *ep, u16 *uniname) +{ + int i; + + exfat_set_entry_type((DENTRY_T *) ep, TYPE_EXTEND); + ep->flags = 0x0; + + for (i = 0; i < 30; i++, i++) { + SET16_A(ep->unicode_0_14+i, *uniname); + if (*uniname == 0x0) + break; + uniname++; + } +} /* end of init_name_entry */ + +void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries) +{ + int i; + sector_t sector; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = num_entries-1; i >= order; i--) { + ep = get_entry_in_dir(sb, p_dir, entry-i, §or); + if (!ep) + return; + + p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); + buf_modify(sb, sector); + } +} /* end of fat_delete_dir_entry */ + +void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries) +{ + int i; + sector_t sector; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = order; i < num_entries; i++) { + ep = get_entry_in_dir(sb, p_dir, entry+i, §or); + if (!ep) + return; + + p_fs->fs_func->set_entry_type(ep, TYPE_DELETED); + buf_modify(sb, sector); + } +} /* end of exfat_delete_dir_entry */ + +void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry) +{ + int i, num_entries; + sector_t sector; + u16 chksum; + FILE_DENTRY_T *file_ep; + DENTRY_T *ep; + + file_ep = (FILE_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, §or); + if (!file_ep) + return; + + buf_lock(sb, sector); + + num_entries = (s32) file_ep->num_ext + 1; + chksum = calc_checksum_2byte((void *) file_ep, DENTRY_SIZE, 0, CS_DIR_ENTRY); + + for (i = 1; i < num_entries; i++) { + ep = get_entry_in_dir(sb, p_dir, entry+i, NULL); + if (!ep) { + buf_unlock(sb, sector); + return; + } + + chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, CS_DEFAULT); + } + + SET16_A(file_ep->checksum, chksum); + buf_modify(sb, sector); + buf_unlock(sb, sector); +} /* end of update_dir_checksum */ + +void update_dir_checksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es) +{ + DENTRY_T *ep; + u16 chksum = 0; + s32 chksum_type = CS_DIR_ENTRY, i; + + ep = (DENTRY_T *)&(es->__buf); + for (i = 0; i < es->num_entries; i++) { + DPRINTK("update_dir_checksum_with_entry_set ep %p\n", ep); + chksum = calc_checksum_2byte((void *) ep, DENTRY_SIZE, chksum, chksum_type); + ep++; + chksum_type = CS_DEFAULT; + } + + ep = (DENTRY_T *)&(es->__buf); + SET16_A(((FILE_DENTRY_T *)ep)->checksum, chksum); + write_whole_entry_set(sb, es); +} + +static s32 _walk_fat_chain(struct super_block *sb, CHAIN_T *p_dir, s32 byte_offset, u32 *clu) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + s32 clu_offset; + u32 cur_clu; + + clu_offset = byte_offset >> p_fs->cluster_size_bits; + cur_clu = p_dir->dir; + + if (p_dir->flags == 0x03) { + cur_clu += clu_offset; + } else { + while (clu_offset > 0) { + if (FAT_read(sb, cur_clu, &cur_clu) == -1) + return FFS_MEDIAERR; + clu_offset--; + } + } + + if (clu) + *clu = cur_clu; + return FFS_SUCCESS; +} +s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector, s32 *offset) +{ + s32 off, ret; + u32 clu = 0; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + off = entry << DENTRY_SIZE_BITS; + + if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + *offset = off & p_bd->sector_size_mask; + *sector = off >> p_bd->sector_size_bits; + *sector += p_fs->root_start_sector; + } else { + ret = _walk_fat_chain(sb, p_dir, off, &clu); + if (ret != FFS_SUCCESS) + return ret; + + off &= p_fs->cluster_size - 1; /* byte offset in cluster */ + + *offset = off & p_bd->sector_size_mask; /* byte offset in sector */ + *sector = off >> p_bd->sector_size_bits; /* sector offset in cluster */ + *sector += START_SECTOR(clu); + } + return FFS_SUCCESS; +} /* end of find_location */ + +DENTRY_T *get_entry_with_sector(struct super_block *sb, sector_t sector, s32 offset) +{ + u8 *buf; + + buf = buf_getblk(sb, sector); + + if (buf == NULL) + return NULL; + + return (DENTRY_T *)(buf + offset); +} /* end of get_entry_with_sector */ + +DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector) +{ + s32 off; + sector_t sec; + u8 *buf; + + if (find_location(sb, p_dir, entry, &sec, &off) != FFS_SUCCESS) + return NULL; + + buf = buf_getblk(sb, sec); + + if (buf == NULL) + return NULL; + + if (sector != NULL) + *sector = sec; + return (DENTRY_T *)(buf + off); +} /* end of get_entry_in_dir */ + + +/* returns a set of dentries for a file or dir. + * Note that this is a copy (dump) of dentries so that user should call write_entry_set() + * to apply changes made in this entry set to the real device. + * in: + * sb+p_dir+entry: indicates a file/dir + * type: specifies how many dentries should be included. + * out: + * file_ep: will point the first dentry(= file dentry) on success + * return: + * pointer of entry set on success, + * NULL on failure. + */ + +#define ES_MODE_STARTED 0 +#define ES_MODE_GET_FILE_ENTRY 1 +#define ES_MODE_GET_STRM_ENTRY 2 +#define ES_MODE_GET_NAME_ENTRY 3 +#define ES_MODE_GET_CRITICAL_SEC_ENTRY 4 +ENTRY_SET_CACHE_T *get_entry_set_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep) +{ + s32 off, ret, byte_offset; + u32 clu = 0; + sector_t sec; + u32 entry_type; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + ENTRY_SET_CACHE_T *es = NULL; + DENTRY_T *ep, *pos; + u8 *buf; + u8 num_entries; + s32 mode = ES_MODE_STARTED; + + DPRINTK("get_entry_set_in_dir entered\n"); + DPRINTK("p_dir dir %u flags %x size %d\n", p_dir->dir, p_dir->flags, p_dir->size); + + byte_offset = entry << DENTRY_SIZE_BITS; + ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); + if (ret != FFS_SUCCESS) + return NULL; + + + byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ + + off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */ + sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + sec += START_SECTOR(clu); + + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + + + ep = (DENTRY_T *)(buf + off); + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type != TYPE_FILE) + && (entry_type != TYPE_DIR)) + goto err_out; + + if (type == ES_ALL_ENTRIES) + num_entries = ((FILE_DENTRY_T *)ep)->num_ext+1; + else + num_entries = type; + + DPRINTK("trying to kmalloc %zx bytes for %d entries\n", offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), num_entries); + es = kmalloc(offsetof(ENTRY_SET_CACHE_T, __buf) + (num_entries) * sizeof(DENTRY_T), GFP_KERNEL); + if (es == NULL) + goto err_out; + + es->num_entries = num_entries; + es->sector = sec; + es->offset = off; + es->alloc_flag = p_dir->flags; + + pos = (DENTRY_T *) &(es->__buf); + + while(num_entries) { + /* instead of copying whole sector, we will check every entry. + * this will provide minimum stablity and consistancy. + */ + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) + goto err_out; + + switch (mode) { + case ES_MODE_STARTED: + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) + mode = ES_MODE_GET_FILE_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_FILE_ENTRY: + if (entry_type == TYPE_STREAM) + mode = ES_MODE_GET_STRM_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_STRM_ENTRY: + if (entry_type == TYPE_EXTEND) + mode = ES_MODE_GET_NAME_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_NAME_ENTRY: + if (entry_type == TYPE_EXTEND) + break; + else if (entry_type == TYPE_STREAM) + goto err_out; + else if (entry_type & TYPE_CRITICAL_SEC) + mode = ES_MODE_GET_CRITICAL_SEC_ENTRY; + else + goto err_out; + break; + case ES_MODE_GET_CRITICAL_SEC_ENTRY: + if ((entry_type == TYPE_EXTEND) || (entry_type == TYPE_STREAM)) + goto err_out; + else if ((entry_type & TYPE_CRITICAL_SEC) != TYPE_CRITICAL_SEC) + goto err_out; + break; + } + + memcpy(pos, ep, sizeof(DENTRY_T)); + + if (--num_entries == 0) + break; + + if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) < (off & p_bd->sector_size_mask)) { + /* get the next sector */ + if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { + if (es->alloc_flag == 0x03) { + clu++; + } else { + if (FAT_read(sb, clu, &clu) == -1) + goto err_out; + } + sec = START_SECTOR(clu); + } else { + sec++; + } + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + off = 0; + ep = (DENTRY_T *)(buf); + } else { + ep++; + off += DENTRY_SIZE; + } + pos++; + } + + if (file_ep) + *file_ep = (DENTRY_T *)&(es->__buf); + + DPRINTK("es sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", + (unsigned long long)es->sector, es->offset, es->alloc_flag, + es->num_entries, &(es->__buf)); + DPRINTK("get_entry_set_in_dir exited %p\n", es); + return es; +err_out: + DPRINTK("get_entry_set_in_dir exited NULL (es %p)\n", es); + if (es) + kfree(es); + return NULL; +} + +void release_entry_set(ENTRY_SET_CACHE_T *es) +{ + DPRINTK("release_entry_set %p\n", es); + if (es) + kfree(es); +} + + +static s32 __write_partial_entries_in_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es, sector_t sec, s32 off, u32 count) +{ + s32 num_entries, buf_off = (off - es->offset); + u32 remaining_byte_in_sector, copy_entries; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + u32 clu; + u8 *buf, *esbuf = (u8 *)&(es->__buf); + + DPRINTK("__write_partial_entries_in_entry_set entered\n"); + DPRINTK("es %p sec %llu off %d count %d\n", es, (unsigned long long)sec, off, count); + num_entries = count; + + while (num_entries) { + /* white per sector base */ + remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off; + copy_entries = MIN(remaining_byte_in_sector >> DENTRY_SIZE_BITS , num_entries); + buf = buf_getblk(sb, sec); + if (buf == NULL) + goto err_out; + DPRINTK("es->buf %p buf_off %u\n", esbuf, buf_off); + DPRINTK("copying %d entries from %p to sector %llu\n", copy_entries, (esbuf + buf_off), (unsigned long long)sec); + memcpy(buf + off, esbuf + buf_off, copy_entries << DENTRY_SIZE_BITS); + buf_modify(sb, sec); + num_entries -= copy_entries; + + if (num_entries) { + /* get next sector */ + if (IS_LAST_SECTOR_IN_CLUSTER(sec)) { + clu = GET_CLUSTER_FROM_SECTOR(sec); + if (es->alloc_flag == 0x03) { + clu++; + } else { + if (FAT_read(sb, clu, &clu) == -1) + goto err_out; + } + sec = START_SECTOR(clu); + } else { + sec++; + } + off = 0; + buf_off += copy_entries << DENTRY_SIZE_BITS; + } + } + + DPRINTK("__write_partial_entries_in_entry_set exited successfully\n"); + return FFS_SUCCESS; +err_out: + DPRINTK("__write_partial_entries_in_entry_set failed\n"); + return FFS_ERROR; +} + +/* write back all entries in entry set */ +s32 write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es) +{ + return __write_partial_entries_in_entry_set(sb, es, es->sector, es->offset, es->num_entries); +} + +/* write back some entries in entry set */ +s32 write_partial_entries_in_entry_set (struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, u32 count) +{ + s32 ret, byte_offset, off; + u32 clu=0; + sector_t sec; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + CHAIN_T dir; + + /* vaidity check */ + if (ep + count > ((DENTRY_T *)&(es->__buf)) + es->num_entries) + return FFS_ERROR; + + dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector); + dir.flags = es->alloc_flag; + dir.size = 0xffffffff; /* XXX */ + + byte_offset = (es->sector - START_SECTOR(dir.dir)) << p_bd->sector_size_bits; + byte_offset += ((void **)ep - &(es->__buf)) + es->offset; + + ret =_walk_fat_chain(sb, &dir, byte_offset, &clu); + if (ret != FFS_SUCCESS) + return ret; + byte_offset &= p_fs->cluster_size - 1; /* byte offset in cluster */ + off = byte_offset & p_bd->sector_size_mask; /* byte offset in sector */ + sec = byte_offset >> p_bd->sector_size_bits; /* sector offset in cluster */ + sec += START_SECTOR(clu); + return __write_partial_entries_in_entry_set(sb, es, sec, off, count); +} + +/* search EMPTY CONTINUOUS "num_entries" entries */ +s32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, s32 num_entries) +{ + int i, dentry, num_empty = 0; + s32 dentries_per_clu; + u32 type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + if (p_fs->hint_uentry.dir == p_dir->dir) { + if (p_fs->hint_uentry.entry == -1) + return -1; + + clu.dir = p_fs->hint_uentry.clu.dir; + clu.size = p_fs->hint_uentry.clu.size; + clu.flags = p_fs->hint_uentry.clu.flags; + + dentry = p_fs->hint_uentry.entry; + } else { + p_fs->hint_uentry.entry = -1; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + dentry = 0; + } + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + i = dentry % dentries_per_clu; + else + i = dentry & (dentries_per_clu-1); + + for (; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -1; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) { + num_empty++; + if (p_fs->hint_uentry.entry == -1) { + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = dentry; + + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = clu.size; + p_fs->hint_uentry.clu.flags = clu.flags; + } + } else if (type == TYPE_DELETED) { + num_empty++; + } else { + num_empty = 0; + } + + if (num_empty >= num_entries) { + p_fs->hint_uentry.dir = CLUSTER_32(~0); + p_fs->hint_uentry.entry = -1; + + if (p_fs->vol_type == EXFAT) + return dentry - (num_entries-1); + else + return dentry; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -1; + } + } + + return -1; +} /* end of search_deleted_or_unused_entry */ + +s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries) +{ + s32 ret, dentry; + u32 last_clu; + sector_t sector; + u64 size = 0; + CHAIN_T clu; + DENTRY_T *ep = NULL; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + return search_deleted_or_unused_entry(sb, p_dir, num_entries); + + while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) { + if (p_fs->dev_ejected) + break; + + if (p_fs->vol_type == EXFAT) { + if (p_dir->dir != p_fs->root_dir) + size = i_size_read(inode); + } + + last_clu = find_last_cluster(sb, p_dir); + clu.dir = last_clu + 1; + clu.size = 0; + clu.flags = p_dir->flags; + + /* (1) allocate a cluster */ + ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); + if (ret < 1) + return -1; + + if (clear_cluster(sb, clu.dir) != FFS_SUCCESS) + return -1; + + /* (2) append to the FAT chain */ + if (clu.flags != p_dir->flags) { + exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size); + p_dir->flags = 0x01; + p_fs->hint_uentry.clu.flags = 0x01; + } + if (clu.flags == 0x01) + if (FAT_write(sb, last_clu, clu.dir) < 0) + return -1; + + if (p_fs->hint_uentry.entry == -1) { + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = 0; + p_fs->hint_uentry.clu.flags = clu.flags; + } + p_fs->hint_uentry.clu.size++; + p_dir->size++; + + /* (3) update the directory entry */ + if (p_fs->vol_type == EXFAT) { + if (p_dir->dir != p_fs->root_dir) { + size += p_fs->cluster_size; + + ep = get_entry_in_dir(sb, &(fid->dir), fid->entry+1, §or); + if (!ep) + return -1; + p_fs->fs_func->set_entry_size(ep, size); + p_fs->fs_func->set_entry_flag(ep, p_dir->flags); + buf_modify(sb, sector); + + update_dir_checksum(sb, &(fid->dir), fid->entry); + } + } + + i_size_write(inode, i_size_read(inode)+p_fs->cluster_size); + EXFAT_I(inode)->mmu_private += p_fs->cluster_size; + EXFAT_I(inode)->fid.size += p_fs->cluster_size; + EXFAT_I(inode)->fid.flags = p_dir->flags; + inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9); + } + + return dentry; +} /* end of find_empty_entry */ + +/* return values of fat_find_dir_entry() + >= 0 : return dir entiry position with the name in dir + -1 : (root dir, ".") it is the root dir itself + -2 : entry with the name does not exist */ +s32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type) +{ + int i, dentry = 0, lossy = FALSE, len; + s32 order = 0, is_feasible_entry = TRUE, has_ext_entry = FALSE; + s32 dentries_per_clu; + u32 entry_type; + u16 entry_uniname[14], *uniname = NULL, unichar; + CHAIN_T clu; + DENTRY_T *ep; + DOS_DENTRY_T *dos_ep; + EXT_DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == p_fs->root_dir) { + if ((!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_CUR_DIR_NAME)) || + (!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_PAR_DIR_NAME))) + return -1; // special case, root directory itself + } + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++, dentry++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -2; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { + if ((type == TYPE_ALL) || (type == entry_type)) { + if (is_feasible_entry && has_ext_entry) + return dentry; + + dos_ep = (DOS_DENTRY_T *) ep; + if ((!lossy) && (!nls_dosname_cmp(sb, p_dosname->name, dos_ep->name))) + return dentry; + } + is_feasible_entry = TRUE; + has_ext_entry = FALSE; + } else if (entry_type == TYPE_EXTEND) { + if (is_feasible_entry) { + ext_ep = (EXT_DENTRY_T *) ep; + if (ext_ep->order > 0x40) { + order = (s32)(ext_ep->order - 0x40); + uniname = p_uniname->name + 13 * (order-1); + } else { + order = (s32) ext_ep->order; + uniname -= 13; + } + + len = extract_uni_name_from_ext_entry(ext_ep, entry_uniname, order); + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (nls_uniname_cmp(sb, uniname, entry_uniname)) + is_feasible_entry = FALSE; + + *(uniname+len) = unichar; + } + has_ext_entry = TRUE; + } else if (entry_type == TYPE_UNUSED) { + return -2; + } else { + is_feasible_entry = TRUE; + has_ext_entry = FALSE; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -2; + } + + return -2; +} /* end of fat_find_dir_entry */ + +/* return values of exfat_find_dir_entry() + >= 0 : return dir entiry position with the name in dir + -1 : (root dir, ".") it is the root dir itself + -2 : entry with the name does not exist */ +s32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type) +{ + int i = 0, dentry = 0, num_ext_entries = 0, len, step; + s32 order = 0, is_feasible_entry = FALSE; + s32 dentries_per_clu, num_empty = 0; + u32 entry_type; + u16 entry_uniname[16], *uniname = NULL, unichar; + CHAIN_T clu; + DENTRY_T *ep; + FILE_DENTRY_T *file_ep; + STRM_DENTRY_T *strm_ep; + NAME_DENTRY_T *name_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == p_fs->root_dir) { + if ((!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_CUR_DIR_NAME)) || + (!nls_uniname_cmp(sb, p_uniname->name, (u16 *) UNI_PAR_DIR_NAME))) + return -1; // special case, root directory itself + } + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + p_fs->hint_uentry.dir = p_dir->dir; + p_fs->hint_uentry.entry = -1; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + while (i < dentries_per_clu) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -2; + + entry_type = p_fs->fs_func->get_entry_type(ep); + step = 1; + + if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) { + is_feasible_entry = FALSE; + + if (p_fs->hint_uentry.entry == -1) { + num_empty++; + + if (num_empty == 1) { + p_fs->hint_uentry.clu.dir = clu.dir; + p_fs->hint_uentry.clu.size = clu.size; + p_fs->hint_uentry.clu.flags = clu.flags; + } + if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED)) + p_fs->hint_uentry.entry = dentry - (num_empty-1); + } + + if (entry_type == TYPE_UNUSED) + return -2; + } else { + num_empty = 0; + + if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) { + file_ep = (FILE_DENTRY_T *) ep; + if ((type == TYPE_ALL) || (type == entry_type)) { + num_ext_entries = file_ep->num_ext; + is_feasible_entry = TRUE; + } else { + is_feasible_entry = FALSE; + step = file_ep->num_ext + 1; + } + } else if (entry_type == TYPE_STREAM) { + if (is_feasible_entry) { + strm_ep = (STRM_DENTRY_T *) ep; + if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) && + p_uniname->name_len == strm_ep->name_len) { + order = 1; + } else { + is_feasible_entry = FALSE; + step = num_ext_entries; + } + } + } else if (entry_type == TYPE_EXTEND) { + if (is_feasible_entry) { + name_ep = (NAME_DENTRY_T *) ep; + + if ((++order) == 2) + uniname = p_uniname->name; + else + uniname += 15; + + len = extract_uni_name_from_name_entry(name_ep, entry_uniname, order); + + unichar = *(uniname+len); + *(uniname+len) = 0x0; + + if (nls_uniname_cmp(sb, uniname, entry_uniname)) { + is_feasible_entry = FALSE; + step = num_ext_entries - order + 1; + } else if (order == num_ext_entries) { + p_fs->hint_uentry.dir = CLUSTER_32(~0); + p_fs->hint_uentry.entry = -1; + return dentry - (num_ext_entries); + } + + *(uniname+len) = unichar; + } + } else { + is_feasible_entry = FALSE; + } + } + + i += step; + dentry += step; + } + + i -= dentries_per_clu; + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -2; + } + } + + return -2; +} /* end of exfat_find_dir_entry */ + +/* returns -1 on error */ +s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry) +{ + s32 count = 0; + u8 chksum; + DOS_DENTRY_T *dos_ep = (DOS_DENTRY_T *) p_entry; + EXT_DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + chksum = calc_checksum_1byte((void *) dos_ep->name, DOS_NAME_LENGTH, 0); + + for (entry--; entry >= 0; entry--) { + ext_ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ext_ep) + return -1; + + if ((p_fs->fs_func->get_entry_type((DENTRY_T *) ext_ep) == TYPE_EXTEND) && + (ext_ep->checksum == chksum)) { + count++; + if (ext_ep->order > 0x40) + return count; + } else { + return count; + } + } + + return count; +} /* end of fat_count_ext_entries */ + +/* returns -1 on error */ +s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry) +{ + int i, count = 0; + u32 type; + FILE_DENTRY_T *file_ep = (FILE_DENTRY_T *) p_entry; + DENTRY_T *ext_ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) { + ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ext_ep) + return -1; + + type = p_fs->fs_func->get_entry_type(ext_ep); + if ((type == TYPE_EXTEND) || (type == TYPE_STREAM)) + count++; + else + return count; + } + + return count; +} /* end of exfat_count_ext_entries */ + +/* returns -1 on error */ +s32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type) +{ + int i, count = 0; + s32 dentries_per_clu; + u32 entry_type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return -1; + + entry_type = p_fs->fs_func->get_entry_type(ep); + + if (entry_type == TYPE_UNUSED) + return count; + if (!(type & TYPE_CRITICAL_PRI) && !(type & TYPE_BENIGN_PRI)) + continue; + + if ((type == TYPE_ALL) || (type == entry_type)) + count++; + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return -1; + } + } + + return count; +} /* end of count_dos_name_entries */ + +bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir) +{ + int i, count = 0; + s32 dentries_per_clu; + u32 type; + CHAIN_T clu; + DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.size = p_dir->size; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + break; + + type = p_fs->fs_func->get_entry_type(ep); + + if (type == TYPE_UNUSED) + return TRUE; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */ + return FALSE; + } else { + if (p_fs->vol_type == EXFAT) + return FALSE; + if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2)) + return FALSE; + } + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (clu.flags == 0x03) { + if ((--clu.size) > 0) + clu.dir++; + else + clu.dir = CLUSTER_32(~0); + } else { + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + break; + } + } + + return TRUE; +} /* end of is_dir_empty */ + +/* + * Name Conversion Functions + */ + +/* input : dir, uni_name + output : num_of_entry, dos_name(format : aaaaaa~1.bbb) */ +s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname) +{ + s32 ret, num_entries, lossy = FALSE; + char **r; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + num_entries = p_fs->fs_func->calc_num_entries(p_uniname); + if (num_entries == 0) + return FFS_INVALIDPATH; + + if (p_fs->vol_type != EXFAT) { + nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy); + + if (lossy) { + ret = fat_generate_dos_name(sb, p_dir, p_dosname); + if (ret) + return ret; + } else { + for (r = reserved_names; *r; r++) { + if (!strncmp((void *) p_dosname->name, *r, 8)) + return FFS_INVALIDPATH; + } + + if (p_dosname->name_case != 0xFF) + num_entries = 1; + } + + if (num_entries > 1) + p_dosname->name_case = 0x0; + } + + *entries = num_entries; + + return FFS_SUCCESS; +} /* end of get_num_entries_and_dos_name */ + +void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode) +{ + DOS_NAME_T dos_name; + + if (mode == 0x0) + dos_name.name_case = 0x0; + else + dos_name.name_case = ep->lcase; + + memcpy(dos_name.name, ep->name, DOS_NAME_LENGTH); + nls_dosname_to_uniname(sb, p_uniname, &dos_name); +} /* end of get_uni_name_from_dos_entry */ + +void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname) +{ + int i; + EXT_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + for (entry--, i = 1; entry >= 0; entry--, i++) { + ep = (EXT_DENTRY_T *) get_entry_in_dir(sb, p_dir, entry, NULL); + if (!ep) + return; + + if (p_fs->fs_func->get_entry_type((DENTRY_T *) ep) == TYPE_EXTEND) { + extract_uni_name_from_ext_entry(ep, uniname, i); + if (ep->order > 0x40) + return; + } else { + return; + } + + uniname += 13; + } +} /* end of fat_get_uni_name_from_ext_entry */ + +void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname) +{ + int i; + DENTRY_T *ep; + ENTRY_SET_CACHE_T *es; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep); + if (es == NULL || es->num_entries < 3) { + if (es) + release_entry_set(es); + return; + } + + ep += 2; + + /* + * First entry : file entry + * Second entry : stream-extension entry + * Third entry : first file-name entry + * So, the index of first file-name dentry should start from 2. + */ + for (i = 2; i < es->num_entries; i++, ep++) { + if (p_fs->fs_func->get_entry_type(ep) == TYPE_EXTEND) + extract_uni_name_from_name_entry((NAME_DENTRY_T *)ep, uniname, i); + else + goto out; + uniname += 15; + } + +out: + release_entry_set(es); +} /* end of exfat_get_uni_name_from_ext_entry */ + +s32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 order) +{ + int i, len = 0; + + for (i = 0; i < 10; i += 2) { + *uniname = GET16(ep->unicode_0_4+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + if (order < 20) { + for (i = 0; i < 12; i += 2) { + *uniname = GET16_A(ep->unicode_5_10+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + } else { + for (i = 0; i < 8; i += 2) { + *uniname = GET16_A(ep->unicode_5_10+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + *uniname = 0x0; /* uniname[MAX_NAME_LENGTH-1] */ + return len; + } + + for (i = 0; i < 4; i += 2) { + *uniname = GET16_A(ep->unicode_11_12+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} /* end of extract_uni_name_from_ext_entry */ + +s32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order) +{ + int i, len = 0; + + for (i = 0; i < 30; i += 2) { + *uniname = GET16_A(ep->unicode_0_14+i); + if (*uniname == 0x0) + return len; + uniname++; + len++; + } + + *uniname = 0x0; + return len; + +} /* end of extract_uni_name_from_name_entry */ + +s32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname) +{ + int i, j, count = 0, count_begin = FALSE; + s32 dentries_per_clu; + u32 type; + u8 bmap[128/* 1 ~ 1023 */]; + CHAIN_T clu; + DOS_DENTRY_T *ep; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + memset(bmap, 0, sizeof bmap); + exfat_bitmap_set(bmap, 0); + + if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */ + dentries_per_clu = p_fs->dentries_in_root; + else + dentries_per_clu = p_fs->dentries_per_clu; + + clu.dir = p_dir->dir; + clu.flags = p_dir->flags; + + while (clu.dir != CLUSTER_32(~0)) { + if (p_fs->dev_ejected) + break; + + for (i = 0; i < dentries_per_clu; i++) { + ep = (DOS_DENTRY_T *) get_entry_in_dir(sb, &clu, i, NULL); + if (!ep) + return FFS_MEDIAERR; + + type = p_fs->fs_func->get_entry_type((DENTRY_T *) ep); + + if (type == TYPE_UNUSED) + break; + if ((type != TYPE_FILE) && (type != TYPE_DIR)) + continue; + + count = 0; + count_begin = FALSE; + + for (j = 0; j < 8; j++) { + if (ep->name[j] == ' ') + break; + + if (ep->name[j] == '~') { + count_begin = TRUE; + } else if (count_begin) { + if ((ep->name[j] >= '0') && (ep->name[j] <= '9')) { + count = count * 10 + (ep->name[j] - '0'); + } else { + count = 0; + count_begin = FALSE; + } + } + } + + if ((count > 0) && (count < 1024)) + exfat_bitmap_set(bmap, count); + } + + if (p_dir->dir == CLUSTER_32(0)) + break; /* FAT16 root_dir */ + + if (FAT_read(sb, clu.dir, &(clu.dir)) != 0) + return FFS_MEDIAERR; + } + + count = 0; + for (i = 0; i < 128; i++) { + if (bmap[i] != 0xFF) { + for (j = 0; j < 8; j++) { + if (exfat_bitmap_test(&(bmap[i]), j) == 0) { + count = (i << 3) + j; + break; + } + } + if (count != 0) + break; + } + } + + if ((count == 0) || (count >= 1024)) + return FFS_FILEEXIST; + else + fat_attach_count_to_dos_name(p_dosname->name, count); + + /* Now dos_name has DOS~????.EXT */ + return FFS_SUCCESS; +} /* end of generate_dos_name */ + +void fat_attach_count_to_dos_name(u8 *dosname, s32 count) +{ + int i, j, length; + char str_count[6]; + + snprintf(str_count, sizeof str_count, "~%d", count); + length = strlen(str_count); + + i = j = 0; + while (j <= (8 - length)) { + i = j; + if (dosname[j] == ' ') + break; + if (dosname[j] & 0x80) + j += 2; + else + j++; + } + + for (j = 0; j < length; i++, j++) + dosname[i] = (u8) str_count[j]; + + if (i == 7) + dosname[7] = ' '; + +} /* end of attach_count_to_dos_name */ + +s32 fat_calc_num_entries(UNI_NAME_T *p_uniname) +{ + s32 len; + + len = p_uniname->name_len; + if (len == 0) + return 0; + + /* 1 dos name entry + extended entries */ + return (len-1) / 13 + 2; + +} /* end of calc_num_enties */ + +s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname) +{ + s32 len; + + len = p_uniname->name_len; + if (len == 0) + return 0; + + /* 1 file entry + 1 stream entry + name entries */ + return (len-1) / 15 + 3; + +} /* end of exfat_calc_num_enties */ + +u8 calc_checksum_1byte(void *data, s32 len, u8 chksum) +{ + int i; + u8 *c = (u8 *) data; + + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 7) | ((chksum & 0xFE) >> 1)) + *c; + + return chksum; +} /* end of calc_checksum_1byte */ + +u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type) +{ + int i; + u8 *c = (u8 *) data; + + switch (type) { + case CS_DIR_ENTRY: + for (i = 0; i < len; i++, c++) { + if ((i == 2) || (i == 3)) + continue; + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; + } + break; + default + : + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 15) | ((chksum & 0xFFFE) >> 1)) + (u16) *c; + } + + return chksum; +} /* end of calc_checksum_2byte */ + +u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type) +{ + int i; + u8 *c = (u8 *) data; + + switch (type) { + case CS_PBR_SECTOR: + for (i = 0; i < len; i++, c++) { + if ((i == 106) || (i == 107) || (i == 112)) + continue; + chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (u32) *c; + } + break; + default + : + for (i = 0; i < len; i++, c++) + chksum = (((chksum & 1) << 31) | ((chksum & 0xFFFFFFFE) >> 1)) + (u32) *c; + } + + return chksum; +} /* end of calc_checksum_4byte */ + +/* + * Name Resolution Functions + */ + +/* return values of resolve_path() + > 0 : return the length of the path + < 0 : return error */ +s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname) +{ + s32 lossy = FALSE; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + + if (strlen(path) >= (MAX_NAME_LENGTH * MAX_CHARSET_SIZE)) + return FFS_INVALIDPATH; + + strcpy(name_buf, path); + + nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); + if (lossy) + return FFS_INVALIDPATH; + + fid->size = i_size_read(inode); + + p_dir->dir = fid->start_clu; + p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits); + p_dir->flags = fid->flags; + + return FFS_SUCCESS; +} + +/* + * File Operation Functions + */ +static FS_FUNC_T fat_fs_func = { + .alloc_cluster = fat_alloc_cluster, + .free_cluster = fat_free_cluster, + .count_used_clusters = fat_count_used_clusters, + + .init_dir_entry = fat_init_dir_entry, + .init_ext_entry = fat_init_ext_entry, + .find_dir_entry = fat_find_dir_entry, + .delete_dir_entry = fat_delete_dir_entry, + .get_uni_name_from_ext_entry = fat_get_uni_name_from_ext_entry, + .count_ext_entries = fat_count_ext_entries, + .calc_num_entries = fat_calc_num_entries, + + .get_entry_type = fat_get_entry_type, + .set_entry_type = fat_set_entry_type, + .get_entry_attr = fat_get_entry_attr, + .set_entry_attr = fat_set_entry_attr, + .get_entry_flag = fat_get_entry_flag, + .set_entry_flag = fat_set_entry_flag, + .get_entry_clu0 = fat_get_entry_clu0, + .set_entry_clu0 = fat_set_entry_clu0, + .get_entry_size = fat_get_entry_size, + .set_entry_size = fat_set_entry_size, + .get_entry_time = fat_get_entry_time, + .set_entry_time = fat_set_entry_time, +}; + + +s32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + s32 num_reserved, num_root_sectors; + BPB16_T *p_bpb = (BPB16_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + num_root_sectors = GET16(p_bpb->num_root_entries) << DENTRY_SIZE_BITS; + num_root_sectors = ((num_root_sectors-1) >> p_bd->sector_size_bits) + 1; + + p_fs->sectors_per_clu = p_bpb->sectors_per_clu; + p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET16(p_bpb->num_fat_sectors); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors; + p_fs->data_start_sector = p_fs->root_start_sector + num_root_sectors; + + p_fs->num_sectors = GET16(p_bpb->num_sectors); + if (p_fs->num_sectors == 0) + p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); + + num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; + p_fs->num_clusters = ((p_fs->num_sectors - num_reserved) >> p_fs->sectors_per_clu_bits) + 2; + /* because the cluster index starts with 2 */ + + if (p_fs->num_clusters < FAT12_THRESHOLD) + p_fs->vol_type = FAT12; + else + p_fs->vol_type = FAT16; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = 0; + p_fs->dentries_in_root = GET16(p_bpb->num_root_entries); + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = VOL_CLEAN; + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &fat_fs_func; + + return FFS_SUCCESS; +} /* end of fat16_mount */ + +s32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + s32 num_reserved; + BPB32_T *p_bpb = (BPB32_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + p_fs->sectors_per_clu = p_bpb->sectors_per_clu; + p_fs->sectors_per_clu_bits = ilog2(p_bpb->sectors_per_clu); + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET32(p_bpb->num_fat32_sectors); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET16(p_bpb->num_reserved); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->FAT2_start_sector + p_fs->num_FAT_sectors; + p_fs->data_start_sector = p_fs->root_start_sector; + + p_fs->num_sectors = GET32(p_bpb->num_huge_sectors); + num_reserved = p_fs->data_start_sector - p_fs->PBR_sector; + + p_fs->num_clusters = ((p_fs->num_sectors-num_reserved) >> p_fs->sectors_per_clu_bits) + 2; + /* because the cluster index starts with 2 */ + + p_fs->vol_type = FAT32; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = GET32(p_bpb->root_cluster); + p_fs->dentries_in_root = 0; + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = VOL_CLEAN; + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &fat_fs_func; + + return FFS_SUCCESS; +} /* end of fat32_mount */ + +static FS_FUNC_T exfat_fs_func = { + .alloc_cluster = exfat_alloc_cluster, + .free_cluster = exfat_free_cluster, + .count_used_clusters = exfat_count_used_clusters, + + .init_dir_entry = exfat_init_dir_entry, + .init_ext_entry = exfat_init_ext_entry, + .find_dir_entry = exfat_find_dir_entry, + .delete_dir_entry = exfat_delete_dir_entry, + .get_uni_name_from_ext_entry = exfat_get_uni_name_from_ext_entry, + .count_ext_entries = exfat_count_ext_entries, + .calc_num_entries = exfat_calc_num_entries, + + .get_entry_type = exfat_get_entry_type, + .set_entry_type = exfat_set_entry_type, + .get_entry_attr = exfat_get_entry_attr, + .set_entry_attr = exfat_set_entry_attr, + .get_entry_flag = exfat_get_entry_flag, + .set_entry_flag = exfat_set_entry_flag, + .get_entry_clu0 = exfat_get_entry_clu0, + .set_entry_clu0 = exfat_set_entry_clu0, + .get_entry_size = exfat_get_entry_size, + .set_entry_size = exfat_set_entry_size, + .get_entry_time = exfat_get_entry_time, + .set_entry_time = exfat_set_entry_time, +}; + +s32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr) +{ + BPBEX_T *p_bpb = (BPBEX_T *) p_pbr->bpb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + + if (p_bpb->num_fats == 0) + return FFS_FORMATERR; + + p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits; + p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits; + p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits + p_bd->sector_size_bits; + p_fs->cluster_size = 1 << p_fs->cluster_size_bits; + + p_fs->num_FAT_sectors = GET32(p_bpb->fat_length); + + p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset); + if (p_bpb->num_fats == 1) + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector; + else + p_fs->FAT2_start_sector = p_fs->FAT1_start_sector + p_fs->num_FAT_sectors; + + p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset); + p_fs->data_start_sector = p_fs->root_start_sector; + + p_fs->num_sectors = GET64(p_bpb->vol_length); + p_fs->num_clusters = GET32(p_bpb->clu_count) + 2; + /* because the cluster index starts with 2 */ + + p_fs->vol_type = EXFAT; + p_fs->vol_id = GET32(p_bpb->vol_serial); + + p_fs->root_dir = GET32(p_bpb->root_cluster); + p_fs->dentries_in_root = 0; + p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS); + + p_fs->vol_flag = (u32) GET16(p_bpb->vol_flags); + p_fs->clu_srch_ptr = 2; + p_fs->used_clusters = (u32) ~0; + + p_fs->fs_func = &exfat_fs_func; + + return FFS_SUCCESS; +} /* end of exfat_mount */ + +s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + u64 size; + CHAIN_T clu; + DOS_NAME_T dos_name, dot_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name); + if (ret) + return ret; + + /* find_empty_entry must be called before alloc_cluster */ + dentry = find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) + return FFS_FULL; + + clu.dir = CLUSTER_32(~0); + clu.size = 0; + clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + + /* (1) allocate a cluster */ + ret = p_fs->fs_func->alloc_cluster(sb, 1, &clu); + if (ret < 0) + return FFS_MEDIAERR; + else if (ret == 0) + return FFS_FULL; + + ret = clear_cluster(sb, clu.dir); + if (ret != FFS_SUCCESS) + return ret; + + if (p_fs->vol_type == EXFAT) { + size = p_fs->cluster_size; + } else { + size = 0; + + /* initialize the . and .. entry + Information for . points to itself + Information for .. points to parent dir */ + + dot_name.name_case = 0x0; + memcpy(dot_name.name, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH); + + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 0, TYPE_DIR, clu.dir, 0); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, &clu, 0, 1, NULL, &dot_name); + if (ret != FFS_SUCCESS) + return ret; + + memcpy(dot_name.name, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH); + + if (p_dir->dir == p_fs->root_dir) + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, CLUSTER_32(0), 0); + else + ret = p_fs->fs_func->init_dir_entry(sb, &clu, 1, TYPE_DIR, p_dir->dir, 0); + + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, &clu, 1, 1, NULL, &dot_name); + if (ret != FFS_SUCCESS) + return ret; + } + + /* (2) update the directory entry */ + /* make sub-dir entry in parent directory */ + ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir, size); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + fid->dir.dir = p_dir->dir; + fid->dir.size = p_dir->size; + fid->dir.flags = p_dir->flags; + fid->entry = dentry; + + fid->attr = ATTR_SUBDIR; + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->size = size; + fid->start_clu = clu.dir; + + fid->type = TYPE_DIR; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + return FFS_SUCCESS; +} /* end of create_dir */ + +s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid) +{ + s32 ret, dentry, num_entries; + DOS_NAME_T dos_name; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries, &dos_name); + if (ret) + return ret; + + /* find_empty_entry must be called before alloc_cluster() */ + dentry = find_empty_entry(inode, p_dir, num_entries); + if (dentry < 0) + return FFS_FULL; + + /* (1) update the directory entry */ + /* fill the dos name directory entry information of the created file. + the first cluster is not determined yet. (0) */ + ret = p_fs->fs_func->init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode, CLUSTER_32(0), 0); + if (ret != FFS_SUCCESS) + return ret; + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + fid->dir.dir = p_dir->dir; + fid->dir.size = p_dir->size; + fid->dir.flags = p_dir->flags; + fid->entry = dentry; + + fid->attr = ATTR_ARCHIVE | mode; + fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; + fid->size = 0; + fid->start_clu = CLUSTER_32(~0); + + fid->type = TYPE_FILE; + fid->rwoffset = 0; + fid->hint_last_off = -1; + + return FFS_SUCCESS; +} /* end of create_file */ + +void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry) +{ + s32 num_entries; + sector_t sector; + DENTRY_T *ep; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + ep = get_entry_in_dir(sb, p_dir, entry, §or); + if (!ep) + return; + + buf_lock(sb, sector); + + /* buf_lock() before call count_ext_entries() */ + num_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, entry, ep); + if (num_entries < 0) { + buf_unlock(sb, sector); + return; + } + num_entries++; + + buf_unlock(sb, sector); + + /* (1) update the directory entry */ + p_fs->fs_func->delete_dir_entry(sb, p_dir, entry, 0, num_entries); +} /* end of remove_file */ + +s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 oldentry, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, newentry = -1, num_old_entries, num_new_entries; + sector_t sector_old, sector_new; + DOS_NAME_T dos_name; + DENTRY_T *epold, *epnew; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + epold = get_entry_in_dir(sb, p_dir, oldentry, §or_old); + if (!epold) + return FFS_MEDIAERR; + + buf_lock(sb, sector_old); + + /* buf_lock() before call count_ext_entries() */ + num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_dir, oldentry, epold); + if (num_old_entries < 0) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + num_old_entries++; + + ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_new_entries, &dos_name); + if (ret) { + buf_unlock(sb, sector_old); + return ret; + } + + if (num_old_entries < num_new_entries) { + newentry = find_empty_entry(inode, p_dir, num_new_entries); + if (newentry < 0) { + buf_unlock(sb, sector_old); + return FFS_FULL; + } + + epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); + if (!epnew) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epold, DENTRY_SIZE); + if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_new); + buf_unlock(sb, sector_old); + + if (p_fs->vol_type == EXFAT) { + epold = get_entry_in_dir(sb, p_dir, oldentry+1, §or_old); + buf_lock(sb, sector_old); + epnew = get_entry_in_dir(sb, p_dir, newentry+1, §or_new); + + if (!epold || !epnew) { + buf_unlock(sb, sector_old); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epold, DENTRY_SIZE); + buf_modify(sb, sector_new); + buf_unlock(sb, sector_old); + } + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, newentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, 0, num_old_entries); + fid->entry = newentry; + } else { + if (p_fs->fs_func->get_entry_type(epold) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epold, p_fs->fs_func->get_entry_attr(epold) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_old); + buf_unlock(sb, sector_old); + + ret = p_fs->fs_func->init_ext_entry(sb, p_dir, oldentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_dir, oldentry, num_new_entries, num_old_entries); + } + + return FFS_SUCCESS; +} /* end of rename_file */ + +s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid) +{ + s32 ret, newentry, num_new_entries, num_old_entries; + sector_t sector_mov, sector_new; + CHAIN_T clu; + DOS_NAME_T dos_name; + DENTRY_T *epmov, *epnew; + struct super_block *sb = inode->i_sb; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + epmov = get_entry_in_dir(sb, p_olddir, oldentry, §or_mov); + if (!epmov) + return FFS_MEDIAERR; + + /* check if the source and target directory is the same */ + if (p_fs->fs_func->get_entry_type(epmov) == TYPE_DIR && + p_fs->fs_func->get_entry_clu0(epmov) == p_newdir->dir) + return FFS_INVALIDPATH; + + buf_lock(sb, sector_mov); + + /* buf_lock() before call count_ext_entries() */ + num_old_entries = p_fs->fs_func->count_ext_entries(sb, p_olddir, oldentry, epmov); + if (num_old_entries < 0) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + num_old_entries++; + + ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname, &num_new_entries, &dos_name); + if (ret) { + buf_unlock(sb, sector_mov); + return ret; + } + + newentry = find_empty_entry(inode, p_newdir, num_new_entries); + if (newentry < 0) { + buf_unlock(sb, sector_mov); + return FFS_FULL; + } + + epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); + if (!epnew) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epmov, DENTRY_SIZE); + if (p_fs->fs_func->get_entry_type(epnew) == TYPE_FILE) { + p_fs->fs_func->set_entry_attr(epnew, p_fs->fs_func->get_entry_attr(epnew) | ATTR_ARCHIVE); + fid->attr |= ATTR_ARCHIVE; + } + buf_modify(sb, sector_new); + buf_unlock(sb, sector_mov); + + if (p_fs->vol_type == EXFAT) { + epmov = get_entry_in_dir(sb, p_olddir, oldentry+1, §or_mov); + buf_lock(sb, sector_mov); + epnew = get_entry_in_dir(sb, p_newdir, newentry+1, §or_new); + if (!epmov || !epnew) { + buf_unlock(sb, sector_mov); + return FFS_MEDIAERR; + } + + memcpy((void *) epnew, (void *) epmov, DENTRY_SIZE); + buf_modify(sb, sector_new); + buf_unlock(sb, sector_mov); + } else if (p_fs->fs_func->get_entry_type(epnew) == TYPE_DIR) { + /* change ".." pointer to new parent dir */ + clu.dir = p_fs->fs_func->get_entry_clu0(epnew); + clu.flags = 0x01; + + epnew = get_entry_in_dir(sb, &clu, 1, §or_new); + if (!epnew) + return FFS_MEDIAERR; + + if (p_newdir->dir == p_fs->root_dir) + p_fs->fs_func->set_entry_clu0(epnew, CLUSTER_32(0)); + else + p_fs->fs_func->set_entry_clu0(epnew, p_newdir->dir); + buf_modify(sb, sector_new); + } + + ret = p_fs->fs_func->init_ext_entry(sb, p_newdir, newentry, num_new_entries, p_uniname, &dos_name); + if (ret != FFS_SUCCESS) + return ret; + + p_fs->fs_func->delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries); + + fid->dir.dir = p_newdir->dir; + fid->dir.size = p_newdir->size; + fid->dir.flags = p_newdir->flags; + + fid->entry = newentry; + + return FFS_SUCCESS; +} /* end of move_file */ + +/* + * Sector Read/Write Functions + */ + +s32 sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 read) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((sec >= (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] sector_read: out of range error! (sec = %llu)\n", (unsigned long long)sec); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_read(sb, sec, bh, 1, read); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of sector_read */ + +s32 sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 sync) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (sec >= (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] sector_write: out of range error! (sec = %llu)\n", (unsigned long long)sec); + fs_error(sb); + return ret; + } + + if (bh == NULL) { + printk("[EXFAT] sector_write: bh is NULL!\n"); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_write(sb, sec, bh, 1, sync); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of sector_write */ + +s32 multi_sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 num_secs, s32 read) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors)) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] multi_sector_read: out of range error! (sec = %llu, num_secs = %d)\n", + (unsigned long long)sec, num_secs); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_read(sb, sec, bh, num_secs, read); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of multi_sector_read */ + +s32 multi_sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 num_secs, s32 sync) +{ + s32 ret = FFS_MEDIAERR; + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if ((sec+num_secs) > (p_fs->PBR_sector+p_fs->num_sectors) && (p_fs->num_sectors > 0)) { + printk("[EXFAT] multi_sector_write: out of range error! (sec = %llu, num_secs = %d)\n", + (unsigned long long)sec, num_secs); + fs_error(sb); + return ret; + } + if (bh == NULL) { + printk("[EXFAT] multi_sector_write: bh is NULL!\n"); + fs_error(sb); + return ret; + } + + if (!p_fs->dev_ejected) { + ret = bdev_write(sb, sec, bh, num_secs, sync); + if (ret != FFS_SUCCESS) + p_fs->dev_ejected = TRUE; + } + + return ret; +} /* end of multi_sector_write */ diff --git a/fs/exfat/exfat_core.h b/fs/exfat/exfat_core.h new file mode 100644 index 0000000000000000000000000000000000000000..52d05c7007d32d34d68df3bfee5301d8fdf1a76f --- /dev/null +++ b/fs/exfat/exfat_core.h @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_core.h */ +/* PURPOSE : Header File for exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_H +#define _EXFAT_H + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_cache.h" + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + /* For Debugging Purpose */ + /* IOCTL code 'f' used by + * - file systems typically #0~0x1F + * - embedded terminal devices #128~ + * - exts for debugging purpose #99 + * number 100 and 101 is availble now but has possible conflicts + */ +#define EXFAT_IOC_GET_DEBUGFLAGS _IOR('f', 100, long) +#define EXFAT_IOC_SET_DEBUGFLAGS _IOW('f', 101, long) + +#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT 0x01 +#define EXFAT_DEBUGFLAGS_ERROR_RW 0x02 +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + /*----------------------------------------------------------------------*/ + /* Constant & Macro Definitions */ + /*----------------------------------------------------------------------*/ + +#define DENTRY_SIZE 32 /* dir entry size */ +#define DENTRY_SIZE_BITS 5 + +/* PBR entries */ +#define PBR_SIGNATURE 0xAA55 +#define EXT_SIGNATURE 0xAA550000 +#define VOL_LABEL "NO NAME " /* size should be 11 */ +#define OEM_NAME "MSWIN4.1" /* size should be 8 */ +#define STR_FAT12 "FAT12 " /* size should be 8 */ +#define STR_FAT16 "FAT16 " /* size should be 8 */ +#define STR_FAT32 "FAT32 " /* size should be 8 */ +#define STR_EXFAT "EXFAT " /* size should be 8 */ +#define VOL_CLEAN 0x0000 +#define VOL_DIRTY 0x0002 + +/* max number of clusters */ +#define FAT12_THRESHOLD 4087 /* 2^12 - 1 + 2 (clu 0 & 1) */ +#define FAT16_THRESHOLD 65527 /* 2^16 - 1 + 2 */ +#define FAT32_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ +#define EXFAT_THRESHOLD 268435457 /* 2^28 - 1 + 2 */ + +/* file types */ +#define TYPE_UNUSED 0x0000 +#define TYPE_DELETED 0x0001 +#define TYPE_INVALID 0x0002 +#define TYPE_CRITICAL_PRI 0x0100 +#define TYPE_BITMAP 0x0101 +#define TYPE_UPCASE 0x0102 +#define TYPE_VOLUME 0x0103 +#define TYPE_DIR 0x0104 +#define TYPE_FILE 0x011F +#define TYPE_SYMLINK 0x015F +#define TYPE_CRITICAL_SEC 0x0200 +#define TYPE_STREAM 0x0201 +#define TYPE_EXTEND 0x0202 +#define TYPE_ACL 0x0203 +#define TYPE_BENIGN_PRI 0x0400 +#define TYPE_GUID 0x0401 +#define TYPE_PADDING 0x0402 +#define TYPE_ACLTAB 0x0403 +#define TYPE_BENIGN_SEC 0x0800 +#define TYPE_ALL 0x0FFF + +/* time modes */ +#define TM_CREATE 0 +#define TM_MODIFY 1 +#define TM_ACCESS 2 + +/* checksum types */ +#define CS_DIR_ENTRY 0 +#define CS_PBR_SECTOR 1 +#define CS_DEFAULT 2 + +#define CLUSTER_16(x) ((u16)(x)) +#define CLUSTER_32(x) ((u32)(x)) + +#define FALSE 0 +#define TRUE 1 + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define START_SECTOR(x) \ + ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) + p_fs->data_start_sector) + +#define IS_LAST_SECTOR_IN_CLUSTER(sec) \ + ((((sec) - p_fs->data_start_sector + 1) & ((1 << p_fs->sectors_per_clu_bits) - 1)) == 0) + +#define GET_CLUSTER_FROM_SECTOR(sec) \ + ((u32)((((sec) - p_fs->data_start_sector) >> p_fs->sectors_per_clu_bits) + 2)) + +#define GET16(p_src) \ + (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8)) +#define GET32(p_src) \ + (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) | \ + (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24)) +#define GET64(p_src) \ + (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) | \ + (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \ + (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \ + (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56)) + + +#define SET16(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u16)(src)) >> 8); \ + } while (0) +#define SET32(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u32)(src)) >> 8); \ + (p_dst)[2] = (u8)(((u32)(src)) >> 16); \ + (p_dst)[3] = (u8)(((u32)(src)) >> 24); \ + } while (0) +#define SET64(p_dst, src) \ + do { \ + (p_dst)[0] = (u8)(src); \ + (p_dst)[1] = (u8)(((u64)(src)) >> 8); \ + (p_dst)[2] = (u8)(((u64)(src)) >> 16); \ + (p_dst)[3] = (u8)(((u64)(src)) >> 24); \ + (p_dst)[4] = (u8)(((u64)(src)) >> 32); \ + (p_dst)[5] = (u8)(((u64)(src)) >> 40); \ + (p_dst)[6] = (u8)(((u64)(src)) >> 48); \ + (p_dst)[7] = (u8)(((u64)(src)) >> 56); \ + } while (0) + +#ifdef __LITTLE_ENDIAN +#define GET16_A(p_src) (*((u16 *)(p_src))) +#define GET32_A(p_src) (*((u32 *)(p_src))) +#define GET64_A(p_src) (*((u64 *)(p_src))) +#define SET16_A(p_dst, src) (*((u16 *)(p_dst)) = (u16)(src)) +#define SET32_A(p_dst, src) (*((u32 *)(p_dst)) = (u32)(src)) +#define SET64_A(p_dst, src) (*((u64 *)(p_dst)) = (u64)(src)) +#else /* BIG_ENDIAN */ +#define GET16_A(p_src) GET16(p_src) +#define GET32_A(p_src) GET32(p_src) +#define GET64_A(p_src) GET64(p_src) +#define SET16_A(p_dst, src) SET16(p_dst, src) +#define SET32_A(p_dst, src) SET32(p_dst, src) +#define SET64_A(p_dst, src) SET64(p_dst, src) +#endif + +/* Upcase tabel mecro */ +#define HIGH_INDEX_BIT (8) +#define HIGH_INDEX_MASK (0xFF00) +#define LOW_INDEX_BIT (16-HIGH_INDEX_BIT) +#define UTBL_ROW_COUNT (1<> LOW_INDEX_BIT; +} +static inline u16 get_row_index(u16 i) +{ + return i & ~HIGH_INDEX_MASK; +} +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +/* MS_DOS FAT partition boot record (512 bytes) */ +typedef struct { + u8 jmp_boot[3]; + u8 oem_name[8]; + u8 bpb[109]; + u8 boot_code[390]; + u8 signature[2]; +} PBR_SECTOR_T; + +/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */ +typedef struct { + u8 sector_size[2]; + u8 sectors_per_clu; + u8 num_reserved[2]; + u8 num_fats; + u8 num_root_entries[2]; + u8 num_sectors[2]; + u8 media_type; + u8 num_fat_sectors[2]; + u8 sectors_in_track[2]; + u8 num_heads[2]; + u8 num_hid_sectors[4]; + u8 num_huge_sectors[4]; + + u8 phy_drv_no; + u8 reserved; + u8 ext_signature; + u8 vol_serial[4]; + u8 vol_label[11]; + u8 vol_type[8]; +} BPB16_T; + +/* MS-DOS FAT32 BIOS parameter block (79 bytes) */ +typedef struct { + u8 sector_size[2]; + u8 sectors_per_clu; + u8 num_reserved[2]; + u8 num_fats; + u8 num_root_entries[2]; + u8 num_sectors[2]; + u8 media_type; + u8 num_fat_sectors[2]; + u8 sectors_in_track[2]; + u8 num_heads[2]; + u8 num_hid_sectors[4]; + u8 num_huge_sectors[4]; + u8 num_fat32_sectors[4]; + u8 ext_flags[2]; + u8 fs_version[2]; + u8 root_cluster[4]; + u8 fsinfo_sector[2]; + u8 backup_sector[2]; + u8 reserved[12]; + + u8 phy_drv_no; + u8 ext_reserved; + u8 ext_signature; + u8 vol_serial[4]; + u8 vol_label[11]; + u8 vol_type[8]; +} BPB32_T; + +/* MS-DOS EXFAT BIOS parameter block (109 bytes) */ +typedef struct { + u8 reserved1[53]; + u8 vol_offset[8]; + u8 vol_length[8]; + u8 fat_offset[4]; + u8 fat_length[4]; + u8 clu_offset[4]; + u8 clu_count[4]; + u8 root_cluster[4]; + u8 vol_serial[4]; + u8 fs_version[2]; + u8 vol_flags[2]; + u8 sector_size_bits; + u8 sectors_per_clu_bits; + u8 num_fats; + u8 phy_drv_no; + u8 perc_in_use; + u8 reserved2[7]; +} BPBEX_T; + +/* MS-DOS FAT file system information sector (512 bytes) */ +typedef struct { + u8 signature1[4]; + u8 reserved1[480]; + u8 signature2[4]; + u8 free_cluster[4]; + u8 next_cluster[4]; + u8 reserved2[14]; + u8 signature3[2]; +} FSI_SECTOR_T; + +/* MS-DOS FAT directory entry (32 bytes) */ +typedef struct { + u8 dummy[32]; +} DENTRY_T; + +typedef struct { + u8 name[DOS_NAME_LENGTH]; + u8 attr; + u8 lcase; + u8 create_time_ms; + u8 create_time[2]; + u8 create_date[2]; + u8 access_date[2]; + u8 start_clu_hi[2]; + u8 modify_time[2]; + u8 modify_date[2]; + u8 start_clu_lo[2]; + u8 size[4]; +} DOS_DENTRY_T; + +/* MS-DOS FAT extended directory entry (32 bytes) */ +typedef struct { + u8 order; + u8 unicode_0_4[10]; + u8 attr; + u8 sysid; + u8 checksum; + u8 unicode_5_10[12]; + u8 start_clu[2]; + u8 unicode_11_12[4]; +} EXT_DENTRY_T; + +/* MS-DOS EXFAT file directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 num_ext; + u8 checksum[2]; + u8 attr[2]; + u8 reserved1[2]; + u8 create_time[2]; + u8 create_date[2]; + u8 modify_time[2]; + u8 modify_date[2]; + u8 access_time[2]; + u8 access_date[2]; + u8 create_time_ms; + u8 modify_time_ms; + u8 access_time_ms; + u8 reserved2[9]; +} FILE_DENTRY_T; + +/* MS-DOS EXFAT stream extension directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 reserved1; + u8 name_len; + u8 name_hash[2]; + u8 reserved2[2]; + u8 valid_size[8]; + u8 reserved3[4]; + u8 start_clu[4]; + u8 size[8]; +} STRM_DENTRY_T; + +/* MS-DOS EXFAT file name directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 unicode_0_14[30]; +} NAME_DENTRY_T; + +/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 flags; + u8 reserved[18]; + u8 start_clu[4]; + u8 size[8]; +} BMAP_DENTRY_T; + +/* MS-DOS EXFAT up-case table directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 reserved1[3]; + u8 checksum[4]; + u8 reserved2[12]; + u8 start_clu[4]; + u8 size[8]; +} CASE_DENTRY_T; + +/* MS-DOS EXFAT volume label directory entry (32 bytes) */ +typedef struct { + u8 type; + u8 label_len; + u8 unicode_0_10[22]; + u8 reserved[8]; +} VOLM_DENTRY_T; + +/* unused entry hint information */ +typedef struct { + u32 dir; + s32 entry; + CHAIN_T clu; +} UENTRY_T; + +typedef struct { + s32 (*alloc_cluster)(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); + void (*free_cluster)(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); + s32 (*count_used_clusters)(struct super_block *sb); + + s32 (*init_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, + u32 start_clu, u64 size); + s32 (*init_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, + UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); + s32 (*find_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); + void (*delete_dir_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 offset, s32 num_entries); + void (*get_uni_name_from_ext_entry)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); + s32 (*count_ext_entries)(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); + s32 (*calc_num_entries)(UNI_NAME_T *p_uniname); + + u32 (*get_entry_type)(DENTRY_T *p_entry); + void (*set_entry_type)(DENTRY_T *p_entry, u32 type); + u32 (*get_entry_attr)(DENTRY_T *p_entry); + void (*set_entry_attr)(DENTRY_T *p_entry, u32 attr); + u8 (*get_entry_flag)(DENTRY_T *p_entry); + void (*set_entry_flag)(DENTRY_T *p_entry, u8 flag); + u32 (*get_entry_clu0)(DENTRY_T *p_entry); + void (*set_entry_clu0)(DENTRY_T *p_entry, u32 clu0); + u64 (*get_entry_size)(DENTRY_T *p_entry); + void (*set_entry_size)(DENTRY_T *p_entry, u64 size); + void (*get_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); + void (*set_entry_time)(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +} FS_FUNC_T; + +typedef struct __FS_INFO_T { + u32 drv; /* drive ID */ + u32 vol_type; /* volume FAT type */ + u32 vol_id; /* volume serial number */ + + u64 num_sectors; /* num of sectors in volume */ + u32 num_clusters; /* num of clusters in volume */ + u32 cluster_size; /* cluster size in bytes */ + u32 cluster_size_bits; + u32 sectors_per_clu; /* cluster size in sectors */ + u32 sectors_per_clu_bits; + + u32 PBR_sector; /* PBR sector */ + u32 FAT1_start_sector; /* FAT1 start sector */ + u32 FAT2_start_sector; /* FAT2 start sector */ + u32 root_start_sector; /* root dir start sector */ + u32 data_start_sector; /* data area start sector */ + u32 num_FAT_sectors; /* num of FAT sectors */ + + u32 root_dir; /* root dir cluster */ + u32 dentries_in_root; /* num of dentries in root dir */ + u32 dentries_per_clu; /* num of dentries per cluster */ + + u32 vol_flag; /* volume dirty flag */ + struct buffer_head *pbr_bh; /* PBR sector */ + + u32 map_clu; /* allocation bitmap start cluster */ + u32 map_sectors; /* num of allocation bitmap sectors */ + struct buffer_head **vol_amap; /* allocation bitmap */ + + u16 **vol_utbl; /* upcase table */ + + u32 clu_srch_ptr; /* cluster search pointer */ + u32 used_clusters; /* number of used clusters */ + UENTRY_T hint_uentry; /* unused entry hint information */ + + u32 dev_ejected; /* block device operation error flag */ + + FS_FUNC_T *fs_func; + struct semaphore v_sem; + + /* FAT cache */ + BUF_CACHE_T FAT_cache_array[FAT_CACHE_SIZE]; + BUF_CACHE_T FAT_cache_lru_list; + BUF_CACHE_T FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; + + /* buf cache */ + BUF_CACHE_T buf_cache_array[BUF_CACHE_SIZE]; + BUF_CACHE_T buf_cache_lru_list; + BUF_CACHE_T buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; +} FS_INFO_T; + +#define ES_2_ENTRIES 2 +#define ES_3_ENTRIES 3 +#define ES_ALL_ENTRIES 0 + +typedef struct { + sector_t sector; /* sector number that contains file_entry */ + s32 offset; /* byte offset in the sector */ + s32 alloc_flag; /* flag in stream entry. 01 for cluster chain, 03 for contig. clusteres. */ + u32 num_entries; + + /* __buf should be the last member */ + void *__buf; +} ENTRY_SET_CACHE_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* file system initialization & shutdown functions */ +s32 ffsInit(void); +s32 ffsShutdown(void); + +/* volume management functions */ +s32 ffsMountVol(struct super_block *sb); +s32 ffsUmountVol(struct super_block *sb); +s32 ffsCheckVol(struct super_block *sb); +s32 ffsGetVolInfo(struct super_block *sb, VOL_INFO_T *info); +s32 ffsSyncVol(struct super_block *sb, s32 do_sync); + +/* file management functions */ +s32 ffsLookupFile(struct inode *inode, char *path, FILE_ID_T *fid); +s32 ffsCreateFile(struct inode *inode, char *path, u8 mode, FILE_ID_T *fid); +s32 ffsReadFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *rcount); +s32 ffsWriteFile(struct inode *inode, FILE_ID_T *fid, void *buffer, u64 count, u64 *wcount); +s32 ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size); +s32 ffsMoveFile(struct inode *old_parent_inode, FILE_ID_T *fid, struct inode *new_parent_inode, struct dentry *new_dentry); +s32 ffsRemoveFile(struct inode *inode, FILE_ID_T *fid); +s32 ffsSetAttr(struct inode *inode, u32 attr); +s32 ffsGetStat(struct inode *inode, DIR_ENTRY_T *info); +s32 ffsSetStat(struct inode *inode, DIR_ENTRY_T *info); +s32 ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu); + +/* directory management functions */ +s32 ffsCreateDir(struct inode *inode, char *path, FILE_ID_T *fid); +s32 ffsReadDir(struct inode *inode, DIR_ENTRY_T *dir_ent); +s32 ffsRemoveDir(struct inode *inode, FILE_ID_T *fid); + +/*----------------------------------------------------------------------*/ +/* External Function Declarations (NOT TO UPPER LAYER) */ +/*----------------------------------------------------------------------*/ + +/* fs management functions */ +s32 fs_init(void); +s32 fs_shutdown(void); +void fs_set_vol_flags(struct super_block *sb, u32 new_flag); +void fs_sync(struct super_block *sb, s32 do_sync); +void fs_error(struct super_block *sb); + +/* cluster management functions */ +s32 clear_cluster(struct super_block *sb, u32 clu); +s32 fat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); +s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc, CHAIN_T *p_chain); +void fat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); +void exfat_free_cluster(struct super_block *sb, CHAIN_T *p_chain, s32 do_relse); +u32 find_last_cluster(struct super_block *sb, CHAIN_T *p_chain); +s32 count_num_clusters(struct super_block *sb, CHAIN_T *dir); +s32 fat_count_used_clusters(struct super_block *sb); +s32 exfat_count_used_clusters(struct super_block *sb); +void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len); + +/* allocation bitmap management functions */ +s32 load_alloc_bitmap(struct super_block *sb); +void free_alloc_bitmap(struct super_block *sb); +s32 set_alloc_bitmap(struct super_block *sb, u32 clu); +s32 clr_alloc_bitmap(struct super_block *sb, u32 clu); +u32 test_alloc_bitmap(struct super_block *sb, u32 clu); +void sync_alloc_bitmap(struct super_block *sb); + +/* upcase table management functions */ +s32 load_upcase_table(struct super_block *sb); +void free_upcase_table(struct super_block *sb); + +/* dir entry management functions */ +u32 fat_get_entry_type(DENTRY_T *p_entry); +u32 exfat_get_entry_type(DENTRY_T *p_entry); +void fat_set_entry_type(DENTRY_T *p_entry, u32 type); +void exfat_set_entry_type(DENTRY_T *p_entry, u32 type); +u32 fat_get_entry_attr(DENTRY_T *p_entry); +u32 exfat_get_entry_attr(DENTRY_T *p_entry); +void fat_set_entry_attr(DENTRY_T *p_entry, u32 attr); +void exfat_set_entry_attr(DENTRY_T *p_entry, u32 attr); +u8 fat_get_entry_flag(DENTRY_T *p_entry); +u8 exfat_get_entry_flag(DENTRY_T *p_entry); +void fat_set_entry_flag(DENTRY_T *p_entry, u8 flag); +void exfat_set_entry_flag(DENTRY_T *p_entry, u8 flag); +u32 fat_get_entry_clu0(DENTRY_T *p_entry); +u32 exfat_get_entry_clu0(DENTRY_T *p_entry); +void fat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu); +void exfat_set_entry_clu0(DENTRY_T *p_entry, u32 start_clu); +u64 fat_get_entry_size(DENTRY_T *p_entry); +u64 exfat_get_entry_size(DENTRY_T *p_entry); +void fat_set_entry_size(DENTRY_T *p_entry, u64 size); +void exfat_set_entry_size(DENTRY_T *p_entry, u64 size); +void fat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void fat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +void exfat_set_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode); +s32 fat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size); +s32 exfat_init_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, u32 start_clu, u64 size); +s32 fat_init_ext_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +s32 exfat_init_ext_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 num_entries, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void init_dos_entry(DOS_DENTRY_T *ep, u32 type, u32 start_clu); +void init_ext_entry(EXT_DENTRY_T *ep, s32 order, u8 chksum, u16 *uniname); +void init_file_entry(FILE_DENTRY_T *ep, u32 type); +void init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size); +void init_name_entry(NAME_DENTRY_T *ep, u16 *uniname); +void fat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries); +void exfat_delete_dir_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, s32 order, s32 num_entries); + +s32 find_location(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector, s32 *offset); +DENTRY_T *get_entry_with_sector(struct super_block *sb, sector_t sector, s32 offset); +DENTRY_T *get_entry_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, sector_t *sector); +ENTRY_SET_CACHE_T *get_entry_set_in_dir(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u32 type, DENTRY_T **file_ep); +void release_entry_set(ENTRY_SET_CACHE_T *es); +s32 write_whole_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); +s32 write_partial_entries_in_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es, DENTRY_T *ep, u32 count); +s32 search_deleted_or_unused_entry(struct super_block *sb, CHAIN_T *p_dir, s32 num_entries); +s32 find_empty_entry(struct inode *inode, CHAIN_T *p_dir, s32 num_entries); +s32 fat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); +s32 exfat_find_dir_entry(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 num_entries, DOS_NAME_T *p_dosname, u32 type); +s32 fat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); +s32 exfat_count_ext_entries(struct super_block *sb, CHAIN_T *p_dir, s32 entry, DENTRY_T *p_entry); +s32 count_dos_name_entries(struct super_block *sb, CHAIN_T *p_dir, u32 type); +void update_dir_checksum(struct super_block *sb, CHAIN_T *p_dir, s32 entry); +void update_dir_checksum_with_entry_set(struct super_block *sb, ENTRY_SET_CACHE_T *es); +bool is_dir_empty(struct super_block *sb, CHAIN_T *p_dir); + +/* name conversion functions */ +s32 get_num_entries_and_dos_name(struct super_block *sb, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, s32 *entries, DOS_NAME_T *p_dosname); +void get_uni_name_from_dos_entry(struct super_block *sb, DOS_DENTRY_T *ep, UNI_NAME_T *p_uniname, u8 mode); +void fat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); +void exfat_get_uni_name_from_ext_entry(struct super_block *sb, CHAIN_T *p_dir, s32 entry, u16 *uniname); +s32 extract_uni_name_from_ext_entry(EXT_DENTRY_T *ep, u16 *uniname, s32 order); +s32 extract_uni_name_from_name_entry(NAME_DENTRY_T *ep, u16 *uniname, s32 order); +s32 fat_generate_dos_name(struct super_block *sb, CHAIN_T *p_dir, DOS_NAME_T *p_dosname); +void fat_attach_count_to_dos_name(u8 *dosname, s32 count); +s32 fat_calc_num_entries(UNI_NAME_T *p_uniname); +s32 exfat_calc_num_entries(UNI_NAME_T *p_uniname); +u8 calc_checksum_1byte(void *data, s32 len, u8 chksum); +u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type); +u32 calc_checksum_4byte(void *data, s32 len, u32 chksum, s32 type); + +/* name resolution functions */ +s32 resolve_path(struct inode *inode, char *path, CHAIN_T *p_dir, UNI_NAME_T *p_uniname); +s32 resolve_name(u8 *name, u8 **arg); + +/* file operation functions */ +s32 fat16_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 fat32_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 exfat_mount(struct super_block *sb, PBR_SECTOR_T *p_pbr); +s32 create_dir(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +s32 create_file(struct inode *inode, CHAIN_T *p_dir, UNI_NAME_T *p_uniname, u8 mode, FILE_ID_T *fid); +void remove_file(struct inode *inode, CHAIN_T *p_dir, s32 entry); +s32 rename_file(struct inode *inode, CHAIN_T *p_dir, s32 old_entry, UNI_NAME_T *p_uniname, FILE_ID_T *fid); +s32 move_file(struct inode *inode, CHAIN_T *p_olddir, s32 oldentry, CHAIN_T *p_newdir, UNI_NAME_T *p_uniname, FILE_ID_T *fid); + +/* sector read/write functions */ +s32 sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 read); +s32 sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 sync); +s32 multi_sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh, s32 num_secs, s32 read); +s32 multi_sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh, s32 num_secs, s32 sync); + +#endif /* _EXFAT_H */ diff --git a/fs/exfat/exfat_data.c b/fs/exfat/exfat_data.c new file mode 100644 index 0000000000000000000000000000000000000000..65da07aff547a2dd123ce93e31d3e601b41ef222 --- /dev/null +++ b/fs/exfat/exfat_data.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_data.c */ +/* PURPOSE : exFAT Configuable Data Definitions */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_super.h" +#include "exfat_core.h" + +/*======================================================================*/ +/* */ +/* GLOBAL VARIABLE DEFINITIONS */ +/* */ +/*======================================================================*/ + +/*----------------------------------------------------------------------*/ +/* File Manager */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Buffer Manager */ +/*----------------------------------------------------------------------*/ + +/* FAT cache */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(f_sem); +#else +DEFINE_SEMAPHORE(f_sem); +#endif +BUF_CACHE_T FAT_cache_array[FAT_CACHE_SIZE]; +BUF_CACHE_T FAT_cache_lru_list; +BUF_CACHE_T FAT_cache_hash_list[FAT_CACHE_HASH_SIZE]; + +/* buf cache */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(b_sem); +#else +DEFINE_SEMAPHORE(b_sem); +#endif +BUF_CACHE_T buf_cache_array[BUF_CACHE_SIZE]; +BUF_CACHE_T buf_cache_lru_list; +BUF_CACHE_T buf_cache_hash_list[BUF_CACHE_HASH_SIZE]; diff --git a/fs/exfat/exfat_data.h b/fs/exfat/exfat_data.h new file mode 100644 index 0000000000000000000000000000000000000000..53b0e39397fa114cd89d556efdd868c06644c91c --- /dev/null +++ b/fs/exfat/exfat_data.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_data.h */ +/* PURPOSE : Header File for exFAT Configuable Constants */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_DATA_H +#define _EXFAT_DATA_H + +#include "exfat_config.h" + +/*======================================================================*/ +/* */ +/* FFS CONFIGURATIONS */ +/* (CHANGE THIS PART IF REQUIRED) */ +/* */ +/*======================================================================*/ + +/* max number of root directory entries in FAT12/16 */ +/* (should be an exponential value of 2) */ +#define MAX_DENTRY 512 + +/* cache size (in number of sectors) */ +/* (should be an exponential value of 2) */ +#define FAT_CACHE_SIZE 128 +#define FAT_CACHE_HASH_SIZE 64 +#define BUF_CACHE_SIZE 256 +#define BUF_CACHE_HASH_SIZE 64 + +#endif /* _EXFAT_DATA_H */ diff --git a/fs/exfat/exfat_nls.c b/fs/exfat/exfat_nls.c new file mode 100644 index 0000000000000000000000000000000000000000..a48b3d05a7c4bcada7602aa96b35acf9849e5eb1 --- /dev/null +++ b/fs/exfat/exfat_nls.c @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_nls.c */ +/* PURPOSE : exFAT NLS Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" +#include "exfat_data.h" + +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_super.h" +#include "exfat_core.h" + +#include + +/*----------------------------------------------------------------------*/ +/* Global Variable Definitions */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Local Variable Definitions */ +/*----------------------------------------------------------------------*/ + +static u16 bad_dos_chars[] = { + /* + , ; = [ ] */ + 0x002B, 0x002C, 0x003B, 0x003D, 0x005B, 0x005D, + 0xFF0B, 0xFF0C, 0xFF1B, 0xFF1D, 0xFF3B, 0xFF3D, + 0 +}; + +static u16 bad_uni_chars[] = { + /* " * / : < > ? \ | */ + 0x0022, 0x002A, 0x002F, 0x003A, + 0x003C, 0x003E, 0x003F, 0x005C, 0x007C, + 0 +}; + +/*----------------------------------------------------------------------*/ +/* Local Function Declarations */ +/*----------------------------------------------------------------------*/ + +static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy); +static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy); + +/*======================================================================*/ +/* Global Function Definitions */ +/*======================================================================*/ + +u16 nls_upper(struct super_block *sb, u16 a) +{ + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + + if (EXFAT_SB(sb)->options.casesensitive) + return a; + if (p_fs->vol_utbl != NULL && (p_fs->vol_utbl)[get_col_index(a)] != NULL) + return (p_fs->vol_utbl)[get_col_index(a)][get_row_index(a)]; + else + return a; +} + +u16 *nls_wstrchr(u16 *str, u16 wchar) +{ + while (*str) { + if (*(str++) == wchar) + return str; + } + + return 0; +} + +s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b) +{ + return strncmp((void *) a, (void *) b, DOS_NAME_LENGTH); +} /* end of nls_dosname_cmp */ + +s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b) +{ + int i; + + for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) { + if (nls_upper(sb, *a) != nls_upper(sb, *b)) + return 1; + if (*a == 0x0) + return 0; + } + return 0; +} /* end of nls_uniname_cmp */ + +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy) +{ + int i, j, len, lossy = FALSE; + u8 buf[MAX_CHARSET_SIZE]; + u8 lower = 0, upper = 0; + u8 *dosname = p_dosname->name; + u16 *uniname = p_uniname->name; + u16 *p, *last_period; + struct nls_table *nls = EXFAT_SB(sb)->nls_disk; + + for (i = 0; i < DOS_NAME_LENGTH; i++) + *(dosname+i) = ' '; + + if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_CUR_DIR_NAME)) { + *(dosname) = '.'; + p_dosname->name_case = 0x0; + if (p_lossy != NULL) + *p_lossy = FALSE; + return; + } + + if (!nls_uniname_cmp(sb, uniname, (u16 *) UNI_PAR_DIR_NAME)) { + *(dosname) = '.'; + *(dosname+1) = '.'; + p_dosname->name_case = 0x0; + if (p_lossy != NULL) + *p_lossy = FALSE; + return; + } + + /* search for the last embedded period */ + last_period = NULL; + for (p = uniname; *p; p++) { + if (*p == (u16) '.') + last_period = p; + } + + i = 0; + while (i < DOS_NAME_LENGTH) { + if (i == 8) { + if (last_period == NULL) + break; + + if (uniname <= last_period) { + if (uniname < last_period) + lossy = TRUE; + uniname = last_period + 1; + } + } + + if (*uniname == (u16) '\0') { + break; + } else if (*uniname == (u16) ' ') { + lossy = TRUE; + } else if (*uniname == (u16) '.') { + if (uniname < last_period) + lossy = TRUE; + else + i = 8; + } else if (nls_wstrchr(bad_dos_chars, *uniname)) { + lossy = TRUE; + *(dosname+i) = '_'; + i++; + } else { + len = convert_uni_to_ch(nls, buf, *uniname, &lossy); + + if (len > 1) { + if ((i >= 8) && ((i+len) > DOS_NAME_LENGTH)) + break; + + if ((i < 8) && ((i+len) > 8)) { + i = 8; + continue; + } + + lower = 0xFF; + + for (j = 0; j < len; j++, i++) + *(dosname+i) = *(buf+j); + } else { /* len == 1 */ + if ((*buf >= 'a') && (*buf <= 'z')) { + *(dosname+i) = *buf - ('a' - 'A'); + + if (i < 8) + lower |= 0x08; + else + lower |= 0x10; + } else if ((*buf >= 'A') && (*buf <= 'Z')) { + *(dosname+i) = *buf; + + if (i < 8) + upper |= 0x08; + else + upper |= 0x10; + } else { + *(dosname+i) = *buf; + } + i++; + } + } + + uniname++; + } + + if (*dosname == 0xE5) + *dosname = 0x05; + + if (*uniname != 0x0) + lossy = TRUE; + + if (upper & lower) + p_dosname->name_case = 0xFF; + else + p_dosname->name_case = lower; + + if (p_lossy != NULL) + *p_lossy = lossy; +} /* end of nls_uniname_to_dosname */ + +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname) +{ + int i = 0, j, n = 0; + u8 buf[DOS_NAME_LENGTH+2]; + u8 *dosname = p_dosname->name; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_disk; + + if (*dosname == 0x05) { + *buf = 0xE5; + i++; + n++; + } + + for (; i < 8; i++, n++) { + if (*(dosname+i) == ' ') + break; + + if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x08)) + *(buf+n) = *(dosname+i) + ('a' - 'A'); + else + *(buf+n) = *(dosname+i); + } + if (*(dosname+8) != ' ') { + *(buf+n) = '.'; + n++; + } + + for (i = 8; i < DOS_NAME_LENGTH; i++, n++) { + if (*(dosname+i) == ' ') + break; + + if ((*(dosname+i) >= 'A') && (*(dosname+i) <= 'Z') && (p_dosname->name_case & 0x10)) + *(buf+n) = *(dosname+i) + ('a' - 'A'); + else + *(buf+n) = *(dosname+i); + } + *(buf+n) = '\0'; + + i = j = 0; + while (j < (MAX_NAME_LENGTH-1)) { + if (*(buf+i) == '\0') + break; + + i += convert_ch_to_uni(nls, uniname, (buf+i), NULL); + + uniname++; + j++; + } + + *uniname = (u16) '\0'; +} /* end of nls_dosname_to_uniname */ + +void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname) +{ + int i, j, len; + u8 buf[MAX_CHARSET_SIZE]; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + if (nls == NULL) { + len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, p_cstring, MAX_NAME_LENGTH); + p_cstring[len] = 0; + return; + } + + i = 0; + while (i < (MAX_NAME_LENGTH-1)) { + if (*uniname == (u16) '\0') + break; + + len = convert_uni_to_ch(nls, buf, *uniname, NULL); + + if (len > 1) { + for (j = 0; j < len; j++) + *p_cstring++ = (char) *(buf+j); + } else { /* len == 1 */ + *p_cstring++ = (char) *buf; + } + + uniname++; + i++; + } + + *p_cstring = '\0'; +} /* end of nls_uniname_to_cstring */ + +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy) +{ + int i, j, lossy = FALSE; + u8 *end_of_name; + u8 upname[MAX_NAME_LENGTH * 2]; + u16 *uniname = p_uniname->name; + struct nls_table *nls = EXFAT_SB(sb)->nls_io; + + + /* strip all trailing spaces */ + end_of_name = p_cstring + strlen((char *) p_cstring); + + while (*(--end_of_name) == ' ') { + if (end_of_name < p_cstring) + break; + } + *(++end_of_name) = '\0'; + + if (strcmp((char *) p_cstring, ".") && strcmp((char *) p_cstring, "..")) { + + /* strip all trailing periods */ + while (*(--end_of_name) == '.') { + if (end_of_name < p_cstring) + break; + } + *(++end_of_name) = '\0'; + } + + if (*p_cstring == '\0') + lossy = TRUE; + + if (nls == NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,101) + i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, uniname); +#else + i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH, UTF16_HOST_ENDIAN, uniname, MAX_NAME_LENGTH); +#endif + for (j = 0; j < i; j++) + SET16_A(upname + j * 2, nls_upper(sb, uniname[j])); + uniname[i] = '\0'; + } + else { + i = j = 0; + while (j < (MAX_NAME_LENGTH-1)) { + if (*(p_cstring+i) == '\0') + break; + + i += convert_ch_to_uni(nls, uniname, (u8 *)(p_cstring+i), &lossy); + + if ((*uniname < 0x0020) || nls_wstrchr(bad_uni_chars, *uniname)) + lossy = TRUE; + + SET16_A(upname + j * 2, nls_upper(sb, *uniname)); + + uniname++; + j++; + } + + if (*(p_cstring+i) != '\0') + lossy = TRUE; + *uniname = (u16) '\0'; + } + + p_uniname->name_len = j; + p_uniname->name_hash = calc_checksum_2byte((void *) upname, j<<1, 0, CS_DEFAULT); + + if (p_lossy != NULL) + *p_lossy = lossy; +} /* end of nls_cstring_to_uniname */ + +/*======================================================================*/ +/* Local Function Definitions */ +/*======================================================================*/ + +static s32 convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch, s32 *lossy) +{ + int len; + + *uni = 0x0; + + if (ch[0] < 0x80) { + *uni = (u16) ch[0]; + return 1; + } + + len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni); + if (len < 0) { + /* conversion failed */ + printk("%s: fail to use nls\n", __func__); + if (lossy != NULL) + *lossy = TRUE; + *uni = (u16) '_'; + if (!strcmp(nls->charset, "utf8")) + return 1; + else + return 2; + } + + return len; +} /* end of convert_ch_to_uni */ + +static s32 convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni, s32 *lossy) +{ + int len; + + ch[0] = 0x0; + + if (uni < 0x0080) { + ch[0] = (u8) uni; + return 1; + } + + len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE); + if (len < 0) { + /* conversion failed */ + printk("%s: fail to use nls\n", __func__); + if (lossy != NULL) + *lossy = TRUE; + ch[0] = '_'; + return 1; + } + + return len; + +} /* end of convert_uni_to_ch */ diff --git a/fs/exfat/exfat_nls.h b/fs/exfat/exfat_nls.h new file mode 100644 index 0000000000000000000000000000000000000000..bc516d762e903bed317cc79729cc2111829f1ead --- /dev/null +++ b/fs/exfat/exfat_nls.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_nls.h */ +/* PURPOSE : Header File for exFAT NLS Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_NLS_H +#define _EXFAT_NLS_H + +#include +#include + +#include "exfat_config.h" +#include "exfat_api.h" + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions */ +/*----------------------------------------------------------------------*/ + +#define NUM_UPCASE 2918 + +#define DOS_CUR_DIR_NAME ". " +#define DOS_PAR_DIR_NAME ".. " + +#ifdef __LITTLE_ENDIAN +#define UNI_CUR_DIR_NAME ".\0" +#define UNI_PAR_DIR_NAME ".\0.\0" +#else +#define UNI_CUR_DIR_NAME "\0." +#define UNI_PAR_DIR_NAME "\0.\0." +#endif + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +/* DOS name stucture */ +typedef struct { + u8 name[DOS_NAME_LENGTH]; + u8 name_case; +} DOS_NAME_T; + +/* unicode name stucture */ +typedef struct { + u16 name[MAX_NAME_LENGTH]; + u16 name_hash; + u8 name_len; +} UNI_NAME_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +/* NLS management function */ +u16 nls_upper(struct super_block *sb, u16 a); +s32 nls_dosname_cmp(struct super_block *sb, u8 *a, u8 *b); +s32 nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b); +void nls_uniname_to_dosname(struct super_block *sb, DOS_NAME_T *p_dosname, UNI_NAME_T *p_uniname, s32 *p_lossy); +void nls_dosname_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, DOS_NAME_T *p_dosname); +void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring, UNI_NAME_T *p_uniname); +void nls_cstring_to_uniname(struct super_block *sb, UNI_NAME_T *p_uniname, u8 *p_cstring, s32 *p_lossy); + +#endif /* _EXFAT_NLS_H */ diff --git a/fs/exfat/exfat_oal.c b/fs/exfat/exfat_oal.c new file mode 100644 index 0000000000000000000000000000000000000000..0b23445f343a30885ba774a573d9432d1618d85c --- /dev/null +++ b/fs/exfat/exfat_oal.c @@ -0,0 +1,202 @@ +/* Some of the source code in this file came from "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_oal.c */ +/* PURPOSE : exFAT OS Adaptation Layer */ +/* (Semaphore Functions & Real-Time Clock Functions) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include +#include + +#include "exfat_config.h" +#include "exfat_api.h" +#include "exfat_oal.h" + +/*======================================================================*/ +/* */ +/* SEMAPHORE FUNCTIONS */ +/* */ +/*======================================================================*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +DECLARE_MUTEX(z_sem); +#else +DEFINE_SEMAPHORE(z_sem); +#endif + +s32 sm_init(struct semaphore *sm) +{ + sema_init(sm, 1); + return 0; +} /* end of sm_init */ + +s32 sm_P(struct semaphore *sm) +{ + down(sm); + return 0; +} /* end of sm_P */ + +void sm_V(struct semaphore *sm) +{ + up(sm); +} /* end of sm_V */ + + +/*======================================================================*/ +/* */ +/* REAL-TIME CLOCK FUNCTIONS */ +/* */ +/*======================================================================*/ + +extern struct timezone sys_tz; + +/* + * The epoch of FAT timestamp is 1980. + * : bits : value + * date: 0 - 4: day (1 - 31) + * date: 5 - 8: month (1 - 12) + * date: 9 - 15: year (0 - 127) from 1980 + * time: 0 - 4: sec (0 - 29) 2sec counts + * time: 5 - 10: min (0 - 59) + * time: 11 - 15: hour (0 - 23) + */ +#define UNIX_SECS_1980 315532800L + +#if BITS_PER_LONG == 64 +#define UNIX_SECS_2108 4354819200L +#endif +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA_DECADE (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while (0) + +/* Linear day numbers of the respective 1sts in non-leap years. */ +static time_t accum_days_in_year[] = { + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, +}; + +TIMESTAMP_T *tm_current(TIMESTAMP_T *tp) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) + struct timespec ts; +#else + struct timespec64 ts; +#endif + time_t second, day, leap_day, month, year; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) + ts = CURRENT_TIME_SEC; +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) + ktime_get_real_ts(&ts); +#else + ktime_get_real_ts64(&ts); +#endif + + second = ts.tv_sec; + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (second < UNIX_SECS_1980) { + tp->sec = 0; + tp->min = 0; + tp->hour = 0; + tp->day = 1; + tp->mon = 1; + tp->year = 0; + return tp; + } +#if BITS_PER_LONG == 64 + if (second >= UNIX_SECS_2108) { + tp->sec = 59; + tp->min = 59; + tp->hour = 23; + tp->day = 31; + tp->mon = 12; + tp->year = 127; + return tp; + } +#endif + + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; + year = day / 365; + + MAKE_LEAP_YEAR(leap_day, year); + if (year * 365 + leap_day > day) + year--; + + MAKE_LEAP_YEAR(leap_day, year); + + day -= year * 365 + leap_day; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { + month = 2; + } else { + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) + day--; + for (month = 1; month < 12; month++) { + if (accum_days_in_year[month + 1] > day) + break; + } + } + day -= accum_days_in_year[month]; + + tp->sec = second % SECS_PER_MIN; + tp->min = (second / SECS_PER_MIN) % 60; + tp->hour = (second / SECS_PER_HOUR) % 24; + tp->day = day + 1; + tp->mon = month; + tp->year = year; + + return tp; +} /* end of tm_current */ diff --git a/fs/exfat/exfat_oal.h b/fs/exfat/exfat_oal.h new file mode 100644 index 0000000000000000000000000000000000000000..b6dd7897ab6e2f3f4276b2e32429a5f3aa1d0d36 --- /dev/null +++ b/fs/exfat/exfat_oal.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_oal.h */ +/* PURPOSE : Header File for exFAT OS Adaptation Layer */ +/* (Semaphore Functions & Real-Time Clock Functions) */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#ifndef _EXFAT_OAL_H +#define _EXFAT_OAL_H + +#include +#include "exfat_config.h" +#include + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Constant & Macro Definitions (Non-Configurable) */ +/*----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------*/ +/* Type Definitions */ +/*----------------------------------------------------------------------*/ + +typedef struct { + u16 sec; /* 0 ~ 59 */ + u16 min; /* 0 ~ 59 */ + u16 hour; /* 0 ~ 23 */ + u16 day; /* 1 ~ 31 */ + u16 mon; /* 1 ~ 12 */ + u16 year; /* 0 ~ 127 (since 1980) */ +} TIMESTAMP_T; + +/*----------------------------------------------------------------------*/ +/* External Function Declarations */ +/*----------------------------------------------------------------------*/ + +s32 sm_init(struct semaphore *sm); +s32 sm_P(struct semaphore *sm); +void sm_V(struct semaphore *sm); + +TIMESTAMP_T *tm_current(TIMESTAMP_T *tm); + +#endif /* _EXFAT_OAL_H */ diff --git a/fs/exfat/exfat_super.c b/fs/exfat/exfat_super.c new file mode 100644 index 0000000000000000000000000000000000000000..51893f1b6ab7d363bd6b6685ab228563c86926aa --- /dev/null +++ b/fs/exfat/exfat_super.c @@ -0,0 +1,2728 @@ +/* Some of the source code in this file came from "linux/fs/fat/file.c","linux/fs/fat/inode.c" and "linux/fs/fat/misc.c". */ +/* + * linux/fs/fat/file.c + * + * Written 1992,1993 by Werner Almesberger + * + * regular file handling primitives for fat-based filesystems + */ + +/* + * linux/fs/fat/inode.c + * + * Written 1992,1993 by Werner Almesberger + * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner + * Rewritten for the constant inumbers support by Al Viro + * + * Fixes: + * + * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 + */ + +/* + * linux/fs/fat/misc.c + * + * Written 1992,1993 by Werner Almesberger + * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980 + * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru) + */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) +#include +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exfat_version.h" +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_core.h" + +#include "exfat_super.h" + +static struct kmem_cache *exfat_inode_cachep; + +static int exfat_default_codepage = CONFIG_EXFAT_DEFAULT_CODEPAGE; +static char exfat_default_iocharset[] = CONFIG_EXFAT_DEFAULT_IOCHARSET; + +extern struct timezone sys_tz; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) +#define timespec_compat timespec64 +#else +#define timespec_compat timespec +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) +#define current_time(x) (CURRENT_TIME_SEC) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0) +#define USE_NEW_IVERSION_API +#define INC_IVERSION(x) (inode_inc_iversion(x)) +#define GET_IVERSION(x) (inode_peek_iversion_raw(x)) +#define SET_IVERSION(x,y) (inode_set_iversion(x, y)) +#else +#define INC_IVERSION(x) (x->i_version++) +#define GET_IVERSION(x) (x->i_version) +#define SET_IVERSION(x,y) (x->i_version = y) +#endif + +#define CHECK_ERR(x) BUG_ON(x) + +#define UNIX_SECS_1980 315532800L + +#if BITS_PER_LONG == 64 +#define UNIX_SECS_2108 4354819200L +#endif +/* days between 1.1.70 and 1.1.80 (2 leap days) */ +#define DAYS_DELTA_DECADE (365 * 10 + 2) +/* 120 (2100 - 1980) isn't leap year */ +#define NO_LEAP_YEAR_2100 (120) +#define IS_LEAP_YEAR(y) (!((y) & 0x3) && (y) != NO_LEAP_YEAR_2100) + +#define SECS_PER_MIN (60) +#define SECS_PER_HOUR (60 * SECS_PER_MIN) +#define SECS_PER_DAY (24 * SECS_PER_HOUR) + +#define MAKE_LEAP_YEAR(leap_year, year) \ + do { \ + if (unlikely(year > NO_LEAP_YEAR_2100)) \ + leap_year = ((year + 3) / 4) - 1; \ + else \ + leap_year = ((year + 3) / 4); \ + } while (0) + +/* Linear day numbers of the respective 1sts in non-leap years. */ +static time_t accum_days_in_year[] = { + /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, +}; + +static void _exfat_truncate(struct inode *inode, loff_t old_size); + +/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ +void exfat_time_fat2unix(struct exfat_sb_info *sbi, struct timespec_compat *ts, + DATE_TIME_T *tp) +{ + time_t year = tp->Year; + time_t ld; + + MAKE_LEAP_YEAR(ld, year); + + if (IS_LEAP_YEAR(year) && (tp->Month) > 2) + ld++; + + ts->tv_sec = tp->Second + tp->Minute * SECS_PER_MIN + + tp->Hour * SECS_PER_HOUR + + (year * 365 + ld + accum_days_in_year[(tp->Month)] + (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY + + sys_tz.tz_minuteswest * SECS_PER_MIN; + ts->tv_nsec = 0; +} + +/* Convert linear UNIX date to a FAT time/date pair. */ +void exfat_time_unix2fat(struct exfat_sb_info *sbi, struct timespec_compat *ts, + DATE_TIME_T *tp) +{ + time_t second = ts->tv_sec; + time_t day, month, year; + time_t ld; + + second -= sys_tz.tz_minuteswest * SECS_PER_MIN; + + /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ + if (second < UNIX_SECS_1980) { + tp->Second = 0; + tp->Minute = 0; + tp->Hour = 0; + tp->Day = 1; + tp->Month = 1; + tp->Year = 0; + return; + } +#if (BITS_PER_LONG == 64) + if (second >= UNIX_SECS_2108) { + tp->Second = 59; + tp->Minute = 59; + tp->Hour = 23; + tp->Day = 31; + tp->Month = 12; + tp->Year = 127; + return; + } +#endif + day = second / SECS_PER_DAY - DAYS_DELTA_DECADE; + year = day / 365; + MAKE_LEAP_YEAR(ld, year); + if (year * 365 + ld > day) + year--; + + MAKE_LEAP_YEAR(ld, year); + day -= year * 365 + ld; + + if (IS_LEAP_YEAR(year) && day == accum_days_in_year[3]) { + month = 2; + } else { + if (IS_LEAP_YEAR(year) && day > accum_days_in_year[3]) + day--; + for (month = 1; month < 12; month++) { + if (accum_days_in_year[month + 1] > day) + break; + } + } + day -= accum_days_in_year[month]; + + tp->Second = second % SECS_PER_MIN; + tp->Minute = (second / SECS_PER_MIN) % 60; + tp->Hour = (second / SECS_PER_HOUR) % 24; + tp->Day = day + 1; + tp->Month = month; + tp->Year = year; +} + +static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static int exfat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +#else +static long exfat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static int exfat_sync_inode(struct inode *inode); +static struct inode *exfat_build_inode(struct super_block *sb, FILE_ID_T *fid, loff_t i_pos); +static void exfat_detach(struct inode *inode); +static void exfat_attach(struct inode *inode, loff_t i_pos); +static inline unsigned long exfat_hash(loff_t i_pos); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +static int exfat_write_inode(struct inode *inode, int wait); +#else +static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc); +#endif +static void exfat_write_super(struct super_block *sb); + +static void __lock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + lock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_lock(&sbi->s_lock); +#endif +} + +static void __unlock_super(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + unlock_super(sb); +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + mutex_unlock(&sbi->s_lock); +#endif +} + +static int __is_sb_dirty(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + return sb->s_dirt; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + return sbi->s_dirt; +#endif +} + +static void __set_sb_clean(struct super_block *sb) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + sb->s_dirt = 0; +#else + struct exfat_sb_info *sbi = EXFAT_SB(sb); + sbi->s_dirt = 0; +#endif +} + +static int __exfat_revalidate(struct dentry *dentry) +{ + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_revalidate(struct dentry *dentry, unsigned int flags) +#else +static int exfat_revalidate(struct dentry *dentry, struct nameidata *nd) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + if (flags & LOOKUP_RCU) + return -ECHILD; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + if (dentry->d_inode) + return 1; + return __exfat_revalidate(dentry); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags) +#else +static int exfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + if (flags & LOOKUP_RCU) + return -ECHILD; +#else + unsigned int flags; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (nd && nd->flags & LOOKUP_RCU) + return -ECHILD; +#endif + + flags = nd ? nd->flags : 0; +#endif + + if (dentry->d_inode) + return 1; + + if (!flags) + return 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,00) + if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; +#else + if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { + if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) + return 0; + } +#endif + + return __exfat_revalidate(dentry); +} + +static unsigned int __exfat_striptail_len(unsigned int len, const char *name) +{ + while (len && name[len - 1] == '.') + len--; + return len; +} + +static unsigned int exfat_striptail_len(const struct qstr *qstr) +{ + return __exfat_striptail_len(qstr->len, qstr->name); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_d_hash(struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hash(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) + qstr->hash = full_name_hash(dentry, qstr->name, exfat_striptail_len(qstr)); +#else + qstr->hash = full_name_hash(qstr->name, exfat_striptail_len(qstr)); +#endif + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_d_hashi(struct dentry *dentry, struct qstr *qstr) +#else +static int exfat_d_hashi(const struct dentry *dentry, const struct inode *inode, + struct qstr *qstr) +#endif +{ + struct super_block *sb = dentry->d_sb; + const unsigned char *name; + unsigned int len; + unsigned long hash; + + name = qstr->name; + len = exfat_striptail_len(qstr); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) + hash = init_name_hash(dentry); +#else + hash = init_name_hash(); +#endif + while (len--) + hash = partial_name_hash(nls_upper(sb, *name++), hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) +static int exfat_cmpi(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_cmpi(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_cmpi(struct dentry *parent, struct qstr *a, struct qstr *b) +#else +static int exfat_cmpi(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) + struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io; +#else + struct nls_table *t = EXFAT_SB(parent->d_sb)->nls_io; +#endif + unsigned int alen, blen; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + alen = exfat_striptail_len(a); + blen = exfat_striptail_len(b); +#else + alen = exfat_striptail_len(name); + blen = __exfat_striptail_len(len, str); +#endif + if (alen == blen) { + if (t == NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (strncasecmp(a->name, b->name, alen) == 0) +#else + if (strncasecmp(name->name, str, alen) == 0) +#endif + return 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + } else if (nls_strnicmp(t, a->name, b->name, alen) == 0) +#else + } else if (nls_strnicmp(t, name->name, str, alen) == 0) +#endif + return 0; + } + return 1; +} +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) +static int exfat_cmp(const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_cmp(const struct dentry *parent, const struct dentry *dentry, + unsigned int len, const char *str, const struct qstr *name) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) +static int exfat_cmp(struct dentry *parent, struct qstr *a, + struct qstr *b) +#else +static int exfat_cmp(const struct dentry *parent, const struct inode *pinode, + const struct dentry *dentry, const struct inode *inode, + unsigned int len, const char *str, const struct qstr *name) +#endif +{ + unsigned int alen, blen; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + alen = exfat_striptail_len(a); + blen = exfat_striptail_len(b); +#else + alen = exfat_striptail_len(name); + blen = __exfat_striptail_len(len, str); +#endif + if (alen == blen) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + if (strncmp(a->name, b->name, alen) == 0) +#else + if (strncmp(name->name, str, alen) == 0) +#endif + return 0; + } + return 1; +} + +static const struct dentry_operations exfat_ci_dentry_ops = { + .d_revalidate = exfat_revalidate_ci, + .d_hash = exfat_d_hashi, + .d_compare = exfat_cmpi, +}; + +static const struct dentry_operations exfat_dentry_ops = { + .d_revalidate = exfat_revalidate, + .d_hash = exfat_d_hash, + .d_compare = exfat_cmp, +}; + +/*======================================================================*/ +/* Directory Entry Operations */ +/*======================================================================*/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) +static int exfat_readdir(struct file *filp, struct dir_context *ctx) +#else +static int exfat_readdir(struct file *filp, void *dirent, filldir_t filldir) +#endif +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) + struct inode *inode = file_inode(filp); +#else + struct inode *inode = filp->f_path.dentry->d_inode; +#endif + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + BD_INFO_T *p_bd = &(EXFAT_SB(sb)->bd_info); + DIR_ENTRY_T de; + unsigned long inum; + loff_t cpos; + int err = 0; + + __lock_super(sb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + cpos = ctx->pos; +#else + cpos = filp->f_pos; +#endif + /* Fake . and .. for the root directory. */ + if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) { + while (cpos < 2) { + if (inode->i_ino == EXFAT_ROOT_INO) + inum = EXFAT_ROOT_INO; + else if (cpos == 0) + inum = inode->i_ino; + else /* (cpos == 1) */ + inum = parent_ino(filp->f_path.dentry); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + if (!dir_emit_dots(filp, ctx)) +#else + if (filldir(dirent, "..", cpos+1, cpos, inum, DT_DIR) < 0) +#endif + goto out; + cpos++; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos++; +#else + filp->f_pos++; +#endif + } + if (cpos == 2) + cpos = 0; + } + if (cpos & (DENTRY_SIZE - 1)) { + err = -ENOENT; + goto out; + } + +get_new: + EXFAT_I(inode)->fid.size = i_size_read(inode); + EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS; + + err = FsReadDir(inode, &de); + if (err) { + /* at least we tried to read a sector + * move cpos to next sector position (should be aligned) + */ + if (err == FFS_MEDIAERR) { + cpos += 1 << p_bd->sector_size_bits; + cpos &= ~((1 << p_bd->sector_size_bits)-1); + } + + err = -EIO; + goto end_of_dir; + } + + cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS; + + if (!de.Name[0]) + goto end_of_dir; + + if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) { + inum = inode->i_ino; + } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) { + inum = parent_ino(filp->f_path.dentry); + } else { + loff_t i_pos = ((loff_t) EXFAT_I(inode)->fid.start_clu << 32) | + ((EXFAT_I(inode)->fid.rwoffset-1) & 0xffffffff); + + struct inode *tmp = exfat_iget(sb, i_pos); + if (tmp) { + inum = tmp->i_ino; + iput(tmp); + } else { + inum = iunique(sb, EXFAT_ROOT_INO); + } + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + if (!dir_emit(ctx, de.Name, strlen(de.Name), inum, + (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG)) +#else + if (filldir(dirent, de.Name, strlen(de.Name), cpos-1, inum, + (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG) < 0) +#endif + goto out; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif + goto get_new; + +end_of_dir: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + ctx->pos = cpos; +#else + filp->f_pos = cpos; +#endif +out: + __unlock_super(sb); + return err; +} + +static int exfat_ioctl_volume_id(struct inode *dir) +{ + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + + return p_fs->vol_id; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static int exfat_generic_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +#else +static long exfat_generic_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +#endif +{ +#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)) + #if !(LINUX_VERSION_CODE < KERNEL_VERSION(3,18,3)) + struct inode *inode = filp->f_path.dentry->d_inode; + #else + struct inode *inode = filp->f_dentry->d_inode; + #endif +#endif +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + unsigned int flags; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + + switch (cmd) { + case EXFAT_IOCTL_GET_VOLUME_ID: + return exfat_ioctl_volume_id(inode); +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + case EXFAT_IOC_GET_DEBUGFLAGS: { + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + flags = sbi->debug_flags; + return put_user(flags, (int __user *)arg); + } + case EXFAT_IOC_SET_DEBUGFLAGS: { + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (get_user(flags, (int __user *) arg)) + return -EFAULT; + + __lock_super(sb); + sbi->debug_flags = flags; + __unlock_super(sb); + + return 0; + } +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + default: + return -ENOTTY; /* Inappropriate ioctl for device */ + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +static int exfat_file_fsync(struct file *filp, struct dentry *dentry, + int datasync) +#else +static int exfat_file_fsync(struct file *filp, int datasync) +#endif +{ + struct inode *inode = filp->f_mapping->host; + struct super_block *sb = inode->i_sb; + int res, err; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + res = simple_fsync(filp, dentry, datasync); +#else + res = generic_file_fsync(filp, datasync); +#endif + err = FsSyncVol(sb, 1); + + return res ? res : err; +} +#endif + +const struct file_operations exfat_dir_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) + .iterate = exfat_readdir, +#else + .readdir = exfat_readdir, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = exfat_generic_ioctl, + .fsync = exfat_file_fsync, +#else + .unlocked_ioctl = exfat_generic_ioctl, + .fsync = generic_file_fsync, +#endif +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + bool excl) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, + struct nameidata *nd) +#else +static int exfat_create(struct inode *dir, struct dentry *dentry, int mode, + struct nameidata *nd) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + FILE_ID_T fid; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_create entered\n"); + + err = FsCreateFile(dir, (u8 *) dentry->d_name.name, FM_REGULAR, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else if (err == FFS_NAMETOOLONG) + err = -ENAMETOOLONG; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + INC_IVERSION(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unnecessary. */ + + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_create exited\n"); + return err; +} + +static int exfat_find(struct inode *dir, struct qstr *qname, + FILE_ID_T *fid) +{ + int err; + + if (qname->len == 0) + return -ENOENT; + + err = FsLookupFile(dir, (u8 *) qname->name, fid); + if (err) + return -ENOENT; + + return 0; +} + +static int exfat_d_anon_disconn(struct dentry *dentry) +{ + return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +#else +static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + struct dentry *alias; + int err; + FILE_ID_T fid; + loff_t i_pos; + u64 ret; + mode_t i_mode; + + __lock_super(sb); + DPRINTK("exfat_lookup entered\n"); + err = exfat_find(dir, &dentry->d_name, &fid); + if (err) { + if (err == -ENOENT) { + inode = NULL; + goto out; + } + goto error; + } + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto error; + } + + i_mode = inode->i_mode; + if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) { + EXFAT_I(inode)->target = kmalloc(i_size_read(inode)+1, GFP_KERNEL); + if (!EXFAT_I(inode)->target) { + err = -ENOMEM; + goto error; + } + FsReadFile(dir, &fid, EXFAT_I(inode)->target, i_size_read(inode), &ret); + *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0'; + } + + alias = d_find_alias(inode); + if (alias && !exfat_d_anon_disconn(alias)) { + CHECK_ERR(d_unhashed(alias)); + if (!S_ISDIR(i_mode)) + d_move(alias, dentry); + iput(inode); + __unlock_super(sb); + DPRINTK("exfat_lookup exited 1\n"); + return alias; + } else { + dput(alias); + } +out: + __unlock_super(sb); + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) + dentry->d_op = sb->s_root->d_op; + dentry = d_splice_alias(inode, dentry); + if (dentry) { + dentry->d_op = sb->s_root->d_op; + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + } +#else + dentry = d_splice_alias(inode, dentry); + if (dentry) + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); +#endif + DPRINTK("exfat_lookup exited 2\n"); + return dentry; + +error: + __unlock_super(sb); + DPRINTK("exfat_lookup exited 3\n"); + return ERR_PTR(err); +} + +static int exfat_unlink(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = dir->i_sb; + int err; + + __lock_super(sb); + + DPRINTK("exfat_unlink entered\n"); + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsRemoveFile(dir, &(EXFAT_I(inode)->fid)); + if (err) { + if (err == FFS_PERMISSIONERR) + err = -EPERM; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = current_time(inode); + exfat_detach(inode); + remove_inode_hash(inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_unlink exited\n"); + return err; +} + +static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *target) +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + FILE_ID_T fid; + loff_t i_pos; + int err; + u64 len = (u64) strlen(target); + u64 ret; + + __lock_super(sb); + + DPRINTK("exfat_symlink entered\n"); + + err = FsCreateFile(dir, (u8 *) dentry->d_name.name, FM_SYMLINK, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + + err = FsWriteFile(dir, &fid, (char *) target, len, &ret); + + if (err) { + FsRemoveFile(dir, &fid); + + if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + + INC_IVERSION(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + INC_IVERSION(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + EXFAT_I(inode)->target = kmalloc(len+1, GFP_KERNEL); + if (!EXFAT_I(inode)->target) { + err = -ENOMEM; + goto out; + } + memcpy(EXFAT_I(inode)->target, target, len+1); + + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_symlink exited\n"); + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +#else +static int exfat_mkdir(struct inode *dir, struct dentry *dentry, int mode) +#endif +{ + struct super_block *sb = dir->i_sb; + struct inode *inode; + FILE_ID_T fid; + loff_t i_pos; + int err; + + __lock_super(sb); + + DPRINTK("exfat_mkdir entered\n"); + + err = FsCreateDir(dir, (u8 *) dentry->d_name.name, &fid); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_FULL) + err = -ENOSPC; + else if (err == FFS_NAMETOOLONG) + err = -ENAMETOOLONG; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + inc_nlink(dir); + + i_pos = ((loff_t) fid.dir.dir << 32) | (fid.entry & 0xffffffff); + + inode = exfat_build_inode(sb, &fid, i_pos); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + INC_IVERSION(inode); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + /* timestamp is already written, so mark_inode_dirty() is unneeded. */ + + dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); + d_instantiate(dentry, inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_mkdir exited\n"); + return err; +} + +static int exfat_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + struct super_block *sb = dir->i_sb; + int err; + + __lock_super(sb); + + DPRINTK("exfat_rmdir entered\n"); + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsRemoveDir(dir, &(EXFAT_I(inode)->fid)); + if (err) { + if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -ENOTEMPTY; + else if (err == FFS_NOTFOUND) + err = -ENOENT; + else if (err == FFS_DIRBUSY) + err = -EBUSY; + else + err = -EIO; + goto out; + } + INC_IVERSION(dir); + dir->i_mtime = dir->i_atime = current_time(dir); + if (IS_DIRSYNC(dir)) + (void) exfat_sync_inode(dir); + else + mark_inode_dirty(dir); + drop_nlink(dir); + + clear_nlink(inode); + inode->i_mtime = inode->i_atime = current_time(inode); + exfat_detach(inode); + remove_inode_hash(inode); + +out: + __unlock_super(sb); + DPRINTK("exfat_rmdir exited\n"); + return err; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) +static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +#else +static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +#endif +{ + struct inode *old_inode, *new_inode; + struct super_block *sb = old_dir->i_sb; + loff_t i_pos; + int err; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + if (flags) + return -EINVAL; +#endif + + __lock_super(sb); + + DPRINTK("exfat_rename entered\n"); + + old_inode = old_dentry->d_inode; + new_inode = new_dentry->d_inode; + + EXFAT_I(old_inode)->fid.size = i_size_read(old_inode); + + err = FsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, new_dentry); + if (err) { + if (err == FFS_PERMISSIONERR) + err = -EPERM; + else if (err == FFS_INVALIDPATH) + err = -EINVAL; + else if (err == FFS_FILEEXIST) + err = -EEXIST; + else if (err == FFS_NOTFOUND) + err = -ENOENT; + else if (err == FFS_FULL) + err = -ENOSPC; + else + err = -EIO; + goto out; + } + INC_IVERSION(new_dir); + new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = current_time(new_dir); + if (IS_DIRSYNC(new_dir)) + (void) exfat_sync_inode(new_dir); + else + mark_inode_dirty(new_dir); + + i_pos = ((loff_t) EXFAT_I(old_inode)->fid.dir.dir << 32) | + (EXFAT_I(old_inode)->fid.entry & 0xffffffff); + + exfat_detach(old_inode); + exfat_attach(old_inode, i_pos); + if (IS_DIRSYNC(new_dir)) + (void) exfat_sync_inode(old_inode); + else + mark_inode_dirty(old_inode); + + if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) { + drop_nlink(old_dir); + if (!new_inode) + inc_nlink(new_dir); + } + INC_IVERSION(old_dir); + old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); + if (IS_DIRSYNC(old_dir)) + (void) exfat_sync_inode(old_dir); + else + mark_inode_dirty(old_dir); + + if (new_inode) { + exfat_detach(new_inode); + drop_nlink(new_inode); + if (S_ISDIR(new_inode->i_mode)) + drop_nlink(new_inode); + new_inode->i_ctime = current_time(new_inode); + } + +out: + __unlock_super(sb); + DPRINTK("exfat_rename exited\n"); + return err; +} + +static int exfat_cont_expand(struct inode *inode, loff_t size) +{ + struct address_space *mapping = inode->i_mapping; + loff_t start = i_size_read(inode), count = size - i_size_read(inode); + int err, err2; + + err = generic_cont_expand_simple(inode, size); + if (err != 0) + return err; + + inode->i_ctime = inode->i_mtime = current_time(inode); + mark_inode_dirty(inode); + + if (IS_SYNC(inode)) { + err = filemap_fdatawrite_range(mapping, start, start + count - 1); + err2 = sync_mapping_buffers(mapping); + err = (err) ? (err) : (err2); + err2 = write_inode_now(inode, 1); + err = (err) ? (err) : (err2); + if (!err) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + err = wait_on_page_writeback_range(mapping, + start >> PAGE_CACHE_SHIFT, + (start + count - 1) >> PAGE_CACHE_SHIFT); +#else + err = filemap_fdatawait_range(mapping, start, start + count - 1); +#endif + } + return err; +} + +static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode) +{ + mode_t allow_utime = sbi->options.allow_utime; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + if (!uid_eq(current_fsuid(), inode->i_uid)) +#else + if (current_fsuid() != inode->i_uid) +#endif + { + if (in_group_p(inode->i_gid)) + allow_utime >>= 3; + if (allow_utime & MAY_WRITE) + return 1; + } + + /* use a default check */ + return 0; +} + +static int exfat_sanitize_mode(const struct exfat_sb_info *sbi, + struct inode *inode, umode_t *mode_ptr) +{ + mode_t i_mode, mask, perm; + + i_mode = inode->i_mode; + + if (S_ISREG(i_mode) || S_ISLNK(i_mode)) + mask = sbi->options.fs_fmask; + else + mask = sbi->options.fs_dmask; + + perm = *mode_ptr & ~(S_IFMT | mask); + + /* Of the r and x bits, all (subject to umask) must be present.*/ + if ((perm & (S_IRUGO | S_IXUGO)) != (i_mode & (S_IRUGO|S_IXUGO))) + return -EPERM; + + if (exfat_mode_can_hold_ro(inode)) { + /* Of the w bits, either all (subject to umask) or none must be present. */ + if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) + return -EPERM; + } else { + /* If exfat_mode_can_hold_ro(inode) is false, can't change w bits. */ + if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) + return -EPERM; + } + + *mode_ptr &= S_IFMT | perm; + + return 0; +} + +static int exfat_setattr(struct dentry *dentry, struct iattr *attr) +{ + + struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb); + struct inode *inode = dentry->d_inode; + unsigned int ia_valid; + int error; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) + loff_t old_size; +#endif + + DPRINTK("exfat_setattr entered\n"); + + if ((attr->ia_valid & ATTR_SIZE) + && (attr->ia_size > i_size_read(inode))) { + error = exfat_cont_expand(inode, attr->ia_size); + if (error || attr->ia_valid == ATTR_SIZE) + return error; + attr->ia_valid &= ~ATTR_SIZE; + } + + ia_valid = attr->ia_valid; + + if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) + && exfat_allow_set_time(sbi, inode)) { + attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + error = setattr_prepare(dentry, attr); +#else + error = inode_change_ok(inode, attr); +#endif + attr->ia_valid = ia_valid; + if (error) + return error; + + if (((attr->ia_valid & ATTR_UID) && +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) || + ((attr->ia_valid & ATTR_GID) && + (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) || +#else + (attr->ia_uid != sbi->options.fs_uid)) || + ((attr->ia_valid & ATTR_GID) && + (attr->ia_gid != sbi->options.fs_gid)) || +#endif + ((attr->ia_valid & ATTR_MODE) && + (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) { + return -EPERM; + } + + /* + * We don't return -EPERM here. Yes, strange, but this is too + * old behavior. + */ + if (attr->ia_valid & ATTR_MODE) { + if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) + attr->ia_valid &= ~ATTR_MODE; + } + + EXFAT_I(inode)->fid.size = i_size_read(inode); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + if (attr->ia_valid) + error = inode_setattr(inode, attr); +#else + if (attr->ia_valid & ATTR_SIZE) { + old_size = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_write(&EXFAT_I(inode)->truncate_lock); + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); + up_write(&EXFAT_I(inode)->truncate_lock); +#else + truncate_setsize(inode, attr->ia_size); + _exfat_truncate(inode, old_size); +#endif + } + setattr_copy(inode, attr); + mark_inode_dirty(inode); +#endif + + DPRINTK("exfat_setattr exited\n"); + return error; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +static int exfat_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + struct inode *inode = path->dentry->d_inode; +#else +static int exfat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; +#endif + + DPRINTK("exfat_getattr entered\n"); + + generic_fillattr(inode, stat); + stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size; + + DPRINTK("exfat_getattr exited\n"); + return 0; +} + +const struct inode_operations exfat_dir_inode_operations = { + .create = exfat_create, + .lookup = exfat_lookup, + .unlink = exfat_unlink, + .symlink = exfat_symlink, + .mkdir = exfat_mkdir, + .rmdir = exfat_rmdir, + .rename = exfat_rename, + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; + +/*======================================================================*/ +/* File Operations */ +/*======================================================================*/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0) +static const char *exfat_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) +{ + struct exfat_inode_info *ei = EXFAT_I(inode); + if (ei->target != NULL) { + char *cookie = ei->target; + if (cookie != NULL) { + return (char *)(ei->target); + } + } + return NULL; +} +#elif LINUX_VERSION_CODE > KERNEL_VERSION(4,1,0) +static const char *exfat_follow_link(struct dentry *dentry, void **cookie) +{ + struct exfat_inode_info *ei = EXFAT_I(dentry->d_inode); + return *cookie = (char *)(ei->target); +} +#else +static void *exfat_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct exfat_inode_info *ei = EXFAT_I(dentry->d_inode); + nd_set_link(nd, (char *)(ei->target)); + return NULL; +} +#endif + +const struct inode_operations exfat_symlink_inode_operations = { + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) + .readlink = generic_readlink, + #endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) + .follow_link = exfat_follow_link, + #endif + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,5,0) + .get_link = exfat_get_link, + #endif +}; + +static int exfat_file_release(struct inode *inode, struct file *filp) +{ + struct super_block *sb = inode->i_sb; + + EXFAT_I(inode)->fid.size = i_size_read(inode); + FsSyncVol(sb, 0); + return 0; +} + +const struct file_operations exfat_file_operations = { + .llseek = generic_file_llseek, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,1,0) + .read = new_sync_read, + .write = new_sync_write, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, +#endif + .mmap = generic_file_mmap, + .release = exfat_file_release, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .ioctl = exfat_generic_ioctl, + .fsync = exfat_file_fsync, +#else + .unlocked_ioctl = exfat_generic_ioctl, + .fsync = generic_file_fsync, +#endif + .splice_read = generic_file_splice_read, +}; + +static void _exfat_truncate(struct inode *inode, loff_t old_size) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + int err; + + __lock_super(sb); + + /* + * This protects against truncating a file bigger than it was then + * trying to write into the hole. + */ + if (EXFAT_I(inode)->mmu_private > i_size_read(inode)) + EXFAT_I(inode)->mmu_private = i_size_read(inode); + + if (EXFAT_I(inode)->fid.start_clu == 0) + goto out; + + err = FsTruncateFile(inode, old_size, i_size_read(inode)); + if (err) + goto out; + + inode->i_ctime = inode->i_mtime = current_time(inode); + if (IS_DIRSYNC(inode)) + (void) exfat_sync_inode(inode); + else + mark_inode_dirty(inode); + + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; +out: + __unlock_super(sb); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) +static void exfat_truncate(struct inode *inode) +{ + _exfat_truncate(inode, i_size_read(inode)); +} +#endif + +const struct inode_operations exfat_file_inode_operations = { +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) + .truncate = exfat_truncate, +#endif + .setattr = exfat_setattr, + .getattr = exfat_getattr, +}; + +/*======================================================================*/ +/* Address Space Operations */ +/*======================================================================*/ + +static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, + unsigned long *mapped_blocks, int *create) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + BD_INFO_T *p_bd = &(sbi->bd_info); + const unsigned long blocksize = sb->s_blocksize; + const unsigned char blocksize_bits = sb->s_blocksize_bits; + sector_t last_block; + int err, clu_offset, sec_offset; + unsigned int cluster; + + *phys = 0; + *mapped_blocks = 0; + + if ((p_fs->vol_type == FAT12) || (p_fs->vol_type == FAT16)) { + if (inode->i_ino == EXFAT_ROOT_INO) { + if (sector < (p_fs->dentries_in_root >> (p_bd->sector_size_bits-DENTRY_SIZE_BITS))) { + *phys = sector + p_fs->root_start_sector; + *mapped_blocks = 1; + } + return 0; + } + } + + last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; + if (sector >= last_block) { + if (*create == 0) + return 0; + } else { + *create = 0; + } + + clu_offset = sector >> p_fs->sectors_per_clu_bits; /* cluster offset */ + sec_offset = sector & (p_fs->sectors_per_clu - 1); /* sector offset in cluster */ + + EXFAT_I(inode)->fid.size = i_size_read(inode); + + err = FsMapCluster(inode, clu_offset, &cluster); + + if (err) { + if (err == FFS_FULL) + return -ENOSPC; + else + return -EIO; + } else if (cluster != CLUSTER_32(~0)) { + *phys = START_SECTOR(cluster) + sec_offset; + *mapped_blocks = p_fs->sectors_per_clu - sec_offset; + } + + return 0; +} + +static int exfat_get_block(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + struct super_block *sb = inode->i_sb; + unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits; + int err; + unsigned long mapped_blocks; + sector_t phys; + + __lock_super(sb); + + err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create); + if (err) { + __unlock_super(sb); + return err; + } + + if (phys) { + max_blocks = min(mapped_blocks, max_blocks); + if (create) { + EXFAT_I(inode)->mmu_private += max_blocks << sb->s_blocksize_bits; + set_buffer_new(bh_result); + } + map_bh(bh_result, sb, phys); + } + + bh_result->b_size = max_blocks << sb->s_blocksize_bits; + __unlock_super(sb); + + return 0; +} + +static int exfat_readpage(struct file *file, struct page *page) +{ + int ret; + ret = mpage_readpage(page, exfat_get_block); + return ret; +} + +static int exfat_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) +{ + int ret; + ret = mpage_readpages(mapping, pages, nr_pages, exfat_get_block); + return ret; +} + +static int exfat_writepage(struct page *page, struct writeback_control *wbc) +{ + int ret; + ret = block_write_full_page(page, exfat_get_block, wbc); + return ret; +} + +static int exfat_writepages(struct address_space *mapping, + struct writeback_control *wbc) +{ + int ret; + ret = mpage_writepages(mapping, wbc, exfat_get_block); + return ret; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) +static void exfat_write_failed(struct address_space *mapping, loff_t to) +{ + struct inode *inode = mapping->host; + if (to > i_size_read(inode)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0) + truncate_pagecache(inode, i_size_read(inode)); +#else + truncate_pagecache(inode, to, i_size_read(inode)); +#endif + EXFAT_I(inode)->fid.size = i_size_read(inode); + _exfat_truncate(inode, i_size_read(inode)); + } +} +#endif + +static int exfat_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + int ret; + *pagep = NULL; + ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + exfat_get_block, + &EXFAT_I(mapping->host)->mmu_private); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (ret < 0) + exfat_write_failed(mapping, pos+len); +#endif + return ret; +} + +static int exfat_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *pagep, void *fsdata) +{ + struct inode *inode = mapping->host; + FILE_ID_T *fid = &(EXFAT_I(inode)->fid); + int err; + + err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if (err < len) + exfat_write_failed(mapping, pos+len); +#endif + + if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { + inode->i_mtime = inode->i_ctime = current_time(inode); + fid->attr |= ATTR_ARCHIVE; + mark_inode_dirty(inode); + } + return err; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifdef CONFIG_AIO_OPTIMIZATION +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + const struct iovec *iov, + loff_t offset, unsigned long nr_segs) +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) +static ssize_t exfat_direct_IO(int rw, struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) +static ssize_t exfat_direct_IO(struct kiocb *iocb, + struct iov_iter *iter, loff_t offset) +#else /* >= 4.7.x */ +static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) +#endif +{ + struct inode *inode = iocb->ki_filp->f_mapping->host; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + struct address_space *mapping = iocb->ki_filp->f_mapping; +#endif + ssize_t ret; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) + int rw; + + rw = iov_iter_rw(iter); +#endif + + if (rw == WRITE) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +#ifdef CONFIG_AIO_OPTIMIZATION + if (EXFAT_I(inode)->mmu_private < + (offset + iov_iter_count(iter))) +#else + if (EXFAT_I(inode)->mmu_private < (offset + iov_length(iov, nr_segs))) +#endif +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) + if (EXFAT_I(inode)->mmu_private < (offset + iov_iter_count(iter))) +#else + if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter)) +#endif + return 0; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) + ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) + ret = blockdev_direct_IO(iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) +#ifdef CONFIG_AIO_OPTIMIZATION + ret = blockdev_direct_IO(rw, iocb, inode, iter, + offset, exfat_get_block); +#else + ret = blockdev_direct_IO(rw, iocb, inode, iov, + offset, nr_segs, exfat_get_block); +#endif +#else + ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, + offset, nr_segs, exfat_get_block, NULL); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,7,0) + if ((ret < 0) && (rw & WRITE)) + exfat_write_failed(mapping, iov_iter_count(iter)); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + if ((ret < 0) && (rw & WRITE)) + exfat_write_failed(mapping, offset+iov_iter_count(iter)); +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) + if ((ret < 0) && (rw & WRITE)) +#ifdef CONFIG_AIO_OPTIMIZATION + exfat_write_failed(mapping, offset+iov_iter_count(iter)); +#else + exfat_write_failed(mapping, offset+iov_length(iov, nr_segs)); +#endif +#endif + return ret; +} + +static sector_t _exfat_bmap(struct address_space *mapping, sector_t block) +{ + sector_t blocknr; + + /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + down_read(&EXFAT_I(mapping->host)->truncate_lock); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->truncate_lock); +#else + down_read(&EXFAT_I(mapping->host)->i_alloc_sem); + blocknr = generic_block_bmap(mapping, block, exfat_get_block); + up_read(&EXFAT_I(mapping->host)->i_alloc_sem); +#endif + + return blocknr; +} + +const struct address_space_operations exfat_aops = { + .readpage = exfat_readpage, + .readpages = exfat_readpages, + .writepage = exfat_writepage, + .writepages = exfat_writepages, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) + .sync_page = block_sync_page, +#endif + .write_begin = exfat_write_begin, + .write_end = exfat_write_end, + .direct_IO = exfat_direct_IO, + .bmap = _exfat_bmap +}; + +/*======================================================================*/ +/* Super Operations */ +/*======================================================================*/ + +static inline unsigned long exfat_hash(loff_t i_pos) +{ + return hash_32(i_pos, EXFAT_HASH_BITS); +} + +static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct exfat_inode_info *info; + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + struct inode *inode = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) + struct hlist_node *node; + + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, node, head, i_hash_fat) { +#else + spin_lock(&sbi->inode_hash_lock); + hlist_for_each_entry(info, head, i_hash_fat) { +#endif + CHECK_ERR(info->vfs_inode.i_sb != sb); + + if (i_pos != info->i_pos) + continue; + inode = igrab(&info->vfs_inode); + if (inode) + break; + } + spin_unlock(&sbi->inode_hash_lock); + return inode; +} + +static void exfat_attach(struct inode *inode, loff_t i_pos) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos); + + spin_lock(&sbi->inode_hash_lock); + EXFAT_I(inode)->i_pos = i_pos; + hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head); + spin_unlock(&sbi->inode_hash_lock); +} + +static void exfat_detach(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + spin_lock(&sbi->inode_hash_lock); + hlist_del_init(&EXFAT_I(inode)->i_hash_fat); + EXFAT_I(inode)->i_pos = 0; + spin_unlock(&sbi->inode_hash_lock); +} + +/* doesn't deal with root inode */ +static int exfat_fill_inode(struct inode *inode, FILE_ID_T *fid) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + DIR_ENTRY_T info; + + memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(FILE_ID_T)); + + FsReadStat(inode, &info); + + EXFAT_I(inode)->i_pos = 0; + EXFAT_I(inode)->target = NULL; + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + INC_IVERSION(inode); + inode->i_generation = get_seconds(); + + if (info.Attr & ATTR_SUBDIR) { /* directory */ + inode->i_generation &= ~1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,00) + set_nlink(inode, info.NumSubdirs); +#else + inode->i_nlink = info.NumSubdirs; +#endif + } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_symlink_inode_operations; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); + } else { /* regular file */ + inode->i_generation |= 1; + inode->i_mode = exfat_make_mode(sbi, info.Attr, S_IRWXUGO); + inode->i_op = &exfat_file_inode_operations; + inode->i_fop = &exfat_file_operations; + inode->i_mapping->a_ops = &exfat_aops; + inode->i_mapping->nrpages = 0; + + i_size_write(inode, info.Size); + EXFAT_I(inode)->mmu_private = i_size_read(inode); + } + exfat_save_attr(inode, info.Attr); + + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; + + exfat_time_fat2unix(sbi, &inode->i_mtime, &info.ModifyTimestamp); + exfat_time_fat2unix(sbi, &inode->i_ctime, &info.CreateTimestamp); + exfat_time_fat2unix(sbi, &inode->i_atime, &info.AccessTimestamp); + + return 0; +} + +static struct inode *exfat_build_inode(struct super_block *sb, + FILE_ID_T *fid, loff_t i_pos) { + struct inode *inode; + int err; + + inode = exfat_iget(sb, i_pos); + if (inode) + goto out; + inode = new_inode(sb); + if (!inode) { + inode = ERR_PTR(-ENOMEM); + goto out; + } + inode->i_ino = iunique(sb, EXFAT_ROOT_INO); + SET_IVERSION(inode, 1); + err = exfat_fill_inode(inode, fid); + if (err) { + iput(inode); + inode = ERR_PTR(err); + goto out; + } + exfat_attach(inode, i_pos); + insert_inode_hash(inode); +out: + return inode; +} + +static int exfat_sync_inode(struct inode *inode) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + return exfat_write_inode(inode, 0); +#else + return exfat_write_inode(inode, NULL); +#endif +} + +static struct inode *exfat_alloc_inode(struct super_block *sb) +{ + struct exfat_inode_info *ei; + + ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS); + if (!ei) + return NULL; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + init_rwsem(&ei->truncate_lock); +#endif + + return &ei->vfs_inode; +} + +static void exfat_destroy_inode(struct inode *inode) +{ + if (EXFAT_I(inode)->target) + kfree(EXFAT_I(inode)->target); + EXFAT_I(inode)->target = NULL; + + kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode)); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +static int exfat_write_inode(struct inode *inode, int wait) +#else +static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc) +#endif +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + DIR_ENTRY_T info; + + if (inode->i_ino == EXFAT_ROOT_INO) + return 0; + + info.Attr = exfat_make_attr(inode); + info.Size = i_size_read(inode); + + exfat_time_unix2fat(sbi, &inode->i_mtime, &info.ModifyTimestamp); + exfat_time_unix2fat(sbi, &inode->i_ctime, &info.CreateTimestamp); + exfat_time_unix2fat(sbi, &inode->i_atime, &info.AccessTimestamp); + + FsWriteStat(inode, &info); + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) +static void exfat_delete_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); +} + +static void exfat_clear_inode(struct inode *inode) +{ + exfat_detach(inode); + remove_inode_hash(inode); +} +#else +static void exfat_evict_inode(struct inode *inode) +{ + truncate_inode_pages(&inode->i_data, 0); + + if (!inode->i_nlink) + i_size_write(inode, 0); + invalidate_inode_buffers(inode); +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) + end_writeback(inode); +#else + clear_inode(inode); +#endif + exfat_detach(inode); + + remove_inode_hash(inode); +} +#endif + +static void exfat_free_super(struct exfat_sb_info *sbi) +{ + if (sbi->nls_disk) + unload_nls(sbi->nls_disk); + if (sbi->nls_io) + unload_nls(sbi->nls_io); + if (sbi->options.iocharset != exfat_default_iocharset) + kfree(sbi->options.iocharset); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + /* mutex_init is in exfat_fill_super function. only for 3.7+ */ + mutex_destroy(&sbi->s_lock); +#endif + kfree(sbi); +} + +static void exfat_put_super(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + if (__is_sb_dirty(sb)) + exfat_write_super(sb); + + FsUmountVol(sb); + + sb->s_fs_info = NULL; + exfat_free_super(sbi); +} + +static void exfat_write_super(struct super_block *sb) +{ + __lock_super(sb); + + __set_sb_clean(sb); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) + if (!(sb->s_flags & SB_RDONLY)) +#else + if (!(sb->s_flags & MS_RDONLY)) +#endif + FsSyncVol(sb, 1); + + __unlock_super(sb); +} + +static int exfat_sync_fs(struct super_block *sb, int wait) +{ + int err = 0; + + if (__is_sb_dirty(sb)) { + __lock_super(sb); + __set_sb_clean(sb); + err = FsSyncVol(sb, 1); + __unlock_super(sb); + } + + return err; +} + +static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + struct super_block *sb = dentry->d_sb; + u64 id = huge_encode_dev(sb->s_bdev->bd_dev); + FS_INFO_T *p_fs = &(EXFAT_SB(sb)->fs_info); + VOL_INFO_T info; + + if (p_fs->used_clusters == (u32) ~0) { + if (FFS_MEDIAERR == FsGetVolInfo(sb, &info)) + return -EIO; + + } else { + info.FatType = p_fs->vol_type; + info.ClusterSize = p_fs->cluster_size; + info.NumClusters = p_fs->num_clusters - 2; + info.UsedClusters = p_fs->used_clusters; + info.FreeClusters = info.NumClusters - info.UsedClusters; + + if (p_fs->dev_ejected) + printk("[EXFAT] statfs on device is ejected\n"); + } + + buf->f_type = sb->s_magic; + buf->f_bsize = info.ClusterSize; + buf->f_blocks = info.NumClusters; + buf->f_bfree = info.FreeClusters; + buf->f_bavail = info.FreeClusters; + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); + buf->f_namelen = 260; + + return 0; +} + +static int exfat_remount(struct super_block *sb, int *flags, char *data) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) + *flags |= SB_NODIRATIME; +#else + *flags |= MS_NODIRATIME; +#endif + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) +static int exfat_show_options(struct seq_file *m, struct dentry *root) +{ + struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb); +#else +static int exfat_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct exfat_sb_info *sbi = EXFAT_SB(mnt->mnt_sb); +#endif + struct exfat_mount_options *opts = &sbi->options; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + if (__kuid_val(opts->fs_uid)) + seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid)); + if (__kgid_val(opts->fs_gid)) + seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid)); +#else + if (opts->fs_uid != 0) + seq_printf(m, ",uid=%u", opts->fs_uid); + if (opts->fs_gid != 0) + seq_printf(m, ",gid=%u", opts->fs_gid); +#endif + seq_printf(m, ",fmask=%04o", opts->fs_fmask); + seq_printf(m, ",dmask=%04o", opts->fs_dmask); + if (opts->allow_utime) + seq_printf(m, ",allow_utime=%04o", opts->allow_utime); + if (sbi->nls_disk) + seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); + if (sbi->nls_io) + seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); + seq_printf(m, ",namecase=%u", opts->casesensitive); + if (opts->errors == EXFAT_ERRORS_CONT) + seq_puts(m, ",errors=continue"); + else if (opts->errors == EXFAT_ERRORS_PANIC) + seq_puts(m, ",errors=panic"); + else + seq_puts(m, ",errors=remount-ro"); +#ifdef CONFIG_EXFAT_DISCARD + if (opts->discard) + seq_printf(m, ",discard"); +#endif + return 0; +} + +const struct super_operations exfat_sops = { + .alloc_inode = exfat_alloc_inode, + .destroy_inode = exfat_destroy_inode, + .write_inode = exfat_write_inode, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) + .delete_inode = exfat_delete_inode, + .clear_inode = exfat_clear_inode, +#else + .evict_inode = exfat_evict_inode, +#endif + .put_super = exfat_put_super, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) + .write_super = exfat_write_super, +#endif + .sync_fs = exfat_sync_fs, + .statfs = exfat_statfs, + .remount_fs = exfat_remount, + .show_options = exfat_show_options, +}; + +/*======================================================================*/ +/* Export Operations */ +/*======================================================================*/ + +static struct inode *exfat_nfs_get_inode(struct super_block *sb, + u64 ino, u32 generation) +{ + struct inode *inode = NULL; + if (ino < EXFAT_ROOT_INO) + return inode; + inode = ilookup(sb, ino); + + if (inode && generation && (inode->i_generation != generation)) { + iput(inode); + inode = NULL; + } + + return inode; +} + +static struct dentry *exfat_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_dentry(sb, fid, fh_len, fh_type, + exfat_nfs_get_inode); +} + +static struct dentry *exfat_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type) +{ + return generic_fh_to_parent(sb, fid, fh_len, fh_type, + exfat_nfs_get_inode); +} + +const struct export_operations exfat_export_ops = { + .fh_to_dentry = exfat_fh_to_dentry, + .fh_to_parent = exfat_fh_to_parent, +}; + +/*======================================================================*/ +/* Super Block Read Operations */ +/*======================================================================*/ + +enum { + Opt_uid, + Opt_gid, + Opt_umask, + Opt_dmask, + Opt_fmask, + Opt_allow_utime, + Opt_codepage, + Opt_charset, + Opt_namecase, + Opt_debug, + Opt_err_cont, + Opt_err_panic, + Opt_err_ro, + Opt_utf8_hack, + Opt_err, +#ifdef CONFIG_EXFAT_DISCARD + Opt_discard, +#endif /* EXFAT_CONFIG_DISCARD */ +}; + +static const match_table_t exfat_tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_umask, "umask=%o"}, + {Opt_dmask, "dmask=%o"}, + {Opt_fmask, "fmask=%o"}, + {Opt_allow_utime, "allow_utime=%o"}, + {Opt_codepage, "codepage=%u"}, + {Opt_charset, "iocharset=%s"}, + {Opt_namecase, "namecase=%u"}, + {Opt_debug, "debug"}, + {Opt_err_cont, "errors=continue"}, + {Opt_err_panic, "errors=panic"}, + {Opt_err_ro, "errors=remount-ro"}, + {Opt_utf8_hack, "utf8"}, +#ifdef CONFIG_EXFAT_DISCARD + {Opt_discard, "discard"}, +#endif /* CONFIG_EXFAT_DISCARD */ + {Opt_err, NULL} +}; + +static int parse_options(char *options, int silent, int *debug, + struct exfat_mount_options *opts) +{ + char *p; + substring_t args[MAX_OPT_ARGS]; + int option; + char *iocharset; + + opts->fs_uid = current_uid(); + opts->fs_gid = current_gid(); + opts->fs_fmask = opts->fs_dmask = current->fs->umask; + opts->allow_utime = (unsigned short) -1; + opts->codepage = exfat_default_codepage; + opts->iocharset = exfat_default_iocharset; + opts->casesensitive = 0; + opts->errors = EXFAT_ERRORS_RO; +#ifdef CONFIG_EXFAT_DISCARD + opts->discard = 0; +#endif + *debug = 0; + + if (!options) + goto out; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, exfat_tokens, args); + switch (token) { + case Opt_uid: + if (match_int(&args[0], &option)) + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_uid = KUIDT_INIT(option); +#else + opts->fs_uid = option; +#endif + break; + case Opt_gid: + if (match_int(&args[0], &option)) + return 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + opts->fs_gid = KGIDT_INIT(option); +#else + opts->fs_gid = option; +#endif + break; + case Opt_umask: + case Opt_dmask: + case Opt_fmask: + if (match_octal(&args[0], &option)) + return 0; + if (token != Opt_dmask) + opts->fs_fmask = option; + if (token != Opt_fmask) + opts->fs_dmask = option; + break; + case Opt_allow_utime: + if (match_octal(&args[0], &option)) + return 0; + opts->allow_utime = option & (S_IWGRP | S_IWOTH); + break; + case Opt_codepage: + if (match_int(&args[0], &option)) + return 0; + opts->codepage = option; + break; + case Opt_charset: + if (opts->iocharset != exfat_default_iocharset) + kfree(opts->iocharset); + iocharset = match_strdup(&args[0]); + if (!iocharset) + return -ENOMEM; + opts->iocharset = iocharset; + break; + case Opt_namecase: + if (match_int(&args[0], &option)) + return 0; + opts->casesensitive = option; + break; + case Opt_err_cont: + opts->errors = EXFAT_ERRORS_CONT; + break; + case Opt_err_panic: + opts->errors = EXFAT_ERRORS_PANIC; + break; + case Opt_err_ro: + opts->errors = EXFAT_ERRORS_RO; + break; + case Opt_debug: + *debug = 1; + break; +#ifdef CONFIG_EXFAT_DISCARD + case Opt_discard: + opts->discard = 1; + break; +#endif /* CONFIG_EXFAT_DISCARD */ + case Opt_utf8_hack: + break; + default: + if (!silent) + printk(KERN_ERR "[EXFAT] Unrecognized mount option %s or missing value\n", p); + return -EINVAL; + } + } + +out: + if (opts->allow_utime == (unsigned short) -1) + opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); + + return 0; +} + +static void exfat_hash_init(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + int i; + + spin_lock_init(&sbi->inode_hash_lock); + for (i = 0; i < EXFAT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); +} + +static int exfat_read_root(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + FS_INFO_T *p_fs = &(sbi->fs_info); + DIR_ENTRY_T info; + + EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; + EXFAT_I(inode)->fid.dir.flags = 0x01; + EXFAT_I(inode)->fid.entry = -1; + EXFAT_I(inode)->fid.start_clu = p_fs->root_dir; + EXFAT_I(inode)->fid.flags = 0x01; + EXFAT_I(inode)->fid.type = TYPE_DIR; + EXFAT_I(inode)->fid.rwoffset = 0; + EXFAT_I(inode)->fid.hint_last_off = -1; + + EXFAT_I(inode)->target = NULL; + + FsReadStat(inode, &info); + + inode->i_uid = sbi->options.fs_uid; + inode->i_gid = sbi->options.fs_gid; + INC_IVERSION(inode); + inode->i_generation = 0; + inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO); + inode->i_op = &exfat_dir_inode_operations; + inode->i_fop = &exfat_dir_operations; + + i_size_write(inode, info.Size); + inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) + & ~((loff_t)p_fs->cluster_size - 1)) >> 9; + EXFAT_I(inode)->i_pos = ((loff_t) p_fs->root_dir << 32) | 0xffffffff; + EXFAT_I(inode)->mmu_private = i_size_read(inode); + + exfat_save_attr(inode, ATTR_SUBDIR); + inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,00) + set_nlink(inode, info.NumSubdirs + 2); +#else + inode->i_nlink = info.NumSubdirs + 2; +#endif + + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) +static void setup_dops(struct super_block *sb) +{ + if (EXFAT_SB(sb)->options.casesensitive == 0) + sb->s_d_op = &exfat_ci_dentry_ops; + else + sb->s_d_op = &exfat_dentry_ops; +} +#endif + +static int exfat_fill_super(struct super_block *sb, void *data, int silent) +{ + struct inode *root_inode = NULL; + struct exfat_sb_info *sbi; + int debug, ret; + long error; + char buf[50]; + + /* + * GFP_KERNEL is ok here, because while we do hold the + * supeblock lock, memory pressure can't call back into + * the filesystem, since we're only just about to mount + * it and have no inodes etc active! + */ + sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) + mutex_init(&sbi->s_lock); +#endif + sb->s_fs_info = sbi; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) + sb->s_flags |= SB_NODIRATIME; +#else + sb->s_flags |= MS_NODIRATIME; +#endif + sb->s_magic = EXFAT_SUPER_MAGIC; + sb->s_op = &exfat_sops; + sb->s_export_op = &exfat_export_ops; + + error = parse_options(data, silent, &debug, &sbi->options); + if (error) + goto out_fail; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) + setup_dops(sb); +#endif + + error = -EIO; + sb_min_blocksize(sb, 512); + sb->s_maxbytes = 0x7fffffffffffffffLL; /* maximum file size */ + + ret = FsMountVol(sb); + if (ret) { + if (!silent) + printk(KERN_ERR "[EXFAT] FsMountVol failed\n"); + + goto out_fail; + } + + /* set up enough so that it can read an inode */ + exfat_hash_init(sb); + + /* + * The low byte of FAT's first entry must have same value with + * media-field. But in real world, too many devices is + * writing wrong value. So, removed that validity check. + * + * if (FAT_FIRST_ENT(sb, media) != first) + */ + + /* codepage is not meaningful in exfat */ + if (sbi->fs_info.vol_type != EXFAT) { + error = -EINVAL; + sprintf(buf, "cp%d", sbi->options.codepage); + sbi->nls_disk = load_nls(buf); + if (!sbi->nls_disk) { + printk(KERN_ERR "[EXFAT] Codepage %s not found\n", buf); + goto out_fail2; + } + } + + sbi->nls_io = load_nls(sbi->options.iocharset); + + error = -ENOMEM; + root_inode = new_inode(sb); + if (!root_inode) + goto out_fail2; + root_inode->i_ino = EXFAT_ROOT_INO; + SET_IVERSION(root_inode, 1); + + error = exfat_read_root(root_inode); + if (error < 0) + goto out_fail2; + error = -ENOMEM; + exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos); + insert_inode_hash(root_inode); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + sb->s_root = d_make_root(root_inode); +#else + sb->s_root = d_alloc_root(root_inode); +#endif + if (!sb->s_root) { + printk(KERN_ERR "[EXFAT] Getting the root inode failed\n"); + goto out_fail2; + } + + return 0; + +out_fail2: + FsUmountVol(sb); +out_fail: + if (root_inode) + iput(root_inode); + sb->s_fs_info = NULL; + exfat_free_super(sbi); + return error; +} +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +static int exfat_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, exfat_fill_super, mnt); +} +#else +static struct dentry *exfat_fs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { + return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super); +} +#endif + +static void init_once(void *foo) +{ + struct exfat_inode_info *ei = (struct exfat_inode_info *)foo; + + INIT_HLIST_NODE(&ei->i_hash_fat); + inode_init_once(&ei->vfs_inode); +} + +static int __init exfat_init_inodecache(void) +{ + exfat_inode_cachep = kmem_cache_create("exfat_inode_cache", + sizeof(struct exfat_inode_info), + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), + init_once); + if (exfat_inode_cachep == NULL) + return -ENOMEM; + return 0; +} + +static void __exit exfat_destroy_inodecache(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); +#endif + kmem_cache_destroy(exfat_inode_cachep); +} + +#ifdef CONFIG_EXFAT_KERNEL_DEBUG +static void exfat_debug_kill_sb(struct super_block *sb) +{ + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct block_device *bdev = sb->s_bdev; + + long flags; + + if (sbi) { + flags = sbi->debug_flags; + + if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) { + /* invalidate_bdev drops all device cache include dirty. + we use this to simulate device removal */ + FsReleaseCache(sb); + invalidate_bdev(bdev); + } + } + + kill_block_super(sb); +} +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + +static struct file_system_type exfat_fs_type = { + .owner = THIS_MODULE, +#if defined(CONFIG_MACH_LGE) || defined(CONFIG_HTC_BATT_CORE) + .name = "texfat", +#else + .name = "exfat", +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + .get_sb = exfat_get_sb, +#else + .mount = exfat_fs_mount, +#endif +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + .kill_sb = exfat_debug_kill_sb, +#else + .kill_sb = kill_block_super, +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ + .fs_flags = FS_REQUIRES_DEV, +}; + +static int __init init_exfat(void) +{ + int err; + + err = FsInit(); + if (err) { + if (err == FFS_MEMORYERR) + return -ENOMEM; + else + return -EIO; + } + + printk(KERN_INFO "exFAT: Version %s\n", EXFAT_VERSION); + + err = exfat_init_inodecache(); + if (err) + goto out; + + err = register_filesystem(&exfat_fs_type); + if (err) + goto out; + + return 0; +out: + FsShutdown(); + return err; +} + +static void __exit exit_exfat(void) +{ + exfat_destroy_inodecache(); + unregister_filesystem(&exfat_fs_type); + FsShutdown(); +} + +module_init(init_exfat); +module_exit(exit_exfat); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("exFAT Filesystem Driver"); +#ifdef MODULE_ALIAS_FS +#if defined(CONFIG_MACH_LGE) || defined(CONFIG_HTC_BATT_CORE) +MODULE_ALIAS_FS("texfat"); +#else +MODULE_ALIAS_FS("exfat"); +#endif +#endif diff --git a/fs/exfat/exfat_super.h b/fs/exfat/exfat_super.h new file mode 100644 index 0000000000000000000000000000000000000000..916811e3d31e24f8418ec1a08296db8d4e7574cc --- /dev/null +++ b/fs/exfat/exfat_super.h @@ -0,0 +1,171 @@ +/* Some of the source code in this file came from "linux/fs/fat/fat.h". */ + +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _EXFAT_LINUX_H +#define _EXFAT_LINUX_H + +#include +#include +#include +#include +#include +#include + +#include "exfat_config.h" +#include "exfat_data.h" +#include "exfat_oal.h" + +#include "exfat_blkdev.h" +#include "exfat_cache.h" +#include "exfat_nls.h" +#include "exfat_api.h" +#include "exfat_core.h" + +#define EXFAT_ERRORS_CONT 1 /* ignore error and continue */ +#define EXFAT_ERRORS_PANIC 2 /* panic on error */ +#define EXFAT_ERRORS_RO 3 /* remount r/o on error */ + +/* ioctl command */ +#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32) + +struct exfat_mount_options { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) + kuid_t fs_uid; + kgid_t fs_gid; +#else + uid_t fs_uid; + gid_t fs_gid; +#endif + unsigned short fs_fmask; + unsigned short fs_dmask; + unsigned short allow_utime; /* permission for setting the [am]time */ + unsigned short codepage; /* codepage for shortname conversions */ + char *iocharset; /* charset for filename input/display */ + unsigned char casesensitive; + unsigned char errors; /* on error: continue, panic, remount-ro */ +#ifdef CONFIG_EXFAT_DISCARD + unsigned char discard; /* flag on if -o dicard specified and device support discard() */ +#endif /* CONFIG_EXFAT_DISCARD */ +}; + +#define EXFAT_HASH_BITS 8 +#define EXFAT_HASH_SIZE (1UL << EXFAT_HASH_BITS) + +/* + * EXFAT file system in-core superblock data + */ +struct exfat_sb_info { + FS_INFO_T fs_info; + BD_INFO_T bd_info; + + struct exfat_mount_options options; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,00) + int s_dirt; + struct mutex s_lock; +#endif + struct nls_table *nls_disk; /* Codepage used on disk */ + struct nls_table *nls_io; /* Charset used for input and display */ + + struct inode *fat_inode; + + spinlock_t inode_hash_lock; + struct hlist_head inode_hashtable[EXFAT_HASH_SIZE]; +#ifdef CONFIG_EXFAT_KERNEL_DEBUG + long debug_flags; +#endif /* CONFIG_EXFAT_KERNEL_DEBUG */ +}; + +/* + * EXFAT file system inode data in memory + */ +struct exfat_inode_info { + FILE_ID_T fid; + char *target; + /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ + loff_t mmu_private; /* physically allocated size */ + loff_t i_pos; /* on-disk position of directory entry or 0 */ + struct hlist_node i_hash_fat; /* hash by i_location */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00) + struct rw_semaphore truncate_lock; +#endif + struct inode vfs_inode; + struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */ +}; + +#define EXFAT_SB(sb) ((struct exfat_sb_info *)((sb)->s_fs_info)) + +static inline struct exfat_inode_info *EXFAT_I(struct inode *inode) +{ + return container_of(inode, struct exfat_inode_info, vfs_inode); +} + +/* + * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to + * save ATTR_RO instead of ->i_mode. + * + * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only + * bit, it's just used as flag for app. + */ +static inline int exfat_mode_can_hold_ro(struct inode *inode) +{ + struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); + + if (S_ISDIR(inode->i_mode)) + return 0; + + if ((~sbi->options.fs_fmask) & S_IWUGO) + return 1; + return 0; +} + +/* Convert attribute bits and a mask to the UNIX mode. */ +static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, + u32 attr, mode_t mode) +{ + if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR)) + mode &= ~S_IWUGO; + + if (attr & ATTR_SUBDIR) + return (mode & ~sbi->options.fs_dmask) | S_IFDIR; + else if (attr & ATTR_SYMLINK) + return (mode & ~sbi->options.fs_dmask) | S_IFLNK; + else + return (mode & ~sbi->options.fs_fmask) | S_IFREG; +} + +/* Return the FAT attribute byte for this inode */ +static inline u32 exfat_make_attr(struct inode *inode) +{ + if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) + return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY; + else + return EXFAT_I(inode)->fid.attr; +} + +static inline void exfat_save_attr(struct inode *inode, u32 attr) +{ + if (exfat_mode_can_hold_ro(inode)) + EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK; + else + EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY); +} + +#endif /* _EXFAT_LINUX_H */ diff --git a/fs/exfat/exfat_upcase.c b/fs/exfat/exfat_upcase.c new file mode 100644 index 0000000000000000000000000000000000000000..3807f37caacb5a56a3754e7484cc41927264a220 --- /dev/null +++ b/fs/exfat/exfat_upcase.c @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_upcase.c */ +/* PURPOSE : exFAT Up-case Table */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY (Ver 0.9) */ +/* */ +/* - 2010.11.15 [Joosun Hahn] : first writing */ +/* */ +/************************************************************************/ + +#include "exfat_config.h" + +#include "exfat_nls.h" + +const u8 uni_upcase[NUM_UPCASE<<1] = { + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, + 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00, + 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00, + 0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00, 0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00, + 0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00, + 0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00, 0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00, + 0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, + 0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00, 0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00, + 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, + 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, + 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00, 0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00, + 0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, + 0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00, 0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00, + 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00, + 0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00, + 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00, + 0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00, + 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, + 0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00, 0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00, + 0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00, + 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00, 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00, + 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00, 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00, + 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00, 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00, + 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00, + 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00, + 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00, + 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01, + 0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01, 0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01, + 0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01, 0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01, + 0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01, 0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01, + 0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01, 0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01, + 0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01, 0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01, + 0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01, 0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01, + 0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01, 0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01, + 0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01, 0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01, + 0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01, 0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01, + 0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01, 0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01, + 0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01, 0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01, + 0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01, 0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01, + 0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01, 0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01, + 0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01, 0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01, + 0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01, 0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01, + 0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01, 0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01, + 0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01, 0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01, + 0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01, 0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01, + 0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01, 0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01, + 0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01, 0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01, + 0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01, 0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01, + 0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01, 0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01, + 0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01, 0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01, + 0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01, 0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01, + 0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01, 0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01, + 0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01, 0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01, + 0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01, 0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01, + 0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01, 0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01, + 0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01, 0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01, + 0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01, 0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01, + 0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01, 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01, + 0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02, + 0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02, 0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02, + 0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02, 0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02, + 0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02, 0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02, + 0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02, 0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02, + 0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02, 0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02, + 0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02, 0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02, + 0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02, 0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02, + 0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02, 0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02, + 0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02, 0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02, + 0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01, 0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01, + 0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01, 0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02, + 0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01, 0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02, + 0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C, 0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01, + 0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02, 0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02, + 0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02, 0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02, + 0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01, 0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02, + 0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01, 0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02, + 0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02, 0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02, + 0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02, 0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02, + 0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02, 0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02, + 0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02, 0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02, + 0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02, + 0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02, 0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02, + 0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02, 0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02, + 0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02, 0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02, + 0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02, 0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02, + 0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02, 0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02, + 0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02, 0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02, + 0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02, 0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02, + 0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02, 0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02, + 0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02, 0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02, + 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03, + 0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03, 0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03, + 0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03, 0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03, + 0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03, 0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03, + 0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03, 0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03, + 0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03, 0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03, + 0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03, 0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03, + 0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03, 0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03, + 0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03, 0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03, + 0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03, 0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03, + 0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03, 0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03, + 0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03, 0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03, + 0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03, 0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03, + 0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03, 0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03, + 0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03, 0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03, + 0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03, + 0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03, 0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03, + 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03, 0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03, + 0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, + 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, + 0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, + 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, + 0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03, 0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03, + 0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03, 0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03, + 0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03, 0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03, + 0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03, 0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03, + 0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03, 0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03, + 0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03, 0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03, + 0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03, 0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03, + 0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03, 0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03, + 0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03, 0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03, + 0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03, 0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03, + 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, + 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, + 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, + 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, + 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, + 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, + 0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04, 0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04, + 0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04, 0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04, + 0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04, 0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04, + 0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04, 0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04, + 0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04, + 0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04, 0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04, + 0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04, 0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04, + 0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04, 0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04, + 0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04, 0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04, + 0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04, 0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04, + 0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04, 0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04, + 0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04, 0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04, + 0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04, 0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04, + 0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04, 0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04, + 0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04, 0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04, + 0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04, 0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04, + 0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04, 0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04, + 0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04, + 0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04, 0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04, + 0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04, 0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04, + 0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04, 0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04, + 0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04, 0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04, + 0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04, 0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04, + 0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04, + 0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04, 0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04, + 0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04, 0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04, + 0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05, 0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05, + 0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05, 0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05, + 0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05, 0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05, + 0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05, 0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05, + 0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05, 0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05, + 0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05, 0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05, + 0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, + 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, + 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, + 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, + 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05, + 0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05, 0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05, + 0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05, 0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05, + 0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05, 0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05, + 0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05, 0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05, + 0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05, 0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05, + 0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05, 0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF, + 0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D, 0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D, + 0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D, 0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D, + 0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D, 0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D, + 0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D, 0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D, + 0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D, 0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D, + 0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D, 0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D, + 0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D, 0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D, + 0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D, 0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D, + 0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D, 0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D, + 0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D, 0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D, + 0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D, 0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D, + 0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D, 0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D, + 0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D, 0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D, + 0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D, 0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D, + 0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D, 0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D, + 0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D, 0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D, + 0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D, 0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, + 0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E, 0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E, 0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E, + 0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E, 0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E, + 0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E, + 0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E, 0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E, + 0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E, 0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E, + 0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E, 0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E, + 0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E, 0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E, + 0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E, 0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E, + 0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E, 0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E, + 0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E, 0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E, + 0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E, 0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E, + 0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E, 0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E, + 0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E, 0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E, + 0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E, + 0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E, 0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E, + 0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E, 0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E, + 0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E, 0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E, + 0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E, 0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E, + 0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E, 0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E, + 0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E, 0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E, + 0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E, 0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E, + 0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E, 0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E, + 0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E, 0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E, + 0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E, 0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E, + 0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E, 0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E, + 0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E, 0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E, + 0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E, 0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E, + 0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E, 0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E, + 0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E, + 0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E, 0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E, + 0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, + 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F, + 0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, + 0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F, 0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F, + 0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, + 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F, + 0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, + 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F, + 0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, + 0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F, 0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F, + 0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F, 0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F, + 0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F, 0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F, + 0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, + 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F, + 0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, + 0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, + 0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, + 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F, + 0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, + 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F, + 0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, + 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F, + 0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F, + 0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F, 0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F, + 0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F, 0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F, + 0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F, + 0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F, + 0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F, 0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F, + 0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F, + 0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F, 0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F, + 0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F, 0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F, + 0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F, 0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F, + 0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20, + 0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20, + 0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20, 0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20, + 0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20, 0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20, + 0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20, + 0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20, 0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20, + 0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20, 0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20, + 0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20, 0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20, + 0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20, 0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20, + 0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20, 0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20, + 0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20, 0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20, + 0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20, 0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20, + 0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20, 0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20, + 0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20, 0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20, + 0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20, 0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20, + 0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20, 0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20, + 0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20, 0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20, + 0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20, 0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20, + 0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20, 0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20, + 0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20, 0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20, + 0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20, 0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20, + 0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20, 0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20, + 0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20, 0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20, + 0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20, 0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20, + 0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20, 0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20, + 0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20, 0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20, + 0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20, 0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20, + 0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20, 0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20, + 0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20, 0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20, + 0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20, 0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20, + 0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20, 0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20, + 0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20, 0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20, + 0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20, 0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21, + 0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21, 0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21, + 0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21, 0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21, + 0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21, 0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21, + 0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21, 0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21, + 0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21, 0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21, + 0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21, 0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21, + 0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21, 0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21, + 0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21, 0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21, + 0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21, 0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21, + 0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21, 0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21, + 0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21, 0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21, + 0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, + 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, + 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21, + 0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21, 0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21, + 0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21, 0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21, + 0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24, 0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24, + 0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24, 0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24, + 0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24, 0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24, + 0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24, 0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C, + 0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C, 0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C, + 0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C, 0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C, + 0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C, 0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C, + 0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C, 0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C, + 0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C, 0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C, + 0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C, 0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C, + 0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C, 0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C, + 0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C, 0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C, + 0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C, 0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C, + 0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C, 0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C, + 0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C, 0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C, + 0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C, 0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C, + 0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C, 0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C, + 0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C, 0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C, + 0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C, 0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C, + 0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C, 0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C, + 0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C, 0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C, + 0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C, 0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C, + 0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C, 0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C, + 0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C, 0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C, + 0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C, 0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C, + 0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C, 0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C, + 0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C, 0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C, + 0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C, 0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C, + 0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C, 0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C, + 0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C, 0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10, + 0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10, 0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10, + 0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10, 0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10, + 0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10, 0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10, + 0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10, 0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10, + 0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10, 0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF, + 0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF, 0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF, + 0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF, 0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF, + 0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF, 0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF, + 0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF, 0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF, + 0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF, 0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF, + 0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF, 0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF, + 0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF, 0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF, + 0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF, 0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF, + 0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF, 0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF, + 0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF, 0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF, + 0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF, 0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, + 0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF, 0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF, + 0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF, 0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF, + 0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF, 0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF, + 0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF, 0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF, + 0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF, 0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF, + 0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF, 0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF, + 0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF, 0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF, + 0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF, + 0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF, 0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF, + 0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF, 0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF, + 0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF, 0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF, + 0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF, + 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF +}; diff --git a/fs/exfat/exfat_version.h b/fs/exfat/exfat_version.h new file mode 100644 index 0000000000000000000000000000000000000000..77e6c074928b6044816753e0a4b759581245e24b --- /dev/null +++ b/fs/exfat/exfat_version.h @@ -0,0 +1,19 @@ +/************************************************************************/ +/* */ +/* PROJECT : exFAT & FAT12/16/32 File System */ +/* FILE : exfat_version.h */ +/* PURPOSE : exFAT File Manager */ +/* */ +/*----------------------------------------------------------------------*/ +/* NOTES */ +/* */ +/*----------------------------------------------------------------------*/ +/* REVISION HISTORY */ +/* */ +/* - 2012.02.10 : Release Version 1.1.0 */ +/* - 2012.04.02 : P1 : Change Module License to Samsung Proprietary */ +/* - 2012.06.07 : P2 : Fixed incorrect filename problem */ +/* */ +/************************************************************************/ + +#define EXFAT_VERSION "1.2.11" diff --git a/fs/f2fs/Kconfig b/fs/f2fs/Kconfig index 2dd1bbca241c78196e629a40ccff20f2ff41cf98..4293f9c80982b4d293dd5ba51b4eeb9b959be2bf 100644 --- a/fs/f2fs/Kconfig +++ b/fs/f2fs/Kconfig @@ -126,3 +126,13 @@ config F2FS_FS_LZ4 default y help Support LZ4 compress algorithm, if unsure, say Y. + +config F2FS_OF2FS + bool "OF2FS optimization" + depends on F2FS_FS + default y + help + Optimization based on F2FS, trys to optimize the gc and discard behaviour. + This option is default a 'y'. + + If unsure, say N. diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 49c18affde5decc31fd10ff2b1852c77d5ea8009..6527d7e07f58405f1bb8edb34c97cfddde556bf5 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -14,6 +14,10 @@ #include #include +#if defined(CONFIG_UFSTW) +#include +#endif + #include "f2fs.h" #include "node.h" #include "segment.h" @@ -1372,7 +1376,12 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi, f2fs_submit_merged_write(sbi, META_FLUSH); } +#ifdef CONFIG_F2FS_BD_STAT +static int do_checkpoint(struct f2fs_sb_info *sbi, + struct cp_control *cpc, u64 *cp_flush_meta_time) +#else static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) +#endif { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); struct f2fs_nm_info *nm_i = NM_I(sbi); @@ -1386,9 +1395,18 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct curseg_info *seg_i = CURSEG_I(sbi, CURSEG_HOT_NODE); u64 kbytes_written; int err; +#ifdef CONFIG_F2FS_BD_STAT + u64 cp_flush_meta_begin; +#endif /* Flush all the NAT/SIT pages */ +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_begin = local_clock(); +#endif f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); +#ifdef CONFIG_F2FS_BD_STAT + *cp_flush_meta_time += local_clock() - cp_flush_meta_begin; +#endif if (get_pages(sbi, F2FS_DIRTY_META) && !f2fs_cp_error(sbi)) { WARN_ON(1); set_sbi_flag(sbi, SBI_NEED_FSCK); @@ -1560,6 +1578,10 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); unsigned long long ckpt_ver; int err = 0; +#ifdef CONFIG_F2FS_BD_STAT + u64 cp_begin = 0, cp_end, cp_submit_end = 0, discard_begin, discard_end; + u64 cp_flush_meta_time, cp_flush_meta_begin; +#endif if (f2fs_readonly(sbi->sb) || f2fs_hw_is_readonly(sbi)) return -EROFS; @@ -1570,6 +1592,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) f2fs_warn(sbi, "Start checkpoint disabled!"); } mutex_lock(&sbi->cp_mutex); +#if defined(CONFIG_UFSTW) + bdev_set_turbo_write(sbi->sb->s_bdev); +#endif if (!is_sbi_flag_set(sbi, SBI_IS_DIRTY) && ((cpc->reason & CP_FASTBOOT) || (cpc->reason & CP_SYNC) || @@ -1582,6 +1607,10 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); +#ifdef CONFIG_F2FS_BD_STAT + cp_begin = local_clock(); +#endif + err = block_operations(sbi); if (err) goto out; @@ -1589,6 +1618,9 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); f2fs_flush_merged_writes(sbi); +#ifdef CONFIG_F2FS_BD_STAT + cp_submit_end = local_clock(); +#endif /* this is the case of multiple fstrims without any changes */ if (cpc->reason & CP_DISCARD) { @@ -1600,8 +1632,22 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (NM_I(sbi)->dirty_nat_cnt == 0 && SIT_I(sbi)->dirty_sentries == 0 && prefree_segments(sbi) == 0) { +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_begin = local_clock(); +#endif f2fs_flush_sit_entries(sbi, cpc); +#ifdef CONFIG_F2FS_BD_STAT + discard_begin = local_clock(); + cp_flush_meta_time = discard_begin - cp_flush_meta_begin; +#endif f2fs_clear_prefree_segments(sbi, cpc); +#ifdef CONFIG_F2FS_BD_STAT + discard_end = local_clock(); + bd_lock(sbi); + bd_max_val(sbi, max_cp_discard_time, + discard_end - discard_begin); + bd_unlock(sbi); +#endif unblock_operations(sbi); goto out; } @@ -1616,18 +1662,38 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver); /* write cached NAT/SIT entries to NAT/SIT area */ +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_begin = local_clock(); +#endif err = f2fs_flush_nat_entries(sbi, cpc); if (err) goto stop; f2fs_flush_sit_entries(sbi, cpc); +#ifdef CONFIG_F2FS_BD_STAT + cp_flush_meta_time = local_clock() - cp_flush_meta_begin; + /* unlock all the fs_lock[] in do_checkpoint() */ + err = do_checkpoint(sbi, cpc, &cp_flush_meta_time); + if (err) + f2fs_release_discard_addrs(sbi); + else { + discard_begin = local_clock(); + f2fs_clear_prefree_segments(sbi, cpc); + discard_end = local_clock(); + bd_lock(sbi); + bd_max_val(sbi, max_cp_discard_time, + discard_end - discard_begin); + bd_unlock(sbi); + } +#else /* unlock all the fs_lock[] in do_checkpoint() */ err = do_checkpoint(sbi, cpc); if (err) f2fs_release_discard_addrs(sbi); else f2fs_clear_prefree_segments(sbi, cpc); +#endif stop: unblock_operations(sbi); stat_inc_cp_count(sbi->stat_info); @@ -1639,7 +1705,22 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) f2fs_update_time(sbi, CP_TIME); trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint"); out: +#if defined(CONFIG_UFSTW) + bdev_clear_turbo_write(sbi->sb->s_bdev); +#endif mutex_unlock(&sbi->cp_mutex); +#ifdef CONFIG_F2FS_BD_STAT + if (!err && cp_begin) { + cp_end = local_clock(); + bd_lock(sbi); + bd_inc_val(sbi, cp_success_count, 1); + bd_max_val(sbi, max_cp_submit_time, cp_submit_end - cp_begin); + bd_inc_val(sbi, cp_time, cp_end - cp_begin); + bd_max_val(sbi, max_cp_time, cp_end - cp_begin); + bd_max_val(sbi, max_cp_flush_meta_time, cp_flush_meta_time); + bd_unlock(sbi); + } +#endif return err; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 16b12d11a9d803b794cd5ee95f6bedf47673b533..12ed1fc35db102db8fdd9547e0ffd41a23891f93 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1403,6 +1403,11 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) alloc: set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); old_blkaddr = dn->data_blkaddr; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_DIRECT_IO, 1); + bd_unlock(sbi); +#endif f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr, &sum, seg_type, NULL, false); if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) @@ -2533,6 +2538,9 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) struct node_info ni; bool ipu_force = false; int err = 0; +#ifdef CONFIG_F2FS_BD_STAT + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); +#endif set_new_dnode(&dn, inode, NULL, NULL, 0); if (need_inplace_update(fio) && @@ -2578,6 +2586,17 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) if (ipu_force || (__is_valid_data_blkaddr(fio->old_blkaddr) && need_inplace_update(fio))) { +#ifdef CONFIG_F2FS_BD_STAT + if (S_ISDIR(inode->i_mode)) { + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_REWRITE_HOT_DATA, 1); + bd_unlock(sbi); + } else { + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_REWRITE_WARM_DATA, 1); + bd_unlock(sbi); + } +#endif err = f2fs_encrypt_one_page(fio); if (err) goto out_writepage; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9c02abdd27cb98f89ab4307f1f51c49b0898ed66..18271ecbadb4756464d80aea407b53e61d995913 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -205,6 +205,11 @@ enum { #define DEF_MAX_DISCARD_ISSUE_TIME 60000 /* 60 s, if no candidates */ #define DEF_DISCARD_URGENT_UTIL 80 /* do more discard over 80% */ #define DEF_CP_INTERVAL 60 /* 60 secs */ +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: set default idle interval to 1s */ +#define DEF_GC_IDLE_INTERVAL 1 /* 1 secs */ +#define DEF_DISCARD_IDLE_INTERVAL 1 /* 1 secs */ +#endif #define DEF_IDLE_INTERVAL 5 /* 5 secs */ #define DEF_DISABLE_INTERVAL 5 /* 5 secs */ #define DEF_DISABLE_QUICK_INTERVAL 1 /* 1 secs */ @@ -314,6 +319,9 @@ struct discard_cmd { int error; /* bio error */ spinlock_t lock; /* for state/bio_ref updating */ unsigned short bio_ref; /* bio reference count */ +#ifdef CONFIG_F2FS_BD_STAT + u64 discard_time; +#endif }; enum { @@ -321,6 +329,10 @@ enum { DPOLICY_FORCE, DPOLICY_FSTRIM, DPOLICY_UMOUNT, +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + DPOLICY_ODISCARD, +#endif MAX_DPOLICY, }; @@ -336,6 +348,10 @@ struct discard_policy { bool ordered; /* issue discard by lba order */ unsigned int granularity; /* discard granularity */ int timeout; /* discard timeout for put_super */ +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + bool io_busy; /* interrupt by user io */ +#endif }; struct discard_cmd_control { @@ -346,6 +362,11 @@ struct discard_cmd_control { struct list_head fstrim_list; /* in-flight discard from fstrim */ wait_queue_head_t discard_wait_queue; /* waiting queue for wake-up */ unsigned int discard_wake; /* to wake up discard thread */ +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add to for oDiscard */ + unsigned int odiscard_wake; /* to wake up discard thread,for odiscard */ + unsigned int otrim_wake; /* to wake up discard thread,for otrim */ +#endif struct mutex cmd_lock; unsigned int nr_discards; /* # of discards in the list */ unsigned int max_discards; /* max. discards to be issued */ @@ -1478,6 +1499,10 @@ struct f2fs_sb_info { unsigned int ndirty_inode[NR_INODE_TYPE]; /* # of dirty inodes */ #endif spinlock_t stat_lock; /* lock for stat operations */ +#ifdef CONFIG_F2FS_BD_STAT + spinlock_t bd_lock; + struct f2fs_bigdata_info *bd_info; /* big data collections */ +#endif /* For app/fs IO statistics */ spinlock_t iostat_lock; @@ -1508,6 +1533,20 @@ struct f2fs_sb_info { __u32 s_chksum_seed; struct workqueue_struct *post_read_wq; /* post read workqueue */ +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add code to optimize gc */ + /* [ASTI-147]: add need_SSR GC */ + bool is_frag; /* urgent gc flag */ + unsigned long last_frag_check; /* last urgent check jiffies */ + atomic_t need_ssr_gc; /* ssr gc count */ + /* [ASTI-147]: control of2fs gc code, will remove */ + bool gc_opt_enable; + + /* [ASTI-147]: add for oDiscard */ + struct list_head sbi_list; + unsigned long last_wp_odc_jiffies; + bool odiscard_already_run; +#endif }; struct f2fs_private_dio { @@ -3623,6 +3662,12 @@ static inline void f2fs_destroy_root_stats(void) { } static inline void update_sit_info(struct f2fs_sb_info *sbi) {} #endif +#ifdef CONFIG_F2FS_BD_STAT +#include "../../drivers/oneplus/fs/f2fs/of2fs_bigdata.h" +extern void f2fs_build_bd_stat(struct f2fs_sb_info *sbi); +extern void f2fs_destroy_bd_stat(struct f2fs_sb_info *sbi); +#endif + extern const struct file_operations f2fs_dir_operations; extern const struct file_operations f2fs_file_operations; extern const struct inode_operations f2fs_file_inode_operations; @@ -4018,6 +4063,52 @@ static inline bool is_journalled_quota(struct f2fs_sb_info *sbi) return false; } +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add for oDiscard */ +#define BATTERY_THRESHOLD 30 /* 30% */ +#define ODISCARD_WAKEUP_INTERVAL 900 /* 900 secs */ +#define ODISCARD_EXEC_TIME_NO_CHARGING 8000 /* 8000 ms */ + +#define DEF_URGENT_DISCARD_ISSUE_TIME 50 /* 50 ms, if force */ +#define DEF_MIN_DISCARD_ISSUE_TIME_OF2FS 100 /* 100 ms, if exists */ +#define DEF_MID_DISCARD_ISSUE_TIME_OF2FS 2000 /* 2 s, if dev is busy */ +#define DEF_MAX_DISCARD_ISSUE_TIME_OF2FS 120000 /* 120 s, if no candidates */ +#define DEF_DISCARD_EMPTY_ISSUE_TIME 600000 /* 10 min, undiscard block=0 */ + +extern int f2fs_odiscard_enable; + +extern inline void wake_up_odiscard_of2fs(struct f2fs_sb_info *sbi); +extern inline void wake_up_otrim_of2fs(struct f2fs_sb_info *sbi); + +enum { + F2FS_TRIM_START, + F2FS_TRIM_FINISH, + F2FS_TRIM_INTERRUPT, +}; + +struct f2fs_device_state { + bool screen_off; + bool battery_charging; + int battery_percent; +}; +extern struct f2fs_device_state f2fs_device; + +#define FS_FREE_SPACE_PERCENT 20 +#define DEVICE_FREE_SPACE_PERCENT 10 +static inline block_t fs_free_space_threshold(struct f2fs_sb_info *sbi) +{ + return (block_t)(SM_I(sbi)->main_segments * sbi->blocks_per_seg * + FS_FREE_SPACE_PERCENT) / 100; +} + +static inline block_t device_free_space_threshold(struct f2fs_sb_info *sbi) +{ + return (block_t)(SM_I(sbi)->main_segments * sbi->blocks_per_seg * + DEVICE_FREE_SPACE_PERCENT) / 100; +} + +#endif + #define EFSBADCRC EBADMSG /* Bad CRC detected */ #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ce3819090f126b098f5402fa20476d95747b67fc..9293438107e1e5724741c2b258023966e0f4cac7 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -22,6 +22,10 @@ #include #include +#if defined(CONFIG_UFSTW) +#include +#endif + #include "f2fs.h" #include "node.h" #include "segment.h" @@ -244,6 +248,15 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, .for_reclaim = 0, }; unsigned int seq_id = 0; +#ifdef CONFIG_F2FS_BD_STAT + u64 fsync_begin = 0, fsync_end = 0, wr_file_end, cp_begin = 0, + cp_end = 0, sync_node_begin = 0, sync_node_end = 0, + flush_begin = 0, flush_end = 0; +#endif + +#if defined(CONFIG_UFSTW) + bool turbo_set = false; +#endif if (unlikely(f2fs_readonly(inode->i_sb) || is_sbi_flag_set(sbi, SBI_CP_DISABLED))) @@ -263,11 +276,17 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, if (S_ISDIR(inode->i_mode)) goto go_write; +#ifdef CONFIG_F2FS_BD_STAT + fsync_begin = local_clock(); +#endif /* if fdatasync is triggered, let's do in-place-update */ if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks) set_inode_flag(inode, FI_NEED_IPU); ret = file_write_and_wait_range(file, start, end); clear_inode_flag(inode, FI_NEED_IPU); +#ifdef CONFIG_F2FS_BD_STAT + wr_file_end = local_clock(); +#endif if (ret) { trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret); @@ -306,7 +325,13 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, if (cp_reason) { /* all the dirty node pages should be flushed for POR */ +#ifdef CONFIG_F2FS_BD_STAT + cp_begin = local_clock(); +#endif ret = f2fs_sync_fs(inode->i_sb, 1); +#ifdef CONFIG_F2FS_BD_STAT + cp_end = local_clock(); +#endif /* * We've secured consistency through sync_fs. Following pino @@ -317,10 +342,20 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, clear_inode_flag(inode, FI_UPDATE_WRITE); goto out; } +#if defined(CONFIG_UFSTW) + bdev_set_turbo_write(sbi->sb->s_bdev); + turbo_set = true; +#endif sync_nodes: +#ifdef CONFIG_F2FS_BD_STAT + sync_node_begin = local_clock(); +#endif atomic_inc(&sbi->wb_sync_req[NODE]); ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id); atomic_dec(&sbi->wb_sync_req[NODE]); +#ifdef CONFIG_F2FS_BD_STAT + sync_node_end = local_clock(); +#endif if (ret) goto out; @@ -354,8 +389,16 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, f2fs_remove_ino_entry(sbi, ino, APPEND_INO); clear_inode_flag(inode, FI_APPEND_WRITE); flush_out: +#ifdef CONFIG_F2FS_BD_STAT + if (!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) { + flush_begin = local_clock(); + ret = f2fs_issue_flush(sbi, inode->i_ino); + flush_end = local_clock(); + } +#else if (!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) ret = f2fs_issue_flush(sbi, inode->i_ino); +#endif if (!ret) { f2fs_remove_ino_entry(sbi, ino, UPDATE_INO); clear_inode_flag(inode, FI_UPDATE_WRITE); @@ -363,8 +406,37 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, } f2fs_update_time(sbi, REQ_TIME); out: +#if defined(CONFIG_UFSTW) + if (turbo_set) + bdev_clear_turbo_write(sbi->sb->s_bdev); +#endif trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret); f2fs_trace_ios(NULL, 1); +#ifdef CONFIG_F2FS_BD_STAT + if (!ret && fsync_begin) { + fsync_end = local_clock(); + bd_lock(sbi); + if (S_ISREG(inode->i_mode)) + bd_inc_val(sbi, fsync_reg_file_count, 1); + else if (S_ISDIR(inode->i_mode)) + bd_inc_val(sbi, fsync_dir_count, 1); + bd_inc_val(sbi, fsync_time, fsync_end - fsync_begin); + bd_max_val(sbi, max_fsync_time, fsync_end - fsync_begin); + bd_inc_val(sbi, fsync_wr_file_time, wr_file_end - fsync_begin); + bd_max_val(sbi, max_fsync_wr_file_time, wr_file_end - fsync_begin); + bd_inc_val(sbi, fsync_cp_time, cp_end - cp_begin); + bd_max_val(sbi, max_fsync_cp_time, cp_end - cp_begin); + if (sync_node_end) { + bd_inc_val(sbi, fsync_sync_node_time, + sync_node_end - sync_node_begin); + bd_max_val(sbi, max_fsync_sync_node_time, + sync_node_end - sync_node_begin); + } + bd_inc_val(sbi, fsync_flush_time, flush_end - flush_begin); + bd_max_val(sbi, max_fsync_flush_time, flush_end - flush_begin); + bd_unlock(sbi); + } +#endif trace_android_fs_fsync_end(inode, start, end - start); return ret; diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index db8725d473b52c285e1522d6379e5c271ea23359..799210b09fe7ce51ac19228f7c026cd9cfa6c346 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -20,6 +20,167 @@ #include "gc.h" #include +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add code to optimize gc */ +#define MIN_WAIT_MS 1000 +#define DEF_GC_BALANCE_MIN_SLEEP_TIME 10000 /* milliseconds */ +#define DEF_GC_FRAG_MIN_SLEEP_TIME 1000 /* milliseconds */ +#define GC_URGENT_CHECK_TIME (10*60*1000) /* milliseconds */ +#define GC_URGENT_DISABLE_BLOCKS (16<<18) /* 16G */ +#define GC_URGENT_DISABLE_FREE_BLOCKS (10<<18) /* 10G */ + +static inline bool __is_frag_urgent(struct f2fs_sb_info *sbi) +{ + block_t total_blocks, valid_blocks; + block_t blocks[9]; + unsigned int i; + + total_blocks = le64_to_cpu(sbi->raw_super->block_count); + valid_blocks = valid_user_blocks(sbi); + + if (total_blocks < GC_URGENT_DISABLE_BLOCKS || + total_blocks - valid_blocks > GC_URGENT_DISABLE_FREE_BLOCKS) + return false; + + total_blocks = 0; + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < MAIN_SEGS(sbi); i++) { + total_blocks += of2fs_seg_freefrag(sbi, i, + blocks, ARRAY_SIZE(blocks)); + cond_resched(); + } + + f2fs_printk(sbi, KERN_INFO "Extent Size Range: Free Blocks"); + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + if (!blocks[i]) + continue; + else if (i < 8) + f2fs_printk(sbi, KERN_INFO + "%dK...%dK-: %u", 4<= (total_blocks >> 1); +} + +static inline bool is_frag_urgent(struct f2fs_sb_info *sbi) +{ + unsigned long next_check = sbi->last_frag_check + + msecs_to_jiffies(GC_URGENT_CHECK_TIME); + if (time_after(jiffies, next_check)) { + sbi->last_frag_check = jiffies; + sbi->is_frag = __is_frag_urgent(sbi); + } + return sbi->is_frag; +} + +/* + * GC tuning ratio [0, 100] in performance mode + */ +static inline int gc_perf_ratio(struct f2fs_sb_info *sbi) +{ + block_t reclaimable_user_blocks = sbi->user_block_count - + written_block_count(sbi); + return reclaimable_user_blocks == 0 ? 100 : + 100ULL * free_user_blocks(sbi) / reclaimable_user_blocks; +} + +/* invaild blocks is more than 10% of total free space */ +static inline bool is_invaild_blocks_enough(struct f2fs_sb_info *sbi) +{ + block_t reclaimable_user_blocks = sbi->user_block_count - + written_block_count(sbi); + + return free_user_blocks(sbi) / 90 < reclaimable_user_blocks / 100; +} + +static inline bool is_gc_frag(struct f2fs_sb_info *sbi) +{ + return is_frag_urgent(sbi) && + free_segments(sbi) < 3 * overprovision_segments(sbi) && + is_invaild_blocks_enough(sbi); +} + +static inline bool is_gc_perf(struct f2fs_sb_info *sbi) +{ + return gc_perf_ratio(sbi) < 10 && + free_segments(sbi) < 3 * overprovision_segments(sbi); +} + +/* more than 90% of main area are valid blocks */ +static inline bool is_gc_lifetime(struct f2fs_sb_info *sbi) +{ + return written_block_count(sbi) / 90 > sbi->user_block_count / 100; +} + +static inline void of2fs_tune_wait_ms(struct f2fs_sb_info *sbi, unsigned int *wait_ms) +{ + unsigned int min_wait_ms; + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + + if (sbi->gc_mode == GC_URGENT) { + // do nothing in GC_URGENT mode + return; + } else if (is_gc_frag(sbi)) { + *wait_ms = DEF_GC_FRAG_MIN_SLEEP_TIME; + } else if (is_gc_lifetime(sbi)) { + gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME; + } else if (is_gc_perf(sbi)) { + *wait_ms = max(DEF_GC_THREAD_MAX_SLEEP_TIME * + gc_perf_ratio(sbi) / 100, MIN_WAIT_MS); + } else { + gc_th->min_sleep_time = DEF_GC_BALANCE_MIN_SLEEP_TIME; + } + min_wait_ms = f2fs_time_to_wait(sbi, GC_TIME); + if (*wait_ms < min_wait_ms) + *wait_ms = min_wait_ms; +} + +static inline bool of2fs_gc_wait(struct f2fs_sb_info *sbi, wait_queue_head_t *wq, unsigned int *wait_ms) +{ + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + wait_queue_head_t *fggc_wq = &gc_th->fggc_wait_queue_head; + + f2fs_printk(sbi, KERN_INFO "Debug:%s:gc_opt_enable:%d", __func__, sbi->gc_opt_enable); + if (!sbi->gc_opt_enable) { + wait_event_interruptible_timeout(*wq, + kthread_should_stop() || freezing(current) || + gc_th->gc_wake, + msecs_to_jiffies(*wait_ms)); + return false; + } + + of2fs_tune_wait_ms(sbi, wait_ms); + wait_event_interruptible_timeout(*wq, + kthread_should_stop() || freezing(current) || + atomic_read(&sbi->need_ssr_gc) > 0 || + wq_has_sleeper(fggc_wq) || + gc_th->gc_wake, + msecs_to_jiffies(*wait_ms)); + if (atomic_read(&sbi->need_ssr_gc) > 0) { + f2fs_printk(sbi, KERN_INFO "need_SSR GC triggered!"); + down_write(&sbi->gc_lock); + f2fs_gc(sbi, true, false, NULL_SEGNO); + atomic_dec(&sbi->need_ssr_gc); + if (!has_not_enough_free_secs(sbi, 0, 0) && + wq_has_sleeper(fggc_wq)) { + wake_up_all(fggc_wq); + } + return true; + } else if (wq_has_sleeper(fggc_wq)) { + f2fs_printk(sbi, KERN_INFO "FG GC triggered!"); + down_write(&sbi->gc_lock); + f2fs_gc(sbi, false, false, NULL_SEGNO); + wake_up_all(fggc_wq); + return true; + } + + return false; +} +#endif + static int gc_thread_func(void *data) { struct f2fs_sb_info *sbi = data; @@ -31,10 +192,18 @@ static int gc_thread_func(void *data) set_freezable(); do { +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add code to optimize gc */ + /* [ASTI-147]: add need_SSR GC */ + /* [ASTI-147]: do FG GC in GC thread */ + if (of2fs_gc_wait(sbi, wq, &wait_ms)) + continue; +#else wait_event_interruptible_timeout(*wq, kthread_should_stop() || freezing(current) || gc_th->gc_wake, msecs_to_jiffies(wait_ms)); +#endif /* give it a try one time */ if (gc_th->gc_wake) @@ -42,6 +211,8 @@ static int gc_thread_func(void *data) if (try_to_freeze()) { stat_other_skip_bggc_count(sbi); + f2fs_printk(sbi, KERN_INFO "Debug:%s:skip BG_GC cause try_to_freeze,wait:%ums", + __func__, wait_ms); continue; } if (kthread_should_stop()) @@ -50,6 +221,8 @@ static int gc_thread_func(void *data) if (sbi->sb->s_writers.frozen >= SB_FREEZE_WRITE) { increase_sleep_time(gc_th, &wait_ms); stat_other_skip_bggc_count(sbi); + f2fs_printk(sbi, KERN_INFO "Debug:%s:skip BG_GC cause FREEZE-writer,wait:%ums", + __func__, wait_ms); continue; } @@ -60,6 +233,8 @@ static int gc_thread_func(void *data) if (!sb_start_write_trylock(sbi->sb)) { stat_other_skip_bggc_count(sbi); + f2fs_printk(sbi, KERN_INFO "Debug:%s:skip BG_GC cause sblock,wait:%ums", + __func__, wait_ms); continue; } @@ -84,6 +259,8 @@ static int gc_thread_func(void *data) if (!down_write_trylock(&sbi->gc_lock)) { stat_other_skip_bggc_count(sbi); + f2fs_printk(sbi, KERN_INFO "Debug:%s:skip BG_GC cause gclock,wait:%ums", + __func__, wait_ms); goto next; } @@ -91,6 +268,8 @@ static int gc_thread_func(void *data) increase_sleep_time(gc_th, &wait_ms); up_write(&sbi->gc_lock); stat_io_skip_bggc_count(sbi); + f2fs_printk(sbi, KERN_INFO "Debug:%s:skip BG_GC cause not idle,wait:%ums", + __func__, wait_ms); goto next; } @@ -100,6 +279,7 @@ static int gc_thread_func(void *data) increase_sleep_time(gc_th, &wait_ms); do_gc: stat_inc_bggc_count(sbi->stat_info); + f2fs_printk(sbi, KERN_INFO "Debug:%s:do BG_GC,wait:%ums", __func__, wait_ms); /* if return value is not zero, no victim was selected */ if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO)) @@ -114,6 +294,7 @@ static int gc_thread_func(void *data) sb_end_write(sbi->sb); } while (!kthread_should_stop()); + f2fs_printk(sbi, KERN_INFO "Debug:%s:gc_opt_return", __func__); return 0; } @@ -136,8 +317,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi) gc_th->gc_wake= 0; + f2fs_printk(sbi, KERN_INFO "Debug:%s:start gc thread", __func__); + sbi->gc_thread = gc_th; init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: do FG GC in GC thread */ + init_waitqueue_head(&sbi->gc_thread->fggc_wait_queue_head); +#endif sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi, "f2fs_gc-%u:%u", MAJOR(dev), MINOR(dev)); if (IS_ERR(gc_th->f2fs_gc_task)) { @@ -512,6 +699,9 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, int phase = 0; bool fggc = (gc_type == FG_GC); int submitted = 0; +#ifdef CONFIG_F2FS_BD_STAT + int gc_blks = 0; +#endif start_addr = START_BLOCK(sbi, segno); @@ -528,8 +718,17 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, int err; /* stop BG_GC if there is not enough free sections. */ +#ifdef CONFIG_F2FS_BD_STAT + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) { + bd_lock(sbi); + bd_inc_array_val(sbi, gc_node_blocks, gc_type, gc_blks); + bd_unlock(sbi); + return submitted; + } +#else if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) return submitted; +#endif if (check_valid_map(sbi, segno, off) == 0) continue; @@ -569,6 +768,10 @@ static int gc_node_segment(struct f2fs_sb_info *sbi, err = f2fs_move_node_page(node_page, gc_type); if (!err && gc_type == FG_GC) submitted++; +#ifdef CONFIG_F2FS_BD_STAT + if (!err) + gc_blks++; +#endif stat_inc_node_blk_count(sbi, 1, gc_type); } @@ -998,6 +1201,9 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, int off; int phase = 0; int submitted = 0; +#ifdef CONFIG_F2FS_BD_STAT + int gc_blks = 0; +#endif start_addr = START_BLOCK(sbi, segno); @@ -1017,10 +1223,20 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, * Or, stop GC if the segment becomes fully valid caused by * race condition along with SSR block allocation. */ +#ifdef CONFIG_F2FS_BD_STAT + if (gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) { + bd_lock(sbi); + bd_inc_array_val(sbi, gc_data_blocks, gc_type, gc_blks); + bd_inc_array_val(sbi, hotcold_count, HC_GC_COLD_DATA, gc_blks); + bd_unlock(sbi); + return submitted; + } +#else if ((gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) || get_valid_blocks(sbi, segno, false) == sbi->blocks_per_seg) return submitted; +#endif if (check_valid_map(sbi, segno, off) == 0) continue; @@ -1129,6 +1345,10 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, up_write(&fi->i_gc_rwsem[READ]); } +#ifdef CONFIG_F2FS_BD_STAT + if (!err) + gc_blks++; +#endif stat_inc_data_blk_count(sbi, 1, gc_type); } } @@ -1136,6 +1356,13 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (++phase < 5) goto next_step; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, gc_data_blocks, gc_type, gc_blks); + bd_inc_array_val(sbi, hotcold_count, HC_GC_COLD_DATA, gc_blks); + bd_unlock(sbi); +#endif + return submitted; } @@ -1165,6 +1392,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned char type = IS_DATASEG(get_seg_entry(sbi, segno)->type) ? SUM_TYPE_DATA : SUM_TYPE_NODE; int submitted = 0; +#ifdef CONFIG_F2FS_BD_STAT + int hc_type = get_seg_entry(sbi, segno)->type; +#endif if (__is_large_section(sbi)) end_segno = rounddown(end_segno, sbi->segs_per_sec); @@ -1239,6 +1469,19 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, get_valid_blocks(sbi, segno, false) == 0) seg_freed++; migrated++; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + if (gc_type == BG_GC || get_valid_blocks(sbi, segno, 1) == 0) { + if (type == SUM_TYPE_NODE) + bd_inc_array_val(sbi, gc_node_segments, gc_type, 1); + else + bd_inc_array_val(sbi, gc_data_segments, gc_type, 1); + bd_inc_array_val(sbi, hotcold_gc_segments, hc_type + 1, 1); + } + bd_inc_array_val(sbi, hotcold_gc_blocks, hc_type + 1, + (unsigned long)get_valid_blocks(sbi, segno, 1)); + bd_unlock(sbi); +#endif if (__is_large_section(sbi) && segno + 1 < end_segno) sbi->next_victim_seg[gc_type] = segno + 1; @@ -1272,6 +1515,12 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, unsigned long long last_skipped = sbi->skipped_atomic_files[FG_GC]; unsigned long long first_skipped; unsigned int skipped_round = 0, round = 0; +#ifdef CONFIG_F2FS_BD_STAT + bool gc_completed = false; + u64 fggc_begin, fggc_end; + + fggc_begin = local_clock(); +#endif trace_f2fs_gc_begin(sbi->sb, sync, background, get_pages(sbi, F2FS_DIRTY_NODES), @@ -1325,6 +1574,9 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, if (gc_type == FG_GC && seg_freed == sbi->segs_per_sec) sec_freed++; total_freed += seg_freed; +#ifdef CONFIG_F2FS_BD_STAT + gc_completed = true; +#endif if (gc_type == FG_GC) { if (sbi->skipped_atomic_files[FG_GC] > last_skipped || @@ -1371,6 +1623,18 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, prefree_segments(sbi)); up_write(&sbi->gc_lock); +#ifdef CONFIG_F2FS_BD_STAT + if (gc_completed) { + fggc_end = gc_type == FG_GC ? local_clock() : 0; + bd_lock(sbi); + if (fggc_end) + bd_inc_val(sbi, fggc_time, fggc_end - fggc_begin); + bd_inc_array_val(sbi, gc_count, gc_type, 1); + if (ret) + bd_inc_array_val(sbi, gc_fail_count, gc_type, 1); + bd_unlock(sbi); + } +#endif put_gc_inode(&gc_list); @@ -1385,6 +1649,12 @@ void f2fs_build_gc_manager(struct f2fs_sb_info *sbi) sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add need_SSR GC */ + atomic_set(&sbi->need_ssr_gc, 0); + sbi->gc_opt_enable = true; +#endif + /* give warm/cold data area from slower device */ if (f2fs_is_multi_device(sbi) && !__is_large_section(sbi)) SIT_I(sbi)->last_victim[ALLOC_NEXT] = diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index bbac9d3787bd35e4bbdfb1a2ea65853148d1e6a2..c82e596de6805ec08ec066180934328877c7f043 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -25,6 +25,11 @@ struct f2fs_gc_kthread { struct task_struct *f2fs_gc_task; wait_queue_head_t gc_wait_queue_head; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: do FG GC in GC thread */ + wait_queue_head_t fggc_wait_queue_head; +#endif + /* for gc sleep time */ unsigned int urgent_sleep_time; @@ -41,6 +46,13 @@ struct gc_inode_list { struct radix_tree_root iroot; }; +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: declare */ +extern block_t of2fs_seg_freefrag(struct f2fs_sb_info *sbi, unsigned int segno, block_t *blocks, unsigned int n); + +extern int f2fs_odiscard_enable; +#endif + /* * inline functions */ diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index aa4a91e8c7356890067965624984a2d4ac17ee22..a0cb01ec7da7028cbf8311be5779272d59f5f275 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -567,6 +567,11 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid, nat_blk = (struct f2fs_nat_block *)page_address(page); ne = nat_blk->entries[nid - start_nid]; node_info_from_raw_nat(ni, &ne); + + if (nid == 3) + f2fs_info(sbi, "%s: roo node, nid:3, nat block:%d, block addr:%u, ino:%d\n", + __func__, index, ni->blk_addr, ni->ino); + f2fs_put_page(page, 1); cache: blkaddr = le32_to_cpu(ne.block_addr); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 469990ab1e629aff0aa5c751b08054736fd4bd28..e2173be5ca6f41af61fb88090873e442763557b5 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -15,6 +15,14 @@ #include #include #include +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: trigger need_SSR GC base on bigdata stats */ +#include + +/* [ASTI-147]: add for oDiscard */ +int f2fs_trim_status; +int f2fs_odiscard_enable = true; +#endif #include "f2fs.h" #include "segment.h" @@ -29,6 +37,16 @@ static struct kmem_cache *discard_entry_slab; static struct kmem_cache *discard_cmd_slab; static struct kmem_cache *sit_entry_set_slab; static struct kmem_cache *inmem_entry_slab; +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add for oDiscard */ +static struct discard_cmd *__create_discard_cmd_of2fs(struct f2fs_sb_info *sbi, + struct block_device *bdev, block_t lstart, + block_t start, block_t len); +static void __init_discard_policy_of2fs(struct f2fs_sb_info *sbi, + struct discard_policy *dpolicy, + int discard_type, unsigned int granularity); +static int select_discard_type_of2fs(struct f2fs_sb_info *sbi, int expect_discard_type); +#endif static unsigned long __reverse_ulong(unsigned char *str) { @@ -183,6 +201,35 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi) SM_I(sbi)->min_ssr_sections + reserved_sections(sbi)); } + +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add code to optimize gc */ +block_t of2fs_seg_freefrag(struct f2fs_sb_info *sbi, unsigned int segno, + block_t *blocks, unsigned int n) +{ + struct seg_entry *se = get_seg_entry(sbi, segno); + unsigned long *cur_map = (unsigned long *)se->cur_valid_map; + unsigned int pos, pos0; + block_t total_blocks = 0; + // free and valid segment is not fragment + if (!se->valid_blocks || se->valid_blocks == sbi->blocks_per_seg) + return total_blocks; + pos0 = __find_rev_next_zero_bit(cur_map, sbi->blocks_per_seg, 0); + while (pos0 < sbi->blocks_per_seg) { + unsigned int blks, order; + + pos = __find_rev_next_bit(cur_map, sbi->blocks_per_seg, pos0 + 1); + blks = pos - pos0; + order = ilog2(blks); + if (order < n) + blocks[order] += blks; + total_blocks += blks; + pos0 = __find_rev_next_zero_bit(cur_map, sbi->blocks_per_seg, pos + 1); + } + return total_blocks; +} +#endif + void f2fs_register_inmem_page(struct inode *inode, struct page *page) { struct inmem_pages *new; @@ -481,6 +528,121 @@ int f2fs_commit_inmem_pages(struct inode *inode) return err; } +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add need_SSR GC */ +/* [ASTI-147]: do FG GC in GC thread */ +/* [ASTI-147]: trigger need_SSR GC base on bigdata stats */ +#define DEF_DIRTY_STAT_INTERVAL 15 /* 15 secs */ +static inline bool of2fs_need_balance_dirty(struct f2fs_sb_info *sbi) +{ +#ifdef CONFIG_F2FS_BD_STAT + struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + struct timespec ts = {DEF_DIRTY_STAT_INTERVAL, 0}; + unsigned long interval = timespec_to_jiffies(&ts); + struct f2fs_bigdata_info *bd = F2FS_BD_STAT(sbi); + unsigned long last_jiffies; + int dirty_node = 0, dirty_data = 0, all_dirty; + long node_cnt, data_cnt; + int i; + + last_jiffies = bd->ssr_last_jiffies; + + if (time_before(jiffies, last_jiffies + interval)) + return false; + + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) + dirty_data += dirty_i->nr_dirty[i]; + for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) + dirty_node += dirty_i->nr_dirty[i]; + all_dirty = dirty_data + dirty_node; + if (!all_dirty) + return false; + + /* how many blocks are consumed during this interval */ + bd_lock(sbi); + node_cnt = (long)(bd->curr_node_alloc_count - bd->last_node_alloc_count); + data_cnt = (long)(bd->curr_data_alloc_count - bd->last_data_alloc_count); + + bd->last_node_alloc_count = bd->curr_node_alloc_count; + bd->last_data_alloc_count = bd->curr_data_alloc_count; + bd->ssr_last_jiffies = jiffies; + bd_unlock(sbi); + + + if (dirty_data < reserved_sections(sbi) && + data_cnt > (long)sbi->blocks_per_seg) { + int randnum = prandom_u32_max(100); + int ratio = dirty_data * 100 / all_dirty; + + if (randnum > ratio) + return true; + } + + if (dirty_node < reserved_sections(sbi) && + node_cnt > (long)sbi->blocks_per_seg) { + int randnum = prandom_u32_max(100); + int ratio = dirty_node * 100 / all_dirty; + + if (randnum > ratio) + return true; + } +#endif + return false; +} + +static inline void of2fs_balance_fs(struct f2fs_sb_info *sbi) +{ + if (!sbi->gc_opt_enable) { + /* + * We should do GC or end up with checkpoint, if there are so many dirty + * dir/node pages without enough free segments. + */ + if (has_not_enough_free_secs(sbi, 0, 0)) { + down_write(&sbi->gc_lock); + f2fs_gc(sbi, false, false, NULL_SEGNO); + } + return; + } + + /* + * We should do GC or end up with checkpoint, if there are so many dirty + * dir/node pages without enough free segments. + */ + if (has_not_enough_free_secs(sbi, 0, 0)) { + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + + if (gc_th != NULL) { + DEFINE_WAIT(__wait); + + f2fs_printk(sbi, KERN_INFO "Debug:%s:begin wait trigger fggc,gc_opt_enable:%d", + __func__, sbi->gc_opt_enable); + + prepare_to_wait(&gc_th->fggc_wait_queue_head, + &__wait, TASK_UNINTERRUPTIBLE); + f2fs_printk(sbi, KERN_INFO "Debug:%s:finish wait trigger fggc,gc_opt_enable:%d", + __func__, sbi->gc_opt_enable); + wake_up(&gc_th->gc_wait_queue_head); + schedule(); + finish_wait(&gc_th->fggc_wait_queue_head, &__wait); + } else { + f2fs_printk(sbi, KERN_INFO "Debug:%s:no-gcthread,fggc,gc_opt_enable:%d", + __func__, sbi->gc_opt_enable); + down_write(&sbi->gc_lock); + f2fs_gc(sbi, false, false, NULL_SEGNO); + } + } else if (f2fs_need_SSR(sbi) && of2fs_need_balance_dirty(sbi)) { + struct f2fs_gc_kthread *gc_th = sbi->gc_thread; + + if (gc_th != NULL) { + f2fs_printk(sbi, KERN_INFO "Debug:%s:tigger SSR,gc_opt_enable:%d", + __func__, sbi->gc_opt_enable); + atomic_inc(&sbi->need_ssr_gc); + wake_up(&gc_th->gc_wait_queue_head); + } + } +} +#endif + /* * This function balances dirty node and dentry pages. * In addition, it controls garbage collection. @@ -499,14 +661,20 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) if (!f2fs_is_checkpoint_ready(sbi)) return; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add need_SSR GC */ + of2fs_balance_fs(sbi); +#else /* * We should do GC or end up with checkpoint, if there are so many dirty * dir/node pages without enough free segments. */ if (has_not_enough_free_secs(sbi, 0, 0)) { down_write(&sbi->gc_lock); + f2fs_printk(sbi, KERN_INFO "Debug:%s:original fggc", __func__); f2fs_gc(sbi, false, false, NULL_SEGNO); } +#endif } void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) @@ -883,6 +1051,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi) struct seg_entry *se; unsigned int segno; + f2fs_info(sbi, "Debug:%s: into", __func__); mutex_lock(&dirty_i->seglist_lock); for_each_set_bit(segno, dirty_i->dirty_segmap[DIRTY], MAIN_SEGS(sbi)) { se = get_seg_entry(sbi, segno); @@ -903,11 +1072,23 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable) { int ovp_hole_segs = (overprovision_segments(sbi) - reserved_segments(sbi)); - if (unusable > F2FS_OPTION(sbi).unusable_cap) + + f2fs_info(sbi, "Debug:%s: unusable:%u, unusable_cap:%u\n" + , __func__, unusable, F2FS_OPTION(sbi).unusable_cap); + + if (unusable > F2FS_OPTION(sbi).unusable_cap){ + f2fs_info(sbi, "Debug:%s: try again1\n", __func__); return -EAGAIN; + } + + f2fs_info(sbi, "Debug:%s: dirty segments:%u, ovp_hole_segs:%u\n" + , __func__, dirty_segments(sbi), ovp_hole_segs); + if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) && - dirty_segments(sbi) > ovp_hole_segs) + dirty_segments(sbi) > ovp_hole_segs){ + f2fs_info(sbi, "Debug:%s: try again2\n", __func__); return -EAGAIN; + } return 0; } @@ -952,6 +1133,9 @@ static struct discard_cmd *__create_discard_cmd(struct f2fs_sb_info *sbi, dc->state = D_PREP; dc->queued = 0; dc->error = 0; +#ifdef CONFIG_F2FS_BD_STAT + dc->discard_time = 0; +#endif init_completion(&dc->wait); list_add_tail(&dc->list, pend_list); spin_lock_init(&dc->lock); @@ -971,7 +1155,15 @@ static struct discard_cmd *__attach_discard_cmd(struct f2fs_sb_info *sbi, struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; struct discard_cmd *dc; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + dc = __create_discard_cmd_of2fs(sbi, bdev, lstart, start, len); + else + dc = __create_discard_cmd(sbi, bdev, lstart, start, len); +#else dc = __create_discard_cmd(sbi, bdev, lstart, start, len); +#endif rb_link_node(&dc->rb_node, parent, p); rb_insert_color_cached(&dc->rb_node, &dcc->root, leftmost); @@ -1010,6 +1202,16 @@ static void __remove_discard_cmd(struct f2fs_sb_info *sbi, spin_unlock_irqrestore(&dc->lock, flags); f2fs_bug_on(sbi, dc->ref); +#ifdef CONFIG_F2FS_BD_STAT + if (dc->state == D_DONE && !dc->error && dc->discard_time) { + bd_lock(sbi); + bd_inc_val(sbi, discard_blocks, dc->len); + bd_inc_val(sbi, discard_count, 1); + bd_inc_val(sbi, discard_time, dc->discard_time); + bd_max_val(sbi, max_discard_time, dc->discard_time); + bd_unlock(sbi); + } +#endif if (dc->error == -EOPNOTSUPP) dc->error = 0; @@ -1033,6 +1235,16 @@ static void f2fs_submit_discard_endio(struct bio *bio) dc->bio_ref--; if (!dc->bio_ref && dc->state == D_SUBMIT) { dc->state = D_DONE; +#ifdef CONFIG_F2FS_BD_STAT + if (dc->discard_time) { + u64 discard_end_time = (u64)ktime_get(); + + if (discard_end_time > dc->discard_time) + dc->discard_time = discard_end_time - dc->discard_time; + else + dc->discard_time = 0; + } +#endif complete_all(&dc->wait); } spin_unlock_irqrestore(&dc->lock, flags); @@ -1182,6 +1394,10 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, * right away */ spin_lock_irqsave(&dc->lock, flags); +#ifdef CONFIG_F2FS_BD_STAT + if (dc->state == D_PREP) + dc->discard_time = (u64)ktime_get(); +#endif if (last) dc->state = D_SUBMIT; else @@ -1431,6 +1647,11 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, goto next; if (dpolicy->io_aware && !is_idle(sbi, DISCARD_TIME)) { +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + dpolicy->io_busy = true; +#endif io_interrupted = true; break; } @@ -1507,6 +1728,11 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, if (dpolicy->io_aware && i < dpolicy->io_aware_gran && !is_idle(sbi, DISCARD_TIME)) { io_interrupted = true; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + dpolicy->io_busy = true; +#endif break; } @@ -1632,9 +1858,25 @@ static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi, return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX); /* wait all */ +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + __init_discard_policy_of2fs(sbi, &dp, DPOLICY_FSTRIM, 1); + else + __init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1); +#else __init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1); +#endif discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + __init_discard_policy_of2fs(sbi, &dp, DPOLICY_UMOUNT, 1); + else + __init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1); +#else __init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1); +#endif discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); return discard_blks; @@ -1683,8 +1925,15 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) struct discard_policy dpolicy; bool dropped; - __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, - dcc->discard_granularity); +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + __init_discard_policy_of2fs(sbi, &dpolicy, DPOLICY_UMOUNT, dcc->discard_granularity); + else + __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, dcc->discard_granularity); +#else + __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, dcc->discard_granularity); +#endif dpolicy.timeout = UMOUNT_DISCARD_TIMEOUT; __issue_discard_cmd(sbi, &dpolicy); dropped = __drop_discard_cmd(sbi); @@ -1704,10 +1953,167 @@ static int issue_discard_thread(void *data) struct discard_policy dpolicy; unsigned int wait_ms = DEF_MIN_DISCARD_ISSUE_TIME; int issued; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for odiscard */ + int discard_type = DPOLICY_BG; + int expect_odiscard_type = MAX_DPOLICY; + unsigned long odiscard_expire = 0; + int discard_cmd_cnt = 0; + + if (f2fs_odiscard_enable) { + wait_ms = DEF_MIN_DISCARD_ISSUE_TIME_OF2FS; + discard_type = DPOLICY_BG; + } +#endif set_freezable(); do { +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for odiscard */ + if (f2fs_odiscard_enable) { + wait_event_interruptible_timeout(*q, + kthread_should_stop() || freezing(current) || + dcc->discard_wake || dcc->odiscard_wake || dcc->otrim_wake, + msecs_to_jiffies(wait_ms)); + + if (dcc->discard_wake) + expect_odiscard_type = MAX_DPOLICY; + + if (dcc->odiscard_wake) { + odiscard_expire = jiffies + msecs_to_jiffies(ODISCARD_EXEC_TIME_NO_CHARGING); + expect_odiscard_type = DPOLICY_ODISCARD; + } + + if (dcc->otrim_wake) { + expect_odiscard_type = DPOLICY_FSTRIM; + discard_cmd_cnt = atomic_read(&dcc->discard_cmd_cnt); + } + + dcc->discard_wake = 0; + dcc->odiscard_wake = 0; + dcc->otrim_wake = 0; + + /* clean up pending candidates before going to sleep */ + if (atomic_read(&dcc->queued_discard)) + __wait_all_discard_cmd(sbi, NULL); + + if (try_to_freeze()) + continue; + if (f2fs_readonly(sbi->sb)) + continue; + if (kthread_should_stop()) { + f2fs_printk(sbi, KERN_INFO "Debug:%s:discard thread return f2fs_odiscard_enable:%d", + __func__, sbi->gc_opt_enable); + return 0; + } + if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { + wait_ms = dpolicy.max_interval; + continue; + } + + if (expect_odiscard_type == DPOLICY_ODISCARD) { + /* limit odiscard exec 8 s */ + if (!f2fs_device.battery_charging && time_after(jiffies, odiscard_expire)) { + wait_ms = DEF_MAX_DISCARD_ISSUE_TIME_OF2FS; + continue; + } + } + + if (sbi->gc_mode == GC_URGENT) { + discard_type = DPOLICY_FORCE; + __init_discard_policy_of2fs(sbi, &dpolicy, discard_type, 1); + } else { + discard_type = select_discard_type_of2fs(sbi, expect_odiscard_type); + __init_discard_policy_of2fs(sbi, &dpolicy, discard_type, + dcc->discard_granularity); + + if (DPOLICY_FSTRIM == expect_odiscard_type && DPOLICY_FSTRIM != discard_type) + f2fs_trim_status = F2FS_TRIM_INTERRUPT; + } + + sb_start_intwrite(sbi->sb); + + issued = __issue_discard_cmd(sbi, &dpolicy); + if (issued > 0) { + __wait_all_discard_cmd(sbi, &dpolicy); + if (dpolicy.io_busy) { + wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); + if (!wait_ms) + wait_ms = dpolicy.mid_interval; + } else { + wait_ms = dpolicy.min_interval; + } + } else if (issued == -1) { + wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); + if (!wait_ms) + wait_ms = dpolicy.mid_interval; + } else { + wait_ms = dpolicy.max_interval; + } + + if (discard_type == DPOLICY_FSTRIM) { + discard_cmd_cnt -= issued; + if (discard_cmd_cnt <= 0 || 0 == issued) { + expect_odiscard_type = MAX_DPOLICY; + wait_ms = dpolicy.max_interval; + f2fs_trim_status = F2FS_TRIM_FINISH; + } + } + + sb_end_intwrite(sbi->sb); + + } else { + + __init_discard_policy(sbi, &dpolicy, DPOLICY_BG, + dcc->discard_granularity); + + wait_event_interruptible_timeout(*q, + kthread_should_stop() || freezing(current) || + dcc->discard_wake, + msecs_to_jiffies(wait_ms)); + + if (dcc->discard_wake) + dcc->discard_wake = 0; + + /* clean up pending candidates before going to sleep */ + if (atomic_read(&dcc->queued_discard)) + __wait_all_discard_cmd(sbi, NULL); + + if (try_to_freeze()) + continue; + if (f2fs_readonly(sbi->sb)) + continue; + if (kthread_should_stop()) { + f2fs_printk(sbi, KERN_INFO "Debug:%s:non-jumpedin, discard thread return", __func__); + return 0; + } + if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { + wait_ms = dpolicy.max_interval; + continue; + } + + if (sbi->gc_mode == GC_URGENT) + __init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1); + + sb_start_intwrite(sbi->sb); + + issued = __issue_discard_cmd(sbi, &dpolicy); + if (issued > 0) { + __wait_all_discard_cmd(sbi, &dpolicy); + wait_ms = dpolicy.min_interval; + } else if (issued == -1) { + wait_ms = f2fs_time_to_wait(sbi, DISCARD_TIME); + if (!wait_ms) + wait_ms = dpolicy.mid_interval; + } else { + wait_ms = dpolicy.max_interval; + } + + sb_end_intwrite(sbi->sb); + + } +#else __init_discard_policy(sbi, &dpolicy, DPOLICY_BG, dcc->discard_granularity); @@ -1727,8 +2133,10 @@ static int issue_discard_thread(void *data) continue; if (f2fs_readonly(sbi->sb)) continue; - if (kthread_should_stop()) + if (kthread_should_stop()) { + f2fs_printk(sbi, KERN_INFO "Debug:%s:non-jumpedin, discard thread return", __func__); return 0; + } if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { wait_ms = dpolicy.max_interval; continue; @@ -1752,8 +2160,9 @@ static int issue_discard_thread(void *data) } sb_end_intwrite(sbi->sb); - +#endif } while (!kthread_should_stop()); + f2fs_printk(sbi, KERN_INFO "Debug:%s:discard return", __func__); return 0; } @@ -2879,13 +3288,27 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) * discard option. User configuration looks like using runtime discard * or periodic fstrim instead of it. */ - if (f2fs_realtime_discard_enable(sbi)) + if (f2fs_realtime_discard_enable(sbi)) { +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + wake_up_otrim_of2fs(sbi); +#endif goto out; + } start_block = START_BLOCK(sbi, start_segno); end_block = START_BLOCK(sbi, end_segno + 1); +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + if (f2fs_odiscard_enable) + __init_discard_policy_of2fs(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); + else + __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); +#else __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); +#endif trimmed = __issue_discard_cmd_range(sbi, &dpolicy, start_block, end_block); @@ -3126,6 +3549,18 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, __refresh_next_blkoff(sbi, curseg); stat_inc_block_count(sbi, curseg); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + if (type >= CURSEG_HOT_DATA && type <= CURSEG_COLD_DATA) { + bd_inc_array_val(sbi, data_alloc_count, curseg->alloc_type, 1); + bd_inc_val(sbi, curr_data_alloc_count, 1); + } else if (type >= CURSEG_HOT_NODE && type <= CURSEG_COLD_NODE) { + bd_inc_array_val(sbi, node_alloc_count, curseg->alloc_type, 1); + bd_inc_val(sbi, curr_node_alloc_count, 1); + } + bd_inc_array_val(sbi, hotcold_count, type + 1, 1UL); + bd_unlock(sbi); +#endif /* * SIT information should be updated before segment allocation, @@ -3249,6 +3684,19 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, stat_inc_meta_count(sbi, page->index); f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + if (fio.new_blkaddr >= le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr) && + (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->sit_blkaddr))) + bd_inc_array_val(sbi, hotcold_count, HC_META_CP, 1); + else if (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->nat_blkaddr)) + bd_inc_array_val(sbi, hotcold_count, HC_META_SIT, 1); + else if (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->ssa_blkaddr)) + bd_inc_array_val(sbi, hotcold_count, HC_META_NAT, 1); + else if (fio.new_blkaddr < le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr)) + bd_inc_array_val(sbi, hotcold_count, HC_META_SSA, 1); + bd_unlock(sbi); +#endif } void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio) @@ -3295,6 +3743,12 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) } stat_inc_inplace_blocks(fio->sbi); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_val(sbi, data_ipu_count, 1); + bd_unlock(sbi); +#endif + if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) err = f2fs_merge_page_bio(fio); @@ -4618,3 +5072,152 @@ void f2fs_destroy_segment_manager_caches(void) kmem_cache_destroy(discard_entry_slab); kmem_cache_destroy(inmem_entry_slab); } + +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add for oDiscard */ +static struct discard_cmd *__create_discard_cmd_of2fs(struct f2fs_sb_info *sbi, + struct block_device *bdev, block_t lstart, + block_t start, block_t len) +{ + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + struct list_head *pend_list; + struct discard_cmd *dc; + block_t user_block_count = sbi->user_block_count; + block_t ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg; + block_t fs_available_blocks = user_block_count - + valid_user_blocks(sbi) + ovp_count; + + f2fs_bug_on(sbi, !len); + + pend_list = &dcc->pend_list[plist_idx(len)]; + + dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS); + INIT_LIST_HEAD(&dc->list); + dc->bdev = bdev; + dc->lstart = lstart; + dc->start = start; + dc->len = len; + dc->ref = 0; + dc->state = D_PREP; + dc->queued = 0; + dc->error = 0; +#ifdef CONFIG_F2FS_BD_STAT + dc->discard_time = 0; +#endif + init_completion(&dc->wait); + list_add_tail(&dc->list, pend_list); + spin_lock_init(&dc->lock); + dc->bio_ref = 0; + atomic_inc(&dcc->discard_cmd_cnt); + dcc->undiscard_blks += len; + + if (dcc->undiscard_blks > (fs_available_blocks * + DEVICE_FREE_SPACE_PERCENT / 100) && + !(fs_available_blocks - dcc->undiscard_blks < + device_free_space_threshold(sbi))) { + wake_up_odiscard_of2fs(sbi); + } + return dc; +} + +static void __init_discard_policy_of2fs(struct f2fs_sb_info *sbi, + struct discard_policy *dpolicy, + int discard_type, unsigned int granularity) +{ + /* common policy */ + dpolicy->type = discard_type; + dpolicy->sync = true; + dpolicy->ordered = false; + dpolicy->granularity = granularity; + + dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST; + dpolicy->io_aware_gran = MAX_PLIST_NUM; + dpolicy->timeout = 0; + dpolicy->io_busy = false; + + if (discard_type == DPOLICY_BG) { + dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME_OF2FS; + dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME_OF2FS; + dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME_OF2FS; + dpolicy->io_aware = true; + dpolicy->sync = false; + dpolicy->ordered = true; + if (utilization(sbi) > DEF_DISCARD_URGENT_UTIL) { + dpolicy->granularity = 1; + dpolicy->max_interval = DEF_MIN_DISCARD_ISSUE_TIME_OF2FS; + } + } else if (discard_type == DPOLICY_FORCE) { + dpolicy->min_interval = DEF_URGENT_DISCARD_ISSUE_TIME; + dpolicy->mid_interval = DEF_MID_DISCARD_ISSUE_TIME_OF2FS; + dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME_OF2FS; + dpolicy->io_aware = false; + } else if (discard_type == DPOLICY_ODISCARD) { + dpolicy->granularity = 1; + dpolicy->min_interval = 0; + dpolicy->mid_interval = 500; + dpolicy->max_interval = DEF_DISCARD_EMPTY_ISSUE_TIME; + dpolicy->io_aware = true; + } else if (discard_type == DPOLICY_FSTRIM) { + dpolicy->granularity = 1; + dpolicy->min_interval = 0; + dpolicy->mid_interval = 0; + dpolicy->max_interval = DEF_DISCARD_EMPTY_ISSUE_TIME; + dpolicy->io_aware = false; + } else if (discard_type == DPOLICY_UMOUNT) { + dpolicy->max_requests = UINT_MAX; + dpolicy->io_aware = false; + /* we need to issue all to keep CP_TRIMMED_FLAG */ + dpolicy->granularity = 1; + } +} + +static int select_discard_type_of2fs(struct f2fs_sb_info *sbi, int expect_discard_type) +{ + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + block_t user_block_count = sbi->user_block_count; + block_t ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg; + block_t fs_available_blocks = user_block_count - + valid_user_blocks(sbi) + ovp_count; + + if (expect_discard_type == DPOLICY_ODISCARD) { + if (f2fs_device.battery_charging || (f2fs_device.screen_off && + f2fs_device.battery_percent >= BATTERY_THRESHOLD)) { + return DPOLICY_ODISCARD; + } + } + + if (expect_discard_type == DPOLICY_FSTRIM) { + if (f2fs_device.battery_charging + && f2fs_device.screen_off) { + return DPOLICY_FSTRIM; + } + } + + if (fs_available_blocks < fs_free_space_threshold(sbi) && + fs_available_blocks - dcc->undiscard_blks < + device_free_space_threshold(sbi)) { + return DPOLICY_FORCE; + } + + return DPOLICY_BG; +} + +inline void wake_up_odiscard_of2fs(struct f2fs_sb_info *sbi) +{ + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + + dcc->odiscard_wake = 1; + sbi->odiscard_already_run = true; + sbi->last_wp_odc_jiffies = jiffies; + wake_up_interruptible_all(&dcc->discard_wait_queue); +} + + +inline void wake_up_otrim_of2fs(struct f2fs_sb_info *sbi) +{ + struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; + + dcc->otrim_wake = 1; + wake_up_interruptible_all(&dcc->discard_wait_queue); +} +#endif diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 459dc3901a574c8a1cc66ef265e5c13dea58bb8e..2753303efb704884958c3de5ade128beb9ee01e3 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -613,7 +613,12 @@ static inline int utilization(struct f2fs_sb_info *sbi) * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode) */ #define DEF_MIN_IPU_UTIL 70 +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: enlarge min_fsync_blocks to optimize performance */ +#define DEF_MIN_FSYNC_BLOCKS 20 +#else #define DEF_MIN_FSYNC_BLOCKS 8 +#endif #define DEF_MIN_HOT_BLOCKS 16 #define SMALL_VOLUME_SEGMENTS (16 * 512) /* 16GB */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ff8f15623a5fa474b795ca0ecf0ccbb4bdc5e02a..c86299d2889a696c2ff3f22d090559b3db22cf40 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,21 @@ #define CREATE_TRACE_POINTS #include + +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add for oDiscard */ +#include +#include +#include + +static LIST_HEAD(all_f2fs_sbi); +static spinlock_t sb_list_lock; +static unsigned long odc_wakeup_interval; +struct f2fs_device_state f2fs_device; +static BLOCKING_NOTIFIER_HEAD(f2fs_panel_notifier_list); +static BLOCKING_NOTIFIER_HEAD(f2fs_battery_notifier_list); +#endif + static struct kmem_cache *f2fs_inode_cachep; #ifdef CONFIG_F2FS_FAULT_INJECTION @@ -214,6 +230,40 @@ static match_table_t f2fs_tokens = { {Opt_err, NULL}, }; +#ifdef CONFIG_F2FS_OF2FS +int f2fs_panel_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&f2fs_panel_notifier_list, nb); +} + +int f2fs_panel_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&f2fs_panel_notifier_list, nb); +} + +int f2fs_panel_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&f2fs_panel_notifier_list, val, v); +} +EXPORT_SYMBOL(f2fs_panel_notifier_call_chain); + +int f2fs_battery_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&f2fs_battery_notifier_list, nb); +} + +int f2fs_battery_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&f2fs_battery_notifier_list, nb); +} + +int f2fs_battery_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&f2fs_battery_notifier_list, val, v); +} +EXPORT_SYMBOL(f2fs_battery_notifier_call_chain); +#endif + void f2fs_printk(struct f2fs_sb_info *sbi, const char *fmt, ...) { struct va_format vaf; @@ -292,6 +342,114 @@ static void init_once(void *foo) inode_init_once(&fi->vfs_inode); } +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add for oDiscard */ +void odiscard_wake_up_thread(void) +{ + struct f2fs_sb_info *sbi = NULL; + struct list_head *p; + + spin_lock(&sb_list_lock); + p = all_f2fs_sbi.next; + while (p != &all_f2fs_sbi) { + sbi = list_entry(p, struct f2fs_sb_info, sbi_list); + p = p->next; + if (sbi->last_wp_odc_jiffies && + time_before(jiffies, sbi->last_wp_odc_jiffies + odc_wakeup_interval)) { + continue; + } + + if (!f2fs_device.battery_charging && sbi->odiscard_already_run) + continue; + wake_up_odiscard_of2fs(sbi); + } + spin_unlock(&sb_list_lock); +} + +void odiscard_update_state(void) +{ + struct f2fs_sb_info *sbi = NULL; + struct list_head *p; + + spin_lock(&sb_list_lock); + p = all_f2fs_sbi.next; + while (p != &all_f2fs_sbi) { + sbi = list_entry(p, struct f2fs_sb_info, sbi_list); + p = p->next; + sbi->odiscard_already_run = false; + } + spin_unlock(&sb_list_lock); +} + +static int f2fs_plane_notify_callback(struct notifier_block *nb, unsigned long val, void *data) +{ + struct drm_panel_notifier *evdata = data; + int *blank; + + if (val != DRM_PANEL_EARLY_EVENT_BLANK) + return 0; + + if (evdata && evdata->data) { + blank = evdata->data; + if (*blank == DRM_PANEL_BLANK_POWERDOWN_CUST) { //suspend + pr_info("%s: f2fs notifier get screen off event!\n", __func__); + f2fs_device.screen_off = true; + if (f2fs_device.battery_charging || f2fs_device.battery_percent >= BATTERY_THRESHOLD) + odiscard_wake_up_thread(); + } else if (*blank == DRM_PANEL_BLANK_UNBLANK_CUST) { //resume + pr_info("%s: f2fs notifier get screen on event!\n", __func__); + f2fs_device.screen_off = false; + odiscard_update_state(); + } + } + return NOTIFY_OK; +} +static struct notifier_block f2fs_plane_notify_block = { + .notifier_call = f2fs_plane_notify_callback, +}; + +static int f2fs_battery_notify_callback(struct notifier_block *nb, + unsigned long ev, void *v) +{ + int err = 0; + union power_supply_propval status = {0, }; + struct power_supply *psy = v; + + if (strcmp(psy->desc->name, "battery")) + return NOTIFY_OK; + + if (ev != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + err = power_supply_get_property(psy, + POWER_SUPPLY_PROP_STATUS, &status); + if (err) { + f2fs_device.battery_charging = false; + f2fs_device.battery_percent = 0; + return NOTIFY_DONE; + } + if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { + f2fs_device.battery_charging = true; + odiscard_wake_up_thread(); + } else { + f2fs_device.battery_charging = false; + + err = power_supply_get_property(psy, + POWER_SUPPLY_PROP_CAPACITY, &status); + if (!err) + f2fs_device.battery_percent = status.intval; + else + f2fs_device.battery_percent = 0; + } + + return NOTIFY_DONE; +} + + +static struct notifier_block f2fs_battery_notify_block = { + .notifier_call = f2fs_battery_notify_callback, +}; +#endif + #ifdef CONFIG_QUOTA static const char * const quotatypes[] = INITQFNAMES; #define QTYPE2NAME(t) (quotatypes[t]) @@ -1148,6 +1306,13 @@ static void f2fs_put_super(struct super_block *sb) int i; bool dropped; +#ifdef CONFIG_F2FS_OF2FS + /*[ASTI-147]: add for oDiscard */ + spin_lock(&sb_list_lock); + list_del(&sbi->sbi_list); + spin_unlock(&sb_list_lock); +#endif + f2fs_quota_off_umount(sb); /* prevent remaining shrinker jobs */ @@ -1564,9 +1729,12 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) seq_printf(seq, ",alloc_mode=%s", "reuse"); - if (test_opt(sbi, DISABLE_CHECKPOINT)) + if (test_opt(sbi, DISABLE_CHECKPOINT)) { + f2fs_info(sbi, "Debug:%s:test_opt checkpoint disable", __func__); seq_printf(seq, ",checkpoint=disable:%u", F2FS_OPTION(sbi).unusable_cap); + } + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX) seq_printf(seq, ",fsync_mode=%s", "posix"); else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) @@ -1605,7 +1773,10 @@ static void default_options(struct f2fs_sb_info *sbi) clear_opt(sbi, DISABLE_CHECKPOINT); F2FS_OPTION(sbi).unusable_cap = 0; sbi->sb->s_flags |= SB_LAZYTIME; +#ifndef CONFIG_F2FS_OF2FS + /* [ASTI-147]: no need to flush_merge as we have reduced most flushes. */ set_opt(sbi, FLUSH_MERGE); +#endif set_opt(sbi, DISCARD); if (f2fs_sb_has_blkzoned(sbi)) set_opt_mode(sbi, F2FS_MOUNT_LFS); @@ -1642,6 +1813,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi) f2fs_update_time(sbi, DISABLE_TIME); + f2fs_info(sbi, "Debug:%s: into\n", __func__); while (!f2fs_time_over(sbi, DISABLE_TIME)) { down_write(&sbi->gc_lock); err = f2fs_gc(sbi, true, false, NULL_SEGNO); @@ -1826,7 +1998,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) } if (checkpoint_changed) { + f2fs_info(sbi, "Debug:%s:checkpoint_changed\n", __func__); if (test_opt(sbi, DISABLE_CHECKPOINT)) { + f2fs_info(sbi, "Debug:%s:into f2fs_disable_checkpoint", __func__); err = f2fs_disable_checkpoint(sbi); if (err) goto restore_gc; @@ -2643,6 +2817,11 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi, } else { err = __f2fs_commit_super(bh, NULL); res = err ? "failed" : "done"; +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_META_SB, 1); + bd_unlock(sbi); +#endif } f2fs_info(sbi, "Fix alignment : %s, start(%u) end(%u) block(%u)", res, main_blkaddr, @@ -2995,8 +3174,13 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->dir_level = DEF_DIR_LEVEL; sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; sbi->interval_time[REQ_TIME] = DEF_IDLE_INTERVAL; +#ifdef CONFIG_F2FS_OF2FS + sbi->interval_time[DISCARD_TIME] = DEF_DISCARD_IDLE_INTERVAL; + sbi->interval_time[GC_TIME] = DEF_GC_IDLE_INTERVAL; +#else sbi->interval_time[DISCARD_TIME] = DEF_IDLE_INTERVAL; sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; +#endif sbi->interval_time[DISABLE_TIME] = DEF_DISABLE_INTERVAL; sbi->interval_time[UMOUNT_DISCARD_TIMEOUT] = DEF_UMOUNT_DISCARD_TIMEOUT; @@ -3189,6 +3373,11 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_META_SB, 1); + bd_unlock(sbi); +#endif brelse(bh); /* if we are in recovery path, skip writing valid superblock */ @@ -3200,6 +3389,11 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); +#ifdef CONFIG_F2FS_BD_STAT + bd_lock(sbi); + bd_inc_array_val(sbi, hotcold_count, HC_META_SB, 1); + bd_unlock(sbi); +#endif brelse(bh); return err; } @@ -3373,6 +3567,16 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (!sbi) return -ENOMEM; +#ifdef CONFIG_F2FS_BD_STAT + sbi->bd_info = kzalloc(sizeof(struct f2fs_bigdata_info), GFP_KERNEL); + if (!sbi->bd_info) { + err = -ENOMEM; + goto free_sbi; + } + sbi->bd_info->ssr_last_jiffies = jiffies; + bd_lock_init(sbi); +#endif + sbi->sb = sb; /* Load the checksum driver */ @@ -3663,8 +3867,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (err) goto free_meta; - if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG))) + if (unlikely(is_set_ckpt_flags(sbi, CP_DISABLED_FLAG))) { + f2fs_info(sbi, "Debug:%s:is_set_ckpt_flags goto reset_checkpoint\n", __func__); goto reset_checkpoint; + } /* recover fsynced data */ if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { @@ -3685,8 +3891,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) if (need_fsck) set_sbi_flag(sbi, SBI_NEED_FSCK); - if (skip_recovery) + if (skip_recovery) { + f2fs_info(sbi, "Debug:%s:skip_recovery", __func__); goto reset_checkpoint; + } err = f2fs_recover_fsync_data(sbi, false); if (err < 0) { @@ -3706,11 +3914,13 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) goto free_meta; } } + f2fs_info(sbi, "Debug:%s:Normal flow into reset_checkpoint\n", __func__); reset_checkpoint: /* f2fs_recover_fsync_data() cleared this already */ clear_sbi_flag(sbi, SBI_POR_DOING); if (test_opt(sbi, DISABLE_CHECKPOINT)) { + f2fs_info(sbi, "Debug:%s: Run option DISABLE_CHECKPOINT\n", __func__); err = f2fs_disable_checkpoint(sbi); if (err) goto sync_free_meta; @@ -3746,6 +3956,14 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) f2fs_update_time(sbi, CP_TIME); f2fs_update_time(sbi, REQ_TIME); clear_sbi_flag(sbi, SBI_CP_DISABLED_QUICK); +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + spin_lock(&sb_list_lock); + list_add_tail(&sbi->sbi_list, &all_f2fs_sbi); + spin_unlock(&sb_list_lock); + sbi->last_wp_odc_jiffies = 0; + sbi->odiscard_already_run = false; +#endif return 0; sync_free_meta: @@ -3885,6 +4103,10 @@ static void destroy_inodecache(void) static int __init init_f2fs_fs(void) { int err; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + struct timespec ts = {ODISCARD_WAKEUP_INTERVAL, 0}; +#endif if (PAGE_SIZE != F2FS_BLKSIZE) { printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n", @@ -3928,6 +4150,20 @@ static int __init init_f2fs_fs(void) err = f2fs_init_bioset(); if (err) goto free_bio_enrty_cache; +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + spin_lock_init(&sb_list_lock); + + odc_wakeup_interval = timespec_to_jiffies(&ts); + memset(&f2fs_device, 0, sizeof(struct f2fs_device_state)); + + err = f2fs_panel_notifier_register(&f2fs_plane_notify_block); + if (err) + pr_err("%s error: register f2fs notifier failed,drm!\n", __func__); + err = f2fs_battery_notifier_register(&f2fs_battery_notify_block); + if (err) + pr_err("%s error: register battery notifier failed!\n", __func__); +#endif return 0; free_bio_enrty_cache: f2fs_destroy_bio_entry_cache(); @@ -3956,6 +4192,18 @@ static int __init init_f2fs_fs(void) static void __exit exit_f2fs_fs(void) { +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add for oDiscard */ + int err = 0; + + err = f2fs_panel_notifier_unregister(&f2fs_plane_notify_block); + if (err) + pr_err("%s error: unregister f2fs plane notifier failed!\n", __func__); + err = f2fs_battery_notifier_unregister(&f2fs_battery_notify_block); + if (err) + pr_err("%s error: unregister f2fs battery notifier failed!\n", __func__); +#endif + f2fs_destroy_bioset(); f2fs_destroy_bio_entry_cache(); f2fs_destroy_post_read_processing(); diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index a97b37c16af4af29a247aa413c1c88a2b27d6473..a5d1679e5ad00bfcc5ccc07a7a4ea5757059b6ef 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -803,6 +803,149 @@ static int __maybe_unused victim_bits_seq_show(struct seq_file *seq, return 0; } +#ifdef CONFIG_F2FS_OF2FS +/* [ASTI-147]: add f2fs frag_score and undiscard_score */ +extern block_t of2fs_seg_freefrag(struct f2fs_sb_info *sbi, unsigned int segno, block_t *blocks, unsigned int n); +static int __maybe_unused frag_score_seq_show(struct seq_file *seq, void *offset) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + unsigned int i, total_segs = + le32_to_cpu(sbi->raw_super->segment_count_main); + block_t blocks[9], total_blocks = 0; + unsigned int score; + + memset(blocks, 0, sizeof(blocks)); + for (i = 0; i < total_segs; i++) { + total_blocks += of2fs_seg_freefrag(sbi, i, + blocks, ARRAY_SIZE(blocks)); + cond_resched(); + } + + f2fs_printk(sbi, KERN_INFO "Extent Size Range: Free Blocks"); + for (i = 0; i < ARRAY_SIZE(blocks); i++) { + if (!blocks[i]) + continue; + else if (i < 8) + f2fs_printk(sbi, KERN_INFO + "%dK...%dK-: %u", 4<private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + unsigned int undiscard_blks = 0; + unsigned int free_blks = sbi->user_block_count - valid_user_blocks(sbi); + unsigned int score; + + if (SM_I(sbi) && SM_I(sbi)->dcc_info) + undiscard_blks = SM_I(sbi)->dcc_info->undiscard_blks; + score = free_blks ? undiscard_blks * 100ULL / free_blks : 0; + seq_printf(seq, "%u\n", score < 100 ? score : 100); + return 0; +} + +static int gc_opt_enable_seq_show(struct seq_file *seq, void *p) +{ + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + seq_printf(seq, "%d\n", sbi->gc_opt_enable); + return 0; +} + +static ssize_t gc_opt_enable_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[64] = { 0 }; + int user_set_value = 0; + int ret = -1; + struct seq_file *seq = filp->private_data; + struct super_block *sb = seq->private; + struct f2fs_sb_info *sbi = F2FS_SB(sb); + + if (cnt > sizeof(buf) - 1) + cnt = sizeof(buf) - 1; + + if (copy_from_user(&buf[0], ubuf, cnt)) + return -EFAULT; + ret = kstrtoint(strstrip(&buf[0]), 0, &user_set_value); + if (ret < 0) + return ret; + + sbi->gc_opt_enable = !!user_set_value; + if (sbi->gc_opt_enable) + sbi->interval_time[GC_TIME] = DEF_GC_IDLE_INTERVAL; + else + sbi->interval_time[GC_TIME] = DEF_IDLE_INTERVAL; + return cnt; +} + +static int gc_opt_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, gc_opt_enable_seq_show, PDE_DATA(inode)); +} + +static const struct file_operations f2fs_seq_gc_opt_enable_fops = { + .open = gc_opt_enable_open, + .read = seq_read, + .write = gc_opt_enable_write, + .llseek = seq_lseek, + .release = single_release, +}; + +/* [ASTI-147]: add for oDiscard */ +static int f2fs_odiscard_enable_seq_show(struct seq_file *seq, void *p) +{ + seq_printf(seq, "%d\n", f2fs_odiscard_enable); + return 0; +} + +static ssize_t f2fs_odiscard_enable_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) +{ + char buf[64] = { 0 }; + int user_set_value = 0; + int ret = -1; + + if (cnt > sizeof(buf) - 1) + cnt = sizeof(buf) - 1; + + if (copy_from_user(&buf[0], ubuf, cnt)) + return -EFAULT; + + ret = kstrtoint(strstrip(&buf[0]), 0, &user_set_value); + + if (ret < 0) + return ret; + + f2fs_odiscard_enable = user_set_value; + return cnt; +} +static int f2fs_odiscard_enable_open(struct inode *inode, struct file *file) +{ + return single_open(file, f2fs_odiscard_enable_seq_show, NULL); +} + +static const struct file_operations f2fs_odiscard_enable_fops = { + .open = f2fs_odiscard_enable_open, + .read = seq_read, + .write = f2fs_odiscard_enable_write, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + int __init f2fs_init_sysfs(void) { int ret; @@ -851,6 +994,18 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root); if (sbi->s_proc) { +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add f2fs frag_score and undiscard_score */ + /* [ASTI-147]: add for oDiscard */ + proc_create_single_data("frag_score", 0444, sbi->s_proc, + frag_score_seq_show, sb); + proc_create_single_data("udc_score", 0444, sbi->s_proc, + undiscard_score_seq_show, sb); + proc_create_data("gc_enable", 0644, sbi->s_proc, + &f2fs_seq_gc_opt_enable_fops, sb); + proc_create_data("dc_enable", 0644, sbi->s_proc, + &f2fs_odiscard_enable_fops, sb); +#endif proc_create_single_data("segment_info", S_IRUGO, sbi->s_proc, segment_info_seq_show, sb); proc_create_single_data("segment_bits", S_IRUGO, sbi->s_proc, @@ -860,16 +1015,30 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi) proc_create_single_data("victim_bits", S_IRUGO, sbi->s_proc, victim_bits_seq_show, sb); } +#ifdef CONFIG_F2FS_BD_STAT + f2fs_build_bd_stat(sbi); +#endif return 0; } void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi) { if (sbi->s_proc) { +#ifdef CONFIG_F2FS_BD_STAT + f2fs_destroy_bd_stat(sbi); +#endif remove_proc_entry("iostat_info", sbi->s_proc); remove_proc_entry("segment_info", sbi->s_proc); remove_proc_entry("segment_bits", sbi->s_proc); remove_proc_entry("victim_bits", sbi->s_proc); +#ifdef CONFIG_F2FS_OF2FS + /* [ASTI-147]: add f2fs frag_score and undiscard_score */ + /* [ASTI-147]: add for oDiscard */ + remove_proc_entry("gc_enable", sbi->s_proc); + remove_proc_entry("udc_score", sbi->s_proc); + remove_proc_entry("frag_score", sbi->s_proc); + remove_proc_entry("dc_enable", sbi->s_proc); +#endif remove_proc_entry(sbi->sb->s_id, f2fs_proc_root); } kobject_del(&sbi->s_kobj); diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 60da84a86dabdb2e00d2725481631db385985054..0d4c2c4a6bfaa2bd1473af41344ade60eabe97c8 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_FUSE_FS) += fuse.o obj-$(CONFIG_CUSE) += cuse.o -fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o +fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o shortcircuit.o diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 24a6bc8b9bd8798770cc42eba822a350b19126d8..ddc0801f53a31964e53b94dbd3eacb29115664cc 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -7,6 +7,7 @@ */ #include "fuse_i.h" +#include "fuse_shortcircuit.h" #include #include @@ -37,6 +38,60 @@ static struct fuse_dev *fuse_get_dev(struct file *file) return READ_ONCE(file->private_data); } +#ifdef CONFIG_ONEPLUS_FG_OPT +#include +extern unsigned int ht_fuse_boost; + +static int fuse_debug; +module_param_named(fuse_debug, fuse_debug, int, 0664); + +static inline bool fuse_can_boost(void) +{ + int uid = current_uid().val; + + if (!ht_fuse_boost) + return false; + + // fuse_boost enabled and is foreground request + if (ht_fuse_boost >= 1 && is_fg(uid)) + return true; + + // fuse_boost enabled and is system request (include foreground request) + if (ht_fuse_boost == 2 && uid < 10000) + return true; + + return false; +} + +static inline void fuse_boost_init(struct fuse_req *req) +{ + clear_bit(FR_BOOST, &req->flags); + + if (fuse_can_boost()) + __set_bit(FR_BOOST, &req->flags); + + if (fuse_debug) { + int uid = current_uid().val; + + pr_info("current %s %d, fg: %d, uid: %d\n", + current->comm, current->pid, current_is_fg(), uid); + } +} + +static inline void fuse_boost_active_check(struct fuse_req *req) +{ + // boost active check + // 1. sysctl: sched_fuse_boost (on) + // 2. target: mediaprovider's specific tasks + // TODO: add system busy check to not impact ux experience + if (ht_fuse_boost) + current->fuse_boost = test_bit(FR_BOOST, &req->flags) ? 1 : 0; +} +#else +static inline void fuse_boost_init(struct fuse_req *req) {} +static inline void fuse_boost_active_check(struct fuse_req *req) {} +#endif + static void fuse_request_init(struct fuse_req *req, struct page **pages, struct fuse_page_desc *page_descs, unsigned npages) @@ -52,6 +107,8 @@ static void fuse_request_init(struct fuse_req *req, struct page **pages, req->page_descs = page_descs; req->max_pages = npages; __set_bit(FR_PENDING, &req->flags); + + fuse_boost_init(req); } static struct fuse_req *__fuse_request_alloc(unsigned npages, gfp_t flags) @@ -102,6 +159,10 @@ void fuse_request_free(struct fuse_req *req) kfree(req->pages); kfree(req->page_descs); } + if (req->iname) { + __putname(req->iname); + req->iname = NULL; + } kmem_cache_free(fuse_req_cachep, req); } @@ -572,10 +633,16 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args) args->in.numargs * sizeof(struct fuse_in_arg)); req->out.argvar = args->out.argvar; req->out.numargs = args->out.numargs; + req->iname = args->iname; + args->iname = NULL; memcpy(req->out.args, args->out.args, args->out.numargs * sizeof(struct fuse_arg)); fuse_request_send(fc, req); ret = req->out.h.error; + if (!ret) { + if (req->private_lower_rw_file != NULL) + args->private_lower_rw_file = req->private_lower_rw_file; + } if (!ret && args->out.argvar) { BUG_ON(args->out.numargs != 1); ret = req->out.args[0].size; @@ -1287,6 +1354,9 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, req = list_entry(fiq->pending.next, struct fuse_req, list); clear_bit(FR_PENDING, &req->flags); + + fuse_boost_active_check(req); + list_del_init(&req->list); spin_unlock(&fiq->lock); @@ -1329,6 +1399,24 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, __fuse_get_request(req); set_bit(FR_SENT, &req->flags); spin_unlock(&fpq->lock); + + if (sct_mode == 1) { + if (current->fpack) { + if (current->fpack->iname) + __putname(current->fpack->iname); + memset(current->fpack, 0, sizeof(struct fuse_package)); + } + if (req->in.h.opcode == FUSE_OPEN || req->in.h.opcode == FUSE_CREATE) { + if (!current->fpack) + current->fpack = kzalloc(sizeof(struct fuse_package), GFP_KERNEL); + if (likely(current->fpack)) { + current->fpack->fuse_open_req = true; + current->fpack->iname = req->iname; + req->iname = NULL; + } + } + } + /* matches barrier in request_wait_answer() */ smp_mb__after_atomic(); if (test_bit(FR_INTERRUPTED, &req->flags)) @@ -1859,6 +1947,11 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, struct fuse_req *req; struct fuse_out_header oh; + if (current->fpack && current->fpack->iname) { + __putname(current->fpack->iname); + current->fpack->iname = NULL; + } + if (nbytes < sizeof(struct fuse_out_header)) return -EINVAL; @@ -1892,6 +1985,8 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, if (!req) goto err_unlock_pq; + fuse_boost_active_check(req); + /* Is it an interrupt reply? */ if (req->intr_unique == oh.unique) { __fuse_get_request(req); @@ -1931,6 +2026,8 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, } fuse_copy_finish(cs); + fuse_setup_shortcircuit(fc, req); + spin_lock(&fpq->lock); clear_bit(FR_LOCKED, &req->flags); if (!fpq->connected) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 2c4ceb75482e06220805a594b34bafb36f4c3414..17ff063f68efd00b868319cb510236be81a924bf 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -464,6 +464,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, struct fuse_open_out outopen; struct fuse_entry_out outentry; struct fuse_file *ff; + char *iname; /* Userspace expects S_IFREG in create mode */ BUG_ON((mode & S_IFMT) != S_IFREG); @@ -482,6 +483,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, mode &= ~current_umask(); flags &= ~O_NOCTTY; + if (fc->writeback_cache) + flags &= ~O_APPEND; memset(&inarg, 0, sizeof(inarg)); memset(&outentry, 0, sizeof(outentry)); inarg.flags = flags; @@ -499,7 +502,22 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, args.out.args[0].value = &outentry; args.out.args[1].size = sizeof(outopen); args.out.args[1].value = &outopen; + args.private_lower_rw_file = NULL; + iname = inode_name(dir); + if (iname) { + /* compose full path */ + if ((strlen(iname) + entry->d_name.len + 2) <= PATH_MAX) { + strlcat(iname, "/", PATH_MAX); + strlcat(iname, entry->d_name.name, PATH_MAX); + } else { + __putname(iname); + iname = NULL; + } + } + args.iname = iname; err = fuse_simple_request(fc, &args); + if (args.iname) + __putname(args.iname); if (err) goto out_free_ff; @@ -511,6 +529,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, ff->fh = outopen.fh; ff->nodeid = outentry.nodeid; ff->open_flags = outopen.open_flags; + if (args.private_lower_rw_file != NULL) + ff->rw_lower_file = args.private_lower_rw_file; inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, &outentry.attr, entry_attr_timeout(&outentry), 0); if (!inode) { diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 3964325432aea3ce321c39cba3f3d1e1cc1a4b43..d0aa8c043805ea66ca58c2407b9d4b91d2f0150b 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -7,6 +7,7 @@ */ #include "fuse_i.h" +#include "fuse_shortcircuit.h" #include #include @@ -22,10 +23,13 @@ static const struct file_operations fuse_direct_io_file_operations; static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, - int opcode, struct fuse_open_out *outargp) + int opcode, struct fuse_open_out *outargp, + struct file **lower_file) { + ssize_t ret; struct fuse_open_in inarg; FUSE_ARGS(args); + char *iname = NULL; memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); @@ -40,7 +44,16 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, args.out.args[0].size = sizeof(*outargp); args.out.args[0].value = outargp; - return fuse_simple_request(fc, &args); + if (opcode == FUSE_OPEN) + iname = inode_name(file_inode(file)); + args.iname = iname; + + ret = fuse_simple_request(fc, &args); + if (args.iname) + __putname(args.iname); + if (args.private_lower_rw_file != NULL) + *lower_file = args.private_lower_rw_file; + return ret; } struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) @@ -51,6 +64,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) if (unlikely(!ff)) return NULL; + ff->rw_lower_file = NULL; ff->fc = fc; ff->reserved_req = fuse_request_alloc(0); if (unlikely(!ff->reserved_req)) { @@ -131,7 +145,8 @@ int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, struct fuse_open_out outarg; int err; - err = fuse_send_open(fc, nodeid, file, opcode, &outarg); + err = fuse_send_open(fc, nodeid, file, opcode, &outarg, + &(ff->rw_lower_file)); if (!err) { ff->fh = outarg.fh; ff->open_flags = outarg.open_flags; @@ -257,6 +272,7 @@ void fuse_release_common(struct file *file, bool isdir) struct fuse_req *req = ff->reserved_req; int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; + fuse_shortcircuit_release(ff); fuse_prepare_release(ff, file->f_flags, opcode); if (ff->flock) { @@ -924,8 +940,10 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { + ssize_t ret_val; struct inode *inode = iocb->ki_filp->f_mapping->host; struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_file *ff = iocb->ki_filp->private_data; /* * In auto invalidate mode, always update attributes on read. @@ -940,7 +958,12 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to) return err; } - return generic_file_read_iter(iocb, to); + if (ff && ff->rw_lower_file) + ret_val = fuse_shortcircuit_read_iter(iocb, to); + else + ret_val = generic_file_read_iter(iocb, to); + + return ret_val; } static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff, @@ -1178,12 +1201,22 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct address_space *mapping = file->f_mapping; + struct fuse_file *ff = file->private_data; ssize_t written = 0; ssize_t written_buffered = 0; struct inode *inode = mapping->host; ssize_t err; loff_t endbyte = 0; + if (ff && ff->rw_lower_file) { + /* Update size (EOF optimization) and mode (SUID clearing) */ + err = fuse_update_attributes(mapping->host, file); + if (err) + return err; + + return fuse_shortcircuit_write_iter(iocb, from); + } + if (get_fuse_conn(inode)->writeback_cache) { /* Update size (EOF optimization) and mode (SUID clearing) */ err = fuse_update_attributes(mapping->host, file); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3d53a17b1f64aed6ff7f3f53e97c3cd578b2f342..27ec4f29754d99d39fa97a8e66dba6e260132412 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -156,6 +156,9 @@ struct fuse_file { /** Has flock been performed on this file? */ bool flock:1; + + /* the read write file */ + struct file *rw_lower_file; }; /** One input argument of a request */ @@ -236,6 +239,10 @@ struct fuse_args { unsigned numargs; struct fuse_arg args[2]; } out; + + /** fuse shortcircuit file */ + struct file *private_lower_rw_file; + char *iname; }; #define FUSE_ARGS(args) struct fuse_args args = {} @@ -278,6 +285,8 @@ struct fuse_io_priv { * FR_SENT: request is in userspace, waiting for an answer * FR_FINISHED: request is finished * FR_PRIVATE: request is on private list + * + * FR_BOOST: request can be boost */ enum fuse_req_flag { FR_ISREPLY, @@ -291,6 +300,10 @@ enum fuse_req_flag { FR_SENT, FR_FINISHED, FR_PRIVATE, + +#ifdef CONFIG_ONEPLUS_FG_OPT + FR_BOOST = 30, +#endif }; /** @@ -385,6 +398,10 @@ struct fuse_req { /** Request is stolen from fuse_file->reserved_req */ struct file *stolen_file; + + /** fuse shortcircuit file */ + struct file *private_lower_rw_file; + char *iname; }; struct fuse_iqueue { @@ -557,6 +574,9 @@ struct fuse_conn { /** handle fs handles killing suid/sgid/cap on write/chown/trunc */ unsigned handle_killpriv:1; + /** Shortcircuited IO. */ + unsigned shortcircuit_io:1; + /* * The following bitfields are only for optimization purposes * and hence races in setting them will not cause malfunction @@ -999,5 +1019,6 @@ extern const struct xattr_handler *fuse_no_acl_xattr_handlers[]; struct posix_acl; struct posix_acl *fuse_get_acl(struct inode *inode, int type); int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type); +extern int sct_mode; #endif /* _FS_FUSE_I_H */ diff --git a/fs/fuse/fuse_shortcircuit.h b/fs/fuse/fuse_shortcircuit.h new file mode 100644 index 0000000000000000000000000000000000000000..b326ef9d798f1739d7fb16051d3b73f0fb4c1490 --- /dev/null +++ b/fs/fuse/fuse_shortcircuit.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + * + */ + +#ifndef _FS_FUSE_SHORCIRCUIT_H +#define _FS_FUSE_SHORCIRCUIT_H + +#include "fuse_i.h" + +#include +#include + +void fuse_setup_shortcircuit(struct fuse_conn *fc, struct fuse_req *req); + +ssize_t fuse_shortcircuit_read_iter(struct kiocb *iocb, struct iov_iter *to); + +ssize_t fuse_shortcircuit_write_iter(struct kiocb *iocb, struct iov_iter *from); + +void fuse_shortcircuit_release(struct fuse_file *ff); + +#endif /* _FS_FUSE_SHORCIRCUIT_H */ diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cb018315ecaf54e7b9c6b02e33228a7e683fd5d0..420343ad9991be5556634e7f1bed192c449c6bf4 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -49,6 +49,10 @@ MODULE_PARM_DESC(max_user_congthresh, "Global limit for the maximum congestion threshold an " "unprivileged user can set"); +static bool shortcircuit = true; +module_param(shortcircuit, bool, 0644); +MODULE_PARM_DESC(shortcircuit, "Enable or disable fuse shortcircuit. Default: y/Y/1"); + #define FUSE_SUPER_MAGIC 0x65735546 #define FUSE_DEFAULT_BLKSIZE 512 @@ -914,6 +918,13 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) fc->async_dio = 1; if (arg->flags & FUSE_WRITEBACK_CACHE) fc->writeback_cache = 1; + if (arg->flags & FUSE_SHORTCIRCUIT || fc->writeback_cache) { + /** an ugly way to determine FuseDaemon by writeback_cache + * since currently only FuseDaemon enable WBC + */ + fc->shortcircuit_io = shortcircuit ? 1 : 0; + pr_info("fuse sct flag: %d\n", shortcircuit); + } if (arg->flags & FUSE_PARALLEL_DIROPS) fc->parallel_dirops = 1; if (arg->flags & FUSE_HANDLE_KILLPRIV) @@ -958,7 +969,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) FUSE_DO_READDIRPLUS | FUSE_READDIRPLUS_AUTO | FUSE_ASYNC_DIO | FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | - FUSE_ABORT_ERROR; + FUSE_ABORT_ERROR | FUSE_SHORTCIRCUIT; req->in.h.opcode = FUSE_INIT; req->in.numargs = 1; req->in.args[0].size = sizeof(*arg); diff --git a/fs/fuse/shortcircuit.c b/fs/fuse/shortcircuit.c new file mode 100644 index 0000000000000000000000000000000000000000..adde8702a30bda46e2dafb07b16bc78c0537cca5 --- /dev/null +++ b/fs/fuse/shortcircuit.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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 "fuse_shortcircuit.h" + +#include +#include + +#include + +int __read_mostly sct_mode = 2; +module_param(sct_mode, int, 0644); + +static char *__dentry_name(struct dentry *dentry, char *name) +{ + char *p = dentry_path_raw(dentry, name, PATH_MAX); + + if (IS_ERR(p)) { + __putname(name); + return NULL; + } + + /* + * This function relies on the fact that dentry_path_raw() will place + * the path name at the end of the provided buffer. + */ + BUG_ON(p + strlen(p) + 1 != name + PATH_MAX); + + if (p > name) + strlcpy(name, p, PATH_MAX); + + return name; +} + +static char *dentry_name(struct dentry *dentry) +{ + char *name = __getname(); + + if (!name) + return NULL; + + return __dentry_name(dentry, name); +} + +char *inode_name(struct inode *ino) +{ + struct dentry *dentry; + char *name; + + if (sct_mode != 1) + return NULL; + + dentry = d_find_alias(ino); + if (!dentry) + return NULL; + + name = dentry_name(dentry); + + dput(dentry); + + return name; +} + +void fuse_setup_shortcircuit(struct fuse_conn *fc, struct fuse_req *req) +{ + int fd, flags, open_out_index; + struct file *rw_lower_file = NULL; + struct fuse_open_out *open_out; + struct fuse_package *fp = current->fpack; + + req->private_lower_rw_file = NULL; + + if (!sct_mode) + return; + + if (!(fc->shortcircuit_io)) + return; + + if ((req->in.h.opcode != FUSE_OPEN) && + (req->in.h.opcode != FUSE_CREATE)) + return; + + open_out_index = req->in.numargs - 1; + + if ((open_out_index != 0 && open_out_index != 1) || + (req->out.args[open_out_index].size != sizeof(*open_out))) + return; + + open_out = req->out.args[open_out_index].value; + if (!open_out->fh) + return; + + flags = open_out->open_flags; + if ((flags & FOPEN_DIRECT_IO) || !(flags & FOPEN_KEEP_CACHE)) { + pr_info("fuse bypass sct #flags:%d\n", flags); + return; + } + + if (sct_mode == 1) { + if (fp) { + req->private_lower_rw_file = fp->filp; + fp->filp = NULL; + } + return; + } + if (fp && fp->filp) { + fput(fp->filp); + fp->filp = NULL; + } + + if (get_user(fd, (int __user *)open_out->fh)) + return; + + if (fd <= 1 || fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_max) { + pr_info("fuse bypass sct:%d, %d\n", fd, flags); + return; + } + + rw_lower_file = fget_raw(fd); + if (!rw_lower_file) + return; + + req->private_lower_rw_file = rw_lower_file; + pr_debug("fuse setup sct:%d, %d\n", fd, flags); +} + +static ssize_t fuse_shortcircuit_read_write_iter(struct kiocb *iocb, + struct iov_iter *iter, + int do_write) +{ + struct file *fuse_filp = iocb->ki_filp; + struct fuse_file *ff = fuse_filp->private_data; + struct file *lower_file = ff->rw_lower_file; + struct inode *fuse_inode, *shortcircuit_inode; + ssize_t ret = -EIO; + + fuse_inode = fuse_filp->f_path.dentry->d_inode; + shortcircuit_inode = file_inode(lower_file); + + iocb->ki_filp = lower_file; + + if (do_write) { + if (!lower_file->f_op->write_iter) + goto out; + + ret = call_write_iter(lower_file, iocb, iter); + if (ret >= 0 || ret == -EIOCBQUEUED) { + fsstack_copy_inode_size(fuse_inode, shortcircuit_inode); + fsstack_copy_attr_times(fuse_inode, shortcircuit_inode); + } + } else { + if (!lower_file->f_op->read_iter) + goto out; + + ret = call_read_iter(lower_file, iocb, iter); + if (ret >= 0 || ret == -EIOCBQUEUED) + fsstack_copy_attr_atime(fuse_inode, shortcircuit_inode); + } + +out: + iocb->ki_filp = fuse_filp; + + return ret; +} + +ssize_t fuse_shortcircuit_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + return fuse_shortcircuit_read_write_iter(iocb, to, 0); +} + +ssize_t fuse_shortcircuit_write_iter(struct kiocb *iocb, struct iov_iter *from) +{ + return fuse_shortcircuit_read_write_iter(iocb, from, 1); +} + +void fuse_shortcircuit_release(struct fuse_file *ff) +{ + if (!(ff->rw_lower_file)) + return; + + /* Release the lower file. */ + fput(ff->rw_lower_file); + ff->rw_lower_file = NULL; +} diff --git a/fs/inode.c b/fs/inode.c index 9e46350dd2a679d279db11d5844cb69c3ad9dcf2..9b0a596e84d9d22f09be0f1a45b11bb65a2035f9 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -752,7 +752,9 @@ static enum lru_status inode_lru_isolate(struct list_head *item, spin_unlock(lru_lock); if (remove_inode_buffers(inode)) { unsigned long reap; - reap = invalidate_mapping_pages(&inode->i_data, 0, -1); + /* bin.zhong@ASTI, 2019/10/11, for CONFIG_SMART_BOOST */ + reap = smb_invalidate_mapping_pages(&inode->i_data, + 0, -1); if (current_is_kswapd()) __count_vm_events(KSWAPD_INODESTEAL, reap); else diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 4200a6fe9599c72695df7d0ff4c0e17ce79bc696..063c53b0508ec2c4558e36b2765bdf4c44600fae 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -26,6 +26,10 @@ #include #include +#if defined(CONFIG_UFSTW) +#include +#endif + /* * IO end handler for temporary buffer_heads handling writes to the journal. */ @@ -530,6 +534,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) write_unlock(&journal->j_state_lock); jbd_debug(3, "JBD2: commit phase 2a\n"); +#if defined(CONFIG_UFSTW) + bdev_set_turbo_write(journal->j_dev); +#endif /* * Now start flushing things to disk, in the order they appear @@ -1129,6 +1136,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) write_unlock(&journal->j_state_lock); wake_up(&journal->j_wait_done_commit); +#if defined(CONFIG_UFSTW) + bdev_clear_turbo_write(journal->j_dev); +#endif /* * Calculate overall stats */ diff --git a/fs/namei.c b/fs/namei.c index 8492dc67fc3cddd33a1f5a2deaa686ede21d3c72..4be81e0ba7f0991bb00efb55ba6457c038a313b6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -39,6 +39,9 @@ #include #include #include +#ifdef CONFIG_FSC +#include +#endif #include #include "internal.h" @@ -2433,12 +2436,26 @@ static int filename_lookup(int dfd, struct filename *name, unsigned flags, { int retval; struct nameidata nd; +#ifdef CONFIG_FSC + unsigned int hidx = 0; + size_t len = 0; + bool is_fsc_path_candidate = false; +#endif if (IS_ERR(name)) return PTR_ERR(name); if (unlikely(root)) { nd.root = *root; flags |= LOOKUP_ROOT; } +#ifdef CONFIG_FSC + is_fsc_path_candidate = (fsc_enable && fsc_allow_list_cur && + fsc_path_check(name, &len)); + if (is_fsc_path_candidate && fsc_absence_check(name->name, len)) { + putname(name); + return -ENOENT; + } +#endif + set_nameidata(&nd, dfd, name); retval = path_lookupat(&nd, flags | LOOKUP_RCU, path); if (unlikely(retval == -ECHILD)) @@ -2446,6 +2463,18 @@ static int filename_lookup(int dfd, struct filename *name, unsigned flags, if (unlikely(retval == -ESTALE)) retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path); +#ifdef CONFIG_FSC + if (is_fsc_path_candidate) { + hidx = fsc_get_hidx(name->name, len); + fsc_spin_lock(hidx); + if (retval == -ENOENT) + fsc_insert_absence_path_locked(name->name, len, hidx); + else + fsc_delete_absence_path_locked(name->name, len, hidx); + fsc_spin_unlock(hidx); + } +#endif + if (likely(!retval)) audit_inode(name, path->dentry, flags & LOOKUP_PARENT); restore_nameidata(); @@ -3801,6 +3830,10 @@ EXPORT_SYMBOL(kern_path_create); void done_path_create(struct path *path, struct dentry *dentry) { +#ifdef CONFIG_FSC + if (fsc_enable && fsc_allow_list_cur) + fsc_delete_absence_path_dentry(path, dentry); +#endif dput(dentry); inode_unlock(path->dentry->d_inode); mnt_drop_write(path->mnt); @@ -4792,6 +4825,12 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd, error = vfs_rename2(old_path.mnt, old_path.dentry->d_inode, old_dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode, flags); + +#ifdef CONFIG_FSC + if (fsc_enable && fsc_allow_list_cur && !error) + fsc_delete_absence_path_dentry(&new_path, new_dentry); +#endif + exit5: dput(new_dentry); exit4: diff --git a/fs/open.c b/fs/open.c index b14aef04ee013c237bd023e8865f8bb495d1434e..6038a57c1ea9a956a6fe5a14ea9c18ae1fdc6064 100644 --- a/fs/open.c +++ b/fs/open.c @@ -32,6 +32,10 @@ #include #include +#ifdef CONFIG_FSC +#include +#endif + #include "internal.h" int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length, @@ -1099,8 +1103,34 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) put_unused_fd(fd); fd = PTR_ERR(f); } else { +#ifdef CONFIG_FSC + path_get(&f->f_path); +#endif fsnotify_open(f); fd_install(fd, f); +#ifdef CONFIG_FSC + if (fsc_enable && fsc_allow_list_cur && tmp->name) { + size_t len = strlen(tmp->name); + + if ((flags & O_CREAT || flags & O_TMPFILE) && + len < FSC_PATH_MAX) { + const char *path = NULL; + char buf[FSC_PATH_MAX] = {0}; + unsigned int hidx; + /* check before use */ + path = file_path(f, buf, FSC_PATH_MAX); /* null-terminator */ + if (!IS_ERR(path)) { + len = strlen(path); + hidx = fsc_get_hidx(path, len); + fsc_spin_lock(hidx); + fsc_delete_absence_path_locked(path, len, hidx); + fsc_spin_unlock(hidx); + pr_debug("%s %s open succeed with create or tmpfile\n", __func__, path); + } + } + } + path_put(&f->f_path); +#endif } } putname(tmp); diff --git a/fs/proc/base.c b/fs/proc/base.c index d4cd5235cbdab37f9084e3e1c2f2dd0beab4b500..90542ce2d5f28a7ab74b6e081601d67a8ed3dd55 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -99,7 +99,11 @@ #include "internal.h" #include "fd.h" +#include + #include "../../lib/kstrtox.h" +#include +#include /* NOTE: * Implementing inode permission operations in /proc is almost @@ -912,6 +916,162 @@ static const struct file_operations proc_mem_operations = { .release = mem_release, }; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ +static int proc_stuck_trace_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + u64 d_time, s_time, ltt_time, mid_time, big_time, rn_time, iow_time, binder_time, futex_time; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + task_lock(p); + iow_time = p->oneplus_stuck_info.d_state.iowait_ns; + binder_time = p->oneplus_stuck_info.s_state.binder_ns; + futex_time = p->oneplus_stuck_info.s_state.futex_ns; + + d_time = p->oneplus_stuck_info.d_state.iowait_ns + p->oneplus_stuck_info.d_state.mutex_ns + + p->oneplus_stuck_info.d_state.downread_ns + p->oneplus_stuck_info.d_state.downwrite_ns + + p->oneplus_stuck_info.d_state.other_ns; + s_time = p->oneplus_stuck_info.s_state.binder_ns + p->oneplus_stuck_info.s_state.futex_ns + + p->oneplus_stuck_info.s_state.epoll_ns + p->oneplus_stuck_info.s_state.other_ns; + + ltt_time = p->oneplus_stuck_info.ltt_running_state; + + mid_time = p->oneplus_stuck_info.mid_running_state; + + big_time = p->oneplus_stuck_info.big_running_state; + + rn_time = p->oneplus_stuck_info.runnable_state; + + task_unlock(p); + + seq_printf(m, "BR:%llu MR:%llu LR:%llu RN:%llu D:%llu IOW:%llu S:%llu BD:%llu FT:%llu\n", + big_time / NSEC_PER_MSEC, mid_time / NSEC_PER_MSEC, ltt_time / NSEC_PER_MSEC, + rn_time / NSEC_PER_MSEC, d_time / NSEC_PER_MSEC, iow_time / NSEC_PER_MSEC, + s_time / NSEC_PER_MSEC, binder_time / NSEC_PER_MSEC, futex_time / NSEC_PER_MSEC); + put_task_struct(p); + return 0; +} + +static int proc_stuck_trace_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, proc_stuck_trace_show, inode); +} + +static ssize_t proc_stuck_trace_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int err, stuck_trace; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + + err = kstrtoint(strstrip(buffer), 0, &stuck_trace); + if (err) + return err; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + if (stuck_trace == 1) { + task->stuck_trace = 1; + } else if (stuck_trace == 0) { + task->stuck_trace = 0; + memset(&task->oneplus_stuck_info, 0, sizeof(struct oneplus_uifirst_monitor_info)); + } + + put_task_struct(task); + return count; +} + +static const struct file_operations proc_stuck_trace_operations = { + .open = proc_stuck_trace_open, + .write = proc_stuck_trace_write, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + +#ifdef CONFIG_UXCHAIN +static int proc_static_ux_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + seq_printf(m, "%d\n", p->static_ux); + put_task_struct(p); + return 0; +} + +static int proc_static_ux_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, proc_static_ux_show, inode); +} + +static ssize_t proc_static_ux_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int err, static_ux; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + err = kstrtoint(strstrip(buffer), 0, &static_ux); + if (err) + return err; + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + task->static_ux = static_ux != 0 ? 1 : 0; + + put_task_struct(task); + return count; +} + +static ssize_t proc_static_ux_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[PROC_NUMBUF]; + struct task_struct *task = NULL; + int static_ux = -1; + size_t len = 0; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + static_ux = task->static_ux; + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", static_ux); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static const struct file_operations proc_static_ux_operations = { + .open = proc_static_ux_open, + .write = proc_static_ux_write, + .read = proc_static_ux_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + static int environ_open(struct inode *inode, struct file *file) { return __mem_open(inode, file, PTRACE_MODE_READ); @@ -3341,6 +3501,33 @@ static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, return err; } +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +static int proc_tli_info_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + u64 window_index = sample_window.window_index; + u64 timestamp = sample_window.timestamp; + + seq_puts(m, "sample window ----------------\n"); + seq_printf(m, "window_index:%llu,timestamp:%llu\n", window_index, timestamp); + seq_puts(m, "task_tfi_slot 0 ----------------\n"); + seq_printf(m, "read_bytes:%llu\n", task->tli[0].read_bytes); + seq_printf(m, "write_bytes:%llu\n", task->tli[0].write_bytes); + seq_printf(m, "exec_time_fg:%llu\n", task->tli[0].runtime[1]); + seq_printf(m, "exec_time_bg:%llu\n", task->tli[0].runtime[0]); + seq_printf(m, "sample_index:%llu\n", task->tli[0].task_sample_index); + seq_printf(m, "overlod_flag:%016llx\n", task->tli[0].tli_overload_flag); + seq_puts(m, "task_tfi_slot 1 ----------------\n"); + seq_printf(m, "read_bytes:%llu\n", task->tli[1].read_bytes); + seq_printf(m, "write_bytes:%llu\n", task->tli[1].write_bytes); + seq_printf(m, "exec_time_fg:%llu\n", task->tli[1].runtime[1]); + seq_printf(m, "exec_time_bg:%llu\n", task->tli[1].runtime[0]); + seq_printf(m, "sample_index:%llu\n", task->tli[1].task_sample_index); + seq_printf(m, "overlod_flag:%016llx\n", task->tli[1].tli_overload_flag); + return 0; +} +#endif /* CONFIG_ONEPLUS_TASKLOAD_INFO */ + #ifdef CONFIG_LIVEPATCH static int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) @@ -3350,6 +3537,374 @@ static int proc_pid_patch_state(struct seq_file *m, struct pid_namespace *ns, } #endif /* CONFIG_LIVEPATCH */ +#ifdef CONFIG_IM +#define IM_TAG_DESC_LEN (128) +static int proc_im_flag_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + char desc[IM_TAG_DESC_LEN] = {0}; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + + im_to_str(p->im_flag, desc, IM_TAG_DESC_LEN); + desc[IM_TAG_DESC_LEN - 1] = '\0'; + seq_printf(m, "%d %s\n", p->im_flag, desc); + + put_task_struct(p); + return 0; +} + +static int proc_im_flag_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, proc_im_flag_show, inode); +} + +static ssize_t proc_im_flag_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int err, imfg; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + err = kstrtoint(strstrip(buffer), 0, &imfg); + if (err) + return err; + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + task->im_flag = imfg; + + put_task_struct(task); + return count; +} + +static ssize_t proc_im_flag_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[PROC_NUMBUF]; + struct task_struct *task = NULL; + int imfg = 0; + size_t len = 0; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + imfg = task->im_flag; + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", imfg); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static const struct file_operations proc_imfg_operations = { + .open = proc_im_flag_open, + .write = proc_im_flag_write, + .read = proc_im_flag_read, + .llseek = seq_lseek, + .release = single_release, +}; +static ssize_t +tbctl_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + char buffer[64]; + int err = 0; + unsigned int tb_pol = 0; + unsigned int tb_type = 0; + unsigned int args[6] = {0}; + unsigned int v[4] = {0}; + int c; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) { + err = -EFAULT; + goto out; + } + + c = sscanf(buffer, "%u,%u,%u,%u,%u,%u,%u,%u\n", + &tb_pol, &tb_type, + &args[0], &args[1], &args[2], &args[3], &args[4], &args[5]); + + if (c != 6 && c != 8) { + pr_err("tb params invalid. %s. IGNORED.\n", buffer); + err = -EFAULT; + goto out; + } + + if (tb_pol == TB_POL_HWUI_BOOST) + tb_parse_req_v2(tb_pol, tb_type, args, 6); + else { + memcpy(v, args, sizeof(unsigned int) * 4); + tb_parse_req(tb_pol, tb_type, v); + } + +out: + return (err < 0) ? err : count; +} + +static int tbctl_show(struct seq_file *m, void *v) +{ + return 0; +} + +static int tbctl_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, tbctl_show, inode); +} +static const struct file_operations proc_tbctl_operation = { + .open = tbctl_open, + .read = seq_read, + .write = tbctl_write, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_IM */ + +#ifdef CONFIG_TPD +static ssize_t +tpd_write(struct file *file, const char __user *buf, + size_t count, loff_t *offset) +{ + struct task_struct *task; + char buffer[PROC_NUMBUF]; + int err, tpdecision; + + memset(buffer, 0, sizeof(buffer)); + if (count > sizeof(buffer) - 1) + count = sizeof(buffer) - 1; + if (copy_from_user(buffer, buf, count)) + return -EFAULT; + + err = kstrtoint(strstrip(buffer), 0, &tpdecision); + if (err) + return err; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + task->tpd = (tpdecision != 0) ? tpdecision : 0; + + put_task_struct(task); + + return count; +} + +static int tpd_show(struct seq_file *m, void *v) +{ + struct inode *inode = m->private; + struct task_struct *p; + + p = get_proc_task(inode); + if (!p) + return -ESRCH; + seq_printf(m, "%d\n", p->tpd); + put_task_struct(p); + return 0; +} + +static int tpd_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, tpd_show, inode); +} + +static ssize_t tpd_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char buffer[PROC_NUMBUF]; + struct task_struct *task = NULL; + int tpdecision; + size_t len = 0; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + tpdecision = task->tpd; + put_task_struct(task); + len = snprintf(buffer, sizeof(buffer), "%d\n", tpdecision); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} +static const struct file_operations proc_tpd_operation = { + .open = tpd_open, + .read = tpd_read, + .write = tpd_write, + .llseek = seq_lseek, + .release = single_release, +}; +#endif /* CONFIG_TPD */ + +#ifdef CONFIG_VM_FRAGMENT_MONITOR +static ssize_t vm_fragment_max_gap_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct task_struct *task; + struct mm_struct *mm; + struct vm_area_struct *vma; + char buffer[PROC_NUMBUF]; + size_t len; + int vm_fragment_gap_max = 0; + int gl_fragment_gap_max = 0; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + mm = get_task_mm(task); + if (!mm) { + put_task_struct(task); + return -ENOMEM; + } + + if (RB_EMPTY_ROOT(&mm->mm_rb)) { + mmput(mm); + put_task_struct(task); + return -ENOMEM; + } + + vma = rb_entry(mm->mm_rb.rb_node, struct vm_area_struct, vm_rb); + vm_fragment_gap_max = (int)(vma->rb_subtree_gap >> 20); + gl_fragment_gap_max = (int)(vma->rb_glfragment_gap >> 20); + + mmput(mm); + put_task_struct(task); + + len = snprintf(buffer, sizeof(buffer), "%d %d\n", vm_fragment_gap_max, gl_fragment_gap_max); + return simple_read_from_buffer(buf, count, ppos, buffer, len); +} + +static const struct file_operations proc_vm_fragment_monitor_operations = { + .read = vm_fragment_max_gap_read, +}; +#endif + +#include +static int va_feature; +module_param(va_feature, int, 0644); + +unsigned long dbg_pm[8] = { 0 }; +static int dbg_buf_store(const char *buf, const struct kernel_param *kp) +{ + /* function for debug-only*/ + if (sscanf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu\n" + , &dbg_pm[0], &dbg_pm[1], &dbg_pm[2], &dbg_pm[3] + , &dbg_pm[4], &dbg_pm[5], &dbg_pm[6], &dbg_pm[7]) <= 7) + return -EINVAL; + va_feature = 0x7; + return 0; +} + +static struct kernel_param_ops module_param_ops = { + .set = dbg_buf_store, + .get = param_get_int, +}; +module_param_cb(dbg_buf, &module_param_ops, &va_feature, 0644); + +static ssize_t proc_va_feature_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + struct mm_struct *mm; + char buffer[32]; + int ret; + + if (!test_thread_flag(TIF_32BIT)) + return -EINVAL; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + ret = -EINVAL; + mm = get_task_mm(task); + if (mm) { + if (mm->va_feature & 0x4) { + ret = snprintf(buffer, sizeof(buffer), "%d\n", + (mm->zygoteheap_in_MB > 256) ? mm->zygoteheap_in_MB : 256); + if (ret > 0) + ret = simple_read_from_buffer(buf, count, ppos, + buffer, ret); + } + mmput(mm); + } + + put_task_struct(task); + + return ret; +} + +static ssize_t proc_va_feature_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct task_struct *task; + struct mm_struct *mm; + int ret; + unsigned int heapsize; + + if (!test_thread_flag(TIF_32BIT)) + return -ENOTTY; + + task = get_proc_task(file_inode(file)); + if (!task) + return -ESRCH; + + ret = kstrtouint_from_user(buf, count, 0, &heapsize); + if (ret) { + put_task_struct(task); + return ret; + } + + mm = get_task_mm(task); + if (mm) { + mm->va_feature = va_feature; + + /* useless to print comm, always "main" */ + if (mm->va_feature & 0x1) { + mm->va_feature_rnd = (dbg_pm[6] + (get_random_long() % 0x1e00000)) & ~(0xffff); + special_arch_pick_mmap_layout(mm); + } + + if ((mm->va_feature & 0x4) && (mm->zygoteheap_in_MB == 0)) + mm->zygoteheap_in_MB = heapsize; + + mmput(mm); + } + + put_task_struct(task); + + return count; +} + +static const struct file_operations proc_va_feature_operations = { + .read = proc_va_feature_read, + .write = proc_va_feature_write, +}; + +static int proc_cpu_dist(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + int i; + + for (i = 0; i < 8; ++i) { + long long cnt = atomic_read(&task->cpu_dist[i]); + long long tcnt = atomic_read(&task->total_cpu_dist[i]) + cnt; + + seq_printf(m, "cpu%d: %lld %lld\n", i, cnt, tcnt); + atomic64_set(&task->cpu_dist[i], 0); + atomic64_set(&task->total_cpu_dist[i], tcnt); + } + return 0; +} + /* * Thread groups */ @@ -3471,6 +4026,31 @@ static const struct pid_entry tgid_base_stuff[] = { #ifdef CONFIG_CPU_FREQ_TIMES ONE("time_in_state", 0444, proc_time_in_state_show), #endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-19, add for stuck monitor*/ + REG("stuck_info", 0666, proc_stuck_trace_operations), +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ +#ifdef CONFIG_IM + REG("im_flag", 0666, proc_imfg_operations), + REG("tb_ctl", 0666, proc_tbctl_operation), +#endif +#ifdef CONFIG_TPD + REG("tpd", 0666, proc_tpd_operation), +#endif + ONE("cpu_dist", 0666, proc_cpu_dist), +#ifdef CONFIG_SMART_BOOST + REG("page_hot_count", 0666, proc_page_hot_count_operations), +#endif +#ifdef CONFIG_UXCHAIN + REG("static_ux", 0666, proc_static_ux_operations), +#endif +#ifdef CONFIG_VM_FRAGMENT_MONITOR + REG("vm_fragment_gap_max", 0666, proc_vm_fragment_monitor_operations), +#endif + REG("va_feature", 0666, proc_va_feature_operations), +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + ONE("tli_info", 0444, proc_tli_info_show), +#endif }; static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) @@ -3865,6 +4445,20 @@ static const struct pid_entry tid_base_stuff[] = { #ifdef CONFIG_CPU_FREQ_TIMES ONE("time_in_state", 0444, proc_time_in_state_show), #endif +#ifdef CONFIG_UXCHAIN + REG("static_ux", 0666, proc_static_ux_operations), +#endif +#ifdef CONFIG_IM + REG("im_flag", 0666, proc_imfg_operations), + REG("tb_ctl", 0666, proc_tbctl_operation), +#endif +#ifdef CONFIG_TPD + REG("tpd", 0666, proc_tpd_operation), +#endif + ONE("cpu_dist", 0666, proc_cpu_dist), +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + ONE("tli_info", 0444, proc_tli_info_show), +#endif }; static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index f2dab6c2edb3b1b2abae48533e13a85f7411bf12..7225e68053bf18259117a28fb091757244d47398 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -20,6 +20,11 @@ #include #include #include "internal.h" +/* bin.zhong@ASTI add CONFIG_DEFRAG */ +#include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) { @@ -147,6 +152,17 @@ static int meminfo_proc_show(struct seq_file *m, void *v) show_val_kb(m, "CmaFree: ", global_zone_page_state(NR_FREE_CMA_PAGES)); #endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#ifdef CONFIG_ION + show_val_kb(m, "IonTotalCache: ", + global_zone_page_state(NR_IONCACHE_PAGES)); + show_val_kb(m, "IonTotalUsed: ", ion_total() >> PAGE_SHIFT); +#endif +#endif + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + show_defrag_free(m); + show_real_freemem(m, i.freeram); + hugetlb_report_meminfo(m); diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 535eda7857cfd5d16545edd40ce0c3cae0fb8f10..549b8a6d872dee2d80f67aeac270d79d61c96435 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c @@ -13,6 +13,10 @@ #include #include #include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#include +#endif #ifndef arch_irq_stat_cpu #define arch_irq_stat_cpu(cpu) 0 @@ -197,6 +201,89 @@ static const struct file_operations proc_stat_operations = { .release = single_release, }; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +// Add for get cpu load +struct cpu_load_stat { + u64 t_user; + u64 t_system; + u64 t_idle; + u64 t_iowait; + u64 t_irq; + u64 t_softirq; +}; + +int ohm_get_cur_cpuload(bool ctrl) +{ + int i; + int ret = 0; + struct cpu_load_stat cpu_load = { 0, 0, 0, 0, 0, 0 }; + struct cpu_load_stat cpu_load_temp = { 0, 0, 0, 0, 0, 0 }; + clock_t ct_user; + clock_t ct_system; + clock_t ct_idle; + clock_t ct_iowait; + clock_t ct_irq; + clock_t ct_softirq; + clock_t load; + clock_t sum = 0; + + if (!ctrl) { + ret = -1; + return ret; + } + + for_each_online_cpu(i) { + cpu_load_temp.t_user += + kcpustat_cpu(i).cpustat[CPUTIME_USER]; + cpu_load_temp.t_system += + kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]; + cpu_load_temp.t_idle += get_idle_time(i); + cpu_load_temp.t_iowait += get_iowait_time(i); + cpu_load_temp.t_irq += + kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; + cpu_load_temp.t_softirq += + kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]; + } + msleep(25); + for_each_online_cpu(i) { + cpu_load.t_user += kcpustat_cpu(i).cpustat[CPUTIME_USER]; + cpu_load.t_system += + kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]; + cpu_load.t_idle += get_idle_time(i); + cpu_load.t_iowait += get_iowait_time(i); + cpu_load.t_irq += kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; + cpu_load.t_softirq += + kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]; + } + + ct_user = nsec_to_clock_t(cpu_load.t_user) - + nsec_to_clock_t(cpu_load_temp.t_user); + ct_system = nsec_to_clock_t(cpu_load.t_system) - + nsec_to_clock_t(cpu_load_temp.t_system); + ct_idle = nsec_to_clock_t(cpu_load.t_idle) - + nsec_to_clock_t(cpu_load_temp.t_idle); + ct_iowait = nsec_to_clock_t(cpu_load.t_iowait) - + nsec_to_clock_t(cpu_load_temp.t_iowait); + ct_irq = nsec_to_clock_t(cpu_load.t_irq) - + nsec_to_clock_t(cpu_load_temp.t_irq); + ct_softirq = nsec_to_clock_t(cpu_load.t_softirq) - + nsec_to_clock_t(cpu_load_temp.t_softirq); + + sum = ct_user + ct_system + ct_idle + ct_iowait + + ct_irq + ct_softirq; + load = ct_user + ct_system + ct_iowait + ct_irq + ct_softirq; + + if (sum == 0) { + ret = -1; + return ret; + } + + ret = 100 * load / sum; + return ret; +} + +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + static int __init proc_stat_init(void) { proc_create("stat", 0, NULL, &proc_stat_operations); diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 6f90d91a8733ad68aa94d71b4caba623cdee0409..6e9c83ccbed99c0a13bed551b496ce4bee383111 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -369,6 +369,12 @@ int pstore_mkfile(struct dentry *root, struct pstore_record *record) scnprintf(name, sizeof(name), "powerpc-opal-%s-%llu", record->psi->name, record->id); break; + + case PSTORE_TYPE_DEVICE_INFO: + scnprintf(name, sizeof(name), "device-info-%s-%lld", + record->psi->name, record->id); + break; + case PSTORE_TYPE_UNKNOWN: scnprintf(name, sizeof(name), "unknown-%s-%llu", record->psi->name, record->id); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 4bae3f4fe829dbb64810be3ccb148eb4d8b40dcb..8fd4362c7d3fd6bd0145eae788a6a5c633d45e5d 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -489,6 +489,34 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c) psinfo->write(&record); } +static void pstore_console_init(void) +{ + size_t oldsize; + size_t size = 0; + struct ramoops_context *cxt = psinfo->data; + struct pstore_record record; + + if (psinfo == NULL) + return; + + size = cxt->console_size; + + pstore_record_init(&record, psinfo); + record.type = PSTORE_TYPE_CONSOLE; + record.buf = psinfo->buf; + record.size = size; + + oldsize = psinfo->bufsize; + + if (size > psinfo->bufsize) + size = psinfo->bufsize; + memset(record.buf, ' ', size); + + psinfo->write(&record); + + psinfo->bufsize = oldsize; +} + static struct console pstore_console = { .name = "pstore", .write = pstore_console_write, @@ -498,6 +526,8 @@ static struct console pstore_console = { static void pstore_register_console(void) { + /*pstore memset before use*/ + pstore_console_init(); register_console(&pstore_console); } diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index bafbab2dd039245e4d02a9fd574201bb590e0d07..b9844436ed0d8f471841e3d408ea993448d1ca89 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c @@ -35,6 +35,7 @@ #include #include #include +#include #define RAMOOPS_KERNMSG_HDR "====" #define MIN_MEM_SIZE 4096UL @@ -52,6 +53,10 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE; module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); +static ulong ramoops_device_info_size = MIN_MEM_SIZE; +module_param_named(device_info_size, ramoops_device_info_size, ulong, 0400); +MODULE_PARM_DESC(device_info_size, "size of device info"); + static ulong ramoops_pmsg_size = MIN_MEM_SIZE; module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400); MODULE_PARM_DESC(pmsg_size, "size of user space message log"); @@ -83,32 +88,6 @@ MODULE_PARM_DESC(ramoops_ecc, "ECC buffer size in bytes (1 is a special value, means 16 " "bytes ECC)"); -struct ramoops_context { - struct persistent_ram_zone **dprzs; /* Oops dump zones */ - struct persistent_ram_zone *cprz; /* Console zone */ - struct persistent_ram_zone **fprzs; /* Ftrace zones */ - struct persistent_ram_zone *mprz; /* PMSG zone */ - phys_addr_t phys_addr; - unsigned long size; - unsigned int memtype; - size_t record_size; - size_t console_size; - size_t ftrace_size; - size_t pmsg_size; - int dump_oops; - u32 flags; - struct persistent_ram_ecc_info ecc_info; - unsigned int max_dump_cnt; - unsigned int dump_write_cnt; - /* _read_cnt need clear on ramoops_pstore_open */ - unsigned int dump_read_cnt; - unsigned int console_read_cnt; - unsigned int max_ftrace_cnt; - unsigned int ftrace_read_cnt; - unsigned int pmsg_read_cnt; - struct pstore_info pstore; -}; - static struct platform_device *dummy; static struct ramoops_platform_data *dummy_data; @@ -120,6 +99,7 @@ static int ramoops_pstore_open(struct pstore_info *psi) cxt->console_read_cnt = 0; cxt->ftrace_read_cnt = 0; cxt->pmsg_read_cnt = 0; + cxt->device_info_read_cnt = 0; return 0; } @@ -284,6 +264,12 @@ static ssize_t ramoops_pstore_read(struct pstore_record *record) 1, &record->id, &record->type, PSTORE_TYPE_PMSG, 0); + if (!prz_ok(prz)) + prz = ramoops_get_next_prz(&cxt->dprz, + &cxt->device_info_read_cnt, + 1, &record->id, &record->type, + PSTORE_TYPE_DEVICE_INFO, 0); + /* ftrace is last since it may want to dynamically allocate memory. */ if (!prz_ok(prz)) { if (!(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)) { @@ -406,6 +392,11 @@ static int notrace ramoops_pstore_write(struct pstore_record *record) } else if (record->type == PSTORE_TYPE_PMSG) { pr_warn_ratelimited("PMSG shouldn't call %s\n", __func__); return -EINVAL; + } else if (record->type == PSTORE_TYPE_DEVICE_INFO) { + if (!cxt->dprz) + return -ENOMEM; + persistent_ram_write(cxt->dprz, record->buf, record->size); + return 0; } if (record->type != PSTORE_TYPE_DMESG) @@ -496,6 +487,11 @@ static int ramoops_pstore_erase(struct pstore_record *record) case PSTORE_TYPE_PMSG: prz = cxt->mprz; break; + + case PSTORE_TYPE_DEVICE_INFO: + prz = cxt->dprz; + break; + default: return -EINVAL; } @@ -714,6 +710,7 @@ static int ramoops_parse_dt(struct platform_device *pdev, parse_size("console-size", pdata->console_size); parse_size("ftrace-size", pdata->ftrace_size); parse_size("pmsg-size", pdata->pmsg_size); + parse_size("devinfo-size", pdata->device_info_size); parse_size("ecc-size", pdata->ecc_info.ecc_size); parse_size("flags", pdata->flags); @@ -728,6 +725,7 @@ static int ramoops_probe(struct platform_device *pdev) struct ramoops_platform_data *pdata = dev->platform_data; struct ramoops_platform_data pdata_local; struct ramoops_context *cxt = &oops_cxt; + struct md_region md_entry; size_t dump_mem_sz; phys_addr_t paddr; int err = -EINVAL; @@ -757,7 +755,8 @@ static int ramoops_probe(struct platform_device *pdev) } if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && - !pdata->ftrace_size && !pdata->pmsg_size)) { + !pdata->ftrace_size && !pdata->pmsg_size + && !pdata->device_info_size)) { pr_err("The memory size and the record/console size must be " "non-zero\n"); goto fail_out; @@ -772,6 +771,10 @@ static int ramoops_probe(struct platform_device *pdev) if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size)) pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size); + if (pdata->device_info_size && !is_power_of_2(pdata->device_info_size)) + pdata->device_info_size = + rounddown_pow_of_two(pdata->device_info_size); + cxt->size = pdata->mem_size; cxt->phys_addr = pdata->mem_address; cxt->memtype = pdata->mem_type; @@ -782,11 +785,12 @@ static int ramoops_probe(struct platform_device *pdev) cxt->dump_oops = pdata->dump_oops; cxt->flags = pdata->flags; cxt->ecc_info = pdata->ecc_info; + cxt->device_info_size = pdata->device_info_size; paddr = cxt->phys_addr; dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size - - cxt->pmsg_size; + - cxt->pmsg_size - cxt->device_info_size; err = ramoops_init_przs("dump", dev, cxt, &cxt->dprzs, &paddr, dump_mem_sz, cxt->record_size, &cxt->max_dump_cnt, 0, 0); @@ -814,6 +818,11 @@ static int ramoops_probe(struct platform_device *pdev) if (err) goto fail_init_mprz; + err = ramoops_init_prz("devinfo", dev, cxt, &cxt->dprz, &paddr, + cxt->device_info_size, 0); + if (err) + goto fail_init_dprz; + cxt->pstore.data = cxt; /* * Prepare frontend flags based on which areas are initialized. @@ -863,6 +872,21 @@ static int ramoops_probe(struct platform_device *pdev) ramoops_console_size = pdata->console_size; ramoops_pmsg_size = pdata->pmsg_size; ramoops_ftrace_size = pdata->ftrace_size; + ramoops_device_info_size = pdata->device_info_size; + + /* Add pmsg info to minidump table */ + strlcpy(md_entry.name, "PMSG", sizeof(md_entry.name)); + md_entry.virt_addr = (u64)cxt->mprz->vaddr; + md_entry.phys_addr = (u64)cxt->mprz->paddr; + md_entry.size = cxt->mprz->size; + if (msm_minidump_add_region(&md_entry)) + pr_info("Failed to add PMSG data in Minidump\n"); + + pr_err("cprz=0X%llX cs=0X%lX mprz=0x%llX ps=0X%lX dprz=0X%llX dfs=0X%lX ft=0X%lX\n", + cxt->cprz->paddr, cxt->console_size, + cxt->mprz->paddr, cxt->pmsg_size, + cxt->dprz->paddr, cxt->device_info_size, + cxt->ftrace_size); pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n", cxt->size, (unsigned long long)cxt->phys_addr, @@ -874,6 +898,8 @@ static int ramoops_probe(struct platform_device *pdev) kfree(cxt->pstore.buf); fail_clear: cxt->pstore.bufsize = 0; + persistent_ram_free(cxt->dprz); +fail_init_dprz: persistent_ram_free(cxt->mprz); fail_init_mprz: fail_init_fprz: @@ -895,6 +921,7 @@ static int ramoops_remove(struct platform_device *pdev) persistent_ram_free(cxt->mprz); persistent_ram_free(cxt->cprz); + persistent_ram_free(cxt->dprz); ramoops_free_przs(cxt); return 0; @@ -947,6 +974,7 @@ static void __init ramoops_register_dummy(void) dummy_data->record_size = record_size; dummy_data->console_size = ramoops_console_size; dummy_data->ftrace_size = ramoops_ftrace_size; + dummy_data->device_info_size = ramoops_device_info_size; dummy_data->pmsg_size = ramoops_pmsg_size; dummy_data->dump_oops = dump_oops; dummy_data->flags = RAMOOPS_FLAG_FTRACE_PER_CPU; diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 271c4c4cb760f829af12cd810943e9580e4a2177..53197fa7e350ca7be6a9a04577a5e2d96ded4f3c 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -236,6 +236,8 @@ static int sdcardfs_open(struct inode *inode, struct file *file) struct dentry *parent = dget_parent(dentry); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; + struct fuse_package *fp = current->fpack; + char *iname; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { @@ -255,6 +257,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) goto out_err; } + file->f_mode |= FMODE_NONMAPPABLE; file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { @@ -275,6 +278,15 @@ static int sdcardfs_open(struct inode *inode, struct file *file) } } else { sdcardfs_set_lower_file(file, lower_file); + if (!err && fp && fp->fuse_open_req && !fp->filp && fp->iname) { + iname = inode_name(inode); + if (iname && !strcasecmp(iname, fp->iname)) { + fp->filp = file; + get_file(file); + } + if (iname) + __putname(iname); + } } if (err) @@ -350,6 +362,11 @@ static int sdcardfs_fasync(int fd, struct file *file, int flag) return err; } +static struct file *sdcardfs_get_lower_file(struct file *f) +{ + return sdcardfs_lower_file(f); +} + /* * Sdcardfs cannot use generic_file_llseek as ->llseek, because it would * only set the offset of the upper file. So we have to implement our @@ -446,6 +463,7 @@ const struct file_operations sdcardfs_main_fops = { .release = sdcardfs_file_release, .fsync = sdcardfs_fsync, .fasync = sdcardfs_fasync, + .get_lower_file = sdcardfs_get_lower_file, .read_iter = sdcardfs_read_iter, .write_iter = sdcardfs_write_iter, }; @@ -463,5 +481,6 @@ const struct file_operations sdcardfs_dir_fops = { .release = sdcardfs_file_release, .flush = sdcardfs_flush, .fsync = sdcardfs_fsync, + .get_lower_file = sdcardfs_get_lower_file, .fasync = sdcardfs_fasync, }; diff --git a/fs/sync.c b/fs/sync.c index 055daab8652a58cafd652fb91c9e98db0d3a9bac..3c3b04f9616dd07c213dfb75756cdb3b11c5cd0e 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -17,6 +17,9 @@ #include #include #include "internal.h" +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ SYNC_FILE_RANGE_WAIT_AFTER) @@ -212,16 +215,30 @@ int vfs_fsync(struct file *file, int datasync) } EXPORT_SYMBOL(vfs_fsync); +/*2020-04-30 [OSP-5970]*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +extern void ohm_schedstats_record(int sched_type, struct task_struct *task, u64 delta_ms); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + static int do_fsync(unsigned int fd, int datasync) { struct fd f = fdget(fd); int ret = -EBADF; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + unsigned long oneplus_fsync_time = jiffies; +#endif + if (f.file) { ret = vfs_fsync(f.file, datasync); fdput(f); inc_syscfs(current); } +/*2020-06-20 [OSP-5970]**/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + ohm_schedstats_record(OHM_SCHED_FSYNC, current, + jiffies_to_msecs(jiffies - oneplus_fsync_time)); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ return ret; } diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 328f232f33eef1cb5bd4c8c68c5f1fe9f8aa5bc9..f9ccc5d927b1db8ade2911eca5b11134d0c17e60 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -115,6 +115,8 @@ struct mipi_dsi_host { int mipi_dsi_host_register(struct mipi_dsi_host *host); void mipi_dsi_host_unregister(struct mipi_dsi_host *host); struct mipi_dsi_host *of_find_mipi_dsi_host_by_node(struct device_node *node); +int mipi_dsi_dcs_set_display_brightness_samsung(struct mipi_dsi_device *dsi, + u16 brightness); /* DSI mode flags */ diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index efe246ce52bf847916777f6f4c7030e4b93baf45..8240d08f5c0e90c31a83ea27de52fd506f9ae6c8 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -43,6 +43,18 @@ enum { DRM_PANEL_BLANK_LP, /* fps change */ DRM_PANEL_BLANK_FPS_CHANGE, + DRM_PANEL_BLANK_UNBLANK_CUST, + /* panel:lcd doze mode */ + DRM_PANEL_BLANK_NORMAL, + /* panel power off */ + DRM_PANEL_BLANK_POWERDOWN_CUST, + DRM_PANEL_ONSCREENFINGERPRINT_EVENT, + DRM_PANEL_BLANK_UNBLANK_CHARGE, + DRM_PANEL_BLANK_POWERDOWN_CHARGE, + /*panel 60HZ */ + DRM_PANEL_DYNAMICFPS_60 = 60, + /*panel 90HZ */ + DRM_PANEL_DYNAMICFPS_90 = 90, }; struct drm_panel_notifier { diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c43316d3f5be62a446ff82bc307c0ac3f552b338..c61e30183a4215c22a6daa66614377f49d47ba09 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -156,6 +156,13 @@ struct request { unsigned int cmd_flags; /* op and common flags */ req_flags_t rq_flags; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/* Add some info in each request */ + ktime_t block_io_start; //save block io start ktime + ktime_t ufs_io_start; //save ufs io start ktime + u64 flash_io_latency; //save mmc host command latency +#endif + int internal_tag; /* the following two fields are internal, NEVER access directly */ @@ -676,6 +683,10 @@ struct request_queue { #define BLK_MAX_WRITE_HINTS 5 u64 write_hints[BLK_MAX_WRITE_HINTS]; + +#ifdef CONFIG_UFSTW + bool turbo_write_dev; +#endif }; #define QUEUE_FLAG_QUEUED 0 /* uses generic tag queueing */ diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index b76413263e44f86e0b03a989fd22121efab5dc1d..bcee266914780eca4511df727aba9387b74cc3c3 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -72,6 +72,18 @@ struct css_task_iter { extern struct cgroup_root cgrp_dfl_root; extern struct css_set init_css_set; +#ifdef CONFIG_RATP + +#define STUNE_FG 1 +#define STUNE_BG 2 +#define STUNE_TOP 3 +#define STUNE_RT 4 +#define STUNE_AUDIOAPP 5 + +extern int stune_map[]; + +#endif + #define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; #include #undef SUBSYS diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 8996c092568bc233a2aa7df33717f8c9690b95b6..eadc548334b7828dbbd3c184f2f48f60e6c5490d 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -29,6 +29,10 @@ SUBSYS(schedtune) SUBSYS(io) #endif +#if IS_ENABLED(CONFIG_CGROUP_IOLIMIT) +SUBSYS(iolimit) +#endif + #if IS_ENABLED(CONFIG_MEMCG) SUBSYS(memory) #endif diff --git a/include/linux/clk.h b/include/linux/clk.h index 751506abe271d313d6af73c4af3134dc884e0ebe..8e91f179abd35da78f07c7d2ac643c8c5a0546fa 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -788,6 +788,10 @@ static inline void clk_bulk_disable_unprepare(int num_clks, clk_bulk_unprepare(num_clks, clks); } +#ifdef CONFIG_HOUSTON +extern void clk_get_ddr_freq(u64 *val); +#endif + #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) struct clk *of_clk_get(struct device_node *np, int index); struct clk *of_clk_get_by_name(struct device_node *np, const char *name); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 12cec9cd4dc0e759153a40c91db9e1614051bf73..ff2cee6b80f2cd3ffc8592a6f78f4b7de89b5663 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -18,7 +18,8 @@ #include #include #include - +//2020/03/28, add for pccore CONFIG_PCCORE +#include /********************************************************************* * CPUFREQ INTERFACE * *********************************************************************/ @@ -151,6 +152,23 @@ struct cpufreq_policy { /* For cpufreq driver's internal use */ void *driver_data; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-05-28, add for stuck monitor*/ + /* For get changed freq info */ + char change_comm[TASK_COMM_LEN]; + unsigned int org_max; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ +#ifdef CONFIG_CONTROL_CENTER + unsigned int req_freq; + unsigned int cc_min; + unsigned int cc_max; + spinlock_t cc_lock; + bool cc_enable; +#endif +//2020/04/01, add for pccore CONFIG_PCCORE +#ifdef CONFIG_PCCORE + unsigned int min_idx; +#endif }; /* Only for ACPI */ @@ -231,7 +249,8 @@ static inline void cpufreq_stats_record_transition(struct cpufreq_policy *policy #define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */ #define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */ #define CPUFREQ_RELATION_C 2 /* closest frequency to target */ - +// 2020/03/28, add for pccore CONFIG_PCCORE +#define CPUFREQ_RELATION_OP 3 /* vendor customized frequency selection */ struct freq_attr { struct attribute attr; ssize_t (*show)(struct cpufreq_policy *, char *); @@ -806,6 +825,10 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, unsigned int freq; int idx, best = -1; +// 2020/03/28, add for pccore CONFIG_PCCORE + unsigned int op_mode = get_op_mode(); + bool op_enable = get_op_select_freq_enable(); + cpufreq_for_each_valid_entry_idx(pos, table, idx) { freq = pos->frequency; @@ -821,9 +844,17 @@ static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy, if (best == -1) return idx; +// 2020/03/05, add for pccore CONFIG_PCCORE /* Choose the closest freq */ - if (target_freq - table[best].frequency > freq - target_freq) - return idx; + if (op_enable && op_mode == 1) { + if ((target_freq - table[best].frequency) > + ((freq - table[best].frequency) * get_op_limit() / 100)) + return idx; + } else { + /* Choose the closest freq */ + if (target_freq - table[best].frequency > freq - target_freq) + return idx; + } return best; } @@ -840,6 +871,10 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, unsigned int freq; int idx, best = -1; +// 2020/03/28, add for pccore CONFIG_PCCORE + unsigned int op_mode = get_op_mode(); + bool op_enable = get_op_select_freq_enable(); + cpufreq_for_each_valid_entry_idx(pos, table, idx) { freq = pos->frequency; @@ -855,9 +890,17 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, if (best == -1) return idx; +// 2020/03/28, add for pccore CONFIG_PCCORE /* Choose the closest freq */ - if (table[best].frequency - target_freq > target_freq - freq) - return idx; + if (op_enable && op_mode == 1) { + if ((target_freq - table[best].frequency) > + ((freq - table[best].frequency) * get_op_limit() / 100)) + return idx; + } else { + /* Choose the closest freq */ + if (target_freq - table[best].frequency > freq - target_freq) + return idx; + } return best; } @@ -869,12 +912,34 @@ static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy, static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy, unsigned int target_freq) { + +// 2020/03/25, add for pccore CONFIG_PCCORE + unsigned int raw_freq = target_freq * 4 / 5; + unsigned int op_mode = get_op_mode(); + bool op_enable = get_op_select_freq_enable(); + unsigned int idx, prefer_idx; + target_freq = clamp_val(target_freq, policy->min, policy->max); + raw_freq = clamp_val(raw_freq, policy->min, policy->max); + + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) { + if (op_enable && op_mode == 2) { + prefer_idx = cpufreq_table_find_index_ac(policy, raw_freq); + idx = cpufreq_table_find_index_ac(policy, target_freq); + return cross_pd(policy->cpu, prefer_idx, idx, true); + } else { + return cpufreq_table_find_index_ac(policy, target_freq); + } + } else { + if (op_enable && op_mode == 2) { + idx = cpufreq_table_find_index_dc(policy, target_freq); + prefer_idx = cpufreq_table_find_index_dc(policy, raw_freq); + return cross_pd(policy->cpu, prefer_idx, idx, false); + } else { + return cpufreq_table_find_index_dc(policy, target_freq); + } + } - if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING) - return cpufreq_table_find_index_ac(policy, target_freq); - else - return cpufreq_table_find_index_dc(policy, target_freq); } static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, @@ -892,6 +957,9 @@ static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy, return cpufreq_table_find_index_h(policy, target_freq); case CPUFREQ_RELATION_C: return cpufreq_table_find_index_c(policy, target_freq); +// 2020/03/28, add for pccore CONFIG_PCCORE + case CPUFREQ_RELATION_OP: + return cpufreq_table_find_index_c(policy, target_freq); default: pr_err("%s: Invalid relation: %d\n", __func__, relation); return -EINVAL; diff --git a/include/linux/cred.h b/include/linux/cred.h index 1dc351d8548bfaa9f6afa4024910277fb84d4f2f..cbb52a32aac2968d6235385985c0b621721a5e0c 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -410,5 +410,32 @@ do { \ *(_fsuid) = __cred->fsuid; \ *(_fsgid) = __cred->fsgid; \ } while(0) +/*2020-06-20 [OSP-5970] add for heathinfo start*/ +extern bool is_fg(int uid); +static inline int task_is_fg(struct task_struct *task) +{ int cur_uid; + cur_uid = task_uid(task).val; + if (is_fg(cur_uid)) + return 1; + return 0; +} /*2020-06-20 [OSP-5970] end*/ + +#ifdef CONFIG_ONEPLUS_FG_OPT +extern bool is_fg(int uid); +static inline int current_is_fg(void) +{ + int cur_uid; + + cur_uid = current_uid().val; + if (is_fg(cur_uid)) + return 1; + return 0; +} +#else +static inline int current_is_fg(void) +{ + return 0; +} +#endif /*CONFIG_ONEPLUS_FG_OPT*/ #endif /* _LINUX_CRED_H */ diff --git a/include/linux/device.h b/include/linux/device.h index 39898a1ee1cce1344331f86f040524d5650b2e88..952c9ad7d726712388523da123ee3a2a5cb29c56 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -1085,6 +1085,10 @@ struct device { bool offline:1; bool of_node_reused:1; bool state_synced:1; + +#ifdef CONFIG_CONTROL_CENTER + bool cc_marked; +#endif }; static inline struct device *kobj_to_dev(struct kobject *kobj) diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 21f5aa0b217f3c0ce3c04a7d459f7a2e44e93076..43722d8f1891b65ef1533b530e2b0552655c8ce0 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -67,6 +67,10 @@ static inline bool try_to_freeze(void) return try_to_freeze_unsafe(); } +/* huruihuan add for freezing task in cgroup despite of PF_FREEZER_SKIP flag */ +extern void unfreezer_fork(struct task_struct *task); +extern bool freeze_cgroup_task(struct task_struct *p); + extern bool freeze_task(struct task_struct *p); extern bool set_freezable(void); diff --git a/include/linux/fs.h b/include/linux/fs.h index 2b0ac02751bdc235221390b0fb1f9e591a95aaae..b98231973da98936069f7e30c523c51d77d7776e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -78,6 +78,7 @@ extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; extern int sysctl_protected_fifos; extern int sysctl_protected_regular; +extern char *inode_name(struct inode *ino); typedef __kernel_rwf_t rwf_t; @@ -158,6 +159,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* File is stream-like */ #define FMODE_STREAM ((__force fmode_t)0x200000) +/* File hasn't page cache and can't be mmaped, for stackable filesystem */ +#define FMODE_NONMAPPABLE ((__force fmode_t)0x400000) + /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) @@ -1798,6 +1802,7 @@ struct file_operations { long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); void (*show_fdinfo)(struct seq_file *m, struct file *f); + struct file* (*get_lower_file)(struct file *f); #ifndef CONFIG_MMU unsigned (*mmap_capabilities)(struct file *); #endif diff --git a/include/linux/genhd.h b/include/linux/genhd.h index f13272d8433200b5c846365b808a29180d21b12f..75687ce0e7ab8c988ed061c2164065f2dc7b49c8 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -611,6 +611,9 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk, extern void __delete_partition(struct percpu_ref *); extern void delete_partition(struct gendisk *, int); extern void printk_all_partitions(void); +#ifdef CONFIG_WB_KERNEL_LOG +extern struct block_device *find_reserve_partition(void); +#endif extern struct gendisk *__alloc_disk_node(int minors, int node_id); extern struct kobject *get_disk_and_module(struct gendisk *disk); diff --git a/include/linux/hid.h b/include/linux/hid.h index 8506637f070d17f730d847c7f492a0365703c325..a46b6832b3733d26026bb09af041348da8367a87 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -956,34 +956,49 @@ static inline void hid_device_io_stop(struct hid_device *hid) { * @max: maximal valid usage->code to consider later (out parameter) * @type: input event type (EV_KEY, EV_REL, ...) * @c: code which corresponds to this usage and type + * + * The value pointed to by @bit will be set to NULL if either @type is + * an unhandled event type, or if @c is out of range for @type. This + * can be used as an error condition. */ static inline void hid_map_usage(struct hid_input *hidinput, struct hid_usage *usage, unsigned long **bit, int *max, - __u8 type, __u16 c) + __u8 type, unsigned int c) { struct input_dev *input = hidinput->input; - - usage->type = type; - usage->code = c; + unsigned long *bmap = NULL; + unsigned int limit = 0; switch (type) { case EV_ABS: - *bit = input->absbit; - *max = ABS_MAX; + bmap = input->absbit; + limit = ABS_MAX; break; case EV_REL: - *bit = input->relbit; - *max = REL_MAX; + bmap = input->relbit; + limit = REL_MAX; break; case EV_KEY: - *bit = input->keybit; - *max = KEY_MAX; + bmap = input->keybit; + limit = KEY_MAX; break; case EV_LED: - *bit = input->ledbit; - *max = LED_MAX; + bmap = input->ledbit; + limit = LED_MAX; break; } + + if (unlikely(c > limit || !bmap)) { + pr_warn_ratelimited("%s: Invalid code %d type %d\n", + input->name, c, type); + *bit = NULL; + return; + } + + usage->type = type; + usage->code = c; + *max = limit; + *bit = bmap; } /** @@ -997,7 +1012,8 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput, __u8 type, __u16 c) { hid_map_usage(hidinput, usage, bit, max, type, c); - clear_bit(c, *bit); + if (*bit) + clear_bit(usage->code, *bit); } /** diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index d80ab2b31d435fc813295ec781394c85cf8b71ea..81c77d291401c8502140f4bd989543e502034988 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -46,6 +46,55 @@ enum pon_power_off_type { PON_POWER_OFF_MAX_TYPE = 0x10, }; +/* @bsp, 20190705 Battery & Charging porting */ +struct qpnp_pon { + struct device *dev; + struct regmap *regmap; + struct input_dev *pon_input; + struct qpnp_pon_config *pon_cfg; + struct pon_regulator *pon_reg_cfg; + struct list_head list; + struct delayed_work bark_work; + struct delayed_work press_work; +#ifdef CONFIG_KEY_FLUSH + struct delayed_work press_work_flush; +#endif + struct work_struct up_work; + atomic_t press_count; + struct dentry *debugfs; + struct device_node *pbs_dev_node; + int pon_trigger_reason; + int pon_power_off_reason; + int num_pon_reg; + int num_pon_config; + u32 dbc_time_us; + u32 uvlo; + int warm_reset_poff_type; + int hard_reset_poff_type; + int shutdown_poff_type; + int resin_warm_reset_type; + int resin_hard_reset_type; + int resin_shutdown_type; + u16 base; + u8 subtype; + u8 pon_ver; + u8 warm_reset_reason1; + u8 warm_reset_reason2; + u8 twm_state; + bool is_spon; + bool store_hard_reset_reason; + bool resin_hard_reset_disable; + bool resin_shutdown_disable; + bool ps_hold_hard_reset_disable; + bool ps_hold_shutdown_disable; + bool kpdpwr_dbc_enable; + bool support_twm_config; + bool resin_pon_reset; + ktime_t kpdpwr_last_release_time; + struct notifier_block pon_nb; + bool legacy_hard_reset_offset; +}; + enum pon_restart_reason { PON_RESTART_REASON_UNKNOWN = 0x00, PON_RESTART_REASON_RECOVERY = 0x01, @@ -54,8 +103,20 @@ enum pon_restart_reason { PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x04, PON_RESTART_REASON_DMVERITY_ENFORCE = 0x05, PON_RESTART_REASON_KEYS_CLEAR = 0x06, + PON_RESTART_REASON_FACTORY = 0x21, + PON_RESTART_REASON_RF = 0x22, + PON_RESTART_BOOTLOADER_RECOVERY = 0X23, + PON_RESTART_REASON_SBL_DDRTEST = 0x24, + PON_RESTART_REASON_SBL_DDR_CUS = 0x25, + PON_RESTART_REASON_MEM_AGING = 0x26, + //0x2E is SBLTEST FAIL, just happen in ddrtest fail when xbl setup + }; +/* Define OEM reboot mode magic*/ +#define FACTORY_MODE 0x77665504 +#define RF_MODE 0x77665506 + #ifdef CONFIG_INPUT_QPNP_POWER_ON int qpnp_pon_system_pwr_off(enum pon_power_off_type type); int qpnp_pon_is_warm_reset(void); @@ -65,6 +126,12 @@ int qpnp_pon_set_restart_reason(enum pon_restart_reason reason); bool qpnp_pon_check_hard_reset_stored(void); int qpnp_pon_modem_pwr_off(enum pon_power_off_type type); +#ifdef CONFIG_KEY_FLUSH +extern int panic_flush_device_cache(int timeout); +extern void panic_flush_device_cache_circled_on(void); +extern void panic_flush_device_cache_circled_off(void); +#endif + #else static int qpnp_pon_system_pwr_off(enum pon_power_off_type type) diff --git a/include/linux/mm.h b/include/linux/mm.h index 678f36b5853500471e350f9c8fd770fab482e19e..961dfe864ceb256f363dde3a09f9eb6228098d7f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -51,6 +51,7 @@ static inline void set_max_mapnr(unsigned long limit) { } extern unsigned long totalram_pages; extern void * high_memory; extern int page_cluster; +extern unsigned long dbg_pm[8]; #ifdef CONFIG_SYSCTL extern int sysctl_legacy_va_layout; diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h index 10191c28fc04ce22c605d54a87257ee5ff427651..725a94aeb59fade9958acd0e974af313d9217c22 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -62,7 +62,10 @@ static __always_inline void del_page_from_lru_list(struct page *page, struct lruvec *lruvec, enum lru_list lru) { list_del(&page->lru); - update_lru_size(lruvec, lru, page_zonenum(page), -hpage_nr_pages(page)); + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + if (!smb_update_uid_lru_size(page, lruvec, lru)) + update_lru_size(lruvec, lru, + page_zonenum(page), -hpage_nr_pages(page)); } /** diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index f9fd5451e139675ed607621611455480d9f0b89d..64fe0e8dac433c3c2a9465bf8134c646c4f27945 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -286,6 +286,10 @@ struct vm_area_struct { */ unsigned long rb_subtree_gap; +#ifdef CONFIG_VM_FRAGMENT_MONITOR + unsigned long rb_glfragment_gap; +#endif + /* Second cache line starts here. */ struct mm_struct *vm_mm; /* The address space we belong to. */ @@ -510,6 +514,9 @@ struct mm_struct { /* HMM needs to track a few things per mm */ struct hmm *hmm; #endif + unsigned int zygoteheap_in_MB; + int va_feature; + unsigned long va_feature_rnd; } __randomize_layout; /* diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index ad855211d81e08a40c584a153dfd0df1bec0ac77..b49bedabc929ad91223c1cfd2309a59b58ca991c 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -60,6 +60,9 @@ enum migratetype { #endif MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, +#ifdef CONFIG_DEFRAG + MIGRATE_UNMOVABLE_DEFRAG_POOL, +#endif #ifdef CONFIG_MEMORY_ISOLATION MIGRATE_ISOLATE, /* can't allocate from here */ #endif @@ -153,8 +156,17 @@ enum zone_stat_item { NR_BOUNCE, #if IS_ENABLED(CONFIG_ZSMALLOC) NR_ZSPAGES, /* allocated in zsmalloc */ +#endif +#ifdef CONFIG_SMART_BOOST + NR_ZONE_UID_LRU, +#endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO + NR_IONCACHE_PAGES, #endif NR_FREE_CMA_PAGES, +#ifdef CONFIG_DEFRAG + NR_FREE_DEFRAG_POOL, +#endif NR_VM_ZONE_STAT_ITEMS }; enum node_stat_item { @@ -241,7 +253,15 @@ struct zone_reclaim_stat { unsigned long recent_rotated[2]; unsigned long recent_scanned[2]; }; - +#ifdef CONFIG_SMART_BOOST +struct uid_node { + struct uid_node __rcu *next; + uid_t uid; + unsigned int hot_count; + struct list_head page_cache_list; + struct rcu_head rcu; +}; +#endif struct lruvec { struct list_head lists[NR_LRU_LISTS]; struct zone_reclaim_stat reclaim_stat; @@ -252,6 +272,9 @@ struct lruvec { #ifdef CONFIG_MEMCG struct pglist_data *pgdat; #endif +#ifdef CONFIG_SMART_BOOST + struct uid_node **uid_hash; +#endif }; /* Mask used at gathering information at once (see memcontrol.c) */ diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h new file mode 100644 index 0000000000000000000000000000000000000000..6a90e1c5de679c5c099586f1043316ad2a7cd488 --- /dev/null +++ b/include/linux/msm_drm_notify.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _MSM_DRM_NOTIFY_H_ +#define _MSM_DRM_NOTIFY_H_ + +#include + +/* A hardware display blank change occurred */ +#define MSM_DRM_EVENT_BLANK 0x01 +/* A hardware display blank early change occurred */ +#define MSM_DRM_EARLY_EVENT_BLANK 0x02 + +enum { + /* panel: power on */ + MSM_DRM_BLANK_UNBLANK, + /* panel: power off */ + MSM_DRM_BLANK_POWERDOWN, + /* panel power on for tp */ + MSM_DRM_BLANK_UNBLANK_CUST, + /* panel:lcd doze mode */ + MSM_DRM_BLANK_NORMAL, + /* panel power off */ + MSM_DRM_BLANK_POWERDOWN_CUST, + /*panel 60HZ */ + MSM_DRM_DYNAMICFPS_60 = 60, + /*panel 90HZ */ + MSM_DRM_DYNAMICFPS_90 = 90, +}; + +enum msm_drm_display_id { + /* primary display */ + MSM_DRM_PRIMARY_DISPLAY, + /* external display */ + MSM_DRM_EXTERNAL_DISPLAY, + MSM_DRM_DISPLAY_MAX +}; + +struct msm_drm_notifier { + enum msm_drm_display_id id; + void *data; +}; + +int dsi_panel_backlight_get(void); + +#ifdef CONFIG_DRM_MSM +int msm_drm_register_client(struct notifier_block *nb); +int msm_drm_unregister_client(struct notifier_block *nb); +#else +static inline int msm_drm_register_client(struct notifier_block *nb) +{ + return 0; +} + +static inline int msm_drm_unregister_client(struct notifier_block *nb) +{ + return 0; +} +#endif +#endif diff --git a/include/linux/netfilter/nf_conntrack_dns.h b/include/linux/netfilter/nf_conntrack_dns.h new file mode 100644 index 0000000000000000000000000000000000000000..650a39432e080ce91053f3df73eb8dea09b01bbd --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_dns.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef _SOP_NF_CONNTRACK_DNS_H +#define _SOP_NF_CONNTRACK_DNS_H + +#define DNS_PORT 53 +#define DNS_RECORD_TYPE 2 +#define DNS_RECORD_CLASS 2 +#define DNS_RECORD_TYPE_AND_CLASS (DNS_RECORD_TYPE + DNS_RECORD_CLASS) +#define DNS_RECORD_MIN (sizeof("A") + DNS_RECORD_TYPE_AND_CLASS) + +struct nf_ct_dns { + u8 usage; + char query[0]; +}; + +struct dnshdr { + __be16 query_id; + __be16 flags; + __be16 question_count; + __be16 answer_count; + __be16 authority_count; + __be16 additional_record_count; + char query[0]; +}; + +#endif /* _SOP_NF_CONNTRACK_DNS_H */ diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 260c4421d3c0f0bfc219059bde19d1bc5e78b026..65d5b7d1f18490e37f4c6473b46a201d59a983d6 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -101,6 +101,9 @@ enum pageflags { #if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) PG_young, PG_idle, +#endif +#ifdef CONFIG_SMART_BOOST + PG_uidlru, #endif __NR_PAGEFLAGS, @@ -323,6 +326,10 @@ PAGEFLAG(Reclaim, reclaim, PF_NO_TAIL) TESTCLEARFLAG(Reclaim, reclaim, PF_NO_TAIL) PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND) +#ifdef CONFIG_SMART_BOOST +PAGEFLAG(UIDLRU, uidlru, PF_HEAD) __CLEARPAGEFLAG(UIDLRU, uidlru, PF_HEAD) + __SETPAGEFLAG(UIDLRU, uidlru, PF_HEAD) +#endif #ifdef CONFIG_HIGHMEM /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 58952fa01f1cadb484e1dd7d8febc667d495e6c0..e3a5348d003e94210ab5ae386a524a1d91044bb2 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1478,4 +1478,12 @@ int perf_event_restart_events(unsigned int cpu); #define perf_event_restart_events NULL #endif +#ifdef CONFIG_HOUSTON +extern bool ht_perf_event_open(pid_t pid, int id); +extern u64 ht_perf_read(struct task_struct *task, int id); +#else +static inline bool ht_perf_event_open(pid_t pid, int id) { return false; }; +static inline u64 ht_perf_read(struct task_struct *task, int id) { return 0; }; +#endif + #endif /* _LINUX_PERF_EVENT_H */ diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index e22de69dcd98fc667b30850fcd7940b94c54fceb..977473280d556f1ca1c5cb85595623c42ece50ed 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -18,7 +18,21 @@ enum { PM_QOS_NETWORK_LATENCY, PM_QOS_NETWORK_THROUGHPUT, PM_QOS_MEMORY_BANDWIDTH, - + PM_QOS_C0_CPUFREQ_MAX, + PM_QOS_C0_CPUFREQ_MIN, + PM_QOS_C1_CPUFREQ_MAX, + PM_QOS_C1_CPUFREQ_MIN, + PM_QOS_C2_CPUFREQ_MAX, + PM_QOS_C2_CPUFREQ_MIN, + PM_QOS_DEVFREQ_MAX, + PM_QOS_DEVFREQ_MIN, + /* add for thermal*/ + PM_QOS_MSM_THERMAL, + PM_QOS_SKIN_THERMAL, + PM_QOS_MMW0_THERMAL, + PM_QOS_MMW1_THERMAL, + PM_QOS_MMW2_THERMAL, + PM_QOS_MODEM_SKIN_THERMAL, /* insert new class ID */ PM_QOS_NUM_CLASSES, }; @@ -44,6 +58,19 @@ enum pm_qos_flags_status { #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) +#define MIN_CPUFREQ 0 +#define MAX_CPUFREQ 0x40 +#define MASK_CPUFREQ 0xE0 + +#define PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE MAX_CPUFREQ +#define PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE MIN_CPUFREQ +#define PM_QOS_DEVFREQ_MAX_DEFAULT_VALUE MAX_CPUFREQ +#define PM_QOS_DEVFREQ_MIN_DEFAULT_VALUE MIN_CPUFREQ + +extern void msm_cpuidle_set_sleep_disable(bool disable); + +#define PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE 0 + #define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) enum pm_qos_req_type { diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index 6e6a25220c565076b152c4664e25a3ae79cffa7c..2389c9acc7b00585232476246d57d7fa7da6a486 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -118,6 +118,7 @@ extern void __pm_relax(struct wakeup_source *ws); extern void pm_relax(struct device *dev); extern void pm_wakeup_ws_event(struct wakeup_source *ws, unsigned int msec, bool hard); extern void pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard); +extern void pm_print_active_wakeup_sources_queue(bool on); #else /* !CONFIG_PM_SLEEP */ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 7f3b376c691fe2fdbde86c974b7cf6d9a3eeda3e..ee423558a7b7823988c6ad8162d2f9f857bca760 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -163,10 +163,34 @@ enum { enum power_supply_property { /* Properties of type `int' */ POWER_SUPPLY_PROP_STATUS = 0, +/* @bsp, 2019/07/05 Battery & Charging porting */ + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, + POWER_SUPPLY_PROP_CC_TO_CV_POINT, + POWER_SUPPLY_PROP_CHG_PROTECT_STATUS, + POWER_SUPPLY_PROP_FASTCHG_IS_OK, + POWER_SUPPLY_PROP_FASTCHG_STATUS, + POWER_SUPPLY_PROP_FASTCHG_STARTING, + POWER_SUPPLY_CUTOFF_VOLT_WITH_CHARGER, + POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF, + POWER_SUPPLY_PROP_CHECK_USB_UNPLUG, + POWER_SUPPLY_PROP_OTG_SWITCH, + POWER_SUPPLY_PROP_HW_DETECT, + POWER_SUPPLY_PROP_SWITCH_DASH, + POWER_SUPPLY_PROP_NOTIFY_CHARGER_SET_PARAMETER, + POWER_SUPPLY_PROP_FG_CAPACITY, + POWER_SUPPLY_PROP_FG_VOLTAGE_NOW, + POWER_SUPPLY_PROP_FG_CURRENT_NOW, + POWER_SUPPLY_PROP_IS_AGING_TEST, + POWER_SUPPLY_PROP_CONNECTER_TEMP_ONE, + POWER_SUPPLY_PROP_CONNECTER_TEMP_TWO, + POWER_SUPPLY_PROP_CONNECT_DISABLE, + POWER_SUPPLY_PROP_BQ_SOC, + POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_SWARP_ONLINE, POWER_SUPPLY_PROP_AUTHENTIC, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CYCLE_COUNT, @@ -255,6 +279,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_COLD_TEMP, POWER_SUPPLY_PROP_HOT_TEMP, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, + POWER_SUPPLY_PROP_BATTERY_HEALTH, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, + POWER_SUPPLY_PROP_REMAINING_CAPACITY, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, POWER_SUPPLY_PROP_RESISTANCE_ID, /* in Ohms */ @@ -375,6 +402,9 @@ enum power_supply_property { * MODEL_NAME and SERIAL_NUMBER. Don't add below SERIAL_NUMBER. */ POWER_SUPPLY_PROP_SERIAL_NUMBER, + /* Property to initate DPDM recovery */ + POWER_SUPPLY_PROP_START_DPDM_RECOVERY, + POWER_SUPPLY_PROP_DISCONNECT_PD, }; enum power_supply_type { @@ -402,6 +432,8 @@ enum power_supply_type { POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */ POWER_SUPPLY_TYPE_DFP, /* Type-C DFP */ POWER_SUPPLY_TYPE_CHARGE_PUMP, /* Charge Pump */ +/* @bsp, 2019/07/05 Battery & Charging porting */ + POWER_SUPPLY_TYPE_DASH, }; enum power_supply_usb_type { diff --git a/include/linux/printk.h b/include/linux/printk.h index cf3eccfe1543621cc3d91fec644a63bb6b1dc0f7..cc7a671ed71f88550f86ef20e321da128e2261b8 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -529,5 +529,5 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, { } #endif - +int force_oem_console_setup(char *str); #endif diff --git a/include/linux/pstore.h b/include/linux/pstore.h index de9093d6e6609a1431aed49322c1c12a5e2940a1..2cf2341e180e79855125d24783f31a94146a9a52 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -30,6 +30,8 @@ #include #include +#include + struct module; /* pstore record types (see fs/pstore/inode.c for filename templates) */ @@ -44,6 +46,7 @@ enum pstore_type_id { PSTORE_TYPE_PPC_COMMON = 6, PSTORE_TYPE_PMSG = 7, PSTORE_TYPE_PPC_OPAL = 8, + PSTORE_TYPE_DEVICE_INFO = 9, PSTORE_TYPE_UNKNOWN = 255 }; @@ -276,4 +279,34 @@ pstore_ftrace_write_timestamp(struct pstore_ftrace_record *rec, u64 val) } #endif +/*move from ram.c*/ +struct ramoops_context { + struct persistent_ram_zone **dprzs; /* Oops dump zones */ + struct persistent_ram_zone *cprz; /* Console zone */ + struct persistent_ram_zone **fprzs; /* Ftrace zones */ + struct persistent_ram_zone *mprz; /* PMSG zone */ + struct persistent_ram_zone *dprz; + phys_addr_t phys_addr; + unsigned long size; + unsigned int memtype; + size_t record_size; + size_t console_size; + size_t ftrace_size; + size_t pmsg_size; + size_t device_info_size; + int dump_oops; + u32 flags; + struct persistent_ram_ecc_info ecc_info; + unsigned int max_dump_cnt; + unsigned int dump_write_cnt; + /* _read_cnt need clear on ramoops_pstore_open */ + unsigned int dump_read_cnt; + unsigned int console_read_cnt; + unsigned int max_ftrace_cnt; + unsigned int ftrace_read_cnt; + unsigned int pmsg_read_cnt; + unsigned int device_info_read_cnt; + struct pstore_info pstore; +}; + #endif /*_LINUX_PSTORE_H*/ diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index e6d226464838a1e2b67c77145207ae5e27cb589b..bed90ebd4b8c1a73d4ae8eeeb605c53bce915186 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h @@ -97,6 +97,7 @@ struct ramoops_platform_data { unsigned long console_size; unsigned long ftrace_size; unsigned long pmsg_size; + unsigned long device_info_size; int dump_oops; u32 flags; struct persistent_ram_ecc_info ecc_info; diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h index 3e2888af87c3c64ee0cafe082df9980aea53956d..c96e04c26c49f99b101878021ea22670212f3eec 100644 --- a/include/linux/qcom-geni-se.h +++ b/include/linux/qcom-geni-se.h @@ -70,6 +70,8 @@ struct se_geni_rsc { struct pinctrl *geni_pinctrl; struct pinctrl_state *geni_gpio_active; struct pinctrl_state *geni_gpio_sleep; + // Added for ESD issue AVICII-556 + struct pinctrl_state *geni_gpio_reset; int clk_freq_out; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; @@ -79,6 +81,9 @@ struct se_geni_rsc { #define PINCTRL_ACTIVE "active" #define PINCTRL_SLEEP "sleep" +// Added for ESD issue AVICII-556 +#define PINCTRL_RESET "reset" + #define KHz(freq) (1000 * (freq)) /* Common SE registers */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 723db739db8b5bd841b585c02820209fa7540755..b432d99f40774d4d2aee86c9362244ca0abe0b6f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -29,6 +29,10 @@ #include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + /* task_struct member predeclarations (sorted alphabetically): */ struct audit_context; struct backing_dev_info; @@ -133,6 +137,20 @@ enum fps { FPS144 = 144, }; +#ifdef CONFIG_UXCHAIN +#define GOLD_PLUS_CPU 7 +#define PREEMPT_DISABLE_NS 10000000 +extern int sysctl_uxchain_enabled; +extern int sysctl_launcher_boost_enabled; +extern void uxchain_mutex_list_add(struct task_struct *task, + struct list_head *entry, struct list_head *head, struct mutex *lock); +extern void uxchain_dynamic_ux_boost(struct task_struct *owner, + struct task_struct *task); +extern void uxchain_dynamic_ux_reset(struct task_struct *task); +extern struct task_struct *get_futex_owner(u32 __user *uaddr2); +extern int ux_thread(struct task_struct *task); +#endif + #ifdef CONFIG_DEBUG_ATOMIC_SLEEP /* @@ -224,6 +242,64 @@ enum fps { } while (0) #endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/* 2020-06-17 add for stuck monitor */ +struct uifirst_d_state { + u64 iowait_ns; + u64 downread_ns; + u64 downwrite_ns; + u64 mutex_ns; + u64 other_ns; + int cnt; +}; + +struct uifirst_s_state { + u64 binder_ns; + u64 epoll_ns; + u64 futex_ns; + u64 other_ns; + int cnt; +}; + +struct oneplus_uifirst_monitor_info { + u64 runnable_state; + u64 ltt_running_state; /* ns */ + u64 mid_running_state; /* ns */ + u64 big_running_state; /* ns */ + struct uifirst_d_state d_state; + struct uifirst_s_state s_state; +}; + +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +#define ODD(x) (bool)(x & 0x0000000000000001) +#define TASK_READ_OVERLOAD_FLAG 0x0000000000000001 +#define TASK_WRITE_OVERLOAD_FLAG 0x0000000000000002 +#define TASK_CPU_OVERLOAD_FG_FLAG 0x0000000000000004 +#define TASK_CPU_OVERLOAD_BG_FLAG 0x0000000000000008 +#define TASK_RT_THREAD_FLAG 0x0000000000000010 + +extern struct sample_window_t sample_window; +extern u64 ohm_write_thresh; +extern u64 ohm_read_thresh; +extern u64 ohm_runtime_thresh_fg; +extern u64 ohm_runtime_thresh_bg; + +struct task_load_info { + u64 write_bytes; + u64 read_bytes; + u64 runtime[2]; + u64 task_sample_index; + u64 tli_overload_flag; +}; + +struct sample_window_t { + u64 timestamp; + u64 window_index; +}; +#endif /* Task command name length: */ #define TASK_COMM_LEN 16 @@ -535,6 +611,9 @@ struct sched_entity { u64 sum_exec_runtime; u64 vruntime; u64 prev_sum_exec_runtime; +#ifdef CONFIG_UXCHAIN + u64 vruntime_minus; +#endif u64 nr_migrations; @@ -827,6 +906,16 @@ struct task_struct { /* Per task flags (PF_*), defined further below: */ unsigned int flags; unsigned int ptrace; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-06-20 [OSP-5970] add for get /proc/oneplus_healthinfo/cpu_rt_info**/ + u64 rtstart_time; + u64 rtend_time; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + /* huruihuan add for kill task in D status */ + unsigned int kill_flag; + struct timespec ttu; + + int compensate_need; #ifdef CONFIG_SMP struct llist_node wake_entry; @@ -907,6 +996,9 @@ struct task_struct { int nr_cpus_allowed; cpumask_t cpus_allowed; cpumask_t cpus_requested; +#ifdef CONFIG_RATP + cpumask_t cpus_suggested; +#endif #ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting; @@ -1151,6 +1243,9 @@ struct task_struct { /* Protection of the PI data structures: */ raw_spinlock_t pi_lock; +#ifdef CONFIG_UXCHAIN + raw_spinlock_t uxchain_lock; +#endif struct wake_q_node wake_q; @@ -1222,6 +1317,11 @@ struct task_struct { siginfo_t *last_siginfo; struct task_io_accounting ioac; + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + struct task_load_info tli[2]; +#endif + #ifdef CONFIG_PSI /* Pressure stall state */ unsigned int psi_flags; @@ -1471,13 +1571,105 @@ struct task_struct { /* Used by LSM modules for access restriction: */ void *security; #endif - +#ifdef CONFIG_OPCHAIN + u64 utask_tag; + u64 utask_tag_base; + int etask_claim; + int claim_cpu; + bool utask_slave; +#endif + +#ifdef CONFIG_ONEPLUS_FG_OPT + int fuse_boost; +#endif + +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-05-27, add for stuck monitor*/ + int stuck_trace; + struct oneplus_uifirst_monitor_info oneplus_stuck_info; + unsigned in_mutex:1; + unsigned in_downread:1; + unsigned in_downwrite:1; + unsigned in_futex:1; + unsigned in_binder:1; + unsigned in_epoll:1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ /* * New fields for task_struct should be added above here, so that * they are included in the randomized portion of task_struct. */ randomized_struct_fields_end +#ifdef CONFIG_SMART_BOOST + int hot_count; +#endif +#ifdef CONFIG_CONTROL_CENTER + bool cc_enable; + struct cc_tsk_data *ctd; + u64 nice_effect_ts; + int cached_prio; +#endif + +#ifdef CONFIG_UXCHAIN + int static_ux; + int dynamic_ux; + int ux_depth; + u64 oncpu_time; + int prio_saved; + int saved_flag; +#endif + +#ifdef CONFIG_IM + int im_flag; +#endif + +#ifdef CONFIG_TPD + int tpd; + int dtpd; /* dynamic tpd task */ + int dtpdg; /* dynamic tpd task group */ +#endif + /* add for cpu distribution statistics */ + atomic64_t cpu_dist[8]; + atomic64_t total_cpu_dist[8]; + +#ifdef CONFIG_HOUSTON +#ifndef HT_PERF_COUNT_MAX +#define HT_PERF_COUNT_MAX 5 + /* RTG */ + spinlock_t rtg_lock; + struct list_head rtg_node; + struct list_head rtg_perf_node; + s64 rtg_ts; + s64 rtg_ts2; + s64 rtg_period_ts; + u32 rtg_cnt; + u32 rtg_peak; + u64 prev_schedstat; + u64 prev_ts_us; + + /* perf */ + struct list_head perf_node; + u32 perf_activate; + u32 perf_regular_activate; + u64 enqueue_ts; + u64 run_ts; + u64 end_ts; + u64 acc_run_ts; + u64 delta_ts; + u64 total_run_ts; + + /* filter */ + s64 f_ts; + u32 f_cnt; + u32 f_peak; + u64 perf_counters[HT_PERF_COUNT_MAX]; + struct perf_event *perf_events[HT_PERF_COUNT_MAX]; + struct work_struct perf_work; + struct list_head ht_perf_event_node; +#undef HT_PERF_COUNT_MAX +#endif +#endif + struct fuse_package *fpack; /* CPU-specific state of this task: */ struct thread_struct thread; @@ -1489,6 +1681,19 @@ struct task_struct { */ }; +/* add for cpu distribution statistics */ +static inline void cpu_dist_inc(struct task_struct *p, int cpu) +{ + if (likely(cpu >= 0 && cpu < 8)) + atomic64_inc(&p->cpu_dist[cpu]); +} + +struct fuse_package { + bool fuse_open_req; + struct file *filp; + char *iname; +}; + static inline struct pid *task_pid(struct task_struct *task) { return task->thread_pid; @@ -1724,6 +1929,11 @@ static inline bool is_percpu_thread(void) #define PFA_SPEC_IB_DISABLE 5 /* Indirect branch speculation restricted */ #define PFA_SPEC_IB_FORCE_DISABLE 6 /* Indirect branch speculation permanently restricted */ +#ifdef CONFIG_CGROUP_IOLIMIT +/* add for pg */ +#define PFA_IN_PAGEFAULT 27 +#endif + #define TASK_PFA_TEST(name, func) \ static inline bool task_##func(struct task_struct *p) \ { return test_bit(PFA_##name, &p->atomic_flags); } @@ -1743,6 +1953,12 @@ TASK_PFA_TEST(SPREAD_PAGE, spread_page) TASK_PFA_SET(SPREAD_PAGE, spread_page) TASK_PFA_CLEAR(SPREAD_PAGE, spread_page) +#ifdef CONFIG_CGROUP_IOLIMIT +TASK_PFA_TEST(IN_PAGEFAULT, in_pagefault) +TASK_PFA_SET(IN_PAGEFAULT, in_pagefault) +TASK_PFA_CLEAR(IN_PAGEFAULT, in_pagefault) +#endif + TASK_PFA_TEST(SPREAD_SLAB, spread_slab) TASK_PFA_SET(SPREAD_SLAB, spread_slab) TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab) @@ -1794,6 +2010,11 @@ static inline bool cpupri_check_rt(void) #define cpu_relax_yield() cpu_relax() #endif +#ifdef CONFIG_CONTROL_CENTER +extern void restore_user_nice_safe(struct task_struct *p); +extern void set_user_nice_no_cache(struct task_struct *p, long nice); +#endif + extern int yield_to(struct task_struct *p, bool preempt); extern void set_user_nice(struct task_struct *p, long nice); extern int task_prio(const struct task_struct *p); @@ -2214,4 +2435,12 @@ static inline void set_wake_up_idle(bool enabled) current->flags &= ~PF_WAKE_UP_IDLE; } +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +static inline void task_tli_init(struct task_struct *cur) +{ + memset(cur->tli, 0, sizeof(cur->tli)); + cur->tli[ODD(sample_window.window_index)].task_sample_index = sample_window.window_index; +} +#endif + #endif diff --git a/include/linux/sched/core_ctl.h b/include/linux/sched/core_ctl.h index b71b42aecb407683ab593a54e982b7d230a38d6a..0df7d21a2038a3d12db9d39c7e102e6b84564f76 100644 --- a/include/linux/sched/core_ctl.h +++ b/include/linux/sched/core_ctl.h @@ -30,4 +30,10 @@ static inline int core_ctl_set_boost(bool boost) static inline void core_ctl_notifier_register(struct notifier_block *n) {} static inline void core_ctl_notifier_unregister(struct notifier_block *n) {} #endif + +#ifdef CONFIG_CONTROL_CENTER +int core_ctl_op_boost(bool boost, int level); +#else +static inline int core_ctl_op_boost(bool boost, int level) { return 0; } +#endif #endif diff --git a/include/linux/sched/mm.h b/include/linux/sched/mm.h index e9d4e389aed937074bb0ff4a399528fc0a269ed4..cb37b33458f45adac9447408d6eeeea6683f3999 100644 --- a/include/linux/sched/mm.h +++ b/include/linux/sched/mm.h @@ -138,6 +138,7 @@ extern unsigned long arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags); +extern void special_arch_pick_mmap_layout(struct mm_struct *mm); #else static inline void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack) {} diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index e59a419ca4a6098acfc815d10f30f0e3f6127dc3..a097ba07616efaaf2ead2683ed9586005c021a94 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -41,6 +41,7 @@ extern unsigned int sysctl_sched_boost; extern unsigned int sysctl_sched_group_upmigrate_pct; extern unsigned int sysctl_sched_group_downmigrate_pct; extern unsigned int sysctl_sched_conservative_pl; +extern unsigned int sysctl_sched_skip_affinity; extern unsigned int sysctl_sched_many_wakeup_threshold; extern unsigned int sysctl_sched_walt_rotate_big_tasks; extern unsigned int sysctl_sched_min_task_util_for_boost; diff --git a/include/linux/swap.h b/include/linux/swap.h index 83302aa822f799df35264a98e0a64492078819a2..fa24801c187be1dfc3bcae293ee6caa58aca30c8 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -13,6 +13,8 @@ #include #include #include +/* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ +#include struct notifier_block; diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 03444cd87c3f8423fcc67db00a0a9a63888328db..8552d4343e86ca23affcd4b56b70aa49e94a5207 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -44,6 +44,8 @@ extern int proc_dostring(struct ctl_table *, int, void __user *, size_t *, loff_t *); extern int proc_dointvec(struct ctl_table *, int, void __user *, size_t *, loff_t *); +extern int proc_dointvec_oem(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); extern int proc_douintvec(struct ctl_table *, int, void __user *, size_t *, loff_t *); extern int proc_dointvec_minmax(struct ctl_table *, int, diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 8c71874e84852b5cefb9b9bf0a06a877457eaf86..82c7a59cafbcfc62aa302605b9add4f9b91052e2 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -36,6 +36,11 @@ struct sysrq_key_op { int enable_mask; }; +#ifdef CONFIG_PANIC_FLUSH +extern int panic_flush_device_cache(int timeout); +extern int oem_get_download_mode(void); +#endif + #ifdef CONFIG_MAGIC_SYSRQ /* Generic SysRq interface -- you may call it from any device driver, supplying diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h index 733ab62ae14130dc62c8d62e48e45002aa149781..1688c2bdd21b42e1153d41afc3501f53eb751713 100644 --- a/include/linux/task_io_accounting_ops.h +++ b/include/linux/task_io_accounting_ops.h @@ -10,6 +10,15 @@ #ifdef CONFIG_TASK_IO_ACCOUNTING static inline void task_io_account_read(size_t bytes) { +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + bool tli_index; + + tli_index = ODD(sample_window.window_index); + current->tli[tli_index].read_bytes += bytes; + /* >=1MB/s */ + if (current->tli[tli_index].read_bytes >= ohm_read_thresh) + current->tli[tli_index].tli_overload_flag |= TASK_READ_OVERLOAD_FLAG; +#endif current->ioac.read_bytes += bytes; } @@ -24,6 +33,15 @@ static inline unsigned long task_io_get_inblock(const struct task_struct *p) static inline void task_io_account_write(size_t bytes) { +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + bool tli_index; + + tli_index = ODD(sample_window.window_index); + current->tli[tli_index].write_bytes += bytes; + /* >=1MB/s */ + if (current->tli[tli_index].write_bytes >= ohm_write_thresh) + current->tli[tli_index].tli_overload_flag |= TASK_WRITE_OVERLOAD_FLAG; +#endif current->ioac.write_bytes += bytes; } @@ -58,6 +76,14 @@ static inline void task_blk_io_accounting_add(struct task_io_accounting *dst, static inline void task_io_account_read(size_t bytes) { +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + bool tli_index = ODD(sample_window.window_index); + + current->tli[tli_index].read_bytes += bytes; + /* >=1MB/s */ + if (current->tli[tli_index].read_bytes >= ohm_read_thresh) + current->tli[tli_index].tli_overload_flag |= TASK_READ_OVERLOAD_FLAG; +#endif } static inline unsigned long task_io_get_inblock(const struct task_struct *p) @@ -67,6 +93,14 @@ static inline unsigned long task_io_get_inblock(const struct task_struct *p) static inline void task_io_account_write(size_t bytes) { +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + bool tli_index = ODD(sample_window.window_index); + + current->tli[tli_index].write_bytes += bytes; + /* >=1MB/s */ + if (current->tli[tli_index].write_bytes >= ohm_write_thresh) + current->tli[tli_index].tli_overload_flag |= TASK_WRITE_OVERLOAD_FLAG; +#endif } static inline unsigned long task_io_get_oublock(const struct task_struct *p) diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index a5a3cfc3c2fa754fd8f21fc721094268a4aa256b..b9a9becf794b4a57b95e0061e92c69ce437e6792 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -43,6 +43,7 @@ extern void ktime_get_ts64(struct timespec64 *ts); extern void ktime_get_real_ts64(struct timespec64 *tv); extern void ktime_get_coarse_ts64(struct timespec64 *ts); extern void ktime_get_coarse_real_ts64(struct timespec64 *ts); +extern void __getnstimeofday64(struct timespec64 *tv); void getboottime64(struct timespec64 *ts); diff --git a/include/linux/ufstw.h b/include/linux/ufstw.h new file mode 100644 index 0000000000000000000000000000000000000000..c0248727fb6863a677e4ea7f33cc55276a2003ce --- /dev/null +++ b/include/linux/ufstw.h @@ -0,0 +1,8 @@ +#ifndef _UFSTW_FS_H_ +#define _UFSTW_FS_H_ + +#if defined(CONFIG_UFSTW) +extern void bdev_set_turbo_write(struct block_device *bdev); +extern void bdev_clear_turbo_write(struct block_device *bdev); +#endif +#endif diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index b0542cd11aeb09f5d0c979e1acf31ad8d550bb6d..1be1cc16a8dc0c7767cb7f8aa7512dba7f904fed 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -55,6 +55,9 @@ static inline gid_t __kgid_val(kgid_t gid) #define GLOBAL_ROOT_UID KUIDT_INIT(0) #define GLOBAL_ROOT_GID KGIDT_INIT(0) +/* huruihuan add for cgroup control */ +#define GLOBAL_SYSTEM_UID KUIDT_INIT(1000) + #define INVALID_UID KUIDT_INIT(-1) #define INVALID_GID KGIDT_INIT(-1) diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index 27a6fc7c35ea7bbcd55b78ee2fe4c6c525175b02..fab39d44abc738ad8741c446768576d66b902fa2 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -53,6 +53,7 @@ enum typec_pwr_opmode { TYPEC_PWR_MODE_1_5A, TYPEC_PWR_MODE_3_0A, TYPEC_PWR_MODE_PD, + TYPEC_PWR_MODE_MAX = TYPEC_PWR_MODE_PD, }; enum typec_accessory { diff --git a/include/linux/usb/usbpd.h b/include/linux/usb/usbpd.h index 87dff93fd0dc3aed89de4a4b42a1ab8b5d730f58..47ea696cde30033cf13f03c1ac762f32776e6559 100644 --- a/include/linux/usb/usbpd.h +++ b/include/linux/usb/usbpd.h @@ -13,7 +13,8 @@ struct device; /* Standard IDs */ #define USBPD_SID 0xff00 - +/* @bsp, 2020/08/04, add to detect SVID */ +#define OP_SVID 0x22d9 /* Structured VDM Command Type */ enum usbpd_svdm_cmd_type { SVDM_CMD_TYPE_INITIATOR, diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h index f25cef84b41db718a0d977c471b9afbc6773378e..da3e67342c20db5b28abe435ccdd7bc7e2eff524 100644 --- a/include/linux/vmstat.h +++ b/include/linux/vmstat.h @@ -376,12 +376,36 @@ static inline void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset) { } #endif /* CONFIG_SMP */ +#ifdef CONFIG_DEFRAG +static inline int is_migrate_defrag(int migratetype) +{ + return migratetype == MIGRATE_UNMOVABLE_DEFRAG_POOL; +} +static inline void defrag_update_zone_free(int migratetype, + struct zone *zone, int nr_pages) +{ + if (is_migrate_defrag(migratetype)) + __mod_zone_page_state(zone, NR_FREE_DEFRAG_POOL, nr_pages); +} +#else /* !CONFIG_DEFRAG */ +static inline int is_migrate_defrag(int migratetype) +{ + return 0; +} +static inline void defrag_update_zone_free(int migratetype, + struct zone *zone, int nr_pages) +{ +} +#endif /* end CONFIG_DEFRAG */ + static inline void __mod_zone_freepage_state(struct zone *zone, int nr_pages, int migratetype) { __mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages); if (is_migrate_cma(migratetype)) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages); + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + defrag_update_zone_free(migratetype, zone, nr_pages); } extern const char * const vmstat_text[]; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index f45141bdbb8375d836672ae5dce405cd4c1e1cd2..e1c0d8390eb4befeaa641fd7a439ae4dd6ef601a 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -19,6 +19,10 @@ #include #include +/* WIFI MODIFICATION */ +#include +/* WIFI MODIFICATION */ + #include #include #include @@ -35,6 +39,9 @@ union nf_conntrack_proto { struct ip_ct_tcp tcp; struct nf_ct_gre gre; unsigned int tmpl_padto; + /* WIFI MODIFICATION */ + struct nf_ct_dns dns; + /* WIFI MODIFICATION */ }; union nf_conntrack_expect_proto { @@ -86,6 +93,22 @@ struct nf_conn { #endif /* all members below initialized via memset */ u8 __nfct_init_offset[0]; + /* WIFI MODIFICATION */ + u32 op_game_skb_len; + u32 op_game_detect_status; + u32 op_game_time_interval; + int op_game_up_count; + int op_game_down_count; + int op_game_lost_count; + int op_game_same_count; + int op_app_type; + unsigned int op_tcp_last_total_retrans; + int op_tcp_continue_retrans; + s64 op_game_timestamp; + s64 op_game_last_timestamp; + s64 op_game_special_rx_pkt_timestamp; + s64 op_game_rx_normal_time_record; + /* WIFI MODIFICATION */ /* If we were expected by an expectation, this will be it */ struct nf_conn *master; diff --git a/include/net/sock.h b/include/net/sock.h index 94ffacc3683a85923accfd7e810eee05b7006c42..3125d04d3dd635d7f062c9ffeb00a96688f0152f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -187,6 +187,10 @@ struct sock_common { struct proto *skc_prot; possible_net_t skc_net; + /* WIFI MODIFICATION */ + u32 skc_op_mark; + /* WIFI MODIFICATION */ + #if IS_ENABLED(CONFIG_IPV6) struct in6_addr skc_v6_daddr; struct in6_addr skc_v6_rcv_saddr; @@ -363,7 +367,9 @@ struct sock { #define sk_incoming_cpu __sk_common.skc_incoming_cpu #define sk_flags __sk_common.skc_flags #define sk_rxhash __sk_common.skc_rxhash - +/* WIFI MODIFICATION */ +#define op_sla_mark __sk_common.skc_op_mark +/* WIFI MODIFICATION */ socket_lock_t sk_lock; atomic_t sk_drops; int sk_rcvlowat; diff --git a/include/oneplus/control_center/control_center_helper.h b/include/oneplus/control_center/control_center_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..33930199befad2d5c352341bb862264ce61a84db --- /dev/null +++ b/include/oneplus/control_center/control_center_helper.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __CONTROL_CENTER_HELPER_INC__ +#define __CONTROL_CENTER_HELPER_INC__ + +#ifdef CONFIG_CONTROL_CENTER +/* define for boost ts information */ +#define CC_BOOST_TS_SIZE (8) +struct cc_boost_ts { + pid_t pid; + u32 type; + u64 ts_us; + u64 min; + u64 max; +}; + +#define CC_CTL_PARAM_SIZE 4 +struct cc_command { + pid_t pid; + pid_t leader; + u32 period_us; + u32 prio; + u32 group; + u32 category; + u32 type; + u64 params[CC_CTL_PARAM_SIZE]; + u64 response; + bool bind_leader; + int status; +}; + +/* define for task embedded data */ +struct cc_tsk_data { + struct cc_command cc; + struct list_head node; + struct delayed_work dwork; +}; + +extern void cc_tsk_init(void *task); +extern void cc_tsk_disable(void *task); +extern void cc_tsk_free(void *task); + +/* ddr related control */ +extern bool cc_is_ddrfreq_related(const char *name); + +/* ddr lock api */ +extern void aop_lock_ddr_freq(int lv); + +extern unsigned long cc_get_expect_ddrfreq(void); +extern bool cc_ddr_boost_enabled(void); +#elif defined(CONFIG_HOUSTON) +static inline void cc_tsk_init(void *task) {}; +static inline void cc_tsk_disable(void *task) {}; +static inline void cc_tsk_free(void *task) {}; + +static bool cc_is_ddrfreq_related(const char *name) { return false; } +static unsigned long cc_get_expect_ddrfreq(void) { return 0; } +static bool cc_ddr_boost_enabled(void) { return false; } +#endif + +#ifdef CONFIG_CONTROL_CENTER +/* expected to public */ +enum { + CCDM_DEFAULT = 0, + CCDM_CLUS_0_CPUFREQ, + CCDM_CLUS_1_CPUFREQ, + CCDM_CLUS_2_CPUFREQ, + CCDM_FPS_BOOST, + CCDM_VOTING_DDRFREQ, + CCDM_FPS_BOOST_HINT, + + /* Turbo Rendering */ + CCDM_TB_CLUS_0_FREQ_BOOST, + CCDM_TB_CLUS_1_FREQ_BOOST, + CCDM_TB_CLUS_2_FREQ_BOOST, + CCDM_TB_FREQ_BOOST, + CCDM_TB_PLACE_BOOST, + + CCDM_TB_CPU_0_IDLE_BLOCK, + CCDM_TB_CPU_1_IDLE_BLOCK, + CCDM_TB_CPU_2_IDLE_BLOCK, + CCDM_TB_CPU_3_IDLE_BLOCK, + CCDM_TB_CPU_4_IDLE_BLOCK, + CCDM_TB_CPU_5_IDLE_BLOCK, + CCDM_TB_CPU_6_IDLE_BLOCK, + CCDM_TB_CPU_7_IDLE_BLOCK, + CCDM_TB_IDLE_BLOCK, + CCDM_TB_CCTL_BOOST, +}; + +/* status check */ +extern bool ccdm_enabled(void); + +/* update hint */ +extern void ccdm_update_hint_1( + int type, + long long arg1 +); +extern void ccdm_update_hint_2( + int type, + long long arg1, + long long arg2 +); +extern void ccdm_update_hint_3( + int type, + long long arg1, + long long arg2, + long long arg3 +); +extern void ccdm_update_hint_4( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4 +); + +/* get hint */ +extern long long ccdm_get_hint(int type); +extern int ccdm_any_hint(void); + +/* make decision */ +extern long long ccdm_decision_1( + int type, + long long arg1 +); +extern long long ccdm_decision_2( + int type, + long long arg1, + long long arg2 +); +extern long long ccdm_decision_3( + int type, + long long arg1, + long long arg2, + long long arg3 +); +extern long long ccdm_decision_4( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4 +); +extern long long ccdm_decision( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4 +); + +/* get current status */ +extern void ccdm_get_status(void *ptr); + +/* reset current status */ +extern void ccdm_reset(void); +extern unsigned int ccdm_get_min_util_threshold(void); + +#else +static inline int ccdm_enabled(void) { return 0; } +static inline void ccdm_update_hint_1( + int type, + long long arg1) +{} +static inline void ccdm_update_hint_2( + int type, + long long arg1, + long long arg2) +{} +static inline void ccdm_update_hint_3( + int type, + long long arg1, + long long arg2, + long long arg3) +{} +static inline void ccdm_update_hint_4( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{} + +static inline long long ccdm_get_hint(int type) { return 0; } +static inline int ccdm_any_hint(void) { return 0; } + +static inline long long ccdm_decision_1( + int type, + long long arg1) +{ return 0; } +static inline long long ccdm_decision_2( + int type, + long long arg1, + long long arg2) +{ return 0; } +static inline long long ccdm_decision_3( + int type, + long long arg1, + long long arg2, + long long arg3) +{ return 0; } +static inline long long ccdm_decision_4( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ return 0; } +static inline long long ccdm_decision( + int type, + long long arg1, + long long arg2, + long long arg3, + long long arg4) +{ return 0; } +static inline void ccdm_get_status(void *ptr) { return; } +static inline void ccdm_reset(void) {} +static inline unsigned int ccdm_get_min_util_threshold(void) { return 0; } +#endif + +#endif diff --git a/include/oneplus/defrag/defrag_helper.h b/include/oneplus/defrag/defrag_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..68129e3a4ec548d2454508ad2cb47a6b6f442062 --- /dev/null +++ b/include/oneplus/defrag/defrag_helper.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_DEFRAG_HELPER_H +#define _LINUX_DEFRAG_HELPER_H +#include +#include +#include +#include + + +#ifdef CONFIG_DEFRAG +#define ALLOC_UNMOVE 0x800 + +#define DEFRAG_FREE_SIZE global_zone_page_state(NR_FREE_DEFRAG_POOL) +#define defrag_zone_free_size(z) zone_page_state(z, NR_FREE_DEFRAG_POOL) +#define show_defrag_free(m) show_val_kb(m, "DefragPoolFree: ", DEFRAG_FREE_SIZE) +#define show_real_freemem(m, free) \ + show_val_kb(m, "RealMemFree: ", free - DEFRAG_FREE_SIZE) +#define IS_NOT_DEFRAG_POOL_EMPTY(area) \ + (!list_empty(&area->free_list[MIGRATE_UNMOVABLE_DEFRAG_POOL])) + +extern atomic64_t fp_order_usage[MAX_ORDER]; +extern atomic64_t fp_order_fail[MAX_ORDER]; + +#define ADD_ORDER_USAGE(o) atomic64_inc(&fp_order_usage[o]) +#define ADD_ORDER_FAIL(o) atomic64_inc(&fp_order_fail[o]) + +struct defrag_cb_set { + struct page *(*defrag_alloc_cb)(struct zone *zone, + unsigned long flags, int migratetype, int order); + long (*defrag_calc_cb)(struct zone *zone, int order, + int alloc_flag); + bool (*defrag_check_alloc_flag_cb)(unsigned int alloc_flags, int order); +}; + +#define defrag_migrate_to_alloc_flag(allocflag, migratetype) \ + do { \ + if (migratetype == MIGRATE_UNMOVABLE) \ + allocflag |= ALLOC_UNMOVE; \ + } while (0) + +extern struct page *defrag___rmqueue(struct zone *zone, unsigned int order, + int migratetype); +extern void defrag_unregister_cb_set(void); +extern void defrag_register_cb_set(struct defrag_cb_set *cbs); + +struct page *defrag_alloc(struct zone *zone, unsigned long flags, + int migratetype, int order); +long defrag_calc(struct zone *zone, int order, int alloc_flag); +bool defrag_check_alloc_flag(unsigned int alloc_flags, int order); + +#else /* !CONFIG_DEFRAG */ + +#define DEFRAG_FREE_SIZE 0 +#define defrag_zone_free_size(z) 0 +#define show_defrag_free(m) +#define show_real_freemem(m, free) +#define ADD_ORDER_USAGE(o) +#define ADD_ORDER_FAIL(o) +#define defrag_migrate_to_alloc_flag(allocflag, migratetype) +#define IS_NOT_DEFRAG_POOL_EMPTY(area) false + + +static __always_inline struct page *defrag_alloc(struct zone *zone, + unsigned long flags, + int migratetype, int order) +{ + return NULL; +} + +static __always_inline long defrag_calc(struct zone *zone, + int order, int alloc_flag) +{ + return 0; +} +static inline bool defrag_check_alloc_flag(unsigned int alloc_flags, int order) +{ + return false; +} + +#endif +#endif + diff --git a/include/oneplus/houston/houston_helper.h b/include/oneplus/houston/houston_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..d5c1beb7824ad9572e15bf23b49468a2f2499c6a --- /dev/null +++ b/include/oneplus/houston/houston_helper.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __INCLUDE_HOUSTON_HELPER__ +#define __INCLUDE_HOUSTON_HELPER__ + +#include +#include +#include + +enum ht_perf_id { + HT_PERF_COUNT_CPU_CYCLES = 0, + HT_PERF_COUNT_INSTRUCTIONS = 1, + HT_PERF_COUNT_CACHE_MISSES_L1 = 2, + HT_PERF_COUNT_CACHE_MISSES_L2 = 3, + HT_PERF_COUNT_CACHE_MISSES_L3 = 4, + HT_PERF_COUNT_MAX, +}; + +#ifdef CONFIG_HOUSTON +extern void ht_register_thermal_zone_device(struct thermal_zone_device *tz); +extern void ht_register_power_supply(struct power_supply *psy); +extern void ht_register_cpu_util(unsigned int cpu, unsigned int first_cpu, unsigned long *util, unsigned long *hi_util); +extern void ht_register_kgsl_pwrctrl(void *pwr); +extern void ht_update_hw_events(u64 inst, u64 miss, u64 cycle); +extern void ht_perf_notify(void); +extern void ht_perf_event_init(struct task_struct *tsk); +extern void ht_perf_event_release(struct task_struct *tsk); +extern void ht_collect_perf_data(struct work_struct *work); +extern void ht_rtg_init(struct task_struct *task); +extern void ht_rtg_list_add_tail(struct task_struct *task); +extern void ht_rtg_list_del(struct task_struct *task); +extern void ht_sched_switch_update(struct task_struct *prev, struct task_struct *next); +extern int ht_pcc_alwayson(void); +extern void tb_parse_req(unsigned int tb_pol, unsigned int tb_type, unsigned int args[4]); +extern void tb_parse_req_v2(unsigned int tb_pol, unsigned int tb_type, unsigned int *args, int size); +#else +static inline void ht_register_thermal_zone_device(struct thermal_zone_device *tz) {}; +static inline void ht_register_power_supply(struct power_supply *psy) {}; +static inline void ht_register_cpu_util(unsigned int cpu, + unsigned int first_cpu, unsigned long *util, unsigned long *hi_util) {}; +static inline void ht_register_kgsl_pwrctrl(void *pwr) {}; +static inline void ht_update_hw_events(u64 inst, u64 miss, u64 cycle) {}; +static inline void ht_perf_notify(void) {}; +static inline void ht_perf_event_init(struct task_struct *tsk) {}; +static inline void ht_perf_event_release(struct task_struct *tsk) {}; +static inline void ht_collect_perf_data(struct work_struct *work) {}; +static inline void ht_rtg_init(struct task_struct *task) {}; +static inline void ht_rtg_list_add_tail(struct task_struct *task) {}; +static inline void ht_rtg_list_del(struct task_struct *task) {}; +static inline void ht_sched_switch_update(struct task_struct *prev, struct task_struct *next) {}; +static inline int ht_pcc_alwayson(void) { return 0; }; +static inline void tb_parse_req(unsigned int tb_pol, unsigned int tb_type, unsigned int args[4]) {}; +static inline void tb_parse_req_v2(unsigned int tb_pol, unsigned int tb_type, unsigned int *args, int size) {}; +#endif +#endif // __INCLUDE_HOUSTON_HELPER__ diff --git a/include/oneplus/op_freezer/op_freezer.h b/include/oneplus/op_freezer/op_freezer.h new file mode 100644 index 0000000000000000000000000000000000000000..f72c1ec8e1d64dff8f61470d670c2f74e9916333 --- /dev/null +++ b/include/oneplus/op_freezer/op_freezer.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_OP_FREEZER_H +#define _LINUX_OP_FREEZER_H + +#include + +#define OP_FREEZER_NOERROR (0) +#define OP_FREEZER_ERROR (-1) +#define MIN_USERAPP_UID (10000) +#define INTERFACETOKEN_BUFF_SIZE (100) +#define PARCEL_OFFSET (16) // sync with the writeInterfaceToken + +/* op_freezer_message for communication with freezer native daemon + * type: async binder/sync binder/signal/pkg/loopback + * Only loop back type is duplex (native daemon <---> kernel) for handshake + * port: native daemon pid + * caller_pid: binder, caller -> unfreeze (target) UID + * target_uid: UID want to be unfrozen + * pkg_cmd: Add/Remove monitored UID + */ +struct op_freezer_message { + int type; + int port; // pid + + int caller_pid; // caller -> unfreeze UID + int target_uid; // unfreeze UID, pkg add/remove UID + + int pkg_cmd; //Add/remove monitored uid + + int code; + char rpc_name[INTERFACETOKEN_BUFF_SIZE]; +}; + +// op_freezer message type definition +enum message_type { + //kernel --> native daemon + ASYNC_BINDER, + SYNC_BINDER, + FROZEN_TRANS, + SIGNAL, + PKG, + + // kernel <--> native daemon + LOOP_BACK, + TYPE_MAX +}; + +// pkg cmd type +enum pkg_cmd { + ADD_ONE_UID, + DEL_ONE_UID, + DEL_ALL_UID, + + PKG_CMD_MAX +}; + +//Check if the thread group is frozen +static inline bool is_frozen_tg(struct task_struct *task) +{ + return (freezing(task->group_leader) || frozen(task->group_leader)); +} + +int op_freezer_report(enum message_type type, int caller_pid, int target_uid, const char *rpc_name, int code); +void op_freezer_network_cmd_parse(uid_t uid, enum pkg_cmd cmd); +void op_freezer_check_frozen_transcation(uid_t uid); +int op_freezer_netfilter_init(void); +void op_freezer_netfilter_deinit(void); + +#endif + diff --git a/include/oneplus/pccore/pccore_helper.h b/include/oneplus/pccore/pccore_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..589f12a824dc82320f41bb0e1805f3a627ec5d28 --- /dev/null +++ b/include/oneplus/pccore/pccore_helper.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __INCLUDE_PCCORE_HELPER__ +#define __INCLUDE_PCCORE_HELPER__ + +#ifdef CONFIG_PCCORE +extern unsigned int get_op_mode(void); +extern int cross_pd(int cpu, int prefer_idx, + int target_idx, bool ascending); +extern bool get_op_select_freq_enable(void); +extern unsigned int get_op_limit(void); +extern unsigned int get_op_level(void); +extern unsigned int get_op_fd_mode(void); +extern int find_prefer_pd(int cpu, + int target_idx, bool ascending, int lv_cnt); +#else +static inline unsigned int get_op_mode(void) { return 0; }; +static inline int cross_pd(int cpu, int prefer_idx, + int target_idx, bool ascending) { return target_idx; }; +static inline bool get_op_select_freq_enable(void) { return false; }; +static inline unsigned int get_op_limit(void) { return 0; }; +static inline unsigned int get_op_level(void) { return 0; }; +static inline unsigned int get_op_fd_mode(void) { return 0; }; +static inline int find_prefer_pd(int cpu, int target_idx, bool ascending, + int lv_cnt) { return target_idx; }; +#endif +#endif // __INCLUDE_PCCORE_HELPER__ diff --git a/include/oneplus/smartboost/smartboost_helper.h b/include/oneplus/smartboost/smartboost_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..212214c01c48f0c2071401f9a0e2bfb7d3d568f5 --- /dev/null +++ b/include/oneplus/smartboost/smartboost_helper.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __SMART_BOOST_HELPER_H__ +#define __SMART_BOOST_HELPER_H__ + +#include + +#ifdef CONFIG_SMART_BOOST +struct smb_cb_set { + bool (*smb_uid_lru_add_cb)(struct page *page); + + unsigned long (*smb_isolate_list_or_putbcak_cb) + (struct list_head *page_list, + struct lruvec *lruvec, + struct pglist_data *pgdat, int priority, + bool enough_list_reclaimed); + + bool (*smb_update_uid_lru_size_cb)(struct page *page, + struct lruvec *lruvec, enum lru_list lru); +}; + +extern unsigned long coretech_reclaim_pagelist(struct list_head *page_list, + struct vm_area_struct *vma, void *sc); +void smb_register_cb_set(struct smb_cb_set *set); +extern const struct file_operations proc_page_hot_count_operations; +extern unsigned long smb_invalidate_mapping_pages(struct address_space *mapping, + pgoff_t start, pgoff_t end); +extern bool smb_uid_lru_add(struct page *page); +extern unsigned long smb_isolate_list_or_putbcak(struct list_head *page_list, + struct lruvec *lruvec, struct pglist_data *pgdat, int priority, + bool enough_list_reclaimed); + +extern bool smb_update_uid_lru_size(struct page *page, + struct lruvec *lruvec, enum lru_list lru); + +#define UID_LRU_SIZE global_zone_page_state(NR_ZONE_UID_LRU) +#define PG_UIDLRU(page) PageUIDLRU(page) +#define ZONE_UID_LRU_SIZE(z) zone_page_state((z), NR_ZONE_UID_LRU) + +#define SMB_HOT_COUNT_INIT(condition, p) \ + do { \ + if (!condition) \ + p->hot_count = 0; \ + } while (0) + + +#else /* !CONFIG_SMART_BOOST */ +#define SMB_HOT_COUNT_INIT +#define UID_LRU_SIZE 0 +#define ZONE_UID_LRU_SIZE(z) 0 +#define PG_UIDLRU(page) 0 + +static __always_inline +unsigned long smb_invalidate_mapping_pages(struct address_space *mapping, + pgoff_t start, pgoff_t end) +{ + return invalidate_mapping_pages(mapping, start, end); +} +static __always_inline +bool smb_update_uid_lru_size(struct page *page, + struct lruvec *lruvec, enum lru_list lru) +{ + return false; +} +static __always_inline bool smb_uid_lru_add(struct page *page) +{ + return false; +} + +static __always_inline unsigned long +smb_isolate_list_or_putbcak(struct list_head *page_list, + struct lruvec *lruvec, struct pglist_data *pgdat, int priority, + bool enough_list_reclaimed) +{ + return 0; +} + +#endif +#endif diff --git a/include/oneplus/uxcore/opchain_helper.h b/include/oneplus/uxcore/opchain_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..ea73b5639cea1acf85cf56907eab4fb28861c47c --- /dev/null +++ b/include/oneplus/uxcore/opchain_helper.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_OPCHAIN_HELPER_H +#define _LINUX_OPCHAIN_HELPER_H +#include + +#ifdef CONFIG_OPCHAIN +extern struct opchain_cb uxcore_api; +extern void opc_binder_pass(size_t data_size, uint32_t *data, int send); +extern bool is_opc_task(struct task_struct *t, int type); +extern void opc_task_switch(bool enqueue, int cpu, struct task_struct *p, u64 clock); +extern int opc_get_claim_on_cpu(int cpu); +extern unsigned int opc_get_claims(void); +extern int opc_select_path(struct task_struct *cur, struct task_struct *t, int prev_cpu); +extern unsigned long opc_cpu_util(unsigned long util, int cpu, struct task_struct *t, int op_path); +extern bool opc_fps_check(int lvl); +extern void *opc_task_rq(void *t); +extern struct rq *opc_cpu_rq(int cpu); +extern unsigned int opc_task_load(struct task_struct *p); +extern int opc_cpu_active(int cpu); +extern int opc_cpu_isolated(int cpu); +bool opc_check_uxtop_cpu(int uxtop, int cpu); +bool opc_utask_slave(struct task_struct *t); +extern unsigned long __init opc_get_orig_capacity(int cpu); +extern void __exit opc_exit_module(void); +extern void opc_set_boost(unsigned int val); +#define UTASK_SLAVE(t) opc_utask_slave(t) + +#else +#define UTASK_SLAVE(t) 0 +static inline void opc_binder_pass(size_t data_size, uint32_t *data, int send) {} +static inline bool is_opc_task(struct task_struct *t, int type) { return 0; } +static inline void opc_task_switch(bool enqueue, int cpu, struct task_struct *p, u64 clock) {} +static inline int opc_get_claim_on_cpu(int cpu) { return 0; } +static inline unsigned int opc_get_claims(void) { return 0; } +static inline int opc_select_path(struct task_struct *cur, + struct task_struct *t, int prev_cpu) { return OP_PATH_NORMAL; } +static inline unsigned long opc_cpu_util(unsigned long util, + int cpu, struct task_struct *t, int op_path) { return util; } +static inline bool opc_fps_check(int lvl) { return false; } +static inline void opc_add_to_chain(struct task_struct *t) {} +static inline bool opc_check_uxtop_cpu(int uxtop, int cpu) { return true; } +static inline void opc_set_boost(unsigned int val) {}; +#endif +#endif + diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index c3686011193224e7ace9093de0d13b2cecf5996d..b32ffa0d563b449dfd2a205909e809394eed8a07 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -72,6 +72,8 @@ #define WRITE_SAME 0x41 #define UNMAP 0x42 #define READ_TOC 0x43 +/* @BSP, 2019/09/21, CD-ROM and VID customized */ +#define READ_CD 0xbe #define READ_HEADER 0x44 #define GET_EVENT_STATUS_NOTIFICATION 0x4a #define LOG_SELECT 0x4c diff --git a/include/slalib/op_sla.h b/include/slalib/op_sla.h new file mode 100644 index 0000000000000000000000000000000000000000..b50330a2b78ab29be03b9defdd391018c38b3447 --- /dev/null +++ b/include/slalib/op_sla.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "op_sla_help_lib.h" + +#define MAX_QUERY_LEN (sizeof(union nf_conntrack_proto) - 1) + +static int op_sla_debug; +static int op_sla_rtt_detect; +static int fw_set_game_mark; +static int op_sla_def_net; //WLAN->0 CELL->1 +static unsigned long last_notify_fw_network_switch; +static u32 op_sla_pid; +static struct sock *op_sla_sock; +static DEFINE_MUTEX(sla_netlink_mutex); + +static struct op_top_app_info top_app_list; diff --git a/include/slalib/op_sla_help_lib.h b/include/slalib/op_sla_help_lib.h new file mode 100644 index 0000000000000000000000000000000000000000..361461c69f17d08ee9f4647a741e08549b8ef26c --- /dev/null +++ b/include/slalib/op_sla_help_lib.h @@ -0,0 +1,261 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#define MARK_MASK 0x0fff +#define RETRAN_MASK 0xf000 +#define RTT_MASK 0xf000 +#define GAME_UNSPEC_MASK 0x8000 +#define FORCE_RESET_MASK 0xf0000 + +#define IP_HDR_LEN 20 +#define MIN(a, b) ((a < b) ? a : b) + +#define MAX_RTT_RECORD_NUM 4 +#define MAX_GAME_RTT 300 + +#define CELL_SCORE_BAD -100 + +#define INIT_APP_TYPE 0 +#define GAME_TYPE 1 +#define TOP_APP_TYPE 2 + +#define GAME_BASE 1 +#define GAME_NUM 64 +#define TOP_APP_BASE 100 +#define TOP_APP_NUM 64 + +#define WLAN_INDEX 0 +#define CELLULAR_INDEX 1 + +#define IFACE_NUM 2 +#define IFACE_LEN 16 + +#define SYN_RETRAN_RTT 350 +#define TCP_RETRAN_RTT 350 +#define UNREACHABLE_RTT 500 + +struct op_game_app_info { + int count; + int game_type[GAME_NUM]; + int uid[GAME_NUM]; + int rtt[GAME_NUM]; + int special_rx_error_count[GAME_NUM]; + int special_rx_count[GAME_NUM]; + int mark[GAME_NUM]; + int switch_time[GAME_NUM]; + int switch_count[GAME_NUM]; + int repeat_switch_time[GAME_NUM]; + int rtt_num[GAME_NUM]; +}; + +struct op_top_app_info { + int count; + int uid[TOP_APP_NUM]; +}; + +struct op_dev_info { + int if_up; + int syn_retran; + int dns_refuse; + int dns_mark_times; + int dns_query_counts; + unsigned long dns_first_query_time; + int tcp_mark_times; + int icmp_unreachable; + int env_dirty_count; + int rtt_index; + int sum_rtt; + int avg_rtt; + int cur_score; + int netlink_valid; + char dev_name[IFACE_LEN]; +}; + +/* NLMSG_MIN_TYPE is 0x10,so we start at 0x11 */ +enum { + SLA_NOTIFY_WIFI_SCORE = 0x11, + SLA_NOTIFY_PID = 0x12, + SLA_ENABLE = 0x13, + SLA_DISABLE = 0x14, + SLA_WIFI_UP = 0x15, + SLA_CELLULAR_UP = 0x16, + SLA_WIFI_DOWN = 0x17, + SLA_CELLULAR_DOWN = 0x18, + SLA_SWITCH_APP_NETWORK = 0x19, + SLA_NOTIFY_GAME_UID = 0x1A, + SLA_NOTIFY_GAME_RTT = 0x1B, + SLA_NOTIFY_TOP_APP = 0x1C, + SLA_ENABLED = 0x1D, + SLA_DISABLED = 0x1E, + SLA_ENABLE_GAME_RTT = 0x1F, + SLA_DISABLE_GAME_RTT = 0x20, + SLA_NOTIFY_GAME_SWITCH_STATE = 0x21, + SLA_NOTIFY_SPEED_RTT = 0x22, + SLA_SWITCH_GAME_NETWORK = 0x23, + SLA_NOTIFY_SCREEN_STATE = 0x24, + SLA_NOTIFY_CELL_SCORE = 0x25, + SLA_SEND_GAME_APP_STATISTIC = 0x26, + SLA_GET_SYN_RETRAN_INFO = 0x27, + SLA_GET_SPEED_UP_APP = 0x28, + SLA_SET_DEBUG = 0x29, + SLA_NOTIFY_DEFAULT_NETWORK = 0x2A, + SLA_NOTIFY_PARAMS = 0x2B, + SLA_NOTIFY_GAME_STATE = 0x2C, + SLA_ENABLE_LINK_TURBO = 0x2D, + SLA_SET_GAME_MARK = 0x2E, + SLA_SET_NETWORK_VALID = 0x2F, + SLA_NOTIFY_APP_SWITCH_STATE = 0x30, + SLA_NOTIFY_SWITCH_APP_NETWORK = 0x31, +}; + +enum { + SLA_SKB_ACCEPT, + SLA_SKB_CONTINUE, + SLA_SKB_MARKED, + SLA_SKB_REMARK, + SLA_SKB_DROP, +}; + + +enum { + WLAN_MARK_BIT = 8, //WLAN mark value,mask 0x0fff + WLAN_MARK = (1 << WLAN_MARK_BIT), + + CELLULAR_MARK_BIT = 9, //cellular mark value mask 0x0fff + CELLULAR_MARK = (1 << CELLULAR_MARK_BIT), + + RETRAN_BIT = 12, //first retran mark value, mask 0xf000 + RETRAN_MARK = (1 << RETRAN_BIT), + + RETRAN_SECOND_BIT = 13, //second retran mark value, mask 0xf000 + RETRAN_SECOND_MARK = (1 << RETRAN_SECOND_BIT), + + RTT_MARK_BIT = 14, //one ct only statistic once rtt,mask 0xf000 + RTT_MARK = (1 << RTT_MARK_BIT), + + GAME_UNSPEC_MARK_BIT = 15, //mark game skb when game not start + GAME_UNSPEC_MARK = (1 << GAME_UNSPEC_MARK_BIT), + + FORCE_RESET_MARK_BIT = 16, // FORCE reset value, mask 0xf0000 + FORCE_RESET_MARK = (1 << FORCE_RESET_MARK_BIT), +}; + +enum { + GAME_RTT_DETECT_INITIAL = 0, + GAME_SKB_COUNT_ENOUGH, + GAME_RTT_DETECTED_STREAM, +}; + +#ifdef CONFIG_SLA +#ifndef CONFIG_SLA_ALGO +struct op_game_app_info op_sla_game_app_list; +struct op_dev_info op_sla_info[IFACE_NUM]; +int rtt_record_num; +int rtt_queue[MAX_RTT_RECORD_NUM]; +int rtt_rear; +int game_rtt_wan_detect_flag; +int game_data[5]; +int op_sla_enable; +int game_start_state; +int sla_game_switch_enable; +int sla_app_switch_enable; +int sla_screen_on; +#else +extern struct op_game_app_info op_sla_game_app_list; +extern struct op_dev_info op_sla_info[IFACE_NUM]; +extern int rtt_record_num; +extern int rtt_queue[MAX_RTT_RECORD_NUM]; +extern int rtt_rear; +extern int game_rtt_wan_detect_flag; +extern int game_data[5]; +extern int op_sla_enable; +extern int game_start_state; +extern int sla_game_switch_enable; +extern int sla_app_switch_enable; +extern int sla_screen_on; + +int is_ping_pong(int game_type, int time_now); +void op_rx_interval_error_estimator(int game_type, + int time_error); +void op_game_rtt_estimator(int *game_data); +int op_get_ct_cell_quality(int game_type); +int switch_to_cell(int cell_quality_good, + int game_rtt, + int gamelostcount, + int game_switch_interval, + int game_type); +int switch_to_wifi(int wlan_bad, + int game_rtt, + int gamelostcount, + int game_switch_interval, + int game_type); +void reset_sla_game_app_rx_error(int game_type); +void reset_sla_game_app_rtt(int game_type); +void record_sla_game_cell_state(int game_type, + int game_switch_interval, + int time_now); +void record_sla_game_wifi_state(int game_type, + int game_switch_interval, + int time_now); +int get_lost_count_threshold(int game_type); +int get_game_interval(int game_type, int game_interval); +int check_wan_detect_flag(int game_type); +int is_detect_game_lost(int game_lost_count, + int game_lost_count_threshold, + int game_time_interval); +int is_support_detect_game_tx(int game_type, + int special_rx_pkt_last_timestamp); +void get_rx_pkt_threshold(int game_type, + int time_now, + int special_rx_pkt_last_timestamp, + int *rtt_callback); +int data_stall_detect(int lastspecialrxtiming, + int specialrxthreshold, + int datastalltimer, + int datastallthreshold); +int get_game_tx_category(int game_type, int skb_len); +int get_game_rx_category(int game_type, unsigned int skb_len); +int drop_pkt_check(int game_type, int skb_len); +int is_support_rtt_wan_detect(int game_type); +int get_rx_interval_error(int game_category, + int time_now, + int rx_pkt_timestamp); +int is_need_check_game_rtt(int game_detect_status, + int game_timestamp, + int skb_len); +int get_game_rtt(int time_now, int game_timestamp, int game_type); +int is_skip_rx_rtt(int game_type, int game_time_interval); +int is_support_game_mark(int game_type); +int need_enable_sla(int cell_quality_good); +int need_enable_sla_for_wlan_score(void); +void set_sla_game_parameter(int num); +void op_init_game_online_info(int num, int time_now); +int op_get_wlan_quality(void); +void update_wlan_score(void); +int mark_retransmits_syn_skb(unsigned int sla_mark); +int mark_force_reset_skb(unsigned int sla_mark); +int find_iface_index_by_mark(unsigned int mark); +int find_tcp_iface_index_by_mark(unsigned int mark); +int update_sla_tcp_info(unsigned int tcp_rtt, unsigned int total_retrans, unsigned int mark); +int is_tcp_unreachable(int ifaceindex, unsigned int tcp_rtt, unsigned int total_retrans); +int is_syn_need_mark(unsigned int ctmark); +unsigned int config_syn_retran(int index, unsigned int ctmark); +int set_syn_skb_result(void); +int set_syn_ack_skb_result(void); +int is_retran_second_mark(unsigned int sla_mark); +unsigned int config_syn_retan(unsigned int sla_mark); +unsigned short get_dns_response(unsigned short response); +unsigned short get_reply_code(unsigned short response); +void update_sla_dns_info(unsigned short rcode, unsigned int dst_addr, + unsigned int wifiip, unsigned int cellip); +void update_dns_mark(unsigned int *dns_callback, unsigned long time_now); +void update_tcp_mark(unsigned int *tcp_callback, unsigned long time_now); +void update_sla_icmp_info(unsigned int dst_addr, unsigned int wifiip, unsigned int cellip); +void reset_sla_info(void); +void reset_sla_mobile_info(void); +void calc_rtt_by_dev_index(int index, int tmp_rtt); +void calc_network_rtt(void); +void record_dns_query_info(int ifaceindex, unsigned long time_now); +int op_get_cur_cell_quality(void); +int try_to_fast_reset(int app_type); +#endif +#endif diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index a5aeb9770c0d061103d278479c26ed88daf39b8c..cba1de41bced60c4d267a8ef6eb906af04e9db65 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -152,4 +152,5 @@ extern void icnss_block_shutdown(bool status); extern bool icnss_is_pdr(void); extern int icnss_idle_restart(struct device *dev); extern int icnss_idle_shutdown(struct device *dev); +extern void cnss_set_fw_version(u32 version, u32 ext); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/soc/qcom/msm-poweroff.h b/include/soc/qcom/msm-poweroff.h new file mode 100644 index 0000000000000000000000000000000000000000..809849462c58114c2406fd6c4a3c42f1cf45d166 --- /dev/null +++ b/include/soc/qcom/msm-poweroff.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _MSM_POWEROFF_H +#define _MSM_POWEROFF_H + +extern void oem_force_minidump_mode(void); + +#endif diff --git a/include/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h index 989112764cb3698f68a50c34a4cc2893a953f059..71e90e1ea025be976fa8666c00dcaa5b6a3f39ae 100644 --- a/include/soc/qcom/subsystem_restart.h +++ b/include/soc/qcom/subsystem_restart.h @@ -146,6 +146,7 @@ struct notif_data { extern int subsys_get_restart_level(struct subsys_device *dev); extern int subsystem_restart_dev(struct subsys_device *dev); +extern void subsys_store_crash_reason(struct subsys_device *dev, char *reason); extern int subsystem_restart(const char *name); extern int subsystem_crashed(const char *name); @@ -180,6 +181,9 @@ static inline int subsystem_restart_dev(struct subsys_device *dev) return 0; } +static inline void subsys_store_crash_reason(struct subsys_device *dev, + char *reason) { } + static inline int subsystem_restart(const char *name) { return 0; diff --git a/include/trace/events/block.h b/include/trace/events/block.h index 81b43f5bdf237d3637880224972cc96a25f986e8..fe2bd0157282df8968638444b1144dc611a0cbaf 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -145,6 +145,67 @@ TRACE_EVENT(block_rq_complete, __entry->nr_sector, __entry->error) ); +/* block io time trace to collect a request information */ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/* + * block_time - trace block io latency during send request to complete request + * @q: queue containing the block operation request + * @rq: block operations request + * @delta_us: block io latency + * @nr_bytes: number of completed bytes + * + * The block_time tracepoint event can collect each request information. + * it include uid,sector,nr_sector,bytes,errors,delta_us,flash_io_latency,tag,now time, + * rwbs,cmd and so on. + */ + +TRACE_EVENT(block_time, + + TP_PROTO(struct request_queue *q, struct request *rq, + u64 delta_us, unsigned int nr_bytes), + + TP_ARGS(q, rq, delta_us, nr_bytes), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(u32, current_uid) + __field(sector_t, sector) + __field(unsigned int, nr_sector) + __field(unsigned int, bytes) + __field(u64, delta_us) + __field(u64, flash_io_latency) + __field(int, tag) + __field(u64, now) + __array(char, rwbs, RWBS_LEN) + __dynamic_array(char, cmd, 1) + ), + + TP_fast_assign( + __entry->dev = rq->rq_disk ? disk_devt(rq->rq_disk) : 0; + __entry->current_uid = from_kuid_munged(current_user_ns(), current_uid()); + __entry->sector = blk_rq_trace_sector(rq); + __entry->nr_sector = blk_rq_trace_nr_sectors(rq); + __entry->bytes = blk_rq_bytes(rq); + __entry->delta_us = delta_us; + __entry->flash_io_latency = rq->flash_io_latency; + __entry->tag = rq->tag; + __entry->now = ktime_to_us(ktime_get()); + + blk_fill_rwbs(__entry->rwbs, rq->cmd_flags, blk_rq_bytes(rq)); + __get_str(cmd)[0] = '\0'; + ), + + TP_printk("%d,%d,%d,%llu,%llu,%d,%llu,%s,(%s),%llu,%u,%u", + MAJOR(__entry->dev), MINOR(__entry->dev), + __entry->current_uid, __entry->flash_io_latency, + __entry->delta_us, __entry->tag, + __entry->now, __entry->rwbs, __get_str(cmd), + (unsigned long long)__entry->sector, + __entry->nr_sector, __entry->bytes) +); + +#endif + DECLARE_EVENT_CLASS(block_rq, TP_PROTO(struct request_queue *q, struct request *rq), diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h index a1675d43777e8feb9165401af1b7c4a26d76f306..752c4520df052ccf9b2dfbac2e4d215941857e1d 100644 --- a/include/trace/events/mmflags.h +++ b/include/trace/events/mmflags.h @@ -79,6 +79,12 @@ #define IF_HAVE_PG_IDLE(flag,string) #endif +#ifdef CONFIG_SMART_BOOST +#define IF_HAVE_PG_UIDRU(flag, string) ,{1UL << flag, string} +#else +#define IF_HAVE_PG_UIDRU(flag, string) +#endif + #define __def_pageflag_names \ {1UL << PG_locked, "locked" }, \ {1UL << PG_waiters, "waiters" }, \ @@ -105,7 +111,9 @@ IF_HAVE_PG_MLOCK(PG_mlocked, "mlocked" ) \ IF_HAVE_PG_UNCACHED(PG_uncached, "uncached" ) \ IF_HAVE_PG_HWPOISON(PG_hwpoison, "hwpoison" ) \ IF_HAVE_PG_IDLE(PG_young, "young" ) \ -IF_HAVE_PG_IDLE(PG_idle, "idle" ) +IF_HAVE_PG_IDLE(PG_idle, "idle" ) \ +/* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ \ +IF_HAVE_PG_UIDRU(PG_uidlru, "uidlru") #define show_page_flags(flags) \ (flags) ? __print_flags(flags, "|", \ diff --git a/include/trace/events/power.h b/include/trace/events/power.h index 53a3fcd4ea0803cf9183e4d13227a87fc8d9c0b4..bbbc95adb42c46a6825394b90607bec8c8816fef 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -172,6 +172,76 @@ TRACE_EVENT(cpu_frequency_limits, (unsigned long)__entry->max_freq, (unsigned long)__entry->cpu_id) ); +// 2020/03/27, add for pccore CONFIG_PCCORE +TRACE_EVENT(find_freq, + + TP_PROTO(unsigned int target_idx, unsigned int target_freq, unsigned int final_idx, + unsigned int final_freq, int cpu, bool op_enable, int dp_level_mode, int dp_level), + + TP_ARGS(target_idx, target_freq, final_idx, final_freq, cpu, op_enable, dp_level_mode, dp_level), + + TP_STRUCT__entry( + __field(u32, target_freq) + __field(u32, target_idx) + __field(u32, final_idx) + __field(u32, final_freq) + __field(int, cpu) + __field(bool, op_enable) + __field(int, dp_level_mode) + __field(int, dp_level) + ), + + TP_fast_assign( + __entry->target_idx = target_idx; + __entry->target_freq = target_freq; + __entry->final_idx = final_idx; + __entry->final_freq = final_freq; + __entry->cpu = cpu; + __entry->op_enable = op_enable; + __entry->dp_level_mode = dp_level_mode; + __entry->dp_level = dp_level; + ), + + TP_printk( + "target[%lu]=%lu final[%lu]=%lu cpu=%d op_enable=%d dp_level_mod=%d dp_level=%d", + (unsigned long)__entry->target_idx, + (unsigned long)__entry->target_freq, + (unsigned long)__entry->final_idx, + (unsigned long)__entry->final_freq, + (unsigned long)__entry->cpu, + __entry->op_enable, __entry->dp_level_mode, __entry->dp_level) +); + +// 2020/03/27, add for pccore CONFIG_PCCORE +TRACE_EVENT(cpu_frequency_select, + + TP_PROTO(unsigned int target_freq, unsigned int final_freq, + unsigned int index, int cpu, int num), + + TP_ARGS(target_freq, final_freq, index, cpu, num), + + TP_STRUCT__entry( + __field(u32, target_freq) + __field(u32, final_freq) + __field(u32, index) + __field(int, cpu) + __field(int, num) + ), + + TP_fast_assign( + __entry->target_freq = target_freq; + __entry->final_freq = final_freq; + __entry->index = index; + __entry->cpu = cpu; + __entry->num = num; + ), + + TP_printk("target=%lu final=%lu index=%lu cpu=%d num=%d", + (unsigned long)__entry->target_freq, + (unsigned long)__entry->final_freq, + (unsigned long)__entry->index, + __entry->cpu, __entry->num) +); TRACE_EVENT(cpu_frequency_switch_start, @@ -604,6 +674,33 @@ TRACE_EVENT(sugov_util_update, __entry->pl, __entry->rtgb, __entry->flags) ); +#ifdef CONFIG_CONTROL_CENTER +TRACE_EVENT(sugov_next_freq, + TP_PROTO(unsigned int cpu, unsigned long util, unsigned long max, + unsigned int freq, unsigned int req_freq), + TP_ARGS(cpu, util, max, freq, req_freq), + TP_STRUCT__entry( + __field(unsigned int, cpu) + __field(unsigned long, util) + __field(unsigned long, max) + __field(unsigned int, freq) + __field(unsigned int, req_freq) + ), + TP_fast_assign( + __entry->cpu = cpu; + __entry->util = util; + __entry->max = max; + __entry->freq = freq; + __entry->req_freq = req_freq; + ), + TP_printk("cpu=%u util=%lu max=%lu freq=%u req_freq=%u", + __entry->cpu, + __entry->util, + __entry->max, + __entry->freq, + __entry->req_freq) +); +#else TRACE_EVENT(sugov_next_freq, TP_PROTO(unsigned int cpu, unsigned long util, unsigned long max, unsigned int freq), @@ -626,6 +723,7 @@ TRACE_EVENT(sugov_next_freq, __entry->max, __entry->freq) ); +#endif TRACE_EVENT(bw_hwmon_meas, diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index ae6480afb01ce8854e385c9751917b442bc44893..18b2a4bf4a79e414543bc88829ae89557f0ecaa0 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -115,6 +115,10 @@ DECLARE_EVENT_CLASS(sched_wakeup_template, __field( int, prio ) __field( int, success ) __field( int, target_cpu ) +#ifdef CONFIG_RATP + __field(unsigned long, cpus_suggested) +#endif + ), TP_fast_assign( @@ -123,11 +127,20 @@ DECLARE_EVENT_CLASS(sched_wakeup_template, __entry->prio = p->prio; /* XXX SCHED_DEADLINE */ __entry->success = 1; /* rudiment, kill when possible */ __entry->target_cpu = task_cpu(p); +#ifdef CONFIG_RATP + __entry->cpus_suggested = cpumask_bits(&p->cpus_suggested)[0]; +#endif ), +#ifdef CONFIG_RATP + TP_printk("comm=%s pid=%d prio=%d target_cpu=%03d prefer=%x", + __entry->comm, __entry->pid, __entry->prio, + __entry->target_cpu, __entry->cpus_suggested) +#else TP_printk("comm=%s pid=%d prio=%d target_cpu=%03d", __entry->comm, __entry->pid, __entry->prio, __entry->target_cpu) +#endif ); /* @@ -990,7 +1003,6 @@ TRACE_EVENT(sched_load_avg_cpu, __entry->util_avg_pelt, __entry->util_avg_walt) ); - /* * Tracepoint for sched_entity load tracking: */ @@ -1174,6 +1186,78 @@ TRACE_EVENT(sched_cpu_util, __entry->nr_rtg_high_prio_tasks) ); +#ifdef CONFIG_RATP + +TRACE_EVENT(sched_tune_group, + + TP_PROTO(struct task_struct *tsk, int idx, bool ret), + + TP_ARGS(tsk, idx, ret), + + TP_STRUCT__entry( + __array(char, comm, TASK_COMM_LEN) + __field(pid_t, pid) + __field(int, idx) + __field(bool, ret) + ), + + TP_fast_assign( + memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); + __entry->pid = tsk->pid; + __entry->idx = idx; + __entry->ret = ret; + ), + + TP_printk("pid=%d comm=%s idx=%d ret=%d", + __entry->pid, __entry->comm, __entry->idx, __entry->ret) +); + +TRACE_EVENT(sched_cpu_sel, + + TP_PROTO(struct task_struct *p, int task_boost, bool task_skip_min, bool boosted, int boost_pol, + bool fit_small, bool fit_mid, bool fit_max, int start_cpu, bool ratp), + + TP_ARGS(p, task_boost, task_skip_min, boosted, boost_pol, fit_small, fit_mid, fit_max, start_cpu, ratp), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(unsigned long, task_util) + __field(int, task_boost) + __field(bool, task_skip_min) + __field(bool, boosted) + __field(int, boost_pol) + __field(bool, fit_small) + __field(bool, fit_mid) + __field(bool, fit_max) + __field(int, start_cpu) + __field(bool, ratp) + ), + + TP_fast_assign( + __entry->pid = p ? p->pid : -1; + memcpy(__entry->comm, p ? p->comm:"NULL", TASK_COMM_LEN); + __entry->task_util = task_util(p); + __entry->task_boost = task_boost; + __entry->task_skip_min = task_skip_min; + __entry->boosted = boosted; + __entry->boost_pol = boost_pol; + __entry->fit_small = fit_small; + __entry->fit_mid = fit_mid; + __entry->fit_max = fit_max; + __entry->start_cpu = start_cpu; + __entry->ratp = ratp; + ), + + TP_printk("pid=%d comm=%s task_util=%lu task_boost=%d skip_min=%d boosted=%d boost_pol=%d fit_small=%d fit_mid=%d fit_max=%d start_cpu=%d ratp=%d", + __entry->pid, __entry->comm, __entry->task_util, __entry->task_boost, + __entry->task_skip_min, __entry->boosted, + __entry->boost_pol, __entry->fit_small, + __entry->fit_mid, __entry->fit_max, __entry->start_cpu, __entry->ratp) +) + +#endif + TRACE_EVENT(sched_compute_energy, TP_PROTO(struct task_struct *p, int eval_cpu, @@ -1215,6 +1299,72 @@ TRACE_EVENT(sched_compute_energy, __entry->best_energy_cpu, __entry->best_energy) ) +#ifdef CONFIG_OPCHAIN +// curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +TRACE_EVENT(sched_task_util, + + TP_PROTO(struct task_struct *p, unsigned long candidates, + int best_energy_cpu, bool sync, bool need_idle, int fastpath, + bool placement_boost, u64 start_t, + bool stune_boosted, bool is_rtg, bool rtg_skip_min, + bool is_uxtop), + + TP_ARGS(p, candidates, best_energy_cpu, sync, need_idle, fastpath, + placement_boost, start_t, stune_boosted, is_rtg, rtg_skip_min, + is_uxtop), + + TP_STRUCT__entry( + __field(int, pid) + __array(char, comm, TASK_COMM_LEN) + __field(unsigned long, util) + __field(unsigned long, candidates) + __field(int, prev_cpu) + __field(int, best_energy_cpu) + __field(bool, sync) + __field(bool, need_idle) + __field(int, fastpath) + __field(int, placement_boost) + __field(int, rtg_cpu) + __field(u64, latency) + __field(bool, stune_boosted) + __field(bool, is_rtg) + __field(bool, rtg_skip_min) + __field(u32, unfilter) + __field(bool, is_uxtop) + ), + + TP_fast_assign( + __entry->pid = p->pid; + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->util = task_util(p); + __entry->prev_cpu = task_cpu(p); + __entry->candidates = candidates; + __entry->best_energy_cpu = best_energy_cpu; + __entry->sync = sync; + __entry->need_idle = need_idle; + __entry->fastpath = fastpath; + __entry->placement_boost = placement_boost; + __entry->latency = (sched_clock() - start_t); + __entry->stune_boosted = stune_boosted; + __entry->is_rtg = is_rtg; + __entry->rtg_skip_min = rtg_skip_min; +#ifdef CONFIG_SCHED_WALT + __entry->unfilter = p->unfilter; +#else + __entry->unfilter = 0; +#endif + __entry->is_uxtop = is_uxtop; + ), + + TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d candidates=%#lx best_energy_cpu=%d sync=%d need_idle=%d fastpath=%d placement_boost=%d latency=%llu stune_boosted=%d is_rtg=%d rtg_skip_min=%d unfilter=%d is_uxtop=%d", + __entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, + __entry->candidates, __entry->best_energy_cpu, __entry->sync, + __entry->need_idle, __entry->fastpath, __entry->placement_boost, + __entry->latency, __entry->stune_boosted, + __entry->is_rtg, __entry->rtg_skip_min, + __entry->unfilter, __entry->is_uxtop) +) +#else TRACE_EVENT(sched_task_util, TP_PROTO(struct task_struct *p, unsigned long candidates, @@ -1283,6 +1433,7 @@ TRACE_EVENT(sched_task_util, __entry->is_rtg, __entry->rtg_skip_min, __entry->start_cpu, __entry->unfilter, __entry->cpus_allowed, __entry->low_latency) ); +#endif /* * Tracepoint for find_best_target diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 24af4edfc98c2d822df109e70f09c04980e1d155..9abec63a0f162f3847fac48f87c8e8c608aad568 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -275,6 +275,8 @@ struct fuse_file_lock { #define FUSE_POSIX_ACL (1 << 20) #define FUSE_ABORT_ERROR (1 << 21) +#define FUSE_SHORTCIRCUIT (1 << 30) + /** * CUSE INIT request/reply flags * diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index 5fa3fcc1012873eb10811d276b4584d4926c6224..68afd8e4743db3479138c2c167dba0e863b24a79 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -30,7 +30,14 @@ #define NETLINK_CRYPTO 21 /* Crypto layer */ #define NETLINK_SMC 22 /* SMC monitoring */ #define NETLINK_SOCKEV 23 /* Socket Administrative Events */ +#ifdef CONFIG_OP_FREEZER +// add for op freeze manager +#define NETLINK_OP_FREEZER 28 /* Socket for freezing solution*/ +#endif #define NETLINK_INET_DIAG NETLINK_SOCK_DIAG +/* WIFI MODIFICATION */ +#define NETLINK_OP_SLA 29 /* SLA NETLINK SOCK */ +/* WIFI MODIFICATION */ #define MAX_LINKS 32 diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h index a4c11c12fdf1e43159d02bdbb2583eec93c5db46..6979396f655bc1b8f8b79a994bdde0d6d27016d1 100644 --- a/include/uapi/scsi/ufs/ioctl.h +++ b/include/uapi/scsi/ufs/ioctl.h @@ -10,6 +10,10 @@ */ #define UFS_IOCTL_QUERY 0x5388 +#if defined(CONFIG_UFSFEATURE) +#define UFSFEATURE_QUERY_OPCODE 0x5500 +#endif + /** * struct ufs_ioctl_query_data - used to transfer data to and from user via * ioctl diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h index 22a0a7e81860a0d301a5931236296265c9845f78..c46a5e05ec10155db5475bd5bce2f78e25c30e8d 100644 --- a/include/uapi/scsi/ufs/ufs.h +++ b/include/uapi/scsi/ufs/ufs.h @@ -17,6 +17,11 @@ enum flag_idn { QUERY_FLAG_IDN_BUSY_RTC = 0x09, QUERY_FLAG_IDN_RESERVED3 = 0x0A, QUERY_FLAG_IDN_PERMANENTLY_DISABLE_FW_UPDATE = 0x0B, +#if defined(CONFIG_UFSTW) + QUERY_FLAG_IDN_TW_EN = 0x0E, + QUERY_FLAG_IDN_TW_BUF_FLUSH_EN = 0x0F, + QUERY_FLAG_IDN_TW_FLUSH_DURING_HIBERN = 0x10, +#endif QUERY_FLAG_IDN_WB_EN = 0x0E, QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN = 0x0F, QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8 = 0x10, @@ -48,6 +53,14 @@ enum attr_idn { QUERY_ATTR_IDN_PSA_STATE = 0x15, QUERY_ATTR_IDN_PSA_DATA_SIZE = 0x16, QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17, +#if defined(CONFIG_UFSTW) + QUERY_ATTR_IDN_TW_FLUSH_STATUS = 0x1C, + QUERY_ATTR_IDN_TW_BUF_SIZE = 0x1D, + QUERY_ATTR_IDN_TW_BUF_LIFETIME_EST = 0x1E, +#endif +#if defined(CONFIG_UFSFEATURE) + QUERY_ATTR_IDN_SUP_VENDOR_OPTIONS = 0xFF, +#endif QUERY_ATTR_IDN_WB_FLUSH_STATUS = 0x1C, QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE = 0x1D, QUERY_ATTR_IDN_WB_BUFF_LIFE_TIME_EST = 0x1E, diff --git a/init/init_task.c b/init/init_task.c index 53e6e27ea8b51a687ac11c2446b2d8a1a7031982..f433d7dbcd8ee0e312f6b3be9aff86d90b93048d 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -119,6 +119,9 @@ struct task_struct init_task .journal_info = NULL, INIT_CPU_TIMERS(init_task) .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(init_task.pi_lock), +#ifdef CONFIG_UXCHAIN + .uxchain_lock = __RAW_SPIN_LOCK_UNLOCKED(init_task.uxchain_lock), +#endif .timer_slack_ns = 50000, /* 50 usec default slack */ .thread_pid = &init_struct_pid, .thread_group = LIST_HEAD_INIT(init_task.thread_group), @@ -181,6 +184,9 @@ struct task_struct init_task #ifdef CONFIG_SECURITY .security = NULL, #endif +#ifdef CONFIG_RATP + .cpus_suggested = CPU_MASK_ALL, +#endif }; EXPORT_SYMBOL(init_task); diff --git a/init/main.c b/init/main.c index 7942ad3cdb428f0527a18ae37f4aaa1cf982afc9..c218b5a355eab669c8db41684a5b43e47c7559c9 100644 --- a/init/main.c +++ b/init/main.c @@ -213,6 +213,7 @@ EXPORT_SYMBOL(loops_per_jiffy); static int __init debug_kernel(char *str) { console_loglevel = CONSOLE_LOGLEVEL_DEBUG; + default_message_loglevel = CONSOLE_LOGLEVEL_DEBUG; return 0; } diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 0a39b26d6e4d2b9aa18b0769c5a3297db07d3c66..1883aaec5a5a7b06b91d9a1b51386aa6d93190eb 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -539,7 +539,9 @@ static ssize_t __cgroup1_procs_write(struct kernfs_open_file *of, */ cred = current_cred(); tcred = get_task_cred(task); + /* huruihuan add for kill task in D status */ if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) && + !uid_eq(cred->euid, GLOBAL_SYSTEM_UID) && !uid_eq(cred->euid, tcred->uid) && !uid_eq(cred->euid, tcred->suid) && !ns_capable(tcred->user_ns, CAP_SYS_NICE)) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 80b2110f402656cdfc3e75307ade12d19f987fcc..2e4404175e2fdd5df662e143172dd50845e0cbe5 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -84,6 +84,13 @@ EXPORT_SYMBOL_GPL(cgroup_mutex); EXPORT_SYMBOL_GPL(css_set_lock); #endif +#ifdef CONFIG_RATP +#define STUNE_TYPE_MAX 5 +int stune_map[STUNE_TYPE_MAX] = {0, 0, 0, 0, 0}; +const char *stune_cgroup_type[STUNE_TYPE_MAX] = {"foreground", "background", + "top-app", "rt", "audio-app"}; +#endif + DEFINE_SPINLOCK(trace_cgroup_path_lock); char trace_cgroup_path[TRACE_CGROUP_PATH_LEN]; @@ -4946,6 +4953,10 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, struct cgroup_subsys_state *parent_css = cgroup_css(parent, ss); struct cgroup_subsys_state *css; int err; +#ifdef CONFIG_RATP + const char *tune_cgroup; + int i; +#endif lockdep_assert_held(&cgroup_mutex); @@ -4983,6 +4994,21 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, ss->warned_broken_hierarchy = true; } +#ifdef CONFIG_RATP + /* establish the groups of schedtune mapping table*/ + if (css->cgroup && css->cgroup->kn) { + tune_cgroup = css->cgroup->kn->name; + if (!strncmp(ss->name, "schedtune", strlen("schedtune"))) { + for (i = 0; i < STUNE_TYPE_MAX; ++i) { + if (!strncmp(tune_cgroup, stune_cgroup_type[i], strlen(stune_cgroup_type[i]))) { + stune_map[i] = i+1; + break; + } + } + } + } +#endif + return css; err_list_del: diff --git a/kernel/cgroup/freezer.c b/kernel/cgroup/freezer.c index 08236798d17315622d73540d62a89dcbafdc5c77..2736f5a747801cd0446bf0970df4900be95d02cb 100644 --- a/kernel/cgroup/freezer.c +++ b/kernel/cgroup/freezer.c @@ -22,7 +22,9 @@ #include #include #include - +/* huruihuan add for kill task in D status */ +#include +#include /* * A cgroup is freezing if any FREEZING flags are set. FREEZING_SELF is * set if "FROZEN" is written to freezer.state cgroupfs file, and cleared @@ -43,6 +45,8 @@ enum freezer_state_flags { struct freezer { struct cgroup_subsys_state css; unsigned int state; + /* huruihuan add for kill task in D status */ + unsigned int oem_freeze_flag; }; static DEFINE_MUTEX(freezer_mutex); @@ -322,7 +326,8 @@ static void freeze_cgroup(struct freezer *freezer) css_task_iter_start(&freezer->css, 0, &it); while ((task = css_task_iter_next(&it))) - freeze_task(task); + /* huruihuan add for kill task in D status */ + freeze_cgroup_task(task); css_task_iter_end(&it); } @@ -330,11 +335,27 @@ static void unfreeze_cgroup(struct freezer *freezer) { struct css_task_iter it; struct task_struct *task; + /* huruihuan add for kill task in D status */ + struct task_struct *g, *p; + uid_t tmp_uid_val = -1; css_task_iter_start(&freezer->css, 0, &it); - while ((task = css_task_iter_next(&it))) + /* huruihuan add for kill task in D status */ + while ((task = css_task_iter_next(&it))) { + if (task->real_cred) + tmp_uid_val = task->real_cred->uid.val; __thaw_task(task); + } css_task_iter_end(&it); + + /* make sure all the thread of one uid been wake up by huruihuan */ + read_lock(&tasklist_lock); + do_each_thread(g, p) { + if (p->real_cred && + p->real_cred->uid.val == tmp_uid_val) + __thaw_task(p); + } while_each_thread(g, p); + read_unlock(&tasklist_lock); } /** @@ -392,6 +413,8 @@ static void freezer_change_state(struct freezer *freezer, bool freeze) * CGROUP_FREEZING_PARENT. */ mutex_lock(&freezer_mutex); + /* huruihuan add for kill task in D status */ + freezer->oem_freeze_flag = freeze ? 1 : 0; rcu_read_lock(); css_for_each_descendant_pre(pos, &freezer->css) { struct freezer *pos_f = css_freezer(pos); @@ -416,6 +439,28 @@ static void freezer_change_state(struct freezer *freezer, bool freeze) mutex_unlock(&freezer_mutex); } +/* huruihuan add for kill task in D status */ +void unfreezer_fork(struct task_struct *task) +{ + struct freezer *freezer = NULL; + + /* + * The root cgroup is non-freezable, so we can skip locking the + */ + if (task_css_is_root(task, freezer_cgrp_id)) + return; + + rcu_read_lock(); + freezer = task_freezer(task); + rcu_read_unlock(); + + if (freezer->oem_freeze_flag != 1) + return; + + pr_debug("%s:%s(%d)try to unfreeze\n", __func__, task->comm, task->pid); + freezer_change_state(freezer, 0); +} + static ssize_t freezer_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { diff --git a/kernel/events/core.c b/kernel/events/core.c index fb93388c9f0c891d2937d4cf2df60ea2053f11a6..6aaedafe2a0e6fb12ead00834073b567692c2667 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -51,6 +51,10 @@ #include #include +#ifdef CONFIG_HOUSTON +#include +#endif + #include "internal.h" #include @@ -5065,6 +5069,35 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) return ret; } +#ifdef CONFIG_HOUSTON +u64 ht_perf_read(struct task_struct *task, int id) +{ + struct perf_event *event = task->perf_events[id], *child; + struct perf_event_context *ctx; + u64 total = 0; + + if (unlikely(!event)) + return total; + + ctx = perf_event_ctx_lock(event); + if (event->state == PERF_EVENT_STATE_ERROR) + goto out; + + WARN_ON_ONCE(event->ctx->parent_ctx); + mutex_lock(&event->child_mutex); + (void)perf_event_read(event, false); + total += perf_event_count(event); + list_for_each_entry(child, &event->child_list, child_list) { + (void)perf_event_read(child, false); + total += perf_event_count(child); + } + mutex_unlock(&event->child_mutex); +out: + perf_event_ctx_unlock(event, ctx); + return total; +} +#endif + static __poll_t perf_poll(struct file *file, poll_table *wait) { struct perf_event *event = file->private_data; @@ -10845,6 +10878,83 @@ static void perf_group_shared_event(struct perf_event *event, } #endif +#ifdef CONFIG_HOUSTON +static DEFINE_MUTEX(ht_perf_event_mutex_lock); +bool ht_perf_event_open(pid_t pid, int id) +{ + struct perf_event_attr attr; + struct perf_event *event = NULL; + struct task_struct *task = NULL; + + mutex_lock(&ht_perf_event_mutex_lock); + memset(&attr, 0, sizeof(struct perf_event_attr)); + if (id < HT_PERF_COUNT_CACHE_MISSES_L1) + attr.type = PERF_TYPE_HARDWARE; + else + attr.type = PERF_TYPE_RAW; + switch (id) { + case HT_PERF_COUNT_CPU_CYCLES: + attr.config = PERF_COUNT_HW_CPU_CYCLES; break; + case HT_PERF_COUNT_INSTRUCTIONS: + attr.config = PERF_COUNT_HW_INSTRUCTIONS; break; + case HT_PERF_COUNT_CACHE_MISSES_L1: + attr.config = 0x3; break; + case HT_PERF_COUNT_CACHE_MISSES_L2: + attr.config = 0x17; break; + case HT_PERF_COUNT_CACHE_MISSES_L3: + attr.config = 0x2a; break; + default: + break; + } + attr.size = sizeof(struct perf_event_attr); + attr.disabled = 1; + + task = find_lively_task_by_vpid(pid); + if (IS_ERR(task)) + goto exit_directly; + if (task->perf_regular_activate) + goto err_task; + if (task->perf_events[id] && task->perf_regular_activate) + goto err_task; + if (mutex_lock_interruptible(&task->signal->cred_guard_mutex)) + goto err_task; + + mutex_lock(&task->perf_event_mutex); + if (task->perf_events[id]) { + pr_warn("ht_core: task %s %d event %d has been occupied\n", task->comm, task->pid, id); + perf_event_disable(task->perf_events[id]); + perf_event_release_kernel(task->perf_events[id]); + task->perf_events[id] = NULL; + task->perf_activate &= ~(1 << id); + } + mutex_unlock(&task->perf_event_mutex); + + event = perf_event_create_kernel_counter(&attr, -1, task, NULL, NULL); + if (IS_ERR(event)) + goto err_cred; + + mutex_lock(&task->perf_event_mutex); + task->perf_events[id] = event; + mutex_unlock(&task->perf_event_mutex); + + perf_event_enable(event); + + mutex_unlock(&task->signal->cred_guard_mutex); + put_task_struct(task); + task->perf_activate |= (1 << id); + mutex_unlock(&ht_perf_event_mutex_lock); + return true; + +err_cred: + mutex_unlock(&task->signal->cred_guard_mutex); +err_task: + put_task_struct(task); +exit_directly: + mutex_unlock(&ht_perf_event_mutex_lock); + return false; +} +#endif + /** * sys_perf_event_open - open a performance event, associate it to a task/cpu * @@ -10929,6 +11039,10 @@ SYSCALL_DEFINE5(perf_event_open, if (event_fd < 0) return event_fd; +#ifdef CONFIG_HOUSTON + mutex_lock(&ht_perf_event_mutex_lock); +#endif + if (group_fd != -1) { err = perf_fget_light(group_fd, &group); if (err) @@ -10956,6 +11070,13 @@ SYSCALL_DEFINE5(perf_event_open, err = PTR_ERR(task); goto err_group_fd; } + +#ifdef CONFIG_HOUSTON + if (task->perf_activate) { + err = -EBUSY; + goto err_group_fd; + } +#endif } if (task && group_leader && @@ -11281,6 +11402,12 @@ SYSCALL_DEFINE5(perf_event_open, task, NULL, ctx, event); #endif +#ifdef CONFIG_HOUSTON + if (task) + task->perf_regular_activate = 1; + mutex_unlock(&ht_perf_event_mutex_lock); +#endif + return event_fd; err_locked: @@ -11311,6 +11438,10 @@ SYSCALL_DEFINE5(perf_event_open, fdput(group); err_fd: put_unused_fd(event_fd); + +#ifdef CONFIG_HOUSTON + mutex_unlock(&ht_perf_event_mutex_lock); +#endif return err; } diff --git a/kernel/exit.c b/kernel/exit.c index c73ebbaf519a0997dc11bfe5f386e31a455aac7d..cd051b5efc0fe2991c3266c50bd23fcba5f41775 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -68,6 +68,18 @@ #include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#ifdef CONFIG_HOUSTON +#include +#endif + +#ifdef CONFIG_TPD +#include +#endif + static void __unhash_process(struct task_struct *p, bool group_dead) { nr_threads--; @@ -176,6 +188,14 @@ static void delayed_put_task_struct(struct rcu_head *rhp) { struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); +#ifdef CONFIG_CONTROL_CENTER + cc_tsk_free((void *) tsk); +#endif + +#ifdef CONFIG_TPD + tpd_tglist_del(tsk); +#endif + perf_event_delayed_put(tsk); trace_sched_process_free(tsk); put_task_struct(tsk); @@ -186,6 +206,15 @@ void release_task(struct task_struct *p) { struct task_struct *leader; int zap_leader; +#ifdef CONFIG_HOUSTON + ht_rtg_list_del(p); +#endif + if (p->fpack) { + if (p->fpack->iname) + __putname(p->fpack->iname); + kfree(p->fpack); + p->fpack = NULL; + } repeat: /* don't need to get the RCU readlock here - the process is dead and * can't be modifying its own credentials. But shut RCU-lockdep up */ @@ -882,6 +911,14 @@ void __noreturn do_exit(long code) exit_task_work(tsk); exit_thread(tsk); +#ifdef CONFIG_CONTROL_CENTER + cc_tsk_disable((void *) tsk); +#endif + +#ifdef CONFIG_HOUSTON + ht_perf_event_release(tsk); +#endif + /* * Flush inherited counters to the parent - before the parent * gets woken up by child-exit notifications. diff --git a/kernel/fork.c b/kernel/fork.c index 68b80fcf94bd8edf17332a4e0d05e3e73fa51c1b..29c5a30ae371541a07cd57ee34d8fb4d806aa232 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -96,6 +96,14 @@ #include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#ifdef CONFIG_HOUSTON +#include +#endif + #include #include #include @@ -138,6 +146,10 @@ int lockdep_tasklist_lock_is_held(void) EXPORT_SYMBOL_GPL(lockdep_tasklist_lock_is_held); #endif /* #ifdef CONFIG_PROVE_RCU */ +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO +struct sample_window_t sample_window; +#endif + int nr_processes(void) { int cpu; @@ -907,6 +919,37 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) tsk->splice_pipe = NULL; tsk->task_frag.page = NULL; tsk->wake_q.next = NULL; +#ifdef CONFIG_OPCHAIN + tsk->utask_tag = 0; + tsk->utask_tag_base = 0; + tsk->etask_claim = 0; + tsk->claim_cpu = -1; + tsk->utask_slave = 0; +#endif + +#ifdef CONFIG_UXCHAIN + tsk->static_ux = 0; + tsk->dynamic_ux = 0; + tsk->ux_depth = 0; + tsk->oncpu_time = 0; + tsk->prio_saved = 0; + tsk->saved_flag = 0; +#endif + +#ifdef CONFIG_CONTROL_CENTER + tsk->nice_effect_ts = 0; + tsk->cached_prio = tsk->static_prio; +#endif + +#ifdef CONFIG_RATP + tsk->cpus_suggested = CPU_MASK_ALL; +#endif + +#ifdef CONFIG_TPD + tsk->tpd = 0; + tsk->dtpd = 0; + tsk->dtpdg = -1; +#endif account_kernel_stack(tsk, 1); @@ -986,6 +1029,8 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p, mm->mmap = NULL; mm->mm_rb = RB_ROOT; mm->vmacache_seqnum = 0; + mm->va_feature = 0; + mm->zygoteheap_in_MB = 0; #ifdef CONFIG_SPECULATIVE_PAGE_FAULT rwlock_init(&mm->mm_rb_lock); #endif @@ -1968,6 +2013,11 @@ static __latent_entropy struct task_struct *copy_process( #endif task_io_accounting_init(&p->ioac); + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + task_tli_init(p); +#endif + acct_clear_integrals(p); posix_cpu_timers_init(p); @@ -2020,7 +2070,12 @@ static __latent_entropy struct task_struct *copy_process( p->sequential_io = 0; p->sequential_io_avg = 0; #endif - +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + p->stuck_trace = 0; + memset(&p->oneplus_stuck_info, 0, sizeof(struct oneplus_uifirst_monitor_info)); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + p->fpack = NULL; /* Perform scheduler related setup. Assign this task to a CPU. */ retval = sched_fork(clone_flags, p); if (retval) @@ -2258,6 +2313,21 @@ static __latent_entropy struct task_struct *copy_process( trace_task_newtask(p, clone_flags); uprobe_copy_process(p, clone_flags); +#if defined(CONFIG_CONTROL_CENTER) || defined(CONFIG_HOUSTON) + if (likely(!IS_ERR(p))) { +#ifdef CONFIG_HOUSTON + ht_perf_event_init(p); + ht_rtg_init(p); +#endif +#ifdef CONFIG_CONTROL_CENTER + cc_tsk_init((void *) p); +#endif +#ifdef CONFIG_ONEPLUS_FG_OPT + p->fuse_boost = 0; +#endif + } +#endif + return p; bad_fork_cancel_cgroup: @@ -2397,6 +2467,8 @@ long _do_fork(unsigned long clone_flags, * might get invalid after that point, if the thread exits quickly. */ trace_sched_process_fork(current, p); + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + SMB_HOT_COUNT_INIT((clone_flags & CLONE_VM), p); pid = get_task_pid(p, PIDTYPE_PID); nr = pid_vnr(pid); diff --git a/kernel/freezer.c b/kernel/freezer.c index b162b74611e475e611723aacb04c857f7638ab53..d80a971b9bf13859e8a3fb076c904d179b2f1a48 100644 --- a/kernel/freezer.c +++ b/kernel/freezer.c @@ -73,7 +73,9 @@ bool __refrigerator(bool check_kthr_stop) spin_lock_irq(&freezer_lock); current->flags |= PF_FROZEN; if (!freezing(current) || - (check_kthr_stop && kthread_should_stop())) + /* huruihuan add for kill task in D status */ + (check_kthr_stop && kthread_should_stop()) || + current->kill_flag) current->flags &= ~PF_FROZEN; spin_unlock_irq(&freezer_lock); @@ -106,6 +108,26 @@ static void fake_signal_wake_up(struct task_struct *p) } } +/* huruihuan add for freezing task in cgroup despite of PF_FREEZER_SKIP flag */ +bool freeze_cgroup_task(struct task_struct *p) +{ + unsigned long flags; + + spin_lock_irqsave(&freezer_lock, flags); + if (!freezing(p) || frozen(p)) { + spin_unlock_irqrestore(&freezer_lock, flags); + return false; + } + + if (!(p->flags & PF_KTHREAD)) + fake_signal_wake_up(p); + else + wake_up_state(p, TASK_INTERRUPTIBLE); + + spin_unlock_irqrestore(&freezer_lock, flags); + return true; +} + /** * freeze_task - send a freeze request to given task * @p: task to send the request to diff --git a/kernel/futex.c b/kernel/futex.c index 920d853a8e9e208d6cd4d08b08db91f4686df4b7..034638cfd686071bbd9bbef00d45a62555e0d39d 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -72,6 +72,9 @@ #include #include "locking/rtmutex_common.h" +#ifdef CONFIG_UXCHAIN +#include +#endif /* * READ this before attempting to hack on futexes! @@ -1634,6 +1637,18 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) spin_unlock(&hb->lock); wake_up_q(&wake_q); +#ifdef CONFIG_UXCHAIN + if (sysctl_uxchain_enabled && current->dynamic_ux) { + //raw_spin_lock(¤t->uxchain_lock); + if (current->saved_flag) { + current->saved_flag = 0; + set_user_nice(current, PRIO_TO_NICE(current->prio_saved)); + } + //raw_spin_unlock(¤t->uxchain_lock); + uxchain_dynamic_ux_reset(current); + } +#endif + out_put_key: put_futex_key(&key); out: @@ -2597,8 +2612,14 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked) * @q: the futex_q to queue up on * @timeout: the prepared hrtimer_sleeper, or null for no timeout */ +#ifdef CONFIG_UXCHAIN +static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, + struct hrtimer_sleeper *timeout, struct task_struct *wait_for) + +#else static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, struct hrtimer_sleeper *timeout) +#endif { /* * The task state is guaranteed to be set before another task can @@ -2623,9 +2644,42 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q, * flagged for rescheduling. Only call schedule if there * is no timeout, or if it has yet to expire. */ +#ifdef CONFIG_UXCHAIN + if (!timeout || timeout->task) { + if (sysctl_uxchain_enabled) { + uxchain_dynamic_ux_boost(wait_for, current); + if (wait_for && current->normal_prio < wait_for->normal_prio) { + //raw_spin_lock(&wait_for->uxchain_lock); + wait_for->saved_flag = 1; + wait_for->prio_saved = wait_for->normal_prio; + set_user_nice(wait_for, PRIO_TO_NICE(current->normal_prio)); + //raw_spin_unlock(&wait_for->uxchain_lock); + } + if (wait_for) { + put_task_struct(wait_for); + wait_for = NULL; + } + } + freezable_schedule(); + } +#elif defined(CONFIG_ONEPLUS_HEALTHINFO) +/*2020-06-17, add for stuck monitor*/ + if (!timeout || timeout->task) { + current->in_futex = 1; + freezable_schedule(); + current->in_futex = 0; + } +#else/*CONFIG_ONEPLUS_HEALTHINFO*/ if (!timeout || timeout->task) freezable_schedule(); +#endif + } +#ifdef CONFIG_UXCHAIN + if (wait_for) { + put_task_struct(wait_for); + wait_for = NULL; } +#endif __set_current_state(TASK_RUNNING); } @@ -2705,19 +2759,33 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, return ret; } +#ifdef CONFIG_UXCHAIN +static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, + ktime_t *abs_time, u32 __user *uaddr2, u32 bitset) +#else static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, ktime_t *abs_time, u32 bitset) +#endif { struct hrtimer_sleeper timeout, *to = NULL; struct restart_block *restart; struct futex_hash_bucket *hb; struct futex_q q = futex_q_init; +#ifdef CONFIG_UXCHAIN + struct task_struct *wait_for = NULL; +#endif int ret; if (!bitset) return -EINVAL; q.bitset = bitset; +#ifdef CONFIG_UXCHAIN + if (sysctl_uxchain_enabled && q.bitset == FUTEX_BITSET_MATCH_ANY && + current->static_ux && !abs_time) + wait_for = get_futex_owner(uaddr2); +#endif + if (abs_time) { to = &timeout; @@ -2735,11 +2803,26 @@ static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, * q.key refs. */ ret = futex_wait_setup(uaddr, val, flags, &q, &hb); +#ifdef CONFIG_UXCHAIN + if (ret) { + if (wait_for) { + put_task_struct(wait_for); + wait_for = NULL; + } + goto out; + } +#else if (ret) goto out; +#endif /* queue_me and wait for wakeup, timeout, or a signal. */ +#ifdef CONFIG_UXCHAIN + futex_wait_queue_me(hb, &q, to, wait_for); + wait_for = NULL; +#else futex_wait_queue_me(hb, &q, to); +#endif /* If we were woken (and unqueued), we succeeded, whatever. */ ret = 0; @@ -2768,6 +2851,9 @@ static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, restart->futex.time = *abs_time; restart->futex.bitset = bitset; restart->futex.flags = flags | FLAGS_HAS_TIMEOUT; +#ifdef CONFIG_UXCHAIN + restart->futex.uaddr2 = uaddr2; +#endif ret = -ERESTART_RESTARTBLOCK; @@ -2791,8 +2877,13 @@ static long futex_wait_restart(struct restart_block *restart) } restart->fn = do_no_restart_syscall; +#ifdef CONFIG_UXCHAIN + return (long)futex_wait(uaddr, restart->futex.flags, + restart->futex.val, tp, restart->futex.uaddr2, restart->futex.bitset); +#else return (long)futex_wait(uaddr, restart->futex.flags, restart->futex.val, tp, restart->futex.bitset); +#endif } @@ -3284,7 +3375,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, } /* Queue the futex_q, drop the hb lock, wait for wakeup. */ +#ifdef CONFIG_UXCHAIN + futex_wait_queue_me(hb, &q, to, NULL); +#else futex_wait_queue_me(hb, &q, to); +#endif spin_lock(&hb->lock); ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to); @@ -3706,7 +3801,11 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, val3 = FUTEX_BITSET_MATCH_ANY; /* fall through */ case FUTEX_WAIT_BITSET: +#ifdef CONFIG_UXCHAIN + return futex_wait(uaddr, flags, val, timeout, uaddr2, val3); +#else return futex_wait(uaddr, flags, val, timeout, val3); +#endif case FUTEX_WAKE: val3 = FUTEX_BITSET_MATCH_ANY; /* fall through */ diff --git a/kernel/hung_task.c b/kernel/hung_task.c index 11f10e0169d01af90134d48a537fe44892a0614b..1a586f8ebb02fda40e75264b0c833debbbc428bf 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -23,6 +23,10 @@ #include #include +#ifdef CONFIG_HUNG_TASK_ENHANCE +#include +#endif + /* * The number of tasks checked: */ @@ -92,6 +96,7 @@ static struct notifier_block panic_block = { .notifier_call = hung_task_panic, }; +#ifndef CONFIG_HUNG_TASK_ENHANCE static void check_hung_task(struct task_struct *t, unsigned long timeout) { unsigned long switch_count = t->nvcsw + t->nivcsw; @@ -148,6 +153,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) touch_nmi_watchdog(); } +#endif /* * To avoid extending the RCU grace period for an unbounded amount of time, @@ -183,6 +189,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) unsigned long last_break = jiffies; struct task_struct *g, *t; +#ifdef CONFIG_HUNG_TASK_ENHANCE + unsigned int iowait_count = 0; +#endif + /* * If the system crashed already then all bets are off, * do not report extra hung tasks: @@ -200,14 +210,21 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) goto unlock; last_break = jiffies; } +#ifdef CONFIG_HUNG_TASK_ENHANCE + io_check_hung_detection(t, timeout, &iowait_count, &hung_task_show_lock, &hung_task_call_panic); +#else /* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ if (t->state == TASK_UNINTERRUPTIBLE) /* Check for selective monitoring */ if (!sysctl_hung_task_selective_monitoring || t->hang_detection_enabled) check_hung_task(t, timeout); +#endif } unlock: +#ifdef CONFIG_HUNG_TASK_ENHANCE + io_block_panic(&iowait_count, sysctl_hung_task_maxiowait_count); +#endif rcu_read_unlock(); if (hung_task_show_lock) debug_show_all_locks(); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index eb69b805f908b2ba33ca702b7940bd147a862060..4ca8513db75c2ebce82533d788c06161f37c9240 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "internals.h" @@ -685,6 +687,87 @@ int irq_set_irq_wake(unsigned int irq, unsigned int on) } EXPORT_SYMBOL(irq_set_irq_wake); +/* + *Add debug node that can disable irq wakeup + */ +static char *factory_wakeup_irq[] = { + "pon_kpdpwr_status", + "pm8xxx_rtc_alarm", + "usbin-uv", + "usbin-plugin", + "op_usb_plug" +}; + +static bool irq_allow_wakeup_factory(int irq) +{ + int i; + int len = ARRAY_SIZE(factory_wakeup_irq); + struct irq_desc *desc = irq_to_desc(irq); + + for (i = 0; i < len; i++) { + if (!strcmp(desc->action->name, factory_wakeup_irq[i])) { + pr_debug("%s: %s allow wakeup in factory\n", __func__, factory_wakeup_irq[i]); + return true; + } + } + return false; +} + +static int disable_irq_wakeup_one(int irq) +{ + int error; + struct irq_desc *desc = irq_to_desc(irq); + + if (irqd_is_wakeup_set(irq_get_irq_data(irq)) && !irq_allow_wakeup_factory(irq)) { + pr_debug("%s: will disable irq = %d; name = %s\n", __func__, irq, desc->action->name); + error = disable_irq_wake(irq); + if (error) + pr_err("failed to disable IRQ %d as wake source: %d\n", irq, error); + } + return error; +} + +/* + *echo "n" > /sys/kernel/debug/irq_wakeup_mode + */ + #define MAX_MSG_SIZE 20 +static ssize_t irq_wakeup_write(struct file *file, const char __user *userstr, + size_t len, loff_t *pos) +{ + char buf[MAX_MSG_SIZE + 1]; + int irq; + + if (!len || (len > MAX_MSG_SIZE)) + return len; + + copy_from_user(buf, userstr, len); + + if (strncmp(buf, "n", 1) != 0) + return len; + + irq_lock_sparse(); + for_each_active_irq(irq) + disable_irq_wakeup_one(irq); + irq_unlock_sparse(); + + return len; +} + +static const struct file_operations irq_wakeup_fops = { + .write = irq_wakeup_write, +}; + +static int __init irq_wakeup_init(void) +{ + debugfs_create_file("irq_wakeup_mode", 0220, NULL, NULL, + &irq_wakeup_fops); + + return 0; +} + +late_initcall(irq_wakeup_init); +/************************************************************************************/ + /* * Internal function that tells the architecture code whether a * particular irq has been exclusively allocated or is available diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index 49dc6f3620f0b9e522a8ecce5c90ae0180b886e6..731a4153a3c1f40028e7ff023dfe103dae012934 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -484,6 +484,7 @@ int show_interrupts(struct seq_file *p, void *v) int i = *(loff_t *) v, j; struct irqaction *action; struct irq_desc *desc; + unsigned long irq_flags; if (i > ACTUAL_NR_IRQS) return 0; @@ -531,11 +532,17 @@ int show_interrupts(struct seq_file *p, void *v) seq_printf(p, " %8s", "None"); } if (desc->irq_data.domain) - seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq); + seq_printf(p, " %*ld", prec, desc->irq_data.hwirq); else seq_printf(p, " %*s", prec, ""); #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL - seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); + irq_flags = irqd_get_trigger_type(&desc->irq_data); + if (irq_flags & IRQ_TYPE_LEVEL_MASK) + seq_printf(p, " %-8s", "Level"); + else if (irq_flags & IRQ_TYPE_EDGE_BOTH) + seq_printf(p, " %-8s", "Edge"); + else + seq_printf(p, " %-8s", "None"); #endif if (desc->name) seq_printf(p, "-%-8s", desc->name); diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c index 202ef0d29fb66574e3921c30ce18b359ca1ffc63..8c2e5b7a3e53d49d14d4c7673b127855562b3b9c 100644 --- a/kernel/locking/mutex.c +++ b/kernel/locking/mutex.c @@ -1011,7 +1011,17 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, } spin_unlock(&lock->wait_lock); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + if (state & TASK_UNINTERRUPTIBLE) + current->in_mutex = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule_preempt_disabled(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + if (state & TASK_UNINTERRUPTIBLE) + current->in_mutex = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ /* * ww_mutex needs to always recheck its position since its waiter diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c index ddc9cbd7700bb549b92b018821f9273b18d2cf2d..c9ad8375d0ff48f18a8f79a43d288bc9046f7921 100644 --- a/kernel/locking/rwsem-xadd.c +++ b/kernel/locking/rwsem-xadd.c @@ -285,7 +285,15 @@ __rwsem_down_read_failed_common(struct rw_semaphore *sem, int state) raw_spin_unlock_irq(&sem->wait_lock); break; } +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + current->in_downread = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + current->in_downread = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ } __set_current_state(TASK_RUNNING); @@ -587,7 +595,15 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state) if (signal_pending_state(state, current)) goto out_nolock; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + current->in_downwrite = 1; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ schedule(); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + current->in_downwrite = 0; +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ set_current_state(state); } while ((count = atomic_long_read(&sem->count)) & RWSEM_ACTIVE_MASK); diff --git a/kernel/panic.c b/kernel/panic.c index 50033a73d6c6667fe99a2b8c1c6a820318a73d0f..07f24f1619cbe9abe423f69009c8ddd19f92fe3b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -31,6 +31,7 @@ #include #include #include +#include #define PANIC_TIMER_STEP 100 #define PANIC_BLINK_SPD 18 @@ -142,6 +143,7 @@ void panic(const char *fmt, ...) int state = 0; int old_cpu, this_cpu; bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; + char *function_name = NULL; /* * Disable local interrupts. This will prevent panic_smp_self_stop @@ -179,7 +181,19 @@ void panic(const char *fmt, ...) vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); dump_stack_minidump(0); + +#ifdef CONFIG_PANIC_FLUSH + if (!oem_get_download_mode()) + panic_flush_device_cache(2000); +#endif + pr_emerg("Kernel panic - not syncing: %s\n", buf); + /* + * Save dump reason to smem + */ + function_name = parse_function_builtin_return_address((unsigned + long)__builtin_return_address(0)); + save_dump_reason_to_smem(buf, function_name); #ifdef CONFIG_DEBUG_BUGVERBOSE /* * Avoid nested stack-dumping if a panic occurs during oops processing diff --git a/kernel/power/main.c b/kernel/power/main.c index 6bcb47d366af8227783aab160162a744859e1196..7c5d065aa0d6766e4a98b8003c12b2c010a2884f 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -891,7 +891,7 @@ EXPORT_SYMBOL_GPL(pm_wq); static int __init pm_start_workqueue(void) { - pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); + pm_wq = alloc_workqueue("pm", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); return pm_wq ? 0 : -ENOMEM; } diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 32a55ecb78d6d9b9f7f24d03763daace23583585..b56644db3d1bd698a96e8985d75d1dcef70944c1 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -129,6 +129,218 @@ static struct pm_qos_object memory_bandwidth_pm_qos = { .name = "memory_bandwidth", }; +static BLOCKING_NOTIFIER_HEAD(c0_cpufreq_max_notifier); +static struct pm_qos_constraints c0_cpufreq_max_constraints = { + .list = PLIST_HEAD_INIT(c0_cpufreq_max_constraints.list), + .target_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE }, + .default_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .type = PM_QOS_MIN, + .notifiers = &c0_cpufreq_max_notifier, +}; +static struct pm_qos_object c0_cpufreq_max_pm_qos = { + .constraints = &c0_cpufreq_max_constraints, + .name = "c0_cpufreq_max", +}; + + +static BLOCKING_NOTIFIER_HEAD(c0_cpufreq_min_notifier); +static struct pm_qos_constraints c0_cpufreq_min_constraints = { + .list = PLIST_HEAD_INIT(c0_cpufreq_min_constraints.list), + .target_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE }, + .default_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &c0_cpufreq_min_notifier, +}; +static struct pm_qos_object c0_cpufreq_min_pm_qos = { + .constraints = &c0_cpufreq_min_constraints, + .name = "c0_cpufreq_min", +}; + +static BLOCKING_NOTIFIER_HEAD(c1_cpufreq_max_notifier); +static struct pm_qos_constraints c1_cpufreq_max_constraints = { + .list = PLIST_HEAD_INIT(c1_cpufreq_max_constraints.list), + .target_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE }, + .default_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .type = PM_QOS_MIN, + .notifiers = &c1_cpufreq_max_notifier, +}; +static struct pm_qos_object c1_cpufreq_max_pm_qos = { + .constraints = &c1_cpufreq_max_constraints, + .name = "c1_cpufreq_max", +}; + +static BLOCKING_NOTIFIER_HEAD(c1_cpufreq_min_notifier); +static struct pm_qos_constraints c1_cpufreq_min_constraints = { + .list = PLIST_HEAD_INIT(c1_cpufreq_min_constraints.list), + .target_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE }, + .default_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &c1_cpufreq_min_notifier, +}; +static struct pm_qos_object c1_cpufreq_min_pm_qos = { + .constraints = &c1_cpufreq_min_constraints, + .name = "c1_cpufreq_min", +}; + +static BLOCKING_NOTIFIER_HEAD(c2_cpufreq_max_notifier); +static struct pm_qos_constraints c2_cpufreq_max_constraints = { + .list = PLIST_HEAD_INIT(c2_cpufreq_max_constraints.list), + .target_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE }, + .default_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_CPUFREQ_MAX_DEFAULT_VALUE, + .type = PM_QOS_MIN, + .notifiers = &c2_cpufreq_max_notifier, +}; +static struct pm_qos_object c2_cpufreq_max_pm_qos = { + .constraints = &c2_cpufreq_max_constraints, + .name = "c2_cpufreq_max", +}; + +static BLOCKING_NOTIFIER_HEAD(c2_cpufreq_min_notifier); +static struct pm_qos_constraints c2_cpufreq_min_constraints = { + .list = PLIST_HEAD_INIT(c2_cpufreq_min_constraints.list), + .target_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE }, + .default_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_CPUFREQ_MIN_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &c2_cpufreq_min_notifier, +}; +static struct pm_qos_object c2_cpufreq_min_pm_qos = { + .constraints = &c2_cpufreq_min_constraints, + .name = "c2_cpufreq_min", +}; + +static BLOCKING_NOTIFIER_HEAD(devfreq_max_notifier); +static struct pm_qos_constraints devfreq_max_constraints = { + .list = PLIST_HEAD_INIT(devfreq_max_constraints.list), + .target_value = PM_QOS_DEVFREQ_MAX_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_DEVFREQ_MAX_DEFAULT_VALUE }, + .default_value = PM_QOS_DEVFREQ_MAX_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DEVFREQ_MAX_DEFAULT_VALUE, + .type = PM_QOS_MIN, + .notifiers = &devfreq_max_notifier, +}; +static struct pm_qos_object devfreq_max_pm_qos = { + .constraints = &devfreq_max_constraints, + .name = "devfreq_max", +}; + +static BLOCKING_NOTIFIER_HEAD(devfreq_min_notifier); +static struct pm_qos_constraints devfreq_min_constraints = { + .list = PLIST_HEAD_INIT(devfreq_min_constraints.list), + .target_value = PM_QOS_DEVFREQ_MIN_DEFAULT_VALUE, + .target_per_cpu = { [0 ... (NR_CPUS - 1)] = + PM_QOS_DEVFREQ_MIN_DEFAULT_VALUE }, + .default_value = PM_QOS_DEVFREQ_MIN_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DEVFREQ_MIN_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &devfreq_min_notifier, +}; +static struct pm_qos_object devfreq_min_pm_qos = { + .constraints = &devfreq_min_constraints, + .name = "devfreq_min", +}; + +static BLOCKING_NOTIFIER_HEAD(msm_thermal_notifier); +static struct pm_qos_constraints msm_thermal_constraints = { + .list = PLIST_HEAD_INIT(msm_thermal_constraints.list), + .target_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .default_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &msm_thermal_notifier, +}; +static struct pm_qos_object msm_thermal_pm_qos = { + .constraints = &msm_thermal_constraints, + .name = "msm_thermal", +}; + +static BLOCKING_NOTIFIER_HEAD(skin_thermal_notifier); +static struct pm_qos_constraints skin_thermal_constraints = { + .list = PLIST_HEAD_INIT(skin_thermal_constraints.list), + .target_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .default_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &skin_thermal_notifier, +}; +static struct pm_qos_object skin_thermal_pm_qos = { + .constraints = &skin_thermal_constraints, + .name = "skin_thermal", +}; + +static BLOCKING_NOTIFIER_HEAD(modem_skin_thermal_notifier); +static struct pm_qos_constraints modem_skin_thermal_constraints = { + .list = PLIST_HEAD_INIT(modem_skin_thermal_constraints.list), + .target_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .default_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &modem_skin_thermal_notifier, +}; +static struct pm_qos_object modem_skin_thermal_pm_qos = { + .constraints = &modem_skin_thermal_constraints, + .name = "modem_skin_thermal", +}; + +static BLOCKING_NOTIFIER_HEAD(pa1_mmw0_thermal_notifier); +static struct pm_qos_constraints pa1_mmw0_thermal_constraints = { + .list = PLIST_HEAD_INIT(pa1_mmw0_thermal_constraints.list), + .target_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .default_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &pa1_mmw0_thermal_notifier, +}; +static struct pm_qos_object pa1_mmw0_thermal_pm_qos = { + .constraints = &pa1_mmw0_thermal_constraints, + .name = "mmw0_thermal", +}; + +static BLOCKING_NOTIFIER_HEAD(xo_mmw1_thermal_notifier); +static struct pm_qos_constraints xo_mmw1_thermal_constraints = { + .list = PLIST_HEAD_INIT(xo_mmw1_thermal_constraints.list), + .target_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .default_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &xo_mmw1_thermal_notifier, +}; +static struct pm_qos_object xo_mmw1_thermal_pm_qos = { + .constraints = &xo_mmw1_thermal_constraints, + .name = "mmw1_thermal", +}; + +static BLOCKING_NOTIFIER_HEAD(modem_mmw2_thermal_notifier); +static struct pm_qos_constraints modem_mmw2_thermal_constraints = { + .list = PLIST_HEAD_INIT(modem_mmw2_thermal_constraints.list), + .target_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .default_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .no_constraint_value = PM_QOS_DYNAMIC_THERMAL_DEFAULT_VALUE, + .type = PM_QOS_MAX, + .notifiers = &modem_mmw2_thermal_notifier, +}; +static struct pm_qos_object modem_mmw2_thermal_pm_qos = { + .constraints = &modem_mmw2_thermal_constraints, + .name = "mmw2_thermal", +}; static struct pm_qos_object *pm_qos_array[] = { &null_pm_qos, @@ -136,6 +348,20 @@ static struct pm_qos_object *pm_qos_array[] = { &network_lat_pm_qos, &network_throughput_pm_qos, &memory_bandwidth_pm_qos, + &c0_cpufreq_max_pm_qos, + &c0_cpufreq_min_pm_qos, + &c1_cpufreq_max_pm_qos, + &c1_cpufreq_min_pm_qos, + &c2_cpufreq_max_pm_qos, + &c2_cpufreq_min_pm_qos, + &devfreq_max_pm_qos, + &devfreq_min_pm_qos, + &msm_thermal_pm_qos, + &skin_thermal_pm_qos, + &pa1_mmw0_thermal_pm_qos, + &xo_mmw1_thermal_pm_qos, + &modem_mmw2_thermal_pm_qos, + &modem_skin_thermal_pm_qos, }; static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, @@ -648,11 +874,12 @@ void pm_qos_add_request(struct pm_qos_request *req, break; } - req->pm_qos_class = pm_qos_class; INIT_DELAYED_WORK(&req->work, pm_qos_work_fn); trace_pm_qos_add_request(pm_qos_class, value); pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, &req->node, PM_QOS_ADD_REQ, value); + /* Fixes rare panic */ + req->pm_qos_class = pm_qos_class; #ifdef CONFIG_SMP if (req->type == PM_QOS_REQ_AFFINE_IRQ && diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 3ef2c536652d452723aed2fe9b1bfc8444078b29..d857fe6a628a86ca118e0a0df8479de542165e97 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -36,6 +36,12 @@ #include "power.h" +#include +#include +extern struct qcom_smem_state *qstate; +#define PROC_AWAKE_ID 12 /* 12th bit */ +#define AWAKE_BIT BIT(PROC_AWAKE_ID) + const char * const pm_labels[] = { [PM_SUSPEND_TO_IDLE] = "freeze", [PM_SUSPEND_STANDBY] = "standby", @@ -633,8 +639,15 @@ int pm_suspend(suspend_state_t state) if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX) return -EINVAL; + qcom_smem_state_update_bits(qstate, AWAKE_BIT, 0); + pr_err("%s: PM_SUSPEND_PREPARE smp2p_change_state", __func__); + pr_info("suspend entry (%s)\n", mem_sleep_labels[state]); error = enter_state(state); + + qcom_smem_state_update_bits(qstate, AWAKE_BIT, AWAKE_BIT); + pr_err("%s: PM_POST_SUSPEND smp2p_change_state", __func__); + if (error) { suspend_stats.fail++; dpm_save_failed_errno(error); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index a9e567ac6ce4f8407c620e07cc212ae55d014b9d..fce3f6f63f6923664770a1c33d4ae36b9bbc2ed6 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -1101,6 +1103,14 @@ static void __init log_buf_add_cpu(void) static inline void log_buf_add_cpu(void) {} #endif /* CONFIG_SMP */ +static int __init ftm_console_silent_setup(char *str) +{ + pr_info("ftm_silent_log\n"); + console_silent(); + return 0; +} +early_param("ftm_console_silent", ftm_console_silent_setup); + void __init setup_log_buf(int early) { unsigned long flags; @@ -1221,21 +1231,8 @@ static inline void boot_delay_msec(int level) static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME); module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); -static size_t print_time(u64 ts, char *buf) -{ - unsigned long rem_nsec; - - if (!printk_time) - return 0; - - rem_nsec = do_div(ts, 1000000000); - - if (!buf) - return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); - - return sprintf(buf, "[%5lu.%06lu] ", - (unsigned long)ts, rem_nsec / 1000); -} +static bool print_wall_time = 1; +module_param_named(print_wall_time, print_wall_time, bool, 0644); static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf) { @@ -1255,8 +1252,6 @@ static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf) len++; } } - - len += print_time(msg->ts_nsec, buf ? buf + len : NULL); return len; } @@ -1851,6 +1846,12 @@ int vprintk_store(int facility, int level, char *text = textbuf; size_t text_len; enum log_flags lflags = 0; + static char texttmp[LOG_LINE_MAX]; + static bool last_new_line = true; + u64 ts_sec = local_clock(); + unsigned long rem_nsec; + + rem_nsec = do_div(ts_sec, 1000000000); /* * The printf needs to come first; we need the syslog @@ -1885,6 +1886,42 @@ int vprintk_store(int facility, int level, text += 2; } } + if (last_new_line) { + if (print_wall_time && ts_sec >= 20) { + struct timespec64 tspec; + struct rtc_time tm; + + __getnstimeofday64(&tspec); + + if (sys_tz.tz_minuteswest < 0 + || (tspec.tv_sec-sys_tz.tz_minuteswest*60) >= 0) + tspec.tv_sec -= sys_tz.tz_minuteswest * 60; + rtc_time_to_tm(tspec.tv_sec, &tm); + + text_len = scnprintf(texttmp, sizeof(texttmp), + "[%02d%02d%02d_%02d:%02d:%02d.%06ld]@%d %s", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + tspec.tv_nsec / 1000, raw_smp_processor_id(), text); + } else { + text_len = scnprintf(texttmp, sizeof(texttmp), + "[%5lu.%06lu]@%d %s", (unsigned long)ts_sec, + rem_nsec / 1000, raw_smp_processor_id(), text); + } + + text = texttmp; + + /* mark and strip a trailing newline */ + if (text_len && text[text_len-1] == '\n') { + text_len--; + lflags |= LOG_NEWLINE; + } + } + + if (lflags & LOG_NEWLINE) + last_new_line = true; + else + last_new_line = false; if (level == LOGLEVEL_DEFAULT) level = default_message_loglevel; @@ -2114,7 +2151,7 @@ __setup("console_msg_format=", console_msg_format_setup); * Set up a console. Called via do_early_param() in init/main.c * for each "console=" parameter in the boot command line. */ -static int __init console_setup(char *str) +static int console_setup(char *str) { char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */ char *s, *options, *brl_options = NULL; @@ -2154,6 +2191,14 @@ static int __init console_setup(char *str) } __setup("console=", console_setup); +int force_oem_console_setup(char *str) +{ + console_setup(str); + return 1; +} +EXPORT_SYMBOL(force_oem_console_setup); + + /** * add_preferred_console - add a device to the list of preferred consoles. * @name: device name diff --git a/kernel/reboot.c b/kernel/reboot.c index 4fef5894b9d2d47b98b938997b1882904b9e8351..1b1da05f77e7df063b40379bda8d0f6195936e16 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include /* * this indicates whether you can reboot with ctrl-alt-del: the default is yes @@ -248,6 +250,16 @@ void kernel_restart(char *cmd) pr_emerg("Restarting system\n"); else pr_emerg("Restarting system with command '%s'\n", cmd); + + /*if enable dump, if dm-verity device corrupted, force enter dump */ + if (oem_get_download_mode()) { + if (((cmd != NULL && cmd[0] != '\0') && + !strcmp(cmd, "dm-verity device corrupted"))) { + panic("dm-verity device corrupted Force Dump"); + pr_emerg("Restarting system painc\n"); + msleep(10000); + } + } kmsg_dump(KMSG_DUMP_RESTART); machine_restart(cmd); } diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 81f880bc9565a69f08643d0201c969a1f49630d0..e30c826f9519c55beabdff99720b553050612574 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -24,12 +24,31 @@ #include "pelt.h" #include "walt.h" - +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif/*CONFIG_ONEPLUS_HEALTHINFO*/ #define CREATE_TRACE_POINTS #include +#ifdef CONFIG_HOUSTON +#include +#endif + +#ifdef CONFIG_IM +#include +#endif + DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); +#define TRACE_DEBUG 0 +static inline void tracing_mark_write(int serial, char *name, unsigned int value) +{ +#if TRACE_DEBUG + trace_printk("C|%d|%s|%u\n", 99990+serial, name, value); +#endif +} + #if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_JUMP_LABEL) /* * Debugging: various feature bits @@ -1376,6 +1395,11 @@ void deactivate_task(struct rq *rq, struct task_struct *p, int flags) clear_ed_task(p, rq); dequeue_task(rq, p, flags); + +#if defined(CONFIG_CONTROL_CENTER) && defined(CONFIG_IM) + if (unlikely(im_main(p) || im_enqueue(p) || im_render(p))) + restore_user_nice_safe(p); +#endif } /* @@ -1461,6 +1485,16 @@ void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) { const struct sched_class *class; +#ifdef CONFIG_UXCHAIN + u64 wallclock = sched_ktime_clock(); + + if (sysctl_uxchain_enabled && + (sysctl_launcher_boost_enabled || + wallclock - rq->curr->oncpu_time < PREEMPT_DISABLE_NS) && + (rq->curr->static_ux || rq->curr->dynamic_ux) && + !(p->flags & PF_WQ_WORKER) && !task_has_rt_policy(p)) + return; +#endif if (p->sched_class == rq->curr->sched_class) { rq->curr->sched_class->check_preempt_curr(rq, p, flags); } else { @@ -2092,9 +2126,14 @@ static int select_fallback_rq(int cpu, struct task_struct *p, bool allow_iso) enum { cpuset, possible, fail, bug } state = cpuset; int dest_cpu; int isolated_candidate = -1; + bool is_rtg; int backup_cpu = -1; unsigned int max_nr = UINT_MAX; + is_rtg = task_in_related_thread_group(p); + if (sysctl_sched_skip_affinity && is_rtg && + cpu_active(cpu) && !cpu_isolated(cpu)) + return cpu; /* * If the node that the CPU is on has been offlined, cpu_to_node() * will return -1. There is no CPU on the node, and we should @@ -2110,8 +2149,10 @@ static int select_fallback_rq(int cpu, struct task_struct *p, bool allow_iso) if (cpu_isolated(dest_cpu)) continue; if (cpumask_test_cpu(dest_cpu, &p->cpus_allowed)) { - if (cpu_rq(dest_cpu)->nr_running < 32) + if (cpu_rq(dest_cpu)->nr_running < 32) { + cpu_dist_inc(p, dest_cpu); return dest_cpu; + } if (cpu_rq(dest_cpu)->nr_running > max_nr) continue; backup_cpu = dest_cpu; @@ -2179,6 +2220,7 @@ static int select_fallback_rq(int cpu, struct task_struct *p, bool allow_iso) } } + cpu_dist_inc(p, dest_cpu); return dest_cpu; } @@ -2189,11 +2231,13 @@ static inline int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags, int sibling_count_hint) { + bool is_rtg; bool allow_isolated = (p->flags & PF_KTHREAD); lockdep_assert_held(&p->pi_lock); - if (p->nr_cpus_allowed > 1) + is_rtg = task_in_related_thread_group(p); + if (p->nr_cpus_allowed > 1 || (sysctl_sched_skip_affinity && is_rtg)) cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags, sibling_count_hint); else @@ -2210,8 +2254,11 @@ int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags, * not worry about this generic constraint ] */ if (unlikely(!is_cpu_allowed(p, cpu)) || - (cpu_isolated(cpu) && !allow_isolated)) - cpu = select_fallback_rq(task_cpu(p), p, allow_isolated); + (cpu_isolated(cpu) && !allow_isolated)) { + if (!sysctl_sched_skip_affinity || !is_rtg) + cpu = task_cpu(p); + cpu = select_fallback_rq(cpu, p, allow_isolated); + } return cpu; } @@ -3037,6 +3084,7 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) * Make sure we do not leak PI boosting priority to the child. */ p->prio = current->normal_prio; + p->compensate_need = 0; uclamp_fork(p); @@ -3047,9 +3095,16 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p) if (task_has_dl_policy(p) || task_has_rt_policy(p)) { p->policy = SCHED_NORMAL; p->static_prio = NICE_TO_PRIO(0); +#ifdef CONFIG_CONTROL_CENTER + p->cached_prio = p->static_prio; +#endif p->rt_priority = 0; } else if (PRIO_TO_NICE(p->static_prio) < 0) +#ifdef CONFIG_CONTROL_CENTER + p->cached_prio = p->static_prio = NICE_TO_PRIO(0); +#else p->static_prio = NICE_TO_PRIO(0); +#endif p->prio = p->normal_prio = __normal_prio(p); set_load_weight(p, false); @@ -3134,6 +3189,7 @@ void wake_up_new_task(struct task_struct *p) raw_spin_lock_irqsave(&p->pi_lock, rf.flags); p->state = TASK_RUNNING; + #ifdef CONFIG_SMP /* * Fork balancing, do it here and not earlier because: @@ -4282,9 +4338,22 @@ static void __sched notrace __schedule(bool preempt) * is a RELEASE barrier), */ ++*switch_count; - +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (prev->sched_class == &rt_sched_class && ohm_rtinfo_ctrl == true) + rt_thresh_times_record(prev, cpu); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + +#ifdef CONFIG_UXCHAIN + prev->oncpu_time = 0; + next->oncpu_time = wallclock; +#endif trace_sched_switch(preempt, prev, next); +#ifdef CONFIG_HOUSTON + ht_sched_switch_update(prev, next); +#endif + /* Also unlocks the rq: */ rq = context_switch(rq, prev, next, &rf); update_md_current_stack(NULL); @@ -4681,6 +4750,91 @@ static inline int rt_effective_prio(struct task_struct *p, int prio) } #endif +#ifdef CONFIG_CONTROL_CENTER +void restore_user_nice_safe(struct task_struct *p) +{ + long nice = PRIO_TO_NICE(p->cached_prio); + + if (rt_prio(p->prio)) + return; + + if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE) + return; + + if (task_on_rq_queued(p)) + return; + + if (task_current(task_rq(p), p)) + return; + + if (!time_after64(get_jiffies_64(), p->nice_effect_ts)) + return; + + p->static_prio = NICE_TO_PRIO(nice); + set_load_weight(p, true); + p->prio = effective_prio(p); + + /* update nice_effect_ts to ULLONG_MAX */ + p->nice_effect_ts = ULLONG_MAX; +} + +void set_user_nice_no_cache(struct task_struct *p, long nice) +{ + bool queued, running; + int old_prio, delta; + struct rq_flags rf; + struct rq *rq; + + if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE) + return; + + /* + * We have to be careful, if called from sys_setpriority(), + * the task might be in the middle of scheduling on another CPU. + */ + rq = task_rq_lock(p, &rf); + update_rq_clock(rq); + + /* + * The RT priorities are set via sched_setscheduler(), but we still + * allow the 'normal' nice value to be set - but as expected + * it wont have any effect on scheduling until the task is + * SCHED_DEADLINE, SCHED_FIFO or SCHED_RR: + */ + if (task_has_dl_policy(p) || task_has_rt_policy(p)) { + p->static_prio = NICE_TO_PRIO(nice); + goto out_unlock; + } + queued = task_on_rq_queued(p); + running = task_current(rq, p); + if (queued) + dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK); + if (running) + put_prev_task(rq, p); + + p->static_prio = NICE_TO_PRIO(nice); + set_load_weight(p, true); + old_prio = p->prio; + p->prio = effective_prio(p); + delta = p->prio - old_prio; + + if (queued) { + enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK); + /* + * If the task increased its priority or is running and + * lowered its priority, then reschedule its CPU: + */ + if (delta < 0 || (delta > 0 && task_running(rq, p))) + resched_curr(rq); + } + if (running) + set_curr_task(rq, p); +out_unlock: + task_rq_unlock(rq, p, &rf); +} +EXPORT_SYMBOL(set_user_nice_no_cache); +#endif + void set_user_nice(struct task_struct *p, long nice) { bool queued, running; @@ -4688,8 +4842,16 @@ void set_user_nice(struct task_struct *p, long nice) struct rq_flags rf; struct rq *rq; +#ifdef CONFIG_CONTROL_CENTER + if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE) { + p->cached_prio = p->static_prio; + return; + } +#else if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE) return; +#endif + /* * We have to be careful, if called from sys_setpriority(), * the task might be in the middle of scheduling on another CPU. @@ -4705,6 +4867,9 @@ void set_user_nice(struct task_struct *p, long nice) */ if (task_has_dl_policy(p) || task_has_rt_policy(p)) { p->static_prio = NICE_TO_PRIO(nice); +#ifdef CONFIG_CONTROL_CENTER + p->cached_prio = p->static_prio; +#endif goto out_unlock; } queued = task_on_rq_queued(p); @@ -4715,6 +4880,9 @@ void set_user_nice(struct task_struct *p, long nice) put_prev_task(rq, p); p->static_prio = NICE_TO_PRIO(nice); +#ifdef CONFIG_CONTROL_CENTER + p->cached_prio = p->static_prio; +#endif set_load_weight(p, true); old_prio = p->prio; p->prio = effective_prio(p); @@ -4880,7 +5048,12 @@ static void __setscheduler_params(struct task_struct *p, if (dl_policy(policy)) __setparam_dl(p, attr); else if (fair_policy(policy)) +#ifdef CONFIG_CONTROL_CENTER + p->cached_prio = + p->static_prio = NICE_TO_PRIO(attr->sched_nice); +#else p->static_prio = NICE_TO_PRIO(attr->sched_nice); +#endif /* * __sched_setscheduler() ensures attr->sched_priority == 0 when @@ -6798,7 +6971,7 @@ int sched_isolate_cpu(int cpu) goto out; } } - + tracing_mark_write(cpu, "isolated", 1); set_cpu_isolated(cpu, true); cpumask_clear_cpu(cpu, &avail_cpus); @@ -6847,7 +7020,7 @@ int sched_unisolate_cpu_unlocked(int cpu) if (--cpu_isolation_vote[cpu]) goto out; - + tracing_mark_write(cpu, "isolated", 0); set_cpu_isolated(cpu, false); update_max_interval(); sched_update_group_capacities(cpu); diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index dc695b0db063fe5a6ccd3ee6c37bf7e5c5c14931..35ca9c1ab1511a824b8f6b94ccfd9f8347a31e6c 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -20,6 +20,8 @@ #include "sched.h" #include "walt.h" +#include + struct cluster_data { bool inited; unsigned int min_cpus; @@ -46,6 +48,7 @@ struct cluster_data { struct task_struct *core_ctl_thread; unsigned int first_cpu; unsigned int boost; + unsigned int op_boost; struct kobject kobj; unsigned int strict_nrrun; }; @@ -329,6 +332,8 @@ static ssize_t show_global_state(const struct cluster_data *state, char *buf) cluster->nr_isolated_cpus); count += snprintf(buf + count, PAGE_SIZE - count, "\tBoost: %u\n", (unsigned int) cluster->boost); + count += snprintf(buf + count, PAGE_SIZE - count, + "\tOPBoost: %u\n", (unsigned int) cluster->op_boost); } spin_unlock_irq(&state_lock); @@ -764,6 +769,15 @@ static bool adjustment_possible(const struct cluster_data *cluster, return (need < cluster->active_cpus || (need > cluster->active_cpus && cluster->nr_isolated_cpus)); } +#define TRACE_DEBUG 0 + +static inline void tracing_mark_write(int serial, char *name, unsigned int value) +{ +#if TRACE_DEBUG + trace_printk("C|%d|%s|%u\n", 99990+serial, name, value); +#endif +} + static bool need_all_cpus(const struct cluster_data *cluster) { @@ -787,7 +801,7 @@ static bool eval_need(struct cluster_data *cluster) spin_lock_irqsave(&state_lock, flags); - if (cluster->boost || !cluster->enable || need_all_cpus(cluster)) { + if (cluster->boost || cluster->op_boost || !cluster->enable || need_all_cpus(cluster)) { need_cpus = cluster->max_cpus; } else { cluster->active_cpus = get_active_cpu_count(cluster); @@ -1247,6 +1261,48 @@ static int core_ctl_isolation_dead_cpu(unsigned int cpu) return isolation_cpuhp_state(cpu, false); } +int core_ctl_op_boost(bool boost, int level) +{ + unsigned int index = 0; + struct cluster_data *cluster; + unsigned long flags; + int ret = 0; + bool boost_state_changed = false; + int total_boost = -1; + + if (unlikely(!initialized)) + return 0; + + tracing_mark_write(0, "cctl_boost", boost); + spin_lock_irqsave(&state_lock, flags); + for_each_cluster(cluster, index) { + if (boost) { + boost_state_changed = !cluster->op_boost; + if (ccdm_get_hint(CCDM_TB_CCTL_BOOST) && cluster->op_boost == 0) + ++cluster->op_boost; + if (++total_boost == level) + break; + } else { + if (!cluster->op_boost) { + ret = -EINVAL; + break; + } + --cluster->op_boost; + boost_state_changed = !cluster->op_boost; + } + } + spin_unlock_irqrestore(&state_lock, flags); + + if (boost_state_changed) { + index = 0; + for_each_cluster(cluster, index) + apply_need(cluster); + } + + return ret; +} +EXPORT_SYMBOL(core_ctl_op_boost); + /* ============================ init code ============================== */ static struct cluster_data *find_cluster_by_first_cpu(unsigned int first_cpu) diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index af3f3c04c66e6d43f1a7bf8a2d931905992b2652..6b76840e0c417ee63293abbaa898c51a8f9545dd 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -17,6 +17,14 @@ #include #include +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#ifdef CONFIG_HOUSTON +#include +#endif + struct sugov_tunables { struct gov_attr_set attr_set; unsigned int up_rate_limit_us; @@ -235,6 +243,45 @@ static void sugov_calc_avg_cap(struct sugov_policy *sg_policy, u64 curr_ws, sg_policy->last_ws = curr_ws; } +#ifdef CONFIG_CONTROL_CENTER +unsigned int cc_cal_next_freq_with_extra_util( + struct cpufreq_policy *policy, + unsigned int next_freq +) +{ + /* scale util by turbo boost */ + int type = CCDM_TB_CLUS_0_FREQ_BOOST; + unsigned long extra_util = 0; + + switch (policy->cpu) { + case 4: case 5: case 6: + type = CCDM_TB_CLUS_1_FREQ_BOOST; + break; + case 7: + type = CCDM_TB_CLUS_2_FREQ_BOOST; + break; + } + + extra_util = ccdm_get_hint(type); + if (extra_util) { + unsigned long orig_util = 0; + unsigned long max = arch_scale_cpu_capacity(NULL, policy->cpu); + unsigned int freq = arch_scale_freq_invariant() ? + policy->cpuinfo.max_freq : policy->cur; + struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, policy->cpu); + + if (max) { + orig_util = freq_to_util(sg_cpu->sg_policy, next_freq); + extra_util = orig_util + extra_util * max / 100; + next_freq = freq * extra_util / max; + } + } + next_freq = cpufreq_driver_resolve_freq(policy, next_freq); + return next_freq; +} +EXPORT_SYMBOL(cc_cal_next_freq_with_extra_util); +#endif + static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time, unsigned int next_freq) { @@ -246,7 +293,7 @@ static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time, sugov_track_cycles(sg_policy, sg_policy->policy->cur, time); next_freq = cpufreq_driver_fast_switch(policy, next_freq); - if (!next_freq) + if (!next_freq || (next_freq == policy->cur)) return; policy->cur = next_freq; @@ -255,6 +302,7 @@ static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time, for_each_cpu(cpu, policy->cpus) trace_cpu_frequency(next_freq, cpu); } + cpufreq_stats_record_transition(policy, next_freq); } static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time, @@ -297,7 +345,25 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, struct cpufreq_policy *policy = sg_policy->policy; unsigned int freq = arch_scale_freq_invariant() ? policy->cpuinfo.max_freq : policy->cur; +#ifdef CONFIG_CONTROL_CENTER + unsigned int req_freq; + + freq = map_util_freq(util, freq, max); + + if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update) { + req_freq = sg_policy->next_freq; + goto out; + } + sg_policy->need_freq_update = false; + sg_policy->cached_raw_freq = freq; + req_freq = cpufreq_driver_resolve_freq(policy, freq); +out: + /* keep resolved freq */ + sg_policy->policy->req_freq = req_freq; + trace_sugov_next_freq(policy->cpu, util, max, freq, req_freq); + return req_freq; +#else freq = map_util_freq(util, freq, max); trace_sugov_next_freq(policy->cpu, util, max, freq); @@ -307,6 +373,7 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy, sg_policy->need_freq_update = false; sg_policy->cached_raw_freq = freq; return cpufreq_driver_resolve_freq(policy, freq); +#endif } /* @@ -653,6 +720,10 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, unsigned int next_f; bool busy; +#ifdef CONFIG_CONTROL_CENTER + struct cpufreq_policy *policy = sg_policy->policy; +#endif + if (!sg_policy->tunables->pl && flags & SCHED_CPUFREQ_PL) return; @@ -705,6 +776,10 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, sg_policy->cached_raw_freq = 0; } +#ifdef CONFIG_CONTROL_CENTER + next_f = cc_cal_next_freq_with_extra_util(policy, next_f); +#endif + /* * This code runs under rq->lock for the target CPU, so it won't run * concurrently on two different CPUs for the same target and it is not @@ -776,6 +851,10 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags) unsigned long hs_util, boost_util; unsigned int next_f; +#ifdef CONFIG_CONTROL_CENTER + struct cpufreq_policy *policy = sg_policy->policy; +#endif + if (!sg_policy->tunables->pl && flags & SCHED_CPUFREQ_PL) return; @@ -810,6 +889,10 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags) !(flags & SCHED_CPUFREQ_CONTINUE)) { next_f = sugov_next_freq_shared(sg_cpu, time); +#ifdef CONFIG_CONTROL_CENTER + next_f = cc_cal_next_freq_with_extra_util(policy, next_f); +#endif + if (sg_policy->policy->fast_switch_enabled) sugov_fast_switch(sg_policy, time, next_f); else @@ -1346,7 +1429,17 @@ static int sugov_start(struct cpufreq_policy *policy) policy_is_shared(policy) ? sugov_update_shared : sugov_update_single); + +#ifdef CONFIG_HOUSTON + ht_register_cpu_util(cpu, cpumask_first(policy->related_cpus), + &sg_cpu->util, &sg_policy->hispeed_util); +#endif } + +#ifdef CONFIG_CONTROL_CENTER + policy->cc_enable = true; +#endif + return 0; } @@ -1355,6 +1448,10 @@ static void sugov_stop(struct cpufreq_policy *policy) struct sugov_policy *sg_policy = policy->governor_data; unsigned int cpu; +#ifdef CONFIG_CONTROL_CENTER + policy->cc_enable = false; +#endif + for_each_cpu(cpu, policy->cpus) cpufreq_remove_update_util_hook(cpu); diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index c3092ff76ac2d1d7e1fea3dca56393cc4d2641e7..fe0d7b324cbfc15932265e3487af628c3efc70e6 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -999,6 +999,14 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns, #endif P(policy); P(prio); + +#ifdef CONFIG_CONTROL_CENTER + /* should remove later */ + P(static_prio); + P(normal_prio); + P(cached_prio); +#endif + if (p->policy == SCHED_DEADLINE) { P(dl.runtime); P(dl.deadline); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index da788314066a6977834b80a13043a67a2adcb9f3..d15c439b9db5d6186f2bc6f11a7b5c966d6d3e24 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -26,6 +26,34 @@ #include "walt.h" +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif + +#ifdef CONFIG_OPCHAIN +// morison.yan@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +#include +#endif + +#ifdef CONFIG_HOUSTON +#include +#endif + +#ifdef CONFIG_ONEPLUS_FG_OPT +extern unsigned int ht_fuse_boost; +#endif + +#ifdef CONFIG_IM +#include +#endif +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#ifdef CONFIG_TPD +#include +#endif + #ifdef CONFIG_SMP static inline bool task_fits_max(struct task_struct *p, int cpu); #endif /* CONFIG_SMP */ @@ -61,6 +89,7 @@ walt_dec_cfs_rq_stats(struct cfs_rq *cfs_rq, struct task_struct *p) {} #endif + /* * Targeted preemption latency for CPU-bound tasks: * @@ -87,6 +116,14 @@ unsigned int sysctl_sched_sync_hint_enable = 1; */ unsigned int sysctl_sched_cstate_aware = 1; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +extern void ohm_schedstats_record(int sched_type, struct task_struct *task, u64 delta); +#endif /*ifdef CONFIG_ONEPLUS_HEALTHINFO*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ +extern void update_stuck_trace_info(struct task_struct *tsk, int trace_type, unsigned int cpu, u64 delta); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + /* * The initial- and re-scaling of tunables is configurable * @@ -603,6 +640,36 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq) #endif } +#ifdef CONFIG_UXCHAIN +static u64 get_min_vruntime(struct cfs_rq *cfs_rq) +{ + struct sched_entity *curr = cfs_rq->curr; + struct rb_node *leftmost = rb_first_cached(&cfs_rq->tasks_timeline); + + u64 vruntime = cfs_rq->min_vruntime; + + if (curr) { + if (curr->on_rq) + vruntime = curr->vruntime; + else + curr = NULL; + } + + if (leftmost) { /* non-empty tree */ + struct sched_entity *se; + + se = rb_entry(leftmost, struct sched_entity, run_node); + + if (!curr) + vruntime = se->vruntime; + else + vruntime = min_vruntime(vruntime, se->vruntime); + } + + return min_vruntime(cfs_rq->min_vruntime, vruntime); +} +#endif + /* * Enqueue an entity into the rb-tree: */ @@ -883,6 +950,11 @@ static void update_curr(struct cfs_rq *cfs_rq) u64 now = rq_clock_task(rq_of(cfs_rq)); u64 delta_exec; +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + u64 window_index = sample_window.window_index; + bool index = ODD(window_index); +#endif + if (unlikely(!curr)) return; @@ -904,9 +976,38 @@ static void update_curr(struct cfs_rq *cfs_rq) if (entity_is_task(curr)) { struct task_struct *curtask = task_of(curr); +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + if (window_index != curtask->tli[index].task_sample_index) { + curtask->tli[index].task_sample_index = window_index; + curtask->tli[index].write_bytes = 0; + curtask->tli[index].read_bytes = 0; + if (current_is_fg()) { + curtask->tli[index].runtime[1] = delta_exec; + curtask->tli[index].runtime[0] = 0; + } else { + curtask->tli[index].runtime[0] = delta_exec; + curtask->tli[index].runtime[1] = 0; + } + curtask->tli[index].tli_overload_flag = 0; + } else { + if (current_is_fg()) { + curtask->tli[index].runtime[1] += delta_exec; + if (curtask->tli[index].runtime[1] > ohm_runtime_thresh_fg) + curtask->tli[index].tli_overload_flag |= TASK_CPU_OVERLOAD_FG_FLAG; + } else { + curtask->tli[index].runtime[0] += delta_exec; + if (curtask->tli[index].runtime[0] > ohm_runtime_thresh_bg) + curtask->tli[index].tli_overload_flag |= TASK_CPU_OVERLOAD_BG_FLAG; + } + } +#endif trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime); cgroup_account_cputime(curtask, delta_exec); account_group_exec_runtime(curtask, delta_exec); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + update_stuck_trace_info(curtask, STUCK_TRACE_RUNNING, cpu_of(rq_of(cfs_rq)), delta_exec); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ } account_cfs_rq_runtime(cfs_rq, delta_exec); @@ -934,6 +1035,11 @@ update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se) __schedstat_set(se->statistics.wait_start, wait_start); } +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +//2020-04-30 +extern void ohm_schedstats_record(int sched_type, struct task_struct *task, u64 delta); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ static inline void update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) @@ -957,6 +1063,14 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) __schedstat_set(se->statistics.wait_start, delta); return; } +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + ohm_schedstats_record(OHM_SCHED_SCHEDLATENCY, p, (delta >> 20)); +#endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + update_stuck_trace_info(p, STUCK_TRACE_RUNNABLE, 0, delta); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ trace_sched_stat_wait(p, delta); } @@ -965,6 +1079,7 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) __schedstat_inc(se->statistics.wait_count); __schedstat_add(se->statistics.wait_sum, delta); __schedstat_set(se->statistics.wait_start, 0); + } static inline void @@ -997,6 +1112,10 @@ update_stats_enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) if (tsk) { account_scheduler_latency(tsk, delta >> 10, 1); trace_sched_stat_sleep(tsk, delta); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + update_stuck_trace_info(tsk, STUCK_TRACE_SSTATE, 0, delta); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ } } if (block_start) { @@ -1016,8 +1135,21 @@ update_stats_enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) __schedstat_add(se->statistics.iowait_sum, delta); __schedstat_inc(se->statistics.iowait_count); trace_sched_stat_iowait(tsk, delta); +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + ohm_schedstats_record(OHM_SCHED_IOWAIT, tsk, + (delta >> 20)); +#endif } - +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (!tsk->in_iowait) + ohm_schedstats_record(OHM_SCHED_DSTATE, tsk, (delta >> 20)); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ + +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-17, add for stuck monitor*/ + update_stuck_trace_info(tsk, STUCK_TRACE_DSTATE, 0, delta); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ trace_sched_stat_blocked(tsk, delta); trace_sched_blocked_reason(tsk); @@ -3926,9 +4058,31 @@ bias_to_this_cpu(struct task_struct *p, int cpu, int start_cpu) { bool base_test = cpumask_test_cpu(cpu, &p->cpus_allowed) && cpu_active(cpu); + bool start_cap_test = (capacity_orig_of(cpu) >= capacity_orig_of(start_cpu)); +#ifdef CONFIG_TPD + struct root_domain *rd = cpu_rq(smp_processor_id())->rd; + cpumask_t mask = CPU_MASK_ALL; +#endif + + if (is_ratp_enable() && + (!(im_rendering(p) && prefer_sched_group(p)) || + (!(is_gmod_enable() && prefer_top(p))))) + base_test = cpumask_test_cpu(cpu, &p->cpus_suggested) && + cpu_active(cpu); + +#ifdef CONFIG_TPD + if (is_tpd_enable() && is_tpd_task(p)) { + + tpd_mask(p, rd->min_cap_orig_cpu, + rd->mid_cap_orig_cpu == -1 ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu, + rd->max_cap_orig_cpu, &mask, nr_cpu_ids); + base_test = cpumask_test_cpu(cpu, &mask) && cpu_active(cpu); + } +#endif + return base_test && start_cap_test; } @@ -3993,6 +4147,9 @@ struct find_best_target_env { bool is_rtg; bool boosted; bool strict_max; +#ifdef CONFIG_OPCHAIN + int op_path; +#endif }; static inline void adjust_cpus_for_packing(struct task_struct *p, @@ -4145,6 +4302,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial) } } #endif + if (is_ratp_enable() && + entity_is_task(se) && + ((im_rendering(task_of(se)) && prefer_sched_group(task_of(se))) || + (is_gmod_enable() && prefer_top(task_of(se))))) + vruntime -= sysctl_sched_latency; } /* ensure we never gain time by being placed backwards. */ @@ -4209,6 +4371,9 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) { bool renorm = !(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_MIGRATED); bool curr = cfs_rq->curr == se; +#ifdef CONFIG_UXCHAIN + bool boost_flag = 0; +#endif /* * If we're the current task, we must renormalise before calling @@ -4228,6 +4393,28 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) if (renorm && !curr) se->vruntime += cfs_rq->min_vruntime; +#ifdef CONFIG_UXCHAIN + if (entity_is_task(se) && sysctl_uxchain_enabled) { + struct task_struct *tsk = task_of(se); + + if (is_opc_task(tsk, UT_FORE) && !tsk->dynamic_ux) + tsk->dynamic_ux = 1; + + if (tsk->static_ux || tsk->dynamic_ux) { + u64 raw_vruntime; + u64 min_vruntime; + + raw_vruntime = se->vruntime; + min_vruntime = get_min_vruntime(cfs_rq); + se->vruntime = min_vruntime - + (sysctl_sched_wakeup_granularity << 3); + if (raw_vruntime > se->vruntime) + se->vruntime_minus = raw_vruntime - se->vruntime; + boost_flag = 1; + } + } +#endif + /* * When enqueuing a sched_entity, we must: * - Update loads to have both entity and cfs_rq synced with now. @@ -4241,8 +4428,13 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) enqueue_runnable_load_avg(cfs_rq, se); account_entity_enqueue(cfs_rq, se); +#ifdef CONFIG_UXCHAIN + if (flags & ENQUEUE_WAKEUP && !boost_flag) + place_entity(cfs_rq, se, 0); +#else if (flags & ENQUEUE_WAKEUP) place_entity(cfs_rq, se, 0); +#endif check_schedstat_required(); update_stats_enqueue(cfs_rq, se, flags); @@ -4332,6 +4524,20 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) se->on_rq = 0; account_entity_dequeue(cfs_rq, se); +#ifdef CONFIG_UXCHAIN + if (entity_is_task(se) && sysctl_uxchain_enabled) { + struct task_struct *tsk = task_of(se); + + if ((tsk->static_ux || tsk->dynamic_ux) && + se->vruntime_minus > 0){ + se->vruntime += se->vruntime_minus; + se->vruntime_minus = 0; + } + if (is_opc_task(tsk, UT_FORE) && tsk->dynamic_ux) + tsk->dynamic_ux = 0; + } +#endif + /* * Normalize after update_curr(); which will also have moved * min_vruntime if @se is the one holding it back. But before doing @@ -4366,6 +4572,18 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) struct sched_entity *se; s64 delta; +#ifdef CONFIG_UXCHAIN + if (entity_is_task(curr) && sysctl_uxchain_enabled) { + struct task_struct *tsk = task_of(curr); + u64 wallclock = sched_ktime_clock(); + + if ((tsk->static_ux || tsk->dynamic_ux) && + (sysctl_launcher_boost_enabled || + wallclock - tsk->oncpu_time < PREEMPT_DISABLE_NS)) + return; + } +#endif + ideal_runtime = sched_slice(cfs_rq, curr); delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; if (delta_exec > ideal_runtime) { @@ -5473,6 +5691,11 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct cfs_rq *cfs_rq; struct sched_entity *se = &p->se; +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + opc_task_switch(true, cpu_of(rq), p, 0); +#endif + /* * The code below (indirectly) updates schedutil which looks at * the cfs_rq utilization to select a frequency. @@ -5596,6 +5819,11 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) struct sched_entity *se = &p->se; int task_sleep = flags & DEQUEUE_SLEEP; +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + opc_task_switch(false, cpu_of(rq), p, rq->clock); +#endif + /* * The code below (indirectly) updates schedutil which looks at * the cfs_rq utilization to select a frequency. @@ -6872,14 +7100,48 @@ static int get_start_cpu(struct task_struct *p) task_boost == TASK_BOOST_ON_MID; bool task_skip_min = task_skip_min_cpu(p); +#ifdef CONFIG_HOUSTON + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + bool is_uxtop = is_opc_task(p, UT_FORE); +#endif +#ifdef CONFIG_RATP + struct cpumask new_mask = CPU_MASK_ALL; + + /*reset cpus_suggest for monitor*/ + cpumask_copy(&p->cpus_suggested, &new_mask); +#endif + +#ifdef CONFIG_HOUSTON + if (is_uxtop && current->ravg.demand_scaled >= p->ravg.demand_scaled) { + /* add 'current' into RTG list */ + ht_rtg_list_add_tail(current); + } +#endif + +#ifdef CONFIG_ONEPLUS_FG_OPT + if (ht_fuse_boost && p->fuse_boost) + return rd->mid_cap_orig_cpu == -1 ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; +#endif + /* * note about min/mid/max_cap_orig_cpu - either all of them will be -ve * or just mid will be -1, there never be any other combinations of -1s * beyond these */ + if (task_skip_min || boosted) { - start_cpu = rd->mid_cap_orig_cpu == -1 ? - rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + /*limit the passerby to the gold/gold+ cores*/ + if (is_ratp_enable()) { + if ((im_rendering(p) && prefer_sched_group(p)) || + (is_gmod_enable() && prefer_top(p))) { + start_cpu = rd->mid_cap_orig_cpu == -1 ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + } + } else { + start_cpu = rd->mid_cap_orig_cpu == -1 ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + } } if (task_boost > TASK_BOOST_ON_MID) { @@ -6900,6 +7162,58 @@ static int get_start_cpu(struct task_struct *p) !task_demand_fits(p, start_cpu)) start_cpu = rd->max_cap_orig_cpu; +#ifdef CONFIG_RATP + /* rock.lin@OPTI, 2020/6/8, add for CONFIG_RATP */ + /* refine the start cpu if RATP enable*/ + if (is_ratp_enable()) { + if (start_cpu == rd->min_cap_orig_cpu) { + /* forced place to gold/gold+ cores even if workload of task is low*/ + /* rendering task or game top app*/ + if (is_gmod_enable() && prefer_top(p)) + start_cpu = rd->mid_cap_orig_cpu == -1 ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + else { + /* force limit cpu selection for non-rendering tasks */ + if (!(im_rendering(p) && prefer_sched_group(p)) && + !(is_gmod_enable() && prefer_top(p))) { + cpumask_clear_cpu( + (rd->mid_cap_orig_cpu == -1) ? + rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu, + &p->cpus_suggested); + cpumask_clear_cpu(rd->max_cap_orig_cpu, &p->cpus_suggested); + } + } + } else { + /*we limit the big task(that hasn't any impact for Rendering) into sliver core*/ + if (!(im_rendering(p) && prefer_sched_group(p)) && !(is_gmod_enable() && prefer_top(p))) { + cpumask_clear_cpu( + (rd->mid_cap_orig_cpu == -1) ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu, + &p->cpus_suggested); + cpumask_clear_cpu(rd->max_cap_orig_cpu, &p->cpus_suggested); + start_cpu = rd->min_cap_orig_cpu; + } + } + } + + trace_sched_cpu_sel(p, + task_boost, + task_skip_min, + boosted, + task_boost_policy(p), + task_demand_fits(p, rd->min_cap_orig_cpu), + task_demand_fits(p, (rd->mid_cap_orig_cpu == -1) ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu), + task_demand_fits(p, rd->max_cap_orig_cpu), + start_cpu, is_ratp_enable()); +#endif + +#ifdef CONFIG_TPD + if ((is_dynamic_tpd_task(p) || is_tpd_task(p)) && is_tpd_enable()) { + start_cpu = tpd_suggested(p, rd->min_cap_orig_cpu, + rd->mid_cap_orig_cpu == -1 ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu, + rd->max_cap_orig_cpu, start_cpu); + } +#endif + return start_cpu; } @@ -6909,6 +7223,7 @@ enum fastpaths { PREV_CPU_FASTPATH, }; +unsigned int sysctl_sched_skip_affinity; static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, struct task_struct *p, struct find_best_target_env *fbt_env) @@ -6936,8 +7251,13 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, int prev_cpu = task_cpu(p); bool next_group_higher_cap = false; int isolated_candidate = -1; + bool is_rtg; + cpumask_t new_allowed_cpus; unsigned int target_nr_rtg_high_prio = UINT_MAX; bool rtg_high_prio_task = task_rtg_high_prio(p); +#ifdef CONFIG_TPD + struct root_domain *rd = cpu_rq(smp_processor_id())->rd; +#endif /* * In most cases, target_capacity tracks capacity_orig of the most @@ -6976,11 +7296,34 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, goto target; } } - /* Scan CPUs in all SDs */ sg = start_sd->groups; + is_rtg = task_in_related_thread_group(p); + if (sysctl_sched_skip_affinity && is_rtg) + cpumask_setall(&new_allowed_cpus); +#ifdef CONFIG_RATP + else { + if (is_ratp_enable() && + !(im_rendering(p) && prefer_sched_group(p)) && !(is_gmod_enable() && prefer_top(p))) + cpumask_copy(&new_allowed_cpus, &p->cpus_suggested); + else + cpumask_copy(&new_allowed_cpus, &p->cpus_allowed); + } +#else + else + cpumask_copy(&new_allowed_cpus, &p->cpus_allowed); +#endif + +#ifdef CONFIG_TPD + if (is_tpd_enable() && is_tpd_task(p)) { + tpd_mask(p, rd->min_cap_orig_cpu, + rd->mid_cap_orig_cpu == -1 ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu, + rd->max_cap_orig_cpu, &new_allowed_cpus, nr_cpu_ids); + } +#endif do { - for_each_cpu_and(i, &p->cpus_allowed, sched_group_span(sg)) { + //for_each_cpu_and(i, &p->cpus_allowed, sched_group_span(sg)) { + for_each_cpu_and(i, &new_allowed_cpus, sched_group_span(sg)) { unsigned long capacity_curr = capacity_curr_of(i); unsigned long capacity_orig = capacity_orig_of(i); unsigned long wake_util, new_util, new_util_cuml; @@ -6992,6 +7335,21 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, if (!cpu_online(i) || cpu_isolated(i)) continue; +#ifdef CONFIG_UXCHAIN + if (current->static_ux == 1 && + current->group_leader == current && sysctl_uxchain_enabled && + sysctl_launcher_boost_enabled && i == smp_processor_id()) + continue; + + if (sysctl_uxchain_enabled && ux_thread(p)) { + struct rq *rq = cpu_rq(i); + struct task_struct *tsk = rq->curr; + + if (ux_thread(tsk) || tsk->normal_prio <= 100) + continue; + } +#endif + if (isolated_candidate == -1) isolated_candidate = i; @@ -7014,7 +7372,13 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, * so prev_cpu will receive a negative bias due to the double * accounting. However, the blocked utilization may be zero. */ +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/12/13, add for uxrealm + wake_util = opc_cpu_util(cpu_util_without(i, p), + i, p, fbt_env->op_path); +#else wake_util = cpu_util_without(i, p); +#endif new_util = wake_util + task_util_est(p); spare_wake_cap = capacity_orig - wake_util; @@ -7358,6 +7722,24 @@ static void find_best_target(struct sched_domain *sd, cpumask_t *cpus, cpu_isolated(prev_cpu)) target_cpu = isolated_candidate; +#ifdef CONFIG_UXCHAIN + if (sysctl_uxchain_enabled && ux_thread(p) && target_cpu == -1) { + sg = start_sd->groups; + do { + for_each_cpu_and(i, &p->cpus_allowed, sched_group_span(sg)) { + struct rq *rq = cpu_rq(i); + struct task_struct *tsk = rq->curr; + + if (!ux_thread(tsk) && tsk->normal_prio > 100) { + target_cpu = i; + break; + } + } + if (target_cpu != -1) + break; + } while (sg = sg->next, sg != start_sd->groups); + } +#endif if (backup_cpu >= 0) cpumask_set_cpu(backup_cpu, cpus); if (target_cpu >= 0) { @@ -7724,12 +8106,20 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int task_boost = per_task_boost(p); int boosted = (schedtune_task_boost(p) > 0) || (task_boost > 0); int start_cpu; +#ifdef CONFIG_OPCHAIN + bool is_uxtop; +#endif if (is_many_wakeup(sibling_count_hint) && prev_cpu != cpu && cpumask_test_cpu(prev_cpu, &p->cpus_allowed)) return prev_cpu; start_cpu = get_start_cpu(p); +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + is_uxtop = is_opc_task(p, UT_FORE); + fbt_env.op_path = opc_select_path(current, p, prev_cpu); +#endif if (start_cpu < 0) goto eas_not_ready; @@ -7739,6 +8129,14 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, fbt_env.fastpath = 0; fbt_env.need_idle = need_idle; +#ifdef CONFIG_UXCHAIN + if (p->static_ux == 1 && p->group_leader == p && + sysctl_uxchain_enabled && sysctl_launcher_boost_enabled) { + if (cpu_online(GOLD_PLUS_CPU) && !cpu_isolated(GOLD_PLUS_CPU)) + return GOLD_PLUS_CPU; + } +#endif + if (trace_sched_task_util_enabled()) start_t = sched_clock(); @@ -7748,9 +8146,16 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, if (sync && (need_idle || (is_rtg && curr_is_rtg))) sync = 0; +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + if (sysctl_sched_sync_hint_enable && sync && + bias_to_this_cpu(p, cpu, start_cpu) && + opc_check_uxtop_cpu(is_uxtop, cpu)) { +#else if (sysctl_sched_sync_hint_enable && sync && bias_to_this_cpu(p, cpu, start_cpu)) { +#endif best_energy_cpu = cpu; fbt_env.fastpath = SYNC_WAKEUP; goto done; @@ -7826,9 +8231,17 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, if (p->state == TASK_WAKING) delta = task_util(p); #endif + +#ifdef CONFIG_TPD + if (task_placement_boost_enabled(p) || fbt_env.need_idle || boosted || + is_rtg || __cpu_overutilized(prev_cpu, delta) || + !task_fits_max(p, prev_cpu) || cpu_isolated(prev_cpu) || is_ratp_enable() || + is_tpd_enable()) { +#else if (task_placement_boost_enabled(p) || fbt_env.need_idle || boosted || is_rtg || __cpu_overutilized(prev_cpu, delta) || - !task_fits_max(p, prev_cpu) || cpu_isolated(prev_cpu)) { + !task_fits_max(p, prev_cpu) || cpu_isolated(prev_cpu) || is_ratp_enable()) { +#endif best_energy_cpu = cpu; goto unlock; } @@ -7870,11 +8283,16 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, best_energy_cpu = prev_cpu; done: - +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN trace_sched_task_util(p, cpumask_bits(candidates)[0], best_energy_cpu, - sync, fbt_env.need_idle, fbt_env.fastpath, - placement_boost, start_t, boosted, is_rtg, - get_rtg_status(p), start_cpu); + sync, fbt_env.need_idle, fbt_env.fastpath, placement_boost, + start_t, boosted, is_rtg, get_rtg_status(p), is_uxtop); +#else + trace_sched_task_util(p, cpumask_bits(candidates)[0], best_energy_cpu, + sync, fbt_env.need_idle, fbt_env.fastpath,placement_boost, + start_t, boosted, is_rtg, get_rtg_status(p), start_cpu); +#endif return best_energy_cpu; @@ -7912,6 +8330,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f sibling_count_hint); if (unlikely(new_cpu < 0)) new_cpu = prev_cpu; + cpu_dist_inc(p, cpu); rcu_read_unlock(); return new_cpu; } @@ -7971,6 +8390,8 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f if (want_affine) current->recent_used_cpu = cpu; } + + cpu_dist_inc(p, cpu); rcu_read_unlock(); return new_cpu; @@ -8558,6 +8979,12 @@ enum group_type { #define LBF_IGNORE_BIG_TASKS 0x100 #define LBF_IGNORE_PREFERRED_CLUSTER_TASKS 0x200 +#ifdef CONFIG_OPCHAIN +// curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +#define LBF_IGNORE_UX_TOP 0x800 +#define LBF_IGNORE_SLAVE 0xC00 +#endif + struct lb_env { struct sched_domain *sd; @@ -8683,10 +9110,41 @@ static inline int migrate_degrades_locality(struct task_struct *p, static inline bool can_migrate_boosted_task(struct task_struct *p, int src_cpu, int dst_cpu) { +#if defined(CONFIG_RATP) || defined(CONFIG_TPD) + struct root_domain *rd = cpu_rq(smp_processor_id())->rd; +#endif + +#ifdef CONFIG_TPD + int mid_core; +#endif + +#ifdef CONFIG_RATP + if (is_ratp_enable()) { + /*avoid rendering task migrate to sliver core*/ + if (im_rendering(p) && prefer_sched_group(p) && + (capacity_orig_of(dst_cpu) < capacity_orig_of(src_cpu)) && + (capacity_orig_of(dst_cpu) == capacity_orig_of(rd->min_cap_orig_cpu))) + return false; + + if (!cpumask_test_cpu(dst_cpu, &p->cpus_suggested)) + return false; + } +#endif + +#ifdef CONFIG_TPD + if (is_tpd_enable() && is_tpd_task(p)) { + /*avoid task migrate to wrong tpd suggested cpu*/ + mid_core = rd->mid_cap_orig_cpu == -1 ? rd->max_cap_orig_cpu : rd->mid_cap_orig_cpu; + if (tpd_check(p, dst_cpu, rd->min_cap_orig_cpu, mid_core, rd->max_cap_orig_cpu)) + return false; + } +#endif + if (per_task_boost(p) == TASK_BOOST_STRICT_MAX && task_in_related_thread_group(p) && (capacity_orig_of(dst_cpu) < capacity_orig_of(src_cpu))) return false; + return true; } @@ -8778,6 +9236,14 @@ int can_migrate_task(struct task_struct *p, struct lb_env *env) return 0; #endif +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + if (env->flags & LBF_IGNORE_UX_TOP && is_opc_task(p, UT_FORE)) + return 0; + if (env->flags & LBF_IGNORE_SLAVE && UTASK_SLAVE(p)) + return 0; +#endif + /* Don't detach task if it is under active migration */ if (env->src_rq->push_task == p) return 0; @@ -8875,6 +9341,10 @@ static int detach_tasks(struct lb_env *env) unsigned long load = 0; int detached = 0; int orig_loop = env->loop; +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + int src_claim = opc_get_claim_on_cpu(env->src_cpu); +#endif u64 start_t = rq_clock(env->src_rq); lockdep_assert_held(&env->src_rq->lock); @@ -8886,9 +9356,20 @@ static int detach_tasks(struct lb_env *env) if (!same_cluster(env->dst_cpu, env->src_cpu)) env->flags |= LBF_IGNORE_PREFERRED_CLUSTER_TASKS; +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + if (capacity_of(env->dst_cpu) < capacity_of(env->src_cpu)) { + env->flags |= LBF_IGNORE_BIG_TASKS; + if (src_claim == 1) + env->flags |= LBF_IGNORE_UX_TOP | LBF_IGNORE_SLAVE; + else if (src_claim == -1) + env->flags |= LBF_IGNORE_SLAVE; + } +#else if (capacity_orig_of(env->dst_cpu) < capacity_orig_of(env->src_cpu)) env->flags |= LBF_IGNORE_BIG_TASKS; +#endif } redo: @@ -8982,6 +9463,12 @@ static int detach_tasks(struct lb_env *env) tasks = &env->src_rq->cfs_tasks; env->flags &= ~(LBF_IGNORE_BIG_TASKS | LBF_IGNORE_PREFERRED_CLUSTER_TASKS); +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + if (env->flags & LBF_IGNORE_SLAVE) + env->flags &= ~LBF_IGNORE_SLAVE; +#endif + env->loop = orig_loop; goto redo; } diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 25e643cff3cba8fc33edcee4cd6b8dfcb50cf83a..01e2b0fc48f5a79c503c57b65b27adf6a2299109 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -12,6 +12,23 @@ #include #include "walt.h" +#ifdef CONFIG_OPCHAIN +// morison.yan@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN +#include +#endif + +#ifdef CONFIG_CONTROL_CENTER +#include +#endif + +#ifdef CONFIG_IM +#include +#endif + +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif/**/ int sched_rr_timeslice = RR_TIMESLICE; int sysctl_sched_rr_timeslice = (MSEC_PER_SEC / HZ) * RR_TIMESLICE; @@ -1035,6 +1052,11 @@ static void update_curr_rt(struct rq *rq) u64 delta_exec; u64 now; +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + u64 window_index = sample_window.window_index; + bool index = ODD(window_index); +#endif + if (curr->sched_class != &rt_sched_class) return; @@ -1048,6 +1070,38 @@ static void update_curr_rt(struct rq *rq) curr->se.sum_exec_runtime += delta_exec; account_group_exec_runtime(curr, delta_exec); +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (ohm_rtinfo_ctrl == true) + rt_total_record(delta_exec, cpu_of(rq)); +#endif + +#ifdef CONFIG_ONEPLUS_TASKLOAD_INFO + curr->tli[index].tli_overload_flag |= TASK_RT_THREAD_FLAG; + if (window_index != curr->tli[index].task_sample_index) { + curr->tli[index].task_sample_index = window_index; + curr->tli[index].write_bytes = 0; + curr->tli[index].read_bytes = 0; + if (current_is_fg()) { + curr->tli[index].runtime[1] = delta_exec; + curr->tli[index].runtime[0] = 0; + } else { + curr->tli[index].runtime[0] = delta_exec; + curr->tli[index].runtime[1] = 0; + } + curr->tli[index].tli_overload_flag = 0; + } else { + if (current_is_fg()) { + curr->tli[index].runtime[1] += delta_exec; + if (curr->tli[index].runtime[1] > ohm_runtime_thresh_fg) + curr->tli[index].tli_overload_flag |= TASK_CPU_OVERLOAD_FG_FLAG; + } else { + curr->tli[index].runtime[0] += delta_exec; + if (curr->tli[index].runtime[0] > ohm_runtime_thresh_bg) + curr->tli[index].tli_overload_flag |= TASK_CPU_OVERLOAD_BG_FLAG; + } + } +#endif curr->se.exec_start = now; cgroup_account_cputime(curr, delta_exec); @@ -1064,6 +1118,11 @@ static void update_curr_rt(struct rq *rq) if (sched_rt_runtime_exceeded(rt_rq)) resched_curr(rq); raw_spin_unlock(&rt_rq->rt_runtime_lock); +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (ohm_rtinfo_ctrl == true) + rt_info_record(rt_rq, cpu_of(rq_of_rt_rq(rt_rq))); +#endif } } } @@ -1425,6 +1484,10 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) schedtune_dequeue_task(p, cpu_of(rq)); update_curr_rt(rq); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + p->rtend_time = rq_clock_task(rq); +#endif dequeue_rt_entity(rt_se, flags); walt_dec_cumulative_runnable_avg(rq, p); @@ -1553,6 +1616,7 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags, p->prio < cpu_rq(target)->rt.highest_prio.curr)) cpu = target; } + cpu_dist_inc(p, cpu); rcu_read_unlock(); out: @@ -1647,7 +1711,10 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq) p = rt_task_of(rt_se); p->se.exec_start = rq_clock_task(rq); - +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-06-20 [OSP-5970] add for add for healthinfo--rt record */ + p->rtstart_time = rq_clock_task(rq); +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ return p; } @@ -1772,6 +1839,15 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) int cpu_idle_idx = -1; bool boost_on_big = rt_boost_on_big(); +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + bool best_cpu_is_claimed = false; +#endif + + /* For surfaceflinger with util > 90, prefer to use big core */ + if (task->compensate_need == 2 && tutil > 90) + boost_on_big = true; + rcu_read_lock(); cpu = cpu_rq(smp_processor_id())->rd->min_cap_orig_cpu; @@ -1781,7 +1857,11 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) sd = rcu_dereference(*per_cpu_ptr(&sd_asym_cpucapacity, cpu)); if (!sd) goto unlock; - +#if defined(CONFIG_CONTROL_CENTER) && defined(CONFIG_IM) + boost_on_big = boost_on_big | + im_hwc(task) | // HWC select big core first + (im_sf(task) && ccdm_get_hint(CCDM_TB_PLACE_BOOST)); +#endif retry: sg = sd->groups; do { @@ -1797,6 +1877,14 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) } for_each_cpu_and(cpu, lowest_mask, sched_group_span(sg)) { +#ifdef CONFIG_UXCHAIN + struct rq *rq = cpu_rq(cpu); + struct task_struct *tsk = rq->curr; + + if (tsk->static_ux && tsk == tsk->group_leader && + sysctl_launcher_boost_enabled && sysctl_uxchain_enabled) + continue; +#endif trace_sched_cpu_util(cpu); @@ -1810,6 +1898,17 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) continue; util = cpu_util(cpu); +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + if (best_cpu_is_claimed) { + best_cpu_idle_idx = cpu_idle_idx; + best_cpu_util_cum = util_cum; + best_cpu_util = util; + best_cpu = cpu; + best_cpu_is_claimed = false; + continue; + } +#endif /* Find the least loaded CPU */ if (util > best_cpu_util) @@ -1842,6 +1941,16 @@ static int rt_energy_aware_wake_cpu(struct task_struct *task) continue; } +#ifdef CONFIG_OPCHAIN + // curtis@ASTI, 2019/4/29, add for uxrealm CONFIG_OPCHAIN + if (opc_get_claim_on_cpu(cpu)) { + if (best_cpu != -1) + continue; + else + best_cpu_is_claimed = true; + } +#endif + best_cpu_idle_idx = cpu_idle_idx; best_cpu_util_cum = util_cum; best_cpu_util = util; diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 3a79dfde98821d2cd5201289520163532f2cc57a..87dfc8605215f61a563168b3f5d2f62187bab9c3 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -83,6 +83,10 @@ #endif #include "tune.h" +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#include +#endif /*CONFIG_ONEPLUS_HEALTHINFO*/ struct rq; struct cpuidle_state; @@ -91,6 +95,14 @@ extern __read_mostly bool sched_predl; extern unsigned int sched_capacity_margin_up[NR_CPUS]; extern unsigned int sched_capacity_margin_down[NR_CPUS]; +#if defined(CONFIG_IM) || defined(CONFIG_HOUSTON) +extern int group_show(struct seq_file *m, void *v); +extern void group_remove(void); +#else +static inline int group_show(struct seq_file *m, void *v) {return 0; } +static inline void group_remove(void) {} +#endif + struct sched_walt_cpu_load { unsigned long nl; unsigned long pl; @@ -98,6 +110,7 @@ struct sched_walt_cpu_load { u64 ws; }; +extern unsigned int sysctl_sched_skip_affinity; #ifdef CONFIG_SCHED_WALT extern unsigned int sched_ravg_window; @@ -143,6 +156,10 @@ struct sched_cluster { unsigned int max_possible_freq; bool freq_init_done; u64 aggr_grp_load; +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo--overload*/ + struct sched_stat_para *overload; +#endif }; extern cpumask_t asym_cap_sibling_cpus; @@ -1113,7 +1130,13 @@ struct rq { #ifdef CONFIG_SMP struct llist_head wake_list; #endif - +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + unsigned int ux_nr_running; + u64 cfs_ol_start; + u64 ux_ol_start; + u64 irqsoff_start_time; +#endif #ifdef CONFIG_CPU_IDLE /* Must be inspected within a rcu lock section */ struct cpuidle_state *idle_state; @@ -2046,7 +2069,11 @@ static inline void add_nr_running(struct rq *rq, unsigned count) sched_update_nr_prod(cpu_of(rq), count, true); rq->nr_running = prev_nr + count; - +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + if (prev_nr <= 5 && rq->nr_running > 5) + rq->cfs_ol_start = rq_clock(rq); +#endif if (prev_nr < 2 && rq->nr_running >= 2) { #ifdef CONFIG_SMP if (!READ_ONCE(rq->rd->overload)) @@ -2059,8 +2086,21 @@ static inline void add_nr_running(struct rq *rq, unsigned count) static inline void sub_nr_running(struct rq *rq, unsigned count) { +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-06-20 [OSP-5970] add for healthinfo*/ + u64 delta; + unsigned int prev_nr = rq->nr_running; +#endif sched_update_nr_prod(cpu_of(rq), count, false); rq->nr_running -= count; +#ifdef CONFIG_ONEPLUS_HEALTHINFO + /*2020-06-20 [OSP-5970] add for healthinfo*/ + if (prev_nr > 5 && rq->nr_running <= 5) { + delta = rq_clock(rq) - rq->cfs_ol_start; + rq->cfs_ol_start = 0; + ohm_overload_record(rq, (delta >> 20)); + } +#endif /* Check if we still need preemption */ sched_update_tick_dependency(rq); } diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 93e3acf0e0aa44e2221ba0275f7d4ebf11730ed1..5202f1341c79e5302cd9d378a15c81076076cdfd 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -634,6 +634,56 @@ int schedtune_task_boost(struct task_struct *p) return task_boost; } +#ifdef CONFIG_RATP + +bool prefer_sched_group(struct task_struct *p) +{ + struct schedtune *st; + int idx; + bool ret = false; + + if (unlikely(!schedtune_initialized)) + return 0; + + /* Get task boost value */ + rcu_read_lock(); + st = task_schedtune(p); + idx = st->idx; + //cgroup_name(st->css.cgroup, name_buf, GROUP_NAME_MAX + 1); + rcu_read_unlock(); + + if (idx == stune_map[STUNE_FG - 1] || idx == stune_map[STUNE_TOP - 1]) + ret = true; + + trace_sched_tune_group(p, idx, ret); + + return ret; +} + +bool prefer_top(struct task_struct *p) +{ + struct schedtune *st; + int idx; + bool ret = false; + + if (unlikely(!schedtune_initialized)) + return 0; + + /* Get task boost value */ + rcu_read_lock(); + st = task_schedtune(p); + idx = st->idx; + rcu_read_unlock(); + + if (idx == stune_map[STUNE_TOP - 1]) + ret = true; + + trace_sched_tune_group(p, idx, ret); + + return ret; +} +#endif + int schedtune_prefer_idle(struct task_struct *p) { struct schedtune *st; diff --git a/kernel/sched/tune.h b/kernel/sched/tune.h index 5ba191b94e153c30e38f10bf46d0a13002093b48..d50bf8b68c175f2a07f0ba7f4b49f0438b116387 100644 --- a/kernel/sched/tune.h +++ b/kernel/sched/tune.h @@ -20,6 +20,14 @@ int schedtune_prefer_idle(struct task_struct *tsk); void schedtune_enqueue_task(struct task_struct *p, int cpu); void schedtune_dequeue_task(struct task_struct *p, int cpu); +#ifdef CONFIG_RATP +bool prefer_sched_group(struct task_struct *tsk); +bool prefer_top(struct task_struct *tsk); +#else +#define prefer_sched_group(tsk) 0 +#define prefer_top(tsk) 0 +#endif + #else /* CONFIG_SCHED_TUNE */ #define schedtune_cpu_boost(cpu) 0 @@ -31,4 +39,7 @@ void schedtune_dequeue_task(struct task_struct *p, int cpu); #define schedtune_dequeue_task(task, cpu) do { } while (0) #define stune_util(cpu, other_util, walt_load) cpu_util_cfs(cpu_rq(cpu)) +#define prefer_sched_group(tsk) 0 +#define prefer_top(tsk) 0 + #endif /* CONFIG_SCHED_TUNE */ diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 789a93939c5cf5b7e0f986c008f0468cc2dbd1a5..bd5b1fa98b9e6b0e130a43145dd143f67aedf02d 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -14,6 +14,10 @@ #include +#ifdef CONFIG_IM +#include +#endif + const char *task_event_names[] = {"PUT_PREV_TASK", "PICK_NEXT_TASK", "TASK_WAKE", "TASK_MIGRATE", "TASK_UPDATE", "IRQ_UPDATE"}; @@ -2325,7 +2329,14 @@ static struct sched_cluster *alloc_new_cluster(const struct cpumask *cpus) raw_spin_lock_init(&cluster->load_lock); cluster->cpus = *cpus; cluster->efficiency = topology_get_cpu_scale(NULL, cpumask_first(cpus)); - +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + cluster->overload = kzalloc(sizeof(struct sched_stat_para), GFP_ATOMIC); + cluster->overload->low_thresh_ms = 100; + cluster->overload->high_thresh_ms = 500; + if (!cluster->overload) + return NULL; +#endif if (cluster->efficiency > max_possible_efficiency) max_possible_efficiency = cluster->efficiency; if (cluster->efficiency < min_possible_efficiency) @@ -2806,7 +2817,7 @@ int update_preferred_cluster(struct related_thread_group *grp, { u32 new_load = task_load(p); - if (!grp) + if (!grp || !p->grp) return 0; if (unlikely(from_tick && is_suh_max())) @@ -3679,6 +3690,63 @@ int walt_proc_user_hint_handler(struct ctl_table *table, return ret; } +#if defined(CONFIG_IM) || defined(CONFIG_HOUSTON) +int group_show(struct seq_file *m, void *v) +{ + struct related_thread_group *grp; + unsigned long flags; + struct task_struct *p; + u64 total_demand = 0; + u64 render_demand = 0; + + if (!im_render_grouping_enable()) + return 0; + + grp = lookup_related_thread_group(DEFAULT_CGROUP_COLOC_ID); + + raw_spin_lock_irqsave(&grp->lock, flags); + if (list_empty(&grp->tasks)) { + raw_spin_unlock_irqrestore(&grp->lock, flags); + return 0; + } + + list_for_each_entry(p, &grp->tasks, grp_list) { + + total_demand += p->ravg.demand_scaled; + + if (!im_rendering(p)) + continue; + + seq_printf(m, "%u, %lu, %d\n", p->pid, p->ravg.demand_scaled, p->cpu); + render_demand += p->ravg.demand_scaled; + } + + seq_printf(m, "total: %u / render: %u\n", total_demand, render_demand); + + raw_spin_unlock_irqrestore(&grp->lock, flags); + return 0; +} + +void group_remove(void) +{ + struct related_thread_group *grp; + struct task_struct *p, *next; + + if (!im_render_grouping_enable()) + return; + + grp = lookup_related_thread_group(DEFAULT_CGROUP_COLOC_ID); + + if (list_empty(&grp->tasks)) + return; + + list_for_each_entry_safe(p, next, &grp->tasks, grp_list) { + if (im_sf(p)) + sched_set_group_id(p, 0); + } +} +#endif + static inline void sched_window_nr_ticks_change(void) { int new_ticks; diff --git a/kernel/signal.c b/kernel/signal.c index 96667620acadc6ae1e1d9bef6c8f1704485d9ca8..b2d0267680305ae20aaf750179d0ab95ef841fc7 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1083,6 +1083,19 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str } #endif +static int print_key_process_murder __read_mostly = 1; +static bool is_zygote_process(struct task_struct *t) +{ + const struct cred *tcred = __task_cred(t); + + if (!strcmp(t->comm, "main") && (tcred->uid.val == 0) && + (t->parent != 0 && !strcmp(t->parent->comm, "init"))) + return true; + else + return false; + return false; +} + static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, enum pid_type type, int from_ancestor_ns) { @@ -1094,6 +1107,21 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, assert_spin_locked(&t->sighand->siglock); result = TRACE_SIGNAL_IGNORED; + + if (print_key_process_murder) { + if (!strcmp(t->comm, "system_server") || + is_zygote_process(t) || + !strcmp(t->comm, "surfaceflinger") || + !strcmp(t->comm, "servicemanager") || + (!strcmp(t->comm, "netd") && sig == 9)) { + struct task_struct *tg = current->group_leader; + + pr_info("process %d:%s, %d:%s send sig:%d to process %d:%s\n", + tg->pid, tg->comm, current->pid, + current->comm, sig, t->pid, t->comm); + } + } + if (!prepare_signal(sig, t, from_ancestor_ns || (info == SEND_SIG_PRIV) || (info == SEND_SIG_FORCED))) goto ret; @@ -1267,6 +1295,20 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, unsigned long flags; int ret = -ESRCH; + /* huruihuan add for kill task in D status */ + if (sig == SIGKILL) { + if (p && p->flags & PF_FROZEN) { + struct task_struct *child = p; + + rcu_read_lock(); + do { + child = next_thread(child); + child->kill_flag = 1; + __thaw_task(child); + } while (child != p); + rcu_read_unlock(); + } + } if (lock_task_sighand(p, &flags)) { ret = send_signal(sig, info, p, type); unlock_task_sighand(p, &flags); @@ -3317,9 +3359,18 @@ static inline void prepare_kill_siginfo(int sig, struct siginfo *info) SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) { struct siginfo info; + /* huruihuan add for kill task in D status */ + struct task_struct *p; prepare_kill_siginfo(sig, &info); + /* huruihuan add for kill task in D status */ + if (sig == SIGQUIT || sig == SIGSEGV || sig == SIGABRT) { + p = pid_task(find_vpid(pid), PIDTYPE_PID); + if (p) + unfreezer_fork(p); + } + return kill_something_info(sig, &info, pid); } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 9557c2175acac322d87804f43de53d9738642062..c63cb7777f47485010732edbdf11bf42d8c4fc54 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -99,6 +99,10 @@ #if defined(CONFIG_SYSCTL) +#ifdef CONFIG_HUNG_TASK_ENHANCE +#include +#endif + /* External variables not in a header file. */ extern int suid_dumpable; #ifdef CONFIG_COREDUMP @@ -106,6 +110,9 @@ extern int core_uses_pid; extern char core_pattern[]; extern unsigned int core_pipe_limit; #endif +#ifdef CONFIG_DIRECT_SWAPPINESS +extern int vm_direct_swapiness; +#endif extern int pid_max; extern int extra_free_kbytes; extern int pid_max_min, pid_max_max; @@ -134,6 +141,14 @@ static unsigned long one_ul = 1; static unsigned long long_max = LONG_MAX; static int one_hundred = 100; static int one_thousand = 1000; +#ifdef CONFIG_DIRECT_SWAPPINESS +static int two_hundred = 200; +#endif + +#ifdef CONFIG_PANIC_FLUSH +unsigned long sysctl_blkdev_issue_flush_count; +#endif + #ifdef CONFIG_PRINTK static int ten_thousand = 10000; #endif @@ -333,6 +348,10 @@ static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1; #endif /* CONFIG_SMP */ #endif /* CONFIG_SCHED_DEBUG */ +#ifdef CONFIG_UXCHAIN +int sysctl_uxchain_enabled = 1; +int sysctl_launcher_boost_enabled; +#endif #ifdef CONFIG_COMPACTION static int min_extfrag_threshold; static int max_extfrag_threshold = 1000; @@ -346,6 +365,15 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, +#ifdef CONFIG_PANIC_FLUSH + { + .procname = "blkdev_issue_flush_count", + .data = &sysctl_blkdev_issue_flush_count, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = proc_dointvec, + }, +#endif #if defined(CONFIG_PREEMPT_TRACER) && defined(CONFIG_PREEMPTIRQ_EVENTS) { .procname = "preemptoff_tracing_threshold_ns", @@ -425,6 +453,15 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &one, }, + { + .procname = "sched_skip_affinity", + .data = &sysctl_sched_skip_affinity, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { .procname = "sched_many_wakeup_threshold", .data = &sysctl_sched_many_wakeup_threshold, @@ -1139,7 +1176,7 @@ static struct ctl_table kern_table[] = { .data = &console_loglevel, .maxlen = 4*sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_oem, }, { .procname = "printk_ratelimit", @@ -1445,7 +1482,25 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &one, }, - +#ifdef CONFIG_HUNG_TASK_ENHANCE +/* record the hung task killing */ + { + .procname = "hung_task_kill", + .data = &sysctl_hung_task_kill, + .maxlen = 128, + .mode = 0666, + .proc_handler = proc_dostring, + }, +/* Foreground background optimization,change max io count */ + { + .procname = "hung_task_maxiowait_count", + .data = &sysctl_hung_task_maxiowait_count, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &five, + }, +#endif #endif #ifdef CONFIG_RT_MUTEXES { @@ -1587,6 +1642,23 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, #endif +#ifdef CONFIG_UXCHAIN + { + .procname = "uxchain_enabled", + .data = &sysctl_uxchain_enabled, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, + { + .procname = "launcher_boost_enabled", + .data = &sysctl_launcher_boost_enabled, + .maxlen = sizeof(int), + .mode = 0666, + .proc_handler = proc_dointvec, + }, +#endif + { } }; @@ -1716,8 +1788,23 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = proc_dointvec_minmax, .extra1 = &zero, +#ifdef CONFIG_DIRECT_SWAPPINESS + .extra2 = &two_hundred, +#else .extra2 = &one_hundred, +#endif + }, +#ifdef CONFIG_DIRECT_SWAPPINESS + { + .procname = "direct_swappiness", + .data = &vm_direct_swapiness, + .maxlen = sizeof(vm_direct_swapiness), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two_hundred, }, +#endif { .procname = "want_old_faultaround_pte", .data = &want_old_faultaround_pte, @@ -2879,6 +2966,24 @@ int proc_dointvec(struct ctl_table *table, int write, return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL); } +static unsigned int oem_en_chg_prk_lv = 1; +module_param(oem_en_chg_prk_lv, uint, 0644); + +int proc_dointvec_oem(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + if (oem_en_chg_prk_lv || !write) + return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL); + + return 0; +} +static int __init oem_disable_chg_prk_lv(char *str) +{ + oem_en_chg_prk_lv = 0; + return 0; +} +early_param("debug", oem_disable_chg_prk_lv); + /** * proc_douintvec - read a vector of unsigned integers * @table: the sysctl table diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 81ee5b83c92007702b59e374aa6296e8190f5dc7..10d3cf4681b74a1df9df61a8ea65aed973a41d5c 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -722,14 +722,12 @@ static void timekeeping_forward_now(struct timekeeper *tk) * * Returns the time of day in a timespec64 (WARN if suspended). */ -void ktime_get_real_ts64(struct timespec64 *ts) +void __getnstimeofday64(struct timespec64 *ts) { struct timekeeper *tk = &tk_core.timekeeper; unsigned long seq; u64 nsecs; - WARN_ON(timekeeping_suspended); - do { seq = read_seqcount_begin(&tk_core.seq); @@ -741,6 +739,13 @@ void ktime_get_real_ts64(struct timespec64 *ts) ts->tv_nsec = 0; timespec64_add_ns(ts, nsecs); } +EXPORT_SYMBOL(__getnstimeofday64); + +void ktime_get_real_ts64(struct timespec64 *ts) +{ + WARN_ON(timekeeping_suspended); + __getnstimeofday64(ts); +} EXPORT_SYMBOL(ktime_get_real_ts64); ktime_t ktime_get(void) diff --git a/kernel/trace/power-traces.c b/kernel/trace/power-traces.c index 21bb161c231698aff56c96d5d5908da1ef3af97d..a8e98bb91eca3f9326ea30a3b782027a4faf7c9d 100644 --- a/kernel/trace/power-traces.c +++ b/kernel/trace/power-traces.c @@ -18,4 +18,6 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(suspend_resume); EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_idle); EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_frequency); EXPORT_TRACEPOINT_SYMBOL_GPL(powernv_throttle); +// 2020/04/01, add for pccore CONFIG_PCCORE +EXPORT_TRACEPOINT_SYMBOL_GPL(cpu_frequency_select); diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index c606f6a07bd0c3996c1c50b09df6d6966dc5c533..6ce5e626276fed9fa34b48ad4359380209e5ed5e 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -17,6 +17,11 @@ #include #include #include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#include +#include <../sched/sched.h> +#endif #include "trace.h" @@ -622,16 +627,36 @@ struct irqsoff_store { static DEFINE_PER_CPU(struct irqsoff_store, the_irqsoff); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ +unsigned int ohm_irqsoff_stat_thresh = 1000000UL; +DEFINE_PER_CPU(u64, irqsoff_stime); +#endif /* * We are only interested in hardirq on/off events: */ void tracer_hardirqs_on(unsigned long a0, unsigned long a1) { unsigned int pc = preempt_count(); + #ifdef CONFIG_PREEMPTIRQ_EVENTS struct irqsoff_store *is; u64 delta; +#endif + +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + if (ohm_irqsoff_ctrl) { + u64 stime = per_cpu(irqsoff_stime, raw_smp_processor_id()); + u64 delta = sched_clock() - stime; + + if (delta > ohm_irqsoff_stat_thresh) + ohm_irqsoff_record(delta / 1000000UL, raw_smp_processor_id()); + } +#endif/*CONFIG_ONEPLUS_HEALTHINFO*/ + +#ifdef CONFIG_PREEMPTIRQ_EVENTS lockdep_off(); is = &per_cpu(the_irqsoff, raw_smp_processor_id()); @@ -666,7 +691,12 @@ void tracer_hardirqs_off(unsigned long a0, unsigned long a1) is->caddr[4] = CALLER_ADDR5; lockdep_on(); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ - +#ifdef CONFIG_ONEPLUS_HEALTHINFO + if (ohm_irqsoff_ctrl) { + u64 *stime = &per_cpu(irqsoff_stime, raw_smp_processor_id()); + *stime = sched_clock(); + } +#endif/* CONFIG_ONEPLUS_HEALTHINFO*/ if (!preempt_trace(pc) && irq_trace()) start_critical_timing(a0, a1, pc); } @@ -722,6 +752,11 @@ struct preempt_store { static DEFINE_PER_CPU(struct preempt_store, the_ps); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ +/*2020-06-20 [OSP-5970] add for healthinfo*/ +#ifdef CONFIG_ONEPLUS_HEALTHINFO +unsigned int ohm_preempt_stat_thresh = 1000000UL; +DEFINE_PER_CPU(u64, preempt_stime); +#endif void tracer_preempt_on(unsigned long a0, unsigned long a1) { @@ -759,6 +794,16 @@ void tracer_preempt_on(unsigned long a0, unsigned long a1) if (preempt_trace(pc) && !irq_trace()) stop_critical_timing(a0, a1, pc); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + if (ohm_preempt_ctrl) { + u64 *stime = &per_cpu(preempt_stime, raw_smp_processor_id()); + u64 delta = sched_clock() - *stime; + + if (delta > ohm_preempt_stat_thresh) + ohm_preempt_record(delta / 1000000UL, raw_smp_processor_id()); + } +#endif } void tracer_preempt_off(unsigned long a0, unsigned long a1) @@ -783,6 +828,13 @@ void tracer_preempt_off(unsigned long a0, unsigned long a1) if (preempt_trace(pc) && !irq_trace()) start_critical_timing(a0, a1, pc); +#ifdef CONFIG_ONEPLUS_HEALTHINFO +/*2020-06-20 [OSP-5970] add for healthinfo*/ + if (ohm_preempt_ctrl) { + u64 *stime = &per_cpu(preempt_stime, raw_smp_processor_id()); + *stime = sched_clock(); + } +#endif } static int preemptoff_tracer_init(struct trace_array *tr) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e6b68cf40aaef449d1745e610949834ec51b7390..8d24b64fc3f7733155ff6876988e9e75b03dee6a 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -52,6 +52,10 @@ #include #include +#ifdef CONFIG_IM +#include +#endif + #include "workqueue_internal.h" enum { @@ -1857,6 +1861,11 @@ static struct worker *create_worker(struct worker_pool *pool) if (IS_ERR(worker->task)) goto fail; +#ifdef CONFIG_IM + /* set kworker flags */ + im_set_flag(worker->task, IM_KWORKER); +#endif + set_user_nice(worker->task, pool->attrs->nice); kthread_bind_mask(worker->task, pool->attrs->cpumask); diff --git a/lib/lzo/lzo1x_compress.c b/lib/lzo/lzo1x_compress.c index 236eb21167b5db1f5cd542efbf6c66dd770455fc..6958b8dc45722ebec36c9efaade3a60a530e3cb4 100644 --- a/lib/lzo/lzo1x_compress.c +++ b/lib/lzo/lzo1x_compress.c @@ -17,6 +17,9 @@ #include #include "lzodefs.h" +#define OVERFLOW_ADD_CHECK(a, b) \ + (((a) + (b)) < (a)) + static noinline size_t lzo1x_1_do_compress(const unsigned char *in, size_t in_len, unsigned char *out, size_t *out_len, @@ -39,6 +42,8 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, size_t t, m_len, m_off; u32 dv; literal: + if (unlikely(OVERFLOW_ADD_CHECK(ip, 1 + ((ip - ii) >> 5)))) + break; ip += 1 + ((ip - ii) >> 5); next: if (unlikely(ip >= ip_end)) @@ -99,7 +104,8 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, m_len += 8; v = get_unaligned((const u64 *) (ip + m_len)) ^ get_unaligned((const u64 *) (m_pos + m_len)); - if (unlikely(ip + m_len >= ip_end)) + if (unlikely((OVERFLOW_ADD_CHECK(ip, m_len)) + || (ip + m_len >= ip_end))) goto m_len_done; } while (v == 0); } @@ -124,7 +130,8 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, m_len += 4; v = get_unaligned((const u32 *) (ip + m_len)) ^ get_unaligned((const u32 *) (m_pos + m_len)); - if (unlikely(ip + m_len >= ip_end)) + if (unlikely((OVERFLOW_ADD_CHECK(ip, m_len)) + || (ip + m_len >= ip_end))) goto m_len_done; } while (v == 0); } @@ -160,7 +167,8 @@ lzo1x_1_do_compress(const unsigned char *in, size_t in_len, if (ip[m_len] != m_pos[m_len]) break; m_len += 1; - if (unlikely(ip + m_len >= ip_end)) + if (unlikely((OVERFLOW_ADD_CHECK(ip, m_len)) + || (ip + m_len >= ip_end))) goto m_len_done; } while (ip[m_len] == m_pos[m_len]); } @@ -224,8 +232,7 @@ int lzo1x_1_compress(const unsigned char *in, size_t in_len, while (l > 20) { size_t ll = l <= (M4_MAX_OFFSET + 1) ? l : (M4_MAX_OFFSET + 1); - uintptr_t ll_end = (uintptr_t) ip + ll; - if ((ll_end + ((t + ll) >> 5)) <= ll_end) + if (((uintptr_t) ip + ll + ((t + ll) >> 5)) <= (uintptr_t) ip) break; BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); diff --git a/lib/show_mem.c b/lib/show_mem.c index 0beaa1d899aae5b962410b4ca1b708181fb6cb32..300e9380737ce0f4798f8e0b2082e8d9e5d15a8c 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c @@ -8,6 +8,9 @@ #include #include #include +#ifdef CONFIG_ONEPLUS_HEALTHINFO +#include +#endif void show_mem(unsigned int filter, nodemask_t *nodemask) { @@ -49,4 +52,7 @@ void show_mem(unsigned int filter, nodemask_t *nodemask) #ifdef CONFIG_MEMORY_FAILURE printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages)); #endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO + printk("%lu pages ion total used\n", ion_total() >> PAGE_SHIFT); +#endif } diff --git a/mm/Kconfig b/mm/Kconfig index 210a06eb94c4a37a270629dbb6b4d6a0536cfc70..ee5e662cf238c35c605163e780739701cee001cf 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -860,3 +860,12 @@ config PROCESS_RECLAIM (addr, addr + size-bytes) of the process. Any other value is ignored. + +config DIRECT_SWAPPINESS + bool "direct swappiness" + default n + help + set direct swappiness rate, higher means more swap and slowly. + echo ratio > proc/sys/vm/direct_swapiness default_value 60 + cat /sys/module/memplus_core/parameters/memory_plus_enabled + default_value 0 diff --git a/mm/filemap.c b/mm/filemap.c index 154213214ab36e943bee7a74a96508d44928940f..c27386f06be0dde35b96e0c1c045d06e877743e5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -40,6 +40,10 @@ #include #include "internal.h" +#ifdef CONFIG_CGROUP_IOLIMIT +#include +#endif + #define CREATE_TRACE_POINTS #include @@ -947,7 +951,10 @@ int add_to_page_cache_lru(struct page *page, struct address_space *mapping, WARN_ON_ONCE(PageActive(page)); if (!(gfp_mask & __GFP_WRITE) && shadow) workingset_refault(page, shadow); - lru_cache_add(page); + + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + if (!smb_uid_lru_add(page)) + lru_cache_add(page); } return ret; } @@ -2192,6 +2199,12 @@ static ssize_t generic_file_buffered_read(struct kiocb *iocb, unsigned long nr, ret; cond_resched(); + +#ifdef CONFIG_CGROUP_IOLIMIT + if (iolimit_enable) + io_read_bandwidth_control(PAGE_SIZE); +#endif + find_page: if (fatal_signal_pending(current)) { error = -EINTR; @@ -3285,6 +3298,11 @@ ssize_t generic_perform_write(struct file *file, size_t copied; /* Bytes copied from user */ void *fsdata; +#ifdef CONFIG_CGROUP_IOLIMIT + if (iolimit_enable) + io_write_bandwidth_control(PAGE_SIZE); +#endif + offset = (pos & (PAGE_SIZE - 1)); bytes = min_t(unsigned long, PAGE_SIZE - offset, iov_iter_count(i)); diff --git a/mm/mmap.c b/mm/mmap.c index 85f87e882d4c273f6820194da4d40c58450e78ca..3cf854369b7e2bd86662f144437ae843c4ad8026 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -51,9 +51,12 @@ #include #include #include +#include #include "internal.h" +#define GPU_HIGH_LIMIT_3776M 3959422976 + #ifndef arch_mmap_check #define arch_mmap_check(addr, len, flags) (0) #endif @@ -279,6 +282,18 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) static long vma_compute_subtree_gap(struct vm_area_struct *vma) { unsigned long max, prev_end, subtree_gap; +#ifdef CONFIG_VM_FRAGMENT_MONITOR + unsigned long gl_tmp, gl_gap; + unsigned long gpu_vm_end; + unsigned long mmap_limit; + bool va32bit = false; + + if (test_thread_flag(TIF_32BIT)) { + va32bit = true; + gpu_vm_end = GPU_HIGH_LIMIT_3776M; + mmap_limit = min_t(unsigned long, gpu_vm_end, vma->vm_mm->mmap_base); + } +#endif /* * Note: in the rare case of a VM_GROWSDOWN above a VM_GROWSUP, we @@ -287,8 +302,23 @@ static long vma_compute_subtree_gap(struct vm_area_struct *vma) * That's a little inconsistent, but keeps the code here simpler. */ max = vm_start_gap(vma); + +#ifdef CONFIG_VM_FRAGMENT_MONITOR + if (va32bit) + gl_gap = min_t(unsigned long, max, mmap_limit); +#endif + if (vma->vm_prev) { prev_end = vm_end_gap(vma->vm_prev); + +#ifdef CONFIG_VM_FRAGMENT_MONITOR + if (va32bit) { + if (prev_end < mmap_limit && max > prev_end) + gl_gap -= prev_end; + else + gl_gap = 0; + } +#endif if (max > prev_end) max -= prev_end; else @@ -299,13 +329,35 @@ static long vma_compute_subtree_gap(struct vm_area_struct *vma) struct vm_area_struct, vm_rb)->rb_subtree_gap; if (subtree_gap > max) max = subtree_gap; + +#ifdef CONFIG_VM_FRAGMENT_MONITOR + if (va32bit) { + gl_tmp = rb_entry(vma->vm_rb.rb_left, struct vm_area_struct, vm_rb)->rb_glfragment_gap; + if (gl_tmp > gl_gap) + gl_gap = gl_tmp; + } +#endif } if (vma->vm_rb.rb_right) { subtree_gap = rb_entry(vma->vm_rb.rb_right, struct vm_area_struct, vm_rb)->rb_subtree_gap; if (subtree_gap > max) max = subtree_gap; + +#ifdef CONFIG_VM_FRAGMENT_MONITOR + if (va32bit) { + gl_tmp = rb_entry(vma->vm_rb.rb_right, struct vm_area_struct, vm_rb)->rb_glfragment_gap; + if (gl_tmp > gl_gap) + gl_gap = gl_tmp; + } +#endif } + +#ifdef CONFIG_VM_FRAGMENT_MONITOR + if (va32bit) + vma->rb_glfragment_gap = gl_gap; +#endif + return max; } @@ -423,8 +475,51 @@ static void validate_mm(struct mm_struct *mm) #define mm_rb_write_unlock(mm) do { } while (0) #endif /* CONFIG_SPECULATIVE_PAGE_FAULT */ +#ifdef CONFIG_VM_FRAGMENT_MONITOR +static inline void vma_gap_callbacks_propagate(struct rb_node *rb, struct rb_node *stop) +{ + unsigned long gl_tmp; + unsigned long augmented; + + while (rb != stop) { + struct vm_area_struct *node = rb_entry(rb, struct vm_area_struct, vm_rb); + + gl_tmp = node->rb_glfragment_gap; + augmented = vma_compute_subtree_gap(node); + + if (node->rb_subtree_gap == augmented && node->rb_glfragment_gap == gl_tmp) + break; + + node->rb_subtree_gap = augmented; + rb = rb_parent(&node->vm_rb); + } +} +static inline void +vma_gap_callbacks_copy(struct rb_node *rb_old, struct rb_node *rb_new) +{ + struct vm_area_struct *old = rb_entry(rb_old, struct vm_area_struct, vm_rb); + struct vm_area_struct *new = rb_entry(rb_new, struct vm_area_struct, vm_rb); + + new->rb_subtree_gap = old->rb_subtree_gap; +} +static void +vma_gap_callbacks_rotate(struct rb_node *rb_old, struct rb_node *rb_new) +{ + struct vm_area_struct *old = rb_entry(rb_old, struct vm_area_struct, vm_rb); + struct vm_area_struct *new = rb_entry(rb_new, struct vm_area_struct, vm_rb); + + new->rb_subtree_gap = old->rb_subtree_gap; + old->rb_subtree_gap = vma_compute_subtree_gap(old); +} +static const struct rb_augment_callbacks vma_gap_callbacks = { + .propagate = vma_gap_callbacks_propagate, + .copy = vma_gap_callbacks_copy, + .rotate = vma_gap_callbacks_rotate +}; +#else RB_DECLARE_CALLBACKS(static, vma_gap_callbacks, struct vm_area_struct, vm_rb, unsigned long, rb_subtree_gap, vma_compute_subtree_gap) +#endif /* * Update augmented rbtree rb_subtree_gap values after vma->vm_start or @@ -1450,6 +1545,8 @@ unsigned long do_mmap(struct file *file, unsigned long addr, if (!len) return -EINVAL; + while (file && (file->f_mode & FMODE_NONMAPPABLE)) + file = file->f_op->get_lower_file(file); /* * Does the application expect PROT_READ to imply PROT_EXEC? * @@ -2041,6 +2138,24 @@ unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info) if (length < info->length) return -ENOMEM; + if ((mm->va_feature & 0x2) && info->high_limit == mm->mmap_base) { + struct vm_unmapped_area_info info_b; + unsigned long addr; + + switch (info->length) { + case 4096: case 8192: case 16384: case 32768: + case 65536: case 131072: case 262144: + info_b = *info; + info_b.high_limit = + current->mm->va_feature_rnd - (dbg_pm[2] * (ilog2(info->length) - dbg_pm[1])); + info_b.low_limit = current->mm->va_feature_rnd - (dbg_pm[2] * dbg_pm[3]); + addr = unmapped_area_topdown(&info_b); + if (!offset_in_page(addr)) + return addr; + default: + break; + } + } /* * Adjust search limits by the desired length. * See implementation comment at top of unmapped_area(). @@ -2208,6 +2323,9 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, info.flags = VM_UNMAPPED_AREA_TOPDOWN; info.length = len; info.low_limit = max(PAGE_SIZE, mmap_min_addr); + if (mm->va_feature & 0x1) + info.low_limit = max_t(unsigned long, dbg_pm[0], info.low_limit); + info.high_limit = mm->mmap_base; info.align_mask = 0; addr = vm_unmapped_area(&info); @@ -2226,6 +2344,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = vm_unmapped_area(&info); } + if ((mm->va_feature & 0x1) && offset_in_page(addr)) { + VM_BUG_ON(addr != -ENOMEM); + info.flags = VM_UNMAPPED_AREA_TOPDOWN; + info.low_limit = max(PAGE_SIZE, mmap_min_addr); + info.high_limit = mm->mmap_base; + addr = vm_unmapped_area(&info); + } return addr; } #endif diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 23c57dbd625ea878324c5b763bb1381947501831..9ea6641256db6cf987ce114910daa6945254cd37 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -1155,6 +1155,12 @@ static void oom_kill_process(struct oom_control *oc, const char *message, pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n", message, task_pid_nr(p), p->comm, points); + if (!strcmp("system_server", p->comm)) { + pr_err("%s: Kernel try to kill (%s) process, I prevent it.\n", + message, p->comm); + panic("Out of memory: panic on oom!!!\n"); + } + /* * If any of p's children has a different mm and is eligible for kill, * the one with the highest oom_badness() score is sacrificed for its diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 078f1461e074633e9066149f945c9cbd5feda0ba..a58953a8058f0f6dc32f73dc330159cb98e45b2e 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -1715,7 +1715,8 @@ static void balance_dirty_pages(struct bdi_writeback *wb, min_pause = wb_min_pause(wb, max_pause, task_ratelimit, dirty_ratelimit, &nr_dirtied_pause); - + trace_printk("max_pause %d, min_pause %d, nr_dirtied_pause %d\n", + max_pause, min_pause, nr_dirtied_pause); if (unlikely(task_ratelimit == 0)) { period = max_pause; pause = max_pause; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c9665e0a6865a6af24fc299c37d19a713aef1512..b5b6b6edd41901b465ff4499d32f9dd0123ecceb 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -73,6 +73,11 @@ #include #include #include "internal.h" +/* bin.zhong@ASTI add CONFIG_DEFRAG */ +#include +#ifdef CONFIG_ONEPLUS_MEM_MONITOR +#include +#endif /* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */ static DEFINE_MUTEX(pcp_batch_high_lock); @@ -296,6 +301,9 @@ char * const migratetype_names[MIGRATE_TYPES] = { "CMA", #endif "HighAtomic", +#ifdef CONFIG_DEFRAG + "Defrag-Pool", +#endif #ifdef CONFIG_MEMORY_ISOLATION "Isolate", #endif @@ -2146,6 +2154,10 @@ static int fallbacks[MIGRATE_TYPES][4] = { #ifdef CONFIG_CMA [MIGRATE_CMA] = { MIGRATE_TYPES }, /* Never used */ #endif +#ifdef CONFIG_DEFRAG + [MIGRATE_UNMOVABLE_DEFRAG_POOL] = {MIGRATE_TYPES}, +#endif + #ifdef CONFIG_MEMORY_ISOLATION [MIGRATE_ISOLATE] = { MIGRATE_TYPES }, /* Never used */ #endif @@ -2494,6 +2506,10 @@ static void reserve_highatomic_pageblock(struct page *page, struct zone *zone, /* Yoink! */ mt = get_pageblock_migratetype(page); + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + if (is_migrate_defrag(mt)) + goto out_unlock; + if (!is_migrate_highatomic(mt) && !is_migrate_isolate(mt) && !is_migrate_cma(mt)) { zone->nr_reserved_highatomic += pageblock_nr_pages; @@ -2716,6 +2732,15 @@ static inline struct page *__rmqueue_cma(struct zone *zone, unsigned int order) } #endif +#ifdef CONFIG_DEFRAG +struct page *defrag___rmqueue(struct zone *zone, unsigned int order, + int migratetype) +{ + return __rmqueue_smallest(zone, order, migratetype); +} +EXPORT_SYMBOL(defrag___rmqueue); +#endif + /* * Obtain a specified number of elements from the buddy allocator, all under * a single hold of the lock, for efficiency. Add them to the supplied list. @@ -3299,6 +3324,11 @@ struct page *rmqueue(struct zone *preferred_zone, * allocate greater than order-1 page units with __GFP_NOFAIL. */ WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1)); + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + page = defrag_alloc(zone, flags, migratetype, order); + if (page) + goto out; + spin_lock_irqsave(&zone->lock, flags); do { @@ -3467,6 +3497,8 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, if (!(alloc_flags & ALLOC_CMA)) free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES); #endif + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + free_pages -= defrag_calc(z, order, alloc_flags); /* * Check watermarks for an order-0 allocation request. If these @@ -3507,6 +3539,11 @@ bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, return true; } #endif + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + if (defrag_check_alloc_flag(alloc_flags, order) && + IS_NOT_DEFRAG_POOL_EMPTY(area)) + return true; + if (alloc_harder && !list_empty(&area->free_list[MIGRATE_HIGHATOMIC])) return true; @@ -3532,6 +3569,8 @@ static inline bool zone_watermark_fast(struct zone *z, unsigned int order, if (!(alloc_flags & ALLOC_CMA)) cma_pages = zone_page_state(z, NR_FREE_CMA_PAGES); #endif + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + cma_pages += defrag_zone_free_size(z); /* * Fast check for order-0 only. If this fails then the reserves @@ -4329,6 +4368,10 @@ gfp_to_alloc_flags(gfp_t gfp_mask) (gfp_mask & __GFP_CMA)) alloc_flags |= ALLOC_CMA; #endif + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + defrag_migrate_to_alloc_flag(alloc_flags, + gfpflags_to_migratetype(gfp_mask)); + return alloc_flags; } @@ -4524,6 +4567,9 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, int no_progress_loops; unsigned int cpuset_mems_cookie; int reserve_flags; +#ifdef CONFIG_ONEPLUS_MEM_MONITOR + unsigned long oneplus_alloc_start = jiffies; +#endif /* * We also sanity check to catch abuse of atomic reserves being used by @@ -4763,6 +4809,10 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, warn_alloc(gfp_mask, ac->nodemask, "page allocation failure: order:%u", order); got_pg: +#ifdef CONFIG_ONEPLUS_MEM_MONITOR + memory_alloc_monitor(gfp_mask, order, + jiffies_to_msecs(jiffies - oneplus_alloc_start)); +#endif return page; } @@ -4795,6 +4845,8 @@ static inline bool prepare_alloc_pages(gfp_t gfp_mask, unsigned int order, if (IS_ENABLED(CONFIG_CMA) && ac->migratetype == MIGRATE_MOVABLE && (gfp_mask & __GFP_CMA)) *alloc_flags |= ALLOC_CMA; + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + defrag_migrate_to_alloc_flag(*alloc_flags, ac->migratetype); return true; } @@ -4842,6 +4894,9 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid, finalise_ac(gfp_mask, &ac); + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + ADD_ORDER_USAGE(order); + /* * Forbid the first pass from falling back to types that fragment * memory until all local zones are considered. @@ -4853,6 +4908,9 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid, if (likely(page)) goto out; + /* bin.zhong@ASTI add CONFIG_DEFRAG */ + ADD_ORDER_FAIL(order); + /* * Apply scoped allocation constraints. This is mainly about GFP_NOFS * resp. GFP_NOIO which has to be inherited for all allocation requests @@ -5301,6 +5359,10 @@ static void show_migration_types(unsigned char type) #ifdef CONFIG_MEMORY_ISOLATION [MIGRATE_ISOLATE] = 'I', #endif +#ifdef CONFIG_DEFRAG + [MIGRATE_UNMOVABLE_DEFRAG_POOL] = 'D', +#endif + }; char tmp[MIGRATE_TYPES + 1]; char *p = tmp; @@ -5344,6 +5406,8 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) " unevictable:%lu dirty:%lu writeback:%lu unstable:%lu\n" " slab_reclaimable:%lu slab_unreclaimable:%lu\n" " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n" + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + " ramboost:%lu\n" " free:%lu free_pcp:%lu free_cma:%lu\n", global_node_page_state(NR_ACTIVE_ANON), global_node_page_state(NR_INACTIVE_ANON), @@ -5362,6 +5426,8 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) global_zone_page_state(NR_PAGETABLE), global_zone_page_state(NR_BOUNCE), global_zone_page_state(NR_FREE_PAGES), + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + UID_LRU_SIZE, free_pcp, global_zone_page_state(NR_FREE_CMA_PAGES)); @@ -5448,6 +5514,10 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) " bounce:%lukB" " free_pcp:%lukB" " local_pcp:%ukB" + /* bin.zhong@ASTI, 2019/10/11, + * add for CONFIG_SMART_BOOST + */ + " ramboost:%lukB" " free_cma:%lukB" "\n", zone->name, @@ -5472,6 +5542,10 @@ void show_free_areas(unsigned int filter, nodemask_t *nodemask) K(zone_page_state(zone, NR_BOUNCE)), K(free_pcp), K(this_cpu_read(zone->pageset->pcp.count)), + /* bin.zhong@ASTI, 2019/10/11, + * add for CONFIG_SMART_BOOST + */ + K(ZONE_UID_LRU_SIZE(zone)), K(zone_page_state(zone, NR_FREE_CMA_PAGES))); printk("lowmem_reserve[]:"); for (i = 0; i < MAX_NR_ZONES; i++) diff --git a/mm/page_poison.c b/mm/page_poison.c index 9bec1f7c9250edb65db94b2ce5c31ce9da0c3601..858ac75959a962fd9b2181cd626ea5db2e885519 100644 --- a/mm/page_poison.c +++ b/mm/page_poison.c @@ -92,6 +92,7 @@ static void check_poison_mem(struct page *page, pr_err("pagealloc: memory corruption on page with phys start 0x%lx\n", (unsigned long)page_to_phys(page)); + pr_err("virt: %p, phys: 0x%llx\n", start, virt_to_phys(start)); print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start, end - start + 1, 1); BUG_ON(PANIC_CORRUPTION); diff --git a/mm/swap.c b/mm/swap.c index c48106674912ef418ebe9d85e1a41aa06974d2d5..8f0b1a67c5e793bd6470f3dc11fb1fdd66260c6c 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -252,6 +252,9 @@ void rotate_reclaimable_page(struct page *page) struct pagevec *pvec; unsigned long flags; + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + if (PG_UIDLRU(page)) + return; get_page(page); local_irq_save(flags); pvec = this_cpu_ptr(&lru_rotate_pvecs); @@ -278,6 +281,10 @@ static void __activate_page(struct page *page, struct lruvec *lruvec, int file = page_is_file_cache(page); int lru = page_lru_base_type(page); + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + if (PG_UIDLRU(page)) + return; + del_page_from_lru_list(page, lruvec, lru); SetPageActive(page); lru += LRU_ACTIVE; @@ -614,6 +621,10 @@ void deactivate_file_page(struct page *page) if (PageUnevictable(page)) return; + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + if (PG_UIDLRU(page)) + return; + if (likely(get_page_unless_zero(page))) { struct pagevec *pvec = &get_cpu_var(lru_deactivate_file_pvecs); diff --git a/mm/truncate.c b/mm/truncate.c index 71b65aab8077570c869bae85f4690bf60e459450..4f9c1fc68cf259a7ec4ee14183bc77c9469d7346 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -530,6 +530,81 @@ void truncate_inode_pages_final(struct address_space *mapping) } EXPORT_SYMBOL(truncate_inode_pages_final); +#ifdef CONFIG_SMART_BOOST +unsigned long smb_invalidate_mapping_pages( + struct address_space *mapping, + pgoff_t start, pgoff_t end) +{ + pgoff_t indices[PAGEVEC_SIZE]; + struct pagevec pvec; + pgoff_t index = start; + unsigned long ret; + unsigned long count = 0; + int i; + + pagevec_init(&pvec); + while (index <= end && pagevec_lookup_entries(&pvec, mapping, index, + min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1, + indices)) { + for (i = 0; i < pagevec_count(&pvec); i++) { + struct page *page = pvec.pages[i]; + + /* We rely upon deletion not changing page->index */ + index = indices[i]; + if (index > end) + break; + + if (radix_tree_exceptional_entry(page)) { + invalidate_exceptional_entry(mapping, index, + page); + continue; + } + + if (PageUIDLRU(page)) + continue; + if (!trylock_page(page)) + continue; + + WARN_ON(page_to_index(page) != index); + + /* Middle of THP: skip */ + if (PageTransTail(page)) { + unlock_page(page); + continue; + } else if (PageTransHuge(page)) { + index += HPAGE_PMD_NR - 1; + i += HPAGE_PMD_NR - 1; + /* + * 'end' is in the middle of THP. Don't + * invalidate the page as the part outside of + * 'end' could be still useful. + */ + if (index > end) { + unlock_page(page); + continue; + } + } + + ret = invalidate_inode_page(page); + unlock_page(page); + /* + * Invalidation is a hint that the page is no longer + * of interest and try to speed up its reclaim. + */ + if (!ret) + deactivate_file_page(page); + count += ret; + } + pagevec_remove_exceptionals(&pvec); + pagevec_release(&pvec); + cond_resched(); + index++; + } + return count; +} +EXPORT_SYMBOL(smb_invalidate_mapping_pages); +#endif + /** * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode * @mapping: the address_space which holds the pages to invalidate diff --git a/mm/vmscan.c b/mm/vmscan.c index cf077f0a6c55abceb938ef5834968b02ea16692f..9c084e9578c5bdd8a3ae26391e7e1b40b60b2df8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -173,10 +173,17 @@ int kswapd_threads_current = DEF_KSWAPD_THREADS_PER_NODE; #define prefetchw_prev_lru_page(_page, _base, _field) do { } while (0) #endif +/* set direct swapiness rate ,higher means more swap */ +#ifdef CONFIG_DIRECT_SWAPPINESS +int vm_swappiness = 100; +int vm_direct_swapiness = 60; +#else /* * From 0 .. 100. Higher means more swappy. */ int vm_swappiness = 60; +#endif + /* * The total number of pages which are beyond the high watermark within all * zones. @@ -1568,6 +1575,86 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone, return ret; } +/* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ +unsigned long coretech_reclaim_pagelist(struct list_head *page_list, + struct vm_area_struct *vma, void *sc) +{ + struct scan_control sc_t = { + .gfp_mask = GFP_KERNEL, + .priority = DEF_PRIORITY, + .may_writepage = 1, + .may_unmap = 1, + .may_swap = 1, + .target_vma = vma, + }; + + unsigned long nr_reclaimed; + struct page *page; + + if (!sc) + sc = &sc_t; + + list_for_each_entry(page, page_list, lru) { + ClearPageActive(page); + } + + nr_reclaimed = shrink_page_list(page_list, NULL, + (struct scan_control *)sc, + TTU_IGNORE_ACCESS, NULL, true); + + while (!list_empty(page_list)) { + page = lru_to_page(page_list); + list_del(&page->lru); + dec_node_page_state(page, NR_ISOLATED_ANON + + page_is_file_cache(page)); + putback_lru_page(page); + } + + return nr_reclaimed; +} + +#ifdef CONFIG_MEMEX_STANDALONE +unsigned long swapout_to_zram(struct list_head *page_list, + struct vm_area_struct *vma) +{ + struct scan_control sc = { + .gfp_mask = GFP_KERNEL, + .priority = DEF_PRIORITY, + .may_writepage = 1, + .may_unmap = 1, + .may_swap = 1, + .target_vma = vma, + }; + + return coretech_reclaim_pagelist(page_list, vma, &sc); +} +#endif + +/* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ +static void smart_boost_reclaim_pages(struct lruvec *lruvec, + struct pglist_data *pgdat, + struct scan_control *sc) +{ + LIST_HEAD(page_list); + unsigned long nr_isolate = 0; + struct page *page; + + nr_isolate = smb_isolate_list_or_putbcak(&page_list, + lruvec, pgdat, sc->priority, + (sc->nr_reclaimed > sc->nr_to_reclaim)); + if (!nr_isolate) + return; + + sc->nr_reclaimed += shrink_page_list(&page_list, pgdat, sc, + TTU_IGNORE_ACCESS, NULL, true); + + while (!list_empty(&page_list)) { + page = lru_to_page(&page_list); + list_del(&page->lru); + putback_lru_page(page); + } +} + #ifdef CONFIG_PROCESS_RECLAIM unsigned long reclaim_pages_from_list(struct list_head *page_list, struct vm_area_struct *vma) @@ -2239,6 +2326,8 @@ static void shrink_active_list(unsigned long nr_to_scan, free_unref_page_list(&l_hold); trace_mm_vmscan_lru_shrink_active(pgdat->node_id, nr_taken, nr_activate, nr_deactivate, nr_rotated, sc->priority, file); + /* bin.zhong@ASTI, 2019/10/11, add for CONFIG_SMART_BOOST */ + smart_boost_reclaim_pages(lruvec, pgdat, sc); } /* @@ -2358,6 +2447,11 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, unsigned long ap, fp; enum lru_list lru; +#ifdef CONFIG_DIRECT_SWAPPINESS + if (!current_is_kswapd()) + swappiness = vm_direct_swapiness; +#endif + /* If we have no swap space, do not bother scanning anon pages. */ if (!sc->may_swap || mem_cgroup_get_nr_swap_pages(memcg) <= 0) { scan_balance = SCAN_FILE; diff --git a/mm/vmstat.c b/mm/vmstat.c index bcd2f31ffe7d22616f48bd65db4993de3b2ca52b..a39c8042793a7270a6cd1ec889a31ef88a4fa79d 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1123,8 +1123,17 @@ const char * const vmstat_text[] = { "nr_bounce", #if IS_ENABLED(CONFIG_ZSMALLOC) "nr_zspages", +#endif +#ifdef CONFIG_SMART_BOOST + "nr_uid_lru", +#endif +#ifdef CONFIG_ONEPLUS_HEALTHINFO + "nr_ioncache_pages", #endif "nr_free_cma", +#ifdef CONFIG_DEFRAG + "nr_free_defrag", +#endif /* enum numa_stat_item counters */ #ifdef CONFIG_NUMA diff --git a/net/Kconfig b/net/Kconfig index 6870f6c838e567af6c142beae0e9ee325b4416d4..61efb334b910dbb78a4593d97d628ecc02bc77d9 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -199,6 +199,27 @@ config BRIDGE_NETFILTER If unsure, say N. +config SLA + bool "to monitor netlink traffic" + default n + help + Realtime netlink traffic monitor. + The purpose of this is to monitor the ipv4 packet status and + switch between each interface. + + If unsure, say n. + +config SLA_ALGO + bool "op algo" + default n + bool "OnePlus SLA algorithm" + help + Realtime netlink traffic monitor. + The purpose of this is to monitor the ipv4 packet status and + switch between each interface. + + If unsure, say n. + source "net/netfilter/Kconfig" source "net/ipv4/netfilter/Kconfig" source "net/ipv6/netfilter/Kconfig" diff --git a/net/Makefile b/net/Makefile index bdaf53925acd5606fdb953800620bd05cf0f259e..b43ddcb2eaac9a4f087d58a2ca80596b1efd0071 100644 --- a/net/Makefile +++ b/net/Makefile @@ -87,3 +87,4 @@ endif obj-$(CONFIG_QRTR) += qrtr/ obj-$(CONFIG_NET_NCSI) += ncsi/ obj-$(CONFIG_XDP_SOCKETS) += xdp/ +obj-$(CONFIG_SLA) += opsla/ diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 496a5ac0e71f19f1eb880b1c747b51942dc9a7b3..b204a7921539b74dcfc2cea2c3656d4a93ae3f5e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -108,6 +108,11 @@ int sysctl_tcp_max_orphans __read_mostly = NR_FILE; #define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) +/* WIFI MODIFICATION */ +void (*statistic_dev_rtt)(struct sock *sk, long rtt) = NULL; +EXPORT_SYMBOL(statistic_dev_rtt); +/* WIFI MODIFICATION */ + #define REXMIT_NONE 0 /* no loss recovery to do */ #define REXMIT_LOST 1 /* retransmit packets marked lost */ #define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ @@ -771,6 +776,11 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us) tp->rtt_seq = tp->snd_nxt; tp->mdev_max_us = tcp_rto_min_us(sk); } + /* WIFI MODIFICATION */ + if (sk->sk_state == TCP_ESTABLISHED && statistic_dev_rtt) { + statistic_dev_rtt(sk, mrtt_us); + } + /* WIFI MODIFICATION */ } else { /* no previous measure. */ srtt = m << 3; /* take the measured time to be rtt */ diff --git a/net/opsla/Makefile b/net/opsla/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..96f486bf9edcae9885b64eb9421ee91d9043989d --- /dev/null +++ b/net/opsla/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the netfilter modules on top of IPv4. +# +obj-$(CONFIG_SLA) += op_sla.o diff --git a/net/opsla/op_sla.c b/net/opsla/op_sla.c new file mode 100644 index 0000000000000000000000000000000000000000..c0c83af39b4d9fe4a0983ffff2ac01ed819f1625 --- /dev/null +++ b/net/opsla/op_sla.c @@ -0,0 +1,1990 @@ +// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + +#include + +extern void (*statistic_dev_rtt)(struct sock *sk, long rtt); + +static rwlock_t sla_lock; +static rwlock_t sla_game_lock; +static rwlock_t sla_game_rx_lock; +static rwlock_t sla_rtt_lock; + +#define sla_write_lock() write_lock_bh(&sla_lock) +#define sla_write_unlock() write_unlock_bh(&sla_lock) + +#define sla_game_write_lock() write_lock_bh(&sla_game_lock) +#define sla_game_write_unlock() write_unlock_bh(&sla_game_lock) + +#define sla_game_rx_error_write_lock() write_lock_bh(&sla_game_rx_lock) +#define sla_game_rx_error_write_unlock() write_unlock_bh(&sla_game_rx_lock) + +#define sla_rtt_write_lock() write_lock_bh(&sla_rtt_lock) +#define sla_rtt_write_unlock() write_unlock_bh(&sla_rtt_lock) + +unsigned int get_default_ipaddr_by_devname(const char *devname) +{ + unsigned int addr; + struct net_device *dev; + + if (!devname) + return 0; + /* find netdev by name, increment refcnt */ + dev = __dev_get_by_name(&init_net, devname); + if (!dev) + return 0; + /* get ip addr from rtable (global scope) */ + addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); + /* decrement netdev refcnt */ + return addr; +} + +static void init_rtt_queue_info(void) +{ + rtt_rear = 0; + memset(rtt_queue, 0, sizeof(rtt_queue)); +} + +//send to user space +static int get_app_type(struct nf_conn *ct) +{ + if (ct->op_app_type >= GAME_BASE && + ct->op_app_type < (GAME_BASE + GAME_NUM)) + return GAME_TYPE; + else if (ct->op_app_type >= TOP_APP_BASE && + ct->op_app_type < (TOP_APP_BASE + TOP_APP_NUM)) + return TOP_APP_TYPE; + else + return INIT_APP_TYPE; +} + +static int op_sla_send_to_user(int msg_type, char *payload, int payload_len) +{ + int ret = -1; + struct sk_buff *skbuff; + struct nlmsghdr *nlh; + + if (!op_sla_pid) { + if (op_sla_debug) + pr_info("[op_sla] %s: op_sla_pid == 0!!\n", __func__); + return ret; + } + + //allocate new buffer cache + skbuff = alloc_skb(NLMSG_SPACE(payload_len), GFP_ATOMIC); + if (!skbuff) { + if (op_sla_debug) + pr_info("[op_sla] %s: skbuff alloc_skb failed\n", + __func__); + return ret; + } + + //fill in the data structure + nlh = nlmsg_put(skbuff, 0, 0, msg_type, NLMSG_ALIGN(payload_len), 0); + if (!nlh) { + if (op_sla_debug) + pr_info("[op_sla] %s: nlmsg_put failaure\n", __func__); + nlmsg_free(skbuff); + return ret; + } + + //compute nlmsg length + nlh->nlmsg_len = NLMSG_HDRLEN + NLMSG_ALIGN(payload_len); + + if (payload) + memcpy((char *)NLMSG_DATA(nlh), payload, payload_len); + + //set control field,sender's pid +#if (KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE) + NETLINK_CB(skbuff).pid = 0; +#else + NETLINK_CB(skbuff).portid = 0; +#endif + NETLINK_CB(skbuff).dst_group = 0; + + //send data + ret = netlink_unicast(op_sla_sock, skbuff, op_sla_pid, MSG_DONTWAIT); + if (ret < 0) { + if (op_sla_debug) { + pr_info("[op_sla] %s: can not unicast skbuff,ret = %d\n", + __func__, ret); + } + return 1; + } + return 0; +} + +static int enable_op_sla_module(void) +{ + if (op_sla_debug) { + pr_info("[op_sla] %s: wlan-if_up:%d cell-if_up:%d\n", + __func__, + op_sla_info[WLAN_INDEX].if_up, + op_sla_info[CELLULAR_INDEX].if_up); + } + + if ((op_sla_info[WLAN_INDEX].if_up && + op_sla_info[CELLULAR_INDEX].if_up)) { + op_sla_enable = 1; + op_sla_send_to_user(SLA_ENABLED, NULL, 0); + } + return 0; +} + +static int calc_retran_syn_rtt(struct sk_buff *skb, struct nf_conn *ct) +{ + int index = -1; + int ret = SLA_SKB_CONTINUE; + unsigned int ctmark = ct->mark; + + if (op_sla_debug) + pr_info("[op_sla] %s: ct->mark:%x\n", __func__, ct->mark); + +#ifdef CONFIG_SLA_ALGO + if (is_syn_need_mark(ctmark)) { + ret = set_syn_skb_result(); +#else + if (ct->mark & CELLULAR_MARK) { +#endif + skb->mark = ct->mark; + return ret; + } + +#ifdef CONFIG_SLA_ALGO + index = find_iface_index_by_mark(ctmark); +#endif + + if (index != -1) { + sla_rtt_write_lock(); +#ifdef CONFIG_SLA_ALGO + calc_rtt_by_dev_index(index, SYN_RETRAN_RTT); +#endif + sla_rtt_write_unlock(); +#ifdef CONFIG_SLA_ALGO + ctmark = config_syn_retran(index, ctmark); + ret = set_syn_skb_result(); +#endif + ct->mark = ctmark; + skb->mark = ctmark; + } + if (op_sla_debug) + pr_info("[op_sla] %s: skb_status:%d ct->mark:%x skb->mark:%x\n", + __func__, ret, ct->mark, skb->mark); + return ret; +} + +static int syn_retransmits_packet_do_specail(struct sock *sk, + struct nf_conn *ct, + struct sk_buff *skb) +{ + int ret = SLA_SKB_CONTINUE; + unsigned int sla_mark = sk->op_sla_mark; + struct iphdr *iph; + struct tcphdr *th = NULL; + struct inet_connection_sock *icsk = inet_csk(sk); + + iph = ip_hdr(skb); + if (iph && iph->protocol == IPPROTO_TCP) { + th = tcp_hdr(skb); + //Only statistic syn retran packet, + //sometimes some rst packets also will be here + if (op_sla_debug) { + pr_info("[op_sla] %s: len:%d op_sla_mark:%x\n", + __func__, skb->len, sk->op_sla_mark); + } + + if (th && th->syn && !th->ack && !th->rst && !th->fin) { + ret = calc_retran_syn_rtt(skb, ct); +#ifdef CONFIG_SLA_ALGO + if (is_retran_second_mark(sla_mark)) { + ret = set_syn_skb_result(); +#else + if (sk->op_sla_mark & CELLULAR_MARK) { +#endif + skb->mark = ct->mark; + return ret; + } + + if (!nf_ct_is_dying(ct) && nf_ct_is_confirmed(ct)) { + ct->mark = 0x0; + //reset the tcp rto, so that can be + //faster to retrans to another dev + icsk->icsk_rto = TCP_RTO_MIN; +#ifdef CONFIG_SLA_ALGO + sla_mark = config_syn_retan(sla_mark); + ret = set_syn_ack_skb_result(); +#endif + sk->op_sla_mark = sla_mark; + + //Del the ct information, so that the + //syn packet can be send to network + //successfully later. + //lookup nf_nat_ipv4_fn() + nf_ct_kill(ct); + } + } else { + ret = SLA_SKB_ACCEPT; + } + } + + if (op_sla_debug) { + pr_info("[op_sla] %s: skb_status:%d skb->mark:%x ct->mark:%x sk->op_sla_mark:%x\n", + __func__, ret, skb->mark, ct->mark, sk->op_sla_mark); + } + return ret; +} + +static int *make_game_vals(struct nf_conn *ct, int game_rtt, + int game_type) +{ + game_data[0] = game_type;//game_type + game_data[1] = game_rtt;//rtt + game_data[2] = ct->op_game_time_interval;//op_game_time_interval + game_data[3] = ct->op_game_lost_count;//op_game_lost_count + game_data[4] = game_rtt_wan_detect_flag; + return game_data; +} + +static void rx_interval_error_estimator(int game_type, int time_error) +{ +#ifdef CONFIG_SLA_ALGO + op_rx_interval_error_estimator(game_type, time_error); +#endif + if (op_sla_debug) { + pr_info("[op_sla] %s: time_error:%d error_count:%d\n", + __func__, time_error, + op_sla_game_app_list.special_rx_error_count[game_type]); + } +} + +static void game_rtt_estimator(int game_type, int rtt, struct nf_conn *ct) +{ + int *game_data; + + game_data = make_game_vals(ct, rtt, game_type); +#ifdef CONFIG_SLA_ALGO + op_game_rtt_estimator(game_data); +#endif + if (op_sla_debug) { + pr_info("[op_sla] %s: rtt:%d averagertt:%d\n", + __func__, rtt, + op_sla_game_app_list.rtt[game_type]); + } +} + +static void game_app_switch_network(struct nf_conn *ct, struct sk_buff *skb) +{ + int game_type = ct->op_app_type; + int game_rtt = 0; + int time_now = (int)(ktime_get_ns() / 1000000); + int gamelostcount = ct->op_game_lost_count; + int game_bp_info[4]; +#ifdef CONFIG_SLA_ALGO + int cell_quality_good = op_get_ct_cell_quality(game_type); + int wlan_bad = op_get_wlan_quality(); +#else + int cell_quality_good = (op_sla_info[CELLULAR_INDEX].cur_score + >= CELL_SCORE_BAD) ? 1 : 0; + int wlan_bad = 0; +#endif + int game_switch_interval = time_now - + op_sla_game_app_list.switch_time[game_type]; + + if (!op_sla_enable) + return; + + if (!game_start_state) + return; + + game_rtt = op_sla_game_app_list.rtt[game_type]; + + if (op_sla_debug) { + pr_info("[op_sla] %s: cell_quality_good:%d wlan_bad:%d game_rtt:%d\n", + __func__, cell_quality_good, wlan_bad, game_rtt); + pr_info("[op_sla] %s: special_rx_error_count:%d game mark:%d time:%d\n", + __func__, + op_sla_game_app_list.special_rx_error_count[game_type], + op_sla_game_app_list.mark[game_type], + game_switch_interval); + pr_info("[op_sla] %s: wlan valid:%d cell valid:%d\n", __func__, + op_sla_info[WLAN_INDEX].netlink_valid, + op_sla_info[CELLULAR_INDEX].netlink_valid); + pr_info("[op_sla] %s: switch_count:%d repeat_switch_time:%d\n", + __func__, op_sla_game_app_list.switch_count[game_type], + op_sla_game_app_list.repeat_switch_time[game_type]); + pr_info("[op_sla] %s: interval_for_switch_time:%d gamelostcount:%d\n", + __func__, + time_now - + op_sla_game_app_list.repeat_switch_time[game_type], + gamelostcount); + } + +#ifdef CONFIG_SLA_ALGO + if (is_ping_pong(game_type, time_now)) + return; + + if (switch_to_cell(cell_quality_good, + game_rtt, + gamelostcount, + game_switch_interval, + game_type) || fw_set_game_mark == 1) { +#else + if (fw_set_game_mark == 1) { +#endif + fw_set_game_mark = -1; + if (op_sla_debug) { + pr_info("[op_sla] %s: game switch to cellular...\n", + __func__); + } + init_rtt_queue_info(); +#ifdef CONFIG_SLA_ALGO + record_sla_game_cell_state(game_type, + game_switch_interval, + time_now); +#endif + memset(game_bp_info, 0x0, sizeof(game_bp_info)); + game_bp_info[0] = game_type; + game_bp_info[1] = CELLULAR_MARK; + game_bp_info[2] = wlan_bad; + game_bp_info[3] = cell_quality_good; + op_sla_send_to_user(SLA_SWITCH_GAME_NETWORK, + (char *)game_bp_info, + sizeof(game_bp_info)); + return; + } + +#ifdef CONFIG_SLA_ALGO + if (switch_to_wifi(wlan_bad, + game_rtt, + gamelostcount, + game_switch_interval, + game_type) || fw_set_game_mark == 0) { +#else + if (fw_set_game_mark == 0) { +#endif + fw_set_game_mark = -1; + if (op_sla_debug) { + pr_info("[op_sla] %s: game switch to wlan...\n", + __func__); + } + init_rtt_queue_info(); +#ifdef CONFIG_SLA_ALGO + record_sla_game_wifi_state(game_type, + game_switch_interval, + time_now); +#endif + memset(game_bp_info, 0x0, sizeof(game_bp_info)); + game_bp_info[0] = game_type; + game_bp_info[1] = WLAN_MARK; + game_bp_info[2] = wlan_bad; + game_bp_info[3] = cell_quality_good; + op_sla_send_to_user(SLA_SWITCH_GAME_NETWORK, + (char *)game_bp_info, + sizeof(game_bp_info)); + return; + } +} + +static void set_game_rtt_stream_up_info(struct nf_conn *ct, s64 now, + u32 game_type) +{ + int game_rtt; + int game_lost_count_threshold = 0; + int game_interval; + int game_lost_count; + int game_time_interval; + +#ifdef CONFIG_SLA_ALGO + game_lost_count_threshold = get_lost_count_threshold(game_type); +#endif + if (!ct->op_game_timestamp && !game_rtt_wan_detect_flag) { + ct->op_game_timestamp = now; + game_interval = (int)(now - ct->op_game_last_timestamp); + ct->op_game_time_interval = +#ifdef CONFIG_SLA_ALGO + get_game_interval(game_type, + game_interval); +#else + game_interval; +#endif + ct->op_game_last_timestamp = now; + ct->op_game_lost_count = 0; + if (ct->op_game_time_interval >= 10000) + ct->op_game_timestamp = 0; +#ifdef CONFIG_SLA_ALGO + if (check_wan_detect_flag(game_type)) + return; +#endif + } else { + ct->op_game_timestamp = now; + ct->op_game_last_timestamp = now; + ct->op_game_lost_count++; + if (op_sla_debug) { + pr_info("[op_sla] %s: lost game detect skb count:%d\n", + __func__, ct->op_game_lost_count); + } + game_lost_count = ct->op_game_lost_count; + game_time_interval = ct->op_game_time_interval; +#ifdef CONFIG_SLA_ALGO + if (is_detect_game_lost(game_lost_count, + game_lost_count_threshold, + game_time_interval)) { +#else + if (ct->op_game_lost_count >= game_lost_count_threshold) { +#endif + game_rtt = MAX_GAME_RTT; + if (op_sla_debug) { + pr_info("[op_sla] %s: lost detect skb, game_type:%d\n", + __func__, game_type); + pr_info("[op_sla] %s: last game rtt:%d\n", + __func__, + op_sla_game_app_list.rtt[game_type]); + } + sla_game_write_lock(); + game_rtt_estimator(game_type, game_rtt, ct); + sla_game_write_unlock(); + game_rtt_wan_detect_flag = 0; + } + } +} + +static void detect_game_tx_stream(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo) +{ + int game_type = ct->op_app_type; + int time_now = (int)(ktime_get_ns() / 1000000); +#ifdef CONFIG_SLA_ALGO + int specialrxthreshold = 0; + int rtt_callback[3] = {0}; +#endif + int lastspecialrxtiming = 0; + int datastallthreshold = 5000; + int special_rx_pkt_last_timestamp = + (int)ct->op_game_special_rx_pkt_timestamp; + int rx_normal_time_record = (int)ct->op_game_rx_normal_time_record; + int datastalltimer = time_now - rx_normal_time_record; + + if (op_sla_debug) { + pr_info("[op_sla] %s: time_now:%d\n", + __func__, time_now); + pr_info("[op_sla] %s: op_game_special_rx_pkt_timestamp:%d\n", + __func__, special_rx_pkt_last_timestamp); + pr_info("[op_sla] %s: op_game_rx_normal_time_record:%d\n", + __func__, rx_normal_time_record); + } + +#ifdef CONFIG_SLA_ALGO + if (is_support_detect_game_tx(game_type, + special_rx_pkt_last_timestamp)) { + get_rx_pkt_threshold(game_type, + time_now, + special_rx_pkt_last_timestamp, + rtt_callback); + specialrxthreshold = rtt_callback[0]; + datastallthreshold = rtt_callback[1]; + lastspecialrxtiming = rtt_callback[2]; + + if (data_stall_detect(lastspecialrxtiming, + specialrxthreshold, + datastalltimer, + datastallthreshold)) { +#else + if (game_type) { + if (datastalltimer >= datastallthreshold) { +#endif + if (op_sla_debug) { + pr_info("[op_sla] %s: lastspecialrxtiming:%d\n", + __func__, lastspecialrxtiming); + pr_info("[op_sla] %s: datastalltimer:%d\n", + __func__, datastalltimer); + } + sla_game_rx_error_write_lock(); + rx_interval_error_estimator(game_type, + datastalltimer); + sla_game_rx_error_write_unlock(); + } + } +} + +static void detect_game_rtt_stream(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo) +{ + int same_count_max = 10; + int up_max_count = 100; + s64 time_now = ktime_get_ns() / 1000000; + s64 time_interval = time_now - ct->op_game_timestamp; + int game_type = ct->op_app_type; + int skb_len = (int)skb->len; + int game_category = 0; + +#ifdef CONFIG_SLA_ALGO + game_category = get_game_tx_category(game_type, skb_len); +#endif + if (game_category == 1) { + same_count_max = 6; + } else if (game_category == 2) { + ct->op_game_detect_status = GAME_RTT_DETECTED_STREAM; + ct->op_game_up_count++; + } else if (game_category == 3) { + same_count_max = 3; + } else if (game_category == 4) { + return; + } + + if (op_sla_debug) { + pr_info("[op_sla] %s: game type:%d timestamp:%llu inter:%u\n", + __func__, game_type, ct->op_game_timestamp, + ct->op_game_time_interval); + pr_info("[op_sla] %s: src port:%d ct state:%d up count:%d game_status:%d\n", + __func__, ntohs(udp_hdr(skb)->source), XT_STATE_BIT(ctinfo), + ct->op_game_up_count, ct->op_game_detect_status); + pr_info("[op_sla] %s: skb len:%d, game_rtt_wan_detect_flag:%d\n", + __func__, skb_len, game_rtt_wan_detect_flag); + } + + if (ct->op_game_up_count == 0) { + ct->op_game_up_count = 1; + ct->op_game_same_count = 0; + ct->op_game_lost_count = 0; + ct->op_game_detect_status = GAME_RTT_DETECT_INITIAL; + ct->op_game_skb_len = skb->len; + ct->op_game_timestamp = time_now; + } else if (ct->op_game_detect_status == GAME_RTT_DETECT_INITIAL) { + ct->op_game_timestamp = time_now; + if (skb->len > 150) + return; + if (ct->op_game_skb_len == skb->len) { + if (time_interval < 300 || time_interval > 10000) + return; + ct->op_game_same_count++; + } else { + ct->op_game_skb_len = skb->len; + ct->op_game_same_count = 0; + ct->op_game_down_count = 0; + } + + if (op_sla_debug) { + pr_info("[op_sla] %s: interval_time:%llu up_count:%d\n", + __func__, time_interval, ct->op_game_up_count); + pr_info("[op_sla] %s: down count:%d same count:%d same_count_max:%d\n", + __func__, ct->op_game_down_count, ct->op_game_same_count, same_count_max); + pr_info("[op_sla] %s: ct->op_game_skb_len:%d\n", + __func__, ct->op_game_skb_len); + } + + if (ct->op_game_down_count >= same_count_max && + ct->op_game_same_count >= same_count_max) { +#ifdef CONFIG_SLA_ALGO + reset_sla_game_app_rtt(game_type); +#endif + init_rtt_queue_info(); + ct->op_game_last_timestamp = time_now; + ct->op_game_time_interval = time_interval; + ct->op_game_detect_status = GAME_RTT_DETECTED_STREAM; + ct->op_game_up_count++; + return; + } + + if (ct->op_game_up_count >= up_max_count) { + ct->op_game_detect_status = GAME_SKB_COUNT_ENOUGH; + if (op_sla_debug) { + pr_info("[op_sla] %s: GAME_SKB_COUNT_ENOUGH!!\n", + __func__); + } + } + ct->op_game_up_count++; + } else if (ct->op_game_detect_status == GAME_RTT_DETECTED_STREAM) { +#ifdef CONFIG_SLA_ALGO + if (drop_pkt_check(game_type, skb_len)) + return; +#endif + set_game_rtt_stream_up_info(ct, time_now, game_type); + } +} + +static int mark_game_app_skb(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo) +{ + int game_type = ct->op_app_type; + struct iphdr *iph = NULL; + u32 ct_mark = ct->mark & GAME_UNSPEC_MASK; + int ret = SLA_SKB_ACCEPT; + + if (!game_start_state && + (ct_mark & GAME_UNSPEC_MARK)) + return SLA_SKB_ACCEPT; + + iph = ip_hdr(skb); + if (iph && (iph->protocol == IPPROTO_UDP || + iph->protocol == IPPROTO_TCP)) { + ct_mark = ct->mark & MARK_MASK; + + if (iph->protocol == IPPROTO_TCP && + ((XT_STATE_BIT(ctinfo) & + XT_STATE_BIT(IP_CT_ESTABLISHED)) || + (XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_RELATED)))) { +#ifdef CONFIG_SLA_ALGO + if (is_support_game_mark(game_type)) { +#else + if (game_type) { +#endif + if (ct_mark == WLAN_MARK && + op_sla_info[WLAN_INDEX].cur_score > 40) { + return SLA_SKB_ACCEPT; + } else if (ct_mark == CELLULAR_MARK) { + skb->mark = CELLULAR_MARK; + return SLA_SKB_MARKED; + } + } + } + + skb->mark = op_sla_game_app_list.mark[game_type]; + + if (ct_mark && skb->mark && + ct_mark != skb->mark) { + if (op_sla_debug) { + pr_info("[op_sla] %s: reset ct proto:%u game type:%d\n", + __func__, iph->protocol, game_type); + pr_info("[op_sla] %s: ct mark:%x skb mark:%x\n", + __func__, ct_mark, skb->mark); + } + if (!nf_ct_is_dying(ct) && + nf_ct_is_confirmed(ct)) { + nf_ct_kill(ct); + return SLA_SKB_DROP; + } + skb->mark = ct_mark; + } + + if (!ct_mark) + ct->mark = (ct->mark & RTT_MASK) | + op_sla_game_app_list.mark[game_type]; + ret = SLA_SKB_MARKED; + } + + return ret; +} + +static bool is_game_app_skb(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo) +{ + int game_type = ct->op_app_type; + kuid_t uid; + struct sock *sk = NULL; + struct iphdr *iph = NULL; + const struct file *filp = NULL; + int app_type = get_app_type(ct); + int total = op_sla_game_app_list.count + GAME_BASE; + + if (app_type == INIT_APP_TYPE) { + sk = skb_to_full_sk(skb); + if (!sk || !sk->sk_socket) + return false; + + filp = sk->sk_socket->file; + if (!filp) + return false; + + iph = ip_hdr(skb); + for (game_type = GAME_BASE; game_type < total; game_type++) { + if (op_sla_game_app_list.uid[game_type]) { + uid = make_kuid(&init_user_ns, + op_sla_game_app_list.uid[game_type]); + if (uid_eq(filp->f_cred->fsuid, uid)) { + ct->op_app_type = game_type; + + if (!game_start_state && + iph && IPPROTO_TCP == + iph->protocol) { + ct->mark = (ct->mark & + RTT_MASK) | + WLAN_MARK; + ct->mark |= GAME_UNSPEC_MARK; + } else { + ct->mark = (ct->mark & + RTT_MASK) | + op_sla_game_app_list.mark[game_type]; + } + return true; + } + } + } + } else if (app_type == GAME_TYPE) { + return true; + } + return false; +} + +static void detect_game_up_skb(struct sk_buff *skb) +{ + struct iphdr *iph = NULL; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + if (!op_sla_rtt_detect) + return; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return; + + if (!is_game_app_skb(ct, skb, ctinfo)) + return; + + //TCP and udp need to switch network + iph = ip_hdr(skb); + if (iph && iph->protocol == IPPROTO_UDP) { + //only udp packet can active switch network to void updating + //game with cell. + sla_game_write_lock(); + game_app_switch_network(ct, skb); + sla_game_write_unlock(); + + detect_game_rtt_stream(ct, skb, ctinfo); + detect_game_tx_stream(ct, skb, ctinfo); + } +} + +static void rtt_game_check(struct nf_conn *ct, struct sk_buff *skb) +{ + int time_now = (int)(ktime_get_ns() / 1000000); + int game_rtt = 0; + struct iphdr *iph = ip_hdr(skb); + int game_type = ct->op_app_type; + int game_detect_status = ct->op_game_detect_status; + int game_timestamp = (int)ct->op_game_timestamp; + int game_time_interval = (int)ct->op_game_time_interval; + int skb_len = skb->len; + int app_type = get_app_type(ct); +#ifdef CONFIG_SLA_ALGO + int cell_quality_good = op_get_ct_cell_quality(game_type); +#else + int cell_quality_good = (op_sla_info[CELLULAR_INDEX].cur_score + >= CELL_SCORE_BAD) ? 1 : 0; +#endif + + if (op_sla_debug) { + if (iph && iph->protocol == IPPROTO_UDP && + app_type == GAME_TYPE) { + pr_info("[op_sla] %s: skb dev:%s game_status:%d\n", + __func__, skb->dev->name, + game_detect_status); + pr_info("[op_sla] %s: game type:%d lost count:%d interval_time:%u\n", + __func__, game_type, ct->op_game_lost_count, + game_time_interval); + pr_info("[op_sla] %s: game mark:%x protp:%d src_port:%d skb len:%d\n", + __func__, op_sla_game_app_list.mark[game_type], + iph->protocol, ntohs(udp_hdr(skb)->dest), + skb_len); + pr_info("[op_sla] %s: time_now:%d game_timeStamp:%d\n", + __func__, time_now, game_timestamp); + } + } + +#ifdef CONFIG_SLA_ALGO + if (is_support_rtt_wan_detect(game_type)) { +#else + if (game_type) { +#endif + if (iph && iph->protocol == IPPROTO_UDP) + game_rtt_wan_detect_flag = 0; + } + + if (app_type == GAME_TYPE) + ct->op_game_down_count++; + + if (!iph || iph->protocol != IPPROTO_UDP) + return; +#ifdef CONFIG_SLA_ALGO + if (is_need_check_game_rtt(game_detect_status, + game_timestamp, + skb_len)) { + game_rtt = get_game_rtt(time_now, game_timestamp, game_type); +#else + if (game_type) { +#endif + if (game_rtt <= 0) { + if (op_sla_debug) { + pr_info("[op_sla] %s: invalid RTT:%dms\n", + __func__, game_rtt); + } + ct->op_game_timestamp = 0; + return; + } + ct->op_game_timestamp = 0; +#ifdef CONFIG_SLA_ALGO + if (is_skip_rx_rtt(game_type, game_time_interval)) + return; + + if (need_enable_sla(cell_quality_good)) { +#else + if (cell_quality_good) { +#endif + if (op_sla_debug) { + pr_info("[op_sla] %s: send SLA_ENABLE\n", + __func__); + } + op_sla_send_to_user(SLA_ENABLE, NULL, 0); + } + if (op_sla_debug) { + pr_info("[op_sla] %s: game_rtt = %d\n", __func__, + op_sla_game_app_list.rtt[game_type]); + } + ct->op_game_lost_count = 0; + sla_game_write_lock(); + game_rtt_estimator(game_type, game_rtt, ct); + sla_game_write_unlock(); + } +} + +static void rx_interval_error_check(struct nf_conn *ct, struct sk_buff *skb) +{ + int time_now = (int)(ktime_get_ns() / 1000000); + int rx_interval = 0; + int special_rx_interval_error = 0; + struct iphdr *iph = ip_hdr(skb); + int game_type = ct->op_app_type; + int skb_len = skb->len; + int rx_pkt_timestamp = (int)ct->op_game_special_rx_pkt_timestamp; + int app_type = get_app_type(ct); +#ifdef CONFIG_SLA_ALGO + int game_category = get_game_rx_category(game_type, skb_len); + int cell_quality_good = op_get_ct_cell_quality(game_type); +#else + int cell_quality_good = (op_sla_info[CELLULAR_INDEX].cur_score + >= CELL_SCORE_BAD) ? 1 : 0; +#endif + + if (app_type == GAME_TYPE) + ct->op_game_rx_normal_time_record = time_now; + + if (!iph || iph->protocol != IPPROTO_UDP) + return; + +#ifdef CONFIG_SLA_ALGO + if (game_category == 1) { +#else + if (game_type) { +#endif + if (rx_pkt_timestamp) { +#ifdef CONFIG_SLA_ALGO + special_rx_interval_error = + get_rx_interval_error(game_category, + time_now, + rx_pkt_timestamp); +#endif + sla_game_rx_error_write_lock(); + rx_interval_error_estimator(game_type, + special_rx_interval_error); + sla_game_rx_error_write_unlock(); +#ifdef CONFIG_SLA_ALGO + } else { + reset_sla_game_app_rx_error(game_type); +#endif + } + ct->op_game_special_rx_pkt_timestamp = time_now; + if (op_sla_debug) { + pr_info("[op_sla] %s: skb_len:%d rx_interval:%dms\n", + __func__, skb_len, rx_interval); + pr_info("[op_sla] %s: special_rx_interval_error:%dms\n", + __func__, special_rx_interval_error); + } +#ifdef CONFIG_SLA_ALGO + if (need_enable_sla(cell_quality_good)) { +#else + if (cell_quality_good) { +#endif + if (op_sla_debug) { + pr_info("[op_sla] %s: send SLA_ENABLE\n", + __func__); + } + op_sla_send_to_user(SLA_ENABLE, NULL, 0); + } + } + +#ifdef CONFIG_SLA_ALGO + if (game_category == 2) { +#else + if (game_type) { +#endif + if (ct->op_game_special_rx_pkt_timestamp) { +#ifdef CONFIG_SLA_ALGO + special_rx_interval_error = + get_rx_interval_error(game_category, + time_now, + rx_pkt_timestamp); + } else { + reset_sla_game_app_rx_error(game_type); +#endif + } + ct->op_game_special_rx_pkt_timestamp = time_now; + if (op_sla_debug) { + pr_info("[op_sla] %s: rx_interval:%dms\n", + __func__, rx_interval); + pr_info("[op_sla] %s: special_rx_interval_error:%dms\n", + __func__, special_rx_interval_error); + } +#ifdef CONFIG_SLA_ALGO + if (need_enable_sla(cell_quality_good)) { +#else + if (cell_quality_good) { +#endif + if (op_sla_debug) { + pr_info("[op_sla] %s: send SLA_ENABLE\n", + __func__); + } + op_sla_send_to_user(SLA_ENABLE, NULL, 0); + } + } +} + +static bool is_skb_pre_bound(struct sk_buff *skb) +{ + u32 pre_mark = skb->mark & 0x10000; + + if (pre_mark == 0x10000) + return true; + return false; +} + +static int sla_skb_reroute(struct sk_buff *skb, + const struct nf_hook_state *state) +{ + int err; + + err = ip_route_me_harder(state->net, skb, RTN_UNSPEC); + if (err < 0) + return NF_DROP_ERR(err); + if (op_sla_debug) + pr_info("[op_sla] %s: skb->mark=%x\n", __func__, skb->mark); + return NF_ACCEPT; +} + +int is_response(const struct dnshdr *dnsh_) +{ + unsigned short response = ntohs(dnsh_->flags); + +#ifdef CONFIG_SLA_ALGO + response = get_dns_response(response); +#endif + return response; +} + +int parser_reply_code(const struct dnshdr *dnsh_) +{ + unsigned short response = ntohs(dnsh_->flags); + +#ifdef CONFIG_SLA_ALGO + response = get_reply_code(response); +#endif + return response; +} + +static void parser_dns(struct sk_buff *skb) +{ + unsigned short rcode; + unsigned int wifiip; + unsigned int cellip; + u8 buffer[sizeof(struct udphdr) + sizeof(struct dnshdr) + + MAX_QUERY_LEN]; + struct iphdr *iph = ip_hdr(skb); + struct udphdr *uh; + struct dnshdr *dnsh; + int packet_len = skb->len - IP_HDR_LEN; + int query_len = packet_len + - sizeof(struct udphdr) + - sizeof(struct dnshdr); + unsigned int dst_addr; + + /* Basic length validation */ + if (packet_len <= 0 || query_len < DNS_RECORD_MIN) { + pr_info("[op_sla] %s: DNS packet of insuffient length: %d\n", + __func__, packet_len); + return; + } + + /* Get UDP header */ + uh = skb_header_pointer(skb, IP_HDR_LEN, MIN(packet_len, + sizeof(buffer)), + buffer); + if (!uh) + return; + + /* Get DNS header */ + dnsh = (struct dnshdr *)(uh + 1); + + /* Only work on Query */ + if (is_response(dnsh)) { + rcode = parser_reply_code(dnsh); + dst_addr = iph->daddr; + wifiip = get_default_ipaddr_by_devname(op_sla_info[WLAN_INDEX].dev_name); + cellip = get_default_ipaddr_by_devname(op_sla_info[CELLULAR_INDEX].dev_name); +#ifdef CONFIG_SLA_ALGO + update_sla_dns_info(rcode, dst_addr, wifiip, cellip); +#endif + } +} + +static void parser_dns_query(struct sk_buff *skb, unsigned long time_now) +{ + unsigned int wifiip; + unsigned int cellip; + u8 buffer[sizeof(struct udphdr) + sizeof(struct dnshdr) + + MAX_QUERY_LEN]; + struct iphdr *iph = ip_hdr(skb); + struct udphdr *uh; + struct dnshdr *dnsh; + int packet_len = skb->len - IP_HDR_LEN; + int query_len = packet_len + - sizeof(struct udphdr) + - sizeof(struct dnshdr); + unsigned int src_addr; + + /* Basic length validation */ + if (packet_len <= 0 || query_len < DNS_RECORD_MIN) { + pr_info("[op_sla] %s: DNS packet of insuffient length: %d\n", + __func__, packet_len); + return; + } + + /* Get UDP header */ + uh = skb_header_pointer(skb, IP_HDR_LEN, MIN(packet_len, + sizeof(buffer)), + buffer); + if (!uh) + return; + + /* Get DNS header */ + dnsh = (struct dnshdr *)(uh + 1); + + src_addr = iph->saddr; + wifiip = get_default_ipaddr_by_devname(op_sla_info[WLAN_INDEX].dev_name); + cellip = get_default_ipaddr_by_devname(op_sla_info[CELLULAR_INDEX].dev_name); + if (src_addr == wifiip) { +#ifdef CONFIG_SLA_ALGO + record_dns_query_info(WLAN_INDEX, time_now); +#endif + } else if (src_addr == cellip) { +#ifdef CONFIG_SLA_ALGO + record_dns_query_info(CELLULAR_INDEX, time_now); +#endif + } +} + +static int dns_skb_need_sla(struct sk_buff *skb, struct nf_conn *ct) +{ + int ret = SLA_SKB_CONTINUE; + struct iphdr *iph = NULL; + unsigned int skbmark = skb->mark; +#ifdef CONFIG_SLA_ALGO + unsigned int dns_callback[2] = {0}; +#endif + unsigned long time_now = ktime_get_ns() / 1000000; + + iph = ip_hdr(skb); + if (iph && + (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) && + (ntohs(udp_hdr(skb)->dest) == 53)) { + ret = SLA_SKB_ACCEPT; + parser_dns_query(skb, time_now); +#ifdef CONFIG_SLA_ALGO + update_dns_mark(dns_callback, time_now); + skbmark = dns_callback[0]; + ret = (int)dns_callback[1]; +#endif + skb->mark = skbmark; + } + return ret; +} + +static void parser_icmp(struct sk_buff *skb) +{ + struct iphdr *iph = ip_hdr(skb); + struct icmphdr *icmph; + struct icmphdr _ih; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + unsigned int wifiip; + unsigned int cellip; + unsigned int dst_addr; + int app_type; + + icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih); + if (!icmph) + return; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return; + + app_type = get_app_type(ct); + if (app_type != TOP_APP_TYPE) + return; + + if (icmph->type == ICMP_DEST_UNREACH) { + wifiip = get_default_ipaddr_by_devname(op_sla_info[WLAN_INDEX].dev_name); + cellip = get_default_ipaddr_by_devname(op_sla_info[CELLULAR_INDEX].dev_name); + dst_addr = iph->daddr; +#ifdef CONFIG_SLA_ALGO + update_sla_icmp_info(dst_addr, wifiip, cellip); +#endif + } +} + +static void parser_tcp(struct sk_buff *skb) +{ + int app_type; + int index = -1; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return; + + app_type = get_app_type(ct); + if (app_type != TOP_APP_TYPE) + return; + + index = find_iface_index_by_mark(ct->mark); + if (index != -1) + op_sla_info[index].icmp_unreachable = 0; +} + +static void notify_fw_network_switch(void) +{ + unsigned long time_now = ktime_get_ns() / 1000000; + + if (!last_notify_fw_network_switch || (time_now - last_notify_fw_network_switch) >= 5000) { + last_notify_fw_network_switch = time_now; + op_sla_send_to_user(SLA_SWITCH_APP_NETWORK, NULL, 0); + } +} + +static unsigned int op_sla_rx_calc(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return NF_ACCEPT; + + if (!op_sla_rtt_detect) + return NF_ACCEPT; + rtt_game_check(ct, skb); + rx_interval_error_check(ct, skb); + return NF_ACCEPT; +} + +static void detect_top_app_skb(struct sk_buff *skb) +{ + int i = 0; + kuid_t uid; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + struct sock *sk = NULL; + const struct file *filp = NULL; + int app_type; + + ct = nf_ct_get(skb, &ctinfo); + + if (!ct) + return; + + app_type = get_app_type(ct); + + if (app_type == INIT_APP_TYPE) { + sk = skb_to_full_sk(skb); + if (!sk || !sk->sk_socket) + return; + + filp = sk->sk_socket->file; + + if (!filp) + return; + + for (i = 0; i < top_app_list.count; i++) { + if (top_app_list.uid[i]) { + uid = make_kuid(&init_user_ns, + top_app_list.uid[i]); + if (uid_eq(filp->f_cred->fsuid, uid)) { + ct->op_app_type = i + TOP_APP_BASE; + return; + } + } + } + } +} + +static int handle_top_app_skb(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) +{ + struct sock *sk = skb_to_full_sk(skb); + int retran_mark = 0; + int reset_mark = 0; + int ret = SLA_SKB_CONTINUE; + struct tcp_sock *tp; + struct inet_connection_sock *icsk; + struct iphdr *iph = NULL; + int ifaceindex = -1; + int i = 1; + unsigned int sla_mark; + unsigned int total_retrans; + unsigned int tcp_rtt; + unsigned int skbmark; +#ifdef CONFIG_SLA_ALGO + unsigned int tcp_callback[1] = {0}; + int cell_quality_good = op_get_cur_cell_quality(); +#else + int cell_quality_good = 1; +#endif + unsigned long time_now = ktime_get_ns() / 1000000; + int top_app_type = ct->op_app_type; + + if (op_sla_debug) + pr_info("[op_sla] %s: len:%d mark:%x port:%d op_sla_enable:%d sla_app_switch_enable:%d\n", + __func__, skb->len, skb->mark, + ntohs(tcp_hdr(skb)->source), op_sla_enable, sla_app_switch_enable); + + if (ctinfo == IP_CT_NEW) { + if (sk) { + iph = ip_hdr(skb); + tp = tcp_sk(sk); + if (tp && iph && iph->protocol == IPPROTO_TCP) { + ct->op_tcp_continue_retrans = 0; + ct->op_tcp_last_total_retrans = tp->total_retrans; + } + ret = syn_retransmits_packet_do_specail(sk, ct, skb); + sla_mark = sk->op_sla_mark; + if (ret == SLA_SKB_MARKED) { + if (op_sla_enable && sla_app_switch_enable) { + if ((skb->mark & MARK_MASK) == CELLULAR_MARK) + notify_fw_network_switch(); + return sla_skb_reroute(skb, state); + } + if (!sla_app_switch_enable && (skb->mark & MARK_MASK) == CELLULAR_MARK) + op_sla_send_to_user(SLA_NOTIFY_SWITCH_APP_NETWORK, NULL, 0); + return NF_ACCEPT; + } else if (ret == SLA_SKB_REMARK) { + if (op_sla_enable && sla_app_switch_enable) + return NF_DROP; + if (!sla_app_switch_enable) + op_sla_send_to_user(SLA_NOTIFY_SWITCH_APP_NETWORK, NULL, 0); + return NF_ACCEPT; + } else if (ret == SLA_SKB_ACCEPT) { +#ifdef CONFIG_SLA_ALGO + reset_mark = mark_force_reset_skb(sla_mark); +#endif + if (reset_mark == 0) + return NF_ACCEPT; + } + sla_mark = sk->op_sla_mark; +#ifdef CONFIG_SLA_ALGO + retran_mark = mark_retransmits_syn_skb(sla_mark); +#endif + if (retran_mark) { + if (op_sla_debug) + pr_info("[op_sla] %s: retran mark:%x\n", + __func__, + retran_mark & MARK_MASK); + skb->mark = retran_mark; + if ((skb->mark & MARK_MASK) == CELLULAR_MARK) { + if (sla_app_switch_enable && op_sla_enable) + notify_fw_network_switch(); + else if (!sla_app_switch_enable) + op_sla_send_to_user(SLA_NOTIFY_SWITCH_APP_NETWORK, NULL, 0); + } + } else if (reset_mark) { + if (op_sla_debug) + pr_info("[op_sla] %s: reset mark:%x\n", + __func__, + reset_mark & MARK_MASK); + skb->mark = reset_mark; + } else { +#ifdef CONFIG_SLA_ALGO + if (op_sla_debug) + pr_info("[op_sla] %s: index: %x , dr: %d , dqc: %d, dfqt: %lu, time: %d\n", + __func__, + WLAN_INDEX, + op_sla_info[WLAN_INDEX].dns_refuse, + op_sla_info[WLAN_INDEX].dns_query_counts, + op_sla_info[WLAN_INDEX].dns_first_query_time, + time_now); + + if (op_sla_debug) + pr_info("[op_sla] %s: index: %x , dr: %d , dqc: %d, dfqt: %lu, time: %d\n", + __func__, + CELLULAR_INDEX, + op_sla_info[CELLULAR_INDEX].dns_refuse, + op_sla_info[CELLULAR_INDEX].dns_query_counts, + op_sla_info[CELLULAR_INDEX].dns_first_query_time, + time_now); + + update_tcp_mark(tcp_callback, time_now); + skbmark = tcp_callback[0]; +#else + skbmark = skb->mark; +#endif + skb->mark = skbmark; + if (skb->mark == CELLULAR_MARK) { + if (!sla_app_switch_enable) { + op_sla_send_to_user(SLA_NOTIFY_SWITCH_APP_NETWORK, NULL, 0); + return NF_ACCEPT; + } + if (sla_app_switch_enable && op_sla_enable) + notify_fw_network_switch(); + } + } + + ct->mark = skb->mark; + sk->op_sla_mark = skb->mark; + } + } else if ((XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_ESTABLISHED)) || + (XT_STATE_BIT(ctinfo) & XT_STATE_BIT(IP_CT_RELATED))) { + skb->mark = ct->mark & MARK_MASK; + iph = ip_hdr(skb); + if (!sk) { + if (op_sla_debug) { + pr_info("[op_sla] %s: len:%d port:%d ct->mark:%x skb->mark:%x\n", + __func__, skb->len, ntohs(tcp_hdr(skb)->source), ct->mark, skb->mark); + } + if (op_sla_enable && sla_app_switch_enable) + return sla_skb_reroute(skb, state); + return NF_ACCEPT; + } + icsk = inet_csk(sk); + sla_mark = skb->mark; + tp = tcp_sk(sk); + if (tp && iph && iph->protocol == IPPROTO_TCP) { + total_retrans = tp->total_retrans; + tcp_rtt = (tp->srtt_us >> 3) / 1000; +#ifdef CONFIG_SLA_ALGO + ifaceindex = update_sla_tcp_info(tcp_rtt, total_retrans, sla_mark); +#endif + if (op_sla_debug && ifaceindex != -1) + pr_info("[op_sla] %s: index:%d avg_rtt:%d total_retrans:%d op_tcp_last_total_retrans:%d icmp_unreachable:%d op_tcp_continue_retrans:%d\n", + __func__, + ifaceindex, + op_sla_info[ifaceindex].avg_rtt, + total_retrans, + ct->op_tcp_last_total_retrans, + op_sla_info[ifaceindex].icmp_unreachable, + ct->op_tcp_continue_retrans); + if (total_retrans > ct->op_tcp_last_total_retrans) { + ct->op_tcp_continue_retrans++; + for (i = 1; i <= ct->op_tcp_continue_retrans; i++) + calc_rtt_by_dev_index(ifaceindex, TCP_RETRAN_RTT); + ct->op_tcp_last_total_retrans = total_retrans; + } else { + ct->op_tcp_continue_retrans = 0; + } + if (ct->op_tcp_continue_retrans >= 3 && cell_quality_good) { + if (!sla_app_switch_enable) { + op_sla_send_to_user(SLA_NOTIFY_SWITCH_APP_NETWORK, NULL, 0); + } else { + if (op_sla_enable && try_to_fast_reset(top_app_type)) { + ct->mark = 0x0; + icsk = inet_csk(sk); + icsk->icsk_rto = TCP_RTO_MIN; + sk->op_sla_mark |= FORCE_RESET_MARK; + nf_reset(skb); + nf_ct_kill(ct); + return NF_DROP; + } + } + } + if (skb->mark == CELLULAR_MARK && sla_app_switch_enable && op_sla_enable) + notify_fw_network_switch(); + } + } + + if (op_sla_debug) { + pr_info("[op_sla] %s: len:%d port:%d ct->mark:%x skb->mark:%x\n", + __func__, skb->len, ntohs(tcp_hdr(skb)->source), ct->mark, skb->mark); + } + if (op_sla_enable && sla_app_switch_enable) + return sla_skb_reroute(skb, state); + return NF_ACCEPT; +} + +static int handle_game_app_skb(struct nf_conn *ct, struct sk_buff *skb, + enum ip_conntrack_info ctinfo, + const struct nf_hook_state *state) +{ + int ret = SLA_SKB_CONTINUE; + + ret = mark_game_app_skb(ct, skb, ctinfo); + if (ret == SLA_SKB_MARKED) + return sla_skb_reroute(skb, state); + else if (ret == SLA_SKB_ACCEPT) + return NF_ACCEPT; + else if (ret == SLA_SKB_DROP) + return NF_DROP; + return NF_ACCEPT; +} + +static int sla_mark_skb(struct sk_buff *skb, const struct nf_hook_state *state) +{ + struct nf_conn *ct = NULL; + int ret = SLA_SKB_CONTINUE; + enum ip_conntrack_info ctinfo; + int app_type; + + //if wlan assistant has change network to cell, do not mark SKB + if (op_sla_def_net) + return NF_ACCEPT; + + ct = nf_ct_get(skb, &ctinfo); + + if (!ct) + return NF_ACCEPT; + + sla_rtt_write_lock(); +#ifdef CONFIG_SLA_ALGO + calc_network_rtt(); +#endif + sla_rtt_write_unlock(); + + // when the wifi is poor,the dns request allways can not rcv respones, + // so please let the dns packet with the cell network mark. + ret = dns_skb_need_sla(skb, ct); + + if (ret == SLA_SKB_MARKED) { + if (!sla_app_switch_enable) { + op_sla_send_to_user(SLA_NOTIFY_SWITCH_APP_NETWORK, NULL, 0); + return NF_ACCEPT; + } + if (op_sla_enable) { + notify_fw_network_switch(); + return sla_skb_reroute(skb, state); + } + return NF_ACCEPT; + } else if (ret == SLA_SKB_ACCEPT) { + return NF_ACCEPT; + } + + if (is_skb_pre_bound(skb)) + return NF_ACCEPT; + + app_type = get_app_type(ct); + + if (app_type == GAME_TYPE && op_sla_enable) + return handle_game_app_skb(ct, skb, ctinfo, state); + else if (app_type == TOP_APP_TYPE) + return handle_top_app_skb(ct, skb, ctinfo, state); + + return NF_ACCEPT; +} + +// op sla hook function, mark skb and rerout skb +static unsigned int op_sla(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + int ret = NF_ACCEPT; + struct nf_conn *ct = NULL; + enum ip_conntrack_info ctinfo; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return NF_ACCEPT; + + detect_game_up_skb(skb); + detect_top_app_skb(skb); + + ret = sla_mark_skb(skb, state); + return ret; +} + +static unsigned int op_sla_pkt_monitor(void *priv, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct iphdr *iph = NULL; + + iph = ip_hdr(skb); + if (iph && iph->protocol == IPPROTO_UDP && + ntohs(udp_hdr(skb)->source) == 53) + parser_dns(skb); + + if (iph && iph->protocol == IPPROTO_ICMP) + parser_icmp(skb); + + if (iph && iph->protocol == IPPROTO_TCP) + parser_tcp(skb); + + return NF_ACCEPT; +} + +static inline int dev_isalive(const struct net_device *dev) +{ + return dev->reg_state <= NETREG_REGISTERED; +} + +static void init_game_online_info(void) +{ + int i = 0; + int time_now = (int)ktime_get_ns() / 1000000; + int total = op_sla_game_app_list.count + GAME_BASE; + + if (op_sla_debug) + pr_info("[op_sla] %s\n", __func__); + sla_game_write_lock(); + for (i = 0 + GAME_BASE; i < total; i++) { +#ifdef CONFIG_SLA_ALGO + op_init_game_online_info(i, time_now); +#else + op_sla_game_app_list.switch_time[i] = time_now; +#endif + } + sla_game_write_unlock(); +} + +static struct nf_hook_ops op_sla_ops[] __read_mostly = { + { + .hook = op_sla, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK + 1, + }, + { + .hook = op_sla_pkt_monitor, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_PRE_ROUTING, + .priority = NF_IP_PRI_MANGLE + 1, + }, + { + .hook = op_sla_rx_calc, + .pf = NFPROTO_IPV4, + .hooknum = NF_INET_LOCAL_IN, + .priority = NF_IP_PRI_FILTER + 1, + } +}; + +static int op_sla_set_debug(struct nlmsghdr *nlh) +{ + op_sla_debug = *(u32 *)NLMSG_DATA(nlh); + if (op_sla_debug) + pr_info("[op_sla] %s: set debug = %d\n", + __func__, op_sla_debug); + return 0; +} + +static int op_sla_set_game_mark(struct nlmsghdr *nlh) +{ + fw_set_game_mark = *(u32 *)NLMSG_DATA(nlh); + if (op_sla_debug) + pr_info("[op_sla] %s: game mark= %d\n", + __func__, fw_set_game_mark); + return 0; +} + +static int op_sla_set_default_network(struct nlmsghdr *nlh) +{ + op_sla_def_net = *(u32 *)NLMSG_DATA(nlh); + if (op_sla_debug) + pr_info("[op_sla] %s: set default network = %d\n", __func__, + op_sla_def_net); + return 0; +} + +static int disable_op_sla_module(void) +{ + if (op_sla_debug) + pr_info("[op_sla] %s: op_sla_enable=%d\n", + __func__, op_sla_enable); + sla_write_lock(); + if (op_sla_enable) { +#ifdef CONFIG_SLA_ALGO + reset_sla_info(); +#endif + init_game_online_info(); + op_sla_send_to_user(SLA_DISABLED, NULL, 0); + } + sla_write_unlock(); + return 0; +} + +static int op_sla_iface_up(struct nlmsghdr *nlh) +{ + int index = -1; + struct op_dev_info *node = NULL; + char *p = (char *)NLMSG_DATA(nlh); + + sla_write_lock(); + if (op_sla_debug) + pr_info("[op_sla] %s: enter type=%d\n", + __func__, nlh->nlmsg_type); + + if (nlh->nlmsg_type == SLA_WIFI_UP) { + index = WLAN_INDEX; + op_sla_info[WLAN_INDEX].if_up = 1; + } else if (nlh->nlmsg_type == SLA_CELLULAR_UP) { + index = CELLULAR_INDEX; + op_sla_info[CELLULAR_INDEX].if_up = 1; + } + + if (index != -1 && p) { + node = &op_sla_info[index]; + memcpy(node->dev_name, p, IFACE_LEN); + if (op_sla_debug) + pr_info("[op_sla] %s: ifname = %s ifup = %d\n", + __func__, node->dev_name, node->if_up); + } + sla_write_unlock(); + return 0; +} + +static int op_sla_iface_down(struct nlmsghdr *nlh) +{ + int index = -1; + + if (op_sla_debug) + pr_info("[op_sla] %s: type=%d\n", __func__, nlh->nlmsg_type); + + if (nlh->nlmsg_type == SLA_WIFI_DOWN) + index = WLAN_INDEX; + else if (nlh->nlmsg_type == SLA_CELLULAR_DOWN) + index = CELLULAR_INDEX; + + if (index != -1) { + sla_write_lock(); + memset(&op_sla_info[index], 0x0, + sizeof(struct op_dev_info)); + sla_write_unlock(); + } + return 0; +} + +static int op_sla_get_pid(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + op_sla_pid = NETLINK_CB(skb).portid; + if (op_sla_debug) + pr_info("[op_sla] %s: op_sla_pid = %u\n", __func__, op_sla_pid); + return 0; +} + +static int op_sla_update_wlan_score(struct nlmsghdr *nlh) +{ + int *score = (int *)NLMSG_DATA(nlh); + + if (op_sla_debug) + pr_info("[op_sla] %s: score=%d\n", __func__, *score); + + op_sla_info[WLAN_INDEX].cur_score = *score; + +#ifdef CONFIG_SLA_ALGO + update_wlan_score(); + if (need_enable_sla_for_wlan_score()) { +#else + if (sla_screen_on) { +#endif + if (op_sla_debug) + pr_info("[op_sla] %s: send SLA_ENABLE\n", + __func__); + op_sla_send_to_user(SLA_ENABLE, NULL, 0); + } + return 0; +} + +static int op_sla_set_game_app_uid(struct nlmsghdr *nlh) +{ + int i; + u32 *info = (u32 *)NLMSG_DATA(nlh); + int total; + + memset(&op_sla_game_app_list, 0x0, sizeof(struct op_game_app_info)); + init_rtt_queue_info(); + op_sla_game_app_list.count = info[0]; + total = op_sla_game_app_list.count + GAME_BASE; + if (op_sla_game_app_list.count > 0 && + op_sla_game_app_list.count <= GAME_NUM) { + for (i = 0 + GAME_BASE; i < total; i++) { + op_sla_game_app_list.uid[i] = info[i]; +#ifdef CONFIG_SLA_ALGO + set_sla_game_parameter(i); +#endif + if (op_sla_debug) + pr_info("[op_sla] %s: index=%d uid=%d\n", + __func__, + op_sla_game_app_list.game_type[i], + op_sla_game_app_list.uid[i]); + } + } + return 0; +} + +static int op_sla_set_top_app_uid(struct nlmsghdr *nlh) +{ + int i; + u32 *info = (u32 *)NLMSG_DATA(nlh); + + memset(&top_app_list, 0x0, sizeof(struct op_top_app_info)); + top_app_list.count = info[0]; + if (top_app_list.count > 0 && top_app_list.count < TOP_APP_NUM) { + for (i = 0; i < top_app_list.count; i++) { + top_app_list.uid[i] = info[i + 1]; + if (op_sla_debug) + pr_info("[op_sla] %s: count=%d, uid[%d]=%d\n", + __func__, top_app_list.count, i, + top_app_list.uid[i]); + } + } + return 0; +} + +static int op_sla_set_netlink_valid(struct nlmsghdr *nlh) +{ + u32 *info = (u32 *)NLMSG_DATA(nlh); + + op_sla_info[WLAN_INDEX].netlink_valid = info[0]; + op_sla_info[CELLULAR_INDEX].netlink_valid = info[1]; + if (op_sla_debug) + pr_info("[op_sla] %s: wlan valid:%d cell valid:%d\n", + __func__, + op_sla_info[WLAN_INDEX].netlink_valid, + op_sla_info[CELLULAR_INDEX].netlink_valid); + return 0; +} + +static int op_sla_set_game_rtt_detecting(struct nlmsghdr *nlh) +{ + op_sla_rtt_detect = (nlh->nlmsg_type == SLA_ENABLE_GAME_RTT) ? 1 : 0; + if (op_sla_debug) + pr_info("[op_sla] %s: set game rtt detect:%d\n", __func__, + op_sla_rtt_detect); + return 0; +} + +static int op_sla_set_game_switch_state(struct nlmsghdr *nlh) +{ + u32 *switch_enable = (u32 *)NLMSG_DATA(nlh); + + sla_game_switch_enable = *switch_enable; + if (op_sla_debug) + pr_info("[op_sla] %s: sla game switch:%d\n", + __func__, sla_game_switch_enable); + return 0; +} + +static int op_sla_set_app_switch_state(struct nlmsghdr *nlh) +{ + u32 *switch_enable = (u32 *)NLMSG_DATA(nlh); + + sla_app_switch_enable = *switch_enable; + if (op_sla_debug) + pr_info("[op_sla] %s: sla app switch:%d\n", + __func__, sla_app_switch_enable); + + if (sla_app_switch_enable) + reset_sla_mobile_info(); + + return 0; +} + +static int op_sla_update_screen_state(struct nlmsghdr *nlh) +{ + u32 *screen_state = (u32 *)NLMSG_DATA(nlh); + + sla_screen_on = *screen_state; + if (op_sla_debug) { + pr_info("[op_sla] %s: update screen state = %d\n", __func__, + sla_screen_on); + } + return 0; +} + +static int op_sla_update_cell_score(struct nlmsghdr *nlh) +{ + int *score = (int *)NLMSG_DATA(nlh); + + op_sla_info[CELLULAR_INDEX].cur_score = *score; + + if (op_sla_debug) { + pr_info("[op_sla] %s: update cell score:%d\n", __func__, + op_sla_info[CELLULAR_INDEX].cur_score); + } + return 0; +} + +static int op_sla_set_game_start_state(struct nlmsghdr *nlh) +{ + int *data = (int *)NLMSG_DATA(nlh); + + game_start_state = *data; + if (op_sla_debug) { + pr_info("[op_sla] %s: set game_start_state = %d\n", __func__, + game_start_state); + } + return 0; +} + +static int sla_netlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, + struct netlink_ext_ack *extack) +{ + int ret = 0; + + switch (nlh->nlmsg_type) { + case SLA_ENABLE: + ret = enable_op_sla_module(); + break; + case SLA_DISABLE: + ret = disable_op_sla_module(); + break; + case SLA_WIFI_UP: + case SLA_CELLULAR_UP: + ret = op_sla_iface_up(nlh); + break; + case SLA_WIFI_DOWN: + case SLA_CELLULAR_DOWN: + ret = op_sla_iface_down(nlh); + break; + case SLA_NOTIFY_PID: + ret = op_sla_get_pid(skb, nlh); + break; + case SLA_NOTIFY_WIFI_SCORE: + ret = op_sla_update_wlan_score(nlh); + break; + case SLA_NOTIFY_GAME_UID: + ret = op_sla_set_game_app_uid(nlh); + break; + case SLA_NOTIFY_TOP_APP: + ret = op_sla_set_top_app_uid(nlh); + break; + case SLA_SET_NETWORK_VALID: + ret = op_sla_set_netlink_valid(nlh); + break; + case SLA_ENABLE_GAME_RTT: + case SLA_DISABLE_GAME_RTT: + ret = op_sla_set_game_rtt_detecting(nlh); + break; + case SLA_NOTIFY_GAME_SWITCH_STATE: + ret = op_sla_set_game_switch_state(nlh); + break; + case SLA_NOTIFY_APP_SWITCH_STATE: + ret = op_sla_set_app_switch_state(nlh); + break; + case SLA_NOTIFY_SCREEN_STATE: + ret = op_sla_update_screen_state(nlh); + break; + case SLA_NOTIFY_CELL_SCORE: + ret = op_sla_update_cell_score(nlh); + break; + case SLA_SET_DEBUG: + op_sla_set_debug(nlh); + break; + case SLA_SET_GAME_MARK: + op_sla_set_game_mark(nlh); + break; + case SLA_NOTIFY_DEFAULT_NETWORK: + op_sla_set_default_network(nlh); + break; + case SLA_NOTIFY_GAME_STATE: + op_sla_set_game_start_state(nlh); + break; + default: + return -EINVAL; + } + + return ret; +} + +static void sla_netlink_rcv(struct sk_buff *skb) +{ + mutex_lock(&sla_netlink_mutex); + netlink_rcv_skb(skb, &sla_netlink_rcv_msg); + mutex_unlock(&sla_netlink_mutex); +} + +static int op_sla_netlink_init(void) +{ + struct netlink_kernel_cfg cfg = { + .input = sla_netlink_rcv, + }; + + op_sla_sock = netlink_kernel_create(&init_net, NETLINK_OP_SLA, &cfg); + return !op_sla_sock ? -ENOMEM : 0; +} + +static void op_sla_netlink_exit(void) +{ + netlink_kernel_release(op_sla_sock); + op_sla_sock = NULL; +} + +static void init_parameter(void) +{ + op_sla_rtt_detect = 1; + op_sla_debug = 0; + fw_set_game_mark = -1; + op_sla_def_net = 0; //WLAN->0 CELL->1 + game_start_state = 0; + game_rtt_wan_detect_flag = 0; + sla_game_switch_enable = 0; + sla_app_switch_enable = 0; + sla_screen_on = 1; + rtt_rear = 0; +} + +static void op_statistic_dev_rtt(struct sock *sk, long rtt) +{ + int index = -1; + int tmp_rtt = rtt / 1000; //us -> ms + u32 mark = sk->op_sla_mark & MARK_MASK; + +#ifdef CONFIG_SLA_ALGO + index = find_tcp_iface_index_by_mark(mark); +#endif + if (index != -1) { + sk->op_sla_mark |= RTT_MARK; + if (op_sla_debug) { + pr_info("[op_sla] %s: index:%d rtt:%d\n", + __func__, index, tmp_rtt); + } + sla_rtt_write_lock(); +#ifdef CONFIG_SLA_ALGO + calc_rtt_by_dev_index(index, tmp_rtt); +#endif + sla_rtt_write_unlock(); + } +} + +static int __init op_sla_init(void) +{ + int ret = 0; + + init_parameter(); + rwlock_init(&sla_lock); + rwlock_init(&sla_game_lock); + rwlock_init(&sla_game_rx_lock); + rwlock_init(&sla_rtt_lock); + + ret = op_sla_netlink_init(); + if (ret < 0) { + pr_info("[op_sla] %s: module can not init op sla netlink.\n", + __func__); + } + + ret |= nf_register_net_hooks(&init_net, + op_sla_ops, ARRAY_SIZE(op_sla_ops)); + if (ret < 0) { + pr_info("[op_sla] %s: module can not register netfilter ops.\n", + __func__); + } + statistic_dev_rtt = op_statistic_dev_rtt; + + return ret; +} + +static void __exit op_sla_deinit(void) +{ + statistic_dev_rtt = NULL; + op_sla_netlink_exit(); + nf_unregister_net_hooks(&init_net, op_sla_ops, ARRAY_SIZE(op_sla_ops)); +} + +module_init(op_sla_init); +module_exit(op_sla_deinit); diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 59dd4ae583ac4a10e21626ef08d4d48d5fa3d78d..3b1222869a2b247d374b17b7349bf5541143b420 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -29,7 +29,13 @@ #define QRTR_LOG_PAGE_CNT 4 #define QRTR_INFO(ctx, x, ...) \ - ipc_log_string(ctx, x, ##__VA_ARGS__) + do { \ + ipc_log_string(ctx, x, ##__VA_ARGS__); \ + if (!qrtr_first_msg) { \ + qrtr_first_msg = 1; \ + pr_info(x, ##__VA_ARGS__); \ + } \ + } while (0) #define QRTR_PROTO_VER_1 1 #define QRTR_PROTO_VER_2 3 @@ -223,8 +229,8 @@ static void qrtr_log_tx_msg(struct qrtr_node *node, struct qrtr_hdr_v1 *hdr, if (hdr->type == QRTR_TYPE_DATA) { skb_copy_bits(skb, QRTR_HDR_MAX_SIZE, &pl_buf, sizeof(pl_buf)); QRTR_INFO(node->ilc, - "TX DATA: Len:0x%x CF:0x%x src[0x%x:0x%x] dst[0x%x:0x%x] [%08x %08x] [%s]\n", - hdr->size, hdr->confirm_rx, + "qrtr_%d: TX DATA: Len:0x%x CF:0x%x src[0x%x:0x%x] dst[0x%x:0x%x] [%08x %08x] [%s]\n", + node->nid, hdr->size, hdr->confirm_rx, hdr->src_node_id, hdr->src_port_id, hdr->dst_node_id, hdr->dst_port_id, (unsigned int)pl_buf, (unsigned int)(pl_buf >> 32), @@ -234,26 +240,26 @@ static void qrtr_log_tx_msg(struct qrtr_node *node, struct qrtr_hdr_v1 *hdr, if (hdr->type == QRTR_TYPE_NEW_SERVER || hdr->type == QRTR_TYPE_DEL_SERVER) QRTR_INFO(node->ilc, - "TX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", - hdr->type, le32_to_cpu(pkt.server.service), + "qrtr_%d: TX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", + node->nid, hdr->type, le32_to_cpu(pkt.server.service), le32_to_cpu(pkt.server.instance), le32_to_cpu(pkt.server.node), le32_to_cpu(pkt.server.port)); else if (hdr->type == QRTR_TYPE_DEL_CLIENT || hdr->type == QRTR_TYPE_RESUME_TX) QRTR_INFO(node->ilc, - "TX CTRL: cmd:0x%x addr[0x%x:0x%x]\n", - hdr->type, le32_to_cpu(pkt.client.node), + "qrtr_%d: TX CTRL: cmd:0x%x addr[0x%x:0x%x]\n", + node->nid, hdr->type, le32_to_cpu(pkt.client.node), le32_to_cpu(pkt.client.port)); else if (hdr->type == QRTR_TYPE_HELLO || hdr->type == QRTR_TYPE_BYE) QRTR_INFO(node->ilc, - "TX CTRL: cmd:0x%x node[0x%x]\n", - hdr->type, hdr->src_node_id); + "qrtr_%d: TX CTRL: cmd:0x%x node[0x%x]\n", + node->nid, hdr->type, hdr->src_node_id); else if (hdr->type == QRTR_TYPE_DEL_PROC) QRTR_INFO(node->ilc, - "TX CTRL: cmd:0x%x node[0x%x]\n", - hdr->type, pkt.proc.node); + "qrtr_%d: TX CTRL: cmd:0x%x node[0x%x]\n", + node->nid, hdr->type, pkt.proc.node); } } @@ -271,8 +277,8 @@ static void qrtr_log_rx_msg(struct qrtr_node *node, struct sk_buff *skb) if (cb->type == QRTR_TYPE_DATA) { skb_copy_bits(skb, 0, &pl_buf, sizeof(pl_buf)); QRTR_INFO(node->ilc, - "RX DATA: Len:0x%x CF:0x%x src[0x%x:0x%x] dst[0x%x:0x%x] [%08x %08x]\n", - skb->len, cb->confirm_rx, cb->src_node, cb->src_port, + "qrtr_%d: RX DATA: Len:0x%x CF:0x%x src[0x%x:0x%x] dst[0x%x:0x%x] [%08x %08x]\n", + node->nid, skb->len, cb->confirm_rx, cb->src_node, cb->src_port, cb->dst_node, cb->dst_port, (unsigned int)pl_buf, (unsigned int)(pl_buf >> 32)); } else { @@ -280,22 +286,22 @@ static void qrtr_log_rx_msg(struct qrtr_node *node, struct sk_buff *skb) if (cb->type == QRTR_TYPE_NEW_SERVER || cb->type == QRTR_TYPE_DEL_SERVER) QRTR_INFO(node->ilc, - "RX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", - cb->type, le32_to_cpu(pkt.server.service), + "qrtr_%d: RX CTRL: cmd:0x%x SVC[0x%x:0x%x] addr[0x%x:0x%x]\n", + node->nid, cb->type, le32_to_cpu(pkt.server.service), le32_to_cpu(pkt.server.instance), le32_to_cpu(pkt.server.node), le32_to_cpu(pkt.server.port)); else if (cb->type == QRTR_TYPE_DEL_CLIENT || cb->type == QRTR_TYPE_RESUME_TX) QRTR_INFO(node->ilc, - "RX CTRL: cmd:0x%x addr[0x%x:0x%x]\n", - cb->type, le32_to_cpu(pkt.client.node), + "qrtr_%d: RX CTRL: cmd:0x%x addr[0x%x:0x%x]\n", + node->nid, cb->type, le32_to_cpu(pkt.client.node), le32_to_cpu(pkt.client.port)); else if (cb->type == QRTR_TYPE_HELLO || cb->type == QRTR_TYPE_BYE) QRTR_INFO(node->ilc, - "RX CTRL: cmd:0x%x node[0x%x]\n", - cb->type, cb->src_node); + "qrtr_%d: RX CTRL: cmd:0x%x node[0x%x]\n", + node->nid, cb->type, cb->src_node); } } diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h index 6a2cccb1296eb3c912f6a118473dcddb44fa5081..e984e95b28943d428e6a2146dfce69c61f19ddb2 100644 --- a/net/qrtr/qrtr.h +++ b/net/qrtr/qrtr.h @@ -4,6 +4,7 @@ #include +extern unsigned int qrtr_first_msg; struct sk_buff; /* endpoint node id auto assignment */ diff --git a/opslalib/Makefile b/opslalib/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cb3c6e7ec792fc59a92967b1b78ff4a7bc44cd74 --- /dev/null +++ b/opslalib/Makefile @@ -0,0 +1,4 @@ +SLA_LIB_PATH = $(KBUILD_SRC)/opslalib/slalib +ifeq ($(SLA_LIB_PATH),$(wildcard $(SLA_LIB_PATH))) +obj-$(CONFIG_SLA) += slalib/op_sla_help_lib.o +endif diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..61af3098ee9895971341202ef49694a535a70d09 --- /dev/null +++ b/readme.txt @@ -0,0 +1 @@ +Oneplus Nord Oxygen OS 11.AC01DA : No change since last Oneplus Nord OPNord_O2_BETA_3 diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index f49524e148516af2d591ace5c6ed1d5a81089c5b..0d6fc5babd57606eabdd3073821be2964dcc1888 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -20,7 +20,7 @@ use constant IN_SHORTTEXT_BLANKLINE => 1; use constant IN_SHORTTEXT => 2; use constant AFTER_SHORTTEXT => 3; use constant CHECK_NEXT_SHORTTEXT => 4; -use constant SHORTTEXT_LIMIT => 75; +use constant SHORTTEXT_LIMIT => 120; my $P = $0; my $D = dirname(abs_path($P)); @@ -58,7 +58,7 @@ my %ignore_type = (); my @ignore = (); my $help = 0; my $configuration_file = ".checkpatch.conf"; -my $max_line_length = 80; +my $max_line_length = 120; my $ignore_perl_version = 0; my $minimum_perl_version = 5.10.0; my $min_conf_desc_length = 4; @@ -2799,10 +2799,10 @@ sub process { } # Check for unwanted Gerrit info - if ($in_commit_log && $line =~ /^\s*change-id:/i) { - ERROR("GERRIT_CHANGE_ID", - "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); - } +# if ($in_commit_log && $line =~ /^\s*change-id:/i) { +# ERROR("GERRIT_CHANGE_ID", +# "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); +# } # Check if the commit log is in a possible stack dump if ($in_commit_log && !$commit_log_possible_stack_dump && @@ -2814,9 +2814,9 @@ sub process { $commit_log_possible_stack_dump = 1; } -# Check for line lengths > 75 in commit log, warn once +# Check for line lengths > 120 in commit log, warn once if ($in_commit_log && !$commit_log_long_line && - length($line) > 75 && + length($line) > 120 && !($line =~ /^\s*[a-zA-Z0-9_\/\.\-\,]+\s+\|\s+\d+/ || # file delta changes $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || @@ -2825,7 +2825,7 @@ sub process { # A Fixes: or Link: line $commit_log_possible_stack_dump)) { WARN("COMMIT_LOG_LONG_LINE", - "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); + "Possible unwrapped commit description (prefer a maximum 120 chars per line)\n" . $herecurr); $commit_log_long_line = 1; } @@ -2887,24 +2887,24 @@ sub process { ($id, $description) = git_commit_info($orig_commit, $id, $orig_desc); - if (defined($id) && - ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens)) { - ERROR("GIT_COMMIT_ID", - "Please use git commit description style 'commit <12+ chars of sha1> (\"\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr); - } +# if (defined($id) && +# ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens)) { +# ERROR("GIT_COMMIT_ID", +# "Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr); +# } } # Check for added, moved or deleted files - if (!$reported_maintainer_file && !$in_commit_log && - ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || - $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || - ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && - (defined($1) || defined($2))))) { - $is_patch = 1; - $reported_maintainer_file = 1; - WARN("FILE_PATH_CHANGES", - "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); - } +# if (!$reported_maintainer_file && !$in_commit_log && +# ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || +# $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || +# ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && +# (defined($1) || defined($2))))) { +# $is_patch = 1; +# $reported_maintainer_file = 1; +# WARN("FILE_PATH_CHANGES", +# "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); +# } # Check for wrappage within a valid hunk of the file if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { @@ -3880,6 +3880,12 @@ sub process { } } +# avoid VENDOR_EDIT + if ($rawline =~ /\bVENDOR_EDIT\b/) { + WARN("VENDOR_EDIT", + "Please remove VENDOR_EDIT before you commit it\n" . $herecurr); + } + # # Checks which are anchored on the added line. # @@ -4126,18 +4132,18 @@ sub process { } # avoid BUG() or BUG_ON() - if ($line =~ /\b(?:BUG|BUG_ON)\b/) { - my $msg_level = \&WARN; - $msg_level = \&CHK if ($file); - &{$msg_level}("AVOID_BUG", - "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); - } +# if ($line =~ /\b(?:BUG|BUG_ON)\b/) { +# my $msg_level = \&WARN; +# $msg_level = \&CHK if ($file); +# &{$msg_level}("AVOID_BUG", +# "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); +# } # avoid LINUX_VERSION_CODE - if ($line =~ /\bLINUX_VERSION_CODE\b/) { - WARN("LINUX_VERSION_CODE", - "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); - } +#if ($line =~ /\bLINUX_VERSION_CODE\b/) { +# WARN("LINUX_VERSION_CODE", +# "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); +# } # check for uses of printk_ratelimit if ($line =~ /\bprintk_ratelimit\s*\(/) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b0195a9d10a7fa08c057194e6a287f8c34b135e2..e7778880c09327820d068822d6f5523b7d39ba6d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -5596,40 +5596,60 @@ static int selinux_tun_dev_open(void *security) static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) { - int err = 0; - u32 perm; + int rc = 0; + unsigned int msg_len; + unsigned int data_len = skb->len; + unsigned char *data = skb->data; struct nlmsghdr *nlh; struct sk_security_struct *sksec = sk->sk_security; + u16 sclass = sksec->sclass; + u32 perm; - if (skb->len < NLMSG_HDRLEN) { - err = -EINVAL; - goto out; - } - nlh = nlmsg_hdr(skb); + while (data_len >= nlmsg_total_size(0)) { + nlh = (struct nlmsghdr *)data; + + /* NOTE: the nlmsg_len field isn't reliably set by some netlink + * users which means we can't reject skb's with bogus + * length fields; our solution is to follow what + * netlink_rcv_skb() does and simply skip processing at + * messages with length fields that are clearly junk + */ + if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len) + return 0; - err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); - if (err) { - if (err == -EINVAL) { + rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm); + if (rc == 0) { + rc = sock_has_perm(sk, perm); + if (rc) + return rc; + } else if (rc == -EINVAL) { + /* -EINVAL is a missing msg/perm mapping */ pr_warn_ratelimited("SELinux: unrecognized netlink" - " message: protocol=%hu nlmsg_type=%hu sclass=%s" - " pig=%d comm=%s\n", - sk->sk_protocol, nlh->nlmsg_type, - secclass_map[sksec->sclass - 1].name, - task_pid_nr(current), current->comm); - if (!enforcing_enabled(&selinux_state) || - security_get_allow_unknown(&selinux_state)) - err = 0; + " message: protocol=%hu nlmsg_type=%hu sclass=%s" + " pid=%d comm=%s\n", + sk->sk_protocol, nlh->nlmsg_type, + secclass_map[sclass - 1].name, + task_pid_nr(current), current->comm); + if (enforcing_enabled(&selinux_state) && + !security_get_allow_unknown(&selinux_state)) + return rc; + rc = 0; + } else if (rc == -ENOENT) { + /* -ENOENT is a missing socket/class mapping, ignore */ + rc = 0; + } else { + return rc; } - /* Ignore */ - if (err == -ENOENT) - err = 0; - goto out; + /* move to the next message after applying netlink padding */ + msg_len = NLMSG_ALIGN(nlh->nlmsg_len); + if (msg_len >= data_len) + return 0; + data_len -= msg_len; + data += msg_len; } - err = sock_has_perm(sk, perm); -out: - return err; + return rc; } #ifdef CONFIG_NETFILTER diff --git a/techpack/.gitignore b/techpack/.gitignore deleted file mode 100644 index 6782432896fa87fcaca704270aac4781b9f5847e..0000000000000000000000000000000000000000 --- a/techpack/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# ignore all subdirs except stub -!/stub/ diff --git a/techpack/camera/Makefile b/techpack/camera/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9e0b13785b5873daa418313fac73c21e30742e2d --- /dev/null +++ b/techpack/camera/Makefile @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# auto-detect subdirs +ifeq ($(CONFIG_ARCH_KONA), y) +include $(srctree)/techpack/camera/config/konacamera.conf +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +include $(srctree)/techpack/camera/config/litocamera.conf +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +include $(srctree)/techpack/camera/config/bengalcamera.conf +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/konacameraconf.h +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/litocameraconf.h +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/camera/config/bengalcameraconf.h +endif + +ifdef CONFIG_SPECTRA_CAMERA +# Use USERINCLUDE when you must reference the UAPI directories only. +USERINCLUDE += \ + -I$(srctree)/techpack/camera/include/uapi + +# Use LINUXINCLUDE when you must reference the include/ directory. +# Needed to be compatible with the O= option +LINUXINCLUDE += \ + -I$(srctree)/techpack/camera/include/uapi \ + -I$(srctree)/techpack/camera/include +obj-y += drivers/ +else +$(info Target not found) +endif diff --git a/techpack/camera/config/bengalcamera.conf b/techpack/camera/config/bengalcamera.conf new file mode 100644 index 0000000000000000000000000000000000000000..451723eebce308111e4ab533a67ca18b1950ac99 --- /dev/null +++ b/techpack/camera/config/bengalcamera.conf @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=y diff --git a/techpack/camera/config/bengalcameraconf.h b/techpack/camera/config/bengalcameraconf.h new file mode 100644 index 0000000000000000000000000000000000000000..1a77140180043c3f22be20d50ad3cd7341913a5f --- /dev/null +++ b/techpack/camera/config/bengalcameraconf.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 + diff --git a/techpack/camera/config/konacamera.conf b/techpack/camera/config/konacamera.conf new file mode 100644 index 0000000000000000000000000000000000000000..9b08bcb80c2ba739ccfe3475123b727f6b8ce9be --- /dev/null +++ b/techpack/camera/config/konacamera.conf @@ -0,0 +1 @@ +export CONFIG_SPECTRA_CAMERA=y \ No newline at end of file diff --git a/techpack/camera/config/konacameraconf.h b/techpack/camera/config/konacameraconf.h new file mode 100644 index 0000000000000000000000000000000000000000..875b95587ab6d5da4b36468a13e42b6aa13ee80a --- /dev/null +++ b/techpack/camera/config/konacameraconf.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#define CONFIG_SPECTRA_CAMERA 1 + diff --git a/techpack/camera/config/litocamera.conf b/techpack/camera/config/litocamera.conf new file mode 100755 index 0000000000000000000000000000000000000000..fb57e2d35c95b20283a9eff7614e294c52a81c3c --- /dev/null +++ b/techpack/camera/config/litocamera.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019, The Linux Foundation. All rights reserved. + +export CONFIG_SPECTRA_CAMERA=y +export DOWNLOAD_OIS_FW_BEFORE=y \ No newline at end of file diff --git a/techpack/camera/config/litocameraconf.h b/techpack/camera/config/litocameraconf.h new file mode 100644 index 0000000000000000000000000000000000000000..eb207dcc7358aa06ab243617657f8458ee10c5e7 --- /dev/null +++ b/techpack/camera/config/litocameraconf.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_SPECTRA_CAMERA 1 +#define DOWNLOAD_OIS_FW_BEFORE 1 + diff --git a/techpack/camera/drivers/Makefile b/techpack/camera/drivers/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..13edfb587419fb93655d1058cda02b29d8118cb7 --- /dev/null +++ b/techpack/camera/drivers/Makefile @@ -0,0 +1,14 @@ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_module/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cust/ diff --git a/techpack/camera/drivers/cam_cdm/Makefile b/techpack/camera/drivers/cam_cdm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..323a523011a2833df1433d19c0325b534a538dd1 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cdm_soc.o cam_cdm_util.o cam_cdm_intf.o\ + cam_cdm_core_common.o cam_cdm_virtual_core.o \ + cam_cdm_hw_core.o diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm.h b/techpack/camera/drivers/cam_cdm/cam_cdm.h new file mode 100644 index 0000000000000000000000000000000000000000..ab12ab52f293483cb0b947b0656a898ee6e73530 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_H_ +#define _CAM_CDM_H_ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/random.h> +#include <linux/spinlock_types.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include <linux/bug.h> + +#include "cam_cdm_intf_api.h" +#include "cam_soc_util.h" +#include "cam_cpas_api.h" +#include "cam_hw_intf.h" +#include "cam_hw.h" +#include "cam_debug_util.h" + +#define CAM_MAX_SW_CDM_VERSION_SUPPORTED 1 +#define CAM_SW_CDM_INDEX 0 +#define CAM_CDM_INFLIGHT_WORKS 5 +#define CAM_CDM_HW_RESET_TIMEOUT 300 + +#define CAM_CDM_HW_ID_MASK 0xF +#define CAM_CDM_HW_ID_SHIFT 0x5 +#define CAM_CDM_CLIENTS_ID_MASK 0x1F + +#define CAM_CDM_GET_HW_IDX(x) (((x) >> CAM_CDM_HW_ID_SHIFT) & \ + CAM_CDM_HW_ID_MASK) +#define CAM_CDM_CREATE_CLIENT_HANDLE(hw_idx, client_idx) \ + ((((hw_idx) & CAM_CDM_HW_ID_MASK) << CAM_CDM_HW_ID_SHIFT) | \ + ((client_idx) & CAM_CDM_CLIENTS_ID_MASK)) +#define CAM_CDM_GET_CLIENT_IDX(x) ((x) & CAM_CDM_CLIENTS_ID_MASK) +#define CAM_PER_CDM_MAX_REGISTERED_CLIENTS (CAM_CDM_CLIENTS_ID_MASK + 1) +#define CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM (CAM_CDM_HW_ID_MASK + 1) + +/* enum cam_cdm_reg_attr - read, write, read and write permissions.*/ +enum cam_cdm_reg_attr { + CAM_REG_ATTR_READ, + CAM_REG_ATTR_WRITE, + CAM_REG_ATTR_READ_WRITE, +}; + +/* enum cam_cdm_hw_process_intf_cmd - interface commands.*/ +enum cam_cdm_hw_process_intf_cmd { + CAM_CDM_HW_INTF_CMD_ACQUIRE, + CAM_CDM_HW_INTF_CMD_RELEASE, + CAM_CDM_HW_INTF_CMD_SUBMIT_BL, + CAM_CDM_HW_INTF_CMD_RESET_HW, + CAM_CDM_HW_INTF_CMD_INVALID, +}; + +/* enum cam_cdm_regs - CDM driver offset enums.*/ +enum cam_cdm_regs { + /*cfg_offsets 0*/ + CDM_CFG_HW_VERSION, + CDM_CFG_TITAN_VERSION, + CDM_CFG_RST_CMD, + CDM_CFG_CGC_CFG, + CDM_CFG_CORE_CFG, + CDM_CFG_CORE_EN, + CDM_CFG_FE_CFG, + /*irq_offsets 7*/ + CDM_IRQ_MASK, + CDM_IRQ_CLEAR, + CDM_IRQ_CLEAR_CMD, + CDM_IRQ_SET, + CDM_IRQ_SET_CMD, + CDM_IRQ_STATUS, + CDM_IRQ_USR_DATA, + /*BL FIFO Registers 14*/ + CDM_BL_FIFO_BASE_REG, + CDM_BL_FIFO_LEN_REG, + CDM_BL_FIFO_STORE_REG, + CDM_BL_FIFO_CFG, + CDM_BL_FIFO_RB, + CDM_BL_FIFO_BASE_RB, + CDM_BL_FIFO_LEN_RB, + CDM_BL_FIFO_PENDING_REQ_RB, + /*CDM System Debug Registers 22*/ + CDM_DBG_WAIT_STATUS, + CDM_DBG_SCRATCH_0_REG, + CDM_DBG_SCRATCH_1_REG, + CDM_DBG_SCRATCH_2_REG, + CDM_DBG_SCRATCH_3_REG, + CDM_DBG_SCRATCH_4_REG, + CDM_DBG_SCRATCH_5_REG, + CDM_DBG_SCRATCH_6_REG, + CDM_DBG_SCRATCH_7_REG, + CDM_DBG_LAST_AHB_ADDR, + CDM_DBG_LAST_AHB_DATA, + CDM_DBG_CORE_DBUG, + CDM_DBG_LAST_AHB_ERR_ADDR, + CDM_DBG_LAST_AHB_ERR_DATA, + CDM_DBG_CURRENT_BL_BASE, + CDM_DBG_CURRENT_BL_LEN, + CDM_DBG_CURRENT_USED_AHB_BASE, + CDM_DBG_DEBUG_STATUS, + /*FE Bus Miser Registers 40*/ + CDM_BUS_MISR_CFG_0, + CDM_BUS_MISR_CFG_1, + CDM_BUS_MISR_RD_VAL, + /*Performance Counter registers 43*/ + CDM_PERF_MON_CTRL, + CDM_PERF_MON_0, + CDM_PERF_MON_1, + CDM_PERF_MON_2, + /*Spare registers 47*/ + CDM_SPARE, +}; + +/* struct cam_cdm_reg_offset - struct for offset with attribute.*/ +struct cam_cdm_reg_offset { + uint32_t offset; + enum cam_cdm_reg_attr attribute; +}; + +/* struct cam_cdm_reg_offset_table - struct for whole offset table.*/ +struct cam_cdm_reg_offset_table { + uint32_t first_offset; + uint32_t last_offset; + uint32_t reg_count; + const struct cam_cdm_reg_offset *offsets; + uint32_t offset_max_size; +}; + +/* enum cam_cdm_flags - Bit fields for CDM flags used */ +enum cam_cdm_flags { + CAM_CDM_FLAG_SHARED_CDM, + CAM_CDM_FLAG_PRIVATE_CDM, +}; + +/* enum cam_cdm_type - Enum for possible CAM CDM types */ +enum cam_cdm_type { + CAM_VIRTUAL_CDM, + CAM_HW_CDM, +}; + +/* enum cam_cdm_mem_base_index - Enum for possible CAM CDM types */ +enum cam_cdm_mem_base_index { + CAM_HW_CDM_BASE_INDEX, + CAM_HW_CDM_MAX_INDEX = CAM_SOC_MAX_BLOCK, +}; + +/* struct cam_cdm_client - struct for cdm clients data.*/ +struct cam_cdm_client { + struct cam_cdm_acquire_data data; + void __iomem *changebase_addr; + uint32_t stream_on; + uint32_t refcount; + struct mutex lock; + uint32_t handle; +}; + +/* struct cam_cdm_work_payload - struct for cdm work payload data.*/ +struct cam_cdm_work_payload { + struct cam_hw_info *hw; + uint32_t irq_status; + uint32_t irq_data; + struct work_struct work; +}; + +/* enum cam_cdm_bl_cb_type - Enum for possible CAM CDM cb request types */ +enum cam_cdm_bl_cb_type { + CAM_HW_CDM_BL_CB_CLIENT = 1, + CAM_HW_CDM_BL_CB_INTERNAL, +}; + +/* struct cam_cdm_bl_cb_request_entry - callback entry for work to process.*/ +struct cam_cdm_bl_cb_request_entry { + uint8_t bl_tag; + enum cam_cdm_bl_cb_type request_type; + uint32_t client_hdl; + void *userdata; + uint32_t cookie; + struct list_head entry; +}; + +/* struct cam_cdm_hw_intf_cmd_submit_bl - cdm interface submit command.*/ +struct cam_cdm_hw_intf_cmd_submit_bl { + uint32_t handle; + struct cam_cdm_bl_request *data; +}; + +/* struct cam_cdm_hw_mem - CDM hw memory struct */ +struct cam_cdm_hw_mem { + int32_t handle; + uint32_t vaddr; + uintptr_t kmdvaddr; + size_t size; +}; + +/* struct cam_cdm - CDM hw device struct */ +struct cam_cdm { + uint32_t index; + char name[128]; + enum cam_cdm_id id; + enum cam_cdm_flags flags; + struct completion reset_complete; + struct completion bl_complete; + struct workqueue_struct *work_queue; + struct list_head bl_request_list; + struct cam_hw_version version; + uint32_t hw_version; + uint32_t hw_family_version; + struct cam_iommu_handle iommu_hdl; + struct cam_cdm_reg_offset_table *offset_tbl; + struct cam_cdm_utils_ops *ops; + struct cam_cdm_client *clients[CAM_PER_CDM_MAX_REGISTERED_CLIENTS]; + uint8_t bl_tag; + atomic_t error; + atomic_t bl_done; + struct cam_cdm_hw_mem gen_irq; + uint32_t cpas_handle; +}; + +/* struct cam_cdm_private_dt_data - CDM hw custom dt data */ +struct cam_cdm_private_dt_data { + bool dt_cdm_shared; + uint32_t dt_num_supported_clients; + const char *dt_cdm_client_name[CAM_PER_CDM_MAX_REGISTERED_CLIENTS]; +}; + +/* struct cam_cdm_intf_devices - CDM mgr interface devices */ +struct cam_cdm_intf_devices { + struct mutex lock; + uint32_t refcount; + struct cam_hw_intf *device; + struct cam_cdm_private_dt_data *data; +}; + +/* struct cam_cdm_intf_mgr - CDM mgr interface device struct */ +struct cam_cdm_intf_mgr { + bool probe_done; + struct cam_cdm_intf_devices nodes[CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM]; + uint32_t cdm_count; + uint32_t dt_supported_hw_cdm; + int32_t refcount; +}; + +int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t *index); +int cam_cdm_intf_deregister_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t index); + +#endif /* _CAM_CDM_H_ */ diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_core_common.c b/techpack/camera/drivers/cam_cdm/cam_cdm_core_common.c new file mode 100644 index 0000000000000000000000000000000000000000..e903dc805ed02f923966354ca7d9a95570355dbf --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_core_common.c @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_io_util.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_soc.h" +#include "cam_cdm_core_common.h" + +static void cam_cdm_get_client_refcount(struct cam_cdm_client *client) +{ + mutex_lock(&client->lock); + CAM_DBG(CAM_CDM, "CDM client get refcount=%d", + client->refcount); + client->refcount++; + mutex_unlock(&client->lock); +} + +static void cam_cdm_put_client_refcount(struct cam_cdm_client *client) +{ + mutex_lock(&client->lock); + CAM_DBG(CAM_CDM, "CDM client put refcount=%d", + client->refcount); + if (client->refcount > 0) { + client->refcount--; + } else { + CAM_ERR(CAM_CDM, "Refcount put when zero"); + WARN_ON(1); + } + mutex_unlock(&client->lock); +} + +bool cam_cdm_set_cam_hw_version( + uint32_t ver, struct cam_hw_version *cam_version) +{ + switch (ver) { + case CAM_CDM170_VERSION: + case CAM_CDM175_VERSION: + case CAM_CDM480_VERSION: + cam_version->major = (ver & 0xF0000000); + cam_version->minor = (ver & 0xFFF0000); + cam_version->incr = (ver & 0xFFFF); + cam_version->reserved = 0; + return true; + default: + CAM_ERR(CAM_CDM, "CDM Version=%x not supported in util", ver); + break; + } + return false; +} + +bool cam_cdm_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + if (!irq_data) + return false; + + CAM_DBG(CAM_CDM, "CPAS error callback type=%d", irq_data->irq_type); + + return false; +} + +struct cam_cdm_utils_ops *cam_cdm_get_ops( + uint32_t ver, struct cam_hw_version *cam_version, bool by_cam_version) +{ + if (by_cam_version == false) { + switch (ver) { + case CAM_CDM170_VERSION: + case CAM_CDM175_VERSION: + case CAM_CDM480_VERSION: + return &CDM170_ops; + default: + CAM_ERR(CAM_CDM, "CDM Version=%x not supported in util", + ver); + } + } else if (cam_version) { + if (((cam_version->major == 1) && + (cam_version->minor == 0) && + (cam_version->incr == 0)) || + ((cam_version->major == 1) && + (cam_version->minor == 1) && + (cam_version->incr == 0)) || + ((cam_version->major == 1) && + (cam_version->minor == 2) && + (cam_version->incr == 0))) { + + CAM_DBG(CAM_CDM, + "cam_hw_version=%x:%x:%x supported", + cam_version->major, cam_version->minor, + cam_version->incr); + return &CDM170_ops; + } + + CAM_ERR(CAM_CDM, "cam_hw_version=%x:%x:%x not supported", + cam_version->major, cam_version->minor, + cam_version->incr); + } + + return NULL; +} + +struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( + uint32_t tag, struct list_head *bl_list) +{ + struct cam_cdm_bl_cb_request_entry *node; + + list_for_each_entry(node, bl_list, entry) { + if (node->bl_tag == tag) + return node; + } + CAM_ERR(CAM_CDM, "Could not find the bl request for tag=%x", tag); + + return NULL; +} + +int cam_cdm_get_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *cdm_core; + + if ((cdm_hw) && (cdm_hw->core_info) && (get_hw_cap_args) && + (sizeof(struct cam_iommu_handle) == arg_size)) { + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + *((struct cam_iommu_handle *)get_hw_cap_args) = + cdm_core->iommu_hdl; + return 0; + } + + return -EINVAL; +} + +int cam_cdm_find_free_client_slot(struct cam_cdm *hw) +{ + int i; + + for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { + if (hw->clients[i] == NULL) { + CAM_DBG(CAM_CDM, "Found client slot %d", i); + return i; + } + } + CAM_ERR(CAM_CDM, "No more client slots"); + + return -EBUSY; +} + + +void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, + enum cam_cdm_cb_status status, void *data) +{ + int i; + struct cam_cdm *core = NULL; + struct cam_cdm_client *client = NULL; + + if (!cdm_hw) { + CAM_ERR(CAM_CDM, "CDM Notify called with NULL hw info"); + return; + } + core = (struct cam_cdm *)cdm_hw->core_info; + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + int client_idx; + struct cam_cdm_bl_cb_request_entry *node = + (struct cam_cdm_bl_cb_request_entry *)data; + + client_idx = CAM_CDM_GET_CLIENT_IDX(node->client_hdl); + client = core->clients[client_idx]; + if ((!client) || (client->handle != node->client_hdl)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, + node->client_hdl); + return; + } + cam_cdm_get_client_refcount(client); + if (client->data.cam_cdm_callback) { + CAM_DBG(CAM_CDM, "Calling client=%s cb cookie=%d", + client->data.identifier, node->cookie); + client->data.cam_cdm_callback(node->client_hdl, + node->userdata, CAM_CDM_CB_STATUS_BL_SUCCESS, + node->cookie); + CAM_DBG(CAM_CDM, "Exit client cb cookie=%d", + node->cookie); + } else { + CAM_ERR(CAM_CDM, "No cb registered for client hdl=%x", + node->client_hdl); + } + cam_cdm_put_client_refcount(client); + return; + } + + for (i = 0; i < CAM_PER_CDM_MAX_REGISTERED_CLIENTS; i++) { + if (core->clients[i] != NULL) { + client = core->clients[i]; + mutex_lock(&client->lock); + CAM_DBG(CAM_CDM, "Found client slot %d", i); + if (client->data.cam_cdm_callback) { + if (status == CAM_CDM_CB_STATUS_PAGEFAULT) { + unsigned long iova = + (unsigned long)data; + + client->data.cam_cdm_callback( + client->handle, + client->data.userdata, + CAM_CDM_CB_STATUS_PAGEFAULT, + (iova & 0xFFFFFFFF)); + } + } else { + CAM_ERR(CAM_CDM, + "No cb registered for client hdl=%x", + client->handle); + } + mutex_unlock(&client->lock); + } + } +} + +int cam_cdm_stream_ops_internal(void *hw_priv, + void *start_args, bool operation) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *core = NULL; + int rc = -EPERM; + int client_idx; + struct cam_cdm_client *client; + uint32_t *handle = start_args; + + if (!hw_priv) + return -EINVAL; + + core = (struct cam_cdm *)cdm_hw->core_info; + client_idx = CAM_CDM_GET_CLIENT_IDX(*handle); + client = core->clients[client_idx]; + if (!client) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, *handle); + return -EINVAL; + } + cam_cdm_get_client_refcount(client); + if (*handle != client->handle) { + CAM_ERR(CAM_CDM, "client id given handle=%x invalid", *handle); + cam_cdm_put_client_refcount(client); + return -EINVAL; + } + if (operation == true) { + if (true == client->stream_on) { + CAM_ERR(CAM_CDM, + "Invalid CDM client is already streamed ON"); + cam_cdm_put_client_refcount(client); + return rc; + } + } else { + if (client->stream_on == false) { + CAM_ERR(CAM_CDM, + "Invalid CDM client is already streamed Off"); + cam_cdm_put_client_refcount(client); + return rc; + } + } + + mutex_lock(&cdm_hw->hw_mutex); + if (operation == true) { + if (!cdm_hw->open_count) { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = + CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core->cpas_handle, + &ahb_vote, &axi_vote); + if (rc != 0) { + CAM_ERR(CAM_CDM, "CPAS start failed"); + goto end; + } + CAM_DBG(CAM_CDM, "CDM init first time"); + if (core->id == CAM_CDM_VIRTUAL) { + CAM_DBG(CAM_CDM, + "Virtual CDM HW init first time"); + rc = 0; + } else { + CAM_DBG(CAM_CDM, "CDM HW init first time"); + rc = cam_hw_cdm_init(hw_priv, NULL, 0); + if (rc == 0) { + rc = cam_hw_cdm_alloc_genirq_mem( + hw_priv); + if (rc != 0) { + CAM_ERR(CAM_CDM, + "Genirqalloc failed"); + cam_hw_cdm_deinit(hw_priv, + NULL, 0); + } + } else { + CAM_ERR(CAM_CDM, "CDM HW init failed"); + } + } + if (rc == 0) { + cdm_hw->open_count++; + client->stream_on = true; + } else { + if (cam_cpas_stop(core->cpas_handle)) + CAM_ERR(CAM_CDM, "CPAS stop failed"); + } + } else { + cdm_hw->open_count++; + CAM_DBG(CAM_CDM, "CDM HW already ON count=%d", + cdm_hw->open_count); + rc = 0; + client->stream_on = true; + } + } else { + if (cdm_hw->open_count) { + cdm_hw->open_count--; + CAM_DBG(CAM_CDM, "stream OFF CDM %d", + cdm_hw->open_count); + if (!cdm_hw->open_count) { + CAM_DBG(CAM_CDM, "CDM Deinit now"); + if (core->id == CAM_CDM_VIRTUAL) { + CAM_DBG(CAM_CDM, + "Virtual CDM HW Deinit"); + rc = 0; + } else { + CAM_DBG(CAM_CDM, "CDM HW Deinit now"); + rc = cam_hw_cdm_deinit( + hw_priv, NULL, 0); + if (cam_hw_cdm_release_genirq_mem( + hw_priv)) + CAM_ERR(CAM_CDM, + "Genirq release fail"); + } + if (rc) { + CAM_ERR(CAM_CDM, + "Deinit failed in streamoff"); + } else { + client->stream_on = false; + rc = cam_cpas_stop(core->cpas_handle); + if (rc) + CAM_ERR(CAM_CDM, + "CPAS stop failed"); + } + } else { + client->stream_on = false; + rc = 0; + CAM_DBG(CAM_CDM, + "Client stream off success =%d", + cdm_hw->open_count); + } + } else { + CAM_DBG(CAM_CDM, "stream OFF CDM Invalid %d", + cdm_hw->open_count); + rc = -ENXIO; + } + } +end: + cam_cdm_put_client_refcount(client); + mutex_unlock(&cdm_hw->hw_mutex); + return rc; +} + +int cam_cdm_stream_start(void *hw_priv, + void *start_args, uint32_t size) +{ + int rc = 0; + + if (!hw_priv) + return -EINVAL; + + rc = cam_cdm_stream_ops_internal(hw_priv, start_args, true); + return rc; + +} + +int cam_cdm_stream_stop(void *hw_priv, + void *start_args, uint32_t size) +{ + int rc = 0; + + if (!hw_priv) + return -EINVAL; + + rc = cam_cdm_stream_ops_internal(hw_priv, start_args, false); + return rc; + +} + +int cam_cdm_process_cmd(void *hw_priv, + uint32_t cmd, void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_hw_soc_info *soc_data = NULL; + struct cam_cdm *core = NULL; + int rc = -EINVAL; + + if ((!hw_priv) || (!cmd_args) || + (cmd >= CAM_CDM_HW_INTF_CMD_INVALID)) + return rc; + + soc_data = &cdm_hw->soc_info; + core = (struct cam_cdm *)cdm_hw->core_info; + switch (cmd) { + case CAM_CDM_HW_INTF_CMD_SUBMIT_BL: { + struct cam_cdm_hw_intf_cmd_submit_bl *req; + int idx; + struct cam_cdm_client *client; + + if (sizeof(struct cam_cdm_hw_intf_cmd_submit_bl) != arg_size) { + CAM_ERR(CAM_CDM, "Invalid CDM cmd %d arg size=%x", cmd, + arg_size); + break; + } + req = (struct cam_cdm_hw_intf_cmd_submit_bl *)cmd_args; + if ((req->data->type < 0) || + (req->data->type > CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA)) { + CAM_ERR(CAM_CDM, "Invalid req bl cmd addr type=%d", + req->data->type); + break; + } + idx = CAM_CDM_GET_CLIENT_IDX(req->handle); + client = core->clients[idx]; + if ((!client) || (req->handle != client->handle)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", client, + req->handle); + break; + } + cam_cdm_get_client_refcount(client); + if ((req->data->flag == true) && + (!client->data.cam_cdm_callback)) { + CAM_ERR(CAM_CDM, + "CDM request cb without registering cb"); + cam_cdm_put_client_refcount(client); + break; + } + if (client->stream_on != true) { + CAM_ERR(CAM_CDM, + "Invalid CDM needs to be streamed ON first"); + cam_cdm_put_client_refcount(client); + break; + } + if (core->id == CAM_CDM_VIRTUAL) + rc = cam_virtual_cdm_submit_bl(cdm_hw, req, client); + else + rc = cam_hw_cdm_submit_bl(cdm_hw, req, client); + + cam_cdm_put_client_refcount(client); + break; + } + case CAM_CDM_HW_INTF_CMD_ACQUIRE: { + struct cam_cdm_acquire_data *data; + int idx; + struct cam_cdm_client *client; + + if (sizeof(struct cam_cdm_acquire_data) != arg_size) { + CAM_ERR(CAM_CDM, "Invalid CDM cmd %d arg size=%x", cmd, + arg_size); + break; + } + + mutex_lock(&cdm_hw->hw_mutex); + data = (struct cam_cdm_acquire_data *)cmd_args; + CAM_DBG(CAM_CDM, "Trying to acquire client=%s in hw idx=%d", + data->identifier, core->index); + idx = cam_cdm_find_free_client_slot(core); + if ((idx < 0) || (core->clients[idx])) { + mutex_unlock(&cdm_hw->hw_mutex); + CAM_ERR(CAM_CDM, + "Fail to client slots, client=%s in hw idx=%d", + data->identifier, core->index); + break; + } + core->clients[idx] = kzalloc(sizeof(struct cam_cdm_client), + GFP_KERNEL); + if (!core->clients[idx]) { + mutex_unlock(&cdm_hw->hw_mutex); + rc = -ENOMEM; + break; + } + + mutex_unlock(&cdm_hw->hw_mutex); + client = core->clients[idx]; + mutex_init(&client->lock); + data->ops = core->ops; + if (core->id == CAM_CDM_VIRTUAL) { + data->cdm_version.major = 1; + data->cdm_version.minor = 0; + data->cdm_version.incr = 0; + data->cdm_version.reserved = 0; + data->ops = cam_cdm_get_ops(0, + &data->cdm_version, true); + if (!data->ops) { + mutex_destroy(&client->lock); + mutex_lock(&cdm_hw->hw_mutex); + kfree(core->clients[idx]); + core->clients[idx] = NULL; + mutex_unlock( + &cdm_hw->hw_mutex); + rc = -EPERM; + CAM_ERR(CAM_CDM, "Invalid ops for virtual cdm"); + break; + } + } else { + data->cdm_version = core->version; + } + + cam_cdm_get_client_refcount(client); + mutex_lock(&client->lock); + memcpy(&client->data, data, + sizeof(struct cam_cdm_acquire_data)); + client->handle = CAM_CDM_CREATE_CLIENT_HANDLE( + core->index, + idx); + client->stream_on = false; + data->handle = client->handle; + CAM_DBG(CAM_CDM, "Acquired client=%s in hwidx=%d", + data->identifier, core->index); + mutex_unlock(&client->lock); + rc = 0; + break; + } + case CAM_CDM_HW_INTF_CMD_RELEASE: { + uint32_t *handle = cmd_args; + int idx; + struct cam_cdm_client *client; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CDM, + "Invalid CDM cmd %d size=%x for handle=%x", + cmd, arg_size, *handle); + return -EINVAL; + } + idx = CAM_CDM_GET_CLIENT_IDX(*handle); + mutex_lock(&cdm_hw->hw_mutex); + client = core->clients[idx]; + if ((!client) || (*handle != client->handle)) { + CAM_ERR(CAM_CDM, "Invalid client %pK hdl=%x", + client, *handle); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + cam_cdm_put_client_refcount(client); + mutex_lock(&client->lock); + if (client->refcount != 0) { + CAM_ERR(CAM_CDM, "CDM Client refcount not zero %d", + client->refcount); + rc = -EPERM; + mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); + break; + } + core->clients[idx] = NULL; + mutex_unlock(&client->lock); + mutex_destroy(&client->lock); + kfree(client); + mutex_unlock(&cdm_hw->hw_mutex); + rc = 0; + break; + } + case CAM_CDM_HW_INTF_CMD_RESET_HW: { + CAM_ERR(CAM_CDM, "CDM HW reset not supported for handle =%x", + *((uint32_t *)cmd_args)); + break; + } + default: + CAM_ERR(CAM_CDM, "CDM HW intf command not valid =%d", cmd); + break; + } + return rc; +} diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_core_common.h b/techpack/camera/drivers/cam_cdm/cam_cdm_core_common.h new file mode 100644 index 0000000000000000000000000000000000000000..8dcbe8ed19711be30b66aff4ae6171a538d2a85c --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_core_common.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_CORE_COMMON_H_ +#define _CAM_CDM_CORE_COMMON_H_ + +#include "cam_mem_mgr.h" + +#define CAM_CDM170_VERSION 0x10000000 +#define CAM_CDM175_VERSION 0x10010000 +#define CAM_CDM480_VERSION 0x10020000 + +extern struct cam_cdm_utils_ops CDM170_ops; + +int cam_hw_cdm_init(void *hw_priv, void *init_hw_args, uint32_t arg_size); +int cam_hw_cdm_deinit(void *hw_priv, void *init_hw_args, uint32_t arg_size); +int cam_hw_cdm_alloc_genirq_mem(void *hw_priv); +int cam_hw_cdm_release_genirq_mem(void *hw_priv); +int cam_cdm_get_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size); +int cam_cdm_stream_ops_internal(void *hw_priv, void *start_args, + bool operation); +int cam_cdm_stream_start(void *hw_priv, void *start_args, uint32_t size); +int cam_cdm_stream_stop(void *hw_priv, void *start_args, uint32_t size); +int cam_cdm_process_cmd(void *hw_priv, uint32_t cmd, void *cmd_args, + uint32_t arg_size); +bool cam_cdm_set_cam_hw_version( + uint32_t ver, struct cam_hw_version *cam_version); +bool cam_cdm_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data); +struct cam_cdm_utils_ops *cam_cdm_get_ops( + uint32_t ver, struct cam_hw_version *cam_version, bool by_cam_version); +int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client); +int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client); +struct cam_cdm_bl_cb_request_entry *cam_cdm_find_request_by_bl_tag( + uint32_t tag, struct list_head *bl_list); +void cam_cdm_notify_clients(struct cam_hw_info *cdm_hw, + enum cam_cdm_cb_status status, void *data); + +#endif /* _CAM_CDM_CORE_COMMON_H_ */ diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_hw_core.c b/techpack/camera/drivers/cam_cdm/cam_cdm_hw_core.c new file mode 100644 index 0000000000000000000000000000000000000000..0663b8d0f30d03449d940e0cf01672019b292202 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_hw_core.c @@ -0,0 +1,1147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include <media/cam_req_mgr.h> +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_core_common.h" +#include "cam_cdm_soc.h" +#include "cam_io_util.h" +#include "cam_hw_cdm170_reg.h" + +#define CAM_HW_CDM_CPAS_0_NAME "qcom,cam170-cpas-cdm0" +#define CAM_HW_CDM_IPE_0_NAME "qcom,cam170-ipe0-cdm" +#define CAM_HW_CDM_IPE_1_NAME "qcom,cam170-ipe1-cdm" +#define CAM_HW_CDM_BPS_NAME "qcom,cam170-bps-cdm" + +#define CAM_CDM_BL_FIFO_WAIT_TIMEOUT 2000 + +static void cam_hw_cdm_work(struct work_struct *work); + +/* DT match table entry for all CDM variants*/ +static const struct of_device_id msm_cam_hw_cdm_dt_match[] = { + { + .compatible = CAM_HW_CDM_CPAS_0_NAME, + .data = &cam170_cpas_cdm_offset_table, + }, + {} +}; + +static enum cam_cdm_id cam_hw_cdm_get_id_by_name(char *name) +{ + if (!strcmp(CAM_HW_CDM_CPAS_0_NAME, name)) + return CAM_CDM_CPAS_0; + + return CAM_CDM_MAX; +} + +int cam_hw_cdm_bl_fifo_pending_bl_rb(struct cam_hw_info *cdm_hw, + uint32_t *pending_bl) +{ + int rc = 0; + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB, + pending_bl)) { + CAM_ERR(CAM_CDM, "Failed to read CDM pending BL's"); + rc = -EIO; + } + + return rc; +} + +static int cam_hw_cdm_enable_bl_done_irq(struct cam_hw_info *cdm_hw, + bool enable) +{ + int rc = -EIO; + uint32_t irq_mask = 0; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_MASK, + &irq_mask)) { + CAM_ERR(CAM_CDM, "Failed to read CDM IRQ mask"); + return rc; + } + + if (enable == true) { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, + (irq_mask | 0x4))) { + CAM_ERR(CAM_CDM, "Write failed to enable BL done irq"); + } else { + atomic_inc(&core->bl_done); + rc = 0; + CAM_DBG(CAM_CDM, "BL done irq enabled =%d", + atomic_read(&core->bl_done)); + } + } else { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, + (irq_mask & 0x70003))) { + CAM_ERR(CAM_CDM, "Write failed to disable BL done irq"); + } else { + atomic_dec(&core->bl_done); + rc = 0; + CAM_DBG(CAM_CDM, "BL done irq disable =%d", + atomic_read(&core->bl_done)); + } + } + return rc; +} + +static int cam_hw_cdm_enable_core(struct cam_hw_info *cdm_hw, bool enable) +{ + int rc = 0; + + if (enable == true) { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x01)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core enable"); + rc = -EIO; + } + } else { + if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_CORE_EN, 0x02)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core disable"); + rc = -EIO; + } + } + return rc; +} + +int cam_hw_cdm_enable_core_dbg(struct cam_hw_info *cdm_hw) +{ + int rc = 0; + + if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0x10100)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); + rc = -EIO; + } + + return rc; +} + +int cam_hw_cdm_disable_core_dbg(struct cam_hw_info *cdm_hw) +{ + int rc = 0; + + if (cam_cdm_write_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, 0)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW core debug"); + rc = -EIO; + } + + return rc; +} + +void cam_hw_cdm_dump_scratch_registors(struct cam_hw_info *cdm_hw) +{ + uint32_t dump_reg = 0; + + cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); + CAM_ERR(CAM_CDM, "dump core en=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_0_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch0=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_1_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch1=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_2_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch2=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_3_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch3=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_4_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch4=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_5_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch5=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_6_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch6=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_SCRATCH_7_REG, &dump_reg); + CAM_ERR(CAM_CDM, "dump scratch7=%x", dump_reg); + +} + +void cam_hw_cdm_dump_core_debug_registers( + struct cam_hw_info *cdm_hw) +{ + uint32_t dump_reg, core_dbg, loop_cnt; + + mutex_lock(&cdm_hw->hw_mutex); + cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_EN, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW core status=%x", dump_reg); + /* First pause CDM, If it fails still proceed to dump debug info */ + cam_hw_cdm_enable_core(cdm_hw, false); + cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current pending BL=%x", dump_reg); + loop_cnt = dump_reg; + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_DEBUG_STATUS, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW Debug status reg=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CORE_DBUG, &core_dbg); + if (core_dbg & 0x100) { + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_LAST_AHB_ADDR, &dump_reg); + CAM_ERR(CAM_CDM, "AHB dump reglastaddr=%x", dump_reg); + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_LAST_AHB_DATA, &dump_reg); + CAM_ERR(CAM_CDM, "AHB dump reglastdata=%x", dump_reg); + } else { + CAM_ERR(CAM_CDM, "CDM HW AHB dump not enable"); + } + + if (core_dbg & 0x10000) { + int i; + + CAM_ERR(CAM_CDM, "CDM HW BL FIFO dump with loop count=%d", + loop_cnt); + for (i = 0 ; i < loop_cnt ; i++) { + cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_RB, i); + cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_BASE_RB, + &dump_reg); + CAM_ERR(CAM_CDM, "BL(%d) base addr =%x", i, dump_reg); + cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_LEN_RB, + &dump_reg); + CAM_ERR(CAM_CDM, "BL(%d) len=%d tag=%d", i, + (dump_reg & 0xFFFFF), (dump_reg & 0xFF000000)); + } + } else { + CAM_ERR(CAM_CDM, "CDM HW BL FIFO readback not enable"); + } + + CAM_ERR(CAM_CDM, "CDM HW default dump"); + cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_CORE_CFG, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW core cfg=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_STATUS, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW irq status=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_SET, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW irq set reg=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_BL_BASE, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current BL base=%x", dump_reg); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_BL_LEN, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current BL len=%d tag=%d", + (dump_reg & 0xFFFFF), (dump_reg & 0xFF000000)); + + cam_cdm_read_hw_reg(cdm_hw, CDM_DBG_CURRENT_USED_AHB_BASE, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current AHB base=%x", dump_reg); + + cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &dump_reg); + CAM_ERR(CAM_CDM, "CDM HW current pending BL=%x", dump_reg); + + /* Enable CDM back */ + cam_hw_cdm_enable_core(cdm_hw, true); + mutex_unlock(&cdm_hw->hw_mutex); + +} + +int cam_hw_cdm_wait_for_bl_fifo(struct cam_hw_info *cdm_hw, + uint32_t bl_count) +{ + uint32_t pending_bl = 0; + int32_t available_bl_slots = 0; + int rc = -EIO; + long time_left; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + do { + if (cam_cdm_read_hw_reg(cdm_hw, CDM_BL_FIFO_PENDING_REQ_RB, + &pending_bl)) { + CAM_ERR(CAM_CDM, "Failed to read CDM pending BL's"); + rc = -EIO; + break; + } + available_bl_slots = CAM_CDM_HWFIFO_SIZE - pending_bl; + if (available_bl_slots < 0) { + CAM_ERR(CAM_CDM, "Invalid available slots %d:%d:%d", + available_bl_slots, CAM_CDM_HWFIFO_SIZE, + pending_bl); + break; + } + if (bl_count < (available_bl_slots - 1)) { + CAM_DBG(CAM_CDM, + "BL slot available_cnt=%d requested=%d", + (available_bl_slots - 1), bl_count); + rc = bl_count; + break; + } else if (0 == (available_bl_slots - 1)) { + rc = cam_hw_cdm_enable_bl_done_irq(cdm_hw, true); + if (rc) { + CAM_ERR(CAM_CDM, "Enable BL done irq failed"); + break; + } + time_left = wait_for_completion_timeout( + &core->bl_complete, msecs_to_jiffies( + CAM_CDM_BL_FIFO_WAIT_TIMEOUT)); + if (time_left <= 0) { + CAM_ERR(CAM_CDM, + "CDM HW BL Wait timed out failed"); + if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, + false)) + CAM_ERR(CAM_CDM, + "Disable BL done irq failed"); + rc = -EIO; + break; + } + if (cam_hw_cdm_enable_bl_done_irq(cdm_hw, false)) + CAM_ERR(CAM_CDM, "Disable BL done irq failed"); + rc = 0; + CAM_DBG(CAM_CDM, "CDM HW is ready for data"); + } else { + rc = (bl_count - (available_bl_slots - 1)); + break; + } + } while (1); + + return rc; +} + +bool cam_hw_cdm_bl_write(struct cam_hw_info *cdm_hw, uint32_t src, + uint32_t len, uint32_t tag) +{ + if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_BASE_REG, src)) { + CAM_ERR(CAM_CDM, "Failed to write CDM base to BL base"); + return true; + } + if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_LEN_REG, + ((len & 0xFFFFF) | ((tag & 0xFF) << 20)))) { + CAM_ERR(CAM_CDM, "Failed to write CDM BL len"); + return true; + } + return false; +} + +bool cam_hw_cdm_commit_bl_write(struct cam_hw_info *cdm_hw) +{ + if (cam_cdm_write_hw_reg(cdm_hw, CDM_BL_FIFO_STORE_REG, 1)) { + CAM_ERR(CAM_CDM, "Failed to write CDM commit BL"); + return true; + } + return false; +} + +int cam_hw_cdm_submit_gen_irq(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req) +{ + struct cam_cdm_bl_cb_request_entry *node; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uint32_t len; + int rc; + + if (core->bl_tag > 63) { + CAM_ERR(CAM_CDM, "bl_tag invalid =%d", core->bl_tag); + rc = -EINVAL; + goto end; + } + CAM_DBG(CAM_CDM, "CDM write BL last cmd tag=%x total=%d cookie=%d", + core->bl_tag, req->data->cmd_arrary_count, req->data->cookie); + node = kzalloc(sizeof(struct cam_cdm_bl_cb_request_entry), + GFP_KERNEL); + if (!node) { + rc = -ENOMEM; + goto end; + } + node->request_type = CAM_HW_CDM_BL_CB_CLIENT; + node->client_hdl = req->handle; + node->cookie = req->data->cookie; + node->bl_tag = core->bl_tag; + node->userdata = req->data->userdata; + list_add_tail(&node->entry, &core->bl_request_list); + len = core->ops->cdm_required_size_genirq() * core->bl_tag; + core->ops->cdm_write_genirq(((uint32_t *)core->gen_irq.kmdvaddr + len), + core->bl_tag); + rc = cam_hw_cdm_bl_write(cdm_hw, (core->gen_irq.vaddr + (4*len)), + ((4 * core->ops->cdm_required_size_genirq()) - 1), + core->bl_tag); + if (rc) { + CAM_ERR(CAM_CDM, "CDM hw bl write failed for gen irq bltag=%d", + core->bl_tag); + list_del_init(&node->entry); + kfree(node); + rc = -EIO; + goto end; + } + + if (cam_hw_cdm_commit_bl_write(cdm_hw)) { + CAM_ERR(CAM_CDM, "Cannot commit the genirq BL with tag tag=%d", + core->bl_tag); + list_del_init(&node->entry); + kfree(node); + rc = -EIO; + } + +end: + return rc; +} + +int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client) +{ + int i, rc; + struct cam_cdm_bl_request *cdm_cmd = req->data; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + uint32_t pending_bl = 0; + int write_count = 0; + + if (req->data->cmd_arrary_count > CAM_CDM_HWFIFO_SIZE) { + pr_info("requested BL more than max size, cnt=%d max=%d", + req->data->cmd_arrary_count, CAM_CDM_HWFIFO_SIZE); + } + + if (atomic_read(&core->error)) + return -EIO; + + mutex_lock(&cdm_hw->hw_mutex); + mutex_lock(&client->lock); + rc = cam_hw_cdm_bl_fifo_pending_bl_rb(cdm_hw, &pending_bl); + if (rc) { + CAM_ERR(CAM_CDM, "Cannot read the current BL depth"); + mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); + return rc; + } + + for (i = 0; i < req->data->cmd_arrary_count ; i++) { + dma_addr_t hw_vaddr_ptr = 0; + size_t len = 0; + + if ((!cdm_cmd->cmd[i].len) && + (cdm_cmd->cmd[i].len > 0x100000)) { + CAM_ERR(CAM_CDM, + "cmd len(%d) is invalid cnt=%d total cnt=%d", + cdm_cmd->cmd[i].len, i, + req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + if (atomic_read(&core->error)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "In error state cnt=%d total cnt=%d\n", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + if (write_count == 0) { + write_count = cam_hw_cdm_wait_for_bl_fifo(cdm_hw, + (req->data->cmd_arrary_count - i)); + if (write_count < 0) { + CAM_ERR(CAM_CDM, + "wait for bl fifo failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + } else { + write_count--; + } + + if (req->data->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) { + rc = cam_mem_get_io_buf( + cdm_cmd->cmd[i].bl_addr.mem_handle, + core->iommu_hdl.non_secure, &hw_vaddr_ptr, + &len); + } else if (req->data->type == CAM_CDM_BL_CMD_TYPE_HW_IOVA) { + if (!cdm_cmd->cmd[i].bl_addr.hw_iova) { + CAM_ERR(CAM_CDM, + "Hw bl hw_iova is invalid %d:%d", + i, req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + rc = 0; + hw_vaddr_ptr = + (uint64_t)cdm_cmd->cmd[i].bl_addr.hw_iova; + len = cdm_cmd->cmd[i].len + cdm_cmd->cmd[i].offset; + } else { + CAM_ERR(CAM_CDM, + "Only mem hdl/hw va type is supported %d", + req->data->type); + rc = -EINVAL; + break; + } + + if ((!rc) && (hw_vaddr_ptr) && (len) && + (len >= cdm_cmd->cmd[i].offset)) { + + if ((len - cdm_cmd->cmd[i].offset) < + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, + "Not enough buffer cmd offset: %u cmd length: %u", + cdm_cmd->cmd[i].offset, + cdm_cmd->cmd[i].len); + rc = -EINVAL; + break; + } + + CAM_DBG(CAM_CDM, "Got the HW VA"); + if (core->bl_tag >= + (CAM_CDM_HWFIFO_SIZE - 1)) + core->bl_tag = 0; + rc = cam_hw_cdm_bl_write(cdm_hw, + ((uint32_t)hw_vaddr_ptr + + cdm_cmd->cmd[i].offset), + (cdm_cmd->cmd[i].len - 1), core->bl_tag); + if (rc) { + CAM_ERR(CAM_CDM, "Hw bl write failed %d:%d", + i, req->data->cmd_arrary_count); + rc = -EIO; + break; + } + } else { + CAM_ERR(CAM_CDM, + "Sanity check failed for hdl=%x len=%zu:%d", + cdm_cmd->cmd[i].bl_addr.mem_handle, len, + cdm_cmd->cmd[i].offset); + CAM_ERR(CAM_CDM, "Sanity check failed for %d:%d", + i, req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + + if (!rc) { + CAM_DBG(CAM_CDM, + "write BL success for cnt=%d with tag=%d total_cnt=%d", + i, core->bl_tag, req->data->cmd_arrary_count); + + CAM_DBG(CAM_CDM, "Now commit the BL"); + if (cam_hw_cdm_commit_bl_write(cdm_hw)) { + CAM_ERR(CAM_CDM, + "Cannot commit the BL %d tag=%d", + i, core->bl_tag); + rc = -EIO; + break; + } + CAM_DBG(CAM_CDM, "BL commit success BL %d tag=%d", i, + core->bl_tag); + core->bl_tag++; + if ((req->data->flag == true) && + (i == (req->data->cmd_arrary_count - + 1))) { + rc = cam_hw_cdm_submit_gen_irq( + cdm_hw, req); + if (rc == 0) + core->bl_tag++; + } + } + } + mutex_unlock(&client->lock); + mutex_unlock(&cdm_hw->hw_mutex); + return rc; + +} + +static void cam_hw_cdm_work(struct work_struct *work) +{ + struct cam_cdm_work_payload *payload; + struct cam_hw_info *cdm_hw; + struct cam_cdm *core; + + payload = container_of(work, struct cam_cdm_work_payload, work); + if (payload) { + cdm_hw = payload->hw; + core = (struct cam_cdm *)cdm_hw->core_info; + + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { + struct cam_cdm_bl_cb_request_entry *node, *tnode; + + CAM_DBG(CAM_CDM, "inline IRQ data=0x%x", + payload->irq_data); + mutex_lock(&cdm_hw->hw_mutex); + list_for_each_entry_safe(node, tnode, + &core->bl_request_list, entry) { + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_BL_SUCCESS, + (void *)node); + } else if (node->request_type == + CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_ERR(CAM_CDM, + "Invalid node=%pK %d", node, + node->request_type); + } + list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { + kfree(node); + break; + } + kfree(node); + } + mutex_unlock(&cdm_hw->hw_mutex); + } + + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_RST_DONE_MASK) { + CAM_DBG(CAM_CDM, "CDM HW reset done IRQ"); + complete(&core->reset_complete); + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_BL_DONE_MASK) { + if (atomic_read(&core->bl_done)) { + CAM_DBG(CAM_CDM, "CDM HW BL done IRQ"); + complete(&core->bl_complete); + } + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Invalid command IRQ, Need HW reset\n"); + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "AHB Error IRQ\n"); + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + atomic_dec(&core->error); + } + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Overflow Error IRQ\n"); + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + atomic_dec(&core->error); + } + kfree(payload); + } else { + CAM_ERR(CAM_CDM, "NULL payload"); + } + +} + +static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token, + uint32_t buf_info) +{ + struct cam_hw_info *cdm_hw = NULL; + struct cam_cdm *core = NULL; + + if (token) { + cdm_hw = (struct cam_hw_info *)token; + core = (struct cam_cdm *)cdm_hw->core_info; + atomic_inc(&core->error); + cam_hw_cdm_dump_core_debug_registers(cdm_hw); + CAM_ERR_RATE_LIMIT(CAM_CDM, "Page fault iova addr %pK\n", + (void *)iova); + cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_PAGEFAULT, + (void *)iova); + atomic_dec(&core->error); + } else { + CAM_ERR(CAM_CDM, "Invalid token"); + } + +} + +irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) +{ + struct cam_hw_info *cdm_hw = data; + struct cam_cdm *cdm_core = cdm_hw->core_info; + struct cam_cdm_work_payload *payload; + bool work_status; + + CAM_DBG(CAM_CDM, "Got irq"); + payload = kzalloc(sizeof(struct cam_cdm_work_payload), GFP_ATOMIC); + if (payload) { + if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_STATUS, + &payload->irq_status)) { + CAM_ERR(CAM_CDM, "Failed to read CDM HW IRQ status"); + } + if (!payload->irq_status) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid irq received\n"); + kfree(payload); + return IRQ_HANDLED; + } + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR, + payload->irq_status)) + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ Clear"); + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_CLEAR_CMD, 0x01)) + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ cmd"); + + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { + if (cam_cdm_read_hw_reg(cdm_hw, CDM_IRQ_USR_DATA, + &payload->irq_data)) { + CAM_ERR(CAM_CDM, + "Failed to read CDM HW IRQ data"); + } + } + CAM_DBG(CAM_CDM, "Got payload=%d", payload->irq_status); + payload->hw = cdm_hw; + INIT_WORK((struct work_struct *)&payload->work, + cam_hw_cdm_work); + work_status = queue_work(cdm_core->work_queue, &payload->work); + if (work_status == false) { + CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", + payload->irq_status); + kfree(payload); + } + } + + return IRQ_HANDLED; +} + +int cam_hw_cdm_alloc_genirq_mem(void *hw_priv) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_mem_mgr_request_desc genirq_alloc_cmd; + struct cam_mem_mgr_memory_desc genirq_alloc_out; + struct cam_cdm *cdm_core = NULL; + int rc = -EINVAL; + + if (!hw_priv) + return rc; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + genirq_alloc_cmd.align = 0; + genirq_alloc_cmd.size = (8 * CAM_CDM_HWFIFO_SIZE); + genirq_alloc_cmd.smmu_hdl = cdm_core->iommu_hdl.non_secure; + genirq_alloc_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE; + rc = cam_mem_mgr_request_mem(&genirq_alloc_cmd, + &genirq_alloc_out); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to get genirq cmd space rc=%d", rc); + goto end; + } + cdm_core->gen_irq.handle = genirq_alloc_out.mem_handle; + cdm_core->gen_irq.vaddr = (genirq_alloc_out.iova & 0xFFFFFFFF); + cdm_core->gen_irq.kmdvaddr = genirq_alloc_out.kva; + cdm_core->gen_irq.size = genirq_alloc_out.len; + +end: + return rc; +} + +int cam_hw_cdm_release_genirq_mem(void *hw_priv) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_cdm *cdm_core = NULL; + struct cam_mem_mgr_memory_desc genirq_release_cmd; + int rc = -EINVAL; + + if (!hw_priv) + return rc; + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + genirq_release_cmd.mem_handle = cdm_core->gen_irq.handle; + rc = cam_mem_mgr_release_mem(&genirq_release_cmd); + if (rc) + CAM_ERR(CAM_CDM, "Failed to put genirq cmd space for hw"); + + return rc; +} + +int cam_hw_cdm_init(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_cdm *cdm_core = NULL; + int rc; + long time_left; + + if (!hw_priv) + return -EINVAL; + + soc_info = &cdm_hw->soc_info; + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) { + CAM_ERR(CAM_CDM, "Enable platform failed"); + goto end; + } + + CAM_DBG(CAM_CDM, "Enable soc done"); + +/* Before triggering the reset to HW, clear the reset complete */ + atomic_set(&cdm_core->error, 0); + atomic_set(&cdm_core->bl_done, 0); + reinit_completion(&cdm_core->reset_complete); + reinit_completion(&cdm_core->bl_complete); + + if (cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW IRQ mask"); + goto disable_return; + } + if (cam_cdm_write_hw_reg(cdm_hw, CDM_CFG_RST_CMD, 0x9)) { + CAM_ERR(CAM_CDM, "Failed to Write CDM HW reset"); + goto disable_return; + } + + CAM_DBG(CAM_CDM, "Waiting for CDM HW resetdone"); + time_left = wait_for_completion_timeout(&cdm_core->reset_complete, + msecs_to_jiffies(CAM_CDM_HW_RESET_TIMEOUT)); + + if (time_left <= 0) { + CAM_ERR(CAM_CDM, "CDM HW reset Wait failed rc=%d", rc); + goto disable_return; + } else { + CAM_DBG(CAM_CDM, "CDM Init success"); + cdm_hw->hw_state = CAM_HW_STATE_POWER_UP; + cam_cdm_write_hw_reg(cdm_hw, CDM_IRQ_MASK, 0x70003); + rc = 0; + goto end; + } + +disable_return: + rc = -EIO; + cam_soc_util_disable_platform_resource(soc_info, true, true); +end: + return rc; +} + +int cam_hw_cdm_deinit(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *cdm_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_cdm *cdm_core = NULL; + int rc = 0; + + if (!hw_priv) + return -EINVAL; + + soc_info = &cdm_hw->soc_info; + cdm_core = cdm_hw->core_info; + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CDM, "disable platform failed"); + } else { + CAM_DBG(CAM_CDM, "CDM Deinit success"); + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + } + + return rc; +} + +int cam_hw_cdm_probe(struct platform_device *pdev) +{ + int rc; + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + struct cam_cdm_private_dt_data *soc_private = NULL; + struct cam_cpas_register_params cpas_parms; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + cdm_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!cdm_hw_intf) + return -ENOMEM; + + cdm_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!cdm_hw) { + kfree(cdm_hw_intf); + return -ENOMEM; + } + + cdm_hw->core_info = kzalloc(sizeof(struct cam_cdm), GFP_KERNEL); + if (!cdm_hw->core_info) { + kfree(cdm_hw); + kfree(cdm_hw_intf); + return -ENOMEM; + } + + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + cdm_hw->soc_info.pdev = pdev; + cdm_hw->soc_info.dev = &pdev->dev; + cdm_hw->soc_info.dev_name = pdev->name; + cdm_hw_intf->hw_type = CAM_HW_CDM; + cdm_hw->open_count = 0; + mutex_init(&cdm_hw->hw_mutex); + spin_lock_init(&cdm_hw->hw_lock); + init_completion(&cdm_hw->hw_complete); + + rc = cam_hw_cdm_soc_get_dt_properties(cdm_hw, msm_cam_hw_cdm_dt_match); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to get dt properties"); + goto release_mem; + } + cdm_hw_intf->hw_idx = cdm_hw->soc_info.index; + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + soc_private = (struct cam_cdm_private_dt_data *) + cdm_hw->soc_info.soc_private; + if (soc_private->dt_cdm_shared == true) + cdm_core->flags = CAM_CDM_FLAG_SHARED_CDM; + else + cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM; + + cdm_core->bl_tag = 0; + cdm_core->id = cam_hw_cdm_get_id_by_name(cdm_core->name); + if (cdm_core->id >= CAM_CDM_MAX) { + CAM_ERR(CAM_CDM, "Failed to get CDM HW name for %s", + cdm_core->name); + goto release_private_mem; + } + INIT_LIST_HEAD(&cdm_core->bl_request_list); + init_completion(&cdm_core->reset_complete); + init_completion(&cdm_core->bl_complete); + cdm_hw_intf->hw_priv = cdm_hw; + cdm_hw_intf->hw_ops.get_hw_caps = cam_cdm_get_caps; + cdm_hw_intf->hw_ops.init = cam_hw_cdm_init; + cdm_hw_intf->hw_ops.deinit = cam_hw_cdm_deinit; + cdm_hw_intf->hw_ops.start = cam_cdm_stream_start; + cdm_hw_intf->hw_ops.stop = cam_cdm_stream_stop; + cdm_hw_intf->hw_ops.read = NULL; + cdm_hw_intf->hw_ops.write = NULL; + cdm_hw_intf->hw_ops.process_cmd = cam_cdm_process_cmd; + mutex_lock(&cdm_hw->hw_mutex); + + CAM_DBG(CAM_CDM, "type %d index %d", cdm_hw_intf->hw_type, + cdm_hw_intf->hw_idx); + + platform_set_drvdata(pdev, cdm_hw_intf); + + rc = cam_smmu_get_handle("cpas-cdm0", &cdm_core->iommu_hdl.non_secure); + if (rc < 0) { + CAM_ERR(CAM_CDM, "cpas-cdm get iommu handle failed"); + goto unlock_release_mem; + } + cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + cam_hw_cdm_iommu_fault_handler, cdm_hw); + + cdm_core->iommu_hdl.secure = -1; + + cdm_core->work_queue = alloc_workqueue(cdm_core->name, + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, + CAM_CDM_INFLIGHT_WORKS); + + rc = cam_soc_util_request_platform_resource(&cdm_hw->soc_info, + cam_hw_cdm_irq, cdm_hw); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to request platform resource"); + goto destroy_non_secure_hdl; + } + + cpas_parms.cam_cpas_client_cb = cam_cdm_cpas_cb; + cpas_parms.cell_index = cdm_hw->soc_info.index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = cdm_hw_intf; + strlcpy(cpas_parms.identifier, "cpas-cdm", CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CDM, "Virtual CDM CPAS registration failed"); + goto release_platform_resource; + } + CAM_DBG(CAM_CDM, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + cdm_core->cpas_handle = cpas_parms.client_handle; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(cdm_core->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS start failed"); + goto cpas_unregister; + } + + rc = cam_hw_cdm_init(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to Init CDM HW"); + goto cpas_stop; + } + cdm_hw->open_count++; + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_HW_VERSION, + &cdm_core->hw_version)) { + CAM_ERR(CAM_CDM, "Failed to read CDM HW Version"); + goto deinit; + } + + if (cam_cdm_read_hw_reg(cdm_hw, CDM_CFG_TITAN_VERSION, + &cdm_core->hw_family_version)) { + CAM_ERR(CAM_CDM, "Failed to read CDM family Version"); + goto deinit; + } + + CAM_DBG(CAM_CDM, "CDM Hw version read success family =%x hw =%x", + cdm_core->hw_family_version, cdm_core->hw_version); + cdm_core->ops = cam_cdm_get_ops(cdm_core->hw_version, NULL, + false); + if (!cdm_core->ops) { + CAM_ERR(CAM_CDM, "Failed to util ops for hw"); + goto deinit; + } + + if (!cam_cdm_set_cam_hw_version(cdm_core->hw_version, + &cdm_core->version)) { + CAM_ERR(CAM_CDM, "Failed to set cam he version for hw"); + goto deinit; + } + + rc = cam_hw_cdm_deinit(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to Deinit CDM HW"); + cdm_hw->open_count--; + goto cpas_stop; + } + + rc = cam_cpas_stop(cdm_core->cpas_handle); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS stop failed"); + cdm_hw->open_count--; + goto cpas_unregister; + } + + rc = cam_cdm_intf_register_hw_cdm(cdm_hw_intf, + soc_private, CAM_HW_CDM, &cdm_core->index); + if (rc) { + CAM_ERR(CAM_CDM, "HW CDM Interface registration failed"); + cdm_hw->open_count--; + goto cpas_unregister; + } + cdm_hw->open_count--; + mutex_unlock(&cdm_hw->hw_mutex); + + CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); + + return rc; + +deinit: + if (cam_hw_cdm_deinit(cdm_hw, NULL, 0)) + CAM_ERR(CAM_CDM, "Deinit failed for hw"); + cdm_hw->open_count--; +cpas_stop: + if (cam_cpas_stop(cdm_core->cpas_handle)) + CAM_ERR(CAM_CDM, "CPAS stop failed"); +cpas_unregister: + if (cam_cpas_unregister_client(cdm_core->cpas_handle)) + CAM_ERR(CAM_CDM, "CPAS unregister failed"); +release_platform_resource: + if (cam_soc_util_release_platform_resource(&cdm_hw->soc_info)) + CAM_ERR(CAM_CDM, "Release platform resource failed"); + + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); +destroy_non_secure_hdl: + cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + NULL, cdm_hw); + if (cam_smmu_destroy_handle(cdm_core->iommu_hdl.non_secure)) + CAM_ERR(CAM_CDM, "Release iommu secure hdl failed"); +unlock_release_mem: + mutex_unlock(&cdm_hw->hw_mutex); +release_private_mem: + kfree(cdm_hw->soc_info.soc_private); +release_mem: + mutex_destroy(&cdm_hw->hw_mutex); + kfree(cdm_hw_intf); + kfree(cdm_hw->core_info); + kfree(cdm_hw); + return rc; +} + +int cam_hw_cdm_remove(struct platform_device *pdev) +{ + int rc = -EBUSY; + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + + cdm_hw_intf = platform_get_drvdata(pdev); + if (!cdm_hw_intf) { + CAM_ERR(CAM_CDM, "Failed to get dev private data"); + return rc; + } + + cdm_hw = cdm_hw_intf->hw_priv; + if (!cdm_hw) { + CAM_ERR(CAM_CDM, + "Failed to get hw private data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + cdm_core = cdm_hw->core_info; + if (!cdm_core) { + CAM_ERR(CAM_CDM, + "Failed to get hw core data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + if (cdm_hw->open_count != 0) { + CAM_ERR(CAM_CDM, "Hw open count invalid type=%d idx=%d cnt=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx, + cdm_hw->open_count); + return rc; + } + + rc = cam_hw_cdm_deinit(cdm_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_CDM, "Deinit failed for hw"); + return rc; + } + + rc = cam_cpas_unregister_client(cdm_core->cpas_handle); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS unregister failed"); + return rc; + } + + if (cam_soc_util_release_platform_resource(&cdm_hw->soc_info)) + CAM_ERR(CAM_CDM, "Release platform resource failed"); + + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); + + if (cam_smmu_destroy_handle(cdm_core->iommu_hdl.non_secure)) + CAM_ERR(CAM_CDM, "Release iommu secure hdl failed"); + cam_smmu_unset_client_page_fault_handler( + cdm_core->iommu_hdl.non_secure, cdm_hw); + + mutex_destroy(&cdm_hw->hw_mutex); + kfree(cdm_hw->soc_info.soc_private); + kfree(cdm_hw_intf); + kfree(cdm_hw->core_info); + kfree(cdm_hw); + + return 0; +} + +static struct platform_driver cam_hw_cdm_driver = { + .probe = cam_hw_cdm_probe, + .remove = cam_hw_cdm_remove, + .driver = { + .name = "msm_cam_cdm", + .owner = THIS_MODULE, + .of_match_table = msm_cam_hw_cdm_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_hw_cdm_init_module(void) +{ + return platform_driver_register(&cam_hw_cdm_driver); +} + +static void __exit cam_hw_cdm_exit_module(void) +{ + platform_driver_unregister(&cam_hw_cdm_driver); +} + +module_init(cam_hw_cdm_init_module); +module_exit(cam_hw_cdm_exit_module); +MODULE_DESCRIPTION("MSM Camera HW CDM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_intf.c b/techpack/camera/drivers/cam_cdm/cam_cdm_intf.c new file mode 100644 index 0000000000000000000000000000000000000000..94e2f36d054443b951bd646c7bf12ce7d5bfc4f4 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_intf.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_virtual.h" +#include "cam_soc_util.h" +#include "cam_cdm_soc.h" + +static struct cam_cdm_intf_mgr cdm_mgr; +static DEFINE_MUTEX(cam_cdm_mgr_lock); + +static const struct of_device_id msm_cam_cdm_intf_dt_match[] = { + { .compatible = "qcom,cam-cdm-intf", }, + {} +}; + +static int get_cdm_mgr_refcount(void) +{ + int rc = 0; + + mutex_lock(&cam_cdm_mgr_lock); + if (cdm_mgr.probe_done == false) { + CAM_ERR(CAM_CDM, "CDM intf mgr not probed yet"); + rc = -EPERM; + } else { + CAM_DBG(CAM_CDM, "CDM intf mgr get refcount=%d", + cdm_mgr.refcount); + cdm_mgr.refcount++; + } + mutex_unlock(&cam_cdm_mgr_lock); + return rc; +} + +static void put_cdm_mgr_refcount(void) +{ + mutex_lock(&cam_cdm_mgr_lock); + if (cdm_mgr.probe_done == false) { + CAM_ERR(CAM_CDM, "CDM intf mgr not probed yet"); + } else { + CAM_DBG(CAM_CDM, "CDM intf mgr put refcount=%d", + cdm_mgr.refcount); + if (cdm_mgr.refcount > 0) { + cdm_mgr.refcount--; + } else { + CAM_ERR(CAM_CDM, "Refcount put when zero"); + WARN_ON(1); + } + } + mutex_unlock(&cam_cdm_mgr_lock); +} + +static int get_cdm_iommu_handle(struct cam_iommu_handle *cdm_handles, + uint32_t hw_idx) +{ + int rc = -EPERM; + struct cam_hw_intf *hw = cdm_mgr.nodes[hw_idx].device; + + if (hw->hw_ops.get_hw_caps) { + rc = hw->hw_ops.get_hw_caps(hw->hw_priv, cdm_handles, + sizeof(struct cam_iommu_handle)); + } + + return rc; +} + +static int get_cdm_index_by_id(char *identifier, + uint32_t cell_index, uint32_t *hw_index) +{ + int rc = -EPERM, i, j; + char client_name[128]; + + CAM_DBG(CAM_CDM, "Looking for HW id of =%s and index=%d", + identifier, cell_index); + snprintf(client_name, sizeof(client_name), "%s", identifier); + CAM_DBG(CAM_CDM, "Looking for HW id of %s count:%d", client_name, + cdm_mgr.cdm_count); + mutex_lock(&cam_cdm_mgr_lock); + for (i = 0; i < cdm_mgr.cdm_count; i++) { + mutex_lock(&cdm_mgr.nodes[i].lock); + CAM_DBG(CAM_CDM, "dt_num_supported_clients=%d", + cdm_mgr.nodes[i].data->dt_num_supported_clients); + + for (j = 0; j < + cdm_mgr.nodes[i].data->dt_num_supported_clients; j++) { + CAM_DBG(CAM_CDM, "client name:%s", + cdm_mgr.nodes[i].data->dt_cdm_client_name[j]); + if (!strcmp( + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + client_name)) { + rc = 0; + *hw_index = i; + break; + } + } + mutex_unlock(&cdm_mgr.nodes[i].lock); + if (rc == 0) + break; + } + mutex_unlock(&cam_cdm_mgr_lock); + + return rc; +} + +int cam_cdm_get_iommu_handle(char *identifier, + struct cam_iommu_handle *cdm_handles) +{ + int i, j, rc = -EPERM; + + if ((!identifier) || (!cdm_handles)) + return -EINVAL; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + CAM_DBG(CAM_CDM, "Looking for Iommu handle of %s", identifier); + + for (i = 0; i < cdm_mgr.cdm_count; i++) { + mutex_lock(&cdm_mgr.nodes[i].lock); + if (!cdm_mgr.nodes[i].data) { + mutex_unlock(&cdm_mgr.nodes[i].lock); + continue; + } + for (j = 0; j < + cdm_mgr.nodes[i].data->dt_num_supported_clients; + j++) { + if (!strcmp( + cdm_mgr.nodes[i].data->dt_cdm_client_name[j], + identifier)) { + rc = get_cdm_iommu_handle(cdm_handles, i); + break; + } + } + mutex_unlock(&cdm_mgr.nodes[i].lock); + if (rc == 0) + break; + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_get_iommu_handle); + +int cam_cdm_acquire(struct cam_cdm_acquire_data *data) +{ + int rc = -EPERM; + struct cam_hw_intf *hw; + uint32_t hw_index = 0; + + if ((!data) || (!data->base_array_cnt)) + return -EINVAL; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + if (data->id > CAM_CDM_HW_ANY) { + CAM_ERR(CAM_CDM, + "only CAM_CDM_VIRTUAL/CAM_CDM_HW_ANY is supported"); + rc = -EPERM; + goto end; + } + rc = get_cdm_index_by_id(data->identifier, data->cell_index, + &hw_index); + if ((rc < 0) && (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM)) { + CAM_ERR(CAM_CDM, "Failed to identify associated hw id"); + goto end; + } else { + CAM_DBG(CAM_CDM, "hw_index:%d", hw_index); + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_ACQUIRE, data, + sizeof(struct cam_cdm_acquire_data)); + if (rc < 0) { + CAM_ERR(CAM_CDM, "CDM hw acquire failed"); + goto end; + } + } else { + CAM_ERR(CAM_CDM, "idx %d doesn't have acquire ops", + hw_index); + rc = -EPERM; + } + } +end: + if (rc < 0) { + CAM_ERR(CAM_CDM, "CDM acquire failed for id=%d name=%s, idx=%d", + data->id, data->identifier, data->cell_index); + put_cdm_mgr_refcount(); + } + return rc; +} +EXPORT_SYMBOL(cam_cdm_acquire); + +int cam_cdm_release(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EPERM; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_RELEASE, &handle, + sizeof(handle)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "hw release failed for handle=%x", + handle); + } else + CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops", + hw_index); + } + put_cdm_mgr_refcount(); + if (rc == 0) + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_release); + + +int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (!data) + return rc; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + struct cam_cdm_hw_intf_cmd_submit_bl req; + + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + req.data = data; + req.handle = handle; + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_SUBMIT_BL, &req, + sizeof(struct cam_cdm_hw_intf_cmd_submit_bl)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "hw submit bl failed for handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have submit ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_submit_bls); + +int cam_cdm_stream_on(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.start) { + rc = hw->hw_ops.start(hw->hw_priv, &handle, + sizeof(uint32_t)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "hw start failed handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, + "hw idx %d doesn't have start ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_stream_on); + +int cam_cdm_stream_off(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.stop) { + rc = hw->hw_ops.stop(hw->hw_priv, &handle, + sizeof(uint32_t)); + if (rc < 0) + CAM_ERR(CAM_CDM, "hw stop failed handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have stop ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_stream_off); + +int cam_cdm_reset_hw(uint32_t handle) +{ + uint32_t hw_index; + int rc = -EINVAL; + struct cam_hw_intf *hw; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + hw_index = CAM_CDM_GET_HW_IDX(handle); + if (hw_index < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM) { + hw = cdm_mgr.nodes[hw_index].device; + if (hw && hw->hw_ops.process_cmd) { + rc = hw->hw_ops.process_cmd(hw->hw_priv, + CAM_CDM_HW_INTF_CMD_RESET_HW, &handle, + sizeof(handle)); + if (rc < 0) + CAM_ERR(CAM_CDM, + "CDM hw release failed for handle=%x", + handle); + } else { + CAM_ERR(CAM_CDM, "hw idx %d doesn't have release ops", + hw_index); + } + } + put_cdm_mgr_refcount(); + + return rc; +} +EXPORT_SYMBOL(cam_cdm_reset_hw); + +int cam_cdm_intf_register_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t *index) +{ + int rc = -EINVAL; + + if ((!hw) || (!data) || (!index)) + return rc; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + mutex_lock(&cam_cdm_mgr_lock); + if ((type == CAM_VIRTUAL_CDM) && + (!cdm_mgr.nodes[CAM_SW_CDM_INDEX].device)) { + mutex_lock(&cdm_mgr.nodes[CAM_SW_CDM_INDEX].lock); + cdm_mgr.nodes[CAM_SW_CDM_INDEX].device = hw; + cdm_mgr.nodes[CAM_SW_CDM_INDEX].data = data; + *index = cdm_mgr.cdm_count; + mutex_unlock(&cdm_mgr.nodes[CAM_SW_CDM_INDEX].lock); + cdm_mgr.cdm_count++; + rc = 0; + } else if ((type == CAM_HW_CDM) && (cdm_mgr.cdm_count > 0)) { + mutex_lock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + cdm_mgr.nodes[cdm_mgr.cdm_count].device = hw; + cdm_mgr.nodes[cdm_mgr.cdm_count].data = data; + *index = cdm_mgr.cdm_count; + mutex_unlock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + cdm_mgr.cdm_count++; + rc = 0; + } else { + CAM_ERR(CAM_CDM, "CDM registration failed type=%d count=%d", + type, cdm_mgr.cdm_count); + } + mutex_unlock(&cam_cdm_mgr_lock); + put_cdm_mgr_refcount(); + + return rc; +} + +int cam_cdm_intf_deregister_hw_cdm(struct cam_hw_intf *hw, + struct cam_cdm_private_dt_data *data, enum cam_cdm_type type, + uint32_t index) +{ + int rc = -EINVAL; + + if ((!hw) || (!data)) + return rc; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + rc = -EPERM; + return rc; + } + + mutex_lock(&cam_cdm_mgr_lock); + if ((type == CAM_VIRTUAL_CDM) && + (hw == cdm_mgr.nodes[CAM_SW_CDM_INDEX].device) && + (index == CAM_SW_CDM_INDEX)) { + mutex_lock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + cdm_mgr.nodes[CAM_SW_CDM_INDEX].device = NULL; + cdm_mgr.nodes[CAM_SW_CDM_INDEX].data = NULL; + mutex_unlock(&cdm_mgr.nodes[cdm_mgr.cdm_count].lock); + rc = 0; + } else if ((type == CAM_HW_CDM) && + (hw == cdm_mgr.nodes[index].device)) { + mutex_lock(&cdm_mgr.nodes[index].lock); + cdm_mgr.nodes[index].device = NULL; + cdm_mgr.nodes[index].data = NULL; + mutex_unlock(&cdm_mgr.nodes[index].lock); + cdm_mgr.cdm_count--; + rc = 0; + } else { + CAM_ERR(CAM_CDM, "CDM Deregistration failed type=%d index=%d", + type, index); + } + mutex_unlock(&cam_cdm_mgr_lock); + put_cdm_mgr_refcount(); + + return rc; +} + +static int cam_cdm_intf_probe(struct platform_device *pdev) +{ + int i, rc; + + rc = cam_cdm_intf_mgr_soc_get_dt_properties(pdev, &cdm_mgr); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to get dt properties"); + return rc; + } + mutex_lock(&cam_cdm_mgr_lock); + for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) { + mutex_init(&cdm_mgr.nodes[i].lock); + cdm_mgr.nodes[i].device = NULL; + cdm_mgr.nodes[i].data = NULL; + cdm_mgr.nodes[i].refcount = 0; + } + cdm_mgr.probe_done = true; + cdm_mgr.refcount = 0; + mutex_unlock(&cam_cdm_mgr_lock); + rc = cam_virtual_cdm_probe(pdev); + if (rc) { + mutex_lock(&cam_cdm_mgr_lock); + cdm_mgr.probe_done = false; + for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) { + if (cdm_mgr.nodes[i].device || cdm_mgr.nodes[i].data || + (cdm_mgr.nodes[i].refcount != 0)) + CAM_ERR(CAM_CDM, + "Valid node present in index=%d", i); + mutex_destroy(&cdm_mgr.nodes[i].lock); + cdm_mgr.nodes[i].device = NULL; + cdm_mgr.nodes[i].data = NULL; + cdm_mgr.nodes[i].refcount = 0; + } + mutex_unlock(&cam_cdm_mgr_lock); + } + + CAM_DBG(CAM_CDM, "CDM Intf probe done"); + + return rc; +} + +static int cam_cdm_intf_remove(struct platform_device *pdev) +{ + int i, rc = -EBUSY; + + if (get_cdm_mgr_refcount()) { + CAM_ERR(CAM_CDM, "CDM intf mgr get refcount failed"); + return rc; + } + + if (cam_virtual_cdm_remove(pdev)) { + CAM_ERR(CAM_CDM, "Virtual CDM remove failed"); + goto end; + } + put_cdm_mgr_refcount(); + + mutex_lock(&cam_cdm_mgr_lock); + if (cdm_mgr.refcount != 0) { + CAM_ERR(CAM_CDM, "cdm manger refcount not zero %d", + cdm_mgr.refcount); + goto end; + } + + for (i = 0 ; i < CAM_CDM_INTF_MGR_MAX_SUPPORTED_CDM; i++) { + if (cdm_mgr.nodes[i].device || cdm_mgr.nodes[i].data || + (cdm_mgr.nodes[i].refcount != 0)) { + CAM_ERR(CAM_CDM, "Valid node present in index=%d", i); + mutex_unlock(&cam_cdm_mgr_lock); + goto end; + } + mutex_destroy(&cdm_mgr.nodes[i].lock); + cdm_mgr.nodes[i].device = NULL; + cdm_mgr.nodes[i].data = NULL; + cdm_mgr.nodes[i].refcount = 0; + } + cdm_mgr.probe_done = false; + rc = 0; + +end: + mutex_unlock(&cam_cdm_mgr_lock); + return rc; +} + +static struct platform_driver cam_cdm_intf_driver = { + .probe = cam_cdm_intf_probe, + .remove = cam_cdm_intf_remove, + .driver = { + .name = "msm_cam_cdm_intf", + .owner = THIS_MODULE, + .of_match_table = msm_cam_cdm_intf_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_cdm_intf_init_module(void) +{ + return platform_driver_register(&cam_cdm_intf_driver); +} + +static void __exit cam_cdm_intf_exit_module(void) +{ + platform_driver_unregister(&cam_cdm_intf_driver); +} + +module_init(cam_cdm_intf_init_module); +module_exit(cam_cdm_intf_exit_module); +MODULE_DESCRIPTION("MSM Camera CDM Intf driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_intf_api.h b/techpack/camera/drivers/cam_cdm/cam_cdm_intf_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3e89b22b1b189e00d645f65a1b685062fdd7215e --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_intf_api.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_API_H_ +#define _CAM_CDM_API_H_ + +#include <media/cam_defs.h> +#include "cam_cdm_util.h" +#include "cam_soc_util.h" + +/* enum cam_cdm_id - Enum for possible CAM CDM hardwares */ +enum cam_cdm_id { + CAM_CDM_VIRTUAL, + CAM_CDM_HW_ANY, + CAM_CDM_CPAS_0, + CAM_CDM_IPE0, + CAM_CDM_IPE1, + CAM_CDM_BPS, + CAM_CDM_VFE, + CAM_CDM_MAX +}; + +/* enum cam_cdm_cb_status - Enum for possible CAM CDM callback */ +enum cam_cdm_cb_status { + CAM_CDM_CB_STATUS_BL_SUCCESS, + CAM_CDM_CB_STATUS_INVALID_BL_CMD, + CAM_CDM_CB_STATUS_PAGEFAULT, + CAM_CDM_CB_STATUS_HW_RESET_ONGOING, + CAM_CDM_CB_STATUS_HW_RESET_DONE, + CAM_CDM_CB_STATUS_UNKNOWN_ERROR, +}; + +/* enum cam_cdm_bl_cmd_addr_type - Enum for possible CDM bl cmd addr types */ +enum cam_cdm_bl_cmd_addr_type { + CAM_CDM_BL_CMD_TYPE_MEM_HANDLE, + CAM_CDM_BL_CMD_TYPE_HW_IOVA, + CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA, +}; + +/** + * struct cam_cdm_acquire_data - Cam CDM acquire data structure + * + * @identifier : Input identifier string which is the device label from dt + * like vfe, ife, jpeg etc + * @cell_index : Input integer identifier pointing to the cell index from dt + * of the device. This can be used to form a unique string + * with @identifier like vfe0, ife1, jpeg0 etc + * @id : ID of a specific or any CDM HW which needs to be acquired. + * @userdata : Input private data which will be returned as part + * of callback. + * @cam_cdm_callback : Input callback pointer for triggering the + * callbacks from CDM driver + * @handle : CDM Client handle + * @userdata : Private data given at the time of acquire + * @status : Callback status + * @cookie : Cookie if the callback is gen irq status + * @base_array_cnt : Input number of ioremapped address pair pointing + * in base_array, needed only if selected cdm is a virtual. + * @base_array : Input pointer to ioremapped address pair arrary + * needed only if selected cdm is a virtual. + * @cdm_version : CDM version is output while acquiring HW cdm and + * it is Input while acquiring virtual cdm, Currently fixing it + * to one version below acquire API. + * @ops : Output pointer updated by cdm driver to the CDM + * util ops for this HW version of CDM acquired. + * @handle : Output Unique handle generated for this acquire + * + */ +struct cam_cdm_acquire_data { + char identifier[128]; + uint32_t cell_index; + enum cam_cdm_id id; + void *userdata; + void (*cam_cdm_callback)(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie); + uint32_t base_array_cnt; + struct cam_soc_reg_map *base_array[CAM_SOC_MAX_BLOCK]; + struct cam_hw_version cdm_version; + struct cam_cdm_utils_ops *ops; + uint32_t handle; +}; + +/** + * struct cam_cdm_bl_cmd - Cam CDM HW bl command + * + * @bl_addr : Union of all three type for CDM BL commands + * @mem_handle : Input mem handle of bl cmd + * @offset : Input offset of the actual bl cmd in the memory pointed + * by mem_handle + * @len : Input length of the BL command, Cannot be more than 1MB and + * this is will be validated with offset+size of the memory pointed + * by mem_handle + * + */ +struct cam_cdm_bl_cmd { + union { + int32_t mem_handle; + uint32_t *hw_iova; + uintptr_t kernel_iova; + } bl_addr; + uint32_t offset; + uint32_t len; +}; + +/** + * struct cam_cdm_bl_request - Cam CDM HW base & length (BL) request + * + * @flag : 1 for callback needed and 0 for no callback when this BL + * request is done + * @userdata :Input private data which will be returned as part + * of callback if request for this bl request in flags. + * @cookie : Cookie if the callback is gen irq status + * @type : type of the submitted bl cmd address. + * @cmd_arrary_count : Input number of BL commands to be submitted to CDM + * @bl_cmd_array : Input payload holding the BL cmd's arrary + * to be sumbitted. + * + */ +struct cam_cdm_bl_request { + int flag; + void *userdata; + uint64_t cookie; + enum cam_cdm_bl_cmd_addr_type type; + uint32_t cmd_arrary_count; + struct cam_cdm_bl_cmd cmd[1]; +}; + +/** + * @brief : API to get the CDM capabilities for a camera device type + * + * @identifier : Input pointer to a string which is the device label from dt + * like vfe, ife, jpeg etc, We do not need cell index + * assuming all devices of a single type maps to one SMMU + * client + * @cdm_handles : Input iommu handle memory pointer to update handles + * + * @return 0 on success + */ +int cam_cdm_get_iommu_handle(char *identifier, + struct cam_iommu_handle *cdm_handles); + +/** + * @brief : API to acquire a CDM + * + * @data : Input data for the CDM to be acquired + * + * @return 0 on success + */ +int cam_cdm_acquire(struct cam_cdm_acquire_data *data); + +/** + * @brief : API to release a previously acquired CDM + * + * @handle : Input handle for the CDM to be released + * + * @return 0 on success + */ +int cam_cdm_release(uint32_t handle); + +/** + * @brief : API to submit the base & length (BL's) for acquired CDM + * + * @handle : Input cdm handle to which the BL's needs to be sumbitted. + * @data : Input pointer to the BL's to be sumbitted + * + * @return 0 on success + */ +int cam_cdm_submit_bls(uint32_t handle, struct cam_cdm_bl_request *data); + +/** + * @brief : API to stream ON a previously acquired CDM, + * during this we turn on/off clocks/power based on active clients. + * + * @handle : Input handle for the CDM to be released + * + * @return 0 on success + */ +int cam_cdm_stream_on(uint32_t handle); + +/** + * @brief : API to stream OFF a previously acquired CDM, + * during this we turn on/off clocks/power based on active clients. + * + * @handle : Input handle for the CDM to be released + * + * @return 0 on success + */ +int cam_cdm_stream_off(uint32_t handle); + +/** + * @brief : API to reset previously acquired CDM, + * this can be only performed only the CDM is private. + * + * @handle : Input handle of the CDM to reset + * + * @return 0 on success + */ +int cam_cdm_reset_hw(uint32_t handle); + +#endif /* _CAM_CDM_API_H_ */ diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_soc.c b/techpack/camera/drivers/cam_cdm/cam_cdm_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..2fb5d5fe97b9c494287246084e2c386c2b09f00a --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_soc.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_cdm.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" + +#define CAM_CDM_OFFSET_FROM_REG(x, y) ((x)->offsets[y].offset) +#define CAM_CDM_ATTR_FROM_REG(x, y) ((x)->offsets[y].attribute) + +bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t *value) +{ + void __iomem *reg_addr; + struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info; + void __iomem *base = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base; + resource_size_t mem_len = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size; + + CAM_DBG(CAM_CDM, "E: b=%pK blen=%d reg=%x off=%x", (void __iomem *)base, + (int)mem_len, reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, + reg))); + CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x", (void __iomem *)base, + reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg))); + + if ((reg > cdm->offset_tbl->offset_max_size) || + (reg > cdm->offset_tbl->last_offset)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "Invalid reg=%d\n", reg); + goto permission_error; + } else { + reg_addr = (base + (CAM_CDM_OFFSET_FROM_REG( + cdm->offset_tbl, reg))); + if (reg_addr > (base + mem_len)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Invalid mapped region %d", reg); + goto permission_error; + } + *value = cam_io_r_mb(reg_addr); + CAM_DBG(CAM_CDM, "X b=%pK reg=%x off=%x val=%x", + (void __iomem *)base, reg, + (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), + *value); + return false; + } +permission_error: + *value = 0; + return true; + +} + +bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t value) +{ + void __iomem *reg_addr; + struct cam_cdm *cdm = (struct cam_cdm *)cdm_hw->core_info; + void __iomem *base = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].mem_base; + resource_size_t mem_len = + cdm_hw->soc_info.reg_map[CAM_HW_CDM_BASE_INDEX].size; + + CAM_DBG(CAM_CDM, "E: b=%pK reg=%x off=%x val=%x", (void __iomem *)base, + reg, (CAM_CDM_OFFSET_FROM_REG(cdm->offset_tbl, reg)), value); + + if ((reg > cdm->offset_tbl->offset_max_size) || + (reg > cdm->offset_tbl->last_offset)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, "CDM accessing invalid reg=%d\n", + reg); + goto permission_error; + } else { + reg_addr = (base + CAM_CDM_OFFSET_FROM_REG( + cdm->offset_tbl, reg)); + if (reg_addr > (base + mem_len)) { + CAM_ERR_RATE_LIMIT(CAM_CDM, + "Accessing invalid region %d:%d\n", + reg, (CAM_CDM_OFFSET_FROM_REG( + cdm->offset_tbl, reg))); + goto permission_error; + } + cam_io_w_mb(value, reg_addr); + return false; + } +permission_error: + return true; + +} + +int cam_cdm_soc_load_dt_private(struct platform_device *pdev, + struct cam_cdm_private_dt_data *ptr) +{ + int i, rc = -EINVAL; + + ptr->dt_num_supported_clients = of_property_count_strings( + pdev->dev.of_node, + "cdm-client-names"); + CAM_DBG(CAM_CDM, "Num supported cdm_client = %d", + ptr->dt_num_supported_clients); + if (ptr->dt_num_supported_clients > + CAM_PER_CDM_MAX_REGISTERED_CLIENTS) { + CAM_ERR(CAM_CDM, "Invalid count of client names count=%d", + ptr->dt_num_supported_clients); + rc = -EINVAL; + return rc; + } + if (ptr->dt_num_supported_clients < 0) { + CAM_DBG(CAM_CDM, "No cdm client names found"); + ptr->dt_num_supported_clients = 0; + ptr->dt_cdm_shared = false; + } else { + ptr->dt_cdm_shared = true; + } + for (i = 0; i < ptr->dt_num_supported_clients; i++) { + rc = of_property_read_string_index(pdev->dev.of_node, + "cdm-client-names", i, &(ptr->dt_cdm_client_name[i])); + CAM_DBG(CAM_CDM, "cdm-client-names[%d] = %s", i, + ptr->dt_cdm_client_name[i]); + if (rc < 0) { + CAM_ERR(CAM_CDM, "Reading cdm-client-names failed"); + break; + } + } + + return rc; +} + +int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, + const struct of_device_id *table) +{ + int rc; + struct cam_hw_soc_info *soc_ptr; + const struct of_device_id *id; + + if (!cdm_hw || (cdm_hw->soc_info.soc_private) + || !(cdm_hw->soc_info.pdev)) + return -EINVAL; + + soc_ptr = &cdm_hw->soc_info; + + rc = cam_soc_util_get_dt_properties(soc_ptr); + if (rc != 0) { + CAM_ERR(CAM_CDM, "Failed to retrieve the CDM dt properties"); + } else { + soc_ptr->soc_private = kzalloc( + sizeof(struct cam_cdm_private_dt_data), + GFP_KERNEL); + if (!soc_ptr->soc_private) + return -ENOMEM; + + rc = cam_cdm_soc_load_dt_private(soc_ptr->pdev, + soc_ptr->soc_private); + if (rc != 0) { + CAM_ERR(CAM_CDM, "Failed to load CDM dt private data"); + goto error; + } + id = of_match_node(table, soc_ptr->pdev->dev.of_node); + if ((!id) || !(id->data)) { + CAM_ERR(CAM_CDM, "Failed to retrieve the CDM id table"); + goto error; + } + CAM_DBG(CAM_CDM, "CDM Hw Id compatible =%s", id->compatible); + ((struct cam_cdm *)cdm_hw->core_info)->offset_tbl = + (struct cam_cdm_reg_offset_table *)id->data; + strlcpy(((struct cam_cdm *)cdm_hw->core_info)->name, + id->compatible, + sizeof(((struct cam_cdm *)cdm_hw->core_info)->name)); + } + + return rc; + +error: + rc = -EINVAL; + kfree(soc_ptr->soc_private); + soc_ptr->soc_private = NULL; + return rc; +} + +int cam_cdm_intf_mgr_soc_get_dt_properties( + struct platform_device *pdev, struct cam_cdm_intf_mgr *mgr) +{ + int rc; + + rc = of_property_read_u32(pdev->dev.of_node, + "num-hw-cdm", &mgr->dt_supported_hw_cdm); + CAM_DBG(CAM_CDM, "Number of HW cdm supported =%d", + mgr->dt_supported_hw_cdm); + + return rc; +} diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_soc.h b/techpack/camera/drivers/cam_cdm/cam_cdm_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..b422b34f244b3872a66c0f01c15f1e8a09ff27d9 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_soc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_SOC_H_ +#define _CAM_CDM_SOC_H_ + +int cam_hw_cdm_soc_get_dt_properties(struct cam_hw_info *cdm_hw, + const struct of_device_id *table); +bool cam_cdm_read_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t *value); +bool cam_cdm_write_hw_reg(struct cam_hw_info *cdm_hw, + enum cam_cdm_regs reg, uint32_t value); +int cam_cdm_intf_mgr_soc_get_dt_properties( + struct platform_device *pdev, + struct cam_cdm_intf_mgr *mgr); +int cam_cdm_soc_load_dt_private(struct platform_device *pdev, + struct cam_cdm_private_dt_data *ptr); + +#endif /* _CAM_CDM_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_util.c b/techpack/camera/drivers/cam_cdm/cam_cdm_util.c new file mode 100644 index 0000000000000000000000000000000000000000..278dadb18db42508e5448104042adc65eea296f6 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_util.c @@ -0,0 +1,717 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/bug.h> + +#include "cam_cdm_intf_api.h" +#include "cam_cdm_util.h" +#include "cam_cdm.h" +#include "cam_io_util.h" + +#define CAM_CDM_DWORD 4 + +#define CAM_CDM_SW_CMD_COUNT 2 +#define CAM_CMD_LENGTH_MASK 0xFFFF +#define CAM_CDM_COMMAND_OFFSET 24 +#define CAM_CDM_REG_OFFSET_MASK 0x00FFFFFF + +#define CAM_CDM_DMI_DATA_HI_OFFSET 8 +#define CAM_CDM_DMI_DATA_OFFSET 8 +#define CAM_CDM_DMI_DATA_LO_OFFSET 12 + +static unsigned int CDMCmdHeaderSizes[ + CAM_CDM_CMD_PRIVATE_BASE + CAM_CDM_SW_CMD_COUNT] = { + 0, /* UNUSED*/ + 3, /* DMI*/ + 0, /* UNUSED*/ + 2, /* RegContinuous*/ + 1, /* RegRandom*/ + 2, /* BUFFER_INDIREC*/ + 2, /* GenerateIRQ*/ + 3, /* WaitForEvent*/ + 1, /* ChangeBase*/ + 1, /* PERF_CONTROL*/ + 3, /* DMI32*/ + 3, /* DMI64*/ +}; + +/** + * struct cdm_regrandom_cmd - Definition for CDM random register command. + * @count: Number of register writes + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + */ +struct cdm_regrandom_cmd { + unsigned int count : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_regcontinuous_cmd - Definition for a CDM register range command. + * @count: Number of register writes + * @reserved0: reserved bits + * @cmd: Command ID (CDMCmd) + * @offset: Start address of the range of registers + * @reserved1: reserved bits + */ +struct cdm_regcontinuous_cmd { + unsigned int count : 16; + unsigned int reserved0 : 8; + unsigned int cmd : 8; + unsigned int offset : 24; + unsigned int reserved1 : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_dmi_cmd - Definition for a CDM DMI command. + * @length: Number of bytes in LUT - 1 + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + * @addr: Address of the LUT in memory + * @DMIAddr: Address of the target DMI config register + * @DMISel: DMI identifier + */ +struct cdm_dmi_cmd { + unsigned int length : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; + unsigned int addr; + unsigned int DMIAddr : 24; + unsigned int DMISel : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_indirect_cmd - Definition for a CDM indirect buffer command. + * @length: Number of bytes in buffer - 1 + * @reserved: reserved bits + * @cmd: Command ID (CDMCmd) + * @addr: Device address of the indirect buffer + */ +struct cdm_indirect_cmd { + unsigned int length : 16; + unsigned int reserved : 8; + unsigned int cmd : 8; + unsigned int addr; +} __attribute__((__packed__)); + +/** + * struct cdm_changebase_cmd - Definition for CDM base address change command. + * @base: Base address to be changed to + * @cmd:Command ID (CDMCmd) + */ +struct cdm_changebase_cmd { + unsigned int base : 24; + unsigned int cmd : 8; +} __attribute__((__packed__)); + +/** + * struct cdm_wait_event_cmd - Definition for a CDM Gen IRQ command. + * @mask: Mask for the events + * @id: ID to read back for debug + * @iw_reserved: reserved bits + * @iw: iw AHB write bit + * @cmd:Command ID (CDMCmd) + * @offset: Offset to where data is written + * @offset_reserved: reserved bits + * @data: data returned in IRQ_USR_DATA + */ +struct cdm_wait_event_cmd { + unsigned int mask : 8; + unsigned int id : 8; + unsigned int iw_reserved : 7; + unsigned int iw : 1; + unsigned int cmd : 8; + unsigned int offset : 24; + unsigned int offset_reserved : 8; + unsigned int data; +} __attribute__((__packed__)); + +/** + * struct cdm_genirq_cmd - Definition for a CDM Wait event command. + * @reserved: reserved bits + * @cmd:Command ID (CDMCmd) + * @userdata: userdata returned in IRQ_USR_DATA + */ +struct cdm_genirq_cmd { + unsigned int reserved : 24; + unsigned int cmd : 8; + unsigned int userdata; +} __attribute__((__packed__)); + +/** + * struct cdm_perf_ctrl_cmd_t - Definition for CDM perf control command. + * @perf: perf command + * @reserved: reserved bits + * @cmd:Command ID (CDMCmd) + */ +struct cdm_perf_ctrl_cmd { + unsigned int perf : 2; + unsigned int reserved : 22; + unsigned int cmd : 8; +} __attribute__((__packed__)); + +uint32_t cdm_get_cmd_header_size(unsigned int command) +{ + return CDMCmdHeaderSizes[command]; +} + +uint32_t cdm_required_size_reg_continuous(uint32_t numVals) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT) + numVals; +} + +uint32_t cdm_required_size_reg_random(uint32_t numRegVals) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM) + + (2 * numRegVals); +} + +uint32_t cdm_required_size_dmi(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); +} + +uint32_t cdm_required_size_genirq(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_GEN_IRQ); +} + +uint32_t cdm_required_size_indirect(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT); +} + +uint32_t cdm_required_size_changebase(void) +{ + return cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE); +} + +uint32_t cdm_offsetof_dmi_addr(void) +{ + return offsetof(struct cdm_dmi_cmd, addr); +} + +uint32_t cdm_offsetof_indirect_addr(void) +{ + return offsetof(struct cdm_indirect_cmd, addr); +} + +uint32_t *cdm_write_regcontinuous(uint32_t *pCmdBuffer, uint32_t reg, + uint32_t numVals, uint32_t *pVals) +{ + uint32_t i; + struct cdm_regcontinuous_cmd *pHeader = + (struct cdm_regcontinuous_cmd *)pCmdBuffer; + + pHeader->count = numVals; + pHeader->cmd = CAM_CDM_CMD_REG_CONT; + pHeader->reserved0 = 0; + pHeader->reserved1 = 0; + pHeader->offset = reg; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + + for (i = 0; i < numVals; i++) + (((uint32_t *)pCmdBuffer)[i]) = (((uint32_t *)pVals)[i]); + + pCmdBuffer += numVals; + + return pCmdBuffer; +} + +uint32_t *cdm_write_regrandom(uint32_t *pCmdBuffer, uint32_t numRegVals, + uint32_t *pRegVals) +{ + uint32_t i; + uint32_t *dst, *src; + struct cdm_regrandom_cmd *pHeader = + (struct cdm_regrandom_cmd *)pCmdBuffer; + + pHeader->count = numRegVals; + pHeader->cmd = CAM_CDM_CMD_REG_RANDOM; + pHeader->reserved = 0; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + dst = pCmdBuffer; + src = pRegVals; + for (i = 0; i < numRegVals; i++) { + *dst++ = *src++; + *dst++ = *src++; + } + + return dst; +} + +uint32_t *cdm_write_dmi(uint32_t *pCmdBuffer, uint8_t dmiCmd, + uint32_t DMIAddr, uint8_t DMISel, uint32_t dmiBufferAddr, + uint32_t length) +{ + struct cdm_dmi_cmd *pHeader = (struct cdm_dmi_cmd *)pCmdBuffer; + + pHeader->cmd = dmiCmd; + pHeader->addr = dmiBufferAddr; + pHeader->length = length - 1; + pHeader->DMIAddr = DMIAddr; + pHeader->DMISel = DMISel; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_DMI); + + return pCmdBuffer; +} + +uint32_t *cdm_write_indirect(uint32_t *pCmdBuffer, uint32_t indirectBufAddr, + uint32_t length) +{ + struct cdm_indirect_cmd *pHeader = + (struct cdm_indirect_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_BUFF_INDIRECT; + pHeader->addr = indirectBufAddr; + pHeader->length = length - 1; + + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_BUFF_INDIRECT); + + return pCmdBuffer; +} + +uint32_t *cdm_write_changebase(uint32_t *pCmdBuffer, uint32_t base) +{ + struct cdm_changebase_cmd *pHeader = + (struct cdm_changebase_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_CHANGE_BASE; + pHeader->base = base; + pCmdBuffer += cdm_get_cmd_header_size(CAM_CDM_CMD_CHANGE_BASE); + + return pCmdBuffer; +} + +void cdm_write_genirq(uint32_t *pCmdBuffer, uint32_t userdata) +{ + struct cdm_genirq_cmd *pHeader = (struct cdm_genirq_cmd *)pCmdBuffer; + + pHeader->cmd = CAM_CDM_CMD_GEN_IRQ; + pHeader->userdata = userdata; +} + +struct cam_cdm_utils_ops CDM170_ops = { + cdm_get_cmd_header_size, + cdm_required_size_reg_continuous, + cdm_required_size_reg_random, + cdm_required_size_dmi, + cdm_required_size_genirq, + cdm_required_size_indirect, + cdm_required_size_changebase, + cdm_offsetof_dmi_addr, + cdm_offsetof_indirect_addr, + cdm_write_regcontinuous, + cdm_write_regrandom, + cdm_write_dmi, + cdm_write_indirect, + cdm_write_changebase, + cdm_write_genirq, +}; + +int cam_cdm_get_ioremap_from_base(uint32_t hw_base, + uint32_t base_array_size, + struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK], + void __iomem **device_base) +{ + int ret = -EINVAL, i; + + for (i = 0; i < base_array_size; i++) { + if (base_table[i]) + CAM_DBG(CAM_CDM, "In loop %d ioremap for %x addr=%x", + i, (base_table[i])->mem_cam_base, hw_base); + if ((base_table[i]) && + ((base_table[i])->mem_cam_base == hw_base)) { + *device_base = (base_table[i])->mem_base; + ret = 0; + break; + } + } + + return ret; +} + +static int cam_cdm_util_reg_cont_write(void __iomem *base_addr, + uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes) +{ + int ret = 0; + uint32_t *data; + struct cdm_regcontinuous_cmd *reg_cont; + + if ((cmd_buf_size < cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) || + (!base_addr)) { + CAM_ERR(CAM_CDM, "invalid base addr and data length %d %pK", + cmd_buf_size, base_addr); + return -EINVAL; + } + + reg_cont = (struct cdm_regcontinuous_cmd *)cmd_buf; + if ((!reg_cont->count) || (reg_cont->count > 0x10000) || + (((reg_cont->count * sizeof(uint32_t)) + + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)) > + cmd_buf_size)) { + CAM_ERR(CAM_CDM, "buffer size %d is not sufficient for count%d", + cmd_buf_size, reg_cont->count); + return -EINVAL; + } + data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT); + cam_io_memcpy(base_addr + reg_cont->offset, data, + reg_cont->count * sizeof(uint32_t)); + + *used_bytes = (reg_cont->count * sizeof(uint32_t)) + + (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_CONT)); + + return ret; +} + +static int cam_cdm_util_reg_random_write(void __iomem *base_addr, + uint32_t *cmd_buf, uint32_t cmd_buf_size, uint32_t *used_bytes) +{ + uint32_t i; + struct cdm_regrandom_cmd *reg_random; + uint32_t *data; + + if (!base_addr) { + CAM_ERR(CAM_CDM, "invalid base address"); + return -EINVAL; + } + + reg_random = (struct cdm_regrandom_cmd *) cmd_buf; + if ((!reg_random->count) || (reg_random->count > 0x10000) || + (((reg_random->count * (sizeof(uint32_t) * 2)) + + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM)) > + cmd_buf_size)) { + CAM_ERR(CAM_CDM, "invalid reg_count %d cmd_buf_size %d", + reg_random->count, cmd_buf_size); + return -EINVAL; + } + data = cmd_buf + cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM); + + for (i = 0; i < reg_random->count; i++) { + CAM_DBG(CAM_CDM, "reg random: offset %pK, value 0x%x", + ((void __iomem *)(base_addr + data[0])), + data[1]); + cam_io_w(data[1], base_addr + data[0]); + data += 2; + } + + *used_bytes = ((reg_random->count * (sizeof(uint32_t) * 2)) + + (4 * cdm_get_cmd_header_size(CAM_CDM_CMD_REG_RANDOM))); + + return 0; +} + +static int cam_cdm_util_swd_dmi_write(uint32_t cdm_cmd_type, + void __iomem *base_addr, uint32_t *cmd_buf, uint32_t cmd_buf_size, + uint32_t *used_bytes) +{ + uint32_t i; + struct cdm_dmi_cmd *swd_dmi; + uint32_t *data; + + swd_dmi = (struct cdm_dmi_cmd *)cmd_buf; + + if (cmd_buf_size < (cdm_required_size_dmi() + swd_dmi->length + 1)) { + CAM_ERR(CAM_CDM, "invalid CDM_SWD_DMI length %d", + swd_dmi->length + 1); + return -EINVAL; + } + data = cmd_buf + cdm_required_size_dmi(); + + if (cdm_cmd_type == CAM_CDM_CMD_SWD_DMI_64) { + for (i = 0; i < (swd_dmi->length + 1)/8; i++) { + cam_io_w_mb(data[0], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET); + cam_io_w_mb(data[1], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_HI_OFFSET); + data += 2; + } + } else if (cdm_cmd_type == CAM_CDM_CMD_DMI) { + for (i = 0; i < (swd_dmi->length + 1)/4; i++) { + cam_io_w_mb(data[0], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_OFFSET); + data += 1; + } + } else { + for (i = 0; i < (swd_dmi->length + 1)/4; i++) { + cam_io_w_mb(data[0], base_addr + + swd_dmi->DMIAddr + CAM_CDM_DMI_DATA_LO_OFFSET); + data += 1; + } + } + *used_bytes = (4 * cdm_required_size_dmi()) + swd_dmi->length + 1; + + return 0; +} + +int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, + uint32_t *cmd_buf, uint32_t cmd_buf_size, + struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK], + uint32_t base_array_size, uint8_t bl_tag) +{ + int ret = 0; + uint32_t cdm_cmd_type = 0, total_cmd_buf_size = 0; + uint32_t used_bytes = 0; + + total_cmd_buf_size = cmd_buf_size; + + while (cmd_buf_size > 0) { + CAM_DBG(CAM_CDM, "cmd data=%x", *cmd_buf); + cdm_cmd_type = (*cmd_buf >> CAM_CDM_COMMAND_OFFSET); + switch (cdm_cmd_type) { + case CAM_CDM_CMD_REG_CONT: { + ret = cam_cdm_util_reg_cont_write(*current_device_base, + cmd_buf, cmd_buf_size, &used_bytes); + if (ret) + break; + + if (used_bytes > 0) { + cmd_buf_size -= used_bytes; + cmd_buf += used_bytes/4; + } + } + break; + case CAM_CDM_CMD_REG_RANDOM: { + ret = cam_cdm_util_reg_random_write( + *current_device_base, cmd_buf, cmd_buf_size, + &used_bytes); + if (ret) + break; + + if (used_bytes > 0) { + cmd_buf_size -= used_bytes; + cmd_buf += used_bytes / 4; + } + } + break; + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_SWD_DMI_32: + case CAM_CDM_CMD_SWD_DMI_64: { + if (*current_device_base == 0) { + CAM_ERR(CAM_CDM, + "Got SWI DMI cmd =%d for invalid hw", + cdm_cmd_type); + ret = -EINVAL; + break; + } + ret = cam_cdm_util_swd_dmi_write(cdm_cmd_type, + *current_device_base, cmd_buf, cmd_buf_size, + &used_bytes); + if (ret) + break; + + if (used_bytes > 0) { + cmd_buf_size -= used_bytes; + cmd_buf += used_bytes / 4; + } + } + break; + case CAM_CDM_CMD_CHANGE_BASE: { + struct cdm_changebase_cmd *change_base_cmd = + (struct cdm_changebase_cmd *)cmd_buf; + + ret = cam_cdm_get_ioremap_from_base( + change_base_cmd->base, base_array_size, + base_table, current_device_base); + if (ret != 0) { + CAM_ERR(CAM_CDM, + "Get ioremap change base failed %x", + change_base_cmd->base); + break; + } + CAM_DBG(CAM_CDM, "Got ioremap for %x addr=%pK", + change_base_cmd->base, + current_device_base); + cmd_buf_size -= (4 * + cdm_required_size_changebase()); + cmd_buf += cdm_required_size_changebase(); + } + break; + default: + CAM_ERR(CAM_CDM, "unsupported cdm_cmd_type type 0%x", + cdm_cmd_type); + ret = -EINVAL; + break; + } + + if (ret < 0) + break; + } + + return ret; +} + +static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; + CAM_INFO(CAM_CDM, "DMI"); + return ret; +} + +static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; + CAM_INFO(CAM_CDM, "Buff Indirect"); + return ret; +} + +static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + int i = 0; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + + CAM_INFO(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X", + p_regcont_cmd->count, p_regcont_cmd->offset); + + for (i = 0; i < p_regcont_cmd->count; i++) { + CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i, + *temp_ptr); + temp_ptr++; + ret++; + } + + return ret; +} + +static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr) +{ + struct cdm_regrandom_cmd *p_regrand_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + long ret = 0; + int i = 0; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + + CAM_INFO(CAM_CDM, "REG_RAND: COUNT: %u", + p_regrand_cmd->count); + + for (i = 0; i < p_regrand_cmd->count; i++) { + CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X", + i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i, + *(temp_ptr + 1)); + temp_ptr += 2; + ret += 2; + } + + return ret; +} + +static long cam_cdm_util_dump_gen_irq_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ]; + + CAM_INFO(CAM_CDM, "GEN_IRQ"); + + return ret; +} + +static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT]; + + CAM_INFO(CAM_CDM, "WAIT_EVENT"); + + return ret; +} + +static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_changebase_cmd *p_cbase_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + + p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; + + CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X", + p_cbase_cmd->base); + + return ret; +} + +static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL]; + + CAM_INFO(CAM_CDM, "PERF_CTRL"); + + return ret; +} + +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buf_start, uint32_t *cmd_buf_end) +{ + uint32_t *buf_now = cmd_buf_start; + uint32_t cmd = 0; + + if (!cmd_buf_start || !cmd_buf_end) { + CAM_INFO(CAM_CDM, "Invalid args"); + return; + } + + do { + cmd = *buf_now; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += cam_cdm_util_dump_dmi_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += cam_cdm_util_dump_buff_indirect(buf_now); + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now); + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now); + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += cam_cdm_util_dump_change_base_cmd(buf_now); + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now); + break; + default: + CAM_INFO(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", + cmd, *buf_now); + buf_now++; + break; + } + } while (buf_now <= cmd_buf_end); +} diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_util.h b/techpack/camera/drivers/cam_cdm/cam_cdm_util.h new file mode 100644 index 0000000000000000000000000000000000000000..663eca92a5fefc47778b4d3411f0b909cc821676 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_util.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_UTIL_H_ +#define _CAM_CDM_UTIL_H_ + +enum cam_cdm_command { + CAM_CDM_CMD_UNUSED = 0x0, + CAM_CDM_CMD_DMI = 0x1, + CAM_CDM_CMD_NOT_DEFINED = 0x2, + CAM_CDM_CMD_REG_CONT = 0x3, + CAM_CDM_CMD_REG_RANDOM = 0x4, + CAM_CDM_CMD_BUFF_INDIRECT = 0x5, + CAM_CDM_CMD_GEN_IRQ = 0x6, + CAM_CDM_CMD_WAIT_EVENT = 0x7, + CAM_CDM_CMD_CHANGE_BASE = 0x8, + CAM_CDM_CMD_PERF_CTRL = 0x9, + CAM_CDM_CMD_DMI_32 = 0xa, + CAM_CDM_CMD_DMI_64 = 0xb, + CAM_CDM_CMD_PRIVATE_BASE = 0xc, + CAM_CDM_CMD_SWD_DMI_32 = (CAM_CDM_CMD_PRIVATE_BASE + 0x64), + CAM_CDM_CMD_SWD_DMI_64 = (CAM_CDM_CMD_PRIVATE_BASE + 0x65), + CAM_CDM_CMD_PRIVATE_BASE_MAX = 0x7F +}; + +/** + * struct cam_cdm_utils_ops - Camera CDM util ops + * + * @cdm_get_cmd_header_size: Returns the size of the given command header + * in DWORDs. + * @command Command ID + * @return Size of the command in DWORDs + * + * @cdm_required_size_reg_continuous: Calculates the size of a reg-continuous + * command in dwords. + * @numVals Number of continuous values + * @return Size in dwords + * + * @cdm_required_size_reg_random: Calculates the size of a reg-random command + * in dwords. + * @numRegVals Number of register/value pairs + * @return Size in dwords + * + * @cdm_required_size_dmi: Calculates the size of a DMI command in dwords. + * @return Size in dwords + * + * @cdm_required_size_genirq: Calculates size of a Genirq command in dwords. + * @return Size in dwords + * + * @cdm_required_size_indirect: Calculates the size of an indirect command + * in dwords. + * @return Size in dwords + * + * @cdm_required_size_changebase: Calculates the size of a change-base command + * in dwords. + * @return Size in dwords + * + * @cdm_offsetof_dmi_addr: Returns the offset of address field in the DMI + * command header. + * @return Offset of addr field + * + * @cdm_offsetof_indirect_addr: Returns the offset of address field in the + * indirect command header. + * @return Offset of addr field + * + * @cdm_write_regcontinuous: Writes a command into the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @reg: Beginning of the register address range where + * values will be written. + * @numVals: Number of values (registers) that will be written + * @pVals : An array of values that will be written + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_regrandom: Writes a command into the command buffer in + * register/value pairs. + * @pCmdBuffer: Pointer to command buffer + * @numRegVals: Number of register/value pairs that will be written + * @pRegVals: An array of register/value pairs that will be written + * The even indices are registers and the odd indices + * arevalues, e.g., {reg1, val1, reg2, val2, ...}. + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_dmi: Writes a DMI command into the command bufferM. + * @pCmdBuffer: Pointer to command buffer + * @dmiCmd: DMI command + * @DMIAddr: Address of the DMI + * @DMISel: Selected bank that the DMI will write to + * @length: Size of data in bytes + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_indirect: Writes a indirect command into the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @indirectBufferAddr: Device address of the indirect cmd buffer. + * @length: Size of data in bytes + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_changebase: Writes a changing CDM (address) base command into + * the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @base: New base (device) address + * @return Pointer in command buffer pointing past the written commands + * + * @cdm_write_genirq: Writes a gen irq command into the command buffer. + * @pCmdBuffer: Pointer to command buffer + * @userdata: userdata or cookie return by hardware during irq. + */ +struct cam_cdm_utils_ops { +uint32_t (*cdm_get_cmd_header_size)(unsigned int command); +uint32_t (*cdm_required_size_reg_continuous)(uint32_t numVals); +uint32_t (*cdm_required_size_reg_random)(uint32_t numRegVals); +uint32_t (*cdm_required_size_dmi)(void); +uint32_t (*cdm_required_size_genirq)(void); +uint32_t (*cdm_required_size_indirect)(void); +uint32_t (*cdm_required_size_changebase)(void); +uint32_t (*cdm_offsetof_dmi_addr)(void); +uint32_t (*cdm_offsetof_indirect_addr)(void); +uint32_t* (*cdm_write_regcontinuous)( + uint32_t *pCmdBuffer, + uint32_t reg, + uint32_t numVals, + uint32_t *pVals); +uint32_t *(*cdm_write_regrandom)( + uint32_t *pCmdBuffer, + uint32_t numRegVals, + uint32_t *pRegVals); +uint32_t *(*cdm_write_dmi)( + uint32_t *pCmdBuffer, + uint8_t dmiCmd, + uint32_t DMIAddr, + uint8_t DMISel, + uint32_t dmiBufferAddr, + uint32_t length); +uint32_t *(*cdm_write_indirect)( + uint32_t *pCmdBuffer, + uint32_t indirectBufferAddr, + uint32_t length); +uint32_t *(*cdm_write_changebase)( + uint32_t *pCmdBuffer, + uint32_t base); +void (*cdm_write_genirq)( + uint32_t *pCmdBuffer, + uint32_t userdata); +}; + +/** + * cam_cdm_util_log_cmd_bufs() + * + * @brief: Util function to log cdm command buffers + * + * @cmd_buffer_start: Pointer to start of cmd buffer + * @cmd_buffer_end: Pointer to end of cmd buffer + * + */ +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); + + + +#endif /* _CAM_CDM_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_virtual.h b/techpack/camera/drivers/cam_cdm/cam_cdm_virtual.h new file mode 100644 index 0000000000000000000000000000000000000000..193e01be4796c9c0c52bac0c367b81e07a182a7b --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_virtual.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CDM_VIRTUAL_H_ +#define _CAM_CDM_VIRTUAL_H_ + +#include "cam_cdm_intf_api.h" + +int cam_virtual_cdm_probe(struct platform_device *pdev); +int cam_virtual_cdm_remove(struct platform_device *pdev); +int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, + uint32_t *cmd_buf, uint32_t cmd_buf_size, + struct cam_soc_reg_map *base_table[CAM_SOC_MAX_BLOCK], + uint32_t base_array_size, uint8_t bl_tag); + +#endif /* _CAM_CDM_VIRTUAL_H_ */ diff --git a/techpack/camera/drivers/cam_cdm/cam_cdm_virtual_core.c b/techpack/camera/drivers/cam_cdm/cam_cdm_virtual_core.c new file mode 100644 index 0000000000000000000000000000000000000000..5abca3939338763f49e6f6db86bd6557ab04b04b --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_cdm_virtual_core.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include "cam_soc_util.h" +#include "cam_smmu_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_cdm.h" +#include "cam_cdm_util.h" +#include "cam_cdm_virtual.h" +#include "cam_cdm_core_common.h" +#include "cam_cdm_soc.h" +#include "cam_io_util.h" + +#define CAM_CDM_VIRTUAL_NAME "qcom,cam_virtual_cdm" + +static void cam_virtual_cdm_work(struct work_struct *work) +{ + struct cam_cdm_work_payload *payload; + struct cam_hw_info *cdm_hw; + struct cam_cdm *core; + + payload = container_of(work, struct cam_cdm_work_payload, work); + if (payload) { + cdm_hw = payload->hw; + core = (struct cam_cdm *)cdm_hw->core_info; + if (payload->irq_status & 0x2) { + struct cam_cdm_bl_cb_request_entry *node; + + CAM_DBG(CAM_CDM, "CDM HW Gen/inline IRQ with data=%x", + payload->irq_data); + mutex_lock(&cdm_hw->hw_mutex); + node = cam_cdm_find_request_by_bl_tag( + payload->irq_data, + &core->bl_request_list); + if (node) { + if (node->request_type == + CAM_HW_CDM_BL_CB_CLIENT) { + cam_cdm_notify_clients(cdm_hw, + CAM_CDM_CB_STATUS_BL_SUCCESS, + (void *)node); + } else if (node->request_type == + CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_ERR(CAM_CDM, "Invalid node=%pK %d", + node, node->request_type); + } + list_del_init(&node->entry); + kfree(node); + } else { + CAM_ERR(CAM_CDM, "Invalid node for inline irq"); + } + mutex_unlock(&cdm_hw->hw_mutex); + } + if (payload->irq_status & 0x1) { + CAM_DBG(CAM_CDM, "CDM HW reset done IRQ"); + complete(&core->reset_complete); + } + kfree(payload); + } + +} + +int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, + struct cam_cdm_hw_intf_cmd_submit_bl *req, + struct cam_cdm_client *client) +{ + int i, rc = -EINVAL; + struct cam_cdm_bl_request *cdm_cmd = req->data; + struct cam_cdm *core = (struct cam_cdm *)cdm_hw->core_info; + + mutex_lock(&client->lock); + for (i = 0; i < req->data->cmd_arrary_count ; i++) { + uintptr_t vaddr_ptr = 0; + size_t len = 0; + + if ((!cdm_cmd->cmd[i].len) && + (cdm_cmd->cmd[i].len > 0x100000)) { + CAM_ERR(CAM_CDM, + "len(%d) is invalid count=%d total cnt=%d", + cdm_cmd->cmd[i].len, i, + req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + if (req->data->type == CAM_CDM_BL_CMD_TYPE_MEM_HANDLE) { + rc = cam_mem_get_cpu_buf( + cdm_cmd->cmd[i].bl_addr.mem_handle, &vaddr_ptr, + &len); + } else if (req->data->type == + CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA) { + rc = 0; + vaddr_ptr = cdm_cmd->cmd[i].bl_addr.kernel_iova; + len = cdm_cmd->cmd[i].offset + cdm_cmd->cmd[i].len; + } else { + CAM_ERR(CAM_CDM, + "Only mem hdl/Kernel va type is supported %d", + req->data->type); + rc = -EINVAL; + break; + } + + if ((!rc) && (vaddr_ptr) && (len) && + (len >= cdm_cmd->cmd[i].offset)) { + + + if ((len - cdm_cmd->cmd[i].offset) < + cdm_cmd->cmd[i].len) { + CAM_ERR(CAM_CDM, "Not enough buffer"); + rc = -EINVAL; + break; + } + CAM_DBG(CAM_CDM, + "hdl=%x vaddr=%pK offset=%d cmdlen=%d:%zu", + cdm_cmd->cmd[i].bl_addr.mem_handle, + (void *)vaddr_ptr, cdm_cmd->cmd[i].offset, + cdm_cmd->cmd[i].len, len); + rc = cam_cdm_util_cmd_buf_write( + &client->changebase_addr, + ((uint32_t *)vaddr_ptr + + ((cdm_cmd->cmd[i].offset)/4)), + cdm_cmd->cmd[i].len, client->data.base_array, + client->data.base_array_cnt, core->bl_tag); + if (rc) { + CAM_ERR(CAM_CDM, + "write failed for cnt=%d:%d len %u", + i, req->data->cmd_arrary_count, + cdm_cmd->cmd[i].len); + break; + } + } else { + CAM_ERR(CAM_CDM, + "Sanity check failed for hdl=%x len=%zu:%d", + cdm_cmd->cmd[i].bl_addr.mem_handle, len, + cdm_cmd->cmd[i].offset); + CAM_ERR(CAM_CDM, + "Sanity check failed for cmd_count=%d cnt=%d", + i, req->data->cmd_arrary_count); + rc = -EINVAL; + break; + } + if (!rc) { + struct cam_cdm_work_payload *payload; + + CAM_DBG(CAM_CDM, + "write BL success for cnt=%d with tag=%d", + i, core->bl_tag); + if ((true == req->data->flag) && + (i == req->data->cmd_arrary_count)) { + struct cam_cdm_bl_cb_request_entry *node; + + node = kzalloc(sizeof( + struct cam_cdm_bl_cb_request_entry), + GFP_KERNEL); + if (!node) { + rc = -ENOMEM; + break; + } + node->request_type = CAM_HW_CDM_BL_CB_CLIENT; + node->client_hdl = req->handle; + node->cookie = req->data->cookie; + node->bl_tag = core->bl_tag; + node->userdata = req->data->userdata; + mutex_lock(&cdm_hw->hw_mutex); + list_add_tail(&node->entry, + &core->bl_request_list); + mutex_unlock(&cdm_hw->hw_mutex); + + payload = kzalloc(sizeof( + struct cam_cdm_work_payload), + GFP_ATOMIC); + if (payload) { + payload->irq_status = 0x2; + payload->irq_data = core->bl_tag; + payload->hw = cdm_hw; + INIT_WORK((struct work_struct *) + &payload->work, + cam_virtual_cdm_work); + queue_work(core->work_queue, + &payload->work); + } + } + core->bl_tag++; + CAM_DBG(CAM_CDM, + "Now commit the BL nothing for virtual"); + if (!rc && (core->bl_tag == 63)) + core->bl_tag = 0; + } + } + mutex_unlock(&client->lock); + return rc; +} + +int cam_virtual_cdm_probe(struct platform_device *pdev) +{ + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + struct cam_cdm_private_dt_data *soc_private = NULL; + int rc; + struct cam_cpas_register_params cpas_parms; + + cdm_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!cdm_hw_intf) + return -ENOMEM; + + cdm_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!cdm_hw) { + kfree(cdm_hw_intf); + return -ENOMEM; + } + + cdm_hw->core_info = kzalloc(sizeof(struct cam_cdm), GFP_KERNEL); + if (!cdm_hw->core_info) { + kfree(cdm_hw); + kfree(cdm_hw_intf); + return -ENOMEM; + } + cdm_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + cdm_hw->soc_info.pdev = pdev; + cdm_hw_intf->hw_type = CAM_VIRTUAL_CDM; + cdm_hw->soc_info.soc_private = kzalloc( + sizeof(struct cam_cdm_private_dt_data), GFP_KERNEL); + if (!cdm_hw->soc_info.soc_private) { + rc = -ENOMEM; + goto soc_load_failed; + } + + rc = cam_cdm_soc_load_dt_private(pdev, cdm_hw->soc_info.soc_private); + if (rc) { + CAM_ERR(CAM_CDM, "Failed to load CDM dt private data"); + kfree(cdm_hw->soc_info.soc_private); + cdm_hw->soc_info.soc_private = NULL; + goto soc_load_failed; + } + + cdm_core = (struct cam_cdm *)cdm_hw->core_info; + soc_private = (struct cam_cdm_private_dt_data *) + cdm_hw->soc_info.soc_private; + if (soc_private->dt_cdm_shared == true) + cdm_core->flags = CAM_CDM_FLAG_SHARED_CDM; + else + cdm_core->flags = CAM_CDM_FLAG_PRIVATE_CDM; + + cdm_core->bl_tag = 0; + INIT_LIST_HEAD(&cdm_core->bl_request_list); + init_completion(&cdm_core->reset_complete); + cdm_hw_intf->hw_priv = cdm_hw; + cdm_hw_intf->hw_ops.get_hw_caps = cam_cdm_get_caps; + cdm_hw_intf->hw_ops.init = NULL; + cdm_hw_intf->hw_ops.deinit = NULL; + cdm_hw_intf->hw_ops.start = cam_cdm_stream_start; + cdm_hw_intf->hw_ops.stop = cam_cdm_stream_stop; + cdm_hw_intf->hw_ops.read = NULL; + cdm_hw_intf->hw_ops.write = NULL; + cdm_hw_intf->hw_ops.process_cmd = cam_cdm_process_cmd; + + CAM_DBG(CAM_CDM, "type %d index %d", cdm_hw_intf->hw_type, + cdm_hw_intf->hw_idx); + + platform_set_drvdata(pdev, cdm_hw_intf); + + cdm_hw->open_count = 0; + cdm_core->iommu_hdl.non_secure = -1; + cdm_core->iommu_hdl.secure = -1; + mutex_init(&cdm_hw->hw_mutex); + spin_lock_init(&cdm_hw->hw_lock); + init_completion(&cdm_hw->hw_complete); + mutex_lock(&cdm_hw->hw_mutex); + cdm_core->id = CAM_CDM_VIRTUAL; + memcpy(cdm_core->name, CAM_CDM_VIRTUAL_NAME, + sizeof(CAM_CDM_VIRTUAL_NAME)); + cdm_core->work_queue = alloc_workqueue(cdm_core->name, + WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, + CAM_CDM_INFLIGHT_WORKS); + cdm_core->ops = NULL; + + cpas_parms.cam_cpas_client_cb = cam_cdm_cpas_cb; + cpas_parms.cell_index = cdm_hw->soc_info.index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = cdm_hw_intf; + strlcpy(cpas_parms.identifier, "cam-cdm-intf", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CDM, "Virtual CDM CPAS registration failed"); + goto cpas_registration_failed; + } + CAM_DBG(CAM_CDM, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + cdm_core->cpas_handle = cpas_parms.client_handle; + + CAM_DBG(CAM_CDM, "CDM%d probe successful", cdm_hw_intf->hw_idx); + + rc = cam_cdm_intf_register_hw_cdm(cdm_hw_intf, + soc_private, CAM_VIRTUAL_CDM, &cdm_core->index); + if (rc) { + CAM_ERR(CAM_CDM, "Virtual CDM Interface registration failed"); + goto intf_registration_failed; + } + CAM_DBG(CAM_CDM, "CDM%d registered to intf successful", + cdm_hw_intf->hw_idx); + mutex_unlock(&cdm_hw->hw_mutex); + + return 0; +intf_registration_failed: + cam_cpas_unregister_client(cdm_core->cpas_handle); +cpas_registration_failed: + kfree(cdm_hw->soc_info.soc_private); + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); + mutex_unlock(&cdm_hw->hw_mutex); + mutex_destroy(&cdm_hw->hw_mutex); +soc_load_failed: + kfree(cdm_hw->core_info); + kfree(cdm_hw); + kfree(cdm_hw_intf); + return rc; +} + +int cam_virtual_cdm_remove(struct platform_device *pdev) +{ + struct cam_hw_info *cdm_hw = NULL; + struct cam_hw_intf *cdm_hw_intf = NULL; + struct cam_cdm *cdm_core = NULL; + int rc = -EBUSY; + + cdm_hw_intf = platform_get_drvdata(pdev); + if (!cdm_hw_intf) { + CAM_ERR(CAM_CDM, "Failed to get dev private data"); + return rc; + } + + cdm_hw = cdm_hw_intf->hw_priv; + if (!cdm_hw) { + CAM_ERR(CAM_CDM, + "Failed to get virtual private data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + cdm_core = cdm_hw->core_info; + if (!cdm_core) { + CAM_ERR(CAM_CDM, + "Failed to get virtual core data for type=%d idx=%d", + cdm_hw_intf->hw_type, cdm_hw_intf->hw_idx); + return rc; + } + + rc = cam_cpas_unregister_client(cdm_core->cpas_handle); + if (rc) { + CAM_ERR(CAM_CDM, "CPAS unregister failed"); + return rc; + } + + rc = cam_cdm_intf_deregister_hw_cdm(cdm_hw_intf, + cdm_hw->soc_info.soc_private, CAM_VIRTUAL_CDM, + cdm_core->index); + if (rc) { + CAM_ERR(CAM_CDM, + "Virtual CDM Interface de-registration failed"); + return rc; + } + + flush_workqueue(cdm_core->work_queue); + destroy_workqueue(cdm_core->work_queue); + mutex_destroy(&cdm_hw->hw_mutex); + kfree(cdm_hw->soc_info.soc_private); + kfree(cdm_hw->core_info); + kfree(cdm_hw); + kfree(cdm_hw_intf); + rc = 0; + + return rc; +} diff --git a/techpack/camera/drivers/cam_cdm/cam_hw_cdm170_reg.h b/techpack/camera/drivers/cam_cdm/cam_hw_cdm170_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..4a0fbda825c514950c8d637d5dc5764d01492370 --- /dev/null +++ b/techpack/camera/drivers/cam_cdm/cam_hw_cdm170_reg.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_CDM170_REG_H_ +#define _CAM_HW_CDM170_REG_H_ + +#define CAM_CDM_REG_OFFSET_FIRST 0x0 +#define CAM_CDM_REG_OFFSET_LAST 0x200 +#define CAM_CDM_REGS_COUNT 0x30 +#define CAM_CDM_HWFIFO_SIZE 0x40 + +#define CAM_CDM_OFFSET_HW_VERSION 0x0 +#define CAM_CDM_OFFSET_TITAN_VERSION 0x4 +#define CAM_CDM_OFFSET_RST_CMD 0x10 +#define CAM_CDM_OFFSET_CGC_CFG 0x14 +#define CAM_CDM_OFFSET_CORE_CFG 0x18 +#define CAM_CDM_OFFSET_CORE_EN 0x1c +#define CAM_CDM_OFFSET_FE_CFG 0x20 +#define CAM_CDM_OFFSET_IRQ_MASK 0x30 +#define CAM_CDM_OFFSET_IRQ_CLEAR 0x34 +#define CAM_CDM_OFFSET_IRQ_CLEAR_CMD 0x38 +#define CAM_CDM_OFFSET_IRQ_SET 0x3c +#define CAM_CDM_OFFSET_IRQ_SET_CMD 0x40 + +#define CAM_CDM_OFFSET_IRQ_STATUS 0x44 +#define CAM_CDM_IRQ_STATUS_INFO_RST_DONE_MASK 0x1 +#define CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK 0x2 +#define CAM_CDM_IRQ_STATUS_INFO_BL_DONE_MASK 0x4 +#define CAM_CDM_IRQ_STATUS_ERROR_INV_CMD_MASK 0x10000 +#define CAM_CDM_IRQ_STATUS_ERROR_OVER_FLOW_MASK 0x20000 +#define CAM_CDM_IRQ_STATUS_ERROR_AHB_BUS_MASK 0x40000 + +#define CAM_CDM_OFFSET_BL_FIFO_BASE_REG 0x50 +#define CAM_CDM_OFFSET_BL_FIFO_LEN_REG 0x54 +#define CAM_CDM_OFFSET_BL_FIFO_STORE_REG 0x58 +#define CAM_CDM_OFFSET_BL_FIFO_CFG 0x5c +#define CAM_CDM_OFFSET_BL_FIFO_RB 0x60 +#define CAM_CDM_OFFSET_BL_FIFO_BASE_RB 0x64 +#define CAM_CDM_OFFSET_BL_FIFO_LEN_RB 0x68 +#define CAM_CDM_OFFSET_BL_FIFO_PENDING_REQ_RB 0x6c +#define CAM_CDM_OFFSET_IRQ_USR_DATA 0x80 +#define CAM_CDM_OFFSET_WAIT_STATUS 0x84 +#define CAM_CDM_OFFSET_SCRATCH_0_REG 0x90 +#define CAM_CDM_OFFSET_SCRATCH_1_REG 0x94 +#define CAM_CDM_OFFSET_SCRATCH_2_REG 0x98 +#define CAM_CDM_OFFSET_SCRATCH_3_REG 0x9c +#define CAM_CDM_OFFSET_SCRATCH_4_REG 0xa0 +#define CAM_CDM_OFFSET_SCRATCH_5_REG 0xa4 +#define CAM_CDM_OFFSET_SCRATCH_6_REG 0xa8 +#define CAM_CDM_OFFSET_SCRATCH_7_REG 0xac +#define CAM_CDM_OFFSET_LAST_AHB_ADDR 0xd0 +#define CAM_CDM_OFFSET_LAST_AHB_DATA 0xd4 +#define CAM_CDM_OFFSET_CORE_DBUG 0xd8 +#define CAM_CDM_OFFSET_LAST_AHB_ERR_ADDR 0xe0 +#define CAM_CDM_OFFSET_LAST_AHB_ERR_DATA 0xe4 +#define CAM_CDM_OFFSET_CURRENT_BL_BASE 0xe8 +#define CAM_CDM_OFFSET_CURRENT_BL_LEN 0xec +#define CAM_CDM_OFFSET_CURRENT_USED_AHB_BASE 0xf0 +#define CAM_CDM_OFFSET_DEBUG_STATUS 0xf4 +#define CAM_CDM_OFFSET_BUS_MISR_CFG_0 0x100 +#define CAM_CDM_OFFSET_BUS_MISR_CFG_1 0x104 +#define CAM_CDM_OFFSET_BUS_MISR_RD_VAL 0x108 +#define CAM_CDM_OFFSET_PERF_MON_CTRL 0x110 +#define CAM_CDM_OFFSET_PERF_MON_0 0x114 +#define CAM_CDM_OFFSET_PERF_MON_1 0x118 +#define CAM_CDM_OFFSET_PERF_MON_2 0x11c +#define CAM_CDM_OFFSET_SPARE 0x200 + +/* + * Always make sure below register offsets are aligned with + * enum cam_cdm_regs offsets + */ +struct cam_cdm_reg_offset cam170_cpas_cdm_register_offsets[] = { + { CAM_CDM_OFFSET_HW_VERSION, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_TITAN_VERSION, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_RST_CMD, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_CGC_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_CORE_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_CORE_EN, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_FE_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_MASK, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_CLEAR, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_CLEAR_CMD, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_IRQ_SET, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_IRQ_SET_CMD, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_IRQ_STATUS, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_IRQ_USR_DATA, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_BASE_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_LEN_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_STORE_REG, CAM_REG_ATTR_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_CFG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_RB, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BL_FIFO_BASE_RB, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_BL_FIFO_LEN_RB, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_BL_FIFO_PENDING_REQ_RB, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_WAIT_STATUS, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_SCRATCH_0_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_1_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_2_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_3_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_4_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_5_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_6_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_SCRATCH_7_REG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_LAST_AHB_ADDR, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_LAST_AHB_DATA, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CORE_DBUG, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_LAST_AHB_ERR_ADDR, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_LAST_AHB_ERR_DATA, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CURRENT_BL_BASE, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CURRENT_BL_LEN, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_CURRENT_USED_AHB_BASE, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_DEBUG_STATUS, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_BUS_MISR_CFG_0, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BUS_MISR_CFG_1, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_BUS_MISR_RD_VAL, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_PERF_MON_CTRL, CAM_REG_ATTR_READ_WRITE }, + { CAM_CDM_OFFSET_PERF_MON_0, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_PERF_MON_1, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_PERF_MON_2, CAM_REG_ATTR_READ }, + { CAM_CDM_OFFSET_SPARE, CAM_REG_ATTR_READ_WRITE } +}; + +struct cam_cdm_reg_offset_table cam170_cpas_cdm_offset_table = { + .first_offset = 0x0, + .last_offset = 0x200, + .reg_count = 0x30, + .offsets = cam170_cpas_cdm_register_offsets, + .offset_max_size = (sizeof(cam170_cpas_cdm_register_offsets)/ + sizeof(struct cam_cdm_reg_offset)), +}; + +#endif /* _CAM_HW_CDM170_REG_H_ */ diff --git a/techpack/camera/drivers/cam_core/Makefile b/techpack/camera/drivers/cam_core/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e117039fc3abc437b5ccc614747fd993dc7ea59b --- /dev/null +++ b/techpack/camera/drivers/cam_core/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_context_utils.o cam_node.o cam_subdev.o diff --git a/techpack/camera/drivers/cam_core/cam_context.c b/techpack/camera/drivers/cam_core/cam_context.c new file mode 100644 index 0000000000000000000000000000000000000000..642d530054d886b04bcb1a6d12d98a217a218e8c --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_context.c @@ -0,0 +1,617 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/refcount.h> + +#include "cam_context.h" +#include "cam_debug_util.h" +#include "cam_node.h" + +static int cam_context_handle_hw_event(void *context, uint32_t evt_id, + void *evt_data) +{ + int rc = 0; + struct cam_context *ctx = (struct cam_context *)context; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (ctx->state_machine[ctx->state].irq_ops) + rc = ctx->state_machine[ctx->state].irq_ops(ctx, evt_id, + evt_data); + else + CAM_DBG(CAM_CORE, + "No function to handle event %d in dev %d, state %d", + evt_id, ctx->dev_hdl, ctx->state); + return rc; +} + +int cam_context_shutdown(struct cam_context *ctx) +{ + int rc = 0; + struct cam_release_dev_cmd cmd; + + if (ctx->state > CAM_CTX_AVAILABLE && ctx->state < CAM_CTX_STATE_MAX) { + cmd.session_handle = ctx->session_hdl; + cmd.dev_handle = ctx->dev_hdl; + rc = cam_context_handle_release_dev(ctx, &cmd); + if (rc) + CAM_ERR(CAM_CORE, + "context release failed for dev_name %s", + ctx->dev_name); + else + cam_context_putref(ctx); + } else { + CAM_WARN(CAM_CORE, + "dev %s context id %u state %d invalid to release hdl", + ctx->dev_name, ctx->ctx_id, ctx->state); + rc = -EINVAL; + } + + if (ctx->dev_hdl != -1) { + rc = cam_destroy_device_hdl(ctx->dev_hdl); + if (rc) + CAM_ERR(CAM_CORE, + "destroy device hdl failed for node %s", + ctx->dev_name); + else + ctx->dev_hdl = -1; + } + + return rc; +} + +int cam_context_handle_crm_get_dev_info(struct cam_context *ctx, + struct cam_req_mgr_device_info *info) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!info) { + CAM_ERR(CAM_CORE, "Invalid get device info payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.get_dev_info) { + rc = ctx->state_machine[ctx->state].crm_ops.get_dev_info( + ctx, info); + } else { + CAM_ERR(CAM_CORE, "No get device info in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_link(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!link) { + CAM_ERR(CAM_CORE, "Invalid link payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.link) { + rc = ctx->state_machine[ctx->state].crm_ops.link(ctx, link); + } else { + CAM_ERR(CAM_CORE, "No crm link in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_unlink(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!unlink) { + CAM_ERR(CAM_CORE, "Invalid unlink payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.unlink) { + rc = ctx->state_machine[ctx->state].crm_ops.unlink( + ctx, unlink); + } else { + CAM_ERR(CAM_CORE, "No crm unlink in dev %d, name %s, state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_apply_req(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!apply) { + CAM_ERR(CAM_CORE, "Invalid apply request payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.apply_req) { + rc = ctx->state_machine[ctx->state].crm_ops.apply_req(ctx, + apply); + } else { + CAM_ERR(CAM_CORE, "No crm apply req in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_flush_req(struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.flush_req) { + rc = ctx->state_machine[ctx->state].crm_ops.flush_req(ctx, + flush); + } else { + CAM_ERR(CAM_CORE, "No crm flush req in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_crm_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *process_evt) +{ + int rc = 0; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].crm_ops.process_evt) { + rc = ctx->state_machine[ctx->state].crm_ops.process_evt(ctx, + process_evt); + } else { + /* handling of this message is optional */ + CAM_DBG(CAM_CORE, "No crm process evt in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, + uint32_t buf_info) +{ + int rc = 0; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if ((ctx->state > CAM_CTX_AVAILABLE) && + (ctx->state < CAM_CTX_STATE_MAX)) { + if (ctx->state_machine[ctx->state].pagefault_ops) { + rc = ctx->state_machine[ctx->state].pagefault_ops( + ctx, iova, buf_info); + } else { + CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } + } + + return rc; +} + +int cam_context_handle_acquire_dev(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + int i; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid acquire device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.acquire_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_dev( + ctx, cmd); + } else { + CAM_ERR(CAM_CORE, "No acquire device in dev %d, state %d", + cmd->dev_handle, ctx->state); + rc = -EPROTO; + } + + INIT_LIST_HEAD(&ctx->active_req_list); + INIT_LIST_HEAD(&ctx->wait_req_list); + INIT_LIST_HEAD(&ctx->pending_req_list); + INIT_LIST_HEAD(&ctx->free_req_list); + + for (i = 0; i < ctx->req_size; i++) { + INIT_LIST_HEAD(&ctx->req_list[i].list); + list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list); + } + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_acquire_hw(struct cam_context *ctx, + void *args) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_CORE, "Invalid acquire device hw command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.acquire_hw) { + rc = ctx->state_machine[ctx->state].ioctl_ops.acquire_hw( + ctx, args); + } else { + CAM_ERR(CAM_CORE, "No acquire hw for dev %s, state %d", + ctx->dev_name, ctx->state); + rc = -EPROTO; + } + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_release_dev(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid release device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev( + ctx, cmd); + } else { + CAM_ERR(CAM_CORE, "No release device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_release_hw(struct cam_context *ctx, + void *args) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_CORE, "Invalid release HW command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.release_hw) { + rc = ctx->state_machine[ctx->state].ioctl_ops.release_hw( + ctx, args); + } else { + CAM_ERR(CAM_CORE, "No release hw for dev %s, state %d", + ctx->dev_name, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_flush_dev(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc = 0; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid flush device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.flush_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.flush_dev( + ctx, cmd); + } else { + CAM_WARN(CAM_CORE, "No flush device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_config_dev(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + + if (!ctx->state_machine) { + CAM_ERR(CAM_CORE, "context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid config device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.config_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.config_dev( + ctx, cmd); + } else { + CAM_ERR(CAM_CORE, "No config device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + rc = -EPROTO; + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_start_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid start device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.start_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.start_dev( + ctx, cmd); + else + /* start device can be optional for some driver */ + CAM_DBG(CAM_CORE, "No start device in dev %d, state %d", + ctx->dev_hdl, ctx->state); + + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_stop_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_CORE, "Invalid stop device command payload"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev) + rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev( + ctx, cmd); + else + /* stop device can be optional for some driver */ + CAM_WARN(CAM_CORE, "No stop device in dev %d, name %s state %d", + ctx->dev_hdl, ctx->dev_name, ctx->state); + + ctx->last_flush_req = 0; + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + +int cam_context_handle_info_dump(void *context, + enum cam_context_dump_id id) +{ + int rc = 0; + struct cam_context *ctx = (struct cam_context *)context; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].dumpinfo_ops) + rc = ctx->state_machine[ctx->state].dumpinfo_ops(ctx, + id); + mutex_unlock(&ctx->ctx_mutex); + + if (rc) + CAM_WARN(CAM_CORE, + "Dump for id %u failed on ctx_id %u name %s state %d", + id, ctx->ctx_id, ctx->dev_name, ctx->state); + + return rc; +} + +int cam_context_init(struct cam_context *ctx, + const char *dev_name, + uint64_t dev_id, + uint32_t ctx_id, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_mgr_intf, + struct cam_ctx_request *req_list, + uint32_t req_size) +{ + int i; + + /* crm_node_intf is optinal */ + if (!ctx || !hw_mgr_intf || !req_list) { + CAM_ERR(CAM_CORE, "Invalid input parameters"); + return -EINVAL; + } + + memset(ctx, 0, sizeof(*ctx)); + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + ctx->session_hdl = -1; + INIT_LIST_HEAD(&ctx->list); + mutex_init(&ctx->ctx_mutex); + mutex_init(&ctx->sync_mutex); + spin_lock_init(&ctx->lock); + + strlcpy(ctx->dev_name, dev_name, CAM_CTX_DEV_NAME_MAX_LENGTH); + ctx->dev_id = dev_id; + ctx->ctx_id = ctx_id; + ctx->last_flush_req = 0; + ctx->ctx_crm_intf = NULL; + ctx->crm_ctx_intf = crm_node_intf; + ctx->hw_mgr_intf = hw_mgr_intf; + ctx->irq_cb_intf = cam_context_handle_hw_event; + + INIT_LIST_HEAD(&ctx->active_req_list); + INIT_LIST_HEAD(&ctx->wait_req_list); + INIT_LIST_HEAD(&ctx->pending_req_list); + INIT_LIST_HEAD(&ctx->free_req_list); + ctx->req_list = req_list; + ctx->req_size = req_size; + for (i = 0; i < req_size; i++) { + INIT_LIST_HEAD(&ctx->req_list[i].list); + list_add_tail(&ctx->req_list[i].list, &ctx->free_req_list); + ctx->req_list[i].ctx = ctx; + } + ctx->state = CAM_CTX_AVAILABLE; + ctx->state_machine = NULL; + ctx->ctx_priv = NULL; + + return 0; +} + +int cam_context_deinit(struct cam_context *ctx) +{ + if (!ctx) + return -EINVAL; + + /** + * This is called from platform device remove. + * Everyting should be released at this moment. + * so we just free the memory for the context + */ + if (ctx->state != CAM_CTX_AVAILABLE) + CAM_ERR(CAM_CORE, "Device did not shutdown cleanly"); + + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} + +void cam_context_putref(struct cam_context *ctx) +{ + kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + CAM_DBG(CAM_CORE, + "ctx device hdl %ld, ref count %d, dev_name %s", + ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), + ctx->dev_name); +} + +void cam_context_getref(struct cam_context *ctx) +{ + if (kref_get_unless_zero(&ctx->refcount) == 0) { + /* should never happen */ + WARN(1, "%s fail\n", __func__); + } + CAM_DBG(CAM_CORE, + "ctx device hdl %ld, ref count %d, dev_name %s", + ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), + ctx->dev_name); +} diff --git a/techpack/camera/drivers/cam_core/cam_context.h b/techpack/camera/drivers/cam_core/cam_context.h new file mode 100644 index 0000000000000000000000000000000000000000..2c1c685e76b84ff956f5fb3047de422421e358b7 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_context.h @@ -0,0 +1,480 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CONTEXT_H_ +#define _CAM_CONTEXT_H_ + +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/kref.h> +#include "cam_req_mgr_interface.h" +#include "cam_hw_mgr_intf.h" + +/* Forward declarations */ +struct cam_context; + +/* max device name string length*/ +#define CAM_CTX_DEV_NAME_MAX_LENGTH 20 + +/* max request number */ +#define CAM_CTX_REQ_MAX 20 +#define CAM_CTX_CFG_MAX 20 +#define CAM_CTX_RES_MAX 20 + +/** + * enum cam_ctx_state - context top level states + * + */ +enum cam_context_state { + CAM_CTX_UNINIT = 0, + CAM_CTX_AVAILABLE = 1, + CAM_CTX_ACQUIRED = 2, + CAM_CTX_READY = 3, + CAM_CTX_FLUSHED = 4, + CAM_CTX_ACTIVATED = 5, + CAM_CTX_STATE_MAX = 6, +}; + +/** + * struct cam_ctx_request - Common request structure for the context + * + * @list: Link list entry + * @status: Request status + * @request_id: Request id + * @req_priv: Derived request object + * @hw_update_entries: Hardware update entries + * @num_hw_update_entries: Number of hardware update entries + * @in_map_entries: Entries for in fences + * @num_in_map_entries: Number of in map entries + * @out_map_entries: Entries for out fences + * @num_out_map_entries: Number of out map entries + * @num_in_acked: Number of in fence acked + * @num_out_acked: Number of out fence acked + * @flushed: Request is flushed + * @ctx: The context to which this request belongs + * @pf_data page fault debug data + * + */ +struct cam_ctx_request { + struct list_head list; + uint32_t status; + uint64_t request_id; + void *req_priv; + struct cam_hw_update_entry hw_update_entries[CAM_CTX_CFG_MAX]; + uint32_t num_hw_update_entries; + struct cam_hw_fence_map_entry in_map_entries[CAM_CTX_CFG_MAX]; + uint32_t num_in_map_entries; + struct cam_hw_fence_map_entry out_map_entries[CAM_CTX_CFG_MAX]; + uint32_t num_out_map_entries; + atomic_t num_in_acked; + uint32_t num_out_acked; + int flushed; + struct cam_context *ctx; + struct cam_hw_mgr_dump_pf_data pf_data; +}; + +/** + * struct cam_ctx_ioctl_ops - Function table for handling IOCTL calls + * + * @acquire_dev: Function pointer for acquire device + * @release_dev: Function pointer for release device + * @config_dev: Function pointer for config device + * @start_dev: Function pointer for start device + * @stop_dev: Function pointer for stop device + * @flush_dev: Function pointer for flush device + * @acquire_hw: Function pointer for acquire hw + * @release_hw: Function pointer for release hw + * + */ +struct cam_ctx_ioctl_ops { + int (*acquire_dev)(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd); + int (*release_dev)(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd); + int (*config_dev)(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd); + int (*start_dev)(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + int (*stop_dev)(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + int (*flush_dev)(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); + int (*acquire_hw)(struct cam_context *ctx, void *args); + int (*release_hw)(struct cam_context *ctx, void *args); +}; + +/** + * struct cam_ctx_crm_ops - Function table for handling CRM to context calls + * + * @get_dev_info: Get device informaiton + * @link: Link the context + * @unlink: Unlink the context + * @apply_req: Apply setting for the context + * @flush_req: Flush request to remove request ids + * @process_evt: Handle event notification from CRM.(optional) + * + */ +struct cam_ctx_crm_ops { + int (*get_dev_info)(struct cam_context *ctx, + struct cam_req_mgr_device_info *device_info); + int (*link)(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link); + int (*unlink)(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink); + int (*apply_req)(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply); + int (*flush_req)(struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush); + int (*process_evt)(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *evt_data); +}; + + +/** + * struct cam_ctx_ops - Collection of the interface funciton tables + * + * @ioctl_ops: Ioctl funciton table + * @crm_ops: CRM to context interface function table + * @irq_ops: Hardware event handle function + * @pagefault_ops: Function to be called on page fault + * @dumpinfo_ops: Function to be invoked for dumping any + * context info + * + */ +struct cam_ctx_ops { + struct cam_ctx_ioctl_ops ioctl_ops; + struct cam_ctx_crm_ops crm_ops; + cam_hw_event_cb_func irq_ops; + cam_hw_pagefault_cb_func pagefault_ops; + cam_ctx_info_dump_cb_func dumpinfo_ops; +}; + +/** + * struct cam_context - camera context object for the subdevice node + * + * @dev_name: String giving name of device associated + * @dev_id: ID of device associated + * @ctx_id: ID for this context + * @list: Link list entry + * @sessoin_hdl: Session handle + * @dev_hdl: Device handle + * @link_hdl: Link handle + * @ctx_mutex: Mutex for ioctl calls + * @lock: Spin lock + * @active_req_list: Requests pending for done event + * @pending_req_list: Requests pending for reg upd event + * @wait_req_list: Requests waiting for apply + * @free_req_list: Requests that are free + * @req_list: Reference to the request storage + * @req_size: Size of the request storage + * @hw_mgr_intf: Context to HW interface + * @ctx_crm_intf: Context to CRM interface + * @crm_ctx_intf: CRM to context interface + * @irq_cb_intf: HW to context callback interface + * @state: Current state for top level state machine + * @state_machine: Top level state machine + * @ctx_priv: Private context pointer + * @ctxt_to_hw_map: Context to hardware mapping pointer + * @refcount: Context object refcount + * @node: The main node to which this context belongs + * @sync_mutex: mutex to sync with sync cb thread + * @last_flush_req: Last request to flush + * + */ +struct cam_context { + char dev_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + uint64_t dev_id; + uint32_t ctx_id; + struct list_head list; + int32_t session_hdl; + int32_t dev_hdl; + int32_t link_hdl; + + struct mutex ctx_mutex; + spinlock_t lock; + + struct list_head active_req_list; + struct list_head pending_req_list; + struct list_head wait_req_list; + struct list_head free_req_list; + struct cam_ctx_request *req_list; + uint32_t req_size; + + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_req_mgr_crm_cb *ctx_crm_intf; + struct cam_req_mgr_kmd_ops *crm_ctx_intf; + cam_hw_event_cb_func irq_cb_intf; + + enum cam_context_state state; + struct cam_ctx_ops *state_machine; + + void *ctx_priv; + void *ctxt_to_hw_map; + + struct kref refcount; + void *node; + struct mutex sync_mutex; + uint32_t last_flush_req; +}; + +/** + * cam_context_shutdown() + * + * @brief: Calls while device close or shutdown + * + * @ctx: Object pointer for cam_context + * + */ +int cam_context_shutdown(struct cam_context *ctx); + +/** + * cam_context_handle_crm_get_dev_info() + * + * @brief: Handle get device information command + * + * @ctx: Object pointer for cam_context + * @info: Device information returned + * + */ +int cam_context_handle_crm_get_dev_info(struct cam_context *ctx, + struct cam_req_mgr_device_info *info); + +/** + * cam_context_handle_crm_link() + * + * @brief: Handle link command + * + * @ctx: Object pointer for cam_context + * @link: Link command payload + * + */ +int cam_context_handle_crm_link(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link); + +/** + * cam_context_handle_crm_unlink() + * + * @brief: Handle unlink command + * + * @ctx: Object pointer for cam_context + * @unlink: Unlink command payload + * + */ +int cam_context_handle_crm_unlink(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink); + +/** + * cam_context_handle_crm_apply_req() + * + * @brief: Handle apply request command + * + * @ctx: Object pointer for cam_context + * @apply: Apply request command payload + * + */ +int cam_context_handle_crm_apply_req(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply); + +/** + * cam_context_handle_crm_flush_req() + * + * @brief: Handle flush request command + * + * @ctx: Object pointer for cam_context + * @apply: Flush request command payload + * + */ +int cam_context_handle_crm_flush_req(struct cam_context *ctx, + struct cam_req_mgr_flush_request *apply); + +/** + * cam_context_handle_crm_process_evt() + * + * @brief: Handle process event command + * + * @ctx: Object pointer for cam_context + * @process_evt: process event command payload + * + */ +int cam_context_handle_crm_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *process_evt); + +/** + * cam_context_dump_pf_info() + * + * @brief: Handle dump active request request command + * + * @ctx: Object pointer for cam_context + * @iova: Page fault address + * @buf_info: Information about closest memory handle + * + */ +int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, + uint32_t buf_info); + +/** + * cam_context_handle_acquire_dev() + * + * @brief: Handle acquire device command + * + * @ctx: Object pointer for cam_context + * @cmd: Acquire device command payload + * + */ +int cam_context_handle_acquire_dev(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd); + +/** + * cam_context_handle_acquire_hw() + * + * @brief: Handle acquire HW command + * + * @ctx: Object pointer for cam_context + * @cmd: Acquire HW command payload + * + */ +int cam_context_handle_acquire_hw(struct cam_context *ctx, + void *cmd); + +/** + * cam_context_handle_release_dev() + * + * @brief: Handle release device command + * + * @ctx: Object pointer for cam_context + * @cmd: Release device command payload + * + */ +int cam_context_handle_release_dev(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd); + +/** + * cam_context_handle_release_hw() + * + * @brief: Handle release HW command + * + * @ctx: Object pointer for cam_context + * @cmd: Release HW command payload + * + */ +int cam_context_handle_release_hw(struct cam_context *ctx, + void *cmd); + +/** + * cam_context_handle_config_dev() + * + * @brief: Handle config device command + * + * @ctx: Object pointer for cam_context + * @cmd: Config device command payload + * + */ +int cam_context_handle_config_dev(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd); + +/** + * cam_context_handle_flush_dev() + * + * @brief: Handle flush device command + * + * @ctx: Object pointer for cam_context + * @cmd: Flush device command payload + * + */ +int cam_context_handle_flush_dev(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); + +/** + * cam_context_handle_start_dev() + * + * @brief: Handle start device command + * + * @ctx: Object pointer for cam_context + * @cmd: Start device command payload + * + */ +int cam_context_handle_start_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + +/** + * cam_context_handle_stop_dev() + * + * @brief: Handle stop device command + * + * @ctx: Object pointer for cam_context + * @cmd: Stop device command payload + * + */ +int cam_context_handle_stop_dev(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + +/** + * cam_context_handle_info_dump() + * + * @brief: Handle any dump info for the context + * + * @ctx: Object pointer for cam_context + * @id: To indicate which info pertaining + * to that ctx needs to be dumped + * + */ +int cam_context_handle_info_dump(void *context, + enum cam_context_dump_id id); + +/** + * cam_context_deinit() + * + * @brief: Camera context deinitialize function + * + * @ctx: Object pointer for cam_context + * + */ +int cam_context_deinit(struct cam_context *ctx); + +/** + * cam_context_init() + * + * @brief: Camera context initialize function + * + * @ctx: Object pointer for cam_context + * @dev_name: String giving name of device associated + * @dev_id: ID of the device associated + * @ctx_id: ID for this context + * @crm_node_intf: Function table for crm to context interface + * @hw_mgr_intf: Function table for context to hw interface + * @req_list: Requests storage + * @req_size: Size of the request storage + * + */ +int cam_context_init(struct cam_context *ctx, + const char *dev_name, + uint64_t dev_id, + uint32_t ctx_id, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_mgr_intf, + struct cam_ctx_request *req_list, + uint32_t req_size); + +/** + * cam_context_putref() + * + * @brief: Put back context reference. + * + * @ctx: Context for which ref is returned + * + */ +void cam_context_putref(struct cam_context *ctx); + +/** + * cam_context_getref() + * + * @brief: Get back context reference. + * + * @ctx: Context for which ref is taken + * + */ +void cam_context_getref(struct cam_context *ctx); + +#endif /* _CAM_CONTEXT_H_ */ diff --git a/techpack/camera/drivers/cam_core/cam_context_utils.c b/techpack/camera/drivers/cam_core/cam_context_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..423961aaf2afd863cccdcc95e51c6378fe24bf51 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_context_utils.c @@ -0,0 +1,1048 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <media/cam_sync.h> +#include <media/cam_defs.h> + +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_mem_mgr.h" +#include "cam_node.h" +#include "cam_req_mgr_util.h" +#include "cam_sync_api.h" +#include "cam_trace.h" +#include "cam_debug_util.h" + +static uint cam_debug_ctx_req_list; +module_param(cam_debug_ctx_req_list, uint, 0644); + +static inline int cam_context_validate_thread(void) +{ + if (in_interrupt()) { + WARN(1, "Invalid execution context\n"); + return -EINVAL; + } + return 0; +} + +int cam_context_buf_done_from_hw(struct cam_context *ctx, + void *done_event_data, uint32_t bubble_state) +{ + int j; + int result; + struct cam_ctx_request *req; + struct cam_hw_done_event_data *done = + (struct cam_hw_done_event_data *)done_event_data; + int rc; + + if (!ctx || !done) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, done); + return -EINVAL; + } + + rc = cam_context_validate_thread(); + if (rc) + return rc; + + spin_lock(&ctx->lock); + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_CTXT, "[%s][%d] no active request", + ctx->dev_name, ctx->ctx_id); + spin_unlock(&ctx->lock); + return -EIO; + } + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + trace_cam_buf_done("UTILS", ctx, req); + + if (done->request_id != req->request_id) { + CAM_ERR(CAM_CTXT, + "[%s][%d] mismatch: done req[%lld], active req[%lld]", + ctx->dev_name, ctx->ctx_id, + done->request_id, req->request_id); + spin_unlock(&ctx->lock); + return -EIO; + } + + if (!req->num_out_map_entries) { + CAM_ERR(CAM_CTXT, "[%s][%d] no output fence to signal", + ctx->dev_name, ctx->ctx_id); + spin_unlock(&ctx->lock); + return -EIO; + } + + /* + * since another thread may be adding/removing from active + * list, so hold the lock + */ + list_del_init(&req->list); + spin_unlock(&ctx->lock); + if (!bubble_state) { + result = CAM_SYNC_STATE_SIGNALED_SUCCESS; + } else { + CAM_DBG(CAM_REQ, + "[%s][ctx_id %d] : req[%llu] is done with error", + ctx->dev_name, ctx->ctx_id, req->request_id); + + for (j = 0; j < req->num_out_map_entries; j++) + CAM_DBG(CAM_REQ, "fence %d signaled with error", + req->out_map_entries[j].sync_id); + + result = CAM_SYNC_STATE_SIGNALED_ERROR; + } + + for (j = 0; j < req->num_out_map_entries; j++) { + cam_sync_signal(req->out_map_entries[j].sync_id, result); + req->out_map_entries[j].sync_id = -1; + } + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from active_list to free_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + /* + * another thread may be adding/removing from free list, + * so hold the lock + */ + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + req->ctx = NULL; + spin_unlock(&ctx->lock); + + return 0; +} + +static int cam_context_apply_req_to_hw(struct cam_ctx_request *req, + struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_context *ctx = req->ctx; + struct cam_hw_config_args cfg; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + spin_lock(&ctx->lock); + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from pending_list to active_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req->hw_update_entries; + cfg.num_hw_update_entries = req->num_hw_update_entries; + cfg.out_map_entries = req->out_map_entries; + cfg.num_out_map_entries = req->num_out_map_entries; + cfg.priv = req->req_priv; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + spin_lock(&ctx->lock); + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from active_list to free_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + } + +end: + return rc; +} + +static void cam_context_sync_callback(int32_t sync_obj, int status, void *data) +{ + struct cam_ctx_request *req = data; + struct cam_context *ctx = NULL; + struct cam_flush_dev_cmd flush_cmd; + struct cam_req_mgr_apply_request apply; + int rc; + + if (!req) { + CAM_ERR(CAM_CTXT, "Invalid input param"); + return; + } + rc = cam_context_validate_thread(); + if (rc) + return; + + ctx = req->ctx; + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid ctx for req %llu", req->request_id); + return; + } + + if (atomic_inc_return(&req->num_in_acked) == req->num_in_map_entries) { + apply.request_id = req->request_id; + /* + * take mutex to ensure that another thread does + * not flush the request while this + * thread is submitting it to h/w. The submit to + * h/w and adding to the active list should happen + * in a critical section which is provided by this + * mutex. + */ + if (status == CAM_SYNC_STATE_SIGNALED_ERROR) { + CAM_DBG(CAM_CTXT, "fence error: %d", sync_obj); + flush_cmd.req_id = req->request_id; + cam_context_flush_req_to_hw(ctx, &flush_cmd); + } + + mutex_lock(&ctx->sync_mutex); + if (!req->flushed) { + cam_context_apply_req_to_hw(req, &apply); + mutex_unlock(&ctx->sync_mutex); + } else { + req->flushed = 0; + req->ctx = NULL; + mutex_unlock(&ctx->sync_mutex); + spin_lock(&ctx->lock); + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from pending_list to free_list", + ctx->dev_name, ctx->ctx_id, + req->request_id); + } + } + cam_context_putref(ctx); +} + +int32_t cam_context_release_dev_to_hw(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + struct cam_hw_release_args arg; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input param"); + return -EINVAL; + } + + if ((!ctx->hw_mgr_intf) || (!ctx->hw_mgr_intf->hw_release)) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + return -EINVAL; + } + + arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + arg.active_req = false; + + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &arg); + ctx->ctxt_to_hw_map = NULL; + + ctx->session_hdl = -1; + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + + return 0; +} + +int32_t cam_context_config_dev_to_hw( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + size_t len; + struct cam_hw_stream_setttings cfg; + uintptr_t packet_addr; + struct cam_packet *packet; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + return -EINVAL; + } + + if (!ctx->hw_mgr_intf->hw_config_stream_settings) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + return rc; + } + + rc = cam_context_validate_thread(); + if (rc) { + CAM_ERR(CAM_CTXT, + "Not executing in the right context"); + return rc; + } + + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc) { + CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + return rc; + } + + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); + + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cfg.priv = NULL; + + CAM_DBG(CAM_CTXT, "Processing config settings"); + rc = ctx->hw_mgr_intf->hw_config_stream_settings( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Config failed stream settings", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + } + + return rc; +} + +int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_hw_prepare_update_args cfg; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + size_t remain_len = 0; + int32_t i = 0, j = 0; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + return -EINVAL; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + return -EFAULT; + } + rc = cam_context_validate_thread(); + if (rc) + return rc; + + spin_lock(&ctx->lock); + if (!list_empty(&ctx->free_req_list)) { + req = list_first_entry(&ctx->free_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + } + spin_unlock(&ctx->lock); + + if (!req) { + CAM_ERR(CAM_CTXT, "[%s][%d] No more request obj free", + ctx->dev_name, ctx->ctx_id); + return -ENOMEM; + } + + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->list); + req->ctx = ctx; + + /* for config dev, only memory handle is supported */ + /* map packet from the memhandle */ + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + goto free_req; + } + + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf"); + return -EINVAL; + + } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CTXT, "invalid buff length: %zu or offset", len); + rc = -EINVAL; + goto free_req; + } + + remain_len -= (size_t)cmd->offset; + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); + + if (packet->header.request_id <= ctx->last_flush_req) { + CAM_ERR(CAM_CORE, + "request %lld has been flushed, reject packet", + packet->header.request_id); + rc = -EINVAL; + goto free_req; + } + + if (packet->header.request_id > ctx->last_flush_req) + ctx->last_flush_req = 0; + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.remain_len = remain_len; + cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cfg.max_hw_update_entries = CAM_CTX_CFG_MAX; + cfg.num_hw_update_entries = req->num_hw_update_entries; + cfg.hw_update_entries = req->hw_update_entries; + cfg.max_out_map_entries = CAM_CTX_CFG_MAX; + cfg.out_map_entries = req->out_map_entries; + cfg.max_in_map_entries = CAM_CTX_CFG_MAX; + cfg.in_map_entries = req->in_map_entries; + cfg.pf_data = &(req->pf_data); + + rc = ctx->hw_mgr_intf->hw_prepare_update( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc != 0) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Prepare config packet failed in HW layer", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto free_req; + } + req->num_hw_update_entries = cfg.num_hw_update_entries; + req->num_out_map_entries = cfg.num_out_map_entries; + req->num_in_map_entries = cfg.num_in_map_entries; + atomic_set(&req->num_in_acked, 0); + req->request_id = packet->header.request_id; + req->status = 1; + req->req_priv = cfg.priv; + + for (i = 0; i < req->num_out_map_entries; i++) { + rc = cam_sync_get_obj_ref(req->out_map_entries[i].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, "Can't get ref for sync %d", + req->out_map_entries[i].sync_id); + goto put_ref; + } + } + + if (req->num_in_map_entries > 0) { + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->pending_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from free_list to pending_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + for (j = 0; j < req->num_in_map_entries; j++) { + cam_context_getref(ctx); + rc = cam_sync_register_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[j].sync_id); + if (rc) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Failed register fence cb: %d ret = %d", + ctx->dev_name, ctx->ctx_id, + req->in_map_entries[j].sync_id, rc); + spin_lock(&ctx->lock); + list_del_init(&req->list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from pending_list to free_list", + ctx->dev_name, ctx->ctx_id, + req->request_id); + + goto put_ctx_ref; + } + CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", + req->in_map_entries[j].sync_id, rc); + } + } + + return rc; +put_ctx_ref: + for (; j >= 0; j--) + cam_context_putref(ctx); +put_ref: + for (--i; i >= 0; i--) { + if (cam_sync_put_obj_ref(req->out_map_entries[i].sync_id)) + CAM_ERR(CAM_CTXT, "Failed to put ref of fence %d", + req->out_map_entries[i].sync_id); + } +free_req: + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + req->ctx = NULL; + spin_unlock(&ctx->lock); + + return rc; +} + +int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + struct cam_hw_acquire_args param; + struct cam_create_dev_hdl req_hdl_param; + struct cam_hw_release_args release; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_CTXT, "ses hdl: %x, num_res: %d, type: %d, res: %lld", + cmd->session_handle, cmd->num_resources, cmd->handle_type, + cmd->resource_hdl); + + if (cmd->num_resources > CAM_CTX_RES_MAX) { + CAM_ERR(CAM_CTXT, "[%s][%d] resource limit exceeded", + ctx->dev_name, ctx->ctx_id); + rc = -ENOMEM; + goto end; + } + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_CTXT, "[%s][%d] Only user pointer is supported", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + goto end; + } + + /* fill in parameters */ + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = cmd->num_resources; + param.acquire_info = cmd->resource_hdl; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_CTXT, "[%s][%d] Acquire device failed", + ctx->dev_name, ctx->ctx_id); + goto end; + } + + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + /* if hw resource acquire successful, acquire dev handle */ + req_hdl_param.session_hdl = cmd->session_handle; + /* bridge is not ready for these flags. so false for now */ + req_hdl_param.v4l2_sub_dev_flag = 0; + req_hdl_param.media_entity_flag = 0; + req_hdl_param.priv = ctx; + req_hdl_param.ops = ctx->crm_ctx_intf; + + ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); + if (ctx->dev_hdl <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_CTXT, "[%s][%d] Can not create device handle", + ctx->dev_name, ctx->ctx_id); + goto free_hw; + } + cmd->dev_handle = ctx->dev_hdl; + + /* store session information */ + ctx->session_hdl = cmd->session_handle; + + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); + ctx->ctxt_to_hw_map = NULL; + ctx->dev_hdl = -1; +end: + return rc; +} + +int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) +{ + struct cam_hw_flush_args flush_args; + struct list_head temp_list; + struct cam_ctx_request *req; + uint32_t i; + int rc = 0; + bool free_req; + + CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name); + memset(&flush_args, 0, sizeof(flush_args)); + + /* + * flush pending requests, take the sync lock to synchronize with the + * sync callback thread so that the sync cb thread does not try to + * submit request to h/w while the request is being flushed + */ + mutex_lock(&ctx->sync_mutex); + INIT_LIST_HEAD(&temp_list); + spin_lock(&ctx->lock); + list_splice_init(&ctx->pending_req_list, &temp_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving all pending requests from pending_list to temp_list", + ctx->dev_name, ctx->ctx_id); + + flush_args.num_req_pending = 0; + flush_args.last_flush_req = ctx->last_flush_req; + while (true) { + spin_lock(&ctx->lock); + if (list_empty(&temp_list)) { + spin_unlock(&ctx->lock); + break; + } + + req = list_first_entry(&temp_list, + struct cam_ctx_request, list); + + list_del_init(&req->list); + spin_unlock(&ctx->lock); + req->flushed = 1; + + flush_args.flush_req_pending[flush_args.num_req_pending++] = + req->req_priv; + + free_req = false; + for (i = 0; i < req->num_in_map_entries; i++) { + rc = cam_sync_deregister_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[i].sync_id); + if (!rc) { + cam_context_putref(ctx); + if (atomic_inc_return(&req->num_in_acked) == + req->num_in_map_entries) + free_req = true; + } + } + + for (i = 0; i < req->num_out_map_entries; i++) { + if (req->out_map_entries[i].sync_id != -1) { + rc = cam_sync_signal( + req->out_map_entries[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc == -EALREADY) { + CAM_ERR(CAM_CTXT, + "Req: %llu already signalled, sync_id:%d", + req->request_id, + req->out_map_entries[i].sync_id); + break; + } + } + } + + /* + * If we have deregistered the last sync callback, req will + * not be put on the free list. So put it on the free list here + */ + if (free_req) { + req->ctx = NULL; + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + } + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Deleting req[%llu] from temp_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + } + mutex_unlock(&ctx->sync_mutex); + + if (ctx->hw_mgr_intf->hw_flush) { + flush_args.num_req_active = 0; + spin_lock(&ctx->lock); + list_for_each_entry(req, &ctx->active_req_list, list) { + flush_args.flush_req_active[flush_args.num_req_active++] + = req->req_priv; + } + spin_unlock(&ctx->lock); + + if (flush_args.num_req_pending || flush_args.num_req_active) { + flush_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + flush_args.flush_type = CAM_FLUSH_TYPE_ALL; + ctx->hw_mgr_intf->hw_flush( + ctx->hw_mgr_intf->hw_mgr_priv, &flush_args); + } + } + + INIT_LIST_HEAD(&temp_list); + spin_lock(&ctx->lock); + list_splice_init(&ctx->active_req_list, &temp_list); + INIT_LIST_HEAD(&ctx->active_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving all requests from active_list to temp_list", + ctx->dev_name, ctx->ctx_id); + + while (true) { + spin_lock(&ctx->lock); + if (list_empty(&temp_list)) { + spin_unlock(&ctx->lock); + break; + } + req = list_first_entry(&temp_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + spin_unlock(&ctx->lock); + + for (i = 0; i < req->num_out_map_entries; i++) { + if (req->out_map_entries[i].sync_id != -1) { + rc = cam_sync_signal( + req->out_map_entries[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc == -EALREADY) { + CAM_ERR(CAM_CTXT, + "Req: %llu already signalled ctx: %pK dev_name: %s dev_handle: %d ctx_state: %d", + req->request_id, req->ctx, + req->ctx->dev_name, + req->ctx->dev_hdl, + req->ctx->state); + break; + } + } + } + + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + req->ctx = NULL; + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from temp_list to free_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + } + + CAM_DBG(CAM_CTXT, "[%s] X: NRT flush ctx", ctx->dev_name); + + return 0; +} + +int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + struct cam_ctx_request *req = NULL; + struct cam_hw_flush_args flush_args; + uint32_t i; + int32_t sync_id = 0; + int rc = 0; + bool free_req = false; + + CAM_DBG(CAM_CTXT, "[%s] E: NRT flush req", ctx->dev_name); + + memset(&flush_args, 0, sizeof(flush_args)); + flush_args.num_req_pending = 0; + flush_args.num_req_active = 0; + mutex_lock(&ctx->sync_mutex); + spin_lock(&ctx->lock); + list_for_each_entry(req, &ctx->pending_req_list, list) { + if (req->request_id != cmd->req_id) + continue; + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Deleting req[%llu] from pending_list", + ctx->dev_name, ctx->ctx_id, req->request_id); + + list_del_init(&req->list); + req->flushed = 1; + + flush_args.flush_req_pending[flush_args.num_req_pending++] = + req->req_priv; + break; + } + spin_unlock(&ctx->lock); + mutex_unlock(&ctx->sync_mutex); + + if (ctx->hw_mgr_intf->hw_flush) { + if (!flush_args.num_req_pending) { + spin_lock(&ctx->lock); + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id != cmd->req_id) + continue; + + list_del_init(&req->list); + + flush_args.flush_req_active[ + flush_args.num_req_active++] = + req->req_priv; + break; + } + spin_unlock(&ctx->lock); + } + + if (flush_args.num_req_pending || flush_args.num_req_active) { + flush_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + flush_args.flush_type = CAM_FLUSH_TYPE_REQ; + ctx->hw_mgr_intf->hw_flush( + ctx->hw_mgr_intf->hw_mgr_priv, &flush_args); + } + } + + if (req) { + if (flush_args.num_req_pending) { + for (i = 0; i < req->num_in_map_entries; i++) { + rc = cam_sync_deregister_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[i].sync_id); + if (rc) + continue; + + cam_context_putref(ctx); + if (atomic_inc_return(&req->num_in_acked) == + req->num_in_map_entries) + free_req = true; + } + } + + if (flush_args.num_req_pending || flush_args.num_req_active) { + for (i = 0; i < req->num_out_map_entries; i++) { + sync_id = + req->out_map_entries[i].sync_id; + if (sync_id != -1) { + rc = cam_sync_signal(sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc == -EALREADY) { + CAM_ERR(CAM_CTXT, + "Req: %llu already signalled, sync_id:%d", + req->request_id, sync_id); + break; + } + } + } + if (flush_args.num_req_active || free_req) { + req->ctx = NULL; + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock(&ctx->lock); + + if (cam_debug_ctx_req_list & ctx->dev_id) + CAM_INFO(CAM_CTXT, + "[%s][%d] : Moving req[%llu] from %s to free_list", + ctx->dev_name, ctx->ctx_id, + req->request_id, + flush_args.num_req_active ? + "active_list" : + "pending_list"); + } + } + } + CAM_DBG(CAM_CTXT, "[%s] X: NRT flush req", ctx->dev_name); + + return 0; +} + +int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + + int rc = 0; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (cmd->flush_type == CAM_FLUSH_TYPE_ALL) { + ctx->last_flush_req = cmd->req_id; + rc = cam_context_flush_ctx_to_hw(ctx); + } else if (cmd->flush_type == CAM_FLUSH_TYPE_REQ) + rc = cam_context_flush_req_to_hw(ctx, cmd); + else { + rc = -EINVAL; + CAM_ERR(CAM_CORE, "[%s][%d] Invalid flush type %d", + ctx->dev_name, ctx->ctx_id, cmd->flush_type); + } + +end: + return rc; +} + +int32_t cam_context_start_dev_to_hw(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_start_args arg; + + if (!ctx || !cmd) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if ((cmd->session_handle != ctx->session_hdl) || + (cmd->dev_handle != ctx->dev_hdl)) { + CAM_ERR(CAM_CTXT, + "[%s][%d] Invalid session hdl[%d], dev_handle[%d]", + ctx->dev_name, ctx->ctx_id, + cmd->session_handle, cmd->dev_handle); + rc = -EPERM; + goto end; + } + + if (ctx->hw_mgr_intf->hw_start) { + arg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &arg); + if (rc) { + /* HW failure. user need to clean up the resource */ + CAM_ERR(CAM_CTXT, "[%s][%d] Start HW failed", + ctx->dev_name, ctx->ctx_id); + goto end; + } + } + +end: + return rc; +} + +int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_stop_args stop; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input param"); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + rc = cam_context_validate_thread(); + if (rc) + goto end; + + rc = cam_context_flush_ctx_to_hw(ctx); + if (rc) + goto end; + + /* stop hw first */ + if (ctx->hw_mgr_intf->hw_stop) { + stop.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop); + } + +end: + return rc; +} + +int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, + struct cam_packet *packet, unsigned long iova, uint32_t buf_info, + bool *mem_found) +{ + int rc = 0; + struct cam_hw_cmd_args cmd_args; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input params %pK ", ctx); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (ctx->hw_mgr_intf->hw_cmd) { + cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_PF_INFO; + cmd_args.u.pf_args.pf_data.packet = packet; + cmd_args.u.pf_args.iova = iova; + cmd_args.u.pf_args.buf_info = buf_info; + cmd_args.u.pf_args.mem_found = mem_found; + ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &cmd_args); + } + +end: + return rc; +} + +int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args cmd_args; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input params"); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (ctx->hw_mgr_intf->hw_cmd) { + cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_ACQ_INFO; + ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &cmd_args); + } + +end: + return rc; +} diff --git a/techpack/camera/drivers/cam_core/cam_context_utils.h b/techpack/camera/drivers/cam_core/cam_context_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..087fdbf3654484fc3898f818a6e6e423df921b51 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_context_utils.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CONTEXT_UTILS_H_ +#define _CAM_CONTEXT_UTILS_H_ + +#include <linux/types.h> + +int cam_context_buf_done_from_hw(struct cam_context *ctx, + void *done_event_data, uint32_t bubble_state); +int32_t cam_context_release_dev_to_hw(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd); +int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd); +int32_t cam_context_config_dev_to_hw( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd); +int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd); +int32_t cam_context_start_dev_to_hw(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); +int32_t cam_context_stop_dev_to_hw(struct cam_context *ctx); +int32_t cam_context_flush_dev_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); +int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx); +int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd); +int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, + struct cam_packet *packet, unsigned long iova, uint32_t buf_info, + bool *mem_found); +int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx); + +#endif /* _CAM_CONTEXT_UTILS_H_ */ diff --git a/techpack/camera/drivers/cam_core/cam_hw.h b/techpack/camera/drivers/cam_core/cam_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..8ee889fcffb93eb70e47e1e6e4508e7a09609a4c --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_hw.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_H_ +#define _CAM_HW_H_ + +#include "cam_soc_util.h" + +/* + * This file declares Enums, Structures and APIs to be used as template + * when writing any HW driver in the camera subsystem. + */ + +/* Hardware state enum */ +enum cam_hw_state { + CAM_HW_STATE_POWER_DOWN, + CAM_HW_STATE_POWER_UP, +}; + +/** + * struct cam_hw_info - Common hardware information + * + * @hw_mutex: Hardware mutex + * @hw_lock: Hardware spinlock + * @hw_complete: Hardware Completion + * @open_count: Count to track the HW enable from the client + * @hw_state: Hardware state + * @soc_info: Platform SOC properties for hardware + * @node_info: Private HW data related to nodes + * @core_info: Private HW data related to core logic + * + */ +struct cam_hw_info { + struct mutex hw_mutex; + spinlock_t hw_lock; + struct completion hw_complete; + uint32_t open_count; + enum cam_hw_state hw_state; + struct cam_hw_soc_info soc_info; + void *node_info; + void *core_info; +}; + +#endif /* _CAM_HW_H_ */ diff --git a/techpack/camera/drivers/cam_core/cam_hw_intf.h b/techpack/camera/drivers/cam_core/cam_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..63e88dd24aeab74c22f8c023cb9cfadeb01f4833 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_hw_intf.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_INTF_H_ +#define _CAM_HW_INTF_H_ + +#include <linux/types.h> + +/* + * This file declares Constants, Enums, Structures and APIs to be used as + * Interface between HW driver and HW Manager. + */ + +/** + * struct cam_hw_ops - Hardware layer interface functions + * + * @get_hw_caps: Function pointer for get hw caps + * @init: Function poniter for initialize hardware + * @deinit: Function pointer for deinitialize hardware + * @reset: Function pointer for reset hardware + * @reserve: Function pointer for reserve hardware + * @release: Function pointer for release hardware + * @start: Function pointer for start hardware + * @stop: Function pointer for stop hardware + * @read: Function pointer for read hardware registers + * @write: Function pointer for Write hardware registers + * @process_cmd: Function pointer for additional hardware controls + * @flush_cmd: Function pointer for flush requests + * + */ +struct cam_hw_ops { + int (*get_hw_caps)(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size); + int (*init)(void *hw_priv, + void *init_hw_args, uint32_t arg_size); + int (*deinit)(void *hw_priv, + void *init_hw_args, uint32_t arg_size); + int (*reset)(void *hw_priv, + void *reset_core_args, uint32_t arg_size); + int (*reserve)(void *hw_priv, + void *reserve_args, uint32_t arg_size); + int (*release)(void *hw_priv, + void *release_args, uint32_t arg_size); + int (*start)(void *hw_priv, + void *start_args, uint32_t arg_size); + int (*stop)(void *hw_priv, + void *stop_args, uint32_t arg_size); + int (*read)(void *hw_priv, + void *read_args, uint32_t arg_size); + int (*write)(void *hw_priv, + void *write_args, uint32_t arg_size); + int (*process_cmd)(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + int (*flush)(void *hw_priv, + void *flush_args, uint32_t arg_size); +}; + +/** + * struct cam_hw_intf - Common hardware node + * + * @hw_type: Hardware type + * @hw_idx: Hardware ID + * @hw_ops: Hardware interface function table + * @hw_priv: Private hardware node pointer + * + */ +struct cam_hw_intf { + uint32_t hw_type; + uint32_t hw_idx; + struct cam_hw_ops hw_ops; + void *hw_priv; +}; + +/* hardware event callback function type */ +typedef int (*cam_hw_mgr_event_cb_func)(void *priv, uint32_t evt_id, + void *evt_data); + +#endif /* _CAM_HW_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h b/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..fe074734f389abea708dd74e389c0f4108b92636 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h @@ -0,0 +1,381 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HW_MGR_INTF_H_ +#define _CAM_HW_MGR_INTF_H_ + +#include <linux/time.h> +#include <linux/types.h> +#include <media/cam_defs.h> +/* + * This file declares Constants, Enums, Structures and APIs to be used as + * Interface between HW Manager and Context. + */ + + +/* maximum context numbers */ +#define CAM_CTX_MAX 8 + +/* maximum buf done irqs */ +#define CAM_NUM_OUT_PER_COMP_IRQ_MAX 12 + +/* Maximum reg dump cmd buffer entries in a context */ +#define CAM_REG_DUMP_MAX_BUF_ENTRIES 10 + +/** + * enum cam_context_dump_id - + * context dump type + * + */ +enum cam_context_dump_id { + CAM_CTX_DUMP_TYPE_NONE, + CAM_CTX_DUMP_ACQ_INFO, + CAM_CTX_DUMP_TYPE_MAX, +}; + +/* hardware event callback function type */ +typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, + void *evt_data); + +/* hardware page fault callback function type */ +typedef int (*cam_hw_pagefault_cb_func)(void *context, unsigned long iova, + uint32_t buf_info); + +/* ctx dump callback function type */ +typedef int (*cam_ctx_info_dump_cb_func)(void *context, + enum cam_context_dump_id dump_id); + +/** + * struct cam_hw_update_entry - Entry for hardware config + * + * @handle: Memory handle for the configuration + * @offset: Memory offset + * @len: Size of the configuration + * @flags: Flags for the config entry(eg. DMI) + * @addr: Address of hardware update entry + * + */ +struct cam_hw_update_entry { + int handle; + uint32_t offset; + uint32_t len; + uint32_t flags; + uintptr_t addr; +}; + +/** + * struct cam_hw_fence_map_entry - Entry for the resource to sync id map + * + * @resrouce_handle: Resource port id for the buffer + * @sync_id: Sync id + * + */ +struct cam_hw_fence_map_entry { + uint32_t resource_handle; + int32_t sync_id; +}; + +/** + * struct cam_hw_done_event_data - Payload for hw done event + * + * @num_handles: number of handles in the event + * @resrouce_handle: list of the resource handle + * @timestamp: time stamp + * @request_id: request identifier + * + */ +struct cam_hw_done_event_data { + uint32_t num_handles; + uint32_t resource_handle[CAM_NUM_OUT_PER_COMP_IRQ_MAX]; + struct timeval timestamp; + uint64_t request_id; +}; + +/** + * struct cam_hw_acquire_args - Payload for acquire command + * + * @context_data: Context data pointer for the callback function + * @event_cb: Callback function array + * @num_acq: Total number of acquire in the payload + * @acquire_info: Acquired resource array pointer + * @ctxt_to_hw_map: HW context (returned) + * @acquired_hw_id: Acquired hardware mask + * @acquired_hw_path: Acquired path mask for an input + * if input splits into multiple paths, + * its updated per hardware + * valid_acquired_hw: Valid num of acquired hardware + * + */ +struct cam_hw_acquire_args { + void *context_data; + cam_hw_event_cb_func event_cb; + uint32_t num_acq; + uint32_t acquire_info_size; + uintptr_t acquire_info; + void *ctxt_to_hw_map; + + uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; + uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; + uint32_t valid_acquired_hw; +}; + +/** + * struct cam_hw_release_args - Payload for release command + * + * @ctxt_to_hw_map: HW context from the acquire + * @active_req: Active request flag + * + */ +struct cam_hw_release_args { + void *ctxt_to_hw_map; + bool active_req; +}; + +/** + * struct cam_hw_start_args - Payload for start command + * + * @ctxt_to_hw_map: HW context from the acquire + * @num_hw_update_entries: Number of Hardware configuration + * @hw_update_entries: Hardware configuration list + * + */ +struct cam_hw_start_args { + void *ctxt_to_hw_map; + uint32_t num_hw_update_entries; + struct cam_hw_update_entry *hw_update_entries; +}; + +/** + * struct cam_hw_stop_args - Payload for stop command + * + * @ctxt_to_hw_map: HW context from the acquire + * @args: Arguments to pass for stop + * + */ +struct cam_hw_stop_args { + void *ctxt_to_hw_map; + void *args; +}; + + +/** + * struct cam_hw_mgr_dump_pf_data - page fault debug data + * + * packet: pointer to packet + */ +struct cam_hw_mgr_dump_pf_data { + void *packet; +}; + +/** + * struct cam_hw_prepare_update_args - Payload for prepare command + * + * @packet: CSL packet from user mode driver + * @remain_len Remaining length of CPU buffer after config offset + * @ctxt_to_hw_map: HW context from the acquire + * @max_hw_update_entries: Maximum hardware update entries supported + * @hw_update_entries: Actual hardware update configuration (returned) + * @num_hw_update_entries: Number of actual hardware update entries (returned) + * @max_out_map_entries: Maximum output fence mapping supported + * @out_map_entries: Actual output fence mapping list (returned) + * @num_out_map_entries: Number of actual output fence mapping (returned) + * @max_in_map_entries: Maximum input fence mapping supported + * @in_map_entries: Actual input fence mapping list (returned) + * @num_in_map_entries: Number of acutal input fence mapping (returned) + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc + * @priv: Private pointer of hw update + * @pf_data: Debug data for page fault + * + */ +struct cam_hw_prepare_update_args { + struct cam_packet *packet; + size_t remain_len; + void *ctxt_to_hw_map; + uint32_t max_hw_update_entries; + struct cam_hw_update_entry *hw_update_entries; + uint32_t num_hw_update_entries; + uint32_t max_out_map_entries; + struct cam_hw_fence_map_entry *out_map_entries; + uint32_t num_out_map_entries; + uint32_t max_in_map_entries; + struct cam_hw_fence_map_entry *in_map_entries; + uint32_t num_in_map_entries; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; + void *priv; + struct cam_hw_mgr_dump_pf_data *pf_data; +}; + +/** + * struct cam_hw_stream_setttings - Payload for config stream command + * + * @packet: CSL packet from user mode driver + * @ctxt_to_hw_map: HW context from the acquire + * @priv: Private pointer of hw update + * + */ +struct cam_hw_stream_setttings { + struct cam_packet *packet; + void *ctxt_to_hw_map; + void *priv; +}; + +/** + * struct cam_hw_config_args - Payload for config command + * + * @ctxt_to_hw_map: HW context from the acquire + * @num_hw_update_entries: Number of hardware update entries + * @hw_update_entries: Hardware update list + * @out_map_entries: Out map info + * @num_out_map_entries: Number of out map entries + * @priv: Private pointer + * @request_id: Request ID + * @reapply True if reapplying after bubble + * + */ +struct cam_hw_config_args { + void *ctxt_to_hw_map; + uint32_t num_hw_update_entries; + struct cam_hw_update_entry *hw_update_entries; + struct cam_hw_fence_map_entry *out_map_entries; + uint32_t num_out_map_entries; + void *priv; + uint64_t request_id; + bool init_packet; + bool reapply; +}; + +/** + * struct cam_hw_flush_args - Flush arguments + * + * @ctxt_to_hw_map: HW context from the acquire + * @num_req_pending: Num request to flush, valid when flush type is REQ + * @flush_req_pending: Request pending pointers to flush + * @num_req_active: Num request to flush, valid when flush type is REQ + * @flush_req_active: Request active pointers to flush + * @flush_type: The flush type + * @last_flush_req: last flush req_id notified to hw_mgr for the + * given stream + * + */ +struct cam_hw_flush_args { + void *ctxt_to_hw_map; + uint32_t num_req_pending; + void *flush_req_pending[20]; + uint32_t num_req_active; + void *flush_req_active[20]; + enum flush_type_t flush_type; + uint32_t last_flush_req; +}; + +/** + * struct cam_hw_dump_pf_args - Payload for dump pf info command + * + * @pf_data: Debug data for page fault + * @iova: Page fault address + * @buf_info: Info about memory buffer where page + * fault occurred + * @mem_found: If fault memory found in current + * request + * + */ +struct cam_hw_dump_pf_args { + struct cam_hw_mgr_dump_pf_data pf_data; + unsigned long iova; + uint32_t buf_info; + bool *mem_found; +}; + +/** + * struct cam_hw_reset_args -hw reset arguments + * + * @ctxt_to_hw_map: HW context from the acquire + * + */ +struct cam_hw_reset_args { + void *ctxt_to_hw_map; +}; + +/* enum cam_hw_mgr_command - Hardware manager command type */ +enum cam_hw_mgr_command { + CAM_HW_MGR_CMD_INTERNAL, + CAM_HW_MGR_CMD_DUMP_PF_INFO, + CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH, + CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR, + CAM_HW_MGR_CMD_DUMP_ACQ_INFO, +}; + +/** + * struct cam_hw_cmd_args - Payload for hw manager command + * + * @ctxt_to_hw_map: HW context from the acquire + * @cmd_type HW command type + * @internal_args Arguments for internal command + * @pf_args Arguments for Dump PF info command + * + */ +struct cam_hw_cmd_args { + void *ctxt_to_hw_map; + uint32_t cmd_type; + union { + void *internal_args; + struct cam_hw_dump_pf_args pf_args; + } u; +}; + +/** + * cam_hw_mgr_intf - HW manager interface + * + * @hw_mgr_priv: HW manager object + * @hw_get_caps: Function pointer for get hw caps + * args = cam_query_cap_cmd + * @hw_acquire: Function poniter for acquire hw resources + * args = cam_hw_acquire_args + * @hw_release: Function pointer for release hw device resource + * args = cam_hw_release_args + * @hw_start: Function pointer for start hw devices + * args = cam_hw_start_args + * @hw_stop: Function pointer for stop hw devices + * args = cam_hw_stop_args + * @hw_prepare_update: Function pointer for prepare hw update for hw + * devices args = cam_hw_prepare_update_args + * @hw_config_stream_settings: Function pointer for configure stream for hw + * devices args = cam_hw_stream_setttings + * @hw_config: Function pointer for configure hw devices + * args = cam_hw_config_args + * @hw_read: Function pointer for read hardware registers + * @hw_write: Function pointer for Write hardware registers + * @hw_cmd: Function pointer for any customized commands for + * the hardware manager + * @hw_open: Function pointer for HW init + * @hw_close: Function pointer for HW deinit + * @hw_flush: Function pointer for HW flush + * @hw_reset: Function pointer for HW reset + * + */ +struct cam_hw_mgr_intf { + void *hw_mgr_priv; + + int (*hw_get_caps)(void *hw_priv, void *hw_caps_args); + int (*hw_acquire)(void *hw_priv, void *hw_acquire_args); + int (*hw_release)(void *hw_priv, void *hw_release_args); + int (*hw_start)(void *hw_priv, void *hw_start_args); + int (*hw_stop)(void *hw_priv, void *hw_stop_args); + int (*hw_prepare_update)(void *hw_priv, void *hw_prepare_update_args); + int (*hw_config_stream_settings)(void *hw_priv, + void *hw_stream_settings); + int (*hw_config)(void *hw_priv, void *hw_config_args); + int (*hw_read)(void *hw_priv, void *read_args); + int (*hw_write)(void *hw_priv, void *write_args); + int (*hw_cmd)(void *hw_priv, void *write_args); + int (*hw_open)(void *hw_priv, void *fw_download_args); + int (*hw_close)(void *hw_priv, void *hw_close_args); + int (*hw_flush)(void *hw_priv, void *hw_flush_args); + int (*hw_reset)(void *hw_priv, void *hw_reset_args); +}; + +#endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_core/cam_node.c b/techpack/camera/drivers/cam_core/cam_node.c new file mode 100644 index 0000000000000000000000000000000000000000..4fefa2f35db31f879a4a5597e7b2904b5c780095 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_node.c @@ -0,0 +1,886 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> + +#include "cam_node.h" +#include "cam_trace.h" +#include "cam_debug_util.h" + +static void cam_node_print_ctx_state( + struct cam_node *node) +{ + int i; + struct cam_context *ctx; + + CAM_INFO(CAM_CORE, "[%s] state=%d, ctx_size %d", + node->name, node->state, node->ctx_size); + + mutex_lock(&node->list_mutex); + for (i = 0; i < node->ctx_size; i++) { + ctx = &node->ctx_list[i]; + + spin_lock_bh(&ctx->lock); + CAM_INFO(CAM_CORE, + "[%s][%d] : state=%d, refcount=%d, active_req_list=%d, pending_req_list=%d, wait_req_list=%d, free_req_list=%d", + ctx->dev_name, + i, ctx->state, + atomic_read(&(ctx->refcount.refcount.refs)), + list_empty(&ctx->active_req_list), + list_empty(&ctx->pending_req_list), + list_empty(&ctx->wait_req_list), + list_empty(&ctx->free_req_list)); + spin_unlock_bh(&ctx->lock); + } + mutex_unlock(&node->list_mutex); +} + +static struct cam_context *cam_node_get_ctxt_from_free_list( + struct cam_node *node) +{ + struct cam_context *ctx = NULL; + + mutex_lock(&node->list_mutex); + if (!list_empty(&node->free_ctx_list)) { + ctx = list_first_entry(&node->free_ctx_list, + struct cam_context, list); + list_del_init(&ctx->list); + } + mutex_unlock(&node->list_mutex); + if (ctx) + kref_init(&ctx->refcount); + return ctx; +} + +void cam_node_put_ctxt_to_free_list(struct kref *ref) +{ + struct cam_context *ctx = + container_of(ref, struct cam_context, refcount); + struct cam_node *node = ctx->node; + + mutex_lock(&node->list_mutex); + list_add_tail(&ctx->list, &node->free_ctx_list); + mutex_unlock(&node->list_mutex); +} + +static int __cam_node_handle_query_cap(struct cam_node *node, + struct cam_query_cap_cmd *query) +{ + int rc = -EFAULT; + + if (!query) { + CAM_ERR(CAM_CORE, "Invalid params"); + return -EINVAL; + } + + if (node->hw_mgr_intf.hw_get_caps) { + rc = node->hw_mgr_intf.hw_get_caps( + node->hw_mgr_intf.hw_mgr_priv, query); + } + + return rc; +} + +static int __cam_node_handle_acquire_dev(struct cam_node *node, + struct cam_acquire_dev_cmd *acquire) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!acquire) + return -EINVAL; + + ctx = cam_node_get_ctxt_from_free_list(node); + if (!ctx) { + CAM_ERR(CAM_CORE, "No free ctx in free list node %s", + node->name); + cam_node_print_ctx_state(node); + + rc = -ENOMEM; + goto err; + } + + ctx->last_flush_req = 0; + rc = cam_context_handle_acquire_dev(ctx, acquire); + if (rc) { + CAM_ERR(CAM_CORE, "Acquire device failed for node %s", + node->name); + goto free_ctx; + } + + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + + return 0; +free_ctx: + cam_context_putref(ctx); +err: + return rc; +} + +static void __cam_node_handle_acquired_hw_dump( + struct cam_node *node) +{ + int i; + + for (i = 0; i < node->ctx_size; i++) + cam_context_handle_info_dump(&(node->ctx_list[i]), + CAM_CTX_DUMP_ACQ_INFO); +} + +static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, + struct cam_acquire_hw_cmd_v1 *acquire) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!acquire) + return -EINVAL; + + if (acquire->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (acquire->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(acquire->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + acquire->dev_handle); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + rc = cam_context_handle_acquire_hw(ctx, acquire); + if (rc) { + CAM_ERR(CAM_CORE, "Acquire device failed for node %s", + node->name); + __cam_node_handle_acquired_hw_dump(node); + return rc; + } + + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + + return 0; +} + +static int __cam_node_handle_acquire_hw_v2(struct cam_node *node, + struct cam_acquire_hw_cmd_v2 *acquire) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!acquire) + return -EINVAL; + + if (acquire->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (acquire->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(acquire->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + acquire->dev_handle); + return -EINVAL; + } + + rc = cam_context_handle_acquire_hw(ctx, acquire); + if (rc) { + CAM_ERR(CAM_CORE, "Acquire device failed for node %s", + node->name); + __cam_node_handle_acquired_hw_dump(node); + return rc; + } + + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + + return 0; +} + +static int __cam_node_handle_start_dev(struct cam_node *node, + struct cam_start_stop_dev_cmd *start) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!start) + return -EINVAL; + + if (start->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (start->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(start->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + start->dev_handle); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + rc = cam_context_handle_start_dev(ctx, start); + if (rc) + CAM_ERR(CAM_CORE, "Start failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_stop_dev(struct cam_node *node, + struct cam_start_stop_dev_cmd *stop) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!stop) + return -EINVAL; + + if (stop->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (stop->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(stop->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + stop->dev_handle); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + rc = cam_context_handle_stop_dev(ctx, stop); + if (rc) + CAM_ERR(CAM_CORE, "Stop failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_config_dev(struct cam_node *node, + struct cam_config_dev_cmd *config) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!config) + return -EINVAL; + + if (config->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (config->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(config->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + config->dev_handle); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + rc = cam_context_handle_config_dev(ctx, config); + if (rc) + CAM_ERR(CAM_CORE, "Config failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_flush_dev(struct cam_node *node, + struct cam_flush_dev_cmd *flush) +{ + struct cam_context *ctx = NULL; + int rc; + + if (!flush) + return -EINVAL; + + if (flush->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (flush->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(flush->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + flush->dev_handle); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + rc = cam_context_handle_flush_dev(ctx, flush); + if (rc) + CAM_ERR(CAM_CORE, "Flush failure for node %s", node->name); + + return rc; +} + +static int __cam_node_handle_release_dev(struct cam_node *node, + struct cam_release_dev_cmd *release) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!release) + return -EINVAL; + + if (release->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (release->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(release->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d node %s", + release->dev_handle, node->name); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + if (ctx->state > CAM_CTX_UNINIT && ctx->state < CAM_CTX_STATE_MAX) { + rc = cam_context_handle_release_dev(ctx, release); + if (rc) + CAM_ERR(CAM_CORE, "context release failed for node %s", + node->name); + } else { + CAM_WARN(CAM_CORE, + "node %s context id %u state %d invalid to release hdl", + node->name, ctx->ctx_id, ctx->state); + goto destroy_dev_hdl; + } + + cam_context_putref(ctx); + +destroy_dev_hdl: + rc = cam_destroy_device_hdl(release->dev_handle); + if (rc) + CAM_ERR(CAM_CORE, "destroy device hdl failed for node %s", + node->name); + else + ctx->dev_hdl = -1; + + CAM_DBG(CAM_CORE, "[%s] Release ctx_id=%d, refcount=%d", + node->name, ctx->ctx_id, + atomic_read(&(ctx->refcount.refcount.refs))); + + return rc; +} + +static int __cam_node_handle_release_hw_v1(struct cam_node *node, + struct cam_release_hw_cmd_v1 *release) +{ + int rc = 0; + struct cam_context *ctx = NULL; + + if (!release) + return -EINVAL; + + if (release->dev_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid device handle for context"); + return -EINVAL; + } + + if (release->session_handle <= 0) { + CAM_ERR(CAM_CORE, "Invalid session handle for context"); + return -EINVAL; + } + + ctx = (struct cam_context *)cam_get_device_priv(release->dev_handle); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d node %s", + release->dev_handle, node->name); + return -EINVAL; + } + + if (strcmp(node->name, ctx->dev_name)) { + CAM_ERR(CAM_CORE, "node name %s dev name:%s not matching", + node->name, ctx->dev_name); + return -EINVAL; + } + + rc = cam_context_handle_release_hw(ctx, release); + if (rc) + CAM_ERR(CAM_CORE, "context release failed node %s", node->name); + + CAM_DBG(CAM_CORE, "[%s] Release ctx_id=%d, refcount=%d", + node->name, ctx->ctx_id, + atomic_read(&(ctx->refcount.refcount.refs))); + + return rc; +} + +static int __cam_node_crm_get_dev_info(struct cam_req_mgr_device_info *info) +{ + struct cam_context *ctx = NULL; + + if (!info) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(info->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + info->dev_hdl); + return -EINVAL; + } + return cam_context_handle_crm_get_dev_info(ctx, info); +} + +static int __cam_node_crm_link_setup( + struct cam_req_mgr_core_dev_link_setup *setup) +{ + int rc; + struct cam_context *ctx = NULL; + + if (!setup) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(setup->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + setup->dev_hdl); + return -EINVAL; + } + + if (setup->link_enable) + rc = cam_context_handle_crm_link(ctx, setup); + else + rc = cam_context_handle_crm_unlink(ctx, setup); + + return rc; +} + +static int __cam_node_crm_apply_req(struct cam_req_mgr_apply_request *apply) +{ + struct cam_context *ctx = NULL; + + if (!apply) + return -EINVAL; + + ctx = (struct cam_context *) cam_get_device_priv(apply->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + apply->dev_hdl); + return -EINVAL; + } + + trace_cam_apply_req("Node", apply->request_id); + + return cam_context_handle_crm_apply_req(ctx, apply); +} + +static int __cam_node_crm_flush_req(struct cam_req_mgr_flush_request *flush) +{ + struct cam_context *ctx = NULL; + + if (!flush) { + CAM_ERR(CAM_CORE, "Invalid flush request payload"); + return -EINVAL; + } + + ctx = (struct cam_context *) cam_get_device_priv(flush->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + flush->dev_hdl); + return -EINVAL; + } + + return cam_context_handle_crm_flush_req(ctx, flush); +} + +static int __cam_node_crm_process_evt( + struct cam_req_mgr_link_evt_data *evt_data) +{ + struct cam_context *ctx = NULL; + + if (!evt_data) { + CAM_ERR(CAM_CORE, "Invalid process event request payload"); + return -EINVAL; + } + + ctx = (struct cam_context *) cam_get_device_priv(evt_data->dev_hdl); + if (!ctx) { + CAM_ERR(CAM_CORE, "Can not get context for handle %d", + evt_data->dev_hdl); + return -EINVAL; + } + return cam_context_handle_crm_process_evt(ctx, evt_data); +} + +int cam_node_deinit(struct cam_node *node) +{ + if (node) + memset(node, 0, sizeof(*node)); + + CAM_DBG(CAM_CORE, "deinit complete"); + + return 0; +} + +int cam_node_shutdown(struct cam_node *node) +{ + int i = 0; + int rc = 0; + + if (!node) + return -EINVAL; + + for (i = 0; i < node->ctx_size; i++) { + if (node->ctx_list[i].dev_hdl > 0) { + CAM_DBG(CAM_CORE, + "Node [%s] invoking shutdown on context [%d]", + node->name, i); + rc = cam_context_shutdown(&(node->ctx_list[i])); + } + } + + if (node->hw_mgr_intf.hw_close) + node->hw_mgr_intf.hw_close(node->hw_mgr_intf.hw_mgr_priv, + NULL); + + return 0; +} + +int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, + struct cam_context *ctx_list, uint32_t ctx_size, char *name) +{ + int rc = 0; + int i; + + if (!node || !hw_mgr_intf || + sizeof(node->hw_mgr_intf) != sizeof(*hw_mgr_intf)) { + return -EINVAL; + } + + memset(node, 0, sizeof(*node)); + + strlcpy(node->name, name, sizeof(node->name)); + + memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf)); + node->crm_node_intf.apply_req = __cam_node_crm_apply_req; + node->crm_node_intf.get_dev_info = __cam_node_crm_get_dev_info; + node->crm_node_intf.link_setup = __cam_node_crm_link_setup; + node->crm_node_intf.flush_req = __cam_node_crm_flush_req; + node->crm_node_intf.process_evt = __cam_node_crm_process_evt; + + mutex_init(&node->list_mutex); + INIT_LIST_HEAD(&node->free_ctx_list); + node->ctx_list = ctx_list; + node->ctx_size = ctx_size; + for (i = 0; i < ctx_size; i++) { + if (!ctx_list[i].state_machine) { + CAM_ERR(CAM_CORE, + "camera context %d is not initialized", i); + rc = -1; + goto err; + } + INIT_LIST_HEAD(&ctx_list[i].list); + list_add_tail(&ctx_list[i].list, &node->free_ctx_list); + ctx_list[i].node = node; + } + + node->state = CAM_NODE_STATE_INIT; +err: + CAM_DBG(CAM_CORE, "Exit. (rc = %d)", rc); + return rc; +} + +int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) +{ + int rc = 0; + + if (!cmd) + return -EINVAL; + + CAM_DBG(CAM_CORE, "handle cmd %d", cmd->op_code); + + switch (cmd->op_code) { + case CAM_QUERY_CAP: { + struct cam_query_cap_cmd query; + + if (copy_from_user(&query, u64_to_user_ptr(cmd->handle), + sizeof(query))) { + rc = -EFAULT; + break; + } + + rc = __cam_node_handle_query_cap(node, &query); + if (rc) { + CAM_ERR(CAM_CORE, "querycap is failed(rc = %d)", + rc); + break; + } + + if (copy_to_user(u64_to_user_ptr(cmd->handle), &query, + sizeof(query))) + rc = -EFAULT; + + break; + } + case CAM_ACQUIRE_DEV: { + struct cam_acquire_dev_cmd acquire; + + if (copy_from_user(&acquire, u64_to_user_ptr(cmd->handle), + sizeof(acquire))) { + rc = -EFAULT; + break; + } + rc = __cam_node_handle_acquire_dev(node, &acquire); + if (rc) { + CAM_ERR(CAM_CORE, "acquire device failed(rc = %d)", + rc); + break; + } + if (copy_to_user(u64_to_user_ptr(cmd->handle), &acquire, + sizeof(acquire))) + rc = -EFAULT; + break; + } + case CAM_ACQUIRE_HW: { + uint32_t api_version; + void *acquire_ptr = NULL; + size_t acquire_size; + + if (copy_from_user(&api_version, (void __user *)cmd->handle, + sizeof(api_version))) { + rc = -EFAULT; + break; + } + + if (api_version == 1) { + acquire_size = sizeof(struct cam_acquire_hw_cmd_v1); + } else if (api_version == 2) { + acquire_size = sizeof(struct cam_acquire_hw_cmd_v2); + } else { + CAM_ERR(CAM_CORE, "Unsupported api version %d", + api_version); + rc = -EINVAL; + break; + } + + acquire_ptr = kzalloc(acquire_size, GFP_KERNEL); + if (!acquire_ptr) { + CAM_ERR(CAM_CORE, "No memory for acquire HW"); + rc = -ENOMEM; + break; + } + + if (copy_from_user(acquire_ptr, (void __user *)cmd->handle, + acquire_size)) { + rc = -EFAULT; + goto acquire_kfree; + } + + if (api_version == 1) { + rc = __cam_node_handle_acquire_hw_v1(node, acquire_ptr); + if (rc) { + CAM_ERR(CAM_CORE, + "acquire device failed(rc = %d)", rc); + goto acquire_kfree; + } + } else if (api_version == 2) { + rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr); + if (rc) { + CAM_ERR(CAM_CORE, + "acquire device failed(rc = %d)", rc); + goto acquire_kfree; + } + } + + if (copy_to_user((void __user *)cmd->handle, acquire_ptr, + acquire_size)) + rc = -EFAULT; + +acquire_kfree: + kfree(acquire_ptr); + break; + } + case CAM_START_DEV: { + struct cam_start_stop_dev_cmd start; + + if (copy_from_user(&start, u64_to_user_ptr(cmd->handle), + sizeof(start))) + rc = -EFAULT; + else { + rc = __cam_node_handle_start_dev(node, &start); + if (rc) + CAM_ERR(CAM_CORE, + "start device failed(rc = %d)", rc); + } + break; + } + case CAM_STOP_DEV: { + struct cam_start_stop_dev_cmd stop; + + if (copy_from_user(&stop, u64_to_user_ptr(cmd->handle), + sizeof(stop))) + rc = -EFAULT; + else { + rc = __cam_node_handle_stop_dev(node, &stop); + if (rc) + CAM_ERR(CAM_CORE, + "stop device failed(rc = %d)", rc); + } + break; + } + case CAM_CONFIG_DEV: { + struct cam_config_dev_cmd config; + + if (copy_from_user(&config, u64_to_user_ptr(cmd->handle), + sizeof(config))) + rc = -EFAULT; + else { + rc = __cam_node_handle_config_dev(node, &config); + if (rc) + CAM_ERR(CAM_CORE, + "config device failed(rc = %d)", rc); + } + break; + } + case CAM_RELEASE_DEV: { + struct cam_release_dev_cmd release; + + if (copy_from_user(&release, u64_to_user_ptr(cmd->handle), + sizeof(release))) + rc = -EFAULT; + else { + rc = __cam_node_handle_release_dev(node, &release); + if (rc) + CAM_ERR(CAM_CORE, + "release device failed(rc = %d)", rc); + } + break; + } + case CAM_RELEASE_HW: { + uint32_t api_version; + size_t release_size; + void *release_ptr = NULL; + + if (copy_from_user(&api_version, (void __user *)cmd->handle, + sizeof(api_version))) { + rc = -EFAULT; + break; + } + + if (api_version == 1) { + release_size = sizeof(struct cam_release_hw_cmd_v1); + } else { + CAM_ERR(CAM_CORE, "Unsupported api version %d", + api_version); + rc = -EINVAL; + break; + } + + release_ptr = kzalloc(release_size, GFP_KERNEL); + if (!release_ptr) { + CAM_ERR(CAM_CORE, "No memory for release HW"); + rc = -ENOMEM; + break; + } + + if (copy_from_user(release_ptr, (void __user *)cmd->handle, + release_size)) { + rc = -EFAULT; + goto release_kfree; + } + + if (api_version == 1) { + rc = __cam_node_handle_release_hw_v1(node, release_ptr); + if (rc) + CAM_ERR(CAM_CORE, + "release device failed(rc = %d)", rc); + } + +release_kfree: + kfree(release_ptr); + break; + } + case CAM_FLUSH_REQ: { + struct cam_flush_dev_cmd flush; + + if (copy_from_user(&flush, u64_to_user_ptr(cmd->handle), + sizeof(flush))) + rc = -EFAULT; + else { + rc = __cam_node_handle_flush_dev(node, &flush); + if (rc) + CAM_ERR(CAM_CORE, + "flush device failed(rc = %d)", rc); + } + break; + } + default: + CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code); + rc = -EINVAL; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_core/cam_node.h b/techpack/camera/drivers/cam_core/cam_node.h new file mode 100644 index 0000000000000000000000000000000000000000..062d0213115c94fd888067f717b49de949908db0 --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_node.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_NODE_H_ +#define _CAM_NODE_H_ + +#include <linux/kref.h> +#include "cam_context.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + + +#define CAM_NODE_STATE_UNINIT 0 +#define CAM_NODE_STATE_INIT 1 + +/** + * struct cam_node - Singleton Node for camera HW devices + * + * @name: Name for struct cam_node + * @state: Node state: + * 0 = uninitialized, 1 = initialized + * @list_mutex: Mutex for the context pool + * @free_ctx_list: Free context pool list + * @ctx_list: Context list + * @ctx_size: Context list size + * @hw_mgr_intf: Interface for cam_node to HW + * @crm_node_intf: Interface for the CRM to cam_node + * + */ +struct cam_node { + char name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + uint32_t state; + + /* context pool */ + struct mutex list_mutex; + struct list_head free_ctx_list; + struct cam_context *ctx_list; + uint32_t ctx_size; + + /* interfaces */ + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_req_mgr_kmd_ops crm_node_intf; +}; + +/** + * cam_node_handle_ioctl() + * + * @brief: Handle ioctl commands + * + * @node: Node handle + * @cmd: IOCTL command + * + */ +int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd); + +/** + * cam_node_deinit() + * + * @brief: Deinitialization function for the Node interface + * + * @node: Node handle + * + */ +int cam_node_deinit(struct cam_node *node); + +/** + * cam_node_shutdown() + * + * @brief: Shutdowns/Closes the cam node. + * + * @node: Cam_node pointer + * + */ +int cam_node_shutdown(struct cam_node *node); + +/** + * cam_node_init() + * + * @brief: Initialization function for the Node interface. + * + * @node: Cam_node pointer + * @hw_mgr_intf: HW manager interface blob + * @ctx_list: List of cam_contexts to be added + * @ctx_size: Size of the cam_context + * @name: Name for the node + * + */ +int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf, + struct cam_context *ctx_list, uint32_t ctx_size, char *name); + +/** + * cam_node_put_ctxt_to_free_list() + * + * @brief: Put context in node free list. + * + * @ref: Context's kref object + * + */ +void cam_node_put_ctxt_to_free_list(struct kref *ref); + +#endif /* _CAM_NODE_H_ */ diff --git a/techpack/camera/drivers/cam_core/cam_subdev.c b/techpack/camera/drivers/cam_core/cam_subdev.c new file mode 100644 index 0000000000000000000000000000000000000000..1a81a4d59e99a792459e73bb9bebe8af643b26ee --- /dev/null +++ b/techpack/camera/drivers/cam_core/cam_subdev.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_debug_util.h" + +/** + * cam_subdev_subscribe_event() + * + * @brief: function to subscribe to v4l2 events + * + * @sd: Pointer to struct v4l2_subdev. + * @fh: Pointer to struct v4l2_fh. + * @sub: Pointer to struct v4l2_event_subscription. + */ +static int cam_subdev_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, CAM_SUBDEVICE_EVENT_MAX, NULL); +} + +/** + * cam_subdev_unsubscribe_event() + * + * @brief: function to unsubscribe from v4l2 events + * + * @sd: Pointer to struct v4l2_subdev. + * @fh: Pointer to struct v4l2_fh. + * @sub: Pointer to struct v4l2_event_subscription. + */ +static int cam_subdev_unsubscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static long cam_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, + void *arg) +{ + long rc; + struct cam_node *node = + (struct cam_node *) v4l2_get_subdevdata(sd); + + if (!node || node->state == CAM_NODE_STATE_UNINIT) { + rc = -EINVAL; + goto end; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_node_handle_ioctl(node, + (struct cam_control *) arg); + break; + default: + CAM_ERR(CAM_CORE, "Invalid command %d for %s", cmd, + node->name); + rc = -EINVAL; + } +end: + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int rc; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_CORE, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + rc = cam_subdev_ioctl(sd, cmd, &cmd_data); + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_CORE, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +const struct v4l2_subdev_core_ops cam_subdev_core_ops = { + .ioctl = cam_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_subdev_compat_ioctl, +#endif + .subscribe_event = cam_subdev_subscribe_event, + .unsubscribe_event = cam_subdev_unsubscribe_event, +}; + +static const struct v4l2_subdev_ops cam_subdev_ops = { + .core = &cam_subdev_core_ops, +}; + +int cam_subdev_remove(struct cam_subdev *sd) +{ + if (!sd) + return -EINVAL; + + cam_unregister_subdev(sd); + cam_node_deinit((struct cam_node *)sd->token); + kfree(sd->token); + + return 0; +} + +int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev, + char *name, uint32_t dev_type) +{ + int rc; + struct cam_node *node = NULL; + + if (!sd || !pdev || !name) + return -EINVAL; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + + /* Setup camera v4l2 subdevice */ + sd->pdev = pdev; + sd->name = name; + sd->ops = &cam_subdev_ops; + sd->token = node; + sd->sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->ent_function = dev_type; + + rc = cam_register_subdev(sd); + if (rc) { + CAM_ERR(CAM_CORE, "cam_register_subdev() failed for dev: %s", + sd->name); + goto err; + } + platform_set_drvdata(sd->pdev, sd); + return rc; +err: + kfree(node); + return rc; +} diff --git a/techpack/camera/drivers/cam_cpas/Makefile b/techpack/camera/drivers/cam_cpas/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6fc8f9830cec63fb2d7f87ff69d9b0d69d41c2e9 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +#ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/cpas_top +#ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/camss_top +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree) + +obj-$(CONFIG_SPECTRA_CAMERA) += cpas_top/ +obj-$(CONFIG_SPECTRA_CAMERA) += camss_top/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpas_soc.o cam_cpas_intf.o cam_cpas_hw.o \ No newline at end of file diff --git a/techpack/camera/drivers/cam_cpas/cam_cpas_hw.c b/techpack/camera/drivers/cam_cpas/cam_cpas_hw.c new file mode 100644 index 0000000000000000000000000000000000000000..75e6c9c71e6586dea69fa85378e202c191a619be --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cam_cpas_hw.c @@ -0,0 +1,2094 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/msm-bus.h> +#include <linux/pm_opp.h> +#include <linux/slab.h> +#include <linux/module.h> + +#include "cam_cpas_hw.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_soc.h" + +static uint cam_min_camnoc_ib_bw; +module_param(cam_min_camnoc_ib_bw, uint, 0644); + + +int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, + enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + uint32_t value; + int reg_base_index; + + if (reg_info->enable == false) + return 0; + + reg_base_index = cpas_core->regbase_index[reg_base]; + if (reg_base_index == -1) + return -EINVAL; + + if (reg_info->masked_value) { + value = cam_io_r_mb( + soc_info->reg_map[reg_base_index].mem_base + + reg_info->offset); + value = value & (~reg_info->mask); + value = value | (reg_info->value << reg_info->shift); + } else { + value = reg_info->value; + } + + CAM_DBG(CAM_CPAS, "Base[%d] Offset[0x%08x] Value[0x%08x]", + reg_base, reg_info->offset, value); + + cam_io_w_mb(value, soc_info->reg_map[reg_base_index].mem_base + + reg_info->offset); + + return 0; +} + +static int cam_cpas_util_vote_bus_client_level( + struct cam_cpas_bus_client *bus_client, unsigned int level) +{ + if (!bus_client->valid || (bus_client->dyn_vote == true)) { + CAM_ERR(CAM_CPAS, "Invalid params %d %d", bus_client->valid, + bus_client->dyn_vote); + return -EINVAL; + } + + if (level >= bus_client->num_usecases) { + CAM_ERR(CAM_CPAS, "Invalid vote level=%d, usecases=%d", level, + bus_client->num_usecases); + return -EINVAL; + } + + if (level == bus_client->curr_vote_level) + return 0; + + CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] index[%d]", + bus_client->client_id, bus_client->name, level); + msm_bus_scale_client_update_request(bus_client->client_id, level); + bus_client->curr_vote_level = level; + + return 0; +} + +static int cam_cpas_util_vote_bus_client_bw( + struct cam_cpas_bus_client *bus_client, uint64_t ab, uint64_t ib, + bool camnoc_bw) +{ + struct msm_bus_paths *path; + struct msm_bus_scale_pdata *pdata; + int idx = 0; + uint64_t min_camnoc_ib_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + + if (cam_min_camnoc_ib_bw > 0) + min_camnoc_ib_bw = (uint64_t)cam_min_camnoc_ib_bw * 1000000L; + + CAM_DBG(CAM_CPAS, "cam_min_camnoc_ib_bw = %d, min_camnoc_ib_bw=%llu", + cam_min_camnoc_ib_bw, min_camnoc_ib_bw); + + if (!bus_client->valid) { + CAM_ERR(CAM_CPAS, "bus client not valid"); + return -EINVAL; + } + + if ((bus_client->num_usecases != 2) || + (bus_client->num_paths != 1) || + (bus_client->dyn_vote != true)) { + CAM_ERR(CAM_CPAS, "dynamic update not allowed %d %d %d", + bus_client->num_usecases, bus_client->num_paths, + bus_client->dyn_vote); + return -EINVAL; + } + + mutex_lock(&bus_client->lock); + + if (bus_client->curr_vote_level > 1) { + CAM_ERR(CAM_CPAS, "curr_vote_level %d cannot be greater than 1", + bus_client->curr_vote_level); + mutex_unlock(&bus_client->lock); + return -EINVAL; + } + + idx = bus_client->curr_vote_level; + idx = 1 - idx; + bus_client->curr_vote_level = idx; + mutex_unlock(&bus_client->lock); + + if (camnoc_bw == true) { + if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_CAMNOC_AB_BW)) + ab = CAM_CPAS_AXI_MIN_CAMNOC_AB_BW; + + if ((ib > 0) && (ib < min_camnoc_ib_bw)) + ib = min_camnoc_ib_bw; + } else { + if ((ab > 0) && (ab < CAM_CPAS_AXI_MIN_MNOC_AB_BW)) + ab = CAM_CPAS_AXI_MIN_MNOC_AB_BW; + + if ((ib > 0) && (ib < CAM_CPAS_AXI_MIN_MNOC_IB_BW)) + ib = CAM_CPAS_AXI_MIN_MNOC_IB_BW; + } + + pdata = bus_client->pdata; + path = &(pdata->usecase[idx]); + path->vectors[0].ab = ab; + path->vectors[0].ib = ib; + + CAM_DBG(CAM_CPAS, "Bus client=[%d][%s] :ab[%llu] ib[%llu], index[%d]", + bus_client->client_id, bus_client->name, ab, ib, idx); + msm_bus_scale_client_update_request(bus_client->client_id, idx); + + return 0; +} + +static int cam_cpas_util_register_bus_client( + struct cam_hw_soc_info *soc_info, struct device_node *dev_node, + struct cam_cpas_bus_client *bus_client) +{ + struct msm_bus_scale_pdata *pdata = NULL; + uint32_t client_id; + int rc; + + pdata = msm_bus_pdata_from_node(soc_info->pdev, + dev_node); + if (!pdata) { + CAM_ERR(CAM_CPAS, "failed get_pdata"); + return -EINVAL; + } + + if ((pdata->num_usecases == 0) || + (pdata->usecase[0].num_paths == 0)) { + CAM_ERR(CAM_CPAS, "usecase=%d", pdata->num_usecases); + rc = -EINVAL; + goto error; + } + + client_id = msm_bus_scale_register_client(pdata); + if (!client_id) { + CAM_ERR(CAM_CPAS, "failed in register ahb bus client"); + rc = -EINVAL; + goto error; + } + + bus_client->dyn_vote = of_property_read_bool(dev_node, + "qcom,msm-bus-vector-dyn-vote"); + + if (bus_client->dyn_vote && (pdata->num_usecases != 2)) { + CAM_ERR(CAM_CPAS, "Excess or less vectors %d", + pdata->num_usecases); + rc = -EINVAL; + goto fail_unregister_client; + } + + msm_bus_scale_client_update_request(client_id, 0); + + bus_client->src = pdata->usecase[0].vectors[0].src; + bus_client->dst = pdata->usecase[0].vectors[0].dst; + bus_client->pdata = pdata; + bus_client->client_id = client_id; + bus_client->num_usecases = pdata->num_usecases; + bus_client->num_paths = pdata->usecase[0].num_paths; + bus_client->curr_vote_level = 0; + bus_client->valid = true; + bus_client->name = pdata->name; + mutex_init(&bus_client->lock); + + CAM_DBG(CAM_CPAS, "Bus Client=[%d][%s] : src=%d, dst=%d", + bus_client->client_id, bus_client->name, + bus_client->src, bus_client->dst); + + return 0; +fail_unregister_client: + msm_bus_scale_unregister_client(bus_client->client_id); +error: + return rc; + +} + +static int cam_cpas_util_unregister_bus_client( + struct cam_cpas_bus_client *bus_client) +{ + if (!bus_client->valid) + return -EINVAL; + + if (bus_client->dyn_vote) + cam_cpas_util_vote_bus_client_bw(bus_client, 0, 0, false); + else + cam_cpas_util_vote_bus_client_level(bus_client, 0); + + msm_bus_scale_unregister_client(bus_client->client_id); + bus_client->valid = false; + + mutex_destroy(&bus_client->lock); + + return 0; +} + +static int cam_cpas_util_axi_cleanup(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info) +{ + int i = 0; + + if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", + cpas_core->num_axi_ports); + return -EINVAL; + } + + if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", + cpas_core->num_camnoc_axi_ports); + return -EINVAL; + } + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + cam_cpas_util_unregister_bus_client( + &cpas_core->axi_port[i].bus_client); + of_node_put(cpas_core->axi_port[i].axi_port_node); + cpas_core->axi_port[i].axi_port_node = NULL; + } + + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + cam_cpas_util_unregister_bus_client( + &cpas_core->camnoc_axi_port[i].bus_client); + of_node_put(cpas_core->camnoc_axi_port[i].axi_port_node); + cpas_core->camnoc_axi_port[i].axi_port_node = NULL; + } + + return 0; +} + +static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info) +{ + int i = 0, rc = 0; + struct device_node *axi_port_mnoc_node = NULL; + struct device_node *axi_port_camnoc_node = NULL; + + if (cpas_core->num_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_axi_ports: %d", + cpas_core->num_axi_ports); + return -EINVAL; + } + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + axi_port_mnoc_node = cpas_core->axi_port[i].axi_port_node; + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_mnoc_node, &cpas_core->axi_port[i].bus_client); + if (rc) + goto bus_register_fail; + } + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + axi_port_camnoc_node = + cpas_core->camnoc_axi_port[i].axi_port_node; + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_camnoc_node, + &cpas_core->camnoc_axi_port[i].bus_client); + if (rc) + goto bus_register_fail; + } + + return 0; +bus_register_fail: + of_node_put(cpas_core->axi_port[i].axi_port_node); + return rc; +} + +static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, + int enable) +{ + int rc, i = 0; + struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; + uint64_t ab_bw, ib_bw; + + rc = cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, + (enable == true) ? CAM_SVS_VOTE : CAM_SUSPEND_VOTE); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in AHB vote, enable=%d, rc=%d", + enable, rc); + return rc; + } + + if (enable) { + ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + } else { + ab_bw = 0; + ib_bw = 0; + } + + for (i = 0; i < cpas_core->num_axi_ports; i++) { + rc = cam_cpas_util_vote_bus_client_bw( + &cpas_core->axi_port[i].bus_client, + ab_bw, ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote, enable=%d, rc=%d", + enable, rc); + goto remove_ahb_vote; + } + } + + return 0; +remove_ahb_vote: + cam_cpas_util_vote_bus_client_level(&cpas_core->ahb_bus_client, + CAM_SUSPEND_VOTE); + return rc; +} + +static int cam_cpas_hw_reg_write(struct cam_hw_info *cpas_hw, + uint32_t client_handle, enum cam_cpas_reg_base reg_base, + uint32_t offset, bool mb, uint32_t value) +{ + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + int reg_base_index = cpas_core->regbase_index[reg_base]; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (reg_base_index < 0 || reg_base_index >= soc_info->num_reg_map) { + CAM_ERR(CAM_CPAS, + "Invalid reg_base=%d, reg_base_index=%d, num_map=%d", + reg_base, reg_base_index, soc_info->num_reg_map); + return -EINVAL; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + if (mb) + cam_io_w_mb(value, + soc_info->reg_map[reg_base_index].mem_base + offset); + else + cam_io_w(value, + soc_info->reg_map[reg_base_index].mem_base + offset); + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + return rc; +} + +static int cam_cpas_hw_reg_read(struct cam_hw_info *cpas_hw, + uint32_t client_handle, enum cam_cpas_reg_base reg_base, + uint32_t offset, bool mb, uint32_t *value) +{ + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + int reg_base_index = cpas_core->regbase_index[reg_base]; + uint32_t reg_value; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!value) + return -EINVAL; + + if (reg_base_index < 0 || reg_base_index >= soc_info->num_reg_map) { + CAM_ERR(CAM_CPAS, + "Invalid reg_base=%d, reg_base_index=%d, num_map=%d", + reg_base, reg_base_index, soc_info->num_reg_map); + return -EINVAL; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + return -EPERM; + } + + if (mb) + reg_value = cam_io_r_mb( + soc_info->reg_map[reg_base_index].mem_base + offset); + else + reg_value = cam_io_r( + soc_info->reg_map[reg_base_index].mem_base + offset); + + *value = reg_value; + + return rc; +} + +static int cam_cpas_util_set_camnoc_axi_clk_rate( + struct cam_hw_info *cpas_hw) +{ + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_tree_node *tree_node = NULL; + int rc = 0, i = 0; + + CAM_DBG(CAM_CPAS, "control_camnoc_axi_clk=%d", + soc_private->control_camnoc_axi_clk); + + if (soc_private->control_camnoc_axi_clk) { + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + uint64_t required_camnoc_bw = 0, intermediate_result = 0; + int64_t clk_rate = 0; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + tree_node = soc_private->tree_node[i]; + if (!tree_node || + !tree_node->camnoc_max_needed) + continue; + + if (required_camnoc_bw < (tree_node->camnoc_bw * + tree_node->bus_width_factor)) { + required_camnoc_bw = tree_node->camnoc_bw * + tree_node->bus_width_factor; + } + } + + intermediate_result = required_camnoc_bw * + soc_private->camnoc_axi_clk_bw_margin; + do_div(intermediate_result, 100); + required_camnoc_bw += intermediate_result; + + if (cpas_core->streamon_clients && (required_camnoc_bw == 0)) { + CAM_DBG(CAM_CPAS, + "Set min vote if streamon_clients is non-zero : streamon_clients=%d", + cpas_core->streamon_clients); + required_camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + } + + if ((required_camnoc_bw > 0) && + (required_camnoc_bw < + soc_private->camnoc_axi_min_ib_bw)) + required_camnoc_bw = soc_private->camnoc_axi_min_ib_bw; + + intermediate_result = required_camnoc_bw; + do_div(intermediate_result, soc_private->camnoc_bus_width); + clk_rate = intermediate_result; + + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %lld", + required_camnoc_bw, clk_rate); + + /* + * CPAS hw is not powered on for the first client. + * Also, clk_rate will be overwritten with default + * value while power on. So, skipping this for first + * client. + */ + if (cpas_core->streamon_clients) { + rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_CPAS, + "Failed in setting camnoc axi clk %llu %lld %d", + required_camnoc_bw, clk_rate, rc); + } + } + + return rc; +} + +static int cam_cpas_util_translate_client_paths( + struct cam_axi_vote *axi_vote) +{ + int i; + uint32_t *path_data_type = NULL; + + if (!axi_vote) + return -EINVAL; + + for (i = 0; i < axi_vote->num_paths; i++) { + path_data_type = &axi_vote->axi_path[i].path_data_type; + /* Update path_data_type from UAPI value to internal value */ + if (*path_data_type >= CAM_CPAS_PATH_DATA_CONSO_OFFSET) + *path_data_type = CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT + + (*path_data_type % + CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT); + else + *path_data_type %= CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT; + + if (*path_data_type >= CAM_CPAS_PATH_DATA_MAX) { + CAM_ERR(CAM_CPAS, "index Invalid: %d", path_data_type); + return -EINVAL; + } + } + + return 0; +} + +static int cam_cpas_axi_consolidate_path_votes( + struct cam_cpas_client *cpas_client, + struct cam_axi_vote *axi_vote) +{ + int rc = 0, i, k, l; + struct cam_axi_vote *con_axi_vote = &cpas_client->axi_vote; + bool path_found = false, cons_entry_found; + struct cam_cpas_tree_node *curr_tree_node = NULL; + struct cam_cpas_tree_node *sum_tree_node = NULL; + uint32_t transac_type; + uint32_t path_data_type; + struct cam_axi_per_path_bw_vote *axi_path; + + con_axi_vote->num_paths = 0; + + for (i = 0; i < axi_vote->num_paths; i++) { + path_found = false; + path_data_type = axi_vote->axi_path[i].path_data_type; + transac_type = axi_vote->axi_path[i].transac_type; + + if ((path_data_type >= CAM_CPAS_PATH_DATA_MAX) || + (transac_type >= CAM_CPAS_TRANSACTION_MAX)) { + CAM_ERR(CAM_CPAS, "Invalid path or transac type: %d %d", + path_data_type, transac_type); + return -EINVAL; + } + + axi_path = &con_axi_vote->axi_path[con_axi_vote->num_paths]; + + curr_tree_node = + cpas_client->tree_node[path_data_type][transac_type]; + if (curr_tree_node) { + path_found = true; + memcpy(axi_path, &axi_vote->axi_path[i], + sizeof(struct cam_axi_per_path_bw_vote)); + con_axi_vote->num_paths++; + continue; + } + + for (k = 0; k < CAM_CPAS_PATH_DATA_MAX; k++) { + sum_tree_node = cpas_client->tree_node[k][transac_type]; + + if (!sum_tree_node) + continue; + + if (sum_tree_node->constituent_paths[path_data_type]) { + path_found = true; + /* + * Check if corresponding consolidated path + * entry is already added into consolidated list + */ + cons_entry_found = false; + for (l = 0; l < con_axi_vote->num_paths; l++) { + if ((con_axi_vote->axi_path[l] + .path_data_type == k) && + (con_axi_vote->axi_path[l] + .transac_type == transac_type)) { + cons_entry_found = true; + con_axi_vote->axi_path[l] + .camnoc_bw += + axi_vote->axi_path[i] + .camnoc_bw; + + con_axi_vote->axi_path[l] + .mnoc_ab_bw += + axi_vote->axi_path[i] + .mnoc_ab_bw; + + con_axi_vote->axi_path[l] + .mnoc_ib_bw += + axi_vote->axi_path[i] + .mnoc_ib_bw; + break; + } + } + + /* If not found, add a new entry */ + if (!cons_entry_found) { + axi_path->path_data_type = k; + axi_path->transac_type = transac_type; + axi_path->camnoc_bw = + axi_vote->axi_path[i].camnoc_bw; + axi_path->mnoc_ab_bw = + axi_vote->axi_path[i].mnoc_ab_bw; + axi_path->mnoc_ib_bw = + axi_vote->axi_path[i].mnoc_ib_bw; + con_axi_vote->num_paths++; + } + break; + } + } + + if (!path_found) { + CAM_ERR(CAM_CPAS, + "Client [%s][%d] Consolidated path not found for path=%d, transac=%d", + cpas_client->data.identifier, + cpas_client->data.cell_index, + path_data_type, transac_type); + return -EINVAL; + } + } + + return rc; +} + +static int cam_cpas_update_axi_vote_bw( + struct cam_hw_info *cpas_hw, + struct cam_cpas_tree_node *cpas_tree_node, + bool *mnoc_axi_port_updated, + bool *camnoc_axi_port_updated) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + if (cpas_tree_node->axi_port_idx >= CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid axi_port_idx: %d", + cpas_tree_node->axi_port_idx); + return -EINVAL; + } + + cpas_core->axi_port[cpas_tree_node->axi_port_idx].ab_bw = + cpas_tree_node->mnoc_ab_bw; + cpas_core->axi_port[cpas_tree_node->axi_port_idx].ib_bw = + cpas_tree_node->mnoc_ib_bw; + mnoc_axi_port_updated[cpas_tree_node->axi_port_idx] = true; + + if (soc_private->control_camnoc_axi_clk) + return 0; + + cpas_core->camnoc_axi_port[cpas_tree_node->axi_port_idx].camnoc_bw = + cpas_tree_node->camnoc_bw; + camnoc_axi_port_updated[cpas_tree_node->camnoc_axi_port_idx] = true; + return 0; +} + +static int cam_cpas_camnoc_set_vote_axi_clk_rate( + struct cam_hw_info *cpas_hw, + bool *camnoc_axi_port_updated) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + int i; + int rc = 0; + struct cam_cpas_axi_port *camnoc_axi_port = NULL; + uint64_t camnoc_bw; + + if (soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_util_set_camnoc_axi_clk_rate(cpas_hw); + if (rc) + CAM_ERR(CAM_CPAS, + "Failed in setting axi clk rate rc=%d", rc); + return rc; + } + + /* Below code is executed if we just vote and do not set the clk rate + * for camnoc + */ + + if (cpas_core->num_camnoc_axi_ports > CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "Invalid num_camnoc_axi_ports: %d", + cpas_core->num_camnoc_axi_ports); + return -EINVAL; + } + + for (i = 0; i < cpas_core->num_camnoc_axi_ports; i++) { + if (camnoc_axi_port_updated[i]) + camnoc_axi_port = &cpas_core->camnoc_axi_port[i]; + else + continue; + + CAM_DBG(CAM_PERF, "Port[%s] : camnoc_bw=%lld", + camnoc_axi_port->axi_port_name, + camnoc_axi_port->camnoc_bw); + + if (camnoc_axi_port->camnoc_bw) + camnoc_bw = camnoc_axi_port->camnoc_bw; + else if (camnoc_axi_port->additional_bw) + camnoc_bw = camnoc_axi_port->additional_bw; + else if (cpas_core->streamon_clients) + camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + camnoc_bw = 0; + + rc = cam_cpas_util_vote_bus_client_bw( + &camnoc_axi_port->bus_client, + 0, camnoc_bw, true); + + CAM_DBG(CAM_CPAS, + "camnoc vote camnoc_bw[%llu] rc=%d %s", + camnoc_bw, rc, camnoc_axi_port->axi_port_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in camnoc vote camnoc_bw[%llu] rc=%d", + camnoc_bw, rc); + break; + } + } + return rc; +} + +static int cam_cpas_util_apply_client_axi_vote( + struct cam_hw_info *cpas_hw, + struct cam_cpas_client *cpas_client, + struct cam_axi_vote *axi_vote) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_axi_vote *con_axi_vote = NULL; + struct cam_cpas_axi_port *mnoc_axi_port = NULL; + struct cam_cpas_tree_node *curr_tree_node = NULL; + struct cam_cpas_tree_node *par_tree_node = NULL; + uint32_t transac_type; + uint32_t path_data_type; + bool mnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + bool camnoc_axi_port_updated[CAM_CPAS_MAX_AXI_PORTS] = {false}; + uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0, + curr_camnoc_old = 0, curr_mnoc_ab_old = 0, curr_mnoc_ib_old = 0, + par_camnoc_old = 0, par_mnoc_ab_old = 0, par_mnoc_ib_old = 0; + int rc = 0, i = 0; + + mutex_lock(&cpas_core->tree_lock); + if (!cpas_client->tree_node_valid) { + /* + * This is by assuming apply_client_axi_vote is called + * for these clients from only cpas_start, cpas_stop. + * not called from hw_update_axi_vote + */ + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (axi_vote->axi_path[0].mnoc_ab_bw) { + /* start case */ + cpas_core->axi_port[i].additional_bw += + CAM_CPAS_DEFAULT_AXI_BW; + } else { + /* stop case */ + cpas_core->axi_port[i].additional_bw -= + CAM_CPAS_DEFAULT_AXI_BW; + } + mnoc_axi_port_updated[i] = true; + } + goto vote_start_clients; + } + + rc = cam_cpas_axi_consolidate_path_votes(cpas_client, axi_vote); + if (rc) { + CAM_ERR(CAM_PERF, "Failed in bw consolidation, Client [%s][%d]", + cpas_client->data.identifier, + cpas_client->data.cell_index); + goto unlock_tree; + } + + con_axi_vote = &cpas_client->axi_vote; + + cam_cpas_dump_axi_vote_info(cpas_client, "Consolidated Vote", + con_axi_vote); + + /* Traverse through node tree and update bw vote values */ + for (i = 0; i < con_axi_vote->num_paths; i++) { + path_data_type = + con_axi_vote->axi_path[i].path_data_type; + transac_type = + con_axi_vote->axi_path[i].transac_type; + curr_tree_node = cpas_client->tree_node[path_data_type] + [transac_type]; + + if (con_axi_vote->axi_path[i].mnoc_ab_bw == 0) + con_axi_vote->axi_path[i].mnoc_ab_bw = + con_axi_vote->axi_path[i].camnoc_bw; + + if (con_axi_vote->axi_path[i].camnoc_bw == 0) + con_axi_vote->axi_path[i].camnoc_bw = + con_axi_vote->axi_path[i].mnoc_ab_bw; + + if ((curr_tree_node->camnoc_bw == + con_axi_vote->axi_path[i].camnoc_bw) && + (curr_tree_node->mnoc_ab_bw == + con_axi_vote->axi_path[i].mnoc_ab_bw) && + (curr_tree_node->mnoc_ib_bw == + con_axi_vote->axi_path[i].mnoc_ib_bw)) + continue; + + curr_camnoc_old = curr_tree_node->camnoc_bw; + curr_mnoc_ab_old = curr_tree_node->mnoc_ab_bw; + curr_mnoc_ib_old = curr_tree_node->mnoc_ib_bw; + curr_tree_node->camnoc_bw = + con_axi_vote->axi_path[i].camnoc_bw; + curr_tree_node->mnoc_ab_bw = + con_axi_vote->axi_path[i].mnoc_ab_bw; + curr_tree_node->mnoc_ib_bw = + con_axi_vote->axi_path[i].mnoc_ib_bw; + + while (curr_tree_node->parent_node) { + par_tree_node = curr_tree_node->parent_node; + par_camnoc_old = par_tree_node->camnoc_bw; + par_mnoc_ab_old = par_tree_node->mnoc_ab_bw; + par_mnoc_ib_old = par_tree_node->mnoc_ib_bw; + par_tree_node->mnoc_ab_bw -= curr_mnoc_ab_old; + par_tree_node->mnoc_ab_bw += curr_tree_node->mnoc_ab_bw; + par_tree_node->mnoc_ib_bw -= curr_mnoc_ib_old; + par_tree_node->mnoc_ib_bw += curr_tree_node->mnoc_ib_bw; + + if (par_tree_node->merge_type == + CAM_CPAS_TRAFFIC_MERGE_SUM) { + par_tree_node->camnoc_bw -= + curr_camnoc_old; + par_tree_node->camnoc_bw += + curr_tree_node->camnoc_bw; + } else if (par_tree_node->merge_type == + CAM_CPAS_TRAFFIC_MERGE_SUM_INTERLEAVE) { + par_tree_node->camnoc_bw -= + (curr_camnoc_old / 2); + par_tree_node->camnoc_bw += + (curr_tree_node->camnoc_bw / 2); + } else { + CAM_ERR(CAM_CPAS, "Invalid Merge type"); + rc = -EINVAL; + goto unlock_tree; + } + + if (!par_tree_node->parent_node) { + if ((par_tree_node->axi_port_idx < 0) || + (par_tree_node->axi_port_idx >= + CAM_CPAS_MAX_AXI_PORTS)) { + CAM_ERR(CAM_CPAS, + "AXI port index invalid"); + rc = -EINVAL; + goto unlock_tree; + } + rc = cam_cpas_update_axi_vote_bw(cpas_hw, + par_tree_node, + mnoc_axi_port_updated, + camnoc_axi_port_updated); + if (rc) { + CAM_ERR(CAM_CPAS, + "Update Vote failed"); + goto unlock_tree; + } + } + + curr_tree_node = par_tree_node; + curr_camnoc_old = par_camnoc_old; + curr_mnoc_ab_old = par_mnoc_ab_old; + curr_mnoc_ib_old = par_mnoc_ib_old; + } + } + + if (!par_tree_node) { + CAM_DBG(CAM_CPAS, "No change in BW for all paths"); + rc = 0; + goto unlock_tree; + } + +vote_start_clients: + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (mnoc_axi_port_updated[i]) + mnoc_axi_port = &cpas_core->axi_port[i]; + else + continue; + + CAM_DBG(CAM_PERF, + "Port[%s] : ab=%lld ib=%lld additional=%lld, streamon_clients=%d", + mnoc_axi_port->axi_port_name, mnoc_axi_port->ab_bw, + mnoc_axi_port->ib_bw, mnoc_axi_port->additional_bw, + cpas_core->streamon_clients); + + if (mnoc_axi_port->ab_bw) + mnoc_ab_bw = mnoc_axi_port->ab_bw; + else if (mnoc_axi_port->additional_bw) + mnoc_ab_bw = mnoc_axi_port->additional_bw; + else if (cpas_core->streamon_clients) + mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + mnoc_ab_bw = 0; + + if (cpas_core->axi_port[i].ib_bw_voting_needed) + mnoc_ib_bw = mnoc_axi_port->ib_bw; + else + mnoc_ib_bw = 0; + + rc = cam_cpas_util_vote_bus_client_bw( + &mnoc_axi_port->bus_client, + mnoc_ab_bw, mnoc_ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", + mnoc_ab_bw, mnoc_ib_bw, rc); + goto unlock_tree; + } + } + rc = cam_cpas_camnoc_set_vote_axi_clk_rate( + cpas_hw, camnoc_axi_port_updated); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in setting axi clk rate rc=%d", rc); + +unlock_tree: + mutex_unlock(&cpas_core->tree_lock); + return rc; +} + +static int cam_cpas_util_apply_default_axi_vote( + struct cam_hw_info *cpas_hw, bool enable) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_axi_port *axi_port = NULL; + uint64_t mnoc_ab_bw = 0, mnoc_ib_bw = 0; + int rc = 0, i = 0; + + mutex_lock(&cpas_core->tree_lock); + for (i = 0; i < cpas_core->num_axi_ports; i++) { + if (!cpas_core->axi_port[i].ab_bw || + !cpas_core->axi_port[i].ib_bw) + axi_port = &cpas_core->axi_port[i]; + else + continue; + + if (enable) + mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + else + mnoc_ib_bw = 0; + + CAM_DBG(CAM_CPAS, "Port=[%s] :ab[%llu] ib[%llu]", + axi_port->axi_port_name, mnoc_ab_bw, mnoc_ib_bw); + + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->bus_client, + mnoc_ab_bw, mnoc_ib_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", + mnoc_ab_bw, mnoc_ib_bw, rc); + goto unlock_tree; + } + } + +unlock_tree: + mutex_unlock(&cpas_core->tree_lock); + return rc; +} + +static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, + uint32_t client_handle, struct cam_axi_vote *client_axi_vote) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + struct cam_axi_vote axi_vote = {0}; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!client_axi_vote) { + CAM_ERR(CAM_CPAS, "Invalid arg, client_handle=%d", + client_handle); + return -EINVAL; + } + + memcpy(&axi_vote, client_axi_vote, sizeof(struct cam_axi_vote)); + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], + "Incoming Vote", &axi_vote); + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + rc = cam_cpas_util_translate_client_paths(&axi_vote); + if (rc) { + CAM_ERR(CAM_CPAS, + "Unable to translate per path votes rc: %d", rc); + goto unlock_client; + } + + cam_cpas_dump_axi_vote_info(cpas_core->cpas_client[client_indx], + "Translated Vote", &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_core->cpas_client[client_indx], &axi_vote); + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_util_get_ahb_level(struct cam_hw_info *cpas_hw, + struct device *dev, unsigned long freq, enum cam_vote_level *req_level) +{ + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct dev_pm_opp *opp; + unsigned int corner; + enum cam_vote_level level = CAM_SVS_VOTE; + unsigned long corner_freq = freq; + int i; + + if (!dev || !req_level) { + CAM_ERR(CAM_CPAS, "Invalid params %pK, %pK", dev, req_level); + return -EINVAL; + } + + opp = dev_pm_opp_find_freq_ceil(dev, &corner_freq); + if (IS_ERR(opp)) { + CAM_DBG(CAM_CPAS, "OPP Ceil not available for freq :%ld, %pK", + corner_freq, opp); + *req_level = CAM_TURBO_VOTE; + return 0; + } + + corner = dev_pm_opp_get_voltage(opp); + + for (i = 0; i < soc_private->num_vdd_ahb_mapping; i++) + if (corner == soc_private->vdd_ahb[i].vdd_corner) + level = soc_private->vdd_ahb[i].ahb_level; + + CAM_DBG(CAM_CPAS, + "From OPP table : freq=[%ld][%ld], corner=%d, level=%d", + freq, corner_freq, corner, level); + + *req_level = level; + + return 0; +} + +static int cam_cpas_util_apply_client_ahb_vote(struct cam_hw_info *cpas_hw, + struct cam_cpas_client *cpas_client, struct cam_ahb_vote *ahb_vote, + enum cam_vote_level *applied_level) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_bus_client *ahb_bus_client = &cpas_core->ahb_bus_client; + enum cam_vote_level required_level; + enum cam_vote_level highest_level; + int i, rc = 0; + + if (!ahb_bus_client->valid) { + CAM_ERR(CAM_CPAS, "AHB Bus client not valid"); + return -EINVAL; + } + + if (ahb_vote->type == CAM_VOTE_DYNAMIC) { + rc = cam_cpas_util_get_ahb_level(cpas_hw, cpas_client->data.dev, + ahb_vote->vote.freq, &required_level); + if (rc) + return rc; + } else { + required_level = ahb_vote->vote.level; + } + + if (cpas_client->ahb_level == required_level) + return 0; + + mutex_lock(&ahb_bus_client->lock); + cpas_client->ahb_level = required_level; + + CAM_DBG(CAM_CPAS, "Client=[%d][%s] required level[%d], curr_level[%d]", + ahb_bus_client->client_id, ahb_bus_client->name, + required_level, ahb_bus_client->curr_vote_level); + + if (required_level == ahb_bus_client->curr_vote_level) + goto unlock_bus_client; + + highest_level = required_level; + for (i = 0; i < cpas_core->num_clients; i++) { + if (cpas_core->cpas_client[i] && (highest_level < + cpas_core->cpas_client[i]->ahb_level)) + highest_level = cpas_core->cpas_client[i]->ahb_level; + } + + CAM_DBG(CAM_CPAS, "Required highest_level[%d]", highest_level); + + if (!cpas_core->ahb_bus_scaling_disable) { + rc = cam_cpas_util_vote_bus_client_level(ahb_bus_client, + highest_level); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in ahb vote, level=%d, rc=%d", + highest_level, rc); + goto unlock_bus_client; + } + } + + rc = cam_soc_util_set_clk_rate_level(&cpas_hw->soc_info, highest_level); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in scaling clock rate level %d for AHB", + highest_level); + goto unlock_bus_client; + } + + if (applied_level) + *applied_level = highest_level; + +unlock_bus_client: + mutex_unlock(&ahb_bus_client->lock); + return rc; +} + +static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw, + uint32_t client_handle, struct cam_ahb_vote *client_ahb_vote) +{ + struct cam_ahb_vote ahb_vote; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_cpas_client *cpas_client = NULL; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!client_ahb_vote) { + CAM_ERR(CAM_CPAS, "Invalid input arg"); + return -EINVAL; + } + + ahb_vote = *client_ahb_vote; + + if (ahb_vote.vote.level == 0) { + CAM_DBG(CAM_CPAS, "0 ahb vote from client %d", + client_handle); + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] has not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto unlock_client; + } + + CAM_DBG(CAM_PERF, + "client=[%d][%s][%d] : type[%d], level[%d], freq[%ld], applied[%d]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, ahb_vote.type, + ahb_vote.vote.level, ahb_vote.vote.freq, + cpas_core->cpas_client[client_indx]->ahb_level); + + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, + cpas_core->cpas_client[client_indx], &ahb_vote, NULL); + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_util_create_vote_all_paths( + struct cam_cpas_client *cpas_client, + struct cam_axi_vote *axi_vote) +{ + int i, j; + uint64_t camnoc_bw, mnoc_ab_bw, mnoc_ib_bw; + struct cam_axi_per_path_bw_vote *axi_path; + + if (!cpas_client || !axi_vote) + return -EINVAL; + + camnoc_bw = axi_vote->axi_path[0].camnoc_bw; + mnoc_ab_bw = axi_vote->axi_path[0].mnoc_ab_bw; + mnoc_ib_bw = axi_vote->axi_path[0].mnoc_ib_bw; + + axi_vote->num_paths = 0; + + for (i = 0; i < CAM_CPAS_TRANSACTION_MAX; i++) { + for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) { + if (cpas_client->tree_node[j][i]) { + axi_path = + &axi_vote->axi_path[axi_vote->num_paths]; + + axi_path->path_data_type = j; + axi_path->transac_type = i; + axi_path->camnoc_bw = camnoc_bw; + axi_path->mnoc_ab_bw = mnoc_ab_bw; + axi_path->mnoc_ib_bw = mnoc_ib_bw; + + axi_vote->num_paths++; + } + } + } + + return 0; +} + +static int cam_cpas_hw_start(void *hw_priv, void *start_args, + uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + uint32_t client_indx; + struct cam_cpas_hw_cmd_start *cmd_hw_start; + struct cam_cpas_client *cpas_client; + struct cam_ahb_vote *ahb_vote; + struct cam_axi_vote axi_vote = {0}; + enum cam_vote_level applied_level = CAM_SVS_VOTE; + int rc, i = 0; + struct cam_cpas_private_soc *soc_private = NULL; + bool invalid_start = true; + + if (!hw_priv || !start_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, start_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_cmd_start) != arg_size) { + CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d", + sizeof(struct cam_cpas_hw_cmd_start), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_private = (struct cam_cpas_private_soc *) + cpas_hw->soc_info.soc_private; + cmd_hw_start = (struct cam_cpas_hw_cmd_start *)start_args; + client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_start->client_handle); + ahb_vote = cmd_hw_start->ahb_vote; + + if (!ahb_vote || !cmd_hw_start->axi_vote) + return -EINVAL; + + if (!ahb_vote->vote.level) { + CAM_ERR(CAM_CPAS, "Invalid vote ahb[%d]", + ahb_vote->vote.level); + return -EINVAL; + } + + memcpy(&axi_vote, cmd_hw_start->axi_vote, sizeof(struct cam_axi_vote)); + for (i = 0; i < axi_vote.num_paths; i++) { + if ((axi_vote.axi_path[i].camnoc_bw != 0) || + (axi_vote.axi_path[i].mnoc_ab_bw != 0) || + (axi_vote.axi_path[i].mnoc_ib_bw != 0)) { + invalid_start = false; + break; + } + } + + if (invalid_start) { + CAM_ERR(CAM_CPAS, "Zero start vote"); + return -EINVAL; + } + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d] is not registered", + client_indx); + rc = -EPERM; + goto done; + } + + if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client=[%d][%s][%d] is in start state", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EALREADY; + goto done; + } + + CAM_DBG(CAM_CPAS, + "AHB :client=[%d][%s][%d] type[%d], level[%d], applied[%d]", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, + ahb_vote->type, ahb_vote->vote.level, cpas_client->ahb_level); + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + ahb_vote, &applied_level); + if (rc) + goto done; + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Vote", + &axi_vote); + + /* + * If client has indicated start bw to be applied on all paths + * of client, apply that otherwise apply whatever the client supplies + * for specific paths + */ + if (axi_vote.axi_path[0].path_data_type == + CAM_CPAS_API_PATH_DATA_STD_START) { + rc = cam_cpas_util_create_vote_all_paths(cpas_client, + &axi_vote); + } else { + rc = cam_cpas_util_translate_client_paths(&axi_vote); + } + + if (rc) { + CAM_ERR(CAM_CPAS, "Unable to create or translate paths rc: %d", + rc); + goto done; + } + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Start Translated Vote", + &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); + if (rc) + goto done; + + if (cpas_core->streamon_clients == 0) { + rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, true); + if (rc) + goto done; + + atomic_set(&cpas_core->irq_count, 1); + rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, + applied_level); + if (rc) { + atomic_set(&cpas_core->irq_count, 0); + CAM_ERR(CAM_CPAS, "enable_resorce failed, rc=%d", rc); + goto done; + } + + if (cpas_core->internal_ops.power_on) { + rc = cpas_core->internal_ops.power_on(cpas_hw); + if (rc) { + atomic_set(&cpas_core->irq_count, 0); + cam_cpas_soc_disable_resources( + &cpas_hw->soc_info, true, true); + CAM_ERR(CAM_CPAS, + "failed in power_on settings rc=%d", + rc); + goto done; + } + } + CAM_DBG(CAM_CPAS, "irq_count=%d\n", + atomic_read(&cpas_core->irq_count)); + cpas_hw->hw_state = CAM_HW_STATE_POWER_UP; + } + + cpas_client->started = true; + cpas_core->streamon_clients++; + + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d] streamon_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->streamon_clients); +done: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int _check_irq_count(struct cam_cpas *cpas_core) +{ + return (atomic_read(&cpas_core->irq_count) > 0) ? 0 : 1; +} + +static int cam_cpas_hw_stop(void *hw_priv, void *stop_args, + uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + uint32_t client_indx; + struct cam_cpas_hw_cmd_stop *cmd_hw_stop; + struct cam_cpas_client *cpas_client; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + struct cam_cpas_private_soc *soc_private = NULL; + int rc = 0; + long result; + + if (!hw_priv || !stop_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, stop_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_cmd_stop) != arg_size) { + CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d", + sizeof(struct cam_cpas_hw_cmd_stop), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_private = (struct cam_cpas_private_soc *) + cpas_hw->soc_info.soc_private; + cmd_hw_stop = (struct cam_cpas_hw_cmd_stop *)stop_args; + client_indx = CAM_CPAS_GET_CLIENT_IDX(cmd_hw_stop->client_handle); + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + cpas_client = cpas_core->cpas_client[client_indx]; + + CAM_DBG(CAM_CPAS, "Client=[%d][%s][%d] streamon_clients=%d", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index, cpas_core->streamon_clients); + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not started", + client_indx, cpas_client->data.identifier, + cpas_client->data.cell_index); + rc = -EPERM; + goto done; + } + + cpas_client->started = false; + cpas_core->streamon_clients--; + + if (cpas_core->streamon_clients == 0) { + if (cpas_core->internal_ops.power_off) { + rc = cpas_core->internal_ops.power_off(cpas_hw); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed in power_off settings rc=%d", + rc); + /* Do not return error, passthrough */ + } + } + + rc = cam_cpas_soc_disable_irq(&cpas_hw->soc_info); + if (rc) { + CAM_ERR(CAM_CPAS, "disable_irq failed, rc=%d", rc); + goto done; + } + + /* Wait for any IRQs still being handled */ + atomic_dec(&cpas_core->irq_count); + result = wait_event_timeout(cpas_core->irq_count_wq, + _check_irq_count(cpas_core), HZ); + if (result == 0) { + CAM_ERR(CAM_CPAS, "Wait failed: irq_count=%d", + atomic_read(&cpas_core->irq_count)); + } + + rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, + true, false); + if (rc) { + CAM_ERR(CAM_CPAS, "disable_resorce failed, rc=%d", rc); + goto done; + } + CAM_DBG(CAM_CPAS, "Disabled all the resources: irq_count=%d\n", + atomic_read(&cpas_core->irq_count)); + cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SUSPEND_VOTE; + rc = cam_cpas_util_apply_client_ahb_vote(cpas_hw, cpas_client, + &ahb_vote, NULL); + if (rc) + goto done; + + rc = cam_cpas_util_create_vote_all_paths(cpas_client, &axi_vote); + if (rc) { + CAM_ERR(CAM_CPAS, "Unable to create per path votes rc: %d", rc); + goto done; + } + + cam_cpas_dump_axi_vote_info(cpas_client, "CPAS Stop Vote", &axi_vote); + + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); + if (rc) + goto done; + + if (cpas_core->streamon_clients == 0) + rc = cam_cpas_util_apply_default_axi_vote(cpas_hw, false); +done: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_hw_init(void *hw_priv, void *init_hw_args, + uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + int rc = 0; + + if (!hw_priv || !init_hw_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, init_hw_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_caps) != arg_size) { + CAM_ERR(CAM_CPAS, "INIT HW size mismatch %zd %d", + sizeof(struct cam_cpas_hw_caps), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *)cpas_hw->core_info; + + if (cpas_core->internal_ops.init_hw_version) { + rc = cpas_core->internal_ops.init_hw_version(cpas_hw, + (struct cam_cpas_hw_caps *)init_hw_args); + } + + return rc; +} + +static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, + struct cam_cpas_register_params *register_params) +{ + int rc; + char client_name[CAM_HW_IDENTIFIER_LENGTH + 3]; + int32_t client_indx = -1; + struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + if ((!register_params) || + (strlen(register_params->identifier) < 1)) { + CAM_ERR(CAM_CPAS, "Invalid cpas client identifier"); + return -EINVAL; + } + + CAM_DBG(CAM_CPAS, "Register params : identifier=%s, cell_index=%d", + register_params->identifier, register_params->cell_index); + + if (soc_private->client_id_based) + snprintf(client_name, sizeof(client_name), "%s%d", + register_params->identifier, + register_params->cell_index); + else + snprintf(client_name, sizeof(client_name), "%s", + register_params->identifier); + + mutex_lock(&cpas_hw->hw_mutex); + + rc = cam_common_util_get_string_index(soc_private->client_name, + soc_private->num_clients, client_name, &client_indx); + + mutex_lock(&cpas_core->client_mutex[client_indx]); + + if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) || + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, + "Inval client %s %d : %d %d %pK %d", + register_params->identifier, + register_params->cell_index, + CAM_CPAS_CLIENT_VALID(client_indx), + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx), + cpas_core->cpas_client[client_indx], rc); + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return -EPERM; + } + + register_params->client_handle = + CAM_CPAS_GET_CLIENT_HANDLE(client_indx); + memcpy(&cpas_core->cpas_client[client_indx]->data, register_params, + sizeof(struct cam_cpas_register_params)); + cpas_core->registered_clients++; + cpas_core->cpas_client[client_indx]->registered = true; + + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index, + cpas_core->registered_clients); + + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + + return 0; +} + +static int cam_cpas_hw_unregister_client(struct cam_hw_info *cpas_hw, + uint32_t client_handle) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + uint32_t client_indx = CAM_CPAS_GET_CLIENT_IDX(client_handle); + int rc = 0; + + if (!CAM_CPAS_CLIENT_VALID(client_indx)) + return -EINVAL; + + mutex_lock(&cpas_hw->hw_mutex); + mutex_lock(&cpas_core->client_mutex[client_indx]); + + if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] not registered", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index); + rc = -EPERM; + goto done; + } + + if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client=[%d][%s][%d] is not stopped", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index); + + rc = -EPERM; + goto done; + } + + CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", + client_indx, + cpas_core->cpas_client[client_indx]->data.identifier, + cpas_core->cpas_client[client_indx]->data.cell_index, + cpas_core->registered_clients); + + cpas_core->cpas_client[client_indx]->registered = false; + cpas_core->registered_clients--; +done: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return rc; +} + +static int cam_cpas_hw_get_hw_info(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + struct cam_cpas_hw_caps *hw_caps; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK", + hw_priv, get_hw_cap_args); + return -EINVAL; + } + + if (sizeof(struct cam_cpas_hw_caps) != arg_size) { + CAM_ERR(CAM_CPAS, "HW_CAPS size mismatch %zd %d", + sizeof(struct cam_cpas_hw_caps), arg_size); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)hw_priv; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + hw_caps = (struct cam_cpas_hw_caps *)get_hw_cap_args; + + *hw_caps = cpas_core->hw_caps; + + return 0; +} + + +static int cam_cpas_hw_process_cmd(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!hw_priv || !cmd_args || + (cmd_type >= CAM_CPAS_HW_CMD_INVALID)) { + CAM_ERR(CAM_CPAS, "Invalid arguments %pK %pK %d", + hw_priv, cmd_args, cmd_type); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_CPAS_HW_CMD_REGISTER_CLIENT: { + struct cam_cpas_register_params *register_params; + + if (sizeof(struct cam_cpas_register_params) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + register_params = (struct cam_cpas_register_params *)cmd_args; + rc = cam_cpas_hw_register_client(hw_priv, register_params); + break; + } + case CAM_CPAS_HW_CMD_UNREGISTER_CLIENT: { + uint32_t *client_handle; + + if (sizeof(uint32_t) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + client_handle = (uint32_t *)cmd_args; + rc = cam_cpas_hw_unregister_client(hw_priv, *client_handle); + break; + } + case CAM_CPAS_HW_CMD_REG_WRITE: { + struct cam_cpas_hw_cmd_reg_read_write *reg_write; + + if (sizeof(struct cam_cpas_hw_cmd_reg_read_write) != + arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + reg_write = + (struct cam_cpas_hw_cmd_reg_read_write *)cmd_args; + rc = cam_cpas_hw_reg_write(hw_priv, reg_write->client_handle, + reg_write->reg_base, reg_write->offset, reg_write->mb, + reg_write->value); + break; + } + case CAM_CPAS_HW_CMD_REG_READ: { + struct cam_cpas_hw_cmd_reg_read_write *reg_read; + + if (sizeof(struct cam_cpas_hw_cmd_reg_read_write) != + arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + reg_read = + (struct cam_cpas_hw_cmd_reg_read_write *)cmd_args; + rc = cam_cpas_hw_reg_read(hw_priv, + reg_read->client_handle, reg_read->reg_base, + reg_read->offset, reg_read->mb, ®_read->value); + + break; + } + case CAM_CPAS_HW_CMD_AHB_VOTE: { + struct cam_cpas_hw_cmd_ahb_vote *cmd_ahb_vote; + + if (sizeof(struct cam_cpas_hw_cmd_ahb_vote) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + cmd_ahb_vote = (struct cam_cpas_hw_cmd_ahb_vote *)cmd_args; + rc = cam_cpas_hw_update_ahb_vote(hw_priv, + cmd_ahb_vote->client_handle, cmd_ahb_vote->ahb_vote); + break; + } + case CAM_CPAS_HW_CMD_AXI_VOTE: { + struct cam_cpas_hw_cmd_axi_vote *cmd_axi_vote; + + if (sizeof(struct cam_cpas_hw_cmd_axi_vote) != arg_size) { + CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + cmd_axi_vote = (struct cam_cpas_hw_cmd_axi_vote *)cmd_args; + rc = cam_cpas_hw_update_axi_vote(hw_priv, + cmd_axi_vote->client_handle, cmd_axi_vote->axi_vote); + break; + } + default: + CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type); + break; + } + + return rc; +} + +static int cam_cpas_util_client_setup(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + int i; + + for (i = 0; i < CAM_CPAS_MAX_CLIENTS; i++) { + mutex_init(&cpas_core->client_mutex[i]); + } + + return 0; +} + +int cam_cpas_util_client_cleanup(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + int i; + + for (i = 0; i < CAM_CPAS_MAX_CLIENTS; i++) { + if (cpas_core->cpas_client[i] && + cpas_core->cpas_client[i]->registered) { + cam_cpas_hw_unregister_client(cpas_hw, i); + } + kfree(cpas_core->cpas_client[i]); + cpas_core->cpas_client[i] = NULL; + mutex_destroy(&cpas_core->client_mutex[i]); + } + + return 0; +} + +static int cam_cpas_util_get_internal_ops(struct platform_device *pdev, + struct cam_hw_intf *hw_intf, struct cam_cpas_internal_ops *internal_ops) +{ + struct device_node *of_node = pdev->dev.of_node; + int rc; + const char *compat_str = NULL; + + rc = of_property_read_string_index(of_node, "arch-compat", 0, + (const char **)&compat_str); + if (rc) { + CAM_ERR(CAM_CPAS, "failed to get arch-compat rc=%d", rc); + return -EINVAL; + } + + if (strnstr(compat_str, "camss_top", strlen(compat_str))) { + hw_intf->hw_type = CAM_HW_CAMSSTOP; + rc = cam_camsstop_get_internal_ops(internal_ops); + } else if (strnstr(compat_str, "cpas_top", strlen(compat_str))) { + hw_intf->hw_type = CAM_HW_CPASTOP; + rc = cam_cpastop_get_internal_ops(internal_ops); + } else { + CAM_ERR(CAM_CPAS, "arch-compat %s not supported", compat_str); + rc = -EINVAL; + } + + return rc; +} + +static int cam_cpas_util_create_debugfs( + struct cam_cpas *cpas_core) +{ + int rc = 0; + + cpas_core->dentry = debugfs_create_dir("camera_cpas", NULL); + if (!cpas_core->dentry) + return -ENOMEM; + + if (!debugfs_create_bool("ahb_bus_scaling_disable", + 0644, + cpas_core->dentry, + &cpas_core->ahb_bus_scaling_disable)) { + CAM_ERR(CAM_CPAS, + "failed to create ahb_bus_scaling_disable entry"); + rc = -ENOMEM; + goto err; + } + + return 0; + +err: + debugfs_remove_recursive(cpas_core->dentry); + cpas_core->dentry = NULL; + return rc; +} + +int cam_cpas_hw_probe(struct platform_device *pdev, + struct cam_hw_intf **hw_intf) +{ + int rc = 0; + int i; + struct cam_hw_info *cpas_hw = NULL; + struct cam_hw_intf *cpas_hw_intf = NULL; + struct cam_cpas *cpas_core = NULL; + struct cam_cpas_private_soc *soc_private; + struct cam_cpas_internal_ops *internal_ops; + + cpas_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!cpas_hw_intf) + return -ENOMEM; + + cpas_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!cpas_hw) { + kfree(cpas_hw_intf); + return -ENOMEM; + } + + cpas_core = kzalloc(sizeof(struct cam_cpas), GFP_KERNEL); + if (!cpas_core) { + kfree(cpas_hw); + kfree(cpas_hw_intf); + return -ENOMEM; + } + + for (i = 0; i < CAM_CPAS_REG_MAX; i++) + cpas_core->regbase_index[i] = -1; + + cpas_hw_intf->hw_priv = cpas_hw; + cpas_hw->core_info = cpas_core; + + cpas_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + cpas_hw->soc_info.pdev = pdev; + cpas_hw->soc_info.dev = &pdev->dev; + cpas_hw->soc_info.dev_name = pdev->name; + cpas_hw->open_count = 0; + cpas_core->ahb_bus_scaling_disable = false; + mutex_init(&cpas_hw->hw_mutex); + spin_lock_init(&cpas_hw->hw_lock); + init_completion(&cpas_hw->hw_complete); + + cpas_hw_intf->hw_ops.get_hw_caps = cam_cpas_hw_get_hw_info; + cpas_hw_intf->hw_ops.init = cam_cpas_hw_init; + cpas_hw_intf->hw_ops.deinit = NULL; + cpas_hw_intf->hw_ops.reset = NULL; + cpas_hw_intf->hw_ops.reserve = NULL; + cpas_hw_intf->hw_ops.release = NULL; + cpas_hw_intf->hw_ops.start = cam_cpas_hw_start; + cpas_hw_intf->hw_ops.stop = cam_cpas_hw_stop; + cpas_hw_intf->hw_ops.read = NULL; + cpas_hw_intf->hw_ops.write = NULL; + cpas_hw_intf->hw_ops.process_cmd = cam_cpas_hw_process_cmd; + + cpas_core->work_queue = alloc_workqueue("cam-cpas", + WQ_UNBOUND | WQ_MEM_RECLAIM, CAM_CPAS_INFLIGHT_WORKS); + if (!cpas_core->work_queue) { + rc = -ENOMEM; + goto release_mem; + } + + internal_ops = &cpas_core->internal_ops; + rc = cam_cpas_util_get_internal_ops(pdev, cpas_hw_intf, internal_ops); + if (rc) + goto release_workq; + + rc = cam_cpas_soc_init_resources(&cpas_hw->soc_info, + internal_ops->handle_irq, cpas_hw); + if (rc) + goto release_workq; + + soc_private = (struct cam_cpas_private_soc *) + cpas_hw->soc_info.soc_private; + cpas_core->num_clients = soc_private->num_clients; + atomic_set(&cpas_core->irq_count, 0); + init_waitqueue_head(&cpas_core->irq_count_wq); + + if (internal_ops->setup_regbase) { + rc = internal_ops->setup_regbase(&cpas_hw->soc_info, + cpas_core->regbase_index, CAM_CPAS_REG_MAX); + if (rc) + goto deinit_platform_res; + } + + rc = cam_cpas_util_client_setup(cpas_hw); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in client setup, rc=%d", rc); + goto deinit_platform_res; + } + + rc = cam_cpas_util_register_bus_client(&cpas_hw->soc_info, + cpas_hw->soc_info.pdev->dev.of_node, + &cpas_core->ahb_bus_client); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in ahb setup, rc=%d", rc); + goto client_cleanup; + } + + rc = cam_cpas_util_axi_setup(cpas_core, &cpas_hw->soc_info); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in axi setup, rc=%d", rc); + goto ahb_cleanup; + } + + /* Need to vote first before enabling clocks */ + rc = cam_cpas_util_vote_default_ahb_axi(cpas_hw, true); + if (rc) + goto axi_cleanup; + + rc = cam_cpas_soc_enable_resources(&cpas_hw->soc_info, CAM_SVS_VOTE); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in soc_enable_resources, rc=%d", rc); + goto remove_default_vote; + } + + if (internal_ops->get_hw_info) { + rc = internal_ops->get_hw_info(cpas_hw, &cpas_core->hw_caps); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in get_hw_info, rc=%d", rc); + goto disable_soc_res; + } + } else { + CAM_ERR(CAM_CPAS, "Invalid get_hw_info"); + goto disable_soc_res; + } + + rc = cam_cpas_hw_init(cpas_hw_intf->hw_priv, + &cpas_core->hw_caps, sizeof(struct cam_cpas_hw_caps)); + if (rc) + goto disable_soc_res; + + rc = cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in soc_disable_resources, rc=%d", rc); + goto remove_default_vote; + } + + rc = cam_cpas_util_vote_default_ahb_axi(cpas_hw, false); + if (rc) + goto axi_cleanup; + + rc = cam_cpas_util_create_debugfs(cpas_core); + if (rc) + CAM_WARN(CAM_CPAS, "Failed to create dentry"); + + *hw_intf = cpas_hw_intf; + return 0; + +disable_soc_res: + cam_cpas_soc_disable_resources(&cpas_hw->soc_info, true, true); +remove_default_vote: + cam_cpas_util_vote_default_ahb_axi(cpas_hw, false); +axi_cleanup: + cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info); +ahb_cleanup: + cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); +client_cleanup: + cam_cpas_util_client_cleanup(cpas_hw); +deinit_platform_res: + cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); +release_workq: + cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); + flush_workqueue(cpas_core->work_queue); + destroy_workqueue(cpas_core->work_queue); +release_mem: + mutex_destroy(&cpas_hw->hw_mutex); + kfree(cpas_core); + kfree(cpas_hw); + kfree(cpas_hw_intf); + CAM_ERR(CAM_CPAS, "failed in hw probe"); + return rc; +} + +int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf) +{ + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + + if (!cpas_hw_intf) { + CAM_ERR(CAM_CPAS, "cpas interface not initialized"); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *)cpas_hw_intf->hw_priv; + cpas_core = (struct cam_cpas *)cpas_hw->core_info; + + if (cpas_hw->hw_state == CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_CPAS, "cpas hw is in power up state"); + return -EINVAL; + } + + cam_cpas_util_axi_cleanup(cpas_core, &cpas_hw->soc_info); + cam_cpas_node_tree_cleanup(cpas_core, cpas_hw->soc_info.soc_private); + cam_cpas_util_unregister_bus_client(&cpas_core->ahb_bus_client); + cam_cpas_util_client_cleanup(cpas_hw); + cam_cpas_soc_deinit_resources(&cpas_hw->soc_info); + debugfs_remove_recursive(cpas_core->dentry); + cpas_core->dentry = NULL; + flush_workqueue(cpas_core->work_queue); + destroy_workqueue(cpas_core->work_queue); + mutex_destroy(&cpas_hw->hw_mutex); + kfree(cpas_core); + kfree(cpas_hw); + kfree(cpas_hw_intf); + + return 0; +} diff --git a/techpack/camera/drivers/cam_cpas/cam_cpas_hw.h b/techpack/camera/drivers/cam_cpas/cam_cpas_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..adbc0d6c34643579e4499251da61e62888f6c1c9 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cam_cpas_hw.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_HW_H_ +#define _CAM_CPAS_HW_H_ + +#include <dt-bindings/msm/msm-camera.h> +#include "cam_cpas_api.h" +#include "cam_cpas_hw_intf.h" +#include "cam_common_util.h" + +#define CAM_CPAS_INFLIGHT_WORKS 5 +#define CAM_CPAS_MAX_CLIENTS 40 +#define CAM_CPAS_MAX_AXI_PORTS 6 +#define CAM_CPAS_MAX_TREE_LEVELS 4 +#define CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT 32 +#define CAM_CPAS_PATH_DATA_MAX 38 +#define CAM_CPAS_TRANSACTION_MAX 2 + +#define CAM_CPAS_AXI_MIN_MNOC_AB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_MNOC_IB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_CAMNOC_AB_BW (2048 * 1024) +#define CAM_CPAS_AXI_MIN_CAMNOC_IB_BW (3000000000UL) + +#define CAM_CPAS_GET_CLIENT_IDX(handle) (handle) +#define CAM_CPAS_GET_CLIENT_HANDLE(indx) (indx) + +#define CAM_CPAS_CLIENT_VALID(indx) \ + ((indx >= 0) && (indx < CAM_CPAS_MAX_CLIENTS)) +#define CAM_CPAS_CLIENT_REGISTERED(cpas_core, indx) \ + ((CAM_CPAS_CLIENT_VALID(indx)) && \ + (cpas_core->cpas_client[indx]->registered)) +#define CAM_CPAS_CLIENT_STARTED(cpas_core, indx) \ + ((CAM_CPAS_CLIENT_REGISTERED(cpas_core, indx)) && \ + (cpas_core->cpas_client[indx]->started)) + +/** + * enum cam_cpas_access_type - Enum for Register access type + */ +enum cam_cpas_access_type { + CAM_REG_TYPE_READ, + CAM_REG_TYPE_WRITE, + CAM_REG_TYPE_READ_WRITE, +}; + +/** + * struct cam_cpas_internal_ops - CPAS Hardware layer internal ops + * + * @get_hw_info: Function pointer for get hw info + * @init_hw_version: Function pointer for hw init based on version + * @handle_irq: Function poniter for irq handling + * @setup_regbase: Function pointer for setup rebase indices + * @power_on: Function pointer for hw core specific power on settings + * @power_off: Function pointer for hw core specific power off settings + * + */ +struct cam_cpas_internal_ops { + int (*get_hw_info)(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps); + int (*init_hw_version)(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps); + irqreturn_t (*handle_irq)(int irq_num, void *data); + int (*setup_regbase)(struct cam_hw_soc_info *soc_info, + int32_t regbase_index[], int32_t num_reg_map); + int (*power_on)(struct cam_hw_info *cpas_hw); + int (*power_off)(struct cam_hw_info *cpas_hw); +}; + +/** + * struct cam_cpas_reg : CPAS register info + * + * @enable: Whether this reg info need to be enabled + * @access_type: Register access type + * @masked_value: Whether this register write/read is based on mask, shift + * @mask: Mask for this register value + * @shift: Shift for this register value + * @value: Register value + * + */ +struct cam_cpas_reg { + bool enable; + enum cam_cpas_access_type access_type; + bool masked_value; + uint32_t offset; + uint32_t mask; + uint32_t shift; + uint32_t value; +}; + +/** + * struct cam_cpas_client : CPAS Client structure info + * + * @data: Client register params + * @registered: Whether client has registered with cpas + * @started: Whether client has streamed on + * @tree_node_valid: Indicates whether tree node has at least one valid node + * @ahb_level: Determined/Applied ahb level for the client + * @axi_vote: Determined/Applied axi vote for the client + * @axi_port: Client's parent axi port + * @tree_node: All granular path voting nodes for the client + * + */ +struct cam_cpas_client { + struct cam_cpas_register_params data; + bool registered; + bool started; + bool tree_node_valid; + enum cam_vote_level ahb_level; + struct cam_axi_vote axi_vote; + struct cam_cpas_axi_port *axi_port; + struct cam_cpas_tree_node *tree_node[CAM_CPAS_PATH_DATA_MAX] + [CAM_CPAS_TRANSACTION_MAX]; +}; + +/** + * struct cam_cpas_bus_client : Bus client information + * + * @src: Bus master/src id + * @dst: Bus slave/dst id + * @pdata: Bus pdata information + * @client_id: Bus client id + * @num_usecases: Number of use cases for this client + * @num_paths: Number of paths for this client + * @curr_vote_level: current voted index + * @dyn_vote: Whether dynamic voting enabled + * @lock: Mutex lock used while voting on this client + * @valid: Whether bus client is valid + * @name: Name of the bus client + * + */ +struct cam_cpas_bus_client { + int src; + int dst; + struct msm_bus_scale_pdata *pdata; + uint32_t client_id; + int num_usecases; + int num_paths; + unsigned int curr_vote_level; + bool dyn_vote; + struct mutex lock; + bool valid; + const char *name; +}; + +/** + * struct cam_cpas_axi_port : AXI port information + * + * @axi_port_name: Name of this AXI port + * @axi_port_name: Name of this AXI port + * @bus_client: bus client info for this port + * @ib_bw_voting_needed: if this port can update ib bw dynamically + * @axi_port_node: Node representing AXI Port info in device tree + * @ab_bw: AB bw value for this port + * @ib_bw: IB bw value for this port + * @camnoc_bw: CAMNOC bw value for this port + * @additional_bw: Additional bandwidth to cover non-hw cpas clients + */ +struct cam_cpas_axi_port { + const char *axi_port_name; + struct cam_cpas_bus_client bus_client; + bool ib_bw_voting_needed; + struct device_node *axi_port_node; + uint64_t ab_bw; + uint64_t ib_bw; + uint64_t camnoc_bw; + uint64_t additional_bw; +}; + +/** + * struct cam_cpas : CPAS core data structure info + * + * @hw_caps: CPAS hw capabilities + * @cpas_client: Array of pointers to CPAS clients info + * @client_mutex: Mutex for accessing client info + * @tree_lock: Mutex lock for accessing CPAS node tree + * @num_clients: Total number of clients that CPAS supports + * @num_axi_ports: Total number of axi ports found in device tree + * @num_camnoc_axi_ports: Total number of camnoc axi ports found in device tree + * @registered_clients: Number of Clients registered currently + * @streamon_clients: Number of Clients that are in start state currently + * @regbase_index: Register base indices for CPAS register base IDs + * @ahb_bus_client: AHB Bus client info + * @axi_port: AXI port info for a specific axi index + * @camnoc_axi_port: CAMNOC AXI port info for a specific camnoc axi index + * @internal_ops: CPAS HW internal ops + * @work_queue: Work queue handle + * @irq_count: atomic irq count + * @irq_count_wq: wait variable to ensure all irq's are handled + * @dentry: debugfs file entry + * @ahb_bus_scaling_disable: ahb scaling based on src clk corner for bus + */ +struct cam_cpas { + struct cam_cpas_hw_caps hw_caps; + struct cam_cpas_client *cpas_client[CAM_CPAS_MAX_CLIENTS]; + struct mutex client_mutex[CAM_CPAS_MAX_CLIENTS]; + struct mutex tree_lock; + uint32_t num_clients; + uint32_t num_axi_ports; + uint32_t num_camnoc_axi_ports; + uint32_t registered_clients; + uint32_t streamon_clients; + int32_t regbase_index[CAM_CPAS_REG_MAX]; + struct cam_cpas_bus_client ahb_bus_client; + struct cam_cpas_axi_port axi_port[CAM_CPAS_MAX_AXI_PORTS]; + struct cam_cpas_axi_port camnoc_axi_port[CAM_CPAS_MAX_AXI_PORTS]; + struct cam_cpas_internal_ops internal_ops; + struct workqueue_struct *work_queue; + atomic_t irq_count; + wait_queue_head_t irq_count_wq; + struct dentry *dentry; + bool ahb_bus_scaling_disable; +}; + +int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); +int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops); + +int cam_cpas_util_reg_update(struct cam_hw_info *cpas_hw, + enum cam_cpas_reg_base reg_base, struct cam_cpas_reg *reg_info); + +int cam_cpas_util_client_cleanup(struct cam_hw_info *cpas_hw); + +#endif /* _CAM_CPAS_HW_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cam_cpas_hw_intf.h b/techpack/camera/drivers/cam_cpas/cam_cpas_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..0926e6e3d8d1653352c4850e912f79b020a0144d --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cam_cpas_hw_intf.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_HW_INTF_H_ +#define _CAM_CPAS_HW_INTF_H_ + +#include <linux/platform_device.h> + +#include "cam_cpas_api.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_debug_util.h" + +/* Number of times to retry while polling */ +#define CAM_CPAS_POLL_RETRY_CNT 5 +/* Minimum usecs to sleep while polling */ +#define CAM_CPAS_POLL_MIN_USECS 200 +/* Maximum usecs to sleep while polling */ +#define CAM_CPAS_POLL_MAX_USECS 250 + +/** + * enum cam_cpas_hw_type - Enum for CPAS HW type + */ +enum cam_cpas_hw_type { + CAM_HW_CPASTOP, + CAM_HW_CAMSSTOP, +}; + +/** + * enum cam_cpas_hw_cmd_process - Enum for CPAS HW process command type + */ +enum cam_cpas_hw_cmd_process { + CAM_CPAS_HW_CMD_REGISTER_CLIENT, + CAM_CPAS_HW_CMD_UNREGISTER_CLIENT, + CAM_CPAS_HW_CMD_REG_WRITE, + CAM_CPAS_HW_CMD_REG_READ, + CAM_CPAS_HW_CMD_AHB_VOTE, + CAM_CPAS_HW_CMD_AXI_VOTE, + CAM_CPAS_HW_CMD_INVALID, +}; + +/** + * struct cam_cpas_hw_cmd_reg_read_write : CPAS cmd struct for reg read, write + * + * @client_handle: Client handle + * @reg_base: Register base type + * @offset: Register offset + * @value: Register value + * @mb: Whether to do operation with memory barrier + * + */ +struct cam_cpas_hw_cmd_reg_read_write { + uint32_t client_handle; + enum cam_cpas_reg_base reg_base; + uint32_t offset; + uint32_t value; + bool mb; +}; + +/** + * struct cam_cpas_hw_cmd_ahb_vote : CPAS cmd struct for AHB vote + * + * @client_handle: Client handle + * @ahb_vote: AHB voting info + * + */ +struct cam_cpas_hw_cmd_ahb_vote { + uint32_t client_handle; + struct cam_ahb_vote *ahb_vote; +}; + +/** + * struct cam_cpas_hw_cmd_axi_vote : CPAS cmd struct for AXI vote + * + * @client_handle: Client handle + * @axi_vote: axi bandwidth vote + * + */ +struct cam_cpas_hw_cmd_axi_vote { + uint32_t client_handle; + struct cam_axi_vote *axi_vote; +}; + +/** + * struct cam_cpas_hw_cmd_start : CPAS cmd struct for start + * + * @client_handle: Client handle + * + */ +struct cam_cpas_hw_cmd_start { + uint32_t client_handle; + struct cam_ahb_vote *ahb_vote; + struct cam_axi_vote *axi_vote; +}; + +/** + * struct cam_cpas_hw_cmd_stop : CPAS cmd struct for stop + * + * @client_handle: Client handle + * + */ +struct cam_cpas_hw_cmd_stop { + uint32_t client_handle; +}; + +/** + * struct cam_cpas_hw_caps : CPAS HW capabilities + * + * @camera_family: Camera family type + * @camera_version: Camera version + * @cpas_version: CPAS version + * @camera_capability: Camera hw capabilities + * + */ +struct cam_cpas_hw_caps { + uint32_t camera_family; + struct cam_hw_version camera_version; + struct cam_hw_version cpas_version; + uint32_t camera_capability; +}; + +int cam_cpas_hw_probe(struct platform_device *pdev, + struct cam_hw_intf **hw_intf); +int cam_cpas_hw_remove(struct cam_hw_intf *cpas_hw_intf); + +#endif /* _CAM_CPAS_HW_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cam_cpas_intf.c b/techpack/camera/drivers/cam_cpas/cam_cpas_intf.c new file mode 100644 index 0000000000000000000000000000000000000000..a1d8b4026059394b88e17f9ad28772e8ecacbf7b --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cam_cpas_intf.c @@ -0,0 +1,752 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <media/cam_cpas.h> +#include <media/cam_req_mgr.h> +#include <dt-bindings/msm/msm-camera.h> + +#include "cam_subdev.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_soc.h" + +#define CAM_CPAS_DEV_NAME "cam-cpas" +#define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done) + +/** + * struct cam_cpas_intf : CPAS interface + * + * @pdev: Platform device + * @subdev: Subdev info + * @hw_intf: CPAS HW interface + * @hw_caps: CPAS HW capabilities + * @intf_lock: CPAS interface mutex + * @open_cnt: CPAS subdev open count + * @probe_done: Whether CPAS prove completed + * + */ +struct cam_cpas_intf { + struct platform_device *pdev; + struct cam_subdev subdev; + struct cam_hw_intf *hw_intf; + struct cam_cpas_hw_caps hw_caps; + struct mutex intf_lock; + uint32_t open_cnt; + bool probe_done; +}; + +static struct cam_cpas_intf *g_cpas_intf; + +const char *cam_cpas_axi_util_path_type_to_string( + uint32_t path_data_type) +{ + switch (path_data_type) { + /* IFE Paths */ + case CAM_AXI_PATH_DATA_IFE_LINEAR: + return "IFE_LINEAR"; + case CAM_AXI_PATH_DATA_IFE_VID: + return "IFE_VID"; + case CAM_AXI_PATH_DATA_IFE_DISP: + return "IFE_DISP"; + case CAM_AXI_PATH_DATA_IFE_STATS: + return "IFE_STATS"; + case CAM_AXI_PATH_DATA_IFE_RDI0: + return "IFE_RDI0"; + case CAM_AXI_PATH_DATA_IFE_RDI1: + return "IFE_RDI1"; + case CAM_AXI_PATH_DATA_IFE_RDI2: + return "IFE_RDI2"; + case CAM_AXI_PATH_DATA_IFE_RDI3: + return "IFE_RDI3"; + case CAM_AXI_PATH_DATA_IFE_PDAF: + return "IFE_PDAF"; + case CAM_AXI_PATH_DATA_IFE_PIXEL_RAW: + return "IFE_PIXEL_RAW"; + + /* IPE Paths */ + case CAM_AXI_PATH_DATA_IPE_RD_IN: + return "IPE_RD_IN"; + case CAM_AXI_PATH_DATA_IPE_RD_REF: + return "IPE_RD_REF"; + case CAM_AXI_PATH_DATA_IPE_WR_VID: + return "IPE_WR_VID"; + case CAM_AXI_PATH_DATA_IPE_WR_DISP: + return "IPE_WR_DISP"; + case CAM_AXI_PATH_DATA_IPE_WR_REF: + return "IPE_WR_REF"; + + /* Common Paths */ + case CAM_AXI_PATH_DATA_ALL: + return "DATA_ALL"; + default: + return "IFE_PATH_INVALID"; + } +} +EXPORT_SYMBOL(cam_cpas_axi_util_path_type_to_string); + +const char *cam_cpas_axi_util_trans_type_to_string( + uint32_t transac_type) +{ + switch (transac_type) { + case CAM_AXI_TRANSACTION_READ: + return "TRANSAC_READ"; + case CAM_AXI_TRANSACTION_WRITE: + return "TRANSAC_WRITE"; + default: + return "TRANSAC_INVALID"; + } +} +EXPORT_SYMBOL(cam_cpas_axi_util_trans_type_to_string); + +int cam_cpas_is_feature_supported(uint32_t flag) +{ + struct cam_hw_info *cpas_hw = NULL; + struct cam_cpas_private_soc *soc_private = NULL; + uint32_t feature_mask; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv; + soc_private = + (struct cam_cpas_private_soc *)cpas_hw->soc_info.soc_private; + feature_mask = soc_private->feature_mask; + + if (flag >= CAM_CPAS_FUSE_FEATURE_MAX) { + CAM_ERR(CAM_CPAS, "Unknown feature flag %x", flag); + return -EINVAL; + } + + return feature_mask & flag ? 1 : 0; +} +EXPORT_SYMBOL(cam_cpas_is_feature_supported); + +int cam_cpas_get_cpas_hw_version(uint32_t *hw_version) +{ + struct cam_hw_info *cpas_hw = NULL; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!hw_version) { + CAM_ERR(CAM_CPAS, "invalid input %pK", hw_version); + return -EINVAL; + } + + cpas_hw = (struct cam_hw_info *) g_cpas_intf->hw_intf->hw_priv; + + *hw_version = cpas_hw->soc_info.hw_version; + + if (*hw_version == CAM_CPAS_TITAN_NONE) { + CAM_DBG(CAM_CPAS, "Didn't find a valid HW Version %d", + *hw_version); + } + + return 0; +} + +int cam_cpas_get_hw_info(uint32_t *camera_family, + struct cam_hw_version *camera_version, + struct cam_hw_version *cpas_version, + uint32_t *cam_caps) +{ + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!camera_family || !camera_version || !cpas_version || !cam_caps) { + CAM_ERR(CAM_CPAS, "invalid input %pK %pK %pK %pK", + camera_family, camera_version, cpas_version, cam_caps); + return -EINVAL; + } + + *camera_family = g_cpas_intf->hw_caps.camera_family; + *camera_version = g_cpas_intf->hw_caps.camera_version; + *cpas_version = g_cpas_intf->hw_caps.cpas_version; + *cam_caps = g_cpas_intf->hw_caps.camera_capability; + + return 0; +} +EXPORT_SYMBOL(cam_cpas_get_hw_info); + +int cam_cpas_reg_write(uint32_t client_handle, + enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb, + uint32_t value) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_reg_read_write cmd_reg_write; + + cmd_reg_write.client_handle = client_handle; + cmd_reg_write.reg_base = reg_base; + cmd_reg_write.offset = offset; + cmd_reg_write.value = value; + cmd_reg_write.mb = mb; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_REG_WRITE, &cmd_reg_write, + sizeof(struct cam_cpas_hw_cmd_reg_read_write)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_reg_write); + +int cam_cpas_reg_read(uint32_t client_handle, + enum cam_cpas_reg_base reg_base, uint32_t offset, bool mb, + uint32_t *value) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!value) { + CAM_ERR(CAM_CPAS, "Invalid arg value"); + return -EINVAL; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_reg_read_write cmd_reg_read; + + cmd_reg_read.client_handle = client_handle; + cmd_reg_read.reg_base = reg_base; + cmd_reg_read.offset = offset; + cmd_reg_read.mb = mb; + cmd_reg_read.value = 0; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_REG_READ, &cmd_reg_read, + sizeof(struct cam_cpas_hw_cmd_reg_read_write)); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + return rc; + } + + *value = cmd_reg_read.value; + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_reg_read); + +int cam_cpas_update_axi_vote(uint32_t client_handle, + struct cam_axi_vote *axi_vote) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!axi_vote) { + CAM_ERR(CAM_CPAS, "NULL axi vote"); + return -EINVAL; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_axi_vote cmd_axi_vote; + + cmd_axi_vote.client_handle = client_handle; + cmd_axi_vote.axi_vote = axi_vote; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_AXI_VOTE, &cmd_axi_vote, + sizeof(struct cam_cpas_hw_cmd_axi_vote)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_update_axi_vote); + +int cam_cpas_update_ahb_vote(uint32_t client_handle, + struct cam_ahb_vote *ahb_vote) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + struct cam_cpas_hw_cmd_ahb_vote cmd_ahb_vote; + + cmd_ahb_vote.client_handle = client_handle; + cmd_ahb_vote.ahb_vote = ahb_vote; + + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_AHB_VOTE, &cmd_ahb_vote, + sizeof(struct cam_cpas_hw_cmd_ahb_vote)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_update_ahb_vote); + +int cam_cpas_stop(uint32_t client_handle) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.stop) { + struct cam_cpas_hw_cmd_stop cmd_hw_stop; + + cmd_hw_stop.client_handle = client_handle; + + rc = g_cpas_intf->hw_intf->hw_ops.stop( + g_cpas_intf->hw_intf->hw_priv, &cmd_hw_stop, + sizeof(struct cam_cpas_hw_cmd_stop)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in stop, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid stop ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_stop); + +int cam_cpas_start(uint32_t client_handle, + struct cam_ahb_vote *ahb_vote, struct cam_axi_vote *axi_vote) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (!axi_vote) { + CAM_ERR(CAM_CPAS, "NULL axi vote"); + return -EINVAL; + } + + if (g_cpas_intf->hw_intf->hw_ops.start) { + struct cam_cpas_hw_cmd_start cmd_hw_start; + + cmd_hw_start.client_handle = client_handle; + cmd_hw_start.ahb_vote = ahb_vote; + cmd_hw_start.axi_vote = axi_vote; + + rc = g_cpas_intf->hw_intf->hw_ops.start( + g_cpas_intf->hw_intf->hw_priv, &cmd_hw_start, + sizeof(struct cam_cpas_hw_cmd_start)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in start, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid start ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_start); + +int cam_cpas_unregister_client(uint32_t client_handle) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_UNREGISTER_CLIENT, + &client_handle, sizeof(uint32_t)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_unregister_client); + +int cam_cpas_register_client( + struct cam_cpas_register_params *register_params) +{ + int rc; + + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + if (g_cpas_intf->hw_intf->hw_ops.process_cmd) { + rc = g_cpas_intf->hw_intf->hw_ops.process_cmd( + g_cpas_intf->hw_intf->hw_priv, + CAM_CPAS_HW_CMD_REGISTER_CLIENT, register_params, + sizeof(struct cam_cpas_register_params)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in process_cmd, rc=%d", rc); + } else { + CAM_ERR(CAM_CPAS, "Invalid process_cmd ops"); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(cam_cpas_register_client); + +int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf, + struct cam_control *cmd) +{ + int rc = 0; + + if (!cmd) { + CAM_ERR(CAM_CPAS, "Invalid input cmd"); + return -EINVAL; + } + + switch (cmd->op_code) { + case CAM_QUERY_CAP: { + struct cam_cpas_query_cap query; + + rc = copy_from_user(&query, u64_to_user_ptr(cmd->handle), + sizeof(query)); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in copy from user, rc=%d", + rc); + break; + } + + rc = cam_cpas_get_hw_info(&query.camera_family, + &query.camera_version, &query.cpas_version, + &query.reserved); + if (rc) + break; + + rc = copy_to_user(u64_to_user_ptr(cmd->handle), &query, + sizeof(query)); + if (rc) + CAM_ERR(CAM_CPAS, "Failed in copy to user, rc=%d", rc); + + break; + } + case CAM_SD_SHUTDOWN: + break; + default: + CAM_ERR(CAM_CPAS, "Unknown op code %d for CPAS", cmd->op_code); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_cpas_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + mutex_lock(&cpas_intf->intf_lock); + cpas_intf->open_cnt++; + CAM_DBG(CAM_CPAS, "CPAS Subdev open count %d", cpas_intf->open_cnt); + mutex_unlock(&cpas_intf->intf_lock); + + return 0; +} + +static int cam_cpas_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + mutex_lock(&cpas_intf->intf_lock); + cpas_intf->open_cnt--; + CAM_DBG(CAM_CPAS, "CPAS Subdev close count %d", cpas_intf->open_cnt); + mutex_unlock(&cpas_intf->intf_lock); + + return 0; +} + +static long cam_cpas_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc; + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_cpas_subdev_cmd(cpas_intf, (struct cam_control *) arg); + break; + default: + CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); + rc = -EINVAL; + break; + } + + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_cpas_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc; + struct cam_cpas_intf *cpas_intf = v4l2_get_subdevdata(sd); + + if (!cpas_intf || !cpas_intf->probe_done) { + CAM_ERR(CAM_CPAS, "CPAS not initialized"); + return -ENODEV; + } + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_CPAS, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_cpas_subdev_cmd(cpas_intf, &cmd_data); + break; + default: + CAM_ERR(CAM_CPAS, "Invalid command %d for CPAS!", cmd); + rc = -EINVAL; + break; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_CPAS, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static struct v4l2_subdev_core_ops cpas_subdev_core_ops = { + .ioctl = cam_cpas_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_cpas_subdev_compat_ioctl, +#endif +}; + +static const struct v4l2_subdev_ops cpas_subdev_ops = { + .core = &cpas_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cpas_subdev_intern_ops = { + .open = cam_cpas_subdev_open, + .close = cam_cpas_subdev_close, +}; + +static int cam_cpas_subdev_register(struct platform_device *pdev) +{ + int rc; + struct cam_subdev *subdev; + + if (!g_cpas_intf) + return -EINVAL; + + subdev = &g_cpas_intf->subdev; + + subdev->name = CAM_CPAS_DEV_NAME; + subdev->pdev = pdev; + subdev->ops = &cpas_subdev_ops; + subdev->internal_ops = &cpas_subdev_intern_ops; + subdev->token = g_cpas_intf; + subdev->sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + subdev->ent_function = CAM_CPAS_DEVICE_TYPE; + + rc = cam_register_subdev(subdev); + if (rc) { + CAM_ERR(CAM_CPAS, "failed register subdev: %s!", + CAM_CPAS_DEV_NAME); + return rc; + } + + platform_set_drvdata(g_cpas_intf->pdev, g_cpas_intf); + return rc; +} + +static int cam_cpas_dev_probe(struct platform_device *pdev) +{ + struct cam_cpas_hw_caps *hw_caps; + struct cam_hw_intf *hw_intf; + int rc; + + if (g_cpas_intf) { + CAM_ERR(CAM_CPAS, "cpas dev proble already done"); + return -EALREADY; + } + + g_cpas_intf = kzalloc(sizeof(*g_cpas_intf), GFP_KERNEL); + if (!g_cpas_intf) + return -ENOMEM; + + mutex_init(&g_cpas_intf->intf_lock); + g_cpas_intf->pdev = pdev; + + rc = cam_cpas_hw_probe(pdev, &g_cpas_intf->hw_intf); + if (rc || (g_cpas_intf->hw_intf == NULL)) { + CAM_ERR(CAM_CPAS, "Failed in hw probe, rc=%d", rc); + goto error_destroy_mem; + } + + hw_intf = g_cpas_intf->hw_intf; + hw_caps = &g_cpas_intf->hw_caps; + if (hw_intf->hw_ops.get_hw_caps) { + rc = hw_intf->hw_ops.get_hw_caps(hw_intf->hw_priv, + hw_caps, sizeof(struct cam_cpas_hw_caps)); + if (rc) { + CAM_ERR(CAM_CPAS, "Failed in get_hw_caps, rc=%d", rc); + goto error_hw_remove; + } + } else { + CAM_ERR(CAM_CPAS, "Invalid get_hw_caps ops"); + goto error_hw_remove; + } + + rc = cam_cpas_subdev_register(pdev); + if (rc) + goto error_hw_remove; + + g_cpas_intf->probe_done = true; + CAM_DBG(CAM_CPAS, + "CPAS INTF Probe success %d, %d.%d.%d, %d.%d.%d, 0x%x", + hw_caps->camera_family, hw_caps->camera_version.major, + hw_caps->camera_version.minor, hw_caps->camera_version.incr, + hw_caps->cpas_version.major, hw_caps->cpas_version.minor, + hw_caps->cpas_version.incr, hw_caps->camera_capability); + + return rc; + +error_hw_remove: + cam_cpas_hw_remove(g_cpas_intf->hw_intf); +error_destroy_mem: + mutex_destroy(&g_cpas_intf->intf_lock); + kfree(g_cpas_intf); + g_cpas_intf = NULL; + CAM_ERR(CAM_CPAS, "CPAS probe failed"); + return rc; +} + +static int cam_cpas_dev_remove(struct platform_device *dev) +{ + if (!CAM_CPAS_INTF_INITIALIZED()) { + CAM_ERR(CAM_CPAS, "cpas intf not initialized"); + return -ENODEV; + } + + mutex_lock(&g_cpas_intf->intf_lock); + g_cpas_intf->probe_done = false; + cam_unregister_subdev(&g_cpas_intf->subdev); + cam_cpas_hw_remove(g_cpas_intf->hw_intf); + mutex_unlock(&g_cpas_intf->intf_lock); + mutex_destroy(&g_cpas_intf->intf_lock); + kfree(g_cpas_intf); + g_cpas_intf = NULL; + + return 0; +} + +static const struct of_device_id cam_cpas_dt_match[] = { + {.compatible = "qcom,cam-cpas"}, + {} +}; + +static struct platform_driver cam_cpas_driver = { + .probe = cam_cpas_dev_probe, + .remove = cam_cpas_dev_remove, + .driver = { + .name = CAM_CPAS_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_cpas_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_cpas_dev_init_module(void) +{ + return platform_driver_register(&cam_cpas_driver); +} + +static void __exit cam_cpas_dev_exit_module(void) +{ + platform_driver_unregister(&cam_cpas_driver); +} + +module_init(cam_cpas_dev_init_module); +module_exit(cam_cpas_dev_exit_module); +MODULE_DESCRIPTION("MSM CPAS driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_cpas/cam_cpas_soc.c b/techpack/camera/drivers/cam_cpas/cam_cpas_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..3b4e4fb25275c8e26935200b19a1ca234fd7e063 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cam_cpas_soc.c @@ -0,0 +1,713 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "cam_cpas_api.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpas_soc.h" + +static uint cpas_dump; +module_param(cpas_dump, uint, 0644); + + +void cam_cpas_dump_axi_vote_info( + const struct cam_cpas_client *cpas_client, + const char *identifier, + struct cam_axi_vote *axi_vote) +{ + int i; + + if (!cpas_dump) + return; + + if (!axi_vote || (axi_vote->num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT)) { + CAM_ERR(CAM_PERF, "Invalid num_paths %d", + axi_vote ? axi_vote->num_paths : -1); + return; + } + + for (i = 0; i < axi_vote->num_paths; i++) { + CAM_INFO(CAM_PERF, + "Client [%s][%d] : [%s], Path=[%d] [%d], camnoc[%llu], mnoc_ab[%llu], mnoc_ib[%llu]", + cpas_client->data.identifier, cpas_client->data.cell_index, + identifier, + axi_vote->axi_path[i].path_data_type, + axi_vote->axi_path[i].transac_type, + axi_vote->axi_path[i].camnoc_bw, + axi_vote->axi_path[i].mnoc_ab_bw, + axi_vote->axi_path[i].mnoc_ib_bw); + } + +} + +void cam_cpas_util_debug_parse_data( + struct cam_cpas_private_soc *soc_private) +{ + int i, j; + struct cam_cpas_tree_node *curr_node = NULL; + + if (!cpas_dump) + return; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + if (!soc_private->tree_node[i]) + break; + + curr_node = soc_private->tree_node[i]; + CAM_INFO(CAM_CPAS, + "NODE cell_idx: %d, level: %d, name: %s, axi_port_idx: %d, merge_type: %d, parent_name: %s", + curr_node->cell_idx, curr_node->level_idx, + curr_node->node_name, curr_node->axi_port_idx, + curr_node->merge_type, curr_node->parent_node ? + curr_node->parent_node->node_name : "no parent"); + + if (curr_node->level_idx) + continue; + + CAM_INFO(CAM_CPAS, "path_type: %d, transac_type: %s", + curr_node->path_data_type, + cam_cpas_axi_util_trans_type_to_string( + curr_node->path_trans_type)); + + for (j = 0; j < CAM_CPAS_PATH_DATA_MAX; j++) { + CAM_INFO(CAM_CPAS, "Constituent path: %d", + curr_node->constituent_paths[j] ? j : -1); + } + } + + CAM_INFO(CAM_CPAS, "NUMBER OF NODES PARSED: %d", i); +} + +int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core, + struct cam_cpas_private_soc *soc_private) +{ + int i = 0; + + for (i = 0; i < CAM_CPAS_MAX_TREE_NODES; i++) { + if (soc_private->tree_node[i]) { + of_node_put(soc_private->tree_node[i]->tree_dev_node); + kfree(soc_private->tree_node[i]); + soc_private->tree_node[i] = NULL; + } + } + + for (i = 0; i < CAM_CPAS_MAX_TREE_LEVELS; i++) { + if (soc_private->level_node[i]) { + of_node_put(soc_private->level_node[i]); + soc_private->level_node[i] = NULL; + } + } + + if (soc_private->camera_bus_node) { + of_node_put(soc_private->camera_bus_node); + soc_private->camera_bus_node = NULL; + } + + mutex_destroy(&cpas_core->tree_lock); + + return 0; +} + +static int cam_cpas_util_path_type_to_idx(uint32_t *path_data_type) +{ + if (*path_data_type >= CAM_CPAS_PATH_DATA_CONSO_OFFSET) + *path_data_type = CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT + + (*path_data_type % CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT); + else + *path_data_type %= CAM_CPAS_MAX_GRAN_PATHS_PER_CLIENT; + + if (*path_data_type >= CAM_CPAS_PATH_DATA_MAX) { + CAM_ERR(CAM_CPAS, "index Invalid: %d", path_data_type); + return -EINVAL; + } + + return 0; +} + +static int cam_cpas_update_camnoc_node(struct cam_cpas *cpas_core, + struct device_node *curr_node, + struct cam_cpas_tree_node *cpas_node_ptr, + int *camnoc_idx) + +{ + struct device_node *camnoc_node; + int rc; + + camnoc_node = of_find_node_by_name(curr_node, + "qcom,axi-port-camnoc"); + if (camnoc_node) { + + if (*camnoc_idx >= + CAM_CPAS_MAX_AXI_PORTS) { + CAM_ERR(CAM_CPAS, "CAMNOC axi index overshoot %d", + *camnoc_idx); + return -EINVAL; + } + + cpas_core->camnoc_axi_port[*camnoc_idx] + .axi_port_node = camnoc_node; + rc = of_property_read_string( + curr_node, + "qcom,axi-port-name", + &cpas_core->camnoc_axi_port[*camnoc_idx] + .axi_port_name); + + if (rc) { + CAM_ERR(CAM_CPAS, + "fail to read camnoc-port-name rc=%d", + rc); + return rc; + } + cpas_node_ptr->camnoc_axi_port_idx = *camnoc_idx; + cpas_core->num_camnoc_axi_ports++; + (*camnoc_idx)++; + } + return 0; +} + +static int cam_cpas_parse_node_tree(struct cam_cpas *cpas_core, + struct device_node *of_node, struct cam_cpas_private_soc *soc_private) +{ + struct device_node *camera_bus_node; + struct device_node *level_node; + struct device_node *curr_node; + struct device_node *parent_node; + struct device_node *mnoc_node; + int mnoc_idx = 0, camnoc_idx = 0; + uint32_t path_idx; + bool camnoc_max_needed = false; + struct cam_cpas_tree_node *curr_node_ptr = NULL; + struct cam_cpas_client *curr_client = NULL; + const char *client_name = NULL; + uint32_t client_idx = 0, cell_idx = 0, level_idx = 0; + int rc = 0, count = 0, i; + + camera_bus_node = of_find_node_by_name(of_node, "camera-bus-nodes"); + if (!camera_bus_node) { + CAM_ERR(CAM_CPAS, "Camera Bus node not found in cpas DT node"); + return -EINVAL; + } + + soc_private->camera_bus_node = camera_bus_node; + + for_each_available_child_of_node(camera_bus_node, level_node) { + rc = of_property_read_u32(level_node, "level-index", + &level_idx); + if (rc) { + CAM_ERR(CAM_CPAS, "Error raeding level idx rc: %d", rc); + return rc; + } + if (level_idx >= CAM_CPAS_MAX_TREE_LEVELS) { + CAM_ERR(CAM_CPAS, "Invalid level idx: %d", level_idx); + return -EINVAL; + } + + soc_private->level_node[level_idx] = level_node; + camnoc_max_needed = of_property_read_bool(level_node, + "camnoc-max-needed"); + + for_each_available_child_of_node(level_node, curr_node) { + curr_node_ptr = + kzalloc(sizeof(struct cam_cpas_tree_node), + GFP_KERNEL); + if (!curr_node_ptr) + return -ENOMEM; + + curr_node_ptr->tree_dev_node = curr_node; + rc = of_property_read_u32(curr_node, "cell-index", + &curr_node_ptr->cell_idx); + if (rc) { + CAM_ERR(CAM_CPAS, "Node index not found"); + return rc; + } + + if (curr_node_ptr->cell_idx >= + CAM_CPAS_MAX_TREE_NODES) { + CAM_ERR(CAM_CPAS, "Invalid cell idx: %d", + cell_idx); + return -EINVAL; + } + + soc_private->tree_node[curr_node_ptr->cell_idx] = + curr_node_ptr; + curr_node_ptr->level_idx = level_idx; + + rc = of_property_read_string(curr_node, "node-name", + &curr_node_ptr->node_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read node-name rc=%d", + rc); + return rc; + } + + curr_node_ptr->camnoc_max_needed = camnoc_max_needed; + rc = of_property_read_u32(curr_node, "bus-width-factor", + &curr_node_ptr->bus_width_factor); + if (rc) + curr_node_ptr->bus_width_factor = 1; + + rc = of_property_read_u32(curr_node, + "traffic-merge-type", + &curr_node_ptr->merge_type); + + curr_node_ptr->axi_port_idx = -1; + mnoc_node = of_find_node_by_name(curr_node, + "qcom,axi-port-mnoc"); + if (mnoc_node) { + if (mnoc_idx >= CAM_CPAS_MAX_AXI_PORTS) + return -EINVAL; + + cpas_core->axi_port[mnoc_idx].axi_port_node + = mnoc_node; + rc = of_property_read_string( + curr_node, "qcom,axi-port-name", + &cpas_core->axi_port[mnoc_idx] + .axi_port_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read mnoc-port-name rc=%d", + rc); + return rc; + } + cpas_core->axi_port + [mnoc_idx].ib_bw_voting_needed + = of_property_read_bool(curr_node, + "ib-bw-voting-needed"); + curr_node_ptr->axi_port_idx = mnoc_idx; + mnoc_idx++; + cpas_core->num_axi_ports++; + } + + if (!soc_private->control_camnoc_axi_clk) { + rc = cam_cpas_update_camnoc_node( + cpas_core, curr_node, curr_node_ptr, + &camnoc_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "Parse Camnoc port fail"); + return rc; + } + } + + rc = of_property_read_string(curr_node, + "client-name", &client_name); + if (!rc) { + rc = of_property_read_u32(curr_node, + "traffic-data", &curr_node_ptr->path_data_type); + if (rc) { + CAM_ERR(CAM_CPAS, + "Path Data type not found"); + return rc; + } + + rc = cam_cpas_util_path_type_to_idx( + &curr_node_ptr->path_data_type); + if (rc) + return rc; + + rc = of_property_read_u32(curr_node, + "traffic-transaction-type", + &curr_node_ptr->path_trans_type); + if (rc) { + CAM_ERR(CAM_CPAS, + "Path Transac type not found"); + return rc; + } + + if (curr_node_ptr->path_trans_type >= + CAM_CPAS_TRANSACTION_MAX) { + CAM_ERR(CAM_CPAS, + "Invalid transac type: %d", + curr_node_ptr->path_trans_type); + return -EINVAL; + } + + count = of_property_count_u32_elems(curr_node, + "constituent-paths"); + for (i = 0; i < count; i++) { + rc = of_property_read_u32_index( + curr_node, "constituent-paths", + i, &path_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "No constituent path at %d", i); + return rc; + } + + rc = cam_cpas_util_path_type_to_idx( + &path_idx); + if (rc) + return rc; + + curr_node_ptr->constituent_paths + [path_idx] = true; + } + + rc = cam_common_util_get_string_index( + soc_private->client_name, + soc_private->num_clients, + client_name, &client_idx); + if (rc) { + CAM_ERR(CAM_CPAS, + "client name not found in list: %s", + client_name); + return rc; + } + + if (client_idx >= CAM_CPAS_MAX_CLIENTS) + return -EINVAL; + + curr_client = + cpas_core->cpas_client[client_idx]; + curr_client->tree_node_valid = true; + curr_client->tree_node + [curr_node_ptr->path_data_type] + [curr_node_ptr->path_trans_type] = + curr_node_ptr; + CAM_DBG(CAM_CPAS, + "CLIENT NODE ADDED: %d %d %s", + curr_node_ptr->path_data_type, + curr_node_ptr->path_trans_type, + client_name); + } + + parent_node = of_parse_phandle(curr_node, + "parent-node", 0); + if (parent_node) { + of_property_read_u32(parent_node, "cell-index", + &cell_idx); + curr_node_ptr->parent_node = + soc_private->tree_node[cell_idx]; + } else { + CAM_DBG(CAM_CPAS, + "no parent node at this level"); + } + } + } + mutex_init(&cpas_core->tree_lock); + cam_cpas_util_debug_parse_data(soc_private); + + return 0; +} + + +int cam_cpas_get_hw_features(struct platform_device *pdev, + struct cam_cpas_private_soc *soc_private) +{ + struct device_node *of_node; + void *fuse; + uint32_t fuse_addr, fuse_bit; + uint32_t fuse_val = 0, feature_bit_pos; + int count = 0, i = 0; + + of_node = pdev->dev.of_node; + count = of_property_count_u32_elems(of_node, "cam_hw_fuse"); + + for (i = 0; (i + 3) <= count; i = i + 3) { + of_property_read_u32_index(of_node, "cam_hw_fuse", i, + &feature_bit_pos); + of_property_read_u32_index(of_node, "cam_hw_fuse", i + 1, + &fuse_addr); + of_property_read_u32_index(of_node, "cam_hw_fuse", i + 2, + &fuse_bit); + CAM_INFO(CAM_CPAS, "feature_bit 0x%x addr 0x%x, bit %d", + feature_bit_pos, fuse_addr, fuse_bit); + + fuse = ioremap(fuse_addr, 4); + if (fuse) { + fuse_val = cam_io_r(fuse); + if (fuse_val & BIT(fuse_bit)) + soc_private->feature_mask |= feature_bit_pos; + else + soc_private->feature_mask &= ~feature_bit_pos; + } + CAM_INFO(CAM_CPAS, "fuse %pK, fuse_val %x, feature_mask %x", + fuse, fuse_val, soc_private->feature_mask); + + } + + return 0; +} + +int cam_cpas_get_custom_dt_info(struct cam_hw_info *cpas_hw, + struct platform_device *pdev, struct cam_cpas_private_soc *soc_private) +{ + struct device_node *of_node; + int count = 0, i = 0, rc = 0; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + + if (!soc_private || !pdev) { + CAM_ERR(CAM_CPAS, "invalid input arg %pK %pK", + soc_private, pdev); + return -EINVAL; + } + + of_node = pdev->dev.of_node; + soc_private->feature_mask = 0xFFFFFFFF; + + rc = of_property_read_string(of_node, "arch-compat", + &soc_private->arch_compat); + if (rc) { + CAM_ERR(CAM_CPAS, "device %s failed to read arch-compat", + pdev->name); + return rc; + } + + cam_cpas_get_hw_features(pdev, soc_private); + + soc_private->camnoc_axi_min_ib_bw = 0; + rc = of_property_read_u64(of_node, + "camnoc-axi-min-ib-bw", + &soc_private->camnoc_axi_min_ib_bw); + if (rc == -EOVERFLOW) { + soc_private->camnoc_axi_min_ib_bw = 0; + rc = of_property_read_u32(of_node, + "camnoc-axi-min-ib-bw", + (u32 *)&soc_private->camnoc_axi_min_ib_bw); + } + + if (rc) { + CAM_DBG(CAM_CPAS, + "failed to read camnoc-axi-min-ib-bw rc:%d", rc); + soc_private->camnoc_axi_min_ib_bw = + CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + } + + CAM_DBG(CAM_CPAS, "camnoc-axi-min-ib-bw = %llu", + soc_private->camnoc_axi_min_ib_bw); + + soc_private->client_id_based = of_property_read_bool(of_node, + "client-id-based"); + + count = of_property_count_strings(of_node, "client-names"); + if (count <= 0) { + CAM_ERR(CAM_CPAS, "no client-names found"); + count = 0; + return -EINVAL; + } else if (count > CAM_CPAS_MAX_CLIENTS) { + CAM_ERR(CAM_CPAS, "Number of clients %d greater than max %d", + count, CAM_CPAS_MAX_CLIENTS); + count = 0; + return -EINVAL; + } + + soc_private->num_clients = count; + CAM_DBG(CAM_CPAS, + "arch-compat=%s, client_id_based = %d, num_clients=%d", + soc_private->arch_compat, soc_private->client_id_based, + soc_private->num_clients); + + for (i = 0; i < soc_private->num_clients; i++) { + rc = of_property_read_string_index(of_node, + "client-names", i, &soc_private->client_name[i]); + if (rc) { + CAM_ERR(CAM_CPAS, "no client-name at cnt=%d", i); + return -EINVAL; + } + + cpas_core->cpas_client[i] = + kzalloc(sizeof(struct cam_cpas_client), GFP_KERNEL); + if (!cpas_core->cpas_client[i]) { + rc = -ENOMEM; + goto cleanup_clients; + } + + CAM_DBG(CAM_CPAS, "Client[%d] : %s", i, + soc_private->client_name[i]); + } + + soc_private->control_camnoc_axi_clk = of_property_read_bool(of_node, + "control-camnoc-axi-clk"); + + if (soc_private->control_camnoc_axi_clk == true) { + rc = of_property_read_u32(of_node, "camnoc-bus-width", + &soc_private->camnoc_bus_width); + if (rc || (soc_private->camnoc_bus_width == 0)) { + CAM_ERR(CAM_CPAS, "Bus width not found rc=%d, %d", + rc, soc_private->camnoc_bus_width); + goto cleanup_clients; + } + + rc = of_property_read_u32(of_node, + "camnoc-axi-clk-bw-margin-perc", + &soc_private->camnoc_axi_clk_bw_margin); + + if (rc) { + /* this is not fatal, overwrite rc */ + rc = 0; + soc_private->camnoc_axi_clk_bw_margin = 0; + } + } + + CAM_DBG(CAM_CPAS, + "control_camnoc_axi_clk=%d, width=%d, margin=%d", + soc_private->control_camnoc_axi_clk, + soc_private->camnoc_bus_width, + soc_private->camnoc_axi_clk_bw_margin); + + count = of_property_count_u32_elems(of_node, "vdd-corners"); + if ((count > 0) && (count <= CAM_REGULATOR_LEVEL_MAX) && + (of_property_count_strings(of_node, "vdd-corner-ahb-mapping") == + count)) { + const char *ahb_string; + + for (i = 0; i < count; i++) { + rc = of_property_read_u32_index(of_node, "vdd-corners", + i, &soc_private->vdd_ahb[i].vdd_corner); + if (rc) { + CAM_ERR(CAM_CPAS, + "vdd-corners failed at index=%d", i); + rc = -ENODEV; + goto cleanup_clients; + } + + rc = of_property_read_string_index(of_node, + "vdd-corner-ahb-mapping", i, &ahb_string); + if (rc) { + CAM_ERR(CAM_CPAS, + "no ahb-mapping at index=%d", i); + rc = -ENODEV; + goto cleanup_clients; + } + + rc = cam_soc_util_get_level_from_string(ahb_string, + &soc_private->vdd_ahb[i].ahb_level); + if (rc) { + CAM_ERR(CAM_CPAS, + "invalid ahb-string at index=%d", i); + rc = -EINVAL; + goto cleanup_clients; + } + + CAM_DBG(CAM_CPAS, + "Vdd-AHB mapping [%d] : [%d] [%s] [%d]", i, + soc_private->vdd_ahb[i].vdd_corner, + ahb_string, soc_private->vdd_ahb[i].ahb_level); + } + + soc_private->num_vdd_ahb_mapping = count; + } + + rc = cam_cpas_parse_node_tree(cpas_core, of_node, soc_private); + if (rc) { + CAM_ERR(CAM_CPAS, "Node tree parsing failed rc: %d", rc); + goto cleanup_tree; + } + + return 0; + +cleanup_tree: + cam_cpas_node_tree_cleanup(cpas_core, soc_private); +cleanup_clients: + cam_cpas_util_client_cleanup(cpas_hw); + return rc; +} + +int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, struct cam_hw_info *cpas_hw) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in get_dt_properties, rc=%d", rc); + return rc; + } + + if (soc_info->irq_line && !irq_handler) { + CAM_ERR(CAM_CPAS, "Invalid IRQ handler"); + return -EINVAL; + } + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + cpas_hw); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in request_platform_resource, rc=%d", + rc); + return rc; + } + + soc_info->soc_private = kzalloc(sizeof(struct cam_cpas_private_soc), + GFP_KERNEL); + if (!soc_info->soc_private) { + rc = -ENOMEM; + goto release_res; + } + + rc = cam_cpas_get_custom_dt_info(cpas_hw, soc_info->pdev, + soc_info->soc_private); + if (rc) { + CAM_ERR(CAM_CPAS, "failed in get_custom_info, rc=%d", rc); + goto free_soc_private; + } + + return rc; + +free_soc_private: + kfree(soc_info->soc_private); +release_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} + +int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_CPAS, "release platform failed, rc=%d", rc); + + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; + + return rc; +} + +int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info, + enum cam_vote_level default_level) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + default_level, true); + if (rc) + CAM_ERR(CAM_CPAS, "enable platform resource failed, rc=%d", rc); + + return rc; +} + +int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, + disable_clocks, disable_irq); + if (rc) + CAM_ERR(CAM_CPAS, "disable platform failed, rc=%d", rc); + + return rc; +} + +int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_irq_disable(soc_info); + if (rc) + CAM_ERR(CAM_CPAS, "disable irq failed, rc=%d", rc); + + return rc; +} diff --git a/techpack/camera/drivers/cam_cpas/cam_cpas_soc.h b/techpack/camera/drivers/cam_cpas/cam_cpas_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..503efc20e8b828be6b19e89345c9a1416223d4dd --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cam_cpas_soc.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_SOC_H_ +#define _CAM_CPAS_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_cpas_hw.h" + +#define CAM_REGULATOR_LEVEL_MAX 16 +#define CAM_CPAS_MAX_TREE_NODES 50 + +/** + * struct cam_cpas_vdd_ahb_mapping : Voltage to ahb level mapping + * + * @vdd_corner : Voltage corner value + * @ahb_level : AHB vote level corresponds to this vdd_corner + * + */ +struct cam_cpas_vdd_ahb_mapping { + unsigned int vdd_corner; + enum cam_vote_level ahb_level; +}; + +/** + * struct cpas_tree_node: Generic cpas tree node for BW voting + * + * @cell_idx: Index to identify node from device tree and its parent + * @level_idx: Index to identify at what level the node is present + * @axi_port_idx: Index to identify which axi port to vote the consolidated bw + * @camnoc_axi_port_idx: Index to find which axi port to vote consolidated bw + * @path_data_type: Traffic type info from device tree (ife-vid, ife-disp etc) + * @path_trans_type: Transaction type info from device tree (rd, wr) + * @merge_type: Traffic merge type (calculation info) from device tree + * @bus_width_factor: Factor for accounting bus width in CAMNOC bw calculation + * @camnoc_bw: CAMNOC bw value at current node + * @mnoc_ab_bw: MNOC AB bw value at current node + * @mnoc_ib_bw: MNOC IB bw value at current node + * @ddr_ab_bw: DDR AB bw value at current node + * @ddr_ib_bw: DDR IB bw value at current node + * @camnoc_max_needed: If node is needed for CAMNOC BW calculation then true + * @constituent_paths: Constituent paths presence info from device tree + * Ex: For CAM_CPAS_PATH_DATA_IFE_UBWC_STATS, index corresponding to + * CAM_CPAS_PATH_DATA_IFE_VID, CAM_CPAS_PATH_DATA_IFE_DISP and + * CAM_CPAS_PATH_DATA_IFE_STATS + * @tree_dev_node: Device node from devicetree for current tree node + * @parent_node: Pointer to node one or more level above the current level + * (starting from end node of cpas client) + * + */ +struct cam_cpas_tree_node { + uint32_t cell_idx; + uint32_t level_idx; + int axi_port_idx; + int camnoc_axi_port_idx; + const char *node_name; + uint32_t path_data_type; + uint32_t path_trans_type; + uint32_t merge_type; + uint32_t bus_width_factor; + uint64_t camnoc_bw; + uint64_t mnoc_ab_bw; + uint64_t mnoc_ib_bw; + uint64_t ddr_ab_bw; + uint64_t ddr_ib_bw; + bool camnoc_max_needed; + bool constituent_paths[CAM_CPAS_PATH_DATA_MAX]; + struct device_node *tree_dev_node; + struct cam_cpas_tree_node *parent_node; +}; + +/** + * struct cam_cpas_private_soc : CPAS private DT info + * + * @arch_compat: ARCH compatible string + * @client_id_based: Whether clients are id based + * @num_clients: Number of clients supported + * @client_name: Client names + * @tree_node: Array of pointers to all tree nodes required to calculate + * axi bw, arranged with help of cell index in device tree + * @camera_bus_node: Device tree node from cpas node + * @level_node: Device tree node for each level in camera_bus_node + * @num_vdd_ahb_mapping : Number of vdd to ahb level mapping supported + * @vdd_ahb : AHB level mapping info for the supported vdd levels + * @control_camnoc_axi_clk : Whether CPAS driver need to set camnoc axi clk freq + * @camnoc_bus_width : CAMNOC Bus width + * @camnoc_axi_clk_bw_margin : BW Margin in percentage to add while calculating + * camnoc axi clock + * @camnoc_axi_min_ib_bw: Min camnoc BW which varies based on target + * @feature_mask: feature mask value for hw supported features + * + */ +struct cam_cpas_private_soc { + const char *arch_compat; + bool client_id_based; + uint32_t num_clients; + const char *client_name[CAM_CPAS_MAX_CLIENTS]; + struct cam_cpas_tree_node *tree_node[CAM_CPAS_MAX_TREE_NODES]; + struct device_node *camera_bus_node; + struct device_node *level_node[CAM_CPAS_MAX_TREE_LEVELS]; + uint32_t num_vdd_ahb_mapping; + struct cam_cpas_vdd_ahb_mapping vdd_ahb[CAM_REGULATOR_LEVEL_MAX]; + bool control_camnoc_axi_clk; + uint32_t camnoc_bus_width; + uint32_t camnoc_axi_clk_bw_margin; + uint64_t camnoc_axi_min_ib_bw; + uint32_t feature_mask; +}; + +void cam_cpas_util_debug_parse_data(struct cam_cpas_private_soc *soc_private); +void cam_cpas_dump_axi_vote_info( + const struct cam_cpas_client *cpas_client, + const char *identifier, + struct cam_axi_vote *axi_vote); +int cam_cpas_node_tree_cleanup(struct cam_cpas *cpas_core, + struct cam_cpas_private_soc *soc_private); +int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, struct cam_hw_info *cpas_hw); +int cam_cpas_soc_deinit_resources(struct cam_hw_soc_info *soc_info); +int cam_cpas_soc_enable_resources(struct cam_hw_soc_info *soc_info, + enum cam_vote_level default_level); +int cam_cpas_soc_disable_resources(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq); +int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info); +#endif /* _CAM_CPAS_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/camss_top/Makefile b/techpack/camera/drivers/cam_cpas/camss_top/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..de11b7136563c463ceed5fa63cf583c730f789c1 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/camss_top/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_camsstop_hw.o diff --git a/techpack/camera/drivers/cam_cpas/camss_top/cam_camsstop_hw.c b/techpack/camera/drivers/cam_cpas/camss_top/cam_camsstop_hw.c new file mode 100644 index 0000000000000000000000000000000000000000..b7f3550bc6324d9f8f444ecf4711c88a86acef9f --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/camss_top/cam_camsstop_hw.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpas_soc.h" + +int cam_camsstop_get_hw_info(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CAMSS]; + uint32_t reg_value; + + if (reg_indx == -1) + return -EINVAL; + + hw_caps->camera_family = CAM_FAMILY_CAMERA_SS; + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0); + hw_caps->camera_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + hw_caps->camera_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->camera_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + CAM_DBG(CAM_FD, "Family %d, version %d.%d.%d", + hw_caps->camera_family, hw_caps->camera_version.major, + hw_caps->camera_version.minor, hw_caps->camera_version.incr); + + return 0; +} + +int cam_camsstop_setup_regbase_indices(struct cam_hw_soc_info *soc_info, + int32_t regbase_index[], int32_t num_reg_map) +{ + uint32_t index; + int rc; + + if (num_reg_map > CAM_CPAS_REG_MAX) { + CAM_ERR(CAM_CPAS, "invalid num_reg_map=%d", num_reg_map); + return -EINVAL; + } + + if (soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) { + CAM_ERR(CAM_CPAS, "invalid num_mem_block=%d", + soc_info->num_mem_block); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "cam_camss", &index); + if ((rc == 0) && (index < num_reg_map)) { + regbase_index[CAM_CPAS_REG_CAMSS] = index; + } else { + CAM_ERR(CAM_CPAS, "regbase not found for CAM_CPAS_REG_CAMSS"); + return -EINVAL; + } + + return 0; +} + +int cam_camsstop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops) +{ + if (!internal_ops) { + CAM_ERR(CAM_CPAS, "invalid NULL param"); + return -EINVAL; + } + + internal_ops->get_hw_info = cam_camsstop_get_hw_info; + internal_ops->init_hw_version = NULL; + internal_ops->handle_irq = NULL; + internal_ops->setup_regbase = cam_camsstop_setup_regbase_indices; + internal_ops->power_on = NULL; + internal_ops->power_off = NULL; + + return 0; +} diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/Makefile b/techpack/camera/drivers/cam_cpas/cpas_top/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0306b14ef14a03890d8365425421bf10f1c89e9a --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpastop_hw.o diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c b/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c new file mode 100644 index 0000000000000000000000000000000000000000..1f52e1993a5c9b176ff390b51183ea9d25d158aa --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/slab.h> + +#include <soc/qcom/scm.h> + +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpastop_hw.h" +#include "cam_io_util.h" +#include "cam_cpas_soc.h" +#include "cpastop100.h" +#include "cpastop_v150_100.h" +#include "cpastop_v170_110.h" +#include "cpastop_v175_100.h" +#include "cpastop_v175_101.h" +#include "cpastop_v175_120.h" +#include "cpastop_v175_130.h" +#include "cpastop_v480_100.h" + +struct cam_camnoc_info *camnoc_info; + +#define CAMNOC_SLAVE_MAX_ERR_CODE 7 +static const char * const camnoc_salve_err_code[] = { + "Target Error", /* err code 0 */ + "Address decode error", /* err code 1 */ + "Unsupported request", /* err code 2 */ + "Disconnected target", /* err code 3 */ + "Security violation", /* err code 4 */ + "Hidden security violation", /* err code 5 */ + "Timeout Error", /* err code 6 */ + "Unknown Error", /* unknown err code */ +}; + +static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP]; + uint32_t reg_value; + + if (reg_indx == -1) + return -EINVAL; + + hw_caps->camera_family = CAM_FAMILY_CPAS_SS; + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0); + hw_caps->camera_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xff0000, 0x10); + hw_caps->camera_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xff00, 0x8); + hw_caps->camera_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x4); + hw_caps->cpas_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + hw_caps->cpas_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->cpas_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x8); + hw_caps->camera_capability = reg_value; + + CAM_DBG(CAM_FD, "Family %d, version %d.%d.%d, cpas %d.%d.%d, cap 0x%x", + hw_caps->camera_family, hw_caps->camera_version.major, + hw_caps->camera_version.minor, hw_caps->camera_version.incr, + hw_caps->cpas_version.major, hw_caps->cpas_version.minor, + hw_caps->cpas_version.incr, hw_caps->camera_capability); + + soc_info->hw_version = CAM_CPAS_TITAN_NONE; + + if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 1) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V110; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V120; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 5)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 1)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V120; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 3) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V130; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 5) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_150_V100; + } else if ((hw_caps->camera_version.major == 4) && + (hw_caps->camera_version.minor == 8) && + (hw_caps->camera_version.incr == 0)) { + soc_info->hw_version = CAM_CPAS_TITAN_480_V100; + } + + CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); + + return 0; +} + +static int cam_cpastop_setup_regbase_indices(struct cam_hw_soc_info *soc_info, + int32_t regbase_index[], int32_t num_reg_map) +{ + uint32_t index; + int rc; + + if (num_reg_map > CAM_CPAS_REG_MAX) { + CAM_ERR(CAM_CPAS, "invalid num_reg_map=%d", num_reg_map); + return -EINVAL; + } + + if (soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) { + CAM_ERR(CAM_CPAS, "invalid num_mem_block=%d", + soc_info->num_mem_block); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "cam_cpas_top", &index); + if ((rc == 0) && (index < num_reg_map)) { + regbase_index[CAM_CPAS_REG_CPASTOP] = index; + } else { + CAM_ERR(CAM_CPAS, "regbase not found for CPASTOP, rc=%d, %d %d", + rc, index, num_reg_map); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "cam_camnoc", &index); + if ((rc == 0) && (index < num_reg_map)) { + regbase_index[CAM_CPAS_REG_CAMNOC] = index; + } else { + CAM_ERR(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d", + rc, index, num_reg_map); + return -EINVAL; + } + + return 0; +} + +static int cam_cpastop_handle_errlogger(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info, + struct cam_camnoc_irq_slave_err_data *slave_err) +{ + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + int err_code_index = 0; + + if (!camnoc_info->err_logger) { + CAM_ERR_RATE_LIMIT(CAM_CPAS, "Invalid err logger info"); + return -EINVAL; + } + + slave_err->mainctrl.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->mainctrl); + + slave_err->errvld.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errvld); + + slave_err->errlog0_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog0_low); + + slave_err->errlog0_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog0_high); + + slave_err->errlog1_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog1_low); + + slave_err->errlog1_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog1_high); + + slave_err->errlog2_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog2_low); + + slave_err->errlog2_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog2_high); + + slave_err->errlog3_low.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog3_low); + + slave_err->errlog3_high.value = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->err_logger->errlog3_high); + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "Possible memory configuration issue, fault at SMMU raised as CAMNOC SLAVE_IRQ"); + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "mainctrl[0x%x 0x%x] errvld[0x%x 0x%x] stall_en=%d, fault_en=%d, err_vld=%d", + camnoc_info->err_logger->mainctrl, + slave_err->mainctrl.value, + camnoc_info->err_logger->errvld, + slave_err->errvld.value, + slave_err->mainctrl.stall_en, + slave_err->mainctrl.fault_en, + slave_err->errvld.err_vld); + + err_code_index = slave_err->errlog0_low.err_code; + if (err_code_index > CAMNOC_SLAVE_MAX_ERR_CODE) + err_code_index = CAMNOC_SLAVE_MAX_ERR_CODE; + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "errlog0 low[0x%x 0x%x] high[0x%x 0x%x] loginfo_vld=%d, word_error=%d, non_secure=%d, device=%d, opc=%d, err_code=%d(%s) sizef=%d, addr_space=%d, len1=%d", + camnoc_info->err_logger->errlog0_low, + slave_err->errlog0_low.value, + camnoc_info->err_logger->errlog0_high, + slave_err->errlog0_high.value, + slave_err->errlog0_low.loginfo_vld, + slave_err->errlog0_low.word_error, + slave_err->errlog0_low.non_secure, + slave_err->errlog0_low.device, + slave_err->errlog0_low.opc, + slave_err->errlog0_low.err_code, + camnoc_salve_err_code[err_code_index], + slave_err->errlog0_low.sizef, + slave_err->errlog0_low.addr_space, + slave_err->errlog0_high.len1); + + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "errlog1_low[0x%x 0x%x] errlog1_high[0x%x 0x%x] errlog2_low[0x%x 0x%x] errlog2_high[0x%x 0x%x] errlog3_low[0x%x 0x%x] errlog3_high[0x%x 0x%x]", + camnoc_info->err_logger->errlog1_low, + slave_err->errlog1_low.value, + camnoc_info->err_logger->errlog1_high, + slave_err->errlog1_high.value, + camnoc_info->err_logger->errlog2_low, + slave_err->errlog2_low.value, + camnoc_info->err_logger->errlog2_high, + slave_err->errlog2_high.value, + camnoc_info->err_logger->errlog3_low, + slave_err->errlog3_low.value, + camnoc_info->err_logger->errlog3_high, + slave_err->errlog3_high.value); + + return 0; +} + +static int cam_cpastop_handle_ubwc_enc_err(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info, int i, + struct cam_camnoc_irq_ubwc_enc_data *enc_err) +{ + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + + enc_err->encerr_status.value = + cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->irq_err[i].err_status.offset); + + /* Let clients handle the UBWC errors */ + CAM_DBG(CAM_CPAS, + "ubwc enc err [%d]: offset[0x%x] value[0x%x]", + i, camnoc_info->irq_err[i].err_status.offset, + enc_err->encerr_status.value); + + return 0; +} + +static int cam_cpastop_handle_ubwc_dec_err(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info, int i, + struct cam_camnoc_irq_ubwc_dec_data *dec_err) +{ + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + + dec_err->decerr_status.value = + cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->irq_err[i].err_status.offset); + + /* Let clients handle the UBWC errors */ + CAM_DBG(CAM_CPAS, + "ubwc dec err status [%d]: offset[0x%x] value[0x%x] thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d", + i, camnoc_info->irq_err[i].err_status.offset, + dec_err->decerr_status.value, + dec_err->decerr_status.thr_err, + dec_err->decerr_status.fcl_err, + dec_err->decerr_status.len_md_err, + dec_err->decerr_status.format_err); + + return 0; +} + +static int cam_cpastop_handle_ahb_timeout_err(struct cam_hw_info *cpas_hw, + struct cam_camnoc_irq_ahb_timeout_data *ahb_err) +{ + CAM_ERR_RATE_LIMIT(CAM_CPAS, "ahb timeout error"); + + return 0; +} + +static int cam_cpastop_disable_test_irq(struct cam_hw_info *cpas_hw) +{ + camnoc_info->irq_sbm->sbm_clear.value &= ~0x4; + camnoc_info->irq_sbm->sbm_enable.value &= ~0x100; + camnoc_info->irq_err[CAM_CAMNOC_HW_IRQ_CAMNOC_TEST].enable = false; + + return 0; +} + +static int cam_cpastop_reset_irq(struct cam_hw_info *cpas_hw) +{ + int i; + + if (camnoc_info->irq_sbm->sbm_enable.enable == false) + return 0; + + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_sbm->sbm_clear); + for (i = 0; i < camnoc_info->irq_err_size; i++) { + if (camnoc_info->irq_err[i].enable) + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_err[i].err_clear); + } + + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_sbm->sbm_enable); + for (i = 0; i < camnoc_info->irq_err_size; i++) { + if (camnoc_info->irq_err[i].enable) + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->irq_err[i].err_enable); + } + + return 0; +} + +static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core, + struct cam_cpas_irq_data *irq_data) +{ + int i; + struct cam_cpas_client *cpas_client; + bool error_handled = false; + + CAM_DBG(CAM_CPAS, + "Notify CB : num_clients=%d, registered=%d, started=%d", + cpas_core->num_clients, cpas_core->registered_clients, + cpas_core->streamon_clients); + + for (i = 0; i < cpas_core->num_clients; i++) { + if (CAM_CPAS_CLIENT_STARTED(cpas_core, i)) { + cpas_client = cpas_core->cpas_client[i]; + if (cpas_client->data.cam_cpas_client_cb) { + CAM_DBG(CAM_CPAS, + "Calling client CB %d : %d", + i, irq_data->irq_type); + error_handled = + cpas_client->data.cam_cpas_client_cb( + cpas_client->data.client_handle, + cpas_client->data.userdata, + irq_data); + if (error_handled) + break; + } + } + } +} + +static void cam_cpastop_work(struct work_struct *work) +{ + struct cam_cpas_work_payload *payload; + struct cam_hw_info *cpas_hw; + struct cam_cpas *cpas_core; + struct cam_hw_soc_info *soc_info; + int i; + enum cam_camnoc_hw_irq_type irq_type; + struct cam_cpas_irq_data irq_data; + + payload = container_of(work, struct cam_cpas_work_payload, work); + if (!payload) { + CAM_ERR(CAM_CPAS, "NULL payload"); + return; + } + + cpas_hw = payload->hw; + cpas_core = (struct cam_cpas *) cpas_hw->core_info; + soc_info = &cpas_hw->soc_info; + + if (!atomic_inc_not_zero(&cpas_core->irq_count)) { + CAM_ERR(CAM_CPAS, "CPAS off"); + return; + } + + for (i = 0; i < camnoc_info->irq_err_size; i++) { + if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) && + (camnoc_info->irq_err[i].enable)) { + irq_type = camnoc_info->irq_err[i].irq_type; + CAM_ERR_RATE_LIMIT(CAM_CPAS, + "Error occurred, type=%d", irq_type); + memset(&irq_data, 0x0, sizeof(irq_data)); + irq_data.irq_type = (enum cam_camnoc_irq_type)irq_type; + + switch (irq_type) { + case CAM_CAMNOC_HW_IRQ_SLAVE_ERROR: + cam_cpastop_handle_errlogger( + cpas_core, soc_info, + &irq_data.u.slave_err); + break; + case CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: + cam_cpastop_handle_ubwc_enc_err( + cpas_core, soc_info, i, + &irq_data.u.enc_err); + break; + case CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR: + case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR: + cam_cpastop_handle_ubwc_dec_err( + cpas_core, soc_info, i, + &irq_data.u.dec_err); + break; + case CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT: + cam_cpastop_handle_ahb_timeout_err( + cpas_hw, &irq_data.u.ahb_err); + break; + case CAM_CAMNOC_HW_IRQ_CAMNOC_TEST: + CAM_DBG(CAM_CPAS, "TEST IRQ"); + break; + default: + CAM_ERR(CAM_CPAS, "Invalid IRQ type"); + break; + } + + cam_cpastop_notify_clients(cpas_core, &irq_data); + + payload->irq_status &= + ~camnoc_info->irq_err[i].sbm_port; + } + } + atomic_dec(&cpas_core->irq_count); + wake_up(&cpas_core->irq_count_wq); + CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count)); + + if (payload->irq_status) + CAM_ERR(CAM_CPAS, "IRQ not handled irq_status=0x%x", + payload->irq_status); + + kfree(payload); +} + +static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data) +{ + struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data; + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + struct cam_cpas_work_payload *payload; + + if (!atomic_inc_not_zero(&cpas_core->irq_count)) { + CAM_ERR(CAM_CPAS, "CPAS off"); + return IRQ_HANDLED; + } + + payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC); + if (!payload) + goto done; + + payload->irq_status = cam_io_r_mb( + soc_info->reg_map[camnoc_index].mem_base + + camnoc_info->irq_sbm->sbm_status.offset); + + CAM_DBG(CAM_CPAS, "IRQ callback, irq_status=0x%x", payload->irq_status); + + payload->hw = cpas_hw; + INIT_WORK((struct work_struct *)&payload->work, cam_cpastop_work); + + if (TEST_IRQ_ENABLE) + cam_cpastop_disable_test_irq(cpas_hw); + + cam_cpastop_reset_irq(cpas_hw); + + queue_work(cpas_core->work_queue, &payload->work); +done: + atomic_dec(&cpas_core->irq_count); + wake_up(&cpas_core->irq_count_wq); + + return IRQ_HANDLED; +} + +static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw) +{ + int i, reg_val; + struct cam_cpas_hw_errata_wa_list *errata_wa_list = + camnoc_info->errata_wa_list; + struct cam_cpas_hw_errata_wa *errata_wa = + &errata_wa_list->tcsr_camera_hf_sf_ares_glitch; + + cam_cpastop_reset_irq(cpas_hw); + for (i = 0; i < camnoc_info->specific_size; i++) { + if (camnoc_info->specific[i].enable) { + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].priority_lut_low); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].priority_lut_high); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].urgency); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].danger_lut); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].safe_lut); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].ubwc_ctl); + cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC, + &camnoc_info->specific[i].flag_out_set0_low); + } + } + + if (errata_wa->enable) { + reg_val = scm_io_read(errata_wa->data.reg_info.offset); + reg_val |= errata_wa->data.reg_info.value; + scm_io_write(errata_wa->data.reg_info.offset, reg_val); + } + + return 0; +} + +static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw) +{ + struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC]; + int rc = 0; + struct cam_cpas_hw_errata_wa_list *errata_wa_list = + camnoc_info->errata_wa_list; + + if (!errata_wa_list) + return 0; + + if (errata_wa_list->camnoc_flush_slave_pending_trans.enable) { + struct cam_cpas_hw_errata_wa *errata_wa = + &errata_wa_list->camnoc_flush_slave_pending_trans; + + rc = cam_io_poll_value_wmask( + soc_info->reg_map[camnoc_index].mem_base + + errata_wa->data.reg_info.offset, + errata_wa->data.reg_info.value, + errata_wa->data.reg_info.mask, + CAM_CPAS_POLL_RETRY_CNT, + CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS); + if (rc) { + CAM_DBG(CAM_CPAS, + "camnoc flush slave pending trans failed"); + /* Do not return error, passthrough */ + rc = 0; + } + } + + return rc; +} + +static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, + struct cam_cpas_hw_caps *hw_caps) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; + + CAM_DBG(CAM_CPAS, + "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d", + soc_info->hw_version, + hw_caps->camera_version.major, + hw_caps->camera_version.minor, + hw_caps->camera_version.incr, + hw_caps->cpas_version.major, + hw_caps->cpas_version.minor, + hw_caps->cpas_version.incr); + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_170_V100: + camnoc_info = &cam170_cpas100_camnoc_info; + break; + case CAM_CPAS_TITAN_170_V110: + camnoc_info = &cam170_cpas110_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V100: + camnoc_info = &cam175_cpas100_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V101: + camnoc_info = &cam175_cpas101_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V120: + camnoc_info = &cam175_cpas120_camnoc_info; + break; + case CAM_CPAS_TITAN_175_V130: + camnoc_info = &cam175_cpas130_camnoc_info; + break; + case CAM_CPAS_TITAN_150_V100: + camnoc_info = &cam150_cpas100_camnoc_info; + break; + case CAM_CPAS_TITAN_480_V100: + camnoc_info = &cam480_cpas100_camnoc_info; + break; + default: + CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", + hw_caps->camera_version.major, + hw_caps->camera_version.minor, + hw_caps->camera_version.incr); + rc = -EINVAL; + break; + } + + return 0; +} + +int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops) +{ + if (!internal_ops) { + CAM_ERR(CAM_CPAS, "invalid NULL param"); + return -EINVAL; + } + + internal_ops->get_hw_info = cam_cpastop_get_hw_info; + internal_ops->init_hw_version = cam_cpastop_init_hw_version; + internal_ops->handle_irq = cam_cpastop_handle_irq; + internal_ops->setup_regbase = cam_cpastop_setup_regbase_indices; + internal_ops->power_on = cam_cpastop_poweron; + internal_ops->power_off = cam_cpastop_poweroff; + + return 0; +} diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h b/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..a4d44a3feff6ba5946f860fb1ca47aedc975c30a --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -0,0 +1,285 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPASTOP_HW_H_ +#define _CAM_CPASTOP_HW_H_ + +#include "cam_cpas_api.h" +#include "cam_cpas_hw.h" + +/** + * enum cam_camnoc_hw_irq_type - Enum for camnoc error types + * + * @CAM_CAMNOC_HW_IRQ_SLAVE_ERROR: Each slave port in CAMNOC (3 QSB ports and + * 1 QHB port) has an error logger. The error + * observed at any slave port is logged into + * the error logger register and an IRQ is + * triggered + * @CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: Triggered if any error + * detected in the IFE UBWC- + * Stats encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error + * detected in the IFE0 UBWC + * encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error + * detected in the IFE1 or IFE3 + * UBWC encoder instance + * @CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: Triggered if any error + * detected in the IPE1/BPS read + * path decoder instance + * @CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR : Triggered if any error detected + * in the IPE0 read path decoder + * instance + * @CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR: Triggered if any error + * detected in the IPE/BPS + * UBWC decoder instance + * @CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: Triggered if any error + * detected in the IPE/BPS UBWC + * encoder instance + * @CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR: Triggered if any UBWC error + * is detected in IFE0 write path + * @CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR: Triggered if any UBWC error + * is detected in IFE1 write path + * @CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT : Triggered when the QHS_ICP + * slave times out after 4000 + * AHB cycles + * @CAM_CAMNOC_HW_IRQ_RESERVED1 : Reserved + * @CAM_CAMNOC_HW_IRQ_RESERVED2 : Reserved + * @CAM_CAMNOC_HW_IRQ_CAMNOC_TEST : To test the IRQ logic + */ +enum cam_camnoc_hw_irq_type { + CAM_CAMNOC_HW_IRQ_SLAVE_ERROR = + CAM_CAMNOC_IRQ_SLAVE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR = + CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR = + CAM_CAMNOC_IRQ_IPE0_UBWC_DECODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR = + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR = + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT = + CAM_CAMNOC_IRQ_AHB_TIMEOUT, + CAM_CAMNOC_HW_IRQ_RESERVED1, + CAM_CAMNOC_HW_IRQ_RESERVED2, + CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, +}; + +/** + * enum cam_camnoc_port_type - Enum for different camnoc hw ports. All CAMNOC + * settings like QoS, LUT mappings need to be configured for + * each of these ports. + * + * @CAM_CAMNOC_CDM: Indicates CDM HW connection to camnoc + * @CAM_CAMNOC_IFE02: Indicates IFE0, IFE2 HW connection to camnoc + * @CAM_CAMNOC_IFE13: Indicates IFE1, IFE3 HW connection to camnoc + * @CAM_CAMNOC_IFE_LINEAR: Indicates linear data from all IFEs to cammnoc + * @CAM_CAMNOC_IFE_UBWC_STATS: Indicates ubwc+stats from all IFEs to cammnoc + * @CAM_CAMNOC_IFE_RDI_WR: Indicates RDI write data from all IFEs to cammnoc + * @CAM_CAMNOC_IFE_RDI_RD: Indicates RDI read data from all IFEs to cammnoc + * @CAM_CAMNOC_IFE0123_RDI_WRITE: RDI write only for all IFEx + * @CAM_CAMNOC_IFE0_NRDI_WRITE: IFE0 non-RDI write + * @CAM_CAMNOC_IFE01_RDI_READ: IFE0/1 RDI READ + * @CAM_CAMNOC_IFE1_NRDI_WRITE: IFE1 non-RDI write + * @CAM_CAMNOC_IPE_BPS_LRME_READ: Indicates IPE, BPS, LRME Read HW + * connection to camnoc + * @CAM_CAMNOC_IPE_BPS_LRME_WRITE: Indicates IPE, BPS, LRME Write HW + * connection to camnoc + * @CAM_CAMNOC_IPE_VID_DISP_WRITE: Indicates IPE's VID/DISP Wrire HW + * connection to camnoc + * @CAM_CAMNOC_IPE0_RD: Indicates IPE's Read0 HW connection to camnoc + * @CAM_CAMNOC_IPE1_BPS_RD: Indicates IPE's Read1 + BPS Read HW connection + * to camnoc + * @CAM_CAMNOC_IPE_BPS_WR: Indicates IPE+BPS Write HW connection to camnoc + * @CAM_CAMNOC_JPEG: Indicates JPEG HW connection to camnoc + * @CAM_CAMNOC_FD: Indicates FD HW connection to camnoc + * @CAM_CAMNOC_ICP: Indicates ICP HW connection to camnoc + */ +enum cam_camnoc_port_type { + CAM_CAMNOC_CDM, + CAM_CAMNOC_IFE02, + CAM_CAMNOC_IFE13, + CAM_CAMNOC_IFE_LINEAR, + CAM_CAMNOC_IFE_UBWC_STATS, + CAM_CAMNOC_IFE_RDI_WR, + CAM_CAMNOC_IFE_RDI_RD, + CAM_CAMNOC_IFE0123_RDI_WRITE, + CAM_CAMNOC_IFE0_NRDI_WRITE, + CAM_CAMNOC_IFE01_RDI_READ, + CAM_CAMNOC_IFE1_NRDI_WRITE, + CAM_CAMNOC_IPE_BPS_LRME_READ, + CAM_CAMNOC_IPE_BPS_LRME_WRITE, + CAM_CAMNOC_IPE_VID_DISP_WRITE, + CAM_CAMNOC_IPE0_RD, + CAM_CAMNOC_IPE1_BPS_RD, + CAM_CAMNOC_IPE_BPS_WR, + CAM_CAMNOC_JPEG, + CAM_CAMNOC_FD, + CAM_CAMNOC_ICP, +}; + +/** + * struct cam_camnoc_specific : CPAS camnoc specific settings + * + * @port_type: Port type + * @enable: Whether to enable settings for this connection + * @priority_lut_low: Priority Low LUT mapping for this connection + * @priority_lut_high: Priority High LUT mapping for this connection + * @urgency: Urgency (QoS) settings for this connection + * @danger_lut: Danger LUT mapping for this connection + * @safe_lut: Safe LUT mapping for this connection + * @ubwc_ctl: UBWC control settings for this connection + * + */ +struct cam_camnoc_specific { + enum cam_camnoc_port_type port_type; + bool enable; + struct cam_cpas_reg priority_lut_low; + struct cam_cpas_reg priority_lut_high; + struct cam_cpas_reg urgency; + struct cam_cpas_reg danger_lut; + struct cam_cpas_reg safe_lut; + struct cam_cpas_reg ubwc_ctl; + struct cam_cpas_reg flag_out_set0_low; +}; + +/** + * struct cam_camnoc_irq_sbm : Sideband manager settings for all CAMNOC IRQs + * + * @sbm_enable: SBM settings for IRQ enable + * @sbm_status: SBM settings for IRQ status + * @sbm_clear: SBM settings for IRQ clear + * + */ +struct cam_camnoc_irq_sbm { + struct cam_cpas_reg sbm_enable; + struct cam_cpas_reg sbm_status; + struct cam_cpas_reg sbm_clear; +}; + +/** + * struct cam_camnoc_irq_err : Error settings specific to each CAMNOC IRQ + * + * @irq_type: Type of IRQ + * @enable: Whether to enable error settings for this IRQ + * @sbm_port: Corresponding SBM port for this IRQ + * @err_enable: Error enable settings for this IRQ + * @err_status: Error status settings for this IRQ + * @err_clear: Error clear settings for this IRQ + * + */ +struct cam_camnoc_irq_err { + enum cam_camnoc_hw_irq_type irq_type; + bool enable; + uint32_t sbm_port; + struct cam_cpas_reg err_enable; + struct cam_cpas_reg err_status; + struct cam_cpas_reg err_clear; +}; + +/** + * struct cam_cpas_hw_errata_wa : Struct for HW errata workaround info + * + * @enable: Whether to enable this errata workround + * @data: HW Errata workaround data + * + */ +struct cam_cpas_hw_errata_wa { + bool enable; + union { + struct cam_cpas_reg reg_info; + } data; +}; + +/** + * struct cam_cpas_hw_errata_wa_list : List of HW Errata workaround info + * + * @camnoc_flush_slave_pending_trans: Errata workaround info for flushing + * camnoc slave pending transactions before turning off CPAS_TOP gdsc + * @tcsr_camera_hf_sf_ares_glitch: Errata workaround info from ignoring + * erroneous signals at camera start + */ +struct cam_cpas_hw_errata_wa_list { + struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans; + struct cam_cpas_hw_errata_wa tcsr_camera_hf_sf_ares_glitch; +}; + +/** + * struct cam_camnoc_err_logger_info : CAMNOC error logger register offsets + * + * @mainctrl: Register offset for mainctrl + * @errvld: Register offset for errvld + * @errlog0_low: Register offset for errlog0_low + * @errlog0_high: Register offset for errlog0_high + * @errlog1_low: Register offset for errlog1_low + * @errlog1_high: Register offset for errlog1_high + * @errlog2_low: Register offset for errlog2_low + * @errlog2_high: Register offset for errlog2_high + * @errlog3_low: Register offset for errlog3_low + * @errlog3_high: Register offset for errlog3_high + * + */ +struct cam_camnoc_err_logger_info { + uint32_t mainctrl; + uint32_t errvld; + uint32_t errlog0_low; + uint32_t errlog0_high; + uint32_t errlog1_low; + uint32_t errlog1_high; + uint32_t errlog2_low; + uint32_t errlog2_high; + uint32_t errlog3_low; + uint32_t errlog3_high; +}; + +/** + * struct cam_camnoc_info : Overall CAMNOC settings info + * + * @specific: Pointer to CAMNOC SPECIFICTONTTPTR settings + * @specific_size: Array size of SPECIFICTONTTPTR settings + * @irq_sbm: Pointer to CAMNOC IRQ SBM settings + * @irq_err: Pointer to CAMNOC IRQ Error settings + * @irq_err_size: Array size of IRQ Error settings + * @err_logger: Pointer to CAMNOC IRQ Error logger read registers + * @errata_wa_list: HW Errata workaround info + * + */ +struct cam_camnoc_info { + struct cam_camnoc_specific *specific; + int specific_size; + struct cam_camnoc_irq_sbm *irq_sbm; + struct cam_camnoc_irq_err *irq_err; + int irq_err_size; + struct cam_camnoc_err_logger_info *err_logger; + struct cam_cpas_hw_errata_wa_list *errata_wa_list; +}; + +/** + * struct cam_cpas_work_payload : Struct for cpas work payload data + * + * @hw: Pointer to HW info + * @irq_status: IRQ status value + * @irq_data: IRQ data + * @work: Work handle + * + */ +struct cam_cpas_work_payload { + struct cam_hw_info *hw; + uint32_t irq_status; + uint32_t irq_data; + struct work_struct work; +}; + +#endif /* _CAM_CPASTOP_HW_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop100.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop100.h new file mode 100644 index 0000000000000000000000000000000000000000..2f444710e9f4c6e4120f5250a9ff551c927dc9d1 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop100.h @@ -0,0 +1,531 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP100_H_ +#define _CPASTOP100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x3, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x3, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = false, + } +}; + +static struct cam_camnoc_err_logger_info cam170_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam170_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = true, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +struct cam_camnoc_info cam170_cpas100_camnoc_info = { + .specific = &cam_cpas100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas100_camnoc_specific) / + sizeof(cam_cpas100_camnoc_specific[0]), + .irq_sbm = &cam_cpas100_irq_sbm, + .irq_err = &cam_cpas100_irq_err[0], + .irq_err_size = sizeof(cam_cpas100_irq_err) / + sizeof(cam_cpas100_irq_err[0]), + .err_logger = &cam170_cpas100_err_logger_offsets, + .errata_wa_list = &cam170_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP100_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v150_100.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v150_100.h new file mode 100644 index 0000000000000000000000000000000000000000..df9711e74379e7cc92b6e3fe6eb9a9ad6c4f2522 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v150_100.h @@ -0,0 +1,530 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V150_100_H_ +#define _CPASTOP_V150_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v150_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v150_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v150_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0x5, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam150_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam150_cpas100_camnoc_info = { + .specific = &cam_cpas_v150_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / + sizeof(cam_cpas_v150_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v150_100_irq_sbm, + .irq_err = &cam_cpas_v150_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v150_100_irq_err) / + sizeof(cam_cpas_v150_100_irq_err[0]), + .err_logger = &cam150_cpas100_err_logger_offsets, + .errata_wa_list = &cam150_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V150_100_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v170_110.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v170_110.h new file mode 100644 index 0000000000000000000000000000000000000000..788f571a3a1343d083a87649c89d60005421749d --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v170_110.h @@ -0,0 +1,538 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V170_110_H_ +#define _CPASTOP_V170_110_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas110_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas110_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas110_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam170_cpas110_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam170_cpas110_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam170_cpas110_camnoc_info = { + .specific = &cam_cpas110_camnoc_specific[0], + .specific_size = sizeof(cam_cpas110_camnoc_specific) / + sizeof(cam_cpas110_camnoc_specific[0]), + .irq_sbm = &cam_cpas110_irq_sbm, + .irq_err = &cam_cpas110_irq_err[0], + .irq_err_size = sizeof(cam_cpas110_irq_err) / + sizeof(cam_cpas110_irq_err[0]), + .err_logger = &cam170_cpas110_err_logger_offsets, + .errata_wa_list = &cam170_cpas110_errata_wa_list, +}; + +#endif /* _CPASTOP_V170_110_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_100.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_100.h new file mode 100644 index 0000000000000000000000000000000000000000..aae26b5a91789b73d4cddcc2f5846d34292786be --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_100.h @@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_100_H_ +#define _CPASTOP_V175_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas100_camnoc_info = { + .specific = &cam_cpas_v175_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v175_100_camnoc_specific) / + sizeof(cam_cpas_v175_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v175_100_irq_sbm, + .irq_err = &cam_cpas_v175_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v175_100_irq_err) / + sizeof(cam_cpas_v175_100_irq_err[0]), + .err_logger = &cam175_cpas100_err_logger_offsets, + .errata_wa_list = &cam175_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_100_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_101.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_101.h new file mode 100644 index 0000000000000000000000000000000000000000..7ec9bec36fd1f8c99980bfb0fa0cbe13079657c5 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_101.h @@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_101_H_ +#define _CPASTOP_V175_101_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_101_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_101_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_101_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x588, /* SPECIFIC_IFE02_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66666543, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x988, /* SPECIFIC_IFE13_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas101_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas101_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas101_camnoc_info = { + .specific = &cam_cpas_v175_101_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v175_101_camnoc_specific) / + sizeof(cam_cpas_v175_101_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v175_101_irq_sbm, + .irq_err = &cam_cpas_v175_101_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v175_101_irq_err) / + sizeof(cam_cpas_v175_101_irq_err[0]), + .err_logger = &cam175_cpas101_err_logger_offsets, + .errata_wa_list = &cam175_cpas101_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_101_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_120.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_120.h new file mode 100644 index 0000000000000000000000000000000000000000..5844c38ae52cf45282db8dcd018869b994d7129f --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_120.h @@ -0,0 +1,760 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_120_H_ +#define _CPASTOP_V175_120_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_120_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2240, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2248, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2280, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_120_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x4F08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x4F10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x4F18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3BA0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3B90, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3B98, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x55a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x5590, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x5598, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2F20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2F10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2F18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2Ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2B90, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2B98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_120_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* cdm_main_SpecificToNttpTr_Urgency_Low */ + .offset = 0x4238, + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4240, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4248, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0123_RDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_LOW */ + .offset = 0x3630, + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_HIGH */ + .offset = 0x3634, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3638, /* SPECIFIC_IFE0123_URGENCY_LOW */ + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3640, /* SPECIFIC_IFE0123_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3648, /* SPECIFIC_IFE0123_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A30, /* SPECIFIC_IFE0_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A34, /* SPECIFIC_IFE0_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3A38, /* SPECIFIC_IFE0_URGENCY_LOW */ + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A40, /* SPECIFIC_IFE0_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A48, /* SPECIFIC_IFE0_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3B88, /* SPECIFIC_IFE0_ENCCTL_LOW */ + .value = 1, + }, + }, + { + /* IFE0/1 RDI READ PATH */ + .port_type = CAM_CAMNOC_IFE01_RDI_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3230, /* SPECIFIC_IFE1_PRIORITYLUT_LOW */ + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3234, /* SPECIFIC_IFE1_PRIORITYLUT_HIGH */ + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3238, /* SPECIFIC_IFE1_URGENCY_LOW */ + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_MASK */ + .mask = 0x7, + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3240, /* SPECIFIC_IFE1_DANGERLUT_LOW */ + .value = 0x00000000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE1_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5430, /* SPECIFIC_IFE1_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE1_WR_PRIORITYLUT_HIGH */ + .offset = 0x5434, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x5438, /* SPECIFIC_IFE1_WR_URGENCY_LOW */ + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5440, /* SPECIFIC_IFE1_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5448, /* SPECIFIC_IFE1_WR_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5588, /* SPECIFIC_IFE1_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2E38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2F08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_VID_DISP_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_LOW */ + .offset = 0x5E30, + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_HIGH */ + .offset = 0x5E34, + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW */ + .offset = 0x5E38, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_MASK */ + .mask = 0x70, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC__IPE_VID_DISP_DANGERLUT_LOW */ + .offset = 0x5E40, + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_SAFELUT_LOW */ + .offset = 0x5E48, + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5F88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2630, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2634, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2638, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2640, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2648, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E30, /* SPECIFIC_FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E34, /* SPECIFIC_FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E38, /* SPECIFIC_FD_URGENCY_LOW */ + .value = 0x44, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E40, /* SPECIFIC_FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E48, /* SPECIFIC_FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + + }, + { + /*SidebandManager_main_SidebandManager_FlagOutSet0_Low*/ + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2288, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas120_err_logger_offsets = { + .mainctrl = 0x4F08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x4F10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x4F20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x4F24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x4F28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x4F2c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x4F30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x4F34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x4F38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x4F3c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas120_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2300, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas120_camnoc_info = { + .specific = &cam_cpas_v175_120_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v175_120_camnoc_specific), + .irq_sbm = &cam_cpas_v175_120_irq_sbm, + .irq_err = &cam_cpas_v175_120_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v175_120_irq_err), + .err_logger = &cam175_cpas120_err_logger_offsets, + .errata_wa_list = &cam175_cpas120_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_120_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_130.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_130.h new file mode 100644 index 0000000000000000000000000000000000000000..769e77fc3d6bf460964e3cea293d176cb80d95bf --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v175_130.h @@ -0,0 +1,773 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V175_130_H_ +#define _CPASTOP_V175_130_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_130_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2240, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2248, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2280, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_130_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x4F08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x4F10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x4F18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3BA0, /* SPECIFIC_IFE0_MAIN_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + /* SPECIFIC_IFE0_MAIN_ENCERRSTATUS_LOW */ + .offset = 0x3B90, + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3B98, /* SPECIFIC_IFE0_MAIN_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x55A0, /* SPECIFIC_IFE1_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + /* SPECIFIC_IFE1_WR_ENCERRSTATUS_LOW */ + .offset = 0x5590, + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x5598, /* SPECIFIC_IFE1_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2F20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2F10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2F18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2BA0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2B90, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2B98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_130_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* cdm_main_SpecificToNttpTr_Urgency_Low */ + .offset = 0x4238, + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4240, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4248, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0123_RDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_LOW */ + .offset = 0x3630, + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_HIGH */ + .offset = 0x3634, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3638, /* SPECIFIC_IFE0123_URGENCY_LOW */ + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3640, /* SPECIFIC_IFE0123_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3648, /* SPECIFIC_IFE0123_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A30, /* SPECIFIC_IFE0_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A34, /* SPECIFIC_IFE0_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3A38, /* SPECIFIC_IFE0_URGENCY_LOW */ + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A40, /* SPECIFIC_IFE0_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A48, /* SPECIFIC_IFE0_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3B88, /* SPECIFIC_IFE0_ENCCTL_LOW */ + .value = 1, + }, + }, + { + /* IFE0/1 RDI READ PATH */ + .port_type = CAM_CAMNOC_IFE01_RDI_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3230, /* SPECIFIC_IFE1_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3234, /* SPECIFIC_IFE1_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3238, /* SPECIFIC_IFE1_URGENCY_LOW */ + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_MASK */ + .mask = 0x7, + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3240, /* SPECIFIC_IFE1_DANGERLUT_LOW */ + .value = 0x00000000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ + .value = 0xFFFFFFFF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE1_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5430, /* SPECIFIC_IFE1_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE1_WR_PRIORITYLUT_HIGH */ + .offset = 0x5434, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x5438, /* SPECIFIC_IFE1_WR_URGENCY_LOW */ + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5440, /* SPECIFIC_IFE1_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5448, /* SPECIFIC_IFE1_WR_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5588, /* SPECIFIC_IFE1_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2E38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2F08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_VID_DISP_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_LOW */ + .offset = 0x5E30, + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_HIGH */ + .offset = 0x5E34, + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW */ + .offset = 0x5E38, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_MASK */ + .mask = 0x70, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC__IPE_VID_DISP_DANGERLUT_LOW */ + .offset = 0x5E40, + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_SAFELUT_LOW */ + .offset = 0x5E48, + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5F88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2630, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2634, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2638, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2640, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2648, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E30, /* SPECIFIC_FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E34, /* SPECIFIC_FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E38, /* SPECIFIC_FD_URGENCY_LOW */ + .value = 0x44, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E40, /* SPECIFIC_FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E48, /* SPECIFIC_FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + + }, + { + /*SidebandManager_main_SidebandManager_FlagOutSet0_Low*/ + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2288, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas130_err_logger_offsets = { + .mainctrl = 0x4F08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x4F10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x4F20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x4F24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x4F28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x4F2c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x4F30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x4F34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x4F38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x4F3c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas130_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2300, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, + /* TZ owned register */ + .tcsr_camera_hf_sf_ares_glitch = { + .enable = true, + .data.reg_info = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + /* TCSR_CAMERA_HF_SF_ARES_GLITCH_MASK */ + .offset = 0x01FCA08C, + .value = 0x4, /* set bit[2] to 1 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas130_camnoc_info = { + .specific = &cam_cpas_v175_130_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v175_130_camnoc_specific), + .irq_sbm = &cam_cpas_v175_130_irq_sbm, + .irq_err = &cam_cpas_v175_130_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v175_130_irq_err), + .err_logger = &cam175_cpas130_err_logger_offsets, + .errata_wa_list = &cam175_cpas130_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_130_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v480_100.h b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v480_100.h new file mode 100644 index 0000000000000000000000000000000000000000..0d46e0ddcc2001112c696f6b1374f5a23c77ff82 --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/cpas_top/cpastop_v480_100.h @@ -0,0 +1,711 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CPASTOP_V480_100_H_ +#define _CPASTOP_V480_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v480_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3840, /* SBM_FAULTINEN0_LOW */ + .value = 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + (TEST_IRQ_ENABLE ? + 0x40 : /* SBM_FAULTINEN0_LOW_PORT6_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3848, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3880, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x5 : 0x1, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v480_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = false, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x7008, /* ERL_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x7010, /* ERL_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x7018, /* ERL_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x1BA0, /* IFE_UBWC_STATS_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1B90, /* IFE_UBWC_STATS_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1B98, /* IFE_UBWC_STATS_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2520, /* IPE1_BPS_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2510, /* IPE1_BPS_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2518, /* IPE1_BPS_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE0_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x1F20, /* IPE0_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1F10, /* IPE0_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1F18, /* IPE0_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x29A0, /* IPE_BPS_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2990, + /* IPE_BPS_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2998, /* IPE_BPS_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = false, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3888, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3890, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x40, /* SBM_FAULTINSTATUS0_LOW_PORT6_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3888, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3890, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v480_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* CDM_PRIORITYLUT_LOW */ + .value = 0x0, + }, + .priority_lut_high = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* CDM_PRIORITYLUT_HIGH */ + .value = 0x0, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x38, /* CDM_URGENCY_LOW */ + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x630, /* FD_PRIORITYLUT_LOW */ + .value = 0x0, + }, + .priority_lut_high = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x634, /* FD_PRIORITYLUT_HIGH */ + .value = 0x0, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x638, /* FD_URGENCY_LOW */ + .value = 0x33, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x640, /* FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x648, /* FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_LINEAR, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xA30, /* IFE_LINEAR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xA34, /* IFE_LINEAR_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xA38, /* IFE_LINEAR_URGENCY_LOW */ + .value = 0x1030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0xA40, /* IFE_LINEAR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0xA48, /* IFE_LINEAR_SAFELUT_LOW */ + .value = 0x000F, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_RDI_RD, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* IFE_RDI_RD_PRIORITYLUT_LOW */ + .value = 0x0, + }, + .priority_lut_high = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* IFE_RDI_RD_PRIORITYLUT_HIGH */ + .value = 0x0, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1038, /* IFE_RDI_RD_URGENCY_LOW */ + .value = 0x3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1040, /* IFE_RDI_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1048, /* IFE_RDI_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_RDI_WR, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* IFE_RDI_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* IFE_RDI_WR_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* IFE_RDI_WR_URGENCY_LOW */ + .value = 0x1030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1440, /* IFE_RDI_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1448, /* IFE_RDI_WR_SAFELUT_LOW */ + .value = 0x000F, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE_UBWC_STATS, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1A30, /* IFE_UBWC_STATS_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1A34, /* IFE_UBWC_STATS_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1A38, /* IFE_UBWC_STATS_URGENCY_LOW */ + .value = 0x1030, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1A40, /* IFE_UBWC_STATS_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x1A48, /* IFE_UBWC_STATS_SAFELUT_LOW */ + .value = 0x000F, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1B88, /* IFE_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE0_RD, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E30, /* IPE0_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E34, /* IPE0_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E38, /* IPE0_RD_URGENCY_LOW */ + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E40, /* IPE0_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1E48, /* IPE0_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1F08, /* IPE0_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE1_BPS_RD, + .enable = true, + .priority_lut_low = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2430, /* IPE1_BPS_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2434, /* IPE1_BPS_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2438, /* IPE1_BPS_RD_URGENCY_LOW */ + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2440, /* IPE1_BPS_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2448, /* IPE1_BPS_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2508, /* IPE1_BPS_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_WR, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2830, /* IPE_BPS_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2834, /* IPE_BPS_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2838, /* IPE_BPS_WR_URGENCY_LOW */ + .value = 0x30, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2840, /* IPE_BPS_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2848, /* IPE_BPS_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2988, /* IPE_BPS_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E38, /* JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam480_cpas100_err_logger_offsets = { + .mainctrl = 0x7008, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x7010, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x7020, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x7024, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x7028, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x702c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x7030, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x7034, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x7038, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x703c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam480_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam480_cpas100_camnoc_info = { + .specific = &cam_cpas_v480_100_camnoc_specific[0], + .specific_size = ARRAY_SIZE(cam_cpas_v480_100_camnoc_specific), + .irq_sbm = &cam_cpas_v480_100_irq_sbm, + .irq_err = &cam_cpas_v480_100_irq_err[0], + .irq_err_size = ARRAY_SIZE(cam_cpas_v480_100_irq_err), + .err_logger = &cam480_cpas100_err_logger_offsets, + .errata_wa_list = &cam480_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V480_100_H_ */ diff --git a/techpack/camera/drivers/cam_cpas/include/cam_cpas_api.h b/techpack/camera/drivers/cam_cpas/include/cam_cpas_api.h new file mode 100644 index 0000000000000000000000000000000000000000..7c551dfcf8a58a16606e4cd65becebc1abf21d1d --- /dev/null +++ b/techpack/camera/drivers/cam_cpas/include/cam_cpas_api.h @@ -0,0 +1,568 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CPAS_API_H_ +#define _CAM_CPAS_API_H_ + +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <media/cam_cpas.h> +#include "cam_soc_util.h" + +#define CAM_HW_IDENTIFIER_LENGTH 128 + +/* Default AXI Bandwidth vote */ +#define CAM_CPAS_DEFAULT_AXI_BW 1024 + +#define CAM_CPAS_MAX_PATHS_PER_CLIENT 15 +#define CAM_CPAS_API_PATH_DATA_STD_START 512 + +/** + * enum cam_cpas_reg_base - Enum for register base identifier. These + * are the identifiers used in generic register + * write/read APIs provided by cpas driver. + */ +enum cam_cpas_reg_base { + CAM_CPAS_REG_CPASTOP, + CAM_CPAS_REG_CAMNOC, + CAM_CPAS_REG_CAMSS, + CAM_CPAS_REG_MAX +}; + +/** + * enum cam_cpas_hw_version - Enum for Titan CPAS HW Versions + */ +enum cam_cpas_hw_version { + CAM_CPAS_TITAN_NONE = 0, + CAM_CPAS_TITAN_150_V100 = 0x150100, + CAM_CPAS_TITAN_170_V100 = 0x170100, + CAM_CPAS_TITAN_170_V110 = 0x170110, + CAM_CPAS_TITAN_170_V120 = 0x170120, + CAM_CPAS_TITAN_175_V100 = 0x175100, + CAM_CPAS_TITAN_175_V101 = 0x175101, + CAM_CPAS_TITAN_175_V120 = 0x175120, + CAM_CPAS_TITAN_175_V130 = 0x175130, + CAM_CPAS_TITAN_480_V100 = 0x480100, + CAM_CPAS_TITAN_MAX +}; + +/** + * enum cam_camnoc_irq_type - Enum for camnoc irq types + * + * @CAM_CAMNOC_IRQ_SLAVE_ERROR: Each slave port in CAMNOC (3 QSB ports and + * 1 QHB port) has an error logger. The error + * observed at any slave port is logged into + * the error logger register and an IRQ is + * triggered + * @CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR: Triggered if any error detected + * in the IFE UBWC-Stats encoder + * instance + * @CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE0 UBWC encoder instance + * @CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE1 or IFE3 UBWC encoder + * instance + * @CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE0 UBWC encoder instance + * @CAM_CAMNOC_IRQ_IFE1_WR_UBWC_ENCODE_ERROR : Triggered if any error detected + * in the IFE1 UBWC encoder + * instance + * @CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR: Triggered if any error detected + * in the IPE1/BPS read path decoder + * instance + * @CAM_CAMNOC_IRQ_IPE0_UBWC_DECODE_ERROR : Triggered if any error detected + * in the IPE0 read path decoder + * instance + * @CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: Triggered if any error detected + * in the IPE/BPS UBWC decoder + * instance + * @CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: Triggered if any error detected + * in the IPE/BPS UBWC encoder + * instance + * @CAM_CAMNOC_IRQ_AHB_TIMEOUT : Triggered when the QHS_ICP slave + * times out after 4000 AHB cycles + */ +enum cam_camnoc_irq_type { + CAM_CAMNOC_IRQ_SLAVE_ERROR, + CAM_CAMNOC_IRQ_IFE_UBWC_STATS_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IPE1_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_IRQ_IPE0_UBWC_DECODE_ERROR, + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_AHB_TIMEOUT, +}; + +/** + * struct cam_camnoc_irq_slave_err_data : Data for Slave error. + * + * @mainctrl : Err logger mainctrl info + * @errvld : Err logger errvld info + * @errlog0_low : Err logger errlog0_low info + * @errlog0_high : Err logger errlog0_high info + * @errlog1_low : Err logger errlog1_low info + * @errlog1_high : Err logger errlog1_high info + * @errlog2_low : Err logger errlog2_low info + * @errlog2_high : Err logger errlog2_high info + * @errlog3_low : Err logger errlog3_low info + * @errlog3_high : Err logger errlog3_high info + * + */ +struct cam_camnoc_irq_slave_err_data { + union { + struct { + uint32_t stall_en : 1; /* bit 0 */ + uint32_t fault_en : 1; /* bit 1 */ + uint32_t rsv : 30; /* bits 2-31 */ + }; + uint32_t value; + } mainctrl; + union { + struct { + uint32_t err_vld : 1; /* bit 0 */ + uint32_t rsv : 31; /* bits 1-31 */ + }; + uint32_t value; + } errvld; + union { + struct { + uint32_t loginfo_vld : 1; /* bit 0 */ + uint32_t word_error : 1; /* bit 1 */ + uint32_t non_secure : 1; /* bit 2 */ + uint32_t device : 1; /* bit 3 */ + uint32_t opc : 3; /* bits 4 - 6 */ + uint32_t rsv0 : 1; /* bit 7 */ + uint32_t err_code : 3; /* bits 8 - 10 */ + uint32_t sizef : 3; /* bits 11 - 13 */ + uint32_t rsv1 : 2; /* bits 14 - 15 */ + uint32_t addr_space : 6; /* bits 16 - 21 */ + uint32_t rsv2 : 10; /* bits 22 - 31 */ + }; + uint32_t value; + } errlog0_low; + union { + struct { + uint32_t len1 : 10; /* bits 0 - 9 */ + uint32_t rsv : 22; /* bits 10 - 31 */ + }; + uint32_t value; + } errlog0_high; + union { + struct { + uint32_t path : 16; /* bits 0 - 15 */ + uint32_t rsv : 16; /* bits 16 - 31 */ + }; + uint32_t value; + } errlog1_low; + union { + struct { + uint32_t extid : 18; /* bits 0 - 17 */ + uint32_t rsv : 14; /* bits 18 - 31 */ + }; + uint32_t value; + } errlog1_high; + union { + struct { + uint32_t errlog2_lsb : 32; /* bits 0 - 31 */ + }; + uint32_t value; + } errlog2_low; + union { + struct { + uint32_t errlog2_msb : 16; /* bits 0 - 16 */ + uint32_t rsv : 16; /* bits 16 - 31 */ + }; + uint32_t value; + } errlog2_high; + union { + struct { + uint32_t errlog3_lsb : 32; /* bits 0 - 31 */ + }; + uint32_t value; + } errlog3_low; + union { + struct { + uint32_t errlog3_msb : 32; /* bits 0 - 31 */ + }; + uint32_t value; + } errlog3_high; +}; + +/** + * struct cam_camnoc_irq_ubwc_enc_data : Data for UBWC Encode error. + * + * @encerr_status : Encode error status + * + */ +struct cam_camnoc_irq_ubwc_enc_data { + union { + struct { + uint32_t encerrstatus : 3; /* bits 0 - 2 */ + uint32_t rsv : 29; /* bits 3 - 31 */ + }; + uint32_t value; + } encerr_status; +}; + +/** + * struct cam_camnoc_irq_ubwc_dec_data : Data for UBWC Decode error. + * + * @decerr_status : Decoder error status + * @thr_err : Set to 1 if + * At least one of the bflc_len fields in the bit steam exceeds + * its threshold value. This error is possible only for + * RGBA1010102, TP10, and RGB565 formats + * @fcl_err : Set to 1 if + * Fast clear with a legal non-RGB format + * @len_md_err : Set to 1 if + * The calculated burst length does not match burst length + * specified by the metadata value + * @format_err : Set to 1 if + * Illegal format + * 1. bad format :2,3,6 + * 2. For 32B MAL, metadata=6 + * 3. For 32B MAL RGB565, Metadata != 0,1,7 + * 4. For 64B MAL RGB565, metadata[3:1] == 1,2 + * + */ +struct cam_camnoc_irq_ubwc_dec_data { + union { + struct { + uint32_t thr_err : 1; /* bit 0 */ + uint32_t fcl_err : 1; /* bit 1 */ + uint32_t len_md_err : 1; /* bit 2 */ + uint32_t format_err : 1; /* bit 3 */ + uint32_t rsv : 28; /* bits 4 - 31 */ + }; + uint32_t value; + } decerr_status; +}; + +struct cam_camnoc_irq_ahb_timeout_data { + uint32_t data; +}; + +/** + * struct cam_cpas_irq_data : CAMNOC IRQ data + * + * @irq_type : To identify the type of IRQ + * @u : Union of irq err data information + * @slave_err : Data for Slave error. + * Valid if type is CAM_CAMNOC_IRQ_SLAVE_ERROR + * @enc_err : Data for UBWC Encode error. + * Valid if type is one of below: + * CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR + * CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR + * CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR + * @dec_err : Data for UBWC Decode error. + * Valid if type is CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR + * @ahb_err : Data for Slave error. + * Valid if type is CAM_CAMNOC_IRQ_AHB_TIMEOUT + * + */ +struct cam_cpas_irq_data { + enum cam_camnoc_irq_type irq_type; + union { + struct cam_camnoc_irq_slave_err_data slave_err; + struct cam_camnoc_irq_ubwc_enc_data enc_err; + struct cam_camnoc_irq_ubwc_dec_data dec_err; + struct cam_camnoc_irq_ahb_timeout_data ahb_err; + } u; +}; + +/** + * struct cam_cpas_register_params : Register params for cpas client + * + * @identifier : Input identifier string which is the device label + * from dt like vfe, ife, jpeg etc + * @cell_index : Input integer identifier pointing to the cell index + * from dt of the device. This can be used to form a + * unique string with @identifier like vfe0, ife1, + * jpeg0, etc + * @dev : device handle + * @userdata : Input private data which will be passed as + * an argument while callback. + * @cam_cpas_callback : Input callback pointer for triggering the + * callbacks from CPAS driver. + * @client_handle : CPAS client handle + * @userdata : User data given at the time of register + * @event_type : event type + * @event_data : event data + * @client_handle : Output Unique handle generated for this register + * + */ +struct cam_cpas_register_params { + char identifier[CAM_HW_IDENTIFIER_LENGTH]; + uint32_t cell_index; + struct device *dev; + void *userdata; + bool (*cam_cpas_client_cb)( + uint32_t client_handle, + void *userdata, + struct cam_cpas_irq_data *irq_data); + uint32_t client_handle; +}; + +/** + * enum cam_vote_type - Enum for voting type + * + * @CAM_VOTE_ABSOLUTE : Absolute vote + * @CAM_VOTE_DYNAMIC : Dynamic vote + */ +enum cam_vote_type { + CAM_VOTE_ABSOLUTE, + CAM_VOTE_DYNAMIC, +}; + +/** + * struct cam_ahb_vote : AHB vote + * + * @type : AHB voting type. + * CAM_VOTE_ABSOLUTE : vote based on the value 'level' is set + * CAM_VOTE_DYNAMIC : vote calculated dynamically using 'freq' + * and 'dev' handle is set + * @level : AHB vote level + * @freq : AHB vote dynamic frequency + * + */ +struct cam_ahb_vote { + enum cam_vote_type type; + union { + enum cam_vote_level level; + unsigned long freq; + } vote; +}; + +/** + * struct cam_axi_vote : AXI vote + * + * @num_paths: Number of paths on which BW vote is sent to CPAS + * @axi_path: Per path BW vote info + * + */ +struct cam_axi_vote { + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_CPAS_MAX_PATHS_PER_CLIENT]; +}; + +/** + * cam_cpas_register_client() + * + * @brief: API to register cpas client + * + * @register_params: Input params to register as a client to CPAS + * + * @return 0 on success. + * + */ +int cam_cpas_register_client( + struct cam_cpas_register_params *register_params); + +/** + * cam_cpas_unregister_client() + * + * @brief: API to unregister cpas client + * + * @client_handle: Client handle to be unregistered + * + * @return 0 on success. + * + */ +int cam_cpas_unregister_client(uint32_t client_handle); + +/** + * cam_cpas_start() + * + * @brief: API to start cpas client hw. Clients have to vote for minimal + * bandwidth requirements for AHB, AXI. Use cam_cpas_update_ahb_vote + * to scale bandwidth after start. + * + * @client_handle: client cpas handle + * @ahb_vote : Pointer to ahb vote info + * @axi_vote : Pointer to axi bandwidth vote info + * + * If AXI vote is not applicable to a particular client, use the value exposed + * by CAM_CPAS_DEFAULT_AXI_BW as the default vote request. + * + * @return 0 on success. + * + */ +int cam_cpas_start( + uint32_t client_handle, + struct cam_ahb_vote *ahb_vote, + struct cam_axi_vote *axi_vote); + +/** + * cam_cpas_stop() + * + * @brief: API to stop cpas client hw. Bandwidth for AHB, AXI votes + * would be removed for this client on this call. Clients should not + * use cam_cpas_update_ahb_vote or cam_cpas_update_axi_vote + * to remove their bandwidth vote. + * + * @client_handle: client cpas handle + * + * @return 0 on success. + * + */ +int cam_cpas_stop(uint32_t client_handle); + +/** + * cam_cpas_update_ahb_vote() + * + * @brief: API to update AHB vote requirement. Use this function only + * between cam_cpas_start and cam_cpas_stop in case clients wants + * to scale to different vote level. Do not use this function to de-vote, + * removing client's vote is implicit on cam_cpas_stop + * + * @client_handle : Client cpas handle + * @ahb_vote : Pointer to ahb vote info + * + * @return 0 on success. + * + */ +int cam_cpas_update_ahb_vote( + uint32_t client_handle, + struct cam_ahb_vote *ahb_vote); + +/** + * cam_cpas_update_axi_vote() + * + * @brief: API to update AXI vote requirement. Use this function only + * between cam_cpas_start and cam_cpas_stop in case clients wants + * to scale to different vote level. Do not use this function to de-vote, + * removing client's vote is implicit on cam_cpas_stop + * + * @client_handle : Client cpas handle + * @axi_vote : Pointer to axi bandwidth vote info + * + * @return 0 on success. + * + */ +int cam_cpas_update_axi_vote( + uint32_t client_handle, + struct cam_axi_vote *axi_vote); + +/** + * cam_cpas_reg_write() + * + * @brief: API to write a register value in CPAS register space + * + * @client_handle : Client cpas handle + * @reg_base : Register base identifier + * @offset : Offset from the register base address + * @mb : Whether to do reg write with memory barrier + * @value : Value to be written in register + * + * @return 0 on success. + * + */ +int cam_cpas_reg_write( + uint32_t client_handle, + enum cam_cpas_reg_base reg_base, + uint32_t offset, + bool mb, + uint32_t value); + +/** + * cam_cpas_reg_read() + * + * @brief: API to read a register value from CPAS register space + * + * @client_handle : Client cpas handle + * @reg_base : Register base identifier + * @offset : Offset from the register base address + * @mb : Whether to do reg read with memory barrier + * @value : Value to be red from register + * + * @return 0 on success. + * + */ +int cam_cpas_reg_read( + uint32_t client_handle, + enum cam_cpas_reg_base reg_base, + uint32_t offset, + bool mb, + uint32_t *value); + +/** + * cam_cpas_get_hw_info() + * + * @brief: API to get camera hw information + * + * @camera_family : Camera family type. One of + * CAM_FAMILY_CAMERA_SS + * CAM_FAMILY_CPAS_SS + * @camera_version : Camera platform version + * @cpas_version : Camera cpas version + * @cam_caps : Camera capability + * + * @return 0 on success. + * + */ +int cam_cpas_get_hw_info( + uint32_t *camera_family, + struct cam_hw_version *camera_version, + struct cam_hw_version *cpas_version, + uint32_t *cam_caps); + +/** + * cam_cpas_get_cpas_hw_version() + * + * @brief: API to get camera cpas hw version + * + * @hw_version : Camera cpas hw version + * + * @return 0 on success. + * + */ +int cam_cpas_get_cpas_hw_version( + uint32_t *hw_version); + +/** + * cam_cpas_is_feature_supported() + * + * @brief: API to get camera features + * + * @flag : Camera hw features to check + * + * @return 1 if feature is supported + * + */ +int cam_cpas_is_feature_supported( + uint32_t flag); + +/** + * cam_cpas_axi_util_path_type_to_string() + * + * @brief: API to get string for given path type + * + * @path_data_type : Path type + * + * @return string. + * + */ +const char *cam_cpas_axi_util_path_type_to_string( + uint32_t path_data_type); + +/** + * cam_cpas_axi_util_trans_type_to_string() + * + * @brief: API to get string for given transaction type + * + * @path_data_type : Transaction type + * + * @return string. + * + */ +const char *cam_cpas_axi_util_trans_type_to_string( + uint32_t path_data_type); + + +#endif /* _CAM_CPAS_API_H_ */ diff --git a/techpack/camera/drivers/cam_cust/Makefile b/techpack/camera/drivers/cam_cust/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..732b9593c38bee20f263439ad2fd40c319e52fd2 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_dev.o cam_custom_context.o diff --git a/techpack/camera/drivers/cam_cust/cam_custom_context.c b/techpack/camera/drivers/cam_cust/cam_custom_context.c new file mode 100644 index 0000000000000000000000000000000000000000..7f38392a7d575d418c0e0fbe53c66ca0f7a53e0e --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_context.c @@ -0,0 +1,947 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/ratelimit.h> + +#include "cam_mem_mgr.h" +#include "cam_sync_api.h" +#include "cam_req_mgr_dev.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" +#include "cam_context_utils.h" +#include "cam_custom_context.h" +#include "cam_common_util.h" + +static const char custom_dev_name[] = "custom hw"; + +static int __cam_custom_ctx_handle_irq_in_activated( + void *context, uint32_t evt_id, void *evt_data); + +static int __cam_custom_ctx_enqueue_request_in_order( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + struct cam_ctx_request *req_current; + struct cam_ctx_request *req_prev; + struct list_head temp_list; + + INIT_LIST_HEAD(&temp_list); + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + } else { + list_for_each_entry_safe_reverse( + req_current, req_prev, &ctx->pending_req_list, list) { + if (req->request_id < req_current->request_id) { + list_del_init(&req_current->list); + list_add(&req_current->list, &temp_list); + continue; + } else if (req->request_id == req_current->request_id) { + CAM_WARN(CAM_CUSTOM, + "Received duplicated request %lld", + req->request_id); + } + break; + } + list_add_tail(&req->list, &ctx->pending_req_list); + + if (!list_empty(&temp_list)) { + list_for_each_entry_safe( + req_current, req_prev, &temp_list, list) { + list_del_init(&req_current->list); + list_add_tail(&req_current->list, + &ctx->pending_req_list); + } + } + } + spin_unlock_bh(&ctx->lock); + return 0; +} + +static int __cam_custom_ctx_flush_req(struct cam_context *ctx, + struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) +{ + int i, rc; + uint32_t cancel_req_id_found = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *req_temp; + struct cam_custom_dev_ctx_req *req_custom; + struct list_head flush_list; + + INIT_LIST_HEAD(&flush_list); + if (list_empty(req_list)) { + CAM_DBG(CAM_CUSTOM, "request list is empty"); + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + CAM_ERR(CAM_CUSTOM, "no request to cancel"); + return -EINVAL; + } else { + return 0; + } + } + + CAM_DBG(CAM_CUSTOM, "Flush [%u] in progress for req_id %llu", + flush_req->type, flush_req->req_id); + list_for_each_entry_safe(req, req_temp, req_list, list) { + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + if (req->request_id != flush_req->req_id) { + continue; + } else { + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + cancel_req_id_found = 1; + break; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + } + + list_for_each_entry_safe(req, req_temp, &flush_list, list) { + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + for (i = 0; i < req_custom->num_fence_map_out; i++) { + if (req_custom->fence_map_out[i].sync_id != -1) { + CAM_DBG(CAM_CUSTOM, + "Flush req 0x%llx, fence %d", + req->request_id, + req_custom->fence_map_out[i].sync_id); + rc = cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) + CAM_ERR_RATE_LIMIT(CAM_CUSTOM, + "signal fence failed\n"); + req_custom->fence_map_out[i].sync_id = -1; + } + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_CUSTOM, + "Flush request id:%lld is not found in the list", + flush_req->req_id); + + return 0; +} + +static int __cam_custom_ctx_flush_req_in_top_state( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + CAM_INFO(CAM_CUSTOM, "Last request id to flush is %lld", + flush_req->req_id); + ctx->last_flush_req = flush_req->req_id; + } + + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); + + return rc; +} + +static int __cam_custom_ctx_flush_req_in_ready( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + + CAM_DBG(CAM_CUSTOM, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + + /* if nothing is in pending req list, change state to acquire */ + if (list_empty(&ctx->pending_req_list)) + ctx->state = CAM_CTX_ACQUIRED; + spin_unlock_bh(&ctx->lock); + + CAM_DBG(CAM_CUSTOM, "Flush request in ready state. next state %d", + ctx->state); + return rc; +} + +static int __cam_custom_ctx_unlink_in_ready(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->state = CAM_CTX_ACQUIRED; + + return 0; +} + +static int __cam_custom_stop_dev_core( + struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) +{ + int rc = 0; + uint32_t i; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_hw_stop_args stop; + + if (ctx_custom->hw_ctx) { + stop.ctxt_to_hw_map = ctx_custom->hw_ctx; + + stop.args = NULL; + if (ctx->hw_mgr_intf->hw_stop) + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop); + } + + while (!list_empty(&ctx->pending_req_list)) { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + CAM_DBG(CAM_CUSTOM, + "signal fence in pending list. fence num %d", + req_custom->num_fence_map_out); + for (i = 0; i < req_custom->num_fence_map_out; i++) + if (req_custom->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + CAM_DBG(CAM_CUSTOM, "signal fence in wait list. fence num %d", + req_custom->num_fence_map_out); + for (i = 0; i < req_custom->num_fence_map_out; i++) + if (req_custom->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + CAM_DBG(CAM_CUSTOM, "signal fence in active list. fence num %d", + req_custom->num_fence_map_out); + for (i = 0; i < req_custom->num_fence_map_out; i++) + if (req_custom->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_custom->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + ctx_custom->frame_id = 0; + ctx_custom->active_req_cnt = 0; + + CAM_DBG(CAM_CUSTOM, "Stop device success next state %d on ctx %u", + ctx->state, ctx->ctx_id); + + if (!stop_cmd) { + rc = __cam_custom_ctx_unlink_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unlink failed rc=%d", rc); + } + return rc; +} + +static int __cam_custom_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *)ctx->ctx_priv; + + __cam_custom_stop_dev_core(ctx, cmd); + ctx_custom->init_received = false; + ctx->state = CAM_CTX_ACQUIRED; + + return 0; +} + +static int __cam_custom_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + struct cam_req_mgr_flush_request flush_req; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unable to release device"); + + ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; + ctx_custom->frame_id = 0; + ctx_custom->active_req_cnt = 0; + ctx_custom->init_received = false; + + if (!list_empty(&ctx->active_req_list)) + CAM_ERR(CAM_CUSTOM, "Active list is not empty"); + + /* Flush all the pending request list */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_CUSTOM, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_custom_ctx_flush_req(ctx, &ctx->pending_req_list, + &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_AVAILABLE; + + CAM_DBG(CAM_CUSTOM, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); + + return rc; +} + +static int __cam_custom_ctx_apply_req_in_activated_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_custom_context *custom_ctx = NULL; + struct cam_hw_config_args cfg; + + if (list_empty(&ctx->pending_req_list)) { + CAM_ERR(CAM_CUSTOM, "No available request for Apply id %lld", + apply->request_id); + rc = -EFAULT; + goto end; + } + + custom_ctx = (struct cam_custom_context *) ctx->ctx_priv; + spin_lock_bh(&ctx->lock); + req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + list); + spin_unlock_bh(&ctx->lock); + + /* + * Check whether the request id is matching the tip + */ + if (req->request_id != apply->request_id) { + CAM_ERR_RATE_LIMIT(CAM_CUSTOM, + "Invalid Request Id asking %llu existing %llu", + apply->request_id, req->request_id); + rc = -EFAULT; + goto end; + } + + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + + cfg.ctxt_to_hw_map = custom_ctx->hw_ctx; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req_custom->cfg; + cfg.num_hw_update_entries = req_custom->num_cfg; + cfg.priv = &req_custom->hw_update_data; + cfg.init_packet = 0; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_CUSTOM, + "Can not apply the configuration"); + } else { + spin_lock_bh(&ctx->lock); + list_del_init(&req->list); + if (!req->num_out_map_entries) { + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + } else { + list_add_tail(&req->list, &ctx->active_req_list); + spin_unlock_bh(&ctx->lock); + /* + * for test purposes only-this should be + * triggered based on irq + */ + __cam_custom_ctx_handle_irq_in_activated(ctx, 0, NULL); + } + } + +end: + return rc; +} + +static int __cam_custom_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + struct cam_custom_context *custom_ctx; + + custom_ctx = (struct cam_custom_context *) ctx->ctx_priv; + + if (cmd->num_resources > CAM_CUSTOM_DEV_CTX_RES_MAX) { + CAM_ERR(CAM_CUSTOM, "Too much resources in the acquire"); + rc = -ENOMEM; + return rc; + } + + if (cmd->handle_type != 1) { + CAM_ERR(CAM_CUSTOM, "Only user pointer is supported"); + rc = -EINVAL; + return rc; + } + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_ACQUIRED; + custom_ctx->hw_ctx = ctx->ctxt_to_hw_map; + } + + CAM_DBG(CAM_CUSTOM, "Acquire done %d", ctx->ctx_id); + return rc; +} + +static int __cam_custom_ctx_enqueue_init_request( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + int rc = 0; + struct cam_ctx_request *req_old; + struct cam_custom_dev_ctx_req *req_custom_old; + struct cam_custom_dev_ctx_req *req_custom_new; + + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + goto end; + } + + req_old = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + req_custom_old = (struct cam_custom_dev_ctx_req *) req_old->req_priv; + req_custom_new = (struct cam_custom_dev_ctx_req *) req->req_priv; + if (req_custom_old->hw_update_data.packet_opcode_type == + CAM_CUSTOM_PACKET_INIT_DEV) { + if ((req_custom_old->num_cfg + req_custom_new->num_cfg) >= + CAM_CUSTOM_CTX_CFG_MAX) { + CAM_WARN(CAM_CUSTOM, "Can not merge INIT pkt"); + rc = -ENOMEM; + } + + if (req_custom_old->num_fence_map_out != 0 || + req_custom_old->num_fence_map_in != 0) { + CAM_WARN(CAM_CUSTOM, "Invalid INIT pkt sequence"); + rc = -EINVAL; + } + + if (!rc) { + memcpy(req_custom_old->fence_map_out, + req_custom_new->fence_map_out, + sizeof(req_custom_new->fence_map_out[0])* + req_custom_new->num_fence_map_out); + req_custom_old->num_fence_map_out = + req_custom_new->num_fence_map_out; + + memcpy(req_custom_old->fence_map_in, + req_custom_new->fence_map_in, + sizeof(req_custom_new->fence_map_in[0])* + req_custom_new->num_fence_map_in); + req_custom_old->num_fence_map_in = + req_custom_new->num_fence_map_in; + + memcpy(&req_custom_old->cfg[req_custom_old->num_cfg], + req_custom_new->cfg, + sizeof(req_custom_new->cfg[0])* + req_custom_new->num_cfg); + req_custom_old->num_cfg += req_custom_new->num_cfg; + + req_old->request_id = req->request_id; + + list_add_tail(&req->list, &ctx->free_req_list); + } + } else { + CAM_WARN(CAM_CUSTOM, + "Received Update pkt before INIT pkt. req_id= %lld", + req->request_id); + rc = -EINVAL; + } +end: + spin_unlock_bh(&ctx->lock); + return rc; +} + +static int __cam_custom_ctx_config_dev(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0, i; + struct cam_ctx_request *req = NULL; + struct cam_custom_dev_ctx_req *req_custom; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + struct cam_hw_prepare_update_args cfg; + struct cam_req_mgr_add_request add_req; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + /* get free request */ + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->free_req_list)) { + req = list_first_entry(&ctx->free_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + } + spin_unlock_bh(&ctx->lock); + + if (!req) { + CAM_ERR(CAM_CUSTOM, "No more request obj free"); + return -ENOMEM; + } + + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + + /* for config dev, only memory handle is supported */ + /* map packet from the memhandle */ + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Can not get packet address"); + rc = -EINVAL; + goto free_req; + } + + packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); + CAM_DBG(CAM_CUSTOM, "pack_handle %llx", cmd->packet_handle); + CAM_DBG(CAM_CUSTOM, "packet address is 0x%zx", packet_addr); + CAM_DBG(CAM_CUSTOM, "packet with length %zu, offset 0x%llx", + len, cmd->offset); + CAM_DBG(CAM_CUSTOM, "Packet request id %lld", + packet->header.request_id); + CAM_DBG(CAM_CUSTOM, "Packet size 0x%x", packet->header.size); + CAM_DBG(CAM_CUSTOM, "packet op %d", packet->header.op_code); + + if ((((packet->header.op_code) & 0xF) == + CAM_CUSTOM_PACKET_UPDATE_DEV) + && (packet->header.request_id <= ctx->last_flush_req)) { + CAM_DBG(CAM_CUSTOM, + "request %lld has been flushed, reject packet", + packet->header.request_id); + rc = -EINVAL; + goto free_req; + } + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.ctxt_to_hw_map = ctx_custom->hw_ctx; + cfg.out_map_entries = req_custom->fence_map_out; + cfg.in_map_entries = req_custom->fence_map_in; + cfg.priv = &req_custom->hw_update_data; + cfg.pf_data = &(req->pf_data); + + rc = ctx->hw_mgr_intf->hw_prepare_update( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Prepare config packet failed in HW layer"); + rc = -EFAULT; + goto free_req; + } + + req_custom->num_cfg = cfg.num_hw_update_entries; + req_custom->num_fence_map_out = cfg.num_out_map_entries; + req_custom->num_fence_map_in = cfg.num_in_map_entries; + req_custom->num_acked = 0; + + for (i = 0; i < req_custom->num_fence_map_out; i++) { + rc = cam_sync_get_obj_ref(req_custom->fence_map_out[i].sync_id); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Can't get ref for fence %d", + req_custom->fence_map_out[i].sync_id); + goto put_ref; + } + } + + CAM_DBG(CAM_CUSTOM, + "num_entry: %d, num fence out: %d, num fence in: %d", + req_custom->num_cfg, req_custom->num_fence_map_out, + req_custom->num_fence_map_in); + + req->request_id = packet->header.request_id; + req->status = 1; + + CAM_DBG(CAM_CUSTOM, "Packet request id %lld packet opcode:%d", + packet->header.request_id, + req_custom->hw_update_data.packet_opcode_type); + + if (req_custom->hw_update_data.packet_opcode_type == + CAM_CUSTOM_PACKET_INIT_DEV) { + if (ctx->state < CAM_CTX_ACTIVATED) { + rc = __cam_custom_ctx_enqueue_init_request(ctx, req); + if (rc) + CAM_ERR(CAM_CUSTOM, "Enqueue INIT pkt failed"); + ctx_custom->init_received = true; + } else { + rc = -EINVAL; + CAM_ERR(CAM_CUSTOM, "Recevied INIT pkt in wrong state"); + } + } else { + if (ctx->state >= CAM_CTX_READY && ctx->ctx_crm_intf->add_req) { + add_req.link_hdl = ctx->link_hdl; + add_req.dev_hdl = ctx->dev_hdl; + add_req.req_id = req->request_id; + add_req.skip_before_applying = 0; + rc = ctx->ctx_crm_intf->add_req(&add_req); + if (rc) { + CAM_ERR(CAM_CUSTOM, + "Add req failed: req id=%llu", + req->request_id); + } else { + __cam_custom_ctx_enqueue_request_in_order( + ctx, req); + } + } else { + rc = -EINVAL; + CAM_ERR(CAM_CUSTOM, "Recevied Update in wrong state"); + } + } + + if (rc) + goto put_ref; + + CAM_DBG(CAM_CUSTOM, + "Preprocessing Config req_id %lld successful on ctx %u", + req->request_id, ctx->ctx_id); + + return rc; + +put_ref: + for (--i; i >= 0; i--) { + if (cam_sync_put_obj_ref(req_custom->fence_map_out[i].sync_id)) + CAM_ERR(CAM_CUSTOM, "Failed to put ref of fence %d", + req_custom->fence_map_out[i].sync_id); + } +free_req: + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + + return rc; + +} + +static int __cam_custom_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + + rc = __cam_custom_ctx_config_dev(ctx, cmd); + + if (!rc && (ctx->link_hdl >= 0)) + ctx->state = CAM_CTX_READY; + + return rc; +} + +static int __cam_custom_ctx_link_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + ctx->link_hdl = link->link_hdl; + ctx->ctx_crm_intf = link->crm_cb; + ctx_custom->subscribe_event = link->subscribe_event; + + /* change state only if we had the init config */ + if (ctx_custom->init_received) + ctx->state = CAM_CTX_READY; + + CAM_DBG(CAM_CUSTOM, "next state %d", ctx->state); + + return 0; +} + +static int __cam_custom_ctx_unlink_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + + return 0; +} + +static int __cam_custom_ctx_get_dev_info_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_device_info *dev_info) +{ + dev_info->dev_hdl = ctx->dev_hdl; + strlcpy(dev_info->name, CAM_CUSTOM_DEV_NAME, sizeof(dev_info->name)); + dev_info->dev_id = CAM_REQ_MGR_DEVICE_CUSTOM_HW; + dev_info->p_delay = 1; + dev_info->trigger = CAM_TRIGGER_POINT_SOF; + + return 0; +} + +static int __cam_custom_ctx_start_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_config_args hw_config; + struct cam_ctx_request *req; + struct cam_custom_dev_ctx_req *req_custom; + struct cam_custom_context *ctx_custom = + (struct cam_custom_context *) ctx->ctx_priv; + + if (cmd->session_handle != ctx->session_hdl || + cmd->dev_handle != ctx->dev_hdl) { + rc = -EPERM; + goto end; + } + + if (list_empty(&ctx->pending_req_list)) { + /* should never happen */ + CAM_ERR(CAM_CUSTOM, "Start device with empty configuration"); + rc = -EFAULT; + goto end; + } else { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + } + req_custom = (struct cam_custom_dev_ctx_req *) req->req_priv; + + if (!ctx_custom->hw_ctx) { + CAM_ERR(CAM_CUSTOM, "Wrong hw context pointer."); + rc = -EFAULT; + goto end; + } + + hw_config.ctxt_to_hw_map = ctx_custom->hw_ctx; + hw_config.request_id = req->request_id; + hw_config.hw_update_entries = req_custom->cfg; + hw_config.num_hw_update_entries = req_custom->num_cfg; + hw_config.priv = &req_custom->hw_update_data; + hw_config.init_packet = 1; + + ctx->state = CAM_CTX_ACTIVATED; + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_config); + if (rc) { + /* HW failure. User need to clean up the resource */ + CAM_ERR(CAM_CUSTOM, "Start HW failed"); + ctx->state = CAM_CTX_READY; + goto end; + } + + CAM_DBG(CAM_CUSTOM, "start device success ctx %u", + ctx->ctx_id); + + spin_lock_bh(&ctx->lock); + list_del_init(&req->list); + if (req_custom->num_fence_map_out) + list_add_tail(&req->list, &ctx->active_req_list); + else + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + +end: + return rc; +} + +static int __cam_custom_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + rc = __cam_custom_stop_dev_core(ctx, NULL); + if (rc) + CAM_ERR(CAM_CUSTOM, "Stop device failed rc=%d", rc); + + rc = __cam_custom_release_dev_in_acquired(ctx, cmd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Release device failed rc=%d", rc); + + return rc; +} + +static int __cam_custom_ctx_unlink_in_activated(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + CAM_WARN(CAM_CUSTOM, + "Received unlink in activated state. It's unexpected"); + + rc = __cam_custom_stop_dev_in_activated(ctx, NULL); + if (rc) + CAM_WARN(CAM_CUSTOM, "Stop device failed rc=%d", rc); + + rc = __cam_custom_ctx_unlink_in_ready(ctx, unlink); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unlink failed rc=%d", rc); + + return rc; +} + +static int __cam_custom_ctx_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *link_evt_data) +{ + switch (link_evt_data->evt_type) { + case CAM_REQ_MGR_LINK_EVT_ERR: + /* Handle error/bubble related issues */ + break; + default: + CAM_WARN(CAM_CUSTOM, "Unknown event from CRM"); + break; + } + + return 0; +} + +static int __cam_custom_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc; + struct cam_context *ctx = + (struct cam_context *)context; + + CAM_DBG(CAM_CUSTOM, "Enter %d", ctx->ctx_id); + + /* + * handle based on different irq's currently + * triggering only buf done if there are fences + */ + rc = cam_context_buf_done_from_hw(ctx, evt_data, 0); + if (rc) + CAM_ERR(CAM_CUSTOM, "Failed in buf done, rc=%d", rc); + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_custom_dev_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = + __cam_custom_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_custom_release_dev_in_acquired, + .config_dev = __cam_custom_ctx_config_dev_in_acquired, + }, + .crm_ops = { + .link = __cam_custom_ctx_link_in_acquired, + .unlink = __cam_custom_ctx_unlink_in_acquired, + .get_dev_info = + __cam_custom_ctx_get_dev_info_in_acquired, + .flush_req = __cam_custom_ctx_flush_req_in_top_state, + }, + .irq_ops = NULL, + .pagefault_ops = NULL, + }, + /* Ready */ + { + .ioctl_ops = { + .start_dev = __cam_custom_ctx_start_dev_in_ready, + .release_dev = __cam_custom_release_dev_in_acquired, + .config_dev = __cam_custom_ctx_config_dev, + }, + .crm_ops = { + .unlink = __cam_custom_ctx_unlink_in_ready, + .flush_req = __cam_custom_ctx_flush_req_in_ready, + }, + .irq_ops = NULL, + .pagefault_ops = NULL, + }, + /* Flushed */ + {}, + /* Activated */ + { + .ioctl_ops = { + .stop_dev = __cam_custom_stop_dev_in_activated, + .release_dev = + __cam_custom_ctx_release_dev_in_activated, + .config_dev = __cam_custom_ctx_config_dev, + }, + .crm_ops = { + .unlink = __cam_custom_ctx_unlink_in_activated, + .apply_req = + __cam_custom_ctx_apply_req_in_activated_state, + .flush_req = __cam_custom_ctx_flush_req_in_top_state, + .process_evt = __cam_custom_ctx_process_evt, + }, + .irq_ops = __cam_custom_ctx_handle_irq_in_activated, + .pagefault_ops = NULL, + }, +}; + +int cam_custom_dev_context_init(struct cam_custom_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) +{ + int rc = -1, i = 0; + + if (!ctx || !ctx_base) { + CAM_ERR(CAM_CUSTOM, "Invalid Context"); + return -EINVAL; + } + + /* Custom HW context setup */ + memset(ctx, 0, sizeof(*ctx)); + + ctx->base = ctx_base; + ctx->frame_id = 0; + ctx->active_req_cnt = 0; + ctx->hw_ctx = NULL; + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + ctx->req_base[i].req_priv = &ctx->req_custom[i]; + ctx->req_custom[i].base = &ctx->req_base[i]; + } + + /* camera context setup */ + rc = cam_context_init(ctx_base, custom_dev_name, CAM_CUSTOM, ctx_id, + crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Camera Context Base init failed"); + return rc; + } + + /* link camera context with custom HW context */ + ctx_base->state_machine = cam_custom_dev_ctx_top_state_machine; + ctx_base->ctx_priv = ctx; + + return rc; +} + +int cam_custom_dev_context_deinit(struct cam_custom_context *ctx) +{ + if (ctx->base) + cam_context_deinit(ctx->base); + + memset(ctx, 0, sizeof(*ctx)); + return 0; +} diff --git a/techpack/camera/drivers/cam_cust/cam_custom_context.h b/techpack/camera/drivers/cam_cust/cam_custom_context.h new file mode 100644 index 0000000000000000000000000000000000000000..91acf1e5ee803a5e6a6a89ff0417aa35c62a89ef --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_context.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_CONTEXT_H_ +#define _CAM_CUSTOM_CONTEXT_H_ + +#include <linux/spinlock.h> +#include <uapi/media/cam_custom.h> +#include <uapi/media/cam_defs.h> + +#include "cam_context.h" +#include "cam_custom_hw_mgr_intf.h" + +/* + * Maximum hw resource - This number is based on the maximum + * output port resource. The current maximum resource number + * is 2. + */ +#define CAM_CUSTOM_DEV_CTX_RES_MAX 2 + +#define CAM_CUSTOM_CTX_CFG_MAX 8 + +/* forward declaration */ +struct cam_custom_context; + +/** + * struct cam_custom_dev_ctx_req - Custom context request object + * + * @base: Common request object pointer + * @cfg: Custom hardware configuration array + * @num_cfg: Number of custom hardware configuration entries + * @fence_map_out: Output fence mapping array + * @num_fence_map_out: Number of the output fence map + * @fence_map_in: Input fence mapping array + * @num_fence_map_in: Number of input fence map + * @num_acked: Count to track acked entried for output. + * If count equals the number of fence out, it means + * the request has been completed. + * @hw_update_data: HW update data for this request + * + */ +struct cam_custom_dev_ctx_req { + struct cam_ctx_request *base; + struct cam_hw_update_entry cfg + [CAM_CUSTOM_CTX_CFG_MAX]; + uint32_t num_cfg; + struct cam_hw_fence_map_entry fence_map_out + [CAM_CUSTOM_DEV_CTX_RES_MAX]; + uint32_t num_fence_map_out; + struct cam_hw_fence_map_entry fence_map_in + [CAM_CUSTOM_DEV_CTX_RES_MAX]; + uint32_t num_fence_map_in; + uint32_t num_acked; + struct cam_custom_prepare_hw_update_data hw_update_data; +}; + +/** + * struct cam_custom_context - Custom device context + * @base: custom device context object + * @state_machine: state machine for Custom device context + * @state: Common context state + * @hw_ctx: HW object returned by the acquire device command + * @init_received: Indicate whether init config packet is received + * @subscribe_event: The irq event mask that CRM subscribes to, + * custom HW will invoke CRM cb at those event. + * @active_req_cnt: Counter for the active request + * @frame_id: Frame id tracking for the custom context + * @req_base: common request structure + * @req_custom: custom request structure + * + */ +struct cam_custom_context { + struct cam_context *base; + struct cam_ctx_ops *state_machine; + uint32_t state; + void *hw_ctx; + bool init_received; + uint32_t subscribe_event; + uint32_t active_req_cnt; + int64_t frame_id; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_custom_dev_ctx_req req_custom[CAM_CTX_REQ_MAX]; +}; + + +/** + * cam_custom_dev_context_init() + * + * @brief: Initialization function for the custom context + * + * @ctx: Custom context obj to be initialized + * @bridge_ops: Bridge call back funciton + * @hw_intf: Cust hw manager interface + * @ctx_id: ID for this context + * + */ +int cam_custom_dev_context_init(struct cam_custom_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *bridge_ops, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); + +/** + * cam_custom_dev_context_deinit() + * + * @brief: Deinitialize function for the Custom context + * + * @ctx: Custom context obj to be deinitialized + * + */ +int cam_custom_dev_context_deinit(struct cam_custom_context *ctx); + +#endif /* _CAM_CUSTOM_CONTEXT_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_dev.c b/techpack/camera/drivers/cam_cust/cam_custom_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..76d4a7d0e17bd43fbb04f348f87f93a63f6749a1 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_dev.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/ion.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include <uapi/media/cam_req_mgr.h> +#include "cam_custom_dev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_custom_hw_mgr_intf.h" +#include "cam_node.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +static struct cam_custom_dev g_custom_dev; + +static void cam_custom_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_CUSTOM, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static const struct of_device_id cam_custom_dt_match[] = { + { + .compatible = "qcom,cam-custom" + }, + {} +}; + +static int cam_custom_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + mutex_lock(&g_custom_dev.custom_dev_mutex); + g_custom_dev.open_cnt++; + mutex_unlock(&g_custom_dev.custom_dev_mutex); + + return 0; +} + +static int cam_custom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_custom_dev.custom_dev_mutex); + if (g_custom_dev.open_cnt <= 0) { + CAM_DBG(CAM_CUSTOM, "Custom subdev is already closed"); + rc = -EINVAL; + goto end; + } + + g_custom_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_CUSTOM, "Node ptr is NULL"); + rc = -EINVAL; + goto end; + } + + if (g_custom_dev.open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&g_custom_dev.custom_dev_mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_custom_subdev_internal_ops = { + .close = cam_custom_subdev_close, + .open = cam_custom_subdev_open, +}; + +static int cam_custom_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + int i; + + /* clean up resources */ + for (i = 0; i < CAM_CUSTOM_HW_MAX_INSTANCES; i++) { + rc = cam_custom_dev_context_deinit(&g_custom_dev.ctx_custom[i]); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Custom context %d deinit failed", i); + } + + rc = cam_subdev_remove(&g_custom_dev.sd); + if (rc) + CAM_ERR(CAM_CUSTOM, "Unregister failed"); + + memset(&g_custom_dev, 0, sizeof(g_custom_dev)); + return 0; +} + +static int cam_custom_dev_probe(struct platform_device *pdev) +{ + int rc = -EINVAL; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + int iommu_hdl = -1; + + g_custom_dev.sd.internal_ops = &cam_custom_subdev_internal_ops; + + rc = cam_subdev_probe(&g_custom_dev.sd, pdev, CAM_CUSTOM_DEV_NAME, + CAM_CUSTOM_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom device cam_subdev_probe failed!"); + goto err; + } + node = (struct cam_node *) g_custom_dev.sd.token; + + memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf)); + rc = cam_custom_hw_mgr_init(pdev->dev.of_node, + &hw_mgr_intf, &iommu_hdl); + if (rc != 0) { + CAM_ERR(CAM_CUSTOM, "Can not initialized Custom HW manager!"); + goto unregister; + } + + for (i = 0; i < CAM_CUSTOM_HW_MAX_INSTANCES; i++) { + rc = cam_custom_dev_context_init(&g_custom_dev.ctx_custom[i], + &g_custom_dev.ctx[i], + &node->crm_node_intf, + &node->hw_mgr_intf, + i); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom context init failed!"); + goto unregister; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_custom_dev.ctx, + CAM_CUSTOM_HW_MAX_INSTANCES, CAM_CUSTOM_DEV_NAME); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom HW node init failed!"); + goto unregister; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_custom_dev_iommu_fault_handler, node); + + mutex_init(&g_custom_dev.custom_dev_mutex); + + CAM_DBG(CAM_CUSTOM, "Camera custom HW probe complete"); + + return 0; +unregister: + rc = cam_subdev_remove(&g_custom_dev.sd); +err: + return rc; +} + + +static struct platform_driver custom_driver = { + .probe = cam_custom_dev_probe, + .remove = cam_custom_dev_remove, + .driver = { + .name = "cam_custom", + .of_match_table = cam_custom_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_custom_dev_init_module(void) +{ + return platform_driver_register(&custom_driver); +} + +static void __exit cam_custom_dev_exit_module(void) +{ + platform_driver_unregister(&custom_driver); +} + +module_init(cam_custom_dev_init_module); +module_exit(cam_custom_dev_exit_module); +MODULE_DESCRIPTION("MSM CUSTOM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_cust/cam_custom_dev.h b/techpack/camera/drivers/cam_cust/cam_custom_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..77ea6badfe942d6d3fd37fd786098bd479726541 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_dev.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_DEV_H_ +#define _CAM_CUSTOM_DEV_H_ + +#include "cam_subdev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_custom_hw_mgr.h" +#include "cam_context.h" +#include "cam_custom_context.h" + +#define CAM_CUSTOM_HW_MAX_INSTANCES 3 + +/** + * struct cam_custom_dev - Camera Custom V4l2 device node + * + * @sd: Common camera subdevice node + * @ctx: Custom base context storage + * @ctx_custom: Custom private context storage + * @custom_dev_mutex: Custom dev mutex + * @open_cnt: Open device count + */ +struct cam_custom_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CUSTOM_HW_MAX_INSTANCES]; + struct cam_custom_context ctx_custom[CAM_CUSTOM_HW_MAX_INSTANCES]; + struct mutex custom_dev_mutex; + int32_t open_cnt; +}; + +#endif /* _CAM_CUSTOM_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/Makefile b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1e0917637b8e32b44f93ac7f5480555ae619b62e --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/Makefile @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw1/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw1/ cam_custom_csid/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_hw_mgr.o + diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ab36c88628881296fc6956c0e92a2f2723b915cd --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_csid_dev.o diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h new file mode 100644 index 0000000000000000000000000000000000000000..a55bb002ffc264efddffee5814efd853f9333fb0 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid480.h @@ -0,0 +1,272 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_CSID_480_H_ +#define _CAM_CUSTOM_CSID_480_H_ + +#include "cam_ife_csid_core.h" + +#define CAM_CSID_VERSION_V480 0x40080000 + +static struct cam_ife_csid_udi_reg_offset + cam_custom_csid_480_udi_0_reg_offset = { + .csid_udi_irq_status_addr = 0x30, + .csid_udi_irq_mask_addr = 0x34, + .csid_udi_irq_clear_addr = 0x38, + .csid_udi_irq_set_addr = 0x3c, + .csid_udi_cfg0_addr = 0x200, + .csid_udi_cfg1_addr = 0x204, + .csid_udi_ctrl_addr = 0x208, + .csid_udi_frm_drop_pattern_addr = 0x20c, + .csid_udi_frm_drop_period_addr = 0x210, + .csid_udi_irq_subsample_pattern_addr = 0x214, + .csid_udi_irq_subsample_period_addr = 0x218, + .csid_udi_rpp_hcrop_addr = 0x21c, + .csid_udi_rpp_vcrop_addr = 0x220, + .csid_udi_rpp_pix_drop_pattern_addr = 0x224, + .csid_udi_rpp_pix_drop_period_addr = 0x228, + .csid_udi_rpp_line_drop_pattern_addr = 0x22c, + .csid_udi_rpp_line_drop_period_addr = 0x230, + .csid_udi_rst_strobes_addr = 0x240, + .csid_udi_status_addr = 0x250, + .csid_udi_misr_val0_addr = 0x254, + .csid_udi_misr_val1_addr = 0x258, + .csid_udi_misr_val2_addr = 0x25c, + .csid_udi_misr_val3_addr = 0x260, + .csid_udi_format_measure_cfg0_addr = 0x270, + .csid_udi_format_measure_cfg1_addr = 0x274, + .csid_udi_format_measure0_addr = 0x278, + .csid_udi_format_measure1_addr = 0x27c, + .csid_udi_format_measure2_addr = 0x280, + .csid_udi_timestamp_curr0_sof_addr = 0x290, + .csid_udi_timestamp_curr1_sof_addr = 0x294, + .csid_udi_timestamp_prev0_sof_addr = 0x298, + .csid_udi_timestamp_prev1_sof_addr = 0x29c, + .csid_udi_timestamp_curr0_eof_addr = 0x2a0, + .csid_udi_timestamp_curr1_eof_addr = 0x2a4, + .csid_udi_timestamp_prev0_eof_addr = 0x2a8, + .csid_udi_timestamp_prev1_eof_addr = 0x2ac, + .csid_udi_err_recovery_cfg0_addr = 0x2b0, + .csid_udi_err_recovery_cfg1_addr = 0x2b4, + .csid_udi_err_recovery_cfg2_addr = 0x2b8, + .csid_udi_multi_vcdt_cfg0_addr = 0x2bc, + .csid_udi_byte_cntr_ping_addr = 0x2e0, + .csid_udi_byte_cntr_pong_addr = 0x2e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_udi_reg_offset + cam_custom_csid_480_udi_1_reg_offset = { + .csid_udi_irq_status_addr = 0x40, + .csid_udi_irq_mask_addr = 0x44, + .csid_udi_irq_clear_addr = 0x48, + .csid_udi_irq_set_addr = 0x4c, + .csid_udi_cfg0_addr = 0x300, + .csid_udi_cfg1_addr = 0x304, + .csid_udi_ctrl_addr = 0x308, + .csid_udi_frm_drop_pattern_addr = 0x30c, + .csid_udi_frm_drop_period_addr = 0x310, + .csid_udi_irq_subsample_pattern_addr = 0x314, + .csid_udi_irq_subsample_period_addr = 0x318, + .csid_udi_rpp_hcrop_addr = 0x31c, + .csid_udi_rpp_vcrop_addr = 0x320, + .csid_udi_rpp_pix_drop_pattern_addr = 0x324, + .csid_udi_rpp_pix_drop_period_addr = 0x328, + .csid_udi_rpp_line_drop_pattern_addr = 0x32c, + .csid_udi_rpp_line_drop_period_addr = 0x330, + .csid_udi_rst_strobes_addr = 0x340, + .csid_udi_status_addr = 0x350, + .csid_udi_misr_val0_addr = 0x354, + .csid_udi_misr_val1_addr = 0x358, + .csid_udi_misr_val2_addr = 0x35c, + .csid_udi_misr_val3_addr = 0x360, + .csid_udi_format_measure_cfg0_addr = 0x370, + .csid_udi_format_measure_cfg1_addr = 0x374, + .csid_udi_format_measure0_addr = 0x378, + .csid_udi_format_measure1_addr = 0x37c, + .csid_udi_format_measure2_addr = 0x380, + .csid_udi_timestamp_curr0_sof_addr = 0x390, + .csid_udi_timestamp_curr1_sof_addr = 0x394, + .csid_udi_timestamp_prev0_sof_addr = 0x398, + .csid_udi_timestamp_prev1_sof_addr = 0x39c, + .csid_udi_timestamp_curr0_eof_addr = 0x3a0, + .csid_udi_timestamp_curr1_eof_addr = 0x3a4, + .csid_udi_timestamp_prev0_eof_addr = 0x3a8, + .csid_udi_timestamp_prev1_eof_addr = 0x3ac, + .csid_udi_err_recovery_cfg0_addr = 0x3b0, + .csid_udi_err_recovery_cfg1_addr = 0x3b4, + .csid_udi_err_recovery_cfg2_addr = 0x3b8, + .csid_udi_multi_vcdt_cfg0_addr = 0x3bc, + .csid_udi_byte_cntr_ping_addr = 0x3e0, + .csid_udi_byte_cntr_pong_addr = 0x3e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_udi_reg_offset + cam_custom_csid_480_udi_2_reg_offset = { + .csid_udi_irq_status_addr = 0x50, + .csid_udi_irq_mask_addr = 0x54, + .csid_udi_irq_clear_addr = 0x58, + .csid_udi_irq_set_addr = 0x5c, + .csid_udi_cfg0_addr = 0x400, + .csid_udi_cfg1_addr = 0x404, + .csid_udi_ctrl_addr = 0x408, + .csid_udi_frm_drop_pattern_addr = 0x40c, + .csid_udi_frm_drop_period_addr = 0x410, + .csid_udi_irq_subsample_pattern_addr = 0x414, + .csid_udi_irq_subsample_period_addr = 0x418, + .csid_udi_rpp_hcrop_addr = 0x41c, + .csid_udi_rpp_vcrop_addr = 0x420, + .csid_udi_rpp_pix_drop_pattern_addr = 0x424, + .csid_udi_rpp_pix_drop_period_addr = 0x428, + .csid_udi_rpp_line_drop_pattern_addr = 0x42c, + .csid_udi_rpp_line_drop_period_addr = 0x430, + .csid_udi_yuv_chroma_conversion_addr = 0x434, + .csid_udi_rst_strobes_addr = 0x440, + .csid_udi_status_addr = 0x450, + .csid_udi_misr_val0_addr = 0x454, + .csid_udi_misr_val1_addr = 0x458, + .csid_udi_misr_val2_addr = 0x45c, + .csid_udi_misr_val3_addr = 0x460, + .csid_udi_format_measure_cfg0_addr = 0x470, + .csid_udi_format_measure_cfg1_addr = 0x474, + .csid_udi_format_measure0_addr = 0x478, + .csid_udi_format_measure1_addr = 0x47c, + .csid_udi_format_measure2_addr = 0x480, + .csid_udi_timestamp_curr0_sof_addr = 0x490, + .csid_udi_timestamp_curr1_sof_addr = 0x494, + .csid_udi_timestamp_prev0_sof_addr = 0x498, + .csid_udi_timestamp_prev1_sof_addr = 0x49c, + .csid_udi_timestamp_curr0_eof_addr = 0x4a0, + .csid_udi_timestamp_curr1_eof_addr = 0x4a4, + .csid_udi_timestamp_prev0_eof_addr = 0x4a8, + .csid_udi_timestamp_prev1_eof_addr = 0x4ac, + .csid_udi_err_recovery_cfg0_addr = 0x4b0, + .csid_udi_err_recovery_cfg1_addr = 0x4b4, + .csid_udi_err_recovery_cfg2_addr = 0x4b8, + .csid_udi_multi_vcdt_cfg0_addr = 0x4bc, + .csid_udi_byte_cntr_ping_addr = 0x4e0, + .csid_udi_byte_cntr_pong_addr = 0x4e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_custom_csid_480_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_common_reg_offset + cam_custom_csid_480_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_udis = 3, + .num_rdis = 0, + .num_pix = 0, + .num_ppp = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0, + .rdi_irq_mask_all = 0, + .ppp_irq_mask_all = 0, + .udi_irq_mask_all = 0x7FFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, + .num_bytes_out_shift_val = 3, +}; + +static struct cam_ife_csid_reg_offset cam_custom_csid_480_reg_offset = { + .cmn_reg = &cam_custom_csid_480_cmn_reg_offset, + .csi2_reg = &cam_custom_csid_480_csi2_reg_offset, + .ipp_reg = NULL, + .ppp_reg = NULL, + .rdi_reg = { + NULL, + NULL, + NULL, + NULL, + }, + .udi_reg = { + &cam_custom_csid_480_udi_0_reg_offset, + &cam_custom_csid_480_udi_1_reg_offset, + &cam_custom_csid_480_udi_2_reg_offset, + }, + .tpg_reg = NULL, +}; + +#endif /*_CAM_IFE_CSID_480_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..be472372aeb04a272c6a75322bcd8e2dc4de8c63 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include "linux/module.h" +#include "cam_custom_csid_dev.h" +#include "cam_ife_csid_core.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_custom_csid480.h" +#include "cam_debug_util.h" + +#define CAM_CUSTOM_CSID_DRV_NAME "custom_csid" + +static struct cam_hw_intf *cam_custom_csid_hw_list[CAM_IFE_CSID_HW_NUM_MAX] = { + 0, 0, 0, 0}; + +static char csid_dev_name[16]; + +static struct cam_ife_csid_hw_info cam_custom_csid480_hw_info = { + .csid_reg = &cam_custom_csid_480_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V480, +}; + +static int cam_custom_csid_probe(struct platform_device *pdev) +{ + + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + struct cam_ife_csid_hw *csid_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ife_csid_hw_info *csid_hw_data = NULL; + uint32_t csid_dev_idx; + int rc = 0; + + csid_hw_intf = kzalloc(sizeof(*csid_hw_intf), GFP_KERNEL); + if (!csid_hw_intf) { + rc = -ENOMEM; + goto err; + } + + csid_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!csid_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + csid_dev = kzalloc(sizeof(struct cam_ife_csid_hw), GFP_KERNEL); + if (!csid_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + /* get custom csid hw index */ + of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx); + /* get custom csid hw information */ + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_CUSTOM, + "No matching table for the CUSTOM CSID HW!"); + rc = -EINVAL; + goto free_dev; + } + + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid-custom%1u", csid_dev_idx); + + csid_hw_intf->hw_idx = csid_dev_idx; + csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_IFE_CSID; + csid_hw_intf->hw_priv = csid_hw_info; + + csid_hw_info->core_info = csid_dev; + csid_hw_info->soc_info.pdev = pdev; + csid_hw_info->soc_info.dev = &pdev->dev; + csid_hw_info->soc_info.dev_name = csid_dev_name; + csid_hw_info->soc_info.index = csid_dev_idx; + + csid_hw_data = (struct cam_ife_csid_hw_info *)match_dev->data; + csid_dev->csid_info = csid_hw_data; + + rc = cam_ife_csid_hw_probe_init(csid_hw_intf, csid_dev_idx, true); + if (rc) + goto free_dev; + + platform_set_drvdata(pdev, csid_dev); + CAM_DBG(CAM_CUSTOM, "CSID:%d probe successful for dev %s", + csid_hw_intf->hw_idx, csid_dev_name); + + if (csid_hw_intf->hw_idx < CAM_IFE_CSID_HW_NUM_MAX) + cam_custom_csid_hw_list[csid_hw_intf->hw_idx] = csid_hw_intf; + else + goto free_dev; + + return 0; + +free_dev: + kfree(csid_dev); +free_hw_info: + kfree(csid_hw_info); +free_hw_intf: + kfree(csid_hw_intf); +err: + return rc; +} + +static int cam_custom_csid_remove(struct platform_device *pdev) +{ + struct cam_ife_csid_hw *csid_dev = NULL; + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + + csid_dev = (struct cam_ife_csid_hw *)platform_get_drvdata(pdev); + csid_hw_intf = csid_dev->hw_intf; + csid_hw_info = csid_dev->hw_info; + + CAM_DBG(CAM_CUSTOM, "CSID:%d remove", + csid_dev->hw_intf->hw_idx); + + cam_ife_csid_hw_deinit(csid_dev); + + /*release the csid device memory */ + kfree(csid_dev); + kfree(csid_hw_info); + kfree(csid_hw_intf); + return 0; +} + +static const struct of_device_id cam_custom_csid_dt_match[] = { + { + .compatible = "qcom,csid-custom480", + .data = &cam_custom_csid480_hw_info + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_custom_csid_dt_match); + +static struct platform_driver cam_custom_csid_driver = { + .probe = cam_custom_csid_probe, + .driver = { + .name = "qcom,custom-csid", + .of_match_table = cam_custom_csid_dt_match, + .suppress_bind_attrs = true, + }, + .remove = cam_custom_csid_remove, +}; + +static int __init cam_custom_csid_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_custom_csid_driver); + if (rc < 0) + CAM_ERR(CAM_CUSTOM, "platform_driver_register Failed: rc = %d", + rc); + + return rc; +} + +int cam_custom_csid_hw_init(struct cam_hw_intf **custom_csid_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_custom_csid_hw_list[hw_idx]) { + *custom_csid_hw = cam_custom_csid_hw_list[hw_idx]; + } else { + *custom_csid_hw = NULL; + rc = -1; + } + + return rc; +} + +static void __exit cam_custom_csid_driver_exit(void) +{ + platform_driver_unregister(&cam_custom_csid_driver); +} + +module_init(cam_custom_csid_driver_init); +module_exit(cam_custom_csid_driver_exit); +MODULE_DESCRIPTION("cam_custom_csid_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..f0c086ccab181fc30d973e2b18c045176c2bbc1e --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_csid/cam_custom_csid_dev.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_DEV_H_ +#define _CAM_IFE_CSID_DEV_H_ + +#include "cam_debug_util.h" +#include "cam_custom_hw_mgr_intf.h" + +#endif /*_CAM_IFE_CSID_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..4895219ffd062ee0d6245258efe65d7530ed9ce1 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1 + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_custom_sub_mod_soc.o cam_custom_sub_mod_dev.o cam_custom_sub_mod_core.o diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c new file mode 100644 index 0000000000000000000000000000000000000000..9ac5da25571e9b9c7e366f08426dacd044aa4e3f --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/ratelimit.h> +#include "cam_custom_sub_mod_core.h" + +int cam_custom_hw_sub_mod_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + /* Add HW Capabilities to be published */ + return rc; +} + +int cam_custom_hw_sub_mod_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_resource_node *custom_res = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + custom_hw->open_count++; + if (custom_hw->open_count > 1) { + mutex_unlock(&custom_hw->hw_mutex); + CAM_DBG(CAM_CUSTOM, + "Cam Custom has already been initialized cnt %d", + custom_hw->open_count); + return 0; + } + mutex_unlock(&custom_hw->hw_mutex); + + soc_info = &custom_hw->soc_info; + + /* Turn ON Regulators, Clocks and other SOC resources */ + rc = cam_custom_hw_sub_mod_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Enable SOC failed"); + rc = -EFAULT; + goto decrement_open_cnt; + } + + custom_res = (struct cam_custom_resource_node *)init_hw_args; + if (custom_res && custom_res->init) { + rc = custom_res->init(custom_res, NULL, 0); + if (rc) { + CAM_ERR(CAM_CUSTOM, "init Failed rc=%d", rc); + goto decrement_open_cnt; + } + } + + rc = cam_custom_hw_sub_mod_reset(hw_priv, NULL, 0); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, "Custom HW reset failed : %d", rc); + goto decrement_open_cnt; + } + /* Initialize all resources here */ + custom_hw->hw_state = CAM_HW_STATE_POWER_UP; + return rc; + +decrement_open_cnt: + mutex_lock(&custom_hw->hw_mutex); + custom_hw->open_count--; + mutex_unlock(&custom_hw->hw_mutex); + return rc; +} + +int cam_custom_hw_sub_mod_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_resource_node *custom_res = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + if (!custom_hw->open_count) { + mutex_unlock(&custom_hw->hw_mutex); + CAM_ERR(CAM_CUSTOM, "Error! Unbalanced deinit"); + return -EFAULT; + } + custom_hw->open_count--; + if (custom_hw->open_count) { + mutex_unlock(&custom_hw->hw_mutex); + CAM_DBG(CAM_CUSTOM, + "open_cnt non-zero =%d", custom_hw->open_count); + return 0; + } + mutex_unlock(&custom_hw->hw_mutex); + + soc_info = &custom_hw->soc_info; + + custom_res = (struct cam_custom_resource_node *)deinit_hw_args; + if (custom_res && custom_res->deinit) { + rc = custom_res->deinit(custom_res, NULL, 0); + if (rc) + CAM_ERR(CAM_CUSTOM, "deinit failed"); + } + + rc = cam_custom_hw_sub_mod_reset(hw_priv, NULL, 0); + + /* Turn OFF Regulators, Clocks and other SOC resources */ + CAM_DBG(CAM_CUSTOM, "Disable SOC resource"); + rc = cam_custom_hw_sub_mod_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_CUSTOM, "Disable SOC failed"); + + custom_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + return rc; +} + +int cam_custom_hw_sub_mod_reset(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &custom_hw->soc_info; + /* Do Reset of HW */ + return rc; +} + +int cam_custom_hw_sub_mod_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + int rc = 0; + + if (!hw_priv || !reserve_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + /*Reserve Args */ + return rc; +} + + +int cam_custom_hw_sub_mod_release(void *hw_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + int rc = 0; + + if (!hw_priv || !release_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + /* Release Resources */ + mutex_unlock(&custom_hw->hw_mutex); + + return rc; +} + + +int cam_custom_hw_sub_mod_start(void *hw_priv, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + int rc = 0; + + if (!hw_priv || !start_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + /* Start HW -- Stream On*/ + mutex_unlock(&custom_hw->hw_mutex); + + return rc; +} + +int cam_custom_hw_sub_mod_stop(void *hw_priv, + void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *custom_hw = hw_priv; + int rc = 0; + + if (!hw_priv || !stop_args) { + CAM_ERR(CAM_CUSTOM, "Invalid input arguments"); + return -EINVAL; + } + + mutex_lock(&custom_hw->hw_mutex); + /* Stop HW */ + mutex_unlock(&custom_hw->hw_mutex); + + return rc; +} + +int cam_custom_hw_sub_mod_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_custom_hw_sub_mod_write(void *hw_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_custom_hw_submit_req(void *hw_priv, void *hw_submit_args, + uint32_t arg_size) +{ + struct cam_hw_info *custom_dev = hw_priv; + struct cam_custom_sub_mod_req_to_dev *submit_req = + (struct cam_custom_sub_mod_req_to_dev *)hw_submit_args; + struct cam_custom_sub_mod_core_info *core_info = NULL; + + core_info = + (struct cam_custom_sub_mod_core_info *)custom_dev->core_info; + + spin_lock(&custom_dev->hw_lock); + if (core_info->curr_req) { + CAM_WARN(CAM_CUSTOM, "Req %lld still processed by %s", + core_info->curr_req->req_id, + custom_dev->soc_info.dev_name); + spin_unlock(&custom_dev->hw_lock); + return -EAGAIN; + } + + core_info->curr_req = submit_req; + spin_unlock(&custom_dev->hw_lock); + + /* Do other submit procedures */ + return 0; +} + +irqreturn_t cam_custom_hw_sub_mod_irq(int irq_num, void *data) +{ + struct cam_hw_info *custom_dev = data; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_hw_cb_args cb_args; + struct cam_custom_sub_mod_core_info *core_info = NULL; + uint32_t irq_status = 0; + + if (!data) { + CAM_ERR(CAM_CUSTOM, "Invalid custom_dev_info"); + return IRQ_HANDLED; + } + + soc_info = &custom_dev->soc_info; + core_info = + (struct cam_custom_sub_mod_core_info *)custom_dev->core_info; + + irq_status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + core_info->device_hw_info->irq_status); + + cam_io_w_mb(irq_status, + soc_info->reg_map[0].mem_base + + core_info->device_hw_info->irq_clear); + + spin_lock(&custom_dev->hw_lock); + cb_args.irq_status = irq_status; + cb_args.req_info = core_info->curr_req; + core_info->curr_req = NULL; + if (core_info->irq_cb.custom_hw_mgr_cb) + core_info->irq_cb.custom_hw_mgr_cb( + core_info->irq_cb.data, &cb_args); + spin_unlock(&custom_dev->hw_lock); + + return IRQ_HANDLED; +} + +int cam_custom_hw_sub_mod_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_custom_sub_mod_core_info *core_info = NULL; + unsigned long flag = 0; + int rc = 0; + + if (!hw_priv || !cmd_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &hw->soc_info; + core_info = hw->core_info; + /* Handle any custom process cmds */ + + switch (cmd_type) { + case CAM_CUSTOM_SET_IRQ_CB: { + struct cam_custom_sub_mod_set_irq_cb *irq_cb = cmd_args; + + CAM_DBG(CAM_CUSTOM, "Setting irq cb"); + spin_lock_irqsave(&hw->hw_lock, flag); + core_info->irq_cb.custom_hw_mgr_cb = irq_cb->custom_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + spin_unlock_irqrestore(&hw->hw_lock, flag); + break; + } + case CAM_CUSTOM_SUBMIT_REQ: { + rc = cam_custom_hw_submit_req(hw_priv, cmd_args, arg_size); + break; + } + default: + break; + } + + return rc; +} + + diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h new file mode 100644 index 0000000000000000000000000000000000000000..d27d578f6c8d9352e0ada24f9fb1bc093c55fa64 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_core.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_SUB_MOD_CORE_H_ +#define _CAM_CUSTOM_SUB_MOD_CORE_H_ + +#include "cam_debug_util.h" +#include "cam_custom_hw.h" +#include "cam_custom_sub_mod_soc.h" +#include "cam_custom_hw_mgr_intf.h" + +struct cam_custom_sub_mod_set_irq_cb { + int32_t (*custom_hw_mgr_cb)(void *data, + struct cam_custom_hw_cb_args *cb_args); + void *data; +}; + +struct cam_custom_sub_mod_req_to_dev { + uint64_t req_id; + uint32_t ctx_idx; + uint32_t dev_idx; +}; + +struct cam_custom_device_hw_info { + uint32_t hw_ver; + uint32_t irq_status; + uint32_t irq_mask; + uint32_t irq_clear; +}; + +struct cam_custom_sub_mod_core_info { + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; + struct cam_custom_sub_mod_set_irq_cb irq_cb; + struct cam_custom_sub_mod_req_to_dev *curr_req; + struct cam_custom_device_hw_info *device_hw_info; + struct cam_hw_info *custom_hw_info; +}; + +enum cam_custom_hw_resource_type { + CAM_CUSTOM_HW_RESOURCE_UNINT, + CAM_CUSTOM_HW_RESOURCE_SRC, + CAM_CUSTOM_HW_RESOURCE_MAX, +}; + +struct cam_custom_sub_mod_acq { + enum cam_custom_hw_resource_type rsrc_type; + int32_t acq; + struct cam_custom_resource_node *rsrc_node; +}; + +int cam_custom_hw_sub_mod_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_reset(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_release(void *hw_priv, + void *release_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_start(void *hw_priv, + void *start_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_stop(void *hw_priv, + void *stop_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_read(void *hw_priv, + void *read_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_write(void *hw_priv, + void *write_args, uint32_t arg_size); +int cam_custom_hw_sub_mod_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_custom_hw_sub_mod_irq(int irq_num, void *data); + +#endif /* _CAM_CUSTOM_SUB_MOD_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..bd7d659136498fa29cec341e43e1cdf4889eaf7d --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include "cam_custom_sub_mod_dev.h" +#include "cam_custom_sub_mod_core.h" +#include "cam_custom_sub_mod_soc.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_custom_hw_sub_mod_list + [CAM_CUSTOM_SUB_MOD_MAX_INSTANCES] = {0, 0}; + +static char cam_custom_hw_sub_mod_name[8]; + +struct cam_custom_device_hw_info cam_custom_hw_info = { + .hw_ver = 0x0, + .irq_status = 0x0, + .irq_mask = 0x0, + .irq_clear = 0x0, +}; +EXPORT_SYMBOL(cam_custom_hw_info); + +int cam_custom_hw_sub_mod_init(struct cam_hw_intf **custom_hw, uint32_t hw_idx) +{ + int rc = 0; + + if (cam_custom_hw_sub_mod_list[hw_idx]) { + *custom_hw = cam_custom_hw_sub_mod_list[hw_idx]; + rc = 0; + } else { + *custom_hw = NULL; + rc = -ENODEV; + } + return 0; +} + +int cam_custom_hw_sub_mod_probe(struct platform_device *pdev) +{ + struct cam_hw_info *hw = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_custom_sub_mod_core_info *core_info = NULL; + int rc = 0; + + hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!hw_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_intf->hw_idx); + + hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!hw) { + rc = -ENOMEM; + goto free_hw_intf; + } + + memset(cam_custom_hw_sub_mod_name, 0, + sizeof(cam_custom_hw_sub_mod_name)); + snprintf(cam_custom_hw_sub_mod_name, sizeof(cam_custom_hw_sub_mod_name), + "custom_hw%1u", hw_intf->hw_idx); + + hw->soc_info.pdev = pdev; + hw->soc_info.dev = &pdev->dev; + hw->soc_info.dev_name = cam_custom_hw_sub_mod_name; + hw_intf->hw_priv = hw; + hw_intf->hw_ops.get_hw_caps = cam_custom_hw_sub_mod_get_hw_caps; + hw_intf->hw_ops.init = cam_custom_hw_sub_mod_init_hw; + hw_intf->hw_ops.deinit = cam_custom_hw_sub_mod_deinit_hw; + hw_intf->hw_ops.reset = cam_custom_hw_sub_mod_reset; + hw_intf->hw_ops.reserve = cam_custom_hw_sub_mod_reserve; + hw_intf->hw_ops.release = cam_custom_hw_sub_mod_release; + hw_intf->hw_ops.start = cam_custom_hw_sub_mod_start; + hw_intf->hw_ops.stop = cam_custom_hw_sub_mod_stop; + hw_intf->hw_ops.read = cam_custom_hw_sub_mod_read; + hw_intf->hw_ops.write = cam_custom_hw_sub_mod_write; + hw_intf->hw_ops.process_cmd = cam_custom_hw_sub_mod_process_cmd; + hw_intf->hw_type = CAM_CUSTOM_HW_TYPE_1; + + platform_set_drvdata(pdev, hw_intf); + + hw->core_info = kzalloc(sizeof(struct cam_custom_sub_mod_core_info), + GFP_KERNEL); + if (!hw->core_info) { + CAM_DBG(CAM_CUSTOM, "Failed to alloc for core"); + rc = -ENOMEM; + goto free_hw; + } + core_info = (struct cam_custom_sub_mod_core_info *)hw->core_info; + + core_info->custom_hw_info = hw; + + rc = cam_custom_hw_sub_mod_init_soc_resources(&hw->soc_info, + cam_custom_hw_sub_mod_irq, hw); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, "Failed to init soc rc=%d", rc); + goto free_core_info; + } + + /* Initialize HW */ + + hw->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&hw->hw_mutex); + spin_lock_init(&hw->hw_lock); + init_completion(&hw->hw_complete); + + if (hw_intf->hw_idx < CAM_CUSTOM_HW_SUB_MOD_MAX) + cam_custom_hw_sub_mod_list[hw_intf->hw_idx] = hw_intf; + + /* needs to be invoked when custom hw is in place */ + //cam_custom_hw_sub_mod_init_hw(hw, NULL, 0); + + CAM_DBG(CAM_CUSTOM, "Custom hw_idx[%d] probe successful", + hw_intf->hw_idx); + return rc; + +free_core_info: + kfree(hw->core_info); +free_hw: + kfree(hw); +free_hw_intf: + kfree(hw_intf); + return rc; +} + +static const struct of_device_id cam_custom_hw_sub_mod_dt_match[] = { + { + .compatible = "qcom,cam_custom_hw_sub_mod", + .data = &cam_custom_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_custom_hw_sub_mod_dt_match); + +static struct platform_driver cam_custom_hw_sub_mod_driver = { + .probe = cam_custom_hw_sub_mod_probe, + .driver = { + .name = CAM_CUSTOM_SUB_MOD_NAME, + .of_match_table = cam_custom_hw_sub_mod_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_custom_hw_sub_module_init(void) +{ + return platform_driver_register(&cam_custom_hw_sub_mod_driver); +} + +static void __exit cam_custom_hw_sub_module_exit(void) +{ + platform_driver_unregister(&cam_custom_hw_sub_mod_driver); +} + +module_init(cam_custom_hw_sub_module_init); +module_exit(cam_custom_hw_sub_module_exit); +MODULE_DESCRIPTION("CAM CUSTOM HW SUB MODULE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..1da630ed5ec236b9866bd2893773c7f65f3da60c --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_dev.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_SUB_MOD_DEV_H_ +#define _CAM_CUSTOM_SUB_MOD_DEV_H_ + +#include "cam_custom_hw_mgr_intf.h" + +#define CAM_CUSTOM_SUB_MOD_NAME "cam_custom_sub_mod" + +#define CAM_CUSTOM_SUB_MOD_MAX_INSTANCES 2 + +#endif /* _CAM_CUSTOM_SUB_MOD_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..9011ac9d5291e1884f08277012129e3a274f1dd2 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include "cam_cpas_api.h" +#include "cam_custom_sub_mod_soc.h" +#include "cam_debug_util.h" + +int cam_custom_hw_sub_mod_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private = NULL; + struct cam_cpas_register_params cpas_register_param; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, + "Error! Get DT properties failed rc=%d", rc); + /* For Test Purposes */ + return 0; + } + + soc_private = kzalloc(sizeof(struct cam_custom_hw_soc_private), + GFP_KERNEL); + if (!soc_private) { + CAM_DBG(CAM_CUSTOM, "Error! soc_private Alloc Failed"); + return -ENOMEM; + } + soc_info->soc_private = soc_private; + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + irq_data); + if (rc < 0) { + CAM_ERR(CAM_CUSTOM, + "Error! Request platform resources failed rc=%d", rc); + return rc; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + + strlcpy(cpas_register_param.identifier, "custom", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + cpas_register_param.cam_cpas_client_cb = NULL; + cpas_register_param.userdata = soc_info; + + rc = cam_cpas_register_client(&cpas_register_param); + if (rc < 0) + goto release_soc; + + soc_private->cpas_handle = + cpas_register_param.client_handle; + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} + +int cam_custom_hw_sub_mod_deinit_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private = NULL; + + if (!soc_info) { + CAM_ERR(CAM_CUSTOM, "Error! soc_info NULL"); + return -ENODEV; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_CUSTOM, "Error! soc_private NULL"); + return -ENODEV; + } + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_CUSTOM, "CPAS0 unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc < 0) + CAM_ERR(CAM_CUSTOM, + "Error! Release platform resources failed rc=%d", rc); + + kfree(soc_private); + + return rc; +} + +int cam_custom_hw_sub_mod_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private = soc_info->soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = 7200000; + axi_vote.axi_path[0].mnoc_ab_bw = 7200000; + axi_vote.axi_path[0].mnoc_ib_bw = 7200000; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = 512000000; + axi_vote.axi_path[1].mnoc_ab_bw = 512000000; + axi_vote.axi_path[1].mnoc_ib_bw = 512000000; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Error! CPAS0 start failed rc=%d", rc); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_TURBO_VOTE, true); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Error! enable platform failed rc=%d", rc); + goto stop_cpas; + } + + return 0; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_custom_hw_sub_mod_disable_soc_resources( + struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_custom_hw_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_CUSTOM, "Error! Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Disable platform failed rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Error! CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..e9c95d43d366d23af678bf837e531e19d65893b7 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw1/cam_custom_sub_mod_soc.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_SUB_MOD_SOC_H_ +#define _CAM_CUSTOM_HW_SUB_MOD_SOC_H_ + +#include "cam_soc_util.h" +/* + * struct cam_custom_hw_soc_private: + * + * @Brief: Private SOC data specific to Custom HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + */ +struct cam_custom_hw_soc_private { + uint32_t cpas_handle; +}; + +int cam_custom_hw_sub_mod_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *irq_data); + +int cam_custom_hw_sub_mod_deinit_soc_resources( + struct cam_hw_soc_info *soc_info); + +int cam_custom_hw_sub_mod_enable_soc_resources( + struct cam_hw_soc_info *soc_info); + +int cam_custom_hw_sub_mod_disable_soc_resources( + struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_CUSTOM_HW_SUB_MOD_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..1db06bb3ab1fe6085c21a5bfa72e2af45d28b5ea --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.c @@ -0,0 +1,1329 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <soc/qcom/scm.h> +#include <uapi/media/cam_custom.h> +#include <media/cam_sync.h> +#include "cam_sync_api.h" +#include "cam_smmu_api.h" +#include "cam_req_mgr_workq.h" +#include "cam_custom_hw_mgr.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_mem_mgr_api.h" +#include "cam_common_util.h" +#include "cam_hw.h" + +static struct cam_custom_hw_mgr g_custom_hw_mgr; + +static int cam_custom_mgr_get_hw_caps(void *hw_mgr_priv, + void *hw_caps_args) +{ + int rc = 0; + struct cam_custom_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_caps_args; + struct cam_custom_query_cap_cmd custom_hw_cap; + struct cam_hw_info *cam_custom_hw; + struct cam_hw_soc_info *soc_info_hw; + + cam_custom_hw = (struct cam_hw_info *) + g_custom_hw_mgr.custom_hw[0]->hw_priv; + if (cam_custom_hw) + soc_info_hw = &cam_custom_hw->soc_info; + + CAM_DBG(CAM_CUSTOM, "enter"); + + if (query->handle_type != CAM_HANDLE_USER_POINTER) + CAM_ERR(CAM_CUSTOM, "Wrong Args"); + + if (copy_from_user(&custom_hw_cap, + u64_to_user_ptr(query->caps_handle), + sizeof(struct cam_custom_query_cap_cmd))) { + rc = -EFAULT; + return rc; + } + + custom_hw_cap.device_iommu.non_secure = hw_mgr->img_iommu_hdl; + custom_hw_cap.device_iommu.secure = -1; + + /* Initializing cdm handles to -1 */ + custom_hw_cap.cdm_iommu.non_secure = -1; + custom_hw_cap.cdm_iommu.secure = -1; + + custom_hw_cap.num_dev = 1; + custom_hw_cap.dev_caps[0].hw_type = 0; + custom_hw_cap.dev_caps[0].hw_version = 0; + + if (copy_to_user(u64_to_user_ptr(query->caps_handle), + &custom_hw_cap, sizeof(struct cam_custom_query_cap_cmd))) + rc = -EFAULT; + + CAM_DBG(CAM_CUSTOM, "exit rc :%d", rc); + return rc; +} + +enum cam_custom_hw_resource_state + cam_custom_hw_mgr_get_custom_res_state( + uint32_t in_rsrc_state) +{ + enum cam_custom_hw_resource_state rsrc_state; + + CAM_DBG(CAM_CUSTOM, "rsrc_state %x", in_rsrc_state); + + switch (in_rsrc_state) { + case CAM_ISP_RESOURCE_STATE_UNAVAILABLE: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE; + break; + case CAM_ISP_RESOURCE_STATE_AVAILABLE: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_AVAILABLE; + break; + case CAM_ISP_RESOURCE_STATE_RESERVED: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_RESERVED; + break; + case CAM_ISP_RESOURCE_STATE_INIT_HW: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_INIT_HW; + break; + case CAM_ISP_RESOURCE_STATE_STREAMING: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_STREAMING; + break; + default: + rsrc_state = CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE; + CAM_DBG(CAM_CUSTOM, "invalid rsrc type"); + break; + } + + return rsrc_state; +} + +enum cam_isp_resource_state + cam_custom_hw_mgr_get_isp_res_state( + uint32_t in_rsrc_state) +{ + enum cam_isp_resource_state rsrc_state; + + CAM_DBG(CAM_CUSTOM, "rsrc_state %x", in_rsrc_state); + + switch (in_rsrc_state) { + case CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE: + rsrc_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_AVAILABLE: + rsrc_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_RESERVED: + rsrc_state = CAM_ISP_RESOURCE_STATE_RESERVED; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_INIT_HW: + rsrc_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + break; + case CAM_CUSTOM_HW_RESOURCE_STATE_STREAMING: + rsrc_state = CAM_ISP_RESOURCE_STATE_STREAMING; + break; + default: + rsrc_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + CAM_DBG(CAM_CUSTOM, "invalid rsrc type"); + break; + } + + return rsrc_state; +} + +enum cam_isp_resource_type + cam_custom_hw_mgr_get_isp_res_type( + enum cam_custom_hw_mgr_res_type res_type) +{ + switch (res_type) { + case CAM_CUSTOM_CID_HW: + return CAM_ISP_RESOURCE_CID; + case CAM_CUSTOM_CSID_HW: + return CAM_ISP_RESOURCE_PIX_PATH; + default: + return CAM_ISP_RESOURCE_MAX; + } +} + +static int cam_custom_hw_mgr_deinit_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.deinit) { + CAM_DBG(CAM_CUSTOM, "DEINIT HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.deinit(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "DEINIT HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_hw_mgr_stop_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_csid_hw_stop_args stop_cmd; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.stop) { + CAM_DBG(CAM_CUSTOM, "STOP HW for res_id:%u", + hw_mgr_res->res_id); + stop_cmd.num_res = 1; + stop_cmd.node_res = &isp_rsrc_node; + stop_cmd.stop_cmd = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + rc = hw_intf->hw_ops.stop(hw_intf->hw_priv, + &stop_cmd, sizeof(struct cam_csid_hw_stop_args)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "STOP HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_custom_hw_mgr_res *hw_mgr_res; + struct cam_custom_hw_mgr_ctx *ctx; + + if (!hw_mgr_priv || !stop_hw_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_custom_hw_mgr_ctx *) + stop_args->ctxt_to_hw_map; + + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, " Enter...ctx id:%d", ctx->ctx_index); + + /* Stop custom cid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_stop_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + + /* Stop custom csid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_stop_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + } + + + /* stop custom hw here */ + + /* Deinit custom cid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_deinit_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + + /* Deinit custom csid here */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_deinit_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "failed to stop hw %d", + hw_mgr_res->res_id); + } + } + + /* deinit custom rsrc */ + + return rc; +} + +static int cam_custom_hw_mgr_init_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.init) { + CAM_DBG(CAM_CUSTOM, "INIT HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.init(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "INIT HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_hw_mgr_start_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = -1; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.start) { + CAM_DBG(CAM_CUSTOM, "Start HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.start(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + + return 0; + +err: + CAM_DBG(CAM_CUSTOM, "START HW failed for res_id:%u", + hw_mgr_res->res_id); + return rc; +} + +static int cam_custom_mgr_start_hw(void *hw_mgr_priv, + void *start_hw_args) +{ + int rc = 0; + struct cam_hw_config_args *hw_config; + struct cam_hw_stop_args stop_args; + struct cam_custom_hw_mgr_res *hw_mgr_res; + struct cam_custom_hw_mgr_ctx *ctx; + + if (!hw_mgr_priv || !start_hw_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + hw_config = (struct cam_hw_config_args *)start_hw_args; + + ctx = (struct cam_custom_hw_mgr_ctx *) + hw_config->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, "Enter... ctx id:%d", + ctx->ctx_index); + + /* Init custom cid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT CID(id :%d)", + hw_mgr_res->res_id); + goto deinit_hw; + } + } + + /* Init custom csid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT CSID(id :%d)", + hw_mgr_res->res_id); + goto deinit_hw; + } + } + + + /* Init custom hw here */ + + /* Apply init config */ + + /* Start custom HW first */ + if (rc < 0) + goto err; + + /* Start custom csid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not START CSID(id :%d)", + hw_mgr_res->res_id); + goto err; + } + } + + /* Start custom cid */ + list_for_each_entry(hw_mgr_res, + &ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_start_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not START CID(id :%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_CUSTOM, "Start success for ctx id:%d", ctx->ctx_index); + return 0; + +err: + stop_args.ctxt_to_hw_map = hw_config->ctxt_to_hw_map; + cam_custom_mgr_stop_hw(hw_mgr_priv, &stop_args); +deinit_hw: + /* deinit the hw previously initialized */ + CAM_DBG(CAM_CUSTOM, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_custom_mgr_read(void *hw_mgr_priv, void *read_args) +{ + return -EPERM; +} + +static int cam_custom_mgr_write(void *hw_mgr_priv, void *write_args) +{ + return -EPERM; +} + +static int cam_custom_hw_mgr_put_ctx( + struct list_head *src_list, + struct cam_custom_hw_mgr_ctx **custom_ctx) +{ + struct cam_custom_hw_mgr_ctx *ctx_ptr = NULL; + + ctx_ptr = *custom_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *custom_ctx = NULL; + return 0; +} + +static int cam_custom_hw_mgr_get_ctx( + struct list_head *src_list, + struct cam_custom_hw_mgr_ctx **custom_ctx) +{ + struct cam_custom_hw_mgr_ctx *ctx_ptr = NULL; + + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_custom_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_CUSTOM, "No more free custom hw mgr ctx"); + return -EINVAL; + } + *custom_ctx = ctx_ptr; + memset(ctx_ptr->sub_hw_list, 0, + sizeof(struct cam_custom_hw_mgr_res) * + CAM_CUSTOM_HW_RES_MAX); + + return 0; +} + +static int cam_custom_hw_mgr_put_res( + struct list_head *src_list, + struct cam_custom_hw_mgr_res **res) +{ + struct cam_custom_hw_mgr_res *res_ptr = NULL; + + res_ptr = *res; + if (res_ptr) + list_add_tail(&res_ptr->list, src_list); + + return 0; +} + +static int cam_custom_hw_mgr_get_res( + struct list_head *src_list, + struct cam_custom_hw_mgr_res **res) +{ + int rc = 0; + struct cam_custom_hw_mgr_res *res_ptr = NULL; + + if (!list_empty(src_list)) { + res_ptr = list_first_entry(src_list, + struct cam_custom_hw_mgr_res, list); + list_del_init(&res_ptr->list); + } else { + CAM_ERR(CAM_CUSTOM, "No more free custom ctx rsrc"); + rc = -1; + } + *res = res_ptr; + + return rc; +} + +static enum cam_ife_pix_path_res_id + cam_custom_hw_mgr_get_csid_res_type( + uint32_t out_port_type) +{ + enum cam_ife_pix_path_res_id path_id; + + CAM_DBG(CAM_CUSTOM, "out_port_type %x", out_port_type); + + switch (out_port_type) { + case CAM_CUSTOM_OUT_RES_UDI_0: + path_id = CAM_IFE_PIX_PATH_RES_UDI_0; + break; + case CAM_CUSTOM_OUT_RES_UDI_1: + path_id = CAM_IFE_PIX_PATH_RES_UDI_1; + break; + case CAM_CUSTOM_OUT_RES_UDI_2: + path_id = CAM_IFE_PIX_PATH_RES_UDI_2; + break; + default: + path_id = CAM_IFE_PIX_PATH_RES_MAX; + CAM_DBG(CAM_CUSTOM, "maximum rdi output type exceeded"); + break; + } + + CAM_DBG(CAM_CUSTOM, "out_port %x path_id %d", out_port_type, path_id); + + return path_id; +} + +static int cam_custom_hw_mgr_acquire_cid_res( + struct cam_custom_hw_mgr_ctx *custom_ctx, + struct cam_isp_in_port_generic_info *in_port, + struct cam_custom_hw_mgr_res **cid_res, + enum cam_ife_pix_path_res_id path_res_id, + struct cam_isp_resource_node **cid_rsrc_node) +{ + int rc = -1; + int i; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_hw_intf *hw_intf; + struct cam_custom_hw_mgr_res *cid_res_temp; + struct cam_csid_hw_reserve_resource_args csid_acquire; + struct cam_isp_resource_node *isp_rsrc_node; + struct cam_isp_out_port_generic_info *out_port = NULL; + + custom_hw_mgr = custom_ctx->hw_mgr; + *cid_res = NULL; + + rc = cam_custom_hw_mgr_get_res( + &custom_ctx->free_res_list, cid_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "No more free hw mgr resource"); + goto end; + } + + memset(&csid_acquire, 0, sizeof(csid_acquire)); + cid_res_temp = *cid_res; + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + csid_acquire.res_id = path_res_id; + csid_acquire.node_res = NULL; + CAM_DBG(CAM_CUSTOM, "path_res_id %d", path_res_id); + + if (in_port->num_out_res) + out_port = &(in_port->data[0]); + + for (i = 0; i < CAM_CUSTOM_CSID_HW_MAX; i++) { + if (!custom_hw_mgr->csid_devices[i]) + continue; + + hw_intf = custom_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + /* since there is a need of 1 cid at this stage */ + if (rc) + continue; + else + break; + + } + + if (!csid_acquire.node_res) { + CAM_ERR(CAM_CUSTOM, + "Can not acquire custom cid resource for path %d", + path_res_id); + rc = -EAGAIN; + goto put_res; + } + + *cid_rsrc_node = csid_acquire.node_res; + isp_rsrc_node = csid_acquire.node_res; + cid_res_temp->rsrc_node = isp_rsrc_node; + cid_res_temp->res_type = CAM_CUSTOM_CID_HW; + cid_res_temp->res_id = isp_rsrc_node->res_id; + cam_custom_hw_mgr_put_res(&custom_ctx->res_list_custom_cid, + &cid_res_temp); + + CAM_DBG(CAM_CUSTOM, "CID acquired successfully %u", + isp_rsrc_node->res_id); + + return 0; + +put_res: + cam_custom_hw_mgr_put_res(&custom_ctx->free_res_list, cid_res); +end: + return rc; + +} + +static int cam_custom_hw_mgr_acquire_csid_res( + struct cam_custom_hw_mgr_ctx *custom_ctx, + struct cam_isp_in_port_generic_info *in_port_info) +{ + int rc = 0, i = 0; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_isp_out_port_generic_info *out_port; + struct cam_custom_hw_mgr_res *custom_csid_res; + struct cam_custom_hw_mgr_res *custom_cid_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_hw_reserve_resource_args custom_csid_acquire; + enum cam_ife_pix_path_res_id path_res_id; + struct cam_isp_resource_node *isp_rsrc_node; + struct cam_isp_resource_node *cid_rsrc_node = NULL; + + custom_hw_mgr = custom_ctx->hw_mgr; + + for (i = 0; i < in_port_info->num_out_res; i++) { + out_port = &in_port_info->data[i]; + path_res_id = cam_custom_hw_mgr_get_csid_res_type( + out_port->res_type); + + if (path_res_id == CAM_IFE_PIX_PATH_RES_MAX) { + CAM_WARN(CAM_CUSTOM, "Invalid out port res_type %u", + out_port->res_type); + continue; + } + + rc = cam_custom_hw_mgr_acquire_cid_res(custom_ctx, in_port_info, + &custom_cid_res, path_res_id, &cid_rsrc_node); + if (rc) { + CAM_ERR(CAM_CUSTOM, "No free cid rsrc %d", rc); + goto end; + } + + rc = cam_custom_hw_mgr_get_res(&custom_ctx->free_res_list, + &custom_csid_res); + if (rc) { + CAM_ERR(CAM_CUSTOM, "No more free hw mgr rsrc"); + goto end; + } + + memset(&custom_csid_acquire, 0, sizeof(custom_csid_acquire)); + custom_csid_acquire.res_id = path_res_id; + custom_csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + custom_csid_acquire.cid = cid_rsrc_node->res_id; + custom_csid_acquire.in_port = in_port_info; + custom_csid_acquire.out_port = out_port; + custom_csid_acquire.sync_mode = 0; + custom_csid_acquire.node_res = NULL; + + hw_intf = cid_rsrc_node->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &custom_csid_acquire, sizeof(custom_csid_acquire)); + if (rc) { + CAM_ERR(CAM_CUSTOM, + "Custom csid acquire failed for hw_idx %u rc %d", + hw_intf->hw_idx, rc); + goto put_res; + } + + if (custom_csid_acquire.node_res == NULL) { + CAM_ERR(CAM_CUSTOM, "Acquire custom csid failed"); + rc = -EAGAIN; + goto put_res; + } + + isp_rsrc_node = custom_csid_acquire.node_res; + custom_csid_res->rsrc_node = isp_rsrc_node; + custom_csid_res->res_type = CAM_CUSTOM_CSID_HW; + custom_csid_res->res_id = custom_csid_acquire.res_id; + cam_custom_hw_mgr_put_res( + &custom_ctx->res_list_custom_csid, + &custom_csid_res); + CAM_DBG(CAM_CUSTOM, "Custom CSID acquired for path %d", + path_res_id); + } + + return 0; + +put_res: + cam_custom_hw_mgr_put_res(&custom_ctx->free_res_list, + &custom_csid_res); +end: + return rc; +} + +static int cam_custom_hw_mgr_free_hw_res( + struct cam_custom_hw_mgr_res *hw_mgr_res) +{ + int rc = 0; + struct cam_isp_resource_node *isp_rsrc_node = NULL; + struct cam_hw_intf *hw_intf = NULL; + + isp_rsrc_node = + (struct cam_isp_resource_node *)hw_mgr_res->rsrc_node; + if (!isp_rsrc_node) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_intf = isp_rsrc_node->hw_intf; + if (hw_intf->hw_ops.release) { + CAM_DBG(CAM_CUSTOM, "RELEASE HW for res_id:%u", + hw_mgr_res->res_id); + rc = hw_intf->hw_ops.release(hw_intf->hw_priv, + isp_rsrc_node, sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_CUSTOM, + "Release HW failed for hw_idx %d", + hw_intf->hw_idx); + } + + /* caller should make sure the resource is in a list */ + list_del_init(&hw_mgr_res->list); + memset(hw_mgr_res, 0, sizeof(*hw_mgr_res)); + INIT_LIST_HEAD(&hw_mgr_res->list); + + return 0; +} + +static int cam_custom_hw_mgr_release_hw_for_ctx( + struct cam_custom_hw_mgr_ctx *custom_ctx) +{ + int rc = -1; + struct cam_custom_hw_mgr_res *hw_mgr_res; + struct cam_custom_hw_mgr_res *hw_mgr_res_temp; + + /* Release custom cid */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &custom_ctx->res_list_custom_cid, list) { + rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_ISP, "Can not release CID(id :%d)", + hw_mgr_res->res_id); + cam_custom_hw_mgr_put_res( + &custom_ctx->free_res_list, &hw_mgr_res); + } + + /* Release custom csid */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &custom_ctx->res_list_custom_csid, list) { + rc = cam_custom_hw_mgr_free_hw_res(hw_mgr_res); + if (rc) + CAM_ERR(CAM_ISP, "Can not release CSID(id :%d)", + hw_mgr_res->res_id); + cam_custom_hw_mgr_put_res( + &custom_ctx->free_res_list, &hw_mgr_res); + } + + /* Release custom HW Here */ + + return 0; +} +static int cam_custom_mgr_release_hw(void *hw_mgr_priv, + void *release_hw_args) +{ + int rc = 0; + struct cam_hw_release_args *release_args = release_hw_args; + struct cam_custom_hw_mgr_ctx *custom_ctx; + + if (!hw_mgr_priv || !release_hw_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + custom_ctx = + (struct cam_custom_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!custom_ctx || !custom_ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_CUSTOM, "Enter...ctx id:%d", + custom_ctx->ctx_index); + + cam_custom_hw_mgr_release_hw_for_ctx(custom_ctx); + list_del_init(&custom_ctx->list); + custom_ctx->ctx_in_use = 0; + cam_custom_hw_mgr_put_ctx(&g_custom_hw_mgr.free_ctx_list, &custom_ctx); + CAM_DBG(CAM_CUSTOM, "Release Exit.."); + return rc; +} + +static void cam_custom_hw_mgr_acquire_get_unified_dev_str( + struct cam_custom_in_port_info *in, + struct cam_isp_in_port_generic_info *gen_port_info) +{ + int i; + + gen_port_info->res_type = in->res_type + + CAM_ISP_IFE_IN_RES_BASE - CAM_CUSTOM_IN_RES_BASE; + gen_port_info->lane_type = in->lane_type; + gen_port_info->lane_num = in->lane_num; + gen_port_info->lane_cfg = in->lane_cfg; + gen_port_info->vc[0] = in->vc[0]; + gen_port_info->dt[0] = in->dt[0]; + gen_port_info->num_valid_vc_dt = in->num_valid_vc_dt; + gen_port_info->format = in->format; + gen_port_info->test_pattern = in->test_pattern; + gen_port_info->usage_type = in->usage_type; + gen_port_info->left_start = in->left_start; + gen_port_info->left_stop = in->left_stop; + gen_port_info->left_width = in->left_width; + gen_port_info->right_start = in->right_start; + gen_port_info->right_stop = in->right_stop; + gen_port_info->right_width = in->right_width; + gen_port_info->line_start = in->line_start; + gen_port_info->line_stop = in->line_stop; + gen_port_info->height = in->height; + gen_port_info->pixel_clk = in->pixel_clk; + gen_port_info->cust_node = 1; + gen_port_info->num_out_res = in->num_out_res; + gen_port_info->num_bytes_out = in->num_bytes_out; + + for (i = 0; i < in->num_out_res; i++) { + gen_port_info->data[i].res_type = in->data[i].res_type; + gen_port_info->data[i].format = in->data[i].format; + } +} + +static int cam_custom_mgr_acquire_hw_for_ctx( + struct cam_custom_hw_mgr_ctx *custom_ctx, + struct cam_isp_in_port_generic_info *in_port_info, + uint32_t *acquired_hw_id, uint32_t *acquired_hw_path) +{ + int rc = 0, i = 0; + struct cam_hw_intf *hw_intf; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_custom_sub_mod_acq acq; + + custom_hw_mgr = custom_ctx->hw_mgr; + + /* Acquire custom csid */ + rc = cam_custom_hw_mgr_acquire_csid_res(custom_ctx, in_port_info); + if (rc) { + CAM_ERR(CAM_CUSTOM, "Custom csid acquire failed rc %d"); + goto err; + } + + /* Acquire custom hw */ + for (i = 0; i < CAM_CUSTOM_HW_SUB_MOD_MAX; i++) { + hw_intf = custom_hw_mgr->custom_hw[i]; + if (!hw_intf) + continue; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &acq, sizeof(acq)); + if (rc) { + CAM_DBG(CAM_CUSTOM, + "No custom resource from hw %d", + hw_intf->hw_idx); + continue; + } + /* need to be set in reserve based on HW being acquired */ + //custom_ctx->sub_hw_list[i].hw_res = acq.rsrc_node; + //custom_ctx->sub_hw_list[i].res_type = <res_type> + //custom_ctx->sub_hw_list[i].res_id = <res_id>; + break; + } + +err: + return rc; +} + +static int cam_custom_mgr_acquire_hw( + void *hw_mgr_priv, + void *acquire_hw_args) +{ + int rc = -1; + int32_t i; + uint32_t in_port_length; + struct cam_custom_hw_mgr_ctx *custom_ctx; + struct cam_custom_hw_mgr *custom_hw_mgr; + struct cam_hw_acquire_args *acquire_args = + (struct cam_hw_acquire_args *) acquire_hw_args; + struct cam_custom_in_port_info *in_port_info; + struct cam_custom_resource *custom_rsrc; + struct cam_isp_in_port_generic_info *gen_port_info = NULL; + + if (!hw_mgr_priv || !acquire_args || (acquire_args->num_acq <= 0)) { + CAM_ERR(CAM_CUSTOM, "Invalid params"); + return -EINVAL; + } + + custom_hw_mgr = (struct cam_custom_hw_mgr *) hw_mgr_priv; + mutex_lock(&g_custom_hw_mgr.ctx_mutex); + rc = cam_custom_hw_mgr_get_ctx( + &custom_hw_mgr->free_ctx_list, &custom_ctx); + if (rc || !custom_ctx) { + CAM_ERR(CAM_CUSTOM, "Get custom hw context failed"); + mutex_unlock(&g_custom_hw_mgr.ctx_mutex); + goto err; + } + mutex_unlock(&g_custom_hw_mgr.ctx_mutex); + + /* Handle Acquire Here */ + custom_ctx->hw_mgr = custom_hw_mgr; + custom_ctx->cb_priv = acquire_args->context_data; + custom_ctx->event_cb = acquire_args->event_cb; + + custom_rsrc = kcalloc(acquire_args->num_acq, + sizeof(*custom_rsrc), GFP_KERNEL); + if (!custom_rsrc) { + rc = -ENOMEM; + goto free_ctx; + } + + CAM_DBG(CAM_CUSTOM, "start copy %d resources from user", + acquire_args->num_acq); + + if (copy_from_user(custom_rsrc, + (void __user *)acquire_args->acquire_info, + ((sizeof(*custom_rsrc)) * acquire_args->num_acq))) { + rc = -EFAULT; + goto free_ctx; + } + + for (i = 0; i < acquire_args->num_acq; i++) { + if (custom_rsrc[i].resource_id != CAM_CUSTOM_RES_ID_PORT) + continue; + + CAM_DBG(CAM_CUSTOM, "acquire no = %d total = %d", i, + acquire_args->num_acq); + + CAM_DBG(CAM_CUSTOM, + "start copy from user handle %lld with len = %d", + custom_rsrc[i].res_hdl, + custom_rsrc[i].length); + + in_port_length = sizeof(struct cam_custom_in_port_info); + if (in_port_length > custom_rsrc[i].length) { + CAM_ERR(CAM_CUSTOM, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + + in_port_info = memdup_user( + u64_to_user_ptr(custom_rsrc[i].res_hdl), + custom_rsrc[i].length); + + if (!IS_ERR(in_port_info)) { + if (in_port_info->num_out_res > + CAM_CUSTOM_HW_OUT_RES_MAX) { + CAM_ERR(CAM_CUSTOM, "too many output res %d", + in_port_info->num_out_res); + rc = -EINVAL; + kfree(in_port_info); + goto free_res; + } + + in_port_length = + sizeof(struct cam_custom_in_port_info) + + (in_port_info->num_out_res - 1) * + sizeof(struct cam_custom_out_port_info); + + if (in_port_length > custom_rsrc[i].length) { + CAM_ERR(CAM_CUSTOM, + "buffer size is not enough"); + rc = -EINVAL; + kfree(in_port_info); + goto free_res; + } + + gen_port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), + GFP_KERNEL); + if (gen_port_info == NULL) { + rc = -ENOMEM; + goto free_res; + } + + gen_port_info->data = kcalloc( + sizeof(struct cam_isp_out_port_generic_info), + in_port_info->num_out_res, GFP_KERNEL); + if (gen_port_info->data == NULL) { + kfree(gen_port_info); + gen_port_info = NULL; + rc = -ENOMEM; + goto free_res; + } + + cam_custom_hw_mgr_acquire_get_unified_dev_str( + in_port_info, gen_port_info); + + rc = cam_custom_mgr_acquire_hw_for_ctx(custom_ctx, + gen_port_info, &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + + kfree(in_port_info); + if (gen_port_info != NULL) { + kfree(gen_port_info->data); + kfree(gen_port_info); + gen_port_info = NULL; + } + + if (rc) { + CAM_ERR(CAM_CUSTOM, "can not acquire resource"); + goto free_res; + } + } else { + CAM_ERR(CAM_CUSTOM, + "Copy from user failed with in_port = %pK", + in_port_info); + rc = -EFAULT; + goto free_res; + } + } + + custom_ctx->ctx_in_use = 1; + acquire_args->ctxt_to_hw_map = custom_ctx; + CAM_DBG(CAM_CUSTOM, "Exit...(success)"); + return 0; + +free_res: + cam_custom_hw_mgr_release_hw_for_ctx(custom_ctx); +free_ctx: + cam_custom_hw_mgr_put_ctx(&custom_hw_mgr->free_ctx_list, &custom_ctx); +err: + CAM_DBG(CAM_CUSTOM, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_custom_add_io_buffers( + int iommu_hdl, + struct cam_hw_prepare_update_args *prepare) +{ + int rc = 0, i = 0; + int32_t hdl; + uint32_t plane_id; + struct cam_buf_io_cfg *io_cfg; + + io_cfg = (struct cam_buf_io_cfg *)((uint8_t *) + &prepare->packet->payload + + prepare->packet->io_configs_offset); + + /* Validate hw update entries */ + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_CUSTOM, "======= io config idx %d ============", i); + CAM_DBG(CAM_CUSTOM, + "i %d req_id %llu resource_type:%d fence:%d direction %d", + i, prepare->packet->header.request_id, + io_cfg[i].resource_type, io_cfg[i].fence, + io_cfg[i].direction); + + CAM_DBG(CAM_CUSTOM, "format: %d", io_cfg[i].format); + + if (io_cfg[i].direction == CAM_BUF_OUTPUT) { + CAM_DBG(CAM_CUSTOM, + "output fence 0x%x", io_cfg[i].fence); + } else if (io_cfg[i].direction == CAM_BUF_INPUT) { + CAM_DBG(CAM_CUSTOM, + "input fence 0x%x", io_cfg[i].fence); + } else { + CAM_ERR(CAM_CUSTOM, "Invalid io config direction :%d", + io_cfg[i].direction); + return -EINVAL; + } + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + continue; + + hdl = io_cfg[i].mem_handle[plane_id]; + CAM_DBG(CAM_CUSTOM, "handle 0x%x for plane %d", + hdl, plane_id); + /* Use cam_mem_get_io_buf() to retrieve iova */ + } + + /* Do other I/O config operations */ + } + + return rc; +} + +static int cam_custom_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + struct cam_hw_prepare_update_args *prepare; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_custom_prepare_hw_update_data *prepare_hw_data; + struct cam_custom_hw_mgr *hw_mgr; + struct cam_custom_hw_mgr_ctx *ctx = NULL; + uint32_t *ptr; + size_t len; + struct cam_custom_cmd_buf_type_1 *custom_buf_type1; + + if (!hw_mgr_priv || !prepare_hw_update_args) { + CAM_ERR(CAM_CUSTOM, "Invalid args"); + return -EINVAL; + } + + hw_mgr = (struct cam_custom_hw_mgr *) hw_mgr_priv; + prepare = + (struct cam_hw_prepare_update_args *) prepare_hw_update_args; + + CAM_DBG(CAM_CUSTOM, "Enter for req_id %lld", + prepare->packet->header.request_id); + + /* Prepare packet */ + prepare_hw_data = + (struct cam_custom_prepare_hw_update_data *)prepare->priv; + prepare_hw_data->packet_opcode_type = + (prepare->packet->header.op_code & 0xFFF); + ctx = (struct cam_custom_hw_mgr_ctx *) prepare->ctxt_to_hw_map; + + /* Test purposes-check the data in cmd buffer */ + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint8_t *)&prepare->packet->payload + + prepare->packet->cmd_buf_offset); + rc = cam_packet_util_get_cmd_mem_addr( + cmd_desc->mem_handle, &ptr, &len); + if (!rc) { + ptr += (cmd_desc->offset / 4); + custom_buf_type1 = + (struct cam_custom_cmd_buf_type_1 *)ptr; + CAM_DBG(CAM_CUSTOM, "frame num %u", + custom_buf_type1->custom_info); + } + + cam_custom_add_io_buffers(hw_mgr->img_iommu_hdl, prepare); + return 0; +} + +static int cam_custom_mgr_config_hw(void *hw_mgr_priv, + void *hw_config_args) +{ + int rc = 0; + int i = 0; + struct cam_custom_hw_mgr_ctx *custom_ctx; + struct cam_custom_hw_mgr_res *res; + struct cam_hw_config_args *cfg; + struct cam_hw_intf *hw_intf = NULL; + + CAM_DBG(CAM_CUSTOM, "Enter"); + if (!hw_mgr_priv || !hw_config_args) { + CAM_ERR(CAM_CUSTOM, "Invalid arguments"); + return -EINVAL; + } + + cfg = + (struct cam_hw_config_args *)hw_config_args; + custom_ctx = cfg->ctxt_to_hw_map; + + if (!custom_ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "Invalid context parameters"); + return -EPERM; + } + + for (i = 0; i < CAM_CUSTOM_HW_SUB_MOD_MAX; i++) { + res = &custom_ctx->sub_hw_list[i]; + if (res->hw_res) { + hw_intf = res->hw_res->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + struct cam_custom_sub_mod_req_to_dev req_to_dev; + + req_to_dev.ctx_idx = custom_ctx->ctx_index; + req_to_dev.dev_idx = i; + req_to_dev.req_id = cfg->request_id; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_CUSTOM_SUBMIT_REQ, + &req_to_dev, sizeof(req_to_dev)); + } + } + } + + return rc; +} + +static int cam_custom_hw_mgr_irq_cb(void *data, + struct cam_custom_hw_cb_args *cb_args) +{ + struct cam_custom_sub_mod_req_to_dev *proc_req; + struct cam_hw_done_event_data evt_data; + struct cam_custom_hw_mgr_ctx *custom_ctx; + uint32_t ctx_idx; + + proc_req = cb_args->req_info; + ctx_idx = proc_req->ctx_idx; + custom_ctx = &g_custom_hw_mgr.ctx_pool[ctx_idx]; + + if (!custom_ctx->ctx_in_use) { + CAM_ERR(CAM_CUSTOM, "ctx %u not in use", ctx_idx); + return 0; + } + + /* Based on irq status notify success/failure */ + + evt_data.request_id = proc_req->req_id; + custom_ctx->event_cb(custom_ctx->cb_priv, + CAM_CUSTOM_EVENT_BUF_DONE, &evt_data); + + return 0; +} + +int cam_custom_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + int rc = 0; + int i, j; + struct cam_custom_hw_mgr_ctx *ctx_pool; + struct cam_custom_sub_mod_set_irq_cb irq_cb_args; + struct cam_hw_intf *hw_intf = NULL; + + memset(&g_custom_hw_mgr, 0, sizeof(g_custom_hw_mgr)); + mutex_init(&g_custom_hw_mgr.ctx_mutex); + + /* fill custom hw intf information */ + for (i = 0; i < CAM_CUSTOM_HW_SUB_MOD_MAX; i++) { + /* Initialize sub modules */ + rc = cam_custom_hw_sub_mod_init( + &g_custom_hw_mgr.custom_hw[i], i); + + /* handle in case init fails */ + if (g_custom_hw_mgr.custom_hw[i]) { + hw_intf = g_custom_hw_mgr.custom_hw[i]; + if (hw_intf->hw_ops.process_cmd) { + irq_cb_args.custom_hw_mgr_cb = + cam_custom_hw_mgr_irq_cb; + irq_cb_args.data = + g_custom_hw_mgr.custom_hw[i]->hw_priv; + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_CUSTOM_SET_IRQ_CB, &irq_cb_args, + sizeof(irq_cb_args)); + } + } + } + + for (i = 0; i < CAM_CUSTOM_CSID_HW_MAX; i++) { + /* Initialize csid custom modules */ + rc = cam_custom_csid_hw_init( + &g_custom_hw_mgr.csid_devices[i], i); + } + + INIT_LIST_HEAD(&g_custom_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_custom_hw_mgr.used_ctx_list); + + /* + * for now, we only support one iommu handle. later + * we will need to setup more iommu handle for other + * use cases. + * Also, we have to release them once we have the + * deinit support + */ + if (cam_smmu_get_handle("custom", + &g_custom_hw_mgr.img_iommu_hdl)) { + CAM_ERR(CAM_CUSTOM, "Can not get iommu handle"); + return -EINVAL; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + memset(&g_custom_hw_mgr.ctx_pool[i], 0, + sizeof(g_custom_hw_mgr.ctx_pool[i])); + INIT_LIST_HEAD(&g_custom_hw_mgr.ctx_pool[i].list); + + ctx_pool = &g_custom_hw_mgr.ctx_pool[i]; + + /* init context pool */ + INIT_LIST_HEAD(&g_custom_hw_mgr.ctx_pool[i].free_res_list); + INIT_LIST_HEAD( + &g_custom_hw_mgr.ctx_pool[i].res_list_custom_csid); + INIT_LIST_HEAD( + &g_custom_hw_mgr.ctx_pool[i].res_list_custom_cid); + for (j = 0; j < CAM_CUSTOM_HW_RES_MAX; j++) { + INIT_LIST_HEAD( + &g_custom_hw_mgr.ctx_pool[i].res_pool[j].list); + list_add_tail( + &g_custom_hw_mgr.ctx_pool[i].res_pool[j].list, + &g_custom_hw_mgr.ctx_pool[i].free_res_list); + } + + g_custom_hw_mgr.ctx_pool[i].ctx_index = i; + g_custom_hw_mgr.ctx_pool[i].hw_mgr = &g_custom_hw_mgr; + + list_add_tail(&g_custom_hw_mgr.ctx_pool[i].list, + &g_custom_hw_mgr.free_ctx_list); + } + + /* fill return structure */ + hw_mgr_intf->hw_mgr_priv = &g_custom_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_custom_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_custom_mgr_acquire_hw; + hw_mgr_intf->hw_start = cam_custom_mgr_start_hw; + hw_mgr_intf->hw_stop = cam_custom_mgr_stop_hw; + hw_mgr_intf->hw_read = cam_custom_mgr_read; + hw_mgr_intf->hw_write = cam_custom_mgr_write; + hw_mgr_intf->hw_release = cam_custom_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_custom_mgr_prepare_hw_update; + hw_mgr_intf->hw_config = cam_custom_mgr_config_hw; + + if (iommu_hdl) + *iommu_hdl = g_custom_hw_mgr.img_iommu_hdl; + + CAM_DBG(CAM_CUSTOM, "HW manager initialized"); + return 0; +} diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..64f4555528bf6eb1e88d91a0a7fce1a6d1e11e21 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/cam_custom_hw_mgr.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_MGR_H_ +#define _CAM_CUSTOM_HW_MGR_H_ + +#include <linux/completion.h> +#include "cam_custom_hw_mgr_intf.h" +#include "cam_custom_sub_mod_core.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_isp_hw.h" +#include "cam_custom_hw.h" +#include <uapi/media/cam_defs.h> +#include <uapi/media/cam_custom.h> + +enum cam_custom_hw_mgr_res_type { + CAM_CUSTOM_HW_SUB_MODULE, + CAM_CUSTOM_CID_HW, + CAM_CUSTOM_CSID_HW, + CAM_CUSTOM_HW_MAX, +}; + +/* Needs to be suitably defined */ +#define CAM_CUSTOM_HW_OUT_RES_MAX 1 + +/** + * struct cam_custom_hw_mgr_res - HW resources for the Custom manager + * + * @list: used by the resource list + * @res_type: Custom manager resource type + * @res_id: resource id based on the resource type for root or + * leaf resource, it matches the KMD interface port id. + * For branch resource, it is defined by the Custom HW + * layer + * @rsrc_node: isp hw layer resource for csid/cid + * @hw_res: hw layer resource array. + */ +struct cam_custom_hw_mgr_res { + struct list_head list; + enum cam_custom_hw_mgr_res_type res_type; + uint32_t res_id; + void *rsrc_node; + struct cam_custom_resource_node *hw_res; +}; + + +/** + * struct ctx_base_info - Base hardware information for the context + * + * @idx: Base resource index + * + */ +struct ctx_base_info { + uint32_t idx; +}; + + +/** + * struct cam_custom_hw_mgr_ctx - Custom HW manager ctx object + * + * @list: used by the ctx list. + * @ctx_index: acquired context id. + * @hw_mgr: Custom hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_custom_csid: custom csid modules for this context + * @res_list_custom_cid: custom cid modules for this context + * @sub_hw_list: HW submodules for this context + * @free_res_list: Free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @base: device base index array contain the all + * Custom HW instance associated with this ctx. + * @num_base: number of valid base data in the base array + * @init_done: indicate whether init hw is done + * @event_cb: event_cb to ctx + * @cb_priv: data sent back with event_cb + * + */ +struct cam_custom_hw_mgr_ctx { + struct list_head list; + + uint32_t ctx_index; + struct cam_custom_hw_mgr *hw_mgr; + uint32_t ctx_in_use; + + struct list_head res_list_custom_csid; + struct list_head res_list_custom_cid; + struct cam_custom_hw_mgr_res sub_hw_list[ + CAM_CUSTOM_HW_RES_MAX]; + + struct list_head free_res_list; + struct cam_custom_hw_mgr_res res_pool[CAM_CUSTOM_HW_RES_MAX]; + struct ctx_base_info base[CAM_CUSTOM_HW_SUB_MOD_MAX]; + uint32_t num_base; + bool init_done; + cam_hw_event_cb_func event_cb; + void *cb_priv; +}; + +/** + * struct cam_custom_hw_mgr - Custom HW Manager + * + * @img_iommu_hdl: iommu handle + * @custom_hw: Custom device instances array. This will be filled by + * HW layer during initialization + * @csid_devices: Custom csid device instance array + * @ctx_mutex: mutex for the hw context pool + * @free_ctx_list: free hw context list + * @used_ctx_list: used hw context list + * @ctx_pool: context storage + * + */ +struct cam_custom_hw_mgr { + int img_iommu_hdl; + struct cam_hw_intf *custom_hw[CAM_CUSTOM_HW_SUB_MOD_MAX]; + struct cam_hw_intf *csid_devices[CAM_CUSTOM_CSID_HW_MAX]; + struct mutex ctx_mutex; + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct cam_custom_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; +}; + +/** + * cam_custom_hw_mgr_init() + * + * @brief: Initialize the Custom hardware manger. This is the + * etnry functinon for the Cust HW manager. + * + * @of_node: Device node + * @hw_mgr_intf: Custom hardware manager object returned + * @iommu_hdl: Iommu handle to be returned + * + */ +int cam_custom_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); + + +/* Utility APIs */ + +/** + * cam_custom_hw_mgr_get_custom_res_state() + * + * @brief: Obtain equivalent custom rsrc state + * from isp rsrc state + * + * @in_rsrc_state: isp rsrc state + * + */ +enum cam_custom_hw_resource_state + cam_custom_hw_mgr_get_custom_res_state( + uint32_t in_rsrc_state); + +/** + * cam_custom_hw_mgr_get_isp_res_state() + * + * @brief: Obtain equivalent isp rsrc state + * from custom rsrc state + * + * @in_rsrc_state: custom rsrc state + * + */ +enum cam_isp_resource_state + cam_custom_hw_mgr_get_isp_res_state( + uint32_t in_rsrc_state); + +/** + * cam_custom_hw_mgr_get_isp_res_type() + * + * @brief: Obtain equivalent isp rsrc type + * from custom rsrc type + * + * @res_type: custom rsrc type + * + */ +enum cam_isp_resource_type + cam_custom_hw_mgr_get_isp_res_type( + enum cam_custom_hw_mgr_res_type res_type); + +#endif /* _CAM_CUSTOM_HW_MGR_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..0fd557c14052b362bbb98348b6952d73d4583761 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_H_ +#define _CAM_CUSTOM_HW_H_ + +#include <linux/of.h> +#include <linux/time.h> +#include <linux/list.h> +#include <uapi/media/cam_custom.h> + +enum cam_custom_hw_resource_state { + CAM_CUSTOM_HW_RESOURCE_STATE_UNAVAILABLE = 0, + CAM_CUSTOM_HW_RESOURCE_STATE_AVAILABLE = 1, + CAM_CUSTOM_HW_RESOURCE_STATE_RESERVED = 2, + CAM_CUSTOM_HW_RESOURCE_STATE_INIT_HW = 3, + CAM_CUSTOM_HW_RESOURCE_STATE_STREAMING = 4, +}; + +/* + * struct cam_custom_resource_node: + * + * @Brief: Structure representing HW resource object + * + * @res_id: Unique resource ID within res_type objects + * for a particular HW + * @res_state: State of the resource + * @hw_intf: HW Interface of HW to which this resource + * belongs + * @res_priv: Private data of the resource + * @irq_handle: handle returned on subscribing for IRQ event + * @init: function pointer to init the HW resource + * @deinit: function pointer to deinit the HW resource + * @start: function pointer to start the HW resource + * @stop: function pointer to stop the HW resource + * @process_cmd: function pointer for processing commands + * specific to the resource + */ +struct cam_custom_resource_node { + uint32_t res_id; + enum cam_custom_hw_resource_state res_state; + struct cam_hw_intf *hw_intf; + void *res_priv; + int irq_handle; + + int (*init)(struct cam_custom_resource_node *rsrc_node, + void *init_args, uint32_t arg_size); + int (*deinit)(struct cam_custom_resource_node *rsrc_node, + void *deinit_args, uint32_t arg_size); + int (*start)(struct cam_custom_resource_node *rsrc_node); + int (*stop)(struct cam_custom_resource_node *rsrc_node); + int (*process_cmd)(struct cam_custom_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); +}; +#endif /* _CAM_CUSTOM_HW_H_ */ diff --git a/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..b1fb1cb42913c7cac1c6bbf9a928251f7f9bf981 --- /dev/null +++ b/techpack/camera/drivers/cam_cust/cam_custom_hw_mgr/include/cam_custom_hw_mgr_intf.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CUSTOM_HW_MGR_INTF_H_ +#define _CAM_CUSTOM_HW_MGR_INTF_H_ + +#include <linux/of.h> +#include <linux/time.h> +#include <linux/list.h> +#include <uapi/media/cam_custom.h> +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" + +#define CAM_CUSTOM_HW_TYPE_1 1 + +#define CAM_CUSTOM_HW_RES_MAX 32 + +#define CAM_CUSTOM_HW_SUB_MOD_MAX 1 +#define CAM_CUSTOM_CSID_HW_MAX 1 + +enum cam_custom_hw_event_type { + CAM_CUSTOM_EVENT_TYPE_ERROR, + CAM_CUSTOM_EVENT_BUF_DONE, +}; + +enum cam_custom_cmd_types { + CAM_CUSTOM_CMD_NONE, + CAM_CUSTOM_SET_IRQ_CB, + CAM_CUSTOM_SUBMIT_REQ, +}; + +/** + * struct cam_custom_stop_args - hardware stop arguments + * + * @stop_only Send stop only to hw drivers. No Deinit to be + * done. + */ +struct cam_custom_stop_args { + bool stop_only; +}; + +/** + * struct cam_custom_start_args - custom hardware start arguments + * + * @hw_config: Hardware configuration commands. + * @start_only Send start only to hw drivers. No init to + * be done. + * + */ +struct cam_custom_start_args { + struct cam_hw_config_args hw_config; + bool start_only; +}; + +/** + * struct cam_custom_prepare_hw_update_data - hw prepare data + * + * @packet_opcode_type: Packet header opcode in the packet header + * this opcode defines, packet is init packet or + * update packet + * + */ +struct cam_custom_prepare_hw_update_data { + uint32_t packet_opcode_type; +}; + +/** + * struct cam_custom_hw_cb_args : HW manager callback args + * + * @irq_status : irq status + * @req_info : Pointer to the request info associated with the cb + */ +struct cam_custom_hw_cb_args { + uint32_t irq_status; + struct cam_custom_sub_mod_req_to_dev *req_info; +}; + +/** + * cam_custom_hw_sub_mod_init() + * + * @Brief: Initialize Custom HW device + * + * @custom_hw: cust_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of Custom HW + */ +int cam_custom_hw_sub_mod_init(struct cam_hw_intf **custom_hw, uint32_t hw_idx); + +/** + * cam_custom_csid_hw_init() + * + * @Brief: Initialize Custom HW device + * + * @custom_hw: cust_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of Custom HW + */ +int cam_custom_csid_hw_init( + struct cam_hw_intf **custom_hw, uint32_t hw_idx); + +#endif /* _CAM_CUSTOM_HW_MGR_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_fd/Makefile b/techpack/camera/drivers/cam_fd/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..92356a35d8c8f03498940ca298fa501c94a8bc39 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_dev.o cam_fd_context.o diff --git a/techpack/camera/drivers/cam_fd/cam_fd_context.c b/techpack/camera/drivers/cam_fd/cam_fd_context.c new file mode 100644 index 0000000000000000000000000000000000000000..ec6468f85dc0da20d08fa99e435673006fa0a7e1 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/cam_fd_context.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_debug_util.h" +#include "cam_fd_context.h" +#include "cam_trace.h" + +static const char fd_dev_name[] = "cam-fd"; + +/* Functions in Available state */ +static int __cam_fd_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Acquire dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("FD", ctx); + + return rc; +} + +/* Functions in Acquired state */ +static int __cam_fd_ctx_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Release dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_AVAILABLE; + trace_cam_context_state("FD", ctx); + + return rc; +} + +static int __cam_fd_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Prepare dev, rc=%d", rc); + return rc; + } + + return rc; +} + +static int __cam_fd_ctx_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Start dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_ACTIVATED; + trace_cam_context_state("FD", ctx); + + return rc; +} + +/* Functions in Activated state */ +static int __cam_fd_ctx_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Stop dev, rc=%d", rc); + return rc; + } + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("FD", ctx); + + return rc; +} + +static int __cam_fd_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = __cam_fd_ctx_stop_dev_in_activated(ctx, NULL); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Stop dev, rc=%d", rc); + return rc; + } + + rc = __cam_fd_ctx_release_dev_in_acquired(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Release dev, rc=%d", rc); + return rc; + } + + return rc; +} + +static int __cam_fd_ctx_flush_dev_in_activated(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to flush device, rc=%d", rc); + + return rc; +} +static int __cam_fd_ctx_config_dev_in_activated( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_FD, "Failed in Prepare dev, rc=%d", rc); + return rc; + } + + return rc; +} + +static int __cam_fd_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc; + + rc = cam_context_buf_done_from_hw(context, evt_data, evt_id); + if (rc) { + CAM_ERR(CAM_FD, "Failed in buf done, rc=%d", rc); + return rc; + } + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_fd_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_fd_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_fd_ctx_release_dev_in_acquired, + .config_dev = __cam_fd_ctx_config_dev_in_acquired, + .start_dev = __cam_fd_ctx_start_dev_in_acquired, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Ready */ + { + .ioctl_ops = { }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Flushed */ + {}, + /* Activated */ + { + .ioctl_ops = { + .stop_dev = __cam_fd_ctx_stop_dev_in_activated, + .release_dev = __cam_fd_ctx_release_dev_in_activated, + .config_dev = __cam_fd_ctx_config_dev_in_activated, + .flush_dev = __cam_fd_ctx_flush_dev_in_activated, + }, + .crm_ops = {}, + .irq_ops = __cam_fd_ctx_handle_irq_in_activated, + }, +}; + + +int cam_fd_context_init(struct cam_fd_context *fd_ctx, + struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) +{ + int rc; + + if (!base_ctx || !fd_ctx) { + CAM_ERR(CAM_FD, "Invalid Context %pK %pK", base_ctx, fd_ctx); + return -EINVAL; + } + + memset(fd_ctx, 0, sizeof(*fd_ctx)); + + rc = cam_context_init(base_ctx, fd_dev_name, CAM_FD, ctx_id, + NULL, hw_intf, fd_ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_FD, "Camera Context Base init failed, rc=%d", rc); + return rc; + } + + fd_ctx->base = base_ctx; + base_ctx->ctx_priv = fd_ctx; + base_ctx->state_machine = cam_fd_ctx_state_machine; + + return rc; +} + +int cam_fd_context_deinit(struct cam_fd_context *fd_ctx) +{ + int rc = 0; + + if (!fd_ctx || !fd_ctx->base) { + CAM_ERR(CAM_FD, "Invalid inputs %pK", fd_ctx); + return -EINVAL; + } + + rc = cam_context_deinit(fd_ctx->base); + if (rc) + CAM_ERR(CAM_FD, "Error in base deinit, rc=%d", rc); + + memset(fd_ctx, 0, sizeof(*fd_ctx)); + + return rc; +} diff --git a/techpack/camera/drivers/cam_fd/cam_fd_context.h b/techpack/camera/drivers/cam_fd/cam_fd_context.h new file mode 100644 index 0000000000000000000000000000000000000000..ab0fa92b43f2894fbf9d7b4e76635883d1102005 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/cam_fd_context.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_CONTEXT_H_ +#define _CAM_FD_CONTEXT_H_ + +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + +/** + * struct cam_fd_context - Face Detection context information + * + * @base : Base context pointer for this FD context + * @req_base : List of base requests for this FD context + */ +struct cam_fd_context { + struct cam_context *base; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; +}; + +int cam_fd_context_init(struct cam_fd_context *fd_ctx, + struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); +int cam_fd_context_deinit(struct cam_fd_context *ctx); + +#endif /* _CAM_FD_CONTEXT_H_ */ diff --git a/techpack/camera/drivers/cam_fd/cam_fd_dev.c b/techpack/camera/drivers/cam_fd/cam_fd_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..c92cea8fc9e9c293cf6d36d5a8c90ef90198c64a --- /dev/null +++ b/techpack/camera/drivers/cam_fd/cam_fd_dev.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_fd_context.h" +#include "cam_fd_hw_mgr.h" +#include "cam_fd_hw_mgr_intf.h" + +#define CAM_FD_DEV_NAME "cam-fd" + +/** + * struct cam_fd_dev - FD device information + * + * @sd: Subdev information + * @base_ctx: List of base contexts + * @fd_ctx: List of FD contexts + * @lock: Mutex handle + * @open_cnt: FD subdev open count + * @probe_done: Whether FD probe is completed + */ +struct cam_fd_dev { + struct cam_subdev sd; + struct cam_context base_ctx[CAM_CTX_MAX]; + struct cam_fd_context fd_ctx[CAM_CTX_MAX]; + struct mutex lock; + uint32_t open_cnt; + bool probe_done; +}; + +static struct cam_fd_dev g_fd_dev; + +static int cam_fd_dev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_fd_dev *fd_dev = &g_fd_dev; + + if (!fd_dev->probe_done) { + CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev); + return -ENODEV; + } + + mutex_lock(&fd_dev->lock); + fd_dev->open_cnt++; + CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); + mutex_unlock(&fd_dev->lock); + + return 0; +} + +static int cam_fd_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_fd_dev *fd_dev = &g_fd_dev; + struct cam_node *node = v4l2_get_subdevdata(sd); + + if (!fd_dev->probe_done) { + CAM_ERR(CAM_FD, "FD Dev not initialized, fd_dev=%pK", fd_dev); + return -ENODEV; + } + + mutex_lock(&fd_dev->lock); + fd_dev->open_cnt--; + CAM_DBG(CAM_FD, "FD Subdev open count %d", fd_dev->open_cnt); + mutex_unlock(&fd_dev->lock); + + if (!node) { + CAM_ERR(CAM_FD, "Node ptr is NULL"); + return -EINVAL; + } + + cam_node_shutdown(node); + + return 0; +} + +static const struct v4l2_subdev_internal_ops cam_fd_subdev_internal_ops = { + .open = cam_fd_dev_open, + .close = cam_fd_dev_close, +}; + +static int cam_fd_dev_probe(struct platform_device *pdev) +{ + int rc; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + + g_fd_dev.sd.internal_ops = &cam_fd_subdev_internal_ops; + + /* Initialize the v4l2 subdevice first. (create cam_node) */ + rc = cam_subdev_probe(&g_fd_dev.sd, pdev, CAM_FD_DEV_NAME, + CAM_FD_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_FD, "FD cam_subdev_probe failed, rc=%d", rc); + return rc; + } + node = (struct cam_node *) g_fd_dev.sd.token; + + rc = cam_fd_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf); + if (rc) { + CAM_ERR(CAM_FD, "Failed in initializing FD HW manager, rc=%d", + rc); + goto unregister_subdev; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_fd_context_init(&g_fd_dev.fd_ctx[i], + &g_fd_dev.base_ctx[i], &node->hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_FD, "FD context init failed i=%d, rc=%d", + i, rc); + goto deinit_ctx; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_fd_dev.base_ctx, CAM_CTX_MAX, + CAM_FD_DEV_NAME); + if (rc) { + CAM_ERR(CAM_FD, "FD node init failed, rc=%d", rc); + goto deinit_ctx; + } + + mutex_init(&g_fd_dev.lock); + g_fd_dev.probe_done = true; + + CAM_DBG(CAM_FD, "Camera FD probe complete"); + + return 0; + +deinit_ctx: + for (--i; i >= 0; i--) { + if (cam_fd_context_deinit(&g_fd_dev.fd_ctx[i])) + CAM_ERR(CAM_FD, "FD context %d deinit failed", i); + } +unregister_subdev: + if (cam_subdev_remove(&g_fd_dev.sd)) + CAM_ERR(CAM_FD, "Failed in subdev remove"); + + return rc; +} + +static int cam_fd_dev_remove(struct platform_device *pdev) +{ + int i, rc; + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_fd_context_deinit(&g_fd_dev.fd_ctx[i]); + if (rc) + CAM_ERR(CAM_FD, "FD context %d deinit failed, rc=%d", + i, rc); + } + + rc = cam_fd_hw_mgr_deinit(pdev->dev.of_node); + if (rc) + CAM_ERR(CAM_FD, "Failed in hw mgr deinit, rc=%d", rc); + + rc = cam_subdev_remove(&g_fd_dev.sd); + if (rc) + CAM_ERR(CAM_FD, "Unregister failed, rc=%d", rc); + + mutex_destroy(&g_fd_dev.lock); + g_fd_dev.probe_done = false; + + return rc; +} + +static const struct of_device_id cam_fd_dt_match[] = { + { + .compatible = "qcom,cam-fd" + }, + {} +}; + +static struct platform_driver cam_fd_driver = { + .probe = cam_fd_dev_probe, + .remove = cam_fd_dev_remove, + .driver = { + .name = "cam_fd", + .owner = THIS_MODULE, + .of_match_table = cam_fd_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_fd_dev_init_module(void) +{ + return platform_driver_register(&cam_fd_driver); +} + +static void __exit cam_fd_dev_exit_module(void) +{ + platform_driver_unregister(&cam_fd_driver); +} + +module_init(cam_fd_dev_init_module); +module_exit(cam_fd_dev_exit_module); +MODULE_DESCRIPTION("MSM FD driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/Makefile b/techpack/camera/drivers/cam_fd/fd_hw_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8db8097679b51c9a4eda490306dfbb593d0386d8 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_mgr.o diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..b33dfa6996473044ba317c6f0c98a47b3abf26da --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -0,0 +1,1959 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_cpas.h> +#include <media/cam_req_mgr.h> + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_mem_mgr_api.h" +#include "cam_smmu_api.h" +#include "cam_packet_util.h" +#include "cam_fd_context.h" +#include "cam_fd_hw_intf.h" +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" +#include "cam_fd_hw_mgr_intf.h" +#include "cam_fd_hw_mgr.h" +#include "cam_trace.h" + +static struct cam_fd_hw_mgr g_fd_hw_mgr; + +static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + int i, rc; + + if (!packet) + return -EINVAL; + + CAM_DBG(CAM_FD, "Packet request=%d, op_code=0x%x, size=%d, flags=%d", + packet->header.request_id, packet->header.op_code, + packet->header.size, packet->header.flags); + CAM_DBG(CAM_FD, + "Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)", + packet->cmd_buf_offset, packet->num_cmd_buf, + packet->io_configs_offset, packet->num_io_configs); + CAM_DBG(CAM_FD, + "Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)", + packet->patch_offset, packet->num_patches, + packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); + + if (cam_packet_util_validate_packet(packet, remain_len)) { + CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d", + packet->kmd_cmd_buf_index, + packet->num_cmd_buf, packet->cmd_buf_offset, + packet->io_configs_offset, packet->header.size); + return -EINVAL; + } + + /* All buffers must come through io config, do not support patching */ + if (packet->num_patches || !packet->num_io_configs) { + CAM_ERR(CAM_FD, "wrong number of cmd/patch info: %u %u", + packet->num_cmd_buf, packet->num_patches); + return -EINVAL; + } + + /* KMD Buf index can never be greater than or equal to num cmd bufs */ + if (packet->kmd_cmd_buf_index >= packet->num_cmd_buf) { + CAM_ERR(CAM_FD, "Invalid kmd index %d (%d)", + packet->kmd_cmd_buf_index, packet->num_cmd_buf); + return -EINVAL; + } + + if ((packet->header.op_code & 0xff) != + CAM_PACKET_OPCODES_FD_FRAME_UPDATE) { + CAM_ERR(CAM_FD, "Invalid op_code %u", + packet->header.op_code & 0xff); + return -EINVAL; + } + + cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)&packet->payload + + packet->cmd_buf_offset); + + for (i = 0; i < packet->num_cmd_buf; i++) { + /* + * We can allow 0 length cmd buffer. This can happen in case + * umd gives an empty cmd buffer as kmd buffer + */ + if (!cmd_desc[i].length) + continue; + + if ((cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_GENERIC) && + (cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_CDM)) { + CAM_ERR(CAM_FD, "Invalid meta_data [%d] %u", i, + cmd_desc[i].meta_data); + return -EINVAL; + } + + CAM_DBG(CAM_FD, + "CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d", + i, + cmd_desc[i].mem_handle, cmd_desc[i].offset, + cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type, + cmd_desc[i].meta_data); + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) { + CAM_ERR(CAM_FD, "Invalid cmd buffer %d", i); + return rc; + } + } + + return 0; +} + +static int cam_fd_mgr_util_put_ctx( + struct list_head *src_list, + struct cam_fd_hw_mgr_ctx **fd_ctx) +{ + int rc = 0; + struct cam_fd_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.ctx_mutex); + ctx_ptr = *fd_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *fd_ctx = NULL; + mutex_unlock(&g_fd_hw_mgr.ctx_mutex); + + return rc; +} + +static int cam_fd_mgr_util_get_ctx( + struct list_head *src_list, + struct cam_fd_hw_mgr_ctx **fd_ctx) +{ + int rc = 0; + struct cam_fd_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.ctx_mutex); + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_fd_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_FD, "No more free fd hw mgr ctx"); + rc = -1; + } + *fd_ctx = ctx_ptr; + mutex_unlock(&g_fd_hw_mgr.ctx_mutex); + + return rc; +} + +static int cam_fd_mgr_util_put_frame_req( + struct list_head *src_list, + struct cam_fd_mgr_frame_request **frame_req) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *req_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.frame_req_mutex); + req_ptr = *frame_req; + if (req_ptr) { + list_del_init(&req_ptr->list); + list_add_tail(&req_ptr->list, src_list); + } + *frame_req = NULL; + mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); + + return rc; +} + +static int cam_fd_mgr_util_get_frame_req( + struct list_head *src_list, + struct cam_fd_mgr_frame_request **frame_req) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *req_ptr = NULL; + + mutex_lock(&g_fd_hw_mgr.frame_req_mutex); + if (!list_empty(src_list)) { + req_ptr = list_first_entry(src_list, + struct cam_fd_mgr_frame_request, list); + list_del_init(&req_ptr->list); + } else { + CAM_DBG(CAM_FD, "Frame req not available"); + rc = -EPERM; + } + *frame_req = req_ptr; + mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); + + return rc; +} + +static int cam_fd_mgr_util_get_device(struct cam_fd_hw_mgr *hw_mgr, + struct cam_fd_hw_mgr_ctx *hw_ctx, struct cam_fd_device **hw_device) +{ + if (!hw_mgr || !hw_ctx || !hw_device) { + CAM_ERR(CAM_FD, "Invalid input %pK %pK %pK", hw_mgr, hw_ctx, + hw_device); + return -EINVAL; + } + + if ((hw_ctx->device_index < 0) || + (hw_ctx->device_index >= CAM_FD_HW_MAX)) { + CAM_ERR(CAM_FD, "Invalid device indx %d", hw_ctx->device_index); + return -EINVAL; + } + + CAM_DBG(CAM_FD, "ctx_index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + *hw_device = &hw_mgr->hw_device[hw_ctx->device_index]; + + return 0; +} + +static int cam_fd_mgr_util_release_device(struct cam_fd_hw_mgr *hw_mgr, + struct cam_fd_hw_mgr_ctx *hw_ctx) +{ + struct cam_fd_device *hw_device; + struct cam_fd_hw_release_args hw_release_args; + int rc; + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + if (hw_device->hw_intf->hw_ops.release) { + hw_release_args.hw_ctx = hw_ctx; + hw_release_args.ctx_hw_private = hw_ctx->ctx_hw_private; + rc = hw_device->hw_intf->hw_ops.release( + hw_device->hw_intf->hw_priv, &hw_release_args, + sizeof(hw_release_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW release %d", rc); + return rc; + } + } else { + CAM_ERR(CAM_FD, "Invalid release function"); + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + hw_device->num_ctxts--; + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + hw_ctx->device_index = -1; + + return rc; +} + +static int cam_fd_mgr_util_select_device(struct cam_fd_hw_mgr *hw_mgr, + struct cam_fd_hw_mgr_ctx *hw_ctx, + struct cam_fd_acquire_dev_info *fd_acquire_args) +{ + int i, rc; + struct cam_fd_hw_reserve_args hw_reserve_args; + struct cam_fd_device *hw_device = NULL; + + if (!hw_mgr || !hw_ctx || !fd_acquire_args) { + CAM_ERR(CAM_FD, "Invalid input %pK %pK %pK", hw_mgr, hw_ctx, + fd_acquire_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + /* Check if a device is free which can satisfy the requirements */ + for (i = 0; i < hw_mgr->num_devices; i++) { + hw_device = &hw_mgr->hw_device[i]; + CAM_DBG(CAM_FD, + "[%d] : num_ctxts=%d, modes=%d, raw_results=%d", + i, hw_device->num_ctxts, + hw_device->hw_caps.supported_modes, + hw_device->hw_caps.raw_results_available); + if ((hw_device->num_ctxts == 0) && + (fd_acquire_args->mode & + hw_device->hw_caps.supported_modes) && + (!fd_acquire_args->get_raw_results || + hw_device->hw_caps.raw_results_available)) { + CAM_DBG(CAM_FD, "Found dedicated HW Index=%d", i); + hw_device->num_ctxts++; + break; + } + } + + /* + * We couldn't find a free HW which meets requirement, now check if + * there is a HW which meets acquire requirements + */ + if (i == hw_mgr->num_devices) { + for (i = 0; i < hw_mgr->num_devices; i++) { + hw_device = &hw_mgr->hw_device[i]; + if ((fd_acquire_args->mode & + hw_device->hw_caps.supported_modes) && + (!fd_acquire_args->get_raw_results || + hw_device->hw_caps.raw_results_available)) { + hw_device->num_ctxts++; + CAM_DBG(CAM_FD, "Found sharing HW Index=%d", i); + break; + } + } + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + if ((i == hw_mgr->num_devices) || !hw_device) { + CAM_ERR(CAM_FD, "Couldn't acquire HW %d %d", + fd_acquire_args->mode, + fd_acquire_args->get_raw_results); + return -EBUSY; + } + + CAM_DBG(CAM_FD, "Device index %d selected for this acquire", i); + + /* Check if we can reserve this HW */ + if (hw_device->hw_intf->hw_ops.reserve) { + hw_reserve_args.hw_ctx = hw_ctx; + hw_reserve_args.mode = fd_acquire_args->mode; + rc = hw_device->hw_intf->hw_ops.reserve( + hw_device->hw_intf->hw_priv, &hw_reserve_args, + sizeof(hw_reserve_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW reserve %d", rc); + return rc; + } + hw_ctx->ctx_hw_private = hw_reserve_args.ctx_hw_private; + } else { + CAM_ERR(CAM_FD, "Invalid reserve function"); + return -EPERM; + } + + /* Update required info in hw context */ + hw_ctx->device_index = i; + + CAM_DBG(CAM_FD, "ctx index=%u, device_index=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + return 0; +} + +static int cam_fd_mgr_util_pdev_get_hw_intf(struct device_node *of_node, + int i, struct cam_hw_intf **device_hw_intf) +{ + struct device_node *device_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *hw_intf = NULL; + const char *name = NULL; + int rc; + + rc = of_property_read_string_index(of_node, "compat-hw-name", i, &name); + if (rc) { + CAM_ERR(CAM_FD, "Getting dev object name failed %d %d", i, rc); + goto put_node; + } + + device_node = of_find_node_by_name(NULL, name); + if (!device_node) { + CAM_ERR(CAM_FD, "Cannot find node in dtsi %s", name); + return -ENODEV; + } + + child_pdev = of_find_device_by_node(device_node); + if (!child_pdev) { + CAM_ERR(CAM_FD, "Failed to find device on bus %s", + device_node->name); + rc = -ENODEV; + goto put_node; + } + + hw_intf = (struct cam_hw_intf *)platform_get_drvdata(child_pdev); + if (!hw_intf) { + CAM_ERR(CAM_FD, "No driver data for child device"); + rc = -ENODEV; + goto put_node; + } + + CAM_DBG(CAM_FD, "child type %d index %d child_intf %pK", + hw_intf->hw_type, hw_intf->hw_idx, hw_intf); + + if (hw_intf->hw_idx >= CAM_FD_HW_MAX) { + CAM_ERR(CAM_FD, "hw_idx invalid %d", hw_intf->hw_idx); + rc = -ENODEV; + goto put_node; + } + + rc = 0; + *device_hw_intf = hw_intf; + +put_node: + of_node_put(device_node); + + return rc; +} + +static int cam_fd_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + struct cam_fd_hw_cmd_prestart_args *prestart_args = + (struct cam_fd_hw_cmd_prestart_args *)user_data; + + if (!blob_data || (blob_size == 0)) { + CAM_ERR(CAM_FD, "Invalid blob info %pK %u", blob_data, + blob_size); + return -EINVAL; + } + + if (!prestart_args) { + CAM_ERR(CAM_FD, "Invalid user data"); + return -EINVAL; + } + + switch (blob_type) { + case CAM_FD_BLOB_TYPE_RAW_RESULTS_REQUIRED: { + uint32_t *get_raw_results = (uint32_t *)blob_data; + + if (sizeof(uint32_t) != blob_size) { + CAM_ERR(CAM_FD, "Invalid blob size %zu %u", + sizeof(uint32_t), blob_size); + return -EINVAL; + } + + prestart_args->get_raw_results = *get_raw_results; + break; + } + case CAM_FD_BLOB_TYPE_SOC_CLOCK_BW_REQUEST: { + struct cam_fd_soc_clock_bw_request *clk_req = + (struct cam_fd_soc_clock_bw_request *)blob_data; + + if (sizeof(struct cam_fd_soc_clock_bw_request) != blob_size) { + CAM_ERR(CAM_FD, "Invalid blob size %zu %u", + sizeof(struct cam_fd_soc_clock_bw_request), + blob_size); + return -EINVAL; + } + + CAM_DBG(CAM_FD, "SOC Clk Request clock=%lld, bw=%lld", + clk_req->clock_rate, clk_req->bandwidth); + + break; + } + default: + CAM_WARN(CAM_FD, "Unknown blob type %d", blob_type); + break; + } + + return 0; +} + +static int cam_fd_mgr_util_parse_generic_cmd_buffer( + struct cam_fd_hw_mgr_ctx *hw_ctx, struct cam_packet *packet, + struct cam_fd_hw_cmd_prestart_args *prestart_args) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + int i, rc = 0; + + cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *)&packet->payload + + packet->cmd_buf_offset); + + for (i = 0; i < packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if (cmd_desc[i].meta_data == CAM_FD_CMD_BUFFER_ID_CDM) + continue; + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) + return rc; + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i], + cam_fd_packet_generic_blob_handler, prestart_args); + if (rc) + CAM_ERR(CAM_FD, "Failed in processing blobs %d", rc); + + break; + } + + return rc; +} + +static int cam_fd_mgr_util_get_buf_map_requirement(uint32_t direction, + uint32_t resource_type, bool *need_io_map, bool *need_cpu_map) +{ + if (!need_io_map || !need_cpu_map) { + CAM_ERR(CAM_FD, "Invalid input pointers %pK %pK", need_io_map, + need_cpu_map); + return -EINVAL; + } + + if (direction == CAM_BUF_INPUT) { + switch (resource_type) { + case CAM_FD_INPUT_PORT_ID_IMAGE: + *need_io_map = true; + *need_cpu_map = false; + break; + default: + CAM_WARN(CAM_FD, "Invalid port: dir %d, id %d", + direction, resource_type); + return -EINVAL; + } + } else if (direction == CAM_BUF_OUTPUT) { + switch (resource_type) { + case CAM_FD_OUTPUT_PORT_ID_RESULTS: + *need_io_map = true; + *need_cpu_map = true; + break; + case CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS: + *need_io_map = true; + *need_cpu_map = true; + break; + case CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER: + *need_io_map = true; + *need_cpu_map = false; + break; + default: + CAM_WARN(CAM_FD, "Invalid port: dir %d, id %d", + direction, resource_type); + return -EINVAL; + } + } else { + CAM_WARN(CAM_FD, "Invalid direction %d", direction); + return -EINVAL; + } + + return 0; +} + +static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + struct cam_fd_hw_io_buffer *input_buf, + struct cam_fd_hw_io_buffer *output_buf, uint32_t io_buf_size) +{ + int rc = -EINVAL; + uint32_t plane, num_out_buf, num_in_buf; + int i, j; + struct cam_buf_io_cfg *io_cfg; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; + uintptr_t cpu_addr[CAM_PACKET_MAX_PLANES]; + size_t size; + bool need_io_map, need_cpu_map; + + /* Get IO Buf information */ + num_out_buf = 0; + num_in_buf = 0; + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &prepare->packet->payload + prepare->packet->io_configs_offset); + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_FD, + "IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]", + i, io_cfg[i].mem_handle[0], io_cfg[i].direction, + io_cfg[i].resource_type, + io_cfg[i].fence, io_cfg[i].format); + + if ((num_in_buf >= io_buf_size) || + (num_out_buf >= io_buf_size)) { + CAM_ERR(CAM_FD, "Invalid number of buffers %d %d %d", + num_in_buf, num_out_buf, io_buf_size); + return -EINVAL; + } + + rc = cam_fd_mgr_util_get_buf_map_requirement( + io_cfg[i].direction, io_cfg[i].resource_type, + &need_io_map, &need_cpu_map); + if (rc) { + CAM_WARN(CAM_FD, "Invalid io buff [%d] : %d %d %d", + i, io_cfg[i].direction, + io_cfg[i].resource_type, rc); + continue; + } + + memset(io_addr, 0x0, sizeof(io_addr)); + for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) { + if (!io_cfg[i].mem_handle[plane]) + break; + + io_addr[plane] = 0x0; + cpu_addr[plane] = 0x0; + + if (need_io_map) { + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane], + iommu_hdl, &io_addr[plane], &size); + if (rc) { + CAM_ERR(CAM_FD, + "Failed to get io buf %u %u %u %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + rc); + return -ENOMEM; + } + + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid io buf %u %u %u %d %u %zu", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + i, io_cfg[i].offsets[plane], + size); + return -EINVAL; + } + + io_addr[plane] += io_cfg[i].offsets[plane]; + } + + if (need_cpu_map) { + rc = cam_mem_get_cpu_buf( + io_cfg[i].mem_handle[plane], + &cpu_addr[plane], &size); + if (rc || ((io_addr[plane] & 0xFFFFFFFF) + != io_addr[plane])) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + rc); + return rc; + } + if (io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane); + rc = -EINVAL; + return rc; + } + cpu_addr[plane] += io_cfg[i].offsets[plane]; + } + + CAM_DBG(CAM_FD, "IO Address[%d][%d] : %pK, %pK", + io_cfg[i].direction, plane, io_addr[plane], + cpu_addr[plane]); + } + + switch (io_cfg[i].direction) { + case CAM_BUF_INPUT: { + prepare->in_map_entries[num_in_buf].resource_handle = + io_cfg[i].resource_type; + prepare->in_map_entries[num_in_buf].sync_id = + io_cfg[i].fence; + + input_buf[num_in_buf].valid = true; + for (j = 0; j < plane; j++) { + input_buf[num_in_buf].io_addr[j] = io_addr[j]; + input_buf[num_in_buf].cpu_addr[j] = cpu_addr[j]; + } + input_buf[num_in_buf].num_buf = plane; + input_buf[num_in_buf].io_cfg = &io_cfg[i]; + + num_in_buf++; + break; + } + case CAM_BUF_OUTPUT: { + prepare->out_map_entries[num_out_buf].resource_handle = + io_cfg[i].resource_type; + prepare->out_map_entries[num_out_buf].sync_id = + io_cfg[i].fence; + + output_buf[num_out_buf].valid = true; + for (j = 0; j < plane; j++) { + output_buf[num_out_buf].io_addr[j] = io_addr[j]; + output_buf[num_out_buf].cpu_addr[j] = + cpu_addr[j]; + } + output_buf[num_out_buf].num_buf = plane; + output_buf[num_out_buf].io_cfg = &io_cfg[i]; + + num_out_buf++; + break; + } + default: + CAM_ERR(CAM_FD, "Unsupported io direction %d", + io_cfg[i].direction); + rc = -EINVAL; + break; + } + } + + prepare->num_in_map_entries = num_in_buf; + prepare->num_out_map_entries = num_out_buf; + return rc; +} + +static int cam_fd_mgr_util_prepare_hw_update_entries( + struct cam_fd_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare, + struct cam_fd_hw_cmd_prestart_args *prestart_args, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int i, rc; + struct cam_hw_update_entry *hw_entry; + uint32_t num_ent; + struct cam_fd_hw_mgr_ctx *hw_ctx = + (struct cam_fd_hw_mgr_ctx *)prepare->ctxt_to_hw_map; + struct cam_fd_device *hw_device; + uint32_t kmd_buf_max_size, kmd_buf_used_bytes = 0; + uint32_t *kmd_buf_addr; + struct cam_cmd_buf_desc *cmd_desc = NULL; + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes); + kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes; + + prestart_args->cmd_buf_addr = kmd_buf_addr; + prestart_args->size = kmd_buf_max_size; + prestart_args->pre_config_buf_size = 0; + prestart_args->post_config_buf_size = 0; + + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, CAM_FD_HW_CMD_PRESTART, + prestart_args, + sizeof(struct cam_fd_hw_cmd_prestart_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in CMD_PRESTART %d", rc); + return rc; + } + } + + kmd_buf_used_bytes += prestart_args->pre_config_buf_size; + kmd_buf_used_bytes += prestart_args->post_config_buf_size; + + /* HW layer is expected to add commands */ + if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) { + CAM_ERR(CAM_FD, "Invalid kmd used bytes %d (%d)", + kmd_buf_used_bytes, kmd_buf_max_size); + return -ENOMEM; + } + + hw_entry = prepare->hw_update_entries; + num_ent = 0; + + if (prestart_args->pre_config_buf_size) { + if ((num_ent + 1) >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_FD, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_ent].handle = kmd_buf_info->handle; + hw_entry[num_ent].len = prestart_args->pre_config_buf_size; + hw_entry[num_ent].offset = kmd_buf_info->offset; + + kmd_buf_info->used_bytes += prestart_args->pre_config_buf_size; + kmd_buf_info->offset += prestart_args->pre_config_buf_size; + num_ent++; + } + + /* + * set the cmd_desc to point the first command descriptor in the + * packet and update hw entries with CDM command buffers + */ + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *) + &prepare->packet->payload + prepare->packet->cmd_buf_offset); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if (cmd_desc[i].meta_data != CAM_FD_CMD_BUFFER_ID_CDM) + continue; + + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_FD, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_ent].handle = cmd_desc[i].mem_handle; + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].offset = cmd_desc[i].offset; + num_ent++; + } + + if (prestart_args->post_config_buf_size) { + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_FD, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_ent].handle = kmd_buf_info->handle; + hw_entry[num_ent].len = prestart_args->post_config_buf_size; + hw_entry[num_ent].offset = kmd_buf_info->offset; + + kmd_buf_info->used_bytes += prestart_args->post_config_buf_size; + kmd_buf_info->offset += prestart_args->post_config_buf_size; + + num_ent++; + } + + prepare->num_hw_update_entries = num_ent; + + CAM_DBG(CAM_FD, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)", + prepare->num_hw_update_entries, prepare->num_in_map_entries, + prepare->num_out_map_entries); + + return rc; +} + +static int cam_fd_mgr_util_submit_frame(void *priv, void *data) +{ + struct cam_fd_device *hw_device; + struct cam_fd_hw_mgr *hw_mgr; + struct cam_fd_mgr_frame_request *frame_req; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_hw_cmd_start_args start_args; + int rc; + + if (!priv) { + CAM_ERR(CAM_FD, "Invalid data"); + return -EINVAL; + } + + hw_mgr = (struct cam_fd_hw_mgr *)priv; + mutex_lock(&hw_mgr->frame_req_mutex); + + /* Check if we have any frames pending in high priority list */ + if (!list_empty(&hw_mgr->frame_pending_list_high)) { + CAM_DBG(CAM_FD, "Pending frames in high priority list"); + frame_req = list_first_entry(&hw_mgr->frame_pending_list_high, + struct cam_fd_mgr_frame_request, list); + } else if (!list_empty(&hw_mgr->frame_pending_list_normal)) { + CAM_DBG(CAM_FD, "Pending frames in normal priority list"); + frame_req = list_first_entry(&hw_mgr->frame_pending_list_normal, + struct cam_fd_mgr_frame_request, list); + } else { + mutex_unlock(&hw_mgr->frame_req_mutex); + CAM_DBG(CAM_FD, "No pending frames"); + return 0; + } + + CAM_DBG(CAM_FD, "FrameSubmit : Frame[%lld]", frame_req->request_id); + hw_ctx = frame_req->hw_ctx; + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + mutex_unlock(&hw_mgr->frame_req_mutex); + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_device->lock); + if (hw_device->ready_to_process == false) { + mutex_unlock(&hw_device->lock); + mutex_unlock(&hw_mgr->frame_req_mutex); + return -EBUSY; + } + + trace_cam_submit_to_hw("FD", frame_req->request_id); + + list_del_init(&frame_req->list); + mutex_unlock(&hw_mgr->frame_req_mutex); + + if (hw_device->hw_intf->hw_ops.start) { + start_args.hw_ctx = hw_ctx; + start_args.ctx_hw_private = hw_ctx->ctx_hw_private; + start_args.hw_req_private = &frame_req->hw_req_private; + start_args.hw_update_entries = frame_req->hw_update_entries; + start_args.num_hw_update_entries = + frame_req->num_hw_update_entries; + + rc = hw_device->hw_intf->hw_ops.start( + hw_device->hw_intf->hw_priv, &start_args, + sizeof(start_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW Start %d", rc); + mutex_unlock(&hw_device->lock); + goto put_req_into_free_list; + } + } else { + CAM_ERR(CAM_FD, "Invalid hw_ops.start"); + mutex_unlock(&hw_device->lock); + rc = -EPERM; + goto put_req_into_free_list; + } + + hw_device->ready_to_process = false; + hw_device->cur_hw_ctx = hw_ctx; + hw_device->req_id = frame_req->request_id; + mutex_unlock(&hw_device->lock); + + rc = cam_fd_mgr_util_put_frame_req( + &hw_mgr->frame_processing_list, &frame_req); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in putting frame req in processing list"); + goto stop_unlock; + } + + return rc; + +stop_unlock: + if (hw_device->hw_intf->hw_ops.stop) { + struct cam_fd_hw_stop_args stop_args; + + stop_args.hw_ctx = hw_ctx; + stop_args.ctx_hw_private = hw_ctx->ctx_hw_private; + stop_args.hw_req_private = &frame_req->hw_req_private; + if (hw_device->hw_intf->hw_ops.stop( + hw_device->hw_intf->hw_priv, &stop_args, + sizeof(stop_args))) + CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc); + } +put_req_into_free_list: + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &frame_req); + + return rc; +} + +static int cam_fd_mgr_util_schedule_frame_worker_task( + struct cam_fd_hw_mgr *hw_mgr) +{ + int32_t rc = 0; + struct crm_workq_task *task; + struct cam_fd_mgr_work_data *work_data; + + task = cam_req_mgr_workq_get_task(hw_mgr->work); + if (!task) { + CAM_ERR(CAM_FD, "no empty task available"); + return -ENOMEM; + } + + work_data = (struct cam_fd_mgr_work_data *)task->payload; + work_data->type = CAM_FD_WORK_FRAME; + + task->process_cb = cam_fd_mgr_util_submit_frame; + rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0); + + return rc; +} + +static int32_t cam_fd_mgr_workq_irq_cb(void *priv, void *data) +{ + struct cam_fd_device *hw_device = NULL; + struct cam_fd_hw_mgr *hw_mgr; + struct cam_fd_mgr_work_data *work_data; + struct cam_fd_mgr_frame_request *frame_req = NULL; + enum cam_fd_hw_irq_type irq_type; + bool frame_abort = true; + int rc; + + if (!data || !priv) { + CAM_ERR(CAM_FD, "Invalid data %pK %pK", data, priv); + return -EINVAL; + } + + hw_mgr = (struct cam_fd_hw_mgr *)priv; + work_data = (struct cam_fd_mgr_work_data *)data; + irq_type = work_data->irq_type; + + CAM_DBG(CAM_FD, "FD IRQ type=%d", irq_type); + + if (irq_type == CAM_FD_IRQ_HALT_DONE) { + /* HALT would be followed by a RESET, ignore this */ + CAM_DBG(CAM_FD, "HALT IRQ callback"); + return 0; + } + + /* Get the frame from processing list */ + rc = cam_fd_mgr_util_get_frame_req(&hw_mgr->frame_processing_list, + &frame_req); + if (rc || !frame_req) { + /* + * This can happen if reset is triggered while no frames + * were pending, so not an error, just continue to check if + * there are any pending frames and submit + */ + CAM_DBG(CAM_FD, "No Frame in processing list, rc=%d", rc); + goto submit_next_frame; + } + + if (!frame_req->hw_ctx) { + CAM_ERR(CAM_FD, "Invalid Frame request %lld", + frame_req->request_id); + goto put_req_in_free_list; + } + + rc = cam_fd_mgr_util_get_device(hw_mgr, frame_req->hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + goto put_req_in_free_list; + } + + /* Read frame results first */ + if (irq_type == CAM_FD_IRQ_FRAME_DONE) { + struct cam_fd_hw_frame_done_args frame_done_args; + + CAM_DBG(CAM_FD, "FrameDone : Frame[%lld]", + frame_req->request_id); + + frame_done_args.hw_ctx = frame_req->hw_ctx; + frame_done_args.ctx_hw_private = + frame_req->hw_ctx->ctx_hw_private; + frame_done_args.request_id = frame_req->request_id; + frame_done_args.hw_req_private = &frame_req->hw_req_private; + + if (hw_device->hw_intf->hw_ops.process_cmd) { + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_FRAME_DONE, + &frame_done_args, sizeof(frame_done_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in CMD_PRESTART %d", + rc); + frame_abort = true; + goto notify_context; + } + } + + frame_abort = false; + } + + trace_cam_irq_handled("FD", irq_type); + +notify_context: + /* Do a callback to inform frame done or stop done */ + if (frame_req->hw_ctx->event_cb) { + struct cam_hw_done_event_data buf_data; + + CAM_DBG(CAM_FD, "FrameHALT : Frame[%lld]", + frame_req->request_id); + + buf_data.num_handles = frame_req->num_hw_update_entries; + buf_data.request_id = frame_req->request_id; + + rc = frame_req->hw_ctx->event_cb(frame_req->hw_ctx->cb_priv, + frame_abort, &buf_data); + if (rc) + CAM_ERR(CAM_FD, "Error in event cb handling %d", rc); + } + + /* + * Now we can set hw device is free to process further frames. + * Note - Do not change state to IDLE until we read the frame results, + * Otherwise, other thread may schedule frame processing before + * reading current frame's results. Also, we need to set to IDLE state + * in case some error happens after getting this irq callback + */ + mutex_lock(&hw_device->lock); + hw_device->ready_to_process = true; + hw_device->req_id = -1; + hw_device->cur_hw_ctx = NULL; + CAM_DBG(CAM_FD, "ready_to_process=%d", hw_device->ready_to_process); + mutex_unlock(&hw_device->lock); + +put_req_in_free_list: + rc = cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req); + if (rc) { + CAM_ERR(CAM_FD, "Failed in putting frame req in free list"); + /* continue */ + } + +submit_next_frame: + /* Check if there are any frames pending for processing and submit */ + rc = cam_fd_mgr_util_submit_frame(hw_mgr, NULL); + if (rc) { + CAM_ERR(CAM_FD, "Error while submit frame, rc=%d", rc); + return rc; + } + + return rc; +} + +static int cam_fd_mgr_irq_cb(void *data, enum cam_fd_hw_irq_type irq_type) +{ + struct cam_fd_hw_mgr *hw_mgr = &g_fd_hw_mgr; + int rc = 0; + unsigned long flags; + struct crm_workq_task *task; + struct cam_fd_mgr_work_data *work_data; + + spin_lock_irqsave(&hw_mgr->hw_mgr_slock, flags); + task = cam_req_mgr_workq_get_task(hw_mgr->work); + if (!task) { + CAM_ERR(CAM_FD, "no empty task available"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_slock, flags); + return -ENOMEM; + } + + work_data = (struct cam_fd_mgr_work_data *)task->payload; + work_data->type = CAM_FD_WORK_IRQ; + work_data->irq_type = irq_type; + + task->process_cb = cam_fd_mgr_workq_irq_cb; + rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0); + if (rc) + CAM_ERR(CAM_FD, "Failed in enqueue work task, rc=%d", rc); + + spin_unlock_irqrestore(&hw_mgr->hw_mgr_slock, flags); + + return rc; +} + +static int cam_fd_mgr_hw_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) +{ + int rc = 0; + struct cam_fd_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_get_caps_args; + struct cam_fd_query_cap_cmd query_fd; + void __user *caps_handle = + u64_to_user_ptr(query->caps_handle); + + if (copy_from_user(&query_fd, caps_handle, + sizeof(struct cam_fd_query_cap_cmd))) { + CAM_ERR(CAM_FD, "Failed in copy from user, rc=%d", rc); + return -EFAULT; + } + + query_fd = hw_mgr->fd_caps; + + CAM_DBG(CAM_FD, + "IOMMU device(%d, %d), CDM(%d, %d), versions %d.%d, %d.%d", + query_fd.device_iommu.secure, query_fd.device_iommu.non_secure, + query_fd.cdm_iommu.secure, query_fd.cdm_iommu.non_secure, + query_fd.hw_caps.core_version.major, + query_fd.hw_caps.core_version.minor, + query_fd.hw_caps.wrapper_version.major, + query_fd.hw_caps.wrapper_version.minor); + + if (copy_to_user(caps_handle, &query_fd, + sizeof(struct cam_fd_query_cap_cmd))) + rc = -EFAULT; + + return rc; +} + +static int cam_fd_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = + (struct cam_hw_acquire_args *)hw_acquire_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_acquire_dev_info fd_acquire_args; + int rc; + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_FD, "Invalid acquire args %pK", acquire_args); + return -EINVAL; + } + + if (copy_from_user(&fd_acquire_args, + (void __user *)acquire_args->acquire_info, + sizeof(struct cam_fd_acquire_dev_info))) { + CAM_ERR(CAM_FD, "Copy from user failed"); + return -EFAULT; + } + + CAM_DBG(CAM_FD, "Acquire : mode=%d, get_raw_results=%d, priority=%d", + fd_acquire_args.mode, fd_acquire_args.get_raw_results, + fd_acquire_args.priority); + + /* get a free fd hw mgr ctx */ + rc = cam_fd_mgr_util_get_ctx(&hw_mgr->free_ctx_list, &hw_ctx); + if (rc || !hw_ctx) { + CAM_ERR(CAM_FD, "Get hw context failed, rc=%d, hw_ctx=%pK", + rc, hw_ctx); + return -EINVAL; + } + + if (fd_acquire_args.get_raw_results && !hw_mgr->raw_results_available) { + CAM_ERR(CAM_FD, "HW cannot support raw results %d (%d)", + fd_acquire_args.get_raw_results, + hw_mgr->raw_results_available); + goto put_ctx; + } + + if (!(fd_acquire_args.mode & hw_mgr->supported_modes)) { + CAM_ERR(CAM_FD, "HW cannot support requested mode 0x%x (0x%x)", + fd_acquire_args.mode, hw_mgr->supported_modes); + rc = -EPERM; + goto put_ctx; + } + + rc = cam_fd_mgr_util_select_device(hw_mgr, hw_ctx, &fd_acquire_args); + if (rc) { + CAM_ERR(CAM_FD, "Failed in selecting device, rc=%d", rc); + goto put_ctx; + } + + hw_ctx->ctx_in_use = true; + hw_ctx->hw_mgr = hw_mgr; + hw_ctx->get_raw_results = fd_acquire_args.get_raw_results; + hw_ctx->mode = fd_acquire_args.mode; + + /* Save incoming cam core info into hw ctx*/ + hw_ctx->cb_priv = acquire_args->context_data; + hw_ctx->event_cb = acquire_args->event_cb; + + /* Update out args */ + acquire_args->ctxt_to_hw_map = hw_ctx; + + cam_fd_mgr_util_put_ctx(&hw_mgr->used_ctx_list, &hw_ctx); + + return 0; +put_ctx: + list_del_init(&hw_ctx->list); + cam_fd_mgr_util_put_ctx(&hw_mgr->free_ctx_list, &hw_ctx); + return rc; +} + +static int cam_fd_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_release_args *release_args = hw_release_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + int rc; + + if (!hw_mgr_priv || !hw_release_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK, %pK", + hw_mgr_priv, hw_release_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + rc = cam_fd_mgr_util_release_device(hw_mgr, hw_ctx); + if (rc) + CAM_ERR(CAM_FD, "Failed in release device, rc=%d", rc); + + hw_ctx->ctx_in_use = false; + list_del_init(&hw_ctx->list); + cam_fd_mgr_util_put_ctx(&hw_mgr->free_ctx_list, &hw_ctx); + + return 0; +} + +static int cam_fd_mgr_hw_start(void *hw_mgr_priv, void *mgr_start_args) +{ + int rc = 0; + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_start_args *hw_mgr_start_args = + (struct cam_hw_start_args *)mgr_start_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_hw_init_args hw_init_args; + + if (!hw_mgr_priv || !hw_mgr_start_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", + hw_mgr_priv, hw_mgr_start_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)hw_mgr_start_args->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + CAM_DBG(CAM_FD, "ctx index=%u, device_index=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + if (hw_device->hw_intf->hw_ops.init) { + hw_init_args.hw_ctx = hw_ctx; + hw_init_args.ctx_hw_private = hw_ctx->ctx_hw_private; + rc = hw_device->hw_intf->hw_ops.init( + hw_device->hw_intf->hw_priv, &hw_init_args, + sizeof(hw_init_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW Init %d", rc); + return rc; + } + } else { + CAM_ERR(CAM_FD, "Invalid init function"); + return -EINVAL; + } + + return rc; +} + +static int cam_fd_mgr_hw_flush_req(void *hw_mgr_priv, + struct cam_hw_flush_args *flush_args) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *frame_req, *req_temp, *flush_req; + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_fd_device *hw_device; + struct cam_fd_hw_stop_args hw_stop_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + uint32_t i = 0; + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)flush_args->ctxt_to_hw_map; + + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + CAM_DBG(CAM_FD, "ctx index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_mgr->frame_req_mutex); + for (i = 0; i < flush_args->num_req_active; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_active[i]; + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_high, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + if (frame_req->request_id != flush_req->request_id) + continue; + + list_del_init(&frame_req->list); + break; + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_normal, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + if (frame_req->request_id != flush_req->request_id) + continue; + + list_del_init(&frame_req->list); + break; + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + if (frame_req->request_id != flush_req->request_id) + continue; + + list_del_init(&frame_req->list); + + mutex_lock(&hw_device->lock); + if ((hw_device->ready_to_process == true) || + (hw_device->cur_hw_ctx != hw_ctx)) + goto unlock_dev_flush_req; + + if (hw_device->hw_intf->hw_ops.stop) { + hw_stop_args.hw_ctx = hw_ctx; + rc = hw_device->hw_intf->hw_ops.stop( + hw_device->hw_intf->hw_priv, + &hw_stop_args, + sizeof(hw_stop_args)); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in HW Stop %d", rc); + goto unlock_dev_flush_req; + } + hw_device->ready_to_process = true; + } + +unlock_dev_flush_req: + mutex_unlock(&hw_device->lock); + break; + } + } + mutex_unlock(&hw_mgr->frame_req_mutex); + + for (i = 0; i < flush_args->num_req_pending; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_pending[i]; + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + return rc; +} + +static int cam_fd_mgr_hw_flush_ctx(void *hw_mgr_priv, + struct cam_hw_flush_args *flush_args) +{ + int rc = 0; + struct cam_fd_mgr_frame_request *frame_req, *req_temp, *flush_req; + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_fd_device *hw_device; + struct cam_fd_hw_stop_args hw_stop_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + uint32_t i = 0; + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)flush_args->ctxt_to_hw_map; + + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + CAM_DBG(CAM_FD, "ctx index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_mgr->frame_req_mutex); + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_high, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + list_del_init(&frame_req->list); + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_pending_list_normal, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + list_del_init(&frame_req->list); + } + + list_for_each_entry_safe(frame_req, req_temp, + &hw_mgr->frame_processing_list, list) { + if (frame_req->hw_ctx != hw_ctx) + continue; + + list_del_init(&frame_req->list); + mutex_lock(&hw_device->lock); + if ((hw_device->ready_to_process == true) || + (hw_device->cur_hw_ctx != hw_ctx)) + goto unlock_dev_flush_ctx; + + if (hw_device->hw_intf->hw_ops.stop) { + hw_stop_args.hw_ctx = hw_ctx; + rc = hw_device->hw_intf->hw_ops.stop( + hw_device->hw_intf->hw_priv, &hw_stop_args, + sizeof(hw_stop_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW Stop %d", rc); + goto unlock_dev_flush_ctx; + } + hw_device->ready_to_process = true; + } + +unlock_dev_flush_ctx: + mutex_unlock(&hw_device->lock); + } + mutex_unlock(&hw_mgr->frame_req_mutex); + + for (i = 0; i < flush_args->num_req_pending; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_pending[i]; + CAM_DBG(CAM_FD, "flush pending req %llu", + flush_req->request_id); + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + for (i = 0; i < flush_args->num_req_active; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_active[i]; + CAM_DBG(CAM_FD, "flush active req %llu", flush_req->request_id); + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + return rc; +} + +static int cam_fd_mgr_hw_flush(void *hw_mgr_priv, + void *hw_flush_args) +{ + int rc = 0; + struct cam_hw_flush_args *flush_args = + (struct cam_hw_flush_args *)hw_flush_args; + + if (!hw_mgr_priv || !hw_flush_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", + hw_mgr_priv, hw_flush_args); + return -EINVAL; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_REQ: + rc = cam_fd_mgr_hw_flush_req(hw_mgr_priv, flush_args); + break; + case CAM_FLUSH_TYPE_ALL: + rc = cam_fd_mgr_hw_flush_ctx(hw_mgr_priv, flush_args); + break; + default: + rc = -EINVAL; + CAM_ERR(CAM_FD, "Invalid flush type %d", + flush_args->flush_type); + break; + } + return rc; +} + +static int cam_fd_mgr_hw_stop(void *hw_mgr_priv, void *mgr_stop_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_stop_args *hw_mgr_stop_args = + (struct cam_hw_stop_args *)mgr_stop_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_hw_deinit_args hw_deinit_args; + int rc = 0; + + if (!hw_mgr_priv || !hw_mgr_stop_args) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", + hw_mgr_priv, hw_mgr_stop_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)hw_mgr_stop_args->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + CAM_DBG(CAM_FD, "ctx index=%u, hw_ctx=%d", hw_ctx->ctx_index, + hw_ctx->device_index); + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + return rc; + } + + CAM_DBG(CAM_FD, "FD Device ready_to_process = %d", + hw_device->ready_to_process); + + if (hw_device->hw_intf->hw_ops.deinit) { + hw_deinit_args.hw_ctx = hw_ctx; + hw_deinit_args.ctx_hw_private = hw_ctx->ctx_hw_private; + rc = hw_device->hw_intf->hw_ops.deinit( + hw_device->hw_intf->hw_priv, &hw_deinit_args, + sizeof(hw_deinit_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HW DeInit %d", rc); + return rc; + } + } + + return rc; +} + +static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv, + void *hw_prepare_update_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_prepare_update_args *prepare = + (struct cam_hw_prepare_update_args *) hw_prepare_update_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_device *hw_device; + struct cam_kmd_buf_info kmd_buf; + int rc; + struct cam_fd_hw_cmd_prestart_args prestart_args; + struct cam_fd_mgr_frame_request *frame_req; + + if (!hw_mgr_priv || !hw_prepare_update_args) { + CAM_ERR(CAM_FD, "Invalid args %pK %pK", + hw_mgr_priv, hw_prepare_update_args); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)prepare->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + rc = cam_fd_mgr_util_get_device(hw_mgr, hw_ctx, &hw_device); + if (rc) { + CAM_ERR(CAM_FD, "Error in getting device %d", rc); + goto error; + } + + rc = cam_fd_mgr_util_packet_validate(prepare->packet, + prepare->remain_len); + if (rc) { + CAM_ERR(CAM_FD, "Error in packet validation %d", rc); + goto error; + } + + rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf); + if (rc) { + CAM_ERR(CAM_FD, "Error in get kmd buf buffer %d", rc); + goto error; + } + + CAM_DBG(CAM_FD, + "KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d", + kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset, + kmd_buf.size, kmd_buf.used_bytes); + + /* We do not expect any patching, but just do it anyway */ + rc = cam_packet_util_process_patches(prepare->packet, + hw_mgr->device_iommu.non_secure, -1); + if (rc) { + CAM_ERR(CAM_FD, "Patch FD packet failed, rc=%d", rc); + return rc; + } + + memset(&prestart_args, 0x0, sizeof(prestart_args)); + prestart_args.ctx_hw_private = hw_ctx->ctx_hw_private; + prestart_args.hw_ctx = hw_ctx; + prestart_args.request_id = prepare->packet->header.request_id; + + rc = cam_fd_mgr_util_parse_generic_cmd_buffer(hw_ctx, prepare->packet, + &prestart_args); + if (rc) { + CAM_ERR(CAM_FD, "Error in parsing gerneric cmd buffer %d", rc); + goto error; + } + + rc = cam_fd_mgr_util_prepare_io_buf_info( + hw_mgr->device_iommu.non_secure, prepare, + prestart_args.input_buf, prestart_args.output_buf, + CAM_FD_MAX_IO_BUFFERS); + if (rc) { + CAM_ERR(CAM_FD, "Error in prepare IO Buf %d", rc); + goto error; + } + + rc = cam_fd_mgr_util_prepare_hw_update_entries(hw_mgr, prepare, + &prestart_args, &kmd_buf); + if (rc) { + CAM_ERR(CAM_FD, "Error in hw update entries %d", rc); + goto error; + } + + /* get a free frame req from free list */ + rc = cam_fd_mgr_util_get_frame_req(&hw_mgr->frame_free_list, + &frame_req); + if (rc || !frame_req) { + CAM_ERR(CAM_FD, "Get frame_req failed, rc=%d, hw_ctx=%pK", + rc, hw_ctx); + return -ENOMEM; + } + + /* Setup frame request info and queue to pending list */ + frame_req->hw_ctx = hw_ctx; + frame_req->request_id = prepare->packet->header.request_id; + /* This has to be passed to HW while calling hw_ops->start */ + frame_req->hw_req_private = prestart_args.hw_req_private; + + /* + * Save the current frame_req into priv, + * this will come as priv while hw_config + */ + prepare->priv = frame_req; + + CAM_DBG(CAM_FD, "FramePrepare : Frame[%lld]", frame_req->request_id); + + return 0; +error: + return rc; +} + +static int cam_fd_mgr_hw_config(void *hw_mgr_priv, void *hw_config_args) +{ + struct cam_fd_hw_mgr *hw_mgr = (struct cam_fd_hw_mgr *)hw_mgr_priv; + struct cam_hw_config_args *config = + (struct cam_hw_config_args *) hw_config_args; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_mgr_frame_request *frame_req; + int rc; + int i; + + if (!hw_mgr || !config) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK", hw_mgr, config); + return -EINVAL; + } + + if (!config->num_hw_update_entries) { + CAM_ERR(CAM_FD, "No hw update enteries are available"); + return -EINVAL; + } + + hw_ctx = (struct cam_fd_hw_mgr_ctx *)config->ctxt_to_hw_map; + if (!hw_ctx || !hw_ctx->ctx_in_use) { + CAM_ERR(CAM_FD, "Invalid context is used, hw_ctx=%pK", hw_ctx); + return -EPERM; + } + + frame_req = config->priv; + + trace_cam_apply_req("FD", frame_req->request_id); + CAM_DBG(CAM_FD, "FrameHWConfig : Frame[%lld]", frame_req->request_id); + + frame_req->num_hw_update_entries = config->num_hw_update_entries; + for (i = 0; i < config->num_hw_update_entries; i++) { + frame_req->hw_update_entries[i] = config->hw_update_entries[i]; + CAM_DBG(CAM_FD, "PreStart HWEntry[%d] : %d %d %d %d %pK", + frame_req->hw_update_entries[i].handle, + frame_req->hw_update_entries[i].offset, + frame_req->hw_update_entries[i].len, + frame_req->hw_update_entries[i].flags, + frame_req->hw_update_entries[i].addr); + } + + if (hw_ctx->priority == CAM_FD_PRIORITY_HIGH) { + CAM_DBG(CAM_FD, "Insert frame into prio0 queue"); + rc = cam_fd_mgr_util_put_frame_req( + &hw_mgr->frame_pending_list_high, &frame_req); + } else { + CAM_DBG(CAM_FD, "Insert frame into prio1 queue"); + rc = cam_fd_mgr_util_put_frame_req( + &hw_mgr->frame_pending_list_normal, &frame_req); + } + if (rc) { + CAM_ERR(CAM_FD, "Failed in queuing frame req, rc=%d", rc); + goto put_free_list; + } + + rc = cam_fd_mgr_util_schedule_frame_worker_task(hw_mgr); + if (rc) { + CAM_ERR(CAM_FD, "Worker task scheduling failed %d", rc); + goto remove_and_put_free_list; + } + + return 0; + +remove_and_put_free_list: + + if (hw_ctx->priority == CAM_FD_PRIORITY_HIGH) { + CAM_DBG(CAM_FD, "Removing frame into prio0 queue"); + cam_fd_mgr_util_get_frame_req( + &hw_mgr->frame_pending_list_high, &frame_req); + } else { + CAM_DBG(CAM_FD, "Removing frame into prio1 queue"); + cam_fd_mgr_util_get_frame_req( + &hw_mgr->frame_pending_list_normal, &frame_req); + } +put_free_list: + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req); + + return rc; +} + +int cam_fd_hw_mgr_deinit(struct device_node *of_node) +{ + CAM_DBG(CAM_FD, "HW Mgr Deinit"); + + cam_req_mgr_workq_destroy(&g_fd_hw_mgr.work); + + cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure); + g_fd_hw_mgr.device_iommu.non_secure = -1; + + mutex_destroy(&g_fd_hw_mgr.ctx_mutex); + mutex_destroy(&g_fd_hw_mgr.frame_req_mutex); + mutex_destroy(&g_fd_hw_mgr.hw_mgr_mutex); + + return 0; +} + +int cam_fd_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf) +{ + int count, i, rc = 0; + struct cam_hw_intf *hw_intf = NULL; + struct cam_fd_hw_mgr_ctx *hw_mgr_ctx; + struct cam_fd_device *hw_device; + struct cam_fd_mgr_frame_request *frame_req; + + if (!of_node || !hw_mgr_intf) { + CAM_ERR(CAM_FD, "Invalid args of_node %pK hw_mgr_intf %pK", + of_node, hw_mgr_intf); + return -EINVAL; + } + + memset(&g_fd_hw_mgr, 0x0, sizeof(g_fd_hw_mgr)); + memset(hw_mgr_intf, 0x0, sizeof(*hw_mgr_intf)); + + mutex_init(&g_fd_hw_mgr.ctx_mutex); + mutex_init(&g_fd_hw_mgr.frame_req_mutex); + mutex_init(&g_fd_hw_mgr.hw_mgr_mutex); + spin_lock_init(&g_fd_hw_mgr.hw_mgr_slock); + + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count || (count > CAM_FD_HW_MAX)) { + CAM_ERR(CAM_FD, "Invalid compat names in dev tree %d", count); + return -EINVAL; + } + g_fd_hw_mgr.num_devices = count; + + g_fd_hw_mgr.raw_results_available = false; + g_fd_hw_mgr.supported_modes = 0; + + for (i = 0; i < count; i++) { + hw_device = &g_fd_hw_mgr.hw_device[i]; + + rc = cam_fd_mgr_util_pdev_get_hw_intf(of_node, i, &hw_intf); + if (rc) { + CAM_ERR(CAM_FD, "hw intf from pdev failed, rc=%d", rc); + return rc; + } + + mutex_init(&hw_device->lock); + + hw_device->valid = true; + hw_device->hw_intf = hw_intf; + hw_device->ready_to_process = true; + + if (hw_device->hw_intf->hw_ops.process_cmd) { + struct cam_fd_hw_cmd_set_irq_cb irq_cb_args; + + irq_cb_args.cam_fd_hw_mgr_cb = cam_fd_mgr_irq_cb; + irq_cb_args.data = hw_device; + + rc = hw_device->hw_intf->hw_ops.process_cmd( + hw_device->hw_intf->hw_priv, + CAM_FD_HW_CMD_REGISTER_CALLBACK, + &irq_cb_args, sizeof(irq_cb_args)); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in REGISTER_CALLBACK %d", rc); + return rc; + } + } + + if (hw_device->hw_intf->hw_ops.get_hw_caps) { + rc = hw_device->hw_intf->hw_ops.get_hw_caps( + hw_intf->hw_priv, &hw_device->hw_caps, + sizeof(hw_device->hw_caps)); + if (rc) { + CAM_ERR(CAM_FD, "Failed in get_hw_caps %d", rc); + return rc; + } + + g_fd_hw_mgr.raw_results_available |= + hw_device->hw_caps.raw_results_available; + g_fd_hw_mgr.supported_modes |= + hw_device->hw_caps.supported_modes; + + CAM_DBG(CAM_FD, + "Device[mode=%d, raw=%d], Mgr[mode=%d, raw=%d]", + hw_device->hw_caps.supported_modes, + hw_device->hw_caps.raw_results_available, + g_fd_hw_mgr.supported_modes, + g_fd_hw_mgr.raw_results_available); + } + } + + INIT_LIST_HEAD(&g_fd_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_fd_hw_mgr.used_ctx_list); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_free_list); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_pending_list_high); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_pending_list_normal); + INIT_LIST_HEAD(&g_fd_hw_mgr.frame_processing_list); + + g_fd_hw_mgr.device_iommu.non_secure = -1; + g_fd_hw_mgr.device_iommu.secure = -1; + g_fd_hw_mgr.cdm_iommu.non_secure = -1; + g_fd_hw_mgr.cdm_iommu.secure = -1; + + rc = cam_smmu_get_handle("fd", + &g_fd_hw_mgr.device_iommu.non_secure); + if (rc) { + CAM_ERR(CAM_FD, "Get iommu handle failed, rc=%d", rc); + goto destroy_mutex; + } + + rc = cam_cdm_get_iommu_handle("fd", &g_fd_hw_mgr.cdm_iommu); + if (rc) + CAM_DBG(CAM_FD, "Failed to acquire the CDM iommu handles"); + + CAM_DBG(CAM_FD, "iommu handles : device(%d, %d), cdm(%d, %d)", + g_fd_hw_mgr.device_iommu.non_secure, + g_fd_hw_mgr.device_iommu.secure, + g_fd_hw_mgr.cdm_iommu.non_secure, + g_fd_hw_mgr.cdm_iommu.secure); + + /* Init hw mgr contexts and add to free list */ + for (i = 0; i < CAM_CTX_MAX; i++) { + hw_mgr_ctx = &g_fd_hw_mgr.ctx_pool[i]; + + memset(hw_mgr_ctx, 0x0, sizeof(*hw_mgr_ctx)); + INIT_LIST_HEAD(&hw_mgr_ctx->list); + + hw_mgr_ctx->ctx_index = i; + hw_mgr_ctx->device_index = -1; + hw_mgr_ctx->hw_mgr = &g_fd_hw_mgr; + + list_add_tail(&hw_mgr_ctx->list, &g_fd_hw_mgr.free_ctx_list); + } + + /* Init hw mgr frame requests and add to free list */ + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + frame_req = &g_fd_hw_mgr.frame_req[i]; + + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->list); + + list_add_tail(&frame_req->list, &g_fd_hw_mgr.frame_free_list); + } + + rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK, + &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc); + goto detach_smmu; + } + + for (i = 0; i < CAM_FD_WORKQ_NUM_TASK; i++) + g_fd_hw_mgr.work->task.pool[i].payload = + &g_fd_hw_mgr.work_data[i]; + + /* Setup hw cap so that we can just return the info when requested */ + memset(&g_fd_hw_mgr.fd_caps, 0, sizeof(g_fd_hw_mgr.fd_caps)); + g_fd_hw_mgr.fd_caps.device_iommu = g_fd_hw_mgr.device_iommu; + g_fd_hw_mgr.fd_caps.cdm_iommu = g_fd_hw_mgr.cdm_iommu; + g_fd_hw_mgr.fd_caps.hw_caps = g_fd_hw_mgr.hw_device[0].hw_caps; + + CAM_DBG(CAM_FD, + "IOMMU device(%d, %d), CDM(%d, %d) versions core[%d.%d], wrapper[%d.%d]", + g_fd_hw_mgr.fd_caps.device_iommu.secure, + g_fd_hw_mgr.fd_caps.device_iommu.non_secure, + g_fd_hw_mgr.fd_caps.cdm_iommu.secure, + g_fd_hw_mgr.fd_caps.cdm_iommu.non_secure, + g_fd_hw_mgr.fd_caps.hw_caps.core_version.major, + g_fd_hw_mgr.fd_caps.hw_caps.core_version.minor, + g_fd_hw_mgr.fd_caps.hw_caps.wrapper_version.major, + g_fd_hw_mgr.fd_caps.hw_caps.wrapper_version.minor); + + hw_mgr_intf->hw_mgr_priv = &g_fd_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_fd_mgr_hw_get_caps; + hw_mgr_intf->hw_acquire = cam_fd_mgr_hw_acquire; + hw_mgr_intf->hw_release = cam_fd_mgr_hw_release; + hw_mgr_intf->hw_start = cam_fd_mgr_hw_start; + hw_mgr_intf->hw_stop = cam_fd_mgr_hw_stop; + hw_mgr_intf->hw_prepare_update = cam_fd_mgr_hw_prepare_update; + hw_mgr_intf->hw_config = cam_fd_mgr_hw_config; + hw_mgr_intf->hw_read = NULL; + hw_mgr_intf->hw_write = NULL; + hw_mgr_intf->hw_close = NULL; + hw_mgr_intf->hw_flush = cam_fd_mgr_hw_flush; + + return rc; + +detach_smmu: + cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure); + g_fd_hw_mgr.device_iommu.non_secure = -1; +destroy_mutex: + mutex_destroy(&g_fd_hw_mgr.ctx_mutex); + mutex_destroy(&g_fd_hw_mgr.frame_req_mutex); + mutex_destroy(&g_fd_hw_mgr.hw_mgr_mutex); + + return rc; +} diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..49bc5bbc1b078632194d617d0a7956a7c4ee17fb --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_MGR_H_ +#define _CAM_FD_HW_MGR_H_ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <media/cam_fd.h> +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_fd_hw_intf.h" + +#define CAM_FD_HW_MAX 1 +#define CAM_FD_WORKQ_NUM_TASK 10 + +struct cam_fd_hw_mgr; + +/** + * enum cam_fd_mgr_work_type - Type of worker task + * + * @CAM_FD_WORK_FRAME : Work type indicating frame task + * @CAM_FD_WORK_IRQ : Work type indicating irq task + */ +enum cam_fd_mgr_work_type { + CAM_FD_WORK_FRAME, + CAM_FD_WORK_IRQ, +}; + +/** + * struct cam_fd_hw_mgr_ctx : FD HW Mgr context + * + * @list : List pointer used to maintain this context + * in free, used list + * @ctx_index : Index of this context + * @ctx_in_use : Whether this context is in use + * @event_cb : Event callback pointer to notify cam core context + * @cb_priv : Event callback private pointer + * @hw_mgr : Pointer to hw manager + * @get_raw_results : Whether this context needs raw results + * @mode : Mode in which this context runs + * @device_index : HW Device used by this context + * @ctx_hw_private : HW layer's private context pointer for this context + * @priority : Priority of this context + */ +struct cam_fd_hw_mgr_ctx { + struct list_head list; + uint32_t ctx_index; + bool ctx_in_use; + cam_hw_event_cb_func event_cb; + void *cb_priv; + struct cam_fd_hw_mgr *hw_mgr; + bool get_raw_results; + enum cam_fd_hw_mode mode; + int32_t device_index; + void *ctx_hw_private; + uint32_t priority; +}; + +/** + * struct cam_fd_device : FD HW Device + * + * @hw_caps : This FD device's capabilities + * @hw_intf : FD device's interface information + * @ready_to_process : Whether this device is ready to process next frame + * @num_ctxts : Number of context currently running on this device + * @valid : Whether this device is valid + * @lock : Lock used for protectin + * @cur_hw_ctx : current hw context running in the device + * @req_id : current processing req id + */ +struct cam_fd_device { + struct cam_fd_hw_caps hw_caps; + struct cam_hw_intf *hw_intf; + bool ready_to_process; + uint32_t num_ctxts; + bool valid; + struct mutex lock; + struct cam_fd_hw_mgr_ctx *cur_hw_ctx; + int64_t req_id; +}; + +/** + * struct cam_fd_mgr_frame_request : Frame request information maintained + * in HW Mgr layer + * + * @list : List pointer used to maintain this request in + * free, pending, processing request lists + * @request_id : Request ID corresponding to this request + * @hw_ctx : HW context from which this request is coming + * @hw_req_private : HW layer's private information specific to + * this request + * @hw_update_entries : HW update entries corresponding to this request + * which needs to be submitted to HW through CDM + * @num_hw_update_entries : Number of HW update entries + */ +struct cam_fd_mgr_frame_request { + struct list_head list; + uint64_t request_id; + struct cam_fd_hw_mgr_ctx *hw_ctx; + struct cam_fd_hw_req_private hw_req_private; + struct cam_hw_update_entry hw_update_entries[CAM_FD_MAX_HW_ENTRIES]; + uint32_t num_hw_update_entries; +}; + +/** + * struct cam_fd_mgr_work_data : HW Mgr work data information + * + * @type : Type of work + * @irq_type : IRQ type when this work is queued because of irq callback + */ +struct cam_fd_mgr_work_data { + enum cam_fd_mgr_work_type type; + enum cam_fd_hw_irq_type irq_type; +}; + +/** + * struct cam_fd_hw_mgr : FD HW Mgr information + * + * @free_ctx_list : List of free contexts available for acquire + * @used_ctx_list : List of contexts that are acquired + * @frame_free_list : List of free frame requests available + * @frame_pending_list_high : List of high priority frame requests pending + * for processing + * @frame_pending_list_normal : List of normal priority frame requests pending + * for processing + * @frame_processing_list : List of frame requests currently being + * processed currently. Generally maximum one + * request would be present in this list + * @hw_mgr_mutex : Mutex to protect hw mgr data when accessed + * from multiple threads + * @hw_mgr_slock : Spin lock to protect hw mgr data when accessed + * from multiple threads + * @ctx_mutex : Mutex to protect context list + * @frame_req_mutex : Mutex to protect frame request list + * @device_iommu : Device IOMMU information + * @cdm_iommu : CDM IOMMU information + * @hw_device : Underlying HW device information + * @num_devices : Number of HW devices available + * @raw_results_available : Whether raw results available in this driver + * @supported_modes : Supported modes by this driver + * @ctx_pool : List of context + * @frame_req : List of frame requests + * @work : Worker handle + * @work_data : Worker data + * @fd_caps : FD driver capabilities + */ +struct cam_fd_hw_mgr { + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct list_head frame_free_list; + struct list_head frame_pending_list_high; + struct list_head frame_pending_list_normal; + struct list_head frame_processing_list; + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_slock; + struct mutex ctx_mutex; + struct mutex frame_req_mutex; + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_fd_device hw_device[CAM_FD_HW_MAX]; + uint32_t num_devices; + bool raw_results_available; + uint32_t supported_modes; + struct cam_fd_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + struct cam_fd_mgr_frame_request frame_req[CAM_CTX_REQ_MAX]; + struct cam_req_mgr_core_workq *work; + struct cam_fd_mgr_work_data work_data[CAM_FD_WORKQ_NUM_TASK]; + struct cam_fd_query_cap_cmd fd_caps; +}; + +#endif /* _CAM_FD_HW_MGR_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..81ed464e400a7cafb6788cf6c899df2a2bd287c7 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_MGR_INTF_H_ +#define _CAM_FD_HW_MGR_INTF_H_ + +#include <linux/of.h> + +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" + +int cam_fd_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr_intf); +int cam_fd_hw_mgr_deinit(struct device_node *of_node); + +#endif /* _CAM_FD_HW_MGR_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6a53cc67f7e649ae171a3b301924359e890dfac6 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -I$(srctree)/techpack/camera +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_dev.o cam_fd_hw_core.o cam_fd_hw_soc.o diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c new file mode 100644 index 0000000000000000000000000000000000000000..c28fcdf3efc6c7a3d13f831694bf1116fb617a63 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -0,0 +1,1164 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" +#include "cam_trace.h" + +#define CAM_FD_REG_VAL_PAIR_SIZE 256 + +static uint32_t cam_fd_cdm_write_reg_val_pair(uint32_t *buffer, + uint32_t index, uint32_t reg_offset, uint32_t reg_value) +{ + buffer[index++] = reg_offset; + buffer[index++] = reg_value; + + CAM_DBG(CAM_FD, "FD_CDM_CMD: Base[FD_CORE] Offset[0x%8x] Value[0x%8x]", + reg_offset, reg_value); + + return index; +} + +static void cam_fd_hw_util_cdm_callback(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie) +{ + trace_cam_cdm_cb("FD", status); + CAM_DBG(CAM_FD, "CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); +} + +static void cam_fd_hw_util_enable_power_on_settings(struct cam_hw_info *fd_hw) +{ + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + struct cam_fd_hw_static_info *hw_static_info = + ((struct cam_fd_core *)fd_hw->core_info)->hw_static_info; + + if (hw_static_info->enable_errata_wa.single_irq_only == false) { + /* Enable IRQs here */ + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + hw_static_info->irq_mask); + } + + /* QoS settings */ + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.vbif_req_priority, + hw_static_info->qos_priority); + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.vbif_priority_level, + hw_static_info->qos_priority_level); +} + +int cam_fd_hw_util_get_hw_caps(struct cam_hw_info *fd_hw, + struct cam_fd_hw_caps *hw_caps) +{ + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + struct cam_fd_hw_static_info *hw_static_info = + ((struct cam_fd_core *)fd_hw->core_info)->hw_static_info; + uint32_t reg_value; + + if (!hw_static_info) { + CAM_ERR(CAM_FD, "Invalid hw info data"); + return -EINVAL; + } + + reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_CORE, + hw_static_info->core_regs.version); + hw_caps->core_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf00, 0x8); + hw_caps->core_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0, 0x4); + hw_caps->core_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xf, 0x0); + + reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.wrapper_version); + hw_caps->wrapper_version.major = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c); + hw_caps->wrapper_version.minor = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->wrapper_version.incr = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + hw_caps->raw_results_available = + hw_static_info->results.raw_results_available; + hw_caps->supported_modes = hw_static_info->supported_modes; + + CAM_DBG(CAM_FD, "core:%d.%d.%d wrapper:%d.%d.%d intermediate:%d", + hw_caps->core_version.major, hw_caps->core_version.minor, + hw_caps->core_version.incr, hw_caps->wrapper_version.major, + hw_caps->wrapper_version.minor, hw_caps->wrapper_version.incr, + hw_caps->raw_results_available); + + return 0; +} + +static int cam_fd_hw_util_fdwrapper_sync_reset(struct cam_hw_info *fd_hw) +{ + struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info; + struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info; + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + long time_left; + + /* Before triggering reset to HW, clear the reset complete */ + reinit_completion(&fd_core->reset_complete); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_CORE, + hw_static_info->core_regs.control, 0x1); + + if (hw_static_info->enable_errata_wa.single_irq_only) { + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE)); + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.sw_reset, 0x1); + + time_left = wait_for_completion_timeout(&fd_core->reset_complete, + msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT)); + if (time_left <= 0) + CAM_WARN(CAM_FD, "HW reset timeout time_left=%ld", time_left); + + CAM_DBG(CAM_FD, "FD Wrapper SW Sync Reset complete"); + + return 0; +} + + +static int cam_fd_hw_util_fdwrapper_halt(struct cam_hw_info *fd_hw) +{ + struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info; + struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info; + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + long time_left; + + /* Before triggering halt to HW, clear halt complete */ + reinit_completion(&fd_core->halt_complete); + + if (hw_static_info->enable_errata_wa.single_irq_only) { + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE)); + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.hw_stop, 0x1); + + time_left = wait_for_completion_timeout(&fd_core->halt_complete, + msecs_to_jiffies(CAM_FD_HW_HALT_RESET_TIMEOUT)); + if (time_left <= 0) + CAM_WARN(CAM_FD, "HW halt timeout time_left=%ld", time_left); + + CAM_DBG(CAM_FD, "FD Wrapper Halt complete"); + + return 0; +} + +static int cam_fd_hw_util_processcmd_prestart(struct cam_hw_info *fd_hw, + struct cam_fd_hw_cmd_prestart_args *prestart_args) +{ + struct cam_hw_soc_info *soc_info = &fd_hw->soc_info; + struct cam_fd_hw_static_info *hw_static_info = + ((struct cam_fd_core *)fd_hw->core_info)->hw_static_info; + struct cam_fd_ctx_hw_private *ctx_hw_private = + prestart_args->ctx_hw_private; + uint32_t size, size_required = 0; + uint32_t mem_base; + uint32_t *cmd_buf_addr = prestart_args->cmd_buf_addr; + uint32_t reg_val_pair[CAM_FD_REG_VAL_PAIR_SIZE]; + uint32_t num_cmds = 0; + int i; + struct cam_fd_hw_io_buffer *io_buf; + struct cam_fd_hw_req_private *req_private; + uint32_t available_size = prestart_args->size; + bool work_buffer_configured = false; + + if (!ctx_hw_private || !cmd_buf_addr) { + CAM_ERR(CAM_FD, "Invalid input prestart args %pK %pK", + ctx_hw_private, cmd_buf_addr); + return -EINVAL; + } + + if (prestart_args->get_raw_results && + !hw_static_info->results.raw_results_available) { + CAM_ERR(CAM_FD, "Raw results not supported %d %d", + prestart_args->get_raw_results, + hw_static_info->results.raw_results_available); + return -EINVAL; + } + + req_private = &prestart_args->hw_req_private; + req_private->ctx_hw_private = prestart_args->ctx_hw_private; + req_private->request_id = prestart_args->request_id; + req_private->get_raw_results = prestart_args->get_raw_results; + req_private->fd_results = NULL; + req_private->raw_results = NULL; + + /* Start preparing CDM register values that KMD has to insert */ + num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, num_cmds, + hw_static_info->core_regs.control, 0x1); + num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, num_cmds, + hw_static_info->core_regs.control, 0x0); + + for (i = 0; i < CAM_FD_MAX_IO_BUFFERS; i++) { + io_buf = &prestart_args->input_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_INPUT) { + CAM_ERR(CAM_FD, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + + switch (io_buf->io_cfg->resource_type) { + case CAM_FD_INPUT_PORT_ID_IMAGE: { + if ((num_cmds + 2) > CAM_FD_REG_VAL_PAIR_SIZE) { + CAM_ERR(CAM_FD, + "Invalid reg_val pair size %d, %d", + num_cmds, CAM_FD_REG_VAL_PAIR_SIZE); + return -EINVAL; + } + + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.image_addr, + io_buf->io_addr[0]); + break; + } + default: + CAM_ERR(CAM_FD, "Invalid resource type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + for (i = 0; i < CAM_FD_MAX_IO_BUFFERS; i++) { + io_buf = &prestart_args->output_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) { + CAM_ERR(CAM_FD, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + + switch (io_buf->io_cfg->resource_type) { + case CAM_FD_OUTPUT_PORT_ID_RESULTS: { + uint32_t face_results_offset; + + size_required = hw_static_info->results.max_faces * + hw_static_info->results.per_face_entries * 4; + + if (io_buf->io_cfg->planes[0].plane_stride < + size_required) { + CAM_ERR(CAM_FD, "Invalid results size %d %d", + io_buf->io_cfg->planes[0].plane_stride, + size_required); + return -EINVAL; + } + + req_private->fd_results = + (struct cam_fd_results *)io_buf->cpu_addr[0]; + + face_results_offset = + (uint8_t *)&req_private->fd_results->faces[0] - + (uint8_t *)req_private->fd_results; + + if (hw_static_info->ro_mode_supported) { + if ((num_cmds + 4) > CAM_FD_REG_VAL_PAIR_SIZE) { + CAM_ERR(CAM_FD, + "Invalid reg_val size %d, %d", + num_cmds, + CAM_FD_REG_VAL_PAIR_SIZE); + return -EINVAL; + } + /* + * Face data actually starts 16bytes later in + * the io buffer Check cam_fd_results. + */ + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.result_addr, + io_buf->io_addr[0] + + face_results_offset); + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.ro_mode, + 0x1); + + req_private->ro_mode_enabled = true; + } else { + req_private->ro_mode_enabled = false; + } + break; + } + case CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS: { + size_required = + hw_static_info->results.raw_results_entries * + sizeof(uint32_t); + + if (io_buf->io_cfg->planes[0].plane_stride < + size_required) { + CAM_ERR(CAM_FD, "Invalid results size %d %d", + io_buf->io_cfg->planes[0].plane_stride, + size_required); + return -EINVAL; + } + + req_private->raw_results = + (uint32_t *)io_buf->cpu_addr[0]; + break; + } + case CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER: { + if ((num_cmds + 2) > CAM_FD_REG_VAL_PAIR_SIZE) { + CAM_ERR(CAM_FD, + "Invalid reg_val pair size %d, %d", + num_cmds, CAM_FD_REG_VAL_PAIR_SIZE); + return -EINVAL; + } + + num_cmds = cam_fd_cdm_write_reg_val_pair( + reg_val_pair, num_cmds, + hw_static_info->core_regs.work_addr, + io_buf->io_addr[0]); + + work_buffer_configured = true; + break; + } + default: + CAM_ERR(CAM_FD, "Invalid resource type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + if (!req_private->fd_results || !work_buffer_configured) { + CAM_ERR(CAM_FD, "Invalid IO Buffers results=%pK work=%d", + req_private->fd_results, work_buffer_configured); + return -EINVAL; + } + + /* First insert CHANGE_BASE command */ + size = ctx_hw_private->cdm_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > available_size) { + CAM_ERR(CAM_FD, "buf size:%d is not sufficient, expected: %d", + prestart_args->size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, + ((struct cam_fd_soc_private *)soc_info->soc_private)-> + regbase_index[CAM_FD_REG_CORE]); + + ctx_hw_private->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base); + cmd_buf_addr += size; + available_size -= (size * 4); + + size = ctx_hw_private->cdm_ops->cdm_required_size_reg_random( + num_cmds/2); + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > available_size) { + CAM_ERR(CAM_FD, "Insufficient size:%d , expected size:%d", + available_size, size); + return -ENOMEM; + } + ctx_hw_private->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmds/2, + reg_val_pair); + cmd_buf_addr += size; + available_size -= (size * 4); + + /* Update pre_config_buf_size in bytes */ + prestart_args->pre_config_buf_size = + prestart_args->size - available_size; + + /* Insert start trigger command into CDM as post config commands. */ + num_cmds = cam_fd_cdm_write_reg_val_pair(reg_val_pair, 0, + hw_static_info->core_regs.control, 0x2); + size = ctx_hw_private->cdm_ops->cdm_required_size_reg_random( + num_cmds/2); + if ((size * 4) > available_size) { + CAM_ERR(CAM_FD, "Insufficient size:%d , expected size:%d", + available_size, size); + return -ENOMEM; + } + ctx_hw_private->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmds/2, + reg_val_pair); + cmd_buf_addr += size; + available_size -= (size * 4); + + prestart_args->post_config_buf_size = size * 4; + + CAM_DBG(CAM_FD, "PreConfig [%pK %d], PostConfig[%pK %d]", + prestart_args->cmd_buf_addr, prestart_args->pre_config_buf_size, + cmd_buf_addr, prestart_args->post_config_buf_size); + + for (i = 0; i < (prestart_args->pre_config_buf_size + + prestart_args->post_config_buf_size) / 4; i++) + CAM_DBG(CAM_FD, "CDM KMD Commands [%d] : [%pK] [0x%x]", i, + &prestart_args->cmd_buf_addr[i], + prestart_args->cmd_buf_addr[i]); + + return 0; +} + +static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, + struct cam_fd_hw_frame_done_args *frame_done_args) +{ + struct cam_fd_core *fd_core = (struct cam_fd_core *)fd_hw->core_info; + struct cam_fd_hw_static_info *hw_static_info = fd_core->hw_static_info; + struct cam_fd_hw_req_private *req_private; + uint32_t base, face_cnt; + uint32_t *buffer; + unsigned long flags; + int i; + + mutex_lock(&fd_hw->hw_mutex); + spin_lock_irqsave(&fd_core->spin_lock, flags); + if ((fd_core->core_state != CAM_FD_CORE_STATE_IDLE) || + (fd_core->results_valid == false) || + !fd_core->hw_req_private) { + CAM_ERR(CAM_FD, + "Invalid state for results state=%d, results=%d %pK", + fd_core->core_state, fd_core->results_valid, + fd_core->hw_req_private); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); + return -EINVAL; + } + fd_core->core_state = CAM_FD_CORE_STATE_READING_RESULTS; + req_private = fd_core->hw_req_private; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + /* + * Copy the register value as is into output buffers. + * Wehter we are copying the output data by reading registers or + * programming output buffer directly to HW must be transparent to UMD. + * In case HW supports writing face count value directly into + * DDR memory in future, these values should match. + */ + req_private->fd_results->face_count = + cam_fd_soc_register_read(&fd_hw->soc_info, CAM_FD_REG_CORE, + hw_static_info->core_regs.result_cnt); + + face_cnt = req_private->fd_results->face_count & 0x3F; + + if (face_cnt > hw_static_info->results.max_faces) { + CAM_WARN(CAM_FD, "Face count greater than max %d %d", + face_cnt, hw_static_info->results.max_faces); + face_cnt = hw_static_info->results.max_faces; + } + + CAM_DBG(CAM_FD, "ReqID[%lld] Faces Detected = %d", + req_private->request_id, face_cnt); + + /* + * We need to read the face data information from registers only + * if one of below is true + * 1. RO mode is not set. i.e FD HW doesn't write face data into + * DDR memory + * 2. On the current chipset, results written into DDR memory by FD HW + * are not gauranteed to be correct + */ + if (!req_private->ro_mode_enabled || + hw_static_info->enable_errata_wa.ro_mode_results_invalid) { + buffer = (uint32_t *)&req_private->fd_results->faces[0]; + base = hw_static_info->core_regs.results_reg_base; + + /* + * Write register values as is into face data buffer. Its UMD + * driver responsibility to interpret the data and extract face + * properties from output buffer. Think in case output buffer + * is directly programmed to HW, then KMD has no control to + * extract the face properties and UMD anyway has to extract + * face properties. So we follow the same approach and keep + * this transparent to UMD. + */ + for (i = 0; + i < (face_cnt * + hw_static_info->results.per_face_entries); i++) { + *buffer = cam_fd_soc_register_read(&fd_hw->soc_info, + CAM_FD_REG_CORE, base + (i * 0x4)); + CAM_DBG(CAM_FD, "FaceData[%d] : 0x%x", i / 4, *buffer); + buffer++; + } + } + + if (req_private->get_raw_results && + req_private->raw_results && + hw_static_info->results.raw_results_available) { + buffer = req_private->raw_results; + base = hw_static_info->core_regs.raw_results_reg_base; + + for (i = 0; + i < hw_static_info->results.raw_results_entries; + i++) { + *buffer = cam_fd_soc_register_read(&fd_hw->soc_info, + CAM_FD_REG_CORE, base + (i * 0x4)); + CAM_DBG(CAM_FD, "RawData[%d] : 0x%x", i, *buffer); + buffer++; + } + } + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->hw_req_private = NULL; + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); + + return 0; +} + +irqreturn_t cam_fd_hw_irq(int irq_num, void *data) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)data; + struct cam_fd_core *fd_core; + struct cam_hw_soc_info *soc_info; + struct cam_fd_hw_static_info *hw_static_info; + uint32_t reg_value; + enum cam_fd_hw_irq_type irq_type = CAM_FD_IRQ_FRAME_DONE; + uint32_t num_irqs = 0; + + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid data in IRQ callback"); + return IRQ_NONE; + } + + fd_core = (struct cam_fd_core *) fd_hw->core_info; + soc_info = &fd_hw->soc_info; + hw_static_info = fd_core->hw_static_info; + + reg_value = cam_fd_soc_register_read(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_status); + + CAM_DBG(CAM_FD, "FD IRQ status 0x%x", reg_value); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_clear, + reg_value); + + if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE)) { + complete_all(&fd_core->halt_complete); + irq_type = CAM_FD_IRQ_HALT_DONE; + num_irqs++; + } + + if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE)) { + complete_all(&fd_core->reset_complete); + irq_type = CAM_FD_IRQ_RESET_DONE; + num_irqs++; + } + + if (reg_value & CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE)) { + complete_all(&fd_core->processing_complete); + irq_type = CAM_FD_IRQ_FRAME_DONE; + num_irqs++; + } + + /* + * We should never get an IRQ callback with no or more than one mask. + * Validate first to make sure nothing going wrong. + */ + if (num_irqs != 1) { + CAM_ERR(CAM_FD, + "Invalid number of IRQs, value=0x%x, num_irqs=%d", + reg_value, num_irqs); + return IRQ_NONE; + } + + trace_cam_irq_activated("FD", irq_type); + + if (irq_type == CAM_FD_IRQ_HALT_DONE) { + /* + * Do not send HALT IRQ callback to Hw Mgr, + * a reset would always follow + */ + return IRQ_HANDLED; + } + + spin_lock(&fd_core->spin_lock); + /* Do not change state to IDLE on HALT IRQ. Reset must follow halt */ + if ((irq_type == CAM_FD_IRQ_RESET_DONE) || + (irq_type == CAM_FD_IRQ_FRAME_DONE)) { + + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + if (irq_type == CAM_FD_IRQ_FRAME_DONE) + fd_core->results_valid = true; + + CAM_DBG(CAM_FD, "FD IRQ type %d, state=%d", + irq_type, fd_core->core_state); + } + spin_unlock(&fd_core->spin_lock); + + if (fd_core->irq_cb.cam_fd_hw_mgr_cb) + fd_core->irq_cb.cam_fd_hw_mgr_cb(fd_core->irq_cb.data, + irq_type); + + return IRQ_HANDLED; +} + +int cam_fd_hw_get_hw_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_caps *fd_hw_caps = + (struct cam_fd_hw_caps *)get_hw_cap_args; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_FD, "Invalid input pointers %pK %pK", + hw_priv, get_hw_cap_args); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + *fd_hw_caps = fd_core->hw_caps; + + CAM_DBG(CAM_FD, "core:%d.%d wrapper:%d.%d mode:%d, raw:%d", + fd_hw_caps->core_version.major, + fd_hw_caps->core_version.minor, + fd_hw_caps->wrapper_version.major, + fd_hw_caps->wrapper_version.minor, + fd_hw_caps->supported_modes, + fd_hw_caps->raw_results_available); + + return 0; +} + +int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_init_args *init_args = + (struct cam_fd_hw_init_args *)init_hw_args; + int rc = 0; + unsigned long flags; + + if (!fd_hw || !init_args) { + CAM_ERR(CAM_FD, "Invalid argument %pK %pK", fd_hw, init_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_init_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_init_args)); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + + mutex_lock(&fd_hw->hw_mutex); + CAM_DBG(CAM_FD, "FD HW Init ref count before %d", fd_hw->open_count); + + if (fd_hw->open_count > 0) { + rc = 0; + goto cdm_streamon; + } + + rc = cam_fd_soc_enable_resources(&fd_hw->soc_info); + if (rc) { + CAM_ERR(CAM_FD, "Enable SOC failed, rc=%d", rc); + goto unlock_return; + } + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_hw->hw_state = CAM_HW_STATE_POWER_UP; + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + rc = cam_fd_hw_reset(hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_FD, "Reset Failed, rc=%d", rc); + goto disable_soc; + } + + cam_fd_hw_util_enable_power_on_settings(fd_hw); + +cdm_streamon: + fd_hw->open_count++; + CAM_DBG(CAM_FD, "FD HW Init ref count after %d", fd_hw->open_count); + + if (init_args->ctx_hw_private) { + struct cam_fd_ctx_hw_private *ctx_hw_private = + init_args->ctx_hw_private; + + rc = cam_cdm_stream_on(ctx_hw_private->cdm_handle); + if (rc) { + CAM_ERR(CAM_FD, "CDM StreamOn fail :handle=0x%x, rc=%d", + ctx_hw_private->cdm_handle, rc); + fd_hw->open_count--; + if (!fd_hw->open_count) + goto disable_soc; + } + } + + mutex_unlock(&fd_hw->hw_mutex); + + return rc; + +disable_soc: + if (cam_fd_soc_disable_resources(&fd_hw->soc_info)) + CAM_ERR(CAM_FD, "Error in disable soc resources"); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + fd_core->core_state = CAM_FD_CORE_STATE_POWERDOWN; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); +unlock_return: + mutex_unlock(&fd_hw->hw_mutex); + return rc; +} + +int cam_fd_hw_deinit(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = hw_priv; + struct cam_fd_core *fd_core = NULL; + struct cam_fd_hw_deinit_args *deinit_args = + (struct cam_fd_hw_deinit_args *)deinit_hw_args; + int rc = 0; + unsigned long flags; + + if (!fd_hw || !deinit_hw_args) { + CAM_ERR(CAM_FD, "Invalid argument"); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_deinit_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_deinit_args)); + return -EINVAL; + } + + mutex_lock(&fd_hw->hw_mutex); + if (fd_hw->open_count == 0) { + mutex_unlock(&fd_hw->hw_mutex); + CAM_ERR(CAM_FD, "Error Unbalanced deinit"); + return -EFAULT; + } + + fd_hw->open_count--; + CAM_DBG(CAM_FD, "FD HW ref count=%d", fd_hw->open_count); + + if (fd_hw->open_count > 0) { + rc = 0; + goto positive_ref_cnt; + } + + rc = cam_fd_soc_disable_resources(&fd_hw->soc_info); + if (rc) + CAM_ERR(CAM_FD, "Failed in Disable SOC, rc=%d", rc); + + fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + fd_core = (struct cam_fd_core *)fd_hw->core_info; + + /* With the ref_cnt correct, this should never happen */ + WARN_ON(!fd_core); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_POWERDOWN; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); +positive_ref_cnt: + if (deinit_args->ctx_hw_private) { + struct cam_fd_ctx_hw_private *ctx_hw_private = + deinit_args->ctx_hw_private; + + rc = cam_cdm_stream_off(ctx_hw_private->cdm_handle); + if (rc) { + CAM_ERR(CAM_FD, + "Failed in CDM StreamOff, handle=0x%x, rc=%d", + ctx_hw_private->cdm_handle, rc); + } + } + + mutex_unlock(&fd_hw->hw_mutex); + return rc; +} + +int cam_fd_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_static_info *hw_static_info; + struct cam_hw_soc_info *soc_info; + unsigned long flags; + int rc; + + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid input handle"); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + hw_static_info = fd_core->hw_static_info; + soc_info = &fd_hw->soc_info; + + spin_lock_irqsave(&fd_core->spin_lock, flags); + if ((fd_core->core_state == CAM_FD_CORE_STATE_POWERDOWN) || + (fd_core->core_state == CAM_FD_CORE_STATE_RESET_PROGRESS)) { + CAM_ERR(CAM_FD, "Reset not allowed in %d state", + fd_core->core_state); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + return -EINVAL; + } + + fd_core->results_valid = false; + fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x1); + + rc = cam_fd_hw_util_fdwrapper_halt(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HALT rc=%d", rc); + return rc; + } + + rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc); + return rc; + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x0); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + return rc; +} + +int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_static_info *hw_static_info; + struct cam_fd_hw_cmd_start_args *start_args = + (struct cam_fd_hw_cmd_start_args *)hw_start_args; + struct cam_fd_ctx_hw_private *ctx_hw_private; + unsigned long flags; + int rc; + + if (!hw_priv || !start_args) { + CAM_ERR(CAM_FD, "Invalid input args %pK %pK", hw_priv, + start_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_cmd_start_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_cmd_start_args)); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + hw_static_info = fd_core->hw_static_info; + + spin_lock_irqsave(&fd_core->spin_lock, flags); + if (fd_core->core_state != CAM_FD_CORE_STATE_IDLE) { + CAM_ERR(CAM_FD, "Cannot start in %d state", + fd_core->core_state); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + return -EINVAL; + } + + /* + * We are about to start FD HW processing, save the request + * private data which is being processed by HW. Once the frame + * processing is finished, process_cmd(FRAME_DONE) should be called + * with same hw_req_private as input. + */ + fd_core->hw_req_private = start_args->hw_req_private; + fd_core->core_state = CAM_FD_CORE_STATE_PROCESSING; + fd_core->results_valid = false; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + ctx_hw_private = start_args->ctx_hw_private; + + /* Before starting HW process, clear processing complete */ + reinit_completion(&fd_core->processing_complete); + + if (hw_static_info->enable_errata_wa.single_irq_only) { + cam_fd_soc_register_write(&fd_hw->soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_mask, + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE)); + } + + if (start_args->num_hw_update_entries > 0) { + struct cam_cdm_bl_request *cdm_cmd = ctx_hw_private->cdm_cmd; + struct cam_hw_update_entry *cmd; + int i; + + cdm_cmd->cmd_arrary_count = start_args->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + + for (i = 0 ; i <= start_args->num_hw_update_entries; i++) { + cmd = (start_args->hw_update_entries + i); + cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i].offset = cmd->offset; + cdm_cmd->cmd[i].len = cmd->len; + } + + rc = cam_cdm_submit_bls(ctx_hw_private->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_FD, + "Failed to submit cdm commands, rc=%d", rc); + goto error; + } + } else { + CAM_ERR(CAM_FD, "Invalid number of hw update entries"); + rc = -EINVAL; + goto error; + } + + return 0; +error: + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + return rc; +} + +int cam_fd_hw_halt_reset(void *hw_priv, void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + struct cam_fd_core *fd_core; + struct cam_fd_hw_static_info *hw_static_info; + struct cam_hw_soc_info *soc_info; + unsigned long flags; + int rc; + + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid input handle"); + return -EINVAL; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + hw_static_info = fd_core->hw_static_info; + soc_info = &fd_hw->soc_info; + + spin_lock_irqsave(&fd_core->spin_lock, flags); + if ((fd_core->core_state == CAM_FD_CORE_STATE_POWERDOWN) || + (fd_core->core_state == CAM_FD_CORE_STATE_RESET_PROGRESS)) { + CAM_ERR(CAM_FD, "Reset not allowed in %d state", + fd_core->core_state); + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + return -EINVAL; + } + + fd_core->results_valid = false; + fd_core->core_state = CAM_FD_CORE_STATE_RESET_PROGRESS; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x1); + + rc = cam_fd_hw_util_fdwrapper_halt(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in HALT rc=%d", rc); + return rc; + } + + /* HALT must be followed by RESET */ + rc = cam_fd_hw_util_fdwrapper_sync_reset(fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed in RESET rc=%d", rc); + return rc; + } + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.cgc_disable, 0x0); + + spin_lock_irqsave(&fd_core->spin_lock, flags); + fd_core->core_state = CAM_FD_CORE_STATE_IDLE; + spin_unlock_irqrestore(&fd_core->spin_lock, flags); + + return rc; +} + +int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + int rc = -EINVAL; + struct cam_fd_ctx_hw_private *ctx_hw_private; + struct cam_fd_hw_reserve_args *reserve_args = + (struct cam_fd_hw_reserve_args *)hw_reserve_args; + struct cam_cdm_acquire_data cdm_acquire; + struct cam_cdm_bl_request *cdm_cmd; + int i; + + if (!fd_hw || !reserve_args) { + CAM_ERR(CAM_FD, "Invalid input %pK, %pK", fd_hw, reserve_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_reserve_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_reserve_args)); + return -EINVAL; + } + + cdm_cmd = kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_FD_MAX_HW_ENTRIES - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!cdm_cmd) + return -ENOMEM; + + ctx_hw_private = kzalloc(sizeof(struct cam_fd_ctx_hw_private), + GFP_KERNEL); + if (!ctx_hw_private) { + kfree(cdm_cmd); + return -ENOMEM; + } + + memset(&cdm_acquire, 0, sizeof(cdm_acquire)); + strlcpy(cdm_acquire.identifier, "fd", sizeof("fd")); + cdm_acquire.cell_index = fd_hw->soc_info.index; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ctx_hw_private; + cdm_acquire.cam_cdm_callback = cam_fd_hw_util_cdm_callback; + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.base_array_cnt = fd_hw->soc_info.num_reg_map; + for (i = 0; i < fd_hw->soc_info.num_reg_map; i++) + cdm_acquire.base_array[i] = &fd_hw->soc_info.reg_map[i]; + + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_FD, "Failed to acquire the CDM HW"); + goto error; + } + + ctx_hw_private->hw_ctx = reserve_args->hw_ctx; + ctx_hw_private->fd_hw = fd_hw; + ctx_hw_private->mode = reserve_args->mode; + ctx_hw_private->cdm_handle = cdm_acquire.handle; + ctx_hw_private->cdm_ops = cdm_acquire.ops; + ctx_hw_private->cdm_cmd = cdm_cmd; + + reserve_args->ctx_hw_private = ctx_hw_private; + + CAM_DBG(CAM_FD, "private=%pK, hw_ctx=%pK, mode=%d, cdm_handle=0x%x", + ctx_hw_private, ctx_hw_private->hw_ctx, ctx_hw_private->mode, + ctx_hw_private->cdm_handle); + + return 0; +error: + kfree(ctx_hw_private); + kfree(cdm_cmd); + return rc; +} + +int cam_fd_hw_release(void *hw_priv, void *hw_release_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + int rc = -EINVAL; + struct cam_fd_ctx_hw_private *ctx_hw_private; + struct cam_fd_hw_release_args *release_args = + (struct cam_fd_hw_release_args *)hw_release_args; + + if (!fd_hw || !release_args) { + CAM_ERR(CAM_FD, "Invalid input %pK, %pK", fd_hw, release_args); + return -EINVAL; + } + + if (arg_size != sizeof(struct cam_fd_hw_release_args)) { + CAM_ERR(CAM_FD, "Invalid arg size %u, %zu", arg_size, + sizeof(struct cam_fd_hw_release_args)); + return -EINVAL; + } + + ctx_hw_private = + (struct cam_fd_ctx_hw_private *)release_args->ctx_hw_private; + + rc = cam_cdm_release(ctx_hw_private->cdm_handle); + if (rc) + CAM_ERR(CAM_FD, "Release cdm handle failed, handle=0x%x, rc=%d", + ctx_hw_private->cdm_handle, rc); + + kfree(ctx_hw_private->cdm_cmd); + kfree(ctx_hw_private); + release_args->ctx_hw_private = NULL; + + return 0; +} + +int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *fd_hw = (struct cam_hw_info *)hw_priv; + int rc = -EINVAL; + + if (!hw_priv || !cmd_args || + (cmd_type >= CAM_FD_HW_CMD_MAX)) { + CAM_ERR(CAM_FD, "Invalid arguments %pK %pK %d", hw_priv, + cmd_args, cmd_type); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_FD_HW_CMD_REGISTER_CALLBACK: { + struct cam_fd_hw_cmd_set_irq_cb *irq_cb_args; + struct cam_fd_core *fd_core = + (struct cam_fd_core *)fd_hw->core_info; + + if (sizeof(struct cam_fd_hw_cmd_set_irq_cb) != arg_size) { + CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + irq_cb_args = (struct cam_fd_hw_cmd_set_irq_cb *)cmd_args; + fd_core->irq_cb.cam_fd_hw_mgr_cb = + irq_cb_args->cam_fd_hw_mgr_cb; + fd_core->irq_cb.data = irq_cb_args->data; + rc = 0; + break; + } + case CAM_FD_HW_CMD_PRESTART: { + struct cam_fd_hw_cmd_prestart_args *prestart_args; + + if (sizeof(struct cam_fd_hw_cmd_prestart_args) != arg_size) { + CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + prestart_args = (struct cam_fd_hw_cmd_prestart_args *)cmd_args; + rc = cam_fd_hw_util_processcmd_prestart(fd_hw, prestart_args); + break; + } + case CAM_FD_HW_CMD_FRAME_DONE: { + struct cam_fd_hw_frame_done_args *cmd_frame_results; + + if (sizeof(struct cam_fd_hw_frame_done_args) != + arg_size) { + CAM_ERR(CAM_FD, "cmd_type %d, size mismatch %d", + cmd_type, arg_size); + break; + } + + cmd_frame_results = + (struct cam_fd_hw_frame_done_args *)cmd_args; + rc = cam_fd_hw_util_processcmd_frame_done(fd_hw, + cmd_frame_results); + break; + } + default: + break; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h new file mode 100644 index 0000000000000000000000000000000000000000..1f8815e72f206470db75ba3c58789b66494d1769 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_CORE_H_ +#define _CAM_FD_HW_CORE_H_ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_defs.h> +#include <media/cam_fd.h> + +#include "cam_common_util.h" +#include "cam_debug_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_fd_hw_intf.h" +#include "cam_fd_hw_soc.h" + +#define CAM_FD_IRQ_TO_MASK(irq) (1 << (irq)) +#define CAM_FD_MASK_TO_IRQ(mask, irq) ((mask) >> (irq)) + +#define CAM_FD_HW_HALT_RESET_TIMEOUT 750 + +/** + * enum cam_fd_core_state - FD Core internal states + * + * @CAM_FD_CORE_STATE_POWERDOWN : Indicates FD core is powered down + * @CAM_FD_CORE_STATE_IDLE : Indicates FD HW is in idle state. + * Core can be in this state when it is + * ready to process frames or when + * processing is finished and results are + * available + * @CAM_FD_CORE_STATE_PROCESSING : Indicates FD core is processing frame + * @CAM_FD_CORE_STATE_READING_RESULTS : Indicates results are being read from + * FD core + * @CAM_FD_CORE_STATE_RESET_PROGRESS : Indicates FD Core is in reset state + */ +enum cam_fd_core_state { + CAM_FD_CORE_STATE_POWERDOWN, + CAM_FD_CORE_STATE_IDLE, + CAM_FD_CORE_STATE_PROCESSING, + CAM_FD_CORE_STATE_READING_RESULTS, + CAM_FD_CORE_STATE_RESET_PROGRESS, +}; + +/** + * struct cam_fd_ctx_hw_private : HW private information for a specific hw ctx. + * This information is populated by HW layer on + * reserve() and given back to HW Mgr as private + * data for the hw context. This private_data + * has to be passed by HW Mgr layer while + * further HW layer calls + * + * @hw_ctx : Corresponding hw_ctx pointer + * @fd_hw : FD HW info pointer + * @cdm_handle : CDM Handle for this context + * @cdm_ops : CDM Ops + * @cdm_cmd : CDM command pointer + * @mode : Mode this context is running + * @curr_req_private : Current Request information + * + */ +struct cam_fd_ctx_hw_private { + void *hw_ctx; + struct cam_hw_info *fd_hw; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; + enum cam_fd_hw_mode mode; + struct cam_fd_hw_req_private *curr_req_private; +}; + +/** + * struct cam_fd_core_regs : FD HW Core register offsets info + * + * @version : Offset of version register + * @control : Offset of control register + * @result_cnt : Offset of result count register + * @result_addr : Offset of results address register + * @image_addr : Offset of image address register + * @work_addr : Offset of work address register + * @ro_mode : Offset of ro_mode register + * @results_reg_base : Offset of results_reg_base register + * @raw_results_reg_base : Offset of raw_results_reg_base register + * + */ +struct cam_fd_core_regs { + uint32_t version; + uint32_t control; + uint32_t result_cnt; + uint32_t result_addr; + uint32_t image_addr; + uint32_t work_addr; + uint32_t ro_mode; + uint32_t results_reg_base; + uint32_t raw_results_reg_base; +}; + +/** + * struct cam_fd_core_regs : FD HW Wrapper register offsets info + * + * @wrapper_version : Offset of wrapper_version register + * @cgc_disable : Offset of cgc_disable register + * @hw_stop : Offset of hw_stop register + * @sw_reset : Offset of sw_reset register + * @vbif_req_priority : Offset of vbif_req_priority register + * @vbif_priority_level : Offset of vbif_priority_level register + * @vbif_done_status : Offset of vbif_done_status register + * @irq_mask : Offset of irq mask register + * @irq_status : Offset of irq status register + * @irq_clear : Offset of irq clear register + * + */ +struct cam_fd_wrapper_regs { + uint32_t wrapper_version; + uint32_t cgc_disable; + uint32_t hw_stop; + uint32_t sw_reset; + uint32_t vbif_req_priority; + uint32_t vbif_priority_level; + uint32_t vbif_done_status; + uint32_t irq_mask; + uint32_t irq_status; + uint32_t irq_clear; +}; + +/** + * struct cam_fd_hw_errata_wa : FD HW Errata workaround enable/dsiable info + * + * @single_irq_only : Whether to enable only one irq at any time + * @ro_mode_enable_always : Whether to enable ro mode always + * @ro_mode_results_invalid : Whether results written directly into output + * memory by HW are valid or not + */ +struct cam_fd_hw_errata_wa { + bool single_irq_only; + bool ro_mode_enable_always; + bool ro_mode_results_invalid; +}; + +/** + * struct cam_fd_hw_results_prop : FD HW Results properties + * + * @max_faces : Maximum number of faces supported + * @per_face_entries : Number of register with properties for each face + * @raw_results_entries : Number of raw results entries for the full search + * @raw_results_available : Whether raw results available on this HW + * + */ +struct cam_fd_hw_results_prop { + uint32_t max_faces; + uint32_t per_face_entries; + uint32_t raw_results_entries; + bool raw_results_available; +}; + +/** + * struct cam_fd_hw_static_info : FD HW information based on HW version + * + * @core_version : Core version of FD HW + * @wrapper_version : Wrapper version of FD HW + * @core_regs : Register offset information for core registers + * @wrapper_regs : Register offset information for wrapper registers + * @results : Information about results available on this HW + * @enable_errata_wa : Errata workaround information + * @irq_mask : IRQ mask to enable + * @qos_priority : QoS priority setting for this chipset + * @qos_priority_level : QoS priority level setting for this chipset + * @supported_modes : Supported HW modes on this HW version + * @ro_mode_supported : Whether RO mode is supported on this HW + * + */ +struct cam_fd_hw_static_info { + struct cam_hw_version core_version; + struct cam_hw_version wrapper_version; + struct cam_fd_core_regs core_regs; + struct cam_fd_wrapper_regs wrapper_regs; + struct cam_fd_hw_results_prop results; + struct cam_fd_hw_errata_wa enable_errata_wa; + uint32_t irq_mask; + uint32_t qos_priority; + uint32_t qos_priority_level; + uint32_t supported_modes; + bool ro_mode_supported; +}; + +/** + * struct cam_fd_core : FD HW core data structure + * + * @hw_static_info : HW information specific to version + * @hw_caps : HW capabilities + * @core_state : Current HW state + * @processing_complete : Whether processing is complete + * @reset_complete : Whether reset is complete + * @halt_complete : Whether halt is complete + * @hw_req_private : Request that is being currently processed by HW + * @results_valid : Whether HW frame results are available to get + * @spin_lock : Mutex to protect shared data in hw layer + * @irq_cb : HW Manager callback information + * + */ +struct cam_fd_core { + struct cam_fd_hw_static_info *hw_static_info; + struct cam_fd_hw_caps hw_caps; + enum cam_fd_core_state core_state; + struct completion processing_complete; + struct completion reset_complete; + struct completion halt_complete; + struct cam_fd_hw_req_private *hw_req_private; + bool results_valid; + spinlock_t spin_lock; + struct cam_fd_hw_cmd_set_irq_cb irq_cb; +}; + +int cam_fd_hw_util_get_hw_caps(struct cam_hw_info *fd_hw, + struct cam_fd_hw_caps *hw_caps); +irqreturn_t cam_fd_hw_irq(int irq_num, void *data); + +int cam_fd_hw_get_hw_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size); +int cam_fd_hw_init(void *hw_priv, void *init_hw_args, uint32_t arg_size); +int cam_fd_hw_deinit(void *hw_priv, void *deinit_hw_args, uint32_t arg_size); +int cam_fd_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size); +int cam_fd_hw_reserve(void *hw_priv, void *hw_reserve_args, uint32_t arg_size); +int cam_fd_hw_release(void *hw_priv, void *hw_release_args, uint32_t arg_size); +int cam_fd_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size); +int cam_fd_hw_halt_reset(void *hw_priv, void *stop_args, uint32_t arg_size); +int cam_fd_hw_read(void *hw_priv, void *read_args, uint32_t arg_size); +int cam_fd_hw_write(void *hw_priv, void *write_args, uint32_t arg_size); +int cam_fd_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +#endif /* _CAM_FD_HW_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..3498e6235279499eba2705784b07601cd23ec5e7 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_subdev.h" +#include "cam_fd_hw_intf.h" +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" +#include "cam_fd_hw_v41.h" +#include "cam_fd_hw_v501.h" +#include "cam_fd_hw_v600.h" + +static char fd_dev_name[8]; + +static int cam_fd_hw_dev_probe(struct platform_device *pdev) +{ + struct cam_hw_info *fd_hw; + struct cam_hw_intf *fd_hw_intf; + struct cam_fd_core *fd_core; + const struct of_device_id *match_dev = NULL; + struct cam_fd_hw_static_info *hw_static_info = NULL; + int rc = 0; + uint32_t hw_idx; + struct cam_fd_hw_init_args init_args; + struct cam_fd_hw_deinit_args deinit_args; + + fd_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!fd_hw_intf) + return -ENOMEM; + + fd_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!fd_hw) { + kfree(fd_hw_intf); + return -ENOMEM; + } + + fd_core = kzalloc(sizeof(struct cam_fd_core), GFP_KERNEL); + if (!fd_core) { + kfree(fd_hw); + kfree(fd_hw_intf); + return -ENOMEM; + } + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); + + fd_hw_intf->hw_priv = fd_hw; + fd_hw->core_info = fd_core; + fd_hw_intf->hw_idx = hw_idx; + + memset(fd_dev_name, 0, sizeof(fd_dev_name)); + snprintf(fd_dev_name, sizeof(fd_dev_name), + "fd%1u", fd_hw_intf->hw_idx); + + fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + fd_hw->soc_info.pdev = pdev; + fd_hw->soc_info.dev = &pdev->dev; + fd_hw->soc_info.dev_name = fd_dev_name; + fd_hw->open_count = 0; + mutex_init(&fd_hw->hw_mutex); + spin_lock_init(&fd_hw->hw_lock); + init_completion(&fd_hw->hw_complete); + + spin_lock_init(&fd_core->spin_lock); + init_completion(&fd_core->processing_complete); + init_completion(&fd_core->halt_complete); + init_completion(&fd_core->reset_complete); + + fd_hw_intf->hw_ops.get_hw_caps = cam_fd_hw_get_hw_caps; + fd_hw_intf->hw_ops.init = cam_fd_hw_init; + fd_hw_intf->hw_ops.deinit = cam_fd_hw_deinit; + fd_hw_intf->hw_ops.reset = cam_fd_hw_reset; + fd_hw_intf->hw_ops.reserve = cam_fd_hw_reserve; + fd_hw_intf->hw_ops.release = cam_fd_hw_release; + fd_hw_intf->hw_ops.start = cam_fd_hw_start; + fd_hw_intf->hw_ops.stop = cam_fd_hw_halt_reset; + fd_hw_intf->hw_ops.read = NULL; + fd_hw_intf->hw_ops.write = NULL; + fd_hw_intf->hw_ops.process_cmd = cam_fd_hw_process_cmd; + fd_hw_intf->hw_type = CAM_HW_FD; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev || !match_dev->data) { + CAM_ERR(CAM_FD, "No Of_match data, %pK", match_dev); + rc = -EINVAL; + goto free_memory; + } + hw_static_info = (struct cam_fd_hw_static_info *)match_dev->data; + fd_core->hw_static_info = hw_static_info; + + CAM_DBG(CAM_FD, "HW Static Info : version core[%d.%d] wrapper[%d.%d]", + hw_static_info->core_version.major, + hw_static_info->core_version.minor, + hw_static_info->wrapper_version.major, + hw_static_info->wrapper_version.minor); + + rc = cam_fd_soc_init_resources(&fd_hw->soc_info, cam_fd_hw_irq, fd_hw); + if (rc) { + CAM_ERR(CAM_FD, "Failed to init soc, rc=%d", rc); + goto free_memory; + } + + memset(&init_args, 0x0, sizeof(init_args)); + memset(&deinit_args, 0x0, sizeof(deinit_args)); + rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed to hw init, rc=%d", rc); + goto deinit_platform_res; + } + + rc = cam_fd_hw_util_get_hw_caps(fd_hw, &fd_core->hw_caps); + if (rc) { + CAM_ERR(CAM_FD, "Failed to get hw caps, rc=%d", rc); + goto deinit_hw; + } + + rc = cam_fd_hw_deinit(fd_hw, &deinit_args, sizeof(deinit_args)); + if (rc) { + CAM_ERR(CAM_FD, "Failed to deinit hw, rc=%d", rc); + goto deinit_platform_res; + } + + platform_set_drvdata(pdev, fd_hw_intf); + CAM_DBG(CAM_FD, "FD-%d probe successful", fd_hw_intf->hw_idx); + + return rc; + +deinit_hw: + if (cam_fd_hw_deinit(fd_hw, &deinit_args, sizeof(deinit_args))) + CAM_ERR(CAM_FD, "Failed in hw deinit"); +deinit_platform_res: + if (cam_fd_soc_deinit_resources(&fd_hw->soc_info)) + CAM_ERR(CAM_FD, "Failed in soc deinit"); + mutex_destroy(&fd_hw->hw_mutex); +free_memory: + kfree(fd_hw); + kfree(fd_hw_intf); + kfree(fd_core); + + return rc; +} + +static int cam_fd_hw_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + struct cam_hw_intf *fd_hw_intf; + struct cam_hw_info *fd_hw; + struct cam_fd_core *fd_core; + + fd_hw_intf = platform_get_drvdata(pdev); + if (!fd_hw_intf) { + CAM_ERR(CAM_FD, "Invalid fd_hw_intf from pdev"); + return -EINVAL; + } + + fd_hw = fd_hw_intf->hw_priv; + if (!fd_hw) { + CAM_ERR(CAM_FD, "Invalid fd_hw from fd_hw_intf"); + rc = -ENODEV; + goto free_fd_hw_intf; + } + + fd_core = (struct cam_fd_core *)fd_hw->core_info; + if (!fd_core) { + CAM_ERR(CAM_FD, "Invalid fd_core from fd_hw"); + rc = -EINVAL; + goto deinit_platform_res; + } + + kfree(fd_core); + +deinit_platform_res: + rc = cam_fd_soc_deinit_resources(&fd_hw->soc_info); + if (rc) + CAM_ERR(CAM_FD, "Error in FD soc deinit, rc=%d", rc); + + mutex_destroy(&fd_hw->hw_mutex); + kfree(fd_hw); + +free_fd_hw_intf: + kfree(fd_hw_intf); + + return rc; +} + +static const struct of_device_id cam_fd_hw_dt_match[] = { + { + .compatible = "qcom,fd41", + .data = &cam_fd_wrapper120_core410_info, + }, + { + .compatible = "qcom,fd501", + .data = &cam_fd_wrapper200_core501_info, + }, + { + .compatible = "qcom,fd600", + .data = &cam_fd_wrapper200_core600_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); + +static struct platform_driver cam_fd_hw_driver = { + .probe = cam_fd_hw_dev_probe, + .remove = cam_fd_hw_dev_remove, + .driver = { + .name = "cam_fd_hw", + .owner = THIS_MODULE, + .of_match_table = cam_fd_hw_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_fd_hw_init_module(void) +{ + return platform_driver_register(&cam_fd_hw_driver); +} + +static void __exit cam_fd_hw_exit_module(void) +{ + platform_driver_unregister(&cam_fd_hw_driver); +} + +module_init(cam_fd_hw_init_module); +module_exit(cam_fd_hw_exit_module); +MODULE_DESCRIPTION("CAM FD HW driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..e35e5e520b7b137323452b0c7affa480065d6f23 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -0,0 +1,282 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_INTF_H_ +#define _CAM_FD_HW_INTF_H_ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_cpas.h> +#include <media/cam_req_mgr.h> +#include <media/cam_fd.h> + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_subdev.h" +#include "cam_cpas_api.h" +#include "cam_hw_mgr_intf.h" +#include "cam_debug_util.h" + +#define CAM_FD_MAX_IO_BUFFERS 5 +#define CAM_FD_MAX_HW_ENTRIES 5 + +/** + * enum cam_fd_hw_type - Enum for FD HW type + * + * @CAM_HW_FD : FaceDetection HW type + */ +enum cam_fd_hw_type { + CAM_HW_FD, +}; + +/** + * enum cam_fd_hw_mode - Mode in which HW can run + * + * @CAM_FD_MODE_FACEDETECTION : Face Detection mode in which face search + * is done on the given frame + * @CAM_FD_MODE_PYRAMID : Pyramid mode where a pyramid image is generated + * from an input image + */ +enum cam_fd_hw_mode { + CAM_FD_MODE_FACEDETECTION = 0x1, + CAM_FD_MODE_PYRAMID = 0x2, +}; + +/** + * enum cam_fd_priority - FD priority levels + * + * @CAM_FD_PRIORITY_HIGH : Indicates high priority client, driver prioritizes + * frame requests coming from contexts with HIGH + * priority compared to context with normal priority + * @CAM_FD_PRIORITY_NORMAL : Indicates normal priority client + */ +enum cam_fd_priority { + CAM_FD_PRIORITY_HIGH = 0x0, + CAM_FD_PRIORITY_NORMAL, +}; + +/** + * enum cam_fd_hw_irq_type - FD HW IRQ types + * + * @CAM_FD_IRQ_FRAME_DONE : Indicates frame processing is finished + * @CAM_FD_IRQ_HALT_DONE : Indicates HW halt is finished + * @CAM_FD_IRQ_RESET_DONE : Indicates HW reset is finished + */ +enum cam_fd_hw_irq_type { + CAM_FD_IRQ_FRAME_DONE, + CAM_FD_IRQ_HALT_DONE, + CAM_FD_IRQ_RESET_DONE, +}; + +/** + * enum cam_fd_hw_cmd_type - FD HW layer custom commands + * + * @CAM_FD_HW_CMD_PRESTART : Command to process pre-start settings + * @CAM_FD_HW_CMD_FRAME_DONE : Command to process frame done settings + * @CAM_FD_HW_CMD_UPDATE_SOC : Command to process soc update + * @CAM_FD_HW_CMD_REGISTER_CALLBACK : Command to set hw mgr callback + * @CAM_FD_HW_CMD_MAX : Indicates max cmd + */ +enum cam_fd_hw_cmd_type { + CAM_FD_HW_CMD_PRESTART, + CAM_FD_HW_CMD_FRAME_DONE, + CAM_FD_HW_CMD_UPDATE_SOC, + CAM_FD_HW_CMD_REGISTER_CALLBACK, + CAM_FD_HW_CMD_MAX, +}; + +/** + * struct cam_fd_hw_io_buffer : FD HW IO Buffer information + * + * @valid : Whether this IO Buf configuration is valid + * @io_cfg : IO Configuration information + * @num_buf : Number planes in io_addr, cpu_addr array + * @io_addr : Array of IO address information for planes + * @cpu_addr : Array of CPU address information for planes + */ +struct cam_fd_hw_io_buffer { + bool valid; + struct cam_buf_io_cfg *io_cfg; + uint32_t num_buf; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + uintptr_t cpu_addr[CAM_PACKET_MAX_PLANES]; +}; + +/** + * struct cam_fd_hw_req_private : FD HW layer's private information + * specific to a request + * + * @ctx_hw_private : FD HW layer's ctx specific private data + * @request_id : Request ID corresponding to this private information + * @get_raw_results : Whether to get raw results for this request + * @ro_mode_enabled : Whether RO mode is enabled for this request + * @fd_results : Pointer to save face detection results + * @raw_results : Pointer to save face detection raw results + */ +struct cam_fd_hw_req_private { + void *ctx_hw_private; + uint64_t request_id; + bool get_raw_results; + bool ro_mode_enabled; + struct cam_fd_results *fd_results; + uint32_t *raw_results; +}; + +/** + * struct cam_fd_hw_reserve_args : Reserve args for this HW context + * + * @hw_ctx : HW context for which reserve is requested + * @mode : Mode for which this reserve is requested + * @ctx_hw_private : Pointer to save HW layer's private information specific + * to this hw context. This has to be passed while calling + * further HW layer calls + */ +struct cam_fd_hw_reserve_args { + void *hw_ctx; + enum cam_fd_hw_mode mode; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_release_args : Release args for this HW context + * + * @hw_ctx : HW context for which release is requested + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_release_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_init_args : Init args for this HW context + * + * @hw_ctx : HW context for which init is requested + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_init_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_deinit_args : Deinit args for this HW context + * + * @hw_ctx : HW context for which deinit is requested + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_deinit_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_cmd_prestart_args : Prestart command args + * + * @hw_ctx : HW context which submitted this prestart + * @ctx_hw_private : HW layer's private information specific to + * this hw context + * @request_id : Request ID corresponds to this pre-start command + * @get_raw_results : Whether to get raw results for this request + * @input_buf : Input IO Buffer information for this request + * @output_buf : Output IO Buffer information for this request + * @cmd_buf_addr : Command buffer address to fill kmd commands + * @size : Size available in command buffer + * @pre_config_buf_size : Buffer size filled with commands by KMD that has + * to be inserted before umd commands + * @post_config_buf_size : Buffer size filled with commands by KMD that has + * to be inserted after umd commands + * @hw_req_private : HW layer's private information specific to + * this request + */ +struct cam_fd_hw_cmd_prestart_args { + void *hw_ctx; + void *ctx_hw_private; + uint64_t request_id; + bool get_raw_results; + struct cam_fd_hw_io_buffer input_buf[CAM_FD_MAX_IO_BUFFERS]; + struct cam_fd_hw_io_buffer output_buf[CAM_FD_MAX_IO_BUFFERS]; + uint32_t *cmd_buf_addr; + uint32_t size; + uint32_t pre_config_buf_size; + uint32_t post_config_buf_size; + struct cam_fd_hw_req_private hw_req_private; +}; + +/** + * struct cam_fd_hw_cmd_start_args : Start command args + * + * @hw_ctx : HW context which submitting start command + * @ctx_hw_private : HW layer's private information specific to + * this hw context + * @hw_req_private : HW layer's private information specific to + * this request + * @hw_update_entries : HW update entries corresponds to this request + * @num_hw_update_entries : Number of hw update entries + */ +struct cam_fd_hw_cmd_start_args { + void *hw_ctx; + void *ctx_hw_private; + struct cam_fd_hw_req_private *hw_req_private; + struct cam_hw_update_entry *hw_update_entries; + uint32_t num_hw_update_entries; +}; + +/** + * struct cam_fd_hw_stop_args : Stop command args + * + * @hw_ctx : HW context which submitting stop command + * @ctx_hw_private : HW layer's private information specific to this hw context + * @request_id : Request ID that need to be stopped + * @hw_req_private : HW layer's private information specific to this request + */ +struct cam_fd_hw_stop_args { + void *hw_ctx; + void *ctx_hw_private; + uint64_t request_id; + struct cam_fd_hw_req_private *hw_req_private; +}; + +/** + * struct cam_fd_hw_frame_done_args : Frame done command args + * + * @hw_ctx : HW context which submitting frame done request + * @ctx_hw_private : HW layer's private information specific to this hw context + * @request_id : Request ID that need to be stopped + * @hw_req_private : HW layer's private information specific to this request + */ +struct cam_fd_hw_frame_done_args { + void *hw_ctx; + void *ctx_hw_private; + uint64_t request_id; + struct cam_fd_hw_req_private *hw_req_private; +}; + +/** + * struct cam_fd_hw_reset_args : Reset command args + * + * @hw_ctx : HW context which submitting reset command + * @ctx_hw_private : HW layer's private information specific to this hw context + */ +struct cam_fd_hw_reset_args { + void *hw_ctx; + void *ctx_hw_private; +}; + +/** + * struct cam_fd_hw_cmd_set_irq_cb : Set IRQ callback command args + * + * @cam_fd_hw_mgr_cb : HW Mgr's callback pointer + * @data : HW Mgr's private data + */ +struct cam_fd_hw_cmd_set_irq_cb { + int (*cam_fd_hw_mgr_cb)(void *data, enum cam_fd_hw_irq_type irq_type); + void *data; +}; + +#endif /* _CAM_FD_HW_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..c3d5a68c69105a2b3456e335abf6e50cff5c606b --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/clk/qcom.h> + +#include "cam_fd_hw_core.h" +#include "cam_fd_hw_soc.h" + +static bool cam_fd_hw_util_cpas_callback(uint32_t handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + if (!irq_data) + return false; + + CAM_DBG(CAM_FD, "CPAS hdl=%d, udata=%pK, irq_type=%d", + handle, userdata, irq_data->irq_type); + + return false; +} + +static int cam_fd_hw_soc_util_setup_regbase_indices( + struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + uint32_t index; + int rc, i; + + for (i = 0; i < CAM_FD_REG_MAX; i++) + soc_private->regbase_index[i] = -1; + + if ((soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) || + (soc_info->num_mem_block != CAM_FD_REG_MAX)) { + CAM_ERR(CAM_FD, "Invalid num_mem_block=%d", + soc_info->num_mem_block); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "fd_core", &index); + if ((rc == 0) && (index < CAM_FD_REG_MAX)) { + soc_private->regbase_index[CAM_FD_REG_CORE] = index; + } else { + CAM_ERR(CAM_FD, "regbase not found for FD_CORE, rc=%d, %d %d", + rc, index, CAM_FD_REG_MAX); + return -EINVAL; + } + + rc = cam_common_util_get_string_index(soc_info->mem_block_name, + soc_info->num_mem_block, "fd_wrapper", &index); + if ((rc == 0) && (index < CAM_FD_REG_MAX)) { + soc_private->regbase_index[CAM_FD_REG_WRAPPER] = index; + } else { + CAM_ERR(CAM_FD, "regbase not found FD_WRAPPER, rc=%d, %d %d", + rc, index, CAM_FD_REG_MAX); + return -EINVAL; + } + + CAM_DBG(CAM_FD, "Reg indices : CORE=%d, WRAPPER=%d", + soc_private->regbase_index[CAM_FD_REG_CORE], + soc_private->regbase_index[CAM_FD_REG_WRAPPER]); + + return 0; +} + +void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + int32_t reg_index = soc_private->regbase_index[reg_base]; + + CAM_DBG(CAM_FD, "FD_REG_WRITE: Base[%d] Offset[0x%8x] Value[0x%8x]", + reg_base, reg_offset, reg_value); + + cam_io_w_mb(reg_value, + soc_info->reg_map[reg_index].mem_base + reg_offset); +} + +uint32_t cam_fd_soc_register_read(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + int32_t reg_index = soc_private->regbase_index[reg_base]; + uint32_t reg_value; + + reg_value = cam_io_r_mb( + soc_info->reg_map[reg_index].mem_base + reg_offset); + + CAM_DBG(CAM_FD, "FD_REG_READ: Base[%d] Offset[0x%8x] Value[0x%8x]", + reg_base, reg_offset, reg_value); + + return reg_value; +} + +int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private = soc_info->soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = 7200000; + axi_vote.axi_path[0].mnoc_ab_bw = 7200000; + axi_vote.axi_path[0].mnoc_ib_bw = 7200000; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = 7200000; + axi_vote.axi_path[1].mnoc_ab_bw = 7200000; + axi_vote.axi_path[1].mnoc_ib_bw = 7200000; + + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_FD, "Error in CPAS START, rc=%d", rc); + return -EFAULT; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE, + true); + if (rc) { + CAM_ERR(CAM_FD, "Error enable platform failed, rc=%d", rc); + goto stop_cpas; + } + + return rc; + +stop_cpas: + if (cam_cpas_stop(soc_private->cpas_handle)) + CAM_ERR(CAM_FD, "Error in CPAS STOP"); + + return rc; +} + + +int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private; + int rc = 0; + + if (!soc_info) { + CAM_ERR(CAM_FD, "Invalid soc_info param"); + return -EINVAL; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_FD, "disable platform resources failed, rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_FD, "Error in CPAS STOP, handle=0x%x, rc=%d", + soc_private->cpas_handle, rc); + return rc; + } + + return rc; +} + +int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data) +{ + struct cam_fd_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_FD, "Failed in get_dt_properties, rc=%d", rc); + return rc; + } + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + private_data); + if (rc) { + CAM_ERR(CAM_FD, "Failed in request_platform_resource rc=%d", + rc); + return rc; + } + + soc_private = kzalloc(sizeof(struct cam_fd_soc_private), GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto release_res; + } + soc_info->soc_private = soc_private; + + rc = cam_fd_hw_soc_util_setup_regbase_indices(soc_info); + if (rc) { + CAM_ERR(CAM_FD, "Failed in setup regbase, rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "fd", CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = &soc_info->pdev->dev; + cpas_register_param.userdata = private_data; + cpas_register_param.cam_cpas_client_cb = cam_fd_hw_util_cpas_callback; + + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_FD, "CPAS registration failed"); + goto free_soc_private; + } + soc_private->cpas_handle = cpas_register_param.client_handle; + CAM_DBG(CAM_FD, "CPAS handle=%d", soc_private->cpas_handle); + + return rc; + +free_soc_private: + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; +release_res: + cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_fd_soc_deinit_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_fd_soc_private *soc_private = + (struct cam_fd_soc_private *)soc_info->soc_private; + int rc; + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_FD, "Unregister cpas failed, handle=%d, rc=%d", + soc_private->cpas_handle, rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_FD, "release platform failed, rc=%d", rc); + + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..b27ce09e36e65495cc7db304b72bff7b8b1dca3a --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_SOC_H_ +#define _CAM_FD_HW_SOC_H_ + +#include "cam_soc_util.h" + +/** + * enum cam_fd_reg_base - Enum for FD register sets + * + * @CAM_FD_REG_CORE : Indicates FD Core register space + * @CAM_FD_REG_WRAPPER : Indicates FD Wrapper register space + * @CAM_FD_REG_MAX : Max number of register sets supported + */ +enum cam_fd_reg_base { + CAM_FD_REG_CORE, + CAM_FD_REG_WRAPPER, + CAM_FD_REG_MAX +}; + +/** + * struct cam_fd_soc_private : FD private SOC information + * + * @regbase_index : Mapping between Register base enum to register index in SOC + * @cpas_handle : CPAS handle + * + */ +struct cam_fd_soc_private { + int32_t regbase_index[CAM_FD_REG_MAX]; + uint32_t cpas_handle; +}; + +int cam_fd_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data); +int cam_fd_soc_deinit_resources(struct cam_hw_soc_info *soc_info); +int cam_fd_soc_enable_resources(struct cam_hw_soc_info *soc_info); +int cam_fd_soc_disable_resources(struct cam_hw_soc_info *soc_info); +uint32_t cam_fd_soc_register_read(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset); +void cam_fd_soc_register_write(struct cam_hw_soc_info *soc_info, + enum cam_fd_reg_base reg_base, uint32_t reg_offset, uint32_t reg_value); + +#endif /* _CAM_FD_HW_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h new file mode 100644 index 0000000000000000000000000000000000000000..ad1fb0bc573717c7c07cafaeab17ba2c08de294e --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_V41_H_ +#define _CAM_FD_HW_V41_H_ + +static struct cam_fd_hw_static_info cam_fd_wrapper120_core410_info = { + .core_version = { + .major = 4, + .minor = 1, + .incr = 0, + }, + .wrapper_version = { + .major = 1, + .minor = 2, + .incr = 0, + }, + .core_regs = { + .version = 0x38, + .control = 0x0, + .result_cnt = 0x4, + .result_addr = 0x20, + .image_addr = 0x24, + .work_addr = 0x28, + .ro_mode = 0x34, + .results_reg_base = 0x400, + .raw_results_reg_base = 0x800, + }, + .wrapper_regs = { + .wrapper_version = 0x0, + .cgc_disable = 0x4, + .hw_stop = 0x8, + .sw_reset = 0x10, + .vbif_req_priority = 0x20, + .vbif_priority_level = 0x24, + .vbif_done_status = 0x34, + .irq_mask = 0x50, + .irq_status = 0x54, + .irq_clear = 0x58, + }, + .results = { + .max_faces = 35, + .per_face_entries = 4, + .raw_results_available = true, + .raw_results_entries = 512, + }, + .enable_errata_wa = { + .single_irq_only = true, + .ro_mode_enable_always = true, + .ro_mode_results_invalid = true, + }, + .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE), + .qos_priority = 4, + .qos_priority_level = 4, + .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V41_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h new file mode 100644 index 0000000000000000000000000000000000000000..f3eedeb3b8110ceeecae0f83133e29fab808c218 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_V501_H_ +#define _CAM_FD_HW_V501_H_ + +static struct cam_fd_hw_static_info cam_fd_wrapper200_core501_info = { + .core_version = { + .major = 5, + .minor = 0, + .incr = 1, + }, + .wrapper_version = { + .major = 2, + .minor = 0, + .incr = 0, + }, + .core_regs = { + .version = 0x38, + .control = 0x0, + .result_cnt = 0x4, + .result_addr = 0x20, + .image_addr = 0x24, + .work_addr = 0x28, + .ro_mode = 0x34, + .results_reg_base = 0x400, + .raw_results_reg_base = 0x800, + }, + .wrapper_regs = { + .wrapper_version = 0x0, + .cgc_disable = 0x4, + .hw_stop = 0x8, + .sw_reset = 0x10, + .vbif_req_priority = 0x20, + .vbif_priority_level = 0x24, + .vbif_done_status = 0x34, + .irq_mask = 0x50, + .irq_status = 0x54, + .irq_clear = 0x58, + }, + .results = { + .max_faces = 35, + .per_face_entries = 4, + .raw_results_available = true, + .raw_results_entries = 512, + }, + .enable_errata_wa = { + .single_irq_only = true, + .ro_mode_enable_always = true, + .ro_mode_results_invalid = true, + }, + .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE), + .qos_priority = 4, + .qos_priority_level = 4, + .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V501_H_ */ diff --git a/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h new file mode 100644 index 0000000000000000000000000000000000000000..0c81cb642930acb58925b1b834da7bcc15ba48b7 --- /dev/null +++ b/techpack/camera/drivers/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v600.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FD_HW_V600_H_ +#define _CAM_FD_HW_V600_H_ + +static struct cam_fd_hw_static_info cam_fd_wrapper200_core600_info = { + .core_version = { + .major = 6, + .minor = 0, + .incr = 0, + }, + .wrapper_version = { + .major = 2, + .minor = 0, + .incr = 0, + }, + .core_regs = { + .version = 0x38, + .control = 0x0, + .result_cnt = 0x4, + .result_addr = 0x20, + .image_addr = 0x24, + .work_addr = 0x28, + .ro_mode = 0x34, + .results_reg_base = 0x400, + }, + .wrapper_regs = { + .wrapper_version = 0x0, + .cgc_disable = 0x4, + .hw_stop = 0x8, + .sw_reset = 0x10, + .vbif_req_priority = 0x20, + .vbif_priority_level = 0x24, + .vbif_done_status = 0x34, + .irq_mask = 0x50, + .irq_status = 0x54, + .irq_clear = 0x58, + }, + .results = { + .max_faces = 35, + .per_face_entries = 4, + .raw_results_available = false, + }, + .enable_errata_wa = { + .single_irq_only = true, + .ro_mode_enable_always = true, + .ro_mode_results_invalid = true, + }, + .irq_mask = CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_FRAME_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_HALT_DONE) | + CAM_FD_IRQ_TO_MASK(CAM_FD_IRQ_RESET_DONE), + .qos_priority = 4, + .qos_priority_level = 4, + .supported_modes = CAM_FD_MODE_FACEDETECTION | CAM_FD_MODE_PYRAMID, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V600_H_ */ diff --git a/techpack/camera/drivers/cam_icp/Makefile b/techpack/camera/drivers/cam_icp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aec65fc06f4b769d743c902e21008d7a7afe10c8 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_subdev.o cam_icp_context.o hfi.o diff --git a/techpack/camera/drivers/cam_icp/cam_icp_context.c b/techpack/camera/drivers/cam_icp/cam_icp_context.c new file mode 100644 index 0000000000000000000000000000000000000000..180ea7152a7687763249ea23632cff271e479b8e --- /dev/null +++ b/techpack/camera/drivers/cam_icp/cam_icp_context.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <media/cam_sync.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "cam_node.h" +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_icp_context.h" +#include "cam_req_mgr_util.h" +#include "cam_mem_mgr.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" + +static const char icp_dev_name[] = "cam-icp"; + +static int cam_icp_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + int rc = 0; + bool b_mem_found = false; + + if (!ctx) { + CAM_ERR(CAM_ICP, "Invalid ctx"); + return -EINVAL; + } + + if (ctx->state < CAM_CTX_ACQUIRED || ctx->state > CAM_CTX_ACTIVATED) { + CAM_ERR(CAM_ICP, "Invalid state icp ctx %d state %d", + ctx->ctx_id, ctx->state); + goto end; + } + + CAM_INFO(CAM_ICP, "iommu fault for icp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ICP, "req_id : %lld", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &b_mem_found); + if (rc) + CAM_ERR(CAM_ICP, "Failed to dump pf info"); + + if (b_mem_found) + CAM_ERR(CAM_ICP, "Found page fault in req %lld %d", + req->request_id, rc); + } + +end: + return rc; +} + +static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ICP", ctx); + } + + return rc; +} + +static int __cam_icp_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Unable to release device"); + + ctx->state = CAM_CTX_AVAILABLE; + trace_cam_context_state("ICP", ctx); + return rc; +} + +static int __cam_icp_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (!rc) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ICP", ctx); + } + + return rc; +} + +static int __cam_icp_flush_dev_in_ready(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to flush device"); + + return rc; +} + +static int __cam_icp_config_dev_in_ready(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + size_t len; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t remain_len = 0; + + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "[%s][%d] Can not get packet address", + ctx->dev_name, ctx->ctx_id); + rc = -EINVAL; + return rc; + } + + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, + "Invalid offset, len: %zu cmd offset: %llu sizeof packet: %zu", + len, cmd->offset, sizeof(struct cam_packet)); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); + + rc = cam_packet_util_validate_packet(packet, remain_len); + if (rc) { + CAM_ERR(CAM_CTXT, "Invalid packet params, remain length: %zu", + remain_len); + return rc; + } + + if (((packet->header.op_code & 0xff) == + CAM_ICP_OPCODE_IPE_SETTINGS) || + ((packet->header.op_code & 0xff) == + CAM_ICP_OPCODE_BPS_SETTINGS)) + rc = cam_context_config_dev_to_hw(ctx, cmd); + else + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + + if (rc) + CAM_ERR(CAM_ICP, "Failed to prepare device"); + + return rc; +} + +static int __cam_icp_stop_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) + CAM_ERR(CAM_ICP, "Failed to stop device"); + + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ICP", ctx); + return rc; +} + +static int __cam_icp_release_dev_in_ready(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = __cam_icp_stop_dev_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_ICP, "Failed to stop device"); + + rc = __cam_icp_release_dev_in_acquired(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to release device"); + + return rc; +} + +static int __cam_icp_handle_buf_done_in_ready(void *ctx, + uint32_t evt_id, void *done) +{ + return cam_context_buf_done_from_hw(ctx, done, evt_id); +} + +static struct cam_ctx_ops + cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_icp_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_icp_release_dev_in_acquired, + .start_dev = __cam_icp_start_dev_in_acquired, + .config_dev = __cam_icp_config_dev_in_ready, + .flush_dev = __cam_icp_flush_dev_in_ready, + }, + .crm_ops = {}, + .irq_ops = __cam_icp_handle_buf_done_in_ready, + .pagefault_ops = cam_icp_context_dump_active_request, + }, + /* Ready */ + { + .ioctl_ops = { + .stop_dev = __cam_icp_stop_dev_in_ready, + .release_dev = __cam_icp_release_dev_in_ready, + .config_dev = __cam_icp_config_dev_in_ready, + .flush_dev = __cam_icp_flush_dev_in_ready, + }, + .crm_ops = {}, + .irq_ops = __cam_icp_handle_buf_done_in_ready, + .pagefault_ops = cam_icp_context_dump_active_request, + }, + /* Flushed */ + {}, + /* Activated */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + .pagefault_ops = cam_icp_context_dump_active_request, + }, +}; + +int cam_icp_context_init(struct cam_icp_context *ctx, + struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id) +{ + int rc; + + if ((!ctx) || (!ctx->base) || (!hw_intf)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", ctx, hw_intf); + rc = -EINVAL; + goto err; + } + + rc = cam_context_init(ctx->base, icp_dev_name, CAM_ICP, ctx_id, + NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_ICP, "Camera Context Base init failed"); + goto err; + } + + ctx->base->state_machine = cam_icp_ctx_state_machine; + ctx->base->ctx_priv = ctx; + ctx->ctxt_to_hw_map = NULL; + +err: + return rc; +} + +int cam_icp_context_deinit(struct cam_icp_context *ctx) +{ + if ((!ctx) || (!ctx->base)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK", ctx); + return -EINVAL; + } + + cam_context_deinit(ctx->base); + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} diff --git a/techpack/camera/drivers/cam_icp/cam_icp_context.h b/techpack/camera/drivers/cam_icp/cam_icp_context.h new file mode 100644 index 0000000000000000000000000000000000000000..edd8bd5617c9208fbd7f4aee574238cf49c40008 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/cam_icp_context.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ICP_CONTEXT_H_ +#define _CAM_ICP_CONTEXT_H_ + +#include "cam_context.h" + +/** + * struct cam_icp_context - icp context + * @base: icp context object + * @state_machine: state machine for ICP context + * @req_base: common request structure + * @state: icp context state + * @ctxt_to_hw_map: context to FW handle mapping + */ +struct cam_icp_context { + struct cam_context *base; + struct cam_ctx_ops *state_machine; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + uint32_t state; + void *ctxt_to_hw_map; +}; + +/** + * cam_icp_context_init() - ICP context init + * @ctx: Pointer to context + * @hw_intf: Pointer to ICP hardware interface + * @ctx_id: ID for this context + */ +int cam_icp_context_init(struct cam_icp_context *ctx, + struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id); + +/** + * cam_icp_context_deinit() - ICP context deinit + * @ctx: Pointer to context + */ +int cam_icp_context_deinit(struct cam_icp_context *ctx); + +#endif /* _CAM_ICP_CONTEXT_H_ */ diff --git a/techpack/camera/drivers/cam_icp/cam_icp_subdev.c b/techpack/camera/drivers/cam_icp/cam_icp_subdev.c new file mode 100644 index 0000000000000000000000000000000000000000..bdb2ed5f900bb39b7a276b3cf74c2a8a1611c3e7 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/cam_icp_subdev.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/platform_device.h> +#include <linux/videodev2.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <media/cam_req_mgr.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "cam_req_mgr_dev.h" +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_context.h" +#include "cam_icp_context.h" +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +#define CAM_ICP_DEV_NAME "cam-icp" + +struct cam_icp_subdev { + struct cam_subdev sd; + struct cam_node *node; + struct cam_context ctx[CAM_ICP_CTX_MAX]; + struct cam_icp_context ctx_icp[CAM_ICP_CTX_MAX]; + struct mutex icp_lock; + int32_t open_cnt; + int32_t reserved; +}; + +static struct cam_icp_subdev g_icp_dev; + +static const struct of_device_id cam_icp_dt_match[] = { + {.compatible = "qcom,cam-icp"}, + {} +}; + +static void cam_icp_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_ICP, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static int cam_icp_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_hw_mgr_intf *hw_mgr_intf = NULL; + struct cam_node *node = v4l2_get_subdevdata(sd); + int rc = 0; + + mutex_lock(&g_icp_dev.icp_lock); + if (g_icp_dev.open_cnt >= 1) { + CAM_ERR(CAM_ICP, "ICP subdev is already opened"); + rc = -EALREADY; + goto end; + } + + if (!node) { + CAM_ERR(CAM_ICP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + hw_mgr_intf = &node->hw_mgr_intf; + rc = hw_mgr_intf->hw_open(hw_mgr_intf->hw_mgr_priv, NULL); + if (rc < 0) { + CAM_ERR(CAM_ICP, "FW download failed"); + goto end; + } + g_icp_dev.open_cnt++; +end: + mutex_unlock(&g_icp_dev.icp_lock); + return rc; +} + +static int cam_icp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_hw_mgr_intf *hw_mgr_intf = NULL; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_icp_dev.icp_lock); + if (g_icp_dev.open_cnt <= 0) { + CAM_DBG(CAM_ICP, "ICP subdev is already closed"); + rc = -EINVAL; + goto end; + } + g_icp_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_ICP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + hw_mgr_intf = &node->hw_mgr_intf; + if (!hw_mgr_intf) { + CAM_ERR(CAM_ICP, "hw_mgr_intf is not initialized"); + rc = -EINVAL; + goto end; + } + + rc = cam_node_shutdown(node); + if (rc < 0) { + CAM_ERR(CAM_ICP, "HW close failed"); + goto end; + } + +end: + mutex_unlock(&g_icp_dev.icp_lock); + return 0; +} + +const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = { + .open = cam_icp_subdev_open, + .close = cam_icp_subdev_close, +}; + +static int cam_icp_probe(struct platform_device *pdev) +{ + int rc = 0, i = 0; + struct cam_node *node; + struct cam_hw_mgr_intf *hw_mgr_intf; + int iommu_hdl = -1; + + if (!pdev) { + CAM_ERR(CAM_ICP, "pdev is NULL"); + return -EINVAL; + } + + g_icp_dev.sd.pdev = pdev; + g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops; + rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME, + CAM_ICP_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_ICP, "ICP cam_subdev_probe failed"); + goto probe_fail; + } + + node = (struct cam_node *) g_icp_dev.sd.token; + + hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL); + if (!hw_mgr_intf) { + rc = -EINVAL; + goto hw_alloc_fail; + } + + rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf, + &iommu_hdl); + if (rc) { + CAM_ERR(CAM_ICP, "ICP HW manager init failed: %d", rc); + goto hw_init_fail; + } + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i]; + rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i], + hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_ICP, "ICP context init failed"); + goto ctx_fail; + } + } + + rc = cam_node_init(node, hw_mgr_intf, g_icp_dev.ctx, + CAM_ICP_CTX_MAX, CAM_ICP_DEV_NAME); + if (rc) { + CAM_ERR(CAM_ICP, "ICP node init failed"); + goto ctx_fail; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_icp_dev_iommu_fault_handler, node); + + g_icp_dev.open_cnt = 0; + mutex_init(&g_icp_dev.icp_lock); + + CAM_DBG(CAM_ICP, "ICP probe complete"); + + return rc; + +ctx_fail: + for (--i; i >= 0; i--) + cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]); +hw_init_fail: + kfree(hw_mgr_intf); +hw_alloc_fail: + cam_subdev_remove(&g_icp_dev.sd); +probe_fail: + return rc; +} + +static int cam_icp_remove(struct platform_device *pdev) +{ + int i; + struct v4l2_subdev *sd; + struct cam_subdev *subdev; + + if (!pdev) { + CAM_ERR(CAM_ICP, "pdev is NULL"); + return -ENODEV; + } + + sd = platform_get_drvdata(pdev); + if (!sd) { + CAM_ERR(CAM_ICP, "V4l2 subdev is NULL"); + return -ENODEV; + } + + subdev = v4l2_get_subdevdata(sd); + if (!subdev) { + CAM_ERR(CAM_ICP, "cam subdev is NULL"); + return -ENODEV; + } + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) + cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]); + cam_node_deinit(g_icp_dev.node); + cam_subdev_remove(&g_icp_dev.sd); + mutex_destroy(&g_icp_dev.icp_lock); + + return 0; +} + +static struct platform_driver cam_icp_driver = { + .probe = cam_icp_probe, + .remove = cam_icp_remove, + .driver = { + .name = "cam_icp", + .owner = THIS_MODULE, + .of_match_table = cam_icp_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_icp_init_module(void) +{ + return platform_driver_register(&cam_icp_driver); +} + +static void __exit cam_icp_exit_module(void) +{ + platform_driver_unregister(&cam_icp_driver); +} +module_init(cam_icp_init_module); +module_exit(cam_icp_exit_module); +MODULE_DESCRIPTION("MSM ICP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_icp/fw_inc/hfi_intf.h b/techpack/camera/drivers/cam_icp/fw_inc/hfi_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..afd42d23b9fb43bd4e2070864da07efd3078df13 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/fw_inc/hfi_intf.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _HFI_INTF_H_ +#define _HFI_INTF_H_ + +#include <linux/types.h> + +/** + * struct hfi_mem + * @len: length of memory + * @kva: kernel virtual address + * @iova: IO virtual address + * @reserved: reserved field + */ +struct hfi_mem { + uint64_t len; + uintptr_t kva; + uint32_t iova; + uint32_t reserved; +}; + +/** + * struct hfi_mem_info + * @qtbl: qtable hfi memory + * @cmd_q: command queue hfi memory for host to firmware communication + * @msg_q: message queue hfi memory for firmware to host communication + * @dbg_q: debug queue hfi memory for firmware debug information + * @sfr_buf: buffer for subsystem failure reason[SFR] + * @sec_heap: secondary heap hfi memory for firmware + * @qdss: qdss mapped memory for fw + * @io_mem: io memory info + * @io_mem2: 2nd io memory info + * @icp_base: icp base address + */ +struct hfi_mem_info { + struct hfi_mem qtbl; + struct hfi_mem cmd_q; + struct hfi_mem msg_q; + struct hfi_mem dbg_q; + struct hfi_mem sfr_buf; + struct hfi_mem sec_heap; + struct hfi_mem shmem; + struct hfi_mem qdss; + struct hfi_mem io_mem; + struct hfi_mem io_mem2; + void __iomem *icp_base; +}; + +/** + * hfi_write_cmd() - function for hfi write + * @cmd_ptr: pointer to command data for hfi write + * + * Returns success(zero)/failure(non zero) + */ +int hfi_write_cmd(void *cmd_ptr); + +/** + * hfi_read_message() - function for hfi read + * @pmsg: buffer to place read message for hfi queue + * @q_id: queue id + * @words_read: total number of words read from the queue + * returned as output to the caller + * + * Returns success(zero)/failure(non zero) + */ +int hfi_read_message(uint32_t *pmsg, uint8_t q_id, uint32_t *words_read); + +/** + * hfi_init() - function initialize hfi after firmware download + * @event_driven_mode: event mode + * @hfi_mem: hfi memory info + * @icp_base: icp base address + * @debug: debug flag + * + * Returns success(zero)/failure(non zero) + */ +int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, + void *__iomem icp_base, bool debug); + +/** + * hfi_get_hw_caps() - hardware capabilities from firmware + * @query_caps: holds query information from hfi + * + * Returns success(zero)/failure(non zero) + */ +int hfi_get_hw_caps(void *query_caps); + +/** + * hfi_send_system_cmd() - send hfi system command to firmware + * @type: type of system command + * @data: command data + * @size: size of command data + */ +void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size); + +/** + * cam_hfi_enable_cpu() - enable A5 CPU + * @icp_base: icp base address + */ +void cam_hfi_enable_cpu(void __iomem *icp_base); + +/** + * cam_hfi_disable_cpu() - disable A5 CPU + * @icp_base: icp base address + */ +void cam_hfi_disable_cpu(void __iomem *icp_base); + +/** + * cam_hfi_deinit() - cleanup HFI + */ +void cam_hfi_deinit(void __iomem *icp_base); +/** + * hfi_set_debug_level() - set debug level + * @a5_dbg_type: 1 for debug_q & 2 for qdss + * @lvl: FW debug message level + */ +int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl); + +/** + * hfi_set_fw_dump_level() - set firmware dump level + * @lvl: level of firmware dump level + */ +int hfi_set_fw_dump_level(uint32_t lvl); + +/** + * hfi_enable_ipe_bps_pc() - Enable interframe pc + * Host sends a command to firmware to enable interframe + * power collapse for IPE and BPS hardware. + * + * @enable: flag to enable/disable + * @core_info: Core information to firmware + */ +int hfi_enable_ipe_bps_pc(bool enable, uint32_t core_info); + +/** + * hfi_cmd_ubwc_config_ext() - UBWC configuration to firmware + * @ubwc_ipe_cfg: UBWC ipe fetch/write configuration params + * @ubwc_bps_cfg: UBWC bps fetch/write configuration params + */ +int hfi_cmd_ubwc_config_ext(uint32_t *ubwc_ipe_cfg, + uint32_t *ubwc_bps_cfg); + +/** + * hfi_cmd_ubwc_config() - UBWC configuration to firmware + * for older targets + * @ubwc_cfg: UBWC configuration parameters + */ +int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg); + +/** + * cam_hfi_resume() - function to resume + * @hfi_mem: hfi memory info + * @icp_base: icp base address + * @debug: debug flag + * + * Returns success(zero)/failure(non zero) + */ +int cam_hfi_resume(struct hfi_mem_info *hfi_mem, + void __iomem *icp_base, bool debug); + +/** + * cam_hfi_queue_dump() - utility function to dump hfi queues + */ +void cam_hfi_queue_dump(void); + + +#endif /* _HFI_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_icp/fw_inc/hfi_reg.h b/techpack/camera/drivers/cam_icp/fw_inc/hfi_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..df4ae01d7ef2a440e112649de288cb2f598cad1c --- /dev/null +++ b/techpack/camera/drivers/cam_icp/fw_inc/hfi_reg.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HFI_REG_H_ +#define _CAM_HFI_REG_H_ + +#include <linux/types.h> +#include "hfi_intf.h" + + +/* start of ICP CSR registers */ +#define HFI_REG_A5_HW_VERSION 0x0 +#define HFI_REG_A5_CSR_NSEC_RESET 0x4 +#define HFI_REG_A5_CSR_A5_CONTROL 0x8 +#define HFI_REG_A5_CSR_ETM 0xC +#define HFI_REG_A5_CSR_A2HOSTINTEN 0x10 +#define HFI_REG_A5_CSR_A2HOSTINT 0x14 +#define HFI_REG_A5_CSR_A2HOSTINTCLR 0x18 +#define HFI_REG_A5_CSR_A2HOSTINTSTATUS 0x1C +#define HFI_REG_A5_CSR_A2HOSTINTSET 0x20 +#define HFI_REG_A5_CSR_HOST2ICPINT 0x30 +#define HFI_REG_A5_CSR_A5_STATUS 0x200 +#define HFI_REG_A5_QGIC2_LM_ID 0x204 +#define HFI_REG_A5_SPARE 0x400 + +/* general purpose registers from */ +#define HFI_REG_FW_VERSION 0x44 +#define HFI_REG_HOST_ICP_INIT_REQUEST 0x48 +#define HFI_REG_ICP_HOST_INIT_RESPONSE 0x4C +#define HFI_REG_SHARED_MEM_PTR 0x50 +#define HFI_REG_SHARED_MEM_SIZE 0x54 +#define HFI_REG_QTBL_PTR 0x58 +#define HFI_REG_UNCACHED_HEAP_PTR 0x5C +#define HFI_REG_UNCACHED_HEAP_SIZE 0x60 +#define HFI_REG_QDSS_IOVA 0x6C +#define HFI_REG_SFR_PTR 0x68 +#define HFI_REG_QDSS_IOVA_SIZE 0x70 +#define HFI_REG_IO_REGION_IOVA 0x74 +#define HFI_REG_IO_REGION_SIZE 0x78 +#define HFI_REG_IO2_REGION_IOVA 0x7C +#define HFI_REG_IO2_REGION_SIZE 0x80 + +/* end of ICP CSR registers */ + +/* flags for ICP CSR registers */ +#define ICP_FLAG_CSR_WAKE_UP_EN (1 << 4) +#define ICP_FLAG_CSR_A5_EN (1 << 9) +#define ICP_CSR_EN_CLKGATE_WFI (1 << 12) +#define ICP_CSR_EDBGRQ (1 << 14) +#define ICP_CSR_DBGSWENABLE (1 << 22) +#define ICP_CSR_A5_STATUS_WFI (1 << 7) + +#define ICP_FLAG_A5_CTRL_DBG_EN (ICP_FLAG_CSR_WAKE_UP_EN|\ + ICP_FLAG_CSR_A5_EN|\ + ICP_CSR_EDBGRQ|\ + ICP_CSR_DBGSWENABLE) + +#define ICP_FLAG_A5_CTRL_EN (ICP_FLAG_CSR_WAKE_UP_EN|\ + ICP_FLAG_CSR_A5_EN|\ + ICP_CSR_EN_CLKGATE_WFI) + +/* start of Queue table and queues */ +#define MAX_ICP_HFI_QUEUES 4 +#define ICP_QHDR_TX_TYPE_MASK 0xFF000000 +#define ICP_QHDR_RX_TYPE_MASK 0x00FF0000 +#define ICP_QHDR_PRI_TYPE_MASK 0x0000FF00 +#define ICP_QHDR_Q_ID_MASK 0x000000FF + +#define ICP_CMD_Q_SIZE_IN_BYTES 4096 +#define ICP_MSG_Q_SIZE_IN_BYTES 4096 +#define ICP_DBG_Q_SIZE_IN_BYTES 102400 +#define ICP_MSG_SFR_SIZE_IN_BYTES 4096 + +#define ICP_SHARED_MEM_IN_BYTES (1024 * 1024) +#define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024) +#define ICP_HFI_MAX_PKT_SIZE_IN_WORDS 25600 +#define ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS 1024 + +#define ICP_HFI_QTBL_HOSTID1 0x01000000 +#define ICP_HFI_QTBL_STATUS_ENABLED 0x00000001 +#define ICP_HFI_NUMBER_OF_QS 3 +#define ICP_HFI_NUMBER_OF_ACTIVE_QS 3 +#define ICP_HFI_QTBL_OFFSET 0 +#define ICP_HFI_VAR_SIZE_PKT 0 +#define ICP_HFI_MAX_MSG_SIZE_IN_WORDS 128 + + +/* Queue Header type masks. Use these to access bitfields in qhdr_type */ +#define HFI_MASK_QHDR_TX_TYPE 0xFF000000 +#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000 +#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00 +#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000FF + + +#define TX_EVENT_DRIVEN_MODE_1 0 +#define RX_EVENT_DRIVEN_MODE_1 0 +#define TX_EVENT_DRIVEN_MODE_2 0x01000000 +#define RX_EVENT_DRIVEN_MODE_2 0x00010000 +#define TX_EVENT_POLL_MODE_2 0x02000000 +#define RX_EVENT_POLL_MODE_2 0x00020000 +#define U32_OFFSET 0x1 +#define BYTE_WORD_SHIFT 2 + +/** + * @INVALID: Invalid state + * @HFI_DEINIT: HFI is not initialized yet + * @HFI_INIT: HFI is initialized + * @HFI_READY: HFI is ready to send/receive commands/messages + */ +enum hfi_state { + HFI_DEINIT, + HFI_INIT, + HFI_READY +}; + +/** + * @RESET: init success + * @SET: init failed + */ +enum reg_settings { + RESET, + SET, + SET_WM = 1024 +}; + +/** + * @INTR_DISABLE: Disable interrupt + * @INTR_ENABLE: Enable interrupt + * @INTR_ENABLE_WD0: Enable WD0 + * @INTR_ENABLE_WD1: Enable WD1 + */ +enum intr_status { + INTR_DISABLE, + INTR_ENABLE, + INTR_ENABLE_WD0, + INTR_ENABLE_WD1 = 0x4 +}; + +/** + * @ICP_INIT_RESP_RESET: reset init state + * @ICP_INIT_RESP_SUCCESS: init success + * @ICP_INIT_RESP_FAILED: init failed + */ +enum host_init_resp { + ICP_INIT_RESP_RESET, + ICP_INIT_RESP_SUCCESS, + ICP_INIT_RESP_FAILED +}; + +/** + * @ICP_INIT_REQUEST_RESET: reset init request + * @ICP_INIT_REQUEST_SET: set init request + */ +enum host_init_request { + ICP_INIT_REQUEST_RESET, + ICP_INIT_REQUEST_SET +}; + +/** + * @QHDR_INACTIVE: Queue is inactive + * @QHDR_ACTIVE: Queue is active + */ +enum qhdr_status { + QHDR_INACTIVE, + QHDR_ACTIVE +}; + +/** + * @INTR_MODE: event driven mode 1, each send and receive generates interrupt + * @WM_MODE: event driven mode 2, interrupts based on watermark mechanism + * @POLL_MODE: poll method + */ +enum qhdr_event_drv_type { + INTR_MODE, + WM_MODE, + POLL_MODE +}; + +/** + * @TX_INT: event driven mode 1, each send and receive generates interrupt + * @TX_INT_WM: event driven mode 2, interrupts based on watermark mechanism + * @TX_POLL: poll method + * @ICP_QHDR_TX_TYPE_MASK defines position in qhdr_type + */ +enum qhdr_tx_type { + TX_INT, + TX_INT_WM, + TX_POLL +}; + +/** + * @RX_INT: event driven mode 1, each send and receive generates interrupt + * @RX_INT_WM: event driven mode 2, interrupts based on watermark mechanism + * @RX_POLL: poll method + * @ICP_QHDR_RX_TYPE_MASK defines position in qhdr_type + */ +enum qhdr_rx_type { + RX_INT, + RX_INT_WM, + RX_POLL +}; + +/** + * @Q_CMD: Host to FW command queue + * @Q_MSG: FW to Host message queue + * @Q_DEBUG: FW to Host debug queue + * @ICP_QHDR_Q_ID_MASK defines position in qhdr_type + */ +enum qhdr_q_id { + Q_CMD, + Q_MSG, + Q_DBG +}; + +/** + * struct hfi_qtbl_hdr + * @qtbl_version: Queue table version number + * Higher 16 bits: Major version + * Lower 16 bits: Minor version + * @qtbl_size: Queue table size from version to last parametr in qhdr entry + * @qtbl_qhdr0_offset: Offset to the start of first qhdr + * @qtbl_qhdr_size: Queue header size in bytes + * @qtbl_num_q: Total number of queues in Queue table + * @qtbl_num_active_q: Total number of active queues + */ +struct hfi_qtbl_hdr { + uint32_t qtbl_version; + uint32_t qtbl_size; + uint32_t qtbl_qhdr0_offset; + uint32_t qtbl_qhdr_size; + uint32_t qtbl_num_q; + uint32_t qtbl_num_active_q; +} __packed; + +/** + * struct hfi_q_hdr + * @qhdr_status: Queue status, qhdr_state define possible status + * @qhdr_start_addr: Queue start address in non cached memory + * @qhdr_type: qhdr_tx, qhdr_rx, qhdr_q_id and priority defines qhdr type + * @qhdr_q_size: Queue size + * Number of queue packets if qhdr_pkt_size is non-zero + * Queue size in bytes if qhdr_pkt_size is zero + * @qhdr_pkt_size: Size of queue packet entries + * 0x0: variable queue packet size + * non zero: size of queue packet entry, fixed + * @qhdr_pkt_drop_cnt: Number of packets dropped by sender + * @qhdr_rx_wm: Receiver watermark, applicable in event driven mode + * @qhdr_tx_wm: Sender watermark, applicable in event driven mode + * @qhdr_rx_req: Receiver sets this bit if queue is empty + * @qhdr_tx_req: Sender sets this bit if queue is full + * @qhdr_rx_irq_status: Receiver sets this bit and triggers an interrupt to + * the sender after packets are dequeued. Sender clears this bit + * @qhdr_tx_irq_status: Sender sets this bit and triggers an interrupt to + * the receiver after packets are queued. Receiver clears this bit + * @qhdr_read_idx: Read index + * @qhdr_write_idx: Write index + */ +struct hfi_q_hdr { + uint32_t dummy[15]; + uint32_t qhdr_status; + uint32_t dummy1[15]; + uint32_t qhdr_start_addr; + uint32_t dummy2[15]; + uint32_t qhdr_type; + uint32_t dummy3[15]; + uint32_t qhdr_q_size; + uint32_t dummy4[15]; + uint32_t qhdr_pkt_size; + uint32_t dummy5[15]; + uint32_t qhdr_pkt_drop_cnt; + uint32_t dummy6[15]; + uint32_t qhdr_rx_wm; + uint32_t dummy7[15]; + uint32_t qhdr_tx_wm; + uint32_t dummy8[15]; + uint32_t qhdr_rx_req; + uint32_t dummy9[15]; + uint32_t qhdr_tx_req; + uint32_t dummy10[15]; + uint32_t qhdr_rx_irq_status; + uint32_t dummy11[15]; + uint32_t qhdr_tx_irq_status; + uint32_t dummy12[15]; + uint32_t qhdr_read_idx; + uint32_t dummy13[15]; + uint32_t qhdr_write_idx; + uint32_t dummy14[15]; +}; + +/** + * struct sfr_buf + * @size: Number of characters + * @msg : Subsystem failure reason + */ +struct sfr_buf { + uint32_t size; + char msg[ICP_MSG_SFR_SIZE_IN_BYTES]; +}; + +/** + * struct hfi_q_tbl + * @q_tbl_hdr: Queue table header + * @q_hdr: Queue header info, it holds info of cmd, msg and debug queues + */ +struct hfi_qtbl { + struct hfi_qtbl_hdr q_tbl_hdr; + struct hfi_q_hdr q_hdr[MAX_ICP_HFI_QUEUES]; +}; + +/** + * struct hfi_info + * @map: Hfi shared memory info + * @smem_size: Shared memory size + * @uncachedheap_size: uncached heap size + * @msgpacket_buf: message buffer + * @hfi_state: State machine for hfi + * @cmd_q_lock: Lock for command queue + * @cmd_q_state: State of command queue + * @mutex msg_q_lock: Lock for message queue + * @msg_q_state: State of message queue + * @csr_base: CSR base address + */ +struct hfi_info { + struct hfi_mem_info map; + uint32_t smem_size; + uint32_t uncachedheap_size; + uint32_t msgpacket_buf[ICP_HFI_MAX_MSG_SIZE_IN_WORDS]; + uint8_t hfi_state; + struct mutex cmd_q_lock; + bool cmd_q_state; + struct mutex msg_q_lock; + bool msg_q_state; + void __iomem *csr_base; +}; + +#endif /* _CAM_HFI_REG_H_ */ diff --git a/techpack/camera/drivers/cam_icp/fw_inc/hfi_session_defs.h b/techpack/camera/drivers/cam_icp/fw_inc/hfi_session_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..9ba7803d4f44bb801f229cc8e00d36abdf0c5660 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/fw_inc/hfi_session_defs.h @@ -0,0 +1,578 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_HFI_SESSION_DEFS_H +#define _CAM_HFI_SESSION_DEFS_H + +#include <linux/types.h> + +#define HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO 0x1 +#define HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS 0x2 +#define HFI_IPEBPS_CMD_OPCODE_BPS_ABORT 0x3 +#define HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY 0x4 + +#define HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO 0x5 +#define HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS 0x6 +#define HFI_IPEBPS_CMD_OPCODE_IPE_ABORT 0x7 +#define HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY 0x8 + +#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_IPE 0x9 +#define HFI_IPEBPS_CMD_OPCODE_BPS_WAIT_FOR_BPS 0xa +#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_BPS 0xb +#define HFI_IPEBPS_CMD_OPCODE_IPE_WAIT_FOR_IPE 0xc + +#define HFI_IPEBPS_CMD_OPCODE_MEM_MAP 0xe +#define HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP 0xf + +#define HFI_IPEBPS_HANDLE_TYPE_BPS 0x1 +#define HFI_IPEBPS_HANDLE_TYPE_IPE_RT 0x2 +#define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT 0x3 + +/** + * struct mem_map_region_data + * @start_addr: cmd buffer region start addr + * @len : length of the region + * + * create mem_map_region_data + */ +struct mem_map_region_data { + uint32_t start_addr; + uint32_t len; +}; + +/** + * struct hfi_cmd_ipe_bps_map + * @user_data : user arg + * @mem_map_request_num: number of mappings + * @mem_map_region_sets: array of all map/unmap info + * + * create hfi_cmd_ipe_bps_map + */ +struct hfi_cmd_ipe_bps_map { + uint64_t user_data; + uint32_t mem_map_request_num; + struct mem_map_region_data mem_map_region_sets[1]; +} __packed; + +/** + * struct hfi_cmd_ipe_bps_map_ack + * @rc : Async return code + * @user_data: user_arg + * + * create hfi_cmd_ipe_bps_map_ack + */ +struct hfi_cmd_ipe_bps_map_ack { + uint32_t rc; + uint64_t user_data; +}; + +/** + * struct abort_data + * @num_req_ids: Number of req ids + * @num_req_id: point to specific req id + * + * create abort data + */ +struct abort_data { + uint32_t num_req_ids; + uint32_t num_req_id[1]; +}; + +/** + * struct hfi_cmd_data + * @abort: abort data + * @user data: user supplied argument + * + * create session abort data + */ +struct hfi_cmd_abort { + struct abort_data abort; + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_abort_destroy + * @user_data: user supplied data + * + * IPE/BPS destroy/abort command + * @HFI_IPEBPS_CMD_OPCODE_IPE_ABORT + * @HFI_IPEBPS_CMD_OPCODE_BPS_ABORT + * @HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY + * @HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY + */ +struct hfi_cmd_abort_destroy { + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_chaining_ops + * @wait_hdl: current session handle waits on wait_hdl to complete operation + * @user_data: user supplied argument + * + * this structure for chaining opcodes + * BPS_WAITS_FOR_IPE + * BPS_WAITS_FOR_BPS + * IPE_WAITS_FOR_BPS + * IPE_WAITS_FOR_IPE + */ +struct hfi_cmd_chaining_ops { + uint32_t wait_hdl; + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_create_handle + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @handle_type: IPE/BPS firmware session handle type + * @user_data1: caller provided data1 + * @user_data2: caller provided data2 + * + * create firmware session handle + */ +struct hfi_cmd_create_handle { + uint32_t size; + uint32_t pkt_type; + uint32_t handle_type; + uint64_t user_data1; + uint64_t user_data2; +} __packed; + +/** + * struct hfi_cmd_ipebps_async + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @opcode: opcode for IPE/BPS async operation + * CONFIG_IO: configures I/O for IPE/BPS handle + * FRAME_PROCESS: image frame to be processed by IPE/BPS + * ABORT: abort all processing frames of IPE/BPS handle + * DESTROY: destroy earlier created IPE/BPS handle + * BPS_WAITS_FOR_IPE: sync for BPS to wait for IPE + * BPS_WAITS_FOR_BPS: sync for BPS to wait for BPS + * IPE_WAITS_FOR_IPE: sync for IPE to wait for IPE + * IPE_WAITS_FOR_BPS: sync for IPE to wait for BPS + * @num_fw_handles: number of IPE/BPS firmware handles in fw_handles array + * @fw_handles: IPE/BPS handles array + * @payload: command payload for IPE/BPS opcodes + * @direct: points to actual payload + * @indirect: points to address of payload + * + * sends async command to the earlier created IPE or BPS handle + * for asynchronous operation. + */ +struct hfi_cmd_ipebps_async { + uint32_t size; + uint32_t pkt_type; + uint32_t opcode; + uint64_t user_data1; + uint64_t user_data2; + uint32_t num_fw_handles; + uint32_t fw_handles[1]; + union { + uint32_t direct[1]; + uint32_t indirect; + } payload; +} __packed; + +/** + * struct hfi_msg_create_handle_ack + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @err_type: error code + * @fw_handle: output param for IPE/BPS handle + * @user_data1: user provided data1 + * @user_data2: user provided data2 + * + * ack for create handle command of IPE/BPS + * @HFI_MSG_IPEBPS_CREATE_HANDLE_ACK + */ +struct hfi_msg_create_handle_ack { + uint32_t size; + uint32_t pkt_type; + uint32_t err_type; + uint32_t fw_handle; + uint64_t user_data1; + uint64_t user_data2; +} __packed; + +/** + * struct hfi_msg_ipebps_async + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @opcode: opcode of IPE/BPS async operation + * @user_data1: user provided data1 + * @user_data2: user provided data2 + * @err_type: error code + * @msg_data: IPE/BPS async done message data + * + * result of IPE/BPS async command + * @HFI_MSG_IPEBPS_ASYNC_COMMAND_ACK + */ +struct hfi_msg_ipebps_async_ack { + uint32_t size; + uint32_t pkt_type; + uint32_t opcode; + uint64_t user_data1; + uint64_t user_data2; + uint32_t err_type; + uint32_t msg_data[1]; +} __packed; + +/** + * struct hfi_msg_frame_process_done + * @result: result of frame process command + * @scratch_buffer_address: address of scratch buffer + */ +struct hfi_msg_frame_process_done { + uint32_t result; + uint32_t scratch_buffer_address; +}; + +/** + * struct hfi_msg_chaining_op + * @status: return status + * @user_data: user data provided as part of chaining ops + * + * IPE/BPS wait response + */ +struct hfi_msg_chaining_op { + uint32_t status; + uint64_t user_data; +} __packed; + +/** + * struct hfi_msg_abort_destroy + * @status: return status + * @user_data: user data provided as part of abort/destroy ops + * + * IPE/BPS abort/destroy response + */ +struct hfi_msg_abort_destroy { + uint32_t status; + uint64_t user_data; +} __packed; + +#define MAX_NUM_OF_IMAGE_PLANES 2 +#define MAX_HFR_GROUP 16 + +enum hfi_ipe_io_images { + IPE_INPUT_IMAGE_FULL, + IPE_INPUT_IMAGE_DS4, + IPE_INPUT_IMAGE_DS16, + IPE_INPUT_IMAGE_DS64, + IPE_INPUT_IMAGE_FULL_REF, + IPE_INPUT_IMAGE_DS4_REF, + IPE_INPUT_IMAGE_DS16_REF, + IPE_INPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_DISPLAY, + IPE_OUTPUT_IMAGE_VIDEO, + IPE_OUTPUT_IMAGE_FULL_REF, + IPE_OUTPUT_IMAGE_DS4_REF, + IPE_OUTPUT_IMAGE_DS16_REF, + IPE_OUTPUT_IMAGE_DS64_REF, + IPE_INPUT2_IMAGE_FULL, + IPE_INPUT2_IMAGE_DSX, + IPE_INPUT_OUTPUT_SCRATCHBUFFER, + IPE_INPUT_IMAGE_FIRST = IPE_INPUT_IMAGE_FULL, + IPE_INPUT_IMAGE_LAST = IPE_INPUT_IMAGE_DS64_REF, + IPE_INPUT_IMAGE_REF_FIRST = IPE_INPUT_IMAGE_FULL_REF, + IPE_INPUT_IMAGE_REF_LAST = IPE_INPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_FIRST = IPE_OUTPUT_IMAGE_DISPLAY, + IPE_OUTPUT_IMAGE_LAST = IPE_OUTPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_REF_FIRST = IPE_OUTPUT_IMAGE_FULL_REF, + IPE_OUTPUT_IMAGE_REF_LAST = IPE_OUTPUT_IMAGE_DS64_REF, + IPE_INPUT2_IMAGE_FIRST = IPE_INPUT2_IMAGE_FULL, + IPE_INPUT2_IMAGE_LAST = IPE_INPUT2_IMAGE_DSX, + IPE_INPUT_OUTPUT_IMAGE_LAST = IPE_INPUT_OUTPUT_SCRATCHBUFFER, + IPE_IO_IMAGES_MAX +}; + +enum bps_io_images { + BPS_INPUT_IMAGE, + BPS_OUTPUT_IMAGE_FULL, + BPS_OUTPUT_IMAGE_DS4, + BPS_OUTPUT_IMAGE_DS16, + BPS_OUTPUT_IMAGE_DS64, + BPS_OUTPUT_IMAGE_STATS_BG, + BPS_OUTPUT_IMAGE_STATS_BHIST, + BPS_OUTPUT_IMAGE_REG1, + BPS_OUTPUT_IMAGE_REG2, + BPS_OUTPUT_IMAGE_FIRST = BPS_OUTPUT_IMAGE_FULL, + BPS_OUTPUT_IMAGE_LAST = BPS_OUTPUT_IMAGE_REG2, + BPS_IO_IMAGES_MAX +}; + +struct frame_buffer { + uint32_t buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; + uint32_t meta_buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +struct bps_frame_process_data { + uint32_t max_num_cores; + uint32_t target_time; + uint32_t ubwc_stats_buffer_addr; + uint32_t ubwc_stats_buffer_size; + uint32_t cdm_buffer_addr; + uint32_t cdm_buffer_size; + uint32_t iq_settings_addr; + uint32_t strip_lib_out_addr; + uint32_t cdm_prog_addr; + uint32_t request_id; + struct frame_buffer buffers[BPS_IO_IMAGES_MAX]; +}; + +enum hfi_ipe_image_format { + IMAGE_FORMAT_INVALID, + IMAGE_FORMAT_MIPI_8, + IMAGE_FORMAT_MIPI_10, + IMAGE_FORMAT_MIPI_12, + IMAGE_FORMAT_MIPI_14, + IMAGE_FORMAT_BAYER_8, + IMAGE_FORMAT_BAYER_10, + IMAGE_FORMAT_BAYER_12, + IMAGE_FORMAT_BAYER_14, + IMAGE_FORMAT_PDI_10, + IMAGE_FORMAT_PD_10, + IMAGE_FORMAT_PD_8, + IMAGE_FORMAT_INDICATIONS, + IMAGE_FORMAT_REFINEMENT, + IMAGE_FORMAT_UBWC_TP_10, + IMAGE_FORMAT_UBWC_NV_12, + IMAGE_FORMAT_UBWC_NV12_4R, + IMAGE_FORMAT_UBWC_P010, + IMAGE_FORMAT_LINEAR_TP_10, + IMAGE_FORMAT_LINEAR_P010, + IMAGE_FORMAT_LINEAR_NV12, + IMAGE_FORMAT_LINEAR_PLAIN_16, + IMAGE_FORMAT_YUV422_8, + IMAGE_FORMAT_YUV422_10, + IMAGE_FORMAT_STATISTICS_BAYER_GRID, + IMAGE_FORMAT_STATISTICS_BAYER_HISTOGRAM, + IMAGE_FORMAT_MAX +}; + +enum hfi_ipe_plane_format { + PLANE_FORMAT_INVALID = 0, + PLANE_FORMAT_MIPI_8, + PLANE_FORMAT_MIPI_10, + PLANE_FORMAT_MIPI_12, + PLANE_FORMAT_MIPI_14, + PLANE_FORMAT_BAYER_8, + PLANE_FORMAT_BAYER_10, + PLANE_FORMAT_BAYER_12, + PLANE_FORMAT_BAYER_14, + PLANE_FORMAT_PDI_10, + PLANE_FORMAT_PD_10, + PLANE_FORMAT_PD_8, + PLANE_FORMAT_INDICATIONS, + PLANE_FORMAT_REFINEMENT, + PLANE_FORMAT_UBWC_TP_10_Y, + PLANE_FORMAT_UBWC_TP_10_C, + PLANE_FORMAT_UBWC_NV_12_Y, + PLANE_FORMAT_UBWC_NV_12_C, + PLANE_FORMAT_UBWC_NV_12_4R_Y, + PLANE_FORMAT_UBWC_NV_12_4R_C, + PLANE_FORMAT_UBWC_P010_Y, + PLANE_FORMAT_UBWC_P010_C, + PLANE_FORMAT_LINEAR_TP_10_Y, + PLANE_FORMAT_LINEAR_TP_10_C, + PLANE_FORMAT_LINEAR_P010_Y, + PLANE_FORMAT_LINEAR_P010_C, + PLANE_FORMAT_LINEAR_NV12_Y, + PLANE_FORMAT_LINEAR_NV12_C, + PLANE_FORMAT_LINEAR_PLAIN_16_Y, + PLANE_FORMAT_LINEAR_PLAIN_16_C, + PLANE_FORMAT_YUV422_8, + PLANE_FORMAT_YUV422_10, + PLANE_FORMAT_STATISTICS_BAYER_GRID, + PLANE_FORMAT_STATISTICS_BAYER_HISTOGRAM, + PLANE_FORMAT_MAX +}; + +enum hfi_ipe_bayer_pixel_order { + FIRST_PIXEL_R, + FIRST_PIXEL_GR, + FIRST_PIXEL_B, + FIRST_PIXEL_GB, + FIRST_PIXEL_MAX +}; + +enum hfi_ipe_pixel_pack_alignment { + PIXEL_LSB_ALIGNED, + PIXEL_MSB_ALIGNED, +}; + +enum hfi_ipe_yuv_422_order { + PIXEL_ORDER_Y_U_Y_V, + PIXEL_ORDER_Y_V_Y_U, + PIXEL_ORDER_U_Y_V_Y, + PIXEL_ORDER_V_Y_U_Y, + PIXEL_ORDER_YUV422_MAX +}; + +enum ubwc_write_client { + IPE_WR_CLIENT_0 = 0, + IPE_WR_CLIENT_1, + IPE_WR_CLIENT_5, + IPE_WR_CLIENT_6, + IPE_WR_CLIENT_7, + IPE_WR_CLIENT_8, + IPE_WR_CLIENT_MAX +}; + +/** + * struct image_info + * @format: image format + * @img_width: image width + * @img_height: image height + * @bayer_order: pixel order + * @pix_align: alignment + * @yuv422_order: YUV order + * @byte_swap: byte swap + */ +struct image_info { + enum hfi_ipe_image_format format; + uint32_t img_width; + uint32_t img_height; + enum hfi_ipe_bayer_pixel_order bayer_order; + enum hfi_ipe_pixel_pack_alignment pix_align; + enum hfi_ipe_yuv_422_order yuv422_order; + uint32_t byte_swap; +} __packed; + +/** + * struct buffer_layout + * @buf_stride: buffer stride + * @buf_height: buffer height + */ +struct buffer_layout { + uint32_t buf_stride; + uint32_t buf_height; +} __packed; + +/** + * struct image_desc + * @info: image info + * @buf_layout: buffer layout + * @meta_buf_layout: meta buffer layout + */ +struct image_desc { + struct image_info info; + struct buffer_layout buf_layout[MAX_NUM_OF_IMAGE_PLANES]; + struct buffer_layout meta_buf_layout[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +struct ica_stab_coeff { + uint32_t coeffs[8]; +} __packed; + +struct ica_stab_params { + uint32_t mode; + struct ica_stab_coeff transforms[3]; +} __packed; + +struct frame_set { + struct frame_buffer buffers[IPE_IO_IMAGES_MAX]; + uint32_t cdm_ica1_addr; + uint32_t cdm_ica2_addr; +} __packed; + +struct ipe_frame_process_data { + uint32_t strip_lib_out_addr; + uint32_t iq_settings_addr; + uint32_t scratch_buffer_addr; + uint32_t scratch_buffer_size; + uint32_t ubwc_stats_buffer_addr; + uint32_t ubwc_stats_buffer_size; + uint32_t cdm_buffer_addr; + uint32_t cdm_buffer_size; + uint32_t max_num_cores; + uint32_t target_time; + uint32_t cdm_prog_base; + uint32_t cdm_pre_ltm; + uint32_t cdm_post_ltm; + uint32_t cdm_anr_full_pass; + uint32_t cdm_anr_ds4; + uint32_t cdm_anr_ds16; + uint32_t cdm_anr_ds64; + uint32_t cdm_tf_full_pass; + uint32_t cdm_tf_ds4; + uint32_t cdm_tf_ds16; + uint32_t cdm_tf_ds64; + uint32_t cdm_dsx_dc4; + uint32_t cdm_dsx_dc16; + uint32_t cdm_dsz_dc64; + uint32_t cdm_mfhdr_full_pass; + uint32_t cdm_mfhdr_dcx; + uint32_t request_id; + uint32_t frames_in_batch; + struct frame_set framesets[MAX_HFR_GROUP]; +} __packed; + +/** + * struct hfi_cmd_ipe_config + * @images: images descreptions + * @user_data: user supplied data + * + * payload for IPE async command + */ +struct hfi_cmd_ipe_config { + struct image_desc images[IPE_IO_IMAGES_MAX]; + uint64_t user_data; +} __packed; + +/** + * struct frame_buffers + * @buf_ptr: buffer pointers for all planes + * @meta_buf_ptr: meta buffer pointers for all planes + */ +struct frame_buffers { + uint32_t buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; + uint32_t meta_buf_ptr[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +/** + * struct hfi_msg_ipe_config + * @rc: result of ipe config command + * @scratch_mem_size: scratch mem size for a config + * @user_data: user data + */ +struct hfi_msg_ipe_config { + uint32_t rc; + uint32_t scratch_mem_size; + uint64_t user_data; +} __packed; + +/** + * struct hfi_msg_bps_common + * @rc: result of ipe config command + * @user_data: user data + */ +struct hfi_msg_bps_common { + uint32_t rc; + uint64_t user_data; +} __packed; + +/** + * struct ipe_bps_destroy + * @user_data: user data + */ +struct ipe_bps_destroy { + uint64_t userdata; +}; + +/** + * struct hfi_msg_ipe_frame_process + * @status: result of ipe frame process command + * @scratch_buf_addr: address of scratch buffer + * @user_data: user data + */ +struct hfi_msg_ipe_frame_process { + uint32_t status; + uint32_t scratch_buf_addr; + uint64_t user_data; +} __packed; + +#endif /* _CAM_HFI_SESSION_DEFS_H */ diff --git a/techpack/camera/drivers/cam_icp/fw_inc/hfi_sys_defs.h b/techpack/camera/drivers/cam_icp/fw_inc/hfi_sys_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..a4f19bf404a5f71fd26adf9f3b37bdbb7dc72583 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/fw_inc/hfi_sys_defs.h @@ -0,0 +1,559 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _HFI_DEFS_H_ +#define _HFI_DEFS_H_ + +#include <linux/types.h> + +/* + * Following base acts as common starting points + * for all enumerations. + */ +#define HFI_COMMON_BASE 0x0 + +/* HFI Domain base offset for commands and messages */ +#define HFI_DOMAIN_SHFT (24) +#define HFI_DOMAIN_BMSK (0x7 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_ICP (0x0 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_IPE_BPS (0x1 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_CDM (0x2 << HFI_DOMAIN_SHFT) +#define HFI_DOMAIN_BASE_DBG (0x3 << HFI_DOMAIN_SHFT) + +/* Command base offset for commands */ +#define HFI_CMD_START_OFFSET 0x10000 + +/* Command base offset for messages */ +#define HFI_MSG_START_OFFSET 0x20000 + +/* System Level Error types */ +#define HFI_ERR_SYS_NONE (HFI_COMMON_BASE) +#define HFI_ERR_SYS_FATAL (HFI_COMMON_BASE + 0x1) +#define HFI_ERR_SYS_VERSION_MISMATCH (HFI_COMMON_BASE + 0x2) +#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN (HFI_COMMON_BASE + 0x3) +#define HFI_ERR_SYS_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x4) +#define HFI_ERR_SYS_CMDFAILED (HFI_COMMON_BASE + 0x5) +#define HFI_ERR_SYS_CMDSIZE (HFI_COMMON_BASE + 0x6) + +/* System Level Event types */ +#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1) +#define HFI_EVENT_ICP_ERROR (HFI_COMMON_BASE + 0x2) +#define HFI_EVENT_IPE_BPS_ERROR (HFI_COMMON_BASE + 0x3) +#define HFI_EVENT_CDM_ERROR (HFI_COMMON_BASE + 0x4) +#define HFI_EVENT_DBG_ERROR (HFI_COMMON_BASE + 0x5) + +/* Core level start Ranges for errors */ +#define HFI_ERR_ICP_START (HFI_COMMON_BASE + 0x64) +#define HFI_ERR_IPE_BPS_START (HFI_ERR_ICP_START + 0x64) +#define HFI_ERR_CDM_START (HFI_ERR_IPE_BPS_START + 0x64) +#define HFI_ERR_DBG_START (HFI_ERR_CDM_START + 0x64) + +/*ICP Core level error messages */ +#define HFI_ERR_NO_RES (HFI_ERR_ICP_START + 0x1) +#define HFI_ERR_UNSUPPORTED_RES (HFI_ERR_ICP_START + 0x2) +#define HFI_ERR_UNSUPPORTED_PROP (HFI_ERR_ICP_START + 0x3) +#define HFI_ERR_INIT_EXPECTED (HFI_ERR_ICP_START + 0x4) +#define HFI_ERR_INIT_IGNORED (HFI_ERR_ICP_START + 0x5) + +/* System level commands */ +#define HFI_CMD_COMMON_START \ + (HFI_DOMAIN_BASE_ICP + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_SYS_INIT (HFI_CMD_COMMON_START + 0x1) +#define HFI_CMD_SYS_PC_PREP (HFI_CMD_COMMON_START + 0x2) +#define HFI_CMD_SYS_SET_PROPERTY (HFI_CMD_COMMON_START + 0x3) +#define HFI_CMD_SYS_GET_PROPERTY (HFI_CMD_COMMON_START + 0x4) +#define HFI_CMD_SYS_PING (HFI_CMD_COMMON_START + 0x5) +#define HFI_CMD_SYS_RESET (HFI_CMD_COMMON_START + 0x6) + +/* General Frame process errors */ +#define CAMERAICP_SUCCESS 0 +#define CAMERAICP_EFAILED 1 +#define CAMERAICP_ENOMEMORY 2 +#define CAMERAICP_EBADSTATE 3 +#define CAMERAICP_EBADPARM 4 +#define CAMERAICP_EBADITEM 5 +#define CAMERAICP_EINVALIDFORMAT 6 +#define CAMERAICP_EUNSUPPORTED 7 +#define CAMERAICP_EOUTOFBOUND 8 +#define CAMERAICP_ETIMEDOUT 9 +#define CAMERAICP_EABORTED 10 +#define CAMERAICP_EHWVIOLATION 11 +#define CAMERAICP_ECDMERROR 12 + +/* Core level commands */ +/* IPE/BPS core Commands */ +#define HFI_CMD_IPE_BPS_COMMON_START \ + (HFI_DOMAIN_BASE_IPE_BPS + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_IPEBPS_CREATE_HANDLE \ + (HFI_CMD_IPE_BPS_COMMON_START + 0x8) +#define HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT \ + (HFI_CMD_IPE_BPS_COMMON_START + 0xa) +#define HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT \ + (HFI_CMD_IPE_BPS_COMMON_START + 0xe) + +/* CDM core Commands */ +#define HFI_CMD_CDM_COMMON_START \ + (HFI_DOMAIN_BASE_CDM + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_CDM_TEST_START (HFI_CMD_CDM_COMMON_START + 0x800) +#define HFI_CMD_CDM_END (HFI_CMD_CDM_COMMON_START + 0xFFF) + +/* Debug/Test Commands */ +#define HFI_CMD_DBG_COMMON_START \ + (HFI_DOMAIN_BASE_DBG + HFI_CMD_START_OFFSET + 0x0) +#define HFI_CMD_DBG_TEST_START (HFI_CMD_DBG_COMMON_START + 0x800) +#define HFI_CMD_DBG_END (HFI_CMD_DBG_COMMON_START + 0xFFF) + +/* System level messages */ +#define HFI_MSG_ICP_COMMON_START \ + (HFI_DOMAIN_BASE_ICP + HFI_MSG_START_OFFSET + 0x0) +#define HFI_MSG_SYS_INIT_DONE (HFI_MSG_ICP_COMMON_START + 0x1) +#define HFI_MSG_SYS_PC_PREP_DONE (HFI_MSG_ICP_COMMON_START + 0x2) +#define HFI_MSG_SYS_DEBUG (HFI_MSG_ICP_COMMON_START + 0x3) +#define HFI_MSG_SYS_IDLE (HFI_MSG_ICP_COMMON_START + 0x4) +#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_ICP_COMMON_START + 0x5) +#define HFI_MSG_SYS_PING_ACK (HFI_MSG_ICP_COMMON_START + 0x6) +#define HFI_MSG_SYS_RESET_ACK (HFI_MSG_ICP_COMMON_START + 0x7) +#define HFI_MSG_EVENT_NOTIFY (HFI_MSG_ICP_COMMON_START + 0x8) + +/* Core level Messages */ +/* IPE/BPS core Messages */ +#define HFI_MSG_IPE_BPS_COMMON_START \ + (HFI_DOMAIN_BASE_IPE_BPS + HFI_MSG_START_OFFSET + 0x0) +#define HFI_MSG_IPEBPS_CREATE_HANDLE_ACK \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x08) +#define HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x0a) +#define HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x0e) +#define HFI_MSG_IPE_BPS_TEST_START \ + (HFI_MSG_IPE_BPS_COMMON_START + 0x800) +#define HFI_MSG_IPE_BPS_END \ + (HFI_MSG_IPE_BPS_COMMON_START + 0xFFF) + +/* CDM core Messages */ +#define HFI_MSG_CDM_COMMON_START \ + (HFI_DOMAIN_BASE_CDM + HFI_MSG_START_OFFSET + 0x0) +#define HFI_MSG_PRI_CDM_PAYLOAD_ACK (HFI_MSG_CDM_COMMON_START + 0xa) +#define HFI_MSG_PRI_LLD_PAYLOAD_ACK (HFI_MSG_CDM_COMMON_START + 0xb) +#define HFI_MSG_CDM_TEST_START (HFI_MSG_CDM_COMMON_START + 0x800) +#define HFI_MSG_CDM_END (HFI_MSG_CDM_COMMON_START + 0xFFF) + +/* core level test command ranges */ +/* ICP core level test command range */ +#define HFI_CMD_ICP_TEST_START (HFI_CMD_ICP_COMMON_START + 0x800) +#define HFI_CMD_ICP_END (HFI_CMD_ICP_COMMON_START + 0xFFF) + +/* IPE/BPS core level test command range */ +#define HFI_CMD_IPE_BPS_TEST_START \ + (HFI_CMD_IPE_BPS_COMMON_START + 0x800) +#define HFI_CMD_IPE_BPS_END (HFI_CMD_IPE_BPS_COMMON_START + 0xFFF) + +/* ICP core level test message range */ +#define HFI_MSG_ICP_TEST_START (HFI_MSG_ICP_COMMON_START + 0x800) +#define HFI_MSG_ICP_END (HFI_MSG_ICP_COMMON_START + 0xFFF) + +/* ICP core level Debug test message range */ +#define HFI_MSG_DBG_COMMON_START \ + (HFI_DOMAIN_BASE_DBG + 0x0) +#define HFI_MSG_DBG_TEST_START (HFI_MSG_DBG_COMMON_START + 0x800) +#define HFI_MSG_DBG_END (HFI_MSG_DBG_COMMON_START + 0xFFF) + +/* System level property base offset */ +#define HFI_PROPERTY_ICP_COMMON_START (HFI_DOMAIN_BASE_ICP + 0x0) + +#define HFI_PROP_SYS_DEBUG_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x1) +#define HFI_PROP_SYS_UBWC_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x2) +#define HFI_PROP_SYS_IMAGE_VER (HFI_PROPERTY_ICP_COMMON_START + 0x3) +#define HFI_PROP_SYS_SUPPORTED (HFI_PROPERTY_ICP_COMMON_START + 0x4) +#define HFI_PROP_SYS_IPEBPS_PC (HFI_PROPERTY_ICP_COMMON_START + 0x5) +#define HFI_PROP_SYS_FW_DUMP_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x8) +#define HFI_PROPERTY_SYS_UBWC_CONFIG_EX (HFI_PROPERTY_ICP_COMMON_START + 0x9) + +/* Capabilities reported at sys init */ +#define HFI_CAPS_PLACEHOLDER_1 (HFI_COMMON_BASE + 0x1) +#define HFI_CAPS_PLACEHOLDER_2 (HFI_COMMON_BASE + 0x2) + +/* Section describes different debug levels (HFI_DEBUG_MSG_X) + * available for debug messages from FW + */ +#define HFI_DEBUG_MSG_LOW 0x00000001 +#define HFI_DEBUG_MSG_MEDIUM 0x00000002 +#define HFI_DEBUG_MSG_HIGH 0x00000004 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +/* Messages containing performance data */ +#define HFI_DEBUG_MSG_PERF 0x00000020 +/* Disable ARM9 WFI in low power mode. */ +#define HFI_DEBUG_CFG_WFI 0x01000000 +/* Disable ARM9 watchdog. */ +#define HFI_DEBUG_CFG_ARM9WD 0x10000000 + + +/* + * HFI_FW_DUMP levels + * HFI_FW_DUMP_xx + */ +#define HFI_FW_DUMP_DISABLED 0x00000000 +#define HFI_FW_DUMP_ON_FAILURE 0x00000001 +#define HFI_FW_DUMP_ALWAYS 0x00000002 + +/* Number of available dump levels. */ +#define NUM_HFI_DUMP_LVL 0x00000003 + +/* Debug Msg Communication types: + * Section describes different modes (HFI_DEBUG_MODE_X) + * available to communicate the debug messages + */ + /* Debug message output through the interface debug queue. */ +#define HFI_DEBUG_MODE_QUEUE 0x00000001 + /* Debug message output through QDSS. */ +#define HFI_DEBUG_MODE_QDSS 0x00000002 + /* Number of debug modes available. */ +#define NUM_HFI_DEBUG_MODE 0x00000002 + +#define HFI_DEBUG_MSG_LOW 0x00000001 +#define HFI_DEBUG_MSG_MEDIUM 0x00000002 +#define HFI_DEBUG_MSG_HIGH 0x00000004 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +#define HFI_DEBUG_MSG_PERF 0x00000020 +#define HFI_DEBUG_CFG_WFI 0x01000000 +#define HFI_DEBUG_CFG_ARM9WD 0x10000000 + +#define HFI_DEV_VERSION_MAX 0x5 + +/* Hang dump settings */ +#define HFI_SET_HANG_DUMP_ALWAYS 0x2 +#define HFI_SET_HANG_DUMP_ON_FAILURE 0x1 + +/** + * start of sys command packet types + * These commands are used to get system level information + * from firmware + */ + +/** + * struct hfi_caps_support + * payload to report caps through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED + * @type: capability type + * @min: minimum supported value for the capability + * @max: maximum supported value for the capability + * @step_size: supported steps between min-max + */ +struct hfi_caps_support { + uint32_t type; + uint32_t min; + uint32_t max; + uint32_t step_size; +} __packed; + +/** + * struct hfi_caps_support_info + * capability report through HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED + * @num_caps: number of capabilities listed + * @caps_data: capabilities info array + */ +struct hfi_caps_support_info { + uint32_t num_caps; + struct hfi_caps_support caps_data[1]; +} __packed; + +/** + * struct hfi_debug + * payload structure to configure HFI_PROPERTY_SYS_DEBUG_CONFIG + * @debug_config: it is a result of HFI_DEBUG_MSG_X values that + * are OR-ed together to specify the debug message types + * to otput + * @debug_mode: debug message output through debug queue/qdss + * @HFI_PROPERTY_SYS_DEBUG_CONFIG + */ +struct hfi_debug { + uint32_t debug_config; + uint32_t debug_mode; +} __packed; + +/** + * struct hfi_ipe_bps_pc + * payload structure to configure HFI_PROPERTY_SYS_IPEBPS_PC + * @enable: Flag to enable IPE, BPS interfrane power collapse + * @core_info: Core information to firmware + */ +struct hfi_ipe_bps_pc { + uint32_t enable; + uint32_t core_info; +} __packed; + +/** + * struct hfi_cmd_ubwc_cfg + * Payload structure to configure HFI_PROP_SYS_UBWC_CFG + * @ubwc_fetch_cfg: UBWC configuration for fecth + * @ubwc_write_cfg: UBWC configuration for write + */ +struct hfi_cmd_ubwc_cfg { + uint32_t ubwc_fetch_cfg; + uint32_t ubwc_write_cfg; +} __packed; + +/** + * struct hfi_cmd_ubwc_cfg_ext + * Payload structure to configure HFI_UBWC_CFG_TYPE_EXT + * @bps: UBWC configuration for bps + * @ipe: UBWC configuration for ipe + */ +struct hfi_cmd_ubwc_cfg_ext { + struct hfi_cmd_ubwc_cfg bps; + struct hfi_cmd_ubwc_cfg ipe; +} __packed; + +/** + * struct hfi_cmd_sys_init + * command to initialization of system session + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @HFI_CMD_SYS_INIT + */ +struct hfi_cmd_sys_init { + uint32_t size; + uint32_t pkt_type; +} __packed; + +/** + * struct hfi_cmd_pc_prep + * command to firmware to prepare for power collapse + * @eize: packet size in bytes + * @pkt_type: opcode of a packet + * @HFI_CMD_SYS_PC_PREP + */ +struct hfi_cmd_pc_prep { + uint32_t size; + uint32_t pkt_type; +} __packed; + +/** + * struct hfi_cmd_prop + * command to get/set properties of firmware + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @num_prop: number of properties queried/set + * @prop_data: array of property IDs being queried. size depends on num_prop + * array of property IDs and associated structure pairs in set + * @HFI_CMD_SYS_GET_PROPERTY + * @HFI_CMD_SYS_SET_PROPERTY + */ +struct hfi_cmd_prop { + uint32_t size; + uint32_t pkt_type; + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_cmd_ping_pkt + * ping command pings the firmware to confirm whether + * it is alive. + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @user_data: client data, firmware returns this data + * as part of HFI_MSG_SYS_PING_ACK + * @HFI_CMD_SYS_PING + */ +struct hfi_cmd_ping_pkt { + uint32_t size; + uint32_t pkt_type; + uint64_t user_data; +} __packed; + +/** + * struct hfi_cmd_sys_reset_pkt + * sends the reset command to FW. FW responds in the same type + * of packet. so can be used for reset_ack_pkt type also + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @user_data: client data, firmware returns this data + * as part of HFI_MSG_SYS_RESET_ACK + * @HFI_CMD_SYS_RESET + */ + +struct hfi_cmd_sys_reset_pkt { + uint32_t size; + uint32_t pkt_type; + uint64_t user_data; +} __packed; + +/* end of sys command packet types */ + +/* start of sys message packet types */ + +/** + * struct hfi_prop + * structure to report maximum supported features of firmware. + */ +struct hfi_sys_support { + uint32_t place_holder; +} __packed; + +/** + * struct hfi_supported_prop + * structure to report HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED + * for a session + * @num_prop: number of properties supported + * @prop_data: array of supported property IDs + */ +struct hfi_supported_prop { + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_image_version + * system image version + * @major: major version number + * @minor: minor version number + * @ver_name_size: size of version name + * @ver_name: image version name + */ +struct hfi_image_version { + uint32_t major; + uint32_t minor; + uint32_t ver_name_size; + uint8_t ver_name[1]; +} __packed; + +/** + * struct hfi_msg_init_done_data + * @api_ver: Firmware API version + * @dev_ver: Device version + * @num_icp_hw: Number of ICP hardware information + * @dev_hw_ver: Supported hardware version information + * @reserved: Reserved field + */ +struct hfi_msg_init_done_data { + uint32_t api_ver; + uint32_t dev_ver; + uint32_t num_icp_hw; + uint32_t dev_hw_ver[HFI_DEV_VERSION_MAX]; + uint32_t reserved; +}; + +/** + * struct hfi_msg_init_done + * system init done message from firmware. Many system level properties + * are returned with the packet + * @size: Packet size in bytes + * @pkt_type: Opcode of a packet + * @err_type: Error code associated with response + * @num_prop: Number of default capability info + * @prop_data: Array of property ids and corresponding structure pairs + */ +struct hfi_msg_init_done { + uint32_t size; + uint32_t pkt_type; + uint32_t err_type; + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_msg_pc_prep_done + * system power collapse preparation done message + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @err_type: error code associated with the response + */ +struct hfi_msg_pc_prep_done { + uint32_t size; + uint32_t pkt_type; + uint32_t err_type; +} __packed; + +/** + * struct hfi_msg_prop + * system property info from firmware + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @num_prop: number of property info structures + * @prop_data: array of property IDs and associated structure pairs + */ +struct hfi_msg_prop { + uint32_t size; + uint32_t pkt_type; + uint32_t num_prop; + uint32_t prop_data[1]; +} __packed; + +/** + * struct hfi_msg_idle + * system idle message from firmware + * @size: packet size in bytes + * @pkt_type: opcode of a packet + */ +struct hfi_msg_idle { + uint32_t size; + uint32_t pkt_type; +} __packed; + +/** + * struct hfi_msg_ping_ack + * system ping ack message + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @user_data: this data is sent as part of ping command from host + */ +struct hfi_msg_ping_ack { + uint32_t size; + uint32_t pkt_type; + uint64_t user_data; +} __packed; + +/** + * struct hfi_msg_debug + * system debug message defination + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @msg_type: debug message type + * @msg_size: size of debug message in bytes + * @timestamp_hi: most significant 32 bits of the 64 bit timestamp field. + * timestamp shall be interpreted as a signed 64-bit value + * representing microseconds. + * @timestamp_lo: least significant 32 bits of the 64 bit timestamp field. + * timestamp shall be interpreted as a signed 64-bit value + * representing microseconds. + * @msg_data: message data in string form + */ +struct hfi_msg_debug { + uint32_t size; + uint32_t pkt_type; + uint32_t msg_type; + uint32_t msg_size; + uint32_t timestamp_hi; + uint32_t timestamp_lo; + uint8_t msg_data[1]; +} __packed; +/** + * struct hfi_msg_event_notify + * event notify message + * @size: packet size in bytes + * @pkt_type: opcode of a packet + * @fw_handle: firmware session handle + * @event_id: session event id + * @event_data1: event data corresponding to event ID + * @event_data2: event data corresponding to event ID + * @ext_event_data: info array, interpreted based on event_data1 + * and event_data2 + */ +struct hfi_msg_event_notify { + uint32_t size; + uint32_t pkt_type; + uint32_t fw_handle; + uint32_t event_id; + uint32_t event_data1; + uint32_t event_data2; + uint32_t ext_event_data[1]; +} __packed; +/** + * end of sys message packet types + */ + +#endif /* _HFI_DEFS_H_ */ diff --git a/techpack/camera/drivers/cam_icp/hfi.c b/techpack/camera/drivers/cam_icp/hfi.c new file mode 100644 index 0000000000000000000000000000000000000000..c03aa58bb8f39acc8c4dda75b3045364d7c7e781 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/hfi.c @@ -0,0 +1,956 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <asm/errno.h> +#include <linux/timer.h> +#include <media/cam_icp.h> +#include <linux/iopoll.h> + +#include "cam_io_util.h" +#include "hfi_reg.h" +#include "hfi_sys_defs.h" +#include "hfi_session_defs.h" +#include "hfi_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_debug_util.h" + +#define HFI_VERSION_INFO_MAJOR_VAL 1 +#define HFI_VERSION_INFO_MINOR_VAL 1 +#define HFI_VERSION_INFO_STEP_VAL 0 +#define HFI_VERSION_INFO_STEP_VAL 0 +#define HFI_VERSION_INFO_MAJOR_BMSK 0xFF000000 +#define HFI_VERSION_INFO_MAJOR_SHFT 24 +#define HFI_VERSION_INFO_MINOR_BMSK 0xFFFF00 +#define HFI_VERSION_INFO_MINOR_SHFT 8 +#define HFI_VERSION_INFO_STEP_BMSK 0xFF +#define HFI_VERSION_INFO_STEP_SHFT 0 + +#define HFI_MAX_POLL_TRY 5 + +#define HFI_MAX_PC_POLL_TRY 150 +#define HFI_POLL_TRY_SLEEP 1 + +static struct hfi_info *g_hfi; +unsigned int g_icp_mmu_hdl; +static DEFINE_MUTEX(hfi_cmd_q_mutex); +static DEFINE_MUTEX(hfi_msg_q_mutex); + +void cam_hfi_queue_dump(void) +{ + struct hfi_qtbl *qtbl; + struct hfi_qtbl_hdr *qtbl_hdr; + struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr; + struct hfi_mem_info *hfi_mem = NULL; + uint32_t *read_q, *read_ptr; + int i; + + hfi_mem = &g_hfi->map; + if (!hfi_mem) { + CAM_ERR(CAM_HFI, "Unable to dump queues hfi memory is NULL"); + return; + } + + qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; + qtbl_hdr = &qtbl->q_tbl_hdr; + CAM_DBG(CAM_HFI, + "qtbl: version = %x size = %u num q = %u qhdr_size = %u", + qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size, + qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size); + + cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; + CAM_DBG(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", + cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx, + cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova); + read_q = (uint32_t *)g_hfi->map.cmd_q.kva; + read_ptr = (uint32_t *)(read_q + 0); + CAM_DBG(CAM_HFI, "CMD Q START"); + for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + + msg_q_hdr = &qtbl->q_hdr[Q_MSG]; + CAM_DBG(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", + msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx, + msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova); + read_q = (uint32_t *)g_hfi->map.msg_q.kva; + read_ptr = (uint32_t *)(read_q + 0); + CAM_DBG(CAM_HFI, "MSG Q START"); + for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) + CAM_DBG(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); +} + +int hfi_write_cmd(void *cmd_ptr) +{ + uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp; + uint32_t *write_q, *write_ptr; + struct hfi_qtbl *q_tbl; + struct hfi_q_hdr *q; + int rc = 0; + + if (!cmd_ptr) { + CAM_ERR(CAM_HFI, "command is null"); + return -EINVAL; + } + + mutex_lock(&hfi_cmd_q_mutex); + if (!g_hfi) { + CAM_ERR(CAM_HFI, "HFI interface not setup"); + rc = -ENODEV; + goto err; + } + + if (g_hfi->hfi_state != HFI_READY || + !g_hfi->cmd_q_state) { + CAM_ERR(CAM_HFI, "HFI state: %u, cmd q state: %u", + g_hfi->hfi_state, g_hfi->cmd_q_state); + rc = -ENODEV; + goto err; + } + + q_tbl = (struct hfi_qtbl *)g_hfi->map.qtbl.kva; + q = &q_tbl->q_hdr[Q_CMD]; + + write_q = (uint32_t *)g_hfi->map.cmd_q.kva; + + size_in_words = (*(uint32_t *)cmd_ptr) >> BYTE_WORD_SHIFT; + if (!size_in_words) { + CAM_DBG(CAM_HFI, "failed"); + rc = -EINVAL; + goto err; + } + + read_idx = q->qhdr_read_idx; + empty_space = (q->qhdr_write_idx >= read_idx) ? + (q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) : + (read_idx - q->qhdr_write_idx); + if (empty_space <= size_in_words) { + CAM_ERR(CAM_HFI, "failed: empty space %u, size_in_words %u", + empty_space, size_in_words); + rc = -EIO; + goto err; + } + + new_write_idx = q->qhdr_write_idx + size_in_words; + write_ptr = (uint32_t *)(write_q + q->qhdr_write_idx); + + if (new_write_idx < q->qhdr_q_size) { + memcpy(write_ptr, (uint8_t *)cmd_ptr, + size_in_words << BYTE_WORD_SHIFT); + } else { + new_write_idx -= q->qhdr_q_size; + temp = (size_in_words - new_write_idx) << BYTE_WORD_SHIFT; + memcpy(write_ptr, (uint8_t *)cmd_ptr, temp); + memcpy(write_q, (uint8_t *)cmd_ptr + temp, + new_write_idx << BYTE_WORD_SHIFT); + } + + /* + * To make sure command data in a command queue before + * updating write index + */ + wmb(); + + q->qhdr_write_idx = new_write_idx; + + /* + * Before raising interrupt make sure command data is ready for + * firmware to process + */ + wmb(); + cam_io_w_mb((uint32_t)INTR_ENABLE, + g_hfi->csr_base + HFI_REG_A5_CSR_HOST2ICPINT); +err: + mutex_unlock(&hfi_cmd_q_mutex); + return rc; +} + +int hfi_read_message(uint32_t *pmsg, uint8_t q_id, + uint32_t *words_read) +{ + struct hfi_qtbl *q_tbl_ptr; + struct hfi_q_hdr *q; + uint32_t new_read_idx, size_in_words, word_diff, temp; + uint32_t *read_q, *read_ptr, *write_ptr; + uint32_t size_upper_bound = 0; + int rc = 0; + + if (!pmsg) { + CAM_ERR(CAM_HFI, "Invalid msg"); + return -EINVAL; + } + + if (q_id > Q_DBG) { + CAM_ERR(CAM_HFI, "Invalid q :%u", q_id); + return -EINVAL; + } + + mutex_lock(&hfi_msg_q_mutex); + if (!g_hfi) { + CAM_ERR(CAM_HFI, "hfi not set up yet"); + rc = -ENODEV; + goto err; + } + + if ((g_hfi->hfi_state != HFI_READY) || + !g_hfi->msg_q_state) { + CAM_ERR(CAM_HFI, "hfi state: %u, msg q state: %u", + g_hfi->hfi_state, g_hfi->msg_q_state); + rc = -ENODEV; + goto err; + } + + q_tbl_ptr = (struct hfi_qtbl *)g_hfi->map.qtbl.kva; + q = &q_tbl_ptr->q_hdr[q_id]; + + if (q->qhdr_read_idx == q->qhdr_write_idx) { + CAM_DBG(CAM_HFI, "Q not ready, state:%u, r idx:%u, w idx:%u", + g_hfi->hfi_state, q->qhdr_read_idx, q->qhdr_write_idx); + rc = -EIO; + goto err; + } + + if (q_id == Q_MSG) { + read_q = (uint32_t *)g_hfi->map.msg_q.kva; + size_upper_bound = ICP_HFI_MAX_PKT_SIZE_MSGQ_IN_WORDS; + } else { + read_q = (uint32_t *)g_hfi->map.dbg_q.kva; + size_upper_bound = ICP_HFI_MAX_PKT_SIZE_IN_WORDS; + } + + read_ptr = (uint32_t *)(read_q + q->qhdr_read_idx); + write_ptr = (uint32_t *)(read_q + q->qhdr_write_idx); + + if (write_ptr > read_ptr) + size_in_words = write_ptr - read_ptr; + else { + word_diff = read_ptr - write_ptr; + if (q_id == Q_MSG) + size_in_words = (ICP_MSG_Q_SIZE_IN_BYTES >> + BYTE_WORD_SHIFT) - word_diff; + else + size_in_words = (ICP_DBG_Q_SIZE_IN_BYTES >> + BYTE_WORD_SHIFT) - word_diff; + } + + if ((size_in_words == 0) || + (size_in_words > size_upper_bound)) { + CAM_ERR(CAM_HFI, "invalid HFI message packet size - 0x%08x", + size_in_words << BYTE_WORD_SHIFT); + q->qhdr_read_idx = q->qhdr_write_idx; + rc = -EIO; + goto err; + } + + new_read_idx = q->qhdr_read_idx + size_in_words; + + if (new_read_idx < q->qhdr_q_size) { + memcpy(pmsg, read_ptr, size_in_words << BYTE_WORD_SHIFT); + } else { + new_read_idx -= q->qhdr_q_size; + temp = (size_in_words - new_read_idx) << BYTE_WORD_SHIFT; + memcpy(pmsg, read_ptr, temp); + memcpy((uint8_t *)pmsg + temp, read_q, + new_read_idx << BYTE_WORD_SHIFT); + } + + q->qhdr_read_idx = new_read_idx; + *words_read = size_in_words; + /* Memory Barrier to make sure message + * queue parameters are updated after read + */ + wmb(); +err: + mutex_unlock(&hfi_msg_q_mutex); + return rc; +} + +int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_cmd_ubwc_cfg); + + CAM_DBG(CAM_HFI, + "size of ubwc %u, ubwc_cfg [rd-0x%x,wr-0x%x]", + size, ubwc_cfg[0], ubwc_cfg[1]); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROP_SYS_UBWC_CFG; + dbg_prop->prop_data[1] = ubwc_cfg[0]; + dbg_prop->prop_data[2] = ubwc_cfg[1]; + + hfi_write_cmd(prop); + kfree(prop); + + return 0; +} + +int hfi_cmd_ubwc_config_ext(uint32_t *ubwc_ipe_cfg, + uint32_t *ubwc_bps_cfg) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_cmd_ubwc_cfg_ext); + + CAM_DBG(CAM_HFI, + "size of ubwc %u, ubwc_ipe_cfg[rd-0x%x,wr-0x%x] ubwc_bps_cfg[rd-0x%x,wr-0x%x]", + size, ubwc_ipe_cfg[0], ubwc_ipe_cfg[1], + ubwc_bps_cfg[0], ubwc_bps_cfg[1]); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG_EX; + dbg_prop->prop_data[1] = ubwc_bps_cfg[0]; + dbg_prop->prop_data[2] = ubwc_bps_cfg[1]; + dbg_prop->prop_data[3] = ubwc_ipe_cfg[0]; + dbg_prop->prop_data[4] = ubwc_ipe_cfg[1]; + + hfi_write_cmd(prop); + kfree(prop); + + return 0; +} + + +int hfi_enable_ipe_bps_pc(bool enable, uint32_t core_info) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_ipe_bps_pc); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROP_SYS_IPEBPS_PC; + dbg_prop->prop_data[1] = enable; + dbg_prop->prop_data[2] = core_info; + + hfi_write_cmd(prop); + kfree(prop); + + return 0; +} + +int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl) +{ + uint8_t *prop; + struct hfi_cmd_prop *dbg_prop; + uint32_t size = 0, val; + + val = HFI_DEBUG_MSG_LOW | + HFI_DEBUG_MSG_MEDIUM | + HFI_DEBUG_MSG_HIGH | + HFI_DEBUG_MSG_ERROR | + HFI_DEBUG_MSG_FATAL | + HFI_DEBUG_MSG_PERF | + HFI_DEBUG_CFG_WFI | + HFI_DEBUG_CFG_ARM9WD; + + if (lvl > val) + return -EINVAL; + + size = sizeof(struct hfi_cmd_prop) + + sizeof(struct hfi_debug); + + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + dbg_prop = (struct hfi_cmd_prop *)prop; + dbg_prop->size = size; + dbg_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + dbg_prop->num_prop = 1; + dbg_prop->prop_data[0] = HFI_PROP_SYS_DEBUG_CFG; + dbg_prop->prop_data[1] = lvl; + dbg_prop->prop_data[2] = a5_dbg_type; + hfi_write_cmd(prop); + + kfree(prop); + + return 0; +} + +int hfi_set_fw_dump_level(uint32_t lvl) +{ + uint8_t *prop = NULL; + struct hfi_cmd_prop *fw_dump_level_switch_prop = NULL; + uint32_t size = 0; + + CAM_DBG(CAM_HFI, "fw dump ENTER"); + + size = sizeof(struct hfi_cmd_prop) + sizeof(lvl); + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + fw_dump_level_switch_prop = (struct hfi_cmd_prop *)prop; + fw_dump_level_switch_prop->size = size; + fw_dump_level_switch_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + fw_dump_level_switch_prop->num_prop = 1; + fw_dump_level_switch_prop->prop_data[0] = HFI_PROP_SYS_FW_DUMP_CFG; + fw_dump_level_switch_prop->prop_data[1] = (lvl > HFI_SET_HANG_DUMP_ON_FAILURE) ? lvl : HFI_SET_HANG_DUMP_ON_FAILURE; + + CAM_DBG(CAM_HFI, "prop->size = %d\n" + "prop->pkt_type = %d\n" + "prop->num_prop = %d\n" + "prop->prop_data[0] = %d\n" + "prop->prop_data[1] = %d\n", + fw_dump_level_switch_prop->size, + fw_dump_level_switch_prop->pkt_type, + fw_dump_level_switch_prop->num_prop, + fw_dump_level_switch_prop->prop_data[0], + fw_dump_level_switch_prop->prop_data[1]); + + hfi_write_cmd(prop); + kfree(prop); + return 0; +} + +void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size) +{ + switch (type) { + case HFI_CMD_SYS_INIT: { + struct hfi_cmd_sys_init init; + + memset(&init, 0, sizeof(init)); + + init.size = sizeof(struct hfi_cmd_sys_init); + init.pkt_type = type; + hfi_write_cmd(&init); + } + break; + case HFI_CMD_SYS_PC_PREP: { + struct hfi_cmd_pc_prep prep; + + prep.size = sizeof(struct hfi_cmd_pc_prep); + prep.pkt_type = type; + hfi_write_cmd(&prep); + } + break; + case HFI_CMD_SYS_SET_PROPERTY: { + struct hfi_cmd_prop prop; + + if ((uint32_t)data == (uint32_t)HFI_PROP_SYS_DEBUG_CFG) { + prop.size = sizeof(struct hfi_cmd_prop); + prop.pkt_type = type; + prop.num_prop = 1; + prop.prop_data[0] = HFI_PROP_SYS_DEBUG_CFG; + hfi_write_cmd(&prop); + } + } + break; + case HFI_CMD_SYS_GET_PROPERTY: + break; + case HFI_CMD_SYS_PING: { + struct hfi_cmd_ping_pkt ping; + + ping.size = sizeof(struct hfi_cmd_ping_pkt); + ping.pkt_type = type; + ping.user_data = (uint64_t)data; + hfi_write_cmd(&ping); + } + break; + case HFI_CMD_SYS_RESET: { + struct hfi_cmd_sys_reset_pkt reset; + + reset.size = sizeof(struct hfi_cmd_sys_reset_pkt); + reset.pkt_type = type; + reset.user_data = (uint64_t)data; + hfi_write_cmd(&reset); + } + break; + case HFI_CMD_IPEBPS_CREATE_HANDLE: { + struct hfi_cmd_create_handle handle; + + handle.size = sizeof(struct hfi_cmd_create_handle); + handle.pkt_type = type; + handle.handle_type = (uint32_t)data; + handle.user_data1 = 0; + hfi_write_cmd(&handle); + } + break; + case HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT: + break; + default: + CAM_ERR(CAM_HFI, "command not supported :%d", type); + break; + } +} + + +int hfi_get_hw_caps(void *query_buf) +{ + int i = 0; + struct cam_icp_query_cap_cmd *query_cmd = NULL; + + if (!query_buf) { + CAM_ERR(CAM_HFI, "query buf is NULL"); + return -EINVAL; + } + + query_cmd = (struct cam_icp_query_cap_cmd *)query_buf; + query_cmd->fw_version.major = 0x12; + query_cmd->fw_version.minor = 0x12; + query_cmd->fw_version.revision = 0x12; + + query_cmd->api_version.major = 0x13; + query_cmd->api_version.minor = 0x13; + query_cmd->api_version.revision = 0x13; + + query_cmd->num_ipe = 2; + query_cmd->num_bps = 1; + + for (i = 0; i < CAM_ICP_DEV_TYPE_MAX; i++) { + query_cmd->dev_ver[i].dev_type = i; + query_cmd->dev_ver[i].hw_ver.major = 0x34 + i; + query_cmd->dev_ver[i].hw_ver.minor = 0x34 + i; + query_cmd->dev_ver[i].hw_ver.incr = 0x34 + i; + } + return 0; +} + +void cam_hfi_disable_cpu(void __iomem *icp_base) +{ + uint32_t data; + uint32_t val; + uint32_t try = 0; + + while (try < HFI_MAX_PC_POLL_TRY) { + data = cam_io_r_mb(icp_base + HFI_REG_A5_CSR_A5_STATUS); + CAM_DBG(CAM_HFI, "wfi status = %x\n", (int)data); + + if (data & ICP_CSR_A5_STATUS_WFI) + break; + /* Need to poll here to confirm that FW is going trigger wfi + * and Host can the proceed. No interrupt is expected from FW + * at this time. + */ + usleep_range(HFI_POLL_TRY_SLEEP * 1000, + (HFI_POLL_TRY_SLEEP * 1000) + 1000); + try++; + } + + val = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_CONTROL); + val &= ~(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN); + cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_A5_CONTROL); + + val = cam_io_r(icp_base + HFI_REG_A5_CSR_NSEC_RESET); + cam_io_w_mb(val, icp_base + HFI_REG_A5_CSR_NSEC_RESET); + + cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_RESET, + icp_base + HFI_REG_HOST_ICP_INIT_REQUEST); + cam_io_w_mb((uint32_t)INTR_DISABLE, + icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); +} + +void cam_hfi_enable_cpu(void __iomem *icp_base) +{ + cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + cam_io_w_mb((uint32_t)0x10, icp_base + HFI_REG_A5_CSR_NSEC_RESET); +} + +int cam_hfi_resume(struct hfi_mem_info *hfi_mem, + void __iomem *icp_base, bool debug) +{ + int rc = 0; + uint32_t data; + uint32_t fw_version, status = 0; + uint32_t retry_cnt = 0; + + cam_hfi_enable_cpu(icp_base); + g_hfi->csr_base = icp_base; + + if (debug) { + cam_io_w_mb(ICP_FLAG_A5_CTRL_DBG_EN, + (icp_base + HFI_REG_A5_CSR_A5_CONTROL)); + + /* Barrier needed as next write should be done after + * sucessful previous write. Next write enable clock + * gating + */ + wmb(); + + cam_io_w_mb((uint32_t)ICP_FLAG_A5_CTRL_EN, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + + } else { + cam_io_w_mb((uint32_t)ICP_FLAG_A5_CTRL_EN, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + } + + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE), + status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000); + + CAM_DBG(CAM_HFI, "1: status = %u", status); + status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE); + CAM_DBG(CAM_HFI, "2: status = %u", status); + if (status == ICP_INIT_RESP_SUCCESS) + break; + + if (status == ICP_INIT_RESP_FAILED) { + CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version); + return -EINVAL; + } + retry_cnt++; + } + + if ((retry_cnt == HFI_MAX_POLL_TRY) && + (status == ICP_INIT_RESP_RESET)) { + CAM_ERR(CAM_HFI, "Reached Max retries. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version); + return -EINVAL; + } + + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), + icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); + + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_DBG(CAM_HFI, "fw version : [%x]", fw_version); + + data = cam_io_r(icp_base + HFI_REG_A5_CSR_A5_STATUS); + CAM_DBG(CAM_HFI, "wfi status = %x", (int)data); + + cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, + icp_base + HFI_REG_SHARED_MEM_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.len, + icp_base + HFI_REG_SHARED_MEM_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova, + icp_base + HFI_REG_UNCACHED_HEAP_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len, + icp_base + HFI_REG_UNCACHED_HEAP_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->qdss.iova, + icp_base + HFI_REG_QDSS_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->qdss.len, + icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); + + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova, + icp_base + HFI_REG_IO2_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len, + icp_base + HFI_REG_IO2_REGION_SIZE); + + CAM_INFO(CAM_HFI, "Resume IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]", + hfi_mem->io_mem.iova, hfi_mem->io_mem.len, + hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len); + + return rc; +} + +int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, + void __iomem *icp_base, bool debug) +{ + int rc = 0; + struct hfi_qtbl *qtbl; + struct hfi_qtbl_hdr *qtbl_hdr; + struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr; + uint32_t hw_version, fw_version, status = 0; + uint32_t retry_cnt = 0; + struct sfr_buf *sfr_buffer; + + mutex_lock(&hfi_cmd_q_mutex); + mutex_lock(&hfi_msg_q_mutex); + + if (!g_hfi) { + g_hfi = kzalloc(sizeof(struct hfi_info), GFP_KERNEL); + if (!g_hfi) { + rc = -ENOMEM; + goto alloc_fail; + } + } + + if (g_hfi->hfi_state != HFI_DEINIT) { + CAM_ERR(CAM_HFI, "hfi_init: invalid state"); + return -EINVAL; + } + + memcpy(&g_hfi->map, hfi_mem, sizeof(g_hfi->map)); + g_hfi->hfi_state = HFI_DEINIT; + if (debug) { + cam_io_w_mb( + (uint32_t)(ICP_FLAG_CSR_A5_EN | ICP_FLAG_CSR_WAKE_UP_EN | + ICP_CSR_EDBGRQ | ICP_CSR_DBGSWENABLE), + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + msleep(100); + cam_io_w_mb((uint32_t)(ICP_FLAG_CSR_A5_EN | + ICP_FLAG_CSR_WAKE_UP_EN | ICP_CSR_EN_CLKGATE_WFI), + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + } else { + /* Due to hardware bug in V1 ICP clock gating has to be + * disabled, this is supposed to be fixed in V-2. But enabling + * the clock gating is causing the firmware hang, hence + * disabling the clock gating on both V1 and V2 until the + * hardware team root causes this + */ + cam_io_w_mb((uint32_t)ICP_FLAG_CSR_A5_EN | + ICP_FLAG_CSR_WAKE_UP_EN | + ICP_CSR_EN_CLKGATE_WFI, + icp_base + HFI_REG_A5_CSR_A5_CONTROL); + } + + qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; + qtbl_hdr = &qtbl->q_tbl_hdr; + qtbl_hdr->qtbl_version = 0xFFFFFFFF; + qtbl_hdr->qtbl_size = sizeof(struct hfi_qtbl); + qtbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_qtbl_hdr); + qtbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_q_hdr); + qtbl_hdr->qtbl_num_q = ICP_HFI_NUMBER_OF_QS; + qtbl_hdr->qtbl_num_active_q = ICP_HFI_NUMBER_OF_QS; + + /* setup host-to-firmware command queue */ + cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; + cmd_q_hdr->qhdr_status = QHDR_ACTIVE; + cmd_q_hdr->qhdr_start_addr = hfi_mem->cmd_q.iova; + cmd_q_hdr->qhdr_q_size = ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; + cmd_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT; + cmd_q_hdr->qhdr_pkt_drop_cnt = RESET; + cmd_q_hdr->qhdr_read_idx = RESET; + cmd_q_hdr->qhdr_write_idx = RESET; + + /* setup firmware-to-Host message queue */ + msg_q_hdr = &qtbl->q_hdr[Q_MSG]; + msg_q_hdr->qhdr_status = QHDR_ACTIVE; + msg_q_hdr->qhdr_start_addr = hfi_mem->msg_q.iova; + msg_q_hdr->qhdr_q_size = ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; + msg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT; + msg_q_hdr->qhdr_pkt_drop_cnt = RESET; + msg_q_hdr->qhdr_read_idx = RESET; + msg_q_hdr->qhdr_write_idx = RESET; + + /* setup firmware-to-Host message queue */ + dbg_q_hdr = &qtbl->q_hdr[Q_DBG]; + dbg_q_hdr->qhdr_status = QHDR_ACTIVE; + dbg_q_hdr->qhdr_start_addr = hfi_mem->dbg_q.iova; + dbg_q_hdr->qhdr_q_size = ICP_DBG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; + dbg_q_hdr->qhdr_pkt_size = ICP_HFI_VAR_SIZE_PKT; + dbg_q_hdr->qhdr_pkt_drop_cnt = RESET; + dbg_q_hdr->qhdr_read_idx = RESET; + dbg_q_hdr->qhdr_write_idx = RESET; + + sfr_buffer = (struct sfr_buf *)hfi_mem->sfr_buf.kva; + sfr_buffer->size = ICP_MSG_SFR_SIZE_IN_BYTES; + + switch (event_driven_mode) { + case INTR_MODE: + cmd_q_hdr->qhdr_type = Q_CMD; + cmd_q_hdr->qhdr_rx_wm = SET; + cmd_q_hdr->qhdr_tx_wm = SET; + cmd_q_hdr->qhdr_rx_req = SET; + cmd_q_hdr->qhdr_tx_req = RESET; + cmd_q_hdr->qhdr_rx_irq_status = RESET; + cmd_q_hdr->qhdr_tx_irq_status = RESET; + + msg_q_hdr->qhdr_type = Q_MSG; + msg_q_hdr->qhdr_rx_wm = SET; + msg_q_hdr->qhdr_tx_wm = SET; + msg_q_hdr->qhdr_rx_req = SET; + msg_q_hdr->qhdr_tx_req = RESET; + msg_q_hdr->qhdr_rx_irq_status = RESET; + msg_q_hdr->qhdr_tx_irq_status = RESET; + + dbg_q_hdr->qhdr_type = Q_DBG; + dbg_q_hdr->qhdr_rx_wm = SET; + dbg_q_hdr->qhdr_tx_wm = SET_WM; + dbg_q_hdr->qhdr_rx_req = RESET; + dbg_q_hdr->qhdr_tx_req = RESET; + dbg_q_hdr->qhdr_rx_irq_status = RESET; + dbg_q_hdr->qhdr_tx_irq_status = RESET; + + break; + + case POLL_MODE: + cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_POLL_MODE_2 | + RX_EVENT_POLL_MODE_2; + msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_POLL_MODE_2 | + RX_EVENT_POLL_MODE_2; + dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_POLL_MODE_2 | + RX_EVENT_POLL_MODE_2; + break; + + case WM_MODE: + cmd_q_hdr->qhdr_type = Q_CMD | TX_EVENT_DRIVEN_MODE_2 | + RX_EVENT_DRIVEN_MODE_2; + cmd_q_hdr->qhdr_rx_wm = SET; + cmd_q_hdr->qhdr_tx_wm = SET; + cmd_q_hdr->qhdr_rx_req = RESET; + cmd_q_hdr->qhdr_tx_req = SET; + cmd_q_hdr->qhdr_rx_irq_status = RESET; + cmd_q_hdr->qhdr_tx_irq_status = RESET; + + msg_q_hdr->qhdr_type = Q_MSG | TX_EVENT_DRIVEN_MODE_2 | + RX_EVENT_DRIVEN_MODE_2; + msg_q_hdr->qhdr_rx_wm = SET; + msg_q_hdr->qhdr_tx_wm = SET; + msg_q_hdr->qhdr_rx_req = SET; + msg_q_hdr->qhdr_tx_req = RESET; + msg_q_hdr->qhdr_rx_irq_status = RESET; + msg_q_hdr->qhdr_tx_irq_status = RESET; + + dbg_q_hdr->qhdr_type = Q_DBG | TX_EVENT_DRIVEN_MODE_2 | + RX_EVENT_DRIVEN_MODE_2; + dbg_q_hdr->qhdr_rx_wm = SET; + dbg_q_hdr->qhdr_tx_wm = SET_WM; + dbg_q_hdr->qhdr_rx_req = RESET; + dbg_q_hdr->qhdr_tx_req = RESET; + dbg_q_hdr->qhdr_rx_irq_status = RESET; + dbg_q_hdr->qhdr_tx_irq_status = RESET; + break; + + default: + CAM_ERR(CAM_HFI, "Invalid event driven mode :%u", + event_driven_mode); + break; + } + + cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, + icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, + icp_base + HFI_REG_SHARED_MEM_PTR); + cam_io_w_mb((uint32_t)hfi_mem->shmem.len, + icp_base + HFI_REG_SHARED_MEM_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.iova, + icp_base + HFI_REG_UNCACHED_HEAP_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sec_heap.len, + icp_base + HFI_REG_UNCACHED_HEAP_SIZE); + cam_io_w_mb((uint32_t)ICP_INIT_REQUEST_SET, + icp_base + HFI_REG_HOST_ICP_INIT_REQUEST); + cam_io_w_mb((uint32_t)hfi_mem->qdss.iova, + icp_base + HFI_REG_QDSS_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->qdss.len, + icp_base + HFI_REG_QDSS_IOVA_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.iova, + icp_base + HFI_REG_IO_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem.len, + icp_base + HFI_REG_IO_REGION_SIZE); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.iova, + icp_base + HFI_REG_IO2_REGION_IOVA); + cam_io_w_mb((uint32_t)hfi_mem->io_mem2.len, + icp_base + HFI_REG_IO2_REGION_SIZE); + + CAM_INFO(CAM_HFI, "Init IO1 : [0x%x 0x%x] IO2 [0x%x 0x%x]", + hfi_mem->io_mem.iova, hfi_mem->io_mem.len, + hfi_mem->io_mem2.iova, hfi_mem->io_mem2.len); + + hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION); + + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE), + status, (status == ICP_INIT_RESP_SUCCESS), 100, 10000); + + CAM_DBG(CAM_HFI, "1: status = %u rc = %d", status, rc); + status = cam_io_r_mb(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE); + CAM_DBG(CAM_HFI, "2: status = %u rc = %d", status, rc); + if (status == ICP_INIT_RESP_SUCCESS) + break; + + if (status == ICP_INIT_RESP_FAILED) { + CAM_ERR(CAM_HFI, "ICP Init Failed. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, "fw version : [%x]", fw_version); + goto regions_fail; + } + retry_cnt++; + } + + if ((retry_cnt == HFI_MAX_POLL_TRY) && + (status == ICP_INIT_RESP_RESET)) { + CAM_ERR(CAM_HFI, "Reached Max retries. status = %u", + status); + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_ERR(CAM_HFI, + "hw version : : [%x], fw version : [%x]", + hw_version, fw_version); + goto regions_fail; + } + + fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); + CAM_DBG(CAM_HFI, "hw version : : [%x], fw version : [%x]", + hw_version, fw_version); + + g_hfi->csr_base = icp_base; + g_hfi->hfi_state = HFI_READY; + g_hfi->cmd_q_state = true; + g_hfi->msg_q_state = true; + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), + icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); + + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); + + return rc; +regions_fail: + kfree(g_hfi); + g_hfi = NULL; +alloc_fail: + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); + return rc; +} + +void cam_hfi_deinit(void __iomem *icp_base) +{ + mutex_lock(&hfi_cmd_q_mutex); + mutex_lock(&hfi_msg_q_mutex); + + if (!g_hfi) { + CAM_ERR(CAM_HFI, "hfi path not established yet"); + goto err; + } + + g_hfi->cmd_q_state = false; + g_hfi->msg_q_state = false; + + kzfree(g_hfi); + g_hfi = NULL; + +err: + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/Makefile b/techpack/camera/drivers/cam_icp/icp_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..68b36f7066040d7eb128339dd4e1449f6442bb37 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw_mgr/ a5_hw/ ipe_hw/ bps_hw/ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/Makefile b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9c3aac09a137175e9a8c6f75ff99725bea262848 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/a5_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += a5_dev.o a5_core.o a5_soc.o diff --git a/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_core.c new file mode 100644 index 0000000000000000000000000000000000000000..e4cb645b7af0c2fd795d48e20695245acb1815b2 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_core.c @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/elf.h> +#include <media/cam_icp.h> +#include "cam_io_util.h" +#include "cam_a5_hw_intf.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "a5_core.h" +#include "a5_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "hfi_intf.h" +#include "hfi_sys_defs.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static int cam_a5_cpas_vote(struct cam_a5_device_core_info *core_info, + struct cam_icp_cpas_vote *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + + if (rc) + CAM_ERR(CAM_ICP, "cpas vote is failed: %d", rc); + + return rc; +} + +static int32_t cam_icp_validate_fw(const uint8_t *elf) +{ + struct elf32_hdr *elf_hdr; + + if (!elf) { + CAM_ERR(CAM_ICP, "Invalid params"); + return -EINVAL; + } + + elf_hdr = (struct elf32_hdr *)elf; + + if (memcmp(elf_hdr->e_ident, ELFMAG, SELFMAG)) { + CAM_ERR(CAM_ICP, "ICP elf identifier is failed"); + return -EINVAL; + } + + /* check architecture */ + if (elf_hdr->e_machine != EM_ARM) { + CAM_ERR(CAM_ICP, "unsupported arch"); + return -EINVAL; + } + + /* check elf bit format */ + if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32) { + CAM_ERR(CAM_ICP, "elf doesn't support 32 bit format"); + return -EINVAL; + } + + return 0; +} + +static int32_t cam_icp_get_fw_size(const uint8_t *elf, uint32_t *fw_size) +{ + int32_t rc = 0; + int32_t i = 0; + uint32_t num_prg_hdrs; + unsigned char *icp_prg_hdr_tbl; + uint32_t seg_mem_size = 0; + struct elf32_hdr *elf_hdr; + struct elf32_phdr *prg_hdr; + + if (!elf || !fw_size) { + CAM_ERR(CAM_ICP, "invalid args"); + return -EINVAL; + } + + *fw_size = 0; + + elf_hdr = (struct elf32_hdr *)elf; + num_prg_hdrs = elf_hdr->e_phnum; + icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff; + prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0]; + + if (!prg_hdr) { + CAM_ERR(CAM_ICP, "failed to get elf program header attr"); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "num_prg_hdrs = %d", num_prg_hdrs); + for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) { + if (prg_hdr->p_flags == 0) + continue; + + seg_mem_size = (prg_hdr->p_memsz + prg_hdr->p_align - 1) & + ~(prg_hdr->p_align - 1); + seg_mem_size += prg_hdr->p_vaddr; + CAM_DBG(CAM_ICP, "memsz:%x align:%x addr:%x seg_mem_size:%x", + (int)prg_hdr->p_memsz, (int)prg_hdr->p_align, + (int)prg_hdr->p_vaddr, (int)seg_mem_size); + if (*fw_size < seg_mem_size) + *fw_size = seg_mem_size; + + } + + if (*fw_size == 0) { + CAM_ERR(CAM_ICP, "invalid elf fw file"); + return -EINVAL; + } + + return rc; +} + +static int32_t cam_icp_program_fw(const uint8_t *elf, + struct cam_a5_device_core_info *core_info) +{ + int32_t rc = 0; + uint32_t num_prg_hdrs; + unsigned char *icp_prg_hdr_tbl; + int32_t i = 0; + u8 *dest; + u8 *src; + struct elf32_hdr *elf_hdr; + struct elf32_phdr *prg_hdr; + + elf_hdr = (struct elf32_hdr *)elf; + num_prg_hdrs = elf_hdr->e_phnum; + icp_prg_hdr_tbl = (unsigned char *)elf + elf_hdr->e_phoff; + prg_hdr = (struct elf32_phdr *)&icp_prg_hdr_tbl[0]; + + if (!prg_hdr) { + CAM_ERR(CAM_ICP, "failed to get elf program header attr"); + return -EINVAL; + } + + for (i = 0; i < num_prg_hdrs; i++, prg_hdr++) { + if (prg_hdr->p_flags == 0) + continue; + + CAM_DBG(CAM_ICP, "Loading FW header size: %u", + prg_hdr->p_filesz); + if (prg_hdr->p_filesz != 0) { + src = (u8 *)((u8 *)elf + prg_hdr->p_offset); + dest = (u8 *)(((u8 *)core_info->fw_kva_addr) + + prg_hdr->p_vaddr); + + memcpy_toio(dest, src, prg_hdr->p_filesz); + } + } + + return rc; +} + +static int32_t cam_a5_download_fw(void *device_priv) +{ + int32_t rc = 0; + uint32_t fw_size; + const uint8_t *fw_start = NULL; + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + struct platform_device *pdev = NULL; + struct a5_soc_info *cam_a5_soc_info = NULL; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + hw_info = core_info->a5_hw_info; + pdev = soc_info->pdev; + cam_a5_soc_info = soc_info->soc_private; + + rc = request_firmware(&core_info->fw_elf, "CAMERA_ICP.elf", &pdev->dev); + if (rc) { + CAM_ERR(CAM_ICP, "Failed to locate fw: %d", rc); + return rc; + } + + if (!core_info->fw_elf) { + CAM_ERR(CAM_ICP, "Invalid elf size"); + rc = -EINVAL; + goto fw_download_failed; + } + + fw_start = core_info->fw_elf->data; + rc = cam_icp_validate_fw(fw_start); + if (rc) { + CAM_ERR(CAM_ICP, "fw elf validation failed"); + goto fw_download_failed; + } + + rc = cam_icp_get_fw_size(fw_start, &fw_size); + if (rc) { + CAM_ERR(CAM_ICP, "unable to get fw size"); + goto fw_download_failed; + } + + if (core_info->fw_buf_len < fw_size) { + CAM_ERR(CAM_ICP, "mismatch in fw size: %u %llu", + fw_size, core_info->fw_buf_len); + rc = -EINVAL; + goto fw_download_failed; + } + + rc = cam_icp_program_fw(fw_start, core_info); + if (rc) { + CAM_ERR(CAM_ICP, "fw program is failed"); + goto fw_download_failed; + } + +fw_download_failed: + release_firmware(core_info->fw_elf); + return rc; +} + +int cam_a5_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct a5_soc_info *a5_soc_info; + struct cam_icp_cpas_vote cpas_vote; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info: %pK core_info: %pK", + soc_info, core_info); + return -EINVAL; + } + + a5_soc_info = soc_info->soc_private; + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE; + cpas_vote.axi_vote.num_paths = 1; + cpas_vote.axi_vote.axi_path[0].path_data_type = + CAM_ICP_DEFAULT_AXI_PATH; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_ICP_DEFAULT_AXI_TRANSAC; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + CAM_ICP_A5_BW_BYTES_VOTE; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_ICP, "cpas start failed: %d", rc); + goto error; + } + core_info->cpas_start = true; + + rc = cam_a5_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ICP, "soc enable is failed: %d", rc); + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } else { + CAM_DBG(CAM_ICP, "a5_qos %d", a5_soc_info->a5_qos_val); + if (a5_soc_info->a5_qos_val) + cam_io_w_mb(a5_soc_info->a5_qos_val, + soc_info->reg_map[A5_SIERRA_BASE].mem_base + + ICP_SIERRA_A5_CSR_ACCESS); + } + +error: + return rc; +} + +int cam_a5_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_a5_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ICP, "soc disable is failed: %d", rc); + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; +} + +irqreturn_t cam_a5_irq(int irq_num, void *data) +{ + struct cam_hw_info *a5_dev = data; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + uint32_t irq_status = 0; + + if (!data) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info or query_cap args"); + return IRQ_HANDLED; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + hw_info = core_info->a5_hw_info; + + irq_status = cam_io_r_mb(soc_info->reg_map[A5_SIERRA_BASE].mem_base + + core_info->a5_hw_info->a5_host_int_status); + + cam_io_w_mb(irq_status, + soc_info->reg_map[A5_SIERRA_BASE].mem_base + + core_info->a5_hw_info->a5_host_int_clr); + + if ((irq_status & A5_WDT_0) || + (irq_status & A5_WDT_1)) { + CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5"); + } + + spin_lock(&a5_dev->hw_lock); + if (core_info->irq_cb.icp_hw_mgr_cb) + core_info->irq_cb.icp_hw_mgr_cb(irq_status, + core_info->irq_cb.data); + spin_unlock(&a5_dev->hw_lock); + + return IRQ_HANDLED; +} + +int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *a5_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + struct a5_soc_info *a5_soc = NULL; + unsigned long flags; + uint32_t ubwc_ipe_cfg[ICP_UBWC_MAX] = {0}; + uint32_t ubwc_bps_cfg[ICP_UBWC_MAX] = {0}; + uint32_t index = 0; + int rc = 0, ddr_type = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_ICP_A5_CMD_MAX) { + CAM_ERR(CAM_ICP, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + soc_info = &a5_dev->soc_info; + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + hw_info = core_info->a5_hw_info; + + switch (cmd_type) { + case CAM_ICP_A5_CMD_FW_DOWNLOAD: + rc = cam_a5_download_fw(device_priv); + break; + case CAM_ICP_A5_CMD_SET_FW_BUF: { + struct cam_icp_a5_set_fw_buf_info *fw_buf_info = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + core_info->fw_buf = fw_buf_info->iova; + core_info->fw_kva_addr = fw_buf_info->kva; + core_info->fw_buf_len = fw_buf_info->len; + + CAM_DBG(CAM_ICP, "fw buf info = %x %llx %lld", + core_info->fw_buf, core_info->fw_kva_addr, + core_info->fw_buf_len); + break; + } + case CAM_ICP_A5_SET_IRQ_CB: { + struct cam_icp_a5_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + spin_lock_irqsave(&a5_dev->hw_lock, flags); + core_info->irq_cb.icp_hw_mgr_cb = irq_cb->icp_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + spin_unlock_irqrestore(&a5_dev->hw_lock, flags); + break; + } + + case CAM_ICP_A5_SEND_INIT: + hfi_send_system_cmd(HFI_CMD_SYS_INIT, 0, 0); + break; + + case CAM_ICP_A5_CMD_PC_PREP: + hfi_send_system_cmd(HFI_CMD_SYS_PC_PREP, 0, 0); + break; + + case CAM_ICP_A5_CMD_VOTE_CPAS: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + cam_a5_cpas_vote(core_info, cpas_vote); + break; + } + + case CAM_ICP_A5_CMD_CPAS_START: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + if (!core_info->cpas_start) { + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote->ahb_vote, + &cpas_vote->axi_vote); + core_info->cpas_start = true; + } + break; + } + + case CAM_ICP_A5_CMD_CPAS_STOP: + if (core_info->cpas_start) { + cam_cpas_stop(core_info->cpas_handle); + core_info->cpas_start = false; + } + break; + case CAM_ICP_A5_CMD_UBWC_CFG: { + struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL; + + a5_soc = soc_info->soc_private; + if (!a5_soc) { + CAM_ERR(CAM_ICP, "A5 private soc info is NULL"); + return -EINVAL; + } + + if (a5_soc->ubwc_config_ext) { + /* Invoke kernel API to determine DDR type */ + ddr_type = of_fdt_get_ddrtype(); + if ((ddr_type == DDR_TYPE_LPDDR5) || + (ddr_type == DDR_TYPE_LPDDR5X)) + index = 1; + + ubwc_cfg_ext = &a5_soc->uconfig.ubwc_cfg_ext; + ubwc_ipe_cfg[0] = + ubwc_cfg_ext->ubwc_ipe_fetch_cfg[index]; + ubwc_ipe_cfg[1] = + ubwc_cfg_ext->ubwc_ipe_write_cfg[index]; + ubwc_bps_cfg[0] = + ubwc_cfg_ext->ubwc_bps_fetch_cfg[index]; + ubwc_bps_cfg[1] = + ubwc_cfg_ext->ubwc_bps_write_cfg[index]; + rc = hfi_cmd_ubwc_config_ext(&ubwc_ipe_cfg[0], + &ubwc_bps_cfg[0]); + } else { + rc = hfi_cmd_ubwc_config(a5_soc->uconfig.ubwc_cfg); + } + + break; + } + case CAM_ICP_A5_CMD_CLK_UPDATE: { + int32_t clk_level = 0; + struct cam_ahb_vote ahb_vote; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + clk_level = *((int32_t *)cmd_args); + CAM_DBG(CAM_ICP, + "Update ICP clock to level [%d]", clk_level); + rc = cam_a5_update_clk_rate(soc_info, clk_level); + if (rc) + CAM_ERR(CAM_ICP, + "Failed to update clk to level: %d rc: %d", + clk_level, rc); + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_level; + cam_cpas_update_ahb_vote( + core_info->cpas_handle, &ahb_vote); + break; + } + default: + break; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_core.h b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_core.h new file mode 100644 index 0000000000000000000000000000000000000000..6c46b3ac8784f21393b4c09b6673898caf9dd37b --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_core.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_A5_CORE_H +#define CAM_A5_CORE_H + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include "cam_a5_hw_intf.h" + +#define A5_QGIC_BASE 0 +#define A5_SIERRA_BASE 1 +#define A5_CSR_BASE 2 + +#define A5_HOST_INT 0x1 +#define A5_WDT_0 0x2 +#define A5_WDT_1 0x4 + +#define ICP_SIERRA_A5_CSR_ACCESS 0x3C + +#define ELF_GUARD_PAGE (2 * 1024 * 1024) + +struct cam_a5_device_hw_info { + uint32_t hw_ver; + uint32_t nsec_reset; + uint32_t a5_control; + uint32_t a5_host_int_en; + uint32_t a5_host_int; + uint32_t a5_host_int_clr; + uint32_t a5_host_int_status; + uint32_t a5_host_int_set; + uint32_t host_a5_int; + uint32_t fw_version; + uint32_t init_req; + uint32_t init_response; + uint32_t shared_mem_ptr; + uint32_t shared_mem_size; + uint32_t qtbl_ptr; + uint32_t uncached_heap_ptr; + uint32_t uncached_heap_size; + uint32_t a5_status; +}; + +/** + * struct cam_a5_device_hw_info + * @a5_hw_info: A5 hardware info + * @fw_elf: start address of fw start with elf header + * @fw: start address of fw blob + * @fw_buf: smmu alloc/mapped fw buffer + * @fw_buf_len: fw buffer length + * @query_cap: A5 query info from firmware + * @a5_acquire: Acquire information of A5 + * @irq_cb: IRQ callback + * @cpas_handle: CPAS handle for A5 + * @cpast_start: state variable for cpas + */ +struct cam_a5_device_core_info { + struct cam_a5_device_hw_info *a5_hw_info; + const struct firmware *fw_elf; + void *fw; + uint32_t fw_buf; + uintptr_t fw_kva_addr; + uint64_t fw_buf_len; + struct cam_icp_a5_query_cap query_cap; + struct cam_icp_a5_acquire_dev a5_acquire[8]; + struct cam_icp_a5_set_irq_cb irq_cb; + uint32_t cpas_handle; + bool cpas_start; +}; + +int cam_a5_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_a5_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_a5_irq(int irq_num, void *data); +#endif /* CAM_A5_CORE_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_dev.c b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..b4f33d3e4dd358e8a194f8731f04610c7f87e774 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_dev.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include <linux/timer.h> +#include "a5_core.h" +#include "a5_soc.h" +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_a5_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +struct a5_soc_info cam_a5_soc_info; +EXPORT_SYMBOL(cam_a5_soc_info); + +struct cam_a5_device_hw_info cam_a5_hw_info = { + .hw_ver = 0x0, + .nsec_reset = 0x4, + .a5_control = 0x8, + .a5_host_int_en = 0x10, + .a5_host_int = 0x14, + .a5_host_int_clr = 0x18, + .a5_host_int_status = 0x1c, + .a5_host_int_set = 0x20, + .host_a5_int = 0x30, + .fw_version = 0x44, + .init_req = 0x48, + .init_response = 0x4c, + .shared_mem_ptr = 0x50, + .shared_mem_size = 0x54, + .qtbl_ptr = 0x58, + .uncached_heap_ptr = 0x5c, + .uncached_heap_size = 0x60, + .a5_status = 0x200, +}; +EXPORT_SYMBOL(cam_a5_hw_info); + +static bool cam_a5_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + switch (irq_data->irq_type) { + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Decode error type=%d status=%x thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d", + irq_data->irq_type, + irq_data->u.dec_err.decerr_status.value, + irq_data->u.dec_err.decerr_status.thr_err, + irq_data->u.dec_err.decerr_status.fcl_err, + irq_data->u.dec_err.decerr_status.len_md_err, + irq_data->u.dec_err.decerr_status.format_err); + error_handled = true; + break; + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Encode error type=%d status=%x", + irq_data->irq_type, + irq_data->u.enc_err.encerr_status.value); + error_handled = true; + break; + default: + break; + } + + return error_handled; +} + +int cam_a5_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_a5_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "icp", sizeof("icp")); + cpas_register_params.cam_cpas_client_cb = cam_a5_cpas_cb; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed: %d", rc); + return rc; + } + + core_info->cpas_handle = cpas_register_params.client_handle; + return rc; +} + +int cam_a5_probe(struct platform_device *pdev) +{ + int rc = 0; + struct cam_hw_info *a5_dev = NULL; + struct cam_hw_intf *a5_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_a5_device_core_info *core_info = NULL; + struct cam_a5_device_hw_info *hw_info = NULL; + + a5_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!a5_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &a5_dev_intf->hw_idx); + + a5_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!a5_dev) { + rc = -ENOMEM; + goto a5_dev_alloc_failure; + } + + a5_dev->soc_info.pdev = pdev; + a5_dev->soc_info.dev = &pdev->dev; + a5_dev->soc_info.dev_name = pdev->name; + a5_dev_intf->hw_priv = a5_dev; + a5_dev_intf->hw_ops.init = cam_a5_init_hw; + a5_dev_intf->hw_ops.deinit = cam_a5_deinit_hw; + a5_dev_intf->hw_ops.process_cmd = cam_a5_process_cmd; + a5_dev_intf->hw_type = CAM_ICP_DEV_A5; + + CAM_DBG(CAM_ICP, "type %d index %d", + a5_dev_intf->hw_type, + a5_dev_intf->hw_idx); + + platform_set_drvdata(pdev, a5_dev_intf); + + a5_dev->core_info = kzalloc(sizeof(struct cam_a5_device_core_info), + GFP_KERNEL); + if (!a5_dev->core_info) { + rc = -ENOMEM; + goto core_info_alloc_failure; + } + core_info = (struct cam_a5_device_core_info *)a5_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ICP, "No a5 hardware info"); + rc = -EINVAL; + goto match_err; + } + hw_info = (struct cam_a5_device_hw_info *)match_dev->data; + core_info->a5_hw_info = hw_info; + + a5_dev->soc_info.soc_private = &cam_a5_soc_info; + + rc = cam_a5_init_soc_resources(&a5_dev->soc_info, cam_a5_irq, + a5_dev); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed to init_soc"); + goto init_soc_failure; + } + + CAM_DBG(CAM_ICP, "soc info : %pK", + (void *)&a5_dev->soc_info); + rc = cam_a5_register_cpas(&a5_dev->soc_info, + core_info, a5_dev_intf->hw_idx); + if (rc < 0) { + CAM_ERR(CAM_ICP, "a5 cpas registration failed"); + goto cpas_reg_failed; + } + a5_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&a5_dev->hw_mutex); + spin_lock_init(&a5_dev->hw_lock); + init_completion(&a5_dev->hw_complete); + + CAM_DBG(CAM_ICP, "A5%d probe successful", + a5_dev_intf->hw_idx); + return 0; + +cpas_reg_failed: +init_soc_failure: +match_err: + kfree(a5_dev->core_info); +core_info_alloc_failure: + kfree(a5_dev); +a5_dev_alloc_failure: + kfree(a5_dev_intf); + + return rc; +} + +static const struct of_device_id cam_a5_dt_match[] = { + { + .compatible = "qcom,cam-a5", + .data = &cam_a5_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_a5_dt_match); + +static struct platform_driver cam_a5_driver = { + .probe = cam_a5_probe, + .driver = { + .name = "cam-a5", + .owner = THIS_MODULE, + .of_match_table = cam_a5_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_a5_init_module(void) +{ + return platform_driver_register(&cam_a5_driver); +} + +static void __exit cam_a5_exit_module(void) +{ + platform_driver_unregister(&cam_a5_driver); +} + +module_init(cam_a5_init_module); +module_exit(cam_a5_exit_module); +MODULE_DESCRIPTION("CAM A5 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..d0629612193ab1cf3cb9609ca850bd2334a770f3 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_soc.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "a5_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static int cam_a5_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0, i; + const char *fw_name; + struct a5_soc_info *a5_soc_info; + struct device_node *of_node = NULL; + struct platform_device *pdev = NULL; + struct a5_ubwc_cfg_ext *ubwc_cfg_ext = NULL; + int num_ubwc_cfg; + + pdev = soc_info->pdev; + of_node = pdev->dev.of_node; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_ICP, "get a5 dt prop is failed"); + return rc; + } + + a5_soc_info = soc_info->soc_private; + fw_name = a5_soc_info->fw_name; + + rc = of_property_read_string(of_node, "fw_name", &fw_name); + if (rc < 0) { + CAM_ERR(CAM_ICP, "fw_name read failed"); + goto end; + } + + rc = of_property_read_u32(of_node, "qos-val", + &a5_soc_info->a5_qos_val); + if (rc < 0) { + CAM_WARN(CAM_ICP, "QoS need not be set"); + a5_soc_info->a5_qos_val = 0; + } + + ubwc_cfg_ext = &a5_soc_info->uconfig.ubwc_cfg_ext; + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-ipe-fetch-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_DBG(CAM_ICP, "wrong ubwc_ipe_fetch_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto ubwc_ex_cfg; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-ipe-fetch-cfg", + i, &ubwc_cfg_ext->ubwc_ipe_fetch_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_ipe_fetch_cfg values"); + goto end; + } + } + + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-ipe-write-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_ipe_write_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-ipe-write-cfg", + i, &ubwc_cfg_ext->ubwc_ipe_write_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_ipe_write_cfg values"); + goto end; + } + } + + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-bps-fetch-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_bps_fetch_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-bps-fetch-cfg", + i, &ubwc_cfg_ext->ubwc_bps_fetch_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_bps_fetch_cfg values"); + goto end; + } + } + + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-bps-write-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_bps_write_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-bps-write-cfg", + i, &ubwc_cfg_ext->ubwc_bps_write_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, + "unable to read ubwc_bps_write_cfg values"); + goto end; + } + } + + a5_soc_info->ubwc_config_ext = true; + CAM_DBG(CAM_ICP, "read ubwc_cfg_ext for ipe/bps"); + return rc; + +ubwc_ex_cfg: + num_ubwc_cfg = of_property_count_u32_elems(of_node, "ubwc-cfg"); + if ((num_ubwc_cfg < 0) || (num_ubwc_cfg > ICP_UBWC_MAX)) { + CAM_ERR(CAM_ICP, "wrong ubwc_cfg: %d", num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, "ubwc-cfg", + i, &a5_soc_info->uconfig.ubwc_cfg[i]); + if (rc < 0) { + CAM_ERR(CAM_ICP, "unable to read ubwc_cfg values"); + break; + } + } + +end: + return rc; +} + +static int cam_a5_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t a5_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, a5_irq_handler, + irq_data); + + return rc; +} + +int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t a5_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_a5_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_a5_request_platform_resource(soc_info, a5_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) + CAM_ERR(CAM_ICP, "enable platform failed"); + + return rc; +} + +int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_ICP, "disable platform failed"); + + return rc; +} + +int cam_a5_update_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_level) +{ + int32_t src_clk_idx = 0; + int32_t clk_rate = 0; + + if (!soc_info) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + if ((clk_level < 0) || (clk_level >= CAM_MAX_VOTE)) { + CAM_ERR(CAM_ICP, "clock level %d is not valid", + clk_level); + return -EINVAL; + } + + if (!soc_info->clk_level_valid[clk_level]) { + CAM_ERR(CAM_ICP, + "Clock level %d not supported", + clk_level); + return -EINVAL; + } + + src_clk_idx = soc_info->src_clk_idx; + if ((src_clk_idx < 0) || (src_clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_WARN(CAM_ICP, "src_clk not defined for %s", + soc_info->dev_name); + return -EINVAL; + } + + clk_rate = soc_info->clk_rate[clk_level][src_clk_idx]; + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE]) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_ICP, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..480364df1fd626099d431dd296997552593f54b9 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/a5_soc.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_A5_SOC_H +#define CAM_A5_SOC_H + +#include "cam_soc_util.h" + +#define ICP_UBWC_MAX 2 + +struct a5_ubwc_cfg_ext { + uint32_t ubwc_ipe_fetch_cfg[ICP_UBWC_MAX]; + uint32_t ubwc_ipe_write_cfg[ICP_UBWC_MAX]; + uint32_t ubwc_bps_fetch_cfg[ICP_UBWC_MAX]; + uint32_t ubwc_bps_write_cfg[ICP_UBWC_MAX]; +}; + +struct a5_soc_info { + char *fw_name; + bool ubwc_config_ext; + uint32_t a5_qos_val; + union { + uint32_t ubwc_cfg[ICP_UBWC_MAX]; + struct a5_ubwc_cfg_ext ubwc_cfg_ext; + } uconfig; +}; + +int cam_a5_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t a5_irq_handler, void *irq_data); + +int cam_a5_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_a5_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_a5_update_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_level); +#endif diff --git a/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/Makefile b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..491e6a16492b52dfded44a9c816aaceaa4d50e3b --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/bps_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += bps_dev.o bps_core.o bps_soc.o diff --git a/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_core.c b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_core.c new file mode 100644 index 0000000000000000000000000000000000000000..8a079bd1420208dce97a0a9172a478ae1d67cf99 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_core.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/iopoll.h> +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "bps_core.h" +#include "bps_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_bps_hw_intf.h" +#include "cam_icp_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 + +static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info, + struct cam_icp_cpas_vote *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + + if (rc < 0) + CAM_ERR(CAM_PERF, "cpas vote is failed: %d", rc); + + return rc; +} + + +int cam_bps_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *bps_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_icp_cpas_vote cpas_vote; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE; + cpas_vote.axi_vote.num_paths = 1; + cpas_vote.axi_vote.axi_path[0].path_data_type = + CAM_BPS_DEFAULT_AXI_PATH; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_BPS_DEFAULT_AXI_TRANSAC; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_ICP, "cpas start failed: %d", rc); + goto error; + } + core_info->cpas_start = true; + + rc = cam_bps_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ICP, "soc enable is failed: %d", rc); + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } else { + core_info->clk_enable = true; + } + +error: + return rc; +} + +int cam_bps_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *bps_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_bps_disable_soc_resources(soc_info, core_info->clk_enable); + if (rc) + CAM_ERR(CAM_ICP, "soc disable is failed: %d", rc); + core_info->clk_enable = false; + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; +} + +static int cam_bps_handle_pc(struct cam_hw_info *bps_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + hw_info = core_info->bps_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + if (!(pwr_ctrl & BPS_COLLAPSE_MASK)) { + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x1); + + if ((pwr_status >> BPS_PWR_ON_MASK)) + CAM_WARN(CAM_PERF, "BPS: pwr_status(%x):pwr_ctrl(%x)", + pwr_status, pwr_ctrl); + } + cam_bps_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, + &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return 0; +} + +static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + int rc = 0; + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + hw_info = core_info->bps_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); + if (pwr_ctrl & BPS_COLLAPSE_MASK) { + CAM_DBG(CAM_PERF, "BPS: pwr_ctrl set(%x)", pwr_ctrl); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0); + } + + rc = cam_bps_transfer_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, true, &pwr_status); + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return rc; +} + +static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_bps_device_core_info *core_info) +{ + uint32_t retry_cnt = 0; + uint32_t status = 0; + int pwr_ctrl, pwr_status, rc = 0; + bool reset_bps_cdm_fail = false; + bool reset_bps_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET"); + + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_ICP, "BPS reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + + /* Reset BPS CDM core*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_cdm_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS CDM rst failed status 0x%x", status); + reset_bps_cdm_fail = true; + } + + /* Reset BPS core*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + BPS_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_top_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS top rst failed status 0x%x", status); + reset_bps_top_fail = true; + } + + cam_bps_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After) pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_bps_cdm_fail || reset_bps_top_fail) + rc = -EAGAIN; + + return rc; +} + +int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *bps_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_ICP_BPS_CMD_MAX) { + CAM_ERR(CAM_ICP, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + soc_info = &bps_dev->soc_info; + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + hw_info = core_info->bps_hw_info; + + switch (cmd_type) { + case CAM_ICP_BPS_CMD_VOTE_CPAS: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + cam_bps_cpas_vote(core_info, cpas_vote); + break; + } + + case CAM_ICP_BPS_CMD_CPAS_START: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_ICP, "cmd args NULL"); + return -EINVAL; + } + + if (!core_info->cpas_start) { + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote->ahb_vote, + &cpas_vote->axi_vote); + core_info->cpas_start = true; + } + break; + } + + case CAM_ICP_BPS_CMD_CPAS_STOP: + if (core_info->cpas_start) { + cam_cpas_stop(core_info->cpas_handle); + core_info->cpas_start = false; + } + break; + case CAM_ICP_BPS_CMD_POWER_COLLAPSE: + rc = cam_bps_handle_pc(bps_dev); + break; + case CAM_ICP_BPS_CMD_POWER_RESUME: + rc = cam_bps_handle_resume(bps_dev); + break; + case CAM_ICP_BPS_CMD_UPDATE_CLK: { + struct cam_a5_clk_update_cmd *clk_upd_cmd = + (struct cam_a5_clk_update_cmd *)cmd_args; + struct cam_ahb_vote ahb_vote; + uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + int32_t clk_level = 0, err = 0; + + CAM_DBG(CAM_PERF, "bps_src_clk rate = %d", (int)clk_rate); + + if (!core_info->clk_enable) { + if (clk_upd_cmd->ipe_bps_pc_enable) { + cam_bps_handle_pc(bps_dev); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x0); + } + rc = cam_bps_toggle_clk(soc_info, true); + if (rc) + CAM_ERR(CAM_ICP, "Enable failed"); + else + core_info->clk_enable = true; + if (clk_upd_cmd->ipe_bps_pc_enable) { + rc = cam_bps_handle_resume(bps_dev); + if (rc) + CAM_ERR(CAM_ICP, "BPS resume failed"); + } + } + CAM_DBG(CAM_PERF, "clock rate %d", clk_rate); + rc = cam_bps_update_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_PERF, "Failed to update clk %d", clk_rate); + + err = cam_soc_util_get_clk_level(soc_info, + clk_rate, soc_info->src_clk_idx, + &clk_level); + + if (!err) { + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_level; + cam_cpas_update_ahb_vote( + core_info->cpas_handle, + &ahb_vote); + } + break; + } + case CAM_ICP_BPS_CMD_DISABLE_CLK: + if (core_info->clk_enable == true) + cam_bps_toggle_clk(soc_info, false); + core_info->clk_enable = false; + break; + case CAM_ICP_BPS_CMD_RESET: + rc = cam_bps_cmd_reset(soc_info, core_info); + break; + default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +irqreturn_t cam_bps_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_core.h b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_core.h new file mode 100644 index 0000000000000000000000000000000000000000..162c5e65530c45948c23c2b3cc7c6c77b5b09b3c --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_core.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_BPS_CORE_H +#define CAM_BPS_CORE_H + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define BPS_COLLAPSE_MASK 0x1 +#define BPS_PWR_ON_MASK 0x2 + +struct cam_bps_device_hw_info { + uint32_t hw_idx; + uint32_t pwr_ctrl; + uint32_t pwr_status; + uint32_t reserved; +}; + +struct cam_bps_device_core_info { + struct cam_bps_device_hw_info *bps_hw_info; + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; +}; + +int cam_bps_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_bps_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_bps_irq(int irq_num, void *data); +#endif /* CAM_BPS_CORE_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_dev.c b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..a80c27325b727ee9e62a541a4839c40f2be1ed15 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_dev.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include <linux/timer.h> +#include "bps_core.h" +#include "bps_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_icp_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static struct cam_bps_device_hw_info cam_bps_hw_info = { + .hw_idx = 0, + .pwr_ctrl = 0x5c, + .pwr_status = 0x58, + .reserved = 0, +}; +EXPORT_SYMBOL(cam_bps_hw_info); + +static char bps_dev_name[8]; + +static bool cam_bps_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + switch (irq_data->irq_type) { + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_DECODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Decode error type=%d status=%x thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d", + irq_data->irq_type, + irq_data->u.dec_err.decerr_status.value, + irq_data->u.dec_err.decerr_status.thr_err, + irq_data->u.dec_err.decerr_status.fcl_err, + irq_data->u.dec_err.decerr_status.len_md_err, + irq_data->u.dec_err.decerr_status.format_err); + error_handled = true; + break; + case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ICP, + "IPE/BPS UBWC Encode error type=%d status=%x", + irq_data->irq_type, + irq_data->u.enc_err.encerr_status.value); + error_handled = true; + break; + default: + break; + } + + return error_handled; +} + +int cam_bps_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_bps_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "bps", sizeof("bps")); + cpas_register_params.cam_cpas_client_cb = cam_bps_cpas_cb; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +int cam_bps_probe(struct platform_device *pdev) +{ + struct cam_hw_info *bps_dev = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_bps_device_core_info *core_info = NULL; + struct cam_bps_device_hw_info *hw_info = NULL; + int rc = 0; + + bps_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!bps_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &bps_dev_intf->hw_idx); + + bps_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!bps_dev) { + kfree(bps_dev_intf); + return -ENOMEM; + } + + memset(bps_dev_name, 0, sizeof(bps_dev_name)); + snprintf(bps_dev_name, sizeof(bps_dev_name), + "bps%1u", bps_dev_intf->hw_idx); + + bps_dev->soc_info.pdev = pdev; + bps_dev->soc_info.dev = &pdev->dev; + bps_dev->soc_info.dev_name = bps_dev_name; + bps_dev_intf->hw_priv = bps_dev; + bps_dev_intf->hw_ops.init = cam_bps_init_hw; + bps_dev_intf->hw_ops.deinit = cam_bps_deinit_hw; + bps_dev_intf->hw_ops.process_cmd = cam_bps_process_cmd; + bps_dev_intf->hw_type = CAM_ICP_DEV_BPS; + platform_set_drvdata(pdev, bps_dev_intf); + bps_dev->core_info = kzalloc(sizeof(struct cam_bps_device_core_info), + GFP_KERNEL); + if (!bps_dev->core_info) { + kfree(bps_dev); + kfree(bps_dev_intf); + return -ENOMEM; + } + core_info = (struct cam_bps_device_core_info *)bps_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ICP, "No bps hardware info"); + kfree(bps_dev->core_info); + kfree(bps_dev); + kfree(bps_dev_intf); + rc = -EINVAL; + return rc; + } + hw_info = &cam_bps_hw_info; + core_info->bps_hw_info = hw_info; + + rc = cam_bps_init_soc_resources(&bps_dev->soc_info, cam_bps_irq, + bps_dev); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed to init_soc"); + kfree(bps_dev->core_info); + kfree(bps_dev); + kfree(bps_dev_intf); + return rc; + } + CAM_DBG(CAM_ICP, "soc info : %pK", + (void *)&bps_dev->soc_info); + + rc = cam_bps_register_cpas(&bps_dev->soc_info, + core_info, bps_dev_intf->hw_idx); + if (rc < 0) { + kfree(bps_dev->core_info); + kfree(bps_dev); + kfree(bps_dev_intf); + return rc; + } + bps_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&bps_dev->hw_mutex); + spin_lock_init(&bps_dev->hw_lock); + init_completion(&bps_dev->hw_complete); + CAM_DBG(CAM_ICP, "BPS%d probe successful", + bps_dev_intf->hw_idx); + + return rc; +} + +static const struct of_device_id cam_bps_dt_match[] = { + { + .compatible = "qcom,cam-bps", + .data = &cam_bps_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_bps_dt_match); + +static struct platform_driver cam_bps_driver = { + .probe = cam_bps_probe, + .driver = { + .name = "cam-bps", + .owner = THIS_MODULE, + .of_match_table = cam_bps_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_bps_init_module(void) +{ + return platform_driver_register(&cam_bps_driver); +} + +static void __exit cam_bps_exit_module(void) +{ + platform_driver_unregister(&cam_bps_driver); +} + +module_init(cam_bps_init_module); +module_exit(cam_bps_exit_module); +MODULE_DESCRIPTION("CAM BPS driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..481eeafdb0b2a23d19a0297152bd9fa93ff6dcd6 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "bps_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static int cam_bps_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + CAM_ERR(CAM_ICP, "get bps dt prop is failed"); + + return rc; +} + +static int cam_bps_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t bps_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, bps_irq_handler, + irq_data); + + return rc; +} + +int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t bps_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_bps_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_bps_request_platform_resource(soc_info, bps_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, false); + if (rc) + CAM_ERR(CAM_ICP, "enable platform failed"); + + return rc; +} + +int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + false); + if (rc) + CAM_ERR(CAM_ICP, "disable platform failed"); + + return rc; +} + +int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + + return rc; +} + +int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + + return rc; +} + +int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate) +{ + int32_t src_clk_idx; + + if (!soc_info) + return -EINVAL; + + src_clk_idx = soc_info->src_clk_idx; + + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_PERF, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} + +int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) +{ + int rc = 0; + + if (clk_enable) + rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + else + cam_soc_util_clk_disable_default(soc_info); + + return rc; +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_soc.h b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..da4feac909e40592c4c5addee522d98418da2984 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/bps_hw/bps_soc.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_BPS_SOC_H_ +#define _CAM_BPS_SOC_H_ + +#include "cam_soc_util.h" + +int cam_bps_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t bps_irq_handler, void *irq_data); + +int cam_bps_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_bps_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk); + +int cam_bps_get_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_bps_transfer_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate); +int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable); +#endif /* _CAM_BPS_SOC_H_*/ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b87d5dba817a51c2dd3e59fb0893e64e1f04d02c --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/isp/isp_hw/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/a5_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_hw_mgr.o diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..9b47ac37349a0e23105520fd09dc463310b0b451 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -0,0 +1,5951 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/io.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/timer.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include <media/cam_cpas.h> + +#include "cam_sync_api.h" +#include "cam_packet_util.h" +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_icp_hw_mgr.h" +#include "cam_a5_hw_intf.h" +#include "cam_bps_hw_intf.h" +#include "cam_ipe_hw_intf.h" +#include "cam_smmu_api.h" +#include "cam_mem_mgr.h" +#include "hfi_intf.h" +#include "hfi_reg.h" +#include "hfi_session_defs.h" +#include "hfi_sys_defs.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "a5_core.h" +#include "hfi_sys_defs.h" +#include "cam_debug_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" +#include "cam_cpas_api.h" +#include "cam_common_util.h" + +#define ICP_WORKQ_TASK_CMD_TYPE 1 +#define ICP_WORKQ_TASK_MSG_TYPE 2 + +#define ICP_DEV_TYPE_TO_CLK_TYPE(dev_type) \ + ((dev_type == CAM_ICP_RES_TYPE_BPS) ? ICP_CLK_HW_BPS : ICP_CLK_HW_IPE) + +#define ICP_DEVICE_IDLE_TIMEOUT 400 + +static struct cam_icp_hw_mgr icp_hw_mgr; + +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); + +static int cam_icp_dump_io_cfg(struct cam_icp_hw_ctx_data *ctx_data, + int32_t buf_handle) +{ + uintptr_t vaddr_ptr; + uint32_t *ptr; + size_t len; + int rc, i; + char buf[512]; + int used = 0; + + rc = cam_mem_get_cpu_buf(buf_handle, &vaddr_ptr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get io_cfg buf address for %d", + ctx_data->ctx_id); + return rc; + } + + len = len / sizeof(uint32_t); + ptr = (uint32_t *)vaddr_ptr; + for (i = 0; i < len; i++) { + used += snprintf(buf + used, + sizeof(buf) - used, "0X%08X-", ptr[i]); + if (!(i % 8)) { + CAM_INFO(CAM_ICP, "%s: %s", __func__, buf); + used = 0; + } + } + + return rc; +} + +static const char *cam_icp_dev_type_to_name( + uint32_t dev_type) +{ + switch (dev_type) { + case CAM_ICP_RES_TYPE_BPS: + return "BPS"; + case CAM_ICP_RES_TYPE_IPE_RT: + return "IPE_RT"; + case CAM_ICP_RES_TYPE_IPE: + return "IPE"; + default: + return "Invalid dev type"; + } +} + +static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + int rc; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is NULL"); + return -EINVAL; + } + + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_UBWC_CFG, NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "CAM_ICP_A5_CMD_UBWC_CFG is failed"); + + return rc; +} + +static void cam_icp_hw_mgr_clk_info_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + struct cam_icp_clk_info *hw_mgr_clk_info; + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + else + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + + if (hw_mgr_clk_info->base_clk >= ctx_data->clk_info.base_clk) + hw_mgr_clk_info->base_clk -= ctx_data->clk_info.base_clk; +} + +static void cam_icp_hw_mgr_reset_clk_info(struct cam_icp_hw_mgr *hw_mgr) +{ + int i; + + for (i = 0; i < ICP_CLK_HW_MAX; i++) { + hw_mgr->clk_info[i].base_clk = 0; + hw_mgr->clk_info[i].curr_clk = ICP_CLK_SVS_HZ; + hw_mgr->clk_info[i].threshold = ICP_OVER_CLK_THRESHOLD; + hw_mgr->clk_info[i].over_clked = 0; + hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + } + hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ; +} + +static int cam_icp_get_actual_clk_rate_idx( + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + for (i = 0; i < CAM_MAX_VOTE; i++) + if (ctx_data->clk_info.clk_rate[i] >= base_clk) + return i; + + /* + * Caller has to ensure returned index is within array + * size bounds while accessing that index. + */ + + return i; +} + +static bool cam_icp_is_over_clk(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info) +{ + int base_clk_idx; + int curr_clk_idx; + + base_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data, + hw_mgr_clk_info->base_clk); + + curr_clk_idx = cam_icp_get_actual_clk_rate_idx(ctx_data, + hw_mgr_clk_info->curr_clk); + + CAM_DBG(CAM_PERF, "bc_idx = %d cc_idx = %d %d %d", + base_clk_idx, curr_clk_idx, hw_mgr_clk_info->base_clk, + hw_mgr_clk_info->curr_clk); + + if (curr_clk_idx > base_clk_idx) + return true; + + return false; +} + +static int cam_icp_get_lower_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + i = cam_icp_get_actual_clk_rate_idx(ctx_data, base_clk); + + if (i > 0) + return ctx_data->clk_info.clk_rate[i - 1]; + + CAM_DBG(CAM_PERF, "Already clk at lower level"); + return base_clk; +} + +static int cam_icp_get_next_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + i = cam_icp_get_actual_clk_rate_idx(ctx_data, base_clk); + + if (i < CAM_MAX_VOTE - 1) + return ctx_data->clk_info.clk_rate[i + 1]; + + CAM_DBG(CAM_PERF, "Already clk at higher level"); + + return base_clk; +} + +static int cam_icp_get_actual_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, uint32_t base_clk) +{ + int i; + + for (i = 0; i < CAM_MAX_VOTE; i++) + if (ctx_data->clk_info.clk_rate[i] >= base_clk) + return ctx_data->clk_info.clk_rate[i]; + + return base_clk; +} + +static int cam_icp_supported_clk_rates(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *dev_intf = NULL; + struct cam_hw_info *dev = NULL; + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + dev_intf = hw_mgr->bps_dev_intf; + else + dev_intf = hw_mgr->ipe0_dev_intf; + + if (!dev_intf) { + CAM_ERR(CAM_ICP, "dev_intf is invalid"); + return -EINVAL; + } + dev = (struct cam_hw_info *)dev_intf->hw_priv; + soc_info = &dev->soc_info; + + for (i = 0; i < CAM_MAX_VOTE; i++) { + ctx_data->clk_info.clk_rate[i] = + soc_info->clk_rate[i][soc_info->src_clk_idx]; + CAM_DBG(CAM_PERF, "clk_info[%d] = %d", + i, ctx_data->clk_info.clk_rate[i]); + } + + return 0; +} + +static int cam_icp_clk_idx_from_req_id(struct cam_icp_hw_ctx_data *ctx_data, + uint64_t req_id) +{ + struct hfi_frame_process_info *frame_process; + int i; + + frame_process = &ctx_data->hfi_frame_process; + + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) + if (frame_process->request_id[i] == req_id) + return i; + + return 0; +} + +static int cam_icp_ctx_clk_info_init(struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + ctx_data->clk_info.uncompressed_bw = 0; + ctx_data->clk_info.compressed_bw = 0; + for (i = 0; i < CAM_ICP_MAX_PER_PATH_VOTES; i++) { + ctx_data->clk_info.axi_path[i].camnoc_bw = 0; + ctx_data->clk_info.axi_path[i].mnoc_ab_bw = 0; + ctx_data->clk_info.axi_path[i].mnoc_ib_bw = 0; + } + + cam_icp_supported_clk_rates(&icp_hw_mgr, ctx_data); + + return 0; +} + +static bool cam_icp_frame_pending(struct cam_icp_hw_ctx_data *ctx_data) +{ + return !bitmap_empty(ctx_data->hfi_frame_process.bitmap, + CAM_FRAME_CMD_MAX); +} + +static int cam_icp_ctx_timer_reset(struct cam_icp_hw_ctx_data *ctx_data) +{ + if (ctx_data && ctx_data->watch_dog) { + ctx_data->watch_dog_reset_counter++; + CAM_DBG(CAM_PERF, "reset timer : ctx_id = %d, counter=%d", + ctx_data->ctx_id, ctx_data->watch_dog_reset_counter); + crm_timer_reset(ctx_data->watch_dog); + } + + return 0; +} + +static void cam_icp_device_timer_reset(struct cam_icp_hw_mgr *hw_mgr, + int device_index) +{ + if ((device_index >= ICP_CLK_HW_MAX) || (!hw_mgr)) + return; + + if (hw_mgr->clk_info[device_index].watch_dog) { + CAM_DBG(CAM_PERF, "reset timer : device_index = %d", + device_index); + crm_timer_reset(hw_mgr->clk_info[device_index].watch_dog); + hw_mgr->clk_info[device_index].watch_dog_reset_counter++; + } +} + +static int32_t cam_icp_deinit_idle_clk(void *priv, void *data) +{ + struct cam_icp_hw_mgr *hw_mgr = (struct cam_icp_hw_mgr *)priv; + struct clk_work_data *task_data = (struct clk_work_data *)data; + struct cam_icp_clk_info *clk_info = + (struct cam_icp_clk_info *)task_data->data; + uint32_t id; + uint32_t i; + struct cam_icp_hw_ctx_data *ctx_data; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_a5_clk_update_cmd clk_upd_cmd; + int rc = 0; + bool busy = false; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + clk_info->base_clk = 0; + clk_info->curr_clk = 0; + clk_info->over_clked = 0; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + ctx_data = &hw_mgr->ctx_data[i]; + mutex_lock(&ctx_data->ctx_mutex); + if ((ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED) && + (ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type) + == clk_info->hw_type)) { + busy = cam_icp_frame_pending(ctx_data); + if (busy) { + mutex_unlock(&ctx_data->ctx_mutex); + break; + } + cam_icp_ctx_clk_info_init(ctx_data); + } + mutex_unlock(&ctx_data->ctx_mutex); + } + + if (busy) { + cam_icp_device_timer_reset(hw_mgr, clk_info->hw_type); + rc = -EBUSY; + goto done; + } + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + rc = -EINVAL; + goto done; + } + + if (clk_info->hw_type == ICP_CLK_HW_BPS) { + dev_intf = bps_dev_intf; + id = CAM_ICP_BPS_CMD_DISABLE_CLK; + } else if (clk_info->hw_type == ICP_CLK_HW_IPE) { + dev_intf = ipe0_dev_intf; + id = CAM_ICP_IPE_CMD_DISABLE_CLK; + } else { + CAM_ERR(CAM_ICP, "Error"); + goto done; + } + + CAM_DBG(CAM_PERF, "Disable %d", clk_info->hw_type); + + clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; + + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd)); + + if (clk_info->hw_type != ICP_CLK_HW_BPS) + if (ipe1_dev_intf) + ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, id, + &clk_upd_cmd, + sizeof(struct cam_a5_clk_update_cmd)); + +done: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_remove_ctx_bw(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + struct cam_hw_intf *dev_intf = NULL; + uint32_t id; + uint64_t temp; + struct cam_icp_clk_info *clk_info; + struct cam_icp_cpas_vote clk_update; + int i = 0; + int device_share_ratio = 1; + uint64_t total_ab_bw = 0; + + if (!ctx_data->icp_dev_acquire_info) { + CAM_WARN(CAM_ICP, "NULL acquire info"); + return -EINVAL; + } + + if ((!hw_mgr->ipe0_dev_intf) || (!hw_mgr->bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + return -EINVAL; + } + + CAM_DBG(CAM_PERF, + "ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + ctx_data->ctx_id, + ctx_data->clk_info.uncompressed_bw, + ctx_data->clk_info.compressed_bw, + ctx_data->clk_info.curr_fc, ctx_data->clk_info.base_clk); + + if (!ctx_data->clk_info.bw_included) { + CAM_DBG(CAM_PERF, "ctx_id = %d BW vote already removed", + ctx_data->ctx_id); + return 0; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + dev_intf = hw_mgr->bps_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + id = CAM_ICP_BPS_CMD_VOTE_CPAS; + } else { + dev_intf = hw_mgr->ipe0_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + id = CAM_ICP_IPE_CMD_VOTE_CPAS; + } + + /* + * Since there are 2 devices, we assume the load is evenly shared + * between HWs and corresponding AXI paths. So divide total bw by half + * to vote on each device + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (hw_mgr->ipe1_dev_intf)) + device_share_ratio = 2; + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { + clk_update.axi_vote.num_paths = 1; + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_BPS_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_BPS_DEFAULT_AXI_TRANSAC; + } else { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_IPE_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_IPE_DEFAULT_AXI_TRANSAC; + } + + clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw; + clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_bw; + + total_ab_bw = clk_info->compressed_bw; + + ctx_data->clk_info.uncompressed_bw = 0; + ctx_data->clk_info.compressed_bw = 0; + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + + clk_update.axi_vote.num_paths = 1; + + temp = clk_info->uncompressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].camnoc_bw = temp; + + temp = clk_info->compressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].mnoc_ab_bw = temp; + clk_update.axi_vote.axi_path[0].mnoc_ib_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ab_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ib_bw = temp; + } else { + int path_index; + + /* + * Remove previous vote of this context from hw mgr first. + * hw_mgr_clk_info has all valid paths, with each path in its + * own index. BW that we wanted to vote now is after removing + * current context's vote from hw mgr consolidated vote + */ + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + /* + * By assuming BPS has Read-All, Write-All + * votes only. + */ + path_index = + ctx_data->clk_info.axi_path[i].transac_type - + CAM_AXI_TRANSACTION_READ; + } else { + path_index = + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; + } + + if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_PERF, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); + continue; + } + + clk_info->axi_path[path_index].camnoc_bw -= + ctx_data->clk_info.axi_path[i].camnoc_bw; + clk_info->axi_path[path_index].mnoc_ab_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + clk_info->axi_path[path_index].mnoc_ib_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + clk_info->axi_path[path_index].ddr_ab_bw -= + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + clk_info->axi_path[path_index].ddr_ib_bw -= + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + + total_ab_bw += + clk_info->axi_path[path_index].mnoc_ab_bw; + + CAM_DBG(CAM_PERF, + "Removing ctx bw from path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + ctx_data->clk_info.axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + ctx_data->clk_info.axi_path[i].transac_type), + ctx_data->clk_info.axi_path[i].camnoc_bw, + ctx_data->clk_info.axi_path[i].mnoc_ab_bw, + ctx_data->clk_info.axi_path[i].mnoc_ib_bw, + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type)); + + CAM_DBG(CAM_PERF, + "Final HW bw for path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + clk_info->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + clk_info->axi_path[i].transac_type), + clk_info->axi_path[i].camnoc_bw, + clk_info->axi_path[i].mnoc_ab_bw, + clk_info->axi_path[i].mnoc_ib_bw, + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type)); + } + + memset(&ctx_data->clk_info.axi_path[0], 0, + CAM_ICP_MAX_PER_PATH_VOTES * + sizeof(struct cam_axi_per_path_bw_vote)); + ctx_data->clk_info.curr_fc = 0; + ctx_data->clk_info.base_clk = 0; + + clk_update.axi_vote.num_paths = clk_info->num_paths; + memcpy(&clk_update.axi_vote.axi_path[0], + &clk_info->axi_path[0], + clk_update.axi_vote.num_paths * + sizeof(struct cam_axi_per_path_bw_vote)); + + if (device_share_ratio > 1) { + for (i = 0; i < clk_update.axi_vote.num_paths; i++) { + do_div( + clk_update.axi_vote.axi_path[i].camnoc_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ib_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ib_bw, + device_share_ratio); + } + } + } + + clk_update.axi_vote_valid = true; + + if (total_ab_bw == 0) { + /* If no more contexts are active, reduce AHB vote to minimum */ + clk_update.ahb_vote.type = CAM_VOTE_ABSOLUTE; + clk_update.ahb_vote.vote.level = CAM_LOWSVS_VOTE; + clk_update.ahb_vote_valid = true; + } else { + clk_update.ahb_vote_valid = false; + } + + rc = dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, "Failed in updating cpas vote, rc=%d", rc); + + /* + * Vote half bandwidth each on both devices. + * Total bw at mnoc - CPAS will take care of adding up. + * camnoc clk calculate is more accurate this way. + */ + if ((!rc) && (hw_mgr->ipe1_dev_intf) && + (ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS)) { + dev_intf = hw_mgr->ipe1_dev_intf; + rc = dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, + id, &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, + "Failed in updating cpas vote for ipe 2, rc=%d", + rc); + } + + ctx_data->clk_info.bw_included = false; + + CAM_DBG(CAM_PERF, "X :ctx_id = %d curr_fc = %u bc = %u", + ctx_data->ctx_id, ctx_data->clk_info.curr_fc, + ctx_data->clk_info.base_clk); + + return rc; + +} + + +static int32_t cam_icp_ctx_timer(void *priv, void *data) +{ + struct clk_work_data *task_data = (struct clk_work_data *)data; + struct cam_icp_hw_ctx_data *ctx_data = + (struct cam_icp_hw_ctx_data *)task_data->data; + + if (!ctx_data) { + CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + + CAM_DBG(CAM_PERF, + "ctx_id = %d ubw = %lld cbw = %lld curr_fc = %u bc = %u", + ctx_data->ctx_id, + ctx_data->clk_info.uncompressed_bw, + ctx_data->clk_info.compressed_bw, + ctx_data->clk_info.curr_fc, + ctx_data->clk_info.base_clk); + + if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || + (ctx_data->watch_dog_reset_counter == 0)) { + CAM_DBG(CAM_PERF, "state %d, counter=%d", + ctx_data->state, ctx_data->watch_dog_reset_counter); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + if (cam_icp_frame_pending(ctx_data)) { + cam_icp_ctx_timer_reset(ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return -EBUSY; + } + + cam_icp_remove_ctx_bw(&icp_hw_mgr, ctx_data); + + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static void cam_icp_ctx_timer_cb(struct timer_list *timer_data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct clk_work_data *task_data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + + spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); + return; + } + + task_data = (struct clk_work_data *)task->payload; + task_data->data = timer->parent; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_ctx_timer; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); +} + +static void cam_icp_device_timer_cb(struct timer_list *timer_data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct clk_work_data *task_data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + + spin_lock_irqsave(&icp_hw_mgr.hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(icp_hw_mgr.timer_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); + return; + } + + task_data = (struct clk_work_data *)task->payload; + task_data->data = timer->parent; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_deinit_idle_clk; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); +} + +static int cam_icp_clk_info_init(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int i, j; + + for (i = 0; i < ICP_CLK_HW_MAX; i++) { + hw_mgr->clk_info[i].base_clk = ICP_CLK_SVS_HZ; + hw_mgr->clk_info[i].curr_clk = ICP_CLK_SVS_HZ; + hw_mgr->clk_info[i].threshold = ICP_OVER_CLK_THRESHOLD; + hw_mgr->clk_info[i].over_clked = 0; + hw_mgr->clk_info[i].uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + hw_mgr->clk_info[i].compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + for (j = 0; j < CAM_ICP_MAX_PER_PATH_VOTES; j++) { + hw_mgr->clk_info[i].axi_path[j].path_data_type = 0; + hw_mgr->clk_info[i].axi_path[j].transac_type = 0; + hw_mgr->clk_info[i].axi_path[j].camnoc_bw = 0; + hw_mgr->clk_info[i].axi_path[j].mnoc_ab_bw = 0; + hw_mgr->clk_info[i].axi_path[j].mnoc_ib_bw = 0; + } + + hw_mgr->clk_info[i].hw_type = i; + hw_mgr->clk_info[i].watch_dog_reset_counter = 0; + } + + hw_mgr->icp_default_clk = ICP_CLK_SVS_HZ; + + return 0; +} + +static int cam_icp_ctx_timer_start(struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + + rc = crm_timer_init(&ctx_data->watch_dog, + 200, ctx_data, &cam_icp_ctx_timer_cb); + if (rc) + CAM_ERR(CAM_ICP, "Failed to start timer"); + + ctx_data->watch_dog_reset_counter = 0; + + CAM_DBG(CAM_PERF, "start timer : ctx_id = %d", ctx_data->ctx_id); + return rc; +} + +static int cam_icp_device_timer_start(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + int i; + + for (i = 0; i < ICP_CLK_HW_MAX; i++) { + if (!hw_mgr->clk_info[i].watch_dog) { + rc = crm_timer_init(&hw_mgr->clk_info[i].watch_dog, + ICP_DEVICE_IDLE_TIMEOUT, &hw_mgr->clk_info[i], + &cam_icp_device_timer_cb); + + if (rc) + CAM_ERR(CAM_ICP, "Failed to start timer %d", i); + + hw_mgr->clk_info[i].watch_dog_reset_counter = 0; + } + } + + return rc; +} + +static int cam_icp_ctx_timer_stop(struct cam_icp_hw_ctx_data *ctx_data) +{ + if (ctx_data->watch_dog) { + CAM_DBG(CAM_PERF, "stop timer : ctx_id = %d", ctx_data->ctx_id); + ctx_data->watch_dog_reset_counter = 0; + crm_timer_exit(&ctx_data->watch_dog); + ctx_data->watch_dog = NULL; + } + + return 0; +} + +static void cam_icp_device_timer_stop(struct cam_icp_hw_mgr *hw_mgr) +{ + if (!hw_mgr->bps_ctxt_cnt && + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog = NULL; + } + + if (!hw_mgr->ipe_ctxt_cnt && + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog = NULL; + } +} + +static uint32_t cam_icp_mgr_calc_base_clk(uint32_t frame_cycles, + uint64_t budget) +{ + uint64_t base_clk; + uint64_t mul = 1000000000; + + base_clk = frame_cycles * mul; + do_div(base_clk, budget); + + CAM_DBG(CAM_PERF, "budget = %lld fc = %d ib = %lld base_clk = %lld", + budget, frame_cycles, + (long long)(frame_cycles * mul), base_clk); + + return base_clk; +} + +static bool cam_icp_busy_prev_reqs(struct hfi_frame_process_info *frm_process, + uint64_t req_id) +{ + int i; + int cnt; + + for (i = 0, cnt = 0; i < CAM_FRAME_CMD_MAX; i++) { + if (frm_process->request_id[i]) { + if (frm_process->fw_process_flag[i]) { + CAM_DBG(CAM_PERF, "r id = %lld busy = %d", + frm_process->request_id[i], + frm_process->fw_process_flag[i]); + cnt++; + } + } + } + if (cnt > 1) + return true; + + return false; +} + +static int cam_icp_calc_total_clk(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_clk_info *hw_mgr_clk_info, uint32_t dev_type) +{ + int i; + struct cam_icp_hw_ctx_data *ctx_data; + + hw_mgr_clk_info->base_clk = 0; + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + ctx_data = &hw_mgr->ctx_data[i]; + if (ctx_data->state == CAM_ICP_CTX_STATE_ACQUIRED && + ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type) == + ICP_DEV_TYPE_TO_CLK_TYPE(dev_type)) + hw_mgr_clk_info->base_clk += + ctx_data->clk_info.base_clk; + } + + return 0; +} + +static bool cam_icp_update_clk_busy(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + uint32_t base_clk) +{ + uint32_t next_clk_level; + uint32_t actual_clk; + bool rc = false; + + /* 1. if current request frame cycles(fc) are more than previous + * frame fc + * Calculate the new base clock. + * if sum of base clocks are more than next available clk level + * Update clock rate, change curr_clk_rate to sum of base clock + * rates and make over_clked to zero + * else + * Update clock rate to next level, update curr_clk_rate and make + * overclked cnt to zero + * 2. if current fc is less than or equal to previous frame fc + * Still Bump up the clock to next available level + * if it is available, then update clock, make overclk cnt to + * zero. If the clock is already at highest clock rate then + * no need to update the clock + */ + ctx_data->clk_info.base_clk = base_clk; + hw_mgr_clk_info->over_clked = 0; + if (clk_info->frame_cycles > ctx_data->clk_info.curr_fc) { + cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info, + ctx_data->icp_dev_acquire_info->dev_type); + actual_clk = cam_icp_get_actual_clk_rate(hw_mgr, + ctx_data, base_clk); + if (hw_mgr_clk_info->base_clk > actual_clk) { + hw_mgr_clk_info->curr_clk = hw_mgr_clk_info->base_clk; + } else { + next_clk_level = cam_icp_get_next_clk_rate(hw_mgr, + ctx_data, hw_mgr_clk_info->curr_clk); + hw_mgr_clk_info->curr_clk = next_clk_level; + } + rc = true; + } else { + next_clk_level = + cam_icp_get_next_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + if (hw_mgr_clk_info->curr_clk < next_clk_level) { + hw_mgr_clk_info->curr_clk = next_clk_level; + rc = true; + } + } + ctx_data->clk_info.curr_fc = clk_info->frame_cycles; + + return rc; +} + +static bool cam_icp_update_clk_overclk_free(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + uint32_t base_clk) +{ + int rc = false; + + /* + * In caseof no pending packets case + * 1. In caseof overclk cnt is less than threshold, increase + * overclk count and no update in the clock rate + * 2. In caseof overclk cnt is greater than or equal to threshold + * then lower clock rate by one level and update hw_mgr current + * clock value. + * a. In case of new clock rate greater than sum of clock + * rates, reset overclk count value to zero if it is + * overclock + * b. if it is less than sum of base clocks then go to next + * level of clock and make overclk count to zero + * c. if it is same as sum of base clock rates update overclock + * cnt to 0 + */ + if (hw_mgr_clk_info->over_clked < hw_mgr_clk_info->threshold) { + hw_mgr_clk_info->over_clked++; + rc = false; + } else { + hw_mgr_clk_info->curr_clk = + cam_icp_get_lower_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) { + if (cam_icp_is_over_clk(hw_mgr, ctx_data, + hw_mgr_clk_info)) + hw_mgr_clk_info->over_clked = 0; + } else if (hw_mgr_clk_info->curr_clk < + hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->curr_clk = + cam_icp_get_next_clk_rate(hw_mgr, ctx_data, + hw_mgr_clk_info->curr_clk); + hw_mgr_clk_info->over_clked = 0; + } else if (hw_mgr_clk_info->curr_clk == + hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->over_clked = 0; + } + rc = true; + } + + return rc; +} + +static bool cam_icp_update_clk_free(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + uint32_t base_clk) +{ + int rc = false; + bool over_clocked = false; + + ctx_data->clk_info.curr_fc = clk_info->frame_cycles; + ctx_data->clk_info.base_clk = base_clk; + cam_icp_calc_total_clk(hw_mgr, hw_mgr_clk_info, + ctx_data->icp_dev_acquire_info->dev_type); + + /* + * Current clock is not always sum of base clocks, due to + * clock scales update to next higher or lower levels, it + * equals to one of discrete clock values supported by hardware. + * So even current clock is higher than sum of base clocks, we + * can not consider it is over clocked. if it is greater than + * discrete clock level then only it is considered as over clock. + * 1. Handle over clock case + * 2. If current clock is less than sum of base clocks + * update current clock + * 3. If current clock is same as sum of base clocks no action + */ + + over_clocked = cam_icp_is_over_clk(hw_mgr, ctx_data, + hw_mgr_clk_info); + + if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk && + over_clocked) { + rc = cam_icp_update_clk_overclk_free(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + } else if (hw_mgr_clk_info->curr_clk > hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->over_clked = 0; + rc = false; + } else if (hw_mgr_clk_info->curr_clk < hw_mgr_clk_info->base_clk) { + hw_mgr_clk_info->curr_clk = cam_icp_get_actual_clk_rate(hw_mgr, + ctx_data, hw_mgr_clk_info->base_clk); + rc = true; + } + + return rc; +} + +static bool cam_icp_debug_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) +{ + if (icp_hw_mgr.icp_debug_clk < ICP_CLK_TURBO_HZ && + icp_hw_mgr.icp_debug_clk && + icp_hw_mgr.icp_debug_clk != hw_mgr_clk_info->curr_clk) { + hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_debug_clk; + hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_debug_clk; + CAM_DBG(CAM_PERF, "bc = %d cc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); + return true; + } + + return false; +} + +static bool cam_icp_default_clk_update(struct cam_icp_clk_info *hw_mgr_clk_info) +{ + if (icp_hw_mgr.icp_default_clk != hw_mgr_clk_info->curr_clk) { + hw_mgr_clk_info->base_clk = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->curr_clk = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->uncompressed_bw = icp_hw_mgr.icp_default_clk; + hw_mgr_clk_info->compressed_bw = icp_hw_mgr.icp_default_clk; + CAM_DBG(CAM_PERF, "bc = %d cc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk); + return true; + } + + return false; +} + +static bool cam_icp_update_bw_v2(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_req_internal_v2 *clk_info, + bool busy) +{ + int i, path_index; + bool update_required = true; + + /* + * If current request bandwidth is different from previous frames, then + * recalculate bandwidth of all contexts of same hardware and update + * voting of bandwidth + */ + + for (i = 0; i < clk_info->num_paths; i++) + CAM_DBG(CAM_PERF, "clk_info camnoc = %lld busy = %d", + clk_info->axi_path[i].camnoc_bw, busy); + + if (clk_info->num_paths == ctx_data->clk_info.num_paths) { + update_required = false; + for (i = 0; i < clk_info->num_paths; i++) { + if ((clk_info->axi_path[i].transac_type == + ctx_data->clk_info.axi_path[i].transac_type) && + (clk_info->axi_path[i].path_data_type == + ctx_data->clk_info.axi_path[i].path_data_type) && + (clk_info->axi_path[i].camnoc_bw == + ctx_data->clk_info.axi_path[i].camnoc_bw) && + (clk_info->axi_path[i].mnoc_ab_bw == + ctx_data->clk_info.axi_path[i].mnoc_ab_bw)) { + continue; + } else { + update_required = true; + break; + } + } + } + + if (!update_required) { + CAM_DBG(CAM_PERF, + "Incoming BW hasn't changed, no update required, num_paths=%d", + clk_info->num_paths); + return false; + } + + if (busy) { + for (i = 0; i < clk_info->num_paths; i++) { + if (ctx_data->clk_info.axi_path[i].camnoc_bw > + clk_info->axi_path[i].camnoc_bw) + return false; + } + } + + /* + * Remove previous vote of this context from hw mgr first. + * hw_mgr_clk_info has all valid paths, with each path in its own index + */ + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + /* By assuming BPS has Read-All, Write-All votes only */ + path_index = + ctx_data->clk_info.axi_path[i].transac_type - + CAM_AXI_TRANSACTION_READ; + } else { + path_index = + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; + } + + if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_PERF, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); + continue; + } + + hw_mgr_clk_info->axi_path[path_index].camnoc_bw -= + ctx_data->clk_info.axi_path[i].camnoc_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ib_bw -= + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ab_bw -= + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw -= + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + } + + ctx_data->clk_info.num_paths = clk_info->num_paths; + + memcpy(&ctx_data->clk_info.axi_path[0], + &clk_info->axi_path[0], + clk_info->num_paths * sizeof(struct cam_axi_per_path_bw_vote)); + + /* + * Add new vote of this context in hw mgr. + * hw_mgr_clk_info has all paths, with each path in its own index + */ + for (i = 0; i < ctx_data->clk_info.num_paths; i++) { + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + /* By assuming BPS has Read-All, Write-All votes only */ + path_index = + ctx_data->clk_info.axi_path[i].transac_type - + CAM_AXI_TRANSACTION_READ; + } else { + path_index = + ctx_data->clk_info.axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IPE_START_OFFSET; + } + + if (path_index >= CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_WARN(CAM_PERF, + "Invalid path %d, start offset=%d, max=%d", + ctx_data->clk_info.axi_path[i].path_data_type, + CAM_AXI_PATH_DATA_IPE_START_OFFSET, + CAM_ICP_MAX_PER_PATH_VOTES); + continue; + } + + hw_mgr_clk_info->axi_path[path_index].path_data_type = + ctx_data->clk_info.axi_path[i].path_data_type; + hw_mgr_clk_info->axi_path[path_index].transac_type = + ctx_data->clk_info.axi_path[i].transac_type; + hw_mgr_clk_info->axi_path[path_index].camnoc_bw += + ctx_data->clk_info.axi_path[i].camnoc_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw += + ctx_data->clk_info.axi_path[i].mnoc_ab_bw; + hw_mgr_clk_info->axi_path[path_index].mnoc_ib_bw += + ctx_data->clk_info.axi_path[i].mnoc_ib_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ab_bw += + ctx_data->clk_info.axi_path[i].ddr_ab_bw; + hw_mgr_clk_info->axi_path[path_index].ddr_ib_bw += + ctx_data->clk_info.axi_path[i].ddr_ib_bw; + + CAM_DBG(CAM_PERF, + "Consolidate Path Vote : Dev[%s] i[%d] path_idx[%d] : [%s %s] [%lld %lld]", + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type), + i, path_index, + cam_cpas_axi_util_trans_type_to_string( + hw_mgr_clk_info->axi_path[path_index].transac_type), + cam_cpas_axi_util_path_type_to_string( + hw_mgr_clk_info->axi_path[path_index].path_data_type), + hw_mgr_clk_info->axi_path[path_index].camnoc_bw, + hw_mgr_clk_info->axi_path[path_index].mnoc_ab_bw); + } + + ctx_data->clk_info.bw_included = true; + + if (hw_mgr_clk_info->num_paths < ctx_data->clk_info.num_paths) + hw_mgr_clk_info->num_paths = ctx_data->clk_info.num_paths; + + return true; +} + +static bool cam_icp_update_bw(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_icp_clk_info *hw_mgr_clk_info, + struct cam_icp_clk_bw_request *clk_info, + bool busy) +{ + int i; + struct cam_icp_hw_ctx_data *ctx; + + /* + * If current request bandwidth is different from previous frames, then + * recalculate bandwidth of all contexts of same hardware and update + * voting of bandwidth + */ + CAM_DBG(CAM_PERF, "ubw ctx = %lld clk_info ubw = %lld busy = %d", + ctx_data->clk_info.uncompressed_bw, + clk_info->uncompressed_bw, busy); + + if ((clk_info->uncompressed_bw == ctx_data->clk_info.uncompressed_bw) && + (ctx_data->clk_info.uncompressed_bw == + hw_mgr_clk_info->uncompressed_bw)) { + CAM_DBG(CAM_PERF, "Update not required bw=%lld", + ctx_data->clk_info.uncompressed_bw); + return false; + } + + if (busy && + (ctx_data->clk_info.uncompressed_bw > + clk_info->uncompressed_bw)) { + CAM_DBG(CAM_PERF, + "Busy, Update not req existing=%lld, new=%lld", + ctx_data->clk_info.uncompressed_bw, + clk_info->uncompressed_bw); + return false; + } + + ctx_data->clk_info.uncompressed_bw = clk_info->uncompressed_bw; + ctx_data->clk_info.compressed_bw = clk_info->compressed_bw; + hw_mgr_clk_info->uncompressed_bw = 0; + hw_mgr_clk_info->compressed_bw = 0; + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + ctx = &hw_mgr->ctx_data[i]; + if (ctx->state == CAM_ICP_CTX_STATE_ACQUIRED && + ICP_DEV_TYPE_TO_CLK_TYPE( + ctx->icp_dev_acquire_info->dev_type) == + ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type)) { + hw_mgr_clk_info->uncompressed_bw += + ctx->clk_info.uncompressed_bw; + hw_mgr_clk_info->compressed_bw += + ctx->clk_info.compressed_bw; + CAM_DBG(CAM_PERF, + "Current context=[%lld %lld] Total=[%lld %lld]", + ctx->clk_info.uncompressed_bw, + ctx->clk_info.compressed_bw, + hw_mgr_clk_info->uncompressed_bw, + hw_mgr_clk_info->compressed_bw); + } + } + + ctx_data->clk_info.bw_included = true; + + return true; +} + +static bool cam_icp_check_clk_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int idx) +{ + bool busy, rc = false; + uint32_t base_clk; + struct cam_icp_clk_bw_request *clk_info; + struct hfi_frame_process_info *frame_info; + uint64_t req_id; + struct cam_icp_clk_info *hw_mgr_clk_info; + + cam_icp_ctx_timer_reset(ctx_data); + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_BPS); + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + CAM_DBG(CAM_PERF, "Reset bps timer"); + } else { + cam_icp_device_timer_reset(hw_mgr, ICP_CLK_HW_IPE); + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + CAM_DBG(CAM_PERF, "Reset ipe timer"); + } + + if (icp_hw_mgr.icp_debug_clk) + return cam_icp_debug_clk_update(hw_mgr_clk_info); + + /* Check is there any pending frames in this context */ + frame_info = &ctx_data->hfi_frame_process; + req_id = frame_info->request_id[idx]; + busy = cam_icp_busy_prev_reqs(frame_info, req_id); + CAM_DBG(CAM_PERF, "busy = %d req_id = %lld", busy, req_id); + + clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; + if (!clk_info->frame_cycles) + return cam_icp_default_clk_update(hw_mgr_clk_info); + + /* Calculate base clk rate */ + base_clk = cam_icp_mgr_calc_base_clk( + clk_info->frame_cycles, clk_info->budget_ns); + ctx_data->clk_info.rt_flag = clk_info->rt_flag; + + if (busy) + rc = cam_icp_update_clk_busy(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + else + rc = cam_icp_update_clk_free(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, base_clk); + + CAM_DBG(CAM_PERF, "bc = %d cc = %d busy = %d overclk = %d uc = %d", + hw_mgr_clk_info->base_clk, hw_mgr_clk_info->curr_clk, + busy, hw_mgr_clk_info->over_clked, rc); + + return rc; +} + +static bool cam_icp_check_bw_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int idx) +{ + bool busy, bw_updated = false; + int i; + struct cam_icp_clk_bw_request *clk_info; + struct cam_icp_clk_bw_req_internal_v2 *clk_info_v2; + struct cam_icp_clk_info *hw_mgr_clk_info; + struct hfi_frame_process_info *frame_info; + uint64_t req_id; + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + else + hw_mgr_clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + + frame_info = &ctx_data->hfi_frame_process; + req_id = frame_info->request_id[idx]; + busy = cam_icp_busy_prev_reqs(frame_info, req_id); + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { + clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; + + CAM_DBG(CAM_PERF, + "Ctx[%pK][%d] Req[%lld] Current camno=%lld, mnoc=%lld", + ctx_data, ctx_data->ctx_id, req_id, + hw_mgr_clk_info->uncompressed_bw, + hw_mgr_clk_info->compressed_bw); + + bw_updated = cam_icp_update_bw(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info, busy); + } else if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V2) { + clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[idx]; + + CAM_DBG(CAM_PERF, "index=%d, num_paths=%d, ctx_data=%pK", + idx, clk_info_v2->num_paths, ctx_data); + + bw_updated = cam_icp_update_bw_v2(hw_mgr, ctx_data, + hw_mgr_clk_info, clk_info_v2, busy); + + for (i = 0; i < hw_mgr_clk_info->num_paths; i++) { + CAM_DBG(CAM_PERF, + "Final path_type: %s, transac_type: %s, camnoc_bw = %lld mnoc_ab_bw = %lld, mnoc_ib_bw = %lld, device: %s", + cam_cpas_axi_util_path_type_to_string( + hw_mgr_clk_info->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + hw_mgr_clk_info->axi_path[i].transac_type), + hw_mgr_clk_info->axi_path[i].camnoc_bw, + hw_mgr_clk_info->axi_path[i].mnoc_ab_bw, + hw_mgr_clk_info->axi_path[i].mnoc_ib_bw, + cam_icp_dev_type_to_name( + ctx_data->icp_dev_acquire_info->dev_type)); + } + } else { + CAM_ERR(CAM_PERF, "Invalid bw config version: %d", + ctx_data->bw_config_version); + return false; + } + + return bw_updated; +} + +static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + uint32_t id; + uint32_t curr_clk_rate; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_a5_clk_update_cmd clk_upd_cmd; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + a5_dev_intf = hw_mgr->a5_dev_intf; + + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + dev_intf = bps_dev_intf; + curr_clk_rate = hw_mgr->clk_info[ICP_CLK_HW_BPS].curr_clk; + id = CAM_ICP_BPS_CMD_UPDATE_CLK; + } else { + dev_intf = ipe0_dev_intf; + curr_clk_rate = hw_mgr->clk_info[ICP_CLK_HW_IPE].curr_clk; + id = CAM_ICP_IPE_CMD_UPDATE_CLK; + } + + CAM_DBG(CAM_PERF, "clk_rate %u for dev_type %d", curr_clk_rate, + ctx_data->icp_dev_acquire_info->dev_type); + clk_upd_cmd.curr_clk_rate = curr_clk_rate; + clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; + clk_upd_cmd.clk_level = -1; + + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_upd_cmd, sizeof(struct cam_a5_clk_update_cmd)); + + if (ctx_data->icp_dev_acquire_info->dev_type != CAM_ICP_RES_TYPE_BPS) { + if (ipe1_dev_intf) { + ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, id, + &clk_upd_cmd, + sizeof(struct cam_a5_clk_update_cmd)); + } + + /* update a5 clock */ + CAM_DBG(CAM_PERF, "Update ICP clk to level [%d]", + clk_upd_cmd.clk_level); + a5_dev_intf->hw_ops.process_cmd(a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_CLK_UPDATE, &clk_upd_cmd.clk_level, + sizeof(clk_upd_cmd.clk_level)); + } + + return 0; +} + +static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + uint32_t id; + uint64_t temp; + int i = 0; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + struct cam_hw_intf *dev_intf = NULL; + struct cam_icp_clk_info *clk_info; + struct cam_icp_cpas_vote clk_update = {{0}, {0}, 0, 0}; + int device_share_ratio = 1; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to update clk"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + dev_intf = bps_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_BPS]; + id = CAM_ICP_BPS_CMD_VOTE_CPAS; + } else { + dev_intf = ipe0_dev_intf; + clk_info = &hw_mgr->clk_info[ICP_CLK_HW_IPE]; + id = CAM_ICP_IPE_CMD_VOTE_CPAS; + } + + /* + * Since there are 2 devices, we assume the load is evenly shared + * between HWs and corresponding AXI paths. So divide total bw by half + * to vote on each device + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) + device_share_ratio = 2; + + clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC; + clk_update.ahb_vote.vote.freq = 0; + clk_update.ahb_vote_valid = false; + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_V1) { + clk_update.axi_vote.num_paths = 1; + if (ctx_data->icp_dev_acquire_info->dev_type == + CAM_ICP_RES_TYPE_BPS) { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_BPS_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_BPS_DEFAULT_AXI_TRANSAC; + } else { + clk_update.axi_vote.axi_path[0].path_data_type = + CAM_IPE_DEFAULT_AXI_PATH; + clk_update.axi_vote.axi_path[0].transac_type = + CAM_IPE_DEFAULT_AXI_TRANSAC; + } + + temp = clk_info->uncompressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].camnoc_bw = temp; + + temp = clk_info->compressed_bw; + do_div(temp, device_share_ratio); + clk_update.axi_vote.axi_path[0].mnoc_ab_bw = temp; + clk_update.axi_vote.axi_path[0].mnoc_ib_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ab_bw = temp; + clk_update.axi_vote.axi_path[0].ddr_ib_bw = temp; + } else { + clk_update.axi_vote.num_paths = clk_info->num_paths; + memcpy(&clk_update.axi_vote.axi_path[0], + &clk_info->axi_path[0], + clk_update.axi_vote.num_paths * + sizeof(struct cam_axi_per_path_bw_vote)); + + if (device_share_ratio > 1) { + for (i = 0; i < clk_update.axi_vote.num_paths; i++) { + do_div( + clk_update.axi_vote.axi_path[i].camnoc_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].mnoc_ib_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ab_bw, + device_share_ratio); + do_div( + clk_update.axi_vote.axi_path[i].ddr_ib_bw, + device_share_ratio); + } + } + } + + clk_update.axi_vote_valid = true; + rc = dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, "Failed in updating cpas vote, rc=%d", rc); + + /* + * Vote half bandwidth each on both devices. + * Total bw at mnoc - CPAS will take care of adding up. + * camnoc clk calculate is more accurate this way. + */ + if ((ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) && (ipe1_dev_intf)) { + rc = ipe1_dev_intf->hw_ops.process_cmd(ipe1_dev_intf->hw_priv, + id, &clk_update, sizeof(clk_update)); + if (rc) + CAM_ERR(CAM_PERF, + "Failed in updating cpas vote for ipe 2, rc=%d", + rc); + } + + return rc; +} + +static int cam_icp_mgr_ipe_bps_clk_update(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int idx) +{ + int rc = 0; + + if (cam_icp_check_clk_update(hw_mgr, ctx_data, idx)) + rc = cam_icp_update_clk_rate(hw_mgr, ctx_data); + + if (cam_icp_check_bw_update(hw_mgr, ctx_data, idx)) + rc |= cam_icp_update_cpas_vote(hw_mgr, ctx_data); + + return rc; +} + +static int cam_icp_mgr_ipe_bps_resume(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + uint32_t core_info_mask = 0; + int rc = 0; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) { + if (hw_mgr->bps_ctxt_cnt++) + goto end; + if (!hw_mgr->bps_clk_state) { + bps_dev_intf->hw_ops.init( + bps_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = true; + } + if (icp_hw_mgr.ipe_bps_pc_flag) { + bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_RESUME, NULL, 0); + } + core_info_mask = ICP_PWR_CLP_BPS; + } else { + if (hw_mgr->ipe_ctxt_cnt++) + goto end; + if (!hw_mgr->ipe_clk_state) + ipe0_dev_intf->hw_ops.init( + ipe0_dev_intf->hw_priv, NULL, 0); + if (icp_hw_mgr.ipe_bps_pc_flag) { + ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_RESUME, NULL, 0); + } + + if ((icp_hw_mgr.ipe1_enable) && + (ipe1_dev_intf) && + (!hw_mgr->ipe_clk_state)) { + ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv, + NULL, 0); + + if (icp_hw_mgr.ipe_bps_pc_flag) { + ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_RESUME, + NULL, 0); + } + } + hw_mgr->ipe_clk_state = true; + + if ((icp_hw_mgr.ipe1_enable) && + (ipe1_dev_intf)) + core_info_mask = (ICP_PWR_CLP_IPE0 | + ICP_PWR_CLP_IPE1); + else + core_info_mask = ICP_PWR_CLP_IPE0; + } + + CAM_DBG(CAM_PERF, "core_info %X", core_info_mask); + if (icp_hw_mgr.ipe_bps_pc_flag) + rc = hfi_enable_ipe_bps_pc(true, core_info_mask); + else + rc = hfi_enable_ipe_bps_pc(false, core_info_mask); +end: + return rc; +} + +static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, int dev_type) +{ + int rc = 0, dev; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return -EINVAL; + } + + if (!ctx_data) + dev = dev_type; + else + dev = ctx_data->icp_dev_acquire_info->dev_type; + + if (dev == CAM_ICP_RES_TYPE_BPS) { + CAM_DBG(CAM_PERF, "bps ctx cnt %d", hw_mgr->bps_ctxt_cnt); + if (ctx_data) + --hw_mgr->bps_ctxt_cnt; + + if (hw_mgr->bps_ctxt_cnt) + goto end; + + if (icp_hw_mgr.ipe_bps_pc_flag && + !atomic_read(&hw_mgr->recovery)) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + } + + if (hw_mgr->bps_clk_state) { + bps_dev_intf->hw_ops.deinit + (bps_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = false; + } + } else { + CAM_DBG(CAM_PERF, "ipe ctx cnt %d", hw_mgr->ipe_ctxt_cnt); + if (ctx_data) + --hw_mgr->ipe_ctxt_cnt; + + if (hw_mgr->ipe_ctxt_cnt) + goto end; + + if (icp_hw_mgr.ipe_bps_pc_flag && + !atomic_read(&hw_mgr->recovery)) { + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); + } + + if (hw_mgr->ipe_clk_state) + ipe0_dev_intf->hw_ops.deinit( + ipe0_dev_intf->hw_priv, NULL, 0); + + if (ipe1_dev_intf) { + if (icp_hw_mgr.ipe_bps_pc_flag && + !atomic_read(&hw_mgr->recovery)) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + NULL, 0); + } + + if (hw_mgr->ipe_clk_state) + ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv, + NULL, 0); + } + + hw_mgr->ipe_clk_state = false; + } + +end: + return rc; +} + +static int cam_icp_mgr_ipe_bps_get_gdsc_control( + struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong"); + return -EINVAL; + } + + if (icp_hw_mgr.ipe_bps_pc_flag) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + NULL, 0); + } + } + + return rc; +} + +static int cam_icp_set_dbg_default_clk(void *data, u64 val) +{ + icp_hw_mgr.icp_debug_clk = val; + return 0; +} + +static int cam_icp_get_dbg_default_clk(void *data, u64 *val) +{ + *val = icp_hw_mgr.icp_debug_clk; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_default_clk, + cam_icp_get_dbg_default_clk, + cam_icp_set_dbg_default_clk, "%16llu"); + +static int cam_icp_set_a5_dbg_lvl(void *data, u64 val) +{ + icp_hw_mgr.a5_dbg_lvl = val; + return 0; +} + +static int cam_icp_get_a5_dbg_lvl(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_dbg_lvl; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_fs, cam_icp_get_a5_dbg_lvl, + cam_icp_set_a5_dbg_lvl, "%08llu"); + +static int cam_icp_set_a5_dbg_type(void *data, u64 val) +{ + if (val <= NUM_HFI_DEBUG_MODE) + icp_hw_mgr.a5_debug_type = val; + return 0; +} + +static int cam_icp_get_a5_dbg_type(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_debug_type; + return 0; +} + + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_type_fs, cam_icp_get_a5_dbg_type, + cam_icp_set_a5_dbg_type, "%08llu"); + +static int cam_icp_set_a5_fw_dump_lvl(void *data, u64 val) +{ + if (val < NUM_HFI_DUMP_LVL) + icp_hw_mgr.a5_fw_dump_lvl = val; + return 0; +} + +static int cam_icp_get_a5_fw_dump_lvl(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_fw_dump_lvl; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_fw_dump, cam_icp_get_a5_fw_dump_lvl, + cam_icp_set_a5_fw_dump_lvl, "%08llu"); + +static int cam_icp_hw_mgr_create_debugfs_entry(void) +{ + int rc = 0; + + icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL); + if (!icp_hw_mgr.dentry) + return -ENOMEM; + + if (!debugfs_create_bool("icp_pc", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.icp_pc_flag)) { + CAM_ERR(CAM_ICP, "failed to create icp_pc entry"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_bool("ipe_bps_pc", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.ipe_bps_pc_flag)) { + CAM_ERR(CAM_ICP, "failed to create ipe_bps_pc entry"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("icp_debug_clk", + 0644, + icp_hw_mgr.dentry, NULL, + &cam_icp_debug_default_clk)) { + CAM_ERR(CAM_ICP, "failed to create icp_debug_clk entry"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_bool("a5_jtag_debug", + 0644, + icp_hw_mgr.dentry, + &icp_hw_mgr.a5_jtag_debug)) { + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_debug_type", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_type_fs)) { + CAM_ERR(CAM_ICP, "failed to create a5_debug_type"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_debug_lvl", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_fs)) { + CAM_ERR(CAM_ICP, "failed to create a5_dbg_lvl"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_fw_dump_lvl", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_fw_dump)) { + CAM_ERR(CAM_ICP, "failed to create a5_fw_dump_lvl"); + rc = -ENOMEM; + goto err; + } + + return rc; +err: + debugfs_remove_recursive(icp_hw_mgr.dentry); + icp_hw_mgr.dentry = NULL; + return rc; +} + +static int cam_icp_mgr_process_cmd(void *priv, void *data) +{ + int rc; + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_mgr *hw_mgr; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params%pK %pK", data, priv); + return -EINVAL; + } + + hw_mgr = priv; + task_data = (struct hfi_cmd_work_data *)data; + + rc = hfi_write_cmd(task_data->data); + + return rc; +} + +static int cam_icp_mgr_cleanup_ctx(struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + struct hfi_frame_process_info *hfi_frame_process; + struct cam_hw_done_event_data buf_data; + + hfi_frame_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if (!hfi_frame_process->request_id[i]) + continue; + buf_data.request_id = hfi_frame_process->request_id[i]; + ctx_data->ctxt_event_cb(ctx_data->context_priv, + false, &buf_data); + hfi_frame_process->request_id[i] = 0; + if (ctx_data->hfi_frame_process.in_resource[i] > 0) { + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_resource[i]); + cam_sync_destroy( + ctx_data->hfi_frame_process.in_resource[i]); + ctx_data->hfi_frame_process.in_resource[i] = 0; + } + hfi_frame_process->fw_process_flag[i] = false; + clear_bit(i, ctx_data->hfi_frame_process.bitmap); + } + + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) { + if (!hfi_frame_process->in_free_resource[i]) + continue; + + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_free_resource[i]); + cam_sync_destroy( + ctx_data->hfi_frame_process.in_free_resource[i]); + ctx_data->hfi_frame_process.in_free_resource[i] = 0; + } + + return 0; +} + +static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) +{ + int i; + uint32_t idx; + uint64_t request_id; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct hfi_frame_process_info *hfi_frame_process; + struct cam_hw_done_event_data buf_data; + uint32_t clk_type; + + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + request_id = ioconfig_ack->user_data2; + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid Context req %llu", request_id); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + cam_icp_ctx_timer_reset(ctx_data); + if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_ICP, "ctx %u is in %d state", + ctx_data->ctx_id, ctx_data->state); + mutex_unlock(&ctx_data->ctx_mutex); + return 0; + } + + CAM_DBG(CAM_REQ, + "ctx_id : %u, request_id :%lld dev_type: %d", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); + + clk_type = ICP_DEV_TYPE_TO_CLK_TYPE( + ctx_data->icp_dev_acquire_info->dev_type); + cam_icp_device_timer_reset(&icp_hw_mgr, clk_type); + + hfi_frame_process = &ctx_data->hfi_frame_process; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) + if (hfi_frame_process->request_id[i] == request_id) + break; + + if (i >= CAM_FRAME_CMD_MAX) { + CAM_ERR(CAM_ICP, "pkt not found in ctx data for req_id =%lld", + request_id); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + idx = i; + + if (flag == ICP_FRAME_PROCESS_FAILURE) { + if (ioconfig_ack->err_type == CAMERAICP_EABORTED) + CAM_WARN(CAM_ICP, + "ctx_id %d req %llu dev %d has been aborted[flushed]", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); + else + CAM_ERR(CAM_ICP, + "Done with error: %u on ctx_id %d dev %d for req %llu", + ioconfig_ack->err_type, + ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type, + request_id); + } + + buf_data.request_id = hfi_frame_process->request_id[idx]; + ctx_data->ctxt_event_cb(ctx_data->context_priv, flag, &buf_data); + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_resource[idx]); + cam_sync_destroy(ctx_data->hfi_frame_process.in_resource[idx]); + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + hfi_frame_process->fw_process_flag[idx] = false; + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static int cam_icp_mgr_process_msg_frame_process(uint32_t *msg_ptr) +{ + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct hfi_msg_frame_process_done *frame_done; + + if (!msg_ptr) { + CAM_ERR(CAM_ICP, "msg ptr is NULL"); + return -EINVAL; + } + + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + if (ioconfig_ack->err_type != CAMERAICP_SUCCESS) { + cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_FAILURE); + return -EIO; + } + + frame_done = + (struct hfi_msg_frame_process_done *)ioconfig_ack->msg_data; + if (!frame_done) { + cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_FAILURE); + return -EINVAL; + } + + if (frame_done->result) + return cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_FAILURE); + else + return cam_icp_mgr_handle_frame_process(msg_ptr, + ICP_FRAME_PROCESS_SUCCESS); +} + +static int cam_icp_mgr_process_msg_config_io(uint32_t *msg_ptr) +{ + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct hfi_msg_ipe_config *ipe_config_ack = NULL; + struct hfi_msg_bps_common *bps_config_ack = NULL; + + if (!msg_ptr) { + CAM_ERR(CAM_ICP, "msg ptr is NULL"); + return -EINVAL; + } + + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + + if (ioconfig_ack->opcode == HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO) { + ipe_config_ack = + (struct hfi_msg_ipe_config *)(ioconfig_ack->msg_data); + if (ipe_config_ack->rc) { + CAM_ERR(CAM_ICP, "rc = %d err = %u", + ipe_config_ack->rc, ioconfig_ack->err_type); + return -EIO; + } + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "wrong ctx data from IPE response"); + return -EINVAL; + } + ctx_data->scratch_mem_size = ipe_config_ack->scratch_mem_size; + } else { + bps_config_ack = + (struct hfi_msg_bps_common *)(ioconfig_ack->msg_data); + if (bps_config_ack->rc) { + CAM_ERR(CAM_ICP, "rc : %u, opcode :%u", + bps_config_ack->rc, ioconfig_ack->opcode); + return -EIO; + } + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "wrong ctx data from BPS response"); + return -EINVAL; + } + } + complete(&ctx_data->wait_complete); + + return 0; +} + +static int cam_icp_mgr_process_msg_create_handle(uint32_t *msg_ptr) +{ + struct hfi_msg_create_handle_ack *create_handle_ack = NULL; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + int rc = 0; + + create_handle_ack = (struct hfi_msg_create_handle_ack *)msg_ptr; + if (!create_handle_ack) { + CAM_ERR(CAM_ICP, "Invalid create_handle_ack"); + return -EINVAL; + } + + ctx_data = + (struct cam_icp_hw_ctx_data *)(uintptr_t) + create_handle_ack->user_data1; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid ctx_data"); + return -EINVAL; + } + + if (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE) { + ctx_data->fw_handle = create_handle_ack->fw_handle; + CAM_DBG(CAM_ICP, "fw_handle = %x", ctx_data->fw_handle); + } else { + CAM_WARN(CAM_ICP, + "This ctx is no longer in use current state: %d", + ctx_data->state); + ctx_data->fw_handle = 0; + rc = -EPERM; + } + complete(&ctx_data->wait_complete); + return rc; +} + +static int cam_icp_mgr_process_msg_ping_ack(uint32_t *msg_ptr) +{ + struct hfi_msg_ping_ack *ping_ack = NULL; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + + ping_ack = (struct hfi_msg_ping_ack *)msg_ptr; + if (!ping_ack) { + CAM_ERR(CAM_ICP, "Empty ping ack message"); + return -EINVAL; + } + + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ping_ack->user_data); + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid ctx_data"); + return -EINVAL; + } + + if (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE) + complete(&ctx_data->wait_complete); + + return 0; +} + +static int cam_icp_mgr_process_indirect_ack_msg(uint32_t *msg_ptr) +{ + int rc; + + if (!msg_ptr) { + CAM_ERR(CAM_ICP, "msg ptr is NULL"); + return -EINVAL; + } + + switch (msg_ptr[ICP_PACKET_OPCODE]) { + case HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO: + case HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO: + CAM_DBG(CAM_ICP, "received IPE/BPS_CONFIG_IO:"); + rc = cam_icp_mgr_process_msg_config_io(msg_ptr); + if (rc) + return rc; + break; + + case HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS: + case HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS: + rc = cam_icp_mgr_process_msg_frame_process(msg_ptr); + if (rc) + return rc; + break; + default: + CAM_ERR(CAM_ICP, "Invalid opcode : %u", + msg_ptr[ICP_PACKET_OPCODE]); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) +{ + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct hfi_msg_ipebps_async_ack *ioconfig_ack = NULL; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + int rc = 0; + + a5_dev_intf = icp_hw_mgr.a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + switch (msg_ptr[ICP_PACKET_OPCODE]) { + case HFI_IPEBPS_CMD_OPCODE_IPE_ABORT: + case HFI_IPEBPS_CMD_OPCODE_BPS_ABORT: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) + complete(&ctx_data->wait_complete); + CAM_DBG(CAM_ICP, "received IPE/BPS/ ABORT: ctx_state =%d", + ctx_data->state); + break; + case HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY: + case HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = (struct cam_icp_hw_ctx_data *) + U64_TO_PTR(ioconfig_ack->user_data1); + if ((ctx_data->state == CAM_ICP_CTX_STATE_RELEASE) || + (ctx_data->state == CAM_ICP_CTX_STATE_IN_USE)) { + complete(&ctx_data->wait_complete); + } + CAM_DBG(CAM_ICP, "received IPE/BPS/ DESTROY: ctx_state =%d", + ctx_data->state); + break; + case HFI_IPEBPS_CMD_OPCODE_MEM_MAP: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = + (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; + if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) + complete(&ctx_data->wait_complete); + CAM_DBG(CAM_ICP, + "received IPE/BPS MAP ACK:ctx_state =%d err_status =%u", + ctx_data->state, ioconfig_ack->err_type); + break; + case HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP: + ioconfig_ack = (struct hfi_msg_ipebps_async_ack *)msg_ptr; + ctx_data = + (struct cam_icp_hw_ctx_data *)ioconfig_ack->user_data1; + if (ctx_data->state != CAM_ICP_CTX_STATE_FREE) + complete(&ctx_data->wait_complete); + CAM_DBG(CAM_ICP, + "received IPE/BPS UNMAP ACK:ctx_state =%d err_status =%u", + ctx_data->state, ioconfig_ack->err_type); + break; + default: + CAM_ERR(CAM_ICP, "Invalid opcode : %u", + msg_ptr[ICP_PACKET_OPCODE]); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_icp_ipebps_reset(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf; + struct cam_hw_intf *ipe1_dev_intf; + struct cam_hw_intf *bps_dev_intf; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if (hw_mgr->bps_ctxt_cnt) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "bps reset failed"); + } + + if (hw_mgr->ipe_ctxt_cnt) { + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe0 reset failed"); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe1 reset failed"); + } + } + + return 0; +} + +static int cam_icp_mgr_trigger_recovery(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct sfr_buf *sfr_buffer = NULL; + + CAM_DBG(CAM_ICP, "Enter"); + + if (atomic_read(&hw_mgr->recovery)) { + CAM_ERR(CAM_ICP, "Recovery is set"); + return rc; + } + + sfr_buffer = (struct sfr_buf *)icp_hw_mgr.hfi_mem.sfr_buf.kva; + CAM_WARN(CAM_ICP, "SFR:%s", sfr_buffer->msg); + + cam_icp_mgr_ipe_bps_get_gdsc_control(hw_mgr); + cam_icp_ipebps_reset(hw_mgr); + + atomic_set(&hw_mgr->recovery, 1); + CAM_DBG(CAM_ICP, "Done"); + return rc; +} +static int cam_icp_mgr_process_fatal_error( + struct cam_icp_hw_mgr *hw_mgr, uint32_t *msg_ptr) +{ + struct hfi_msg_event_notify *event_notify; + int rc = 0; + + CAM_DBG(CAM_ICP, "Enter"); + + event_notify = (struct hfi_msg_event_notify *)msg_ptr; + if (!event_notify) { + CAM_ERR(CAM_ICP, "Empty event message"); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "evt_id: %u evt_data1: %u evt_data2: %u", + event_notify->event_id, + event_notify->event_data1, + event_notify->event_data2); + + if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { + CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + } + + return rc; +} + +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl) +{ + uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; + struct hfi_msg_debug *dbg_msg; + uint32_t read_len, size_processed = 0; + uint64_t timestamp = 0; + char *dbg_buf; + int rc = 0; + + rc = hfi_read_message(icp_hw_mgr.dbg_buf, Q_DBG, &read_len); + if (rc) + return; + + msg_ptr = (uint32_t *)icp_hw_mgr.dbg_buf; + while (true) { + pkt_ptr = msg_ptr; + if (pkt_ptr[ICP_PACKET_TYPE] == HFI_MSG_SYS_DEBUG) { + dbg_msg = (struct hfi_msg_debug *)pkt_ptr; + dbg_buf = (char *)&dbg_msg->msg_data; + timestamp = ((((uint64_t)(dbg_msg->timestamp_hi) << 32) + | dbg_msg->timestamp_lo) >> 16); + trace_cam_icp_fw_dbg(dbg_buf, timestamp/2); + if (!debug_lvl) + CAM_INFO(CAM_ICP, "FW_DBG:%s", dbg_buf); + } + size_processed += (pkt_ptr[ICP_PACKET_SIZE] >> + BYTE_WORD_SHIFT); + if (size_processed >= read_len) + return; + msg_ptr += (pkt_ptr[ICP_PACKET_SIZE] >> + BYTE_WORD_SHIFT); + pkt_ptr = NULL; + dbg_msg = NULL; + dbg_buf = NULL; + } +} + +static int cam_icp_process_msg_pkt_type( + struct cam_icp_hw_mgr *hw_mgr, + uint32_t *msg_ptr, + uint32_t *msg_processed_len) +{ + int rc = 0; + int size_processed = 0; + + switch (msg_ptr[ICP_PACKET_TYPE]) { + case HFI_MSG_SYS_INIT_DONE: + CAM_DBG(CAM_ICP, "received SYS_INIT_DONE"); + complete(&hw_mgr->a5_complete); + size_processed = ( + (struct hfi_msg_init_done *)msg_ptr)->size; + break; + + case HFI_MSG_SYS_PC_PREP_DONE: + CAM_DBG(CAM_ICP, "HFI_MSG_SYS_PC_PREP_DONE is received\n"); + complete(&hw_mgr->a5_complete); + size_processed = sizeof(struct hfi_msg_pc_prep_done); + break; + + case HFI_MSG_SYS_PING_ACK: + CAM_DBG(CAM_ICP, "received SYS_PING_ACK"); + rc = cam_icp_mgr_process_msg_ping_ack(msg_ptr); + size_processed = sizeof(struct hfi_msg_ping_ack); + break; + + case HFI_MSG_IPEBPS_CREATE_HANDLE_ACK: + CAM_DBG(CAM_ICP, "received IPEBPS_CREATE_HANDLE_ACK"); + rc = cam_icp_mgr_process_msg_create_handle(msg_ptr); + size_processed = sizeof(struct hfi_msg_create_handle_ack); + break; + + case HFI_MSG_IPEBPS_ASYNC_COMMAND_INDIRECT_ACK: + CAM_DBG(CAM_ICP, "received ASYNC_INDIRECT_ACK"); + rc = cam_icp_mgr_process_indirect_ack_msg(msg_ptr); + size_processed = ( + (struct hfi_msg_ipebps_async_ack *)msg_ptr)->size; + break; + + case HFI_MSG_IPEBPS_ASYNC_COMMAND_DIRECT_ACK: + CAM_DBG(CAM_ICP, "received ASYNC_DIRECT_ACK"); + rc = cam_icp_mgr_process_direct_ack_msg(msg_ptr); + size_processed = ( + (struct hfi_msg_ipebps_async_ack *)msg_ptr)->size; + break; + + case HFI_MSG_EVENT_NOTIFY: + CAM_DBG(CAM_ICP, "received EVENT_NOTIFY"); + size_processed = ( + (struct hfi_msg_event_notify *)msg_ptr)->size; + rc = cam_icp_mgr_process_fatal_error(hw_mgr, msg_ptr); + if (rc) + CAM_ERR(CAM_ICP, "failed in processing evt notify"); + + break; + + default: + CAM_ERR(CAM_ICP, "invalid msg : %u", + msg_ptr[ICP_PACKET_TYPE]); + rc = -EINVAL; + break; + } + + *msg_processed_len = size_processed; + return rc; +} + +static int32_t cam_icp_mgr_process_msg(void *priv, void *data) +{ + uint32_t read_len, msg_processed_len; + uint32_t *msg_ptr = NULL; + struct hfi_msg_work_data *task_data; + struct cam_icp_hw_mgr *hw_mgr; + int rc = 0; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid data"); + return -EINVAL; + } + + task_data = data; + hw_mgr = priv; + + rc = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG, &read_len); + if (rc) { + CAM_DBG(CAM_ICP, "Unable to read msg q rc %d", rc); + } else { + read_len = read_len << BYTE_WORD_SHIFT; + msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf; + while (true) { + cam_icp_process_msg_pkt_type(hw_mgr, msg_ptr, + &msg_processed_len); + + if (!msg_processed_len) { + CAM_ERR(CAM_ICP, "Failed to read"); + rc = -EINVAL; + break; + } + + read_len -= msg_processed_len; + if (read_len > 0) { + msg_ptr += (msg_processed_len >> + BYTE_WORD_SHIFT); + msg_processed_len = 0; + } else { + break; + } + } + } + + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + + if ((task_data->irq_status & A5_WDT_0) || + (task_data->irq_status & A5_WDT_1)) { + CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5"); + + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + } + + return rc; +} + +int32_t cam_icp_hw_mgr_cb(uint32_t irq_status, void *data) +{ + int32_t rc = 0; + unsigned long flags; + struct cam_icp_hw_mgr *hw_mgr = data; + struct crm_workq_task *task; + struct hfi_msg_work_data *task_data; + + if (!data) { + CAM_ERR(CAM_ICP, "irq cb data is NULL"); + return rc; + } + + spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task(icp_hw_mgr.msg_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + return -ENOMEM; + } + + task_data = (struct hfi_msg_work_data *)task->payload; + task_data->data = hw_mgr; + task_data->irq_status = irq_status; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_mgr_process_msg; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + + return rc; +} + +static void cam_icp_free_hfi_mem(void) +{ + int rc; + + cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl); + rc = cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap); + if (rc) + CAM_ERR(CAM_ICP, "failed to unreserve sec heap"); + + cam_smmu_dealloc_qdss(icp_hw_mgr.iommu_hdl); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); +} + +static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + struct cam_smmu_region_info secheap_info; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + + rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl, + CAM_SMMU_REGION_SECHEAP, + &secheap_info); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get secheap memory info"); + return rc; + } + + alloc.size = secheap_info.iova_len; + alloc.align = 0; + alloc.flags = 0; + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_reserve_memory_region(&alloc, + CAM_SMMU_REGION_SECHEAP, + &out); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to reserve secheap memory"); + return rc; + } + + *secheap = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + +static int cam_icp_alloc_sfr_mem(struct cam_mem_mgr_memory_desc *sfr) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + alloc.size = SZ_8K; + alloc.align = 0; + alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE | + CAM_MEM_FLAG_HW_SHARED_ACCESS; + + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_request_mem(&alloc, &out); + if (rc) + return rc; + + *sfr = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + +static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + alloc.size = SZ_1M; + alloc.align = 0; + alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE | + CAM_MEM_FLAG_HW_SHARED_ACCESS; + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_request_mem(&alloc, &out); + if (rc) + return rc; + + *qtbl = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + +static int cam_icp_allocate_fw_mem(void) +{ + int rc; + uintptr_t kvaddr; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl, + &iova, &kvaddr, &len); + if (rc) + return -ENOMEM; + + icp_hw_mgr.hfi_mem.fw_buf.len = len; + icp_hw_mgr.hfi_mem.fw_buf.kva = kvaddr; + icp_hw_mgr.hfi_mem.fw_buf.iova = iova; + icp_hw_mgr.hfi_mem.fw_buf.smmu_hdl = icp_hw_mgr.iommu_hdl; + + CAM_DBG(CAM_ICP, "kva: %zX, iova: %llx, len: %zu", + kvaddr, iova, len); + + return rc; +} + +static int cam_icp_allocate_qdss_mem(void) +{ + int rc; + size_t len; + dma_addr_t iova; + + rc = cam_smmu_alloc_qdss(icp_hw_mgr.iommu_hdl, + &iova, &len); + if (rc) + return rc; + + icp_hw_mgr.hfi_mem.qdss_buf.len = len; + icp_hw_mgr.hfi_mem.qdss_buf.iova = iova; + icp_hw_mgr.hfi_mem.qdss_buf.smmu_hdl = icp_hw_mgr.iommu_hdl; + + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu", iova, len); + + return rc; +} + +static int cam_icp_get_io_mem_info(void) +{ + int rc; + size_t len, discard_iova_len; + dma_addr_t iova, discard_iova_start; + + rc = cam_smmu_get_io_region_info(icp_hw_mgr.iommu_hdl, + &iova, &len, &discard_iova_start, &discard_iova_len); + if (rc) + return rc; + + icp_hw_mgr.hfi_mem.io_mem.iova_len = len; + icp_hw_mgr.hfi_mem.io_mem.iova_start = iova; + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start = discard_iova_start; + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len = discard_iova_len; + + CAM_DBG(CAM_ICP, "iova: %llx, len: %zu discard iova %llx len %llx", + iova, len, discard_iova_start, discard_iova_len); + + return rc; +} + +static int cam_icp_allocate_hfi_mem(void) +{ + int rc; + + rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl, + CAM_SMMU_REGION_SHARED, + &icp_hw_mgr.hfi_mem.shmem); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get shared memory info"); + return rc; + } + + rc = cam_icp_allocate_fw_mem(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate FW memory"); + return rc; + } + + rc = cam_icp_allocate_qdss_mem(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate qdss memory"); + goto fw_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.qtbl); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate qtbl memory"); + goto qtbl_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.cmd_q); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate cmd q memory"); + goto cmd_q_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.msg_q); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate msg q memory"); + goto msg_q_alloc_failed; + } + + rc = cam_icp_alloc_shared_mem(&icp_hw_mgr.hfi_mem.dbg_q); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate dbg q memory"); + goto dbg_q_alloc_failed; + } + + rc = cam_icp_alloc_sfr_mem(&icp_hw_mgr.hfi_mem.sfr_buf); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate sfr buffer"); + goto sfr_buf_alloc_failed; + } + + rc = cam_icp_alloc_secheap_mem(&icp_hw_mgr.hfi_mem.sec_heap); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate sec heap memory"); + goto sec_heap_alloc_failed; + } + + rc = cam_icp_get_io_mem_info(); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to get I/O region info"); + goto get_io_mem_failed; + } + + return rc; +get_io_mem_failed: + cam_mem_mgr_free_memory_region(&icp_hw_mgr.hfi_mem.sec_heap); +sec_heap_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); +sfr_buf_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); +dbg_q_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); +msg_q_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q); +cmd_q_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.qtbl); +qtbl_alloc_failed: + cam_smmu_dealloc_qdss(icp_hw_mgr.iommu_hdl); +fw_alloc_failed: + cam_smmu_dealloc_firmware(icp_hw_mgr.iommu_hdl); + return rc; +} + +static int cam_icp_mgr_get_free_ctx(struct cam_icp_hw_mgr *hw_mgr) +{ + int i = 0; + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex); + if (hw_mgr->ctx_data[i].state == CAM_ICP_CTX_STATE_FREE) { + hw_mgr->ctx_data[i].state = CAM_ICP_CTX_STATE_IN_USE; + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + break; + } + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + } + + return i; +} + +static void cam_icp_mgr_put_ctx(struct cam_icp_hw_ctx_data *ctx_data) +{ + ctx_data->state = CAM_ICP_CTX_STATE_FREE; +} + +static int cam_icp_mgr_send_pc_prep(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + unsigned long rem_jiffies; + int timeout = 5000; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n"); + return -EINVAL; + } + + reinit_completion(&hw_mgr->a5_complete); + CAM_DBG(CAM_ICP, "Sending HFI init command"); + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, CAM_ICP_A5_CMD_PC_PREP, NULL, 0); + if (rc) + return rc; + + CAM_DBG(CAM_ICP, "Wait for PC_PREP_DONE Message\n"); + rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "PC_PREP response timed out %d\n", rc); + } + CAM_DBG(CAM_ICP, "Done Waiting for PC_PREP Message\n"); + + return rc; +} + +static int cam_ipe_bps_deint(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + if ((!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return 0; + } + + if (ipe1_dev_intf && hw_mgr->ipe_clk_state) { + ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv, + NULL, 0); + } + + if (hw_mgr->ipe_clk_state) + ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0); + if (hw_mgr->bps_clk_state) + bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0); + + + hw_mgr->bps_clk_state = false; + hw_mgr->ipe_clk_state = false; + + return 0; +} + +static int cam_icp_mgr_hw_close_u(void *hw_priv, void *hw_close_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + int rc = 0; + + CAM_DBG(CAM_ICP, "UMD calls close"); + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_icp_mgr_hw_close(hw_mgr, NULL); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_icp_mgr_hw_close_k(void *hw_priv, void *hw_close_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + + CAM_DBG(CAM_ICP, "KMD calls close"); + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + return cam_icp_mgr_hw_close(hw_mgr, NULL); + +} + +static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + + CAM_DBG(CAM_PERF, "ENTER"); + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + if (!hw_mgr->icp_pc_flag || atomic_read(&hw_mgr->recovery)) { + cam_hfi_disable_cpu( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + rc = cam_icp_mgr_hw_close_k(hw_mgr, NULL); + } else { + CAM_DBG(CAM_PERF, "Sending PC prep ICP PC enabled"); + rc = cam_icp_mgr_send_pc_prep(hw_mgr); + cam_hfi_disable_cpu( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + } + a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); + CAM_DBG(CAM_PERF, "EXIT"); + + return rc; +} + +static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct hfi_mem_info hfi_mem; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid\n"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva; + hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova; + hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len; + CAM_DBG(CAM_ICP, "qtbl kva = %llX IOVA = %X length = %lld\n", + hfi_mem.qtbl.kva, hfi_mem.qtbl.iova, hfi_mem.qtbl.len); + + hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva; + hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova; + hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len; + CAM_DBG(CAM_ICP, "cmd_q kva = %llX IOVA = %X length = %lld\n", + hfi_mem.cmd_q.kva, hfi_mem.cmd_q.iova, hfi_mem.cmd_q.len); + + hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva; + hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova; + hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len; + CAM_DBG(CAM_ICP, "msg_q kva = %llX IOVA = %X length = %lld\n", + hfi_mem.msg_q.kva, hfi_mem.msg_q.iova, hfi_mem.msg_q.len); + + hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva; + hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; + hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; + CAM_DBG(CAM_ICP, "dbg_q kva = %llX IOVA = %X length = %lld\n", + hfi_mem.dbg_q.kva, hfi_mem.dbg_q.iova, hfi_mem.dbg_q.len); + + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + CAM_DBG(CAM_ICP, "sfr kva = %llX IOVA = %X length = %lld\n", + hfi_mem.sfr_buf.kva, hfi_mem.sfr_buf.iova, + hfi_mem.sfr_buf.len); + + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; + hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; + hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; + + hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start; + hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len; + + hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; + hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + + if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start && + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start - + icp_hw_mgr.hfi_mem.io_mem.iova_start; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start + + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len; + hfi_mem.io_mem2.len = + icp_hw_mgr.hfi_mem.io_mem.iova_start + + icp_hw_mgr.hfi_mem.io_mem.iova_len - + hfi_mem.io_mem2.iova; + } else { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = 0x0; + hfi_mem.io_mem2.len = 0x0; + } + + CAM_DBG(CAM_ICP, + "IO region1 IOVA = %X length = %lld, IO region2 IOVA = %X length = %lld", + hfi_mem.io_mem.iova, + hfi_mem.io_mem.len, + hfi_mem.io_mem2.iova, + hfi_mem.io_mem2.len); + + return cam_hfi_resume(&hfi_mem, + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, + hw_mgr->a5_jtag_debug); +} + +static int cam_icp_retry_wait_for_abort( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int retry_cnt = 1; + unsigned long rem_jiffies; + int timeout = 1000; + + CAM_WARN(CAM_ICP, "FW timeout in abort ctx: %u retry_left: %d", + ctx_data->ctx_id, retry_cnt); + while (retry_cnt > 0) { + rem_jiffies = wait_for_completion_timeout( + &ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + retry_cnt--; + if (retry_cnt > 0) { + CAM_WARN(CAM_ICP, + "FW timeout in abort ctx: %u retry_left: %u", + ctx_data->ctx_id, retry_cnt); + continue; + } + } + + if (retry_cnt > 0) + return 0; + } + + return -ETIMEDOUT; +} + +static int cam_icp_mgr_abort_handle_wq( + void *priv, void *data) +{ + int rc; + size_t packet_size; + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_ctx_data *ctx_data; + struct hfi_cmd_ipebps_async *abort_cmd; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params %pK %pK", data, priv); + return -EINVAL; + } + + task_data = (struct hfi_cmd_work_data *)data; + ctx_data = + (struct cam_icp_hw_ctx_data *)task_data->data; + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + abort_cmd = kzalloc(packet_size, GFP_KERNEL); + CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size); + if (!abort_cmd) { + rc = -ENOMEM; + return rc; + } + + abort_cmd->size = packet_size; + abort_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT; + else + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_ABORT; + + abort_cmd->num_fw_handles = 1; + abort_cmd->fw_handles[0] = ctx_data->fw_handle; + abort_cmd->user_data1 = PTR_TO_U64(ctx_data); + abort_cmd->user_data2 = (uint64_t)0x0; + + rc = hfi_write_cmd(abort_cmd); + if (rc) { + kfree(abort_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK ctx_id %d", + ctx_data->fw_handle, ctx_data, ctx_data->ctx_id); + + kfree(abort_cmd); + return rc; +} + +static int cam_icp_mgr_abort_handle( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + unsigned long rem_jiffies = 0; + size_t packet_size; + int timeout = 1000; + struct hfi_cmd_ipebps_async *abort_cmd; + + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + abort_cmd = kzalloc(packet_size, GFP_KERNEL); + CAM_DBG(CAM_ICP, "abort pkt size = %d", (int) packet_size); + if (!abort_cmd) { + rc = -ENOMEM; + return rc; + } + + abort_cmd->size = packet_size; + abort_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_ABORT; + else + abort_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_ABORT; + + reinit_completion(&ctx_data->wait_complete); + abort_cmd->num_fw_handles = 1; + abort_cmd->fw_handles[0] = ctx_data->fw_handle; + abort_cmd->user_data1 = PTR_TO_U64(ctx_data); + abort_cmd->user_data2 = (uint64_t)0x0; + + rc = hfi_write_cmd(abort_cmd); + if (rc) { + kfree(abort_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK", + ctx_data->fw_handle, ctx_data); + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = cam_icp_retry_wait_for_abort(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, + "FW timeout/err in abort handle command ctx: %u", + ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + } + + kfree(abort_cmd); + return rc; +} + +static int cam_icp_mgr_destroy_handle( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + int timeout = 1000; + unsigned long rem_jiffies; + size_t packet_size; + struct hfi_cmd_ipebps_async *destroy_cmd; + + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + sizeof(struct hfi_cmd_abort_destroy) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + destroy_cmd = kzalloc(packet_size, GFP_KERNEL); + if (!destroy_cmd) { + rc = -ENOMEM; + return rc; + } + + destroy_cmd->size = packet_size; + destroy_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + destroy_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_DESTROY; + else + destroy_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_DESTROY; + + reinit_completion(&ctx_data->wait_complete); + destroy_cmd->num_fw_handles = 1; + destroy_cmd->fw_handles[0] = ctx_data->fw_handle; + destroy_cmd->user_data1 = PTR_TO_U64(ctx_data); + destroy_cmd->user_data2 = (uint64_t)0x0; + memcpy(destroy_cmd->payload.direct, &ctx_data->temp_payload, + sizeof(uint64_t)); + + rc = hfi_write_cmd(destroy_cmd); + if (rc) { + kfree(destroy_cmd); + return rc; + } + CAM_DBG(CAM_ICP, "fw_handle = %x ctx_data = %pK", + ctx_data->fw_handle, ctx_data); + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timeout: %d for %u", + rc, ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + kfree(destroy_cmd); + return rc; +} + +static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) +{ + int i = 0; + + if (ctx_id >= CAM_ICP_CTX_MAX) { + CAM_ERR(CAM_ICP, "ctx_id is wrong: %d", ctx_id); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + cam_icp_remove_ctx_bw(hw_mgr, &hw_mgr->ctx_data[ctx_id]); + if (hw_mgr->ctx_data[ctx_id].state != + CAM_ICP_CTX_STATE_ACQUIRED) { + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + CAM_DBG(CAM_ICP, + "ctx with id: %d not in right state to release: %d", + ctx_id, hw_mgr->ctx_data[ctx_id].state); + return 0; + } + cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, + &hw_mgr->ctx_data[ctx_id], 0); + hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE; + CAM_DBG(CAM_ICP, "E: ctx_id = %d recovery = %d", + ctx_id, atomic_read(&hw_mgr->recovery)); + cam_icp_mgr_abort_handle(&hw_mgr->ctx_data[ctx_id]); + cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]); + cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]); + + hw_mgr->ctx_data[ctx_id].fw_handle = 0; + hw_mgr->ctx_data[ctx_id].scratch_mem_size = 0; + hw_mgr->ctx_data[ctx_id].last_flush_req = 0; + for (i = 0; i < CAM_FRAME_CMD_MAX; i++) + clear_bit(i, hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); + kfree(hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap); + hw_mgr->ctx_data[ctx_id].hfi_frame_process.bitmap = NULL; + cam_icp_hw_mgr_clk_info_update(hw_mgr, &hw_mgr->ctx_data[ctx_id]); + hw_mgr->ctx_data[ctx_id].clk_info.curr_fc = 0; + hw_mgr->ctx_data[ctx_id].clk_info.base_clk = 0; + hw_mgr->ctxt_cnt--; + kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info); + hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL; + hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_FREE; + cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[ctx_id]); + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + + CAM_DBG(CAM_ICP, "X: ctx_id = %d", ctx_id); + return 0; +} + +static void cam_icp_mgr_device_deinit(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + a5_dev_intf = hw_mgr->a5_dev_intf; + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong, failed to close"); + return; + } + + if (ipe1_dev_intf) + ipe1_dev_intf->hw_ops.deinit(ipe1_dev_intf->hw_priv, NULL, 0); + ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0); + bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0); + a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = false; + hw_mgr->ipe_clk_state = false; +} + +static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct cam_icp_a5_set_irq_cb irq_cb; + struct cam_icp_a5_set_fw_buf_info fw_buf_info; + int rc = 0; + + CAM_DBG(CAM_ICP, "E"); + if (hw_mgr->fw_download == false) { + CAM_DBG(CAM_ICP, "hw mgr is already closed"); + return 0; + } + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_DBG(CAM_ICP, "a5_dev_intf is NULL"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + fw_buf_info.kva = 0; + fw_buf_info.iova = 0; + fw_buf_info.len = 0; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_SET_FW_BUF, + &fw_buf_info, + sizeof(fw_buf_info)); + if (rc) + CAM_ERR(CAM_ICP, "nullify the fw buf failed"); + cam_hfi_deinit( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + irq_cb.icp_hw_mgr_cb = NULL; + irq_cb.data = NULL; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_ICP, "deregister irq call back failed"); + + cam_icp_free_hfi_mem(); + hw_mgr->fw_download = false; + + CAM_DBG(CAM_ICP, "Exit"); + return rc; +} + +static int cam_icp_mgr_device_init(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_intf *ipe0_dev_intf = NULL; + struct cam_hw_intf *ipe1_dev_intf = NULL; + struct cam_hw_intf *bps_dev_intf = NULL; + + a5_dev_intf = hw_mgr->a5_dev_intf; + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + if ((!a5_dev_intf) || (!ipe0_dev_intf) || (!bps_dev_intf)) { + CAM_ERR(CAM_ICP, "dev intfs are wrong"); + return -EINVAL; + } + + rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0); + if (rc) + goto a5_dev_init_failed; + + rc = bps_dev_intf->hw_ops.init(bps_dev_intf->hw_priv, NULL, 0); + if (rc) + goto bps_dev_init_failed; + + rc = ipe0_dev_intf->hw_ops.init(ipe0_dev_intf->hw_priv, NULL, 0); + if (rc) + goto ipe0_dev_init_failed; + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.init(ipe1_dev_intf->hw_priv, + NULL, 0); + if (rc) + goto ipe1_dev_init_failed; + } + + hw_mgr->bps_clk_state = true; + hw_mgr->ipe_clk_state = true; + + return rc; +ipe1_dev_init_failed: + ipe0_dev_intf->hw_ops.deinit(ipe0_dev_intf->hw_priv, NULL, 0); + hw_mgr->ipe_clk_state = false; +ipe0_dev_init_failed: + bps_dev_intf->hw_ops.deinit(bps_dev_intf->hw_priv, NULL, 0); + hw_mgr->bps_clk_state = false; +bps_dev_init_failed: + a5_dev_intf->hw_ops.deinit(a5_dev_intf->hw_priv, NULL, 0); +a5_dev_init_failed: + return rc; +} + +static int cam_icp_mgr_fw_download(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct cam_icp_a5_set_irq_cb irq_cb; + struct cam_icp_a5_set_fw_buf_info fw_buf_info; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + irq_cb.icp_hw_mgr_cb = cam_icp_hw_mgr_cb; + irq_cb.data = hw_mgr; + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + goto set_irq_failed; + + fw_buf_info.kva = icp_hw_mgr.hfi_mem.fw_buf.kva; + fw_buf_info.iova = icp_hw_mgr.hfi_mem.fw_buf.iova; + fw_buf_info.len = icp_hw_mgr.hfi_mem.fw_buf.len; + + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_SET_FW_BUF, + &fw_buf_info, sizeof(fw_buf_info)); + if (rc) + goto set_irq_failed; + + cam_hfi_enable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); + + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_CMD_FW_DOWNLOAD, + NULL, 0); + if (rc) + goto fw_download_failed; + + return rc; +fw_download_failed: + cam_hfi_disable_cpu(a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); +set_irq_failed: + return rc; +} + +static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct hfi_mem_info hfi_mem; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + + hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva; + hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova; + hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len; + + hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva; + hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova; + hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len; + + hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva; + hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova; + hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len; + + hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva; + hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; + hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; + + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; + hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; + hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; + + hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start; + hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len; + + hfi_mem.qdss.iova = icp_hw_mgr.hfi_mem.qdss_buf.iova; + hfi_mem.qdss.len = icp_hw_mgr.hfi_mem.qdss_buf.len; + + if (icp_hw_mgr.hfi_mem.io_mem.discard_iova_start && + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len) { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start - + icp_hw_mgr.hfi_mem.io_mem.iova_start; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = + icp_hw_mgr.hfi_mem.io_mem.discard_iova_start + + icp_hw_mgr.hfi_mem.io_mem.discard_iova_len; + hfi_mem.io_mem2.len = + icp_hw_mgr.hfi_mem.io_mem.iova_start + + icp_hw_mgr.hfi_mem.io_mem.iova_len - + hfi_mem.io_mem2.iova; + } else { + /* IO Region 1 */ + hfi_mem.io_mem.iova = icp_hw_mgr.hfi_mem.io_mem.iova_start; + hfi_mem.io_mem.len = icp_hw_mgr.hfi_mem.io_mem.iova_len; + + /* IO Region 2 */ + hfi_mem.io_mem2.iova = 0x0; + hfi_mem.io_mem2.len = 0x0; + } + + return cam_hfi_init(0, &hfi_mem, + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base, + hw_mgr->a5_jtag_debug); +} + +static int cam_icp_mgr_send_fw_init(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc; + struct cam_hw_intf *a5_dev_intf = NULL; + unsigned long rem_jiffies; + int timeout = 5000; + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + + reinit_completion(&hw_mgr->a5_complete); + CAM_DBG(CAM_ICP, "Sending HFI init command"); + rc = a5_dev_intf->hw_ops.process_cmd( + a5_dev_intf->hw_priv, + CAM_ICP_A5_SEND_INIT, + NULL, 0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message"); + + return rc; +} + +static int cam_icp_mgr_hw_open_u(void *hw_mgr_priv, void *download_fw_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + int rc = 0; + + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_icp_mgr_hw_open(hw_mgr, download_fw_args); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_icp_mgr_hw_open_k(void *hw_mgr_priv, void *download_fw_args) +{ + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "Null hw mgr"); + return 0; + } + + return cam_icp_mgr_hw_open(hw_mgr, download_fw_args); +} + +static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *a5_dev_intf = NULL; + bool downloadFromResume = true; + + CAM_DBG(CAM_ICP, "Enter"); + a5_dev_intf = hw_mgr->devices[CAM_ICP_DEV_A5][0]; + + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5 dev intf is wrong"); + return -EINVAL; + } + + if (hw_mgr->fw_download == false) { + CAM_DBG(CAM_ICP, "Downloading FW"); + rc = cam_icp_mgr_hw_open_k(hw_mgr, &downloadFromResume); + CAM_DBG(CAM_ICP, "FW Download Done Exit"); + return rc; + } + + rc = a5_dev_intf->hw_ops.init(a5_dev_intf->hw_priv, NULL, 0); + if (rc) + return -EINVAL; + + rc = cam_icp_mgr_hfi_resume(hw_mgr); + if (rc) + goto hfi_resume_failed; + + CAM_DBG(CAM_ICP, "Exit"); + return rc; +hfi_resume_failed: + cam_icp_mgr_icp_power_collapse(hw_mgr); + return rc; +} + +static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args) +{ + struct cam_hw_intf *a5_dev_intf = NULL; + struct cam_hw_info *a5_dev = NULL; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + bool icp_pc = false; + int rc = 0; + + if (!hw_mgr) { + CAM_ERR(CAM_ICP, "hw_mgr is NULL"); + return -EINVAL; + } + + if (hw_mgr->fw_download) { + CAM_DBG(CAM_ICP, "FW already downloaded"); + return rc; + } + + a5_dev_intf = hw_mgr->a5_dev_intf; + if (!a5_dev_intf) { + CAM_ERR(CAM_ICP, "a5_dev_intf is invalid"); + return -EINVAL; + } + a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; + rc = cam_icp_allocate_hfi_mem(); + if (rc) + goto alloc_hfi_mem_failed; + + rc = cam_icp_mgr_device_init(hw_mgr); + if (rc) + goto dev_init_fail; + + rc = cam_icp_mgr_fw_download(hw_mgr); + if (rc) + goto fw_download_failed; + + rc = cam_icp_mgr_hfi_init(hw_mgr); + if (rc) + goto hfi_init_failed; + + rc = cam_icp_mgr_send_fw_init(hw_mgr); + if (rc) + goto fw_init_failed; + + hw_mgr->ctxt_cnt = 0; + hw_mgr->fw_download = true; + atomic_set(&hw_mgr->recovery, 0); + + CAM_INFO(CAM_ICP, "FW download done successfully"); + + rc = cam_ipe_bps_deint(hw_mgr); + if (download_fw_args) + icp_pc = *((bool *)download_fw_args); + + if (download_fw_args && icp_pc == true && hw_mgr->icp_pc_flag) { + rc = cam_ipe_bps_deint(hw_mgr); + CAM_DBG(CAM_ICP, "deinit all clocks"); + } + + if (download_fw_args && icp_pc == true) + return rc; + + rc = cam_ipe_bps_deint(hw_mgr); + rc = cam_icp_mgr_icp_power_collapse(hw_mgr); + CAM_DBG(CAM_ICP, "deinit all clocks at boot up"); + + return rc; + +fw_init_failed: + cam_hfi_deinit( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); +hfi_init_failed: + cam_hfi_disable_cpu( + a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); +fw_download_failed: + cam_icp_mgr_device_deinit(hw_mgr); +dev_init_fail: + cam_icp_free_hfi_mem(); +alloc_hfi_mem_failed: + return rc; +} + +static int cam_icp_mgr_handle_config_err( + struct cam_hw_config_args *config_args, + struct cam_icp_hw_ctx_data *ctx_data, + int idx) +{ + struct cam_hw_done_event_data buf_data; + + buf_data.request_id = *(uint64_t *)config_args->priv; + ctx_data->ctxt_event_cb(ctx_data->context_priv, false, &buf_data); + + ctx_data->hfi_frame_process.request_id[idx] = 0; + ctx_data->hfi_frame_process.fw_process_flag[idx] = false; + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + + return 0; +} + +static int cam_icp_mgr_enqueue_config(struct cam_icp_hw_mgr *hw_mgr, + struct cam_hw_config_args *config_args) +{ + int rc = 0; + uint64_t request_id = 0; + struct crm_workq_task *task; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async *hfi_cmd; + struct cam_hw_update_entry *hw_update_entries; + struct icp_frame_info *frame_info = NULL; + + frame_info = (struct icp_frame_info *)config_args->priv; + request_id = frame_info->request_id; + hw_update_entries = config_args->hw_update_entries; + CAM_DBG(CAM_ICP, "req_id = %lld %pK", request_id, config_args->priv); + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)hw_update_entries->addr; + hfi_cmd = (struct hfi_cmd_ipebps_async *)hw_update_entries->addr; + task_data->request_id = request_id; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, + uint32_t io_buf_addr) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async ioconfig_cmd; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + uint32_t size_in_words; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + reinit_completion(&ctx_data->wait_complete); + + ioconfig_cmd.num_fw_handles = 1; + ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd.payload.indirect = io_buf_addr; + ioconfig_cmd.user_data1 = PTR_TO_U64(ctx_data); + ioconfig_cmd.user_data2 = (uint64_t)0x0; + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&ioconfig_cmd; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + size_in_words = (*(uint32_t *)task_data->data) >> 2; + CAM_DBG(CAM_ICP, "size_in_words %u", size_in_words); + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + return rc; +} + +static int cam_icp_mgr_send_recfg_io(struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, uint64_t req_id) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ioconfig_cmd; + task_data->request_id = req_id; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + return rc; +} + +static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) +{ + int rc = 0; + int idx; + uint64_t req_id; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_config_args *config_args = config_hw_args; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct icp_frame_info *frame_info = NULL; + + if (!hw_mgr || !config_args) { + CAM_ERR(CAM_ICP, "Invalid arguments %pK %pK", + hw_mgr, config_args); + return -EINVAL; + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_ICP, "No hw update enteries are available"); + return -EINVAL; + } + + ctx_data = config_args->ctxt_to_hw_map; + mutex_lock(&hw_mgr->hw_mgr_mutex); + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) { + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_ICP, "ctx id :%u is not in use", + ctx_data->ctx_id); + return -EINVAL; + } + + frame_info = (struct icp_frame_info *)config_args->priv; + req_id = frame_info->request_id; + idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); + + cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); + ctx_data->hfi_frame_process.fw_process_flag[idx] = true; + + CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, + frame_info->io_config); + + if (frame_info->io_config != 0) { + CAM_INFO(CAM_ICP, "Send recfg io"); + rc = cam_icp_mgr_send_recfg_io(ctx_data, + &frame_info->hfi_cfg_io_cmd, req_id); + if (rc) + CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd"); + } + + if (req_id <= ctx_data->last_flush_req) + CAM_WARN(CAM_ICP, + "Anomaly submitting flushed req %llu [last_flush %llu] in ctx %u", + req_id, ctx_data->last_flush_req, ctx_data->ctx_id); + + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); + if (rc) + goto config_err; + CAM_DBG(CAM_REQ, + "req_id = %lld on ctx_id %u for dev %d queued to FW", + req_id, ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return 0; +config_err: + cam_icp_mgr_handle_config_err(config_args, ctx_data, idx); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_mgr_prepare_frame_process_cmd( + struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *hfi_cmd, + uint64_t request_id, + uint32_t fw_cmd_buf_iova_addr) +{ + hfi_cmd->size = sizeof(struct hfi_cmd_ipebps_async); + hfi_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_FRAME_PROCESS; + else + hfi_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_FRAME_PROCESS; + hfi_cmd->num_fw_handles = 1; + hfi_cmd->fw_handles[0] = ctx_data->fw_handle; + hfi_cmd->payload.indirect = fw_cmd_buf_iova_addr; + hfi_cmd->user_data1 = PTR_TO_U64(ctx_data); + hfi_cmd->user_data2 = request_id; + + CAM_DBG(CAM_ICP, "ctx_data : %pK, request_id :%lld cmd_buf %x", + (void *)ctx_data->context_priv, request_id, + fw_cmd_buf_iova_addr); + + return 0; +} + +static bool cam_icp_mgr_is_valid_inconfig(struct cam_packet *packet) +{ + int i, num_in_map_entries = 0; + bool in_config_valid = false; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + + for (i = 0 ; i < packet->num_io_configs; i++) + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) + num_in_map_entries++; + + if (num_in_map_entries <= CAM_MAX_IN_RES) { + in_config_valid = true; + } else { + CAM_ERR(CAM_ICP, "In config entries(%u) more than allowed(%u)", + num_in_map_entries, CAM_MAX_IN_RES); + } + + CAM_DBG(CAM_ICP, "number of in_config info: %u %u %u %u", + packet->num_io_configs, IPE_IO_IMAGES_MAX, + num_in_map_entries, CAM_MAX_IN_RES); + + return in_config_valid; +} + +static bool cam_icp_mgr_is_valid_outconfig(struct cam_packet *packet) +{ + int i, num_out_map_entries = 0; + bool out_config_valid = false; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + + for (i = 0 ; i < packet->num_io_configs; i++) + if (io_cfg_ptr[i].direction == CAM_BUF_OUTPUT) + num_out_map_entries++; + + if (num_out_map_entries <= CAM_MAX_OUT_RES) { + out_config_valid = true; + } else { + CAM_ERR(CAM_ICP, "Out config entries(%u) more than allowed(%u)", + num_out_map_entries, CAM_MAX_OUT_RES); + } + + CAM_DBG(CAM_ICP, "number of out_config info: %u %u %u %u", + packet->num_io_configs, IPE_IO_IMAGES_MAX, + num_out_map_entries, CAM_MAX_OUT_RES); + + return out_config_valid; +} + +static int cam_icp_mgr_pkt_validation(struct cam_packet *packet) +{ + if (((packet->header.op_code & 0xff) != + CAM_ICP_OPCODE_IPE_UPDATE) && + ((packet->header.op_code & 0xff) != + CAM_ICP_OPCODE_BPS_UPDATE)) { + CAM_ERR(CAM_ICP, "Invalid Opcode in pkt: %d", + packet->header.op_code & 0xff); + return -EINVAL; + } + + if (packet->num_io_configs > IPE_IO_IMAGES_MAX) { + CAM_ERR(CAM_ICP, "Invalid number of io configs: %d %d", + IPE_IO_IMAGES_MAX, packet->num_io_configs); + return -EINVAL; + } + + if (packet->num_cmd_buf > CAM_ICP_CTX_MAX_CMD_BUFFERS) { + CAM_ERR(CAM_ICP, "Invalid number of cmd buffers: %d %d", + CAM_ICP_CTX_MAX_CMD_BUFFERS, packet->num_cmd_buf); + return -EINVAL; + } + + if (!cam_icp_mgr_is_valid_inconfig(packet) || + !cam_icp_mgr_is_valid_outconfig(packet)) { + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "number of cmd/patch info: %u %u %u %u", + packet->num_cmd_buf, + packet->num_io_configs, IPE_IO_IMAGES_MAX, + packet->num_patches); + return 0; +} + +static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, + struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data, + uint32_t *fw_cmd_buf_iova_addr) +{ + int rc = 0; + int i; + int num_cmd_buf = 0; + dma_addr_t addr; + size_t len; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cpu_addr = 0; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + rc = cam_packet_util_validate_cmd_desc(cmd_desc); + if (rc) + return rc; + + *fw_cmd_buf_iova_addr = 0; + for (i = 0; i < packet->num_cmd_buf; i++, num_cmd_buf++) { + if (cmd_desc[i].type == CAM_CMD_BUF_FW) { + rc = cam_mem_get_io_buf(cmd_desc[i].mem_handle, + hw_mgr->iommu_hdl, &addr, &len); + if (rc) { + CAM_ERR(CAM_ICP, "get cmd buf failed %x", + hw_mgr->iommu_hdl); + + if (num_cmd_buf > 0) + num_cmd_buf--; + return rc; + } + *fw_cmd_buf_iova_addr = addr; + + if ((cmd_desc[i].offset >= len) || + ((len - cmd_desc[i].offset) < + cmd_desc[i].size)){ + CAM_ERR(CAM_ICP, + "Invalid offset, i: %d offset: %u len: %zu size: %zu", + i, cmd_desc[i].offset, + len, cmd_desc[i].size); + return -EINVAL; + } + + *fw_cmd_buf_iova_addr = + (*fw_cmd_buf_iova_addr + cmd_desc[i].offset); + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &cpu_addr, &len); + if (rc || !cpu_addr) { + CAM_ERR(CAM_ICP, "get cmd buf failed %x", + hw_mgr->iommu_hdl); + *fw_cmd_buf_iova_addr = 0; + + if (num_cmd_buf > 0) + num_cmd_buf--; + return rc; + } + if ((len <= cmd_desc[i].offset) || + (cmd_desc[i].size < cmd_desc[i].length) || + ((len - cmd_desc[i].offset) < + cmd_desc[i].length)) { + CAM_ERR(CAM_ICP, "Invalid offset or length"); + return -EINVAL; + } + cpu_addr = cpu_addr + cmd_desc[i].offset; + } + } + + if (!cpu_addr) { + CAM_ERR(CAM_ICP, "invalid number of cmd buf"); + return -EINVAL; + } + + return rc; +} + +static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_packet *packet, + struct cam_hw_prepare_update_args *prepare_args, + int32_t index) +{ + int i, j, k, rc = 0; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + int32_t sync_in_obj[CAM_MAX_IN_RES]; + int32_t merged_sync_in_obj; + + io_cfg_ptr = (struct cam_buf_io_cfg *) ((uint32_t *) &packet->payload + + packet->io_configs_offset/4); + prepare_args->num_out_map_entries = 0; + prepare_args->num_in_map_entries = 0; + + for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) { + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) { + sync_in_obj[j++] = io_cfg_ptr[i].fence; + prepare_args->num_in_map_entries++; + } else { + prepare_args->out_map_entries[k++].sync_id = + io_cfg_ptr[i].fence; + prepare_args->num_out_map_entries++; + } + CAM_DBG(CAM_REQ, + "ctx_id: %u req_id: %llu dir[%d]: %u, fence: %u resource_type = %u memh %x", + ctx_data->ctx_id, packet->header.request_id, i, + io_cfg_ptr[i].direction, io_cfg_ptr[i].fence, + io_cfg_ptr[i].resource_type, + io_cfg_ptr[i].mem_handle[0]); + } + + if (prepare_args->num_in_map_entries > 1) + prepare_args->num_in_map_entries = + cam_common_util_remove_duplicate_arr( + sync_in_obj, prepare_args->num_in_map_entries); + + if (prepare_args->num_in_map_entries > 1) { + rc = cam_sync_merge(&sync_in_obj[0], + prepare_args->num_in_map_entries, &merged_sync_in_obj); + if (rc) { + prepare_args->num_out_map_entries = 0; + prepare_args->num_in_map_entries = 0; + return rc; + } + + ctx_data->hfi_frame_process.in_resource[index] = + merged_sync_in_obj; + prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj; + prepare_args->num_in_map_entries = 1; + CAM_DBG(CAM_REQ, "ctx_id: %u req_id: %llu Merged Sync obj: %d", + ctx_data->ctx_id, packet->header.request_id, + merged_sync_in_obj); + } else if (prepare_args->num_in_map_entries == 1) { + prepare_args->in_map_entries[0].sync_id = sync_in_obj[0]; + prepare_args->num_in_map_entries = 1; + ctx_data->hfi_frame_process.in_resource[index] = 0; + } else { + CAM_ERR(CAM_ICP, "No input fences"); + prepare_args->num_in_map_entries = 0; + ctx_data->hfi_frame_process.in_resource[index] = 0; + rc = -EINVAL; + } + + return rc; +} + +static int cam_icp_process_stream_settings( + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_cmd_mem_regions *cmd_mem_regions, + bool map_unmap) +{ + int rc = 0, i = 0; + size_t packet_size, map_cmd_size, len; + dma_addr_t iova; + unsigned long rem_jiffies; + int timeout = 5000; + struct hfi_cmd_ipe_bps_map *map_cmd; + struct hfi_cmd_ipebps_async *async_direct; + + map_cmd_size = + sizeof(struct hfi_cmd_ipe_bps_map) + + ((cmd_mem_regions->num_regions - 1) * + sizeof(struct mem_map_region_data)); + + map_cmd = kzalloc(map_cmd_size, GFP_KERNEL); + if (!map_cmd) + return -ENOMEM; + + for (i = 0; i < cmd_mem_regions->num_regions; i++) { + rc = cam_mem_get_io_buf( + cmd_mem_regions->map_info_array[i].mem_handle, + icp_hw_mgr.iommu_hdl, &iova, &len); + if (rc) { + CAM_ERR(CAM_ICP, + "Failed to get cmd region iova for handle %u", + cmd_mem_regions->map_info_array[i].mem_handle); + kfree(map_cmd); + return -EINVAL; + } + + map_cmd->mem_map_region_sets[i].start_addr = (uint32_t)iova + + (cmd_mem_regions->map_info_array[i].offset); + map_cmd->mem_map_region_sets[i].len = (uint32_t) len; + + CAM_DBG(CAM_ICP, "Region %u mem_handle %d iova %pK len %u", + (i+1), cmd_mem_regions->map_info_array[i].mem_handle, + (uint32_t)iova, (uint32_t)len); + } + + map_cmd->mem_map_request_num = cmd_mem_regions->num_regions; + map_cmd->user_data = 0; + + packet_size = + sizeof(struct hfi_cmd_ipebps_async) + + (sizeof(struct hfi_cmd_ipe_bps_map) + + ((cmd_mem_regions->num_regions - 1) * + sizeof(struct mem_map_region_data))) - + sizeof(((struct hfi_cmd_ipebps_async *)0)->payload.direct); + + async_direct = kzalloc(packet_size, GFP_KERNEL); + if (!async_direct) { + kfree(map_cmd); + return -ENOMEM; + } + + async_direct->size = packet_size; + async_direct->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_DIRECT; + if (map_unmap) + async_direct->opcode = HFI_IPEBPS_CMD_OPCODE_MEM_MAP; + else + async_direct->opcode = HFI_IPEBPS_CMD_OPCODE_MEM_UNMAP; + async_direct->num_fw_handles = 1; + async_direct->fw_handles[0] = ctx_data->fw_handle; + async_direct->user_data1 = (uint64_t)ctx_data; + async_direct->user_data2 = (uint64_t)0x0; + memcpy(async_direct->payload.direct, map_cmd, + map_cmd_size); + + reinit_completion(&ctx_data->wait_complete); + rc = hfi_write_cmd(async_direct); + if (rc) { + CAM_ERR(CAM_ICP, "hfi write failed rc %d", rc); + goto end; + } + + CAM_DBG(CAM_ICP, "Sent FW %s cmd", + map_unmap ? "Map" : "Unmap"); + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); + } + +end: + kfree(map_cmd); + kfree(async_direct); + return rc; +} + +static int cam_icp_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + struct cam_icp_clk_bw_request *soc_req; + struct cam_icp_clk_bw_request *clk_info; + struct cam_icp_clk_bw_request_v2 *soc_req_v2; + struct cam_icp_clk_bw_req_internal_v2 *clk_info_v2; + struct cam_cmd_mem_regions *cmd_mem_regions; + struct icp_cmd_generic_blob *blob; + struct cam_icp_hw_ctx_data *ctx_data; + uint32_t index; + size_t io_buf_size, clk_update_size; + int rc = 0; + uintptr_t pResource; + uint32_t i = 0; + + if (!blob_data || (blob_size == 0)) { + CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data, + blob_size); + return -EINVAL; + } + + blob = (struct icp_cmd_generic_blob *)user_data; + ctx_data = blob->ctx; + index = blob->frame_info_idx; + + switch (blob_type) { + case CAM_ICP_CMD_GENERIC_BLOB_CLK: + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, + "Using deprecated blob type GENERIC_BLOB_CLK"); + if (blob_size != sizeof(struct cam_icp_clk_bw_request)) { + CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", + blob_size, + sizeof(struct cam_icp_clk_bw_request)); + return -EINVAL; + } + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_UNKNOWN) { + ctx_data->bw_config_version = CAM_ICP_BW_CONFIG_V1; + } else if (ctx_data->bw_config_version != + CAM_ICP_BW_CONFIG_V1) { + CAM_ERR(CAM_ICP, + "Mismatch blob versions %d expected v1 %d, blob_type=%d", + ctx_data->bw_config_version, + CAM_ICP_BW_CONFIG_V1, blob_type); + return -EINVAL; + } + + clk_info = &ctx_data->hfi_frame_process.clk_info[index]; + + soc_req = (struct cam_icp_clk_bw_request *)blob_data; + *clk_info = *soc_req; + CAM_DBG(CAM_PERF, "budget:%llu fc: %llu %d BW %lld %lld", + clk_info->budget_ns, clk_info->frame_cycles, + clk_info->rt_flag, clk_info->uncompressed_bw, + clk_info->compressed_bw); + break; + + case CAM_ICP_CMD_GENERIC_BLOB_CLK_V2: + if (blob_size < sizeof(struct cam_icp_clk_bw_request_v2)) { + CAM_ERR(CAM_ICP, "Mismatch blob size %d expected %lu", + blob_size, + sizeof(struct cam_icp_clk_bw_request_v2)); + return -EINVAL; + } + + if (ctx_data->bw_config_version == CAM_ICP_BW_CONFIG_UNKNOWN) { + ctx_data->bw_config_version = CAM_ICP_BW_CONFIG_V2; + } else if (ctx_data->bw_config_version != + CAM_ICP_BW_CONFIG_V2) { + CAM_ERR(CAM_ICP, + "Mismatch blob versions %d expected v2 %d, blob_type=%d", + ctx_data->bw_config_version, + CAM_ICP_BW_CONFIG_V2, blob_type); + return -EINVAL; + } + + soc_req_v2 = (struct cam_icp_clk_bw_request_v2 *)blob_data; + if (soc_req_v2->num_paths > CAM_ICP_MAX_PER_PATH_VOTES) { + CAM_ERR(CAM_PERF, "Invalid num paths: %d", + soc_req_v2->num_paths); + return -EINVAL; + } + + /* Check for integer overflow */ + if (soc_req_v2->num_paths != 1) { + if (sizeof(struct cam_axi_per_path_bw_vote) > + ((UINT_MAX - + sizeof(struct cam_icp_clk_bw_request_v2)) / + (soc_req_v2->num_paths - 1))) { + CAM_ERR(CAM_ICP, + "Size exceeds limit paths:%u size per path:%lu", + soc_req_v2->num_paths - 1, + sizeof( + struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + } + + clk_update_size = sizeof(struct cam_icp_clk_bw_request_v2) + + ((soc_req_v2->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)); + if (blob_size < clk_update_size) { + CAM_ERR(CAM_ICP, "Invalid blob size: %u", + blob_size); + return -EINVAL; + } + + clk_info = &ctx_data->hfi_frame_process.clk_info[index]; + clk_info_v2 = &ctx_data->hfi_frame_process.clk_info_v2[index]; + + memcpy(clk_info_v2, soc_req_v2, clk_update_size); + + /* Use v1 structure for clk fields */ + clk_info->budget_ns = clk_info_v2->budget_ns; + clk_info->frame_cycles = clk_info_v2->frame_cycles; + clk_info->rt_flag = clk_info_v2->rt_flag; + + CAM_DBG(CAM_PERF, + "budget=%llu, frame_cycle=%llu, rt_flag=%d, num_paths=%d, clk_update_size=%d, index=%d, ctx_data=%pK", + clk_info_v2->budget_ns, clk_info_v2->frame_cycles, + clk_info_v2->rt_flag, + clk_info_v2->num_paths, + clk_update_size, + index, + ctx_data); + + for (i = 0; i < clk_info_v2->num_paths; i++) { + CAM_DBG(CAM_PERF, + "[%d] : path_type=%d, trans_type=%d, camnoc=%lld, mnoc_ab=%lld, mnoc_ib=%lld", + i, + clk_info_v2->axi_path[i].path_data_type, + clk_info_v2->axi_path[i].transac_type, + clk_info_v2->axi_path[i].camnoc_bw, + clk_info_v2->axi_path[i].mnoc_ab_bw, + clk_info_v2->axi_path[i].mnoc_ib_bw); + } + + break; + + case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO: + CAM_DBG(CAM_ICP, "CAM_ICP_CMD_GENERIC_BLOB_CFG_IO"); + pResource = *((uint32_t *)blob_data); + if (copy_from_user(&ctx_data->icp_dev_io_info, + (void __user *)pResource, + sizeof(struct cam_icp_acquire_dev_info))) { + CAM_ERR(CAM_ICP, "Failed in copy from user"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "buf handle %d", + ctx_data->icp_dev_io_info.io_config_cmd_handle); + rc = cam_mem_get_io_buf( + ctx_data->icp_dev_io_info.io_config_cmd_handle, + icp_hw_mgr.iommu_hdl, + blob->io_buf_addr, &io_buf_size); + if (rc) + CAM_ERR(CAM_ICP, "Failed in blob update"); + else + CAM_DBG(CAM_ICP, "io buf addr %llu", + *blob->io_buf_addr); + break; + + case CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_MAP: + cmd_mem_regions = + (struct cam_cmd_mem_regions *)blob_data; + if (cmd_mem_regions->num_regions <= 0) { + rc = -EINVAL; + CAM_ERR(CAM_ICP, + "Invalid number of regions for FW map %u", + cmd_mem_regions->num_regions); + } else { + CAM_DBG(CAM_ICP, + "Processing blob for mapping %u regions", + cmd_mem_regions->num_regions); + rc = cam_icp_process_stream_settings(ctx_data, + cmd_mem_regions, true); + } + break; + + case CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_UNMAP: + cmd_mem_regions = + (struct cam_cmd_mem_regions *)blob_data; + if (cmd_mem_regions->num_regions <= 0) { + rc = -EINVAL; + CAM_ERR(CAM_ICP, + "Invalid number of regions for FW unmap %u", + cmd_mem_regions->num_regions); + } else { + CAM_DBG(CAM_ICP, + "Processing blob for unmapping %u regions", + cmd_mem_regions->num_regions); + rc = cam_icp_process_stream_settings(ctx_data, + cmd_mem_regions, false); + } + break; + + default: + CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type); + break; + } + return rc; +} + +static int cam_icp_process_generic_cmd_buffer( + struct cam_packet *packet, + struct cam_icp_hw_ctx_data *ctx_data, + int32_t index, + dma_addr_t *io_buf_addr) +{ + int i, rc = 0; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct icp_cmd_generic_blob cmd_generic_blob; + + cmd_generic_blob.ctx = ctx_data; + cmd_generic_blob.frame_info_idx = index; + cmd_generic_blob.io_buf_addr = io_buf_addr; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + for (i = 0; i < packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if (cmd_desc[i].meta_data != CAM_ICP_CMD_META_GENERIC_BLOB) + continue; + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[i], + cam_icp_packet_generic_blob_handler, &cmd_generic_blob); + if (rc) + CAM_ERR(CAM_ICP, "Failed in processing blobs %d", rc); + } + + return rc; +} + +static int cam_icp_mgr_process_cfg_io_cmd( + struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, + uint64_t request_id, + uint64_t io_config) +{ + ioconfig_cmd->size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + ioconfig_cmd->num_fw_handles = 1; + ioconfig_cmd->fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd->payload.indirect = io_config; + ioconfig_cmd->user_data1 = PTR_TO_U64(ctx_data); + ioconfig_cmd->user_data2 = request_id; + + return 0; +} + +static int cam_icp_mgr_update_hfi_frame_process( + struct cam_icp_hw_ctx_data *ctx_data, + struct cam_packet *packet, + struct cam_hw_prepare_update_args *prepare_args, + int32_t *idx) +{ + int32_t index, rc; + struct hfi_cmd_ipebps_async *hfi_cmd = NULL; + + index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap, + ctx_data->hfi_frame_process.bits); + if (index < 0 || index >= CAM_FRAME_CMD_MAX) { + CAM_ERR(CAM_ICP, "request idx is wrong: %d", index); + return -EINVAL; + } + set_bit(index, ctx_data->hfi_frame_process.bitmap); + + ctx_data->hfi_frame_process.request_id[index] = + packet->header.request_id; + ctx_data->hfi_frame_process.frame_info[index].request_id = + packet->header.request_id; + ctx_data->hfi_frame_process.frame_info[index].io_config = 0; + rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index, + &ctx_data->hfi_frame_process.frame_info[index].io_config); + if (rc) { + clear_bit(index, ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.request_id[index] = -1; + return rc; + } + + if (ctx_data->hfi_frame_process.frame_info[index].io_config) { + hfi_cmd = (struct hfi_cmd_ipebps_async *) + &ctx_data->hfi_frame_process.frame_info[index].hfi_cfg_io_cmd; + rc = cam_icp_mgr_process_cfg_io_cmd(ctx_data, hfi_cmd, + packet->header.request_id, + ctx_data->hfi_frame_process.frame_info[index].io_config); + } + *idx = index; + + return rc; +} + +static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + dma_addr_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_ICP, + "Found PF at port: %d mem %x fd: %x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_ICP, "port: %d f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, + "get src buf address fail rc %d", rc); + continue; + } + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { + CAM_ERR(CAM_ICP, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_ICP, + "pln %d dir %d w %d h %d s %u sh %u sz %d addr 0x%x off 0x%x memh %x", + j, io_cfg[i].direction, + io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, + (int32_t)src_buf_size, + (unsigned int)iova_addr, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + + iova_addr += io_cfg[i].offsets[j]; + + } + } + cam_packet_dump_patch_info(packet, icp_hw_mgr.iommu_hdl, + icp_hw_mgr.iommu_sec_hdl); +} + +static int cam_icp_mgr_config_stream_settings( + void *hw_mgr_priv, void *hw_stream_settings) +{ + int rc = 0; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct cam_packet *packet = NULL; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct icp_cmd_generic_blob cmd_generic_blob; + struct cam_hw_stream_setttings *config_args = + hw_stream_settings; + + if ((!hw_stream_settings) || + (!hw_mgr) || (!config_args->packet)) { + CAM_ERR(CAM_ICP, "Invalid input arguments"); + return -EINVAL; + } + + ctx_data = config_args->ctxt_to_hw_map; + mutex_lock(&ctx_data->ctx_mutex); + packet = config_args->packet; + + cmd_generic_blob.ctx = ctx_data; + cmd_generic_blob.frame_info_idx = -1; + cmd_generic_blob.io_buf_addr = NULL; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + + if (!cmd_desc[0].length || + cmd_desc[0].meta_data != CAM_ICP_CMD_META_GENERIC_BLOB) { + CAM_ERR(CAM_ICP, "Invalid cmd buffer length/metadata"); + rc = -EINVAL; + goto end; + } + + rc = cam_packet_util_process_generic_cmd_buffer(&cmd_desc[0], + cam_icp_packet_generic_blob_handler, &cmd_generic_blob); + if (rc) + CAM_ERR(CAM_ICP, "Failed in processing cmd mem blob %d", rc); + +end: + mutex_unlock(&ctx_data->ctx_mutex); + return rc; +} + +static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + int32_t idx; + uint32_t fw_cmd_buf_iova_addr; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct cam_packet *packet = NULL; + struct hfi_cmd_ipebps_async *hfi_cmd = NULL; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_prepare_update_args *prepare_args = + prepare_hw_update_args; + + if ((!prepare_args) || (!hw_mgr) || (!prepare_args->packet)) { + CAM_ERR(CAM_ICP, "Invalid args"); + return -EINVAL; + } + + ctx_data = prepare_args->ctxt_to_hw_map; + mutex_lock(&ctx_data->ctx_mutex); + if (ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) { + mutex_unlock(&ctx_data->ctx_mutex); + CAM_ERR(CAM_ICP, "ctx id: %u is not in use", + ctx_data->ctx_id); + return -EINVAL; + } + + packet = prepare_args->packet; + + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + return -EINVAL; + + rc = cam_icp_mgr_pkt_validation(packet); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + rc = cam_icp_mgr_process_cmd_desc(hw_mgr, packet, + ctx_data, &fw_cmd_buf_iova_addr); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + prepare_args->pf_data->packet = packet; + + CAM_DBG(CAM_REQ, "req id = %lld for ctx = %u", + packet->header.request_id, ctx_data->ctx_id); + /* Update Buffer Address from handles and patch information */ + rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + rc = cam_icp_mgr_update_hfi_frame_process(ctx_data, packet, + prepare_args, &idx); + if (rc) { + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + rc = cam_icp_mgr_process_io_cfg(hw_mgr, ctx_data, + packet, prepare_args, idx); + if (rc) { + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) + cam_sync_destroy( + ctx_data->hfi_frame_process.in_resource[idx]); + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.request_id[idx] = -1; + mutex_unlock(&ctx_data->ctx_mutex); + return rc; + } + + hfi_cmd = (struct hfi_cmd_ipebps_async *) + &ctx_data->hfi_frame_process.hfi_frame_cmd[idx]; + cam_icp_mgr_prepare_frame_process_cmd( + ctx_data, hfi_cmd, packet->header.request_id, + fw_cmd_buf_iova_addr); + + prepare_args->num_hw_update_entries = 1; + prepare_args->hw_update_entries[0].addr = (uintptr_t)hfi_cmd; + prepare_args->priv = &ctx_data->hfi_frame_process.frame_info[idx]; + + CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u", + packet->header.request_id, ctx_data->ctx_id); + mutex_unlock(&ctx_data->ctx_mutex); + return rc; +} + +static int cam_icp_mgr_send_abort_status(struct cam_icp_hw_ctx_data *ctx_data) +{ + struct hfi_frame_process_info *hfi_frame_process; + int idx; + + mutex_lock(&ctx_data->ctx_mutex); + hfi_frame_process = &ctx_data->hfi_frame_process; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->request_id[idx]) + continue; + + ctx_data->ctxt_event_cb(ctx_data->context_priv, true, + &hfi_frame_process->request_id[idx]); + + /* now release memory for hfi frame process command */ + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + CAM_DBG(CAM_ICP, "Delete merged sync in object: %d", + ctx_data->hfi_frame_process.in_resource[idx]); + cam_sync_destroy( + ctx_data->hfi_frame_process.in_resource[idx]); + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + } + mutex_unlock(&ctx_data->ctx_mutex); + return 0; +} + +static int cam_icp_mgr_delete_sync(void *priv, void *data) +{ + struct hfi_cmd_work_data *task_data = NULL; + struct cam_icp_hw_ctx_data *ctx_data; + struct hfi_frame_process_info *hfi_frame_process; + int idx; + + if (!data || !priv) { + CAM_ERR(CAM_ICP, "Invalid params%pK %pK", data, priv); + return -EINVAL; + } + + task_data = (struct hfi_cmd_work_data *)data; + ctx_data = task_data->data; + + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Null Context"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + hfi_frame_process = &ctx_data->hfi_frame_process; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->in_free_resource[idx]) + continue; + //cam_sync_destroy( + //ctx_data->hfi_frame_process.in_free_resource[idx]); + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + mutex_unlock(&ctx_data->ctx_mutex); + return 0; +} + +static int cam_icp_mgr_delete_sync_obj(struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + struct crm_workq_task *task; + struct hfi_cmd_work_data *task_data; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ctx_data; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_delete_sync; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_icp_mgr_flush_all(struct cam_icp_hw_ctx_data *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + struct hfi_frame_process_info *hfi_frame_process; + int idx; + bool clear_in_resource = false; + + hfi_frame_process = &ctx_data->hfi_frame_process; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->request_id[idx]) + continue; + + /* now release memory for hfi frame process command */ + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + ctx_data->hfi_frame_process.in_free_resource[idx] = + ctx_data->hfi_frame_process.in_resource[idx]; + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + clear_in_resource = true; + } + + if (clear_in_resource) + cam_icp_mgr_delete_sync_obj(ctx_data); + + return 0; +} + +static int cam_icp_mgr_flush_req(struct cam_icp_hw_ctx_data *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + int64_t request_id; + struct hfi_frame_process_info *hfi_frame_process; + int idx; + bool clear_in_resource = false; + + hfi_frame_process = &ctx_data->hfi_frame_process; + request_id = *(int64_t *)flush_args->flush_req_pending[0]; + for (idx = 0; idx < CAM_FRAME_CMD_MAX; idx++) { + if (!hfi_frame_process->request_id[idx]) + continue; + + if (hfi_frame_process->request_id[idx] != request_id) + continue; + + /* now release memory for hfi frame process command */ + hfi_frame_process->request_id[idx] = 0; + if (ctx_data->hfi_frame_process.in_resource[idx] > 0) { + ctx_data->hfi_frame_process.in_free_resource[idx] = + ctx_data->hfi_frame_process.in_resource[idx]; + ctx_data->hfi_frame_process.in_resource[idx] = 0; + } + clear_bit(idx, ctx_data->hfi_frame_process.bitmap); + clear_in_resource = true; + } + + if (clear_in_resource) + cam_icp_mgr_delete_sync_obj(ctx_data); + + return 0; +} + +static void cam_icp_mgr_flush_info_dump( + struct cam_hw_flush_args *flush_args, uint32_t ctx_id) +{ + int i; + + for (i = 0; i < flush_args->num_req_active; i++) { + CAM_DBG(CAM_ICP, "Flushing active request %lld in ctx %u", + *(int64_t *)flush_args->flush_req_active[i], + ctx_id); + } + + for (i = 0; i < flush_args->num_req_pending; i++) { + CAM_DBG(CAM_ICP, "Flushing pending request %lld in ctx %u", + *(int64_t *)flush_args->flush_req_pending[i], + ctx_id); + } +} + +static int cam_icp_mgr_enqueue_abort( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int timeout = 1000, rc; + unsigned long rem_jiffies = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "no empty task"); + return -ENOMEM; + } + + reinit_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ctx_data; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_abort_handle_wq; + cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = cam_icp_retry_wait_for_abort(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, + "FW timeout/err in abort handle command ctx: %u", + ctx_data->ctx_id); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + return rc; + } + } + + CAM_DBG(CAM_ICP, "Abort after flush is success"); + return 0; +} + +static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) +{ + struct cam_hw_flush_args *flush_args = hw_flush_args; + struct cam_icp_hw_ctx_data *ctx_data; + struct cam_icp_hw_mgr *hw_mgr = hw_priv; + + if ((!hw_priv) || (!hw_flush_args)) { + CAM_ERR(CAM_ICP, "Input params are Null:"); + return -EINVAL; + } + + ctx_data = flush_args->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Ctx data is NULL"); + return -EINVAL; + } + + if ((flush_args->flush_type >= CAM_FLUSH_TYPE_MAX) || + (flush_args->flush_type < CAM_FLUSH_TYPE_REQ)) { + CAM_ERR(CAM_ICP, "Invalid lush type: %d", + flush_args->flush_type); + return -EINVAL; + } + + ctx_data->last_flush_req = flush_args->last_flush_req; + CAM_DBG(CAM_REQ, "ctx_id %d Flush type %d last_flush_req %u", + ctx_data->ctx_id, flush_args->flush_type, + ctx_data->last_flush_req); + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!atomic_read(&hw_mgr->recovery) + && flush_args->num_req_active) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_flush_info_dump(flush_args, + ctx_data->ctx_id); + cam_icp_mgr_enqueue_abort(ctx_data); + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + } + mutex_lock(&ctx_data->ctx_mutex); + cam_icp_mgr_flush_all(ctx_data, flush_args); + mutex_unlock(&ctx_data->ctx_mutex); + break; + case CAM_FLUSH_TYPE_REQ: + mutex_lock(&ctx_data->ctx_mutex); + if (flush_args->num_req_active) { + CAM_ERR(CAM_ICP, "Flush request is not supported"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + if (flush_args->num_req_pending) + cam_icp_mgr_flush_req(ctx_data, flush_args); + mutex_unlock(&ctx_data->ctx_mutex); + break; + default: + CAM_ERR(CAM_ICP, "Invalid flush type: %d", + flush_args->flush_type); + return -EINVAL; + } + + return 0; +} + +static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) +{ + int rc = 0; + int ctx_id = 0; + struct cam_hw_release_args *release_hw = release_hw_args; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + + if (!release_hw || !hw_mgr) { + CAM_ERR(CAM_ICP, "Invalid args: %pK %pK", release_hw, hw_mgr); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "Enter recovery set %d", + atomic_read(&hw_mgr->recovery)); + ctx_data = release_hw->ctxt_to_hw_map; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "NULL ctx data"); + return -EINVAL; + } + + ctx_id = ctx_data->ctx_id; + if (ctx_id < 0 || ctx_id >= CAM_ICP_CTX_MAX) { + CAM_ERR(CAM_ICP, "Invalid ctx id: %d", ctx_id); + return -EINVAL; + } + + mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + if (hw_mgr->ctx_data[ctx_id].state != CAM_ICP_CTX_STATE_ACQUIRED) { + CAM_DBG(CAM_ICP, "ctx is not in use: %d", ctx_id); + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + return -EINVAL; + } + mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!atomic_read(&hw_mgr->recovery) && release_hw->active_req) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_send_abort_status(ctx_data); + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + rc = cam_icp_mgr_release_ctx(hw_mgr, ctx_id); + if (!hw_mgr->ctxt_cnt) { + CAM_DBG(CAM_ICP, "Last Release"); + cam_icp_mgr_icp_power_collapse(hw_mgr); + cam_icp_hw_mgr_reset_clk_info(hw_mgr); + rc = cam_ipe_bps_deint(hw_mgr); + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + if ((!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)) + cam_icp_device_timer_stop(hw_mgr); + + CAM_DBG(CAM_ICP, "Release done for ctx_id %d", ctx_id); + return rc; +} + +static int cam_icp_mgr_create_handle(uint32_t dev_type, + struct cam_icp_hw_ctx_data *ctx_data) +{ + struct hfi_cmd_create_handle create_handle; + struct hfi_cmd_work_data *task_data; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + int rc = 0; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + create_handle.size = sizeof(struct hfi_cmd_create_handle); + create_handle.pkt_type = HFI_CMD_IPEBPS_CREATE_HANDLE; + create_handle.handle_type = dev_type; + create_handle.user_data1 = PTR_TO_U64(ctx_data); + reinit_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&create_handle; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + if (ctx_data->fw_handle == 0) { + CAM_ERR(CAM_ICP, "Invalid handle created"); + rc = -EINVAL; + } + + return rc; +} + +static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data) +{ + struct hfi_cmd_ping_pkt ping_pkt; + struct hfi_cmd_work_data *task_data; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + int rc = 0; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) { + CAM_ERR(CAM_ICP, "No free task to send ping command"); + return -ENOMEM; + } + + ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt); + ping_pkt.pkt_type = HFI_CMD_SYS_PING; + ping_pkt.user_data = PTR_TO_U64(ctx_data); + init_completion(&ctx_data->wait_complete); + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&ping_pkt; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + cam_hfi_queue_dump(); + } + + return rc; +} + +static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, + struct cam_hw_acquire_args *args, + struct cam_icp_hw_ctx_data *ctx_data) +{ + int i; + int acquire_size; + struct cam_icp_acquire_dev_info icp_dev_acquire_info; + struct cam_icp_res_info *p_icp_out = NULL; + + if (copy_from_user(&icp_dev_acquire_info, + (void __user *)args->acquire_info, + sizeof(struct cam_icp_acquire_dev_info))) { + CAM_ERR(CAM_ICP, "Failed in acquire"); + return -EFAULT; + } + + if (icp_dev_acquire_info.secure_mode > CAM_SECURE_MODE_SECURE) { + CAM_ERR(CAM_ICP, "Invalid mode:%d", + icp_dev_acquire_info.secure_mode); + return -EINVAL; + } + + if ((icp_dev_acquire_info.num_out_res > ICP_MAX_OUTPUT_SUPPORTED) || + (icp_dev_acquire_info.num_out_res <= 0)) { + CAM_ERR(CAM_ICP, "Invalid num of out resources: %u", + icp_dev_acquire_info.num_out_res); + return -EINVAL; + } + + if (icp_dev_acquire_info.dev_type >= CAM_ICP_RES_TYPE_MAX) { + CAM_ERR(CAM_ICP, "Invalid device type: %d", + icp_dev_acquire_info.dev_type); + return -EFAULT; + } + + acquire_size = sizeof(struct cam_icp_acquire_dev_info) + + ((icp_dev_acquire_info.num_out_res - 1) * + sizeof(struct cam_icp_res_info)); + ctx_data->icp_dev_acquire_info = kzalloc(acquire_size, GFP_KERNEL); + if (!ctx_data->icp_dev_acquire_info) + return -ENOMEM; + + if (copy_from_user(ctx_data->icp_dev_acquire_info, + (void __user *)args->acquire_info, acquire_size)) { + CAM_ERR(CAM_ICP, "Failed in acquire: size = %d", acquire_size); + kfree(ctx_data->icp_dev_acquire_info); + ctx_data->icp_dev_acquire_info = NULL; + return -EFAULT; + } + + CAM_DBG(CAM_ICP, "%x %x %x %x %x %x %x", + ctx_data->icp_dev_acquire_info->dev_type, + ctx_data->icp_dev_acquire_info->in_res.format, + ctx_data->icp_dev_acquire_info->in_res.width, + ctx_data->icp_dev_acquire_info->in_res.height, + ctx_data->icp_dev_acquire_info->in_res.fps, + ctx_data->icp_dev_acquire_info->num_out_res, + ctx_data->icp_dev_acquire_info->scratch_mem_size); + + p_icp_out = ctx_data->icp_dev_acquire_info->out_res; + for (i = 0; i < icp_dev_acquire_info.num_out_res; i++) + CAM_DBG(CAM_ICP, "out[i] %x %x %x %x", + p_icp_out[i].format, + p_icp_out[i].width, + p_icp_out[i].height, + p_icp_out[i].fps); + + return 0; +} + +static uint32_t cam_icp_unify_dev_type( + uint32_t dev_type) +{ + switch (dev_type) { + case CAM_ICP_RES_TYPE_BPS: + return CAM_ICP_RES_TYPE_BPS; + case CAM_ICP_RES_TYPE_BPS_RT: + return CAM_ICP_RES_TYPE_BPS; + case CAM_ICP_RES_TYPE_BPS_SEMI_RT: + return CAM_ICP_RES_TYPE_BPS; + case CAM_ICP_RES_TYPE_IPE: + return CAM_ICP_RES_TYPE_IPE; + case CAM_ICP_RES_TYPE_IPE_RT: + return CAM_ICP_RES_TYPE_IPE; + case CAM_ICP_RES_TYPE_IPE_SEMI_RT: + return CAM_ICP_RES_TYPE_IPE; + default: + return CAM_ICP_RES_TYPE_MAX; + } +} + +static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + int rc = 0, bitmap_size = 0; + uint32_t ctx_id = 0, dev_type; + dma_addr_t io_buf_addr; + size_t io_buf_size; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct cam_hw_acquire_args *args = acquire_hw_args; + struct cam_icp_acquire_dev_info *icp_dev_acquire_info; + struct cam_cmd_mem_regions cmd_mem_region; + + if ((!hw_mgr_priv) || (!acquire_hw_args)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", hw_mgr_priv, + acquire_hw_args); + return -EINVAL; + } + + if (args->num_acq > 1) { + CAM_ERR(CAM_ICP, "number of resources are wrong: %u", + args->num_acq); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "ENTER"); + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_id = cam_icp_mgr_get_free_ctx(hw_mgr); + if (ctx_id >= CAM_ICP_CTX_MAX) { + CAM_ERR(CAM_ICP, "No free ctx space in hw_mgr"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -ENOSPC; + } + ctx_data = &hw_mgr->ctx_data[ctx_id]; + ctx_data->ctx_id = ctx_id; + + mutex_lock(&ctx_data->ctx_mutex); + rc = cam_icp_get_acquire_info(hw_mgr, args, ctx_data); + if (rc) + goto acquire_info_failed; + + icp_dev_acquire_info = ctx_data->icp_dev_acquire_info; + dev_type = icp_dev_acquire_info->dev_type; + icp_dev_acquire_info->dev_type = + cam_icp_unify_dev_type(dev_type); + + CAM_DBG(CAM_ICP, "acquire io buf handle %d", + icp_dev_acquire_info->io_config_cmd_handle); + rc = cam_mem_get_io_buf( + icp_dev_acquire_info->io_config_cmd_handle, + hw_mgr->iommu_hdl, + &io_buf_addr, &io_buf_size); + if (rc) { + CAM_ERR(CAM_ICP, "unable to get src buf info from io desc"); + goto get_io_buf_failed; + } + + CAM_DBG(CAM_ICP, "hdl: %d, addr: %pK, size: %zu", + icp_dev_acquire_info->io_config_cmd_handle, + (void *)io_buf_addr, io_buf_size); + + if (!hw_mgr->ctxt_cnt) { + rc = cam_icp_clk_info_init(hw_mgr, ctx_data); + if (rc) + goto get_io_buf_failed; + + rc = cam_icp_mgr_icp_resume(hw_mgr); + if (rc) + goto get_io_buf_failed; + + if (icp_hw_mgr.a5_debug_type) + hfi_set_debug_level(icp_hw_mgr.a5_debug_type, + icp_hw_mgr.a5_dbg_lvl); + + hfi_set_fw_dump_level(icp_hw_mgr.a5_fw_dump_lvl); + + rc = cam_icp_send_ubwc_cfg(hw_mgr); + if (rc) + goto ubwc_cfg_failed; + } + + + rc = cam_icp_mgr_ipe_bps_resume(hw_mgr, ctx_data); + if (rc) + goto ipe_bps_resume_failed; + + rc = cam_icp_mgr_send_ping(ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, "ping ack not received"); + goto send_ping_failed; + } + CAM_DBG(CAM_ICP, "ping ack received"); + + rc = cam_icp_mgr_create_handle(dev_type, + ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, "create handle failed"); + goto create_handle_failed; + } + + CAM_DBG(CAM_ICP, + "created stream handle for dev_type %u", + dev_type); + + cmd_mem_region.num_regions = 1; + cmd_mem_region.map_info_array[0].mem_handle = + icp_dev_acquire_info->io_config_cmd_handle; + cmd_mem_region.map_info_array[0].offset = 0; + cmd_mem_region.map_info_array[0].size = + icp_dev_acquire_info->io_config_cmd_size; + cmd_mem_region.map_info_array[0].flags = 0; + + rc = cam_icp_process_stream_settings(ctx_data, + &cmd_mem_region, true); + if (rc) { + CAM_ERR(CAM_ICP, + "sending config io mapping failed rc %d", rc); + goto send_map_info_failed; + } + + rc = cam_icp_mgr_send_config_io(ctx_data, io_buf_addr); + if (rc) { + CAM_ERR(CAM_ICP, "IO Config command failed %d", rc); + cam_icp_dump_io_cfg(ctx_data, + icp_dev_acquire_info->io_config_cmd_handle); + goto ioconfig_failed; + } + + rc = cam_icp_process_stream_settings(ctx_data, + &cmd_mem_region, false); + if (rc) { + CAM_ERR(CAM_ICP, + "sending config io unmapping failed %d", rc); + goto send_map_info_failed; + } + + ctx_data->context_priv = args->context_data; + args->ctxt_to_hw_map = ctx_data; + + bitmap_size = BITS_TO_LONGS(CAM_FRAME_CMD_MAX) * sizeof(long); + ctx_data->hfi_frame_process.bitmap = + kzalloc(bitmap_size, GFP_KERNEL); + if (!ctx_data->hfi_frame_process.bitmap) + goto ioconfig_failed; + + ctx_data->hfi_frame_process.bits = bitmap_size * BITS_PER_BYTE; + hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb; + icp_dev_acquire_info->scratch_mem_size = ctx_data->scratch_mem_size; + + if (copy_to_user((void __user *)args->acquire_info, + icp_dev_acquire_info, sizeof(struct cam_icp_acquire_dev_info))) + goto copy_to_user_failed; + + cam_icp_ctx_clk_info_init(ctx_data); + ctx_data->state = CAM_ICP_CTX_STATE_ACQUIRED; + mutex_unlock(&ctx_data->ctx_mutex); + CAM_DBG(CAM_ICP, "scratch size = %x fw_handle = %x", + (unsigned int)icp_dev_acquire_info->scratch_mem_size, + (unsigned int)ctx_data->fw_handle); + /* Start device timer*/ + if (((hw_mgr->bps_ctxt_cnt == 1) || (hw_mgr->ipe_ctxt_cnt == 1))) + cam_icp_device_timer_start(hw_mgr); + /* Start context timer*/ + cam_icp_ctx_timer_start(ctx_data); + hw_mgr->ctxt_cnt++; + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev type %d", + ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type); + + return 0; + +copy_to_user_failed: + kfree(ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.bitmap = NULL; +ioconfig_failed: + cam_icp_process_stream_settings(ctx_data, + &cmd_mem_region, false); +send_map_info_failed: + cam_icp_mgr_destroy_handle(ctx_data); +create_handle_failed: +send_ping_failed: + cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, ctx_data, 0); +ipe_bps_resume_failed: +ubwc_cfg_failed: + if (!hw_mgr->ctxt_cnt) + cam_icp_mgr_icp_power_collapse(hw_mgr); +get_io_buf_failed: + kfree(hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info); + hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL; +acquire_info_failed: + cam_icp_mgr_put_ctx(ctx_data); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); + mutex_unlock(&ctx_data->ctx_mutex); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) +{ + int rc = 0; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query_cap = hw_caps_args; + + if ((!hw_mgr_priv) || (!hw_caps_args)) { + CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", + hw_mgr_priv, hw_caps_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (copy_from_user(&icp_hw_mgr.icp_caps, + u64_to_user_ptr(query_cap->caps_handle), + sizeof(struct cam_icp_query_cap_cmd))) { + CAM_ERR(CAM_ICP, "copy_from_user failed"); + rc = -EFAULT; + goto end; + } + + rc = hfi_get_hw_caps(&icp_hw_mgr.icp_caps); + if (rc) + goto end; + + icp_hw_mgr.icp_caps.dev_iommu_handle.non_secure = hw_mgr->iommu_hdl; + icp_hw_mgr.icp_caps.dev_iommu_handle.secure = hw_mgr->iommu_sec_hdl; + + if (copy_to_user(u64_to_user_ptr(query_cap->caps_handle), + &icp_hw_mgr.icp_caps, sizeof(struct cam_icp_query_cap_cmd))) { + CAM_ERR(CAM_ICP, "copy_to_user failed"); + rc = -EFAULT; + } +end: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_icp_mgr_alloc_devs(struct device_node *of_node) +{ + int rc; + uint32_t num_dev; + + rc = of_property_read_u32(of_node, "num-a5", &num_dev); + if (rc) { + CAM_ERR(CAM_ICP, "getting num of a5 failed"); + goto num_a5_failed; + } + + icp_hw_mgr.devices[CAM_ICP_DEV_A5] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_A5]) { + rc = -ENOMEM; + goto num_a5_failed; + } + + rc = of_property_read_u32(of_node, "num-ipe", &num_dev); + if (rc) { + CAM_ERR(CAM_ICP, "getting number of ipe dev nodes failed"); + goto num_ipe_failed; + } + + if (!icp_hw_mgr.ipe1_enable) + num_dev = 1; + + icp_hw_mgr.devices[CAM_ICP_DEV_IPE] = kcalloc(num_dev, + sizeof(struct cam_hw_intf *), GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_IPE]) { + rc = -ENOMEM; + goto num_ipe_failed; + } + + rc = of_property_read_u32(of_node, "num-bps", &num_dev); + if (rc) { + CAM_ERR(CAM_ICP, "read num bps devices failed"); + goto num_bps_failed; + } + icp_hw_mgr.devices[CAM_ICP_DEV_BPS] = kcalloc(num_dev, + sizeof(struct cam_hw_intf *), GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_BPS]) { + rc = -ENOMEM; + goto num_bps_failed; + } + + icp_hw_mgr.ipe_bps_pc_flag = of_property_read_bool(of_node, + "ipe_bps_pc_en"); + + icp_hw_mgr.icp_pc_flag = of_property_read_bool(of_node, + "icp_pc_en"); + + return 0; +num_bps_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]); +num_ipe_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]); +num_a5_failed: + return rc; +} + +static int cam_icp_mgr_init_devs(struct device_node *of_node) +{ + int rc = 0; + int count, i; + const char *name = NULL; + struct device_node *child_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *child_dev_intf = NULL; + + rc = cam_icp_mgr_alloc_devs(of_node); + if (rc) + return rc; + + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count) { + CAM_ERR(CAM_ICP, "no compat hw found in dev tree, cnt = %d", + count); + rc = -EINVAL; + goto compat_hw_name_failed; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "compat-hw-name", + i, &name); + if (rc) { + CAM_ERR(CAM_ICP, "getting dev object name failed"); + goto compat_hw_name_failed; + } + + child_node = of_find_node_by_name(NULL, name); + if (!child_node) { + CAM_ERR(CAM_ICP, "Cannot find node in dtsi %s", name); + rc = -ENODEV; + goto compat_hw_name_failed; + } + + child_pdev = of_find_device_by_node(child_node); + if (!child_pdev) { + CAM_ERR(CAM_ICP, "failed to find device on bus %s", + child_node->name); + rc = -ENODEV; + of_node_put(child_node); + goto compat_hw_name_failed; + } + + child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata( + child_pdev); + if (!child_dev_intf) { + CAM_ERR(CAM_ICP, "no child device"); + of_node_put(child_node); + if (!icp_hw_mgr.ipe1_enable) + continue; + goto compat_hw_name_failed; + } + icp_hw_mgr.devices[child_dev_intf->hw_type] + [child_dev_intf->hw_idx] = child_dev_intf; + + if (!child_dev_intf->hw_ops.process_cmd) + goto compat_hw_name_failed; + + of_node_put(child_node); + } + + icp_hw_mgr.a5_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_A5][0]; + icp_hw_mgr.bps_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_BPS][0]; + icp_hw_mgr.ipe0_dev_intf = icp_hw_mgr.devices[CAM_ICP_DEV_IPE][0]; + if (icp_hw_mgr.ipe1_enable) + icp_hw_mgr.ipe1_dev_intf = + icp_hw_mgr.devices[CAM_ICP_DEV_IPE][1]; + + return 0; +compat_hw_name_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]); + return rc; +} + +static int cam_icp_mgr_create_wq(void) +{ + int rc; + int i; + + rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK, + &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, + 0); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a command worker"); + goto cmd_work_failed; + } + + rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK, + &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a message worker"); + goto msg_work_failed; + } + + rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK, + &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a timer worker"); + goto timer_work_failed; + } + + icp_hw_mgr.cmd_work_data = + kzalloc(sizeof(struct hfi_cmd_work_data) * ICP_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!icp_hw_mgr.cmd_work_data) + goto cmd_work_data_failed; + + icp_hw_mgr.msg_work_data = + kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!icp_hw_mgr.msg_work_data) + goto msg_work_data_failed; + + icp_hw_mgr.timer_work_data = + kzalloc(sizeof(struct hfi_msg_work_data) * ICP_WORKQ_NUM_TASK, + GFP_KERNEL); + if (!icp_hw_mgr.timer_work_data) + goto timer_work_data_failed; + + rc = cam_icp_hw_mgr_create_debugfs_entry(); + if (rc) + goto debugfs_create_failed; + + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) + icp_hw_mgr.msg_work->task.pool[i].payload = + &icp_hw_mgr.msg_work_data[i]; + + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) + icp_hw_mgr.cmd_work->task.pool[i].payload = + &icp_hw_mgr.cmd_work_data[i]; + + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) + icp_hw_mgr.timer_work->task.pool[i].payload = + &icp_hw_mgr.timer_work_data[i]; + return 0; + +debugfs_create_failed: + kfree(icp_hw_mgr.timer_work_data); +timer_work_data_failed: + kfree(icp_hw_mgr.msg_work_data); +msg_work_data_failed: + kfree(icp_hw_mgr.cmd_work_data); +cmd_work_data_failed: + cam_req_mgr_workq_destroy(&icp_hw_mgr.timer_work); +timer_work_failed: + cam_req_mgr_workq_destroy(&icp_hw_mgr.msg_work); +msg_work_failed: + cam_req_mgr_workq_destroy(&icp_hw_mgr.cmd_work); +cmd_work_failed: + return rc; +} + +static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_icp_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + + break; + default: + CAM_ERR(CAM_ICP, "Invalid cmd"); + } + + return rc; +} + +int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, + int *iommu_hdl) +{ + int i, rc = 0; + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_cpas_query_cap query; + uint32_t cam_caps, camera_hw_version; + + hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl; + if (!of_node || !hw_mgr_intf) { + CAM_ERR(CAM_ICP, "Invalid args of_node %pK hw_mgr %pK", + of_node, hw_mgr_intf); + return -EINVAL; + } + + hw_mgr_intf->hw_mgr_priv = &icp_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_icp_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_icp_mgr_acquire_hw; + hw_mgr_intf->hw_release = cam_icp_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_icp_mgr_prepare_hw_update; + hw_mgr_intf->hw_config_stream_settings = + cam_icp_mgr_config_stream_settings; + hw_mgr_intf->hw_config = cam_icp_mgr_config_hw; + hw_mgr_intf->hw_open = cam_icp_mgr_hw_open_u; + hw_mgr_intf->hw_close = cam_icp_mgr_hw_close_u; + hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush; + hw_mgr_intf->hw_cmd = cam_icp_mgr_cmd; + + icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE; + mutex_init(&icp_hw_mgr.hw_mgr_mutex); + spin_lock_init(&icp_hw_mgr.hw_mgr_lock); + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) + mutex_init(&icp_hw_mgr.ctx_data[i].ctx_mutex); + + cam_cpas_get_hw_info(&query.camera_family, + &query.camera_version, &query.cpas_version, &cam_caps); + cam_cpas_get_cpas_hw_version(&camera_hw_version); + + if (camera_hw_version == CAM_CPAS_TITAN_480_V100) { + if (cam_caps & CPAS_TITAN_480_IPE0_BIT) + icp_hw_mgr.ipe0_enable = true; + if (cam_caps & CPAS_BPS_BIT) + icp_hw_mgr.bps_enable = true; + } else { + if (cam_caps & CPAS_IPE0_BIT) + icp_hw_mgr.ipe0_enable = true; + if (cam_caps & CPAS_IPE1_BIT) + icp_hw_mgr.ipe1_enable = true; + if (cam_caps & CPAS_BPS_BIT) + icp_hw_mgr.bps_enable = true; + } + + rc = cam_icp_mgr_init_devs(of_node); + if (rc) + goto dev_init_failed; + + rc = cam_smmu_get_handle("icp", &icp_hw_mgr.iommu_hdl); + if (rc) { + CAM_ERR(CAM_ICP, "get mmu handle failed: %d", rc); + goto icp_get_hdl_failed; + } + + rc = cam_smmu_get_handle("cam-secure", &icp_hw_mgr.iommu_sec_hdl); + if (rc) { + CAM_ERR(CAM_ICP, "get secure mmu handle failed: %d", rc); + goto secure_hdl_failed; + } + + rc = cam_icp_mgr_create_wq(); + if (rc) + goto icp_wq_create_failed; + + if (iommu_hdl) + *iommu_hdl = icp_hw_mgr.iommu_hdl; + + init_completion(&icp_hw_mgr.a5_complete); + return rc; + +icp_wq_create_failed: + cam_smmu_destroy_handle(icp_hw_mgr.iommu_sec_hdl); + icp_hw_mgr.iommu_sec_hdl = -1; +secure_hdl_failed: + cam_smmu_destroy_handle(icp_hw_mgr.iommu_hdl); + icp_hw_mgr.iommu_hdl = -1; +icp_get_hdl_failed: + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_BPS]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_IPE]); + kfree(icp_hw_mgr.devices[CAM_ICP_DEV_A5]); +dev_init_failed: + mutex_destroy(&icp_hw_mgr.hw_mgr_mutex); + for (i = 0; i < CAM_ICP_CTX_MAX; i++) + mutex_destroy(&icp_hw_mgr.ctx_data[i].ctx_mutex); + + return rc; +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..b118471823cd8d71563175b481276105c77ade43 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_ICP_HW_MGR_H +#define CAM_ICP_HW_MGR_H + +#include <linux/types.h> +#include <linux/completion.h> +#include <media/cam_icp.h> +#include "cam_icp_hw_intf.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_a5_hw_intf.h" +#include "hfi_session_defs.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "cam_smmu_api.h" +#include "cam_soc_util.h" +#include "cam_req_mgr_timer.h" + +#define CAM_ICP_ROLE_PARENT 1 +#define CAM_ICP_ROLE_CHILD 2 + +#define CAM_FRAME_CMD_MAX 20 + +#define CAM_MAX_OUT_RES 6 +#define CAM_MAX_IN_RES 8 + +#define ICP_WORKQ_NUM_TASK 100 +#define ICP_WORKQ_TASK_CMD_TYPE 1 +#define ICP_WORKQ_TASK_MSG_TYPE 2 + +#define ICP_PACKET_SIZE 0 +#define ICP_PACKET_TYPE 1 +#define ICP_PACKET_OPCODE 2 +#define ICP_MAX_OUTPUT_SUPPORTED 6 + +#define ICP_FRAME_PROCESS_SUCCESS 0 +#define ICP_FRAME_PROCESS_FAILURE 1 +#define ICP_MSG_BUF_SIZE 256 +#define ICP_DBG_BUF_SIZE 102400 + +#define ICP_CLK_HW_IPE 0x0 +#define ICP_CLK_HW_BPS 0x1 +#define ICP_CLK_HW_MAX 0x2 + +#define ICP_OVER_CLK_THRESHOLD 5 + +#define CPAS_IPE0_BIT 0x1000 +#define CPAS_IPE1_BIT 0x2000 +#define CPAS_BPS_BIT 0x400 +#define CPAS_TITAN_480_IPE0_BIT 0x800 + +#define ICP_PWR_CLP_BPS 0x00000001 +#define ICP_PWR_CLP_IPE0 0x00010000 +#define ICP_PWR_CLP_IPE1 0x00020000 + +#define CAM_ICP_CTX_STATE_FREE 0x0 +#define CAM_ICP_CTX_STATE_IN_USE 0x1 +#define CAM_ICP_CTX_STATE_ACQUIRED 0x2 +#define CAM_ICP_CTX_STATE_RELEASE 0x3 + +#define CAM_ICP_CTX_MAX_CMD_BUFFERS 0x2 + +/* Current appliacble vote paths, based on number of UAPI definitions */ +#define CAM_ICP_MAX_PER_PATH_VOTES 6 + +/** + * struct icp_hfi_mem_info + * @qtbl: Memory info of queue table + * @cmd_q: Memory info of command queue + * @msg_q: Memory info of message queue + * @dbg_q: Memory info of debug queue + * @sec_heap: Memory info of secondary heap + * @fw_buf: Memory info of firmware + * @qdss_buf: Memory info of qdss + * @sfr_buf: Memory info for sfr buffer + * @shmem: Memory info for shared region + * @io_mem: Memory info for io region + */ +struct icp_hfi_mem_info { + struct cam_mem_mgr_memory_desc qtbl; + struct cam_mem_mgr_memory_desc cmd_q; + struct cam_mem_mgr_memory_desc msg_q; + struct cam_mem_mgr_memory_desc dbg_q; + struct cam_mem_mgr_memory_desc sec_heap; + struct cam_mem_mgr_memory_desc fw_buf; + struct cam_mem_mgr_memory_desc qdss_buf; + struct cam_mem_mgr_memory_desc sfr_buf; + struct cam_smmu_region_info shmem; + struct cam_smmu_region_info io_mem; +}; + +/** + * struct hfi_cmd_work_data + * @type: Task type + * @data: Pointer to command data + * @request_id: Request id + */ +struct hfi_cmd_work_data { + uint32_t type; + void *data; + int32_t request_id; +}; + +/** + * struct hfi_msg_work_data + * @type: Task type + * @data: Pointer to message data + * @irq_status: IRQ status + */ +struct hfi_msg_work_data { + uint32_t type; + void *data; + uint32_t irq_status; +}; + +/** + * struct clk_work_data + * @type: Task type + * @data: Pointer to clock info + */ +struct clk_work_data { + uint32_t type; + void *data; +}; + +/* + * struct icp_frame_info + * @request_id: request id + * @io_config: the address of io config + * @hfi_cfg_io_cmd: command struct to be sent to hfi + */ +struct icp_frame_info { + uint64_t request_id; + dma_addr_t io_config; + struct hfi_cmd_ipebps_async hfi_cfg_io_cmd; +}; + +/** + * struct cam_icp_clk_bw_request_v2 + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: Reserved filed. + * @num_paths: Number of paths for per path bw vote + * @axi_path: Per path vote info for IPE/BPS + */ +struct cam_icp_clk_bw_req_internal_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; +}; + +/** + * struct hfi_frame_process_info + * @hfi_frame_cmd: Frame process command info + * @bitmap: Bitmap for hfi_frame_cmd + * @bits: Used in hfi_frame_cmd bitmap + * @lock: Lock for hfi_frame_cmd + * @request_id: Request id list + * @num_out_resources: Number of out syncs + * @out_resource: Out sync info + * @fw_process_flag: Frame process flag + * @clk_info: Clock information for a request + * @clk_info_v2: Clock info for AXI bw voting v2 + * @frame_info: information needed to process request + */ +struct hfi_frame_process_info { + struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; + void *bitmap; + size_t bits; + struct mutex lock; + uint64_t request_id[CAM_FRAME_CMD_MAX]; + uint32_t num_out_resources[CAM_FRAME_CMD_MAX]; + uint32_t out_resource[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES]; + uint32_t in_resource[CAM_FRAME_CMD_MAX]; + uint32_t in_free_resource[CAM_FRAME_CMD_MAX]; + uint32_t fw_process_flag[CAM_FRAME_CMD_MAX]; + struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; + struct cam_icp_clk_bw_req_internal_v2 clk_info_v2[CAM_FRAME_CMD_MAX]; + struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; +}; + +/** + * struct cam_ctx_clk_info + * @curr_fc: Context latest request frame cycles + * @rt_flag: Flag to indicate real time request + * @base_clk: Base clock to process the request + * @reserved: Reserved field + * #uncompressed_bw: Current bandwidth voting + * @compressed_bw: Current compressed bandwidth voting + * @clk_rate: Supported clock rates for the context + * @num_paths: Number of valid AXI paths + * @axi_path: ctx based per path bw vote + * @bw_included: Whether bw of this context is included in overal voting + */ +struct cam_ctx_clk_info { + uint32_t curr_fc; + uint32_t rt_flag; + uint32_t base_clk; + uint32_t reserved; + uint64_t uncompressed_bw; + uint64_t compressed_bw; + int32_t clk_rate[CAM_MAX_VOTE]; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; + bool bw_included; +}; +/** + * struct cam_icp_hw_ctx_data + * @context_priv: Context private data + * @ctx_mutex: Mutex for context + * @fw_handle: Firmware handle + * @scratch_mem_size: Scratch memory size + * @acquire_dev_cmd: Acquire command + * @icp_dev_acquire_info: Acquire device info + * @ctxt_event_cb: Context callback function + * @state: context state + * @role: Role of a context in case of chaining + * @chain_ctx: Peer context + * @hfi_frame_process: Frame process command + * @wait_complete: Completion info + * @temp_payload: Payload for destroy handle data + * @ctx_id: Context Id + * @bw_config_version: BW config version indicator + * @clk_info: Current clock info of a context + * @watch_dog: watchdog timer handle + * @watch_dog_reset_counter: Counter for watch dog reset + * @icp_dev_io_info: io config resource + * @last_flush_req: last flush req for this ctx + */ +struct cam_icp_hw_ctx_data { + void *context_priv; + struct mutex ctx_mutex; + uint32_t fw_handle; + uint32_t scratch_mem_size; + struct cam_acquire_dev_cmd acquire_dev_cmd; + struct cam_icp_acquire_dev_info *icp_dev_acquire_info; + cam_hw_event_cb_func ctxt_event_cb; + uint32_t state; + uint32_t role; + struct cam_icp_hw_ctx_data *chain_ctx; + struct hfi_frame_process_info hfi_frame_process; + struct completion wait_complete; + struct ipe_bps_destroy temp_payload; + uint32_t ctx_id; + uint32_t bw_config_version; + struct cam_ctx_clk_info clk_info; + struct cam_req_mgr_timer *watch_dog; + uint32_t watch_dog_reset_counter; + struct cam_icp_acquire_dev_info icp_dev_io_info; + uint64_t last_flush_req; +}; + +/** + * struct icp_cmd_generic_blob + * @ctx: Current context info + * @frame_info_idx: Index used for frame process info + * @io_buf_addr: pointer to io buffer address + */ +struct icp_cmd_generic_blob { + struct cam_icp_hw_ctx_data *ctx; + uint32_t frame_info_idx; + dma_addr_t *io_buf_addr; +}; + +/** + * struct cam_icp_clk_info + * @base_clk: Base clock to process request + * @curr_clk: Current clock of hadrware + * @threshold: Threshold for overclk count + * @over_clked: Over clock count + * @uncompressed_bw: Current bandwidth voting + * @compressed_bw: Current compressed bandwidth voting + * @num_paths: Number of AXI vote paths + * @axi_path: Current per path bw vote info + * @hw_type: IPE/BPS device type + * @watch_dog: watchdog timer handle + * @watch_dog_reset_counter: Counter for watch dog reset + */ +struct cam_icp_clk_info { + uint32_t base_clk; + uint32_t curr_clk; + uint32_t threshold; + uint32_t over_clked; + uint64_t uncompressed_bw; + uint64_t compressed_bw; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ICP_MAX_PER_PATH_VOTES]; + uint32_t hw_type; + struct cam_req_mgr_timer *watch_dog; + uint32_t watch_dog_reset_counter; +}; + +/** + * struct cam_icp_hw_mgr + * @hw_mgr_mutex: Mutex for ICP hardware manager + * @hw_mgr_lock: Spinlock for ICP hardware manager + * @devices: Devices of ICP hardware manager + * @ctx_data: Context data + * @icp_caps: ICP capabilities + * @fw_download: Firmware download state + * @iommu_hdl: Non secure IOMMU handle + * @iommu_sec_hdl: Secure IOMMU handle + * @hfi_mem: Memory for hfi + * @cmd_work: Work queue for hfi commands + * @msg_work: Work queue for hfi messages + * @timer_work: Work queue for timer watchdog + * @msg_buf: Buffer for message data from firmware + * @dbg_buf: Buffer for debug data from firmware + * @a5_complete: Completion info + * @cmd_work_data: Pointer to command work queue task + * @msg_work_data: Pointer to message work queue task + * @timer_work_data: Pointer to timer work queue task + * @ctxt_cnt: Active context count + * @ipe_ctxt_cnt: IPE Active context count + * @bps_ctxt_cnt: BPS Active context count + * @dentry: Debugfs entry + * @a5_debug: A5 debug flag + * @icp_pc_flag: Flag to enable/disable power collapse + * @ipe_bps_pc_flag: Flag to enable/disable + * power collapse for ipe & bps + * @icp_debug_clk: Set clock based on debug value + * @icp_default_clk: Set this clok if user doesn't supply + * @clk_info: Clock info of hardware + * @secure_mode: Flag to enable/disable secure camera + * @a5_jtag_debug: entry to enable A5 JTAG debugging + * @a5_debug_type : entry to enable FW debug message/qdss + * @a5_dbg_lvl : debug level set to FW. + * @a5_fw_dump_lvl : level set for dumping the FW data + * @ipe0_enable: Flag for IPE0 + * @ipe1_enable: Flag for IPE1 + * @bps_enable: Flag for BPS + * @a5_dev_intf : Device interface for A5 + * @ipe0_dev_intf: Device interface for IPE0 + * @ipe1_dev_intf: Device interface for IPE1 + * @bps_dev_intf: Device interface for BPS + * @ipe_clk_state: IPE clock state flag + * @bps_clk_state: BPS clock state flag + * @recovery: Flag to validate if in previous session FW + * reported a fatal error or wdt. If set FW is + * re-downloaded for new camera session. + */ +struct cam_icp_hw_mgr { + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_lock; + + struct cam_hw_intf **devices[CAM_ICP_DEV_MAX]; + struct cam_icp_hw_ctx_data ctx_data[CAM_ICP_CTX_MAX]; + struct cam_icp_query_cap_cmd icp_caps; + + bool fw_download; + int32_t iommu_hdl; + int32_t iommu_sec_hdl; + struct icp_hfi_mem_info hfi_mem; + struct cam_req_mgr_core_workq *cmd_work; + struct cam_req_mgr_core_workq *msg_work; + struct cam_req_mgr_core_workq *timer_work; + uint32_t msg_buf[ICP_MSG_BUF_SIZE]; + uint32_t dbg_buf[ICP_DBG_BUF_SIZE]; + struct completion a5_complete; + struct hfi_cmd_work_data *cmd_work_data; + struct hfi_msg_work_data *msg_work_data; + struct hfi_msg_work_data *timer_work_data; + uint32_t ctxt_cnt; + uint32_t ipe_ctxt_cnt; + uint32_t bps_ctxt_cnt; + struct dentry *dentry; + bool a5_debug; + bool icp_pc_flag; + bool ipe_bps_pc_flag; + uint64_t icp_debug_clk; + uint64_t icp_default_clk; + struct cam_icp_clk_info clk_info[ICP_CLK_HW_MAX]; + bool secure_mode; + bool a5_jtag_debug; + u64 a5_debug_type; + u64 a5_dbg_lvl; + u64 a5_fw_dump_lvl; + bool ipe0_enable; + bool ipe1_enable; + bool bps_enable; + struct cam_hw_intf *a5_dev_intf; + struct cam_hw_intf *ipe0_dev_intf; + struct cam_hw_intf *ipe1_dev_intf; + struct cam_hw_intf *bps_dev_intf; + bool ipe_clk_state; + bool bps_clk_state; + atomic_t recovery; +}; + +static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args); +static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args); +static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr); +static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr); +#endif /* CAM_ICP_HW_MGR_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..af80a2eac15d1f612ad3b27b7ab0b7f829ed7c89 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_A5_HW_INTF_H +#define CAM_A5_HW_INTF_H + +#include <linux/timer.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +enum cam_icp_a5_cmd_type { + CAM_ICP_A5_CMD_FW_DOWNLOAD, + CAM_ICP_A5_CMD_POWER_COLLAPSE, + CAM_ICP_A5_CMD_POWER_RESUME, + CAM_ICP_A5_CMD_SET_FW_BUF, + CAM_ICP_A5_CMD_ACQUIRE, + CAM_ICP_A5_SET_IRQ_CB, + CAM_ICP_A5_TEST_IRQ, + CAM_ICP_A5_SEND_INIT, + CAM_ICP_A5_CMD_VOTE_CPAS, + CAM_ICP_A5_CMD_CPAS_START, + CAM_ICP_A5_CMD_CPAS_STOP, + CAM_ICP_A5_CMD_UBWC_CFG, + CAM_ICP_A5_CMD_PC_PREP, + CAM_ICP_A5_CMD_CLK_UPDATE, + CAM_ICP_A5_CMD_MAX, +}; + +struct cam_icp_a5_set_fw_buf_info { + uint32_t iova; + uint64_t kva; + uint64_t len; +}; + +/** + * struct cam_icp_a5_query_cap - ICP query device capability payload + * @fw_version: firmware version info + * @api_version: api version info + * @num_ipe: number of ipes + * @num_bps: number of bps + * @num_dev: number of device capabilities in dev_caps + * @reserved: reserved + * @dev_ver: returned device capability array + * @CAM_QUERY_CAP IOCTL + */ +struct cam_icp_a5_query_cap { + struct cam_icp_ver fw_version; + struct cam_icp_ver api_version; + uint32_t num_ipe; + uint32_t num_bps; + uint32_t num_dev; + uint32_t reserved; + struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX]; +}; + +struct cam_icp_a5_acquire_dev { + uint32_t ctx_id; + struct cam_icp_acquire_dev_info icp_acquire_info; + struct cam_icp_res_info icp_out_acquire_info[2]; + uint32_t fw_handle; +}; + +struct cam_icp_a5_set_irq_cb { + int32_t (*icp_hw_mgr_cb)(uint32_t irq_status, void *data); + void *data; +}; + +struct cam_icp_a5_test_irq { + uint32_t test_irq; +}; +#endif /* CAM_A5_HW_INTF_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..f2628e41640b757d75000b93f045f5fb62511759 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_BPS_HW_INTF_H +#define CAM_BPS_HW_INTF_H + +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +/* BPS register */ +#define BPS_TOP_RST_CMD 0x1008 +#define BPS_CDM_RST_CMD 0x10 +#define BPS_CDM_IRQ_STATUS 0x44 +#define BPS_TOP_IRQ_STATUS 0x100C + +/* BPS CDM/TOP status register */ +#define BPS_RST_DONE_IRQ_STATUS_BIT 0x1 + +enum cam_icp_bps_cmd_type { + CAM_ICP_BPS_CMD_FW_DOWNLOAD, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + CAM_ICP_BPS_CMD_POWER_RESUME, + CAM_ICP_BPS_CMD_SET_FW_BUF, + CAM_ICP_BPS_CMD_VOTE_CPAS, + CAM_ICP_BPS_CMD_CPAS_START, + CAM_ICP_BPS_CMD_CPAS_STOP, + CAM_ICP_BPS_CMD_UPDATE_CLK, + CAM_ICP_BPS_CMD_DISABLE_CLK, + CAM_ICP_BPS_CMD_RESET, + CAM_ICP_BPS_CMD_MAX, +}; + +#endif /* CAM_BPS_HW_INTF_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..80a724b53d9479bbb351def8e7a975465de12481 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_ICP_HW_INTF_H +#define CAM_ICP_HW_INTF_H + +#define CAM_ICP_CMD_BUF_MAX_SIZE 128 +#define CAM_ICP_MSG_BUF_MAX_SIZE CAM_ICP_CMD_BUF_MAX_SIZE + +#define CAM_ICP_BW_CONFIG_UNKNOWN 0 +#define CAM_ICP_BW_CONFIG_V1 1 +#define CAM_ICP_BW_CONFIG_V2 2 + +enum cam_a5_hw_type { + CAM_ICP_DEV_A5, + CAM_ICP_DEV_IPE, + CAM_ICP_DEV_BPS, + CAM_ICP_DEV_MAX, +}; + +/** + * struct cam_a5_clk_update_cmd - Payload for hw manager command + * + * @curr_clk_rate: clk rate to HW + * @ipe_bps_pc_enable power collpase enable flag + * @clk_level: clk level corresponding to the clk rate + * populated as output while the clk is being + * updated to the given rate + */ +struct cam_a5_clk_update_cmd { + uint32_t curr_clk_rate; + bool ipe_bps_pc_enable; + int32_t clk_level; +}; + +#endif diff --git a/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..ea14ee623fb3b46fbd079f2bf47170fe53ad6d65 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_IPE_HW_INTF_H +#define CAM_IPE_HW_INTF_H + +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +/* IPE registers */ +#define IPE_TOP_RST_CMD 0x1008 +#define IPE_CDM_RST_CMD 0x10 +#define IPE_CDM_IRQ_STATUS 0x44 +#define IPE_TOP_IRQ_STATUS 0x100C + +/* IPE CDM/TOP status register */ +#define IPE_RST_DONE_IRQ_STATUS_BIT 0x1 + +enum cam_icp_ipe_cmd_type { + CAM_ICP_IPE_CMD_FW_DOWNLOAD, + CAM_ICP_IPE_CMD_POWER_COLLAPSE, + CAM_ICP_IPE_CMD_POWER_RESUME, + CAM_ICP_IPE_CMD_SET_FW_BUF, + CAM_ICP_IPE_CMD_VOTE_CPAS, + CAM_ICP_IPE_CMD_CPAS_START, + CAM_ICP_IPE_CMD_CPAS_STOP, + CAM_ICP_IPE_CMD_UPDATE_CLK, + CAM_ICP_IPE_CMD_DISABLE_CLK, + CAM_ICP_IPE_CMD_RESET, + CAM_ICP_IPE_CMD_MAX, +}; + +#endif /* CAM_IPE_HW_INTF_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/techpack/camera/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..d87c7ef238df474c8529d9fe444b6a71e56b04a3 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_ICP_HW_MGR_INTF_H +#define CAM_ICP_HW_MGR_INTF_H + +#include <linux/of.h> +#include <media/cam_icp.h> +#include <media/cam_defs.h> +#include "cam_cpas_api.h" + +#define ICP_CLK_TURBO_HZ 600000000 +#define ICP_CLK_SVS_HZ 400000000 + +#define CAM_ICP_A5_BW_BYTES_VOTE 40000000 + +#define CAM_ICP_CTX_MAX 54 + +#define CPAS_IPE1_BIT 0x2000 + +#define CAM_IPE_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_IPE_WR_VID +#define CAM_IPE_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_WRITE +#define CAM_BPS_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL +#define CAM_BPS_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_WRITE +#define CAM_ICP_DEFAULT_AXI_PATH CAM_AXI_PATH_DATA_ALL +#define CAM_ICP_DEFAULT_AXI_TRANSAC CAM_AXI_TRANSACTION_READ + +int cam_icp_hw_mgr_init(struct device_node *of_node, + uint64_t *hw_mgr_hdl, int *iommu_hdl); + +/** + * struct cam_icp_cpas_vote + * @ahb_vote: AHB vote info + * @axi_vote: AXI vote info + * @ahb_vote_valid: Flag for ahb vote data + * @axi_vote_valid: flag for axi vote data + */ +struct cam_icp_cpas_vote { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote; + uint32_t ahb_vote_valid; + uint32_t axi_vote_valid; +}; + +#endif /* CAM_ICP_HW_MGR_INTF_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/Makefile b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d57373c332e0158e66c25acc0aa26d957a895d06 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_icp/fw_inc +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += ipe_dev.o ipe_core.o ipe_soc.o diff --git a/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c new file mode 100644 index 0000000000000000000000000000000000000000..4263cf7ea669a4b312cc03901f15d7019b846032 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/iopoll.h> +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "ipe_core.h" +#include "ipe_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_ipe_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 + +static int cam_ipe_cpas_vote(struct cam_ipe_device_core_info *core_info, + struct cam_icp_cpas_vote *cpas_vote) +{ + int rc = 0; + + if (cpas_vote->ahb_vote_valid) + rc = cam_cpas_update_ahb_vote(core_info->cpas_handle, + &cpas_vote->ahb_vote); + if (cpas_vote->axi_vote_valid) + rc = cam_cpas_update_axi_vote(core_info->cpas_handle, + &cpas_vote->axi_vote); + + if (rc) + CAM_ERR(CAM_PERF, "cpas vote is failed: %d", rc); + + return rc; +} + +int cam_ipe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *ipe_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_icp_cpas_vote cpas_vote; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE; + cpas_vote.axi_vote.num_paths = 1; + cpas_vote.axi_vote.axi_path[0].path_data_type = + CAM_IPE_DEFAULT_AXI_PATH; + cpas_vote.axi_vote.axi_path[0].transac_type = + CAM_IPE_DEFAULT_AXI_TRANSAC; + cpas_vote.axi_vote.axi_path[0].camnoc_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ab_bw = + CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.axi_path[0].ddr_ib_bw = + CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote.ahb_vote, &cpas_vote.axi_vote); + if (rc) { + CAM_ERR(CAM_ICP, "cpas start failed: %d", rc); + goto error; + } + core_info->cpas_start = true; + + rc = cam_ipe_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ICP, "soc enable is failed : %d", rc); + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } else { + core_info->clk_enable = true; + } + +error: + return rc; +} + +int cam_ipe_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *ipe_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + if ((!soc_info) || (!core_info)) { + CAM_ERR(CAM_ICP, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + rc = cam_ipe_disable_soc_resources(soc_info, core_info->clk_enable); + if (rc) + CAM_ERR(CAM_ICP, "soc disable is failed : %d", rc); + core_info->clk_enable = false; + + if (core_info->cpas_start) { + if (cam_cpas_stop(core_info->cpas_handle)) + CAM_ERR(CAM_ICP, "cpas stop is failed"); + else + core_info->cpas_start = false; + } + + return rc; +} + +static int cam_ipe_handle_pc(struct cam_hw_info *ipe_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + hw_info = core_info->ipe_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + if (!(pwr_ctrl & IPE_COLLAPSE_MASK)) { + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x1); + + if (pwr_status >> IPE_PWR_ON_MASK) + CAM_WARN(CAM_PERF, "BPS: pwr_status(%x):pwr_ctrl(%x)", + pwr_status, pwr_ctrl); + + } + cam_ipe_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return 0; +} + +static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int pwr_ctrl; + int pwr_status; + int rc = 0; + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + hw_info = core_info->ipe_hw_info; + + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, + true, &pwr_ctrl); + if (pwr_ctrl & IPE_COLLAPSE_MASK) { + CAM_DBG(CAM_PERF, "IPE pwr_ctrl set(%x)", pwr_ctrl); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0); + } + + rc = cam_ipe_transfer_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_ctrl, true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_PERF, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + return rc; +} + +static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_ipe_device_core_info *core_info) +{ + int pwr_ctrl, pwr_status, rc = 0; + uint32_t status = 0, retry_cnt = 0; + bool reset_ipe_cdm_fail = false; + bool reset_ipe_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET"); + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_HFI, "IPE reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + + /* IPE CDM core reset*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_cdm_irq_status = %u", status); + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE CDM rst failed status 0x%x", status); + reset_ipe_cdm_fail = true; + } + + /* IPE reset*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + IPE_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_top_irq_status = %u", status); + + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE top rst failed status 0x%x", status); + reset_ipe_top_fail = true; + } + + cam_ipe_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After)pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_ipe_cdm_fail || reset_ipe_top_fail) + rc = -EAGAIN; + + return rc; +} + +int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *ipe_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int rc = 0; + + if (!device_priv) { + CAM_ERR(CAM_ICP, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_ICP_IPE_CMD_MAX) { + CAM_ERR(CAM_ICP, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + soc_info = &ipe_dev->soc_info; + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + hw_info = core_info->ipe_hw_info; + + switch (cmd_type) { + case CAM_ICP_IPE_CMD_VOTE_CPAS: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) + return -EINVAL; + + cam_ipe_cpas_vote(core_info, cpas_vote); + break; + } + + case CAM_ICP_IPE_CMD_CPAS_START: { + struct cam_icp_cpas_vote *cpas_vote = cmd_args; + + if (!cmd_args) + return -EINVAL; + + if (!core_info->cpas_start) { + rc = cam_cpas_start(core_info->cpas_handle, + &cpas_vote->ahb_vote, &cpas_vote->axi_vote); + core_info->cpas_start = true; + } + break; + } + + case CAM_ICP_IPE_CMD_CPAS_STOP: + if (core_info->cpas_start) { + cam_cpas_stop(core_info->cpas_handle); + core_info->cpas_start = false; + } + break; + case CAM_ICP_IPE_CMD_POWER_COLLAPSE: + rc = cam_ipe_handle_pc(ipe_dev); + break; + case CAM_ICP_IPE_CMD_POWER_RESUME: + rc = cam_ipe_handle_resume(ipe_dev); + break; + case CAM_ICP_IPE_CMD_UPDATE_CLK: { + struct cam_a5_clk_update_cmd *clk_upd_cmd = + (struct cam_a5_clk_update_cmd *)cmd_args; + struct cam_ahb_vote ahb_vote; + uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + int32_t clk_level = 0, err = 0; + + CAM_DBG(CAM_PERF, "ipe_src_clk rate = %d", (int)clk_rate); + if (!core_info->clk_enable) { + if (clk_upd_cmd->ipe_bps_pc_enable) { + cam_ipe_handle_pc(ipe_dev); + cam_cpas_reg_write(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, + hw_info->pwr_ctrl, true, 0x0); + } + rc = cam_ipe_toggle_clk(soc_info, true); + if (rc) + CAM_ERR(CAM_ICP, "Enable failed"); + else + core_info->clk_enable = true; + if (clk_upd_cmd->ipe_bps_pc_enable) { + rc = cam_ipe_handle_resume(ipe_dev); + if (rc) + CAM_ERR(CAM_ICP, "bps resume failed"); + } + } + CAM_DBG(CAM_PERF, "clock rate %d", clk_rate); + + rc = cam_ipe_update_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_PERF, "Failed to update clk %d", clk_rate); + + err = cam_soc_util_get_clk_level(soc_info, + clk_rate, soc_info->src_clk_idx, + &clk_level); + + if (!err) { + clk_upd_cmd->clk_level = clk_level; + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_level; + cam_cpas_update_ahb_vote( + core_info->cpas_handle, + &ahb_vote); + } + break; + } + case CAM_ICP_IPE_CMD_DISABLE_CLK: + if (core_info->clk_enable == true) + cam_ipe_toggle_clk(soc_info, false); + core_info->clk_enable = false; + break; + case CAM_ICP_IPE_CMD_RESET: + rc = cam_ipe_cmd_reset(soc_info, core_info); + break; + default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +irqreturn_t cam_ipe_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h new file mode 100644 index 0000000000000000000000000000000000000000..1a15e9233896f13887df181ea87f4c350eb7956a --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_core.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_IPE_CORE_H +#define CAM_IPE_CORE_H + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define IPE_COLLAPSE_MASK 0x1 +#define IPE_PWR_ON_MASK 0x2 + +struct cam_ipe_device_hw_info { + uint32_t hw_idx; + uint32_t pwr_ctrl; + uint32_t pwr_status; + uint32_t reserved; +}; + +struct cam_ipe_device_core_info { + struct cam_ipe_device_hw_info *ipe_hw_info; + uint32_t cpas_handle; + bool cpas_start; + bool clk_enable; +}; + +int cam_ipe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_ipe_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_ipe_irq(int irq_num, void *data); + +#endif /* CAM_IPE_CORE_H */ diff --git a/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..0390488d92b3d790eb32937cb942b28ec963a272 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_dev.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include <linux/timer.h> +#include "ipe_core.h" +#include "ipe_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_icp_hw_intf.h" +#include "cam_icp_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static struct cam_ipe_device_hw_info cam_ipe_hw_info[] = { + { + .hw_idx = 0, + .pwr_ctrl = 0x4c, + .pwr_status = 0x48, + .reserved = 0, + }, + { + .hw_idx = 1, + .pwr_ctrl = 0x54, + .pwr_status = 0x50, + .reserved = 0, + }, +}; +EXPORT_SYMBOL(cam_ipe_hw_info); + +static char ipe_dev_name[8]; + +int cam_ipe_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_ipe_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = &soc_info->pdev->dev; + memcpy(cpas_register_params.identifier, "ipe", sizeof("ipe")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +int cam_ipe_probe(struct platform_device *pdev) +{ + struct cam_hw_info *ipe_dev = NULL; + struct cam_hw_intf *ipe_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ipe_device_core_info *core_info = NULL; + struct cam_ipe_device_hw_info *hw_info = NULL; + int rc = 0; + struct cam_cpas_query_cap query; + uint32_t cam_caps; + uint32_t hw_idx; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); + + cam_cpas_get_hw_info(&query.camera_family, + &query.camera_version, &query.cpas_version, &cam_caps); + if ((!(cam_caps & CPAS_IPE1_BIT)) && (hw_idx)) { + CAM_ERR(CAM_ICP, "IPE1 hw idx = %d\n", hw_idx); + return -EINVAL; + } + + ipe_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!ipe_dev_intf) + return -ENOMEM; + + ipe_dev_intf->hw_idx = hw_idx; + ipe_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!ipe_dev) { + kfree(ipe_dev_intf); + return -ENOMEM; + } + + memset(ipe_dev_name, 0, sizeof(ipe_dev_name)); + snprintf(ipe_dev_name, sizeof(ipe_dev_name), + "ipe%1u", ipe_dev_intf->hw_idx); + + ipe_dev->soc_info.pdev = pdev; + ipe_dev->soc_info.dev = &pdev->dev; + ipe_dev->soc_info.dev_name = ipe_dev_name; + ipe_dev_intf->hw_priv = ipe_dev; + ipe_dev_intf->hw_ops.init = cam_ipe_init_hw; + ipe_dev_intf->hw_ops.deinit = cam_ipe_deinit_hw; + ipe_dev_intf->hw_ops.process_cmd = cam_ipe_process_cmd; + ipe_dev_intf->hw_type = CAM_ICP_DEV_IPE; + + CAM_DBG(CAM_ICP, "type %d index %d", + ipe_dev_intf->hw_type, + ipe_dev_intf->hw_idx); + + platform_set_drvdata(pdev, ipe_dev_intf); + + ipe_dev->core_info = kzalloc(sizeof(struct cam_ipe_device_core_info), + GFP_KERNEL); + if (!ipe_dev->core_info) { + kfree(ipe_dev); + kfree(ipe_dev_intf); + return -ENOMEM; + } + core_info = (struct cam_ipe_device_core_info *)ipe_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_DBG(CAM_ICP, "No ipe hardware info"); + kfree(ipe_dev->core_info); + kfree(ipe_dev); + kfree(ipe_dev_intf); + rc = -EINVAL; + return rc; + } + hw_info = &cam_ipe_hw_info[ipe_dev_intf->hw_idx]; + core_info->ipe_hw_info = hw_info; + + rc = cam_ipe_init_soc_resources(&ipe_dev->soc_info, cam_ipe_irq, + ipe_dev); + if (rc < 0) { + CAM_ERR(CAM_ICP, "failed to init_soc"); + kfree(ipe_dev->core_info); + kfree(ipe_dev); + kfree(ipe_dev_intf); + return rc; + } + + CAM_DBG(CAM_ICP, "cam_ipe_init_soc_resources : %pK", + (void *)&ipe_dev->soc_info); + rc = cam_ipe_register_cpas(&ipe_dev->soc_info, + core_info, ipe_dev_intf->hw_idx); + if (rc < 0) { + kfree(ipe_dev->core_info); + kfree(ipe_dev); + kfree(ipe_dev_intf); + return rc; + } + ipe_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&ipe_dev->hw_mutex); + spin_lock_init(&ipe_dev->hw_lock); + init_completion(&ipe_dev->hw_complete); + + CAM_DBG(CAM_ICP, "IPE%d probe successful", + ipe_dev_intf->hw_idx); + + return rc; +} + +static const struct of_device_id cam_ipe_dt_match[] = { + { + .compatible = "qcom,cam-ipe", + .data = &cam_ipe_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_ipe_dt_match); + +static struct platform_driver cam_ipe_driver = { + .probe = cam_ipe_probe, + .driver = { + .name = "cam-ipe", + .owner = THIS_MODULE, + .of_match_table = cam_ipe_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ipe_init_module(void) +{ + return platform_driver_register(&cam_ipe_driver); +} + +static void __exit cam_ipe_exit_module(void) +{ + platform_driver_unregister(&cam_ipe_driver); +} + +module_init(cam_ipe_init_module); +module_exit(cam_ipe_exit_module); +MODULE_DESCRIPTION("CAM IPE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..11cc7f7a33172cf23c4c51fdc1025f49f77b2b5d --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/cam_defs.h> +#include <media/cam_icp.h> +#include "ipe_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + + +int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + + return rc; +} + +int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info) +{ + int i; + int rc; + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_NORMAL); + if (rc) { + CAM_ERR(CAM_ICP, "Regulator set mode %s failed", + soc_info->rgltr_name[i]); + goto rgltr_set_mode_failed; + } + } + return 0; + +rgltr_set_mode_failed: + for (i = i - 1; i >= 0; i--) + if (soc_info->rgltr[i]) + regulator_set_mode(soc_info->rgltr[i], + REGULATOR_MODE_FAST); + + return rc; +} + +static int cam_ipe_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) + CAM_ERR(CAM_ICP, "get ipe dt prop is failed"); + + return rc; +} + +static int cam_ipe_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t ipe_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, ipe_irq_handler, + irq_data); + + return rc; +} + +int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ipe_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_ipe_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + rc = cam_ipe_request_platform_resource(soc_info, ipe_irq_handler, + irq_data); + if (rc < 0) + return rc; + + return rc; +} + +int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, false); + if (rc) { + CAM_ERR(CAM_ICP, "enable platform failed"); + return rc; + } + + return rc; +} + +int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, disable_clk, + false); + if (rc) + CAM_ERR(CAM_ICP, "enable platform failed"); + + return rc; +} + +int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate) +{ + int32_t src_clk_idx; + + if (!soc_info) + return -EINVAL; + + src_clk_idx = soc_info->src_clk_idx; + + if ((soc_info->clk_level_valid[CAM_TURBO_VOTE] == true) && + (soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx] != 0) && + (clk_rate > soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx])) { + CAM_DBG(CAM_PERF, "clk_rate %d greater than max, reset to %d", + clk_rate, + soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]); + clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; + } + + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); +} + +int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) +{ + int rc = 0; + + if (clk_enable) + rc = cam_soc_util_clk_enable_default(soc_info, CAM_SVS_VOTE); + else + cam_soc_util_clk_disable_default(soc_info); + + return rc; +} diff --git a/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..8981b18823adb0568a2ed98ef4b85ac3071aef38 --- /dev/null +++ b/techpack/camera/drivers/cam_icp/icp_hw/ipe_hw/ipe_soc.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_IPE_SOC_H +#define CAM_IPE_SOC_H + +#include "cam_soc_util.h" + +int cam_ipe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t ipe_irq_handler, void *irq_data); + +int cam_ipe_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_ipe_disable_soc_resources(struct cam_hw_soc_info *soc_info, + bool disable_clk); + +int cam_ipe_get_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_ipe_transfer_gdsc_control(struct cam_hw_soc_info *soc_info); + +int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_rate); +int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable); +#endif /* CAM_IPE_SOC_H */ diff --git a/techpack/camera/drivers/cam_isp/Makefile b/techpack/camera/drivers/cam_isp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..86ad96d61cb7c7caaf6c73fb2254ac041016d272 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ + +obj-$(CONFIG_SPECTRA_CAMERA) += isp_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_dev.o cam_isp_context.o diff --git a/techpack/camera/drivers/cam_isp/cam_isp_context.c b/techpack/camera/drivers/cam_isp/cam_isp_context.c new file mode 100755 index 0000000000000000000000000000000000000000..8ee6f693a8082364d90a966eac570ded0844949d --- /dev/null +++ b/techpack/camera/drivers/cam_isp/cam_isp_context.c @@ -0,0 +1,4468 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/ratelimit.h> + +#include "cam_mem_mgr.h" +#include "cam_sync_api.h" +#include "cam_req_mgr_dev.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" +#include "cam_context_utils.h" +#include "cam_cdm_util.h" +#include "cam_isp_context.h" +#include "cam_common_util.h" + +static const char isp_dev_name[] = "cam-isp"; + +static struct cam_isp_ctx_debug isp_ctx_debug; + +#define INC_STATE_MONITOR_HEAD(head, ret) \ + div_u64_rem(atomic64_add_return(1, head),\ + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, (ret)) + +static int cam_isp_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info); + +static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd); + +static void __cam_isp_ctx_update_state_monitor_array( + struct cam_isp_context *ctx_isp, + enum cam_isp_state_change_trigger trigger_type, + uint64_t req_id) +{ + int iterator; + + INC_STATE_MONITOR_HEAD(&ctx_isp->state_monitor_head, &iterator); + + ctx_isp->cam_isp_ctx_state_monitor[iterator].curr_state = + ctx_isp->substate_activated; + ctx_isp->cam_isp_ctx_state_monitor[iterator].frame_id = + ctx_isp->frame_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].trigger = + trigger_type; + ctx_isp->cam_isp_ctx_state_monitor[iterator].req_id = + req_id; + ctx_isp->cam_isp_ctx_state_monitor[iterator].evt_time_stamp = + jiffies_to_msecs(jiffies) - ctx_isp->init_timestamp; +} + +static const char *__cam_isp_ctx_substate_val_to_type( + enum cam_isp_ctx_activated_substate type) +{ + switch (type) { + case CAM_ISP_CTX_ACTIVATED_SOF: + return "SOF"; + case CAM_ISP_CTX_ACTIVATED_APPLIED: + return "APPLIED"; + case CAM_ISP_CTX_ACTIVATED_EPOCH: + return "EPOCH"; + case CAM_ISP_CTX_ACTIVATED_BUBBLE: + return "BUBBLE"; + case CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED: + return "BUBBLE_APPLIED"; + case CAM_ISP_CTX_ACTIVATED_HW_ERROR: + return "HW_ERROR"; + case CAM_ISP_CTX_ACTIVATED_HALT: + return "HALT"; + default: + return "INVALID"; + } +} + +static const char *__cam_isp_hw_evt_val_to_type( + uint32_t evt_id) +{ + switch (evt_id) { + case CAM_ISP_STATE_CHANGE_TRIGGER_ERROR: + return "ERROR"; + case CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED: + return "APPLIED"; + case CAM_ISP_STATE_CHANGE_TRIGGER_SOF: + return "SOF"; + case CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE: + return "REG_UPDATE"; + case CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH: + return "EPOCH"; + case CAM_ISP_STATE_CHANGE_TRIGGER_EOF: + return "EOF"; + case CAM_ISP_STATE_CHANGE_TRIGGER_DONE: + return "DONE"; + case CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH: + return "FLUSH"; + default: + return "CAM_ISP_EVENT_INVALID"; + } +} + +static void __cam_isp_ctx_dump_state_monitor_array( + struct cam_isp_context *ctx_isp) +{ + int i = 0; + int64_t state_head = 0; + uint32_t index, num_entries, oldest_entry; + + state_head = atomic64_read(&ctx_isp->state_monitor_head); + + if (state_head == -1) { + return; + } else if (state_head < CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) { + num_entries = state_head; + oldest_entry = 0; + } else { + num_entries = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; + div_u64_rem(state_head + 1, + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, &oldest_entry); + } + + CAM_ERR(CAM_ISP, + "Dumping state information for preceding requests"); + + index = oldest_entry; + + for (i = 0; i < num_entries; i++) { + CAM_ERR(CAM_ISP, + "Index[%d] time[%d] : Substate[%s] Frame[%lld] ReqId[%llu] evt_type[%s]", + index, + ctx_isp->cam_isp_ctx_state_monitor[index].evt_time_stamp, + __cam_isp_ctx_substate_val_to_type( + ctx_isp->cam_isp_ctx_state_monitor[index].curr_state), + ctx_isp->cam_isp_ctx_state_monitor[index].frame_id, + ctx_isp->cam_isp_ctx_state_monitor[index].req_id, + __cam_isp_hw_evt_val_to_type( + ctx_isp->cam_isp_ctx_state_monitor[index].trigger)); + + index = (index + 1) % CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; + } +} + +static int cam_isp_context_info_dump(void *context, + enum cam_context_dump_id id) +{ + struct cam_context *ctx = (struct cam_context *)context; + + switch (id) { + case CAM_CTX_DUMP_ACQ_INFO: { + cam_context_dump_hw_acq_info(ctx); + break; + } + default: + CAM_DBG(CAM_ISP, "DUMP id not valid %u", id); + break; + } + + return 0; +} + +static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) +{ + int i = 0, rc = 0; + size_t len = 0; + uint32_t *buf_addr; + uint32_t *buf_start, *buf_end; + size_t remain_len = 0; + + for (i = 0; i < req_isp->num_cfg; i++) { + rc = cam_packet_util_get_cmd_mem_addr( + req_isp->cfg[i].handle, &buf_addr, &len); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Failed to get_cmd_mem_addr, rc=%d", + rc); + } else { + if (req_isp->cfg[i].offset >= ((uint32_t)len)) { + CAM_ERR(CAM_ISP, + "Invalid offset exp %u actual %u", + req_isp->cfg[i].offset, (uint32_t)len); + return; + } + remain_len = len - req_isp->cfg[i].offset; + + if (req_isp->cfg[i].len > + ((uint32_t)remain_len)) { + CAM_ERR(CAM_ISP, + "Invalid len exp %u remain_len %u", + req_isp->cfg[i].len, + (uint32_t)remain_len); + return; + } + + buf_start = (uint32_t *)((uint8_t *) buf_addr + + req_isp->cfg[i].offset); + buf_end = (uint32_t *)((uint8_t *) buf_start + + req_isp->cfg[i].len - 1); + cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + } + } +} + +static int __cam_isp_ctx_enqueue_request_in_order( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + struct cam_ctx_request *req_current; + struct cam_ctx_request *req_prev; + struct list_head temp_list; + + INIT_LIST_HEAD(&temp_list); + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + } else { + list_for_each_entry_safe_reverse( + req_current, req_prev, &ctx->pending_req_list, list) { + if (req->request_id < req_current->request_id) { + list_del_init(&req_current->list); + list_add(&req_current->list, &temp_list); + continue; + } else if (req->request_id == req_current->request_id) { + CAM_WARN(CAM_ISP, + "Received duplicated request %lld", + req->request_id); + } + break; + } + list_add_tail(&req->list, &ctx->pending_req_list); + + if (!list_empty(&temp_list)) { + list_for_each_entry_safe( + req_current, req_prev, &temp_list, list) { + list_del_init(&req_current->list); + list_add_tail(&req_current->list, + &ctx->pending_req_list); + } + } + } + spin_unlock_bh(&ctx->lock); + return 0; +} + +static int __cam_isp_ctx_enqueue_init_request( + struct cam_context *ctx, struct cam_ctx_request *req) +{ + int rc = 0; + struct cam_ctx_request *req_old; + struct cam_isp_ctx_req *req_isp_old; + struct cam_isp_ctx_req *req_isp_new; + + spin_lock_bh(&ctx->lock); + if (list_empty(&ctx->pending_req_list)) { + list_add_tail(&req->list, &ctx->pending_req_list); + CAM_DBG(CAM_ISP, "INIT packet added req id= %d", + req->request_id); + goto end; + } + + req_old = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + req_isp_old = (struct cam_isp_ctx_req *) req_old->req_priv; + req_isp_new = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp_old->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) { + if ((req_isp_old->num_cfg + req_isp_new->num_cfg) >= + CAM_ISP_CTX_CFG_MAX) { + CAM_WARN(CAM_ISP, "Can not merge INIT pkt"); + rc = -ENOMEM; + } + + if (req_isp_old->num_fence_map_out != 0 || + req_isp_old->num_fence_map_in != 0) { + CAM_WARN(CAM_ISP, "Invalid INIT pkt sequence"); + rc = -EINVAL; + } + + if (!rc) { + memcpy(req_isp_old->fence_map_out, + req_isp_new->fence_map_out, + sizeof(req_isp_new->fence_map_out[0])* + req_isp_new->num_fence_map_out); + req_isp_old->num_fence_map_out = + req_isp_new->num_fence_map_out; + + memcpy(req_isp_old->fence_map_in, + req_isp_new->fence_map_in, + sizeof(req_isp_new->fence_map_in[0])* + req_isp_new->num_fence_map_in); + req_isp_old->num_fence_map_in = + req_isp_new->num_fence_map_in; + + memcpy(&req_isp_old->cfg[req_isp_old->num_cfg], + req_isp_new->cfg, + sizeof(req_isp_new->cfg[0])* + req_isp_new->num_cfg); + req_isp_old->num_cfg += req_isp_new->num_cfg; + + memcpy(&req_old->pf_data, &req->pf_data, + sizeof(struct cam_hw_mgr_dump_pf_data)); + + req_old->request_id = req->request_id; + + list_add_tail(&req->list, &ctx->free_req_list); + } + } else { + CAM_WARN(CAM_ISP, + "Received Update pkt before INIT pkt. req_id= %lld", + req->request_id); + rc = -EINVAL; + } +end: + spin_unlock_bh(&ctx->lock); + return rc; +} + +static const char *__cam_isp_resource_handle_id_to_type( + uint32_t resource_handle) +{ + switch (resource_handle) { + case CAM_ISP_IFE_OUT_RES_FULL: + return "FULL"; + case CAM_ISP_IFE_OUT_RES_DS4: + return "DS4"; + case CAM_ISP_IFE_OUT_RES_DS16: + return "DS16"; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return "RAW_DUMP"; + case CAM_ISP_IFE_OUT_RES_FD: + return "FD"; + case CAM_ISP_IFE_OUT_RES_PDAF: + return "PDAF"; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return "RDI_0"; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return "RDI_1"; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return "RDI_2"; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return "RDI_3"; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return "STATS_HDR_BE"; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return "STATS_HDR_BHIST"; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return "STATS_TL_BG"; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return "STATS_BF"; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return "STATS_AWB_BG"; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return "STATS_BHIST"; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return "STATS_RS"; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return "STATS_CS"; + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + return "STATS_IHIST"; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return "FULL_DISP"; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return "DS4_DISP"; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return "DS16_DISP"; + case CAM_ISP_IFE_OUT_RES_2PD: + return "2PD"; + case CAM_ISP_IFE_OUT_RES_RDI_RD: + return "RDI_RD"; + case CAM_ISP_IFE_OUT_RES_LCR: + return "LCR"; + default: + return "CAM_ISP_Invalid_Resource_Type"; + } +} + +static uint64_t __cam_isp_ctx_get_event_ts(uint32_t evt_id, void *evt_data) +{ + uint64_t ts = 0; + + if (!evt_data) + return 0; + + switch (evt_id) { + case CAM_ISP_HW_EVENT_ERROR: + ts = ((struct cam_isp_hw_error_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_SOF: + ts = ((struct cam_isp_hw_sof_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_REG_UPDATE: + ts = ((struct cam_isp_hw_reg_update_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_EPOCH: + ts = ((struct cam_isp_hw_epoch_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_EOF: + ts = ((struct cam_isp_hw_eof_event_data *)evt_data)-> + timestamp; + break; + case CAM_ISP_HW_EVENT_DONE: + break; + default: + CAM_DBG(CAM_ISP, "Invalid Event Type %d", evt_id); + } + + return ts; +} + +static void __cam_isp_ctx_send_sof_boot_timestamp( + struct cam_isp_context *ctx_isp, uint64_t request_id, + uint32_t sof_event_status) +{ + struct cam_req_mgr_message req_msg; + + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->boot_timestamp; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld boot time stamp:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->boot_timestamp); + + if (cam_is_log_enabled(CAM_CUSTOM)) { + CAM_DBG(CAM_ISP, + "#request id:%lld frame number:%lld boot time stamp:%lld\n", + request_id, ctx_isp->frame_id, + ctx_isp->boot_timestamp); + } + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the boot time for req id:%lld", + request_id); +} + + +static void __cam_isp_ctx_send_sof_timestamp( + struct cam_isp_context *ctx_isp, uint64_t request_id, + uint32_t sof_event_status) +{ + struct cam_req_mgr_message req_msg; + + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.frame_msg.frame_id = ctx_isp->frame_id; + req_msg.u.frame_msg.request_id = request_id; + req_msg.u.frame_msg.timestamp = ctx_isp->sof_timestamp_val; + req_msg.u.frame_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.frame_msg.sof_status = sof_event_status; + + CAM_DBG(CAM_ISP, + "request id:%lld frame number:%lld SOF time stamp:0x%llx", + request_id, ctx_isp->frame_id, + ctx_isp->sof_timestamp_val); + + if (cam_is_log_enabled(CAM_CUSTOM)) { + CAM_DBG(CAM_ISP, + "#request id:%lld frame number:%lld SOF time stamp:%lld\n", + request_id, ctx_isp->frame_id, + ctx_isp->sof_timestamp_val); + } + + CAM_DBG(CAM_ISP, "sof status:%d", sof_event_status); + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_SOF, V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the sof time for req id:%lld", + request_id); + + __cam_isp_ctx_send_sof_boot_timestamp(ctx_isp, + request_id, sof_event_status); + +} + +static void __cam_isp_ctx_handle_buf_done_fail_log( + uint64_t request_id, struct cam_isp_ctx_req *req_isp) +{ + int i; + + if (req_isp->num_fence_map_out >= CAM_ISP_CTX_RES_MAX) { + CAM_ERR(CAM_ISP, + "Num Resources exceed mMAX %d >= %d ", + req_isp->num_fence_map_out, CAM_ISP_CTX_RES_MAX); + return; + } + + CAM_WARN(CAM_ISP, + "Prev Req[%lld] : num_out=%d, num_acked=%d, bubble : report=%d, detected=%d", + request_id, req_isp->num_fence_map_out, req_isp->num_acked, + req_isp->bubble_report, req_isp->bubble_detected); + CAM_WARN(CAM_ISP, + "Resource Handles that fail to generate buf_done in prev frame"); + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) { + CAM_WARN(CAM_ISP, + "Resource_Handle: [%s][0x%x] Sync_ID: [0x%x]", + __cam_isp_resource_handle_id_to_type( + req_isp->fence_map_out[i].resource_handle), + req_isp->fence_map_out[i].resource_handle, + req_isp->fence_map_out[i].sync_id); + } + } +} + +static int __cam_isp_ctx_handle_buf_done_for_request( + struct cam_isp_context *ctx_isp, + struct cam_ctx_request *req, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state, + struct cam_isp_hw_done_event_data *done_next_req) +{ + int rc = 0; + int i, j; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + uint64_t buf_done_req_id; + + trace_cam_buf_done("ISP", ctx, req); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", + bubble_state, req_isp->bubble_detected); + + if (done_next_req) { + done_next_req->num_handles = 0; + done_next_req->timestamp = done->timestamp; + } + + for (i = 0; i < done->num_handles; i++) { + for (j = 0; j < req_isp->num_fence_map_out; j++) { + if (done->resource_handle[i] == + req_isp->fence_map_out[j].resource_handle) + break; + } + + if (j == req_isp->num_fence_map_out) { + CAM_ERR(CAM_ISP, + "Can not find matching lane handle 0x%x!", + done->resource_handle[i]); + rc = -EINVAL; + continue; + } + + if (req_isp->fence_map_out[j].sync_id == -1) { + CAM_WARN(CAM_ISP, + "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", + req->request_id, i, j, + __cam_isp_resource_handle_id_to_type( + done->resource_handle[i])); + + if (done_next_req) { + done_next_req->resource_handle + [done_next_req->num_handles++] = + done->resource_handle[i]; + } + + continue; + } + + if (!req_isp->bubble_detected) { + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_SUCCESS); + if (rc) + CAM_DBG(CAM_ISP, "Sync failed with rc = %d", + rc); + } else if (!req_isp->bubble_report) { + CAM_ERR(CAM_ISP, + "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) + CAM_ERR(CAM_ISP, "Sync failed with rc = %d", + rc); + } else { + /* + * Ignore the buffer done if bubble detect is on + * Increment the ack number here, and queue the + * request back to pending list whenever all the + * buffers are done. + */ + req_isp->num_acked++; + CAM_DBG(CAM_ISP, + "buf done with bubble state %d recovery %d", + bubble_state, req_isp->bubble_report); + continue; + } + + CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); + if (!rc) { + req_isp->num_acked++; + req_isp->fence_map_out[j].sync_id = -1; + } + } + + if (req_isp->num_acked > req_isp->num_fence_map_out) { + /* Should not happen */ + CAM_ERR(CAM_ISP, + "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", + req->request_id, req_isp->num_acked, + req_isp->num_fence_map_out, ctx->ctx_id); + WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); + } + + if (req_isp->num_acked != req_isp->num_fence_map_out) + return rc; + + ctx_isp->active_req_cnt--; + buf_done_req_id = req->request_id; + + if (req_isp->bubble_detected && req_isp->bubble_report) { + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + list_del_init(&req->list); + atomic_set(&ctx_isp->process_bubble, 0); + + if (buf_done_req_id <= ctx->last_flush_req) { + for (i = 0; i < req_isp->num_fence_map_out; i++) + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", + buf_done_req_id, ctx_isp->active_req_cnt, + ctx->ctx_id); + } else { + list_add(&req->list, &ctx->pending_req_list); + ctx_isp->bubble_frame_cnt = 0; + CAM_DBG(CAM_REQ, + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + req->request_id, ctx_isp->active_req_cnt, + ctx->ctx_id); + } + } else { + if (ctx_isp->reported_req_id < buf_done_req_id) { + ctx_isp->reported_req_id = buf_done_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + req_isp->reapply = false; + + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", + buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); + ctx_isp->req_info.last_bufdone_req_id = req->request_id; + } + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); + + return rc; +} + +static int __cam_isp_ctx_handle_buf_done_in_activated_state( + struct cam_isp_context *ctx_isp, + struct cam_isp_hw_done_event_data *done, + uint32_t bubble_state) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_done_event_data done_next_req; + + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "Buf done with no active request"); + return 0; + } + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + rc = __cam_isp_ctx_handle_buf_done_for_request(ctx_isp, req, done, + bubble_state, &done_next_req); + + if (done_next_req.num_handles) { + struct cam_isp_hw_done_event_data unhandled_res; + struct cam_ctx_request *next_req = list_last_entry( + &ctx->active_req_list, struct cam_ctx_request, list); + + if (next_req->request_id != req->request_id) { + /* + * Few resource handles are already signalled in the + * current request, lets check if there is another + * request waiting for these resources. This can + * happen if handling some of next request's buf done + * events are happening first before handling current + * request's remaining buf dones due to IRQ scheduling. + * Lets check only one more request as we will have + * maximum of 2 requests in active_list at any time. + */ + + CAM_WARN(CAM_ISP, + "Unhandled buf done resources for req %lld, trying next request %lld in active_list", + req->request_id, next_req->request_id); + + __cam_isp_ctx_handle_buf_done_for_request(ctx_isp, + next_req, &done_next_req, + bubble_state, &unhandled_res); + + if (unhandled_res.num_handles == 0) + CAM_INFO(CAM_ISP, + "BUF Done event handed for next request %lld", + next_req->request_id); + else + CAM_ERR(CAM_ISP, + "BUF Done not handled for next request %lld", + next_req->request_id); + } else { + CAM_WARN(CAM_ISP, + "Req %lld only active request, spurious buf_done rxd", + req->request_id); + } + } + + return rc; +} + +static int __cam_isp_ctx_reg_upd_in_epoch_bubble_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + if (ctx_isp->frame_id == 1) + CAM_DBG(CAM_ISP, "Reg update in Substate[%s] for early PCR", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + else + CAM_WARN(CAM_ISP, + "Unexpected reg update in activated Substate[%s] for frame_id:%lld", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), + ctx_isp->frame_id); + return 0; +} + +static int __cam_isp_ctx_reg_upd_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto end; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + request_id = req->request_id; + CAM_DBG(CAM_REQ, + "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_ISP, + "move active request %lld to free list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } + + /* + * This function only called directly from applied and bubble applied + * state so change substate here. + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, request_id); + +end: + return rc; +} + +static int __cam_isp_ctx_notify_sof_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify notify; + struct cam_context *ctx = ctx_isp->base; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + + /* + * notify reqmgr with sof signal. Note, due to scheduling delay + * we can run into situation that two active requests has already + * be in the active queue while we try to do the notification. + * In this case, we need to skip the current notification. This + * helps the state machine to catch up the delay. + */ + + if (atomic_read(&ctx_isp->process_bubble)) { + + if (list_empty(&ctx->active_req_list)) { + CAM_ERR(CAM_ISP, + "No available active req in bubble"); + atomic_set(&ctx_isp->process_bubble, 0); + rc = -EINVAL; + return rc; + } + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (ctx_isp->bubble_frame_cnt >= 1 && + req_isp->bubble_detected) { + req_isp->num_acked = 0; + ctx_isp->bubble_frame_cnt = 0; + req_isp->bubble_detected = false; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_REQ, + "Move active req: %lld to pending list(cnt = %d) [bubble re-apply], ctx %u", + req->request_id, + ctx_isp->active_req_cnt, ctx->ctx_id); + } else if (req_isp->bubble_detected) { + ctx_isp->bubble_frame_cnt++; + CAM_DBG(CAM_ISP, + "Waiting on bufdone for bubble req: %lld, since frame_cnt = %lld", + req->request_id, ctx_isp->bubble_frame_cnt); + } else + CAM_DBG(CAM_ISP, "Delayed bufdone for req: %lld", + req->request_id); + } + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); + } + + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + if (ctx_isp->substate_activated == CAM_ISP_CTX_ACTIVATED_BUBBLE) + request_id = 0; + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + request_id); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify SOF to CRM for ctx %u", + ctx->ctx_id); + rc = -EFAULT; + } + + return 0; +} + +static int __cam_isp_ctx_notify_eof_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_req_mgr_trigger_notify notify; + struct cam_context *ctx = ctx_isp->base; + + if (!(ctx_isp->subscribe_event & CAM_TRIGGER_POINT_EOF)) + return rc; + + /* notify reqmgr with eof signal */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_EOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EOF, 0); + } else { + CAM_ERR(CAM_ISP, "Can not notify EOF to CRM for ctx %u", + ctx->ctx_id); + rc = -EFAULT; + } + + return rc; +} + +static int __cam_isp_ctx_reg_upd_in_hw_error( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + return 0; +} + +static int __cam_isp_ctx_sof_in_activated_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + uint64_t request_id = 0; + + /* First check if there is a valid request in active list */ + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + break; + } + } + + /* + * If nothing in active list, current request might have not moved + * from wait to active list. This could happen if REG_UPDATE to sw + * is coming immediately after SOF + */ + if (request_id == 0) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + if (req) + request_id = req->request_id; + } + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, request_id); + + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id); + + return rc; +} + +static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) { + CAM_DBG(CAM_ISP, "invalid RUP"); + goto end; + } + + /* + * This is for the first update. The initial setting will + * cause the reg_upd in the first frame. + */ + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out == req_isp->num_acked) + list_add_tail(&req->list, &ctx->free_req_list); + else + CAM_ERR(CAM_ISP, + "receive rup in unexpected state"); + } + if (req != NULL) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + /* + * If no wait req in epoch, this is an error case. + * The recovery is to go back to sof state + */ + CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + /* Send SOF event as empty frame*/ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + goto end; + } + + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + req_isp->bubble_detected = true; + req_isp->reapply = true; + + CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); + if (req_isp->bubble_report && ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_err) { + struct cam_req_mgr_error_notify notify; + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = req->request_id; + notify.error = CRM_KMD_ERR_BUBBLE; + CAM_WARN(CAM_ISP, + "Notify CRM about Bubble req %lld frame %lld, ctx %u", + req->request_id, ctx_isp->frame_id, ctx->ctx_id); + ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); + } else { + req_isp->bubble_report = 0; + } + + /* + * Always move the request to active list. Let buf done + * function handles the rest. + */ + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + } + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_ERROR); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); +end: + if (request_id == 0) { + req = list_last_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id); + } else { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, request_id); + } + return 0; +} + + +static int __cam_isp_ctx_buf_done_in_applied(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + return rc; +} + + +static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + if (list_empty(&ctx->active_req_list)) + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + else + CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); + + req = list_last_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + if (req) + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, + req->request_id); + + if (ctx_isp->frame_id == 1) + CAM_INFO(CAM_ISP, + "First SOF in EPCR ctx:%d frame_id:%lld next substate %s", + ctx->ctx_id, ctx_isp->frame_id, + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + CAM_DBG(CAM_ISP, "SOF in epoch ctx:%d frame_id:%lld next substate:%s", + ctx->ctx_id, ctx_isp->frame_id, + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + return rc; +} + +static int __cam_isp_ctx_buf_done_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + return rc; +} + +static int __cam_isp_ctx_buf_done_in_bubble( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); + return rc; +} + +static int __cam_isp_ctx_epoch_in_bubble_applied( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + uint64_t request_id = 0; + + /* + * This means we missed the reg upd ack. So we need to + * transition to BUBBLE state again. + */ + + if (list_empty(&ctx->wait_req_list)) { + /* + * If no pending req in epoch, this is an error case. + * Just go back to the bubble state. + */ + CAM_ERR(CAM_ISP, "ctx:%d No pending request.", ctx->ctx_id); + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + goto end; + } + + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); + req_isp->reapply = true; + + if (req_isp->bubble_report && ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_err) { + struct cam_req_mgr_error_notify notify; + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = req->request_id; + notify.error = CRM_KMD_ERR_BUBBLE; + CAM_WARN(CAM_REQ, + "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", + req->request_id, ctx_isp->frame_id, ctx->ctx_id); + ctx->ctx_crm_intf->notify_err(¬ify); + atomic_set(&ctx_isp->process_bubble, 1); + } else { + req_isp->bubble_report = 0; + } + + /* + * Always move the request to active list. Let buf done + * function handles the rest. + */ + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u", + req->request_id, ctx_isp->active_req_cnt); + + if (!req_isp->bubble_report) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_ERROR); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); +end: + req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, + list); + if (req) + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, req->request_id); + return 0; +} + +static int __cam_isp_ctx_buf_done_in_bubble_applied( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); + + return rc; +} + +static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + uint32_t i = 0; + bool found = 0; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_to_report = NULL; + struct cam_ctx_request *req_to_dump = NULL; + struct cam_ctx_request *req_temp; + struct cam_isp_ctx_req *req_isp = NULL; + struct cam_isp_ctx_req *req_isp_to_report = NULL; + struct cam_req_mgr_error_notify notify = {}; + uint64_t error_request_id; + struct cam_hw_fence_map_entry *fence_map_out = NULL; + struct cam_req_mgr_message req_msg; + + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_error_event_data *error_event_data = + (struct cam_isp_hw_error_event_data *)evt_data; + + uint32_t error_type = error_event_data->error_type; + + CAM_DBG(CAM_ISP, "Enter error_type = %d", error_type); + + if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW) || + (error_type == CAM_ISP_HW_ERROR_VIOLATION)) { + struct cam_hw_cmd_args hw_cmd_args; + + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on error failed rc: %d", rc); + rc = 0; + } + } + /* + * The error is likely caused by first request on the active list. + * If active list is empty check wait list (maybe error hit as soon + * as RUP and we handle error before RUP. + */ + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, + "handling error with no active request"); + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Error with no active/wait request"); + goto end; + } else { + req_to_dump = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + } + } else { + req_to_dump = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + } + + req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; + + if (error_event_data->enable_req_dump) + cam_isp_ctx_dump_req(req_isp); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (!req_isp->bubble_report) { + for (i = 0; i < req_isp->num_fence_map_out; i++) { + fence_map_out = + &req_isp->fence_map_out[i]; + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); + if (req_isp->fence_map_out[i].sync_id != -1) { + rc = cam_sync_signal( + fence_map_out->sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + fence_map_out->sync_id = -1; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + } else { + found = 1; + break; + } + } + + if (found) + goto move_to_pending; + + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (!req_isp->bubble_report) { + for (i = 0; i < req_isp->num_fence_map_out; i++) { + fence_map_out = + &req_isp->fence_map_out[i]; + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", + req->request_id, + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); + if (req_isp->fence_map_out[i].sync_id != -1) { + rc = cam_sync_signal( + fence_map_out->sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + fence_map_out->sync_id = -1; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + } else { + found = 1; + break; + } + } + +move_to_pending: + /* + * If bubble recovery is enabled on any request we need to move that + * request and all the subsequent requests to the pending list. + * Note: + * We need to traverse the active list in reverse order and add + * to head of pending list. + * e.g. pending current state: 10, 11 | active current state: 8, 9 + * intermittent for loop iteration- pending: 9, 10, 11 | active: 8 + * final state - pending: 8, 9, 10, 11 | active: NULL + */ + if (found) { + list_for_each_entry_safe_reverse(req, req_temp, + &ctx->active_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + ctx_isp->active_req_cnt--; + } + list_for_each_entry_safe_reverse(req, req_temp, + &ctx->wait_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + ctx_isp->active_req_cnt--; + } + } + +end: + do { + if (list_empty(&ctx->pending_req_list)) { + error_request_id = ctx_isp->last_applied_req_id; + req_isp = NULL; + break; + } + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + error_request_id = ctx_isp->last_applied_req_id; + + if (req_isp->bubble_report) { + req_to_report = req; + req_isp_to_report = req_to_report->req_priv; + break; + } + + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) + rc = cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + req_isp->fence_map_out[i].sync_id = -1; + } + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + + } while (req->request_id < ctx_isp->last_applied_req_id); + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = error_request_id; + notify.error = CRM_KMD_ERR_FATAL; + + if (req_isp_to_report && req_isp_to_report->bubble_report) + if (error_event_data->recovery_enabled) + notify.error = CRM_KMD_ERR_BUBBLE; + + CAM_WARN(CAM_ISP, + "Notify CRM: req %lld, frame %lld ctx %u, error %d", + error_request_id, ctx_isp->frame_id, ctx->ctx_id, + notify.error); + + ctx->ctx_crm_intf->notify_err(¬ify); + + /* + * Need to send error occurred in KMD + * This will help UMD to take necessary action + * and to dump relevant info + */ + + if (notify.error == CRM_KMD_ERR_FATAL) { + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.err_msg.request_id = error_request_id; + req_msg.u.err_msg.resource_size = 0x0; + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the error time for req id:%lld ctx %u", + ctx_isp->last_applied_req_id, + ctx->ctx_id); + } + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify ERRROR to CRM for ctx %u", + ctx->ctx_id); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "Exit"); + + return rc; +} + +static int __cam_isp_ctx_fs2_sof_in_sof_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (!(list_empty(&ctx->wait_req_list))) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, request_id); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + +end: + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + struct cam_context *ctx = ctx_isp->base; + int prev_active_req_cnt = 0; + int curr_req_id = 0; + struct cam_ctx_request *req; + + prev_active_req_cnt = ctx_isp->active_req_cnt; + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + if (req) + curr_req_id = req->request_id; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + + if (prev_active_req_cnt == ctx_isp->active_req_cnt + 1) { + if (list_empty(&ctx->wait_req_list) && + list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "No request, move to SOF"); + ctx_isp->substate_activated = + CAM_ISP_CTX_ACTIVATED_SOF; + if (ctx_isp->reported_req_id < curr_req_id) { + ctx_isp->reported_req_id = curr_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + curr_req_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + } + } + + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_applied( + struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) { + CAM_DBG(CAM_ISP, "invalid RUP"); + goto end; + } + + /* + * This is for the first update. The initial setting will + * cause the reg_upd in the first frame. + */ + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out == req_isp->num_acked) + list_add_tail(&req->list, &ctx->free_req_list); + else + CAM_ERR(CAM_ISP, + "receive rup in unexpected state"); + } + if (req != NULL) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto end; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + } + + /* + * This function only called directly from applied and bubble applied + * state so change substate here. + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + if (req_isp->num_fence_map_out != 1) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); +end: + if (req != NULL && !rc) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } + return rc; +} + +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_sof, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* Bubble Applied */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_bubble_applied, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_hw_error, + NULL, + NULL, + NULL, + }, + }, + /* HALT */ + { + }, +}; + +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_fs2_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_fs2_reg_upd_in_sof, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_notify_eof_in_activated_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_fs2_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_epoch_bubble_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* Bubble Applied */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_bubble_applied, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_hw_error, + NULL, + NULL, + NULL, + }, + }, + /* HALT */ + { + }, +}; + +static int __cam_isp_ctx_apply_req_in_activated_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply, + enum cam_isp_ctx_activated_substate next_state) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *active_req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_ctx_req *active_req_isp; + struct cam_isp_context *ctx_isp = NULL; + struct cam_hw_config_args cfg; + + if (list_empty(&ctx->pending_req_list)) { + CAM_ERR(CAM_ISP, "No available request for Apply id %lld", + apply->request_id); + rc = -EFAULT; + goto end; + } + + /* + * When the pipeline has issue, the requests can be queued up in the + * pipeline. In this case, we should reject the additional request. + * The maximum number of request allowed to be outstanding is 2. + * + */ + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + + if (atomic_read(&ctx_isp->process_bubble)) { + CAM_INFO(CAM_ISP, + "Processing bubble cannot apply Request Id %llu", + apply->request_id); + rc = -EAGAIN; + goto end; + } + + spin_lock_bh(&ctx->lock); + req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + list); + spin_unlock_bh(&ctx->lock); + + /* + * Check whether the request id is matching the tip, if not, this means + * we are in the middle of the error handling. Need to reject this apply + */ + if (req->request_id != apply->request_id) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid Request Id asking %llu existing %llu", + apply->request_id, req->request_id); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_REQ, "Apply request %lld in Substate[%s] ctx %u", + req->request_id, + __cam_isp_ctx_substate_val_to_type(ctx_isp->substate_activated), + ctx->ctx_id); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (ctx_isp->active_req_cnt >= 2) { + CAM_WARN(CAM_ISP, + "Reject apply request (id %lld) due to congestion(cnt = %d) ctx %u", + req->request_id, + ctx_isp->active_req_cnt, + ctx->ctx_id); + + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->active_req_list)) + active_req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + else + CAM_ERR_RATE_LIMIT(CAM_ISP, + "WARNING: should not happen (cnt = %d) but active_list empty", + ctx_isp->active_req_cnt); + spin_unlock_bh(&ctx->lock); + + if (active_req) { + active_req_isp = + (struct cam_isp_ctx_req *) active_req->req_priv; + __cam_isp_ctx_handle_buf_done_fail_log( + active_req->request_id, active_req_isp); + } + + rc = -EFAULT; + goto end; + } + req_isp->bubble_report = apply->report_if_bubble; + + cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; + cfg.request_id = req->request_id; + cfg.hw_update_entries = req_isp->cfg; + cfg.num_hw_update_entries = req_isp->num_cfg; + cfg.priv = &req_isp->hw_update_data; + cfg.init_packet = 0; + cfg.reapply = req_isp->reapply; + + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration"); + } else { + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = next_state; + ctx_isp->last_applied_req_id = apply->request_id; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->wait_req_list); + CAM_DBG(CAM_ISP, "new substate Substate[%s], applied req %lld", + __cam_isp_ctx_substate_val_to_type(next_state), + ctx_isp->last_applied_req_id); + spin_unlock_bh(&ctx->lock); + + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_apply_req_in_sof( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_APPLIED); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + if (rc) + CAM_DBG(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); + + return rc; +} + +static int __cam_isp_ctx_apply_req_in_epoch( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_APPLIED); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + if (rc) + CAM_DBG(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); + + return rc; +} + +static int __cam_isp_ctx_apply_req_in_bubble( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + if (rc) + CAM_DBG(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); + + return rc; +} + +static int __cam_isp_ctx_flush_req(struct cam_context *ctx, + struct list_head *req_list, struct cam_req_mgr_flush_request *flush_req) +{ + int i, rc, tmp = 0; + uint32_t cancel_req_id_found = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *req_temp; + struct cam_isp_ctx_req *req_isp; + struct list_head flush_list; + struct cam_isp_context *ctx_isp = NULL; + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + + INIT_LIST_HEAD(&flush_list); + if (list_empty(req_list)) { + CAM_DBG(CAM_ISP, "request list is empty"); + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + CAM_ERR(CAM_ISP, "no request to cancel"); + return -EINVAL; + } else + return 0; + } + + CAM_DBG(CAM_REQ, "Flush [%u] in progress for req_id %llu", + flush_req->type, flush_req->req_id); + list_for_each_entry_safe(req, req_temp, req_list, list) { + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + if (req->request_id != flush_req->req_id) { + continue; + } else { + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + cancel_req_id_found = 1; + __cam_isp_ctx_update_state_monitor_array( + ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH, + req->request_id); + break; + } + } + list_del_init(&req->list); + list_add_tail(&req->list, &flush_list); + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH, req->request_id); + } + + list_for_each_entry_safe(req, req_temp, &flush_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + for (i = 0; i < req_isp->num_fence_map_out; i++) { + if (req_isp->fence_map_out[i].sync_id != -1) { + CAM_DBG(CAM_ISP, "Flush req 0x%llx, fence %d", + req->request_id, + req_isp->fence_map_out[i].sync_id); + rc = cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc) { + tmp = req_isp->fence_map_out[i].sync_id; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "signal fence %d failed", tmp); + } + req_isp->fence_map_out[i].sync_id = -1; + } + } + req_isp->reapply = false; + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_ISP, + "Flush request id:%lld is not found in the list", + flush_req->req_id); + + return 0; +} + +static int __cam_isp_ctx_flush_req_in_top_state( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + struct cam_isp_context *ctx_isp; + struct cam_isp_stop_args stop_isp; + struct cam_hw_stop_args stop_args; + struct cam_hw_reset_args reset_args; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_req_mgr_timer_notify timer; + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "Flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + spin_unlock_bh(&ctx->lock); + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + if (ctx->state <= CAM_CTX_READY) { + ctx->state = CAM_CTX_ACQUIRED; + goto end; + } + + spin_lock_bh(&ctx->lock); + ctx->state = CAM_CTX_FLUSHED; + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; + spin_unlock_bh(&ctx->lock); + + CAM_INFO(CAM_ISP, "Last request id to flush is %lld", + flush_req->req_id); + ctx->last_flush_req = flush_req->req_id; + + memset(&hw_cmd_args, 0, sizeof(hw_cmd_args)); + hw_cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Reg dump on flush failed rc: %d", rc); + rc = 0; + } + + stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_isp.stop_only = true; + stop_args.args = (void *)&stop_isp; + rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop_args); + if (rc) + CAM_ERR(CAM_ISP, "Failed to stop HW in Flush rc: %d", + rc); + + CAM_INFO(CAM_ISP, "Stop HW complete. Reset HW next."); + CAM_DBG(CAM_ISP, "Flush wait and active lists"); + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_timer) { + timer.link_hdl = ctx->link_hdl; + timer.dev_hdl = ctx->dev_hdl; + timer.state = false; + ctx->ctx_crm_intf->notify_timer(&timer); + } + + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->wait_req_list)) + rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, + flush_req); + + if (!list_empty(&ctx->active_req_list)) + rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, + flush_req); + + ctx_isp->active_req_cnt = 0; + spin_unlock_bh(&ctx->lock); + + reset_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv, + &reset_args); + if (rc) + CAM_ERR(CAM_ISP, "Failed to reset HW rc: %d", rc); + + ctx_isp->init_received = false; + } + +end: + ctx_isp->bubble_frame_cnt = 0; + atomic_set(&ctx_isp->process_bubble, 0); + return rc; +} + +static int __cam_isp_ctx_flush_req_in_ready( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + + /* if nothing is in pending req list, change state to acquire */ + if (list_empty(&ctx->pending_req_list)) + ctx->state = CAM_CTX_ACQUIRED; + spin_unlock_bh(&ctx->lock); + + trace_cam_context_state("ISP", ctx); + + CAM_DBG(CAM_ISP, "Flush request in ready state. next state %d", + ctx->state); + return rc; +} + +static struct cam_ctx_ops + cam_isp_ctx_activated_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_sof, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_epoch, + }, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_bubble, + }, + .irq_ops = NULL, + }, + /* Bubble Applied */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +static struct cam_ctx_ops + cam_isp_ctx_fs2_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_sof, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_epoch, + }, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_bubble, + }, + .irq_ops = NULL, + }, + /* Bubble Applied */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +static int __cam_isp_ctx_rdi_only_sof_in_top_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + uint64_t request_id = 0; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + /* + * notify reqmgr with sof signal. Note, due to scheduling delay + * we can run into situation that two active requests has already + * be in the active queue while we try to do the notification. + * In this case, we need to skip the current notification. This + * helps the state machine to catch up the delay. + */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + + /* + * It is idle frame with out any applied request id, send + * request id as zero + */ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + } + + if (list_empty(&ctx->active_req_list)) + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + else + CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); + + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + return rc; +} + +static int __cam_isp_ctx_rdi_only_sof_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED; + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + return 0; +} + +static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + uint64_t request_id = 0; + + /* + * Sof in bubble applied state means, reg update not received. + * before increment frame id and override time stamp value, send + * the previous sof time stamp that got captured in the + * sof in applied state. + */ + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (list_empty(&ctx->wait_req_list)) { + /* + * If no pending req in epoch, this is an error case. + * The recovery is to go back to sof state + */ + CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + /* Send SOF event as empty frame*/ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + goto end; + } + + req = list_first_entry(&ctx->wait_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + req_isp->bubble_detected = true; + CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld", + ctx->ctx_id, req_isp->bubble_report, req->request_id); + req_isp->reapply = true; + + if (req_isp->bubble_report && ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_err) { + struct cam_req_mgr_error_notify notify; + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.req_id = req->request_id; + notify.error = CRM_KMD_ERR_BUBBLE; + CAM_WARN(CAM_ISP, + "Notify CRM about Bubble req %lld frame %lld ctx %u", + req->request_id, + ctx_isp->frame_id, + ctx->ctx_id); + ctx->ctx_crm_intf->notify_err(¬ify); + } else { + req_isp->bubble_report = 0; + } + + /* + * Always move the request to active list. Let buf done + * function handles the rest. + */ + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + + if (!req_isp->bubble_report) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_ERROR); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + /* change the state to bubble, as reg update has not come */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); +end: + return 0; +} + +static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + uint32_t i; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_isp_ctx_req *req_isp; + uint64_t request_id = 0; + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + /* + * Signal all active requests with error and move the all the active + * requests to free list + */ + while (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in active list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + } + + /* notify reqmgr with sof signal */ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + + } else { + CAM_ERR(CAM_ISP, "Can not notify SOF to CRM"); + } + + /* + * It is idle frame with out any applied request id, send + * request id as zero + */ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + return 0; +} + +static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + /* notify reqmgr with sof signal*/ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto error; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + request_id = + (req_isp->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) ? + 0 : req->request_id; + + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_ISP, + "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + /* if packet has buffers, set correct request id */ + request_id = req->request_id; + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + CAM_DBG(CAM_ISP, + "move active req %lld to free list(cnt=%d)", + req->request_id, ctx_isp->active_req_cnt); + } + + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + notify.req_id = ctx_isp->req_info.last_bufdone_req_id; + notify.sof_timestamp_val = ctx_isp->sof_timestamp_val; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } else { + CAM_ERR(CAM_ISP, "Can not notify SOF to CRM"); + } + if (request_id) + ctx_isp->reported_req_id = request_id; + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + return 0; +error: + /* Send SOF event as idle frame*/ + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + /* + * There is no request in the pending list, move the sub state machine + * to SOF sub state + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + return 0; +} + +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_rdi_only_activated_state_machine_irq + [CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_rdi_only_sof_in_top_state, + __cam_isp_ctx_reg_upd_in_sof, + NULL, + NULL, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_applied_state, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_top_state, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_epoch, + }, + }, + /* BUBBLE*/ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_bubble_state, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* BUBBLE APPLIED ie PRE_BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_rdi_only_sof_in_bubble_applied, + __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_bubble_applied, + }, + }, + /* HW ERROR */ + { + }, + /* HALT */ + { + }, +}; + +static int __cam_isp_ctx_rdi_only_apply_req_top_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "current Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + rc = __cam_isp_ctx_apply_req_in_activated_state(ctx, apply, + CAM_ISP_CTX_ACTIVATED_APPLIED); + CAM_DBG(CAM_ISP, "new Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + if (rc) + CAM_ERR(CAM_ISP, "Apply failed in Substate[%s], rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); + + return rc; +} + +static struct cam_ctx_ops + cam_isp_ctx_rdi_only_activated_state_machine + [CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_rdi_only_apply_req_top_state, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_rdi_only_apply_req_top_state, + }, + .irq_ops = NULL, + }, + /* PRE BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, + void *cmd) +{ + int rc = 0; + struct cam_hw_release_args rel_arg; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_req_mgr_flush_request flush_req; + + if (ctx_isp->hw_ctx) { + rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &rel_arg); + ctx_isp->hw_ctx = NULL; + } else { + CAM_ERR(CAM_ISP, "No hw resources acquired for this ctx"); + } + + ctx->last_flush_req = 0; + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->hw_acquired = false; + ctx_isp->init_received = false; + ctx_isp->req_info.last_bufdone_req_id = 0; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + /* + * Ideally, we should never have any active request here. + * But we still add some sanity check code here to help the debug + */ + if (!list_empty(&ctx->active_req_list)) + CAM_WARN(CAM_ISP, "Active list is not empty"); + + /* Flush all the pending request list */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_ACQUIRED; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); + return rc; +} + +/* top level state machine */ +static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_release_args rel_arg; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_req_mgr_flush_request flush_req; + + if (cmd && ctx_isp->hw_ctx) { + CAM_ERR(CAM_ISP, "releasing hw"); + __cam_isp_ctx_release_hw_in_top_state(ctx, NULL); + } + + if (ctx_isp->hw_ctx) { + rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &rel_arg); + ctx_isp->hw_ctx = NULL; + } + + ctx->session_hdl = -1; + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->hw_acquired = false; + ctx_isp->init_received = false; + ctx_isp->rdi_only_context = false; + ctx_isp->req_info.last_bufdone_req_id = 0; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + /* + * Ideally, we should never have any active request here. + * But we still add some sanity check code here to help the debug + */ + if (!list_empty(&ctx->active_req_list)) + CAM_ERR(CAM_ISP, "Active list is not empty"); + + /* Flush all the pending request list */ + flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; + flush_req.link_hdl = ctx->link_hdl; + flush_req.dev_hdl = ctx->dev_hdl; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + spin_lock_bh(&ctx->lock); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); + spin_unlock_bh(&ctx->lock); + ctx->state = CAM_CTX_AVAILABLE; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); + return rc; +} + +static int __cam_isp_ctx_config_dev_in_top_state( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc = 0, i; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + uintptr_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + size_t remain_len = 0; + struct cam_hw_prepare_update_args cfg; + struct cam_req_mgr_add_request add_req; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "get free request object......"); + + /* get free request */ + spin_lock_bh(&ctx->lock); + if (!list_empty(&ctx->free_req_list)) { + req = list_first_entry(&ctx->free_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + } + spin_unlock_bh(&ctx->lock); + + if (!req) { + CAM_ERR(CAM_ISP, "No more request obj free"); + return -ENOMEM; + } + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + /* for config dev, only memory handle is supported */ + /* map packet from the memhandle */ + rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, + &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Can not get packet address"); + rc = -EINVAL; + goto free_req; + } + + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len); + rc = -EINVAL; + goto free_req; + } + + remain_len -= (size_t)cmd->offset; + packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); + CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle); + CAM_DBG(CAM_ISP, "packet address is 0x%zx", packet_addr); + CAM_DBG(CAM_ISP, "packet with length %zu, offset 0x%llx", + len, cmd->offset); + CAM_DBG(CAM_ISP, "Packet request id %lld", + packet->header.request_id); + CAM_DBG(CAM_ISP, "Packet size 0x%x", packet->header.size); + CAM_DBG(CAM_ISP, "packet op %d", packet->header.op_code); + + if ((((packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_UPDATE_DEV) + && (packet->header.request_id <= ctx->last_flush_req)) { + CAM_INFO(CAM_ISP, + "request %lld has been flushed, reject packet", + packet->header.request_id); + rc = -EBADR; + goto free_req; + } + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + cfg.remain_len = remain_len; + cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; + cfg.max_hw_update_entries = CAM_ISP_CTX_CFG_MAX; + cfg.hw_update_entries = req_isp->cfg; + cfg.max_out_map_entries = CAM_ISP_CTX_RES_MAX; + cfg.max_in_map_entries = CAM_ISP_CTX_RES_MAX; + cfg.out_map_entries = req_isp->fence_map_out; + cfg.in_map_entries = req_isp->fence_map_in; + cfg.priv = &req_isp->hw_update_data; + cfg.pf_data = &(req->pf_data); + + CAM_DBG(CAM_ISP, "try to prepare config packet......"); + + rc = ctx->hw_mgr_intf->hw_prepare_update( + ctx->hw_mgr_intf->hw_mgr_priv, &cfg); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Prepare config packet failed in HW layer"); + rc = -EFAULT; + goto free_req; + } + req_isp->num_cfg = cfg.num_hw_update_entries; + req_isp->num_fence_map_out = cfg.num_out_map_entries; + req_isp->num_fence_map_in = cfg.num_in_map_entries; + req_isp->num_acked = 0; + req_isp->bubble_detected = false; + + for (i = 0; i < req_isp->num_fence_map_out; i++) { + rc = cam_sync_get_obj_ref(req_isp->fence_map_out[i].sync_id); + if (rc) { + CAM_ERR(CAM_ISP, "Can't get ref for fence %d", + req_isp->fence_map_out[i].sync_id); + goto put_ref; + } + } + + CAM_DBG(CAM_ISP, "num_entry: %d, num fence out: %d, num fence in: %d", + req_isp->num_cfg, req_isp->num_fence_map_out, + req_isp->num_fence_map_in); + + req->request_id = packet->header.request_id; + req->status = 1; + + CAM_DBG(CAM_ISP, "Packet request id %lld packet opcode:%d", + packet->header.request_id, + req_isp->hw_update_data.packet_opcode_type); + + if (req_isp->hw_update_data.packet_opcode_type == + CAM_ISP_PACKET_INIT_DEV) { + if (ctx->state < CAM_CTX_ACTIVATED) { + rc = __cam_isp_ctx_enqueue_init_request(ctx, req); + if (rc) + CAM_ERR(CAM_ISP, "Enqueue INIT pkt failed"); + ctx_isp->init_received = true; + } else { + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Recevied INIT pkt in wrong state:%d", + ctx->state); + } + } else { + if (ctx->state != CAM_CTX_FLUSHED && ctx->state >= CAM_CTX_READY + && ctx->ctx_crm_intf->add_req) { + add_req.link_hdl = ctx->link_hdl; + add_req.dev_hdl = ctx->dev_hdl; + add_req.req_id = req->request_id; + add_req.skip_before_applying = 0; + rc = ctx->ctx_crm_intf->add_req(&add_req); + if (rc) { + CAM_ERR(CAM_ISP, "Add req failed: req id=%llu", + req->request_id); + } else { + __cam_isp_ctx_enqueue_request_in_order( + ctx, req); + } + } else { + rc = -EINVAL; + CAM_ERR(CAM_ISP, + "Recevied update req %lld in wrong state:%d", + req->request_id, ctx->state); + } + } + if (rc) + goto put_ref; + + CAM_DBG(CAM_REQ, + "Preprocessing Config req_id %lld successful on ctx %u", + req->request_id, ctx->ctx_id); + + return rc; + +put_ref: + for (--i; i >= 0; i--) { + if (cam_sync_put_obj_ref(req_isp->fence_map_out[i].sync_id)) + CAM_ERR(CAM_CTXT, "Failed to put ref of fence %d", + req_isp->fence_map_out[i].sync_id); + } +free_req: + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + + return rc; +} + +static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + struct cam_hw_acquire_args param; + struct cam_isp_resource *isp_res = NULL; + struct cam_create_dev_hdl req_hdl_param; + struct cam_hw_release_args release; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_ISP, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_ISP, + "session_hdl 0x%x, num_resources %d, hdl type %d, res %lld", + cmd->session_handle, cmd->num_resources, + cmd->handle_type, cmd->resource_hdl); + + if (cmd->num_resources == CAM_API_COMPAT_CONSTANT) { + ctx_isp->split_acquire = true; + CAM_DBG(CAM_ISP, "Acquire dev handle"); + goto get_dev_handle; + } + + if (cmd->num_resources > CAM_ISP_CTX_RES_MAX) { + CAM_ERR(CAM_ISP, "Too much resources in the acquire"); + rc = -ENOMEM; + goto end; + } + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_ISP, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + isp_res = kzalloc( + sizeof(*isp_res)*cmd->num_resources, GFP_KERNEL); + if (!isp_res) { + rc = -ENOMEM; + goto end; + } + + CAM_DBG(CAM_ISP, "start copy %d resources from user", + cmd->num_resources); + + if (copy_from_user(isp_res, u64_to_user_ptr(cmd->resource_hdl), + sizeof(*isp_res)*cmd->num_resources)) { + rc = -EFAULT; + goto free_res; + } + + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = cmd->num_resources; + param.acquire_info = (uintptr_t) isp_res; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Acquire device failed"); + goto free_res; + } + + /* Query the context has rdi only resource */ + hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_hw; + } + + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { + /* + * this context has rdi only resource assign rdi only + * state machine + */ + CAM_DBG(CAM_ISP, "RDI only session Context"); + + ctx_isp->substate_machine_irq = + cam_isp_ctx_rdi_only_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; + } else { + CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_activated_state_machine; + } + + ctx_isp->hw_ctx = param.ctxt_to_hw_map; + ctx_isp->hw_acquired = true; + ctx_isp->split_acquire = false; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + kfree(isp_res); + isp_res = NULL; + +get_dev_handle: + + req_hdl_param.session_hdl = cmd->session_handle; + /* bridge is not ready for these flags. so false for now */ + req_hdl_param.v4l2_sub_dev_flag = 0; + req_hdl_param.media_entity_flag = 0; + req_hdl_param.ops = ctx->crm_ctx_intf; + req_hdl_param.priv = ctx; + + CAM_DBG(CAM_ISP, "get device handle form bridge"); + ctx->dev_hdl = cam_create_device_hdl(&req_hdl_param); + if (ctx->dev_hdl <= 0) { + rc = -EFAULT; + CAM_ERR(CAM_ISP, "Can not create device handle"); + goto free_hw; + } + cmd->dev_handle = ctx->dev_hdl; + + /* store session information */ + ctx->session_hdl = cmd->session_handle; + ctx->state = CAM_CTX_ACQUIRED; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%x num_rsrces %d ctx %u", + cmd->session_handle, cmd->num_resources, ctx->ctx_id); + + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx_isp->hw_ctx; + if (ctx_isp->hw_acquired) + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, + &release); + ctx_isp->hw_ctx = NULL; + ctx_isp->hw_acquired = false; +free_res: + kfree(isp_res); +end: + return rc; +} + +static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, + void *args) +{ + int rc = 0; + struct cam_acquire_hw_cmd_v1 *cmd = + (struct cam_acquire_hw_cmd_v1 *)args; + struct cam_hw_acquire_args param; + struct cam_hw_release_args release; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_ISP, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_ISP, + "session_hdl 0x%x, hdl type %d, res %lld", + cmd->session_handle, cmd->handle_type, cmd->resource_hdl); + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_ISP, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + if (cmd->data_size < sizeof(*acquire_hw_info)) { + CAM_ERR(CAM_ISP, "data_size is not a valid value"); + goto end; + } + + acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL); + if (!acquire_hw_info) { + rc = -ENOMEM; + goto end; + } + + CAM_DBG(CAM_ISP, "start copy resources from user"); + + if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl, + cmd->data_size)) { + rc = -EFAULT; + goto free_res; + } + + memset(¶m, 0, sizeof(param)); + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = CAM_API_COMPAT_CONSTANT; + param.acquire_info_size = cmd->data_size; + param.acquire_info = (uint64_t) acquire_hw_info; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Acquire device failed"); + goto free_res; + } + + /* Query the context has rdi only resource */ + hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_hw; + } + + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { + /* + * this context has rdi only resource assign rdi only + * state machine + */ + CAM_DBG(CAM_ISP, "RDI only session Context"); + + ctx_isp->substate_machine_irq = + cam_isp_ctx_rdi_only_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; + } else { + CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_activated_state_machine; + } + + ctx_isp->hw_ctx = param.ctxt_to_hw_map; + ctx_isp->hw_acquired = true; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", + ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id); + kfree(acquire_hw_info); + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); + ctx_isp->hw_ctx = NULL; + ctx_isp->hw_acquired = false; +free_res: + kfree(acquire_hw_info); +end: + return rc; +} + +static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, + void *args) +{ + int rc = 0, i, j; + struct cam_acquire_hw_cmd_v2 *cmd = + (struct cam_acquire_hw_cmd_v2 *)args; + struct cam_hw_acquire_args param; + struct cam_hw_release_args release; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_ISP, "HW interface is not ready"); + rc = -EFAULT; + goto end; + } + + CAM_DBG(CAM_ISP, + "session_hdl 0x%x, hdl type %d, res %lld", + cmd->session_handle, cmd->handle_type, cmd->resource_hdl); + + /* for now we only support user pointer */ + if (cmd->handle_type != 1) { + CAM_ERR(CAM_ISP, "Only user pointer is supported"); + rc = -EINVAL; + goto end; + } + + if (cmd->data_size < sizeof(*acquire_hw_info)) { + CAM_ERR(CAM_ISP, "data_size is not a valid value"); + goto end; + } + + acquire_hw_info = kzalloc(cmd->data_size, GFP_KERNEL); + if (!acquire_hw_info) { + rc = -ENOMEM; + goto end; + } + + CAM_DBG(CAM_ISP, "start copy resources from user"); + + if (copy_from_user(acquire_hw_info, (void __user *)cmd->resource_hdl, + cmd->data_size)) { + rc = -EFAULT; + goto free_res; + } + + memset(¶m, 0, sizeof(param)); + param.context_data = ctx; + param.event_cb = ctx->irq_cb_intf; + param.num_acq = CAM_API_COMPAT_CONSTANT; + param.acquire_info_size = cmd->data_size; + param.acquire_info = (uint64_t) acquire_hw_info; + + /* call HW manager to reserve the resource */ + rc = ctx->hw_mgr_intf->hw_acquire(ctx->hw_mgr_intf->hw_mgr_priv, + ¶m); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Acquire device failed"); + goto free_res; + } + + /* Query the context has rdi only resource */ + hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "HW command failed"); + goto free_hw; + } + + if (param.valid_acquired_hw) { + for (i = 0; i < CAM_MAX_ACQ_RES; i++) + cmd->hw_info.acquired_hw_id[i] = + param.acquired_hw_id[i]; + + for (i = 0; i < CAM_MAX_ACQ_RES; i++) + for (j = 0; j < CAM_MAX_HW_SPLIT; j++) + cmd->hw_info.acquired_hw_path[i][j] = + param.acquired_hw_path[i][j]; + } + cmd->hw_info.valid_acquired_hw = + param.valid_acquired_hw; + + cmd->hw_info.valid_acquired_hw = param.valid_acquired_hw; + + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { + /* + * this context has rdi only resource assign rdi only + * state machine + */ + CAM_DBG(CAM_ISP, "RDI only session Context"); + + ctx_isp->substate_machine_irq = + cam_isp_ctx_rdi_only_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; + } else { + CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_activated_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_activated_state_machine; + } + + ctx_isp->hw_ctx = param.ctxt_to_hw_map; + ctx_isp->hw_acquired = true; + ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; + + trace_cam_context_state("ISP", ctx); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", + ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id); + kfree(acquire_hw_info); + return rc; + +free_hw: + release.ctxt_to_hw_map = ctx_isp->hw_ctx; + ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &release); + ctx_isp->hw_ctx = NULL; + ctx_isp->hw_acquired = false; +free_res: + kfree(acquire_hw_info); +end: + return rc; +} + +static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx, + void *args) +{ + int rc = -EINVAL; + uint32_t api_version; + + if (!ctx || !args) { + CAM_ERR(CAM_ISP, "Invalid input pointer"); + return rc; + } + + api_version = *((uint32_t *)args); + if (api_version == 1) + rc = __cam_isp_ctx_acquire_hw_v1(ctx, args); + else if (api_version == 2) + rc = __cam_isp_ctx_acquire_hw_v2(ctx, args); + else + CAM_ERR(CAM_ISP, "Unsupported api version %d", api_version); + + return rc; +} + +static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (!ctx_isp->hw_acquired) { + CAM_ERR(CAM_ISP, "HW is not acquired, reject packet"); + return -EINVAL; + } + + rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd); + + if (!rc && (ctx->link_hdl >= 0)) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ISP", ctx); + } + + CAM_DBG(CAM_ISP, "next state %d", ctx->state); + return rc; +} + +static int __cam_isp_ctx_config_dev_in_flushed(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_start_stop_dev_cmd start_cmd; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (!ctx_isp->hw_acquired) { + CAM_ERR(CAM_ISP, "HW is not acquired, reject packet"); + rc = -EINVAL; + goto end; + } + + rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd); + if (rc) + goto end; + + if (!ctx_isp->init_received) { + CAM_WARN(CAM_ISP, + "Received update packet in flushed state, skip start"); + goto end; + } + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_RESUME_HW; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to resume HW rc: %d", rc); + goto end; + } + + start_cmd.dev_handle = cmd->dev_handle; + start_cmd.session_handle = cmd->session_handle; + rc = __cam_isp_ctx_start_dev_in_ready(ctx, &start_cmd); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to re-start HW after flush rc: %d", rc); + else + CAM_INFO(CAM_ISP, + "Received init after flush. Re-start HW complete."); + +end: + CAM_DBG(CAM_ISP, "next state %d sub_state:%d", ctx->state, + ctx_isp->substate_activated); + return rc; +} + +static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *link) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + CAM_DBG(CAM_ISP, "Enter........."); + + ctx->link_hdl = link->link_hdl; + ctx->ctx_crm_intf = link->crm_cb; + ctx_isp->subscribe_event = link->subscribe_event; + + /* change state only if we had the init config */ + if (ctx_isp->init_received) { + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ISP", ctx); + } + + CAM_DBG(CAM_ISP, "next state %d", ctx->state); + + return rc; +} + +static int __cam_isp_ctx_unlink_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + + return rc; +} + +static int __cam_isp_ctx_get_dev_info_in_acquired(struct cam_context *ctx, + struct cam_req_mgr_device_info *dev_info) +{ + int rc = 0; + + dev_info->dev_hdl = ctx->dev_hdl; + strlcpy(dev_info->name, CAM_ISP_DEV_NAME, sizeof(dev_info->name)); + dev_info->dev_id = CAM_REQ_MGR_DEVICE_IFE; + dev_info->p_delay = 1; + dev_info->trigger = CAM_TRIGGER_POINT_SOF; + + return rc; +} + +static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_isp_start_args start_isp; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + if (cmd->session_handle != ctx->session_hdl || + cmd->dev_handle != ctx->dev_hdl) { + rc = -EPERM; + goto end; + } + + if (list_empty(&ctx->pending_req_list)) { + /* should never happen */ + CAM_ERR(CAM_ISP, "Start device with empty configuration"); + rc = -EFAULT; + goto end; + } else { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + } + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (!ctx_isp->hw_ctx) { + CAM_ERR(CAM_ISP, "Wrong hw context pointer."); + rc = -EFAULT; + goto end; + } + + start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; + start_isp.hw_config.request_id = req->request_id; + start_isp.hw_config.hw_update_entries = req_isp->cfg; + start_isp.hw_config.num_hw_update_entries = req_isp->num_cfg; + start_isp.hw_config.priv = &req_isp->hw_update_data; + start_isp.hw_config.init_packet = 1; + start_isp.hw_config.reapply = 0; + + ctx_isp->last_applied_req_id = req->request_id; + + if (ctx->state == CAM_CTX_FLUSHED) + start_isp.start_only = true; + else + start_isp.start_only = false; + + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->bubble_frame_cnt = 0; + ctx_isp->substate_activated = ctx_isp->rdi_only_context ? + CAM_ISP_CTX_ACTIVATED_APPLIED : + (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : + CAM_ISP_CTX_ACTIVATED_SOF; + + atomic64_set(&ctx_isp->state_monitor_head, -1); + + /* + * In case of CSID TPG we might receive SOF and RUP IRQs + * before hw_mgr_intf->hw_start has returned. So move + * req out of pending list before hw_start and add it + * back to pending list if hw_start fails. + */ + list_del_init(&req->list); + + if (ctx_isp->rdi_only_context || !req_isp->num_fence_map_out) { + list_add_tail(&req->list, &ctx->wait_req_list); + } else { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + } + + /* + * Only place to change state before calling the hw due to + * hardware tasklet has higher priority that can cause the + * irq handling comes early + */ + ctx->state = CAM_CTX_ACTIVATED; + trace_cam_context_state("ISP", ctx); + rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, + &start_isp); + if (rc) { + /* HW failure. user need to clean up the resource */ + CAM_ERR(CAM_ISP, "Start HW failed"); + ctx->state = CAM_CTX_READY; + trace_cam_context_state("ISP", ctx); + if (rc == -ETIMEDOUT) + cam_isp_ctx_dump_req(req_isp); + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + goto end; + } + CAM_DBG(CAM_ISP, "start device success ctx %u", ctx->ctx_id); + +end: + return rc; +} + +static int __cam_isp_ctx_unlink_in_ready(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ISP", ctx); + + return rc; +} + +static int __cam_isp_ctx_stop_dev_in_activated_unlock( + struct cam_context *ctx, struct cam_start_stop_dev_cmd *stop_cmd) +{ + int rc = 0; + uint32_t i; + struct cam_hw_stop_args stop; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + struct cam_isp_stop_args stop_isp; + + /* stop hw first */ + if (ctx_isp->hw_ctx) { + stop.ctxt_to_hw_map = ctx_isp->hw_ctx; + + if (stop_cmd) + stop_isp.hw_stop_cmd = + CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; + else + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + + stop_isp.stop_only = false; + stop.args = (void *) &stop_isp; + ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, + &stop); + } + + /* Mask off all the incoming hardware events */ + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT; + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "next Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + + if (ctx->ctx_crm_intf && + ctx->ctx_crm_intf->notify_stop) { + struct cam_req_mgr_notify_stop notify; + + notify.link_hdl = ctx->link_hdl; + CAM_DBG(CAM_ISP, + "Notify CRM about device stop ctx %u link 0x%x", + ctx->ctx_id, ctx->link_hdl); + ctx->ctx_crm_intf->notify_stop(¬ify); + } else + CAM_ERR(CAM_ISP, "cb not present"); + + while (!list_empty(&ctx->pending_req_list)) { + req = list_first_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in pending list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in wait list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + while (!list_empty(&ctx->active_req_list)) { + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + CAM_DBG(CAM_ISP, "signal fence in active list. fence num %d", + req_isp->num_fence_map_out); + for (i = 0; i < req_isp->num_fence_map_out; i++) + if (req_isp->fence_map_out[i].sync_id != -1) { + cam_sync_signal( + req_isp->fence_map_out[i].sync_id, + CAM_SYNC_STATE_SIGNALED_ERROR); + } + list_add_tail(&req->list, &ctx->free_req_list); + } + + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->bubble_frame_cnt = 0; + ctx_isp->last_applied_req_id = 0; + ctx_isp->req_info.last_bufdone_req_id = 0; + atomic_set(&ctx_isp->process_bubble, 0); + atomic64_set(&ctx_isp->state_monitor_head, -1); + + CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", + ctx->state, ctx->ctx_id); + + if (!stop_cmd) { + rc = __cam_isp_ctx_unlink_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Unlink failed rc=%d", rc); + } + return rc; +} + +static int __cam_isp_ctx_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *)ctx->ctx_priv; + + __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, cmd); + ctx_isp->init_received = false; + ctx->state = CAM_CTX_ACQUIRED; + trace_cam_context_state("ISP", ctx); + return rc; +} + +static int __cam_isp_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Stop device failed rc=%d", rc); + + rc = __cam_isp_ctx_release_dev_in_top_state(ctx, cmd); + if (rc) + CAM_ERR(CAM_ISP, "Release device failed rc=%d", rc); + + return rc; +} + +static int __cam_isp_ctx_release_hw_in_activated(struct cam_context *ctx, + void *cmd) +{ + int rc = 0; + + rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Stop device failed rc=%d", rc); + + rc = __cam_isp_ctx_release_hw_in_top_state(ctx, cmd); + if (rc) + CAM_ERR(CAM_ISP, "Release hw failed rc=%d", rc); + + return rc; +} + +static int __cam_isp_ctx_link_pause(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_PAUSE_HW; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + +static int __cam_isp_ctx_link_resume(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_RESUME_HW; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + +static int __cam_isp_ctx_handle_sof_freeze_evt( + struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args hw_cmd_args; + struct cam_isp_hw_cmd_args isp_hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_SOF_DEBUG; + isp_hw_cmd_args.u.sof_irq_enable = 1; + hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; + + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + +static int __cam_isp_ctx_process_evt(struct cam_context *ctx, + struct cam_req_mgr_link_evt_data *link_evt_data) +{ + int rc = 0; + + switch (link_evt_data->evt_type) { + case CAM_REQ_MGR_LINK_EVT_ERR: + /* No need to handle this message now */ + break; + case CAM_REQ_MGR_LINK_EVT_PAUSE: + __cam_isp_ctx_link_pause(ctx); + break; + case CAM_REQ_MGR_LINK_EVT_RESUME: + __cam_isp_ctx_link_resume(ctx); + break; + case CAM_REQ_MGR_LINK_EVT_SOF_FREEZE: + __cam_isp_ctx_handle_sof_freeze_evt(ctx); + break; + default: + CAM_WARN(CAM_ISP, "Unknown event from CRM"); + break; + } + return rc; +} + +static int __cam_isp_ctx_unlink_in_activated(struct cam_context *ctx, + struct cam_req_mgr_core_dev_link_setup *unlink) +{ + int rc = 0; + + CAM_WARN(CAM_ISP, + "Received unlink in activated state. It's unexpected"); + + rc = __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, NULL); + if (rc) + CAM_WARN(CAM_ISP, "Stop device failed rc=%d", rc); + + rc = __cam_isp_ctx_unlink_in_ready(ctx, unlink); + if (rc) + CAM_ERR(CAM_ISP, "Unlink failed rc=%d", rc); + + return rc; +} + +static int __cam_isp_ctx_apply_req(struct cam_context *ctx, + struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_ctx_ops *ctx_ops = NULL; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + trace_cam_apply_req("ISP", apply->request_id); + CAM_DBG(CAM_ISP, "Enter: apply req in Substate[%s] request_id:%lld", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), apply->request_id); + ctx_ops = &ctx_isp->substate_machine[ctx_isp->substate_activated]; + if (ctx_ops->crm_ops.apply_req) { + rc = ctx_ops->crm_ops.apply_req(ctx, apply); + } else { + CAM_WARN_RATE_LIMIT(CAM_ISP, + "No handle function in activated Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + rc = -EFAULT; + } + + if (rc) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "Apply failed in active Substate[%s] rc %d", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), rc); + return rc; +} + + + +static int __cam_isp_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc = 0; + struct cam_isp_ctx_irq_ops *irq_ops = NULL; + struct cam_context *ctx = (struct cam_context *)context; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *)ctx->ctx_priv; + + spin_lock(&ctx->lock); + + trace_cam_isp_activated_irq(ctx, ctx_isp->substate_activated, evt_id, + __cam_isp_ctx_get_event_ts(evt_id, evt_data)); + + CAM_DBG(CAM_ISP, "Enter: State %d, Substate[%s], evt id %d", + ctx->state, __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated), evt_id); + irq_ops = &ctx_isp->substate_machine_irq[ctx_isp->substate_activated]; + if (irq_ops->irq_ops[evt_id]) { + rc = irq_ops->irq_ops[evt_id](ctx_isp, evt_data); + } else { + CAM_DBG(CAM_ISP, "No handle function for Substate[%s]", + __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + if (isp_ctx_debug.enable_state_monitor_dump) + __cam_isp_ctx_dump_state_monitor_array(ctx_isp); + } + + CAM_DBG(CAM_ISP, "Exit: State %d Substate[%s]", + ctx->state, __cam_isp_ctx_substate_val_to_type( + ctx_isp->substate_activated)); + spin_unlock(&ctx->lock); + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_isp_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .acquire_hw = __cam_isp_ctx_acquire_hw_in_acquired, + .release_dev = __cam_isp_ctx_release_dev_in_top_state, + .config_dev = __cam_isp_ctx_config_dev_in_acquired, + .release_hw = __cam_isp_ctx_release_hw_in_top_state, + }, + .crm_ops = { + .link = __cam_isp_ctx_link_in_acquired, + .unlink = __cam_isp_ctx_unlink_in_acquired, + .get_dev_info = __cam_isp_ctx_get_dev_info_in_acquired, + .flush_req = __cam_isp_ctx_flush_req_in_top_state, + }, + .irq_ops = NULL, + .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, + }, + /* Ready */ + { + .ioctl_ops = { + .start_dev = __cam_isp_ctx_start_dev_in_ready, + .release_dev = __cam_isp_ctx_release_dev_in_top_state, + .config_dev = __cam_isp_ctx_config_dev_in_top_state, + .release_hw = __cam_isp_ctx_release_hw_in_top_state, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_ready, + .flush_req = __cam_isp_ctx_flush_req_in_ready, + }, + .irq_ops = NULL, + .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, + }, + /* Flushed */ + { + .ioctl_ops = { + .stop_dev = __cam_isp_ctx_stop_dev_in_activated, + .release_dev = __cam_isp_ctx_release_dev_in_activated, + .config_dev = __cam_isp_ctx_config_dev_in_flushed, + .release_hw = __cam_isp_ctx_release_hw_in_activated, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_ready, + .process_evt = __cam_isp_ctx_process_evt, + }, + .irq_ops = NULL, + .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, + }, + /* Activated */ + { + .ioctl_ops = { + .stop_dev = __cam_isp_ctx_stop_dev_in_activated, + .release_dev = __cam_isp_ctx_release_dev_in_activated, + .config_dev = __cam_isp_ctx_config_dev_in_top_state, + .release_hw = __cam_isp_ctx_release_hw_in_activated, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_activated, + .apply_req = __cam_isp_ctx_apply_req, + .flush_req = __cam_isp_ctx_flush_req_in_top_state, + .process_evt = __cam_isp_ctx_process_evt, + }, + .irq_ops = __cam_isp_ctx_handle_irq_in_activated, + .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, + }, +}; + + +static int cam_isp_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_isp_ctx_req *req_isp = NULL; + struct cam_isp_prepare_hw_update_data *hw_update_data = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + bool mem_found = false; + int rc = 0; + + struct cam_isp_context *isp_ctx = + (struct cam_isp_context *)ctx->ctx_priv; + + if (!isp_ctx) { + CAM_ERR(CAM_ISP, "Invalid isp ctx"); + return -EINVAL; + } + + CAM_INFO(CAM_ISP, "iommu fault handler for isp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + hw_update_data = &req_isp->hw_update_data; + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ISP, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &mem_found); + if (rc) + CAM_ERR(CAM_ISP, "Failed to dump pf info"); + + if (mem_found) + CAM_ERR(CAM_ISP, "Found page fault in req %lld %d", + req->request_id, rc); + } + + CAM_INFO(CAM_ISP, "Iterating over wait_list of isp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->wait_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + hw_update_data = &req_isp->hw_update_data; + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ISP, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &mem_found); + if (rc) + CAM_ERR(CAM_ISP, "Failed to dump pf info"); + + if (mem_found) + CAM_ERR(CAM_ISP, "Found page fault in req %lld %d", + req->request_id, rc); + } + + /* + * In certain scenarios we observe both overflow and SMMU pagefault + * for a particular request. If overflow is handled before page fault + * we need to traverse through pending request list because if + * bubble recovery is enabled on any request we move that request + * and all the subsequent requests to the pending list while handling + * overflow error. + */ + + CAM_INFO(CAM_ISP, + "Iterating over pending req list of isp ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->pending_req_list, list) { + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + hw_update_data = &req_isp->hw_update_data; + pf_dbg_entry = &(req->pf_data); + CAM_INFO(CAM_ISP, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &mem_found); + if (rc) + CAM_ERR(CAM_ISP, "Failed to dump pf info"); + + if (mem_found) + CAM_ERR(CAM_ISP, "Found page fault in req %lld %d", + req->request_id, rc); + } + + return rc; +} + +static int cam_isp_context_debug_register(void) +{ + isp_ctx_debug.dentry = debugfs_create_dir("camera_isp_ctx", + NULL); + + if (!isp_ctx_debug.dentry) { + CAM_ERR(CAM_ISP, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_u32("enable_state_monitor_dump", + 0644, + isp_ctx_debug.dentry, + &isp_ctx_debug.enable_state_monitor_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_state_monitor_dump"); + goto err; + } + + return 0; + +err: + debugfs_remove_recursive(isp_ctx_debug.dentry); + return -ENOMEM; +} + +int cam_isp_context_init(struct cam_isp_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *crm_node_intf, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) + +{ + int rc = -1; + int i; + + if (!ctx || !ctx_base) { + CAM_ERR(CAM_ISP, "Invalid Context"); + goto err; + } + + /* ISP context setup */ + memset(ctx, 0, sizeof(*ctx)); + + ctx->base = ctx_base; + ctx->frame_id = 0; + ctx->active_req_cnt = 0; + ctx->reported_req_id = 0; + ctx->req_info.last_bufdone_req_id = 0; + ctx->bubble_frame_cnt = 0; + ctx->hw_ctx = NULL; + ctx->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + ctx->substate_machine = cam_isp_ctx_activated_state_machine; + ctx->substate_machine_irq = cam_isp_ctx_activated_state_machine_irq; + ctx->init_timestamp = jiffies_to_msecs(jiffies); + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) { + ctx->req_base[i].req_priv = &ctx->req_isp[i]; + ctx->req_isp[i].base = &ctx->req_base[i]; + } + + /* camera context setup */ + rc = cam_context_init(ctx_base, isp_dev_name, CAM_ISP, ctx_id, + crm_node_intf, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_ISP, "Camera Context Base init failed"); + goto err; + } + + /* link camera context with isp context */ + ctx_base->state_machine = cam_isp_ctx_top_state_machine; + ctx_base->ctx_priv = ctx; + + /* initializing current state for error logging */ + for (i = 0; i < CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES; i++) { + ctx->cam_isp_ctx_state_monitor[i].curr_state = + CAM_ISP_CTX_ACTIVATED_MAX; + } + atomic64_set(&ctx->state_monitor_head, -1); + + cam_isp_context_debug_register(); +err: + return rc; +} + +int cam_isp_context_deinit(struct cam_isp_context *ctx) +{ + int rc = 0; + + if (ctx->base) + cam_context_deinit(ctx->base); + + if (ctx->substate_activated != CAM_ISP_CTX_ACTIVATED_SOF) + CAM_ERR(CAM_ISP, "ISP context Substate[%s] is invalid", + __cam_isp_ctx_substate_val_to_type( + ctx->substate_activated)); + + memset(ctx, 0, sizeof(*ctx)); + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/cam_isp_context.h b/techpack/camera/drivers/cam_isp/cam_isp_context.h new file mode 100644 index 0000000000000000000000000000000000000000..503e46526dee1aab888164e850976610cc0414a8 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/cam_isp_context.h @@ -0,0 +1,254 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_CONTEXT_H_ +#define _CAM_ISP_CONTEXT_H_ + + +#include <linux/spinlock.h> +#include <media/cam_isp.h> +#include <media/cam_defs.h> + +#include "cam_context.h" +#include "cam_isp_hw_mgr_intf.h" + +/* + * Maximum hw resource - This number is based on the maximum + * output port resource. The current maximum resource number + * is 24. + */ +#define CAM_ISP_CTX_RES_MAX 24 + +/* + * Maximum configuration entry size - This is based on the + * worst case DUAL IFE use case plus some margin. + */ +#define CAM_ISP_CTX_CFG_MAX 22 + +/* + * Maximum entries in state monitoring array for error logging + */ +#define CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES 40 + +/* forward declaration */ +struct cam_isp_context; + +/* cam isp context irq handling function type */ +typedef int (*cam_isp_hw_event_cb_func)(struct cam_isp_context *ctx_isp, + void *evt_data); + +/** + * enum cam_isp_ctx_activated_substate - sub states for activated + * + */ +enum cam_isp_ctx_activated_substate { + CAM_ISP_CTX_ACTIVATED_SOF, + CAM_ISP_CTX_ACTIVATED_APPLIED, + CAM_ISP_CTX_ACTIVATED_EPOCH, + CAM_ISP_CTX_ACTIVATED_BUBBLE, + CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED, + CAM_ISP_CTX_ACTIVATED_HW_ERROR, + CAM_ISP_CTX_ACTIVATED_HALT, + CAM_ISP_CTX_ACTIVATED_MAX, +}; + +/** + * enum cam_isp_state_change_trigger - Different types of ISP events + * + */ +enum cam_isp_state_change_trigger { + CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, + CAM_ISP_STATE_CHANGE_TRIGGER_APPLIED, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + CAM_ISP_STATE_CHANGE_TRIGGER_DONE, + CAM_ISP_STATE_CHANGE_TRIGGER_EOF, + CAM_ISP_STATE_CHANGE_TRIGGER_FLUSH, + CAM_ISP_STATE_CHANGE_TRIGGER_MAX +}; + +/** + * struct cam_isp_ctx_debug - Contains debug parameters + * + * @dentry: Debugfs entry + * @enable_state_monitor_dump: Enable isp state monitor dump + * + */ +struct cam_isp_ctx_debug { + struct dentry *dentry; + uint32_t enable_state_monitor_dump; +}; + +/** + * struct cam_isp_ctx_irq_ops - Function table for handling IRQ callbacks + * + * @irq_ops: Array of handle function pointers. + * + */ +struct cam_isp_ctx_irq_ops { + cam_isp_hw_event_cb_func irq_ops[CAM_ISP_HW_EVENT_MAX]; +}; + +/** + * struct cam_isp_ctx_req - ISP context request object + * + * @base: Common request object ponter + * @cfg: ISP hardware configuration array + * @num_cfg: Number of ISP hardware configuration entries + * @fence_map_out: Output fence mapping array + * @num_fence_map_out: Number of the output fence map + * @fence_map_in: Input fence mapping array + * @num_fence_map_in: Number of input fence map + * @num_acked: Count to track acked entried for output. + * If count equals the number of fence out, it means + * the request has been completed. + * @bubble_report: Flag to track if bubble report is active on + * current request + * @hw_update_data: HW update data for this request + * @reapply: True if reapplying after bubble + * + */ +struct cam_isp_ctx_req { + struct cam_ctx_request *base; + + struct cam_hw_update_entry cfg[CAM_ISP_CTX_CFG_MAX]; + uint32_t num_cfg; + struct cam_hw_fence_map_entry fence_map_out + [CAM_ISP_CTX_RES_MAX]; + uint32_t num_fence_map_out; + struct cam_hw_fence_map_entry fence_map_in[CAM_ISP_CTX_RES_MAX]; + uint32_t num_fence_map_in; + uint32_t num_acked; + int32_t bubble_report; + struct cam_isp_prepare_hw_update_data hw_update_data; + bool bubble_detected; + bool reapply; +}; + +/** + * struct cam_isp_context_state_monitor - ISP context state + * monitoring for + * debug purposes + * + * @curr_state: Current sub state that received req + * @trigger: Event type of incoming req + * @req_id: Request id + * @frame_id: Frame id based on SOFs + * @evt_time_stamp Current time stamp + * + */ +struct cam_isp_context_state_monitor { + enum cam_isp_ctx_activated_substate curr_state; + enum cam_isp_state_change_trigger trigger; + uint64_t req_id; + int64_t frame_id; + unsigned int evt_time_stamp; +}; + +/** + * struct cam_isp_context_req_id_info - ISP context request id + * information for bufdone. + * + *@last_bufdone_req_id: Last bufdone request id + * + */ + +struct cam_isp_context_req_id_info { + int64_t last_bufdone_req_id; +}; +/** + * + * struct cam_isp_context - ISP context object + * + * @base: Common context object pointer + * @frame_id: Frame id tracking for the isp context + * @substate_actiavted: Current substate for the activated state. + * @process_bubble: Atomic variable to check if ctx is still + * processing bubble. + * @bubble_frame_cnt: Count number of frames since the req is in bubble + * @substate_machine: ISP substate machine for external interface + * @substate_machine_irq: ISP substate machine for irq handling + * @req_base: Common request object storage + * @req_isp: ISP private request object storage + * @hw_ctx: HW object returned by the acquire device command + * @sof_timestamp_val: Captured time stamp value at sof hw event + * @boot_timestamp: Boot time stamp for a given req_id + * @active_req_cnt: Counter for the active request + * @reported_req_id: Last reported request id + * @subscribe_event: The irq event mask that CRM subscribes to, IFE + * will invoke CRM cb at those event. + * @last_applied_req_id: Last applied request id + * @state_monitor_head: Write index to the state monitoring array + * @req_info Request id information about last buf done + * @cam_isp_ctx_state_monitor: State monitoring array + * @rdi_only_context: Get context type information. + * true, if context is rdi only context + * @hw_acquired: Indicate whether HW resources are acquired + * @init_received: Indicate whether init config packet is received + * @split_acquire: Indicate whether a separate acquire is expected + * @init_timestamp: Timestamp at which this context is initialized + * + */ +struct cam_isp_context { + struct cam_context *base; + + int64_t frame_id; + enum cam_isp_ctx_activated_substate substate_activated; + atomic_t process_bubble; + uint32_t bubble_frame_cnt; + struct cam_ctx_ops *substate_machine; + struct cam_isp_ctx_irq_ops *substate_machine_irq; + + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + struct cam_isp_ctx_req req_isp[CAM_CTX_REQ_MAX]; + + void *hw_ctx; + uint64_t sof_timestamp_val; + uint64_t boot_timestamp; + int32_t active_req_cnt; + int64_t reported_req_id; + uint32_t subscribe_event; + int64_t last_applied_req_id; + atomic64_t state_monitor_head; + struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[ + CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES]; + struct cam_isp_context_req_id_info req_info; + bool rdi_only_context; + bool hw_acquired; + bool init_received; + bool split_acquire; + unsigned int init_timestamp; +}; + +/** + * cam_isp_context_init() + * + * @brief: Initialization function for the ISP context + * + * @ctx: ISP context obj to be initialized + * @bridge_ops: Bridge call back funciton + * @hw_intf: ISP hw manager interface + * @ctx_id: ID for this context + * + */ +int cam_isp_context_init(struct cam_isp_context *ctx, + struct cam_context *ctx_base, + struct cam_req_mgr_kmd_ops *bridge_ops, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); + +/** + * cam_isp_context_deinit() + * + * @brief: Deinitialize function for the ISP context + * + * @ctx: ISP context obj to be deinitialized + * + */ +int cam_isp_context_deinit(struct cam_isp_context *ctx); + + +#endif /* __CAM_ISP_CONTEXT_H__ */ diff --git a/techpack/camera/drivers/cam_isp/cam_isp_dev.c b/techpack/camera/drivers/cam_isp/cam_isp_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..9c3f33181ae6ef51d58f96ebea6b52afdf5128a7 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/cam_isp_dev.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> + +#include <media/cam_req_mgr.h> +#include "cam_isp_dev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_node.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +static struct cam_isp_dev g_isp_dev; + +static void cam_isp_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_ISP, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static const struct of_device_id cam_isp_dt_match[] = { + { + .compatible = "qcom,cam-isp" + }, + {} +}; + +static int cam_isp_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + mutex_lock(&g_isp_dev.isp_mutex); + g_isp_dev.open_cnt++; + mutex_unlock(&g_isp_dev.isp_mutex); + + return 0; +} + +static int cam_isp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_node *node = v4l2_get_subdevdata(sd); + + mutex_lock(&g_isp_dev.isp_mutex); + if (g_isp_dev.open_cnt <= 0) { + CAM_DBG(CAM_ISP, "ISP subdev is already closed"); + rc = -EINVAL; + goto end; + } + + g_isp_dev.open_cnt--; + if (!node) { + CAM_ERR(CAM_ISP, "Node ptr is NULL"); + rc = -EINVAL; + goto end; + } + + if (g_isp_dev.open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&g_isp_dev.isp_mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = { + .close = cam_isp_subdev_close, + .open = cam_isp_subdev_open, +}; + +static int cam_isp_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + int i; + + /* clean up resources */ + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_isp_context_deinit(&g_isp_dev.ctx_isp[i]); + if (rc) + CAM_ERR(CAM_ISP, "ISP context %d deinit failed", + i); + } + + rc = cam_subdev_remove(&g_isp_dev.sd); + if (rc) + CAM_ERR(CAM_ISP, "Unregister failed"); + + memset(&g_isp_dev, 0, sizeof(g_isp_dev)); + return 0; +} + +static int cam_isp_dev_probe(struct platform_device *pdev) +{ + int rc = -1; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + int iommu_hdl = -1; + + g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; + /* Initialize the v4l2 subdevice first. (create cam_node) */ + rc = cam_subdev_probe(&g_isp_dev.sd, pdev, CAM_ISP_DEV_NAME, + CAM_IFE_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_ISP, "ISP cam_subdev_probe failed!"); + goto err; + } + node = (struct cam_node *) g_isp_dev.sd.token; + + memset(&hw_mgr_intf, 0, sizeof(hw_mgr_intf)); + rc = cam_isp_hw_mgr_init(pdev->dev.of_node, &hw_mgr_intf, &iommu_hdl); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Can not initialized ISP HW manager!"); + goto unregister; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_isp_context_init(&g_isp_dev.ctx_isp[i], + &g_isp_dev.ctx[i], + &node->crm_node_intf, + &node->hw_mgr_intf, + i); + if (rc) { + CAM_ERR(CAM_ISP, "ISP context init failed!"); + goto unregister; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_isp_dev.ctx, CAM_CTX_MAX, + CAM_ISP_DEV_NAME); + if (rc) { + CAM_ERR(CAM_ISP, "ISP node init failed!"); + goto unregister; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_isp_dev_iommu_fault_handler, node); + + mutex_init(&g_isp_dev.isp_mutex); + + CAM_INFO(CAM_ISP, "Camera ISP probe complete"); + + return 0; +unregister: + rc = cam_subdev_remove(&g_isp_dev.sd); +err: + return rc; +} + + +static struct platform_driver isp_driver = { + .probe = cam_isp_dev_probe, + .remove = cam_isp_dev_remove, + .driver = { + .name = "cam_isp", + .owner = THIS_MODULE, + .of_match_table = cam_isp_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_isp_dev_init_module(void) +{ + return platform_driver_register(&isp_driver); +} + +static void __exit cam_isp_dev_exit_module(void) +{ + platform_driver_unregister(&isp_driver); +} + +module_init(cam_isp_dev_init_module); +module_exit(cam_isp_dev_exit_module); +MODULE_DESCRIPTION("MSM ISP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_isp/cam_isp_dev.h b/techpack/camera/drivers/cam_isp/cam_isp_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..cf9140eb8c8835640ea1d7df4f3dd646767924ce --- /dev/null +++ b/techpack/camera/drivers/cam_isp/cam_isp_dev.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_DEV_H_ +#define _CAM_ISP_DEV_H_ + +#include "cam_subdev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_context.h" +#include "cam_isp_context.h" + +/** + * struct cam_isp_dev - Camera ISP V4l2 device node + * + * @sd: Commone camera subdevice node + * @ctx: Isp base context storage + * @ctx_isp: Isp private context storage + * @isp_mutex: ISP dev mutex + * @open_cnt: Open device count + */ +struct cam_isp_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_isp_context ctx_isp[CAM_CTX_MAX]; + struct mutex isp_mutex; + int32_t open_cnt; +}; + +#endif /* __CAM_ISP_DEV_H__ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..33b808c934e3c95284ef5ac192e1992f6f28795d --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += hw_utils/ isp_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_hw_mgr.o cam_ife_hw_mgr.o diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..3e2620a143605f9ea2890d155bd749f835c8c420 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -0,0 +1,6915 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <soc/qcom/scm.h> +#include <uapi/media/cam_isp.h> +#include "cam_smmu_api.h" +#include "cam_req_mgr_workq.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_vfe_hw_intf.h" +#include "cam_isp_packet_parser.h" +#include "cam_ife_hw_mgr.h" +#include "cam_cdm_intf_api.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" +#include "cam_mem_mgr_api.h" +#include "cam_common_util.h" + +#define CAM_IFE_HW_ENTRIES_MAX 20 + +#define TZ_SVC_SMMU_PROGRAM 0x15 +#define TZ_SAFE_SYSCALL_ID 0x3 +#define CAM_IFE_SAFE_DISABLE 0 +#define CAM_IFE_SAFE_ENABLE 1 +#define SMMU_SE_IFE 0 + +#define CAM_ISP_PACKET_META_MAX \ + (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) + +#define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ + (CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 + 1) + +static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { + CAM_ISP_HW_CMD_GET_HFR_UPDATE, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE, + CAM_ISP_HW_CMD_UBWC_UPDATE, + CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG, + CAM_ISP_HW_CMD_UBWC_UPDATE_V2, + CAM_ISP_HW_CMD_CORE_CONFIG, + CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE_V2, +}; + +static struct cam_ife_hw_mgr g_ife_hw_mgr; + +static int cam_ife_hw_mgr_event_handler( + void *priv, + uint32_t evt_id, + void *evt_info); + +static int cam_ife_mgr_regspace_data_cb(uint32_t reg_base_type, + void *hw_mgr_ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_ife_hw_mgr_ctx *ctx = + (struct cam_ife_hw_mgr_ctx *) hw_mgr_ctx; + + *soc_info_ptr = NULL; + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + continue; + + switch (reg_base_type) { + case CAM_REG_DUMP_BASE_TYPE_CAMNOC: + case CAM_REG_DUMP_BASE_TYPE_ISP_LEFT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_LEFT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_LEFT, rc); + return rc; + } + + if (reg_base_type == CAM_REG_DUMP_BASE_TYPE_ISP_LEFT) + *reg_base_idx = 0; + else + *reg_base_idx = 1; + + *soc_info_ptr = soc_info; + break; + case CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT: + if (!hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]) + continue; + + rc = hw_mgr_res->hw_res[ + CAM_ISP_HW_SPLIT_RIGHT]->process_cmd( + hw_mgr_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT], + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, &soc_info, + sizeof(void *)); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in regspace data query split idx: %d rc : %d", + CAM_ISP_HW_SPLIT_RIGHT, rc); + return rc; + } + + *reg_base_idx = 0; + *soc_info_ptr = soc_info; + break; + default: + CAM_ERR(CAM_ISP, + "Unrecognized reg base type: %u", + reg_base_type); + return -EINVAL; + } + + break; + } + + return rc; +} + +static int cam_ife_mgr_handle_reg_dump(struct cam_ife_hw_mgr_ctx *ctx, + struct cam_cmd_buf_desc *reg_dump_buf_desc, uint32_t num_reg_dump_buf, + uint32_t meta_type) +{ + int rc = 0, i; + + if (!num_reg_dump_buf || !reg_dump_buf_desc) { + CAM_DBG(CAM_ISP, + "Invalid args for reg dump req_id: [%llu] ctx idx: [%u] meta_type: [%u] num_reg_dump_buf: [%u] reg_dump_buf_desc: [%pK]", + ctx->applied_req_id, ctx->ctx_index, meta_type, + num_reg_dump_buf, reg_dump_buf_desc); + return rc; + } + + if (!atomic_read(&ctx->cdm_done)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "Reg dump values might be from more than one request"); + + for (i = 0; i < num_reg_dump_buf; i++) { + CAM_DBG(CAM_ISP, "Reg dump cmd meta data: %u req_type: %u", + reg_dump_buf_desc[i].meta_data, meta_type); + if (reg_dump_buf_desc[i].meta_data == meta_type) { + rc = cam_soc_util_reg_dump_to_cmd_buf(ctx, + ®_dump_buf_desc[i], + ctx->applied_req_id, + cam_ife_mgr_regspace_data_cb); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump failed at idx: %d, rc: %d req_id: %llu meta type: %u", + i, rc, ctx->applied_req_id, meta_type); + return rc; + } + } + } + + return rc; +} + +static int cam_ife_notify_safe_lut_scm(bool safe_trigger) +{ + uint32_t camera_hw_version, rc = 0; + struct scm_desc desc = {0}; + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (!rc) { + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_175_V100: + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = SMMU_SE_IFE; + desc.args[1] = safe_trigger; + + CAM_DBG(CAM_ISP, "Safe scm call %d", safe_trigger); + if (scm_call2(SCM_SIP_FNID(TZ_SVC_SMMU_PROGRAM, + TZ_SAFE_SYSCALL_ID), &desc)) { + CAM_ERR(CAM_ISP, + "scm call to Enable Safe failed"); + rc = -EINVAL; + } + break; + default: + break; + } + } + + return rc; +} + +static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv, + void *hw_caps_args) +{ + int rc = 0; + int i; + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query = hw_caps_args; + struct cam_isp_query_cap_cmd query_isp; + + CAM_DBG(CAM_ISP, "enter"); + + if (copy_from_user(&query_isp, + u64_to_user_ptr(query->caps_handle), + sizeof(struct cam_isp_query_cap_cmd))) { + rc = -EFAULT; + return rc; + } + + query_isp.device_iommu.non_secure = hw_mgr->mgr_common.img_iommu_hdl; + query_isp.device_iommu.secure = hw_mgr->mgr_common.img_iommu_hdl_secure; + query_isp.cdm_iommu.non_secure = hw_mgr->mgr_common.cmd_iommu_hdl; + query_isp.cdm_iommu.secure = hw_mgr->mgr_common.cmd_iommu_hdl_secure; + query_isp.num_dev = 2; + for (i = 0; i < query_isp.num_dev; i++) { + query_isp.dev_caps[i].hw_type = CAM_ISP_HW_IFE; + query_isp.dev_caps[i].hw_version.major = 1; + query_isp.dev_caps[i].hw_version.minor = 7; + query_isp.dev_caps[i].hw_version.incr = 0; + query_isp.dev_caps[i].hw_version.reserved = 0; + } + + if (copy_to_user(u64_to_user_ptr(query->caps_handle), + &query_isp, sizeof(struct cam_isp_query_cap_cmd))) + rc = -EFAULT; + + CAM_DBG(CAM_ISP, "exit rc :%d", rc); + + return rc; +} + +static int cam_ife_hw_mgr_is_rdi_res(uint32_t res_id) +{ + int rc = 0; + + switch (res_id) { + case CAM_ISP_IFE_OUT_RES_RDI_0: + case CAM_ISP_IFE_OUT_RES_RDI_1: + case CAM_ISP_IFE_OUT_RES_RDI_2: + case CAM_ISP_IFE_OUT_RES_RDI_3: + rc = 1; + break; + default: + break; + } + + return rc; +} + +static int cam_ife_hw_mgr_reset_csid_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + int rc = 0; + struct cam_hw_intf *hw_intf; + struct cam_csid_reset_cfg_args csid_reset_args; + + csid_reset_args.reset_type = CAM_IFE_CSID_RESET_PATH; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + csid_reset_args.node_res = isp_hw_res->hw_res[i]; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + CAM_DBG(CAM_ISP, "Resetting csid hardware %d", + hw_intf->hw_idx); + if (hw_intf->hw_ops.reset) { + rc = hw_intf->hw_ops.reset(hw_intf->hw_priv, + &csid_reset_args, + sizeof(struct cam_csid_reset_cfg_args)); + if (rc <= 0) + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "RESET HW res failed: (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static int cam_ife_hw_mgr_init_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + int rc = -1; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + CAM_DBG(CAM_ISP, "enabled vfe hardware %d", + hw_intf->hw_idx); + if (hw_intf->hw_ops.init) { + rc = hw_intf->hw_ops.init(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "INIT HW res failed: (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static int cam_ife_hw_mgr_start_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res, + struct cam_ife_hw_mgr_ctx *ctx) +{ + int i; + int rc = -1; + struct cam_hw_intf *hw_intf; + + /* Start slave (which is right split) first */ + for (i = CAM_ISP_HW_SPLIT_MAX - 1; i >= 0; i--) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.start) { + rc = hw_intf->hw_ops.start(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start HW resources"); + goto err; + } + CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx, + isp_hw_res->hw_res[i]->res_id); + } else { + CAM_ERR(CAM_ISP, "function null"); + goto err; + } + } + + return 0; +err: + CAM_ERR(CAM_ISP, "Start hw res failed (type:%d, id:%d)", + isp_hw_res->res_type, isp_hw_res->res_id); + return rc; +} + +static void cam_ife_hw_mgr_stop_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + struct cam_hw_intf *hw_intf; + uint32_t dummy_args; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + + if (isp_hw_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING) + continue; + + if (hw_intf->hw_ops.stop) + hw_intf->hw_ops.stop(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + else + CAM_ERR(CAM_ISP, "stop null"); + if (hw_intf->hw_ops.process_cmd && + isp_hw_res->res_type == CAM_IFE_HW_MGR_RES_IFE_OUT) { + hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, + CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + &dummy_args, sizeof(dummy_args)); + } + } +} + +static void cam_ife_hw_mgr_deinit_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int i; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.deinit) + hw_intf->hw_ops.deinit(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + } +} + +static void cam_ife_hw_mgr_deinit_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int i = 0; + + if (!ctx->init_done) { + CAM_WARN(CAM_ISP, "ctx is not in init state"); + return; + } + + /* Deinit IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE CSID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CSID\n", __func__); + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint IFE MUX(SRC) */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deint IFE RD */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + + /* Deinit IFE OUT */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); + + ctx->init_done = false; +} + +static int cam_ife_hw_mgr_init_hw( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + int rc = 0, i; + + CAM_DBG(CAM_ISP, "INIT IFE CID ... in ctx id:%d", + ctx->ctx_index); + /* INIT IFE CID */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CID(id :%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + CAM_DBG(CAM_ISP, "INIT IFE csid ... in ctx id:%d", + ctx->ctx_index); + + /* INIT IFE csid */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE CSID(id :%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + /* INIT IFE SRC */ + CAM_DBG(CAM_ISP, "INIT IFE SRC in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE SRC (%d)", + hw_mgr_res->res_id); + goto deinit; + } + } + + /* INIT IFE BUS RD */ + CAM_DBG(CAM_ISP, "INIT IFE BUS RD in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not IFE BUS RD (%d)", + hw_mgr_res->res_id); + return rc; + } + } + + /* INIT IFE OUT */ + CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", + ctx->ctx_index); + + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_init_hw_res(&ctx->res_list_ife_out[i]); + if (rc) { + CAM_ERR(CAM_ISP, "Can not INIT IFE OUT (%d)", + ctx->res_list_ife_out[i].res_id); + goto deinit; + } + } + + return rc; +deinit: + ctx->init_done = true; + cam_ife_hw_mgr_deinit_hw(ctx); + return rc; +} + +static int cam_ife_hw_mgr_put_res( + struct list_head *src_list, + struct cam_ife_hw_mgr_res **res) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *res_ptr = NULL; + + res_ptr = *res; + if (res_ptr) + list_add_tail(&res_ptr->list, src_list); + + return rc; +} + +static int cam_ife_hw_mgr_get_res( + struct list_head *src_list, + struct cam_ife_hw_mgr_res **res) +{ + int rc = 0; + struct cam_ife_hw_mgr_res *res_ptr = NULL; + + if (!list_empty(src_list)) { + res_ptr = list_first_entry(src_list, + struct cam_ife_hw_mgr_res, list); + list_del_init(&res_ptr->list); + } else { + CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx"); + rc = -1; + } + *res = res_ptr; + + return rc; +} + +static int cam_ife_hw_mgr_free_hw_res( + struct cam_ife_hw_mgr_res *isp_hw_res) +{ + int rc = 0; + int i; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!isp_hw_res->hw_res[i]) + continue; + hw_intf = isp_hw_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.release) { + rc = hw_intf->hw_ops.release(hw_intf->hw_priv, + isp_hw_res->hw_res[i], + sizeof(struct cam_isp_resource_node)); + if (rc) + CAM_ERR(CAM_ISP, + "Release hw resource id %d failed", + isp_hw_res->res_id); + isp_hw_res->hw_res[i] = NULL; + } else + CAM_ERR(CAM_ISP, "Release null"); + } + /* caller should make sure the resource is in a list */ + list_del_init(&isp_hw_res->list); + memset(isp_hw_res, 0, sizeof(*isp_hw_res)); + INIT_LIST_HEAD(&isp_hw_res->list); + + return 0; +} + +static const char *cam_ife_hw_mgr_get_res_state( + uint32_t res_state) +{ + switch (res_state) { + case CAM_ISP_RESOURCE_STATE_UNAVAILABLE: + return "UNAVAILABLE"; + case CAM_ISP_RESOURCE_STATE_AVAILABLE: + return "AVAILABLE"; + case CAM_ISP_RESOURCE_STATE_RESERVED: + return "RESERVED"; + case CAM_ISP_RESOURCE_STATE_INIT_HW: + return "HW INIT DONE"; + case CAM_ISP_RESOURCE_STATE_STREAMING: + return "STREAMING"; + default: + return "INVALID STATE"; + } +} + +static const char *cam_ife_hw_mgr_get_csid_res_id( + uint32_t res_id) +{ + switch (res_id) { + case CAM_IFE_PIX_PATH_RES_RDI_0: + return "RDI_0"; + case CAM_IFE_PIX_PATH_RES_RDI_1: + return "RDI_1"; + case CAM_IFE_PIX_PATH_RES_RDI_2: + return "RDI_2"; + case CAM_IFE_PIX_PATH_RES_RDI_3: + return "RDI_3"; + case CAM_IFE_PIX_PATH_RES_IPP: + return "IPP"; + case CAM_IFE_PIX_PATH_RES_PPP: + return "PPP"; + default: + return "INVALID"; + } +} + +static const char *cam_ife_hw_mgr_get_src_res_id( + uint32_t res_id) +{ + switch (res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + return "CAMIF"; + case CAM_ISP_HW_VFE_IN_TESTGEN: + return "TESTGEN"; + case CAM_ISP_HW_VFE_IN_RD: + return "BUS_RD"; + case CAM_ISP_HW_VFE_IN_RDI0: + return "RDI_0"; + case CAM_ISP_HW_VFE_IN_RDI1: + return "RDI_1"; + case CAM_ISP_HW_VFE_IN_RDI2: + return "RDI_2"; + case CAM_ISP_HW_VFE_IN_RDI3: + return "RDI_3"; + case CAM_ISP_HW_VFE_IN_PDLIB: + return "PDLIB"; + case CAM_ISP_HW_VFE_IN_LCR: + return "LCR"; + default: + return "INVALID"; + } +} + +static void cam_ife_hw_mgr_dump_src_acq_info( + struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx, + uint32_t num_pix_port, uint32_t num_rdi_port) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_resource_node *hw_res = NULL; + int i = 0; + + CAM_INFO(CAM_ISP, + "Acquired HW for ctx: %u with pix_port: %u rdi_port: %u", + hwr_mgr_ctx->ctx_index, num_pix_port, num_rdi_port); + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } +} + +static void cam_ife_hw_mgr_dump_acq_data( + struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_resource_node *hw_res = NULL; + struct timespec64 *ts = NULL; + uint64_t ms, tmp, hrs, min, sec; + int i = 0, j = 0; + + ts = &hwr_mgr_ctx->ts; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + sec = do_div(tmp, 60); + min = do_div(tmp, 60); + hrs = do_div(tmp, 24); + + CAM_INFO(CAM_ISP, + "**** %llu:%llu:%llu.%llu ctx_idx: %u rdi_only: %s is_dual: %s acquired ****", + hrs, min, sec, ms, + hwr_mgr_ctx->ctx_index, + (hwr_mgr_ctx->is_rdi_only_context ? "true" : "false"), + (hwr_mgr_ctx->is_dual ? "true" : "false")); + + /* Iterate over CID resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_cid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) { + CAM_INFO(CAM_ISP, + "CID split_id: %d res_id: %u hw_idx: %u state: %s", + i, hw_res->res_id, + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + } + + /* Iterate over CSID resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "CSID split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_csid_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE IN resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE RD resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src_rd split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE OUT resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + hw_mgr_res = &hwr_mgr_ctx->res_list_ife_out[i]; + hw_res = hw_mgr_res->hw_res[j]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE out split_id: %d res_id: 0x%x hw_idx: %u state: %s", + j, hw_res->res_id, + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } +} + +static int cam_ife_mgr_csid_stop_hw( + struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list, + uint32_t base_idx, uint32_t stop_cmd) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *isp_res; + struct cam_isp_resource_node *stop_res[CAM_IFE_PIX_PATH_RES_MAX - 1]; + struct cam_csid_hw_stop_args stop; + struct cam_hw_intf *hw_intf; + uint32_t i, cnt; + + cnt = 0; + list_for_each_entry(hw_mgr_res, stop_list, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i] || + (hw_mgr_res->hw_res[i]->res_state != + CAM_ISP_RESOURCE_STATE_STREAMING)) + continue; + + isp_res = hw_mgr_res->hw_res[i]; + if (isp_res->hw_intf->hw_idx != base_idx) + continue; + CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u", + base_idx, isp_res->res_id, cnt); + stop_res[cnt] = isp_res; + cnt++; + } + } + + if (cnt) { + hw_intf = stop_res[0]->hw_intf; + stop.num_res = cnt; + stop.node_res = stop_res; + stop.stop_cmd = stop_cmd; + hw_intf->hw_ops.stop(hw_intf->hw_priv, &stop, sizeof(stop)); + } + + return 0; +} + +static int cam_ife_hw_mgr_release_hw_for_ctx( + struct cam_ife_hw_mgr_ctx *ife_ctx) +{ + uint32_t i; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp; + + /* ife leaf resource */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_out[i]); + + /* ife bus rd resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife source resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife csid resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_csid, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife cid resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_cid, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + + /* ife root node */ + if (ife_ctx->res_list_ife_in.res_type != CAM_IFE_HW_MGR_RES_UNINIT) + cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_in); + + /* clean up the callback function */ + ife_ctx->common.cb_priv = NULL; + memset(ife_ctx->common.event_cb, 0, sizeof(ife_ctx->common.event_cb)); + + CAM_DBG(CAM_ISP, "release context completed ctx id:%d", + ife_ctx->ctx_index); + + return 0; +} + + +static int cam_ife_hw_mgr_put_ctx( + struct list_head *src_list, + struct cam_ife_hw_mgr_ctx **ife_ctx) +{ + int rc = 0; + struct cam_ife_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + ctx_ptr = *ife_ctx; + if (ctx_ptr) + list_add_tail(&ctx_ptr->list, src_list); + *ife_ctx = NULL; + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + return rc; +} + +static int cam_ife_hw_mgr_get_ctx( + struct list_head *src_list, + struct cam_ife_hw_mgr_ctx **ife_ctx) +{ + int rc = 0; + struct cam_ife_hw_mgr_ctx *ctx_ptr = NULL; + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + if (!list_empty(src_list)) { + ctx_ptr = list_first_entry(src_list, + struct cam_ife_hw_mgr_ctx, list); + list_del_init(&ctx_ptr->list); + } else { + CAM_ERR(CAM_ISP, "No more free ife hw mgr ctx"); + rc = -1; + } + *ife_ctx = ctx_ptr; + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + + return rc; +} + +static void cam_ife_mgr_add_base_info( + struct cam_ife_hw_mgr_ctx *ctx, + enum cam_isp_hw_split_id split_id, + uint32_t base_idx) +{ + uint32_t i; + + if (!ctx->num_base) { + ctx->base[0].split_id = split_id; + ctx->base[0].idx = base_idx; + ctx->num_base++; + CAM_DBG(CAM_ISP, + "Add split id = %d for base idx = %d num_base=%d", + split_id, base_idx, ctx->num_base); + } else { + /*Check if base index already exists in the list */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == base_idx) { + if (split_id != CAM_ISP_HW_SPLIT_MAX && + ctx->base[i].split_id == + CAM_ISP_HW_SPLIT_MAX) + ctx->base[i].split_id = split_id; + + break; + } + } + + if (i == ctx->num_base) { + ctx->base[ctx->num_base].split_id = split_id; + ctx->base[ctx->num_base].idx = base_idx; + ctx->num_base++; + CAM_DBG(CAM_ISP, + "Add split_id=%d for base idx=%d num_base=%d", + split_id, base_idx, ctx->num_base); + } + } +} + +static int cam_ife_mgr_process_base_info( + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res = NULL; + uint32_t i; + + if (list_empty(&ctx->res_list_ife_src)) { + CAM_ERR(CAM_ISP, "Mux List empty"); + return -ENODEV; + } + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + cam_ife_mgr_add_base_info(ctx, i, + res->hw_intf->hw_idx); + CAM_DBG(CAM_ISP, "add base info for hw %d", + res->hw_intf->hw_idx); + } + } + CAM_DBG(CAM_ISP, "ctx base num = %d", ctx->num_base); + + return 0; +} + +static int cam_ife_hw_mgr_acquire_res_bus_rd( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_ife_hw_mgr_res *ife_in_rd_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *ife_src_res; + int i; + + CAM_DBG(CAM_ISP, "Enter"); + + list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { + if (ife_src_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_in_rd_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, + &ife_in_rd_res); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.priv = ife_ctx; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!ife_src_res->hw_res[i]) + continue; + + hw_intf = ife_src_res->hw_res[i]->hw_intf; + if (i == CAM_ISP_HW_SPLIT_LEFT) { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (ife_src_res->is_dual_vfe) { + /*TBD */ + vfe_acquire.vfe_out.is_master = 1; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } else { + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + 0; + } + } else { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + vfe_acquire.rsrc_type); + goto err; + } + + ife_in_rd_res->hw_res[i] = + vfe_acquire.vfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + ife_in_rd_res->hw_res[i]->res_type, + ife_in_rd_res->hw_res[i]->res_id); + + } + ife_in_rd_res->is_dual_vfe = in_port->usage_type; + ife_in_rd_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_VFE_BUS_RD; + } + + return 0; +err: + CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_ife_hw_mgr_res *ife_src_res, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_isp_out_port_generic_info *out_port = NULL; + struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_hw_intf *hw_intf; + uint32_t i, vfe_out_res_id, vfe_in_res_id; + + /* take left resource */ + vfe_in_res_id = ife_src_res->hw_res[0]->res_id; + + switch (vfe_in_res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_0; + break; + case CAM_ISP_HW_VFE_IN_RDI1: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_1; + break; + case CAM_ISP_HW_VFE_IN_RDI2: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_2; + break; + case CAM_ISP_HW_VFE_IN_RDI3: + vfe_out_res_id = CAM_ISP_IFE_OUT_RES_RDI_3; + break; + default: + CAM_ERR(CAM_ISP, "invalid resource type"); + goto err; + } + CAM_DBG(CAM_ISP, "vfe_in_res_id = %d, vfe_out_red_id = %d", + vfe_in_res_id, vfe_out_res_id); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + + ife_out_res = &ife_ctx->res_list_ife_out[vfe_out_res_id & 0xFF]; + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + + CAM_DBG(CAM_ISP, "i = %d, vfe_out_res_id = %d, out_port: %d", + i, vfe_out_res_id, out_port->res_type); + + if (vfe_out_res_id != out_port->res_type) + continue; + + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.priv = ife_ctx; + vfe_acquire.vfe_out.out_port_info = out_port; + vfe_acquire.vfe_out.split_id = CAM_ISP_HW_SPLIT_LEFT; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.is_dual = 0; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + hw_intf = ife_src_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, "Can not acquire out resource 0x%x", + out_port->res_type); + goto err; + } + break; + } + + if (i == in_port->num_out_res) { + CAM_ERR(CAM_ISP, + "Cannot acquire out resource, i=%d, num_out_res=%d", + i, in_port->num_out_res); + goto err; + } + + ife_out_res->hw_res[0] = vfe_acquire.vfe_out.rsrc_node; + ife_out_res->is_dual_vfe = 0; + ife_out_res->res_id = vfe_out_res_id; + ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_VFE_OUT; + ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); + + return 0; +err: + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_ife_hw_mgr_res *ife_src_res, + struct cam_isp_in_port_generic_info *in_port, + bool acquire_lcr) +{ + int rc = -1; + uint32_t i, j, k; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_isp_out_port_generic_info *out_port; + struct cam_ife_hw_mgr_res *ife_out_res; + struct cam_hw_intf *hw_intf; + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + k = out_port->res_type & 0xFF; + if (k >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "invalid output resource type 0x%x", + out_port->res_type); + continue; + } + + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + continue; + + if ((acquire_lcr && + out_port->res_type != CAM_ISP_IFE_OUT_RES_LCR) || + (!acquire_lcr && + out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR)) + continue; + + if ((out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD && + ife_src_res->res_id != CAM_ISP_HW_VFE_IN_PDLIB) || + (ife_src_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB && + out_port->res_type != CAM_ISP_IFE_OUT_RES_2PD)) + continue; + + CAM_DBG(CAM_ISP, "res_type 0x%x", out_port->res_type); + + ife_out_res = &ife_ctx->res_list_ife_out[k]; + ife_out_res->is_dual_vfe = in_port->usage_type; + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.priv = ife_ctx; + vfe_acquire.vfe_out.out_port_info = out_port; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!ife_src_res->hw_res[j]) + continue; + + hw_intf = ife_src_res->hw_res[j]->hw_intf; + + if (j == CAM_ISP_HW_SPLIT_LEFT) { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (ife_src_res->is_dual_vfe) { + /*TBD */ + vfe_acquire.vfe_out.is_master = 1; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } else { + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + 0; + } + } else { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + out_port->res_type); + goto err; + } + + ife_out_res->hw_res[j] = + vfe_acquire.vfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + ife_out_res->hw_res[j]->res_type, + ife_out_res->hw_res[j]->res_id); + + } + ife_out_res->res_type = + (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_VFE_OUT; + ife_out_res->res_id = out_port->res_type; + ife_out_res->parent = ife_src_res; + ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); + } + + return 0; +err: + /* release resource at the entry function */ + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_out( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + struct cam_ife_hw_mgr_res *ife_src_res; + + list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { + if (ife_src_res->num_children) + continue; + + switch (ife_src_res->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_RD: + rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, + ife_src_res, in_port, false); + break; + case CAM_ISP_HW_VFE_IN_LCR: + rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, + ife_src_res, in_port, true); + break; + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + rc = cam_ife_hw_mgr_acquire_res_ife_out_rdi(ife_ctx, + ife_src_res, in_port); + break; + default: + CAM_ERR(CAM_ISP, "Unknown IFE SRC resource: %d", + ife_src_res->res_id); + break; + } + if (rc) + goto err; + } + + return 0; +err: + /* release resource on entry function */ + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_ife_rd_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -1; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + int vfe_idx = -1, i = 0; + + ife_hw_mgr = ife_ctx->hw_mgr; + + CAM_DBG(CAM_ISP, "Enter"); + list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { + if (csid_res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0) { + CAM_DBG(CAM_ISP, "not RDI0: %d", csid_res->res_id); + continue; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, + &ife_src_res); + + CAM_DBG(CAM_ISP, "csid_res_id %d", csid_res->res_id); + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + + hw_intf = + ife_hw_mgr->ife_devices[csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx]; + + vfe_idx = csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx; + + /* + * fill in more acquire information as needed + */ + if (ife_src_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT] = + vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id); + + if (!ife_src_res->is_dual_vfe) + goto acq; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + CAM_DBG(CAM_ISP, "vfe_idx %d is acquired", + vfe_idx); + continue; + } + + hw_intf = ife_hw_mgr->ife_devices[i]; + + /* fill in more acquire information as needed */ + if (i == CAM_ISP_HW_SPLIT_RIGHT) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + } +acq: + /* + * It should be one to one mapping between + * csid resource and ife source resource + */ + csid_res->child[0] = ife_src_res; + ife_src_res->parent = csid_res; + csid_res->child[csid_res->num_children++] = ife_src_res; + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", + csid_res->res_id, csid_res->num_children, + ife_src_res->res_id); + } + +err: + /* release resource at the entry function */ + CAM_DBG(CAM_ISP, "Exit rc %d", rc); + return rc; +} + +static int cam_convert_hw_idx_to_ife_hw_num(int hw_idx) +{ + uint32_t hw_version, rc = 0; + + rc = cam_cpas_get_cpas_hw_version(&hw_version); + if (!rc) { + switch (hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + case CAM_CPAS_TITAN_480_V100: + if (hw_idx == 0) + return CAM_ISP_IFE0_HW; + else if (hw_idx == 1) + return CAM_ISP_IFE1_HW; + else if (hw_idx == 2) + return CAM_ISP_IFE0_LITE_HW; + else if (hw_idx == 3) + return CAM_ISP_IFE1_LITE_HW; + else if (hw_idx == 4) + return CAM_ISP_IFE2_LITE_HW; + break; + default: + CAM_ERR(CAM_ISP, "Invalid hw_version: 0x%X", + hw_version); + rc = -EINVAL; + break; + } + } + + return rc; +} + +static int cam_convert_rdi_out_res_id_to_src(int res_id) +{ + if (res_id == CAM_ISP_IFE_OUT_RES_RDI_0) + return CAM_ISP_HW_VFE_IN_RDI0; + else if (res_id == CAM_ISP_IFE_OUT_RES_RDI_1) + return CAM_ISP_HW_VFE_IN_RDI1; + else if (res_id == CAM_ISP_IFE_OUT_RES_RDI_2) + return CAM_ISP_HW_VFE_IN_RDI2; + else if (res_id == CAM_ISP_IFE_OUT_RES_RDI_3) + return CAM_ISP_HW_VFE_IN_RDI3; + return CAM_ISP_HW_VFE_IN_MAX; +} + +static int cam_convert_res_id_to_hw_path(int res_id) +{ + if (res_id == CAM_ISP_HW_VFE_IN_LCR) + return CAM_ISP_LCR_PATH; + else if (res_id == CAM_ISP_HW_VFE_IN_PDLIB) + return CAM_ISP_PPP_PATH; + else if (res_id == CAM_ISP_HW_VFE_IN_CAMIF) + return CAM_ISP_PXL_PATH; + else if (res_id == CAM_ISP_HW_VFE_IN_RDI0) + return CAM_ISP_RDI0_PATH; + else if (res_id == CAM_ISP_HW_VFE_IN_RDI1) + return CAM_ISP_RDI1_PATH; + else if (res_id == CAM_ISP_HW_VFE_IN_RDI2) + return CAM_ISP_RDI2_PATH; + else if (res_id == CAM_ISP_HW_VFE_IN_RDI3) + return CAM_ISP_RDI3_PATH; + return 0; +} + +static int cam_ife_hw_mgr_acquire_res_ife_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + bool acquire_lcr, uint32_t *acquired_hw_id, + uint32_t *acquired_hw_path) +{ + int rc = -1; + int i; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { + if (csid_res->num_children && !acquire_lcr) + continue; + + if (acquire_lcr && csid_res->res_id != CAM_IFE_PIX_PATH_RES_IPP) + continue; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, + &ife_src_res); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.priv = ife_ctx; + vfe_acquire.event_cb = cam_ife_hw_mgr_event_handler; + + switch (csid_res->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (!acquire_lcr) + vfe_acquire.vfe_in.res_id = + CAM_ISP_HW_VFE_IN_CAMIF; + else + vfe_acquire.vfe_in.res_id = + CAM_ISP_HW_VFE_IN_LCR; + if (csid_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + else + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_NONE; + + break; + case CAM_IFE_PIX_PATH_RES_PPP: + vfe_acquire.vfe_in.res_id = + CAM_ISP_HW_VFE_IN_PDLIB; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI0; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_IFE_PIX_PATH_RES_RDI_1: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI1; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_IFE_PIX_PATH_RES_RDI_2: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI2; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + case CAM_IFE_PIX_PATH_RES_RDI_3: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RDI3; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + break; + default: + CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node"); + goto err; + } + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!csid_res->hw_res[i]) + continue; + + hw_intf = ife_hw_mgr->ife_devices[ + csid_res->hw_res[i]->hw_intf->hw_idx]; + + /* fill in more acquire information as needed */ + /* slave Camif resource, */ + if (i == CAM_ISP_HW_SPLIT_RIGHT && + ife_src_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + + *acquired_hw_id |= + cam_convert_hw_idx_to_ife_hw_num( + hw_intf->hw_idx); + + if (i >= CAM_MAX_HW_SPLIT) { + CAM_ERR(CAM_ISP, "HW split is invalid: %d", i); + return -EINVAL; + } + + acquired_hw_path[i] |= cam_convert_res_id_to_hw_path( + ife_src_res->hw_res[i]->res_id); + + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + + } + + ife_src_res->parent = csid_res; + csid_res->child[csid_res->num_children++] = ife_src_res; + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", + csid_res->res_id, csid_res->num_children, + ife_src_res->res_id); + } + + return 0; +err: + /* release resource at the entry function */ + return rc; +} + +static int cam_ife_mgr_acquire_cid_res( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + struct cam_ife_hw_mgr_res **cid_res, + enum cam_ife_pix_path_res_id path_res_id) +{ + int rc = -1; + int i, j; + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator; + struct cam_csid_hw_reserve_resource_args csid_acquire; + uint32_t acquired_cnt = 0; + struct cam_isp_out_port_generic_info *out_port = NULL; + + ife_hw_mgr = ife_ctx->hw_mgr; + *cid_res = NULL; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + cid_res_temp = *cid_res; + + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + csid_acquire.res_id = path_res_id; + CAM_DBG(CAM_ISP, "path_res_id %d", path_res_id); + + if (in_port->num_out_res) + out_port = &(in_port->data[0]); + + /* Try acquiring CID resource from previously acquired HW */ + list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid, + list) { + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!cid_res_iterator->hw_res[i]) + continue; + + if (in_port->num_out_res && + ((cid_res_iterator->is_secure == 1 && + out_port->secure_mode == 0) || + (cid_res_iterator->is_secure == 0 && + out_port->secure_mode == 1))) + continue; + + if (!in_port->num_out_res && + cid_res_iterator->is_secure == 1) + continue; + + hw_intf = cid_res_iterator->hw_res[i]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "No ife cid resource from hw %d", + hw_intf->hw_idx); + continue; + } + + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + + CAM_DBG(CAM_ISP, + "acquired from old csid(%s)=%d CID rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); + + if (in_port->usage_type && acquired_cnt == 1 && + path_res_id == CAM_IFE_PIX_PATH_RES_IPP) + /* + * Continue to acquire Right for IPP. + * Dual IFE for RDI and PPP is not currently + * supported. + */ + + continue; + + if (acquired_cnt) + /* + * If successfully acquired CID from + * previously acquired HW, skip the next + * part + */ + goto acquire_successful; + } + } + + /* Acquire Left if not already acquired */ + if (ife_ctx->is_fe_enable) { + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } + } else { + for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + if (i == -1 || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } + } + + +acquire_successful: + CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", + in_port->usage_type); + + cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID; + /* CID(DT_ID) value of acquire device, require for path */ + cid_res_temp->res_id = csid_acquire.node_res->res_id; + cid_res_temp->is_dual_vfe = in_port->usage_type; + ife_ctx->is_dual = (bool)in_port->usage_type; + + if (in_port->num_out_res) + cid_res_temp->is_secure = out_port->secure_mode; + + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res); + + /* + * Acquire Right if not already acquired. + * Dual IFE for RDI and PPP is not currently supported. + */ + if (cid_res_temp->is_dual_vfe && path_res_id + == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { + csid_acquire.node_res = NULL; + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { + if (!ife_hw_mgr->csid_devices[j]) + continue; + + if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx) + continue; + + hw_intf = ife_hw_mgr->csid_devices[j]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else + break; + } + + if (j == CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, + "Can not acquire ife csid rdi resource"); + goto end; + } + cid_res_temp->hw_res[1] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", + in_port->usage_type); + } + cid_res_temp->parent = &ife_ctx->res_list_ife_in; + ife_ctx->res_list_ife_in.child[ + ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; + CAM_DBG(CAM_ISP, "IFE IN num_children = %d", + ife_ctx->res_list_ife_in.num_children); + + return 0; +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res); +end: + return rc; + +} + +static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + bool is_ipp, + bool crop_enable) +{ + int rc = -1; + int i; + int master_idx = -1; + + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *cid_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_hw_reserve_resource_args csid_acquire; + enum cam_ife_pix_path_res_id path_res_id; + + ife_hw_mgr = ife_ctx->hw_mgr; + /* get cid resource */ + if (is_ipp) + path_res_id = CAM_IFE_PIX_PATH_RES_IPP; + else + path_res_id = CAM_IFE_PIX_PATH_RES_PPP; + + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, + path_res_id); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto end; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + csid_res->res_type = + (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_PIX_PATH; + + csid_res->res_id = path_res_id; + + if (in_port->usage_type && is_ipp) + csid_res->is_dual_vfe = 1; + else { + csid_res->is_dual_vfe = 0; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + } + + CAM_DBG(CAM_ISP, "CSID Acq: E"); + /* IPP resource needs to be from same HW as CID resource */ + for (i = 0; i <= csid_res->is_dual_vfe; i++) { + CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); + + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = path_res_id; + csid_acquire.cid = cid_res->hw_res[i]->res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + csid_acquire.node_res = NULL; + csid_acquire.crop_enable = crop_enable; + csid_acquire.drop_enable = false; + + hw_intf = cid_res->hw_res[i]->hw_intf; + + if (csid_res->is_dual_vfe) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + master_idx = hw_intf->hw_idx; + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + } else { + if (master_idx == -1) { + CAM_ERR(CAM_ISP, + "No Master found"); + goto put_res; + } + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + csid_acquire.master_idx = master_idx; + } + } + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_ERR(CAM_ISP, + "Cannot acquire ife csid pxl path rsrc %s", + (is_ipp) ? "IPP" : "PPP"); + goto put_res; + } + + csid_res->hw_res[i] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, + "acquired csid(%s)=%d pxl path rsrc %s successfully", + (i == 0) ? "left" : "right", hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP"); + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = csid_res; + + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); + return 0; +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: + return rc; +} + +static enum cam_ife_pix_path_res_id + cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + uint32_t out_port_type) +{ + enum cam_ife_pix_path_res_id path_id; + CAM_DBG(CAM_ISP, "out_port_type %x", out_port_type); + + switch (out_port_type) { + case CAM_ISP_IFE_OUT_RES_RDI_0: + path_id = CAM_IFE_PIX_PATH_RES_RDI_0; + break; + case CAM_ISP_IFE_OUT_RES_RDI_1: + path_id = CAM_IFE_PIX_PATH_RES_RDI_1; + break; + case CAM_ISP_IFE_OUT_RES_RDI_2: + path_id = CAM_IFE_PIX_PATH_RES_RDI_2; + break; + case CAM_ISP_IFE_OUT_RES_RDI_3: + path_id = CAM_IFE_PIX_PATH_RES_RDI_3; + break; + default: + path_id = CAM_IFE_PIX_PATH_RES_MAX; + CAM_DBG(CAM_ISP, "maximum rdi output type exceeded"); + break; + } + + CAM_DBG(CAM_ISP, "out_port %x path_id %d", out_port_type, path_id); + + return path_id; +} + +static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -EINVAL; + int i; + + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *cid_res; + struct cam_hw_intf *hw_intf; + struct cam_isp_out_port_generic_info *out_port; + struct cam_csid_hw_reserve_resource_args csid_acquire; + enum cam_ife_pix_path_res_id path_res_id; + + ife_hw_mgr = ife_ctx->hw_mgr; + + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + path_res_id = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type); + if (path_res_id == CAM_IFE_PIX_PATH_RES_MAX) + continue; + + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, + path_res_id); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto end; + } + + /* For each RDI we need CID + PATH resource */ + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &csid_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto end; + } + + memset(&csid_acquire, 0, sizeof(csid_acquire)); + csid_acquire.res_id = path_res_id; + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.cid = cid_res->hw_res[0]->res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = out_port; + csid_acquire.node_res = NULL; + + /* + * Enable RDI pixel drop by default. CSID will enable only for + * ver 480 HW to allow userspace to control pixel drop pattern. + */ + csid_acquire.drop_enable = true; + csid_acquire.crop_enable = true; + + if (in_port->usage_type) + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_MASTER; + else + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + + hw_intf = cid_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_ERR(CAM_ISP, + "CSID Path reserve failed hw=%d rc=%d cid=%d", + hw_intf->hw_idx, rc, + cid_res->hw_res[0]->res_id); + + goto put_res; + } + + if (csid_acquire.node_res == NULL) { + CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed"); + + goto put_res; + } + + csid_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_id = csid_acquire.res_id; + csid_res->is_dual_vfe = 0; + csid_res->hw_res[0] = csid_acquire.node_res; + csid_res->hw_res[1] = NULL; + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = + csid_res; + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + } + + return 0; +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_root( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port) +{ + int rc = -1; + + if (ife_ctx->res_list_ife_in.res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + /* first acquire */ + ife_ctx->res_list_ife_in.res_type = CAM_IFE_HW_MGR_RES_ROOT; + ife_ctx->res_list_ife_in.res_id = in_port->res_type; + ife_ctx->res_list_ife_in.is_dual_vfe = in_port->usage_type; + } else if ((ife_ctx->res_list_ife_in.res_id != + in_port->res_type) && (!ife_ctx->is_fe_enable)) { + CAM_ERR(CAM_ISP, "No Free resource for this context"); + goto err; + } else { + /* else do nothing */ + } + return 0; +err: + /* release resource in entry function */ + return rc; +} + +static int cam_ife_mgr_check_and_update_fe_v0( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + int i; + struct cam_isp_in_port_info *in_port = NULL; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + + in_port = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || + (in_port->num_out_res <= 0)) { + CAM_ERR(CAM_ISP, "Invalid num output res %u", + in_port->num_out_res); + return -EINVAL; + } + + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, + in_port->res_type); + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_ctx->is_fe_enable = true; + break; + } + + in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port + + in_port_length); + } + CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + + return 0; +} + +static int cam_ife_mgr_check_and_update_fe_v2( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + int i; + struct cam_isp_in_port_info_v2 *in_port = NULL; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + + in_port = (struct cam_isp_in_port_info_v2 *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if ((in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) || + (in_port->num_out_res <= 0)) { + CAM_ERR(CAM_ISP, "Invalid num output res %u", + in_port->num_out_res); + return -EINVAL; + } + + in_port_length = sizeof(struct cam_isp_in_port_info_v2) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info_v2); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, + in_port->res_type); + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_ctx->is_fe_enable = true; + break; + } + + in_port = (struct cam_isp_in_port_info_v2 *) + ((uint8_t *)in_port + in_port_length); + } + CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + + return 0; +} + +static int cam_ife_mgr_check_and_update_fe( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + uint32_t major_ver = 0, minor_ver = 0; + + if (acquire_hw_info == NULL || ife_ctx == NULL) + return -EINVAL; + + major_ver = (acquire_hw_info->common_info_version >> 12) & 0xF; + minor_ver = (acquire_hw_info->common_info_version) & 0xFFF; + + switch (major_ver) { + case 1: + return cam_ife_mgr_check_and_update_fe_v0( + ife_ctx, acquire_hw_info); + case 2: + return cam_ife_mgr_check_and_update_fe_v2( + ife_ctx, acquire_hw_info); + break; + default: + CAM_ERR(CAM_ISP, "Invalid ver of common info from user"); + return -EINVAL; + } + + return 0; +} + +static int cam_ife_hw_mgr_preprocess_port( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + int *ipp_count, + int *rdi_count, + int *ppp_count, + int *ife_rd_count, + int *lcr_count) +{ + int ipp_num = 0; + int rdi_num = 0; + int ppp_num = 0; + int ife_rd_num = 0; + int lcr_num = 0; + uint32_t i; + struct cam_isp_out_port_generic_info *out_port; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_rd_num++; + } else { + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + rdi_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) + ppp_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_LCR) + lcr_num++; + else { + CAM_DBG(CAM_ISP, "out_res_type %d", + out_port->res_type); + ipp_num++; + } + } + } + + *ipp_count = ipp_num; + *rdi_count = rdi_num; + *ppp_count = ppp_num; + *ife_rd_count = ife_rd_num; + *lcr_count = lcr_num; + + CAM_DBG(CAM_ISP, "rdi: %d ipp: %d ppp: %d ife_rd: %d lcr: %d", + rdi_num, ipp_num, ppp_num, ife_rd_num, lcr_num); + + return 0; +} + +static int cam_ife_mgr_acquire_hw_for_ctx( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_generic_info *in_port, + uint32_t *num_pix_port, uint32_t *num_rdi_port, + uint32_t *acquired_hw_id, uint32_t *acquired_hw_path) +{ + int rc = -1; + int is_dual_vfe = 0; + int ipp_count = 0; + int rdi_count = 0; + int ppp_count = 0; + int ife_rd_count = 0; + int lcr_count = 0; + bool crop_enable = true; + + is_dual_vfe = in_port->usage_type; + + /* get root node resource */ + rc = cam_ife_hw_mgr_acquire_res_root(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, "Can not acquire csid rx resource"); + goto err; + } + + cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, &ipp_count, + &rdi_count, &ppp_count, &ife_rd_count, &lcr_count); + + if (!ipp_count && !rdi_count && !ppp_count && !ife_rd_count + && !lcr_count) { + CAM_ERR(CAM_ISP, + "No PIX or RDI or PPP or IFE RD or LCR resource"); + return -EINVAL; + } + + if (ipp_count || lcr_count) { + /* get ife csid IPP resource */ + rc = cam_ife_hw_mgr_acquire_res_ife_csid_pxl(ife_ctx, + in_port, true, crop_enable); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID IPP/LCR resource Failed"); + goto err; + } + } + + if (rdi_count) { + /* get ife csid RDI resource */ + rc = cam_ife_hw_mgr_acquire_res_ife_csid_rdi(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID RDI resource Failed"); + goto err; + } + } + + if (ppp_count) { + /* get ife csid PPP resource */ + + /* If both IPP and PPP paths are requested with the same vc dt + * it is implied that the sensor is a type 3 PD sensor. Crop + * must be enabled for this sensor on PPP path as well. + */ + if (!ipp_count) + crop_enable = false; + + rc = cam_ife_hw_mgr_acquire_res_ife_csid_pxl(ife_ctx, + in_port, false, crop_enable); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID PPP resource Failed"); + goto err; + } + } + + /* get ife src resource */ + if (ife_rd_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_rd_src(ife_ctx, in_port); + rc = cam_ife_hw_mgr_acquire_res_bus_rd(ife_ctx, in_port); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE RD SRC resource Failed"); + goto err; + } + } else if (ipp_count || ppp_count || rdi_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, + in_port, false, + acquired_hw_id, acquired_hw_path); + + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE IPP/PPP SRC resource Failed"); + goto err; + } + } + + if (lcr_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port, true, + acquired_hw_id, acquired_hw_path); + + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE LCR SRC resource Failed"); + goto err; + } + } + + CAM_DBG(CAM_ISP, "Acquiring IFE OUT resource..."); + rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed"); + goto err; + } + + *num_pix_port = ipp_count + ppp_count + ife_rd_count + lcr_count; + *num_rdi_port = rdi_count; + + return 0; +err: + /* release resource at the acquire entry funciton */ + return rc; +} + +void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata, + enum cam_cdm_cb_status status, uint64_t cookie) +{ + struct cam_isp_prepare_hw_update_data *hw_update_data = NULL; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + + if (!userdata) { + CAM_ERR(CAM_ISP, "Invalid args"); + return; + } + + hw_update_data = (struct cam_isp_prepare_hw_update_data *)userdata; + ctx = (struct cam_ife_hw_mgr_ctx *)hw_update_data->ife_mgr_ctx; + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + complete_all(&ctx->config_done_complete); + atomic_set(&ctx->cdm_done, 1); + if (g_ife_hw_mgr.debug_cfg.per_req_reg_dump) + cam_ife_mgr_handle_reg_dump(ctx, + hw_update_data->reg_dump_buf_desc, + hw_update_data->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST); + + CAM_DBG(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", + handle, userdata, status, cookie, ctx->ctx_index); + } else { + CAM_WARN(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); + } +} + +static int cam_ife_mgr_acquire_get_unified_structure_v0( + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t offset, uint32_t *input_size, + struct cam_isp_in_port_generic_info **in_port) +{ + struct cam_isp_in_port_info *in = NULL; + uint32_t in_port_length = 0; + struct cam_isp_in_port_generic_info *port_info = NULL; + int32_t rc = 0, i; + + in = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset + *input_size); + + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + + *input_size += in_port_length; + + if ((*input_size) > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "Input is not proper"); + rc = -EINVAL; + } + + port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), GFP_KERNEL); + + if (!port_info) + return -ENOMEM; + + port_info->major_ver = + (acquire_hw_info->input_info_version >> 16) & 0xFFFF; + port_info->minor_ver = + acquire_hw_info->input_info_version & 0xFFFF; + port_info->res_type = in->res_type; + port_info->lane_type = in->lane_type; + port_info->lane_num = in->lane_num; + port_info->lane_cfg = in->lane_cfg; + port_info->vc[0] = in->vc; + port_info->dt[0] = in->dt; + port_info->num_valid_vc_dt = 1; + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->batch_size = in->batch_size; + port_info->dsp_mode = in->dsp_mode; + port_info->hbi_cnt = in->hbi_cnt; + port_info->cust_node = 0; + port_info->horizontal_bin = 0; + port_info->qcfa_bin = 0; + port_info->num_out_res = in->num_out_res; + + port_info->data = kcalloc(in->num_out_res, + sizeof(struct cam_isp_out_port_generic_info), + GFP_KERNEL); + if (port_info->data == NULL) { + rc = -ENOMEM; + goto release_port_mem; + } + + for (i = 0; i < in->num_out_res; i++) { + port_info->data[i].res_type = in->data[i].res_type; + port_info->data[i].format = in->data[i].format; + port_info->data[i].width = in->data[i].width; + port_info->data[i].height = in->data[i].height; + port_info->data[i].comp_grp_id = in->data[i].comp_grp_id; + port_info->data[i].split_point = in->data[i].split_point; + port_info->data[i].secure_mode = in->data[i].secure_mode; + port_info->data[i].reserved = in->data[i].reserved; + } + *in_port = port_info; + + return 0; +release_port_mem: + kfree(port_info); + return rc; +} + +static int cam_ife_mgr_acquire_get_unified_structure_v2( + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t offset, uint32_t *input_size, + struct cam_isp_in_port_generic_info **in_port) +{ + struct cam_isp_in_port_info_v2 *in = NULL; + uint32_t in_port_length = 0; + struct cam_isp_in_port_generic_info *port_info = NULL; + int32_t rc = 0, i; + + in = (struct cam_isp_in_port_info_v2 *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset + *input_size); + + in_port_length = sizeof(struct cam_isp_in_port_info_v2) + + (in->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info_v2); + + *input_size += in_port_length; + + if ((*input_size) > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "Input is not proper"); + rc = -EINVAL; + } + + port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), GFP_KERNEL); + + if (!port_info) + return -ENOMEM; + + port_info->major_ver = + (acquire_hw_info->input_info_version >> 16) & 0xFFFF; + port_info->minor_ver = + acquire_hw_info->input_info_version & 0xFFFF; + port_info->res_type = in->res_type; + port_info->lane_type = in->lane_type; + port_info->lane_num = in->lane_num; + port_info->lane_cfg = in->lane_cfg; + port_info->num_valid_vc_dt = in->num_valid_vc_dt; + + if (port_info->num_valid_vc_dt == 0 || + port_info->num_valid_vc_dt >= CAM_ISP_VC_DT_CFG) { + CAM_ERR(CAM_ISP, "Invalid i/p arg invalid vc-dt: %d", + in->num_valid_vc_dt); + rc = -EINVAL; + goto release_mem; + } + + for (i = 0; i < port_info->num_valid_vc_dt; i++) { + port_info->vc[i] = in->vc[i]; + port_info->dt[i] = in->dt[i]; + } + + port_info->format = in->format; + port_info->test_pattern = in->test_pattern; + port_info->usage_type = in->usage_type; + port_info->left_start = in->left_start; + port_info->left_stop = in->left_stop; + port_info->left_width = in->left_width; + port_info->right_start = in->right_start; + port_info->right_stop = in->right_stop; + port_info->right_width = in->right_width; + port_info->line_start = in->line_start; + port_info->line_stop = in->line_stop; + port_info->height = in->height; + port_info->pixel_clk = in->pixel_clk; + port_info->batch_size = in->batch_size; + port_info->dsp_mode = in->dsp_mode; + port_info->hbi_cnt = in->hbi_cnt; + port_info->cust_node = in->cust_node; + port_info->horizontal_bin = in->horizontal_bin; + port_info->qcfa_bin = in->qcfa_bin; + port_info->num_out_res = in->num_out_res; + + port_info->data = kcalloc(in->num_out_res, + sizeof(struct cam_isp_out_port_generic_info), + GFP_KERNEL); + if (port_info->data == NULL) { + rc = -ENOMEM; + goto release_mem; + } + + for (i = 0; i < port_info->num_out_res; i++) { + port_info->data[i].res_type = in->data[i].res_type; + port_info->data[i].format = in->data[i].format; + port_info->data[i].width = in->data[i].width; + port_info->data[i].height = in->data[i].height; + port_info->data[i].comp_grp_id = in->data[i].comp_grp_id; + port_info->data[i].split_point = in->data[i].split_point; + port_info->data[i].secure_mode = in->data[i].secure_mode; + } + + *in_port = port_info; + + return 0; + +release_mem: + kfree(port_info); + return rc; +} + +static int cam_ife_mgr_acquire_get_unified_structure( + struct cam_isp_acquire_hw_info *acquire_hw_info, + uint32_t offset, uint32_t *input_size, + struct cam_isp_in_port_generic_info **in_port) +{ + uint32_t major_ver = 0, minor_ver = 0; + + if (acquire_hw_info == NULL || input_size == NULL) + return -EINVAL; + + major_ver = (acquire_hw_info->common_info_version >> 12) & 0xF; + minor_ver = (acquire_hw_info->common_info_version) & 0xFFF; + + switch (major_ver) { + case 1: + return cam_ife_mgr_acquire_get_unified_structure_v0( + acquire_hw_info, offset, input_size, in_port); + case 2: + return cam_ife_mgr_acquire_get_unified_structure_v2( + acquire_hw_info, offset, input_size, in_port); + break; + default: + CAM_ERR(CAM_ISP, "Invalid ver of i/p port info from user"); + return -EINVAL; + } + + return 0; +} + +/* entry function: acquire_hw */ +static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + struct cam_ife_hw_mgr *ife_hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -1; + int i, j; + struct cam_ife_hw_mgr_ctx *ife_ctx; + struct cam_isp_in_port_generic_info *in_port = NULL; + struct cam_cdm_acquire_data cdm_acquire; + uint32_t num_pix_port_per_in = 0; + uint32_t num_rdi_port_per_in = 0; + uint32_t total_pix_port = 0; + uint32_t total_rdi_port = 0; + struct cam_isp_acquire_hw_info *acquire_hw_info = NULL; + uint32_t input_size = 0; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + /* get the ife ctx */ + rc = cam_ife_hw_mgr_get_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); + if (rc || !ife_ctx) { + CAM_ERR(CAM_ISP, "Get ife hw context failed"); + goto err; + } + + ife_ctx->common.cb_priv = acquire_args->context_data; + for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) + ife_ctx->common.event_cb[i] = acquire_args->event_cb; + + ife_ctx->hw_mgr = ife_hw_mgr; + + + memcpy(cdm_acquire.identifier, "ife", sizeof("ife")); + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ife_ctx; + cdm_acquire.base_array_cnt = CAM_IFE_HW_NUM_MAX; + for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (ife_hw_mgr->cdm_reg_map[i]) + cdm_acquire.base_array[j++] = + ife_hw_mgr->cdm_reg_map[i]; + } + cdm_acquire.base_array_cnt = j; + + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW"); + goto free_ctx; + } + + CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x", + cdm_acquire.handle); + ife_ctx->cdm_handle = cdm_acquire.handle; + ife_ctx->cdm_ops = cdm_acquire.ops; + atomic_set(&ife_ctx->cdm_done, 1); + + acquire_hw_info = + (struct cam_isp_acquire_hw_info *)acquire_args->acquire_info; + + rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); + if (rc) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + goto free_cdm; + } + + /* acquire HW resources */ + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + rc = cam_ife_mgr_acquire_get_unified_structure(acquire_hw_info, + i, &input_size, &in_port); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed in parsing: %d", rc); + goto free_res; + } + CAM_DBG(CAM_ISP, "in_res_type %x", in_port->res_type); + + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, + &num_pix_port_per_in, &num_rdi_port_per_in, + &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + if (rc) { + CAM_ERR(CAM_ISP, "can not acquire resource"); + cam_ife_hw_mgr_dump_src_acq_info(ife_ctx, + total_pix_port, total_rdi_port); + goto free_mem; + } + + kfree(in_port->data); + kfree(in_port); + in_port = NULL; + } + + /* Check whether context has only RDI resource */ + if (!total_pix_port) { + ife_ctx->is_rdi_only_context = 1; + CAM_DBG(CAM_ISP, "RDI only context"); + } + + /* Process base info */ + rc = cam_ife_mgr_process_base_info(ife_ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Process base info failed"); + goto free_res; + } + + acquire_args->ctxt_to_hw_map = ife_ctx; + ife_ctx->ctx_in_use = 1; + + acquire_args->valid_acquired_hw = + acquire_hw_info->num_inputs; + + getnstimeofday64(&ife_ctx->ts); + CAM_INFO(CAM_ISP, + "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", + total_pix_port, total_rdi_port, + ife_ctx->is_dual, ife_ctx->ctx_index); + + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + + return 0; +free_mem: + kfree(in_port->data); + kfree(in_port); +free_res: + cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx); +free_cdm: + cam_cdm_release(ife_ctx->cdm_handle); +free_ctx: + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); +err: + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +void cam_ife_mgr_acquire_get_unified_dev_str(struct cam_isp_in_port_info *in, + struct cam_isp_in_port_generic_info *gen_port_info) +{ + int i; + + gen_port_info->res_type = in->res_type; + gen_port_info->lane_type = in->lane_type; + gen_port_info->lane_num = in->lane_num; + gen_port_info->lane_cfg = in->lane_cfg; + gen_port_info->vc[0] = in->vc; + gen_port_info->dt[0] = in->dt; + gen_port_info->num_valid_vc_dt = 1; + gen_port_info->format = in->format; + gen_port_info->test_pattern = in->test_pattern; + gen_port_info->usage_type = in->usage_type; + gen_port_info->left_start = in->left_start; + gen_port_info->left_stop = in->left_stop; + gen_port_info->left_width = in->left_width; + gen_port_info->right_start = in->right_start; + gen_port_info->right_stop = in->right_stop; + gen_port_info->right_width = in->right_width; + gen_port_info->line_start = in->line_start; + gen_port_info->line_stop = in->line_stop; + gen_port_info->height = in->height; + gen_port_info->pixel_clk = in->pixel_clk; + gen_port_info->batch_size = in->batch_size; + gen_port_info->dsp_mode = in->dsp_mode; + gen_port_info->hbi_cnt = in->hbi_cnt; + gen_port_info->cust_node = 0; + gen_port_info->num_out_res = in->num_out_res; + + for (i = 0; i < in->num_out_res; i++) { + gen_port_info->data[i].res_type = in->data[i].res_type; + gen_port_info->data[i].format = in->data[i].format; + gen_port_info->data[i].width = in->data[i].width; + gen_port_info->data[i].height = in->data[i].height; + gen_port_info->data[i].comp_grp_id = in->data[i].comp_grp_id; + gen_port_info->data[i].split_point = in->data[i].split_point; + gen_port_info->data[i].secure_mode = in->data[i].secure_mode; + } +} + +/* entry function: acquire_hw */ +static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) +{ + struct cam_ife_hw_mgr *ife_hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -1; + int i, j; + struct cam_ife_hw_mgr_ctx *ife_ctx; + struct cam_isp_in_port_info *in_port = NULL; + struct cam_isp_resource *isp_resource = NULL; + struct cam_cdm_acquire_data cdm_acquire; + struct cam_isp_in_port_generic_info *gen_port_info = NULL; + uint32_t num_pix_port_per_in = 0; + uint32_t num_rdi_port_per_in = 0; + uint32_t total_pix_port = 0; + uint32_t total_rdi_port = 0; + uint32_t in_port_length = 0; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + /* get the ife ctx */ + rc = cam_ife_hw_mgr_get_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); + if (rc || !ife_ctx) { + CAM_ERR(CAM_ISP, "Get ife hw context failed"); + goto err; + } + + ife_ctx->common.cb_priv = acquire_args->context_data; + for (i = 0; i < CAM_ISP_HW_EVENT_MAX; i++) + ife_ctx->common.event_cb[i] = acquire_args->event_cb; + + ife_ctx->hw_mgr = ife_hw_mgr; + + + memcpy(cdm_acquire.identifier, "ife", sizeof("ife")); + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ife_ctx; + cdm_acquire.base_array_cnt = CAM_IFE_HW_NUM_MAX; + for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (ife_hw_mgr->cdm_reg_map[i]) + cdm_acquire.base_array[j++] = + ife_hw_mgr->cdm_reg_map[i]; + } + cdm_acquire.base_array_cnt = j; + + + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = cam_ife_cam_cdm_callback; + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to acquire the CDM HW"); + goto free_ctx; + } + + CAM_DBG(CAM_ISP, "Successfully acquired the CDM HW hdl=%x", + cdm_acquire.handle); + ife_ctx->cdm_handle = cdm_acquire.handle; + ife_ctx->cdm_ops = cdm_acquire.ops; + atomic_set(&ife_ctx->cdm_done, 1); + + isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info; + + /* acquire HW resources */ + for (i = 0; i < acquire_args->num_acq; i++) { + if (isp_resource[i].resource_id != CAM_ISP_RES_ID_PORT) + continue; + + CAM_DBG(CAM_ISP, "acquire no = %d total = %d", i, + acquire_args->num_acq); + CAM_DBG(CAM_ISP, + "start copy from user handle %lld with len = %d", + isp_resource[i].res_hdl, + isp_resource[i].length); + + in_port_length = sizeof(struct cam_isp_in_port_info); + + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + goto free_res; + } + + in_port = memdup_user( + u64_to_user_ptr(isp_resource[i].res_hdl), + isp_resource[i].length); + if (!IS_ERR(in_port)) { + if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + if (in_port_length > isp_resource[i].length) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + + gen_port_info = kzalloc( + sizeof(struct cam_isp_in_port_generic_info), + GFP_KERNEL); + if (gen_port_info == NULL) { + rc = -ENOMEM; + goto free_res; + } + + gen_port_info->data = kcalloc( + sizeof(struct cam_isp_out_port_generic_info), + in_port->num_out_res, GFP_KERNEL); + if (gen_port_info->data == NULL) { + kfree(gen_port_info); + gen_port_info = NULL; + rc = -ENOMEM; + goto free_res; + } + + cam_ife_mgr_acquire_get_unified_dev_str(in_port, + gen_port_info); + + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, + gen_port_info, &num_pix_port_per_in, + &num_rdi_port_per_in, + &acquire_args->acquired_hw_id[i], + acquire_args->acquired_hw_path[i]); + + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + kfree(in_port); + if (gen_port_info != NULL) { + kfree(gen_port_info->data); + kfree(gen_port_info); + gen_port_info = NULL; + } + if (rc) { + CAM_ERR(CAM_ISP, "can not acquire resource"); + goto free_res; + } + } else { + CAM_ERR(CAM_ISP, + "Copy from user failed with in_port = %pK", + in_port); + rc = -EFAULT; + goto free_res; + } + } + + /* Check whether context has only RDI resource */ + if (!total_pix_port) { + ife_ctx->is_rdi_only_context = 1; + CAM_DBG(CAM_ISP, "RDI only context"); + } + + /* Process base info */ + rc = cam_ife_mgr_process_base_info(ife_ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Process base info failed"); + goto free_res; + } + + acquire_args->ctxt_to_hw_map = ife_ctx; + ife_ctx->ctx_in_use = 1; + + CAM_INFO(CAM_ISP, + "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", + total_pix_port, total_rdi_port, + ife_ctx->is_dual, ife_ctx->ctx_index); + + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + + return 0; +free_res: + cam_ife_hw_mgr_release_hw_for_ctx(ife_ctx); + cam_cdm_release(ife_ctx->cdm_handle); +free_ctx: + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->free_ctx_list, &ife_ctx); +err: + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +/* entry function: acquire_hw */ +static int cam_ife_mgr_acquire(void *hw_mgr_priv, + void *acquire_hw_args) +{ + struct cam_hw_acquire_args *acquire_args = acquire_hw_args; + int rc = -1; + + CAM_DBG(CAM_ISP, "Enter..."); + + if (!acquire_args || acquire_args->num_acq <= 0) { + CAM_ERR(CAM_ISP, "Nothing to acquire. Seems like error"); + return -EINVAL; + } + + if (acquire_args->num_acq == CAM_API_COMPAT_CONSTANT) + rc = cam_ife_mgr_acquire_hw(hw_mgr_priv, acquire_hw_args); + else + rc = cam_ife_mgr_acquire_dev(hw_mgr_priv, acquire_hw_args); + + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +static const char *cam_isp_util_usage_data_to_string( + uint32_t usage_data) +{ + switch (usage_data) { + case CAM_ISP_USAGE_LEFT_PX: + return "LEFT_PX"; + case CAM_ISP_USAGE_RIGHT_PX: + return "RIGHT_PX"; + case CAM_ISP_USAGE_RDI: + return "RDI"; + default: + return "USAGE_INVALID"; + } +} + +static int cam_isp_classify_vote_info( + struct cam_ife_hw_mgr_res *hw_mgr_res, + struct cam_isp_bw_config_v2 *bw_config, + struct cam_axi_vote *isp_vote, + uint32_t split_idx, + bool *camif_l_bw_updated, + bool *camif_r_bw_updated) +{ + int rc = 0, i, j = 0; + + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_LCR)) { + if (split_idx == CAM_ISP_HW_SPLIT_LEFT) { + if (*camif_l_bw_updated) + return rc; + + for (i = 0; i < bw_config->num_paths; i++) { + if (bw_config->axi_path[i].usage_data == + CAM_ISP_USAGE_LEFT_PX) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + *camif_l_bw_updated = true; + } else { + if (*camif_r_bw_updated) + return rc; + + for (i = 0; i < bw_config->num_paths; i++) { + if (bw_config->axi_path[i].usage_data == + CAM_ISP_USAGE_RIGHT_PX) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + *camif_r_bw_updated = true; + } + } else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) + && (hw_mgr_res->res_id <= + CAM_ISP_HW_VFE_IN_RDI3)) { + for (i = 0; i < bw_config->num_paths; i++) { + if ((bw_config->axi_path[i].usage_data == + CAM_ISP_USAGE_RDI) && + ((bw_config->axi_path[i].path_data_type - + CAM_AXI_PATH_DATA_IFE_RDI0) == + (hw_mgr_res->res_id - + CAM_ISP_HW_VFE_IN_RDI0))) { + memcpy(&isp_vote->axi_path[j], + &bw_config->axi_path[i], + sizeof(struct + cam_axi_per_path_bw_vote)); + j++; + } + } + isp_vote->num_paths = j; + + } else { + if (hw_mgr_res->hw_res[split_idx]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u, split_idx: %u", + hw_mgr_res->res_id, split_idx); + rc = -EINVAL; + return rc; + } + } + + for (i = 0; i < isp_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "CLASSIFY_VOTE [%s] [%s] [%s] [%llu] [%llu] [%llu]", + cam_isp_util_usage_data_to_string( + isp_vote->axi_path[i].usage_data), + cam_cpas_axi_util_path_type_to_string( + isp_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + isp_vote->axi_path[i].transac_type), + isp_vote->axi_path[i].camnoc_bw, + isp_vote->axi_path[i].mnoc_ab_bw, + isp_vote->axi_path[i].mnoc_ib_bw); + } + + return rc; +} + +static int cam_isp_blob_bw_update_v2( + struct cam_isp_bw_config_v2 *bw_config, + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_bw_update_args_v2 bw_upd_args; + int rc = -EINVAL; + uint32_t i, split_idx; + bool camif_l_bw_updated = false; + bool camif_r_bw_updated = false; + + for (i = 0; i < bw_config->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ISP_BLOB usage_type=%u [%s] [%s] [%s] [%llu] [%llu] [%llu]", + bw_config->usage_type, + cam_isp_util_usage_data_to_string( + bw_config->axi_path[i].usage_data), + cam_cpas_axi_util_path_type_to_string( + bw_config->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + bw_config->axi_path[i].transac_type), + bw_config->axi_path[i].camnoc_bw, + bw_config->axi_path[i].mnoc_ab_bw, + bw_config->axi_path[i].mnoc_ib_bw); + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (split_idx = 0; split_idx < CAM_ISP_HW_SPLIT_MAX; + split_idx++) { + if (!hw_mgr_res->hw_res[split_idx]) + continue; + + memset(&bw_upd_args.isp_vote, 0, + sizeof(struct cam_axi_vote)); + rc = cam_isp_classify_vote_info(hw_mgr_res, bw_config, + &bw_upd_args.isp_vote, split_idx, + &camif_l_bw_updated, &camif_r_bw_updated); + if (rc) + return rc; + + if (!bw_upd_args.isp_vote.num_paths) + continue; + + hw_intf = hw_mgr_res->hw_res[split_idx]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_upd_args.node_res = + hw_mgr_res->hw_res[split_idx]; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_UPDATE_V2, + &bw_upd_args, + sizeof( + struct cam_vfe_bw_update_args_v2)); + if (rc) + CAM_ERR(CAM_PERF, + "BW Update failed rc: %d", rc); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + } + + return rc; +} + +static int cam_isp_blob_bw_update( + struct cam_isp_bw_config *bw_config, + struct cam_ife_hw_mgr_ctx *ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_bw_update_args bw_upd_args; + uint64_t cam_bw_bps = 0; + uint64_t ext_bw_bps = 0; + int rc = -EINVAL; + uint32_t i; + bool camif_l_bw_updated = false; + bool camif_r_bw_updated = false; + + CAM_DBG(CAM_PERF, + "ISP_BLOB usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu, right cam_bw_bps=%llu ext_bw_bps=%llu", + bw_config->usage_type, + bw_config->left_pix_vote.cam_bw_bps, + bw_config->left_pix_vote.ext_bw_bps, + bw_config->right_pix_vote.cam_bw_bps, + bw_config->right_pix_vote.ext_bw_bps); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD) || + (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) + || (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_LCR)) + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_bw_updated) + continue; + + cam_bw_bps = + bw_config->left_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->left_pix_vote.ext_bw_bps; + + camif_l_bw_updated = true; + } else { + if (camif_r_bw_updated) + continue; + + cam_bw_bps = + bw_config->right_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->right_pix_vote.ext_bw_bps; + + camif_r_bw_updated = true; + } + else if ((hw_mgr_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) + && (hw_mgr_res->res_id <= + CAM_ISP_HW_VFE_IN_RDI3)) { + uint32_t idx = hw_mgr_res->res_id - + CAM_ISP_HW_VFE_IN_RDI0; + if (idx >= bw_config->num_rdi) + continue; + + cam_bw_bps = + bw_config->rdi_vote[idx].cam_bw_bps; + ext_bw_bps = + bw_config->rdi_vote[idx].ext_bw_bps; + } else { + if (hw_mgr_res->hw_res[i]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u", + hw_mgr_res->res_id); + rc = -EINVAL; + return rc; + } + } + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + bw_upd_args.camnoc_bw_bytes = cam_bw_bps; + bw_upd_args.external_bw_bytes = ext_bw_bps; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_UPDATE, + &bw_upd_args, + sizeof(struct cam_vfe_bw_update_args)); + if (rc) + CAM_ERR(CAM_PERF, "BW Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +/* entry function: config_hw */ +static int cam_ife_mgr_config_hw(void *hw_mgr_priv, + void *config_hw_args) +{ + int rc = -1, i, skip = 0; + struct cam_hw_config_args *cfg; + struct cam_hw_update_entry *cmd; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_isp_prepare_hw_update_data *hw_update_data; + + if (!hw_mgr_priv || !config_hw_args) { + CAM_ERR(CAM_ISP, + "Invalid arguments, hw_mgr_priv=%pK, config_hw_args=%pK", + hw_mgr_priv, config_hw_args); + return -EINVAL; + } + + cfg = config_hw_args; + ctx = (struct cam_ife_hw_mgr_ctx *)cfg->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EINVAL; + } + + if (!ctx->ctx_in_use || !ctx->cdm_cmd) { + CAM_ERR(CAM_ISP, + "Invalid context parameters : ctx_in_use=%d, cdm_cmd=%pK", + ctx->ctx_in_use, ctx->cdm_cmd); + return -EPERM; + } + + if (atomic_read(&ctx->overflow_pending)) { + CAM_DBG(CAM_ISP, + "Ctx[%pK][%d] Overflow pending, cannot apply req %llu", + ctx, ctx->ctx_index, cfg->request_id); + return -EPERM; + } + + hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; + hw_update_data->ife_mgr_ctx = ctx; + + CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld, init_packet=%d", + ctx, ctx->ctx_index, cfg->request_id, cfg->init_packet); + + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (hw_update_data->bw_config_valid[i] == true) { + + CAM_DBG(CAM_PERF, "idx=%d, bw_config_version=%d", + ctx, ctx->ctx_index, i, + hw_update_data->bw_config_version); + + if (hw_update_data->bw_config_version == + CAM_ISP_BW_CONFIG_V1) { + rc = cam_isp_blob_bw_update( + (struct cam_isp_bw_config *) + &hw_update_data->bw_config[i], ctx); + if (rc) + CAM_ERR(CAM_PERF, + "Bandwidth Update Failed rc: %d", rc); + } else if (hw_update_data->bw_config_version == + CAM_ISP_BW_CONFIG_V2) { + rc = cam_isp_blob_bw_update_v2( + (struct cam_isp_bw_config_v2 *) + &hw_update_data->bw_config_v2[i], ctx); + if (rc) + CAM_ERR(CAM_PERF, + "Bandwidth Update Failed rc: %d", rc); + + } else { + CAM_ERR(CAM_PERF, + "Invalid bw config version: %d", + hw_update_data->bw_config_version); + } + } + } + + CAM_DBG(CAM_ISP, + "Enter ctx id:%d num_hw_upd_entries %d request id: %llu", + ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id); + + if (cfg->num_hw_update_entries > 0) { + cdm_cmd = ctx->cdm_cmd; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = true; + cdm_cmd->userdata = hw_update_data; + cdm_cmd->cookie = cfg->request_id; + + for (i = 0 ; i < cfg->num_hw_update_entries; i++) { + cmd = (cfg->hw_update_entries + i); + + if (cfg->reapply && + cmd->flags == CAM_ISP_IQ_BL) { + skip++; + continue; + } + + if (cmd->flags == CAM_ISP_UNUSED_BL || + cmd->flags >= CAM_ISP_BL_MAX) + CAM_ERR(CAM_ISP, "Unexpected BL type %d", + cmd->flags); + + cdm_cmd->cmd[i - skip].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i - skip].offset = cmd->offset; + cdm_cmd->cmd[i - skip].len = cmd->len; + } + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries - skip; + + reinit_completion(&ctx->config_done_complete); + ctx->applied_req_id = cfg->request_id; + + CAM_DBG(CAM_ISP, "Submit to CDM"); + atomic_set(&ctx->cdm_done, 0); + rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to apply the configs for req %llu, rc %d", + cfg->request_id, rc); + return rc; + } + + if (cfg->init_packet) { + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(60)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, ctx->ctx_index); + if (rc == 0) + rc = -ETIMEDOUT; + } else { + rc = 0; + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); + } + } + } else { + CAM_ERR(CAM_ISP, "No commands to config"); + } + CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); + + return rc; +} + +static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_ctx *ctx; + uint32_t i, master_base_idx = 0; + + if (!stop_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", + ctx->ctx_index); + + if (!ctx->num_base) { + CAM_ERR(CAM_ISP, "Number of bases are zero"); + return -EINVAL; + } + + /* get master base index first */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { + master_base_idx = ctx->base[i].idx; + break; + } + } + + if (i == ctx->num_base) + master_base_idx = ctx->base[0].idx; + + + /* stop the master CIDs first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + master_base_idx, CAM_CSID_HALT_IMMEDIATELY); + + /* stop rest of the CIDs */ + for (i = 0; i < ctx->num_base; i++) { + if (i == master_base_idx) + continue; + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + ctx->base[i].idx, CAM_CSID_HALT_IMMEDIATELY); + } + + /* stop the master CSID path first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + master_base_idx, CAM_CSID_HALT_IMMEDIATELY); + + /* Stop rest of the CSID paths */ + for (i = 0; i < ctx->num_base; i++) { + if (i == master_base_idx) + continue; + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, CAM_CSID_HALT_IMMEDIATELY); + } + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + /* IFE out resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); + + + /* Stop tasklet for context */ + cam_tasklet_stop(ctx->common.tasklet_info); + CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d", + ctx->ctx_index, rc); + + return rc; +} + +static int cam_ife_mgr_bw_control(struct cam_ife_hw_mgr_ctx *ctx, + enum cam_vfe_bw_control_action action) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_bw_control_args bw_ctrl_args; + int rc = -EINVAL; + uint32_t i; + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", ctx->ctx_index); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + bw_ctrl_args.node_res = + hw_mgr_res->hw_res[i]; + bw_ctrl_args.action = action; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_BW_CONTROL, + &bw_ctrl_args, + sizeof(struct cam_vfe_bw_control_args)); + if (rc) + CAM_ERR(CAM_ISP, "BW Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_ife_mgr_pause_hw(struct cam_ife_hw_mgr_ctx *ctx) +{ + return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_EXCLUDE); +} + +/* entry function: stop_hw */ +static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc = 0; + struct cam_hw_stop_args *stop_args = stop_hw_args; + struct cam_isp_stop_args *stop_isp; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_ife_hw_mgr_ctx *ctx; + enum cam_ife_csid_halt_cmd csid_halt_type; + uint32_t i, master_base_idx = 0; + + if (!hw_mgr_priv || !stop_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)stop_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, " Enter...ctx id:%d", ctx->ctx_index); + stop_isp = (struct cam_isp_stop_args *)stop_args->args; + + /* Set the csid halt command */ + if (stop_isp->hw_stop_cmd == CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY) + csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + else + csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; + + /* Note:stop resource will remove the irq mask from the hardware */ + + if (!ctx->num_base) { + CAM_ERR(CAM_ISP, "number of bases are zero"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Halting CSIDs"); + + /* get master base index first */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].split_id == CAM_ISP_HW_SPLIT_LEFT) { + master_base_idx = ctx->base[i].idx; + break; + } + } + + /* + * If Context does not have PIX resources and has only RDI resource + * then take the first base index. + */ + if (i == ctx->num_base) + master_base_idx = ctx->base[0].idx; + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); + + /* Stop the master CSID path first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + master_base_idx, csid_halt_type); + + /* stop rest of the CSID paths */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, csid_halt_type); + } + + CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); + + /* Stop the master CIDs first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + master_base_idx, csid_halt_type); + + /* stop rest of the CIDs */ + for (i = 0; i < ctx->num_base; i++) { + if (ctx->base[i].idx == master_base_idx) + continue; + CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + ctx->base[i].idx, csid_halt_type); + } + + CAM_DBG(CAM_ISP, "Going to stop IFE Out"); + + /* IFE out resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); + + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + cam_tasklet_stop(ctx->common.tasklet_info); + + cam_ife_mgr_pause_hw(ctx); + + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(300)); + if (rc <= 0) { + CAM_WARN(CAM_ISP, + "config done completion timeout for last applied req_id=%llu rc=%d ctx_index %d", + ctx->applied_req_id, rc, ctx->ctx_index); + rc = -ETIMEDOUT; + } else { + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu ctx_index %d", + ctx->applied_req_id, ctx->ctx_index); + rc = 0; + } + + if (stop_isp->stop_only) + goto end; + + if (cam_cdm_stream_off(ctx->cdm_handle)) + CAM_ERR(CAM_ISP, "CDM stream off failed %d", ctx->cdm_handle); + + cam_ife_hw_mgr_deinit_hw(ctx); + CAM_DBG(CAM_ISP, + "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) { + rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE); + if (rc) { + CAM_ERR(CAM_ISP, + "SAFE SCM call failed:Check TZ/HYP dependency"); + rc = 0; + } + } + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + +end: + return rc; +} + +static int cam_ife_mgr_reset_vfe_hw(struct cam_ife_hw_mgr *hw_mgr, + uint32_t hw_idx) +{ + uint32_t i = 0; + struct cam_hw_intf *vfe_hw_intf; + uint32_t vfe_reset_type; + + if (!hw_mgr) { + CAM_DBG(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + /* Reset VFE HW*/ + vfe_reset_type = CAM_VFE_HW_RESET_HW; + + for (i = 0; i < CAM_VFE_HW_NUM_MAX; i++) { + if (hw_idx != hw_mgr->ife_devices[i]->hw_idx) + continue; + CAM_DBG(CAM_ISP, "VFE (id = %d) reset", hw_idx); + vfe_hw_intf = hw_mgr->ife_devices[i]; + vfe_hw_intf->hw_ops.reset(vfe_hw_intf->hw_priv, + &vfe_reset_type, sizeof(vfe_reset_type)); + break; + } + + CAM_DBG(CAM_ISP, "Exit Successfully"); + return 0; +} + +static int cam_ife_mgr_restart_hw(void *start_hw_args) +{ + int rc = -1; + struct cam_hw_start_args *start_args = start_hw_args; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t i; + + if (!start_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)start_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", ctx->ctx_index); + + cam_tasklet_start(ctx->common.tasklet_info); + + /* start the IFE out devices */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + rc = cam_ife_hw_mgr_start_hw_res( + &ctx->res_list_ife_out[i], ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)", i); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); + + /* Start IFE BUS RD device */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", ctx->ctx_index); + /* Start the IFE CSID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d", ctx->ctx_index); + /* Start IFE root node: do nothing */ + CAM_DBG(CAM_ISP, "Exit...(success)"); + return 0; + +err: + cam_ife_mgr_stop_hw_in_overflow(start_hw_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; +} + +static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) +{ + int rc = -1; + struct cam_isp_start_args *start_isp = start_hw_args; + struct cam_hw_stop_args stop_args; + struct cam_isp_stop_args stop_isp; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *rsrc_node = NULL; + uint32_t i, camif_debug; + bool res_rdi_context_set = false; + uint32_t primary_rdi_src_res; + uint32_t primary_rdi_out_res; + + primary_rdi_src_res = CAM_ISP_HW_VFE_IN_MAX; + primary_rdi_out_res = CAM_ISP_IFE_OUT_RES_MAX; + + if (!hw_mgr_priv || !start_isp) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *) + start_isp->hw_config.ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + if ((!ctx->init_done) && start_isp->start_only) { + CAM_ERR(CAM_ISP, "Invalid args init_done %d start_only %d", + ctx->init_done, start_isp->start_only); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enter... ctx id:%d", + ctx->ctx_index); + + /* update Bandwidth should be done at the hw layer */ + + cam_tasklet_start(ctx->common.tasklet_info); + + if (ctx->init_done && start_isp->start_only) + goto start_only; + + /* set current csid debug information to CSID HW */ + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (g_ife_hw_mgr.csid_devices[i]) + rc = g_ife_hw_mgr.csid_devices[i]->hw_ops.process_cmd( + g_ife_hw_mgr.csid_devices[i]->hw_priv, + CAM_IFE_CSID_SET_CSID_DEBUG, + &g_ife_hw_mgr.debug_cfg.csid_debug, + sizeof(g_ife_hw_mgr.debug_cfg.csid_debug)); + } + + camif_debug = g_ife_hw_mgr.debug_cfg.camif_debug; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF)) { + rc = hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + &camif_debug, + sizeof(camif_debug)); + } + } + } + + rc = cam_ife_hw_mgr_init_hw(ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Init failed"); + goto tasklet_stop; + } + + ctx->init_done = true; + + mutex_lock(&g_ife_hw_mgr.ctx_mutex); + if (!atomic_fetch_inc(&g_ife_hw_mgr.active_ctx_cnt)) { + rc = cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_ENABLE); + if (rc) { + CAM_ERR(CAM_ISP, + "SAFE SCM call failed:Check TZ/HYP dependency"); + rc = -EFAULT; + goto deinit_hw; + } + } + mutex_unlock(&g_ife_hw_mgr.ctx_mutex); + + CAM_DBG(CAM_ISP, "start cdm interface"); + rc = cam_cdm_stream_on(ctx->cdm_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start cdm (%d)", + ctx->cdm_handle); + goto safe_disable; + } + +start_only: + + atomic_set(&ctx->overflow_pending, 0); + + /* Apply initial configuration */ + CAM_DBG(CAM_ISP, "Config HW"); + rc = cam_ife_mgr_config_hw(hw_mgr_priv, &start_isp->hw_config); + if (rc) { + CAM_ERR(CAM_ISP, + "Config HW failed, start_only=%d, rc=%d", + start_isp->start_only, rc); + goto cdm_streamoff; + } + + CAM_DBG(CAM_ISP, "START IFE OUT ... in ctx id:%d", + ctx->ctx_index); + /* start the IFE out devices */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + hw_mgr_res = &ctx->res_list_ife_out[i]; + switch (hw_mgr_res->res_id) { + case CAM_ISP_IFE_OUT_RES_RDI_0: + case CAM_ISP_IFE_OUT_RES_RDI_1: + case CAM_ISP_IFE_OUT_RES_RDI_2: + case CAM_ISP_IFE_OUT_RES_RDI_3: + if (!res_rdi_context_set && ctx->is_rdi_only_context) { + hw_mgr_res->hw_res[0]->rdi_only_ctx = + ctx->is_rdi_only_context; + res_rdi_context_set = true; + primary_rdi_out_res = hw_mgr_res->res_id; + } + break; + default: + break; + } + rc = cam_ife_hw_mgr_start_hw_res( + &ctx->res_list_ife_out[i], ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE OUT (%d)", + i); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + if (primary_rdi_out_res < CAM_ISP_IFE_OUT_RES_MAX) + primary_rdi_src_res = + cam_convert_rdi_out_res_id_to_src(primary_rdi_out_res); + + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + if (primary_rdi_src_res == hw_mgr_res->res_id) { + hw_mgr_res->hw_res[0]->rdi_only_ctx = + ctx->is_rdi_only_context; + } + + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE MUX (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CSID HW ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE CSID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + CAM_DBG(CAM_ISP, "START CID SRC ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE CID HW devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE CSID (%d)", + hw_mgr_res->res_id); + goto err; + } + } + + /* Start IFE root node: do nothing */ + CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); + + return 0; + +err: + stop_isp.stop_only = false; + stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY; + stop_args.ctxt_to_hw_map = start_isp->hw_config.ctxt_to_hw_map; + stop_args.args = (void *)(&stop_isp); + + cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + return rc; + +cdm_streamoff: + cam_cdm_stream_off(ctx->cdm_handle); + +safe_disable: + cam_ife_notify_safe_lut_scm(CAM_IFE_SAFE_DISABLE); + +deinit_hw: + cam_ife_hw_mgr_deinit_hw(ctx); + +tasklet_stop: + cam_tasklet_stop(ctx->common.tasklet_info); + + return rc; +} + +static int cam_ife_mgr_read(void *hw_mgr_priv, void *read_args) +{ + return -EPERM; +} + +static int cam_ife_mgr_write(void *hw_mgr_priv, void *write_args) +{ + return -EPERM; +} + +static int cam_ife_mgr_reset(void *hw_mgr_priv, void *hw_reset_args) +{ + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_reset_args *reset_args = hw_reset_args; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + int rc = 0, i = 0; + + if (!hw_mgr_priv || !hw_reset_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)reset_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Reset CSID and VFE"); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + rc = cam_ife_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to reset CSID:%d rc: %d", + hw_mgr_res->res_id, rc); + goto end; + } + } + + for (i = 0; i < ctx->num_base; i++) { + rc = cam_ife_mgr_reset_vfe_hw(hw_mgr, ctx->base[i].idx); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to reset VFE:%d rc: %d", + ctx->base[i].idx, rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_ife_mgr_release_hw(void *hw_mgr_priv, + void *release_hw_args) +{ + int rc = 0; + struct cam_hw_release_args *release_args = release_hw_args; + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_ife_hw_mgr_ctx *ctx; + uint32_t i; + + if (!hw_mgr_priv || !release_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)release_args->ctxt_to_hw_map; + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Invalid context is used"); + return -EPERM; + } + + CAM_DBG(CAM_ISP, "Enter...ctx id:%d", + ctx->ctx_index); + + if (ctx->init_done) + cam_ife_hw_mgr_deinit_hw(ctx); + + /* we should called the stop hw before this already */ + cam_ife_hw_mgr_release_hw_for_ctx(ctx); + + /* reset base info */ + ctx->num_base = 0; + memset(ctx->base, 0, sizeof(ctx->base)); + + /* release cdm handle */ + cam_cdm_release(ctx->cdm_handle); + + /* clean context */ + list_del_init(&ctx->list); + ctx->ctx_in_use = 0; + ctx->is_rdi_only_context = 0; + ctx->cdm_handle = 0; + ctx->cdm_ops = NULL; + atomic_set(&ctx->overflow_pending, 0); + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + ctx->sof_cnt[i] = 0; + ctx->eof_cnt[i] = 0; + ctx->epoch_cnt[i] = 0; + } + + CAM_INFO(CAM_ISP, "Release HW success ctx id: %u", + ctx->ctx_index); + + memset(&ctx->ts, 0, sizeof(struct timespec64)); + cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx); + return rc; +} + +static int cam_isp_blob_fe_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_fe_config *fe_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + int rc = -EINVAL; + uint32_t i; + struct cam_vfe_fe_update_args fe_upd_args; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + &fe_upd_args, + sizeof( + struct cam_fe_config)); + if (rc) + CAM_ERR(CAM_ISP, "fs Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + &fe_upd_args, + sizeof( + struct cam_vfe_fe_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "fe Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + return rc; +} + +static int cam_isp_blob_ubwc_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_ubwc_config *ubwc_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid ctx"); + rc = -EINVAL; + goto end; + } + + if ((prepare->num_hw_update_entries + 1) >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d max:%d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + rc = -EINVAL; + goto end; + } + + switch (ubwc_config->api_version) { + case CAM_UBWC_CFG_VERSION_1: + CAM_DBG(CAM_ISP, "num_ports= %d", ubwc_config->num_ports); + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < ubwc_config->num_ports; i++) { + ubwc_plane_cfg = &ubwc_config->ubwc_plane_cfg[i][0]; + res_id_out = ubwc_plane_cfg->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "UBWC config idx %d, port_type=%d", i, + ubwc_plane_cfg->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid port type:%x", + ubwc_plane_cfg->port_type); + rc = -EINVAL; + goto end; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base=%d bytes_used=%u buf_size=%u", + blob_info->base_info->idx, bytes_used, + kmd_buf_info->size); + rc = -ENOMEM; + goto end; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, "Invalid hw_mgr_res"); + rc = -EINVAL; + goto end; + } + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)ubwc_plane_cfg, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + blob_info->base_info->idx, + bytes_used, + res_id_out); + goto end; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = + total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid UBWC API Version %d", + ubwc_config->api_version); + rc = -EINVAL; + break; + } +end: + return rc; +} + +static int cam_isp_get_generic_ubwc_data_v2( + struct cam_ubwc_plane_cfg_v2 *ubwc_cfg, + uint32_t version, + struct cam_vfe_generic_ubwc_config *generic_ubwc_cfg) +{ + int i = 0; + + generic_ubwc_cfg->api_version = version; + for (i = 0; i < CAM_PACKET_MAX_PLANES - 1; i++) { + generic_ubwc_cfg->ubwc_plane_cfg[i].port_type = + ubwc_cfg[i].port_type; + generic_ubwc_cfg->ubwc_plane_cfg[i].meta_stride = + ubwc_cfg[i].meta_stride; + generic_ubwc_cfg->ubwc_plane_cfg[i].meta_size = + ubwc_cfg[i].meta_size; + generic_ubwc_cfg->ubwc_plane_cfg[i].meta_offset = + ubwc_cfg[i].meta_offset; + generic_ubwc_cfg->ubwc_plane_cfg[i].packer_config = + ubwc_cfg[i].packer_config; + generic_ubwc_cfg->ubwc_plane_cfg[i].mode_config_0 = + ubwc_cfg[i].mode_config_0; + generic_ubwc_cfg->ubwc_plane_cfg[i].mode_config_1 = + ubwc_cfg[i].mode_config_1; + generic_ubwc_cfg->ubwc_plane_cfg[i].tile_config = + ubwc_cfg[i].tile_config; + generic_ubwc_cfg->ubwc_plane_cfg[i].h_init = + ubwc_cfg[i].h_init; + generic_ubwc_cfg->ubwc_plane_cfg[i].v_init = + ubwc_cfg[i].v_init; + generic_ubwc_cfg->ubwc_plane_cfg[i].static_ctrl = + ubwc_cfg[i].static_ctrl; + generic_ubwc_cfg->ubwc_plane_cfg[i].ctrl_2 = + ubwc_cfg[i].ctrl_2; + generic_ubwc_cfg->ubwc_plane_cfg[i].stats_ctrl_2 = + ubwc_cfg[i].stats_ctrl_2; + generic_ubwc_cfg->ubwc_plane_cfg[i].lossy_threshold_0 = + ubwc_cfg[i].lossy_threshold_0; + generic_ubwc_cfg->ubwc_plane_cfg[i].lossy_threshold_1 = + ubwc_cfg[i].lossy_threshold_1; + generic_ubwc_cfg->ubwc_plane_cfg[i].lossy_var_offset = + ubwc_cfg[i].lossy_var_offset; + generic_ubwc_cfg->ubwc_plane_cfg[i].bandwidth_limit = + ubwc_cfg[i].bandwidth_limit; + } + + return 0; +} + +static int cam_isp_blob_ubwc_update_v2( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_ubwc_config_v2 *ubwc_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ubwc_plane_cfg_v2 *ubwc_plane_cfg; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + struct cam_vfe_generic_ubwc_config generic_ubwc_cfg; + + ctx = prepare->ctxt_to_hw_map; + if (!ctx) { + CAM_ERR(CAM_ISP, "Invalid ctx"); + rc = -EINVAL; + goto end; + } + + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d max:%d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "num_ports= %d", ubwc_config->num_ports); + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < ubwc_config->num_ports; i++) { + ubwc_plane_cfg = &ubwc_config->ubwc_plane_cfg[i][0]; + res_id_out = ubwc_plane_cfg->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "UBWC config idx %d, port_type=%d", i, + ubwc_plane_cfg->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid port type:%x", + ubwc_plane_cfg->port_type); + rc = -EINVAL; + goto end; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base=%d bytes_used=%u buf_size=%u", + blob_info->base_info->idx, bytes_used, + kmd_buf_info->size); + rc = -ENOMEM; + goto end; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + if (!hw_mgr_res) { + CAM_ERR(CAM_ISP, "Invalid hw_mgr_res"); + rc = -EINVAL; + goto end; + } + + rc = cam_isp_get_generic_ubwc_data_v2(ubwc_plane_cfg, + ubwc_config->api_version, &generic_ubwc_cfg); + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)&generic_ubwc_cfg, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, bytes_used=%u, res_id_out=0x%x", + blob_info->base_info->idx, + bytes_used, + res_id_out); + goto end; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = + total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } +end: + return rc; +} + +static int cam_isp_blob_hfr_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_resource_hfr_config *hfr_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_isp_port_hfr_config *port_hfr_config; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + CAM_DBG(CAM_ISP, "num_ports= %d", + hfr_config->num_ports); + + /* Max one hw entries required for hfr config update */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < hfr_config->num_ports; i++) { + port_hfr_config = &hfr_config->port_hfr_config[i]; + res_id_out = port_hfr_config->resource_type & 0xFF; + + CAM_DBG(CAM_ISP, "hfr config idx %d, type=%d", i, + res_id_out); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "invalid out restype:%x", + port_hfr_config->resource_type); + return -EINVAL; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + blob_info->base_info->idx); + rc = -ENOMEM; + return rc; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + total_used_bytes/4; + hw_mgr_res = &ctx->res_list_ife_out[res_id_out]; + + rc = cam_isp_add_cmd_buf_update( + hw_mgr_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)port_hfr_config, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed cmd_update, base_idx=%d, rc=%d", + blob_info->base_info->idx, bytes_used); + return rc; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +static int cam_isp_blob_csid_clock_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_csid_clock_config *clock_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_csid_clock_update_args csid_clock_upd_args; + uint64_t clk_rate = 0; + int rc = -EINVAL; + uint32_t i; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_ISP, + "csid clk=%llu", clock_config->csid_clock); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i]) + continue; + clk_rate = clock_config->csid_clock; + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + csid_clock_upd_args.clk_rate = clk_rate; + CAM_DBG(CAM_ISP, "i= %d clk=%llu\n", + i, csid_clock_upd_args.clk_rate); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + blob_type_hw_cmd_map[blob_type], + &csid_clock_upd_args, + sizeof( + struct cam_ife_csid_clock_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update failed"); + } else + CAM_ERR(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_isp_blob_csid_qcfa_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_csid_qcfa_config *qcfa_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_csid_qcfa_update_args csid_qcfa_upd_args; + int rc = -EINVAL; + uint32_t i; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_ISP, + "csid binning=%d", qcfa_config->csid_binning); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + + if (!hw_mgr_res->hw_res[i] || + hw_mgr_res->res_id != CAM_IFE_PIX_PATH_RES_IPP) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + csid_qcfa_upd_args.qcfa_binning = + qcfa_config->csid_binning; + CAM_DBG(CAM_ISP, "i= %d QCFA binning=%d\n", + i, csid_qcfa_upd_args.qcfa_binning); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, + &csid_qcfa_upd_args, + sizeof( + struct cam_ife_csid_qcfa_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "QCFA Update failed"); + } else + CAM_ERR(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_isp_blob_core_cfg_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_core_config *core_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + uint64_t clk_rate = 0; + int rc = 0, i; + struct cam_vfe_core_config_args vfe_core_config; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i] || + hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + vfe_core_config.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&vfe_core_config.core_config, + core_config, + sizeof(struct cam_isp_core_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CORE_CONFIG, + &vfe_core_config, + sizeof( + struct cam_vfe_core_config_args)); + if (rc) + CAM_ERR(CAM_ISP, "Core cfg parse fail"); + } else { + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + } + + return rc; +} + +static int cam_isp_blob_clock_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_clock_config *clock_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_vfe_clock_update_args clock_upd_args; + uint64_t clk_rate = 0; + int rc = -EINVAL; + uint32_t i; + uint32_t j; + bool camif_l_clk_updated = false; + bool camif_r_clk_updated = false; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_PERF, + "usage=%u left_clk= %lu right_clk=%lu", + clock_config->usage_type, + clock_config->left_pix_hz, + clock_config->right_pix_hz); + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + clk_rate = 0; + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_clk_updated) + continue; + + clk_rate = + clock_config->left_pix_hz; + + camif_l_clk_updated = true; + } else { + if (camif_r_clk_updated) + continue; + + clk_rate = + clock_config->right_pix_hz; + + camif_r_clk_updated = true; + } + } else if (hw_mgr_res->res_id == + CAM_ISP_HW_VFE_IN_PDLIB) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + if (camif_l_clk_updated) + continue; + + clk_rate = + clock_config->left_pix_hz; + + camif_l_clk_updated = true; + } else { + if (camif_r_clk_updated) + continue; + + clk_rate = + clock_config->right_pix_hz; + + camif_r_clk_updated = true; + } + } else if ((hw_mgr_res->res_id >= + CAM_ISP_HW_VFE_IN_RD) && (hw_mgr_res->res_id + <= CAM_ISP_HW_VFE_IN_RDI3)) + for (j = 0; j < clock_config->num_rdi; j++) + clk_rate = max(clock_config->rdi_hz[j], + clk_rate); + else + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_LCR + && hw_mgr_res->hw_res[i]) { + CAM_ERR(CAM_ISP, "Invalid res_id %u", + hw_mgr_res->res_id); + rc = -EINVAL; + return rc; + } + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + clock_upd_args.node_res = + hw_mgr_res->hw_res[i]; + CAM_DBG(CAM_PERF, + "res_id=%u i= %d clk=%llu\n", + hw_mgr_res->res_id, i, clk_rate); + + clock_upd_args.clk_rate = clk_rate; + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + &clock_upd_args, + sizeof( + struct cam_vfe_clock_update_args)); + if (rc) + CAM_ERR(CAM_PERF, + "Clock Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + return rc; +} + +static int cam_isp_blob_vfe_out_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_isp_vfe_out_config *vfe_out_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_isp_vfe_wm_config *wm_config; + struct cam_kmd_buf_info *kmd_buf_info; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *ife_out_res; + uint32_t res_id_out, i; + uint32_t total_used_bytes = 0; + uint32_t kmd_buf_remain_size; + uint32_t *cmd_buf_addr; + uint32_t bytes_used = 0; + int num_ent, rc = 0; + + ctx = prepare->ctxt_to_hw_map; + + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + kmd_buf_info = blob_info->kmd_buf_info; + for (i = 0; i < vfe_out_config->num_ports; i++) { + wm_config = &vfe_out_config->wm_config[i]; + res_id_out = wm_config->port_type & 0xFF; + + CAM_DBG(CAM_ISP, "VFE out config idx: %d port: 0x%x", + i, wm_config->port_type); + + if (res_id_out >= CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid out port:0x%x", + wm_config->port_type); + return -EINVAL; + } + + if ((kmd_buf_info->used_bytes + + total_used_bytes) < kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + total_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "No free kmd memory for base idx: %d", + blob_info->base_info->idx); + rc = -ENOMEM; + return rc; + } + + cmd_buf_addr = kmd_buf_info->cpu_addr + + (kmd_buf_info->used_bytes / 4) + + (total_used_bytes / 4); + ife_out_res = &ctx->res_list_ife_out[res_id_out]; + + rc = cam_isp_add_cmd_buf_update( + ife_out_res, blob_type, + blob_type_hw_cmd_map[blob_type], + blob_info->base_info->idx, + (void *)cmd_buf_addr, + kmd_buf_remain_size, + (void *)wm_config, + &bytes_used); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Failed to update VFE Out out_type:0x%X base_idx:%d bytes_used:%u rc:%d", + wm_config->port_type, blob_info->base_info->idx, + bytes_used, rc); + return rc; + } + + total_used_bytes += bytes_used; + } + + if (total_used_bytes) { + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = total_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + num_ent++; + + kmd_buf_info->used_bytes += total_used_bytes; + kmd_buf_info->offset += total_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +static int cam_isp_packet_generic_blob_handler(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) +{ + int rc = 0; + struct cam_isp_generic_blob_info *blob_info = user_data; + struct cam_hw_prepare_update_args *prepare = NULL; + struct cam_ife_hw_mgr_ctx *ife_mgr_ctx = NULL; + + if (!blob_data || (blob_size == 0) || !blob_info) { + CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK", + blob_data, blob_size, blob_info); + return -EINVAL; + } + + if (blob_type >= CAM_ISP_GENERIC_BLOB_TYPE_MAX) { + CAM_ERR(CAM_ISP, "Invalid Blob Type %d Max %d", blob_type, + CAM_ISP_GENERIC_BLOB_TYPE_MAX); + return -EINVAL; + } + + prepare = blob_info->prepare; + if (!prepare || !prepare->ctxt_to_hw_map) { + CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d", + blob_type); + return -EINVAL; + } + + ife_mgr_ctx = prepare->ctxt_to_hw_map; + CAM_DBG(CAM_ISP, "Context[%pK][%d] blob_type=%d, blob_size=%d", + ife_mgr_ctx, ife_mgr_ctx->ctx_index, blob_type, blob_size); + + switch (blob_type) { + case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: { + struct cam_isp_resource_hfr_config *hfr_config; + + if (blob_size < sizeof(struct cam_isp_resource_hfr_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + hfr_config = (struct cam_isp_resource_hfr_config *)blob_data; + + if (hfr_config->num_ports > CAM_ISP_IFE_OUT_RES_MAX || + hfr_config->num_ports == 0) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in HFR config", + hfr_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (hfr_config->num_ports != 1) { + if (sizeof(struct cam_isp_port_hfr_config) > + ((UINT_MAX - + sizeof(struct cam_isp_resource_hfr_config)) / + (hfr_config->num_ports - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in hfr config num_ports:%u size per port:%lu", + hfr_config->num_ports, + sizeof(struct cam_isp_port_hfr_config)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_resource_hfr_config) + + (hfr_config->num_ports - 1) * + sizeof(struct cam_isp_port_hfr_config))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_resource_hfr_config) + + (hfr_config->num_ports - 1) * + sizeof(struct cam_isp_port_hfr_config)); + return -EINVAL; + } + + rc = cam_isp_blob_hfr_update(blob_type, blob_info, + hfr_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "HFR Update Failed"); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: { + struct cam_isp_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + clock_config = (struct cam_isp_clock_config *)blob_data; + + if (clock_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in clock config", + clock_config->num_rdi); + return -EINVAL; + } + + /* Check for integer overflow */ + if (clock_config->num_rdi > 1) { + if (sizeof(uint64_t) > ((UINT_MAX - + sizeof(struct cam_isp_clock_config)) / + (clock_config->num_rdi - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in clock config num_rdi:%u size per port:%lu", + clock_config->num_rdi, + sizeof(uint64_t)); + return -EINVAL; + } + } + + if ((clock_config->num_rdi != 0) && (blob_size < + (sizeof(struct cam_isp_clock_config) + + sizeof(uint64_t) * (clock_config->num_rdi - 1)))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2)); + return -EINVAL; + } + + rc = cam_isp_blob_clock_update(blob_type, blob_info, + clock_config, prepare); + if (rc) + CAM_ERR(CAM_PERF, "Clock Update Failed, rc=%d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG: { + struct cam_isp_bw_config *bw_config; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_PERF, 300, 1, + "Deprecated Blob TYPE_BW_CONFIG"); + if (blob_size < sizeof(struct cam_isp_bw_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config = (struct cam_isp_bw_config *)blob_data; + + if (bw_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config", + bw_config->num_rdi); + return -EINVAL; + } + + /* Check for integer overflow */ + if (bw_config->num_rdi > 1) { + if (sizeof(struct cam_isp_bw_vote) > ((UINT_MAX - + sizeof(struct cam_isp_bw_config)) / + (bw_config->num_rdi - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in bw config num_rdi:%u size per port:%lu", + bw_config->num_rdi, + sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } + } + + if ((bw_config->num_rdi != 0) && (blob_size < + (sizeof(struct cam_isp_bw_config) + + (bw_config->num_rdi - 1) * + sizeof(struct cam_isp_bw_vote)))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_isp_bw_config) + + (bw_config->num_rdi - 1) * + sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } + + if (!prepare || !prepare->priv || + (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + memcpy(&prepare_hw_data->bw_config[bw_config->usage_type], + bw_config, sizeof(prepare_hw_data->bw_config[0])); + prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V1; + prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2: { + size_t bw_config_size = 0; + struct cam_isp_bw_config_v2 *bw_config; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (blob_size < sizeof(struct cam_isp_bw_config_v2)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config = (struct cam_isp_bw_config_v2 *)blob_data; + + if (bw_config->num_paths > CAM_ISP_MAX_PER_PATH_VOTES) { + CAM_ERR(CAM_ISP, "Invalid num paths %d", + bw_config->num_paths); + return -EINVAL; + } + + /* Check for integer overflow */ + if (bw_config->num_paths > 1) { + if (sizeof(struct cam_axi_per_path_bw_vote) > + ((UINT_MAX - + sizeof(struct cam_isp_bw_config_v2)) / + (bw_config->num_paths - 1))) { + CAM_ERR(CAM_ISP, + "Size exceeds limit paths:%u size per path:%lu", + bw_config->num_paths - 1, + sizeof( + struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + } + + if ((bw_config->num_paths != 0) && (blob_size < + (sizeof(struct cam_isp_bw_config_v2) + + (bw_config->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)))) { + CAM_ERR(CAM_ISP, + "Invalid blob size: %u, num_paths: %u, bw_config size: %lu, per_path_vote size: %lu", + blob_size, bw_config->num_paths, + sizeof(struct cam_isp_bw_config_v2), + sizeof(struct cam_axi_per_path_bw_vote)); + return -EINVAL; + } + + if (!prepare || !prepare->priv || + (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + memset(&prepare_hw_data->bw_config_v2[bw_config->usage_type], + 0, sizeof( + prepare_hw_data->bw_config_v2[bw_config->usage_type])); + bw_config_size = sizeof(struct cam_isp_bw_config_internal_v2) + + ((bw_config->num_paths - 1) * + sizeof(struct cam_axi_per_path_bw_vote)); + memcpy(&prepare_hw_data->bw_config_v2[bw_config->usage_type], + bw_config, bw_config_size); + + prepare_hw_data->bw_config_version = CAM_ISP_BW_CONFIG_V2; + prepare_hw_data->bw_config_valid[bw_config->usage_type] = true; + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: { + struct cam_ubwc_config *ubwc_config; + + if (blob_size < sizeof(struct cam_ubwc_config)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u", blob_size); + return -EINVAL; + } + + ubwc_config = (struct cam_ubwc_config *)blob_data; + + if (ubwc_config->num_ports > CAM_VFE_MAX_UBWC_PORTS || + ubwc_config->num_ports == 0) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in ubwc config", + ubwc_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (ubwc_config->num_ports != 1) { + if (sizeof(struct cam_ubwc_plane_cfg_v1) > + ((UINT_MAX - sizeof(struct cam_ubwc_config)) / + ((ubwc_config->num_ports - 1) * 2))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in ubwc config num_ports:%u size per port:%lu", + ubwc_config->num_ports, + sizeof(struct cam_ubwc_plane_cfg_v1) * + 2); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_ubwc_config) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v1) * 2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u expected %lu", + blob_size, + sizeof(struct cam_ubwc_config) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v1) * 2); + return -EINVAL; + } + + rc = cam_isp_blob_ubwc_update(blob_type, blob_info, + ubwc_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "UBWC Update Failed rc: %d", rc); + } + break; + + case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG_V2: { + struct cam_ubwc_config_v2 *ubwc_config; + + if (blob_size < sizeof(struct cam_ubwc_config_v2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u", blob_size); + return -EINVAL; + } + + ubwc_config = (struct cam_ubwc_config_v2 *)blob_data; + + if (ubwc_config->num_ports > CAM_VFE_MAX_UBWC_PORTS || + ubwc_config->num_ports == 0) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in ubwc config", + ubwc_config->num_ports); + return -EINVAL; + } + + /* Check for integer overflow */ + if (ubwc_config->num_ports != 1) { + if (sizeof(struct cam_ubwc_plane_cfg_v2) > + ((UINT_MAX - sizeof(struct cam_ubwc_config_v2)) + / ((ubwc_config->num_ports - 1) * 2))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in ubwc config num_ports:%u size per port:%lu", + ubwc_config->num_ports, + sizeof(struct cam_ubwc_plane_cfg_v2) * + 2); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_ubwc_config_v2) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v2) * 2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u expected %lu", + blob_size, + sizeof(struct cam_ubwc_config_v2) + + (ubwc_config->num_ports - 1) * + sizeof(struct cam_ubwc_plane_cfg_v2) * 2); + return -EINVAL; + } + + rc = cam_isp_blob_ubwc_update_v2(blob_type, blob_info, + ubwc_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "UBWC Update Failed rc: %d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG: { + struct cam_isp_csid_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_csid_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_csid_clock_config)); + return -EINVAL; + } + + clock_config = (struct cam_isp_csid_clock_config *)blob_data; + + rc = cam_isp_blob_csid_clock_update(blob_type, blob_info, + clock_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Clock Update Failed"); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG: { + struct cam_isp_csid_qcfa_config *qcfa_config; + + if (blob_size < sizeof(struct cam_isp_csid_qcfa_config)) { + CAM_ERR(CAM_ISP, + "Invalid qcfa blob size %u expected %u", + blob_size, + sizeof(struct cam_isp_csid_qcfa_config)); + return -EINVAL; + } + + qcfa_config = (struct cam_isp_csid_qcfa_config *)blob_data; + + rc = cam_isp_blob_csid_qcfa_update(blob_type, blob_info, + qcfa_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "QCFA Update Failed rc: %d", rc); + + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: { + struct cam_fe_config *fe_config; + + if (blob_size < sizeof(struct cam_fe_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_fe_config)); + return -EINVAL; + } + + fe_config = (struct cam_fe_config *)blob_data; + + rc = cam_isp_blob_fe_update(blob_type, blob_info, + fe_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG: { + struct cam_isp_core_config *core_config; + + if (blob_size < sizeof(struct cam_isp_core_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_isp_core_config)); + return -EINVAL; + } + + core_config = (struct cam_isp_core_config *)blob_data; + + rc = cam_isp_blob_core_cfg_update(blob_type, blob_info, + core_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "Core cfg update fail: %d", rc); + } + break; + case CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG: { + struct cam_isp_vfe_out_config *vfe_out_config; + + if (blob_size < sizeof(struct cam_isp_vfe_out_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", + blob_size, + sizeof(struct cam_isp_vfe_out_config)); + return -EINVAL; + } + + vfe_out_config = (struct cam_isp_vfe_out_config *)blob_data; + + if (vfe_out_config->num_ports > CAM_IFE_HW_OUT_RES_MAX || + vfe_out_config->num_ports == 0) { + CAM_ERR(CAM_ISP, + "Invalid num_ports:%u in vfe out config", + vfe_out_config->num_ports, + CAM_IFE_HW_OUT_RES_MAX); + return -EINVAL; + } + + /* Check for integer overflow */ + if (vfe_out_config->num_ports != 1) { + if (sizeof(struct cam_isp_vfe_wm_config) > ((UINT_MAX - + sizeof(struct cam_isp_vfe_out_config)) / + (vfe_out_config->num_ports - 1))) { + CAM_ERR(CAM_ISP, + "Max size exceeded in vfe out config num_ports:%u size per port:%lu", + vfe_out_config->num_ports, + sizeof(struct cam_isp_vfe_wm_config)); + return -EINVAL; + } + } + + if (blob_size < (sizeof(struct cam_isp_vfe_out_config) + + (vfe_out_config->num_ports - 1) * + sizeof(struct cam_isp_vfe_wm_config))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_isp_vfe_out_config) + + (vfe_out_config->num_ports - 1) * + sizeof(struct cam_isp_vfe_wm_config)); + return -EINVAL; + } + + rc = cam_isp_blob_vfe_out_update(blob_type, blob_info, + vfe_out_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "VFE out update failed rc: %d", rc); + } + break; + + default: + CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); + break; + } + + return rc; +} + +static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc = 0; + struct cam_hw_prepare_update_args *prepare = + (struct cam_hw_prepare_update_args *) prepare_hw_update_args; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr *hw_mgr; + struct cam_kmd_buf_info kmd_buf; + uint32_t i; + bool fill_fence = true; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (!hw_mgr_priv || !prepare_hw_update_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) + prepare->priv; + + ctx = (struct cam_ife_hw_mgr_ctx *) prepare->ctxt_to_hw_map; + hw_mgr = (struct cam_ife_hw_mgr *)hw_mgr_priv; + + + CAM_DBG(CAM_REQ, "ctx[%pK][%d] Enter for req_id %lld", + ctx, ctx->ctx_index, prepare->packet->header.request_id); + + rc = cam_packet_util_validate_packet(prepare->packet, + prepare->remain_len); + if (rc) + return rc; + + /* Pre parse the packet*/ + rc = cam_packet_util_get_kmd_buffer(prepare->packet, &kmd_buf); + if (rc) + return rc; + + rc = cam_packet_util_process_patches(prepare->packet, + hw_mgr->mgr_common.cmd_iommu_hdl, + hw_mgr->mgr_common.cmd_iommu_hdl_secure); + if (rc) { + CAM_ERR(CAM_ISP, "Patch ISP packet failed."); + return rc; + } + + prepare->num_hw_update_entries = 0; + prepare->num_in_map_entries = 0; + prepare->num_out_map_entries = 0; + prepare->num_reg_dump_buf = 0; + + memset(&prepare_hw_data->bw_config[0], 0x0, + sizeof(prepare_hw_data->bw_config[0]) * + CAM_IFE_HW_NUM_MAX); + memset(&prepare_hw_data->bw_config_valid[0], 0x0, + sizeof(prepare_hw_data->bw_config_valid[0]) * + CAM_IFE_HW_NUM_MAX); + + for (i = 0; i < ctx->num_base; i++) { + CAM_DBG(CAM_ISP, "process cmd buffer for device %d", i); + + /* Add change base */ + rc = cam_isp_add_change_base(prepare, &ctx->res_list_ife_src, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in change base i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + + + /* get command buffers */ + if (ctx->base[i].split_id != CAM_ISP_HW_SPLIT_MAX) { + rc = cam_isp_add_command_buffers(prepare, &kmd_buf, + &ctx->base[i], + cam_isp_packet_generic_blob_handler, + ctx->res_list_ife_out, CAM_IFE_HW_OUT_RES_MAX); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in add cmdbuf, i=%d, split_id=%d, rc=%d", + i, ctx->base[i].split_id, rc); + goto end; + } + } + + /* get IO buffers */ + rc = cam_isp_add_io_buffers(hw_mgr->mgr_common.img_iommu_hdl, + hw_mgr->mgr_common.img_iommu_hdl_secure, + prepare, ctx->base[i].idx, + &kmd_buf, ctx->res_list_ife_out, + &ctx->res_list_ife_in_rd, + CAM_IFE_HW_OUT_RES_MAX, fill_fence); + + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in io buffers, i=%d, rc=%d", + i, rc); + goto end; + } + + /* fence map table entries need to fill only once in the loop */ + if (fill_fence) + fill_fence = false; + } + + /* + * reg update will be done later for the initial configure. + * need to plus one to the op_code and only take the lower + * bits to get the type of operation since UMD definition + * of op_code has some difference from KMD. + */ + if (((prepare->packet->header.op_code + 1) & 0xF) == + CAM_ISP_PACKET_INIT_DEV) { + prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_INIT_DEV; + if ((prepare->num_reg_dump_buf) && (prepare->num_reg_dump_buf < + CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + ctx->num_reg_dump_buf = prepare->num_reg_dump_buf; + memcpy(ctx->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare->num_reg_dump_buf); + } + + goto end; + } else { + prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV; + prepare_hw_data->num_reg_dump_buf = prepare->num_reg_dump_buf; + if ((prepare_hw_data->num_reg_dump_buf) && + (prepare_hw_data->num_reg_dump_buf < + CAM_REG_DUMP_MAX_BUF_ENTRIES)) { + memcpy(prepare_hw_data->reg_dump_buf_desc, + prepare->reg_dump_buf_desc, + sizeof(struct cam_cmd_buf_desc) * + prepare_hw_data->num_reg_dump_buf); + } + } + + /* add reg update commands */ + for (i = 0; i < ctx->num_base; i++) { + /* Add change base */ + rc = cam_isp_add_change_base(prepare, &ctx->res_list_ife_src, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in change base adding reg_update cmd i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + + /*Add reg update */ + rc = cam_isp_add_reg_update(prepare, &ctx->res_list_ife_src, + ctx->base[i].idx, &kmd_buf); + if (rc) { + CAM_ERR(CAM_ISP, + "Add Reg_update cmd Failed i=%d, idx=%d, rc=%d", + i, ctx->base[i].idx, rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx) +{ + return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE); +} + +static int cam_ife_mgr_sof_irq_debug( + struct cam_ife_hw_mgr_ctx *ctx, + uint32_t sof_irq_enable) +{ + int rc = 0; + uint32_t i = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc |= hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF)) { + rc |= hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + return rc; +} + +static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + dma_addr_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (pf_buf_info && + GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_ISP, + "Found PF at port: 0x%x mem 0x%x fd: 0x%x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_ISP, "port: 0x%x f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "get src buf address fail mem_handle 0x%x", + io_cfg[i].mem_handle[j]); + continue; + } + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { + CAM_ERR(CAM_ISP, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_ISP, + "pln %d w %d h %d s %u size 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", + j, io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + (unsigned int)src_buf_size, + (unsigned int)iova_addr, + (unsigned int)iova_addr + + (unsigned int)src_buf_size, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + } + } +} + +static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_ife_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_ife_hw_mgr_ctx *ctx = (struct cam_ife_hw_mgr_ctx *) + hw_cmd_args->ctxt_to_hw_map; + struct cam_isp_hw_cmd_args *isp_hw_cmd_args = NULL; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + if (!ctx || !ctx->ctx_in_use) { + CAM_ERR(CAM_ISP, "Fatal: Invalid context is used"); + return -EPERM; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_INTERNAL: + if (!hw_cmd_args->u.internal_args) { + CAM_ERR(CAM_ISP, "Invalid cmd arguments"); + return -EINVAL; + } + + isp_hw_cmd_args = (struct cam_isp_hw_cmd_args *) + hw_cmd_args->u.internal_args; + + switch (isp_hw_cmd_args->cmd_type) { + case CAM_ISP_HW_MGR_CMD_PAUSE_HW: + cam_ife_mgr_pause_hw(ctx); + break; + case CAM_ISP_HW_MGR_CMD_RESUME_HW: + cam_ife_mgr_resume_hw(ctx); + break; + case CAM_ISP_HW_MGR_CMD_SOF_DEBUG: + cam_ife_mgr_sof_irq_debug(ctx, + isp_hw_cmd_args->u.sof_irq_enable); + break; + case CAM_ISP_HW_MGR_CMD_CTX_TYPE: + if (ctx->is_fe_enable) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2; + else if (ctx->is_rdi_only_context) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI; + else + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; + break; + default: + CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", + hw_cmd_args->cmd_type); + rc = -EINVAL; + break; + } + break; + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_ife_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->mgr_common.img_iommu_hdl, + hw_mgr->mgr_common.img_iommu_hdl_secure, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH: + if (ctx->last_dump_flush_req_id == ctx->applied_req_id) + return 0; + + rc = wait_for_completion_timeout( + &ctx->config_done_complete, + msecs_to_jiffies(30)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, + "config done completion timeout, Reg dump will be unreliable rc=%d ctx_index %d", + rc, ctx->ctx_index); + rc = 0; + } + + ctx->last_dump_flush_req_id = ctx->applied_req_id; + rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, + ctx->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on flush failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; + case CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR: + if (ctx->last_dump_err_req_id == ctx->applied_req_id) + return 0; + + ctx->last_dump_err_req_id = ctx->applied_req_id; + rc = cam_ife_mgr_handle_reg_dump(ctx, ctx->reg_dump_buf_desc, + ctx->num_reg_dump_buf, + CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR); + if (rc) { + CAM_ERR(CAM_ISP, + "Reg dump on error failed req id: %llu rc: %d", + ctx->applied_req_id, rc); + return rc; + } + + break; + case CAM_HW_MGR_CMD_DUMP_ACQ_INFO: + cam_ife_hw_mgr_dump_acq_data(ctx); + break; + default: + CAM_ERR(CAM_ISP, "Invalid cmd"); + } + + return rc; +} + +static int cam_ife_mgr_cmd_get_sof_timestamp( + struct cam_ife_hw_mgr_ctx *ife_ctx, + uint64_t *time_stamp, + uint64_t *boot_time_stamp) +{ + int rc = -EINVAL; + uint32_t i; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_get_time_stamp_args csid_get_time; + + hw_mgr_res = list_first_entry(&ife_ctx->res_list_ife_csid, + struct cam_ife_hw_mgr_res, list); + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + /* + * Get the SOF time stamp from left resource only. + * Left resource is master for dual vfe case and + * Rdi only context case left resource only hold + * the RDI resource + */ + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + /* + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient + */ + + csid_get_time.node_res = + hw_mgr_res->hw_res[i]; + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + &csid_get_time, + sizeof( + struct cam_csid_get_time_stamp_args)); + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { + *time_stamp = + csid_get_time.time_stamp_val; + *boot_time_stamp = + csid_get_time.boot_timestamp; + } + } + } + + if (rc) + CAM_ERR_RATE_LIMIT(CAM_ISP, "Getting sof time stamp failed"); + + return rc; +} + +static int cam_ife_mgr_process_recovery_cb(void *priv, void *data) +{ + int32_t rc = 0; + struct cam_hw_event_recovery_data *recovery_data = data; + struct cam_hw_start_args start_args; + struct cam_hw_stop_args stop_args; + struct cam_ife_hw_mgr *ife_hw_mgr = priv; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t i = 0; + + uint32_t error_type = recovery_data->error_type; + struct cam_ife_hw_mgr_ctx *ctx = NULL; + + /* Here recovery is performed */ + CAM_DBG(CAM_ISP, "ErrorType = %d", error_type); + + switch (error_type) { + case CAM_ISP_HW_ERROR_OVERFLOW: + case CAM_ISP_HW_ERROR_BUSIF_OVERFLOW: + if (!recovery_data->affected_ctx[0]) { + CAM_ERR(CAM_ISP, + "No context is affected but recovery called"); + kfree(recovery_data); + return 0; + } + /* stop resources here */ + CAM_DBG(CAM_ISP, "STOP: Number of affected context: %d", + recovery_data->no_of_context); + for (i = 0; i < recovery_data->no_of_context; i++) { + stop_args.ctxt_to_hw_map = + recovery_data->affected_ctx[i]; + rc = cam_ife_mgr_stop_hw_in_overflow(&stop_args); + if (rc) { + CAM_ERR(CAM_ISP, "CTX stop failed(%d)", rc); + return rc; + } + } + + CAM_DBG(CAM_ISP, "RESET: CSID PATH"); + for (i = 0; i < recovery_data->no_of_context; i++) { + ctx = recovery_data->affected_ctx[i]; + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, + list) { + rc = cam_ife_hw_mgr_reset_csid_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Failed RESET (%d)", + hw_mgr_res->res_id); + return rc; + } + } + } + + CAM_DBG(CAM_ISP, "RESET: Calling VFE reset"); + + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (recovery_data->affected_core[i]) + cam_ife_mgr_reset_vfe_hw(ife_hw_mgr, i); + } + + CAM_DBG(CAM_ISP, "START: Number of affected context: %d", + recovery_data->no_of_context); + + for (i = 0; i < recovery_data->no_of_context; i++) { + ctx = recovery_data->affected_ctx[i]; + start_args.ctxt_to_hw_map = ctx; + + atomic_set(&ctx->overflow_pending, 0); + + rc = cam_ife_mgr_restart_hw(&start_args); + if (rc) { + CAM_ERR(CAM_ISP, "CTX start failed(%d)", rc); + return rc; + } + CAM_DBG(CAM_ISP, "Started resources rc (%d)", rc); + } + CAM_DBG(CAM_ISP, "Recovery Done rc (%d)", rc); + + break; + + case CAM_ISP_HW_ERROR_P2I_ERROR: + break; + + case CAM_ISP_HW_ERROR_VIOLATION: + break; + + default: + CAM_ERR(CAM_ISP, "Invalid Error"); + } + CAM_DBG(CAM_ISP, "Exit: ErrorType = %d", error_type); + + kfree(recovery_data); + return rc; +} + +static int cam_ife_hw_mgr_do_error_recovery( + struct cam_hw_event_recovery_data *ife_mgr_recovery_data) +{ + int32_t rc = 0; + struct crm_workq_task *task = NULL; + struct cam_hw_event_recovery_data *recovery_data = NULL; + + recovery_data = kzalloc(sizeof(struct cam_hw_event_recovery_data), + GFP_ATOMIC); + if (!recovery_data) + return -ENOMEM; + + memcpy(recovery_data, ife_mgr_recovery_data, + sizeof(struct cam_hw_event_recovery_data)); + + CAM_DBG(CAM_ISP, "Enter: error_type (%d)", recovery_data->error_type); + + task = cam_req_mgr_workq_get_task(g_ife_hw_mgr.workq); + if (!task) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No empty task frame"); + kfree(recovery_data); + return -ENOMEM; + } + + task->process_cb = &cam_ife_mgr_process_recovery_cb; + task->payload = recovery_data; + rc = cam_req_mgr_workq_enqueue_task(task, + recovery_data->affected_ctx[0]->hw_mgr, + CRM_TASK_PRIORITY_0); + + return rc; +} + +/* + * This function checks if any of the valid entry in affected_core[] + * is associated with this context. if YES + * a. It fills the other cores associated with this context.in + * affected_core[] + * b. Return true + */ +static bool cam_ife_hw_mgr_is_ctx_affected( + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx, + uint32_t *affected_core, + uint32_t size) +{ + + bool rc = false; + uint32_t i = 0, j = 0; + uint32_t max_idx = ife_hwr_mgr_ctx->num_base; + uint32_t ctx_affected_core_idx[CAM_IFE_HW_NUM_MAX] = {0}; + + CAM_DBG(CAM_ISP, "Enter:max_idx = %d", max_idx); + + if ((max_idx >= CAM_IFE_HW_NUM_MAX) || (size > CAM_IFE_HW_NUM_MAX)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "invalid parameter = %d", max_idx); + return rc; + } + + for (i = 0; i < max_idx; i++) { + if (affected_core[ife_hwr_mgr_ctx->base[i].idx]) + rc = true; + else { + ctx_affected_core_idx[j] = ife_hwr_mgr_ctx->base[i].idx; + j = j + 1; + } + } + + if (rc) { + while (j) { + if (affected_core[ctx_affected_core_idx[j-1]] != 1) + affected_core[ctx_affected_core_idx[j-1]] = 1; + j = j - 1; + } + } + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +/* + * For any dual VFE context, if non-affected VFE is also serving + * another context, then that context should also be notified with fatal error + * So Loop through each context and - + * a. match core_idx + * b. Notify CTX with fatal error + */ +static int cam_ife_hw_mgr_find_affected_ctx( + struct cam_isp_hw_error_event_data *error_event_data, + uint32_t curr_core_idx, + struct cam_hw_event_recovery_data *recovery_data) +{ + uint32_t affected_core[CAM_IFE_HW_NUM_MAX] = {0}; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL; + cam_hw_event_cb_func notify_err_cb; + struct cam_ife_hw_mgr *ife_hwr_mgr = NULL; + enum cam_isp_hw_event_type event_type = CAM_ISP_HW_EVENT_ERROR; + uint32_t i = 0; + + if (!recovery_data) { + CAM_ERR(CAM_ISP, "recovery_data parameter is NULL"); + return -EINVAL; + } + + recovery_data->no_of_context = 0; + affected_core[curr_core_idx] = 1; + ife_hwr_mgr = &g_ife_hw_mgr; + + list_for_each_entry(ife_hwr_mgr_ctx, + &ife_hwr_mgr->used_ctx_list, list) { + /* + * Check if current core_idx matches the HW associated + * with this context + */ + if (!cam_ife_hw_mgr_is_ctx_affected(ife_hwr_mgr_ctx, + affected_core, CAM_IFE_HW_NUM_MAX)) + continue; + + atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1); + notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type]; + + /* Add affected_context in list of recovery data */ + CAM_DBG(CAM_ISP, "Add affected ctx %d to list", + ife_hwr_mgr_ctx->ctx_index); + if (recovery_data->no_of_context < CAM_CTX_MAX) + recovery_data->affected_ctx[ + recovery_data->no_of_context++] = + ife_hwr_mgr_ctx; + + /* + * In the call back function corresponding ISP context + * will update CRM about fatal Error + */ + notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_ERROR, error_event_data); + } + + /* fill the affected_core in recovery data */ + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + recovery_data->affected_core[i] = affected_core[i]; + CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)", + i, recovery_data->affected_core[i]); + } + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_err( + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + uint32_t core_idx; + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_hw_event_recovery_data recovery_data = {0}; + int rc = -EINVAL; + + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) + error_event_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_IN) + error_event_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) + error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + + core_idx = event_info->hw_idx; + + if (g_ife_hw_mgr.debug_cfg.enable_recovery) + error_event_data.recovery_enabled = true; + + if (g_ife_hw_mgr.debug_cfg.enable_req_dump) + error_event_data.enable_req_dump = true; + + rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data, + core_idx, &recovery_data); + + if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT) + return rc; + + if (g_ife_hw_mgr.debug_cfg.enable_recovery) { + CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled"); + + /* Trigger for recovery */ + if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION) + recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION; + else + recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + cam_ife_hw_mgr_do_error_recovery(&recovery_data); + } else { + CAM_DBG(CAM_ISP, "recovery is not enabled"); + rc = 0; + } + + return rc; +} + +static int cam_ife_hw_mgr_handle_hw_rup( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hwr_irq_rup_cb; + struct cam_isp_hw_reg_update_event_data rup_event_data; + + ife_hwr_irq_rup_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + if (ife_hw_mgr_ctx->is_dual) + if (event_info->hw_idx != 1) + break; + + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hwr_irq_rup_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (!ife_hw_mgr_ctx->is_rdi_only_context) + break; + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hwr_irq_rup_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, &rup_event_data); + break; + + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "RUP done for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_check_irq_for_dual_vfe( + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx, + uint32_t hw_event_type) +{ + int32_t rc = -1; + uint32_t *event_cnt = NULL; + uint32_t core_idx0 = 0; + uint32_t core_idx1 = 1; + + if (!ife_hw_mgr_ctx->is_dual) + return 0; + + switch (hw_event_type) { + case CAM_ISP_HW_EVENT_SOF: + event_cnt = ife_hw_mgr_ctx->sof_cnt; + break; + case CAM_ISP_HW_EVENT_EPOCH: + event_cnt = ife_hw_mgr_ctx->epoch_cnt; + break; + case CAM_ISP_HW_EVENT_EOF: + event_cnt = ife_hw_mgr_ctx->eof_cnt; + break; + default: + return 0; + } + + if (event_cnt[core_idx0] == event_cnt[core_idx1]) { + + event_cnt[core_idx0] = 0; + event_cnt[core_idx1] = 0; + + rc = 0; + return rc; + } + + if ((event_cnt[core_idx0] && + (event_cnt[core_idx0] - event_cnt[core_idx1] > 1)) || + (event_cnt[core_idx1] && + (event_cnt[core_idx1] - event_cnt[core_idx0] > 1))) { + + CAM_ERR_RATE_LIMIT(CAM_ISP, + "One of the VFE could not generate hw event %d core_0_cnt %d core_1_cnt %d", + hw_event_type, event_cnt[core_idx0], + event_cnt[core_idx1]); + rc = -1; + return rc; + } + + CAM_DBG(CAM_ISP, "Only one core_index has given hw event %d", + hw_event_type); + + return rc; +} + +static int cam_ife_hw_mgr_handle_hw_epoch( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hw_irq_epoch_cb; + struct cam_isp_hw_epoch_event_data epoch_done_event_data; + int rc = 0; + + ife_hw_irq_epoch_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + ife_hw_mgr_ctx->epoch_cnt[event_info->hw_idx]++; + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, + CAM_ISP_HW_EVENT_EPOCH); + if (!rc) { + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); + } + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "Epoch for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_sof( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hw_irq_sof_cb; + struct cam_isp_hw_sof_event_data sof_done_event_data; + int rc = 0; + + ife_hw_irq_sof_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_RD: + ife_hw_mgr_ctx->sof_cnt[event_info->hw_idx]++; + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, + CAM_ISP_HW_EVENT_SOF); + if (!rc) { + cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + + ife_hw_irq_sof_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); + } + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + if (!ife_hw_mgr_ctx->is_rdi_only_context) + break; + cam_ife_mgr_cmd_get_sof_timestamp(ife_hw_mgr_ctx, + &sof_done_event_data.timestamp, + &sof_done_event_data.boot_time); + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hw_irq_sof_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); + break; + + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "SOF for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_eof( + void *ctx, + void *evt_info) +{ + struct cam_isp_hw_event_info *event_info = evt_info; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + cam_hw_event_cb_func ife_hw_irq_eof_cb; + struct cam_isp_hw_eof_event_data eof_done_event_data; + int rc = 0; + + ife_hw_irq_eof_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]; + + switch (event_info->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + ife_hw_mgr_ctx->eof_cnt[event_info->hw_idx]++; + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hw_mgr_ctx, + CAM_ISP_HW_EVENT_EOF); + if (!rc) { + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + break; + ife_hw_irq_eof_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EOF, &eof_done_event_data); + } + break; + + case CAM_ISP_HW_VFE_IN_RDI0: + case CAM_ISP_HW_VFE_IN_RDI1: + case CAM_ISP_HW_VFE_IN_RDI2: + case CAM_ISP_HW_VFE_IN_RDI3: + case CAM_ISP_HW_VFE_IN_PDLIB: + case CAM_ISP_HW_VFE_IN_LCR: + break; + + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid res_id: %d", + event_info->res_id); + break; + } + + CAM_DBG(CAM_ISP, "EOF for VFE:%d source %d", event_info->hw_idx, + event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_handle_hw_buf_done( + void *ctx, + void *evt_info) +{ + cam_hw_event_cb_func ife_hwr_irq_wm_done_cb; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx = ctx; + struct cam_isp_hw_done_event_data buf_done_event_data = {0}; + struct cam_isp_hw_event_info *event_info = evt_info; + + ife_hwr_irq_wm_done_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE]; + + buf_done_event_data.num_handles = 1; + buf_done_event_data.resource_handle[0] = event_info->res_id; + + if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) + return 0; + + if (buf_done_event_data.num_handles > 0 && ife_hwr_irq_wm_done_cb) { + CAM_DBG(CAM_ISP, "Notify ISP context"); + ife_hwr_irq_wm_done_cb(ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_DONE, &buf_done_event_data); + } + + CAM_DBG(CAM_ISP, "Buf done for VFE:%d out_res->res_id: 0x%x", + event_info->hw_idx, event_info->res_id); + + return 0; +} + +static int cam_ife_hw_mgr_event_handler( + void *priv, + uint32_t evt_id, + void *evt_info) +{ + int rc = 0; + + if (!evt_info) + return -EINVAL; + + if (!priv) + if (evt_id != CAM_ISP_HW_EVENT_ERROR) + return -EINVAL; + + CAM_DBG(CAM_ISP, "Event ID 0x%x", evt_id); + + switch (evt_id) { + case CAM_ISP_HW_EVENT_SOF: + rc = cam_ife_hw_mgr_handle_hw_sof(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_REG_UPDATE: + rc = cam_ife_hw_mgr_handle_hw_rup(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_EPOCH: + rc = cam_ife_hw_mgr_handle_hw_epoch(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_EOF: + rc = cam_ife_hw_mgr_handle_hw_eof(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_DONE: + rc = cam_ife_hw_mgr_handle_hw_buf_done(priv, evt_info); + break; + + case CAM_ISP_HW_EVENT_ERROR: + rc = cam_ife_hw_mgr_handle_hw_err(evt_info); + break; + + default: + CAM_ERR(CAM_ISP, "Invalid event ID %d", evt_id); + break; + } + + return rc; +} + +static int cam_ife_hw_mgr_sort_dev_with_caps( + struct cam_ife_hw_mgr *ife_hw_mgr) +{ + int i; + + /* get caps for csid devices */ + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; + if (ife_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps) { + ife_hw_mgr->csid_devices[i]->hw_ops.get_hw_caps( + ife_hw_mgr->csid_devices[i]->hw_priv, + &ife_hw_mgr->ife_csid_dev_caps[i], + sizeof(ife_hw_mgr->ife_csid_dev_caps[i])); + } + } + + /* get caps for ife devices */ + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->ife_devices[i]) + continue; + if (ife_hw_mgr->ife_devices[i]->hw_ops.get_hw_caps) { + ife_hw_mgr->ife_devices[i]->hw_ops.get_hw_caps( + ife_hw_mgr->ife_devices[i]->hw_priv, + &ife_hw_mgr->ife_dev_caps[i], + sizeof(ife_hw_mgr->ife_dev_caps[i])); + } + } + + return 0; +} + +static int cam_ife_set_csid_debug(void *data, u64 val) +{ + g_ife_hw_mgr.debug_cfg.csid_debug = val; + CAM_DBG(CAM_ISP, "Set CSID Debug value :%lld", val); + return 0; +} + +static int cam_ife_get_csid_debug(void *data, u64 *val) +{ + *val = g_ife_hw_mgr.debug_cfg.csid_debug; + CAM_DBG(CAM_ISP, "Get CSID Debug value :%lld", + g_ife_hw_mgr.debug_cfg.csid_debug); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_ife_csid_debug, + cam_ife_get_csid_debug, + cam_ife_set_csid_debug, "%16llu"); + +static int cam_ife_set_camif_debug(void *data, u64 val) +{ + g_ife_hw_mgr.debug_cfg.camif_debug = val; + CAM_DBG(CAM_ISP, + "Set camif enable_diag_sensor_status value :%lld", val); + return 0; +} + +static int cam_ife_get_camif_debug(void *data, u64 *val) +{ + *val = g_ife_hw_mgr.debug_cfg.camif_debug; + CAM_DBG(CAM_ISP, + "Set camif enable_diag_sensor_status value :%lld", + g_ife_hw_mgr.debug_cfg.csid_debug); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_ife_camif_debug, + cam_ife_get_camif_debug, + cam_ife_set_camif_debug, "%16llu"); + +static int cam_ife_hw_mgr_debug_register(void) +{ + g_ife_hw_mgr.debug_cfg.dentry = debugfs_create_dir("camera_ife", + NULL); + + if (!g_ife_hw_mgr.debug_cfg.dentry) { + CAM_ERR(CAM_ISP, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_file("ife_csid_debug", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, NULL, + &cam_ife_csid_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_ife_csid_debug"); + goto err; + } + + if (!debugfs_create_u32("enable_recovery", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_recovery)) { + CAM_ERR(CAM_ISP, "failed to create enable_recovery"); + goto err; + } + + if (!debugfs_create_bool("enable_req_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_req_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_req_dump"); + goto err; + } + + if (!debugfs_create_file("ife_camif_debug", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, NULL, + &cam_ife_camif_debug)) { + CAM_ERR(CAM_ISP, "failed to create cam_ife_camif_debug"); + goto err; + } + + if (!debugfs_create_bool("per_req_reg_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.per_req_reg_dump)) { + CAM_ERR(CAM_ISP, "failed to create per_req_reg_dump entry"); + goto err; + } + + g_ife_hw_mgr.debug_cfg.enable_recovery = 0; + + return 0; + +err: + debugfs_remove_recursive(g_ife_hw_mgr.debug_cfg.dentry); + return -ENOMEM; +} + +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) +{ + int rc = -EFAULT; + int i, j; + struct cam_iommu_handle cdm_handles; + struct cam_ife_hw_mgr_ctx *ctx_pool; + struct cam_ife_hw_mgr_res *res_list_ife_out; + + CAM_DBG(CAM_ISP, "Enter"); + + memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr)); + + mutex_init(&g_ife_hw_mgr.ctx_mutex); + + if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "CSID num is different then IFE num"); + return -EINVAL; + } + + /* fill ife hw intf information */ + for (i = 0, j = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + rc = cam_vfe_hw_init(&g_ife_hw_mgr.ife_devices[i], i); + if (!rc) { + struct cam_hw_info *vfe_hw = + (struct cam_hw_info *) + g_ife_hw_mgr.ife_devices[i]->hw_priv; + struct cam_hw_soc_info *soc_info = &vfe_hw->soc_info; + + j++; + + g_ife_hw_mgr.cdm_reg_map[i] = &soc_info->reg_map[0]; + CAM_DBG(CAM_ISP, + "reg_map: mem base = %pK cam_base = 0x%llx", + (void __iomem *)soc_info->reg_map[0].mem_base, + (uint64_t) soc_info->reg_map[0].mem_cam_base); + } else { + g_ife_hw_mgr.cdm_reg_map[i] = NULL; + } + } + if (j == 0) { + CAM_ERR(CAM_ISP, "no valid IFE HW"); + return -EINVAL; + } + + /* fill csid hw intf information */ + for (i = 0, j = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + rc = cam_ife_csid_hw_init(&g_ife_hw_mgr.csid_devices[i], i); + if (!rc) + j++; + } + if (!j) { + CAM_ERR(CAM_ISP, "no valid IFE CSID HW"); + return -EINVAL; + } + + cam_ife_hw_mgr_sort_dev_with_caps(&g_ife_hw_mgr); + + /* setup ife context list */ + INIT_LIST_HEAD(&g_ife_hw_mgr.free_ctx_list); + INIT_LIST_HEAD(&g_ife_hw_mgr.used_ctx_list); + + /* + * for now, we only support one iommu handle. later + * we will need to setup more iommu handle for other + * use cases. + * Also, we have to release them once we have the + * deinit support + */ + if (cam_smmu_get_handle("ife", + &g_ife_hw_mgr.mgr_common.img_iommu_hdl)) { + CAM_ERR(CAM_ISP, "Can not get iommu handle"); + return -EINVAL; + } + + if (cam_smmu_get_handle("cam-secure", + &g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure)) { + CAM_ERR(CAM_ISP, "Failed to get secure iommu handle"); + goto secure_fail; + } + + CAM_DBG(CAM_ISP, "iommu_handles: non-secure[0x%x], secure[0x%x]", + g_ife_hw_mgr.mgr_common.img_iommu_hdl, + g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure); + + if (!cam_cdm_get_iommu_handle("ife", &cdm_handles)) { + CAM_DBG(CAM_ISP, "Successfully acquired the CDM iommu handles"); + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl = cdm_handles.non_secure; + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure = + cdm_handles.secure; + } else { + CAM_DBG(CAM_ISP, "Failed to acquire the CDM iommu handles"); + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl = -1; + g_ife_hw_mgr.mgr_common.cmd_iommu_hdl_secure = -1; + } + + atomic_set(&g_ife_hw_mgr.active_ctx_cnt, 0); + for (i = 0; i < CAM_CTX_MAX; i++) { + memset(&g_ife_hw_mgr.ctx_pool[i], 0, + sizeof(g_ife_hw_mgr.ctx_pool[i])); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].list); + + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in.list); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_cid); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_csid); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_src); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in_rd); + ctx_pool = &g_ife_hw_mgr.ctx_pool[i]; + for (j = 0; j < CAM_IFE_HW_OUT_RES_MAX; j++) { + res_list_ife_out = &ctx_pool->res_list_ife_out[j]; + INIT_LIST_HEAD(&res_list_ife_out->list); + } + + /* init context pool */ + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].free_res_list); + for (j = 0; j < CAM_IFE_HW_RES_POOL_MAX; j++) { + INIT_LIST_HEAD( + &g_ife_hw_mgr.ctx_pool[i].res_pool[j].list); + list_add_tail( + &g_ife_hw_mgr.ctx_pool[i].res_pool[j].list, + &g_ife_hw_mgr.ctx_pool[i].free_res_list); + } + + g_ife_hw_mgr.ctx_pool[i].cdm_cmd = + kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_IFE_HW_ENTRIES_MAX - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!g_ife_hw_mgr.ctx_pool[i].cdm_cmd) { + rc = -ENOMEM; + CAM_ERR(CAM_ISP, "Allocation Failed for cdm command"); + goto end; + } + + g_ife_hw_mgr.ctx_pool[i].ctx_index = i; + g_ife_hw_mgr.ctx_pool[i].hw_mgr = &g_ife_hw_mgr; + + cam_tasklet_init(&g_ife_hw_mgr.mgr_common.tasklet_pool[i], + &g_ife_hw_mgr.ctx_pool[i], i); + g_ife_hw_mgr.ctx_pool[i].common.tasklet_info = + g_ife_hw_mgr.mgr_common.tasklet_pool[i]; + + + init_completion(&g_ife_hw_mgr.ctx_pool[i].config_done_complete); + list_add_tail(&g_ife_hw_mgr.ctx_pool[i].list, + &g_ife_hw_mgr.free_ctx_list); + } + + /* Create Worker for ife_hw_mgr with 10 tasks */ + rc = cam_req_mgr_workq_create("cam_ife_worker", 10, + &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Unable to create worker"); + goto end; + } + + /* fill return structure */ + hw_mgr_intf->hw_mgr_priv = &g_ife_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_ife_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_ife_mgr_acquire; + hw_mgr_intf->hw_start = cam_ife_mgr_start_hw; + hw_mgr_intf->hw_stop = cam_ife_mgr_stop_hw; + hw_mgr_intf->hw_read = cam_ife_mgr_read; + hw_mgr_intf->hw_write = cam_ife_mgr_write; + hw_mgr_intf->hw_release = cam_ife_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_ife_mgr_prepare_hw_update; + hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; + hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; + hw_mgr_intf->hw_reset = cam_ife_mgr_reset; + + if (iommu_hdl) + *iommu_hdl = g_ife_hw_mgr.mgr_common.img_iommu_hdl; + + cam_ife_hw_mgr_debug_register(); + CAM_DBG(CAM_ISP, "Exit"); + + return 0; +end: + if (rc) { + for (i = 0; i < CAM_CTX_MAX; i++) { + cam_tasklet_deinit( + &g_ife_hw_mgr.mgr_common.tasklet_pool[i]); + kfree(g_ife_hw_mgr.ctx_pool[i].cdm_cmd); + g_ife_hw_mgr.ctx_pool[i].cdm_cmd = NULL; + g_ife_hw_mgr.ctx_pool[i].common.tasklet_info = NULL; + } + } + cam_smmu_destroy_handle( + g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure); + g_ife_hw_mgr.mgr_common.img_iommu_hdl_secure = -1; +secure_fail: + cam_smmu_destroy_handle(g_ife_hw_mgr.mgr_common.img_iommu_hdl); + g_ife_hw_mgr.mgr_common.img_iommu_hdl = -1; + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..7e6b91bab91672dc9b3807371d3c7ba6a7bf36a4 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_HW_MGR_H_ +#define _CAM_IFE_HW_MGR_H_ + +#include <linux/completion.h> +#include <linux/time.h> +#include "cam_isp_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_tasklet_util.h" + +/* enum cam_ife_hw_mgr_res_type - manager resource node type */ +enum cam_ife_hw_mgr_res_type { + CAM_IFE_HW_MGR_RES_UNINIT, + CAM_IFE_HW_MGR_RES_ROOT, + CAM_IFE_HW_MGR_RES_CID, + CAM_IFE_HW_MGR_RES_CSID, + CAM_IFE_HW_MGR_RES_IFE_SRC, + CAM_IFE_HW_MGR_RES_IFE_IN_RD, + CAM_IFE_HW_MGR_RES_IFE_OUT, +}; + +/* IFE resource constants */ +#define CAM_IFE_HW_IN_RES_MAX (CAM_ISP_IFE_IN_RES_MAX & 0xFF) +#define CAM_IFE_HW_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_MAX & 0xFF) +#define CAM_IFE_HW_RES_POOL_MAX 64 + +/** + * struct cam_vfe_hw_mgr_res- HW resources for the VFE manager + * + * @list: used by the resource list + * @res_type: IFE manager resource type + * @res_id: resource id based on the resource type for root or + * leaf resource, it matches the KMD interface port id. + * For branch resrouce, it is defined by the ISP HW + * layer + * @hw_res: hw layer resource array. For single VFE, only one VFE + * hw resrouce will be acquired. For dual VFE, two hw + * resources from different VFE HW device will be + * acquired + * @parent: point to the parent resource node. + * @children: point to the children resource nodes + * @child_num: numbe of the child resource node. + * @is_secure informs whether the resource is in secure mode or not + * + */ +struct cam_ife_hw_mgr_res { + struct list_head list; + enum cam_ife_hw_mgr_res_type res_type; + uint32_t res_id; + uint32_t is_dual_vfe; + struct cam_isp_resource_node *hw_res[CAM_ISP_HW_SPLIT_MAX]; + + /* graph */ + struct cam_ife_hw_mgr_res *parent; + struct cam_ife_hw_mgr_res *child[CAM_IFE_HW_OUT_RES_MAX]; + uint32_t num_children; + uint32_t is_secure; +}; + + +/** + * struct ctx_base_info - Base hardware information for the context + * + * @idx: Base resource index + * @split_id: Split info for the base resource + * + */ +struct ctx_base_info { + uint32_t idx; + enum cam_isp_hw_split_id split_id; +}; + +/** + * struct cam_ife_hw_mgr_debug - contain the debug information + * + * @dentry: Debugfs entry + * @csid_debug: csid debug information + * @enable_recovery: enable recovery + * @enable_diag_sensor_status: enable sensor diagnosis status + * @enable_req_dump: Enable request dump on HW errors + * @per_req_reg_dump: Enable per request reg dump + * + */ +struct cam_ife_hw_mgr_debug { + struct dentry *dentry; + uint64_t csid_debug; + uint32_t enable_recovery; + uint32_t camif_debug; + bool enable_req_dump; + bool per_req_reg_dump; +}; + +/** + * struct cam_vfe_hw_mgr_ctx - IFE HW manager Context object + * + * @list: used by the ctx list. + * @common: common acquired context data + * @ctx_index: acquired context id. + * @hw_mgr: IFE hw mgr which owns this context + * @ctx_in_use: flag to tell whether context is active + * @res_list_ife_in: Starting resource(TPG,PHY0, PHY1...) Can only be + * one. + * @res_list_csid: CSID resource list + * @res_list_ife_src: IFE input resource list + * @res_list_ife_in_rd IFE input resource list for read path + * @res_list_ife_out: IFE output resoruces array + * @free_res_list: Free resources list for the branch node + * @res_pool: memory storage for the free resource list + * @irq_status0_mask: irq_status0_mask for the context + * @irq_status1_mask: irq_status1_mask for the context + * @base device base index array contain the all IFE HW + * instance associated with this context. + * @num_base number of valid base data in the base array + * @cdm_handle cdm hw acquire handle + * @cdm_ops cdm util operation pointer for building + * cdm commands + * @cdm_cmd cdm base and length request pointer + * @sof_cnt sof count value per core, used for dual VFE + * @epoch_cnt epoch count value per core, used for dual VFE + * @eof_cnt eof count value per core, used for dual VFE + * @overflow_pending flat to specify the overflow is pending for the + * context + * @cdm_done flag to indicate cdm has finished writing shadow + * registers + * @is_rdi_only_context flag to specify the context has only rdi resource + * @config_done_complete indicator for configuration complete + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc + * @applied_req_id: Last request id to be applied + * @last_dump_flush_req_id Last req id for which reg dump on flush was called + * @last_dump_err_req_id Last req id for which reg dump on error was called + * @init_done indicate whether init hw is done + * @is_fe_enable indicate whether fetch engine\read path is enabled + * @is_dual indicate whether context is in dual VFE mode + * @ts captured timestamp when the ctx is acquired + */ +struct cam_ife_hw_mgr_ctx { + struct list_head list; + struct cam_isp_hw_mgr_ctx common; + + uint32_t ctx_index; + struct cam_ife_hw_mgr *hw_mgr; + uint32_t ctx_in_use; + + struct cam_ife_hw_mgr_res res_list_ife_in; + struct list_head res_list_ife_cid; + struct list_head res_list_ife_csid; + struct list_head res_list_ife_src; + struct list_head res_list_ife_in_rd; + struct cam_ife_hw_mgr_res res_list_ife_out[ + CAM_IFE_HW_OUT_RES_MAX]; + + struct list_head free_res_list; + struct cam_ife_hw_mgr_res res_pool[CAM_IFE_HW_RES_POOL_MAX]; + + uint32_t irq_status0_mask[CAM_IFE_HW_NUM_MAX]; + uint32_t irq_status1_mask[CAM_IFE_HW_NUM_MAX]; + struct ctx_base_info base[CAM_IFE_HW_NUM_MAX]; + uint32_t num_base; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; + + uint32_t sof_cnt[CAM_IFE_HW_NUM_MAX]; + uint32_t epoch_cnt[CAM_IFE_HW_NUM_MAX]; + uint32_t eof_cnt[CAM_IFE_HW_NUM_MAX]; + atomic_t overflow_pending; + atomic_t cdm_done; + uint32_t is_rdi_only_context; + struct completion config_done_complete; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; + uint64_t applied_req_id; + uint64_t last_dump_flush_req_id; + uint64_t last_dump_err_req_id; + bool init_done; + bool is_fe_enable; + bool is_dual; + struct timespec64 ts; +}; + +/** + * struct cam_ife_hw_mgr - IFE HW Manager + * + * @mgr_common: common data for all HW managers + * @csid_devices; csid device instances array. This will be filled by + * HW manager during the initialization. + * @ife_devices: IFE device instances array. This will be filled by + * HW layer during initialization + * @ctx_mutex: mutex for the hw context pool + * @free_ctx_list: free hw context list + * @used_ctx_list: used hw context list + * @ctx_pool: context storage + * @ife_csid_dev_caps csid device capability stored per core + * @ife_dev_caps ife device capability per core + * @work q work queue for IFE hw manager + * @debug_cfg debug configuration + */ +struct cam_ife_hw_mgr { + struct cam_isp_hw_mgr mgr_common; + struct cam_hw_intf *csid_devices[CAM_IFE_CSID_HW_NUM_MAX]; + struct cam_hw_intf *ife_devices[CAM_IFE_HW_NUM_MAX]; + struct cam_soc_reg_map *cdm_reg_map[CAM_IFE_HW_NUM_MAX]; + + struct mutex ctx_mutex; + atomic_t active_ctx_cnt; + struct list_head free_ctx_list; + struct list_head used_ctx_list; + struct cam_ife_hw_mgr_ctx ctx_pool[CAM_CTX_MAX]; + + struct cam_ife_csid_hw_caps ife_csid_dev_caps[ + CAM_IFE_CSID_HW_NUM_MAX]; + struct cam_vfe_hw_get_hw_cap ife_dev_caps[CAM_IFE_HW_NUM_MAX]; + struct cam_req_mgr_core_workq *workq; + struct cam_ife_hw_mgr_debug debug_cfg; +}; + +/** + * cam_ife_hw_mgr_init() + * + * @brief: Initialize the IFE hardware manger. This is the + * etnry functinon for the IFE HW manager. + * + * @hw_mgr_intf: IFE hardware manager object returned + * @iommu_hdl: Iommu handle to be returned + * + */ +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); + +#endif /* _CAM_IFE_HW_MGR_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..b1567d6b9cd8cc5245563f6fd4861c8d73b9b6a3 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_isp_hw_mgr_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_debug_util.h" + + +int cam_isp_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl) +{ + int rc = 0; + const char *compat_str = NULL; + + rc = of_property_read_string_index(of_node, "arch-compat", 0, + (const char **)&compat_str); + + if (strnstr(compat_str, "ife", strlen(compat_str))) + rc = cam_ife_hw_mgr_init(hw_mgr, iommu_hdl); + else { + CAM_ERR(CAM_ISP, "Invalid ISP hw type"); + rc = -EINVAL; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..69e24bcc86259018e3041c2986bd1a26a1377db1 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_MGR_H_ +#define _CAM_ISP_HW_MGR_H_ + +#include "cam_isp_hw_mgr_intf.h" +#include "cam_tasklet_util.h" + +#define CAM_ISP_HW_NUM_MAX 7 + +/** + * struct cam_isp_hw_mgr_ctx - common acquired context for managers + * + * @takslet_info: assciated tasklet + * @event_cb: call back interface to ISP context. Set during + * acquire device + * @cb_priv: first argument for the call back function + * set during acquire device + * + */ +struct cam_isp_hw_mgr_ctx { + void *tasklet_info; + cam_hw_event_cb_func event_cb[CAM_ISP_HW_EVENT_MAX]; + void *cb_priv; +}; + +/** + * struct cam_isp_hw_mgr - ISP HW Manager common object + * + * @tasklet_pool: Tasklet pool + * @img_iommu_hdl: iommu memory handle for regular image buffer + * @img_iommu_hdl_secure: iommu memory handle for secure image buffer + * @cmd_iommu_hdl: iommu memory handle for regular command buffer + * @cmd_iommu_hdl: iommu memory handle for secure command buffer + * @scratch_buf_range: scratch buffer range (not for IFE) + * @scratch_buf_addr: scratch buffer address (not for IFE) + * + */ +struct cam_isp_hw_mgr { + void *tasklet_pool[CAM_CTX_MAX]; + int img_iommu_hdl; + int img_iommu_hdl_secure; + int cmd_iommu_hdl; + int cmd_iommu_hdl_secure; + uint32_t scratch_buf_range; + dma_addr_t scratch_buf_addr; +}; + +/** + * struct cam_hw_event_recovery_data - Payload for the recovery procedure + * + * @error_type: Error type that causes the recovery + * @affected_core: Array of the hardware cores that are affected + * @affected_ctx: Array of the hardware contexts that are affected + * @no_of_context: Actual number of the affected context + * + */ +struct cam_hw_event_recovery_data { + uint32_t error_type; + uint32_t affected_core[CAM_ISP_HW_NUM_MAX]; + struct cam_ife_hw_mgr_ctx *affected_ctx[CAM_CTX_MAX]; + uint32_t no_of_context; +}; +#endif /* _CAM_ISP_HW_MGR_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ccdfc05f103dda6fa7937a2b7f8a962a0b64e5a3 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tasklet_util.o cam_isp_packet_parser.o +obj-$(CONFIG_SPECTRA_CAMERA) += irq_controller/ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..86a14229915fe5945dda53e54e74cdd851808e5d --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -0,0 +1,945 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <media/cam_defs.h> +#include <media/cam_isp.h> +#include "cam_mem_mgr.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_isp_packet_parser.h" +#include "cam_debug_util.h" + +int cam_isp_add_change_base( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int rc = -EINVAL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res; + struct cam_isp_hw_get_cmd_update get_base; + struct cam_hw_update_entry *hw_entry; + uint32_t num_ent, i; + + hw_entry = prepare->hw_update_entries; + num_ent = prepare->num_hw_update_entries; + + /* Max one hw entries required for each base */ + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + list_for_each_entry(hw_mgr_res, res_list_isp_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + if (res->hw_intf->hw_idx != base_idx) + continue; + + get_base.res = res; + get_base.cmd_type = CAM_ISP_HW_CMD_GET_CHANGE_BASE; + get_base.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4; + get_base.cmd.size = kmd_buf_info->size - + kmd_buf_info->used_bytes; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_CHANGE_BASE, &get_base, + sizeof(struct cam_isp_hw_get_cmd_update)); + if (rc) + return rc; + + hw_entry[num_ent].handle = kmd_buf_info->handle; + hw_entry[num_ent].len = get_base.cmd.used_bytes; + hw_entry[num_ent].offset = kmd_buf_info->offset; + + /* Marking change base as IOCFG to reapply on bubble */ + hw_entry[num_ent].flags = CAM_ISP_IOCFG_BL; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + + kmd_buf_info->used_bytes += get_base.cmd.used_bytes; + kmd_buf_info->offset += get_base.cmd.used_bytes; + num_ent++; + prepare->num_hw_update_entries = num_ent; + + /* return success */ + return 0; + } + } + + return rc; +} + +static int cam_isp_update_dual_config( + struct cam_hw_prepare_update_args *prepare, + struct cam_cmd_buf_desc *cmd_desc, + uint32_t split_id, + uint32_t base_idx, + struct cam_ife_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out) +{ + int rc = -EINVAL; + struct cam_isp_dual_config *dual_config; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_resource_node *res; + struct cam_isp_hw_dual_isp_update_args dual_isp_update_args; + uint32_t outport_id; + uint32_t ports_plane_idx; + size_t len = 0, remain_len = 0; + uint32_t *cpu_addr; + uint32_t i, j; + + CAM_DBG(CAM_ISP, "cmd des size %d, length: %d", + cmd_desc->size, cmd_desc->length); + + rc = cam_packet_util_get_cmd_mem_addr( + cmd_desc->mem_handle, &cpu_addr, &len); + if (rc) + return rc; + + if ((len < sizeof(struct cam_isp_dual_config)) || + (cmd_desc->offset >= + (len - sizeof(struct cam_isp_dual_config)))) { + CAM_ERR(CAM_ISP, "not enough buffer provided"); + return -EINVAL; + } + remain_len = len - cmd_desc->offset; + cpu_addr += (cmd_desc->offset / 4); + dual_config = (struct cam_isp_dual_config *)cpu_addr; + + if ((dual_config->num_ports * + sizeof(struct cam_isp_dual_stripe_config)) > + (remain_len - offsetof(struct cam_isp_dual_config, stripes))) { + CAM_ERR(CAM_ISP, "not enough buffer for all the dual configs"); + return -EINVAL; + } + for (i = 0; i < dual_config->num_ports; i++) { + + if (i >= CAM_ISP_IFE_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, + "failed update for i:%d > size_isp_out:%d", + i, size_isp_out); + rc = -EINVAL; + goto end; + } + + hw_mgr_res = &res_list_isp_out[i]; + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + if (res->res_id < CAM_ISP_IFE_OUT_RES_BASE || + res->res_id >= CAM_ISP_IFE_OUT_RES_MAX) + continue; + + outport_id = res->res_id & 0xFF; + + ports_plane_idx = (j * (dual_config->num_ports * + CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + + if (dual_config->stripes[ports_plane_idx].port_id == 0) + continue; + + dual_isp_update_args.split_id = j; + dual_isp_update_args.res = res; + dual_isp_update_args.dual_cfg = dual_config; + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_STRIPE_UPDATE, + &dual_isp_update_args, + sizeof(struct cam_isp_hw_dual_isp_update_args)); + if (rc) + goto end; + } + } + +end: + return rc; +} + +int cam_isp_add_cmd_buf_update( + struct cam_ife_hw_mgr_res *hw_mgr_res, + uint32_t cmd_type, + uint32_t hw_cmd_type, + uint32_t base_idx, + uint32_t *cmd_buf_addr, + uint32_t kmd_buf_remain_size, + void *cmd_update_data, + uint32_t *bytes_used) +{ + int rc = 0; + struct cam_isp_resource_node *res; + struct cam_isp_hw_get_cmd_update cmd_update; + uint32_t i; + uint32_t total_used_bytes = 0; + + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + CAM_ERR(CAM_ISP, "io res id:%d not valid", + hw_mgr_res->res_type); + return -EINVAL; + } + + cmd_update.cmd_type = hw_cmd_type; + cmd_update.cmd.cmd_buf_addr = cmd_buf_addr; + cmd_update.cmd.size = kmd_buf_remain_size; + cmd_update.cmd.used_bytes = 0; + cmd_update.data = cmd_update_data; + CAM_DBG(CAM_ISP, "cmd_type %u cmd buffer 0x%pK, size %d", + cmd_update.cmd_type, + cmd_update.cmd.cmd_buf_addr, + cmd_update.cmd.size); + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->hw_res[i]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[i]; + cmd_update.res = res; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + cmd_update.cmd_type, &cmd_update, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + total_used_bytes += cmd_update.cmd.used_bytes; + } + *bytes_used = total_used_bytes; + CAM_DBG(CAM_ISP, "total_used_bytes %u", total_used_bytes); + return rc; +} + +int cam_isp_add_command_buffers( + struct cam_hw_prepare_update_args *prepare, + struct cam_kmd_buf_info *kmd_buf_info, + struct ctx_base_info *base_info, + cam_packet_generic_blob_handler blob_handler_cb, + struct cam_ife_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out) +{ + int rc = 0; + uint32_t cmd_meta_data, num_ent, i; + uint32_t base_idx; + enum cam_isp_hw_split_id split_id; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_hw_update_entry *hw_entry; + + hw_entry = prepare->hw_update_entries; + split_id = base_info->split_id; + base_idx = base_info->idx; + + /* + * set the cmd_desc to point the first command descriptor in the + * packet + */ + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint8_t *)&prepare->packet->payload + + prepare->packet->cmd_buf_offset); + + CAM_DBG(CAM_ISP, "split id = %d, number of command buffers:%d", + split_id, prepare->packet->num_cmd_buf); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + num_ent = prepare->num_hw_update_entries; + if (!cmd_desc[i].length) + continue; + + /* One hw entry space required for left or right or common */ + if (num_ent + 1 >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + num_ent, prepare->max_hw_update_entries); + return -EINVAL; + } + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) + return rc; + + cmd_meta_data = cmd_desc[i].meta_data; + + CAM_DBG(CAM_ISP, "meta type: %d, split_id: %d", + cmd_meta_data, split_id); + + switch (cmd_meta_data) { + case CAM_ISP_PACKET_META_BASE: + case CAM_ISP_PACKET_META_LEFT: + case CAM_ISP_PACKET_META_DMI_LEFT: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + hw_entry[num_ent].flags = + CAM_ISP_IQ_BL; + + num_ent++; + } + break; + case CAM_ISP_PACKET_META_RIGHT: + case CAM_ISP_PACKET_META_DMI_RIGHT: + if (split_id == CAM_ISP_HW_SPLIT_RIGHT) { + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + hw_entry[num_ent].flags = + CAM_ISP_IQ_BL; + num_ent++; + } + break; + case CAM_ISP_PACKET_META_COMMON: + case CAM_ISP_PACKET_META_DMI_COMMON: + hw_entry[num_ent].len = cmd_desc[i].length; + hw_entry[num_ent].handle = + cmd_desc[i].mem_handle; + hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + + num_ent++; + break; + case CAM_ISP_PACKET_META_DUAL_CONFIG: + rc = cam_isp_update_dual_config(prepare, + &cmd_desc[i], split_id, base_idx, + res_list_isp_out, size_isp_out); + + if (rc) + return rc; + break; + case CAM_ISP_PACKET_META_GENERIC_BLOB_LEFT: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", + rc); + return rc; + } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + num_ent = prepare->num_hw_update_entries; + } + break; + case CAM_ISP_PACKET_META_GENERIC_BLOB_RIGHT: + if (split_id == CAM_ISP_HW_SPLIT_RIGHT) { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", + rc); + return rc; + } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + num_ent = prepare->num_hw_update_entries; + } + break; + case CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON: { + struct cam_isp_generic_blob_info blob_info; + + prepare->num_hw_update_entries = num_ent; + blob_info.prepare = prepare; + blob_info.base_info = base_info; + blob_info.kmd_buf_info = kmd_buf_info; + + rc = cam_packet_util_process_generic_cmd_buffer( + &cmd_desc[i], + blob_handler_cb, + &blob_info); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed in processing blobs %d", rc); + return rc; + } + hw_entry[num_ent].flags = CAM_ISP_IQ_BL; + num_ent = prepare->num_hw_update_entries; + } + break; + case CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH: + case CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR: + case CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST: + if (split_id == CAM_ISP_HW_SPLIT_LEFT) { + if (prepare->num_reg_dump_buf >= + CAM_REG_DUMP_MAX_BUF_ENTRIES) { + CAM_ERR(CAM_ISP, + "Descriptor count out of bounds: %d", + prepare->num_reg_dump_buf); + return -EINVAL; + } + + prepare->reg_dump_buf_desc[ + prepare->num_reg_dump_buf] = + cmd_desc[i]; + prepare->num_reg_dump_buf++; + CAM_DBG(CAM_ISP, + "Added command buffer: %d desc_count: %d", + cmd_desc[i].meta_data, + prepare->num_reg_dump_buf); + } + break; + default: + CAM_ERR(CAM_ISP, "invalid cdm command meta data %d", + cmd_meta_data); + return -EINVAL; + } + prepare->num_hw_update_entries = num_ent; + } + + return rc; +} + +int cam_isp_add_io_buffers( + int iommu_hdl, + int sec_iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info, + struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, + uint32_t size_isp_out, + bool fill_fence) +{ + int rc = 0; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; + struct cam_buf_io_cfg *io_cfg; + struct cam_isp_resource_node *res; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_isp_hw_get_cmd_update update_buf; + struct cam_isp_hw_get_wm_update wm_update; + struct cam_isp_hw_get_wm_update bus_rd_update; + struct cam_hw_fence_map_entry *out_map_entries; + struct cam_hw_fence_map_entry *in_map_entries; + uint32_t kmd_buf_remain_size; + uint32_t i, j, num_out_buf, num_in_buf; + uint32_t res_id_out, res_id_in, plane_id; + uint32_t io_cfg_used_bytes, num_ent; + size_t size; + int32_t hdl; + int mmu_hdl; + bool mode, is_buf_secure; + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &prepare->packet->payload + + prepare->packet->io_configs_offset); + num_out_buf = 0; + num_in_buf = 0; + io_cfg_used_bytes = 0; + prepare->pf_data->packet = prepare->packet; + + /* Max one hw entries required for each base */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_ISP, "======= io config idx %d ============", i); + CAM_DBG(CAM_REQ, + "i %d req_id %llu resource_type:%d fence:%d direction %d", + i, prepare->packet->header.request_id, + io_cfg[i].resource_type, io_cfg[i].fence, + io_cfg[i].direction); + CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); + + if (io_cfg[i].direction == CAM_BUF_OUTPUT) { + res_id_out = io_cfg[i].resource_type & 0xFF; + if (res_id_out >= size_isp_out) { + CAM_ERR(CAM_ISP, "invalid out restype:%x", + io_cfg[i].resource_type); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, + "configure output io with fill fence %d", + fill_fence); + out_map_entries = + &prepare->out_map_entries[num_out_buf]; + if (fill_fence) { + if (num_out_buf < + prepare->max_out_map_entries) { + out_map_entries->resource_handle = + io_cfg[i].resource_type; + out_map_entries->sync_id = + io_cfg[i].fence; + num_out_buf++; + } else { + CAM_ERR(CAM_ISP, "ln_out:%d max_ln:%d", + num_out_buf, + prepare->max_out_map_entries); + return -EINVAL; + } + } + + hw_mgr_res = &res_list_isp_out[res_id_out]; + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) { + CAM_ERR(CAM_ISP, "io res id:%d not valid", + io_cfg[i].resource_type); + return -EINVAL; + } + } else if (io_cfg[i].direction == CAM_BUF_INPUT) { + res_id_in = io_cfg[i].resource_type & 0xFF; + CAM_DBG(CAM_ISP, + "configure input io with fill fence %d", + fill_fence); + if (!list_empty(res_list_ife_in_rd)) { + hw_mgr_res = + list_first_entry(res_list_ife_in_rd, + struct cam_ife_hw_mgr_res, list); + } else { + CAM_ERR(CAM_ISP, + "No IFE in Read resource"); + return -EINVAL; + } + in_map_entries = + &prepare->in_map_entries[num_in_buf]; + if (fill_fence) { + if (num_in_buf < prepare->max_in_map_entries) { + in_map_entries->resource_handle = + io_cfg[i].resource_type; + in_map_entries->sync_id = + io_cfg[i].fence; + num_in_buf++; + } else { + CAM_ERR(CAM_ISP, "ln_in:%d imax_ln:%d", + num_in_buf, + prepare->max_in_map_entries); + return -EINVAL; + } + } + } else { + CAM_ERR(CAM_ISP, "Invalid io config direction :%d", + io_cfg[i].direction); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "setup mem io"); + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_OUTPUT; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + if (res->res_id != io_cfg[i].resource_type) { + CAM_ERR(CAM_ISP, + "wm err res id:%d io res id:%d", + res->res_id, io_cfg[i].resource_type); + return -EINVAL; + } + + memset(io_addr, 0, sizeof(io_addr)); + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + break; + + hdl = io_cfg[i].mem_handle[plane_id]; + if (res->process_cmd(res, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, + sizeof(bool))) + return -EINVAL; + + is_buf_secure = cam_mem_is_secure_buf(hdl); + if ((mode == CAM_SECURE_MODE_SECURE) && + is_buf_secure) { + mmu_hdl = sec_iommu_hdl; + } else if ( + (mode == CAM_SECURE_MODE_NON_SECURE) && + (!is_buf_secure)) { + mmu_hdl = iommu_hdl; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid hdl: port mode[%u], buf mode[%u]", + mode, is_buf_secure); + return -EINVAL; + } + + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane_id], + mmu_hdl, &io_addr[plane_id], &size); + if (rc) { + CAM_ERR(CAM_ISP, + "no io addr for plane%d", + plane_id); + rc = -ENOMEM; + return rc; + } + + /* need to update with offset */ + io_addr[plane_id] += + io_cfg[i].offsets[plane_id]; + CAM_DBG(CAM_ISP, + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + + } + if (!plane_id) { + CAM_ERR(CAM_ISP, "No valid planes for res%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + wm_update.image_buf = io_addr; + wm_update.num_buf = plane_id; + wm_update.io_cfg = &io_cfg[i]; + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.wm_update = &wm_update; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + update_buf.cmd.cmd_buf_addr, + update_buf.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_BUF_UPDATE, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_INPUT; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + memset(io_addr, 0, sizeof(io_addr)); + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + break; + + hdl = io_cfg[i].mem_handle[plane_id]; + if (res->process_cmd(res, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, + sizeof(bool))) + return -EINVAL; + + is_buf_secure = cam_mem_is_secure_buf(hdl); + if ((mode == CAM_SECURE_MODE_SECURE) && + is_buf_secure) { + mmu_hdl = sec_iommu_hdl; + } else if ( + (mode == CAM_SECURE_MODE_NON_SECURE) && + (!is_buf_secure)) { + mmu_hdl = iommu_hdl; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid hdl: port mode[%u], buf mode[%u]", + mode, is_buf_secure); + return -EINVAL; + } + + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane_id], + mmu_hdl, &io_addr[plane_id], &size); + if (rc) { + CAM_ERR(CAM_ISP, + "no io addr for plane%d", + plane_id); + rc = -ENOMEM; + return rc; + } + + /* need to update with offset */ + io_addr[plane_id] += + io_cfg[i].offsets[plane_id]; + CAM_DBG(CAM_ISP, + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + + } + if (!plane_id) { + CAM_ERR(CAM_ISP, "No valid planes for res%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + bus_rd_update.image_buf = io_addr; + bus_rd_update.num_buf = plane_id; + bus_rd_update.io_cfg = &io_cfg[i]; + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.rm_update = &bus_rd_update; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + update_buf.cmd.cmd_buf_addr, + update_buf.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } + } + + CAM_DBG(CAM_ISP, "io_cfg_used_bytes %d, fill_fence %d", + io_cfg_used_bytes, fill_fence); + if (io_cfg_used_bytes) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + prepare->hw_update_entries[num_ent].flags = + CAM_ISP_IOCFG_BL; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); + num_ent++; + + kmd_buf_info->used_bytes += io_cfg_used_bytes; + kmd_buf_info->offset += io_cfg_used_bytes; + prepare->num_hw_update_entries = num_ent; + } + + if (fill_fence) { + prepare->num_out_map_entries = num_out_buf; + prepare->num_in_map_entries = num_in_buf; + } + + return rc; +} + + +int cam_isp_add_reg_update( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int rc = -EINVAL; + struct cam_isp_resource_node *res; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_update_entry *hw_entry; + struct cam_isp_hw_get_cmd_update get_regup; + uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size; + + hw_entry = prepare->hw_update_entries; + /* Max one hw entries required for each base */ + if (prepare->num_hw_update_entries + 1 >= + prepare->max_hw_update_entries) { + CAM_ERR(CAM_ISP, "Insufficient HW entries :%d %d", + prepare->num_hw_update_entries, + prepare->max_hw_update_entries); + return -EINVAL; + } + + reg_update_size = 0; + list_for_each_entry(hw_mgr_res, res_list_isp_src, list) { + if (hw_mgr_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + res = hw_mgr_res->hw_res[i]; + if (res->hw_intf->hw_idx != base_idx) + continue; + + if (kmd_buf_info->size > (kmd_buf_info->used_bytes + + reg_update_size)) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + reg_update_size); + } else { + CAM_ERR(CAM_ISP, "no free mem %d %d %d", + base_idx, kmd_buf_info->size, + kmd_buf_info->used_bytes + + reg_update_size); + rc = -EINVAL; + return rc; + } + + get_regup.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + reg_update_size/4; + get_regup.cmd.size = kmd_buf_remain_size; + get_regup.cmd_type = CAM_ISP_HW_CMD_GET_REG_UPDATE; + get_regup.res = res; + + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_REG_UPDATE, &get_regup, + sizeof(struct cam_isp_hw_get_cmd_update)); + if (rc) + return rc; + + CAM_DBG(CAM_ISP, "Reg update added for res %d hw_id %d", + res->res_id, res->hw_intf->hw_idx); + reg_update_size += get_regup.cmd.used_bytes; + } + } + + if (reg_update_size) { + /* Update the HW entries */ + num_ent = prepare->num_hw_update_entries; + prepare->hw_update_entries[num_ent].handle = + kmd_buf_info->handle; + prepare->hw_update_entries[num_ent].len = reg_update_size; + prepare->hw_update_entries[num_ent].offset = + kmd_buf_info->offset; + + /* Marking reg update as IOCFG to reapply on bubble */ + prepare->hw_update_entries[num_ent].flags = + CAM_ISP_IOCFG_BL; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); + num_ent++; + + kmd_buf_info->used_bytes += reg_update_size; + kmd_buf_info->offset += reg_update_size; + prepare->num_hw_update_entries = num_ent; + /* reg update is success return status 0 */ + rc = 0; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c new file mode 100644 index 0000000000000000000000000000000000000000..356c9a0a891967e704a887946683855506e7f0f9 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/ratelimit.h> +#include "cam_tasklet_util.h" +#include "cam_irq_controller.h" +#include "cam_debug_util.h" + +#define CAM_TASKLETQ_SIZE 256 + +static void cam_tasklet_action(unsigned long data); + +/** + * struct cam_tasklet_queue_cmd: + * @Brief: Structure associated with each slot in the + * tasklet queue + * + * @list: list_head member for each entry in queue + * @payload: Payload structure for the event. This will be + * passed to the handler function + * @handler_priv: Private data passed at event subscribe + * @bottom_half_handler: Function pointer for event handler in bottom + * half context + * + */ +struct cam_tasklet_queue_cmd { + struct list_head list; + void *payload; + void *handler_priv; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/** + * struct cam_tasklet_info: + * @Brief: Tasklet private structure + * + * @list: list_head member for each tasklet + * @index: Instance id for the tasklet + * @tasklet_lock: Spin lock + * @tasklet_active: Atomic variable to control tasklet state + * @tasklet: Tasklet structure used to schedule bottom half + * @free_cmd_list: List of free tasklet queue cmd for use + * @used_cmd_list: List of used tasklet queue cmd + * @cmd_queue: Array of tasklet cmd for storage + * @ctx_priv: Private data passed to the handling function + * + */ +struct cam_tasklet_info { + struct list_head list; + uint32_t index; + spinlock_t tasklet_lock; + atomic_t tasklet_active; + struct tasklet_struct tasklet; + + struct list_head free_cmd_list; + struct list_head used_cmd_list; + struct cam_tasklet_queue_cmd cmd_queue[CAM_TASKLETQ_SIZE]; + + void *ctx_priv; +}; + +struct cam_irq_bh_api tasklet_bh_api = { + .bottom_half_enqueue_func = cam_tasklet_enqueue_cmd, + .get_bh_payload_func = cam_tasklet_get_cmd, + .put_bh_payload_func = cam_tasklet_put_cmd, +}; + +int cam_tasklet_get_cmd( + void *bottom_half, + void **bh_cmd) +{ + int rc = 0; + unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; + + *bh_cmd = NULL; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return -EINVAL; + } + + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet idx:%d is not active", + tasklet->index); + rc = -EPIPE; + return rc; + } + + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + if (list_empty(&tasklet->free_cmd_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd idx:%d", + tasklet->index); + rc = -ENODEV; + goto spin_unlock; + } else { + tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, + struct cam_tasklet_queue_cmd, list); + list_del_init(&(tasklet_cmd)->list); + *bh_cmd = tasklet_cmd; + } + +spin_unlock: + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + return rc; +} + +void cam_tasklet_put_cmd( + void *bottom_half, + void **bh_cmd) +{ + unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = *bh_cmd; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return; + } + + if (tasklet_cmd == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid tasklet_cmd"); + return; + } + + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_del_init(&tasklet_cmd->list); + list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list); + *bh_cmd = NULL; + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); +} + +/** + * cam_tasklet_dequeue_cmd() + * + * @brief: Initialize the tasklet info structure + * + * @hw_mgr_ctx: Private Ctx data that will be passed to the handler + * function + * @idx: Index of tasklet used as identity + * @tasklet_action: Tasklet callback function that will be called + * when tasklet runs on CPU + * + * @return: 0: Success + * Negative: Failure + */ +static int cam_tasklet_dequeue_cmd( + struct cam_tasklet_info *tasklet, + struct cam_tasklet_queue_cmd **tasklet_cmd) +{ + int rc = 0; + unsigned long flags; + + *tasklet_cmd = NULL; + + CAM_DBG(CAM_ISP, "Dequeue before lock tasklet idx:%d", tasklet->index); + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + if (list_empty(&tasklet->used_cmd_list)) { + CAM_DBG(CAM_ISP, "End of list reached. Exit"); + rc = -ENODEV; + goto spin_unlock; + } else { + *tasklet_cmd = list_first_entry(&tasklet->used_cmd_list, + struct cam_tasklet_queue_cmd, list); + list_del_init(&(*tasklet_cmd)->list); + CAM_DBG(CAM_ISP, "Dequeue Successful"); + } + +spin_unlock: + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + return rc; +} + +void cam_tasklet_enqueue_cmd( + void *bottom_half, + void *bh_cmd, + void *handler_priv, + void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler) +{ + unsigned long flags; + struct cam_tasklet_queue_cmd *tasklet_cmd = bh_cmd; + struct cam_tasklet_info *tasklet = bottom_half; + + if (!bottom_half) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bottom half"); + return; + } + + if (!bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bh cmd"); + return; + } + + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active idx:%d", + tasklet->index); + return; + } + + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd idx:%d", tasklet->index); + tasklet_cmd->bottom_half_handler = bottom_half_handler; + tasklet_cmd->payload = evt_payload_priv; + tasklet_cmd->handler_priv = handler_priv; + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_add_tail(&tasklet_cmd->list, + &tasklet->used_cmd_list); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_hi_schedule(&tasklet->tasklet); +} + +int cam_tasklet_init( + void **tasklet_info, + void *hw_mgr_ctx, + uint32_t idx) +{ + int i; + struct cam_tasklet_info *tasklet = NULL; + + tasklet = kzalloc(sizeof(struct cam_tasklet_info), GFP_KERNEL); + if (!tasklet) { + CAM_DBG(CAM_ISP, + "Error! Unable to allocate memory for tasklet"); + *tasklet_info = NULL; + return -ENOMEM; + } + + tasklet->ctx_priv = hw_mgr_ctx; + tasklet->index = idx; + spin_lock_init(&tasklet->tasklet_lock); + memset(tasklet->cmd_queue, 0, sizeof(tasklet->cmd_queue)); + INIT_LIST_HEAD(&tasklet->free_cmd_list); + INIT_LIST_HEAD(&tasklet->used_cmd_list); + for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { + INIT_LIST_HEAD(&tasklet->cmd_queue[i].list); + list_add_tail(&tasklet->cmd_queue[i].list, + &tasklet->free_cmd_list); + } + tasklet_init(&tasklet->tasklet, cam_tasklet_action, + (unsigned long)tasklet); + tasklet_disable(&tasklet->tasklet); + + *tasklet_info = tasklet; + + return 0; +} + +void cam_tasklet_deinit(void **tasklet_info) +{ + struct cam_tasklet_info *tasklet = *tasklet_info; + + if (atomic_read(&tasklet->tasklet_active)) { + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + } + kfree(tasklet); + *tasklet_info = NULL; +} + +static inline void cam_tasklet_flush(struct cam_tasklet_info *tasklet_info) +{ + cam_tasklet_action((unsigned long) tasklet_info); +} + +int cam_tasklet_start(void *tasklet_info) +{ + struct cam_tasklet_info *tasklet = tasklet_info; + int i = 0; + + if (atomic_read(&tasklet->tasklet_active)) { + CAM_ERR(CAM_ISP, "Tasklet already active idx:%d", + tasklet->index); + return -EBUSY; + } + + /* clean up the command queue first */ + for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { + list_del_init(&tasklet->cmd_queue[i].list); + list_add_tail(&tasklet->cmd_queue[i].list, + &tasklet->free_cmd_list); + } + + atomic_set(&tasklet->tasklet_active, 1); + + tasklet_enable(&tasklet->tasklet); + + return 0; +} + +void cam_tasklet_stop(void *tasklet_info) +{ + struct cam_tasklet_info *tasklet = tasklet_info; + + if (!atomic_read(&tasklet->tasklet_active)) + return; + + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + cam_tasklet_flush(tasklet); +} + +/* + * cam_tasklet_action() + * + * @brief: Process function that will be called when tasklet runs + * on CPU + * + * @data: Tasklet Info structure that is passed in tasklet_init + * + * @return: Void + */ +static void cam_tasklet_action(unsigned long data) +{ + struct cam_tasklet_info *tasklet_info = NULL; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; + + tasklet_info = (struct cam_tasklet_info *)data; + + while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) { + tasklet_cmd->bottom_half_handler(tasklet_cmd->handler_priv, + tasklet_cmd->payload); + cam_tasklet_put_cmd(tasklet_info, (void **)(&tasklet_cmd)); + } +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..c9bd4c4430e99cd45d1c67837fcbe233eece8da1 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_PARSER_H_ +#define _CAM_ISP_HW_PARSER_H_ + +#include <linux/types.h> +#include <media/cam_isp.h> +#include "cam_isp_hw_mgr_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_hw_intf.h" +#include "cam_packet_util.h" + +/* enum cam_isp_cdm_bl_type - isp cdm packet type*/ +enum cam_isp_cdm_bl_type { + CAM_ISP_UNUSED_BL, + CAM_ISP_IQ_BL, + CAM_ISP_IOCFG_BL, + CAM_ISP_BL_MAX, +}; + +/* + * struct cam_isp_generic_blob_info + * + * @prepare: Payload for prepare command + * @ctx_base_info: Base hardware information for the context + * @kmd_buf_info: Kmd buffer to store the custom cmd data + */ +struct cam_isp_generic_blob_info { + struct cam_hw_prepare_update_args *prepare; + struct ctx_base_info *base_info; + struct cam_kmd_buf_info *kmd_buf_info; +}; + +/* + * cam_isp_add_change_base() + * + * @brief Add change base in the hw entries list + * processe the isp source list get the change base from + * ISP HW instance + * + * @prepare: Contain the packet and HW update variables + * @res_list_isp_src: Resource list for IFE/VFE source + * @base_idx: Base or dev index of the IFE/VFE HW instance for + * which change change base need to be added + * @kmd_buf_info: Kmd buffer to store the change base command + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_change_base( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info); + +/* + * cam_isp_add_cmd_buf_update() + * + * @brief Add command buffer in the HW entries list for given + * Blob Data. + * + * @hw_mgr_res: HW resource to get the update from + * @cmd_type: Cmd type to get update for + * @hw_cmd_type: HW Cmd type corresponding to cmd_type + * @base_idx: Base hardware index + * @cmd_buf_addr: Cpu buf addr of kmd scratch buffer + * @kmd_buf_remain_size: Remaining size left for cmd buffer update + * @cmd_update_data: Data needed by HW to process the cmd and provide + * cmd buffer + * @bytes_used: Address of the field to be populated with + * total bytes used as output to caller + * + * @return: Negative for Failure + * otherwise returns bytes used + */ +int cam_isp_add_cmd_buf_update( + struct cam_ife_hw_mgr_res *hw_mgr_res, + uint32_t cmd_type, + uint32_t hw_cmd_type, + uint32_t base_idx, + uint32_t *cmd_buf_addr, + uint32_t kmd_buf_remain_size, + void *cmd_update_data, + uint32_t *bytes_used); + +/* + * cam_isp_add_command_buffers() + * + * @brief Add command buffer in the HW entries list for given + * left or right VFE/IFE instance. + * + * @prepare: Contain the packet and HW update variables + * @kmd_buf_info: KMD buffer to store the custom cmd data + * @base_info: base hardware information + * @blob_handler_cb: Call_back_function for Meta handling + * @res_list_isp_out: IFE /VFE out resource list + * @size_isp_out: Size of the res_list_isp_out array + * + * @return: 0 for success + * Negative for Failure + */ +int cam_isp_add_command_buffers( + struct cam_hw_prepare_update_args *prepare, + struct cam_kmd_buf_info *kmd_buf_info, + struct ctx_base_info *base_info, + cam_packet_generic_blob_handler blob_handler_cb, + struct cam_ife_hw_mgr_res *res_list_isp_out, + uint32_t size_isp_out); + +/* + * cam_isp_add_io_buffers() + * + * @brief Add io buffer configurations in the HW entries list + * processe the io configurations based on the base + * index and update the HW entries list + * + * @iommu_hdl: Iommu handle to get the IO buf from memory manager + * @sec_iommu_hdl: Secure iommu handle to get the IO buf from + * memory manager + * @prepare: Contain the packet and HW update variables + * @base_idx: Base or dev index of the IFE/VFE HW instance + * @kmd_buf_info: Kmd buffer to store the change base command + * @res_list_isp_out: IFE /VFE out resource list + * @res_list_ife_in_rd: IFE /VFE in rd resource list + * @size_isp_out: Size of the res_list_isp_out array + * @fill_fence: If true, Fence map table will be filled + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_io_buffers( + int iommu_hdl, + int sec_iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info, + struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, + uint32_t size_isp_out, + bool fill_fence); + +/* + * cam_isp_add_reg_update() + * + * @brief Add reg update in the hw entries list + * processe the isp source list get the reg update from + * ISP HW instance + * + * @prepare: Contain the packet and HW update variables + * @res_list_isp_src: Resource list for IFE/VFE source + * @base_idx: Base or dev index of the IFE/VFE HW instance + * @kmd_buf_info: Kmd buffer to store the change base command + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_isp_add_reg_update( + struct cam_hw_prepare_update_args *prepare, + struct list_head *res_list_isp_src, + uint32_t base_idx, + struct cam_kmd_buf_info *kmd_buf_info); + +#endif /*_CAM_ISP_HW_PARSER_H */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h new file mode 100644 index 0000000000000000000000000000000000000000..22beb49ef6fca022ac0549fe85f648c6acd43acb --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_TASKLET_UTIL_H_ +#define _CAM_TASKLET_UTIL_H_ + +#include "cam_irq_controller.h" + +/* + * cam_tasklet_init() + * + * @brief: Initialize the tasklet info structure + * + * @tasklet: Tasklet to initialize + * @hw_mgr_ctx: Private Ctx data that will be passed to the handler + * function + * @idx: Index of tasklet used as identity + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_init( + void **tasklet, + void *hw_mgr_ctx, + uint32_t idx); + +/* + * cam_tasklet_deinit() + * + * @brief: Deinitialize the tasklet info structure + * + * @tasklet: Tasklet to deinitialize + * + * @return: Void + */ +void cam_tasklet_deinit(void **tasklet); + +/* + * cam_tasklet_start() + * + * @brief: Enable the tasklet to be scheduled and run. + * Caller should make sure this function is called + * before trying to enqueue. + * + * @tasklet: Tasklet to start + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_start(void *tasklet); + +/* + * cam_tasklet_stop() + * + * @brief: Disable the tasklet so it can no longer be scheduled. + * Need to enable again to run. + * + * @tasklet: Tasklet to stop + * + * @return: Void + */ +void cam_tasklet_stop(void *tasklet); + +/* + * cam_tasklet_enqueue_cmd() + * + * @brief: Enqueue the tasklet_cmd to used list + * + * @bottom_half: Tasklet info to enqueue onto + * @bh_cmd: Tasklet cmd used to enqueue task + * @handler_priv: Private Handler data that will be passed to the + * handler function + * @evt_payload_priv: Event payload that will be passed to the handler + * function + * @bottom_half_handler: Callback function that will be called by tasklet + * for handling event + * + * @return: Void + */ +void cam_tasklet_enqueue_cmd( + void *bottom_half, + void *bh_cmd, + void *handler_priv, + void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler); + +/** + * cam_tasklet_get_cmd() + * + * @brief: Get free cmd from tasklet + * + * @bottom_half: Tasklet Info structure to get cmd from + * @bh_cmd: Return tasklet_cmd pointer if successful + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_get_cmd(void *bottom_half, void **bh_cmd); + +/** + * cam_tasklet_put_cmd() + * + * @brief: Put back cmd to free list + * + * @bottom_half: Tasklet Info structure to put cmd into + * @bh_cmd: tasklet_cmd pointer that needs to be put back + * + * @return: Void + */ +void cam_tasklet_put_cmd(void *bottom_half, void **bh_cmd); + +extern struct cam_irq_bh_api tasklet_bh_api; + +#endif /* _CAM_TASKLET_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fb595fe8f02a2e722de6bc00e8dbd5131fb8bf57 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_irq_controller.o \ No newline at end of file diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c new file mode 100644 index 0000000000000000000000000000000000000000..cc1fe18e05fdde8845d21b4f95c23ef7d6f291d7 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -0,0 +1,750 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include <linux/ratelimit.h> + +#include "cam_io_util.h" +#include "cam_irq_controller.h" +#include "cam_debug_util.h" + +/** + * struct cam_irq_evt_handler: + * @Brief: Event handler information + * + * @priority: Priority level of this event + * @evt_bit_mask_arr: evt_bit_mask that has the bits set for IRQs to + * subscribe for + * @handler_priv: Private data that will be passed to the Top/Bottom + * Half handler function + * @top_half_handler: Top half Handler callback function + * @bottom_half_handler: Bottom half Handler callback function + * @bottom_half: Pointer to bottom_half implementation on which to + * enqueue the event for further handling + * @bottom_half_enqueue_func: + * Function used to enqueue the bottom_half event + * @list_node: list_head struct used for overall handler List + * @th_list_node: list_head struct used for top half handler List + */ +struct cam_irq_evt_handler { + enum cam_irq_priority_level priority; + uint32_t *evt_bit_mask_arr; + void *handler_priv; + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; + void *bottom_half; + struct cam_irq_bh_api irq_bh_api; + struct list_head list_node; + struct list_head th_list_node; + int index; +}; + +/** + * struct cam_irq_register_obj: + * @Brief: Structure containing information related to + * a particular register Set + * + * @index: Index of set in Array + * @mask_reg_offset: Offset of IRQ MASK register + * @clear_reg_offset: Offset of IRQ CLEAR register + * @status_reg_offset: Offset of IRQ STATUS register + * @top_half_enable_mask: Array of enabled bit_mask sorted by priority + * @pclear_mask: Partial mask to be cleared in case entire status + * register is not to be cleared + */ +struct cam_irq_register_obj { + uint32_t index; + uint32_t mask_reg_offset; + uint32_t clear_reg_offset; + uint32_t status_reg_offset; + uint32_t top_half_enable_mask[CAM_IRQ_PRIORITY_MAX]; + uint32_t pclear_mask; +}; + +/** + * struct cam_irq_controller: + * + * @brief: IRQ Controller structure. + * + * @name: Name of IRQ Controller block + * @mem_base: Mapped base address of register space to which + * register offsets are added to access registers + * @num_registers: Number of sets(mask/clear/status) of IRQ registers + * @irq_register_arr: Array of Register object associated with this + * Controller + * @irq_status_arr: Array of IRQ Status values + * @global_clear_offset: Offset of Global IRQ Clear register. This register + * contains the BIT that needs to be set for the CLEAR + * to take effect + * @global_clear_bitmask: Bitmask needed to be used in Global Clear register + * for Clear IRQ cmd to take effect + * @evt_handler_list_head: List of all event handlers + * @th_list_head: List of handlers sorted by priority + * @hdl_idx: Unique identity of handler assigned on Subscribe. + * Used to Unsubscribe. + * @lock: Lock for use by controller + * @clear_all: Flag to indicate whether to clear entire status + * register + */ +struct cam_irq_controller { + const char *name; + void __iomem *mem_base; + uint32_t num_registers; + struct cam_irq_register_obj *irq_register_arr; + uint32_t *irq_status_arr; + uint32_t global_clear_offset; + uint32_t global_clear_bitmask; + struct list_head evt_handler_list_head; + struct list_head th_list_head[CAM_IRQ_PRIORITY_MAX]; + uint32_t hdl_idx; + spinlock_t lock; + struct cam_irq_th_payload th_payload; + bool clear_all; +}; + +int cam_irq_controller_deinit(void **irq_controller) +{ + struct cam_irq_controller *controller = *irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + + while (!list_empty(&controller->evt_handler_list_head)) { + evt_handler = list_first_entry( + &controller->evt_handler_list_head, + struct cam_irq_evt_handler, list_node); + list_del_init(&evt_handler->list_node); + kfree(evt_handler->evt_bit_mask_arr); + kfree(evt_handler); + } + + kfree(controller->th_payload.evt_status_arr); + kfree(controller->irq_status_arr); + kfree(controller->irq_register_arr); + kfree(controller); + *irq_controller = NULL; + return 0; +} + +int cam_irq_controller_init(const char *name, + void __iomem *mem_base, + struct cam_irq_controller_reg_info *register_info, + void **irq_controller, + bool clear_all) +{ + struct cam_irq_controller *controller = NULL; + int i, rc = 0; + + *irq_controller = NULL; + + if (!register_info->num_registers || !register_info->irq_reg_set || + !name || !mem_base) { + CAM_ERR(CAM_IRQ_CTRL, "Invalid parameters"); + rc = -EINVAL; + return rc; + } + + controller = kzalloc(sizeof(struct cam_irq_controller), GFP_KERNEL); + if (!controller) { + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ Controller"); + return -ENOMEM; + } + + controller->irq_register_arr = kzalloc(register_info->num_registers * + sizeof(struct cam_irq_register_obj), GFP_KERNEL); + if (!controller->irq_register_arr) { + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ register Arr"); + rc = -ENOMEM; + goto reg_alloc_error; + } + + controller->irq_status_arr = kzalloc(register_info->num_registers * + sizeof(uint32_t), GFP_KERNEL); + if (!controller->irq_status_arr) { + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ status Arr"); + rc = -ENOMEM; + goto status_alloc_error; + } + + controller->th_payload.evt_status_arr = + kzalloc(register_info->num_registers * sizeof(uint32_t), + GFP_KERNEL); + if (!controller->th_payload.evt_status_arr) { + CAM_DBG(CAM_IRQ_CTRL, + "Failed to allocate BH payload bit mask Arr"); + rc = -ENOMEM; + goto evt_mask_alloc_error; + } + + controller->name = name; + + CAM_DBG(CAM_IRQ_CTRL, "num_registers: %d", + register_info->num_registers); + for (i = 0; i < register_info->num_registers; i++) { + controller->irq_register_arr[i].index = i; + controller->irq_register_arr[i].mask_reg_offset = + register_info->irq_reg_set[i].mask_reg_offset; + controller->irq_register_arr[i].clear_reg_offset = + register_info->irq_reg_set[i].clear_reg_offset; + controller->irq_register_arr[i].status_reg_offset = + register_info->irq_reg_set[i].status_reg_offset; + CAM_DBG(CAM_IRQ_CTRL, "i %d mask_reg_offset: 0x%x", i, + controller->irq_register_arr[i].mask_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "i %d clear_reg_offset: 0x%x", i, + controller->irq_register_arr[i].clear_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "i %d status_reg_offset: 0x%x", i, + controller->irq_register_arr[i].status_reg_offset); + } + controller->num_registers = register_info->num_registers; + controller->global_clear_bitmask = register_info->global_clear_bitmask; + controller->global_clear_offset = register_info->global_clear_offset; + controller->mem_base = mem_base; + controller->clear_all = clear_all; + + CAM_DBG(CAM_IRQ_CTRL, "global_clear_bitmask: 0x%x", + controller->global_clear_bitmask); + CAM_DBG(CAM_IRQ_CTRL, "global_clear_offset: 0x%x", + controller->global_clear_offset); + CAM_DBG(CAM_IRQ_CTRL, "mem_base: %pK", + (void __iomem *)controller->mem_base); + + INIT_LIST_HEAD(&controller->evt_handler_list_head); + for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) + INIT_LIST_HEAD(&controller->th_list_head[i]); + + spin_lock_init(&controller->lock); + + controller->hdl_idx = 1; + *irq_controller = controller; + + return rc; + +evt_mask_alloc_error: + kfree(controller->irq_status_arr); +status_alloc_error: + kfree(controller->irq_register_arr); +reg_alloc_error: + kfree(controller); + + return rc; +} + +int cam_irq_controller_subscribe_irq(void *irq_controller, + enum cam_irq_priority_level priority, + uint32_t *evt_bit_mask_arr, + void *handler_priv, + CAM_IRQ_HANDLER_TOP_HALF top_half_handler, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, + void *bottom_half, + struct cam_irq_bh_api *irq_bh_api) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + int i; + int rc = 0; + uint32_t irq_mask; + unsigned long flags = 0; + bool need_lock; + + if (!controller || !handler_priv || !evt_bit_mask_arr) { + CAM_ERR(CAM_IRQ_CTRL, + "Inval params: ctlr=%pK hdl_priv=%pK bit_mask_arr=%pK", + controller, handler_priv, evt_bit_mask_arr); + return -EINVAL; + } + + if (!top_half_handler) { + CAM_ERR(CAM_IRQ_CTRL, "Missing top half handler"); + return -EINVAL; + } + + if (bottom_half_handler && + (!bottom_half || !irq_bh_api)) { + CAM_ERR(CAM_IRQ_CTRL, + "Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK", + bottom_half_handler, + bottom_half, + irq_bh_api); + return -EINVAL; + } + + if (irq_bh_api && + (!irq_bh_api->bottom_half_enqueue_func || + !irq_bh_api->get_bh_payload_func || + !irq_bh_api->put_bh_payload_func)) { + CAM_ERR(CAM_IRQ_CTRL, + "Invalid: enqueue_func=%pK get_bh=%pK put_bh=%pK", + irq_bh_api->bottom_half_enqueue_func, + irq_bh_api->get_bh_payload_func, + irq_bh_api->put_bh_payload_func); + return -EINVAL; + } + + if (priority >= CAM_IRQ_PRIORITY_MAX) { + CAM_ERR(CAM_IRQ_CTRL, "Invalid priority=%u, max=%u", priority, + CAM_IRQ_PRIORITY_MAX); + return -EINVAL; + } + + evt_handler = kzalloc(sizeof(struct cam_irq_evt_handler), GFP_KERNEL); + if (!evt_handler) { + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); + return -ENOMEM; + } + + evt_handler->evt_bit_mask_arr = kzalloc(sizeof(uint32_t) * + controller->num_registers, GFP_KERNEL); + if (!evt_handler->evt_bit_mask_arr) { + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); + rc = -ENOMEM; + goto free_evt_handler; + } + + INIT_LIST_HEAD(&evt_handler->list_node); + INIT_LIST_HEAD(&evt_handler->th_list_node); + + for (i = 0; i < controller->num_registers; i++) + evt_handler->evt_bit_mask_arr[i] = evt_bit_mask_arr[i]; + + evt_handler->priority = priority; + evt_handler->handler_priv = handler_priv; + evt_handler->top_half_handler = top_half_handler; + evt_handler->bottom_half_handler = bottom_half_handler; + evt_handler->bottom_half = bottom_half; + evt_handler->index = controller->hdl_idx++; + + if (irq_bh_api) + evt_handler->irq_bh_api = *irq_bh_api; + + /* Avoid rollover to negative values */ + if (controller->hdl_idx > 0x3FFFFFFF) + controller->hdl_idx = 1; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + for (i = 0; i < controller->num_registers; i++) { + controller->irq_register_arr[i].top_half_enable_mask[priority] + |= evt_bit_mask_arr[i]; + + controller->irq_register_arr[i].pclear_mask + |= evt_bit_mask_arr[i]; + + irq_mask = cam_io_r_mb(controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + irq_mask |= evt_bit_mask_arr[i]; + + cam_io_w_mb(irq_mask, controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + } + + list_add_tail(&evt_handler->list_node, + &controller->evt_handler_list_head); + list_add_tail(&evt_handler->th_list_node, + &controller->th_list_head[priority]); + + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return evt_handler->index; + +free_evt_handler: + kfree(evt_handler); + evt_handler = NULL; + + return rc; +} + +int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_evt_handler *evt_handler_temp; + struct cam_irq_register_obj *irq_register = NULL; + enum cam_irq_priority_level priority; + unsigned long flags = 0; + unsigned int i; + uint32_t irq_mask; + uint32_t found = 0; + int rc = -EINVAL; + bool need_lock; + + if (!controller) + return rc; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + + list_for_each_entry_safe(evt_handler, evt_handler_temp, + &controller->evt_handler_list_head, list_node) { + if (evt_handler->index == handle) { + CAM_DBG(CAM_IRQ_CTRL, "enable item %d", handle); + found = 1; + rc = 0; + break; + } + } + + if (!found) { + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + return rc; + } + + priority = evt_handler->priority; + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + irq_register->top_half_enable_mask[priority] |= + evt_handler->evt_bit_mask_arr[i]; + + irq_mask = cam_io_r_mb(controller->mem_base + + irq_register->mask_reg_offset); + irq_mask |= evt_handler->evt_bit_mask_arr[i]; + + cam_io_w_mb(irq_mask, controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + } + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return rc; +} + +int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_evt_handler *evt_handler_temp; + struct cam_irq_register_obj *irq_register; + enum cam_irq_priority_level priority; + unsigned long flags = 0; + unsigned int i; + uint32_t irq_mask; + uint32_t found = 0; + int rc = -EINVAL; + bool need_lock; + + if (!controller) + return rc; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + + list_for_each_entry_safe(evt_handler, evt_handler_temp, + &controller->evt_handler_list_head, list_node) { + if (evt_handler->index == handle) { + CAM_DBG(CAM_IRQ_CTRL, "disable item %d", handle); + found = 1; + rc = 0; + break; + } + } + + if (!found) { + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + return rc; + } + + priority = evt_handler->priority; + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + irq_register->top_half_enable_mask[priority] &= + ~(evt_handler->evt_bit_mask_arr[i]); + + irq_mask = cam_io_r_mb(controller->mem_base + + irq_register->mask_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x before disable 0x%x", + irq_register->mask_reg_offset, irq_mask); + irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]); + + cam_io_w_mb(irq_mask, controller->mem_base + + irq_register->mask_reg_offset); + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x after disable 0x%x", + irq_register->mask_reg_offset, irq_mask); + + /* Clear the IRQ bits of this handler */ + cam_io_w_mb(evt_handler->evt_bit_mask_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + + if (controller->global_clear_offset) + cam_io_w_mb( + controller->global_clear_bitmask, + controller->mem_base + + controller->global_clear_offset); + } + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return rc; +} + +int cam_irq_controller_unsubscribe_irq(void *irq_controller, + uint32_t handle) +{ + struct cam_irq_controller *controller = irq_controller; + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_evt_handler *evt_handler_temp; + struct cam_irq_register_obj *irq_register; + enum cam_irq_priority_level priority; + uint32_t i; + uint32_t found = 0; + uint32_t irq_mask; + unsigned long flags = 0; + int rc = -EINVAL; + bool need_lock; + + need_lock = !in_irq(); + if (need_lock) + spin_lock_irqsave(&controller->lock, flags); + + list_for_each_entry_safe(evt_handler, evt_handler_temp, + &controller->evt_handler_list_head, list_node) { + if (evt_handler->index == handle) { + CAM_DBG(CAM_IRQ_CTRL, "unsubscribe item %d", handle); + list_del_init(&evt_handler->list_node); + list_del_init(&evt_handler->th_list_node); + found = 1; + rc = 0; + break; + } + } + + priority = evt_handler->priority; + if (found) { + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + irq_register->top_half_enable_mask[priority] &= + ~(evt_handler->evt_bit_mask_arr[i]); + + irq_mask = cam_io_r_mb(controller->mem_base + + irq_register->mask_reg_offset); + irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]); + + cam_io_w_mb(irq_mask, controller->mem_base + + irq_register->mask_reg_offset); + + /* Clear the IRQ bits of this handler */ + cam_io_w_mb(evt_handler->evt_bit_mask_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + if (controller->global_clear_offset) + cam_io_w_mb( + controller->global_clear_bitmask, + controller->mem_base + + controller->global_clear_offset); + } + + kfree(evt_handler->evt_bit_mask_arr); + kfree(evt_handler); + } + + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + + return rc; +} + +/** + * cam_irq_controller_match_bit_mask() + * + * @Brief: This function checks if any of the enabled IRQ bits + * for a certain handler is Set in the Status values + * of the controller. + * + * @controller: IRQ Controller structure + * @evt_handler: Event handler structure + * + * @Return: True: If any interested IRQ Bit is Set + * False: Otherwise + */ +static bool cam_irq_controller_match_bit_mask( + struct cam_irq_controller *controller, + struct cam_irq_evt_handler *evt_handler) +{ + int i; + + for (i = 0; i < controller->num_registers; i++) { + if (evt_handler->evt_bit_mask_arr[i] & + controller->irq_status_arr[i]) + return true; + } + + return false; +} + +static void cam_irq_controller_th_processing( + struct cam_irq_controller *controller, + struct list_head *th_list_head) +{ + struct cam_irq_evt_handler *evt_handler = NULL; + struct cam_irq_th_payload *th_payload = &controller->th_payload; + bool is_irq_match; + int rc = -EINVAL; + int i; + void *bh_cmd = NULL; + struct cam_irq_bh_api *irq_bh_api = NULL; + + CAM_DBG(CAM_IRQ_CTRL, "Enter"); + + if (list_empty(th_list_head)) + return; + + list_for_each_entry(evt_handler, th_list_head, th_list_node) { + is_irq_match = cam_irq_controller_match_bit_mask(controller, + evt_handler); + + if (!is_irq_match) + continue; + + CAM_DBG(CAM_IRQ_CTRL, "match found"); + + cam_irq_th_payload_init(th_payload); + th_payload->handler_priv = evt_handler->handler_priv; + th_payload->num_registers = controller->num_registers; + for (i = 0; i < controller->num_registers; i++) { + th_payload->evt_status_arr[i] = + controller->irq_status_arr[i] & + evt_handler->evt_bit_mask_arr[i]; + } + + irq_bh_api = &evt_handler->irq_bh_api; + bh_cmd = NULL; + + if (evt_handler->bottom_half_handler) { + rc = irq_bh_api->get_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No payload, IRQ handling frozen for %s", + controller->name); + continue; + } + } + + /* + * irq_status_arr[0] is dummy argument passed. the entire + * status array is passed in th_payload. + */ + if (evt_handler->top_half_handler) + rc = evt_handler->top_half_handler( + controller->irq_status_arr[0], + (void *)th_payload); + + if (rc && bh_cmd) { + irq_bh_api->put_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + continue; + } + + if (evt_handler->bottom_half_handler) { + CAM_DBG(CAM_IRQ_CTRL, "Enqueuing bottom half for %s", + controller->name); + irq_bh_api->bottom_half_enqueue_func( + evt_handler->bottom_half, + bh_cmd, + evt_handler->handler_priv, + th_payload->evt_payload_priv, + evt_handler->bottom_half_handler); + } + } + + CAM_DBG(CAM_IRQ_CTRL, "Exit"); +} + +irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv) +{ + struct cam_irq_controller *controller = priv; + uint32_t i = 0; + + if (!controller) + return IRQ_NONE; + + for (i = 0; i < controller->num_registers; i++) { + + cam_io_w_mb(0x0, controller->mem_base + + controller->irq_register_arr[i].clear_reg_offset); + } + + if (controller->global_clear_offset) + cam_io_w_mb(controller->global_clear_bitmask, + controller->mem_base + + controller->global_clear_offset); + + for (i = 0; i < controller->num_registers; i++) { + cam_io_w_mb(0x0, controller->mem_base + + controller->irq_register_arr[i].mask_reg_offset); + } + + return IRQ_HANDLED; +} + +irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) +{ + struct cam_irq_controller *controller = priv; + struct cam_irq_register_obj *irq_register; + bool need_th_processing[CAM_IRQ_PRIORITY_MAX] = {false}; + int i; + int j; + + if (!controller) + return IRQ_NONE; + + CAM_DBG(CAM_IRQ_CTRL, "locking controller %pK name %s lock %pK", + controller, controller->name, &controller->lock); + spin_lock(&controller->lock); + for (i = 0; i < controller->num_registers; i++) { + irq_register = &controller->irq_register_arr[i]; + controller->irq_status_arr[i] = cam_io_r_mb( + controller->mem_base + irq_register->status_reg_offset); + + if (controller->clear_all) + cam_io_w_mb(controller->irq_status_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + else + cam_io_w_mb( + controller->irq_register_arr[i].pclear_mask & + controller->irq_status_arr[i], + controller->mem_base + + irq_register->clear_reg_offset); + + CAM_DBG(CAM_IRQ_CTRL, "Read irq status%d (0x%x) = 0x%x", i, + controller->irq_register_arr[i].status_reg_offset, + controller->irq_status_arr[i]); + for (j = 0; j < CAM_IRQ_PRIORITY_MAX; j++) { + if (irq_register->top_half_enable_mask[j] & + controller->irq_status_arr[i]) + need_th_processing[j] = true; + CAM_DBG(CAM_IRQ_CTRL, + "i %d j %d need_th_processing = %d", + i, j, need_th_processing[j]); + } + } + + CAM_DBG(CAM_IRQ_CTRL, "Status Registers read Successful"); + + if (controller->global_clear_offset) + cam_io_w_mb(controller->global_clear_bitmask, + controller->mem_base + controller->global_clear_offset); + + CAM_DBG(CAM_IRQ_CTRL, "Status Clear done"); + + for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) { + if (need_th_processing[i]) { + CAM_DBG(CAM_IRQ_CTRL, "Invoke TH processing"); + cam_irq_controller_th_processing(controller, + &controller->th_list_head[i]); + } + } + spin_unlock(&controller->lock); + CAM_DBG(CAM_IRQ_CTRL, "unlocked controller %pK name %s lock %pK", + controller, controller->name, &controller->lock); + + return IRQ_HANDLED; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..8fa0e951b71401cbd3f94c25d0893cf30bf22fa6 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h @@ -0,0 +1,274 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IRQ_CONTROLLER_H_ +#define _CAM_IRQ_CONTROLLER_H_ + +#include <linux/interrupt.h> + +#define CAM_IRQ_BITS_PER_REGISTER 32 + +/* + * enum cam_irq_priority_level: + * @Brief: Priority levels for IRQ events. + * Priority_0 events will be serviced before + * Priority_1 if they these bits are set in the same + * Status Read. And so on upto Priority_4. + * + * Default Priority is Priority_4. + */ +enum cam_irq_priority_level { + CAM_IRQ_PRIORITY_0, + CAM_IRQ_PRIORITY_1, + CAM_IRQ_PRIORITY_2, + CAM_IRQ_PRIORITY_3, + CAM_IRQ_PRIORITY_4, + CAM_IRQ_PRIORITY_MAX, +}; + +/* + * struct cam_irq_register_set: + * @Brief: Structure containing offsets of IRQ related + * registers belonging to a Set + * + * @mask_reg_offset: Offset of IRQ MASK register + * @clear_reg_offset: Offset of IRQ CLEAR register + * @status_reg_offset: Offset of IRQ STATUS register + */ +struct cam_irq_register_set { + uint32_t mask_reg_offset; + uint32_t clear_reg_offset; + uint32_t status_reg_offset; +}; + +/* + * struct cam_irq_controller_reg_info: + * @Brief: Structure describing the IRQ registers + * + * @num_registers: Number of sets(mask/clear/status) of IRQ registers + * @irq_reg_set: Array of Register Set Offsets. + * Length of array = num_registers + * @global_clear_offset: Offset of Global IRQ Clear register. This register + * contains the BIT that needs to be set for the CLEAR + * to take effect + * @global_clear_bitmask: Bitmask needed to be used in Global Clear register + * for Clear IRQ cmd to take effect + */ +struct cam_irq_controller_reg_info { + uint32_t num_registers; + struct cam_irq_register_set *irq_reg_set; + uint32_t global_clear_offset; + uint32_t global_clear_bitmask; +}; + +/* + * struct cam_irq_th_payload: + * @Brief: Event payload structure. This structure will be + * passed to the Top Half handler functions. + * + * @handler_priv: Private Data of handling object set when + * subscribing to IRQ event. + * @num_registers: Length of evt_bit_mask Array below + * @evt_status_arr: Array of Status bitmask read from registers. + * Length of array = num_registers + * @evt_payload_priv: Private payload pointer which can be set by Top + * Half handler for use in Bottom Half. + */ +struct cam_irq_th_payload { + void *handler_priv; + uint32_t num_registers; + uint32_t *evt_status_arr; + void *evt_payload_priv; +}; + +/* + * cam_irq_th_payload_init() + * + * @brief: Initialize the top half payload structure + * + * @th_payload: Top Half payload structure to Initialize + * + * @return: Void + */ +static inline void cam_irq_th_payload_init( + struct cam_irq_th_payload *th_payload) { + th_payload->handler_priv = NULL; + th_payload->evt_payload_priv = NULL; +} + +typedef int (*CAM_IRQ_HANDLER_TOP_HALF)(uint32_t evt_id, + struct cam_irq_th_payload *th_payload); + +typedef int (*CAM_IRQ_HANDLER_BOTTOM_HALF)(void *handler_priv, + void *evt_payload_priv); + +typedef void (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF); + +typedef int (*CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +typedef void (*CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +struct cam_irq_bh_api { + CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func; + CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC get_bh_payload_func; + CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC put_bh_payload_func; +}; + +/* + * cam_irq_controller_init() + * + * @brief: Create and Initialize IRQ Controller. + * + * @name: Name of IRQ Controller block + * @mem_base: Mapped base address of register space to which + * register offsets are added to access registers + * @register_info: Register Info structure associated with this Controller + * @irq_controller: Pointer to IRQ Controller that will be filled if + * initialization is successful + * @clear_all: Flag to indicate whether to clear entire status register + * + * @return: 0: Success + * Negative: Failure + */ +int cam_irq_controller_init(const char *name, + void __iomem *mem_base, + struct cam_irq_controller_reg_info *register_info, + void **irq_controller, + bool clear_all); + +/* + * cam_irq_controller_subscribe_irq() + * + * @brief: Subscribe to certain IRQ events. + * + * @irq_controller: Pointer to IRQ Controller that controls this event IRQ + * @priority: Priority level of these events used if multiple events + * are SET in the Status Register + * @evt_bit_mask_arr: evt_bit_mask that has the bits set for IRQs to + * subscribe for + * @handler_priv: Private data that will be passed to the Top/Bottom Half + * handler function + * @top_half_handler: Top half Handler callback function + * @bottom_half_handler: Bottom half Handler callback function + * @bottom_half: Pointer to bottom_half implementation on which to + * enqueue the event for further handling + * @bottom_half_enqueue_func: + * Function used to enqueue the bottom_half event + * + * @return: Positive: Success. Value represents handle which is + * to be used to unsubscribe + * Negative: Failure + */ +int cam_irq_controller_subscribe_irq(void *irq_controller, + enum cam_irq_priority_level priority, + uint32_t *evt_bit_mask_arr, + void *handler_priv, + CAM_IRQ_HANDLER_TOP_HALF top_half_handler, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, + void *bottom_half, + struct cam_irq_bh_api *irq_bh_api); + +/* + * cam_irq_controller_unsubscribe_irq() + * + * @brief: Unsubscribe to IRQ events previously subscribed to. + * + * @irq_controller: Pointer to IRQ Controller that controls this event IRQ + * @handle: Handle returned on successful subscribe used to + * identify the handler object + * + * @return: 0: Success + * Negative: Failure + */ +int cam_irq_controller_unsubscribe_irq(void *irq_controller, + uint32_t handle); + +/* + * cam_irq_controller_deinit() + * + * @brief: Deinitialize IRQ Controller. + * + * @irq_controller: Pointer to IRQ Controller that needs to be + * deinitialized + * + * @return: 0: Success + * Negative: Failure + */ +int cam_irq_controller_deinit(void **irq_controller); + +/* + * cam_irq_controller_handle_irq() + * + * @brief: Function that should be registered with the IRQ line. + * This is the first function to be called when the IRQ + * is fired. It will read the Status register and Clear + * the IRQ bits. It will then call the top_half handlers + * and enqueue the result to bottom_half. + * + * @irq_num: Number of IRQ line that was set that lead to this + * function being called + * @priv: Private data registered with request_irq is passed back + * here. This private data should be the irq_controller + * structure. + * + * @return: IRQ_HANDLED/IRQ_NONE + */ +irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv); + +/* + * cam_irq_controller_disable_irq() + * + * @brief: Disable the interrupts on given controller. + * Unsubscribe will disable the IRQ by default, so this is + * only needed if between subscribe/unsubscribe there is + * need to disable IRQ again + * + * @irq_controller: Pointer to IRQ Controller that controls the registered + * events to it. + * @handle: Handle returned on successful subscribe, used to + * identify the handler object + * + * @return: 0: events found and disabled + * Negative: events not registered on this controller + */ +int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle); + +/* + * cam_irq_controller_enable_irq() + * + * @brief: Enable the interrupts on given controller. + * Subscribe will enable the IRQ by default, so this is + * only needed if between subscribe/unsubscribe there is + * need to enable IRQ again + * + * @irq_controller: Pointer to IRQ Controller that controls the registered + * events to it. + * @handle: Handle returned on successful subscribe, used to + * identify the handler object + * + * @return: 0: events found and enabled + * Negative: events not registered on this controller + */ +int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle); + +/* + * cam_irq_controller_clear_and_mask() + * + * @brief: This function clears and masks all the irq bits + * + * @irq_num: Number of IRQ line that was set that lead to this + * function being called + * @priv: Private data registered with request_irq is passed back + * here. This private data should be the irq_controller + * structure. + * + * @return: IRQ_HANDLED/IRQ_NONE + */ +irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv); +#endif /* _CAM_IRQ_CONTROLLER_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..6d5d0fd61c88dd87ad75548dac2d0c62aa86c5b3 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_MGR_INTF_H_ +#define _CAM_ISP_HW_MGR_INTF_H_ + +#include <linux/of.h> +#include <linux/time.h> +#include <linux/list.h> +#include <media/cam_isp.h> +#include "cam_hw_mgr_intf.h" + +/* MAX IFE instance */ +#define CAM_IFE_HW_NUM_MAX 7 +#define CAM_IFE_RDI_NUM_MAX 4 +#define CAM_ISP_BW_CONFIG_V1 1 +#define CAM_ISP_BW_CONFIG_V2 2 + +/* Appliacble vote paths for dual ife, based on no. of UAPI definitions */ +#define CAM_ISP_MAX_PER_PATH_VOTES 30 +/** + * enum cam_isp_hw_event_type - Collection of the ISP hardware events + */ +enum cam_isp_hw_event_type { + CAM_ISP_HW_EVENT_ERROR, + CAM_ISP_HW_EVENT_SOF, + CAM_ISP_HW_EVENT_REG_UPDATE, + CAM_ISP_HW_EVENT_EPOCH, + CAM_ISP_HW_EVENT_EOF, + CAM_ISP_HW_EVENT_DONE, + CAM_ISP_HW_EVENT_MAX +}; + + +/** + * enum cam_isp_hw_err_type - Collection of the ISP error types for + * ISP hardware event CAM_ISP_HW_EVENT_ERROR + */ +enum cam_isp_hw_err_type { + CAM_ISP_HW_ERROR_NONE, + CAM_ISP_HW_ERROR_OVERFLOW, + CAM_ISP_HW_ERROR_P2I_ERROR, + CAM_ISP_HW_ERROR_VIOLATION, + CAM_ISP_HW_ERROR_BUSIF_OVERFLOW, + CAM_ISP_HW_ERROR_MAX, +}; + +/** + * enum cam_isp_hw_stop_cmd - Specify the stop command type + */ +enum cam_isp_hw_stop_cmd { + CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY, + CAM_ISP_HW_STOP_IMMEDIATELY, + CAM_ISP_HW_STOP_MAX, +}; + +/** + * struct cam_isp_stop_args - hardware stop arguments + * + * @hw_stop_cmd: Hardware stop command type information + * @stop_only Send stop only to hw drivers. No Deinit to be + * done. + * + */ +struct cam_isp_stop_args { + enum cam_isp_hw_stop_cmd hw_stop_cmd; + bool stop_only; +}; + +/** + * struct cam_isp_start_args - isp hardware start arguments + * + * @config_args: Hardware configuration commands. + * @start_only Send start only to hw drivers. No init to + * be done. + * + */ +struct cam_isp_start_args { + struct cam_hw_config_args hw_config; + bool start_only; +}; + +/** + * struct cam_isp_bw_config_internal_v2 - Bandwidth configuration + * + * @usage_type: ife hw index + * @num_paths: Number of data paths + * @axi_path per path vote info + */ +struct cam_isp_bw_config_internal_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[CAM_ISP_MAX_PER_PATH_VOTES]; +}; + +/** + * struct cam_isp_bw_config_internal - Internal Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_vote: Bandwidth vote for left ISP + * @right_pix_vote: Bandwidth vote for right ISP + * @rdi_vote: RDI bandwidth requirements + */ +struct cam_isp_bw_config_internal { + uint32_t usage_type; + uint32_t num_rdi; + struct cam_isp_bw_vote left_pix_vote; + struct cam_isp_bw_vote right_pix_vote; + struct cam_isp_bw_vote rdi_vote[CAM_IFE_RDI_NUM_MAX]; +}; + +/** + * struct cam_isp_prepare_hw_update_data - hw prepare data + * + * @ife_mgr_ctx: IFE HW manager Context for current request + * @packet_opcode_type: Packet header opcode in the packet header + * this opcode defines, packet is init packet or + * update packet + * @bw_config_version: BW config version indicator + * @bw_config: BW config information + * @bw_config_v2: BW config info for AXI bw voting v2 + * @bw_config_valid: Flag indicating whether the bw_config at the index + * is valid or not + * @reg_dump_buf_desc: cmd buffer descriptors for reg dump + * @num_reg_dump_buf: Count of descriptors in reg_dump_buf_desc + * + */ +struct cam_isp_prepare_hw_update_data { + struct cam_ife_hw_mgr_ctx *ife_mgr_ctx; + uint32_t packet_opcode_type; + uint32_t bw_config_version; + struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; + struct cam_isp_bw_config_internal_v2 bw_config_v2[CAM_IFE_HW_NUM_MAX]; + bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; + struct cam_cmd_buf_desc reg_dump_buf_desc[ + CAM_REG_DUMP_MAX_BUF_ENTRIES]; + uint32_t num_reg_dump_buf; +}; + + +/** + * struct cam_isp_hw_sof_event_data - Event payload for CAM_HW_EVENT_SOF + * + * @timestamp: Time stamp for the sof event + * @boot_time: Boot time stamp for the sof event + * + */ +struct cam_isp_hw_sof_event_data { + uint64_t timestamp; + uint64_t boot_time; +}; + +/** + * struct cam_isp_hw_reg_update_event_data - Event payload for + * CAM_HW_EVENT_REG_UPDATE + * + * @timestamp: Time stamp for the reg update event + * + */ +struct cam_isp_hw_reg_update_event_data { + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_epoch_event_data - Event payload for CAM_HW_EVENT_EPOCH + * + * @timestamp: Time stamp for the epoch event + * + */ +struct cam_isp_hw_epoch_event_data { + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_done_event_data - Event payload for CAM_HW_EVENT_DONE + * + * @num_handles: Number of resource handeles + * @resource_handle: Resource handle array + * @timestamp: Timestamp for the buf done event + * + */ +struct cam_isp_hw_done_event_data { + uint32_t num_handles; + uint32_t resource_handle[ + CAM_NUM_OUT_PER_COMP_IRQ_MAX]; + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_eof_event_data - Event payload for CAM_HW_EVENT_EOF + * + * @timestamp: Timestamp for the eof event + * + */ +struct cam_isp_hw_eof_event_data { + uint64_t timestamp; +}; + +/** + * struct cam_isp_hw_error_event_data - Event payload for CAM_HW_EVENT_ERROR + * + * @error_type: Error type for the error event + * @timestamp: Timestamp for the error event + * @recovery_enabled: Identifies if the context needs to recover & reapply + * this request + * @enable_req_dump: Enable request dump on HW errors + */ +struct cam_isp_hw_error_event_data { + uint32_t error_type; + uint64_t timestamp; + bool recovery_enabled; + bool enable_req_dump; +}; + +/* enum cam_isp_hw_mgr_command - Hardware manager command type */ +enum cam_isp_hw_mgr_command { + CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT, + CAM_ISP_HW_MGR_CMD_PAUSE_HW, + CAM_ISP_HW_MGR_CMD_RESUME_HW, + CAM_ISP_HW_MGR_CMD_SOF_DEBUG, + CAM_ISP_HW_MGR_CMD_CTX_TYPE, + CAM_ISP_HW_MGR_CMD_MAX, +}; + +enum cam_isp_ctx_type { + CAM_ISP_CTX_FS2 = 1, + CAM_ISP_CTX_RDI, + CAM_ISP_CTX_PIX, + CAM_ISP_CTX_MAX, +}; +/** + * struct cam_isp_hw_cmd_args - Payload for hw manager command + * + * @cmd_type HW command type + * @sof_irq_enable To debug if SOF irq is enabled + * @ctx_type RDI_ONLY, PIX and RDI, or FS2 + */ +struct cam_isp_hw_cmd_args { + uint32_t cmd_type; + union { + uint32_t sof_irq_enable; + uint32_t ctx_type; + } u; +}; + + +/** + * cam_isp_hw_mgr_init() + * + * @brief: Initialization function for the ISP hardware manager + * + * @of_node: Device node input + * @hw_mgr: Input/output structure for the ISP hardware manager + * initialization + * @iommu_hdl: Iommu handle to be returned + */ +int cam_isp_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl); + +#endif /* __CAM_ISP_HW_MGR_INTF_H__ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..41c244c96572dd120995e0cf3271946999fc37b2 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8ccd9f0b3f621e8ba463be641b3ce455547be68d --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ife_csid_dev.o cam_ife_csid_soc.o cam_ife_csid_core.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ife_csid17x.o cam_ife_csid_lite17x.o diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h new file mode 100644 index 0000000000000000000000000000000000000000..714fa8ef2b3167e20eef1c5412ac4420e03b0c59 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h @@ -0,0 +1,305 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_170_H_ +#define _CAM_IFE_CSID_170_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_170_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_170_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_170_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_170_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_170_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_170_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_170_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0x0, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_170_reg_offset = { + .cmn_reg = &cam_ife_csid_170_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_170_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_170_ipp_reg_offset, + .ppp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_170_rdi_0_reg_offset, + &cam_ife_csid_170_rdi_1_reg_offset, + &cam_ife_csid_170_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_170_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_170_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h new file mode 100644 index 0000000000000000000000000000000000000000..70f96ea416d842f19495d23c512057e76d780c12 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_175_H_ +#define _CAM_IFE_CSID_175_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_175_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_175_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_175_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_175_reg_offset = { + .cmn_reg = &cam_ife_csid_175_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_175_rdi_0_reg_offset, + &cam_ife_csid_175_rdi_1_reg_offset, + &cam_ife_csid_175_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_175_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_175_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h new file mode 100644 index 0000000000000000000000000000000000000000..612379ec4bdd54686d57a8cda0e600885c9ceda8 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -0,0 +1,364 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_175_200_H_ +#define _CAM_IFE_CSID_175_200_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .quad_cfa_bin_en_shift_val = 30, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_175_200_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + .csid_csi2_rx_de_scramble_type3_cfg0_addr = 0x170, + .csid_csi2_rx_de_scramble_type3_cfg1_addr = 0x174, + .csid_csi2_rx_de_scramble_type2_cfg0_addr = 0x178, + .csid_csi2_rx_de_scramble_type2_cfg1_addr = 0x17c, + .csid_csi2_rx_de_scramble_type1_cfg0_addr = 0x180, + .csid_csi2_rx_de_scramble_type1_cfg1_addr = 0x184, + .csid_csi2_rx_de_scramble_type0_cfg0_addr = 0x188, + .csid_csi2_rx_de_scramble_type0_cfg1_addr = 0x18c, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_175_200_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_175_200_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 5, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0xFFFF, + .rdi_irq_mask_all = 0xFFFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_175_200_reg_offset = { + .cmn_reg = &cam_ife_csid_175_200_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_200_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_200_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_200_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_175_200_rdi_0_reg_offset, + &cam_ife_csid_175_200_rdi_1_reg_offset, + &cam_ife_csid_175_200_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_175_200_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_175_200_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c new file mode 100644 index 0000000000000000000000000000000000000000..d88347caa38864ae20964e55c756c344b5e75621 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + + +#include <linux/module.h> +#include "cam_ife_csid_core.h" +#include "cam_ife_csid170.h" +#include "cam_ife_csid175.h" +#include "cam_ife_csid175_200.h" +#include "cam_ife_csid480.h" +#include "cam_ife_csid_dev.h" + +#define CAM_CSID_DRV_NAME "csid_17x" +#define CAM_CSID_VERSION_V170 0x10070000 +#define CAM_CSID_VERSION_V175 0x10070050 +#define CAM_CSID_VERSION_V480 0x40080000 + +static struct cam_ife_csid_hw_info cam_ife_csid170_hw_info = { + .csid_reg = &cam_ife_csid_170_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V170, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid175_hw_info = { + .csid_reg = &cam_ife_csid_175_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid175_200_hw_info = { + .csid_reg = &cam_ife_csid_175_200_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid480_hw_info = { + .csid_reg = &cam_ife_csid_480_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V480, +}; + +static const struct of_device_id cam_ife_csid17x_dt_match[] = { + { + .compatible = "qcom,csid170", + .data = &cam_ife_csid170_hw_info, + }, + { + .compatible = "qcom,csid175", + .data = &cam_ife_csid175_hw_info, + }, + { + .compatible = "qcom,csid175_200", + .data = &cam_ife_csid175_200_hw_info, + }, + { + .compatible = "qcom,csid480", + .data = &cam_ife_csid480_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_ife_csid17x_dt_match); + +static struct platform_driver cam_ife_csid17x_driver = { + .probe = cam_ife_csid_probe, + .remove = cam_ife_csid_remove, + .driver = { + .name = CAM_CSID_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_ife_csid17x_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ife_csid17x_init_module(void) +{ + return platform_driver_register(&cam_ife_csid17x_driver); +} + +static void __exit cam_ife_csid17x_exit_module(void) +{ + platform_driver_unregister(&cam_ife_csid17x_driver); +} + +module_init(cam_ife_csid17x_init_module); +module_exit(cam_ife_csid17x_exit_module); +MODULE_DESCRIPTION("CAM IFE_CSID17X driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h new file mode 100644 index 0000000000000000000000000000000000000000..66c1b32d51b0f51cf47e526198e30c9a7eeea9eb --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid480.h @@ -0,0 +1,384 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_480_H_ +#define _CAM_IFE_CSID_480_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_480_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + .csid_pxl_err_recovery_cfg0_addr = 0x2d0, + .csid_pxl_err_recovery_cfg1_addr = 0x2d4, + .csid_pxl_err_recovery_cfg2_addr = 0x2d8, + .csid_pxl_multi_vcdt_cfg0_addr = 0x2dc, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .horizontal_bin_en_shift_val = 2, + .quad_cfa_bin_en_shift_val = 30, + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_480_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + .csid_pxl_err_recovery_cfg0_addr = 0x7d0, + .csid_pxl_err_recovery_cfg1_addr = 0x7d4, + .csid_pxl_err_recovery_cfg2_addr = 0x7d8, + .csid_pxl_multi_vcdt_cfg0_addr = 0x7dc, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_480_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_err_recovery_cfg0_addr = 0x3b0, + .csid_rdi_err_recovery_cfg1_addr = 0x3b4, + .csid_rdi_err_recovery_cfg2_addr = 0x3b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x3bc, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_480_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_err_recovery_cfg0_addr = 0x4b0, + .csid_rdi_err_recovery_cfg1_addr = 0x4b4, + .csid_rdi_err_recovery_cfg2_addr = 0x4b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x4bc, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_480_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_err_recovery_cfg0_addr = 0x5b0, + .csid_rdi_err_recovery_cfg1_addr = 0x5b4, + .csid_rdi_err_recovery_cfg2_addr = 0x5b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x5bc, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_480_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_480_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_480_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .drop_v_en_shift_val = 4, + .drop_h_en_shift_val = 3, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_480_reg_offset = { + .cmn_reg = &cam_ife_csid_480_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_480_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_480_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_480_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_480_rdi_0_reg_offset, + &cam_ife_csid_480_rdi_1_reg_offset, + &cam_ife_csid_480_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_480_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_480_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c new file mode 100644 index 0000000000000000000000000000000000000000..75cd32a0cd6078192c5214a28ce187c1138bf911 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -0,0 +1,4485 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/iopoll.h> +#include <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include <uapi/media/cam_defs.h> + +#include <dt-bindings/msm/msm-camera.h> + +#include "cam_ife_csid_core.h" +#include "cam_isp_hw.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +/* Timeout value in msec */ +#define IFE_CSID_TIMEOUT 1000 + +/* TPG VC/DT values */ +#define CAM_IFE_CSID_TPG_VC_VAL 0xA +#define CAM_IFE_CSID_TPG_DT_VAL 0x2B + +/* Timeout values in usec */ +#define CAM_IFE_CSID_TIMEOUT_SLEEP_US 1000 +#define CAM_IFE_CSID_TIMEOUT_ALL_US 300000 + +/* + * Constant Factors needed to change QTimer ticks to nanoseconds + * QTimer Freq = 19.2 MHz + * Time(us) = ticks/19.2 + * Time(ns) = ticks/19.2 * 1000 + */ +#define CAM_IFE_CSID_QTIMER_MUL_FACTOR 10000 +#define CAM_IFE_CSID_QTIMER_DIV_FACTOR 192 + +/* Max number of sof irq's triggered in case of SOF freeze */ +#define CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX 12 + +/* Max CSI Rx irq error count threshold value */ +#define CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT 100 + +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw); +static int cam_ife_csid_is_ipp_ppp_format_supported( + uint32_t in_format) +{ + int rc = -EINVAL; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_DPCM_10_6_10: + case CAM_FORMAT_DPCM_10_8_10: + case CAM_FORMAT_DPCM_12_6_12: + case CAM_FORMAT_DPCM_12_8_12: + case CAM_FORMAT_DPCM_14_8_14: + case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_DPCM_12_10_12: + rc = 0; + break; + default: + break; + } + return rc; +} + +static int cam_ife_csid_get_format_rdi( + uint32_t in_format, uint32_t out_format, uint32_t *decode_fmt, + uint32_t *plain_fmt, uint32_t *packing_fmt, bool rpp) +{ + int rc = 0; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x0; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN8: + *decode_fmt = 0x0; + *plain_fmt = 0x0; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_8: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN128: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x1; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN8: + *decode_fmt = 0x1; + *plain_fmt = 0x0; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_10: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_PLAIN128: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x2; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN16_10: + *decode_fmt = 0x2; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_12: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_12: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x3; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN16_12: + *decode_fmt = 0x3; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_14: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_14: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x4; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN16_14: + *decode_fmt = 0x4; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_16: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_16: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x5; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN16_16: + *decode_fmt = 0x5; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_MIPI_RAW_20: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_20: + *decode_fmt = 0xf; + if (rpp) { + *decode_fmt = 0x6; + *packing_fmt = 0x1; + } + break; + case CAM_FORMAT_PLAIN32_20: + *decode_fmt = 0x6; + *plain_fmt = 0x2; + break; + default: + rc = -EINVAL; + break; + } + break; + case CAM_FORMAT_DPCM_10_6_10: + *decode_fmt = 0x7; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_10_8_10: + *decode_fmt = 0x8; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_6_12: + *decode_fmt = 0x9; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_8_12: + *decode_fmt = 0xA; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_8_14: + *decode_fmt = 0xB; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_10_14: + *decode_fmt = 0xC; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; + default: + rc = -EINVAL; + break; + } + + if (rc) + CAM_ERR(CAM_ISP, "Unsupported format pair in %d out %d", + in_format, out_format); + + return rc; +} + +static int cam_ife_csid_get_format_ipp_ppp( + uint32_t in_format, + uint32_t *decode_fmt, uint32_t *plain_fmt) +{ + int rc = 0; + + CAM_DBG(CAM_ISP, "input format:%d", + in_format); + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0; + *plain_fmt = 0; + break; + case CAM_FORMAT_MIPI_RAW_8: + *decode_fmt = 0x1; + *plain_fmt = 0; + break; + case CAM_FORMAT_MIPI_RAW_10: + *decode_fmt = 0x2; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_12: + *decode_fmt = 0x3; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_14: + *decode_fmt = 0x4; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_16: + *decode_fmt = 0x5; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_MIPI_RAW_20: + *decode_fmt = 0x6; + *plain_fmt = 0x2; + break; + case CAM_FORMAT_DPCM_10_6_10: + *decode_fmt = 0x7; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_10_8_10: + *decode_fmt = 0x8; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_6_12: + *decode_fmt = 0x9; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_8_12: + *decode_fmt = 0xA; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_8_14: + *decode_fmt = 0xB; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_14_10_14: + *decode_fmt = 0xC; + *plain_fmt = 0x1; + break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported format %d", + in_format); + rc = -EINVAL; + } + + CAM_DBG(CAM_ISP, "decode_fmt:%d plain_fmt:%d", + *decode_fmt, *plain_fmt); + + return rc; +} + +static int cam_ife_match_vc_dt_pair(int32_t *vc, uint32_t *dt, + uint32_t num_valid_vc_dt, struct cam_ife_csid_cid_data *cid_data) +{ + uint32_t camera_hw_version; + int rc = 0; + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + return -EINVAL; + } + + if (camera_hw_version != CAM_CPAS_TITAN_480_V100) + num_valid_vc_dt = 1; + + switch (num_valid_vc_dt) { + case 2: + if (vc[1] != cid_data->vc1 || + dt[1] != cid_data->dt1) + return -EINVAL; + case 1: + if (vc[0] != cid_data->vc || + dt[0] != cid_data->dt) + return -EINVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node **res, int32_t *vc, uint32_t *dt, + uint32_t num_valid_vc_dt) +{ + struct cam_ife_csid_cid_data *cid_data; + uint32_t i = 0; + + *res = NULL; + + /* Return already reserved CID if the VC/DT matches */ + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) { + if (csid_hw->cid_res[i].res_state >= + CAM_ISP_RESOURCE_STATE_RESERVED) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[i].res_priv; + if (!cam_ife_match_vc_dt_pair(vc, dt, + num_valid_vc_dt, cid_data)) { + cid_data->cnt++; + *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); + return 0; + } + } + } + + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) { + if (csid_hw->cid_res[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[i].res_priv; + cid_data->vc = vc[0]; + cid_data->dt = dt[0]; + if (num_valid_vc_dt > 1) { + cid_data->vc1 = vc[1]; + cid_data->dt1 = dt[1]; + cid_data->is_valid_vc1_dt1 = 1; + } + cid_data->cnt = 1; + csid_hw->cid_res[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); + return 0; + } + } + + CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", + csid_hw->hw_intf->hw_idx); + + return -EINVAL; +} + + +static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + int rc = 0; + uint32_t val = 0, i; + unsigned long flags; + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid HW State:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d Csid reset", + csid_hw->hw_intf->hw_idx); + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + + /* Mask all interrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + + /* clear all interrupts */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(csid_reg->csi2_reg->csi2_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(csid_reg->cmn_reg->ppp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); + + for (i = 0 ; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + + for (i = 0 ; i < csid_reg->cmn_reg->num_udis; i++) + cam_io_w_mb(csid_reg->cmn_reg->udi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + /* enable the IPP and RDI format measure */ + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_cfg0_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_cfg0_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); + + /* reset HW regs first, then SW */ + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc < 0) + goto end; + rc = cam_ife_csid_reset_regs(csid_hw, false); + if (rc < 0) + goto end; + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + if (val != 0) + CAM_ERR(CAM_ISP, "CSID:%d IRQ value after reset rc = %d", + csid_hw->hw_intf->hw_idx, val); + csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; + +end: + return rc; +} + +static int cam_ife_csid_path_reset(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_reset_cfg_args *reset) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t reset_strb_addr, reset_strb_val, val, id; + struct completion *complete; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + res = reset->node_res; + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid hw state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d resource:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + if (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = csid_reg->ipp_reg->csid_pxl_rst_strobes_addr; + complete = &csid_hw->csid_ipp_complete; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + if (!csid_reg->ppp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d PPP not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = csid_reg->ppp_reg->csid_pxl_rst_strobes_addr; + complete = &csid_hw->csid_ppp_complete; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_mask_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + id = res->res_id; + if (!csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d RDI res not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = + csid_reg->rdi_reg[id]->csid_rdi_rst_strobes_addr; + complete = + &csid_hw->csid_rdin_complete[id]; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if (!csid_reg->udi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d UDI res not supported :%d", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + reset_strb_addr = + csid_reg->udi_reg[id]->csid_udi_rst_strobes_addr; + complete = + &csid_hw->csid_udin_complete[id]; + + /* Enable path reset done interrupt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + val |= CSID_PATH_INFO_RST_DONE; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id %u", res->res_id); + return -EINVAL; + } + + reinit_completion(complete); + reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; + + /* Reset the corresponding ife csid path */ + cam_io_w_mb(reset_strb_val, soc_info->reg_map[0].mem_base + + reset_strb_addr); + + rc = wait_for_completion_timeout(complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "CSID:%d Res id %d fail rc = %d", + csid_hw->hw_intf->hw_idx, + res->res_id, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } + +end: + return rc; + +} + +int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *cid_reserv) +{ + int rc = 0, i, id; + struct cam_ife_csid_cid_data *cid_data; + uint32_t camera_hw_version; + uint32_t valid_vc_dt; + + CAM_DBG(CAM_ISP, + "CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type, + cid_reserv->in_port->lane_type, + cid_reserv->in_port->lane_num, + cid_reserv->in_port->dt[0], + cid_reserv->in_port->vc[0]); + + if (cid_reserv->in_port->res_type >= CAM_ISP_IFE_IN_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid phy sel %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type); + rc = -EINVAL; + goto end; + } + + if (cid_reserv->in_port->lane_type >= CAM_ISP_LANE_TYPE_MAX && + cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid lane type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_type); + rc = -EINVAL; + goto end; + } + + if ((cid_reserv->in_port->lane_type == CAM_ISP_LANE_TYPE_DPHY && + cid_reserv->in_port->lane_num > 4) && + cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid lane num %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_num); + rc = -EINVAL; + goto end; + } + if ((cid_reserv->in_port->lane_type == CAM_ISP_LANE_TYPE_CPHY && + cid_reserv->in_port->lane_num > 3) && + cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, " CSID:%d Invalid lane type %d & num %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->lane_type, + cid_reserv->in_port->lane_num); + rc = -EINVAL; + goto end; + } + + valid_vc_dt = cid_reserv->in_port->num_valid_vc_dt; + + /* CSID CSI2 v2.0 supports 31 vc */ + for (i = 0; i < valid_vc_dt; i++) { + if (cid_reserv->in_port->vc[i] > 0x1f || + cid_reserv->in_port->dt[i] > 0x3f) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d or dt: %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->vc[i], + cid_reserv->in_port->dt[i]); + rc = -EINVAL; + goto end; + } + } + + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG && ( + (cid_reserv->in_port->format < CAM_FORMAT_MIPI_RAW_8 && + cid_reserv->in_port->format > CAM_FORMAT_MIPI_RAW_16))) { + CAM_ERR(CAM_ISP, " CSID:%d Invalid tpg decode fmt %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->format); + rc = -EINVAL; + goto end; + } + + if (csid_hw->csi2_reserve_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, + "CSID%d reserve cnt reached max", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + goto end; + } + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_NONE: + case CAM_CPAS_TITAN_MAX: + CAM_ERR(CAM_ISP, "Invalid HW version: %x", camera_hw_version); + break; + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && + csid_hw->hw_intf->hw_idx != 2) { + rc = -EINVAL; + goto end; + } + break; + case CAM_CPAS_TITAN_480_V100: + if (cid_reserv->in_port->cust_node == 1) { + if (cid_reserv->in_port->usage_type == 1) { + CAM_ERR(CAM_ISP, "Dual IFE is not supported"); + rc = -EINVAL; + goto end; + } + if (csid_hw->hw_intf->hw_idx != 0) { + CAM_DBG(CAM_ISP, "CSID%d not eligible", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + } + break; + default: + break; + } + CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt); + + if (csid_hw->csi2_reserve_cnt) { + /* current configure res type should match requested res type */ + if (csid_hw->res_type != cid_reserv->in_port->res_type) { + rc = -EINVAL; + goto end; + } + + if (cid_reserv->in_port->res_type != CAM_ISP_IFE_IN_RES_TPG) { + if (csid_hw->csi2_rx_cfg.lane_cfg != + cid_reserv->in_port->lane_cfg || + csid_hw->csi2_rx_cfg.lane_type != + cid_reserv->in_port->lane_type || + csid_hw->csi2_rx_cfg.lane_num != + cid_reserv->in_port->lane_num) { + rc = -EINVAL; + goto end; + } + } else { + if (csid_hw->tpg_cfg.in_format != + cid_reserv->in_port->format || + csid_hw->tpg_cfg.width != + cid_reserv->in_port->left_width || + csid_hw->tpg_cfg.height != + cid_reserv->in_port->height || + csid_hw->tpg_cfg.test_pattern != + cid_reserv->in_port->test_pattern) { + rc = -EINVAL; + goto end; + } + } + } + + switch (cid_reserv->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource not available", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_PPP: + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d PPP resource not available state %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ppp_res.res_state); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (csid_hw->rdi_res[cid_reserv->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available", + csid_hw->hw_intf->hw_idx, + cid_reserv->res_id); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_UDI_0: + case CAM_IFE_PIX_PATH_RES_UDI_1: + case CAM_IFE_PIX_PATH_RES_UDI_2: + id = cid_reserv->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if (csid_hw->udi_res[id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d UDI:%d resource not available", + csid_hw->hw_intf->hw_idx, + cid_reserv->res_id); + rc = -EINVAL; + goto end; + } + break; + default: + CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + rc = cam_ife_csid_cid_get(csid_hw, + &cid_reserv->node_res, + cid_reserv->in_port->vc, + cid_reserv->in_port->dt, + cid_reserv->in_port->num_valid_vc_dt); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type); + goto end; + } + cid_data = (struct cam_ife_csid_cid_data *) + cid_reserv->node_res->res_priv; + + if (!csid_hw->csi2_reserve_cnt) { + csid_hw->res_type = cid_reserv->in_port->res_type; + + csid_hw->csi2_rx_cfg.lane_cfg = + cid_reserv->in_port->lane_cfg; + csid_hw->csi2_rx_cfg.lane_type = + cid_reserv->in_port->lane_type; + csid_hw->csi2_rx_cfg.lane_num = + cid_reserv->in_port->lane_num; + + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) { + csid_hw->csi2_rx_cfg.phy_sel = 0; + if (cid_reserv->in_port->format > + CAM_FORMAT_MIPI_RAW_16) { + CAM_ERR(CAM_ISP, " Wrong TPG format"); + rc = -EINVAL; + goto end; + } + csid_hw->tpg_cfg.in_format = + cid_reserv->in_port->format; + csid_hw->tpg_cfg.usage_type = + cid_reserv->in_port->usage_type; + if (cid_reserv->in_port->usage_type) + csid_hw->tpg_cfg.width = + (cid_reserv->in_port->right_stop + 1); + else + csid_hw->tpg_cfg.width = + cid_reserv->in_port->left_width; + + csid_hw->tpg_cfg.height = cid_reserv->in_port->height; + csid_hw->tpg_cfg.test_pattern = + cid_reserv->in_port->test_pattern; + + CAM_DBG(CAM_ISP, "CSID:%d TPG width:%d height:%d", + csid_hw->hw_intf->hw_idx, + csid_hw->tpg_cfg.width, + csid_hw->tpg_cfg.height); + + cid_data->tpg_set = 1; + } else { + csid_hw->csi2_rx_cfg.phy_sel = + (cid_reserv->in_port->res_type & 0xFF) - 1; + } + } + + csid_hw->csi2_reserve_cnt++; + CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", + csid_hw->hw_intf->hw_idx, + cid_reserv->node_res->res_id); + +end: + return rc; +} + +int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *reserve) +{ + int rc = 0, i, id; + struct cam_ife_csid_path_cfg *path_data; + struct cam_isp_resource_node *res; + bool is_rdi = false; + + /* CSID CSI2 v2.0 supports 31 vc */ + if (reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX) { + CAM_ERR(CAM_ISP, "CSID: %d Sync Mode: %d", + reserve->sync_mode); + return -EINVAL; + } + + for (i = 0; i < reserve->in_port->num_valid_vc_dt; i++) { + if (reserve->in_port->dt[i] > 0x3f || + reserve->in_port->vc[i] > 0x1f) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d", + csid_hw->hw_intf->hw_idx, + reserve->in_port->vc, reserve->in_port->dt); + rc = -EINVAL; + goto end; + } + } + + switch (reserve->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d IPP resource not available %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ipp_res.res_state); + rc = -EINVAL; + goto end; + } + + if (cam_ife_csid_is_ipp_ppp_format_supported( + reserve->in_port->format)) { + CAM_ERR(CAM_ISP, + "CSID:%d res id:%d un support format %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->format); + rc = -EINVAL; + goto end; + } + + /* assign the IPP resource */ + res = &csid_hw->ipp_res; + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource:%d acquired successfully", + csid_hw->hw_intf->hw_idx, res->res_id); + + break; + case CAM_IFE_PIX_PATH_RES_PPP: + if (csid_hw->ppp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d PPP resource not available %d", + csid_hw->hw_intf->hw_idx, + csid_hw->ppp_res.res_state); + rc = -EINVAL; + goto end; + } + + if (cam_ife_csid_is_ipp_ppp_format_supported( + reserve->in_port->format)) { + CAM_ERR(CAM_ISP, + "CSID:%d res id:%d unsupported format %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->format); + rc = -EINVAL; + goto end; + } + + /* assign the PPP resource */ + res = &csid_hw->ppp_res; + CAM_DBG(CAM_ISP, + "CSID:%d PPP resource:%d acquired successfully", + csid_hw->hw_intf->hw_idx, res->res_id); + + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (csid_hw->rdi_res[reserve->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available %d", + csid_hw->hw_intf->hw_idx, + reserve->res_id, + csid_hw->rdi_res[reserve->res_id].res_state); + rc = -EINVAL; + goto end; + } else { + res = &csid_hw->rdi_res[reserve->res_id]; + CAM_DBG(CAM_ISP, + "CSID:%d RDI resource:%d acquire success", + csid_hw->hw_intf->hw_idx, + res->res_id); + is_rdi = true; + } + + break; + case CAM_IFE_PIX_PATH_RES_UDI_0: + case CAM_IFE_PIX_PATH_RES_UDI_1: + case CAM_IFE_PIX_PATH_RES_UDI_2: + id = reserve->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if (csid_hw->udi_res[id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d UDI:%d resource not available %d", + csid_hw->hw_intf->hw_idx, + reserve->res_id, + csid_hw->udi_res[id].res_state); + rc = -EINVAL; + goto end; + } else { + res = &csid_hw->udi_res[id]; + CAM_DBG(CAM_ISP, + "CSID:%d UDI resource:%d acquire success", + csid_hw->hw_intf->hw_idx, + res->res_id); + } + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id:%d", + csid_hw->hw_intf->hw_idx, reserve->res_id); + rc = -EINVAL; + goto end; + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; + + path_data->cid = reserve->cid; + path_data->in_format = reserve->in_port->format; + path_data->out_format = reserve->out_port->format; + path_data->sync_mode = reserve->sync_mode; + path_data->height = reserve->in_port->height; + path_data->start_line = reserve->in_port->line_start; + path_data->end_line = reserve->in_port->line_stop; + path_data->crop_enable = reserve->crop_enable; + path_data->drop_enable = reserve->drop_enable; + path_data->horizontal_bin = reserve->in_port->horizontal_bin; + path_data->qcfa_bin = reserve->in_port->qcfa_bin; + path_data->num_bytes_out = reserve->in_port->num_bytes_out; + + CAM_DBG(CAM_ISP, + "Res id: %d height:%d line_start %d line_stop %d crop_en %d", + reserve->res_id, reserve->in_port->height, + reserve->in_port->line_start, reserve->in_port->line_stop, + path_data->crop_enable); + + if (reserve->in_port->res_type == CAM_ISP_IFE_IN_RES_TPG) { + path_data->dt = CAM_IFE_CSID_TPG_DT_VAL; + path_data->vc = CAM_IFE_CSID_TPG_VC_VAL; + } else { + path_data->dt = reserve->in_port->dt[0]; + path_data->vc = reserve->in_port->vc[0]; + if (reserve->in_port->num_valid_vc_dt) { + path_data->dt1 = reserve->in_port->dt[1]; + path_data->vc1 = reserve->in_port->vc[1]; + path_data->is_valid_vc1_dt1 = 1; + } + } + + if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) { + path_data->start_pixel = reserve->in_port->left_start; + path_data->end_pixel = reserve->in_port->left_stop; + path_data->width = reserve->in_port->left_width; + + if (is_rdi) { + path_data->end_pixel = reserve->in_port->right_stop; + path_data->width = path_data->end_pixel - + path_data->start_pixel + 1; + } + + CAM_DBG(CAM_ISP, + "CSID:%d res:%d master:startpixel 0x%x endpixel:0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_pixel, path_data->end_pixel); + CAM_DBG(CAM_ISP, + "CSID:%d res:%d master:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_line, path_data->end_line); + } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { + path_data->master_idx = reserve->master_idx; + CAM_DBG(CAM_ISP, "CSID:%d master_idx=%d", + csid_hw->hw_intf->hw_idx, path_data->master_idx); + path_data->start_pixel = reserve->in_port->right_start; + path_data->end_pixel = reserve->in_port->right_stop; + path_data->width = reserve->in_port->right_width; + CAM_DBG(CAM_ISP, + "CSID:%d res:%d slave:start:0x%x end:0x%x width 0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_pixel, path_data->end_pixel, + path_data->width); + CAM_DBG(CAM_ISP, + "CSID:%d res:%d slave:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->start_line, path_data->end_line); + } else { + path_data->width = reserve->in_port->left_width; + path_data->start_pixel = reserve->in_port->left_start; + path_data->end_pixel = reserve->in_port->left_stop; + CAM_DBG(CAM_ISP, + "CSID:%d res:%d left width %d start: %d stop:%d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + reserve->in_port->left_width, + reserve->in_port->left_start, + reserve->in_port->left_stop); + } + + CAM_DBG(CAM_ISP, "CSID:%d res:%d width %d height %d", + csid_hw->hw_intf->hw_idx, reserve->res_id, + path_data->width, path_data->height); + reserve->node_res = res; + +end: + return rc; +} + +static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) +{ + int rc = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i, val; + int clk_lvl; + unsigned long flags; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + /* overflow check before increment */ + if (csid_hw->hw_info->open_count == UINT_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Open count reached max", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + + /* Increment ref Count */ + csid_hw->hw_info->open_count++; + if (csid_hw->hw_info->open_count > 1) { + CAM_DBG(CAM_ISP, "CSID hw has already been enabled"); + return rc; + } + + CAM_DBG(CAM_ISP, "CSID:%d init CSID HW", + csid_hw->hw_intf->hw_idx); + + rc = cam_soc_util_get_clk_level(soc_info, csid_hw->clk_rate, + soc_info->src_clk_idx, &clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get clk level for rate %d", + csid_hw->clk_rate); + goto err; + } + + CAM_DBG(CAM_ISP, "CSID clock lvl %d", clk_lvl); + + rc = cam_ife_csid_enable_soc_resources(soc_info, clk_lvl); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d Enable SOC failed", + csid_hw->hw_intf->hw_idx); + goto err; + } + + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_UP; + /* Reset CSID top */ + rc = cam_ife_csid_global_reset(csid_hw); + if (rc) + goto disable_soc; + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + + /* clear all interrupts */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(csid_reg->csi2_reg->csi2_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(csid_reg->cmn_reg->ipp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(csid_reg->cmn_reg->ppp_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) + cam_io_w_mb(csid_reg->cmn_reg->rdi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) + cam_io_w_mb(csid_reg->cmn_reg->udi_irq_mask_all, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_hw_version_addr); + CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + return 0; + +disable_soc: + cam_ife_csid_disable_soc_resources(soc_info); + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; +err: + csid_hw->hw_info->open_count--; + return rc; +} + +static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) +{ + int rc = -EINVAL; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; + + /* Check for refcount */ + if (!csid_hw->hw_info->open_count) { + CAM_WARN(CAM_ISP, "Unbalanced disable_hw"); + return rc; + } + + /* Decrement ref Count */ + csid_hw->hw_info->open_count--; + + if (csid_hw->hw_info->open_count) { + rc = 0; + return rc; + } + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + CAM_DBG(CAM_ISP, "%s:Calling Global Reset\n", __func__); + cam_ife_csid_global_reset(csid_hw); + CAM_DBG(CAM_ISP, "%s:Global Reset Done\n", __func__); + + CAM_DBG(CAM_ISP, "CSID:%d De-init CSID HW", + csid_hw->hw_intf->hw_idx); + + /*disable the top IRQ interrupt */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + + rc = cam_ife_csid_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", + csid_hw->hw_intf->hw_idx); + + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 0; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + csid_hw->error_irq_count = 0; + csid_hw->prev_boot_timestamp = 0; + + return rc; +} + + +static int cam_ife_csid_tpg_start(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t val = 0; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg = NULL; + + csid_hw->tpg_start_cnt++; + if (csid_hw->tpg_start_cnt == 1) { + /*Enable the TPG */ + CAM_DBG(CAM_ISP, "CSID:%d start CSID TPG", + csid_hw->hw_intf->hw_idx); + + soc_info = &csid_hw->hw_info->soc_info; + { + uint32_t val; + uint32_t i; + uint32_t base = 0x600; + + CAM_DBG(CAM_ISP, "================ TPG ============"); + for (i = 0; i < 16; i++) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + base + i * 4); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", + (base + i*4), val); + } + + CAM_DBG(CAM_ISP, "================ IPP ============="); + base = 0x200; + for (i = 0; i < 10; i++) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + base + i * 4); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", + (base + i*4), val); + } + + CAM_DBG(CAM_ISP, "================ RX ============="); + base = 0x100; + for (i = 0; i < 5; i++) { + val = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + base + i * 4); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", + (base + i*4), val); + } + } + + /* Enable the IFE force clock on for dual isp case */ + csid_reg = csid_hw->csid_info->csid_reg; + if (csid_hw->tpg_cfg.usage_type) { + rc = cam_ife_csid_enable_ife_force_clock_on(soc_info, + csid_reg->tpg_reg->tpg_cpas_ife_reg_offset); + if (rc) + return rc; + } + + CAM_DBG(CAM_ISP, "============ TPG control ============"); + val = (4 << 20); + val |= (0x80 << 8); + val |= (((csid_hw->csi2_rx_cfg.lane_num - 1) & 0x3) << 4); + val |= 7; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_ctrl_addr); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + 0x600); + CAM_DBG(CAM_ISP, "reg 0x%x = 0x%x", 0x600, val); + } + + return 0; +} + +static int cam_ife_csid_tpg_stop(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg = NULL; + + if (csid_hw->tpg_start_cnt) + csid_hw->tpg_start_cnt--; + + if (csid_hw->tpg_start_cnt) + return 0; + + soc_info = &csid_hw->hw_info->soc_info; + csid_reg = csid_hw->csid_info->csid_reg; + + /* disable the TPG */ + if (!csid_hw->tpg_start_cnt) { + CAM_DBG(CAM_ISP, "CSID:%d stop CSID TPG", + csid_hw->hw_intf->hw_idx); + + /* Disable the IFE force clock on for dual isp case */ + if (csid_hw->tpg_cfg.usage_type) + rc = cam_ife_csid_disable_ife_force_clock_on(soc_info, + csid_reg->tpg_reg->tpg_cpas_ife_reg_offset); + + /*stop the TPG */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->tpg_reg->csid_tpg_ctrl_addr); + } + + return 0; +} + + +static int cam_ife_csid_config_tpg(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + CAM_DBG(CAM_ISP, "CSID:%d TPG config", + csid_hw->hw_intf->hw_idx); + + /* configure one DT, infinite frames */ + val = (0 << 16) | (1 << 10) | CAM_IFE_CSID_TPG_VC_VAL; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_vc_cfg0_addr); + + /* vertical blanking count = 0x3FF, horzontal blanking count = 0x740*/ + val = (0x3FF << 12) | 0x740; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_vc_cfg1_addr); + + cam_io_w_mb(0x12345678, soc_info->reg_map[0].mem_base + + csid_hw->csid_info->csid_reg->tpg_reg->csid_tpg_lfsr_seed_addr); + + val = csid_hw->tpg_cfg.width << 16 | + csid_hw->tpg_cfg.height; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_dt_n_cfg_0_addr); + + cam_io_w_mb(CAM_IFE_CSID_TPG_DT_VAL, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_dt_n_cfg_1_addr); + + /* + * in_format is the same as the input resource format. + * it is one larger than the register spec format. + */ + val = ((csid_hw->tpg_cfg.in_format - 1) << 16) | 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_dt_n_cfg_2_addr); + + /* static frame with split color bar */ + val = 1 << 5; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_color_bars_cfg_addr); + /* config pix pattern */ + cam_io_w_mb(csid_hw->tpg_cfg.test_pattern, + soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_common_gen_cfg_addr); + + return 0; +} + +static int cam_ife_csid_enable_csi2( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_cid_data *cid_data; + uint32_t val = 0; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_DBG(CAM_ISP, "CSID:%d count:%d config csi2 rx", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + + /* overflow check before increment */ + if (csid_hw->csi2_cfg_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Open count reached max", + csid_hw->hw_intf->hw_idx); + return -EINVAL; + } + + cid_data = (struct cam_ife_csid_cid_data *)res->res_priv; + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + csid_hw->csi2_cfg_cnt++; + if (csid_hw->csi2_cfg_cnt > 1) + return rc; + + /* rx cfg0 */ + val = 0; + val = (csid_hw->csi2_rx_cfg.lane_num - 1) | + (csid_hw->csi2_rx_cfg.lane_cfg << 4) | + (csid_hw->csi2_rx_cfg.lane_type << 24); + val |= (csid_hw->csi2_rx_cfg.phy_sel & + csid_reg->csi2_reg->csi2_rx_phy_num_mask) << 20; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + + /* rx cfg1*/ + val = (1 << csid_reg->csi2_reg->csi2_misr_enable_shift_val); + /* if VC value is more than 3 than set full width of VC */ + if (cid_data->vc > 3 || (cid_data->is_valid_vc1_dt1 && + cid_data->vc1 > 3)) + val |= (1 << csid_reg->csi2_reg->csi2_vc_mode_shift_val); + + /* enable packet ecc correction */ + val |= 1; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) { + /* Config the TPG */ + rc = cam_ife_csid_config_tpg(csid_hw, res); + if (rc) { + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; + } + } + + /*Enable the CSI2 rx interrupts */ + val = CSID_CSI2_RX_INFO_RST_DONE | + CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW | + CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION | + CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION | + CSID_CSI2_RX_ERROR_CRC | + CSID_CSI2_RX_ERROR_ECC | + CSID_CSI2_RX_ERROR_MMAPPED_VC_DT | + CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW | + CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME | + CSID_CSI2_RX_ERROR_CPHY_PH_CRC; + + /* Enable the interrupt based on csid debug info set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) + val |= CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) + val |= CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED | + CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + return 0; +} + +static int cam_ife_csid_disable_csi2( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + if (res->res_id >= CAM_IFE_CSID_CID_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id :%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_DBG(CAM_ISP, "CSID:%d cnt : %d Disable csi2 rx", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + + if (csid_hw->csi2_cfg_cnt) + csid_hw->csi2_cfg_cnt--; + + if (csid_hw->csi2_cfg_cnt) + return 0; + + /* Disable the CSI2 rx inerrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + /* Reset the Rx CFG registers */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static void cam_ife_csid_halt_csi2( + struct cam_ife_csid_hw *csid_hw) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + CAM_INFO(CAM_ISP, "CSID: %d cnt: %d Halt csi2 rx", + csid_hw->hw_intf->hw_idx, csid_hw->csi2_cfg_cnt); + + /* Disable the CSI2 rx inerrupts */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + + /* Reset the Rx CFG registers */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); +} + +static int cam_ife_csid_init_config_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + bool is_ipp; + uint32_t decode_format = 0, plain_format = 0, val = 0; + uint32_t camera_hw_version; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Config %s Path", (is_ipp) ? "IPP" : "PPP"); + rc = cam_ife_csid_get_format_ipp_ppp(path_data->in_format, + &decode_format, &plain_format); + if (rc) + return rc; + + /* + * configure Pxl path and enable the time stamp capture. + * enable the HW measrurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (decode_format << csid_reg->cmn_reg->fmt_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 1) | 1; + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + camera_hw_version = 0; + } + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + + if (camera_hw_version == CAM_CPAS_TITAN_480_V100) + val |= (path_data->drop_enable << + csid_reg->cmn_reg->drop_h_en_shift_val) | + (path_data->drop_enable << + csid_reg->cmn_reg->drop_v_en_shift_val); + + if (path_data->horizontal_bin || path_data->qcfa_bin) { + val |= (1 << pxl_reg->horizontal_bin_en_shift_val); + if (path_data->qcfa_bin) + val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val); + } + + if (is_ipp && csid_hw->binning_supported && + csid_hw->binning_enable) + val |= (1 << pxl_reg->quad_cfa_bin_en_shift_val); + + val |= (1 << pxl_reg->pix_store_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + if (path_data->is_valid_vc1_dt1 && + camera_hw_version == CAM_CPAS_TITAN_480_V100) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_multi_vcdt_cfg0_addr); + val |= ((path_data->vc1 << 2) | + (path_data->dt1 << 7) | 1); + } + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg1_addr); + + /* select the post irq sub sample strobe for time stamp capture */ + val |= CSID_TIMESTAMP_STB_POST_IRQ; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg1_addr); + + if (path_data->crop_enable) { + val = (((path_data->end_pixel & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_pixel & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_hcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Horizontal crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + val = (((path_data->end_line & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_line & 0xFFFF)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_vcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + /* Enable generating early eof strobe based on crop config. + * Skip for version 480 HW due to HW limitation. + */ + if (!(csid_hw->csid_debug & CSID_DEBUG_DISABLE_EARLY_EOF) && + (camera_hw_version != CAM_CPAS_TITAN_480_V100)) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + val |= (1 << pxl_reg->early_eof_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + } + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_frm_drop_pattern_addr); + /* set irq sub sample pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_subsample_pattern_addr); + /* set pxl drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_pix_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_pix_drop_period_addr); + /* set line drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_line_drop_period_addr); + + + /* Enable the Pxl path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) + val |= csid_reg->cmn_reg->format_measure_en_val; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + /* Enable Error Detection */ + if (pxl_reg->overflow_ctrl_en) { + val = pxl_reg->overflow_ctrl_en; + /* Overflow ctrl mode: 2 -> Detect overflow */ + val |= 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_err_recovery_cfg0_addr); + } + + /* Enable the HBI/VBI counter */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + val |= csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + } + + /* configure the rx packet capture based on csid debug set */ + val = 0; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + CAM_DBG(CAM_ISP, "rx capture control value 0x%x", val); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_ife_csid_deinit_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t val; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + bool is_ipp; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d %s Res type %d res_id:%d in wrong state %d", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s %d is not supported on HW", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id); + rc = -EINVAL; + goto end; + } + + /* Disable Error Recovery */ + if (pxl_reg->overflow_ctrl_en) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_err_recovery_cfg0_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + if (val & csid_reg->cmn_reg->format_measure_en_val) { + val &= ~csid_reg->cmn_reg->format_measure_en_val; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_cfg0_addr); + + /* Disable the HBI/VBI counter */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + val &= ~csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_format_measure_cfg0_addr); + } + +end: + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_ife_csid_enable_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg = NULL; + bool is_ipp; + uint32_t val = 0; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d %s path res type:%d res_id:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s %d not supported on HW", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enable %s path", (is_ipp) ? "IPP" : "PPP"); + + /* Set master or slave path */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) + /*Set halt mode as master */ + val = CSID_HALT_MODE_MASTER << 2; + else if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + /*Set halt mode as slave and set master idx */ + val = path_data->master_idx << 4 | CSID_HALT_MODE_SLAVE << 2; + else + /* Default is internal halt mode */ + val = 0; + + /* + * Resume at frame boundary if Master or No Sync. + * Slave will get resume command from Master. + */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + + CAM_DBG(CAM_ISP, "CSID:%d %s Ctrl val: 0x%x", + csid_hw->hw_intf->hw_idx, + (is_ipp) ? "IPP" : "PPP", val); + + /* Enable the required pxl path interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + if (pxl_reg->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + + if (pxl_reg->overflow_ctrl_en) + val |= CSID_PATH_OVERFLOW_RECOVERY; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) + val |= CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + CAM_DBG(CAM_ISP, "Enable %s IRQ mask 0x%x", + (is_ipp) ? "IPP" : "PPP", val); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_ife_csid_disable_pxl_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_pxl_reg_offset *pxl_reg; + bool is_ipp; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, res->res_state); + return rc; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + is_ipp = true; + pxl_reg = csid_reg->ipp_reg; + } else { + is_ipp = false; + pxl_reg = csid_reg->ppp_reg; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_DBG(CAM_ISP, "CSID:%d %s path Res:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id, res->res_state); + return -EINVAL; + } + + if (!pxl_reg) { + CAM_ERR(CAM_ISP, "CSID:%d %s %d is not supported on HW", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + res->res_id); + return -EINVAL; + } + + if (stop_cmd != CAM_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d %s path un supported stop command:%d", + csid_hw->hw_intf->hw_idx, (is_ipp) ? "IPP" : "PPP", + stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d %s path", + csid_hw->hw_intf->hw_idx, res->res_id, + (is_ipp) ? "IPP" : "PPP"); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_irq_mask_addr); + + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { + /* configure Halt for master */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + if (path_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE && + stop_cmd == CAM_CSID_HALT_IMMEDIATELY) { + /* configure Halt for slave */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0xF; + val |= stop_cmd; + val |= (CSID_HALT_MODE_MASTER << 2); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + + return rc; +} + +static int cam_ife_csid_init_config_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t path_format = 0, plain_fmt = 0, val = 0, id; + uint32_t format_measure_addr, camera_hw_version, packing_fmt = 0; + + path_data = (struct cam_ife_csid_path_cfg *) res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + id = res->res_id; + if (!csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d RDI:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, id); + return -EINVAL; + } + + rc = cam_ife_csid_get_format_rdi(path_data->in_format, + path_data->out_format, &path_format, &plain_fmt, &packing_fmt, + path_data->crop_enable || path_data->drop_enable); + if (rc) + return rc; + + /* + * RDI path config and enable the time stamp capture + * Enable the measurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (path_format << csid_reg->cmn_reg->fmt_shift_val) | + (plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 2) | 3; + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + camera_hw_version = 0; + } + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); + + if (camera_hw_version == CAM_CPAS_TITAN_480_V100 || + camera_hw_version == CAM_CPAS_TITAN_175_V130) { + val |= (path_data->drop_enable << + csid_reg->cmn_reg->drop_h_en_shift_val) | + (path_data->drop_enable << + csid_reg->cmn_reg->drop_v_en_shift_val) | + (packing_fmt << + csid_reg->cmn_reg->packing_fmt_shift_val); + } + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + if (path_data->is_valid_vc1_dt1 && + camera_hw_version == CAM_CPAS_TITAN_480_V100) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_multi_vcdt_cfg0_addr); + val |= ((path_data->vc1 << 2) | + (path_data->dt1 << 7) | 1); + } + + /* select the post irq sub sample strobe for time stamp capture */ + cam_io_w_mb(CSID_TIMESTAMP_STB_POST_IRQ, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg1_addr); + + if (path_data->crop_enable) { + val = (((path_data->end_pixel & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_pixel & 0xFFFF)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_hcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Horizontal crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + + val = (((path_data->end_line & 0xFFFF) << + csid_reg->cmn_reg->crop_shift) | + (path_data->start_line & 0xFFFF)); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_vcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + } + + /* Enable Error Detection */ + if (csid_reg->rdi_reg[id]->overflow_ctrl_en) { + val = csid_reg->rdi_reg[id]->overflow_ctrl_en; + /* Overflow ctrl mode: 2 -> Detect overflow */ + val |= 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_frm_drop_pattern_addr); + /* set IRQ sum sabmple */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_subsample_pattern_addr); + + /* set pixel drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_pattern_addr); + + /* Write max value to pixel drop period due to a bug in ver 480 HW */ + if (camera_hw_version == CAM_CPAS_TITAN_480_V100 && + path_data->drop_enable) + cam_io_w_mb(0x1F, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_period_addr); + else + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_pix_drop_period_addr); + + /* set line drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_rpp_line_drop_period_addr); + + /* Configure the halt mode */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + /* Enable the RPP path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) + val |= csid_reg->cmn_reg->format_measure_en_val; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + format_measure_addr = + csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg0_addr; + + /* Enable the HBI/VBI counter */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val |= csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + format_measure_addr); + } + + /* configure the rx packet capture based on csid debug set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_ife_csid_init_config_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t path_format = 0, plain_fmt = 0, val = 0, val1, id; + uint32_t format_measure_addr, packing_fmt = 0; + + path_data = (struct cam_ife_csid_path_cfg *)res->res_priv; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + if ((id >= CAM_IFE_CSID_UDI_MAX) || (!csid_reg->udi_reg[id])) { + CAM_ERR(CAM_ISP, "CSID:%d UDI:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, id); + return -EINVAL; + } + + rc = cam_ife_csid_get_format_rdi(path_data->in_format, + path_data->out_format, &path_format, &plain_fmt, &packing_fmt, + path_data->crop_enable || path_data->drop_enable); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to get format in_format: %u out_format: %u rc: %d", + path_data->in_format, path_data->out_format, rc); + return rc; + } + + /* + * UDI path config and enable the time stamp capture + * Enable the measurement blocks + */ + val = (path_data->vc << csid_reg->cmn_reg->vc_shift_val) | + (path_data->dt << csid_reg->cmn_reg->dt_shift_val) | + (path_data->cid << csid_reg->cmn_reg->dt_id_shift_val) | + (path_format << csid_reg->cmn_reg->fmt_shift_val) | + (plain_fmt << csid_reg->cmn_reg->plain_fmt_shit_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_h_en_shift_val) | + (path_data->crop_enable << + csid_reg->cmn_reg->crop_v_en_shift_val) | + (1 << 2) | 3; + + val |= (packing_fmt << csid_reg->cmn_reg->packing_fmt_shift_val); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + + /* select the post irq sub sample strobe for time stamp capture */ + val1 = CSID_TIMESTAMP_STB_POST_IRQ; + + /* select the num bytes out per cycle */ + val1 |= (path_data->num_bytes_out << + csid_reg->cmn_reg->num_bytes_out_shift_val); + + cam_io_w_mb(val1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg1_addr); + + /* Enable Error Detection */ + if (csid_reg->udi_reg[id]->overflow_ctrl_en) { + val = csid_reg->udi_reg[id]->overflow_ctrl_en; + /* Overflow ctrl mode: 2 -> Detect overflow */ + val |= 0x8; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_err_recovery_cfg0_addr); + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_frm_drop_pattern_addr); + /* set IRQ sum sabmple */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_subsample_pattern_addr); + + /* set pixel drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_pix_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_pix_drop_period_addr); + /* set line drop pattern to 0 and period to 1 */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_rpp_line_drop_period_addr); + + /* Configure the halt mode */ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) + val |= csid_reg->cmn_reg->format_measure_en_val; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + + format_measure_addr = + csid_reg->udi_reg[id]->csid_udi_format_measure_cfg0_addr; + + /* Enable the HBI/VBI counter */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val |= csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + format_measure_addr); + } + + /* configure the rx packet capture based on csid debug set */ + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) + val = ((1 << + csid_reg->csi2_reg->csi2_capture_short_pkt_en_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_short_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_long_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_long_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_long_pkt_vc_shift)); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) + val |= ((1 << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_en_shift) | + (path_data->dt << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_dt_shift) | + (path_data->vc << + csid_reg->csi2_reg->csi2_capture_cphy_pkt_vc_shift)); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_capture_ctrl_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + + return rc; +} + +static int cam_ife_csid_deinit_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t id, val, format_measure_addr; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + + if ((res->res_id < CAM_IFE_PIX_PATH_RES_UDI_0) || + (res->res_id > CAM_IFE_PIX_PATH_RES_UDI_2) || + (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) || + (!csid_reg->udi_reg[id])) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + /* Disable Error Recovery */ + if (csid_reg->udi_reg[id]->overflow_ctrl_en) { + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_err_recovery_cfg0_addr); + } + + format_measure_addr = + csid_reg->udi_reg[id]->csid_udi_format_measure_cfg0_addr; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + val &= ~csid_reg->cmn_reg->format_measure_en_val; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_cfg0_addr); + + /* Disable the HBI/VBI counter */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val &= ~csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + format_measure_addr); + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_ife_csid_deinit_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t id, val, format_measure_addr; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if (res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3 || + res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || + !csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res id%d state:%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + /* Disable Error Recovery */ + if (csid_reg->rdi_reg[id]->overflow_ctrl_en) { + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_err_recovery_cfg0_addr); + } + + format_measure_addr = + csid_reg->rdi_reg[id]->csid_rdi_format_measure_cfg0_addr; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + val &= ~csid_reg->cmn_reg->format_measure_en_val; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + /* Disable the HBI/VBI counter */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + format_measure_addr); + val &= ~csid_reg->cmn_reg->measure_en_hbi_vbi_cnt_mask; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + format_measure_addr); + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_ife_csid_enable_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t id, val; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3 || + !csid_reg->rdi_reg[id]) { + CAM_ERR(CAM_ISP, + "CSID:%d invalid res type:%d res_id:%d state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + /*resume at frame boundary */ + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + /* Enable the required RDI interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + if (csid_reg->rdi_reg[id]->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + + if (csid_reg->rdi_reg[id]->overflow_ctrl_en) + val |= CSID_PATH_OVERFLOW_RECOVERY; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + val |= CSID_PATH_INFO_INPUT_SOF; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) + val |= CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_ife_csid_enable_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t id, val; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + + if ((res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) || + (res->res_id > CAM_IFE_PIX_PATH_RES_UDI_2) || + (res->res_id < CAM_IFE_PIX_PATH_RES_UDI_0) || + (!csid_reg->udi_reg[id])) { + CAM_ERR(CAM_ISP, + "CSID:%d invalid res type:%d res_id:%d state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + /*resume at frame boundary */ + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + + /* Enable the required UDI interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + if (csid_reg->udi_reg[id]->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + + if (csid_reg->udi_reg[id]->overflow_ctrl_en) + val |= CSID_PATH_OVERFLOW_RECOVERY; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) + val |= CSID_PATH_INFO_INPUT_SOF; + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) + val |= CSID_PATH_INFO_INPUT_EOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_ife_csid_disable_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t id, val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id; + + if ((res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3) || + (!csid_reg->rdi_reg[res->res_id])) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, res->res_state); + return rc; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d Invalid res_state%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + if (stop_cmd != CAM_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d un supported stop command:%d", + csid_hw->hw_intf->hw_idx, stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + + /* Halt the RDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + return rc; +} + +static int cam_ife_csid_disable_udi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res, + enum cam_ife_csid_halt_cmd stop_cmd) +{ + int rc = 0; + uint32_t id, val = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + + if ((res->res_id > CAM_IFE_PIX_PATH_RES_UDI_2) || + (res->res_id < CAM_IFE_PIX_PATH_RES_UDI_0) || + (!csid_reg->udi_reg[id])) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", + csid_hw->hw_intf->hw_idx, res->res_id); + return -EINVAL; + } + + if (res->res_state == CAM_ISP_RESOURCE_STATE_INIT_HW || + res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d already in stopped state:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, res->res_state); + return rc; + } + + if (res->res_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d Res:%d Invalid res_state%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + if (stop_cmd != CAM_CSID_HALT_AT_FRAME_BOUNDARY && + stop_cmd != CAM_CSID_HALT_IMMEDIATELY) { + CAM_ERR(CAM_ISP, "CSID:%d un supported stop command:%d", + csid_hw->hw_intf->hw_idx, stop_cmd); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_id); + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_irq_mask_addr); + + /* Halt the UDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[id]->csid_udi_ctrl_addr); + + return rc; +} + +static int cam_ife_csid_poll_stop_status( + struct cam_ife_csid_hw *csid_hw, + uint32_t res_mask) +{ + int rc = 0, id; + uint32_t csid_status_addr = 0, val = 0, res_id = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + for (; res_id < CAM_IFE_PIX_PATH_RES_MAX; res_id++, res_mask >>= 1) { + if ((res_mask & 0x1) == 0) + continue; + val = 0; + + if (res_id == CAM_IFE_PIX_PATH_RES_IPP) { + csid_status_addr = + csid_reg->ipp_reg->csid_pxl_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) { + csid_status_addr = + csid_reg->ppp_reg->csid_pxl_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + csid_status_addr = + csid_reg->rdi_reg[res_id]->csid_rdi_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + csid_status_addr = + csid_reg->udi_reg[id]->csid_udi_status_addr; + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res_id); + rc = -EINVAL; + break; + } + + CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_status_addr, val, (val & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, + CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d res:%d halt failed rc %d", + csid_hw->hw_intf->hw_idx, res_id, rc); + rc = -ETIMEDOUT; + break; + } + CAM_DBG(CAM_ISP, "End polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + } + + return rc; +} + +static int cam_ife_csid_get_hbi_vbi( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + uint32_t hbi, vbi; + int32_t id; + const struct cam_ife_csid_reg_offset *csid_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; + const struct cam_ife_csid_udi_reg_offset *udi_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH || + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res_type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid dev state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_format_measure2_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_format_measure2_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + rdi_reg = csid_reg->rdi_reg[res->res_id]; + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_format_measure2_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + udi_reg = csid_reg->udi_reg[id]; + hbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_format_measure1_addr); + vbi = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_format_measure2_addr); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + return -EINVAL; + } + + CAM_INFO_RATE_LIMIT(CAM_ISP, + "Device %s index %u Resource %u HBI: 0x%x VBI: 0x%x", + soc_info->dev_name, soc_info->index, + res->res_id, hbi, vbi); + + return 0; +} + +static int cam_ife_csid_get_time_stamp( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_csid_get_time_stamp_args *time_stamp; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg; + const struct cam_ife_csid_udi_reg_offset *udi_reg; + struct timespec64 ts; + uint32_t time_32, id; + uint64_t time_delta; + + time_stamp = (struct cam_csid_get_time_stamp_args *)cmd_args; + res = time_stamp->node_res; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (res->res_type != CAM_ISP_RESOURCE_PIX_PATH || + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res_type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + if (csid_hw->hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid dev state :%d", + csid_hw->hw_intf->hw_idx, + csid_hw->hw_info->hw_state); + return -EINVAL; + } + + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) { + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_timestamp_curr0_sof_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_timestamp_curr0_sof_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + id = res->res_id; + rdi_reg = csid_reg->rdi_reg[id]; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + rdi_reg->csid_rdi_timestamp_curr0_sof_addr); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + id = res->res_id - CAM_IFE_PIX_PATH_RES_UDI_0; + udi_reg = csid_reg->udi_reg[id]; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = (uint64_t) time_32; + time_stamp->time_stamp_val = time_stamp->time_stamp_val << 32; + + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + udi_reg->csid_udi_timestamp_curr0_sof_addr); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + return -EINVAL; + } + + time_stamp->time_stamp_val |= (uint64_t) time_32; + time_stamp->time_stamp_val = mul_u64_u32_div( + time_stamp->time_stamp_val, + CAM_IFE_CSID_QTIMER_MUL_FACTOR, + CAM_IFE_CSID_QTIMER_DIV_FACTOR); + + if (!csid_hw->prev_boot_timestamp) { + get_monotonic_boottime64(&ts); + time_stamp->boot_timestamp = + (uint64_t)((ts.tv_sec * 1000000000) + + ts.tv_nsec); + csid_hw->prev_qtimer_ts = 0; + CAM_DBG(CAM_ISP, "timestamp:%lld", + time_stamp->boot_timestamp); + } else { + time_delta = time_stamp->time_stamp_val - + csid_hw->prev_qtimer_ts; + time_stamp->boot_timestamp = + csid_hw->prev_boot_timestamp + time_delta; + } + csid_hw->prev_qtimer_ts = time_stamp->time_stamp_val; + csid_hw->prev_boot_timestamp = time_stamp->boot_timestamp; + + return 0; +} + +static int cam_ife_csid_set_csid_debug(struct cam_ife_csid_hw *csid_hw, + void *cmd_args) +{ + uint32_t *csid_debug; + + csid_debug = (uint32_t *) cmd_args; + csid_hw->csid_debug = *csid_debug; + CAM_DBG(CAM_ISP, "CSID:%d set csid debug value:%d", + csid_hw->hw_intf->hw_idx, csid_hw->csid_debug); + + return 0; +} + +int cam_ife_csid_get_hw_caps(void *hw_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw_caps *hw_caps; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + const struct cam_ife_csid_reg_offset *csid_reg; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + csid_reg = csid_hw->csid_info->csid_reg; + hw_caps = (struct cam_ife_csid_hw_caps *) get_hw_cap_args; + + hw_caps->num_rdis = csid_reg->cmn_reg->num_rdis; + hw_caps->num_pix = csid_reg->cmn_reg->num_pix; + hw_caps->num_ppp = csid_reg->cmn_reg->num_ppp; + hw_caps->major_version = csid_reg->cmn_reg->major_version; + hw_caps->minor_version = csid_reg->cmn_reg->minor_version; + hw_caps->version_incr = csid_reg->cmn_reg->version_incr; + + CAM_DBG(CAM_ISP, + "CSID:%d No rdis:%d, no pix:%d, major:%d minor:%d ver :%d", + csid_hw->hw_intf->hw_idx, hw_caps->num_rdis, + hw_caps->num_pix, hw_caps->major_version, + hw_caps->minor_version, hw_caps->version_incr); + + return rc; +} + +int cam_ife_csid_reset(void *hw_priv, + void *reset_args, uint32_t arg_size) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_csid_reset_cfg_args *reset; + int rc = 0; + + if (!hw_priv || !reset_args || (arg_size != + sizeof(struct cam_csid_reset_cfg_args))) { + CAM_ERR(CAM_ISP, "CSID:Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + reset = (struct cam_csid_reset_cfg_args *)reset_args; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + switch (reset->reset_type) { + case CAM_IFE_CSID_RESET_GLOBAL: + rc = cam_ife_csid_global_reset(csid_hw); + break; + case CAM_IFE_CSID_RESET_PATH: + rc = cam_ife_csid_path_reset(csid_hw, reset); + break; + default: + CAM_ERR(CAM_ISP, "CSID:Invalid reset type :%d", + reset->reset_type); + rc = -EINVAL; + break; + } + mutex_unlock(&csid_hw->hw_info->hw_mutex); + + return rc; +} + +int cam_ife_csid_reserve(void *hw_priv, + void *reserve_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_csid_hw_reserve_resource_args *reserv; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_csid_hw_reserve_resource_args))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + reserv = (struct cam_csid_hw_reserve_resource_args *)reserve_args; + + CAM_DBG(CAM_ISP, "res_type %d, CSID: %u", + reserv->res_type, csid_hw->hw_intf->hw_idx); + + mutex_lock(&csid_hw->hw_info->hw_mutex); + switch (reserv->res_type) { + case CAM_ISP_RESOURCE_CID: + rc = cam_ife_csid_cid_reserve(csid_hw, reserv); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + rc = cam_ife_csid_path_reserve(csid_hw, reserv); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type :%d", + csid_hw->hw_intf->hw_idx, reserv->res_type); + rc = -EINVAL; + break; + } + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +int cam_ife_csid_release(void *hw_priv, + void *release_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + struct cam_ife_csid_cid_data *cid_data; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + res = (struct cam_isp_resource_node *)release_args; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if ((res->res_type == CAM_ISP_RESOURCE_CID && + res->res_id >= CAM_IFE_CSID_CID_MAX) || + (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + if ((res->res_state <= CAM_ISP_RESOURCE_STATE_AVAILABLE) || + (res->res_state >= CAM_ISP_RESOURCE_STATE_STREAMING)) { + CAM_WARN(CAM_ISP, + "CSID:%d res type:%d Res %d in state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, + res->res_state); + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d res type :%d Resource id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + cid_data = (struct cam_ife_csid_cid_data *) res->res_priv; + if (cid_data->cnt) + cid_data->cnt--; + + if (!cid_data->cnt) + res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + if (csid_hw->csi2_reserve_cnt) + csid_hw->csi2_reserve_cnt--; + + if (!csid_hw->csi2_reserve_cnt) + memset(&csid_hw->csi2_rx_cfg, 0, + sizeof(struct cam_ife_csid_csi2_rx_cfg)); + + CAM_DBG(CAM_ISP, "CSID:%d res id :%d cnt:%d reserv cnt:%d", + csid_hw->hw_intf->hw_idx, + res->res_id, cid_data->cnt, csid_hw->csi2_reserve_cnt); + + break; + case CAM_ISP_RESOURCE_PIX_PATH: + res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + break; + } + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static int cam_ife_csid_reset_regs( + struct cam_ife_csid_hw *csid_hw, bool reset_hw) +{ + int rc = 0; + const struct cam_ife_csid_reg_offset *csid_reg = + csid_hw->csid_info->csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t val = 0; + unsigned long flags; + + soc_info = &csid_hw->hw_info->soc_info; + + reinit_completion(&csid_hw->csid_top_complete); + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + + /* clear the top interrupt first */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + if (reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + /* perform the top CSID registers reset */ + val = reset_hw ? csid_reg->cmn_reg->csid_rst_stb : + csid_reg->cmn_reg->csid_reg_rst_stb; + cam_io_w_mb(val, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + /* + * for SW reset, we enable the IRQ after since the mask + * register has been reset + */ + if (!reset_hw) { + /* enable top reset complete IRQ */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + } + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + CAM_DBG(CAM_ISP, "CSID reset start"); + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + if (val & 0x1) { + /* clear top reset IRQ */ + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, + reset_hw ? "hw" : "sw", + rc); + rc = 0; + goto end; + } + CAM_ERR(CAM_ISP, "CSID:%d csid_reset %s fail rc = %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); + rc = -ETIMEDOUT; + goto end; + } else { + CAM_DBG(CAM_ISP, "CSID:%d %s reset completed %d", + csid_hw->hw_intf->hw_idx, reset_hw ? "hw" : "sw", rc); + rc = 0; + } + +end: + return rc; +} + +int cam_ife_csid_init_hw(void *hw_priv, + void *init_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + + if (!hw_priv || !init_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + res = (struct cam_isp_resource_node *)init_args; + csid_reg = csid_hw->csid_info->csid_reg; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if ((res->res_type == CAM_ISP_RESOURCE_CID && + res->res_id >= CAM_IFE_CSID_CID_MAX) || + (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid res tpe:%d res id%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + if ((res->res_type == CAM_ISP_RESOURCE_PIX_PATH) && + (res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED)) { + CAM_ERR(CAM_ISP, + "CSID:%d res type:%d res_id:%dInvalid state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ISP, "CSID:%d res type :%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + /* Initialize the csid hardware */ + rc = cam_ife_csid_enable_hw(csid_hw); + if (rc) + goto end; + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + rc = cam_ife_csid_enable_csi2(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + rc = cam_ife_csid_init_config_pxl_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + rc = cam_ife_csid_init_config_rdi_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_init_config_udi_path(csid_hw, res); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + rc = -EINVAL; + goto end; + } + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type state %d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + + rc = cam_ife_csid_reset_regs(csid_hw, true); + if (rc < 0) + CAM_ERR(CAM_ISP, "CSID: Failed in HW reset"); + + if (rc) + cam_ife_csid_disable_hw(csid_hw); + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +int cam_ife_csid_deinit_hw(void *hw_priv, + void *deinit_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + + if (!hw_priv || !deinit_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID:Invalid arguments"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enter"); + res = (struct cam_isp_resource_node *)deinit_args; + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + + mutex_lock(&csid_hw->hw_info->hw_mutex); + if (res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "CSID:%d Res:%d already in De-init state", + csid_hw->hw_intf->hw_idx, + res->res_id); + goto end; + } + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + CAM_DBG(CAM_ISP, "De-Init ife_csid"); + rc = cam_ife_csid_disable_csi2(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + CAM_DBG(CAM_ISP, "De-Init Pix Path: %d\n", res->res_id); + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + rc = cam_ife_csid_deinit_pxl_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + rc = cam_ife_csid_deinit_rdi_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_deinit_udi_path(csid_hw, res); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + rc = -EINVAL; + goto end; + } + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid Res type %d", + csid_hw->hw_intf->hw_idx, + res->res_type); + goto end; + } + + /* Disable CSID HW */ + CAM_DBG(CAM_ISP, "Disabling CSID Hw\n"); + cam_ife_csid_disable_hw(csid_hw); + CAM_DBG(CAM_ISP, "%s: Exit\n", __func__); + +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +int cam_ife_csid_start(void *hw_priv, void *start_args, + uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + const struct cam_ife_csid_reg_offset *csid_reg; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + res = (struct cam_isp_resource_node *)start_args; + csid_reg = csid_hw->csid_info->csid_reg; + + if ((res->res_type == CAM_ISP_RESOURCE_CID && + res->res_id >= CAM_IFE_CSID_CID_MAX) || + (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_id >= CAM_IFE_PIX_PATH_RES_MAX)) { + CAM_DBG(CAM_ISP, "CSID:%d Invalid res tpe:%d res id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, + res->res_id); + rc = -EINVAL; + goto end; + } + + /* Reset sof irq debug fields */ + csid_hw->sof_irq_triggered = false; + csid_hw->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "CSID:%d res_type :%d res_id:%d", + csid_hw->hw_intf->hw_idx, res->res_type, res->res_id); + + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) + rc = cam_ife_csid_tpg_start(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + rc = cam_ife_csid_enable_pxl_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + rc = cam_ife_csid_enable_rdi_path(csid_hw, res); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_enable_udi_path(csid_hw, res); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", res->res_id); + rc = -EINVAL; + goto end; + } + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } +end: + return rc; +} + +int cam_ife_csid_stop(void *hw_priv, + void *stop_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res; + struct cam_csid_hw_stop_args *csid_stop; + uint32_t i; + uint32_t res_mask = 0; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_csid_hw_stop_args))) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + csid_stop = (struct cam_csid_hw_stop_args *) stop_args; + + if (!csid_stop->num_res) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + CAM_DBG(CAM_ISP, "CSID:%d num_res %d", + csid_hw->hw_intf->hw_idx, + csid_stop->num_res); + + /* Stop the resource first */ + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); + switch (res->res_type) { + case CAM_ISP_RESOURCE_CID: + if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) + rc = cam_ife_csid_tpg_stop(csid_hw, res); + break; + case CAM_ISP_RESOURCE_PIX_PATH: + res_mask |= (1 << res->res_id); + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || + res->res_id == CAM_IFE_PIX_PATH_RES_PPP) { + rc = cam_ife_csid_disable_pxl_path(csid_hw, + res, csid_stop->stop_cmd); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_RDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_2 || + res->res_id == CAM_IFE_PIX_PATH_RES_RDI_3) { + rc = cam_ife_csid_disable_rdi_path(csid_hw, + res, csid_stop->stop_cmd); + } else if (res->res_id == CAM_IFE_PIX_PATH_RES_UDI_0 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_1 || + res->res_id == CAM_IFE_PIX_PATH_RES_UDI_2) { + rc = cam_ife_csid_disable_udi_path(csid_hw, + res, csid_stop->stop_cmd); + } else { + CAM_ERR(CAM_ISP, "Invalid res_id: %u", + res->res_id); + return -EINVAL; + } + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + } + + if (res_mask) + rc = cam_ife_csid_poll_stop_status(csid_hw, res_mask); + + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + } + + CAM_DBG(CAM_ISP, "%s: Exit\n", __func__); + + return rc; + +} + +int cam_ife_csid_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + + return -EINVAL; +} + +int cam_ife_csid_write(void *hw_priv, + void *write_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + return -EINVAL; +} + +static int cam_ife_csid_sof_irq_debug( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + int i = 0; + uint32_t val = 0; + bool sof_irq_enable = false; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (*((uint32_t *)cmd_args) == 1) + sof_irq_enable = true; + + if (csid_hw->hw_info->hw_state == + CAM_HW_STATE_POWER_DOWN) { + CAM_WARN(CAM_ISP, + "CSID powered down unable to %s sof irq", + (sof_irq_enable == true) ? "enable" : "disable"); + return 0; + } + + if (csid_reg->ipp_reg) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_mask_addr); + val = 0; + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + val = 0; + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_mask_addr); + val = 0; + } + } + + if (sof_irq_enable) { + csid_hw->csid_debug |= CSID_DEBUG_ENABLE_SOF_IRQ; + csid_hw->sof_irq_triggered = true; + } else { + csid_hw->csid_debug &= ~CSID_DEBUG_ENABLE_SOF_IRQ; + csid_hw->sof_irq_triggered = false; + } + + CAM_INFO(CAM_ISP, "SOF freeze: CSID SOF irq %s", + (sof_irq_enable == true) ? "enabled" : "disabled"); + + return 0; +} + +static int cam_ife_csid_set_csid_clock( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_ife_csid_clock_update_args *clk_update = NULL; + + if (!csid_hw) + return -EINVAL; + + clk_update = + (struct cam_ife_csid_clock_update_args *)cmd_args; + + csid_hw->clk_rate = clk_update->clk_rate; + CAM_INFO(CAM_ISP, "CSID clock rate %llu", csid_hw->clk_rate); + + return 0; +} + +static int cam_ife_csid_set_csid_qcfa( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + struct cam_ife_csid_qcfa_update_args *qcfa_update = NULL; + + if (!csid_hw) + return -EINVAL; + + qcfa_update = + (struct cam_ife_csid_qcfa_update_args *)cmd_args; + + csid_hw->binning_supported = qcfa_update->qcfa_binning; + CAM_DBG(CAM_ISP, "CSID QCFA binning %d", csid_hw->binning_supported); + + return 0; +} + +static int cam_ife_csid_process_cmd(void *hw_priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_info *csid_hw_info; + struct cam_isp_resource_node *res = NULL; + + if (!hw_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return -EINVAL; + } + + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + + switch (cmd_type) { + case CAM_IFE_CSID_CMD_GET_TIME_STAMP: + rc = cam_ife_csid_get_time_stamp(csid_hw, cmd_args); + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_HBI_VBI_INFO) { + res = ((struct cam_csid_get_time_stamp_args *) + cmd_args)->node_res; + cam_ife_csid_get_hbi_vbi(csid_hw, res); + } + break; + case CAM_IFE_CSID_SET_CSID_DEBUG: + rc = cam_ife_csid_set_csid_debug(csid_hw, cmd_args); + break; + case CAM_IFE_CSID_SOF_IRQ_DEBUG: + rc = cam_ife_csid_sof_irq_debug(csid_hw, cmd_args); + break; + case CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE: + rc = cam_ife_csid_set_csid_clock(csid_hw, cmd_args); + break; + case CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED: + rc = cam_ife_csid_set_csid_qcfa(csid_hw, cmd_args); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", + csid_hw->hw_intf->hw_idx, cmd_type); + rc = -EINVAL; + break; + } + + return rc; + +} + +irqreturn_t cam_ife_csid_irq(int irq_num, void *data) +{ + struct cam_ife_csid_hw *csid_hw; + struct cam_hw_soc_info *soc_info; + const struct cam_ife_csid_reg_offset *csid_reg; + const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; + uint32_t irq_status_rdi[CAM_IFE_CSID_RDI_MAX] = {0, 0, 0, 0}; + uint32_t irq_status_udi[CAM_IFE_CSID_UDI_MAX] = {0, 0, 0}; + uint32_t val, irq_status_ppp = 0; + bool fatal_err_detected = false; + uint32_t sof_irq_debug_en = 0; + unsigned long flags; + + csid_hw = (struct cam_ife_csid_hw *)data; + + CAM_DBG(CAM_ISP, "CSID %d IRQ Handling", csid_hw->hw_intf->hw_idx); + + if (!data) { + CAM_ERR(CAM_ISP, "CSID: Invalid arguments"); + return IRQ_HANDLED; + } + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + csi2_reg = csid_reg->csi2_reg; + + /* read */ + irq_status_top = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr); + + irq_status_rx = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_status_addr); + + if (csid_reg->cmn_reg->num_pix) + irq_status_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_status_addr); + + if (csid_reg->cmn_reg->num_ppp) + irq_status_ppp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_status_addr); + + if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + irq_status_rdi[i] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); + } + } + + if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + irq_status_udi[i] = + cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_status_addr); + } + } + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear */ + cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + + cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); + if (csid_reg->cmn_reg->num_pix) + cam_io_w_mb(irq_status_ipp, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_ppp) + cam_io_w_mb(irq_status_ppp, soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_irq_clear_addr); + + if (csid_reg->cmn_reg->num_rdis <= CAM_IFE_CSID_RDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + cam_io_w_mb(irq_status_rdi[i], + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_clear_addr); + } + } + + if (csid_reg->cmn_reg->num_udis <= CAM_IFE_CSID_UDI_MAX) { + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + cam_io_w_mb(irq_status_udi[i], + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_irq_clear_addr); + } + } + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); + CAM_DBG(CAM_ISP, "irq_status_rx = 0x%x", irq_status_rx); + CAM_DBG(CAM_ISP, "irq_status_ipp = 0x%x", irq_status_ipp); + CAM_DBG(CAM_ISP, "irq_status_ppp = 0x%x", irq_status_ppp); + CAM_DBG(CAM_ISP, + "irq_status_rdi0= 0x%x irq_status_rdi1= 0x%x irq_status_rdi2= 0x%x", + irq_status_rdi[0], irq_status_rdi[1], irq_status_rdi[2]); + CAM_DBG(CAM_ISP, + "irq_status_udi0= 0x%x irq_status_udi1= 0x%x irq_status_udi2= 0x%x", + irq_status_udi[0], irq_status_udi[1], irq_status_udi[2]); + + if (irq_status_top & CSID_TOP_IRQ_DONE) { + CAM_DBG(CAM_ISP, "csid top reset complete"); + complete(&csid_hw->csid_top_complete); + } + + if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "csi rx reset complete"); + complete(&csid_hw->csid_csi2_complete); + } + + spin_lock_irqsave(&csid_hw->lock_state, flags); + if (csid_hw->device_enabled == 1) { + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_EOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_SOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d ERROR_STREAM_UNDERFLOW", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + } + spin_unlock_irqrestore(&csid_hw->lock_state, flags); + + if (csid_hw->error_irq_count > + CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT) { + fatal_err_detected = true; + csid_hw->error_irq_count = 0; + } + + if (fatal_err_detected) + cam_ife_csid_halt_csi2(csid_hw); + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_EOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + } + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOT_IRQ) { + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL0_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL1_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL2_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PHY_DL3_SOT_CAPTURED", + csid_hw->hw_intf->hw_idx); + } + } + + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE) && + (irq_status_rx & CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d LONG_PKT_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_0_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d long packet VC :%d DT:%d WC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x3F), (val & 0xFFFF)); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_1_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d long packet ECC :%d", + csid_hw->hw_intf->hw_idx, val); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_long_pkt_ftr_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d long pkt cal CRC:%d expected CRC:%d", + csid_hw->hw_intf->hw_idx, (val >> 16), (val & 0xFFFF)); + } + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE) && + (irq_status_rx & CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d SHORT_PKT_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_short_pkt_0_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d short pkt VC :%d DT:%d LC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_short_pkt_1_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d short packet ECC :%d", + csid_hw->hw_intf->hw_idx, val); + } + + if ((csid_hw->csid_debug & CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE) && + (irq_status_rx & CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PKT_HDR_CAPTURED", + csid_hw->hw_intf->hw_idx); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csi2_reg->csid_csi2_rx_captured_cphy_pkt_hdr_addr); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d cphy packet VC :%d DT:%d WC:%d", + csid_hw->hw_intf->hw_idx, + (val >> 22), ((val >> 16) & 0x1F), (val & 0xFFFF)); + } + + /*read the IPP errors */ + if (csid_reg->cmn_reg->num_pix) { + /* IPP reset done bit */ + if (irq_status_ipp & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID IPP reset complete"); + complete(&csid_hw->csid_ipp_complete); + } + + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP SOF received", + csid_hw->hw_intf->hw_idx); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP CCIF violation", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ipp & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP Overflow due to back pressure", + csid_hw->hw_intf->hw_idx); + + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop IPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_pxl_ctrl_addr); + } + } + + /*read PPP errors */ + if (csid_reg->cmn_reg->num_ppp) { + /* PPP reset done bit */ + if (irq_status_ppp & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID PPP reset complete"); + complete(&csid_hw->csid_ppp_complete); + } + + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP SOF received", + csid_hw->hw_intf->hw_idx); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_ppp & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ppp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP CCIF violation", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ppp & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP Overflow due to back pressure", + csid_hw->hw_intf->hw_idx); + + if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop PPP path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->ppp_reg->csid_pxl_ctrl_addr); + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_rdis; i++) { + if (irq_status_rdi[i] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID RDI%d reset complete", i); + complete(&csid_hw->csid_rdin_complete[i]); + } + + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d SOF received", i); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI:%d EOF received", i); + + if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI :%d CCIF violation", i); + + if ((irq_status_rdi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID RDI :%d Overflow due to back pressure", + i); + + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d RDI fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop RDI path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_ctrl_addr); + } + } + + for (i = 0; i < csid_reg->cmn_reg->num_udis; i++) { + if (irq_status_udi[i] & + BIT(csid_reg->cmn_reg->path_rst_done_shift_val)) { + CAM_DBG(CAM_ISP, "CSID UDI%d reset complete", i); + complete(&csid_hw->csid_udin_complete[i]); + } + + if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_SOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID UDI:%d SOF received", i); + if (csid_hw->sof_irq_triggered) + csid_hw->irq_debug_cnt++; + } + + if ((irq_status_udi[i] & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID UDI:%d EOF received", i); + + if ((irq_status_udi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "CSID UDI :%d CCIF violation", i); + + if ((irq_status_udi[i] & CSID_PATH_OVERFLOW_RECOVERY)) + CAM_WARN_RATE_LIMIT(CAM_ISP, + "CSID UDI :%d Overflow due to back pressure", + i); + + if (irq_status_udi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d UDI fifo over flow", + csid_hw->hw_intf->hw_idx); + /* Stop UDI path immediately */ + cam_io_w_mb(CAM_CSID_HALT_IMMEDIATELY, + soc_info->reg_map[0].mem_base + + csid_reg->udi_reg[i]->csid_udi_ctrl_addr); + } + } + + if (csid_hw->irq_debug_cnt >= CAM_CSID_IRQ_SOF_DEBUG_CNT_MAX) { + cam_ife_csid_sof_irq_debug(csid_hw, &sof_irq_debug_en); + csid_hw->irq_debug_cnt = 0; + } + + CAM_DBG(CAM_ISP, "IRQ Handling exit"); + return IRQ_HANDLED; +} + +int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx, bool is_custom) +{ + int rc = -EINVAL; + uint32_t i; + uint32_t num_paths; + struct cam_ife_csid_path_cfg *path_data; + struct cam_ife_csid_cid_data *cid_data; + struct cam_hw_info *csid_hw_info; + struct cam_ife_csid_hw *ife_csid_hw = NULL; + + if (csid_idx >= CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid csid index:%d", csid_idx); + return rc; + } + + csid_hw_info = (struct cam_hw_info *) csid_hw_intf->hw_priv; + ife_csid_hw = (struct cam_ife_csid_hw *) csid_hw_info->core_info; + + ife_csid_hw->hw_intf = csid_hw_intf; + ife_csid_hw->hw_info = csid_hw_info; + + CAM_DBG(CAM_ISP, "type %d index %d", + ife_csid_hw->hw_intf->hw_type, csid_idx); + + + ife_csid_hw->device_enabled = 0; + ife_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&ife_csid_hw->hw_info->hw_mutex); + spin_lock_init(&ife_csid_hw->hw_info->hw_lock); + spin_lock_init(&ife_csid_hw->lock_state); + init_completion(&ife_csid_hw->hw_info->hw_complete); + + init_completion(&ife_csid_hw->csid_top_complete); + init_completion(&ife_csid_hw->csid_csi2_complete); + init_completion(&ife_csid_hw->csid_ipp_complete); + init_completion(&ife_csid_hw->csid_ppp_complete); + for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) + init_completion(&ife_csid_hw->csid_rdin_complete[i]); + + for (i = 0; i < CAM_IFE_CSID_UDI_MAX; i++) + init_completion(&ife_csid_hw->csid_udin_complete[i]); + + rc = cam_ife_csid_init_soc_resources(&ife_csid_hw->hw_info->soc_info, + cam_ife_csid_irq, ife_csid_hw, is_custom); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); + goto err; + } + + if (cam_cpas_is_feature_supported(CAM_CPAS_QCFA_BINNING_ENABLE) == 1) + ife_csid_hw->binning_enable = 1; + + ife_csid_hw->hw_intf->hw_ops.get_hw_caps = cam_ife_csid_get_hw_caps; + ife_csid_hw->hw_intf->hw_ops.init = cam_ife_csid_init_hw; + ife_csid_hw->hw_intf->hw_ops.deinit = cam_ife_csid_deinit_hw; + ife_csid_hw->hw_intf->hw_ops.reset = cam_ife_csid_reset; + ife_csid_hw->hw_intf->hw_ops.reserve = cam_ife_csid_reserve; + ife_csid_hw->hw_intf->hw_ops.release = cam_ife_csid_release; + ife_csid_hw->hw_intf->hw_ops.start = cam_ife_csid_start; + ife_csid_hw->hw_intf->hw_ops.stop = cam_ife_csid_stop; + ife_csid_hw->hw_intf->hw_ops.read = cam_ife_csid_read; + ife_csid_hw->hw_intf->hw_ops.write = cam_ife_csid_write; + ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd; + + num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->num_pix + + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis + + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + /* Initialize the CID resource */ + for (i = 0; i < num_paths; i++) { + ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID; + ife_csid_hw->cid_res[i].res_id = i; + ife_csid_hw->cid_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->cid_res[i].hw_intf = ife_csid_hw->hw_intf; + + cid_data = kzalloc(sizeof(struct cam_ife_csid_cid_data), + GFP_KERNEL); + if (!cid_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->cid_res[i].res_priv = cid_data; + } + + /* Initialize the IPP resources */ + if (ife_csid_hw->csid_info->csid_reg->cmn_reg->num_pix) { + ife_csid_hw->ipp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->ipp_res.res_id = CAM_IFE_PIX_PATH_RES_IPP; + ife_csid_hw->ipp_res.res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->ipp_res.hw_intf = ife_csid_hw->hw_intf; + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->ipp_res.res_priv = path_data; + } + + /* Initialize PPP resource */ + if (ife_csid_hw->csid_info->csid_reg->cmn_reg->num_ppp) { + ife_csid_hw->ppp_res.res_type = CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->ppp_res.res_id = CAM_IFE_PIX_PATH_RES_PPP; + ife_csid_hw->ppp_res.res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->ppp_res.hw_intf = ife_csid_hw->hw_intf; + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->ppp_res.res_priv = path_data; + } + + /* Initialize the RDI resource */ + for (i = 0; i < ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) { + /* res type is from RDI 0 to RDI3 */ + ife_csid_hw->rdi_res[i].res_type = + CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->rdi_res[i].res_id = i; + ife_csid_hw->rdi_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->rdi_res[i].hw_intf = ife_csid_hw->hw_intf; + + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->rdi_res[i].res_priv = path_data; + } + + /* Initialize the UDI resource */ + for (i = 0; i < ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + i++) { + /* res type is from UDI0 to UDI3 */ + ife_csid_hw->udi_res[i].res_type = + CAM_ISP_RESOURCE_PIX_PATH; + ife_csid_hw->udi_res[i].res_id = i + + CAM_IFE_PIX_PATH_RES_UDI_0; + ife_csid_hw->udi_res[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + ife_csid_hw->udi_res[i].hw_intf = ife_csid_hw->hw_intf; + + path_data = kzalloc(sizeof(*path_data), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->udi_res[i].res_priv = path_data; + } + + ife_csid_hw->csid_debug = 0; + ife_csid_hw->error_irq_count = 0; + + return 0; +err: + if (rc) { + kfree(ife_csid_hw->ipp_res.res_priv); + kfree(ife_csid_hw->ppp_res.res_priv); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) + kfree(ife_csid_hw->rdi_res[i].res_priv); + + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + i++) + kfree(ife_csid_hw->udi_res[i].res_priv); + + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) + kfree(ife_csid_hw->cid_res[i].res_priv); + + } + + return rc; +} +EXPORT_SYMBOL(cam_ife_csid_hw_probe_init); + +int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw) +{ + int rc = -EINVAL; + uint32_t i; + + if (!ife_csid_hw) { + CAM_ERR(CAM_ISP, "Invalid param"); + return rc; + } + + /* release the privdate data memory from resources */ + kfree(ife_csid_hw->ipp_res.res_priv); + kfree(ife_csid_hw->ppp_res.res_priv); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_rdis; + i++) { + kfree(ife_csid_hw->rdi_res[i].res_priv); + } + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->num_udis; + i++) { + kfree(ife_csid_hw->udi_res[i].res_priv); + } + for (i = 0; i < CAM_IFE_CSID_CID_MAX; i++) + kfree(ife_csid_hw->cid_res[i].res_priv); + + cam_ife_csid_deinit_soc_resources(&ife_csid_hw->hw_info->soc_info); + + return 0; +} +EXPORT_SYMBOL(cam_ife_csid_hw_deinit); diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h new file mode 100644 index 0000000000000000000000000000000000000000..4c2ac18089af5d5ad8944a38fe59ca2fa36e1dd6 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -0,0 +1,602 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_HW_H_ +#define _CAM_IFE_CSID_HW_H_ + +#include "cam_hw.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_ife_csid_soc.h" +#include "cam_ife_csid_core.h" + +#define CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED BIT(0) +#define CSID_CSI2_RX_INFO_PHY_DL1_EOT_CAPTURED BIT(1) +#define CSID_CSI2_RX_INFO_PHY_DL2_EOT_CAPTURED BIT(2) +#define CSID_CSI2_RX_INFO_PHY_DL3_EOT_CAPTURED BIT(3) +#define CSID_CSI2_RX_INFO_PHY_DL0_SOT_CAPTURED BIT(4) +#define CSID_CSI2_RX_INFO_PHY_DL1_SOT_CAPTURED BIT(5) +#define CSID_CSI2_RX_INFO_PHY_DL2_SOT_CAPTURED BIT(6) +#define CSID_CSI2_RX_INFO_PHY_DL3_SOT_CAPTURED BIT(7) +#define CSID_CSI2_RX_INFO_LONG_PKT_CAPTURED BIT(8) +#define CSID_CSI2_RX_INFO_SHORT_PKT_CAPTURED BIT(9) +#define CSID_CSI2_RX_INFO_CPHY_PKT_HDR_CAPTURED BIT(10) +#define CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION BIT(11) +#define CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION BIT(12) +#define CSID_CSI2_RX_ERROR_CPHY_PH_CRC BIT(13) +#define CSID_CSI2_RX_WARNING_ECC BIT(14) +#define CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW BIT(15) +#define CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW BIT(16) +#define CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW BIT(17) +#define CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW BIT(18) +#define CSID_CSI2_RX_ERROR_CRC BIT(19) +#define CSID_CSI2_RX_ERROR_ECC BIT(20) +#define CSID_CSI2_RX_ERROR_MMAPPED_VC_DT BIT(21) +#define CSID_CSI2_RX_ERROR_UNMAPPED_VC_DT BIT(22) +#define CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW BIT(23) +#define CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME BIT(24) +#define CSID_CSI2_RX_INFO_TG_DONE BIT(25) +#define CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW BIT(26) +#define CSID_CSI2_RX_INFO_RST_DONE BIT(27) + +#define CSID_TOP_IRQ_DONE BIT(0) +#define CSID_PATH_INFO_RST_DONE BIT(1) +#define CSID_PATH_ERROR_FIFO_OVERFLOW BIT(2) +#define CSID_PATH_INFO_SUBSAMPLED_EOF BIT(3) +#define CSID_PATH_INFO_SUBSAMPLED_SOF BIT(4) +#define CSID_PATH_INFO_FRAME_DROP_EOF BIT(5) +#define CSID_PATH_INFO_FRAME_DROP_EOL BIT(6) +#define CSID_PATH_INFO_FRAME_DROP_SOL BIT(7) +#define CSID_PATH_INFO_FRAME_DROP_SOF BIT(8) +#define CSID_PATH_INFO_INPUT_EOF BIT(9) +#define CSID_PATH_INFO_INPUT_EOL BIT(10) +#define CSID_PATH_INFO_INPUT_SOL BIT(11) +#define CSID_PATH_INFO_INPUT_SOF BIT(12) +#define CSID_PATH_ERROR_PIX_COUNT BIT(13) +#define CSID_PATH_ERROR_LINE_COUNT BIT(14) +#define CSID_PATH_ERROR_CCIF_VIOLATION BIT(15) +#define CSID_PATH_OVERFLOW_RECOVERY BIT(17) + +/* + * Debug values enable the corresponding interrupts and debug logs provide + * necessary information + */ +#define CSID_DEBUG_ENABLE_SOF_IRQ BIT(0) +#define CSID_DEBUG_ENABLE_EOF_IRQ BIT(1) +#define CSID_DEBUG_ENABLE_SOT_IRQ BIT(2) +#define CSID_DEBUG_ENABLE_EOT_IRQ BIT(3) +#define CSID_DEBUG_ENABLE_SHORT_PKT_CAPTURE BIT(4) +#define CSID_DEBUG_ENABLE_LONG_PKT_CAPTURE BIT(5) +#define CSID_DEBUG_ENABLE_CPHY_PKT_CAPTURE BIT(6) +#define CSID_DEBUG_ENABLE_HBI_VBI_INFO BIT(7) +#define CSID_DEBUG_DISABLE_EARLY_EOF BIT(8) + +/* enum cam_csid_path_halt_mode select the path halt mode control */ +enum cam_csid_path_halt_mode { + CSID_HALT_MODE_INTERNAL, + CSID_HALT_MODE_GLOBAL, + CSID_HALT_MODE_MASTER, + CSID_HALT_MODE_SLAVE, +}; + +/** + *enum cam_csid_path_timestamp_stb_sel - select the sof/eof strobes used to + * capture the timestamp + */ +enum cam_csid_path_timestamp_stb_sel { + CSID_TIMESTAMP_STB_PRE_HALT, + CSID_TIMESTAMP_STB_POST_HALT, + CSID_TIMESTAMP_STB_POST_IRQ, + CSID_TIMESTAMP_STB_MAX, +}; + +struct cam_ife_csid_pxl_reg_offset { + /* Pxl path register offsets*/ + uint32_t csid_pxl_irq_status_addr; + uint32_t csid_pxl_irq_mask_addr; + uint32_t csid_pxl_irq_clear_addr; + uint32_t csid_pxl_irq_set_addr; + + uint32_t csid_pxl_cfg0_addr; + uint32_t csid_pxl_cfg1_addr; + uint32_t csid_pxl_ctrl_addr; + uint32_t csid_pxl_frm_drop_pattern_addr; + uint32_t csid_pxl_frm_drop_period_addr; + uint32_t csid_pxl_irq_subsample_pattern_addr; + uint32_t csid_pxl_irq_subsample_period_addr; + uint32_t csid_pxl_hcrop_addr; + uint32_t csid_pxl_vcrop_addr; + uint32_t csid_pxl_pix_drop_pattern_addr; + uint32_t csid_pxl_pix_drop_period_addr; + uint32_t csid_pxl_line_drop_pattern_addr; + uint32_t csid_pxl_line_drop_period_addr; + uint32_t csid_pxl_rst_strobes_addr; + uint32_t csid_pxl_status_addr; + uint32_t csid_pxl_misr_val_addr; + uint32_t csid_pxl_format_measure_cfg0_addr; + uint32_t csid_pxl_format_measure_cfg1_addr; + uint32_t csid_pxl_format_measure0_addr; + uint32_t csid_pxl_format_measure1_addr; + uint32_t csid_pxl_format_measure2_addr; + uint32_t csid_pxl_timestamp_curr0_sof_addr; + uint32_t csid_pxl_timestamp_curr1_sof_addr; + uint32_t csid_pxl_timestamp_perv0_sof_addr; + uint32_t csid_pxl_timestamp_perv1_sof_addr; + uint32_t csid_pxl_timestamp_curr0_eof_addr; + uint32_t csid_pxl_timestamp_curr1_eof_addr; + uint32_t csid_pxl_timestamp_perv0_eof_addr; + uint32_t csid_pxl_timestamp_perv1_eof_addr; + uint32_t csid_pxl_err_recovery_cfg0_addr; + uint32_t csid_pxl_err_recovery_cfg1_addr; + uint32_t csid_pxl_err_recovery_cfg2_addr; + uint32_t csid_pxl_multi_vcdt_cfg0_addr; + + /* configuration */ + uint32_t pix_store_en_shift_val; + uint32_t early_eof_en_shift_val; + uint32_t horizontal_bin_en_shift_val; + uint32_t quad_cfa_bin_en_shift_val; + uint32_t ccif_violation_en; + uint32_t overflow_ctrl_en; +}; + +struct cam_ife_csid_rdi_reg_offset { + uint32_t csid_rdi_irq_status_addr; + uint32_t csid_rdi_irq_mask_addr; + uint32_t csid_rdi_irq_clear_addr; + uint32_t csid_rdi_irq_set_addr; + + /*RDI N register address */ + uint32_t csid_rdi_cfg0_addr; + uint32_t csid_rdi_cfg1_addr; + uint32_t csid_rdi_ctrl_addr; + uint32_t csid_rdi_frm_drop_pattern_addr; + uint32_t csid_rdi_frm_drop_period_addr; + uint32_t csid_rdi_irq_subsample_pattern_addr; + uint32_t csid_rdi_irq_subsample_period_addr; + uint32_t csid_rdi_rpp_hcrop_addr; + uint32_t csid_rdi_rpp_vcrop_addr; + uint32_t csid_rdi_rpp_pix_drop_pattern_addr; + uint32_t csid_rdi_rpp_pix_drop_period_addr; + uint32_t csid_rdi_rpp_line_drop_pattern_addr; + uint32_t csid_rdi_rpp_line_drop_period_addr; + uint32_t csid_rdi_yuv_chroma_conversion_addr; + uint32_t csid_rdi_rst_strobes_addr; + uint32_t csid_rdi_status_addr; + uint32_t csid_rdi_misr_val0_addr; + uint32_t csid_rdi_misr_val1_addr; + uint32_t csid_rdi_misr_val2_addr; + uint32_t csid_rdi_misr_val3_addr; + uint32_t csid_rdi_format_measure_cfg0_addr; + uint32_t csid_rdi_format_measure_cfg1_addr; + uint32_t csid_rdi_format_measure0_addr; + uint32_t csid_rdi_format_measure1_addr; + uint32_t csid_rdi_format_measure2_addr; + uint32_t csid_rdi_timestamp_curr0_sof_addr; + uint32_t csid_rdi_timestamp_curr1_sof_addr; + uint32_t csid_rdi_timestamp_prev0_sof_addr; + uint32_t csid_rdi_timestamp_prev1_sof_addr; + uint32_t csid_rdi_timestamp_curr0_eof_addr; + uint32_t csid_rdi_timestamp_curr1_eof_addr; + uint32_t csid_rdi_timestamp_prev0_eof_addr; + uint32_t csid_rdi_timestamp_prev1_eof_addr; + uint32_t csid_rdi_err_recovery_cfg0_addr; + uint32_t csid_rdi_err_recovery_cfg1_addr; + uint32_t csid_rdi_err_recovery_cfg2_addr; + uint32_t csid_rdi_multi_vcdt_cfg0_addr; + uint32_t csid_rdi_byte_cntr_ping_addr; + uint32_t csid_rdi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; + uint32_t ccif_violation_en; + uint32_t overflow_ctrl_en; +}; + +struct cam_ife_csid_udi_reg_offset { + uint32_t csid_udi_irq_status_addr; + uint32_t csid_udi_irq_mask_addr; + uint32_t csid_udi_irq_clear_addr; + uint32_t csid_udi_irq_set_addr; + + /* UDI N register address */ + uint32_t csid_udi_cfg0_addr; + uint32_t csid_udi_cfg1_addr; + uint32_t csid_udi_ctrl_addr; + uint32_t csid_udi_frm_drop_pattern_addr; + uint32_t csid_udi_frm_drop_period_addr; + uint32_t csid_udi_irq_subsample_pattern_addr; + uint32_t csid_udi_irq_subsample_period_addr; + uint32_t csid_udi_rpp_hcrop_addr; + uint32_t csid_udi_rpp_vcrop_addr; + uint32_t csid_udi_rpp_pix_drop_pattern_addr; + uint32_t csid_udi_rpp_pix_drop_period_addr; + uint32_t csid_udi_rpp_line_drop_pattern_addr; + uint32_t csid_udi_rpp_line_drop_period_addr; + uint32_t csid_udi_yuv_chroma_conversion_addr; + uint32_t csid_udi_rst_strobes_addr; + uint32_t csid_udi_status_addr; + uint32_t csid_udi_misr_val0_addr; + uint32_t csid_udi_misr_val1_addr; + uint32_t csid_udi_misr_val2_addr; + uint32_t csid_udi_misr_val3_addr; + uint32_t csid_udi_format_measure_cfg0_addr; + uint32_t csid_udi_format_measure_cfg1_addr; + uint32_t csid_udi_format_measure0_addr; + uint32_t csid_udi_format_measure1_addr; + uint32_t csid_udi_format_measure2_addr; + uint32_t csid_udi_timestamp_curr0_sof_addr; + uint32_t csid_udi_timestamp_curr1_sof_addr; + uint32_t csid_udi_timestamp_prev0_sof_addr; + uint32_t csid_udi_timestamp_prev1_sof_addr; + uint32_t csid_udi_timestamp_curr0_eof_addr; + uint32_t csid_udi_timestamp_curr1_eof_addr; + uint32_t csid_udi_timestamp_prev0_eof_addr; + uint32_t csid_udi_timestamp_prev1_eof_addr; + uint32_t csid_udi_err_recovery_cfg0_addr; + uint32_t csid_udi_err_recovery_cfg1_addr; + uint32_t csid_udi_err_recovery_cfg2_addr; + uint32_t csid_udi_multi_vcdt_cfg0_addr; + uint32_t csid_udi_byte_cntr_ping_addr; + uint32_t csid_udi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; + uint32_t ccif_violation_en; + uint32_t overflow_ctrl_en; +}; + +struct cam_ife_csid_csi2_rx_reg_offset { + uint32_t csid_csi2_rx_irq_status_addr; + uint32_t csid_csi2_rx_irq_mask_addr; + uint32_t csid_csi2_rx_irq_clear_addr; + uint32_t csid_csi2_rx_irq_set_addr; + uint32_t csid_csi2_rx_cfg0_addr; + uint32_t csid_csi2_rx_cfg1_addr; + uint32_t csid_csi2_rx_capture_ctrl_addr; + uint32_t csid_csi2_rx_rst_strobes_addr; + uint32_t csid_csi2_rx_de_scramble_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_cfg1_addr; + uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr; + uint32_t csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr; + uint32_t csid_csi2_rx_captured_short_pkt_0_addr; + uint32_t csid_csi2_rx_captured_short_pkt_1_addr; + uint32_t csid_csi2_rx_captured_long_pkt_0_addr; + uint32_t csid_csi2_rx_captured_long_pkt_1_addr; + uint32_t csid_csi2_rx_captured_long_pkt_ftr_addr; + uint32_t csid_csi2_rx_captured_cphy_pkt_hdr_addr; + uint32_t csid_csi2_rx_lane0_misr_addr; + uint32_t csid_csi2_rx_lane1_misr_addr; + uint32_t csid_csi2_rx_lane2_misr_addr; + uint32_t csid_csi2_rx_lane3_misr_addr; + uint32_t csid_csi2_rx_total_pkts_rcvd_addr; + uint32_t csid_csi2_rx_stats_ecc_addr; + uint32_t csid_csi2_rx_total_crc_err_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg1_addr; + + /*configurations */ + uint32_t csi2_rst_srb_all; + uint32_t csi2_rst_done_shift_val; + uint32_t csi2_irq_mask_all; + uint32_t csi2_misr_enable_shift_val; + uint32_t csi2_vc_mode_shift_val; + uint32_t csi2_capture_long_pkt_en_shift; + uint32_t csi2_capture_short_pkt_en_shift; + uint32_t csi2_capture_cphy_pkt_en_shift; + uint32_t csi2_capture_long_pkt_dt_shift; + uint32_t csi2_capture_long_pkt_vc_shift; + uint32_t csi2_capture_short_pkt_vc_shift; + uint32_t csi2_capture_cphy_pkt_dt_shift; + uint32_t csi2_capture_cphy_pkt_vc_shift; + uint32_t csi2_rx_phy_num_mask; +}; + +struct cam_ife_csid_csi2_tpg_reg_offset { + uint32_t csid_tpg_ctrl_addr; + uint32_t csid_tpg_vc_cfg0_addr; + uint32_t csid_tpg_vc_cfg1_addr; + uint32_t csid_tpg_lfsr_seed_addr; + uint32_t csid_tpg_dt_n_cfg_0_addr; + uint32_t csid_tpg_dt_n_cfg_1_addr; + uint32_t csid_tpg_dt_n_cfg_2_addr; + uint32_t csid_tpg_color_bars_cfg_addr; + uint32_t csid_tpg_color_box_cfg_addr; + uint32_t csid_tpg_common_gen_cfg_addr; + uint32_t csid_tpg_cgen_n_cfg_addr; + uint32_t csid_tpg_cgen_n_x0_addr; + uint32_t csid_tpg_cgen_n_x1_addr; + uint32_t csid_tpg_cgen_n_x2_addr; + uint32_t csid_tpg_cgen_n_xy_addr; + uint32_t csid_tpg_cgen_n_y1_addr; + uint32_t csid_tpg_cgen_n_y2_addr; + + /*configurations */ + uint32_t tpg_dtn_cfg_offset; + uint32_t tpg_cgen_cfg_offset; + uint32_t tpg_cpas_ife_reg_offset; + +}; +struct cam_ife_csid_common_reg_offset { + /* MIPI CSID registers */ + uint32_t csid_hw_version_addr; + uint32_t csid_cfg0_addr; + uint32_t csid_ctrl_addr; + uint32_t csid_reset_addr; + uint32_t csid_rst_strobes_addr; + + uint32_t csid_test_bus_ctrl_addr; + uint32_t csid_top_irq_status_addr; + uint32_t csid_top_irq_mask_addr; + uint32_t csid_top_irq_clear_addr; + uint32_t csid_top_irq_set_addr; + uint32_t csid_irq_cmd_addr; + + /*configurations */ + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; + uint32_t num_udis; + uint32_t num_rdis; + uint32_t num_pix; + uint32_t num_ppp; + uint32_t csid_reg_rst_stb; + uint32_t csid_rst_stb; + uint32_t csid_rst_stb_sw_all; + uint32_t path_rst_stb_all; + uint32_t path_rst_done_shift_val; + uint32_t path_en_shift_val; + uint32_t packing_fmt_shift_val; + uint32_t dt_id_shift_val; + uint32_t vc_shift_val; + uint32_t dt_shift_val; + uint32_t fmt_shift_val; + uint32_t plain_fmt_shit_val; + uint32_t crop_v_en_shift_val; + uint32_t crop_h_en_shift_val; + uint32_t drop_v_en_shift_val; + uint32_t drop_h_en_shift_val; + uint32_t crop_shift; + uint32_t ipp_irq_mask_all; + uint32_t rdi_irq_mask_all; + uint32_t ppp_irq_mask_all; + uint32_t udi_irq_mask_all; + uint32_t measure_en_hbi_vbi_cnt_mask; + uint32_t format_measure_en_val; + uint32_t num_bytes_out_shift_val; +}; + +/** + * struct cam_ife_csid_reg_offset- CSID instance register info + * + * @cmn_reg: csid common registers info + * @ipp_reg: ipp register offset information + * @ppp_reg: ppp register offset information + * @rdi_reg: rdi register offset information + * @udi_reg: udi register offset information + * @tpg_reg: tpg register offset information + * + */ +struct cam_ife_csid_reg_offset { + const struct cam_ife_csid_common_reg_offset *cmn_reg; + const struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + const struct cam_ife_csid_pxl_reg_offset *ipp_reg; + const struct cam_ife_csid_pxl_reg_offset *ppp_reg; + const struct cam_ife_csid_rdi_reg_offset *rdi_reg[CAM_IFE_CSID_RDI_MAX]; + const struct cam_ife_csid_udi_reg_offset *udi_reg[CAM_IFE_CSID_UDI_MAX]; + const struct cam_ife_csid_csi2_tpg_reg_offset *tpg_reg; +}; + + +/** + * struct cam_ife_csid_hw_info- CSID HW info + * + * @csid_reg: csid register offsets + * @hw_dts_version: HW DTS version + * @csid_max_clk: maximim csid clock + * + */ +struct cam_ife_csid_hw_info { + const struct cam_ife_csid_reg_offset *csid_reg; + uint32_t hw_dts_version; + uint32_t csid_max_clk; + +}; + + + +/** + * struct cam_ife_csid_csi2_rx_cfg- csid csi2 rx configuration data + * @phy_sel: input resource type for sensor only + * @lane_type: lane type: c-phy or d-phy + * @lane_num : active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * + */ +struct cam_ife_csid_csi2_rx_cfg { + uint32_t phy_sel; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; +}; + +/** + * struct cam_ife_csid_tpg_cfg- csid tpg configuration data + * @width: width + * @height: height + * @test_pattern : pattern + * @in_format: decode format + * @usage_type: whether dual isp is required + * + */ +struct cam_ife_csid_tpg_cfg { + uint32_t width; + uint32_t height; + uint32_t test_pattern; + uint32_t in_format; + uint32_t usage_type; +}; + +/** + * struct cam_ife_csid_cid_data- cid configuration private data + * + * @vc: Virtual channel + * @dt: Data type + * @cnt: Cid resource reference count. + * @tpg_set: Tpg used for this cid resource + * @is_valid_vc1_dt1: Valid vc1 and dt1 + * + */ +struct cam_ife_csid_cid_data { + uint32_t vc; + uint32_t dt; + uint32_t vc1; + uint32_t dt1; + uint32_t cnt; + uint32_t tpg_set; + uint32_t is_valid_vc1_dt1; +}; + + +/** + * struct cam_ife_csid_path_cfg- csid path configuration details. It is stored + * as private data for IPP/ RDI paths + * @vc : Virtual channel number + * @dt : Data type number + * @cid cid number, it is same as DT_ID number in HW + * @in_format: input decode format + * @out_format: output format + * @crop_enable: crop is enable or disabled, if enabled + * then remaining parameters are valid. + * @drop_enable: flag to indicate pixel drop enable or disable + * @start_pixel: start pixel + * @end_pixel: end_pixel + * @width: width + * @start_line: start line + * @end_line: end_line + * @height: heigth + * @sync_mode: Applicable for IPP/RDI path reservation + * Reserving the path for master IPP or slave IPP + * master (set value 1), Slave ( set value 2) + * for RDI, set mode to none + * @master_idx: For Slave reservation, Give master IFE instance Index. + * Slave will synchronize with master Start and stop operations + * @clk_rate Clock rate + * @num_bytes_out: Number of output bytes per cycle + * + */ +struct cam_ife_csid_path_cfg { + uint32_t vc; + uint32_t dt; + uint32_t vc1; + uint32_t dt1; + uint32_t is_valid_vc1_dt1; + uint32_t cid; + uint32_t in_format; + uint32_t out_format; + bool crop_enable; + bool drop_enable; + uint32_t start_pixel; + uint32_t end_pixel; + uint32_t width; + uint32_t start_line; + uint32_t end_line; + uint32_t height; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t master_idx; + uint64_t clk_rate; + uint32_t horizontal_bin; + uint32_t qcfa_bin; + uint32_t num_bytes_out; +}; + +/** + * struct cam_ife_csid_hw- csid hw device resources data + * + * @hw_intf: contain the csid hw interface information + * @hw_info: csid hw device information + * @csid_info: csid hw specific information + * @res_type: CSID in resource type + * @csi2_rx_cfg: Csi2 rx decoder configuration for csid + * @tpg_cfg: TPG configuration + * @csi2_rx_reserve_cnt: CSI2 reservations count value + * @csi2_cfg_cnt: csi2 configuration count + * @tpg_start_cnt: tpg start count + * @ipp_res: image pixel path resource + * @ppp_res: phase pxl path resource + * @rdi_res: raw dump image path resources + * @udi_res: udi path resources + * @cid_res: cid resources state + * @csid_top_reset_complete: csid top reset completion + * @csid_csi2_reset_complete: csi2 reset completion + * @csid_ipp_reset_complete: ipp reset completion + * @csid_ppp_complete: ppp reset completion + * @csid_rdin_reset_complete: rdi n completion + * @csid_udin_reset_complete: udi n completion + * @csid_debug: csid debug information to enable the SOT, EOT, + * SOF, EOF, measure etc in the csid hw + * @clk_rate Clock rate + * @sof_irq_triggered: Flag is set on receiving event to enable sof irq + * incase of SOF freeze. + * @irq_debug_cnt: Counter to track sof irq's when above flag is set. + * @error_irq_count Error IRQ count, if continuous error irq comes + * need to stop the CSID and mask interrupts. + * @binning_enable Flag is set if hardware supports QCFA binning + * @binning_supported Flag is set if sensor supports QCFA binning + * + * @first_sof_ts first bootime stamp at the start + * @prev_qtimer_ts stores csid timestamp + */ +struct cam_ife_csid_hw { + struct cam_hw_intf *hw_intf; + struct cam_hw_info *hw_info; + struct cam_ife_csid_hw_info *csid_info; + uint32_t res_type; + struct cam_ife_csid_csi2_rx_cfg csi2_rx_cfg; + struct cam_ife_csid_tpg_cfg tpg_cfg; + uint32_t csi2_reserve_cnt; + uint32_t csi2_cfg_cnt; + uint32_t tpg_start_cnt; + struct cam_isp_resource_node ipp_res; + struct cam_isp_resource_node ppp_res; + struct cam_isp_resource_node rdi_res[CAM_IFE_CSID_RDI_MAX]; + struct cam_isp_resource_node udi_res[CAM_IFE_CSID_UDI_MAX]; + struct cam_isp_resource_node cid_res[CAM_IFE_CSID_CID_MAX]; + struct completion csid_top_complete; + struct completion csid_csi2_complete; + struct completion csid_ipp_complete; + struct completion csid_ppp_complete; + struct completion csid_rdin_complete[CAM_IFE_CSID_RDI_MAX]; + struct completion csid_udin_complete[CAM_IFE_CSID_UDI_MAX]; + uint64_t csid_debug; + uint64_t clk_rate; + bool sof_irq_triggered; + uint32_t irq_debug_cnt; + uint32_t error_irq_count; + uint32_t device_enabled; + spinlock_t lock_state; + uint32_t binning_enable; + uint32_t binning_supported; + uint64_t prev_boot_timestamp; + uint64_t prev_qtimer_ts; +}; + +int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx, bool is_custom); + +int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw); + +int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *cid_reserv); + +int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *reserve); + +#endif /* _CAM_IFE_CSID_HW_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..eca0e43a9b5e19dd5b9ad4c8639dff467c5fa5bb --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include "cam_ife_csid_core.h" +#include "cam_ife_csid_dev.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_ife_csid_hw_list[CAM_IFE_CSID_HW_NUM_MAX] = { + 0, 0, 0, 0}; + +static char csid_dev_name[8]; + +int cam_ife_csid_probe(struct platform_device *pdev) +{ + + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + struct cam_ife_csid_hw *csid_dev = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_ife_csid_hw_info *csid_hw_data = NULL; + uint32_t csid_dev_idx; + int rc = 0; + + CAM_DBG(CAM_ISP, "probe called"); + + csid_hw_intf = kzalloc(sizeof(*csid_hw_intf), GFP_KERNEL); + if (!csid_hw_intf) { + rc = -ENOMEM; + goto err; + } + + csid_hw_info = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!csid_hw_info) { + rc = -ENOMEM; + goto free_hw_intf; + } + + csid_dev = kzalloc(sizeof(struct cam_ife_csid_hw), GFP_KERNEL); + if (!csid_dev) { + rc = -ENOMEM; + goto free_hw_info; + } + + /* get ife csid hw index */ + of_property_read_u32(pdev->dev.of_node, "cell-index", &csid_dev_idx); + /* get ife csid hw information */ + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "No matching table for the IFE CSID HW!"); + rc = -EINVAL; + goto free_dev; + } + + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid%1u", csid_dev_idx); + + csid_hw_intf->hw_idx = csid_dev_idx; + csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_IFE_CSID; + csid_hw_intf->hw_priv = csid_hw_info; + + csid_hw_info->core_info = csid_dev; + csid_hw_info->soc_info.pdev = pdev; + csid_hw_info->soc_info.dev = &pdev->dev; + csid_hw_info->soc_info.dev_name = csid_dev_name; + csid_hw_info->soc_info.index = csid_dev_idx; + + csid_hw_data = (struct cam_ife_csid_hw_info *)match_dev->data; + /* need to setup the pdev before call the ife hw probe init */ + csid_dev->csid_info = csid_hw_data; + + rc = cam_ife_csid_hw_probe_init(csid_hw_intf, csid_dev_idx, false); + if (rc) + goto free_dev; + + platform_set_drvdata(pdev, csid_dev); + CAM_DBG(CAM_ISP, "CSID:%d probe successful", + csid_hw_intf->hw_idx); + + + if (csid_hw_intf->hw_idx < CAM_IFE_CSID_HW_NUM_MAX) + cam_ife_csid_hw_list[csid_hw_intf->hw_idx] = csid_hw_intf; + else + goto free_dev; + + return 0; + +free_dev: + kfree(csid_dev); +free_hw_info: + kfree(csid_hw_info); +free_hw_intf: + kfree(csid_hw_intf); +err: + return rc; +} + +int cam_ife_csid_remove(struct platform_device *pdev) +{ + struct cam_ife_csid_hw *csid_dev = NULL; + struct cam_hw_intf *csid_hw_intf; + struct cam_hw_info *csid_hw_info; + + csid_dev = (struct cam_ife_csid_hw *)platform_get_drvdata(pdev); + csid_hw_intf = csid_dev->hw_intf; + csid_hw_info = csid_dev->hw_info; + + CAM_DBG(CAM_ISP, "CSID:%d remove", + csid_dev->hw_intf->hw_idx); + + cam_ife_csid_hw_deinit(csid_dev); + + /*release the csid device memory */ + kfree(csid_dev); + kfree(csid_hw_info); + kfree(csid_hw_intf); + return 0; +} + +int cam_ife_csid_hw_init(struct cam_hw_intf **ife_csid_hw, + uint32_t hw_idx) +{ + int rc = 0; + + if (cam_ife_csid_hw_list[hw_idx]) { + *ife_csid_hw = cam_ife_csid_hw_list[hw_idx]; + } else { + *ife_csid_hw = NULL; + rc = -1; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..1f8e4d05b74b427412b2660be6f498a7d2b5a87d --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_DEV_H_ +#define _CAM_IFE_CSID_DEV_H_ + +#include "cam_isp_hw.h" + +irqreturn_t cam_ife_csid_irq(int irq_num, void *data); + +int cam_ife_csid_probe(struct platform_device *pdev); +int cam_ife_csid_remove(struct platform_device *pdev); + +#endif /*_CAM_IFE_CSID_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c new file mode 100644 index 0000000000000000000000000000000000000000..07d555b170093c041e545bab06dfa13274c02d39 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include "cam_ife_csid_lite17x.h" +#include "cam_ife_csid_lite480.h" +#include "cam_ife_csid_core.h" +#include "cam_ife_csid_dev.h" + +#define CAM_CSID_LITE_DRV_NAME "csid_lite" + +static struct cam_ife_csid_hw_info cam_ife_csid_lite_17x_hw_info = { + .csid_reg = &cam_ife_csid_lite_17x_reg_offset, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid_lite_480_hw_info = { + .csid_reg = &cam_ife_csid_lite_480_reg_offset, +}; + +static const struct of_device_id cam_ife_csid_lite_dt_match[] = { + { + .compatible = "qcom,csid-lite170", + .data = &cam_ife_csid_lite_17x_hw_info, + }, + { + .compatible = "qcom,csid-lite175", + .data = &cam_ife_csid_lite_17x_hw_info, + }, + { + .compatible = "qcom,csid-lite480", + .data = &cam_ife_csid_lite_480_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_ife_csid_lite_dt_match); + +static struct platform_driver cam_ife_csid_lite_driver = { + .probe = cam_ife_csid_probe, + .remove = cam_ife_csid_remove, + .driver = { + .name = CAM_CSID_LITE_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_ife_csid_lite_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ife_csid_lite_init_module(void) +{ + return platform_driver_register(&cam_ife_csid_lite_driver); +} + +static void __exit cam_ife_csid_lite_exit_module(void) +{ + platform_driver_unregister(&cam_ife_csid_lite_driver); +} + +module_init(cam_ife_csid_lite_init_module); +module_exit(cam_ife_csid_lite_exit_module); +MODULE_DESCRIPTION("CAM IFE_CSID_LITE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h new file mode 100644 index 0000000000000000000000000000000000000000..4d8783ce0c0f4d7f2e96a418ebc7fb46942021e0 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_LITE17X_H_ +#define _CAM_IFE_CSID_LITE17X_H_ +#include "cam_ife_csid_core.h" + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_0_reg_offset = { + + .csid_rdi_irq_status_addr = 0x30, + .csid_rdi_irq_mask_addr = 0x34, + .csid_rdi_irq_clear_addr = 0x38, + .csid_rdi_irq_set_addr = 0x3c, + .csid_rdi_cfg0_addr = 0x200, + .csid_rdi_cfg1_addr = 0x204, + .csid_rdi_ctrl_addr = 0x208, + .csid_rdi_frm_drop_pattern_addr = 0x20c, + .csid_rdi_frm_drop_period_addr = 0x210, + .csid_rdi_irq_subsample_pattern_addr = 0x214, + .csid_rdi_irq_subsample_period_addr = 0x218, + .csid_rdi_rpp_hcrop_addr = 0x21c, + .csid_rdi_rpp_vcrop_addr = 0x220, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x224, + .csid_rdi_rpp_pix_drop_period_addr = 0x228, + .csid_rdi_rpp_line_drop_pattern_addr = 0x22c, + .csid_rdi_rpp_line_drop_period_addr = 0x230, + .csid_rdi_rst_strobes_addr = 0x240, + .csid_rdi_status_addr = 0x250, + .csid_rdi_misr_val0_addr = 0x254, + .csid_rdi_misr_val1_addr = 0x258, + .csid_rdi_misr_val2_addr = 0x25c, + .csid_rdi_misr_val3_addr = 0x260, + .csid_rdi_format_measure_cfg0_addr = 0x270, + .csid_rdi_format_measure_cfg1_addr = 0x274, + .csid_rdi_format_measure0_addr = 0x278, + .csid_rdi_format_measure1_addr = 0x27c, + .csid_rdi_format_measure2_addr = 0x280, + .csid_rdi_timestamp_curr0_sof_addr = 0x290, + .csid_rdi_timestamp_curr1_sof_addr = 0x294, + .csid_rdi_timestamp_prev0_sof_addr = 0x298, + .csid_rdi_timestamp_prev1_sof_addr = 0x29c, + .csid_rdi_timestamp_curr0_eof_addr = 0x2a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x2a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x2a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x2ac, + .csid_rdi_byte_cntr_ping_addr = 0x2e0, + .csid_rdi_byte_cntr_pong_addr = 0x2e4, +}; + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_1_reg_offset = { + + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, +}; + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_2_reg_offset = { + + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_yuv_chroma_conversion_addr = 0x434, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, +}; + +static const struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_17x_rdi_3_reg_offset = { + + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, +}; + +static const struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_lite_17x_csi2_reg_offset = { + + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, +}; + + +static const struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_lite_17x_tpg_reg_offset = { + + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /*configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + + +static const struct cam_ife_csid_common_reg_offset + cam_csid_lite_17x_cmn_reg_offset = { + + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 0, + .num_rdis = 4, + .num_pix = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, +}; + +static const struct cam_ife_csid_reg_offset cam_ife_csid_lite_17x_reg_offset = { + .cmn_reg = &cam_csid_lite_17x_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_lite_17x_csi2_reg_offset, + .ipp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_lite_17x_rdi_0_reg_offset, + &cam_ife_csid_lite_17x_rdi_1_reg_offset, + &cam_ife_csid_lite_17x_rdi_2_reg_offset, + &cam_ife_csid_lite_17x_rdi_3_reg_offset, + }, + .tpg_reg = &cam_ife_csid_lite_17x_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_LITE17X_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h new file mode 100644 index 0000000000000000000000000000000000000000..b77f2dfa350e6de73c5f45addc501747497ae6fc --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite480.h @@ -0,0 +1,340 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_LITE_480_H_ +#define _CAM_IFE_CSID_LITE_480_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x30, + .csid_rdi_irq_mask_addr = 0x34, + .csid_rdi_irq_clear_addr = 0x38, + .csid_rdi_irq_set_addr = 0x3c, + .csid_rdi_cfg0_addr = 0x200, + .csid_rdi_cfg1_addr = 0x204, + .csid_rdi_ctrl_addr = 0x208, + .csid_rdi_frm_drop_pattern_addr = 0x20c, + .csid_rdi_frm_drop_period_addr = 0x210, + .csid_rdi_irq_subsample_pattern_addr = 0x214, + .csid_rdi_irq_subsample_period_addr = 0x218, + .csid_rdi_rpp_hcrop_addr = 0x21c, + .csid_rdi_rpp_vcrop_addr = 0x220, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x224, + .csid_rdi_rpp_pix_drop_period_addr = 0x228, + .csid_rdi_rpp_line_drop_pattern_addr = 0x22c, + .csid_rdi_rpp_line_drop_period_addr = 0x230, + .csid_rdi_rst_strobes_addr = 0x240, + .csid_rdi_status_addr = 0x250, + .csid_rdi_misr_val0_addr = 0x254, + .csid_rdi_misr_val1_addr = 0x258, + .csid_rdi_misr_val2_addr = 0x25c, + .csid_rdi_misr_val3_addr = 0x260, + .csid_rdi_format_measure_cfg0_addr = 0x270, + .csid_rdi_format_measure_cfg1_addr = 0x274, + .csid_rdi_format_measure0_addr = 0x278, + .csid_rdi_format_measure1_addr = 0x27c, + .csid_rdi_format_measure2_addr = 0x280, + .csid_rdi_timestamp_curr0_sof_addr = 0x290, + .csid_rdi_timestamp_curr1_sof_addr = 0x294, + .csid_rdi_timestamp_prev0_sof_addr = 0x298, + .csid_rdi_timestamp_prev1_sof_addr = 0x29c, + .csid_rdi_timestamp_curr0_eof_addr = 0x2a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x2a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x2a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x2ac, + .csid_rdi_err_recovery_cfg0_addr = 0x2b0, + .csid_rdi_err_recovery_cfg1_addr = 0x2b4, + .csid_rdi_err_recovery_cfg2_addr = 0x2b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x2bc, + .csid_rdi_byte_cntr_ping_addr = 0x2e0, + .csid_rdi_byte_cntr_pong_addr = 0x2e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_err_recovery_cfg0_addr = 0x3b0, + .csid_rdi_err_recovery_cfg1_addr = 0x3b4, + .csid_rdi_err_recovery_cfg2_addr = 0x3b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x3bc, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_err_recovery_cfg0_addr = 0x4b0, + .csid_rdi_err_recovery_cfg1_addr = 0x4b4, + .csid_rdi_err_recovery_cfg2_addr = 0x4b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x4bc, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_480_rdi_3_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_err_recovery_cfg0_addr = 0x5b0, + .csid_rdi_err_recovery_cfg1_addr = 0x5b4, + .csid_rdi_err_recovery_cfg2_addr = 0x5b8, + .csid_rdi_multi_vcdt_cfg0_addr = 0x5bc, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + /* configurations */ + .ccif_violation_en = 1, + .overflow_ctrl_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_lite_480_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_de_scramble_cfg0_addr = 0x114, + .csid_csi2_rx_de_scramble_cfg1_addr = 0x118, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_lite_480_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_lite_480_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 4, + .minor_version = 8, + .version_incr = 0, + .num_rdis = 4, + .num_pix = 0, + .num_ppp = 0, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .packing_fmt_shift_val = 30, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .drop_v_en_shift_val = 4, + .drop_h_en_shift_val = 3, + .crop_shift = 16, + .ipp_irq_mask_all = 0x7FFF, + .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_lite_480_reg_offset = { + .cmn_reg = &cam_ife_csid_lite_480_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_lite_480_csi2_reg_offset, + .ipp_reg = NULL, + .ppp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_lite_480_rdi_0_reg_offset, + &cam_ife_csid_lite_480_rdi_1_reg_offset, + &cam_ife_csid_lite_480_rdi_2_reg_offset, + &cam_ife_csid_lite_480_rdi_3_reg_offset, + }, + .tpg_reg = &cam_ife_csid_lite_480_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_LITE480_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..7abcc64068eed5df8fe5fcde887aeef0c7f7cc0f --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#include <linux/slab.h> +#include "cam_ife_csid_soc.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static int cam_ife_csid_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = NULL; + struct csid_device_soc_info *csid_soc_info = NULL; + int rc = 0; + + of_node = soc_info->pdev->dev.of_node; + csid_soc_info = (struct csid_device_soc_info *)soc_info->soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + return rc; + + return rc; +} + +static int cam_ife_csid_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, + void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, csid_irq_handler, + irq_data); + if (rc) + return rc; + + return rc; +} + +int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data, bool is_custom) +{ + int rc = 0; + struct cam_cpas_register_params cpas_register_param; + struct cam_csid_soc_private *soc_private; + + soc_private = kzalloc(sizeof(struct cam_csid_soc_private), GFP_KERNEL); + if (!soc_private) + return -ENOMEM; + + soc_info->soc_private = soc_private; + + rc = cam_ife_csid_get_dt_properties(soc_info); + if (rc < 0) + return rc; + + /* Need to see if we want post process the clock list */ + + rc = cam_ife_csid_request_platform_resource(soc_info, csid_irq_handler, + irq_data); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + if (is_custom) + strlcpy(cpas_register_param.identifier, "csid-custom", + CAM_HW_IDENTIFIER_LENGTH); + else + strlcpy(cpas_register_param.identifier, "csid", + CAM_HW_IDENTIFIER_LENGTH); + + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle = cpas_register_param.client_handle; + } + + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_ife_csid_deinit_soc_resources( + struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_ife_csid_enable_soc_resources( + struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + CAM_DBG(CAM_ISP, "csid camnoc_bw:%lld mnoc_ab_bw:%lld mnoc_ib_bw:%lld ", + axi_vote.axi_path[0].camnoc_bw, + axi_vote.axi_path[0].mnoc_ab_bw, + axi_vote.axi_path[0].mnoc_ib_bw); + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS start failed"); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + clk_level, true); + if (rc) { + CAM_ERR(CAM_ISP, "enable platform failed"); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_ife_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_ISP, "Disable platform failed"); + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} + +int cam_ife_csid_enable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + uint32_t cpass_ife_force_clk_offset; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + + soc_private = soc_info->soc_private; + cpass_ife_force_clk_offset = + cpas_ife_base_offset + (0x4 * soc_info->index); + rc = cam_cpas_reg_write(soc_private->cpas_handle, CAM_CPAS_REG_CPASTOP, + cpass_ife_force_clk_offset, 1, 1); + + if (rc) + CAM_ERR(CAM_ISP, "CPASS set IFE:%d Force clock On failed", + soc_info->index); + else + CAM_DBG(CAM_ISP, "CPASS set IFE:%d Force clock On", + soc_info->index); + + return rc; +} + +int cam_ife_csid_disable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + uint32_t cpass_ife_force_clk_offset; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + return -EINVAL; + } + + soc_private = soc_info->soc_private; + cpass_ife_force_clk_offset = + cpas_ife_base_offset + (0x4 * soc_info->index); + rc = cam_cpas_reg_write(soc_private->cpas_handle, CAM_CPAS_REG_CPASTOP, + cpass_ife_force_clk_offset, 1, 0); + + if (rc) + CAM_ERR(CAM_ISP, "CPASS set IFE:%d Force clock Off failed", + soc_info->index); + else + CAM_DBG(CAM_ISP, "CPASS set IFE:%d Force clock off", + soc_info->index); + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..4f76d084fba3050b770dce731cb4b75752c8c084 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IFE_CSID_SOC_H_ +#define _CAM_IFE_CSID_SOC_H_ + +#include "cam_isp_hw.h" + +/* + * struct cam_csid_soc_private: + * + * @Brief: Private SOC data specific to CSID HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + */ +struct cam_csid_soc_private { + uint32_t cpas_handle; +}; + +/** + * struct csid_device_soc_info - CSID SOC info object + * + * @csi_vdd_voltage: csi vdd voltage value + * + */ +struct csid_device_soc_info { + int csi_vdd_voltage; +}; + +/** + * cam_ife_csid_init_soc_resources() + * + * @brief: csid initialization function for the soc info + * + * @soc_info: soc info structure pointer + * @csid_irq_handler: irq handler function to be registered + * @irq_data: irq data for the callback function + * @is_custom: for custom csid hw + * + */ +int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data, bool is_custom); + + +/** + * cam_ife_csid_deinit_soc_resources() + * + * @brief: csid de initialization function for the soc info + * + * @soc_info: soc info structure pointer + * + */ +int cam_ife_csid_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_ife_csid_enable_soc_resources() + * + * @brief: csid soc resource enable function + * + * @soc_info: soc info structure pointer + * @clk_lvl: vote level to start with + * + */ +int cam_ife_csid_enable_soc_resources(struct cam_hw_soc_info *soc_info, + uint32_t clk_lvl); + +/** + * cam_ife_csid_disable_soc_resources() + * + * @brief: csid soc resource disable function + * + * @soc_info: soc info structure pointer + * + */ +int cam_ife_csid_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * cam_ife_csid_enable_ife_force_clock() + * + * @brief: if csid testgen used for dual isp case, before + * starting csid test gen, enable ife force clock on + * through cpas + * + * @soc_info: soc info structure pointer + * @cpas_ife_base_offset: cpas ife force clock base reg offset value + * + */ +int cam_ife_csid_enable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset); + +/** + * cam_ife_csid_disable_ife_force_clock_on() + * + * @brief: disable the IFE force clock on after dual ISP + * CSID test gen stop + * + * @soc_info: soc info structure pointer + * @cpas_ife_base_offset: cpas ife force clock base reg offset value + * + */ +int cam_ife_csid_disable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, + uint32_t cpas_ife_base_offset); + +/** + * cam_ife_csid_get_vote_level() + * + * @brief: get the vote level from clock rate + * + * @soc_info: soc info structure pointer + * @clock_rate clock rate + * + */ +uint32_t cam_ife_csid_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate); + +#endif diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..56ce59636ddaa4956e6954fe15ce583a70a19036 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSID_HW_INTF_H_ +#define _CAM_CSID_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_hw_intf.h" + +/* MAX IFE CSID instance */ +#define CAM_IFE_CSID_HW_NUM_MAX 7 +#define CAM_IFE_CSID_RDI_MAX 4 +#define CAM_IFE_CSID_UDI_MAX 3 + +/** + * enum cam_ife_pix_path_res_id - Specify the csid patch + */ +enum cam_ife_pix_path_res_id { + CAM_IFE_PIX_PATH_RES_RDI_0, + CAM_IFE_PIX_PATH_RES_RDI_1, + CAM_IFE_PIX_PATH_RES_RDI_2, + CAM_IFE_PIX_PATH_RES_RDI_3, + CAM_IFE_PIX_PATH_RES_IPP, + CAM_IFE_PIX_PATH_RES_PPP, + CAM_IFE_PIX_PATH_RES_UDI_0, + CAM_IFE_PIX_PATH_RES_UDI_1, + CAM_IFE_PIX_PATH_RES_UDI_2, + CAM_IFE_PIX_PATH_RES_MAX, +}; + +/** + * enum cam_ife_cid_res_id - Specify the csid cid + */ +enum cam_ife_cid_res_id { + CAM_IFE_CSID_CID_0, + CAM_IFE_CSID_CID_1, + CAM_IFE_CSID_CID_2, + CAM_IFE_CSID_CID_3, + CAM_IFE_CSID_CID_MAX, +}; + +/** + * struct cam_ife_csid_hw_caps- get the CSID hw capability + * @num_rdis: number of rdis supported by CSID HW device + * @num_pix: number of pxl paths supported by CSID HW device + * @num_ppp: number of ppp paths supported by CSID HW device + * @major_version : major version + * @minor_version: minor version + * @version_incr: version increment + * + */ +struct cam_ife_csid_hw_caps { + uint32_t num_rdis; + uint32_t num_pix; + uint32_t num_ppp; + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; +}; + +struct cam_isp_out_port_generic_info { + uint32_t res_type; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t comp_grp_id; + uint32_t split_point; + uint32_t secure_mode; + uint32_t reserved; +}; + +struct cam_isp_in_port_generic_info { + uint32_t major_ver; + uint32_t minor_ver; + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc[CAM_ISP_VC_DT_CFG]; + uint32_t dt[CAM_ISP_VC_DT_CFG]; + uint32_t num_valid_vc_dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t hbi_cnt; + uint32_t cust_node; + uint32_t num_out_res; + uint32_t horizontal_bin; + uint32_t qcfa_bin; + uint32_t num_bytes_out; + struct cam_isp_out_port_generic_info *data; +}; + +/** + * struct cam_csid_hw_reserve_resource- hw reserve + * @res_type : Reource type CID or PATH + * if type is CID, then res_id is not required, + * if type is path then res id need to be filled + * @res_id : Resource id to be reserved + * @in_port : Input port resource info + * @out_port: Output port resource info, used for RDI path only + * @sync_mode: Sync mode + * Sync mode could be master, slave or none + * @master_idx: Master device index to be configured in the slave path + * for master path, this value is not required. + * only slave need to configure the master index value + * @cid: cid (DT_ID) value for path, this is applicable for CSID path + * reserve + * @node_res : Reserved resource structure pointer + * @crop_enable : Flag to indicate CSID crop enable + * @drop_enable : Flag to indicate CSID drop enable + * + */ +struct cam_csid_hw_reserve_resource_args { + enum cam_isp_resource_type res_type; + uint32_t res_id; + struct cam_isp_in_port_generic_info *in_port; + struct cam_isp_out_port_generic_info *out_port; + enum cam_isp_hw_sync_mode sync_mode; + uint32_t master_idx; + uint32_t cid; + struct cam_isp_resource_node *node_res; + bool crop_enable; + bool drop_enable; +}; + +/** + * enum cam_ife_csid_halt_cmd - Specify the halt command type + */ +enum cam_ife_csid_halt_cmd { + CAM_CSID_HALT_AT_FRAME_BOUNDARY, + CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + CAM_CSID_HALT_IMMEDIATELY, + CAM_CSID_HALT_MAX, +}; + +/** + * struct cam_csid_hw_stop- stop all resources + * @stop_cmd : Applicable only for PATH resources + * if stop command set to Halt immediately,driver will stop + * path immediately, manager need to reset the path after HI + * if stop command set to halt at frame boundary, driver will set + * halt at frame boundary and wait for frame boundary + * @node_res : reource pointer array( ie cid or CSID) + * @num_res : number of resources to be stopped + * + */ +struct cam_csid_hw_stop_args { + enum cam_ife_csid_halt_cmd stop_cmd; + struct cam_isp_resource_node **node_res; + uint32_t num_res; +}; + +/** + * enum cam_ife_csid_reset_type - Specify the reset type + */ +enum cam_ife_csid_reset_type { + CAM_IFE_CSID_RESET_GLOBAL, + CAM_IFE_CSID_RESET_PATH, + CAM_IFE_CSID_RESET_MAX, +}; + +/** + * struct cam_ife_csid_reset_cfg- csid reset configuration + * @ reset_type : Global reset or path reset + * @res_node : resource need to be reset + * + */ +struct cam_csid_reset_cfg_args { + enum cam_ife_csid_reset_type reset_type; + struct cam_isp_resource_node *node_res; +}; + +/** + * struct cam_csid_get_time_stamp_args- time stamp capture arguments + * @res_node : resource to get the time stamp + * @time_stamp_val : captured time stamp + * @boot_timestamp : boot time stamp + */ +struct cam_csid_get_time_stamp_args { + struct cam_isp_resource_node *node_res; + uint64_t time_stamp_val; + uint64_t boot_timestamp; +}; + +/** + * enum cam_ife_csid_cmd_type - Specify the csid command + */ +enum cam_ife_csid_cmd_type { + CAM_IFE_CSID_CMD_GET_TIME_STAMP, + CAM_IFE_CSID_SET_CSID_DEBUG, + CAM_IFE_CSID_SOF_IRQ_DEBUG, + CAM_IFE_CSID_CMD_MAX, +}; + +/** + * cam_ife_csid_hw_init() + * + * @brief: Initialize function for the CSID hardware + * + * @ife_csid_hw: CSID hardware instance returned + * @hw_idex: CSID hardware instance id + */ +int cam_ife_csid_hw_init(struct cam_hw_intf **ife_csid_hw, + uint32_t hw_idx); + +/* + * struct cam_ife_csid_clock_update_args: + * + * @clk_rate: Clock rate requested + */ +struct cam_ife_csid_clock_update_args { + uint64_t clk_rate; +}; + +/* + * struct cam_ife_csid_qcfa_update_args: + * + * @qcfa_binning: QCFA binning supported + */ +struct cam_ife_csid_qcfa_update_args { + uint32_t qcfa_binning; +}; + + +#endif /* _CAM_CSID_HW_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..7ac79feb2a9f016473609b14b913cdd5cddcfd38 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -0,0 +1,252 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ISP_HW_H_ +#define _CAM_ISP_HW_H_ + +#include <linux/completion.h> +#include <media/cam_isp.h> +#include "cam_hw.h" +#include "cam_soc_util.h" +#include "cam_irq_controller.h" +#include "cam_hw_intf.h" + +/* + * struct cam_isp_timestamp: + * + * @mono_time: Monotonic boot time + * @vt_time: AV Timer time + * @ticks: Qtimer ticks + */ +struct cam_isp_timestamp { + struct timeval mono_time; + struct timeval vt_time; + uint64_t ticks; +}; + +/* + * cam_isp_hw_get_timestamp() + * + * @Brief: Get timestamp values + * + * @time_stamp: Structure that holds different time values + * + * @Return: Void + */ +void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp); + +enum cam_isp_hw_type { + CAM_ISP_HW_TYPE_CSID = 0, + CAM_ISP_HW_TYPE_ISPIF = 1, + CAM_ISP_HW_TYPE_VFE = 2, + CAM_ISP_HW_TYPE_IFE_CSID = 3, + CAM_ISP_HW_TYPE_MAX = 4, +}; + +enum cam_isp_hw_split_id { + CAM_ISP_HW_SPLIT_LEFT = 0, + CAM_ISP_HW_SPLIT_RIGHT, + CAM_ISP_HW_SPLIT_MAX, +}; + +enum cam_isp_hw_sync_mode { + CAM_ISP_HW_SYNC_NONE, + CAM_ISP_HW_SYNC_MASTER, + CAM_ISP_HW_SYNC_SLAVE, + CAM_ISP_HW_SYNC_MAX, +}; + +enum cam_isp_resource_state { + CAM_ISP_RESOURCE_STATE_UNAVAILABLE = 0, + CAM_ISP_RESOURCE_STATE_AVAILABLE = 1, + CAM_ISP_RESOURCE_STATE_RESERVED = 2, + CAM_ISP_RESOURCE_STATE_INIT_HW = 3, + CAM_ISP_RESOURCE_STATE_STREAMING = 4, +}; + +enum cam_isp_resource_type { + CAM_ISP_RESOURCE_UNINT, + CAM_ISP_RESOURCE_SRC, + CAM_ISP_RESOURCE_CID, + CAM_ISP_RESOURCE_PIX_PATH, + CAM_ISP_RESOURCE_VFE_IN, + CAM_ISP_RESOURCE_VFE_OUT, + CAM_ISP_RESOURCE_VFE_BUS_RD, + CAM_ISP_RESOURCE_MAX, +}; + +enum cam_isp_hw_cmd_type { + CAM_ISP_HW_CMD_GET_CHANGE_BASE, + CAM_ISP_HW_CMD_GET_BUF_UPDATE, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, + CAM_ISP_HW_CMD_GET_REG_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + CAM_ISP_HW_CMD_STRIPE_UPDATE, + CAM_ISP_HW_CMD_CLOCK_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE, + CAM_ISP_HW_CMD_BW_UPDATE_V2, + CAM_ISP_HW_CMD_BW_CONTROL, + CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + CAM_ISP_HW_CMD_UBWC_UPDATE, + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, + CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + CAM_ISP_HW_CMD_UBWC_UPDATE_V2, + CAM_ISP_HW_CMD_CORE_CONFIG, + CAM_ISP_HW_CMD_WM_CONFIG_UPDATE, + CAM_ISP_HW_CMD_CSID_QCFA_SUPPORTED, + CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA, + CAM_ISP_HW_CMD_MAX, +}; + +/* + * struct cam_isp_resource_node: + * + * @Brief: Structure representing HW resource object + * + * @res_type: Resource Type + * @res_id: Unique resource ID within res_type objects + * for a particular HW + * @res_state: State of the resource + * @hw_intf: HW Interface of HW to which this resource + * belongs + * @res_priv: Private data of the resource + * @list: list_head node for this resource + * @cdm_ops: CDM operation functions + * @tasklet_info: Tasklet structure that will be used to + * schedule IRQ events related to this resource + * @irq_handle: handle returned on subscribing for IRQ event + * @rdi_only_ctx: resource belong to rdi only context or not + * @init: function pointer to init the HW resource + * @deinit: function pointer to deinit the HW resource + * @start: function pointer to start the HW resource + * @stop: function pointer to stop the HW resource + * @process_cmd: function pointer for processing commands + * specific to the resource + * @top_half_handler: Top Half handler function + * @bottom_half_handler: Bottom Half handler function + */ +struct cam_isp_resource_node { + enum cam_isp_resource_type res_type; + uint32_t res_id; + enum cam_isp_resource_state res_state; + struct cam_hw_intf *hw_intf; + void *res_priv; + struct list_head list; + void *cdm_ops; + void *tasklet_info; + int irq_handle; + int rdi_only_ctx; + + int (*init)(struct cam_isp_resource_node *rsrc_node, + void *init_args, uint32_t arg_size); + int (*deinit)(struct cam_isp_resource_node *rsrc_node, + void *deinit_args, uint32_t arg_size); + int (*start)(struct cam_isp_resource_node *rsrc_node); + int (*stop)(struct cam_isp_resource_node *rsrc_node); + int (*process_cmd)(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/* + * struct cam_isp_hw_event_info: + * + * @Brief: Structure to pass event details to hw mgr + * + * @res_type: Type of IFE resource + * @res_id: Unique resource ID + * @hw_idx: IFE hw index + * @err_type: Error type if any + * + */ +struct cam_isp_hw_event_info { + enum cam_isp_resource_type res_type; + uint32_t res_id; + uint32_t hw_idx; + uint32_t err_type; +}; + +/* + * struct cam_isp_hw_cmd_buf_update: + * + * @Brief: Contain the new created command buffer information + * + * @cmd_buf_addr: Command buffer to store the change base command + * @size: Size of the buffer in bytes + * @used_bytes: Consumed bytes in the command buffer + * + */ +struct cam_isp_hw_cmd_buf_update { + uint32_t *cmd_buf_addr; + uint32_t size; + uint32_t used_bytes; +}; + +/* + * struct cam_isp_hw_get_wm_update: + * + * @Brief: Get cmd buffer for WM updates. + * + * @ image_buf: image buffer address array + * @ num_buf: Number of buffers in the image_buf array + * @ io_cfg: IO buffer config information sent from UMD + * + */ +struct cam_isp_hw_get_wm_update { + dma_addr_t *image_buf; + uint32_t num_buf; + struct cam_buf_io_cfg *io_cfg; +}; + +/* + * struct cam_isp_hw_get_cmd_update: + * + * @Brief: Get cmd buffer update for different CMD types + * + * @res: Resource node + * @cmd_type: Command type for which to get update + * @cmd: Command buffer information + * + */ +struct cam_isp_hw_get_cmd_update { + struct cam_isp_resource_node *res; + enum cam_isp_hw_cmd_type cmd_type; + struct cam_isp_hw_cmd_buf_update cmd; + union { + void *data; + struct cam_isp_hw_get_wm_update *wm_update; + struct cam_isp_hw_get_wm_update *rm_update; + struct cam_isp_port_hfr_config *hfr_update; + struct cam_isp_clock_config *clock_update; + struct cam_isp_bw_config *bw_update; + struct cam_ubwc_plane_cfg_v1 *ubwc_update; + struct cam_fe_config *fe_update; + struct cam_vfe_generic_ubwc_config *ubwc_config; + struct cam_isp_vfe_wm_config *wm_config; + }; +}; + +/* + * struct cam_isp_hw_dual_isp_update_args: + * + * @Brief: update the dual isp striping configuration. + * + * @ split_id: spilt id to inform left or rifht + * @ res: resource node + * @ dual_cfg: dual isp configuration + * + */ +struct cam_isp_hw_dual_isp_update_args { + enum cam_isp_hw_split_id split_id; + struct cam_isp_resource_node *res; + struct cam_isp_dual_config *dual_cfg; +}; +#endif /* _CAM_ISP_HW_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..a1d1c6a608812e71dee6a8f22593ce77aee0395a --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -0,0 +1,371 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_HW_INTF_H_ +#define _CAM_VFE_HW_INTF_H_ + +#include "cam_isp_hw.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_ife_csid_hw_intf.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_HW_NUM_MAX 7 + +#define VFE_CORE_BASE_IDX 0 +/* + * VBIF and BUS do not exist on same HW. + * Hence both can be 1 below. + */ +#define VFE_VBIF_BASE_IDX 1 +#define VFE_BUS_BASE_IDX 1 + +#define CAM_VFE_MAX_UBWC_PORTS 4 + +enum cam_isp_hw_vfe_in_mux { + CAM_ISP_HW_VFE_IN_CAMIF = 0, + CAM_ISP_HW_VFE_IN_TESTGEN = 1, + CAM_ISP_HW_VFE_IN_RD = 2, + CAM_ISP_HW_VFE_IN_RDI0 = 3, + CAM_ISP_HW_VFE_IN_RDI1 = 4, + CAM_ISP_HW_VFE_IN_RDI2 = 5, + CAM_ISP_HW_VFE_IN_RDI3 = 6, + CAM_ISP_HW_VFE_IN_PDLIB = 7, + CAM_ISP_HW_VFE_IN_LCR = 8, + CAM_ISP_HW_VFE_IN_MAX, +}; + +enum cam_isp_hw_vfe_core { + CAM_ISP_HW_VFE_CORE_0, + CAM_ISP_HW_VFE_CORE_1, + CAM_ISP_HW_VFE_CORE_2, + CAM_ISP_HW_VFE_CORE_3, + CAM_ISP_HW_VFE_CORE_MAX, +}; + +enum cam_vfe_hw_irq_status { + CAM_VFE_IRQ_STATUS_ERR_COMP = -3, + CAM_VFE_IRQ_STATUS_COMP_OWRT = -2, + CAM_VFE_IRQ_STATUS_ERR = -1, + CAM_VFE_IRQ_STATUS_SUCCESS = 0, + CAM_VFE_IRQ_STATUS_OVERFLOW = 1, + CAM_VFE_IRQ_STATUS_P2I_ERROR = 2, + CAM_VFE_IRQ_STATUS_VIOLATION = 3, + CAM_VFE_IRQ_STATUS_MAX, +}; + +enum cam_vfe_hw_irq_regs { + CAM_IFE_IRQ_CAMIF_REG_STATUS0 = 0, + CAM_IFE_IRQ_CAMIF_REG_STATUS1 = 1, + CAM_IFE_IRQ_CAMIF_REG_STATUS2 = 2, + CAM_IFE_IRQ_VIOLATION_STATUS = 3, + CAM_IFE_IRQ_BUS_OVERFLOW_STATUS = 4, + CAM_IFE_IRQ_REGISTERS_MAX, +}; + +enum cam_vfe_bus_irq_regs { + CAM_IFE_IRQ_BUS_REG_STATUS0 = 0, + CAM_IFE_IRQ_BUS_REG_STATUS1 = 1, + CAM_IFE_IRQ_BUS_REG_STATUS2 = 2, + CAM_IFE_IRQ_BUS_REG_COMP_ERR = 3, + CAM_IFE_IRQ_BUS_REG_COMP_OWRT = 4, + CAM_IFE_IRQ_BUS_DUAL_COMP_ERR = 5, + CAM_IFE_IRQ_BUS_DUAL_COMP_OWRT = 6, + CAM_IFE_BUS_IRQ_REGISTERS_MAX, +}; + +enum cam_vfe_bus_ver3_irq_regs { + CAM_IFE_IRQ_BUS_VER3_REG_STATUS0 = 0, + CAM_IFE_IRQ_BUS_VER3_REG_STATUS1 = 1, + CAM_IFE_IRQ_BUS_VER3_REG_MAX, +}; + +enum cam_vfe_reset_type { + CAM_VFE_HW_RESET_HW_AND_REG, + CAM_VFE_HW_RESET_HW, + CAM_VFE_HW_RESET_MAX, +}; + +/* + * struct cam_vfe_hw_get_hw_cap: + * + * @max_width: Max width supported by HW + * @max_height: Max height supported by HW + * @max_pixel_num: Max Pixel channels available + * @max_rdi_num: Max Raw channels available + */ +struct cam_vfe_hw_get_hw_cap { + uint32_t max_width; + uint32_t max_height; + uint32_t max_pixel_num; + uint32_t max_rdi_num; +}; + +/* + * struct cam_vfe_hw_vfe_out_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @out_port_info: Output Port details to acquire + * @unique_id: Unique Identity of Context to associate with this + * resource. Used for composite grouping of multiple + * resources in the same context + * @is_dual: Dual VFE or not + * @split_id: In case of Dual VFE, this is Left or Right. + * (Default is Left if Single VFE) + * @is_master: In case of Dual VFE, this is Master or Slave. + * (Default is Master in case of Single VFE) + * @dual_slave_core: If Master and Slave exists, HW Index of Slave + * @cdm_ops: CDM operations + */ +struct cam_vfe_hw_vfe_out_acquire_args { + struct cam_isp_resource_node *rsrc_node; + struct cam_isp_out_port_generic_info *out_port_info; + uint32_t unique_id; + uint32_t is_dual; + enum cam_isp_hw_split_id split_id; + uint32_t is_master; + uint32_t dual_slave_core; + struct cam_cdm_utils_ops *cdm_ops; +}; + +/* + * struct cam_vfe_hw_vfe_in_acquire_args: + * + * @rsrc_node: Pointer to Resource Node object, filled if acquire + * is successful + * @res_id: Resource ID of resource to acquire if specific, + * else CAM_ISP_HW_VFE_IN_MAX + * @cdm_ops: CDM operations + * @sync_mode: In case of Dual VFE, this is Master or Slave. + * (Default is Master in case of Single VFE) + * @in_port: Input port details to acquire + */ +struct cam_vfe_hw_vfe_in_acquire_args { + struct cam_isp_resource_node *rsrc_node; + uint32_t res_id; + void *cdm_ops; + enum cam_isp_hw_sync_mode sync_mode; + struct cam_isp_in_port_generic_info *in_port; +}; + +/* + * struct cam_vfe_acquire_args: + * + * @rsrc_type: Type of Resource (OUT/IN) to acquire + * @tasklet: Tasklet to associate with this resource. This is + * used to schedule bottom of IRQ events associated + * with this resource. + * @priv: Context data + * @event_cb: Callback function to hw mgr in case of hw events + * @vfe_out: Acquire args for VFE_OUT + * @vfe_bus_rd Acquire args for VFE_BUS_READ + * @vfe_in: Acquire args for VFE_IN + */ +struct cam_vfe_acquire_args { + enum cam_isp_resource_type rsrc_type; + void *tasklet; + void *priv; + cam_hw_mgr_event_cb_func event_cb; + union { + struct cam_vfe_hw_vfe_out_acquire_args vfe_out; + struct cam_vfe_hw_vfe_out_acquire_args vfe_bus_rd; + struct cam_vfe_hw_vfe_in_acquire_args vfe_in; + }; +}; + +/* + * struct cam_vfe_clock_update_args: + * + * @node_res: Resource to get the time stamp + * @clk_rate: Clock rate requested + */ +struct cam_vfe_clock_update_args { + struct cam_isp_resource_node *node_res; + uint64_t clk_rate; +}; + +/* + * struct cam_vfe_core_config_args: + * + * @node_res: Resource to get the time stamp + * @core_config: Core config for IFE + */ +struct cam_vfe_core_config_args { + struct cam_isp_resource_node *node_res; + struct cam_isp_core_config core_config; +}; + +/* + * struct cam_vfe_bw_update_args_v2: + * + * @node_res: Resource to get the BW + * @isp_vote: Vote info according to usage data (left/right/rdi) + */ +struct cam_vfe_bw_update_args_v2 { + struct cam_isp_resource_node *node_res; + struct cam_axi_vote isp_vote; +}; + +/* + * struct cam_vfe_bw_update_args: + * + * @node_res: Resource to get the BW + * @camnoc_bw_bytes: Bandwidth vote request for CAMNOC + * @external_bw_bytes: Bandwidth vote request from CAMNOC + * out to the rest of the path-to-DDR + */ +struct cam_vfe_bw_update_args { + struct cam_isp_resource_node *node_res; + uint64_t camnoc_bw_bytes; + uint64_t external_bw_bytes; +}; + +/* + * struct cam_vfe_fe_update_args: + * + * @node_res: Resource to get fetch configuration + * @fe_config: fetch engine configuration + * + */ +struct cam_vfe_fe_update_args { + struct cam_isp_resource_node *node_res; + struct cam_fe_config fe_config; +}; + +enum cam_vfe_bw_control_action { + CAM_VFE_BW_CONTROL_EXCLUDE = 0, + CAM_VFE_BW_CONTROL_INCLUDE = 1 +}; + +/* + * struct cam_vfe_bw_control_args: + * + * @node_res: Resource to get the time stamp + * @action: Bandwidth control action + */ +struct cam_vfe_bw_control_args { + struct cam_isp_resource_node *node_res; + enum cam_vfe_bw_control_action action; +}; + +/* + * struct cam_vfe_top_irq_evt_payload: + * + * @Brief: This structure is used to save payload for IRQ + * related to VFE_TOP resources + * + * @list: list_head node for the payload + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @ts: Timestamp + */ +struct cam_vfe_top_irq_evt_payload { + struct list_head list; + uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; + struct cam_isp_timestamp ts; +}; + +/* + * struct cam_vfe_bus_irq_evt_payload: + * + * @Brief: This structure is used to save payload for IRQ + * related to VFE_BUS resources + * + * @list: list_head node for the payload + * @core_index: Index of VFE HW that generated this IRQ event + * @debug_status_0: Value of debug status_0 register at time of IRQ + * @evt_id: IRQ event + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @error_type: Identify different errors + * @ts: Timestamp + */ +struct cam_vfe_bus_irq_evt_payload { + struct list_head list; + uint32_t core_index; + uint32_t debug_status_0; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_violation_status; + uint32_t evt_id; + uint32_t irq_reg_val[CAM_IFE_BUS_IRQ_REGISTERS_MAX]; + struct cam_isp_timestamp ts; +}; + +/** + * struct cam_ubwc_generic_plane_config - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config: UBWC mode config + * @static ctrl: UBWC static ctrl + * @ctrl_2: UBWC ctrl 2 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * @stats_ctrl_2: UBWC stats control + * @lossy_threshold0 UBWC lossy threshold 0 + * @lossy_threshold1 UBWC lossy threshold 1 + * @lossy_var_offset UBWC offset variance threshold + * @bandwidth limit UBWC bandwidth limit + */ +struct cam_vfe_generic_ubwc_plane_config { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; + uint32_t static_ctrl; + uint32_t ctrl_2; + uint32_t stats_ctrl_2; + uint32_t lossy_threshold_0; + uint32_t lossy_threshold_1; + uint32_t lossy_var_offset; + uint32_t bandwidth_limit; +}; + +/** + * struct cam_ubwc_generic_config - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @ubwc_plane_config: Array of UBWC configurations per plane + */ +struct cam_vfe_generic_ubwc_config { + uint32_t api_version; + struct cam_vfe_generic_ubwc_plane_config + ubwc_plane_cfg[CAM_PACKET_MAX_PLANES - 1]; +}; + +/* + * cam_vfe_hw_init() + * + * @Brief: Initialize VFE HW device + * + * @vfe_hw: vfe_hw interface to fill in and return on + * successful initialization + * @hw_idx: Index of VFE HW + */ +int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx); + +/* + * cam_vfe_put_evt_payload() + * + * @Brief: Put the evt payload back to free list + * + * @core_info: VFE HW core_info + * @evt_payload: Event payload data + */ +int cam_vfe_put_evt_payload(void *core_info, + struct cam_vfe_top_irq_evt_payload **evt_payload); + +#endif /* _CAM_VFE_HW_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1609a7a048088bc7004d6a441b3144b444a330df --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_soc.o cam_vfe_dev.o cam_vfe_core.o +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_bus/ vfe_top/ vfe17x/ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c new file mode 100644 index 0000000000000000000000000000000000000000..11d6a602117c9d22c1085701bd7fc58bb26427ca --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -0,0 +1,749 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/ratelimit.h> +#include "cam_tasklet_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_core.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_top.h" +#include "cam_ife_hw_mgr.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe"; + +#define CAM_VFE_17X_CLEAR_0_REG_OFFSET 0x00000064 +#define CAM_VFE_17X_CLEAR_1_REG_OFFSET 0x00000068 +#define CAM_VFE_17X_IRQ_CMD_REG_OFFSET 0x00000058 +#define CAM_VFE_17X_TOP_RESET_MASK 0x80000000 + +#define CAM_VFE_48X_CLEAR_0_REG_OFFSET 0x00000048 +#define CAM_VFE_48X_CLEAR_1_REG_OFFSET 0x0000004C +#define CAM_VFE_48X_CLEAR_2_REG_OFFSET 0x00000050 +#define CAM_VFE_48X_IRQ_CMD_REG_OFFSET 0x00000038 +#define CAM_VFE_48X_TOP_RESET_MASK 0x00000001 + +#define CAM_VFE_LITE_48X_CLEAR_0_REG_OFFSET 0x00000034 +#define CAM_VFE_LITE_48X_CLEAR_1_REG_OFFSET 0x00000038 +#define CAM_VFE_LITE_48X_CLEAR_2_REG_OFFSET 0x0000003C +#define CAM_VFE_LITE_48X_IRQ_CMD_REG_OFFSET 0x00000024 +#define CAM_VFE_LITE_48X_TOP_RESET_MASK 0x00020000 + +int cam_vfe_get_hw_caps(void *hw_priv, void *get_hw_cap_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_dev = hw_priv; + struct cam_vfe_hw_core_info *core_info = NULL; + int rc = 0; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_dev->core_info; + + if (core_info->vfe_top->hw_ops.get_hw_caps) + core_info->vfe_top->hw_ops.get_hw_caps( + core_info->vfe_top->top_priv, + get_hw_cap_args, arg_size); + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_vfe_reset_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc = -EINVAL; + struct cam_hw_info *vfe_hw; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + void __iomem *mem_base; + + vfe_hw = th_payload->handler_priv; + soc_info = &vfe_hw->soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + CAM_DBG(CAM_ISP, "Enter"); + + /* + * Clear All IRQs to avoid spurious IRQs immediately + * after Reset Done. + */ + CAM_DBG(CAM_ISP, "TOP_IRQ_STATUS_0 = 0x%x", + th_payload->evt_status_arr[0]); + + mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_480_V100: + if (!soc_private->is_ife_lite) { + if (th_payload->evt_status_arr[0] & 0x1) { + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_48X_CLEAR_0_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_48X_CLEAR_1_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_48X_CLEAR_2_REG_OFFSET); + cam_io_w(0x00000001, mem_base + + CAM_VFE_48X_IRQ_CMD_REG_OFFSET); + CAM_DBG(CAM_ISP, + "Calling Complete for RESET CMD"); + complete(&vfe_hw->hw_complete); + rc = 0; + } + } else { + if (th_payload->evt_status_arr[0] & (1<<17)) { + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_LITE_48X_CLEAR_0_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_LITE_48X_CLEAR_1_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_LITE_48X_CLEAR_2_REG_OFFSET); + cam_io_w(0x00000001, mem_base + + CAM_VFE_LITE_48X_IRQ_CMD_REG_OFFSET); + CAM_DBG(CAM_ISP, + "Calling Complete for RESET CMD"); + complete(&vfe_hw->hw_complete); + rc = 0; + } + } + break; + default: + if (th_payload->evt_status_arr[0] & (1<<31)) { + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_17X_CLEAR_0_REG_OFFSET); + cam_io_w(0xFFFFFFFF, mem_base + + CAM_VFE_17X_CLEAR_1_REG_OFFSET); + cam_io_w(0x00000001, mem_base + + CAM_VFE_17X_IRQ_CMD_REG_OFFSET); + CAM_DBG(CAM_ISP, "Calling Complete for RESET CMD"); + complete(&vfe_hw->hw_complete); + rc = 0; + } + break; + } + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_isp_resource_node *isp_res = NULL; + int rc = 0; + uint32_t reset_core_args = + CAM_VFE_HW_RESET_HW_AND_REG; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + mutex_lock(&vfe_hw->hw_mutex); + vfe_hw->open_count++; + if (vfe_hw->open_count > 1) { + mutex_unlock(&vfe_hw->hw_mutex); + CAM_DBG(CAM_ISP, "VFE has already been initialized cnt %d", + vfe_hw->open_count); + return 0; + } + mutex_unlock(&vfe_hw->hw_mutex); + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + /* Turn ON Regulators, Clocks and other SOC resources */ + rc = cam_vfe_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "Enable SOC failed"); + rc = -EFAULT; + goto decrement_open_cnt; + } + + isp_res = (struct cam_isp_resource_node *)init_hw_args; + if (isp_res && isp_res->init) { + rc = isp_res->init(isp_res, NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "init Failed rc=%d", rc); + goto disable_soc; + } + } + + CAM_DBG(CAM_ISP, "Enable soc done"); + + /* Do HW Reset */ + rc = cam_vfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); + if (rc) { + CAM_ERR(CAM_ISP, "Reset Failed rc=%d", rc); + goto deinint_vfe_res; + } + + rc = core_info->vfe_bus->hw_ops.init(core_info->vfe_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Bus HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + + rc = core_info->vfe_top->hw_ops.init(core_info->vfe_top->top_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Top HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.init( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Bus RD HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + } + + vfe_hw->hw_state = CAM_HW_STATE_POWER_UP; + return rc; + +deinint_vfe_res: + if (isp_res && isp_res->deinit) + isp_res->deinit(isp_res, NULL, 0); +disable_soc: + cam_vfe_disable_soc_resources(soc_info); +decrement_open_cnt: + mutex_lock(&vfe_hw->hw_mutex); + vfe_hw->open_count--; + mutex_unlock(&vfe_hw->hw_mutex); + return rc; +} + +int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_isp_resource_node *isp_res = NULL; + int rc = 0; + uint32_t reset_core_args = + CAM_VFE_HW_RESET_HW_AND_REG; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + isp_res = (struct cam_isp_resource_node *)deinit_hw_args; + if (isp_res && isp_res->deinit) { + rc = isp_res->deinit(isp_res, NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "deinit failed"); + } + + mutex_lock(&vfe_hw->hw_mutex); + if (!vfe_hw->open_count) { + mutex_unlock(&vfe_hw->hw_mutex); + CAM_ERR(CAM_ISP, "Error. Unbalanced deinit"); + return -EFAULT; + } + vfe_hw->open_count--; + if (vfe_hw->open_count) { + mutex_unlock(&vfe_hw->hw_mutex); + CAM_DBG(CAM_ISP, "open_cnt non-zero =%d", vfe_hw->open_count); + return 0; + } + mutex_unlock(&vfe_hw->hw_mutex); + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + rc = core_info->vfe_bus->hw_ops.deinit(core_info->vfe_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.deinit( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + } + + rc = cam_vfe_reset(hw_priv, &reset_core_args, sizeof(uint32_t)); + + /* Turn OFF Regulators, Clocks and other SOC resources */ + CAM_DBG(CAM_ISP, "Disable SOC resource"); + rc = cam_vfe_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_ISP, "Disable SOC failed"); + + vfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +int cam_vfe_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + int rc; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &vfe_hw->soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + memset(top_reset_irq_reg_mask, 0, sizeof(top_reset_irq_reg_mask)); + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_480_V100: + if (!soc_private->is_ife_lite) + top_reset_irq_reg_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + = CAM_VFE_48X_TOP_RESET_MASK; + else + top_reset_irq_reg_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + = CAM_VFE_LITE_48X_TOP_RESET_MASK; + break; + default: + top_reset_irq_reg_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + = CAM_VFE_17X_TOP_RESET_MASK; + break; + } + + core_info->reset_irq_handle = cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_0, + top_reset_irq_reg_mask, vfe_hw, + cam_vfe_reset_irq_top_half, NULL, NULL, NULL); + if (core_info->reset_irq_handle < 1) { + CAM_ERR(CAM_ISP, "subscribe irq controller failed"); + core_info->reset_irq_handle = 0; + return -EFAULT; + } + + reinit_completion(&vfe_hw->hw_complete); + + CAM_DBG(CAM_ISP, "calling RESET on VFE:%d", soc_info->index); + + core_info->vfe_top->hw_ops.reset(core_info->vfe_top->top_priv, + reset_core_args, arg_size); + + /* Wait for Completion or Timeout of 500ms */ + rc = wait_for_completion_timeout(&vfe_hw->hw_complete, 500); + + if (!rc) + CAM_ERR(CAM_ISP, "Reset Timeout"); + else + CAM_DBG(CAM_ISP, "reset complete done (%d)", rc); + + rc = cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, core_info->reset_irq_handle); + if (rc) + CAM_ERR(CAM_ISP, "Error. Unsubscribe failed"); + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + time_stamp->mono_time.tv_sec = ts.tv_sec; + time_stamp->mono_time.tv_usec = ts.tv_nsec/1000; +} + +int cam_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_vfe_acquire_args *acquire; + int rc = -ENODEV; + + if (!hw_priv || !reserve_args || (arg_size != + sizeof(struct cam_vfe_acquire_args))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + acquire = (struct cam_vfe_acquire_args *)reserve_args; + + CAM_DBG(CAM_ISP, "acq res type: %d", acquire->rsrc_type); + mutex_lock(&vfe_hw->hw_mutex); + if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_IN) { + rc = core_info->vfe_top->hw_ops.reserve( + core_info->vfe_top->top_priv, + acquire, sizeof(*acquire)); + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.reserve( + core_info->vfe_bus->bus_priv, acquire, + sizeof(*acquire)); + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.reserve( + core_info->vfe_rd_bus->bus_priv, acquire, + sizeof(*acquire)); + } else + CAM_ERR(CAM_ISP, "Invalid res type:%d", acquire->rsrc_type); + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + +int cam_vfe_release(void *hw_priv, void *release_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + int rc = -ENODEV; + + if (!hw_priv || !release_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *) release_args; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) + rc = core_info->vfe_top->hw_ops.release( + core_info->vfe_top->top_priv, isp_res, + sizeof(*isp_res)); + else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) + rc = core_info->vfe_bus->hw_ops.release( + core_info->vfe_bus->bus_priv, isp_res, + sizeof(*isp_res)); + else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.release( + core_info->vfe_rd_bus->bus_priv, isp_res, + sizeof(*isp_res)); + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + + +int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + struct cam_hw_soc_info *soc_info = NULL; + int rc = 0; + + if (!hw_priv || !start_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *)start_args; + core_info->tasklet_info = isp_res->tasklet_info; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { + rc = core_info->vfe_top->hw_ops.start( + core_info->vfe_top->top_priv, isp_res, + sizeof(struct cam_isp_resource_node)); + + if (rc) + CAM_ERR(CAM_ISP, "Failed to start VFE IN"); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.start(isp_res, NULL, 0); + + if (rc) + CAM_ERR(CAM_ISP, "Failed to start VFE OUT"); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.start(isp_res, + NULL, 0); + + if (rc) + CAM_ERR(CAM_ISP, "Failed to start BUS RD"); + } + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + rc = -EFAULT; + } + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + +int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) +{ + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_isp_resource_node *isp_res; + int rc = -EINVAL; + + if (!hw_priv || !stop_args || + (arg_size != sizeof(struct cam_isp_resource_node))) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + isp_res = (struct cam_isp_resource_node *)stop_args; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { + rc = core_info->vfe_top->hw_ops.stop( + core_info->vfe_top->top_priv, isp_res, + sizeof(struct cam_isp_resource_node)); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.stop(isp_res, + NULL, 0); + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } + + if (core_info->reset_irq_handle > 0) { + cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, + core_info->reset_irq_handle); + core_info->reset_irq_handle = 0; + } + + mutex_unlock(&vfe_hw->hw_mutex); + + return rc; +} + +int cam_vfe_read(void *hw_priv, void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_write(void *hw_priv, void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *vfe_hw = hw_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_vfe_hw_info *hw_info = NULL; + int rc = 0; + + if (!hw_priv) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = &vfe_hw->soc_info; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + hw_info = core_info->vfe_hw_info; + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + case CAM_ISP_HW_CMD_BW_UPDATE: + case CAM_ISP_HW_CMD_BW_CONTROL: + case CAM_ISP_HW_CMD_CORE_CONFIG: + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + case CAM_ISP_HW_CMD_UBWC_UPDATE: + case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: + case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + rc = core_info->vfe_bus->hw_ops.process_cmd( + core_info->vfe_bus->bus_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + break; + + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid cmd type:%d", cmd_type); + rc = -EINVAL; + break; + } + return rc; +} + +irqreturn_t cam_vfe_irq(int irq_num, void *data) +{ + struct cam_hw_info *vfe_hw; + struct cam_vfe_hw_core_info *core_info; + + if (!data) + return IRQ_NONE; + + vfe_hw = (struct cam_hw_info *)data; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + return cam_irq_controller_handle_irq(irq_num, + core_info->vfe_irq_controller); +} + +int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_vfe_hw_info *vfe_hw_info) +{ + int rc = -EINVAL; + struct cam_vfe_soc_private *soc_private = NULL; + + CAM_DBG(CAM_ISP, "Enter"); + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + rc = cam_irq_controller_init(drv_name, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX), + vfe_hw_info->irq_reg_info, &core_info->vfe_irq_controller, + true); + if (rc) { + CAM_ERR(CAM_ISP, + "Error, cam_irq_controller_init failed rc = %d", rc); + return rc; + } + + rc = cam_vfe_top_init(vfe_hw_info->top_version, soc_info, hw_intf, + vfe_hw_info->top_hw_info, core_info->vfe_irq_controller, + &core_info->vfe_top); + if (rc) { + CAM_ERR(CAM_ISP, "Error, cam_vfe_top_init failed rc = %d", rc); + goto deinit_controller; + } + + rc = cam_vfe_bus_init(vfe_hw_info->bus_version, BUS_TYPE_WR, + soc_info, hw_intf, vfe_hw_info->bus_hw_info, + core_info->vfe_irq_controller, &core_info->vfe_bus); + if (rc) { + CAM_ERR(CAM_ISP, "Error, cam_vfe_bus_init failed rc = %d", rc); + goto deinit_top; + } + + /* Read Bus is not valid for vfe-lite */ + if (!soc_private->is_ife_lite) { + rc = cam_vfe_bus_init(vfe_hw_info->bus_rd_version, BUS_TYPE_RD, + soc_info, hw_intf, vfe_hw_info->bus_rd_hw_info, + core_info->vfe_irq_controller, &core_info->vfe_rd_bus); + if (rc) { + CAM_WARN(CAM_ISP, "Error, RD cam_vfe_bus_init failed"); + rc = 0; + } + CAM_DBG(CAM_ISP, "vfe_bus_rd %pK hw_idx %d", + core_info->vfe_rd_bus, hw_intf->hw_idx); + } + + spin_lock_init(&core_info->spin_lock); + + return rc; + +deinit_top: + cam_vfe_top_deinit(vfe_hw_info->top_version, + &core_info->vfe_top); + +deinit_controller: + cam_irq_controller_deinit(&core_info->vfe_irq_controller); + + return rc; +} + +int cam_vfe_core_deinit(struct cam_vfe_hw_core_info *core_info, + struct cam_vfe_hw_info *vfe_hw_info) +{ + int rc = -EINVAL; + unsigned long flags; + + spin_lock_irqsave(&core_info->spin_lock, flags); + + rc = cam_vfe_bus_deinit(vfe_hw_info->bus_version, + &core_info->vfe_bus); + if (rc) + CAM_ERR(CAM_ISP, "Error cam_vfe_bus_deinit failed rc=%d", rc); + + rc = cam_vfe_top_deinit(vfe_hw_info->top_version, + &core_info->vfe_top); + if (rc) + CAM_ERR(CAM_ISP, "Error cam_vfe_top_deinit failed rc=%d", rc); + + rc = cam_irq_controller_deinit(&core_info->vfe_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Error cam_irq_controller_deinit failed rc=%d", rc); + + spin_unlock_irqrestore(&core_info->spin_lock, flags); + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h new file mode 100644 index 0000000000000000000000000000000000000000..43afd0377057e3c66b5547bca2e7541429a29221 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CORE_H_ +#define _CAM_VFE_CORE_H_ + +#include <linux/spinlock.h> +#include "cam_hw_intf.h" +#include "cam_vfe_top.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_hw_intf.h" + +struct cam_vfe_hw_info { + struct cam_irq_controller_reg_info *irq_reg_info; + + uint32_t bus_version; + void *bus_hw_info; + + uint32_t bus_rd_version; + void *bus_rd_hw_info; + + uint32_t top_version; + void *top_hw_info; + uint32_t camif_version; + void *camif_reg; + + uint32_t camif_lite_version; + void *camif_lite_reg; + + uint32_t testgen_version; + void *testgen_reg; + + uint32_t num_qos_settings; + struct cam_isp_reg_val_pair *qos_settings; + + uint32_t num_ds_settings; + struct cam_isp_reg_val_pair *ds_settings; + + uint32_t num_vbif_settings; + struct cam_isp_reg_val_pair *vbif_settings; +}; + +#define CAM_VFE_EVT_MAX 256 + +struct cam_vfe_hw_core_info { + struct cam_vfe_hw_info *vfe_hw_info; + void *vfe_irq_controller; + struct cam_vfe_top *vfe_top; + struct cam_vfe_bus *vfe_bus; + struct cam_vfe_bus *vfe_rd_bus; + void *tasklet_info; + spinlock_t spin_lock; + int reset_irq_handle; +}; + +int cam_vfe_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size); +int cam_vfe_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_vfe_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size); +int cam_vfe_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size); +int cam_vfe_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_vfe_release(void *device_priv, + void *reserve_args, uint32_t arg_size); +int cam_vfe_start(void *device_priv, + void *start_args, uint32_t arg_size); +int cam_vfe_stop(void *device_priv, + void *stop_args, uint32_t arg_size); +int cam_vfe_read(void *device_priv, + void *read_args, uint32_t arg_size); +int cam_vfe_write(void *device_priv, + void *write_args, uint32_t arg_size); +int cam_vfe_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); + +irqreturn_t cam_vfe_irq(int irq_num, void *data); + +int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + struct cam_vfe_hw_info *vfe_hw_info); + +int cam_vfe_core_deinit(struct cam_vfe_hw_core_info *core_info, + struct cam_vfe_hw_info *vfe_hw_info); + +#endif /* _CAM_VFE_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..362d513c6a8f8b5fedbfdc789e3f5837e3475933 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + + +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include "cam_vfe_dev.h" +#include "cam_vfe_core.h" +#include "cam_vfe_soc.h" +#include "cam_debug_util.h" + +static struct cam_hw_intf *cam_vfe_hw_list[CAM_VFE_HW_NUM_MAX] = {0, 0, 0, 0}; + +static char vfe_dev_name[8]; + +int cam_vfe_probe(struct platform_device *pdev) +{ + struct cam_hw_info *vfe_hw = NULL; + struct cam_hw_intf *vfe_hw_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + struct cam_vfe_hw_info *hw_info = NULL; + int rc = 0; + + vfe_hw_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!vfe_hw_intf) { + rc = -ENOMEM; + goto end; + } + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &vfe_hw_intf->hw_idx); + + vfe_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!vfe_hw) { + rc = -ENOMEM; + goto free_vfe_hw_intf; + } + + memset(vfe_dev_name, 0, sizeof(vfe_dev_name)); + snprintf(vfe_dev_name, sizeof(vfe_dev_name), + "vfe%1u", vfe_hw_intf->hw_idx); + + vfe_hw->soc_info.pdev = pdev; + vfe_hw->soc_info.dev = &pdev->dev; + vfe_hw->soc_info.dev_name = vfe_dev_name; + vfe_hw_intf->hw_priv = vfe_hw; + vfe_hw_intf->hw_ops.get_hw_caps = cam_vfe_get_hw_caps; + vfe_hw_intf->hw_ops.init = cam_vfe_init_hw; + vfe_hw_intf->hw_ops.deinit = cam_vfe_deinit_hw; + vfe_hw_intf->hw_ops.reset = cam_vfe_reset; + vfe_hw_intf->hw_ops.reserve = cam_vfe_reserve; + vfe_hw_intf->hw_ops.release = cam_vfe_release; + vfe_hw_intf->hw_ops.start = cam_vfe_start; + vfe_hw_intf->hw_ops.stop = cam_vfe_stop; + vfe_hw_intf->hw_ops.read = cam_vfe_read; + vfe_hw_intf->hw_ops.write = cam_vfe_write; + vfe_hw_intf->hw_ops.process_cmd = cam_vfe_process_cmd; + vfe_hw_intf->hw_type = CAM_ISP_HW_TYPE_VFE; + + CAM_DBG(CAM_ISP, "type %d index %d", + vfe_hw_intf->hw_type, vfe_hw_intf->hw_idx); + + platform_set_drvdata(pdev, vfe_hw_intf); + + vfe_hw->core_info = kzalloc(sizeof(struct cam_vfe_hw_core_info), + GFP_KERNEL); + if (!vfe_hw->core_info) { + CAM_DBG(CAM_ISP, "Failed to alloc for core"); + rc = -ENOMEM; + goto free_vfe_hw; + } + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_ISP, "Of_match Failed"); + rc = -EINVAL; + goto free_core_info; + } + hw_info = (struct cam_vfe_hw_info *)match_dev->data; + core_info->vfe_hw_info = hw_info; + + rc = cam_vfe_init_soc_resources(&vfe_hw->soc_info, cam_vfe_irq, + vfe_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed to init soc rc=%d", rc); + goto free_core_info; + } + + rc = cam_vfe_core_init(core_info, &vfe_hw->soc_info, + vfe_hw_intf, hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Failed to init core rc=%d", rc); + goto deinit_soc; + } + + vfe_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&vfe_hw->hw_mutex); + spin_lock_init(&vfe_hw->hw_lock); + init_completion(&vfe_hw->hw_complete); + + if (vfe_hw_intf->hw_idx < CAM_VFE_HW_NUM_MAX) + cam_vfe_hw_list[vfe_hw_intf->hw_idx] = vfe_hw_intf; + + cam_vfe_init_hw(vfe_hw, NULL, 0); + cam_vfe_deinit_hw(vfe_hw, NULL, 0); + + CAM_DBG(CAM_ISP, "VFE%d probe successful", vfe_hw_intf->hw_idx); + + return rc; + +deinit_soc: + if (cam_vfe_deinit_soc_resources(&vfe_hw->soc_info)) + CAM_ERR(CAM_ISP, "Failed to deinit soc"); +free_core_info: + kfree(vfe_hw->core_info); +free_vfe_hw: + kfree(vfe_hw); +free_vfe_hw_intf: + kfree(vfe_hw_intf); +end: + return rc; +} + +int cam_vfe_remove(struct platform_device *pdev) +{ + struct cam_hw_info *vfe_hw = NULL; + struct cam_hw_intf *vfe_hw_intf = NULL; + struct cam_vfe_hw_core_info *core_info = NULL; + int rc = 0; + + vfe_hw_intf = platform_get_drvdata(pdev); + if (!vfe_hw_intf) { + CAM_ERR(CAM_ISP, "Error! No data in pdev"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "type %d index %d", + vfe_hw_intf->hw_type, vfe_hw_intf->hw_idx); + + if (vfe_hw_intf->hw_idx < CAM_VFE_HW_NUM_MAX) + cam_vfe_hw_list[vfe_hw_intf->hw_idx] = NULL; + + vfe_hw = vfe_hw_intf->hw_priv; + if (!vfe_hw) { + CAM_ERR(CAM_ISP, "Error! HW data is NULL"); + rc = -ENODEV; + goto free_vfe_hw_intf; + } + + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + if (!core_info) { + CAM_ERR(CAM_ISP, "Error! core data NULL"); + rc = -EINVAL; + goto deinit_soc; + } + + rc = cam_vfe_core_deinit(core_info, core_info->vfe_hw_info); + if (rc < 0) + CAM_ERR(CAM_ISP, "Failed to deinit core rc=%d", rc); + + kfree(vfe_hw->core_info); + +deinit_soc: + rc = cam_vfe_deinit_soc_resources(&vfe_hw->soc_info); + if (rc < 0) + CAM_ERR(CAM_ISP, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&vfe_hw->hw_mutex); + kfree(vfe_hw); + + CAM_DBG(CAM_ISP, "VFE%d remove successful", vfe_hw_intf->hw_idx); + +free_vfe_hw_intf: + kfree(vfe_hw_intf); + + return rc; +} + +int cam_vfe_hw_init(struct cam_hw_intf **vfe_hw, uint32_t hw_idx) +{ + int rc = 0; + + if (cam_vfe_hw_list[hw_idx]) { + *vfe_hw = cam_vfe_hw_list[hw_idx]; + rc = 0; + } else { + *vfe_hw = NULL; + rc = -ENODEV; + } + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..c2d78b69c684947a3881314c938a3659a509c94c --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_DEV_H_ +#define _CAM_VFE_DEV_H_ + +#include <linux/platform_device.h> + +/* + * cam_vfe_probe() + * + * @brief: Driver probe function called on Boot + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_probe(struct platform_device *pdev); + +/* + * cam_vfe_remove() + * + * @brief: Driver remove function + * + * @pdev: Platform Device pointer + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_remove(struct platform_device *pdev); + +#endif /* _CAM_VFE_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..77e2a059af57edc54d5921d40d4c65a759ac6666 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include "cam_cpas_api.h" +#include "cam_vfe_soc.h" +#include "cam_debug_util.h" + +static bool cam_vfe_cpas_cb(uint32_t client_handle, void *userdata, + struct cam_cpas_irq_data *irq_data) +{ + bool error_handled = false; + + if (!irq_data) + return error_handled; + + switch (irq_data->irq_type) { + case CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR: + CAM_ERR_RATE_LIMIT(CAM_ISP, + "IFE UBWC Encode error type=%d status=%x", + irq_data->irq_type, + irq_data->u.enc_err.encerr_status.value); + error_handled = true; + break; + default: + break; + } + + return error_handled; +} + +static int cam_vfe_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + int rc = 0, num_ubwc_cfg = 0, i = 0; + struct device_node *of_node = NULL; + struct platform_device *pdev = NULL; + struct cam_vfe_soc_private *vfe_soc_private; + + pdev = soc_info->pdev; + of_node = pdev->dev.of_node; + vfe_soc_private = soc_info->soc_private; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "Error! get DT properties failed rc=%d", rc); + return rc; + } + + vfe_soc_private->is_ife_lite = false; + if (strnstr(soc_info->compatible, "lite", + strlen(soc_info->compatible)) != NULL) { + vfe_soc_private->is_ife_lite = true; + goto end; + } + + switch (soc_info->hw_version) { + case CAM_CPAS_TITAN_480_V100: + num_ubwc_cfg = of_property_count_u32_elems(of_node, + "ubwc-static-cfg"); + + if (num_ubwc_cfg < 0 || num_ubwc_cfg > UBWC_STATIC_CONFIG_MAX) { + CAM_ERR(CAM_ISP, "wrong num_ubwc_cfg: %d", + num_ubwc_cfg); + rc = num_ubwc_cfg; + goto end; + } + + for (i = 0; i < num_ubwc_cfg; i++) { + rc = of_property_read_u32_index(of_node, + "ubwc-static-cfg", i, + &vfe_soc_private->ubwc_static_ctrl[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "unable to read ubwc static config"); + break; + } + } + break; + default: + break; + } + +end: + return rc; +} + +static int cam_vfe_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data) +{ + int rc = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, vfe_irq_handler, + irq_data); + if (rc) + CAM_ERR(CAM_ISP, + "Error! Request platform resource failed rc=%d", rc); + + return rc; +} + +static int cam_vfe_release_platform_resource(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_ISP, + "Error! Release platform resource failed rc=%d", rc); + + return rc; +} + +int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + + soc_private = kzalloc(sizeof(struct cam_vfe_soc_private), + GFP_KERNEL); + if (!soc_private) { + CAM_DBG(CAM_ISP, "Error! soc_private Alloc Failed"); + return -ENOMEM; + } + soc_info->soc_private = soc_private; + + rc = cam_cpas_get_cpas_hw_version(&soc_private->cpas_version); + if (rc) { + CAM_ERR(CAM_ISP, "Error! Invalid cpas version rc=%d", rc); + goto free_soc_private; + } + soc_info->hw_version = soc_private->cpas_version; + + rc = cam_vfe_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Error! Get DT properties failed rc=%d", rc); + goto free_soc_private; + } + + rc = cam_soc_util_get_option_clk_by_name(soc_info, + CAM_VFE_DSP_CLK_NAME, &soc_private->dsp_clk, + &soc_private->dsp_clk_index, &soc_private->dsp_clk_rate); + if (rc) + CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc); + + rc = cam_vfe_request_platform_resource(soc_info, vfe_irq_handler, + irq_data); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "Error! Request platform resources failed rc=%d", rc); + goto free_soc_private; + } + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, "ife", + CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = soc_info->dev; + cpas_register_param.cam_cpas_client_cb = cam_vfe_cpas_cb; + cpas_register_param.userdata = soc_info; + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "CPAS registration failed rc=%d", rc); + goto release_soc; + } else { + soc_private->cpas_handle = cpas_register_param.client_handle; + } + return rc; + +release_soc: + cam_soc_util_release_platform_resource(soc_info); +free_soc_private: + kfree(soc_private); + + return rc; +} + +int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! soc_info NULL"); + return -ENODEV; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + + rc = cam_vfe_release_platform_resource(soc_info); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Error! Release platform resources failed rc=%d", rc); + + rc = cam_soc_util_clk_put(&soc_private->dsp_clk); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Error Put dsp clk failed rc=%d", rc); + + kfree(soc_private); + + return rc; +} + +int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid params"); + rc = -EINVAL; + goto end; + } + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + if (strnstr(soc_info->compatible, "lite", + strlen(soc_info->compatible))) { + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI1; + } else { + axi_vote.axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + } + + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = 10640000000L; + axi_vote.axi_path[0].mnoc_ab_bw = 10640000000L; + axi_vote.axi_path[0].mnoc_ib_bw = 10640000000L; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS start failed rc=%d", rc); + rc = -EFAULT; + goto end; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_TURBO_VOTE, true); + if (rc) { + CAM_ERR(CAM_ISP, "Error! enable platform failed rc=%d", rc); + goto stop_cpas; + } + + return rc; + +stop_cpas: + cam_cpas_stop(soc_private->cpas_handle); +end: + return rc; +} + +int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + if (strcmp(clk_name, CAM_VFE_DSP_CLK_NAME) == 0) { + rc = cam_soc_util_clk_enable(soc_private->dsp_clk, + CAM_VFE_DSP_CLK_NAME, soc_private->dsp_clk_rate); + if (rc) + CAM_ERR(CAM_ISP, + "Error enable dsp clk failed rc=%d", rc); + } + + return rc; +} + +int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + if (strcmp(clk_name, CAM_VFE_DSP_CLK_NAME) == 0) { + rc = cam_soc_util_clk_disable(soc_private->dsp_clk, + CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, + "Error enable dsp clk failed rc=%d", rc); + } + + return rc; +} + + +int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_vfe_soc_private *soc_private; + + if (!soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid params"); + rc = -EINVAL; + return rc; + } + soc_private = soc_info->soc_private; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_ISP, "Disable platform failed rc=%d", rc); + return rc; + } + + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc); + return rc; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..64d9de084ec1e6b91a5385ed4590200ad2d049b9 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_SOC_H_ +#define _CAM_VFE_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_isp_hw.h" + +#define CAM_VFE_DSP_CLK_NAME "ife_dsp_clk" + +#define UBWC_STATIC_CONFIG_MAX 2 + +/* + * struct cam_vfe_soc_private: + * + * @Brief: Private SOC data specific to VFE HW Driver + * + * @cpas_handle: Handle returned on registering with CPAS driver. + * This handle is used for all further interface + * with CPAS. + * @cpas_version: Has cpas version read from Hardware + * @ubwc_static_ctrl: UBWC static control configuration + * @is_ife_lite: Flag to indicate full vs lite IFE + */ +struct cam_vfe_soc_private { + uint32_t cpas_handle; + uint32_t cpas_version; + struct clk *dsp_clk; + int32_t dsp_clk_index; + int32_t dsp_clk_rate; + uint32_t ubwc_static_ctrl[UBWC_STATIC_CONFIG_MAX]; + bool is_ife_lite; +}; + +/* + * cam_vfe_init_soc_resources() + * + * @Brief: Initialize SOC resources including private data + * + * @soc_info: Device soc information + * @handler: Irq handler function pointer + * @irq_data: Irq handler function Callback data + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data); + +/* + * cam_vfe_deinit_soc_resources() + * + * @Brief: Deinitialize SOC resources including private data + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_vfe_enable_soc_resources() + * + * @brief: Enable regulator, irq resources, start CPAS + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_vfe_disable_soc_resources() + * + * @brief: Disable regulator, irq resources, stop CPAS + * + * @soc_info: Device soc information + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +/* + * cam_vfe_soc_enable_clk() + * + * @brief: Enable clock with given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_soc_enable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +/* + * cam_vfe_soc_disable_dsp_clk() + * + * @brief: Disable clock with given name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to enable + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_soc_disable_clk(struct cam_hw_soc_info *soc_info, + const char *clk_name); + +#endif /* _CAM_VFE_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e129ea6999b0713878e3e03988de7ccc8a331211 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe.o diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c new file mode 100644 index 0000000000000000000000000000000000000000..5336352a479780d93b5e90c69d38966c5827b532 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include "cam_vfe170.h" +#include "cam_vfe175.h" +#include "cam_vfe175_130.h" +#include "cam_vfe480.h" +#include "cam_vfe_lite17x.h" +#include "cam_vfe_lite48x.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_core.h" +#include "cam_vfe_dev.h" + +static const struct of_device_id cam_vfe_dt_match[] = { + { + .compatible = "qcom,vfe170", + .data = &cam_vfe170_hw_info, + }, + { + .compatible = "qcom,vfe175", + .data = &cam_vfe175_hw_info, + }, + { + .compatible = "qcom,vfe175_130", + .data = &cam_vfe175_130_hw_info, + }, + { + .compatible = "qcom,vfe480", + .data = &cam_vfe480_hw_info, + }, + { + .compatible = "qcom,vfe-lite170", + .data = &cam_vfe_lite17x_hw_info, + }, + { + .compatible = "qcom,vfe-lite175", + .data = &cam_vfe_lite17x_hw_info, + }, + { + .compatible = "qcom,vfe-lite480", + .data = &cam_vfe_lite48x_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_vfe_dt_match); + +static struct platform_driver cam_vfe_driver = { + .probe = cam_vfe_probe, + .remove = cam_vfe_remove, + .driver = { + .name = "cam_vfe", + .owner = THIS_MODULE, + .of_match_table = cam_vfe_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_vfe_init_module(void) +{ + return platform_driver_register(&cam_vfe_driver); +} + +static void __exit cam_vfe_exit_module(void) +{ + platform_driver_unregister(&cam_vfe_driver); +} + +module_init(cam_vfe_init_module); +module_exit(cam_vfe_exit_module); +MODULE_DESCRIPTION("CAM VFE driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h new file mode 100644 index 0000000000000000000000000000000000000000..663bc247b27fac5cb19900404cd84e69f72b2850 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h @@ -0,0 +1,844 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE170_H_ +#define _CAM_VFE170_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe170_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe170_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0x0FFF7E80, + .enable_diagnostic_hw = 0x1, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_170_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_170_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_170_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_170_reg, + &stats_170_reg, + &color_170_reg, + &zoom_170_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe170_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_170_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { + .common_reg = &vfe170_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe170_top_common_reg, + .camif_reg = &vfe170_camif_reg, + .reg_data = &vfe_170_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = NULL, + .camif_lite_reg = NULL, + .reg_data = NULL, + }, + .rdi_hw_info = { + .common_reg = &vfe170_top_common_reg, + .rdi_reg = &vfe170_rdi_reg, + .reg_data = { + &vfe_170_rdi_0_data, + &vfe_170_rdi_1_data, + &vfe_170_rdi_2_data, + NULL, + }, + }, + .num_mux = 4, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_client ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe170_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 20, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = &ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = &ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 18, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe170_hw_info = { + .irq_reg_info = &vfe170_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe170_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe170_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe170_camif_reg, + + .camif_lite_version = 0, + .camif_reg = NULL, + +}; + +#endif /* _CAM_VFE170_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h new file mode 100644 index 0000000000000000000000000000000000000000..6823b6386b911dceca852fb3d6ad75b7dff1e3f3 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h @@ -0,0 +1,1014 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE175_H_ +#define _CAM_VFE175_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_175_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .subscribe_irq_mask0 = 0x00000017, + .subscribe_irq_mask1 = 0x00000000, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_camif_lite_ver2_reg vfe175_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data vfe175_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_err_irq_mask0 = 0x00400000, + .lite_err_irq_mask1 = 0x00004100, + .lite_subscribe_irq_mask0 = 0x001C0000, + .lite_subscribe_irq_mask1 = 0x0, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_reg, + &stats_175_reg, + &color_175_reg, + &zoom_175_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_common_reg_data vfe175_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_reg = &vfe175_camif_reg, + .reg_data = &vfe_175_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_lite_reg = &vfe175_camif_lite_reg, + .reg_data = &vfe175_camif_lite_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_top_common_reg, + .rdi_reg = &vfe175_rdi_reg, + .common_reg_data = &vfe175_rdi_reg_data, + .reg_data = { + &vfe_175_rdi_0_data, + &vfe_175_rdi_1_data, + &vfe_175_rdi_2_data, + NULL, + }, + }, + .num_mux = 5, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, + }, +}; + +static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = &vfe175_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = &vfe175_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = &vfe175_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = &vfe175_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 22, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe175_hw_info = { + .irq_reg_info = &vfe175_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_camif_lite_reg, + +}; + +#endif /* _CAM_VFE175_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h new file mode 100644 index 0000000000000000000000000000000000000000..8acd77d1f1e21a1cfafd6ee41b74bfb7e11fc8c9 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -0,0 +1,1122 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE175_130_H_ +#define _CAM_VFE175_130_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_130_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_130_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_175_130_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .subscribe_irq_mask0 = 0x00000017, + .subscribe_irq_mask1 = 0x00000000, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_fe_ver1_reg vfe175_130_fe_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, + .fe_cfg = 0x00000084, +}; + +static struct cam_vfe_fe_reg_data vfe_175_130_fe_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .enable_diagnostic_hw = 0x1, + .fe_mux_data = 0x2, + .hbi_cnt_shift = 0x8, +}; + +static struct cam_vfe_camif_lite_ver2_reg vfe175_130_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data + vfe175_130_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_err_irq_mask0 = 0x00400000, + .lite_err_irq_mask1 = 0x00004100, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_130_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_130_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_130_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_130_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_130_reg, + &stats_175_130_reg, + &color_175_130_reg, + &zoom_175_130_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_130_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_common_reg_data vfe175_130_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_reg = &vfe175_130_camif_reg, + .reg_data = &vfe_175_130_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + .reg_data = &vfe175_130_camif_lite_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .rdi_reg = &vfe175_130_rdi_reg, + .common_reg_data = &vfe175_130_rdi_reg_data, + .reg_data = { + &vfe_175_130_rdi_0_data, + &vfe_175_130_rdi_1_data, + &vfe_175_130_rdi_2_data, + NULL, + }, + }, + .fe_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .fe_reg = &vfe175_130_fe_reg, + .reg_data = &vfe_175_130_fe_reg_data, + }, + .num_mux = 6, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, + CAM_VFE_IN_RD_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = { + { + .mask_reg_offset = 0x00005010, + .clear_reg_offset = 0x00005014, + .status_reg_offset = 0x0000501C, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, +}; + +static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x00005000, + .hw_capability = 0x00005004, + .sw_reset = 0x00005008, + .cgc_ovd = 0x0000500C, + .pwr_iso_cfg = 0x000050CC, + .input_if_cmd = 0x00005020, + .test_bus_ctrl = 0x00005048, + .irq_reg_info = { + .num_registers = 1, + .irq_reg_set = vfe175_130_bus_rd_irq_reg, + .global_clear_offset = 0x00005018, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 1, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x00005050, + .image_addr = 0x00005058, + .buf_size = 0x0000505C, + .stride = 0x00005060, + .unpacker_cfg = 0x00005064, + .latency_buf_allocation = 0x00005078, + .burst_limit = 0x00005080, + }, + }, + .num_bus_rd_resc = 1, + .vfe_bus_rd_hw_info = { + { + .vfe_bus_rd_type = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_130_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + .debug_status_cfg = 0x0000226C, + .debug_status_0 = 0x00002270, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 22, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe175_130_hw_info = { + .irq_reg_info = &vfe175_130_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_130_bus_hw_info, + + .bus_rd_version = CAM_VFE_BUS_RD_VER_1_0, + .bus_rd_hw_info = &vfe175_130_bus_rd_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_130_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_130_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + +}; + +#endif /* _CAM_VFE175_130_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h new file mode 100644 index 0000000000000000000000000000000000000000..ae65df7c1126599fccdd70ac4cf37b91a44dc422 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe480.h @@ -0,0 +1,1377 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_VFE480_H_ +#define _CAM_VFE480_H_ +#include "cam_vfe_camif_ver3.h" +#include "cam_vfe_top_ver3.h" +#include "cam_vfe_core.h" +#include "cam_vfe_bus_ver3.h" +#include "cam_irq_controller.h" + +static struct cam_irq_register_set vfe480_top_irq_reg_set[3] = { + { + .mask_reg_offset = 0x0000003C, + .clear_reg_offset = 0x00000048, + .status_reg_offset = 0x00000054, + }, + { + .mask_reg_offset = 0x00000040, + .clear_reg_offset = 0x0000004C, + .status_reg_offset = 0x00000058, + }, + { + .mask_reg_offset = 0x00000044, + .clear_reg_offset = 0x00000050, + .status_reg_offset = 0x0000005C, + }, +}; + +static struct cam_irq_controller_reg_info vfe480_top_irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe480_top_irq_reg_set, + .global_clear_offset = 0x00000038, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver3_pp_clc_reg vfe480_camif_reg = { + .hw_version = 0x00002600, + .hw_status = 0x00002604, + .module_cfg = 0x00002660, + .pdaf_raw_crop_width_cfg = 0x00002668, + .pdaf_raw_crop_height_cfg = 0x0000266C, + .line_skip_pattern = 0x00002670, + .pixel_skip_pattern = 0x00002674, + .period_cfg = 0x00002678, + .irq_subsample_pattern = 0x0000267C, + .epoch_irq_cfg = 0x00002680, + .debug_1 = 0x000027F0, + .debug_0 = 0x000027F4, + .test_bus_ctrl = 0x000027F8, + .spare = 0x000027FC, + .reg_update_cmd = 0x00000034, +}; + +static struct cam_vfe_camif_ver3_reg_data vfe_480_camif_reg_data = { + .pp_extern_reg_update_shift = 4, + .dual_pd_extern_reg_update_shift = 17, + .extern_reg_update_mask = 1, + .dual_ife_pix_en_shift = 3, + .operating_mode_shift = 11, + .input_mux_sel_shift = 5, + .pixel_pattern_shift = 24, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 24, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 23, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x41, + .epoch_line_cfg = 0x00000014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .epoch1_irq_mask = 0x00000008, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x82000200, + .error_irq_mask2 = 0x30301F80, + .subscribe_irq_mask1 = 0x00000007, + .enable_diagnostic_hw = 0x1, + .pp_camif_cfg_en_shift = 0, + .pp_camif_cfg_ife_out_en_shift = 8, + .top_debug_cfg_en = 1, +}; + +static struct cam_vfe_top_ver3_reg_offset_common vfe480_top_common_reg = { + .hw_version = 0x00000000, + .titan_version = 0x00000004, + .hw_capability = 0x00000008, + .lens_feature = 0x0000000C, + .stats_feature = 0x00000010, + .color_feature = 0x00000014, + .zoom_feature = 0x00000018, + .global_reset_cmd = 0x0000001C, + .core_cfg_0 = 0x0000002C, + .core_cfg_1 = 0x00000030, + .reg_update_cmd = 0x00000034, + .violation_status = 0x00000074, + .core_cgc_ovd_0 = 0x00000020, + .core_cgc_ovd_1 = 0x00000094, + .ahb_cgc_ovd = 0x00000024, + .noc_cgc_ovd = 0x00000028, + .trigger_cdm_events = 0x00000090, + .sbi_frame_idx = 0x00000110, + .dsp_status = 0x0000007C, + .diag_config = 0x00000064, + .diag_sensor_status_0 = 0x00000068, + .diag_sensor_status_1 = 0x00000098, + .bus_overflow_status = 0x0000AA68, + .top_debug_cfg = 0x000000DC, + .top_debug_0 = 0x00000080, + .top_debug_1 = 0x00000084, + .top_debug_2 = 0x00000088, + .top_debug_3 = 0x0000008C, + .top_debug_4 = 0x0000009C, + .top_debug_5 = 0x000000A0, + .top_debug_6 = 0x000000A4, + .top_debug_7 = 0x000000A8, + .top_debug_8 = 0x000000AC, + .top_debug_9 = 0x000000B0, + .top_debug_10 = 0x000000B4, + .top_debug_11 = 0x000000B8, + .top_debug_12 = 0x000000BC, + .top_debug_13 = 0x000000C0, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_rdi[3] = { + { + .lite_hw_version = 0x9A00, + .lite_hw_status = 0x9A04, + .lite_module_config = 0x9A60, + .lite_skip_period = 0x9A68, + .lite_irq_subsample_pattern = 0x9A6C, + .lite_epoch_irq = 0x9A70, + .lite_debug_1 = 0x9BF0, + .lite_debug_0 = 0x9BF4, + .lite_test_bus_ctrl = 0x9BF8, + .camif_lite_spare = 0x9BFC, + .reg_update_cmd = 0x34, + }, + { + .lite_hw_version = 0x9C00, + .lite_hw_status = 0x9C04, + .lite_module_config = 0x9C60, + .lite_skip_period = 0x9C68, + .lite_irq_subsample_pattern = 0x9C6C, + .lite_epoch_irq = 0x9C70, + .lite_debug_1 = 0x9DF0, + .lite_debug_0 = 0x9DF4, + .lite_test_bus_ctrl = 0x9DF8, + .camif_lite_spare = 0x9DFC, + .reg_update_cmd = 0x34, + }, + { + .lite_hw_version = 0x9E00, + .lite_hw_status = 0x9E04, + .lite_module_config = 0x9E60, + .lite_skip_period = 0x9E68, + .lite_irq_subsample_pattern = 0x9E6C, + .lite_epoch_irq = 0x9E70, + .lite_debug_1 = 0x9FF0, + .lite_debug_0 = 0x9FF4, + .lite_test_bus_ctrl = 0x9FF8, + .camif_lite_spare = 0x9FFC, + .reg_update_cmd = 0x34, + }, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe480_camif_rdi_reg_data[3] = { + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x2, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x10, + .epoch0_irq_mask = 0x40, + .epoch1_irq_mask = 0x80, + .eof_irq_mask = 0x20, + .error_irq_mask0 = 0x20000000, + .error_irq_mask2 = 0x20000, + .subscribe_irq_mask1 = 0x30, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x4, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x100, + .epoch0_irq_mask = 0x400, + .epoch1_irq_mask = 0x800, + .eof_irq_mask = 0x200, + .error_irq_mask0 = 0x10000000, + .error_irq_mask2 = 0x40000, + .subscribe_irq_mask1 = 0x300, + .enable_diagnostic_hw = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x8, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x1000, + .epoch0_irq_mask = 0x4000, + .epoch1_irq_mask = 0x8000, + .eof_irq_mask = 0x2000, + .error_irq_mask0 = 0x8000000, + .error_irq_mask2 = 0x80000, + .subscribe_irq_mask1 = 0x3000, + .enable_diagnostic_hw = 0x1, + }, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_lcr = { + .lite_hw_version = 0xA000, + .lite_hw_status = 0xA004, + .lite_module_config = 0xA060, + .lite_skip_period = 0xA068, + .lite_irq_subsample_pattern = 0xA06C, + .lite_epoch_irq = 0xA070, + .lite_debug_1 = 0xA1F0, + .lite_debug_0 = 0xA1F4, + .lite_test_bus_ctrl = 0xA1F8, + .camif_lite_spare = 0xA1FC, + .reg_update_cmd = 0x0034, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe480_camif_lcr_reg_data = { + .extern_reg_update_shift = 16, + .reg_update_cmd_data = 0x40, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x100000, + .epoch0_irq_mask = 0x400000, + .epoch1_irq_mask = 0x800000, + .eof_irq_mask = 0x200000, + .error_irq_mask0 = 0x0, + .error_irq_mask2 = 0x18000, + .subscribe_irq_mask1 = 0x300000, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe480_camif_pd = { + .lite_hw_version = 0xA400, + .lite_hw_status = 0xA404, + .lite_module_config = 0xA460, + .lite_skip_period = 0xA468, + .lite_irq_subsample_pattern = 0xA46C, + .lite_epoch_irq = 0xA470, + .lite_debug_1 = 0xA5F0, + .lite_debug_0 = 0xA5F4, + .lite_test_bus_ctrl = 0xA5F8, + .camif_lite_spare = 0xA5FC, + .reg_update_cmd = 0x0034, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe480_camif_pd_reg_data = { + .extern_reg_update_shift = 17, + .operating_mode_shift = 13, + .input_mux_sel_shift = 31, + .reg_update_cmd_data = 0x20, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x10000, + .epoch0_irq_mask = 0x40000, + .epoch1_irq_mask = 0x80000, + .eof_irq_mask = 0x20000, + .error_irq_mask0 = 0x40000000, + .error_irq_mask2 = 0x6000, + .subscribe_irq_mask1 = 0x30000, + .enable_diagnostic_hw = 0x1, +}; + +struct cam_vfe_camif_lite_ver3_hw_info rdi_hw_info_arr[CAM_VFE_RDI_VER2_MAX] = { + { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_rdi[0], + .reg_data = &vfe480_camif_rdi_reg_data[0], + }, + { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_rdi[1], + .reg_data = &vfe480_camif_rdi_reg_data[1], + }, + { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_rdi[2], + .reg_data = &vfe480_camif_rdi_reg_data[2], + }, +}; + +static struct cam_vfe_top_ver3_hw_info vfe480_top_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_reg = &vfe480_camif_reg, + .reg_data = &vfe_480_camif_reg_data, + }, + .pdlib_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_pd, + .reg_data = &vfe480_camif_pd_reg_data, + }, + .rdi_hw_info[0] = &rdi_hw_info_arr[0], + .rdi_hw_info[1] = &rdi_hw_info_arr[1], + .rdi_hw_info[2] = &rdi_hw_info_arr[2], + .lcr_hw_info = { + .common_reg = &vfe480_top_common_reg, + .camif_lite_reg = &vfe480_camif_lcr, + .reg_data = &vfe480_camif_lcr_reg_data, + }, + .num_mux = 6, + .mux_type = { + CAM_VFE_CAMIF_VER_3_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_PDLIB_VER_1_0, + CAM_VFE_LCR_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe480_bus_irq_reg[2] = { + { + .mask_reg_offset = 0x0000AA18, + .clear_reg_offset = 0x0000AA20, + .status_reg_offset = 0x0000AA28, + }, + { + .mask_reg_offset = 0x0000AA1C, + .clear_reg_offset = 0x0000AA24, + .status_reg_offset = 0x0000AA2C, + }, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_0 = { + .meta_addr = 0x0000AC40, + .meta_cfg = 0x0000AC44, + .mode_cfg = 0x0000AC48, + .stats_ctrl = 0x0000AC4C, + .ctrl_2 = 0x0000AC50, + .lossy_thresh0 = 0x0000AC54, + .lossy_thresh1 = 0x0000AC58, + .off_lossy_var = 0x0000AC5C, + .bw_limit = 0x0000AC1C, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_1 = { + .meta_addr = 0x0000AD40, + .meta_cfg = 0x0000AD44, + .mode_cfg = 0x0000AD48, + .stats_ctrl = 0x0000AD4C, + .ctrl_2 = 0x0000AD50, + .lossy_thresh0 = 0x0000AD54, + .lossy_thresh1 = 0x0000AD58, + .off_lossy_var = 0x0000AD5C, + .bw_limit = 0x0000AD1C, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_4 = { + .meta_addr = 0x0000B040, + .meta_cfg = 0x0000B044, + .mode_cfg = 0x0000B048, + .stats_ctrl = 0x0000B04C, + .ctrl_2 = 0x0000B050, + .lossy_thresh0 = 0x0000B054, + .lossy_thresh1 = 0x0000B058, + .off_lossy_var = 0x0000B05C, + .bw_limit = 0x0000B01C, +}; + +static struct cam_vfe_bus_ver3_reg_offset_ubwc_client + vfe480_ubwc_regs_client_5 = { + .meta_addr = 0x0000B140, + .meta_cfg = 0x0000B144, + .mode_cfg = 0x0000B148, + .stats_ctrl = 0x0000B14C, + .ctrl_2 = 0x0000B150, + .lossy_thresh0 = 0x0000B154, + .lossy_thresh1 = 0x0000B158, + .off_lossy_var = 0x0000B15C, + .bw_limit = 0x0000B11C, +}; + +static struct cam_vfe_bus_ver3_hw_info vfe480_bus_hw_info = { + .common_reg = { + .hw_version = 0x0000AA00, + .cgc_ovd = 0x0000AA08, + .comp_cfg_0 = 0x0000AA0C, + .comp_cfg_1 = 0x0000AA10, + .if_frameheader_cfg = { + 0x0000AA34, + 0x0000AA38, + 0x0000AA3C, + 0x0000AA40, + 0x0000AA44, + 0x0000AA48, + }, + .ubwc_static_ctrl = 0x0000AA58, + .pwr_iso_cfg = 0x0000AA5C, + .overflow_status_clear = 0x0000AA60, + .ccif_violation_status = 0x0000AA64, + .overflow_status = 0x0000AA68, + .image_size_violation_status = 0x0000AA70, + .debug_status_top_cfg = 0x0000AAD4, + .debug_status_top = 0x0000AAD8, + .test_bus_ctrl = 0x0000AADC, + .irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe480_bus_irq_reg, + .global_clear_offset = 0x0000AA30, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = CAM_VFE_BUS_VER3_MAX_CLIENTS, + .bus_client_reg = { + /* BUS Client 0 FULL Y */ + { + .cfg = 0x0000AC00, + .image_addr = 0x0000AC04, + .frame_incr = 0x0000AC08, + .image_cfg_0 = 0x0000AC0C, + .image_cfg_1 = 0x0000AC10, + .image_cfg_2 = 0x0000AC14, + .packer_cfg = 0x0000AC18, + .frame_header_addr = 0x0000AC20, + .frame_header_incr = 0x0000AC24, + .frame_header_cfg = 0x0000AC28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AC30, + .irq_subsample_pattern = 0x0000AC34, + .framedrop_period = 0x0000AC38, + .framedrop_pattern = 0x0000AC3C, + .system_cache_cfg = 0x0000AC60, + .burst_limit = 0x0000AC64, + .addr_status_0 = 0x0000AC68, + .addr_status_1 = 0x0000AC6C, + .addr_status_2 = 0x0000AC70, + .addr_status_3 = 0x0000AC74, + .debug_status_cfg = 0x0000AC78, + .debug_status_0 = 0x0000AC7C, + .debug_status_1 = 0x0000AC80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = &vfe480_ubwc_regs_client_0, + }, + /* BUS Client 1 FULL C */ + { + .cfg = 0x0000AD00, + .image_addr = 0x0000AD04, + .frame_incr = 0x0000AD08, + .image_cfg_0 = 0x0000AD0C, + .image_cfg_1 = 0x0000AD10, + .image_cfg_2 = 0x0000AD14, + .packer_cfg = 0x0000AD18, + .frame_header_addr = 0x0000AD20, + .frame_header_incr = 0x0000AD24, + .frame_header_cfg = 0x0000AD28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AD30, + .irq_subsample_pattern = 0x0000AD34, + .framedrop_period = 0x0000AD38, + .framedrop_pattern = 0x0000AD3C, + .system_cache_cfg = 0x0000AD60, + .burst_limit = 0x0000AD64, + .addr_status_0 = 0x0000AD68, + .addr_status_1 = 0x0000AD6C, + .addr_status_2 = 0x0000AD70, + .addr_status_3 = 0x0000AD74, + .debug_status_cfg = 0x0000AD78, + .debug_status_0 = 0x0000AD7C, + .debug_status_1 = 0x0000AD80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = &vfe480_ubwc_regs_client_1, + }, + /* BUS Client 2 DS4 */ + { + .cfg = 0x0000AE00, + .image_addr = 0x0000AE04, + .frame_incr = 0x0000AE08, + .image_cfg_0 = 0x0000AE0C, + .image_cfg_1 = 0x0000AE10, + .image_cfg_2 = 0x0000AE14, + .packer_cfg = 0x0000AE18, + .frame_header_addr = 0x0000AE20, + .frame_header_incr = 0x0000AE24, + .frame_header_cfg = 0x0000AE28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AE30, + .irq_subsample_pattern = 0x0000AE34, + .framedrop_period = 0x0000AE38, + .framedrop_pattern = 0x0000AE3C, + .system_cache_cfg = 0x0000AE60, + .burst_limit = 0x0000AE64, + .addr_status_0 = 0x0000AE68, + .addr_status_1 = 0x0000AE6C, + .addr_status_2 = 0x0000AE70, + .addr_status_3 = 0x0000AE74, + .debug_status_cfg = 0x0000AE78, + .debug_status_0 = 0x0000AE7C, + .debug_status_1 = 0x0000AE80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = NULL, + }, + /* BUS Client 3 DS16 */ + { + .cfg = 0x0000AF00, + .image_addr = 0x0000AF04, + .frame_incr = 0x0000AF08, + .image_cfg_0 = 0x0000AF0C, + .image_cfg_1 = 0x0000AF10, + .image_cfg_2 = 0x0000AF14, + .packer_cfg = 0x0000AF18, + .frame_header_addr = 0x0000AF20, + .frame_header_incr = 0x0000AF24, + .frame_header_cfg = 0x0000AF28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000AF30, + .irq_subsample_pattern = 0x0000AF34, + .framedrop_period = 0x0000AF38, + .framedrop_pattern = 0x0000AF3C, + .system_cache_cfg = 0x0000AF60, + .burst_limit = 0x0000AF64, + .addr_status_0 = 0x0000AF68, + .addr_status_1 = 0x0000AF6C, + .addr_status_2 = 0x0000AF70, + .addr_status_3 = 0x0000AF74, + .debug_status_cfg = 0x0000AF78, + .debug_status_0 = 0x0000AF7C, + .debug_status_1 = 0x0000AF80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = NULL, + }, + /* BUS Client 4 DISP Y */ + { + .cfg = 0x0000B000, + .image_addr = 0x0000B004, + .frame_incr = 0x0000B008, + .image_cfg_0 = 0x0000B00C, + .image_cfg_1 = 0x0000B010, + .image_cfg_2 = 0x0000B014, + .packer_cfg = 0x0000B018, + .frame_header_addr = 0x0000B020, + .frame_header_incr = 0x0000B024, + .frame_header_cfg = 0x0000B028, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B030, + .irq_subsample_pattern = 0x0000B034, + .framedrop_period = 0x0000B038, + .framedrop_pattern = 0x0000B03C, + .system_cache_cfg = 0x0000B060, + .burst_limit = 0x0000B064, + .addr_status_0 = 0x0000B068, + .addr_status_1 = 0x0000B06C, + .addr_status_2 = 0x0000B070, + .addr_status_3 = 0x0000B074, + .debug_status_cfg = 0x0000B078, + .debug_status_0 = 0x0000B07C, + .debug_status_1 = 0x0000B080, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = &vfe480_ubwc_regs_client_4, + }, + /* BUS Client 5 DISP C */ + { + .cfg = 0x0000B100, + .image_addr = 0x0000B104, + .frame_incr = 0x0000B108, + .image_cfg_0 = 0x0000B10C, + .image_cfg_1 = 0x0000B110, + .image_cfg_2 = 0x0000B114, + .packer_cfg = 0x0000B118, + .frame_header_addr = 0x0000B120, + .frame_header_incr = 0x0000B124, + .frame_header_cfg = 0x0000B128, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B130, + .irq_subsample_pattern = 0x0000B134, + .framedrop_period = 0x0000B138, + .framedrop_pattern = 0x0000B13C, + .system_cache_cfg = 0x0000B160, + .burst_limit = 0x0000B164, + .addr_status_0 = 0x0000B168, + .addr_status_1 = 0x0000B16C, + .addr_status_2 = 0x0000B170, + .addr_status_3 = 0x0000B174, + .debug_status_cfg = 0x0000B178, + .debug_status_0 = 0x0000B17C, + .debug_status_1 = 0x0000B180, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = &vfe480_ubwc_regs_client_5, + }, + /* BUS Client 6 DISP DS4 */ + { + .cfg = 0x0000B200, + .image_addr = 0x0000B204, + .frame_incr = 0x0000B208, + .image_cfg_0 = 0x0000B20C, + .image_cfg_1 = 0x0000B210, + .image_cfg_2 = 0x0000B214, + .packer_cfg = 0x0000B218, + .frame_header_addr = 0x0000B220, + .frame_header_incr = 0x0000B224, + .frame_header_cfg = 0x0000B228, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B230, + .irq_subsample_pattern = 0x0000B234, + .framedrop_period = 0x0000B238, + .framedrop_pattern = 0x0000B23C, + .system_cache_cfg = 0x0000B260, + .burst_limit = 0x0000B264, + .addr_status_0 = 0x0000B268, + .addr_status_1 = 0x0000B26C, + .addr_status_2 = 0x0000B270, + .addr_status_3 = 0x0000B274, + .debug_status_cfg = 0x0000B278, + .debug_status_0 = 0x0000B27C, + .debug_status_1 = 0x0000B280, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = NULL, + }, + /* BUS Client 7 DISP DS16 */ + { + .cfg = 0x0000B300, + .image_addr = 0x0000B304, + .frame_incr = 0x0000B308, + .image_cfg_0 = 0x0000B30C, + .image_cfg_1 = 0x0000B310, + .image_cfg_2 = 0x0000B314, + .packer_cfg = 0x0000B318, + .frame_header_addr = 0x0000B320, + .frame_header_incr = 0x0000B324, + .frame_header_cfg = 0x0000B328, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B330, + .irq_subsample_pattern = 0x0000B334, + .framedrop_period = 0x0000B338, + .framedrop_pattern = 0x0000B33C, + .system_cache_cfg = 0x0000B360, + .burst_limit = 0x0000B364, + .addr_status_0 = 0x0000B368, + .addr_status_1 = 0x0000B36C, + .addr_status_2 = 0x0000B370, + .addr_status_3 = 0x0000B374, + .debug_status_cfg = 0x0000B378, + .debug_status_0 = 0x0000B37C, + .debug_status_1 = 0x0000B380, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = NULL, + }, + /* BUS Client 8 FD Y */ + { + .cfg = 0x0000B400, + .image_addr = 0x0000B404, + .frame_incr = 0x0000B408, + .image_cfg_0 = 0x0000B40C, + .image_cfg_1 = 0x0000B410, + .image_cfg_2 = 0x0000B414, + .packer_cfg = 0x0000B418, + .frame_header_addr = 0x0000B420, + .frame_header_incr = 0x0000B424, + .frame_header_cfg = 0x0000B428, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B430, + .irq_subsample_pattern = 0x0000B434, + .framedrop_period = 0x0000B438, + .framedrop_pattern = 0x0000B43C, + .system_cache_cfg = 0x0000B460, + .burst_limit = 0x0000B464, + .addr_status_0 = 0x0000B468, + .addr_status_1 = 0x0000B46C, + .addr_status_2 = 0x0000B470, + .addr_status_3 = 0x0000B474, + .debug_status_cfg = 0x0000B478, + .debug_status_0 = 0x0000B47C, + .debug_status_1 = 0x0000B480, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_2, + .ubwc_regs = NULL, + }, + /* BUS Client 9 FD C */ + { + .cfg = 0x0000B500, + .image_addr = 0x0000B504, + .frame_incr = 0x0000B508, + .image_cfg_0 = 0x0000B50C, + .image_cfg_1 = 0x0000B510, + .image_cfg_2 = 0x0000B514, + .packer_cfg = 0x0000B518, + .frame_header_addr = 0x0000B520, + .frame_header_incr = 0x0000B524, + .frame_header_cfg = 0x0000B528, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B530, + .irq_subsample_pattern = 0x0000B534, + .framedrop_period = 0x0000B538, + .framedrop_pattern = 0x0000B53C, + .system_cache_cfg = 0x0000B560, + .burst_limit = 0x0000B564, + .addr_status_0 = 0x0000B568, + .addr_status_1 = 0x0000B56C, + .addr_status_2 = 0x0000B570, + .addr_status_3 = 0x0000B574, + .debug_status_cfg = 0x0000B578, + .debug_status_0 = 0x0000B57C, + .debug_status_1 = 0x0000B580, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_2, + .ubwc_regs = NULL, + }, + /* BUS Client 10 PIXEL RAW */ + { + .cfg = 0x0000B600, + .image_addr = 0x0000B604, + .frame_incr = 0x0000B608, + .image_cfg_0 = 0x0000B60C, + .image_cfg_1 = 0x0000B610, + .image_cfg_2 = 0x0000B614, + .packer_cfg = 0x0000B618, + .frame_header_addr = 0x0000B620, + .frame_header_incr = 0x0000B624, + .frame_header_cfg = 0x0000B628, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B630, + .irq_subsample_pattern = 0x0000B634, + .framedrop_period = 0x0000B638, + .framedrop_pattern = 0x0000B63C, + .system_cache_cfg = 0x0000B660, + .burst_limit = 0x0000B664, + .addr_status_0 = 0x0000B668, + .addr_status_1 = 0x0000B66C, + .addr_status_2 = 0x0000B670, + .addr_status_3 = 0x0000B674, + .debug_status_cfg = 0x0000B678, + .debug_status_0 = 0x0000B67C, + .debug_status_1 = 0x0000B680, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_3, + .ubwc_regs = NULL, + }, + /* BUS Client 11 CAMIF PD */ + { + .cfg = 0x0000B700, + .image_addr = 0x0000B704, + .frame_incr = 0x0000B708, + .image_cfg_0 = 0x0000B70C, + .image_cfg_1 = 0x0000B710, + .image_cfg_2 = 0x0000B714, + .packer_cfg = 0x0000B718, + .frame_header_addr = 0x0000B720, + .frame_header_incr = 0x0000B724, + .frame_header_cfg = 0x0000B728, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B730, + .irq_subsample_pattern = 0x0000B734, + .framedrop_period = 0x0000B738, + .framedrop_pattern = 0x0000B73C, + .system_cache_cfg = 0x0000B760, + .burst_limit = 0x0000B764, + .addr_status_0 = 0x0000B768, + .addr_status_1 = 0x0000B76C, + .addr_status_2 = 0x0000B770, + .addr_status_3 = 0x0000B774, + .debug_status_cfg = 0x0000B778, + .debug_status_0 = 0x0000B77C, + .debug_status_1 = 0x0000B780, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_4, + .ubwc_regs = NULL, + }, + /* BUS Client 12 STATS HDR BE */ + { + .cfg = 0x0000B800, + .image_addr = 0x0000B804, + .frame_incr = 0x0000B808, + .image_cfg_0 = 0x0000B80C, + .image_cfg_1 = 0x0000B810, + .image_cfg_2 = 0x0000B814, + .packer_cfg = 0x0000B818, + .frame_header_addr = 0x0000B820, + .frame_header_incr = 0x0000B824, + .frame_header_cfg = 0x0000B828, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B830, + .irq_subsample_pattern = 0x0000B834, + .framedrop_period = 0x0000B838, + .framedrop_pattern = 0x0000B83C, + .system_cache_cfg = 0x0000B860, + .burst_limit = 0x0000B864, + .addr_status_0 = 0x0000B868, + .addr_status_1 = 0x0000B86C, + .addr_status_2 = 0x0000B870, + .addr_status_3 = 0x0000B874, + .debug_status_cfg = 0x0000B878, + .debug_status_0 = 0x0000B87C, + .debug_status_1 = 0x0000B880, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_5, + .ubwc_regs = NULL, + }, + /* BUS Client 13 STATS HDR BHIST */ + { + .cfg = 0x0000B900, + .image_addr = 0x0000B904, + .frame_incr = 0x0000B908, + .image_cfg_0 = 0x0000B90C, + .image_cfg_1 = 0x0000B910, + .image_cfg_2 = 0x0000B914, + .packer_cfg = 0x0000B918, + .frame_header_addr = 0x0000B920, + .frame_header_incr = 0x0000B924, + .frame_header_cfg = 0x0000B928, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000B930, + .irq_subsample_pattern = 0x0000B934, + .framedrop_period = 0x0000B938, + .framedrop_pattern = 0x0000B93C, + .system_cache_cfg = 0x0000B960, + .burst_limit = 0x0000B964, + .addr_status_0 = 0x0000B968, + .addr_status_1 = 0x0000B96C, + .addr_status_2 = 0x0000B970, + .addr_status_3 = 0x0000B974, + .debug_status_cfg = 0x0000B978, + .debug_status_0 = 0x0000B97C, + .debug_status_1 = 0x0000B980, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_5, + .ubwc_regs = NULL, + }, + /* BUS Client 14 STATS TINTLESS BG */ + { + .cfg = 0x0000BA00, + .image_addr = 0x0000BA04, + .frame_incr = 0x0000BA08, + .image_cfg_0 = 0x0000BA0C, + .image_cfg_1 = 0x0000BA10, + .image_cfg_2 = 0x0000BA14, + .packer_cfg = 0x0000BA18, + .frame_header_addr = 0x0000BA20, + .frame_header_incr = 0x0000BA24, + .frame_header_cfg = 0x0000BA28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BA30, + .irq_subsample_pattern = 0x0000BA34, + .framedrop_period = 0x0000BA38, + .framedrop_pattern = 0x0000BA3C, + .system_cache_cfg = 0x0000BA60, + .burst_limit = 0x0000BA64, + .addr_status_0 = 0x0000BA68, + .addr_status_1 = 0x0000BA6C, + .addr_status_2 = 0x0000BA70, + .addr_status_3 = 0x0000BA74, + .debug_status_cfg = 0x0000BA78, + .debug_status_0 = 0x0000BA7C, + .debug_status_1 = 0x0000BA80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_6, + .ubwc_regs = NULL, + }, + /* BUS Client 15 STATS AWB BG */ + { + .cfg = 0x0000BB00, + .image_addr = 0x0000BB04, + .frame_incr = 0x0000BB08, + .image_cfg_0 = 0x0000BB0C, + .image_cfg_1 = 0x0000BB10, + .image_cfg_2 = 0x0000BB14, + .packer_cfg = 0x0000BB18, + .frame_header_addr = 0x0000BB20, + .frame_header_incr = 0x0000BB24, + .frame_header_cfg = 0x0000BB28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BB30, + .irq_subsample_pattern = 0x0000BB34, + .framedrop_period = 0x0000BB38, + .framedrop_pattern = 0x0000BB3C, + .system_cache_cfg = 0x0000BB60, + .burst_limit = 0x0000BB64, + .addr_status_0 = 0x0000BB68, + .addr_status_1 = 0x0000BB6C, + .addr_status_2 = 0x0000BB70, + .addr_status_3 = 0x0000BB74, + .debug_status_cfg = 0x0000BB78, + .debug_status_0 = 0x0000BB7C, + .debug_status_1 = 0x0000BB80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_6, + .ubwc_regs = NULL, + }, + /* BUS Client 16 STATS BHIST */ + { + .cfg = 0x0000BC00, + .image_addr = 0x0000BC04, + .frame_incr = 0x0000BC08, + .image_cfg_0 = 0x0000BC0C, + .image_cfg_1 = 0x0000BC10, + .image_cfg_2 = 0x0000BC14, + .packer_cfg = 0x0000BC18, + .frame_header_addr = 0x0000BC20, + .frame_header_incr = 0x0000BC24, + .frame_header_cfg = 0x0000BC28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BC30, + .irq_subsample_pattern = 0x0000BC34, + .framedrop_period = 0x0000BC38, + .framedrop_pattern = 0x0000BC3C, + .system_cache_cfg = 0x0000BC60, + .burst_limit = 0x0000BC64, + .addr_status_0 = 0x0000BC68, + .addr_status_1 = 0x0000BC6C, + .addr_status_2 = 0x0000BC70, + .addr_status_3 = 0x0000BC74, + .debug_status_cfg = 0x0000BC78, + .debug_status_0 = 0x0000BC7C, + .debug_status_1 = 0x0000BC80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 17 STATS RS */ + { + .cfg = 0x0000BD00, + .image_addr = 0x0000BD04, + .frame_incr = 0x0000BD08, + .image_cfg_0 = 0x0000BD0C, + .image_cfg_1 = 0x0000BD10, + .image_cfg_2 = 0x0000BD14, + .packer_cfg = 0x0000BD18, + .frame_header_addr = 0x0000BD20, + .frame_header_incr = 0x0000BD24, + .frame_header_cfg = 0x0000BD28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BD30, + .irq_subsample_pattern = 0x0000BD34, + .framedrop_period = 0x0000BD38, + .framedrop_pattern = 0x0000BD3C, + .system_cache_cfg = 0x0000BD60, + .burst_limit = 0x0000BD64, + .addr_status_0 = 0x0000BD68, + .addr_status_1 = 0x0000BD6C, + .addr_status_2 = 0x0000BD70, + .addr_status_3 = 0x0000BD74, + .debug_status_cfg = 0x0000BD78, + .debug_status_0 = 0x0000BD7C, + .debug_status_1 = 0x0000BD80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 18 STATS CS */ + { + .cfg = 0x0000BE00, + .image_addr = 0x0000BE04, + .frame_incr = 0x0000BE08, + .image_cfg_0 = 0x0000BE0C, + .image_cfg_1 = 0x0000BE10, + .image_cfg_2 = 0x0000BE14, + .packer_cfg = 0x0000BE18, + .frame_header_addr = 0x0000BE20, + .frame_header_incr = 0x0000BE24, + .frame_header_cfg = 0x0000BE28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BE30, + .irq_subsample_pattern = 0x0000BE34, + .framedrop_period = 0x0000BE38, + .framedrop_pattern = 0x0000BE3C, + .system_cache_cfg = 0x0000BE60, + .burst_limit = 0x0000BE64, + .addr_status_0 = 0x0000BE68, + .addr_status_1 = 0x0000BE6C, + .addr_status_2 = 0x0000BE70, + .addr_status_3 = 0x0000BE74, + .debug_status_cfg = 0x0000BE78, + .debug_status_0 = 0x0000BE7C, + .debug_status_1 = 0x0000BE80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 19 STATS IHIST */ + { + .cfg = 0x0000BF00, + .image_addr = 0x0000BF04, + .frame_incr = 0x0000BF08, + .image_cfg_0 = 0x0000BF0C, + .image_cfg_1 = 0x0000BF10, + .image_cfg_2 = 0x0000BF14, + .packer_cfg = 0x0000BF18, + .frame_header_addr = 0x0000BF20, + .frame_header_incr = 0x0000BF24, + .frame_header_cfg = 0x0000BF28, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000BF30, + .irq_subsample_pattern = 0x0000BF34, + .framedrop_period = 0x0000BF38, + .framedrop_pattern = 0x0000BF3C, + .system_cache_cfg = 0x0000BF60, + .burst_limit = 0x0000BF64, + .addr_status_0 = 0x0000BF68, + .addr_status_1 = 0x0000BF6C, + .addr_status_2 = 0x0000BF70, + .addr_status_3 = 0x0000BF74, + .debug_status_cfg = 0x0000BF78, + .debug_status_0 = 0x0000BF7C, + .debug_status_1 = 0x0000BF80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_7, + .ubwc_regs = NULL, + }, + /* BUS Client 20 STATS BF */ + { + .cfg = 0x0000C000, + .image_addr = 0x0000C004, + .frame_incr = 0x0000C008, + .image_cfg_0 = 0x0000C00C, + .image_cfg_1 = 0x0000C010, + .image_cfg_2 = 0x0000C014, + .packer_cfg = 0x0000C018, + .frame_header_addr = 0x0000C020, + .frame_header_incr = 0x0000C024, + .frame_header_cfg = 0x0000C028, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000C030, + .irq_subsample_pattern = 0x0000C034, + .framedrop_period = 0x0000C038, + .framedrop_pattern = 0x0000C03C, + .system_cache_cfg = 0x0000C060, + .burst_limit = 0x0000C064, + .addr_status_0 = 0x0000C068, + .addr_status_1 = 0x0000C06C, + .addr_status_2 = 0x0000C070, + .addr_status_3 = 0x0000C074, + .debug_status_cfg = 0x0000C078, + .debug_status_0 = 0x0000C07C, + .debug_status_1 = 0x0000C080, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_8, + .ubwc_regs = NULL, + }, + /* BUS Client 21 PDAF V2.0 */ + { + .cfg = 0x0000C100, + .image_addr = 0x0000C104, + .frame_incr = 0x0000C108, + .image_cfg_0 = 0x0000C10C, + .image_cfg_1 = 0x0000C110, + .image_cfg_2 = 0x0000C114, + .packer_cfg = 0x0000C118, + .frame_header_addr = 0x0000C120, + .frame_header_incr = 0x0000C124, + .frame_header_cfg = 0x0000C128, + .line_done_cfg = 0x0000C12C, + .irq_subsample_period = 0x0000C130, + .irq_subsample_pattern = 0x0000C134, + .framedrop_period = 0x0000C138, + .framedrop_pattern = 0x0000C13C, + .system_cache_cfg = 0x0000C160, + .burst_limit = 0x0000C164, + .addr_status_0 = 0x0000C168, + .addr_status_1 = 0x0000C16C, + .addr_status_2 = 0x0000C170, + .addr_status_3 = 0x0000C174, + .debug_status_cfg = 0x0000C178, + .debug_status_0 = 0x0000C17C, + .debug_status_1 = 0x0000C180, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_9, + .ubwc_regs = NULL, + }, + /* BUS Client 22 LCR */ + { + .cfg = 0x0000C200, + .image_addr = 0x0000C204, + .frame_incr = 0x0000C208, + .image_cfg_0 = 0x0000C20C, + .image_cfg_1 = 0x0000C210, + .image_cfg_2 = 0x0000C214, + .packer_cfg = 0x0000C218, + .frame_header_addr = 0x0000C220, + .frame_header_incr = 0x0000C224, + .frame_header_cfg = 0x0000C228, + .line_done_cfg = 0, + .irq_subsample_period = 0x0000C230, + .irq_subsample_pattern = 0x0000C234, + .framedrop_period = 0x0000C238, + .framedrop_pattern = 0x0000C23C, + .system_cache_cfg = 0x0000C260, + .burst_limit = 0x0000C264, + .addr_status_0 = 0x0000C268, + .addr_status_1 = 0x0000C26C, + .addr_status_2 = 0x0000C270, + .addr_status_3 = 0x0000C274, + .debug_status_cfg = 0x0000C278, + .debug_status_0 = 0x0000C27C, + .debug_status_1 = 0x0000C280, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_10, + .ubwc_regs = NULL, + }, + /* BUS Client 23 RDI0 */ + { + .cfg = 0x0000C300, + .image_addr = 0x0000C304, + .frame_incr = 0x0000C308, + .image_cfg_0 = 0x0000C30C, + .image_cfg_1 = 0x0000C310, + .image_cfg_2 = 0x0000C314, + .packer_cfg = 0x0000C318, + .frame_header_addr = 0x0000C320, + .frame_header_incr = 0x0000C324, + .frame_header_cfg = 0x0000C328, + .line_done_cfg = 0x0000C32C, + .irq_subsample_period = 0x0000C330, + .irq_subsample_pattern = 0x0000C334, + .framedrop_period = 0x0000C338, + .framedrop_pattern = 0x0000C33C, + .system_cache_cfg = 0x0000C360, + .burst_limit = 0x0000C364, + .addr_status_0 = 0x0000C368, + .addr_status_1 = 0x0000C36C, + .addr_status_2 = 0x0000C370, + .addr_status_3 = 0x0000C374, + .debug_status_cfg = 0x0000C378, + .debug_status_0 = 0x0000C37C, + .debug_status_1 = 0x0000C380, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_11, + .ubwc_regs = NULL, + }, + /* BUS Client 24 RDI1 */ + { + .cfg = 0x0000C400, + .image_addr = 0x0000C404, + .frame_incr = 0x0000C408, + .image_cfg_0 = 0x0000C40C, + .image_cfg_1 = 0x0000C410, + .image_cfg_2 = 0x0000C414, + .packer_cfg = 0x0000C418, + .frame_header_addr = 0x0000C420, + .frame_header_incr = 0x0000C424, + .frame_header_cfg = 0x0000C428, + .line_done_cfg = 0x0000C42C, + .irq_subsample_period = 0x0000C430, + .irq_subsample_pattern = 0x0000C434, + .framedrop_period = 0x0000C438, + .framedrop_pattern = 0x0000C43C, + .system_cache_cfg = 0x0000C460, + .burst_limit = 0x0000C464, + .addr_status_0 = 0x0000C468, + .addr_status_1 = 0x0000C46C, + .addr_status_2 = 0x0000C470, + .addr_status_3 = 0x0000C474, + .debug_status_cfg = 0x0000C478, + .debug_status_0 = 0x0000C47C, + .debug_status_1 = 0x0000C480, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_12, + .ubwc_regs = NULL, + }, + /* BUS Client 25 RDI2 */ + { + .cfg = 0x0000C500, + .image_addr = 0x0000C504, + .frame_incr = 0x0000C508, + .image_cfg_0 = 0x0000C50C, + .image_cfg_1 = 0x0000C510, + .image_cfg_2 = 0x0000C514, + .packer_cfg = 0x0000C518, + .frame_header_addr = 0x0000C520, + .frame_header_incr = 0x0000C524, + .frame_header_cfg = 0x0000C528, + .line_done_cfg = 0x0000C52C, + .irq_subsample_period = 0x0000C530, + .irq_subsample_pattern = 0x0000C534, + .framedrop_period = 0x0000C538, + .framedrop_pattern = 0x0000C53C, + .system_cache_cfg = 0x0000C560, + .burst_limit = 0x0000C564, + .addr_status_0 = 0x0000C568, + .addr_status_1 = 0x0000C56C, + .addr_status_2 = 0x0000C570, + .addr_status_3 = 0x0000C574, + .debug_status_cfg = 0x0000C578, + .debug_status_0 = 0x0000C57C, + .debug_status_1 = 0x0000C580, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_13, + .ubwc_regs = NULL, + }, + }, + .num_out = 23, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_3, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_4, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_5, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_LCR, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_2, + }, + }, + .comp_done_shift = 6, + .top_irq_shift = 7, +}; + +static struct cam_irq_register_set vfe480_bus_rd_irq_reg[1] = { + { + .mask_reg_offset = 0x0000A810, + .clear_reg_offset = 0x0000A814, + .status_reg_offset = 0x0000A81C, + }, +}; + +static struct cam_vfe_bus_rd_ver1_hw_info vfe480_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x0000A800, + .hw_capability = 0x0000A804, + .sw_reset = 0x0000A808, + .cgc_ovd = 0x0000A80C, + .pwr_iso_cfg = 0x0000A834, + .input_if_cmd = 0x0000A820, + .test_bus_ctrl = 0x0000A848, + .irq_reg_info = { + .num_registers = 1, + .irq_reg_set = vfe480_bus_rd_irq_reg, + .global_clear_offset = 0x0000A818, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 1, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x0000A850, + .image_addr = 0x0000A858, + .buf_size = 0x0000A85C, + .stride = 0x0000A860, + .unpacker_cfg = 0x0000A864, + .latency_buf_allocation = 0x0000A878, + .burst_limit = 0x0000A880, + }, + }, + .num_bus_rd_resc = 1, + .vfe_bus_rd_hw_info = { + { + .vfe_bus_rd_type = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +struct cam_vfe_hw_info cam_vfe480_hw_info = { + .irq_reg_info = &vfe480_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_3_0, + .bus_hw_info = &vfe480_bus_hw_info, + + .bus_rd_version = CAM_VFE_BUS_RD_VER_1_0, + .bus_rd_hw_info = &vfe480_bus_rd_hw_info, + + .top_version = CAM_VFE_TOP_VER_3_0, + .top_hw_info = &vfe480_top_hw_info, +}; + +#endif /* _CAM_VFE480_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h new file mode 100644 index 0000000000000000000000000000000000000000..aab38c791637ccc41cd7e13aa76ac74e046d5d8f --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite17x.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_LITE17X_H_ +#define _CAM_VFE_LITE17X_H_ + +#include "cam_vfe_bus_ver2.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe17x_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe17x_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe17x_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe17x_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + NULL, + NULL, + NULL, + NULL, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000000, + .three_D_cfg = 0x00000000, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe17x_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_common_reg_data vfe17x_rdi_reg_data = { + .subscribe_irq_mask0 = 0x780001E0, + .subscribe_irq_mask1 = 0x0, + .error_irq_mask0 = 0x0, + .error_irq_mask1 = 0x3C, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_rdi_reg_data vfe17x_rdi_3_data = { + .reg_update_cmd_data = 0x10, + .sof_irq_mask = 0x40000000, + .reg_update_irq_mask = 0x100, +}; + +static struct cam_vfe_top_ver2_hw_info vfe17x_top_hw_info = { + .common_reg = &vfe17x_top_common_reg, + .camif_hw_info = { + .common_reg = NULL, + .camif_reg = NULL, + .reg_data = NULL, + }, + .rdi_hw_info = { + .common_reg = &vfe17x_top_common_reg, + .rdi_reg = &vfe17x_rdi_reg, + .common_reg_data = &vfe17x_rdi_reg_data, + .reg_data = { + &vfe17x_rdi_0_data, + &vfe17x_rdi_1_data, + &vfe17x_rdi_2_data, + &vfe17x_rdi_3_data, + }, + }, + .num_mux = 4, + .mux_type = { + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe17x_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe17x_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe17x_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + }, + .num_client = 4, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 4, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI3, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +static struct cam_vfe_hw_info cam_vfe_lite17x_hw_info = { + .irq_reg_info = &vfe17x_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe17x_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe17x_top_hw_info, + +}; + +#endif /* _CAM_VFE_LITE17X_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h new file mode 100644 index 0000000000000000000000000000000000000000..c19ade50bec969f3944b23ee82b5a4a9639a28e8 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe_lite48x.h @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_LITE48x_H_ +#define _CAM_VFE_LITE48x_H_ + +#include "cam_vfe_bus_ver3.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver3.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe48x_top_irq_reg_set[3] = { + { + .mask_reg_offset = 0x00000028, + .clear_reg_offset = 0x00000034, + .status_reg_offset = 0x00000040, + }, + { + .mask_reg_offset = 0x0000002C, + .clear_reg_offset = 0x00000038, + .status_reg_offset = 0x00000044, + }, + { + .mask_reg_offset = 0x00000030, + .clear_reg_offset = 0x0000003C, + .status_reg_offset = 0x00000048, + }, +}; + +static struct cam_irq_controller_reg_info vfe48x_top_irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe48x_top_irq_reg_set, + .global_clear_offset = 0x00000024, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_top_ver3_reg_offset_common vfe48x_top_common_reg = { + .hw_version = 0x00000000, + .titan_version = 0x00000004, + .hw_capability = 0x00000008, + .global_reset_cmd = 0x0000000C, + .core_cgc_ovd_0 = 0x00000010, + .ahb_cgc_ovd = 0x00000014, + .noc_cgc_ovd = 0x00000018, + .reg_update_cmd = 0x00000020, + .diag_config = 0x00000050, + .diag_sensor_status_0 = 0x00000054, + .bus_overflow_status = 0x00001A68, + .top_debug_cfg = 0x00000074, + .top_debug_0 = 0x0000005C, + .top_debug_1 = 0x00000068, + .top_debug_2 = 0x0000006C, + .top_debug_3 = 0x00000070, +}; + +static struct cam_vfe_camif_lite_ver3_reg vfe48x_camif_rdi[4] = { + { + .lite_hw_version = 0x1200, + .lite_hw_status = 0x1204, + .lite_module_config = 0x1260, + .lite_skip_period = 0x1268, + .lite_irq_subsample_pattern = 0x126C, + .lite_epoch_irq = 0x1270, + .lite_debug_1 = 0x13F0, + .lite_debug_0 = 0x13F4, + .lite_test_bus_ctrl = 0x13F8, + .camif_lite_spare = 0x13FC, + .reg_update_cmd = 0x0020, + }, + { + .lite_hw_version = 0x1400, + .lite_hw_status = 0x1404, + .lite_module_config = 0x1460, + .lite_skip_period = 0x1468, + .lite_irq_subsample_pattern = 0x146C, + .lite_epoch_irq = 0x1470, + .lite_debug_1 = 0x15F0, + .lite_debug_0 = 0x15F4, + .lite_test_bus_ctrl = 0x15F8, + .camif_lite_spare = 0x15FC, + .reg_update_cmd = 0x0020, + }, + { + .lite_hw_version = 0x1600, + .lite_hw_status = 0x1604, + .lite_module_config = 0x1660, + .lite_skip_period = 0x1668, + .lite_irq_subsample_pattern = 0x166C, + .lite_epoch_irq = 0x1670, + .lite_debug_1 = 0x17F0, + .lite_debug_0 = 0x17F4, + .lite_test_bus_ctrl = 0x17F8, + .camif_lite_spare = 0x17FC, + .reg_update_cmd = 0x0020, + }, + { + .lite_hw_version = 0x1800, + .lite_hw_status = 0x1804, + .lite_module_config = 0x1860, + .lite_skip_period = 0x1868, + .lite_irq_subsample_pattern = 0x186C, + .lite_epoch_irq = 0x1870, + .lite_debug_1 = 0x19F0, + .lite_debug_0 = 0x19F4, + .lite_test_bus_ctrl = 0x19F8, + .camif_lite_spare = 0x19FC, + .reg_update_cmd = 0x0020, + }, +}; + +static struct cam_vfe_camif_lite_ver3_reg_data vfe48x_camif_rdi_reg_data[4] = { + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x1, + .epoch0_irq_mask = 0x4, + .epoch1_irq_mask = 0x8, + .eof_irq_mask = 0x02, + .error_irq_mask0 = 0x1, + .error_irq_mask2 = 0x100, + .subscribe_irq_mask1 = 0x3, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x2, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x10, + .epoch0_irq_mask = 0x40, + .epoch1_irq_mask = 0x80, + .eof_irq_mask = 0x20, + .error_irq_mask0 = 0x2, + .error_irq_mask2 = 0x200, + .subscribe_irq_mask1 = 0x30, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x4, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x100, + .epoch0_irq_mask = 0x400, + .epoch1_irq_mask = 0x800, + .eof_irq_mask = 0x200, + .error_irq_mask0 = 0x4, + .error_irq_mask2 = 0x400, + .subscribe_irq_mask1 = 0x300, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, + }, + { + .extern_reg_update_shift = 0, + .reg_update_cmd_data = 0x8, + .epoch_line_cfg = 0x0, + .sof_irq_mask = 0x1000, + .epoch0_irq_mask = 0x4000, + .epoch1_irq_mask = 0x8000, + .eof_irq_mask = 0x2000, + .error_irq_mask0 = 0x8, + .error_irq_mask2 = 0x800, + .subscribe_irq_mask1 = 0x3000, + .enable_diagnostic_hw = 0x1, + .top_debug_cfg_en = 0x1, + }, +}; + +static struct cam_vfe_camif_lite_ver3_hw_info + vfe48x_rdi_hw_info[CAM_VFE_RDI_VER2_MAX] = { + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[0], + .reg_data = &vfe48x_camif_rdi_reg_data[0], + }, + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[1], + .reg_data = &vfe48x_camif_rdi_reg_data[1], + }, + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[2], + .reg_data = &vfe48x_camif_rdi_reg_data[2], + }, + { + .common_reg = &vfe48x_top_common_reg, + .camif_lite_reg = &vfe48x_camif_rdi[3], + .reg_data = &vfe48x_camif_rdi_reg_data[3], + }, +}; + +static struct cam_vfe_top_ver3_hw_info vfe48x_top_hw_info = { + .common_reg = &vfe48x_top_common_reg, + .rdi_hw_info[0] = &vfe48x_rdi_hw_info[0], + .rdi_hw_info[1] = &vfe48x_rdi_hw_info[1], + .rdi_hw_info[2] = &vfe48x_rdi_hw_info[2], + .rdi_hw_info[3] = &vfe48x_rdi_hw_info[3], + .num_mux = 4, + .mux_type = { + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe48x_bus_irq_reg[2] = { + { + .mask_reg_offset = 0x00001A18, + .clear_reg_offset = 0x00001A20, + .status_reg_offset = 0x00001A28, + }, + { + .mask_reg_offset = 0x00001A1C, + .clear_reg_offset = 0x00001A24, + .status_reg_offset = 0x00001A2C, + }, +}; + +static struct cam_vfe_bus_ver3_hw_info vfe48x_bus_hw_info = { + .common_reg = { + .hw_version = 0x00001A00, + .cgc_ovd = 0x00001A08, + .if_frameheader_cfg = { + 0x00001A34, + 0x00001A38, + 0x00001A3C, + 0x00001A40, + }, + .pwr_iso_cfg = 0x00001A5C, + .overflow_status_clear = 0x00001A60, + .ccif_violation_status = 0x00001A64, + .overflow_status = 0x00001A68, + .image_size_violation_status = 0x00001A70, + .debug_status_top_cfg = 0x00001AD4, + .debug_status_top = 0x00001AD8, + .test_bus_ctrl = 0x00001ADC, + .irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe48x_bus_irq_reg, + .global_clear_offset = 0x00001A30, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 4, + .bus_client_reg = { + /* RDI 0 */ + { + .cfg = 0x00001C00, + .image_addr = 0x00001C04, + .frame_incr = 0x00001C08, + .image_cfg_0 = 0x00001C0C, + .image_cfg_1 = 0x00001C10, + .image_cfg_2 = 0x00001C14, + .packer_cfg = 0x00001C18, + .frame_header_addr = 0x00001C20, + .frame_header_incr = 0x00001C24, + .frame_header_cfg = 0x00001C28, + .line_done_cfg = 0x00001C2C, + .irq_subsample_period = 0x00001C30, + .irq_subsample_pattern = 0x00001C34, + .framedrop_period = 0x00001C38, + .framedrop_pattern = 0x00001C3C, + .system_cache_cfg = 0x00001C60, + .burst_limit = 0x00001C64, + .addr_status_0 = 0x00001C68, + .addr_status_1 = 0x00001C6C, + .addr_status_2 = 0x00001C70, + .addr_status_3 = 0x00001C74, + .debug_status_cfg = 0x00001C78, + .debug_status_0 = 0x00001C7C, + .debug_status_1 = 0x00001C80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_0, + .ubwc_regs = NULL, + }, + /* RDI 1 */ + { + .cfg = 0x00001D00, + .image_addr = 0x00001D04, + .frame_incr = 0x00001D08, + .image_cfg_0 = 0x00001D0C, + .image_cfg_1 = 0x00001D10, + .image_cfg_2 = 0x00001D14, + .packer_cfg = 0x00001D18, + .frame_header_addr = 0x00001D20, + .frame_header_incr = 0x00001D24, + .frame_header_cfg = 0x00001D28, + .line_done_cfg = 0x00001D2C, + .irq_subsample_period = 0x00001D30, + .irq_subsample_pattern = 0x00001D34, + .framedrop_period = 0x00001D38, + .framedrop_pattern = 0x00001D3C, + .system_cache_cfg = 0x00001D60, + .burst_limit = 0x00001D64, + .addr_status_0 = 0x00001D68, + .addr_status_1 = 0x00001D6C, + .addr_status_2 = 0x00001D70, + .addr_status_3 = 0x00001D74, + .debug_status_cfg = 0x00001D78, + .debug_status_0 = 0x00001D7C, + .debug_status_1 = 0x00001D80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_1, + .ubwc_regs = NULL, + }, + /* RDI 2 */ + { + .cfg = 0x00001E00, + .image_addr = 0x00001E04, + .frame_incr = 0x00001E08, + .image_cfg_0 = 0x00001E0C, + .image_cfg_1 = 0x00001E10, + .image_cfg_2 = 0x00001E14, + .packer_cfg = 0x00001E18, + .frame_header_addr = 0x00001E20, + .frame_header_incr = 0x00001E24, + .frame_header_cfg = 0x00001E28, + .line_done_cfg = 0x00001E2C, + .irq_subsample_period = 0x00001E30, + .irq_subsample_pattern = 0x00001E34, + .framedrop_period = 0x00001E38, + .framedrop_pattern = 0x00001E3C, + .system_cache_cfg = 0x00001E60, + .burst_limit = 0x00001E64, + .addr_status_0 = 0x00001E68, + .addr_status_1 = 0x00001E6C, + .addr_status_2 = 0x00001E70, + .addr_status_3 = 0x00001E74, + .debug_status_cfg = 0x00001E78, + .debug_status_0 = 0x00001E7C, + .debug_status_1 = 0x00001E80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_2, + .ubwc_regs = NULL, + }, + /* RDI 3 */ + { + .cfg = 0x00001F00, + .image_addr = 0x00001F04, + .frame_incr = 0x00001F08, + .image_cfg_0 = 0x00001F0C, + .image_cfg_1 = 0x00001F10, + .image_cfg_2 = 0x00001F14, + .packer_cfg = 0x00001F18, + .frame_header_addr = 0x00001F20, + .frame_header_incr = 0x00001F24, + .frame_header_cfg = 0x00001F28, + .line_done_cfg = 0x00001F2C, + .irq_subsample_period = 0x00001F30, + .irq_subsample_pattern = 0x00001F34, + .framedrop_period = 0x00001F38, + .framedrop_pattern = 0x00001F3C, + .system_cache_cfg = 0x00001F60, + .burst_limit = 0x00001F64, + .addr_status_0 = 0x00001F68, + .addr_status_1 = 0x00001F6C, + .addr_status_2 = 0x00001F70, + .addr_status_3 = 0x00001F74, + .debug_status_cfg = 0x00001F78, + .debug_status_0 = 0x00001F7C, + .debug_status_1 = 0x00001F80, + .comp_group = CAM_VFE_BUS_VER3_COMP_GRP_3, + .ubwc_regs = NULL, + }, + }, + .num_out = 4, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_0, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_2, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + .max_width = -1, + .max_height = -1, + .source_group = CAM_VFE_BUS_VER3_SRC_GRP_3, + }, + }, + .comp_done_shift = 4, + .top_irq_shift = 4, +}; + +static struct cam_vfe_hw_info cam_vfe_lite48x_hw_info = { + .irq_reg_info = &vfe48x_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_3_0, + .bus_hw_info = &vfe48x_bus_hw_info, + + .top_version = CAM_VFE_TOP_VER_3_0, + .top_hw_info = &vfe48x_top_hw_info, + +}; + +#endif /* _CAM_VFE_LITE48x_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d5ab83c81dd729743f9265253d07a1ad311e6a63 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o cam_vfe_bus_rd_ver1.o cam_vfe_bus_ver3.o diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c new file mode 100644 index 0000000000000000000000000000000000000000..2b902d753ad26ba966a8f2938201bbc949b720e2 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver1.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_vfe_bus_ver3.h" +#include "cam_debug_util.h" + +int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int rc = -ENODEV; + + switch (bus_type) { + case BUS_TYPE_WR: + switch (bus_version) { + case CAM_VFE_BUS_VER_2_0: + rc = cam_vfe_bus_ver2_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + case CAM_VFE_BUS_VER_3_0: + rc = cam_vfe_bus_ver3_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus WR Version 0x%x", + bus_version); + break; + } + break; + case BUS_TYPE_RD: + switch (bus_version) { + case CAM_VFE_BUS_RD_VER_1_0: + /* Call vfe bus rd init function */ + rc = cam_vfe_bus_rd_ver1_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus RD Version 0x%x", + bus_version); + break; + } + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus type %d", bus_type); + break; + } + + return rc; +} + +int cam_vfe_bus_deinit(uint32_t bus_version, + struct cam_vfe_bus **vfe_bus) +{ + int rc = -ENODEV; + + switch (bus_version) { + case CAM_VFE_BUS_VER_2_0: + rc = cam_vfe_bus_ver2_deinit(vfe_bus); + break; + case CAM_VFE_BUS_VER_3_0: + rc = cam_vfe_bus_ver3_deinit(vfe_bus); + break; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus Version %x", bus_version); + break; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c new file mode 100644 index 0000000000000000000000000000000000000000..314ebff70fc0ba0d029e8daf749db90445111f45 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -0,0 +1,1221 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/ratelimit.h> +#include <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_vfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus_rd"; + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_vfe_bus_rd_ver1_reg_offset_bus_client)/4) + +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +enum cam_vfe_bus_rd_ver1_unpacker_format { + BUS_RD_VER1_PACKER_FMT_PLAIN_128 = 0x0, + BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x5, + BUS_RD_VER1_PACKER_FMT_ARGB_10 = 0x6, + BUS_RD_VER1_PACKER_FMT_ARGB_12 = 0x7, + BUS_RD_VER1_PACKER_FMT_ARGB_14 = 0x8, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x9, + BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_32BPP = 0xC, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, + BUS_RD_VER1_PACKER_FMT_MAX = 0xF, +}; + +struct cam_vfe_bus_rd_ver1_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; +}; + +struct cam_vfe_bus_rd_ver1_rm_resource_data { + uint32_t index; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client *hw_regs; + void *ctx; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t hbi_count; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t latency_buf_allocation; + uint32_t unpacker_cfg; + uint32_t burst_len; + + uint32_t go_cmd_sel; + uint32_t fs_sync_enable; + uint32_t fs_line_sync_en; + + uint32_t en_cfg; + uint32_t is_dual; + uint32_t img_addr; + uint32_t input_if_cmd; +}; + +struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data { + uint32_t bus_rd_type; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + + uint32_t num_rm; + struct cam_isp_resource_node *rm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_bus_rd_list; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; +}; + +struct cam_vfe_bus_rd_ver1_priv { + struct cam_vfe_bus_rd_ver1_common_data common_data; + uint32_t num_client; + uint32_t num_bus_rd_resc; + + struct cam_isp_resource_node bus_client[ + CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + struct cam_isp_resource_node vfe_bus_rd[ + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; + + int irq_handle; + int error_irq_handle; +}; + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static enum cam_vfe_bus_rd_ver1_unpacker_format + cam_vfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) +{ + switch (unpack_fmt) { + case CAM_FORMAT_MIPI_RAW_10: + return BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN; + default: + return BUS_RD_VER1_PACKER_FMT_MAX; + } +} + +static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return false; + + default: + return false; + } +} + +static enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type + cam_vfe_bus_get_bus_rd_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_RESOURCE_VFE_BUS_RD: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0; + default: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + } +} + +static int cam_vfe_bus_get_num_rm( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type res_type) +{ + switch (res_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return 1; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported resource_type %u", + res_type); + return -EINVAL; +} + +static int cam_vfe_bus_get_rm_idx( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane) +{ + int rm_idx = -1; + + switch (vfe_bus_rd_res_id) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + switch (plane) { + case PLANE_Y: + rm_idx = 0; + break; + default: + break; + } + break; + default: + break; + } + + return rm_idx; +} + +static int cam_vfe_bus_acquire_rm( + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + void *ctx, + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane, + uint32_t subscribe_irq, + struct cam_isp_resource_node **rm_res, + uint32_t *client_done_mask, + uint32_t is_dual) +{ + uint32_t rm_idx = 0; + struct cam_isp_resource_node *rm_res_local = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = NULL; + + *rm_res = NULL; + *client_done_mask = 0; + + /* No need to allocate for BUS VER2. VFE OUT to RM is fixed. */ + rm_idx = cam_vfe_bus_get_rm_idx(vfe_bus_rd_res_id, plane); + if (rm_idx < 0 || rm_idx >= ver1_bus_rd_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + vfe_bus_rd_res_id, plane); + return -EINVAL; + } + + rm_res_local = &ver1_bus_rd_priv->bus_client[rm_idx]; + if (rm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "RM res not available state:%d", + rm_res_local->res_state); + return -EALREADY; + } + rm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rm_res_local->tasklet_info = tasklet; + + rsrc_data = rm_res_local->res_priv; + rsrc_data->ctx = ctx; + rsrc_data->is_dual = is_dual; + /* Set RM offset value to default */ + rsrc_data->offset = 0; + + *client_done_mask = (1 << rm_idx); + *rm_res = rm_res_local; + + CAM_DBG(CAM_ISP, "RM %d: Acquired"); + return 0; +} + +static int cam_vfe_bus_release_rm(void *bus_priv, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->unpacker_cfg = 0; + rsrc_data->burst_len = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rm_res->tasklet_info = NULL; + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rm_data->common_data; + uint32_t buf_size; + uint32_t val; + uint32_t offset; + + CAM_DBG(CAM_ISP, "w: 0x%x", rm_data->width); + CAM_DBG(CAM_ISP, "h: 0x%x", rm_data->height); + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", rm_data->fs_sync_enable); + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", rm_data->fs_line_sync_en); + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + + /* Write All the values*/ + offset = rm_data->hw_regs->buf_size; + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + cam_io_w_mb(buf_size, common_data->mem_base + offset); + CAM_DBG(CAM_ISP, "buf_size: 0x%x", buf_size); + + val = rm_data->width; + offset = rm_data->hw_regs->stride; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + CAM_DBG(CAM_ISP, "rm_data->unpacker_cfg:0x%x", rm_data->unpacker_cfg); + val = cam_vfe_bus_get_unpacker_fmt(rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, " value:0x%x", val); + offset = rm_data->hw_regs->unpacker_cfg; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + val = rm_data->latency_buf_allocation; + offset = rm_data->hw_regs->latency_buf_allocation; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + cam_io_w_mb(0x1, common_data->mem_base + + rm_data->hw_regs->cfg); + return rc; +} + +static int cam_vfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rsrc_data->common_data; + + /* Disable RM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + + return rc; +} + +static int cam_vfe_bus_init_rm_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_rm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for RM res priv"); + return -ENOMEM; + } + rm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &bus_rd_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver1_bus_rd_priv->common_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = cam_vfe_bus_start_rm; + rm_res->stop = cam_vfe_bus_stop_rm; + rm_res->hw_intf = ver1_bus_rd_priv->common_data.hw_intf; + + + return 0; +} + +static int cam_vfe_bus_deinit_rm_resource( + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = NULL; + rm_res->stop = NULL; + rm_res->top_half_handler = NULL; + rm_res->bottom_half_handler = NULL; + rm_res->hw_intf = NULL; + + rsrc_data = rm_res->res_priv; + rm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type bus_rd_res_id; + int num_rm; + uint32_t subscribe_irq; + uint32_t client_done_mask; + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv = + bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *bus_rd_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + bus_rd_acquire_args = &acq_args->vfe_bus_rd; + + CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", + acq_args->rsrc_type); + + bus_rd_res_id = cam_vfe_bus_get_bus_rd_res_id( + acq_args->rsrc_type); + if (bus_rd_res_id == CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX) + return -ENODEV; + + num_rm = cam_vfe_bus_get_num_rm(bus_rd_res_id); + if (num_rm < 1) + return -EINVAL; + + rsrc_node = &ver1_bus_rd_priv->vfe_bus_rd[bus_rd_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + bus_rd_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + secure_caps = cam_vfe_bus_can_be_secure( + rsrc_data->bus_rd_type); + + mode = bus_rd_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + rsrc_data->num_rm = num_rm; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = bus_rd_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = bus_rd_acquire_args->cdm_ops; + + subscribe_irq = 1; + + for (i = 0; i < num_rm; i++) { + rc = cam_vfe_bus_acquire_rm(ver1_bus_rd_priv, + bus_rd_acquire_args->out_port_info, + acq_args->tasklet, + acq_args->priv, + bus_rd_res_id, + i, + subscribe_irq, + &rsrc_data->rm_res[i], + &client_done_mask, + bus_rd_acquire_args->is_dual); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d RM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + bus_rd_res_id, rc); + goto release_rm; + } + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + bus_rd_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_rm: + for (i--; i >= 0; i--) + cam_vfe_bus_release_rm(ver1_bus_rd_priv, rsrc_data->rm_res[i]); + return rc; +} + +static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_bus_rd = release_args; + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_bus_rd->res_state); + } + + for (i = 0; i < rsrc_data->num_rm; i++) + cam_vfe_bus_release_rm(bus_priv, rsrc_data->rm_res[i]); + rsrc_data->num_rm = 0; + + vfe_bus_rd->tasklet_info = NULL; + vfe_bus_rd->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->bus_rd_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_vfe_bus_rd( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + struct cam_vfe_bus_rd_ver1_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "Start resource type: %x", rsrc_data->bus_rd_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_start_rm(rsrc_data->rm_res[i]); + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_stop_vfe_bus_rd( + struct cam_isp_resource_node *vfe_bus_rd) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + + CAM_DBG(CAM_ISP, "E:Stop rd Res"); + if (!vfe_bus_rd) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "vfe_out res_state is %d", + vfe_bus_rd->res_state); + return rc; + } + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_stop_rm(rsrc_data->rm_res[i]); + + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_init_vfe_bus_read_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info) +{ + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_bus_rd_resc_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + + if (vfe_bus_rd_resc_type < 0 || + vfe_bus_rd_resc_type > CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_bus_rd_resc_type); + return -EINVAL; + } + + vfe_bus_rd = &bus_rd_priv->vfe_bus_rd[vfe_bus_rd_resc_type]; + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_bus_rd->res_priv) { + CAM_ERR(CAM_ISP, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_bus_rd->res_priv = rsrc_data; + + vfe_bus_rd->res_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd->list); + + rsrc_data->bus_rd_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + rsrc_data->common_data = &bus_rd_priv->common_data; + rsrc_data->max_width = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_width; + rsrc_data->max_height = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_bus_rd->start = cam_vfe_bus_start_vfe_bus_rd; + vfe_bus_rd->stop = cam_vfe_bus_stop_vfe_bus_rd; + vfe_bus_rd->process_cmd = cam_vfe_bus_process_cmd; + vfe_bus_rd->hw_intf = bus_rd_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_vfe_bus_rd_resource( + struct cam_isp_resource_node *vfe_bus_rd_res) +{ + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = + vfe_bus_rd_res->res_priv; + + if (vfe_bus_rd_res->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + vfe_bus_rd_res->start = NULL; + vfe_bus_rd_res->stop = NULL; + vfe_bus_rd_res->top_half_handler = NULL; + vfe_bus_rd_res->bottom_half_handler = NULL; + vfe_bus_rd_res->hw_intf = NULL; + + vfe_bus_rd_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd_res->list); + vfe_bus_rd_res->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_ver1_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "BUS READ IRQ Received"); + return 0; +} + +static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + uint32_t val; + uint32_t buf_size = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + update_buf->res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "#of RM: %d", vfe_bus_rd_data->num_rm); + if (update_buf->rm_update->num_buf != vfe_bus_rd_data->num_rm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->rm_update->num_buf, + vfe_bus_rd_data->num_rm); + return -EINVAL; + } + + reg_val_pair = &vfe_bus_rd_data->common_data->io_buf_update[0]; + io_cfg = update_buf->rm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_bus_rd_data->num_rm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + + /* update size register */ + rm_data->width = io_cfg->planes[i].width; + rm_data->height = io_cfg->planes[i].height; + CAM_DBG(CAM_ISP, "RM %d image w 0x%x h 0x%x image size 0x%x", + rm_data->index, rm_data->width, rm_data->height, + buf_size); + + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + + CAM_DBG(CAM_ISP, "size offset 0x%x buf_size 0x%x", + rm_data->hw_regs->buf_size, buf_size); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->buf_size, buf_size); + CAM_DBG(CAM_ISP, "RM %d image size 0x%x", + rm_data->index, reg_val_pair[j-1]); + + val = rm_data->width; + CAM_DBG(CAM_ISP, "io_cfg stride 0x%x", val); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->stride, + val); + rm_data->stride = val; + CAM_DBG(CAM_ISP, "RM %d image stride 0x%x", + rm_data->index, reg_val_pair[j-1]); + + /* RM Image address */ + CAM_DBG(CAM_ISP, "image_addr offset %x", + rm_data->hw_regs->image_addr); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->image_addr, + update_buf->rm_update->image_buf[i] + + rm_data->offset); + CAM_DBG(CAM_ISP, "RM %d image address 0x%x", + rm_data->index, reg_val_pair[j-1]); + rm_data->img_addr = reg_val_pair[j-1]; + + } + + size = vfe_bus_rd_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_bus_rd_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_rd_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_rd_update_fs_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + struct cam_vfe_fe_update_args *fe_upd_args; + struct cam_fe_config *fe_cfg; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + int i = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + fe_upd_args = (struct cam_vfe_fe_update_args *)cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + fe_upd_args->node_res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + fe_cfg = &fe_upd_args->fe_config; + + for (i = 0; i < vfe_bus_rd_data->num_rm; i++) { + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + common_data = rm_data->common_data; + + rm_data->format = fe_cfg->format; + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + + rm_data->unpacker_cfg = fe_cfg->unpacker_cfg; + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + + rm_data->latency_buf_allocation = fe_cfg->latency_buf_size; + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + + rm_data->stride = fe_cfg->stride; + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + + rm_data->go_cmd_sel = fe_cfg->go_cmd_sel; + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + + rm_data->fs_sync_enable = fe_cfg->fs_sync_enable; + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", + rm_data->fs_sync_enable); + + rm_data->hbi_count = fe_cfg->hbi_count; + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + + rm_data->fs_line_sync_en = fe_cfg->fs_line_sync_en; + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", + rm_data->fs_line_sync_en); + + rm_data->fs_mode = fe_cfg->fs_mode; + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + + rm_data->min_vbi = fe_cfg->min_vbi; + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + } + bus_priv->common_data.fs_sync_enable = fe_cfg->fs_sync_enable; + bus_priv->common_data.go_cmd_sel = fe_cfg->go_cmd_sel; + return 0; +} + +static int cam_vfe_bus_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_start_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_stop_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[3] = {0}; + uint32_t offset = 0, val = 0; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + common_reg = bus_priv->common_data.common_reg; + top_irq_reg_mask[0] = (1 << 23); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_rd_ver1_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + bus_priv->irq_handle = 0; + return -EFAULT; + } + /* no clock gating at bus input */ + offset = common_reg->cgc_ovd; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* BUS_RD_TEST_BUS_CTRL */ + offset = common_reg->test_bus_ctrl; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* Read irq mask */ + offset = common_reg->irq_reg_info.irq_reg_set->mask_reg_offset; + cam_io_w_mb(0x5, bus_priv->common_data.mem_base + offset); + + /* INPUT_IF_CMD */ + val = (bus_priv->common_data.fs_sync_enable << 5) | + (bus_priv->common_data.go_cmd_sel << 4); + offset = common_reg->input_if_cmd; + cam_io_w_mb(val, bus_priv->common_data.mem_base + offset); + return 0; +} + +static int cam_vfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->irq_handle); + bus_priv->irq_handle = 0; + } + + return rc; +} + +static int __cam_vfe_bus_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + rc = cam_vfe_bus_rd_update_rm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + rc = cam_vfe_bus_rd_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_rd_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + rc = cam_vfe_bus_rd_update_fs_cfg(priv, cmd_args, arg_size); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info = bus_hw_info; + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_rd_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = bus_rd_hw_info->num_client; + bus_priv->num_bus_rd_resc = + bus_rd_hw_info->num_bus_rd_resc; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &bus_rd_hw_info->common_reg; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &bus_rd_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller, true); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_init_rm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init RM failed rc=%d", rc); + goto deinit_rm; + } + } + + for (i = 0; i < bus_priv->num_bus_rd_resc; i++) { + rc = cam_vfe_bus_init_vfe_bus_read_resource(i, bus_priv, + bus_rd_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed rc=%d", rc); + goto deinit_vfe_bus_rd; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_bus_rd; + vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_bus_rd; + vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_rd_ver1_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + + *vfe_bus = vfe_bus_local; + + return rc; + +deinit_vfe_bus_rd: + if (i < 0) + i = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); +deinit_rm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_rd_bus_ver1_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit RM failed rc=%d", rc); + } + for (i = 0; i < CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; i++) { + rc = cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit VFE Out failed rc=%d", rc); + } + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h new file mode 100644 index 0000000000000000000000000000000000000000..19cc86496371b51bc310aa4c818dd8726d5cf847 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_R_VER1_H_ +#define _CAM_VFE_BUS_R_VER1_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_RD_VER1_MAX_CLIENTS 1 + +enum cam_vfe_bus_rd_ver1_vfe_core_id { + CAM_VFE_BUS_RD_VER1_VFE_CORE_0, + CAM_VFE_BUS_RD_VER1_VFE_CORE_1, + CAM_VFE_BUS_RD_VER1_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_rd_ver1_comp_grp_type { + CAM_VFE_BUS_RD_VER1_COMP_GRP_0, + CAM_VFE_BUS_RD_VER1_COMP_GRP_MAX, +}; + + +enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type { + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX, +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_ovd; + uint32_t pwr_iso_cfg; + uint32_t input_if_cmd; + uint32_t test_bus_ctrl; + struct cam_irq_controller_reg_info irq_reg_info; +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_bus_client { + uint32_t cfg; + uint32_t image_addr; + uint32_t buf_size; + uint32_t stride; + uint32_t unpacker_cfg; + uint32_t latency_buf_allocation; + uint32_t burst_limit; +}; + +/* + * struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info { + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_vfe_bus_rd_ver1_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @bus_client_reg: Bus client register info + * @comp_reg_grp: Composite group register info + * @vfe_out_hw_info: VFE output capability + */ +struct cam_vfe_bus_rd_ver1_hw_info { + struct cam_vfe_bus_rd_ver1_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + uint32_t num_bus_rd_resc; + struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info + vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; +}; + +/* + * cam_vfe_bus_rd_ver1_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_rd_bus_ver1_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_bus_ver1_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_R_VER1_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h new file mode 100644 index 0000000000000000000000000000000000000000..2783ddccf2d82a163a7a871ba5b4cc03d0cb4126 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_VER1_H_ +#define _CAM_VFE_BUS_VER1_H_ + +enum cam_vfe_bus_ver1_pingpong_id { + CAM_VFE_BUS_VER1_PING, + CAM_VFE_BUS_VER1_PONG, + CAM_VFE_BUS_VER1_PINGPONG_MAX, +}; + +enum cam_vfe_bus_ver1_wm_type { + CAM_VFE_BUS_WM_TYPE_IMAGE, + CAM_VFE_BUS_WM_TYPE_STATS, + CAM_VFE_BUS_WM_TYPE_MAX, +}; + +enum cam_vfe_bus_ver1_comp_grp_type { + CAM_VFE_BUS_VER1_COMP_GRP_IMG0, + CAM_VFE_BUS_VER1_COMP_GRP_IMG1, + CAM_VFE_BUS_VER1_COMP_GRP_IMG2, + CAM_VFE_BUS_VER1_COMP_GRP_IMG3, + CAM_VFE_BUS_VER1_COMP_GRP_STATS0, + CAM_VFE_BUS_VER1_COMP_GRP_STATS1, + CAM_VFE_BUS_VER1_COMP_GRP_MAX, +}; + +struct cam_vfe_bus_ver1_common_reg { + uint32_t cmd_offset; + uint32_t cfg_offset; + uint32_t io_fmt_offset; + uint32_t argb_cfg_offset; + uint32_t xbar_cfg0_offset; + uint32_t xbar_cfg1_offset; + uint32_t xbar_cfg2_offset; + uint32_t xbar_cfg3_offset; + uint32_t ping_pong_status_reg; +}; + +struct cam_vfe_bus_ver1_wm_reg { + uint32_t wm_cfg_offset; + uint32_t ping_addr_offset; + uint32_t ping_max_addr_offset; + uint32_t pong_addr_offset; + uint32_t pong_max_addr_offset; + uint32_t addr_cfg_offset; + uint32_t ub_cfg_offset; + uint32_t image_size_offset; + uint32_t buffer_cfg_offset; + uint32_t framedrop_pattern_offset; + uint32_t irq_subsample_pattern_offset; + uint32_t ping_pong_status_bit; /* 0 - 31 */ + uint32_t composite_bit; /* 0 -31 */ +}; + +struct cam_vfe_bus_ver1_wm_resource_data { + uint32_t index; + uint32_t wm_type; + uint32_t res_type; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t scanline; + + uint32_t burst_len; + + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t buf_valid[CAM_VFE_BUS_VER1_PINGPONG_MAX]; + uint32_t ub_size; + uint32_t ub_offset; + + struct cam_vfe_bus_ver1_wm_reg hw_regs; +}; + +struct cam_vfe_bus_ver1_comp_grp_reg { + enum cam_vfe_bus_ver1_comp_grp_type comp_grp_type; + uint32_t comp_grp_offset; +}; + +struct cam_vfe_bus_ver1_comp_grp { + struct cam_vfe_bus_ver1_comp_grp_reg reg_info; + struct list_head wm_list; + uint32_t cur_bit_mask; +}; + +/* + * cam_vfe_bus_ver1_init() + * + * @Brief: Initialize Bus layer + * + * @mem_base: Mapped base address of register space + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + */ +int cam_vfe_bus_ver1_init( + void __iomem *mem_base, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_VER1_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c new file mode 100644 index 0000000000000000000000000000000000000000..9094f1409a66a6202aba151aeb3ff0f6f27f3c52 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -0,0 +1,3781 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/ratelimit.h> +#include <linux/slab.h> +#include <media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus"; + +#define CAM_VFE_BUS_IRQ_REG0 0 +#define CAM_VFE_BUS_IRQ_REG1 1 +#define CAM_VFE_BUS_IRQ_REG2 2 +#define CAM_VFE_BUS_IRQ_MAX 3 + +#define CAM_VFE_BUS_VER2_PAYLOAD_MAX 256 + +#define CAM_VFE_BUS_SET_DEBUG_REG 0x82 + +#define CAM_VFE_RDI_BUS_DEFAULT_WIDTH 0xFF01 +#define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFF01 +#define CAM_VFE_BUS_INTRA_CLIENT_MASK 0x3 +#define CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT 8 +#define CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL \ + ((1 << CAM_VFE_BUS_VER2_MAX_CLIENTS) - 1) + +#define MAX_BUF_UPDATE_REG_NUM \ + ((sizeof(struct cam_vfe_bus_ver2_reg_offset_bus_client) + \ + sizeof(struct cam_vfe_bus_ver2_reg_offset_ubwc_client))/4) +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +static uint32_t bus_error_irq_mask[3] = { + 0x7800, + 0x0000, + 0x0040, +}; + +enum cam_vfe_bus_packer_format { + PACKER_FMT_PLAIN_128 = 0x0, + PACKER_FMT_PLAIN_8 = 0x1, + PACKER_FMT_PLAIN_16_10BPP = 0x2, + PACKER_FMT_PLAIN_16_12BPP = 0x3, + PACKER_FMT_PLAIN_16_14BPP = 0x4, + PACKER_FMT_PLAIN_16_16BPP = 0x5, + PACKER_FMT_ARGB_10 = 0x6, + PACKER_FMT_ARGB_12 = 0x7, + PACKER_FMT_ARGB_14 = 0x8, + PACKER_FMT_PLAIN_32_20BPP = 0x9, + PACKER_FMT_PLAIN_64 = 0xA, + PACKER_FMT_TP_10 = 0xB, + PACKER_FMT_PLAIN_32_32BPP = 0xC, + PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, + PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, + PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, + PACKER_FMT_MAX = 0xF, +}; + +enum cam_vfe_bus_comp_grp_id { + CAM_VFE_BUS_COMP_GROUP_NONE = -EINVAL, + CAM_VFE_BUS_COMP_GROUP_ID_0 = 0x0, + CAM_VFE_BUS_COMP_GROUP_ID_1 = 0x1, + CAM_VFE_BUS_COMP_GROUP_ID_2 = 0x2, + CAM_VFE_BUS_COMP_GROUP_ID_3 = 0x3, + CAM_VFE_BUS_COMP_GROUP_ID_4 = 0x4, + CAM_VFE_BUS_COMP_GROUP_ID_5 = 0x5, +}; + +struct cam_vfe_bus_ver2_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_ver2_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct cam_vfe_bus_irq_evt_payload evt_payload[ + CAM_VFE_BUS_VER2_PAYLOAD_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t addr_no_sync; + cam_hw_mgr_event_cb_func event_cb; + bool hw_init; +}; + +struct cam_vfe_bus_ver2_wm_resource_data { + uint32_t index; + struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_vfe_bus_ver2_reg_offset_bus_client *hw_regs; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + enum cam_vfe_bus_packer_format pack_fmt; + + uint32_t burst_len; + + uint32_t en_ubwc; + bool ubwc_updated; + uint32_t packer_cfg; + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t ubwc_meta_stride; + uint32_t ubwc_mode_cfg_0; + uint32_t ubwc_mode_cfg_1; + uint32_t ubwc_meta_offset; + + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t en_cfg; + uint32_t is_dual; + uint32_t ubwc_lossy_threshold_0; + uint32_t ubwc_lossy_threshold_1; + uint32_t ubwc_bandwidth_limit; +}; + +struct cam_vfe_bus_ver2_comp_grp_data { + enum cam_vfe_bus_ver2_comp_grp_type comp_grp_type; + struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_vfe_bus_ver2_reg_offset_comp_grp *hw_regs; + + uint32_t comp_grp_local_idx; + uint32_t unique_id; + + uint32_t is_master; + uint32_t dual_slave_core; + uint32_t intra_client_mask; + uint32_t composite_mask; + uint32_t addr_sync_mode; + + uint32_t acquire_dev_cnt; +}; + +struct cam_vfe_bus_ver2_vfe_out_data { + uint32_t out_type; + struct cam_vfe_bus_ver2_common_data *common_data; + + uint32_t num_wm; + struct cam_isp_resource_node *wm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_out_list; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; + void *priv; +}; + +struct cam_vfe_bus_ver2_priv { + struct cam_vfe_bus_ver2_common_data common_data; + uint32_t num_client; + uint32_t num_out; + + struct cam_isp_resource_node bus_client[CAM_VFE_BUS_VER2_MAX_CLIENTS]; + struct cam_isp_resource_node comp_grp[CAM_VFE_BUS_VER2_COMP_GRP_MAX]; + struct cam_isp_resource_node vfe_out[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; + + struct list_head free_comp_grp; + struct list_head free_dual_comp_grp; + struct list_head used_comp_grp; + + int irq_handle; + int error_irq_handle; + void *tasklet_info; +}; + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static int cam_vfe_bus_get_evt_payload( + struct cam_vfe_bus_ver2_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + int rc; + + spin_lock(&common_data->spin_lock); + + if (!common_data->hw_init) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d Bus uninitialized", + common_data->core_index); + rc = -EPERM; + goto done; + } + + if (list_empty(&common_data->free_payload_list)) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&common_data->free_payload_list, + struct cam_vfe_bus_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&common_data->spin_lock); + return rc; +} + +static enum cam_vfe_bus_comp_grp_id + cam_vfe_bus_comp_grp_id_convert(uint32_t comp_grp) +{ + switch (comp_grp) { + case CAM_ISP_RES_COMP_GROUP_ID_0: + return CAM_VFE_BUS_COMP_GROUP_ID_0; + case CAM_ISP_RES_COMP_GROUP_ID_1: + return CAM_VFE_BUS_COMP_GROUP_ID_1; + case CAM_ISP_RES_COMP_GROUP_ID_2: + return CAM_VFE_BUS_COMP_GROUP_ID_2; + case CAM_ISP_RES_COMP_GROUP_ID_3: + return CAM_VFE_BUS_COMP_GROUP_ID_3; + case CAM_ISP_RES_COMP_GROUP_ID_4: + return CAM_VFE_BUS_COMP_GROUP_ID_4; + case CAM_ISP_RES_COMP_GROUP_ID_5: + return CAM_VFE_BUS_COMP_GROUP_ID_5; + case CAM_ISP_RES_COMP_GROUP_NONE: + default: + return CAM_VFE_BUS_COMP_GROUP_NONE; + } +} + +static int cam_vfe_bus_put_evt_payload( + struct cam_vfe_bus_ver2_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!common_data) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&common_data->spin_lock, flags); + if (common_data->hw_init) + list_add_tail(&(*evt_payload)->list, + &common_data->free_payload_list); + spin_unlock_irqrestore(&common_data->spin_lock, flags); + + *evt_payload = NULL; + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_bus_ver2_get_intra_client_mask( + enum cam_vfe_bus_ver2_vfe_core_id dual_slave_core, + enum cam_vfe_bus_ver2_vfe_core_id current_core, + uint32_t *intra_client_mask) +{ + int rc = 0; + uint32_t camera_hw_version = 0; + uint32_t version_based_intra_client_mask = 0x1; + + *intra_client_mask = 0; + + + if (dual_slave_core == current_core) { + CAM_ERR(CAM_ISP, + "Invalid params. Same core as Master and Slave"); + return -EINVAL; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + + CAM_DBG(CAM_ISP, "CPAS VERSION %d", camera_hw_version); + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + version_based_intra_client_mask = 0x3; + break; + default: + version_based_intra_client_mask = 0x1; + break; + } + + + switch (current_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_0: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_1: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_CORE_1: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER2_VFE_CORE_0: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + default: + CAM_ERR(CAM_ISP, + "Invalid value for master core %u", current_core); + rc = -EINVAL; + break; + } + + return rc; +} + +static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + case CAM_VFE_BUS_VER2_VFE_OUT_FD: + case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + return true; + + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + case CAM_VFE_BUS_VER2_VFE_OUT_2PD: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST: + default: + return false; + } +} + +static enum cam_vfe_bus_ver2_vfe_out_type + cam_vfe_bus_get_out_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_IFE_OUT_RES_FULL: + return CAM_VFE_BUS_VER2_VFE_OUT_FULL; + case CAM_ISP_IFE_OUT_RES_DS4: + return CAM_VFE_BUS_VER2_VFE_OUT_DS4; + case CAM_ISP_IFE_OUT_RES_DS16: + return CAM_VFE_BUS_VER2_VFE_OUT_DS16; + case CAM_ISP_IFE_OUT_RES_FD: + return CAM_VFE_BUS_VER2_VFE_OUT_FD; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP; + case CAM_ISP_IFE_OUT_RES_PDAF: + return CAM_VFE_BUS_VER2_VFE_OUT_PDAF; + case CAM_ISP_IFE_OUT_RES_2PD: + return CAM_VFE_BUS_VER2_VFE_OUT_2PD; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI0; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI1; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI2; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return CAM_VFE_BUS_VER2_VFE_OUT_RDI3; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS; + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + return CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP; + default: + return CAM_VFE_BUS_VER2_VFE_OUT_MAX; + } +} + +static int cam_vfe_bus_get_num_wm( + enum cam_vfe_bus_ver2_vfe_out_type res_type, + uint32_t format) +{ + switch (res_type) { + case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER2_VFE_OUT_RDI3: + switch (format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_DPCM_10_6_10: + case CAM_FORMAT_DPCM_10_8_10: + case CAM_FORMAT_DPCM_12_6_12: + case CAM_FORMAT_DPCM_12_8_12: + case CAM_FORMAT_DPCM_14_8_14: + case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + case CAM_FORMAT_PLAIN128: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_UBWC_P010: + case CAM_FORMAT_PLAIN16_10: + return 2; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FD: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_PLAIN16_10: + return 2; + case CAM_FORMAT_Y_ONLY: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + switch (format) { + case CAM_FORMAT_PD8: + case CAM_FORMAT_PD10: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP: + switch (format) { + case CAM_FORMAT_ARGB_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + switch (format) { + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_2PD: + switch (format) { + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS: + switch (format) { + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST: + switch (format) { + case CAM_FORMAT_PLAIN16_16: + return 1; + default: + break; + } + break; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported format %u for resource_type %u", + format, res_type); + + return -EINVAL; +} + +static int cam_vfe_bus_get_wm_idx( + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane) +{ + int wm_idx = -1; + + switch (vfe_out_res_id) { + case CAM_VFE_BUS_VER2_VFE_OUT_RDI0: + switch (plane) { + case PLANE_Y: + wm_idx = 0; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RDI1: + switch (plane) { + case PLANE_Y: + wm_idx = 1; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RDI2: + switch (plane) { + case PLANE_Y: + wm_idx = 2; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RDI3: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + case PLANE_C: + wm_idx = 4; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + switch (plane) { + case PLANE_Y: + wm_idx = 5; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + switch (plane) { + case PLANE_Y: + wm_idx = 6; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FD: + switch (plane) { + case PLANE_Y: + wm_idx = 7; + break; + case PLANE_C: + wm_idx = 8; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP: + switch (plane) { + case PLANE_Y: + wm_idx = 9; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + case CAM_VFE_BUS_VER2_VFE_OUT_2PD: + switch (plane) { + case PLANE_Y: + wm_idx = 10; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE: + switch (plane) { + case PLANE_Y: + wm_idx = 11; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 12; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 13; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF: + switch (plane) { + case PLANE_Y: + wm_idx = 14; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 15; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 16; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS: + switch (plane) { + case PLANE_Y: + wm_idx = 17; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS: + switch (plane) { + case PLANE_Y: + wm_idx = 18; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 19; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 20; + break; + case PLANE_C: + wm_idx = 21; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 22; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 23; + break; + default: + break; + } + break; + + default: + break; + } + + return wm_idx; +} + +static void cam_vfe_bus_get_comp_vfe_out_res_id_list( + uint32_t comp_mask, uint32_t *out_list, int *num_out) +{ + int count = 0; + + if (comp_mask & 0x1) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_0; + + if (comp_mask & 0x2) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (comp_mask & 0x4) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_2; + + if ((comp_mask & 0x8) && (((comp_mask >> 4) & 0x1) == 0)) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_3; + + if (comp_mask & 0x18) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL; + + if (comp_mask & 0x20) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4; + + if (comp_mask & 0x40) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16; + + if (comp_mask & 0x180) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FD; + + if (comp_mask & 0x200) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RAW_DUMP; + + if (comp_mask & 0x800) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BE; + + if (comp_mask & 0x1000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST; + + if (comp_mask & 0x2000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_TL_BG; + + if (comp_mask & 0x4000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BF; + + if (comp_mask & 0x8000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_AWB_BG; + + if (comp_mask & 0x10000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BHIST; + + if (comp_mask & 0x20000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_RS; + + if (comp_mask & 0x40000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_CS; + + if (comp_mask & 0x80000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_IHIST; + + if (comp_mask & 0x300000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL_DISP; + + if (comp_mask & 0x400000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4_DISP; + + if (comp_mask & 0x800000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16_DISP; + + *num_out = count; + +} + +static enum cam_vfe_bus_packer_format + cam_vfe_bus_get_packer_fmt(uint32_t out_fmt, int wm_index) +{ + switch (out_fmt) { + case CAM_FORMAT_NV21: + if ((wm_index == 4) || (wm_index == 6) || (wm_index == 21)) + return PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN; + case CAM_FORMAT_NV12: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_Y_ONLY: + return PACKER_FMT_PLAIN_8_LSB_MSB_10; + case CAM_FORMAT_PLAIN16_16: + return PACKER_FMT_PLAIN_16_16BPP; + case CAM_FORMAT_PLAIN64: + return PACKER_FMT_PLAIN_64; + case CAM_FORMAT_PLAIN8: + return PACKER_FMT_PLAIN_8; + case CAM_FORMAT_PLAIN16_10: + return PACKER_FMT_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return PACKER_FMT_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return PACKER_FMT_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN32_20: + return PACKER_FMT_PLAIN_32_20BPP; + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PD8: + case CAM_FORMAT_PD10: + return PACKER_FMT_PLAIN_128; + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_TP10: + return PACKER_FMT_TP_10; + case CAM_FORMAT_ARGB_14: + return PACKER_FMT_ARGB_14; + default: + return PACKER_FMT_MAX; + } +} + +static int cam_vfe_bus_acquire_wm( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_isp_resource_node **wm_res, + uint32_t *client_done_mask, + uint32_t is_dual) +{ + uint32_t wm_idx = 0; + struct cam_isp_resource_node *wm_res_local = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = NULL; + + *wm_res = NULL; + *client_done_mask = 0; + + /* No need to allocate for BUS VER2. VFE OUT to WM is fixed. */ + wm_idx = cam_vfe_bus_get_wm_idx(vfe_out_res_id, plane); + if (wm_idx < 0 || wm_idx >= ver2_bus_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + vfe_out_res_id, plane); + return -EINVAL; + } + + wm_res_local = &ver2_bus_priv->bus_client[wm_idx]; + if (wm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "WM res not available state:%d", + wm_res_local->res_state); + return -EALREADY; + } + wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + wm_res_local->tasklet_info = tasklet; + + rsrc_data = wm_res_local->res_priv; + rsrc_data->format = out_port_info->format; + rsrc_data->pack_fmt = cam_vfe_bus_get_packer_fmt(rsrc_data->format, + wm_idx); + + rsrc_data->width = out_port_info->width; + rsrc_data->height = out_port_info->height; + rsrc_data->is_dual = is_dual; + /* Set WM offset value to default */ + rsrc_data->offset = 0; + CAM_DBG(CAM_ISP, "WM %d width %d height %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + + if (rsrc_data->index < 3) { + /* Write master 0-2 refers to RDI 0/ RDI 1/RDI 2 */ + switch (rsrc_data->format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN128: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->pack_fmt = 0x0; + rsrc_data->en_cfg = 0x3; + break; + case CAM_FORMAT_PLAIN8: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x1; + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + break; + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->pack_fmt = 0x0; + rsrc_data->en_cfg = 0x3; + break; + case CAM_FORMAT_PLAIN64: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0xA; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported RDI format %d", + rsrc_data->format); + return -EINVAL; + } + } else if ((rsrc_data->index < 5) || + (rsrc_data->index == 7) || (rsrc_data->index == 8) || + (rsrc_data->index == 20) || (rsrc_data->index == 21)) { + /* + * Write master 3, 4 - for Full OUT , 7-8 FD OUT, + * WM 20-21 = FULL_DISP + */ + switch (rsrc_data->format) { + case CAM_FORMAT_UBWC_NV12_4R: + rsrc_data->en_ubwc = 1; + rsrc_data->width = ALIGNUP(rsrc_data->width, 64); + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_NV12: + rsrc_data->en_ubwc = 1; + /* Fall through for NV12 */ + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_Y_ONLY: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_TP10: + rsrc_data->en_ubwc = 1; + rsrc_data->width = + ALIGNUP(rsrc_data->width, 48) * 4 / 3; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_TP10: + rsrc_data->width = + ALIGNUP(rsrc_data->width, 3) * 4 / 3; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_PLAIN16_10: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + rsrc_data->width *= 2; + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + rsrc_data->en_cfg = 0x1; + } else if (rsrc_data->index >= 11 && rsrc_data->index < 20) { + /* Write master 11 - 19 stats */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = 0x3; + } else if (rsrc_data->index == 10) { + /* Write master 10 - PDAF/2PD */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = 0x3; + if (vfe_out_res_id == CAM_VFE_BUS_VER2_VFE_OUT_PDAF) + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else if (rsrc_data->index == 9) { + /* Write master 9 - Raw dump */ + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else { + /* Write master 5-6 DS ports */ + uint32_t align_width; + + rsrc_data->width = rsrc_data->width * 4; + rsrc_data->height = rsrc_data->height / 2; + rsrc_data->en_cfg = 0x1; + CAM_DBG(CAM_ISP, "before width %d", rsrc_data->width); + align_width = ALIGNUP(rsrc_data->width, 16); + if (align_width != rsrc_data->width) { + CAM_WARN(CAM_ISP, + "Override width %u with expected %u", + rsrc_data->width, align_width); + rsrc_data->width = align_width; + } + } + + *client_done_mask = (1 << wm_idx); + *wm_res = wm_res_local; + + CAM_DBG(CAM_ISP, "WM %d: processed width %d, processed height %d", + rsrc_data->index, rsrc_data->width, rsrc_data->height); + return 0; +} + +static int cam_vfe_bus_release_wm(void *bus_priv, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + wm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->pack_fmt = 0; + rsrc_data->burst_len = 0; + rsrc_data->irq_subsample_period = 0; + rsrc_data->irq_subsample_pattern = 0; + rsrc_data->framedrop_period = 0; + rsrc_data->framedrop_pattern = 0; + rsrc_data->packer_cfg = 0; + rsrc_data->en_ubwc = 0; + rsrc_data->tile_cfg = 0; + rsrc_data->h_init = 0; + rsrc_data->v_init = 0; + rsrc_data->ubwc_meta_stride = 0; + rsrc_data->ubwc_mode_cfg_0 = 0; + rsrc_data->ubwc_mode_cfg_1 = 0; + rsrc_data->ubwc_meta_offset = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rsrc_data->ubwc_lossy_threshold_0 = 0; + rsrc_data->ubwc_lossy_threshold_1 = 0; + rsrc_data->ubwc_bandwidth_limit = 0; + wm_res->tasklet_info = NULL; + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_wm( + struct cam_isp_resource_node *wm_res, + uint32_t *bus_irq_reg_mask) +{ + int rc = 0, val = 0; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver2_common_data *common_data = + rsrc_data->common_data; + uint32_t camera_hw_version; + + cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); + + cam_io_w_mb(rsrc_data->width, + common_data->mem_base + rsrc_data->hw_regs->buffer_width_cfg); + cam_io_w(rsrc_data->height, + common_data->mem_base + rsrc_data->hw_regs->buffer_height_cfg); + cam_io_w(rsrc_data->pack_fmt, + common_data->mem_base + rsrc_data->hw_regs->packer_cfg); + + /* Configure stride for RDIs */ + if (rsrc_data->index < 3) + cam_io_w_mb(rsrc_data->stride, (common_data->mem_base + + rsrc_data->hw_regs->stride)); + + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG1] = (1 << rsrc_data->index); + + /* enable ubwc if needed*/ + if (rsrc_data->en_ubwc) { + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version:%d rc:%d", + camera_hw_version, rc); + return rc; + } + if ((camera_hw_version > CAM_CPAS_TITAN_NONE) && + (camera_hw_version < CAM_CPAS_TITAN_175_V100)) { + struct cam_vfe_bus_ver2_reg_offset_ubwc_client + *ubwc_regs; + + ubwc_regs = + (struct + cam_vfe_bus_ver2_reg_offset_ubwc_client *) + rsrc_data->hw_regs->ubwc_regs; + val = cam_io_r_mb(common_data->mem_base + + ubwc_regs->mode_cfg_0); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + + ubwc_regs->mode_cfg_0); + } else if ((camera_hw_version == CAM_CPAS_TITAN_175_V100) || + (camera_hw_version == CAM_CPAS_TITAN_175_V101) || + (camera_hw_version == CAM_CPAS_TITAN_175_V120) || + (camera_hw_version == CAM_CPAS_TITAN_175_V130)) { + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + *ubwc_regs; + + ubwc_regs = + (struct + cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + rsrc_data->hw_regs->ubwc_regs; + val = cam_io_r_mb(common_data->mem_base + + ubwc_regs->mode_cfg_0); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + + ubwc_regs->mode_cfg_0); + } else { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + return -EINVAL; + } + } + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); + + CAM_DBG(CAM_ISP, "WM res %d width = %d, height = %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + CAM_DBG(CAM_ISP, "WM res %d pk_fmt = %d", rsrc_data->index, + rsrc_data->pack_fmt & PACKER_FMT_MAX); + CAM_DBG(CAM_ISP, "WM res %d stride = %d, burst len = %d", + rsrc_data->index, rsrc_data->stride, 0xf); + CAM_DBG(CAM_ISP, "enable WM res %d offset 0x%x val 0x%x", + rsrc_data->index, (uint32_t) rsrc_data->hw_regs->cfg, + rsrc_data->en_cfg); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) +{ + int rc = 0; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver2_common_data *common_data = + rsrc_data->common_data; + + /* Disable WM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + + /* Disable all register access, reply on global reset */ + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + + return rc; +} + +static int cam_vfe_bus_handle_wm_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_handle_wm_done_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *wm_res = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = + (wm_res == NULL) ? NULL : wm_res->res_priv; + uint32_t *cam_ife_irq_regs; + uint32_t status_reg; + + if (!evt_payload || !wm_res || !rsrc_data) + return rc; + + CAM_DBG(CAM_ISP, "addr of evt_payload = %llx core index:0x%x", + (uint64_t)evt_payload, evt_payload->core_index); + CAM_DBG(CAM_ISP, "bus_irq_status_0: = %x", evt_payload->irq_reg_val[0]); + CAM_DBG(CAM_ISP, "bus_irq_status_1: = %x", evt_payload->irq_reg_val[1]); + CAM_DBG(CAM_ISP, "bus_irq_status_2: = %x", evt_payload->irq_reg_val[2]); + CAM_DBG(CAM_ISP, "bus_irq_comp_err: = %x", evt_payload->irq_reg_val[3]); + CAM_DBG(CAM_ISP, "bus_irq_comp_owrt: = %x", + evt_payload->irq_reg_val[4]); + CAM_DBG(CAM_ISP, "bus_irq_dual_comp_err: = %x", + evt_payload->irq_reg_val[5]); + CAM_DBG(CAM_ISP, "bus_irq_dual_comp_owrt: = %x", + evt_payload->irq_reg_val[6]); + + cam_ife_irq_regs = evt_payload->irq_reg_val; + status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1]; + + if (status_reg & BIT(rsrc_data->index)) { + cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1] &= + ~BIT(rsrc_data->index); + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + } + CAM_DBG(CAM_ISP, "status_reg %x rc %d wm_idx %d", + status_reg, rc, rsrc_data->index); + + return rc; +} + + +static int cam_vfe_bus_err_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver2_priv *bus_priv = handler_priv; + struct cam_vfe_bus_ver2_common_data *common_data; + struct cam_isp_hw_event_info evt_info; + uint32_t val = 0; + + if (!handler_priv || !evt_payload_priv) + return -EINVAL; + + evt_payload = evt_payload_priv; + common_data = &bus_priv->common_data; + + val = evt_payload->debug_status_0; + CAM_ERR(CAM_ISP, "Bus Violation: debug_status_0 = 0x%x", val); + + if (val & 0x01) + CAM_INFO(CAM_ISP, "RDI 0 violation"); + + if (val & 0x02) + CAM_INFO(CAM_ISP, "RDI 1 violation"); + + if (val & 0x04) + CAM_INFO(CAM_ISP, "RDI 2 violation"); + + if (val & 0x08) + CAM_INFO(CAM_ISP, "VID Y 1:1 UBWC violation"); + + if (val & 0x010) + CAM_INFO(CAM_ISP, "VID C 1:1 UBWC violation"); + + if (val & 0x020) + CAM_INFO(CAM_ISP, "VID YC 4:1 violation"); + + if (val & 0x040) + CAM_INFO(CAM_ISP, "VID YC 16:1 violation"); + + if (val & 0x080) + CAM_INFO(CAM_ISP, "FD Y violation"); + + if (val & 0x0100) + CAM_INFO(CAM_ISP, "FD C violation"); + + if (val & 0x0200) + CAM_INFO(CAM_ISP, "RAW DUMP violation"); + + if (val & 0x0400) + CAM_INFO(CAM_ISP, "PDAF violation"); + + if (val & 0x0800) + CAM_INFO(CAM_ISP, "STATs HDR BE violation"); + + if (val & 0x01000) + CAM_INFO(CAM_ISP, "STATs HDR BHIST violation"); + + if (val & 0x02000) + CAM_INFO(CAM_ISP, "STATs TINTLESS BG violation"); + + if (val & 0x04000) + CAM_INFO(CAM_ISP, "STATs BF violation"); + + if (val & 0x08000) + CAM_INFO(CAM_ISP, "STATs AWB BG UBWC violation"); + + if (val & 0x010000) + CAM_INFO(CAM_ISP, "STATs BHIST violation"); + + if (val & 0x020000) + CAM_INFO(CAM_ISP, "STATs RS violation"); + + if (val & 0x040000) + CAM_INFO(CAM_ISP, "STATs CS violation"); + + if (val & 0x080000) + CAM_INFO(CAM_ISP, "STATs IHIST violation"); + + if (val & 0x0100000) + CAM_INFO(CAM_ISP, "DISP Y 1:1 UBWC violation"); + + if (val & 0x0200000) + CAM_INFO(CAM_ISP, "DISP C 1:1 UBWC violation"); + + if (val & 0x0400000) + CAM_INFO(CAM_ISP, "DISP YC 4:1 violation"); + + if (val & 0x0800000) + CAM_INFO(CAM_ISP, "DISP YC 16:1 violation"); + + cam_vfe_bus_put_evt_payload(common_data, &evt_payload); + + evt_info.hw_idx = common_data->core_index; + evt_info.res_type = CAM_ISP_RESOURCE_VFE_OUT; + evt_info.res_id = CAM_VFE_BUS_VER2_VFE_OUT_MAX; + + if (common_data->event_cb) + common_data->event_cb(NULL, CAM_ISP_HW_EVENT_ERROR, + (void *)&evt_info); + + return 0; +} + +static int cam_vfe_bus_init_wm_resource(uint32_t index, + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_wm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for WM res priv"); + return -ENOMEM; + } + wm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &ver2_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver2_bus_priv->common_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = cam_vfe_bus_handle_wm_done_top_half; + wm_res->bottom_half_handler = cam_vfe_bus_handle_wm_done_bottom_half; + wm_res->hw_intf = ver2_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_wm_resource( + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = NULL; + wm_res->bottom_half_handler = NULL; + wm_res->hw_intf = NULL; + + rsrc_data = wm_res->res_priv; + wm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_vfe_bus_add_wm_to_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t composite_mask) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = comp_grp->res_priv; + + rsrc_data->composite_mask |= composite_mask; +} + +static void cam_vfe_bus_match_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_local_idx, + uint32_t unique_id) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + struct cam_isp_resource_node *comp_grp_local = NULL; + + list_for_each_entry(comp_grp_local, + &ver2_bus_priv->used_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_local_idx == comp_grp_local_idx && + rsrc_data->unique_id == unique_id) { + /* Match found */ + *comp_grp = comp_grp_local; + return; + } + } + + *comp_grp = NULL; +} + +static int cam_vfe_bus_acquire_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + uint32_t unique_id, + uint32_t is_dual, + uint32_t is_master, + enum cam_vfe_bus_ver2_vfe_core_id dual_slave_core, + struct cam_isp_resource_node **comp_grp) +{ + int rc = 0; + uint32_t bus_comp_grp_id; + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + + bus_comp_grp_id = cam_vfe_bus_comp_grp_id_convert( + out_port_info->comp_grp_id); + /* Perform match only if there is valid comp grp request */ + if (out_port_info->comp_grp_id != CAM_ISP_RES_COMP_GROUP_NONE) { + /* Check if matching comp_grp already acquired */ + cam_vfe_bus_match_comp_grp(ver2_bus_priv, &comp_grp_local, + bus_comp_grp_id, unique_id); + } + + if (!comp_grp_local) { + /* First find a free group */ + if (is_dual) { + CAM_DBG(CAM_ISP, "Acquire dual comp group"); + if (list_empty(&ver2_bus_priv->free_dual_comp_grp)) { + CAM_ERR(CAM_ISP, "No Free Composite Group"); + return -ENODEV; + } + comp_grp_local = list_first_entry( + &ver2_bus_priv->free_dual_comp_grp, + struct cam_isp_resource_node, list); + rsrc_data = comp_grp_local->res_priv; + rc = cam_vfe_bus_ver2_get_intra_client_mask( + dual_slave_core, + comp_grp_local->hw_intf->hw_idx, + &rsrc_data->intra_client_mask); + if (rc) + return rc; + } else { + CAM_DBG(CAM_ISP, "Acquire comp group"); + if (list_empty(&ver2_bus_priv->free_comp_grp)) { + CAM_ERR(CAM_ISP, "No Free Composite Group"); + return -ENODEV; + } + comp_grp_local = list_first_entry( + &ver2_bus_priv->free_comp_grp, + struct cam_isp_resource_node, list); + rsrc_data = comp_grp_local->res_priv; + } + + list_del(&comp_grp_local->list); + comp_grp_local->tasklet_info = tasklet; + comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + rsrc_data->is_master = is_master; + rsrc_data->composite_mask = 0; + rsrc_data->unique_id = unique_id; + rsrc_data->comp_grp_local_idx = bus_comp_grp_id; + + if (is_master) + rsrc_data->addr_sync_mode = 0; + else + rsrc_data->addr_sync_mode = 1; + + list_add_tail(&comp_grp_local->list, + &ver2_bus_priv->used_comp_grp); + + } else { + rsrc_data = comp_grp_local->res_priv; + /* Do not support runtime change in composite mask */ + if (comp_grp_local->res_state == + CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d Comp Grp %u", + comp_grp_local->res_state, + rsrc_data->comp_grp_type); + return -EBUSY; + } + } + + CAM_DBG(CAM_ISP, "Comp Grp type %u", rsrc_data->comp_grp_type); + + rsrc_data->acquire_dev_cnt++; + *comp_grp = comp_grp_local; + + return rc; +} + +static int cam_vfe_bus_release_comp_grp( + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_isp_resource_node *in_comp_grp) +{ + struct cam_isp_resource_node *comp_grp = NULL; + struct cam_vfe_bus_ver2_comp_grp_data *in_rsrc_data = NULL; + int match_found = 0; + + if (!in_comp_grp) { + CAM_ERR(CAM_ISP, "Invalid Params Comp Grp %pK", in_comp_grp); + return -EINVAL; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Already released Comp Grp"); + return 0; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d", + in_comp_grp->res_state); + return -EBUSY; + } + + in_rsrc_data = in_comp_grp->res_priv; + CAM_DBG(CAM_ISP, "Comp Grp type %u", in_rsrc_data->comp_grp_type); + + list_for_each_entry(comp_grp, &ver2_bus_priv->used_comp_grp, list) { + if (comp_grp == in_comp_grp) { + match_found = 1; + break; + } + } + + if (!match_found) { + CAM_ERR(CAM_ISP, "Could not find matching Comp Grp type %u", + in_rsrc_data->comp_grp_type); + return -ENODEV; + } + + in_rsrc_data->acquire_dev_cnt--; + if (in_rsrc_data->acquire_dev_cnt == 0) { + list_del(&comp_grp->list); + + in_rsrc_data->unique_id = 0; + in_rsrc_data->comp_grp_local_idx = CAM_VFE_BUS_COMP_GROUP_NONE; + in_rsrc_data->composite_mask = 0; + in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX; + in_rsrc_data->addr_sync_mode = 0; + + comp_grp->tasklet_info = NULL; + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + if (in_rsrc_data->comp_grp_type >= + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 && + in_rsrc_data->comp_grp_type <= + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5) + list_add_tail(&comp_grp->list, + &ver2_bus_priv->free_dual_comp_grp); + else if (in_rsrc_data->comp_grp_type >= + CAM_VFE_BUS_VER2_COMP_GRP_0 && + in_rsrc_data->comp_grp_type <= + CAM_VFE_BUS_VER2_COMP_GRP_5) + list_add_tail(&comp_grp->list, + &ver2_bus_priv->free_comp_grp); + } + + return 0; +} + +static int cam_vfe_bus_start_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t *bus_irq_reg_mask) +{ + int rc = 0; + uint32_t addr_sync_cfg; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = + comp_grp->res_priv; + struct cam_vfe_bus_ver2_common_data *common_data = + rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "comp group id:%d streaming state:%d", + rsrc_data->comp_grp_type, comp_grp->res_state); + + cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base + + rsrc_data->hw_regs->comp_mask); + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + return 0; + + CAM_DBG(CAM_ISP, "composite_mask is 0x%x", rsrc_data->composite_mask); + CAM_DBG(CAM_ISP, "composite_mask addr 0x%x", + rsrc_data->hw_regs->comp_mask); + + if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 && + rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5) { + int dual_comp_grp = (rsrc_data->comp_grp_type - + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0); + + if (rsrc_data->is_master) { + int intra_client_en = cam_io_r_mb( + common_data->mem_base + + common_data->common_reg->dual_master_comp_cfg); + + /* + * 2 Bits per comp_grp. Hence left shift by + * comp_grp * 2 + */ + intra_client_en |= + (rsrc_data->intra_client_mask << + (dual_comp_grp * 2)); + + cam_io_w_mb(intra_client_en, common_data->mem_base + + common_data->common_reg->dual_master_comp_cfg); + + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG2] = + (1 << dual_comp_grp); + } + + CAM_DBG(CAM_ISP, "addr_sync_mask addr 0x%x", + rsrc_data->hw_regs->addr_sync_mask); + cam_io_w_mb(rsrc_data->composite_mask, common_data->mem_base + + rsrc_data->hw_regs->addr_sync_mask); + + addr_sync_cfg = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->addr_sync_cfg); + addr_sync_cfg |= (rsrc_data->addr_sync_mode << dual_comp_grp); + /* + * 2 Bits per dual_comp_grp. dual_comp_grp stats at bit number + * 8. Hence left shift cdual_comp_grp dual comp_grp * 2 and + * add 8 + */ + addr_sync_cfg |= + (rsrc_data->intra_client_mask << + ((dual_comp_grp * 2) + + CAM_VFE_BUS_ADDR_SYNC_INTRA_CLIENT_SHIFT)); + cam_io_w_mb(addr_sync_cfg, common_data->mem_base + + common_data->common_reg->addr_sync_cfg); + + common_data->addr_no_sync &= ~(rsrc_data->composite_mask); + cam_io_w_mb(common_data->addr_no_sync, common_data->mem_base + + common_data->common_reg->addr_sync_no_sync); + CAM_DBG(CAM_ISP, "addr_sync_cfg: 0x%x addr_no_sync_cfg: 0x%x", + addr_sync_cfg, common_data->addr_no_sync); + } else { + /* IRQ bits for COMP GRP start at 5. So add 5 to the shift */ + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG0] = + (1 << (rsrc_data->comp_grp_type + 5)); + } + + CAM_DBG(CAM_ISP, "VFE start COMP_GRP%d", rsrc_data->comp_grp_type); + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_vfe_bus_stop_comp_grp(struct cam_isp_resource_node *comp_grp) +{ + int rc = 0; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_bus_handle_comp_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_handle_comp_done_bottom_half(void *handler_priv, + void *evt_payload_priv, uint32_t *comp_mask) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *comp_grp = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = comp_grp->res_priv; + uint32_t *cam_ife_irq_regs; + uint32_t status_reg; + uint32_t comp_err_reg; + uint32_t comp_grp_id; + + CAM_DBG(CAM_ISP, "comp grp type %d", rsrc_data->comp_grp_type); + + if (!evt_payload) + return rc; + + cam_ife_irq_regs = evt_payload->irq_reg_val; + + switch (rsrc_data->comp_grp_type) { + case CAM_VFE_BUS_VER2_COMP_GRP_0: + case CAM_VFE_BUS_VER2_COMP_GRP_1: + case CAM_VFE_BUS_VER2_COMP_GRP_2: + case CAM_VFE_BUS_VER2_COMP_GRP_3: + case CAM_VFE_BUS_VER2_COMP_GRP_4: + case CAM_VFE_BUS_VER2_COMP_GRP_5: + comp_grp_id = (rsrc_data->comp_grp_type - + CAM_VFE_BUS_VER2_COMP_GRP_0); + + /* Check for Regular composite error */ + status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0]; + + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_COMP_ERR]; + if ((status_reg & BIT(11)) && + (comp_err_reg & rsrc_data->composite_mask)) { + /* Check for Regular composite error */ + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_ERR_COMP; + break; + } + + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_COMP_OWRT]; + /* Check for Regular composite Overwrite */ + if ((status_reg & BIT(12)) && + (comp_err_reg & rsrc_data->composite_mask)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_COMP_OWRT; + break; + } + + /* Regular Composite SUCCESS */ + if (status_reg & BIT(comp_grp_id + 5)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + CAM_DBG(CAM_ISP, "status reg = 0x%x, bit index = %d rc %d", + status_reg, (comp_grp_id + 5), rc); + break; + + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4: + case CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5: + comp_grp_id = (rsrc_data->comp_grp_type - + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0); + + /* Check for DUAL composite error */ + status_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2]; + + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_DUAL_COMP_ERR]; + if ((status_reg & BIT(6)) && + (comp_err_reg & rsrc_data->composite_mask)) { + /* Check for DUAL composite error */ + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_ERR_COMP; + break; + } + + /* Check for Dual composite Overwrite */ + comp_err_reg = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_DUAL_COMP_OWRT]; + if ((status_reg & BIT(7)) && + (comp_err_reg & rsrc_data->composite_mask)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + rc = CAM_VFE_IRQ_STATUS_COMP_OWRT; + break; + } + + /* DUAL Composite SUCCESS */ + if (status_reg & BIT(comp_grp_id)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + break; + default: + rc = CAM_VFE_IRQ_STATUS_ERR; + CAM_ERR(CAM_ISP, "Invalid comp_grp_type %u", + rsrc_data->comp_grp_type); + break; + } + + *comp_mask = rsrc_data->composite_mask; + + return rc; +} + +static int cam_vfe_bus_init_comp_grp(uint32_t index, + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_comp_grp_data), + GFP_KERNEL); + if (!rsrc_data) + return -ENOMEM; + + comp_grp->res_priv = rsrc_data; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&comp_grp->list); + + rsrc_data->comp_grp_type = index; + rsrc_data->common_data = &ver2_bus_priv->common_data; + rsrc_data->hw_regs = &ver2_hw_info->comp_grp_reg[index]; + rsrc_data->dual_slave_core = CAM_VFE_BUS_VER2_VFE_CORE_MAX; + + if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 && + rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5) + list_add_tail(&comp_grp->list, + &ver2_bus_priv->free_dual_comp_grp); + else if (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0 + && rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5) + list_add_tail(&comp_grp->list, &ver2_bus_priv->free_comp_grp); + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = cam_vfe_bus_handle_comp_done_top_half; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = ver2_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = + comp_grp->res_priv; + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = NULL; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = NULL; + + list_del_init(&comp_grp->list); + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + + comp_grp->res_priv = NULL; + + if (!rsrc_data) { + CAM_ERR(CAM_ISP, "comp_grp_priv is NULL"); + return -ENODEV; + } + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + bool *mode = cmd_args; + struct cam_isp_resource_node *res = + (struct cam_isp_resource_node *) priv; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = + (struct cam_vfe_bus_ver2_vfe_out_data *)res->res_priv; + + *mode = + (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_vfe_bus_acquire_vfe_out(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id; + uint32_t format; + int num_wm; + uint32_t client_done_mask; + struct cam_vfe_bus_ver2_priv *ver2_bus_priv = bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *out_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + out_acquire_args = &acq_args->vfe_out; + format = out_acquire_args->out_port_info->format; + + CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", + out_acquire_args->out_port_info->res_type); + + vfe_out_res_id = cam_vfe_bus_get_out_res_id( + out_acquire_args->out_port_info->res_type); + if (vfe_out_res_id == CAM_VFE_BUS_VER2_VFE_OUT_MAX) + return -ENODEV; + + num_wm = cam_vfe_bus_get_num_wm(vfe_out_res_id, format); + if (num_wm < 1) + return -EINVAL; + + rsrc_node = &ver2_bus_priv->vfe_out[vfe_out_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + vfe_out_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->out_type); + mode = out_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + ver2_bus_priv->tasklet_info = acq_args->tasklet; + rsrc_data->num_wm = num_wm; + rsrc_node->res_id = out_acquire_args->out_port_info->res_type; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = out_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops; + + /* Reserve Composite Group */ + if (num_wm > 1 || (out_acquire_args->is_dual) || + (out_acquire_args->out_port_info->comp_grp_id > + CAM_ISP_RES_COMP_GROUP_NONE && + out_acquire_args->out_port_info->comp_grp_id < + CAM_ISP_RES_COMP_GROUP_ID_MAX)) { + + rc = cam_vfe_bus_acquire_comp_grp(ver2_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + out_acquire_args->unique_id, + out_acquire_args->is_dual, + out_acquire_args->is_master, + out_acquire_args->dual_slave_core, + &rsrc_data->comp_grp); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d Comp_Grp acquire fail for Out %d rc=%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + return rc; + } + } + + /* Reserve WM */ + for (i = 0; i < num_wm; i++) { + rc = cam_vfe_bus_acquire_wm(ver2_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + vfe_out_res_id, + i, + &rsrc_data->wm_res[i], + &client_done_mask, + out_acquire_args->is_dual); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d WM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + goto release_wm; + } + + if (rsrc_data->comp_grp) + cam_vfe_bus_add_wm_to_comp_grp(rsrc_data->comp_grp, + client_done_mask); + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + out_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_wm: + for (i--; i >= 0; i--) + cam_vfe_bus_release_wm(ver2_bus_priv, rsrc_data->wm_res[i]); + + cam_vfe_bus_release_comp_grp(ver2_bus_priv, + rsrc_data->comp_grp); + + return rc; +} + +static int cam_vfe_bus_release_vfe_out(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_out = release_args; + rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + } + + for (i = 0; i < rsrc_data->num_wm; i++) + cam_vfe_bus_release_wm(bus_priv, rsrc_data->wm_res[i]); + rsrc_data->num_wm = 0; + + if (rsrc_data->comp_grp) + cam_vfe_bus_release_comp_grp(bus_priv, rsrc_data->comp_grp); + rsrc_data->comp_grp = NULL; + + vfe_out->tasklet_info = NULL; + vfe_out->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->out_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver2_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX]; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "Start resource index %d", rsrc_data->out_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + return -EACCES; + } + + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_start_wm(rsrc_data->wm_res[i], + bus_irq_reg_mask); + + if (rsrc_data->comp_grp) { + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + rc = cam_vfe_bus_start_comp_grp(rsrc_data->comp_grp, + bus_irq_reg_mask); + } + + vfe_out->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1, + bus_irq_reg_mask, vfe_out, vfe_out->top_half_handler, + vfe_out->bottom_half_handler, vfe_out->tasklet_info, + &tasklet_bh_api); + + if (vfe_out->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Subscribe IRQ failed for res_id %d", + vfe_out->res_id); + vfe_out->irq_handle = 0; + return -EFAULT; + } + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_stop_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver2_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "vfe_out res_state is %d", vfe_out->res_state); + return rc; + } + + if (rsrc_data->comp_grp) + rc = cam_vfe_bus_stop_comp_grp(rsrc_data->comp_grp); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_stop_wm(rsrc_data->wm_res[i]); + + if (vfe_out->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + vfe_out->irq_handle); + vfe_out->irq_handle = 0; + } + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_handle_vfe_out_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + vfe_out = th_payload->handler_priv; + if (!vfe_out) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = vfe_out->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = 0x%x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = 0x%x", th_payload->evt_status_arr[1]); + CAM_DBG(CAM_ISP, "IRQ status_2 = 0x%x", th_payload->evt_status_arr[2]); + + rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "IRQ status_0 = 0x%x status_1 = 0x%x status_2 = 0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], + th_payload->evt_status_arr[2]); + + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + evt_payload->core_index = rsrc_data->common_data->core_index; + evt_payload->evt_id = evt_id; + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_bus_handle_vfe_out_done_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int rc = -EINVAL; + struct cam_isp_resource_node *vfe_out = handler_priv; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv; + struct cam_isp_hw_event_info evt_info; + void *ctx = NULL; + uint32_t evt_id = 0; + uint32_t comp_mask = 0; + int num_out = 0, i = 0; + struct cam_vfe_bus_irq_evt_payload *evt_payload = + evt_payload_priv; + uint32_t out_list[CAM_VFE_BUS_VER2_VFE_OUT_MAX] = {0}; + + /* + * If this resource has Composite Group then we only handle + * Composite done. We acquire Composite if number of WM > 1. + * So Else case is only one individual buf_done = WM[0]. + */ + if (rsrc_data->comp_grp) { + rc = cam_vfe_bus_handle_comp_done_bottom_half( + rsrc_data->comp_grp, evt_payload_priv, &comp_mask); + } else { + rc = rsrc_data->wm_res[0]->bottom_half_handler( + rsrc_data->wm_res[0], evt_payload_priv); + } + + ctx = rsrc_data->priv; + + switch (rc) { + case CAM_VFE_IRQ_STATUS_SUCCESS: + evt_id = evt_payload->evt_id; + + evt_info.res_type = vfe_out->res_type; + evt_info.hw_idx = vfe_out->hw_intf->hw_idx; + if (rsrc_data->comp_grp) { + cam_vfe_bus_get_comp_vfe_out_res_id_list( + comp_mask, out_list, &num_out); + for (i = 0; i < num_out; i++) { + evt_info.res_id = out_list[i]; + if (rsrc_data->common_data->event_cb) + rsrc_data->common_data->event_cb(ctx, + evt_id, (void *)&evt_info); + } + } else { + evt_info.res_id = vfe_out->res_id; + if (rsrc_data->common_data->event_cb) + rsrc_data->common_data->event_cb(ctx, evt_id, + (void *)&evt_info); + } + break; + default: + break; + } + + cam_vfe_bus_put_evt_payload(rsrc_data->common_data, &evt_payload); + CAM_DBG(CAM_ISP, "vfe_out %d rc %d", rsrc_data->out_type, rc); + + return rc; +} + +static int cam_vfe_bus_init_vfe_out_resource(uint32_t index, + struct cam_vfe_bus_ver2_priv *ver2_bus_priv, + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info) +{ + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_out_type = + ver2_hw_info->vfe_out_hw_info[index].vfe_out_type; + + if (vfe_out_type < 0 || + vfe_out_type >= CAM_VFE_BUS_VER2_VFE_OUT_MAX) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_out_type); + return -EINVAL; + } + + vfe_out = &ver2_bus_priv->vfe_out[vfe_out_type]; + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_out->res_priv) { + CAM_ERR(CAM_ISP, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver2_vfe_out_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_out->res_priv = rsrc_data; + + vfe_out->res_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + + rsrc_data->out_type = + ver2_hw_info->vfe_out_hw_info[index].vfe_out_type; + rsrc_data->common_data = &ver2_bus_priv->common_data; + rsrc_data->max_width = + ver2_hw_info->vfe_out_hw_info[index].max_width; + rsrc_data->max_height = + ver2_hw_info->vfe_out_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_out->start = cam_vfe_bus_start_vfe_out; + vfe_out->stop = cam_vfe_bus_stop_vfe_out; + vfe_out->top_half_handler = cam_vfe_bus_handle_vfe_out_done_top_half; + vfe_out->bottom_half_handler = + cam_vfe_bus_handle_vfe_out_done_bottom_half; + vfe_out->process_cmd = cam_vfe_bus_process_cmd; + vfe_out->hw_intf = ver2_bus_priv->common_data.hw_intf; + vfe_out->irq_handle = 0; + + return 0; +} + +static int cam_vfe_bus_deinit_vfe_out_resource( + struct cam_isp_resource_node *vfe_out) +{ + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + vfe_out->start = NULL; + vfe_out->stop = NULL; + vfe_out->top_half_handler = NULL; + vfe_out->bottom_half_handler = NULL; + vfe_out->hw_intf = NULL; + vfe_out->irq_handle = 0; + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + vfe_out->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_ver2_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + int rc = 0; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Enter"); + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.bus_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; +} + +static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int i = 0, rc = 0; + struct cam_vfe_bus_ver2_priv *bus_priv = + th_payload->handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + CAM_ERR_RATE_LIMIT(CAM_ISP, "Bus Err IRQ"); + for (i = 0; i < th_payload->num_registers; i++) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "vfe:%d: IRQ_Status%d: 0x%x", + bus_priv->common_data.core_index, i, + th_payload->evt_status_arr[i]); + } + cam_irq_controller_disable_irq(bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + + rc = cam_vfe_bus_get_evt_payload(&bus_priv->common_data, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Cannot get payload"); + return rc; + } + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->core_index = bus_priv->common_data.core_index; + evt_payload->evt_id = evt_id; + evt_payload->debug_status_0 = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->debug_status_0); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static void cam_vfe_bus_update_ubwc_meta_addr( + uint32_t *reg_val_pair, + uint32_t *j, + void *regs, + uint64_t image_buf) +{ + uint32_t camera_hw_version; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_3_regs; + int rc = 0; + + if (!regs || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); + goto end; + } else if ((camera_hw_version < CAM_CPAS_TITAN_170_V100) || + (camera_hw_version > CAM_CPAS_TITAN_175_V130)) { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + goto end; + } + + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + ubwc_regs = + (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *)regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_addr, + image_buf); + break; + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + ubwc_3_regs = + (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_3_regs->meta_addr, + image_buf); + break; + default: + break; + } +end: + return; +} + +static int cam_vfe_bus_update_ubwc_3_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_regs; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->offset); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->v_init, wm_data->v_init); + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_1, wm_data->ubwc_mode_cfg_1); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_1 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->ubwc_bandwidth_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, wm_data->ubwc_bandwidth_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, wm_data->ubwc_bandwidth_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_legacy_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t camera_hw_version, uint32_t *reg_val_pair, + uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; + uint32_t ubwc_bw_limit = 0; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM %d packer cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->tile_cfg, wm_data->tile_cfg); + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + if (wm_data->is_dual) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->offset); + } else { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->h_init, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->v_init, wm_data->v_init); + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_stride, wm_data->ubwc_meta_stride); + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg_0, wm_data->ubwc_mode_cfg_0); + CAM_DBG(CAM_ISP, "WM %d ubwc_mode_cfg_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_offset, wm_data->ubwc_meta_offset); + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + if (camera_hw_version == CAM_CPAS_TITAN_170_V110) { + switch (wm_data->format) { + case CAM_FORMAT_UBWC_TP10: + ubwc_bw_limit = 0x8 | BIT(0); + break; + case CAM_FORMAT_UBWC_NV12_4R: + ubwc_bw_limit = 0xB | BIT(0); + break; + default: + ubwc_bw_limit = 0; + break; + } + } + + if (ubwc_bw_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, ubwc_bw_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, ubwc_bw_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_regs( + struct cam_vfe_bus_ver2_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + uint32_t camera_hw_version; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); + goto end; + } else if ((camera_hw_version <= CAM_CPAS_TITAN_NONE) || + (camera_hw_version >= CAM_CPAS_TITAN_MAX)) { + CAM_ERR(CAM_ISP, "Invalid HW version: %d", + camera_hw_version); + rc = -EINVAL; + goto end; + } + switch (camera_hw_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + rc = cam_vfe_bus_update_ubwc_legacy_regs( + wm_data, camera_hw_version, reg_val_pair, i, j); + break; + case CAM_CPAS_TITAN_175_V100: + case CAM_CPAS_TITAN_175_V101: + case CAM_CPAS_TITAN_175_V120: + case CAM_CPAS_TITAN_175_V130: + rc = cam_vfe_bus_update_ubwc_3_regs( + wm_data, reg_val_pair, i, j); + break; + default: + break; + } + + if (rc) + CAM_ERR(CAM_ISP, "Failed to update ubwc regs rc:%d", rc); + +end: + return rc; +} + +static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_client = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, k, size = 0; + uint32_t frame_inc = 0, val; + uint32_t loop_size = 0; + + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_buf->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != vfe_out_data->num_wm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, vfe_out_data->num_wm); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + io_cfg = update_buf->wm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_client = wm_data->hw_regs->ubwc_regs; + /* update width register */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->buffer_width_cfg, + wm_data->width); + CAM_DBG(CAM_ISP, "WM %d image width 0x%x", + wm_data->index, reg_val_pair[j-1]); + + /* For initial configuration program all bus registers */ + val = io_cfg->planes[i].plane_stride; + CAM_DBG(CAM_ISP, "before stride %d", val); + val = ALIGNUP(val, 16); + if (val != io_cfg->planes[i].plane_stride && + val != wm_data->stride) + CAM_WARN(CAM_ISP, + "Warning stride %u expected %u", + io_cfg->planes[i].plane_stride, + val); + + if ((wm_data->stride != val || + !wm_data->init_cfg_done) && (wm_data->index >= 3)) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->stride, + io_cfg->planes[i].plane_stride); + wm_data->stride = val; + CAM_DBG(CAM_ISP, "WM %d image stride 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->en_ubwc) { + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + return -EINVAL; + } + if (wm_data->ubwc_updated) { + wm_data->ubwc_updated = false; + cam_vfe_bus_update_ubwc_regs( + wm_data, reg_val_pair, i, &j); + } + + /* UBWC meta address */ + cam_vfe_bus_update_ubwc_meta_addr( + reg_val_pair, &j, + wm_data->hw_regs->ubwc_regs, + update_buf->wm_update->image_buf[i]); + CAM_DBG(CAM_ISP, "WM %d ubwc meta addr 0x%llx", + wm_data->index, + update_buf->wm_update->image_buf[i]); + } + + if (wm_data->en_ubwc) { + frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height, 4096); + frame_inc += io_cfg->planes[i].meta_size; + CAM_DBG(CAM_ISP, + "WM %d frm %d: ht: %d stride %d meta: %d", + wm_data->index, frame_inc, + io_cfg->planes[i].slice_height, + io_cfg->planes[i].plane_stride, + io_cfg->planes[i].meta_size); + } else { + frame_inc = io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height; + } + + if (wm_data->index < 3) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_ubwc) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size + + k * frame_inc); + else + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc); + CAM_DBG(CAM_ISP, "WM %d image address 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_inc, frame_inc); + CAM_DBG(CAM_ISP, "WM %d frame_inc %d", + wm_data->index, reg_val_pair[j-1]); + + + /* enable the WM */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, + wm_data->en_cfg); + + /* set initial configuration done */ + if (!wm_data->init_cfg_done) + wm_data->init_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_hfr; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_isp_port_hfr_config *hfr_cfg = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + update_hfr = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_hfr->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + hfr_cfg = update_hfr->hfr_update; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + + if (wm_data->index <= 2 && hfr_cfg->subsample_period > 3) { + CAM_ERR(CAM_ISP, + "RDI doesn't support irq subsample period %d", + hfr_cfg->subsample_period); + return -EINVAL; + } + + if ((wm_data->framedrop_pattern != + hfr_cfg->framedrop_pattern) || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_pattern, + hfr_cfg->framedrop_pattern); + wm_data->framedrop_pattern = hfr_cfg->framedrop_pattern; + CAM_DBG(CAM_ISP, "WM %d framedrop pattern 0x%x", + wm_data->index, wm_data->framedrop_pattern); + } + + if (wm_data->framedrop_period != hfr_cfg->framedrop_period || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_period, + hfr_cfg->framedrop_period); + wm_data->framedrop_period = hfr_cfg->framedrop_period; + CAM_DBG(CAM_ISP, "WM %d framedrop period 0x%x", + wm_data->index, wm_data->framedrop_period); + } + + if (wm_data->irq_subsample_period != hfr_cfg->subsample_period + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_period, + hfr_cfg->subsample_period); + wm_data->irq_subsample_period = + hfr_cfg->subsample_period; + CAM_DBG(CAM_ISP, "WM %d irq subsample period 0x%x", + wm_data->index, wm_data->irq_subsample_period); + } + + if (wm_data->irq_subsample_pattern != hfr_cfg->subsample_pattern + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_pattern, + hfr_cfg->subsample_pattern); + wm_data->irq_subsample_pattern = + hfr_cfg->subsample_pattern; + CAM_DBG(CAM_ISP, "WM %d irq subsample pattern 0x%x", + wm_data->index, wm_data->irq_subsample_pattern); + } + + /* set initial configuration done */ + if (!wm_data->hfr_cfg_done) + wm_data->hfr_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_hfr->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_hfr->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_hfr->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_hfr->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_update_ubwc_config(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_ubwc_plane_cfg_v1 *ubwc_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_plane_cfg = update_ubwc->ubwc_update; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + if (i > 0) + ubwc_plane_cfg++; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = ubwc_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->tile_cfg != + ubwc_plane_cfg->tile_config) + || !wm_data->init_cfg_done)) { + wm_data->tile_cfg = ubwc_plane_cfg->tile_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->v_init != ubwc_plane_cfg->v_init || + !wm_data->init_cfg_done) { + wm_data->v_init = ubwc_plane_cfg->v_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_stride != + ubwc_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_stride = ubwc_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_0 != + ubwc_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_0 = + ubwc_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_1 != + ubwc_plane_cfg->mode_config_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_1 = + ubwc_plane_cfg->mode_config_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_offset != + ubwc_plane_cfg->meta_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_offset = ubwc_plane_cfg->meta_offset; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + +static int cam_vfe_bus_update_ubwc_config_v2(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_vfe_generic_ubwc_config *ubwc_generic_cfg = NULL; + struct cam_vfe_generic_ubwc_plane_config *ubwc_generic_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_generic_cfg = update_ubwc->ubwc_config; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_generic_plane_cfg = &ubwc_generic_cfg->ubwc_plane_cfg[i]; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_generic_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = + ubwc_generic_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->tile_cfg != + ubwc_generic_plane_cfg->tile_config) + || !wm_data->init_cfg_done)) { + wm_data->tile_cfg = ubwc_generic_plane_cfg->tile_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_generic_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_generic_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->v_init != ubwc_generic_plane_cfg->v_init || + !wm_data->init_cfg_done) { + wm_data->v_init = ubwc_generic_plane_cfg->v_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_stride != + ubwc_generic_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_stride = + ubwc_generic_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_0 != + ubwc_generic_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_0 = + ubwc_generic_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg_1 != + ubwc_generic_plane_cfg->mode_config_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg_1 = + ubwc_generic_plane_cfg->mode_config_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_offset != + ubwc_generic_plane_cfg->meta_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_offset = + ubwc_generic_plane_cfg->meta_offset; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_0 != + ubwc_generic_plane_cfg->lossy_threshold_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_0 = + ubwc_generic_plane_cfg->lossy_threshold_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_1 != + ubwc_generic_plane_cfg->lossy_threshold_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_1 = + ubwc_generic_plane_cfg->lossy_threshold_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_bandwidth_limit != + ubwc_generic_plane_cfg->bandwidth_limit || + !wm_data->init_cfg_done) { + wm_data->ubwc_bandwidth_limit = + ubwc_generic_plane_cfg->bandwidth_limit; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + + +static int cam_vfe_bus_update_stripe_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv; + struct cam_isp_hw_dual_isp_update_args *stripe_args; + struct cam_vfe_bus_ver2_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *wm_data = NULL; + struct cam_isp_dual_stripe_config *stripe_config; + uint32_t outport_id, ports_plane_idx, i; + + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + stripe_args = (struct cam_isp_hw_dual_isp_update_args *)cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver2_vfe_out_data *) + stripe_args->res->res_priv; + + if (!vfe_out_data) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + outport_id = stripe_args->res->res_id & 0xFF; + if (stripe_args->res->res_id < CAM_ISP_IFE_OUT_RES_BASE || + stripe_args->res->res_id >= CAM_ISP_IFE_OUT_RES_MAX) + return 0; + + ports_plane_idx = (stripe_args->split_id * + (stripe_args->dual_cfg->num_ports * CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + for (i = 0; i < vfe_out_data->num_wm; i++) { + wm_data = vfe_out_data->wm_res[i]->res_priv; + stripe_config = (struct cam_isp_dual_stripe_config *) + &stripe_args->dual_cfg->stripes[ports_plane_idx + i]; + wm_data->width = stripe_config->width; + wm_data->offset = stripe_config->offset; + wm_data->tile_cfg = stripe_config->tileconfig; + CAM_DBG(CAM_ISP, "id:%x wm:%d width:0x%x offset:%x tilecfg:%x", + stripe_args->res->res_id, i, wm_data->width, + wm_data->offset, wm_data->tile_cfg); + } + + return 0; +} + +static int cam_vfe_bus_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_start_vfe_out(hw_priv); +} + +static int cam_vfe_bus_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_stop_vfe_out(hw_priv); +} + +static int cam_vfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[2] = {0}; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + if (bus_priv->common_data.hw_init) + return 0; + + top_irq_reg_mask[0] = (1 << 9); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_ver2_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + bus_priv->irq_handle = 0; + return -EFAULT; + } + + if (bus_priv->tasklet_info != NULL) { + bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.bus_irq_controller, + CAM_IRQ_PRIORITY_0, + bus_error_irq_mask, + bus_priv, + cam_vfe_bus_error_irq_top_half, + cam_vfe_bus_err_bottom_half, + bus_priv->tasklet_info, + &tasklet_bh_api); + + if (bus_priv->error_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS error IRQ %d", + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + return -EFAULT; + } + } + + /*Set Debug Registers*/ + cam_io_w_mb(CAM_VFE_BUS_SET_DEBUG_REG, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->debug_status_cfg); + + /* BUS_WR_INPUT_IF_ADDR_SYNC_FRAME_HEADER */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->addr_sync_frame_hdr); + + /* no clock gating at bus input */ + cam_io_w_mb(0xFFFFF, bus_priv->common_data.mem_base + 0x0000200C); + + /* BUS_WR_TEST_BUS_CTRL */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + 0x0000211C); + + /* if addr_no_sync has default value then config the addr no sync reg */ + cam_io_w_mb(CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL, + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->addr_sync_no_sync); + + bus_priv->common_data.hw_init = true; + + return 0; +} + +static int cam_vfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver2_priv *bus_priv = hw_priv; + int rc = 0, i; + unsigned long flags; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (!bus_priv->common_data.hw_init) + return 0; + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->irq_handle); + bus_priv->irq_handle = 0; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + return rc; +} + +static int __cam_vfe_bus_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_bus_ver2_priv *bus_priv; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + rc = cam_vfe_bus_update_wm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + rc = cam_vfe_bus_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + rc = cam_vfe_bus_update_stripe_cfg(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + bus_priv = (struct cam_vfe_bus_ver2_priv *) priv; + if (bus_priv->error_irq_handle) { + CAM_DBG(CAM_ISP, "Mask off bus error irq handler"); + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + break; + case CAM_ISP_HW_CMD_UBWC_UPDATE: + rc = cam_vfe_bus_update_ubwc_config(cmd_args); + break; + case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: + rc = cam_vfe_bus_update_ubwc_config_v2(cmd_args); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver2_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_ver2_hw_info *ver2_hw_info = bus_hw_info; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver2_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = ver2_hw_info->num_client; + bus_priv->num_out = ver2_hw_info->num_out; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &ver2_hw_info->common_reg; + bus_priv->common_data.addr_no_sync = + CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL; + bus_priv->common_data.hw_init = false; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &ver2_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller, true); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_init_wm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init WM failed rc=%d", rc); + goto deinit_wm; + } + } + + for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_init_comp_grp(i, bus_priv, bus_hw_info, + &bus_priv->comp_grp[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init Comp Grp failed rc=%d", rc); + goto deinit_comp_grp; + } + } + + for (i = 0; i < bus_priv->num_out; i++) { + rc = cam_vfe_bus_init_vfe_out_resource(i, bus_priv, + bus_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed rc=%d", rc); + goto deinit_vfe_out; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_out; + vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_out; + vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_ver2_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + + *vfe_bus = vfe_bus_local; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; + +deinit_vfe_out: + if (i < 0) + i = CAM_VFE_BUS_VER2_VFE_OUT_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]); + +deinit_comp_grp: + if (i < 0) + i = CAM_VFE_BUS_VER2_COMP_GRP_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + +deinit_wm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_ver2_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver2_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + unsigned long flags; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_deinit_wm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit WM failed rc=%d", rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER2_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_deinit_comp_grp(&bus_priv->comp_grp[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit Comp Grp failed rc=%d", rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER2_VFE_OUT_MAX; i++) { + rc = cam_vfe_bus_deinit_vfe_out_resource(&bus_priv->vfe_out[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit VFE Out failed rc=%d", rc); + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->free_dual_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h new file mode 100644 index 0000000000000000000000000000000000000000..cac3adf65a9385165262dee8c16f5829dbb1f459 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_VER2_H_ +#define _CAM_VFE_BUS_VER2_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_VER2_MAX_CLIENTS 24 + +enum cam_vfe_bus_ver2_vfe_core_id { + CAM_VFE_BUS_VER2_VFE_CORE_0, + CAM_VFE_BUS_VER2_VFE_CORE_1, + CAM_VFE_BUS_VER2_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_ver2_comp_grp_type { + CAM_VFE_BUS_VER2_COMP_GRP_0, + CAM_VFE_BUS_VER2_COMP_GRP_1, + CAM_VFE_BUS_VER2_COMP_GRP_2, + CAM_VFE_BUS_VER2_COMP_GRP_3, + CAM_VFE_BUS_VER2_COMP_GRP_4, + CAM_VFE_BUS_VER2_COMP_GRP_5, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4, + CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5, + CAM_VFE_BUS_VER2_COMP_GRP_MAX, +}; + +enum cam_vfe_bus_ver2_vfe_out_type { + CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + CAM_VFE_BUS_VER2_VFE_OUT_RDI3, + CAM_VFE_BUS_VER2_VFE_OUT_FULL, + CAM_VFE_BUS_VER2_VFE_OUT_DS4, + CAM_VFE_BUS_VER2_VFE_OUT_DS16, + CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + CAM_VFE_BUS_VER2_VFE_OUT_FD, + CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + CAM_VFE_BUS_VER2_VFE_OUT_2PD, + CAM_VFE_BUS_VER2_VFE_OUT_MAX, +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_ovd; + uint32_t pwr_iso_cfg; + uint32_t dual_master_comp_cfg; + struct cam_irq_controller_reg_info irq_reg_info; + uint32_t comp_error_status; + uint32_t comp_ovrwr_status; + uint32_t dual_comp_error_status; + uint32_t dual_comp_ovrwr_status; + uint32_t addr_sync_cfg; + uint32_t addr_sync_frame_hdr; + uint32_t addr_sync_no_sync; + uint32_t debug_status_cfg; + uint32_t debug_status_0; +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_ubwc_client { + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t meta_addr; + uint32_t meta_offset; + uint32_t meta_stride; + uint32_t mode_cfg_0; + uint32_t bw_limit; +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client { + uint32_t tile_cfg; + uint32_t h_init; + uint32_t v_init; + uint32_t meta_addr; + uint32_t meta_offset; + uint32_t meta_stride; + uint32_t mode_cfg_0; + uint32_t mode_cfg_1; + uint32_t bw_limit; +}; + + +/* + * struct cam_vfe_bus_ver2_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_ver2_reg_offset_bus_client { + uint32_t status0; + uint32_t status1; + uint32_t cfg; + uint32_t header_addr; + uint32_t header_cfg; + uint32_t image_addr; + uint32_t image_addr_offset; + uint32_t buffer_width_cfg; + uint32_t buffer_height_cfg; + uint32_t packer_cfg; + uint32_t stride; + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t frame_inc; + uint32_t burst_limit; + void *ubwc_regs; +}; + +/* + * struct cam_vfe_bus_ver2_reg_offset_comp_grp: + * + * @Brief: Register offsets for Composite Group registers + * comp_mask: Comp group register address + * addr_sync_mask:Address sync group register address + */ +struct cam_vfe_bus_ver2_reg_offset_comp_grp { + uint32_t comp_mask; + uint32_t addr_sync_mask; +}; + +/* + * struct cam_vfe_bus_ver2_vfe_out_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_ver2_vfe_out_hw_info { + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_vfe_bus_ver2_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @bus_client_reg: Bus client register info + * @comp_reg_grp: Composite group register info + * @vfe_out_hw_info: VFE output capability + */ +struct cam_vfe_bus_ver2_hw_info { + struct cam_vfe_bus_ver2_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_ver2_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_VER2_MAX_CLIENTS]; + struct cam_vfe_bus_ver2_reg_offset_comp_grp + comp_grp_reg[CAM_VFE_BUS_VER2_COMP_GRP_MAX]; + uint32_t num_out; + struct cam_vfe_bus_ver2_vfe_out_hw_info + vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; +}; + +/* + * cam_vfe_bus_ver2_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_ver2_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver2_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_VER2_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c new file mode 100644 index 0000000000000000000000000000000000000000..cae12531589564fee015843879b7b8d8f33a1df6 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c @@ -0,0 +1,3967 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#include <linux/ratelimit.h> +#include <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver3.h" +#include "cam_vfe_core.h" +#include "cam_vfe_soc.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus"; + +#define CAM_VFE_BUS_VER3_IRQ_REG0 0 +#define CAM_VFE_BUS_VER3_IRQ_REG1 1 +#define CAM_VFE_BUS_VER3_IRQ_MAX 2 + +#define CAM_VFE_BUS_VER3_PAYLOAD_MAX 256 + +#define CAM_VFE_RDI_BUS_DEFAULT_WIDTH 0xFFFF +#define CAM_VFE_RDI_BUS_DEFAULT_STRIDE 0xFFFF +#define CAM_VFE_BUS_VER3_INTRA_CLIENT_MASK 0x3 + +#define MAX_BUF_UPDATE_REG_NUM \ + ((sizeof(struct cam_vfe_bus_ver3_reg_offset_bus_client) + \ + sizeof(struct cam_vfe_bus_ver3_reg_offset_ubwc_client))/4) +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +static uint32_t bus_error_irq_mask[2] = { + 0xC0000000, + 0x00000000, +}; + +enum cam_vfe_bus_ver3_packer_format { + PACKER_FMT_VER3_PLAIN_128, + PACKER_FMT_VER3_PLAIN_8, + PACKER_FMT_VER3_PLAIN_8_ODD_EVEN, + PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10, + PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10_ODD_EVEN, + PACKER_FMT_VER3_PLAIN_16_10BPP, + PACKER_FMT_VER3_PLAIN_16_12BPP, + PACKER_FMT_VER3_PLAIN_16_14BPP, + PACKER_FMT_VER3_PLAIN_16_16BPP, + PACKER_FMT_VER3_PLAIN_32, + PACKER_FMT_VER3_PLAIN_64, + PACKER_FMT_VER3_TP_10, + PACKER_FMT_VER3_MAX, +}; + +struct cam_vfe_bus_ver3_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *rup_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_ver3_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct cam_vfe_bus_irq_evt_payload evt_payload[ + CAM_VFE_BUS_VER3_PAYLOAD_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t addr_no_sync; + uint32_t comp_done_shift; + bool is_lite; + bool hw_init; + cam_hw_mgr_event_cb_func event_cb; + int rup_irq_handle[CAM_VFE_BUS_VER3_SRC_GRP_MAX]; +}; + +struct cam_vfe_bus_ver3_wm_resource_data { + uint32_t index; + struct cam_vfe_bus_ver3_common_data *common_data; + struct cam_vfe_bus_ver3_reg_offset_bus_client *hw_regs; + + bool init_cfg_done; + bool hfr_cfg_done; + + uint32_t offset; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + enum cam_vfe_bus_ver3_packer_format pack_fmt; + + uint32_t burst_len; + + uint32_t en_ubwc; + bool ubwc_updated; + uint32_t packer_cfg; + uint32_t h_init; + uint32_t ubwc_meta_addr; + uint32_t ubwc_meta_cfg; + uint32_t ubwc_mode_cfg; + uint32_t ubwc_stats_ctrl; + uint32_t ubwc_ctrl_2; + + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + + uint32_t en_cfg; + uint32_t is_dual; + + uint32_t ubwc_lossy_threshold_0; + uint32_t ubwc_lossy_threshold_1; + uint32_t ubwc_offset_lossy_variance; + uint32_t ubwc_bandwidth_limit; +}; + +struct cam_vfe_bus_ver3_comp_grp_data { + enum cam_vfe_bus_ver3_comp_grp_type comp_grp_type; + struct cam_vfe_bus_ver3_common_data *common_data; + + uint32_t is_master; + uint32_t is_dual; + uint32_t dual_slave_core; + uint32_t intra_client_mask; + uint32_t addr_sync_mode; + uint32_t composite_mask; + + uint32_t acquire_dev_cnt; + uint32_t irq_trigger_cnt; + uint32_t ubwc_static_ctrl; +}; + +struct cam_vfe_bus_ver3_vfe_out_data { + uint32_t out_type; + uint32_t source_group; + struct cam_vfe_bus_ver3_common_data *common_data; + + uint32_t num_wm; + struct cam_isp_resource_node *wm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_out_list; + + uint32_t is_master; + uint32_t is_dual; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; + void *priv; +}; + +struct cam_vfe_bus_ver3_priv { + struct cam_vfe_bus_ver3_common_data common_data; + uint32_t num_client; + uint32_t num_out; + uint32_t top_irq_shift; + + struct cam_isp_resource_node bus_client[CAM_VFE_BUS_VER3_MAX_CLIENTS]; + struct cam_isp_resource_node comp_grp[CAM_VFE_BUS_VER3_COMP_GRP_MAX]; + struct cam_isp_resource_node vfe_out[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; + + struct list_head free_comp_grp; + struct list_head used_comp_grp; + + int bus_irq_handle; + int rup_irq_handle; + int error_irq_handle; + void *tasklet_info; +}; + +static int cam_vfe_bus_ver3_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size); + +static int cam_vfe_bus_ver3_get_evt_payload( + struct cam_vfe_bus_ver3_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + int rc; + + spin_lock(&common_data->spin_lock); + + if (!common_data->hw_init) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d Bus uninitialized", + common_data->core_index); + rc = -EPERM; + goto done; + } + + if (list_empty(&common_data->free_payload_list)) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free BUS event payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&common_data->free_payload_list, + struct cam_vfe_bus_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&common_data->spin_lock); + return rc; +} + +static int cam_vfe_bus_ver3_put_evt_payload( + struct cam_vfe_bus_ver3_common_data *common_data, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!common_data) { + CAM_ERR(CAM_ISP, "Invalid param common_data NULL"); + return -EINVAL; + } + + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&common_data->spin_lock, flags); + if (common_data->hw_init) + list_add_tail(&(*evt_payload)->list, + &common_data->free_payload_list); + spin_unlock_irqrestore(&common_data->spin_lock, flags); + + *evt_payload = NULL; + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_bus_ver3_get_intra_client_mask( + enum cam_vfe_bus_ver3_vfe_core_id dual_slave_core, + enum cam_vfe_bus_ver3_vfe_core_id current_core, + uint32_t *intra_client_mask) +{ + int rc = 0; + uint32_t version_based_intra_client_mask = 0x1; + + *intra_client_mask = 0; + + if (dual_slave_core == current_core) { + CAM_ERR(CAM_ISP, + "Invalid params. Same core as Master and Slave"); + return -EINVAL; + } + + switch (current_core) { + case CAM_VFE_BUS_VER3_VFE_CORE_0: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER3_VFE_CORE_1: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_CORE_1: + switch (dual_slave_core) { + case CAM_VFE_BUS_VER3_VFE_CORE_0: + *intra_client_mask = version_based_intra_client_mask; + break; + default: + CAM_ERR(CAM_ISP, "Invalid value for slave core %u", + dual_slave_core); + rc = -EINVAL; + break; + } + break; + default: + CAM_ERR(CAM_ISP, + "Invalid value for master core %u", current_core); + rc = -EINVAL; + break; + } + + return rc; +} + +static bool cam_vfe_bus_ver3_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_VER3_VFE_OUT_FULL: + case CAM_VFE_BUS_VER3_VFE_OUT_DS4: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16: + case CAM_VFE_BUS_VER3_VFE_OUT_FD: + case CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP: + case CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP: + return true; + + case CAM_VFE_BUS_VER3_VFE_OUT_2PD: + case CAM_VFE_BUS_VER3_VFE_OUT_LCR: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST: + default: + return false; + } +} + +static enum cam_vfe_bus_ver3_vfe_out_type + cam_vfe_bus_ver3_get_out_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_IFE_OUT_RES_FULL: + return CAM_VFE_BUS_VER3_VFE_OUT_FULL; + case CAM_ISP_IFE_OUT_RES_DS4: + return CAM_VFE_BUS_VER3_VFE_OUT_DS4; + case CAM_ISP_IFE_OUT_RES_DS16: + return CAM_VFE_BUS_VER3_VFE_OUT_DS16; + case CAM_ISP_IFE_OUT_RES_FD: + return CAM_VFE_BUS_VER3_VFE_OUT_FD; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP; + case CAM_ISP_IFE_OUT_RES_2PD: + return CAM_VFE_BUS_VER3_VFE_OUT_2PD; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI0; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI1; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI2; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return CAM_VFE_BUS_VER3_VFE_OUT_RDI3; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS; + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + return CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST; + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + return CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP; + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + return CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP; + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + return CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP; + case CAM_ISP_IFE_OUT_RES_LCR: + return CAM_VFE_BUS_VER3_VFE_OUT_LCR; + default: + return CAM_VFE_BUS_VER3_VFE_OUT_MAX; + } +} + +static int cam_vfe_bus_ver3_get_num_wm( + enum cam_vfe_bus_ver3_vfe_out_type res_type, + uint32_t format) +{ + switch (res_type) { + case CAM_VFE_BUS_VER3_VFE_OUT_RDI0: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI1: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI2: + case CAM_VFE_BUS_VER3_VFE_OUT_RDI3: + switch (format) { + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_DPCM_10_6_10: + case CAM_FORMAT_DPCM_10_8_10: + case CAM_FORMAT_DPCM_12_6_12: + case CAM_FORMAT_DPCM_12_8_12: + case CAM_FORMAT_DPCM_14_8_14: + case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN32_20: + case CAM_FORMAT_PLAIN128: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FULL: + case CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_UBWC_P010: + case CAM_FORMAT_PLAIN16_10: + return 2; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FD: + switch (format) { + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_TP10: + case CAM_FORMAT_PLAIN16_10: + return 2; + case CAM_FORMAT_Y_ONLY: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS4: + case CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16: + case CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP: + switch (format) { + case CAM_FORMAT_PD8: + case CAM_FORMAT_PD10: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP: + switch (format) { + case CAM_FORMAT_ARGB_14: + case CAM_FORMAT_PLAIN8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_2PD: + switch (format) { + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS: + switch (format) { + case CAM_FORMAT_PLAIN64: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS: + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST: + switch (format) { + case CAM_FORMAT_PLAIN16_16: + return 1; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_LCR: + return 1; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported format %u for out_type:0x%X", + format, res_type); + + return -EINVAL; +} + +static int cam_vfe_bus_ver3_get_wm_idx( + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + bool is_lite) +{ + int wm_idx = -1; + + switch (vfe_out_res_id) { + case CAM_VFE_BUS_VER3_VFE_OUT_RDI0: + switch (plane) { + case PLANE_Y: + if (is_lite) + wm_idx = 0; + else + wm_idx = 23; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RDI1: + switch (plane) { + case PLANE_Y: + if (is_lite) + wm_idx = 1; + else + wm_idx = 24; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RDI2: + switch (plane) { + case PLANE_Y: + if (is_lite) + wm_idx = 2; + else + wm_idx = 25; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RDI3: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FULL: + switch (plane) { + case PLANE_Y: + wm_idx = 0; + break; + case PLANE_C: + wm_idx = 1; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS4: + switch (plane) { + case PLANE_Y: + wm_idx = 2; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS16: + switch (plane) { + case PLANE_Y: + wm_idx = 3; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FD: + switch (plane) { + case PLANE_Y: + wm_idx = 8; + break; + case PLANE_C: + wm_idx = 9; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP: + switch (plane) { + case PLANE_Y: + wm_idx = 10; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_2PD: + switch (plane) { + case PLANE_Y: + wm_idx = 21; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE: + switch (plane) { + case PLANE_Y: + wm_idx = 12; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 13; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 14; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF: + switch (plane) { + case PLANE_Y: + wm_idx = 20; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG: + switch (plane) { + case PLANE_Y: + wm_idx = 15; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 16; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS: + switch (plane) { + case PLANE_Y: + wm_idx = 17; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS: + switch (plane) { + case PLANE_Y: + wm_idx = 18; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST: + switch (plane) { + case PLANE_Y: + wm_idx = 19; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 4; + break; + case PLANE_C: + wm_idx = 5; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 6; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP: + switch (plane) { + case PLANE_Y: + wm_idx = 7; + break; + default: + break; + } + break; + case CAM_VFE_BUS_VER3_VFE_OUT_LCR: + switch (plane) { + case PLANE_Y: + wm_idx = 22; + break; + default: + break; + } + default: + break; + } + + return wm_idx; +} + +static int cam_vfe_bus_ver3_get_comp_vfe_out_res_id_list( + uint32_t comp_mask, uint32_t *out_list, int *num_out, bool is_lite) +{ + int count = 0; + + if (is_lite) + goto vfe_lite; + + if (comp_mask & 0x3) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL; + + if (comp_mask & 0x4) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4; + + if (comp_mask & 0x8) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16; + + if (comp_mask & 0x30) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FULL_DISP; + + if (comp_mask & 0x40) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS4_DISP; + + if (comp_mask & 0x80) + out_list[count++] = CAM_ISP_IFE_OUT_RES_DS16_DISP; + + if (comp_mask & 0x300) + out_list[count++] = CAM_ISP_IFE_OUT_RES_FD; + + if (comp_mask & 0x400) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RAW_DUMP; + + if (comp_mask & 0x1000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BE; + + if (comp_mask & 0x2000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST; + + if (comp_mask & 0x4000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_TL_BG; + + if (comp_mask & 0x8000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_AWB_BG; + + if (comp_mask & 0x10000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BHIST; + + if (comp_mask & 0x20000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_RS; + + if (comp_mask & 0x40000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_CS; + + if (comp_mask & 0x80000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_IHIST; + + if (comp_mask & 0x100000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_STATS_BF; + + if (comp_mask & 0x200000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_2PD; + + if (comp_mask & 0x400000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_LCR; + + if (comp_mask & 0x800000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_0; + + if (comp_mask & 0x1000000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (comp_mask & 0x2000000) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_2; + + *num_out = count; + return 0; + +vfe_lite: + if (comp_mask & 0x1) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_0; + + if (comp_mask & 0x2) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_1; + + if (comp_mask & 0x4) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_2; + + if (comp_mask & 0x8) + out_list[count++] = CAM_ISP_IFE_OUT_RES_RDI_3; + + *num_out = count; + return 0; +} + +static enum cam_vfe_bus_ver3_packer_format + cam_vfe_bus_ver3_get_packer_fmt(uint32_t out_fmt, int wm_index) +{ + switch (out_fmt) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN16_8: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PD8: + return PACKER_FMT_VER3_PLAIN_128; + case CAM_FORMAT_PLAIN8: + return PACKER_FMT_VER3_PLAIN_8; + case CAM_FORMAT_NV21: + if ((wm_index == 1) || (wm_index == 3) || (wm_index == 5)) + return PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10_ODD_EVEN; + case CAM_FORMAT_NV12: + case CAM_FORMAT_UBWC_NV12: + case CAM_FORMAT_UBWC_NV12_4R: + case CAM_FORMAT_Y_ONLY: + return PACKER_FMT_VER3_PLAIN_8_LSB_MSB_10; + case CAM_FORMAT_PLAIN16_10: + return PACKER_FMT_VER3_PLAIN_16_10BPP; + case CAM_FORMAT_PLAIN16_12: + return PACKER_FMT_VER3_PLAIN_16_12BPP; + case CAM_FORMAT_PLAIN16_14: + return PACKER_FMT_VER3_PLAIN_16_14BPP; + case CAM_FORMAT_PLAIN16_16: + return PACKER_FMT_VER3_PLAIN_16_16BPP; + case CAM_FORMAT_PLAIN32: + case CAM_FORMAT_ARGB: + return PACKER_FMT_VER3_PLAIN_32; + case CAM_FORMAT_PLAIN64: + case CAM_FORMAT_ARGB_16: + case CAM_FORMAT_PD10: + return PACKER_FMT_VER3_PLAIN_64; + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_TP10: + return PACKER_FMT_VER3_TP_10; + default: + return PACKER_FMT_VER3_MAX; + } +} + +static int cam_vfe_bus_ver3_handle_rup_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + vfe_out = th_payload->handler_priv; + if (!vfe_out) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = vfe_out->res_priv; + + CAM_DBG(CAM_ISP, "VFE:%d Bus IRQ status_0: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0]); + + rc = cam_vfe_bus_ver3_get_evt_payload(rsrc_data->common_data, + &evt_payload); + + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d Bus IRQ status_0: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0]); + return rc; + } + + evt_payload->core_index = rsrc_data->common_data->core_index; + evt_payload->evt_id = evt_id; + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_bus_ver3_handle_rup_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_vfe_bus_irq_evt_payload *payload; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + payload = evt_payload_priv; + vfe_out = handler_priv; + rsrc_data = vfe_out->res_priv; + + if (!rsrc_data->common_data->event_cb) { + CAM_ERR(CAM_ISP, "Callback to HW MGR not found"); + return ret; + } + + irq_status = payload->irq_reg_val[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + evt_info.hw_idx = rsrc_data->common_data->core_index; + evt_info.res_type = CAM_ISP_RESOURCE_VFE_IN; + + if (!rsrc_data->common_data->is_lite) { + if (irq_status & 0x1) { + CAM_DBG(CAM_ISP, "VFE:%d Received CAMIF RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_CAMIF; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x2) { + CAM_DBG(CAM_ISP, "VFE:%d Received PDLIB RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_PDLIB; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x4) + CAM_DBG(CAM_ISP, "VFE:%d Received LCR RUP", + evt_info.hw_idx); + + if (irq_status & 0x8) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI0 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI0; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x10) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI1 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI1; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x20) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI2 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI2; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + } else { + if (irq_status & 0x1) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI0 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI0; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x2) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI1 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI1; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x4) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI2 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI2; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + + if (irq_status & 0x8) { + CAM_DBG(CAM_ISP, "VFE:%d Received RDI3 RUP", + evt_info.hw_idx); + evt_info.res_id = CAM_ISP_HW_VFE_IN_RDI3; + rsrc_data->common_data->event_cb( + rsrc_data->priv, CAM_ISP_HW_EVENT_REG_UPDATE, + (void *)&evt_info); + } + } + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + CAM_DBG(CAM_ISP, + "VFE:%d Bus RUP IRQ status_0:0x%X rc:%d", + evt_info.hw_idx, CAM_ISP_HW_EVENT_REG_UPDATE, irq_status, ret); + + cam_vfe_bus_ver3_put_evt_payload(rsrc_data->common_data, &payload); + + return ret; +} + +static int cam_vfe_bus_ver3_acquire_wm( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_isp_resource_node **wm_res, + uint32_t *client_done_mask, + uint32_t is_dual, + enum cam_vfe_bus_ver3_comp_grp_type *comp_grp_id) +{ + int32_t wm_idx = 0; + struct cam_isp_resource_node *wm_res_local = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = NULL; + + *wm_res = NULL; + + /* VFE OUT to WM is fixed. */ + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, + ver3_bus_priv->common_data.is_lite); + if (wm_idx < 0 || wm_idx >= ver3_bus_priv->num_client || + plane > PLANE_C) { + CAM_ERR(CAM_ISP, + "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", + vfe_out_res_id, plane, wm_idx, + ver3_bus_priv->num_client - 1); + return -EINVAL; + } + + wm_res_local = &ver3_bus_priv->bus_client[wm_idx]; + if (wm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "WM:%d not available state:%d", + wm_idx, wm_res_local->res_state); + return -EALREADY; + } + wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + wm_res_local->tasklet_info = tasklet; + + rsrc_data = wm_res_local->res_priv; + rsrc_data->format = out_port_info->format; + rsrc_data->pack_fmt = cam_vfe_bus_ver3_get_packer_fmt(rsrc_data->format, + wm_idx); + + rsrc_data->width = out_port_info->width; + rsrc_data->height = out_port_info->height; + rsrc_data->is_dual = is_dual; + /* Set WM offset value to default */ + rsrc_data->offset = 0; + CAM_DBG(CAM_ISP, "WM:%d width %d height %d", rsrc_data->index, + rsrc_data->width, rsrc_data->height); + + if (ver3_bus_priv->common_data.is_lite || (rsrc_data->index > 22)) { + rsrc_data->pack_fmt = 0x0; + /* WM 23-25 refers to RDI 0/ RDI 1/RDI 2 */ + switch (rsrc_data->format) { + case CAM_FORMAT_MIPI_RAW_6: + case CAM_FORMAT_MIPI_RAW_8: + case CAM_FORMAT_MIPI_RAW_10: + case CAM_FORMAT_MIPI_RAW_12: + case CAM_FORMAT_MIPI_RAW_14: + case CAM_FORMAT_MIPI_RAW_16: + case CAM_FORMAT_MIPI_RAW_20: + case CAM_FORMAT_PLAIN128: + case CAM_FORMAT_PLAIN32_20: + rsrc_data->width = CAM_VFE_RDI_BUS_DEFAULT_WIDTH; + rsrc_data->height = 0; + rsrc_data->stride = CAM_VFE_RDI_BUS_DEFAULT_STRIDE; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + break; + case CAM_FORMAT_PLAIN8: + rsrc_data->en_cfg = 0x1; + rsrc_data->stride = rsrc_data->width * 2; + break; + case CAM_FORMAT_PLAIN16_10: + case CAM_FORMAT_PLAIN16_12: + case CAM_FORMAT_PLAIN16_14: + case CAM_FORMAT_PLAIN16_16: + rsrc_data->width = + ALIGNUP(rsrc_data->width * 2, 16) / 16; + rsrc_data->en_cfg = 0x1; + break; + case CAM_FORMAT_PLAIN64: + rsrc_data->width = + ALIGNUP(rsrc_data->width * 8, 16) / 16; + rsrc_data->en_cfg = 0x1; + break; + default: + CAM_ERR(CAM_ISP, "Unsupported RDI format %d", + rsrc_data->format); + return -EINVAL; + } + } else if ((rsrc_data->index < 2) || + (rsrc_data->index == 8) || (rsrc_data->index == 9) || + (rsrc_data->index == 4) || (rsrc_data->index == 5)) { + /* + * WM 0-1 FULL_OUT, WM 8-9 FD_OUT, + * WM 4-5 FULL_DISP + */ + switch (rsrc_data->format) { + case CAM_FORMAT_UBWC_NV12_4R: + rsrc_data->en_ubwc = 1; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_NV12: + rsrc_data->en_ubwc = 1; + /* Fall through for NV12 */ + case CAM_FORMAT_NV21: + case CAM_FORMAT_NV12: + case CAM_FORMAT_Y_ONLY: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_UBWC_TP10: + rsrc_data->en_ubwc = 1; + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_TP10: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + case CAM_FORMAT_PLAIN16_10: + switch (plane) { + case PLANE_C: + rsrc_data->height /= 2; + break; + case PLANE_Y: + break; + default: + CAM_ERR(CAM_ISP, "Invalid plane %d", plane); + return -EINVAL; + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + rsrc_data->en_cfg = 0x1; + } else if (rsrc_data->index == 20) { + /* WM 20 stats BAF */ + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index > 11 && rsrc_data->index < 20) { + /* WM 12-19 stats */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index == 21) { + /* WM 21 PD */ + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 1; + rsrc_data->en_cfg = (0x1 << 16) | 0x1; + } else if (rsrc_data->index == 10) { + /* WM 10 Raw dump */ + rsrc_data->stride = rsrc_data->width; + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + } else if (rsrc_data->index == 22) { + switch (rsrc_data->format) { + case CAM_FORMAT_PLAIN16_16: + rsrc_data->stride = ALIGNUP(rsrc_data->width * 2, 8); + rsrc_data->en_cfg = 0x1; + /* LSB aligned */ + rsrc_data->pack_fmt |= 0x10; + break; + default: + CAM_ERR(CAM_ISP, "Invalid format %d", + rsrc_data->format); + return -EINVAL; + } + } else if ((rsrc_data->index == 2) || (rsrc_data->index == 3) || + (rsrc_data->index == 6) || (rsrc_data->index == 7)) { + /* Write master 2-3 and 6-7 DS ports */ + + rsrc_data->height = rsrc_data->height / 2; + rsrc_data->width = rsrc_data->width / 2; + rsrc_data->en_cfg = 0x1; + + } else { + CAM_ERR(CAM_ISP, "Invalid WM:%d requested", rsrc_data->index); + return -EINVAL; + } + + *wm_res = wm_res_local; + *comp_grp_id = rsrc_data->hw_regs->comp_group; + *client_done_mask |= (1 << wm_idx); + + CAM_DBG(CAM_ISP, + "VFE:%d WM:%d processed width:%d height:%d format:0x%X en_ubwc:%d", + rsrc_data->common_data->core_index, rsrc_data->index, + rsrc_data->width, rsrc_data->height, rsrc_data->format, + rsrc_data->en_ubwc); + return 0; +} + +static int cam_vfe_bus_ver3_release_wm(void *bus_priv, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = + wm_res->res_priv; + + rsrc_data->offset = 0; + rsrc_data->width = 0; + rsrc_data->height = 0; + rsrc_data->stride = 0; + rsrc_data->format = 0; + rsrc_data->pack_fmt = 0; + rsrc_data->burst_len = 0; + rsrc_data->irq_subsample_period = 0; + rsrc_data->irq_subsample_pattern = 0; + rsrc_data->framedrop_period = 0; + rsrc_data->framedrop_pattern = 0; + rsrc_data->packer_cfg = 0; + rsrc_data->en_ubwc = 0; + rsrc_data->h_init = 0; + rsrc_data->ubwc_meta_addr = 0; + rsrc_data->ubwc_meta_cfg = 0; + rsrc_data->ubwc_mode_cfg = 0; + rsrc_data->ubwc_stats_ctrl = 0; + rsrc_data->ubwc_ctrl_2 = 0; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->ubwc_updated = false; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rsrc_data->ubwc_lossy_threshold_0 = 0; + rsrc_data->ubwc_lossy_threshold_1 = 0; + rsrc_data->ubwc_offset_lossy_variance = 0; + rsrc_data->ubwc_bandwidth_limit = 0; + wm_res->tasklet_info = NULL; + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + CAM_DBG(CAM_ISP, "VFE:%d Release WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + return 0; +} + +static int cam_vfe_bus_ver3_start_wm(struct cam_isp_resource_node *wm_res) +{ + int val = 0; + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver3_common_data *common_data = + rsrc_data->common_data; + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_regs; + + ubwc_regs = (struct cam_vfe_bus_ver3_reg_offset_ubwc_client *) + rsrc_data->hw_regs->ubwc_regs; + + cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); + + cam_io_w((rsrc_data->height << 16) | rsrc_data->width, + common_data->mem_base + rsrc_data->hw_regs->image_cfg_0); + cam_io_w(rsrc_data->pack_fmt, + common_data->mem_base + rsrc_data->hw_regs->packer_cfg); + + /* enable ubwc if needed*/ + if (rsrc_data->en_ubwc) { + val = cam_io_r_mb(common_data->mem_base + ubwc_regs->mode_cfg); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + ubwc_regs->mode_cfg); + } + + /* Enable WM */ + cam_io_w_mb(rsrc_data->en_cfg, common_data->mem_base + + rsrc_data->hw_regs->cfg); + + CAM_DBG(CAM_ISP, + "Start VFE:%d WM:%d offset:0x%X en_cfg:0x%X width:%d height:%d", + rsrc_data->common_data->core_index, rsrc_data->index, + (uint32_t) rsrc_data->hw_regs->cfg, rsrc_data->en_cfg, + rsrc_data->width, rsrc_data->height); + CAM_DBG(CAM_ISP, "WM:%d pk_fmt:%d stride:%d burst len:%d", + rsrc_data->index, rsrc_data->pack_fmt & PACKER_FMT_VER3_MAX, + rsrc_data->stride, 0xF); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_vfe_bus_ver3_stop_wm(struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data = + wm_res->res_priv; + struct cam_vfe_bus_ver3_common_data *common_data = + rsrc_data->common_data; + + /* Disable WM */ + cam_io_w_mb(0x0, common_data->mem_base + rsrc_data->hw_regs->cfg); + CAM_DBG(CAM_ISP, "Stop VFE:%d WM:%d", + rsrc_data->common_data->core_index, rsrc_data->index); + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rsrc_data->init_cfg_done = false; + rsrc_data->hfr_cfg_done = false; + rsrc_data->ubwc_updated = false; + + return 0; +} + +static int cam_vfe_bus_ver3_handle_wm_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_ver3_handle_wm_done_bottom_half(void *wm_node, + void *evt_payload_priv) +{ + return -EPERM; +} + +static int cam_vfe_bus_ver3_init_wm_resource(uint32_t index, + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info, + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver3_wm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for WM res priv"); + return -ENOMEM; + } + wm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &ver3_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver3_bus_priv->common_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = cam_vfe_bus_ver3_start_wm; + wm_res->stop = cam_vfe_bus_ver3_stop_wm; + wm_res->top_half_handler = cam_vfe_bus_ver3_handle_wm_done_top_half; + wm_res->bottom_half_handler = + cam_vfe_bus_ver3_handle_wm_done_bottom_half; + wm_res->hw_intf = ver3_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_wm_resource( + struct cam_isp_resource_node *wm_res) +{ + struct cam_vfe_bus_ver3_wm_resource_data *rsrc_data; + + wm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&wm_res->list); + + wm_res->start = NULL; + wm_res->stop = NULL; + wm_res->top_half_handler = NULL; + wm_res->bottom_half_handler = NULL; + wm_res->hw_intf = NULL; + + rsrc_data = wm_res->res_priv; + wm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_vfe_bus_ver3_add_wm_to_comp_grp( + struct cam_isp_resource_node *comp_grp, + uint32_t composite_mask) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = comp_grp->res_priv; + + rsrc_data->composite_mask |= composite_mask; +} + +static bool cam_vfe_bus_ver3_match_comp_grp( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_resource_node **comp_grp, + uint32_t comp_grp_id) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + struct cam_isp_resource_node *comp_grp_local = NULL; + + list_for_each_entry(comp_grp_local, + &ver3_bus_priv->used_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_type == comp_grp_id) { + /* Match found */ + *comp_grp = comp_grp_local; + return true; + } + } + + list_for_each_entry(comp_grp_local, + &ver3_bus_priv->free_comp_grp, list) { + rsrc_data = comp_grp_local->res_priv; + if (rsrc_data->comp_grp_type == comp_grp_id) { + /* Match found */ + *comp_grp = comp_grp_local; + list_del(&comp_grp_local->list); + list_add_tail(&comp_grp_local->list, + &ver3_bus_priv->used_comp_grp); + return false; + } + } + + *comp_grp = NULL; + return false; +} + +static int cam_vfe_bus_ver3_acquire_comp_grp( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_out_port_generic_info *out_port_info, + void *tasklet, + uint32_t is_dual, + uint32_t is_master, + enum cam_vfe_bus_ver3_vfe_core_id dual_slave_core, + struct cam_isp_resource_node **comp_grp, + enum cam_vfe_bus_ver3_comp_grp_type comp_grp_id) +{ + int rc = 0; + struct cam_isp_resource_node *comp_grp_local = NULL; + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + bool previously_acquired = false; + + if (comp_grp_id >= CAM_VFE_BUS_VER3_COMP_GRP_0 && + comp_grp_id <= CAM_VFE_BUS_VER3_COMP_GRP_13) { + /* Check if matching comp_grp has already been acquired */ + previously_acquired = cam_vfe_bus_ver3_match_comp_grp( + ver3_bus_priv, &comp_grp_local, comp_grp_id); + } + + if (!comp_grp_local) { + CAM_ERR(CAM_ISP, "Invalid comp_grp:%d", comp_grp_id); + return -ENODEV; + } + + rsrc_data = comp_grp_local->res_priv; + + if (!previously_acquired) { + if (is_dual) { + rc = cam_vfe_bus_ver3_get_intra_client_mask( + dual_slave_core, + comp_grp_local->hw_intf->hw_idx, + &rsrc_data->intra_client_mask); + if (rc) + return rc; + } + + comp_grp_local->tasklet_info = tasklet; + comp_grp_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + rsrc_data->is_master = is_master; + rsrc_data->is_dual = is_dual; + + if (is_master) + rsrc_data->addr_sync_mode = 0; + else + rsrc_data->addr_sync_mode = 1; + + } else { + rsrc_data = comp_grp_local->res_priv; + /* Do not support runtime change in composite mask */ + if (comp_grp_local->res_state == + CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d comp_grp:%u", + comp_grp_local->res_state, + rsrc_data->comp_grp_type); + return -EBUSY; + } + } + + CAM_DBG(CAM_ISP, "Acquire VFE:%d comp_grp:%u", + rsrc_data->common_data->core_index, rsrc_data->comp_grp_type); + + rsrc_data->acquire_dev_cnt++; + *comp_grp = comp_grp_local; + + return rc; +} + +static int cam_vfe_bus_ver3_release_comp_grp( + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_isp_resource_node *in_comp_grp) +{ + struct cam_isp_resource_node *comp_grp = NULL; + struct cam_vfe_bus_ver3_comp_grp_data *in_rsrc_data = NULL; + int match_found = 0; + + if (!in_comp_grp) { + CAM_ERR(CAM_ISP, "Invalid Params comp_grp %pK", in_comp_grp); + return -EINVAL; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Already released comp_grp"); + return 0; + } + + if (in_comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_ERR(CAM_ISP, "Invalid State %d", + in_comp_grp->res_state); + return -EBUSY; + } + + in_rsrc_data = in_comp_grp->res_priv; + CAM_DBG(CAM_ISP, "Release VFE:%d comp_grp:%u", + ver3_bus_priv->common_data.core_index, + in_rsrc_data->comp_grp_type); + + list_for_each_entry(comp_grp, &ver3_bus_priv->used_comp_grp, list) { + if (comp_grp == in_comp_grp) { + match_found = 1; + break; + } + } + + if (!match_found) { + CAM_ERR(CAM_ISP, "Could not find comp_grp:%u", + in_rsrc_data->comp_grp_type); + return -ENODEV; + } + + in_rsrc_data->acquire_dev_cnt--; + if (in_rsrc_data->acquire_dev_cnt == 0) { + list_del(&comp_grp->list); + + in_rsrc_data->dual_slave_core = CAM_VFE_BUS_VER3_VFE_CORE_MAX; + in_rsrc_data->addr_sync_mode = 0; + in_rsrc_data->composite_mask = 0; + + comp_grp->tasklet_info = NULL; + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + list_add_tail(&comp_grp->list, &ver3_bus_priv->free_comp_grp); + } + + return 0; +} + +static int cam_vfe_bus_ver3_start_comp_grp( + struct cam_isp_resource_node *comp_grp, uint32_t *bus_irq_reg_mask) +{ + int rc = 0; + uint32_t val; + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + + rsrc_data = comp_grp->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, + "Start VFE:%d comp_grp:%d streaming state:%d comp_mask:0x%X", + rsrc_data->common_data->core_index, + rsrc_data->comp_grp_type, comp_grp->res_state, + rsrc_data->composite_mask); + + if (comp_grp->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + return 0; + + if (rsrc_data->is_dual) { + if (rsrc_data->is_master) { + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val |= (0x1 << (rsrc_data->comp_grp_type + 14)); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_1); + + val |= (0x1 << rsrc_data->comp_grp_type); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_1); + } else { + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val |= (0x1 << rsrc_data->comp_grp_type); + val |= (0x1 << (rsrc_data->comp_grp_type + 14)); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_0); + + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->comp_cfg_1); + + val |= (0x1 << rsrc_data->comp_grp_type); + + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->comp_cfg_1); + } + } + + if (rsrc_data->ubwc_static_ctrl) { + val = cam_io_r_mb(common_data->mem_base + + common_data->common_reg->ubwc_static_ctrl); + val |= rsrc_data->ubwc_static_ctrl; + cam_io_w_mb(val, common_data->mem_base + + common_data->common_reg->ubwc_static_ctrl); + } + + bus_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0] = + (0x1 << (rsrc_data->comp_grp_type + + rsrc_data->common_data->comp_done_shift)); + + CAM_DBG(CAM_ISP, "Start Done VFE:%d comp_grp:%d bus_irq_mask_0: 0x%X", + rsrc_data->common_data->core_index, + rsrc_data->comp_grp_type, + bus_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0]); + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return rc; +} + +static int cam_vfe_bus_ver3_stop_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return 0; +} + +static int cam_vfe_bus_ver3_handle_comp_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_bus_ver3_handle_comp_done_bottom_half( + void *handler_priv, + void *evt_payload_priv, + uint32_t *comp_mask) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *comp_grp = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = comp_grp->res_priv; + uint32_t *cam_ife_irq_regs; + uint32_t status_0; + + if (!evt_payload) + return rc; + + if (rsrc_data->is_dual && (!rsrc_data->is_master)) { + CAM_ERR(CAM_ISP, "Invalid comp_grp:%u is_master:%u", + rsrc_data->comp_grp_type, rsrc_data->is_master); + return rc; + } + + cam_ife_irq_regs = evt_payload->irq_reg_val; + status_0 = cam_ife_irq_regs[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + + if (status_0 & BIT(rsrc_data->comp_grp_type + + rsrc_data->common_data->comp_done_shift)) { + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + rc = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + CAM_DBG(CAM_ISP, "VFE:%d comp_grp:%d Bus IRQ status_0: 0x%X rc:%d", + rsrc_data->common_data->core_index, rsrc_data->comp_grp_type, + status_0, rc); + + *comp_mask = rsrc_data->composite_mask; + + return rc; +} + +static int cam_vfe_bus_ver3_init_comp_grp(uint32_t index, + struct cam_hw_soc_info *soc_info, + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info, + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = NULL; + struct cam_vfe_soc_private *vfe_soc_private = soc_info->soc_private; + int ddr_type = 0; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver3_comp_grp_data), + GFP_KERNEL); + if (!rsrc_data) + return -ENOMEM; + + comp_grp->res_priv = rsrc_data; + + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&comp_grp->list); + + rsrc_data->comp_grp_type = index; + rsrc_data->common_data = &ver3_bus_priv->common_data; + rsrc_data->dual_slave_core = CAM_VFE_BUS_VER3_VFE_CORE_MAX; + + if (rsrc_data->comp_grp_type != CAM_VFE_BUS_VER3_COMP_GRP_0 && + rsrc_data->comp_grp_type != CAM_VFE_BUS_VER3_COMP_GRP_1) + rsrc_data->ubwc_static_ctrl = 0; + else { + ddr_type = of_fdt_get_ddrtype(); + if ((ddr_type == DDR_TYPE_LPDDR5) || + (ddr_type == DDR_TYPE_LPDDR5X)) + rsrc_data->ubwc_static_ctrl = + vfe_soc_private->ubwc_static_ctrl[1]; + else + rsrc_data->ubwc_static_ctrl = + vfe_soc_private->ubwc_static_ctrl[0]; + } + + list_add_tail(&comp_grp->list, &ver3_bus_priv->free_comp_grp); + + comp_grp->top_half_handler = cam_vfe_bus_ver3_handle_comp_done_top_half; + comp_grp->hw_intf = ver3_bus_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_comp_grp( + struct cam_isp_resource_node *comp_grp) +{ + struct cam_vfe_bus_ver3_comp_grp_data *rsrc_data = + comp_grp->res_priv; + + comp_grp->start = NULL; + comp_grp->stop = NULL; + comp_grp->top_half_handler = NULL; + comp_grp->bottom_half_handler = NULL; + comp_grp->hw_intf = NULL; + + list_del_init(&comp_grp->list); + comp_grp->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + + comp_grp->res_priv = NULL; + + if (!rsrc_data) { + CAM_ERR(CAM_ISP, "comp_grp_priv is NULL"); + return -ENODEV; + } + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_ver3_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + bool *mode = cmd_args; + struct cam_isp_resource_node *res = + (struct cam_isp_resource_node *) priv; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = + (struct cam_vfe_bus_ver3_vfe_out_data *)res->res_priv; + + *mode = (rsrc_data->secure_mode == CAM_SECURE_MODE_SECURE) ? + true : false; + + return 0; +} + +static int cam_vfe_bus_ver3_acquire_vfe_out(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id; + uint32_t format; + int num_wm; + struct cam_vfe_bus_ver3_priv *ver3_bus_priv = bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *out_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + enum cam_vfe_bus_ver3_comp_grp_type comp_grp_id; + uint32_t client_done_mask = 0; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + out_acquire_args = &acq_args->vfe_out; + format = out_acquire_args->out_port_info->format; + + CAM_DBG(CAM_ISP, "VFE:%d Acquire out_type:0x%X", + ver3_bus_priv->common_data.core_index, + out_acquire_args->out_port_info->res_type); + + vfe_out_res_id = cam_vfe_bus_ver3_get_out_res_id( + out_acquire_args->out_port_info->res_type); + if (vfe_out_res_id == CAM_VFE_BUS_VER3_VFE_OUT_MAX) + return -ENODEV; + + num_wm = cam_vfe_bus_ver3_get_num_wm(vfe_out_res_id, format); + if (num_wm < 1) + return -EINVAL; + + rsrc_node = &ver3_bus_priv->vfe_out[vfe_out_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "VFE:%d out_type:0x%X resource not available state:%d", + ver3_bus_priv->common_data.core_index, + vfe_out_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + rsrc_data->common_data->event_cb = acq_args->event_cb; + rsrc_data->priv = acq_args->priv; + + secure_caps = cam_vfe_bus_ver3_can_be_secure( + rsrc_data->out_type); + mode = out_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + ver3_bus_priv->tasklet_info = acq_args->tasklet; + rsrc_data->num_wm = num_wm; + rsrc_node->rdi_only_ctx = 0; + rsrc_node->res_id = out_acquire_args->out_port_info->res_type; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = out_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = out_acquire_args->cdm_ops; + + /* Acquire WM and retrieve COMP GRP ID */ + for (i = 0; i < num_wm; i++) { + rc = cam_vfe_bus_ver3_acquire_wm(ver3_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + vfe_out_res_id, + i, + &rsrc_data->wm_res[i], + &client_done_mask, + out_acquire_args->is_dual, + &comp_grp_id); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to acquire WM VFE:%d out_type:%d rc:%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + goto release_wm; + } + } + + /* Acquire composite group using COMP GRP ID */ + rc = cam_vfe_bus_ver3_acquire_comp_grp(ver3_bus_priv, + out_acquire_args->out_port_info, + acq_args->tasklet, + out_acquire_args->is_dual, + out_acquire_args->is_master, + out_acquire_args->dual_slave_core, + &rsrc_data->comp_grp, + comp_grp_id); + if (rc) { + CAM_ERR(CAM_ISP, + "Failed to acquire comp_grp VFE:%d out_typp:%d rc:%d", + rsrc_data->common_data->core_index, + vfe_out_res_id, rc); + return rc; + } + + rsrc_data->is_dual = out_acquire_args->is_dual; + rsrc_data->is_master = out_acquire_args->is_master; + + cam_vfe_bus_ver3_add_wm_to_comp_grp(rsrc_data->comp_grp, + client_done_mask); + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + out_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_wm: + for (i--; i >= 0; i--) + cam_vfe_bus_ver3_release_wm(ver3_bus_priv, + rsrc_data->wm_res[i]); + + cam_vfe_bus_ver3_release_comp_grp(ver3_bus_priv, rsrc_data->comp_grp); + + return rc; +} + +static int cam_vfe_bus_ver3_release_vfe_out(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_out = release_args; + rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, + "Invalid resource state:%d VFE:%d out_type:0x%X", + vfe_out->res_state, rsrc_data->common_data->core_index, + vfe_out->res_id); + } + + for (i = 0; i < rsrc_data->num_wm; i++) + cam_vfe_bus_ver3_release_wm(bus_priv, rsrc_data->wm_res[i]); + rsrc_data->num_wm = 0; + + if (rsrc_data->comp_grp) + cam_vfe_bus_ver3_release_comp_grp(bus_priv, + rsrc_data->comp_grp); + rsrc_data->comp_grp = NULL; + + vfe_out->tasklet_info = NULL; + vfe_out->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_ver3_can_be_secure(rsrc_data->out_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_ver3_start_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + uint32_t bus_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_MAX]; + uint32_t rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_MAX]; + uint32_t source_group = 0; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + source_group = rsrc_data->source_group; + + CAM_DBG(CAM_ISP, "Start VFE:%d out_type:0x%X", + rsrc_data->common_data->core_index, rsrc_data->out_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, + "Invalid resource state:%d VFE:%d out_type:0x%X", + vfe_out->res_state, rsrc_data->common_data->core_index, + rsrc_data->out_type); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_ver3_start_wm(rsrc_data->wm_res[i]); + + memset(bus_irq_reg_mask, 0, sizeof(bus_irq_reg_mask)); + rc = cam_vfe_bus_ver3_start_comp_grp(rsrc_data->comp_grp, + bus_irq_reg_mask); + + if (rsrc_data->is_dual && !rsrc_data->is_master) + goto end; + + vfe_out->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, + CAM_IRQ_PRIORITY_1, + bus_irq_reg_mask, + vfe_out, + vfe_out->top_half_handler, + vfe_out->bottom_half_handler, + vfe_out->tasklet_info, + &tasklet_bh_api); + + if (vfe_out->irq_handle < 1) { + CAM_ERR(CAM_ISP, "Subscribe IRQ failed for VFE out_res %d", + vfe_out->res_id); + vfe_out->irq_handle = 0; + return -EFAULT; + } + + if ((common_data->is_lite || source_group > CAM_VFE_BUS_VER3_SRC_GRP_0) + && !vfe_out->rdi_only_ctx) + goto end; + + if (!common_data->rup_irq_handle[source_group]) { + memset(rup_irq_reg_mask, 0, sizeof(rup_irq_reg_mask)); + rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0] |= + 0x1 << source_group; + + CAM_DBG(CAM_ISP, + "VFE:%d out_type:0x%X bus_irq_mask_0:0x%X for RUP", + rsrc_data->common_data->core_index, rsrc_data->out_type, + rup_irq_reg_mask[CAM_VFE_BUS_VER3_IRQ_REG0]); + + common_data->rup_irq_handle[source_group] = + cam_irq_controller_subscribe_irq( + common_data->rup_irq_controller, + CAM_IRQ_PRIORITY_0, + rup_irq_reg_mask, + vfe_out, + cam_vfe_bus_ver3_handle_rup_top_half, + cam_vfe_bus_ver3_handle_rup_bottom_half, + vfe_out->tasklet_info, + &tasklet_bh_api); + + if (common_data->rup_irq_handle[source_group] < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe RUP IRQ"); + common_data->rup_irq_handle[source_group] = 0; + return -EFAULT; + } + } + +end: + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_ver3_stop_vfe_out( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_ver3_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_out->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "Stop VFE:%d out_type:0x%X state:%d", + rsrc_data->common_data->core_index, rsrc_data->out_type, + vfe_out->res_state); + return rc; + } + + rc = cam_vfe_bus_ver3_stop_comp_grp(rsrc_data->comp_grp); + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_ver3_stop_wm(rsrc_data->wm_res[i]); + + if (common_data->rup_irq_handle[rsrc_data->source_group]) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->rup_irq_controller, + common_data->rup_irq_handle[rsrc_data->source_group]); + common_data->rup_irq_handle[rsrc_data->source_group] = 0; + } + + if (vfe_out->irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + vfe_out->irq_handle); + vfe_out->irq_handle = 0; + } + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_ver3_handle_vfe_out_done_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + vfe_out = th_payload->handler_priv; + if (!vfe_out) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = vfe_out->res_priv; + + CAM_DBG(CAM_ISP, "VFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + + rc = cam_vfe_bus_ver3_get_evt_payload(rsrc_data->common_data, + &evt_payload); + + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d Bus IRQ status_0: 0x%X status_1: 0x%X", + rsrc_data->common_data->core_index, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + evt_payload->core_index = rsrc_data->common_data->core_index; + evt_payload->evt_id = evt_id; + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_bus_ver3_handle_vfe_out_done_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int rc = -EINVAL, num_out = 0, i = 0; + struct cam_isp_resource_node *vfe_out = handler_priv; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = vfe_out->res_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_isp_hw_event_info evt_info; + void *ctx = NULL; + uint32_t evt_id = 0, comp_mask = 0; + uint32_t out_list[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; + + rc = cam_vfe_bus_ver3_handle_comp_done_bottom_half( + rsrc_data->comp_grp, evt_payload_priv, &comp_mask); + CAM_DBG(CAM_ISP, "VFE:%d out_type:0x%X rc:%d", + rsrc_data->common_data->core_index, rsrc_data->out_type, + rsrc_data->out_type, rc); + + ctx = rsrc_data->priv; + memset(out_list, 0, sizeof(out_list)); + + switch (rc) { + case CAM_VFE_IRQ_STATUS_SUCCESS: + evt_id = evt_payload->evt_id; + + evt_info.res_type = vfe_out->res_type; + evt_info.hw_idx = vfe_out->hw_intf->hw_idx; + + rc = cam_vfe_bus_ver3_get_comp_vfe_out_res_id_list( + comp_mask, out_list, &num_out, + rsrc_data->common_data->is_lite); + for (i = 0; i < num_out; i++) { + evt_info.res_id = out_list[i]; + if (rsrc_data->common_data->event_cb) + rsrc_data->common_data->event_cb(ctx, evt_id, + (void *)&evt_info); + } + break; + default: + break; + } + + cam_vfe_bus_ver3_put_evt_payload(rsrc_data->common_data, &evt_payload); + + return rc; +} + +static int cam_vfe_bus_ver3_init_vfe_out_resource(uint32_t index, + struct cam_vfe_bus_ver3_priv *ver3_bus_priv, + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info) +{ + struct cam_isp_resource_node *vfe_out = NULL; + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_out_type = + ver3_hw_info->vfe_out_hw_info[index].vfe_out_type; + + if (vfe_out_type < 0 || + vfe_out_type >= CAM_VFE_BUS_VER3_VFE_OUT_MAX) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_out_type); + return -EINVAL; + } + + vfe_out = &ver3_bus_priv->vfe_out[vfe_out_type]; + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_out->res_priv) { + CAM_ERR(CAM_ISP, "vfe_out_type %d has already been initialized", + vfe_out_type); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_ver3_vfe_out_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_out->res_priv = rsrc_data; + + vfe_out->res_type = CAM_ISP_RESOURCE_VFE_OUT; + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + + rsrc_data->source_group = + ver3_hw_info->vfe_out_hw_info[index].source_group; + rsrc_data->out_type = + ver3_hw_info->vfe_out_hw_info[index].vfe_out_type; + rsrc_data->common_data = &ver3_bus_priv->common_data; + rsrc_data->max_width = + ver3_hw_info->vfe_out_hw_info[index].max_width; + rsrc_data->max_height = + ver3_hw_info->vfe_out_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_out->start = cam_vfe_bus_ver3_start_vfe_out; + vfe_out->stop = cam_vfe_bus_ver3_stop_vfe_out; + vfe_out->top_half_handler = + cam_vfe_bus_ver3_handle_vfe_out_done_top_half; + vfe_out->bottom_half_handler = + cam_vfe_bus_ver3_handle_vfe_out_done_bottom_half; + vfe_out->process_cmd = cam_vfe_bus_ver3_process_cmd; + vfe_out->hw_intf = ver3_bus_priv->common_data.hw_intf; + vfe_out->irq_handle = 0; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_vfe_out_resource( + struct cam_isp_resource_node *vfe_out) +{ + struct cam_vfe_bus_ver3_vfe_out_data *rsrc_data = vfe_out->res_priv; + + if (vfe_out->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "VFE:%d out_type:%d already deinitialized", + rsrc_data->common_data->core_index, + rsrc_data->out_type); + return 0; + } + + vfe_out->start = NULL; + vfe_out->stop = NULL; + vfe_out->top_half_handler = NULL; + vfe_out->bottom_half_handler = NULL; + vfe_out->hw_intf = NULL; + vfe_out->irq_handle = 0; + + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_out->list); + vfe_out->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static void cam_vfe_bus_ver3_print_dimensions( + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + struct cam_vfe_bus_ver3_priv *bus_priv) +{ + struct cam_isp_resource_node *wm_res = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + int wm_idx = 0; + + wm_idx = cam_vfe_bus_ver3_get_wm_idx(vfe_out_res_id, plane, + bus_priv->common_data.is_lite); + + if (wm_idx < 0 || wm_idx >= bus_priv->num_client || plane > PLANE_C) { + CAM_ERR(CAM_ISP, + "Unsupported VFE out_type:0x%X plane:%d wm_idx:%d max_idx:%d", + vfe_out_res_id, plane, wm_idx, + bus_priv->num_client - 1); + return; + } + + wm_res = &bus_priv->bus_client[wm_idx]; + wm_data = wm_res->res_priv; + + CAM_INFO(CAM_ISP, + "VFE:%d WM:%d width:%u height:%u stride:%u x_init:%u en_cfg:%u", + wm_data->common_data->core_index, wm_idx, wm_data->width, + wm_data->height, wm_data->stride, wm_data->h_init, + wm_data->en_cfg); +} + +static int cam_vfe_bus_ver3_handle_bus_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + int rc = 0; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Enter"); + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.bus_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; +} + +static int cam_vfe_bus_ver3_handle_rup_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + int rc = 0; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "Enter"); + rc = cam_irq_controller_handle_irq(evt_id, + bus_priv->common_data.rup_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; +} + +static int cam_vfe_bus_ver3_err_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int i = 0, rc = 0; + struct cam_vfe_bus_ver3_priv *bus_priv = + th_payload->handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d BUS Err IRQ", + bus_priv->common_data.core_index); + for (i = 0; i < th_payload->num_registers; i++) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "VFE:%d BUS IRQ status_%d: 0x%X", + bus_priv->common_data.core_index, i, + th_payload->evt_status_arr[i]); + } + cam_irq_controller_disable_irq(bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + + rc = cam_vfe_bus_ver3_get_evt_payload(&bus_priv->common_data, + &evt_payload); + if (rc) + return rc; + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->core_index = bus_priv->common_data.core_index; + + evt_payload->ccif_violation_status = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->ccif_violation_status); + + evt_payload->image_size_violation_status = cam_io_r_mb( + bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->image_size_violation_status); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_bus_ver3_err_irq_bottom_half( + void *handler_priv, void *evt_payload_priv) +{ + struct cam_vfe_bus_irq_evt_payload *evt_payload = evt_payload_priv; + struct cam_vfe_bus_ver3_priv *bus_priv = handler_priv; + struct cam_vfe_bus_ver3_common_data *common_data; + struct cam_isp_hw_event_info evt_info; + uint32_t val = 0, image_size_violation = 0, ccif_violation = 0; + + if (!handler_priv || !evt_payload_priv) + return -EINVAL; + + common_data = &bus_priv->common_data; + + val = evt_payload->irq_reg_val[CAM_IFE_IRQ_BUS_VER3_REG_STATUS0]; + image_size_violation = (val >> 31) & 0x1; + ccif_violation = (val >> 30) & 0x1; + + CAM_ERR(CAM_ISP, + "VFE:%d BUS Violation image_size_violation %d ccif_violation %d", + bus_priv->common_data.core_index, image_size_violation, + ccif_violation); + CAM_INFO(CAM_ISP, + "image_size_violation_status 0x%X ccif_violation_status 0x%X", + evt_payload->image_size_violation_status, + evt_payload->ccif_violation_status); + + if (common_data->is_lite) { + if (image_size_violation) { + val = evt_payload->image_size_violation_status; + + if (val & 0x01) { + CAM_INFO(CAM_ISP, + "RDI 0 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + PLANE_Y, + bus_priv); + } + + if (val & 0x02) { + CAM_INFO(CAM_ISP, + "RDI 1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + PLANE_Y, + bus_priv); + } + + if (val & 0x04) { + CAM_INFO(CAM_ISP, + "RDI 2 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + PLANE_Y, + bus_priv); + } + + if (val & 0x08) { + CAM_INFO(CAM_ISP, + "RDI 3 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + PLANE_Y, + bus_priv); + } + } + + if (ccif_violation) { + val = evt_payload->ccif_violation_status; + + if (val & 0x01) + CAM_INFO(CAM_ISP, + "RDI 0 ccif violation"); + + if (val & 0x02) + CAM_INFO(CAM_ISP, + "RDI 1 ccif violation"); + + if (val & 0x04) + CAM_INFO(CAM_ISP, + "RDI 2 ccif violation"); + + if (val & 0x08) + CAM_INFO(CAM_ISP, + "RDI 3 ccif violation"); + } + + goto end; + } + + if (image_size_violation) { + val = evt_payload->image_size_violation_status; + + if (val & 0x01) { + CAM_INFO(CAM_ISP, "VID Y 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL, + PLANE_Y, + bus_priv); + } + + if (val & 0x02) { + CAM_INFO(CAM_ISP, "VID C 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL, + PLANE_C, + bus_priv); + } + + if (val & 0x04) { + CAM_INFO(CAM_ISP, "VID YC 4:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS4, + PLANE_Y, + bus_priv); + } + + if (val & 0x08) { + CAM_INFO(CAM_ISP, "VID YC 16:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS16, + PLANE_Y, + bus_priv); + } + + if (val & 0x010) { + CAM_INFO(CAM_ISP, "DISP Y 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + PLANE_Y, + bus_priv); + } + + if (val & 0x020) { + CAM_INFO(CAM_ISP, "DISP C 1:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + PLANE_C, + bus_priv); + } + + if (val & 0x040) { + CAM_INFO(CAM_ISP, "DISP YC 4:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + PLANE_Y, + bus_priv); + } + + if (val & 0x080) { + CAM_INFO(CAM_ISP, "DISP YC 16:1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + PLANE_Y, + bus_priv); + } + + if (val & 0x0100) { + CAM_INFO(CAM_ISP, "FD Y image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FD, + PLANE_Y, + bus_priv); + } + + if (val & 0x0200) { + CAM_INFO(CAM_ISP, "FD C image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_FD, + PLANE_C, + bus_priv); + } + + if (val & 0x0400) { + CAM_INFO(CAM_ISP, + "PIXEL RAW DUMP image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + PLANE_Y, + bus_priv); + } + + if (val & 0x01000) { + CAM_INFO(CAM_ISP, "STATS HDR BE image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + PLANE_Y, + bus_priv); + } + + if (val & 0x02000) { + CAM_INFO(CAM_ISP, + "STATS HDR BHIST image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + PLANE_Y, + bus_priv); + } + + if (val & 0x04000) { + CAM_INFO(CAM_ISP, + "STATS TINTLESS BG image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + PLANE_Y, + bus_priv); + } + + if (val & 0x08000) { + CAM_INFO(CAM_ISP, "STATS AWB BG image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + PLANE_Y, + bus_priv); + } + + if (val & 0x010000) { + CAM_INFO(CAM_ISP, "STATS BHIST image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + PLANE_Y, + bus_priv); + } + + if (val & 0x020000) { + CAM_INFO(CAM_ISP, "STATS RS image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + PLANE_Y, + bus_priv); + } + + if (val & 0x040000) { + CAM_INFO(CAM_ISP, "STATS CS image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + PLANE_Y, + bus_priv); + } + + if (val & 0x080000) { + CAM_INFO(CAM_ISP, "STATS IHIST image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + PLANE_Y, + bus_priv); + } + + if (val & 0x0100000) { + CAM_INFO(CAM_ISP, "STATS BAF image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + PLANE_Y, + bus_priv); + } + + if (val & 0x0200000) { + CAM_INFO(CAM_ISP, "PD image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_2PD, + PLANE_Y, + bus_priv); + } + + if (val & 0x0400000) { + CAM_INFO(CAM_ISP, "LCR image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_LCR, + PLANE_Y, + bus_priv); + } + + if (val & 0x0800000) { + CAM_INFO(CAM_ISP, "RDI 0 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + PLANE_Y, + bus_priv); + } + + if (val & 0x01000000) { + CAM_INFO(CAM_ISP, "RDI 1 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + PLANE_Y, + bus_priv); + } + + if (val & 0x02000000) { + CAM_INFO(CAM_ISP, "RDI 2 image size violation"); + cam_vfe_bus_ver3_print_dimensions( + CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + PLANE_Y, + bus_priv); + } + + } + + if (ccif_violation) { + val = evt_payload->ccif_violation_status; + + if (val & 0x01) + CAM_INFO(CAM_ISP, "VID Y 1:1 ccif violation"); + + if (val & 0x02) + CAM_INFO(CAM_ISP, "VID C 1:1 ccif violation"); + + if (val & 0x04) + CAM_INFO(CAM_ISP, "VID YC 4:1 ccif violation"); + + if (val & 0x08) + CAM_INFO(CAM_ISP, "VID YC 16:1 ccif violation"); + + if (val & 0x010) + CAM_INFO(CAM_ISP, "DISP Y 1:1 ccif violation"); + + if (val & 0x020) + CAM_INFO(CAM_ISP, "DISP C 1:1 ccif violation"); + + if (val & 0x040) + CAM_INFO(CAM_ISP, "DISP YC 4:1 ccif violation"); + + if (val & 0x080) + CAM_INFO(CAM_ISP, "DISP YC 16:1 ccif violation"); + + if (val & 0x0100) + CAM_INFO(CAM_ISP, "FD Y ccif violation"); + + if (val & 0x0200) + CAM_INFO(CAM_ISP, "FD C ccif violation"); + + if (val & 0x0400) + CAM_INFO(CAM_ISP, "PIXEL RAW DUMP ccif violation"); + + if (val & 0x01000) + CAM_INFO(CAM_ISP, "STATS HDR BE ccif violation"); + + if (val & 0x02000) + CAM_INFO(CAM_ISP, "STATS HDR BHIST ccif violation"); + + if (val & 0x04000) + CAM_INFO(CAM_ISP, "STATS TINTLESS BG ccif violation"); + + if (val & 0x08000) + CAM_INFO(CAM_ISP, "STATS AWB BG ccif violation"); + + if (val & 0x010000) + CAM_INFO(CAM_ISP, "STATS BHIST ccif violation"); + + if (val & 0x020000) + CAM_INFO(CAM_ISP, "STATS RS ccif violation"); + + if (val & 0x040000) + CAM_INFO(CAM_ISP, "STATS CS ccif violation"); + + if (val & 0x080000) + CAM_INFO(CAM_ISP, "STATS IHIST ccif violation"); + + if (val & 0x0100000) + CAM_INFO(CAM_ISP, "STATS BAF ccif violation"); + + if (val & 0x0200000) + CAM_INFO(CAM_ISP, "PD ccif violation"); + + if (val & 0x0400000) + CAM_INFO(CAM_ISP, "LCR ccif violation"); + + if (val & 0x0800000) + CAM_INFO(CAM_ISP, "RDI 0 ccif violation"); + + if (val & 0x01000000) + CAM_INFO(CAM_ISP, "RDI 1 ccif violation"); + + if (val & 0x02000000) + CAM_INFO(CAM_ISP, "RDI 2 ccif violation"); + + } + +end: + cam_vfe_bus_ver3_put_evt_payload(common_data, &evt_payload); + + evt_info.hw_idx = common_data->core_index; + evt_info.res_type = CAM_ISP_RESOURCE_VFE_OUT; + evt_info.res_id = CAM_VFE_BUS_VER3_VFE_OUT_MAX; + evt_info.err_type = CAM_VFE_IRQ_STATUS_VIOLATION; + + if (common_data->event_cb) + common_data->event_cb(NULL, CAM_ISP_HW_EVENT_ERROR, + (void *)&evt_info); + return 0; +} + +static void cam_vfe_bus_ver3_update_ubwc_meta_addr( + uint32_t *reg_val_pair, + uint32_t *j, + void *regs, + uint64_t image_buf) +{ + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_regs; + + if (!regs || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver3_reg_offset_ubwc_client *)regs; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_addr, image_buf); + +end: + return; +} + +static int cam_vfe_bus_ver3_update_ubwc_regs( + struct cam_vfe_bus_ver3_wm_resource_data *wm_data, + uint32_t *reg_val_pair, uint32_t i, uint32_t *j) +{ + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_regs; + int rc = 0; + + if (!wm_data || !reg_val_pair || !j) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + ubwc_regs = (struct cam_vfe_bus_ver3_reg_offset_ubwc_client *) + wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); + CAM_DBG(CAM_ISP, "WM:%d packer cfg 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->meta_cfg, wm_data->ubwc_meta_cfg); + CAM_DBG(CAM_ISP, "WM:%d meta stride 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->mode_cfg, wm_data->ubwc_mode_cfg); + CAM_DBG(CAM_ISP, "WM:%d ubwc_mode_cfg 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->ctrl_2, wm_data->ubwc_ctrl_2); + CAM_DBG(CAM_ISP, "WM:%d ubwc_ctrl_2 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->lossy_thresh0, wm_data->ubwc_lossy_threshold_0); + CAM_DBG(CAM_ISP, "WM:%d lossy_thresh0 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->lossy_thresh1, wm_data->ubwc_lossy_threshold_1); + CAM_DBG(CAM_ISP, "WM:%d lossy_thresh1 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->off_lossy_var, wm_data->ubwc_offset_lossy_variance); + CAM_DBG(CAM_ISP, "WM:%d off_lossy_var 0x%X", + wm_data->index, reg_val_pair[*j-1]); + + if (wm_data->ubwc_bandwidth_limit) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->bw_limit, wm_data->ubwc_bandwidth_limit); + CAM_DBG(CAM_ISP, "WM:%d ubwc bw limit 0x%X", + wm_data->index, wm_data->ubwc_bandwidth_limit); + } + +end: + return rc; +} + +static int cam_vfe_bus_ver3_update_wm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_vfe_bus_ver3_reg_offset_ubwc_client *ubwc_client = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, k, size = 0; + uint32_t frame_inc = 0, val; + uint32_t loop_size = 0; + + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + update_buf->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + if (update_buf->wm_update->num_buf != vfe_out_data->num_wm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->wm_update->num_buf, vfe_out_data->num_wm); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + io_cfg = update_buf->wm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_client = wm_data->hw_regs->ubwc_regs; + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, wm_data->en_cfg); + CAM_DBG(CAM_ISP, "WM:%d en_cfg 0x%X", + wm_data->index, reg_val_pair[j-1]); + + val = (wm_data->height << 16) | wm_data->width; + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_0, val); + CAM_DBG(CAM_ISP, "WM:%d image height and width 0x%X", + wm_data->index, reg_val_pair[j-1]); + + /* For initial configuration program all bus registers */ + val = io_cfg->planes[i].plane_stride; + CAM_DBG(CAM_ISP, "before stride %d", val); + val = ALIGNUP(val, 16); + if (val != io_cfg->planes[i].plane_stride && + val != wm_data->stride) + CAM_WARN(CAM_ISP, "Warning stride %u expected %u", + io_cfg->planes[i].plane_stride, val); + + if (wm_data->stride != val || !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_2, + io_cfg->planes[i].plane_stride); + wm_data->stride = val; + CAM_DBG(CAM_ISP, "WM:%d image stride 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->en_ubwc) { + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + return -EINVAL; + } + if (wm_data->ubwc_updated) { + wm_data->ubwc_updated = false; + cam_vfe_bus_ver3_update_ubwc_regs( + wm_data, reg_val_pair, i, &j); + } + + /* UBWC meta address */ + cam_vfe_bus_ver3_update_ubwc_meta_addr( + reg_val_pair, &j, + wm_data->hw_regs->ubwc_regs, + update_buf->wm_update->image_buf[i]); + CAM_DBG(CAM_ISP, "WM:%d ubwc meta addr 0x%llx", + wm_data->index, + update_buf->wm_update->image_buf[i]); + } + + if (wm_data->en_ubwc) { + frame_inc = ALIGNUP(io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height, 4096); + frame_inc += io_cfg->planes[i].meta_size; + CAM_DBG(CAM_ISP, + "WM:%d frm %d: ht: %d stride %d meta: %d", + wm_data->index, frame_inc, + io_cfg->planes[i].slice_height, + io_cfg->planes[i].plane_stride, + io_cfg->planes[i].meta_size); + } else { + frame_inc = io_cfg->planes[i].plane_stride * + io_cfg->planes[i].slice_height; + } + + if (!(wm_data->en_cfg & (0x3 << 16))) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_cfg_1, wm_data->h_init); + CAM_DBG(CAM_ISP, "WM:%d h_init 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + if ((!bus_priv->common_data.is_lite && wm_data->index > 22) || + bus_priv->common_data.is_lite) + loop_size = wm_data->irq_subsample_period + 1; + else + loop_size = 1; + + /* WM Image address */ + for (k = 0; k < loop_size; k++) { + if (wm_data->en_ubwc) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + update_buf->wm_update->image_buf[i] + + io_cfg->planes[i].meta_size + + k * frame_inc); + else if (wm_data->en_cfg & (0x3 << 16)) + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + wm_data->offset + k * frame_inc)); + else + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->image_addr, + (update_buf->wm_update->image_buf[i] + + k * frame_inc)); + + CAM_DBG(CAM_ISP, "WM:%d image address 0x%X", + wm_data->index, reg_val_pair[j-1]); + } + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->frame_incr, frame_inc); + CAM_DBG(CAM_ISP, "WM:%d frame_inc %d", + wm_data->index, reg_val_pair[j-1]); + + + /* enable the WM */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->cfg, + wm_data->en_cfg); + + /* set initial configuration done */ + if (!wm_data->init_cfg_done) + wm_data->init_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_ver3_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_hfr; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_isp_port_hfr_config *hfr_cfg = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + update_hfr = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + update_hfr->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + reg_val_pair = &vfe_out_data->common_data->io_buf_update[0]; + hfr_cfg = update_hfr->hfr_update; + + for (i = 0, j = 0; i < vfe_out_data->num_wm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %zu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + + if (((!bus_priv->common_data.is_lite && wm_data->index > 22) || + bus_priv->common_data.is_lite) && + hfr_cfg->subsample_period > 3) { + CAM_ERR(CAM_ISP, + "RDI doesn't support irq subsample period %d", + hfr_cfg->subsample_period); + return -EINVAL; + } + + if ((wm_data->framedrop_pattern != + hfr_cfg->framedrop_pattern) || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_pattern, + hfr_cfg->framedrop_pattern); + wm_data->framedrop_pattern = hfr_cfg->framedrop_pattern; + CAM_DBG(CAM_ISP, "WM:%d framedrop pattern 0x%X", + wm_data->index, wm_data->framedrop_pattern); + } + + if (wm_data->framedrop_period != hfr_cfg->framedrop_period || + !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->framedrop_period, + hfr_cfg->framedrop_period); + wm_data->framedrop_period = hfr_cfg->framedrop_period; + CAM_DBG(CAM_ISP, "WM:%d framedrop period 0x%X", + wm_data->index, wm_data->framedrop_period); + } + + if (wm_data->irq_subsample_period != hfr_cfg->subsample_period + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_period, + hfr_cfg->subsample_period); + wm_data->irq_subsample_period = + hfr_cfg->subsample_period; + CAM_DBG(CAM_ISP, "WM:%d irq subsample period 0x%X", + wm_data->index, wm_data->irq_subsample_period); + } + + if (wm_data->irq_subsample_pattern != hfr_cfg->subsample_pattern + || !wm_data->hfr_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->irq_subsample_pattern, + hfr_cfg->subsample_pattern); + wm_data->irq_subsample_pattern = + hfr_cfg->subsample_pattern; + CAM_DBG(CAM_ISP, "WM:%d irq subsample pattern 0x%X", + wm_data->index, wm_data->irq_subsample_pattern); + } + + /* set initial configuration done */ + if (!wm_data->hfr_cfg_done) + wm_data->hfr_cfg_done = true; + } + + size = vfe_out_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_hfr->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_hfr->cmd.size, size); + return -ENOMEM; + } + + vfe_out_data->cdm_util_ops->cdm_write_regrandom( + update_hfr->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_hfr->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_ver3_update_ubwc_config_v2(void *cmd_args) +{ + struct cam_isp_hw_get_cmd_update *update_ubwc; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_vfe_generic_ubwc_config *ubwc_generic_cfg = NULL; + struct cam_vfe_generic_ubwc_plane_config *ubwc_generic_plane_cfg = NULL; + uint32_t i; + int rc = 0; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + rc = -EINVAL; + goto end; + } + + update_ubwc = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + update_ubwc->res->res_priv; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid data"); + rc = -EINVAL; + goto end; + } + + ubwc_generic_cfg = update_ubwc->ubwc_config; + + for (i = 0; i < vfe_out_data->num_wm; i++) { + + wm_data = vfe_out_data->wm_res[i]->res_priv; + ubwc_generic_plane_cfg = &ubwc_generic_cfg->ubwc_plane_cfg[i]; + + if (!wm_data->hw_regs->ubwc_regs) { + CAM_ERR(CAM_ISP, + "No UBWC register to configure."); + rc = -EINVAL; + goto end; + } + + if (!wm_data->en_ubwc) { + CAM_ERR(CAM_ISP, "UBWC Disabled"); + rc = -EINVAL; + goto end; + } + + if (wm_data->packer_cfg != + ubwc_generic_plane_cfg->packer_config || + !wm_data->init_cfg_done) { + wm_data->packer_cfg = + ubwc_generic_plane_cfg->packer_config; + wm_data->ubwc_updated = true; + } + + if ((!wm_data->is_dual) && ((wm_data->h_init != + ubwc_generic_plane_cfg->h_init) || + !wm_data->init_cfg_done)) { + wm_data->h_init = ubwc_generic_plane_cfg->h_init; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_meta_cfg != + ubwc_generic_plane_cfg->meta_stride || + !wm_data->init_cfg_done) { + wm_data->ubwc_meta_cfg = + ubwc_generic_plane_cfg->meta_stride; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_mode_cfg != + ubwc_generic_plane_cfg->mode_config_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_mode_cfg = + ubwc_generic_plane_cfg->mode_config_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_ctrl_2 != + ubwc_generic_plane_cfg->ctrl_2 || + !wm_data->init_cfg_done) { + wm_data->ubwc_ctrl_2 = + ubwc_generic_plane_cfg->ctrl_2; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_0 != + ubwc_generic_plane_cfg->lossy_threshold_0 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_0 = + ubwc_generic_plane_cfg->lossy_threshold_0; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_lossy_threshold_1 != + ubwc_generic_plane_cfg->lossy_threshold_1 || + !wm_data->init_cfg_done) { + wm_data->ubwc_lossy_threshold_1 = + ubwc_generic_plane_cfg->lossy_threshold_1; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_offset_lossy_variance != + ubwc_generic_plane_cfg->lossy_var_offset || + !wm_data->init_cfg_done) { + wm_data->ubwc_offset_lossy_variance = + ubwc_generic_plane_cfg->lossy_var_offset; + wm_data->ubwc_updated = true; + } + + if (wm_data->ubwc_bandwidth_limit != + ubwc_generic_plane_cfg->bandwidth_limit || + !wm_data->init_cfg_done) { + wm_data->ubwc_bandwidth_limit = + ubwc_generic_plane_cfg->bandwidth_limit; + wm_data->ubwc_updated = true; + } + } + +end: + return rc; +} + +static int cam_vfe_bus_ver3_update_stripe_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv; + struct cam_isp_hw_dual_isp_update_args *stripe_args; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_isp_dual_stripe_config *stripe_config; + uint32_t outport_id, ports_plane_idx, i; + + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + stripe_args = (struct cam_isp_hw_dual_isp_update_args *)cmd_args; + + vfe_out_data = (struct cam_vfe_bus_ver3_vfe_out_data *) + stripe_args->res->res_priv; + + if (!vfe_out_data) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + outport_id = stripe_args->res->res_id & 0xFF; + if (stripe_args->res->res_id < CAM_ISP_IFE_OUT_RES_BASE || + stripe_args->res->res_id >= CAM_ISP_IFE_OUT_RES_MAX) + return 0; + + ports_plane_idx = (stripe_args->split_id * + (stripe_args->dual_cfg->num_ports * CAM_PACKET_MAX_PLANES)) + + (outport_id * CAM_PACKET_MAX_PLANES); + for (i = 0; i < vfe_out_data->num_wm; i++) { + wm_data = vfe_out_data->wm_res[i]->res_priv; + stripe_config = (struct cam_isp_dual_stripe_config *) + &stripe_args->dual_cfg->stripes[ports_plane_idx + i]; + wm_data->width = stripe_config->width; + + /* + * UMD sends buffer offset address as offset for clients + * programmed to operate in frame/index based mode and h_init + * value as offset for clients programmed to operate in line + * based mode. + */ + + if (wm_data->en_cfg & (0x3 << 16)) + wm_data->offset = stripe_config->offset; + else + wm_data->h_init = stripe_config->offset; + + CAM_DBG(CAM_ISP, + "out_type:0x%X WM:%d width:%d offset:0x%X h_init:%d", + stripe_args->res->res_id, wm_data->index, + wm_data->width, wm_data->offset, wm_data->h_init); + } + + return 0; +} + +static int cam_vfe_bus_ver3_update_wm_config( + void *cmd_args) +{ + int i; + struct cam_isp_hw_get_cmd_update *wm_config_update; + struct cam_vfe_bus_ver3_vfe_out_data *vfe_out_data = NULL; + struct cam_vfe_bus_ver3_wm_resource_data *wm_data = NULL; + struct cam_isp_vfe_wm_config *wm_config = NULL; + + if (!cmd_args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + wm_config_update = cmd_args; + vfe_out_data = wm_config_update->res->res_priv; + wm_config = wm_config_update->wm_config; + + if (!vfe_out_data || !vfe_out_data->cdm_util_ops || !wm_config) { + CAM_ERR(CAM_ISP, "Invalid data"); + return -EINVAL; + } + + for (i = 0; i < vfe_out_data->num_wm; i++) { + wm_data = vfe_out_data->wm_res[i]->res_priv; + + if (wm_config->wm_mode > 0x2) { + CAM_ERR(CAM_ISP, "Invalid wm_mode: 0x%X WM:%d", + wm_config->wm_mode, wm_data->index); + return -EINVAL; + } + + wm_data->en_cfg = (wm_config->wm_mode << 16) | 0x1; + wm_data->height = wm_config->height; + wm_data->width = wm_config->width; + + CAM_DBG(CAM_ISP, + "WM:%d en_cfg:0x%X height:%d width:%d", + wm_data->index, wm_data->en_cfg, wm_data->height, + wm_data->width); + } + + return 0; +} + +static int cam_vfe_bus_ver3_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_ver3_start_vfe_out(hw_priv); +} + +static int cam_vfe_bus_ver3_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_ver3_stop_vfe_out(hw_priv); +} + +static int cam_vfe_bus_ver3_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[3] = {0}; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + if (bus_priv->common_data.hw_init) + return 0; + + top_irq_reg_mask[0] = (1 << bus_priv->top_irq_shift); + + bus_priv->bus_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_4, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_ver3_handle_bus_irq, + NULL, + NULL, + NULL); + + if (bus_priv->bus_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS (buf_done) IRQ"); + bus_priv->bus_irq_handle = 0; + return -EFAULT; + } + + bus_priv->rup_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_ver3_handle_rup_irq, + NULL, + NULL, + NULL); + + if (bus_priv->rup_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS (rup) IRQ"); + bus_priv->rup_irq_handle = 0; + return -EFAULT; + } + + if (bus_priv->tasklet_info != NULL) { + bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.bus_irq_controller, + CAM_IRQ_PRIORITY_0, + bus_error_irq_mask, + bus_priv, + cam_vfe_bus_ver3_err_irq_top_half, + cam_vfe_bus_ver3_err_irq_bottom_half, + bus_priv->tasklet_info, + &tasklet_bh_api); + + if (bus_priv->error_irq_handle < 1) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS Error IRQ"); + bus_priv->error_irq_handle = 0; + return -EFAULT; + } + } + + /* no clock gating at bus input */ + CAM_INFO(CAM_ISP, "Overriding clock gating at bus input"); + cam_io_w_mb(0x3FFFFFF, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->cgc_ovd); + + /* BUS_WR_TEST_BUS_CTRL */ + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + + bus_priv->common_data.common_reg->test_bus_ctrl); + + bus_priv->common_data.hw_init = true; + + return 0; +} + +static int cam_vfe_bus_ver3_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_ver3_priv *bus_priv = hw_priv; + int rc = 0, i; + unsigned long flags; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (!bus_priv->common_data.hw_init) + return 0; + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + + if (bus_priv->bus_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->bus_irq_handle); + bus_priv->bus_irq_handle = 0; + } + + if (bus_priv->rup_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.vfe_irq_controller, + bus_priv->rup_irq_handle); + bus_priv->rup_irq_handle = 0; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER3_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + return rc; +} + +static int __cam_vfe_bus_ver3_process_cmd(void *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + return cam_vfe_bus_ver3_process_cmd(priv, cmd_type, cmd_args, arg_size); +} + +static int cam_vfe_bus_ver3_process_cmd( + struct cam_isp_resource_node *priv, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_bus_ver3_priv *bus_priv; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE: + rc = cam_vfe_bus_ver3_update_wm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE: + rc = cam_vfe_bus_ver3_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_ver3_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STRIPE_UPDATE: + rc = cam_vfe_bus_ver3_update_stripe_cfg(priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ: + bus_priv = (struct cam_vfe_bus_ver3_priv *) priv; + if (bus_priv->error_irq_handle) { + CAM_DBG(CAM_ISP, "Mask off bus error irq handler"); + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + bus_priv->error_irq_handle = 0; + } + break; + case CAM_ISP_HW_CMD_UBWC_UPDATE_V2: + rc = cam_vfe_bus_ver3_update_ubwc_config_v2(cmd_args); + break; + case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE: + rc = cam_vfe_bus_ver3_update_wm_config(cmd_args); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_ver3_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver3_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_ver3_hw_info *ver3_hw_info = bus_hw_info; + struct cam_vfe_soc_private *soc_private = NULL; + char rup_controller_name[12] = ""; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + rc = -ENODEV; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_ver3_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = ver3_hw_info->num_client; + bus_priv->num_out = ver3_hw_info->num_out; + bus_priv->top_irq_shift = ver3_hw_info->top_irq_shift; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &ver3_hw_info->common_reg; + bus_priv->common_data.comp_done_shift = + ver3_hw_info->comp_done_shift; + bus_priv->common_data.hw_init = false; + + bus_priv->common_data.is_lite = soc_private->is_ife_lite; + + for (i = 0; i < CAM_VFE_BUS_VER3_SRC_GRP_MAX; i++) + bus_priv->common_data.rup_irq_handle[i] = 0; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &ver3_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller, false); + if (rc) { + CAM_ERR(CAM_ISP, "Init bus_irq_controller failed"); + goto free_bus_priv; + } + + strlcat(rup_controller_name, drv_name, sizeof(rup_controller_name)); + strlcat(rup_controller_name, "_rup", sizeof(rup_controller_name)); + + rc = cam_irq_controller_init(rup_controller_name, + bus_priv->common_data.mem_base, + &ver3_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.rup_irq_controller, false); + if (rc) { + CAM_ERR(CAM_ISP, "Init rup_irq_controller failed"); + goto free_bus_priv; + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_ver3_init_wm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "VFE:%d init WM:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_wm; + } + } + + for (i = 0; i < CAM_VFE_BUS_VER3_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_ver3_init_comp_grp(i, soc_info, + bus_priv, bus_hw_info, + &bus_priv->comp_grp[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "VFE:%d init comp_grp:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_comp_grp; + } + } + + for (i = 0; i < bus_priv->num_out; i++) { + rc = cam_vfe_bus_ver3_init_vfe_out_resource(i, bus_priv, + bus_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, + "VFE:%d init out_type:0x%X failed rc:%d", + bus_priv->common_data.core_index, i, rc); + goto deinit_vfe_out; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER3_PAYLOAD_MAX; i++) { + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + list_add_tail(&bus_priv->common_data.evt_payload[i].list, + &bus_priv->common_data.free_payload_list); + } + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_ver3_acquire_vfe_out; + vfe_bus_local->hw_ops.release = cam_vfe_bus_ver3_release_vfe_out; + vfe_bus_local->hw_ops.start = cam_vfe_bus_ver3_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_ver3_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_ver3_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_ver3_deinit_hw; + vfe_bus_local->top_half_handler = NULL; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_ver3_process_cmd; + + *vfe_bus = vfe_bus_local; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; + +deinit_vfe_out: + if (i < 0) + i = CAM_VFE_BUS_VER3_VFE_OUT_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_ver3_deinit_vfe_out_resource(&bus_priv->vfe_out[i]); + +deinit_comp_grp: + if (i < 0) + i = CAM_VFE_BUS_VER3_COMP_GRP_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_ver3_deinit_comp_grp(&bus_priv->comp_grp[i]); + +deinit_wm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_ver3_deinit_wm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_ver3_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_ver3_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + unsigned long flags; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + spin_lock_irqsave(&bus_priv->common_data.spin_lock, flags); + INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); + for (i = 0; i < CAM_VFE_BUS_VER3_PAYLOAD_MAX; i++) + INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); + bus_priv->common_data.hw_init = false; + spin_unlock_irqrestore(&bus_priv->common_data.spin_lock, flags); + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_ver3_deinit_wm_resource( + &bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "VFE:%d deinit WM:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER3_COMP_GRP_MAX; i++) { + rc = cam_vfe_bus_ver3_deinit_comp_grp(&bus_priv->comp_grp[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "VFE:%d deinit comp_grp:%d failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + for (i = 0; i < CAM_VFE_BUS_VER3_VFE_OUT_MAX; i++) { + rc = cam_vfe_bus_ver3_deinit_vfe_out_resource( + &bus_priv->vfe_out[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "VFE:%d deinit out_type:0x%X failed rc:%d", + bus_priv->common_data.core_index, i, rc); + } + + INIT_LIST_HEAD(&bus_priv->free_comp_grp); + INIT_LIST_HEAD(&bus_priv->used_comp_grp); + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit BUS IRQ Controller failed rc=%d", rc); + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.rup_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit RUP IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h new file mode 100644 index 0000000000000000000000000000000000000000..c5b4ab69fa9f503b03e9e074d2421aa737e4738f --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_VFE_BUS_VER3_H_ +#define _CAM_VFE_BUS_VER3_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_VER3_MAX_CLIENTS 26 +#define CAM_VFE_BUS_VER3_MAX_SUB_GRPS 6 + +enum cam_vfe_bus_ver3_vfe_core_id { + CAM_VFE_BUS_VER3_VFE_CORE_0, + CAM_VFE_BUS_VER3_VFE_CORE_1, + CAM_VFE_BUS_VER3_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_ver3_src_grp { + CAM_VFE_BUS_VER3_SRC_GRP_0, + CAM_VFE_BUS_VER3_SRC_GRP_1, + CAM_VFE_BUS_VER3_SRC_GRP_2, + CAM_VFE_BUS_VER3_SRC_GRP_3, + CAM_VFE_BUS_VER3_SRC_GRP_4, + CAM_VFE_BUS_VER3_SRC_GRP_5, + CAM_VFE_BUS_VER3_SRC_GRP_MAX, +}; + +enum cam_vfe_bus_ver3_comp_grp_type { + CAM_VFE_BUS_VER3_COMP_GRP_0, + CAM_VFE_BUS_VER3_COMP_GRP_1, + CAM_VFE_BUS_VER3_COMP_GRP_2, + CAM_VFE_BUS_VER3_COMP_GRP_3, + CAM_VFE_BUS_VER3_COMP_GRP_4, + CAM_VFE_BUS_VER3_COMP_GRP_5, + CAM_VFE_BUS_VER3_COMP_GRP_6, + CAM_VFE_BUS_VER3_COMP_GRP_7, + CAM_VFE_BUS_VER3_COMP_GRP_8, + CAM_VFE_BUS_VER3_COMP_GRP_9, + CAM_VFE_BUS_VER3_COMP_GRP_10, + CAM_VFE_BUS_VER3_COMP_GRP_11, + CAM_VFE_BUS_VER3_COMP_GRP_12, + CAM_VFE_BUS_VER3_COMP_GRP_13, + CAM_VFE_BUS_VER3_COMP_GRP_MAX, +}; + +enum cam_vfe_bus_ver3_vfe_out_type { + CAM_VFE_BUS_VER3_VFE_OUT_RDI0, + CAM_VFE_BUS_VER3_VFE_OUT_RDI1, + CAM_VFE_BUS_VER3_VFE_OUT_RDI2, + CAM_VFE_BUS_VER3_VFE_OUT_RDI3, + CAM_VFE_BUS_VER3_VFE_OUT_FULL, + CAM_VFE_BUS_VER3_VFE_OUT_DS4, + CAM_VFE_BUS_VER3_VFE_OUT_DS16, + CAM_VFE_BUS_VER3_VFE_OUT_RAW_DUMP, + CAM_VFE_BUS_VER3_VFE_OUT_FD, + CAM_VFE_BUS_VER3_VFE_OUT_PDAF, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BE, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_HDR_BHIST, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_TL_BG, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BF, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_AWB_BG, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_BHIST, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_RS, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_CS, + CAM_VFE_BUS_VER3_VFE_OUT_STATS_IHIST, + CAM_VFE_BUS_VER3_VFE_OUT_FULL_DISP, + CAM_VFE_BUS_VER3_VFE_OUT_DS4_DISP, + CAM_VFE_BUS_VER3_VFE_OUT_DS16_DISP, + CAM_VFE_BUS_VER3_VFE_OUT_2PD, + CAM_VFE_BUS_VER3_VFE_OUT_LCR, + CAM_VFE_BUS_VER3_VFE_OUT_MAX, +}; + +/* + * struct cam_vfe_bus_ver3_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_ver3_reg_offset_common { + uint32_t hw_version; + uint32_t cgc_ovd; + uint32_t comp_cfg_0; + uint32_t comp_cfg_1; + uint32_t if_frameheader_cfg[CAM_VFE_BUS_VER3_MAX_SUB_GRPS]; + uint32_t ubwc_static_ctrl; + uint32_t pwr_iso_cfg; + uint32_t overflow_status_clear; + uint32_t ccif_violation_status; + uint32_t overflow_status; + uint32_t image_size_violation_status; + uint32_t debug_status_top_cfg; + uint32_t debug_status_top; + uint32_t test_bus_ctrl; + struct cam_irq_controller_reg_info irq_reg_info; +}; + +/* + * struct cam_vfe_bus_ver3_reg_offset_ubwc_client: + * + * @Brief: UBWC register offsets for BUS Clients + */ +struct cam_vfe_bus_ver3_reg_offset_ubwc_client { + uint32_t meta_addr; + uint32_t meta_cfg; + uint32_t mode_cfg; + uint32_t stats_ctrl; + uint32_t ctrl_2; + uint32_t lossy_thresh0; + uint32_t lossy_thresh1; + uint32_t off_lossy_var; + uint32_t bw_limit; +}; + +/* + * struct cam_vfe_bus_ver3_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_ver3_reg_offset_bus_client { + uint32_t cfg; + uint32_t image_addr; + uint32_t frame_incr; + uint32_t image_cfg_0; + uint32_t image_cfg_1; + uint32_t image_cfg_2; + uint32_t packer_cfg; + uint32_t frame_header_addr; + uint32_t frame_header_incr; + uint32_t frame_header_cfg; + uint32_t line_done_cfg; + uint32_t irq_subsample_period; + uint32_t irq_subsample_pattern; + uint32_t framedrop_period; + uint32_t framedrop_pattern; + uint32_t burst_limit; + uint32_t system_cache_cfg; + void *ubwc_regs; + uint32_t addr_status_0; + uint32_t addr_status_1; + uint32_t addr_status_2; + uint32_t addr_status_3; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; + uint32_t comp_group; +}; + +/* + * struct cam_vfe_bus_ver3_vfe_out_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_ver3_vfe_out_hw_info { + enum cam_vfe_bus_ver3_vfe_out_type vfe_out_type; + uint32_t max_width; + uint32_t max_height; + uint32_t source_group; +}; + +/* + * struct cam_vfe_bus_ver3_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @num_client: Total number of write clients + * @bus_client_reg: Bus client register info + * @vfe_out_hw_info: VFE output capability + * @comp_done_shift: Mask shift for comp done mask + * @top_irq_shift: Mask shift for top level BUS WR irq + */ +struct cam_vfe_bus_ver3_hw_info { + struct cam_vfe_bus_ver3_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_ver3_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_VER3_MAX_CLIENTS]; + uint32_t num_out; + struct cam_vfe_bus_ver3_vfe_out_hw_info + vfe_out_hw_info[CAM_VFE_BUS_VER3_VFE_OUT_MAX]; + uint32_t comp_done_shift; + uint32_t top_irq_shift; +}; + +/* + * cam_vfe_bus_ver3_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver3_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_ver3_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_ver3_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_VER3_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h new file mode 100644 index 0000000000000000000000000000000000000000..97336a2da3b89104b5ece0210c4f935b9d92321b --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_BUS_H_ +#define _CAM_VFE_BUS_H_ + +#include <uapi/media/cam_isp.h> +#include "cam_hw_intf.h" +#include "cam_isp_hw.h" + +#define CAM_VFE_BUS_VER_1_0 0x1000 +#define CAM_VFE_BUS_VER_2_0 0x2000 +#define CAM_VFE_BUS_VER_3_0 0x3000 + +#define CAM_VFE_BUS_RD_VER_1_0 0x1000 + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +enum cam_vfe_bus_plane_type { + PLANE_Y, + PLANE_C, + PLANE_MAX, +}; + +enum cam_vfe_bus_type { + BUS_TYPE_WR, + BUS_TYPE_RD, + BUS_TYPE_MAX, +}; + +/* + * struct cam_vfe_bus: + * + * @Brief: Bus interface structure + * + * @bus_priv: Private data of BUS + * @hw_ops: Hardware interface functions + * @top_half_handler: Top Half handler function + * @bottom_half_handler: Bottom Half handler function + */ +struct cam_vfe_bus { + void *bus_priv; + + struct cam_hw_ops hw_ops; + CAM_IRQ_HANDLER_TOP_HALF top_half_handler; + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; +}; + +/* + * cam_vfe_bus_init() + * + * @Brief: Initialize Bus layer + * + * @bus_version: Version of BUS to initialize + * @bus_type: Bus Type RD/WR + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @bus_version: Version of BUS to deinitialize + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_deinit(uint32_t bus_version, + struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2ab4651e42717ba2289b39177118bb18d0092f82 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_lite_ver2.o cam_vfe_top.o cam_vfe_top_common.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top_ver3.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_ver3.o cam_vfe_rdi.o cam_vfe_fe_ver1.o cam_vfe_camif_lite_ver3.o diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c new file mode 100644 index 0000000000000000000000000000000000000000..9ea8d74a35caa00a5e9acc0512a95abacf473745 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -0,0 +1,556 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" + +struct cam_vfe_mux_camif_lite_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_lite_ver2_reg *camif_lite_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver2_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + enum cam_isp_hw_sync_mode sync_mode; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload + evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; +}; + +static int cam_vfe_camif_lite_get_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_lite_priv->spin_lock); + if (list_empty(&camif_lite_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_lite_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&camif_lite_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_lite_put_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_lite_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, + &camif_lite_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_lite_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_lite_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x, IRQ status_1 = %x", + th_payload->evt_status_arr[0], th_payload->evt_status_arr[1]); + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[1] || (th_payload->evt_status_arr[0] & + camif_lite_priv->reg_data->lite_err_irq_mask0)) { + CAM_ERR(CAM_ISP, + "CAMIF LITE ERR VFE:%d IRQ STATUS_0=0x%x STATUS_1=0x%x", + camif_lite_node->hw_intf->hw_idx, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from VFE:%d", + camif_lite_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_lite_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ STATUS_0=0x%x STATUS_1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%x", + evt_payload->irq_reg_val[i]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + + +static int cam_vfe_camif_lite_get_reg_update( + struct cam_isp_resource_node *camif_lite_res, + void *cmd_args, + uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_lite_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = camif_lite_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_lite_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->dual_pd_reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF Lite reg_update_cmd %x offset %x", + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_lite_ver2_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_data; + struct cam_vfe_acquire_args *acquire_data; + int rc = 0; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_lite_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + camif_lite_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_lite_data->event_cb = acquire_data->event_cb; + camif_lite_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "hw id:%d sync_mode=%d", + camif_lite_res->hw_intf->hw_idx, + camif_lite_data->sync_mode); + return rc; +} + +static int cam_vfe_camif_lite_resource_start( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *rsrc_data; + uint32_t val = 0; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (camif_lite_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid camif lite res res_state:%d", + camif_lite_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->lite_err_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->lite_err_irq_mask1; + + /* vfe core config */ + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg); + + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + val |= (1 << rsrc_data->reg_data->dual_pd_path_sel_shift); + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg val:%d", + camif_lite_res->hw_intf->hw_idx, val); + + /* epoch config with 20 line */ + cam_io_w_mb(rsrc_data->reg_data->lite_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_epoch_irq); + + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->dual_pd_reg_update_cmd_data, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP val:%d", + camif_lite_res->hw_intf->hw_idx, + rsrc_data->reg_data->dual_pd_reg_update_cmd_data); + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + err_irq_mask, + camif_lite_res, + cam_vfe_camif_lite_err_irq_top_half, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "Start Camif Lite IFE %d Done", + camif_lite_res->hw_intf->hw_idx); + return rc; +} + +static int cam_vfe_camif_lite_resource_stop( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + int rc = 0; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_lite_priv = (struct cam_vfe_mux_camif_lite_data *)camif_lite_res; + + if (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + if (camif_lite_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_handle); + camif_lite_priv->irq_handle = 0; + } + + if (camif_lite_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_err_handle); + camif_lite_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_lite_process_cmd( + struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_lite_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_lite_handle_irq_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_MAX; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + uint32_t irq_status1; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + camif_lite_node = handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; + evt_info.res_id = camif_lite_node->res_id; + evt_info.res_type = camif_lite_node->res_type; + + CAM_DBG(CAM_ISP, "irq_status_0 = 0x%x irq_status_1 = 0x%x", + irq_status0, irq_status1); + + if (irq_status0 & camif_lite_priv->reg_data->lite_sof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received SOF", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_lite_priv->reg_data->lite_epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received EPOCH", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_lite_priv->reg_data->dual_pd_reg_upd_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received REG_UPDATE_ACK", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_lite_priv->reg_data->lite_eof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Lite Received EOF", + evt_info.hw_idx); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if ((irq_status0 & camif_lite_priv->reg_data->lite_err_irq_mask0) || + (irq_status1 & camif_lite_priv->reg_data->lite_err_irq_mask1)) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE Received ERROR", + evt_info.hw_idx); + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + } + + cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_lite_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = NULL; + struct cam_vfe_camif_lite_ver2_hw_info *camif_lite_info = + camif_lite_hw_info; + int i = 0; + + camif_lite_priv = kzalloc(sizeof(*camif_lite_priv), + GFP_KERNEL); + if (!camif_lite_priv) + return -ENOMEM; + + camif_lite_node->res_priv = camif_lite_priv; + + camif_lite_priv->mem_base = + soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_lite_priv->camif_lite_reg = camif_lite_info->camif_lite_reg; + camif_lite_priv->common_reg = camif_lite_info->common_reg; + camif_lite_priv->reg_data = camif_lite_info->reg_data; + camif_lite_priv->hw_intf = hw_intf; + camif_lite_priv->soc_info = soc_info; + camif_lite_priv->vfe_irq_controller = vfe_irq_controller; + + camif_lite_node->init = NULL; + camif_lite_node->deinit = NULL; + camif_lite_node->start = cam_vfe_camif_lite_resource_start; + camif_lite_node->stop = cam_vfe_camif_lite_resource_stop; + camif_lite_node->process_cmd = cam_vfe_camif_lite_process_cmd; + camif_lite_node->top_half_handler = + cam_vfe_camif_lite_handle_irq_top_half; + camif_lite_node->bottom_half_handler = + cam_vfe_camif_lite_handle_irq_bottom_half; + + spin_lock_init(&camif_lite_priv->spin_lock); + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + list_add_tail(&camif_lite_priv->evt_payload[i].list, + &camif_lite_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_lite_ver2_deinit( + struct cam_isp_resource_node *camif_lite_node) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = + camif_lite_node->res_priv; + int i = 0; + + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + + camif_lite_node->start = NULL; + camif_lite_node->stop = NULL; + camif_lite_node->process_cmd = NULL; + camif_lite_node->top_half_handler = NULL; + camif_lite_node->bottom_half_handler = NULL; + + camif_lite_node->res_priv = NULL; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Error! camif_priv is NULL"); + return -ENODEV; + } + + kfree(camif_lite_priv); + + return 0; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h new file mode 100644 index 0000000000000000000000000000000000000000..7813e55f508bf45382a02c23971caa65d44c2c61 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_LITE_VER2_H_ +#define _CAM_VFE_CAMIF_LITE_VER2_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +#define CAM_VFE_CAMIF_LITE_EVT_MAX 256 + +struct cam_vfe_camif_lite_ver2_reg { + uint32_t camif_lite_cmd; + uint32_t camif_lite_config; + uint32_t lite_skip_period; + uint32_t lite_irq_subsample_pattern; + uint32_t lite_epoch_irq; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_camif_lite_ver2_reg_data { + uint32_t dual_pd_reg_update_cmd_data; + uint32_t lite_epoch_line_cfg; + uint32_t lite_sof_irq_mask; + uint32_t lite_epoch0_irq_mask; + uint32_t dual_pd_reg_upd_irq_mask; + uint32_t lite_eof_irq_mask; + uint32_t lite_err_irq_mask0; + uint32_t lite_err_irq_mask1; + uint32_t lite_subscribe_irq_mask0; + uint32_t lite_subscribe_irq_mask1; + uint32_t extern_reg_update_shift; + uint32_t dual_pd_path_sel_shift; +}; + +struct cam_vfe_camif_lite_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver2_reg *camif_lite_reg; + struct cam_vfe_camif_lite_ver2_reg_data *reg_data; +}; + +int cam_vfe_camif_lite_ver2_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param); + +int cam_vfe_camif_lite_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller); + +int cam_vfe_camif_lite_ver2_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_LITE_VER2_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c new file mode 100644 index 0000000000000000000000000000000000000000..bfb17d2145f8bfaf614644c0a8c51e8a57315f2e --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.c @@ -0,0 +1,1256 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver3.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_lite_ver3.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +struct cam_vfe_mux_camif_lite_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_lite_ver3_reg *camif_lite_reg; + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver3_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + enum cam_isp_hw_sync_mode sync_mode; + struct cam_vfe_camif_common_cfg cam_common_cfg; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + int sof_irq_handle; + void *vfe_irq_controller; + struct list_head free_payload_list; + spinlock_t spin_lock; + uint32_t camif_debug; + struct cam_vfe_top_irq_evt_payload + evt_payload[CAM_VFE_CAMIF_LITE_EVT_MAX]; +}; + +static int cam_vfe_camif_lite_get_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_lite_priv->spin_lock); + if (list_empty(&camif_lite_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free CAMIF LITE event payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_lite_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&camif_lite_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_lite_put_evt_payload( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_lite_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, + &camif_lite_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_lite_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_lite_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_vfe_soc_private *soc_private = NULL; + bool error_flag = false; + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + + soc_private = camif_lite_priv->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[2] || (th_payload->evt_status_arr[0] & + camif_lite_priv->reg_data->error_irq_mask0)) { + CAM_ERR(CAM_ISP, + "VFE:%d CAMIF LITE:%d Err IRQ status_1: 0x%X status_2: 0x%X", + camif_lite_node->hw_intf->hw_idx, + camif_lite_node->res_id, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[2]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from VFE:%d", + camif_lite_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq( + camif_lite_priv->vfe_irq_controller, + camif_lite_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_lite_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) + return rc; + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->violation_status); + + evt_payload->irq_reg_val[++i] = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->bus_overflow_status); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + + +static int cam_vfe_camif_lite_get_reg_update( + struct cam_isp_resource_node *camif_lite_res, + void *cmd_args, + uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_lite_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, + "Invalid args: cdm args %pK", cdm_args); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CAMIF LITE:%d get RUP", camif_lite_res->res_id); + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = camif_lite_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_lite_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF LITE:%d reg_update_cmd 0x%X offset 0x%X", + camif_lite_res->res_id, reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_lite_ver3_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_data; + struct cam_vfe_acquire_args *acquire_data; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_lite_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + camif_lite_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_lite_data->event_cb = acquire_data->event_cb; + camif_lite_data->priv = acquire_data->priv; + camif_lite_res->rdi_only_ctx = 0; + CAM_DBG(CAM_ISP, "Acquired VFE:%d CAMIF LITE:%d sync_mode=%d", + camif_lite_res->hw_intf->hw_idx, + camif_lite_res->res_id, + camif_lite_data->sync_mode); + return 0; +} + +static int cam_vfe_camif_lite_resource_start( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *rsrc_data; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t val = 0; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + if (camif_lite_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid camif lite res res_state:%d", + camif_lite_res->res_state); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "CAMIF LITE:%d Start", camif_lite_res->res_id); + + rsrc_data = (struct cam_vfe_mux_camif_lite_data *) + camif_lite_res->res_priv; + + soc_private = rsrc_data->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + if (soc_private->is_ife_lite) + goto skip_core_cfg; + + /* vfe core config */ + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + if (camif_lite_res->res_id == CAM_ISP_HW_VFE_IN_LCR && + rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if (camif_lite_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) { + val |= (1 << rsrc_data->reg_data->operating_mode_shift); + val |= (rsrc_data->cam_common_cfg.input_mux_sel_pdaf & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_MUXSEL_PDAF; + } + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + CAM_DBG(CAM_ISP, "VFE:%d core_cfg val:%d", + camif_lite_res->hw_intf->hw_idx, val); + + /* epoch config */ + cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_epoch_irq); + +skip_core_cfg: + + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + + rsrc_data->camif_lite_reg->reg_update_cmd); + + memset(err_irq_mask, 0, sizeof(err_irq_mask)); + memset(irq_mask, 0, sizeof(irq_mask)); + + /* config debug status registers */ + cam_io_w_mb(rsrc_data->reg_data->top_debug_cfg_en, rsrc_data->mem_base + + rsrc_data->common_reg->top_debug_cfg); + + if (!camif_lite_res->rdi_only_ctx) + goto subscribe_err; + + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->epoch0_irq_mask | + rsrc_data->reg_data->eof_irq_mask; + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_3, + irq_mask, + camif_lite_res, + camif_lite_res->top_half_handler, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->sof_irq_mask; + + if (!rsrc_data->sof_irq_handle) { + rsrc_data->sof_irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_mask, + camif_lite_res, + camif_lite_res->top_half_handler, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->sof_irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->sof_irq_handle = 0; + } + } + +subscribe_err: + + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = + rsrc_data->reg_data->error_irq_mask2; + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + err_irq_mask, + camif_lite_res, + cam_vfe_camif_lite_err_irq_top_half, + camif_lite_res->bottom_half_handler, + camif_lite_res->tasklet_info, + &tasklet_bh_api); + + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Start Done", + camif_lite_res->hw_intf->hw_idx, + camif_lite_res->res_id); + return rc; +} + +static int cam_vfe_camif_lite_reg_dump( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t offset, val, wm_idx; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if ((camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_lite_priv = + (struct cam_vfe_mux_camif_lite_data *)camif_lite_res->res_priv; + + soc_private = camif_lite_priv->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + CAM_INFO(CAM_ISP, "IFE:%d TOP", camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x0; offset <= 0x1FC; offset += 0x4) { + if (offset == 0x1C || offset == 0x34 || + offset == 0x38 || offset == 0x90) + continue; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } else { + for (offset = 0x0; offset <= 0x74; offset += 0x4) { + if (offset == 0xC || offset == 0x20 || offset == 0x24) + continue; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } + + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI0) + goto dump_rdi_1; + + CAM_INFO(CAM_ISP, "IFE:%d RDI0 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x9A00; offset <= 0x9BFC; offset += 0x4) { + if (offset == 0x9A08) + offset = 0x9A60; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x9A60) + offset = 0x9A64; + else if (offset == 0x9A70) + offset = 0x9AEC; + } + } else { + for (offset = 0x1200; offset <= 0x13FC; offset += 0x4) { + if (offset == 0x1208) + offset = 0x1260; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1260) + offset = 0x1264; + else if (offset == 0x1270) + offset = 0x12EC; + } + } + + goto wr_dump; + +dump_rdi_1: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI1) + goto dump_rdi_2; + + CAM_INFO(CAM_ISP, "IFE:%d RDI1 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x9C00; offset <= 0x9DFC; offset += 0x4) { + if (offset == 0x9A08) + offset = 0x9A60; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x9A60) + offset = 0x9A64; + else if (offset == 0x9A70) + offset = 0x9BEC; + } + } else { + for (offset = 0x1400; offset <= 0x15FC; offset += 0x4) { + if (offset == 0x1408) + offset = 0x1460; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1460) + offset = 0x1464; + else if (offset == 0x1470) + offset = 0x15EC; + } + } + + goto wr_dump; + +dump_rdi_2: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI2) + goto dump_rdi_3; + + CAM_INFO(CAM_ISP, "IFE:%d RDI2 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (!soc_private->is_ife_lite) { + for (offset = 0x9E00; offset <= 0x9FFC; offset += 0x4) { + if (offset == 0x9E08) + offset = 0x9E60; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x9E60) + offset = 0x9E64; + else if (offset == 0x9E80) + offset = 0x9FEC; + } + } else { + for (offset = 0x1600; offset <= 0x17FC; offset += 0x4) { + if (offset == 0x1608) + offset = 0x1660; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1660) + offset = 0x1664; + else if (offset == 0x1670) + offset = 0x17EC; + } + } + + goto wr_dump; + +dump_rdi_3: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_RDI3) + goto dump_pdlib; + + CAM_INFO(CAM_ISP, "IFE:%d RDI3 CAMIF", + camif_lite_priv->hw_intf->hw_idx); + if (soc_private->is_ife_lite) { + for (offset = 0x1800; offset <= 0x19FC; offset += 0x4) { + if (offset == 0x1808) + offset = 0x1860; + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0x1860) + offset = 0x1864; + else if (offset == 0x1870) + offset = 0x19EC; + } + } + + goto wr_dump; + +dump_pdlib: + if (camif_lite_res->res_id != CAM_ISP_HW_VFE_IN_PDLIB) + goto dump_lcr; + + CAM_INFO(CAM_ISP, "IFE:%d PDLIB CAMIF", + camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA400; offset <= 0xA5FC; offset += 0x4) { + if (offset == 0xA408) + offset = 0xA460; + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0xA460) + offset = 0xA464; + else if (offset == 0xA470) + offset = 0xA5EC; + } + + CAM_INFO(CAM_ISP, "IFE:%d CLC PDLIB", + camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA600; offset <= 0xA718; offset += 0x4) { + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + goto wr_dump; + +dump_lcr: + CAM_INFO(CAM_ISP, "IFE:%d LCR CAMIF", camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA000; offset <= 0xA1FC; offset += 0x4) { + if (offset == 0xA008) + offset = 0xA060; + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0xA060) + offset = 0xA064; + else if (offset == 0xA070) + offset = 0xA1EC; + } + + CAM_INFO(CAM_ISP, "IFE:%d CLC LCR", camif_lite_priv->hw_intf->hw_idx); + for (offset = 0xA200; offset <= 0xA3FC; offset += 0x4) { + if (offset == 0xA208) + offset = 0xA260; + else if (offset == 0xA288) + offset = 0xA3F8; + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + if (offset == 0xA260) + offset = 0xA264; + else if (offset == 0xA280) + offset = 0xA1EC; + } + +wr_dump: + if (!soc_private->is_ife_lite) + goto end_dump; + + CAM_INFO(CAM_ISP, "IFE:%d LITE BUS WR", + camif_lite_priv->hw_intf->hw_idx); + for (offset = 0x1A00; offset <= 0x1AE0; offset += 0x4) { + val = cam_soc_util_r(camif_lite_priv->soc_info, 0, offset); + CAM_DBG(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + for (wm_idx = 0; wm_idx <= 3; wm_idx++) { + for (offset = 0x1C00 + 0x100 * wm_idx; offset < (0x1C00 + + 0x100 * wm_idx + 0x84); offset += 0x4) { + val = cam_soc_util_r(camif_lite_priv->soc_info, + 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } + +end_dump: + return 0; +} + +static int cam_vfe_camif_lite_resource_stop( + struct cam_isp_resource_node *camif_lite_res) +{ + struct cam_vfe_mux_camif_lite_data *rsrc_data; + int rc = 0; + + if (!camif_lite_res) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Stop", + camif_lite_res->hw_intf->hw_idx, + camif_lite_res->res_id); + + if ((camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + rsrc_data = + (struct cam_vfe_mux_camif_lite_data *)camif_lite_res->res_priv; + + /* Disable Camif */ + cam_io_w_mb(0x0, rsrc_data->mem_base + + rsrc_data->camif_lite_reg->lite_module_config); + + if (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + if (rsrc_data->irq_handle > 0) { + cam_irq_controller_unsubscribe_irq( + rsrc_data->vfe_irq_controller, + rsrc_data->irq_handle); + rsrc_data->irq_handle = 0; + } + + if (rsrc_data->sof_irq_handle > 0) { + cam_irq_controller_unsubscribe_irq( + rsrc_data->vfe_irq_controller, + rsrc_data->sof_irq_handle); + rsrc_data->sof_irq_handle = 0; + } + + if (rsrc_data->irq_err_handle > 0) { + cam_irq_controller_unsubscribe_irq( + rsrc_data->vfe_irq_controller, + rsrc_data->irq_err_handle); + rsrc_data->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_lite_ver3_core_config( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_core_config_args *vfe_core_cfg = + (struct cam_vfe_core_config_args *)cmd_args; + + camif_lite_priv = + (struct cam_vfe_mux_camif_lite_data *)rsrc_node->res_priv; + camif_lite_priv->cam_common_cfg.vid_ds16_r2pd = + vfe_core_cfg->core_config.vid_ds16_r2pd; + camif_lite_priv->cam_common_cfg.vid_ds4_r2pd = + vfe_core_cfg->core_config.vid_ds4_r2pd; + camif_lite_priv->cam_common_cfg.disp_ds16_r2pd = + vfe_core_cfg->core_config.disp_ds16_r2pd; + camif_lite_priv->cam_common_cfg.disp_ds4_r2pd = + vfe_core_cfg->core_config.disp_ds4_r2pd; + camif_lite_priv->cam_common_cfg.dsp_streaming_tap_point = + vfe_core_cfg->core_config.dsp_streaming_tap_point; + camif_lite_priv->cam_common_cfg.ihist_src_sel = + vfe_core_cfg->core_config.ihist_src_sel; + camif_lite_priv->cam_common_cfg.hdr_be_src_sel = + vfe_core_cfg->core_config.hdr_be_src_sel; + camif_lite_priv->cam_common_cfg.hdr_bhist_src_sel = + vfe_core_cfg->core_config.hdr_bhist_src_sel; + camif_lite_priv->cam_common_cfg.input_mux_sel_pdaf = + vfe_core_cfg->core_config.input_mux_sel_pdaf; + camif_lite_priv->cam_common_cfg.input_mux_sel_pp = + vfe_core_cfg->core_config.input_mux_sel_pp; + + return 0; +} + +static int cam_vfe_camif_lite_process_cmd( + struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = NULL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_lite_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_vfe_camif_lite_ver3_core_config(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + camif_lite_priv = (struct cam_vfe_mux_camif_lite_data *) + rsrc_node->res_priv; + camif_lite_priv->camif_debug = *((uint32_t *)cmd_args); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static void cam_vfe_camif_lite_overflow_debug_info( + struct cam_vfe_mux_camif_lite_data *camif_lite_priv) +{ + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t val0, val1, val2, val3; + + soc_private = camif_lite_priv->soc_info->soc_private; + + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_0); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_1); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_2); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_3); + CAM_INFO(CAM_ISP, + "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", + val0, val1, val2, val3); + + if (soc_private->is_ife_lite) + return; + + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_4); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_5); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_6); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_7); + CAM_INFO(CAM_ISP, + "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", + val0, val1, val2, val3); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_8); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_9); + val2 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_10); + val3 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_11); + CAM_INFO(CAM_ISP, + "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", + val0, val1, val2, val3); + val0 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_12); + val1 = cam_io_r(camif_lite_priv->mem_base + + camif_lite_priv->common_reg->top_debug_13); + CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", + val0, val1); +} + +static void cam_vfe_camif_lite_print_status(uint32_t *status, + int err_type, struct cam_vfe_mux_camif_lite_data *camif_lite_priv) +{ + uint32_t violation_mask = 0x3F00, violation_status = 0; + uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t val0, val1, val2; + + if (!status) { + CAM_ERR(CAM_ISP, "Invalid params"); + return; + } + + bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; + violation_status = status[CAM_IFE_IRQ_VIOLATION_STATUS]; + status_0 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + status_2 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]; + soc_private = camif_lite_priv->soc_info->soc_private; + + if (soc_private->is_ife_lite) + goto ife_lite; + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { + if (status_0 & 0x200000) + CAM_INFO(CAM_ISP, "RDI2 FRAME DROP"); + + if (status_0 & 0x400000) + CAM_INFO(CAM_ISP, "RDI1 FRAME DROP"); + + if (status_0 & 0x800000) + CAM_INFO(CAM_ISP, "RDI0 FRAME DROP"); + + if (status_0 & 0x1000000) + CAM_INFO(CAM_ISP, "PD PIPE FRAME DROP"); + + if (status_0 & 0x8000000) + CAM_INFO(CAM_ISP, "RDI2 OVERFLOW"); + + if (status_0 & 0x10000000) + CAM_INFO(CAM_ISP, "RDI1 OVERFLOW"); + + if (status_0 & 0x20000000) + CAM_INFO(CAM_ISP, "RDI0 OVERFLOW"); + + if (status_0 & 0x40000000) + CAM_INFO(CAM_ISP, "PD PIPE OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { + if (bus_overflow_status & 0x0800) + CAM_INFO(CAM_ISP, "CAMIF PD BUS OVERFLOW"); + + if (bus_overflow_status & 0x0400000) + CAM_INFO(CAM_ISP, "LCR BUS OVERFLOW"); + + if (bus_overflow_status & 0x0800000) + CAM_INFO(CAM_ISP, "RDI0 BUS OVERFLOW"); + + if (bus_overflow_status & 0x01000000) + CAM_INFO(CAM_ISP, "RDI1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x02000000) + CAM_INFO(CAM_ISP, "RDI2 BUS OVERFLOW"); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { + CAM_INFO(CAM_ISP, "PDLIB / LCR Module hang"); + /* print debug registers */ + cam_vfe_camif_lite_overflow_debug_info(camif_lite_priv); + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { + if (status_2 & 0x02000) + CAM_INFO(CAM_ISP, "PD CAMIF VIOLATION"); + + if (status_2 & 0x04000) + CAM_INFO(CAM_ISP, "PD VIOLATION"); + + if (status_2 & 0x08000) + CAM_INFO(CAM_ISP, "LCR CAMIF VIOLATION"); + + if (status_2 & 0x010000) + CAM_INFO(CAM_ISP, "LCR VIOLATION"); + + if (status_2 & 0x020000) + CAM_INFO(CAM_ISP, "RDI0 CAMIF VIOLATION"); + + if (status_2 & 0x040000) + CAM_INFO(CAM_ISP, "RDI1 CAMIF VIOLATION"); + + if (status_2 & 0x080000) + CAM_INFO(CAM_ISP, "RDI2 CAMIF VIOLATION"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION && violation_status) { + if (violation_mask & violation_status) + CAM_INFO(CAM_ISP, "LCR VIOLATION Module ID:%d", + violation_mask & violation_status); + + violation_mask = 0x0F0000; + if (violation_mask & violation_status) + CAM_INFO(CAM_ISP, "PD VIOLATION Module ID:%d", + violation_mask & violation_status); + + } + + return; + +ife_lite: + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { + if (status_0 & 0x100) + CAM_INFO(CAM_ISP, "RDI3 FRAME DROP"); + + if (status_0 & 0x80) + CAM_INFO(CAM_ISP, "RDI2 FRAME DROP"); + + if (status_0 & 0x40) + CAM_INFO(CAM_ISP, "RDI1 FRAME DROP"); + + if (status_0 & 0x20) + CAM_INFO(CAM_ISP, "RDI0 FRAME DROP"); + + if (status_0 & 0x8) + CAM_INFO(CAM_ISP, "RDI3 OVERFLOW"); + + if (status_0 & 0x4) + CAM_INFO(CAM_ISP, "RDI2 OVERFLOW"); + + if (status_0 & 0x2) + CAM_INFO(CAM_ISP, "RDI1 OVERFLOW"); + + if (status_0 & 0x1) + CAM_INFO(CAM_ISP, "RDI0 OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { + if (bus_overflow_status & 0x01) + CAM_INFO(CAM_ISP, "RDI0 BUS OVERFLOW"); + + if (bus_overflow_status & 0x02) + CAM_INFO(CAM_ISP, "RDI1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x04) + CAM_INFO(CAM_ISP, "RDI2 BUS OVERFLOW"); + + if (bus_overflow_status & 0x08) + CAM_INFO(CAM_ISP, "RDI3 BUS OVERFLOW"); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { + CAM_INFO(CAM_ISP, "RDI hang"); + /* print debug registers */ + cam_vfe_camif_lite_overflow_debug_info(camif_lite_priv); + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { + if (status_2 & 0x100) + CAM_INFO(CAM_ISP, "RDI0 CAMIF VIOLATION"); + + if (status_2 & 0x200) + CAM_INFO(CAM_ISP, "RDI1 CAMIF VIOLATION"); + + if (status_2 & 0x400) + CAM_INFO(CAM_ISP, "RDI2 CAMIF VIOLATION"); + + if (status_2 & 0x800) + CAM_INFO(CAM_ISP, "RDI3 CAMIF VIOLATION"); + } +} + +static int cam_vfe_camif_lite_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_lite_node = th_payload->handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + + CAM_DBG(CAM_ISP, + "VFE:%d CAMIF LITE:%d IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_lite_node->hw_intf->hw_idx, + camif_lite_node->res_id, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], + th_payload->evt_status_arr[2]); + + rc = cam_vfe_camif_lite_get_evt_payload(camif_lite_priv, &evt_payload); + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d CAMIF LITE:%d IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_lite_node->hw_intf->hw_idx, + camif_lite_node->res_id, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], + th_payload->evt_status_arr[2]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_lite_handle_irq_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_MAX; + struct cam_isp_resource_node *camif_lite_node; + struct cam_vfe_mux_camif_lite_data *camif_lite_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + struct cam_vfe_soc_private *soc_private = NULL; + uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; + int i = 0; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + camif_lite_node = handler_priv; + camif_lite_priv = camif_lite_node->res_priv; + payload = evt_payload_priv; + + soc_private = camif_lite_priv->soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + for (i = 0; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) + irq_status[i] = payload->irq_reg_val[i]; + + evt_info.hw_idx = camif_lite_node->hw_intf->hw_idx; + evt_info.res_id = camif_lite_node->res_id; + evt_info.res_type = camif_lite_node->res_type; + + CAM_DBG(CAM_ISP, + "VFE:%d CAMIF LITE:%d IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + evt_info.hw_idx, evt_info.res_id, + irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0], + irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1], + irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]); + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_lite_priv->reg_data->sof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received SOF", + evt_info.hw_idx, evt_info.res_id); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_lite_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EPOCH", + evt_info.hw_idx, evt_info.res_id); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_lite_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Received EOF", + evt_info.hw_idx, evt_info.res_id); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_lite_priv->reg_data->error_irq_mask0) { + CAM_ERR(CAM_ISP, "VFE:%d Overflow", + camif_lite_node->hw_intf->hw_idx); + + evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + cam_vfe_camif_lite_print_status(irq_status, ret, + camif_lite_priv); + + if (camif_lite_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_lite_reg_dump(camif_lite_node); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { + CAM_ERR(CAM_ISP, "VFE:%d Violation", + camif_lite_node->hw_intf->hw_idx); + + evt_info.err_type = CAM_VFE_IRQ_STATUS_VIOLATION; + + if (camif_lite_priv->event_cb) + camif_lite_priv->event_cb(camif_lite_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_VIOLATION; + + cam_vfe_camif_lite_print_status(irq_status, ret, + camif_lite_priv); + + if (camif_lite_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_lite_reg_dump(camif_lite_node); + } + + cam_vfe_camif_lite_put_evt_payload(camif_lite_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_lite_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = NULL; + struct cam_vfe_camif_lite_ver3_hw_info *camif_lite_info = + camif_lite_hw_info; + int i = 0; + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Init", + camif_lite_node->res_id, camif_lite_node->res_id); + + camif_lite_priv = kzalloc(sizeof(*camif_lite_priv), + GFP_KERNEL); + if (!camif_lite_priv) + return -ENOMEM; + + camif_lite_node->res_priv = camif_lite_priv; + + camif_lite_priv->mem_base = + soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_lite_priv->camif_lite_reg = camif_lite_info->camif_lite_reg; + camif_lite_priv->common_reg = camif_lite_info->common_reg; + camif_lite_priv->reg_data = camif_lite_info->reg_data; + camif_lite_priv->hw_intf = hw_intf; + camif_lite_priv->soc_info = soc_info; + camif_lite_priv->vfe_irq_controller = vfe_irq_controller; + + camif_lite_node->init = NULL; + camif_lite_node->deinit = NULL; + camif_lite_node->start = cam_vfe_camif_lite_resource_start; + camif_lite_node->stop = cam_vfe_camif_lite_resource_stop; + camif_lite_node->process_cmd = cam_vfe_camif_lite_process_cmd; + camif_lite_node->top_half_handler = + cam_vfe_camif_lite_handle_irq_top_half; + camif_lite_node->bottom_half_handler = + cam_vfe_camif_lite_handle_irq_bottom_half; + + spin_lock_init(&camif_lite_priv->spin_lock); + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + list_add_tail(&camif_lite_priv->evt_payload[i].list, + &camif_lite_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_lite_ver3_deinit( + struct cam_isp_resource_node *camif_lite_node) +{ + struct cam_vfe_mux_camif_lite_data *camif_lite_priv = + camif_lite_node->res_priv; + int i = 0; + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF LITE:%d Deinit", + camif_lite_node->hw_intf->hw_idx, camif_lite_node->res_id); + + INIT_LIST_HEAD(&camif_lite_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_LITE_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_lite_priv->evt_payload[i].list); + + camif_lite_node->start = NULL; + camif_lite_node->stop = NULL; + camif_lite_node->process_cmd = NULL; + camif_lite_node->top_half_handler = NULL; + camif_lite_node->bottom_half_handler = NULL; + + camif_lite_node->res_priv = NULL; + + if (!camif_lite_priv) { + CAM_ERR(CAM_ISP, "Error. camif_priv is NULL"); + return -ENODEV; + } + + kfree(camif_lite_priv); + + return 0; +} + diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h new file mode 100644 index 0000000000000000000000000000000000000000..54a38bdf41ca587c63d40ca5aead86a355a29aa1 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver3.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_LITE_VER3_H_ +#define _CAM_VFE_CAMIF_LITE_VER3_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +#define CAM_VFE_RDI_VER2_MAX 4 +#define CAM_VFE_CAMIF_LITE_EVT_MAX 256 + +struct cam_vfe_camif_lite_ver3_reg { + uint32_t lite_hw_version; + uint32_t lite_hw_status; + uint32_t lite_module_config; + uint32_t lite_skip_period; + uint32_t lite_irq_subsample_pattern; + uint32_t lite_epoch_irq; + uint32_t lite_debug_1; + uint32_t lite_debug_0; + uint32_t lite_test_bus_ctrl; + uint32_t camif_lite_spare; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_camif_lite_ver3_reg_data { + uint32_t extern_reg_update_shift; + uint32_t operating_mode_shift; + uint32_t input_mux_sel_shift; + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask2; + uint32_t subscribe_irq_mask1; + uint32_t enable_diagnostic_hw; + uint32_t top_debug_cfg_en; +}; + +struct cam_vfe_camif_lite_ver3_hw_info { + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_lite_ver3_reg *camif_lite_reg; + struct cam_vfe_camif_lite_ver3_reg_data *reg_data; +}; + +int cam_vfe_camif_lite_ver3_acquire_resource( + struct cam_isp_resource_node *camif_lite_res, + void *acquire_param); + +int cam_vfe_camif_lite_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_lite_hw_info, + struct cam_isp_resource_node *camif_lite_node, + void *vfe_irq_controller); + +int cam_vfe_camif_lite_ver3_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_LITE_VER3_H_ */ + diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c new file mode 100644 index 0000000000000000000000000000000000000000..0ed1c6ede3ce600ca093445882f3f892d9a0c303 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -0,0 +1,881 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_ver2.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_camif_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_ver2_reg *camif_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t camif_debug; +}; + +static int cam_vfe_camif_get_evt_payload( + struct cam_vfe_mux_camif_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_priv->spin_lock); + if (list_empty(&camif_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); +done: + spin_unlock(&camif_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_put_evt_payload( + struct cam_vfe_mux_camif_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, &camif_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x, IRQ status_1 = %x", + th_payload->evt_status_arr[0], th_payload->evt_status_arr[1]); + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[1] || (th_payload->evt_status_arr[0] & + camif_priv->reg_data->error_irq_mask0)) { + CAM_ERR(CAM_ISP, + "Camif Error: vfe:%d: IRQ STATUS_0=0x%x STATUS_1=0x%x", + camif_node->hw_intf->hw_idx, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from vfe=%d", + camif_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq(camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_get_evt_payload(camif_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ STATUS_0=0x%x STATUS_1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%x", + evt_payload->irq_reg_val[2]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_camif_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error! Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_camif_get_reg_update( + struct cam_isp_resource_node *camif_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = camif_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF reg_update_cmd %x offset %x", + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_ver2_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_data *camif_data; + struct cam_vfe_acquire_args *acquire_data; + + int rc = 0; + + camif_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_camif_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + if (rc) + return rc; + + camif_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + camif_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + camif_data->first_line = acquire_data->vfe_in.in_port->line_start; + camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->event_cb = acquire_data->event_cb; + camif_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + camif_res->hw_intf->hw_idx, + camif_data->pix_pattern, camif_data->dsp_mode); + return rc; +} + +static int cam_vfe_camif_resource_init( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to enable dsp clk"); + } + + return rc; +} + +static int cam_vfe_camif_resource_deinit( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; +} + +static int cam_vfe_camif_resource_start( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + struct cam_vfe_soc_private *soc_private; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid camif res res_state:%d", + camif_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->error_irq_mask1; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->subscribe_irq_mask0; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->subscribe_irq_mask1; + + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + + /*config vfe core*/ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg val:%d", camif_res->hw_intf->hw_idx, + val); + + /* disable the CGC for stats */ + cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base + + rsrc_data->common_reg->module_ctrl[ + CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); + + /* epoch config */ + switch (soc_private->cpas_version) { + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq); + break; + default: + epoch0_irq_mask = ((rsrc_data->last_line - + rsrc_data->first_line) / 2) + + rsrc_data->first_line; + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & + 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | + epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line: %u\n" + "last_line: %u\n" + "epoch_line_cfg: 0x%x", + rsrc_data->first_line, + rsrc_data->last_line, + computed_epoch_line_cfg); + break; + } + + camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP val:%d", camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + if (rsrc_data->camif_debug & + CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->camif_reg->vfe_diag_config); + val |= rsrc_data->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->camif_reg->vfe_diag_config); + } + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_mask, + camif_res, + camif_res->top_half_handler, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + err_irq_mask, + camif_res, + cam_vfe_camif_err_irq_top_half, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", camif_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_camif_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; + uint32_t offset, val, wm_idx; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + for (offset = 0x0; offset < 0x1160; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + } + + for (offset = 0x2000; offset <= 0x20B8; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + } + + for (wm_idx = 0; wm_idx <= 23; wm_idx++) { + for (offset = 0x2200 + 0x100 * wm_idx; + offset < 0x2278 + 0x100 * wm_idx; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, + "offset 0x%x value 0x%x", offset, val); + } + } + + soc_private = camif_priv->soc_info->soc_private; + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120 || + soc_private->cpas_version == CAM_CPAS_TITAN_175_V130) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_INFO(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_INFO(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_INFO(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + + } else if (soc_private->cpas_version < CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } + + return 0; +} + +static int cam_vfe_camif_resource_stop( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_camif_ver2_reg *camif_reg; + int rc = 0; + uint32_t val = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + camif_reg = camif_priv->camif_reg; + + if ((camif_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->core_cfg); + val &= (~(1 << camif_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->common_reg->core_cfg); + } + + if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->camif_reg->vfe_diag_config); + if (val & camif_priv->reg_data->enable_diagnostic_hw) { + val &= ~camif_priv->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->camif_reg->vfe_diag_config); + } + + if (camif_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, camif_priv->irq_handle); + camif_priv->irq_handle = 0; + } + + if (camif_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + camif_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_data *camif_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + camif_priv->enable_sof_irq_debug = true; + else + camif_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_mux_camif_data *camif_priv = NULL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + camif_priv->camif_debug = *((uint32_t *)cmd_args); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_camif_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rc = cam_vfe_camif_get_evt_payload(camif_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_MAX; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + uint32_t irq_status1; + uint32_t val; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + camif_node = handler_priv; + camif_priv = camif_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + evt_info.hw_idx = camif_node->hw_intf->hw_idx; + evt_info.res_id = camif_node->res_id; + evt_info.res_type = camif_node->res_type; + + CAM_DBG(CAM_ISP, "irq_status_0 = 0x%x irq_status_1 = 0x%x", + irq_status0, irq_status1); + + if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { + if ((camif_priv->enable_sof_irq_debug) && + (camif_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + camif_priv->irq_debug_cnt++; + if (camif_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + camif_priv->enable_sof_irq_debug = + false; + camif_priv->irq_debug_cnt = 0; + } + } else + CAM_DBG(CAM_ISP, "Received SOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_REG_UPDATE, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & camif_priv->reg_data->error_irq_mask0) { + CAM_DBG(CAM_ISP, "Received ERROR"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + CAM_INFO(CAM_ISP, "Violation status = %x", + payload->irq_reg_val[2]); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_reg_dump(camif_node->res_priv); + } + + if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR"); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + CAM_INFO(CAM_ISP, "Violation status = %x", + payload->irq_reg_val[2]); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_reg_dump(camif_node->res_priv); + } + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r(camif_priv->mem_base + + camif_priv->camif_reg->vfe_diag_sensor_status); + CAM_DBG(CAM_ISP, "VFE_DIAG_SENSOR_STATUS: 0x%x", + camif_priv->mem_base, val); + } + + cam_vfe_camif_put_evt_payload(camif_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_data *camif_priv = NULL; + struct cam_vfe_camif_ver2_hw_info *camif_info = camif_hw_info; + int i = 0; + + camif_priv = kzalloc(sizeof(struct cam_vfe_mux_camif_data), + GFP_KERNEL); + if (!camif_priv) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for camif_priv"); + return -ENOMEM; + } + + camif_node->res_priv = camif_priv; + + camif_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_priv->camif_reg = camif_info->camif_reg; + camif_priv->common_reg = camif_info->common_reg; + camif_priv->reg_data = camif_info->reg_data; + camif_priv->hw_intf = hw_intf; + camif_priv->soc_info = soc_info; + camif_priv->vfe_irq_controller = vfe_irq_controller; + + camif_node->init = cam_vfe_camif_resource_init; + camif_node->deinit = cam_vfe_camif_resource_deinit; + camif_node->start = cam_vfe_camif_resource_start; + camif_node->stop = cam_vfe_camif_resource_stop; + camif_node->process_cmd = cam_vfe_camif_process_cmd; + camif_node->top_half_handler = cam_vfe_camif_handle_irq_top_half; + camif_node->bottom_half_handler = cam_vfe_camif_handle_irq_bottom_half; + + spin_lock_init(&camif_priv->spin_lock); + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + list_add_tail(&camif_priv->evt_payload[i].list, + &camif_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_ver2_deinit( + struct cam_isp_resource_node *camif_node) +{ + struct cam_vfe_mux_camif_data *camif_priv = camif_node->res_priv; + int i = 0; + + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + + camif_node->start = NULL; + camif_node->stop = NULL; + camif_node->process_cmd = NULL; + camif_node->top_half_handler = NULL; + camif_node->bottom_half_handler = NULL; + + camif_node->res_priv = NULL; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Error! camif_priv is NULL"); + return -ENODEV; + } + + kfree(camif_priv); + + return 0; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h new file mode 100644 index 0000000000000000000000000000000000000000..f071a0627bbcb83612c9deec8de68e99d5cc13a8 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_VER2_H_ +#define _CAM_VFE_CAMIF_VER2_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_camif_ver2_reg { + uint32_t camif_cmd; + uint32_t camif_config; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t skip_period; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq; + uint32_t raw_crop_width_cfg; + uint32_t raw_crop_height_cfg; + uint32_t reg_update_cmd; + uint32_t vfe_diag_config; + uint32_t vfe_diag_sensor_status; +}; + +struct cam_vfe_camif_reg_data { + uint32_t raw_crop_first_pixel_shift; + uint32_t raw_crop_first_pixel_mask; + + uint32_t raw_crop_last_pixel_shift; + uint32_t raw_crop_last_pixel_mask; + + uint32_t raw_crop_first_line_shift; + uint32_t raw_crop_first_line_mask; + + uint32_t raw_crop_last_line_shift; + uint32_t raw_crop_last_line_mask; + + uint32_t input_mux_sel_shift; + uint32_t input_mux_sel_mask; + uint32_t extern_reg_update_shift; + uint32_t extern_reg_update_mask; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + uint32_t subscribe_irq_mask0; + uint32_t subscribe_irq_mask1; + + uint32_t enable_diagnostic_hw; +}; + +struct cam_vfe_camif_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_ver2_reg *camif_reg; + struct cam_vfe_camif_reg_data *reg_data; +}; + +int cam_vfe_camif_ver2_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_camif_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller); + +int cam_vfe_camif_ver2_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_VER2_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c new file mode 100644 index 0000000000000000000000000000000000000000..e125bbb235d8b0d0300018cdc87cda9018d3e638 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.c @@ -0,0 +1,1385 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver3.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_camif_ver3.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_camif_ver3_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_camif_ver3_pp_clc_reg *camif_reg; + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_ver3_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + struct cam_vfe_camif_common_cfg cam_common_cfg; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + int sof_irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_CAMIF_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t camif_debug; + uint32_t horizontal_bin; + uint32_t qcfa_bin; +}; + +static int cam_vfe_camif_ver3_get_evt_payload( + struct cam_vfe_mux_camif_ver3_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&camif_priv->spin_lock); + if (list_empty(&camif_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free CAMIF event payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&camif_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); +done: + spin_unlock(&camif_priv->spin_lock); + return rc; +} + +static int cam_vfe_camif_ver3_put_evt_payload( + struct cam_vfe_mux_camif_ver3_data *camif_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&camif_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, &camif_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&camif_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_camif_ver3_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[2] || (th_payload->evt_status_arr[0] & + camif_priv->reg_data->error_irq_mask0)) { + CAM_ERR(CAM_ISP, + "VFE:%d CAMIF Err IRQ status_0: 0x%X status_2: 0x%X", + camif_node->hw_intf->hw_idx, + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[2]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from VFE:%d", + camif_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq(camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + camif_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_camif_ver3_get_evt_payload(camif_priv, &evt_payload); + if (rc) + return rc; + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->violation_status); + + evt_payload->irq_reg_val[++i] = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->bus_overflow_status); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_camif_ver3_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error, Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_camif_ver3_get_reg_update( + struct cam_isp_resource_node *camif_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_camif_ver3_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid arg size: %d expected:%ld", + arg_size, sizeof(struct cam_isp_hw_get_cmd_update)); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args: %pK", cdm_args); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, (size*4)); + return -EINVAL; + } + + rsrc_data = camif_res->res_priv; + reg_val_pair[0] = rsrc_data->camif_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "VFE:%d CAMIF reg_update_cmd 0x%X offset 0x%X", + camif_res->hw_intf->hw_idx, + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_camif_ver3_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param) +{ + struct cam_vfe_mux_camif_ver3_data *camif_data; + struct cam_vfe_acquire_args *acquire_data; + int rc = 0; + + camif_data = (struct cam_vfe_mux_camif_ver3_data *) + camif_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_camif_ver3_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + + if (rc) { + CAM_ERR(CAM_ISP, "Validate pix pattern failed, rc = %d", rc); + return rc; + } + + camif_data->sync_mode = acquire_data->vfe_in.sync_mode; + camif_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + camif_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + camif_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + camif_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + camif_data->first_line = acquire_data->vfe_in.in_port->line_start; + camif_data->last_line = acquire_data->vfe_in.in_port->line_stop; + camif_data->horizontal_bin = + acquire_data->vfe_in.in_port->horizontal_bin; + camif_data->qcfa_bin = acquire_data->vfe_in.in_port->qcfa_bin; + camif_data->event_cb = acquire_data->event_cb; + camif_data->priv = acquire_data->priv; + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF pix_pattern:%d dsp_mode=%d", + camif_res->hw_intf->hw_idx, + camif_data->pix_pattern, camif_data->dsp_mode); + + return rc; +} + +static int cam_vfe_camif_ver3_resource_init( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_ver3_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_ver3_data *) + camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, + "failed to enable dsp clk, rc = %d", rc); + } + + return rc; +} + +static int cam_vfe_camif_ver3_resource_deinit( + struct cam_isp_resource_node *camif_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_camif_ver3_data *camif_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + camif_data = (struct cam_vfe_mux_camif_ver3_data *) + camif_res->res_priv; + + soc_info = camif_data->soc_info; + + if ((camif_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; +} + +static int cam_vfe_camif_ver3_resource_start( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_line_cfg; + uint32_t epoch1_line_cfg; + uint32_t computed_epoch_line_cfg; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + struct cam_vfe_soc_private *soc_private; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if (camif_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error, Invalid camif res res_state:%d", + camif_res->res_state); + return -EINVAL; + } + + memset(err_irq_mask, 0, sizeof(err_irq_mask)); + memset(irq_mask, 0, sizeof(irq_mask)); + + rsrc_data = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error, soc_private NULL"); + return -ENODEV; + } + + /* config debug status registers */ + cam_io_w_mb(rsrc_data->reg_data->top_debug_cfg_en, rsrc_data->mem_base + + rsrc_data->common_reg->top_debug_cfg); + + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + /* AF stitching by hw disabled by default + * PP CAMIF currently operates only in offline mode + */ + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->pp_extern_reg_update_shift); + + if ((rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) || + (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_MASTER)) + val |= (1 << rsrc_data->reg_data->dual_ife_pix_en_shift); + + val |= (~rsrc_data->cam_common_cfg.vid_ds16_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_VID_DS16_R2PD; + val |= (~rsrc_data->cam_common_cfg.vid_ds4_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_VID_DS4_R2PD; + val |= (~rsrc_data->cam_common_cfg.disp_ds16_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_DISP_DS16_R2PD; + val |= (~rsrc_data->cam_common_cfg.disp_ds4_r2pd & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_DISP_DS4_R2PD; + val |= (rsrc_data->cam_common_cfg.dsp_streaming_tap_point & 0x3) << + CAM_SHIFT_TOP_CORE_CFG_DSP_STREAMING; + val |= (rsrc_data->cam_common_cfg.ihist_src_sel & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_STATS_IHIST; + val |= (rsrc_data->cam_common_cfg.hdr_be_src_sel & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BE; + val |= (rsrc_data->cam_common_cfg.hdr_bhist_src_sel & 0x1) << + CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BHIST; + val |= (rsrc_data->cam_common_cfg.input_mux_sel_pp & 0x3) << + CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP; + + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->core_cfg_0); + + /* epoch config */ + switch (soc_private->cpas_version) { + case CAM_CPAS_TITAN_480_V100: + epoch0_line_cfg = (rsrc_data->last_line - + rsrc_data->first_line) / 4; + /* epoch line cfg will still be configured at midpoint of the + * frame width. We use '/ 4' instead of '/ 2' + * cause it is multipixel path + */ + if (rsrc_data->horizontal_bin || rsrc_data->qcfa_bin) + epoch0_line_cfg >>= 1; + + epoch1_line_cfg = rsrc_data->reg_data->epoch_line_cfg & + 0xFFFF; + computed_epoch_line_cfg = (epoch1_line_cfg << 16) | + epoch0_line_cfg; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + + rsrc_data->camif_reg->epoch_irq_cfg); + CAM_DBG(CAM_ISP, "epoch_line_cfg: 0x%X", + computed_epoch_line_cfg); + break; + default: + CAM_ERR(CAM_ISP, "Hardware version not proper: 0x%X", + soc_private->cpas_version); + return -EINVAL; + break; + } + + camif_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->camif_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "VFE:%d CAMIF RUP val:0x%X", + camif_res->hw_intf->hw_idx, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + if (rsrc_data->camif_debug & + CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + val = cam_io_r_mb(rsrc_data->mem_base + + rsrc_data->common_reg->diag_config); + val |= rsrc_data->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, rsrc_data->mem_base + + rsrc_data->common_reg->diag_config); + } + + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS2] = + rsrc_data->reg_data->error_irq_mask2; + + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->epoch0_irq_mask | + rsrc_data->reg_data->eof_irq_mask; + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_3, + irq_mask, + camif_res, + camif_res->top_half_handler, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->reg_data->sof_irq_mask; + + if (!rsrc_data->sof_irq_handle) { + rsrc_data->sof_irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_mask, + camif_res, + camif_res->top_half_handler, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + + if (rsrc_data->sof_irq_handle < 1) { + CAM_ERR(CAM_ISP, "SOF IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->sof_irq_handle = 0; + } + } + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + err_irq_mask, + camif_res, + cam_vfe_camif_ver3_err_irq_top_half, + camif_res->bottom_half_handler, + camif_res->tasklet_info, + &tasklet_bh_api); + + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "VFE:%d CAMIF Start Done", camif_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_camif_ver3_reg_dump( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + uint32_t offset, val, wm_idx; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + + CAM_INFO(CAM_ISP, "IFE:%d TOP", camif_res->hw_intf->hw_idx); + for (offset = 0x0; offset <= 0x1FC; offset += 0x4) { + if (offset == 0x1C || offset == 0x34 || + offset == 0x38 || offset == 0x90) + continue; + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + CAM_INFO(CAM_ISP, "IFE:%d PP CLC PREPROCESS", + camif_res->hw_intf->hw_idx); + for (offset = 0x2200; offset <= 0x23FC; offset += 0x4) { + if (offset == 0x2208) + offset = 0x2260; + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + if (offset == 0x2260) + offset = 0x23F4; + } + + CAM_INFO(CAM_ISP, "IFE:%d PP CLC CAMIF", camif_res->hw_intf->hw_idx); + for (offset = 0x2600; offset <= 0x27FC; offset += 0x4) { + if (offset == 0x2608) + offset = 0x2660; + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + if (offset == 0x2660) + offset = 0x2664; + else if (offset == 0x2680) + offset = 0x27EC; + } + + CAM_INFO(CAM_ISP, "IFE:%d PP CLC Modules", camif_res->hw_intf->hw_idx); + for (offset = 0x2800; offset <= 0x8FFC; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + CAM_INFO(CAM_ISP, "IFE:%d BUS WR", camif_res->hw_intf->hw_idx); + for (offset = 0xAA00; offset <= 0xAADC; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_DBG(CAM_ISP, "offset 0x%X value 0x%X", offset, val); + } + + for (wm_idx = 0; wm_idx <= 25; wm_idx++) { + for (offset = 0xAC00 + 0x100 * wm_idx; + offset < 0xAC84 + 0x100 * wm_idx; offset += 0x4) { + val = cam_soc_util_r(camif_priv->soc_info, 0, offset); + CAM_INFO(CAM_ISP, "offset 0x%X value 0x%X", + offset, val); + } + } + + return 0; +} + +static int cam_vfe_camif_ver3_resource_stop( + struct cam_isp_resource_node *camif_res) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_camif_ver3_pp_clc_reg *camif_reg; + int rc = 0; + uint32_t val = 0; + + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_ver3_data *)camif_res->res_priv; + camif_reg = camif_priv->camif_reg; + + if ((camif_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (camif_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->core_cfg_0); + val &= (~(1 << camif_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->common_reg->core_cfg_0); + } + + if (camif_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + camif_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + val = cam_io_r_mb(camif_priv->mem_base + + camif_priv->common_reg->diag_config); + if (val & camif_priv->reg_data->enable_diagnostic_hw) { + val &= ~camif_priv->reg_data->enable_diagnostic_hw; + cam_io_w_mb(val, camif_priv->mem_base + + camif_priv->common_reg->diag_config); + } + + if (camif_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, camif_priv->irq_handle); + camif_priv->irq_handle = 0; + } + + if (camif_priv->sof_irq_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, + camif_priv->sof_irq_handle); + camif_priv->sof_irq_handle = 0; + } + + if (camif_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + camif_priv->vfe_irq_controller, + camif_priv->irq_err_handle); + camif_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_camif_ver3_core_config( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_core_config_args *vfe_core_cfg = + (struct cam_vfe_core_config_args *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; + camif_priv->cam_common_cfg.vid_ds16_r2pd = + vfe_core_cfg->core_config.vid_ds16_r2pd; + camif_priv->cam_common_cfg.vid_ds4_r2pd = + vfe_core_cfg->core_config.vid_ds4_r2pd; + camif_priv->cam_common_cfg.disp_ds16_r2pd = + vfe_core_cfg->core_config.disp_ds16_r2pd; + camif_priv->cam_common_cfg.disp_ds4_r2pd = + vfe_core_cfg->core_config.disp_ds4_r2pd; + camif_priv->cam_common_cfg.dsp_streaming_tap_point = + vfe_core_cfg->core_config.dsp_streaming_tap_point; + camif_priv->cam_common_cfg.ihist_src_sel = + vfe_core_cfg->core_config.ihist_src_sel; + camif_priv->cam_common_cfg.hdr_be_src_sel = + vfe_core_cfg->core_config.hdr_be_src_sel; + camif_priv->cam_common_cfg.hdr_bhist_src_sel = + vfe_core_cfg->core_config.hdr_bhist_src_sel; + camif_priv->cam_common_cfg.input_mux_sel_pdaf = + vfe_core_cfg->core_config.input_mux_sel_pdaf; + camif_priv->cam_common_cfg.input_mux_sel_pp = + vfe_core_cfg->core_config.input_mux_sel_pp; + + return 0; +} + +static int cam_vfe_camif_ver3_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_ver3_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + camif_priv->enable_sof_irq_debug = true; + else + camif_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_camif_ver3_process_cmd( + struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + struct cam_vfe_mux_camif_ver3_data *camif_priv = NULL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, + "Invalid input arguments rsesource node:%pK cmd_args:%pK", + rsrc_node, cmd_args); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_camif_ver3_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_camif_ver3_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_vfe_camif_ver3_core_config(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_SET_CAMIF_DEBUG: + camif_priv = (struct cam_vfe_mux_camif_ver3_data *) + rsrc_node->res_priv; + camif_priv->camif_debug = *((uint32_t *)cmd_args); + break; + case CAM_ISP_HW_CMD_QUERY_REGSPACE_DATA: + camif_priv = (struct cam_vfe_mux_camif_ver3_data *) + rsrc_node->res_priv; + *((struct cam_hw_soc_info **)cmd_args) = camif_priv->soc_info; + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + + +static void cam_vfe_camif_ver3_overflow_debug_info( + struct cam_vfe_mux_camif_ver3_data *camif_priv) +{ + uint32_t val0, val1, val2, val3; + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_0); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_1); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_2); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_3); + CAM_INFO(CAM_ISP, + "status_0: 0x%X status_1: 0x%X status_2: 0x%X status_3: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_4); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_5); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_6); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_7); + CAM_INFO(CAM_ISP, + "status_4: 0x%X status_5: 0x%X status_6: 0x%X status_7: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_8); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_9); + val2 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_10); + val3 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_11); + CAM_INFO(CAM_ISP, + "status_8: 0x%X status_9: 0x%X status_10: 0x%X status_11: 0x%X", + val0, val1, val2, val3); + + val0 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_12); + val1 = cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->top_debug_13); + CAM_INFO(CAM_ISP, "status_12: 0x%X status_13: 0x%X", + val0, val1); +} + +static void cam_vfe_camif_ver3_print_status(uint32_t *status, + int err_type, struct cam_vfe_mux_camif_ver3_data *camif_priv) +{ + uint32_t violation_mask = 0x3F, module_id = 0; + uint32_t bus_overflow_status = 0, status_0 = 0, status_2 = 0; + struct cam_vfe_soc_private *soc_private; + uint32_t val0, val1, val2; + + if (!status) { + CAM_ERR(CAM_ISP, "Invalid params"); + return; + } + + bus_overflow_status = status[CAM_IFE_IRQ_BUS_OVERFLOW_STATUS]; + status_0 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + status_2 = status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]; + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW) { + if (status_0 & 0x0200) + CAM_INFO(CAM_ISP, "DSP OVERFLOW"); + + if (status_0 & 0x2000000) + CAM_INFO(CAM_ISP, "PIXEL PIPE FRAME DROP"); + + if (status_0 & 0x80000000) + CAM_INFO(CAM_ISP, "PIXEL PIPE OVERFLOW"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && bus_overflow_status) { + if (bus_overflow_status & 0x01) + CAM_INFO(CAM_ISP, "VID Y 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x02) + CAM_INFO(CAM_ISP, "VID C 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x04) + CAM_INFO(CAM_ISP, "VID YC 4:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x08) + CAM_INFO(CAM_ISP, "VID YC 16:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x010) + CAM_INFO(CAM_ISP, "DISP Y 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x020) + CAM_INFO(CAM_ISP, "DISP C 1:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x040) + CAM_INFO(CAM_ISP, "DISP YC 4:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x080) + CAM_INFO(CAM_ISP, "DISP YC 16:1 BUS OVERFLOW"); + + if (bus_overflow_status & 0x0100) + CAM_INFO(CAM_ISP, "FD Y BUS OVERFLOW"); + + if (bus_overflow_status & 0x0200) + CAM_INFO(CAM_ISP, "FD C BUS OVERFLOW"); + + if (bus_overflow_status & 0x0400) + CAM_INFO(CAM_ISP, "PIXEL RAW DUMP BUS OVERFLOW"); + + if (bus_overflow_status & 0x01000) + CAM_INFO(CAM_ISP, "STATS HDR BE BUS OVERFLOW"); + + if (bus_overflow_status & 0x02000) + CAM_INFO(CAM_ISP, "STATS HDR BHIST BUS OVERFLOW"); + + if (bus_overflow_status & 0x04000) + CAM_INFO(CAM_ISP, "STATS TINTLESS BG BUS OVERFLOW"); + + if (bus_overflow_status & 0x08000) + CAM_INFO(CAM_ISP, "STATS AWB BG BUS OVERFLOW"); + + if (bus_overflow_status & 0x010000) + CAM_INFO(CAM_ISP, "STATS BHIST BUS OVERFLOW"); + + if (bus_overflow_status & 0x020000) + CAM_INFO(CAM_ISP, "STATS RS BUS OVERFLOW"); + + if (bus_overflow_status & 0x040000) + CAM_INFO(CAM_ISP, "STATS CS BUS OVERFLOW"); + + if (bus_overflow_status & 0x080000) + CAM_INFO(CAM_ISP, "STATS IHIST BUS OVERFLOW"); + + if (bus_overflow_status & 0x0100000) + CAM_INFO(CAM_ISP, "STATS BAF BUS OVERFLOW"); + + if (bus_overflow_status & 0x0200000) + CAM_INFO(CAM_ISP, "PDAF BUS OVERFLOW"); + + soc_private = camif_priv->soc_info->soc_private; + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0xA20, true, &val0); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1420, true, &val1); + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x1A20, true, &val2); + CAM_INFO(CAM_ISP, + "CAMNOC REG ife_linear: 0x%X ife_rdi_wr: 0x%X ife_ubwc_stats: 0x%X", + val0, val1, val2); + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_OVERFLOW && !bus_overflow_status) { + CAM_INFO(CAM_ISP, "PIXEL PIPE Module hang"); + /* print debug registers */ + cam_vfe_camif_ver3_overflow_debug_info(camif_priv); + return; + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION) { + if (status_2 & 0x080) + CAM_INFO(CAM_ISP, "DSP IFE PROTOCOL VIOLATION"); + + if (status_2 & 0x0100) + CAM_INFO(CAM_ISP, "IFE DSP TX PROTOCOL VIOLATION"); + + if (status_2 & 0x0200) + CAM_INFO(CAM_ISP, "DSP IFE RX PROTOCOL VIOLATION"); + + if (status_2 & 0x0400) + CAM_INFO(CAM_ISP, "PP PREPROCESS VIOLATION"); + + if (status_2 & 0x0800) + CAM_INFO(CAM_ISP, "PP CAMIF VIOLATION"); + + if (status_2 & 0x01000) + CAM_INFO(CAM_ISP, "PP VIOLATION"); + + if (status_2 & 0x0100000) + CAM_INFO(CAM_ISP, + "DSP_TX_VIOLATION:overflow on DSP interface TX path FIFO"); + + if (status_2 & 0x0200000) + CAM_INFO(CAM_ISP, + "DSP_RX_VIOLATION:overflow on DSP interface RX path FIFO"); + + if (status_2 & 0x10000000) + CAM_INFO(CAM_ISP, "DSP ERROR VIOLATION"); + + if (status_2 & 0x20000000) + CAM_INFO(CAM_ISP, + "DIAG VIOLATION: HBI is less than the minimum required HBI"); + } + + if (err_type == CAM_VFE_IRQ_STATUS_VIOLATION && + status[CAM_IFE_IRQ_VIOLATION_STATUS]) { + module_id = + violation_mask & status[CAM_IFE_IRQ_VIOLATION_STATUS]; + CAM_INFO(CAM_ISP, "PIXEL PIPE VIOLATION Module ID:%d", + module_id); + + switch (module_id) { + case 0: + CAM_INFO(CAM_ISP, "DEMUX"); + break; + case 1: + CAM_INFO(CAM_ISP, "CHROMA_UP"); + break; + case 2: + CAM_INFO(CAM_ISP, "PEDESTAL"); + break; + case 3: + CAM_INFO(CAM_ISP, "LINEARIZATION"); + break; + case 4: + CAM_INFO(CAM_ISP, "BPC_PDPC"); + break; + case 5: + CAM_INFO(CAM_ISP, "HDR_BINCORRECT"); + break; + case 6: + CAM_INFO(CAM_ISP, "ABF"); + break; + case 7: + CAM_INFO(CAM_ISP, "LSC"); + break; + case 8: + CAM_INFO(CAM_ISP, "DEMOSAIC"); + break; + case 9: + CAM_INFO(CAM_ISP, "COLOR_CORRECT"); + break; + case 10: + CAM_INFO(CAM_ISP, "GTM"); + break; + case 11: + CAM_INFO(CAM_ISP, "GLUT"); + break; + case 12: + CAM_INFO(CAM_ISP, "COLOR_XFORM"); + break; + case 13: + CAM_INFO(CAM_ISP, "CROP_RND_CLAMP_PIXEL_RAW_OUT"); + break; + case 14: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_Y_FD_OUT"); + break; + case 15: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_C_FD_OUT"); + break; + case 16: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_FD_OUT"); + break; + case 17: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_FD_OUT"); + break; + case 18: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_Y_DISP_OUT"); + break; + case 19: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_C_DISP_OUT"); + break; + case 20: + CAM_INFO(CAM_ISP, + "module: CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_DISP_OUT"); + break; + case 21: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_DISP_OUT"); + break; + case 22: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_Y_DISP_DS4_OUT"); + break; + case 23: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_C_DISP_DS4_OUT"); + break; + case 24: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_DISP_DS4_OUT"); + break; + case 25: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_DISP_DS4_OUT"); + break; + case 26: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_Y_DISP_DS16_OUT"); + break; + case 27: + CAM_INFO(CAM_ISP, "DOWNSCALE_4TO1_C_DISP_DS16_OUT"); + break; + case 28: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_DISP_DS16_OUT"); + break; + case 29: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_DISP_DS16_OUT"); + break; + case 30: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_Y_VID_OUT"); + break; + case 31: + CAM_INFO(CAM_ISP, "DOWNSCALE_MN_C_VID_OUT"); + break; + case 32: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_Y_VID_OUT"); + break; + case 33: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_MN_C_VID_OUT"); + break; + case 34: + CAM_INFO(CAM_ISP, "DSX_Y_VID_OUT"); + break; + case 35: + CAM_INFO(CAM_ISP, "DSX_C_VID_OUT"); + break; + case 36: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DSX_Y_VID_OUT"); + break; + case 37: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DSX_C_VID_OUT"); + break; + case 38: + CAM_INFO(CAM_ISP, + "DOWNSCALE_4TO1_Y_VID_DS16_OUT"); + break; + case 39: + CAM_INFO(CAM_ISP, + "DOWNSCALE_4TO1_C_VID_DS16_OUT"); + break; + case 40: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_Y_VID_DS16_OUT"); + break; + case 41: + CAM_INFO(CAM_ISP, + "CROP_RND_CLAMP_POST_DOWNSCALE_4TO1_C_VID_DS16_OUT"); + break; + case 42: + CAM_INFO(CAM_ISP, "BLS"); + break; + case 43: + CAM_INFO(CAM_ISP, "STATS_TINTLESS_BG"); + break; + case 44: + CAM_INFO(CAM_ISP, "STATS_HDR_BHIST"); + break; + case 45: + CAM_INFO(CAM_ISP, "STATS_HDR_BE"); + break; + case 46: + CAM_INFO(CAM_ISP, "STATS_AWB_BG"); + break; + case 47: + CAM_INFO(CAM_ISP, "STATS_BHIST"); + break; + case 48: + CAM_INFO(CAM_ISP, "STATS_BAF"); + break; + case 49: + CAM_INFO(CAM_ISP, "STATS_RS"); + break; + case 50: + CAM_INFO(CAM_ISP, "STATS_CS"); + break; + case 51: + CAM_INFO(CAM_ISP, "STATS_IHIST"); + break; + default: + CAM_ERR(CAM_ISP, + "Invalid Module ID:%d", module_id); + break; + } + } +} + +static int cam_vfe_camif_ver3_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + camif_node = th_payload->handler_priv; + camif_priv = camif_node->res_priv; + + CAM_DBG(CAM_ISP, + "VFE:%d CAMIF IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_node->hw_intf->hw_idx, th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], th_payload->evt_status_arr[2]); + + rc = cam_vfe_camif_ver3_get_evt_payload(camif_priv, &evt_payload); + if (rc) { + CAM_INFO_RATE_LIMIT(CAM_ISP, + "VFE:%d CAMIF IRQ status_0: 0x%X status_1: 0x%X status_2: 0x%X", + camif_node->hw_intf->hw_idx, th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1], th_payload->evt_status_arr[2]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_camif_ver3_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *camif_node; + struct cam_vfe_mux_camif_ver3_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status[CAM_IFE_IRQ_REGISTERS_MAX] = {0}; + int i = 0; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, + "Invalid params handle_priv:%pK, evt_payload_priv:%pK", + handler_priv, evt_payload_priv); + return ret; + } + + camif_node = handler_priv; + camif_priv = camif_node->res_priv; + payload = evt_payload_priv; + + for (i = 0; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) + irq_status[i] = payload->irq_reg_val[i]; + + evt_info.hw_idx = camif_node->hw_intf->hw_idx; + evt_info.res_id = camif_node->res_id; + evt_info.res_type = camif_node->res_type; + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->sof_irq_mask) { + if ((camif_priv->enable_sof_irq_debug) && + (camif_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "VFE:%d Received SOF", + evt_info.hw_idx); + + camif_priv->irq_debug_cnt++; + if (camif_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + camif_priv->enable_sof_irq_debug = + false; + camif_priv->irq_debug_cnt = 0; + } + } else + CAM_DBG(CAM_ISP, "VFE:%d Received SOF", + evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d Received EPOCH", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EPOCH, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS1] + & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "VFE:%d Received EOF", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_EOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS0] + & camif_priv->reg_data->error_irq_mask0) { + CAM_ERR(CAM_ISP, "VFE:%d Overflow", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_OVERFLOW; + + cam_vfe_camif_ver3_print_status(irq_status, ret, camif_priv); + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_ver3_reg_dump(camif_node); + } + + if (irq_status[CAM_IFE_IRQ_CAMIF_REG_STATUS2]) { + CAM_ERR(CAM_ISP, "VFE:%d Violation", evt_info.hw_idx); + + if (camif_priv->event_cb) + camif_priv->event_cb(camif_priv->priv, + CAM_ISP_HW_EVENT_ERROR, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_VIOLATION; + + cam_vfe_camif_ver3_print_status(irq_status, ret, camif_priv); + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_REG_DUMP) + cam_vfe_camif_ver3_reg_dump(camif_node); + } + + if (camif_priv->camif_debug & CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS) { + CAM_DBG(CAM_ISP, "VFE:%d VFE_DIAG_SENSOR_STATUS: 0x%X", + evt_info.hw_idx, camif_priv->mem_base, + cam_io_r(camif_priv->mem_base + + camif_priv->common_reg->diag_sensor_status_0)); + } + + cam_vfe_camif_ver3_put_evt_payload(camif_priv, &payload); + + CAM_DBG(CAM_ISP, "returning status = %d", ret); + return ret; +} + +int cam_vfe_camif_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv = NULL; + struct cam_vfe_camif_ver3_hw_info *camif_info = camif_hw_info; + int i = 0; + + camif_priv = kzalloc(sizeof(struct cam_vfe_mux_camif_ver3_data), + GFP_KERNEL); + if (!camif_priv) + return -ENOMEM; + + camif_node->res_priv = camif_priv; + + camif_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + camif_priv->camif_reg = camif_info->camif_reg; + camif_priv->common_reg = camif_info->common_reg; + camif_priv->reg_data = camif_info->reg_data; + camif_priv->hw_intf = hw_intf; + camif_priv->soc_info = soc_info; + camif_priv->vfe_irq_controller = vfe_irq_controller; + + camif_node->init = cam_vfe_camif_ver3_resource_init; + camif_node->deinit = cam_vfe_camif_ver3_resource_deinit; + camif_node->start = cam_vfe_camif_ver3_resource_start; + camif_node->stop = cam_vfe_camif_ver3_resource_stop; + camif_node->process_cmd = cam_vfe_camif_ver3_process_cmd; + camif_node->top_half_handler = cam_vfe_camif_ver3_handle_irq_top_half; + camif_node->bottom_half_handler = + cam_vfe_camif_ver3_handle_irq_bottom_half; + spin_lock_init(&camif_priv->spin_lock); + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) { + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + list_add_tail(&camif_priv->evt_payload[i].list, + &camif_priv->free_payload_list); + } + + return 0; +} + +int cam_vfe_camif_ver3_deinit( + struct cam_isp_resource_node *camif_node) +{ + struct cam_vfe_mux_camif_ver3_data *camif_priv; + int i = 0; + + if (!camif_node) { + CAM_ERR(CAM_ISP, "Error, camif_node is NULL %pK", camif_node); + return -ENODEV; + } + + camif_priv = camif_node->res_priv; + + INIT_LIST_HEAD(&camif_priv->free_payload_list); + for (i = 0; i < CAM_VFE_CAMIF_EVT_MAX; i++) + INIT_LIST_HEAD(&camif_priv->evt_payload[i].list); + + camif_priv = camif_node->res_priv; + + camif_node->start = NULL; + camif_node->stop = NULL; + camif_node->process_cmd = NULL; + camif_node->top_half_handler = NULL; + camif_node->bottom_half_handler = NULL; + camif_node->res_priv = NULL; + + if (!camif_priv) { + CAM_ERR(CAM_ISP, "Error, camif_priv is NULL %pK", camif_priv); + return -ENODEV; + } + + kfree(camif_priv); + + return 0; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h new file mode 100644 index 0000000000000000000000000000000000000000..40d8e40ae8522aeff82fa4c558fc499d42d8f418 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver3.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_CAMIF_VER3_H_ +#define _CAM_VFE_CAMIF_VER3_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_camif_ver3_pp_clc_reg { + uint32_t hw_version; + uint32_t hw_status; + uint32_t module_cfg; + uint32_t pdaf_raw_crop_width_cfg; + uint32_t pdaf_raw_crop_height_cfg; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t period_cfg; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq_cfg; + uint32_t debug_1; + uint32_t debug_0; + uint32_t test_bus_ctrl; + uint32_t spare; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_camif_ver3_reg_data { + uint32_t pp_extern_reg_update_shift; + uint32_t dual_pd_extern_reg_update_shift; + uint32_t extern_reg_update_mask; + uint32_t dual_ife_pix_en_shift; + uint32_t operating_mode_shift; + uint32_t input_mux_sel_shift; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask2; + uint32_t subscribe_irq_mask1; + + uint32_t enable_diagnostic_hw; + uint32_t pp_camif_cfg_en_shift; + uint32_t pp_camif_cfg_ife_out_en_shift; + uint32_t top_debug_cfg_en; +}; + +struct cam_vfe_camif_ver3_hw_info { + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_ver3_pp_clc_reg *camif_reg; + struct cam_vfe_camif_ver3_reg_data *reg_data; +}; + +int cam_vfe_camif_ver3_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_camif_ver3_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node, + void *vfe_irq_controller); + +int cam_vfe_camif_ver3_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_VER3_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c new file mode 100644 index 0000000000000000000000000000000000000000..98c84ad77d9334feffcd391124b197d107c0c30e --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_fe_ver1.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_fe_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t fe_cfg_data; + uint32_t hbi_count; +}; + +static int cam_vfe_fe_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error! Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_fe_update( + struct cam_isp_resource_node *fe_res, + void *cmd_data, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + struct cam_vfe_fe_update_args *args = cmd_data; + uint32_t fe_cfg_data; + + if (arg_size != sizeof(struct cam_vfe_fe_update_args)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "fe_update->min_vbi = 0x%x", args->fe_config.min_vbi); + CAM_DBG(CAM_ISP, "fe_update->hbi_count = 0x%x", + args->fe_config.hbi_count); + CAM_DBG(CAM_ISP, "fe_update->fs_mode = 0x%x", args->fe_config.fs_mode); + CAM_DBG(CAM_ISP, "fe_update->fs_line_sync_en = 0x%x", + args->fe_config.fs_line_sync_en); + + fe_cfg_data = args->fe_config.min_vbi | + args->fe_config.fs_mode << 8 | + args->fe_config.fs_line_sync_en; + + rsrc_data = fe_res->res_priv; + rsrc_data->fe_cfg_data = fe_cfg_data; + rsrc_data->hbi_count = args->fe_config.hbi_count; + + CAM_DBG(CAM_ISP, "fe_cfg_data = 0x%x", fe_cfg_data); + return 0; +} + +static int cam_vfe_fe_get_reg_update( + struct cam_isp_resource_node *fe_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = fe_res->res_priv; + reg_val_pair[0] = rsrc_data->fe_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF reg_update_cmd 0x%x offset 0x%x", + reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *fe_res, + void *acquire_param) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_vfe_acquire_args *acquire_data; + + int rc = 0; + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_fe_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + if (rc) { + CAM_ERR(CAM_ISP, "pix validation failed: id:%d pix_pattern %d", + fe_res->hw_intf->hw_idx, + acquire_data->vfe_in.in_port->test_pattern); + return rc; + } + + fe_data->sync_mode = acquire_data->vfe_in.sync_mode; + fe_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + fe_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + fe_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + fe_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + fe_data->first_line = acquire_data->vfe_in.in_port->line_start; + fe_data->last_line = acquire_data->vfe_in.in_port->line_stop; + + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + fe_res->hw_intf->hw_idx, + fe_data->pix_pattern, fe_data->dsp_mode); + return rc; +} + +static int cam_vfe_fe_resource_init( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to enable dsp clk"); + } + + return rc; +} + +static int cam_vfe_fe_resource_deinit( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; + +} + +static int cam_vfe_fe_resource_start( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid fe res res_state:%d", + fe_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + /* config vfe core */ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + if (rsrc_data->fe_cfg_data) { + /*set Mux mode value to EXT_RD_PATH */ + val |= (rsrc_data->reg_data->fe_mux_data << + rsrc_data->reg_data->input_mux_sel_shift); + } + + if (rsrc_data->hbi_count) { + /*set hbi count*/ + val |= (rsrc_data->hbi_count << + rsrc_data->reg_data->hbi_cnt_shift); + } + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->common_reg->core_cfg, + val); + + /* disable the CGC for stats */ + cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base + + rsrc_data->common_reg->module_ctrl[ + CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); + + /* epoch config */ + epoch0_irq_mask = ((rsrc_data->last_line - rsrc_data->first_line) / 2) + + rsrc_data->first_line; + + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + rsrc_data->fe_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line:0x%x last_line:0x%x epoch_line_cfg: 0x%x", + rsrc_data->first_line, rsrc_data->last_line, + computed_epoch_line_cfg); + + fe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Read Back cfg */ + cam_io_w_mb(rsrc_data->fe_cfg_data, + rsrc_data->mem_base + rsrc_data->fe_reg->fe_cfg); + CAM_DBG(CAM_ISP, "hw id:%d fe_cfg_data(off:0x%x val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->fe_cfg, + rsrc_data->fe_cfg_data); + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->fe_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->reg_update_cmd, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", fe_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_fe_reg_dump( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0, i; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + soc_private = fe_priv->soc_info->soc_private; + for (i = 0xA3C; i <= 0xA90; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0xE0C; i <= 0xE3C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2000; i <= 0x20B8; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2500; i <= 0x255C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2600; i <= 0x265C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle, + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + + return rc; +} + +static int cam_vfe_fe_resource_stop( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_fe_ver1_reg *fe_reg; + int rc = 0; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + fe_reg = fe_priv->fe_reg; + + if ((fe_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + val &= (~(1 << fe_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + fe_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_fe_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_fe_data *fe_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + fe_priv = + (struct cam_vfe_mux_fe_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + fe_priv->enable_sof_irq_debug = true; + else + fe_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_fe_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_fe_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_fe_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_fe_update(rsrc_node, cmd_args, arg_size); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_fe_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_fe_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *fe_node; + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + uint32_t irq_status1; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + fe_node = handler_priv; + fe_priv = fe_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + evt_info.hw_idx = fe_node->hw_intf->hw_idx; + evt_info.res_id = fe_node->res_id; + evt_info.res_type = fe_node->res_type; + + CAM_DBG(CAM_ISP, "event ID, irq_status_0 = 0x%x", irq_status0); + + if (irq_status0 & fe_priv->reg_data->sof_irq_mask) { + if ((fe_priv->enable_sof_irq_debug) && + (fe_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + fe_priv->irq_debug_cnt++; + if (fe_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + fe_priv->enable_sof_irq_debug = + false; + fe_priv->irq_debug_cnt = 0; + } + } else { + CAM_DBG(CAM_ISP, "Received SOF"); + } + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & fe_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & fe_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & fe_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status1 & fe_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR"); + ret = CAM_ISP_HW_ERROR_OVERFLOW; + evt_info.err_type = CAM_VFE_IRQ_STATUS_OVERFLOW; + cam_vfe_fe_reg_dump(fe_node); + } else { + ret = CAM_ISP_HW_ERROR_NONE; + } + + CAM_DBG(CAM_ISP, "returing status = %d", ret); + return ret; +} + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *fe_hw_info, + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = NULL; + struct cam_vfe_fe_ver1_hw_info *fe_info = fe_hw_info; + + fe_priv = kzalloc(sizeof(struct cam_vfe_mux_fe_data), + GFP_KERNEL); + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! Failed to alloc for fe_priv"); + return -ENOMEM; + } + + fe_node->res_priv = fe_priv; + + fe_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + fe_priv->fe_reg = fe_info->fe_reg; + fe_priv->common_reg = fe_info->common_reg; + fe_priv->reg_data = fe_info->reg_data; + fe_priv->hw_intf = hw_intf; + fe_priv->soc_info = soc_info; + + fe_node->init = cam_vfe_fe_resource_init; + fe_node->deinit = cam_vfe_fe_resource_deinit; + fe_node->start = cam_vfe_fe_resource_start; + fe_node->stop = cam_vfe_fe_resource_stop; + fe_node->process_cmd = cam_vfe_fe_process_cmd; + fe_node->top_half_handler = cam_vfe_fe_handle_irq_top_half; + fe_node->bottom_half_handler = cam_vfe_fe_handle_irq_bottom_half; + + return 0; +} + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = fe_node->res_priv; + + fe_node->start = NULL; + fe_node->stop = NULL; + fe_node->process_cmd = NULL; + fe_node->top_half_handler = NULL; + fe_node->bottom_half_handler = NULL; + + fe_node->res_priv = NULL; + + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! fe_priv is NULL"); + return -ENODEV; + } + + kfree(fe_priv); + + return 0; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h new file mode 100644 index 0000000000000000000000000000000000000000..6974a568fd6c02eeb386c7bae38748430588b71f --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_FE_VER1_H_ +#define _CAM_VFE_FE_VER1_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_fe_ver1_reg { + uint32_t camif_cmd; + uint32_t camif_config; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t skip_period; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq; + uint32_t raw_crop_width_cfg; + uint32_t raw_crop_height_cfg; + uint32_t reg_update_cmd; + uint32_t vfe_diag_config; + uint32_t vfe_diag_sensor_status; + uint32_t fe_cfg; +}; + +struct cam_vfe_fe_reg_data { + uint32_t raw_crop_first_pixel_shift; + uint32_t raw_crop_first_pixel_mask; + + uint32_t raw_crop_last_pixel_shift; + uint32_t raw_crop_last_pixel_mask; + + uint32_t raw_crop_first_line_shift; + uint32_t raw_crop_first_line_mask; + + uint32_t raw_crop_last_line_shift; + uint32_t raw_crop_last_line_mask; + + uint32_t input_mux_sel_shift; + uint32_t input_mux_sel_mask; + uint32_t extern_reg_update_shift; + uint32_t extern_reg_update_mask; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + + uint32_t enable_diagnostic_hw; + uint32_t fe_mux_data; + uint32_t hbi_cnt_shift; +}; + +struct cam_vfe_fe_ver1_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_fe_reg_data *reg_data; +}; + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node); + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_FE_VER1_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c new file mode 100644 index 0000000000000000000000000000000000000000..7aaacde775f493ea7317f05cce1490b6f27ae279 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include "cam_vfe_rdi.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_top_ver2.h" +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" + +struct cam_vfe_mux_rdi_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_rdi_ver2_reg *rdi_reg; + struct cam_vfe_rdi_common_reg_data *rdi_common_reg_data; + struct cam_vfe_rdi_reg_data *reg_data; + + cam_hw_mgr_event_cb_func event_cb; + void *priv; + int irq_err_handle; + int irq_handle; + void *vfe_irq_controller; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_RDI_EVT_MAX]; + struct list_head free_payload_list; + spinlock_t spin_lock; + + enum cam_isp_hw_sync_mode sync_mode; +}; + +static int cam_vfe_rdi_get_evt_payload( + struct cam_vfe_mux_rdi_data *rdi_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + int rc = 0; + + spin_lock(&rdi_priv->spin_lock); + if (list_empty(&rdi_priv->free_payload_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + rc = -ENODEV; + goto done; + } + + *evt_payload = list_first_entry(&rdi_priv->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + rc = 0; +done: + spin_unlock(&rdi_priv->spin_lock); + return rc; +} + +static int cam_vfe_rdi_put_evt_payload( + struct cam_vfe_mux_rdi_data *rdi_priv, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + unsigned long flags; + + if (!rdi_priv) { + CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); + return -EINVAL; + } + if (*evt_payload == NULL) { + CAM_ERR(CAM_ISP, "No payload to put"); + return -EINVAL; + } + + spin_lock_irqsave(&rdi_priv->spin_lock, flags); + list_add_tail(&(*evt_payload)->list, &rdi_priv->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&rdi_priv->spin_lock, flags); + + CAM_DBG(CAM_ISP, "Done"); + return 0; +} + +static int cam_vfe_rdi_err_irq_top_half( + uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *rdi_node; + struct cam_vfe_mux_rdi_data *rdi_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + bool error_flag = false; + + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rdi_node = th_payload->handler_priv; + rdi_priv = rdi_node->res_priv; + /* + * need to handle overflow condition here, otherwise irq storm + * will block everything + */ + if (th_payload->evt_status_arr[1]) { + CAM_ERR(CAM_ISP, + "RDI Error: vfe:%d: STATUS_1=0x%x", + rdi_node->hw_intf->hw_idx, + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, "Stopping further IRQ processing from vfe=%d", + rdi_node->hw_intf->hw_idx); + cam_irq_controller_disable_irq(rdi_priv->vfe_irq_controller, + rdi_priv->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + rdi_priv->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_rdi_get_evt_payload(rdi_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "STATUS_1=0x%x", + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + evt_payload->irq_reg_val[i] = cam_io_r(rdi_priv->mem_base + + rdi_priv->common_reg->violation_status); + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = 0x%x", + evt_payload->irq_reg_val[i]); + + th_payload->evt_payload_priv = evt_payload; + + return rc; +} + +static int cam_vfe_rdi_get_reg_update( + struct cam_isp_resource_node *rdi_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_rdi_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error - Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Error - Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Error - Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, + "Error - buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size * 4); + return -EINVAL; + } + + rsrc_data = rdi_res->res_priv; + reg_val_pair[0] = rsrc_data->rdi_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "RDI%d reg_update_cmd %x", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0, reg_val_pair[1]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_rdi_ver2_acquire_resource( + struct cam_isp_resource_node *rdi_res, + void *acquire_param) +{ + struct cam_vfe_mux_rdi_data *rdi_data; + struct cam_vfe_acquire_args *acquire_data; + + rdi_data = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rdi_data->event_cb = acquire_data->event_cb; + rdi_data->priv = acquire_data->priv; + rdi_data->sync_mode = acquire_data->vfe_in.sync_mode; + rdi_res->rdi_only_ctx = 0; + + return 0; +} + +static int cam_vfe_rdi_resource_start( + struct cam_isp_resource_node *rdi_res) +{ + struct cam_vfe_mux_rdi_data *rsrc_data; + int rc = 0; + uint32_t err_irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t irq_mask[CAM_IFE_IRQ_REGISTERS_MAX]; + + if (!rdi_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (rdi_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid rdi res res_state:%d", + rdi_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->rdi_common_reg_data->error_irq_mask0; + err_irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->rdi_common_reg_data->error_irq_mask1; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS0] = + rsrc_data->rdi_common_reg_data->subscribe_irq_mask0; + irq_mask[CAM_IFE_IRQ_CAMIF_REG_STATUS1] = + rsrc_data->rdi_common_reg_data->subscribe_irq_mask1; + + rdi_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->rdi_reg->reg_update_cmd); + + if (!rsrc_data->irq_err_handle) { + rsrc_data->irq_err_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + err_irq_mask, + rdi_res, + cam_vfe_rdi_err_irq_top_half, + rdi_res->bottom_half_handler, + rdi_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_err_handle = 0; + } + } + + if (!rdi_res->rdi_only_ctx) + goto end; + + if (!rsrc_data->irq_handle) { + rsrc_data->irq_handle = cam_irq_controller_subscribe_irq( + rsrc_data->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + irq_mask, + rdi_res, + rdi_res->top_half_handler, + rdi_res->bottom_half_handler, + rdi_res->tasklet_info, + &tasklet_bh_api); + if (rsrc_data->irq_handle < 1) { + CAM_ERR(CAM_ISP, "IRQ handle subscribe failure"); + rc = -ENOMEM; + rsrc_data->irq_handle = 0; + } + } + + CAM_DBG(CAM_ISP, "Start RDI %d", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0); +end: + return rc; +} + + +static int cam_vfe_rdi_resource_stop( + struct cam_isp_resource_node *rdi_res) +{ + struct cam_vfe_mux_rdi_data *rdi_priv; + int rc = 0; + + if (!rdi_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (rdi_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + rdi_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + rdi_priv = (struct cam_vfe_mux_rdi_data *)rdi_res->res_priv; + + if (rdi_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + rdi_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + if (rdi_priv->irq_handle) { + cam_irq_controller_unsubscribe_irq( + rdi_priv->vfe_irq_controller, rdi_priv->irq_handle); + rdi_priv->irq_handle = 0; + } + + if (rdi_priv->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + rdi_priv->vfe_irq_controller, rdi_priv->irq_err_handle); + rdi_priv->irq_err_handle = 0; + } + + return rc; +} + +static int cam_vfe_rdi_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_rdi_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported RDI process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_rdi_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *rdi_node; + struct cam_vfe_mux_rdi_data *rdi_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + + rdi_node = th_payload->handler_priv; + rdi_priv = rdi_node->res_priv; + + CAM_DBG(CAM_ISP, "IRQ status_0 = %x", th_payload->evt_status_arr[0]); + CAM_DBG(CAM_ISP, "IRQ status_1 = %x", th_payload->evt_status_arr[1]); + + rc = cam_vfe_rdi_get_evt_payload(rdi_priv, &evt_payload); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No tasklet_cmd is free in queue"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "IRQ status0=0x%x status1=0x%x", + th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + return rc; + } + + cam_isp_hw_get_timestamp(&evt_payload->ts); + + for (i = 0; i < th_payload->num_registers; i++) + evt_payload->irq_reg_val[i] = th_payload->evt_status_arr[i]; + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_rdi_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *rdi_node; + struct cam_vfe_mux_rdi_data *rdi_priv; + struct cam_vfe_top_irq_evt_payload *payload; + struct cam_isp_hw_event_info evt_info; + uint32_t irq_status0; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + rdi_node = handler_priv; + rdi_priv = rdi_node->res_priv; + payload = evt_payload_priv; + + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + + evt_info.hw_idx = rdi_node->hw_intf->hw_idx; + evt_info.res_id = rdi_node->res_id; + evt_info.res_type = rdi_node->res_type; + + CAM_DBG(CAM_ISP, "irq_status_0 = %x", irq_status0); + + if (irq_status0 & rdi_priv->reg_data->sof_irq_mask) { + CAM_DBG(CAM_ISP, "Received SOF"); + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_SOF, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + if (irq_status0 & rdi_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG UPDATE"); + + if (rdi_priv->event_cb) + rdi_priv->event_cb(rdi_priv->priv, + CAM_ISP_HW_EVENT_REG_UPDATE, (void *)&evt_info); + + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + + cam_vfe_rdi_put_evt_payload(rdi_priv, &payload); + CAM_DBG(CAM_ISP, "returing status = %d", ret); + return ret; +} + +int cam_vfe_rdi_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *rdi_hw_info, + struct cam_isp_resource_node *rdi_node, + void *vfe_irq_controller) +{ + struct cam_vfe_mux_rdi_data *rdi_priv = NULL; + struct cam_vfe_rdi_ver2_hw_info *rdi_info = rdi_hw_info; + int i = 0; + + rdi_priv = kzalloc(sizeof(struct cam_vfe_mux_rdi_data), + GFP_KERNEL); + if (!rdi_priv) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for rdi_priv"); + return -ENOMEM; + } + + rdi_node->res_priv = rdi_priv; + + rdi_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + rdi_priv->hw_intf = hw_intf; + rdi_priv->common_reg = rdi_info->common_reg; + rdi_priv->rdi_reg = rdi_info->rdi_reg; + rdi_priv->vfe_irq_controller = vfe_irq_controller; + rdi_priv->rdi_common_reg_data = rdi_info->common_reg_data; + + switch (rdi_node->res_id) { + case CAM_ISP_HW_VFE_IN_RDI0: + rdi_priv->reg_data = rdi_info->reg_data[0]; + break; + case CAM_ISP_HW_VFE_IN_RDI1: + rdi_priv->reg_data = rdi_info->reg_data[1]; + break; + case CAM_ISP_HW_VFE_IN_RDI2: + rdi_priv->reg_data = rdi_info->reg_data[2]; + break; + case CAM_ISP_HW_VFE_IN_RDI3: + if (rdi_info->reg_data[3]) { + rdi_priv->reg_data = rdi_info->reg_data[3]; + } else { + CAM_ERR(CAM_ISP, "Error! RDI3 is not supported"); + goto err_init; + } + break; + default: + CAM_DBG(CAM_ISP, "invalid Resource id:%d", rdi_node->res_id); + goto err_init; + } + + rdi_node->start = cam_vfe_rdi_resource_start; + rdi_node->stop = cam_vfe_rdi_resource_stop; + rdi_node->process_cmd = cam_vfe_rdi_process_cmd; + rdi_node->top_half_handler = cam_vfe_rdi_handle_irq_top_half; + rdi_node->bottom_half_handler = cam_vfe_rdi_handle_irq_bottom_half; + + spin_lock_init(&rdi_priv->spin_lock); + INIT_LIST_HEAD(&rdi_priv->free_payload_list); + for (i = 0; i < CAM_VFE_RDI_EVT_MAX; i++) { + INIT_LIST_HEAD(&rdi_priv->evt_payload[i].list); + list_add_tail(&rdi_priv->evt_payload[i].list, + &rdi_priv->free_payload_list); + } + + return 0; +err_init: + kfree(rdi_priv); + return -EINVAL; +} + +int cam_vfe_rdi_ver2_deinit( + struct cam_isp_resource_node *rdi_node) +{ + struct cam_vfe_mux_rdi_data *rdi_priv = rdi_node->res_priv; + int i = 0; + + INIT_LIST_HEAD(&rdi_priv->free_payload_list); + for (i = 0; i < CAM_VFE_RDI_EVT_MAX; i++) + INIT_LIST_HEAD(&rdi_priv->evt_payload[i].list); + + rdi_node->start = NULL; + rdi_node->stop = NULL; + rdi_node->process_cmd = NULL; + rdi_node->top_half_handler = NULL; + rdi_node->bottom_half_handler = NULL; + + rdi_node->res_priv = NULL; + + if (!rdi_priv) { + CAM_ERR(CAM_ISP, "Error! rdi_priv NULL"); + return -ENODEV; + } + kfree(rdi_priv); + + return 0; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h new file mode 100644 index 0000000000000000000000000000000000000000..c570e84a011ceb8129613a7e0bf87e3c0c2cc55a --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_RDI_H_ +#define _CAM_VFE_RDI_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +#define CAM_VFE_RDI_VER2_MAX 4 + +#define CAM_VFE_RDI_EVT_MAX 256 + +struct cam_vfe_rdi_ver2_reg { + uint32_t reg_update_cmd; +}; + +struct cam_vfe_rdi_common_reg_data { + uint32_t subscribe_irq_mask0; + uint32_t subscribe_irq_mask1; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + uint32_t error_irq_mask2; + uint32_t rdi_frame_drop_mask; +}; + +struct cam_vfe_rdi_reg_data { + uint32_t reg_update_cmd_data; + uint32_t sof_irq_mask; + uint32_t reg_update_irq_mask; +}; +struct cam_vfe_rdi_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_rdi_ver2_reg *rdi_reg; + struct cam_vfe_rdi_common_reg_data *common_reg_data; + struct cam_vfe_rdi_reg_data *reg_data[CAM_VFE_RDI_VER2_MAX]; +}; + +int cam_vfe_rdi_ver2_acquire_resource( + struct cam_isp_resource_node *rdi_res, + void *acquire_param); + +int cam_vfe_rdi_ver2_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *rdi_hw_info, + struct cam_isp_resource_node *rdi_node, + void *vfe_irq_controller); + +int cam_vfe_rdi_ver2_deinit( + struct cam_isp_resource_node *rdi_node); + +#endif /* _CAM_VFE_RDI_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c new file mode 100644 index 0000000000000000000000000000000000000000..077f89060bca5a2bba0d1a8b09776a16256e6334 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_top_ver3.h" +#include "cam_debug_util.h" + +int cam_vfe_top_init(uint32_t top_version, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top) +{ + int rc = -EINVAL; + + switch (top_version) { + case CAM_VFE_TOP_VER_2_0: + rc = cam_vfe_top_ver2_init(soc_info, hw_intf, top_hw_info, + vfe_irq_controller, vfe_top); + break; + case CAM_VFE_TOP_VER_3_0: + rc = cam_vfe_top_ver3_init(soc_info, hw_intf, top_hw_info, + vfe_irq_controller, vfe_top); + break; + default: + CAM_ERR(CAM_ISP, "Error! Unsupported Version %x", top_version); + break; + } + + return rc; +} + +int cam_vfe_top_deinit(uint32_t top_version, + struct cam_vfe_top **vfe_top) +{ + int rc = -EINVAL; + + switch (top_version) { + case CAM_VFE_TOP_VER_2_0: + rc = cam_vfe_top_ver2_deinit(vfe_top); + break; + case CAM_VFE_TOP_VER_3_0: + rc = cam_vfe_top_ver3_deinit(vfe_top); + break; + default: + CAM_ERR(CAM_ISP, "Error! Unsupported Version %x", top_version); + break; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c new file mode 100644 index 0000000000000000000000000000000000000000..2eae53205c8c6ea3535ca500988e711292ac08f8 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_vfe_top_common.h" +#include "cam_debug_util.h" + +static struct cam_axi_vote *cam_vfe_top_delay_bw_reduction( + struct cam_vfe_top_priv_common *top_common, + uint64_t *to_be_applied_bw) +{ + uint32_t i, j; + int vote_idx = -1; + uint64_t max_bw = 0; + uint64_t total_bw; + struct cam_axi_vote *curr_l_vote; + + for (i = 0; i < CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; i++) { + total_bw = 0; + curr_l_vote = &top_common->last_vote[i]; + for (j = 0; j < curr_l_vote->num_paths; j++) { + if (total_bw > + (U64_MAX - + curr_l_vote->axi_path[j].camnoc_bw)) { + CAM_ERR(CAM_PERF, + "ife[%d] : Integer overflow at hist idx: %d, path: %d, total_bw = %llu, camnoc_bw = %llu", + top_common->hw_idx, i, j, total_bw, + curr_l_vote->axi_path[j].camnoc_bw); + return NULL; + } + + total_bw += curr_l_vote->axi_path[j].camnoc_bw; + } + + if (total_bw > max_bw) { + vote_idx = i; + max_bw = total_bw; + } + } + + if (vote_idx < 0) + return NULL; + + *to_be_applied_bw = max_bw; + + return &top_common->last_vote[vote_idx]; +} + +int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, bool start_stop) +{ + struct cam_axi_vote agg_vote = {0}; + struct cam_axi_vote *to_be_applied_axi_vote = NULL; + int rc = 0; + uint32_t i; + uint32_t num_paths = 0; + uint64_t total_bw_new_vote = 0; + bool bw_unchanged = true; + bool apply_bw_update = false; + + for (i = 0; i < top_common->num_mux; i++) { + if (top_common->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE) { + if (num_paths + + top_common->req_axi_vote[i].num_paths > + CAM_CPAS_MAX_PATHS_PER_CLIENT) { + CAM_ERR(CAM_PERF, + "Required paths(%d) more than max(%d)", + num_paths + + top_common->req_axi_vote[i].num_paths, + CAM_CPAS_MAX_PATHS_PER_CLIENT); + return -EINVAL; + } + + memcpy(&agg_vote.axi_path[num_paths], + &top_common->req_axi_vote[i].axi_path[0], + top_common->req_axi_vote[i].num_paths * + sizeof( + struct cam_axi_per_path_bw_vote)); + num_paths += top_common->req_axi_vote[i].num_paths; + } + } + + agg_vote.num_paths = num_paths; + + for (i = 0; i < agg_vote.num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : New BW Vote : counter[%d] [%s][%s] [%llu %llu %llu]", + top_common->hw_idx, + top_common->last_counter, + cam_cpas_axi_util_path_type_to_string( + agg_vote.axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + agg_vote.axi_path[i].transac_type), + agg_vote.axi_path[i].camnoc_bw, + agg_vote.axi_path[i].mnoc_ab_bw, + agg_vote.axi_path[i].mnoc_ib_bw); + + total_bw_new_vote += agg_vote.axi_path[i].camnoc_bw; + } + + memcpy(&top_common->last_vote[top_common->last_counter], &agg_vote, + sizeof(struct cam_axi_vote)); + top_common->last_counter = (top_common->last_counter + 1) % + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; + + if ((agg_vote.num_paths != top_common->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_common->total_bw_applied)) + bw_unchanged = false; + + CAM_DBG(CAM_PERF, + "ife[%d] : applied_total=%lld, new_total=%lld unchanged=%d, start_stop=%d", + top_common->hw_idx, top_common->total_bw_applied, + total_bw_new_vote, bw_unchanged, start_stop); + + if (bw_unchanged) { + CAM_DBG(CAM_PERF, "BW config unchanged"); + return 0; + } + + if (start_stop) { + /* need to vote current request immediately */ + to_be_applied_axi_vote = &agg_vote; + /* Reset everything, we can start afresh */ + memset(top_common->last_vote, 0x0, sizeof(struct cam_axi_vote) * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); + top_common->last_counter = 0; + top_common->last_vote[top_common->last_counter] = agg_vote; + top_common->last_counter = (top_common->last_counter + 1) % + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES; + } else { + /* + * Find max bw request in last few frames. This will the bw + * that we want to vote to CPAS now. + */ + to_be_applied_axi_vote = + cam_vfe_top_delay_bw_reduction(top_common, + &total_bw_new_vote); + if (!to_be_applied_axi_vote) { + CAM_ERR(CAM_PERF, "to_be_applied_axi_vote is NULL"); + return -EINVAL; + } + } + + for (i = 0; i < to_be_applied_axi_vote->num_paths; i++) { + CAM_DBG(CAM_PERF, + "ife[%d] : Apply BW Vote : [%s][%s] [%llu %llu %llu]", + top_common->hw_idx, + cam_cpas_axi_util_path_type_to_string( + to_be_applied_axi_vote->axi_path[i].path_data_type), + cam_cpas_axi_util_trans_type_to_string( + to_be_applied_axi_vote->axi_path[i].transac_type), + to_be_applied_axi_vote->axi_path[i].camnoc_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ab_bw, + to_be_applied_axi_vote->axi_path[i].mnoc_ib_bw); + } + + if ((to_be_applied_axi_vote->num_paths != + top_common->applied_axi_vote.num_paths) || + (total_bw_new_vote != top_common->total_bw_applied)) + apply_bw_update = true; + + CAM_DBG(CAM_PERF, + "ife[%d] : Delayed update: applied_total=%lld, new_total=%lld apply_bw_update=%d, start_stop=%d", + top_common->hw_idx, top_common->total_bw_applied, + total_bw_new_vote, apply_bw_update, start_stop); + + if (apply_bw_update) { + rc = cam_cpas_update_axi_vote(soc_private->cpas_handle, + to_be_applied_axi_vote); + if (!rc) { + memcpy(&top_common->applied_axi_vote, + to_be_applied_axi_vote, + sizeof(struct cam_axi_vote)); + top_common->total_bw_applied = total_bw_new_vote; + } else { + CAM_ERR(CAM_PERF, "BW request failed, rc=%d", rc); + } + } + + return rc; +} + +int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bw_update_args_v2 *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_update = (struct cam_vfe_bw_update_args_v2 *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_common->num_mux; i++) { + if (top_common->mux_rsrc[i].res_id == res->res_id) { + memcpy(&top_common->req_axi_vote[i], + &bw_update->isp_vote, + sizeof(struct cam_axi_vote)); + top_common->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_PERF, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, + false); + } + + return rc; +} + +int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bw_update_args *bw_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + struct cam_axi_vote *mux_axi_vote; + bool vid_exists = false; + bool rdi_exists = false; + + bw_update = (struct cam_vfe_bw_update_args *)cmd_args; + res = bw_update->node_res; + + if (!res || !res->hw_intf || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + CAM_DBG(CAM_PERF, "res_id=%d, BW=[%lld %lld]", + res->res_id, bw_update->camnoc_bw_bytes, + bw_update->external_bw_bytes); + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_common->num_mux; i++) { + mux_axi_vote = &top_common->req_axi_vote[i]; + if (top_common->mux_rsrc[i].res_id == res->res_id) { + mux_axi_vote->num_paths = 1; + if ((res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && + (res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) { + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_RDI0 + + (res->res_id - CAM_ISP_HW_VFE_IN_RDI0); + } else { + /* + * Vote all bw into VIDEO path as we cannot + * differentiate to which path this has to go + */ + mux_axi_vote->axi_path[0].path_data_type = + CAM_AXI_PATH_DATA_IFE_VID; + } + + mux_axi_vote->axi_path[0].transac_type = + CAM_AXI_TRANSACTION_WRITE; + mux_axi_vote->axi_path[0].camnoc_bw = + bw_update->camnoc_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].mnoc_ib_bw = + bw_update->external_bw_bytes; + /* Make ddr bw same as mnoc bw */ + mux_axi_vote->axi_path[0].ddr_ab_bw = + bw_update->external_bw_bytes; + mux_axi_vote->axi_path[0].ddr_ib_bw = + bw_update->external_bw_bytes; + + top_common->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_INCLUDE; + break; + } + + if (mux_axi_vote->num_paths == 1) { + if (mux_axi_vote->axi_path[0].path_data_type == + CAM_AXI_PATH_DATA_IFE_VID) + vid_exists = true; + else if ((mux_axi_vote->axi_path[0].path_data_type >= + CAM_AXI_PATH_DATA_IFE_RDI0) && + (mux_axi_vote->axi_path[0].path_data_type <= + CAM_AXI_PATH_DATA_IFE_RDI3)) + rdi_exists = true; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_PERF, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, + false); + } + + return rc; +} + +int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bw_control_args *bw_ctrl = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int rc = 0; + int i; + + bw_ctrl = (struct cam_vfe_bw_control_args *)cmd_args; + res = bw_ctrl->node_res; + + if (!res || !res->hw_intf->hw_priv) + return -EINVAL; + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_ISP, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_common->num_mux; i++) { + if (top_common->mux_rsrc[i].res_id == res->res_id) { + top_common->axi_vote_control[i] = bw_ctrl->action; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_PERF, + "VFE:%d Not ready to set BW yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else { + rc = cam_vfe_top_set_axi_bw_vote(soc_private, top_common, true); + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h new file mode 100644 index 0000000000000000000000000000000000000000..03be713e606801c2681ea4d0eeb9983193030862 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_common.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_COMMON_H_ +#define _CAM_VFE_TOP_COMMON_H_ + +#define CAM_VFE_TOP_MUX_MAX 6 +#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 18 + +#include "cam_cpas_api.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" + +struct cam_vfe_top_priv_common { + struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_MUX_MAX]; + uint32_t num_mux; + uint32_t hw_idx; + struct cam_axi_vote applied_axi_vote; + struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_MUX_MAX]; + struct cam_axi_vote last_vote[ + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; + uint32_t last_counter; + uint64_t total_bw_applied; + enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_MUX_MAX]; +}; + +int cam_vfe_top_set_axi_bw_vote(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, bool start_stop); + +int cam_vfe_top_bw_update_v2(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size); + +int cam_vfe_top_bw_update(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size); + +int cam_vfe_top_bw_control(struct cam_vfe_soc_private *soc_private, + struct cam_vfe_top_priv_common *top_common, void *cmd_args, + uint32_t arg_size); + +#endif /* _CAM_VFE_TOP_COMMON_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c new file mode 100644 index 0000000000000000000000000000000000000000..c5225c5407224d538ee262172a02f57e58724b58 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -0,0 +1,730 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include "cam_io_util.h" +#include "cam_cdm_util.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_debug_util.h" +#include "cam_vfe_soc.h" + +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00003F9F +#define CAM_VFE_HW_RESET_HW_VAL 0x00003F87 + +struct cam_vfe_top_ver2_common_data { + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *hw_intf; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; +}; + +struct cam_vfe_top_ver2_priv { + struct cam_vfe_top_ver2_common_data common_data; + unsigned long hw_clk_rate; + unsigned long req_clk_rate[ + CAM_VFE_TOP_MUX_MAX]; + struct cam_vfe_top_priv_common top_common; +}; + +static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t mem_base = 0; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error! Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_ISP, "Error! Invalid args"); + return -EINVAL; + } + + cdm_util_ops = + (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE( + top_priv->common_data.soc_info, VFE_CORE_BASE_IDX); + CAM_DBG(CAM_ISP, "core %d mem_base 0x%x", + top_priv->common_data.soc_info->index, mem_base); + + cdm_util_ops->cdm_write_changebase( + cdm_args->cmd.cmd_buf_addr, mem_base); + cdm_args->cmd.used_bytes = (size * 4); + + return 0; +} + +static int cam_vfe_top_set_hw_clk_rate( + struct cam_vfe_top_ver2_priv *top_priv) +{ + struct cam_hw_soc_info *soc_info = NULL; + int i, rc = 0; + unsigned long max_clk_rate = 0; + + soc_info = top_priv->common_data.soc_info; + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->req_clk_rate[i] > max_clk_rate) + max_clk_rate = top_priv->req_clk_rate[i]; + } + if (max_clk_rate == top_priv->hw_clk_rate) + return 0; + + CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, max_clk_rate); + + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); + + if (!rc) + top_priv->hw_clk_rate = max_clk_rate; + else + CAM_ERR(CAM_PERF, "Set Clock rate failed, rc=%d", rc); + + return rc; +} + +static int cam_vfe_top_fs_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_fe_update_args *cmd_update = cmd_args; + + if (cmd_update->node_res->process_cmd) + return cmd_update->node_res->process_cmd(cmd_update->node_res, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, cmd_args, arg_size); + + return 0; +} + +static int cam_vfe_top_clock_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_clock_update_args *clk_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + clk_update = + (struct cam_vfe_clock_update_args *)cmd_args; + res = clk_update->node_res; + + if (!res || !res->hw_intf->hw_priv) { + CAM_ERR(CAM_PERF, "Invalid input res %pK", res); + return -EINVAL; + } + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_PERF, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == res->res_id) { + top_priv->req_clk_rate[i] = clk_update->clk_rate; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_DBG(CAM_PERF, + "VFE:%d Not ready to set clocks yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else + rc = cam_vfe_top_set_hw_clk_rate(top_priv); + + return rc; +} + +static int cam_vfe_top_mux_get_reg_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + return cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_REG_UPDATE, cmd_args, arg_size); + + return -EINVAL; +} + +int cam_vfe_top_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv = device_priv; + + top_priv->hw_clk_rate = 0; + + return 0; +} + +int cam_vfe_top_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_top_ver2_reg_offset_common *reg_common = NULL; + uint32_t *reset_reg_args = reset_core_args; + uint32_t reset_reg_val; + + if (!top_priv || !reset_reg_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + switch (*reset_reg_args) { + case CAM_VFE_HW_RESET_HW_AND_REG: + reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; + break; + default: + reset_reg_val = CAM_VFE_HW_RESET_HW_VAL; + break; + } + + CAM_DBG(CAM_ISP, "reset reg value: %x", reset_reg_val); + soc_info = top_priv->common_data.soc_info; + reg_common = top_priv->common_data.common_reg; + + /* Mask All the IRQs except RESET */ + cam_io_w_mb((1 << 31), + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + 0x5C); + + /* Reset HW */ + cam_io_w_mb(reset_reg_val, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + reg_common->global_reset_cmd); + + CAM_DBG(CAM_ISP, "Reset HW exit"); + return 0; +} + +int cam_vfe_top_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_vfe_acquire_args *args; + struct cam_vfe_hw_vfe_in_acquire_args *acquire_args; + uint32_t i; + int rc = -EINVAL; + + if (!device_priv || !reserve_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + args = (struct cam_vfe_acquire_args *)reserve_args; + acquire_args = &args->vfe_in; + + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + acquire_args->res_id && + top_priv->top_common.mux_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + rc = cam_vfe_camif_ver2_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id == + CAM_ISP_HW_VFE_IN_PDLIB) { + rc = cam_vfe_camif_lite_ver2_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + if ((acquire_args->res_id >= + CAM_ISP_HW_VFE_IN_RDI0) && + (acquire_args->res_id <= + CAM_ISP_HW_VFE_IN_RDI3)) { + rc = cam_vfe_rdi_ver2_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { + rc = cam_vfe_fe_ver1_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + top_priv->top_common.mux_rsrc[i].cdm_ops = + acquire_args->cdm_ops; + top_priv->top_common.mux_rsrc[i].tasklet_info = + args->tasklet; + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + acquire_args->rsrc_node = + &top_priv->top_common.mux_rsrc[i]; + + rc = 0; + break; + } + } + + return rc; + +} + +int cam_vfe_top_release(void *device_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_isp_resource_node *mux_res; + + if (!device_priv || !release_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)release_args; + + CAM_DBG(CAM_ISP, "Resource in state %d", mux_res->res_state); + if (mux_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Resource in Invalid res_state :%d", + mux_res->res_state); + return -EINVAL; + } + mux_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +int cam_vfe_top_start(void *device_priv, + void *start_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + int rc = 0; + + if (!device_priv || !start_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + mux_res = (struct cam_isp_resource_node *)start_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) { + rc = cam_vfe_top_set_hw_clk_rate(top_priv); + if (rc) { + CAM_ERR(CAM_ISP, + "set_hw_clk_rate failed, rc=%d", rc); + return rc; + } + + rc = cam_vfe_top_set_axi_bw_vote(soc_private, + &top_priv->top_common, true); + if (rc) { + CAM_ERR(CAM_ISP, + "set_axi_bw_vote failed, rc=%d", rc); + return rc; + } + + if (mux_res->start) { + rc = mux_res->start(mux_res); + } else { + CAM_ERR(CAM_ISP, + "Invalid res id:%d", mux_res->res_id); + rc = -EINVAL; + } + } else { + CAM_ERR(CAM_ISP, "VFE HW not powered up"); + rc = -EPERM; + } + + return rc; +} + +int cam_vfe_top_stop(void *device_priv, + void *stop_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + if (!device_priv || !stop_args) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)stop_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || + (mux_res->res_id == CAM_ISP_HW_VFE_IN_PDLIB) || + (mux_res->res_id == CAM_ISP_HW_VFE_IN_RD) || + ((mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && + (mux_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3))) { + rc = mux_res->stop(mux_res); + } else { + CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id); + return -EINVAL; + } + + if (!rc) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + mux_res->res_id) { + top_priv->req_clk_rate[i] = 0; + top_priv->req_clk_rate[i] = 0; + top_priv->top_common.req_axi_vote[i] + .axi_path[0].camnoc_bw = 0; + top_priv->top_common.req_axi_vote[i] + .axi_path[0].mnoc_ab_bw = 0; + top_priv->top_common.req_axi_vote[i] + .axi_path[0].mnoc_ib_bw = 0; + top_priv->top_common.axi_vote_control[i] = + CAM_VFE_BW_CONTROL_EXCLUDE; + break; + } + } + } + + return rc; +} + +int cam_vfe_top_read(void *device_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_write(void *device_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_vfe_top_ver2_priv *top_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + + if (!device_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Error! Invalid arguments"); + return -EINVAL; + } + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + rc = cam_vfe_top_mux_get_base(top_priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_top_mux_get_reg_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + rc = cam_vfe_top_clock_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_top_fs_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE: + rc = cam_vfe_top_bw_update(soc_private, &top_priv->top_common, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = cam_vfe_top_bw_update_v2(soc_private, + &top_priv->top_common, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common, + cmd_args, arg_size); + break; + default: + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Error! Invalid cmd:%d", cmd_type); + break; + } + + return rc; +} + +int cam_vfe_top_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top_ptr) +{ + int i, j, rc = 0; + struct cam_vfe_top_ver2_priv *top_priv = NULL; + struct cam_vfe_top_ver2_hw_info *ver2_hw_info = top_hw_info; + struct cam_vfe_top *vfe_top; + + vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL); + if (!vfe_top) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for vfe_top"); + rc = -ENOMEM; + goto end; + } + + top_priv = kzalloc(sizeof(struct cam_vfe_top_ver2_priv), + GFP_KERNEL); + if (!top_priv) { + CAM_DBG(CAM_ISP, "Error! Failed to alloc for vfe_top_priv"); + rc = -ENOMEM; + goto free_vfe_top; + } + + vfe_top->top_priv = top_priv; + top_priv->hw_clk_rate = 0; + if (ver2_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) { + CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d", + ver2_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX); + rc = -EINVAL; + goto free_top_priv; + } + + top_priv->top_common.num_mux = ver2_hw_info->num_mux; + + for (i = 0, j = 0; i < top_priv->top_common.num_mux; i++) { + top_priv->top_common.mux_rsrc[i].res_type = + CAM_ISP_RESOURCE_VFE_IN; + top_priv->top_common.mux_rsrc[i].hw_intf = hw_intf; + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + top_priv->req_clk_rate[i] = 0; + + if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_CAMIF; + + rc = cam_vfe_camif_ver2_init(hw_intf, soc_info, + &ver2_hw_info->camif_hw_info, + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_CAMIF_LITE_VER_2_0) { + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_PDLIB; + + rc = cam_vfe_camif_lite_ver2_init(hw_intf, soc_info, + &ver2_hw_info->camif_lite_hw_info, + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + + if (rc) + goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_RDI_VER_1_0) { + /* set the RDI resource id */ + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RDI0 + j++; + + rc = cam_vfe_rdi_ver2_init(hw_intf, soc_info, + &ver2_hw_info->rdi_hw_info, + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + /* set the RD resource id */ + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RD; + + rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, + &ver2_hw_info->fe_hw_info, + &top_priv->top_common.mux_rsrc[i]); + if (rc) + goto deinit_resources; + } else { + CAM_WARN(CAM_ISP, "Invalid mux type: %u", + ver2_hw_info->mux_type[i]); + } + } + + vfe_top->hw_ops.get_hw_caps = cam_vfe_top_get_hw_caps; + vfe_top->hw_ops.init = cam_vfe_top_init_hw; + vfe_top->hw_ops.reset = cam_vfe_top_reset; + vfe_top->hw_ops.reserve = cam_vfe_top_reserve; + vfe_top->hw_ops.release = cam_vfe_top_release; + vfe_top->hw_ops.start = cam_vfe_top_start; + vfe_top->hw_ops.stop = cam_vfe_top_stop; + vfe_top->hw_ops.read = cam_vfe_top_read; + vfe_top->hw_ops.write = cam_vfe_top_write; + vfe_top->hw_ops.process_cmd = cam_vfe_top_process_cmd; + *vfe_top_ptr = vfe_top; + + top_priv->common_data.soc_info = soc_info; + top_priv->common_data.hw_intf = hw_intf; + top_priv->top_common.hw_idx = hw_intf->hw_idx; + top_priv->common_data.common_reg = ver2_hw_info->common_reg; + + return rc; + +deinit_resources: + for (--i; i >= 0; i--) { + if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { + if (cam_vfe_camif_ver2_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif Deinit failed"); + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_CAMIF_LITE_VER_2_0) { + if (cam_vfe_camif_lite_ver2_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif lite deinit failed"); + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + if (cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, "VFE FE deinit failed"); + } else { + if (cam_vfe_rdi_ver2_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, "RDI Deinit failed"); + } + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + } + +free_top_priv: + kfree(vfe_top->top_priv); +free_vfe_top: + kfree(vfe_top); +end: + return rc; +} + +int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top_ptr) +{ + int i, rc = 0; + struct cam_vfe_top_ver2_priv *top_priv = NULL; + struct cam_vfe_top *vfe_top; + + if (!vfe_top_ptr) { + CAM_ERR(CAM_ISP, "Error! Invalid input"); + return -EINVAL; + } + + vfe_top = *vfe_top_ptr; + if (!vfe_top) { + CAM_ERR(CAM_ISP, "Error! vfe_top NULL"); + return -ENODEV; + } + + top_priv = vfe_top->top_priv; + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error! vfe_top_priv NULL"); + rc = -ENODEV; + goto free_vfe_top; + } + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + if (top_priv->top_common.mux_rsrc[i].res_type == + CAM_VFE_CAMIF_VER_2_0) { + rc = cam_vfe_camif_ver2_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else if (top_priv->top_common.mux_rsrc[i].res_type == + CAM_VFE_CAMIF_LITE_VER_2_0) { + rc = cam_vfe_camif_lite_ver2_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, + "Camif lite deinit failed rc=%d", rc); + } else if (top_priv->top_common.mux_rsrc[i].res_type == + CAM_VFE_RDI_VER_1_0) { + rc = cam_vfe_rdi_ver2_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "RDI deinit failed rc=%d", rc); + } else if (top_priv->top_common.mux_rsrc[i].res_type == + CAM_VFE_IN_RD_VER_1_0) { + rc = cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } + } + + kfree(vfe_top->top_priv); + +free_vfe_top: + kfree(vfe_top); + *vfe_top_ptr = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h new file mode 100644 index 0000000000000000000000000000000000000000..961bf954aaa17081e76f79a1e4828022fec8a67d --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_VER2_H_ +#define _CAM_VFE_TOP_VER2_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_rdi.h" +#include "cam_vfe_fe_ver1.h" +#include "cam_vfe_top_common.h" + +enum cam_vfe_top_ver2_module_type { + CAM_VFE_TOP_VER2_MODULE_LENS, + CAM_VFE_TOP_VER2_MODULE_STATS, + CAM_VFE_TOP_VER2_MODULE_COLOR, + CAM_VFE_TOP_VER2_MODULE_ZOOM, + CAM_VFE_TOP_VER2_MODULE_MAX, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl { + uint32_t reset; + uint32_t cgc_ovd; + uint32_t enable; +}; + +struct cam_vfe_top_ver2_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t lens_feature; + uint32_t stats_feature; + uint32_t color_feature; + uint32_t zoom_feature; + uint32_t global_reset_cmd; + struct cam_vfe_top_ver2_reg_offset_module_ctrl + *module_ctrl[CAM_VFE_TOP_VER2_MODULE_MAX]; + uint32_t bus_cgc_ovd; + uint32_t core_cfg; + uint32_t three_D_cfg; + uint32_t violation_status; + uint32_t reg_update_cmd; +}; + +struct cam_vfe_top_ver2_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_camif_ver2_hw_info camif_hw_info; + struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; + struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; + struct cam_vfe_fe_ver1_hw_info fe_hw_info; + uint32_t num_mux; + uint32_t mux_type[CAM_VFE_TOP_MUX_MAX]; +}; + +int cam_vfe_top_ver2_init(struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top_ptr); + +int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_VER2_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c new file mode 100644 index 0000000000000000000000000000000000000000..2bd393fc97a8b69d031ad59004f77f96e90034d5 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.c @@ -0,0 +1,796 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include "cam_io_util.h" +#include "cam_cdm_util.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver3.h" +#include "cam_debug_util.h" +#include "cam_vfe_soc.h" + +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00000003 +#define CAM_VFE_HW_RESET_HW_VAL 0x007F0000 +#define CAM_VFE_LITE_HW_RESET_AND_REG_VAL 0x00000002 +#define CAM_VFE_LITE_HW_RESET_HW_VAL 0x0000003D + +struct cam_vfe_top_ver3_common_data { + struct cam_hw_soc_info *soc_info; + struct cam_hw_intf *hw_intf; + struct cam_vfe_top_ver3_reg_offset_common *common_reg; +}; + +struct cam_vfe_top_ver3_priv { + struct cam_vfe_top_ver3_common_data common_data; + unsigned long hw_clk_rate; + unsigned long req_clk_rate[ + CAM_VFE_TOP_MUX_MAX]; + struct cam_vfe_top_priv_common top_common; +}; + +static int cam_vfe_top_ver3_mux_get_base(struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t mem_base = 0; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Error, Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res || !top_priv || + !top_priv->common_data.soc_info) { + CAM_ERR(CAM_ISP, "Error, Invalid args"); + return -EINVAL; + } + + cdm_util_ops = + (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + size = cdm_util_ops->cdm_required_size_changebase(); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE( + top_priv->common_data.soc_info, VFE_CORE_BASE_IDX); + CAM_DBG(CAM_ISP, "core %d mem_base 0x%x", + top_priv->common_data.soc_info->index, mem_base); + + cdm_util_ops->cdm_write_changebase( + cdm_args->cmd.cmd_buf_addr, mem_base); + cdm_args->cmd.used_bytes = (size * 4); + + return 0; +} + +static int cam_vfe_top_ver3_set_hw_clk_rate( + struct cam_vfe_top_ver3_priv *top_priv) +{ + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct cam_ahb_vote ahb_vote; + int i, rc = 0, clk_lvl = -1; + unsigned long max_clk_rate = 0; + + soc_info = top_priv->common_data.soc_info; + soc_private = + (struct cam_vfe_soc_private *)soc_info->soc_private; + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->req_clk_rate[i] > max_clk_rate) + max_clk_rate = top_priv->req_clk_rate[i]; + } + if (max_clk_rate == top_priv->hw_clk_rate) + return 0; + + CAM_DBG(CAM_PERF, "VFE: Clock name=%s idx=%d clk=%llu", + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, max_clk_rate); + + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); + + if (!rc) { + top_priv->hw_clk_rate = max_clk_rate; + rc = cam_soc_util_get_clk_level(soc_info, max_clk_rate, + soc_info->src_clk_idx, &clk_lvl); + if (rc) { + CAM_WARN(CAM_ISP, + "Failed to get clk level for %s with clk_rate %llu src_idx %d rc %d", + soc_info->dev_name, max_clk_rate, + soc_info->src_clk_idx, rc); + rc = 0; + goto end; + } + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = clk_lvl; + cam_cpas_update_ahb_vote(soc_private->cpas_handle, &ahb_vote); + } else { + CAM_ERR(CAM_PERF, "Set Clock rate failed, rc=%d", rc); + } + +end: + return rc; +} + +static int cam_vfe_top_fs_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_fe_update_args *cmd_update = cmd_args; + + if (cmd_update->node_res->process_cmd) + return cmd_update->node_res->process_cmd(cmd_update->node_res, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, cmd_args, arg_size); + + return 0; +} + +static int cam_vfe_top_ver3_clock_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_clock_update_args *clk_update = NULL; + struct cam_isp_resource_node *res = NULL; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + clk_update = + (struct cam_vfe_clock_update_args *)cmd_args; + res = clk_update->node_res; + + if (!res || !res->hw_intf->hw_priv) { + CAM_ERR(CAM_PERF, "Invalid input res %pK", res); + return -EINVAL; + } + + hw_info = res->hw_intf->hw_priv; + + if (res->res_type != CAM_ISP_RESOURCE_VFE_IN || + res->res_id >= CAM_ISP_HW_VFE_IN_MAX) { + CAM_ERR(CAM_PERF, "VFE:%d Invalid res_type:%d res id%d", + res->hw_intf->hw_idx, res->res_type, + res->res_id); + return -EINVAL; + } + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == res->res_id) { + top_priv->req_clk_rate[i] = clk_update->clk_rate; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_DBG(CAM_PERF, + "VFE:%d Not ready to set clocks yet :%d", + res->hw_intf->hw_idx, + hw_info->hw_state); + } else + rc = cam_vfe_top_ver3_set_hw_clk_rate(top_priv); + + return rc; +} + +static int cam_vfe_core_config_control( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_core_config_args *core_config = cmd_args; + + if (core_config->node_res->process_cmd) + return core_config->node_res->process_cmd(core_config->node_res, + CAM_ISP_HW_CMD_CORE_CONFIG, cmd_args, arg_size); + + return -EINVAL; +} + +static int cam_vfe_top_ver3_mux_get_reg_update( + struct cam_vfe_top_ver3_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_isp_hw_get_cmd_update *cmd_update = cmd_args; + + if (cmd_update->res->process_cmd) + return cmd_update->res->process_cmd(cmd_update->res, + CAM_ISP_HW_CMD_GET_REG_UPDATE, cmd_args, arg_size); + + return -EINVAL; +} + +int cam_vfe_top_ver3_get_hw_caps(void *device_priv, + void *get_hw_cap_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_ver3_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv = device_priv; + struct cam_vfe_top_ver3_common_data common_data = top_priv->common_data; + + top_priv->hw_clk_rate = 0; + + /* Disable clock gating at IFE top */ + CAM_INFO(CAM_ISP, "Disable clock gating at IFE top"); + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->core_cgc_ovd_0, 0xFFFFFFFF); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->core_cgc_ovd_1, 0xFF); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->ahb_cgc_ovd, 0x1); + + cam_soc_util_w_mb(common_data.soc_info, VFE_CORE_BASE_IDX, + common_data.common_reg->noc_cgc_ovd, 0x1); + + return 0; +} + +int cam_vfe_top_ver3_reset(void *device_priv, + void *reset_core_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + struct cam_vfe_top_ver3_reg_offset_common *reg_common = NULL; + uint32_t *reset_reg_args = reset_core_args; + uint32_t reset_reg_val; + + if (!top_priv || !reset_reg_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + soc_info = top_priv->common_data.soc_info; + reg_common = top_priv->common_data.common_reg; + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Invalid soc_private"); + return -ENODEV; + } + + switch (*reset_reg_args) { + case CAM_VFE_HW_RESET_HW_AND_REG: + if (!soc_private->is_ife_lite) + reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; + else + reset_reg_val = CAM_VFE_LITE_HW_RESET_AND_REG_VAL; + break; + default: + if (!soc_private->is_ife_lite) + reset_reg_val = CAM_VFE_HW_RESET_HW_VAL; + else + reset_reg_val = CAM_VFE_LITE_HW_RESET_HW_VAL; + break; + } + /* override due to hw limitation */ + if (!soc_private->is_ife_lite) + reset_reg_val = CAM_VFE_HW_RESET_HW_AND_REG_VAL; + else + reset_reg_val = CAM_VFE_LITE_HW_RESET_AND_REG_VAL; + + CAM_DBG(CAM_ISP, "reset reg value: 0x%x", reset_reg_val); + + /* Mask All the IRQs except RESET */ + if (!soc_private->is_ife_lite) + cam_io_w_mb(0x00000001, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + 0x3C); + else + cam_io_w_mb(0x00020000, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + 0x28); + + /* Reset HW */ + cam_io_w_mb(reset_reg_val, + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX) + + reg_common->global_reset_cmd); + + CAM_DBG(CAM_ISP, "Reset HW exit"); + return 0; +} + +int cam_vfe_top_ver3_reserve(void *device_priv, + void *reserve_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_vfe_acquire_args *args; + struct cam_vfe_hw_vfe_in_acquire_args *acquire_args; + uint32_t i; + int rc = -EINVAL; + + if (!device_priv || !reserve_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + args = (struct cam_vfe_acquire_args *)reserve_args; + acquire_args = &args->vfe_in; + + CAM_DBG(CAM_ISP, "res id %d", acquire_args->res_id); + + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + acquire_args->res_id && + top_priv->top_common.mux_rsrc[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + rc = cam_vfe_camif_ver3_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id >= CAM_ISP_HW_VFE_IN_RDI0 && + acquire_args->res_id < CAM_ISP_HW_VFE_IN_MAX) { + rc = cam_vfe_camif_lite_ver3_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { + rc = cam_vfe_fe_ver1_acquire_resource( + &top_priv->top_common.mux_rsrc[i], + args); + if (rc) + break; + } + + top_priv->top_common.mux_rsrc[i].cdm_ops = + acquire_args->cdm_ops; + top_priv->top_common.mux_rsrc[i].tasklet_info = + args->tasklet; + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + acquire_args->rsrc_node = + &top_priv->top_common.mux_rsrc[i]; + + rc = 0; + break; + } + } + + return rc; + +} + +int cam_vfe_top_ver3_release(void *device_priv, + void *release_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_isp_resource_node *mux_res; + + if (!device_priv || !release_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)release_args; + + CAM_DBG(CAM_ISP, "Resource in state %d", mux_res->res_state); + if (mux_res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error, Resource in Invalid res_state :%d", + mux_res->res_state); + return -EINVAL; + } + mux_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +int cam_vfe_top_ver3_start(void *device_priv, + void *start_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + int rc = 0; + + if (!device_priv || !start_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + mux_res = (struct cam_isp_resource_node *)start_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if (hw_info->hw_state == CAM_HW_STATE_POWER_UP) { + rc = cam_vfe_top_ver3_set_hw_clk_rate(top_priv); + if (rc) { + CAM_ERR(CAM_ISP, + "set_hw_clk_rate failed, rc=%d", rc); + return rc; + } + + rc = cam_vfe_top_set_axi_bw_vote(soc_private, + &top_priv->top_common, true); + if (rc) { + CAM_ERR(CAM_ISP, + "set_axi_bw_vote failed, rc=%d", rc); + return rc; + } + + if (mux_res->start) { + rc = mux_res->start(mux_res); + } else { + CAM_ERR(CAM_ISP, + "Invalid res id:%d", mux_res->res_id); + rc = -EINVAL; + } + } else { + CAM_ERR(CAM_ISP, "VFE HW not powered up"); + rc = -EPERM; + } + + return rc; +} + +int cam_vfe_top_ver3_stop(void *device_priv, + void *stop_args, uint32_t arg_size) +{ + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_isp_resource_node *mux_res; + struct cam_hw_info *hw_info = NULL; + int i, rc = 0; + + if (!device_priv || !stop_args) { + CAM_ERR(CAM_ISP, "Error, Invalid input arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + mux_res = (struct cam_isp_resource_node *)stop_args; + hw_info = (struct cam_hw_info *)mux_res->hw_intf->hw_priv; + + if (mux_res->res_id < CAM_ISP_HW_VFE_IN_MAX) { + rc = mux_res->stop(mux_res); + } else { + CAM_ERR(CAM_ISP, "Invalid res id:%d", mux_res->res_id); + return -EINVAL; + } + + if (!rc) { + for (i = 0; i < top_priv->top_common.num_mux; i++) { + if (top_priv->top_common.mux_rsrc[i].res_id == + mux_res->res_id) { + top_priv->req_clk_rate[i] = 0; + memset(&top_priv->top_common.req_axi_vote[i], + 0, sizeof(struct cam_axi_vote)); + top_priv->top_common.axi_vote_control[i] = + CAM_VFE_BW_CONTROL_EXCLUDE; + break; + } + } + } + + return rc; +} + +int cam_vfe_top_ver3_read(void *device_priv, + void *read_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_ver3_write(void *device_priv, + void *write_args, uint32_t arg_size) +{ + return -EPERM; +} + +int cam_vfe_top_ver3_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + int rc = 0; + struct cam_vfe_top_ver3_priv *top_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_vfe_soc_private *soc_private = NULL; + + if (!device_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Error, Invalid arguments"); + return -EINVAL; + } + + top_priv = (struct cam_vfe_top_ver3_priv *)device_priv; + soc_info = top_priv->common_data.soc_info; + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_CHANGE_BASE: + rc = cam_vfe_top_ver3_mux_get_base(top_priv, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_top_ver3_mux_get_reg_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_CLOCK_UPDATE: + rc = cam_vfe_top_ver3_clock_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_top_fs_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE: + rc = cam_vfe_top_bw_update(soc_private, &top_priv->top_common, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_BW_UPDATE_V2: + rc = cam_vfe_top_bw_update_v2(soc_private, + &top_priv->top_common, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + rc = cam_vfe_top_bw_control(soc_private, &top_priv->top_common, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_CORE_CONFIG: + rc = cam_vfe_core_config_control(top_priv, cmd_args, arg_size); + break; + default: + rc = -EINVAL; + CAM_ERR(CAM_ISP, "Error, Invalid cmd:%d", cmd_type); + break; + } + + return rc; +} + +int cam_vfe_top_ver3_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top_ptr) +{ + int i, j, rc = 0; + struct cam_vfe_top_ver3_priv *top_priv = NULL; + struct cam_vfe_top_ver3_hw_info *ver3_hw_info = top_hw_info; + struct cam_vfe_top *vfe_top; + + vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL); + if (!vfe_top) { + CAM_DBG(CAM_ISP, "Error, Failed to alloc for vfe_top"); + rc = -ENOMEM; + goto end; + } + + top_priv = kzalloc(sizeof(struct cam_vfe_top_ver3_priv), + GFP_KERNEL); + if (!top_priv) { + CAM_DBG(CAM_ISP, "Error, Failed to alloc for vfe_top_priv"); + rc = -ENOMEM; + goto free_vfe_top; + } + + vfe_top->top_priv = top_priv; + top_priv->hw_clk_rate = 0; + if (ver3_hw_info->num_mux > CAM_VFE_TOP_MUX_MAX) { + CAM_ERR(CAM_ISP, "Invalid number of input rsrc: %d, max: %d", + ver3_hw_info->num_mux, CAM_VFE_TOP_MUX_MAX); + rc = -EINVAL; + goto free_top_priv; + } + + top_priv->top_common.num_mux = ver3_hw_info->num_mux; + + for (i = 0, j = 0; i < top_priv->top_common.num_mux && + j < CAM_VFE_RDI_VER2_MAX; i++) { + top_priv->top_common.mux_rsrc[i].res_type = + CAM_ISP_RESOURCE_VFE_IN; + top_priv->top_common.mux_rsrc[i].hw_intf = hw_intf; + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + top_priv->req_clk_rate[i] = 0; + + if (ver3_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_3_0) { + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_CAMIF; + + rc = cam_vfe_camif_ver3_init(hw_intf, soc_info, + &ver3_hw_info->camif_hw_info, + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_PDLIB_VER_1_0) { + /* set the PDLIB resource id */ + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_PDLIB; + + rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, + &ver3_hw_info->pdlib_hw_info, + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + /* set the RD resource id */ + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RD; + + rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, + &ver3_hw_info->fe_hw_info, + &top_priv->top_common.mux_rsrc[i]); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_RDI_VER_1_0) { + /* set the RDI resource id */ + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RDI0 + j; + + rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, + ver3_hw_info->rdi_hw_info[j++], + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + if (rc) + goto deinit_resources; + } else if (ver3_hw_info->mux_type[i] == + CAM_VFE_LCR_VER_1_0) { + /* set the LCR resource id */ + top_priv->top_common.mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_LCR; + + rc = cam_vfe_camif_lite_ver3_init(hw_intf, soc_info, + &ver3_hw_info->lcr_hw_info, + &top_priv->top_common.mux_rsrc[i], + vfe_irq_controller); + if (rc) + goto deinit_resources; + } else { + CAM_WARN(CAM_ISP, "Invalid mux type: %u", + ver3_hw_info->mux_type[i]); + } + } + + vfe_top->hw_ops.get_hw_caps = cam_vfe_top_ver3_get_hw_caps; + vfe_top->hw_ops.init = cam_vfe_top_ver3_init_hw; + vfe_top->hw_ops.reset = cam_vfe_top_ver3_reset; + vfe_top->hw_ops.reserve = cam_vfe_top_ver3_reserve; + vfe_top->hw_ops.release = cam_vfe_top_ver3_release; + vfe_top->hw_ops.start = cam_vfe_top_ver3_start; + vfe_top->hw_ops.stop = cam_vfe_top_ver3_stop; + vfe_top->hw_ops.read = cam_vfe_top_ver3_read; + vfe_top->hw_ops.write = cam_vfe_top_ver3_write; + vfe_top->hw_ops.process_cmd = cam_vfe_top_ver3_process_cmd; + *vfe_top_ptr = vfe_top; + + top_priv->common_data.soc_info = soc_info; + top_priv->common_data.hw_intf = hw_intf; + top_priv->top_common.hw_idx = hw_intf->hw_idx; + top_priv->common_data.common_reg = ver3_hw_info->common_reg; + + return rc; + +deinit_resources: + for (--i; i >= 0; i--) { + if (ver3_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_3_0) { + if (cam_vfe_camif_ver3_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif Deinit failed"); + } else if (ver3_hw_info->mux_type[i] == CAM_VFE_IN_RD_VER_1_0) { + if (cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif fe Deinit failed"); + } else { + if (cam_vfe_camif_lite_ver3_deinit( + &top_priv->top_common.mux_rsrc[i])) + CAM_ERR(CAM_ISP, + "Camif lite res id %d Deinit failed", + top_priv->top_common.mux_rsrc[i] + .res_id); + } + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + } + +free_top_priv: + kfree(vfe_top->top_priv); +free_vfe_top: + kfree(vfe_top); +end: + return rc; +} + +int cam_vfe_top_ver3_deinit(struct cam_vfe_top **vfe_top_ptr) +{ + int i, rc = 0; + struct cam_vfe_top_ver3_priv *top_priv = NULL; + struct cam_vfe_top *vfe_top; + + if (!vfe_top_ptr) { + CAM_ERR(CAM_ISP, "Error, Invalid input"); + return -EINVAL; + } + + vfe_top = *vfe_top_ptr; + if (!vfe_top) { + CAM_ERR(CAM_ISP, "Error, vfe_top NULL"); + return -ENODEV; + } + + top_priv = vfe_top->top_priv; + if (!top_priv) { + CAM_ERR(CAM_ISP, "Error, vfe_top_priv NULL"); + rc = -ENODEV; + goto free_vfe_top; + } + + for (i = 0; i < top_priv->top_common.num_mux; i++) { + top_priv->top_common.mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + if (top_priv->top_common.mux_rsrc[i].res_type == + CAM_VFE_CAMIF_VER_3_0) { + rc = cam_vfe_camif_ver3_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else if (top_priv->top_common.mux_rsrc[i].res_type == + CAM_VFE_IN_RD_VER_1_0) { + rc = cam_vfe_fe_ver1_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else { + rc = cam_vfe_camif_lite_ver3_deinit( + &top_priv->top_common.mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, + "Camif lite res id %d Deinit failed", + top_priv->top_common.mux_rsrc[i] + .res_id); + } + } + + kfree(vfe_top->top_priv); + +free_vfe_top: + kfree(vfe_top); + *vfe_top_ptr = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h new file mode 100644 index 0000000000000000000000000000000000000000..14c96097cdf6d59bbd1fe556ca8a054a3c81b776 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver3.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_VER3_H_ +#define _CAM_VFE_TOP_VER3_H_ + +#include "cam_vfe_camif_ver3.h" +#include "cam_vfe_camif_lite_ver3.h" +#include "cam_vfe_fe_ver1.h" +#include "cam_vfe_top_common.h" + +#define CAM_SHIFT_TOP_CORE_CFG_MUXSEL_PDAF 31 +#define CAM_SHIFT_TOP_CORE_CFG_VID_DS16_R2PD 30 +#define CAM_SHIFT_TOP_CORE_CFG_VID_DS4_R2PD 29 +#define CAM_SHIFT_TOP_CORE_CFG_DISP_DS16_R2PD 28 +#define CAM_SHIFT_TOP_CORE_CFG_DISP_DS4_R2PD 27 +#define CAM_SHIFT_TOP_CORE_CFG_DSP_STREAMING 25 +#define CAM_SHIFT_TOP_CORE_CFG_STATS_IHIST 10 +#define CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BE 9 +#define CAM_SHIFT_TOP_CORE_CFG_STATS_HDR_BHIST 8 +#define CAM_SHIFT_TOP_CORE_CFG_INPUTMUX_PP 5 + +struct cam_vfe_top_ver3_reg_offset_common { + uint32_t hw_version; + uint32_t titan_version; + uint32_t hw_capability; + uint32_t lens_feature; + uint32_t stats_feature; + uint32_t color_feature; + uint32_t zoom_feature; + uint32_t global_reset_cmd; + uint32_t core_cgc_ovd_0; + uint32_t core_cgc_ovd_1; + uint32_t ahb_cgc_ovd; + uint32_t noc_cgc_ovd; + uint32_t bus_cgc_ovd; + uint32_t core_cfg_0; + uint32_t core_cfg_1; + uint32_t reg_update_cmd; + uint32_t trigger_cdm_events; + uint32_t violation_status; + uint32_t sbi_frame_idx; + uint32_t dsp_status; + uint32_t diag_config; + uint32_t diag_sensor_status_0; + uint32_t diag_sensor_status_1; + uint32_t bus_overflow_status; + uint32_t top_debug_cfg; + uint32_t top_debug_0; + uint32_t top_debug_1; + uint32_t top_debug_2; + uint32_t top_debug_3; + uint32_t top_debug_4; + uint32_t top_debug_5; + uint32_t top_debug_6; + uint32_t top_debug_7; + uint32_t top_debug_8; + uint32_t top_debug_9; + uint32_t top_debug_10; + uint32_t top_debug_11; + uint32_t top_debug_12; + uint32_t top_debug_13; +}; + +struct cam_vfe_camif_common_cfg { + uint32_t vid_ds16_r2pd; + uint32_t vid_ds4_r2pd; + uint32_t disp_ds16_r2pd; + uint32_t disp_ds4_r2pd; + uint32_t dsp_streaming_tap_point; + uint32_t ihist_src_sel; + uint32_t hdr_be_src_sel; + uint32_t hdr_bhist_src_sel; + uint32_t input_mux_sel_pdaf; + uint32_t input_mux_sel_pp; +}; + +struct cam_vfe_top_ver3_hw_info { + struct cam_vfe_top_ver3_reg_offset_common *common_reg; + struct cam_vfe_camif_ver3_hw_info camif_hw_info; + struct cam_vfe_camif_lite_ver3_hw_info pdlib_hw_info; + struct cam_vfe_camif_lite_ver3_hw_info + *rdi_hw_info[CAM_VFE_RDI_VER2_MAX]; + struct cam_vfe_camif_lite_ver3_hw_info lcr_hw_info; + struct cam_vfe_fe_ver1_hw_info fe_hw_info; + uint32_t num_mux; + uint32_t mux_type[CAM_VFE_TOP_MUX_MAX]; +}; + +int cam_vfe_top_ver3_init(struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top); + +int cam_vfe_top_ver3_deinit(struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_VER3_H_ */ diff --git a/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h new file mode 100644 index 0000000000000000000000000000000000000000..932cab858a7094a0b094d9bd43e45fa95f904657 --- /dev/null +++ b/techpack/camera/drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_VFE_TOP_H_ +#define _CAM_VFE_TOP_H_ + +#include "cam_hw_intf.h" +#include "cam_isp_hw.h" + +#define CAM_VFE_TOP_VER_1_0 0x100000 +#define CAM_VFE_TOP_VER_2_0 0x200000 +#define CAM_VFE_TOP_VER_3_0 0x300000 + +#define CAM_VFE_CAMIF_VER_1_0 0x10 +#define CAM_VFE_CAMIF_VER_2_0 0x20 +#define CAM_VFE_CAMIF_VER_3_0 0x30 + +#define CAM_VFE_CAMIF_LITE_VER_2_0 0x02 + +#define CAM_VFE_RDI_VER_1_0 0x1000 +#define CAM_VFE_IN_RD_VER_1_0 0x2000 + +#define CAM_VFE_LCR_VER_1_0 0x100 +#define CAM_VFE_PDLIB_VER_1_0 0x10000 + +/* + * Debug values for camif module + */ +#define CAMIF_DEBUG_ENABLE_SENSOR_DIAG_STATUS BIT(0) +#define CAMIF_DEBUG_ENABLE_REG_DUMP BIT(1) +#define CAM_VFE_CAMIF_EVT_MAX 256 + +struct cam_vfe_top { + void *top_priv; + struct cam_hw_ops hw_ops; +}; + +int cam_vfe_top_init(uint32_t top_version, + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + void *vfe_irq_controller, + struct cam_vfe_top **vfe_top); + +int cam_vfe_top_deinit(uint32_t top_version, + struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_H_*/ diff --git a/techpack/camera/drivers/cam_jpeg/Makefile b/techpack/camera/drivers/cam_jpeg/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..471f870e4c739db473b64202e979784a4b63dbe3 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg_dev.o cam_jpeg_context.o diff --git a/techpack/camera/drivers/cam_jpeg/cam_jpeg_context.c b/techpack/camera/drivers/cam_jpeg/cam_jpeg_context.c new file mode 100644 index 0000000000000000000000000000000000000000..b16a9dfed0115d8c19f1ce64b73446f26d1f4b50 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/cam_jpeg_context.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +#include "cam_mem_mgr.h" +#include "cam_jpeg_context.h" +#include "cam_context_utils.h" +#include "cam_debug_util.h" +#include "cam_packet_util.h" + +static const char jpeg_dev_name[] = "cam-jpeg"; + +static int cam_jpeg_context_dump_active_request(void *data, unsigned long iova, + uint32_t buf_info) +{ + + struct cam_context *ctx = (struct cam_context *)data; + struct cam_ctx_request *req = NULL; + struct cam_ctx_request *req_temp = NULL; + struct cam_hw_mgr_dump_pf_data *pf_dbg_entry = NULL; + int rc = 0; + int closest_port; + bool b_mem_found = false; + + + if (!ctx) { + CAM_ERR(CAM_JPEG, "Invalid ctx"); + return -EINVAL; + } + + CAM_INFO(CAM_JPEG, "iommu fault for jpeg ctx %d state %d", + ctx->ctx_id, ctx->state); + + list_for_each_entry_safe(req, req_temp, + &ctx->active_req_list, list) { + pf_dbg_entry = &(req->pf_data); + closest_port = -1; + CAM_INFO(CAM_JPEG, "req_id : %lld ", req->request_id); + + rc = cam_context_dump_pf_info_to_hw(ctx, pf_dbg_entry->packet, + iova, buf_info, &b_mem_found); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to dump pf info"); + + if (b_mem_found) + CAM_ERR(CAM_JPEG, "Found page fault in req %lld %d", + req->request_id, rc); + } + return rc; +} + +static int __cam_jpeg_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_JPEG, "Unable to Acquire device %d", rc); + else + ctx->state = CAM_CTX_ACQUIRED; + + return rc; +} + +static int __cam_jpeg_ctx_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_JPEG, "Unable to release device %d", rc); + + ctx->state = CAM_CTX_AVAILABLE; + + return rc; +} + +static int __cam_jpeg_ctx_flush_dev_in_acquired(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_ICP, "Failed to flush device"); + + return rc; +} + +static int __cam_jpeg_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + return cam_context_prepare_dev_to_hw(ctx, cmd); +} + +static int __cam_jpeg_ctx_handle_buf_done_in_acquired(void *ctx, + uint32_t evt_id, void *done) +{ + return cam_context_buf_done_from_hw(ctx, done, evt_id); +} + +static int __cam_jpeg_ctx_stop_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc; + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed in Stop dev, rc=%d", rc); + return rc; + } + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = { }, + .crm_ops = { }, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_jpeg_ctx_acquire_dev_in_available, + }, + .crm_ops = { }, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .release_dev = __cam_jpeg_ctx_release_dev_in_acquired, + .config_dev = __cam_jpeg_ctx_config_dev_in_acquired, + .stop_dev = __cam_jpeg_ctx_stop_dev_in_acquired, + .flush_dev = __cam_jpeg_ctx_flush_dev_in_acquired, + }, + .crm_ops = { }, + .irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired, + .pagefault_ops = cam_jpeg_context_dump_active_request, + }, +}; + +int cam_jpeg_context_init(struct cam_jpeg_context *ctx, + struct cam_context *ctx_base, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id) +{ + int rc; + int i; + + if (!ctx || !ctx_base) { + CAM_ERR(CAM_JPEG, "Invalid Context"); + rc = -EFAULT; + goto err; + } + + memset(ctx, 0, sizeof(*ctx)); + + ctx->base = ctx_base; + + for (i = 0; i < CAM_CTX_REQ_MAX; i++) + ctx->req_base[i].req_priv = ctx; + + rc = cam_context_init(ctx_base, jpeg_dev_name, CAM_JPEG, ctx_id, + NULL, hw_intf, ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_JPEG, "Camera Context Base init failed"); + goto err; + } + + ctx_base->state_machine = cam_jpeg_ctx_state_machine; + ctx_base->ctx_priv = ctx; + +err: + return rc; +} + +int cam_jpeg_context_deinit(struct cam_jpeg_context *ctx) +{ + if (!ctx || !ctx->base) { + CAM_ERR(CAM_JPEG, "Invalid params: %pK", ctx); + return -EINVAL; + } + + cam_context_deinit(ctx->base); + + memset(ctx, 0, sizeof(*ctx)); + + return 0; +} diff --git a/techpack/camera/drivers/cam_jpeg/cam_jpeg_context.h b/techpack/camera/drivers/cam_jpeg/cam_jpeg_context.h new file mode 100644 index 0000000000000000000000000000000000000000..3a11865a605139b204e42a09c7e188eacbac1b10 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/cam_jpeg_context.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_CONTEXT_H_ +#define _CAM_JPEG_CONTEXT_H_ + +#include <media/cam_jpeg.h> + +#include "cam_context.h" +#include "cam_jpeg_hw_mgr_intf.h" + +#define CAM_JPEG_HW_EVENT_MAX 20 + +/** + * struct cam_jpeg_context - Jpeg context + * @base: Base jpeg cam context object + * @req_base: Common request structure + */ +struct cam_jpeg_context { + struct cam_context *base; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; +}; + +/* cam jpeg context irq handling function type */ +typedef int (*cam_jpeg_hw_event_cb_func)( + struct cam_jpeg_context *ctx_jpeg, + void *evt_data); + +/** + * struct cam_jpeg_ctx_irq_ops - Function table for handling IRQ callbacks + * + * @irq_ops: Array of handle function pointers. + * + */ +struct cam_jpeg_ctx_irq_ops { + cam_jpeg_hw_event_cb_func irq_ops[CAM_JPEG_HW_EVENT_MAX]; +}; + +/** + * cam_jpeg_context_init() + * + * @brief: Initialization function for the JPEG context + * + * @ctx: JPEG context obj to be initialized + * @ctx_base: Context base from cam_context + * @hw_intf: JPEG hw manager interface + * @ctx_id: ID for this context + * + */ +int cam_jpeg_context_init(struct cam_jpeg_context *ctx, + struct cam_context *ctx_base, + struct cam_hw_mgr_intf *hw_intf, + uint32_t ctx_id); + +/** + * cam_jpeg_context_deinit() + * + * @brief: Deinitialize function for the JPEG context + * + * @ctx: JPEG context obj to be deinitialized + * + */ +int cam_jpeg_context_deinit(struct cam_jpeg_context *ctx); + +#endif /* __CAM_JPEG_CONTEXT_H__ */ diff --git a/techpack/camera/drivers/cam_jpeg/cam_jpeg_dev.c b/techpack/camera/drivers/cam_jpeg/cam_jpeg_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..0a68ce99728378156b9389cba66dacf9aedcc439 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/cam_jpeg_dev.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_node.h" +#include "cam_hw_mgr_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_jpeg_dev.h" +#include "cam_debug_util.h" +#include "cam_smmu_api.h" + +#define CAM_JPEG_DEV_NAME "cam-jpeg" + +static struct cam_jpeg_dev g_jpeg_dev; + +static void cam_jpeg_dev_iommu_fault_handler( + struct iommu_domain *domain, struct device *dev, unsigned long iova, + int flags, void *token, uint32_t buf_info) +{ + int i = 0; + struct cam_node *node = NULL; + + if (!token) { + CAM_ERR(CAM_JPEG, "invalid token in page handler cb"); + return; + } + + node = (struct cam_node *)token; + + for (i = 0; i < node->ctx_size; i++) + cam_context_dump_pf_info(&(node->ctx_list[i]), iova, + buf_info); +} + +static const struct of_device_id cam_jpeg_dt_match[] = { + { + .compatible = "qcom,cam-jpeg" + }, + { } +}; + +static int cam_jpeg_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + + mutex_lock(&g_jpeg_dev.jpeg_mutex); + g_jpeg_dev.open_cnt++; + mutex_unlock(&g_jpeg_dev.jpeg_mutex); + + return 0; +} + +static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_node *node = v4l2_get_subdevdata(sd); + + + mutex_lock(&g_jpeg_dev.jpeg_mutex); + if (g_jpeg_dev.open_cnt <= 0) { + CAM_DBG(CAM_JPEG, "JPEG subdev is already closed"); + rc = -EINVAL; + goto end; + } + + g_jpeg_dev.open_cnt--; + + if (!node) { + CAM_ERR(CAM_JPEG, "Node ptr is NULL"); + rc = -EINVAL; + goto end; + } + + if (g_jpeg_dev.open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&g_jpeg_dev.jpeg_mutex); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_jpeg_subdev_internal_ops = { + .close = cam_jpeg_subdev_close, + .open = cam_jpeg_subdev_open, +}; + +static int cam_jpeg_dev_remove(struct platform_device *pdev) +{ + int rc; + int i; + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_jpeg_context_deinit(&g_jpeg_dev.ctx_jpeg[i]); + if (rc) + CAM_ERR(CAM_JPEG, "JPEG context %d deinit failed %d", + i, rc); + } + + rc = cam_subdev_remove(&g_jpeg_dev.sd); + if (rc) + CAM_ERR(CAM_JPEG, "Unregister failed %d", rc); + + return rc; +} + +static int cam_jpeg_dev_probe(struct platform_device *pdev) +{ + int rc; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + int iommu_hdl = -1; + + g_jpeg_dev.sd.internal_ops = &cam_jpeg_subdev_internal_ops; + rc = cam_subdev_probe(&g_jpeg_dev.sd, pdev, CAM_JPEG_DEV_NAME, + CAM_JPEG_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_JPEG, "JPEG cam_subdev_probe failed %d", rc); + goto err; + } + node = (struct cam_node *)g_jpeg_dev.sd.token; + + rc = cam_jpeg_hw_mgr_init(pdev->dev.of_node, + (uint64_t *)&hw_mgr_intf, &iommu_hdl); + if (rc) { + CAM_ERR(CAM_JPEG, "Can not initialize JPEG HWmanager %d", rc); + goto unregister; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_jpeg_context_init(&g_jpeg_dev.ctx_jpeg[i], + &g_jpeg_dev.ctx[i], + &node->hw_mgr_intf, + i); + if (rc) { + CAM_ERR(CAM_JPEG, "JPEG context init failed %d %d", + i, rc); + goto ctx_init_fail; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_CTX_MAX, + CAM_JPEG_DEV_NAME); + if (rc) { + CAM_ERR(CAM_JPEG, "JPEG node init failed %d", rc); + goto ctx_init_fail; + } + + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_jpeg_dev_iommu_fault_handler, node); + + mutex_init(&g_jpeg_dev.jpeg_mutex); + + CAM_INFO(CAM_JPEG, "Camera JPEG probe complete"); + + return rc; + +ctx_init_fail: + for (--i; i >= 0; i--) + if (cam_jpeg_context_deinit(&g_jpeg_dev.ctx_jpeg[i])) + CAM_ERR(CAM_JPEG, "deinit fail %d %d", i, rc); +unregister: + if (cam_subdev_remove(&g_jpeg_dev.sd)) + CAM_ERR(CAM_JPEG, "remove fail %d", rc); +err: + return rc; +} + +static struct platform_driver jpeg_driver = { + .probe = cam_jpeg_dev_probe, + .remove = cam_jpeg_dev_remove, + .driver = { + .name = "cam_jpeg", + .owner = THIS_MODULE, + .of_match_table = cam_jpeg_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_jpeg_dev_init_module(void) +{ + return platform_driver_register(&jpeg_driver); +} + +static void __exit cam_jpeg_dev_exit_module(void) +{ + platform_driver_unregister(&jpeg_driver); +} + +module_init(cam_jpeg_dev_init_module); +module_exit(cam_jpeg_dev_exit_module); +MODULE_DESCRIPTION("MSM JPEG driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_jpeg/cam_jpeg_dev.h b/techpack/camera/drivers/cam_jpeg/cam_jpeg_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..4961527de1a7c8a0e42acb9c3a2e31933bd93367 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/cam_jpeg_dev.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_DEV_H_ +#define _CAM_JPEG_DEV_H_ + +#include "cam_subdev.h" +#include "cam_hw_mgr_intf.h" +#include "cam_context.h" +#include "cam_jpeg_context.h" + +/** + * struct cam_jpeg_dev - Camera JPEG V4l2 device node + * + * @sd: Commone camera subdevice node + * @node: Pointer to jpeg subdevice + * @ctx: JPEG base context storage + * @ctx_jpeg: JPEG private context storage + * @jpeg_mutex: Jpeg dev mutex + * @open_cnt: Open device count + */ +struct cam_jpeg_dev { + struct cam_subdev sd; + struct cam_node *node; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_jpeg_context ctx_jpeg[CAM_CTX_MAX]; + struct mutex jpeg_mutex; + int32_t open_cnt; +}; +#endif /* __CAM_JPEG_DEV_H__ */ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/Makefile b/techpack/camera/drivers/cam_jpeg/jpeg_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f189bd13a24467f6718f031e9b7f055503a2575b --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_enc_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_dma_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg_hw_mgr.o diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..09b4b8d3e0f68b2471d9448c0b89b508f90fedeb --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -0,0 +1,1610 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/uaccess.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/debugfs.h> +#include <media/cam_defs.h> +#include <media/cam_jpeg.h> + +#include "cam_packet_util.h" +#include "cam_hw.h" +#include "cam_hw_mgr_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_jpeg_hw_mgr.h" +#include "cam_smmu_api.h" +#include "cam_mem_mgr.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" +#include "cam_cdm_intf_api.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +#define CAM_JPEG_HW_ENTRIES_MAX 20 +#define CAM_JPEG_CHBASE 0 +#define CAM_JPEG_CFG 1 +#define CAM_JPEG_PARAM 2 + +static struct cam_jpeg_hw_mgr g_jpeg_hw_mgr; + +static int32_t cam_jpeg_hw_mgr_cb(uint32_t irq_status, + int32_t result_size, void *data); +static int cam_jpeg_mgr_process_cmd(void *priv, void *data); + +static int cam_jpeg_mgr_process_irq(void *priv, void *data) +{ + int rc = 0; + int mem_hdl = 0; + struct cam_jpeg_process_irq_work_data_t *task_data; + struct cam_jpeg_hw_mgr *hw_mgr; + int32_t i; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_hw_done_event_data buf_data; + struct cam_jpeg_set_irq_cb irq_cb; + uintptr_t dev_type = 0; + uintptr_t kaddr; + uint32_t *cmd_buf_kaddr; + size_t cmd_buf_len; + struct cam_jpeg_config_inout_param_info *p_params; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct crm_workq_task *task; + struct cam_jpeg_process_frame_work_data_t *wq_task_data; + + if (!data || !priv) { + CAM_ERR(CAM_JPEG, "Invalid data"); + return -EINVAL; + } + + task_data = data; + hw_mgr = &g_jpeg_hw_mgr; + + ctx_data = (struct cam_jpeg_hw_ctx_data *)task_data->data; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + mutex_lock(&g_jpeg_hw_mgr.hw_mgr_mutex); + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + + if (hw_mgr->device_in_use[dev_type][0] == false || + p_cfg_req == NULL) { + CAM_ERR(CAM_JPEG, "irq for old request %d", rc); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return -EINVAL; + } + + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (!hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + CAM_ERR(CAM_JPEG, "process_cmd null "); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return -EINVAL; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) { + CAM_ERR(CAM_JPEG, "CMD_SET_IRQ_CB failed %d", rc); + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + return rc; + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %lu HW", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; + mutex_unlock(&g_jpeg_hw_mgr.hw_mgr_mutex); + + task = cam_req_mgr_workq_get_task( + g_jpeg_hw_mgr.work_process_frame); + if (!task) { + CAM_ERR(CAM_JPEG, "no empty task"); + return -EINVAL; + } + + wq_task_data = (struct cam_jpeg_process_frame_work_data_t *) + task->payload; + if (!task_data) { + CAM_ERR(CAM_JPEG, "task_data is NULL"); + return -EINVAL; + } + wq_task_data->data = (void *)dev_type; + wq_task_data->request_id = 0; + wq_task_data->type = CAM_JPEG_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_jpeg_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &g_jpeg_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) { + CAM_ERR(CAM_JPEG, "could not enque task %d", rc); + return rc; + } + + mem_hdl = + p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].handle; + rc = cam_mem_get_cpu_buf(mem_hdl, &kaddr, &cmd_buf_len); + if (rc) { + CAM_ERR(CAM_JPEG, "unable to get info for cmd buf: %x %d", + hw_mgr->iommu_hdl, rc); + return rc; + } + + cmd_buf_kaddr = (uint32_t *)kaddr; + + if ((p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset / + sizeof(uint32_t)) >= cmd_buf_len) { + CAM_ERR(CAM_JPEG, "Invalid offset: %u cmd buf len: %zu", + p_cfg_req->hw_cfg_args.hw_update_entries[ + CAM_JPEG_PARAM].offset, cmd_buf_len); + return -EINVAL; + } + + cmd_buf_kaddr = + (cmd_buf_kaddr + + (p_cfg_req->hw_cfg_args.hw_update_entries[CAM_JPEG_PARAM].offset + / sizeof(uint32_t))); + + p_params = (struct cam_jpeg_config_inout_param_info *)cmd_buf_kaddr; + + p_params->output_size = task_data->result_size; + CAM_DBG(CAM_JPEG, "Encoded Size %d", task_data->result_size); + + buf_data.num_handles = + p_cfg_req->hw_cfg_args.num_out_map_entries; + for (i = 0; i < buf_data.num_handles; i++) { + buf_data.resource_handle[i] = + p_cfg_req->hw_cfg_args.out_map_entries[i].resource_handle; + } + buf_data.request_id = + PTR_TO_U64(p_cfg_req->hw_cfg_args.priv); + ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data); + + list_add_tail(&p_cfg_req->list, &hw_mgr->free_req_list); + return rc; +} + +static int cam_jpeg_hw_mgr_cb( + uint32_t irq_status, int32_t result_size, void *data) +{ + int32_t rc; + unsigned long flags; + struct cam_jpeg_hw_mgr *hw_mgr = &g_jpeg_hw_mgr; + struct crm_workq_task *task; + struct cam_jpeg_process_irq_work_data_t *task_data; + + spin_lock_irqsave(&hw_mgr->hw_mgr_lock, flags); + task = cam_req_mgr_workq_get_task( + g_jpeg_hw_mgr.work_process_irq_cb); + if (!task) { + CAM_ERR(CAM_JPEG, "no empty task"); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + return -ENOMEM; + } + + task_data = (struct cam_jpeg_process_irq_work_data_t *)task->payload; + task_data->data = data; + task_data->irq_status = irq_status; + task_data->result_size = result_size; + task_data->type = CAM_JPEG_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_jpeg_mgr_process_irq; + + rc = cam_req_mgr_workq_enqueue_task(task, &g_jpeg_hw_mgr, + CRM_TASK_PRIORITY_0); + spin_unlock_irqrestore(&hw_mgr->hw_mgr_lock, flags); + + return rc; +} + +static int cam_jpeg_mgr_get_free_ctx(struct cam_jpeg_hw_mgr *hw_mgr) +{ + int i = 0; + int num_ctx = CAM_JPEG_CTX_MAX; + + for (i = 0; i < num_ctx; i++) { + mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex); + if (hw_mgr->ctx_data[i].in_use == false) { + hw_mgr->ctx_data[i].in_use = true; + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + break; + } + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + } + + return i; +} + + +static int cam_jpeg_mgr_release_ctx( + struct cam_jpeg_hw_mgr *hw_mgr, struct cam_jpeg_hw_ctx_data *ctx_data) +{ + if (!ctx_data) { + CAM_ERR(CAM_JPEG, "invalid ctx_data %pK", ctx_data); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is already un-used: %pK", ctx_data); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + + ctx_data->in_use = false; + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static int cam_jpeg_insert_cdm_change_base( + struct cam_hw_config_args *config_args, + struct cam_jpeg_hw_ctx_data *ctx_data, + struct cam_jpeg_hw_mgr *hw_mgr) +{ + int rc = 0; + uint32_t dev_type; + struct cam_cdm_bl_request *cdm_cmd; + uint32_t size; + uint32_t mem_cam_base; + uintptr_t iova_addr; + uint32_t *ch_base_iova_addr; + size_t ch_base_len; + + rc = cam_mem_get_cpu_buf( + config_args->hw_update_entries[CAM_JPEG_CHBASE].handle, + &iova_addr, &ch_base_len); + if (rc) { + CAM_ERR(CAM_JPEG, + "unable to get src buf info for cmd buf: %d", rc); + return rc; + } + + if (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset >= + ch_base_len) { + CAM_ERR(CAM_JPEG, "Not enough buf"); + return -EINVAL; + } + CAM_DBG(CAM_JPEG, "iova %pK len %zu offset %d", + (void *)iova_addr, ch_base_len, + config_args->hw_update_entries[CAM_JPEG_CHBASE].offset); + ch_base_iova_addr = (uint32_t *)iova_addr; + ch_base_iova_addr = (ch_base_iova_addr + + (config_args->hw_update_entries[CAM_JPEG_CHBASE].offset / + sizeof(uint32_t))); + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + mem_cam_base = hw_mgr->cdm_reg_map[dev_type][0]->mem_cam_base; + size = + hw_mgr->cdm_info[dev_type][0].cdm_ops->cdm_required_size_changebase(); + hw_mgr->cdm_info[dev_type][0].cdm_ops->cdm_write_changebase( + ch_base_iova_addr, mem_cam_base); + + cdm_cmd = ctx_data->cdm_cmd; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].bl_addr.mem_handle = + config_args->hw_update_entries[CAM_JPEG_CHBASE].handle; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].offset = + config_args->hw_update_entries[CAM_JPEG_CHBASE].offset; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = size * sizeof(uint32_t); + cdm_cmd->cmd_arrary_count++; + + ch_base_iova_addr += size; + *ch_base_iova_addr = 0; + ch_base_iova_addr += size; + *ch_base_iova_addr = 0; + + return rc; +} + +static int cam_jpeg_mgr_process_cmd(void *priv, void *data) +{ + int rc; + int i = 0; + struct cam_jpeg_hw_mgr *hw_mgr = priv; + struct cam_hw_update_entry *cmd; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_hw_config_args *config_args = NULL; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uintptr_t request_id = 0; + struct cam_jpeg_process_frame_work_data_t *task_data = + (struct cam_jpeg_process_frame_work_data_t *)data; + uint32_t dev_type; + struct cam_jpeg_set_irq_cb irq_cb; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct cam_hw_done_event_data buf_data; + struct cam_hw_config_args *hw_cfg_args = NULL; + + if (!hw_mgr || !task_data) { + CAM_ERR(CAM_JPEG, "Invalid arguments %pK %pK", + hw_mgr, task_data); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + if (list_empty(&hw_mgr->hw_config_req_list)) { + CAM_DBG(CAM_JPEG, "no available request"); + rc = -EFAULT; + goto end; + } + + p_cfg_req = list_first_entry(&hw_mgr->hw_config_req_list, + struct cam_jpeg_hw_cfg_req, list); + if (!p_cfg_req) { + CAM_ERR(CAM_JPEG, "no request"); + rc = -EFAULT; + goto end; + } + + if (false == hw_mgr->device_in_use[p_cfg_req->dev_type][0]) { + hw_mgr->device_in_use[p_cfg_req->dev_type][0] = true; + hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = p_cfg_req; + list_del_init(&p_cfg_req->list); + } else { + CAM_DBG(CAM_JPEG, "Not dequeing, just return"); + rc = -EFAULT; + goto end; + } + + config_args = (struct cam_hw_config_args *)&p_cfg_req->hw_cfg_args; + request_id = task_data->request_id; + if (request_id != (uintptr_t)config_args->priv) { + CAM_DBG(CAM_JPEG, "not a recent req %zd %zd", + request_id, (uintptr_t)config_args->priv); + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_JPEG, "No hw update enteries are available"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -EINVAL; + goto end_unusedev; + } + + ctx_data = (struct cam_jpeg_hw_ctx_data *)config_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -EINVAL; + goto end_unusedev; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + if (dev_type != p_cfg_req->dev_type) + CAM_WARN(CAM_JPEG, "dev types not same something wrong"); + + if (!hw_mgr->devices[dev_type][0]->hw_ops.init) { + CAM_ERR(CAM_JPEG, "hw op init null "); + rc = -EFAULT; + goto end; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.init( + hw_mgr->devices[dev_type][0]->hw_priv, + ctx_data, + sizeof(ctx_data)); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to Init %d HW", dev_type); + goto end; + } + + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = (void *)ctx_data; + irq_cb.b_set_cb = true; + if (!hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + CAM_ERR(CAM_JPEG, "op process_cmd null "); + rc = -EFAULT; + goto end_callcb; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) { + CAM_ERR(CAM_JPEG, "SET_IRQ_CB failed %d", rc); + goto end_callcb; + } + + if (!hw_mgr->devices[dev_type][0]->hw_ops.reset) { + CAM_ERR(CAM_JPEG, "op reset null "); + rc = -EFAULT; + goto end_callcb; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.reset( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg hw reset failed %d", rc); + goto end_callcb; + } + + cdm_cmd = ctx_data->cdm_cmd; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + cdm_cmd->cmd_arrary_count = 0; + + rc = cam_jpeg_insert_cdm_change_base(config_args, + ctx_data, hw_mgr); + if (rc) { + CAM_ERR(CAM_JPEG, "insert change base failed %d", rc); + goto end_callcb; + } + + CAM_DBG(CAM_JPEG, "num hw up %d", config_args->num_hw_update_entries); + for (i = CAM_JPEG_CFG; i < (config_args->num_hw_update_entries - 1); + i++) { + cmd = (config_args->hw_update_entries + i); + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].bl_addr.mem_handle + = cmd->handle; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].offset = + cmd->offset; + cdm_cmd->cmd[cdm_cmd->cmd_arrary_count].len = + cmd->len; + CAM_DBG(CAM_JPEG, "i %d entry h %d o %d l %d", + i, cmd->handle, cmd->offset, cmd->len); + cdm_cmd->cmd_arrary_count++; + } + + rc = cam_cdm_submit_bls( + hw_mgr->cdm_info[dev_type][0].cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to apply the configs %d", rc); + goto end_callcb; + } + + if (!hw_mgr->devices[dev_type][0]->hw_ops.start) { + CAM_ERR(CAM_JPEG, "op start null "); + rc = -EINVAL; + goto end_callcb; + } + rc = hw_mgr->devices[dev_type][0]->hw_ops.start( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to start hw %d", + rc); + goto end_callcb; + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; + +end_callcb: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + if (p_cfg_req) { + hw_cfg_args = &p_cfg_req->hw_cfg_args; + buf_data.num_handles = + hw_cfg_args->num_out_map_entries; + for (i = 0; i < buf_data.num_handles; i++) { + buf_data.resource_handle[i] = + hw_cfg_args->out_map_entries[i].resource_handle; + } + buf_data.request_id = + (uintptr_t)p_cfg_req->hw_cfg_args.priv; + ctx_data->ctxt_event_cb(ctx_data->context_priv, 0, &buf_data); + } +end_unusedev: + mutex_lock(&hw_mgr->hw_mgr_mutex); + hw_mgr->device_in_use[p_cfg_req->dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[p_cfg_req->dev_type][0] = NULL; + +end: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_jpeg_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) +{ + int rc; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_config_args *config_args = config_hw_args; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uintptr_t request_id = 0; + struct cam_hw_update_entry *hw_update_entries; + struct crm_workq_task *task; + struct cam_jpeg_process_frame_work_data_t *task_data; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + + if (!hw_mgr || !config_args) { + CAM_ERR(CAM_JPEG, "Invalid arguments %pK %pK", + hw_mgr, config_args); + return -EINVAL; + } + + if (!config_args->num_hw_update_entries) { + CAM_ERR(CAM_JPEG, "No hw update enteries are available"); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + ctx_data = (struct cam_jpeg_hw_ctx_data *)config_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + if (list_empty(&hw_mgr->free_req_list)) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_JPEG, "list empty"); + return -ENOMEM; + } + + p_cfg_req = list_first_entry(&hw_mgr->free_req_list, + struct cam_jpeg_hw_cfg_req, list); + list_del_init(&p_cfg_req->list); + + /* Update Currently Processing Config Request */ + p_cfg_req->hw_cfg_args = *config_args; + p_cfg_req->dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + request_id = (uintptr_t)config_args->priv; + p_cfg_req->req_id = request_id; + hw_update_entries = config_args->hw_update_entries; + CAM_DBG(CAM_JPEG, "ctx_data = %pK req_id = %lld %zd", + ctx_data, request_id, (uintptr_t)config_args->priv); + task = cam_req_mgr_workq_get_task(g_jpeg_hw_mgr.work_process_frame); + if (!task) { + CAM_ERR(CAM_JPEG, "no empty task"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -ENOMEM; + goto err_after_dq_free_list; + } + + + task_data = (struct cam_jpeg_process_frame_work_data_t *) + task->payload; + if (!task_data) { + CAM_ERR(CAM_JPEG, "task_data is NULL"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + rc = -EINVAL; + goto err_after_dq_free_list; + } + CAM_DBG(CAM_JPEG, "cfge %pK num %d", + p_cfg_req->hw_cfg_args.hw_update_entries, + p_cfg_req->hw_cfg_args.num_hw_update_entries); + + list_add_tail(&p_cfg_req->list, &hw_mgr->hw_config_req_list); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + task_data->data = (void *)(uintptr_t)p_cfg_req->dev_type; + task_data->request_id = request_id; + task_data->type = CAM_JPEG_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_jpeg_mgr_process_cmd; + + rc = cam_req_mgr_workq_enqueue_task(task, &g_jpeg_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) { + CAM_ERR(CAM_JPEG, "failed to enqueue task %d", rc); + goto err_after_get_task; + } + + return rc; + +err_after_get_task: + list_del_init(&p_cfg_req->list); +err_after_dq_free_list: + list_add_tail(&p_cfg_req->list, &hw_mgr->free_req_list); + + return rc; +} + +static void cam_jpeg_mgr_print_io_bufs(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl, uint32_t pf_buf_info, + bool *mem_found) +{ + dma_addr_t iova_addr; + size_t src_buf_size; + int i; + int j; + int rc = 0; + int32_t mmu_hdl; + struct cam_buf_io_cfg *io_cfg = NULL; + + if (mem_found) + *mem_found = false; + + io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + + for (i = 0; i < packet->num_io_configs; i++) { + for (j = 0; j < CAM_PACKET_MAX_PLANES; j++) { + if (!io_cfg[i].mem_handle[j]) + break; + + if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + GET_FD_FROM_HANDLE(pf_buf_info)) { + CAM_INFO(CAM_JPEG, + "Found PF at port: %d mem %x fd: %x", + io_cfg[i].resource_type, + io_cfg[i].mem_handle[j], + pf_buf_info); + if (mem_found) + *mem_found = true; + } + + CAM_INFO(CAM_JPEG, "port: %d f: %u format: %d dir %d", + io_cfg[i].resource_type, + io_cfg[i].fence, + io_cfg[i].format, + io_cfg[i].direction); + + mmu_hdl = cam_mem_is_secure_buf( + io_cfg[i].mem_handle[j]) ? sec_mmu_hdl : + iommu_hdl; + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[j], + mmu_hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "get src buf address fail"); + continue; + } + if ((iova_addr & 0xFFFFFFFF) != iova_addr) { + CAM_ERR(CAM_JPEG, "Invalid mapped address"); + rc = -EINVAL; + continue; + } + + CAM_INFO(CAM_JPEG, + "pln %u w %u h %u stride %u slice %u size %d addr 0x%x offset 0x%x memh %x", + j, io_cfg[i].planes[j].width, + io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, + (int32_t)src_buf_size, + (unsigned int)iova_addr, + io_cfg[i].offsets[j], + io_cfg[i].mem_handle[j]); + } + } +} + +static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, + void *prepare_hw_update_args) +{ + int rc, i, j, k; + struct cam_hw_prepare_update_args *prepare_args = + prepare_hw_update_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_packet *packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_buf_io_cfg *io_cfg_ptr = NULL; + struct cam_kmd_buf_info kmd_buf; + + if (!prepare_args || !hw_mgr) { + CAM_ERR(CAM_JPEG, "Invalid args %pK %pK", + prepare_args, hw_mgr); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_data = (struct cam_jpeg_hw_ctx_data *)prepare_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + packet = prepare_args->packet; + if (!packet) { + CAM_ERR(CAM_JPEG, "received packet is NULL"); + return -EINVAL; + } + + if (((packet->header.op_code & 0xff) != CAM_JPEG_OPCODE_ENC_UPDATE) && + ((packet->header.op_code + & 0xff) != CAM_JPEG_OPCODE_DMA_UPDATE)) { + CAM_ERR(CAM_JPEG, "Invalid Opcode in pkt: %d", + packet->header.op_code & 0xff); + return -EINVAL; + } + + rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len); + if (rc) { + CAM_ERR(CAM_JPEG, "invalid packet %d", rc); + return rc; + } + + if ((packet->num_cmd_buf > 5) || !packet->num_patches || + !packet->num_io_configs) { + CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u", + packet->num_cmd_buf, + packet->num_patches); + return -EINVAL; + } + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&packet->payload + + (packet->cmd_buf_offset / 4)); + CAM_DBG(CAM_JPEG, "packet = %pK cmd_desc = %pK size = %lu", + (void *)packet, (void *)cmd_desc, + sizeof(struct cam_cmd_buf_desc)); + + rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, -1); + if (rc) { + CAM_ERR(CAM_JPEG, "Patch processing failed %d", rc); + return rc; + } + + io_cfg_ptr = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload + + packet->io_configs_offset / 4); + CAM_DBG(CAM_JPEG, "packet = %pK io_cfg_ptr = %pK size = %lu", + (void *)packet, (void *)io_cfg_ptr, + sizeof(struct cam_buf_io_cfg)); + prepare_args->pf_data->packet = packet; + + prepare_args->num_out_map_entries = 0; + + for (i = 0, j = 0, k = 0; i < packet->num_io_configs; i++) { + if (io_cfg_ptr[i].direction == CAM_BUF_INPUT) { + prepare_args->in_map_entries[j].resource_handle = + io_cfg_ptr[i].resource_type; + prepare_args->in_map_entries[j++].sync_id = + io_cfg_ptr[i].fence; + prepare_args->num_in_map_entries++; + } else { + prepare_args->in_map_entries[k].resource_handle = + io_cfg_ptr[i].resource_type; + prepare_args->out_map_entries[k++].sync_id = + io_cfg_ptr[i].fence; + prepare_args->num_out_map_entries++; + } + CAM_DBG(CAM_JPEG, "dir[%d]: %u, fence: %u", + i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); + } + + + j = prepare_args->num_hw_update_entries; + rc = cam_packet_util_get_kmd_buffer(packet, &kmd_buf); + if (rc) { + CAM_ERR(CAM_JPEG, "get kmd buf failed %d", rc); + return rc; + } + /* fill kmd buf info into 1st hw update entry */ + prepare_args->hw_update_entries[j].len = + (uint32_t)kmd_buf.used_bytes; + prepare_args->hw_update_entries[j].handle = + (uint32_t)kmd_buf.handle; + prepare_args->hw_update_entries[j].offset = + (uint32_t)kmd_buf.offset; + j++; + + for (i = 0; i < packet->num_cmd_buf; i++, j++) { + prepare_args->hw_update_entries[j].len = + (uint32_t)cmd_desc[i].length; + prepare_args->hw_update_entries[j].handle = + (uint32_t)cmd_desc[i].mem_handle; + prepare_args->hw_update_entries[j].offset = + (uint32_t)cmd_desc[i].offset; + } + prepare_args->num_hw_update_entries = j; + prepare_args->priv = (void *)(uintptr_t)packet->header.request_id; + + CAM_DBG(CAM_JPEG, "will wait on input sync sync_id %d", + prepare_args->in_map_entries[0].sync_id); + + return rc; +} + +static void cam_jpeg_mgr_stop_deinit_dev(struct cam_jpeg_hw_mgr *hw_mgr, + struct cam_jpeg_hw_cfg_req *p_cfg_req, uint32_t dev_type) +{ + int rc = 0; + struct cam_jpeg_set_irq_cb irq_cb; + + /* stop reset Unregister CB and deinit */ + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_JPEG, "SET_IRQ_CB fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "process_cmd null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "stop fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "op stop null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %d HW %d", + dev_type, rc); + } else { + CAM_ERR(CAM_JPEG, "op deinit null %d", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; +} + +static int cam_jpeg_mgr_flush(void *hw_mgr_priv, + struct cam_jpeg_hw_ctx_data *ctx_data) +{ + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL; + + CAM_DBG(CAM_JPEG, "E: JPEG flush ctx"); + + if (!hw_mgr || !ctx_data) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if ((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + } + } + + list_for_each_entry_safe(cfg_req, req_temp, + &hw_mgr->hw_config_req_list, list) { + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) + continue; + + list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + } + + CAM_DBG(CAM_JPEG, "X: JPEG flush ctx"); + + return 0; +} + +static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, + struct cam_jpeg_hw_ctx_data *ctx_data, + struct cam_hw_flush_args *flush_args) +{ + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_cfg_req *cfg_req = NULL; + struct cam_jpeg_hw_cfg_req *req_temp = NULL; + long request_id = 0; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + bool b_req_found = false; + + CAM_DBG(CAM_JPEG, "E: JPEG flush req"); + + if (!hw_mgr || !ctx_data || !flush_args) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + if (flush_args->num_req_pending) + return 0; + + request_id = (uintptr_t)flush_args->flush_req_active[0]; + + if (!flush_args->num_req_active) + return 0; + + if (request_id <= 0) { + CAM_ERR(CAM_JPEG, "Invalid red id %ld", request_id); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if (((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) && + (p_cfg_req->req_id == request_id)) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + b_req_found = true; + } + } + + list_for_each_entry_safe(cfg_req, req_temp, + &hw_mgr->hw_config_req_list, list) { + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) + continue; + + if (cfg_req->req_id != request_id) + continue; + + list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + b_req_found = true; + break; + } + + if (!b_req_found) { + CAM_ERR(CAM_JPEG, "req not found %ld", request_id); + return -EINVAL; + } + + CAM_DBG(CAM_JPEG, "X: JPEG flush req"); + return 0; +} + +static int cam_jpeg_mgr_hw_flush(void *hw_mgr_priv, void *flush_hw_args) +{ + int rc = 0; + struct cam_hw_flush_args *flush_args = flush_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + + if (!hw_mgr || !flush_args || !flush_args->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + mutex_lock(&hw_mgr->hw_mgr_mutex); + + ctx_data = (struct cam_jpeg_hw_ctx_data *)flush_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + if ((flush_args->flush_type >= CAM_FLUSH_TYPE_MAX) || + (flush_args->flush_type < CAM_FLUSH_TYPE_REQ)) { + CAM_ERR(CAM_JPEG, "Invalid flush type: %d", + flush_args->flush_type); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + rc = cam_jpeg_mgr_flush(hw_mgr_priv, ctx_data); + if ((rc)) + CAM_ERR(CAM_JPEG, "Flush failed %d", rc); + break; + case CAM_FLUSH_TYPE_REQ: + rc = cam_jpeg_mgr_flush_req(hw_mgr_priv, ctx_data, flush_args); + break; + default: + CAM_ERR(CAM_JPEG, "Invalid flush type: %d", + flush_args->flush_type); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_jpeg_mgr_hw_stop(void *hw_mgr_priv, void *stop_hw_args) +{ + int rc; + struct cam_hw_stop_args *stop_args = + (struct cam_hw_stop_args *)stop_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + + if (!hw_mgr || !stop_args || !stop_args->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + mutex_lock(&hw_mgr->hw_mgr_mutex); + + ctx_data = (struct cam_jpeg_hw_ctx_data *)stop_args->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + + rc = cam_jpeg_mgr_flush(hw_mgr_priv, ctx_data); + if ((rc)) + CAM_ERR(CAM_JPEG, "flush failed %d", rc); + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) +{ + int rc; + struct cam_hw_release_args *release_hw = release_hw_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + uint32_t dev_type; + + if (!hw_mgr || !release_hw || !release_hw->ctxt_to_hw_map) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + ctx_data = (struct cam_jpeg_hw_ctx_data *)release_hw->ctxt_to_hw_map; + if (!ctx_data->in_use) { + CAM_ERR(CAM_JPEG, "ctx is not in use"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EINVAL; + } + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_JPEG, "Error Unbalanced deinit"); + return -EFAULT; + } + + hw_mgr->cdm_info[dev_type][0].ref_cnt--; + if (!(hw_mgr->cdm_info[dev_type][0].ref_cnt)) { + if (cam_cdm_stream_off( + hw_mgr->cdm_info[dev_type][0].cdm_handle)) { + CAM_ERR(CAM_JPEG, "CDM stream off failed %d", + hw_mgr->cdm_info[dev_type][0].cdm_handle); + } + /* release cdm handle */ + cam_cdm_release(hw_mgr->cdm_info[dev_type][0].cdm_handle); + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + rc = cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data); + if (rc) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_JPEG, "JPEG release ctx failed"); + kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + + return -EINVAL; + } + + kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + CAM_DBG(CAM_JPEG, "handle %llu", ctx_data); + + return rc; +} + +static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) +{ + int rc = 0; + int32_t ctx_id = 0; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_jpeg_hw_ctx_data *ctx_data = NULL; + struct cam_hw_acquire_args *args = acquire_hw_args; + struct cam_jpeg_acquire_dev_info jpeg_dev_acquire_info; + struct cam_cdm_acquire_data cdm_acquire; + uint32_t dev_type; + uint32_t size = 0; + + if ((!hw_mgr_priv) || (!acquire_hw_args)) { + CAM_ERR(CAM_JPEG, "Invalid params: %pK %pK", hw_mgr_priv, + acquire_hw_args); + return -EINVAL; + } + + if (args->num_acq > 1) { + CAM_ERR(CAM_JPEG, + "number of resources are wrong: %u", + args->num_acq); + return -EINVAL; + } + + if (copy_from_user(&jpeg_dev_acquire_info, + (void __user *)args->acquire_info, + sizeof(jpeg_dev_acquire_info))) { + CAM_ERR(CAM_JPEG, "copy failed"); + return -EFAULT; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + ctx_id = cam_jpeg_mgr_get_free_ctx(hw_mgr); + if (ctx_id >= CAM_JPEG_CTX_MAX) { + CAM_ERR(CAM_JPEG, "No free ctx space in hw_mgr"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return -EFAULT; + } + + ctx_data = &hw_mgr->ctx_data[ctx_id]; + + ctx_data->cdm_cmd = + kzalloc(((sizeof(struct cam_cdm_bl_request)) + + ((CAM_JPEG_HW_ENTRIES_MAX - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!ctx_data->cdm_cmd) { + rc = -ENOMEM; + goto jpeg_release_ctx; + } + + mutex_lock(&ctx_data->ctx_mutex); + ctx_data->jpeg_dev_acquire_info = jpeg_dev_acquire_info; + mutex_unlock(&ctx_data->ctx_mutex); + + if (ctx_data->jpeg_dev_acquire_info.dev_type >= + CAM_JPEG_RES_TYPE_MAX) { + rc = -EINVAL; + goto acq_cdm_hdl_failed; + } + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + if (!hw_mgr->cdm_info[dev_type][0].ref_cnt) { + + if (dev_type == CAM_JPEG_RES_TYPE_ENC) { + memcpy(cdm_acquire.identifier, + "jpegenc", sizeof("jpegenc")); + } else { + memcpy(cdm_acquire.identifier, + "jpegdma", sizeof("jpegdma")); + } + cdm_acquire.cell_index = 0; + cdm_acquire.handle = 0; + cdm_acquire.userdata = ctx_data; + if (hw_mgr->cdm_reg_map[dev_type][0]) { + cdm_acquire.base_array[0] = + hw_mgr->cdm_reg_map[dev_type][0]; + } + cdm_acquire.base_array_cnt = 1; + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.cam_cdm_callback = NULL; + + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_JPEG, "Failed to acquire the CDM HW %d", + rc); + rc = -EFAULT; + goto acq_cdm_hdl_failed; + } + hw_mgr->cdm_info[dev_type][0].cdm_handle = cdm_acquire.handle; + hw_mgr->cdm_info[dev_type][0].cdm_ops = cdm_acquire.ops; + hw_mgr->cdm_info[dev_type][0].ref_cnt++; + } else { + hw_mgr->cdm_info[dev_type][0].ref_cnt++; + } + + size = + hw_mgr->cdm_info[dev_type][0].cdm_ops->cdm_required_size_changebase(); + + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1) + if (cam_cdm_stream_on( + hw_mgr->cdm_info[dev_type][0].cdm_handle)) { + CAM_ERR(CAM_JPEG, "Can not start cdm (%d)!", + hw_mgr->cdm_info[dev_type][0].cdm_handle); + rc = -EFAULT; + goto start_cdm_hdl_failed; + } + + mutex_lock(&ctx_data->ctx_mutex); + ctx_data->context_priv = args->context_data; + + args->ctxt_to_hw_map = (void *)&(hw_mgr->ctx_data[ctx_id]); + + mutex_unlock(&ctx_data->ctx_mutex); + + hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb; + + + if (copy_to_user((void __user *)args->acquire_info, + &jpeg_dev_acquire_info, + sizeof(jpeg_dev_acquire_info))) { + rc = -EFAULT; + goto copy_to_user_failed; + } + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_JPEG, "success ctx_data= %pK", ctx_data); + + return rc; + +copy_to_user_failed: + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1) + cam_cdm_stream_off(hw_mgr->cdm_info[dev_type][0].cdm_handle); +start_cdm_hdl_failed: + if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 1) + cam_cdm_release(hw_mgr->cdm_info[dev_type][0].cdm_handle); + hw_mgr->cdm_info[dev_type][0].ref_cnt--; +acq_cdm_hdl_failed: + kfree(ctx_data->cdm_cmd); +jpeg_release_ctx: + cam_jpeg_mgr_release_ctx(hw_mgr, ctx_data); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_jpeg_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) +{ + int rc; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *query_cap = hw_caps_args; + + if (!hw_mgr_priv || !hw_caps_args) { + CAM_ERR(CAM_JPEG, "Invalid params: %pK %pK", + hw_mgr_priv, hw_caps_args); + return -EINVAL; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + + if (copy_to_user(u64_to_user_ptr(query_cap->caps_handle), + &g_jpeg_hw_mgr.jpeg_caps, + sizeof(struct cam_jpeg_query_cap_cmd))) { + CAM_ERR(CAM_JPEG, "copy_to_user failed"); + rc = -EFAULT; + goto copy_error; + } + CAM_DBG(CAM_JPEG, "Success"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return 0; + +copy_error: + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; +} + +static int cam_jpeg_setup_workqs(void) +{ + int rc, i; + + rc = cam_req_mgr_workq_create( + "jpeg_command_queue", + CAM_JPEG_WORKQ_NUM_TASK, + &g_jpeg_hw_mgr.work_process_frame, + CRM_WORKQ_USAGE_NON_IRQ, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); + goto work_process_frame_failed; + } + + rc = cam_req_mgr_workq_create( + "jpeg_message_queue", + CAM_JPEG_WORKQ_NUM_TASK, + &g_jpeg_hw_mgr.work_process_irq_cb, + CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); + goto work_process_irq_cb_failed; + } + + g_jpeg_hw_mgr.process_frame_work_data = + kzalloc(sizeof(struct cam_jpeg_process_frame_work_data_t) * + CAM_JPEG_WORKQ_NUM_TASK, GFP_KERNEL); + if (!g_jpeg_hw_mgr.process_frame_work_data) { + rc = -ENOMEM; + goto work_process_frame_data_failed; + } + + g_jpeg_hw_mgr.process_irq_cb_work_data = + kzalloc(sizeof(struct cam_jpeg_process_irq_work_data_t) * + CAM_JPEG_WORKQ_NUM_TASK, GFP_KERNEL); + if (!g_jpeg_hw_mgr.process_irq_cb_work_data) { + rc = -ENOMEM; + goto work_process_irq_cb_data_failed; + } + + for (i = 0; i < CAM_JPEG_WORKQ_NUM_TASK; i++) + g_jpeg_hw_mgr.work_process_irq_cb->task.pool[i].payload = + &g_jpeg_hw_mgr.process_irq_cb_work_data[i]; + + for (i = 0; i < CAM_JPEG_WORKQ_NUM_TASK; i++) + g_jpeg_hw_mgr.work_process_frame->task.pool[i].payload = + &g_jpeg_hw_mgr.process_frame_work_data[i]; + + INIT_LIST_HEAD(&g_jpeg_hw_mgr.hw_config_req_list); + INIT_LIST_HEAD(&g_jpeg_hw_mgr.free_req_list); + for (i = 0; i < CAM_JPEG_HW_CFG_Q_MAX; i++) { + INIT_LIST_HEAD(&(g_jpeg_hw_mgr.req_list[i].list)); + list_add_tail(&(g_jpeg_hw_mgr.req_list[i].list), + &(g_jpeg_hw_mgr.free_req_list)); + } + + return rc; + +work_process_irq_cb_data_failed: + kfree(g_jpeg_hw_mgr.process_frame_work_data); +work_process_frame_data_failed: + cam_req_mgr_workq_destroy(&g_jpeg_hw_mgr.work_process_irq_cb); +work_process_irq_cb_failed: + cam_req_mgr_workq_destroy(&g_jpeg_hw_mgr.work_process_frame); +work_process_frame_failed: + + return rc; +} + +static int cam_jpeg_init_devices(struct device_node *of_node, + uint32_t *p_num_enc_dev, + uint32_t *p_num_dma_dev) +{ + int count, i, rc; + uint32_t num_dev; + uint32_t num_dma_dev; + const char *name = NULL; + struct device_node *child_node = NULL; + struct platform_device *child_pdev = NULL; + struct cam_hw_intf *child_dev_intf = NULL; + struct cam_hw_info *enc_hw = NULL; + struct cam_hw_info *dma_hw = NULL; + struct cam_hw_soc_info *enc_soc_info = NULL; + struct cam_hw_soc_info *dma_soc_info = NULL; + + if (!p_num_enc_dev || !p_num_dma_dev) { + rc = -EINVAL; + goto num_dev_failed; + } + count = of_property_count_strings(of_node, "compat-hw-name"); + if (!count) { + CAM_ERR(CAM_JPEG, + "no compat hw found in dev tree, count = %d", + count); + rc = -EINVAL; + goto num_dev_failed; + } + + rc = of_property_read_u32(of_node, "num-jpeg-enc", &num_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "read num enc devices failed %d", rc); + goto num_enc_failed; + } + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL); + if (!g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC]) { + rc = -ENOMEM; + CAM_ERR(CAM_JPEG, "getting number of dma dev nodes failed"); + goto num_enc_failed; + } + + rc = of_property_read_u32(of_node, "num-jpeg-dma", &num_dma_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "get num dma dev nodes failed %d", rc); + goto num_dma_failed; + } + + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dma_dev, GFP_KERNEL); + if (!g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA]) { + rc = -ENOMEM; + goto num_dma_failed; + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "compat-hw-name", + i, &name); + if (rc) { + CAM_ERR(CAM_JPEG, "getting dev object name failed"); + goto compat_hw_name_failed; + } + + child_node = of_find_node_by_name(NULL, name); + if (!child_node) { + CAM_ERR(CAM_JPEG, + "error! Cannot find node in dtsi %s", name); + rc = -ENODEV; + goto compat_hw_name_failed; + } + + child_pdev = of_find_device_by_node(child_node); + if (!child_pdev) { + CAM_ERR(CAM_JPEG, "failed to find device on bus %s", + child_node->name); + rc = -ENODEV; + of_node_put(child_node); + goto compat_hw_name_failed; + } + + child_dev_intf = (struct cam_hw_intf *)platform_get_drvdata( + child_pdev); + if (!child_dev_intf) { + CAM_ERR(CAM_JPEG, "no child device"); + of_node_put(child_node); + rc = -ENODEV; + goto compat_hw_name_failed; + } + CAM_DBG(CAM_JPEG, "child_intf %pK type %d id %d", + child_dev_intf, + child_dev_intf->hw_type, + child_dev_intf->hw_idx); + + if ((child_dev_intf->hw_type == CAM_JPEG_DEV_ENC && + child_dev_intf->hw_idx >= num_dev) || + (child_dev_intf->hw_type == CAM_JPEG_DEV_DMA && + child_dev_intf->hw_idx >= num_dma_dev)) { + CAM_ERR(CAM_JPEG, "index out of range"); + rc = -ENODEV; + goto compat_hw_name_failed; + } + g_jpeg_hw_mgr.devices[child_dev_intf->hw_type] + [child_dev_intf->hw_idx] = child_dev_intf; + + of_node_put(child_node); + } + + enc_hw = (struct cam_hw_info *) + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC][0]->hw_priv; + enc_soc_info = &enc_hw->soc_info; + g_jpeg_hw_mgr.cdm_reg_map[CAM_JPEG_DEV_ENC][0] = + &enc_soc_info->reg_map[0]; + dma_hw = (struct cam_hw_info *) + g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA][0]->hw_priv; + dma_soc_info = &dma_hw->soc_info; + g_jpeg_hw_mgr.cdm_reg_map[CAM_JPEG_DEV_DMA][0] = + &dma_soc_info->reg_map[0]; + + *p_num_enc_dev = num_dev; + *p_num_dma_dev = num_dma_dev; + + return rc; + +compat_hw_name_failed: + kfree(g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_DMA]); +num_dma_failed: + kfree(g_jpeg_hw_mgr.devices[CAM_JPEG_DEV_ENC]); +num_enc_failed: +num_dev_failed: + + return rc; +} + +static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_JPEG, "Invalid arguments"); + return -EINVAL; + } + + switch (hw_cmd_args->cmd_type) { + case CAM_HW_MGR_CMD_DUMP_PF_INFO: + cam_jpeg_mgr_print_io_bufs( + hw_cmd_args->u.pf_args.pf_data.packet, + hw_mgr->iommu_hdl, + hw_mgr->iommu_sec_hdl, + hw_cmd_args->u.pf_args.buf_info, + hw_cmd_args->u.pf_args.mem_found); + break; + default: + CAM_ERR(CAM_JPEG, "Invalid cmd"); + } + + return rc; +} + +int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl, + int *iommu_hdl) +{ + int i, rc; + uint32_t num_dev; + uint32_t num_dma_dev; + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_iommu_handle cdm_handles; + + hw_mgr_intf = (struct cam_hw_mgr_intf *)hw_mgr_hdl; + if (!of_node || !hw_mgr_intf) { + CAM_ERR(CAM_JPEG, "Invalid args of_node %pK hw_mgr %pK", + of_node, hw_mgr_intf); + return -EINVAL; + } + + memset(hw_mgr_hdl, 0x0, sizeof(struct cam_hw_mgr_intf)); + hw_mgr_intf->hw_mgr_priv = &g_jpeg_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_jpeg_mgr_get_hw_caps; + hw_mgr_intf->hw_acquire = cam_jpeg_mgr_acquire_hw; + hw_mgr_intf->hw_release = cam_jpeg_mgr_release_hw; + hw_mgr_intf->hw_prepare_update = cam_jpeg_mgr_prepare_hw_update; + hw_mgr_intf->hw_config = cam_jpeg_mgr_config_hw; + hw_mgr_intf->hw_flush = cam_jpeg_mgr_hw_flush; + hw_mgr_intf->hw_stop = cam_jpeg_mgr_hw_stop; + hw_mgr_intf->hw_cmd = cam_jpeg_mgr_cmd; + + mutex_init(&g_jpeg_hw_mgr.hw_mgr_mutex); + spin_lock_init(&g_jpeg_hw_mgr.hw_mgr_lock); + + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) + mutex_init(&g_jpeg_hw_mgr.ctx_data[i].ctx_mutex); + + rc = cam_jpeg_init_devices(of_node, &num_dev, &num_dma_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg init devices %d", rc); + goto smmu_get_failed; + } + + rc = cam_smmu_get_handle("jpeg", &g_jpeg_hw_mgr.iommu_hdl); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg get iommu handle failed %d", rc); + goto smmu_get_failed; + } + + CAM_DBG(CAM_JPEG, "mmu handle :%d", g_jpeg_hw_mgr.iommu_hdl); + + rc = cam_cdm_get_iommu_handle("jpegenc", &cdm_handles); + if (rc) { + CAM_ERR(CAM_JPEG, "acquire cdm iommu handle Fail %d", rc); + g_jpeg_hw_mgr.cdm_iommu_hdl = -1; + g_jpeg_hw_mgr.cdm_iommu_hdl_secure = -1; + goto cdm_iommu_failed; + } + g_jpeg_hw_mgr.cdm_iommu_hdl = cdm_handles.non_secure; + g_jpeg_hw_mgr.cdm_iommu_hdl_secure = cdm_handles.secure; + + g_jpeg_hw_mgr.jpeg_caps.dev_iommu_handle.non_secure = + g_jpeg_hw_mgr.iommu_hdl; + g_jpeg_hw_mgr.jpeg_caps.dev_iommu_handle.secure = + g_jpeg_hw_mgr.iommu_sec_hdl; + g_jpeg_hw_mgr.jpeg_caps.cdm_iommu_handle.non_secure = + g_jpeg_hw_mgr.cdm_iommu_hdl; + g_jpeg_hw_mgr.jpeg_caps.cdm_iommu_handle.secure = + g_jpeg_hw_mgr.cdm_iommu_hdl_secure; + g_jpeg_hw_mgr.jpeg_caps.num_enc = num_dev; + g_jpeg_hw_mgr.jpeg_caps.num_dma = num_dma_dev; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.major = 4; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.minor = 2; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.incr = 0; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_ENC].hw_ver.reserved = 0; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.major = 4; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.minor = 2; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.incr = 0; + g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.reserved = 0; + + rc = cam_jpeg_setup_workqs(); + if (rc) { + CAM_ERR(CAM_JPEG, "setup work qs failed %d", rc); + goto cdm_iommu_failed; + } + + if (iommu_hdl) + *iommu_hdl = g_jpeg_hw_mgr.iommu_hdl; + + return rc; + +cdm_iommu_failed: + cam_smmu_destroy_handle(g_jpeg_hw_mgr.iommu_hdl); + g_jpeg_hw_mgr.iommu_hdl = 0; +smmu_get_failed: + mutex_destroy(&g_jpeg_hw_mgr.hw_mgr_mutex); + for (i = 0; i < CAM_JPEG_CTX_MAX; i++) + mutex_destroy(&g_jpeg_hw_mgr.ctx_data[i].ctx_mutex); + + return rc; +} diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..e482c11a82bd6033a32c8b871adce4a8766e7f18 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_HW_MGR_H +#define CAM_JPEG_HW_MGR_H + +#include <linux/types.h> +#include <linux/completion.h> +#include <media/cam_jpeg.h> + +#include "cam_jpeg_hw_intf.h" +#include "cam_hw_mgr_intf.h" +#include "cam_hw_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_mem_mgr.h" + +#define CAM_JPEG_WORKQ_NUM_TASK 30 +#define CAM_JPEG_WORKQ_TASK_CMD_TYPE 1 +#define CAM_JPEG_WORKQ_TASK_MSG_TYPE 2 +#define CAM_JPEG_HW_CFG_Q_MAX 50 + +/** + * struct cam_jpeg_process_frame_work_data_t + * + * @type: Task type + * @data: Pointer to command data + * @request_id: Request id + */ +struct cam_jpeg_process_frame_work_data_t { + uint32_t type; + void *data; + uintptr_t request_id; +}; + +/** + * struct cam_jpeg_process_irq_work_data_t + * + * @type: Task type + * @data: Pointer to message data + * @result_size: Result size of enc/dma + * @irq_status: IRQ status + */ +struct cam_jpeg_process_irq_work_data_t { + uint32_t type; + void *data; + int32_t result_size; + uint32_t irq_status; +}; + +/** + * struct cam_jpeg_hw_cdm_info_t + * + * @ref_cnt: Ref count of how many times device type is acquired + * @cdm_handle: Cdm handle + * @cdm_ops: Cdm ops struct + */ +struct cam_jpeg_hw_cdm_info_t { + int ref_cnt; + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; +}; + +/** + * struct cam_jpeg_hw_cfg_req_t + * + * @list_head: List head + * @hw_cfg_args: Hw config args + * @dev_type: Dev type for cfg request + * @req_id: Request Id + */ +struct cam_jpeg_hw_cfg_req { + struct list_head list; + struct cam_hw_config_args hw_cfg_args; + uint32_t dev_type; + uintptr_t req_id; +}; + +/** + * struct cam_jpeg_hw_ctx_data + * + * @context_priv: Context private data, cam_context from + * acquire. + * @ctx_mutex: Mutex for context + * @jpeg_dev_acquire_info: Acquire device info + * @ctxt_event_cb: Context callback function + * @in_use: Flag for context usage + * @wait_complete: Completion info + * @cdm_cmd: Cdm cmd submitted for that context. + */ +struct cam_jpeg_hw_ctx_data { + void *context_priv; + struct mutex ctx_mutex; + struct cam_jpeg_acquire_dev_info jpeg_dev_acquire_info; + cam_hw_event_cb_func ctxt_event_cb; + bool in_use; + struct completion wait_complete; + struct cam_cdm_bl_request *cdm_cmd; +}; + +/** + * struct cam_jpeg_hw_mgr + * @hw_mgr_mutex: Mutex for JPEG hardware manager + * @hw_mgr_lock: Spinlock for JPEG hardware manager + * @ctx_data: Context data + * @jpeg_caps: JPEG capabilities + * @iommu_hdl: Non secure IOMMU handle + * @iommu_sec_hdl: Secure IOMMU handle + * @work_process_frame: Work queue for hw config requests + * @work_process_irq_cb: Work queue for processing IRQs. + * @process_frame_work_data: Work data pool for hw config + * requests + * @process_irq_cb_work_data: Work data pool for irq requests + * @cdm_iommu_hdl: Iommu handle received from cdm + * @cdm_iommu_hdl_secure: Secure iommu handle received from cdm + * @devices: Core hw Devices of JPEG hardware manager + * @cdm_info: Cdm info for each core device. + * @cdm_reg_map: Regmap of each device for cdm. + * @device_in_use: Flag device being used for an active request + * @dev_hw_cfg_args: Current cfg request per core dev + * @hw_config_req_list: Pending hw update requests list + * @free_req_list: Free nodes for above list + * @req_list: Nodes of hw update list + */ +struct cam_jpeg_hw_mgr { + struct mutex hw_mgr_mutex; + spinlock_t hw_mgr_lock; + struct cam_jpeg_hw_ctx_data ctx_data[CAM_JPEG_CTX_MAX]; + struct cam_jpeg_query_cap_cmd jpeg_caps; + int32_t iommu_hdl; + int32_t iommu_sec_hdl; + struct cam_req_mgr_core_workq *work_process_frame; + struct cam_req_mgr_core_workq *work_process_irq_cb; + struct cam_jpeg_process_frame_work_data_t *process_frame_work_data; + struct cam_jpeg_process_irq_work_data_t *process_irq_cb_work_data; + int cdm_iommu_hdl; + int cdm_iommu_hdl_secure; + + struct cam_hw_intf **devices[CAM_JPEG_DEV_TYPE_MAX]; + struct cam_jpeg_hw_cdm_info_t cdm_info[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + struct cam_soc_reg_map *cdm_reg_map[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + uint32_t device_in_use[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + struct cam_jpeg_hw_cfg_req *dev_hw_cfg_args[CAM_JPEG_DEV_TYPE_MAX] + [CAM_JPEG_NUM_DEV_PER_RES_MAX]; + + struct list_head hw_config_req_list; + struct list_head free_req_list; + struct cam_jpeg_hw_cfg_req req_list[CAM_JPEG_HW_CFG_Q_MAX]; +}; + +#endif /* CAM_JPEG_HW_MGR_H */ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..1b93547fdf2565e839d57f9ed3c78ea69d3da9f4 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_HW_INTF_H +#define CAM_JPEG_HW_INTF_H + +#include "cam_cpas_api.h" + +#define CAM_JPEG_CTX_MAX 8 +#define CAM_JPEG_DEV_PER_TYPE_MAX 1 + +#define CAM_JPEG_CMD_BUF_MAX_SIZE 128 +#define CAM_JPEG_MSG_BUF_MAX_SIZE CAM_JPEG_CMD_BUF_MAX_SIZE + +#define JPEG_VOTE 640000000 + +enum cam_jpeg_hw_type { + CAM_JPEG_DEV_ENC, + CAM_JPEG_DEV_DMA, +}; + +struct cam_jpeg_set_irq_cb { + int32_t (*jpeg_hw_mgr_cb)(uint32_t irq_status, + int32_t result_size, void *data); + void *data; + uint32_t b_set_cb; +}; + +enum cam_jpeg_cmd_type { + CAM_JPEG_CMD_CDM_CFG, + CAM_JPEG_CMD_SET_IRQ_CB, + CAM_JPEG_CMD_MAX, +}; + +#endif diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..30c51f7cfcfd9e80bbe1ceb299b8926738879910 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_HW_MGR_INTF_H +#define CAM_JPEG_HW_MGR_INTF_H + +#include <linux/of.h> +#include <media/cam_jpeg.h> +#include <media/cam_defs.h> + +int cam_jpeg_hw_mgr_init(struct device_node *of_node, + uint64_t *hw_mgr_hdl, int *iommu_hdl); + +#endif /* CAM_JPEG_HW_MGR_INTF_H */ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f0162f98833a4f8613053718a8e2b6ce5511c04e --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_dma_dev.o jpeg_dma_core.o jpeg_dma_soc.o diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c new file mode 100644 index 0000000000000000000000000000000000000000..1304bbc71d389daa5ee9de31df72fe5ceab1a0b0 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/timer.h> + +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "jpeg_dma_core.h" +#include "jpeg_dma_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +int cam_jpeg_dma_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (++core_info->ref_count > 1) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ib_bw = JPEG_VOTE; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ib_bw = JPEG_VOTE; + + + rc = cam_cpas_start(core_info->cpas_handle, + &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_JPEG, "cpass start failed: %d", rc); + goto cpas_failed; + } + + rc = cam_jpeg_dma_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); + goto soc_failed; + } + + mutex_unlock(&core_info->core_mutex); + + return 0; + +soc_failed: + cam_cpas_stop(core_info->cpas_handle); +cpas_failed: + --core_info->ref_count; + mutex_unlock(&core_info->core_mutex); + + return rc; +} + +int cam_jpeg_dma_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_dma_dev->soc_info; + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (--core_info->ref_count > 0) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + if (core_info->ref_count < 0) { + CAM_ERR(CAM_JPEG, "ref cnt %d", core_info->ref_count); + core_info->ref_count = 0; + mutex_unlock(&core_info->core_mutex); + return -EFAULT; + } + + rc = cam_jpeg_dma_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "soc enable failed %d", rc); + + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas stop failed: %d", rc); + + mutex_unlock(&core_info->core_mutex); + + return 0; +} + +int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_dma_dev = device_priv; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_JPEG_CMD_MAX) { + CAM_ERR(CAM_JPEG, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + + switch (cmd_type) { + case CAM_JPEG_CMD_SET_IRQ_CB: + { + struct cam_jpeg_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_JPEG, "cmd args NULL"); + return -EINVAL; + } + if (irq_cb->b_set_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb = + irq_cb->jpeg_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + } else { + core_info->irq_cb.jpeg_hw_mgr_cb = NULL; + core_info->irq_cb.data = NULL; + } + rc = 0; + break; + } + default: + rc = -EINVAL; + break; + } + + return rc; +} + +irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h new file mode 100644 index 0000000000000000000000000000000000000000..dc3a1c13fe829b6120efc80a1f5722013180530f --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_DMA_CORE_H +#define CAM_JPEG_DMA_CORE_H + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "cam_jpeg_hw_intf.h" + +struct cam_jpeg_dma_device_hw_info { + uint32_t reserved; +}; + +enum cam_jpeg_dma_core_state { + CAM_JPEG_DMA_CORE_NOT_READY, + CAM_JPEG_DMA_CORE_READY, + CAM_JPEG_DMA_CORE_RESETTING, + CAM_JPEG_DMA_CORE_STATE_MAX, +}; + +struct cam_jpeg_dma_device_core_info { + enum cam_jpeg_dma_core_state core_state; + struct cam_jpeg_dma_device_hw_info *jpeg_dma_hw_info; + uint32_t cpas_handle; + struct cam_jpeg_set_irq_cb irq_cb; + int32_t ref_count; + struct mutex core_mutex; +}; + +int cam_jpeg_dma_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_dma_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_jpeg_dma_irq(int irq_num, void *data); + +#endif /* CAM_JPEG_DMA_CORE_H */ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..ce82c5e799c5fe1c8ead1694326271df0cc7eab5 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include <linux/timer.h> + +#include "jpeg_dma_core.h" +#include "jpeg_dma_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +static struct cam_jpeg_dma_device_hw_info cam_jpeg_dma_hw_info = { + .reserved = 0, +}; +EXPORT_SYMBOL(cam_jpeg_dma_hw_info); + +static int cam_jpeg_dma_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_jpeg_dma_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = soc_info->dev; + memcpy(cpas_register_params.identifier, "jpeg-dma", + sizeof("jpeg-dma")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc) { + CAM_ERR(CAM_JPEG, "cpas_register failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +static int cam_jpeg_dma_unregister_cpas( + struct cam_jpeg_dma_device_core_info *core_info) +{ + int rc; + + rc = cam_cpas_unregister_client(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas unregister failed: %d", rc); + core_info->cpas_handle = 0; + + return rc; +} + +static int cam_jpeg_dma_remove(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_dma_dev = NULL; + struct cam_hw_intf *jpeg_dma_dev_intf = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + int rc; + + jpeg_dma_dev_intf = platform_get_drvdata(pdev); + if (!jpeg_dma_dev_intf) { + CAM_ERR(CAM_JPEG, "error No data in pdev"); + return -EINVAL; + } + + jpeg_dma_dev = jpeg_dma_dev_intf->hw_priv; + if (!jpeg_dma_dev) { + CAM_ERR(CAM_JPEG, "error HW data is NULL"); + rc = -ENODEV; + goto free_jpeg_hw_intf; + } + + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + if (!core_info) { + CAM_ERR(CAM_JPEG, "error core data NULL"); + goto deinit_soc; + } + + rc = cam_jpeg_dma_unregister_cpas(core_info); + if (rc) + CAM_ERR(CAM_JPEG, " unreg failed to reg cpas %d", rc); + + mutex_destroy(&core_info->core_mutex); + kfree(core_info); + +deinit_soc: + rc = cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&jpeg_dma_dev->hw_mutex); + kfree(jpeg_dma_dev); + +free_jpeg_hw_intf: + kfree(jpeg_dma_dev_intf); + return rc; +} + +static int cam_jpeg_dma_probe(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_dma_dev = NULL; + struct cam_hw_intf *jpeg_dma_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_jpeg_dma_device_core_info *core_info = NULL; + struct cam_jpeg_dma_device_hw_info *hw_info = NULL; + int rc; + + jpeg_dma_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!jpeg_dma_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &jpeg_dma_dev_intf->hw_idx); + + jpeg_dma_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!jpeg_dma_dev) { + rc = -ENOMEM; + goto error_alloc_dev; + } + jpeg_dma_dev->soc_info.pdev = pdev; + jpeg_dma_dev->soc_info.dev = &pdev->dev; + jpeg_dma_dev->soc_info.dev_name = pdev->name; + jpeg_dma_dev_intf->hw_priv = jpeg_dma_dev; + jpeg_dma_dev_intf->hw_ops.init = cam_jpeg_dma_init_hw; + jpeg_dma_dev_intf->hw_ops.deinit = cam_jpeg_dma_deinit_hw; + jpeg_dma_dev_intf->hw_ops.process_cmd = cam_jpeg_dma_process_cmd; + jpeg_dma_dev_intf->hw_type = CAM_JPEG_DEV_DMA; + + platform_set_drvdata(pdev, jpeg_dma_dev_intf); + jpeg_dma_dev->core_info = + kzalloc(sizeof(struct cam_jpeg_dma_device_core_info), + GFP_KERNEL); + if (!jpeg_dma_dev->core_info) { + rc = -ENOMEM; + goto error_alloc_core; + } + core_info = (struct cam_jpeg_dma_device_core_info *) + jpeg_dma_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_JPEG, " No jpeg_dma hardware info"); + rc = -EINVAL; + goto error_match_dev; + } + hw_info = (struct cam_jpeg_dma_device_hw_info *)match_dev->data; + core_info->jpeg_dma_hw_info = hw_info; + core_info->core_state = CAM_JPEG_DMA_CORE_NOT_READY; + mutex_init(&core_info->core_mutex); + + rc = cam_jpeg_dma_init_soc_resources(&jpeg_dma_dev->soc_info, + cam_jpeg_dma_irq, + jpeg_dma_dev); + if (rc) { + CAM_ERR(CAM_JPEG, "failed to init_soc %d", rc); + goto error_init_soc; + } + + rc = cam_jpeg_dma_register_cpas(&jpeg_dma_dev->soc_info, + core_info, jpeg_dma_dev_intf->hw_idx); + if (rc) { + CAM_ERR(CAM_JPEG, " failed to reg cpas %d", rc); + goto error_reg_cpas; + } + jpeg_dma_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&jpeg_dma_dev->hw_mutex); + spin_lock_init(&jpeg_dma_dev->hw_lock); + init_completion(&jpeg_dma_dev->hw_complete); + + CAM_DBG(CAM_JPEG, " hwidx %d", jpeg_dma_dev_intf->hw_idx); + + return rc; + +error_reg_cpas: + rc = cam_soc_util_release_platform_resource(&jpeg_dma_dev->soc_info); +error_init_soc: + mutex_destroy(&core_info->core_mutex); +error_match_dev: + kfree(jpeg_dma_dev->core_info); +error_alloc_core: + kfree(jpeg_dma_dev); +error_alloc_dev: + kfree(jpeg_dma_dev_intf); + return rc; +} + +static const struct of_device_id cam_jpeg_dma_dt_match[] = { + { + .compatible = "qcom,cam_jpeg_dma", + .data = &cam_jpeg_dma_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_jpeg_dma_dt_match); + +static struct platform_driver cam_jpeg_dma_driver = { + .probe = cam_jpeg_dma_probe, + .remove = cam_jpeg_dma_remove, + .driver = { + .name = "cam-jpeg-dma", + .owner = THIS_MODULE, + .of_match_table = cam_jpeg_dma_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_jpeg_dma_init_module(void) +{ + return platform_driver_register(&cam_jpeg_dma_driver); +} + +static void __exit cam_jpeg_dma_exit_module(void) +{ + platform_driver_unregister(&cam_jpeg_dma_driver); +} + +module_init(cam_jpeg_dma_init_module); +module_exit(cam_jpeg_dma_exit_module); +MODULE_DESCRIPTION("CAM JPEG_DMA driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..9dda8f284c354ea8d9f0925693f058e84364723f --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/cam_defs.h> +#include <media/cam_jpeg.h> + +#include "jpeg_dma_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +int cam_jpeg_dma_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_dma_irq_handler, void *irq_data) +{ + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_request_platform_resource(soc_info, + jpeg_dma_irq_handler, + irq_data); + if (rc) + CAM_ERR(CAM_JPEG, "init soc failed %d", rc); + + return rc; +} + +int cam_jpeg_dma_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) + CAM_ERR(CAM_JPEG, "enable platform failed %d", rc); + + return rc; +} + +int cam_jpeg_dma_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_JPEG, "disable platform failed %d", rc); + + return rc; +} diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..a0c07489ee77e71226a825a6041b6fb736865ff3 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_DMA_SOC_H_ +#define _CAM_JPEG_DMA_SOC_H_ + +#include "cam_soc_util.h" + +int cam_jpeg_dma_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_dma_irq_handler, void *irq_data); + +int cam_jpeg_dma_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_jpeg_dma_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_JPEG_DMA_SOC_H_*/ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..159c54bbed0cda6df85f4d8f404d0a6ee15bdd41 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_hw_mgr/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_enc_dev.o jpeg_enc_core.o jpeg_enc_soc.o diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h new file mode 100644 index 0000000000000000000000000000000000000000..e610a9e7ee038c9070dc6bdb2b6d5328a824fa80 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_ENC_HW_INFO_TITAN170_H +#define CAM_JPEG_ENC_HW_INFO_TITAN170_H + +#define CAM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK 0x00000001 +#define CAM_JPEG_HW_IRQ_STATUS_FRAMEDONE_SHIFT 0x00000000 + +#define CAM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK 0x10000000 +#define CAM_JPEG_HW_IRQ_STATUS_RESET_ACK_SHIFT 0x0000000a + +#define CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK 0x8000000 +#define CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_SHIFT 0x0000001b + +#define CAM_JPEG_HW_IRQ_STATUS_BUS_ERROR_MASK 0x00000800 +#define CAM_JPEG_HW_IRQ_STATUS_BUS_ERROR_SHIFT 0x0000000b + +#define CAM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF (0x1<<19) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR (0x1<<20) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR (0x1<<21) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF (0x1<<22) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW (0x1<<23) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM (0x1<<24) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ (0x1<<25) +#define CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM (0x1<<26) +#define CAM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK (0x1<<29) + +#define CAM_JPEG_HW_MASK_COMP_FRAMEDONE \ + CAM_JPEG_HW_IRQ_STATUS_FRAMEDONE_MASK +#define CAM_JPEG_HW_MASK_COMP_RESET_ACK \ + CAM_JPEG_HW_IRQ_STATUS_RESET_ACK_MASK +#define CAM_JPEG_HW_MASK_COMP_ERR \ + (CAM_JPEG_HW_IRQ_STATUS_DCD_UNESCAPED_FF | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_HUFFMAN_ERROR | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_COEFFICIENT_ERR | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_BIT_STUFF | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_SCAN_UNDERFLOW | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_INVALID_RSM_SEQ | \ + CAM_JPEG_HW_IRQ_STATUS_DCD_MISSING_RSM | \ + CAM_JPEG_HW_IRQ_STATUS_VIOLATION_MASK) + +static struct cam_jpeg_enc_device_hw_info cam_jpeg_enc_hw_info = { + .reg_offset = { + .hw_version = 0x0, + .int_clr = 0x1c, + .int_status = 0x20, + .int_mask = 0x18, + .hw_cmd = 0x10, + .reset_cmd = 0x8, + .encode_size = 0x180, + }, + .reg_val = { + .int_clr_clearall = 0xFFFFFFFF, + .int_mask_disable_all = 0x00000000, + .int_mask_enable_all = 0xFFFFFFFF, + .hw_cmd_start = 0x00000001, + .reset_cmd = 0x200320D3, + .hw_cmd_stop = 0x00000002, + }, + .int_status = { + .framedone = CAM_JPEG_HW_MASK_COMP_FRAMEDONE, + .resetdone = CAM_JPEG_HW_MASK_COMP_RESET_ACK, + .iserror = CAM_JPEG_HW_MASK_COMP_ERR, + .stopdone = CAM_JPEG_HW_IRQ_STATUS_STOP_DONE_MASK, + } +}; + +#endif /* CAM_JPEG_ENC_HW_INFO_TITAN170_H */ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c new file mode 100644 index 0000000000000000000000000000000000000000..4830bf58e89eabf512175afb6c4f1200ffff7366 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/debugfs.h> +#include <linux/videodev2.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/timer.h> + +#include "cam_io_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "jpeg_enc_core.h" +#include "jpeg_enc_soc.h" +#include "cam_soc_util.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" + +#define CAM_JPEG_HW_IRQ_IS_FRAME_DONE(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.framedone) +#define CAM_JPEG_HW_IRQ_IS_RESET_ACK(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.resetdone) +#define CAM_JPEG_HW_IRQ_IS_ERR(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.iserror) +#define CAM_JPEG_HW_IRQ_IS_STOP_DONE(jpeg_irq_status, hi) \ + ((jpeg_irq_status) & (hi)->int_status.stopdone) + +#define CAM_JPEG_ENC_RESET_TIMEOUT msecs_to_jiffies(500) + +int cam_jpeg_enc_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (++core_info->ref_count > 1) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[0].mnoc_ib_bw = JPEG_VOTE; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ab_bw = JPEG_VOTE; + axi_vote.axi_path[1].mnoc_ib_bw = JPEG_VOTE; + + + rc = cam_cpas_start(core_info->cpas_handle, + &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_JPEG, "cpass start failed: %d", rc); + goto cpas_failed; + } + + rc = cam_jpeg_enc_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_JPEG, "soc enable is failed %d", rc); + goto soc_failed; + } + + mutex_unlock(&core_info->core_mutex); + + return 0; + +soc_failed: + cam_cpas_stop(core_info->cpas_handle); +cpas_failed: + --core_info->ref_count; + mutex_unlock(&core_info->core_mutex); + + return rc; +} + +int cam_jpeg_enc_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = device_priv; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid cam_dev_info"); + return -EINVAL; + } + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + if (!soc_info || !core_info) { + CAM_ERR(CAM_JPEG, "soc_info = %pK core_info = %pK", + soc_info, core_info); + return -EINVAL; + } + + mutex_lock(&core_info->core_mutex); + if (--core_info->ref_count > 0) { + mutex_unlock(&core_info->core_mutex); + return 0; + } + + if (core_info->ref_count < 0) { + CAM_ERR(CAM_JPEG, "ref cnt %d", core_info->ref_count); + core_info->ref_count = 0; + mutex_unlock(&core_info->core_mutex); + return -EFAULT; + } + + rc = cam_jpeg_enc_disable_soc_resources(soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "soc disable failed %d", rc); + + rc = cam_cpas_stop(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas stop failed: %d", rc); + + mutex_unlock(&core_info->core_mutex); + + return 0; +} + +irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + uint32_t irq_status = 0; + uint32_t encoded_size = 0; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return IRQ_HANDLED; + } + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + irq_status = cam_io_r_mb(mem_base + + core_info->jpeg_enc_hw_info->reg_offset.int_status); + + cam_io_w_mb(irq_status, + soc_info->reg_map[0].mem_base + + core_info->jpeg_enc_hw_info->reg_offset.int_clr); + + CAM_DBG(CAM_JPEG, "irq_num %d irq_status = %x , core_state %d", + irq_num, irq_status, core_info->core_state); + + if (CAM_JPEG_HW_IRQ_IS_FRAME_DONE(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_READY) { + encoded_size = cam_io_r_mb(mem_base + + core_info->jpeg_enc_hw_info->reg_offset.encode_size); + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + encoded_size, + core_info->irq_cb.data); + } else { + CAM_ERR(CAM_JPEG, "unexpected done, no cb"); + } + } else { + CAM_ERR(CAM_JPEG, "unexpected done irq"); + } + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + spin_unlock(&jpeg_enc_dev->hw_lock); + } + if (CAM_JPEG_HW_IRQ_IS_RESET_ACK(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { + core_info->core_state = CAM_JPEG_ENC_CORE_READY; + complete(&jpeg_enc_dev->hw_complete); + } else { + CAM_ERR(CAM_JPEG, "unexpected reset irq"); + } + spin_unlock(&jpeg_enc_dev->hw_lock); + } + if (CAM_JPEG_HW_IRQ_IS_STOP_DONE(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + complete(&jpeg_enc_dev->hw_complete); + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + -1, + core_info->irq_cb.data); + } + } else { + CAM_ERR(CAM_JPEG, "unexpected abort irq"); + } + spin_unlock(&jpeg_enc_dev->hw_lock); + } + /* Unexpected/unintended HW interrupt */ + if (CAM_JPEG_HW_IRQ_IS_ERR(irq_status, hw_info)) { + spin_lock(&jpeg_enc_dev->hw_lock); + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + CAM_ERR_RATE_LIMIT(CAM_JPEG, + "error irq_num %d irq_status = %x , core_state %d", + irq_num, irq_status, core_info->core_state); + + if (core_info->irq_cb.jpeg_hw_mgr_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb(irq_status, + -1, + core_info->irq_cb.data); + } + spin_unlock(&jpeg_enc_dev->hw_lock); + } + + return IRQ_HANDLED; +} + +int cam_jpeg_enc_reset_hw(void *data, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + unsigned long rem_jiffies; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + /* maskdisable.clrirq.maskenable.resetcmd */ + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_RESETTING) { + CAM_ERR(CAM_JPEG, "alrady resetting"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return 0; + } + + reinit_completion(&jpeg_enc_dev->hw_complete); + core_info->core_state = CAM_JPEG_ENC_CORE_RESETTING; + spin_unlock(&jpeg_enc_dev->hw_lock); + + cam_io_w_mb(hw_info->reg_val.int_mask_disable_all, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.int_clr_clearall, + mem_base + hw_info->reg_offset.int_clr); + cam_io_w_mb(hw_info->reg_val.int_mask_enable_all, + mem_base + hw_info->reg_offset.int_mask); + cam_io_w_mb(hw_info->reg_val.reset_cmd, + mem_base + hw_info->reg_offset.reset_cmd); + + rem_jiffies = wait_for_completion_timeout(&jpeg_enc_dev->hw_complete, + CAM_JPEG_ENC_RESET_TIMEOUT); + if (!rem_jiffies) { + CAM_ERR(CAM_JPEG, "error Reset Timeout"); + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + } + + mutex_unlock(&core_info->core_mutex); + return 0; +} + +int cam_jpeg_enc_start_hw(void *data, + void *start_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + if (core_info->core_state != CAM_JPEG_ENC_CORE_READY) { + CAM_ERR(CAM_JPEG, "Error not ready"); + return -EINVAL; + } + + cam_io_w_mb(hw_info->reg_val.hw_cmd_start, + mem_base + hw_info->reg_offset.hw_cmd); + + return 0; +} + +int cam_jpeg_enc_stop_hw(void *data, + void *stop_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = data; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + void __iomem *mem_base; + unsigned long rem_jiffies; + + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "Invalid args"); + return -EINVAL; + } + soc_info = &jpeg_enc_dev->soc_info; + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + hw_info = core_info->jpeg_enc_hw_info; + mem_base = soc_info->reg_map[0].mem_base; + + mutex_lock(&core_info->core_mutex); + spin_lock(&jpeg_enc_dev->hw_lock); + if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { + CAM_ERR(CAM_JPEG, "alrady stopping"); + spin_unlock(&jpeg_enc_dev->hw_lock); + mutex_unlock(&core_info->core_mutex); + return 0; + } + + reinit_completion(&jpeg_enc_dev->hw_complete); + core_info->core_state = CAM_JPEG_ENC_CORE_ABORTING; + spin_unlock(&jpeg_enc_dev->hw_lock); + + cam_io_w_mb(hw_info->reg_val.hw_cmd_stop, + mem_base + hw_info->reg_offset.hw_cmd); + + rem_jiffies = wait_for_completion_timeout(&jpeg_enc_dev->hw_complete, + CAM_JPEG_ENC_RESET_TIMEOUT); + if (!rem_jiffies) { + CAM_ERR(CAM_JPEG, "error Reset Timeout"); + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + } + + mutex_unlock(&core_info->core_mutex); + return 0; +} + +int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *jpeg_enc_dev = device_priv; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + int rc; + + if (!device_priv) { + CAM_ERR(CAM_JPEG, "Invalid arguments"); + return -EINVAL; + } + + if (cmd_type >= CAM_JPEG_CMD_MAX) { + CAM_ERR(CAM_JPEG, "Invalid command : %x", cmd_type); + return -EINVAL; + } + + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + + switch (cmd_type) { + case CAM_JPEG_CMD_SET_IRQ_CB: + { + struct cam_jpeg_set_irq_cb *irq_cb = cmd_args; + + if (!cmd_args) { + CAM_ERR(CAM_JPEG, "cmd args NULL"); + return -EINVAL; + } + if (irq_cb->b_set_cb) { + core_info->irq_cb.jpeg_hw_mgr_cb = + irq_cb->jpeg_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + } else { + core_info->irq_cb.jpeg_hw_mgr_cb = NULL; + core_info->irq_cb.data = NULL; + } + rc = 0; + break; + } + default: + rc = -EINVAL; + break; + } + if (rc) + CAM_ERR(CAM_JPEG, "error cmdtype %d rc = %d", cmd_type, rc); + return rc; +} diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h new file mode 100644 index 0000000000000000000000000000000000000000..df9341c90c7768bada0c8bbc62d53faad7631e10 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef CAM_JPEG_ENC_CORE_H +#define CAM_JPEG_ENC_CORE_H + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "cam_jpeg_hw_intf.h" + +struct cam_jpeg_enc_reg_offsets { + uint32_t hw_version; + uint32_t int_status; + uint32_t int_clr; + uint32_t int_mask; + uint32_t hw_cmd; + uint32_t reset_cmd; + uint32_t encode_size; +}; + +struct cam_jpeg_enc_regval { + uint32_t int_clr_clearall; + uint32_t int_mask_disable_all; + uint32_t int_mask_enable_all; + uint32_t hw_cmd_start; + uint32_t reset_cmd; + uint32_t hw_cmd_stop; +}; + +struct cam_jpeg_enc_int_status { + uint32_t framedone; + uint32_t resetdone; + uint32_t iserror; + uint32_t stopdone; +}; + +struct cam_jpeg_enc_device_hw_info { + struct cam_jpeg_enc_reg_offsets reg_offset; + struct cam_jpeg_enc_regval reg_val; + struct cam_jpeg_enc_int_status int_status; +}; + +enum cam_jpeg_enc_core_state { + CAM_JPEG_ENC_CORE_NOT_READY, + CAM_JPEG_ENC_CORE_READY, + CAM_JPEG_ENC_CORE_RESETTING, + CAM_JPEG_ENC_CORE_ABORTING, + CAM_JPEG_ENC_CORE_STATE_MAX, +}; + +struct cam_jpeg_enc_device_core_info { + enum cam_jpeg_enc_core_state core_state; + struct cam_jpeg_enc_device_hw_info *jpeg_enc_hw_info; + uint32_t cpas_handle; + struct cam_jpeg_set_irq_cb irq_cb; + int32_t ref_count; + struct mutex core_mutex; +}; + +int cam_jpeg_enc_init_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_enc_deinit_hw(void *device_priv, + void *init_hw_args, uint32_t arg_size); +int cam_jpeg_enc_start_hw(void *device_priv, + void *start_hw_args, uint32_t arg_size); +int cam_jpeg_enc_stop_hw(void *device_priv, + void *stop_hw_args, uint32_t arg_size); +int cam_jpeg_enc_reset_hw(void *device_priv, + void *reset_hw_args, uint32_t arg_size); +int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +irqreturn_t cam_jpeg_enc_irq(int irq_num, void *data); + +#endif /* CAM_JPEG_ENC_CORE_H */ diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..8eb8ec36785082d29dee6075bd19f626170dcfe5 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/of_device.h> +#include <linux/timer.h> + +#include "jpeg_enc_core.h" +#include "jpeg_enc_soc.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_io_util.h" +#include "cam_jpeg_hw_intf.h" +#include "cam_jpeg_hw_mgr_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_jpeg_enc_hw_info_ver_4_2_0.h" + +static int cam_jpeg_enc_register_cpas(struct cam_hw_soc_info *soc_info, + struct cam_jpeg_enc_device_core_info *core_info, + uint32_t hw_idx) +{ + struct cam_cpas_register_params cpas_register_params; + int rc; + + cpas_register_params.dev = soc_info->dev; + memcpy(cpas_register_params.identifier, "jpeg-enc", + sizeof("jpeg-enc")); + cpas_register_params.cam_cpas_client_cb = NULL; + cpas_register_params.cell_index = hw_idx; + cpas_register_params.userdata = NULL; + + rc = cam_cpas_register_client(&cpas_register_params); + if (rc) { + CAM_ERR(CAM_JPEG, "cpas_register failed: %d", rc); + return rc; + } + core_info->cpas_handle = cpas_register_params.client_handle; + + return rc; +} + +static int cam_jpeg_enc_unregister_cpas( + struct cam_jpeg_enc_device_core_info *core_info) +{ + int rc; + + rc = cam_cpas_unregister_client(core_info->cpas_handle); + if (rc) + CAM_ERR(CAM_JPEG, "cpas unregister failed: %d", rc); + core_info->cpas_handle = 0; + + return rc; +} + +static int cam_jpeg_enc_remove(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_enc_dev = NULL; + struct cam_hw_intf *jpeg_enc_dev_intf = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + int rc; + + jpeg_enc_dev_intf = platform_get_drvdata(pdev); + if (!jpeg_enc_dev_intf) { + CAM_ERR(CAM_JPEG, "error No data in pdev"); + return -EINVAL; + } + + jpeg_enc_dev = jpeg_enc_dev_intf->hw_priv; + if (!jpeg_enc_dev) { + CAM_ERR(CAM_JPEG, "error HW data is NULL"); + rc = -ENODEV; + goto free_jpeg_hw_intf; + } + + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + if (!core_info) { + CAM_ERR(CAM_JPEG, "error core data NULL"); + goto deinit_soc; + } + + rc = cam_jpeg_enc_unregister_cpas(core_info); + if (rc) + CAM_ERR(CAM_JPEG, " unreg failed to reg cpas %d", rc); + + mutex_destroy(&core_info->core_mutex); + kfree(core_info); + +deinit_soc: + rc = cam_soc_util_release_platform_resource(&jpeg_enc_dev->soc_info); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to deinit soc rc=%d", rc); + + mutex_destroy(&jpeg_enc_dev->hw_mutex); + kfree(jpeg_enc_dev); + +free_jpeg_hw_intf: + kfree(jpeg_enc_dev_intf); + return rc; +} + +static int cam_jpeg_enc_probe(struct platform_device *pdev) +{ + struct cam_hw_info *jpeg_enc_dev = NULL; + struct cam_hw_intf *jpeg_enc_dev_intf = NULL; + const struct of_device_id *match_dev = NULL; + struct cam_jpeg_enc_device_core_info *core_info = NULL; + struct cam_jpeg_enc_device_hw_info *hw_info = NULL; + int rc; + + jpeg_enc_dev_intf = kzalloc(sizeof(struct cam_hw_intf), GFP_KERNEL); + if (!jpeg_enc_dev_intf) + return -ENOMEM; + + of_property_read_u32(pdev->dev.of_node, + "cell-index", &jpeg_enc_dev_intf->hw_idx); + + jpeg_enc_dev = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!jpeg_enc_dev) { + rc = -ENOMEM; + goto error_alloc_dev; + } + jpeg_enc_dev->soc_info.pdev = pdev; + jpeg_enc_dev->soc_info.dev = &pdev->dev; + jpeg_enc_dev->soc_info.dev_name = pdev->name; + jpeg_enc_dev_intf->hw_priv = jpeg_enc_dev; + jpeg_enc_dev_intf->hw_ops.init = cam_jpeg_enc_init_hw; + jpeg_enc_dev_intf->hw_ops.deinit = cam_jpeg_enc_deinit_hw; + jpeg_enc_dev_intf->hw_ops.start = cam_jpeg_enc_start_hw; + jpeg_enc_dev_intf->hw_ops.stop = cam_jpeg_enc_stop_hw; + jpeg_enc_dev_intf->hw_ops.reset = cam_jpeg_enc_reset_hw; + jpeg_enc_dev_intf->hw_ops.process_cmd = cam_jpeg_enc_process_cmd; + jpeg_enc_dev_intf->hw_type = CAM_JPEG_DEV_ENC; + + platform_set_drvdata(pdev, jpeg_enc_dev_intf); + jpeg_enc_dev->core_info = + kzalloc(sizeof(struct cam_jpeg_enc_device_core_info), + GFP_KERNEL); + if (!jpeg_enc_dev->core_info) { + rc = -ENOMEM; + goto error_alloc_core; + } + core_info = (struct cam_jpeg_enc_device_core_info *) + jpeg_enc_dev->core_info; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev) { + CAM_ERR(CAM_JPEG, " No jpeg_enc hardware info"); + rc = -EINVAL; + goto error_match_dev; + } + hw_info = (struct cam_jpeg_enc_device_hw_info *)match_dev->data; + core_info->jpeg_enc_hw_info = hw_info; + core_info->core_state = CAM_JPEG_ENC_CORE_NOT_READY; + mutex_init(&core_info->core_mutex); + + rc = cam_jpeg_enc_init_soc_resources(&jpeg_enc_dev->soc_info, + cam_jpeg_enc_irq, + jpeg_enc_dev); + if (rc) { + CAM_ERR(CAM_JPEG, " failed to init_soc %d", rc); + goto error_init_soc; + } + + rc = cam_jpeg_enc_register_cpas(&jpeg_enc_dev->soc_info, + core_info, jpeg_enc_dev_intf->hw_idx); + if (rc) { + CAM_ERR(CAM_JPEG, " failed to reg cpas %d", rc); + goto error_reg_cpas; + } + jpeg_enc_dev->hw_state = CAM_HW_STATE_POWER_DOWN; + mutex_init(&jpeg_enc_dev->hw_mutex); + spin_lock_init(&jpeg_enc_dev->hw_lock); + init_completion(&jpeg_enc_dev->hw_complete); + + return rc; + +error_reg_cpas: + cam_soc_util_release_platform_resource(&jpeg_enc_dev->soc_info); +error_init_soc: + mutex_destroy(&core_info->core_mutex); +error_match_dev: + kfree(jpeg_enc_dev->core_info); +error_alloc_core: + kfree(jpeg_enc_dev); +error_alloc_dev: + kfree(jpeg_enc_dev_intf); + + return rc; +} + +static const struct of_device_id cam_jpeg_enc_dt_match[] = { + { + .compatible = "qcom,cam_jpeg_enc", + .data = &cam_jpeg_enc_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_jpeg_enc_dt_match); + +static struct platform_driver cam_jpeg_enc_driver = { + .probe = cam_jpeg_enc_probe, + .remove = cam_jpeg_enc_remove, + .driver = { + .name = "cam-jpeg-enc", + .owner = THIS_MODULE, + .of_match_table = cam_jpeg_enc_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_jpeg_enc_init_module(void) +{ + return platform_driver_register(&cam_jpeg_enc_driver); +} + +static void __exit cam_jpeg_enc_exit_module(void) +{ + platform_driver_unregister(&cam_jpeg_enc_driver); +} + +module_init(cam_jpeg_enc_init_module); +module_exit(cam_jpeg_enc_exit_module); +MODULE_DESCRIPTION("CAM JPEG_ENC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..4a5d9e0a9b600998583e39d12ff34f0530d003f0 --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <media/cam_defs.h> +#include <media/cam_jpeg.h> + +#include "jpeg_enc_soc.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +int cam_jpeg_enc_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_enc_irq_handler, void *irq_data) +{ + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_request_platform_resource(soc_info, + jpeg_enc_irq_handler, + irq_data); + if (rc) + CAM_ERR(CAM_JPEG, "init soc failed %d", rc); + + return rc; +} + +int cam_jpeg_enc_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, true); + if (rc) + CAM_ERR(CAM_JPEG, "enable platform failed %d", rc); + + return rc; +} + +int cam_jpeg_enc_disable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc; + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) + CAM_ERR(CAM_JPEG, "disable platform failed %d", rc); + + return rc; +} diff --git a/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..e0fb0103de7557b7c64f7307b06273bf4324987c --- /dev/null +++ b/techpack/camera/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_JPEG_ENC_SOC_H_ +#define _CAM_JPEG_ENC_SOC_H_ + +#include "cam_soc_util.h" + +int cam_jpeg_enc_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t jpeg_enc_irq_handler, void *irq_data); + +int cam_jpeg_enc_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +int cam_jpeg_enc_disable_soc_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_JPEG_ENC_SOC_H_*/ diff --git a/techpack/camera/drivers/cam_lrme/Makefile b/techpack/camera/drivers/cam_lrme/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..72cdba4da04c4b5c52b9ae582d8d6cab6112996d --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_dev.o cam_lrme_context.o diff --git a/techpack/camera/drivers/cam_lrme/cam_lrme_context.c b/techpack/camera/drivers/cam_lrme/cam_lrme_context.c new file mode 100644 index 0000000000000000000000000000000000000000..fa544c7a089ee6985d5edf34043cf25f5867a56b --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/cam_lrme_context.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_debug_util.h" +#include "cam_lrme_context.h" + +static const char lrme_dev_name[] = "cam-lrme"; + +static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + uintptr_t ctxt_to_hw_map = (uintptr_t)ctx->ctxt_to_hw_map; + struct cam_lrme_context *lrme_ctx = ctx->ctx_priv; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_acquire_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to acquire"); + return rc; + } + + ctxt_to_hw_map |= (lrme_ctx->index << CAM_LRME_CTX_INDEX_SHIFT); + ctx->ctxt_to_hw_map = (void *)ctxt_to_hw_map; + + ctx->state = CAM_CTX_ACQUIRED; + + return rc; +} + +static int __cam_lrme_ctx_release_dev_in_acquired(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to release"); + return rc; + } + + ctx->state = CAM_CTX_AVAILABLE; + + return rc; +} + +static int __cam_lrme_ctx_start_dev_in_acquired(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_start_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to start"); + return rc; + } + + ctx->state = CAM_CTX_ACTIVATED; + + return rc; +} + +static int __cam_lrme_ctx_config_dev_in_activated(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_prepare_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to config"); + return rc; + } + + return rc; +} + +static int __cam_lrme_ctx_flush_dev_in_activated(struct cam_context *ctx, + struct cam_flush_dev_cmd *cmd) +{ + int rc; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_flush_dev_to_hw(ctx, cmd); + if (rc) + CAM_ERR(CAM_LRME, "Failed to flush device"); + + return rc; +} +static int __cam_lrme_ctx_stop_dev_in_activated(struct cam_context *ctx, + struct cam_start_stop_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = cam_context_stop_dev_to_hw(ctx); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to stop dev"); + return rc; + } + + ctx->state = CAM_CTX_ACQUIRED; + + return rc; +} + +static int __cam_lrme_ctx_release_dev_in_activated(struct cam_context *ctx, + struct cam_release_dev_cmd *cmd) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter ctx %d", ctx->ctx_id); + + rc = __cam_lrme_ctx_stop_dev_in_activated(ctx, NULL); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to stop"); + return rc; + } + + rc = cam_context_release_dev_to_hw(ctx, cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to release"); + return rc; + } + + ctx->state = CAM_CTX_AVAILABLE; + + return rc; +} + +static int __cam_lrme_ctx_handle_irq_in_activated(void *context, + uint32_t evt_id, void *evt_data) +{ + int rc; + + CAM_DBG(CAM_LRME, "Enter"); + + rc = cam_context_buf_done_from_hw(context, evt_data, evt_id); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in buf done, rc=%d", rc); + return rc; + } + + return rc; +} + +/* top state machine */ +static struct cam_ctx_ops + cam_lrme_ctx_state_machine[CAM_CTX_STATE_MAX] = { + /* Uninit */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Available */ + { + .ioctl_ops = { + .acquire_dev = __cam_lrme_ctx_acquire_dev_in_available, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Acquired */ + { + .ioctl_ops = { + .config_dev = __cam_lrme_ctx_config_dev_in_activated, + .release_dev = __cam_lrme_ctx_release_dev_in_acquired, + .start_dev = __cam_lrme_ctx_start_dev_in_acquired, + }, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Ready */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* Flushed */ + {}, + /* Activate */ + { + .ioctl_ops = { + .config_dev = __cam_lrme_ctx_config_dev_in_activated, + .release_dev = __cam_lrme_ctx_release_dev_in_activated, + .stop_dev = __cam_lrme_ctx_stop_dev_in_activated, + .flush_dev = __cam_lrme_ctx_flush_dev_in_activated, + }, + .crm_ops = {}, + .irq_ops = __cam_lrme_ctx_handle_irq_in_activated, + }, +}; + +int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx, + struct cam_context *base_ctx, + struct cam_hw_mgr_intf *hw_intf, + uint32_t index) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter"); + + if (!base_ctx || !lrme_ctx) { + CAM_ERR(CAM_LRME, "Invalid input"); + return -EINVAL; + } + + memset(lrme_ctx, 0, sizeof(*lrme_ctx)); + + rc = cam_context_init(base_ctx, lrme_dev_name, CAM_LRME, index, + NULL, hw_intf, lrme_ctx->req_base, CAM_CTX_REQ_MAX); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to init context"); + return rc; + } + lrme_ctx->base = base_ctx; + lrme_ctx->index = index; + base_ctx->ctx_priv = lrme_ctx; + base_ctx->state_machine = cam_lrme_ctx_state_machine; + + return rc; +} + +int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx) +{ + int rc = 0; + + CAM_DBG(CAM_LRME, "Enter"); + + if (!lrme_ctx) { + CAM_ERR(CAM_LRME, "No ctx to deinit"); + return -EINVAL; + } + + rc = cam_context_deinit(lrme_ctx->base); + + memset(lrme_ctx, 0, sizeof(*lrme_ctx)); + return rc; +} diff --git a/techpack/camera/drivers/cam_lrme/cam_lrme_context.h b/techpack/camera/drivers/cam_lrme/cam_lrme_context.h new file mode 100644 index 0000000000000000000000000000000000000000..9fb88ed85f1b6cd6b3fc5dd0becc26b538d2e81f --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/cam_lrme_context.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_CONTEXT_H_ +#define _CAM_LRME_CONTEXT_H_ + +#include "cam_context.h" +#include "cam_context_utils.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + +#define CAM_LRME_CTX_INDEX_SHIFT 16 + +/** + * struct cam_lrme_context + * + * @base : Base context pointer for this LRME context + * @req_base : List of base request for this LRME context + */ +struct cam_lrme_context { + struct cam_context *base; + struct cam_ctx_request req_base[CAM_CTX_REQ_MAX]; + uint64_t index; +}; + +int cam_lrme_context_init(struct cam_lrme_context *lrme_ctx, + struct cam_context *base_ctx, struct cam_hw_mgr_intf *hw_intf, + uint32_t index); +int cam_lrme_context_deinit(struct cam_lrme_context *lrme_ctx); + +#endif /* _CAM_LRME_CONTEXT_H_ */ diff --git a/techpack/camera/drivers/cam_lrme/cam_lrme_dev.c b/techpack/camera/drivers/cam_lrme/cam_lrme_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..7c09f2b435f530f63a549de182fa550b92bdb280 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/cam_lrme_dev.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_subdev.h" +#include "cam_node.h" +#include "cam_lrme_context.h" +#include "cam_lrme_hw_mgr.h" +#include "cam_lrme_hw_mgr_intf.h" + +#define CAM_LRME_DEV_NAME "cam-lrme" + +/** + * struct cam_lrme_dev + * + * @sd : Subdev information + * @ctx : List of base contexts + * @lrme_ctx : List of LRME contexts + * @lock : Mutex for LRME subdev + * @open_cnt : Open count of LRME subdev + */ +struct cam_lrme_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_lrme_context lrme_ctx[CAM_CTX_MAX]; + struct mutex lock; + uint32_t open_cnt; +}; + +static struct cam_lrme_dev *g_lrme_dev; + +static int cam_lrme_dev_buf_done_cb(void *ctxt_to_hw_map, uint32_t evt_id, + void *evt_data) +{ + uint64_t index; + struct cam_context *ctx; + int rc; + + index = CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map); + CAM_DBG(CAM_LRME, "ctx index %llu, evt_id %u\n", index, evt_id); + ctx = &g_lrme_dev->ctx[index]; + rc = ctx->irq_cb_intf(ctx, evt_id, evt_data); + if (rc) + CAM_ERR(CAM_LRME, "irq callback failed"); + + return rc; +} + +static int cam_lrme_dev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_lrme_dev *lrme_dev = g_lrme_dev; + + if (!lrme_dev) { + CAM_ERR(CAM_LRME, + "LRME Dev not initialized, dev=%pK", lrme_dev); + return -ENODEV; + } + + mutex_lock(&lrme_dev->lock); + lrme_dev->open_cnt++; + mutex_unlock(&lrme_dev->lock); + + return 0; +} + +static int cam_lrme_dev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + int rc = 0; + struct cam_lrme_dev *lrme_dev = g_lrme_dev; + struct cam_node *node = v4l2_get_subdevdata(sd); + + if (!lrme_dev) { + CAM_ERR(CAM_LRME, "Invalid args"); + return -ENODEV; + } + + mutex_lock(&lrme_dev->lock); + if (lrme_dev->open_cnt <= 0) { + CAM_DBG(CAM_LRME, "LRME subdev is already closed"); + rc = -EINVAL; + goto end; + } + + lrme_dev->open_cnt--; + if (!node) { + CAM_ERR(CAM_LRME, "Node is NULL"); + rc = -EINVAL; + goto end; + } + + if (lrme_dev->open_cnt == 0) + cam_node_shutdown(node); + +end: + mutex_unlock(&lrme_dev->lock); + return rc; +} + +static const struct v4l2_subdev_internal_ops cam_lrme_subdev_internal_ops = { + .open = cam_lrme_dev_open, + .close = cam_lrme_dev_close, +}; + +static int cam_lrme_dev_probe(struct platform_device *pdev) +{ + int rc; + int i; + struct cam_hw_mgr_intf hw_mgr_intf; + struct cam_node *node; + + g_lrme_dev = kzalloc(sizeof(struct cam_lrme_dev), GFP_KERNEL); + if (!g_lrme_dev) { + CAM_ERR(CAM_LRME, "No memory"); + return -ENOMEM; + } + g_lrme_dev->sd.internal_ops = &cam_lrme_subdev_internal_ops; + + mutex_init(&g_lrme_dev->lock); + + rc = cam_subdev_probe(&g_lrme_dev->sd, pdev, CAM_LRME_DEV_NAME, + CAM_LRME_DEVICE_TYPE); + if (rc) { + CAM_ERR(CAM_LRME, "LRME cam_subdev_probe failed"); + goto free_mem; + } + node = (struct cam_node *)g_lrme_dev->sd.token; + + rc = cam_lrme_hw_mgr_init(&hw_mgr_intf, cam_lrme_dev_buf_done_cb); + if (rc) { + CAM_ERR(CAM_LRME, "Can not initialized LRME HW manager"); + goto unregister; + } + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_lrme_context_init(&g_lrme_dev->lrme_ctx[i], + &g_lrme_dev->ctx[i], + &node->hw_mgr_intf, i); + if (rc) { + CAM_ERR(CAM_LRME, "LRME context init failed"); + goto deinit_ctx; + } + } + + rc = cam_node_init(node, &hw_mgr_intf, g_lrme_dev->ctx, CAM_CTX_MAX, + CAM_LRME_DEV_NAME); + if (rc) { + CAM_ERR(CAM_LRME, "LRME node init failed"); + goto deinit_ctx; + } + + CAM_DBG(CAM_LRME, "%s probe complete", g_lrme_dev->sd.name); + + return 0; + +deinit_ctx: + for (--i; i >= 0; i--) { + if (cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i])) + CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i); + } +unregister: + if (cam_subdev_remove(&g_lrme_dev->sd)) + CAM_ERR(CAM_LRME, "Failed in subdev remove"); +free_mem: + kfree(g_lrme_dev); + + return rc; +} + +static int cam_lrme_dev_remove(struct platform_device *pdev) +{ + int i; + int rc = 0; + + for (i = 0; i < CAM_CTX_MAX; i++) { + rc = cam_lrme_context_deinit(&g_lrme_dev->lrme_ctx[i]); + if (rc) + CAM_ERR(CAM_LRME, "LRME context %d deinit failed", i); + } + + rc = cam_lrme_hw_mgr_deinit(); + if (rc) + CAM_ERR(CAM_LRME, "Failed in hw mgr deinit, rc=%d", rc); + + rc = cam_subdev_remove(&g_lrme_dev->sd); + if (rc) + CAM_ERR(CAM_LRME, "Unregister failed"); + + mutex_destroy(&g_lrme_dev->lock); + kfree(g_lrme_dev); + g_lrme_dev = NULL; + + return rc; +} + +static const struct of_device_id cam_lrme_dt_match[] = { + { + .compatible = "qcom,cam-lrme" + }, + {} +}; + +static struct platform_driver cam_lrme_driver = { + .probe = cam_lrme_dev_probe, + .remove = cam_lrme_dev_remove, + .driver = { + .name = "cam_lrme", + .owner = THIS_MODULE, + .of_match_table = cam_lrme_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_lrme_dev_init_module(void) +{ + return platform_driver_register(&cam_lrme_driver); +} + +static void __exit cam_lrme_dev_exit_module(void) +{ + platform_driver_unregister(&cam_lrme_driver); +} + +module_init(cam_lrme_dev_init_module); +module_exit(cam_lrme_dev_exit_module); +MODULE_DESCRIPTION("MSM LRME driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/Makefile b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3387c3d0f062ea256fa41bc5e9bee4a08774c227 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -I$(srctree)/techpack/camera +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_mgr.o diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..40700bbce9e0aec56e1a37d7bc5950df9a5d41b2 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -0,0 +1,1155 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_cpas.h> +#include <media/cam_req_mgr.h> + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_mem_mgr_api.h" +#include "cam_smmu_api.h" +#include "cam_packet_util.h" +#include "cam_lrme_context.h" +#include "cam_lrme_hw_intf.h" +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_lrme_hw_mgr_intf.h" +#include "cam_lrme_hw_mgr.h" + +static struct cam_lrme_hw_mgr g_lrme_hw_mgr; + +static int cam_lrme_mgr_util_reserve_device(struct cam_lrme_hw_mgr *hw_mgr, + struct cam_lrme_acquire_args *lrme_acquire_args) +{ + int i, index = 0; + uint32_t min_ctx = UINT_MAX; + struct cam_lrme_device *hw_device = NULL; + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!hw_mgr->device_count) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + CAM_ERR(CAM_LRME, "No device is registered"); + return -EINVAL; + } + + for (i = 0; i < hw_mgr->device_count && i < CAM_LRME_HW_MAX; i++) { + hw_device = &hw_mgr->hw_device[i]; + if (!hw_device->num_context) { + index = i; + break; + } + if (hw_device->num_context < min_ctx) { + min_ctx = hw_device->num_context; + index = i; + } + } + + hw_device = &hw_mgr->hw_device[index]; + hw_device->num_context++; + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_LRME, "reserve device index %d", index); + + return index; +} + +static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr, + uint32_t device_index, struct cam_lrme_device **hw_device) +{ + if (!hw_mgr) { + CAM_ERR(CAM_LRME, "invalid params hw_mgr %pK", hw_mgr); + return -EINVAL; + } + + if (device_index >= CAM_LRME_HW_MAX) { + CAM_ERR(CAM_LRME, "Wrong device index %d", device_index); + return -EINVAL; + } + + *hw_device = &hw_mgr->hw_device[device_index]; + + return 0; +} + +static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + int i, rc; + + if (!packet) { + CAM_ERR(CAM_LRME, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_LRME, "Packet request=%d, op_code=0x%x, size=%d, flags=%d", + packet->header.request_id, packet->header.op_code, + packet->header.size, packet->header.flags); + CAM_DBG(CAM_LRME, + "Packet cmdbuf(offset=%d, num=%d) io(offset=%d, num=%d)", + packet->cmd_buf_offset, packet->num_cmd_buf, + packet->io_configs_offset, packet->num_io_configs); + CAM_DBG(CAM_LRME, + "Packet Patch(offset=%d, num=%d) kmd(offset=%d, num=%d)", + packet->patch_offset, packet->num_patches, + packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); + + if (cam_packet_util_validate_packet(packet, remain_len)) { + CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d", + packet->kmd_cmd_buf_index, + packet->num_cmd_buf, packet->cmd_buf_offset, + packet->io_configs_offset, packet->header.size); + return -EINVAL; + } + + if (!packet->num_io_configs) { + CAM_ERR(CAM_LRME, "no io configs"); + return -EINVAL; + } + + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *)&packet->payload + + packet->cmd_buf_offset); + + for (i = 0; i < packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + CAM_DBG(CAM_LRME, + "CmdBuf[%d] hdl=%d, offset=%d, size=%d, len=%d, type=%d, meta_data=%d", + i, + cmd_desc[i].mem_handle, cmd_desc[i].offset, + cmd_desc[i].size, cmd_desc[i].length, cmd_desc[i].type, + cmd_desc[i].meta_data); + + rc = cam_packet_util_validate_cmd_desc(&cmd_desc[i]); + if (rc) { + CAM_ERR(CAM_LRME, "Invalid cmd buffer %d", i); + return rc; + } + } + + return 0; +} + +static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, + struct cam_hw_prepare_update_args *prepare, + struct cam_lrme_hw_io_buffer *input_buf, + struct cam_lrme_hw_io_buffer *output_buf, uint32_t io_buf_size) +{ + int rc = -EINVAL; + uint32_t num_in_buf, num_out_buf, i, j, plane; + struct cam_buf_io_cfg *io_cfg; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; + size_t size; + + num_in_buf = 0; + num_out_buf = 0; + io_cfg = (struct cam_buf_io_cfg *)((uint8_t *) + &prepare->packet->payload + + prepare->packet->io_configs_offset); + + for (i = 0; i < prepare->packet->num_io_configs; i++) { + CAM_DBG(CAM_LRME, + "IOConfig[%d] : handle[%d] Dir[%d] Res[%d] Fence[%d], Format[%d]", + i, io_cfg[i].mem_handle[0], io_cfg[i].direction, + io_cfg[i].resource_type, + io_cfg[i].fence, io_cfg[i].format); + + memset(io_addr, 0, sizeof(io_addr)); + for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) { + if (!io_cfg[i].mem_handle[plane]) + break; + + rc = cam_mem_get_io_buf(io_cfg[i].mem_handle[plane], + iommu_hdl, &io_addr[plane], &size); + if (rc) { + CAM_ERR(CAM_LRME, "Cannot get io buf for %d %d", + plane, rc); + return -ENOMEM; + } + + if ((size_t)io_cfg[i].offsets[plane] >= size) { + CAM_ERR(CAM_LRME, "Invalid plane offset: %zu", + (size_t)io_cfg[i].offsets[plane]); + return -EINVAL; + } + + io_addr[plane] += io_cfg[i].offsets[plane]; + + CAM_DBG(CAM_LRME, "IO Address[%d][%d] : %llu", + io_cfg[i].direction, plane, io_addr[plane]); + } + + switch (io_cfg[i].direction) { + case CAM_BUF_INPUT: { + if (num_in_buf >= io_buf_size) { + CAM_ERR(CAM_LRME, + "Invalid number of buffers %d %d %d", + num_in_buf, num_out_buf, io_buf_size); + return -EINVAL; + } + prepare->in_map_entries[num_in_buf].resource_handle = + io_cfg[i].resource_type; + prepare->in_map_entries[num_in_buf].sync_id = + io_cfg[i].fence; + + input_buf[num_in_buf].valid = true; + for (j = 0; j < plane; j++) + input_buf[num_in_buf].io_addr[j] = io_addr[j]; + input_buf[num_in_buf].num_plane = plane; + input_buf[num_in_buf].io_cfg = &io_cfg[i]; + + num_in_buf++; + break; + } + case CAM_BUF_OUTPUT: { + if (num_out_buf >= io_buf_size) { + CAM_ERR(CAM_LRME, + "Invalid number of buffers %d %d %d", + num_in_buf, num_out_buf, io_buf_size); + return -EINVAL; + } + prepare->out_map_entries[num_out_buf].resource_handle = + io_cfg[i].resource_type; + prepare->out_map_entries[num_out_buf].sync_id = + io_cfg[i].fence; + + output_buf[num_out_buf].valid = true; + for (j = 0; j < plane; j++) + output_buf[num_out_buf].io_addr[j] = io_addr[j]; + output_buf[num_out_buf].num_plane = plane; + output_buf[num_out_buf].io_cfg = &io_cfg[i]; + + num_out_buf++; + break; + } + default: + CAM_ERR(CAM_LRME, "Unsupported io direction %d", + io_cfg[i].direction); + return -EINVAL; + } + } + prepare->num_in_map_entries = num_in_buf; + prepare->num_out_map_entries = num_out_buf; + + return 0; +} + +static int cam_lrme_mgr_util_prepare_hw_update_entries( + struct cam_lrme_hw_mgr *hw_mgr, + struct cam_hw_prepare_update_args *prepare, + struct cam_lrme_hw_cmd_config_args *config_args, + struct cam_kmd_buf_info *kmd_buf_info) +{ + int i, rc = 0; + struct cam_lrme_device *hw_device = NULL; + uint32_t *kmd_buf_addr; + uint32_t num_entry; + uint32_t kmd_buf_max_size; + uint32_t kmd_buf_used_bytes = 0; + struct cam_hw_update_entry *hw_entry; + struct cam_cmd_buf_desc *cmd_desc = NULL; + + hw_device = config_args->hw_device; + if (!hw_device) { + CAM_ERR(CAM_LRME, "Invalid hw_device"); + return -EINVAL; + } + + kmd_buf_addr = (uint32_t *)((uint8_t *)kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes); + kmd_buf_max_size = kmd_buf_info->size - kmd_buf_info->used_bytes; + + config_args->cmd_buf_addr = kmd_buf_addr; + config_args->size = kmd_buf_max_size; + config_args->config_buf_size = 0; + + if (hw_device->hw_intf.hw_ops.process_cmd) { + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, + config_args, + sizeof(struct cam_lrme_hw_cmd_config_args)); + if (rc) { + CAM_ERR(CAM_LRME, + "Failed in CMD_PREPARE_HW_UPDATE %d", rc); + return rc; + } + } else { + CAM_ERR(CAM_LRME, "Can't find handle function"); + return -EINVAL; + } + + kmd_buf_used_bytes += config_args->config_buf_size; + + if (!kmd_buf_used_bytes || (kmd_buf_used_bytes > kmd_buf_max_size)) { + CAM_ERR(CAM_LRME, "Invalid kmd used bytes %d (%d)", + kmd_buf_used_bytes, kmd_buf_max_size); + return -ENOMEM; + } + + hw_entry = prepare->hw_update_entries; + num_entry = 0; + + if (config_args->config_buf_size) { + if ((num_entry + 1) >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_LRME, "Insufficient HW entries :%d %d", + num_entry, prepare->max_hw_update_entries); + return -EINVAL; + } + + hw_entry[num_entry].handle = kmd_buf_info->handle; + hw_entry[num_entry].len = config_args->config_buf_size; + hw_entry[num_entry].offset = kmd_buf_info->offset; + + kmd_buf_info->used_bytes += config_args->config_buf_size; + kmd_buf_info->offset += config_args->config_buf_size; + num_entry++; + } + + cmd_desc = (struct cam_cmd_buf_desc *)((uint8_t *) + &prepare->packet->payload + prepare->packet->cmd_buf_offset); + + for (i = 0; i < prepare->packet->num_cmd_buf; i++) { + if (!cmd_desc[i].length) + continue; + + if ((num_entry + 1) >= prepare->max_hw_update_entries) { + CAM_ERR(CAM_LRME, "Exceed max num of entry"); + return -EINVAL; + } + + hw_entry[num_entry].handle = cmd_desc[i].mem_handle; + hw_entry[num_entry].len = cmd_desc[i].length; + hw_entry[num_entry].offset = cmd_desc[i].offset; + num_entry++; + } + prepare->num_hw_update_entries = num_entry; + + CAM_DBG(CAM_LRME, "FinalConfig : hw_entries=%d, Sync(in=%d, out=%d)", + prepare->num_hw_update_entries, prepare->num_in_map_entries, + prepare->num_out_map_entries); + + return rc; +} + +static void cam_lrme_mgr_util_put_frame_req( + struct list_head *src_list, + struct list_head *list, + spinlock_t *lock) +{ + spin_lock(lock); + list_add_tail(list, src_list); + spin_unlock(lock); +} + +static int cam_lrme_mgr_util_get_frame_req( + struct list_head *src_list, + struct cam_lrme_frame_request **frame_req, + spinlock_t *lock) +{ + int rc = 0; + struct cam_lrme_frame_request *req_ptr = NULL; + + spin_lock(lock); + if (!list_empty(src_list)) { + req_ptr = list_first_entry(src_list, + struct cam_lrme_frame_request, frame_list); + list_del_init(&req_ptr->frame_list); + } else { + rc = -ENOENT; + } + *frame_req = req_ptr; + spin_unlock(lock); + + return rc; +} + + +static int cam_lrme_mgr_util_submit_req(void *priv, void *data) +{ + struct cam_lrme_device *hw_device; + struct cam_lrme_hw_mgr *hw_mgr; + struct cam_lrme_frame_request *frame_req = NULL; + struct cam_lrme_hw_submit_args submit_args; + struct cam_lrme_mgr_work_data *work_data; + int rc; + int req_prio = 0; + + if (!priv) { + CAM_ERR(CAM_LRME, "worker doesn't have private data"); + return -EINVAL; + } + + hw_mgr = (struct cam_lrme_hw_mgr *)priv; + work_data = (struct cam_lrme_mgr_work_data *)data; + hw_device = work_data->hw_device; + + rc = cam_lrme_mgr_util_get_frame_req( + &hw_device->frame_pending_list_high, &frame_req, + &hw_device->high_req_lock); + + if (!frame_req) { + rc = cam_lrme_mgr_util_get_frame_req( + &hw_device->frame_pending_list_normal, &frame_req, + &hw_device->normal_req_lock); + if (frame_req) + req_prio = 1; + } + + if (!frame_req) { + CAM_DBG(CAM_LRME, "No pending request"); + return 0; + } + + if (hw_device->hw_intf.hw_ops.process_cmd) { + submit_args.hw_update_entries = frame_req->hw_update_entries; + submit_args.num_hw_update_entries = + frame_req->num_hw_update_entries; + submit_args.frame_req = frame_req; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_SUBMIT, + &submit_args, sizeof(struct cam_lrme_hw_submit_args)); + + if (rc == -EBUSY) + CAM_DBG(CAM_LRME, "device busy"); + else if (rc) + CAM_ERR(CAM_LRME, "submit request failed rc %d", rc); + if (rc) { + req_prio == 0 ? spin_lock(&hw_device->high_req_lock) : + spin_lock(&hw_device->normal_req_lock); + list_add(&frame_req->frame_list, + (req_prio == 0 ? + &hw_device->frame_pending_list_high : + &hw_device->frame_pending_list_normal)); + req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) : + spin_unlock(&hw_device->normal_req_lock); + } + if (rc == -EBUSY) + rc = 0; + } else { + req_prio == 0 ? spin_lock(&hw_device->high_req_lock) : + spin_lock(&hw_device->normal_req_lock); + list_add(&frame_req->frame_list, + (req_prio == 0 ? + &hw_device->frame_pending_list_high : + &hw_device->frame_pending_list_normal)); + req_prio == 0 ? spin_unlock(&hw_device->high_req_lock) : + spin_unlock(&hw_device->normal_req_lock); + rc = -EINVAL; + } + + CAM_DBG(CAM_LRME, "End of submit, rc %d", rc); + + return rc; +} + +static int cam_lrme_mgr_util_schedule_frame_req( + struct cam_lrme_hw_mgr *hw_mgr, struct cam_lrme_device *hw_device) +{ + int rc = 0; + struct crm_workq_task *task; + struct cam_lrme_mgr_work_data *work_data; + + task = cam_req_mgr_workq_get_task(hw_device->work); + if (!task) { + CAM_ERR(CAM_LRME, "Can not get task for worker"); + return -ENOMEM; + } + + work_data = (struct cam_lrme_mgr_work_data *)task->payload; + work_data->hw_device = hw_device; + + task->process_cb = cam_lrme_mgr_util_submit_req; + CAM_DBG(CAM_LRME, "enqueue submit task"); + rc = cam_req_mgr_workq_enqueue_task(task, hw_mgr, CRM_TASK_PRIORITY_0); + + return rc; +} + +static int cam_lrme_mgr_util_release(struct cam_lrme_hw_mgr *hw_mgr, + uint32_t device_index) +{ + int rc = 0; + struct cam_lrme_device *hw_device; + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Error in getting device %d", rc); + return rc; + } + + mutex_lock(&hw_mgr->hw_mgr_mutex); + hw_device->num_context--; + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + return rc; +} + +static int cam_lrme_mgr_cb(void *data, + struct cam_lrme_hw_cb_args *cb_args) +{ + struct cam_lrme_hw_mgr *hw_mgr = &g_lrme_hw_mgr; + int rc = 0; + bool frame_abort = true; + struct cam_lrme_frame_request *frame_req; + struct cam_lrme_device *hw_device; + + if (!data || !cb_args) { + CAM_ERR(CAM_LRME, "Invalid input args"); + return -EINVAL; + } + + hw_device = (struct cam_lrme_device *)data; + frame_req = cb_args->frame_req; + + if (cb_args->cb_type & CAM_LRME_CB_PUT_FRAME) { + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->frame_list); + cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req->frame_list, + &hw_mgr->free_req_lock); + cb_args->cb_type &= ~CAM_LRME_CB_PUT_FRAME; + frame_req = NULL; + } + + if (cb_args->cb_type & CAM_LRME_CB_COMP_REG_UPDATE) { + cb_args->cb_type &= ~CAM_LRME_CB_COMP_REG_UPDATE; + CAM_DBG(CAM_LRME, "Reg update"); + } + + if (!frame_req) + return rc; + + if (cb_args->cb_type & CAM_LRME_CB_BUF_DONE) { + cb_args->cb_type &= ~CAM_LRME_CB_BUF_DONE; + frame_abort = false; + } else if (cb_args->cb_type & CAM_LRME_CB_ERROR) { + cb_args->cb_type &= ~CAM_LRME_CB_ERROR; + frame_abort = true; + } else { + CAM_ERR(CAM_LRME, "Wrong cb type %d, req %lld", + cb_args->cb_type, frame_req->req_id); + return -EINVAL; + } + + if (hw_mgr->event_cb) { + struct cam_hw_done_event_data buf_data; + + buf_data.request_id = frame_req->req_id; + CAM_DBG(CAM_LRME, "frame req %llu, frame_abort %d", + frame_req->req_id, frame_abort); + rc = hw_mgr->event_cb(frame_req->ctxt_to_hw_map, + frame_abort, &buf_data); + } else { + CAM_ERR(CAM_LRME, "No cb function"); + } + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->frame_list); + cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req->frame_list, + &hw_mgr->free_req_lock); + + rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device); + + return rc; +} + +static int cam_lrme_mgr_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_query_cap_cmd *args = hw_get_caps_args; + + if (sizeof(struct cam_lrme_query_cap_cmd) != args->size) { + CAM_ERR(CAM_LRME, + "sizeof(struct cam_query_cap_cmd) = %zu, args->size = %d", + sizeof(struct cam_query_cap_cmd), args->size); + return -EFAULT; + } + + if (copy_to_user(u64_to_user_ptr(args->caps_handle), + &(hw_mgr->lrme_caps), + sizeof(struct cam_lrme_query_cap_cmd))) { + CAM_ERR(CAM_LRME, "copy to user failed"); + return -EFAULT; + } + + return rc; +} + +static int cam_lrme_mgr_hw_acquire(void *hw_mgr_priv, void *hw_acquire_args) +{ + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_acquire_args *args = + (struct cam_hw_acquire_args *)hw_acquire_args; + struct cam_lrme_acquire_args lrme_acquire_args; + uintptr_t device_index; + + if (!hw_mgr_priv || !args) { + CAM_ERR(CAM_LRME, + "Invalid input params hw_mgr_priv %pK, acquire_args %pK", + hw_mgr_priv, args); + return -EINVAL; + } + + if (copy_from_user(&lrme_acquire_args, + (void __user *)args->acquire_info, + sizeof(struct cam_lrme_acquire_args))) { + CAM_ERR(CAM_LRME, "Failed to copy acquire args from user"); + return -EFAULT; + } + + device_index = cam_lrme_mgr_util_reserve_device(hw_mgr, + &lrme_acquire_args); + CAM_DBG(CAM_LRME, "Get device id %llu", device_index); + + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Get wrong device id %lu", device_index); + return -EINVAL; + } + + /* device_index is the right 4 bit in ctxt_to_hw_map */ + args->ctxt_to_hw_map = (void *)device_index; + + return 0; +} + +static int cam_lrme_mgr_hw_release(void *hw_mgr_priv, void *hw_release_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_release_args *args = + (struct cam_hw_release_args *)hw_release_args; + uint64_t device_index; + + if (!hw_mgr_priv || !hw_release_args) { + CAM_ERR(CAM_LRME, "Invalid arguments %pK, %pK", + hw_mgr_priv, hw_release_args); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %llu", device_index); + return -EPERM; + } + + rc = cam_lrme_mgr_util_release(hw_mgr, device_index); + if (rc) + CAM_ERR(CAM_LRME, "Failed in release device, rc=%d", rc); + + return rc; +} + +static int cam_lrme_mgr_hw_flush(void *hw_mgr_priv, void *hw_flush_args) +{ int rc = 0, i; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_flush_args *args; + struct cam_lrme_device *hw_device; + struct cam_lrme_frame_request *frame_req = NULL, *req_to_flush = NULL; + struct cam_lrme_frame_request **req_list = NULL; + uint32_t device_index; + struct cam_lrme_hw_flush_args lrme_flush_args; + uint32_t priority; + + if (!hw_mgr_priv || !hw_flush_args) { + CAM_ERR(CAM_LRME, "Invalid args %pK %pK", + hw_mgr_priv, hw_flush_args); + return -EINVAL; + } + + args = (struct cam_hw_flush_args *)hw_flush_args; + device_index = ((uintptr_t)args->ctxt_to_hw_map & 0xF); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Error in getting device %d", rc); + goto end; + } + + req_list = (struct cam_lrme_frame_request **)args->flush_req_pending; + for (i = 0; i < args->num_req_pending; i++) { + frame_req = req_list[i]; + memset(frame_req, 0x0, sizeof(*frame_req)); + cam_lrme_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &frame_req->frame_list, &hw_mgr->free_req_lock); + } + + req_list = (struct cam_lrme_frame_request **)args->flush_req_active; + for (i = 0; i < args->num_req_active; i++) { + frame_req = req_list[i]; + priority = CAM_LRME_DECODE_PRIORITY(args->ctxt_to_hw_map); + spin_lock((priority == CAM_LRME_PRIORITY_HIGH) ? + &hw_device->high_req_lock : + &hw_device->normal_req_lock); + if (!list_empty(&frame_req->frame_list)) { + list_del_init(&frame_req->frame_list); + cam_lrme_mgr_util_put_frame_req( + &hw_mgr->frame_free_list, + &frame_req->frame_list, + &hw_mgr->free_req_lock); + } else + req_to_flush = frame_req; + spin_unlock((priority == CAM_LRME_PRIORITY_HIGH) ? + &hw_device->high_req_lock : + &hw_device->normal_req_lock); + } + if (!req_to_flush) + goto end; + if (hw_device->hw_intf.hw_ops.flush) { + lrme_flush_args.ctxt_to_hw_map = req_to_flush->ctxt_to_hw_map; + lrme_flush_args.flush_type = args->flush_type; + lrme_flush_args.req_to_flush = req_to_flush; + rc = hw_device->hw_intf.hw_ops.flush(hw_device->hw_intf.hw_priv, + &lrme_flush_args, + sizeof(lrme_flush_args)); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in HW Stop %d", rc); + goto end; + } + } else { + CAM_ERR(CAM_LRME, "No stop ops"); + goto end; + } + +end: + return rc; +} + + +static int cam_lrme_mgr_hw_start(void *hw_mgr_priv, void *hw_start_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_start_args *args = + (struct cam_hw_start_args *)hw_start_args; + struct cam_lrme_device *hw_device; + uint32_t device_index; + + if (!hw_mgr || !args) { + CAM_ERR(CAM_LRME, "Invalid input params"); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Start device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + + if (hw_device->hw_intf.hw_ops.start) { + rc = hw_device->hw_intf.hw_ops.start( + hw_device->hw_intf.hw_priv, NULL, 0); + } else { + CAM_ERR(CAM_LRME, "Invalid start function"); + return -EINVAL; + } + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_DUMP_REGISTER, + &g_lrme_hw_mgr.debugfs_entry.dump_register, + sizeof(bool)); + + return rc; +} + +static int cam_lrme_mgr_hw_stop(void *hw_mgr_priv, void *stop_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_stop_args *args = + (struct cam_hw_stop_args *)stop_args; + struct cam_lrme_device *hw_device; + uint32_t device_index; + + if (!hw_mgr_priv || !stop_args) { + CAM_ERR(CAM_LRME, "Invalid arguments"); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + CAM_DBG(CAM_LRME, "Stop device index %d", device_index); + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw device"); + return rc; + } + + if (hw_device->hw_intf.hw_ops.stop) { + rc = hw_device->hw_intf.hw_ops.stop( + hw_device->hw_intf.hw_priv, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in HW stop %d", rc); + goto end; + } + } + +end: + return rc; +} + +static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, + void *hw_prepare_update_args) +{ + int rc = 0, i; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_prepare_update_args *args = + (struct cam_hw_prepare_update_args *)hw_prepare_update_args; + struct cam_lrme_device *hw_device; + struct cam_kmd_buf_info kmd_buf; + struct cam_lrme_hw_cmd_config_args config_args; + struct cam_lrme_frame_request *frame_req = NULL; + uint32_t device_index; + + if (!hw_mgr_priv || !hw_prepare_update_args) { + CAM_ERR(CAM_LRME, "Invalid args %pK %pK", + hw_mgr_priv, hw_prepare_update_args); + return -EINVAL; + } + + device_index = CAM_LRME_DECODE_DEVICE_INDEX(args->ctxt_to_hw_map); + if (device_index >= hw_mgr->device_count) { + CAM_ERR(CAM_LRME, "Invalid device index %d", device_index); + return -EPERM; + } + + rc = cam_lrme_mgr_util_get_device(hw_mgr, device_index, &hw_device); + if (rc) { + CAM_ERR(CAM_LRME, "Error in getting device %d", rc); + goto error; + } + + rc = cam_lrme_mgr_util_packet_validate(args->packet, args->remain_len); + if (rc) { + CAM_ERR(CAM_LRME, "Error in packet validation %d", rc); + goto error; + } + + rc = cam_packet_util_get_kmd_buffer(args->packet, &kmd_buf); + if (rc) { + CAM_ERR(CAM_LRME, "Error in get kmd buf buffer %d", rc); + goto error; + } + + CAM_DBG(CAM_LRME, + "KMD Buf : hdl=%d, cpu_addr=%pK, offset=%d, size=%d, used=%d", + kmd_buf.handle, kmd_buf.cpu_addr, kmd_buf.offset, + kmd_buf.size, kmd_buf.used_bytes); + + rc = cam_packet_util_process_patches(args->packet, + hw_mgr->device_iommu.non_secure, hw_mgr->device_iommu.secure); + if (rc) { + CAM_ERR(CAM_LRME, "Patch packet failed, rc=%d", rc); + return rc; + } + + memset(&config_args, 0, sizeof(config_args)); + config_args.hw_device = hw_device; + + rc = cam_lrme_mgr_util_prepare_io_buffer( + hw_mgr->device_iommu.non_secure, args, + config_args.input_buf, config_args.output_buf, + CAM_LRME_MAX_IO_BUFFER); + if (rc) { + CAM_ERR(CAM_LRME, "Error in prepare IO Buf %d", rc); + goto error; + } + /* Check port number */ + if (args->num_in_map_entries == 0 || args->num_out_map_entries == 0) { + CAM_ERR(CAM_LRME, "Error in port number in %d, out %d", + args->num_in_map_entries, args->num_out_map_entries); + rc = -EINVAL; + goto error; + } + + rc = cam_lrme_mgr_util_prepare_hw_update_entries(hw_mgr, args, + &config_args, &kmd_buf); + if (rc) { + CAM_ERR(CAM_LRME, "Error in hw update entries %d", rc); + goto error; + } + + rc = cam_lrme_mgr_util_get_frame_req(&hw_mgr->frame_free_list, + &frame_req, &hw_mgr->free_req_lock); + if (rc || !frame_req) { + CAM_ERR(CAM_LRME, "Can not get free frame request"); + goto error; + } + + frame_req->ctxt_to_hw_map = args->ctxt_to_hw_map; + frame_req->req_id = args->packet->header.request_id; + frame_req->hw_device = hw_device; + frame_req->num_hw_update_entries = args->num_hw_update_entries; + for (i = 0; i < args->num_hw_update_entries; i++) + frame_req->hw_update_entries[i] = args->hw_update_entries[i]; + + args->priv = frame_req; + + CAM_DBG(CAM_LRME, "FramePrepare : Frame[%lld]", frame_req->req_id); + + return 0; + +error: + return rc; +} + +static int cam_lrme_mgr_hw_config(void *hw_mgr_priv, + void *hw_config_args) +{ + int rc = 0; + struct cam_lrme_hw_mgr *hw_mgr = hw_mgr_priv; + struct cam_hw_config_args *args = + (struct cam_hw_config_args *)hw_config_args; + struct cam_lrme_frame_request *frame_req; + struct cam_lrme_device *hw_device = NULL; + enum cam_lrme_hw_mgr_ctx_priority priority; + + if (!hw_mgr_priv || !hw_config_args) { + CAM_ERR(CAM_LRME, "Invalid arguments, hw_mgr %pK, config %pK", + hw_mgr_priv, hw_config_args); + return -EINVAL; + } + + if (!args->num_hw_update_entries) { + CAM_ERR(CAM_LRME, "No hw update entries"); + return -EINVAL; + } + + frame_req = (struct cam_lrme_frame_request *)args->priv; + if (!frame_req) { + CAM_ERR(CAM_LRME, "No frame request"); + return -EINVAL; + } + + hw_device = frame_req->hw_device; + if (!hw_device) + return -EINVAL; + + priority = CAM_LRME_DECODE_PRIORITY(args->ctxt_to_hw_map); + if (priority == CAM_LRME_PRIORITY_HIGH) { + cam_lrme_mgr_util_put_frame_req( + &hw_device->frame_pending_list_high, + &frame_req->frame_list, &hw_device->high_req_lock); + } else { + cam_lrme_mgr_util_put_frame_req( + &hw_device->frame_pending_list_normal, + &frame_req->frame_list, &hw_device->normal_req_lock); + } + + CAM_DBG(CAM_LRME, "schedule req %llu", frame_req->req_id); + rc = cam_lrme_mgr_util_schedule_frame_req(hw_mgr, hw_device); + + return rc; +} + +static int cam_lrme_mgr_create_debugfs_entry(void) +{ + int rc = 0; + + g_lrme_hw_mgr.debugfs_entry.dentry = + debugfs_create_dir("camera_lrme", NULL); + if (!g_lrme_hw_mgr.debugfs_entry.dentry) { + CAM_ERR(CAM_LRME, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("dump_register", + 0644, + g_lrme_hw_mgr.debugfs_entry.dentry, + &g_lrme_hw_mgr.debugfs_entry.dump_register)) { + CAM_ERR(CAM_LRME, "failed to create dump register entry"); + rc = -ENOMEM; + goto err; + } + + return rc; + +err: + debugfs_remove_recursive(g_lrme_hw_mgr.debugfs_entry.dentry); + g_lrme_hw_mgr.debugfs_entry.dentry = NULL; + return rc; +} + + +int cam_lrme_mgr_register_device( + struct cam_hw_intf *lrme_hw_intf, + struct cam_iommu_handle *device_iommu, + struct cam_iommu_handle *cdm_iommu) +{ + struct cam_lrme_device *hw_device; + char buf[128]; + int i, rc; + + hw_device = &g_lrme_hw_mgr.hw_device[lrme_hw_intf->hw_idx]; + + g_lrme_hw_mgr.device_iommu = *device_iommu; + g_lrme_hw_mgr.cdm_iommu = *cdm_iommu; + + memcpy(&hw_device->hw_intf, lrme_hw_intf, sizeof(struct cam_hw_intf)); + + spin_lock_init(&hw_device->high_req_lock); + spin_lock_init(&hw_device->normal_req_lock); + INIT_LIST_HEAD(&hw_device->frame_pending_list_high); + INIT_LIST_HEAD(&hw_device->frame_pending_list_normal); + + rc = snprintf(buf, sizeof(buf), "cam_lrme_device_submit_worker%d", + lrme_hw_intf->hw_idx); + CAM_DBG(CAM_LRME, "Create submit workq for %s", buf); + rc = cam_req_mgr_workq_create(buf, + CAM_LRME_WORKQ_NUM_TASK, + &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, + 0); + if (rc) { + CAM_ERR(CAM_LRME, + "Unable to create a worker, rc=%d", rc); + return rc; + } + + for (i = 0; i < CAM_LRME_WORKQ_NUM_TASK; i++) + hw_device->work->task.pool[i].payload = + &hw_device->work_data[i]; + + if (hw_device->hw_intf.hw_ops.process_cmd) { + struct cam_lrme_hw_cmd_set_cb cb_args; + + cb_args.cam_lrme_hw_mgr_cb = cam_lrme_mgr_cb; + cb_args.data = hw_device; + + rc = hw_device->hw_intf.hw_ops.process_cmd( + hw_device->hw_intf.hw_priv, + CAM_LRME_HW_CMD_REGISTER_CB, + &cb_args, sizeof(cb_args)); + if (rc) { + CAM_ERR(CAM_LRME, "Register cb failed"); + goto destroy_workqueue; + } + CAM_DBG(CAM_LRME, "cb registered"); + } + + if (hw_device->hw_intf.hw_ops.get_hw_caps) { + rc = hw_device->hw_intf.hw_ops.get_hw_caps( + hw_device->hw_intf.hw_priv, &hw_device->hw_caps, + sizeof(hw_device->hw_caps)); + if (rc) + CAM_ERR(CAM_LRME, "Get caps failed"); + } else { + CAM_ERR(CAM_LRME, "No get_hw_caps function"); + goto destroy_workqueue; + } + g_lrme_hw_mgr.lrme_caps.dev_caps[lrme_hw_intf->hw_idx] = + hw_device->hw_caps; + g_lrme_hw_mgr.device_count++; + g_lrme_hw_mgr.lrme_caps.device_iommu = g_lrme_hw_mgr.device_iommu; + g_lrme_hw_mgr.lrme_caps.cdm_iommu = g_lrme_hw_mgr.cdm_iommu; + g_lrme_hw_mgr.lrme_caps.num_devices = g_lrme_hw_mgr.device_count; + + hw_device->valid = true; + + CAM_DBG(CAM_LRME, "device registration done"); + return 0; + +destroy_workqueue: + cam_req_mgr_workq_destroy(&hw_device->work); + + return rc; +} + +int cam_lrme_mgr_deregister_device(int device_index) +{ + struct cam_lrme_device *hw_device; + + hw_device = &g_lrme_hw_mgr.hw_device[device_index]; + cam_req_mgr_workq_destroy(&hw_device->work); + memset(hw_device, 0x0, sizeof(struct cam_lrme_device)); + g_lrme_hw_mgr.device_count--; + + return 0; +} + +int cam_lrme_hw_mgr_deinit(void) +{ + mutex_destroy(&g_lrme_hw_mgr.hw_mgr_mutex); + memset(&g_lrme_hw_mgr, 0x0, sizeof(g_lrme_hw_mgr)); + + return 0; +} + +int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, + cam_hw_event_cb_func cam_lrme_dev_buf_done_cb) +{ + int i, rc = 0; + struct cam_lrme_frame_request *frame_req; + + if (!hw_mgr_intf) + return -EINVAL; + + CAM_DBG(CAM_LRME, "device count %d", g_lrme_hw_mgr.device_count); + if (g_lrme_hw_mgr.device_count > CAM_LRME_HW_MAX) { + CAM_ERR(CAM_LRME, "Invalid count of devices"); + return -EINVAL; + } + + memset(hw_mgr_intf, 0, sizeof(*hw_mgr_intf)); + + mutex_init(&g_lrme_hw_mgr.hw_mgr_mutex); + spin_lock_init(&g_lrme_hw_mgr.free_req_lock); + INIT_LIST_HEAD(&g_lrme_hw_mgr.frame_free_list); + + /* Init hw mgr frame requests and add to free list */ + for (i = 0; i < CAM_CTX_REQ_MAX * CAM_CTX_MAX; i++) { + frame_req = &g_lrme_hw_mgr.frame_req[i]; + + memset(frame_req, 0x0, sizeof(*frame_req)); + INIT_LIST_HEAD(&frame_req->frame_list); + + list_add_tail(&frame_req->frame_list, + &g_lrme_hw_mgr.frame_free_list); + } + + hw_mgr_intf->hw_mgr_priv = &g_lrme_hw_mgr; + hw_mgr_intf->hw_get_caps = cam_lrme_mgr_get_caps; + hw_mgr_intf->hw_acquire = cam_lrme_mgr_hw_acquire; + hw_mgr_intf->hw_release = cam_lrme_mgr_hw_release; + hw_mgr_intf->hw_start = cam_lrme_mgr_hw_start; + hw_mgr_intf->hw_stop = cam_lrme_mgr_hw_stop; + hw_mgr_intf->hw_prepare_update = cam_lrme_mgr_hw_prepare_update; + hw_mgr_intf->hw_config = cam_lrme_mgr_hw_config; + hw_mgr_intf->hw_read = NULL; + hw_mgr_intf->hw_write = NULL; + hw_mgr_intf->hw_close = NULL; + hw_mgr_intf->hw_flush = cam_lrme_mgr_hw_flush; + + g_lrme_hw_mgr.event_cb = cam_lrme_dev_buf_done_cb; + + cam_lrme_mgr_create_debugfs_entry(); + + CAM_DBG(CAM_LRME, "Hw mgr init done"); + return rc; +} diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..bc77e726d3e6f1e2df9313af1f22f46711a6e0a8 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_MGR_H_ +#define _CAM_LRME_HW_MGR_H_ + +#include <linux/module.h> +#include <linux/kernel.h> + +#include <media/cam_lrme.h> +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_cpas_api.h" +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_workq.h" +#include "cam_lrme_hw_intf.h" +#include "cam_context.h" + +#define CAM_LRME_HW_MAX 1 +#define CAM_LRME_WORKQ_NUM_TASK 10 + +#define CAM_LRME_DECODE_DEVICE_INDEX(ctxt_to_hw_map) \ + ((uintptr_t)ctxt_to_hw_map & 0xF) + +#define CAM_LRME_DECODE_PRIORITY(ctxt_to_hw_map) \ + (((uintptr_t)ctxt_to_hw_map & 0xF0) >> 4) + +#define CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map) \ + ((uint64_t)(uintptr_t)ctxt_to_hw_map >> CAM_LRME_CTX_INDEX_SHIFT) + +/** + * enum cam_lrme_hw_mgr_ctx_priority + * + * CAM_LRME_PRIORITY_HIGH : High priority client + * CAM_LRME_PRIORITY_NORMAL : Normal priority client + */ +enum cam_lrme_hw_mgr_ctx_priority { + CAM_LRME_PRIORITY_HIGH, + CAM_LRME_PRIORITY_NORMAL, +}; + +/** + * struct cam_lrme_mgr_work_data : HW Mgr work data + * + * @hw_device : Pointer to the hw device + */ +struct cam_lrme_mgr_work_data { + struct cam_lrme_device *hw_device; +}; + +/** + * struct cam_lrme_debugfs_entry : debugfs entry struct + * + * @dentry : entry of debugfs + * @dump_register : flag to dump registers + */ +struct cam_lrme_debugfs_entry { + struct dentry *dentry; + bool dump_register; +}; + +/** + * struct cam_lrme_device : LRME HW device + * + * @hw_caps : HW device's capabilities + * @hw_intf : HW device's interface information + * @num_context : Number of contexts using this device + * @valid : Whether this device is valid + * @work : HW device's work queue + * @work_data : HW device's work data + * @frame_pending_list_high : High priority request queue + * @frame_pending_list_normal : Normal priority request queue + * @high_req_lock : Spinlock of high priority queue + * @normal_req_lock : Spinlock of normal priority queue + */ +struct cam_lrme_device { + struct cam_lrme_dev_cap hw_caps; + struct cam_hw_intf hw_intf; + uint32_t num_context; + bool valid; + struct cam_req_mgr_core_workq *work; + struct cam_lrme_mgr_work_data work_data[CAM_LRME_WORKQ_NUM_TASK]; + struct list_head frame_pending_list_high; + struct list_head frame_pending_list_normal; + spinlock_t high_req_lock; + spinlock_t normal_req_lock; +}; + +/** + * struct cam_lrme_hw_mgr : LRME HW manager + * + * @device_count : Number of HW devices + * @frame_free_list : List of free frame request + * @hw_mgr_mutex : Mutex to protect HW manager data + * @free_req_lock :Spinlock to protect frame_free_list + * @hw_device : List of HW devices + * @device_iommu : Device iommu + * @cdm_iommu : cdm iommu + * @frame_req : List of frame request to use + * @lrme_caps : LRME capabilities + * @event_cb : IRQ callback function + * @debugfs_entry : debugfs entry to set debug prop + */ +struct cam_lrme_hw_mgr { + uint32_t device_count; + struct list_head frame_free_list; + struct mutex hw_mgr_mutex; + spinlock_t free_req_lock; + struct cam_lrme_device hw_device[CAM_LRME_HW_MAX]; + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_lrme_frame_request frame_req[CAM_CTX_REQ_MAX * CAM_CTX_MAX]; + struct cam_lrme_query_cap_cmd lrme_caps; + cam_hw_event_cb_func event_cb; + struct cam_lrme_debugfs_entry debugfs_entry; +}; + +int cam_lrme_mgr_register_device(struct cam_hw_intf *lrme_hw_intf, + struct cam_iommu_handle *device_iommu, + struct cam_iommu_handle *cdm_iommu); +int cam_lrme_mgr_deregister_device(int device_index); + +#endif /* _CAM_LRME_HW_MGR_H_ */ diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..df6ea0eac798e6ececae363b30a50103fe58f56e --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_MGR_INTF_H_ +#define _CAM_LRME_HW_MGR_INTF_H_ + +#include <linux/of.h> + +#include "cam_debug_util.h" +#include "cam_hw_mgr_intf.h" + +int cam_lrme_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, + cam_hw_event_cb_func cam_lrme_dev_buf_done_cb); +int cam_lrme_hw_mgr_deinit(void); + +#endif /* _CAM_LRME_HW_MGR_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..8df30c0f44deb895df2bb938948d8f250ea75790 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sync +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cdm +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -I$(srctree)/techpack/camera0 +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_dev.o cam_lrme_hw_core.o cam_lrme_hw_soc.o diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c new file mode 100644 index 0000000000000000000000000000000000000000..b736708fa99d05ca855553f3108ddb20a526996c --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -0,0 +1,1274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_smmu_api.h" + +static void cam_lrme_dump_registers(void __iomem *base) +{ + /* dump the clc registers */ + cam_io_dump(base, 0x60, (0xc0 - 0x60) / 0x4); + /* dump the fe and we registers */ + cam_io_dump(base, 0x200, (0x29c - 0x200) / 0x4); + cam_io_dump(base, 0x2f0, (0x330 - 0x2f0) / 0x4); + cam_io_dump(base, 0x500, (0x5b4 - 0x500) / 0x4); + cam_io_dump(base, 0x700, (0x778 - 0x700) / 0x4); + cam_io_dump(base, 0x800, (0x878 - 0x800) / 0x4); + /* dump lrme sw registers, interrupts */ + cam_io_dump(base, 0x900, (0x928 - 0x900) / 0x4); +} + +static void cam_lrme_cdm_write_reg_val_pair(uint32_t *buffer, + uint32_t *index, uint32_t reg_offset, uint32_t reg_value) +{ + buffer[(*index)++] = reg_offset; + buffer[(*index)++] = reg_value; +} + +static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf, + uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd, + struct cam_lrme_hw_info *hw_info) +{ + uint32_t reg_val; + + /* 1. config buffer size */ + if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) + reg_val = io_buf->io_cfg->planes[0].width * 2; + else + reg_val = io_buf->io_cfg->planes[0].width; + reg_val |= (io_buf->io_cfg->planes[0].height << 16); + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size, + reg_val); + + CAM_DBG(CAM_LRME, + "width %d", io_buf->io_cfg->planes[0].width); + CAM_DBG(CAM_LRME, + "height %d", io_buf->io_cfg->planes[0].height); + + /* 2. config image address */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].addr_image, + io_buf->io_addr[0]); + + CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]); + + /* 3. config stride */ + reg_val = io_buf->io_cfg->planes[0].plane_stride; + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].rd_stride, + reg_val); + + CAM_DBG(CAM_LRME, "plane_stride %d", + io_buf->io_cfg->planes[0].plane_stride); + + /* 4. enable client */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].core_cfg, 0x1); + + /* 5. unpack_cfg */ + if (io_buf->io_cfg->format == CAM_FORMAT_PD10) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, + 0x0); + else if (io_buf->io_cfg->format == CAM_FORMAT_Y_ONLY || + io_buf->io_cfg->format == CAM_FORMAT_PLAIN8 || + io_buf->io_cfg->format == CAM_FORMAT_NV12 || + io_buf->io_cfg->format == CAM_FORMAT_NV21) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, + 0x1); + else if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_rd_reg.bus_client_reg[index].unpack_cfg_0, + 0x22); + else + CAM_ERR(CAM_LRME, "Unsupported format %d", + io_buf->io_cfg->format); +} + +static void cam_lrme_hw_util_fill_we_reg(struct cam_lrme_hw_io_buffer *io_buf, + uint32_t index, uint32_t *reg_val_pair, uint32_t *num_cmd, + struct cam_lrme_hw_info *hw_info) +{ + /* config client mode */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].cfg, + 0x1); + + /* image address */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].addr_image, + io_buf->io_addr[0]); + CAM_DBG(CAM_LRME, "io addr %llu", io_buf->io_addr[0]); + + /* buffer width and height */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].buffer_width_cfg, + io_buf->io_cfg->planes[0].width); + CAM_DBG(CAM_LRME, "width %d", io_buf->io_cfg->planes[0].width); + + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].buffer_height_cfg, + io_buf->io_cfg->planes[0].height); + CAM_DBG(CAM_LRME, "height %d", io_buf->io_cfg->planes[0].height); + + /* packer cfg */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].packer_cfg, + (index == 0) ? 0x1 : 0x5); + + /* client stride */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, + hw_info->bus_wr_reg.bus_client_reg[index].wr_stride, + io_buf->io_cfg->planes[0].plane_stride); + CAM_DBG(CAM_LRME, "plane_stride %d", + io_buf->io_cfg->planes[0].plane_stride); +} + + +static int cam_lrme_hw_util_process_config_hw(struct cam_hw_info *lrme_hw, + struct cam_lrme_hw_cmd_config_args *config_args) +{ + int i; + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_cdm_info *hw_cdm_info; + uint32_t *cmd_buf_addr = config_args->cmd_buf_addr; + uint32_t reg_val_pair[CAM_LRME_MAX_REG_PAIR_NUM]; + struct cam_lrme_hw_io_buffer *io_buf; + struct cam_lrme_hw_info *hw_info = + ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info; + uint32_t num_cmd = 0; + uint32_t size; + uint32_t mem_base, available_size = config_args->size; + uint32_t output_res_mask = 0, input_res_mask = 0; + + + if (!cmd_buf_addr) { + CAM_ERR(CAM_LRME, "Invalid input args"); + return -EINVAL; + } + + hw_cdm_info = + ((struct cam_lrme_core *)lrme_hw->core_info)->hw_cdm_info; + + for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) { + io_buf = &config_args->input_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_INPUT) { + CAM_ERR(CAM_LRME, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + CAM_DBG(CAM_LRME, + "resource_type %d", io_buf->io_cfg->resource_type); + + switch (io_buf->io_cfg->resource_type) { + case CAM_LRME_IO_TYPE_TAR: + cam_lrme_hw_util_fill_fe_reg(io_buf, 0, reg_val_pair, + &num_cmd, hw_info); + + input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_TAR; + break; + case CAM_LRME_IO_TYPE_REF: + cam_lrme_hw_util_fill_fe_reg(io_buf, 1, reg_val_pair, + &num_cmd, hw_info); + + input_res_mask |= CAM_LRME_INPUT_PORT_TYPE_REF; + break; + default: + CAM_ERR(CAM_LRME, "wrong resource_type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++) + if (!((input_res_mask >> i) & 0x1)) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, + hw_info->bus_rd_reg.bus_client_reg[i].core_cfg, + 0x0); + + for (i = 0; i < CAM_LRME_MAX_IO_BUFFER; i++) { + io_buf = &config_args->output_buf[i]; + + if (io_buf->valid == false) + break; + + if (io_buf->io_cfg->direction != CAM_BUF_OUTPUT) { + CAM_ERR(CAM_LRME, "Incorrect direction %d %d", + io_buf->io_cfg->direction, CAM_BUF_INPUT); + return -EINVAL; + } + + CAM_DBG(CAM_LRME, "resource_type %d", + io_buf->io_cfg->resource_type); + switch (io_buf->io_cfg->resource_type) { + case CAM_LRME_IO_TYPE_DS2: + cam_lrme_hw_util_fill_we_reg(io_buf, 0, reg_val_pair, + &num_cmd, hw_info); + + output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_DS2; + break; + case CAM_LRME_IO_TYPE_RES: + cam_lrme_hw_util_fill_we_reg(io_buf, 1, reg_val_pair, + &num_cmd, hw_info); + + output_res_mask |= CAM_LRME_OUTPUT_PORT_TYPE_RES; + break; + + default: + CAM_ERR(CAM_LRME, "wrong resource_type %d", + io_buf->io_cfg->resource_type); + return -EINVAL; + } + } + + for (i = 0; i < CAM_LRME_BUS_RD_MAX_CLIENTS; i++) + if (!((output_res_mask >> i) & 0x1)) + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, + hw_info->bus_wr_reg.bus_client_reg[i].cfg, 0x0); + + if (output_res_mask) { + /* write composite mask */ + cam_lrme_cdm_write_reg_val_pair(reg_val_pair, &num_cmd, + hw_info->bus_wr_reg.common_reg.composite_mask_0, + output_res_mask); + } + + size = hw_cdm_info->cdm_ops->cdm_required_size_changebase(); + if ((size * 4) > available_size) { + CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d", + available_size, size); + return -EINVAL; + } + + mem_base = CAM_SOC_GET_REG_MAP_CAM_BASE(soc_info, CAM_LRME_BASE_IDX); + + hw_cdm_info->cdm_ops->cdm_write_changebase(cmd_buf_addr, mem_base); + cmd_buf_addr += size; + available_size -= (size * 4); + + size = hw_cdm_info->cdm_ops->cdm_required_size_reg_random( + num_cmd / 2); + + if ((size * 4) > available_size) { + CAM_ERR(CAM_LRME, "buf size:%d is not sufficient, expected: %d", + available_size, size); + return -ENOMEM; + } + + hw_cdm_info->cdm_ops->cdm_write_regrandom(cmd_buf_addr, num_cmd / 2, + reg_val_pair); + cmd_buf_addr += size; + available_size -= (size * 4); + + config_args->config_buf_size = + config_args->size - available_size; + + return 0; +} + +static int cam_lrme_hw_util_submit_go(struct cam_hw_info *lrme_hw) +{ + struct cam_lrme_core *lrme_core; + struct cam_hw_soc_info *soc_info; + struct cam_lrme_hw_info *hw_info; + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + hw_info = lrme_core->hw_info; + soc_info = &lrme_hw->soc_info; + + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.cmd); + + return 0; +} + +static int cam_lrme_hw_util_reset(struct cam_hw_info *lrme_hw, + uint32_t reset_type) +{ + struct cam_lrme_core *lrme_core; + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_hw_info *hw_info; + long time_left; + + lrme_core = lrme_hw->core_info; + hw_info = lrme_core->hw_info; + + switch (reset_type) { + case CAM_LRME_HW_RESET_TYPE_HW_RESET: + reinit_completion(&lrme_core->reset_complete); + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_rst_cmd); + time_left = wait_for_completion_timeout( + &lrme_core->reset_complete, + msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT)); + if (time_left <= 0) { + CAM_ERR(CAM_LRME, + "HW reset wait failed time_left=%ld", + time_left); + return -ETIMEDOUT; + } + break; + case CAM_LRME_HW_RESET_TYPE_SW_RESET: + cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.sw_reset); + cam_io_w_mb(0x3, soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.sw_reset); + reinit_completion(&lrme_core->reset_complete); + cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_rst_cmd); + time_left = wait_for_completion_timeout( + &lrme_core->reset_complete, + msecs_to_jiffies(CAM_LRME_HW_RESET_TIMEOUT)); + if (time_left <= 0) { + CAM_ERR(CAM_LRME, + "SW reset wait failed time_left=%ld", + time_left); + return -ETIMEDOUT; + } + break; + } + + return 0; +} + +int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw, + struct cam_lrme_dev_cap *hw_caps) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_hw_info *hw_info = + ((struct cam_lrme_core *)lrme_hw->core_info)->hw_info; + uint32_t reg_value; + + if (!hw_info) { + CAM_ERR(CAM_LRME, "Invalid hw info data"); + return -EINVAL; + } + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->clc_reg.clc_hw_version); + hw_caps->clc_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->clc_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->clc_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.hw_version); + hw_caps->bus_rd_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->bus_rd_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->bus_rd_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.hw_version); + hw_caps->bus_wr_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->bus_wr_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->bus_wr_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_hw_version); + hw_caps->top_hw_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->top_hw_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->top_hw_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + reg_value = cam_io_r_mb(soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_titan_version); + hw_caps->top_titan_version.gen = + CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1C); + hw_caps->top_titan_version.rev = + CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10); + hw_caps->top_titan_version.step = + CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0); + + return 0; +} + +static int cam_lrme_hw_util_submit_req(struct cam_lrme_core *lrme_core, + struct cam_lrme_frame_request *frame_req) +{ + struct cam_lrme_cdm_info *hw_cdm_info = + lrme_core->hw_cdm_info; + struct cam_cdm_bl_request *cdm_cmd = hw_cdm_info->cdm_cmd; + struct cam_hw_update_entry *cmd; + int i, rc = 0; + + if (frame_req->num_hw_update_entries > 0) { + cdm_cmd->cmd_arrary_count = frame_req->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = false; + cdm_cmd->userdata = NULL; + cdm_cmd->cookie = 0; + + for (i = 0; i <= frame_req->num_hw_update_entries; i++) { + cmd = (frame_req->hw_update_entries + i); + cdm_cmd->cmd[i].bl_addr.mem_handle = cmd->handle; + cdm_cmd->cmd[i].offset = cmd->offset; + cdm_cmd->cmd[i].len = cmd->len; + } + + rc = cam_cdm_submit_bls(hw_cdm_info->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to submit cdm commands"); + return -EINVAL; + } + } else { + CAM_ERR(CAM_LRME, "No hw update entry"); + rc = -EINVAL; + } + + return rc; +} + +static int cam_lrme_hw_util_flush_ctx(struct cam_hw_info *lrme_hw, + void *ctxt_to_hw_map) +{ + int rc = -ENODEV; + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_hw_cb_args cb_args; + struct cam_lrme_frame_request *req_proc, *req_submit; + struct cam_lrme_hw_submit_args submit_args; + + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) { + CAM_ERR(CAM_LRME, "reset failed"); + return rc; + } + + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + req_proc = lrme_core->req_proc; + req_submit = lrme_core->req_submit; + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + + if (req_submit && req_submit->ctxt_to_hw_map == ctxt_to_hw_map) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_submit; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_submit) { + submit_args.frame_req = req_submit; + submit_args.hw_update_entries = req_submit->hw_update_entries; + submit_args.num_hw_update_entries = + req_submit->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_submit); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_submit; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + if (req_proc && req_proc->ctxt_to_hw_map == ctxt_to_hw_map) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_proc; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_proc) { + submit_args.frame_req = req_proc; + submit_args.hw_update_entries = req_proc->hw_update_entries; + submit_args.num_hw_update_entries = + req_proc->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_proc); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_proc; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + return rc; +} + +static int cam_lrme_hw_util_flush_req(struct cam_hw_info *lrme_hw, + struct cam_lrme_frame_request *req_to_flush) +{ + int rc = -ENODEV; + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_hw_cb_args cb_args; + struct cam_lrme_frame_request *req_proc, *req_submit; + struct cam_lrme_hw_submit_args submit_args; + + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) { + CAM_ERR(CAM_LRME, "reset failed"); + return rc; + } + + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + req_proc = lrme_core->req_proc; + req_submit = lrme_core->req_submit; + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + + if (req_submit && req_submit == req_to_flush) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_submit; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_submit) { + submit_args.frame_req = req_submit; + submit_args.hw_update_entries = req_submit->hw_update_entries; + submit_args.num_hw_update_entries = + req_submit->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_submit); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_submit; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + if (req_proc && req_proc == req_to_flush) { + cb_args.cb_type = CAM_LRME_CB_PUT_FRAME; + cb_args.frame_req = req_proc; + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else if (req_proc) { + submit_args.frame_req = req_proc; + submit_args.hw_update_entries = req_proc->hw_update_entries; + submit_args.num_hw_update_entries = + req_proc->num_hw_update_entries; + rc = cam_lrme_hw_util_submit_req(lrme_core, req_proc); + if (rc) + CAM_ERR(CAM_LRME, "Submit failed"); + lrme_core->req_submit = req_proc; + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + } + + return rc; +} + + +static int cam_lrme_hw_util_process_err(struct cam_hw_info *lrme_hw) +{ + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_frame_request *req_proc, *req_submit; + struct cam_lrme_hw_cb_args cb_args; + int rc; + + req_proc = lrme_core->req_proc; + req_submit = lrme_core->req_submit; + cb_args.cb_type = CAM_LRME_CB_ERROR; + + if ((lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) && + (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING) && + (lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND)) { + CAM_ERR(CAM_LRME, "Get error irq in wrong state %d", + lrme_core->state); + } + + cam_lrme_dump_registers(lrme_hw->soc_info.reg_map[0].mem_base); + + CAM_ERR_RATE_LIMIT(CAM_LRME, "Start recovery"); + lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY; + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) + CAM_ERR(CAM_LRME, "Failed to reset"); + + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + if (!rc) + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + + cb_args.frame_req = req_proc; + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data, + &cb_args); + + cb_args.frame_req = req_submit; + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb(lrme_core->hw_mgr_cb.data, + &cb_args); + + return rc; +} + +static int cam_lrme_hw_util_process_reg_update( + struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args) +{ + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + int rc = 0; + + cb_args->cb_type |= CAM_LRME_CB_COMP_REG_UPDATE; + if (lrme_core->state == CAM_LRME_CORE_STATE_REQ_PENDING) { + lrme_core->state = CAM_LRME_CORE_STATE_PROCESSING; + } else { + CAM_ERR(CAM_LRME, "Reg update in wrong state %d", + lrme_core->state); + rc = cam_lrme_hw_util_process_err(lrme_hw); + if (rc) + CAM_ERR(CAM_LRME, "Failed to reset"); + return -EINVAL; + } + + lrme_core->req_proc = lrme_core->req_submit; + lrme_core->req_submit = NULL; + + if (lrme_core->dump_flag) + cam_lrme_dump_registers(lrme_hw->soc_info.reg_map[0].mem_base); + + return 0; +} + +static int cam_lrme_hw_util_process_idle( + struct cam_hw_info *lrme_hw, struct cam_lrme_hw_cb_args *cb_args) +{ + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + int rc = 0; + + cb_args->cb_type |= CAM_LRME_CB_BUF_DONE; + switch (lrme_core->state) { + case CAM_LRME_CORE_STATE_REQ_PROC_PEND: + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + break; + + case CAM_LRME_CORE_STATE_PROCESSING: + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + break; + + default: + CAM_ERR(CAM_LRME, "Idle in wrong state %d", + lrme_core->state); + rc = cam_lrme_hw_util_process_err(lrme_hw); + return rc; + } + cb_args->frame_req = lrme_core->req_proc; + lrme_core->req_proc = NULL; + + return 0; +} + +void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, + enum cam_lrme_irq_set set) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_core *lrme_core = lrme_hw->core_info; + struct cam_lrme_hw_info *hw_info = lrme_core->hw_info; + + switch (set) { + case CAM_LRME_IRQ_ENABLE: + cam_io_w_mb(0xFFFF, + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_mask); + cam_io_w_mb(0xFFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_0); + cam_io_w_mb(0xFFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_1); + cam_io_w_mb(0xFFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_mask); + break; + + case CAM_LRME_IRQ_DISABLE: + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_mask); + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_0); + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_1); + cam_io_w_mb(0x0, + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_mask); + break; + } +} + + +int cam_lrme_hw_process_irq(void *priv, void *data) +{ + struct cam_lrme_hw_work_data *work_data; + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + int rc = 0; + uint32_t top_irq_status, fe_irq_status; + uint32_t *we_irq_status; + struct cam_lrme_hw_cb_args cb_args; + + if (!data || !priv) { + CAM_ERR(CAM_LRME, "Invalid data %pK %pK", data, priv); + return -EINVAL; + } + + memset(&cb_args, 0, sizeof(struct cam_lrme_hw_cb_args)); + lrme_hw = (struct cam_hw_info *)priv; + work_data = (struct cam_lrme_hw_work_data *)data; + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + top_irq_status = work_data->top_irq_status; + fe_irq_status = work_data->fe_irq_status; + we_irq_status = work_data->we_irq_status; + + CAM_DBG(CAM_LRME, + "top status %x, fe status %x, we status0 %x, we status1 %x", + top_irq_status, fe_irq_status, we_irq_status[0], + we_irq_status[1]); + CAM_DBG(CAM_LRME, "Current state %d", lrme_core->state); + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_DBG(CAM_LRME, "LRME HW is in off state"); + goto end; + } + + if (top_irq_status & (1 << 3)) { + CAM_DBG(CAM_LRME, "Error"); + rc = cam_lrme_hw_util_process_err(lrme_hw); + if (rc) + CAM_ERR(CAM_LRME, "Process error failed"); + goto end; + } + + if (we_irq_status[0] & (1 << 1)) { + CAM_DBG(CAM_LRME, "reg update"); + rc = cam_lrme_hw_util_process_reg_update(lrme_hw, &cb_args); + if (rc) { + CAM_ERR(CAM_LRME, "Process reg_update failed"); + goto end; + } + } + + if (top_irq_status & (1 << 4)) { + CAM_DBG(CAM_LRME, "IDLE"); + if (!lrme_core->req_proc) { + CAM_DBG(CAM_LRME, "No frame request to process idle"); + goto end; + } + rc = cam_lrme_hw_util_process_idle(lrme_hw, &cb_args); + if (rc) { + CAM_ERR(CAM_LRME, "Process idle failed"); + goto end; + } + } + + if (lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb) { + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb( + lrme_core->hw_mgr_cb.data, &cb_args); + } else { + CAM_ERR(CAM_LRME, "No hw mgr cb"); + rc = -EINVAL; + } + +end: + mutex_unlock(&lrme_hw->hw_mutex); + return rc; +} + +int cam_lrme_hw_start(void *hw_priv, void *hw_start_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + int rc = 0; + struct cam_lrme_core *lrme_core; + + if (!lrme_hw) { + CAM_ERR(CAM_LRME, + "Invalid input params, lrme_hw %pK", + lrme_hw); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->open_count > 0) { + lrme_hw->open_count++; + CAM_DBG(CAM_LRME, "This device is activated before"); + goto unlock; + } + + rc = cam_lrme_soc_enable_resources(lrme_hw); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to enable soc resources"); + goto unlock; + } + + rc = cam_lrme_hw_util_reset(lrme_hw, CAM_LRME_HW_RESET_TYPE_HW_RESET); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to reset hw"); + goto disable_soc; + } + + if (lrme_core->hw_cdm_info) { + struct cam_lrme_cdm_info *hw_cdm_info = + lrme_core->hw_cdm_info; + + rc = cam_cdm_stream_on(hw_cdm_info->cdm_handle); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to stream on cdm"); + goto disable_soc; + } + } + + lrme_hw->hw_state = CAM_HW_STATE_POWER_UP; + lrme_hw->open_count++; + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + + CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); + mutex_unlock(&lrme_hw->hw_mutex); + return rc; + +disable_soc: + if (cam_lrme_soc_disable_resources(lrme_hw)) + CAM_ERR(CAM_LRME, "Error in disable soc resources"); +unlock: + CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); + mutex_unlock(&lrme_hw->hw_mutex); + return rc; +} + +int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + int rc = 0; + struct cam_lrme_core *lrme_core; + + if (!lrme_hw) { + CAM_ERR(CAM_LRME, "Invalid argument"); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->open_count == 0 || + lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_ERR(CAM_LRME, "Error Unbalanced stop"); + return -EINVAL; + } + lrme_hw->open_count--; + + CAM_DBG(CAM_LRME, "open count %d", lrme_hw->open_count); + + if (lrme_hw->open_count) + goto unlock; + + lrme_core->req_proc = NULL; + lrme_core->req_submit = NULL; + + if (lrme_core->hw_cdm_info) { + struct cam_lrme_cdm_info *hw_cdm_info = + lrme_core->hw_cdm_info; + + rc = cam_cdm_stream_off(hw_cdm_info->cdm_handle); + if (rc) { + CAM_ERR(CAM_LRME, + "Failed in CDM StreamOff, handle=0x%x, rc=%d", + hw_cdm_info->cdm_handle, rc); + goto unlock; + } + } + + rc = cam_lrme_soc_disable_resources(lrme_hw); + if (rc) + CAM_ERR(CAM_LRME, "Failed in Disable SOC, rc=%d", rc); + + lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + if (lrme_core->state == CAM_LRME_CORE_STATE_IDLE) { + lrme_core->state = CAM_LRME_CORE_STATE_INIT; + } else { + CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state); + rc = -EINVAL; + } + +unlock: + mutex_unlock(&lrme_hw->hw_mutex); + return rc; +} + +int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, + uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + struct cam_lrme_core *lrme_core; + struct cam_lrme_hw_submit_args *args = + (struct cam_lrme_hw_submit_args *)hw_submit_args; + int rc = 0; + struct cam_lrme_frame_request *frame_req; + + + if (!hw_priv || !hw_submit_args) { + CAM_ERR(CAM_LRME, "Invalid input"); + return -EINVAL; + } + + if (sizeof(struct cam_lrme_hw_submit_args) != arg_size) { + CAM_ERR(CAM_LRME, + "size of args %zu, arg_size %d", + sizeof(struct cam_lrme_hw_submit_args), arg_size); + return -EINVAL; + } + + frame_req = args->frame_req; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_hw->open_count == 0) { + CAM_ERR(CAM_LRME, "HW is not open"); + mutex_unlock(&lrme_hw->hw_mutex); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + if (lrme_core->state != CAM_LRME_CORE_STATE_IDLE && + lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "device busy, can not submit, state %d", + lrme_core->state); + return -EBUSY; + } + + if (lrme_core->req_submit != NULL) { + CAM_ERR(CAM_LRME, "req_submit is not NULL"); + return -EBUSY; + } + + rc = cam_lrme_hw_util_submit_req(lrme_core, frame_req); + if (rc) { + CAM_ERR(CAM_LRME, "Submit req failed"); + goto error; + } + + switch (lrme_core->state) { + case CAM_LRME_CORE_STATE_PROCESSING: + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PROC_PEND; + break; + + case CAM_LRME_CORE_STATE_IDLE: + cam_lrme_hw_util_submit_go(lrme_hw); + lrme_core->state = CAM_LRME_CORE_STATE_REQ_PENDING; + break; + + default: + CAM_ERR(CAM_LRME, "Wrong hw state"); + rc = -EINVAL; + goto error; + } + + lrme_core->req_submit = frame_req; + + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "Release lock, submit done for req %llu", + frame_req->req_id); + + return 0; + +error: + mutex_unlock(&lrme_hw->hw_mutex); + + return rc; + +} + +int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = hw_priv; + struct cam_lrme_core *lrme_core; + struct cam_lrme_hw_reset_args *lrme_reset_args = reset_core_args; + int rc; + + if (!hw_priv) { + CAM_ERR(CAM_LRME, "Invalid input args"); + return -EINVAL; + } + + if (!reset_core_args || + sizeof(struct cam_lrme_hw_reset_args) != arg_size) { + CAM_ERR(CAM_LRME, "Invalid reset args"); + return -EINVAL; + } + + lrme_core = lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + if (lrme_core->state == CAM_LRME_CORE_STATE_RECOVERY) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_ERR(CAM_LRME, "Reset not allowed in %d state", + lrme_core->state); + return -EINVAL; + } + + lrme_core->state = CAM_LRME_CORE_STATE_RECOVERY; + + rc = cam_lrme_hw_util_reset(lrme_hw, lrme_reset_args->reset_type); + if (rc) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_ERR(CAM_FD, "Failed to reset"); + return rc; + } + + lrme_core->state = CAM_LRME_CORE_STATE_IDLE; + + mutex_unlock(&lrme_hw->hw_mutex); + + return 0; +} + +int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size) +{ + struct cam_lrme_core *lrme_core = NULL; + struct cam_hw_info *lrme_hw = hw_priv; + struct cam_lrme_hw_flush_args *flush_args = + (struct cam_lrme_hw_flush_args *)hw_flush_args; + int rc = -ENODEV; + + if (!hw_priv) { + CAM_ERR(CAM_LRME, "Invalid arguments %pK", hw_priv); + return -EINVAL; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + + mutex_lock(&lrme_hw->hw_mutex); + + if (lrme_core->state != CAM_LRME_CORE_STATE_PROCESSING && + lrme_core->state != CAM_LRME_CORE_STATE_REQ_PENDING && + lrme_core->state != CAM_LRME_CORE_STATE_REQ_PROC_PEND) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "Flush is not needed in %d state", + lrme_core->state); + return 0; + } + + if (!lrme_core->req_proc && !lrme_core->req_submit) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "no req in device"); + return 0; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + if ((!lrme_core->req_submit || + lrme_core->req_submit->ctxt_to_hw_map != + flush_args->ctxt_to_hw_map) && + (!lrme_core->req_proc || + lrme_core->req_proc->ctxt_to_hw_map != + flush_args->ctxt_to_hw_map)) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "hw running on different ctx"); + return 0; + } + rc = cam_lrme_hw_util_flush_ctx(lrme_hw, + flush_args->ctxt_to_hw_map); + if (rc) + CAM_ERR(CAM_LRME, "Flush all failed"); + break; + + case CAM_FLUSH_TYPE_REQ: + if ((!lrme_core->req_submit || + lrme_core->req_submit != flush_args->req_to_flush) && + (!lrme_core->req_proc || + lrme_core->req_proc != flush_args->req_to_flush)) { + mutex_unlock(&lrme_hw->hw_mutex); + CAM_DBG(CAM_LRME, "hw running on different ctx"); + return 0; + } + rc = cam_lrme_hw_util_flush_req(lrme_hw, + flush_args->req_to_flush); + if (rc) + CAM_ERR(CAM_LRME, "Flush req failed"); + break; + + default: + CAM_ERR(CAM_LRME, "Unsupported flush type"); + break; + } + + mutex_unlock(&lrme_hw->hw_mutex); + + return rc; +} + +int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + struct cam_lrme_dev_cap *lrme_hw_caps = + (struct cam_lrme_dev_cap *)get_hw_cap_args; + + if (!hw_priv || !get_hw_cap_args) { + CAM_ERR(CAM_LRME, "Invalid input pointers %pK %pK", + hw_priv, get_hw_cap_args); + return -EINVAL; + } + + lrme_hw = (struct cam_hw_info *)hw_priv; + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + *lrme_hw_caps = lrme_core->hw_caps; + + return 0; +} + +irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) +{ + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + struct cam_hw_soc_info *soc_info; + struct cam_lrme_hw_info *hw_info; + struct crm_workq_task *task; + struct cam_lrme_hw_work_data *work_data; + uint32_t top_irq_status, fe_irq_status, we_irq_status0, we_irq_status1; + int rc; + + if (!data) { + CAM_ERR(CAM_LRME, "Invalid data in IRQ callback"); + return IRQ_NONE; + } + + lrme_hw = (struct cam_hw_info *)data; + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + soc_info = &lrme_hw->soc_info; + hw_info = lrme_core->hw_info; + + top_irq_status = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_status); + CAM_DBG(CAM_LRME, "top_irq_status %x", top_irq_status); + cam_io_w_mb(top_irq_status, + soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_clear); + top_irq_status &= CAM_LRME_TOP_IRQ_MASK; + + fe_irq_status = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_status); + CAM_DBG(CAM_LRME, "fe_irq_status %x", fe_irq_status); + cam_io_w_mb(fe_irq_status, + soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_clear); + fe_irq_status &= CAM_LRME_FE_IRQ_MASK; + + we_irq_status0 = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_status_0); + CAM_DBG(CAM_LRME, "we_irq_status[0] %x", we_irq_status0); + cam_io_w_mb(we_irq_status0, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_clear_0); + we_irq_status0 &= CAM_LRME_WE_IRQ_MASK_0; + + we_irq_status1 = cam_io_r_mb( + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_status_1); + CAM_DBG(CAM_LRME, "we_irq_status[1] %x", we_irq_status1); + cam_io_w_mb(we_irq_status1, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_clear_1); + we_irq_status1 &= CAM_LRME_WE_IRQ_MASK_1; + + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->titan_reg.top_irq_cmd); + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_cmd); + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + hw_info->bus_rd_reg.common_reg.irq_cmd); + + if (top_irq_status & 0x1) { + complete(&lrme_core->reset_complete); + top_irq_status &= (~0x1); + } + + if (top_irq_status || fe_irq_status || + we_irq_status0 || we_irq_status1) { + task = cam_req_mgr_workq_get_task(lrme_core->work); + if (!task) { + CAM_ERR(CAM_LRME, "no empty task available"); + return IRQ_NONE; + } + work_data = (struct cam_lrme_hw_work_data *)task->payload; + work_data->top_irq_status = top_irq_status; + work_data->fe_irq_status = fe_irq_status; + work_data->we_irq_status[0] = we_irq_status0; + work_data->we_irq_status[1] = we_irq_status1; + task->process_cb = cam_lrme_hw_process_irq; + rc = cam_req_mgr_workq_enqueue_task(task, data, + CRM_TASK_PRIORITY_0); + if (rc) + CAM_ERR(CAM_LRME, + "Failed in enqueue work task, rc=%d", rc); + } + + return IRQ_HANDLED; +} + +int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size) +{ + struct cam_hw_info *lrme_hw = (struct cam_hw_info *)hw_priv; + int rc = 0; + + switch (cmd_type) { + case CAM_LRME_HW_CMD_PREPARE_HW_UPDATE: { + struct cam_lrme_hw_cmd_config_args *config_args; + + config_args = (struct cam_lrme_hw_cmd_config_args *)cmd_args; + rc = cam_lrme_hw_util_process_config_hw(lrme_hw, config_args); + break; + } + + case CAM_LRME_HW_CMD_REGISTER_CB: { + struct cam_lrme_hw_cmd_set_cb *cb_args; + struct cam_lrme_device *hw_device; + struct cam_lrme_core *lrme_core = + (struct cam_lrme_core *)lrme_hw->core_info; + cb_args = (struct cam_lrme_hw_cmd_set_cb *)cmd_args; + lrme_core->hw_mgr_cb.cam_lrme_hw_mgr_cb = + cb_args->cam_lrme_hw_mgr_cb; + lrme_core->hw_mgr_cb.data = cb_args->data; + hw_device = cb_args->data; + rc = 0; + break; + } + + case CAM_LRME_HW_CMD_SUBMIT: { + struct cam_lrme_hw_submit_args *submit_args; + + submit_args = (struct cam_lrme_hw_submit_args *)cmd_args; + rc = cam_lrme_hw_submit_req(hw_priv, + submit_args, arg_size); + break; + } + + case CAM_LRME_HW_CMD_DUMP_REGISTER: { + struct cam_lrme_core *lrme_core = + (struct cam_lrme_core *)lrme_hw->core_info; + lrme_core->dump_flag = *(bool *)cmd_args; + CAM_DBG(CAM_LRME, "dump_flag %d", lrme_core->dump_flag); + break; + } + + default: + break; + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h new file mode 100644 index 0000000000000000000000000000000000000000..accb5a8b582734e9136aa2df48fd957c9654feb4 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h @@ -0,0 +1,451 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_CORE_H_ +#define _CAM_LRME_HW_CORE_H_ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_defs.h> +#include <media/cam_lrme.h> + +#include "cam_common_util.h" +#include "cam_debug_util.h" +#include "cam_io_util.h" +#include "cam_cpas_api.h" +#include "cam_cdm_intf_api.h" +#include "cam_lrme_hw_intf.h" +#include "cam_lrme_hw_soc.h" +#include "cam_req_mgr_workq.h" + +#define CAM_LRME_HW_RESET_TIMEOUT 3000 + +#define CAM_LRME_BUS_RD_MAX_CLIENTS 2 +#define CAM_LRME_BUS_WR_MAX_CLIENTS 2 + +#define CAM_LRME_HW_WORKQ_NUM_TASK 30 + +#define CAM_LRME_TOP_IRQ_MASK 0x19 +#define CAM_LRME_WE_IRQ_MASK_0 0x2 +#define CAM_LRME_WE_IRQ_MASK_1 0x0 +#define CAM_LRME_FE_IRQ_MASK 0x0 + +#define CAM_LRME_MAX_REG_PAIR_NUM 60 + +/** + * enum cam_lrme_irq_set + * + * @CAM_LRME_IRQ_ENABLE : Enable irqs + * @CAM_LRME_IRQ_DISABLE : Disable irqs + */ +enum cam_lrme_irq_set { + CAM_LRME_IRQ_ENABLE, + CAM_LRME_IRQ_DISABLE, +}; + +/** + * struct cam_lrme_cdm_info : information used to submit cdm command + * + * @cdm_handle : CDM handle for this device + * @cdm_ops : CDM ops + * @cdm_cmd : CDM command pointer + */ +struct cam_lrme_cdm_info { + uint32_t cdm_handle; + struct cam_cdm_utils_ops *cdm_ops; + struct cam_cdm_bl_request *cdm_cmd; +}; + +/** + * struct cam_lrme_hw_work_data : Work data for HW work queue + * + * @top_irq_status : Top registers irq status + * @fe_irq_status : FE engine irq status + * @we_irq_status : WE engine irq status + */ +struct cam_lrme_hw_work_data { + uint32_t top_irq_status; + uint32_t fe_irq_status; + uint32_t we_irq_status[2]; +}; + +/** + * enum cam_lrme_core_state : LRME core states + * + * @CAM_LRME_CORE_STATE_UNINIT : LRME is in uninit state + * @CAM_LRME_CORE_STATE_INIT : LRME is in init state after probe + * @ CAM_LRME_CORE_STATE_IDLE : LRME is in idle state. Hardware is in + * this state when no frame is processing + * or waiting for this core. + * @CAM_LRME_CORE_STATE_REQ_PENDING : LRME is in pending state. One frame is + * waiting for processing + * @CAM_LRME_CORE_STATE_PROCESSING : LRME is in processing state. HW manager + * can submit one more frame to HW + * @CAM_LRME_CORE_STATE_REQ_PROC_PEND : Indicate two frames are inside HW. + * @CAM_LRME_CORE_STATE_RECOVERY : Indicate core is in the process of reset + * @CAM_LRME_CORE_STATE_MAX : upper limit of states + */ +enum cam_lrme_core_state { + CAM_LRME_CORE_STATE_UNINIT, + CAM_LRME_CORE_STATE_INIT, + CAM_LRME_CORE_STATE_IDLE, + CAM_LRME_CORE_STATE_REQ_PENDING, + CAM_LRME_CORE_STATE_PROCESSING, + CAM_LRME_CORE_STATE_REQ_PROC_PEND, + CAM_LRME_CORE_STATE_RECOVERY, + CAM_LRME_CORE_STATE_MAX, +}; + +/** + * struct cam_lrme_core : LRME HW core information + * + * @hw_info : Pointer to base HW information structure + * @device_iommu : Device iommu handle + * @cdm_iommu : CDM iommu handle + * @hw_caps : Hardware capabilities + * @state : Hardware state + * @reset_complete : Reset completion + * @work : Hardware workqueue to handle irq events + * @work_data : Work data used by hardware workqueue + * @hw_mgr_cb : Hw manager callback + * @req_proc : Pointer to the processing frame request + * @req_submit : Pointer to the frame request waiting for processing + * @hw_cdm_info : CDM information used by this device + * @hw_idx : Hardware index + */ +struct cam_lrme_core { + struct cam_lrme_hw_info *hw_info; + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_lrme_dev_cap hw_caps; + enum cam_lrme_core_state state; + struct completion reset_complete; + struct cam_req_mgr_core_workq *work; + struct cam_lrme_hw_work_data work_data[CAM_LRME_HW_WORKQ_NUM_TASK]; + struct cam_lrme_hw_cmd_set_cb hw_mgr_cb; + struct cam_lrme_frame_request *req_proc; + struct cam_lrme_frame_request *req_submit; + struct cam_lrme_cdm_info *hw_cdm_info; + uint32_t hw_idx; + bool dump_flag; +}; + +/** + * struct cam_lrme_bus_rd_reg_common : Offsets of FE common registers + * + * @hw_version : Offset of hw_version register + * @hw_capability : Offset of hw_capability register + * @sw_reset : Offset of sw_reset register + * @cgc_override : Offset of cgc_override register + * @irq_mask : Offset of irq_mask register + * @irq_clear : Offset of irq_clear register + * @irq_cmd : Offset of irq_cmd register + * @irq_status : Offset of irq_status register + * @cmd : Offset of cmd register + * @irq_set : Offset of irq_set register + * @misr_reset : Offset of misr_reset register + * @security_cfg : Offset of security_cfg register + * @pwr_iso_cfg : Offset of pwr_iso_cfg register + * @pwr_iso_seed : Offset of pwr_iso_seed register + * @test_bus_ctrl : Offset of test_bus_ctrl register + * @spare : Offset of spare register + */ +struct cam_lrme_bus_rd_reg_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_override; + uint32_t irq_mask; + uint32_t irq_clear; + uint32_t irq_cmd; + uint32_t irq_status; + uint32_t cmd; + uint32_t irq_set; + uint32_t misr_reset; + uint32_t security_cfg; + uint32_t pwr_iso_cfg; + uint32_t pwr_iso_seed; + uint32_t test_bus_ctrl; + uint32_t spare; +}; + +/** + * struct cam_lrme_bus_wr_reg_common : Offset of WE common registers + * @hw_version : Offset of hw_version register + * @hw_capability : Offset of hw_capability register + * @sw_reset : Offset of sw_reset register + * @cgc_override : Offset of cgc_override register + * @misr_reset : Offset of misr_reset register + * @pwr_iso_cfg : Offset of pwr_iso_cfg register + * @test_bus_ctrl : Offset of test_bus_ctrl register + * @composite_mask_0 : Offset of composite_mask_0 register + * @irq_mask_0 : Offset of irq_mask_0 register + * @irq_mask_1 : Offset of irq_mask_1 register + * @irq_clear_0 : Offset of irq_clear_0 register + * @irq_clear_1 : Offset of irq_clear_1 register + * @irq_status_0 : Offset of irq_status_0 register + * @irq_status_1 : Offset of irq_status_1 register + * @irq_cmd : Offset of irq_cmd register + * @irq_set_0 : Offset of irq_set_0 register + * @irq_set_1 : Offset of irq_set_1 register + * @addr_fifo_status : Offset of addr_fifo_status register + * @frame_header_cfg0 : Offset of frame_header_cfg0 register + * @frame_header_cfg1 : Offset of frame_header_cfg1 register + * @spare : Offset of spare register + */ +struct cam_lrme_bus_wr_reg_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_override; + uint32_t misr_reset; + uint32_t pwr_iso_cfg; + uint32_t test_bus_ctrl; + uint32_t composite_mask_0; + uint32_t irq_mask_0; + uint32_t irq_mask_1; + uint32_t irq_clear_0; + uint32_t irq_clear_1; + uint32_t irq_status_0; + uint32_t irq_status_1; + uint32_t irq_cmd; + uint32_t irq_set_0; + uint32_t irq_set_1; + uint32_t addr_fifo_status; + uint32_t frame_header_cfg0; + uint32_t frame_header_cfg1; + uint32_t spare; +}; + +/** + * struct cam_lrme_bus_rd_bus_client : Offset of FE registers + * + * @core_cfg : Offset of core_cfg register + * @ccif_meta_data : Offset of ccif_meta_data register + * @addr_image : Offset of addr_image register + * @rd_buffer_size : Offset of rd_buffer_size register + * @rd_stride : Offset of rd_stride register + * @unpack_cfg_0 : Offset of unpack_cfg_0 register + * @latency_buff_allocation : Offset of latency_buff_allocation register + * @burst_limit_cfg : Offset of burst_limit_cfg register + * @misr_cfg_0 : Offset of misr_cfg_0 register + * @misr_cfg_1 : Offset of misr_cfg_1 register + * @misr_rd_val : Offset of misr_rd_val register + * @debug_status_cfg : Offset of debug_status_cfg register + * @debug_status_0 : Offset of debug_status_0 register + * @debug_status_1 : Offset of debug_status_1 register + */ +struct cam_lrme_bus_rd_bus_client { + uint32_t core_cfg; + uint32_t ccif_meta_data; + uint32_t addr_image; + uint32_t rd_buffer_size; + uint32_t rd_stride; + uint32_t unpack_cfg_0; + uint32_t latency_buff_allocation; + uint32_t burst_limit_cfg; + uint32_t misr_cfg_0; + uint32_t misr_cfg_1; + uint32_t misr_rd_val; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; +}; + +/** + * struct cam_lrme_bus_wr_bus_client : Offset of WE registers + * + * @status_0 : Offset of status_0 register + * @status_1 : Offset of status_1 register + * @cfg : Offset of cfg register + * @addr_frame_header : Offset of addr_frame_header register + * @frame_header_cfg : Offset of frame_header_cfg register + * @addr_image : Offset of addr_image register + * @addr_image_offset : Offset of addr_image_offset register + * @buffer_width_cfg : Offset of buffer_width_cfg register + * @buffer_height_cfg : Offset of buffer_height_cfg register + * @packer_cfg : Offset of packer_cfg register + * @wr_stride : Offset of wr_stride register + * @irq_subsample_cfg_period : Offset of irq_subsample_cfg_period register + * @irq_subsample_cfg_pattern : Offset of irq_subsample_cfg_pattern register + * @burst_limit_cfg : Offset of burst_limit_cfg register + * @misr_cfg : Offset of misr_cfg register + * @misr_rd_word_sel : Offset of misr_rd_word_sel register + * @misr_val : Offset of misr_val register + * @debug_status_cfg : Offset of debug_status_cfg register + * @debug_status_0 : Offset of debug_status_0 register + * @debug_status_1 : Offset of debug_status_1 register + */ +struct cam_lrme_bus_wr_bus_client { + uint32_t status_0; + uint32_t status_1; + uint32_t cfg; + uint32_t addr_frame_header; + uint32_t frame_header_cfg; + uint32_t addr_image; + uint32_t addr_image_offset; + uint32_t buffer_width_cfg; + uint32_t buffer_height_cfg; + uint32_t packer_cfg; + uint32_t wr_stride; + uint32_t irq_subsample_cfg_period; + uint32_t irq_subsample_cfg_pattern; + uint32_t burst_limit_cfg; + uint32_t misr_cfg; + uint32_t misr_rd_word_sel; + uint32_t misr_val; + uint32_t debug_status_cfg; + uint32_t debug_status_0; + uint32_t debug_status_1; +}; + +/** + * struct cam_lrme_bus_rd_hw_info : FE registers information + * + * @common_reg : FE common register + * @bus_client_reg : List of FE bus registers information + */ +struct cam_lrme_bus_rd_hw_info { + struct cam_lrme_bus_rd_reg_common common_reg; + struct cam_lrme_bus_rd_bus_client + bus_client_reg[CAM_LRME_BUS_RD_MAX_CLIENTS]; +}; + +/** + * struct cam_lrme_bus_wr_hw_info : WE engine registers information + * + * @common_reg : WE common register + * @bus_client_reg : List of WE bus registers information + */ +struct cam_lrme_bus_wr_hw_info { + struct cam_lrme_bus_wr_reg_common common_reg; + struct cam_lrme_bus_wr_bus_client + bus_client_reg[CAM_LRME_BUS_WR_MAX_CLIENTS]; +}; + +/** + * struct cam_lrme_clc_reg : Offset of clc registers + * + * @clc_hw_version : Offset of clc_hw_version register + * @clc_hw_status : Offset of clc_hw_status register + * @clc_hw_status_dbg : Offset of clc_hw_status_dbg register + * @clc_module_cfg : Offset of clc_module_cfg register + * @clc_moduleformat : Offset of clc_moduleformat register + * @clc_rangestep : Offset of clc_rangestep register + * @clc_offset : Offset of clc_offset register + * @clc_maxallowedsad : Offset of clc_maxallowedsad register + * @clc_minallowedtarmad : Offset of clc_minallowedtarmad register + * @clc_meaningfulsaddiff : Offset of clc_meaningfulsaddiff register + * @clc_minsaddiffdenom : Offset of clc_minsaddiffdenom register + * @clc_robustnessmeasuredistmap_0 : Offset of measuredistmap_0 register + * @clc_robustnessmeasuredistmap_1 : Offset of measuredistmap_1 register + * @clc_robustnessmeasuredistmap_2 : Offset of measuredistmap_2 register + * @clc_robustnessmeasuredistmap_3 : Offset of measuredistmap_3 register + * @clc_robustnessmeasuredistmap_4 : Offset of measuredistmap_4 register + * @clc_robustnessmeasuredistmap_5 : Offset of measuredistmap_5 register + * @clc_robustnessmeasuredistmap_6 : Offset of measuredistmap_6 register + * @clc_robustnessmeasuredistmap_7 : Offset of measuredistmap_7 register + * @clc_ds_crop_horizontal : Offset of clc_ds_crop_horizontal register + * @clc_ds_crop_vertical : Offset of clc_ds_crop_vertical register + * @clc_tar_pd_unpacker : Offset of clc_tar_pd_unpacker register + * @clc_ref_pd_unpacker : Offset of clc_ref_pd_unpacker register + * @clc_sw_override : Offset of clc_sw_override register + * @clc_tar_height : Offset of clc_tar_height register + * @clc_test_bus_ctrl : Offset of clc_test_bus_ctrl register + * @clc_spare : Offset of clc_spare register + */ +struct cam_lrme_clc_reg { + uint32_t clc_hw_version; + uint32_t clc_hw_status; + uint32_t clc_hw_status_dbg; + uint32_t clc_module_cfg; + uint32_t clc_moduleformat; + uint32_t clc_rangestep; + uint32_t clc_offset; + uint32_t clc_maxallowedsad; + uint32_t clc_minallowedtarmad; + uint32_t clc_meaningfulsaddiff; + uint32_t clc_minsaddiffdenom; + uint32_t clc_robustnessmeasuredistmap_0; + uint32_t clc_robustnessmeasuredistmap_1; + uint32_t clc_robustnessmeasuredistmap_2; + uint32_t clc_robustnessmeasuredistmap_3; + uint32_t clc_robustnessmeasuredistmap_4; + uint32_t clc_robustnessmeasuredistmap_5; + uint32_t clc_robustnessmeasuredistmap_6; + uint32_t clc_robustnessmeasuredistmap_7; + uint32_t clc_ds_crop_horizontal; + uint32_t clc_ds_crop_vertical; + uint32_t clc_tar_pd_unpacker; + uint32_t clc_ref_pd_unpacker; + uint32_t clc_sw_override; + uint32_t clc_tar_height; + uint32_t clc_ref_height; + uint32_t clc_test_bus_ctrl; + uint32_t clc_spare; +}; + +/** + * struct cam_lrme_titan_reg : Offset of LRME top registers + * + * @top_hw_version : Offset of top_hw_version register + * @top_titan_version : Offset of top_titan_version register + * @top_rst_cmd : Offset of top_rst_cmd register + * @top_core_clk_cfg : Offset of top_core_clk_cfg register + * @top_irq_status : Offset of top_irq_status register + * @top_irq_mask : Offset of top_irq_mask register + * @top_irq_clear : Offset of top_irq_clear register + * @top_irq_set : Offset of top_irq_set register + * @top_irq_cmd : Offset of top_irq_cmd register + * @top_violation_status : Offset of top_violation_status register + * @top_spare : Offset of top_spare register + */ +struct cam_lrme_titan_reg { + uint32_t top_hw_version; + uint32_t top_titan_version; + uint32_t top_rst_cmd; + uint32_t top_core_clk_cfg; + uint32_t top_irq_status; + uint32_t top_irq_mask; + uint32_t top_irq_clear; + uint32_t top_irq_set; + uint32_t top_irq_cmd; + uint32_t top_violation_status; + uint32_t top_spare; +}; + +/** + * struct cam_lrme_hw_info : LRME registers information + * + * @clc_reg : LRME CLC registers + * @bus_rd_reg : LRME FE registers + * @bus_wr_reg : LRME WE registers + * @titan_reg : LRME top reisters + */ +struct cam_lrme_hw_info { + struct cam_lrme_clc_reg clc_reg; + struct cam_lrme_bus_rd_hw_info bus_rd_reg; + struct cam_lrme_bus_wr_hw_info bus_wr_reg; + struct cam_lrme_titan_reg titan_reg; +}; + +int cam_lrme_hw_process_irq(void *priv, void *data); +int cam_lrme_hw_submit_req(void *hw_priv, void *hw_submit_args, + uint32_t arg_size); +int cam_lrme_hw_reset(void *hw_priv, void *reset_core_args, uint32_t arg_size); +int cam_lrme_hw_stop(void *hw_priv, void *stop_args, uint32_t arg_size); +int cam_lrme_hw_get_caps(void *hw_priv, void *get_hw_cap_args, + uint32_t arg_size); +irqreturn_t cam_lrme_hw_irq(int irq_num, void *data); +int cam_lrme_hw_process_cmd(void *hw_priv, uint32_t cmd_type, + void *cmd_args, uint32_t arg_size); +int cam_lrme_hw_util_get_caps(struct cam_hw_info *lrme_hw, + struct cam_lrme_dev_cap *hw_caps); +int cam_lrme_hw_start(void *hw_priv, void *hw_init_args, uint32_t arg_size); +int cam_lrme_hw_flush(void *hw_priv, void *hw_flush_args, uint32_t arg_size); +void cam_lrme_set_irq(struct cam_hw_info *lrme_hw, enum cam_lrme_irq_set set); + +#endif /* _CAM_LRME_HW_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..4e2609648b300d1486774539fd9fd8b0cff330ac --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_req_mgr.h> + +#include "cam_subdev.h" +#include "cam_lrme_hw_intf.h" +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_lrme_hw_reg.h" +#include "cam_req_mgr_workq.h" +#include "cam_lrme_hw_mgr.h" +#include "cam_mem_mgr_api.h" +#include "cam_smmu_api.h" + +static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core, + struct cam_hw_info *lrme_hw) +{ + int rc, i; + struct cam_cdm_bl_request *cdm_cmd; + struct cam_cdm_acquire_data cdm_acquire; + struct cam_lrme_cdm_info *hw_cdm_info; + + hw_cdm_info = kzalloc(sizeof(struct cam_lrme_cdm_info), + GFP_KERNEL); + if (!hw_cdm_info) { + CAM_ERR(CAM_LRME, "No memory for hw_cdm_info"); + return -ENOMEM; + } + + cdm_cmd = kzalloc((sizeof(struct cam_cdm_bl_request) + + ((CAM_LRME_MAX_HW_ENTRIES - 1) * + sizeof(struct cam_cdm_bl_cmd))), GFP_KERNEL); + if (!cdm_cmd) { + CAM_ERR(CAM_LRME, "No memory for cdm_cmd"); + kfree(hw_cdm_info); + return -ENOMEM; + } + + memset(&cdm_acquire, 0, sizeof(cdm_acquire)); + strlcpy(cdm_acquire.identifier, "lrmecdm", sizeof("lrmecdm")); + cdm_acquire.cell_index = lrme_hw->soc_info.index; + cdm_acquire.handle = 0; + cdm_acquire.userdata = hw_cdm_info; + cdm_acquire.cam_cdm_callback = NULL; + cdm_acquire.id = CAM_CDM_VIRTUAL; + cdm_acquire.base_array_cnt = lrme_hw->soc_info.num_reg_map; + for (i = 0; i < lrme_hw->soc_info.num_reg_map; i++) + cdm_acquire.base_array[i] = &lrme_hw->soc_info.reg_map[i]; + + rc = cam_cdm_acquire(&cdm_acquire); + if (rc) { + CAM_ERR(CAM_LRME, "Can't acquire cdm"); + goto error; + } + + hw_cdm_info->cdm_cmd = cdm_cmd; + hw_cdm_info->cdm_ops = cdm_acquire.ops; + hw_cdm_info->cdm_handle = cdm_acquire.handle; + + lrme_core->hw_cdm_info = hw_cdm_info; + CAM_DBG(CAM_LRME, "cdm acquire done"); + + return 0; +error: + kfree(cdm_cmd); + kfree(hw_cdm_info); + return rc; +} + +static int cam_lrme_hw_dev_probe(struct platform_device *pdev) +{ + struct cam_hw_info *lrme_hw; + struct cam_hw_intf lrme_hw_intf; + struct cam_lrme_core *lrme_core; + const struct of_device_id *match_dev = NULL; + struct cam_lrme_hw_info *hw_info; + int rc, i; + + lrme_hw = kzalloc(sizeof(struct cam_hw_info), GFP_KERNEL); + if (!lrme_hw) { + CAM_ERR(CAM_LRME, "No memory to create lrme_hw"); + return -ENOMEM; + } + + lrme_core = kzalloc(sizeof(struct cam_lrme_core), GFP_KERNEL); + if (!lrme_core) { + CAM_ERR(CAM_LRME, "No memory to create lrme_core"); + kfree(lrme_hw); + return -ENOMEM; + } + + lrme_hw->core_info = lrme_core; + lrme_hw->hw_state = CAM_HW_STATE_POWER_DOWN; + lrme_hw->soc_info.pdev = pdev; + lrme_hw->soc_info.dev = &pdev->dev; + lrme_hw->soc_info.dev_name = pdev->name; + lrme_hw->open_count = 0; + lrme_core->state = CAM_LRME_CORE_STATE_INIT; + + mutex_init(&lrme_hw->hw_mutex); + spin_lock_init(&lrme_hw->hw_lock); + init_completion(&lrme_hw->hw_complete); + init_completion(&lrme_core->reset_complete); + + rc = cam_req_mgr_workq_create("cam_lrme_hw_worker", + CAM_LRME_HW_WORKQ_NUM_TASK, + &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc); + goto free_memory; + } + + for (i = 0; i < CAM_LRME_HW_WORKQ_NUM_TASK; i++) + lrme_core->work->task.pool[i].payload = + &lrme_core->work_data[i]; + + match_dev = of_match_device(pdev->dev.driver->of_match_table, + &pdev->dev); + if (!match_dev || !match_dev->data) { + CAM_ERR(CAM_LRME, "No Of_match data, %pK", match_dev); + rc = -EINVAL; + goto destroy_workqueue; + } + hw_info = (struct cam_lrme_hw_info *)match_dev->data; + lrme_core->hw_info = hw_info; + + rc = cam_lrme_soc_init_resources(&lrme_hw->soc_info, + cam_lrme_hw_irq, lrme_hw); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to init soc, rc=%d", rc); + goto destroy_workqueue; + } + + rc = cam_lrme_hw_dev_util_cdm_acquire(lrme_core, lrme_hw); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to acquire cdm"); + goto deinit_platform_res; + } + + rc = cam_smmu_get_handle("lrme", &lrme_core->device_iommu.non_secure); + if (rc) { + CAM_ERR(CAM_LRME, "Get iommu handle failed"); + goto release_cdm; + } + + rc = cam_lrme_hw_start(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); + goto detach_smmu; + } + + rc = cam_lrme_hw_util_get_caps(lrme_hw, &lrme_core->hw_caps); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to get hw caps, rc=%d", rc); + if (cam_lrme_hw_stop(lrme_hw, NULL, 0)) + CAM_ERR(CAM_LRME, "Failed in hw deinit"); + goto detach_smmu; + } + + rc = cam_lrme_hw_stop(lrme_hw, NULL, 0); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to deinit hw, rc=%d", rc); + goto detach_smmu; + } + + lrme_core->hw_idx = lrme_hw->soc_info.index; + lrme_hw_intf.hw_priv = lrme_hw; + lrme_hw_intf.hw_idx = lrme_hw->soc_info.index; + lrme_hw_intf.hw_ops.get_hw_caps = cam_lrme_hw_get_caps; + lrme_hw_intf.hw_ops.init = NULL; + lrme_hw_intf.hw_ops.deinit = NULL; + lrme_hw_intf.hw_ops.reset = cam_lrme_hw_reset; + lrme_hw_intf.hw_ops.reserve = NULL; + lrme_hw_intf.hw_ops.release = NULL; + lrme_hw_intf.hw_ops.start = cam_lrme_hw_start; + lrme_hw_intf.hw_ops.stop = cam_lrme_hw_stop; + lrme_hw_intf.hw_ops.read = NULL; + lrme_hw_intf.hw_ops.write = NULL; + lrme_hw_intf.hw_ops.process_cmd = cam_lrme_hw_process_cmd; + lrme_hw_intf.hw_ops.flush = cam_lrme_hw_flush; + lrme_hw_intf.hw_type = CAM_HW_LRME; + + rc = cam_cdm_get_iommu_handle("lrmecdm", &lrme_core->cdm_iommu); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to acquire the CDM iommu handles"); + goto detach_smmu; + } + + rc = cam_lrme_mgr_register_device(&lrme_hw_intf, + &lrme_core->device_iommu, + &lrme_core->cdm_iommu); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to register device"); + goto detach_smmu; + } + + platform_set_drvdata(pdev, lrme_hw); + CAM_DBG(CAM_LRME, "LRME-%d probe successful", lrme_hw_intf.hw_idx); + + return rc; + +detach_smmu: + cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure); +release_cdm: + cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle); + kfree(lrme_core->hw_cdm_info->cdm_cmd); + kfree(lrme_core->hw_cdm_info); +deinit_platform_res: + if (cam_lrme_soc_deinit_resources(&lrme_hw->soc_info)) + CAM_ERR(CAM_LRME, "Failed in soc deinit"); + mutex_destroy(&lrme_hw->hw_mutex); +destroy_workqueue: + cam_req_mgr_workq_destroy(&lrme_core->work); +free_memory: + mutex_destroy(&lrme_hw->hw_mutex); + kfree(lrme_hw); + kfree(lrme_core); + + return rc; +} + +static int cam_lrme_hw_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + struct cam_hw_info *lrme_hw; + struct cam_lrme_core *lrme_core; + + lrme_hw = platform_get_drvdata(pdev); + if (!lrme_hw) { + CAM_ERR(CAM_LRME, "Invalid lrme_hw from fd_hw_intf"); + return -ENODEV; + } + + lrme_core = (struct cam_lrme_core *)lrme_hw->core_info; + if (!lrme_core) { + CAM_ERR(CAM_LRME, "Invalid lrme_core from fd_hw"); + rc = -EINVAL; + goto deinit_platform_res; + } + + cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure); + cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle); + cam_lrme_mgr_deregister_device(lrme_core->hw_idx); + + kfree(lrme_core->hw_cdm_info->cdm_cmd); + kfree(lrme_core->hw_cdm_info); + kfree(lrme_core); + +deinit_platform_res: + rc = cam_lrme_soc_deinit_resources(&lrme_hw->soc_info); + if (rc) + CAM_ERR(CAM_LRME, "Error in LRME soc deinit, rc=%d", rc); + + mutex_destroy(&lrme_hw->hw_mutex); + kfree(lrme_hw); + + return rc; +} + +static const struct of_device_id cam_lrme_hw_dt_match[] = { + { + .compatible = "qcom,lrme", + .data = &cam_lrme10_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_lrme_hw_dt_match); + +static struct platform_driver cam_lrme_hw_driver = { + .probe = cam_lrme_hw_dev_probe, + .remove = cam_lrme_hw_dev_remove, + .driver = { + .name = "cam_lrme_hw", + .owner = THIS_MODULE, + .of_match_table = cam_lrme_hw_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_lrme_hw_init_module(void) +{ + return platform_driver_register(&cam_lrme_hw_driver); +} + +static void __exit cam_lrme_hw_exit_module(void) +{ + platform_driver_unregister(&cam_lrme_hw_driver); +} + +module_init(cam_lrme_hw_init_module); +module_exit(cam_lrme_hw_exit_module); +MODULE_DESCRIPTION("CAM LRME HW driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..b74d537004192e8eda870b889a28533b05e67858 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_INTF_H_ +#define _CAM_LRME_HW_INTF_H_ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <media/cam_cpas.h> +#include <media/cam_req_mgr.h> +#include <media/cam_lrme.h> + +#include "cam_io_util.h" +#include "cam_soc_util.h" +#include "cam_hw.h" +#include "cam_hw_intf.h" +#include "cam_subdev.h" +#include "cam_cpas_api.h" +#include "cam_hw_mgr_intf.h" +#include "cam_debug_util.h" + + +#define CAM_LRME_MAX_IO_BUFFER 2 +#define CAM_LRME_MAX_HW_ENTRIES 5 + +#define CAM_LRME_BASE_IDX 0 + +/** + * enum cam_lrme_hw_type : Enum for LRME HW type + * + * @CAM_HW_LRME : LRME HW type + */ +enum cam_lrme_hw_type { + CAM_HW_LRME, +}; + +/** + * enum cam_lrme_cb_type : HW manager call back type + * + * @CAM_LRME_CB_BUF_DONE : Indicate buf done has been generated + * @CAM_LRME_CB_COMP_REG_UPDATE : Indicate receiving WE comp reg update + * @CAM_LRME_CB_PUT_FRAME : Request HW manager to put back the frame + * @CAM_LRME_CB_ERROR : Indicate error irq has been generated + */ +enum cam_lrme_cb_type { + CAM_LRME_CB_BUF_DONE = 1, + CAM_LRME_CB_COMP_REG_UPDATE = 1 << 1, + CAM_LRME_CB_PUT_FRAME = 1 << 2, + CAM_LRME_CB_ERROR = 1 << 3, +}; + +/** + * enum cam_lrme_hw_cmd_type : HW CMD type + * + * @CAM_LRME_HW_CMD_prepare_hw_update : Prepare HW update + * @CAM_LRME_HW_CMD_REGISTER_CB : register HW manager callback + * @CAM_LRME_HW_CMD_SUBMIT : Submit frame to HW + * @CAM_LRME_HW_CMD_DUMP_REGISTER : dump register values + */ +enum cam_lrme_hw_cmd_type { + CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, + CAM_LRME_HW_CMD_REGISTER_CB, + CAM_LRME_HW_CMD_SUBMIT, + CAM_LRME_HW_CMD_DUMP_REGISTER, +}; + +/** + * enum cam_lrme_hw_reset_type : Type of reset + * + * @CAM_LRME_HW_RESET_TYPE_HW_RESET : HW reset + * @CAM_LRME_HW_RESET_TYPE_SW_RESET : SW reset + */ +enum cam_lrme_hw_reset_type { + CAM_LRME_HW_RESET_TYPE_HW_RESET, + CAM_LRME_HW_RESET_TYPE_SW_RESET, +}; + +/** + *struct cam_lrme_frame_request : LRME frame request + * + * @frame_list : List head + * @req_id : Request ID + * @ctxt_to_hw_map : Information about context id, priority and device id + * @hw_device : Pointer to HW device + * @hw_update_entries : List of hw_update_entries + * @num_hw_update_entries : number of hw_update_entries + */ +struct cam_lrme_frame_request { + struct list_head frame_list; + uint64_t req_id; + void *ctxt_to_hw_map; + struct cam_lrme_device *hw_device; + struct cam_hw_update_entry hw_update_entries[CAM_LRME_MAX_HW_ENTRIES]; + uint32_t num_hw_update_entries; +}; + +/** + * struct cam_lrme_hw_io_buffer : IO buffer information + * + * @valid : Indicate whether this IO config is valid + * @io_cfg : Pointer to IO configuration + * @num_buf : Number of buffers + * @num_plane : Number of planes + * @io_addr : List of IO address + */ +struct cam_lrme_hw_io_buffer { + bool valid; + struct cam_buf_io_cfg *io_cfg; + uint32_t num_buf; + uint32_t num_plane; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; +}; + +/** + * struct cam_lrme_hw_cmd_config_args : Args for prepare HW update + * + * @hw_device : Pointer to HW device + * @input_buf : List of input buffers + * @output_buf : List of output buffers + * @cmd_buf_addr : Pointer to available KMD buffer + * @size : Available KMD buffer size + * @config_buf_size : Size used to prepare update + */ +struct cam_lrme_hw_cmd_config_args { + struct cam_lrme_device *hw_device; + struct cam_lrme_hw_io_buffer input_buf[CAM_LRME_MAX_IO_BUFFER]; + struct cam_lrme_hw_io_buffer output_buf[CAM_LRME_MAX_IO_BUFFER]; + uint32_t *cmd_buf_addr; + uint32_t size; + uint32_t config_buf_size; +}; + +/** + * struct cam_lrme_hw_flush_args : Args for flush HW + * + * @ctxt_to_hw_map : Identity of context + * @req_to_flush : Pointer to the frame need to flush in + * case of single frame flush + * @flush_type : Flush type + */ +struct cam_lrme_hw_flush_args { + void *ctxt_to_hw_map; + struct cam_lrme_frame_request *req_to_flush; + uint32_t flush_type; +}; + +/** + * struct cam_lrme_hw_reset_args : Args for reset HW + * + * @reset_type : Enum cam_lrme_hw_reset_type + */ +struct cam_lrme_hw_reset_args { + uint32_t reset_type; +}; + +/** + * struct cam_lrme_hw_cb_args : HW manager callback args + * + * @cb_type : Callback event type + * @frame_req : Pointer to the frame associated with the cb + */ +struct cam_lrme_hw_cb_args { + uint32_t cb_type; + struct cam_lrme_frame_request *frame_req; +}; + +/** + * struct cam_lrme_hw_cmd_set_cb : Args for set callback function + * + * @cam_lrme_hw_mgr_cb : Callback function pointer + * @data : Data sent along with callback function + */ +struct cam_lrme_hw_cmd_set_cb { + int (*cam_lrme_hw_mgr_cb)(void *data, + struct cam_lrme_hw_cb_args *args); + void *data; +}; + +/** + * struct cam_lrme_hw_submit_args : Args for submit request + * + * @hw_update_entries : List of hw update entries used to program registers + * @num_hw_update_entries : Number of hw update entries + * @frame_req : Pointer to the frame request + */ +struct cam_lrme_hw_submit_args { + struct cam_hw_update_entry *hw_update_entries; + uint32_t num_hw_update_entries; + struct cam_lrme_frame_request *frame_req; +}; + +#endif /* _CAM_LRME_HW_INTF_H_ */ diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..17eb25b0facfa71af1df429f11a2066d96d45277 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_REG_H_ +#define _CAM_LRME_HW_REG_H_ + +#include "cam_lrme_hw_core.h" + +static struct cam_lrme_hw_info cam_lrme10_hw_info = { + .clc_reg = { + .clc_hw_version = 0x00000000, + .clc_hw_status = 0x00000004, + .clc_hw_status_dbg = 0x00000008, + .clc_module_cfg = 0x00000060, + .clc_moduleformat = 0x000000A8, + .clc_rangestep = 0x00000068, + .clc_offset = 0x0000006C, + .clc_maxallowedsad = 0x00000070, + .clc_minallowedtarmad = 0x00000074, + .clc_meaningfulsaddiff = 0x00000078, + .clc_minsaddiffdenom = 0x0000007C, + .clc_robustnessmeasuredistmap_0 = 0x00000080, + .clc_robustnessmeasuredistmap_1 = 0x00000084, + .clc_robustnessmeasuredistmap_2 = 0x00000088, + .clc_robustnessmeasuredistmap_3 = 0x0000008C, + .clc_robustnessmeasuredistmap_4 = 0x00000090, + .clc_robustnessmeasuredistmap_5 = 0x00000094, + .clc_robustnessmeasuredistmap_6 = 0x00000098, + .clc_robustnessmeasuredistmap_7 = 0x0000009C, + .clc_ds_crop_horizontal = 0x000000A0, + .clc_ds_crop_vertical = 0x000000A4, + .clc_tar_pd_unpacker = 0x000000AC, + .clc_ref_pd_unpacker = 0x000000B0, + .clc_sw_override = 0x000000B4, + .clc_tar_height = 0x000000B8, + .clc_ref_height = 0x000000BC, + .clc_test_bus_ctrl = 0x000001F8, + .clc_spare = 0x000001FC, + }, + .bus_rd_reg = { + .common_reg = { + .hw_version = 0x00000200, + .hw_capability = 0x00000204, + .sw_reset = 0x00000208, + .cgc_override = 0x0000020C, + .irq_mask = 0x00000210, + .irq_clear = 0x00000214, + .irq_cmd = 0x00000218, + .irq_status = 0x0000021C, + .cmd = 0x00000220, + .irq_set = 0x00000224, + .misr_reset = 0x0000022C, + .security_cfg = 0x00000230, + .pwr_iso_cfg = 0x00000234, + .pwr_iso_seed = 0x00000238, + .test_bus_ctrl = 0x00000248, + .spare = 0x0000024C, + }, + .bus_client_reg = { + /* bus client 0 */ + { + .core_cfg = 0x00000250, + .ccif_meta_data = 0x00000254, + .addr_image = 0x00000258, + .rd_buffer_size = 0x0000025C, + .rd_stride = 0x00000260, + .unpack_cfg_0 = 0x00000264, + .latency_buff_allocation = 0x00000278, + .burst_limit_cfg = 0x00000280, + .misr_cfg_0 = 0x00000284, + .misr_cfg_1 = 0x00000288, + .misr_rd_val = 0x0000028C, + .debug_status_cfg = 0x00000290, + .debug_status_0 = 0x00000294, + .debug_status_1 = 0x00000298, + }, + /* bus client 1 */ + { + .core_cfg = 0x000002F0, + .ccif_meta_data = 0x000002F4, + .addr_image = 0x000002F8, + .rd_buffer_size = 0x000002FC, + .rd_stride = 0x00000300, + .unpack_cfg_0 = 0x00000304, + .latency_buff_allocation = 0x00000318, + .burst_limit_cfg = 0x00000320, + .misr_cfg_0 = 0x00000324, + .misr_cfg_1 = 0x00000328, + .misr_rd_val = 0x0000032C, + .debug_status_cfg = 0x00000330, + .debug_status_0 = 0x00000334, + .debug_status_1 = 0x00000338, + }, + }, + }, + .bus_wr_reg = { + .common_reg = { + .hw_version = 0x00000500, + .hw_capability = 0x00000504, + .sw_reset = 0x00000508, + .cgc_override = 0x0000050C, + .misr_reset = 0x000005C8, + .pwr_iso_cfg = 0x000005CC, + .test_bus_ctrl = 0x0000061C, + .composite_mask_0 = 0x00000510, + .irq_mask_0 = 0x00000544, + .irq_mask_1 = 0x00000548, + .irq_clear_0 = 0x00000550, + .irq_clear_1 = 0x00000554, + .irq_status_0 = 0x0000055C, + .irq_status_1 = 0x00000560, + .irq_cmd = 0x00000568, + .irq_set_0 = 0x000005BC, + .irq_set_1 = 0x000005C0, + .addr_fifo_status = 0x000005A8, + .frame_header_cfg0 = 0x000005AC, + .frame_header_cfg1 = 0x000005B0, + .spare = 0x00000620, + }, + .bus_client_reg = { + /* bus client 0 */ + { + .status_0 = 0x00000700, + .status_1 = 0x00000704, + .cfg = 0x00000708, + .addr_frame_header = 0x0000070C, + .frame_header_cfg = 0x00000710, + .addr_image = 0x00000714, + .addr_image_offset = 0x00000718, + .buffer_width_cfg = 0x0000071C, + .buffer_height_cfg = 0x00000720, + .packer_cfg = 0x00000724, + .wr_stride = 0x00000728, + .irq_subsample_cfg_period = 0x00000748, + .irq_subsample_cfg_pattern = 0x0000074C, + .burst_limit_cfg = 0x0000075C, + .misr_cfg = 0x00000760, + .misr_rd_word_sel = 0x00000764, + .misr_val = 0x00000768, + .debug_status_cfg = 0x0000076C, + .debug_status_0 = 0x00000770, + .debug_status_1 = 0x00000774, + }, + /* bus client 1 */ + { + .status_0 = 0x00000800, + .status_1 = 0x00000804, + .cfg = 0x00000808, + .addr_frame_header = 0x0000080C, + .frame_header_cfg = 0x00000810, + .addr_image = 0x00000814, + .addr_image_offset = 0x00000818, + .buffer_width_cfg = 0x0000081C, + .buffer_height_cfg = 0x00000820, + .packer_cfg = 0x00000824, + .wr_stride = 0x00000828, + .irq_subsample_cfg_period = 0x00000848, + .irq_subsample_cfg_pattern = 0x0000084C, + .burst_limit_cfg = 0x0000085C, + .misr_cfg = 0x00000860, + .misr_rd_word_sel = 0x00000864, + .misr_val = 0x00000868, + .debug_status_cfg = 0x0000086C, + .debug_status_0 = 0x00000870, + .debug_status_1 = 0x00000874, + }, + }, + }, + .titan_reg = { + .top_hw_version = 0x00000900, + .top_titan_version = 0x00000904, + .top_rst_cmd = 0x00000908, + .top_core_clk_cfg = 0x00000920, + .top_irq_status = 0x0000090C, + .top_irq_mask = 0x00000910, + .top_irq_clear = 0x00000914, + .top_irq_set = 0x00000918, + .top_irq_cmd = 0x0000091C, + .top_violation_status = 0x00000924, + .top_spare = 0x000009FC, + }, +}; + +#endif /* _CAM_LRME_HW_REG_H_ */ diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..5ef984cba883374ca5d8d85c1330e8c0a75b9a10 --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> + +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" + + +int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_soc_private *soc_private = + (struct cam_lrme_soc_private *)soc_info->soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + int rc = 0; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 2; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_READ; + axi_vote.axi_path[0].camnoc_bw = 7200000; + axi_vote.axi_path[0].mnoc_ab_bw = 7200000; + axi_vote.axi_path[0].mnoc_ib_bw = 7200000; + axi_vote.axi_path[1].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[1].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[1].camnoc_bw = 7200000; + axi_vote.axi_path[1].mnoc_ab_bw = 7200000; + axi_vote.axi_path[1].mnoc_ib_bw = 7200000; + + rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to start cpas, rc %d", rc); + return -EFAULT; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_SVS_VOTE, + true); + if (rc) { + CAM_ERR(CAM_LRME, + "Failed to enable platform resource, rc %d", rc); + goto stop_cpas; + } + + cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_ENABLE); + + return rc; + +stop_cpas: + if (cam_cpas_stop(soc_private->cpas_handle)) + CAM_ERR(CAM_LRME, "Failed to stop cpas"); + + return rc; +} + +int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw) +{ + struct cam_hw_soc_info *soc_info = &lrme_hw->soc_info; + struct cam_lrme_soc_private *soc_private; + int rc = 0; + + soc_private = soc_info->soc_private; + + cam_lrme_set_irq(lrme_hw, CAM_LRME_IRQ_DISABLE); + + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_LRME, "Failed to disable platform resource"); + return rc; + } + rc = cam_cpas_stop(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_LRME, "Failed to stop cpas"); + + return rc; +} + +int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data) +{ + struct cam_lrme_soc_private *soc_private; + struct cam_cpas_register_params cpas_register_param; + int rc; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in get_dt_properties, rc=%d", rc); + return rc; + } + + rc = cam_soc_util_request_platform_resource(soc_info, irq_handler, + private_data); + if (rc) { + CAM_ERR(CAM_LRME, "Failed in request_platform_resource rc=%d", + rc); + return rc; + } + + soc_private = kzalloc(sizeof(struct cam_lrme_soc_private), GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto release_res; + } + soc_info->soc_private = soc_private; + + memset(&cpas_register_param, 0, sizeof(cpas_register_param)); + strlcpy(cpas_register_param.identifier, + "lrmecpas", CAM_HW_IDENTIFIER_LENGTH); + cpas_register_param.cell_index = soc_info->index; + cpas_register_param.dev = &soc_info->pdev->dev; + cpas_register_param.userdata = private_data; + cpas_register_param.cam_cpas_client_cb = NULL; + + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_LRME, "CPAS registration failed"); + goto free_soc_private; + } + soc_private->cpas_handle = cpas_register_param.client_handle; + CAM_DBG(CAM_LRME, "CPAS handle=%d", soc_private->cpas_handle); + + return rc; + +free_soc_private: + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; +release_res: + cam_soc_util_release_platform_resource(soc_info); + + return rc; +} + +int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info) +{ + struct cam_lrme_soc_private *soc_private = + (struct cam_lrme_soc_private *)soc_info->soc_private; + int rc; + + rc = cam_cpas_unregister_client(soc_private->cpas_handle); + if (rc) + CAM_ERR(CAM_LRME, "Unregister cpas failed, handle=%d, rc=%d", + soc_private->cpas_handle, rc); + + rc = cam_soc_util_release_platform_resource(soc_info); + if (rc) + CAM_ERR(CAM_LRME, "release platform failed, rc=%d", rc); + + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..d77ac2bfdb63c90e34832ae769de4bc6a551f1aa --- /dev/null +++ b/techpack/camera/drivers/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_LRME_HW_SOC_H_ +#define _CAM_LRME_HW_SOC_H_ + +#include "cam_soc_util.h" + +struct cam_lrme_soc_private { + uint32_t cpas_handle; +}; + +int cam_lrme_soc_enable_resources(struct cam_hw_info *lrme_hw); +int cam_lrme_soc_disable_resources(struct cam_hw_info *lrme_hw); +int cam_lrme_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *private_data); +int cam_lrme_soc_deinit_resources(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_LRME_HW_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_req_mgr/Makefile b/techpack/camera/drivers/cam_req_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..50599d87925596274c7a88498c522374432419d9 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr_core.o\ + cam_req_mgr_dev.o \ + cam_req_mgr_util.o \ + cam_req_mgr_workq.o \ + cam_mem_mgr.o \ + cam_req_mgr_timer.o \ + cam_req_mgr_debug.o diff --git a/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr.c b/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..eef1583451ba04e2d6aa350b84be6b3c01e60eaa --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr.c @@ -0,0 +1,1401 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/msm_ion.h> +#include <linux/slab.h> +#include <linux/ion_kernel.h> +#include <linux/dma-buf.h> + +#include "cam_req_mgr_util.h" +#include "cam_mem_mgr.h" +#include "cam_smmu_api.h" +#include "cam_debug_util.h" + +static struct cam_mem_table tbl; +static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); + +static int cam_mem_util_get_dma_dir(uint32_t flags) +{ + int rc = -EINVAL; + + if (flags & CAM_MEM_FLAG_HW_READ_ONLY) + rc = DMA_TO_DEVICE; + else if (flags & CAM_MEM_FLAG_HW_WRITE_ONLY) + rc = DMA_FROM_DEVICE; + else if (flags & CAM_MEM_FLAG_HW_READ_WRITE) + rc = DMA_BIDIRECTIONAL; + else if (flags & CAM_MEM_FLAG_PROTECTED_MODE) + rc = DMA_BIDIRECTIONAL; + + return rc; +} + +static int cam_mem_util_map_cpu_va(struct dma_buf *dmabuf, + uintptr_t *vaddr, + size_t *len) +{ + int i, j, rc; + void *addr; + + /* + * dma_buf_begin_cpu_access() and dma_buf_end_cpu_access() + * need to be called in pair to avoid stability issue. + */ + rc = dma_buf_begin_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + if (rc) { + CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); + return rc; + } + + /* + * Code could be simplified if ION support of dma_buf_vmap is + * available. This workaround takes the avandaage that ion_alloc + * returns a virtually contiguous memory region, so we just need + * to _kmap each individual page and then only use the virtual + * address returned from the first call to _kmap. + */ + for (i = 0; i < PAGE_ALIGN(dmabuf->size) / PAGE_SIZE; i++) { + addr = dma_buf_kmap(dmabuf, i); + if (IS_ERR_OR_NULL(addr)) { + CAM_ERR(CAM_MEM, "kernel map fail"); + for (j = 0; j < i; j++) + dma_buf_kunmap(dmabuf, + j, + (void *)(*vaddr + (j * PAGE_SIZE))); + *vaddr = 0; + *len = 0; + rc = -ENOSPC; + goto fail; + } + if (i == 0) + *vaddr = (uint64_t)addr; + } + + *len = dmabuf->size; + + return 0; + +fail: + dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + return rc; +} +static int cam_mem_util_unmap_cpu_va(struct dma_buf *dmabuf, + uint64_t vaddr) +{ + int i, rc = 0, page_num; + + if (!dmabuf || !vaddr) { + CAM_ERR(CAM_MEM, "Invalid input args %pK %llX", dmabuf, vaddr); + return -EINVAL; + } + + page_num = PAGE_ALIGN(dmabuf->size) / PAGE_SIZE; + + for (i = 0; i < page_num; i++) { + dma_buf_kunmap(dmabuf, i, + (void *)(vaddr + (i * PAGE_SIZE))); + } + + /* + * dma_buf_begin_cpu_access() and + * dma_buf_end_cpu_access() need to be called in pair + * to avoid stability issue. + */ + rc = dma_buf_end_cpu_access(dmabuf, DMA_BIDIRECTIONAL); + if (rc) { + CAM_ERR(CAM_MEM, "Failed in end cpu access, dmabuf=%pK", + dmabuf); + return rc; + } + + return rc; +} + +int cam_mem_mgr_init(void) +{ + int i; + int bitmap_size; + + memset(tbl.bufq, 0, sizeof(tbl.bufq)); + + bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long); + tbl.bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!tbl.bitmap) + return -ENOMEM; + + tbl.bits = bitmap_size * BITS_PER_BYTE; + bitmap_zero(tbl.bitmap, tbl.bits); + /* We need to reserve slot 0 because 0 is invalid */ + set_bit(0, tbl.bitmap); + + for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { + tbl.bufq[i].fd = -1; + tbl.bufq[i].buf_handle = -1; + } + mutex_init(&tbl.m_lock); + + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); + + return 0; +} + +static int32_t cam_mem_get_slot(void) +{ + int32_t idx; + + mutex_lock(&tbl.m_lock); + idx = find_first_zero_bit(tbl.bitmap, tbl.bits); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + mutex_unlock(&tbl.m_lock); + return -ENOMEM; + } + + set_bit(idx, tbl.bitmap); + tbl.bufq[idx].active = true; + mutex_init(&tbl.bufq[idx].q_lock); + mutex_unlock(&tbl.m_lock); + + return idx; +} + +static void cam_mem_put_slot(int32_t idx) +{ + mutex_lock(&tbl.m_lock); + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].active = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + mutex_destroy(&tbl.bufq[idx].q_lock); + clear_bit(idx, tbl.bitmap); + mutex_unlock(&tbl.m_lock); +} + +int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, + dma_addr_t *iova_ptr, size_t *len_ptr) +{ + int rc = 0, idx; + + *len_ptr = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) + return -ENOENT; + + if (!tbl.bufq[idx].active) + return -EAGAIN; + + mutex_lock(&tbl.bufq[idx].q_lock); + if (buf_handle != tbl.bufq[idx].buf_handle) { + rc = -EINVAL; + goto handle_mismatch; + } + + if (CAM_MEM_MGR_IS_SECURE_HDL(buf_handle)) + rc = cam_smmu_get_stage2_iova(mmu_handle, + tbl.bufq[idx].fd, + iova_ptr, + len_ptr); + else + rc = cam_smmu_get_iova(mmu_handle, + tbl.bufq[idx].fd, + iova_ptr, + len_ptr); + if (rc) { + CAM_ERR(CAM_MEM, + "fail to map buf_hdl:0x%x, mmu_hdl: 0x%x for fd:%d", + buf_handle, mmu_handle, tbl.bufq[idx].fd); + goto handle_mismatch; + } + + CAM_DBG(CAM_MEM, + "handle:0x%x fd:%d iova_ptr:%pK len_ptr:%llu", + mmu_handle, tbl.bufq[idx].fd, iova_ptr, *len_ptr); +handle_mismatch: + mutex_unlock(&tbl.bufq[idx].q_lock); + return rc; +} +EXPORT_SYMBOL(cam_mem_get_io_buf); + +int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) +{ + int idx; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!buf_handle || !vaddr_ptr || !len) + return -EINVAL; + + idx = CAM_MEM_MGR_GET_HDL_IDX(buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) + return -EINVAL; + + if (!tbl.bufq[idx].active) + return -EPERM; + + if (buf_handle != tbl.bufq[idx].buf_handle) + return -EINVAL; + + if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) + return -EINVAL; + + if (tbl.bufq[idx].kmdvaddr) { + *vaddr_ptr = tbl.bufq[idx].kmdvaddr; + *len = tbl.bufq[idx].len; + } else { + CAM_ERR(CAM_MEM, "No KMD access was requested for 0x%x handle", + buf_handle); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(cam_mem_get_cpu_buf); + +int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) +{ + int rc = 0, idx; + uint32_t cache_dir; + unsigned long dmabuf_flag = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd) + return -EINVAL; + + idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) + return -EINVAL; + + mutex_lock(&tbl.bufq[idx].q_lock); + + if (!tbl.bufq[idx].active) { + rc = -EINVAL; + goto end; + } + + if (cmd->buf_handle != tbl.bufq[idx].buf_handle) { + rc = -EINVAL; + goto end; + } + + rc = dma_buf_get_flags(tbl.bufq[idx].dma_buf, &dmabuf_flag); + if (rc) { + CAM_ERR(CAM_MEM, "cache get flags failed %d", rc); + goto end; + } + + if (dmabuf_flag & ION_FLAG_CACHED) { + switch (cmd->mem_cache_ops) { + case CAM_MEM_CLEAN_CACHE: + cache_dir = DMA_TO_DEVICE; + break; + case CAM_MEM_INV_CACHE: + cache_dir = DMA_FROM_DEVICE; + break; + case CAM_MEM_CLEAN_INV_CACHE: + cache_dir = DMA_BIDIRECTIONAL; + break; + default: + CAM_ERR(CAM_MEM, + "invalid cache ops :%d", cmd->mem_cache_ops); + rc = -EINVAL; + goto end; + } + } else { + CAM_DBG(CAM_MEM, "BUF is not cached"); + goto end; + } + + rc = dma_buf_begin_cpu_access(tbl.bufq[idx].dma_buf, + (cmd->mem_cache_ops == CAM_MEM_CLEAN_INV_CACHE) ? + DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + if (rc) { + CAM_ERR(CAM_MEM, "dma begin access failed rc=%d", rc); + goto end; + } + + rc = dma_buf_end_cpu_access(tbl.bufq[idx].dma_buf, + cache_dir); + if (rc) { + CAM_ERR(CAM_MEM, "dma end access failed rc=%d", rc); + goto end; + } + +end: + mutex_unlock(&tbl.bufq[idx].q_lock); + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_cache_ops); + +static int cam_mem_util_get_dma_buf(size_t len, + unsigned int heap_id_mask, + unsigned int flags, + struct dma_buf **buf) +{ + int rc = 0; + + if (!buf) { + CAM_ERR(CAM_MEM, "Invalid params"); + return -EINVAL; + } + + *buf = ion_alloc(len, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*buf)) + return -ENOMEM; + + return rc; +} + +static int cam_mem_util_get_dma_buf_fd(size_t len, + size_t align, + unsigned int heap_id_mask, + unsigned int flags, + struct dma_buf **buf, + int *fd) +{ + struct dma_buf *dmabuf = NULL; + int rc = 0; + + if (!buf || !fd) { + CAM_ERR(CAM_MEM, "Invalid params, buf=%pK, fd=%pK", buf, fd); + return -EINVAL; + } + + *buf = ion_alloc(len, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*buf)) + return -ENOMEM; + + *fd = dma_buf_fd(*buf, O_CLOEXEC); + if (*fd < 0) { + CAM_ERR(CAM_MEM, "get fd fail, *fd=%d", *fd); + rc = -EINVAL; + goto get_fd_fail; + } + + /* + * increment the ref count so that ref count becomes 2 here + * when we close fd, refcount becomes 1 and when we do + * dmap_put_buf, ref count becomes 0 and memory will be freed. + */ + dmabuf = dma_buf_get(*fd); + if (IS_ERR_OR_NULL(dmabuf)) { + CAM_ERR(CAM_MEM, "dma_buf_get failed, *fd=%d", *fd); + rc = -EINVAL; + } + + return rc; + +get_fd_fail: + dma_buf_put(*buf); + return rc; +} + +static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, + struct dma_buf **dmabuf, + int *fd) +{ + uint32_t heap_id; + uint32_t ion_flag = 0; + int rc; + + if ((cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) && + (cmd->flags & CAM_MEM_FLAG_CDSP_OUTPUT)) { + heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); + ion_flag |= + ION_FLAG_SECURE | ION_FLAG_CP_CAMERA | ION_FLAG_CP_CDSP; + } else if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) { + heap_id = ION_HEAP(ION_SECURE_DISPLAY_HEAP_ID); + ion_flag |= ION_FLAG_SECURE | ION_FLAG_CP_CAMERA; + } else { + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | + ION_HEAP(ION_CAMERA_HEAP_ID); + } + + if (cmd->flags & CAM_MEM_FLAG_CACHE) + ion_flag |= ION_FLAG_CACHED; + else + ion_flag &= ~ION_FLAG_CACHED; + + rc = cam_mem_util_get_dma_buf_fd(cmd->len, + cmd->align, + heap_id, + ion_flag, + dmabuf, + fd); + + return rc; +} + + +static int cam_mem_util_check_alloc_flags(struct cam_mem_mgr_alloc_cmd *cmd) +{ + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", + CAM_MEM_MMU_MAX_HANDLE); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && + cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); + return -EINVAL; + } + + return 0; +} + +static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd) +{ + if (!cmd->flags) { + CAM_ERR(CAM_MEM, "Invalid flags"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_MEM, "Num of mmu hdl %d exceeded maximum(%d)", + cmd->num_hdl, CAM_MEM_MMU_MAX_HANDLE); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && + cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + CAM_ERR(CAM_MEM, + "Kernel mapping in secure mode not allowed, flags=0x%x", + cmd->flags); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + CAM_ERR(CAM_MEM, + "Shared memory buffers are not allowed to be mapped"); + return -EINVAL; + } + + return 0; +} + +static int cam_mem_util_map_hw_va(uint32_t flags, + int32_t *mmu_hdls, + int32_t num_hdls, + int fd, + dma_addr_t *hw_vaddr, + size_t *len, + enum cam_smmu_region_id region) +{ + int i; + int rc = -1; + int dir = cam_mem_util_get_dma_dir(flags); + bool dis_delayed_unmap = false; + + if (dir < 0) { + CAM_ERR(CAM_MEM, "fail to map DMA direction, dir=%d", dir); + return dir; + } + + if (flags & CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP) + dis_delayed_unmap = true; + + CAM_DBG(CAM_MEM, + "map_hw_va : fd = %d, flags = 0x%x, dir=%d, num_hdls=%d", + fd, flags, dir, num_hdls); + + if (flags & CAM_MEM_FLAG_PROTECTED_MODE) { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_map_stage2_iova(mmu_hdls[i], + fd, + dir, + hw_vaddr, + len); + + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed to securely map to smmu, i=%d, fd=%d, dir=%d, mmu_hdl=%d, rc=%d", + i, fd, dir, mmu_hdls[i], rc); + goto multi_map_fail; + } + } + } else { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_map_user_iova(mmu_hdls[i], + fd, + dis_delayed_unmap, + dir, + (dma_addr_t *)hw_vaddr, + len, + region); + + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed to map to smmu, i=%d, fd=%d, dir=%d, mmu_hdl=%d, region=%d, rc=%d", + i, fd, dir, mmu_hdls[i], region, rc); + goto multi_map_fail; + } + } + } + + return rc; +multi_map_fail: + if (flags & CAM_MEM_FLAG_PROTECTED_MODE) + for (--i; i > 0; i--) + cam_smmu_unmap_stage2_iova(mmu_hdls[i], fd); + else + for (--i; i > 0; i--) + cam_smmu_unmap_user_iova(mmu_hdls[i], + fd, + CAM_SMMU_REGION_IO); + return rc; + +} + +int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) +{ + int rc; + int32_t idx; + struct dma_buf *dmabuf = NULL; + int fd = -1; + dma_addr_t hw_vaddr = 0; + size_t len; + uintptr_t kvaddr = 0; + size_t klen; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_MEM, " Invalid argument"); + return -EINVAL; + } + len = cmd->len; + + rc = cam_mem_util_check_alloc_flags(cmd); + if (rc) { + CAM_ERR(CAM_MEM, "Invalid flags: flags = 0x%X, rc=%d", + cmd->flags, rc); + return rc; + } + + rc = cam_mem_util_ion_alloc(cmd, + &dmabuf, + &fd); + if (rc) { + CAM_ERR(CAM_MEM, + "Ion Alloc failed, len=%llu, align=%llu, flags=0x%x, num_hdl=%d", + cmd->len, cmd->align, cmd->flags, cmd->num_hdl); + return rc; + } + + idx = cam_mem_get_slot(); + if (idx < 0) { + CAM_ERR(CAM_MEM, "Failed in getting mem slot, idx=%d", idx); + rc = -ENOMEM; + goto slot_fail; + } + + if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || + (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) || + (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { + + enum cam_smmu_region_id region; + + if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + + + if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) + region = CAM_SMMU_REGION_SHARED; + + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) + region = CAM_SMMU_REGION_SECHEAP; + + rc = cam_mem_util_map_hw_va(cmd->flags, + cmd->mmu_hdls, + cmd->num_hdl, + fd, + &hw_vaddr, + &len, + region); + + if (rc) { + CAM_ERR(CAM_MEM, + "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->flags, fd, region, cmd->num_hdl, rc); + goto map_hw_fail; + } + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].fd = fd; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].flags = cmd->flags; + tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, fd); + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) + CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true); + + if (cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { + rc = cam_mem_util_map_cpu_va(dmabuf, &kvaddr, &klen); + if (rc) { + CAM_ERR(CAM_MEM, "dmabuf: %pK mapping failed: %d", + dmabuf, rc); + goto map_kernel_fail; + } + } + + tbl.bufq[idx].kmdvaddr = kvaddr; + tbl.bufq[idx].vaddr = hw_vaddr; + tbl.bufq[idx].dma_buf = dmabuf; + tbl.bufq[idx].len = cmd->len; + tbl.bufq[idx].num_hdl = cmd->num_hdl; + memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls, + sizeof(int32_t) * cmd->num_hdl); + tbl.bufq[idx].is_imported = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + + cmd->out.buf_handle = tbl.bufq[idx].buf_handle; + cmd->out.fd = tbl.bufq[idx].fd; + cmd->out.vaddr = 0; + + CAM_DBG(CAM_MEM, + "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu", + cmd->out.fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle, + tbl.bufq[idx].len); + + return rc; + +map_kernel_fail: + mutex_unlock(&tbl.bufq[idx].q_lock); +map_hw_fail: + cam_mem_put_slot(idx); +slot_fail: + dma_buf_put(dmabuf); + return rc; +} + +int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) +{ + int32_t idx; + int rc; + struct dma_buf *dmabuf; + dma_addr_t hw_vaddr = 0; + size_t len = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd || (cmd->fd < 0)) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_MEM, "Num of mmu hdl %d exceeded maximum(%d)", + cmd->num_hdl, CAM_MEM_MMU_MAX_HANDLE); + return -EINVAL; + } + + rc = cam_mem_util_check_map_flags(cmd); + if (rc) { + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); + return rc; + } + + dmabuf = dma_buf_get(cmd->fd); + if (IS_ERR_OR_NULL((void *)(dmabuf))) { + CAM_ERR(CAM_MEM, "Failed to import dma_buf fd"); + return -EINVAL; + } + + if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || + (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { + rc = cam_mem_util_map_hw_va(cmd->flags, + cmd->mmu_hdls, + cmd->num_hdl, + cmd->fd, + &hw_vaddr, + &len, + CAM_SMMU_REGION_IO); + if (rc) { + CAM_ERR(CAM_MEM, + "Failed in map_hw_va, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + cmd->flags, cmd->fd, CAM_SMMU_REGION_IO, + cmd->num_hdl, rc); + goto map_fail; + } + } + + idx = cam_mem_get_slot(); + if (idx < 0) { + rc = -ENOMEM; + goto map_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].fd = cmd->fd; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].flags = cmd->flags; + tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, cmd->fd); + if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE) + CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true); + tbl.bufq[idx].kmdvaddr = 0; + + if (cmd->num_hdl > 0) + tbl.bufq[idx].vaddr = hw_vaddr; + else + tbl.bufq[idx].vaddr = 0; + + tbl.bufq[idx].dma_buf = dmabuf; + tbl.bufq[idx].len = len; + tbl.bufq[idx].num_hdl = cmd->num_hdl; + memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls, + sizeof(int32_t) * cmd->num_hdl); + tbl.bufq[idx].is_imported = true; + mutex_unlock(&tbl.bufq[idx].q_lock); + + cmd->out.buf_handle = tbl.bufq[idx].buf_handle; + cmd->out.vaddr = 0; + + CAM_DBG(CAM_MEM, + "fd=%d, flags=0x%x, num_hdl=%d, idx=%d, buf handle=%x, len=%zu", + cmd->fd, cmd->flags, cmd->num_hdl, idx, cmd->out.buf_handle, + tbl.bufq[idx].len); + + return rc; + +map_fail: + dma_buf_put(dmabuf); + return rc; +} + +static int cam_mem_util_unmap_hw_va(int32_t idx, + enum cam_smmu_region_id region, + enum cam_smmu_mapping_client client) +{ + int i; + uint32_t flags; + int32_t *mmu_hdls; + int num_hdls; + int fd; + int rc = 0; + + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index"); + return -EINVAL; + } + + flags = tbl.bufq[idx].flags; + mmu_hdls = tbl.bufq[idx].hdls; + num_hdls = tbl.bufq[idx].num_hdl; + fd = tbl.bufq[idx].fd; + + CAM_DBG(CAM_MEM, + "unmap_hw_va : idx=%d, fd=%x, flags=0x%x, num_hdls=%d, client=%d", + idx, fd, flags, num_hdls, client); + + if (flags & CAM_MEM_FLAG_PROTECTED_MODE) { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_unmap_stage2_iova(mmu_hdls[i], fd); + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed in secure unmap, i=%d, fd=%d, mmu_hdl=%d, rc=%d", + i, fd, mmu_hdls[i], rc); + goto unmap_end; + } + } + } else { + for (i = 0; i < num_hdls; i++) { + if (client == CAM_SMMU_MAPPING_USER) { + rc = cam_smmu_unmap_user_iova(mmu_hdls[i], + fd, region); + } else if (client == CAM_SMMU_MAPPING_KERNEL) { + rc = cam_smmu_unmap_kernel_iova(mmu_hdls[i], + tbl.bufq[idx].dma_buf, region); + } else { + CAM_ERR(CAM_MEM, + "invalid caller for unmapping : %d", + client); + rc = -EINVAL; + } + if (rc < 0) { + CAM_ERR(CAM_MEM, + "Failed in unmap, i=%d, fd=%d, mmu_hdl=%d, region=%d, rc=%d", + i, fd, mmu_hdls[i], region, rc); + goto unmap_end; + } + } + } + + return rc; + +unmap_end: + CAM_ERR(CAM_MEM, "unmapping failed"); + return rc; +} + +static void cam_mem_mgr_unmap_active_buf(int idx) +{ + enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; + + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) + region = CAM_SMMU_REGION_SHARED; + else if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + + cam_mem_util_unmap_hw_va(idx, region, CAM_SMMU_MAPPING_USER); +} + +static int cam_mem_mgr_cleanup_table(void) +{ + int i; + + mutex_lock(&tbl.m_lock); + for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { + if (!tbl.bufq[i].active) { + CAM_DBG(CAM_MEM, + "Buffer inactive at idx=%d, continuing", i); + continue; + } else { + CAM_DBG(CAM_MEM, + "Active buffer at idx=%d, possible leak needs unmapping", + i); + cam_mem_mgr_unmap_active_buf(i); + } + + mutex_lock(&tbl.bufq[i].q_lock); + if (tbl.bufq[i].dma_buf) { + dma_buf_put(tbl.bufq[i].dma_buf); + tbl.bufq[i].dma_buf = NULL; + } + tbl.bufq[i].fd = -1; + tbl.bufq[i].flags = 0; + tbl.bufq[i].buf_handle = -1; + tbl.bufq[i].vaddr = 0; + tbl.bufq[i].len = 0; + memset(tbl.bufq[i].hdls, 0, + sizeof(int32_t) * tbl.bufq[i].num_hdl); + tbl.bufq[i].num_hdl = 0; + tbl.bufq[i].dma_buf = NULL; + tbl.bufq[i].active = false; + mutex_unlock(&tbl.bufq[i].q_lock); + mutex_destroy(&tbl.bufq[i].q_lock); + } + + bitmap_zero(tbl.bitmap, tbl.bits); + /* We need to reserve slot 0 because 0 is invalid */ + set_bit(0, tbl.bitmap); + mutex_unlock(&tbl.m_lock); + + return 0; +} + +void cam_mem_mgr_deinit(void) +{ + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_UNINITIALIZED); + cam_mem_mgr_cleanup_table(); + mutex_lock(&tbl.m_lock); + bitmap_zero(tbl.bitmap, tbl.bits); + kfree(tbl.bitmap); + tbl.bitmap = NULL; + mutex_unlock(&tbl.m_lock); + mutex_destroy(&tbl.m_lock); +} + +static int cam_mem_util_unmap(int32_t idx, + enum cam_smmu_mapping_client client) +{ + int rc = 0; + enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; + + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index"); + return -EINVAL; + } + + CAM_DBG(CAM_MEM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); + + mutex_lock(&tbl.m_lock); + if ((!tbl.bufq[idx].active) && + (tbl.bufq[idx].vaddr) == 0) { + CAM_WARN(CAM_MEM, "Buffer at idx=%d is already unmapped,", + idx); + mutex_unlock(&tbl.m_lock); + return 0; + } + + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) { + if (tbl.bufq[idx].dma_buf && tbl.bufq[idx].kmdvaddr) { + rc = cam_mem_util_unmap_cpu_va(tbl.bufq[idx].dma_buf, + tbl.bufq[idx].kmdvaddr); + if (rc) + CAM_ERR(CAM_MEM, + "Failed, dmabuf=%pK, kmdvaddr=%pK", + tbl.bufq[idx].dma_buf, + (void *) tbl.bufq[idx].kmdvaddr); + } + } + + /* SHARED flag gets precedence, all other flags after it */ + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + region = CAM_SMMU_REGION_SHARED; + } else { + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + } + + if ((tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_READ_WRITE) || + (tbl.bufq[idx].flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) || + (tbl.bufq[idx].flags & CAM_MEM_FLAG_PROTECTED_MODE)) { + if (cam_mem_util_unmap_hw_va(idx, region, client)) + CAM_ERR(CAM_MEM, "Failed, dmabuf=%pK", + tbl.bufq[idx].dma_buf); + if (client == CAM_SMMU_MAPPING_KERNEL) + tbl.bufq[idx].dma_buf = NULL; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].flags = 0; + tbl.bufq[idx].buf_handle = -1; + tbl.bufq[idx].vaddr = 0; + memset(tbl.bufq[idx].hdls, 0, + sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE); + + CAM_DBG(CAM_MEM, + "Ion buf at idx = %d freeing fd = %d, imported %d, dma_buf %pK", + idx, tbl.bufq[idx].fd, + tbl.bufq[idx].is_imported, + tbl.bufq[idx].dma_buf); + + if (tbl.bufq[idx].dma_buf) + dma_buf_put(tbl.bufq[idx].dma_buf); + + tbl.bufq[idx].fd = -1; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].is_imported = false; + tbl.bufq[idx].len = 0; + tbl.bufq[idx].num_hdl = 0; + tbl.bufq[idx].active = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + mutex_destroy(&tbl.bufq[idx].q_lock); + clear_bit(idx, tbl.bitmap); + mutex_unlock(&tbl.m_lock); + + return rc; +} + +int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd) +{ + int idx; + int rc; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!cmd) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index %d extracted from mem handle", + idx); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_MEM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != cmd->buf_handle) { + CAM_ERR(CAM_MEM, + "Released buf handle %d not matching within table %d, idx=%d", + cmd->buf_handle, tbl.bufq[idx].buf_handle, idx); + return -EINVAL; + } + + CAM_DBG(CAM_MEM, "Releasing hdl = %x, idx = %d", cmd->buf_handle, idx); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_USER); + + return rc; +} + +int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, + struct cam_mem_mgr_memory_desc *out) +{ + struct dma_buf *buf = NULL; + int ion_fd = -1; + int rc = 0; + uint32_t heap_id; + int32_t ion_flag = 0; + uintptr_t kvaddr; + dma_addr_t iova = 0; + size_t request_len = 0; + uint32_t mem_handle; + int32_t idx; + int32_t smmu_hdl = 0; + int32_t num_hdl = 0; + + enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp || !out) { + CAM_ERR(CAM_MEM, "Invalid params"); + return -EINVAL; + } + + if (!(inp->flags & CAM_MEM_FLAG_HW_READ_WRITE || + inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS || + inp->flags & CAM_MEM_FLAG_CACHE)) { + CAM_ERR(CAM_MEM, "Invalid flags for request mem"); + return -EINVAL; + } + + if (inp->flags & CAM_MEM_FLAG_CACHE) + ion_flag |= ION_FLAG_CACHED; + else + ion_flag &= ~ION_FLAG_CACHED; + + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | + ION_HEAP(ION_CAMERA_HEAP_ID); + + rc = cam_mem_util_get_dma_buf(inp->size, + heap_id, + ion_flag, + &buf); + + if (rc) { + CAM_ERR(CAM_MEM, "ION alloc failed for shared buffer"); + goto ion_fail; + } else { + CAM_DBG(CAM_MEM, "Got dma_buf = %pK", buf); + } + + /* + * we are mapping kva always here, + * update flags so that we do unmap properly + */ + inp->flags |= CAM_MEM_FLAG_KMD_ACCESS; + rc = cam_mem_util_map_cpu_va(buf, &kvaddr, &request_len); + if (rc) { + CAM_ERR(CAM_MEM, "Failed to get kernel vaddr"); + goto map_fail; + } + + if (!inp->smmu_hdl) { + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); + rc = -EINVAL; + goto smmu_fail; + } + + /* SHARED flag gets precedence, all other flags after it */ + if (inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + region = CAM_SMMU_REGION_SHARED; + } else { + if (inp->flags & CAM_MEM_FLAG_HW_READ_WRITE) + region = CAM_SMMU_REGION_IO; + } + + rc = cam_smmu_map_kernel_iova(inp->smmu_hdl, + buf, + CAM_SMMU_MAP_RW, + &iova, + &request_len, + region); + + if (rc < 0) { + CAM_ERR(CAM_MEM, "SMMU mapping failed"); + goto smmu_fail; + } + + smmu_hdl = inp->smmu_hdl; + num_hdl = 1; + + idx = cam_mem_get_slot(); + if (idx < 0) { + rc = -ENOMEM; + goto slot_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + mem_handle = GET_MEM_HANDLE(idx, ion_fd); + tbl.bufq[idx].dma_buf = buf; + tbl.bufq[idx].fd = -1; + tbl.bufq[idx].flags = inp->flags; + tbl.bufq[idx].buf_handle = mem_handle; + tbl.bufq[idx].kmdvaddr = kvaddr; + + tbl.bufq[idx].vaddr = iova; + + tbl.bufq[idx].len = inp->size; + tbl.bufq[idx].num_hdl = num_hdl; + memcpy(tbl.bufq[idx].hdls, &smmu_hdl, + sizeof(int32_t)); + tbl.bufq[idx].is_imported = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + + out->kva = kvaddr; + out->iova = (uint32_t)iova; + out->smmu_hdl = smmu_hdl; + out->mem_handle = mem_handle; + out->len = inp->size; + out->region = region; + + return rc; +slot_fail: + cam_smmu_unmap_kernel_iova(inp->smmu_hdl, + buf, region); +smmu_fail: + cam_mem_util_unmap_cpu_va(buf, kvaddr); +map_fail: + dma_buf_put(buf); +ion_fail: + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_request_mem); + +int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp) +{ + int32_t idx; + int rc; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + if (tbl.bufq[idx].vaddr == 0) { + CAM_ERR(CAM_MEM, "buffer is released already"); + return 0; + } + CAM_ERR(CAM_MEM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != inp->mem_handle) { + CAM_ERR(CAM_MEM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); + + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_release_mem); + +int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, + enum cam_smmu_region_id region, + struct cam_mem_mgr_memory_desc *out) +{ + struct dma_buf *buf = NULL; + int rc = 0; + int ion_fd = -1; + uint32_t heap_id; + dma_addr_t iova = 0; + size_t request_len = 0; + uint32_t mem_handle; + int32_t idx; + int32_t smmu_hdl = 0; + int32_t num_hdl = 0; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp || !out) { + CAM_ERR(CAM_MEM, "Invalid param(s)"); + return -EINVAL; + } + + if (!inp->smmu_hdl) { + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); + return -EINVAL; + } + + if (region != CAM_SMMU_REGION_SECHEAP) { + CAM_ERR(CAM_MEM, "Only secondary heap supported"); + return -EINVAL; + } + + heap_id = ION_HEAP(ION_SYSTEM_HEAP_ID) | + ION_HEAP(ION_CAMERA_HEAP_ID); + rc = cam_mem_util_get_dma_buf(inp->size, + heap_id, + 0, + &buf); + + if (rc) { + CAM_ERR(CAM_MEM, "ION alloc failed for sec heap buffer"); + goto ion_fail; + } else { + CAM_DBG(CAM_MEM, "Got dma_buf = %pK", buf); + } + + rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl, + buf, + &iova, + &request_len); + + if (rc) { + CAM_ERR(CAM_MEM, "Reserving secondary heap failed"); + goto smmu_fail; + } + + smmu_hdl = inp->smmu_hdl; + num_hdl = 1; + + idx = cam_mem_get_slot(); + if (idx < 0) { + rc = -ENOMEM; + goto slot_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + mem_handle = GET_MEM_HANDLE(idx, ion_fd); + tbl.bufq[idx].fd = -1; + tbl.bufq[idx].dma_buf = buf; + tbl.bufq[idx].flags = inp->flags; + tbl.bufq[idx].buf_handle = mem_handle; + tbl.bufq[idx].kmdvaddr = 0; + + tbl.bufq[idx].vaddr = iova; + + tbl.bufq[idx].len = request_len; + tbl.bufq[idx].num_hdl = num_hdl; + memcpy(tbl.bufq[idx].hdls, &smmu_hdl, + sizeof(int32_t)); + tbl.bufq[idx].is_imported = false; + mutex_unlock(&tbl.bufq[idx].q_lock); + + out->kva = 0; + out->iova = (uint32_t)iova; + out->smmu_hdl = smmu_hdl; + out->mem_handle = mem_handle; + out->len = request_len; + out->region = region; + + return rc; + +slot_fail: + cam_smmu_release_sec_heap(smmu_hdl); +smmu_fail: + dma_buf_put(buf); +ion_fail: + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_reserve_memory_region); + +int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) +{ + int32_t idx; + int rc; + int32_t smmu_hdl; + + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_MEM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + + if (!inp) { + CAM_ERR(CAM_MEM, "Invalid argument"); + return -EINVAL; + } + + if (inp->region != CAM_SMMU_REGION_SECHEAP) { + CAM_ERR(CAM_MEM, "Only secondary heap supported"); + return -EINVAL; + } + + idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + if (tbl.bufq[idx].vaddr == 0) { + CAM_ERR(CAM_MEM, "buffer is released already"); + return 0; + } + CAM_ERR(CAM_MEM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != inp->mem_handle) { + CAM_ERR(CAM_MEM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + if (tbl.bufq[idx].num_hdl != 1) { + CAM_ERR(CAM_MEM, + "Sec heap region should have only one smmu hdl"); + return -ENODEV; + } + + memcpy(&smmu_hdl, tbl.bufq[idx].hdls, + sizeof(int32_t)); + if (inp->smmu_hdl != smmu_hdl) { + CAM_ERR(CAM_MEM, + "Passed SMMU handle doesn't match with internal hdl"); + return -ENODEV; + } + + rc = cam_smmu_release_sec_heap(inp->smmu_hdl); + if (rc) { + CAM_ERR(CAM_MEM, + "Sec heap region release failed"); + return -ENODEV; + } + + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); + if (rc) + CAM_ERR(CAM_MEM, "unmapping secondary heap failed"); + + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_free_memory_region); diff --git a/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr.h b/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..6ce30db66fe3fb008e16bd07e167861fa8803009 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr.h @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_MEM_MGR_H_ +#define _CAM_MEM_MGR_H_ + +#include <linux/mutex.h> +#include <linux/dma-buf.h> +#include <media/cam_req_mgr.h> +#include "cam_mem_mgr_api.h" + +#define CAM_MEM_BUFQ_MAX 1024 + +/* Enum for possible mem mgr states */ +enum cam_mem_mgr_state { + CAM_MEM_MGR_UNINITIALIZED, + CAM_MEM_MGR_INITIALIZED, +}; + +/*Enum for possible SMMU operations */ +enum cam_smmu_mapping_client { + CAM_SMMU_MAPPING_USER, + CAM_SMMU_MAPPING_KERNEL, +}; + +/** + * struct cam_mem_buf_queue + * + * @dma_buf: pointer to the allocated dma_buf in the table + * @q_lock: mutex lock for buffer + * @hdls: list of mapped handles + * @num_hdl: number of handles + * @fd: file descriptor of buffer + * @buf_handle: unique handle for buffer + * @align: alignment for allocation + * @len: size of buffer + * @flags: attributes of buffer + * @vaddr: IOVA of buffer + * @kmdvaddr: Kernel virtual address + * @active: state of the buffer + * @is_imported: Flag indicating if buffer is imported from an FD in user space + */ +struct cam_mem_buf_queue { + struct dma_buf *dma_buf; + struct mutex q_lock; + int32_t hdls[CAM_MEM_MMU_MAX_HANDLE]; + int32_t num_hdl; + int32_t fd; + int32_t buf_handle; + int32_t align; + size_t len; + uint32_t flags; + uint64_t vaddr; + uintptr_t kmdvaddr; + bool active; + bool is_imported; +}; + +/** + * struct cam_mem_table + * + * @m_lock: mutex lock for table + * @bitmap: bitmap of the mem mgr utility + * @bits: max bits of the utility + * @bufq: array of buffers + */ +struct cam_mem_table { + struct mutex m_lock; + void *bitmap; + size_t bits; + struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX]; +}; + +/** + * @brief: Allocates and maps buffer + * + * @cmd: Allocation information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd); + +/** + * @brief: Releases a buffer reference + * + * @cmd: Buffer release information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd); + +/** + * @brief Maps a buffer + * + * @cmd: Buffer mapping information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd); + +/** + * @brief: Perform cache ops on the buffer + * + * @cmd: Cache ops information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd); + +/** + * @brief: Initializes the memory manager + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_init(void); + +/** + * @brief: Tears down the memory manager + * + * @return None + */ +void cam_mem_mgr_deinit(void); + +#endif /* _CAM_MEM_MGR_H_ */ diff --git a/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr_api.h b/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr_api.h new file mode 100644 index 0000000000000000000000000000000000000000..e216a46a3a6fe96c6f580f769d2832cf01543037 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_mem_mgr_api.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_MEM_MGR_API_H_ +#define _CAM_MEM_MGR_API_H_ + +#include <media/cam_req_mgr.h> +#include "cam_smmu_api.h" + +/** + * struct cam_mem_mgr_request_desc + * + * @size : Size of memory requested for allocation + * @align : Alignment of requested memory + * @smmu_hdl: SMMU handle to identify context bank where memory will be mapped + * @flags : Flags to indicate cached/uncached property + * @region : Region where memory should be allocated + */ +struct cam_mem_mgr_request_desc { + uint64_t size; + uint64_t align; + int32_t smmu_hdl; + uint32_t flags; +}; + +/** + * struct cam_mem_mgr_memory_desc + * + * @kva : Kernel virtual address of allocated memory + * @iova : IOVA of allocated memory + * @smmu_hdl : SMMU handle of allocated memory + * @mem_handle : Mem handle identifying allocated memory + * @len : Length of allocated memory + * @region : Region to which allocated memory belongs + */ +struct cam_mem_mgr_memory_desc { + uintptr_t kva; + uint32_t iova; + int32_t smmu_hdl; + uint32_t mem_handle; + uint64_t len; + enum cam_smmu_region_id region; +}; + +/** + * @brief: Requests a memory buffer + * + * @inp: Information specifying requested buffer properties + * @out: Information about allocated buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, + struct cam_mem_mgr_memory_desc *out); + +/** + * @brief: Releases a memory buffer + * + * @inp: Information specifying buffer to be released + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp); + +/** + * @brief: Returns IOVA information about buffer + * + * @buf_handle: Handle of the buffer + * @mmu_handle: SMMU handle where buffer is mapped + * @iova_ptr : Pointer to mmu's iova + * @len_ptr : Length of the buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, + dma_addr_t *iova_ptr, size_t *len_ptr); + +/** + * @brief: This indicates begin of CPU access. + * Also returns CPU address information about DMA buffer + * + * @buf_handle: Handle for the buffer + * @vaddr_ptr : pointer to kernel virtual address + * @len_ptr : Length of the buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, + size_t *len); + +static inline bool cam_mem_is_secure_buf(int32_t buf_handle) +{ + return CAM_MEM_MGR_IS_SECURE_HDL(buf_handle); +} + +/** + * @brief: Reserves a memory region + * + * @inp: Information specifying requested region properties + * @region : Region which is to be reserved + * @out : Information about reserved region + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, + enum cam_smmu_region_id region, + struct cam_mem_mgr_memory_desc *out); + +/** + * @brief: Frees a memory region + * + * @inp : Information about region which is to be freed + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp); + +#endif /* _CAM_MEM_MGR_API_H_ */ diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.c b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.c new file mode 100644 index 0000000000000000000000000000000000000000..4751db8850a26f6bbbc9903694ced7c3b0ba3049 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.c @@ -0,0 +1,3937 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include "cam_req_mgr_interface.h" +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_core.h" +#include "cam_req_mgr_workq.h" +#include "cam_req_mgr_debug.h" +#include "cam_trace.h" +#include "cam_debug_util.h" +#include "cam_req_mgr_dev.h" + +static struct cam_req_mgr_core_device *g_crm_core_dev; +static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION]; + +void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) +{ + link->link_hdl = 0; + link->num_devs = 0; + link->max_delay = CAM_PIPELINE_DELAY_0; + link->workq = NULL; + link->pd_mask = 0; + link->l_dev = NULL; + link->req.in_q = NULL; + link->req.l_tbl = NULL; + link->req.num_tbl = 0; + link->watchdog = NULL; + link->state = CAM_CRM_LINK_STATE_AVAILABLE; + link->parent = NULL; + link->subscribe_event = 0; + link->trigger_mask = 0; + link->sync_link = 0; + link->sync_link_sof_skip = false; + link->open_req_cnt = 0; + link->last_flush_id = 0; + link->initial_sync_req = -1; + link->in_msync_mode = false; + link->retry_cnt = 0; + link->is_shutdown = false; + link->initial_skip = true; + link->sof_timestamp = 0; + link->prev_sof_timestamp = 0; +} + +void cam_req_mgr_handle_core_shutdown(void) +{ + struct cam_req_mgr_core_session *session; + struct cam_req_mgr_core_session *tsession; + struct cam_req_mgr_session_info ses_info; + + if (!list_empty(&g_crm_core_dev->session_head)) { + list_for_each_entry_safe(session, tsession, + &g_crm_core_dev->session_head, entry) { + ses_info.session_hdl = + session->session_hdl; + cam_req_mgr_destroy_session(&ses_info, true); + } + } +} + +static int __cam_req_mgr_setup_payload(struct cam_req_mgr_core_workq *workq) +{ + int32_t i = 0; + int rc = 0; + struct crm_task_payload *task_data = NULL; + + task_data = kcalloc( + workq->task.num_task, sizeof(*task_data), + GFP_KERNEL); + if (!task_data) { + rc = -ENOMEM; + } else { + for (i = 0; i < workq->task.num_task; i++) + workq->task.pool[i].payload = &task_data[i]; + } + + return rc; +} + +/** + * __cam_req_mgr_find_pd_tbl() + * + * @brief : Find pipeline delay based table pointer which matches delay + * @tbl : Pointer to list of request table + * @delay : Pipeline delay value to be searched for comparison + * + * @return : pointer to request table for matching pipeline delay table. + * + */ +static struct cam_req_mgr_req_tbl *__cam_req_mgr_find_pd_tbl( + struct cam_req_mgr_req_tbl *tbl, int32_t delay) +{ + if (!tbl) + return NULL; + + do { + if (delay != tbl->pd) + tbl = tbl->next; + else + return tbl; + } while (tbl != NULL); + + return NULL; +} + +/** + * __cam_req_mgr_inc_idx() + * + * @brief : Increment val passed by step size and rollover after max_val + * @val : value to be incremented + * @step : amount/step by which val is incremented + * @max_val : max val after which idx will roll over + * + */ +static void __cam_req_mgr_inc_idx(int32_t *val, int32_t step, int32_t max_val) +{ + *val = (*val + step) % max_val; +} + +/** + * __cam_req_mgr_dec_idx() + * + * @brief : Decrement val passed by step size and rollover after max_val + * @val : value to be decremented + * @step : amount/step by which val is decremented + * @max_val : after zero value will roll over to max val + * + */ +static void __cam_req_mgr_dec_idx(int32_t *val, int32_t step, int32_t max_val) +{ + *val = *val - step; + if (*val < 0) + *val = max_val + (*val); +} + +/** + * __cam_req_mgr_inject_delay() + * + * @brief : Check if any pd device is injecting delay + * @tbl : cam_req_mgr_req_tbl + * @curr_idx : slot idx + * + * @return : 0 for success, negative for failure + */ +static int __cam_req_mgr_inject_delay( + struct cam_req_mgr_req_tbl *tbl, + int32_t curr_idx) +{ + struct cam_req_mgr_tbl_slot *slot = NULL; + int rc = 0; + + while (tbl) { + slot = &tbl->slot[curr_idx]; + if (slot->inject_delay > 0) { + slot->inject_delay--; + CAM_DBG(CAM_CRM, + "Delay injected by pd %d device", + tbl->pd); + rc = -EAGAIN; + } + __cam_req_mgr_dec_idx(&curr_idx, tbl->pd_delta, + tbl->num_slots); + tbl = tbl->next; + } + return rc; +} + +/** + * __cam_req_mgr_find_dev_name() + * + * @brief : Find the dev name whose req is not ready + * @link : link info + * @req_id : req_id which is not ready + * @pd : pipeline delay + * @masked_val : masked value holds the bit for all devices + * that don't have the req_id ready for a given + * pipeline delay + * @pd : pipeline delay + * + */ +static void __cam_req_mgr_find_dev_name( + struct cam_req_mgr_core_link *link, + int64_t req_id, uint32_t pd, uint32_t masked_val) +{ + int i = 0; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev->dev_info.p_delay == pd) { + if (masked_val & (1 << dev->dev_bit)) + continue; + + CAM_INFO(CAM_CRM, + "Skip Frame: req: %lld not ready on link: 0x%x for pd: %d dev: %s open_req count: %d", + req_id, link->link_hdl, pd, dev->dev_info.name, + link->open_req_cnt); + } + } +} + +/** + * __cam_req_mgr_notify_error_on_link() + * + * @brief : Notify userspace on exceeding max retry + * attempts to apply same req + * @link : link on which the req could not be applied + * + */ +static int __cam_req_mgr_notify_error_on_link( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_connected_device *dev) +{ + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_message msg; + int rc = 0, pd; + + session = (struct cam_req_mgr_core_session *)link->parent; + + pd = dev->dev_info.p_delay; + if (pd >= CAM_PIPELINE_DELAY_MAX) { + CAM_ERR(CAM_CRM, "pd : %d is more than expected", pd); + return -EINVAL; + } + + CAM_ERR(CAM_CRM, + "Notifying userspace to trigger recovery on link 0x%x for session %d", + link->link_hdl, session->session_hdl); + + memset(&msg, 0, sizeof(msg)); + + msg.session_hdl = session->session_hdl; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + msg.u.err_msg.request_id = + link->req.apply_data[pd].req_id; + msg.u.err_msg.link_hdl = link->link_hdl; + + CAM_DBG(CAM_CRM, "Failed for device: %s while applying request: %lld", + dev->dev_info.name, link->req.apply_data[pd].req_id); + + rc = cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT); + + if (rc) + CAM_ERR(CAM_CRM, + "Error in notifying recovery for session %d link 0x%x rc %d", + session->session_hdl, link->link_hdl, rc); + + return rc; +} + +/** + * __cam_req_mgr_traverse() + * + * @brief : Traverse through pd tables, it will internally cover all linked + * pd tables. Each pd table visited will check if idx passed to its + * in ready state. If ready means all devices linked to the pd table + * have this request id packet ready. Then it calls subsequent pd + * tbl with new idx. New idx value takes into account the delta + * between current pd table and next one. + * @traverse_data: contains all the info to traverse through pd tables + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) +{ + int rc = 0; + int32_t next_idx = traverse_data->idx; + int32_t curr_idx = traverse_data->idx; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_apply *apply_data; + struct cam_req_mgr_tbl_slot *slot = NULL; + + if (!traverse_data->tbl || !traverse_data->apply_data) { + CAM_ERR(CAM_CRM, "NULL pointer %pK %pK", + traverse_data->tbl, traverse_data->apply_data); + traverse_data->result = 0; + return -EINVAL; + } + + tbl = traverse_data->tbl; + apply_data = traverse_data->apply_data; + slot = &tbl->slot[curr_idx]; + CAM_DBG(CAM_CRM, + "Enter pd %d idx %d state %d skip %d status %d skip_idx %d", + tbl->pd, curr_idx, tbl->slot[curr_idx].state, + tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status, + traverse_data->in_q->slot[curr_idx].skip_idx); + + /* Check if req is ready or in skip mode or pd tbl is in skip mode */ + if (tbl->slot[curr_idx].state == CRM_REQ_STATE_READY || + traverse_data->in_q->slot[curr_idx].skip_idx == 1 || + tbl->skip_traverse > 0) { + if (tbl->next) { + __cam_req_mgr_dec_idx(&next_idx, tbl->pd_delta, + tbl->num_slots); + traverse_data->idx = next_idx; + traverse_data->tbl = tbl->next; + rc = __cam_req_mgr_traverse(traverse_data); + } + if (rc >= 0) { + SET_SUCCESS_BIT(traverse_data->result, tbl->pd); + + if (traverse_data->validate_only == false) { + apply_data[tbl->pd].pd = tbl->pd; + apply_data[tbl->pd].req_id = + CRM_GET_REQ_ID( + traverse_data->in_q, curr_idx); + apply_data[tbl->pd].idx = curr_idx; + + CAM_DBG(CAM_CRM, "req_id: %lld with pd of %d", + apply_data[tbl->pd].req_id, + apply_data[tbl->pd].pd); + /* + * If traverse is successful decrement + * traverse skip + */ + if (tbl->skip_traverse > 0) { + apply_data[tbl->pd].req_id = -1; + tbl->skip_traverse--; + } + } + } else { + /* linked pd table is not ready for this traverse yet */ + return rc; + } + } else { + /* This pd table is not ready to proceed with asked idx */ + traverse_data->result_data.req_id = + CRM_GET_REQ_ID(traverse_data->in_q, curr_idx); + traverse_data->result_data.pd = tbl->pd; + traverse_data->result_data.masked_value = + (tbl->dev_mask & slot->req_ready_map); + SET_FAILURE_BIT(traverse_data->result, tbl->pd); + return -EAGAIN; + } + + return 0; +} + +/** + * __cam_req_mgr_in_q_skip_idx() + * + * @brief : Decrement val passed by step size and rollover after max_val + * @in_q : input queue pointer + * @idx : Sets skip_idx bit of the particular slot to true so when traverse + * happens for this idx, no req will be submitted for devices + * handling this idx. + * + */ +static void __cam_req_mgr_in_q_skip_idx(struct cam_req_mgr_req_queue *in_q, + int32_t idx) +{ + in_q->slot[idx].req_id = -1; + in_q->slot[idx].skip_idx = 1; + in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; + CAM_DBG(CAM_CRM, "SET IDX SKIP on slot= %d", idx); +} + +/** + * __cam_req_mgr_tbl_set_id() + * + * @brief : Set unique id to table + * @tbl : pipeline based table which requires new id + * @req : pointer to request data wihch contains num_tables counter + * + */ +static void __cam_req_mgr_tbl_set_id(struct cam_req_mgr_req_tbl *tbl, + struct cam_req_mgr_req_data *req) +{ + if (!tbl) + return; + do { + tbl->id = req->num_tbl++; + CAM_DBG(CAM_CRM, "%d: pd %d skip_traverse %d delta %d", + tbl->id, tbl->pd, tbl->skip_traverse, + tbl->pd_delta); + tbl = tbl->next; + } while (tbl != NULL); +} + +/** + * __cam_req_mgr_tbl_set_all_skip_cnt() + * + * @brief : Each pd table sets skip value based on delta between itself and + * max pd value. During initial streamon or bubble case this is + * used. That way each pd table skips required num of traverse and + * align themselve with req mgr connected devs. + * @l_tbl : iterates through list of pd tables and sets skip traverse + * + */ +static void __cam_req_mgr_tbl_set_all_skip_cnt( + struct cam_req_mgr_req_tbl **l_tbl) +{ + struct cam_req_mgr_req_tbl *tbl = *l_tbl; + int32_t max_pd; + + if (!tbl) + return; + + max_pd = tbl->pd; + do { + tbl->skip_traverse = max_pd - tbl->pd; + CAM_DBG(CAM_CRM, "%d: pd %d skip_traverse %d delta %d", + tbl->id, tbl->pd, tbl->skip_traverse, + tbl->pd_delta); + tbl = tbl->next; + } while (tbl != NULL); +} + +/** + * __cam_req_mgr_find_slot_for_req() + * + * @brief : Find idx from input queue at which req id is enqueued + * @in_q : input request queue pointer + * @req_id : request id which needs to be searched in input queue + * + * @return : slot index where passed request id is stored, -1 for failure + * + */ +static int32_t __cam_req_mgr_find_slot_for_req( + struct cam_req_mgr_req_queue *in_q, int64_t req_id) +{ + int32_t idx, i; + struct cam_req_mgr_slot *slot; + + idx = in_q->rd_idx; + for (i = 0; i < in_q->num_slots; i++) { + slot = &in_q->slot[idx]; + if (slot->req_id == req_id) { + CAM_DBG(CAM_CRM, + "req: %lld found at idx: %d status: %d sync_mode: %d", + req_id, idx, slot->status, slot->sync_mode); + break; + } + __cam_req_mgr_dec_idx(&idx, 1, in_q->num_slots); + } + if (i >= in_q->num_slots) + idx = -1; + + return idx; +} + +/** + * __cam_req_mgr_reset_slot_sync_mode() + * + * @brief : reset the sync mode for the given slot + * @link : link pointer + * @req_id : request id + * + */ +static void __cam_req_mgr_reset_slot_sync_mode( + struct cam_req_mgr_core_link *link, + uint64_t req_id) +{ + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + int slot_idx = -1; + + slot_idx = __cam_req_mgr_find_slot_for_req( + in_q, req_id); + + if (slot_idx != -1) { + CAM_DBG(CAM_CRM, + "link %0x req %lld sync mode %d -> %d", + link->link_hdl, + in_q->slot[slot_idx].sync_mode, + CAM_REQ_MGR_SYNC_MODE_NO_SYNC); + in_q->slot[slot_idx].sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + } else { + CAM_WARN(CAM_CRM, + "Can't get slot on link 0x%x for req %lld", + link->link_hdl, req_id); + } +} + + +/** + * __cam_req_mgr_flush_req_slot() + * + * @brief : reset all the slots/pd tables when flush is + * invoked + * @link : link pointer + * + */ +static void __cam_req_mgr_flush_req_slot( + struct cam_req_mgr_core_link *link) +{ + int idx = 0; + struct cam_req_mgr_slot *slot; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + struct cam_req_mgr_core_link *sync_link = link->sync_link; + + for (idx = 0; idx < in_q->num_slots; idx++) { + slot = &in_q->slot[idx]; + tbl = link->req.l_tbl; + CAM_DBG(CAM_CRM, + "RESET idx: %d req_id: %lld slot->status: %d", + idx, slot->req_id, slot->status); + + /* Reset the sync mode of sync link slots */ + if (sync_link && (slot->req_id != -1) && + (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) + __cam_req_mgr_reset_slot_sync_mode( + sync_link, slot->req_id); + + /* Reset input queue slot */ + slot->req_id = -1; + slot->skip_idx = 1; + slot->recover = 0; + slot->additional_timeout = 0; + slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->status = CRM_SLOT_STATUS_NO_REQ; + + /* Reset all pd table slot */ + while (tbl != NULL) { + CAM_DBG(CAM_CRM, "pd: %d: idx %d state %d", + tbl->pd, idx, tbl->slot[idx].state); + tbl->slot[idx].req_ready_map = 0; + tbl->slot[idx].state = CRM_REQ_STATE_EMPTY; + tbl = tbl->next; + } + } + + in_q->wr_idx = 0; + in_q->rd_idx = 0; +} + +/** + * __cam_req_mgr_reset_req_slot() + * + * @brief : reset specified idx/slot in input queue as well as all pd tables + * @link : link pointer + * @idx : slot index which will be reset + * + */ +static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, + int32_t idx) +{ + struct cam_req_mgr_slot *slot; + struct cam_req_mgr_req_tbl *tbl = link->req.l_tbl; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + + slot = &in_q->slot[idx]; + CAM_DBG(CAM_CRM, "RESET: idx: %d: slot->status %d", idx, slot->status); + + /* Check if CSL has already pushed new request*/ + if (slot->status == CRM_SLOT_STATUS_REQ_ADDED || + in_q->last_applied_idx == idx || + idx < 0) + return; + + /* Reset input queue slot */ + slot->req_id = -1; + slot->skip_idx = 0; + slot->recover = 0; + slot->additional_timeout = 0; + slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->status = CRM_SLOT_STATUS_NO_REQ; + + /* Reset all pd table slot */ + while (tbl != NULL) { + CAM_DBG(CAM_CRM, "pd: %d: idx %d state %d", + tbl->pd, idx, tbl->slot[idx].state); + tbl->slot[idx].req_ready_map = 0; + tbl->slot[idx].state = CRM_REQ_STATE_EMPTY; + tbl = tbl->next; + } +} + +/** + * __cam_req_mgr_validate_crm_wd_timer() + * + * @brief : Validate/modify the wd timer based on associated + * timeout with the request + * @link : link pointer + * + */ +static void __cam_req_mgr_validate_crm_wd_timer( + struct cam_req_mgr_core_link *link) +{ + int idx = 0; + int next_frame_timeout = 0, current_frame_timeout = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + + idx = in_q->rd_idx; + __cam_req_mgr_dec_idx( + &idx, (link->max_delay - 1), + in_q->num_slots); + next_frame_timeout = in_q->slot[idx].additional_timeout; + CAM_DBG(CAM_CRM, + "rd_idx: %d idx: %d next_frame_timeout: %d ms", + in_q->rd_idx, idx, next_frame_timeout); + + idx = in_q->rd_idx; + __cam_req_mgr_dec_idx( + &idx, link->max_delay, + in_q->num_slots); + current_frame_timeout = in_q->slot[idx].additional_timeout; + CAM_DBG(CAM_CRM, + "rd_idx: %d idx: %d current_frame_timeout: %d ms", + in_q->rd_idx, idx, current_frame_timeout); + + if ((!current_frame_timeout) && (!next_frame_timeout)) + return; + spin_lock_bh(&link->link_state_spin_lock); + if (link->watchdog) { + if ((next_frame_timeout + CAM_REQ_MGR_WATCHDOG_TIMEOUT) > + link->watchdog->expires) { + CAM_DBG(CAM_CRM, + "Modifying wd timer expiry from %d ms to %d ms", + link->watchdog->expires, + (next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + next_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (current_frame_timeout) { + CAM_DBG(CAM_CRM, + "Reset wd timer to frame from %d ms to %d ms", + link->watchdog->expires, + (current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT)); + crm_timer_modify(link->watchdog, + current_frame_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } else if (link->watchdog->expires > + CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + CAM_DBG(CAM_CRM, + "Reset wd timer to default from %d ms to %d ms", + link->watchdog->expires, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + crm_timer_modify(link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT); + } + } else { + CAM_WARN(CAM_CRM, "Watchdog timer exited already"); + } + spin_unlock_bh(&link->link_state_spin_lock); +} + +/** + * __cam_req_mgr_check_for_lower_pd_devices() + * + * @brief : Checks if there are any devices on the link having a lesser + * pd than the max pd of the link + * @link : Pointer to link which needs to be checked + * + * @return : 0 if a lower pd device is found negative otherwise + */ +static int __cam_req_mgr_check_for_lower_pd_devices( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev->dev_info.p_delay < link->max_delay) + return 0; + } + + return -EAGAIN; +} + +/** + * __cam_req_mgr_check_next_req_slot() + * + * @brief : While streaming if input queue does not contain any pending + * request, req mgr still needs to submit pending request ids to + * devices with lower pipeline delay value. + * @in_q : Pointer to input queue where req mgr wil peep into + * + * @return : 0 for success, negative for failure + */ +static int __cam_req_mgr_check_next_req_slot( + struct cam_req_mgr_core_link *link) +{ + int rc = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + int32_t idx = in_q->rd_idx; + struct cam_req_mgr_slot *slot; + + __cam_req_mgr_inc_idx(&idx, 1, in_q->num_slots); + slot = &in_q->slot[idx]; + + CAM_DBG(CAM_CRM, "idx: %d: slot->status %d", idx, slot->status); + + /* Check if there is new req from CSL, if not complete req */ + if (slot->status == CRM_SLOT_STATUS_NO_REQ) { + rc = __cam_req_mgr_check_for_lower_pd_devices(link); + if (rc) { + CAM_DBG(CAM_CRM, "No lower pd devices on link 0x%x", + link->link_hdl); + return rc; + } + __cam_req_mgr_in_q_skip_idx(in_q, idx); + if (in_q->wr_idx != idx) + CAM_WARN(CAM_CRM, + "CHECK here wr %d, rd %d", in_q->wr_idx, idx); + __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + } + + return rc; +} + +/** + * __cam_req_mgr_send_req() + * + * @brief : send request id to be applied to each device connected on link + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @in_q : pointer to input request queue + * + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_req_queue *in_q, uint32_t trigger, + struct cam_req_mgr_connected_device **failed_dev) +{ + int rc = 0, pd, i, idx; + struct cam_req_mgr_connected_device *dev = NULL; + struct cam_req_mgr_apply_request apply_req; + struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_tbl_slot *slot = NULL; + + apply_req.link_hdl = link->link_hdl; + apply_req.report_if_bubble = 0; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (!dev) + continue; + pd = dev->dev_info.p_delay; + if (pd >= CAM_PIPELINE_DELAY_MAX) { + CAM_WARN(CAM_CRM, "pd %d greater than max", + pd); + continue; + } + + idx = link->req.apply_data[pd].idx; + slot = &dev->pd_tbl->slot[idx]; + /* + * Just let flash go for this request and other + * device get restricted + */ + + if ((slot->skip_next_frame != true) || + (slot->dev_hdl != dev->dev_hdl)) + continue; + + if (!(dev->dev_info.trigger & trigger)) + continue; + + apply_req.dev_hdl = dev->dev_hdl; + apply_req.request_id = + link->req.apply_data[pd].req_id; + apply_req.trigger_point = trigger; + if (dev->ops && dev->ops->apply_req) { + rc = dev->ops->apply_req(&apply_req); + if (rc) + return rc; + CAM_DBG(CAM_REQ, + "SEND: link_hdl: %x pd: %d req_id %lld", + link->link_hdl, pd, apply_req.request_id); + slot->skip_next_frame = false; + slot->is_applied = true; + return -EAGAIN; + } + } + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev) { + pd = dev->dev_info.p_delay; + if (pd >= CAM_PIPELINE_DELAY_MAX) { + CAM_WARN(CAM_CRM, "pd %d greater than max", + pd); + continue; + } + if (link->req.apply_data[pd].skip_idx || + link->req.apply_data[pd].req_id < 0) { + CAM_DBG(CAM_CRM, "skip %d req_id %lld", + link->req.apply_data[pd].skip_idx, + link->req.apply_data[pd].req_id); + continue; + } + if (!(dev->dev_info.trigger & trigger)) + continue; + + apply_req.dev_hdl = dev->dev_hdl; + apply_req.request_id = + link->req.apply_data[pd].req_id; + idx = link->req.apply_data[pd].idx; + slot = &dev->pd_tbl->slot[idx]; + apply_req.report_if_bubble = + in_q->slot[idx].recover; + + if ((slot->dev_hdl == dev->dev_hdl) && + (slot->is_applied == true)) { + slot->is_applied = false; + continue; + } + + apply_req.trigger_point = trigger; + CAM_DBG(CAM_REQ, + "SEND: link_hdl: %x pd %d req_id %lld", + link->link_hdl, pd, apply_req.request_id); + if (dev->ops && dev->ops->apply_req) { + rc = dev->ops->apply_req(&apply_req); + if (rc < 0) { + *failed_dev = dev; + break; + } + } + trace_cam_req_mgr_apply_request(link, &apply_req, dev); + } + } + if (rc < 0) { + CAM_WARN_RATE_LIMIT(CAM_CRM, "APPLY FAILED pd %d req_id %lld", + dev->dev_info.p_delay, apply_req.request_id); + /* Apply req failed notify already applied devs */ + for (; i >= 0; i--) { + dev = &link->l_dev[i]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = apply_req.request_id; + evt_data.u.error = CRM_KMD_ERR_BUBBLE; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } + } + return rc; +} + +/** + * __cam_req_mgr_check_link_is_ready() + * + * @brief : traverse through all request tables and see if all devices are + * ready to apply request settings. + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @idx : index within input request queue + * @validate_only : Whether to validate only and/or update settings + * + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, + int32_t idx, bool validate_only) +{ + int rc; + struct cam_req_mgr_traverse traverse_data; + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_apply *apply_data; + + in_q = link->req.in_q; + + apply_data = link->req.apply_data; + + if (validate_only == false) { + memset(apply_data, 0, + sizeof(struct cam_req_mgr_apply) * CAM_PIPELINE_DELAY_MAX); + } + + traverse_data.apply_data = apply_data; + traverse_data.idx = idx; + traverse_data.tbl = link->req.l_tbl; + traverse_data.in_q = in_q; + traverse_data.result = 0; + traverse_data.result_data.masked_value = 0; + traverse_data.result_data.pd = 0; + traverse_data.result_data.req_id = 0; + traverse_data.validate_only = validate_only; + traverse_data.open_req_cnt = link->open_req_cnt; + + /* + * Some no-sync mode requests are processed after link config, + * then process the sync mode requests after no-sync mode requests + * are handled, the initial_skip should be false when processing + * the sync mode requests. + */ + if (link->initial_skip) { + CAM_DBG(CAM_CRM, + "Set initial_skip to false for link %x", + link->link_hdl); + link->initial_skip = false; + } + + /* + * Traverse through all pd tables, if result is success, + * apply the settings + */ + rc = __cam_req_mgr_traverse(&traverse_data); + CAM_DBG(CAM_CRM, + "SOF: idx %d result %x pd_mask %x rc %d", + idx, traverse_data.result, link->pd_mask, rc); + + if (!rc && traverse_data.result == link->pd_mask) { + CAM_DBG(CAM_CRM, + "READY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld", + link->link_hdl, idx, + apply_data[2].req_id, + apply_data[1].req_id, + apply_data[0].req_id); + } else { + rc = -EAGAIN; + __cam_req_mgr_find_dev_name(link, + traverse_data.result_data.req_id, + traverse_data.result_data.pd, + traverse_data.result_data.masked_value); + } + + return rc; +} + +/** + * __cam_req_mgr_check_sync_for_mslave() + * + * @brief : Processes requests during sync mode [master-slave] + * Here master corresponds to the link having a higher + * max_delay (pd) compared to the slave link. + * @link : Pointer to link whose input queue and req tbl are + * traversed through + * @slot : Pointer to the current slot being processed + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_check_sync_for_mslave( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) +{ + struct cam_req_mgr_core_link *sync_link = NULL; + struct cam_req_mgr_slot *sync_slot = NULL; + int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; + int64_t req_id = 0, sync_req_id = 0; + int32_t sync_num_slots = 0; + + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } + + sync_link = link->sync_link; + req_id = slot->req_id; + sync_num_slots = sync_link->req.in_q->num_slots; + sync_rd_idx = sync_link->req.in_q->rd_idx; + + CAM_DBG(CAM_CRM, + "link_hdl %x req %lld frame_skip_flag %d open_req_cnt:%d initial_sync_req [%lld,%lld] is_master:%d", + link->link_hdl, req_id, link->sync_link_sof_skip, + link->open_req_cnt, link->initial_sync_req, + sync_link->initial_sync_req, link->is_master); + + if (sync_link->sync_link_sof_skip) { + CAM_DBG(CAM_CRM, + "No req applied on corresponding SOF on sync link: %x", + sync_link->link_hdl); + sync_link->sync_link_sof_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; + } + + if (link->in_msync_mode && + sync_link->in_msync_mode && + (req_id - sync_link->req.in_q->slot[sync_rd_idx].req_id > + link->max_delay - sync_link->max_delay)) { + CAM_DBG(CAM_CRM, + "Req: %lld on link:%x need to hold for link: %x req:%d", + req_id, + link->link_hdl, + sync_link->link_hdl, + sync_link->req.in_q->slot[sync_rd_idx].req_id); + return -EINVAL; + } + + if (link->is_master) { + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + if (sync_link->initial_skip) { + CAM_DBG(CAM_CRM, "Link 0x%x [slave] not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [master] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + + prev_idx = slot->idx; + __cam_req_mgr_dec_idx(&prev_idx, + (link->max_delay - sync_link->max_delay), + link->req.in_q->num_slots); + + rd_idx = sync_link->req.in_q->rd_idx; + sync_req_id = link->req.in_q->slot[prev_idx].req_id; + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not found on link: %x [slave]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + (((sync_slot_idx - rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not next on link: %x [slave]", + sync_req_id, + sync_link->link_hdl); + return -EINVAL; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && + (sync_link->req.in_q->slot[sync_slot_idx].status + != CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [slave] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } + } else { + if (link->initial_skip) + link->initial_skip = false; + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [slave] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + + next_idx = link->req.in_q->rd_idx; + rd_idx = sync_link->req.in_q->rd_idx; + __cam_req_mgr_inc_idx(&next_idx, + (sync_link->max_delay - link->max_delay), + link->req.in_q->num_slots); + + sync_req_id = link->req.in_q->slot[next_idx].req_id; + + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not found on link: %x [master]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + (((sync_slot_idx - rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not next on link: %x [master]", + sync_req_id, sync_link->link_hdl); + return -EINVAL; + } + + sync_slot = &sync_link->req.in_q->slot[sync_slot_idx]; + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && (sync_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not ready on [master] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } + } + + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); + + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; +} + + +/** + * __cam_req_mgr_check_sync_request_is_ready() + * + * @brief : processes requests during sync mode + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @slot : pointer to the current slot being processed + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_check_sync_req_is_ready( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) +{ + struct cam_req_mgr_core_link *sync_link = NULL; + struct cam_req_mgr_slot *sync_rd_slot = NULL; + int64_t req_id = 0, sync_req_id = 0; + int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; + int32_t sync_num_slots = 0; + uint64_t sync_frame_duration = 0; + bool ready = true, sync_ready = true; + + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } + + sync_link = link->sync_link; + req_id = slot->req_id; + sync_num_slots = sync_link->req.in_q->num_slots; + sync_rd_idx = sync_link->req.in_q->rd_idx; + sync_rd_slot = &sync_link->req.in_q->slot[sync_rd_idx]; + sync_req_id = sync_rd_slot->req_id; + + CAM_DBG(CAM_REQ, + "link_hdl %x req %lld frame_skip_flag %d ", + link->link_hdl, req_id, link->sync_link_sof_skip); + + if (sync_link->initial_skip) { + link->initial_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "sync link %x not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } + + if (sync_link->prev_sof_timestamp) + sync_frame_duration = sync_link->sof_timestamp - + sync_link->prev_sof_timestamp; + else + sync_frame_duration = DEFAULT_FRAME_DURATION; + + CAM_DBG(CAM_CRM, + "sync link %x last frame_duration is %d ns", + sync_link->link_hdl, sync_frame_duration); + + if (link->initial_skip) { + link->initial_skip = false; + + if ((link->sof_timestamp > sync_link->sof_timestamp) && + (sync_link->sof_timestamp > 0) && + (link->sof_timestamp - sync_link->sof_timestamp) < + (sync_frame_duration / 2)) { + /* + * If this frame sync with the previous frame of sync + * link, then we need to skip this frame, since the + * previous frame of sync link is also skipped. + */ + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "This frame sync with previous sync_link %x frame", + sync_link->link_hdl); + return -EAGAIN; + } else if (link->sof_timestamp <= sync_link->sof_timestamp) { + /* + * Sometimes, link receives the SOF event is eariler + * than sync link in IFE CSID side, but link's SOF + * event is processed later than sync link's, then + * we need to skip this SOF event since the sync + * link's SOF event is also skipped. + */ + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + CAM_DBG(CAM_CRM, + "The previous frame of sync link is skipped"); + return -EAGAIN; + } + } + + if (sync_link->sync_link_sof_skip) { + CAM_DBG(CAM_REQ, + "No req applied on corresponding SOF on sync link: %x", + sync_link->link_hdl); + sync_link->sync_link_sof_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; + } + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + ready = false; + } + + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, req_id); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", + req_id, sync_link->link_hdl); + sync_ready = false; + return -EAGAIN; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + (((sync_slot_idx - sync_rd_idx + sync_num_slots) % + sync_num_slots) >= 1) && + (sync_rd_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld [other link] not next req to be applied on link: %x", + req_id, sync_link->link_hdl); + return -EAGAIN; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [My link] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + ready = false; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); + if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [other link] link: %x, rc=%d", + req_id, sync_link->link_hdl, rc); + sync_ready = false; + } + + /* + * If both of them are ready or not ready, then just + * skip this sof and don't skip sync link next SOF. + */ + if (sync_ready != ready) { + CAM_DBG(CAM_CRM, + "Req: %lld ready %d sync_ready %d, ignore sync link next SOF", + req_id, ready, sync_ready); + + /* + * Only skip the frames if current frame sync with + * next frame of sync link. + */ + if (link->sof_timestamp - sync_link->sof_timestamp > + sync_frame_duration / 2) + link->sync_link_sof_skip = true; + return -EINVAL; + } else if (ready == false) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on link: %x", + req_id, link->link_hdl); + return -EINVAL; + } + + /* + * Do the self-correction when the frames are sync, + * we consider that the frames are synced if the + * difference of two SOF timestamp less than + * (sync_frame_duration / 5). + */ + do_div(sync_frame_duration, 5); + if ((link->sof_timestamp > sync_link->sof_timestamp) && + (sync_link->sof_timestamp > 0) && + (link->sof_timestamp - sync_link->sof_timestamp < + sync_frame_duration) && + (sync_rd_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) { + + /* + * This means current frame should sync with next + * frame of sync link, then the request id of in + * rd slot of two links should be same. + */ + CAM_DBG(CAM_CRM, + "link %x req_id %lld, sync_link %x req_id %lld", + link->link_hdl, req_id, + sync_link->link_hdl, sync_req_id); + + if (req_id > sync_req_id) { + CAM_DBG(CAM_CRM, + "link %x too quickly, skip this frame", + link->link_hdl); + return -EAGAIN; + } else if (req_id < sync_req_id) { + CAM_DBG(CAM_CRM, + "sync link %x too quickly, skip next frame of sync link", + sync_link->link_hdl); + link->sync_link_sof_skip = true; + } + } + + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); + + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; +} + +/** + * __cam_req_mgr_process_req() + * + * @brief : processes read index in request queue and traverse through table + * @link : pointer to link whose input queue and req tbl are + * traversed through + * + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_trigger_notify *trigger_data) +{ + int rc = 0, idx; + int reset_step = 0; + uint32_t trigger = trigger_data->trigger; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_core_session *session; + struct cam_req_mgr_connected_device *dev; + + in_q = link->req.in_q; + session = (struct cam_req_mgr_core_session *)link->parent; + mutex_lock(&session->lock); + /* + * Check if new read index, + * - if in pending state, traverse again to complete + * transaction of this read index. + * - if in applied_state, somthign wrong. + * - if in no_req state, no new req + */ + CAM_DBG(CAM_REQ, + "SOF Req[%lld] idx %d req_status %d link_hdl %x wd_timeout %d ms", + in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, + in_q->slot[in_q->rd_idx].status, link->link_hdl, + in_q->slot[in_q->rd_idx].additional_timeout); + + slot = &in_q->slot[in_q->rd_idx]; + if (slot->status == CRM_SLOT_STATUS_NO_REQ) { + CAM_DBG(CAM_CRM, "No Pending req"); + rc = 0; + goto error; + } + + if ((trigger != CAM_TRIGGER_POINT_SOF) && + (trigger != CAM_TRIGGER_POINT_EOF)) + goto error; + + if ((trigger == CAM_TRIGGER_POINT_EOF) && + (!(link->trigger_mask & CAM_TRIGGER_POINT_SOF))) { + CAM_DBG(CAM_CRM, "Applying for last SOF fails"); + rc = -EINVAL; + goto error; + } + + if (trigger == CAM_TRIGGER_POINT_SOF) { + /* + * Update the timestamp in session lock protection + * to avoid timing issue. + */ + link->prev_sof_timestamp = link->sof_timestamp; + link->sof_timestamp = trigger_data->sof_timestamp_val; + + if (link->trigger_mask) { + CAM_ERR_RATE_LIMIT(CAM_CRM, + "Applying for last EOF fails"); + rc = -EINVAL; + goto error; + } + + if ((slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) && + (link->sync_link)) { + if (link->is_master || link->sync_link->is_master) { + if (!link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = true; + } + + rc = __cam_req_mgr_check_sync_for_mslave( + link, slot); + } else { + rc = __cam_req_mgr_check_sync_req_is_ready( + link, slot); + } + } else { + if (link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave non sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = false; + link->initial_sync_req = -1; + if (link->sync_link) { + link->sync_link->initial_sync_req = -1; + link->sync_link->in_msync_mode = false; + } + } + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, + slot->idx); + if (!rc) + rc = __cam_req_mgr_check_link_is_ready(link, + slot->idx, false); + } + + if (rc < 0) { + /* + * If traverse result is not success, then some devices + * are not ready with packet for the asked request id, + * hence try again in next sof + */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + spin_lock_bh(&link->link_state_spin_lock); + if (link->state == CAM_CRM_LINK_STATE_ERR) { + /* + * During error recovery all tables should be + * ready, don't expect to enter here. + * @TODO: gracefully handle if recovery fails. + */ + CAM_ERR_RATE_LIMIT(CAM_CRM, + "FATAL recovery cant finish idx %d status %d", + in_q->rd_idx, + in_q->slot[in_q->rd_idx].status); + rc = -EPERM; + } + spin_unlock_bh(&link->link_state_spin_lock); + goto error; + } + } + + rc = __cam_req_mgr_send_req(link, link->req.in_q, trigger, &dev); + if (rc < 0) { + /* Apply req failed retry at next sof */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + + link->retry_cnt++; + if (link->retry_cnt == MAXIMUM_RETRY_ATTEMPTS) { + CAM_DBG(CAM_CRM, + "Max retry attempts reached on link[0x%x] for req [%lld]", + link->link_hdl, + in_q->slot[in_q->rd_idx].req_id); + __cam_req_mgr_notify_error_on_link(link, dev); + link->retry_cnt = 0; + } + } else { + if (link->retry_cnt) + link->retry_cnt = 0; + + link->trigger_mask |= trigger; + + /* Check for any long exposure settings */ + __cam_req_mgr_validate_crm_wd_timer(link); + + CAM_DBG(CAM_CRM, "Applied req[%lld] on link[%x] success", + slot->req_id, link->link_hdl); + spin_lock_bh(&link->link_state_spin_lock); + if (link->state == CAM_CRM_LINK_STATE_ERR) { + CAM_WARN(CAM_CRM, "Err recovery done idx %d", + in_q->rd_idx); + link->state = CAM_CRM_LINK_STATE_READY; + } + spin_unlock_bh(&link->link_state_spin_lock); + + if (link->sync_link_sof_skip) + link->sync_link_sof_skip = false; + + if (link->trigger_mask == link->subscribe_event) { + slot->status = CRM_SLOT_STATUS_REQ_APPLIED; + link->trigger_mask = 0; + CAM_DBG(CAM_CRM, "req %d is applied on link %x", + slot->req_id, + link->link_hdl); + idx = in_q->rd_idx; + reset_step = link->max_delay; + if (link->sync_link) { + if ((link->in_msync_mode) && + (link->sync_link->is_master)) + reset_step = + link->sync_link->max_delay; + } + + if (slot->req_id > 0) + in_q->last_applied_idx = idx; + + __cam_req_mgr_dec_idx( + &idx, reset_step + 1, + in_q->num_slots); + __cam_req_mgr_reset_req_slot(link, idx); + link->open_req_cnt--; + } + } + + mutex_unlock(&session->lock); + return rc; +error: + mutex_unlock(&session->lock); + return rc; +} + +/** + * __cam_req_mgr_add_tbl_to_link() + * + * @brief : Add table to list under link sorted by pd decremeting order + * @l_tbl : list of pipeline delay tables. + * @new_tbl : new tbl which will be appended to above list as per its pd value + * + */ +static void __cam_req_mgr_add_tbl_to_link(struct cam_req_mgr_req_tbl **l_tbl, + struct cam_req_mgr_req_tbl *new_tbl) +{ + struct cam_req_mgr_req_tbl *tbl; + + if (!(*l_tbl) || (*l_tbl)->pd < new_tbl->pd) { + new_tbl->next = *l_tbl; + if (*l_tbl) { + new_tbl->pd_delta = + new_tbl->pd - (*l_tbl)->pd; + } + *l_tbl = new_tbl; + } else { + tbl = *l_tbl; + + /* Reach existing tbl which has less pd value */ + while (tbl->next != NULL && + new_tbl->pd < tbl->next->pd) { + tbl = tbl->next; + } + if (tbl->next != NULL) { + new_tbl->pd_delta = + new_tbl->pd - tbl->next->pd; + } else { + /* This is last table in linked list*/ + new_tbl->pd_delta = 0; + } + new_tbl->next = tbl->next; + tbl->next = new_tbl; + tbl->pd_delta = tbl->pd - new_tbl->pd; + } + CAM_DBG(CAM_CRM, "added pd %d tbl to link delta %d", new_tbl->pd, + new_tbl->pd_delta); +} + +/** + * __cam_req_mgr_create_pd_tbl() + * + * @brief : Creates new request table for new delay value + * @delay : New pd table allocated will have this delay value + * + * @return : pointer to newly allocated table, NULL for failure + * + */ +static struct cam_req_mgr_req_tbl *__cam_req_mgr_create_pd_tbl(int32_t delay) +{ + struct cam_req_mgr_req_tbl *tbl = + kzalloc(sizeof(struct cam_req_mgr_req_tbl), GFP_KERNEL); + if (tbl != NULL) { + tbl->num_slots = MAX_REQ_SLOTS; + CAM_DBG(CAM_CRM, "pd= %d slots= %d", delay, tbl->num_slots); + } + + return tbl; +} + +/** + * __cam_req_mgr_destroy_all_tbl() + * + * @brief : This func will destroy all pipeline delay based req table structs + * @l_tbl : pointer to first table in list and it has max pd . + * + */ +static void __cam_req_mgr_destroy_all_tbl(struct cam_req_mgr_req_tbl **l_tbl) +{ + struct cam_req_mgr_req_tbl *tbl = *l_tbl, *temp; + + CAM_DBG(CAM_CRM, "*l_tbl %pK", tbl); + while (tbl != NULL) { + temp = tbl->next; + kfree(tbl); + tbl = temp; + } + *l_tbl = NULL; +} + +/** + * __cam_req_mgr_setup_in_q() + * + * @brief : Initialize req table data + * @req : request data pointer + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_setup_in_q(struct cam_req_mgr_req_data *req) +{ + int i; + struct cam_req_mgr_req_queue *in_q = req->in_q; + + if (!in_q) { + CAM_ERR(CAM_CRM, "NULL in_q"); + return -EINVAL; + } + + mutex_lock(&req->lock); + in_q->num_slots = MAX_REQ_SLOTS; + + for (i = 0; i < in_q->num_slots; i++) { + in_q->slot[i].idx = i; + in_q->slot[i].req_id = -1; + in_q->slot[i].skip_idx = 0; + in_q->slot[i].status = CRM_SLOT_STATUS_NO_REQ; + } + + in_q->wr_idx = 0; + in_q->rd_idx = 0; + mutex_unlock(&req->lock); + + return 0; +} + +/** + * __cam_req_mgr_reset_req_tbl() + * + * @brief : Initialize req table data + * @req : request queue pointer + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_reset_in_q(struct cam_req_mgr_req_data *req) +{ + struct cam_req_mgr_req_queue *in_q = req->in_q; + + if (!in_q) { + CAM_ERR(CAM_CRM, "NULL in_q"); + return -EINVAL; + } + + mutex_lock(&req->lock); + memset(in_q->slot, 0, + sizeof(struct cam_req_mgr_slot) * in_q->num_slots); + in_q->num_slots = 0; + + in_q->wr_idx = 0; + in_q->rd_idx = 0; + mutex_unlock(&req->lock); + + return 0; +} + +/** + * __cam_req_mgr_notify_sof_freeze() + * + * @brief : Notify devices on link on detecting a SOF freeze + * @link : link on which the sof freeze was detected + * + */ +static void __cam_req_mgr_notify_sof_freeze( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_SOF_FREEZE; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = 0; + evt_data.u.error = CRM_KMD_ERR_FATAL; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } +} + +/** + * __cam_req_mgr_process_sof_freeze() + * + * @brief : Apoptosis - Handles case when connected devices are not responding + * @priv : link information + * @data : task data + * + */ +static int __cam_req_mgr_process_sof_freeze(void *priv, void *data) +{ + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_message msg; + int rc = 0; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + return -EINVAL; + } + + link = (struct cam_req_mgr_core_link *)priv; + session = (struct cam_req_mgr_core_session *)link->parent; + + spin_lock_bh(&link->link_state_spin_lock); + if ((link->watchdog) && (link->watchdog->pause_timer)) { + CAM_INFO(CAM_CRM, "Watchdog Paused"); + spin_unlock_bh(&link->link_state_spin_lock); + return rc; + } + spin_unlock_bh(&link->link_state_spin_lock); + + CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", + session->session_hdl, link->link_hdl); + + __cam_req_mgr_notify_sof_freeze(link); + memset(&msg, 0, sizeof(msg)); + + msg.session_hdl = session->session_hdl; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE; + msg.u.err_msg.request_id = 0; + msg.u.err_msg.link_hdl = link->link_hdl; + + rc = cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT); + + if (rc) + CAM_ERR(CAM_CRM, + "Error notifying SOF freeze for session %d link 0x%x rc %d", + session->session_hdl, link->link_hdl, rc); + + return rc; +} + +/** + * __cam_req_mgr_sof_freeze() + * + * @brief : Callback function for timer timeout indicating SOF freeze + * @data : timer pointer + * + */ +static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) +{ + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct crm_task_payload *task_data; + + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + + link = (struct cam_req_mgr_core_link *)timer->parent; + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "No empty task"); + return; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_FREEZE; + task->process_cb = &__cam_req_mgr_process_sof_freeze; + cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); +} + +/** + * __cam_req_mgr_create_subdevs() + * + * @brief : Create new crm subdev to link with realtime devices + * @l_dev : list of subdevs internal to crm + * @num_dev : num of subdevs to be created for link + * + * @return : pointer to allocated list of devices + */ +static int __cam_req_mgr_create_subdevs( + struct cam_req_mgr_connected_device **l_dev, int32_t num_dev) +{ + int rc = 0; + *l_dev = kzalloc(sizeof(struct cam_req_mgr_connected_device) * + num_dev, GFP_KERNEL); + if (!*l_dev) + rc = -ENOMEM; + + return rc; +} + +/** + * __cam_req_mgr_destroy_subdev() + * + * @brief : Cleans up the subdevs allocated by crm for link + * @l_device : pointer to list of subdevs crm created + * + */ +static void __cam_req_mgr_destroy_subdev( + struct cam_req_mgr_connected_device *l_device) +{ + kfree(l_device); + l_device = NULL; +} + +/** + * __cam_req_mgr_destroy_link_info() + * + * @brief : Unlinks all devices on the link + * @link : pointer to link + * + * @return : returns if unlink for any device was success or failure + */ +static int __cam_req_mgr_disconnect_link(struct cam_req_mgr_core_link *link) +{ + int32_t i = 0; + struct cam_req_mgr_connected_device *dev; + struct cam_req_mgr_core_dev_link_setup link_data; + int rc = 0; + + link_data.link_enable = 0; + link_data.link_hdl = link->link_hdl; + link_data.crm_cb = NULL; + link_data.subscribe_event = 0; + + /* Using device ops unlink devices */ + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev == NULL) + continue; + + link_data.dev_hdl = dev->dev_hdl; + if (dev->ops && dev->ops->link_setup) { + rc = dev->ops->link_setup(&link_data); + if (rc) + CAM_ERR(CAM_CRM, + "Unlink failed dev name %s hdl %x", + dev->dev_info.name, + dev->dev_hdl); + } + dev->dev_hdl = 0; + dev->parent = NULL; + dev->ops = NULL; + } + + return rc; +} + +/** + * __cam_req_mgr_destroy_link_info() + * + * @brief : Cleans up the mem allocated while linking + * @link : pointer to link, mem associated with this link is freed + */ +static void __cam_req_mgr_destroy_link_info(struct cam_req_mgr_core_link *link) +{ + __cam_req_mgr_destroy_all_tbl(&link->req.l_tbl); + __cam_req_mgr_reset_in_q(&link->req); + link->req.num_tbl = 0; + mutex_destroy(&link->req.lock); + + link->pd_mask = 0; + link->num_devs = 0; + link->max_delay = 0; +} + +/** + * __cam_req_mgr_reserve_link() + * + * @brief: Reserves one link data struct within session + * @session: session identifier + * + * @return: pointer to link reserved + * + */ +static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link( + struct cam_req_mgr_core_session *session) +{ + struct cam_req_mgr_core_link *link; + struct cam_req_mgr_req_queue *in_q; + int i; + + if (!session || !g_crm_core_dev) { + CAM_ERR(CAM_CRM, "NULL session/core_dev ptr"); + return NULL; + } + + if (session->num_links >= MAXIMUM_LINKS_PER_SESSION) { + CAM_ERR(CAM_CRM, "Reached max links %d per session limit %d", + session->num_links, MAXIMUM_LINKS_PER_SESSION); + return NULL; + } + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (!atomic_cmpxchg(&g_links[i].is_used, 0, 1)) { + link = &g_links[i]; + CAM_DBG(CAM_CRM, "alloc link index %d", i); + cam_req_mgr_core_link_reset(link); + break; + } + } + if (i == MAXIMUM_LINKS_PER_SESSION) + return NULL; + + in_q = kzalloc(sizeof(struct cam_req_mgr_req_queue), + GFP_KERNEL); + if (!in_q) { + CAM_ERR(CAM_CRM, "failed to create input queue, no mem"); + return NULL; + } + + mutex_lock(&link->lock); + link->num_devs = 0; + link->max_delay = 0; + memset(in_q->slot, 0, + sizeof(struct cam_req_mgr_slot) * MAX_REQ_SLOTS); + link->req.in_q = in_q; + in_q->num_slots = 0; + link->state = CAM_CRM_LINK_STATE_IDLE; + link->parent = (void *)session; + link->sync_link = NULL; + mutex_unlock(&link->lock); + + mutex_lock(&session->lock); + /* Loop through and find a free index */ + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (!session->links[i]) { + CAM_DBG(CAM_CRM, + "Free link index %d found, num_links=%d", + i, session->num_links); + session->links[i] = link; + break; + } + } + + if (i == MAXIMUM_LINKS_PER_SESSION) { + CAM_ERR(CAM_CRM, "Free link index not found"); + goto error; + } + + session->num_links++; + CAM_DBG(CAM_CRM, "Active session links (%d)", + session->num_links); + mutex_unlock(&session->lock); + + return link; +error: + mutex_unlock(&session->lock); + kfree(in_q); + return NULL; +} + +/* + * __cam_req_mgr_free_link() + * + * @brief: Frees the link and its request queue + * + * @link: link identifier + * + */ +static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link) +{ + ptrdiff_t i; + kfree(link->req.in_q); + link->req.in_q = NULL; + i = link - g_links; + CAM_DBG(CAM_CRM, "free link index %d", i); + cam_req_mgr_core_link_reset(link); + atomic_set(&g_links[i].is_used, 0); +} + +/** + * __cam_req_mgr_unreserve_link() + * + * @brief : Removes the link data struct from the session and frees it + * @session: session identifier + * @link : link identifier + * + */ +static void __cam_req_mgr_unreserve_link( + struct cam_req_mgr_core_session *session, + struct cam_req_mgr_core_link *link) +{ + int i; + + if (!session || !link) { + CAM_ERR(CAM_CRM, "NULL session/link ptr %pK %pK", + session, link); + return; + } + + mutex_lock(&session->lock); + if (!session->num_links) { + CAM_WARN(CAM_CRM, "No active link or invalid state: hdl %x", + link->link_hdl); + mutex_unlock(&session->lock); + return; + } + + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (session->links[i] == link) + session->links[i] = NULL; + + if (link->sync_link) { + if (link->sync_link == session->links[i]) + session->links[i]->sync_link = NULL; + } + } + + link->sync_link = NULL; + session->num_links--; + CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links); + mutex_unlock(&session->lock); + __cam_req_mgr_free_link(link); +} + +/* Workqueue context processing section */ + +/** + * cam_req_mgr_process_send_req() + * + * @brief: This runs in workque thread context. Call core funcs to send + * apply request id to drivers. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_send_req(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_send_request *send_req = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_connected_device *dev; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + send_req = (struct cam_req_mgr_send_request *)data; + in_q = send_req->in_q; + + rc = __cam_req_mgr_send_req(link, in_q, CAM_TRIGGER_POINT_SOF, &dev); +end: + return rc; +} + +/** + * cam_req_mgr_process_flush_req() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which requests need to be removed/cancelled. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_flush_req(void *priv, void *data) +{ + int rc = 0, i = 0, idx = -1; + struct cam_req_mgr_flush_info *flush_info = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_connected_device *device = NULL; + struct cam_req_mgr_flush_request flush_req; + struct crm_task_payload *task_data = NULL; + struct cam_req_mgr_core_link *sync_link = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + sync_link = link->sync_link; + task_data = (struct crm_task_payload *)data; + flush_info = (struct cam_req_mgr_flush_info *)&task_data->u; + CAM_DBG(CAM_REQ, "link_hdl %x req_id %lld type %d", + flush_info->link_hdl, + flush_info->req_id, + flush_info->flush_type); + + in_q = link->req.in_q; + + trace_cam_flush_req(link, flush_info); + + mutex_lock(&link->req.lock); + if (flush_info->flush_type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + link->last_flush_id = flush_info->req_id; + CAM_INFO(CAM_CRM, "Last request id to flush is %lld", + flush_info->req_id); + __cam_req_mgr_flush_req_slot(link); + } else if (flush_info->flush_type == + CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + idx = __cam_req_mgr_find_slot_for_req(in_q, flush_info->req_id); + if (idx < 0) { + CAM_ERR(CAM_CRM, "req_id %lld not found in input queue", + flush_info->req_id); + } else { + CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", + flush_info->req_id, idx); + slot = &in_q->slot[idx]; + if (slot->status == CRM_SLOT_STATUS_REQ_PENDING || + slot->status == CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_WARN(CAM_CRM, + "req_id %lld can not be cancelled", + flush_info->req_id); + mutex_unlock(&link->req.lock); + return -EINVAL; + } + slot->additional_timeout = 0; + __cam_req_mgr_in_q_skip_idx(in_q, idx); + + /* Reset the sync mode of sync link slots */ + if (sync_link && (slot->req_id != -1) && + (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC)) + __cam_req_mgr_reset_slot_sync_mode( + sync_link, slot->req_id); + } + } + + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + flush_req.link_hdl = flush_info->link_hdl; + flush_req.dev_hdl = device->dev_hdl; + flush_req.req_id = flush_info->req_id; + flush_req.type = flush_info->flush_type; + /* @TODO: error return handling from drivers */ + if (device->ops && device->ops->flush_req) + rc = device->ops->flush_req(&flush_req); + } + complete(&link->workq_comp); + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_sched_req() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which peding requests can be processed. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_sched_req(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_sched_request *sched_req = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + sched_req = (struct cam_req_mgr_sched_request *)&task_data->u; + in_q = link->req.in_q; + + CAM_DBG(CAM_CRM, + "link_hdl %x req_id %lld at slot %d sync_mode %d is_master %d exp_timeout_val %d ms", + sched_req->link_hdl, sched_req->req_id, + in_q->wr_idx, sched_req->sync_mode, + link->is_master, + sched_req->additional_timeout); + + mutex_lock(&link->req.lock); + slot = &in_q->slot[in_q->wr_idx]; + + if (slot->status != CRM_SLOT_STATUS_NO_REQ && + slot->status != CRM_SLOT_STATUS_REQ_APPLIED) + CAM_WARN(CAM_CRM, "in_q overwrite %d", slot->status); + + slot->status = CRM_SLOT_STATUS_REQ_ADDED; + slot->req_id = sched_req->req_id; + slot->sync_mode = sched_req->sync_mode; + slot->skip_idx = 0; + slot->recover = sched_req->bubble_enable; + if (sched_req->additional_timeout < 0) { + CAM_WARN(CAM_CRM, + "Requested timeout is invalid [%dms]", + sched_req->additional_timeout); + slot->additional_timeout = 0; + } else if (sched_req->additional_timeout > + CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX) { + CAM_WARN(CAM_CRM, + "Requested timeout [%dms] max supported timeout [%dms] resetting to max", + sched_req->additional_timeout, + CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX); + slot->additional_timeout = CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX; + } else { + slot->additional_timeout = sched_req->additional_timeout; + } + + if (link->is_first_req) { + if (sched_req->additional_timeout > + CAM_REQ_MGR_WATCHDOG_TIMEOUT) { + crm_timer_modify(link->watchdog, + (sched_req->additional_timeout + + CAM_REQ_MGR_WATCHDOG_TIMEOUT - 1)); + } + link->is_first_req = false; + } + + link->open_req_cnt++; + __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + + if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + if (link->initial_sync_req == -1) + link->initial_sync_req = slot->req_id; + } else { + link->initial_sync_req = -1; + if (link->sync_link) + link->sync_link->initial_sync_req = -1; + } + + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_add_req() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which peding requests can be processed. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_add_req(void *priv, void *data) +{ + int rc = 0, i = 0, idx; + struct cam_req_mgr_add_request *add_req = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_connected_device *device = NULL; + struct cam_req_mgr_req_tbl *tbl = NULL; + struct cam_req_mgr_tbl_slot *slot = NULL; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + add_req = (struct cam_req_mgr_add_request *)&task_data->u; + + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + if (device->dev_hdl == add_req->dev_hdl) { + tbl = device->pd_tbl; + break; + } + } + if (!tbl) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "dev_hdl not found %x, %x %x", + add_req->dev_hdl, + link->l_dev[0].dev_hdl, + link->l_dev[1].dev_hdl); + rc = -EINVAL; + goto end; + } + /* + * Go through request table and add + * request id to proper table + * 1. find req slot in in_q matching req_id.sent by dev + * 2. goto table of this device based on p_delay + * 3. mark req_ready_map with this dev_bit. + */ + + mutex_lock(&link->req.lock); + idx = __cam_req_mgr_find_slot_for_req(link->req.in_q, add_req->req_id); + if (idx < 0) { + CAM_ERR(CAM_CRM, + "req %lld not found in in_q for dev %s on link 0x%x", + add_req->req_id, device->dev_info.name, link->link_hdl); + rc = -EBADSLT; + mutex_unlock(&link->req.lock); + goto end; + } + + slot = &tbl->slot[idx]; + slot->is_applied = false; + if ((add_req->skip_before_applying & 0xFF) > slot->inject_delay) { + slot->inject_delay = (add_req->skip_before_applying & 0xFF); + slot->dev_hdl = add_req->dev_hdl; + if (add_req->skip_before_applying & SKIP_NEXT_FRAME) + slot->skip_next_frame = true; + CAM_DBG(CAM_CRM, "Req_id %llu injecting delay %llu", + add_req->req_id, + (add_req->skip_before_applying & 0xFF)); + } + + if (slot->state != CRM_REQ_STATE_PENDING && + slot->state != CRM_REQ_STATE_EMPTY) { + CAM_WARN(CAM_CRM, + "Unexpected state %d for slot %d map %x for dev %s on link 0x%x", + slot->state, idx, slot->req_ready_map, + device->dev_info.name, link->link_hdl); + } + + slot->state = CRM_REQ_STATE_PENDING; + slot->req_ready_map |= (1 << device->dev_bit); + + CAM_DBG(CAM_CRM, "idx %d dev_hdl %x req_id %lld pd %d ready_map %x", + idx, add_req->dev_hdl, add_req->req_id, tbl->pd, + slot->req_ready_map); + + trace_cam_req_mgr_add_req(link, idx, add_req, tbl, device); + + if (slot->req_ready_map == tbl->dev_mask) { + CAM_DBG(CAM_REQ, + "link 0x%x idx %d req_id %lld pd %d SLOT READY", + link->link_hdl, idx, add_req->req_id, tbl->pd); + slot->state = CRM_REQ_STATE_READY; + } + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_error() + * + * @brief: This runs in workque thread context. bubble /err recovery. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_error(void *priv, void *data) +{ + int rc = 0, idx = -1, i; + struct cam_req_mgr_error_notify *err_info = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_connected_device *device = NULL; + struct cam_req_mgr_link_evt_data evt_data; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + err_info = (struct cam_req_mgr_error_notify *)&task_data->u; + CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld error %d", + err_info->link_hdl, + err_info->req_id, + err_info->error); + + in_q = link->req.in_q; + + mutex_lock(&link->req.lock); + if (err_info->error == CRM_KMD_ERR_BUBBLE) { + idx = __cam_req_mgr_find_slot_for_req(in_q, err_info->req_id); + if (idx < 0) { + CAM_ERR_RATE_LIMIT(CAM_CRM, + "req_id %lld not found in input queue", + err_info->req_id); + } else { + CAM_DBG(CAM_CRM, "req_id %lld found at idx %d", + err_info->req_id, idx); + slot = &in_q->slot[idx]; + if (!slot->recover) { + CAM_WARN(CAM_CRM, + "err recovery disabled req_id %lld", + err_info->req_id); + mutex_unlock(&link->req.lock); + return 0; + } else if (slot->status != CRM_SLOT_STATUS_REQ_PENDING + && slot->status != CRM_SLOT_STATUS_REQ_APPLIED) { + CAM_WARN(CAM_CRM, + "req_id %lld can not be recovered %d", + err_info->req_id, slot->status); + mutex_unlock(&link->req.lock); + return -EINVAL; + } + /* Notify all devices in the link about error */ + for (i = 0; i < link->num_devs; i++) { + device = &link->l_dev[i]; + if (device != NULL) { + evt_data.dev_hdl = device->dev_hdl; + evt_data.evt_type = + CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = err_info->req_id; + evt_data.u.error = err_info->error; + if (device->ops && + device->ops->process_evt) + rc = device->ops->process_evt( + &evt_data); + } + } + /* Bring processing pointer to bubbled req id */ + __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); + in_q->rd_idx = idx; + in_q->slot[idx].status = CRM_SLOT_STATUS_REQ_ADDED; + if (link->sync_link) { + in_q->slot[idx].sync_mode = 0; + __cam_req_mgr_inc_idx(&idx, 1, + link->req.l_tbl->num_slots); + in_q->slot[idx].sync_mode = 0; + } + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_ERR; + spin_unlock_bh(&link->link_state_spin_lock); + link->open_req_cnt++; + } + } + mutex_unlock(&link->req.lock); + +end: + return rc; +} + +/** + * cam_req_mgr_process_stop() + * + * @brief: This runs in workque thread context. stop notification. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +int cam_req_mgr_process_stop(void *priv, void *data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + __cam_req_mgr_flush_req_slot(link); +end: + return rc; +} + +/** + * cam_req_mgr_process_trigger() + * + * @brief: This runs in workque thread context. Call core funcs to check + * which peding requests can be processed. + * @priv : link information. + * @data : contains information about frame_id, link etc. + * + * @return: 0 on success. + */ +static int cam_req_mgr_process_trigger(void *priv, void *data) +{ + int rc = 0; + int32_t idx = -1; + struct cam_req_mgr_trigger_notify *trigger_data = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_req_queue *in_q = NULL; + struct crm_task_payload *task_data = NULL; + + if (!data || !priv) { + CAM_ERR(CAM_CRM, "input args NULL %pK %pK", data, priv); + rc = -EINVAL; + goto end; + } + link = (struct cam_req_mgr_core_link *)priv; + task_data = (struct crm_task_payload *)data; + trigger_data = (struct cam_req_mgr_trigger_notify *)&task_data->u; + + CAM_DBG(CAM_REQ, "link_hdl %x frame_id %lld, trigger %x\n", + trigger_data->link_hdl, + trigger_data->frame_id, + trigger_data->trigger); + + in_q = link->req.in_q; + + mutex_lock(&link->req.lock); + + if (trigger_data->trigger == CAM_TRIGGER_POINT_SOF) { + idx = __cam_req_mgr_find_slot_for_req(in_q, + trigger_data->req_id); + if (idx >= 0) { + if (idx == in_q->last_applied_idx) + in_q->last_applied_idx = -1; + __cam_req_mgr_reset_req_slot(link, idx); + } + } + + /* + * Check if current read index is in applied state, if yes make it free + * and increment read index to next slot. + */ + CAM_DBG(CAM_CRM, "link_hdl %x curent idx %d req_status %d", + link->link_hdl, in_q->rd_idx, in_q->slot[in_q->rd_idx].status); + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state == CAM_CRM_LINK_STATE_ERR) + CAM_WARN(CAM_CRM, "Error recovery idx %d status %d", + in_q->rd_idx, + in_q->slot[in_q->rd_idx].status); + + spin_unlock_bh(&link->link_state_spin_lock); + + if (in_q->slot[in_q->rd_idx].status == CRM_SLOT_STATUS_REQ_APPLIED) { + /* + * Do NOT reset req q slot data here, it can not be done + * here because we need to preserve the data to handle bubble. + * + * Check if any new req is pending in slot, if not finish the + * lower pipeline delay device with available req ids. + */ + CAM_DBG(CAM_CRM, "link[%x] Req[%lld] invalidating slot", + link->link_hdl, in_q->slot[in_q->rd_idx].req_id); + rc = __cam_req_mgr_check_next_req_slot(link); + if (rc) { + CAM_DBG(CAM_REQ, + "No pending req to apply to lower pd devices"); + rc = 0; + goto release_lock; + } + __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); + } + + rc = __cam_req_mgr_process_req(link, trigger_data); + +release_lock: + mutex_unlock(&link->req.lock); +end: + return rc; +} + +/** + * __cam_req_mgr_dev_handle_to_name() + * + * @brief : Finds device name based on the device handle + * @dev_hdl : Device handle whose name is to be found + * @link : Link on which the device is connected + * @return : String containing the device name + * + */ +static const char *__cam_req_mgr_dev_handle_to_name( + int32_t dev_hdl, struct cam_req_mgr_core_link *link) +{ + struct cam_req_mgr_connected_device *dev = NULL; + int i = 0; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + + if (dev_hdl == dev->dev_hdl) + return dev->dev_info.name; + } + + return "Invalid dev_hdl"; +} + +/* Linked devices' Callback section */ + +/** + * cam_req_mgr_cb_add_req() + * + * @brief : Drivers call this function to notify new packet is available. + * @add_req : Information about new request available at a device. + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) +{ + int rc = 0, idx; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_add_request *dev_req; + struct crm_task_payload *task_data; + + if (!add_req) { + CAM_ERR(CAM_CRM, "sof_data is NULL"); + return -EINVAL; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(add_req->link_hdl); + + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", add_req->link_hdl); + return -EINVAL; + } + + CAM_DBG(CAM_REQ, "dev name %s dev_hdl %d dev req %lld", + __cam_req_mgr_dev_handle_to_name(add_req->dev_hdl, link), + add_req->dev_hdl, add_req->req_id); + + mutex_lock(&link->lock); + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + rc = -EPERM; + spin_unlock_bh(&link->link_state_spin_lock); + goto end; + } + spin_unlock_bh(&link->link_state_spin_lock); + + /* Validate if req id is present in input queue */ + idx = __cam_req_mgr_find_slot_for_req(link->req.in_q, add_req->req_id); + if (idx < 0) { + CAM_ERR(CAM_CRM, "req %lld not found in in_q", add_req->req_id); + rc = -ENOENT; + goto end; + } + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "no empty task dev %x req %lld", + add_req->dev_hdl, add_req->req_id); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_DEV_ADD_REQ; + dev_req = (struct cam_req_mgr_add_request *)&task_data->u; + dev_req->req_id = add_req->req_id; + dev_req->link_hdl = add_req->link_hdl; + dev_req->dev_hdl = add_req->dev_hdl; + dev_req->skip_before_applying = add_req->skip_before_applying; + task->process_cb = &cam_req_mgr_process_add_req; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + CAM_DBG(CAM_CRM, "X: dev %x dev req %lld", + add_req->dev_hdl, add_req->req_id); + +end: + mutex_unlock(&link->lock); + return rc; +} + +/** + * cam_req_mgr_cb_notify_err() + * + * @brief : Error received from device, sends bubble recovery + * @err_info : contains information about error occurred like bubble/overflow + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_notify_err( + struct cam_req_mgr_error_notify *err_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_error_notify *notify_err; + struct crm_task_payload *task_data; + + if (!err_info) { + CAM_ERR(CAM_CRM, "err_info is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(err_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", err_info->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state != CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task req_id %lld", err_info->req_id); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_ERR; + notify_err = (struct cam_req_mgr_error_notify *)&task_data->u; + notify_err->req_id = err_info->req_id; + notify_err->link_hdl = err_info->link_hdl; + notify_err->dev_hdl = err_info->dev_hdl; + notify_err->error = err_info->error; + task->process_cb = &cam_req_mgr_process_error; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + + +/** + * cam_req_mgr_cb_notify_timer() + * + * @brief : Notify SOF timer to pause after flush + * @timer_data : contains information about frame_id, link etc. + * + * @return : 0 on success + * + */ +static int cam_req_mgr_cb_notify_timer( + struct cam_req_mgr_timer_notify *timer_data) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + + if (!timer_data) { + CAM_ERR(CAM_CRM, "timer data is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(timer_data->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", timer_data->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + if ((link->watchdog) && (!timer_data->state)) + link->watchdog->pause_timer = true; + spin_unlock_bh(&link->link_state_spin_lock); + +end: + return rc; +} + +/* + * cam_req_mgr_cb_notify_stop() + * + * @brief : Stop received from device, resets the morked slots + * @err_info : contains information about error occurred like bubble/overflow + * + * @return : 0 on success, negative in case of failure + * + */ +static int cam_req_mgr_cb_notify_stop( + struct cam_req_mgr_notify_stop *stop_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_notify_stop *notify_stop; + struct crm_task_payload *task_data; + + if (!stop_info) { + CAM_ERR(CAM_CRM, "stop_info is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(stop_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", stop_info->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state != CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task"); + rc = -EBUSY; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_ERR; + notify_stop = (struct cam_req_mgr_notify_stop *)&task_data->u; + notify_stop->link_hdl = stop_info->link_hdl; + task->process_cb = &cam_req_mgr_process_stop; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + + + +/** + * cam_req_mgr_cb_notify_trigger() + * + * @brief : SOF received from device, sends trigger through workqueue + * @sof_data: contains information about frame_id, link etc. + * + * @return : 0 on success + * + */ +static int cam_req_mgr_cb_notify_trigger( + struct cam_req_mgr_trigger_notify *trigger_data) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_trigger_notify *notify_trigger; + struct crm_task_payload *task_data; + + if (!trigger_data) { + CAM_ERR(CAM_CRM, "sof_data is NULL"); + rc = -EINVAL; + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(trigger_data->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", trigger_data->link_hdl); + rc = -EINVAL; + goto end; + } + + spin_lock_bh(&link->link_state_spin_lock); + if (link->state < CAM_CRM_LINK_STATE_READY) { + CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); + spin_unlock_bh(&link->link_state_spin_lock); + rc = -EPERM; + goto end; + } + + if ((link->watchdog) && (link->watchdog->pause_timer)) + link->watchdog->pause_timer = false; + + crm_timer_reset(link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + CAM_ERR(CAM_CRM, "no empty task frame %lld", + trigger_data->frame_id); + rc = -EBUSY; + goto end; + } + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_NOTIFY_SOF; + notify_trigger = (struct cam_req_mgr_trigger_notify *)&task_data->u; + notify_trigger->frame_id = trigger_data->frame_id; + notify_trigger->link_hdl = trigger_data->link_hdl; + notify_trigger->dev_hdl = trigger_data->dev_hdl; + notify_trigger->trigger = trigger_data->trigger; + notify_trigger->req_id = trigger_data->req_id; + notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val; + task->process_cb = &cam_req_mgr_process_trigger; + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + +end: + return rc; +} + +static struct cam_req_mgr_crm_cb cam_req_mgr_ops = { + .notify_trigger = cam_req_mgr_cb_notify_trigger, + .notify_err = cam_req_mgr_cb_notify_err, + .add_req = cam_req_mgr_cb_add_req, + .notify_timer = cam_req_mgr_cb_notify_timer, + .notify_stop = cam_req_mgr_cb_notify_stop, +}; + +/** + * __cam_req_mgr_setup_link_info() + * + * @brief : Sets up input queue, create pd based tables, communicate with + * devs connected on this link and setup communication. + * @link : pointer to link to setup + * @link_info : link_info coming from CSL to prepare link + * + * @return : 0 on success, negative in case of failure + * + */ +static int __cam_req_mgr_setup_link_info(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0, i = 0, num_devices = 0; + struct cam_req_mgr_core_dev_link_setup link_data; + struct cam_req_mgr_connected_device *dev; + struct cam_req_mgr_req_tbl *pd_tbl; + enum cam_pipeline_delay max_delay; + uint32_t subscribe_event = 0; + if (link_info->version == VERSION_1) { + if (link_info->u.link_info_v1.num_devices > + CAM_REQ_MGR_MAX_HANDLES) + return -EPERM; + } + else if (link_info->version == VERSION_2) { + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) + return -EPERM; + } + mutex_init(&link->req.lock); + CAM_DBG(CAM_CRM, "LOCK_DBG in_q lock %pK", &link->req.lock); + link->req.num_tbl = 0; + + rc = __cam_req_mgr_setup_in_q(&link->req); + if (rc < 0) + return rc; + + max_delay = CAM_PIPELINE_DELAY_0; + if (link_info->version == VERSION_1) + num_devices = link_info->u.link_info_v1.num_devices; + else if (link_info->version == VERSION_2) + num_devices = link_info->u.link_info_v2.num_devices; + for (i = 0; i < num_devices; i++) { + dev = &link->l_dev[i]; + /* Using dev hdl, get ops ptr to communicate with device */ + if (link_info->version == VERSION_1) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v1.dev_hdls[i]); + else if (link_info->version == VERSION_2) + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops( + link_info->u.link_info_v2.dev_hdls[i]); + if (!dev->ops || + !dev->ops->get_dev_info || + !dev->ops->link_setup) { + CAM_ERR(CAM_CRM, "FATAL: device ops NULL"); + rc = -ENXIO; + goto error; + } + if (link_info->version == VERSION_1) + dev->dev_hdl = link_info->u.link_info_v1.dev_hdls[i]; + else if (link_info->version == VERSION_2) + dev->dev_hdl = link_info->u.link_info_v2.dev_hdls[i]; + dev->parent = (void *)link; + dev->dev_info.dev_hdl = dev->dev_hdl; + rc = dev->ops->get_dev_info(&dev->dev_info); + + trace_cam_req_mgr_connect_device(link, &dev->dev_info); + if (link_info->version == VERSION_1) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + else if (link_info->version == VERSION_2) + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.dev_id, dev->dev_info.p_delay, + dev->dev_info.trigger); + if (rc < 0 || + dev->dev_info.p_delay >= + CAM_PIPELINE_DELAY_MAX || + dev->dev_info.p_delay < + CAM_PIPELINE_DELAY_0) { + CAM_ERR(CAM_CRM, "get device info failed"); + goto error; + } else { + if (link_info->version == VERSION_1) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v1.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } + else if (link_info->version == VERSION_2) { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->u.link_info_v2.session_hdl, + dev->dev_info.name, + dev->dev_info.p_delay); + } + if (dev->dev_info.p_delay > max_delay) + max_delay = dev->dev_info.p_delay; + + subscribe_event |= (uint32_t)dev->dev_info.trigger; + } + } + + link->subscribe_event = subscribe_event; + link_data.link_enable = 1; + link_data.link_hdl = link->link_hdl; + link_data.crm_cb = &cam_req_mgr_ops; + link_data.max_delay = max_delay; + link_data.subscribe_event = subscribe_event; + + for (i = 0; i < num_devices; i++) { + dev = &link->l_dev[i]; + + link_data.dev_hdl = dev->dev_hdl; + /* + * For unique pipeline delay table create request + * tracking table + */ + if (link->pd_mask & (1 << dev->dev_info.p_delay)) { + pd_tbl = __cam_req_mgr_find_pd_tbl(link->req.l_tbl, + dev->dev_info.p_delay); + if (!pd_tbl) { + CAM_ERR(CAM_CRM, "pd %d tbl not found", + dev->dev_info.p_delay); + rc = -ENXIO; + goto error; + } + } else { + pd_tbl = __cam_req_mgr_create_pd_tbl( + dev->dev_info.p_delay); + if (pd_tbl == NULL) { + CAM_ERR(CAM_CRM, "create new pd tbl failed"); + rc = -ENXIO; + goto error; + } + pd_tbl->pd = dev->dev_info.p_delay; + link->pd_mask |= (1 << pd_tbl->pd); + /* + * Add table to list and also sort list + * from max pd to lowest + */ + __cam_req_mgr_add_tbl_to_link(&link->req.l_tbl, pd_tbl); + } + dev->dev_bit = pd_tbl->dev_count++; + dev->pd_tbl = pd_tbl; + pd_tbl->dev_mask |= (1 << dev->dev_bit); + CAM_DBG(CAM_CRM, "dev_bit %u name %s pd %u mask %d", + dev->dev_bit, dev->dev_info.name, pd_tbl->pd, + pd_tbl->dev_mask); + /* Communicate with dev to establish the link */ + dev->ops->link_setup(&link_data); + + if (link->max_delay < dev->dev_info.p_delay) + link->max_delay = dev->dev_info.p_delay; + } + link->num_devs = num_devices; + + /* Assign id for pd tables */ + __cam_req_mgr_tbl_set_id(link->req.l_tbl, &link->req); + + /* At start, expect max pd devices, all are in skip state */ + __cam_req_mgr_tbl_set_all_skip_cnt(&link->req.l_tbl); + + return 0; + +error: + __cam_req_mgr_destroy_link_info(link); + return rc; +} + +/* IOCTLs handling section */ +int cam_req_mgr_create_session( + struct cam_req_mgr_session_info *ses_info) +{ + int rc = 0; + int32_t session_hdl; + struct cam_req_mgr_core_session *cam_session = NULL; + + if (!ses_info) { + CAM_DBG(CAM_CRM, "NULL session info pointer"); + return -EINVAL; + } + mutex_lock(&g_crm_core_dev->crm_lock); + cam_session = kzalloc(sizeof(*cam_session), + GFP_KERNEL); + if (!cam_session) { + rc = -ENOMEM; + goto end; + } + + session_hdl = cam_create_session_hdl((void *)cam_session); + if (session_hdl < 0) { + CAM_ERR(CAM_CRM, "unable to create session_hdl = %x", + session_hdl); + rc = session_hdl; + kfree(cam_session); + goto end; + } + ses_info->session_hdl = session_hdl; + + mutex_init(&cam_session->lock); + CAM_DBG(CAM_CRM, "LOCK_DBG session lock %pK", &cam_session->lock); + + mutex_lock(&cam_session->lock); + cam_session->session_hdl = session_hdl; + cam_session->num_links = 0; + cam_session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + list_add(&cam_session->entry, &g_crm_core_dev->session_head); + mutex_unlock(&cam_session->lock); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +/** + * __cam_req_mgr_unlink() + * + * @brief : Unlink devices on a link structure from the session + * @link : Pointer to the link structure + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) +{ + int rc; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_IDLE; + spin_unlock_bh(&link->link_state_spin_lock); + + if (!link->is_shutdown) { + rc = __cam_req_mgr_disconnect_link(link); + if (rc) + CAM_ERR(CAM_CORE, + "Unlink for all devices was not successful"); + } + + mutex_lock(&link->lock); + /* Destroy workq of link */ + cam_req_mgr_workq_destroy(&link->workq); + + /* Destroy timer of link */ + spin_lock_bh(&link->link_state_spin_lock); + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + + /* Cleanup request tables and unlink devices */ + __cam_req_mgr_destroy_link_info(link); + /* Free memory holding data of linked devs */ + + __cam_req_mgr_destroy_subdev(link->l_dev); + + /* Destroy the link handle */ + rc = cam_destroy_device_hdl(link->link_hdl); + if (rc < 0) { + CAM_ERR(CAM_CRM, "error destroying link hdl %x rc %d", + link->link_hdl, rc); + } else + link->link_hdl = -1; + + mutex_unlock(&link->lock); + return rc; +} + +int cam_req_mgr_destroy_session( + struct cam_req_mgr_session_info *ses_info, + bool is_shutdown) +{ + int rc; + int i; + struct cam_req_mgr_core_session *cam_session = NULL; + struct cam_req_mgr_core_link *link; + + if (!ses_info) { + CAM_DBG(CAM_CRM, "NULL session info pointer"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(ses_info->session_hdl); + if (!cam_session) { + CAM_ERR(CAM_CRM, "failed to get session priv"); + rc = -ENOENT; + goto end; + + } + if (cam_session->num_links) { + CAM_DBG(CAM_CRM, "destroy session %x num_active_links %d", + ses_info->session_hdl, + cam_session->num_links); + + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + link = cam_session->links[i]; + + if (!link) + continue; + + /* Ignore return value since session is going away */ + link->is_shutdown = is_shutdown; + __cam_req_mgr_unlink(link); + __cam_req_mgr_free_link(link); + } + } + list_del(&cam_session->entry); + mutex_destroy(&cam_session->lock); + kfree(cam_session); + + rc = cam_destroy_session_hdl(ses_info->session_hdl); + if (rc < 0) + CAM_ERR(CAM_CRM, "unable to destroy session_hdl = %x rc %d", + ses_info->session_hdl, rc); + +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->u.link_info_v1.num_devices > CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->u.link_info_v1.num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->u.link_info_v1.session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->u.link_info_v1.session_hdl; + root_dev.priv = (void *)link; + + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->u.link_info_v1.link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->u.link_info_v1.num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->u.link_info_v1.session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->u.link_info_v1.link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info) +{ + int rc = 0; + int wq_flag = 0; + char buf[128]; + struct cam_create_dev_hdl root_dev; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!link_info) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + if (link_info->u.link_info_v2.num_devices > + CAM_REQ_MGR_MAX_HANDLES_V2) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->u.link_info_v2.num_devices); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->u.link_info_v2.session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* Allocate link struct and map it with session's request queue */ + link = __cam_req_mgr_reserve_link(cam_session); + if (!link) { + CAM_ERR(CAM_CRM, "failed to reserve new link"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "link reserved %pK %x", link, link->link_hdl); + + memset(&root_dev, 0, sizeof(struct cam_create_dev_hdl)); + root_dev.session_hdl = link_info->u.link_info_v2.session_hdl; + root_dev.priv = (void *)link; + + mutex_lock(&link->lock); + /* Create unique dev handle for link */ + link->link_hdl = cam_create_device_hdl(&root_dev); + if (link->link_hdl < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new device handle"); + rc = link->link_hdl; + goto link_hdl_fail; + } + link_info->u.link_info_v2.link_hdl = link->link_hdl; + link->last_flush_id = 0; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->u.link_info_v2.num_devices); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Insufficient memory to create new crm subdevs"); + goto create_subdev_failed; + } + + /* Using device ops query connected devs, prepare request tables */ + rc = __cam_req_mgr_setup_link_info(link, link_info); + if (rc < 0) + goto setup_failed; + + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + spin_unlock_bh(&link->link_state_spin_lock); + + /* Create worker for current link */ + snprintf(buf, sizeof(buf), "%x-%x", + link_info->u.link_info_v2.session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); + if (rc < 0) { + CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); + __cam_req_mgr_destroy_link_info(link); + goto setup_failed; + } + + /* Assign payload to workqueue tasks */ + rc = __cam_req_mgr_setup_payload(link->workq); + if (rc < 0) { + __cam_req_mgr_destroy_link_info(link); + cam_req_mgr_workq_destroy(&link->workq); + goto setup_failed; + } + + mutex_unlock(&link->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +setup_failed: + __cam_req_mgr_destroy_subdev(link->l_dev); +create_subdev_failed: + cam_destroy_device_hdl(link->link_hdl); + link_info->u.link_info_v2.link_hdl = -1; +link_hdl_fail: + mutex_unlock(&link->lock); + __cam_req_mgr_unreserve_link(cam_session, link); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + + +int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info) +{ + int rc = 0; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link; + + if (!unlink_info) { + CAM_ERR(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + CAM_DBG(CAM_CRM, "link_hdl %x", unlink_info->link_hdl); + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(unlink_info->session_hdl); + if (!cam_session) { + CAM_ERR(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + /* link hdl's priv data is core_link struct */ + link = cam_get_device_priv(unlink_info->link_hdl); + if (!link) { + CAM_ERR(CAM_CRM, "NULL pointer"); + rc = -EINVAL; + goto done; + } + + rc = __cam_req_mgr_unlink(link); + + /* Free curent link and put back into session's free pool of links */ + __cam_req_mgr_unreserve_link(cam_session, link); + +done: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_schedule_request( + struct cam_req_mgr_sched_request *sched_req) +{ + int rc = 0; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_sched_request *sched; + struct crm_task_payload task_data; + + if (!sched_req) { + CAM_ERR(CAM_CRM, "csl_req is NULL"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(sched_req->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", sched_req->link_hdl); + rc = -EINVAL; + goto end; + } + + session = (struct cam_req_mgr_core_session *)link->parent; + if (!session) { + CAM_WARN(CAM_CRM, "session ptr NULL %x", sched_req->link_hdl); + rc = -EINVAL; + goto end; + } + + if (sched_req->req_id <= link->last_flush_id) { + CAM_INFO(CAM_CRM, + "request %lld is flushed, last_flush_id to flush %d", + sched_req->req_id, link->last_flush_id); + rc = -EBADR; + goto end; + } + + if (sched_req->req_id > link->last_flush_id) + link->last_flush_id = 0; + + CAM_DBG(CAM_CRM, "link 0x%x req %lld, sync_mode %d", + sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); + + task_data.type = CRM_WORKQ_TASK_SCHED_REQ; + sched = (struct cam_req_mgr_sched_request *)&task_data.u; + sched->req_id = sched_req->req_id; + sched->sync_mode = sched_req->sync_mode; + sched->link_hdl = sched_req->link_hdl; + sched->additional_timeout = sched_req->additional_timeout; + if (session->force_err_recovery == AUTO_RECOVERY) { + sched->bubble_enable = sched_req->bubble_enable; + } else { + sched->bubble_enable = + (session->force_err_recovery == FORCE_ENABLE_RECOVERY) ? 1 : 0; + } + + rc = cam_req_mgr_process_sched_req(link, &task_data); + + CAM_DBG(CAM_REQ, "Open req %lld on link 0x%x with sync_mode %d", + sched_req->req_id, sched_req->link_hdl, sched_req->sync_mode); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +/** + * __cam_req_mgr_set_master_link() + * + * @brief : Each links sets its max pd delay based on the devices on the + * link. The link with higher pd is assigned master. + * @link1 : One of the sync links + * @link2 : The other sync link + */ +static void __cam_req_mgr_set_master_link( + struct cam_req_mgr_core_link *link1, + struct cam_req_mgr_core_link *link2) +{ + + if (link1->max_delay > link2->max_delay) { + link1->is_master = true; + link2->initial_skip = true; + } else if (link2->max_delay > link1->max_delay) { + link2->is_master = true; + link1->initial_skip = true; + } + + CAM_DBG(CAM_CRM, + "link_hdl1[0x%x] is_master [%u] link_hdl2[0x%x] is_master[%u]", + link1->link_hdl, link1->is_master, + link2->link_hdl, link2->is_master); +} + +int cam_req_mgr_sync_config( + struct cam_req_mgr_sync_mode *sync_info) +{ + int rc = 0; + struct cam_req_mgr_core_session *cam_session; + struct cam_req_mgr_core_link *link1 = NULL; + struct cam_req_mgr_core_link *link2 = NULL; + + if (!sync_info) { + CAM_ERR(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + if ((sync_info->num_links < 0) || + (sync_info->num_links > + MAX_LINKS_PER_SESSION)) { + CAM_ERR(CAM_CRM, "Invalid num links %d", sync_info->num_links); + return -EINVAL; + } + + if ((sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_SYNC) && + (sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC)) { + CAM_ERR(CAM_CRM, "Invalid sync mode %d", sync_info->sync_mode); + return -EINVAL; + } + + if ((!sync_info->link_hdls[0]) || (!sync_info->link_hdls[1])) { + CAM_WARN(CAM_CRM, "Invalid link handles 0x%x 0x%x", + sync_info->link_hdls[0], sync_info->link_hdls[1]); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(sync_info->session_hdl); + if (!cam_session) { + CAM_ERR(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); + return -EINVAL; + } + + mutex_lock(&cam_session->lock); + + CAM_DBG(CAM_CRM, "link handles %x %x", + sync_info->link_hdls[0], sync_info->link_hdls[1]); + + /* only two links existing per session in dual cam use case*/ + link1 = cam_get_device_priv(sync_info->link_hdls[0]); + if (!link1) { + CAM_ERR(CAM_CRM, "link1 NULL pointer"); + rc = -EINVAL; + goto done; + } + + link2 = cam_get_device_priv(sync_info->link_hdls[1]); + if (!link2) { + CAM_ERR(CAM_CRM, "link2 NULL pointer"); + rc = -EINVAL; + goto done; + } + + link1->sync_link_sof_skip = false; + link1->sync_link = NULL; + + link2->sync_link_sof_skip = false; + link2->sync_link = NULL; + + link1->is_master = false; + link2->is_master = false; + + link1->in_msync_mode = false; + link2->in_msync_mode = false; + link1->initial_sync_req = -1; + link2->initial_sync_req = -1; + + if (sync_info->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + link1->sync_link = link2; + link2->sync_link = link1; + __cam_req_mgr_set_master_link(link1, link2); + } else { + /* + * Reset below info after the mode is configured + * to NO-SYNC mode since they may be overridden + * if the sync config is invoked after SOF comes. + */ + link1->initial_skip = true; + link2->initial_skip = true; + link1->sof_timestamp = 0; + link2->sof_timestamp = 0; + } + + cam_session->sync_mode = sync_info->sync_mode; + CAM_DBG(CAM_REQ, + "Sync config on link1 0x%x & link2 0x%x with sync_mode %d", + link1->link_hdl, link2->link_hdl, cam_session->sync_mode); + +done: + mutex_unlock(&cam_session->lock); + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_flush_requests( + struct cam_req_mgr_flush_info *flush_info) +{ + int rc = 0; + struct crm_workq_task *task = NULL; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_flush_info *flush; + struct crm_task_payload *task_data; + struct cam_req_mgr_core_session *session = NULL; + + if (!flush_info) { + CAM_ERR(CAM_CRM, "flush req is NULL"); + return -EFAULT; + } + if (flush_info->flush_type >= CAM_REQ_MGR_FLUSH_TYPE_MAX) { + CAM_ERR(CAM_CRM, "incorrect flush type %x", + flush_info->flush_type); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ + session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(flush_info->session_hdl); + if (!session) { + CAM_ERR(CAM_CRM, "Invalid session %x", flush_info->session_hdl); + rc = -EINVAL; + goto end; + } + if (session->num_links <= 0) { + CAM_WARN(CAM_CRM, "No active links in session %x", + flush_info->session_hdl); + goto end; + } + + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(flush_info->link_hdl); + if (!link) { + CAM_DBG(CAM_CRM, "link ptr NULL %x", flush_info->link_hdl); + rc = -EINVAL; + goto end; + } + + task = cam_req_mgr_workq_get_task(link->workq); + if (!task) { + rc = -ENOMEM; + goto end; + } + + task_data = (struct crm_task_payload *)task->payload; + task_data->type = CRM_WORKQ_TASK_FLUSH_REQ; + flush = (struct cam_req_mgr_flush_info *)&task_data->u; + flush->req_id = flush_info->req_id; + flush->link_hdl = flush_info->link_hdl; + flush->flush_type = flush_info->flush_type; + task->process_cb = &cam_req_mgr_process_flush_req; + init_completion(&link->workq_comp); + rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0); + + /* Blocking call */ + rc = wait_for_completion_timeout( + &link->workq_comp, + msecs_to_jiffies(CAM_REQ_MGR_SCHED_REQ_TIMEOUT)); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) +{ + int rc = 0; + int i, j; + struct cam_req_mgr_core_link *link = NULL; + + struct cam_req_mgr_connected_device *dev = NULL; + struct cam_req_mgr_link_evt_data evt_data; + + if (!control) { + CAM_ERR(CAM_CRM, "Control command is NULL"); + rc = -EINVAL; + goto end; + } + + if ((control->num_links <= 0) || + (control->num_links > MAX_LINKS_PER_SESSION)) { + CAM_ERR(CAM_CRM, "Invalid number of links %d", + control->num_links); + rc = -EINVAL; + goto end; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + for (i = 0; i < control->num_links; i++) { + link = (struct cam_req_mgr_core_link *) + cam_get_device_priv(control->link_hdls[i]); + if (!link) { + CAM_ERR(CAM_CRM, "Link(%d) is NULL on session 0x%x", + i, control->session_hdl); + rc = -EINVAL; + break; + } + + mutex_lock(&link->lock); + if (control->ops == CAM_REQ_MGR_LINK_ACTIVATE) { + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_READY; + link->is_first_req = true; + spin_unlock_bh(&link->link_state_spin_lock); + /* Start SOF watchdog timer */ + rc = crm_timer_init(&link->watchdog, + CAM_REQ_MGR_WATCHDOG_TIMEOUT, link, + &__cam_req_mgr_sof_freeze); + if (rc < 0) { + CAM_ERR(CAM_CRM, + "SOF timer start fails: link=0x%x", + link->link_hdl); + rc = -EFAULT; + } + /* notify nodes */ + for (j = 0; j < link->num_devs; j++) { + dev = &link->l_dev[j]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_RESUME; + evt_data.link_hdl = link->link_hdl; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.req_id = 0; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } + } else if (control->ops == CAM_REQ_MGR_LINK_DEACTIVATE) { + /* notify nodes */ + for (j = 0; j < link->num_devs; j++) { + dev = &link->l_dev[j]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_PAUSE; + evt_data.link_hdl = link->link_hdl; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.req_id = 0; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } + /* Destroy SOF watchdog timer */ + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_IDLE; + link->is_first_req = false; + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + } else { + CAM_ERR(CAM_CRM, "Invalid link control command"); + rc = -EINVAL; + } + mutex_unlock(&link->lock); + } + mutex_unlock(&g_crm_core_dev->crm_lock); +end: + return rc; +} + + +int cam_req_mgr_core_device_init(void) +{ + int i; + CAM_DBG(CAM_CRM, "Enter g_crm_core_dev %pK", g_crm_core_dev); + + if (g_crm_core_dev) { + CAM_WARN(CAM_CRM, "core device is already initialized"); + return 0; + } + g_crm_core_dev = kzalloc(sizeof(*g_crm_core_dev), + GFP_KERNEL); + if (!g_crm_core_dev) + return -ENOMEM; + + CAM_DBG(CAM_CRM, "g_crm_core_dev %pK", g_crm_core_dev); + INIT_LIST_HEAD(&g_crm_core_dev->session_head); + mutex_init(&g_crm_core_dev->crm_lock); + cam_req_mgr_debug_register(g_crm_core_dev); + + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + mutex_init(&g_links[i].lock); + spin_lock_init(&g_links[i].link_state_spin_lock); + atomic_set(&g_links[i].is_used, 0); + cam_req_mgr_core_link_reset(&g_links[i]); + } + return 0; +} + +int cam_req_mgr_core_device_deinit(void) +{ + if (!g_crm_core_dev) { + CAM_ERR(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + CAM_DBG(CAM_CRM, "g_crm_core_dev %pK", g_crm_core_dev); + mutex_destroy(&g_crm_core_dev->crm_lock); + kfree(g_crm_core_dev); + g_crm_core_dev = NULL; + + return 0; +} diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.h new file mode 100644 index 0000000000000000000000000000000000000000..6f5440a96d4363506cff61f9c5bce159e3358c5b --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core.h @@ -0,0 +1,510 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_REQ_MGR_CORE_H_ +#define _CAM_REQ_MGR_CORE_H_ + +#include <linux/spinlock.h> +#include "cam_req_mgr_interface.h" +#include "cam_req_mgr_core_defs.h" +#include "cam_req_mgr_timer.h" + +#define CAM_REQ_MGR_MAX_LINKED_DEV 16 +#define MAX_REQ_SLOTS 48 + +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT 5000 +#define CAM_REQ_MGR_WATCHDOG_TIMEOUT_MAX 50000 +#define CAM_REQ_MGR_SCHED_REQ_TIMEOUT 1000 +#define CAM_REQ_MGR_SIMULATE_SCHED_REQ 30 + +#define FORCE_DISABLE_RECOVERY 2 +#define FORCE_ENABLE_RECOVERY 1 +#define AUTO_RECOVERY 0 + +#define CRM_WORKQ_NUM_TASKS 60 + +#define MAX_SYNC_COUNT 65535 + +/* Default frame rate is 30 */ +#define DEFAULT_FRAME_DURATION 33333333 + +#define SYNC_LINK_SOF_CNT_MAX_LMT 1 + +#define MAXIMUM_LINKS_PER_SESSION 4 + +#define MAXIMUM_RETRY_ATTEMPTS 3 + +#define VERSION_1 1 +#define VERSION_2 2 + +/** + * enum crm_workq_task_type + * @codes: to identify which type of task is present + */ +enum crm_workq_task_type { + CRM_WORKQ_TASK_GET_DEV_INFO, + CRM_WORKQ_TASK_SETUP_LINK, + CRM_WORKQ_TASK_DEV_ADD_REQ, + CRM_WORKQ_TASK_APPLY_REQ, + CRM_WORKQ_TASK_NOTIFY_SOF, + CRM_WORKQ_TASK_NOTIFY_ERR, + CRM_WORKQ_TASK_NOTIFY_FREEZE, + CRM_WORKQ_TASK_SCHED_REQ, + CRM_WORKQ_TASK_FLUSH_REQ, + CRM_WORKQ_TASK_INVALID, +}; + +/** + * struct crm_task_payload + * @type : to identify which type of task is present + * @u : union of payload of all types of tasks supported + * @sched_req : contains info of incoming reqest from CSL to CRM + * @flush_info : contains info of cancelled reqest + * @dev_req : contains tracking info of available req id at device + * @send_req : contains info of apply settings to be sent to devs in link + * @apply_req : contains info of which request is applied at device + * @notify_trigger : contains notification from IFE to CRM about trigger + * @notify_err : contains error info happened while processing request + * - + */ +struct crm_task_payload { + enum crm_workq_task_type type; + union { + struct cam_req_mgr_sched_request sched_req; + struct cam_req_mgr_flush_info flush_info; + struct cam_req_mgr_add_request dev_req; + struct cam_req_mgr_send_request send_req; + struct cam_req_mgr_trigger_notify notify_trigger; + struct cam_req_mgr_error_notify notify_err; + } u; +}; + +/** + * enum crm_req_state + * State machine for life cycle of request in pd table + * EMPTY : indicates req slot is empty + * PENDING : indicates req slot is waiting for reqs from all devs + * READY : indicates req slot is ready to be sent to devs + * INVALID : indicates req slot is not in valid state + */ +enum crm_req_state { + CRM_REQ_STATE_EMPTY, + CRM_REQ_STATE_PENDING, + CRM_REQ_STATE_READY, + CRM_REQ_STATE_INVALID, +}; + +/** + * enum crm_slot_status + * State machine for life cycle of request in input queue + * NO_REQ : empty slot + * REQ_ADDED : new entry in slot + * PENDING : waiting for next trigger to apply + * APPLIED : req is sent to all devices + * INVALID : invalid state + */ +enum crm_slot_status { + CRM_SLOT_STATUS_NO_REQ, + CRM_SLOT_STATUS_REQ_ADDED, + CRM_SLOT_STATUS_REQ_PENDING, + CRM_SLOT_STATUS_REQ_APPLIED, + CRM_SLOT_STATUS_INVALID, +}; + +/** + * enum cam_req_mgr_link_state + * State machine for life cycle of link in crm + * AVAILABLE : link available + * IDLE : link initialized but not ready yet + * READY : link is ready for use + * ERR : link has encountered error + * MAX : invalid state + */ +enum cam_req_mgr_link_state { + CAM_CRM_LINK_STATE_AVAILABLE, + CAM_CRM_LINK_STATE_IDLE, + CAM_CRM_LINK_STATE_READY, + CAM_CRM_LINK_STATE_ERR, + CAM_CRM_LINK_STATE_MAX, +}; + +/** + * struct cam_req_mgr_traverse_result + * @req_id : Req id that is not ready + * @pd : pipeline delay + * @masked_value : Holds the dev bit for devices not ready + * for the given request + */ +struct cam_req_mgr_traverse_result { + int64_t req_id; + uint32_t pd; + uint32_t masked_value; +}; + +/** + * struct cam_req_mgr_traverse + * @idx : slot index + * @result : contains which all tables were able to apply successfully + * @result_data : holds the result of traverse in case it fails + * @tbl : pointer of pipeline delay based request table + * @apply_data : pointer which various tables will update during traverse + * @in_q : input request queue pointer + * @validate_only : Whether to validate only and/or update settings + * @open_req_cnt : Count of open requests yet to be serviced in the kernel. + */ +struct cam_req_mgr_traverse { + int32_t idx; + uint32_t result; + struct cam_req_mgr_traverse_result result_data; + struct cam_req_mgr_req_tbl *tbl; + struct cam_req_mgr_apply *apply_data; + struct cam_req_mgr_req_queue *in_q; + bool validate_only; + int32_t open_req_cnt; +}; + +/** + * struct cam_req_mgr_apply + * @idx : corresponding input queue slot index + * @pd : pipeline delay of device + * @req_id : req id for dev with above pd to process + * @skip_idx: skip applying settings when this is set. + */ +struct cam_req_mgr_apply { + int32_t idx; + int32_t pd; + int64_t req_id; + int32_t skip_idx; +}; + +/** + * struct cam_req_mgr_tbl_slot + * @idx : slot index + * @req_ready_map : mask tracking which all devices have request ready + * @state : state machine for life cycle of a slot + * @inject_delay : insert extra bubbling for flash type of use cases + * @dev_hdl : stores the dev_hdl, who is having higher inject delay + * @skip_next_frame : flag to drop the frame after skip_before_apply frame + * @is_applied : flag to identify if request is already applied to + * device. + */ +struct cam_req_mgr_tbl_slot { + int32_t idx; + uint32_t req_ready_map; + enum crm_req_state state; + uint32_t inject_delay; + int32_t dev_hdl; + bool skip_next_frame; + bool is_applied; +}; + +/** + * struct cam_req_mgr_req_tbl + * @id : table indetifier + * @pd : pipeline delay of table + * @dev_count : num of devices having same pipeline delay + * @dev_mask : mask to track which devices are linked + * @skip_traverse : to indicate how many traverses need to be dropped + * by this table especially in the beginning or bubble recovery + * @next : pointer to next pipeline delay request table + * @pd_delta : differnce between this table's pipeline delay and next + * @num_slots : number of request slots present in the table + * @slot : array of slots tracking requests availability at devices + */ +struct cam_req_mgr_req_tbl { + int32_t id; + int32_t pd; + int32_t dev_count; + int32_t dev_mask; + int32_t skip_traverse; + struct cam_req_mgr_req_tbl *next; + int32_t pd_delta; + int32_t num_slots; + struct cam_req_mgr_tbl_slot slot[MAX_REQ_SLOTS]; +}; + +/** + * struct cam_req_mgr_slot + * - Internal Book keeping + * @idx : slot index + * @skip_idx : if req id in this slot needs to be skipped/not applied + * @status : state machine for life cycle of a slot + * - members updated due to external events + * @recover : if user enabled recovery for this request. + * @req_id : mask tracking which all devices have request ready + * @sync_mode : Sync mode in which req id in this slot has to applied + * @additional_timeout : Adjusted watchdog timeout value associated with + * this request + */ +struct cam_req_mgr_slot { + int32_t idx; + int32_t skip_idx; + enum crm_slot_status status; + int32_t recover; + int64_t req_id; + int32_t sync_mode; + int32_t additional_timeout; +}; + +/** + * struct cam_req_mgr_req_queue + * @num_slots : max num of input queue slots + * @slot : request slot holding incoming request id and bubble info. + * @rd_idx : indicates slot index currently in process. + * @wr_idx : indicates slot index to hold new upcoming req. + * @last_applied_idx : indicates slot index last applied successfully. + */ +struct cam_req_mgr_req_queue { + int32_t num_slots; + struct cam_req_mgr_slot slot[MAX_REQ_SLOTS]; + int32_t rd_idx; + int32_t wr_idx; + int32_t last_applied_idx; +}; + +/** + * struct cam_req_mgr_req_data + * @in_q : Poiner to Input request queue + * @l_tbl : unique pd request tables. + * @num_tbl : how many unique pd value devices are present + * @apply_data : Holds information about request id for a request + * @lock : mutex lock protecting request data ops. + */ +struct cam_req_mgr_req_data { + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_req_tbl *l_tbl; + int32_t num_tbl; + struct cam_req_mgr_apply apply_data[CAM_PIPELINE_DELAY_MAX]; + struct mutex lock; +}; + +/** + * struct cam_req_mgr_connected_device + * - Device Properties + * @dev_hdl : device handle + * @dev_bit : unique bit assigned to device in link + * - Device characteristics + * @pd_tbl : tracks latest available req id at this device + * @dev_info : holds dev characteristics such as pipeline delay, dev name + * @ops : holds func pointer to call methods on this device + * @parent : pvt data - like link which this dev hdl belongs to + */ +struct cam_req_mgr_connected_device { + int32_t dev_hdl; + int64_t dev_bit; + struct cam_req_mgr_req_tbl *pd_tbl; + struct cam_req_mgr_device_info dev_info; + struct cam_req_mgr_kmd_ops *ops; + void *parent; +}; + +/** + * struct cam_req_mgr_core_link + * - Link Properties + * @link_hdl : Link identifier + * @num_devs : num of connected devices to this link + * @max_delay : Max of pipeline delay of all connected devs + * @workq : Pointer to handle workq related jobs + * @pd_mask : each set bit indicates the device with pd equal to + * bit position is available. + * - List of connected devices + * @l_dev : List of connected devices to this link + * - Request handling data struct + * @req : req data holder. + * - Timer + * @watchdog : watchdog timer to recover from sof freeze + * - Link private data + * @workq_comp : conditional variable to block user thread for workq + * to finish schedule request processing + * @state : link state machine + * @parent : pvt data - link's parent is session + * @lock : mutex lock to guard link data operations + * @link_state_spin_lock : spin lock to protect link state variable + * @subscribe_event : irqs that link subscribes, IFE should send + * notification to CRM at those hw events. + * @trigger_mask : mask on which irq the req is already applied + * @sync_link : pointer to the sync link for synchronization + * @sync_link_sof_skip : flag determines if a pkt is not available for a given + * frame in a particular link skip corresponding + * frame in sync link as well. + * @open_req_cnt : Counter to keep track of open requests that are yet + * to be serviced in the kernel. + * @last_flush_id : Last request to flush + * @is_used : 1 if link is in use else 0 + * @is_master : Based on pd among links, the link with the highest pd + * is assigned as master + * @initial_skip : Flag to determine if slave has started streaming in + * master-slave sync + * @in_msync_mode : Flag to determine if a link is in master-slave mode + * @initial_sync_req : The initial req which is required to sync with the + * other link + * @retry_cnt : Counter that tracks number of attempts to apply + * the same req + * @is_shutdown : Flag to indicate if link needs to be disconnected + * as part of shutdown. + * @sof_timestamp_value : SOF timestamp value + * @prev_sof_timestamp : Previous SOF timestamp value + * @is_first_req : Flag to indicate about link first req + */ +struct cam_req_mgr_core_link { + int32_t link_hdl; + int32_t num_devs; + enum cam_pipeline_delay max_delay; + struct cam_req_mgr_core_workq *workq; + int32_t pd_mask; + struct cam_req_mgr_connected_device *l_dev; + struct cam_req_mgr_req_data req; + struct cam_req_mgr_timer *watchdog; + struct completion workq_comp; + enum cam_req_mgr_link_state state; + void *parent; + struct mutex lock; + spinlock_t link_state_spin_lock; + uint32_t subscribe_event; + uint32_t trigger_mask; + struct cam_req_mgr_core_link *sync_link; + bool sync_link_sof_skip; + int32_t open_req_cnt; + uint32_t last_flush_id; + atomic_t is_used; + bool is_master; + bool initial_skip; + bool in_msync_mode; + int64_t initial_sync_req; + uint32_t retry_cnt; + bool is_shutdown; + uint64_t sof_timestamp; + uint64_t prev_sof_timestamp; + bool is_first_req; +}; + +/** + * struct cam_req_mgr_core_session + * - Session Properties + * @session_hdl : session identifier + * @num_links : num of active links for current session + * - Links of this session + * @links : pointer to array of links within session + * @in_q : Input request queue one per session + * - Session private data + * @entry : pvt data - entry in the list of sessions + * @lock : pvt data - spin lock to guard session data + * - Debug data + * @force_err_recovery : For debugging, we can force bubble recovery + * to be always ON or always OFF using debugfs. + * @sync_mode : Sync mode for this session links + */ +struct cam_req_mgr_core_session { + int32_t session_hdl; + uint32_t num_links; + struct cam_req_mgr_core_link *links[MAXIMUM_LINKS_PER_SESSION]; + struct list_head entry; + struct mutex lock; + int32_t force_err_recovery; + int32_t sync_mode; +}; + +/** + * struct cam_req_mgr_core_device + * - Core camera request manager data struct + * @session_head : list head holding sessions + * @crm_lock : mutex lock to protect session creation & destruction + */ +struct cam_req_mgr_core_device { + struct list_head session_head; + struct mutex crm_lock; +}; + +/** + * cam_req_mgr_create_session() + * @brief : creates session + * @ses_info : output param for session handle + * + * called as part of session creation. + */ +int cam_req_mgr_create_session(struct cam_req_mgr_session_info *ses_info); + +/** + * cam_req_mgr_destroy_session() + * @brief : destroy session + * @ses_info : session handle info, input param + * @is_shutdown: To indicate if devices on link need to be disconnected. + * + * Called as part of session destroy + * return success/failure + */ +int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info, + bool is_shutdown); + +/** + * cam_req_mgr_link() + * @brief : creates a link for a session + * @link_info : handle and session info to create a link + * + * link is formed in a session for multiple devices. it creates + * a unique link handle for the link and is specific to a + * session. Returns link handle + */ +int cam_req_mgr_link(struct cam_req_mgr_ver_info *link_info); +int cam_req_mgr_link_v2(struct cam_req_mgr_ver_info *link_info); + + +/** + * cam_req_mgr_unlink() + * @brief : destroy a link in a session + * @unlink_info : session and link handle info + * + * link is destroyed in a session + */ +int cam_req_mgr_unlink(struct cam_req_mgr_unlink_info *unlink_info); + +/** + * cam_req_mgr_schedule_request() + * @brief: Request is scheduled + * @sched_req: request id, session and link id info, bubble recovery info + */ +int cam_req_mgr_schedule_request( + struct cam_req_mgr_sched_request *sched_req); + +/** + * cam_req_mgr_sync_mode_setup() + * @brief: sync for links in a session + * @sync_info: session, links info and master link info + */ +int cam_req_mgr_sync_config(struct cam_req_mgr_sync_mode *sync_info); + +/** + * cam_req_mgr_flush_requests() + * @brief: flush all requests + * @flush_info: requests related to link and session + */ +int cam_req_mgr_flush_requests( + struct cam_req_mgr_flush_info *flush_info); + +/** + * cam_req_mgr_core_device_init() + * @brief: initialize crm core + */ +int cam_req_mgr_core_device_init(void); + +/** + * cam_req_mgr_core_device_deinit() + * @brief: cleanp crm core + */ +int cam_req_mgr_core_device_deinit(void); + +/** + * cam_req_mgr_handle_core_shutdown() + * @brief: Handles camera close + */ +void cam_req_mgr_handle_core_shutdown(void); + +/** + * cam_req_mgr_link_control() + * @brief: Handles link control operations + * @control: Link control command + */ +int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control); + +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core_defs.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..fbaa7de494f7225125d60c94bafe57ada0f70adb --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_core_defs.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_REQ_MGR_CORE_DEFS_H_ +#define _CAM_REQ_MGR_CORE_DEFS_H_ + +#define CRM_TRACE_ENABLE 0 +#define CRM_DEBUG_MUTEX 0 + +#define SET_SUCCESS_BIT(ret, pd) (ret |= (1 << (pd))) + +#define SET_FAILURE_BIT(ret, pd) (ret &= (~(1 << (pd)))) + +#define CRM_GET_REQ_ID(in_q, idx) in_q->slot[idx].req_id + +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_debug.c b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..6b428c41c1b02705343a56b5b92c44b94499184c --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_debug.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_req_mgr_debug.h" + +#define MAX_SESS_INFO_LINE_BUFF_LEN 256 + +static char sess_info_buffer[MAX_SESS_INFO_LINE_BUFF_LEN]; + +static int cam_req_mgr_debug_set_bubble_recovery(void *data, u64 val) +{ + struct cam_req_mgr_core_device *core_dev = data; + struct cam_req_mgr_core_session *session; + int rc = 0; + + mutex_lock(&core_dev->crm_lock); + + if (!list_empty(&core_dev->session_head)) { + list_for_each_entry(session, + &core_dev->session_head, entry) { + session->force_err_recovery = val; + } + } + + mutex_unlock(&core_dev->crm_lock); + + return rc; +} + +static int cam_req_mgr_debug_get_bubble_recovery(void *data, u64 *val) +{ + struct cam_req_mgr_core_device *core_dev = data; + struct cam_req_mgr_core_session *session; + + mutex_lock(&core_dev->crm_lock); + + if (!list_empty(&core_dev->session_head)) { + session = list_first_entry(&core_dev->session_head, + struct cam_req_mgr_core_session, + entry); + *val = session->force_err_recovery; + } + mutex_unlock(&core_dev->crm_lock); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(bubble_recovery, cam_req_mgr_debug_get_bubble_recovery, + cam_req_mgr_debug_set_bubble_recovery, "%lld\n"); + +static int session_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t session_info_read(struct file *t_file, char *t_char, + size_t t_size_t, loff_t *t_loff_t) +{ + int i; + char *out_buffer = sess_info_buffer; + char line_buffer[MAX_SESS_INFO_LINE_BUFF_LEN] = {0}; + struct cam_req_mgr_core_device *core_dev = + (struct cam_req_mgr_core_device *) t_file->private_data; + struct cam_req_mgr_core_session *session; + + memset(out_buffer, 0, MAX_SESS_INFO_LINE_BUFF_LEN); + + mutex_lock(&core_dev->crm_lock); + + if (!list_empty(&core_dev->session_head)) { + list_for_each_entry(session, + &core_dev->session_head, entry) { + snprintf(line_buffer, sizeof(line_buffer), + "session_hdl = %x \t" + "num_links = %d\n", + session->session_hdl, session->num_links); + strlcat(out_buffer, line_buffer, + sizeof(sess_info_buffer)); + for (i = 0; i < session->num_links; i++) { + snprintf(line_buffer, sizeof(line_buffer), + "link_hdl[%d] = 0x%x, num_devs connected = %d\n", + i, session->links[i]->link_hdl, + session->links[i]->num_devs); + strlcat(out_buffer, line_buffer, + sizeof(sess_info_buffer)); + } + } + } + + mutex_unlock(&core_dev->crm_lock); + + return simple_read_from_buffer(t_char, t_size_t, + t_loff_t, out_buffer, strlen(out_buffer)); +} + +static ssize_t session_info_write(struct file *t_file, + const char *t_char, size_t t_size_t, loff_t *t_loff_t) +{ + memset(sess_info_buffer, 0, MAX_SESS_INFO_LINE_BUFF_LEN); + + return 0; +} + +static const struct file_operations session_info = { + .open = session_info_open, + .read = session_info_read, + .write = session_info_write, +}; + +int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev) +{ + struct dentry *debugfs_root; + char dirname[32] = {0}; + + snprintf(dirname, sizeof(dirname), "cam_req_mgr"); + debugfs_root = debugfs_create_dir(dirname, NULL); + if (!debugfs_root) + return -ENOMEM; + + if (!debugfs_create_file("sessions_info", 0644, + debugfs_root, core_dev, &session_info)) + return -ENOMEM; + + if (!debugfs_create_file("bubble_recovery", 0644, + debugfs_root, core_dev, &bubble_recovery)) + return -ENOMEM; + + return 0; +} diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_debug.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..dc72c522d140e56c7b58db5b57d653d0e94200d6 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_debug.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_DEBUG_H_ +#define _CAM_REQ_MGR_DEBUG_H_ + +#include <linux/debugfs.h> +#include "cam_req_mgr_core.h" + +int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev); + +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.c b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.c new file mode 100755 index 0000000000000000000000000000000000000000..c778401374845c410cf6df030f3fec92a2f0b872 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.c @@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/cam_req_mgr.h> +#include <media/cam_defs.h> +#include "cam_req_mgr_dev.h" +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_core.h" +#include "cam_subdev.h" +#include "cam_mem_mgr.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" +#include <linux/slub_def.h> + +#define CAM_REQ_MGR_EVENT_MAX 64 + +static struct cam_req_mgr_device g_dev; +struct kmem_cache *g_cam_req_mgr_timer_cachep; + +static int cam_media_device_setup(struct device *dev) +{ + int rc; + + g_dev.v4l2_dev->mdev = kzalloc(sizeof(*g_dev.v4l2_dev->mdev), + GFP_KERNEL); + if (!g_dev.v4l2_dev->mdev) { + rc = -ENOMEM; + goto mdev_fail; + } + + media_device_init(g_dev.v4l2_dev->mdev); + g_dev.v4l2_dev->mdev->dev = dev; + strlcpy(g_dev.v4l2_dev->mdev->model, CAM_REQ_MGR_VNODE_NAME, + sizeof(g_dev.v4l2_dev->mdev->model)); + + rc = media_device_register(g_dev.v4l2_dev->mdev); + if (rc) + goto media_fail; + + return rc; + +media_fail: + kfree(g_dev.v4l2_dev->mdev); + g_dev.v4l2_dev->mdev = NULL; +mdev_fail: + return rc; +} + +static void cam_media_device_cleanup(void) +{ + media_entity_cleanup(&g_dev.video->entity); + media_device_unregister(g_dev.v4l2_dev->mdev); + kfree(g_dev.v4l2_dev->mdev); + g_dev.v4l2_dev->mdev = NULL; +} + +static int cam_v4l2_device_setup(struct device *dev) +{ + int rc; + + g_dev.v4l2_dev = kzalloc(sizeof(*g_dev.v4l2_dev), + GFP_KERNEL); + if (!g_dev.v4l2_dev) + return -ENOMEM; + + rc = v4l2_device_register(dev, g_dev.v4l2_dev); + if (rc) + goto reg_fail; + + return rc; + +reg_fail: + kfree(g_dev.v4l2_dev); + g_dev.v4l2_dev = NULL; + return rc; +} + +static void cam_v4l2_device_cleanup(void) +{ + v4l2_device_unregister(g_dev.v4l2_dev); + kfree(g_dev.v4l2_dev); + g_dev.v4l2_dev = NULL; +} + +static int cam_req_mgr_open(struct file *filep) +{ + int rc; + + mutex_lock(&g_dev.cam_lock); + if (g_dev.open_cnt >= 1) { + rc = -EALREADY; + goto end; + } + + rc = v4l2_fh_open(filep); + if (rc) { + CAM_ERR(CAM_CRM, "v4l2_fh_open failed: %d", rc); + goto end; + } + + spin_lock_bh(&g_dev.cam_eventq_lock); + g_dev.cam_eventq = filep->private_data; + spin_unlock_bh(&g_dev.cam_eventq_lock); + + g_dev.open_cnt++; + rc = cam_mem_mgr_init(); + if (rc) { + g_dev.open_cnt--; + CAM_ERR(CAM_CRM, "mem mgr init failed"); + goto mem_mgr_init_fail; + } + + mutex_unlock(&g_dev.cam_lock); + return rc; + +mem_mgr_init_fail: + v4l2_fh_release(filep); +end: + mutex_unlock(&g_dev.cam_lock); + return rc; +} + +static unsigned int cam_req_mgr_poll(struct file *f, + struct poll_table_struct *pll_table) +{ + int rc = 0; + struct v4l2_fh *eventq = f->private_data; + + if (!eventq) + return -EINVAL; + + poll_wait(f, &eventq->wait, pll_table); + if (v4l2_event_pending(eventq)) + rc = POLLPRI; + + return rc; +} + +static int cam_req_mgr_close(struct file *filep) +{ + struct v4l2_subdev *sd; + struct v4l2_fh *vfh = filep->private_data; + struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); + + CAM_WARN(CAM_CRM, + "release invoked associated userspace process has died"); + mutex_lock(&g_dev.cam_lock); + + if (g_dev.open_cnt <= 0) { + mutex_unlock(&g_dev.cam_lock); + return -EINVAL; + } + + cam_req_mgr_handle_core_shutdown(); + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + continue; + if (sd->internal_ops && sd->internal_ops->close) { + CAM_DBG(CAM_CRM, "Invoke subdev close for device %s", + sd->name); + sd->internal_ops->close(sd, subdev_fh); + } + } + + g_dev.open_cnt--; + v4l2_fh_release(filep); + + spin_lock_bh(&g_dev.cam_eventq_lock); + g_dev.cam_eventq = NULL; + spin_unlock_bh(&g_dev.cam_eventq_lock); + + cam_req_mgr_util_free_hdls(); + cam_mem_mgr_deinit(); + mutex_unlock(&g_dev.cam_lock); + + return 0; +} + +static struct v4l2_file_operations g_cam_fops = { + .owner = THIS_MODULE, + .open = cam_req_mgr_open, + .poll = cam_req_mgr_poll, + .release = cam_req_mgr_close, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif +}; + +static void cam_v4l2_event_queue_notify_error(const struct v4l2_event *old, + struct v4l2_event *new) +{ + struct cam_req_mgr_message *ev_header; + + ev_header = CAM_REQ_MGR_GET_PAYLOAD_PTR((*old), + struct cam_req_mgr_message); + + switch (old->id) { + case V4L_EVENT_CAM_REQ_MGR_SOF: + case V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS: + if (ev_header->u.frame_msg.request_id) + CAM_ERR(CAM_CRM, + "Failed to notify %s Sess %X FrameId %lld FrameMeta %d ReqId %lld link %X", + ((old->id == V4L_EVENT_CAM_REQ_MGR_SOF) ? + "SOF_TS" : "BOOT_TS"), + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.frame_id_meta, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); + else + CAM_WARN_RATE_LIMIT_CUSTOM(CAM_CRM, 5, 1, + "Failed to notify %s Sess %X FrameId %lld FrameMeta %d ReqId %lld link %X", + ((old->id == V4L_EVENT_CAM_REQ_MGR_SOF) ? + "SOF_TS" : "BOOT_TS"), + ev_header->session_hdl, + ev_header->u.frame_msg.frame_id, + ev_header->u.frame_msg.frame_id_meta, + ev_header->u.frame_msg.request_id, + ev_header->u.frame_msg.link_hdl); + break; + case V4L_EVENT_CAM_REQ_MGR_ERROR: + CAM_ERR(CAM_CRM, + "Failed to notify ERROR Sess %X ReqId %d Link %X Type %d", + ev_header->session_hdl, + ev_header->u.err_msg.request_id, + ev_header->u.err_msg.link_hdl, + ev_header->u.err_msg.error_type); + break; + default: + CAM_ERR(CAM_CRM, "Failed to notify crm event id %d", + old->id); + } +} + +static struct v4l2_subscribed_event_ops g_cam_v4l2_ops = { + .merge = cam_v4l2_event_queue_notify_error, +}; + +static int cam_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, CAM_REQ_MGR_EVENT_MAX, + &g_cam_v4l2_ops); +} + +static int cam_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static long cam_private_ioctl(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int rc; + struct cam_control *k_ioctl; + + if ((!arg) || (cmd != VIDIOC_CAM_CONTROL)) + return -EINVAL; + + k_ioctl = (struct cam_control *)arg; + + if (!k_ioctl->handle) + return -EINVAL; + + switch (k_ioctl->op_code) { + case CAM_REQ_MGR_CREATE_SESSION: { + struct cam_req_mgr_session_info ses_info; + + if (k_ioctl->size != sizeof(ses_info)) + return -EINVAL; + + if (copy_from_user(&ses_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_session_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_create_session(&ses_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ses_info, + sizeof(struct cam_req_mgr_session_info))) + rc = -EFAULT; + } + break; + + case CAM_REQ_MGR_DESTROY_SESSION: { + struct cam_req_mgr_session_info ses_info; + + if (k_ioctl->size != sizeof(ses_info)) + return -EINVAL; + + if (copy_from_user(&ses_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_session_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_destroy_session(&ses_info, false); + } + break; + + case CAM_REQ_MGR_LINK: { + struct cam_req_mgr_ver_info ver_info; + + if (k_ioctl->size != sizeof(ver_info.u.link_info_v1)) + return -EINVAL; + + if (copy_from_user(&ver_info.u.link_info_v1, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info))) { + return -EFAULT; + } + ver_info.version = VERSION_1; + rc = cam_req_mgr_link(&ver_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ver_info.u.link_info_v1, + sizeof(struct cam_req_mgr_link_info))) + rc = -EFAULT; + } + break; + + case CAM_REQ_MGR_LINK_V2: { + struct cam_req_mgr_ver_info ver_info; + + if (k_ioctl->size != sizeof(ver_info.u.link_info_v2)) + return -EINVAL; + + if (copy_from_user(&ver_info.u.link_info_v2, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_info_v2))) { + return -EFAULT; + } + + ver_info.version = VERSION_2; + rc = cam_req_mgr_link_v2(&ver_info); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ver_info.u.link_info_v2, + sizeof(struct cam_req_mgr_link_info_v2))) + rc = -EFAULT; + } + break; + + case CAM_REQ_MGR_UNLINK: { + struct cam_req_mgr_unlink_info unlink_info; + + if (k_ioctl->size != sizeof(unlink_info)) + return -EINVAL; + + if (copy_from_user(&unlink_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_unlink_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_unlink(&unlink_info); + } + break; + + case CAM_REQ_MGR_SCHED_REQ: { + struct cam_req_mgr_sched_request sched_req; + + if (k_ioctl->size != sizeof(sched_req)) + return -EINVAL; + + if (copy_from_user(&sched_req, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_sched_request))) { + return -EFAULT; + } + + rc = cam_req_mgr_schedule_request(&sched_req); + } + break; + + case CAM_REQ_MGR_FLUSH_REQ: { + struct cam_req_mgr_flush_info flush_info; + + if (k_ioctl->size != sizeof(flush_info)) + return -EINVAL; + + if (copy_from_user(&flush_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_flush_info))) { + return -EFAULT; + } + + rc = cam_req_mgr_flush_requests(&flush_info); + } + break; + + case CAM_REQ_MGR_SYNC_MODE: { + struct cam_req_mgr_sync_mode sync_info; + + if (k_ioctl->size != sizeof(sync_info)) + return -EINVAL; + + if (copy_from_user(&sync_info, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_sync_mode))) { + return -EFAULT; + } + + rc = cam_req_mgr_sync_config(&sync_info); + } + break; + case CAM_REQ_MGR_ALLOC_BUF: { + struct cam_mem_mgr_alloc_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_mgr_alloc_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_alloc_and_map(&cmd); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &cmd, sizeof(struct cam_mem_mgr_alloc_cmd))) { + rc = -EFAULT; + break; + } + } + break; + case CAM_REQ_MGR_MAP_BUF: { + struct cam_mem_mgr_map_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_mgr_map_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_map(&cmd); + if (!rc) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &cmd, sizeof(struct cam_mem_mgr_map_cmd))) { + rc = -EFAULT; + break; + } + } + break; + case CAM_REQ_MGR_RELEASE_BUF: { + struct cam_mem_mgr_release_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_mgr_release_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_release(&cmd); + } + break; + case CAM_REQ_MGR_CACHE_OPS: { + struct cam_mem_cache_ops_cmd cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_mem_cache_ops_cmd))) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_cache_ops(&cmd); + if (rc) + rc = -EINVAL; + } + break; + case CAM_REQ_MGR_LINK_CONTROL: { + struct cam_req_mgr_link_control cmd; + + if (k_ioctl->size != sizeof(cmd)) + return -EINVAL; + + if (copy_from_user(&cmd, + u64_to_user_ptr(k_ioctl->handle), + sizeof(struct cam_req_mgr_link_control))) { + rc = -EFAULT; + break; + } + + rc = cam_req_mgr_link_control(&cmd); + if (rc) + rc = -EINVAL; + } + break; + default: + return -ENOIOCTLCMD; + } + + return rc; +} + +static const struct v4l2_ioctl_ops g_cam_ioctl_ops = { + .vidioc_subscribe_event = cam_subscribe_event, + .vidioc_unsubscribe_event = cam_unsubscribe_event, + .vidioc_default = cam_private_ioctl, +}; + +static int cam_video_device_setup(void) +{ + int rc; + + g_dev.video = video_device_alloc(); + if (!g_dev.video) { + rc = -ENOMEM; + goto video_fail; + } + + g_dev.video->v4l2_dev = g_dev.v4l2_dev; + + strlcpy(g_dev.video->name, "cam-req-mgr", + sizeof(g_dev.video->name)); + g_dev.video->release = video_device_release; + g_dev.video->fops = &g_cam_fops; + g_dev.video->ioctl_ops = &g_cam_ioctl_ops; + g_dev.video->minor = -1; + g_dev.video->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(g_dev.video, VFL_TYPE_GRABBER, -1); + if (rc) + goto v4l2_fail; + + rc = media_entity_pads_init(&g_dev.video->entity, 0, NULL); + if (rc) + goto entity_fail; + + g_dev.video->entity.function = CAM_VNODE_DEVICE_TYPE; + g_dev.video->entity.name = video_device_node_name(g_dev.video); + + return rc; + +entity_fail: + video_unregister_device(g_dev.video); +v4l2_fail: + video_device_release(g_dev.video); + g_dev.video = NULL; +video_fail: + return rc; +} + +int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg, + uint32_t id, + uint32_t type) +{ + struct v4l2_event event; + struct cam_req_mgr_message *ev_header; + + if (!msg) + return -EINVAL; + + event.id = id; + event.type = type; + ev_header = CAM_REQ_MGR_GET_PAYLOAD_PTR(event, + struct cam_req_mgr_message); + memcpy(ev_header, msg, sizeof(struct cam_req_mgr_message)); + v4l2_event_queue(g_dev.video, &event); + + return 0; +} +EXPORT_SYMBOL(cam_req_mgr_notify_message); + +void cam_video_device_cleanup(void) +{ + video_unregister_device(g_dev.video); + video_device_release(g_dev.video); + g_dev.video = NULL; +} + +void cam_register_subdev_fops(struct v4l2_file_operations *fops) +{ + *fops = v4l2_subdev_fops; +} +EXPORT_SYMBOL(cam_register_subdev_fops); + +int cam_register_subdev(struct cam_subdev *csd) +{ + struct v4l2_subdev *sd; + int rc; + + if (g_dev.state != true) { + CAM_ERR(CAM_CRM, "camera root device not ready yet"); + return -ENODEV; + } + + if (!csd || !csd->name) { + CAM_ERR(CAM_CRM, "invalid arguments"); + return -EINVAL; + } + + mutex_lock(&g_dev.dev_lock); + if ((g_dev.subdev_nodes_created) && + (csd->sd_flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) { + CAM_ERR(CAM_CRM, + "dynamic node is not allowed, name: %s, type :%d", + csd->name, csd->ent_function); + rc = -EINVAL; + goto reg_fail; + } + + sd = &csd->sd; + v4l2_subdev_init(sd, csd->ops); + sd->internal_ops = csd->internal_ops; + snprintf(sd->name, ARRAY_SIZE(sd->name), csd->name); + v4l2_set_subdevdata(sd, csd->token); + + sd->flags = csd->sd_flags; + sd->entity.num_pads = 0; + sd->entity.pads = NULL; + sd->entity.function = csd->ent_function; + + rc = v4l2_device_register_subdev(g_dev.v4l2_dev, sd); + if (rc) { + CAM_ERR(CAM_CRM, "register subdev failed"); + goto reg_fail; + } + g_dev.count++; + +reg_fail: + mutex_unlock(&g_dev.dev_lock); + return rc; +} +EXPORT_SYMBOL(cam_register_subdev); + +int cam_unregister_subdev(struct cam_subdev *csd) +{ + if (g_dev.state != true) { + CAM_ERR(CAM_CRM, "camera root device not ready yet"); + return -ENODEV; + } + + mutex_lock(&g_dev.dev_lock); + v4l2_device_unregister_subdev(&csd->sd); + g_dev.count--; + mutex_unlock(&g_dev.dev_lock); + + return 0; +} +EXPORT_SYMBOL(cam_unregister_subdev); + +static int cam_req_mgr_remove(struct platform_device *pdev) +{ + cam_req_mgr_core_device_deinit(); + cam_req_mgr_util_deinit(); + cam_media_device_cleanup(); + cam_video_device_cleanup(); + cam_v4l2_device_cleanup(); + mutex_destroy(&g_dev.dev_lock); + g_dev.state = false; + g_dev.subdev_nodes_created = false; + + return 0; +} + +static int cam_req_mgr_probe(struct platform_device *pdev) +{ + int rc; + + rc = cam_v4l2_device_setup(&pdev->dev); + if (rc) + return rc; + + rc = cam_media_device_setup(&pdev->dev); + if (rc) + goto media_setup_fail; + + rc = cam_video_device_setup(); + if (rc) + goto video_setup_fail; + + g_dev.open_cnt = 0; + mutex_init(&g_dev.cam_lock); + spin_lock_init(&g_dev.cam_eventq_lock); + g_dev.subdev_nodes_created = false; + mutex_init(&g_dev.dev_lock); + + rc = cam_req_mgr_util_init(); + if (rc) { + CAM_ERR(CAM_CRM, "cam req mgr util init is failed"); + goto req_mgr_util_fail; + } + + rc = cam_req_mgr_core_device_init(); + if (rc) { + CAM_ERR(CAM_CRM, "core device setup failed"); + goto req_mgr_core_fail; + } + + g_dev.state = true; + + if (g_cam_req_mgr_timer_cachep == NULL) { + g_cam_req_mgr_timer_cachep = kmem_cache_create("crm_timer", + sizeof(struct cam_req_mgr_timer), 64, + SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | + SLAB_POISON | SLAB_STORE_USER, NULL); + if (!g_cam_req_mgr_timer_cachep) + CAM_ERR(CAM_CRM, + "Failed to create kmem_cache for crm_timer"); + else + CAM_DBG(CAM_CRM, "Name : %s", + g_cam_req_mgr_timer_cachep->name); + } + + return rc; + +req_mgr_core_fail: + cam_req_mgr_util_deinit(); +req_mgr_util_fail: + mutex_destroy(&g_dev.dev_lock); + mutex_destroy(&g_dev.cam_lock); + cam_video_device_cleanup(); +video_setup_fail: + cam_media_device_cleanup(); +media_setup_fail: + cam_v4l2_device_cleanup(); + return rc; +} + +static const struct of_device_id cam_req_mgr_dt_match[] = { + {.compatible = "qcom,cam-req-mgr"}, + {} +}; +MODULE_DEVICE_TABLE(of, cam_dt_match); + +static struct platform_driver cam_req_mgr_driver = { + .probe = cam_req_mgr_probe, + .remove = cam_req_mgr_remove, + .driver = { + .name = "cam_req_mgr", + .owner = THIS_MODULE, + .of_match_table = cam_req_mgr_dt_match, + .suppress_bind_attrs = true, + }, +}; + +int cam_dev_mgr_create_subdev_nodes(void) +{ + int rc; + struct v4l2_subdev *sd; + + if (!g_dev.v4l2_dev) + return -EINVAL; + + if (g_dev.state != true) { + CAM_ERR(CAM_CRM, "camera root device not ready yet"); + return -ENODEV; + } + + mutex_lock(&g_dev.dev_lock); + if (g_dev.subdev_nodes_created) { + rc = -EEXIST; + goto create_fail; + } + + rc = v4l2_device_register_subdev_nodes(g_dev.v4l2_dev); + if (rc) { + CAM_ERR(CAM_CRM, "failed to register the sub devices"); + goto create_fail; + } + + list_for_each_entry(sd, &g_dev.v4l2_dev->subdevs, list) { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + continue; + sd->entity.name = video_device_node_name(sd->devnode); + CAM_DBG(CAM_CRM, "created node :%s", sd->entity.name); + } + + g_dev.subdev_nodes_created = true; + +create_fail: + mutex_unlock(&g_dev.dev_lock); + return rc; +} + +static int __init cam_req_mgr_init(void) +{ + return platform_driver_register(&cam_req_mgr_driver); +} + +static int __init cam_req_mgr_late_init(void) +{ + return cam_dev_mgr_create_subdev_nodes(); +} + +static void __exit cam_req_mgr_exit(void) +{ + platform_driver_unregister(&cam_req_mgr_driver); +} + +module_init(cam_req_mgr_init); +late_initcall(cam_req_mgr_late_init); +module_exit(cam_req_mgr_exit); +MODULE_DESCRIPTION("Camera Request Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..48ad09ce5ee218d92799a60781b2e672610d52df --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_dev.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_DEV_H_ +#define _CAM_REQ_MGR_DEV_H_ + +/** + * struct cam_req_mgr_device - a camera request manager device + * + * @video: pointer to struct video device. + * @v4l2_dev: pointer to struct v4l2 device. + * @subdev_nodes_created: flag to check the created state. + * @count: number of subdevices registered. + * @dev_lock: lock for the subdevice count. + * @state: state of the root device. + * @open_cnt: open count of subdev + * @cam_lock: per file handle lock + * @cam_eventq: event queue + * @cam_eventq_lock: lock for event queue + */ +struct cam_req_mgr_device { + struct video_device *video; + struct v4l2_device *v4l2_dev; + bool subdev_nodes_created; + int count; + struct mutex dev_lock; + bool state; + int32_t open_cnt; + struct mutex cam_lock; + struct v4l2_fh *cam_eventq; + spinlock_t cam_eventq_lock; +}; + +#define CAM_REQ_MGR_GET_PAYLOAD_PTR(ev, type) \ + (type *)((char *)ev.u.data) + +int cam_req_mgr_notify_message(struct cam_req_mgr_message *msg, + uint32_t id, + uint32_t type); + +#endif /* _CAM_REQ_MGR_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_interface.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..68ab7917e9471b88b3956bd55d86c549b5165ca3 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_interface.h @@ -0,0 +1,369 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_INTERFACE_H +#define _CAM_REQ_MGR_INTERFACE_H + +#include <linux/types.h> +#include <media/cam_req_mgr.h> +#include "cam_req_mgr_core_defs.h" +#include "cam_req_mgr_util.h" + +struct cam_req_mgr_trigger_notify; +struct cam_req_mgr_error_notify; +struct cam_req_mgr_add_request; +struct cam_req_mgr_timer_notify; +struct cam_req_mgr_notify_stop; +struct cam_req_mgr_device_info; +struct cam_req_mgr_core_dev_link_setup; +struct cam_req_mgr_apply_request; +struct cam_req_mgr_flush_request; +struct cam_req_mgr_link_evt_data; + +#define SKIP_NEXT_FRAME 0x100 + +/* Request Manager -- camera device driver interface */ +/** + * @brief: camera kernel drivers to cam req mgr communication + * + * @cam_req_mgr_notify_trigger: for device which generates trigger to inform CRM + * @cam_req_mgr_notify_err : device use this to inform about different errors + * @cam_req_mgr_add_req : to info CRm about new rqeuest received from + * userspace + */ +typedef int (*cam_req_mgr_notify_trigger)( + struct cam_req_mgr_trigger_notify *); +typedef int (*cam_req_mgr_notify_err)(struct cam_req_mgr_error_notify *); +typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); +typedef int (*cam_req_mgr_notify_timer)(struct cam_req_mgr_timer_notify *); +typedef int (*cam_req_mgr_notify_stop)(struct cam_req_mgr_notify_stop *); + +/** + * @brief: cam req mgr to camera device drivers + * + * @cam_req_mgr_get_dev_info: to fetch details about device linked + * @cam_req_mgr_link_setup : to establish link with device for a session + * @cam_req_mgr_notify_err : to broadcast error happened on link for request id + * @cam_req_mgr_apply_req : CRM asks device to apply certain request id. + * @cam_req_mgr_flush_req : Flush or cancel request + * cam_req_mgr_process_evt : generic events + */ +typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *); +typedef int (*cam_req_mgr_link_setup)( + struct cam_req_mgr_core_dev_link_setup *); +typedef int (*cam_req_mgr_apply_req)(struct cam_req_mgr_apply_request *); +typedef int (*cam_req_mgr_flush_req)(struct cam_req_mgr_flush_request *); +typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *); + +/** + * @brief : cam_req_mgr_crm_cb - func table + * + * @notify_trigger : payload for trigger indication event + * @notify_err : payload for different error occurred at device + * @add_req : payload to inform which device and what request is received + * @notify_stop : payload to inform stop event + */ +struct cam_req_mgr_crm_cb { + cam_req_mgr_notify_trigger notify_trigger; + cam_req_mgr_notify_err notify_err; + cam_req_mgr_add_req add_req; + cam_req_mgr_notify_timer notify_timer; + cam_req_mgr_notify_stop notify_stop; +}; + +/** + * @brief : cam_req_mgr_kmd_ops - func table + * + * @get_dev_info : payload to fetch device details + * @link_setup : payload to establish link with device + * @apply_req : payload to apply request id on a device linked + * @flush_req : payload to flush request + * @process_evt : payload to generic event + */ +struct cam_req_mgr_kmd_ops { + cam_req_mgr_get_dev_info get_dev_info; + cam_req_mgr_link_setup link_setup; + cam_req_mgr_apply_req apply_req; + cam_req_mgr_flush_req flush_req; + cam_req_mgr_process_evt process_evt; +}; + +/** + * enum cam_pipeline_delay + * @brief : enumerator for different pipeline delays in camera + * + * @DELAY_0 : device processed settings on same frame + * @DELAY_1 : device processed settings after 1 frame + * @DELAY_2 : device processed settings after 2 frames + * @DELAY_MAX : maximum supported pipeline delay + */ +enum cam_pipeline_delay { + CAM_PIPELINE_DELAY_0, + CAM_PIPELINE_DELAY_1, + CAM_PIPELINE_DELAY_2, + CAM_PIPELINE_DELAY_MAX, +}; + +/** + * @CAM_TRIGGER_POINT_SOF : Trigger point for SOF + * @CAM_TRIGGER_POINT_EOF : Trigger point for EOF + */ +#define CAM_TRIGGER_POINT_SOF (1 << 0) +#define CAM_TRIGGER_POINT_EOF (1 << 1) + +/** + * enum cam_req_status + * @brief : enumerator for request status + * + * @SUCCESS : device processed settings successfully + * @FAILED : device processed settings failed + * @MAX : invalid status value + */ +enum cam_req_status { + CAM_REQ_STATUS_SUCCESS, + CAM_REQ_STATUS_FAILED, + CAM_REQ_STATUS_MAX, +}; + +/** + * enum cam_req_mgr_device_error + * @brief : enumerator for different errors occurred at device + * + * @NOT_FOUND : settings asked by request manager is not found + * @BUBBLE : device hit timing issue and is able to recover + * @FATAL : device is in bad shape and can not recover from error + * @PAGE_FAULT : Page fault while accessing memory + * @OVERFLOW : Bus Overflow for IFE/VFE + * @TIMEOUT : Timeout from cci or bus. + * @MAX : Invalid error value + */ +enum cam_req_mgr_device_error { + CRM_KMD_ERR_NOT_FOUND, + CRM_KMD_ERR_BUBBLE, + CRM_KMD_ERR_FATAL, + CRM_KMD_ERR_PAGE_FAULT, + CRM_KMD_ERR_OVERFLOW, + CRM_KMD_ERR_TIMEOUT, + CRM_KMD_ERR_STOPPED, + CRM_KMD_ERR_MAX, +}; + +/** + * enum cam_req_mgr_device_id + * @brief : enumerator for different devices in subsystem + * + * @CAM_REQ_MGR : request manager itself + * @SENSOR : sensor device + * @FLASH : LED flash or dual LED device + * @ACTUATOR : lens mover + * @IFE : Image processing device + * @CUSTOM : Custom HW block + * @EXTERNAL_1 : third party device + * @EXTERNAL_2 : third party device + * @EXTERNAL_3 : third party device + * @MAX : invalid device id + */ +enum cam_req_mgr_device_id { + CAM_REQ_MGR_DEVICE, + CAM_REQ_MGR_DEVICE_SENSOR, + CAM_REQ_MGR_DEVICE_FLASH, + CAM_REQ_MGR_DEVICE_ACTUATOR, + CAM_REQ_MGR_DEVICE_IFE, + CAM_REQ_MGR_DEVICE_CUSTOM_HW, + CAM_REQ_MGR_DEVICE_EXTERNAL_1, + CAM_REQ_MGR_DEVICE_EXTERNAL_2, + CAM_REQ_MGR_DEVICE_EXTERNAL_3, + CAM_REQ_MGR_DEVICE_ID_MAX, +}; + +/* Camera device driver to Req Mgr device interface */ + +/** + * enum cam_req_mgr_link_evt_type + * @CAM_REQ_MGR_LINK_EVT_ERR : error on the link from any of the + * connected devices + * @CAM_REQ_MGR_LINK_EVT_PAUSE : to pause the link + * @CAM_REQ_MGR_LINK_EVT_RESUME : resumes the link which was paused + * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE : request manager has detected an sof freeze + * @CAM_REQ_MGR_LINK_EVT_MAX : invalid event type + */ +enum cam_req_mgr_link_evt_type { + CAM_REQ_MGR_LINK_EVT_ERR, + CAM_REQ_MGR_LINK_EVT_PAUSE, + CAM_REQ_MGR_LINK_EVT_RESUME, + CAM_REQ_MGR_LINK_EVT_SOF_FREEZE, + CAM_REQ_MGR_LINK_EVT_MAX, +}; + +/** + * struct cam_req_mgr_trigger_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @frame_id : frame id for internal tracking + * @trigger : trigger point of this notification, CRM will send apply + * only to the devices which subscribe to this point. + * @sof_timestamp_val: Captured time stamp value at sof hw event + * @req_id : req id which returned buf_done + */ +struct cam_req_mgr_trigger_notify { + int32_t link_hdl; + int32_t dev_hdl; + int64_t frame_id; + uint32_t trigger; + uint64_t sof_timestamp_val; + uint64_t req_id; +}; + +/** + * struct cam_req_mgr_timer_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @frame_id : frame id for internal tracking + * @state : timer state i.e ON or OFF + */ +struct cam_req_mgr_timer_notify { + int32_t link_hdl; + int32_t dev_hdl; + bool state; +}; + +/** + * struct cam_req_mgr_error_notify + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @req_id : req id which hit error + * @error : what error device hit while processing this req + */ +struct cam_req_mgr_error_notify { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + enum cam_req_mgr_device_error error; +}; + +/** + * struct cam_req_mgr_add_request + * @link_hdl : link identifier + * @dev_hdl : device handle which has sent this req id + * @req_id : req id which device is ready to process + * @skip_before_applying : before applying req mgr introduce bubble + * by not sending request to device/s. + * ex: IFE and Flash + */ +struct cam_req_mgr_add_request { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + uint32_t skip_before_applying; +}; + + +/** + * struct cam_req_mgr_notify_stop + * @link_hdl : link identifier + * + */ +struct cam_req_mgr_notify_stop { + int32_t link_hdl; +}; + + +/* CRM to KMD devices */ +/** + * struct cam_req_mgr_device_info + * @dev_hdl : Input_param : device handle for reference + * @name : link link or unlink + * @dev_id : device id info + * @p_delay : delay between time settings applied and take effect + * @trigger : Trigger point for the client + * + */ +struct cam_req_mgr_device_info { + int32_t dev_hdl; + char name[256]; + enum cam_req_mgr_device_id dev_id; + enum cam_pipeline_delay p_delay; + uint32_t trigger; +}; + +/** + * struct cam_req_mgr_core_dev_link_setup + * @link_enable : link link or unlink + * @link_hdl : link identifier + * @dev_hdl : device handle for reference + * @max_delay : max pipeline delay on this link + * @crm_cb : callback funcs to communicate with req mgr + * @subscribe_event : the mask of trigger points this link subscribes + * + */ +struct cam_req_mgr_core_dev_link_setup { + int32_t link_enable; + int32_t link_hdl; + int32_t dev_hdl; + enum cam_pipeline_delay max_delay; + struct cam_req_mgr_crm_cb *crm_cb; + uint32_t subscribe_event; +}; + +/** + * struct cam_req_mgr_apply_request + * @link_hdl : link identifier + * @dev_hdl : device handle for cross check + * @request_id : request id settings to apply + * @report_if_bubble : report to crm if failure in applying + * @trigger_point : the trigger point of this apply + * + */ +struct cam_req_mgr_apply_request { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t request_id; + int32_t report_if_bubble; + uint32_t trigger_point; +}; + +/** + * struct cam_req_mgr_flush_request + * @link_hdl : link identifier + * @dev_hdl : device handle for cross check + * @type : cancel request type flush all or a request + * @request_id : request id to cancel + * + */ +struct cam_req_mgr_flush_request { + int32_t link_hdl; + int32_t dev_hdl; + uint32_t type; + uint64_t req_id; +}; + +/** + * struct cam_req_mgr_event_data + * @link_hdl : link handle + * @req_id : request id + * + */ +struct cam_req_mgr_link_evt_data { + int32_t link_hdl; + int32_t dev_hdl; + uint64_t req_id; + + enum cam_req_mgr_link_evt_type evt_type; + union { + enum cam_req_mgr_device_error error; + } u; +}; + +/** + * struct cam_req_mgr_send_request + * @link_hdl : link identifier + * @idx : slot idx + * + */ +struct cam_req_mgr_send_request { + int32_t link_hdl; + struct cam_req_mgr_req_queue *in_q; +}; +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_timer.c b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..ba44534fa48dd31d31772f035d6feafdea539bcb --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_timer.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_req_mgr_timer.h" +#include "cam_debug_util.h" + +void crm_timer_reset(struct cam_req_mgr_timer *crm_timer) +{ + if (!crm_timer) + return; + CAM_DBG(CAM_CRM, "Starting timer to fire in %d ms. (jiffies=%lu)\n", + crm_timer->expires, jiffies); + mod_timer(&crm_timer->sys_timer, + (jiffies + msecs_to_jiffies(crm_timer->expires))); +} + +void crm_timer_callback(struct timer_list *timer_data) +{ + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + CAM_DBG(CAM_CRM, "timer %pK parent %pK", timer, timer->parent); + crm_timer_reset(timer); +} + +void crm_timer_modify(struct cam_req_mgr_timer *crm_timer, + int32_t expires) +{ + CAM_DBG(CAM_CRM, "new time %d", expires); + if (crm_timer) { + crm_timer->expires = expires; + crm_timer_reset(crm_timer); + } +} + +int crm_timer_init(struct cam_req_mgr_timer **timer, + int32_t expires, void *parent, void (*timer_cb)(struct timer_list *)) +{ + int ret = 0; + struct cam_req_mgr_timer *crm_timer = NULL; + + CAM_DBG(CAM_CRM, "init timer %d %pK", expires, *timer); + if (*timer == NULL) { + if (g_cam_req_mgr_timer_cachep) { + crm_timer = kmem_cache_alloc(g_cam_req_mgr_timer_cachep, + __GFP_ZERO | GFP_KERNEL); + if (!crm_timer) { + ret = -ENOMEM; + goto end; + } + } + + else { + ret = -ENOMEM; + goto end; + } + + if (timer_cb != NULL) + crm_timer->timer_cb = timer_cb; + else + crm_timer->timer_cb = crm_timer_callback; + + crm_timer->expires = expires; + crm_timer->parent = parent; + timer_setup(&crm_timer->sys_timer, + crm_timer->timer_cb, 0); + crm_timer_reset(crm_timer); + *timer = crm_timer; + } else { + CAM_WARN(CAM_CRM, "Timer already exists!!"); + ret = -EINVAL; + } +end: + return ret; +} +void crm_timer_exit(struct cam_req_mgr_timer **crm_timer) +{ + CAM_DBG(CAM_CRM, "destroy timer %pK @ %pK", *crm_timer, crm_timer); + if (*crm_timer) { + del_timer_sync(&(*crm_timer)->sys_timer); + if (g_cam_req_mgr_timer_cachep) + kmem_cache_free(g_cam_req_mgr_timer_cachep, *crm_timer); + *crm_timer = NULL; + } +} diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_timer.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..be200f1b2693b6a9ee887270bbface5a0f7fa1f3 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_timer.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_TIMER_H_ +#define _CAM_REQ_MGR_TIMER_H_ + +#include <linux/slab.h> +#include <linux/timer.h> + +#include "cam_req_mgr_core_defs.h" + +/** struct cam_req_mgr_timer + * @expires : timeout value for timer + * @sys_timer : system timer variable + * @parent : priv data - link pointer + * @timer_cb : callback func which will be called when timeout expires + * @pause_timer : flag to pause SOF timer + */ +struct cam_req_mgr_timer { + int32_t expires; + struct timer_list sys_timer; + void *parent; + void (*timer_cb)(struct timer_list *timer_data); + bool pause_timer; +}; + +/** + * crm_timer_modify() + * @brief : allows ser to modify expiry time. + * @timer : timer which will be reset to expires values + */ +void crm_timer_modify(struct cam_req_mgr_timer *crm_timer, + int32_t expires); + +/** + * crm_timer_reset() + * @brief : destroys the timer allocated. + * @timer : timer which will be reset to expires values + */ +void crm_timer_reset(struct cam_req_mgr_timer *timer); + +/** + * crm_timer_init() + * @brief : create a new general purpose timer. + * timer utility takes care of allocating memory and deleting + * @timer : double pointer to new timer allocated + * @expires : Timeout value to fire callback + * @parent : void pointer which caller can use for book keeping + * @timer_cb : caller can chose to use its own callback function when + * timer fires the timeout. If no value is set timer util + * will use default. + */ +int crm_timer_init(struct cam_req_mgr_timer **timer, + int32_t expires, void *parent, void (*timer_cb)(struct timer_list *)); + +/** + * crm_timer_exit() + * @brief : destroys the timer allocated. + * @timer : timer pointer which will be freed + */ +void crm_timer_exit(struct cam_req_mgr_timer **timer); + +extern struct kmem_cache *g_cam_req_mgr_timer_cachep; +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util.c b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util.c new file mode 100644 index 0000000000000000000000000000000000000000..88b6bf079e9ccc31f463f812901f6b62a0bb675c --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/random.h> +#include <media/cam_req_mgr.h> +#include "cam_req_mgr_util.h" +#include "cam_debug_util.h" + +static struct cam_req_mgr_util_hdl_tbl *hdl_tbl; +static DEFINE_SPINLOCK(hdl_tbl_lock); + +int cam_req_mgr_util_init(void) +{ + int rc = 0; + int bitmap_size; + static struct cam_req_mgr_util_hdl_tbl *hdl_tbl_local; + + if (hdl_tbl) { + rc = -EINVAL; + CAM_ERR(CAM_CRM, "Hdl_tbl is already present"); + goto hdl_tbl_check_failed; + } + + hdl_tbl_local = kzalloc(sizeof(*hdl_tbl), GFP_KERNEL); + if (!hdl_tbl_local) { + rc = -ENOMEM; + goto hdl_tbl_alloc_failed; + } + spin_lock_bh(&hdl_tbl_lock); + if (hdl_tbl) { + spin_unlock_bh(&hdl_tbl_lock); + rc = -EEXIST; + kfree(hdl_tbl_local); + goto hdl_tbl_check_failed; + } + hdl_tbl = hdl_tbl_local; + spin_unlock_bh(&hdl_tbl_lock); + + bitmap_size = BITS_TO_LONGS(CAM_REQ_MGR_MAX_HANDLES_V2) * sizeof(long); + hdl_tbl->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!hdl_tbl->bitmap) { + rc = -ENOMEM; + goto bitmap_alloc_fail; + } + hdl_tbl->bits = bitmap_size * BITS_PER_BYTE; + + return rc; + +bitmap_alloc_fail: + kfree(hdl_tbl); + hdl_tbl = NULL; +hdl_tbl_alloc_failed: +hdl_tbl_check_failed: + return rc; +} + +int cam_req_mgr_util_deinit(void) +{ + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + kfree(hdl_tbl->bitmap); + hdl_tbl->bitmap = NULL; + kfree(hdl_tbl); + hdl_tbl = NULL; + spin_unlock_bh(&hdl_tbl_lock); + + return 0; +} + +int cam_req_mgr_util_free_hdls(void) +{ + int i = 0; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + for (i = 0; i < CAM_REQ_MGR_MAX_HANDLES_V2; i++) { + if (hdl_tbl->hdl[i].state == HDL_ACTIVE) { + CAM_WARN(CAM_CRM, "Dev handle = %x session_handle = %x", + hdl_tbl->hdl[i].hdl_value, + hdl_tbl->hdl[i].session_hdl); + hdl_tbl->hdl[i].state = HDL_FREE; + clear_bit(i, hdl_tbl->bitmap); + } + } + bitmap_zero(hdl_tbl->bitmap, CAM_REQ_MGR_MAX_HANDLES_V2); + spin_unlock_bh(&hdl_tbl_lock); + + return 0; +} + +static int32_t cam_get_free_handle_index(void) +{ + int idx; + + idx = find_first_zero_bit(hdl_tbl->bitmap, hdl_tbl->bits); + + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2 || idx < 0) + return -ENOSR; + + set_bit(idx, hdl_tbl->bitmap); + + return idx; +} + +int32_t cam_create_session_hdl(void *priv) +{ + int idx; + int rand = 0; + int32_t handle = 0; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + idx = cam_get_free_handle_index(); + if (idx < 0) { + CAM_ERR(CAM_CRM, "Unable to create session handle"); + spin_unlock_bh(&hdl_tbl_lock); + return idx; + } + + get_random_bytes(&rand, CAM_REQ_MGR_RND1_BYTES); + handle = GET_DEV_HANDLE(rand, HDL_TYPE_SESSION, idx); + hdl_tbl->hdl[idx].session_hdl = handle; + hdl_tbl->hdl[idx].hdl_value = handle; + hdl_tbl->hdl[idx].type = HDL_TYPE_SESSION; + hdl_tbl->hdl[idx].state = HDL_ACTIVE; + hdl_tbl->hdl[idx].priv = priv; + hdl_tbl->hdl[idx].ops = NULL; + spin_unlock_bh(&hdl_tbl_lock); + + return handle; +} + +int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data) +{ + int idx; + int rand = 0; + int32_t handle; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; + } + + idx = cam_get_free_handle_index(); + if (idx < 0) { + CAM_ERR(CAM_CRM, "Unable to create device handle"); + spin_unlock_bh(&hdl_tbl_lock); + return idx; + } + + get_random_bytes(&rand, CAM_REQ_MGR_RND1_BYTES); + handle = GET_DEV_HANDLE(rand, HDL_TYPE_DEV, idx); + hdl_tbl->hdl[idx].session_hdl = hdl_data->session_hdl; + hdl_tbl->hdl[idx].hdl_value = handle; + hdl_tbl->hdl[idx].type = HDL_TYPE_DEV; + hdl_tbl->hdl[idx].state = HDL_ACTIVE; + hdl_tbl->hdl[idx].priv = hdl_data->priv; + hdl_tbl->hdl[idx].ops = hdl_data->ops; + spin_unlock_bh(&hdl_tbl_lock); + + pr_debug("%s: handle = %x", __func__, handle); + return handle; +} + +void *cam_get_device_priv(int32_t dev_hdl) +{ + int idx; + int type; + void *priv; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Hdl tbl is NULL"); + goto device_priv_fail; + } + + idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid idx"); + goto device_priv_fail; + } + + if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid state"); + goto device_priv_fail; + } + + type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl); + if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid type"); + goto device_priv_fail; + } + + if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) { + CAM_ERR_RATE_LIMIT(CAM_CRM, "Invalid hdl"); + goto device_priv_fail; + } + + priv = hdl_tbl->hdl[idx].priv; + spin_unlock_bh(&hdl_tbl_lock); + + return priv; + +device_priv_fail: + spin_unlock_bh(&hdl_tbl_lock); + return NULL; +} + +void *cam_get_device_ops(int32_t dev_hdl) +{ + int idx; + int type; + void *ops; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + goto device_ops_fail; + } + + idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2) { + CAM_ERR(CAM_CRM, "Invalid idx"); + goto device_ops_fail; + } + + if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) { + CAM_ERR(CAM_CRM, "Invalid state"); + goto device_ops_fail; + } + + type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl); + if (HDL_TYPE_DEV != type && HDL_TYPE_SESSION != type) { + CAM_ERR(CAM_CRM, "Invalid type"); + goto device_ops_fail; + } + + if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) { + CAM_ERR(CAM_CRM, "Invalid hdl"); + goto device_ops_fail; + } + + ops = hdl_tbl->hdl[idx].ops; + spin_unlock_bh(&hdl_tbl_lock); + + return ops; + +device_ops_fail: + spin_unlock_bh(&hdl_tbl_lock); + return NULL; +} + +static int cam_destroy_hdl(int32_t dev_hdl, int dev_hdl_type) +{ + int idx; + int type; + + spin_lock_bh(&hdl_tbl_lock); + if (!hdl_tbl) { + CAM_ERR(CAM_CRM, "Hdl tbl is NULL"); + goto destroy_hdl_fail; + } + + idx = CAM_REQ_MGR_GET_HDL_IDX(dev_hdl); + if (idx >= CAM_REQ_MGR_MAX_HANDLES_V2) { + CAM_ERR(CAM_CRM, "Invalid idx %d", idx); + goto destroy_hdl_fail; + } + + if (hdl_tbl->hdl[idx].state != HDL_ACTIVE) { + CAM_ERR(CAM_CRM, "Invalid state"); + goto destroy_hdl_fail; + } + + type = CAM_REQ_MGR_GET_HDL_TYPE(dev_hdl); + if (type != dev_hdl_type) { + CAM_ERR(CAM_CRM, "Invalid type %d, %d", type, dev_hdl_type); + goto destroy_hdl_fail; + } + + if (hdl_tbl->hdl[idx].hdl_value != dev_hdl) { + CAM_ERR(CAM_CRM, "Invalid hdl"); + goto destroy_hdl_fail; + } + + hdl_tbl->hdl[idx].state = HDL_FREE; + hdl_tbl->hdl[idx].ops = NULL; + hdl_tbl->hdl[idx].priv = NULL; + clear_bit(idx, hdl_tbl->bitmap); + spin_unlock_bh(&hdl_tbl_lock); + + return 0; + +destroy_hdl_fail: + spin_unlock_bh(&hdl_tbl_lock); + return -EINVAL; +} + +int cam_destroy_device_hdl(int32_t dev_hdl) +{ + return cam_destroy_hdl(dev_hdl, HDL_TYPE_DEV); +} + +int cam_destroy_session_hdl(int32_t dev_hdl) +{ + return cam_destroy_hdl(dev_hdl, HDL_TYPE_SESSION); +} diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util.h new file mode 100644 index 0000000000000000000000000000000000000000..c0e339eedd9bb5b0b2c85c5b423dc9f6f0eaefc6 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_UTIL_API_H_ +#define _CAM_REQ_MGR_UTIL_API_H_ + +#include <media/cam_req_mgr.h> +#include "cam_req_mgr_util_priv.h" + +/** + * state of a handle(session/device) + * @HDL_FREE: free handle + * @HDL_ACTIVE: active handles + */ +enum hdl_state { + HDL_FREE, + HDL_ACTIVE +}; + +/** + * handle type + * @HDL_TYPE_DEV: for device and link + * @HDL_TYPE_SESSION: for session + */ +enum hdl_type { + HDL_TYPE_DEV = 1, + HDL_TYPE_SESSION +}; + +/** + * struct handle + * @session_hdl: session handle + * @hdl_value: Allocated handle + * @type: session/device handle + * @state: free/used + * @ops: ops structure + * @priv: private data of a handle + */ +struct handle { + int32_t session_hdl; + uint32_t hdl_value; + enum hdl_type type; + enum hdl_state state; + void *ops; + void *priv; +}; + +/** + * struct cam_req_mgr_util_hdl_tbl + * @hdl: row of handles + * @bitmap: bit map to get free hdl row idx + * @bits: size of bit map in bits + */ +struct cam_req_mgr_util_hdl_tbl { + struct handle hdl[CAM_REQ_MGR_MAX_HANDLES_V2]; + void *bitmap; + size_t bits; +}; + +/** + * cam_req_mgr_util APIs for KMD drivers and cam_req_mgr + * @session_hdl: session_hdl info + * @v4l2_sub_dev_flag: flag to create v4l2 sub device + * @media_entity_flag: flag for media entity + * @reserved: reserved field + * @ops: ops pointer for a device handle + * @priv: private data for a device handle + */ +struct cam_create_dev_hdl { + int32_t session_hdl; + int32_t v4l2_sub_dev_flag; + int32_t media_entity_flag; + int32_t reserved; + void *ops; + void *priv; +}; + +/** + * cam_create_session_hdl() - create a session handle + * @priv: private data for a session handle + * + * cam_req_mgr core calls this function to get + * a unique session handle. Returns a unique session + * handle + */ +int32_t cam_create_session_hdl(void *priv); + +/** + * cam_create_device_hdl() - create a device handle + * @hdl_data: session hdl, flags, ops and priv dara as input + * + * cam_req_mgr_core calls this function to get + * session and link handles + * KMD drivers calls this function to create + * a device handle. Returns a unique device handle + */ +int32_t cam_create_device_hdl(struct cam_create_dev_hdl *hdl_data); + +/** + * cam_get_device_priv() - get private data of a handle + * @dev_hdl: handle for a session/link/device + * + * cam_req_mgr_core and KMD drivers use this function to + * get private data of a handle. Returns a private data + * structure pointer. + */ +void *cam_get_device_priv(int32_t dev_hdl); + +/** + * cam_get_device_ops() - get ops of a handle + * @dev_hdl: handle for a session/link/device + * + * cam_req_mgr_core and KMD drivers use this function to + * get ops of a handle. Returns a pointer to ops. + */ +void *cam_get_device_ops(int32_t dev_hdl); + +/** + * cam_destroy_device_hdl() - destroy device handle + * @dev_hdl: handle for a link/device. + * + * Returns success/failure + */ +int32_t cam_destroy_device_hdl(int32_t dev_hdl); + +/** + * cam_destroy_session_hdl() - destroy device handle + * @dev_hdl: handle for a session + * + * Returns success/failure + */ +int32_t cam_destroy_session_hdl(int32_t dev_hdl); + + +/* Internal functions */ +/** + * cam_req_mgr_util_init() - init function of cam_req_mgr_util + * + * This is called as part of probe function to initialize + * handle table, bitmap, locks + */ +int cam_req_mgr_util_init(void); + +/** + * cam_req_mgr_util_deinit() - deinit function of cam_req_mgr_util + * + * This function is called in case of probe failure + */ +int32_t cam_req_mgr_util_deinit(void); + +/** + * cam_req_mgr_util_free_hdls() - free handles in case of crash + * + * Called from cam_req_mgr_dev release function to make sure + * all data structures are cleaned to avoid leaks + * + * cam_req_mgr core can call this function at the end of + * camera to make sure all stale entries are printed and + * cleaned + */ +int32_t cam_req_mgr_util_free_hdls(void); + +#endif /* _CAM_REQ_MGR_UTIL_API_H_ */ diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util_priv.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..075f5c34702d109916f99bd635bf4beb2f36bc05 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_util_priv.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_UTIL_PRIV_H_ +#define _CAM_REQ_MGR_UTIL_PRIV_H_ + +/** + * handle format: + * @bits (0-7): handle index + * @bits (8-11): handle type + * @bits (12-15): reserved + * @bits (16-23): random bits + * @bits (24-31): zeros + */ + +#define CAM_REQ_MGR_HDL_SIZE 32 +#define CAM_REQ_MGR_RND1_SIZE 8 +#define CAM_REQ_MGR_RVD_SIZE 4 +#define CAM_REQ_MGR_HDL_TYPE_SIZE 4 +#define CAM_REQ_MGR_HDL_IDX_SIZE 8 + +#define CAM_REQ_MGR_RND1_POS 24 +#define CAM_REQ_MGR_RVD_POS 16 +#define CAM_REQ_MGR_HDL_TYPE_POS 12 + +#define CAM_REQ_MGR_RND1_BYTES 1 + +#define CAM_REQ_MGR_HDL_TYPE_MASK ((1 << CAM_REQ_MGR_HDL_TYPE_SIZE) - 1) + +#define GET_DEV_HANDLE(rnd1, type, idx) \ + ((rnd1 << (CAM_REQ_MGR_RND1_POS - CAM_REQ_MGR_RND1_SIZE)) | \ + (0x0 << (CAM_REQ_MGR_RVD_POS - CAM_REQ_MGR_RVD_SIZE)) | \ + (type << (CAM_REQ_MGR_HDL_TYPE_POS - CAM_REQ_MGR_HDL_TYPE_SIZE)) | \ + (idx << (CAM_REQ_MGR_HDL_IDX_POS - CAM_REQ_MGR_HDL_IDX_SIZE))) \ + +#define CAM_REQ_MGR_GET_HDL_IDX(hdl) (hdl & CAM_REQ_MGR_HDL_IDX_MASK) +#define CAM_REQ_MGR_GET_HDL_TYPE(hdl) \ + ((hdl >> CAM_REQ_MGR_HDL_IDX_POS) & CAM_REQ_MGR_HDL_TYPE_MASK) + +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_workq.c b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_workq.c new file mode 100644 index 0000000000000000000000000000000000000000..29d98503f305d72c46b440de39e3e3c3bd204bf5 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_workq.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_req_mgr_workq.h" +#include "cam_debug_util.h" + +#define WORKQ_ACQUIRE_LOCK(workq, flags) {\ + if ((workq)->in_irq) \ + spin_lock_irqsave(&(workq)->lock_bh, (flags)); \ + else \ + spin_lock_bh(&(workq)->lock_bh); \ +} + +#define WORKQ_RELEASE_LOCK(workq, flags) {\ + if ((workq)->in_irq) \ + spin_unlock_irqrestore(&(workq)->lock_bh, (flags)); \ + else \ + spin_unlock_bh(&(workq)->lock_bh); \ +} + +struct crm_workq_task *cam_req_mgr_workq_get_task( + struct cam_req_mgr_core_workq *workq) +{ + struct crm_workq_task *task = NULL; + unsigned long flags = 0; + + if (!workq) + return NULL; + + WORKQ_ACQUIRE_LOCK(workq, flags); + if (list_empty(&workq->task.empty_head)) + goto end; + + task = list_first_entry(&workq->task.empty_head, + struct crm_workq_task, entry); + if (task) { + atomic_sub(1, &workq->task.free_cnt); + list_del_init(&task->entry); + } + +end: + WORKQ_RELEASE_LOCK(workq, flags); + + return task; +} + +static void cam_req_mgr_workq_put_task(struct crm_workq_task *task) +{ + struct cam_req_mgr_core_workq *workq = + (struct cam_req_mgr_core_workq *)task->parent; + unsigned long flags = 0; + + list_del_init(&task->entry); + task->cancel = 0; + task->process_cb = NULL; + task->priv = NULL; + WORKQ_ACQUIRE_LOCK(workq, flags); + list_add_tail(&task->entry, + &workq->task.empty_head); + atomic_add(1, &workq->task.free_cnt); + WORKQ_RELEASE_LOCK(workq, flags); +} + +/** + * cam_req_mgr_process_task() - Process the enqueued task + * @task: pointer to task workq thread shall process + */ +static int cam_req_mgr_process_task(struct crm_workq_task *task) +{ + struct cam_req_mgr_core_workq *workq = NULL; + + if (!task) + return -EINVAL; + + workq = (struct cam_req_mgr_core_workq *)task->parent; + if (task->process_cb) + task->process_cb(task->priv, task->payload); + else + CAM_WARN(CAM_CRM, "FATAL:no task handler registered for workq"); + cam_req_mgr_workq_put_task(task); + + return 0; +} + +/** + * cam_req_mgr_process_workq() - main loop handling + * @w: workqueue task pointer + */ +static void cam_req_mgr_process_workq(struct work_struct *w) +{ + struct cam_req_mgr_core_workq *workq = NULL; + struct crm_workq_task *task; + int32_t i = CRM_TASK_PRIORITY_0; + unsigned long flags = 0; + + if (!w) { + CAM_ERR(CAM_CRM, "NULL task pointer can not schedule"); + return; + } + workq = (struct cam_req_mgr_core_workq *) + container_of(w, struct cam_req_mgr_core_workq, work); + + while (i < CRM_TASK_PRIORITY_MAX) { + WORKQ_ACQUIRE_LOCK(workq, flags); + while (!list_empty(&workq->task.process_head[i])) { + task = list_first_entry(&workq->task.process_head[i], + struct crm_workq_task, entry); + atomic_sub(1, &workq->task.pending_cnt); + list_del_init(&task->entry); + WORKQ_RELEASE_LOCK(workq, flags); + cam_req_mgr_process_task(task); + CAM_DBG(CAM_CRM, "processed task %pK free_cnt %d", + task, atomic_read(&workq->task.free_cnt)); + WORKQ_ACQUIRE_LOCK(workq, flags); + } + WORKQ_RELEASE_LOCK(workq, flags); + i++; + } +} + +int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, + void *priv, int32_t prio) +{ + int rc = 0; + struct cam_req_mgr_core_workq *workq = NULL; + unsigned long flags = 0; + + if (!task) { + CAM_WARN(CAM_CRM, "NULL task pointer can not schedule"); + rc = -EINVAL; + goto end; + } + workq = (struct cam_req_mgr_core_workq *)task->parent; + if (!workq) { + CAM_DBG(CAM_CRM, "NULL workq pointer suspect mem corruption"); + rc = -EINVAL; + goto end; + } + + if (task->cancel == 1) { + cam_req_mgr_workq_put_task(task); + CAM_WARN(CAM_CRM, "task aborted and queued back to pool"); + rc = 0; + goto end; + } + task->priv = priv; + task->priority = + (prio < CRM_TASK_PRIORITY_MAX && prio >= CRM_TASK_PRIORITY_0) + ? prio : CRM_TASK_PRIORITY_0; + + WORKQ_ACQUIRE_LOCK(workq, flags); + if (!workq->job) { + rc = -EINVAL; + WORKQ_RELEASE_LOCK(workq, flags); + goto end; + } + + list_add_tail(&task->entry, + &workq->task.process_head[task->priority]); + + atomic_add(1, &workq->task.pending_cnt); + CAM_DBG(CAM_CRM, "enq task %pK pending_cnt %d", + task, atomic_read(&workq->task.pending_cnt)); + + queue_work(workq->job, &workq->work); + WORKQ_RELEASE_LOCK(workq, flags); +end: + return rc; +} + +int cam_req_mgr_workq_create(char *name, int32_t num_tasks, + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags) +{ + int32_t i, wq_flags = 0, max_active_tasks = 0; + struct crm_workq_task *task; + struct cam_req_mgr_core_workq *crm_workq = NULL; + char buf[128] = "crm_workq-"; + + if (!*workq) { + crm_workq = kzalloc(sizeof(struct cam_req_mgr_core_workq), + GFP_KERNEL); + if (crm_workq == NULL) + return -ENOMEM; + + wq_flags |= WQ_UNBOUND; + if (flags & CAM_WORKQ_FLAG_HIGH_PRIORITY) + wq_flags |= WQ_HIGHPRI; + + if (flags & CAM_WORKQ_FLAG_SERIAL) + max_active_tasks = 1; + + strlcat(buf, name, sizeof(buf)); + CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name); + crm_workq->job = alloc_workqueue(buf, + wq_flags, max_active_tasks, NULL); + if (!crm_workq->job) { + kfree(crm_workq); + return -ENOMEM; + } + + /* Workq attributes initialization */ + INIT_WORK(&crm_workq->work, cam_req_mgr_process_workq); + spin_lock_init(&crm_workq->lock_bh); + CAM_DBG(CAM_CRM, "LOCK_DBG workq %s lock %pK", + name, &crm_workq->lock_bh); + + /* Task attributes initialization */ + atomic_set(&crm_workq->task.pending_cnt, 0); + atomic_set(&crm_workq->task.free_cnt, 0); + for (i = CRM_TASK_PRIORITY_0; i < CRM_TASK_PRIORITY_MAX; i++) + INIT_LIST_HEAD(&crm_workq->task.process_head[i]); + INIT_LIST_HEAD(&crm_workq->task.empty_head); + crm_workq->in_irq = in_irq; + crm_workq->task.num_task = num_tasks; + crm_workq->task.pool = kcalloc(crm_workq->task.num_task, + sizeof(struct crm_workq_task), GFP_KERNEL); + if (!crm_workq->task.pool) { + CAM_WARN(CAM_CRM, "Insufficient memory %zu", + sizeof(struct crm_workq_task) * + crm_workq->task.num_task); + kfree(crm_workq); + return -ENOMEM; + } + + for (i = 0; i < crm_workq->task.num_task; i++) { + task = &crm_workq->task.pool[i]; + task->parent = (void *)crm_workq; + /* Put all tasks in free pool */ + INIT_LIST_HEAD(&task->entry); + cam_req_mgr_workq_put_task(task); + } + *workq = crm_workq; + CAM_DBG(CAM_CRM, "free tasks %d", + atomic_read(&crm_workq->task.free_cnt)); + } + + return 0; +} + +void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **crm_workq) +{ + unsigned long flags = 0; + struct workqueue_struct *job; + + CAM_DBG(CAM_CRM, "destroy workque %pK", crm_workq); + if (*crm_workq) { + WORKQ_ACQUIRE_LOCK(*crm_workq, flags); + if ((*crm_workq)->job) { + job = (*crm_workq)->job; + (*crm_workq)->job = NULL; + WORKQ_RELEASE_LOCK(*crm_workq, flags); + destroy_workqueue(job); + } else { + WORKQ_RELEASE_LOCK(*crm_workq, flags); + } + + /* Destroy workq payload data */ + kfree((*crm_workq)->task.pool[0].payload); + (*crm_workq)->task.pool[0].payload = NULL; + kfree((*crm_workq)->task.pool); + kfree(*crm_workq); + *crm_workq = NULL; + } +} diff --git a/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_workq.h b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_workq.h new file mode 100644 index 0000000000000000000000000000000000000000..f938710b69aeddaf7a463a84f3a8c9b06074a5cf --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_req_mgr_workq.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_REQ_MGR_WORKQ_H_ +#define _CAM_REQ_MGR_WORKQ_H_ + +#include<linux/kernel.h> +#include<linux/module.h> +#include<linux/init.h> +#include<linux/sched.h> +#include <linux/workqueue.h> +#include <linux/slab.h> +#include <linux/timer.h> + +#include "cam_req_mgr_core.h" + +/* Flag to create a high priority workq */ +#define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0) + +/* + * This flag ensures only one task from a given + * workq will execute at any given point on any + * given CPU. + */ +#define CAM_WORKQ_FLAG_SERIAL (1 << 1) + +/* Task priorities, lower the number higher the priority*/ +enum crm_task_priority { + CRM_TASK_PRIORITY_0, + CRM_TASK_PRIORITY_1, + CRM_TASK_PRIORITY_MAX, +}; + +/* workqueue will be used from irq context or not */ +enum crm_workq_context { + CRM_WORKQ_USAGE_NON_IRQ, + CRM_WORKQ_USAGE_IRQ, + CRM_WORKQ_USAGE_INVALID, +}; + +/** struct crm_workq_task + * @priority : caller can assign priority to task based on type. + * @payload : depending of user of task this payload type will change + * @process_cb : registered callback called by workq when task enqueued is + * ready for processing in workq thread context + * @parent : workq's parent is link which is enqqueing taks to this workq + * @entry : list head of this list entry is worker's empty_head + * @cancel : if caller has got free task from pool but wants to abort + * or put back without using it + * @priv : when task is enqueuer caller can attach priv along which + * it will get in process callback + * @ret : return value in future to use for blocking calls + */ +struct crm_workq_task { + int32_t priority; + void *payload; + int32_t (*process_cb)(void *priv, void *data); + void *parent; + struct list_head entry; + uint8_t cancel; + void *priv; + int32_t ret; +}; + +/** struct cam_req_mgr_core_workq + * @work : work token used by workqueue + * @job : workqueue internal job struct + * task - + * @lock_bh : lock for task structs + * @in_irq : set true if workque can be used in irq context + * @free_cnt : num of free/available tasks + * @empty_head : list head of available taska which can be used + * or acquired in order to enqueue a task to workq + * @pool : pool of tasks used for handling events in workq context + * @num_task : size of tasks pool + * - + */ +struct cam_req_mgr_core_workq { + struct work_struct work; + struct workqueue_struct *job; + spinlock_t lock_bh; + uint32_t in_irq; + + /* tasks */ + struct { + struct mutex lock; + atomic_t pending_cnt; + atomic_t free_cnt; + + struct list_head process_head[CRM_TASK_PRIORITY_MAX]; + struct list_head empty_head; + struct crm_workq_task *pool; + uint32_t num_task; + } task; +}; + +/** + * cam_req_mgr_workq_create() + * @brief : create a workqueue + * @name : Name of the workque to be allocated, it is combination + * of session handle and link handle + * @num_task : Num_tasks to be allocated for workq + * @workq : Double pointer worker + * @in_irq : Set to one if workq might be used in irq context + * @flags : Bitwise OR of Flags for workq behavior. + * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL + * This function will allocate and create workqueue and pass + * the workq pointer to caller. + */ +int cam_req_mgr_workq_create(char *name, int32_t num_tasks, + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags); + +/** + * cam_req_mgr_workq_destroy() + * @brief: destroy workqueue + * @workq: pointer to worker data struct + * this function will destroy workqueue and clean up resources + * associated with worker such as tasks. + */ +void cam_req_mgr_workq_destroy(struct cam_req_mgr_core_workq **workq); + +/** + * cam_req_mgr_workq_enqueue_task() + * @brief: Enqueue task in worker queue + * @task : task to be processed by worker + * @priv : clients private data + * @prio : task priority + * process callback func + */ +int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, + void *priv, int32_t prio); + +/** + * cam_req_mgr_workq_get_task() + * @brief: Returns empty task pointer for use + * @workq: workque used for processing + */ +struct crm_workq_task *cam_req_mgr_workq_get_task( + struct cam_req_mgr_core_workq *workq); + +#endif diff --git a/techpack/camera/drivers/cam_req_mgr/cam_subdev.h b/techpack/camera/drivers/cam_req_mgr/cam_subdev.h new file mode 100644 index 0000000000000000000000000000000000000000..385643d5e53258f6961e4719a00b8738326f5434 --- /dev/null +++ b/techpack/camera/drivers/cam_req_mgr/cam_subdev.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SUBDEV_H_ +#define _CAM_SUBDEV_H_ + +#include <linux/types.h> +#include <linux/platform_device.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> + +#define CAM_SUBDEVICE_EVENT_MAX 30 + +/** + * struct cam_subdev - describes a camera sub-device + * + * @pdev: Pointer to the platform device + * @sd: V4l2 subdevice + * @ops: V4l2 subdecie operations + * @internal_ops: V4l2 subdevice internal operations + * @name: Name of the sub-device. Please notice that the name + * must be unique. + * @sd_flags: Subdev flags. Can be: + * %V4L2_SUBDEV_FL_HAS_DEVNODE - Set this flag if + * this subdev needs a device node. + * %V4L2_SUBDEV_FL_HAS_EVENTS - Set this flag if + * this subdev generates events. + * @token: Pointer to cookie of the client driver + * @ent_function: Media entity function type. Can be: + * %CAM_IFE_DEVICE_TYPE - identifies as IFE device. + * %CAM_ICP_DEVICE_TYPE - identifies as ICP device. + * + * Each instance of a subdev driver should create this struct, either + * stand-alone or embedded in a larger struct. This structure should be + * initialized/registered by cam_register_subdev + * + */ +struct cam_subdev { + struct platform_device *pdev; + struct v4l2_subdev sd; + const struct v4l2_subdev_ops *ops; + const struct v4l2_subdev_internal_ops *internal_ops; + char *name; + u32 sd_flags; + void *token; + u32 ent_function; +}; + +/** + * cam_subdev_probe() + * + * @brief: Camera Subdevice node probe function for v4l2 setup + * + * @sd: Camera subdevice object + * @name: Name of the subdevice node + * @dev_type: Subdevice node type + * + */ +int cam_subdev_probe(struct cam_subdev *sd, struct platform_device *pdev, + char *name, uint32_t dev_type); + +/** + * cam_subdev_remove() + * + * @brief: Called when subdevice node is unloaded + * + * @sd: Camera subdevice node object + * + */ +int cam_subdev_remove(struct cam_subdev *sd); + +/** + * cam_register_subdev_fops() + * + * @brief: This common utility function assigns subdev ops + * + * @fops: v4l file operations + */ +void cam_register_subdev_fops(struct v4l2_file_operations *fops); + +/** + * cam_register_subdev() + * + * @brief: This is the common utility function to be called by each camera + * subdevice node when it tries to register itself to the camera + * request manager + * + * @sd: Pointer to struct cam_subdev. + */ +int cam_register_subdev(struct cam_subdev *sd); + +/** + * cam_unregister_subdev() + * + * @brief: This is the common utility function to be called by each camera + * subdevice node when it tries to unregister itself from the + * camera request manger + * + * @sd: Pointer to struct cam_subdev. + */ +int cam_unregister_subdev(struct cam_subdev *sd); + +#endif /* _CAM_SUBDEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/Makefile b/techpack/camera/drivers/cam_sensor_module/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6925b3aba80f1a9fe6e373a4970a174753860103 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_res_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_utils/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_actuator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e61c6eeba3c0b121de9fbcf9cfd1d185c5f4d4d2 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator_dev.o cam_actuator_core.o cam_actuator_soc.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c new file mode 100755 index 0000000000000000000000000000000000000000..a174d67766c32d52c989b183f401ae5b2d40fcd3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -0,0 +1,1037 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <cam_sensor_cmn_header.h> +#include "cam_actuator_core.h" +#include "cam_sensor_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +int32_t cam_actuator_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 1; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_setting[0].seq_type = SENSOR_VAF; + power_info->power_setting[0].seq_val = CAM_VAF; + power_info->power_setting[0].config_val = 1; + power_info->power_setting[0].delay = 2; + + power_info->power_down_setting_size = 1; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + power_info->power_down_setting[0].seq_type = SENSOR_VAF; + power_info->power_down_setting[0].seq_val = CAM_VAF; + power_info->power_down_setting[0].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + +static int32_t cam_actuator_power_up(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = + &a_ctrl->soc_info; + struct cam_actuator_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + if ((power_info->power_setting == NULL) && + (power_info->power_down_setting == NULL)) { + CAM_ERR(CAM_ACTUATOR, + "fatal! no power settings."); + return -EINVAL; + } + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params( + &a_ctrl->soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "failed to fill vreg params for power up rc:%d", rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + &a_ctrl->soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "failed to fill vreg params power down rc:%d", rc); + return rc; + } + + power_info->dev = soc_info->dev; + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "failed in actuator power up rc %d", rc); + return rc; + } + + rc = camera_io_init(&a_ctrl->io_master_info); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "cci init failed: rc: %d", rc); + + return rc; +} + +static int32_t cam_actuator_power_down(struct cam_actuator_ctrl_t *a_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info = &a_ctrl->soc_info; + struct cam_actuator_soc_private *soc_private; + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "failed: a_ctrl %pK", a_ctrl); + return -EINVAL; + } + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + soc_info = &a_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_ACTUATOR, "failed: power_info %pK", power_info); + return -EINVAL; + } + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_ACTUATOR, "power down the core is failed:%d", rc); + return rc; + } + + camera_io_release(&a_ctrl->io_master_info); + + return rc; +} + +static int32_t cam_actuator_i2c_modes_util( + struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list) +{ + int32_t rc = 0; + uint32_t i, size; + + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to random write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 0); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to seq write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_BURST) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to burst write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + io_master_info, + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "i2c poll apply setting Fail: %d", rc); + return rc; + } + } + } + + return rc; +} + +int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl, + uint32_t *cmd_buf, size_t len) +{ + int32_t rc = 0; + struct cam_cmd_i2c_info *i2c_info; + + if (!a_ctrl || !cmd_buf || (len < sizeof(struct cam_cmd_i2c_info))) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if (a_ctrl->io_master_info.master_type == CCI_MASTER) { + a_ctrl->io_master_info.cci_client->cci_i2c_master = + a_ctrl->cci_i2c_master; + a_ctrl->io_master_info.cci_client->i2c_freq_mode = + i2c_info->i2c_freq_mode; + a_ctrl->io_master_info.cci_client->sid = + i2c_info->slave_addr >> 1; + CAM_DBG(CAM_ACTUATOR, "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, i2c_info->i2c_freq_mode); + } else if (a_ctrl->io_master_info.master_type == I2C_MASTER) { + a_ctrl->io_master_info.client->addr = i2c_info->slave_addr; + CAM_DBG(CAM_ACTUATOR, "Slave addr: 0x%x", i2c_info->slave_addr); + } else { + CAM_ERR(CAM_ACTUATOR, "Invalid Master type: %d", + a_ctrl->io_master_info.master_type); + rc = -EINVAL; + } + + return rc; +} + +int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, + struct i2c_settings_array *i2c_set) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0; + + if (a_ctrl == NULL || i2c_set == NULL) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + if (i2c_set->is_settings_valid != 1) { + CAM_ERR(CAM_ACTUATOR, " Invalid settings"); + return -EINVAL; + } + + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_actuator_i2c_modes_util( + &(a_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + a_ctrl->is_actuator_ready = false; + CAM_ERR(CAM_ACTUATOR, "poll failed rc %d", rc); + } + CAM_ERR(CAM_ACTUATOR, + "Failed to apply settings: %d", + rc); + } else { + if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + if (rc == I2C_COMPARE_MISMATCH) { + a_ctrl->is_actuator_ready = false; + CAM_ERR(CAM_ACTUATOR, "poll failed(non-fatal), will poll later"); + } + } + CAM_DBG(CAM_ACTUATOR, + "Success:request ID: %d", + i2c_set->request_id); + } + } + + return rc; +} + +int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int32_t rc = 0, request_id, del_req_id; + struct cam_actuator_ctrl_t *a_ctrl = NULL; + + if (!apply) { + CAM_ERR(CAM_ACTUATOR, "Invalid Input Args"); + return -EINVAL; + } + + a_ctrl = (struct cam_actuator_ctrl_t *) + cam_get_device_priv(apply->dev_hdl); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Device data is NULL"); + return -EINVAL; + } + request_id = apply->request_id % MAX_PER_FRAME_ARRAY; + + trace_cam_apply_req("Actuator", apply->request_id); + + CAM_DBG(CAM_ACTUATOR, "Request Id: %lld", apply->request_id); + mutex_lock(&(a_ctrl->actuator_mutex)); + if ((apply->request_id == + a_ctrl->i2c_data.per_frame[request_id].request_id) && + (a_ctrl->i2c_data.per_frame[request_id].is_settings_valid) + == 1) { + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.per_frame[request_id]); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed in applying the request: %lld\n", + apply->request_id); + goto release_mutex; + } + } + del_req_id = (request_id + + MAX_PER_FRAME_ARRAY - MAX_SYSTEM_PIPELINE_DELAY) % + MAX_PER_FRAME_ARRAY; + + if (apply->request_id > + a_ctrl->i2c_data.per_frame[del_req_id].request_id) { + a_ctrl->i2c_data.per_frame[del_req_id].request_id = 0; + rc = delete_request(&a_ctrl->i2c_data.per_frame[del_req_id]); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Fail deleting the req: %d err: %d\n", + del_req_id, rc); + goto release_mutex; + } + } else { + CAM_DBG(CAM_ACTUATOR, "No Valid Req to clean Up"); + } + +release_mutex: + mutex_unlock(&(a_ctrl->actuator_mutex)); + return rc; +} + +int32_t cam_actuator_establish_link( + struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_actuator_ctrl_t *a_ctrl = NULL; + + if (!link) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + a_ctrl = (struct cam_actuator_ctrl_t *) + cam_get_device_priv(link->dev_hdl); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + if (link->link_enable) { + a_ctrl->bridge_intf.link_hdl = link->link_hdl; + a_ctrl->bridge_intf.crm_cb = link->crm_cb; + } else { + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.crm_cb = NULL; + } + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + +static void cam_actuator_update_req_mgr( + struct cam_actuator_ctrl_t *a_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = a_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + + if (a_ctrl->bridge_intf.crm_cb && + a_ctrl->bridge_intf.crm_cb->add_req) { + a_ctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_ACTUATOR, "Request Id: %lld added to CRM", + add_req.req_id); + } else { + CAM_ERR(CAM_ACTUATOR, "Can't add Request ID: %lld to CRM", + csl_packet->header.request_id); + } +} + +int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + if (!info) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR; + strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name)); + info->p_delay = 1; + info->trigger = CAM_TRIGGER_POINT_SOF; + + return 0; +} + +int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, + void *arg) +{ + int32_t rc = 0; + int32_t i = 0; + uint32_t total_cmd_buf_in_bytes = 0; + size_t len_of_buff = 0; + size_t remain_len = 0; + uint32_t *offset = NULL; + uint32_t *cmd_buf = NULL; + uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; + struct common_header *cmm_hdr = NULL; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_config_dev_cmd config; + struct i2c_data_settings *i2c_data = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + struct i2c_settings_list *i2c_list = NULL; + int ret = 0; + + if (!a_ctrl || !arg) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + + power_info = &soc_private->power_info; + + ioctl_ctrl = (struct cam_control *)arg; + if (copy_from_user(&config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(config.packet_handle, + &generic_pkt_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Error in converting command Handle %d", + rc); + return rc; + } + + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_ACTUATOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto end; + } + + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_ACTUATOR, "Invalid packet params"); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_ACTUATOR_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= a_ctrl->last_flush_req + && a_ctrl->last_flush_req != 0) { + CAM_DBG(CAM_ACTUATOR, + "reject request %lld, last request to flush %lld", + csl_packet->header.request_id, a_ctrl->last_flush_req); + rc = -EINVAL; + goto end; + } + + if (csl_packet->header.request_id > a_ctrl->last_flush_req) + a_ctrl->last_flush_req = 0; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_ACTUATOR_PACKET_OPCODE_INIT: + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + if (!total_cmd_buf_in_bytes) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf"); + goto end; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_ACTUATOR, "invalid cmd buf"); + rc = -EINVAL; + goto end; + } + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_ACTUATOR, + "Invalid length for sensor cmd"); + rc = -EINVAL; + goto end; + } + remain_len = len_of_buff - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + cmm_hdr = (struct common_header *)cmd_buf; + + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + CAM_DBG(CAM_ACTUATOR, + "Received slave info buffer"); + rc = cam_actuator_slaveInfo_pkt_parser( + a_ctrl, cmd_buf, remain_len); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to parse slave info: %d", rc); + goto end; + } + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + CAM_DBG(CAM_ACTUATOR, + "Received power settings buffer"); + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + power_info, remain_len); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "Failed:parse power settings: %d", + rc); + goto end; + } + break; + default: + CAM_DBG(CAM_ACTUATOR, + "Received initSettings buffer"); + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = + &i2c_data->init_settings; + + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + rc = cam_sensor_i2c_command_parser( + &a_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed:parse init settings: %d", + rc); + goto end; + } + break; + } + } + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) { + + { + a_ctrl->is_actuator_ready = true; + memset(&(a_ctrl->poll_register), 0, sizeof(struct cam_sensor_i2c_reg_array)); + list_for_each_entry(i2c_list, + &(a_ctrl->i2c_data.init_settings.list_head), list) { + if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + a_ctrl->poll_register.reg_addr = i2c_list->i2c_settings.reg_setting[0].reg_addr; + a_ctrl->poll_register.reg_data = i2c_list->i2c_settings.reg_setting[0].reg_data; + a_ctrl->poll_register.data_mask = i2c_list->i2c_settings.reg_setting[0].data_mask; + a_ctrl->poll_register.delay = 100; //i2c_list->i2c_settings.reg_setting[0].delay; // The max delay should be 100 + a_ctrl->addr_type = i2c_list->i2c_settings.addr_type; + a_ctrl->data_type = i2c_list->i2c_settings.data_type; + } + } + } + + rc = cam_actuator_power_up(a_ctrl); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + " Actuator Power up failed"); + goto end; + } + a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; + } + + { + if (!a_ctrl->is_actuator_ready) { + if (a_ctrl->poll_register.reg_addr || a_ctrl->poll_register.reg_data) { + ret = camera_io_dev_poll( + &(a_ctrl->io_master_info), + a_ctrl->poll_register.reg_addr, + a_ctrl->poll_register.reg_data, + a_ctrl->poll_register.data_mask, + a_ctrl->addr_type, + a_ctrl->data_type, + a_ctrl->poll_register.delay); + if (ret < 0) { + CAM_ERR(CAM_ACTUATOR, + "i2c poll apply setting Fail: %d, is_actuator_ready %d", ret, a_ctrl->is_actuator_ready); + } else { + CAM_DBG(CAM_ACTUATOR, + "is_actuator_ready %d, ret %d", a_ctrl->is_actuator_ready, ret); + } + a_ctrl->is_actuator_ready = true; //Just poll one time + } + } + } + + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings"); + goto end; + } + + /* Delete the request even if the apply is failed */ + rc = delete_request(&a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_WARN(CAM_ACTUATOR, + "Fail in deleting the Init settings"); + rc = 0; + } + break; + case CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to move lens: %d", + a_ctrl->cam_act_state); + goto end; + } + a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_NOW; + + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->init_settings; + + i2c_data->init_settings.request_id = + csl_packet->header.request_id; + i2c_reg_settings->is_settings_valid = 1; + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / sizeof(uint32_t); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &a_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Auto move lens parsing failed: %d", rc); + goto end; + } + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; + case CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to move lens: %d", + a_ctrl->cam_act_state); + goto end; + } + + a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_LATER; + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->per_frame[ + csl_packet->header.request_id % MAX_PER_FRAME_ARRAY]; + + i2c_reg_settings->request_id = + csl_packet->header.request_id; + i2c_reg_settings->is_settings_valid = 1; + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / sizeof(uint32_t); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &a_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Manual move lens parsing failed: %d", rc); + goto end; + } + + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; + case CAM_PKT_NOP_OPCODE: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + CAM_WARN(CAM_ACTUATOR, + "Received NOP packets in invalid state: %d", + a_ctrl->cam_act_state); + rc = -EINVAL; + goto end; + } + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; + default: + CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d", + csl_packet->header.op_code & 0xFFFFFF); + rc = -EINVAL; + goto end; + } + +end: + return rc; +} + +void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + struct cam_actuator_soc_private *soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = + &soc_private->power_info; + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_INIT) + return; + + if (a_ctrl->cam_act_state >= CAM_ACTUATOR_CONFIG) { + rc = cam_actuator_power_down(a_ctrl); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "Actuator Power down failed"); + a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE; + } + + if (a_ctrl->cam_act_state >= CAM_ACTUATOR_ACQUIRE) { + rc = cam_destroy_device_hdl(a_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "destroying dhdl failed"); + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.session_hdl = -1; + } + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; +} + +int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, + void *arg) +{ + int rc = 0; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + if (!a_ctrl || !cmd) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); + return -EINVAL; + } + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + + power_info = &soc_private->power_info; + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_ACTUATOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + CAM_DBG(CAM_ACTUATOR, "Opcode to Actuator: %d", cmd->op_code); + + mutex_lock(&(a_ctrl->actuator_mutex)); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev actuator_acq_dev; + struct cam_create_dev_hdl bridge_params; + + if (a_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_ACTUATOR, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&actuator_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(actuator_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed Copying from user\n"); + goto release_mutex; + } + + bridge_params.session_hdl = actuator_acq_dev.session_handle; + bridge_params.ops = &a_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = a_ctrl; + + actuator_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + a_ctrl->bridge_intf.device_hdl = actuator_acq_dev.device_handle; + a_ctrl->bridge_intf.session_hdl = + actuator_acq_dev.session_handle; + + CAM_DBG(CAM_ACTUATOR, "Device Handle: %d", + actuator_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &actuator_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_ACTUATOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + + a_ctrl->cam_act_state = CAM_ACTUATOR_ACQUIRE; + } + break; + case CAM_RELEASE_DEV: { + if (a_ctrl->cam_act_state == CAM_ACTUATOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Cant release actuator: in start state"); + goto release_mutex; + } + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_CONFIG) { + rc = cam_actuator_power_down(a_ctrl); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Actuator Power down failed"); + goto release_mutex; + } + } + + if (a_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_ACTUATOR, "link hdl: %d device hdl: %d", + a_ctrl->bridge_intf.device_hdl, + a_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + + if (a_ctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_ACTUATOR, + "Device [%d] still active on link 0x%x", + a_ctrl->cam_act_state, + a_ctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + rc = cam_destroy_device_hdl(a_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, "destroying the device hdl"); + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.session_hdl = -1; + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + a_ctrl->last_flush_req = 0; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + } + break; + case CAM_QUERY_CAP: { + struct cam_actuator_query_cap actuator_cap = {0}; + + actuator_cap.slot_info = a_ctrl->soc_info.index; + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &actuator_cap, + sizeof(struct cam_actuator_query_cap))) { + CAM_ERR(CAM_ACTUATOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + } + break; + case CAM_START_DEV: { + if (a_ctrl->cam_act_state != CAM_ACTUATOR_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to start : %d", + a_ctrl->cam_act_state); + goto release_mutex; + } + a_ctrl->cam_act_state = CAM_ACTUATOR_START; + a_ctrl->last_flush_req = 0; + } + break; + case CAM_STOP_DEV: { + struct i2c_settings_array *i2c_set = NULL; + int i; + + if (a_ctrl->cam_act_state != CAM_ACTUATOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_ACTUATOR, + "Not in right state to stop : %d", + a_ctrl->cam_act_state); + goto release_mutex; + } + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(a_ctrl->i2c_data.per_frame[i]); + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + } + } + a_ctrl->last_flush_req = 0; + a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; + } + break; + case CAM_CONFIG_DEV: { + a_ctrl->setting_apply_state = + ACT_APPLY_SETTINGS_LATER; + rc = cam_actuator_i2c_pkt_parse(a_ctrl, arg); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed in actuator Parsing"); + goto release_mutex; + } + + if (a_ctrl->setting_apply_state == + ACT_APPLY_SETTINGS_NOW) { + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + if ((rc == -EAGAIN) && + (a_ctrl->io_master_info.master_type == CCI_MASTER)) { + CAM_WARN(CAM_ACTUATOR, + "CCI HW is in resetting mode:: Reapplying Init settings"); + usleep_range(5000, 5010); + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + } + + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, + "Failed to apply Init settings: rc = %d", + rc); + /* Delete the request even if the apply is failed */ + rc = delete_request(&a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed in Deleting the Init Pkt: %d", + rc); + goto release_mutex; + } + } + } + break; + default: + CAM_ERR(CAM_ACTUATOR, "Invalid Opcode %d", cmd->op_code); + } + +release_mutex: + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return rc; +} + +int32_t cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush_req) +{ + int32_t rc = 0, i; + uint32_t cancel_req_id_found = 0; + struct cam_actuator_ctrl_t *a_ctrl = NULL; + struct i2c_settings_array *i2c_set = NULL; + + if (!flush_req) + return -EINVAL; + + a_ctrl = (struct cam_actuator_ctrl_t *) + cam_get_device_priv(flush_req->dev_hdl); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Device data is NULL"); + return -EINVAL; + } + + if (a_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_ACTUATOR, "i2c frame data is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + a_ctrl->last_flush_req = flush_req->req_id; + CAM_DBG(CAM_ACTUATOR, "last reqest to flush is %lld", + flush_req->req_id); + } + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(a_ctrl->i2c_data.per_frame[i]); + + if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) + && (i2c_set->request_id != flush_req->req_id)) + continue; + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_ACTUATOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + + if (flush_req->type == + CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + cancel_req_id_found = 1; + break; + } + } + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_ACTUATOR, + "Flush request id:%lld not found in the pending list", + flush_req->req_id); + mutex_unlock(&(a_ctrl->actuator_mutex)); + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h new file mode 100644 index 0000000000000000000000000000000000000000..e5636f26ce36ecd9ae88fdafa55a5c1643b8fe4b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ACTUATOR_CORE_H_ +#define _CAM_ACTUATOR_CORE_H_ + +#include "cam_actuator_dev.h" + +/** + * @power_info: power setting info to control the power + * + * This API construct the default actuator power setting. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int32_t cam_actuator_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info); + +/** + * @apply: Req mgr structure for applying request + * + * This API applies the request that is mentioned + */ +int32_t cam_actuator_apply_request(struct cam_req_mgr_apply_request *apply); + +/** + * @info: Sub device info to req mgr + * + * This API publish the subdevice info to req mgr + */ +int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info); + +/** + * @flush: Req mgr structure for flushing request + * + * This API flushes the request that is mentioned + */ +int cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush); + + +/** + * @link: Link setup info + * + * This API establishes link actuator subdevice with req mgr + */ +int32_t cam_actuator_establish_link( + struct cam_req_mgr_core_dev_link_setup *link); + +/** + * @a_ctrl: Actuator ctrl structure + * @arg: Camera control command argument + * + * This API handles the camera control argument reached to actuator + */ +int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, void *arg); + +/** + * @a_ctrl: Actuator ctrl structure + * + * This API handles the shutdown ioctl/close + */ +void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl); + +#endif /* _CAM_ACTUATOR_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..46bd99fc9e292c4ae288d3929109760e5c87c01e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_actuator_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_actuator_soc.h" +#include "cam_actuator_core.h" +#include "cam_trace.h" + +static long cam_actuator_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_actuator_driver_cmd(a_ctrl, arg); + break; + default: + CAM_ERR(CAM_ACTUATOR, "Invalid ioctl cmd"); + rc = -EINVAL; + break; + } + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_actuator_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_ACTUATOR, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + cmd = VIDIOC_CAM_CONTROL; + rc = cam_actuator_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "Failed in actuator subdev handling rc: %d", + rc); + return rc; + } + break; + default: + CAM_ERR(CAM_ACTUATOR, "Invalid compat ioctl: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_ACTUATOR, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + return rc; +} +#endif + +static int cam_actuator_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_actuator_ctrl_t *a_ctrl = + v4l2_get_subdevdata(sd); + + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "a_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_actuator_subdev_core_ops = { + .ioctl = cam_actuator_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_actuator_init_subdev_do_ioctl, +#endif +}; + +static struct v4l2_subdev_ops cam_actuator_subdev_ops = { + .core = &cam_actuator_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_actuator_internal_ops = { + .close = cam_actuator_subdev_close, +}; + +static int cam_actuator_init_subdev(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc = 0; + + a_ctrl->v4l2_dev_str.internal_ops = + &cam_actuator_internal_ops; + a_ctrl->v4l2_dev_str.ops = + &cam_actuator_subdev_ops; + strlcpy(a_ctrl->device_name, CAMX_ACTUATOR_DEV_NAME, + sizeof(a_ctrl->device_name)); + a_ctrl->v4l2_dev_str.name = + a_ctrl->device_name; + a_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + a_ctrl->v4l2_dev_str.ent_function = + CAM_ACTUATOR_DEVICE_TYPE; + a_ctrl->v4l2_dev_str.token = a_ctrl; + + rc = cam_register_subdev(&(a_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev rc: %d", rc); + + return rc; +} + +static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + int32_t i = 0; + struct cam_actuator_ctrl_t *a_ctrl; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_actuator_soc_private *soc_private = NULL; + + if (client == NULL || id == NULL) { + CAM_ERR(CAM_ACTUATOR, "Invalid Args client: %pK id: %pK", + client, id); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_ACTUATOR, "%s :: i2c_check_functionality failed", + client->name); + rc = -EFAULT; + return rc; + } + + /* Create sensor control structure */ + a_ctrl = kzalloc(sizeof(*a_ctrl), GFP_KERNEL); + if (!a_ctrl) + return -ENOMEM; + + i2c_set_clientdata(client, a_ctrl); + + soc_private = kzalloc(sizeof(struct cam_actuator_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_ctrl; + } + a_ctrl->soc_info.soc_private = soc_private; + + a_ctrl->io_master_info.client = client; + soc_info = &a_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + a_ctrl->io_master_info.master_type = I2C_MASTER; + + rc = cam_actuator_parse_dt(a_ctrl, &client->dev); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "failed: cam_sensor_parse_dt rc %d", rc); + goto free_soc; + } + + rc = cam_actuator_init_subdev(a_ctrl); + if (rc) + goto free_soc; + + if (soc_private->i2c_info.slave_addr != 0) + a_ctrl->io_master_info.client->addr = + soc_private->i2c_info.slave_addr; + + a_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (a_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(a_ctrl->i2c_data.per_frame[i].list_head)); + + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.ops.get_dev_info = + cam_actuator_publish_dev_info; + a_ctrl->bridge_intf.ops.link_setup = + cam_actuator_establish_link; + a_ctrl->bridge_intf.ops.apply_req = + cam_actuator_apply_request; + a_ctrl->last_flush_req = 0; + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + + return rc; + +unreg_subdev: + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); +free_soc: + kfree(soc_private); +free_ctrl: + kfree(a_ctrl); + return rc; +} + +static int32_t cam_actuator_platform_remove(struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_actuator_ctrl_t *a_ctrl; + struct cam_actuator_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + a_ctrl = platform_get_drvdata(pdev); + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Actuator device is NULL"); + return 0; + } + + CAM_INFO(CAM_ACTUATOR, "platform remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); + + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + kfree(a_ctrl->io_master_info.cci_client); + a_ctrl->io_master_info.cci_client = NULL; + kfree(a_ctrl->soc_info.soc_private); + a_ctrl->soc_info.soc_private = NULL; + kfree(a_ctrl->i2c_data.per_frame); + a_ctrl->i2c_data.per_frame = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, a_ctrl); + + return rc; +} + +static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) +{ + struct cam_actuator_ctrl_t *a_ctrl = + i2c_get_clientdata(client); + struct cam_actuator_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + /* Handle I2C Devices */ + if (!a_ctrl) { + CAM_ERR(CAM_ACTUATOR, "Actuator device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_ACTUATOR, "i2c remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + /*Free Allocated Mem */ + kfree(a_ctrl->i2c_data.per_frame); + a_ctrl->i2c_data.per_frame = NULL; + a_ctrl->soc_info.soc_private = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); + kfree(a_ctrl); + + return 0; +} + +static const struct of_device_id cam_actuator_driver_dt_match[] = { + {.compatible = "qcom,actuator"}, + {} +}; + +static int32_t cam_actuator_driver_platform_probe( + struct platform_device *pdev) +{ + int32_t rc = 0; + int32_t i = 0; + struct cam_actuator_ctrl_t *a_ctrl = NULL; + struct cam_actuator_soc_private *soc_private = NULL; + + /* Create actuator control structure */ + a_ctrl = devm_kzalloc(&pdev->dev, + sizeof(struct cam_actuator_ctrl_t), GFP_KERNEL); + if (!a_ctrl) + return -ENOMEM; + + /*fill in platform device*/ + a_ctrl->v4l2_dev_str.pdev = pdev; + a_ctrl->soc_info.pdev = pdev; + a_ctrl->soc_info.dev = &pdev->dev; + a_ctrl->soc_info.dev_name = pdev->name; + a_ctrl->io_master_info.master_type = CCI_MASTER; + + a_ctrl->io_master_info.cci_client = kzalloc(sizeof( + struct cam_sensor_cci_client), GFP_KERNEL); + if (!(a_ctrl->io_master_info.cci_client)) { + rc = -ENOMEM; + goto free_ctrl; + } + + soc_private = kzalloc(sizeof(struct cam_actuator_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_cci_client; + } + a_ctrl->soc_info.soc_private = soc_private; + soc_private->power_info.dev = &pdev->dev; + + a_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (a_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto free_soc; + } + + INIT_LIST_HEAD(&(a_ctrl->i2c_data.init_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(a_ctrl->i2c_data.per_frame[i].list_head)); + + rc = cam_actuator_parse_dt(a_ctrl, &(pdev->dev)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Paring actuator dt failed rc %d", rc); + goto free_mem; + } + + /* Fill platform device id*/ + pdev->id = a_ctrl->soc_info.index; + + rc = cam_actuator_init_subdev(a_ctrl); + if (rc) + goto free_mem; + + a_ctrl->bridge_intf.device_hdl = -1; + a_ctrl->bridge_intf.link_hdl = -1; + a_ctrl->bridge_intf.ops.get_dev_info = + cam_actuator_publish_dev_info; + a_ctrl->bridge_intf.ops.link_setup = + cam_actuator_establish_link; + a_ctrl->bridge_intf.ops.apply_req = + cam_actuator_apply_request; + a_ctrl->bridge_intf.ops.flush_req = + cam_actuator_flush_request; + a_ctrl->last_flush_req = 0; + + platform_set_drvdata(pdev, a_ctrl); + a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + + return rc; + +free_mem: + kfree(a_ctrl->i2c_data.per_frame); +free_soc: + kfree(soc_private); +free_cci_client: + kfree(a_ctrl->io_master_info.cci_client); +free_ctrl: + devm_kfree(&pdev->dev, a_ctrl); + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_actuator_driver_dt_match); + +static struct platform_driver cam_actuator_platform_driver = { + .probe = cam_actuator_driver_platform_probe, + .driver = { + .name = "qcom,actuator", + .owner = THIS_MODULE, + .of_match_table = cam_actuator_driver_dt_match, + .suppress_bind_attrs = true, + }, + .remove = cam_actuator_platform_remove, +}; + +static const struct i2c_device_id i2c_id[] = { + {ACTUATOR_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_actuator_driver_i2c = { + .id_table = i2c_id, + .probe = cam_actuator_driver_i2c_probe, + .remove = cam_actuator_driver_i2c_remove, + .driver = { + .name = ACTUATOR_DRIVER_I2C, + }, +}; + +static int __init cam_actuator_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_actuator_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "platform_driver_register failed rc = %d", rc); + return rc; + } + rc = i2c_add_driver(&cam_actuator_driver_i2c); + if (rc) + CAM_ERR(CAM_ACTUATOR, "i2c_add_driver failed rc = %d", rc); + + return rc; +} + +static void __exit cam_actuator_driver_exit(void) +{ + platform_driver_unregister(&cam_actuator_platform_driver); + i2c_del_driver(&cam_actuator_driver_i2c); +} + +module_init(cam_actuator_driver_init); +module_exit(cam_actuator_driver_exit); +MODULE_DESCRIPTION("cam_actuator_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h new file mode 100755 index 0000000000000000000000000000000000000000..be6f8dd994ed572811f736714e218654f3650e47 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _CAM_ACTUATOR_DEV_H_ +#define _CAM_ACTUATOR_DEV_H_ + +#include <cam_sensor_io.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <cam_cci_dev.h> +#include <cam_sensor_cmn_header.h> +#include <cam_subdev.h> +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_context.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define ACTUATOR_DRIVER_I2C "i2c_actuator" +#define CAMX_ACTUATOR_DEV_NAME "cam-actuator-driver" + +#define MSM_ACTUATOR_MAX_VREGS (10) +#define ACTUATOR_MAX_POLL_COUNT 10 + +enum cam_actuator_apply_state_t { + ACT_APPLY_SETTINGS_NOW, + ACT_APPLY_SETTINGS_LATER, +}; + +enum cam_actuator_state { + CAM_ACTUATOR_INIT, + CAM_ACTUATOR_ACQUIRE, + CAM_ACTUATOR_CONFIG, + CAM_ACTUATOR_START, +}; + +/** + * struct cam_actuator_i2c_info_t - I2C info + * @slave_addr : slave address + * @i2c_freq_mode : i2c frequency mode + */ +struct cam_actuator_i2c_info_t { + uint16_t slave_addr; + uint8_t i2c_freq_mode; +}; + +struct cam_actuator_soc_private { + struct cam_actuator_i2c_info_t i2c_info; + struct cam_sensor_power_ctrl_t power_info; +}; + +/** + * struct intf_params + * @device_hdl: Device Handle + * @session_hdl: Session Handle + * @ops: KMD operations + * @crm_cb: Callback API pointers + */ +struct intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_actuator_ctrl_t + * @device_name: Device name + * @i2c_driver: I2C device info + * @pdev: Platform device + * @cci_i2c_master: I2C structure + * @io_master_info: Information about the communication master + * @actuator_mutex: Actuator mutex + * @act_apply_state: Actuator settings aRegulator config + * @id: Cell Index + * @res_apply_state: Actuator settings apply state + * @cam_act_state: Actuator state + * @gconf: GPIO config + * @pinctrl_info: Pinctrl information + * @v4l2_dev_str: V4L2 device structure + * @i2c_data: I2C register settings structure + * @act_info: Sensor query cap structure + * @of_node: Node ptr + * @last_flush_req: Last request to flush + */ +struct cam_actuator_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct i2c_driver *i2c_driver; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct camera_io_master io_master_info; + struct cam_hw_soc_info soc_info; + struct mutex actuator_mutex; + uint32_t id; + enum cam_actuator_apply_state_t setting_apply_state; + enum cam_actuator_state cam_act_state; + uint8_t cam_pinctrl_status; + struct cam_subdev v4l2_dev_str; + struct i2c_data_settings i2c_data; + struct cam_actuator_query_cap act_info; + struct intf_params bridge_intf; + uint32_t last_flush_req; + + bool is_actuator_ready; + struct cam_sensor_i2c_reg_array poll_register; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; +}; + +#endif /* _CAM_ACTUATOR_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..3ee629e3f1ca835f42632fbe3f4a1b697962b4e2 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <cam_sensor_cmn_header.h> +#include <cam_sensor_util.h> +#include <cam_sensor_io.h> +#include <cam_req_mgr_util.h> +#include "cam_actuator_soc.h" +#include "cam_soc_util.h" + +int32_t cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl, + struct device *dev) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info = &a_ctrl->soc_info; + struct cam_actuator_soc_private *soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + struct device_node *of_node = NULL; + struct device_node *of_parent = NULL; + + /* Initialize mutex */ + mutex_init(&(a_ctrl->actuator_mutex)); + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "parsing common soc dt(rc %d)", rc); + return rc; + } + + of_node = soc_info->dev->of_node; + + if (a_ctrl->io_master_info.master_type == CCI_MASTER) { + rc = of_property_read_u32(of_node, "cci-master", + &(a_ctrl->cci_i2c_master)); + CAM_DBG(CAM_ACTUATOR, "cci-master %d, rc %d", + a_ctrl->cci_i2c_master, rc); + if ((rc < 0) || (a_ctrl->cci_i2c_master >= MASTER_MAX)) { + CAM_ERR(CAM_ACTUATOR, + "Wrong info: rc: %d, dt CCI master:%d", + rc, a_ctrl->cci_i2c_master); + rc = -EFAULT; + return rc; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &a_ctrl->cci_num) < 0) + /* Set default master 0 */ + a_ctrl->cci_num = CCI_DEVICE_0; + a_ctrl->io_master_info.cci_client->cci_device = a_ctrl->cci_num; + CAM_DBG(CAM_ACTUATOR, "cci-device %d", a_ctrl->cci_num); + } + + if (!soc_info->gpio_data) { + CAM_INFO(CAM_ACTUATOR, "No GPIO found"); + rc = 0; + return rc; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_ACTUATOR, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &power_info->gpio_num_info); + if ((rc < 0) || (!power_info->gpio_num_info)) { + CAM_ERR(CAM_ACTUATOR, "No/Error Actuator GPIOs"); + return -EINVAL; + } + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..65b4fb99fa0337350c62ad905833fde34b5e1976 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_ACTUATOR_SOC_H_ +#define _CAM_ACTUATOR_SOC_H_ + +#include "cam_actuator_dev.h" + +/** + * @a_ctrl: Actuator ctrl structure + * + * This API parses actuator device tree + */ +int cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl, + struct device *dev); + +#endif /* _CAM_ACTUATOR_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_cci/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..a1301bf41d5d3d31c851b7d1308041a77bf6acb7 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci_dev.o cam_cci_core.o cam_cci_soc.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c new file mode 100644 index 0000000000000000000000000000000000000000..4e1238ce1a4e4c391793e4341001f88ccd4ea03b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -0,0 +1,1948 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include "cam_cci_core.h" +#include "cam_cci_dev.h" +#include "cam_cci_ctrl_interface.h" +#define DUMP_CCI_REGISTERS + +static int32_t cam_cci_convert_type_to_num_bytes( + enum camera_sensor_i2c_type type) +{ + int32_t num_bytes; + + switch (type) { + case CAMERA_SENSOR_I2C_TYPE_BYTE: + num_bytes = 1; + break; + case CAMERA_SENSOR_I2C_TYPE_WORD: + num_bytes = 2; + break; + case CAMERA_SENSOR_I2C_TYPE_3B: + num_bytes = 3; + break; + case CAMERA_SENSOR_I2C_TYPE_DWORD: + num_bytes = 4; + break; + default: + CAM_ERR(CAM_CCI, "failed: %d", type); + num_bytes = 0; + break; + } + return num_bytes; +} + +static void cam_cci_flush_queue(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + cam_io_w_mb(1 << master, base + CCI_HALT_REQ_ADDR); + if (!cci_dev->cci_master_info[master].status) + reinit_completion(&cci_dev->cci_master_info[master] + .reset_complete); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc < 0) { + CAM_ERR(CAM_CCI, "wait failed"); + } else if (rc == 0) { + CAM_ERR(CAM_CCI, "wait timeout"); + + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; + cci_dev->cci_master_info[master].status = 0; + + /* Set proper mask to RESET CMD address based on MASTER */ + if (master == MASTER_0) + cam_io_w_mb(CCI_M0_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + else + cam_io_w_mb(CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + + /* wait for reset done irq */ + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT); + if (rc <= 0) + CAM_ERR(CAM_CCI, "wait failed %d", rc); + cci_dev->cci_master_info[master].status = 0; + } +} + +static int32_t cam_cci_validate_queue(struct cci_device *cci_dev, + uint32_t len, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t read_val = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + unsigned long flags; + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d", + read_val, len, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); + if ((read_val + len + 1) > + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size) { + uint32_t reg_val = 0; + uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); + + CAM_DBG(CAM_CCI, "CCI_I2C_REPORT_CMD"); + cam_io_w_mb(report_val, + base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + read_val++; + CAM_DBG(CAM_CCI, + "CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d, queue: %d", + read_val, queue); + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + reg_val = 1 << ((master * 2) + queue); + CAM_DBG(CAM_CCI, "CCI_QUEUE_START_ADDR"); + spin_lock_irqsave( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + atomic_set( + &cci_dev->cci_master_info[master].done_pending[queue], + 1); + cam_io_w_mb(reg_val, base + + CCI_QUEUE_START_ADDR); + CAM_DBG(CAM_CCI, "wait_for_completion_timeout"); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].report_q[queue], + CCI_TIMEOUT); + if (rc <= 0) { + CAM_ERR(CAM_CCI, "Wait_for_completion_timeout: rc: %d", + rc); + if (rc == 0) + rc = -ETIMEDOUT; + cam_cci_flush_queue(cci_dev, master); + return rc; + } + rc = cci_dev->cci_master_info[master].status; + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed rc %d", rc); + cci_dev->cci_master_info[master].status = 0; + } + } + + return rc; +} + +static int32_t cam_cci_write_i2c_queue(struct cci_device *cci_dev, + uint32_t val, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "Failed"); + return -EINVAL; + } + + rc = cam_cci_validate_queue(cci_dev, 1, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed %d", rc); + return rc; + } + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x", + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset, val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + return rc; +} + +static int32_t cam_cci_lock_queue(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue, uint32_t en) +{ + uint32_t val; + + if (queue != PRIORITY_QUEUE) + return 0; + + val = en ? CCI_I2C_LOCK_CMD : CCI_I2C_UNLOCK_CMD; + return cam_cci_write_i2c_queue(cci_dev, val, master, queue); +} + +#ifdef DUMP_CCI_REGISTERS +static void cam_cci_dump_registers(struct cci_device *cci_dev, + enum cci_i2c_master_t master, enum cci_i2c_queue_t queue) +{ + uint32_t read_val = 0; + uint32_t i = 0; + uint32_t reg_offset = 0; + uint32_t read_buf_level = 0; + uint32_t read_data_reg_offset = 0x0; + void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; + + /* CCI Top Registers */ + CAM_INFO(CAM_CCI, "****CCI TOP Registers ****"); + for (i = 0; i < DEBUG_TOP_REG_COUNT; i++) { + reg_offset = DEBUG_TOP_REG_START + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } + + /* CCI Master registers */ + CAM_INFO(CAM_CCI, "****CCI MASTER %d Registers ****", + master); + read_buf_level = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + read_data_reg_offset = CCI_I2C_M0_READ_DATA_ADDR + master * 0x100; + for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { + reg_offset = DEBUG_MASTER_REG_START + master*0x100 + i * 4; + /* + * Don't read from READ_DATA_ADDR if + * i2c read fifo is empty, this may lead to + * read underflow status bits getting set + */ + if ((read_buf_level == 0) && + (reg_offset == read_data_reg_offset)) + continue; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } + + /* CCI Master Queue registers */ + CAM_INFO(CAM_CCI, " **** CCI MASTER%d QUEUE%d Registers ****", + master, queue); + for (i = 0; i < DEBUG_MASTER_QUEUE_REG_COUNT; i++) { + reg_offset = DEBUG_MASTER_QUEUE_REG_START + master*0x200 + + queue*0x100 + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } + + /* CCI Interrupt registers */ + CAM_INFO(CAM_CCI, " ****CCI Interrupt Registers ****"); + for (i = 0; i < DEBUG_INTR_REG_COUNT; i++) { + reg_offset = DEBUG_INTR_REG_START + i * 4; + read_val = cam_io_r_mb(base + reg_offset); + CAM_INFO(CAM_CCI, "offset = 0x%X value = 0x%X", + reg_offset, read_val); + } +} +#endif + +static uint32_t cam_cci_wait(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "failed"); + return -EINVAL; + } + + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].report_q[queue], CCI_TIMEOUT); + CAM_DBG(CAM_CCI, "wait DONE_for_completion_timeout"); + + if (rc <= 0) { +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + CAM_ERR(CAM_CCI, "wait for queue: %d", queue); + if (rc == 0) + rc = -ETIMEDOUT; + cam_cci_flush_queue(cci_dev, master); + return rc; + } + rc = cci_dev->cci_master_info[master].status; + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + cci_dev->cci_master_info[master].status = 0; + return rc; + } + + return 0; +} + +static void cam_cci_load_report_cmd(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + uint32_t reg_offset = master * 0x200 + queue * 0x100; + uint32_t read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8); + + CAM_DBG(CAM_CCI, "CCI_I2C_REPORT_CMD curr_w_cnt: %d", read_val); + cam_io_w_mb(report_val, + base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + read_val++; + + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d", read_val); + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); +} + +static int32_t cam_cci_wait_report_cmd(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + unsigned long flags; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + uint32_t reg_val = 1 << ((master * 2) + queue); + + cam_cci_load_report_cmd(cci_dev, master, queue); + spin_lock_irqsave( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); + atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + cam_io_w_mb(reg_val, base + + CCI_QUEUE_START_ADDR); + + return cam_cci_wait(cci_dev, master, queue); +} + +static int32_t cam_cci_transfer_end(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + unsigned long flags; + + spin_lock_irqsave( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) { + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_lock_queue(cci_dev, master, queue, 0); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + return rc; + } + rc = cam_cci_wait_report_cmd(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + } else { + atomic_set( + &cci_dev->cci_master_info[master].done_pending[queue], + 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_wait(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + rc = cam_cci_lock_queue(cci_dev, master, queue, 0); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + rc = cam_cci_wait_report_cmd(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed rc %d", rc); + return rc; + } + } + + return rc; +} + +static int32_t cam_cci_get_queue_free_size(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + uint32_t read_val = 0; + uint32_t reg_offset = master * 0x200 + queue * 0x100; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d max %d", read_val, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size); + return ((cci_dev->cci_i2c_queue_info[master][queue].max_queue_size) - + read_val); +} + +static void cam_cci_process_half_q(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + unsigned long flags; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + uint32_t reg_val = 1 << ((master * 2) + queue); + + spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 0) { + cam_cci_load_report_cmd(cci_dev, master, queue); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1); + cam_io_w_mb(reg_val, base + + CCI_QUEUE_START_ADDR); + } + spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue], + flags); +} + +static int32_t cam_cci_process_full_q(struct cci_device *cci_dev, + enum cci_i2c_master_t master, + enum cci_i2c_queue_t queue) +{ + int32_t rc = 0; + unsigned long flags; + + + spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + if (atomic_read(&cci_dev->cci_master_info[master].q_free[queue]) == 1) { + atomic_set( + &cci_dev->cci_master_info[master].done_pending[queue], + 1); + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_wait(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + } else { + spin_unlock_irqrestore( + &cci_dev->cci_master_info[master].lock_q[queue], flags); + rc = cam_cci_wait_report_cmd(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + return rc; + } + } + + return rc; +} + +static int32_t cam_cci_calc_cmd_len(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl, uint32_t cmd_size, + struct cam_sensor_i2c_reg_array *i2c_cmd, uint32_t *pack) +{ + uint8_t i; + uint32_t len = 0; + uint8_t data_len = 0, addr_len = 0; + uint8_t pack_max_len; + struct cam_sensor_i2c_reg_setting *msg; + struct cam_sensor_i2c_reg_array *cmd = i2c_cmd; + uint32_t size = cmd_size; + + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed"); + return -EINVAL; + } + + msg = &c_ctrl->cfg.cci_i2c_write_cfg; + *pack = 0; + + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) { + addr_len = cam_cci_convert_type_to_num_bytes(msg->addr_type); + len = (size + addr_len) <= (cci_dev->payload_size) ? + (size + addr_len):cci_dev->payload_size; + } else { + addr_len = cam_cci_convert_type_to_num_bytes(msg->addr_type); + data_len = cam_cci_convert_type_to_num_bytes(msg->data_type); + len = data_len + addr_len; + pack_max_len = size < (cci_dev->payload_size-len) ? + size : (cci_dev->payload_size-len); + for (i = 0; i < pack_max_len;) { + if (cmd->delay || ((cmd - i2c_cmd) >= (cmd_size - 1))) + break; + if (cmd->reg_addr + 1 == + (cmd+1)->reg_addr) { + len += data_len; + if (len > cci_dev->payload_size) { + len = len - data_len; + break; + } + (*pack)++; + } else { + break; + } + i += data_len; + cmd++; + } + } + + if (len > cci_dev->payload_size) { + CAM_ERR(CAM_CCI, "Len error: %d", len); + return -EINVAL; + } + + len += 1; /*add i2c WR command*/ + len = len/4 + 1; + + return len; +} + +static uint32_t cam_cci_cycles_per_ms(unsigned long clk) +{ + uint32_t cycles_per_us; + + if (clk) { + cycles_per_us = ((clk/1000)*256)/1000; + } else { + CAM_ERR(CAM_CCI, "failed: Can use default: %d", + CYCLES_PER_MICRO_SEC_DEFAULT); + cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT; + } + + return cycles_per_us; +} + +void cam_cci_get_clk_rates(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl) + +{ + int32_t src_clk_idx, j; + uint32_t cci_clk_src; + unsigned long clk; + struct cam_cci_clk_params_t *clk_params = NULL; + + enum i2c_freq_mode i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; + + if (i2c_freq_mode >= I2C_MAX_MODES || + i2c_freq_mode < I2C_STANDARD_MODE) { + CAM_ERR(CAM_CCI, "Invalid frequency mode: %d", + (int32_t)i2c_freq_mode); + cci_dev->clk_level_index = -1; + return; + } + + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; + cci_clk_src = clk_params->cci_clk_src; + + src_clk_idx = soc_info->src_clk_idx; + + if (src_clk_idx < 0) { + cci_dev->cycles_per_us = CYCLES_PER_MICRO_SEC_DEFAULT; + cci_dev->clk_level_index = 0; + return; + } + + if (cci_clk_src == 0) { + clk = soc_info->clk_rate[0][src_clk_idx]; + cci_dev->cycles_per_us = cam_cci_cycles_per_ms(clk); + cci_dev->clk_level_index = 0; + return; + } + + for (j = 0; j < CAM_MAX_VOTE; j++) { + clk = soc_info->clk_rate[j][src_clk_idx]; + if (clk == cci_clk_src) { + cci_dev->cycles_per_us = cam_cci_cycles_per_ms(clk); + cci_dev->clk_level_index = j; + return; + } + } +} + +static int32_t cam_cci_set_clk_param(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl) +{ + struct cam_cci_clk_params_t *clk_params = NULL; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + enum i2c_freq_mode i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + + if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) { + CAM_ERR(CAM_CCI, "invalid i2c_freq_mode = %d", i2c_freq_mode); + return -EINVAL; + } + + clk_params = &cci_dev->cci_clk_params[i2c_freq_mode]; + + if (cci_dev->i2c_freq_mode[master] == i2c_freq_mode) + return 0; + if (master == MASTER_0) { + cam_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + base + CCI_I2C_M0_SCL_CTL_ADDR); + cam_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + base + CCI_I2C_M0_SDA_CTL_0_ADDR); + cam_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + base + CCI_I2C_M0_SDA_CTL_1_ADDR); + cam_io_w_mb(clk_params->hw_tbuf, + base + CCI_I2C_M0_SDA_CTL_2_ADDR); + cam_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + base + CCI_I2C_M0_MISC_CTL_ADDR); + } else if (master == MASTER_1) { + cam_io_w_mb(clk_params->hw_thigh << 16 | + clk_params->hw_tlow, + base + CCI_I2C_M1_SCL_CTL_ADDR); + cam_io_w_mb(clk_params->hw_tsu_sto << 16 | + clk_params->hw_tsu_sta, + base + CCI_I2C_M1_SDA_CTL_0_ADDR); + cam_io_w_mb(clk_params->hw_thd_dat << 16 | + clk_params->hw_thd_sta, + base + CCI_I2C_M1_SDA_CTL_1_ADDR); + cam_io_w_mb(clk_params->hw_tbuf, + base + CCI_I2C_M1_SDA_CTL_2_ADDR); + cam_io_w_mb(clk_params->hw_scl_stretch_en << 8 | + clk_params->hw_trdhld << 4 | clk_params->hw_tsp, + base + CCI_I2C_M1_MISC_CTL_ADDR); + } + cci_dev->i2c_freq_mode[master] = i2c_freq_mode; + + return 0; +} + +static int32_t cam_cci_data_queue(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, + enum cci_i2c_sync sync_en) +{ + uint16_t i = 0, j = 0, k = 0, h = 0, len = 0; + int32_t rc = 0, free_size = 0, en_seq_write = 0; + uint8_t data[12]; + struct cam_sensor_i2c_reg_setting *i2c_msg = + &c_ctrl->cfg.cci_i2c_write_cfg; + struct cam_sensor_i2c_reg_array *i2c_cmd = i2c_msg->reg_setting; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + uint16_t reg_addr = 0, cmd_size = i2c_msg->size; + uint32_t read_val = 0, reg_offset, val, delay = 0; + uint32_t max_queue_size, queue_size = 0, cmd = 0; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + unsigned long flags; + + if (i2c_cmd == NULL) { + CAM_ERR(CAM_CCI, "Failed: i2c cmd is NULL"); + return -EINVAL; + } + + if ((!cmd_size) || (cmd_size > CCI_I2C_MAX_WRITE)) { + CAM_ERR(CAM_CCI, "failed: invalid cmd_size %d", + cmd_size); + return -EINVAL; + } + + CAM_DBG(CAM_CCI, "addr type %d data type %d cmd_size %d", + i2c_msg->addr_type, i2c_msg->data_type, cmd_size); + + if (i2c_msg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed: invalid addr_type 0x%X", + i2c_msg->addr_type); + return -EINVAL; + } + if (i2c_msg->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed: invalid data_type 0x%X", + i2c_msg->data_type); + return -EINVAL; + } + reg_offset = master * 0x200 + queue * 0x100; + + cam_io_w_mb(cci_dev->cci_wait_sync_cfg.cid, + base + CCI_SET_CID_SYNC_TIMER_ADDR + + cci_dev->cci_wait_sync_cfg.csid * + CCI_SET_CID_SYNC_TIMER_OFFSET); + + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + + CAM_DBG(CAM_CCI, "CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val 0x%x:0x%x", + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset, val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + + spin_lock_irqsave(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0); + spin_unlock_irqrestore(&cci_dev->cci_master_info[master].lock_q[queue], + flags); + + max_queue_size = + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size; + + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) + queue_size = max_queue_size; + else + queue_size = max_queue_size/2; + reg_addr = i2c_cmd->reg_addr; + + if (sync_en == MSM_SYNC_ENABLE && cci_dev->valid_sync && + cmd_size < max_queue_size) { + val = CCI_I2C_WAIT_SYNC_CMD | + ((cci_dev->cci_wait_sync_cfg.line) << 4); + cam_io_w_mb(val, + base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + reg_offset); + } + + rc = cam_cci_lock_queue(cci_dev, master, queue, 1); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed line %d", rc); + return rc; + } + + while (cmd_size) { + uint32_t pack = 0; + + len = cam_cci_calc_cmd_len(cci_dev, c_ctrl, cmd_size, + i2c_cmd, &pack); + if (len <= 0) { + CAM_ERR(CAM_CCI, "failed"); + return -EINVAL; + } + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + CAM_DBG(CAM_CCI, "CUR_WORD_CNT_ADDR %d len %d max %d", + read_val, len, max_queue_size); + /* + 1 - space alocation for Report CMD */ + if ((read_val + len + 1) > queue_size) { + if ((read_val + len + 1) > max_queue_size) { + rc = cam_cci_process_full_q(cci_dev, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + return rc; + } + continue; + } + cam_cci_process_half_q(cci_dev, master, queue); + } + + CAM_DBG(CAM_CCI, "cmd_size %d addr 0x%x data 0x%x", + cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data); + delay = i2c_cmd->delay; + i = 0; + data[i++] = CCI_I2C_WRITE_CMD; + + /* + * in case of multiple command + * MSM_CCI_I2C_WRITE : address is not continuous, so update + * address for a new packet. + * MSM_CCI_I2C_WRITE_SEQ : address is continuous, need to keep + * the incremented address for a + * new packet + */ + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_ASYNC || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_SYNC_BLOCK) + reg_addr = i2c_cmd->reg_addr; + + if (en_seq_write == 0) { + /* either byte or word addr */ + if (i2c_msg->addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + data[i++] = reg_addr; + else { + data[i++] = (reg_addr & 0xFF00) >> 8; + data[i++] = reg_addr & 0x00FF; + } + } + /* max of 10 data bytes */ + do { + if (i2c_msg->data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + data[i++] = i2c_cmd->reg_data; + if (c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ) + reg_addr++; + } else { + if ((i + 1) <= cci_dev->payload_size) { + switch (i2c_msg->data_type) { + case CAMERA_SENSOR_I2C_TYPE_DWORD: + data[i++] = (i2c_cmd->reg_data & + 0xFF000000) >> 24; + /* fallthrough */ + case CAMERA_SENSOR_I2C_TYPE_3B: + data[i++] = (i2c_cmd->reg_data & + 0x00FF0000) >> 16; + /* fallthrough */ + case CAMERA_SENSOR_I2C_TYPE_WORD: + data[i++] = (i2c_cmd->reg_data & + 0x0000FF00) >> 8; + /* fallthrough */ + case CAMERA_SENSOR_I2C_TYPE_BYTE: + data[i++] = i2c_cmd->reg_data & + 0x000000FF; + break; + default: + CAM_ERR(CAM_CCI, + "invalid data type: %d", + i2c_msg->data_type); + return -EINVAL; + } + + if (c_ctrl->cmd == + MSM_CCI_I2C_WRITE_SEQ) + reg_addr++; + } else + break; + } + i2c_cmd++; + --cmd_size; + } while (((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) || pack--) && + (cmd_size > 0) && (i <= cci_dev->payload_size)); + free_size = cam_cci_get_queue_free_size(cci_dev, master, + queue); + if ((c_ctrl->cmd == MSM_CCI_I2C_WRITE_SEQ || + c_ctrl->cmd == MSM_CCI_I2C_WRITE_BURST) && + ((i-1) == MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11) && + cci_dev->support_seq_write && cmd_size > 0 && + free_size > BURST_MIN_FREE_SIZE) { + data[0] |= 0xF0; + en_seq_write = 1; + } else { + data[0] |= ((i-1) << 4); + en_seq_write = 0; + } + len = ((i-1)/4) + 1; + + read_val = cam_io_r_mb(base + + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset); + for (h = 0, k = 0; h < len; h++) { + cmd = 0; + for (j = 0; (j < 4 && k < i); j++) + cmd |= (data[k++] << (j * 8)); + CAM_DBG(CAM_CCI, + "LOAD_DATA_ADDR 0x%x, q: %d, len:%d, cnt: %d", + cmd, queue, len, read_val); + cam_io_w_mb(cmd, base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + + read_val += 1; + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + } + + if ((delay > 0) && (delay < CCI_MAX_DELAY) && + en_seq_write == 0) { + cmd = (uint32_t)((delay * cci_dev->cycles_per_us) / + 0x100); + cmd <<= 4; + cmd |= CCI_I2C_WAIT_CMD; + CAM_DBG(CAM_CCI, + "CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x", cmd); + cam_io_w_mb(cmd, base + + CCI_I2C_M0_Q0_LOAD_DATA_ADDR + + master * 0x200 + queue * 0x100); + read_val += 1; + cam_io_w_mb(read_val, base + + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset); + } + } + + rc = cam_cci_transfer_end(cci_dev, master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Slave: 0x%x failed rc %d", + (c_ctrl->cci_info->sid << 1), rc); + return rc; + } + + return rc; +} + +static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0, i = 0, j = 0, irq_mask_update = 0; + unsigned long rem_jiffies, flags; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0, total_read_words = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct cam_cci_read_cfg *read_cfg = NULL; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto rel_master; + } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); + goto rel_mutex_q; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto rel_mutex_q; + } + + if (read_cfg->data == NULL) { + CAM_ERR(CAM_CCI, "Data ptr is NULL"); + goto rel_mutex_q; + } + + if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", + read_cfg->addr_type); + rc = -EINVAL; + goto rel_mutex_q; + } + + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_LOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); + for (i = 0; i < read_cfg->addr_type; i++) { + val |= ((read_cfg->addr >> (i << 3)) & 0xFF) << + ((read_cfg->addr_type - i) << 3); + } + + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CAM_DBG(CAM_CCI, "cur word cnt 0x%x", val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); + + exp_words = ((read_cfg->num_byte / 4) + 1); + CAM_DBG(CAM_CCI, "waiting for threshold [exp_words %d]", exp_words); + + while (total_read_words != exp_words) { + rem_jiffies = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].th_complete, + CCI_TIMEOUT); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + + master * 0x100); + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d FIFO buf_lvl:0x%x", + rc, val); +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex_q; + } + + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "Error with Salve: 0x%x", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + + read_words = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + if (read_words <= 0) { + CAM_DBG(CAM_CCI, "FIFO Buffer lvl is 0"); + continue; + } + + j++; + CAM_DBG(CAM_CCI, "Iteration: %u read_words %d", j, read_words); + + total_read_words += read_words; + while (read_words > 0) { + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + for (i = 0; (i < 4) && + (index < read_cfg->num_byte); i++) { + CAM_DBG(CAM_CCI, "i:%d index:%d", i, index); + if (!first_byte) { + CAM_DBG(CAM_CCI, "sid 0x%x", + val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CAM_DBG(CAM_CCI, "data[%d] 0x%x", index, + read_cfg->data[index]); + index++; + } + } + read_words--; + } + + CAM_DBG(CAM_CCI, "Iteraion:%u total_read_words %d", + j, total_read_words); + + spin_lock_irqsave(&cci_dev->lock_status, flags); + if (cci_dev->irqs_disabled) { + irq_mask_update = + cam_io_r_mb(base + CCI_IRQ_MASK_1_ADDR) | + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + if (master == MASTER_0 && cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) + irq_mask_update |= + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + else if (master == MASTER_1 && cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) + irq_mask_update |= + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + cam_io_w_mb(irq_mask_update, + base + CCI_IRQ_MASK_1_ADDR); + } + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + + if (total_read_words == exp_words) { + /* + * This wait is for RD_DONE irq, if RD_DONE is + * triggered we will call complete on both threshold + * & read done waits. As part of the threshold wait + * we will be draining the entire buffer out. This + * wait is to compensate for the complete invoked for + * RD_DONE exclusively. + */ + rem_jiffies = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].rd_done, + CCI_TIMEOUT); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + + master * 0x100); + CAM_ERR(CAM_CCI, + "Failed to receive RD_DONE irq rc = %d FIFO buf_lvl:0x%x", + rc, val); + #ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, + master, queue); + #endif + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex_q; + } + + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "Error with Slave 0x%x", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + break; + } + } + + CAM_DBG(CAM_CCI, "Burst read successful words_read %d", + total_read_words); + +rel_mutex_q: + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + return rc; +} + +static int32_t cam_cci_read(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + uint32_t val = 0; + int32_t read_words = 0, exp_words = 0; + int32_t index = 0, first_byte = 0; + uint32_t i = 0; + enum cci_i2c_master_t master; + enum cci_i2c_queue_t queue = QUEUE_1; + struct cci_device *cci_dev = NULL; + struct cam_cci_read_cfg *read_cfg = NULL; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + goto rel_master; + } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); + + // read operation done only in Q1 + reinit_completion(&cci_dev->cci_master_info[master].rd_done); + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_read call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size - 1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); + goto rel_mutex_q; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto rel_mutex_q; + } + + if (read_cfg->data == NULL) { + CAM_ERR(CAM_CCI, "Data ptr is NULL"); + goto rel_mutex_q; + } + + CAM_DBG(CAM_CCI, "master %d, queue %d", master, queue); + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 | + c_ctrl->cci_info->retries << 16 | + c_ctrl->cci_info->id_map << 18; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_LOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", + read_cfg->addr_type); + rc = -EINVAL; + goto rel_mutex_q; + } + + val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); + for (i = 0; i < read_cfg->addr_type; i++) { + val |= ((read_cfg->addr >> (i << 3)) & 0xFF) << + ((read_cfg->addr_type - i) << 3); + } + + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = CCI_I2C_UNLOCK_CMD; + rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); + if (rc < 0) { + CAM_DBG(CAM_CCI, "failed rc: %d", rc); + goto rel_mutex_q; + } + + val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + CAM_DBG(CAM_CCI, "cur word cnt 0x%x", val); + cam_io_w_mb(val, base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + + master * 0x200 + queue * 0x100); + + val = 1 << ((master * 2) + queue); + cam_io_w_mb(val, base + CCI_QUEUE_START_ADDR); + CAM_DBG(CAM_CCI, + "waiting_for_rd_done [exp_words: %d]", + ((read_cfg->num_byte / 4) + 1)); + + rc = wait_for_completion_timeout( + &cci_dev->cci_master_info[master].rd_done, CCI_TIMEOUT); + if (rc <= 0) { +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + if (rc == 0) + rc = -ETIMEDOUT; + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d FIFO buf_lvl: 0x%x", + rc, val); + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex_q; + } else { + rc = 0; + } + + if (cci_dev->cci_master_info[master].status) { + CAM_ERR(CAM_CCI, "ERROR with Slave 0x%x:", + (c_ctrl->cci_info->sid << 1)); + rc = -EINVAL; + cci_dev->cci_master_info[master].status = 0; + goto rel_mutex_q; + } + + read_words = cam_io_r_mb(base + + CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100); + exp_words = ((read_cfg->num_byte / 4) + 1); + if (read_words != exp_words) { + CAM_ERR(CAM_CCI, "read_words = %d, exp words = %d", + read_words, exp_words); + memset(read_cfg->data, 0, read_cfg->num_byte); + rc = -EINVAL; + goto rel_mutex_q; + } + index = 0; + CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); + first_byte = 0; + while (read_words > 0) { + val = cam_io_r_mb(base + + CCI_I2C_M0_READ_DATA_ADDR + master * 0x100); + CAM_DBG(CAM_CCI, "read val 0x%x", val); + for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) { + CAM_DBG(CAM_CCI, "i:%d index:%d", i, index); + if (!first_byte) { + CAM_DBG(CAM_CCI, "sid 0x%x", val & 0xFF); + first_byte++; + } else { + read_cfg->data[index] = + (val >> (i * 8)) & 0xFF; + CAM_DBG(CAM_CCI, "data[%d] 0x%x", index, + read_cfg->data[index]); + index++; + } + } + read_words--; + } +rel_mutex_q: + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + return rc; +} + +static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, + enum cci_i2c_sync sync_en) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master; + + cci_dev = v4l2_get_subdevdata(sd); + + if (cci_dev->cci_state != CCI_STATE_ENABLED) { + CAM_ERR(CAM_CCI, "invalid cci state %d", + cci_dev->cci_state); + return -EINVAL; + } + master = c_ctrl->cci_info->cci_i2c_master; + CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", + c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, + c_ctrl->cci_info->id_map); + + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + + /* Set the I2C Frequency */ + rc = cam_cci_set_clk_param(cci_dev, c_ctrl); + if (rc < 0) { + CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto ERROR; + } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + /* + * Call validate queue to make sure queue is empty before starting. + * If this call fails, don't proceed with i2c_write call. This is to + * avoid overflow / underflow of queue + */ + rc = cam_cci_validate_queue(cci_dev, + cci_dev->cci_i2c_queue_info[master][queue].max_queue_size-1, + master, queue); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", + rc); + goto ERROR; + } + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto ERROR; + } + rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + goto ERROR; + } + +ERROR: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + return rc; +} + +static void cam_cci_write_async_helper(struct work_struct *work) +{ + int rc; + struct cci_device *cci_dev; + struct cci_write_async *write_async = + container_of(work, struct cci_write_async, work); + struct cam_sensor_i2c_reg_setting *i2c_msg; + enum cci_i2c_master_t master; + struct cam_cci_master_info *cci_master_info; + + cci_dev = write_async->cci_dev; + i2c_msg = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; + master = write_async->c_ctrl.cci_info->cci_i2c_master; + cci_master_info = &cci_dev->cci_master_info[master]; + + mutex_lock(&cci_master_info->mutex_q[write_async->queue]); + rc = cam_cci_i2c_write(&(cci_dev->v4l2_dev_str.sd), + &write_async->c_ctrl, write_async->queue, write_async->sync_en); + mutex_unlock(&cci_master_info->mutex_q[write_async->queue]); + if (rc < 0) + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + + kfree(write_async->c_ctrl.cfg.cci_i2c_write_cfg.reg_setting); + kfree(write_async); +} + +static int32_t cam_cci_i2c_write_async(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue, + enum cci_i2c_sync sync_en) +{ + int32_t rc = 0; + struct cci_write_async *write_async; + struct cci_device *cci_dev; + struct cam_sensor_i2c_reg_setting *cci_i2c_write_cfg; + struct cam_sensor_i2c_reg_setting *cci_i2c_write_cfg_w; + + cci_dev = v4l2_get_subdevdata(sd); + + write_async = kzalloc(sizeof(*write_async), GFP_KERNEL); + if (!write_async) + return -ENOMEM; + + + INIT_WORK(&write_async->work, cam_cci_write_async_helper); + write_async->cci_dev = cci_dev; + write_async->c_ctrl = *c_ctrl; + write_async->queue = queue; + write_async->sync_en = sync_en; + + cci_i2c_write_cfg = &c_ctrl->cfg.cci_i2c_write_cfg; + cci_i2c_write_cfg_w = &write_async->c_ctrl.cfg.cci_i2c_write_cfg; + + if (cci_i2c_write_cfg->size == 0) { + kfree(write_async); + return -EINVAL; + } + + cci_i2c_write_cfg_w->reg_setting = + kzalloc(sizeof(struct cam_sensor_i2c_reg_array)* + cci_i2c_write_cfg->size, GFP_KERNEL); + if (!cci_i2c_write_cfg_w->reg_setting) { + CAM_ERR(CAM_CCI, "Couldn't allocate memory"); + kfree(write_async); + return -ENOMEM; + } + memcpy(cci_i2c_write_cfg_w->reg_setting, + cci_i2c_write_cfg->reg_setting, + (sizeof(struct cam_sensor_i2c_reg_array)* + cci_i2c_write_cfg->size)); + + cci_i2c_write_cfg_w->addr_type = cci_i2c_write_cfg->addr_type; + cci_i2c_write_cfg_w->addr_type = cci_i2c_write_cfg->addr_type; + cci_i2c_write_cfg_w->data_type = cci_i2c_write_cfg->data_type; + cci_i2c_write_cfg_w->size = cci_i2c_write_cfg->size; + cci_i2c_write_cfg_w->delay = cci_i2c_write_cfg->delay; + + queue_work(cci_dev->write_wq[write_async->queue], &write_async->work); + + return rc; +} + +static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = NULL; + enum cci_i2c_master_t master; + struct cam_cci_read_cfg *read_cfg = NULL; + uint16_t read_bytes = 0; + + if (!sd || !c_ctrl) { + CAM_ERR(CAM_CCI, "sd %pK c_ctrl %pK", sd, c_ctrl); + return -EINVAL; + } + if (!c_ctrl->cci_info) { + CAM_ERR(CAM_CCI, "cci_info NULL"); + return -EINVAL; + } + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev) { + CAM_ERR(CAM_CCI, "cci_dev NULL"); + return -EINVAL; + } + if (cci_dev->cci_state != CCI_STATE_ENABLED) { + CAM_ERR(CAM_CCI, "invalid cci state %d", cci_dev->cci_state); + return -EINVAL; + } + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + master = c_ctrl->cci_info->cci_i2c_master; + read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg; + if ((!read_cfg->num_byte) || (read_cfg->num_byte > CCI_I2C_MAX_READ)) { + CAM_ERR(CAM_CCI, "read num bytes 0"); + rc = -EINVAL; + goto ERROR; + } + + read_bytes = read_cfg->num_byte; + + /* + * To avoid any conflicts due to back to back trigger of + * THRESHOLD irq's, we reinit the threshold wait before + * we load the burst read cmd. + */ + reinit_completion(&cci_dev->cci_master_info[master].th_complete); + + CAM_DBG(CAM_CCI, "Bytes to read %u", read_bytes); + do { + if (read_bytes >= CCI_I2C_MAX_BYTE_COUNT) + read_cfg->num_byte = CCI_I2C_MAX_BYTE_COUNT; + else + read_cfg->num_byte = read_bytes; + + if (read_cfg->num_byte >= CCI_READ_MAX) { + cci_dev->is_burst_read = true; + rc = cam_cci_burst_read(sd, c_ctrl); + } else { + cci_dev->is_burst_read = false; + rc = cam_cci_read(sd, c_ctrl); + } + if (rc) { + CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); + goto ERROR; + } + + if (read_bytes >= CCI_I2C_MAX_BYTE_COUNT) { + read_cfg->addr += (CCI_I2C_MAX_BYTE_COUNT / + read_cfg->data_type); + read_cfg->data += CCI_I2C_MAX_BYTE_COUNT; + read_bytes -= CCI_I2C_MAX_BYTE_COUNT; + } else { + read_bytes = 0; + } + } while (read_bytes); + +ERROR: + cci_dev->is_burst_read = false; + return rc; +} + +static int32_t cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + cci_dev, c_ctrl); + rc = -EINVAL; + return rc; + } + cci_dev->cci_wait_sync_cfg = c_ctrl->cfg.cci_wait_sync_cfg; + cci_dev->valid_sync = cci_dev->cci_wait_sync_cfg.csid < 0 ? 0 : 1; + + return rc; +} + +static int32_t cam_cci_release(struct v4l2_subdev *sd, + enum cci_i2c_master_t master) +{ + uint8_t rc = 0; + struct cci_device *cci_dev; + + cci_dev = v4l2_get_subdevdata(sd); + + rc = cam_cci_soc_release(cci_dev, master); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc); + return rc; + } + + return rc; +} + +static int32_t cam_cci_write(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master; + struct cam_cci_master_info *cci_master_info; + uint32_t i; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + cci_dev, c_ctrl); + rc = -EINVAL; + return rc; + } + + master = c_ctrl->cci_info->cci_i2c_master; + + if (c_ctrl->cci_info->cci_i2c_master >= MASTER_MAX + || c_ctrl->cci_info->cci_i2c_master < 0) { + CAM_ERR(CAM_CCI, "Invalid I2C master addr"); + return -EINVAL; + } + + cci_master_info = &cci_dev->cci_master_info[master]; + + switch (c_ctrl->cmd) { + case MSM_CCI_I2C_WRITE_SYNC_BLOCK: + mutex_lock(&cci_master_info->mutex_q[SYNC_QUEUE]); + rc = cam_cci_i2c_write(sd, c_ctrl, + SYNC_QUEUE, MSM_SYNC_ENABLE); + mutex_unlock(&cci_master_info->mutex_q[SYNC_QUEUE]); + break; + case MSM_CCI_I2C_WRITE_SYNC: + rc = cam_cci_i2c_write_async(sd, c_ctrl, + SYNC_QUEUE, MSM_SYNC_ENABLE); + break; + case MSM_CCI_I2C_WRITE: + case MSM_CCI_I2C_WRITE_SEQ: + case MSM_CCI_I2C_WRITE_BURST: + for (i = 0; i < NUM_QUEUES; i++) { + if (mutex_trylock(&cci_master_info->mutex_q[i])) { + rc = cam_cci_i2c_write(sd, c_ctrl, i, + MSM_SYNC_DISABLE); + mutex_unlock(&cci_master_info->mutex_q[i]); + return rc; + } + } + mutex_lock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); + rc = cam_cci_i2c_write(sd, c_ctrl, + PRIORITY_QUEUE, MSM_SYNC_DISABLE); + mutex_unlock(&cci_master_info->mutex_q[PRIORITY_QUEUE]); + break; + case MSM_CCI_I2C_WRITE_ASYNC: + rc = cam_cci_i2c_write_async(sd, c_ctrl, + PRIORITY_QUEUE, MSM_SYNC_DISABLE); + break; + default: + rc = -ENOIOCTLCMD; + } + + return rc; +} + +int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, + struct cam_cci_ctrl *cci_ctrl) +{ + int32_t rc = 0; + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + enum cci_i2c_master_t master = MASTER_MAX; + CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + + if (!cci_dev) { + CAM_ERR(CAM_CCI, "CCI_DEV IS NULL"); + return -EINVAL; + } + + if (!cci_ctrl) { + CAM_ERR(CAM_CCI, "CCI_CTRL IS NULL"); + return -EINVAL; + } + + master = cci_ctrl->cci_info->cci_i2c_master; + if (master >= MASTER_MAX) { + CAM_ERR(CAM_CCI, "INVALID MASTER: %d", master); + return -EINVAL; + } + + if (cci_dev->cci_master_info[master].status < 0) { + CAM_WARN(CAM_CCI, "CCI hardware is resetting"); + return -EAGAIN; + } + CAM_DBG(CAM_CCI, "master = %d", master); + + switch (cci_ctrl->cmd) { + case MSM_CCI_INIT: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_init(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); + break; + case MSM_CCI_RELEASE: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_release(sd, master); + mutex_unlock(&cci_dev->init_mutex); + break; + case MSM_CCI_I2C_READ: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_read_bytes(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); + break; + case MSM_CCI_I2C_WRITE: + case MSM_CCI_I2C_WRITE_SEQ: + case MSM_CCI_I2C_WRITE_BURST: + case MSM_CCI_I2C_WRITE_SYNC: + case MSM_CCI_I2C_WRITE_ASYNC: + case MSM_CCI_I2C_WRITE_SYNC_BLOCK: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_write(sd, cci_ctrl); + mutex_unlock(&cci_dev->init_mutex); + break; + case MSM_CCI_GPIO_WRITE: + break; + case MSM_CCI_SET_SYNC_CID: + rc = cam_cci_i2c_set_sync_prms(sd, cci_ctrl); + break; + + default: + rc = -ENOIOCTLCMD; + } + + cci_ctrl->status = rc; + if(rc == 0) + CAM_DBG(CAM_CCI, "master = %d, cmd = %d successful", master, cci_ctrl->cmd); + return rc; +} + + +#define MAX_WRITE_ARRAY_SIZE 300 +static struct cam_cci_ctrl cci_ctrl_interface; +static struct cam_sensor_cci_client cci_ctrl_interface_info; +static struct cam_sensor_i2c_reg_array write_regarray[MAX_WRITE_ARRAY_SIZE]; + +int32_t cam_cci_read_packet(struct cam_cci_ctrl *cci_ctrl, + uint32_t addr, uint8_t *data,uint32_t count) +{ + int32_t rc = -EINVAL; + + cci_ctrl->cmd = MSM_CCI_I2C_READ; + cci_ctrl->cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl->cfg.cci_i2c_read_cfg.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + cci_ctrl->cfg.cci_i2c_read_cfg.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + cci_ctrl->cfg.cci_i2c_read_cfg.data = data; + cci_ctrl->cfg.cci_i2c_read_cfg.num_byte = count; + //CAM_ERR(CAM_SENSOR, "cam_cci_read_packet addr = 0x%x,data=0x%x,count=%d,rc=%d", + // addr,data[0],count,rc); + //for(int i=0;i<count;i++){ + // CAM_ERR(CAM_SENSOR, "data before read data= 0x%x,index=%d",data[i],i); + //} + + rc = cci_ctrl->status; + return rc; +} + +static int32_t cam_cci_write_packet( + struct cam_cci_ctrl *cci_ctrl, + int addr, + uint8_t *data, + uint16_t count) +{ + int32_t rc = 0; + int i; + memset(write_regarray,0,sizeof(write_regarray)); + if (!cci_ctrl || !data) + return rc; + if(count > MAX_WRITE_ARRAY_SIZE){ + CAM_ERR(CAM_SENSOR, "fatal error!!count exceeds 300,count=%d", + count); + count = MAX_WRITE_ARRAY_SIZE; + } + for(i=0; i<count; i++){ + write_regarray[i].reg_addr = addr+i; + write_regarray[i].reg_data = data[i]; + //CAM_ERR(CAM_SENSOR, "cam_cci_write_packet addr = 0x%x,data= 0x%x,count=%d", + // addr,data[i],count); + } + cci_ctrl->cfg.cci_i2c_write_cfg.reg_setting = + write_regarray; + cci_ctrl->cfg.cci_i2c_write_cfg.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + cci_ctrl->cfg.cci_i2c_write_cfg.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + cci_ctrl->cfg.cci_i2c_write_cfg.size = count; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); + return rc; + } + rc = cci_ctrl->status; + //if (write_setting->delay > 20) + // msleep(write_setting->delay); + //else if (write_setting->delay) + // usleep_range(write_setting->delay * 1000, (write_setting->delay + // * 1000) + 1000); + + return rc; +} + + +int32_t cam_cci_control_interface(void* control) +{ + int32_t rc = 0,exp_byte; + struct v4l2_subdev *sd = cam_cci_get_subdev(CCI_DEVICE_1); + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + struct camera_cci_transfer* pControl = (struct camera_cci_transfer*)control; + enum cci_i2c_master_t master = MASTER_MAX; + + switch (pControl->cmd) { + case CAMERA_CCI_INIT: + memset(&cci_ctrl_interface,0,sizeof(cci_ctrl_interface)); + memset(&cci_ctrl_interface_info,0,sizeof(cci_ctrl_interface_info)); + cci_ctrl_interface.cci_info = &cci_ctrl_interface_info; + cci_ctrl_interface.cci_info->cci_i2c_master = MASTER_1; + cci_ctrl_interface.cci_info->i2c_freq_mode = I2C_FAST_PLUS_MODE; + cci_ctrl_interface.cci_info->sid = (0x52 >> 1); + cci_ctrl_interface.cci_info->retries = 3; + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_init(sd, &cci_ctrl_interface); + mutex_unlock(&cci_dev->init_mutex); + CAM_INFO(CAM_CCI, "cci init cmd,rc=%d",rc); + break; + case CAMERA_CCI_RELEASE: + mutex_lock(&cci_dev->init_mutex); + rc = cam_cci_release(sd, master); + mutex_unlock(&cci_dev->init_mutex); + CAM_INFO(CAM_CCI, "cci release cmd,rc=%d",rc); + break; + case CAMERA_CCI_READ: + cci_ctrl_interface.cmd = MSM_CCI_I2C_READ; + //pack read data + cam_cci_read_packet(&cci_ctrl_interface, + pControl->addr, + pControl->data, + pControl->count); + rc = cam_cci_read_bytes(sd, &cci_ctrl_interface); + if(rc < 0){ + int i; + CAM_ERR(CAM_CCI, "cmd %d,rc=%d", pControl->cmd,rc); + exp_byte = ((cci_ctrl_interface.cfg.cci_i2c_read_cfg.num_byte / 4) + 1); + CAM_ERR(CAM_CCI, "songyt read exp byte=%d", exp_byte); + for(i=0; i<exp_byte; i++){ + CAM_ERR(CAM_CCI, "songyt read byte=0x%x,index=%d", + cci_ctrl_interface.cfg.cci_i2c_read_cfg.data[i],i); + } + } + break; + case CAMERA_CCI_WRITE: + //if(pControl->count>1) + // cci_ctrl_interface.cmd = MSM_CCI_I2C_WRITE_SEQ; + //else + // cci_ctrl_interface.cmd = MSM_CCI_I2C_WRITE_SYNC_BLOCK; + cci_ctrl_interface.cmd = MSM_CCI_I2C_WRITE; + //pack write data + cam_cci_write_packet(&cci_ctrl_interface, + pControl->addr, + pControl->data, + pControl->count); + rc = cam_cci_write(sd, &cci_ctrl_interface); + if(rc < 0){ + CAM_ERR(CAM_CCI, "cmd %d,rc=%d",pControl->cmd,rc); + } + break; + default: + rc = -ENOIOCTLCMD; + } + + cci_ctrl_interface.status = rc; + return rc; +} \ No newline at end of file diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.h b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.h new file mode 100644 index 0000000000000000000000000000000000000000..739fd303b236ca18123ac6e960a4442ab0f74e36 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_CCI_CORE_H_ +#define _CAM_CCI_CORE_H_ + +#include <linux/irqreturn.h> +#include <media/cam_sensor.h> +#include "cam_cci_dev.h" +#include "cam_cci_soc.h" + +/** + * @cci_dev: CCI device structure + * @c_ctrl: CCI control structure + * + * This API gets CCI clk rates + */ +void cam_cci_get_clk_rates(struct cci_device *cci_dev, + struct cam_cci_ctrl *c_ctrl); + +/** + * @sd: V4L2 sub device + * @c_ctrl: CCI control structure + * + * This API handles I2C operations for CCI + */ +int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, + struct cam_cci_ctrl *cci_ctrl); + +/** + * @irq_num: IRQ number + * @data: CCI private structure + * + * This API handles CCI IRQs + */ +irqreturn_t cam_cci_irq(int irq_num, void *data); + +#endif /* _CAM_CCI_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_ctrl_interface.h b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_ctrl_interface.h new file mode 100755 index 0000000000000000000000000000000000000000..a03df823f27c0a8890eebf479b1211d68ef0044e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_ctrl_interface.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#ifndef _CAM_CCI_CTRL_INTERFACE_H_ +#define _CAM_CCI_CTRL_INTERFACE_H_ + + +int32_t cam_cci_control_interface(void*); + +#define USE_CAMERA_CCI + +enum camera_cci_operations { + CAMERA_CCI_INIT, + CAMERA_CCI_RELEASE, + CAMERA_CCI_READ, + CAMERA_CCI_WRITE, +}; + +struct camera_cci_transfer { + int cmd; + uint16_t addr; + uint8_t *data; + uint16_t count; +}; + +#endif /* _CAM_CCI_CTRL_INTERFACE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..e563ccecb8a4f35b09393922d006d452d7764556 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -0,0 +1,561 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include "cam_cci_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_cci_soc.h" +#include "cam_cci_core.h" + +#define CCI_MAX_DELAY 1000000 + +static struct v4l2_subdev *g_cci_subdev[MAX_CCI]; + +struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) +{ + struct v4l2_subdev *sub_device = NULL; + + if (cci_dev_index < MAX_CCI) + sub_device = g_cci_subdev[cci_dev_index]; + else + CAM_WARN(CAM_CCI, "Index: %u is beyond max num CCI allowed: %u", + cci_dev_index, + MAX_CCI); + + return sub_device; +} + +static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int32_t rc = 0; + + if (arg == NULL) { + CAM_ERR(CAM_CCI, "Invalid Args"); + return rc; + } + + switch (cmd) { + case VIDIOC_MSM_CCI_CFG: + rc = cam_cci_core_cfg(sd, arg); + break; + case VIDIOC_CAM_CONTROL: + break; + default: + CAM_ERR(CAM_CCI, "Invalid ioctl cmd: %d", cmd); + rc = -ENOIOCTLCMD; + } + + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_cci_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + return cam_cci_subdev_ioctl(sd, cmd, NULL); +} +#endif + +irqreturn_t cam_cci_irq(int irq_num, void *data) +{ + uint32_t irq_status0, irq_status1, reg_bmsk; + uint32_t irq_update_rd_done = 0; + struct cci_device *cci_dev = data; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + void __iomem *base = soc_info->reg_map[0].mem_base; + unsigned long flags; + bool rd_done_th_assert = false; + + irq_status0 = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); + irq_status1 = cam_io_r_mb(base + CCI_IRQ_STATUS_1_ADDR); + CAM_DBG(CAM_CCI, "BASE: %pK", base); + CAM_DBG(CAM_CCI, "irq0:%x irq1:%x", irq_status0, irq_status1); + + if (irq_status0 & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + struct cam_cci_master_info *cci_master_info; + if (cci_dev->cci_master_info[MASTER_0].reset_pending == true) { + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; + cci_dev->cci_master_info[MASTER_0].reset_pending = + false; + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; + + complete_all(&cci_master_info->rd_done); + complete_all(&cci_master_info->th_complete); + } + if (cci_dev->cci_master_info[MASTER_1].reset_pending == true) { + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; + cci_dev->cci_master_info[MASTER_1].reset_pending = + false; + if (!cci_master_info->status) + complete(&cci_master_info->reset_complete); + cci_master_info->status = 0; + + complete_all(&cci_master_info->rd_done); + complete_all(&cci_master_info->th_complete); + } + } + + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && + (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + rd_done_th_assert = true; + complete(&cci_dev->cci_master_info[MASTER_0].th_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); + } + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + rd_done_th_assert = true; + if (cci_dev->is_burst_read) + complete( + &cci_dev->cci_master_info[MASTER_0].th_complete); + complete(&cci_dev->cci_master_info[MASTER_0].rd_done); + } + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].th_complete); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_0], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) { + complete(&cci_master_info->report_q[QUEUE_0]); + atomic_set(&cci_master_info->done_pending[QUEUE_0], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_0], + flags); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_0]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_1], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) { + complete(&cci_master_info->report_q[QUEUE_1]); + atomic_set(&cci_master_info->done_pending[QUEUE_1], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_0].lock_q[QUEUE_1], + flags); + } + rd_done_th_assert = false; + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && + (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + rd_done_th_assert = true; + complete(&cci_dev->cci_master_info[MASTER_1].th_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); + } + if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + rd_done_th_assert = true; + if (cci_dev->is_burst_read) + complete( + &cci_dev->cci_master_info[MASTER_1].th_complete); + complete(&cci_dev->cci_master_info[MASTER_1].rd_done); + } + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && + (!rd_done_th_assert)) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].th_complete); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_0], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) { + complete(&cci_master_info->report_q[QUEUE_0]); + atomic_set(&cci_master_info->done_pending[QUEUE_0], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_0], + flags); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) { + struct cam_cci_master_info *cci_master_info; + + cci_master_info = &cci_dev->cci_master_info[MASTER_1]; + spin_lock_irqsave( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1], + flags); + atomic_set(&cci_master_info->q_free[QUEUE_1], 0); + cci_master_info->status = 0; + if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) { + complete(&cci_master_info->report_q[QUEUE_1]); + atomic_set(&cci_master_info->done_pending[QUEUE_1], 0); + } + spin_unlock_irqrestore( + &cci_dev->cci_master_info[MASTER_1].lock_q[QUEUE_1], + flags); + } + if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE) + CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_0"); + + if (irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_PAUSE) + CAM_DBG(CAM_CCI, "RD_PAUSE ON MASTER_1"); + + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_0].reset_pending = true; + cam_io_w_mb(CCI_M0_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) { + cci_dev->cci_master_info[MASTER_1].reset_pending = true; + cam_io_w_mb(CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { + cci_dev->cci_master_info[MASTER_0].status = -EINVAL; + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q0 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_0]); + reinit_completion(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M0_Q1 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_1]); + reinit_completion(&cci_dev->cci_master_info[MASTER_0] + .report_q[QUEUE_1]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M0 QUEUE_OVER/UNDER_FLOW OR CMD ERR: 0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base: %pK, M0 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { + cci_dev->cci_master_info[MASTER_1].status = -EINVAL; + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q0 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_0]); + reinit_completion(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_0]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK) { + CAM_ERR(CAM_CCI, "Base:%pK, M1_Q1 NACK ERROR: 0x%x", + base, irq_status0); + complete_all(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_1]); + reinit_completion(&cci_dev->cci_master_info[MASTER_1] + .report_q[QUEUE_1]); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 QUEUE_OVER_UNDER_FLOW OR CMD ERROR:0x%x", + base, irq_status0); + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK) + CAM_ERR(CAM_CCI, + "Base:%pK, M1 RD_OVER/UNDER_FLOW ERROR: 0x%x", + base, irq_status0); + + cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, base + CCI_HALT_REQ_ADDR); + } + + cam_io_w_mb(irq_status0, base + CCI_IRQ_CLEAR_0_ADDR); + + reg_bmsk = CCI_IRQ_MASK_1_RMSK; + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) && + !(irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK)) { + reg_bmsk &= ~CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + spin_lock_irqsave(&cci_dev->lock_status, flags); + cci_dev->irqs_disabled |= + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + + if ((irq_status1 & CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) && + !(irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK)) { + reg_bmsk &= ~CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + spin_lock_irqsave(&cci_dev->lock_status, flags); + cci_dev->irqs_disabled |= + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + + if (reg_bmsk != CCI_IRQ_MASK_1_RMSK) { + cam_io_w_mb(reg_bmsk, base + CCI_IRQ_MASK_1_ADDR); + CAM_DBG(CAM_CCI, "Updating the reg mask for irq1: 0x%x", + reg_bmsk); + } else if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK || + irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) { + spin_lock_irqsave(&cci_dev->lock_status, flags); + if (cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD) { + irq_update_rd_done |= + CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + cci_dev->irqs_disabled &= + ~CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD; + } + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + if (irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { + spin_lock_irqsave(&cci_dev->lock_status, flags); + if (cci_dev->irqs_disabled & + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD) { + irq_update_rd_done |= + CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + cci_dev->irqs_disabled &= + ~CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD; + } + spin_unlock_irqrestore(&cci_dev->lock_status, flags); + } + } + + if (irq_update_rd_done != 0) { + irq_update_rd_done |= cam_io_r_mb(base + CCI_IRQ_MASK_1_ADDR); + cam_io_w_mb(irq_update_rd_done, base + CCI_IRQ_MASK_1_ADDR); + } + + + cam_io_w_mb(irq_status1, base + CCI_IRQ_CLEAR_1_ADDR); + cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + return IRQ_HANDLED; +} + +static int cam_cci_irq_routine(struct v4l2_subdev *sd, u32 status, + bool *handled) +{ + struct cci_device *cci_dev = v4l2_get_subdevdata(sd); + irqreturn_t ret; + struct cam_hw_soc_info *soc_info = + &cci_dev->soc_info; + + ret = cam_cci_irq(soc_info->irq_line->start, cci_dev); + *handled = true; + return 0; +} + +static struct v4l2_subdev_core_ops cci_subdev_core_ops = { + .ioctl = cam_cci_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_cci_subdev_compat_ioctl, +#endif + .interrupt_service_routine = cam_cci_irq_routine, +}; + +static const struct v4l2_subdev_ops cci_subdev_ops = { + .core = &cci_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cci_subdev_intern_ops; + +static struct v4l2_file_operations cci_v4l2_subdev_fops; + +static long cam_cci_subdev_do_ioctl( + struct file *file, unsigned int cmd, void *arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return cam_cci_subdev_ioctl(sd, cmd, NULL); +} + +static long cam_cci_subdev_fops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, cam_cci_subdev_do_ioctl); +} + +#ifdef CONFIG_COMPAT +static long cam_cci_subdev_fops_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + + return v4l2_subdev_call(sd, core, ioctl, cmd, NULL); +} +#endif + +static int cam_cci_platform_probe(struct platform_device *pdev) +{ + struct cam_cpas_register_params cpas_parms; + struct cci_device *new_cci_dev; + struct cam_hw_soc_info *soc_info = NULL; + int rc = 0; + + new_cci_dev = kzalloc(sizeof(struct cci_device), + GFP_KERNEL); + if (!new_cci_dev) + return -ENOMEM; + + soc_info = &new_cci_dev->soc_info; + + new_cci_dev->v4l2_dev_str.pdev = pdev; + + soc_info->pdev = pdev; + soc_info->dev = &pdev->dev; + soc_info->dev_name = pdev->name; + + rc = cam_cci_parse_dt_info(pdev, new_cci_dev); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Resource get Failed: %d", rc); + goto cci_no_resource; + } + + new_cci_dev->v4l2_dev_str.internal_ops = + &cci_subdev_intern_ops; + new_cci_dev->v4l2_dev_str.ops = + &cci_subdev_ops; + strlcpy(new_cci_dev->device_name, CAMX_CCI_DEV_NAME, + sizeof(new_cci_dev->device_name)); + new_cci_dev->v4l2_dev_str.name = + new_cci_dev->device_name; + new_cci_dev->v4l2_dev_str.sd_flags = + V4L2_SUBDEV_FL_HAS_EVENTS; + new_cci_dev->v4l2_dev_str.ent_function = + CAM_CCI_DEVICE_TYPE; + new_cci_dev->v4l2_dev_str.token = + new_cci_dev; + + rc = cam_register_subdev(&(new_cci_dev->v4l2_dev_str)); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Fail with cam_register_subdev"); + goto cci_no_resource; + } + + platform_set_drvdata(pdev, &(new_cci_dev->v4l2_dev_str.sd)); + v4l2_set_subdevdata(&new_cci_dev->v4l2_dev_str.sd, new_cci_dev); + if (soc_info->index >= MAX_CCI) { + CAM_ERR(CAM_CCI, "Invalid index: %d max supported:%d", + soc_info->index, MAX_CCI-1); + goto cci_no_resource; + } + + g_cci_subdev[soc_info->index] = &new_cci_dev->v4l2_dev_str.sd; + mutex_init(&(new_cci_dev->init_mutex)); + CAM_INFO(CAM_CCI, "Device Type :%d", soc_info->index); + + cam_register_subdev_fops(&cci_v4l2_subdev_fops); + cci_v4l2_subdev_fops.unlocked_ioctl = cam_cci_subdev_fops_ioctl; +#ifdef CONFIG_COMPAT + cci_v4l2_subdev_fops.compat_ioctl32 = + cam_cci_subdev_fops_compat_ioctl; +#endif + + cpas_parms.cam_cpas_client_cb = NULL; + cpas_parms.cell_index = soc_info->index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = new_cci_dev; + strlcpy(cpas_parms.identifier, "cci", CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CCI, "CPAS registration failed"); + goto cci_no_resource; + } + CAM_DBG(CAM_CCI, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + new_cci_dev->cpas_handle = cpas_parms.client_handle; + + return rc; +cci_no_resource: + kfree(new_cci_dev); + return rc; +} + +static int cam_cci_device_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev = platform_get_drvdata(pdev); + struct cci_device *cci_dev = + v4l2_get_subdevdata(subdev); + + cam_cpas_unregister_client(cci_dev->cpas_handle); + cam_cci_soc_remove(pdev, cci_dev); + devm_kfree(&pdev->dev, cci_dev); + return 0; +} + +static const struct of_device_id cam_cci_dt_match[] = { + {.compatible = "qcom,cci"}, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_cci_dt_match); + +static struct platform_driver cci_driver = { + .probe = cam_cci_platform_probe, + .remove = cam_cci_device_remove, + .driver = { + .name = CAMX_CCI_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_cci_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int cam_cci_assign_fops(void) +{ + struct v4l2_subdev *sd; + int i = 0; + + for (; i < MAX_CCI; i++) { + sd = g_cci_subdev[i]; + if (!sd) + return 0; + if (!(sd->devnode)) { + CAM_ERR(CAM_CCI, + "Invalid dev node:%pK offset: %d", + sd->devnode, i); + return -EINVAL; + } + sd->devnode->fops = &cci_v4l2_subdev_fops; + } + + return 0; +} + +static int __init cam_cci_late_init(void) +{ + return cam_cci_assign_fops(); +} + +static int __init cam_cci_init_module(void) +{ + return platform_driver_register(&cci_driver); +} + +static void __exit cam_cci_exit_module(void) +{ + platform_driver_unregister(&cci_driver); +} + +module_init(cam_cci_init_module); +late_initcall(cam_cci_late_init); +module_exit(cam_cci_exit_module); +MODULE_DESCRIPTION("MSM CCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..e6d934b5d8757a513299839c6bc06c201caed6a3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -0,0 +1,309 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CCI_DEV_H_ +#define _CAM_CCI_DEV_H_ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> +#include <linux/module.h> +#include <linux/irqreturn.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/semaphore.h> +#include <media/cam_sensor.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <cam_sensor_cmn_header.h> +#include <cam_io_util.h> +#include <cam_sensor_util.h> +#include "cam_subdev.h" +#include <cam_cpas_api.h> +#include "cam_cci_hwreg.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define V4L2_IDENT_CCI 50005 +#define CCI_I2C_QUEUE_0_SIZE 128 +#define CCI_I2C_QUEUE_1_SIZE 32 +#define CYCLES_PER_MICRO_SEC_DEFAULT 4915 +#define CCI_MAX_DELAY 1000000 + +#define CCI_TIMEOUT msecs_to_jiffies(1500) + +#define NUM_QUEUES 2 + +#define CCI_PINCTRL_STATE_DEFAULT "cci_default" +#define CCI_PINCTRL_STATE_SLEEP "cci_suspend" + +#define CCI_NUM_CLK_MAX 16 +#define CCI_NUM_CLK_CASES 5 +#define CCI_CLK_SRC_NAME "cci_src_clk" +#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_10 10 +#define MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11 11 +#define BURST_MIN_FREE_SIZE 8 +#define MAX_LRME_V4l2_EVENTS 30 + +/* Max bytes that can be read per CCI read transaction */ +#define CCI_READ_MAX 256 +#define CCI_I2C_READ_MAX_RETRIES 3 +#define CCI_I2C_MAX_READ 8192 +#define CCI_I2C_MAX_WRITE 8192 +#define CCI_I2C_MAX_BYTE_COUNT 65535 + +#define CCI_VERSION_1_2_9 0x10020009 +#define CCI_I2C_QUEUE_0_SIZE_V_1_2 64 +#define CCI_I2C_QUEUE_1_SIZE_V_1_2 16 + +#define CAMX_CCI_DEV_NAME "cam-cci-driver" + +#define MAX_CCI 2 + +#define PRIORITY_QUEUE (QUEUE_0) +#define SYNC_QUEUE (QUEUE_1) + +enum cci_i2c_sync { + MSM_SYNC_DISABLE, + MSM_SYNC_ENABLE, +}; + +enum cam_cci_cmd_type { + MSM_CCI_INIT, + MSM_CCI_RELEASE, + MSM_CCI_SET_SID, + MSM_CCI_SET_FREQ, + MSM_CCI_SET_SYNC_CID, + MSM_CCI_I2C_READ, + MSM_CCI_I2C_WRITE, + MSM_CCI_I2C_WRITE_SEQ, + MSM_CCI_I2C_WRITE_BURST, + MSM_CCI_I2C_WRITE_ASYNC, + MSM_CCI_GPIO_WRITE, + MSM_CCI_I2C_WRITE_SYNC, + MSM_CCI_I2C_WRITE_SYNC_BLOCK, +}; + +enum cci_i2c_queue_t { + QUEUE_0, + QUEUE_1, + QUEUE_INVALID, +}; + +struct cam_cci_wait_sync_cfg { + uint16_t cid; + int16_t csid; + uint16_t line; + uint16_t delay; +}; + +struct cam_cci_gpio_cfg { + uint16_t gpio_queue; + uint16_t i2c_queue; +}; + +struct cam_cci_read_cfg { + uint32_t addr; + uint16_t addr_type; + uint8_t *data; + uint16_t num_byte; + uint16_t data_type; +}; + +struct cam_cci_i2c_queue_info { + uint32_t max_queue_size; + uint32_t report_id; + uint32_t irq_en; + uint32_t capture_rep_data; +}; + +struct cam_cci_master_info { + uint32_t status; + atomic_t q_free[NUM_QUEUES]; + uint8_t q_lock[NUM_QUEUES]; + uint8_t reset_pending; + struct mutex mutex; + struct completion reset_complete; + struct completion rd_done; + struct completion th_complete; + struct mutex mutex_q[NUM_QUEUES]; + struct completion report_q[NUM_QUEUES]; + atomic_t done_pending[NUM_QUEUES]; + spinlock_t lock_q[NUM_QUEUES]; + spinlock_t freq_cnt; + struct semaphore master_sem; + bool is_first_req; + uint16_t freq_ref_cnt; + bool is_initilized; +}; + +struct cam_cci_clk_params_t { + uint16_t hw_thigh; + uint16_t hw_tlow; + uint16_t hw_tsu_sto; + uint16_t hw_tsu_sta; + uint16_t hw_thd_dat; + uint16_t hw_thd_sta; + uint16_t hw_tbuf; + uint8_t hw_scl_stretch_en; + uint8_t hw_trdhld; + uint8_t hw_tsp; + uint32_t cci_clk_src; +}; + +enum cam_cci_state_t { + CCI_STATE_ENABLED, + CCI_STATE_DISABLED, +}; + +/** + * struct cci_device + * @pdev: Platform device + * @subdev: V4L2 sub device + * @base: Base address of CCI device + * @hw_version: Hardware version + * @ref_count: Reference Count + * @cci_state: CCI state machine + * @num_clk: Number of CCI clock + * @cci_clk: CCI clock structure + * @cci_clk_info: CCI clock information + * @cam_cci_i2c_queue_info: CCI queue information + * @i2c_freq_mode: I2C frequency of operations + * @master_active_slave: Number of active/connected slaves for master + * @cci_clk_params: CCI hw clk params + * @cci_gpio_tbl: CCI GPIO table + * @cci_gpio_tbl_size: GPIO table size + * @cci_pinctrl: Pinctrl structure + * @cci_pinctrl_status: CCI pinctrl status + * @cci_clk_src: CCI clk src rate + * @cci_vreg: CCI regulator structure + * @cci_reg_ptr: CCI individual regulator structure + * @regulator_count: Regulator count + * @support_seq_write: Set this flag when sequential write is enabled + * @write_wq: Work queue structure + * @valid_sync: Is it a valid sync with CSID + * @v4l2_dev_str: V4L2 device structure + * @cci_wait_sync_cfg: CCI sync config + * @cycles_per_us: Cycles per micro sec + * @payload_size: CCI packet payload size + * @irq_status1: Store irq_status1 to be cleared after + * draining FIFO buffer for burst read + * @lock_status: to protect changes to irq_status1 + * @is_burst_read: Flag to determine if we are performing + * a burst read operation or not + * @irqs_disabled: Mask for IRQs that are disabled + * @init_mutex: Mutex for maintaining refcount for attached + * devices to cci during init/deinit. + */ +struct cci_device { + struct v4l2_subdev subdev; + struct cam_hw_soc_info soc_info; + uint32_t hw_version; + uint8_t ref_count; + enum cam_cci_state_t cci_state; + struct cam_cci_i2c_queue_info + cci_i2c_queue_info[MASTER_MAX][NUM_QUEUES]; + struct cam_cci_master_info cci_master_info[MASTER_MAX]; + enum i2c_freq_mode i2c_freq_mode[MASTER_MAX]; + uint8_t master_active_slave[MASTER_MAX]; + struct cam_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; + struct msm_pinctrl_info cci_pinctrl; + uint8_t cci_pinctrl_status; + uint8_t support_seq_write; + struct workqueue_struct *write_wq[MASTER_MAX]; + struct cam_cci_wait_sync_cfg cci_wait_sync_cfg; + uint8_t valid_sync; + struct cam_subdev v4l2_dev_str; + uint32_t cycles_per_us; + int32_t clk_level_index; + uint8_t payload_size; + char device_name[20]; + uint32_t cpas_handle; + uint32_t irq_status1; + spinlock_t lock_status; + bool is_burst_read; + uint32_t irqs_disabled; + struct mutex init_mutex; +}; + +enum cam_cci_i2c_cmd_type { + CCI_I2C_SET_PARAM_CMD = 1, + CCI_I2C_WAIT_CMD, + CCI_I2C_WAIT_SYNC_CMD, + CCI_I2C_WAIT_GPIO_EVENT_CMD, + CCI_I2C_TRIG_I2C_EVENT_CMD, + CCI_I2C_LOCK_CMD, + CCI_I2C_UNLOCK_CMD, + CCI_I2C_REPORT_CMD, + CCI_I2C_WRITE_CMD, + CCI_I2C_READ_CMD, + CCI_I2C_WRITE_DISABLE_P_CMD, + CCI_I2C_READ_DISABLE_P_CMD, + CCI_I2C_WRITE_CMD2, + CCI_I2C_WRITE_CMD3, + CCI_I2C_REPEAT_CMD, + CCI_I2C_INVALID_CMD, +}; + +enum cam_cci_gpio_cmd_type { + CCI_GPIO_SET_PARAM_CMD = 1, + CCI_GPIO_WAIT_CMD, + CCI_GPIO_WAIT_SYNC_CMD, + CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD, + CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD, + CCI_GPIO_OUT_CMD, + CCI_GPIO_TRIG_EVENT_CMD, + CCI_GPIO_REPORT_CMD, + CCI_GPIO_REPEAT_CMD, + CCI_GPIO_CONTINUE_CMD, + CCI_GPIO_INVALID_CMD, +}; + +struct cam_sensor_cci_client { + struct v4l2_subdev *cci_subdev; + uint32_t freq; + enum i2c_freq_mode i2c_freq_mode; + enum cci_i2c_master_t cci_i2c_master; + uint16_t sid; + uint16_t cid; + uint32_t timeout; + uint16_t retries; + uint16_t id_map; + uint16_t cci_device; +}; + +struct cam_cci_ctrl { + int32_t status; + struct cam_sensor_cci_client *cci_info; + enum cam_cci_cmd_type cmd; + union { + struct cam_sensor_i2c_reg_setting cci_i2c_write_cfg; + struct cam_cci_read_cfg cci_i2c_read_cfg; + struct cam_cci_wait_sync_cfg cci_wait_sync_cfg; + struct cam_cci_gpio_cfg gpio_cfg; + } cfg; +}; + +struct cci_write_async { + struct cci_device *cci_dev; + struct cam_cci_ctrl c_ctrl; + enum cci_i2c_queue_t queue; + struct work_struct work; + enum cci_i2c_sync sync_en; +}; + +irqreturn_t cam_cci_irq(int irq_num, void *data); + +struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index); + +#define VIDIOC_MSM_CCI_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) + +#endif /* _CAM_CCI_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..73756a301f7ad4d752b27211a87e70d5315f9e1c --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2015, 2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CCI_HWREG_ +#define _CAM_CCI_HWREG_ + +#define CCI_HW_VERSION_ADDR 0x00000000 +#define CCI_RESET_CMD_ADDR 0x00000004 +#define CCI_RESET_CMD_RMSK 0x0f73f3f7 +#define CCI_M0_RESET_RMSK 0x3F1 +#define CCI_M1_RESET_RMSK 0x3F001 +#define CCI_QUEUE_START_ADDR 0x00000008 +#define CCI_SET_CID_SYNC_TIMER_ADDR 0x00000010 +#define CCI_SET_CID_SYNC_TIMER_OFFSET 0x00000004 +#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100 +#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104 +#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108 +#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c +#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118 +#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110 +#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C +#define CCI_HALT_REQ_ADDR 0x00000034 +#define CCI_M0_HALT_REQ_RMSK 0x1 +#define CCI_M1_HALT_REQ_RMSK 0x2 +#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200 +#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204 +#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208 +#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c +#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210 +#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304 +#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308 +#define CCI_I2C_M0_Q0_REPORT_STATUS_ADDR 0x0000030c +#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300 +#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310 +#define CCI_IRQ_MASK_0_ADDR 0x00000c04 +#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7 +#define CCI_IRQ_MASK_1_ADDR 0x00000c10 +#define CCI_IRQ_MASK_1_RMSK 0x00110000 +#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08 +#define CCI_IRQ_CLEAR_1_ADDR 0x00000c14 +#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c +#define CCI_IRQ_STATUS_1_ADDR 0x00000c18 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000 +#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000 +#define CCI_IRQ_STATUS_1_I2C_M1_RD_THRESHOLD 0x100000 +#define CCI_IRQ_STATUS_1_I2C_M1_RD_PAUSE 0x200000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10 +#define CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK 0x18000EE6 +#define CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK 0x60EE6000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERROR_BMSK 0x8000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERROR_BMSK 0x10000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERROR_BMSK 0x20000000 +#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERROR_BMSK 0x40000000 +#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_ERROR_BMSK 0xEE0 +#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_ERROR_BMSK 0xEE0000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_ERROR_BMSK 0x6 +#define CCI_IRQ_STATUS_0_I2C_M1_RD_ERROR_BMSK 0x6000 +#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1 +#define CCI_IRQ_STATUS_1_I2C_M0_RD_THRESHOLD 0x10000 +#define CCI_IRQ_STATUS_1_I2C_M0_RD_PAUSE 0x20000 +#define CCI_I2C_M0_RD_THRESHOLD_ADDR 0x00000120 +#define CCI_I2C_M1_RD_THRESHOLD_ADDR 0x00000220 +#define CCI_I2C_RD_THRESHOLD_VALUE 0x30 +#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00 + +#define DEBUG_TOP_REG_START 0x0 +#define DEBUG_TOP_REG_COUNT 14 +#define DEBUG_MASTER_REG_START 0x100 +#define DEBUG_MASTER_REG_COUNT 9 +#define DEBUG_MASTER_QUEUE_REG_START 0x300 +#define DEBUG_MASTER_QUEUE_REG_COUNT 7 +#define DEBUG_INTR_REG_START 0xC00 +#define DEBUG_INTR_REG_COUNT 7 +#endif /* _CAM_CCI_HWREG_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..3698a36457e2a14a64f961ce88235a574fced71b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -0,0 +1,445 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_cci_dev.h" +#include "cam_cci_core.h" + +static int cam_cci_init_master(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + int i = 0, rc = 0; + void __iomem *base = NULL; + struct cam_hw_soc_info *soc_info = NULL; + uint32_t max_queue_0_size = 0, max_queue_1_size = 0; + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + if (cci_dev->hw_version != CCI_VERSION_1_2_9) { + max_queue_0_size = CCI_I2C_QUEUE_0_SIZE_V_1_2; + max_queue_1_size = CCI_I2C_QUEUE_1_SIZE_V_1_2; + } else { + max_queue_0_size = CCI_I2C_QUEUE_0_SIZE; + max_queue_1_size = CCI_I2C_QUEUE_1_SIZE; + } + + cci_dev->master_active_slave[master]++; + if (!cci_dev->cci_master_info[master].is_initilized) { + /* Re-initialize the completion */ + reinit_completion( + &cci_dev->cci_master_info[master].reset_complete); + reinit_completion(&cci_dev->cci_master_info[master].rd_done); + + /* reinit the reports for the queue */ + for (i = 0; i < NUM_QUEUES; i++) + reinit_completion( + &cci_dev->cci_master_info[master].report_q[i]); + + if (cci_dev->ref_count == 1) { + cam_io_w_mb(CCI_RESET_CMD_RMSK, base + + CCI_RESET_CMD_ADDR); + cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); + } else { + /* Set reset pending flag to true */ + cci_dev->cci_master_info[master].reset_pending = true; + cam_io_w_mb((master == MASTER_0) ? + CCI_M0_RESET_RMSK : CCI_M1_RESET_RMSK, + base + CCI_RESET_CMD_ADDR); + if (!wait_for_completion_timeout( + &cci_dev->cci_master_info[master].reset_complete, + CCI_TIMEOUT)) { + CAM_ERR(CAM_CCI, + "Failed: reset complete timeout for master: %d", + master); + rc = -ETIMEDOUT; + cci_dev->master_active_slave[master]--; + return rc; + } + } + + flush_workqueue(cci_dev->write_wq[master]); + + /* Setting up the queue size for master */ + cci_dev->cci_i2c_queue_info[master][QUEUE_0].max_queue_size + = max_queue_0_size; + cci_dev->cci_i2c_queue_info[master][QUEUE_1].max_queue_size + = max_queue_1_size; + + CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0: %d Q1: %d", master, + cci_dev->cci_i2c_queue_info[master][QUEUE_0] + .max_queue_size, + cci_dev->cci_i2c_queue_info[master][QUEUE_1] + .max_queue_size); + + cci_dev->cci_master_info[master].status = 0; + cci_dev->cci_master_info[master].is_initilized = true; + } + + return 0; +} + + +int cam_cci_init(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl) +{ + uint8_t i = 0; + int32_t rc = 0; + struct cci_device *cci_dev; + enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + struct cam_hw_soc_info *soc_info = NULL; + void __iomem *base = NULL; + + cci_dev = v4l2_get_subdevdata(sd); + if (!cci_dev || !c_ctrl) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + cci_dev, c_ctrl); + rc = -EINVAL; + return rc; + } + + soc_info = &cci_dev->soc_info; + base = soc_info->reg_map[0].mem_base; + + if (!soc_info || !base) { + CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", + soc_info, base); + rc = -EINVAL; + return rc; + } + + CAM_DBG(CAM_CCI, "Base address %pK", base); + if (master >= MASTER_MAX || master < 0) { + CAM_ERR(CAM_CCI, "Incorrect Master: %d", master); + return -EINVAL; + } + + if (!cci_dev->write_wq[master]) { + CAM_ERR(CAM_CCI, "Null memory for write wq[:%d]", master); + rc = -ENOMEM; + return rc; + } + + if (cci_dev->ref_count++) { + rc = cam_cci_init_master(cci_dev, master); + if (rc) { + CAM_ERR(CAM_CCI, "Failed to init: Master: %d: rc: %d", + master, rc); + cci_dev->ref_count--; + } + CAM_DBG(CAM_CCI, "ref_count %d, master: %d", + cci_dev->ref_count, master); + return rc; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); + if (rc) { + CAM_ERR(CAM_CCI, "CPAS start failed rc= %d", rc); + return rc; + } + + cam_cci_get_clk_rates(cci_dev, c_ctrl); + + /* Enable Regulators and IRQ*/ + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_LOWSVS_VOTE, true); + if (rc < 0) { + CAM_DBG(CAM_CCI, "request platform resources failed"); + goto platform_enable_failed; + } + + cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR); + CAM_DBG(CAM_CCI, "hw_version = 0x%x", cci_dev->hw_version); + + cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; + cci_dev->support_seq_write = 1; + + cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); + cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); + + rc = cam_cci_init_master(cci_dev, master); + if (rc) { + CAM_ERR(CAM_CCI, "Failed to init: Master: %d, rc: %d", + master, rc); + goto reset_complete_failed; + } + + for (i = 0; i < MASTER_MAX; i++) + cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; + cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR); + cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR); + cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + /* Set RD FIFO threshold for M0 & M1 */ + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M0_RD_THRESHOLD_ADDR); + cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, + base + CCI_I2C_M1_RD_THRESHOLD_ADDR); + + cci_dev->cci_state = CCI_STATE_ENABLED; + + return 0; + +reset_complete_failed: + cam_soc_util_disable_platform_resource(soc_info, 1, 1); + +platform_enable_failed: + cci_dev->ref_count--; + cam_cpas_stop(cci_dev->cpas_handle); + + return rc; +} + +void cam_cci_soc_remove(struct platform_device *pdev, + struct cci_device *cci_dev) +{ + struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; + + cam_soc_util_release_platform_resource(soc_info); +} + +static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) +{ + uint8_t i = 0, j = 0; + + for (i = 0; i < MASTER_MAX; i++) { + new_cci_dev->cci_master_info[i].status = 0; + new_cci_dev->cci_master_info[i].is_first_req = true; + new_cci_dev->cci_master_info[i].is_initilized = false; + mutex_init(&new_cci_dev->cci_master_info[i].mutex); + sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); + spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); + init_completion( + &new_cci_dev->cci_master_info[i].reset_complete); + init_completion( + &new_cci_dev->cci_master_info[i].th_complete); + init_completion( + &new_cci_dev->cci_master_info[i].rd_done); + + for (j = 0; j < NUM_QUEUES; j++) { + mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]); + init_completion( + &new_cci_dev->cci_master_info[i].report_q[j]); + spin_lock_init( + &new_cci_dev->cci_master_info[i].lock_q[j]); + } + } + spin_lock_init(&new_cci_dev->lock_status); +} + +static void cam_cci_init_default_clk_params(struct cci_device *cci_dev, + uint8_t index) +{ + /* default clock params are for 100Khz */ + cci_dev->cci_clk_params[index].hw_thigh = 201; + cci_dev->cci_clk_params[index].hw_tlow = 174; + cci_dev->cci_clk_params[index].hw_tsu_sto = 204; + cci_dev->cci_clk_params[index].hw_tsu_sta = 231; + cci_dev->cci_clk_params[index].hw_thd_dat = 22; + cci_dev->cci_clk_params[index].hw_thd_sta = 162; + cci_dev->cci_clk_params[index].hw_tbuf = 227; + cci_dev->cci_clk_params[index].hw_scl_stretch_en = 0; + cci_dev->cci_clk_params[index].hw_trdhld = 6; + cci_dev->cci_clk_params[index].hw_tsp = 3; + cci_dev->cci_clk_params[index].cci_clk_src = 37500000; +} + +static void cam_cci_init_clk_params(struct cci_device *cci_dev) +{ + int32_t rc = 0; + uint32_t val = 0; + uint8_t count = 0; + struct device_node *of_node = cci_dev->v4l2_dev_str.pdev->dev.of_node; + struct device_node *src_node = NULL; + + for (count = 0; count < I2C_MAX_MODES; count++) { + + if (count == I2C_STANDARD_MODE) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_standard_mode"); + else if (count == I2C_FAST_MODE) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_fast_mode"); + else if (count == I2C_FAST_PLUS_MODE) + src_node = of_find_node_by_name(of_node, + "qcom,i2c_fast_plus_mode"); + else + src_node = of_find_node_by_name(of_node, + "qcom,i2c_custom_mode"); + + rc = of_property_read_u32(src_node, "hw-thigh", &val); + CAM_DBG(CAM_CCI, "hw-thigh %d, rc %d", val, rc); + if (!rc) { + cci_dev->cci_clk_params[count].hw_thigh = val; + rc = of_property_read_u32(src_node, "hw-tlow", + &val); + CAM_DBG(CAM_CCI, "hw-tlow %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tlow = val; + rc = of_property_read_u32(src_node, "hw-tsu-sto", + &val); + CAM_DBG(CAM_CCI, "hw-tsu-sto %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sto = val; + rc = of_property_read_u32(src_node, "hw-tsu-sta", + &val); + CAM_DBG(CAM_CCI, "hw-tsu-sta %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsu_sta = val; + rc = of_property_read_u32(src_node, "hw-thd-dat", + &val); + CAM_DBG(CAM_CCI, "hw-thd-dat %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_dat = val; + rc = of_property_read_u32(src_node, "hw-thd-sta", + &val); + CAM_DBG(CAM_CCI, "hw-thd-sta %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_thd_sta = val; + rc = of_property_read_u32(src_node, "hw-tbuf", + &val); + CAM_DBG(CAM_CCI, "hw-tbuf %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tbuf = val; + rc = of_property_read_u32(src_node, + "hw-scl-stretch-en", &val); + CAM_DBG(CAM_CCI, "hw-scl-stretch-en %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_scl_stretch_en = val; + rc = of_property_read_u32(src_node, "hw-trdhld", + &val); + CAM_DBG(CAM_CCI, "hw-trdhld %d, rc %d", + val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_trdhld = val; + rc = of_property_read_u32(src_node, "hw-tsp", + &val); + CAM_DBG(CAM_CCI, "hw-tsp %d, rc %d", val, rc); + } + if (!rc) { + cci_dev->cci_clk_params[count].hw_tsp = val; + val = 0; + rc = of_property_read_u32(src_node, "cci-clk-src", + &val); + CAM_DBG(CAM_CCI, "cci-clk-src %d, rc %d", val, rc); + cci_dev->cci_clk_params[count].cci_clk_src = val; + } else + cam_cci_init_default_clk_params(cci_dev, count); + + of_node_put(src_node); + } +} + +int cam_cci_parse_dt_info(struct platform_device *pdev, + struct cci_device *new_cci_dev) +{ + int rc = 0, i = 0; + struct cam_hw_soc_info *soc_info = + &new_cci_dev->soc_info; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_CCI, "Parsing DT data failed:%d", rc); + return -EINVAL; + } + + new_cci_dev->ref_count = 0; + + rc = cam_soc_util_request_platform_resource(soc_info, + cam_cci_irq, new_cci_dev); + if (rc < 0) { + CAM_ERR(CAM_CCI, "requesting platform resources failed:%d", rc); + return -EINVAL; + } + new_cci_dev->v4l2_dev_str.pdev = pdev; + cam_cci_init_cci_params(new_cci_dev); + cam_cci_init_clk_params(new_cci_dev); + + rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (rc) + CAM_ERR(CAM_CCI, "failed to add child nodes, rc=%d", rc); + + for (i = 0; i < MASTER_MAX; i++) { + new_cci_dev->write_wq[i] = create_singlethread_workqueue( + "cam_cci_wq"); + if (!new_cci_dev->write_wq[i]) + CAM_ERR(CAM_CCI, "Failed to create write wq"); + } + CAM_DBG(CAM_CCI, "Exit"); + return 0; +} + +int cam_cci_soc_release(struct cci_device *cci_dev, + enum cci_i2c_master_t master) +{ + uint8_t i = 0, rc = 0; + struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; + + if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED || + !cci_dev->master_active_slave[master]) { + CAM_ERR(CAM_CCI, + "invalid cci_dev_ref count %u | cci state %d | master_ref_count %u", + cci_dev->ref_count, cci_dev->cci_state, + cci_dev->master_active_slave[master]); + return -EINVAL; + } + + if (!(--cci_dev->master_active_slave[master])) { + cci_dev->cci_master_info[master].is_initilized = false; + CAM_DBG(CAM_CCI, + "All submodules are released for master: %d", master); + } + + if (--cci_dev->ref_count) { + CAM_DBG(CAM_CCI, "Submodule release: Ref_count: %d", + cci_dev->ref_count); + return 0; + } + for (i = 0; i < MASTER_MAX; i++) { + if (cci_dev->write_wq[i]) + flush_workqueue(cci_dev->write_wq[i]); + cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; + } + rc = cam_soc_util_disable_platform_resource(soc_info, true, true); + if (rc) { + CAM_ERR(CAM_CCI, "platform resources disable failed, rc=%d", + rc); + return rc; + } + + cci_dev->cci_state = CCI_STATE_DISABLED; + cci_dev->cycles_per_us = 0; + + cam_cpas_stop(cci_dev->cpas_handle); + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..e78d9918ff45112835f2be164d6dc75a82c90458 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_soc.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CCI_SOC_H_ +#define _CAM_CCI_SOC_H_ + +#include "cam_cci_core.h" +#include "cam_soc_util.h" + +/** + * @sd: V4L2 sub device + * @c_ctrl: CCI control structure + * + * This API initializes the CCI and acquires SOC resources + */ +int cam_cci_init(struct v4l2_subdev *sd, + struct cam_cci_ctrl *c_ctrl); + +/** + * @cci_dev: CCI device structure + * + * This API releases the CCI and its SOC resources + */ +int cam_cci_soc_release(struct cci_device *cci_dev, + enum cci_i2c_master_t master); + +/** + * @pdev: Platform device + * @new_cci_dev: CCI device structure + * + * This API parses CCI device tree + */ +int cam_cci_parse_dt_info(struct platform_device *pdev, + struct cci_device *new_cci_dev); + +/** + * @pdev: Platform device + * @cci_dev: CCI device structure + * + * This API puts all SOC resources + */ +void cam_cci_soc_remove(struct platform_device *pdev, + struct cci_device *cci_dev); +#endif /* _CAM_CCI_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d98b8457436300da9023e99b7bfb0c8fc43cc1d3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy_soc.o cam_csiphy_dev.o cam_csiphy_core.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c new file mode 100644 index 0000000000000000000000000000000000000000..7af2a7a3d26bdeda8c739ec857381e05358a32dc --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -0,0 +1,999 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include "cam_csiphy_core.h" +#include "cam_csiphy_dev.h" +#include "cam_csiphy_soc.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +#include <dt-bindings/msm/msm-camera.h> + +#include <soc/qcom/scm.h> +#include <cam_mem_mgr.h> +#include <cam_cpas_api.h> + +#define SCM_SVC_CAMERASS 0x18 +#define SECURE_SYSCALL_ID 0x6 +#define SECURE_SYSCALL_ID_2 0x7 + +#define LANE_MASK_2PH 0x1F +#define LANE_MASK_3PH 0x7 + +static int csiphy_dump; +module_param(csiphy_dump, int, 0644); + +static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, + bool protect, int32_t offset) +{ + struct scm_desc desc = {0}; + + if (offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid CSIPHY offset"); + return -EINVAL; + } + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = protect; + desc.args[1] = csiphy_dev->csiphy_cpas_cp_reg_mask[offset]; + + if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID_2), + &desc)) { + CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); + return -EINVAL; + } + + return 0; +} + +int32_t cam_csiphy_get_instance_offset( + struct csiphy_device *csiphy_dev, + int32_t dev_handle) +{ + int32_t i; + + if (csiphy_dev->acquire_count > + CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid acquire count"); + return -EINVAL; + } + + for (i = 0; i < csiphy_dev->acquire_count; i++) { + if (dev_handle == + csiphy_dev->bridge_intf.device_hdl[i]) + break; + } + + return i; +} + +void cam_csiphy_query_cap(struct csiphy_device *csiphy_dev, + struct cam_csiphy_query_cap *csiphy_cap) +{ + struct cam_hw_soc_info *soc_info = &csiphy_dev->soc_info; + + csiphy_cap->slot_info = soc_info->index; + csiphy_cap->version = csiphy_dev->hw_version; + csiphy_cap->clk_lane = csiphy_dev->clk_lane; +} + +void cam_csiphy_reset(struct csiphy_device *csiphy_dev) +{ + int32_t i; + void __iomem *base = NULL; + uint32_t size = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_reset_array_size; + struct cam_hw_soc_info *soc_info = &csiphy_dev->soc_info; + + base = soc_info->reg_map[0].mem_base; + + for (i = 0; i < size; i++) { + cam_io_w_mb( + csiphy_dev->ctrl_reg->csiphy_reset_reg[i].reg_data, + base + + csiphy_dev->ctrl_reg->csiphy_reset_reg[i].reg_addr); + + usleep_range(csiphy_dev->ctrl_reg->csiphy_reset_reg[i].delay + * 1000, csiphy_dev->ctrl_reg->csiphy_reset_reg[i].delay + * 1000 + 10); + } +} + +int32_t cam_csiphy_update_secure_info( + struct csiphy_device *csiphy_dev, + struct cam_csiphy_info *cam_cmd_csiphy_info, + struct cam_config_dev_cmd *cfg_dev) +{ + uint32_t clock_lane, adj_lane_mask, temp; + int32_t offset; + + if (csiphy_dev->acquire_count >= + CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid acquire count"); + return -EINVAL; + } + + offset = cam_csiphy_get_instance_offset(csiphy_dev, + cfg_dev->dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + return -EINVAL; + } + + if (cam_cmd_csiphy_info->combo_mode) + clock_lane = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_combo_ck_ln; + else + clock_lane = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_clock_lane; + + adj_lane_mask = cam_cmd_csiphy_info->lane_mask & LANE_MASK_2PH & + ~clock_lane; + temp = adj_lane_mask & (clock_lane - 1); + adj_lane_mask = + ((adj_lane_mask & (~(clock_lane - 1))) >> 1) | temp; + + if (cam_cmd_csiphy_info->csiphy_3phase) + adj_lane_mask = cam_cmd_csiphy_info->lane_mask & LANE_MASK_3PH; + + csiphy_dev->csiphy_info.secure_mode[offset] = 1; + + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = + adj_lane_mask << (csiphy_dev->soc_info.index * + (CAM_CSIPHY_MAX_DPHY_LANES + CAM_CSIPHY_MAX_CPHY_LANES) + + (!cam_cmd_csiphy_info->csiphy_3phase) * + (CAM_CSIPHY_MAX_CPHY_LANES)); + + return 0; +} + +int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, + struct cam_config_dev_cmd *cfg_dev) +{ + int32_t rc = 0; + uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint32_t *cmd_buf = NULL; + struct cam_csiphy_info *cam_cmd_csiphy_info = NULL; + size_t len; + size_t remain_len; + + if (!cfg_dev || !csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "Invalid Args"); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle, + &generic_pkt_ptr, &len); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc); + return rc; + } + + remain_len = len; + if ((sizeof(struct cam_packet) > len) || + ((size_t)cfg_dev->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CSIPHY, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len); + rc = -EINVAL; + return rc; + } + + remain_len -= (size_t)cfg_dev->offset; + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)cfg_dev->offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_CSIPHY, "Invalid packet params"); + rc = -EINVAL; + return rc; + } + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset / 4); + + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &generic_ptr, &len); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, + "Failed to get cmd buf Mem address : %d", rc); + return rc; + } + + if ((len < sizeof(struct cam_csiphy_info)) || + (cmd_desc->offset > (len - sizeof(struct cam_csiphy_info)))) { + CAM_ERR(CAM_CSIPHY, + "Not enough buffer provided for cam_cisphy_info"); + rc = -EINVAL; + return rc; + } + + cmd_buf = (uint32_t *)generic_ptr; + cmd_buf += cmd_desc->offset / 4; + cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf; + + csiphy_dev->config_count++; + csiphy_dev->csiphy_info.lane_cnt += cam_cmd_csiphy_info->lane_cnt; + csiphy_dev->csiphy_info.lane_mask |= cam_cmd_csiphy_info->lane_mask; + csiphy_dev->csiphy_info.csiphy_3phase = + cam_cmd_csiphy_info->csiphy_3phase; + csiphy_dev->csiphy_info.combo_mode |= cam_cmd_csiphy_info->combo_mode; + if (cam_cmd_csiphy_info->combo_mode == 1) { + csiphy_dev->csiphy_info.settle_time_combo_sensor = + cam_cmd_csiphy_info->settle_time; + csiphy_dev->csiphy_info.data_rate_combo_sensor = + cam_cmd_csiphy_info->data_rate; + } else { + csiphy_dev->csiphy_info.settle_time = + cam_cmd_csiphy_info->settle_time; + csiphy_dev->csiphy_info.data_rate = + cam_cmd_csiphy_info->data_rate; + } + + + if (cam_cmd_csiphy_info->secure_mode == 1) + cam_csiphy_update_secure_info(csiphy_dev, + cam_cmd_csiphy_info, cfg_dev); + + return rc; +} + +void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev) +{ + int32_t i; + void __iomem *csiphybase = + csiphy_dev->soc_info.reg_map[0].mem_base; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) + cam_io_w_mb( + csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_data, + csiphybase + + csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); +} + +void cam_csiphy_cphy_data_rate_config(struct csiphy_device *csiphy_device) +{ + int i = 0, j = 0; + uint64_t phy_data_rate = 0; + void __iomem *csiphybase = NULL; + ssize_t num_table_entries = 0; + struct data_rate_settings_t *settings_table = NULL; + + if ((csiphy_device == NULL) || + (csiphy_device->ctrl_reg == NULL) || + (csiphy_device->ctrl_reg->data_rates_settings_table == NULL)) { + CAM_DBG(CAM_CSIPHY, + "Data rate specific register table not found"); + return; + } + + phy_data_rate = csiphy_device->csiphy_info.data_rate; + csiphybase = + csiphy_device->soc_info.reg_map[0].mem_base; + settings_table = + csiphy_device->ctrl_reg->data_rates_settings_table; + num_table_entries = + settings_table->num_data_rate_settings; + + CAM_DBG(CAM_CSIPHY, "required data rate : %llu", phy_data_rate); + for (i = 0; i < num_table_entries; i++) { + struct data_rate_reg_info_t *drate_settings = + settings_table->data_rate_settings; + uint64_t bandwidth = + drate_settings[i].bandwidth; + ssize_t num_reg_entries = + drate_settings[i].data_rate_reg_array_size; + + if (phy_data_rate > bandwidth) { + CAM_DBG(CAM_CSIPHY, + "Skipping table [%d] %llu required: %llu", + i, bandwidth, phy_data_rate); + continue; + } + + CAM_DBG(CAM_CSIPHY, + "table[%d] BW : %llu Selected", i, bandwidth); + for (j = 0; j < num_reg_entries; j++) { + uint32_t reg_addr = + drate_settings[i].csiphy_data_rate_regs[j].reg_addr; + + uint32_t reg_data = + drate_settings[i].csiphy_data_rate_regs[j].reg_data; + + CAM_DBG(CAM_CSIPHY, + "writing reg : %x val : %x", + reg_addr, reg_data); + cam_io_w_mb(reg_data, + csiphybase + reg_addr); + } + break; + } +} + +void cam_csiphy_cphy_irq_disable(struct csiphy_device *csiphy_dev) +{ + int32_t i; + void __iomem *csiphybase = + csiphy_dev->soc_info.reg_map[0].mem_base; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) + cam_io_w_mb(0x0, csiphybase + + csiphy_dev->ctrl_reg->csiphy_irq_reg[i].reg_addr); +} + +irqreturn_t cam_csiphy_irq(int irq_num, void *data) +{ + uint32_t irq; + uint8_t i; + struct csiphy_device *csiphy_dev = + (struct csiphy_device *)data; + struct cam_hw_soc_info *soc_info = NULL; + struct csiphy_reg_parms_t *csiphy_reg = NULL; + void __iomem *base = NULL; + + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "Invalid Args"); + return IRQ_NONE; + } + + soc_info = &csiphy_dev->soc_info; + base = csiphy_dev->soc_info.reg_map[0].mem_base; + csiphy_reg = &csiphy_dev->ctrl_reg->csiphy_reg; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) { + irq = cam_io_r(base + + csiphy_reg->mipi_csiphy_interrupt_status0_addr + + (0x4 * i)); + cam_io_w_mb(irq, base + + csiphy_reg->mipi_csiphy_interrupt_clear0_addr + + (0x4 * i)); + CAM_ERR_RATE_LIMIT(CAM_CSIPHY, + "CSIPHY%d_IRQ_STATUS_ADDR%d = 0x%x", + soc_info->index, i, irq); + cam_io_w_mb(0x0, base + + csiphy_reg->mipi_csiphy_interrupt_clear0_addr + + (0x4 * i)); + } + cam_io_w_mb(0x1, base + csiphy_reg->mipi_csiphy_glbl_irq_cmd_addr); + cam_io_w_mb(0x0, base + csiphy_reg->mipi_csiphy_glbl_irq_cmd_addr); + + return IRQ_HANDLED; +} + +int32_t cam_csiphy_config_dev(struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0; + uint32_t lane_enable = 0, mask = 1, size = 0; + uint16_t lane_mask = 0, i = 0, cfg_size = 0, temp = 0; + uint8_t lane_cnt, lane_pos = 0; + uint16_t settle_cnt = 0; + uint64_t intermediate_var; + void __iomem *csiphybase; + struct csiphy_reg_t *csiphy_common_reg = NULL; + struct csiphy_reg_t (*reg_array)[MAX_SETTINGS_PER_LANE]; + + lane_cnt = csiphy_dev->csiphy_info.lane_cnt; + csiphybase = csiphy_dev->soc_info.reg_map[0].mem_base; + + if (!csiphybase) { + CAM_ERR(CAM_CSIPHY, "csiphybase NULL"); + return -EINVAL; + } + + if (!csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->csiphy_info.combo_mode == 1) + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg; + else + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_reg; + csiphy_dev->num_irq_registers = 11; + cfg_size = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_2ph_config_array_size; + + lane_mask = csiphy_dev->csiphy_info.lane_mask & LANE_MASK_2PH; + for (i = 0; i < MAX_DPHY_DATA_LN; i++) { + if (mask == 0x2) { + if (lane_mask & mask) + lane_enable |= 0x80; + i--; + } else if (lane_mask & mask) { + lane_enable |= 0x1 << (i<<1); + } + mask <<= 1; + } + } else { + if (csiphy_dev->csiphy_info.combo_mode == 1) { + if (csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg) + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg; + else { + reg_array = + csiphy_dev->ctrl_reg->csiphy_3ph_reg; + CAM_ERR(CAM_CSIPHY, + "Unsupported configuration, Falling back to CPHY mode"); + } + } else + reg_array = + csiphy_dev->ctrl_reg->csiphy_3ph_reg; + csiphy_dev->num_irq_registers = 11; + cfg_size = + csiphy_dev->ctrl_reg->csiphy_reg.csiphy_3ph_config_array_size; + + lane_mask = csiphy_dev->csiphy_info.lane_mask & LANE_MASK_3PH; + mask = lane_mask; + while (mask != 0) { + temp = (i << 1)+1; + lane_enable |= ((mask & 0x1) << temp); + mask >>= 1; + i++; + } + } + + size = csiphy_dev->ctrl_reg->csiphy_reg.csiphy_common_array_size; + + for (i = 0; i < size; i++) { + csiphy_common_reg = &csiphy_dev->ctrl_reg->csiphy_common_reg[i]; + switch (csiphy_common_reg->csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + cam_io_w_mb(lane_enable, + csiphybase + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + break; + case CSIPHY_DEFAULT_PARAMS: + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + break; + case CSIPHY_2PH_REGS: + if (!csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; + case CSIPHY_3PH_REGS: + if (csiphy_dev->csiphy_info.csiphy_3phase) { + cam_io_w_mb(csiphy_common_reg->reg_data, + csiphybase + + csiphy_common_reg->reg_addr); + usleep_range(csiphy_common_reg->delay * 1000, + csiphy_common_reg->delay * 1000 + 10); + } + break; + default: + break; + } + } + + while (lane_mask) { + if (!(lane_mask & 0x1)) { + lane_pos++; + lane_mask >>= 1; + continue; + } + + intermediate_var = csiphy_dev->csiphy_info.settle_time; + do_div(intermediate_var, 200000000); + settle_cnt = intermediate_var; + if (csiphy_dev->csiphy_info.combo_mode == 1 && + (lane_pos >= 3)) { + intermediate_var = + csiphy_dev->csiphy_info.settle_time_combo_sensor; + do_div(intermediate_var, 200000000); + settle_cnt = intermediate_var; + } + for (i = 0; i < cfg_size; i++) { + switch (reg_array[lane_pos][i].csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + cam_io_w_mb(lane_enable, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + case CSIPHY_DEFAULT_PARAMS: + cam_io_w_mb(reg_array[lane_pos][i].reg_data, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + case CSIPHY_SETTLE_CNT_LOWER_BYTE: + cam_io_w_mb(settle_cnt & 0xFF, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + case CSIPHY_SETTLE_CNT_HIGHER_BYTE: + cam_io_w_mb((settle_cnt >> 8) & 0xFF, + csiphybase + + reg_array[lane_pos][i].reg_addr); + break; + default: + CAM_DBG(CAM_CSIPHY, "Do Nothing"); + break; + } + if (reg_array[lane_pos][i].delay > 0) { + usleep_range(reg_array[lane_pos][i].delay*1000, + reg_array[lane_pos][i].delay*1000 + 10); + } + } + lane_mask >>= 1; + lane_pos++; + } + + if (csiphy_dev->csiphy_info.csiphy_3phase) + cam_csiphy_cphy_data_rate_config(csiphy_dev); + + cam_csiphy_cphy_irq_config(csiphy_dev); + + return rc; +} + +void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev) +{ + struct cam_hw_soc_info *soc_info; + int32_t i = 0; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) + return; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + soc_info = &csiphy_dev->soc_info; + + for (i = 0; i < csiphy_dev->acquire_count; i++) { + if (csiphy_dev->csiphy_info.secure_mode[i]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, i); + + csiphy_dev->csiphy_info.secure_mode[i] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[i] = 0; + } + + cam_csiphy_reset(csiphy_dev); + cam_soc_util_disable_platform_resource(soc_info, true, true); + + cam_cpas_stop(csiphy_dev->cpas_handle); + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + } + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_ACQUIRE) { + if (csiphy_dev->bridge_intf.device_hdl[0] != -1) + cam_destroy_device_hdl( + csiphy_dev->bridge_intf.device_hdl[0]); + if (csiphy_dev->bridge_intf.device_hdl[1] != -1) + cam_destroy_device_hdl( + csiphy_dev->bridge_intf.device_hdl[1]); + csiphy_dev->bridge_intf.device_hdl[0] = -1; + csiphy_dev->bridge_intf.device_hdl[1] = -1; + csiphy_dev->bridge_intf.link_hdl[0] = -1; + csiphy_dev->bridge_intf.link_hdl[1] = -1; + csiphy_dev->bridge_intf.session_hdl[0] = -1; + csiphy_dev->bridge_intf.session_hdl[1] = -1; + } + + csiphy_dev->ref_count = 0; + csiphy_dev->is_acquired_dev_combo_mode = 0; + csiphy_dev->acquire_count = 0; + csiphy_dev->start_dev_count = 0; + csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; +} + +static int32_t cam_csiphy_external_cmd(struct csiphy_device *csiphy_dev, + struct cam_config_dev_cmd *p_submit_cmd) +{ + struct cam_csiphy_info cam_cmd_csiphy_info; + int32_t rc = 0; + + if (copy_from_user(&cam_cmd_csiphy_info, + u64_to_user_ptr(p_submit_cmd->packet_handle), + sizeof(struct cam_csiphy_info))) { + CAM_ERR(CAM_CSIPHY, "failed to copy cam_csiphy_info\n"); + rc = -EFAULT; + } else { + csiphy_dev->csiphy_info.lane_cnt = + cam_cmd_csiphy_info.lane_cnt; + csiphy_dev->csiphy_info.lane_cnt = + cam_cmd_csiphy_info.lane_cnt; + csiphy_dev->csiphy_info.lane_mask = + cam_cmd_csiphy_info.lane_mask; + csiphy_dev->csiphy_info.csiphy_3phase = + cam_cmd_csiphy_info.csiphy_3phase; + csiphy_dev->csiphy_info.combo_mode = + cam_cmd_csiphy_info.combo_mode; + csiphy_dev->csiphy_info.settle_time = + cam_cmd_csiphy_info.settle_time; + csiphy_dev->csiphy_info.data_rate = + cam_cmd_csiphy_info.data_rate; + CAM_DBG(CAM_CSIPHY, + "%s CONFIG_DEV_EXT settle_time= %lld lane_cnt=%d lane_mask=0x%x", + __func__, + csiphy_dev->csiphy_info.settle_time, + csiphy_dev->csiphy_info.lane_cnt, + csiphy_dev->csiphy_info.lane_mask); + } + + return rc; +} + +int32_t cam_csiphy_core_cfg(void *phy_dev, + void *arg) +{ + struct csiphy_device *csiphy_dev = + (struct csiphy_device *)phy_dev; + struct intf_params *bridge_intf = NULL; + struct cam_control *cmd = (struct cam_control *)arg; + int32_t rc = 0; + + if (!csiphy_dev || !cmd) { + CAM_ERR(CAM_CSIPHY, "Invalid input args"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_CSIPHY, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + CAM_DBG(CAM_CSIPHY, "Opcode received: %d", cmd->op_code); + mutex_lock(&csiphy_dev->mutex); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev csiphy_acq_dev; + struct cam_csiphy_acquire_dev_info csiphy_acq_params; + + struct cam_create_dev_hdl bridge_params; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + CAM_ERR(CAM_CSIPHY, + "Not in right state to acquire : %d", + csiphy_dev->csiphy_state); + rc = -EINVAL; + goto release_mutex; + } + + rc = copy_from_user(&csiphy_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(csiphy_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + goto release_mutex; + } + + csiphy_acq_params.combo_mode = 0; + + if (copy_from_user(&csiphy_acq_params, + u64_to_user_ptr(csiphy_acq_dev.info_handle), + sizeof(csiphy_acq_params))) { + CAM_ERR(CAM_CSIPHY, + "Failed copying from User"); + goto release_mutex; + } + + if (csiphy_dev->acquire_count == 2) { + CAM_ERR(CAM_CSIPHY, + "CSIPHY device do not allow more than 2 acquires"); + rc = -EINVAL; + goto release_mutex; + } + + if ((csiphy_acq_params.combo_mode == 1) && + (csiphy_dev->is_acquired_dev_combo_mode == 1)) { + CAM_ERR(CAM_CSIPHY, + "Multiple Combo Acq are not allowed: cm: %d, acm: %d", + csiphy_acq_params.combo_mode, + csiphy_dev->is_acquired_dev_combo_mode); + rc = -EINVAL; + goto release_mutex; + } + + if ((csiphy_acq_params.combo_mode != 1) && + (csiphy_dev->is_acquired_dev_combo_mode != 1) && + (csiphy_dev->acquire_count == 1)) { + CAM_ERR(CAM_CSIPHY, + "Multiple Acquires are not allowed cm: %d acm: %d", + csiphy_acq_params.combo_mode, + csiphy_dev->is_acquired_dev_combo_mode); + rc = -EINVAL; + goto release_mutex; + } + + bridge_params.ops = NULL; + bridge_params.session_hdl = csiphy_acq_dev.session_handle; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = csiphy_dev; + + if (csiphy_acq_params.combo_mode >= 2) { + CAM_ERR(CAM_CSIPHY, "Invalid combo_mode %d", + csiphy_acq_params.combo_mode); + rc = -EINVAL; + goto release_mutex; + } + + csiphy_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + bridge_intf = &csiphy_dev->bridge_intf; + bridge_intf->device_hdl[csiphy_acq_params.combo_mode] + = csiphy_acq_dev.device_handle; + bridge_intf->session_hdl[csiphy_acq_params.combo_mode] = + csiphy_acq_dev.session_handle; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &csiphy_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + rc = -EINVAL; + goto release_mutex; + } + if (csiphy_acq_params.combo_mode == 1) + csiphy_dev->is_acquired_dev_combo_mode = 1; + + csiphy_dev->acquire_count++; + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + } + break; + case CAM_QUERY_CAP: { + struct cam_csiphy_query_cap csiphy_cap = {0}; + + cam_csiphy_query_cap(csiphy_dev, &csiphy_cap); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &csiphy_cap, sizeof(struct cam_csiphy_query_cap))) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + rc = -EINVAL; + goto release_mutex; + } + } + break; + case CAM_STOP_DEV: { + int32_t offset, rc = 0; + struct cam_start_stop_dev_cmd config; + + rc = copy_from_user(&config, (void __user *)cmd->handle, + sizeof(config)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + goto release_mutex; + } + + if ((csiphy_dev->csiphy_state != CAM_CSIPHY_START) || + !csiphy_dev->start_dev_count) { + CAM_ERR(CAM_CSIPHY, "Not in right state to stop : %d", + csiphy_dev->csiphy_state); + rc = -EINVAL; + goto release_mutex; + } + + offset = cam_csiphy_get_instance_offset(csiphy_dev, + config.dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + goto release_mutex; + } + + if (--csiphy_dev->start_dev_count) { + CAM_DBG(CAM_CSIPHY, "Stop Dev ref Cnt: %d", + csiphy_dev->start_dev_count); + if (csiphy_dev->csiphy_info.secure_mode[offset]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0; + + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode[offset]) + cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + + csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; + + rc = cam_csiphy_disable_hw(csiphy_dev); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "Failed in csiphy release"); + + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc); + + csiphy_dev->csiphy_state = CAM_CSIPHY_ACQUIRE; + } + break; + case CAM_RELEASE_DEV: { + struct cam_release_dev_cmd release; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + rc = cam_csiphy_disable_hw(csiphy_dev); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "Failed in csiphy release"); + rc = cam_cpas_stop(csiphy_dev->cpas_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "de-voting CPAS: %d", rc); + } + + if (!csiphy_dev->acquire_count) { + CAM_ERR(CAM_CSIPHY, "No valid devices to release"); + rc = -EINVAL; + goto release_mutex; + } + + if (copy_from_user(&release, + u64_to_user_ptr(cmd->handle), + sizeof(release))) { + rc = -EFAULT; + goto release_mutex; + } + + rc = cam_destroy_device_hdl(release.dev_handle); + if (rc < 0) + CAM_ERR(CAM_CSIPHY, "destroying the device hdl"); + if (release.dev_handle == + csiphy_dev->bridge_intf.device_hdl[0]) { + csiphy_dev->bridge_intf.device_hdl[0] = -1; + csiphy_dev->bridge_intf.link_hdl[0] = -1; + csiphy_dev->bridge_intf.session_hdl[0] = -1; + } else { + csiphy_dev->bridge_intf.device_hdl[1] = -1; + csiphy_dev->bridge_intf.link_hdl[1] = -1; + csiphy_dev->bridge_intf.session_hdl[1] = -1; + csiphy_dev->is_acquired_dev_combo_mode = 0; + } + + csiphy_dev->config_count--; + csiphy_dev->acquire_count--; + + if (csiphy_dev->acquire_count == 0) + csiphy_dev->csiphy_state = CAM_CSIPHY_INIT; + + if (csiphy_dev->config_count == 0) { + CAM_DBG(CAM_CSIPHY, "reset csiphy_info"); + csiphy_dev->csiphy_info.lane_mask = 0; + csiphy_dev->csiphy_info.lane_cnt = 0; + csiphy_dev->csiphy_info.combo_mode = 0; + } + } + break; + case CAM_CONFIG_DEV: { + struct cam_config_dev_cmd config; + + if (copy_from_user(&config, + u64_to_user_ptr(cmd->handle), + sizeof(config))) { + rc = -EFAULT; + } else { + rc = cam_cmd_buf_parser(csiphy_dev, &config); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Fail in cmd buf parser"); + goto release_mutex; + } + } + break; + } + case CAM_START_DEV: { + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote = {0}; + struct cam_start_stop_dev_cmd config; + int32_t offset; + + rc = copy_from_user(&config, (void __user *)cmd->handle, + sizeof(config)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed copying from User"); + goto release_mutex; + } + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + csiphy_dev->start_dev_count++; + goto release_mutex; + } + + offset = cam_csiphy_get_instance_offset(csiphy_dev, + config.dev_handle); + if (offset < 0 || offset >= CSIPHY_MAX_INSTANCES) { + CAM_ERR(CAM_CSIPHY, "Invalid offset"); + goto release_mutex; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_LOWSVS_VOTE; + axi_vote.num_paths = 1; + axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; + axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; + axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; + + rc = cam_cpas_start(csiphy_dev->cpas_handle, + &ahb_vote, &axi_vote); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "voting CPAS: %d", rc); + if (rc == -EALREADY) + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode[offset] == 1) { + if (cam_cpas_is_feature_supported( + CAM_CPAS_SECURE_CAMERA_ENABLE) != 1) { + CAM_ERR(CAM_CSIPHY, + "sec_cam: camera fuse bit not set"); + cam_cpas_stop(csiphy_dev->cpas_handle); + rc = -1; + goto release_mutex; + } + + rc = cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_SECURE, offset); + if (rc < 0) { + csiphy_dev->csiphy_info.secure_mode[offset] = + CAM_SECURE_MODE_NON_SECURE; + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + } + + rc = cam_csiphy_enable_hw(csiphy_dev); + if (rc != 0) { + CAM_ERR(CAM_CSIPHY, "cam_csiphy_enable_hw failed"); + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + rc = cam_csiphy_config_dev(csiphy_dev); + if (csiphy_dump == 1) + cam_csiphy_mem_dmp(&csiphy_dev->soc_info); + + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "cam_csiphy_config_dev failed"); + cam_csiphy_disable_hw(csiphy_dev); + cam_cpas_stop(csiphy_dev->cpas_handle); + goto release_mutex; + } + csiphy_dev->start_dev_count++; + csiphy_dev->csiphy_state = CAM_CSIPHY_START; + } + break; + case CAM_CONFIG_DEV_EXTERNAL: { + struct cam_config_dev_cmd submit_cmd; + + if (copy_from_user(&submit_cmd, + u64_to_user_ptr(cmd->handle), + sizeof(struct cam_config_dev_cmd))) { + CAM_ERR(CAM_CSIPHY, "failed copy config ext\n"); + rc = -EFAULT; + } else { + rc = cam_csiphy_external_cmd(csiphy_dev, &submit_cmd); + } + break; + } + default: + CAM_ERR(CAM_CSIPHY, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + goto release_mutex; + } + +release_mutex: + mutex_unlock(&csiphy_dev->mutex); + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h new file mode 100644 index 0000000000000000000000000000000000000000..237fa787f2268745f5634e257552c4625854cdfa --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_CORE_H_ +#define _CAM_CSIPHY_CORE_H_ + +#include <linux/irqreturn.h> +#include "cam_csiphy_dev.h" +#include <cam_mem_mgr.h> +#include <cam_req_mgr_util.h> +#include <cam_io_util.h> + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API programs CSIPhy IRQ registers + */ +void cam_csiphy_cphy_irq_config(struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API resets CSIPhy hardware + */ +void cam_csiphy_reset(struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * @arg: Camera control command argument + * + * This API handles the camera control argument reached to CSIPhy + */ +int cam_csiphy_core_cfg(void *csiphy_dev, void *arg); + +/** + * @irq_num: IRQ number + * @data: CSIPhy device structure + * + * This API handles CSIPhy IRQs + */ +irqreturn_t cam_csiphy_irq(int irq_num, void *data); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API handles the CSIPhy close + */ +void cam_csiphy_shutdown(struct csiphy_device *csiphy_dev); + +#endif /* _CAM_CSIPHY_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..ba98d9adcc2dfe3a3b438156ff40fea5cee27759 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_csiphy_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_csiphy_soc.h" +#include "cam_csiphy_core.h" +#include <media/cam_sensor.h> + +static long cam_csiphy_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(sd); + int rc = 0; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_csiphy_core_cfg(csiphy_dev, arg); + if (rc != 0) { + CAM_ERR(CAM_CSIPHY, "in configuring the device"); + return rc; + } + break; + default: + CAM_ERR(CAM_CSIPHY, "Wrong ioctl : %d", cmd); + break; + } + + return rc; +} + +static int cam_csiphy_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct csiphy_device *csiphy_dev = + v4l2_get_subdevdata(sd); + + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "csiphy_dev ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&csiphy_dev->mutex); + cam_csiphy_shutdown(csiphy_dev); + mutex_unlock(&csiphy_dev->mutex); + + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_csiphy_subdev_compat_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + int32_t rc = 0; + struct cam_control cmd_data; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_CSIPHY, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + /* All the arguments converted to 64 bit here + * Passed to the api in core.c + */ + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_csiphy_subdev_ioctl(sd, cmd, &cmd_data); + break; + default: + CAM_ERR(CAM_CSIPHY, "Invalid compat ioctl cmd: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_CSIPHY, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static struct v4l2_subdev_core_ops csiphy_subdev_core_ops = { + .ioctl = cam_csiphy_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_csiphy_subdev_compat_ioctl, +#endif +}; + +static const struct v4l2_subdev_ops csiphy_subdev_ops = { + .core = &csiphy_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops csiphy_subdev_intern_ops = { + .close = cam_csiphy_subdev_close, +}; + +static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) +{ + struct cam_cpas_register_params cpas_parms; + struct csiphy_device *new_csiphy_dev; + int32_t rc = 0; + + new_csiphy_dev = devm_kzalloc(&pdev->dev, + sizeof(struct csiphy_device), GFP_KERNEL); + if (!new_csiphy_dev) + return -ENOMEM; + + new_csiphy_dev->ctrl_reg = kzalloc(sizeof(struct csiphy_ctrl_t), + GFP_KERNEL); + if (!new_csiphy_dev->ctrl_reg) { + devm_kfree(&pdev->dev, new_csiphy_dev); + return -ENOMEM; + } + + mutex_init(&new_csiphy_dev->mutex); + new_csiphy_dev->v4l2_dev_str.pdev = pdev; + + new_csiphy_dev->soc_info.pdev = pdev; + new_csiphy_dev->soc_info.dev = &pdev->dev; + new_csiphy_dev->soc_info.dev_name = pdev->name; + new_csiphy_dev->ref_count = 0; + + rc = cam_csiphy_parse_dt_info(pdev, new_csiphy_dev); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "DT parsing failed: %d", rc); + goto csiphy_no_resource; + } + + new_csiphy_dev->v4l2_dev_str.internal_ops = + &csiphy_subdev_intern_ops; + new_csiphy_dev->v4l2_dev_str.ops = + &csiphy_subdev_ops; + strlcpy(new_csiphy_dev->device_name, CAMX_CSIPHY_DEV_NAME, + sizeof(new_csiphy_dev->device_name)); + new_csiphy_dev->v4l2_dev_str.name = + new_csiphy_dev->device_name; + new_csiphy_dev->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + new_csiphy_dev->v4l2_dev_str.ent_function = + CAM_CSIPHY_DEVICE_TYPE; + new_csiphy_dev->v4l2_dev_str.token = + new_csiphy_dev; + + rc = cam_register_subdev(&(new_csiphy_dev->v4l2_dev_str)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "cam_register_subdev Failed rc: %d", rc); + goto csiphy_no_resource; + } + + platform_set_drvdata(pdev, &(new_csiphy_dev->v4l2_dev_str.sd)); + + new_csiphy_dev->bridge_intf.device_hdl[0] = -1; + new_csiphy_dev->bridge_intf.device_hdl[1] = -1; + new_csiphy_dev->bridge_intf.ops.get_dev_info = + NULL; + new_csiphy_dev->bridge_intf.ops.link_setup = + NULL; + new_csiphy_dev->bridge_intf.ops.apply_req = + NULL; + + new_csiphy_dev->acquire_count = 0; + new_csiphy_dev->start_dev_count = 0; + new_csiphy_dev->is_acquired_dev_combo_mode = 0; + + cpas_parms.cam_cpas_client_cb = NULL; + cpas_parms.cell_index = new_csiphy_dev->soc_info.index; + cpas_parms.dev = &pdev->dev; + cpas_parms.userdata = new_csiphy_dev; + + strlcpy(cpas_parms.identifier, "csiphy", CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_parms); + if (rc) { + CAM_ERR(CAM_CSIPHY, "CPAS registration failed rc: %d", rc); + goto csiphy_no_resource; + } + CAM_DBG(CAM_CSIPHY, "CPAS registration successful handle=%d", + cpas_parms.client_handle); + new_csiphy_dev->cpas_handle = cpas_parms.client_handle; + + return rc; +csiphy_no_resource: + mutex_destroy(&new_csiphy_dev->mutex); + kfree(new_csiphy_dev->ctrl_reg); + devm_kfree(&pdev->dev, new_csiphy_dev); + return rc; +} + + +static int32_t cam_csiphy_device_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev = + platform_get_drvdata(pdev); + struct csiphy_device *csiphy_dev = + v4l2_get_subdevdata(subdev); + + CAM_INFO(CAM_CSIPHY, "device remove invoked"); + cam_cpas_unregister_client(csiphy_dev->cpas_handle); + cam_csiphy_soc_release(csiphy_dev); + mutex_lock(&csiphy_dev->mutex); + cam_csiphy_shutdown(csiphy_dev); + mutex_unlock(&csiphy_dev->mutex); + cam_unregister_subdev(&(csiphy_dev->v4l2_dev_str)); + kfree(csiphy_dev->ctrl_reg); + csiphy_dev->ctrl_reg = NULL; + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(csiphy_dev->v4l2_dev_str.sd), NULL); + devm_kfree(&pdev->dev, csiphy_dev); + + return 0; +} + +static const struct of_device_id cam_csiphy_dt_match[] = { + {.compatible = "qcom,csiphy"}, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_csiphy_dt_match); + +static struct platform_driver csiphy_driver = { + .probe = cam_csiphy_platform_probe, + .remove = cam_csiphy_device_remove, + .driver = { + .name = CAMX_CSIPHY_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = cam_csiphy_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int32_t __init cam_csiphy_init_module(void) +{ + return platform_driver_register(&csiphy_driver); +} + +static void __exit cam_csiphy_exit_module(void) +{ + platform_driver_unregister(&csiphy_driver); +} + +module_init(cam_csiphy_init_module); +module_exit(cam_csiphy_exit_module); +MODULE_DESCRIPTION("CAM CSIPHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..78c7a848cd8194390859761dc00cb6c6423af820 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -0,0 +1,295 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_DEV_H_ +#define _CAM_CSIPHY_DEV_H_ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/irqreturn.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <media/cam_defs.h> +#include <cam_sensor_cmn_header.h> +#include <cam_req_mgr_interface.h> +#include <cam_subdev.h> +#include <cam_io_util.h> +#include <cam_cpas_api.h> +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_context.h" + +#define MAX_CSIPHY 6 +#define MAX_DPHY_DATA_LN 4 +#define MAX_LRME_V4l2_EVENTS 30 +#define CSIPHY_NUM_CLK_MAX 16 +#define MAX_CSIPHY_REG_ARRAY 70 +#define MAX_CSIPHY_CMN_REG_ARRAY 5 + +#define MAX_LANES 5 +#define MAX_SETTINGS_PER_LANE 43 +#define MAX_DATA_RATES 3 +#define MAX_DATA_RATE_REGS 30 + +#define MAX_REGULATOR 5 +#define CAMX_CSIPHY_DEV_NAME "cam-csiphy-driver" + +#define CSIPHY_POWER_UP 0 +#define CSIPHY_POWER_DOWN 1 + +#define CSIPHY_DEFAULT_PARAMS 0 +#define CSIPHY_LANE_ENABLE 1 +#define CSIPHY_SETTLE_CNT_LOWER_BYTE 2 +#define CSIPHY_SETTLE_CNT_HIGHER_BYTE 3 +#define CSIPHY_DNP_PARAMS 4 +#define CSIPHY_2PH_REGS 5 +#define CSIPHY_3PH_REGS 6 + +#define CSIPHY_MAX_INSTANCES 2 + +#define CAM_CSIPHY_MAX_DPHY_LANES 4 +#define CAM_CSIPHY_MAX_CPHY_LANES 3 + +#define ENABLE_IRQ false + +#undef CDBG +#ifdef CAM_CSIPHY_CORE_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +enum cam_csiphy_state { + CAM_CSIPHY_INIT, + CAM_CSIPHY_ACQUIRE, + CAM_CSIPHY_START, +}; + +/** + * struct csiphy_reg_parms_t + * @mipi_csiphy_glbl_irq_cmd_addr: CSIPhy irq addr + * @mipi_csiphy_interrupt_status0_addr: + * CSIPhy interrupt status addr + * @mipi_csiphy_interrupt_mask0_addr: + * CSIPhy interrupt mask addr + * @mipi_csiphy_interrupt_mask_val: + * CSIPhy interrupt mask val + * @mipi_csiphy_interrupt_clear0_addr: + * CSIPhy interrupt clear addr + * @csiphy_version: CSIPhy Version + * @csiphy_common_array_size: CSIPhy common array size + * @csiphy_reset_array_size: CSIPhy reset array size + * @csiphy_2ph_config_array_size: 2ph settings size + * @csiphy_3ph_config_array_size: 3ph settings size + * @csiphy_cpas_cp_bits_per_phy: CP bits per phy + * @csiphy_cpas_cp_is_interleaved: checks whether cp bits + * are interleaved or not + * @csiphy_cpas_cp_2ph_offset: cp register 2ph offset + * @csiphy_cpas_cp_3ph_offset: cp register 3ph offset + * @csiphy_2ph_clock_lane: clock lane in 2ph + * @csiphy_2ph_combo_ck_ln: clk lane in combo 2ph + */ +struct csiphy_reg_parms_t { +/*MIPI CSI PHY registers*/ + uint32_t mipi_csiphy_glbl_irq_cmd_addr; + uint32_t mipi_csiphy_interrupt_status0_addr; + uint32_t mipi_csiphy_interrupt_mask0_addr; + uint32_t mipi_csiphy_interrupt_mask_val; + uint32_t mipi_csiphy_interrupt_mask_addr; + uint32_t mipi_csiphy_interrupt_clear0_addr; + uint32_t csiphy_version; + uint32_t csiphy_common_array_size; + uint32_t csiphy_reset_array_size; + uint32_t csiphy_2ph_config_array_size; + uint32_t csiphy_3ph_config_array_size; + uint32_t csiphy_cpas_cp_bits_per_phy; + uint32_t csiphy_cpas_cp_is_interleaved; + uint32_t csiphy_cpas_cp_2ph_offset; + uint32_t csiphy_cpas_cp_3ph_offset; + uint32_t csiphy_2ph_clock_lane; + uint32_t csiphy_2ph_combo_ck_ln; +}; + +/** + * struct intf_params + * @device_hdl: Device Handle + * @session_hdl: Session Handle + * @ops: KMD operations + * @crm_cb: Callback API pointers + */ +struct intf_params { + int32_t device_hdl[CSIPHY_MAX_INSTANCES]; + int32_t session_hdl[CSIPHY_MAX_INSTANCES]; + int32_t link_hdl[CSIPHY_MAX_INSTANCES]; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct csiphy_reg_t + * @reg_addr: Register address + * @reg_data: Register data + * @delay: Delay + * @csiphy_param_type: CSIPhy parameter type + */ +struct csiphy_reg_t { + int32_t reg_addr; + int32_t reg_data; + int32_t delay; + uint32_t csiphy_param_type; +}; + +struct csiphy_device; + +/* + * struct data_rate_reg_info_t + * @bandwidth: max bandwidth supported by this reg settings + * @data_rate_reg_array_size: number of reg value pairs in the array + * @csiphy_data_rate_regs: array of data rate specific reg value pairs + */ +struct data_rate_reg_info_t { + uint64_t bandwidth; + ssize_t data_rate_reg_array_size; + struct csiphy_reg_t csiphy_data_rate_regs[MAX_DATA_RATE_REGS]; +}; + +/** + * struct data_rate_settings_t + * @num_data_rate_settings: number of valid settings + * present in the data rate settings array + * @data_rate_settings: array of regsettings which are specific to + * data rate + */ +struct data_rate_settings_t { + ssize_t num_data_rate_settings; + struct data_rate_reg_info_t data_rate_settings[MAX_DATA_RATES]; +}; + +/** + * struct csiphy_ctrl_t + * @csiphy_reg: Register address + * @csiphy_common_reg: Common register set + * @csiphy_reset_reg: Reset register set + * @csiphy_2ph_reg: 2phase register set + * @csiphy_2ph_combo_mode_reg: + * 2phase combo register set + * @csiphy_3ph_reg: 3phase register set + * @csiphy_2ph_3ph_mode_reg: + * 2 phase 3phase combo register set + * @getclockvoting: function pointer which + * is used to find the clock voting + * for the sensor output data rate + * @data_rate_settings_table: + * Table which maintains the resgister + * settings specific to data rate + */ +struct csiphy_ctrl_t { + struct csiphy_reg_parms_t csiphy_reg; + struct csiphy_reg_t *csiphy_common_reg; + struct csiphy_reg_t *csiphy_irq_reg; + struct csiphy_reg_t *csiphy_reset_reg; + struct csiphy_reg_t (*csiphy_2ph_reg)[MAX_SETTINGS_PER_LANE]; + struct csiphy_reg_t (*csiphy_2ph_combo_mode_reg)[MAX_SETTINGS_PER_LANE]; + struct csiphy_reg_t (*csiphy_3ph_reg)[MAX_SETTINGS_PER_LANE]; + struct csiphy_reg_t (*csiphy_2ph_3ph_mode_reg)[MAX_SETTINGS_PER_LANE]; + enum cam_vote_level (*getclockvoting)(struct csiphy_device *phy_dev); + struct data_rate_settings_t *data_rates_settings_table; +}; + +/** + * cam_csiphy_param: Provides cmdbuffer structre + * @lane_mask : Lane mask details + * @lane_assign : Lane sensor will be using + * @csiphy_3phase : Mentions DPHY or CPHY + * @combo_mode : Info regarding combo_mode is enable / disable + * @lane_cnt : Total number of lanes + * @reserved + * @3phase : Details whether 3Phase / 2Phase operation + * @settle_time : Settling time in ms + * @settle_time_combo_sensor : Settling time in ms + * @data_rate : Data rate in mbps + * @data_rate_combo_sensor: data rate of combo sensor + * in the the same phy + * + */ +struct cam_csiphy_param { + uint16_t lane_mask; + uint16_t lane_assign; + uint8_t csiphy_3phase; + uint8_t combo_mode; + uint8_t lane_cnt; + uint8_t secure_mode[CSIPHY_MAX_INSTANCES]; + uint64_t settle_time; + uint64_t settle_time_combo_sensor; + uint64_t data_rate; + uint64_t data_rate_combo_sensor; +}; + +/** + * struct csiphy_device + * @device_name: Device name + * @pdev: Platform device + * @irq: Interrupt structure + * @base: Base address + * @hw_version: Hardware Version + * @csiphy_state: CSIPhy state + * @ctrl_reg: CSIPhy control registers + * @num_clk: Number of clocks + * @csiphy_max_clk: Max timer clock rate + * @num_vreg: Number of regulators + * @csiphy_clk: Clock structure + * @csiphy_clk_info: Clock information structure + * @csiphy_vreg: Regulator structure + * @csiphy_reg_ptr: Regulator structure + * @csiphy_3p_clk_info: 3Phase clock information + * @csiphy_3p_clk: 3Phase clocks structure + * @csi_3phase: Is it a 3Phase mode + * @ref_count: Reference count + * @clk_lane: Clock lane + * @acquire_count: Acquire device count + * @start_dev_count: Start count + * @is_acquired_dev_combo_mode: Flag that mentions whether already acquired + * device is for combo mode + * @soc_info: SOC information + * @cpas_handle: CPAS handle + * @config_count: Config reg count + * @csiphy_cpas_cp_reg_mask: CP reg mask for phy instance + */ +struct csiphy_device { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct mutex mutex; + uint32_t hw_version; + enum cam_csiphy_state csiphy_state; + struct csiphy_ctrl_t *ctrl_reg; + uint32_t csiphy_max_clk; + struct msm_cam_clk_info csiphy_3p_clk_info[2]; + struct clk *csiphy_3p_clk[2]; + unsigned char csi_3phase; + int32_t ref_count; + uint16_t lane_mask[MAX_CSIPHY]; + uint8_t is_csiphy_3phase_hw; + uint8_t is_divisor_32_comp; + uint8_t num_irq_registers; + struct cam_subdev v4l2_dev_str; + struct cam_csiphy_param csiphy_info; + struct intf_params bridge_intf; + uint32_t clk_lane; + uint32_t acquire_count; + uint32_t start_dev_count; + uint32_t is_acquired_dev_combo_mode; + struct cam_hw_soc_info soc_info; + uint32_t cpas_handle; + uint32_t config_count; + uint64_t csiphy_cpas_cp_reg_mask[CSIPHY_MAX_INSTANCES]; +}; + +#endif /* _CAM_CSIPHY_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..c5a8033aaffbd5236d027386b17a91703bd661f7 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_csiphy_soc.h" +#include "cam_csiphy_core.h" +#include "include/cam_csiphy_1_1_hwreg.h" +#include "include/cam_csiphy_1_0_hwreg.h" +#include "include/cam_csiphy_1_2_hwreg.h" +#include "include/cam_csiphy_1_2_1_hwreg.h" +#include "include/cam_csiphy_2_0_hwreg.h" + +#define CSIPHY_DIVISOR_16 16 +#define CSIPHY_DIVISOR_32 32 +#define CSIPHY_DIVISOR_8 8 +#define BYTES_PER_REGISTER 4 +#define NUM_REGISTER_PER_LINE 4 +#define REG_OFFSET(__start, __i) ((__start) + ((__i) * BYTES_PER_REGISTER)) + +static int cam_io_phy_dump(void __iomem *base_addr, + uint32_t start_offset, int size) +{ + char line_str[128]; + char *p_str; + int i; + uint32_t data; + + CAM_INFO(CAM_CSIPHY, "addr=%pK offset=0x%x size=%d", + base_addr, start_offset, size); + + if (!base_addr || (size <= 0)) + return -EINVAL; + + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size; i++) { + if (i % NUM_REGISTER_PER_LINE == 0) { + snprintf(p_str, 12, "0x%08x: ", + REG_OFFSET(start_offset, i)); + p_str += 11; + } + data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); + snprintf(p_str, 9, "%08x ", data); + p_str += 8; + if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { + CAM_ERR(CAM_CSIPHY, "%s", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CAM_ERR(CAM_CSIPHY, "%s", line_str); + + return 0; +} + +int32_t cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0; + resource_size_t size = 0; + void __iomem *addr = NULL; + + if (!soc_info) { + rc = -EINVAL; + CAM_ERR(CAM_CSIPHY, "invalid input %d", rc); + return rc; + } + addr = soc_info->reg_map[0].mem_base; + size = resource_size(soc_info->mem_block[0]); + rc = cam_io_phy_dump(addr, 0, (size >> 2)); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "generating dump failed %d", rc); + return rc; + } + return rc; +} + +enum cam_vote_level get_clk_vote_default(struct csiphy_device *csiphy_dev) +{ + CAM_DBG(CAM_CSIPHY, "voting for SVS"); + return CAM_SVS_VOTE; +} + +enum cam_vote_level get_clk_voting_dynamic(struct csiphy_device *csiphy_dev) +{ + uint32_t cam_vote_level = 0; + uint32_t last_valid_vote = 0; + struct cam_hw_soc_info *soc_info; + uint64_t phy_data_rate = csiphy_dev->csiphy_info.data_rate; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->is_acquired_dev_combo_mode) + phy_data_rate = max(phy_data_rate, + csiphy_dev->csiphy_info.data_rate_combo_sensor); + + if (csiphy_dev->csiphy_info.csiphy_3phase) { + if (csiphy_dev->is_divisor_32_comp) + do_div(phy_data_rate, CSIPHY_DIVISOR_32); + else + do_div(phy_data_rate, CSIPHY_DIVISOR_16); + } else { + do_div(phy_data_rate, CSIPHY_DIVISOR_8); + } + + /* round off to next integer */ + phy_data_rate += 1; + + for (cam_vote_level = 0; + cam_vote_level < CAM_MAX_VOTE; cam_vote_level++) { + if (soc_info->clk_level_valid[cam_vote_level] != true) + continue; + + if (soc_info->clk_rate[cam_vote_level][0] > + phy_data_rate) { + CAM_DBG(CAM_CSIPHY, + "match detected %s : %llu:%d level : %d", + soc_info->clk_name[0], + phy_data_rate, + soc_info->clk_rate[cam_vote_level][0], + cam_vote_level); + return cam_vote_level; + } + last_valid_vote = cam_vote_level; + } + return last_valid_vote; +} + +int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info; + enum cam_vote_level vote_level = CAM_SVS_VOTE; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->ref_count++) { + CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", + csiphy_dev->ref_count); + return rc; + } + + vote_level = csiphy_dev->ctrl_reg->getclockvoting(csiphy_dev); + rc = cam_soc_util_enable_platform_resource(soc_info, true, + vote_level, ENABLE_IRQ); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "failed to enable platform resources %d", + rc); + return rc; + } + + rc = cam_soc_util_set_src_clk_rate(soc_info, + soc_info->clk_rate[0][soc_info->src_clk_idx]); + + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "csiphy_clk_set_rate failed rc: %d", rc); + goto csiphy_disable_platform_resource; + } + + cam_csiphy_reset(csiphy_dev); + + return rc; + + +csiphy_disable_platform_resource: + cam_soc_util_disable_platform_resource(soc_info, true, true); + + return rc; +} + +int32_t cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev) +{ + struct cam_hw_soc_info *soc_info; + + if (!csiphy_dev || !csiphy_dev->ref_count) { + CAM_ERR(CAM_CSIPHY, "csiphy dev NULL / ref_count ZERO"); + return 0; + } + soc_info = &csiphy_dev->soc_info; + + if (--csiphy_dev->ref_count) { + CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", + csiphy_dev->ref_count); + return 0; + } + + cam_csiphy_reset(csiphy_dev); + + cam_soc_util_disable_platform_resource(soc_info, true, true); + + return 0; +} + +int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, + struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0, i = 0; + uint32_t clk_cnt = 0; + char *csi_3p_clk_name = "csi_phy_3p_clk"; + char *csi_3p_clk_src_name = "csiphy_3p_clk_src"; + struct cam_hw_soc_info *soc_info; + + csiphy_dev->is_csiphy_3phase_hw = 0; + soc_info = &csiphy_dev->soc_info; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "parsing common soc dt(rc %d)", rc); + return rc; + } + + csiphy_dev->is_csiphy_3phase_hw = 0; + + if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.0")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = + csiphy_3ph_v1_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_1_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_1_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->hw_version = CSIPHY_VERSION_V10; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.1")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_1_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = + csiphy_3ph_v1_1_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_1; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_1; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_1; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_1; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->hw_version = CSIPHY_VERSION_V11; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = true; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.1")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_1_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_1_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2_1; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2_1; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2_1; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2_1; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_voting_dynamic; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = true; + csiphy_dev->hw_version = CSIPHY_VERSION_V121; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2_1; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v1.2.2")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v1_2_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v1_2_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_common_reg = + csiphy_common_reg_1_2; + csiphy_dev->ctrl_reg->csiphy_reset_reg = + csiphy_reset_reg_1_2; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v1_2; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->hw_version = CSIPHY_VERSION_V12; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = + &data_rate_delta_table_1_2; + } else if (of_device_is_compatible(soc_info->dev->of_node, + "qcom,csiphy-v2.0")) { + csiphy_dev->ctrl_reg->csiphy_2ph_reg = csiphy_2ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_combo_mode_reg = + csiphy_2ph_v2_0_combo_mode_reg; + csiphy_dev->ctrl_reg->csiphy_3ph_reg = csiphy_3ph_v2_0_reg; + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg = NULL; + csiphy_dev->ctrl_reg->csiphy_irq_reg = csiphy_irq_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_common_reg = csiphy_common_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reset_reg = csiphy_reset_reg_2_0; + csiphy_dev->ctrl_reg->csiphy_reg = csiphy_v2_0; + csiphy_dev->ctrl_reg->getclockvoting = get_clk_vote_default; + csiphy_dev->hw_version = CSIPHY_VERSION_V20; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->is_divisor_32_comp = false; + csiphy_dev->clk_lane = 0; + csiphy_dev->ctrl_reg->data_rates_settings_table = NULL; + } else { + CAM_ERR(CAM_CSIPHY, "invalid hw version : 0x%x", + csiphy_dev->hw_version); + rc = -EINVAL; + return rc; + } + + if (soc_info->num_clk > CSIPHY_NUM_CLK_MAX) { + CAM_ERR(CAM_CSIPHY, "invalid clk count=%d, max is %d", + soc_info->num_clk, CSIPHY_NUM_CLK_MAX); + return -EINVAL; + } + for (i = 0; i < soc_info->num_clk; i++) { + if (!strcmp(soc_info->clk_name[i], + csi_3p_clk_src_name)) { + csiphy_dev->csiphy_3p_clk_info[0].clk_name = + soc_info->clk_name[i]; + csiphy_dev->csiphy_3p_clk_info[0].clk_rate = + soc_info->clk_rate[0][i]; + csiphy_dev->csiphy_3p_clk[0] = + soc_info->clk[i]; + continue; + } else if (!strcmp(soc_info->clk_name[i], + csi_3p_clk_name)) { + csiphy_dev->csiphy_3p_clk_info[1].clk_name = + soc_info->clk_name[i]; + csiphy_dev->csiphy_3p_clk_info[1].clk_rate = + soc_info->clk_rate[0][i]; + csiphy_dev->csiphy_3p_clk[1] = + soc_info->clk[i]; + continue; + } + + CAM_DBG(CAM_CSIPHY, "clk_rate[%d] = %d", clk_cnt, + soc_info->clk_rate[0][clk_cnt]); + clk_cnt++; + } + + csiphy_dev->csiphy_max_clk = + soc_info->clk_rate[0][soc_info->src_clk_idx]; + + rc = cam_soc_util_request_platform_resource(&csiphy_dev->soc_info, + cam_csiphy_irq, csiphy_dev); + + return rc; +} + +int32_t cam_csiphy_soc_release(struct csiphy_device *csiphy_dev) +{ + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "csiphy dev NULL"); + return 0; + } + + cam_soc_util_release_platform_resource(&csiphy_dev->soc_info); + + return 0; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..c02b9556add4dfc789284bcb7398c8004d2407df --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_SOC_H_ +#define _CAM_CSIPHY_SOC_H_ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/irqreturn.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include "cam_csiphy_dev.h" +#include "cam_csiphy_core.h" + +#undef CDBG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) + +#define CSI_3PHASE_HW 1 +#define CSIPHY_VERSION_V35 0x35 +#define CSIPHY_VERSION_V10 0x10 +#define CSIPHY_VERSION_V11 0x11 +#define CSIPHY_VERSION_V12 0x12 +#define CSIPHY_VERSION_V121 0x121 +#define CSIPHY_VERSION_V20 0x20 + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API release SOC related parameters + */ +int cam_csiphy_soc_release(struct csiphy_device *csiphy_dev); + +/** + * @pdev: Platform device + * @csiphy_dev: CSIPhy device structure + * + * This API parses csiphy device tree information + */ +int cam_csiphy_parse_dt_info(struct platform_device *pdev, + struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API enables SOC related parameters + */ +int cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev); + +/** + * @csiphy_dev: CSIPhy device structure + * + * This API disables SOC related parameters + */ +int cam_csiphy_disable_hw(struct csiphy_device *csiphy_dev); + +/** + * @soc_info: Soc info of cam hw driver module + * + * This API dumps memory for the entire mapped region + * (needs to be macro enabled before use) + */ +int cam_csiphy_mem_dmp(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_CSIPHY_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..e910162858b326013c6444c074e64d9a08f82d80 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h @@ -0,0 +1,348 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_0_HWREG_H_ +#define _CAM_CSIPHY_1_0_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_0 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 5, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 14, + .csiphy_3ph_config_array_size = 19, +}; + +struct csiphy_reg_t csiphy_common_reg_1_0[] = { + {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_0[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_0[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_2ph_v1_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x0A, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x0A, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t csiphy_3ph_v1_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_3ph_v1_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x63, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x12, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x51, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_1_0_HWREG_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..30b61067a792a024a4fbce39d334ca247d1dfbf8 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_1_hwreg.h @@ -0,0 +1,499 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_1_HWREG_H_ +#define _CAM_CSIPHY_1_1_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_1 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 5, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 14, + .csiphy_3ph_config_array_size = 43, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_1[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_1[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_1[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x90, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x0E, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x31, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0144, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x24, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0344, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x24, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0544, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x24, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_3ph_v1_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0144, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x015C, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09AC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0344, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x035C, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0544, 0xB6, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0x5F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x8E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x59, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x055C, 0x48, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BAC, 0x55, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x2B, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_D5_0_HWREG_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..32fbf47eabd9700b2b78b8eb7f32d7e4b1f5f6c4 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_1_hwreg.h @@ -0,0 +1,481 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_1_HWREG_H_ +#define _CAM_CSIPHY_1_2_1_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_2_1 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 20, + .csiphy_3ph_config_array_size = 34, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2_1[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x081C, 0x52, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x02, 0x00, CSIPHY_2PH_REGS}, + {0x0800, 0x0E, 0x00, CSIPHY_3PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_2_1[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_2_1[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0600, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v1_2_1_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0900, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0908, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0904, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C80, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C88, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C84, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070c, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C00, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C08, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0C04, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x07, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x060C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_2_1_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09C8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xBF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xAC, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x07, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC0, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC4, 0x7D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BC8, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct data_rate_settings_t data_rate_delta_table_1_2_1 = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 12, + .csiphy_data_rate_regs = { + {0x15C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x66, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0xAD, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 24, + .csiphy_data_rate_regs = { + {0x15C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x35C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x55C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x9B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x13C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x33C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x53C, 0x10, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x140, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x340, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x540, 0x81, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x16C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x36C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x56C, 0x1D, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; + +#endif /* _CAM_CSIPHY_1_2_1_HWREG_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..3bed231e0246eb902cbd0747818f67dc49927b94 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -0,0 +1,430 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_1_2_HWREG_H_ +#define _CAM_CSIPHY_1_2_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v1_2 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 5, + .csiphy_2ph_config_array_size = 18, + .csiphy_3ph_config_array_size = 33, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_1_2[] = { + {0x0814, 0xd5, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x5A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0824, 0x72, 0x00, CSIPHY_2PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_1_2[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_1_2[] = { + {0x082c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xFB, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xEF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct +csiphy_reg_t csiphy_2ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +struct csiphy_reg_t +csiphy_2ph_v1_2_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x005C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, + { + {0x0230, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x0D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DNP_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0624, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0000, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + }, +}; + +struct +csiphy_reg_t csiphy_3ph_v1_2_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0990, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0994, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0998, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x098C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0150, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0188, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x018C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0190, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0984, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x09B4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0350, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0388, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x038C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0390, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0A84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0AB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x46, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B90, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B94, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B98, 0x1A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B8C, 0xAF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0xA0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x25, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0550, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0588, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x058C, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0590, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x33, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05DC, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB0, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0B84, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0BB4, 0x03, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct data_rate_settings_t data_rate_delta_table_1_2 = { + .num_data_rate_settings = 3, + .data_rate_settings = { + { + /* (2.5 * 10**3 * 2.28) rounded value*/ + .bandwidth = 5700000000, + .data_rate_reg_array_size = 3, + .csiphy_data_rate_regs = { + {0x144, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0x22, 0x00, CSIPHY_DEFAULT_PARAMS}, + } + }, + { + /* (3.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 7980000000, + .data_rate_reg_array_size = 15, + .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + }, + { + /* (4.5 * 10**3 * 2.28) rounded value */ + .bandwidth = 10260000000, + .data_rate_reg_array_size = 15, + .csiphy_data_rate_regs = { + {0x9B4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xAB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xBB4, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x144, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x344, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x544, 0xB2, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x980, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xA80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0xB80, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x10C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x30C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x50C, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + } + } +}; +#endif /* _CAM_CSIPHY_1_2_HWREG_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h new file mode 100644 index 0000000000000000000000000000000000000000..cbd0dc582b3280586e58a49d7f83b777036af19c --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -0,0 +1,289 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CSIPHY_2_0_HWREG_H_ +#define _CAM_CSIPHY_2_0_HWREG_H_ + +#include "../cam_csiphy_dev.h" + +struct csiphy_reg_parms_t csiphy_v2_0 = { + .mipi_csiphy_interrupt_status0_addr = 0x8B0, + .mipi_csiphy_interrupt_clear0_addr = 0x858, + .mipi_csiphy_glbl_irq_cmd_addr = 0x828, + .csiphy_common_array_size = 6, + .csiphy_reset_array_size = 3, + .csiphy_2ph_config_array_size = 15, + .csiphy_3ph_config_array_size = 17, + .csiphy_2ph_clock_lane = 0x1, + .csiphy_2ph_combo_ck_ln = 0x10, +}; + +struct csiphy_reg_t csiphy_common_reg_2_0[] = { + {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, + {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, + {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, +}; + +struct csiphy_reg_t csiphy_reset_reg_2_0[] = { + {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, + {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_irq_reg_2_0[] = { + {0x082c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0xff, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0xfb, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0x7f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0840, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0844, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0848, 0xef, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x084c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0850, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0854, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + +struct csiphy_reg_t csiphy_2ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t + csiphy_2ph_v2_0_combo_mode_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xD7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xFF, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x0E, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xC0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +struct csiphy_reg_t csiphy_3ph_v2_0_reg[MAX_LANES][MAX_SETTINGS_PER_LANE] = { + { + {0x015C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0104, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x010C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0108, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0114, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0168, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x016C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0118, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x011C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0120, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0124, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0128, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x012C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0144, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0160, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x01CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0164, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x035C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0304, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x030C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0308, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0314, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0368, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x036C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0318, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x031C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0320, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0324, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0328, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x032C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0344, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0360, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x03CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0364, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x055C, 0x23, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0504, 0x06, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x050C, 0x12, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0508, 0x00, 0x00, CSIPHY_SETTLE_CNT_HIGHER_BYTE}, + {0x0514, 0x20, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0568, 0x70, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x056C, 0x17, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0518, 0x3e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x051C, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0520, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0524, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0528, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x052C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0544, 0x32, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0560, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x05CC, 0x41, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0564, 0x40, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + +#endif /* _CAM_CSIPHY_2_0_HWREG_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7a676c1135a05291b3a6915f75de1f33a5a192f1 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom_dev.o cam_eeprom_core.o cam_eeprom_soc.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c new file mode 100755 index 0000000000000000000000000000000000000000..ae2035115c89e19481778c8cb3c4b1d5ba965c11 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -0,0 +1,1639 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/crc32.h> +#include <media/cam_sensor.h> + +#include "cam_eeprom_core.h" +#include "cam_eeprom_soc.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" +#define USER_MAT 0 +#define INF_MAT0 1 +#define INF_MAT1 2 +#define INF_MAT2 4 +#define CMD_IO_ADR_ACCESS 0xC000 // IO Write Access +#define CMD_IO_DAT_ACCESS 0xD000 // IO Read Access + +//******************************************************************************** +// Function Name : IOWrite32A +//******************************************************************************** +int EEPROM_RamWrite32A(struct cam_eeprom_ctrl_t *e_ctrl,uint32_t addr, uint32_t data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + struct cam_sensor_i2c_reg_array i2c_write_setting = { + .reg_addr = addr, + .reg_data = data, + .delay = 0x00, + .data_mask = 0x00, + }; + struct cam_sensor_i2c_reg_setting i2c_write = { + .reg_setting = &i2c_write_setting, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_DWORD, + .delay = 0x00, + }; + + if (e_ctrl == NULL) { + CAM_ERR(CAM_EEPROM, "Invalid Args"); + return -EINVAL; + } + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_write(&(e_ctrl->io_master_info), &i2c_write); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "write 0x%04x failed, retry:%d", addr, i+1); + } else { + return rc; + } + } + return rc; +} + +int EEPROM_RamRead32A(struct cam_eeprom_ctrl_t *e_ctrl,uint32_t addr, uint32_t* data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + if (e_ctrl == NULL) { + CAM_ERR(CAM_EEPROM, "Invalid Args"); + return -EINVAL; + } + for(i = 0; i < retry; i++) { + rc = camera_io_dev_read(&(e_ctrl->io_master_info), (uint32_t)addr, (uint32_t *)data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_DWORD); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "read 0x%04x failed, retry:%d", addr, i+1); + } else { + return rc; + } + } + return rc; +} + +void EEPROM_IORead32A(struct cam_eeprom_ctrl_t *e_ctrl, uint32_t IOadrs, uint32_t *IOdata ) +{ + EEPROM_RamWrite32A(e_ctrl, CMD_IO_ADR_ACCESS, IOadrs ) ; + EEPROM_RamRead32A (e_ctrl, CMD_IO_DAT_ACCESS, IOdata ) ; +} + +//******************************************************************************** +// Function Name : IOWrite32A +//******************************************************************************** +void EEPROM_IOWrite32A(struct cam_eeprom_ctrl_t *e_ctrl, uint32_t IOadrs, uint32_t IOdata ) +{ + EEPROM_RamWrite32A(e_ctrl, CMD_IO_ADR_ACCESS, IOadrs ) ; + EEPROM_RamWrite32A(e_ctrl, CMD_IO_DAT_ACCESS, IOdata ) ; +} + +uint8_t EEPROM_FlashMultiRead(struct cam_eeprom_ctrl_t *e_ctrl, uint8_t SelMat, uint32_t UlAddress, uint32_t *PulData , uint8_t UcLength ) +{ + uint8_t i ; + + if( SelMat != USER_MAT && SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; + + if( UlAddress > 0x000003FFF ) return 9; + + EEPROM_IOWrite32A(e_ctrl, 0xE07008 , 0x00000000 | (uint32_t)(UcLength-1) ); + EEPROM_IOWrite32A(e_ctrl, 0xE0700C , ((uint32_t)SelMat << 16) | ( UlAddress & 0x00003FFF ) ); + + EEPROM_IOWrite32A(e_ctrl, 0xE0701C , 0x00000000); + EEPROM_IOWrite32A(e_ctrl, 0xE07010 , 0x00000001 ); + for( i=0 ; i < UcLength ; i++ ){ + EEPROM_IORead32A(e_ctrl, 0xE07000 , &PulData[i] ) ; + } + + EEPROM_IOWrite32A(e_ctrl, 0xE0701C , 0x00000002); + return( 0 ) ; +} + +#define MAX_READ_SIZE 0x7FFFF + +/** + * cam_eeprom_read_memory() - read map data into buffer + * @e_ctrl: eeprom control struct + * @block: block to be read + * + * This function iterates through blocks stored in block->map, reads each + * region and concatenate them into the pre-allocated block->mapdata + */ +static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_eeprom_memory_block_t *block) +{ + int rc = 0; + int j; + struct cam_sensor_i2c_reg_setting i2c_reg_settings = {0}; + struct cam_sensor_i2c_reg_array i2c_reg_array = {0}; + struct cam_eeprom_memory_map_t *emap = block->map; + struct cam_eeprom_soc_private *eb_info = NULL; + uint8_t *memptr = block->mapdata; + int i,m,size,read_size; + uint32_t data[32]={0}; + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "e_ctrl is NULL"); + return -EINVAL; + } + + eb_info = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + + for (j = 0; j < block->num_map; j++) { + CAM_DBG(CAM_EEPROM, "slave-addr = 0x%X", emap[j].saddr); + if (emap[j].saddr) { + eb_info->i2c_info.slave_addr = emap[j].saddr; + rc = cam_eeprom_update_i2c_info(e_ctrl, + &eb_info->i2c_info); + if (rc) { + CAM_ERR(CAM_EEPROM, + "failed: to update i2c info rc %d", + rc); + return rc; + } + } + + if (emap[j].page.valid_size) { + i2c_reg_settings.addr_type = emap[j].page.addr_type; + i2c_reg_settings.data_type = emap[j].page.data_type; + i2c_reg_settings.size = 1; + i2c_reg_array.reg_addr = emap[j].page.addr; + i2c_reg_array.reg_data = emap[j].page.data; + i2c_reg_array.delay = emap[j].page.delay; + i2c_reg_settings.reg_setting = &i2c_reg_array; + rc = camera_io_dev_write(&e_ctrl->io_master_info, + &i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_EEPROM, "page write failed rc %d", + rc); + return rc; + } + } + + if (emap[j].pageen.valid_size) { + i2c_reg_settings.addr_type = emap[j].pageen.addr_type; + i2c_reg_settings.data_type = emap[j].pageen.data_type; + i2c_reg_settings.size = 1; + i2c_reg_array.reg_addr = emap[j].pageen.addr; + i2c_reg_array.reg_data = emap[j].pageen.data; + i2c_reg_array.delay = emap[j].pageen.delay; + i2c_reg_settings.reg_setting = &i2c_reg_array; + rc = camera_io_dev_write(&e_ctrl->io_master_info, + &i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_EEPROM, "page enable failed rc %d", + rc); + return rc; + } + } + + if (emap[j].poll.valid_size) { + rc = camera_io_dev_poll(&e_ctrl->io_master_info, + emap[j].poll.addr, emap[j].poll.data, + 0, emap[j].poll.addr_type, + emap[j].poll.data_type, + emap[j].poll.delay); + if (rc) { + CAM_ERR(CAM_EEPROM, "poll failed rc %d", + rc); + return rc; + } + } + + if (e_ctrl->io_master_info.cci_client->sid==0x24) { + if(j>0) + size=emap[j-1].mem.valid_size; + else + size=0; + for(i=0;i<((emap[j].mem.valid_size/4)/32+1);i++){ + if((i==(emap[j].mem.valid_size/4)/32)&&(((emap[j].mem.valid_size/4)%32)!=0)) + read_size=((emap[j].mem.valid_size/4)%32); + else if((i==(emap[j].mem.valid_size/4)/32)&&(((emap[j].mem.valid_size/4)%32)==0)) + break; + else + read_size=32; + rc=EEPROM_FlashMultiRead(e_ctrl,USER_MAT,emap[j].mem.addr+i*32,data,read_size); + if(rc!=0){ + CAM_ERR(CAM_EEPROM, "read failed rc=%d ",rc); + return rc; + }else{ + for(m=0;m<read_size;m++){ + memptr[size+i*4*32+m*4]=(data[m]&0xff); + memptr[size+i*4*32+m*4+1]=((data[m]>>8)&0xff); + memptr[size+i*4*32+m*4+2]=((data[m]>>16)&0xff); + memptr[size+i*4*32+m*4+3]=(data[m]>>24); + } + } + } + }else{ + if (emap[j].mem.valid_size) { + rc = camera_io_dev_read_seq(&e_ctrl->io_master_info, + emap[j].mem.addr, memptr, + emap[j].mem.addr_type, + emap[j].mem.data_type, + emap[j].mem.valid_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "read failed rc %d",rc); + return rc; + } + memptr += emap[j].mem.valid_size; + } + } + + if (emap[j].pageen.valid_size) { + i2c_reg_settings.addr_type = emap[j].pageen.addr_type; + i2c_reg_settings.data_type = emap[j].pageen.data_type; + i2c_reg_settings.size = 1; + i2c_reg_array.reg_addr = emap[j].pageen.addr; + i2c_reg_array.reg_data = 0; + i2c_reg_array.delay = emap[j].pageen.delay; + i2c_reg_settings.reg_setting = &i2c_reg_array; + rc = camera_io_dev_write(&e_ctrl->io_master_info, + &i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_EEPROM, + "page disable failed rc %d", + rc); + return rc; + } + } + } + return rc; +} + +/** + * cam_eeprom_power_up - Power up eeprom hardware + * @e_ctrl: ctrl structure + * @power_info: power up/down info for eeprom + * + * Returns success or failure + */ +static int cam_eeprom_power_up(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_sensor_power_ctrl_t *power_info) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info = + &e_ctrl->soc_info; + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params( + &e_ctrl->soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_EEPROM, + "failed to fill power up vreg params rc:%d", rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + &e_ctrl->soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_EEPROM, + "failed to fill power down vreg params rc:%d", rc); + return rc; + } + + power_info->dev = soc_info->dev; + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed in eeprom power up rc %d", rc); + return rc; + } + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) { + rc = camera_io_init(&(e_ctrl->io_master_info)); + if (rc) { + CAM_ERR(CAM_EEPROM, "cci_init failed"); + return -EINVAL; + } + } + return rc; +} + +/** + * cam_eeprom_power_down - Power down eeprom hardware + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int cam_eeprom_power_down(struct cam_eeprom_ctrl_t *e_ctrl) +{ + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info; + struct cam_eeprom_soc_private *soc_private; + int rc = 0; + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "failed: e_ctrl %pK", e_ctrl); + return -EINVAL; + } + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + soc_info = &e_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_EEPROM, "failed: power_info %pK", power_info); + return -EINVAL; + } + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "power down the core is failed:%d", rc); + return rc; + } + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) + camera_io_release(&(e_ctrl->io_master_info)); + + return rc; +} + +/** + * cam_eeprom_match_id - match eeprom id + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int cam_eeprom_match_id(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct camera_io_master *client = &e_ctrl->io_master_info; + uint8_t id[2]; + + rc = cam_spi_query_id(client, 0, CAMERA_SENSOR_I2C_TYPE_WORD, + &id[0], 2); + if (rc) + return rc; + CAM_DBG(CAM_EEPROM, "read 0x%x 0x%x, check 0x%x 0x%x", + id[0], id[1], client->spi_client->mfr_id0, + client->spi_client->device_id0); + if (id[0] != client->spi_client->mfr_id0 + || id[1] != client->spi_client->device_id0) + return -ENODEV; + return 0; +} + +/** + * cam_eeprom_parse_read_memory_map - Parse memory map + * @of_node: device node + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, + struct cam_eeprom_ctrl_t *e_ctrl) +{ + int32_t rc = 0; + struct cam_eeprom_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "failed: e_ctrl is NULL"); + return -EINVAL; + } + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + rc = cam_eeprom_parse_dt_memory_map(of_node, &e_ctrl->cal_data); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: eeprom dt parse rc %d", rc); + return rc; + } + rc = cam_eeprom_power_up(e_ctrl, power_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: eeprom power up rc %d", rc); + goto data_mem_free; + } + + e_ctrl->cam_eeprom_state = CAM_EEPROM_CONFIG; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) { + rc = cam_eeprom_match_id(e_ctrl); + if (rc) { + CAM_DBG(CAM_EEPROM, "eeprom not matching %d", rc); + goto power_down; + } + } + rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); + if (rc) { + CAM_ERR(CAM_EEPROM, "read_eeprom_memory failed"); + goto power_down; + } + + rc = cam_eeprom_power_down(e_ctrl); + if (rc) + CAM_ERR(CAM_EEPROM, "failed: eeprom power down rc %d", rc); + + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + return rc; +power_down: + cam_eeprom_power_down(e_ctrl); +data_mem_free: + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + return rc; +} + +/** + * cam_eeprom_get_dev_handle - get device handle + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, + void *arg) +{ + struct cam_sensor_acquire_dev eeprom_acq_dev; + struct cam_create_dev_hdl bridge_params; + struct cam_control *cmd = (struct cam_control *)arg; + + if (e_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_EEPROM, "Device is already acquired"); + return -EFAULT; + } + if (copy_from_user(&eeprom_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(eeprom_acq_dev))) { + CAM_ERR(CAM_EEPROM, + "EEPROM:ACQUIRE_DEV: copy from user failed"); + return -EFAULT; + } + + bridge_params.session_hdl = eeprom_acq_dev.session_handle; + bridge_params.ops = &e_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = e_ctrl; + + eeprom_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; + e_ctrl->bridge_intf.session_hdl = eeprom_acq_dev.session_handle; + + CAM_DBG(CAM_EEPROM, "Device Handle: %d", eeprom_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &eeprom_acq_dev, sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_EEPROM, "EEPROM:ACQUIRE_DEV: copy to user failed"); + return -EFAULT; + } + return 0; +} + +/** + * cam_eeprom_update_slaveInfo - Update slave info + * @e_ctrl: ctrl structure + * @cmd_buf: command buffer + * + * Returns success or failure + */ +static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl, + void *cmd_buf) +{ + int32_t rc = 0; + struct cam_eeprom_soc_private *soc_private; + struct cam_cmd_i2c_info *cmd_i2c_info = NULL; + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + cmd_i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + soc_private->i2c_info.slave_addr = cmd_i2c_info->slave_addr; + soc_private->i2c_info.i2c_freq_mode = cmd_i2c_info->i2c_freq_mode; + + rc = cam_eeprom_update_i2c_info(e_ctrl, + &soc_private->i2c_info); + CAM_DBG(CAM_EEPROM, "Slave addr: 0x%x Freq Mode: %d", + soc_private->i2c_info.slave_addr, + soc_private->i2c_info.i2c_freq_mode); + + return rc; +} + +/** + * cam_eeprom_parse_memory_map - Parse memory map info + * @data: memory block data + * @cmd_buf: command buffer + * @cmd_length: command buffer length + * @num_map: memory map size + * @cmd_length_bytes: command length processed in this function + * + * Returns success or failure + */ +static int32_t cam_eeprom_parse_memory_map( + struct cam_eeprom_memory_block_t *data, + void *cmd_buf, int cmd_length, uint32_t *cmd_length_bytes, + int *num_map, size_t remain_buf_len) +{ + int32_t rc = 0; + int32_t cnt = 0; + int32_t processed_size = 0; + uint8_t generic_op_code; + struct cam_eeprom_memory_map_t *map = data->map; + struct common_header *cmm_hdr = + (struct common_header *)cmd_buf; + uint16_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_random_wr *i2c_random_wr = NULL; + struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL; + struct cam_cmd_conditional_wait *i2c_poll = NULL; + struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL; + size_t validate_size = 0; + + generic_op_code = cmm_hdr->fifth_byte; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR) + validate_size = sizeof(struct cam_cmd_i2c_random_wr); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD) + validate_size = sizeof(struct cam_cmd_i2c_continuous_rd); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf_len < validate_size || + *num_map >= (MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE)) { + CAM_ERR(CAM_EEPROM, "not enough buffer"); + return -EINVAL; + } + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: + i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if (i2c_random_wr->header.count == 0 || + i2c_random_wr->header.count >= MSM_EEPROM_MAX_MEM_MAP_CNT || + (size_t)*num_map >= ((MSM_EEPROM_MAX_MEM_MAP_CNT * + MSM_EEPROM_MEMORY_MAP_MAX_SIZE) - + i2c_random_wr->header.count)) { + CAM_ERR(CAM_EEPROM, "OOB Error"); + return -EINVAL; + } + cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) + + ((i2c_random_wr->header.count - 1) * + sizeof(struct i2c_random_wr_payload)); + + if (cmd_length_in_bytes > remain_buf_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer remaining"); + return -EINVAL; + } + for (cnt = 0; cnt < (i2c_random_wr->header.count); + cnt++) { + map[*num_map + cnt].page.addr = + i2c_random_wr->random_wr_payload[cnt].reg_addr; + map[*num_map + cnt].page.addr_type = + i2c_random_wr->header.addr_type; + map[*num_map + cnt].page.data = + i2c_random_wr->random_wr_payload[cnt].reg_data; + map[*num_map + cnt].page.data_type = + i2c_random_wr->header.data_type; + map[*num_map + cnt].page.valid_size = 1; + } + + *num_map += (i2c_random_wr->header.count - 1); + cmd_buf += cmd_length_in_bytes / sizeof(int32_t); + processed_size += + cmd_length_in_bytes; + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: + i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf; + cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); + + if (i2c_cont_rd->header.count >= U32_MAX - data->num_data) { + CAM_ERR(CAM_EEPROM, + "int overflow on eeprom memory block"); + return -EINVAL; + } + map[*num_map].mem.addr = i2c_cont_rd->reg_addr; + map[*num_map].mem.addr_type = i2c_cont_rd->header.addr_type; + map[*num_map].mem.data_type = i2c_cont_rd->header.data_type; + map[*num_map].mem.valid_size = + i2c_cont_rd->header.count; + cmd_buf += cmd_length_in_bytes / sizeof(int32_t); + processed_size += + cmd_length_in_bytes; + data->num_data += map[*num_map].mem.valid_size; + break; + case CAMERA_SENSOR_CMD_TYPE_WAIT: + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND || + generic_op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) { + i2c_uncond_wait = + (struct cam_cmd_unconditional_wait *)cmd_buf; + cmd_length_in_bytes = + sizeof(struct cam_cmd_unconditional_wait); + + if (*num_map < 1) { + CAM_ERR(CAM_EEPROM, + "invalid map number, num_map=%d", + *num_map); + return -EINVAL; + } + + /* + * Though delay is added all of them, but delay will + * be applicable to only one of them as only one of + * them will have valid_size set to >= 1. + */ + map[*num_map - 1].mem.delay = i2c_uncond_wait->delay; + map[*num_map - 1].page.delay = i2c_uncond_wait->delay; + map[*num_map - 1].pageen.delay = i2c_uncond_wait->delay; + } else if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_COND) { + i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf; + cmd_length_in_bytes = + sizeof(struct cam_cmd_conditional_wait); + + map[*num_map].poll.addr = i2c_poll->reg_addr; + map[*num_map].poll.addr_type = i2c_poll->addr_type; + map[*num_map].poll.data = i2c_poll->reg_data; + map[*num_map].poll.data_type = i2c_poll->data_type; + map[*num_map].poll.delay = i2c_poll->timeout; + map[*num_map].poll.valid_size = 1; + } + cmd_buf += cmd_length_in_bytes / sizeof(int32_t); + processed_size += + cmd_length_in_bytes; + break; + default: + break; + } + + *cmd_length_bytes = processed_size; + return rc; +} + +static struct i2c_settings_list* + cam_eeprom_get_i2c_ptr(struct i2c_settings_array *i2c_reg_settings, + uint32_t size) +{ + struct i2c_settings_list *tmp; + + tmp = kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL); + + if (tmp != NULL) + list_add_tail(&(tmp->list), + &(i2c_reg_settings->list_head)); + else + return NULL; + + tmp->seq_settings.reg_data = + kcalloc(size, sizeof(uint8_t), GFP_KERNEL); + if (tmp->seq_settings.reg_data == NULL) { + list_del(&(tmp->list)); + kfree(tmp); + tmp = NULL; + return NULL; + } + tmp->seq_settings.size = size; + + return tmp; +} + +static int32_t cam_eeprom_handle_continuous_write( + struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt = 0; + + + CAM_DBG(CAM_EEPROM, "Total Size: %d", + cam_cmd_i2c_continuous_wr->header.count); + + i2c_list = cam_eeprom_get_i2c_ptr(i2c_reg_settings, + cam_cmd_i2c_continuous_wr->header.count); + if (i2c_list == NULL || + i2c_list->seq_settings.reg_data == NULL) { + CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); + return -ENOMEM; + } + + *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + sizeof(struct cam_cmd_read) * + (cam_cmd_i2c_continuous_wr->header.count)); + if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST; + else if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_SEQ; + else { + rc = -EINVAL; + goto deallocate_i2c_list; + } + + i2c_list->seq_settings.addr_type = + cam_cmd_i2c_continuous_wr->header.addr_type; + + CAM_ERR(CAM_EEPROM, "Write Address: 0x%x", + cam_cmd_i2c_continuous_wr->reg_addr); + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM; + e_ctrl->eebin_info.start_address = + cam_cmd_i2c_continuous_wr->reg_addr; + e_ctrl->eebin_info.size = + cam_cmd_i2c_continuous_wr->header.count; + CAM_DBG(CAM_EEPROM, "Header Count: %d", + cam_cmd_i2c_continuous_wr->header.count); + e_ctrl->eebin_info.is_valid = 1; + + i2c_list->seq_settings.reg_addr = + cam_cmd_i2c_continuous_wr->reg_addr; + } else + CAM_ERR(CAM_EEPROM, "Burst Mode Not Supported\n"); + + (*offset) += cnt; + *list = &(i2c_list->list); + return rc; +deallocate_i2c_list: + kfree(i2c_list); + return rc; +} + +static int32_t cam_eeprom_handle_delay( + uint32_t **cmd_buf, + uint16_t generic_op_code, + struct i2c_settings_array *i2c_reg_settings, + uint32_t offset, uint32_t *byte_cnt, + struct list_head *list_ptr, + size_t remain_buf_len) +{ + int32_t rc = 0; + struct i2c_settings_list *i2c_list = NULL; + struct cam_cmd_unconditional_wait *cmd_uncond_wait = + (struct cam_cmd_unconditional_wait *) *cmd_buf; + + if (remain_buf_len < (sizeof(struct cam_cmd_unconditional_wait))) { + CAM_ERR(CAM_EEPROM, "Not Enough buffer"); + return -EINVAL; + } + + if (list_ptr == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid list ptr"); + return -EINVAL; + } + + if (offset > 0) { + i2c_list = + list_entry(list_ptr, struct i2c_settings_list, list); + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND) + i2c_list->i2c_settings.reg_setting[offset - 1].delay = + cmd_uncond_wait->delay; + else + i2c_list->i2c_settings.delay = + cmd_uncond_wait->delay; + (*cmd_buf) += + sizeof( + struct cam_cmd_unconditional_wait) / sizeof(uint32_t); + (*byte_cnt) += + sizeof( + struct cam_cmd_unconditional_wait); + } else { + CAM_ERR(CAM_SENSOR, "Delay Rxed before any buffer: %d", offset); + return -EINVAL; + } + + return rc; +} + +/** + * cam_eeprom_parse_write_memory_packet - Write eeprom packet + * @csl_packet: csl packet received + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int32_t cam_eeprom_parse_write_memory_packet( + struct cam_packet *csl_packet, + struct cam_eeprom_ctrl_t *e_ctrl) +{ + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint32_t *offset = NULL; + int32_t i, rc = 0; + uint32_t *cmd_buf = NULL; + uintptr_t generic_pkt_addr; + size_t pkt_len = 0; + size_t remain_len = 0; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_info *i2c_info = NULL; + + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + CAM_DBG(CAM_EEPROM, "Number of Command Buffers: %d", + csl_packet->num_cmd_buf); + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + struct list_head *list = NULL; + uint16_t generic_op_code; + uint32_t off = 0; + int master; + struct cam_sensor_cci_client *cci; + + total_cmd_buf_in_bytes = cmd_desc[i].length; + processed_cmd_buf_in_bytes = 0; + + if (!total_cmd_buf_in_bytes) + continue; + + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to get cpu buf"); + return rc; + } + + cmd_buf = (uint32_t *)generic_pkt_addr; + if (!cmd_buf) { + CAM_ERR(CAM_EEPROM, "invalid cmd buf"); + rc = -EINVAL; + goto end; + } + + if ((pkt_len < sizeof(struct common_header) || + (cmd_desc[i].offset) > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto end; + } + + remain_len = pkt_len - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + rc = -EINVAL; + goto end; + } + + master = e_ctrl->io_master_info.master_type; + cci = e_ctrl->io_master_info.cci_client; + while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not Enough buffer"); + rc = -EINVAL; + goto end; + } + cmm_hdr = (struct common_header *)cmd_buf; + generic_op_code = cmm_hdr->fifth_byte; + + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + if (master == CCI_MASTER) { + cci->cci_i2c_master = + e_ctrl->cci_i2c_master; + cci->i2c_freq_mode = + i2c_info->i2c_freq_mode; + cci->sid = + i2c_info->slave_addr >> 1; + CAM_DBG(CAM_EEPROM, + "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, + i2c_info->i2c_freq_mode); + } else if (master == I2C_MASTER) { + e_ctrl->io_master_info.client->addr = + i2c_info->slave_addr; + CAM_DBG(CAM_EEPROM, + "Slave addr: 0x%x", + i2c_info->slave_addr); + } else if (master == SPI_MASTER) { + CAM_ERR(CAM_EEPROM, + "No Need of Slave Info"); + } else { + CAM_ERR(CAM_EEPROM, + "Invalid Master type: %d", + master); + rc = -EINVAL; + goto end; + } + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/4; + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: { + struct cam_cmd_i2c_continuous_wr + *cam_cmd_i2c_continuous_wr = + (struct cam_cmd_i2c_continuous_wr *) + cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_EEPROM, + "CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR"); + rc = cam_eeprom_handle_continuous_write( + e_ctrl, + cam_cmd_i2c_continuous_wr, + &(e_ctrl->wr_settings), + &cmd_length_in_bytes, &off, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in continuous write %d", rc); + goto end; + } + + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + break; + } + case CAMERA_SENSOR_CMD_TYPE_WAIT: { + CAM_DBG(CAM_EEPROM, + "CAMERA_SENSOR_CMD_TYPE_WAIT"); + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND || + generic_op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) { + + rc = cam_eeprom_handle_delay( + &cmd_buf, generic_op_code, + &(e_ctrl->wr_settings), off, + &cmd_length_in_bytes, + list, (remain_len - + processed_cmd_buf_in_bytes)); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "delay hdl failed: %d", + rc); + goto end; + } + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + } else { + CAM_ERR(CAM_EEPROM, + "Wrong Wait Command: %d", + generic_op_code); + rc = -EINVAL; + goto end; + } + break; + } + default: + CAM_ERR(CAM_EEPROM, + "Invalid Cmd_type rxed: %d\n", + cmm_hdr->cmd_type); + rc = -EINVAL; + break; + } + } + } + +end: + return rc; +} + +/** + * cam_eeprom_init_pkt_parser - Parse eeprom packet + * @e_ctrl: ctrl structure + * @csl_packet: csl packet received + * + * Returns success or failure + */ +static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_packet *csl_packet) +{ + int32_t rc = 0; + int i = 0; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint32_t *offset = NULL; + uint32_t *cmd_buf = NULL; + uintptr_t generic_pkt_addr; + size_t pkt_len = 0; + size_t remain_len = 0; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_info *i2c_info = NULL; + int num_map = -1; + struct cam_eeprom_memory_map_t *map = NULL; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + e_ctrl->cal_data.map = vzalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * + MSM_EEPROM_MAX_MEM_MAP_CNT) * + (sizeof(struct cam_eeprom_memory_map_t))); + if (!e_ctrl->cal_data.map) { + rc = -ENOMEM; + CAM_ERR(CAM_EEPROM, "failed"); + return rc; + } + map = e_ctrl->cal_data.map; + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + processed_cmd_buf_in_bytes = 0; + if (!total_cmd_buf_in_bytes) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to get cpu buf"); + return rc; + } + cmd_buf = (uint32_t *)generic_pkt_addr; + if (!cmd_buf) { + CAM_ERR(CAM_EEPROM, "invalid cmd buf"); + rc = -EINVAL; + goto end; + } + + if ((pkt_len < sizeof(struct common_header)) || + (cmd_desc[i].offset > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto end; + } + remain_len = pkt_len - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + rc = -EINVAL; + goto end; + } + /* Loop through multiple cmd formats in one cmd buffer */ + while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + cmm_hdr = (struct common_header *)cmd_buf; + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto end; + } + /* Configure the following map slave address */ + map[num_map + 1].saddr = i2c_info->slave_addr; + rc = cam_eeprom_update_slaveInfo(e_ctrl, + cmd_buf); + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + cmd_length_in_bytes = total_cmd_buf_in_bytes; + rc = cam_sensor_update_power_settings(cmd_buf, + cmd_length_in_bytes, power_info, + (remain_len - + processed_cmd_buf_in_bytes)); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed"); + goto end; + } + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: + case CAMERA_SENSOR_CMD_TYPE_WAIT: + num_map++; + rc = cam_eeprom_parse_memory_map( + &e_ctrl->cal_data, cmd_buf, + total_cmd_buf_in_bytes, + &cmd_length_in_bytes, &num_map, + (remain_len - + processed_cmd_buf_in_bytes)); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/sizeof(uint32_t); + break; + default: + CAM_ERR(CAM_EEPROM, "Invalid cmd_type 0x%x", + cmm_hdr->cmd_type); + rc = -EINVAL; + goto end; + } + } + e_ctrl->cal_data.num_map = num_map + 1; + } + +end: + return rc; +} + +/** + * cam_eeprom_get_cal_data - parse the userspace IO config and + * copy read data to share with userspace + * @e_ctrl: ctrl structure + * @csl_packet: csl packet received + * + * Returns success or failure + */ +static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_buf_io_cfg *io_cfg; + uint32_t i = 0; + int rc = 0; + uintptr_t buf_addr; + size_t buf_size; + uint8_t *read_buffer; + size_t remain_len = 0; + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + CAM_DBG(CAM_EEPROM, "number of IO configs: %d:", + csl_packet->num_io_configs); + + for (i = 0; i < csl_packet->num_io_configs; i++) { + CAM_DBG(CAM_EEPROM, "Direction: %d:", io_cfg->direction); + if (io_cfg->direction == CAM_BUF_OUTPUT) { + rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], + &buf_addr, &buf_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "Fail in get buffer: %d", + rc); + return rc; + } + if (buf_size <= io_cfg->offsets[0]) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + + remain_len = buf_size - io_cfg->offsets[0]; + CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", + (void *)buf_addr, buf_size); + + read_buffer = (uint8_t *)buf_addr; + if (!read_buffer) { + CAM_ERR(CAM_EEPROM, + "invalid buffer to copy data"); + rc = -EINVAL; + return rc; + } + read_buffer += io_cfg->offsets[0]; + + if (remain_len < e_ctrl->cal_data.num_data) { + CAM_ERR(CAM_EEPROM, + "failed to copy, Invalid size"); + rc = -EINVAL; + return rc; + } + + CAM_DBG(CAM_EEPROM, "copy the data, len:%d", + e_ctrl->cal_data.num_data); + memcpy(read_buffer, e_ctrl->cal_data.mapdata, + e_ctrl->cal_data.num_data); + } else { + CAM_ERR(CAM_EEPROM, "Invalid direction"); + rc = -EINVAL; + } + } + + return rc; +} + +static int32_t delete_eeprom_request(struct i2c_settings_array *i2c_array) +{ + struct i2c_settings_list *i2c_list = NULL, *i2c_next = NULL; + int32_t rc = 0; + + if (i2c_array == NULL) { + CAM_ERR(CAM_SENSOR, "FATAL:: Invalid argument"); + return -EINVAL; + } + + list_for_each_entry_safe(i2c_list, i2c_next, + &(i2c_array->list_head), list) { + kfree(i2c_list->seq_settings.reg_data); + list_del(&(i2c_list->list)); + kfree(i2c_list); + } + INIT_LIST_HEAD(&(i2c_array->list_head)); + i2c_array->is_settings_valid = 0; + + return rc; +} + +/** + * cam_eeprom_write - Write Packet + * @e_ctrl: ctrl structure + * + * Returns success or failure + */ +static int32_t cam_eeprom_write(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int32_t rc = 0; + struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list = NULL; + + i2c_set = &e_ctrl->wr_settings; + + if (i2c_set->is_settings_valid == 1) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = camera_io_dev_write_continuous( + &e_ctrl->io_master_info, + &i2c_list->i2c_settings, 1); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "Error in EEPROM write"); + goto del_req; + } + } + } + +del_req: + delete_eeprom_request(i2c_set); + return rc; +} + +/** + * cam_eeprom_pkt_parse - Parse csl packet + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) +{ + int32_t rc = 0; + struct cam_control *ioctl_ctrl = NULL; + struct cam_config_dev_cmd dev_config; + uintptr_t generic_pkt_addr; + size_t pkt_len; + size_t remain_len = 0; + struct cam_packet *csl_packet = NULL; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user(&dev_config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(dev_config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(dev_config.packet_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, + "error in converting command Handle Error: %d", rc); + return rc; + } + + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_EEPROM, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + rc = -EINVAL; + return rc; + } + + remain_len -= (size_t)dev_config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_EEPROM, "Invalid packet params"); + rc = -EINVAL; + return rc; + } + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_EEPROM_PACKET_OPCODE_INIT: + if (e_ctrl->userspace_probe == false) { + rc = cam_eeprom_parse_read_memory_map( + e_ctrl->soc_info.dev->of_node, e_ctrl); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); + return rc; + } + rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + CAM_DBG(CAM_EEPROM, + "Returning the data using kernel probe"); + break; + } + rc = cam_eeprom_init_pkt_parser(e_ctrl, csl_packet); + if (rc) { + CAM_ERR(CAM_EEPROM, + "Failed in parsing the pkt"); + return rc; + } + + e_ctrl->cal_data.mapdata = + vzalloc(e_ctrl->cal_data.num_data); + if (!e_ctrl->cal_data.mapdata) { + rc = -ENOMEM; + CAM_ERR(CAM_EEPROM, "failed"); + goto error; + } + + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) { + rc = cam_eeprom_match_id(e_ctrl); + if (rc) { + CAM_DBG(CAM_EEPROM, + "eeprom not matching %d", rc); + goto memdata_free; + } + } + + rc = cam_eeprom_power_up(e_ctrl, + &soc_private->power_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed rc %d", rc); + goto memdata_free; + } + + e_ctrl->cam_eeprom_state = CAM_EEPROM_CONFIG; + rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); + if (rc) { + CAM_ERR(CAM_EEPROM, + "read_eeprom_memory failed"); + goto power_down; + } + + rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); + rc = cam_eeprom_power_down(e_ctrl); + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + vfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.map); + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + break; + case CAM_EEPROM_WRITE: { + struct i2c_settings_array *i2c_reg_settings = + &e_ctrl->wr_settings; + + i2c_reg_settings->is_settings_valid = 1; + rc = cam_eeprom_parse_write_memory_packet( + csl_packet, e_ctrl); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); + return rc; + } + + rc = cam_eeprom_power_up(e_ctrl, + &soc_private->power_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed power up rc %d", rc); + goto memdata_free; + } + + usleep_range(10*1000, 11*1000); + CAM_DBG(CAM_EEPROM, + "Calling Erase : %d start Address: 0x%x size: %d", + rc, e_ctrl->eebin_info.start_address, + e_ctrl->eebin_info.size); + + rc = camera_io_dev_erase(&e_ctrl->io_master_info, + e_ctrl->eebin_info.start_address, + e_ctrl->eebin_info.size); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed in erase : %d", rc); + return rc; + } + + /* Buffer time margin */ + usleep_range(10*1000, 11*1000); + + rc = cam_eeprom_write(e_ctrl); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); + return rc; + } + + rc = cam_eeprom_power_down(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed power down rc %d", rc); + goto memdata_free; + } + + break; + } + default: + CAM_ERR(CAM_EEPROM, "Invalid op-code 0x%x", + csl_packet->header.op_code & 0xFFFFFF); + rc = -EINVAL; + break; + } + + return rc; +power_down: + cam_eeprom_power_down(e_ctrl); +memdata_free: + vfree(e_ctrl->cal_data.mapdata); +error: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + vfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + return rc; +} + +void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + if (e_ctrl->cam_eeprom_state == CAM_EEPROM_INIT) + return; + + if (e_ctrl->cam_eeprom_state == CAM_EEPROM_CONFIG) { + rc = cam_eeprom_power_down(e_ctrl); + if (rc < 0) + CAM_ERR(CAM_EEPROM, "EEPROM Power down failed"); + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + } + + if (e_ctrl->cam_eeprom_state == CAM_EEPROM_ACQUIRE) { + rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_EEPROM, "destroying the device hdl"); + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.link_hdl = -1; + e_ctrl->bridge_intf.session_hdl = -1; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + } + + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; +} + +/** + * cam_eeprom_driver_cmd - Handle eeprom cmds + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) +{ + int rc = 0; + struct cam_eeprom_query_cap_t eeprom_cap = {0}; + struct cam_control *cmd = (struct cam_control *)arg; + + if (!e_ctrl || !cmd) { + CAM_ERR(CAM_EEPROM, "Invalid Arguments"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_EEPROM, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + mutex_lock(&(e_ctrl->eeprom_mutex)); + switch (cmd->op_code) { + case CAM_QUERY_CAP: + eeprom_cap.slot_info = e_ctrl->soc_info.index; + if (e_ctrl->userspace_probe == false) + eeprom_cap.eeprom_kernel_probe = true; + else + eeprom_cap.eeprom_kernel_probe = false; + + eeprom_cap.is_multimodule_mode = + e_ctrl->is_multimodule_mode; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &eeprom_cap, + sizeof(struct cam_eeprom_query_cap_t))) { + CAM_ERR(CAM_EEPROM, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info); + break; + case CAM_ACQUIRE_DEV: + rc = cam_eeprom_get_dev_handle(e_ctrl, arg); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to acquire dev"); + goto release_mutex; + } + e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + break; + case CAM_RELEASE_DEV: + if (e_ctrl->cam_eeprom_state != CAM_EEPROM_ACQUIRE) { + rc = -EINVAL; + CAM_WARN(CAM_EEPROM, + "Not in right state to release : %d", + e_ctrl->cam_eeprom_state); + goto release_mutex; + } + + if (e_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_EEPROM, + "Invalid Handles: link hdl: %d device hdl: %d", + e_ctrl->bridge_intf.device_hdl, + e_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_EEPROM, + "failed in destroying the device hdl"); + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.link_hdl = -1; + e_ctrl->bridge_intf.session_hdl = -1; + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + break; + case CAM_CONFIG_DEV: + rc = cam_eeprom_pkt_parse(e_ctrl, arg); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed in eeprom pkt Parsing"); + goto release_mutex; + } + break; + default: + CAM_DBG(CAM_EEPROM, "invalid opcode"); + break; + } + +release_mutex: + mutex_unlock(&(e_ctrl->eeprom_mutex)); + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h new file mode 100644 index 0000000000000000000000000000000000000000..6a1e867542cb129fd9a90695ea02a43a635f1df9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_core.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_EEPROM_CORE_H_ +#define _CAM_EEPROM_CORE_H_ + +#include "cam_eeprom_dev.h" + +int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg); +int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, + struct cam_eeprom_ctrl_t *e_ctrl); +/** + * @e_ctrl: EEPROM ctrl structure + * + * This API handles the shutdown ioctl/close + */ +void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl); + +#endif +/* _CAM_EEPROM_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..328541553b59ad5f09cd95d4714d274e51fe30f4 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_eeprom_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_eeprom_soc.h" +#include "cam_eeprom_core.h" +#include "cam_debug_util.h" + +static long cam_eeprom_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_eeprom_driver_cmd(e_ctrl, arg); + break; + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + +static int cam_eeprom_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_eeprom_ctrl_t *e_ctrl = + v4l2_get_subdevdata(sd); + + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "e_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + + return 0; +} + +int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_eeprom_i2c_info_t *i2c_info) +{ + struct cam_sensor_cci_client *cci_client = NULL; + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) { + cci_client = e_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_EEPROM, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = e_ctrl->cci_i2c_master; + cci_client->sid = (i2c_info->slave_addr) >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + } else if (e_ctrl->io_master_info.master_type == I2C_MASTER) { + e_ctrl->io_master_info.client->addr = i2c_info->slave_addr; + CAM_DBG(CAM_EEPROM, "Slave addr: 0x%x", i2c_info->slave_addr); + } else if (e_ctrl->io_master_info.master_type == SPI_MASTER) { + CAM_ERR(CAM_EEPROM, "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, i2c_info->i2c_freq_mode); + } + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_eeprom_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_EEPROM, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_eeprom_subdev_ioctl(sd, cmd, &cmd_data); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "Failed in eeprom suddev handling rc %d", + rc); + return rc; + } + break; + default: + CAM_ERR(CAM_EEPROM, "Invalid compat ioctl: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_EEPROM, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + return rc; +} +#endif + +static const struct v4l2_subdev_internal_ops cam_eeprom_internal_ops = { + .close = cam_eeprom_subdev_close, +}; + +static struct v4l2_subdev_core_ops cam_eeprom_subdev_core_ops = { + .ioctl = cam_eeprom_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_eeprom_init_subdev_do_ioctl, +#endif +}; + +static struct v4l2_subdev_ops cam_eeprom_subdev_ops = { + .core = &cam_eeprom_subdev_core_ops, +}; + +static int cam_eeprom_init_subdev(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0; + + e_ctrl->v4l2_dev_str.internal_ops = &cam_eeprom_internal_ops; + e_ctrl->v4l2_dev_str.ops = &cam_eeprom_subdev_ops; + strlcpy(e_ctrl->device_name, CAM_EEPROM_NAME, + sizeof(e_ctrl->device_name)); + e_ctrl->v4l2_dev_str.name = e_ctrl->device_name; + e_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + e_ctrl->v4l2_dev_str.ent_function = CAM_EEPROM_DEVICE_TYPE; + e_ctrl->v4l2_dev_str.token = e_ctrl; + + rc = cam_register_subdev(&(e_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev"); + + return rc; +} + +static int cam_eeprom_i2c_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = NULL; + struct cam_eeprom_soc_private *soc_private = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_EEPROM, "i2c_check_functionality failed"); + goto probe_failure; + } + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "kzalloc failed"); + rc = -ENOMEM; + goto probe_failure; + } + + soc_private = kzalloc(sizeof(*soc_private), GFP_KERNEL); + if (!soc_private) + goto ectrl_free; + + e_ctrl->soc_info.soc_private = soc_private; + + i2c_set_clientdata(client, e_ctrl); + + mutex_init(&(e_ctrl->eeprom_mutex)); + + INIT_LIST_HEAD(&(e_ctrl->wr_settings.list_head)); + soc_info = &e_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + e_ctrl->io_master_info.master_type = I2C_MASTER; + e_ctrl->io_master_info.client = client; + e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + e_ctrl->userspace_probe = false; + + rc = cam_eeprom_parse_dt(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: soc init rc %d", rc); + goto free_soc; + } + + rc = cam_eeprom_update_i2c_info(e_ctrl, &soc_private->i2c_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: to update i2c info rc %d", rc); + goto free_soc; + } + + rc = cam_eeprom_init_subdev(e_ctrl); + if (rc) + goto free_soc; + + if (soc_private->i2c_info.slave_addr != 0) + e_ctrl->io_master_info.client->addr = + soc_private->i2c_info.slave_addr; + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.ops.get_dev_info = NULL; + e_ctrl->bridge_intf.ops.link_setup = NULL; + e_ctrl->bridge_intf.ops.apply_req = NULL; + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + + return rc; +free_soc: + kfree(soc_private); +ectrl_free: + kfree(e_ctrl); +probe_failure: + return rc; +} + +static int cam_eeprom_i2c_driver_remove(struct i2c_client *client) +{ + int i; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct cam_eeprom_ctrl_t *e_ctrl; + struct cam_eeprom_soc_private *soc_private; + struct cam_hw_soc_info *soc_info; + + if (!sd) { + CAM_ERR(CAM_EEPROM, "Subdevice is NULL"); + return -EINVAL; + } + + e_ctrl = (struct cam_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "eeprom device is NULL"); + return -EINVAL; + } + + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + if (!soc_private) { + CAM_ERR(CAM_EEPROM, "soc_info.soc_private is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_EEPROM, "i2c driver remove invoked"); + soc_info = &e_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); + kfree(soc_private); + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); + kfree(e_ctrl); + + return 0; +} + +static int cam_eeprom_spi_setup(struct spi_device *spi) +{ + struct cam_eeprom_ctrl_t *e_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + struct cam_sensor_spi_client *spi_client; + struct cam_eeprom_soc_private *eb_info; + struct cam_sensor_power_ctrl_t *power_info = NULL; + int rc = 0; + + e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); + if (!e_ctrl) + return -ENOMEM; + + soc_info = &e_ctrl->soc_info; + soc_info->dev = &spi->dev; + soc_info->dev_name = spi->modalias; + + e_ctrl->v4l2_dev_str.ops = &cam_eeprom_subdev_ops; + e_ctrl->userspace_probe = false; + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + + spi_client = kzalloc(sizeof(*spi_client), GFP_KERNEL); + if (!spi_client) { + kfree(e_ctrl); + return -ENOMEM; + } + + eb_info = kzalloc(sizeof(*eb_info), GFP_KERNEL); + if (!eb_info) + goto spi_free; + e_ctrl->soc_info.soc_private = eb_info; + + e_ctrl->eeprom_device_type = MSM_CAMERA_SPI_DEVICE; + e_ctrl->io_master_info.spi_client = spi_client; + e_ctrl->io_master_info.master_type = SPI_MASTER; + spi_client->spi_master = spi; + INIT_LIST_HEAD(&(e_ctrl->wr_settings.list_head)); + power_info = &eb_info->power_info; + power_info->dev = &spi->dev; + + /* set spi instruction info */ + spi_client->retry_delay = 1; + spi_client->retries = 0; + + /* Initialize mutex */ + mutex_init(&(e_ctrl->eeprom_mutex)); + + e_ctrl->bridge_intf.device_hdl = -1; + rc = cam_eeprom_parse_dt(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: spi soc init rc %d", rc); + goto board_free; + } + + rc = cam_eeprom_spi_parse_of(spi_client); + if (rc) { + CAM_ERR(CAM_EEPROM, "Device tree parsing error"); + goto board_free; + } + + rc = cam_eeprom_init_subdev(e_ctrl); + if (rc) + goto board_free; + + e_ctrl->bridge_intf.ops.get_dev_info = NULL; + e_ctrl->bridge_intf.ops.link_setup = NULL; + e_ctrl->bridge_intf.ops.apply_req = NULL; + + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl); + return rc; + +board_free: + kfree(e_ctrl->soc_info.soc_private); +spi_free: + kfree(spi_client); + kfree(e_ctrl); + return rc; +} + +static int cam_eeprom_spi_driver_probe(struct spi_device *spi) +{ + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + spi_setup(spi); + + CAM_DBG(CAM_EEPROM, "irq[%d] cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x]", + spi->irq, spi->chip_select, (spi->mode & SPI_CPHA) ? 1 : 0, + (spi->mode & SPI_CPOL) ? 1 : 0, + (spi->mode & SPI_CS_HIGH) ? 1 : 0); + CAM_DBG(CAM_EEPROM, "max_speed[%u]", spi->max_speed_hz); + + return cam_eeprom_spi_setup(spi); +} + +static int cam_eeprom_spi_driver_remove(struct spi_device *sdev) +{ + int i; + struct v4l2_subdev *sd = spi_get_drvdata(sdev); + struct cam_eeprom_ctrl_t *e_ctrl; + struct cam_eeprom_soc_private *soc_private; + struct cam_hw_soc_info *soc_info; + + if (!sd) { + CAM_ERR(CAM_EEPROM, "Subdevice is NULL"); + return -EINVAL; + } + + e_ctrl = (struct cam_eeprom_ctrl_t *)v4l2_get_subdevdata(sd); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "eeprom device is NULL"); + return -EINVAL; + } + + soc_info = &e_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); + kfree(e_ctrl->io_master_info.spi_client); + e_ctrl->io_master_info.spi_client = NULL; + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + if (soc_private) { + kfree(soc_private->power_info.gpio_num_info); + soc_private->power_info.gpio_num_info = NULL; + kfree(soc_private); + soc_private = NULL; + } + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); + kfree(e_ctrl); + + return 0; +} + +static int32_t cam_eeprom_platform_driver_probe( + struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_eeprom_ctrl_t *e_ctrl = NULL; + struct cam_eeprom_soc_private *soc_private = NULL; + + e_ctrl = kzalloc(sizeof(struct cam_eeprom_ctrl_t), GFP_KERNEL); + if (!e_ctrl) + return -ENOMEM; + + e_ctrl->soc_info.pdev = pdev; + e_ctrl->soc_info.dev = &pdev->dev; + e_ctrl->soc_info.dev_name = pdev->name; + e_ctrl->eeprom_device_type = MSM_CAMERA_PLATFORM_DEVICE; + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + e_ctrl->userspace_probe = false; + + e_ctrl->io_master_info.master_type = CCI_MASTER; + e_ctrl->io_master_info.cci_client = kzalloc( + sizeof(struct cam_sensor_cci_client), GFP_KERNEL); + if (!e_ctrl->io_master_info.cci_client) { + rc = -ENOMEM; + goto free_e_ctrl; + } + + soc_private = kzalloc(sizeof(struct cam_eeprom_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_cci_client; + } + e_ctrl->soc_info.soc_private = soc_private; + soc_private->power_info.dev = &pdev->dev; + + /* Initialize mutex */ + mutex_init(&(e_ctrl->eeprom_mutex)); + rc = cam_eeprom_parse_dt(e_ctrl); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: soc init rc %d", rc); + goto free_soc; + } + rc = cam_eeprom_update_i2c_info(e_ctrl, &soc_private->i2c_info); + if (rc) { + CAM_ERR(CAM_EEPROM, "failed: to update i2c info rc %d", rc); + goto free_soc; + } + + INIT_LIST_HEAD(&(e_ctrl->wr_settings.list_head)); + rc = cam_eeprom_init_subdev(e_ctrl); + if (rc) + goto free_soc; + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.ops.get_dev_info = NULL; + e_ctrl->bridge_intf.ops.link_setup = NULL; + e_ctrl->bridge_intf.ops.apply_req = NULL; + platform_set_drvdata(pdev, e_ctrl); + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; + + return rc; +free_soc: + kfree(soc_private); +free_cci_client: + kfree(e_ctrl->io_master_info.cci_client); +free_e_ctrl: + kfree(e_ctrl); + + return rc; +} + +static int cam_eeprom_platform_driver_remove(struct platform_device *pdev) +{ + int i; + struct cam_eeprom_ctrl_t *e_ctrl; + struct cam_hw_soc_info *soc_info; + + e_ctrl = platform_get_drvdata(pdev); + if (!e_ctrl) { + CAM_ERR(CAM_EEPROM, "eeprom device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_EEPROM, "Platform driver remove invoked"); + soc_info = &e_ctrl->soc_info; + + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); + kfree(soc_info->soc_private); + kfree(e_ctrl->io_master_info.cci_client); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); + kfree(e_ctrl); + + return 0; +} + +static const struct of_device_id cam_eeprom_dt_match[] = { + { .compatible = "qcom,eeprom" }, + { } +}; + + +MODULE_DEVICE_TABLE(of, cam_eeprom_dt_match); + +static struct platform_driver cam_eeprom_platform_driver = { + .driver = { + .name = "qcom,eeprom", + .owner = THIS_MODULE, + .of_match_table = cam_eeprom_dt_match, + .suppress_bind_attrs = true, + }, + .probe = cam_eeprom_platform_driver_probe, + .remove = cam_eeprom_platform_driver_remove, +}; + +static const struct i2c_device_id cam_eeprom_i2c_id[] = { + { "msm_eeprom", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_eeprom_i2c_driver = { + .id_table = cam_eeprom_i2c_id, + .probe = cam_eeprom_i2c_driver_probe, + .remove = cam_eeprom_i2c_driver_remove, + .driver = { + .name = "msm_eeprom", + }, +}; + +static struct spi_driver cam_eeprom_spi_driver = { + .driver = { + .name = "qcom_eeprom", + .owner = THIS_MODULE, + .of_match_table = cam_eeprom_dt_match, + }, + .probe = cam_eeprom_spi_driver_probe, + .remove = cam_eeprom_spi_driver_remove, +}; +static int __init cam_eeprom_driver_init(void) +{ + int rc = 0; + + rc = platform_driver_register(&cam_eeprom_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "platform_driver_register failed rc = %d", + rc); + return rc; + } + + rc = spi_register_driver(&cam_eeprom_spi_driver); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "spi_register_driver failed rc = %d", rc); + return rc; + } + + rc = i2c_add_driver(&cam_eeprom_i2c_driver); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "i2c_add_driver failed rc = %d", rc); + return rc; + } + + return rc; +} + +static void __exit cam_eeprom_driver_exit(void) +{ + platform_driver_unregister(&cam_eeprom_platform_driver); + spi_unregister_driver(&cam_eeprom_spi_driver); + i2c_del_driver(&cam_eeprom_i2c_driver); +} + +module_init(cam_eeprom_driver_init); +module_exit(cam_eeprom_driver_exit); +MODULE_DESCRIPTION("CAM EEPROM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..66f8aaddc9589afb98f6b5eaab7c268349654736 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_EEPROM_DEV_H_ +#define _CAM_EEPROM_DEV_H_ + +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/gpio.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-ioctl.h> +#include <cam_sensor_i2c.h> +#include <cam_sensor_spi.h> +#include <cam_sensor_io.h> +#include <cam_cci_dev.h> +#include <cam_req_mgr_util.h> +#include <cam_req_mgr_interface.h> +#include <cam_mem_mgr.h> +#include <cam_subdev.h> +#include <media/cam_sensor.h> +#include "cam_soc_util.h" +#include "cam_context.h" + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define PROPERTY_MAXSIZE 32 + +#define MSM_EEPROM_MEMORY_MAP_MAX_SIZE 80 +#define MSM_EEPROM_MAX_MEM_MAP_CNT 100 +#define MSM_EEPROM_MEM_MAP_PROPERTIES_CNT 8 + +enum cam_eeprom_state { + CAM_EEPROM_INIT, + CAM_EEPROM_ACQUIRE, + CAM_EEPROM_CONFIG, +}; + +/** + * struct cam_eeprom_map_t - eeprom map + * @data_type : Data type + * @addr_type : Address type + * @addr : Address + * @data : data + * @delay : Delay + * + */ +struct cam_eeprom_map_t { + uint32_t valid_size; + uint32_t addr; + uint32_t addr_type; + uint32_t data; + uint32_t data_type; + uint32_t delay; +}; + +/** + * struct cam_eeprom_memory_map_t - eeprom memory map types + * @page : page memory + * @pageen : pageen memory + * @poll : poll memory + * @mem : mem + * @saddr : slave addr + * + */ +struct cam_eeprom_memory_map_t { + struct cam_eeprom_map_t page; + struct cam_eeprom_map_t pageen; + struct cam_eeprom_map_t poll; + struct cam_eeprom_map_t mem; + uint32_t saddr; +}; + +/** + * struct cam_eeprom_memory_block_t - eeprom mem block info + * @map : eeprom memory map + * @num_map : number of map blocks + * @mapdata : map data + * @cmd_type : size of total mapdata + * + */ +struct cam_eeprom_memory_block_t { + struct cam_eeprom_memory_map_t *map; + uint32_t num_map; + uint8_t *mapdata; + uint32_t num_data; +}; + +/** + * struct cam_eeprom_cmm_t - camera multimodule + * @cmm_support : cmm support flag + * @cmm_compression : cmm compression flag + * @cmm_offset : cmm data start offset + * @cmm_size : cmm data size + * + */ +struct cam_eeprom_cmm_t { + uint32_t cmm_support; + uint32_t cmm_compression; + uint32_t cmm_offset; + uint32_t cmm_size; +}; + +/** + * struct cam_eeprom_i2c_info_t - I2C info + * @slave_addr : slave address + * @i2c_freq_mode : i2c frequency mode + * + */ +struct cam_eeprom_i2c_info_t { + uint16_t slave_addr; + uint8_t i2c_freq_mode; +}; + +/** + * struct cam_eeprom_soc_private - eeprom soc private data structure + * @eeprom_name : eeprom name + * @i2c_info : i2c info structure + * @power_info : eeprom power info + * @cmm_data : cmm data + * + */ +struct cam_eeprom_soc_private { + const char *eeprom_name; + struct cam_eeprom_i2c_info_t i2c_info; + struct cam_sensor_power_ctrl_t power_info; + struct cam_eeprom_cmm_t cmm_data; +}; + +/** + * struct cam_eeprom_intf_params - bridge interface params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_eeprom_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +struct eebin_info { + uint32_t start_address; + uint32_t size; + uint32_t is_valid; +}; + +/** + * struct cam_eeprom_ctrl_t - EEPROM control structure + * @device_name : Device name + * @pdev : platform device + * @spi : spi device + * @eeprom_mutex : eeprom mutex + * @soc_info : eeprom soc related info + * @io_master_info : Information about the communication master + * @gpio_num_info : gpio info + * @cci_i2c_master : I2C structure + * @v4l2_dev_str : V4L2 device structure + * @bridge_intf : bridge interface params + * @cam_eeprom_state : eeprom_device_state + * @userspace_probe : flag indicates userspace or kernel probe + * @cal_data : Calibration data + * @device_name : Device name + * @is_multimodule_mode : To identify multimodule node + * @wr_settings : I2C write settings + * @eebin_info : EEBIN address, size info + */ +struct cam_eeprom_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct platform_device *pdev; + struct spi_device *spi; + struct mutex eeprom_mutex; + struct cam_hw_soc_info soc_info; + struct camera_io_master io_master_info; + struct msm_camera_gpio_num_info *gpio_num_info; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct cam_subdev v4l2_dev_str; + struct cam_eeprom_intf_params bridge_intf; + enum msm_camera_device_type_t eeprom_device_type; + enum cam_eeprom_state cam_eeprom_state; + bool userspace_probe; + struct cam_eeprom_memory_block_t cal_data; + uint16_t is_multimodule_mode; + struct i2c_settings_array wr_settings; + struct eebin_info eebin_info; +}; + +int32_t cam_eeprom_update_i2c_info(struct cam_eeprom_ctrl_t *e_ctrl, + struct cam_eeprom_i2c_info_t *i2c_info); + +#endif /*_CAM_EEPROM_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..33f80b0c9716fa3190377862268524cf5e7a0dc9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c @@ -0,0 +1,384 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <cam_sensor_cmn_header.h> +#include <cam_sensor_util.h> +#include <cam_sensor_io.h> +#include <cam_req_mgr_util.h> + +#include "cam_eeprom_soc.h" +#include "cam_debug_util.h" + +#define cam_eeprom_spi_parse_cmd(spi_dev, name, out) \ + { \ + spi_dev->cmd_tbl.name.opcode = out[0]; \ + spi_dev->cmd_tbl.name.addr_len = out[1]; \ + spi_dev->cmd_tbl.name.dummy_len = out[2]; \ + spi_dev->cmd_tbl.name.delay_intv = out[3]; \ + spi_dev->cmd_tbl.name.delay_count = out[4]; \ + } + +int cam_eeprom_spi_parse_of(struct cam_sensor_spi_client *spi_dev) +{ + int rc = -EFAULT; + uint32_t tmp[5]; + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-read", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, read, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get read data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-readseq", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, read_seq, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get readseq data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-queryid", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, query_id, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get queryid data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-pprog", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, page_program, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get page program data"); + return -EFAULT; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-wenable", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, write_enable, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get write enable data"); + return rc; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-readst", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, read_status, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get readdst data"); + return rc; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "spiop-erase", tmp, 5); + if (!rc) { + cam_eeprom_spi_parse_cmd(spi_dev, erase, tmp); + } else { + CAM_ERR(CAM_EEPROM, "Failed to get erase data"); + return rc; + } + + rc = of_property_read_u32_array(spi_dev->spi_master->dev.of_node, + "eeprom-id", tmp, 2); + if (rc) { + CAM_ERR(CAM_EEPROM, "Failed to get eeprom id"); + return rc; + } + + spi_dev->mfr_id0 = tmp[0]; + spi_dev->device_id0 = tmp[1]; + + return 0; +} + +/* + * cam_eeprom_parse_memory_map() - parse memory map in device node + * @of: device node + * @data: memory block for output + * + * This functions parses @of to fill @data. It allocates map itself, parses + * the @of node, calculate total data length, and allocates required buffer. + * It only fills the map, but does not perform actual reading. + */ +int cam_eeprom_parse_dt_memory_map(struct device_node *node, + struct cam_eeprom_memory_block_t *data) +{ + int i, rc = 0; + char property[PROPERTY_MAXSIZE]; + uint32_t count = MSM_EEPROM_MEM_MAP_PROPERTIES_CNT; + struct cam_eeprom_memory_map_t *map; + + snprintf(property, PROPERTY_MAXSIZE, "num-blocks"); + rc = of_property_read_u32(node, property, &data->num_map); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: num-blocks not available rc %d", + rc); + return rc; + } + + map = vzalloc((sizeof(*map) * data->num_map)); + if (!map) { + rc = -ENOMEM; + return rc; + } + data->map = map; + + for (i = 0; i < data->num_map; i++) { + snprintf(property, PROPERTY_MAXSIZE, "page%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].page, count); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: page not available rc %d", + rc); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "pageen%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].pageen, count); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "pageen not needed"); + + snprintf(property, PROPERTY_MAXSIZE, "saddr%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].saddr, 1); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "saddr not needed - block %d", i); + + snprintf(property, PROPERTY_MAXSIZE, "poll%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].poll, count); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: poll not available rc %d", + rc); + goto ERROR; + } + + snprintf(property, PROPERTY_MAXSIZE, "mem%d", i); + rc = of_property_read_u32_array(node, property, + (uint32_t *) &map[i].mem, count); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: mem not available rc %d", + rc); + goto ERROR; + } + data->num_data += map[i].mem.valid_size; + } + + data->mapdata = vzalloc(data->num_data); + if (!data->mapdata) { + rc = -ENOMEM; + goto ERROR; + } + return rc; + +ERROR: + vfree(data->map); + memset(data, 0, sizeof(*data)); + return rc; +} + +/** + * @e_ctrl: ctrl structure + * + * Parses eeprom dt + */ +static int cam_eeprom_get_dt_data(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &e_ctrl->soc_info; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + struct device_node *of_node = NULL; + + of_node = soc_info->dev->of_node; + + if (e_ctrl->userspace_probe == false) { + rc = cam_get_dt_power_setting_data(of_node, + soc_info, power_info); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed in getting power settings"); + return rc; + } + } + + if (!soc_info->gpio_data) { + CAM_INFO(CAM_EEPROM, "No GPIO found"); + return 0; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_EEPROM, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &power_info->gpio_num_info); + if ((rc < 0) || (!power_info->gpio_num_info)) { + CAM_ERR(CAM_EEPROM, "No/Error EEPROM GPIOs"); + return -EINVAL; + } + + return rc; +} + +/** + * @eb_info: eeprom private data structure + * @of_node: eeprom device node + * + * This function parses the eeprom dt to get the MM data + */ +static int cam_eeprom_cmm_dts(struct cam_eeprom_soc_private *eb_info, + struct device_node *of_node) +{ + int rc = 0; + struct cam_eeprom_cmm_t *cmm_data = &eb_info->cmm_data; + + cmm_data->cmm_support = + of_property_read_bool(of_node, "cmm-data-support"); + if (!cmm_data->cmm_support) { + CAM_DBG(CAM_EEPROM, "No cmm support"); + return 0; + } + + cmm_data->cmm_compression = + of_property_read_bool(of_node, "cmm-data-compressed"); + + rc = of_property_read_u32(of_node, "cmm-data-offset", + &cmm_data->cmm_offset); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "No MM offset data rc %d", rc); + + rc = of_property_read_u32(of_node, "cmm-data-size", + &cmm_data->cmm_size); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "No MM size data rc %d", rc); + + CAM_DBG(CAM_EEPROM, "cmm_compr %d, cmm_offset %d, cmm_size %d", + cmm_data->cmm_compression, cmm_data->cmm_offset, + cmm_data->cmm_size); + return 0; +} + +/** + * @e_ctrl: ctrl structure + * + * This function is called from cam_eeprom_platform/i2c/spi_driver_probe + * it parses the eeprom dt node and decides for userspace or kernel probe. + */ +int cam_eeprom_parse_dt(struct cam_eeprom_ctrl_t *e_ctrl) +{ + int i, rc = 0; + struct cam_hw_soc_info *soc_info = &e_ctrl->soc_info; + struct device_node *of_node = NULL; + struct device_node *of_parent = NULL; + struct cam_eeprom_soc_private *soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + uint32_t temp; + + if (!soc_info->dev) { + CAM_ERR(CAM_EEPROM, "Dev is NULL"); + return -EINVAL; + } + + e_ctrl->is_multimodule_mode = false; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "Failed to read DT properties rc : %d", rc); + return rc; + } + + of_node = soc_info->dev->of_node; + + if (of_property_read_bool(of_node, "multimodule-support")) { + CAM_DBG(CAM_UTIL, "Multi Module is Supported"); + e_ctrl->is_multimodule_mode = true; + } + + rc = of_property_read_string(of_node, "eeprom-name", + &soc_private->eeprom_name); + if (rc < 0) { + CAM_DBG(CAM_EEPROM, "kernel probe is not enabled"); + e_ctrl->userspace_probe = true; + } + + if (e_ctrl->io_master_info.master_type == CCI_MASTER) { + rc = of_property_read_u32(of_node, "cci-master", + &e_ctrl->cci_i2c_master); + if (rc < 0 || (e_ctrl->cci_i2c_master >= MASTER_MAX)) { + CAM_DBG(CAM_EEPROM, "failed rc %d", rc); + rc = -EFAULT; + return rc; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &e_ctrl->cci_num) < 0) + /* Set default master 0 */ + e_ctrl->cci_num = CCI_DEVICE_0; + + e_ctrl->io_master_info.cci_client->cci_device = e_ctrl->cci_num; + CAM_DBG(CAM_EEPROM, "cci-index %d", e_ctrl->cci_num, rc); + } + + if (e_ctrl->io_master_info.master_type == SPI_MASTER) { + rc = cam_eeprom_cmm_dts(soc_private, soc_info->dev->of_node); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "MM data not available rc %d", rc); + } + + rc = cam_eeprom_get_dt_data(e_ctrl); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "failed: eeprom get dt data rc %d", rc); + + if ((e_ctrl->userspace_probe == false) && + (e_ctrl->io_master_info.master_type != SPI_MASTER)) { + rc = of_property_read_u32(of_node, "slave-addr", &temp); + if (rc < 0) + CAM_DBG(CAM_EEPROM, "failed: no slave-addr rc %d", rc); + + soc_private->i2c_info.slave_addr = temp; + + rc = of_property_read_u32(of_node, "i2c-freq-mode", &temp); + soc_private->i2c_info.i2c_freq_mode = temp; + if (rc < 0) { + CAM_ERR(CAM_EEPROM, + "i2c-freq-mode read fail %d", rc); + soc_private->i2c_info.i2c_freq_mode = 0; + } + if (soc_private->i2c_info.i2c_freq_mode >= I2C_MAX_MODES) { + CAM_ERR(CAM_EEPROM, "invalid i2c_freq_mode = %d", + soc_private->i2c_info.i2c_freq_mode); + soc_private->i2c_info.i2c_freq_mode = 0; + } + CAM_DBG(CAM_EEPROM, "slave-addr = 0x%X", + soc_private->i2c_info.slave_addr); + } + + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = devm_clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_EEPROM, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + return rc; + } + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..ed37989eb2d7047ae1e09a6ad332c7b596c045b0 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_EEPROM_SOC_H_ +#define _CAM_EEPROM_SOC_H_ + +#include "cam_eeprom_dev.h" + +int cam_eeprom_spi_parse_of(struct cam_sensor_spi_client *client); + +int cam_eeprom_parse_dt_memory_map(struct device_node *of, + struct cam_eeprom_memory_block_t *data); + +int cam_eeprom_parse_dt(struct cam_eeprom_ctrl_t *e_ctrl); +#endif/* _CAM_EEPROM_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_flash/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..da9e9e1b19cbb81bd7956cd0cb4c648949029178 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash_dev.o cam_flash_core.o cam_flash_soc.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c new file mode 100644 index 0000000000000000000000000000000000000000..f4dc655045a4080b86ffece9f9692edfcbe34ede --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -0,0 +1,1822 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> + +#include "cam_sensor_cmn_header.h" +#include "cam_flash_core.h" +#include "cam_res_mgr_api.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, + bool regulator_enable) +{ + int rc = 0; + struct cam_flash_private_soc *soc_private = + (struct cam_flash_private_soc *) + flash_ctrl->soc_info.soc_private; + + if (!(flash_ctrl->switch_trigger)) { + CAM_ERR(CAM_FLASH, "Invalid argument"); + return -EINVAL; + } + + if (soc_private->is_wled_flash) { + if (regulator_enable && + flash_ctrl->is_regulator_enabled == false) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "enable reg failed: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = true; + } else if (!regulator_enable && + flash_ctrl->is_regulator_enabled == true) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "disalbe reg fail: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Wled flash state: %d", + flash_ctrl->flash_state); + rc = -EINVAL; + } + } else { + if (regulator_enable && + (flash_ctrl->is_regulator_enabled == false)) { + rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Regulator enable failed rc = %d", rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = true; + } else if ((!regulator_enable) && + (flash_ctrl->is_regulator_enabled == true)) { + rc = qpnp_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, + "Regulator disable failed rc = %d", rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Flash State : %d", + flash_ctrl->flash_state); + rc = -EINVAL; + } + } + return rc; +} + +static int cam_flash_pmic_flush_nrt(struct cam_flash_ctrl *fctrl) +{ + int j = 0; + struct cam_flash_frame_setting *nrt_settings; + + if (!fctrl) + return -EINVAL; + + nrt_settings = &fctrl->nrt_info; + + if (nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO) { + fctrl->flash_init_setting.cmn_attr.is_settings_valid = false; + } else if ((nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) || + (nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_RER) || + (nrt_settings->cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE)) { + fctrl->nrt_info.cmn_attr.is_settings_valid = false; + fctrl->nrt_info.cmn_attr.count = 0; + fctrl->nrt_info.num_iterations = 0; + fctrl->nrt_info.led_on_delay_ms = 0; + fctrl->nrt_info.led_off_delay_ms = 0; + for (j = 0; j < CAM_FLASH_MAX_LED_TRIGGERS; j++) + fctrl->nrt_info.led_current_ma[j] = 0; + } + + return 0; +} + +static int cam_flash_i2c_flush_nrt(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + if (fctrl->i2c_data.init_settings.is_settings_valid == true) { + rc = delete_request(&fctrl->i2c_data.init_settings); + if (rc) { + CAM_WARN(CAM_FLASH, + "Failed to delete Init i2c_setting: %d", + rc); + return rc; + } + } + if (fctrl->i2c_data.config_settings.is_settings_valid == true) { + rc = delete_request(&fctrl->i2c_data.config_settings); + if (rc) { + CAM_WARN(CAM_FLASH, + "Failed to delete NRT i2c_setting: %d", + rc); + return rc; + } + } + + return rc; +} + +static int cam_flash_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 1; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_setting[0].seq_type = SENSOR_CUSTOM_REG1; + power_info->power_setting[0].seq_val = CAM_V_CUSTOM1; + power_info->power_setting[0].config_val = 0; + power_info->power_setting[0].delay = 2; + + power_info->power_down_setting_size = 1; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting), + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + power_info->power_down_setting[0].seq_type = SENSOR_CUSTOM_REG1; + power_info->power_down_setting[0].seq_val = CAM_V_CUSTOM1; + power_info->power_down_setting[0].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + +int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable) +{ + int rc = 0; + + if (!(fctrl->switch_trigger)) { + CAM_ERR(CAM_FLASH, "Invalid argument"); + return -EINVAL; + } + + if (regulator_enable) { + rc = cam_flash_prepare(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + fctrl->last_flush_req = 0; + } + + if (!regulator_enable) { + if ((fctrl->flash_state == CAM_FLASH_STATE_START) && + (fctrl->is_regulator_enabled == true)) { + rc = cam_flash_prepare(fctrl, false); + if (rc) + CAM_ERR(CAM_FLASH, + "Disable Regulator Failed rc: %d", rc); + } + } + + return rc; +} + +int cam_flash_i2c_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = &fctrl->soc_info; + struct cam_sensor_power_ctrl_t *power_info = + &fctrl->power_info; + + if (!power_info || !soc_info) { + CAM_ERR(CAM_FLASH, "Power Info is NULL"); + return -EINVAL; + } + power_info->dev = soc_info->dev; + + if (regulator_enable && (fctrl->is_regulator_enabled == false)) { + if ((power_info->power_setting == NULL) && + (power_info->power_down_setting == NULL)) { + CAM_INFO(CAM_FLASH, + "Using default power settings"); + rc = cam_flash_construct_default_power_setting( + power_info); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "Construct default pwr setting failed rc: %d", + rc); + return rc; + } + } + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "power up the core is failed:%d", + rc); + goto free_pwr_settings; + } + + rc = camera_io_init(&(fctrl->io_master_info)); + if (rc) { + CAM_ERR(CAM_FLASH, "cci_init failed: rc: %d", rc); + cam_sensor_util_power_down(power_info, soc_info); + goto free_pwr_settings; + } + fctrl->is_regulator_enabled = true; + } else if ((!regulator_enable) && + (fctrl->is_regulator_enabled == true)) { + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "power down the core is failed:%d", + rc); + return rc; + } + camera_io_release(&(fctrl->io_master_info)); + fctrl->is_regulator_enabled = false; + goto free_pwr_settings; + } + return rc; + +free_pwr_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + + return rc; +} + +int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id) +{ + int rc = 0; + int i = 0, j = 0; + int frame_offset = 0; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + if (type == FLUSH_ALL) { + /* flush all requests*/ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + fctrl->per_frame[i].cmn_attr.request_id = 0; + fctrl->per_frame[i].cmn_attr.is_settings_valid = false; + fctrl->per_frame[i].cmn_attr.count = 0; + for (j = 0; j < CAM_FLASH_MAX_LED_TRIGGERS; j++) + fctrl->per_frame[i].led_current_ma[j] = 0; + } + + cam_flash_pmic_flush_nrt(fctrl); + } else if ((type == FLUSH_REQ) && (req_id != 0)) { + /* flush request with req_id*/ + frame_offset = req_id % MAX_PER_FRAME_ARRAY; + fctrl->per_frame[frame_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid = + false; + fctrl->per_frame[frame_offset].cmn_attr.count = 0; + for (i = 0; i < CAM_FLASH_MAX_LED_TRIGGERS; i++) + fctrl->per_frame[frame_offset].led_current_ma[i] = 0; + } else if ((type == FLUSH_REQ) && (req_id == 0)) { + /* Handels NonRealTime usecase */ + cam_flash_pmic_flush_nrt(fctrl); + } else { + CAM_ERR(CAM_FLASH, "Invalid arguments"); + return -EINVAL; + } + + return rc; +} + +int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id) +{ + int rc = 0; + int i = 0; + uint32_t cancel_req_id_found = 0; + struct i2c_settings_array *i2c_set = NULL; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + if ((type == FLUSH_REQ) && (req_id == 0)) { + /* This setting will be called only when NonRealTime + * settings needs to clean. + */ + cam_flash_i2c_flush_nrt(fctrl); + } else { + /* All other usecase will be handle here */ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(fctrl->i2c_data.per_frame[i]); + + if ((type == FLUSH_REQ) && + (i2c_set->request_id != req_id)) + continue; + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_FLASH, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + + if (type == FLUSH_REQ) { + cancel_req_id_found = 1; + break; + } + } + } + } + + if ((type == FLUSH_REQ) && (req_id != 0) && + (!cancel_req_id_found)) + CAM_DBG(CAM_FLASH, + "Flush request id:%lld not found in the pending list", + req_id); + + return rc; +} + +int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush) +{ + int rc = 0; + struct cam_flash_ctrl *fctrl = NULL; + + fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(flush->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + if (fctrl->flash_state == CAM_FLASH_STATE_INIT) + goto end; + + if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + fctrl->last_flush_req = flush->req_id; + CAM_DBG(CAM_FLASH, "last reqest to flush is %lld", + flush->req_id); + rc = fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + if (rc) { + CAM_ERR(CAM_FLASH, "FLUSH_TYPE_ALL failed rc: %d", rc); + goto end; + } + } else if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + rc = fctrl->func_tbl.flush_req(fctrl, + FLUSH_REQ, flush->req_id); + if (rc) { + CAM_ERR(CAM_FLASH, "FLUSH_REQ failed rc: %d", rc); + goto end; + } + } +end: + mutex_unlock(&fctrl->flash_mutex); + return rc; +} + +static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, + struct cam_flash_frame_setting *flash_data, enum camera_flash_opcode op) +{ + uint32_t curr = 0, max_current = 0; + struct cam_flash_private_soc *soc_private = NULL; + int i = 0; + + if (!flash_ctrl || !flash_data) { + CAM_ERR(CAM_FLASH, "Fctrl or Data NULL"); + return -EINVAL; + } + + soc_private = (struct cam_flash_private_soc *) + flash_ctrl->soc_info.soc_private; + + if (op == CAMERA_SENSOR_FLASH_OP_FIRELOW) { + for (i = 0; i < flash_ctrl->torch_num_sources; i++) { + if (flash_ctrl->torch_trigger[i]) { + max_current = soc_private->torch_max_current[i]; + if (flash_data->led_current_ma[i] <= + max_current) + curr = flash_data->led_current_ma[i]; + else + curr = max_current; + } + CAM_DBG(CAM_FLASH, "Led_Torch[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->torch_trigger[i], curr); + } + } else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + for (i = 0; i < flash_ctrl->flash_num_sources; i++) { + if (flash_ctrl->flash_trigger[i]) { + max_current = soc_private->flash_max_current[i]; + if (flash_data->led_current_ma[i] <= + max_current) + curr = flash_data->led_current_ma[i]; + else + curr = max_current; + } + CAM_DBG(CAM_FLASH, "LED_Flash[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->flash_trigger[i], curr); + } + } else { + CAM_ERR(CAM_FLASH, "Wrong Operation: %d", op); + return -EINVAL; + } + + if (flash_ctrl->switch_trigger) + cam_res_mgr_led_trigger_event( + flash_ctrl->switch_trigger, + (enum led_brightness)LED_SWITCH_ON); + + return 0; +} + +int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) +{ + if (!flash_ctrl) { + CAM_ERR(CAM_FLASH, "Flash control Null"); + return -EINVAL; + } + + if (flash_ctrl->switch_trigger) + cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, + (enum led_brightness)LED_SWITCH_OFF); + + flash_ctrl->flash_state = CAM_FLASH_STATE_START; + return 0; +} + +static int cam_flash_low( + struct cam_flash_ctrl *flash_ctrl, + struct cam_flash_frame_setting *flash_data) +{ + int i = 0, rc = 0; + + if (!flash_data) { + CAM_ERR(CAM_FLASH, "Flash Data Null"); + return -EINVAL; + } + + for (i = 0; i < flash_ctrl->flash_num_sources; i++) + if (flash_ctrl->flash_trigger[i]) + cam_res_mgr_led_trigger_event( + flash_ctrl->flash_trigger[i], + LED_OFF); + + rc = cam_flash_ops(flash_ctrl, flash_data, + CAMERA_SENSOR_FLASH_OP_FIRELOW); + if (rc) + CAM_ERR(CAM_FLASH, "Fire Torch failed: %d", rc); + + return rc; +} + +static int cam_flash_high( + struct cam_flash_ctrl *flash_ctrl, + struct cam_flash_frame_setting *flash_data) +{ + int i = 0, rc = 0; + + if (!flash_data) { + CAM_ERR(CAM_FLASH, "Flash Data Null"); + return -EINVAL; + } + + for (i = 0; i < flash_ctrl->torch_num_sources; i++) + if (flash_ctrl->torch_trigger[i]) + cam_res_mgr_led_trigger_event( + flash_ctrl->torch_trigger[i], + LED_OFF); + + rc = cam_flash_ops(flash_ctrl, flash_data, + CAMERA_SENSOR_FLASH_OP_FIREHIGH); + if (rc) + CAM_ERR(CAM_FLASH, "Fire Flash Failed: %d", rc); + + return rc; +} + +static int cam_flash_i2c_delete_req(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + int i = 0, rc = 0; + uint64_t top = 0, del_req_id = 0; + + if (req_id != 0) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((req_id >= + fctrl->i2c_data.per_frame[i].request_id) && + (top < + fctrl->i2c_data.per_frame[i].request_id) && + (fctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + del_req_id = top; + top = fctrl->i2c_data.per_frame[i].request_id; + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return rc; + + CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", + top, del_req_id); + } + fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + return 0; +} + +static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + int i = 0; + struct cam_flash_frame_setting *flash_data = NULL; + uint64_t top = 0, del_req_id = 0; + + if (req_id != 0) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + flash_data = &fctrl->per_frame[i]; + if (req_id >= flash_data->cmn_attr.request_id && + flash_data->cmn_attr.is_settings_valid + == 1) { + if (top < flash_data->cmn_attr.request_id) { + del_req_id = top; + top = flash_data->cmn_attr.request_id; + } else if (top > + flash_data->cmn_attr.request_id && + del_req_id < + flash_data->cmn_attr.request_id) { + del_req_id = + flash_data->cmn_attr.request_id; + } + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return 0; + + CAM_DBG(CAM_FLASH, "top: %llu, del_req_id:%llu", + top, del_req_id); + } + + fctrl->func_tbl.flush_req(fctrl, FLUSH_REQ, del_req_id); + return 0; +} + +static int32_t cam_flash_slaveInfo_pkt_parser(struct cam_flash_ctrl *fctrl, + uint32_t *cmd_buf, size_t len) +{ + int32_t rc = 0; + struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + + if (len < sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + if (fctrl->io_master_info.master_type == CCI_MASTER) { + fctrl->io_master_info.cci_client->cci_i2c_master = + fctrl->cci_i2c_master; + fctrl->io_master_info.cci_client->i2c_freq_mode = + i2c_info->i2c_freq_mode; + fctrl->io_master_info.cci_client->sid = + i2c_info->slave_addr >> 1; + CAM_DBG(CAM_FLASH, "Slave addr: 0x%x Freq Mode: %d", + i2c_info->slave_addr, i2c_info->i2c_freq_mode); + } else if (fctrl->io_master_info.master_type == I2C_MASTER) { + fctrl->io_master_info.client->addr = i2c_info->slave_addr; + CAM_DBG(CAM_FLASH, "Slave addr: 0x%x", i2c_info->slave_addr); + } else { + CAM_ERR(CAM_FLASH, "Invalid Master type: %d", + fctrl->io_master_info.master_type); + rc = -EINVAL; + } + + return rc; +} + +int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + struct i2c_settings_list *i2c_list; + struct i2c_settings_array *i2c_set = NULL; + int frame_offset = 0, rc = 0; + + if (req_id == 0) { + /* NonRealTime Init settings*/ + if (fctrl->i2c_data.init_settings.is_settings_valid == true) { + list_for_each_entry(i2c_list, + &(fctrl->i2c_data.init_settings.list_head), + list) { + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + if ((rc == -EAGAIN) && + (fctrl->io_master_info.master_type == + CCI_MASTER)) { + CAM_WARN(CAM_FLASH, + "CCI HW is in reset mode: Reapplying Init settings"); + usleep_range(5000, 5010); + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + } + + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply init settings: %d", + rc); + return rc; + } + } + } + /* NonRealTime (Widget/RER/INIT_FIRE settings) */ + if (fctrl->i2c_data.config_settings.is_settings_valid == true) { + list_for_each_entry(i2c_list, + &(fctrl->i2c_data.config_settings.list_head), + list) { + rc = cam_sensor_util_i2c_apply_setting + (&(fctrl->io_master_info), i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply NRT settings: %d", rc); + return rc; + } + } + } + } else { + /* RealTime */ + frame_offset = req_id % MAX_PER_FRAME_ARRAY; + i2c_set = &fctrl->i2c_data.per_frame[frame_offset]; + if ((i2c_set->is_settings_valid == true) && + (i2c_set->request_id == req_id)) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_util_i2c_apply_setting( + &(fctrl->io_master_info), i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply settings: %d", rc); + return rc; + } + } + } + } + + cam_flash_i2c_delete_req(fctrl, req_id); + return rc; +} + +int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, + uint64_t req_id) +{ + int rc = 0, i = 0; + int frame_offset = 0; + uint16_t num_iterations; + struct cam_flash_frame_setting *flash_data = NULL; + + if (req_id == 0) { + if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE) { + flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_INIT_FIRE req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + if (fctrl->flash_state == + CAM_FLASH_STATE_START) { + CAM_WARN(CAM_FLASH, + "Wrong state :Prev state: %d", + fctrl->flash_state); + return -EINVAL; + } + + rc = cam_flash_high(fctrl, flash_data); + if (rc) + CAM_ERR(CAM_FLASH, + "FLASH ON failed : %d", rc); + } + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIRELOW) { + if (fctrl->flash_state == + CAM_FLASH_STATE_START) { + CAM_WARN(CAM_FLASH, + "Wrong state :Prev state: %d", + fctrl->flash_state); + return -EINVAL; + } + + rc = cam_flash_low(fctrl, flash_data); + if (rc) + CAM_ERR(CAM_FLASH, + "TORCH ON failed : %d", rc); + } + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "LED OFF FAILED: %d", + rc); + return rc; + } + } + } else if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) { + flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_WIDGET req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIRELOW) { + rc = cam_flash_low(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Torch ON failed : %d", + rc); + goto nrt_del_req; + } + } else if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_OFF) { + rc = cam_flash_off(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, + "LED off failed: %d", + rc); + } + } else if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_RER) { + flash_data = &fctrl->nrt_info; + if (fctrl->flash_state != CAM_FLASH_STATE_START) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash off failed: %d", + rc); + goto nrt_del_req; + } + } + CAM_DBG(CAM_REQ, "FLASH_RER req_id: %u", req_id); + + num_iterations = flash_data->num_iterations; + for (i = 0; i < num_iterations; i++) { + /* Turn On Torch */ + if (fctrl->flash_state == + CAM_FLASH_STATE_START) { + rc = cam_flash_low(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Fire Torch Failed"); + goto nrt_del_req; + } + + usleep_range( + flash_data->led_on_delay_ms * 1000, + flash_data->led_on_delay_ms * 1000 + + 100); + } + /* Turn Off Torch */ + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash off failed: %d", rc); + continue; + } + fctrl->flash_state = CAM_FLASH_STATE_START; + usleep_range( + flash_data->led_off_delay_ms * 1000, + flash_data->led_off_delay_ms * 1000 + 100); + } + } + } else { + frame_offset = req_id % MAX_PER_FRAME_ARRAY; + flash_data = &fctrl->per_frame[frame_offset]; + CAM_DBG(CAM_REQ, "FLASH_RT req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + + if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) && + (flash_data->cmn_attr.is_settings_valid) && + (flash_data->cmn_attr.request_id == req_id)) { + /* Turn On Flash */ + if (fctrl->flash_state == CAM_FLASH_STATE_START) { + rc = cam_flash_high(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash ON failed: rc= %d", + rc); + goto apply_setting_err; + } + } + } else if ((flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIRELOW) && + (flash_data->cmn_attr.is_settings_valid) && + (flash_data->cmn_attr.request_id == req_id)) { + /* Turn On Torch */ + if (fctrl->flash_state == CAM_FLASH_STATE_START) { + rc = cam_flash_low(fctrl, flash_data); + if (rc) { + CAM_ERR(CAM_FLASH, + "Torch ON failed: rc= %d", + rc); + goto apply_setting_err; + } + } + } else if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) && + (flash_data->cmn_attr.is_settings_valid) && + (flash_data->cmn_attr.request_id == req_id)) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "Flash off failed %d", rc); + goto apply_setting_err; + } + } else if (flash_data->opcode == CAM_PKT_NOP_OPCODE) { + CAM_DBG(CAM_FLASH, "NOP Packet"); + } else { + rc = -EINVAL; + CAM_ERR(CAM_FLASH, "Invalid opcode: %d req_id: %llu", + flash_data->opcode, req_id); + goto apply_setting_err; + } + } + +nrt_del_req: + cam_flash_pmic_delete_req(fctrl, req_id); +apply_setting_err: + return rc; +} + +int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) +{ + int rc = 0, i = 0; + uintptr_t generic_ptr; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + uint16_t cmd_length_in_bytes = 0; + uint32_t *cmd_buf = NULL; + uint32_t *offset = NULL; + uint32_t frm_offset = 0; + size_t len_of_buffer; + size_t remain_len; + struct cam_flash_init *flash_init = NULL; + struct common_header *cmn_hdr = NULL; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_config_dev_cmd config; + struct cam_req_mgr_add_request add_req; + struct i2c_data_settings *i2c_data = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + if (!fctrl || !arg) { + CAM_ERR(CAM_FLASH, "fctrl/arg is NULL"); + return -EINVAL; + } + /* getting CSL Packet */ + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user((&config), (void __user *) ioctl_ctrl->handle, + sizeof(config))) { + CAM_ERR(CAM_FLASH, "Copy cmd handle from user failed"); + return -EFAULT; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed in getting the packet : %d", rc); + return rc; + } + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_FLASH, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); + return -EINVAL; + } + + remain_len -= (size_t)config.offset; + /* Add offset to the flash csl header */ + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + return -EINVAL; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_DBG(CAM_FLASH, + "reject request %lld, last request to flush %lld", + csl_packet->header.request_id, fctrl->last_flush_req); + return -EINVAL; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_FLASH_PACKET_OPCODE_INIT: { + /* INIT packet*/ + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 1; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + processed_cmd_buf_in_bytes = 0; + if (!total_cmd_buf_in_bytes) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buffer); + if (rc < 0) { + CAM_ERR(CAM_FLASH, "Failed to get cpu buf"); + return rc; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_FLASH, "invalid cmd buf"); + return -EINVAL; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buffer - + sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "invalid cmd buf length"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + cmn_hdr = (struct common_header *)cmd_buf; + + /* Loop through cmd formats in one cmd buffer */ + CAM_DBG(CAM_FLASH, + "command Type: %d,Processed: %d,Total: %d", + cmn_hdr->cmd_type, processed_cmd_buf_in_bytes, + total_cmd_buf_in_bytes); + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: + if (len_of_buffer < + sizeof(struct cam_flash_init)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + + flash_init = (struct cam_flash_init *)cmd_buf; + fctrl->flash_type = flash_init->flash_type; + cmd_length_in_bytes = + sizeof(struct cam_flash_init); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + break; + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + rc = cam_flash_slaveInfo_pkt_parser( + fctrl, cmd_buf, remain_len); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "Failed parsing slave info: rc: %d", + rc); + return rc; + } + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + CAM_DBG(CAM_FLASH, + "Received power settings"); + cmd_length_in_bytes = + total_cmd_buf_in_bytes; + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + &fctrl->power_info, remain_len); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed update power settings"); + return rc; + } + break; + default: + CAM_DBG(CAM_FLASH, + "Received initSettings"); + i2c_data = &(fctrl->i2c_data); + i2c_reg_settings = + &fctrl->i2c_data.init_settings; + + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + rc = cam_sensor_i2c_command_parser( + &fctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "pkt parsing failed: %d", rc); + return rc; + } + cmd_length_in_bytes = + cmd_desc[i].length; + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/ + sizeof(uint32_t); + + break; + } + } + power_info = &fctrl->power_info; + if (!power_info) { + CAM_ERR(CAM_FLASH, "Power_info is NULL"); + return -EINVAL; + } + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params(&fctrl->soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed to fill vreg params for power up rc:%d", + rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + &fctrl->soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed to fill vreg params power down rc:%d", + rc); + return rc; + } + + rc = fctrl->func_tbl.power_ops(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) { + CAM_ERR(CAM_FLASH, "cannot apply settings rc = %d", rc); + return rc; + } + + fctrl->flash_state = CAM_FLASH_STATE_CONFIG; + break; + } + case CAM_FLASH_PACKET_OPCODE_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + /* add support for handling i2c_data*/ + i2c_reg_settings = + &fctrl->i2c_data.per_frame[frm_offset]; + if (i2c_reg_settings->is_settings_valid == true) { + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = false; + goto update_req_mgr; + } + i2c_reg_settings->is_settings_valid = true; + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &fctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in parsing i2c packets"); + return rc; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + + /* add support for handling i2c_data*/ + i2c_reg_settings = &fctrl->i2c_data.config_settings; + if (i2c_reg_settings->is_settings_valid == true) { + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = false; + + rc = delete_request(i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in Deleting the err: %d", rc); + return rc; + } + } + i2c_reg_settings->is_settings_valid = true; + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_sensor_i2c_command_parser( + &fctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed in parsing i2c NRT packets"); + return rc; + } + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, + "Apply setting failed: %d", rc); + return rc; + } + case CAM_PKT_NOP_OPCODE: { + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { + CAM_WARN(CAM_FLASH, + "Rxed NOP packets without linking"); + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + fctrl->i2c_data.per_frame[frm_offset].is_settings_valid + = false; + return 0; + } + + CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u", + csl_packet->header.request_id); + goto update_req_mgr; + } + default: + CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", + (csl_packet->header.op_code & 0xFFFFFF)); + return -EINVAL; + } +update_req_mgr: + if (((csl_packet->header.op_code & 0xFFFFF) == + CAM_PKT_NOP_OPCODE) || + ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS)) { + add_req.link_hdl = fctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = fctrl->bridge_intf.device_hdl; + + if ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS) + add_req.skip_before_applying = 1; + else + add_req.skip_before_applying = 0; + + if (fctrl->bridge_intf.crm_cb && + fctrl->bridge_intf.crm_cb->add_req) + fctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id); + } + return rc; +} + +int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) +{ + int rc = 0, i = 0; + uintptr_t generic_ptr, cmd_buf_ptr; + uint32_t *cmd_buf = NULL; + uint32_t *offset = NULL; + uint32_t frm_offset = 0; + size_t len_of_buffer; + size_t remain_len; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct common_header *cmn_hdr; + struct cam_config_dev_cmd config; + struct cam_req_mgr_add_request add_req = {0}; + struct cam_flash_init *cam_flash_info = NULL; + struct cam_flash_set_rer *flash_rer_info = NULL; + struct cam_flash_set_on_off *flash_operation_info = NULL; + struct cam_flash_query_curr *flash_query_info = NULL; + struct cam_flash_frame_setting *flash_data = NULL; + struct cam_flash_private_soc *soc_private = NULL; + + if (!fctrl || !arg) { + CAM_ERR(CAM_FLASH, "fctrl/arg is NULL"); + return -EINVAL; + } + + soc_private = (struct cam_flash_private_soc *) + fctrl->soc_info.soc_private; + + /* getting CSL Packet */ + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user((&config), + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) { + CAM_ERR(CAM_FLASH, "Copy cmd handle from user failed"); + rc = -EFAULT; + return rc; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed in getting the packet: %d", rc); + return rc; + } + + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_FLASH, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); + rc = -EINVAL; + return rc; + } + + remain_len -= (size_t)config.offset; + /* Add offset to the flash csl header */ + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + rc = -EINVAL; + return rc; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_WARN(CAM_FLASH, + "reject request %lld, last request to flush %d", + csl_packet->header.request_id, fctrl->last_flush_req); + rc = -EINVAL; + return rc; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_FLASH_PACKET_OPCODE_INIT: { + /* INIT packet*/ + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + return rc; + } + if ((len_of_buffer < sizeof(struct cam_flash_init)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct cam_flash_init)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + cam_flash_info = (struct cam_flash_init *)cmd_buf; + + switch (cam_flash_info->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: { + CAM_DBG(CAM_FLASH, "INIT_INFO CMD CALLED"); + fctrl->flash_init_setting.cmn_attr.request_id = 0; + fctrl->flash_init_setting.cmn_attr.is_settings_valid = + true; + fctrl->flash_type = cam_flash_info->flash_type; + fctrl->is_regulator_enabled = false; + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO; + + rc = fctrl->func_tbl.power_ops(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + + fctrl->flash_state = + CAM_FLASH_STATE_CONFIG; + break; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: { + CAM_DBG(CAM_FLASH, "INIT_FIRE Operation"); + + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + fctrl->nrt_info.cmn_attr.count = + flash_operation_info->count; + fctrl->nrt_info.cmn_attr.request_id = 0; + fctrl->nrt_info.opcode = + flash_operation_info->opcode; + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE; + for (i = 0; + i < flash_operation_info->count; i++) + fctrl->nrt_info.led_current_ma[i] = + flash_operation_info->led_current_ma[i]; + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, + "Apply setting failed: %d", + rc); + + fctrl->flash_state = CAM_FLASH_STATE_CONFIG; + break; + } + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", + cam_flash_info->cmd_type); + rc = -EINVAL; + return rc; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + flash_data = &fctrl->per_frame[frm_offset]; + + if (flash_data->cmn_attr.is_settings_valid == true) { + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + for (i = 0; i < flash_data->cmn_attr.count; i++) + flash_data->led_current_ma[i] = 0; + } + + flash_data->cmn_attr.request_id = csl_packet->header.request_id; + flash_data->cmn_attr.is_settings_valid = true; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: 0x%x", + cmd_desc->mem_handle); + return rc; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "not enough buffer"); + rc = -EINVAL; + return rc; + } + remain_len = len_of_buffer - cmd_desc->offset; + + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + if (!cmd_buf) { + rc = -EINVAL; + return rc; + } + cmn_hdr = (struct common_header *)cmd_buf; + + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: { + CAM_DBG(CAM_FLASH, + "CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE cmd called"); + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == + CAM_FLASH_STATE_ACQUIRE)) { + CAM_WARN(CAM_FLASH, + "Rxed Flash fire ops without linking"); + flash_data->cmn_attr.is_settings_valid = false; + return -EINVAL; + } + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + + flash_data->opcode = flash_operation_info->opcode; + flash_data->cmn_attr.count = + flash_operation_info->count; + for (i = 0; i < flash_operation_info->count; i++) + flash_data->led_current_ma[i] + = flash_operation_info->led_current_ma[i]; + + if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_OFF) + add_req.skip_before_applying |= SKIP_NEXT_FRAME; + } + break; + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", + cmn_hdr->cmd_type); + rc = -EINVAL; + return rc; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + fctrl->nrt_info.cmn_attr.is_settings_valid = true; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + return rc; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + cmn_hdr = (struct common_header *)cmd_buf; + + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET: { + CAM_DBG(CAM_FLASH, "Widget Flash Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + + fctrl->nrt_info.cmn_attr.count = + flash_operation_info->count; + fctrl->nrt_info.cmn_attr.request_id = 0; + fctrl->nrt_info.opcode = + flash_operation_info->opcode; + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET; + + for (i = 0; i < flash_operation_info->count; i++) + fctrl->nrt_info.led_current_ma[i] = + flash_operation_info->led_current_ma[i]; + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, "Apply setting failed: %d", + rc); + return rc; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR: { + int query_curr_ma = 0; + + if (remain_len < sizeof(struct cam_flash_query_curr)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + flash_query_info = + (struct cam_flash_query_curr *)cmd_buf; + + if (soc_private->is_wled_flash) + rc = wled_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + else + rc = qpnp_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + + CAM_DBG(CAM_FLASH, "query_curr_ma = %d", + query_curr_ma); + if (rc) { + CAM_ERR(CAM_FLASH, + "Query current failed with rc=%d", rc); + return rc; + } + flash_query_info->query_current_ma = query_curr_ma; + break; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_RER: { + rc = 0; + if (remain_len < sizeof(struct cam_flash_set_rer)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + return rc; + } + flash_rer_info = (struct cam_flash_set_rer *)cmd_buf; + if (!flash_rer_info) { + CAM_ERR(CAM_FLASH, + "flash_rer_info Null"); + rc = -EINVAL; + return rc; + } + if (flash_rer_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + return rc; + } + + fctrl->nrt_info.cmn_attr.cmd_type = + CAMERA_SENSOR_FLASH_CMD_TYPE_RER; + fctrl->nrt_info.opcode = flash_rer_info->opcode; + fctrl->nrt_info.cmn_attr.count = flash_rer_info->count; + fctrl->nrt_info.cmn_attr.request_id = 0; + fctrl->nrt_info.num_iterations = + flash_rer_info->num_iteration; + fctrl->nrt_info.led_on_delay_ms = + flash_rer_info->led_on_delay_ms; + fctrl->nrt_info.led_off_delay_ms = + flash_rer_info->led_off_delay_ms; + + for (i = 0; i < flash_rer_info->count; i++) + fctrl->nrt_info.led_current_ma[i] = + flash_rer_info->led_current_ma[i]; + + rc = fctrl->func_tbl.apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed: %d", + rc); + return rc; + } + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type : %d", + cmn_hdr->cmd_type); + rc = -EINVAL; + return rc; + } + + break; + } + case CAM_PKT_NOP_OPCODE: { + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { + CAM_WARN(CAM_FLASH, + "Rxed NOP packets without linking"); + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid + = false; + return -EINVAL; + } + + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; + fctrl->per_frame[frm_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; + CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %llu", + csl_packet->header.request_id); + break; + } + default: + CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", + (csl_packet->header.op_code & 0xFFFFFF)); + rc = -EINVAL; + return rc; + } + + if (((csl_packet->header.op_code & 0xFFFFF) == + CAM_PKT_NOP_OPCODE) || + ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS)) { + add_req.link_hdl = fctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = fctrl->bridge_intf.device_hdl; + + if ((csl_packet->header.op_code & 0xFFFFF) == + CAM_FLASH_PACKET_OPCODE_SET_OPS) + add_req.skip_before_applying |= 1; + else + add_req.skip_before_applying = 0; + + if (fctrl->bridge_intf.crm_cb && + fctrl->bridge_intf.crm_cb->add_req) + fctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id); + } + + return rc; +} + +int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + info->dev_id = CAM_REQ_MGR_DEVICE_FLASH; + strlcpy(info->name, CAM_FLASH_NAME, sizeof(info->name)); + info->p_delay = CAM_FLASH_PIPELINE_DELAY; + info->trigger = CAM_TRIGGER_POINT_SOF; + return 0; +} + +int cam_flash_establish_link(struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_flash_ctrl *fctrl = NULL; + + if (!link) + return -EINVAL; + + fctrl = (struct cam_flash_ctrl *)cam_get_device_priv(link->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, " Device data is NULL"); + return -EINVAL; + } + mutex_lock(&fctrl->flash_mutex); + if (link->link_enable) { + fctrl->bridge_intf.link_hdl = link->link_hdl; + fctrl->bridge_intf.crm_cb = link->crm_cb; + } else { + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.crm_cb = NULL; + } + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + +int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + if (fctrl->bridge_intf.device_hdl != 1) { + rc = cam_destroy_device_hdl(fctrl->bridge_intf.device_hdl); + if (rc) + CAM_ERR(CAM_FLASH, + "Failed in destroying device handle rc = %d", + rc); + fctrl->bridge_intf.device_hdl = -1; + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.session_hdl = -1; + fctrl->last_flush_req = 0; + } + + return rc; +} + +void cam_flash_shutdown(struct cam_flash_ctrl *fctrl) +{ + int rc; + + if (fctrl->flash_state == CAM_FLASH_STATE_INIT) + return; + + if ((fctrl->flash_state == CAM_FLASH_STATE_CONFIG) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) { + fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + rc = fctrl->func_tbl.power_ops(fctrl, false); + if (rc) + CAM_ERR(CAM_FLASH, "Power Down Failed rc: %d", + rc); + } + + rc = cam_flash_release_dev(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, "Release failed rc: %d", rc); + + fctrl->flash_state = CAM_FLASH_STATE_INIT; +} + +int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int rc = 0; + struct cam_flash_ctrl *fctrl = NULL; + + if (!apply) + return -EINVAL; + + fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(apply->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + rc = fctrl->func_tbl.apply_setting(fctrl, apply->request_id); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", + rc); + mutex_unlock(&fctrl->flash_mutex); + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.h b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.h new file mode 100644 index 0000000000000000000000000000000000000000..c382809dbb92199df12dead139795e7632cb8bcc --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FLASH_CORE_H_ +#define _CAM_FLASH_CORE_H_ + +#include <media/cam_sensor.h> +#include "cam_flash_dev.h" + +int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info); +int cam_flash_establish_link(struct cam_req_mgr_core_dev_link_setup *link); +int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply); +int cam_flash_process_evt(struct cam_req_mgr_link_evt_data *event_data); +int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush); + + +#endif /*_CAM_FLASH_CORE_H_*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..5eccfd8aa11bb3ebd190aa192cccaf1d5ae23896 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include "cam_flash_dev.h" +#include "cam_flash_soc.h" +#include "cam_flash_core.h" +#include "cam_common_util.h" + +static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, + void *arg, struct cam_flash_private_soc *soc_private) +{ + int rc = 0; + int i = 0; + struct cam_control *cmd = (struct cam_control *)arg; + + if (!fctrl || !arg) { + CAM_ERR(CAM_FLASH, "fctrl/arg is NULL with arg:%pK fctrl%pK", + fctrl, arg); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_FLASH, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + mutex_lock(&(fctrl->flash_mutex)); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev flash_acq_dev; + struct cam_create_dev_hdl bridge_params; + + CAM_DBG(CAM_FLASH, "CAM_ACQUIRE_DEV"); + + if (fctrl->flash_state != CAM_FLASH_STATE_INIT) { + CAM_ERR(CAM_FLASH, + "Cannot apply Acquire dev: Prev state: %d", + fctrl->flash_state); + rc = -EINVAL; + goto release_mutex; + } + + if (fctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_FLASH, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + + rc = copy_from_user(&flash_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(flash_acq_dev)); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Copying from User"); + goto release_mutex; + } + + bridge_params.session_hdl = flash_acq_dev.session_handle; + bridge_params.ops = &fctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = fctrl; + + flash_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + fctrl->bridge_intf.device_hdl = + flash_acq_dev.device_handle; + fctrl->bridge_intf.session_hdl = + flash_acq_dev.session_handle; + + rc = copy_to_user(u64_to_user_ptr(cmd->handle), + &flash_acq_dev, + sizeof(struct cam_sensor_acquire_dev)); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Copy to User with rc = %d", + rc); + rc = -EFAULT; + goto release_mutex; + } + fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; + break; + } + case CAM_RELEASE_DEV: { + CAM_DBG(CAM_FLASH, "CAM_RELEASE_DEV"); + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) { + CAM_WARN(CAM_FLASH, + "Wrong state for Release dev: Prev state:%d", + fctrl->flash_state); + } + + if (fctrl->bridge_intf.device_hdl == -1 && + fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE) { + CAM_ERR(CAM_FLASH, + "Invalid Handle: Link Hdl: %d device hdl: %d", + fctrl->bridge_intf.device_hdl, + fctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + + if (fctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_FLASH, + "Device [%d] still active on link 0x%x", + fctrl->flash_state, + fctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + if ((fctrl->flash_state == CAM_FLASH_STATE_CONFIG) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) + fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + + if (cam_flash_release_dev(fctrl)) + CAM_WARN(CAM_FLASH, + "Failed in destroying the device Handle"); + + if (fctrl->func_tbl.power_ops(fctrl, false)) + CAM_WARN(CAM_FLASH, "Power Down Failed"); + + fctrl->flash_state = CAM_FLASH_STATE_INIT; + break; + } + case CAM_QUERY_CAP: { + struct cam_flash_query_cap_info flash_cap = {0}; + + CAM_DBG(CAM_FLASH, "CAM_QUERY_CAP"); + flash_cap.slot_info = fctrl->soc_info.index; + for (i = 0; i < fctrl->flash_num_sources; i++) { + flash_cap.max_current_flash[i] = + soc_private->flash_max_current[i]; + flash_cap.max_duration_flash[i] = + soc_private->flash_max_duration[i]; + } + + for (i = 0; i < fctrl->torch_num_sources; i++) + flash_cap.max_current_torch[i] = + soc_private->torch_max_current[i]; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &flash_cap, sizeof(struct cam_flash_query_cap_info))) { + CAM_ERR(CAM_FLASH, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + break; + } + case CAM_START_DEV: { + CAM_DBG(CAM_FLASH, "CAM_START_DEV"); + if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || + (fctrl->flash_state == CAM_FLASH_STATE_START)) { + CAM_WARN(CAM_FLASH, + "Cannot apply Start Dev: Prev state: %d", + fctrl->flash_state); + rc = -EINVAL; + goto release_mutex; + } + + fctrl->flash_state = CAM_FLASH_STATE_START; + break; + } + case CAM_STOP_DEV: { + CAM_DBG(CAM_FLASH, "CAM_STOP_DEV ENTER"); + if (fctrl->flash_state != CAM_FLASH_STATE_START) { + CAM_WARN(CAM_FLASH, + "Cannot apply Stop dev: Prev state is: %d", + fctrl->flash_state); + rc = -EINVAL; + goto release_mutex; + } + + cam_flash_off(fctrl); + fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + fctrl->last_flush_req = 0; + fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; + break; + } + case CAM_CONFIG_DEV: { + CAM_DBG(CAM_FLASH, "CAM_CONFIG_DEV"); + rc = fctrl->func_tbl.parser(fctrl, arg); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Flash Config: rc=%d\n", rc); + goto release_mutex; + } + break; + } + default: + CAM_ERR(CAM_FLASH, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + } + +release_mutex: + mutex_unlock(&(fctrl->flash_mutex)); + return rc; +} + +static int32_t cam_flash_init_default_params(struct cam_flash_ctrl *fctrl) +{ + /* Validate input parameters */ + if (!fctrl) { + CAM_ERR(CAM_FLASH, "failed: invalid params fctrl %pK", + fctrl); + return -EINVAL; + } + + CAM_DBG(CAM_FLASH, + "master_type: %d", fctrl->io_master_info.master_type); + /* Initialize cci_client */ + if (fctrl->io_master_info.master_type == CCI_MASTER) { + fctrl->io_master_info.cci_client = kzalloc(sizeof( + struct cam_sensor_cci_client), GFP_KERNEL); + if (!(fctrl->io_master_info.cci_client)) + return -ENOMEM; + } else if (fctrl->io_master_info.master_type == I2C_MASTER) { + if (!(fctrl->io_master_info.client)) + return -EINVAL; + } else { + CAM_ERR(CAM_FLASH, + "Invalid master / Master type Not supported"); + return -EINVAL; + } + + return 0; +} + +static const struct of_device_id cam_flash_dt_match[] = { + {.compatible = "qcom,camera-flash", .data = NULL}, + {} +}; + +static long cam_flash_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_flash_ctrl *fctrl = NULL; + struct cam_flash_private_soc *soc_private = NULL; + + CAM_DBG(CAM_FLASH, "Enter"); + + fctrl = v4l2_get_subdevdata(sd); + soc_private = fctrl->soc_info.soc_private; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: { + rc = cam_flash_driver_cmd(fctrl, arg, + soc_private); + break; + } + default: + CAM_ERR(CAM_FLASH, "Invalid ioctl cmd type"); + rc = -EINVAL; + break; + } + + CAM_DBG(CAM_FLASH, "Exit"); + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_flash_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_FLASH, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: { + rc = cam_flash_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) + CAM_ERR(CAM_FLASH, "cam_flash_ioctl failed"); + break; + } + default: + CAM_ERR(CAM_FLASH, "Invalid compat ioctl cmd_type:%d", + cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_FLASH, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static int cam_flash_platform_remove(struct platform_device *pdev) +{ + struct cam_flash_ctrl *fctrl; + + fctrl = platform_get_drvdata(pdev); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash device is NULL"); + return 0; + } + + CAM_INFO(CAM_FLASH, "Platform remove invoked"); + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + cam_unregister_subdev(&(fctrl->v4l2_dev_str)); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&fctrl->v4l2_dev_str.sd, NULL); + kfree(fctrl); + + return 0; +} + +static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) +{ + int32_t rc = 0; + struct cam_flash_ctrl *fctrl = i2c_get_clientdata(client); + /* Handle I2C Devices */ + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_FLASH, "i2c driver remove invoked"); + /*Free Allocated Mem */ + kfree(fctrl->i2c_data.per_frame); + fctrl->i2c_data.per_frame = NULL; + kfree(fctrl); + return rc; +} + +static int cam_flash_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_flash_ctrl *fctrl = + v4l2_get_subdevdata(sd); + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_flash_subdev_core_ops = { + .ioctl = cam_flash_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_flash_subdev_do_ioctl +#endif +}; + +static struct v4l2_subdev_ops cam_flash_subdev_ops = { + .core = &cam_flash_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_flash_internal_ops = { + .close = cam_flash_subdev_close, +}; + +static int cam_flash_init_subdev(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + strlcpy(fctrl->device_name, CAM_FLASH_NAME, + sizeof(fctrl->device_name)); + fctrl->v4l2_dev_str.internal_ops = + &cam_flash_internal_ops; + fctrl->v4l2_dev_str.ops = &cam_flash_subdev_ops; + fctrl->v4l2_dev_str.name = CAMX_FLASH_DEV_NAME; + fctrl->v4l2_dev_str.sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + fctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE; + fctrl->v4l2_dev_str.token = fctrl; + + rc = cam_register_subdev(&(fctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_FLASH, "Fail to create subdev with %d", rc); + + return rc; +} + +static int32_t cam_flash_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0, i = 0; + struct cam_flash_ctrl *fctrl = NULL; + struct device_node *of_parent = NULL; + + CAM_DBG(CAM_FLASH, "Enter"); + if (!pdev->dev.of_node) { + CAM_ERR(CAM_FLASH, "of_node NULL"); + return -EINVAL; + } + + fctrl = kzalloc(sizeof(struct cam_flash_ctrl), GFP_KERNEL); + if (!fctrl) + return -ENOMEM; + + fctrl->pdev = pdev; + fctrl->soc_info.pdev = pdev; + fctrl->soc_info.dev = &pdev->dev; + fctrl->soc_info.dev_name = pdev->name; + + platform_set_drvdata(pdev, fctrl); + + rc = cam_flash_get_dt_data(fctrl, &fctrl->soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "cam_flash_get_dt_data failed with %d", rc); + kfree(fctrl); + return -EINVAL; + } + + if (of_find_property(pdev->dev.of_node, "cci-master", NULL)) { + /* Get CCI master */ + rc = of_property_read_u32(pdev->dev.of_node, "cci-master", + &fctrl->cci_i2c_master); + CAM_DBG(CAM_FLASH, "cci-master %d, rc %d", + fctrl->cci_i2c_master, rc); + if (rc < 0) { + /* Set default master 0 */ + fctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + fctrl->io_master_info.master_type = CCI_MASTER; + rc = cam_flash_init_default_params(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "failed: cam_flash_init_default_params rc %d", + rc); + return rc; + } + + of_parent = of_get_parent(pdev->dev.of_node); + if (of_property_read_u32(of_parent, "cell-index", + &fctrl->cci_num) < 0) + /* Set default master 0 */ + fctrl->cci_num = CCI_DEVICE_0; + + fctrl->io_master_info.cci_client->cci_device = fctrl->cci_num; + CAM_DBG(CAM_FLASH, "cci-index %d", fctrl->cci_num, rc); + + fctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (fctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_FLASH, "No Memory"); + rc = -ENOMEM; + goto free_cci_resource; + } + + INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head)); + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD( + &(fctrl->i2c_data.per_frame[i].list_head)); + + fctrl->func_tbl.parser = cam_flash_i2c_pkt_parser; + fctrl->func_tbl.apply_setting = cam_flash_i2c_apply_setting; + fctrl->func_tbl.power_ops = cam_flash_i2c_power_ops; + fctrl->func_tbl.flush_req = cam_flash_i2c_flush_request; + } else { + /* PMIC Flash */ + fctrl->func_tbl.parser = cam_flash_pmic_pkt_parser; + fctrl->func_tbl.apply_setting = cam_flash_pmic_apply_setting; + fctrl->func_tbl.power_ops = cam_flash_pmic_power_ops; + fctrl->func_tbl.flush_req = cam_flash_pmic_flush_request; + } + + rc = cam_flash_init_subdev(fctrl); + if (rc) { + if (fctrl->io_master_info.cci_client != NULL) + goto free_cci_resource; + else + goto free_resource; + } + + fctrl->bridge_intf.device_hdl = -1; + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.ops.get_dev_info = cam_flash_publish_dev_info; + fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; + fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; + fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; + + mutex_init(&(fctrl->flash_mutex)); + + fctrl->flash_state = CAM_FLASH_STATE_INIT; + CAM_DBG(CAM_FLASH, "Probe success"); + return rc; + +free_cci_resource: + kfree(fctrl->io_master_info.cci_client); + fctrl->io_master_info.cci_client = NULL; +free_resource: + kfree(fctrl->i2c_data.per_frame); + kfree(fctrl->soc_info.soc_private); + cam_soc_util_release_platform_resource(&fctrl->soc_info); + fctrl->i2c_data.per_frame = NULL; + fctrl->soc_info.soc_private = NULL; + kfree(fctrl); + fctrl = NULL; + return rc; +} + +static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0, i = 0; + struct cam_flash_ctrl *fctrl; + + if (client == NULL || id == NULL) { + CAM_ERR(CAM_FLASH, "Invalid Args client: %pK id: %pK", + client, id); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_FLASH, "%s :: i2c_check_functionality failed", + client->name); + return -EFAULT; + } + + /* Create sensor control structure */ + fctrl = kzalloc(sizeof(*fctrl), GFP_KERNEL); + if (!fctrl) + return -ENOMEM; + + i2c_set_clientdata(client, fctrl); + + fctrl->io_master_info.client = client; + fctrl->soc_info.dev = &client->dev; + fctrl->soc_info.dev_name = client->name; + fctrl->io_master_info.master_type = I2C_MASTER; + + rc = cam_flash_get_dt_data(fctrl, &fctrl->soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "failed: cam_sensor_parse_dt rc %d", rc); + goto free_ctrl; + } + + rc = cam_flash_init_subdev(fctrl); + if (rc) + goto free_ctrl; + + fctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (fctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(fctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(fctrl->i2c_data.config_settings.list_head)); + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(fctrl->i2c_data.per_frame[i].list_head)); + + fctrl->func_tbl.parser = cam_flash_i2c_pkt_parser; + fctrl->func_tbl.apply_setting = cam_flash_i2c_apply_setting; + fctrl->func_tbl.power_ops = cam_flash_i2c_power_ops; + fctrl->func_tbl.flush_req = cam_flash_i2c_flush_request; + + fctrl->bridge_intf.device_hdl = -1; + fctrl->bridge_intf.link_hdl = -1; + fctrl->bridge_intf.ops.get_dev_info = cam_flash_publish_dev_info; + fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; + fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; + fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; + + mutex_init(&(fctrl->flash_mutex)); + fctrl->flash_state = CAM_FLASH_STATE_INIT; + + return rc; + +unreg_subdev: + cam_unregister_subdev(&(fctrl->v4l2_dev_str)); +free_ctrl: + kfree(fctrl); + fctrl = NULL; + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_flash_dt_match); + +static struct platform_driver cam_flash_platform_driver = { + .probe = cam_flash_platform_probe, + .remove = cam_flash_platform_remove, + .driver = { + .name = "CAM-FLASH-DRIVER", + .owner = THIS_MODULE, + .of_match_table = cam_flash_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static const struct i2c_device_id i2c_id[] = { + {FLASH_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_flash_i2c_driver = { + .id_table = i2c_id, + .probe = cam_flash_i2c_driver_probe, + .remove = cam_flash_i2c_driver_remove, + .driver = { + .name = FLASH_DRIVER_I2C, + }, +}; + +static int32_t __init cam_flash_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_flash_platform_driver); + if (rc == 0) { + CAM_DBG(CAM_FLASH, "platform probe success"); + return 0; + } + + rc = i2c_add_driver(&cam_flash_i2c_driver); + if (rc) + CAM_ERR(CAM_FLASH, "i2c_add_driver failed rc: %d", rc); + return rc; +} + +static void __exit cam_flash_exit_module(void) +{ + platform_driver_unregister(&cam_flash_platform_driver); + i2c_del_driver(&cam_flash_i2c_driver); +} + +module_init(cam_flash_init_module); +module_exit(cam_flash_exit_module); +MODULE_DESCRIPTION("CAM FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..29e352e47ce9dcc66e2e1305857a3746526b015b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FLASH_DEV_H_ +#define _CAM_FLASH_DEV_H_ + +#include <linux/leds.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/leds-qpnp-flash.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/cam_sensor.h> +#include <media/cam_req_mgr.h> +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_interface.h" +#include "cam_subdev.h" +#include "cam_mem_mgr.h" +#include "cam_sensor_cmn_header.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_sensor_io.h" +#include "cam_flash_core.h" +#include "cam_context.h" + +#define CAMX_FLASH_DEV_NAME "cam-flash-dev" + +#define CAM_FLASH_PIPELINE_DELAY 1 + +#define FLASH_DRIVER_I2C "i2c_flash" + +#define CAM_FLASH_PACKET_OPCODE_INIT 0 +#define CAM_FLASH_PACKET_OPCODE_SET_OPS 1 +#define CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS 2 + +struct cam_flash_ctrl; + +enum cam_flash_switch_trigger_ops { + LED_SWITCH_OFF = 0, + LED_SWITCH_ON, +}; + +enum cam_flash_state { + CAM_FLASH_STATE_INIT, + CAM_FLASH_STATE_ACQUIRE, + CAM_FLASH_STATE_CONFIG, + CAM_FLASH_STATE_START, +}; + +enum cam_flash_flush_type { + FLUSH_ALL = 0, + FLUSH_REQ, + FLUSH_MAX, +}; + +/** + * struct cam_flash_intf_params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @link_hdl : Link Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_flash_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_flash_common_attr + * @is_settings_valid : Notify the valid settings + * @request_id : Request id provided by umd + * @count : Number of led count + * @cmd_type : Command buffer type + */ +struct cam_flash_common_attr { + bool is_settings_valid; + uint64_t request_id; + uint32_t count; + uint8_t cmd_type; +}; + +/** + * struct flash_init_packet + * @cmn_attr : Provides common attributes + * @flash_type : Flash type(PMIC/I2C/GPIO) + */ +struct cam_flash_init_packet { + struct cam_flash_common_attr cmn_attr; + uint32_t flash_type; +}; + +/** + * struct flash_frame_setting + * @cmn_attr : Provides common attributes + * @num_iterations : Iterations used to perform RER + * @led_on_delay_ms : LED on time in milisec + * @led_off_delay_ms : LED off time in milisec + * @opcode : Command buffer opcode + * @led_current_ma[] : LED current array in miliamps + * + */ +struct cam_flash_frame_setting { + struct cam_flash_common_attr cmn_attr; + uint16_t num_iterations; + uint16_t led_on_delay_ms; + uint16_t led_off_delay_ms; + int8_t opcode; + uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; +}; + +/** + * struct cam_flash_private_soc + * @switch_trigger_name : Switch trigger name + * @flash_trigger_name : Flash trigger name array + * @flash_op_current : Flash operational current + * @flash_max_current : Max supported current for LED in flash mode + * @flash_max_duration : Max turn on duration for LED in Flash mode + * @torch_trigger_name : Torch trigger name array + * @torch_op_current : Torch operational current + * @torch_max_current : Max supported current for LED in torch mode + * @is_wled_flash : Detection between WLED/LED flash + */ + +struct cam_flash_private_soc { + const char *switch_trigger_name; + const char *flash_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t flash_max_duration[CAM_FLASH_MAX_LED_TRIGGERS]; + const char *torch_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; + bool is_wled_flash; +}; + +struct cam_flash_func_tbl { + int (*parser)(struct cam_flash_ctrl *fctrl, void *arg); + int (*apply_setting)(struct cam_flash_ctrl *fctrl, uint64_t req_id); + int (*power_ops)(struct cam_flash_ctrl *fctrl, bool regulator_enable); + int (*flush_req)(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id); +}; + +/** + * struct cam_flash_ctrl + * @device_name : Device name + * @soc_info : Soc related information + * @pdev : Platform device + * @per_frame[] : Per_frame setting array + * @nrt_info : NonRealTime settings + * @of_node : Of Node ptr + * @v4l2_dev_str : V4L2 device structure + * @bridge_intf : CRM interface + * @flash_init_setting : Init command buffer structure + * @switch_trigger : Switch trigger ptr + * @flash_num_sources : Number of flash sources + * @torch_num_source : Number of torch sources + * @flash_mutex : Mutex for flash operations + * @flash_state : Current flash state (LOW/OFF/ON/INIT) + * @flash_type : Flash types (PMIC/I2C/GPIO) + * @is_regulator_enable : Regulator disable/enable notifier + * @func_tbl : Function table for different HW + * (e.g. i2c/pmic/gpio) + * @flash_trigger : Flash trigger ptr + * @torch_trigger : Torch trigger ptr + * @cci_i2c_master : I2C structure + * @cci_device_num : cci parent cell index + * @io_master_info : Information about the communication master + * @i2c_data : I2C register settings + * @last_flush_req : last request to flush + */ +struct cam_flash_ctrl { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct cam_hw_soc_info soc_info; + struct platform_device *pdev; + struct cam_sensor_power_ctrl_t power_info; + struct cam_flash_frame_setting per_frame[MAX_PER_FRAME_ARRAY]; + struct cam_flash_frame_setting nrt_info; + struct device_node *of_node; + struct cam_subdev v4l2_dev_str; + struct cam_flash_intf_params bridge_intf; + struct cam_flash_init_packet flash_init_setting; + struct led_trigger *switch_trigger; + uint32_t flash_num_sources; + uint32_t torch_num_sources; + struct mutex flash_mutex; + enum cam_flash_state flash_state; + uint8_t flash_type; + bool is_regulator_enabled; + struct cam_flash_func_tbl func_tbl; + struct led_trigger *flash_trigger[CAM_FLASH_MAX_LED_TRIGGERS]; + struct led_trigger *torch_trigger[CAM_FLASH_MAX_LED_TRIGGERS]; +/* I2C related setting */ + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct camera_io_master io_master_info; + struct i2c_data_settings i2c_data; + uint32_t last_flush_req; +}; + +int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); +int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); +int cam_flash_pmic_apply_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); +int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); +int cam_flash_off(struct cam_flash_ctrl *fctrl); +int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable); +int cam_flash_i2c_power_ops(struct cam_flash_ctrl *fctrl, + bool regulator_enable); +int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type type, uint64_t req_id); +int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, + enum cam_flash_flush_type, uint64_t req_id); +void cam_flash_shutdown(struct cam_flash_ctrl *fctrl); +int cam_flash_release_dev(struct cam_flash_ctrl *fctrl); + +#endif /*_CAM_FLASH_DEV_H_*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..762977f4b9682055f0794cd9cf706d8d4d215f07 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/of_gpio.h> +#include "cam_flash_soc.h" +#include "cam_res_mgr_api.h" + +static int32_t cam_get_source_node_info( + struct device_node *of_node, + struct cam_flash_ctrl *fctrl, + struct cam_flash_private_soc *soc_private) +{ + int32_t rc = 0; + uint32_t count = 0, i = 0; + struct device_node *flash_src_node = NULL; + struct device_node *torch_src_node = NULL; + struct device_node *switch_src_node = NULL; + + soc_private->is_wled_flash = + of_property_read_bool(of_node, "wled-flash-support"); + + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); + if (!switch_src_node) { + CAM_WARN(CAM_FLASH, "switch_src_node NULL"); + } else { + rc = of_property_read_string(switch_src_node, + "qcom,default-led-trigger", + &soc_private->switch_trigger_name); + if (rc) { + CAM_ERR(CAM_FLASH, + "default-led-trigger read failed rc=%d", rc); + } else { + CAM_DBG(CAM_FLASH, "switch trigger %s", + soc_private->switch_trigger_name); + cam_res_mgr_led_trigger_register( + soc_private->switch_trigger_name, + &fctrl->switch_trigger); + } + + of_node_put(switch_src_node); + } + + if (of_get_property(of_node, "flash-source", &count)) { + count /= sizeof(uint32_t); + + if (count > CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "Invalid LED count: %d", count); + return -EINVAL; + } + + fctrl->flash_num_sources = count; + + for (i = 0; i < count; i++) { + flash_src_node = of_parse_phandle(of_node, + "flash-source", i); + if (!flash_src_node) { + CAM_WARN(CAM_FLASH, "flash_src_node NULL"); + continue; + } + + rc = of_property_read_string(flash_src_node, + "qcom,default-led-trigger", + &soc_private->flash_trigger_name[i]); + if (rc) { + CAM_WARN(CAM_FLASH, + "defalut-led-trigger read failed rc=%d", rc); + of_node_put(flash_src_node); + continue; + } + + CAM_DBG(CAM_FLASH, "Flash default trigger %s", + soc_private->flash_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->flash_trigger_name[i], + &fctrl->flash_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->flash_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->flash_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED FLASH max_current read fail: %d", + rc); + of_node_put(flash_src_node); + rc = 0; + continue; + } + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &soc_private->flash_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED FLASH max-current read fail: %d", + rc); + of_node_put(flash_src_node); + continue; + } + } + + /* Read operational-current */ + rc = of_property_read_u32(flash_src_node, + "qcom,current-ma", + &soc_private->flash_op_current[i]); + if (rc) { + CAM_INFO(CAM_FLASH, "op-current: read failed"); + rc = 0; + } + + /* Read max-duration */ + rc = of_property_read_u32(flash_src_node, + "qcom,duration-ms", + &soc_private->flash_max_duration[i]); + if (rc) { + CAM_INFO(CAM_FLASH, + "max-duration prop unavailable: %d", + rc); + rc = 0; + } + of_node_put(flash_src_node); + + CAM_DBG(CAM_FLASH, "MainFlashMaxCurrent[%d]: %d", + i, soc_private->flash_max_current[i]); + } + } + + if (of_get_property(of_node, "torch-source", &count)) { + count /= sizeof(uint32_t); + if (count > CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "Invalid LED count : %d", count); + return -EINVAL; + } + + fctrl->torch_num_sources = count; + + CAM_DBG(CAM_FLASH, "torch_num_sources = %d", + fctrl->torch_num_sources); + for (i = 0; i < count; i++) { + torch_src_node = of_parse_phandle(of_node, + "torch-source", i); + if (!torch_src_node) { + CAM_WARN(CAM_FLASH, "torch_src_node NULL"); + continue; + } + + rc = of_property_read_string(torch_src_node, + "qcom,default-led-trigger", + &soc_private->torch_trigger_name[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "default-trigger read failed"); + of_node_put(torch_src_node); + continue; + } + + CAM_DBG(CAM_FLASH, "Torch default trigger %s", + soc_private->torch_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->torch_trigger_name[i], + &fctrl->torch_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->torch_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->torch_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED TORCH max_current read fail: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } else { + rc = of_property_read_u32(torch_src_node, + "qcom,max-current", + &soc_private->torch_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED-TORCH max-current read failed: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } + + /* Read operational-current */ + rc = of_property_read_u32(torch_src_node, + "qcom,current-ma", + &soc_private->torch_op_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "op-current prop unavailable: %d", rc); + rc = 0; + } + + of_node_put(torch_src_node); + + CAM_DBG(CAM_FLASH, "TorchMaxCurrent[%d]: %d", + i, soc_private->torch_max_current[i]); + } + } + + return rc; +} + +int cam_flash_get_dt_data(struct cam_flash_ctrl *fctrl, + struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0; + struct device_node *of_node = NULL; + + if (!fctrl) { + CAM_ERR(CAM_FLASH, "NULL flash control structure"); + return -EINVAL; + } + + soc_info->soc_private = + kzalloc(sizeof(struct cam_flash_private_soc), GFP_KERNEL); + if (!soc_info->soc_private) { + rc = -ENOMEM; + goto release_soc_res; + } + of_node = fctrl->pdev->dev.of_node; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "Get_dt_properties failed rc %d", rc); + goto free_soc_private; + } + + rc = cam_get_source_node_info(of_node, fctrl, soc_info->soc_private); + if (rc) { + CAM_ERR(CAM_FLASH, + "cam_flash_get_pmic_source_info failed rc %d", rc); + goto free_soc_private; + } + return rc; + +free_soc_private: + kfree(soc_info->soc_private); + soc_info->soc_private = NULL; +release_soc_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..cfe7c3464f649f62b237911ec50de993101487d8 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_FLASH_SOC_H_ +#define _CAM_FLASH_SOC_H_ + +#include "cam_flash_dev.h" + +int cam_flash_get_dt_data(struct cam_flash_ctrl *fctrl, + struct cam_hw_soc_info *soc_info); + +#endif /*_CAM_FLASH_SOC_H_*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_ois/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..948f297a1e7712dd69645887605c1b41985e69b3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/ + +obj-$(CONFIG_SPECTRA_CAMERA) += onsemi_fw/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c new file mode 100755 index 0000000000000000000000000000000000000000..a4db237971eee78b532c4a43b36a56beada9aa0b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -0,0 +1,1111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/dma-contiguous.h> +#include <cam_sensor_cmn_header.h> +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_res_mgr_api.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" + +#include "onsemi_fw/fw_download_interface.h" + +#ifdef ENABLE_OIS_DELAY_POWER_DOWN +static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl); + +int ois_power_down_thread(void *arg) +{ + int rc = 0; + int i; + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + + if (!o_ctrl || !soc_private || !power_info) { + CAM_ERR(CAM_OIS, "failed: o_ctrl %pK, soc_private %pK, power_info %pK", o_ctrl, soc_private, power_info); + return -EINVAL; + } + + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + o_ctrl->ois_power_down_thread_state = CAM_OIS_POWER_DOWN_THREAD_RUNNING; + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + + for (i = 0; i < (OIS_POWER_DOWN_DELAY/50); i++) { + msleep(50);// sleep 50ms every time, and sleep OIS_POWER_DOWN_DELAY/50 times. + + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_down_thread_exit) { + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + break; + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + } + + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if ((!o_ctrl->ois_power_down_thread_exit) && (o_ctrl->ois_power_state == CAM_OIS_POWER_ON)) { + rc = cam_ois_power_down(o_ctrl); + if (!rc){ + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + CAM_ERR(CAM_OIS, "ois type=%d,cam_ois_power_down successfully",o_ctrl->ois_type); + } else { + CAM_ERR(CAM_OIS, "ois type=%d,cam_ois_power_down failed",o_ctrl->ois_type); + } +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_lock(&(o_ctrl->do_ioctl_ois)); + o_ctrl->ois_downloadfw_thread = NULL; + o_ctrl->ois_download_fw_done = CAM_OIS_FW_NOT_DOWNLOAD; + o_ctrl->ois_fd_have_close_state = CAM_OIS_IS_CLOSE; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + o_ctrl->ois_power_state = CAM_OIS_POWER_OFF; + } else { + CAM_ERR(CAM_OIS, "ois type=%d,No need to do power down, ois_power_down_thread_exit %d, ois_power_state %d",o_ctrl->ois_type, o_ctrl->ois_power_down_thread_exit, o_ctrl->ois_power_state); + } + o_ctrl->ois_power_down_thread_state = CAM_OIS_POWER_DOWN_THREAD_STOPPED; + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + + return rc; +} +#endif + +int32_t cam_ois_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 3; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting)*3, + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + power_info->power_setting[0].seq_type = SENSOR_VIO; + power_info->power_setting[0].seq_val = CAM_VIO; + power_info->power_setting[0].config_val = 1; + power_info->power_setting[0].delay = 0; + + power_info->power_setting[1].seq_type = SENSOR_VAF; + power_info->power_setting[1].seq_val = CAM_VAF; + power_info->power_setting[1].config_val = 1; + power_info->power_setting[1].delay = 0; + + power_info->power_setting[2].seq_type = SENSOR_VDIG; + power_info->power_setting[2].seq_val = CAM_VDIG; + power_info->power_setting[2].config_val = 1; + power_info->power_setting[2].delay = 10; + + power_info->power_down_setting_size = 3; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting)*3, + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + power_info->power_down_setting[0].seq_type = SENSOR_VDIG; + power_info->power_down_setting[0].seq_val = CAM_VDIG; + power_info->power_down_setting[0].config_val = 0; + + power_info->power_down_setting[1].seq_type = SENSOR_VIO; + power_info->power_down_setting[1].seq_val = CAM_VIO; + power_info->power_down_setting[1].config_val = 0; + + power_info->power_down_setting[2].seq_type = SENSOR_VAF; + power_info->power_down_setting[2].seq_val = CAM_VAF; + power_info->power_down_setting[2].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + + +/** + * cam_ois_get_dev_handle - get device handle + * @o_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, + void *arg) +{ + struct cam_sensor_acquire_dev ois_acq_dev; + struct cam_create_dev_hdl bridge_params; + struct cam_control *cmd = (struct cam_control *)arg; + + if (o_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_OIS, "Device is already acquired"); + return -EFAULT; + } + if (copy_from_user(&ois_acq_dev, u64_to_user_ptr(cmd->handle), + sizeof(ois_acq_dev))) + return -EFAULT; + + bridge_params.session_hdl = ois_acq_dev.session_handle; + bridge_params.ops = &o_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = o_ctrl; + + ois_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle; + o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle; + + CAM_DBG(CAM_OIS, "Device Handle: %d", ois_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), &ois_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_OIS, "ACQUIRE_DEV: copy to user failed"); + return -EFAULT; + } + return 0; +} + +int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + struct cam_hw_soc_info *soc_info = + &o_ctrl->soc_info; + struct cam_ois_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + if ((power_info->power_setting == NULL) && + (power_info->power_down_setting == NULL)) { + CAM_INFO(CAM_OIS, + "Using default power settings"); + rc = cam_ois_construct_default_power_setting(power_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Construct default ois power setting failed."); + return rc; + } + } + + /* Parse and fill vreg params for power up settings */ + rc = msm_camera_fill_vreg_params( + soc_info, + power_info->power_setting, + power_info->power_setting_size); + if (rc) { + CAM_ERR(CAM_OIS, + "failed to fill vreg params for power up rc:%d", rc); + return rc; + } + + /* Parse and fill vreg params for power down settings*/ + rc = msm_camera_fill_vreg_params( + soc_info, + power_info->power_down_setting, + power_info->power_down_setting_size); + if (rc) { + CAM_ERR(CAM_OIS, + "failed to fill vreg params for power down rc:%d", rc); + return rc; + } + + power_info->dev = soc_info->dev; + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_OIS, "failed in ois power up rc %d", rc); + return rc; + } + + rc = camera_io_init(&o_ctrl->io_master_info); + if (rc) + CAM_ERR(CAM_OIS, "cci_init failed: rc: %d", rc); + + InitOIS(o_ctrl); + + return rc; +} + +/** + * cam_ois_power_down - power down OIS device + * @o_ctrl: ctrl structure + * + * Returns success or failure + */ +static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info = + &o_ctrl->soc_info; + struct cam_ois_soc_private *soc_private; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "failed: o_ctrl %pK", o_ctrl); + return -EINVAL; + } + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + soc_info = &o_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_OIS, "failed: power_info %pK", power_info); + return -EINVAL; + } + + DeinitOIS(o_ctrl); + + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc) { + CAM_ERR(CAM_OIS, "power down the core is failed:%d", rc); + return rc; + } + + camera_io_release(&o_ctrl->io_master_info); + + return rc; +} + +static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, + struct i2c_settings_array *i2c_set) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0; + uint32_t i, size; + + if (o_ctrl == NULL || i2c_set == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + if (i2c_set->is_settings_valid != 1) { + CAM_ERR(CAM_OIS, " Invalid settings"); + return -EINVAL; + } + + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { + rc = camera_io_dev_write(&(o_ctrl->io_master_info), + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in Applying i2c wrt settings"); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + &(o_ctrl->io_master_info), + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "i2c poll apply setting Fail"); + return rc; + } + } + } + } + + return rc; +} + +static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, + uint32_t *cmd_buf, size_t len) +{ + int32_t rc = 0; + struct cam_cmd_ois_info *ois_info; + + if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_info)) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + ois_info = (struct cam_cmd_ois_info *)cmd_buf; + if (o_ctrl->io_master_info.master_type == CCI_MASTER) { + o_ctrl->io_master_info.cci_client->i2c_freq_mode = + ois_info->i2c_freq_mode; + o_ctrl->io_master_info.cci_client->sid = + ois_info->slave_addr >> 1; + o_ctrl->ois_fw_flag = ois_info->ois_fw_flag; + o_ctrl->is_ois_calib = ois_info->is_ois_calib; + memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN); + o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0'; + o_ctrl->io_master_info.cci_client->retries = 3; + o_ctrl->io_master_info.cci_client->id_map = 0; + memcpy(&(o_ctrl->opcode), &(ois_info->opcode), + sizeof(struct cam_ois_opcode)); + CAM_DBG(CAM_OIS, "Slave addr: 0x%x Freq Mode: %d", + ois_info->slave_addr, ois_info->i2c_freq_mode); + } else if (o_ctrl->io_master_info.master_type == I2C_MASTER) { + o_ctrl->io_master_info.client->addr = ois_info->slave_addr; + CAM_DBG(CAM_OIS, "Slave addr: 0x%x", ois_info->slave_addr); + } else { + CAM_ERR(CAM_OIS, "Invalid Master type : %d", + o_ctrl->io_master_info.master_type); + rc = -EINVAL; + } + + return rc; +} + +static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + uint8_t *ptr = NULL; + int32_t rc = 0, cnt; + uint32_t fw_size; + const struct firmware *fw = NULL; + const char *fw_name_prog = NULL; + const char *fw_name_coeff = NULL; + char name_prog[32] = {0}; + char name_coeff[32] = {0}; + struct device *dev = &(o_ctrl->pdev->dev); + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + struct page *page = NULL; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name); + + snprintf(name_prog, 32, "%s.prog", o_ctrl->ois_name); + + /* cast pointer as const pointer*/ + fw_name_prog = name_prog; + fw_name_coeff = name_coeff; + + /* Load FW */ + rc = request_firmware(&fw, fw_name_prog, dev); + if (rc) { + CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_prog); + return rc; + } + + total_bytes = fw->size; + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * + total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)), + fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + release_firmware(fw); + return -ENOMEM; + } + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( + page_address(page)); + + for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes; + cnt++, ptr++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = + o_ctrl->opcode.prog; + i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + goto release_firmware; + } + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), + page, fw_size); + page = NULL; + fw_size = 0; + release_firmware(fw); + + rc = request_firmware(&fw, fw_name_coeff, dev); + if (rc) { + CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_coeff); + return rc; + } + + total_bytes = fw->size; + i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.size = total_bytes; + i2c_reg_setting.delay = 0; + fw_size = PAGE_ALIGN(sizeof(struct cam_sensor_i2c_reg_array) * + total_bytes) >> PAGE_SHIFT; + page = cma_alloc(dev_get_cma_area((o_ctrl->soc_info.dev)), + fw_size, 0, GFP_KERNEL); + if (!page) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + release_firmware(fw); + return -ENOMEM; + } + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( + page_address(page)); + + for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes; + cnt++, ptr++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = + o_ctrl->opcode.coeff; + i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + if (rc < 0) + CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + +release_firmware: + cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), + page, fw_size); + release_firmware(fw); + + return rc; +} + +/** + * cam_ois_pkt_parse - Parse csl packet + * @o_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) +{ + int32_t rc = 0; + int32_t i = 0; + uint32_t total_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uintptr_t generic_ptr; + struct cam_control *ioctl_ctrl = NULL; + struct cam_config_dev_cmd dev_config; + struct i2c_settings_array *i2c_reg_settings = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t generic_pkt_addr; + size_t pkt_len; + size_t remain_len = 0; + struct cam_packet *csl_packet = NULL; + size_t len_of_buff = 0; + uint32_t *offset = NULL, *cmd_buf; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + int count=0; + int enable=0; + + ioctl_ctrl = (struct cam_control *)arg; + if (copy_from_user(&dev_config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(dev_config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(dev_config.packet_handle, + &generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_OIS, + "error in converting command Handle Error: %d", rc); + return rc; + } + + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_OIS, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + return -EINVAL; + } + + remain_len -= (size_t)dev_config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_OIS, "Invalid packet params"); + return -EINVAL; + } + + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_OIS_PACKET_OPCODE_INIT: + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + /* Loop through multiple command buffers */ + for (i = 0; i < csl_packet->num_cmd_buf; i++) { + total_cmd_buf_in_bytes = cmd_desc[i].length; + if (!total_cmd_buf_in_bytes) + continue; + + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to get cpu buf : 0x%x", + cmd_desc[i].mem_handle); + return rc; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_OIS, "invalid cmd buf"); + return -EINVAL; + } + + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_OIS, + "Invalid length for sensor cmd"); + return -EINVAL; + } + remain_len = len_of_buff - cmd_desc[i].offset; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + cmm_hdr = (struct common_header *)cmd_buf; + + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: + rc = cam_ois_slaveInfo_pkt_parser( + o_ctrl, cmd_buf, remain_len); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in parsing slave info"); + return rc; + } + break; + case CAMERA_SENSOR_CMD_TYPE_PWR_UP: + case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: + CAM_DBG(CAM_OIS, + "Received power settings buffer"); +#ifdef ENABLE_OIS_DELAY_POWER_DOWN + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_OFF){ + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + power_info, remain_len); + if (!rc) { + CAM_ERR(CAM_OIS, "ois type=%d,cam_sensor_update_power_settings successfully",o_ctrl->ois_type); + } else { + CAM_ERR(CAM_OIS, "ois type=%d,cam_sensor_update_power_settings failed",o_ctrl->ois_type); + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + return rc; + } + } else { + CAM_ERR(CAM_OIS, "ois type=%d,OIS already power on, no need to update power setting",o_ctrl->ois_type); + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); +#else + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + power_info, remain_len); +#endif + if (rc) { + CAM_ERR(CAM_OIS, + "Failed: parse power settings"); + return rc; + } + break; + default: + if (o_ctrl->i2c_init_data.is_settings_valid == 0) { + CAM_DBG(CAM_OIS, + "Received init settings"); + i2c_reg_settings = + &(o_ctrl->i2c_init_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "init parsing failed: %d", rc); + return rc; + } + } else if ((o_ctrl->is_ois_calib != 0) && + (o_ctrl->i2c_calib_data.is_settings_valid == + 0)) { + CAM_DBG(CAM_OIS, + "Received calib settings"); + i2c_reg_settings = &(o_ctrl->i2c_calib_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Calib parsing failed: %d", rc); + return rc; + } + } + break; + } + } + + if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { +#ifdef ENABLE_OIS_DELAY_POWER_DOWN + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + o_ctrl->ois_power_down_thread_exit = true; + if (o_ctrl->ois_power_state == CAM_OIS_POWER_OFF){ + rc = cam_ois_power_up(o_ctrl); + if (!rc){ + o_ctrl->ois_power_state = CAM_OIS_POWER_ON; + CAM_ERR(CAM_OIS, "ois type=%d,cam_ois_power_up successfully",o_ctrl->ois_type); + } else { + CAM_ERR(CAM_OIS, "ois type=%d,cam_ois_power_up failed",o_ctrl->ois_type); + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + return rc; + } + } else { + CAM_ERR(CAM_OIS, "ois type=%d,OIS already power on, no need to power on again",o_ctrl->ois_type); + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); +#else + rc = cam_ois_power_up(o_ctrl); +#endif + if (rc) { + CAM_ERR(CAM_OIS, " OIS Power up failed"); + return rc; + } + o_ctrl->cam_ois_state = CAM_OIS_CONFIG; + } + + if (o_ctrl->ois_fw_flag) { + if (strstr(o_ctrl->ois_name, "lc898")) { + o_ctrl->ois_module_vendor = (o_ctrl->opcode.pheripheral & 0xFF00) >> 8; + o_ctrl->ois_actuator_vendor = o_ctrl->opcode.pheripheral & 0xFF; +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_lock(&(o_ctrl->do_ioctl_ois)); + if(o_ctrl->ois_download_fw_done == CAM_OIS_FW_NOT_DOWNLOAD){ + rc = DownloadFW(o_ctrl); + } else { + CAM_INFO(CAM_OIS, "OIS FW Have Download"); + } +#else + rc = DownloadFW(o_ctrl); +#endif + } else { + rc = cam_ois_fw_download(o_ctrl); + } + + if (rc) { +#ifdef DOWNLOAD_OIS_FW_BEFORE + o_ctrl->ois_download_fw_done = CAM_OIS_FW_NOT_DOWNLOAD; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + CAM_ERR(CAM_OIS, "Failed OIS FW Download"); + goto pwr_dwn; + } +#ifdef DOWNLOAD_OIS_FW_BEFORE + o_ctrl->ois_download_fw_done = CAM_OIS_FW_DOWNLOAD_DONE; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + } + + rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data); + if ((rc == -EAGAIN) && + (o_ctrl->io_master_info.master_type == CCI_MASTER)) { + CAM_WARN(CAM_OIS, + "CCI HW is restting: Reapplying INIT settings"); + usleep_range(5000, 5010); + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_init_data); + } + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Cannot apply Init settings: rc = %d", + rc); + goto pwr_dwn; + } + + if (o_ctrl->is_ois_calib) { + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_calib_data); + if (rc) { + CAM_ERR(CAM_OIS, "Cannot apply calib data"); + goto pwr_dwn; + } + } + + rc = delete_request(&o_ctrl->i2c_init_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting Init data: rc: %d", rc); + rc = 0; + } + rc = delete_request(&o_ctrl->i2c_calib_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting Calibration data: rc: %d", rc); + rc = 0; + } + break; + case CAM_OIS_PACKET_OPCODE_OIS_CONTROL: + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to control OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + i2c_reg_settings = &(o_ctrl->i2c_mode_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); + return rc; + } + + if (!IsOISReady(o_ctrl)) { + CAM_ERR(CAM_OIS, "OIS is not ready, apply setting may fail"); + for(count=0;count<o_ctrl->soc_info.num_rgltr;count++){ + enable=regulator_is_enabled(regulator_get(o_ctrl->soc_info.dev,o_ctrl->soc_info.rgltr_name[count])); + CAM_ERR(CAM_OIS, " jay regulator enable=%d,name[%d]=%s",enable,count,o_ctrl->soc_info.rgltr_name[count]); + } + } + o_ctrl->ois_poll_thread_control_cmd = CAM_OIS_START_POLL_THREAD; + OISControl(o_ctrl); + + rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Cannot apply mode settings"); + return rc; + } + + rc = delete_request(i2c_reg_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Fail deleting Mode data: rc: %d", rc); + return rc; + } + break; + default: + CAM_ERR(CAM_OIS, "Invalid Opcode: %d", + (csl_packet->header.op_code & 0xFFFFFF)); + return -EINVAL; + } + + if (!rc) + return rc; +pwr_dwn: + cam_ois_power_down(o_ctrl); + return rc; +} + +void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; +#ifndef ENABLE_OIS_DELAY_POWER_DOWN + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; +#endif + + o_ctrl->ois_poll_thread_control_cmd = CAM_OIS_STOP_POLL_THREAD; + OISControl(o_ctrl); + + if (o_ctrl->cam_ois_state == CAM_OIS_INIT) + return; + + if (o_ctrl->cam_ois_state >= CAM_OIS_CONFIG) { +#ifdef ENABLE_OIS_DELAY_POWER_DOWN + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_ON && o_ctrl->ois_power_down_thread_state == CAM_OIS_POWER_DOWN_THREAD_STOPPED) { + o_ctrl->ois_power_down_thread_exit = false; + kthread_run(ois_power_down_thread, o_ctrl, "ois_power_down_thread"); + CAM_ERR(CAM_OIS, "ois type=%d,ois_power_down_thread created",o_ctrl->ois_type); + } else { + CAM_ERR(CAM_OIS, "ois type=%d,no need to create ois_power_down_thread, ois_power_state %d, ois_power_down_thread_state %d",o_ctrl->ois_type, o_ctrl->ois_power_state, o_ctrl->ois_power_down_thread_state); + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); +#else + rc = cam_ois_power_down(o_ctrl); +#endif + + if (rc < 0) + CAM_ERR(CAM_OIS, "OIS Power down failed"); + o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE; + } + + if (o_ctrl->cam_ois_state >= CAM_OIS_ACQUIRE) { + rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_OIS, "destroying the device hdl"); + o_ctrl->bridge_intf.device_hdl = -1; + o_ctrl->bridge_intf.link_hdl = -1; + o_ctrl->bridge_intf.session_hdl = -1; + } + + if (o_ctrl->i2c_mode_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_mode_data); + + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_calib_data); + + if (o_ctrl->i2c_init_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_init_data); + +#ifndef ENABLE_OIS_DELAY_POWER_DOWN + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; +#endif + + o_ctrl->cam_ois_state = CAM_OIS_INIT; +} + +/** + * cam_ois_driver_cmd - Handle ois cmds + * @e_ctrl: ctrl structure + * @arg: Camera control command argument + * + * Returns success or failure + */ +int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) +{ + int rc = 0; + struct cam_ois_query_cap_t ois_cap = {0}; + struct cam_control *cmd = (struct cam_control *)arg; +#ifndef ENABLE_OIS_DELAY_POWER_DOWN + struct cam_ois_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; +#endif + + if (!o_ctrl || !cmd) { + CAM_ERR(CAM_OIS, "Invalid arguments"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_OIS, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + +#ifndef ENABLE_OIS_DELAY_POWER_DOWN + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; +#endif + + mutex_lock(&(o_ctrl->ois_mutex)); + switch (cmd->op_code) { + case CAM_QUERY_CAP: + ois_cap.slot_info = o_ctrl->soc_info.index; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &ois_cap, + sizeof(struct cam_ois_query_cap_t))) { + CAM_ERR(CAM_OIS, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + CAM_DBG(CAM_OIS, "ois_cap: ID: %d", ois_cap.slot_info); + break; + case CAM_ACQUIRE_DEV: +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_ON){ + CAM_INFO(CAM_OIS, "ois need to exit power down thread"); + o_ctrl->ois_power_down_thread_exit = true; + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + mutex_lock(&(o_ctrl->do_ioctl_ois)); + o_ctrl->ois_fd_have_close_state = CAM_OIS_IS_OPEN; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + rc = cam_ois_get_dev_handle(o_ctrl, arg); + if (rc) { + CAM_ERR(CAM_OIS, "Failed to acquire dev"); + goto release_mutex; + } + + o_ctrl->cam_ois_state = CAM_OIS_ACQUIRE; + break; + case CAM_START_DEV: + if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state for start : %d", + o_ctrl->cam_ois_state); + goto release_mutex; + } + o_ctrl->cam_ois_state = CAM_OIS_START; + break; + case CAM_CONFIG_DEV: +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_lock(&(o_ctrl->do_ioctl_ois)); + if(o_ctrl->ois_fd_have_close_state != CAM_OIS_IS_OPEN){ + CAM_INFO(CAM_OIS, "ois have closing"); + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + break; + } + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + rc = cam_ois_pkt_parse(o_ctrl, arg); + if (rc) { + CAM_ERR(CAM_OIS, "Failed in ois pkt Parsing"); + goto release_mutex; + } + break; + case CAM_RELEASE_DEV: +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_lock(&(o_ctrl->do_ioctl_ois)); + if(o_ctrl->ois_fd_have_close_state != CAM_OIS_IS_OPEN){ + rc = 0; + CAM_INFO(CAM_OIS,"ois have release"); + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + goto release_mutex; + } + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + if (o_ctrl->cam_ois_state == CAM_OIS_START) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Cant release ois: in start state"); + goto release_mutex; + } + + if (o_ctrl->cam_ois_state == CAM_OIS_CONFIG) { + + o_ctrl->ois_poll_thread_control_cmd = CAM_OIS_STOP_POLL_THREAD; + OISControl(o_ctrl); +#ifdef ENABLE_OIS_DELAY_POWER_DOWN + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_ON && o_ctrl->ois_power_down_thread_state == CAM_OIS_POWER_DOWN_THREAD_STOPPED) { + o_ctrl->ois_power_down_thread_exit = false; + kthread_run(ois_power_down_thread, o_ctrl, "ois_power_down_thread"); + CAM_ERR(CAM_OIS, "ois type=%d,ois_power_down_thread created",o_ctrl->ois_type); + } else { + CAM_ERR(CAM_OIS, "ois type=%d,no need to create ois_power_down_thread, ois_power_state %d, ois_power_down_thread_state %d",o_ctrl->ois_type, o_ctrl->ois_power_state, o_ctrl->ois_power_down_thread_state); + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); +#else + rc = cam_ois_power_down(o_ctrl); +#endif + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS Power down failed"); + goto release_mutex; + } + } + + if (o_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_OIS, "link hdl: %d device hdl: %d", + o_ctrl->bridge_intf.device_hdl, + o_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_OIS, "destroying the device hdl"); + o_ctrl->bridge_intf.device_hdl = -1; + o_ctrl->bridge_intf.link_hdl = -1; + o_ctrl->bridge_intf.session_hdl = -1; + o_ctrl->cam_ois_state = CAM_OIS_INIT; + +#ifndef ENABLE_OIS_DELAY_POWER_DOWN + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; +#endif + + if (o_ctrl->i2c_mode_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_mode_data); + + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_calib_data); + + if (o_ctrl->i2c_init_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_init_data); + + break; + case CAM_STOP_DEV: +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_lock(&(o_ctrl->do_ioctl_ois)); + if(o_ctrl->ois_fd_have_close_state != CAM_OIS_IS_OPEN){ + rc = 0; + CAM_INFO(CAM_OIS,"ois have stop"); + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + break; + } + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + if (o_ctrl->cam_ois_state != CAM_OIS_START) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state for stop : %d", + o_ctrl->cam_ois_state); + } + o_ctrl->cam_ois_state = CAM_OIS_CONFIG; + break; + case CAM_GET_OIS_EIS_HALL: { + int get_hall_version; + get_hall_version = cmd->reserved; + if (o_ctrl->cam_ois_state == CAM_OIS_START || o_ctrl->cam_ois_state == CAM_OIS_CONFIG) { + if (get_hall_version == GET_HALL_DATA_VERSION_V2){ + ReadOISHALLDataV2(o_ctrl, u64_to_user_ptr(cmd->handle)); + } else if (get_hall_version == GET_HALL_DATA_VERSION_V3){ + ReadOISHALLDataV3(o_ctrl, u64_to_user_ptr(cmd->handle)); + } else { + ReadOISHALLData(o_ctrl, u64_to_user_ptr(cmd->handle)); + } + } else { + CAM_DBG(CAM_OIS, "OIS in wrong state %d", o_ctrl->cam_ois_state); + } + break; + } + default: + CAM_ERR(CAM_OIS, "invalid opcode"); + goto release_mutex; + } +release_mutex: + mutex_unlock(&(o_ctrl->ois_mutex)); + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.h new file mode 100755 index 0000000000000000000000000000000000000000..685bd200b0797e0234febbb299e9a3d331b8adfe --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_OIS_CORE_H_ +#define _CAM_OIS_CORE_H_ + +#include <linux/cma.h> +#include "cam_ois_dev.h" + +#define OIS_NAME_LEN 32 + +/** + * @power_info: power setting info to control the power + * + * This API construct the default ois power setting. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int32_t cam_ois_construct_default_power_setting( + struct cam_sensor_power_ctrl_t *power_info); + + +int cam_ois_driver_cmd(struct cam_ois_ctrl_t *e_ctrl, void *arg); +int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl); + +/** + * @o_ctrl: OIS ctrl structure + * + * This API handles the shutdown ioctl/close + */ +void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl); + +#endif +/* _CAM_OIS_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c new file mode 100755 index 0000000000000000000000000000000000000000..e03c817a1d9c8f0aab57bf7f6659e1870d24c50d --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_ois_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_ois_soc.h" +#include "cam_ois_core.h" +#include "cam_debug_util.h" + +#include "onsemi_fw/fw_download_interface.h" +#ifdef DOWNLOAD_OIS_FW_BEFORE +static int cam_ois_slaveInfo_pkt_parser_oem(struct cam_ois_ctrl_t *o_ctrl) +{ + o_ctrl->io_master_info.cci_client->i2c_freq_mode = I2C_FAST_PLUS_MODE; + o_ctrl->io_master_info.cci_client->sid = (0x7c >> 1); + o_ctrl->io_master_info.cci_client->retries = 3; + o_ctrl->io_master_info.cci_client->id_map = 0; + + return 0; +} + +int ois_download_fw_thread(void *arg) +{ + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + int rc = -1; + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_slaveInfo_pkt_parser_oem(o_ctrl); + if (o_ctrl->cam_ois_state != CAM_OIS_CONFIG) { + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + o_ctrl->ois_power_down_thread_exit = true; + if (o_ctrl->ois_power_state == CAM_OIS_POWER_OFF){ + rc = cam_ois_power_up(o_ctrl); + if(rc != 0) { + CAM_ERR(CAM_OIS, "ois power up failed"); + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + mutex_unlock(&(o_ctrl->ois_mutex)); + return rc; + } + } else { + CAM_ERR(CAM_OIS, "ois type=%d,OIS already power on, no need to power on again",o_ctrl->ois_type); + } + CAM_ERR(CAM_OIS, "ois power up successful"); + o_ctrl->ois_power_state = CAM_OIS_POWER_ON; + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + } + o_ctrl->cam_ois_state = CAM_OIS_CONFIG; + mutex_unlock(&(o_ctrl->ois_mutex)); + mutex_lock(&(o_ctrl->do_ioctl_ois)); + if(o_ctrl->ois_download_fw_done == CAM_OIS_FW_NOT_DOWNLOAD){ + rc = DownloadFW(o_ctrl); + if(rc != 0) { + CAM_ERR(CAM_OIS, "ois download fw failed"); + o_ctrl->ois_download_fw_done = CAM_OIS_FW_NOT_DOWNLOAD; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + return rc; + } else { + o_ctrl->ois_download_fw_done = CAM_OIS_FW_DOWNLOAD_DONE; + } + } + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + return rc; +} +#endif +static long cam_ois_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_ois_ctrl_t *o_ctrl = v4l2_get_subdevdata(sd); + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ois_driver_cmd(o_ctrl, arg); + break; +#ifdef DOWNLOAD_OIS_FW_BEFORE + case VIDIOC_CAM_FTM_POWNER_UP: + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_ON){ + CAM_INFO(CAM_OIS, "do not need to create ois download fw thread"); + o_ctrl->ois_power_down_thread_exit = true; + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + return rc; + } else { + CAM_INFO(CAM_OIS, "create ois download fw thread"); + o_ctrl->ois_downloadfw_thread = kthread_run(ois_download_fw_thread, o_ctrl, o_ctrl->ois_name); + if (!o_ctrl->ois_downloadfw_thread) { + CAM_ERR(CAM_OIS, "create ois download fw thread failed"); + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + return -1; + } + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + mutex_lock(&(o_ctrl->do_ioctl_ois)); + o_ctrl->ois_fd_have_close_state = CAM_OIS_IS_OPEN; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); + break; +#endif + default: + rc = -ENOIOCTLCMD; + break; + } + + return rc; +} + +static int cam_ois_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_ois_ctrl_t *o_ctrl = + v4l2_get_subdevdata(sd); + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "o_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(o_ctrl->ois_mutex)); +#ifdef DOWNLOAD_OIS_FW_BEFORE + //when close ois,should be disable ois + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_ON){ + RamWrite32A_oneplus(o_ctrl,0xf012,0x0); + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + mutex_lock(&(o_ctrl->do_ioctl_ois)); + o_ctrl->ois_fd_have_close_state = CAM_OIS_IS_DOING_CLOSE; + mutex_unlock(&(o_ctrl->do_ioctl_ois)); +#endif + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + + return 0; +} + +static int32_t cam_ois_update_i2c_info(struct cam_ois_ctrl_t *o_ctrl, + struct cam_ois_i2c_info_t *i2c_info) +{ + struct cam_sensor_cci_client *cci_client = NULL; + + if (o_ctrl->io_master_info.master_type == CCI_MASTER) { + cci_client = o_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_OIS, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = o_ctrl->cci_i2c_master; + cci_client->sid = (i2c_info->slave_addr) >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_ois_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_OIS, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_ois_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) { + CAM_ERR(CAM_OIS, + "Failed in ois suddev handling rc %d", + rc); + return rc; + } + break; + default: + CAM_ERR(CAM_OIS, "Invalid compat ioctl: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_OIS, + "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + return rc; +} +#endif + +static const struct v4l2_subdev_internal_ops cam_ois_internal_ops = { + .close = cam_ois_subdev_close, +}; + +static struct v4l2_subdev_core_ops cam_ois_subdev_core_ops = { + .ioctl = cam_ois_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_ois_init_subdev_do_ioctl, +#endif +}; + +static struct v4l2_subdev_ops cam_ois_subdev_ops = { + .core = &cam_ois_subdev_core_ops, +}; + +static int cam_ois_init_subdev_param(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + + o_ctrl->v4l2_dev_str.internal_ops = &cam_ois_internal_ops; + o_ctrl->v4l2_dev_str.ops = &cam_ois_subdev_ops; + strlcpy(o_ctrl->device_name, CAM_OIS_NAME, + sizeof(o_ctrl->device_name)); + o_ctrl->v4l2_dev_str.name = o_ctrl->device_name; + o_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + o_ctrl->v4l2_dev_str.ent_function = CAM_OIS_DEVICE_TYPE; + o_ctrl->v4l2_dev_str.token = o_ctrl; + + rc = cam_register_subdev(&(o_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_OIS, "fail to create subdev"); + + return rc; +} + +static int cam_ois_i2c_driver_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct cam_ois_ctrl_t *o_ctrl = NULL; + struct cam_ois_soc_private *soc_private = NULL; + + if (client == NULL || id == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args client: %pK id: %pK", + client, id); + return -EINVAL; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_OIS, "i2c_check_functionality failed"); + goto probe_failure; + } + + o_ctrl = kzalloc(sizeof(*o_ctrl), GFP_KERNEL); + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "kzalloc failed"); + rc = -ENOMEM; + goto probe_failure; + } + + i2c_set_clientdata(client, o_ctrl); + + o_ctrl->soc_info.dev = &client->dev; + o_ctrl->soc_info.dev_name = client->name; + o_ctrl->ois_device_type = MSM_CAMERA_I2C_DEVICE; + o_ctrl->io_master_info.master_type = I2C_MASTER; + o_ctrl->io_master_info.client = client; + + soc_private = kzalloc(sizeof(struct cam_ois_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto octrl_free; + } + + o_ctrl->soc_info.soc_private = soc_private; + rc = cam_ois_driver_soc_init(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "failed: cam_sensor_parse_dt rc %d", rc); + goto soc_free; + } + + rc = cam_ois_init_subdev_param(o_ctrl); + if (rc) + goto soc_free; + + o_ctrl->cam_ois_state = CAM_OIS_INIT; + + return rc; + +soc_free: + kfree(soc_private); +octrl_free: + kfree(o_ctrl); +probe_failure: + return rc; +} + +static int cam_ois_i2c_driver_remove(struct i2c_client *client) +{ + int i; + struct cam_ois_ctrl_t *o_ctrl = i2c_get_clientdata(client); + struct cam_hw_soc_info *soc_info; + struct cam_ois_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "ois device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_OIS, "i2c driver remove invoked"); + soc_info = &o_ctrl->soc_info; + + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + + soc_private = + (struct cam_ois_soc_private *)soc_info->soc_private; + power_info = &soc_private->power_info; + + kfree(o_ctrl->soc_info.soc_private); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); + kfree(o_ctrl); + + return 0; +} + +static int32_t cam_ois_platform_driver_probe( + struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_ois_ctrl_t *o_ctrl = NULL; + struct cam_ois_soc_private *soc_private = NULL; + + o_ctrl = kzalloc(sizeof(struct cam_ois_ctrl_t), GFP_KERNEL); + if (!o_ctrl) + return -ENOMEM; + + o_ctrl->soc_info.pdev = pdev; + o_ctrl->pdev = pdev; + o_ctrl->soc_info.dev = &pdev->dev; + o_ctrl->soc_info.dev_name = pdev->name; + + o_ctrl->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE; + + o_ctrl->io_master_info.master_type = CCI_MASTER; + o_ctrl->io_master_info.cci_client = kzalloc( + sizeof(struct cam_sensor_cci_client), GFP_KERNEL); + if (!o_ctrl->io_master_info.cci_client) + goto free_o_ctrl; + + soc_private = kzalloc(sizeof(struct cam_ois_soc_private), + GFP_KERNEL); + if (!soc_private) { + rc = -ENOMEM; + goto free_cci_client; + } + o_ctrl->soc_info.soc_private = soc_private; + soc_private->power_info.dev = &pdev->dev; + + INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_mode_data.list_head)); + mutex_init(&(o_ctrl->ois_mutex)); + mutex_init(&(o_ctrl->ois_read_mutex)); +#ifdef DOWNLOAD_OIS_FW_BEFORE + mutex_init(&(o_ctrl->do_ioctl_ois)); + o_ctrl->ois_download_fw_done = CAM_OIS_FW_NOT_DOWNLOAD; + o_ctrl->ois_fd_have_close_state = CAM_OIS_IS_OPEN; +#endif +#ifdef ENABLE_OIS_DELAY_POWER_DOWN + o_ctrl->ois_power_down_thread_state = CAM_OIS_POWER_DOWN_THREAD_STOPPED; + o_ctrl->ois_power_state = CAM_OIS_POWER_OFF; + o_ctrl->ois_power_down_thread_exit = false; + mutex_init(&(o_ctrl->ois_power_down_mutex)); +#endif + rc = cam_ois_driver_soc_init(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "failed: soc init rc %d", rc); + goto free_soc; + } + + rc = cam_ois_init_subdev_param(o_ctrl); + if (rc) + goto free_soc; + + rc = cam_ois_update_i2c_info(o_ctrl, &soc_private->i2c_info); + if (rc) { + CAM_ERR(CAM_OIS, "failed: to update i2c info rc %d", rc); + goto unreg_subdev; + } + o_ctrl->bridge_intf.device_hdl = -1; + + platform_set_drvdata(pdev, o_ctrl); + o_ctrl->cam_ois_state = CAM_OIS_INIT; + + mutex_init(&(o_ctrl->ois_hall_data_mutex)); + mutex_init(&(o_ctrl->ois_poll_thread_mutex)); + + o_ctrl->ois_poll_thread_control_cmd = 0; + if (kfifo_alloc(&o_ctrl->ois_hall_data_fifo, SAMPLE_COUNT_IN_DRIVER*SAMPLE_SIZE_IN_DRIVER, GFP_KERNEL)) { + CAM_ERR(CAM_OIS, "failed to init ois_hall_data_fifo"); + } + + if (kfifo_alloc(&o_ctrl->ois_hall_data_fifoV2, SAMPLE_COUNT_IN_DRIVER*SAMPLE_SIZE_IN_DRIVER, GFP_KERNEL)) { + CAM_ERR(CAM_OIS, "failed to init ois_hall_data_fifoV2"); + } + InitOISResource(o_ctrl); + + return rc; +unreg_subdev: + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); +free_soc: + kfree(soc_private); +free_cci_client: + kfree(o_ctrl->io_master_info.cci_client); +free_o_ctrl: + kfree(o_ctrl); + return rc; +} + +static int cam_ois_platform_driver_remove(struct platform_device *pdev) +{ + int i; + struct cam_ois_ctrl_t *o_ctrl; + struct cam_ois_soc_private *soc_private; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info; + + o_ctrl = platform_get_drvdata(pdev); + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "ois device is NULL"); + return -EINVAL; + } + + CAM_INFO(CAM_OIS, "platform driver remove invoked"); + soc_info = &o_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + kfree(o_ctrl->soc_info.soc_private); + kfree(o_ctrl->io_master_info.cci_client); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); + kfree(o_ctrl); + + return 0; +} + +static const struct of_device_id cam_ois_dt_match[] = { + { .compatible = "qcom,ois" }, + { } +}; + + +MODULE_DEVICE_TABLE(of, cam_ois_dt_match); + +static struct platform_driver cam_ois_platform_driver = { + .driver = { + .name = "qcom,ois", + .owner = THIS_MODULE, + .of_match_table = cam_ois_dt_match, + }, + .probe = cam_ois_platform_driver_probe, + .remove = cam_ois_platform_driver_remove, +}; +static const struct i2c_device_id cam_ois_i2c_id[] = { + { "msm_ois", (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_ois_i2c_driver = { + .id_table = cam_ois_i2c_id, + .probe = cam_ois_i2c_driver_probe, + .remove = cam_ois_i2c_driver_remove, + .driver = { + .name = "msm_ois", + }, +}; + +static struct cam_ois_registered_driver_t registered_driver = { + 0, 0}; + +static int __init cam_ois_driver_init(void) +{ + int rc = 0; + + rc = platform_driver_register(&cam_ois_platform_driver); + if (rc) { + CAM_ERR(CAM_OIS, "platform_driver_register failed rc = %d", + rc); + return rc; + } + + registered_driver.platform_driver = 1; + + rc = i2c_add_driver(&cam_ois_i2c_driver); + if (rc) { + CAM_ERR(CAM_OIS, "i2c_add_driver failed rc = %d", rc); + return rc; + } + + registered_driver.i2c_driver = 1; + return rc; +} + +static void __exit cam_ois_driver_exit(void) +{ + if (registered_driver.platform_driver) + platform_driver_unregister(&cam_ois_platform_driver); + + if (registered_driver.i2c_driver) + i2c_del_driver(&cam_ois_i2c_driver); +} + +module_init(cam_ois_driver_init); +module_exit(cam_ois_driver_exit); +MODULE_DESCRIPTION("CAM OIS driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h new file mode 100755 index 0000000000000000000000000000000000000000..84e878dcb266dbd9e02c3238c9093560e15fc300 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_OIS_DEV_H_ +#define _CAM_OIS_DEV_H_ + +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-ioctl.h> +#include <media/cam_sensor.h> +#include <cam_sensor_i2c.h> +#include <cam_sensor_spi.h> +#include <cam_sensor_io.h> +#include <cam_cci_dev.h> +#include <cam_req_mgr_util.h> +#include <cam_req_mgr_interface.h> +#include <cam_mem_mgr.h> +#include <cam_subdev.h> +#include "cam_soc_util.h" +#include "cam_context.h" +#include <linux/kfifo.h> + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +#define GET_HALL_DATA_VERSION_DEFUALT 0 +#define GET_HALL_DATA_VERSION_V2 1 +#define GET_HALL_DATA_VERSION_V3 2 +struct cam_ois_hall_data_in_ois_aligned { + uint16_t hall_data_cnt; + uint32_t hall_data; +}; + +struct cam_ois_hall_data_in_driver { + uint32_t high_dword; + uint32_t low_dword; + uint32_t hall_data; +}; + +#define SAMPLE_COUNT_IN_DRIVER 100 +#define SAMPLE_COUNT_IN_OIS 34 +#define SAMPLE_SIZE_IN_OIS 6 +#define SAMPLE_SIZE_IN_OIS_ALIGNED (sizeof(struct cam_ois_hall_data_in_ois_aligned)) +#define SAMPLE_SIZE_IN_DRIVER (sizeof(struct cam_ois_hall_data_in_driver)) +#define CLOCK_TICKCOUNT_MS 19200 +#define OIS_MAGIC_NUMBER 0x7777 +#define OIS_MAX_COUNTER 36 + +#define ENABLE_OIS_DELAY_POWER_DOWN + +#ifdef ENABLE_OIS_DELAY_POWER_DOWN +#define OIS_POWER_DOWN_DELAY 500//ms +enum cam_ois_power_down_thread_state { + CAM_OIS_POWER_DOWN_THREAD_RUNNING, + CAM_OIS_POWER_DOWN_THREAD_STOPPED, +}; + +enum cam_ois_power_state { + CAM_OIS_POWER_ON, + CAM_OIS_POWER_OFF, +}; +#endif +#ifdef DOWNLOAD_OIS_FW_BEFORE +enum cam_ois_close_state { + CAM_OIS_IS_OPEN, + CAM_OIS_IS_DOING_CLOSE, + CAM_OIS_IS_CLOSE, +}; +enum cam_ois_download_fw_state { + CAM_OIS_FW_NOT_DOWNLOAD, + CAM_OIS_FW_DOWNLOAD_DONE, +}; +#endif + +enum cam_ois_state { + CAM_OIS_INIT, + CAM_OIS_ACQUIRE, + CAM_OIS_CONFIG, + CAM_OIS_START, +}; + +enum cam_ois_type_vendor { + CAM_OIS_MASTER, + CAM_OIS_SLAVE, + CAM_OIS_TYPE_MAX, +}; + +enum cam_ois_state_vendor { + CAM_OIS_INVALID, + CAM_OIS_FW_DOWNLOADED, + CAM_OIS_READY, +}; + +enum cam_ois_control_cmd { + CAM_OIS_START_POLL_THREAD, + CAM_OIS_STOP_POLL_THREAD, +}; + +/** + * struct cam_ois_registered_driver_t - registered driver info + * @platform_driver : flag indicates if platform driver is registered + * @i2c_driver : flag indicates if i2c driver is registered + * + */ +struct cam_ois_registered_driver_t { + bool platform_driver; + bool i2c_driver; +}; + +/** + * struct cam_ois_i2c_info_t - I2C info + * @slave_addr : slave address + * @i2c_freq_mode : i2c frequency mode + * + */ +struct cam_ois_i2c_info_t { + uint16_t slave_addr; + uint8_t i2c_freq_mode; +}; + +/** + * struct cam_ois_soc_private - ois soc private data structure + * @ois_name : ois name + * @i2c_info : i2c info structure + * @power_info : ois power info + * + */ +struct cam_ois_soc_private { + const char *ois_name; + struct cam_ois_i2c_info_t i2c_info; + struct cam_sensor_power_ctrl_t power_info; +}; + +/** + * struct cam_ois_intf_params - bridge interface params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_ois_intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_ois_ctrl_t - OIS ctrl private data + * @device_name : ois device_name + * @pdev : platform device + * @ois_mutex : ois mutex + * @soc_info : ois soc related info + * @io_master_info : Information about the communication master + * @cci_i2c_master : I2C structure + * @v4l2_dev_str : V4L2 device structure + * @bridge_intf : bridge interface params + * @i2c_init_data : ois i2c init settings + * @i2c_mode_data : ois i2c mode settings + * @i2c_calib_data : ois i2c calib settings + * @ois_device_type : ois device type + * @cam_ois_state : ois_device_state + * @ois_fw_flag : flag for firmware download + * @is_ois_calib : flag for Calibration data + * @opcode : ois opcode + * @device_name : Device name + * + */ +struct cam_ois_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct platform_device *pdev; + struct mutex ois_mutex; + struct cam_hw_soc_info soc_info; + struct camera_io_master io_master_info; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct cam_subdev v4l2_dev_str; + struct cam_ois_intf_params bridge_intf; + struct i2c_settings_array i2c_init_data; + struct i2c_settings_array i2c_calib_data; + struct i2c_settings_array i2c_mode_data; + enum msm_camera_device_type_t ois_device_type; + enum cam_ois_state cam_ois_state; + char ois_name[32]; + uint8_t ois_fw_flag; + uint8_t is_ois_calib; + struct cam_ois_opcode opcode; + enum cam_ois_type_vendor ois_type; //Master or Slave + uint8_t ois_gyro_position; //Gyro positon + uint8_t ois_gyro_vendor; //Gyro vendor + uint8_t ois_actuator_vendor; //Actuator vendor + uint8_t ois_module_vendor; //Module vendor + struct mutex ois_read_mutex; + bool ois_read_thread_start_to_read; + struct task_struct *ois_read_thread; + struct mutex ois_hall_data_mutex; + struct mutex ois_poll_thread_mutex; + bool ois_poll_thread_exit; + enum cam_ois_control_cmd ois_poll_thread_control_cmd; + struct task_struct *ois_poll_thread; + struct kfifo ois_hall_data_fifo; + struct kfifo ois_hall_data_fifoV2; +#ifdef ENABLE_OIS_DELAY_POWER_DOWN + struct mutex ois_power_down_mutex; + enum cam_ois_power_down_thread_state ois_power_down_thread_state; + enum cam_ois_power_state ois_power_state; + bool ois_power_down_thread_exit; +#endif +#ifdef DOWNLOAD_OIS_FW_BEFORE + struct task_struct *ois_downloadfw_thread; + struct mutex do_ioctl_ois; + enum cam_ois_download_fw_state ois_download_fw_done; + enum cam_ois_close_state ois_fd_have_close_state; +#endif +}; + +#endif /*_CAM_OIS_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c new file mode 100755 index 0000000000000000000000000000000000000000..dcea33b57b86ff142ce7e41ece4c0b6fc75c624e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <cam_sensor_cmn_header.h> +#include <cam_sensor_util.h> +#include <cam_sensor_io.h> +#include <cam_req_mgr_util.h> + +#include "cam_ois_soc.h" +#include "cam_debug_util.h" + +/** + * @e_ctrl: ctrl structure + * + * Parses ois dt + */ +static int cam_ois_get_dt_data(struct cam_ois_ctrl_t *o_ctrl) +{ + int i, rc = 0; + struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info; + struct cam_ois_soc_private *soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; + struct device_node *of_node = NULL; + + of_node = soc_info->dev->of_node; + + if (!of_node) { + CAM_ERR(CAM_OIS, "of_node is NULL, device type %d", + o_ctrl->ois_device_type); + return -EINVAL; + } + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, "cam_soc_util_get_dt_properties rc %d", + rc); + return rc; + } + + if (!soc_info->gpio_data) { + CAM_INFO(CAM_OIS, "No GPIO found"); + return 0; + } + + if (!soc_info->gpio_data->cam_gpio_common_tbl_size) { + CAM_INFO(CAM_OIS, "No GPIO found"); + return -EINVAL; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &power_info->gpio_num_info); + if ((rc < 0) || (!power_info->gpio_num_info)) { + CAM_ERR(CAM_OIS, "No/Error OIS GPIOs"); + return -EINVAL; + } + + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = devm_clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_SENSOR, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + return rc; + } + } + + return rc; +} +/** + * @o_ctrl: ctrl structure + * + * This function is called from cam_ois_platform/i2c_driver_probe, it parses + * the ois dt node. + */ +int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc = 0; + const char *p = NULL; + struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info; + struct device_node *of_node = NULL; + struct device_node *of_parent = NULL; + int ret = 0; + int id; + + if (!soc_info->dev) { + CAM_ERR(CAM_OIS, "soc_info is not initialized"); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + if (!of_node) { + CAM_ERR(CAM_OIS, "dev.of_node NULL"); + return -EINVAL; + } + + if (o_ctrl->ois_device_type == MSM_CAMERA_PLATFORM_DEVICE) { + rc = of_property_read_u32(of_node, "cci-master", + &o_ctrl->cci_i2c_master); + if (rc < 0) { + CAM_DBG(CAM_OIS, "failed rc %d", rc); + return rc; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &o_ctrl->cci_num) < 0) + /* Set default master 0 */ + o_ctrl->cci_num = CCI_DEVICE_0; + + o_ctrl->io_master_info.cci_client->cci_device = o_ctrl->cci_num; + CAM_DBG(CAM_OIS, "cci-device %d", o_ctrl->cci_num); + + } + + rc = cam_ois_get_dt_data(o_ctrl); + if (rc < 0) + CAM_DBG(CAM_OIS, "failed: ois get dt data rc %d", rc); + + ret = of_property_read_u32(of_node, "ois_gyro,position", &id); + if (ret) { + o_ctrl->ois_gyro_position = 1; + CAM_ERR(CAM_OIS, "get ois_gyro,position failed rc:%d, set default value to %d", ret, o_ctrl->ois_gyro_position); + } else { + o_ctrl->ois_gyro_position = (uint8_t)id; + CAM_INFO(CAM_OIS, "read ois_gyro,position success, value:%d", o_ctrl->ois_gyro_position); + } + + ret = of_property_read_u32(of_node, "ois,type", &id); + if (ret) { + o_ctrl->ois_type = CAM_OIS_MASTER; + CAM_ERR(CAM_OIS, "get ois,type failed rc:%d, default %d", ret, o_ctrl->ois_type); + } else { + o_ctrl->ois_type = (uint8_t)id; + CAM_INFO(CAM_OIS, "read ois,type success, value:%d", o_ctrl->ois_type); + } + + ret = of_property_read_u32(of_node, "ois_gyro,type", &id); + if (ret) { + o_ctrl->ois_gyro_vendor = 0x02; + CAM_ERR(CAM_OIS, "get ois_gyro,type failed rc:%d, default %d", ret, o_ctrl->ois_gyro_vendor); + } else { + o_ctrl->ois_gyro_vendor = (uint8_t)id; + CAM_INFO(CAM_OIS, "read ois_gyro,type success, value:%d", o_ctrl->ois_gyro_vendor); + } + + ret = of_property_read_string_index(of_node, "ois,name", 0, (const char **)&p); + if (ret) { + CAM_ERR(CAM_OIS, "get ois,name failed rc:%d, set default value to %s", ret, o_ctrl->ois_name); + } else { + memcpy(o_ctrl->ois_name, p, sizeof(o_ctrl->ois_name)); + CAM_INFO(CAM_OIS, "read ois,name success, value:%s", o_ctrl->ois_name); + } + + ret = of_property_read_u32(of_node, "ois_module,vendor", &id); + if (ret) { + o_ctrl->ois_module_vendor = 0x01; + CAM_ERR(CAM_OIS, "get ois_module,vendor failed rc:%d, default %d", ret, o_ctrl->ois_module_vendor); + } else { + o_ctrl->ois_module_vendor = (uint8_t)id; + CAM_INFO(CAM_OIS, "read ois_module,vendor success, value:%d", o_ctrl->ois_module_vendor); + } + + ret = of_property_read_u32(of_node, "ois_actuator,vednor", &id); + if (ret) { + o_ctrl->ois_actuator_vendor = 0x01; + CAM_ERR(CAM_OIS, "get ois_actuator,vednor failed rc:%d, default %d", ret, o_ctrl->ois_actuator_vendor); + } else { + o_ctrl->ois_actuator_vendor = (uint8_t)id; + CAM_INFO(CAM_OIS, "read ois_actuator,vednor success, value:%d", o_ctrl->ois_actuator_vendor); + } + + ret = of_property_read_u32(of_node, "ois,fw", &id); + if (ret) { + o_ctrl->ois_fw_flag = 0x01; + CAM_ERR(CAM_OIS, "get ois,fw failed rc:%d, default %d", ret, o_ctrl->ois_fw_flag); + } else { + o_ctrl->ois_fw_flag = (uint8_t)id; + CAM_INFO(CAM_OIS, "read ois,fw success, value:%d", o_ctrl->ois_fw_flag); + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..fd2c209c7504b2cb5b54ba6840ecffcb68c535f0 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ +#ifndef _CAM_OIS_SOC_H_ +#define _CAM_OIS_SOC_H_ + +#include "cam_ois_dev.h" + +int cam_ois_driver_soc_init(struct cam_ois_ctrl_t *o_ctrl); + +#endif/* _CAM_OIS_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Accuracy.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Accuracy.c new file mode 100644 index 0000000000000000000000000000000000000000..9b603645dd855e9c09098a85e2b4dde54790b685 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Accuracy.c @@ -0,0 +1,174 @@ +/*======================================================================= + Accuracy Test Sample code for LC898124 + by Rex.Tang + 2016.03.27 +========================================================================*/ +#include "math.h" +#include "OisLc898124EP3.h" +#include "Ois.h" +#include "Accuracy.h" + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A(int addr, int data); +extern void RamRead32A( unsigned short addr, void * data ); +extern void WitTim( unsigned short UsWitTim ); + +/* Raw data buffers */ +//Dual_Axis_t xy_raw_data[360/DEGSTEP + 1]; +Dual_Axis_t xy_raw_data[360/3 + 1]; +float xMaxAcc, yMaxAcc; +float xLimit, yLimit; + +static float fix2float(unsigned int fix) +{ + if((fix & 0x80000000) > 0) + { + return ((float)fix-(float)0x100000000)/(float)0x7FFFFFFF; + } else { + return (float)fix/(float)0x7FFFFFFF; + } +} + +static unsigned int float2fix(float f) +{ + if(f < 0) + { + return (unsigned int)(f * (float)0x7FFFFFFF + 0x100000000); + } else { + return (unsigned int)(f * (float)0x7FFFFFFF); + } +} + +/*------------------------------------------------------------------- + Function Name: Accuracy + Param: none + Return: value = 0 (no NG point) + value > 0 (High byte: X total NG points; + Low byte: Y total NG points) +--------------------------------------------------------------------*/ +//unsigned short Accuracy() +unsigned short Accuracy(float ACCURACY, unsigned short RADIUS, unsigned short DEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3) +{ + float xpos, ypos; + unsigned int xhall_value, yhall_value; + float xMaxHall, yMaxHall; + unsigned short xng = 0, yng = 0; + unsigned short deg; + float xRadius, yRadius; + unsigned int xGyrogain, yGyrogain; + unsigned int xGLenz, yGLenz; + unsigned int xG2x4xb, yG2x4xb; + + // Get Gyro gain + RamRead32A(GyroFilterTableX_gxzoom, &xGyrogain); + RamRead32A(GyroFilterTableY_gyzoom, &yGyrogain); + + // Get Lenz + RamRead32A(GyroFilterTableX_gxlenz, &xGLenz); + RamRead32A(GyroFilterTableY_gylenz, &yGLenz); + + // Get Lenz + RamRead32A(Gyro_ShiftX_RG, &xG2x4xb); + RamRead32A(Gyro_ShiftY_RG, &yG2x4xb); + + // Calculate Radius (100um) + xRadius = 0.10546843F * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * (1 << (unsigned char)( xG2x4xb >> 8 )); + yRadius = 0.10546843F * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * (1 << (unsigned char)( yG2x4xb >> 8 )); + TRACE("xRadius = %d, yRadius = %d", (int)(xRadius*1000), (int)(yRadius*1000)); + + // Calculate Limit + xLimit = ACCURACY / 100 * xRadius; + yLimit = ACCURACY / 100 * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * RADIUS / 100; + yRadius = yRadius * RADIUS / 100; + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check + xpos = xRadius * cos(0); + ypos = yRadius * sin(0); + RamWrite32A(HALL_RAM_HXOFF1, float2fix(xpos)); + RamWrite32A(HALL_RAM_HYOFF1, float2fix(ypos)); + WitTim(WAIT_MSEC1); + + for( deg = 0; deg <= 360; deg += DEGSTEP ) // 0-360 degree + { + xpos = xRadius * cos(deg * PI/180); + ypos = yRadius * sin(deg * PI/180); + RamWrite32A(HALL_RAM_HXOFF1, float2fix(xpos)); + RamWrite32A(HALL_RAM_HYOFF1, float2fix(ypos)); + + if(deg ==0) + WitTim(500); + + xMaxHall = 0; + yMaxHall = 0; + WitTim(WAIT_MSEC2); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim(WAIT_MSEC3); + RamRead32A( HALL_RAM_HXOUT0, &xhall_value ); + RamRead32A( HALL_RAM_HYOUT0, &yhall_value ); + if(fabsf(fix2float(xhall_value) - xpos) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value) - xpos; + if(fabsf(fix2float(yhall_value) - ypos) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value) - ypos; + } + + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + + // Save raw data + xy_raw_data[deg/DEGSTEP].xpos = xpos; + xy_raw_data[deg/DEGSTEP].xhall = xMaxHall + xpos; + xy_raw_data[deg/DEGSTEP].ypos = ypos; + xy_raw_data[deg/DEGSTEP].yhall = yMaxHall + ypos; + + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + + } + RamWrite32A(HALL_RAM_HXOFF1, 0); // x = center + RamWrite32A(HALL_RAM_HYOFF1, 0); // y = center + + return (xng << 8) | yng; +} + +//unsigned short HallCheck(void) +unsigned short HallCheck(float ACCURACY, unsigned short RADIUS, unsigned short DEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3) +{ + short i; +// unsigned short ret = Accuracy(); + unsigned short ret = Accuracy(ACCURACY, RADIUS, DEGSTEP, WAIT_MSEC1, WAIT_MSEC2, WAIT_MSEC3); + + if(ret) + { + TRACE("\n VCM has NG points: X = %d, Y = %d", ret >> 8, ret & 0xff); + } else { + TRACE("\n VCM is good!"); + } + + // Max Accuracy + //TRACE("\n X Max Accuracy = %f, Y Max Accuracy = %f", xMaxAcc, yMaxAcc); + TRACE("\n X Max Accuracy = %d, Y Max Accuracy = %d", (int)(xMaxAcc*1000), (int)(yMaxAcc*1000)); + + // Limit vale + //TRACE("\n xLimit = %f, yLimit = %f", xLimit, yLimit); + TRACE("\n xLimit = %d, yLimit = %d", (int)(xLimit*1000), (int)(yLimit*1000)); + + // Circle + for(i=0; i<=(360/DEGSTEP); i++) + { + //TRACE("\n xPos = %f, xHall = %f, yPos = %f, yHall = %f", xy_raw_data[i].xpos, xy_raw_data[i].xhall, xy_raw_data[i].ypos, xy_raw_data[i].yhall); + TRACE("\n xPos = %d, xHall = %d, yPos = %d, yHall = %d", (int)(xy_raw_data[i].xpos*1000), (int)(xy_raw_data[i].xhall*1000), (int)(xy_raw_data[i].ypos*1000), (int)(xy_raw_data[i].yhall*1000)); + } + + return( ret ); +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Accuracy.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Accuracy.h new file mode 100644 index 0000000000000000000000000000000000000000..be24c421482578064371808e71fe607cf262e3da --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Accuracy.h @@ -0,0 +1,27 @@ +/*======================================================================= + Accuracy Test Sample code for LC898124 + by Rex.Tang + 2016.03.27 +========================================================================*/ + +// Checking radius +//#define RADIUS 75 // 75um + +// Parameter define +//#define DEGSTEP 3 // Degree of one step (3‹) +//#define ACCURACY 3.0F // Accuracy (}3.0um) +//#define WAIT_MSEC 10 // Each step wait time(msec) +#define LOOPTIME 3 // Read times at each step + +// Constants +#define PI 3.14159 // ƒÎ + + +typedef struct tag_Dual_Axis +{ + float xpos; + float xhall; + float ypos; + float yhall; +}Dual_Axis_t; + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/DownloadCmd.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/DownloadCmd.c new file mode 100755 index 0000000000000000000000000000000000000000..e637704b26216e469fc43d2bc2064706908cd8e0 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/DownloadCmd.c @@ -0,0 +1,378 @@ +//******************************************************************************** +// << LC898124 Evaluation Soft >> +//******************************************************************************** +//#define DEBUG_FRA +//************************** +// Include Header File +//************************** +#include "Ois.h" + +#if ((((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) && (SELECT_MODEL == 0x00)) // SEMCO or Oneplus +#include "LC898124EP3_Code_0_1_0_2_2_0.h" // Gyro=LSM6DSM, SO2823 +#include "LC898124EP3_Code_0_1_0_2_2_1.h" // Gyro=LSM6DSM, FRA, SO2823 +#endif +#if ((((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) && (SELECT_MODEL == 0x01)) // SEMCO or Oneplus +#include "LC898124EP3_Code_1_1_0_2_2_0.h" // Gyro=LSM6DSM, SO2823 +#include "LC898124EP3_Code_1_1_0_2_2_1.h" // Gyro=LSM6DSM, FRA, SO2823 +#endif +#if ((((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) && (SELECT_MODEL == 0x02)) // SEMCO or Oneplus +#include "LC898124EP3_Code_2_1_0_3_2_0.h" // Gyro=BMI260, SO2823 +#include "LC898124EP3_Code_2_1_0_3_2_1.h" // Gyro=BMI260, FRA, SO2823 +#endif +#if (((SELECT_VENDOR&0x02) == 0x02) || ((SELECT_VENDOR&0x80) == 0x80)) // OFILM or Oneplus +#include "LC898124EP3_Code_1_2_1_2_2_0.h" // Gyro=LSM6DSM, M12337 +#include "LC898124EP3_Code_1_2_1_2_2_1.h" // Gyro=LSM6DSM, FRA, M12337 +#endif + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A( unsigned short, int ); +extern void RamRead32A( unsigned short, void * ); +/* for I2C Multi Translation : Burst Mode*/ +extern void CntWrt( void *, unsigned short) ; +extern void CntRd( unsigned int addr, void * PcSetDat, unsigned short UsDatNum ) ; +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( unsigned short UsWitTim ); + +//**************************************************** +// LOCAL RAM LIST +//**************************************************** +#define BURST_LENGTH_PM ( 12*5 ) // 60 å¿…ãš5ã®å€æ•°ã§è¨­å®šã™ã‚‹ã“ã¨ã€‚最大64Byteã¾ã§ +#define BURST_LENGTH_DM ( 10*6 ) // 60 å¿…ãš6ã®å€æ•°ã§è¨­å®šã™ã‚‹ã“ã¨ã€‚最大64Byteã¾ã§ +#define BURST_LENGTH BURST_LENGTH_PM + +//******************************************************************************** +// Function Name : DMIOWrite32 +// Retun Value : None +// Argment Value : IOadrs, IOdata +// Explanation : Read From code version Command +// History : First edition +//******************************************************************************** +void DMIOWrite32( UINT32 IOadrs, UINT32 IOdata ) +{ +#if 1 + UINT8 data[10]; + data[0] = 0xC0; // Pmem address set + data[1] = 0x00; // Command High + data[2] = (UINT8)(IOadrs >>24); // IOadres + data[3] = (UINT8)(IOadrs >>16); // Command High + data[4] = (UINT8)(IOadrs >> 8); // Command High + data[5] = (UINT8)(IOadrs >> 0); // Command High + data[6] = (UINT8)(IOdata >>24); // IOadres + data[7] = (UINT8)(IOdata >>16); // Command High + data[8] = (UINT8)(IOdata >> 8); // Command High + data[9] = (UINT8)(IOdata >> 0); // Command High + CntWrt( data, 10 ); // I2C 1Byte address. +#else + RamWrite32A( CMD_IO_ADR_ACCESS, IOadrs ) ; + RamWrite32A( CMD_IO_DAT_ACCESS, IOdata ) ; +#endif +}; + +//******************************************************************************** +// Function Name : DownloadToEP3 +// Retun Value : NON +// Argment Value : PMlength: 5byte unit, DMlength : 1Byte unit +// Explanation : <Pmem Memory> Write Data +// History : First edition +//******************************************************************************** +unsigned char DownloadToEP3( const UINT8* DataPM, UINT32 LengthPM, UINT32 Parity, const UINT8* DataDM, UINT32 LengthDMA , UINT32 LengthDMB ) +{ + UINT32 i, j; + UINT8 data[64]; // work fifo buffer max size 64 byte + UINT8 Remainder; // 余り + UINT32 UlReadVal, UlCnt; + UINT32 ReadVerifyPM = 0, ReadVerifyDMA = 0, ReadVerifyDMB = 0; // Checksum + UINT32 VerifySUM = 0; + +//*******************************************************************************// +//* pre-check ROM code version *// +//*******************************************************************************// + RamRead32A( CMD_ROMVER , &UlReadVal ); + if( UlReadVal == OLD_VER ) return( 3 ); /* ROM code version error */ + +//-------------------------------------------------------------------------------- +// 0. Start up to boot exection +//-------------------------------------------------------------------------------- + RamWrite32A( CMD_IO_ADR_ACCESS , ROMINFO ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + switch ( (UINT8)UlReadVal ){ + case 0x0A: /* Normal Rom program execution */ + break; + + case 0x01: /* Normal Ram program execution */ + /* å†Donloadã®ãŸã‚ã«ã¯ RomRebootã—ãªã‘れã°ãªã‚‰ãªã„。AutoDownloadã•ã›ã‚‹ãŸã‚ã«CORE_RSTã§å®Ÿè¡Œã•ã›ã‚‹*/ + DMIOWrite32( SYSDSP_REMAP, 0x00001000 ); // CORE_RST + WitTim( 6 ) ; // Bootプログラムを回ã™ã®ã«6msecå¿…è¦ã€‚ + break; + +// case 0x0B: +// case 0x08: + default: + return( 1 ); + } +//-------------------------------------------------------------------------------- +// 1. Download Program +//-------------------------------------------------------------------------------- + data[0] = 0x30; // Pmem address set + data[1] = 0x00; // Command High + data[2] = 0x10; // Command High + data[3] = 0x00; // Command High + data[4] = 0x00; // Command High + CntWrt( data, 5 ); // I2C 1Byte address. + // program start + data[0] = 0x40; // Pmem address set + Remainder = ( (LengthPM*5) / BURST_LENGTH_PM ); + for(i=0 ; i< Remainder ; i++) + { + UlCnt = 1; + for(j=0 ; j < BURST_LENGTH_PM; j++) data[UlCnt++] = *DataPM++; + + CntWrt( data, BURST_LENGTH_PM+1 ); // I2Caddresss 1Byte. + } + Remainder = ( (LengthPM*5) % BURST_LENGTH_PM); + if (Remainder != 0 ) + { + UlCnt = 1; + for(j=0 ; j < Remainder; j++) data[UlCnt++] = *DataPM++; +//TRACE("Remainder %d \n", (UINT8)Remainder ); + CntWrt( data, UlCnt ); // I2C 1Byte address. + } + // Chercksum start + data[0] = 0xF0; // Pmem address set + data[1] = 0x0A; // Command High + data[2] = (unsigned char)(( LengthPM & 0xFF00) >> 8 ); // Size High + data[3] = (unsigned char)(( LengthPM & 0x00FF) >> 0 ); // Size Low + CntWrt( data, 4 ); // I2C 2Byte addresss. + +//-------------------------------------------------------------------------------- +// 2. Download Table Data +//-------------------------------------------------------------------------------- +//TRACE("DM Start \n" ); + RamWrite32A( DmCheck_CheckSumDMA, 0 ); // DMA Parity Clear + RamWrite32A( DmCheck_CheckSumDMB, 0 ); // DMB Parity Clear + + /***** DMA Data Send *****/ + Remainder = ( (LengthDMA*6/4) / BURST_LENGTH_DM ); + for(i=0 ; i< Remainder ; i++) + { + CntWrt( (UINT8*)DataDM, BURST_LENGTH_DM ); // I2Caddresss 1Byte. + DataDM += BURST_LENGTH_DM; + } + Remainder = ( (LengthDMA*6/4) % BURST_LENGTH_DM ); + if (Remainder != 0 ) + { + CntWrt( (UINT8*)DataDM, (UINT8)Remainder ); // I2Caddresss 1Byte. + } + DataDM += Remainder; + + /***** DMB Data Send *****/ + Remainder = ( (LengthDMB*6/4) / BURST_LENGTH_DM ); + for( i=0 ; i< Remainder ; i++) /* ç¶šãã‹ã‚‰ */ + { + CntWrt( (UINT8*)DataDM, BURST_LENGTH_DM ); // I2Caddresss 1Byte. + DataDM += BURST_LENGTH_DM; + } + Remainder = ( (LengthDMB*6/4) % BURST_LENGTH_DM ); + if (Remainder != 0 ) + { + CntWrt( (UINT8*)DataDM, (UINT8)Remainder ); // I2Caddresss 1Byte. + } + +//-------------------------------------------------------------------------------- +// 3. Verify +//-------------------------------------------------------------------------------- + RamRead32A( PmCheck_CheckSum, &ReadVerifyPM ); + RamRead32A( DmCheck_CheckSumDMA, &ReadVerifyDMA ); + RamRead32A( DmCheck_CheckSumDMB, &ReadVerifyDMB ); + VerifySUM = ReadVerifyPM + ReadVerifyDMA + ReadVerifyDMB; + if(VerifySUM == Parity){ + CAM_ERR(CAM_OIS, "verify success. ReadVerifyPM=0x%x, ReadVerifyDMA=0x%x, ReadVerifyDMB=0x%x, VerifySUM=0x%x, Parity=0x%x", + ReadVerifyPM, ReadVerifyDMA, ReadVerifyDMB, VerifySUM, Parity); + } else { + CAM_ERR(CAM_OIS, "verify fail. ReadVerifyPM=0x%x, ReadVerifyDMA=0x%x, ReadVerifyDMB=0x%x, VerifySUM=0x%x, Parity=0x%x", + ReadVerifyPM, ReadVerifyDMA, ReadVerifyDMB, VerifySUM, Parity); + return( 2 ); + } + return(0); +} + + +//******************************************************************************** +// Function Name : ReMapMain +// Retun Value : NON +// Argment Value : NON +// Explanation : <Pmem Memory> Write Data +// History : First edition +//******************************************************************************** +void RemapMain( void ) +{ + RamWrite32A( 0xF000, 0x00000000 ) ; +} + +//******************************************************************************** +// Function Name : MonitorInfo124 +// Retun Value : NON +// Argment Value : NON +// Explanation : +// History : Second edition +//******************************************************************************** +void MonitorInfo124( DSPVER* Dspcode ) +{ +TRACE("Vendor : %02x \n", Dspcode->Vendor ); +TRACE("User : %02x \n", Dspcode->User ); +TRACE("Model : %02x \n", Dspcode->Model ); +TRACE("Version : %02x \n", Dspcode->Version ); + + +if(Dspcode->SpiMode == SPI_MST ) +TRACE("spi mode : Master\n"); +if(Dspcode->SpiMode == SPI_SLV ) +TRACE("spi mode : Slave\n"); +if(Dspcode->SpiMode == SPI_SNGL ) +TRACE("spi mode : only master\n"); + +//if(Dspcode->ActType == ACT_SEMCO ) +//TRACE("actuator type : SOXXXX\n"); +if(Dspcode->ActType == ACT_SO2821) { + TRACE("actuator type : SO2823\n"); +} else if(Dspcode->ActType == ACT_M12337_A1) { + TRACE("actuator type : M12337 rev.1\n"); +} else { + TRACE("Error Act \n"); +} + +if(Dspcode->GyroType == GYRO_ICM20690 ) +TRACE("gyro type : INVEN ICM20690 \n"); +if(Dspcode->GyroType == GYRO_LSM6DSM ) +TRACE("gyro type : ST LSM6DSM \n") ; + +} + + +//******************************************************************************** +// Function Name : GetInfomationAfterDownload +// Retun Value : NON +// Argment Value : NON +// Explanation : <Pmem Memory> Write Data +// History : First edition +//******************************************************************************** +UINT8 GetInfomationAfterDownload( DSPVER* Info ) +{ + UINT32 Data; + UINT32 UlReadVal; + + RamWrite32A( CMD_IO_ADR_ACCESS , ROMINFO ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + if( (UINT8)UlReadVal != 0x01 ) return( 1 ); + + RamRead32A( (SiVerNum + 0), &Data ); + Info->Vendor = (UINT8)(Data >> 24 ); + Info->User = (UINT8)(Data >> 16 ); + Info->Model = (UINT8)(Data >> 8 ); + Info->Version = (UINT8)(Data >> 0 ); + RamRead32A( (SiVerNum + 4), &Data ); + Info->SpiMode = (UINT8)(Data >> 24 ); + Info->ActType = (UINT8)(Data >> 8 ); + Info->GyroType = (UINT8)(Data >> 0 ); + +// MonitorInfo124( Info ); + return( 0 ); +} + +//******************************************************************************** +// Function Name : GetInfomationBeforeDownlaod +// Retun Value : True(0) / Fail(1) +// Argment Value : NON +// Explanation : <Pmem Memory> Write Data +// History : First edition +//******************************************************************************** +UINT8 GetInfomationBeforeDownload( DSPVER* Info, const UINT8* DataDM, UINT32 LengthDM ) +{ + UINT32 i; + Info->ActType = 0; + Info->GyroType = 0; + + for( i=0; i < LengthDM; i+=6 ) + { + if ( (DataDM[0+i] == 0xA0) && (DataDM[1+i] == 0x00) ) + { + Info->Vendor = DataDM[2+i]; + Info->User = DataDM[3+i]; + Info->Model = DataDM[4+i]; + Info->Version = DataDM[5+i]; + if ( (DataDM[6+i] == 0xA0) && (DataDM[7+i] == 0x04) ) + { + Info->SpiMode = DataDM[8+i]; + Info->ActType = DataDM[10+i]; + Info->GyroType = DataDM[11+i]; + } + MonitorInfo124( Info ); + return (0); + } + } + return(1); +} + + +//******************************************************************************** +// Function Name : SelectDownload +// Retun Value : NON +// Argment Value : NON +// Explanation : +// History : Second edition +//******************************************************************************** + +const DOWNLOAD_TBL DTbl124[] = { +#if ((((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) && (SELECT_MODEL == 0x00)) // SEMCO or Oneplus + {0x0002, 1, LC898124EP3_PM_0_1_0_2_2_0, LC898124EP3_PMSize_0_1_0_2_2_0, (UINT32)((UINT32)LC898124EP3_PMCheckSum_0_1_0_2_2_0 + (UINT32)LC898124EP3_DMA_CheckSum_0_1_0_2_2_0 + (UINT32)LC898124EP3_DMB_CheckSum_0_1_0_2_2_0), LC898124EP3_DM_0_1_0_2_2_0, LC898124EP3_DMA_ByteSize_0_1_0_2_2_0 , LC898124EP3_DMB_ByteSize_0_1_0_2_2_0 }, + {0x0082, 1, LC898124EP3_PM_0_1_0_2_2_1, LC898124EP3_PMSize_0_1_0_2_2_1, (UINT32)((UINT32)LC898124EP3_PMCheckSum_0_1_0_2_2_1 + (UINT32)LC898124EP3_DMA_CheckSum_0_1_0_2_2_1 + (UINT32)LC898124EP3_DMB_CheckSum_0_1_0_2_2_1), LC898124EP3_DM_0_1_0_2_2_1, LC898124EP3_DMA_ByteSize_0_1_0_2_2_1 , LC898124EP3_DMB_ByteSize_0_1_0_2_2_1 }, +#endif +#if ((((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) && (SELECT_MODEL == 0x01)) // SEMCO or Oneplus + {0x0002, 1, LC898124EP3_PM_1_1_0_2_2_0, LC898124EP3_PMSize_1_1_0_2_2_0, (UINT32)((UINT32)LC898124EP3_PMCheckSum_1_1_0_2_2_0 + (UINT32)LC898124EP3_DMA_CheckSum_1_1_0_2_2_0 + (UINT32)LC898124EP3_DMB_CheckSum_1_1_0_2_2_0), LC898124EP3_DM_1_1_0_2_2_0, LC898124EP3_DMA_ByteSize_1_1_0_2_2_0 , LC898124EP3_DMB_ByteSize_1_1_0_2_2_0 }, + {0x0082, 1, LC898124EP3_PM_1_1_0_2_2_1, LC898124EP3_PMSize_1_1_0_2_2_1, (UINT32)((UINT32)LC898124EP3_PMCheckSum_1_1_0_2_2_1 + (UINT32)LC898124EP3_DMA_CheckSum_1_1_0_2_2_1 + (UINT32)LC898124EP3_DMB_CheckSum_1_1_0_2_2_1), LC898124EP3_DM_1_1_0_2_2_1, LC898124EP3_DMA_ByteSize_1_1_0_2_2_1 , LC898124EP3_DMB_ByteSize_1_1_0_2_2_1 }, +#endif +#if ((((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) && (SELECT_MODEL == 0x02)) // SEMCO or Oneplus + {0x0003, 1, LC898124EP3_PM_2_1_0_3_2_0, LC898124EP3_PMSize_2_1_0_3_2_0, (UINT32)((UINT32)LC898124EP3_PMCheckSum_2_1_0_3_2_0 + (UINT32)LC898124EP3_DMA_CheckSum_2_1_0_3_2_0 + (UINT32)LC898124EP3_DMB_CheckSum_2_1_0_3_2_0), LC898124EP3_DM_2_1_0_3_2_0, LC898124EP3_DMA_ByteSize_2_1_0_3_2_0 , LC898124EP3_DMB_ByteSize_2_1_0_3_2_0 }, + {0x0083, 1, LC898124EP3_PM_2_1_0_3_2_1, LC898124EP3_PMSize_2_1_0_3_2_1, (UINT32)((UINT32)LC898124EP3_PMCheckSum_2_1_0_3_2_1 + (UINT32)LC898124EP3_DMA_CheckSum_2_1_0_3_2_1 + (UINT32)LC898124EP3_DMB_CheckSum_2_1_0_3_2_1), LC898124EP3_DM_2_1_0_3_2_1, LC898124EP3_DMA_ByteSize_2_1_0_3_2_1 , LC898124EP3_DMB_ByteSize_2_1_0_3_2_1 }, +#endif +#if (((SELECT_VENDOR&0x02) == 0x02) || ((SELECT_VENDOR&0x80) == 0x80)) // OFILM or Oneplus + {0x0102, 1, LC898124EP3_PM_1_2_1_2_2_0, LC898124EP3_PMSize_1_2_1_2_2_0, (UINT32)((UINT32)LC898124EP3_PMCheckSum_1_2_1_2_2_0 + (UINT32)LC898124EP3_DMA_CheckSum_1_2_1_2_2_0 + (UINT32)LC898124EP3_DMB_CheckSum_1_2_1_2_2_0), LC898124EP3_DM_1_2_1_2_2_0, LC898124EP3_DMA_ByteSize_1_2_1_2_2_0 , LC898124EP3_DMB_ByteSize_1_2_1_2_2_0 }, + {0x0182, 1, LC898124EP3_PM_1_2_1_2_2_1, LC898124EP3_PMSize_1_2_1_2_2_1, (UINT32)((UINT32)LC898124EP3_PMCheckSum_1_2_1_2_2_1 + (UINT32)LC898124EP3_DMA_CheckSum_1_2_1_2_2_1 + (UINT32)LC898124EP3_DMB_CheckSum_1_2_1_2_2_1), LC898124EP3_DM_1_2_1_2_2_1, LC898124EP3_DMA_ByteSize_1_2_1_2_2_1 , LC898124EP3_DMB_ByteSize_1_2_1_2_2_1 }, +#endif + {0xFFFF, 0, (void*)0, 0, 0, (void*)0 ,0 ,0 } +}; + +unsigned char SelectDownload(UINT8 GyroSelect, UINT8 ActSelect, UINT8 MasterSlave, UINT8 FWType) +{ + DSPVER Dspcode; + DOWNLOAD_TBL *ptr; + CAM_INFO(CAM_OIS, "GyroSelect:0x%x, ActSelect:0x%x, MasterSlave:0x%x, FWType:%d\n", GyroSelect, ActSelect, MasterSlave, FWType); + + if ((MasterSlave == 0x00) || (MasterSlave == 0x02)) { //20190522 Komori + ptr = ( DOWNLOAD_TBL *)DTbl124; + } + + /* ã©ã®Codeã‚’Downloadã™ã‚‹ã®ã‹Tableã‹ã‚‰æ¤œç´¢ */ + while (ptr->Cmd != 0xFFFF ){ + if( (ptr->Cmd == ( ((uint16_t)ActSelect<<8) + GyroSelect)) && (ptr->FWType == FWType) ) break; + ptr++ ; + } + if (ptr->Cmd == 0xFFFF) return(0xF0); + + /* Downloadã™ã‚‹å‰Codeã®Informationæƒ…å ±ç¢ºèª */ + if( GetInfomationBeforeDownload( &Dspcode, ptr->DataDM, ( ptr->LengthDMA + ptr->LengthDMB ) ) != 0 ){ + return(0xF1); + } + + /* Downloadã™ã‚‹å‰ã®Codeã¨ã€è¦æ±‚ã—ã¦ã„ã‚‹Actuator/Gyro情報ãŒä¸€è‡´ã—ã¦ã„ã‚‹ã‹ç¢ºèª */ + if( (ActSelect != Dspcode.ActType) || ((GyroSelect&0x7f) != Dspcode.GyroType) ) return(0xF2); + + // 高速化対応Download +TRACE("DataPM( %08x ), LengthPM( %08x ) , Parity( %08x ), DataDM( %08x ) , LengthDMA( %08x ) , LengthDMB( %08x ) \n" + , (int)ptr->DataPM , (int)ptr->LengthPM , (int)ptr->Parity , (int)ptr->DataDM , (int)ptr->LengthDMA , (int)ptr->LengthDMB ); + return( DownloadToEP3( ptr->DataPM, ptr->LengthPM, ptr->Parity, ptr->DataDM, ptr->LengthDMA , ptr->LengthDMB ) ); +} + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/E2PromCmd.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/E2PromCmd.c new file mode 100755 index 0000000000000000000000000000000000000000..3da9f9de00f15ca612361b434afd2578b5080f53 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/E2PromCmd.c @@ -0,0 +1,1581 @@ +//******************************************************************************** +// << LC898124 Evaluation Soft >> +//******************************************************************************** + +//************************** +// Include Header File +//************************** +#include "Ois.h" +#include "OisAPI.h" + +//**************************************************** +// LC898124 calibration parameters +//**************************************************** +#if (((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) // SEMCO or Oneplus +extern const ADJ_HALL SO2821_HallCalParameter; +extern const ADJ_LOPGAN SO2821_LoopGainParameter; +extern AF_PARA SO2821_OpenAfParameter; +#endif + +#if (((SELECT_VENDOR&0x02) == 0x02) || ((SELECT_VENDOR&0x80) == 0x80)) // OFILM or Oneplus +extern const ADJ_HALL M12337_HallCalParameter; +extern const ADJ_LOPGAN M12337_LoopGainParameter; +extern AF_PARA M12337_OpenAfParameter; +#endif + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A( int, int ); +extern void RamRead32A( unsigned short, void * ); +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( unsigned short UsWitTim ); + +//**************************************************** +// EXTERN LIST +//**************************************************** +extern void DMIOWrite32( UINT32 IOadrs, UINT32 IOdata ); + + extern const AF_PARA SO_OpenAfParameter; +//**************************************************** +// LOCAL RAM LIST +//**************************************************** +stAdjPar StAdjPar124 ; // temporary buffer for caribration data +UINT16 UsGzoVal ; // Gyro A/D Offset X + +#ifdef SEL_SHIFT_COR +stPosOff StPosOff124 ; //!< Execute Command Parameter +stAclVal StAclVal124 ; //!< Execute Command Parameter +#endif //SEL_SHIFT_COR + +#ifdef ZERO_SERVO +stZeroServo StZeroServoX; +stZeroServo StZeroServoY; +stZeroServo StZeroServoZ; +#endif //ZERO_SERVO + +//**************************************************** +// Parameter E2Prom defines +//**************************************************** +#define HALLCROSSXX 0x7FFFFFFF +#define HALLCROSSXY 0x00000000 +#define HALLCROSSYY 0x7FFFFFFF +#define HALLCROSSYX 0x00000000 +#define HALLCROSSXSHIFT 0x00 +#define HALLCROSSYSHIFT 0x00 + + +//**************************************************** +// DEFINE LIST +//**************************************************** +#define E2P_ONSEMI_AREA_SIZE (8*2) +#define E2P_USER_AREA_SIZE (8*13) + +#define LSB 0 +#define MSB 8 + + +#define CHECK_SUM_ADR 0x7D + +//******************************************************************************** +// Function Name : UnlockCodeSet124 +// Retun Value : NON +// Argment Value : NON +// Explanation : <Flash Memory> Unlock Code Set +// History : First edition +//******************************************************************************** +unsigned char UnlockCodeSet124( void ) +{ + unsigned long UlReadVal; + + DMIOWrite32( E2P_UNLK_CODE1, 0xAAAAAAAA ); // UNLK_CODE1(E0_7554h) = AAAA_AAAAh + DMIOWrite32( E2P_UNLK_CODE2, 0x55555555 ); // UNLK_CODE2(E0_7AA8h) = 5555_5555h + DMIOWrite32( E2P_RSTB, 0x00000001 ); // RSTB_FLA_WR(E0_74CCh[0])=1 + DMIOWrite32( E2P_CLKON, 0x00000010 ); // FLA_WR_ON(E0_7664h[4])=1 + DMIOWrite32( E2P_UNLK_CODE3, 0x0000ACD5 ); // Additional Unllock Code Set + + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_WPB ) ; + RamRead32A( CMD_IO_DAT_ACCESS , &UlReadVal ) ; + if ( (UlReadVal & 0x00000002) != 2 ) return(1); + + return(0); + +} + +//******************************************************************************** +// Function Name : UnlockCodeClear124 +// Retun Value : NON +// Argment Value : NON +// Explanation : <Flash Memory> Clear Unlock Code +// History : First edition +//******************************************************************************** +unsigned char UnlockCodeClear124(void) +{ + unsigned long UlReadVal; + + RamWrite32A( CMD_IO_ADR_ACCESS, E2P_WPB ); // UNLOCK_CLR(E0_7014h[4])=1 + RamWrite32A( CMD_IO_DAT_ACCESS, 0x00000010 ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + if( (UlReadVal & 0x00000080) != 0 ) return (3); + + return(0); +} + +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +//******************************************************************************** +// Function Name : WriteE2Prom +// Retun Value : error +// Argment Value : NON +// Explanation : Write data to E2Prom +// History : First edition +//******************************************************************************** +unsigned char WriteE2Prom( unsigned char address, unsigned char data ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, e2prom_data[CHECK_SUM_NUM], cnt; + UINT32 ReadVerify, Parity; + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return (ans); // Unlock Code Set + + DMIOWrite32( E2P_ADR, address ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + switch ( (address & 0x0F) ){ + case 0 : DMIOWrite32( E2P_WDAT00, data ); break; + case 1 : DMIOWrite32( E2P_WDAT01, data ); break; + case 2 : DMIOWrite32( E2P_WDAT02, data ); break; + case 3 : DMIOWrite32( E2P_WDAT03, data ); break; + case 4 : DMIOWrite32( E2P_WDAT04, data ); break; + case 5 : DMIOWrite32( E2P_WDAT05, data ); break; + case 6 : DMIOWrite32( E2P_WDAT06, data ); break; + case 7 : DMIOWrite32( E2P_WDAT07, data ); break; + case 8 : DMIOWrite32( E2P_WDAT08, data ); break; + case 9 : DMIOWrite32( E2P_WDAT09, data ); break; + case 10 : DMIOWrite32( E2P_WDAT10, data ); break; + case 11 : DMIOWrite32( E2P_WDAT11, data ); break; + case 12 : DMIOWrite32( E2P_WDAT12, data ); break; + case 13 : DMIOWrite32( E2P_WDAT13, data ); break; + case 14 : DMIOWrite32( E2P_WDAT14, data ); break; + case 15 : DMIOWrite32( E2P_WDAT15, data ); break; + } + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ ans = 2; break; } ; + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, e2prom_data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += e2prom_data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, e2prom_data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += e2prom_data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + return( 0 ); +} +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + + +//******************************************************************************** +// Function Name : ReadE2Prom +// Retun Value : data +// Argment Value : NON +// Explanation : Read data from E2Prom +// History : First edition +//******************************************************************************** +void ReadE2Prom( unsigned char address, unsigned char * val ) +{ + UINT32 UlReadVal; + + DMIOWrite32( E2P_ADR, address ); // Start Address + DMIOWrite32( E2P_ASCNT, 0 ); // Count Number + DMIOWrite32( E2P_CMD, 1 ); // Re-Program + // Read Exe + RamWrite32A( CMD_IO_ADR_ACCESS, E2P_RDAT ); + RamRead32A ( CMD_IO_DAT_ACCESS, &UlReadVal ); // Read Access + + *val = (unsigned char)UlReadVal; +} + +//******************************************************************************** +// Function Name : BurstReadE2Prom +// Retun Value : data +// Argment Value : NON +// Explanation : Read data from E2Prom +// History : First edition +//******************************************************************************** +void BurstReadE2Prom( unsigned char address, unsigned char * val, unsigned char cnt ) +{ + UINT32 UlReadVal; + unsigned char i; + + DMIOWrite32( E2P_ADR, address ); // Start Address + DMIOWrite32( E2P_ASCNT, (cnt -1) ); // Count Number + DMIOWrite32( E2P_CMD, 1 ); // Re-Program + // Read Exe + RamWrite32A( CMD_IO_ADR_ACCESS, E2P_RDAT ); + for(i=0; i<cnt; i++ ){ + RamRead32A ( CMD_IO_DAT_ACCESS, &UlReadVal ); // Read Access + val[i] = (unsigned char)UlReadVal; + } +} + + +//******************************************************************************** +// Function Name : E2PromVerificationONSEMI +// Retun Value : data +// Argment Value : NON +// Explanation : Read data from E2Prom +// History : First edition +//******************************************************************************** +UINT8 E2PromVerificationONSEMI( void ) +{ + UINT32 Verify; + UINT8 cnt; + UINT8 temp[16]; + + // Create Checksum + Verify = 0; + BurstReadE2Prom( EEPROM_ONSEMI_LDO , temp, E2P_ONSEMI_AREA_SIZE ); + for( cnt= 0 ; cnt <(E2P_ONSEMI_AREA_SIZE -1); cnt++ ){ + Verify += temp[cnt]; + } + if ( (UINT8)Verify != temp[ (E2P_ONSEMI_AREA_SIZE -1) ]) return( FAILURE ); + + return( SUCCESS ); +} + +//******************************************************************************** +// Function Name : E2PromVerificationONSEMI +// Retun Value : data +// Argment Value : NON +// Explanation : Read data from E2Prom +// History : First edition +//******************************************************************************** +UINT8 E2PromVerification( void ) +{ + UINT32 Verify; + UINT8 cnt; + UINT8 temp[ E2P_USER_AREA_SIZE ]; + + // Create Checksum + Verify = 0; + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL , temp, E2P_USER_AREA_SIZE ); + for( cnt= 0; cnt < (E2P_USER_AREA_SIZE -1); cnt++ ){ + Verify += temp[cnt]; + } + if ( (UINT8)Verify != temp[ (E2P_USER_AREA_SIZE-1) ]) return( FAILURE ); + return( SUCCESS ); +} + +//******************************************************************************** +// Function Name : WrI2cSlaveAddr +// Retun Value : error +// Argment Value : NON +// Explanation : Write data to E2Prom +// History : First edition +//******************************************************************************** +extern unsigned char I2cSlvAddrWr; + +UINT8 WrI2cSlaveAddr( unsigned char Addr ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans; + + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + if( Addr == 0x74 ) { + DMIOWrite32( E2P_WDAT00, 0x7F ); // IDSEL(Slave Addr = 0x74) + } else { + DMIOWrite32( E2P_WDAT00, 0xFF ); // IDSEL(Slave Addr = 0x7C) + } + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + return( 0 ); +} + + +//******************************************************************************** +// Function Name : WrHallCalData124 +// Retun Value : error +// Argment Value : NON +// Explanation : Write data to E2Prom +// History : First edition +//******************************************************************************** +UINT8 WrHallCalData124( void ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt, UcReadVal[2]; + UINT32 ReadVerify, Parity; + + // Read the Status & Update + BurstReadE2Prom( EEPROM_Calibration_Status_LSB, UcReadVal, 2 ); + StAdjPar124.StHalAdj.UlAdjPhs |= ( (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) & (~( HALL_CALB_FLG | HALL_CALB_BIT )) ); + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + + DMIOWrite32( E2P_ADR, EEPROM_ONSEMI_IDSEL ); + DMIOWrite32( E2P_ASCNT, 0 ); + DMIOWrite32( E2P_CMD, 1 ); + RamWrite32A( CMD_IO_ADR_ACCESS, E2P_RDAT ); + RamRead32A ( CMD_IO_DAT_ACCESS, &UlReadVal ); + UlReadVal &= 0xF0; // Get Upper 4bit + UlReadVal |= 0x07; // Set lower 4bit + + +//------------------------------------------------------------------------------------------------ +// Page 1 (0x10-0x1F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT00, UlReadVal ); // IDSEL + + DMIOWrite32( E2P_WDAT08, (UINT8)((StAdjPar124.StHalAdj.UlAdjPhs)>>LSB ) ); // Calibration Status + DMIOWrite32( E2P_WDAT09, (UINT8)((StAdjPar124.StHalAdj.UlAdjPhs)>>MSB ) ); + DMIOWrite32( E2P_WDAT10, (UINT8)((StAdjPar124.StHalAdj.UsHlxMxa)>>LSB ) ); // OIS Hall X Max After + DMIOWrite32( E2P_WDAT11, (UINT8)((StAdjPar124.StHalAdj.UsHlxMxa)>>MSB ) ); + DMIOWrite32( E2P_WDAT12, (UINT8)((StAdjPar124.StHalAdj.UsHlxMna)>>LSB ) ); // OIS Hall X Min After + DMIOWrite32( E2P_WDAT13, (UINT8)((StAdjPar124.StHalAdj.UsHlxMna)>>MSB ) ); + DMIOWrite32( E2P_WDAT14, (UINT8)((StAdjPar124.StHalAdj.UsHlyMxa)>>LSB ) ); // OIS Hall Y Max After + DMIOWrite32( E2P_WDAT15, (UINT8)((StAdjPar124.StHalAdj.UsHlyMxa)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); +//------------------------------------------------------------------------------------------------ +// Page 2 (0x20-0x2F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x20 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT00, (UINT8)((StAdjPar124.StHalAdj.UsHlyMna)>>LSB ) ); // OIS Hall Y Min After + DMIOWrite32( E2P_WDAT01, (UINT8)((StAdjPar124.StHalAdj.UsHlyMna)>>MSB ) ); + DMIOWrite32( E2P_WDAT02, (UINT8)((StAdjPar124.StHalAdj.UsHlxGan)>>8 ) ); // OIS Hall Bias X + DMIOWrite32( E2P_WDAT03, (UINT8)((StAdjPar124.StHalAdj.UsHlxOff)>>8 ) ); // OIS Hall Offset X + DMIOWrite32( E2P_WDAT04, (UINT8)((StAdjPar124.StHalAdj.UsHlyGan)>>8 ) ); // OIS Hall Bias Y + DMIOWrite32( E2P_WDAT05, (UINT8)((StAdjPar124.StHalAdj.UsHlyOff)>>8 ) ); // OIS Hall Offset Y + DMIOWrite32( E2P_WDAT06, (UINT8)((StAdjPar124.StLopGan.UlLxgVal)>>16 ) ); // OIS Hall Loop Gain X + DMIOWrite32( E2P_WDAT07, (UINT8)((StAdjPar124.StLopGan.UlLxgVal)>>24 ) ); // OIS Hall Loop Gain X + DMIOWrite32( E2P_WDAT08, (UINT8)((StAdjPar124.StLopGan.UlLygVal)>>16 ) ); // OIS Hall Loop Gain Y + DMIOWrite32( E2P_WDAT09, (UINT8)((StAdjPar124.StLopGan.UlLygVal)>>24 ) ); + DMIOWrite32( E2P_WDAT10, (UINT8)((StAdjPar124.StHalAdj.UsAdxOff)>>LSB ) ); // OIS Mecha center X + DMIOWrite32( E2P_WDAT11, (UINT8)((StAdjPar124.StHalAdj.UsAdxOff)>>MSB ) ); + DMIOWrite32( E2P_WDAT12, (UINT8)((StAdjPar124.StHalAdj.UsAdyOff)>>LSB ) ); // OIS Mecha center Y + DMIOWrite32( E2P_WDAT13, (UINT8)((StAdjPar124.StHalAdj.UsAdyOff)>>MSB ) ); + DMIOWrite32( E2P_WDAT14, 0xFF ); //GyroFilterTableX_gxzoom + DMIOWrite32( E2P_WDAT15, 0xFF ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 3 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); +//------------------------------------------------------------------------------------------------ +// Page 3 (0x30-0x32) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x30 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT00, 0xFF ); // GyroFilterTableX_gxzoom + DMIOWrite32( E2P_WDAT01, 0x3F ); + DMIOWrite32( E2P_WDAT02, 0xFF ); // GyroFilterTableY_gyzoom + DMIOWrite32( E2P_WDAT03, 0xFF ); + DMIOWrite32( E2P_WDAT04, 0xFF ); + DMIOWrite32( E2P_WDAT05, 0x3F ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); +//------------------------------------------------------------------------------------------------ +// Page 5 (0x50-0x5F) +//------------------------------------------------------------------------------------------------ +#if 0 + DMIOWrite32( E2P_ADR, 0x50 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT06, 0 ); // OIS gyro offset X + DMIOWrite32( E2P_WDAT07, (UINT8)(HALLCROSSXX>>16) ); // CrossXX lower Byte + DMIOWrite32( E2P_WDAT08, (UINT8)(HALLCROSSXX>>24) ); // CrossXX Higher Byte + DMIOWrite32( E2P_WDAT09, (UINT8)(HALLCROSSXY>>16) ); // CrossXY lower Byte + DMIOWrite32( E2P_WDAT10, (UINT8)(HALLCROSSXY>>24) ); // CrossXY Higher Byte + DMIOWrite32( E2P_WDAT11, (UINT8)(HALLCROSSYY>>16) ); // CrossYY lower Byte + DMIOWrite32( E2P_WDAT12, (UINT8)(HALLCROSSYY>>24) ); // CrossYY Higher Byte + DMIOWrite32( E2P_WDAT13, (UINT8)(HALLCROSSYX>>16) ); // CrossYX lower Byte + DMIOWrite32( E2P_WDAT14, (UINT8)(HALLCROSSYX>>24) ); // CrossYX Higher Byte + DMIOWrite32( E2P_WDAT15, HALLCROSSXSHIFT ); // CrsXsft + DMIOWrite32( E2P_WDAT10, HALLCROSSYSHIFT ); // CrsYsft + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); +#endif +//------------------------------------------------------------------------------------------------ +// Page 6 (0x50-0x5F) +//------------------------------------------------------------------------------------------------ +#if 0 + DMIOWrite32( E2P_ADR, 0x60 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT00, CH2SEL ); // DrvY direction + DMIOWrite32( E2P_WDAT01, CH3SEL ); // DrvZ direction + DMIOWrite32( E2P_WDAT02, (UINT8)(AF_FST_FREQ) ); // AfFreq + DMIOWrite32( E2P_WDAT03, (UINT8)(AF_FST_FREQ>>8) ); // AfFreq + DMIOWrite32( E2P_WDAT04, (UINT8)(AF_FST_UCOEF>>16) ); // AfUcode + DMIOWrite32( E2P_WDAT05, (UINT8)(AF_FST_UCOEF>>24) ); // AfUcode + DMIOWrite32( E2P_WDAT06, (UINT8)(AF_FST_DCOEF>>16) ); // AfDcode + DMIOWrite32( E2P_WDAT07, (UINT8)(AF_FST_DCOEF>>24) ); // AfDcode + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); +#endif +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + return( 0 ); + +} +//******************************************************************************** +// Function Name : WrGyroGainData124 +// Retun Value : 0:OK, 1:NG +// Argment Value : NON +// Explanation : Flash Write Hall Calibration Data Function +// History : First edition +//******************************************************************************** +UINT8 WrGyroGainData124( void ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt, UcReadVal[2]; + UINT32 ReadVerify, Parity; + UINT32 UlZoomX, UlZoomY; + + // Read the Gyro Gain value + RamRead32A( GyroFilterTableX_gxzoom , &UlZoomX ) ; + RamRead32A( GyroFilterTableY_gyzoom , &UlZoomY ) ; + // Read the Status & Update + BurstReadE2Prom( EEPROM_Calibration_Status_LSB, UcReadVal, 2 ); + UlReadVal = (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) & (~GYRO_GAIN_FLG) ; + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + +//------------------------------------------------------------------------------------------------ +// Page 1 (0x10-0x1F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + +// DMIOWrite32( E2P_WDAT00, ); // IDSEL + DMIOWrite32( E2P_WDAT08, (UINT8)((UlReadVal)>>LSB ) ); // Calibration Status + DMIOWrite32( E2P_WDAT09, (UINT8)((UlReadVal)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); +//------------------------------------------------------------------------------------------------ +// Page 2 (0x20-0x2F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x20 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT14, (UINT8)(UlZoomX>>0) );//GyroFilterTableX_gxzoom + DMIOWrite32( E2P_WDAT15, (UINT8)(UlZoomX>>8) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 3 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// Page 3 (0x30-0x3F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x30 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT00, (UINT8)(UlZoomX>>16) ); + DMIOWrite32( E2P_WDAT01, (UINT8)(UlZoomX>>24) ); + DMIOWrite32( E2P_WDAT02, (UINT8)(UlZoomY>>0) ); // GyroFilterTableY_gyzoom + DMIOWrite32( E2P_WDAT03, (UINT8)(UlZoomY>>8) ); + DMIOWrite32( E2P_WDAT04, (UINT8)(UlZoomY>>16) ); + DMIOWrite32( E2P_WDAT05, (UINT8)(UlZoomY>>24) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 3 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + return(ans); +} + +#if 0 +//******************************************************************************** +// Function Name : WrGyroGainData_NV +// Retun Value : 0:OK, 1:NG +// Argment Value : UlReadValX: gyro gain X, UlReadValY: gyro gain Y +// Explanation : Flash Write Hall Calibration Data Function +// History : First edition +//******************************************************************************** +UINT8 WrGyroGainData_NV( UINT32 UlReadValX , UINT32 UlReadValY ) +{ + +} +#endif + + +#ifdef ZERO_SERVO +//******************************************************************************** +// Function Name : WrZeroServoData +// Retun Value : SUCCESS or FAILURE +// Argment Value : NON +// Explanation : Flash Write Zero Servo data Function +// History : First edition 2016.9.5 +//******************************************************************************** +UINT8 WrZeroServoData( void ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt, UcReadVal[2]; + UINT32 ReadVerify, Parity; + + // Read the Status & Update + BurstReadE2Prom( EEPROM_Calibration_Status_LSB, UcReadVal, 2 ); + UlReadVal = (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) & (~ZSRV_CAL_FLG) ; + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + +//------------------------------------------------------------------------------------------------ +// Page 1 (0x10-0x1F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + +// DMIOWrite32( E2P_WDAT00, 0xF7 ); // IDSEL + DMIOWrite32( E2P_WDAT08, (UINT8)((UlReadVal)>>LSB ) ); // Calibration Status + DMIOWrite32( E2P_WDAT09, (UINT8)((UlReadVal)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// Page 3 (0x30-0x3F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x30 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + +// DMIOWrite32( E2P_WDAT00, (UINT8)( ); +// DMIOWrite32( E2P_WDAT01, (UINT8)( ); +// DMIOWrite32( E2P_WDAT02, (UINT8)( ); +// DMIOWrite32( E2P_WDAT03, (UINT8)( ); +// DMIOWrite32( E2P_WDAT04, (UINT8)( ); +// DMIOWrite32( E2P_WDAT05, (UINT8)( ); + DMIOWrite32( E2P_WDAT06, (UINT8)( ((StZeroServoX.SlOffset)>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT07, (UINT8)( ((StZeroServoX.SlOffset)>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT08, (UINT8)( ((StZeroServoX.SlShift) >> 0)>>LSB ) ); + DMIOWrite32( E2P_WDAT09, (UINT8)( ((StZeroServoX.SlShift) >> 0)>>MSB ) ); + DMIOWrite32( E2P_WDAT10, (UINT8)( ((StZeroServoX.SlGcora) >>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT11, (UINT8)( ((StZeroServoX.SlGcora) >>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT12, (UINT8)( ((StZeroServoX.SlGaina) >>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT13, (UINT8)( ((StZeroServoX.SlGaina) >>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT14, (UINT8)( ((StZeroServoY.SlOffset)>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT15, (UINT8)( ((StZeroServoY.SlOffset)>>16)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// Page 4 (0x40-0x4F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x40 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT00, (UINT8)( ((StZeroServoY.SlShift) >> 0)>>LSB ) ); + DMIOWrite32( E2P_WDAT01, (UINT8)( ((StZeroServoY.SlShift) >> 0)>>MSB ) ); + DMIOWrite32( E2P_WDAT02, (UINT8)( ((StZeroServoY.SlGcora) >>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT03, (UINT8)( ((StZeroServoY.SlGcora) >>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT04, (UINT8)( ((StZeroServoY.SlGaina) >>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT05, (UINT8)( ((StZeroServoY.SlGaina) >>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT06, (UINT8)( ((StZeroServoZ.SlOffset)>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT07, (UINT8)( ((StZeroServoZ.SlOffset)>>16)>>MSB ) ); +// DMIOWrite32( E2P_WDAT08, (UINT8)( ); +// DMIOWrite32( E2P_WDAT09, (UINT8)( ); +// DMIOWrite32( E2P_WDAT10, (UINT8)( ); +// DMIOWrite32( E2P_WDAT11, (UINT8)( ); +// DMIOWrite32( E2P_WDAT12, (UINT8)( ); +// DMIOWrite32( E2P_WDAT13, (UINT8)( ); +// DMIOWrite32( E2P_WDAT14, (UINT8)( ); +// DMIOWrite32( E2P_WDAT15, (UINT8)( ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear + +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + return( 0 ); +} + +#endif //ZERO_SERVO + +//******************************************************************************** +// Function Name : WrAfParameter +// Retun Value : 0:OK, 1:NG +// Argment Value : SelectAct +// Explanation : Flash Write Af paramter Function +// History : First edition +//******************************************************************************** +#if 0 +UINT8 WrAfParameter( UINT8 SelectAct ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt; + UINT32 ReadVerify, Parity; + AF_PARA* AfParaPtr; + // Select parameter + + if( SelectAct == ACT_SO2821 ){ + AfParaPtr = (AF_PARA*)&SO2821_OpenAfParameter; + }else{ + return( 7 ); /* Error */ + } + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + +//------------------------------------------------------------------------------------------------ +// Page 1 (0x10-0x1F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + +// DMIOWrite32( E2P_WDAT00, ); // IDSEL + DMIOWrite32( E2P_WDAT01, (UINT8)( AfParaPtr->DrvDir )); // Af driver direction + DMIOWrite32( E2P_WDAT02, (UINT8)((AfParaPtr->Rrmd1ToMacro)>>LSB ) ); // Af rrmd1 para to macro + DMIOWrite32( E2P_WDAT03, (UINT8)((AfParaPtr->Rrmd1ToMacro)>>MSB ) ); + DMIOWrite32( E2P_WDAT04, (UINT8)((AfParaPtr->Rrmd1ToInfini)>>LSB ) ); // Af rrmd1 para to inf + DMIOWrite32( E2P_WDAT05, (UINT8)((AfParaPtr->Rrmd1ToInfini)>>MSB ) ); + DMIOWrite32( E2P_WDAT06, (UINT8)((AfParaPtr->Freq)>>LSB ) ); // Af freq + DMIOWrite32( E2P_WDAT07, (UINT8)((AfParaPtr->Freq)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + DMIOWrite32( DRVCH3SEL, (UINT32)AfParaPtr->DrvDir ); // Af driver direction + RamWrite32A( OLAF_COEF_FSTVAL0, ((UINT32)AfParaPtr->Rrmd1ToMacro)<<16 ); // Af rrmd1 para to macro + RamWrite32A( OLAF_COEF_FSTVAL1, ((UINT32)AfParaPtr->Rrmd1ToInfini)<<16 ); // Af rrmd1 para to inf + RamWrite32A( OLAF_COEF_FSTVAL2, (UINT32)AfParaPtr->Freq ); // Af freq + RamWrite32A( OLAF_DMB_FT, (UINT32)AfParaPtr->Freq ); // Af freq + + return(ans); +} +#endif + +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +//******************************************************************************** +// Function Name : WrHallLnData +// Retun Value : SUCCESS or FAILURE +// Argment Value : NON +// Explanation : EEPROM Write Hall Linearity data Function +// History : First edition 2017.6.27 +//******************************************************************************** +UINT8 WrHallLnData( UINT8 UcMode, mlLinearityValue *linval ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt, UcReadVal[2]; + UINT32 ReadVerify, Parity; + double *pPosX, *pPosY; + UINT32 PosDifX, PosDifY; + DSPVER Info; + + // Read the Status & Update + BurstReadE2Prom( EEPROM_Calibration_Status_LSB, UcReadVal, 2 ); + if( UcMode ){ + UlReadVal = (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) & (~HLLN_CALB_FLG) ; + }else{ + UlReadVal = (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) | (HLLN_CALB_FLG) ; + } + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + +//------------------------------------------------------------------------------------------------ +// Page 1 (0x10-0x1F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + +// DMIOWrite32( E2P_WDAT00, 0xF7 ); // IDSEL + DMIOWrite32( E2P_WDAT08, (UINT8)((UlReadVal)>>LSB ) ); // Calibration Status + DMIOWrite32( E2P_WDAT09, (UINT8)((UlReadVal)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + if( GetInfomationAfterDownload( &Info ) != 0) return( EXE_ERROR ); +//------------------------------------------------------------------------------------------------ +// Page 4 (0x40-0x4F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x40 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + if( UcMode ){ + + + pPosX = linval->positionX; + pPosY = linval->positionY; + + + // DMIOWrite32( E2P_WDAT00, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT01, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT02, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT03, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT04, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT05, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT06, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT07, (UINT8)( ) ); + DMIOWrite32( E2P_WDAT08, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS1 X + DMIOWrite32( E2P_WDAT09, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); pPosX++; + DMIOWrite32( E2P_WDAT10, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS1 Y + DMIOWrite32( E2P_WDAT11, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); pPosY++; + DMIOWrite32( E2P_WDAT12, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS2 X + DMIOWrite32( E2P_WDAT13, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); pPosX++; + DMIOWrite32( E2P_WDAT14, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS2 Y + DMIOWrite32( E2P_WDAT15, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); pPosY++; + }else{ + DMIOWrite32( E2P_WDAT08, (UINT8)0xFF ); // POS1 X + DMIOWrite32( E2P_WDAT09, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT10, (UINT8)0xFF ); // POS1 Y + DMIOWrite32( E2P_WDAT11, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT12, (UINT8)0xFF ); // POS2 X + DMIOWrite32( E2P_WDAT13, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT14, (UINT8)0xFF ); // POS2 Y + DMIOWrite32( E2P_WDAT15, (UINT8)0xFF ); + } + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// Page 5 (0x50-0x5F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x50 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + if( UcMode ){ + DMIOWrite32( E2P_WDAT00, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS3 X + DMIOWrite32( E2P_WDAT01, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); pPosX++; + DMIOWrite32( E2P_WDAT02, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS3 Y + DMIOWrite32( E2P_WDAT03, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); pPosY++; + DMIOWrite32( E2P_WDAT04, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS4 X + DMIOWrite32( E2P_WDAT05, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); pPosX++; + DMIOWrite32( E2P_WDAT06, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS4 Y + DMIOWrite32( E2P_WDAT07, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); pPosY++; + DMIOWrite32( E2P_WDAT08, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS5 X + DMIOWrite32( E2P_WDAT09, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); pPosX++; + DMIOWrite32( E2P_WDAT10, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS5 Y + DMIOWrite32( E2P_WDAT11, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); pPosY++; + DMIOWrite32( E2P_WDAT12, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS6 X + DMIOWrite32( E2P_WDAT13, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); pPosX++; + DMIOWrite32( E2P_WDAT14, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS6 Y + DMIOWrite32( E2P_WDAT15, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); pPosY++; + }else{ + DMIOWrite32( E2P_WDAT00, (UINT8)0xFF ); // POS3 X + DMIOWrite32( E2P_WDAT01, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT02, (UINT8)0xFF ); // POS3 Y + DMIOWrite32( E2P_WDAT03, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT04, (UINT8)0xFF ); // POS4 X + DMIOWrite32( E2P_WDAT05, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT06, (UINT8)0xFF ); // POS4 Y + DMIOWrite32( E2P_WDAT07, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT08, (UINT8)0xFF ); // POS5 X + DMIOWrite32( E2P_WDAT09, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT10, (UINT8)0xFF ); // POS5 Y + DMIOWrite32( E2P_WDAT11, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT12, (UINT8)0xFF ); // POS6 X + DMIOWrite32( E2P_WDAT13, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT14, (UINT8)0xFF ); // POS6 Y + DMIOWrite32( E2P_WDAT15, (UINT8)0xFF ); + } + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// Page 6 (0x60-0x6F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x60 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + if( UcMode ){ + DMIOWrite32( E2P_WDAT00, (UINT8)( (UINT32)(*pPosX * 10)>>LSB ) ); // POS7 X + DMIOWrite32( E2P_WDAT01, (UINT8)( (UINT32)(*pPosX * 10)>>MSB ) ); + DMIOWrite32( E2P_WDAT02, (UINT8)( (UINT32)(*pPosY * 10)>>LSB ) ); // POS7 Y + DMIOWrite32( E2P_WDAT03, (UINT8)( (UINT32)(*pPosY * 10)>>MSB ) ); + + + PosDifX = (linval->dacX[1] - linval->dacX[0]); + PosDifY = (linval->dacY[1] - linval->dacY[0]); + + + DMIOWrite32( E2P_WDAT04, (UINT8)( (UINT16)(PosDifX>>16)>>LSB ) ); // STEP X + DMIOWrite32( E2P_WDAT05, (UINT8)( (UINT16)(PosDifX>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT06, (UINT8)( (UINT16)(PosDifY>>16)>>LSB ) ); // STEP Y + DMIOWrite32( E2P_WDAT07, (UINT8)( (UINT16)(PosDifY>>16)>>MSB ) ); + }else{ + DMIOWrite32( E2P_WDAT00, (UINT8)0xFF ); // POS7 X + DMIOWrite32( E2P_WDAT01, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT02, (UINT8)0xFF ); // POS7 Y + DMIOWrite32( E2P_WDAT03, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT04, (UINT8)0xFF ); // STEP X + DMIOWrite32( E2P_WDAT05, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT06, (UINT8)0xFF ); // STEP Y + DMIOWrite32( E2P_WDAT07, (UINT8)0xFF ); + } + // DMIOWrite32( E2P_WDAT08, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT09, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT10, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT11, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT12, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT13, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT14, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT15, (UINT8)( ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear + +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + return( 0 ); +} + +//******************************************************************************** +// Function Name : WrMixCalData124 +// Retun Value : SUCCESS or FAILURE +// Argment Value : NON +// Explanation : EEPROM Writecross talk data Function +// History : First edition 2017.6.27 +//******************************************************************************** +UINT8 WrMixCalData124( UINT8 UcMode, mlMixingValue *mixval ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt, UcReadVal[2]; + UINT32 ReadVerify, Parity; + DSPVER Info; + + // Read the Status & Update + BurstReadE2Prom( EEPROM_Calibration_Status_LSB, UcReadVal, 2 ); + if( UcMode ){ + UlReadVal = (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) & (~MIXI_CALB_FLG) ; + }else{ + UlReadVal = (((UINT32)UcReadVal[1]<<8) +UcReadVal[0]) | (MIXI_CALB_FLG) ; + } + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) return ( 1 ); // Unlock Code Set + +//------------------------------------------------------------------------------------------------ +// Page 1 (0x10-0x1F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x10 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + +// DMIOWrite32( E2P_WDAT00, 0xF7 ); // IDSEL + DMIOWrite32( E2P_WDAT08, (UINT8)((UlReadVal)>>LSB ) ); // Calibration Status + DMIOWrite32( E2P_WDAT09, (UINT8)((UlReadVal)>>MSB ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 2 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + if( GetInfomationAfterDownload( &Info ) != 0) return( EXE_ERROR ); + +//------------------------------------------------------------------------------------------------ +// Page 6 (0x60-0x6F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x60 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + // DMIOWrite32( E2P_WDAT00, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT01, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT02, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT03, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT04, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT05, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT06, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT07, (UINT8)( ) ); + + if( GetInfomationAfterDownload( &Info ) != 0) return( EXE_ERROR ); + +#if 0 + if( Info.ActType == ACT_SO2821 ){ + + mixval->hx45yL = (-1)*mixval->hx45yL; + mixval->hy45xL = (-1)*mixval->hy45xL; + + if(mixval->hy45yL<0){ /* for MeasurementLibrary 1.X */ + mixval->hy45yL = (-1)*mixval->hy45yL; + mixval->hx45yL = (-1)*mixval->hx45yL; + } + } +#endif +//*****************************************************// +// if( XYSTPDIR == 0x10 || XYSTPDIR == 0x01 ){ +// mixval->hx45yL = (-1)*mixval->hx45yL; +// mixval->hy45xL = (-1)*mixval->hy45xL; +// } +//****************************************************// + + if( UcMode ){ + if( Info.ActType == ACT_SO2821 ){ + /* XYSWAP == 0 */ + DMIOWrite32( E2P_WDAT08, (UINT8)(( mixval->hx45xL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT09, (UINT8)(( mixval->hx45xL>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT10, (UINT8)(( mixval->hx45yL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT11, (UINT8)(( mixval->hx45yL>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT12, (UINT8)(( mixval->hy45yL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT13, (UINT8)(( mixval->hy45yL>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT14, (UINT8)(( mixval->hy45xL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT15, (UINT8)(( mixval->hy45xL>>16)>>MSB ) ); + }else{ + /* XYSWAP == 0 */ + DMIOWrite32( E2P_WDAT08, (UINT8)(( mixval->hx45xL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT09, (UINT8)(( mixval->hx45xL>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT10, (UINT8)(( mixval->hx45yL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT11, (UINT8)(( mixval->hx45yL>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT12, (UINT8)(( mixval->hy45yL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT13, (UINT8)(( mixval->hy45yL>>16)>>MSB ) ); + DMIOWrite32( E2P_WDAT14, (UINT8)(( mixval->hy45xL>>16)>>LSB ) ); + DMIOWrite32( E2P_WDAT15, (UINT8)(( mixval->hy45xL>>16)>>MSB ) ); + } + }else{ + DMIOWrite32( E2P_WDAT08, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT09, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT10, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT11, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT12, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT13, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT14, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT15, (UINT8)0xFF ); + } + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + if( UcMode ){ + if( Info.ActType == ACT_SO2821 ){ + /* XYSWAP == 0 */ + DMIOWrite32( E2P_WDAT00, (UINT8)( mixval->hxsx ) ); + DMIOWrite32( E2P_WDAT01, (UINT8)( mixval->hysx ) ); + }else{ + /* XYSWAP == 0 */ + DMIOWrite32( E2P_WDAT00, (UINT8)( mixval->hxsx ) ); + DMIOWrite32( E2P_WDAT01, (UINT8)( mixval->hysx ) ); + } + }else{ + DMIOWrite32( E2P_WDAT00, (UINT8)0xFF ); + DMIOWrite32( E2P_WDAT01, (UINT8)0xFF ); + } + // DMIOWrite32( E2P_WDAT02, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT03, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT04, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT05, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT06, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT07, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT08, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT09, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT10, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT11, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT12, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT13, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT14, (UINT8)( ) ); + // DMIOWrite32( E2P_WDAT15, (UINT8)( ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 4 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +// } + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear + +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + if( (UINT8)ReadVerify != (UINT8)Parity) return( 6 ); + + return( 0 ); +} +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + +//******************************************************************************** +// Function Name : WrOptOffsetData +// Retun Value : error +// Argment Value : NON +// Explanation : Write opt offset data to E2Prom +// History : First edition +//******************************************************************************** +UINT8 WrOptOffsetData( void ) +{ + UINT32 UlReadVal, UlCnt; + UINT8 ans, data[CHECK_SUM_NUM], cnt; + UINT32 ReadVerify, Parity; + + UINT32 UlHxoff; + UINT32 UlHyoff; + + RamRead32A( Optical_Offset_X , &UlHxoff ) ; + RamRead32A( Optical_Offset_Y , &UlHyoff ) ; +// UlHxoff = 0xFFFFFFFF; +// UlHyoff = 0xFFFFFFFF; + +TRACE("UlHxoff = %08X\n", UlHxoff); +TRACE("UlHyoff = %08X\n", UlHyoff); + + // Flash write€”õ + ans = UnlockCodeSet124(); + if ( ans != 0 ) { + TRACE("Error 1 \n"); + return ( 1 ); // Unlock Code Set + } + +//------------------------------------------------------------------------------------------------ +// Page 2 (0x72-0x75) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT02, (UINT8)((UlHxoff)>>(16+LSB) ) ); // optical center X + DMIOWrite32( E2P_WDAT03, (UINT8)((UlHxoff)>>(16+MSB) ) ); + DMIOWrite32( E2P_WDAT04, (UINT8)((UlHyoff)>>(16+LSB) ) ); // optical center Y + DMIOWrite32( E2P_WDAT05, (UINT8)((UlHyoff)>>(16+MSB) ) ); + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear +TRACE("Error 2 \n"); + return( 3 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + +//------------------------------------------------------------------------------------------------ +// CheckSum Creating +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + Parity = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + Parity += data[cnt]; + } + +//------------------------------------------------------------------------------------------------ +// Page 7 (0x70-0x7F) +//------------------------------------------------------------------------------------------------ + DMIOWrite32( E2P_ADR, 0x70 ); // Start Address + DMIOWrite32( E2P_DFG, 0 ); // FLG CLR + + DMIOWrite32( E2P_WDAT13, (UINT8)(Parity) ); // CheckSum:0x7D + + DMIOWrite32( E2P_CMD, 2 ); // Re-Program + WitTim( 20 ) ; + UlCnt=0; + do{ + if( UlCnt++ > 10 ){ + UnlockCodeClear124(); // Unlock Code Clear +TRACE("Error 3 \n"); + return( 5 ); + } + RamWrite32A( CMD_IO_ADR_ACCESS , E2P_INT ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + }while ( (UlReadVal & 0x00000080) != 0 ); + + UnlockCodeClear124(); // Unlock Code Clear +//------------------------------------------------------------------------------------------------ +// Checksum Verification +//------------------------------------------------------------------------------------------------ + BurstReadE2Prom( EEPROM_ONSEMI_IDSEL, data, CHECK_SUM_NUM ); + ReadVerify = 0; + for( cnt=0; cnt < CHECK_SUM_NUM; cnt++ ){ + ReadVerify += data[cnt]; + } + ReadE2Prom( CHECK_SUM_ADR, &cnt ); + Parity = cnt; + if( (UINT8)ReadVerify != (UINT8)Parity){ +TRACE("Error 4 \n"); + return( 6 ); + } + +TRACE("Pass All \n"); + return( 0 ); + +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/HighLevelCmd.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/HighLevelCmd.c new file mode 100755 index 0000000000000000000000000000000000000000..b027cc2611ddf754c3ced49edfcb293dd868cae1 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/HighLevelCmd.c @@ -0,0 +1,2006 @@ +//******************************************************************************** +// << LC898124 Evaluation Soft >> +// Program Name : OisCmd.c +// Design : Y.Shigoeka +// History : First edition +//******************************************************************************** +//************************** +// Include Header File +//************************** +#include "Ois.h" +//#include <stdlib.h> +//#include <math.h> +#include <linux/kernel.h> + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A(int addr, int data); +extern void RamRead32A( unsigned short addr, void * data ); +extern void WitTim( unsigned short UsWitTim ); +extern UINT8 GetInfomationAfterDownload( DSPVER* Info ); +extern void DMIOWrite32( UINT32 IOadrs, UINT32 IOdata ); +extern void BurstReadE2Prom( UINT8 startaddress, UINT8* val, UINT8 cnt ); +extern void ReadE2Prom( unsigned char address, unsigned char * val ); +//************************** +// STRICT +//************************** +typedef struct { + INT32 SiSampleNum ; // Measure Sample Number + INT32 SiSampleMax ; // Measure Sample Number Max + + struct { + INT32 SiMax1 ; // Max Measure Result + INT32 SiMin1 ; // Min Measure Result + UINT32 UiAmp1 ; // Amplitude Measure Result + INT64 LLiIntegral1 ; // Integration Measure Result + INT64 LLiAbsInteg1 ; // Absolute Integration Measure Result + INT32 PiMeasureRam1 ; // Measure Delay RAM Address + } MeasureFilterA ; + + struct { + INT32 SiMax2 ; // Max Measure Result + INT32 SiMin2 ; // Min Measure Result + UINT32 UiAmp2 ; // Amplitude Measure Result + INT64 LLiIntegral2 ; // Integration Measure Result + INT64 LLiAbsInteg2 ; // Absolute Integration Measure Result + INT32 PiMeasureRam2 ; // Measure Delay RAM Address + } MeasureFilterB ; +} MeasureFunction_Type ; + +//************************** +// Local Function LIST +//************************** +void MesFil124( UINT8 ) ; // Measure Filter Setting +void ClrMesFil124( void ); +void MeasureStart124( INT32 , UINT32 , UINT32 ) ; // Measure Start Function +void MeasureWait124( void ) ; // Measure Wait +void MemoryClear124( UINT16 , UINT16 ) ; // Memory Cloear +void SetWaitTime124( UINT16 ) ; // Set Wait Timer +void SetTransDataAdr124( UINT16 UsLowAddress , UINT32 UlLowAdrBeforeTrans ); + +void OisEnaNCL124( void ); +void OisEnaDrCl124( void ); +void OisEnaDrNcl124( void ); +void OisDis124( void ); +void SetRec124( void ); +void SetStill124( void ); + +UINT8 MesRam124( INT32 , INT32 , INT32 , stMesRam124* , stMesRam124* ); + +UINT8 RdStatus124( UINT8 UcStBitChk ); +void MeasureStart2124( INT32 SlMeasureParameterNum , INT32 SlMeasureParameterA , INT32 SlMeasureParameterB , UINT16 UsTime ); +void MesFil2124( UINT16 UsMesFreq ) ; +void SetLinearityParameter( void ); +void SetGyroCoef124( UINT8 ); +void SetAccelCoef124( UINT8 ); + +extern stAclVal StAclVal124 ; //!< Execute Command Parameter + +//************************** +// define +//************************** +#define ONE_MSEC_COUNT 18 // 18.0288kHz * 18 à 1ms + +//#define HALL_ADJ 0 +#define LOOPGAIN 1 +#define THROUGH 2 +#define NOISE 3 +#define OSCCHK 4 + +#define CNT050MS 676 +#define CNT100MS 1352 +#define CNT200MS 2703 + +//******************************************************************************** +// Function Name : SetTregAf +// Retun Value : +// Argment Value : Min:000h Max:7FFh (11bit) in the case of Bi-direction +// Argment Value : Min:000h Max:3FFh (10bit) in the case of Uni-direction +// Explanation : +// History : First edition 2014.06.19 T.Tokoro +//******************************************************************************** +void SetTregAf( UINT16 UsTregAf ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + + RamWrite32A( CMD_AF_POSITION, UsTregAf| 0x00010000 ) ; // bit 16 : FST mode + while( UcStRd && ( UlStCnt++ < CNT050MS) ) { + UcStRd = RdStatus124(1); + } +TRACE("SetTregAf( status , cnt ) = %02x , %08x\n", UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : PreparationForPowerOff +// Retun Value : +// Argment Value : +// Explanation : +// History : First edition +//******************************************************************************** +void PreparationForPowerOff124( void ) +{ + UINT32 UlReadVa; + DSPVER Dspcode; + + /* SPI communication pending */ + RamRead32A ( (GYRO_RAM_GYRO_AF_Switch & 0xFFFC), &UlReadVa ); + RamWrite32A( (GYRO_RAM_GYRO_AF_Switch & 0xFFFC), (UlReadVa|0x00008000) ); + + RamWrite32A( CMD_IO_ADR_ACCESS , ROMINFO ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVa ); + if ( UlReadVa == 0x01 ){ + /* Normal Ram program execution */ + GetInfomationAfterDownload( &Dspcode ); + switch ( Dspcode.GyroType ){ + case GYRO_LSM6DSM: + /* Gyro SPI disable command set for ST by secondary SPI*/ + RamWrite32A( CMD_GYRO_WR_ACCS, 0x70000000 ); + break; + } + } +} + +//******************************************************************************** +// Function Name : MesFil124 +// Retun Value : NON +// Argment Value : Measure Filter Mode +// Explanation : Measure Filter Setting Function +// History : First edition +//******************************************************************************** +void MesFil124( UINT8 UcMesMod ) // 20.019kHz +{ + UINT32 UlMeasFilaA , UlMeasFilaB , UlMeasFilaC ; + UINT32 UlMeasFilbA , UlMeasFilbB , UlMeasFilbC ; + + UlMeasFilaA = 0x00000000 ; + UlMeasFilaB = 0x00000000 ; + UlMeasFilaC = 0x00000000 ; + UlMeasFilbA = 0x00000000 ; + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + if( !UcMesMod ) { // Hall Bias&Offset Adjust + + UlMeasFilaA = 0x0342AD4D ; // LPF 150Hz + UlMeasFilaB = 0x0342AD4D ; + UlMeasFilaC = 0x797AA565 ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } else if( UcMesMod == LOOPGAIN ) { // Loop Gain Adjust + + UlMeasFilaA = 0x12FEA055 ; // LPF1000Hz + UlMeasFilaB = 0x12FEA055 ; + UlMeasFilaC = 0x5A02BF55 ; + UlMeasFilbA = 0x7F559791 ; // HPF30Hz + UlMeasFilbB = 0x80AA686F ; + UlMeasFilbC = 0x7EAB2F23 ; + + } else if( UcMesMod == THROUGH ) { // for Through + + UlMeasFilaA = 0x7FFFFFFF ; // Through + UlMeasFilaB = 0x00000000 ; + UlMeasFilaC = 0x00000000 ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } else if( UcMesMod == NOISE ) { // SINE WAVE TEST for NOISE + + UlMeasFilaA = 0x0342AD4D ; // LPF150Hz + UlMeasFilaB = 0x0342AD4D ; + UlMeasFilaC = 0x797AA565 ; + UlMeasFilbA = 0x0342AD4D ; // LPF150Hz + UlMeasFilbB = 0x0342AD4D ; + UlMeasFilbC = 0x797AA565 ; + + } else if(UcMesMod == OSCCHK) { + UlMeasFilaA = 0x065BE349 ; // LPF300Hz + UlMeasFilaB = 0x065BE349 ; + UlMeasFilaC = 0x7348396D ; + UlMeasFilbA = 0x065BE349 ; // LPF300Hz + UlMeasFilbB = 0x065BE349 ; + UlMeasFilbC = 0x7348396D ; + } + + RamWrite32A ( MeasureFilterA_Coeff_a1 , UlMeasFilaA ) ; + RamWrite32A ( MeasureFilterA_Coeff_b1 , UlMeasFilaB ) ; + RamWrite32A ( MeasureFilterA_Coeff_c1 , UlMeasFilaC ) ; + + RamWrite32A ( MeasureFilterA_Coeff_a2 , UlMeasFilbA ) ; + RamWrite32A ( MeasureFilterA_Coeff_b2 , UlMeasFilbB ) ; + RamWrite32A ( MeasureFilterA_Coeff_c2 , UlMeasFilbC ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a1 , UlMeasFilaA ) ; + RamWrite32A ( MeasureFilterB_Coeff_b1 , UlMeasFilaB ) ; + RamWrite32A ( MeasureFilterB_Coeff_c1 , UlMeasFilaC ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a2 , UlMeasFilbA ) ; + RamWrite32A ( MeasureFilterB_Coeff_b2 , UlMeasFilbB ) ; + RamWrite32A ( MeasureFilterB_Coeff_c2 , UlMeasFilbC ) ; +} + +//******************************************************************************** +// Function Name : ClrMesFil124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Clear Measure Filter Function +// History : First edition +//******************************************************************************** +void ClrMesFil124( void ) +{ + RamWrite32A ( MeasureFilterA_Delay_z11 , 0 ) ; + RamWrite32A ( MeasureFilterA_Delay_z12 , 0 ) ; + + RamWrite32A ( MeasureFilterA_Delay_z21 , 0 ) ; + RamWrite32A ( MeasureFilterA_Delay_z22 , 0 ) ; + + RamWrite32A ( MeasureFilterB_Delay_z11 , 0 ) ; + RamWrite32A ( MeasureFilterB_Delay_z12 , 0 ) ; + + RamWrite32A ( MeasureFilterB_Delay_z21 , 0 ) ; + RamWrite32A ( MeasureFilterB_Delay_z22 , 0 ) ; +} + + +//******************************************************************************** +// Function Name : SetWaitTime124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Set Timer wait Function +// History : First edition +//******************************************************************************** +void SetWaitTime124( UINT16 UsWaitTime ) +{ + RamWrite32A( WaitTimerData_UiWaitCounter , 0 ) ; + RamWrite32A( WaitTimerData_UiTargetCount , (UINT32)(ONE_MSEC_COUNT * UsWaitTime)) ; +} + +//******************************************************************************** +// Function Name : SetTransDataAdr124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Trans Address for Data Function +// History : First edition +//******************************************************************************** +void SetTransDataAdr124( UINT16 UsLowAddress , UINT32 UlLowAdrBeforeTrans ) +{ + UnDwdVal StTrsVal ; + + if( UlLowAdrBeforeTrans < 0x00009000 ){ + StTrsVal.UlDwdVal = UlLowAdrBeforeTrans ; + }else{ + StTrsVal.StDwdVal.UsHigVal = (UINT16)(( UlLowAdrBeforeTrans & 0x0000F000 ) >> 8 ) ; + StTrsVal.StDwdVal.UsLowVal = (UINT16)( UlLowAdrBeforeTrans & 0x00000FFF ) ; + } +//TRACE(" TRANS ADR = %04xh , DAT = %08xh \n",UsLowAddress , StTrsVal.UlDwdVal ) ; + RamWrite32A( UsLowAddress , StTrsVal.UlDwdVal ); + +} + +//******************************************************************************** +// Function Name : MemoryClear124 +// Retun Value : NON +// Argment Value : Top pointer , Size +// Explanation : Memory Clear Function +// History : First edition +//******************************************************************************** +void MemoryClear124( UINT16 UsSourceAddress, UINT16 UsClearSize ) +{ + UINT16 UsLoopIndex ; + + for ( UsLoopIndex = 0 ; UsLoopIndex < UsClearSize ; UsLoopIndex += 4 ) { + RamWrite32A( UsSourceAddress + UsLoopIndex , 0x00000000 ) ; // 4Byte +//TRACE("MEM CLR ADR = %04xh \n",UsSourceAddress + UsLoopIndex) ; + } +} + +//******************************************************************************** +// Function Name : MeasureStart124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void MeasureStart124( INT32 SlMeasureParameterNum , UINT32 SlMeasureParameterA , UINT32 SlMeasureParameterB ) +{ + MemoryClear124( StMeasFunc_SiSampleNum , sizeof( MeasureFunction_Type ) ) ; + RamWrite32A( StMeasFunc_MFA_SiMax1 , 0x80000000 ) ; // Set Min + RamWrite32A( StMeasFunc_MFB_SiMax2 , 0x80000000 ) ; // Set Min + RamWrite32A( StMeasFunc_MFA_SiMin1 , 0x7FFFFFFF ) ; // Set Max + RamWrite32A( StMeasFunc_MFB_SiMin2 , 0x7FFFFFFF ) ; // Set Max + + SetTransDataAdr124( StMeasFunc_MFA_PiMeasureRam1 , SlMeasureParameterA ) ; // Set Measure Filter A Ram Address + SetTransDataAdr124( StMeasFunc_MFB_PiMeasureRam2 , SlMeasureParameterB ) ; // Set Measure Filter B Ram Address + RamWrite32A( StMeasFunc_SiSampleNum , 0 ) ; // Clear Measure Counter + ClrMesFil124() ; // Clear Delay Ram +// SetWaitTime124(50) ; + SetWaitTime124(1) ; + RamWrite32A( StMeasFunc_SiSampleMax , SlMeasureParameterNum ) ; // Set Measure Max Number + +} + +//******************************************************************************** +// Function Name : MeasureWait124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Wait complete of Measure Function +// History : First edition +//******************************************************************************** +void MeasureWait124( void ) +{ + UINT32 SlWaitTimerSt ; + + SlWaitTimerSt = 1 ; + while( SlWaitTimerSt ){ + RamRead32A( StMeasFunc_SiSampleMax , &SlWaitTimerSt ) ; + } +} + +//******************************************************************************** +// Function Name : SetGyroOffset124 +// Retun Value : NON +// Argment Value : NON +// Explanation : set the gyro offset data. before do this before Remapmain. +// History : First edition +//******************************************************************************** +void SetGyroOffset124( UINT16 GyroOffsetX, UINT16 GyroOffsetY, UINT16 GyroOffsetZ ) +{ + RamWrite32A( GYRO_RAM_GXOFFZ , (( GyroOffsetX << 16 ) & 0xFFFF0000 ) ) ; // X axis Gyro offset + RamWrite32A( GYRO_RAM_GYOFFZ , (( GyroOffsetY << 16 ) & 0xFFFF0000 ) ) ; // Y axis Gyro offset + RamWrite32A( GYRO_RAM_GZOFFZ , (( GyroOffsetZ << 16 ) & 0xFFFF0000 ) ) ; // Z axis Gyro offset +} + +//******************************************************************************** +// Function Name :GyroOffsetMeasureStart124 +// Retun Value : NON +// Argment Value : NON +// Explanation : start the gyro offset adjustment +// History : First edition +//******************************************************************************** +#define GYROF_NUM 2048 // 2048times +void GyroOffsetMeasureStart124( void ) +{ + MesFil124( THROUGH ) ; // Set Measure Filter + MeasureStart124( GYROF_NUM , GYRO_RAM_GX_ADIDAT , GYRO_RAM_GY_ADIDAT ) ; // Start measure +} + +//******************************************************************************** +// Function Name :GyroOffsetMeasureStartZ124 +// Retun Value : NON +// Argment Value : NON +// Explanation : start the gyro offset adjustment +// History : First edition +//******************************************************************************** +#define GYROF_NUM 2048 // 2048times +void GyroOffsetMeasureStartZ124( void ) +{ + MesFil124( THROUGH ) ; // Set Measure Filter + MeasureStart124( GYROF_NUM , GYRO_RAM_GZ_ADIDAT , GYRO_RAM_GZ_ADIDAT ) ; // Start measure +} + +//******************************************************************************** +// Function Name : GetGyroOffset124 +// Retun Value : NON +// Argment Value : NON +// Explanation : get the gyro offset adjustment result +// History : First edition +//******************************************************************************** +UINT8 GetGyroOffset124( UINT16* GyroOffsetX, UINT16* GyroOffsetY, INT16 GYROF_UPPER, INT16 GYROF_LOWER ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureAveValueA , SlMeasureAveValueB ; + INT32 SlMeasureMaxValue , SlMeasureMinValue ; + UINT32 UlReadVal, UlCnt=0; + UINT8 ans=0; + + // Wait complete of measurement + do{ + if( UlCnt++ > 100 ){ + /* timeout error */ + *GyroOffsetX = 0; + *GyroOffsetY = 0; + CAM_ERR(CAM_OIS, + "UlCnt up to 100+ return 3.");//byron + return( 3 ); + } + RamRead32A( StMeasFunc_SiSampleMax , &UlReadVal ) ; + }while ( UlReadVal != 0 ); + + RamRead32A( StMeasFunc_MFA_SiMax1 , ( UINT32 * )&SlMeasureMaxValue ) ; // Max value + RamRead32A( StMeasFunc_MFA_SiMin1 , ( UINT32 * )&SlMeasureMinValue ) ; // Min value + if (SlMeasureMaxValue == SlMeasureMinValue ) + { + CAM_ERR(CAM_OIS, + "SlMeasureMaxValue == SlMeasureMinValue return 3.");//byron2 + return( 3 ); + } + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT32)( (INT64)StMeasValueA.UllnValue / GYROF_NUM ) ; + SlMeasureAveValueB = (INT32)( (INT64)StMeasValueB.UllnValue / GYROF_NUM ) ; + + SlMeasureAveValueA = ( SlMeasureAveValueA >> 16 ) & 0x0000FFFF ; + SlMeasureAveValueB = ( SlMeasureAveValueB >> 16 ) & 0x0000FFFF ; + // EP1‚ł͔½“]ˆ—‚µ‚È‚¢B +// SlMeasureAveValueA = 0x00010000 - SlMeasureAveValueA ; +// SlMeasureAveValueB = 0x00010000 - SlMeasureAveValueB ; + + *GyroOffsetX = ( UINT16 )( SlMeasureAveValueA & 0x0000FFFF ); //Measure Result Store + *GyroOffsetY = ( UINT16 )( SlMeasureAveValueB & 0x0000FFFF ); //Measure Result Store + + if(( (INT16)(*GyroOffsetX) > GYROF_UPPER ) || ( (INT16)(*GyroOffsetX) < GYROF_LOWER )){ + ans |= 1; + } + if(( (INT16)(*GyroOffsetY) > GYROF_UPPER ) || ( (INT16)(*GyroOffsetY) < GYROF_LOWER )){ + ans |= 2; + } + CAM_ERR(CAM_OIS, + "func finish return.");//byron3 + return( ans ); +} + +#ifdef SEL_SHIFT_COR +//******************************************************************************** +// Function Name : SetAcclOffset124 +// Retun Value : NON +// Argment Value : NON +// Explanation : set the accl offset data. before do this before Remapmain. +// History : First edition +//******************************************************************************** +void SetAcclOffset124( UINT16 AcclOffsetX, UINT16 AcclOffsetY, UINT16 AcclOffsetZ ) +{ + RamWrite32A( ZeroServoRAM_X_OFFSET , ( ( AcclOffsetX << 16 ) & 0xFFFF0000 ) ) ; // X axis Accl offset + RamWrite32A( ZeroServoRAM_Y_OFFSET , ( ( AcclOffsetY << 16 ) & 0xFFFF0000 ) ) ; // Y axis Accl offset + RamWrite32A( ZeroServoRAM_Z_OFFSET , ( ( AcclOffsetZ << 16 ) & 0xFFFF0000 ) ) ; // Z axis Accl offset +} + +//******************************************************************************** +// Function Name : GetAcclOffset124 +// Retun Value : NON +// Argment Value : NON +// Explanation : get the accl offset adjustment result +// History : First edition +//******************************************************************************** +void GetAcclOffset124( UINT16* AcclOffsetX, UINT16* AcclOffsetY, UINT16* AcclOffsetZ ) +{ + *AcclOffsetX = ( UINT16 )( StAclVal124.StAccel.SlOffsetX & 0x0000FFFF ); + *AcclOffsetY = ( UINT16 )( StAclVal124.StAccel.SlOffsetY & 0x0000FFFF ); + *AcclOffsetZ = ( UINT16 )( StAclVal124.StAccel.SlOffsetZ & 0x0000FFFF ); +} +#endif //SEL_SHIFT_COR + +//******************************************************************************** +// Function Name : RtnCen124 +// Retun Value : Command Status +// Argment Value : Command Parameter +// Explanation : Return to center Command Function +// History : First edition +//******************************************************************************** +UINT8 RtnCen124( UINT8 UcCmdPar ) +{ + UINT8 UcSndDat = 1 ; + UINT32 UlStCnt = 0; + + if( !UcCmdPar ){ // X,Y centering + RamWrite32A( CMD_RETURN_TO_CENTER , BOTH_SRV_ON ) ; + }else if( UcCmdPar == XONLY_ON ){ // only X centering + RamWrite32A( CMD_RETURN_TO_CENTER , XAXS_SRV_ON ) ; + }else if( UcCmdPar == YONLY_ON ){ // only Y centering + RamWrite32A( CMD_RETURN_TO_CENTER , YAXS_SRV_ON ) ; + }else{ // Both off + RamWrite32A( CMD_RETURN_TO_CENTER , BOTH_SRV_OFF ) ; + } + + while( UcSndDat && (UlStCnt++ < CNT200MS )) { + UcSndDat = RdStatus124(1); + } +TRACE("RtnCen124( cmd , status , cnt ) = %02x , %02x , %08x \n", UcCmdPar , UcSndDat , (int)UlStCnt ) ; + return( UcSndDat ); +} + + + +//******************************************************************************** +// Function Name : ZsvCnt +// Retun Value : Command Status +// Argment Value : Command Parameter +// Explanation : Zero servo control Command Function +// History : First edition +//******************************************************************************** +UINT8 ZscCnt( UINT8 UcCmdPar ) +{ + UINT8 UcSndDat = 1 ; + UINT32 UlStCnt = 0; + +TRACE("ZscCnt(%02x) = ", UcCmdPar ) ; + if( !UcCmdPar ){ // Zero servo off + RamWrite32A( CMD_ZSRV_MODE , ZSRV_DISABLE ) ; + }else if( UcCmdPar == 1 ){ // Zero servo on + RamWrite32A( CMD_ZSRV_MODE , ZSRV_ENABLE ) ; + }else if( UcCmdPar == 3 ){ // Zero servo hold + RamWrite32A( CMD_ZSRV_MODE , ZSRV_HOLD ) ; + }else{ + return( 2 ); + } + + while( UcSndDat && (UlStCnt++ < CNT050MS )) { + UcSndDat = RdStatus124(1); + } +TRACE("ZscCnt( cmd , status , cnt ) = %02x , %02x , %08x \n", UcCmdPar , UcSndDat , (int)UlStCnt ) ; + + return( UcSndDat ); +} + +//******************************************************************************** +// Function Name : OisEna124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function +// History : First edition +//******************************************************************************** +void OisEna124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENABLE ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus124(1); + } +TRACE(" OisEna124( Status , cnt ) = %02x , %08x \n", UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : OisEnaNCL124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function w/o delay clear +// History : First edition +//******************************************************************************** +void OisEnaNCL124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENA_NCL | OIS_ENABLE ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus124(1); + } +TRACE(" OisEnaNCL124( Status , cnt ) = %02x %08x \n", UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : OisEnaDrCl124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function w/o delay clear +// History : First edition +//******************************************************************************** +void OisEnaDrCl124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENA_DOF | OIS_ENABLE ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus124(1); + } +TRACE(" OisEnaDrCl124( Status , cnt ) = %02x , %08x \n", UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : OisEnaDrNcl124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function w/o delay clear +// History : First edition +//******************************************************************************** +void OisEnaDrNcl124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENA_DOF | OIS_ENA_NCL | OIS_ENABLE ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus124(1); + } +TRACE(" OisEnaDrCl124( Status , cnt ) = %02x , %08x \n", UcStRd , (int)UlStCnt ) ; +} +//******************************************************************************** +// Function Name : OisDis124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Disable Control Function +// History : First edition +//******************************************************************************** +void OisDis124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_OIS_ENABLE , OIS_DISABLE ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" OisDis124( Status , cnt ) = %02x , %08x \n", UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : SscEna124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Ssc Enable Control Function +// History : First edition +//******************************************************************************** +void SscEna124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_SSC_ENABLE , SSC_ENABLE ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" SscEna124( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : SscDis124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Ssc Disable Control Function +// History : First edition +//******************************************************************************** +void SscDis124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_SSC_ENABLE , SSC_DISABLE ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" SscDis124( Status) = %02x\n", UcStRd ) ; +} + + +//******************************************************************************** +// Function Name : SetRec124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Rec Mode Enable Function +// History : First edition +//******************************************************************************** +void SetRec124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" SetRec124( Status , cnt ) = %02x , %08x \n", UcStRd , (int)UlStCnt ) ; +} + + +//******************************************************************************** +// Function Name : SetStill124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Set Still Mode Enable Function +// History : First edition +//******************************************************************************** +void SetStill124( void ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" SetStill124( Status , cnt ) = %02x , %08x \n", UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : SetRecPreview124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Rec Preview Mode Enable Function +// History : First edition +//******************************************************************************** +void SetRecPreview124( UINT8 mode ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + switch( mode ){ + case 0: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE ) ; + break; + case 1: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE1 ) ; + break; + case 2: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE2 ) ; + break; + case 3: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE3 ) ; + break; + } + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" SetRec124( %02x )( status , cnt ) = %02x , %08x , \n", mode , UcStRd ,(int)UlStCnt ) ; +} + + +//******************************************************************************** +// Function Name : SetStillPreview124 +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Set Still Preview Mode Enable Function +// History : First edition +//******************************************************************************** +void SetStillPreview124( unsigned char mode ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + switch( mode ){ + case 0: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE ) ; + break; + case 1: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE1 ) ; + break; + case 2: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE2 ) ; + break; + case 3: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE3 ) ; + break; + } + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" SetStill124( %02x )( status , cnt ) = %02x , %08x \n", mode , UcStRd , (int)UlStCnt ) ; +} + +//******************************************************************************** +// Function Name : SetPanTiltMode124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Pan-Tilt Enable/Disable +// History : First edition +//******************************************************************************** +void SetPanTiltMode124( UINT8 UcPnTmod ) +{ + UINT8 UcStRd = 1; + UINT32 UlStCnt = 0; + + switch ( UcPnTmod ) { + case OFF : + RamWrite32A( CMD_PAN_TILT , PAN_TILT_OFF ) ; +//TRACE(" PanTilt OFF\n"); + break ; + case ON : + RamWrite32A( CMD_PAN_TILT , PAN_TILT_ON ) ; +//TRACE(" PanTilt ON\n"); + break ; + } + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus124(1); + } +TRACE(" PanTilt( Status , mode , cnt ) = %02x , %02x , %08x \n", UcStRd , UcPnTmod , (int)UlStCnt ) ; + +} + +//******************************************************************************** +// Function Name : AfStbyRls +// Retun Value : Command Status +// Argment Value : Command Parameter +// Explanation : Af Standby release Command Function +// History : First edition +//******************************************************************************** +UINT8 AfStbyRls( void ) +{ + +TRACE("AfStbyRls \n" ) ; + DMIOWrite32( SYSDSP_STBOTH, 0x00000C00 ); + + return( SUCCESS ); +} + +//******************************************************************************** +// Function Name : RdStatus124 +// Retun Value : 0:success 1:FAILURE +// Argment Value : bit check 0:ALL 1:bit24 +// Explanation : High level status check Function +// History : First edition +//******************************************************************************** +UINT8 RdStatus124( UINT8 UcStBitChk ) +{ + UINT32 UlReadVal ; + + RamRead32A( CMD_READ_STATUS , &UlReadVal ); +//TRACE(" (Rd St) = %08x\n", (unsigned INT16)UlReadVal ) ; + if( UcStBitChk ){ + UlReadVal &= READ_STATUS_INI ; + } + if( !UlReadVal ){ + return( SUCCESS ); + }else{ + return( FAILURE ); + } +} + + +//******************************************************************************** +// Function Name : SetSinWavGenInt124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Sine wave generator initial Function +// History : First edition +//******************************************************************************** +void SetSinWavGenInt124( void ) +{ + + RamWrite32A( SinWave_Offset , 0x00000000 ) ; // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( SinWave_Phase , 0x60000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( SinWave_Gain , 0x00000000 ) ; // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚Í0[dB]) +// RamWrite32A( SinWave_Gain , 0x7FFFFFFF ) ; // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚ÍCut) +// SetTransDataAdr124( SinWave_OutAddr , (UINT32)SinWave_Output ) ; // ‰Šú’l‚Ìo—ÍæƒAƒhƒŒƒX‚ÍAŽ©•ª‚̃ƒ“ƒo + + RamWrite32A( CosWave_Offset , 0x00000000 ); // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( CosWave_Phase , 0x00000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( CosWave_Gain , 0x00000000 ); // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚ÍCut) +// RamWrite32A( CosWave_Gain , 0x7FFFFFFF ); // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚Í0[dB]) +// SetTransDataAdr124( CosWave_OutAddr , (UINT32)CosWave_Output ); // ‰Šú’l‚Ìo—ÍæƒAƒhƒŒƒX‚ÍAŽ©•ª‚̃ƒ“ƒo + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + +} + + +//******************************************************************************** +// Function Name : TstActMov124 +// Retun Value : Result +// Argment Value : NON +// Explanation : Hall Examination of Acceptance +// History : First edition +//******************************************************************************** +// #define ACT_CHK_LVL 0x33320000 // 0.4 + #define ACT_CHK_FRQ 0x00074528 // 4Hz + #define ACT_CHK_NUM 4507 // 18.0288/0.004 + #define ACT_THR 0x000003E8 // 20dB 10*100 + #define ACT_MARGIN 0.75f // + +UINT8 TstActMov124( UINT8 UcDirSel ) +{ + UINT8 UcRsltSts = 0; + INT32 SlMeasureParameterNum ; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + UnllnVal StMeasValueA , StMeasValueB ; + float SfLimit , Sfzoom , Sflenz , Sfshift ; + UINT32 UlLimit , Ulzoom , Ullenz , Ulshift , UlActChkLvl ; + UINT8 i; + UINT32 UlReturnVal; + + if( UcDirSel == X_DIR ) { // X axis + RamRead32A( Gyro_Limiter_X , ( UINT32 * )&UlLimit ) ; // + RamRead32A( GyroFilterTableX_gxzoom , ( UINT32 * )&Ulzoom ) ; // + RamRead32A( GyroFilterTableX_gxlenz , ( UINT32 * )&Ullenz ) ; // + RamRead32A( Gyro_ShiftX_RG , ( UINT32 * )&Ulshift ) ; // + }else{ + RamRead32A( Gyro_Limiter_Y , ( UINT32 * )&UlLimit ) ; // + RamRead32A( GyroFilterTableY_gyzoom , ( UINT32 * )&Ulzoom ) ; // + RamRead32A( GyroFilterTableY_gylenz , ( UINT32 * )&Ullenz ) ; // + RamRead32A( Gyro_ShiftY_RG , ( UINT32 * )&Ulshift ) ; // + } + +TRACE(" DIR = %d, lmt = %08x, zom = %08x , lnz = %08x ,sft = %08x \n", UcDirSel, (unsigned int)UlLimit , (unsigned int)Ulzoom , (unsigned int)Ullenz , (unsigned int)Ulshift ) ; + + SfLimit = (float)UlLimit / (float)0x7FFFFFFF; + if( Ulzoom == 0){ + Sfzoom = 0; + }else{ + Sfzoom = (float)abs(Ulzoom) / (float)0x7FFFFFFF; + } + if( Ullenz == 0){ + Sflenz = 0; + }else{ + Sflenz = (float)Ullenz / (float)0x7FFFFFFF; + } + Ulshift = ( Ulshift & 0x0000FF00) >> 8 ; // 2X4XB + Sfshift = 1; + for( i = 0 ; i < Ulshift ; i++ ){ + Sfshift *= 2; + } + UlActChkLvl = (UINT32)( (float)0x7FFFFFFF * SfLimit * Sfzoom * Sflenz * Sfshift * ACT_MARGIN ); +//TRACE(" lvl = %08x \n", (unsigned int)UlActChkLvl ) ; + + SlMeasureParameterNum = ACT_CHK_NUM ; + + if( UcDirSel == X_DIR ) { // X axis + SlMeasureParameterA = HALL_RAM_HXOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = HallFilterD_HXDAZ1 ; // Set Measure RAM Address + } else if( UcDirSel == Y_DIR ) { // Y axis + SlMeasureParameterA = HALL_RAM_HYOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = HallFilterD_HYDAZ1 ; // Set Measure RAM Address + } + SetSinWavGenInt124(); + + RamWrite32A( SinWave_Offset , ACT_CHK_FRQ ) ; // Freq Setting = Freq * 80000000h / Fs : 5Hz + RamWrite32A( SinWave_Gain , UlActChkLvl ) ; // Set Sine Wave Gain + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_HXOFF1 ) ; // Set Sine Wave Input RAM + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_HYOFF1 ) ; // Set Sine Wave Input RAM + } + MesFil124( NOISE ) ; // ‘ª’è—pƒtƒBƒ‹ƒ^[‚ðÝ’è‚·‚éB + + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; // DelayRam Clear + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; // DelayRam Clear + } + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + + UlReturnVal = (INT32)((INT64)StMeasValueA.UllnValue * 100 / (INT64)StMeasValueB.UllnValue ) ; + + +TRACE(" Ret = %d \n", (unsigned int)UlReturnVal ) ; + + + UcRsltSts = EXE_END ; + if( UlReturnVal < ACT_THR ){ + if ( !UcDirSel ) { // AXIS X + UcRsltSts = EXE_HXMVER ; + }else{ // AXIS Y + UcRsltSts = EXE_HYMVER ; + } + } + + return( UcRsltSts ) ; + +} +//******************************************************************************** +// Function Name : RunHea124 +// Retun Value : Result +// Argment Value : NON +// Explanation : Hall Examination of Acceptance +// History : First edition +//******************************************************************************** +UINT8 RunHea124( void ) +{ + UINT8 UcRst ; + UcRst = EXE_END ; + UcRst |= TstActMov124( X_DIR) ; + UcRst |= TstActMov124( Y_DIR) ; + +//TRACE("UcRst = %02x\n", UcRst ) ; + return( UcRst ) ; +} + + +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +//******************************************************************************** +// Function Name : RunGea124 +// Retun Value : Result +// Argment Value : NON +// Explanation : Gyro Examination of Acceptance +// History : First edition +//******************************************************************************** +#define GEA_NUM 512 // 512times +// #define GEA_DIF_HIG 0x0062 // 2021_32.8lsb/‹/s max 3.0‹/s-p-p + #define GEA_DIF_HIG 0x0057 // 2030_87.5lsb/‹/s max 1.0‹/s-p-p + #define GEA_DIF_LOW 0x0001 // Gyro Examination of Acceptance + +UINT8 RunGea124( void ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + UINT8 UcRst, UcCnt, UcXLowCnt, UcYLowCnt, UcXHigCnt, UcYHigCnt ; + UINT16 UsGxoVal[10], UsGyoVal[10], UsDif; + INT32 SlMeasureParameterNum , SlMeasureAveValueA , SlMeasureAveValueB ; + + + UcRst = EXE_END ; + UcXLowCnt = UcYLowCnt = UcXHigCnt = UcYHigCnt = 0 ; + + MesFil124( THROUGH ) ; // ‘ª’è—pƒtƒBƒ‹ƒ^[‚ðÝ’è‚·‚éB + + for( UcCnt = 0 ; UcCnt < 10 ; UcCnt++ ) + { + //•½‹Ï’l‘ª’è + + MesFil124( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = GEA_NUM ; // Measurement times + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address + + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + +//TRACE("Read Adr = %04x, %04xh \n",StMeasFunc_MFA_LLiIntegral1 + 4 , StMeasFunc_MFA_LLiIntegral1) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + +//TRACE("GX_OFT = %08x, %08xh \n",(unsigned int)StMeasValueA.StUllnVal.UlHigVal,(unsigned int)StMeasValueA.StUllnVal.UlLowVal) ; +//TRACE("GY_OFT = %08x, %08xh \n",(unsigned int)StMeasValueB.StUllnVal.UlHigVal,(unsigned int)StMeasValueB.StUllnVal.UlLowVal) ; + SlMeasureAveValueA = (INT32)( (INT64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT32)( (INT64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; +//TRACE("GX_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueA) ; +//TRACE("GY_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueB) ; + // X + UsGxoVal[UcCnt] = (UINT16)( SlMeasureAveValueA >> 16 ); // •½‹Ï’l‘ª’è + + // Y + UsGyoVal[UcCnt] = (UINT16)( SlMeasureAveValueB >> 16 ); // •½‹Ï’l‘ª’è + +//TRACE("UcCnt = %02x, UsGxoVal[UcCnt] = %04x\n", UcCnt, UsGxoVal[UcCnt] ) ; +//TRACE("UcCnt = %02x, UsGyoVal[UcCnt] = %04x\n", UcCnt, UsGyoVal[UcCnt] ) ; + + + if( UcCnt > 0 ) + { + if ( (INT16)UsGxoVal[0] > (INT16)UsGxoVal[UcCnt] ) { + UsDif = (UINT16)((INT16)UsGxoVal[0] - (INT16)UsGxoVal[UcCnt]) ; + } else { + UsDif = (UINT16)((INT16)UsGxoVal[UcCnt] - (INT16)UsGxoVal[0]) ; + } + + if( UsDif > GEA_DIF_HIG ) { + //UcRst = UcRst | EXE_GXABOVE ; + UcXHigCnt ++ ; + } + if( UsDif < GEA_DIF_LOW ) { + //UcRst = UcRst | EXE_GXBELOW ; + UcXLowCnt ++ ; + } +//TRACE("CNT = %02x , X diff = %04x ", UcCnt , UsDif ) ; + + if ( (INT16)UsGyoVal[0] > (INT16)UsGyoVal[UcCnt] ) { + UsDif = (UINT16)((INT16)UsGyoVal[0] - (INT16)UsGyoVal[UcCnt]) ; + } else { + UsDif = (UINT16)((INT16)UsGyoVal[UcCnt] - (INT16)UsGyoVal[0]) ; + } + + if( UsDif > GEA_DIF_HIG ) { + //UcRst = UcRst | EXE_GYABOVE ; + UcYHigCnt ++ ; + } + if( UsDif < GEA_DIF_LOW ) { + //UcRst = UcRst | EXE_GYBELOW ; + UcYLowCnt ++ ; + } +//TRACE(" Y diff = %04x \n", UsDif ) ; + } + } + + if( UcXHigCnt >= 1 ) { + UcRst = UcRst | EXE_GXABOVE ; + } + if( UcXLowCnt > 8 ) { + UcRst = UcRst | EXE_GXBELOW ; + } + + if( UcYHigCnt >= 1 ) { + UcRst = UcRst | EXE_GYABOVE ; + } + if( UcYLowCnt > 8 ) { + UcRst = UcRst | EXE_GYBELOW ; + } + +//TRACE("UcRst = %02x\n", UcRst ) ; + + return( UcRst ) ; +} +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + + +//******************************************************************************** +// Function Name : GetGyroWhoAmI +// Retun Value : Result +// Argment Value : NON +// Explanation : Get Gyro Who Am I +// History : First edition +//******************************************************************************** +void GetGyroWhoAmI( UINT8 * UcWho ) +{ + UINT32 UlVal ; + + RamWrite32A( 0xF01D , 0x75000000 ) ; + WitTim( 5 ) ; + + RamRead32A( 0xF01D , &UlVal ) ; +//TRACE("%08x \n", UlVal ); + + *UcWho = (UINT8)( UlVal >> 24 ) ; +} + +//******************************************************************************** +// Function Name : GetGyroID +// Retun Value : Result +// Argment Value : NON +// Explanation : Get Gyro ID +// History : First edition +//******************************************************************************** +void GetGyroID( UINT8 * UcGid ) +{ + UINT32 UlCnt; + UINT32 UlVal; + + for( UlCnt = 0; UlCnt < 8; UlCnt++ ){ + RamWrite32A( 0xF01E, 0x6D000000 ) ; + WitTim( 5 ) ; + + RamWrite32A( 0xF01E, ( 0x6E000000 | ( UlCnt << 16 ) ) ) ; + WitTim( 5 ) ; + + RamWrite32A( 0xF01D, 0x6F000000 ) ; + WitTim( 5 ) ; + + RamRead32A( 0xF01D, &UlVal ) ; +//TRACE("%08x \n", UlVal ); + + WitTim( 5 ) ; + UcGid[UlCnt] = (UINT8)( UlVal >> 24 ) ; + } +} + +//******************************************************************************** +// Function Name : GyroSleep +// Retun Value : Result +// Argment Value : NON +// Explanation : Gyro Sleep Control +// History : First edition +//******************************************************************************** +void GyroSleep( UINT8 UcCtrl ) +{ + UINT8 UcReg; + UINT32 UlVal; + + RamWrite32A( 0xF01D, 0x6B000000 ) ; + WitTim( 5 ) ; + + RamRead32A( 0xF01D, &UlVal ) ; + WitTim( 5 ) ; + + UcReg = (UINT8)( UlVal >> 24 ) ; + + if( UcCtrl == ON ){ + UcReg = UcReg | 0x40; // Bit6(SLEEP) ON + } + else if( UcCtrl == OFF ){ + UcReg = UcReg & 0xBF; // Bit6(SLEEP) OFF + } + + RamWrite32A( 0xF01E, ( 0x6B000000 | ( UcReg << 16 ) ) ) ; +} + +//******************************************************************************** +// Function Name : MesRam124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure +// History : First edition 2015.07.06 +//******************************************************************************** +UINT8 MesRam124( INT32 SlMeasureParameterA, INT32 SlMeasureParameterB, INT32 SlMeasureParameterNum, stMesRam124* pStMesRamA, stMesRam124* pStMesRamB ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + + MesFil124( THROUGH ) ; // Set Measure Filter + + MeasureStart124( SlMeasureParameterNum, SlMeasureParameterA, SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + // A : X axis + RamRead32A( StMeasFunc_MFA_SiMax1 , &(pStMesRamA->SlMeasureMaxValue) ) ; // Max value + RamRead32A( StMeasFunc_MFA_SiMin1 , &(pStMesRamA->SlMeasureMinValue) ) ; // Min value + RamRead32A( StMeasFunc_MFA_UiAmp1 , &(pStMesRamA->SlMeasureAmpValue) ) ; // Amp value + RamRead32A( StMeasFunc_MFA_LLiIntegral1, &(StMeasValueA.StUllnVal.UlLowVal) ) ; // Integration Low + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4, &(StMeasValueA.StUllnVal.UlHigVal) ) ; // Integration Hig + pStMesRamA->SlMeasureAveValue = + (INT32)( (INT64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; // Ave value + + // B : Y axis + RamRead32A( StMeasFunc_MFB_SiMax2 , &(pStMesRamB->SlMeasureMaxValue) ) ; // Max value + RamRead32A( StMeasFunc_MFB_SiMin2 , &(pStMesRamB->SlMeasureMinValue) ) ; // Min value + RamRead32A( StMeasFunc_MFB_UiAmp2 , &(pStMesRamB->SlMeasureAmpValue) ) ; // Amp value + RamRead32A( StMeasFunc_MFB_LLiIntegral2, &(StMeasValueB.StUllnVal.UlLowVal) ) ; // Integration Low + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4, &(StMeasValueB.StUllnVal.UlHigVal) ) ; // Integration Hig + pStMesRamB->SlMeasureAveValue = + (INT32)( (INT64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; // Ave value + + return( 0 ); +} + + +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +//******************************************************************************** +// Function Name : RunGea2124 +// Retun Value : Result +// Argment Value : NON +// Explanation : Gyro Examination of Acceptance +// History : First edition +//******************************************************************************** +#define GEA_NUM2 2048 // 2048times +// level of judgement +#define GEA_MAX_LVL 0x0A41 // 2030_87.5lsb/‹/s max 30‹/s-p-p +#define GEA_MIN_LVL 0x1482 // 2030_87.5lsb/‹/s min 60‹/s-p-p +UINT8 RunGea2124( UINT8 UcMode ) +{ + INT32 SlMeasureParameterA , SlMeasureParameterB ; + UINT8 UcRst ; + UINT16 UsGyrXval , UsGyrYval; + INT32 SlMeasureParameterNum ; + UINT8 UcStRd; + UINT32 UlSwRd , UlGyroConfig ; //, UlGyCnt; + + stMesRam124 StMesRamA ; + stMesRam124 StMesRamB ; + + UcRst = EXE_END ; + + OisDis124() ; + + RamRead32A( GYRO_RAM_GYRO_Switch , &UlSwRd); + RamWrite32A( GYRO_RAM_GYRO_Switch , UlSwRd & 0xFFFFFFFC ) ; + + RamWrite32A( CMD_GYRO_RD_ACCS , 0x1B000000 ); + UcStRd = 1; + while( UcStRd ) { + UcStRd = RdStatus124(1); + } + RamRead32A( CMD_GYRO_RD_ACCS , &UlGyroConfig ); /* FS_SEL backup */ +//TRACE("GYCONFIG = %08x \n",(UINT32)UlGyroConfig ) ; + +////////// ////////// ////////// ////////// ////////// + + RamWrite32A( CMD_GYRO_WR_ACCS , 0x1B180000 ); /* FS_SEL=3ŒÅ’è & Disable Self Test */ + UcStRd = 1; + while( UcStRd ) { + UcStRd = RdStatus124(1); + } + + SlMeasureParameterNum = GEA_NUM2 ; // Measurement times + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address + + MesRam124( SlMeasureParameterA, SlMeasureParameterB, SlMeasureParameterNum, &StMesRamA, &StMesRamB ); + + if( UcMode == GEA_MINMAX_MODE ){ // min, max mode + +//TRACE("GX [max] = %08x, [min] = %08xh \n", (unsigned int)StMesRamA.SlMeasureMaxValue, (unsigned int)StMesRamA.SlMeasureMinValue) ; +//TRACE("GY [max] = %08x, [min] = %08xh \n", (unsigned int)StMesRamB.SlMeasureMaxValue, (unsigned int)StMesRamB.SlMeasureMinValue) ; + +//TRACE("ABS_GX [max] = %08x, [min] = %08xh \n", (unsigned int)abs(StMesRamA.SlMeasureMaxValue), (unsigned int)abs(StMesRamA.SlMeasureMinValue)) ; +//TRACE("ABS_GY [max] = %08x, [min] = %08xh \n", (unsigned int)abs(StMesRamB.SlMeasureMaxValue), (unsigned int)abs(StMesRamB.SlMeasureMinValue)) ; + + // X + if( abs(StMesRamA.SlMeasureMaxValue) >= abs(StMesRamA.SlMeasureMinValue) ) { + UsGyrXval = (UINT16)( abs(StMesRamA.SlMeasureMaxValue) >> 16 ); // max value + } + else{ + UsGyrXval = (UINT16)( abs(StMesRamA.SlMeasureMinValue) >> 16 ); // max value + } + + // Y + if( abs(StMesRamB.SlMeasureMaxValue) >= abs(StMesRamB.SlMeasureMinValue) ) { + UsGyrYval = (UINT16)( abs(StMesRamB.SlMeasureMaxValue) >> 16 ); // max value + } + else{ + UsGyrYval = (UINT16)( abs(StMesRamB.SlMeasureMinValue) >> 16 ); // max value + } + + } + else{ // mean mode + +//TRACE("GX [ave] = %08xh \n", (UINT32)StMesRamA.SlMeasureAveValue) ; +//TRACE("GY [ave] = %08xh \n", (UINT32)StMesRamB.SlMeasureAveValue) ; + +//TRACE("ABS_GX [ave] = %08xh \n", (UINT32)abs(StMesRamA.SlMeasureAveValue)) ; +//TRACE("ABS_GY [ave] = %08xh \n", (UINT32)abs(StMesRamB.SlMeasureAveValue)) ; + + // X + UsGyrXval = (UINT16)( abs(StMesRamA.SlMeasureAveValue) >> 16 ); // ave value + + // Y + UsGyrYval = (UINT16)( abs(StMesRamB.SlMeasureAveValue) >> 16 ); // ave value + + } + +//TRACE("UsGyrXval = %04x\n", UsGyrXval ) ; +//TRACE("UsGyrYval = %04x\n", UsGyrYval ) ; + + if( UsGyrXval > GEA_MAX_LVL ) { + UcRst = UcRst | EXE_GXABOVE ; + } + if( UsGyrYval > GEA_MAX_LVL ) { + UcRst = UcRst | EXE_GYABOVE ; + } + + if( StMesRamA.SlMeasureMinValue == StMesRamA.SlMeasureMaxValue ){ + UcRst = UcRst | EXE_GXABOVE ; + } + if( StMesRamB.SlMeasureMinValue == StMesRamB.SlMeasureMaxValue ){ + UcRst = UcRst | EXE_GYABOVE ; + } + +////////// ////////// ////////// ////////// ////////// + + RamWrite32A( CMD_GYRO_WR_ACCS , 0x1BD80000 ); /* FS_SEL=3ŒÅ’è & Enable Self Test */ + UcStRd = 1; + while( UcStRd ) { + UcStRd = RdStatus124(1); + } + + WitTim( 50 ) ; /* 50ms*/ + + SlMeasureParameterNum = GEA_NUM2 ; // Measurement times + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address + + MesRam124( SlMeasureParameterA, SlMeasureParameterB, SlMeasureParameterNum, &StMesRamA, &StMesRamB ); + + if( UcMode == GEA_MINMAX_MODE ){ // min, max mode + +//TRACE("GX [max] = %08x, [min] = %08xh \n", (UINT32)StMesRamA.SlMeasureMaxValue, (UINT32)StMesRamA.SlMeasureMinValue) ; +//TRACE("GY [max] = %08x, [min] = %08xh \n", (UINT32)StMesRamB.SlMeasureMaxValue, (UINT32)StMesRamB.SlMeasureMinValue) ; + + // X + UsGyrXval = (UINT16)( StMesRamA.SlMeasureMinValue >> 16 ); // min value + + // Y + UsGyrYval = (UINT16)( StMesRamB.SlMeasureMinValue >> 16 ); // min value + + } + else{ // mean mode +//TRACE("GX [ave] = %08xh \n", (UINT32)StMesRamA.SlMeasureAveValue) ; +//TRACE("GY [ave] = %08xh \n", (UINT32)StMesRamB.SlMeasureAveValue) ; + + // X + UsGyrXval = (UINT16)( StMesRamA.SlMeasureAveValue >> 16 ); // ave value + + // Y + UsGyrYval = (UINT16)( StMesRamB.SlMeasureAveValue >> 16 ); // ave value + + } + +//TRACE("UsGyrXval = %04x\n", UsGyrXval ) ; +//TRACE("UsGyrYval = %04x\n", UsGyrYval ) ; + + if( UsGyrXval < GEA_MIN_LVL ) { + UcRst = UcRst | EXE_GXBELOW ; + } + if( UsGyrYval < GEA_MIN_LVL ) { + UcRst = UcRst | EXE_GYBELOW ; + } + + if( StMesRamA.SlMeasureMinValue == StMesRamA.SlMeasureMaxValue ){ + UcRst = UcRst | EXE_GXBELOW ; + } + if( StMesRamB.SlMeasureMinValue == StMesRamB.SlMeasureMaxValue ){ + UcRst = UcRst | EXE_GYBELOW ; + } + + RamWrite32A( CMD_GYRO_WR_ACCS , 0x1B000000 | ( UlGyroConfig >> 8)); /* Œ³‚ÌÝ’è’l‚É–ß‚· */ + UcStRd = 1; + while( UcStRd ) { + UcStRd = RdStatus124(1); + } + +//TRACE("GYCONFIG = %08x \n",(UINT32)(0x1B000000 | ( UlGyroConfig >> 8)) ) ; + + RamWrite32A( GYRO_RAM_GYRO_Switch , UlSwRd | 0x00000001 ) ; +//TRACE("UcRst = %02x\n", UcRst ) ; + + return( UcRst ) ; +} +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + + +//******************************************************************************** +// Function Name : SetAngleCorrection124 +// Retun Value : True/Fail +// Argment Value : +// Explanation : Angle Correction +// History : First edition +//******************************************************************************** +/* bit7 HX GYR Hall X ‚Æ“¯•ûŒü‚ÌGyroM†‚ªGX? 0:GX 1:GY */ +/* bit6 HX GYR pol Hall X+ ‚Æ“¯•ûŒü‚ÌGyroM†‚ªX+‚ÆG+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit5 HY GYR pol Hall Y+ ‚Æ“¯•ûŒü‚ÌGyroM†‚ªY+‚ÆG+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit4 GZ pol Šî–{‹É«‚ɑ΂µ‚ÄGyroZM†‚ª“¯•ûŒü? 0:NEG 1:POS */ +/* bit3 HX ACL Hall X ‚Æ“¯•ûŒü‚ÌAcclM†‚ªAX? 0:AX 1:AY */ +/* bit2 HX ACL pol Hall X+ ‚Æ“¯•ûŒü‚ÌAcclM†‚ªX+‚ÆA+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit1 HY ACL pol Hall Y+ ‚Æ“¯•ûŒü‚ÌAcclM†‚ªY+‚ÆA+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit0 AZ pol Šî–{‹É«‚ɑ΂µ‚ÄAcclZM†‚ª“¯•ûŒü? 0:NEG 1:POS */ + // top0‹btm0‹// +const UINT8 PACT0Tbl124[] = { 0xFF, 0xFF }; /* Dummy table */ +const UINT8 PACT1Tbl124[] = { 0x20, 0xDF }; +const UINT8 PACT2Tbl124[] = { 0x26, 0xD9 }; /* ACT_45DEG */ + + +UINT8 SetAngleCorrection124( float DegreeGap, UINT8 SelectAct, UINT8 Arrangement ) +{ + double OffsetAngle = 0.0f; + INT32 Slgx45x = 0, Slgx45y = 0; + INT32 Slgy45y = 0, Slgy45x = 0; + +// INT32 Slgx45m = 0, Slgx45s = 0; +// INT32 Slgy45m = 0, Slgy45s = 0; + UINT8 UcCnvF = 0; + + if( ( DegreeGap > 180.0f) || ( DegreeGap < -180.0f ) ) return ( 1 ); + if( Arrangement >= 2 ) return ( 1 ); + +/************************************************************************/ +/* Gyro angle correction */ +/************************************************************************/ + switch(SelectAct) { + case ACT_45DEG : + OffsetAngle = (double)( 45.0f + DegreeGap ) * 3.141592653589793238 / 180.0f ; + UcCnvF = PACT2Tbl124[ Arrangement ]; + break; + case ACT_SO2821 : + case ACT_M12337_A1: + OffsetAngle = (double)( DegreeGap ) * 3.141592653589793238 / 180.0f ; + UcCnvF = PACT1Tbl124[ Arrangement ]; + break; + default : + break; + } + + SetGyroCoef124( UcCnvF ); + SetAccelCoef124( UcCnvF ); + + //***********************************************// + // Gyro & Accel rotation correction + // Zero Servo angle correction + //***********************************************// +// Slgx45x = (INT32)( cos( OffsetAngle )*2147483647.0); +// Slgx45y = (INT32)(-sin( OffsetAngle )*2147483647.0); +// Slgy45y = (INT32)( cos( OffsetAngle )*2147483647.0); +// Slgy45x = (INT32)( sin( OffsetAngle )*2147483647.0); + + RamWrite32A( GyroFilterTableX_gx45x , (UINT32)Slgx45x ); + RamWrite32A( GyroFilterTableX_gx45y , (UINT32)Slgx45y ); + RamWrite32A( GyroFilterTableY_gy45y , (UINT32)Slgy45y ); + RamWrite32A( GyroFilterTableY_gy45x , (UINT32)Slgy45x ); +#ifdef ACCEL_SERVO + RamWrite32A( Accl45Filter_XAmain , (UINT32)Slgx45x ); + RamWrite32A( Accl45Filter_XAsub , (UINT32)Slgx45y ); + RamWrite32A( Accl45Filter_YAmain , (UINT32)Slgy45y ); + RamWrite32A( Accl45Filter_YAsub , (UINT32)Slgy45x ); +#endif + +#ifdef ZERO_SERVO + RamWrite32A( ZeroServoFilterTableX_g45main , (UINT32)Slgx45x ); + RamWrite32A( ZeroServoFilterTableX_g45sub , (UINT32)Slgx45y ); + RamWrite32A( ZeroServoFilterTableY_g45main , (UINT32)Slgy45y ); + RamWrite32A( ZeroServoFilterTableY_g45sub , (UINT32)Slgy45x ); +#endif + + return ( 0 ); +} + +void SetGyroCoef124( UINT8 UcCnvF ) +{ + INT32 Slgxx = 0, Slgxy = 0; + INT32 Slgyy = 0, Slgyx = 0; + INT32 Slgzp = 0; + /************************************************/ + /* signal convet */ + /************************************************/ + switch( UcCnvF & 0xE0 ){ + /* HX <== GX , HY <== GY */ + case 0x00: + Slgxx = 0x7FFFFFFF ; Slgxy = 0x00000000 ; Slgyy = 0x7FFFFFFF ; Slgyx = 0x00000000 ; break; //HX<==GX(NEG), HY<==GY(NEG) + case 0x20: + Slgxx = 0x7FFFFFFF ; Slgxy = 0x00000000 ; Slgyy = 0x80000001 ; Slgyx = 0x00000000 ; break; //HX<==GX(NEG), HY<==GY(POS) + case 0x40: + Slgxx = 0x80000001 ; Slgxy = 0x00000000 ; Slgyy = 0x7FFFFFFF ; Slgyx = 0x00000000 ; break; //HX<==GX(POS), HY<==GY(NEG) + case 0x60: + Slgxx = 0x80000001 ; Slgxy = 0x00000000 ; Slgyy = 0x80000001 ; Slgyx = 0x00000000 ; break; //HX<==GX(POS), HY<==GY(POS) + /* HX <== GY , HY <== GX */ + case 0x80: + Slgxx = 0x00000000 ; Slgxy = 0x7FFFFFFF ; Slgyy = 0x00000000 ; Slgyx = 0x7FFFFFFF ; break; //HX<==GY(NEG), HY<==GX(NEG) + case 0xA0: + Slgxx = 0x00000000 ; Slgxy = 0x7FFFFFFF ; Slgyy = 0x00000000 ; Slgyx = 0x80000001 ; break; //HX<==GY(NEG), HY<==GX(POS) + case 0xC0: + Slgxx = 0x00000000 ; Slgxy = 0x80000001 ; Slgyy = 0x00000000 ; Slgyx = 0x7FFFFFFF ; break; //HX<==GY(POS), HY<==GX(NEG) + case 0xE0: + Slgxx = 0x00000000 ; Slgxy = 0x80000001 ; Slgyy = 0x00000000 ; Slgyx = 0x80000001 ; break; //HX<==GY(NEG), HY<==GX(NEG) + } + switch( UcCnvF & 0x10 ){ + case 0x00: + Slgzp = 0x7FFFFFFF ; break; //GZ(POS) + case 0x10: + Slgzp = 0x80000001 ; break; //GZ(NEG) + } + RamWrite32A( GCNV_XX , (UINT32)Slgxx ); + RamWrite32A( GCNV_XY , (UINT32)Slgxy ); + RamWrite32A( GCNV_YY , (UINT32)Slgyy ); + RamWrite32A( GCNV_YX , (UINT32)Slgyx ); + RamWrite32A( GCNV_ZP , (UINT32)Slgzp ); +} + +void SetAccelCoef124( UINT8 UcCnvF ) +{ + INT32 Slaxx = 0, Slaxy = 0; + INT32 Slayy = 0, Slayx = 0; + INT32 Slazp = 0; + + switch( UcCnvF & 0x0E ){ + /* HX <== AX , HY <== AY */ + case 0x00: + Slaxx = 0x7FFFFFFF ; Slaxy = 0x00000000 ; Slayy = 0x7FFFFFFF ; Slayx = 0x00000000 ; break; //HX<==AX(NEG), HY<==AY(NEG) + case 0x02: + Slaxx = 0x7FFFFFFF ; Slaxy = 0x00000000 ; Slayy = 0x80000001 ; Slayx = 0x00000000 ; break; //HX<==AX(NEG), HY<==AY(POS) + case 0x04: + Slaxx = 0x80000001 ; Slaxy = 0x00000000 ; Slayy = 0x7FFFFFFF ; Slayx = 0x00000000 ; break; //HX<==AX(POS), HY<==AY(NEG) + case 0x06: + Slaxx = 0x80000001 ; Slaxy = 0x00000000 ; Slayy = 0x80000001 ; Slayx = 0x00000000 ; break; //HX<==AX(POS), HY<==AY(POS) + /* HX <== AY , HY <== AX */ + case 0x08: + Slaxx = 0x00000000 ; Slaxy = 0x7FFFFFFF ; Slayy = 0x00000000 ; Slayx = 0x7FFFFFFF ; break; //HX<==AY(NEG), HY<==AX(NEG) + case 0x0A: + Slaxx = 0x00000000 ; Slaxy = 0x7FFFFFFF ; Slayy = 0x00000000 ; Slayx = 0x80000001 ; break; //HX<==AY(NEG), HY<==AX(POS) + case 0x0C: + Slaxx = 0x00000000 ; Slaxy = 0x80000001 ; Slayy = 0x00000000 ; Slayx = 0x7FFFFFFF ; break; //HX<==AY(POS), HY<==AX(NEG) + case 0x0E: + Slaxx = 0x00000000 ; Slaxy = 0x80000001 ; Slayy = 0x00000000 ; Slayx = 0x80000001 ; break; //HX<==AY(NEG), HY<==AX(NEG) + } + switch( UcCnvF & 0x01 ){ + case 0x00: + Slazp = 0x7FFFFFFF ; break; //AZ(POS) + case 0x01: + Slazp = 0x80000001 ; break; //AZ(NEG) + } + RamWrite32A( ACNV_XX , (UINT32)Slaxx ); + RamWrite32A( ACNV_XY , (UINT32)Slaxy ); + RamWrite32A( ACNV_YY , (UINT32)Slayy ); + RamWrite32A( ACNV_YX , (UINT32)Slayx ); + RamWrite32A( ACNV_ZP , (UINT32)Slazp ); +} + +//******************************************************************************** +// Function Name : SetGyroAccelCoef +// Retun Value : non +// Argment Value : +// Explanation : Set Gyro Coef and Accel Coef +// History : First edition +//******************************************************************************** +void SetGyroAccelCoef( UINT8 SelectAct, UINT8 GyroPostion ){ +TRACE("SetGyroAccelCoef SelectAct 0x%x GyroPostion 0x%x\n", SelectAct, GyroPostion); +#if ( SELECT_VENDOR == 0x01 ) + RamWrite32A( GCNV_XX , (UINT32)0x00000000 ); + RamWrite32A( GCNV_XY , (UINT32)0x7FFFFFFF ); + RamWrite32A( GCNV_YY , (UINT32)0x00000000 ); + RamWrite32A( GCNV_YX , (UINT32)0x7FFFFFFF ); + RamWrite32A( GCNV_ZP , (UINT32)0x7FFFFFFF ); + + RamWrite32A( ACNV_XX , (UINT32)0x00000000 ); + RamWrite32A( ACNV_XY , (UINT32)0x7FFFFFFF ); + RamWrite32A( ACNV_YY , (UINT32)0x00000000 ); + RamWrite32A( ACNV_YX , (UINT32)0x80000001 ); + RamWrite32A( ACNV_ZP , (UINT32)0x80000001 ); +#else + RamWrite32A( GCNV_XX , (UINT32)0x7FFFFFFF ); + RamWrite32A( GCNV_XY , (UINT32)0x00000000 ); + RamWrite32A( GCNV_YY , (UINT32)0x7FFFFFFF ); + RamWrite32A( GCNV_YX , (UINT32)0x00000000 ); + RamWrite32A( GCNV_ZP , (UINT32)0x7FFFFFFF ); + + RamWrite32A( ACNV_XX , (UINT32)0x80000001 ); + RamWrite32A( ACNV_XY , (UINT32)0x00000000 ); + RamWrite32A( ACNV_YY , (UINT32)0x80000001 ); + RamWrite32A( ACNV_YX , (UINT32)0x00000000 ); + RamWrite32A( ACNV_ZP , (UINT32)0x80000001 ); +#endif +} + +//******************************************************************************** +// Function Name : MeasGain124 +// Retun Value : Hall amp & Sine amp +// Argment Value : X,Y Direction, Freq +// Explanation : Measuring Hall Paek To Peak +// History : First edition +//******************************************************************************** +#define FS4TIME (UINT32)0x000119B3 // 18028.8 * 4 +#define FRQOFST (UINT32)0x0001D14A // 80000000h / 18028.8 + +UINT32 MeasGain124 ( UINT16 UcDirSel, UINT16 UsMeasFreq , UINT32 UlMesAmp ) +{ + INT32 SlMeasureParameterA , SlMeasureParameterB ; + INT32 SlMeasureParameterNum , SlSineWaveOffset; + UnllnVal StMeasValueA , StMeasValueB ; + UINT32 UlReturnVal; + + StMeasValueA.UllnValue = 0; + StMeasValueB.UllnValue = 0; + SlMeasureParameterNum = (INT32)( FS4TIME / (UINT32)UsMeasFreq) * 2; // + + if( UcDirSel == X_DIR ) { // X axis + SlMeasureParameterA = HALL_RAM_HXOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = HallFilterD_HXDAZ1 ; // Set Measure RAM Address + } else if( UcDirSel == Y_DIR ) { // Y axis + SlMeasureParameterA = HALL_RAM_HYOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = HallFilterD_HYDAZ1 ; // Set Measure RAM Address + } + SetSinWavGenInt124(); + + SlSineWaveOffset = (INT32)( FRQOFST * (UINT32)UsMeasFreq ); + RamWrite32A( SinWave_Offset , SlSineWaveOffset ) ; // Freq Setting = Freq * 80000000h / Fs + + RamWrite32A( SinWave_Gain , UlMesAmp ) ; // Set Sine Wave Gain + + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_HXOFF1 ) ; // Set Sine Wave Input RAM + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_HYOFF1 ) ; // Set Sine Wave Input RAM + } + + MesFil2124( UsMeasFreq ) ; // Filter setting for measurement + + MeasureStart2124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB , 8000/UsMeasFreq ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; // DelayRam Clear + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; // DelayRam Clear + } + + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + + UlReturnVal = (INT32)((INT64)StMeasValueA.UllnValue * 100 / (INT64)StMeasValueB.UllnValue ) ; + + + return( UlReturnVal ) ; +} +//******************************************************************************** +// Function Name : MesFil2124 +// Retun Value : NON +// Argment Value : Measure Filter Mode +// Explanation : Measure Filter Setting Function +// History : First edition +//******************************************************************************** +#define DivOffset 5741.65f /* 18028.8/3.14 */ + +void MesFil2124( UINT16 UsMesFreq ) +{ + UINT32 UlMeasFilA1 , UlMeasFilB1 , UlMeasFilC1 , UlTempval ; + UINT32 UlMeasFilA2 , UlMeasFilC2 ; + + UlTempval = (UINT32)((float)2147483647 * (float)UsMesFreq / ((float)UsMesFreq + DivOffset )); + UlMeasFilA1 = 0x7fffffff - UlTempval; + UlMeasFilB1 = ~UlMeasFilA1 + 0x00000001; + UlMeasFilC1 = 0x7FFFFFFF - ( UlTempval << 1 ) ; + + UlMeasFilA2 = UlTempval ; + UlMeasFilC2 = UlMeasFilC1 ; + + + RamWrite32A ( MeasureFilterA_Coeff_a1 , UlMeasFilA1 ) ; + RamWrite32A ( MeasureFilterA_Coeff_b1 , UlMeasFilB1 ) ; + RamWrite32A ( MeasureFilterA_Coeff_c1 , UlMeasFilC1 ) ; + + RamWrite32A ( MeasureFilterA_Coeff_a2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterA_Coeff_b2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterA_Coeff_c2 , UlMeasFilC2 ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a1 , UlMeasFilA1 ) ; + RamWrite32A ( MeasureFilterB_Coeff_b1 , UlMeasFilB1 ) ; + RamWrite32A ( MeasureFilterB_Coeff_c1 , UlMeasFilC1 ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterB_Coeff_b2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterB_Coeff_c2 , UlMeasFilC2 ) ; +} + +//******************************************************************************** +// Function Name : MeasureStart2124 +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void MeasureStart2124( INT32 SlMeasureParameterNum , INT32 SlMeasureParameterA , INT32 SlMeasureParameterB , UINT16 UsTime ) +{ + MemoryClear124( StMeasFunc_SiSampleNum , sizeof( MeasureFunction_Type ) ) ; + RamWrite32A( StMeasFunc_MFA_SiMax1 , 0x80000001 ) ; // Set Min + RamWrite32A( StMeasFunc_MFB_SiMax2 , 0x80000001 ) ; // Set Min + RamWrite32A( StMeasFunc_MFA_SiMin1 , 0x7FFFFFFF ) ; // Set Max + RamWrite32A( StMeasFunc_MFB_SiMin2 , 0x7FFFFFFF ) ; // Set Max + + SetTransDataAdr124( StMeasFunc_MFA_PiMeasureRam1 , ( UINT32 )SlMeasureParameterA ) ; // Set Measure Filter A Ram Address + SetTransDataAdr124( StMeasFunc_MFB_PiMeasureRam2 , ( UINT32 )SlMeasureParameterB ) ; // Set Measure Filter B Ram Address + RamWrite32A( StMeasFunc_SiSampleNum , 0 ) ; // Clear Measure Counter + ClrMesFil124() ; // Clear Delay Ram + RamWrite32A( StMeasFunc_SiSampleMax , SlMeasureParameterNum ) ; // Set Measure Max Number + SetWaitTime124(UsTime) ; + +} + + +//******************************************************************************** +// Function Name : LinearityCalculation +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void LinearityCalculation( void ) +{ + UINT8 tempL[32]; +// UINT8 tempC[10]; + UINT16 tblX[7],tblY[7]; + INT16 stpx,stpy; +// UINT16 tblC[5]; + UINT8 i,n,cnt; + UINT16 adr; + INT32 dacx[7],dacy[7]; + INT16 pixx[7],pixy[7]; + INT16 cfax[6],cfbx[6],cfzx[5]; + INT16 cfay[6],cfby[6],cfzy[5]; + float cffax[6]; + float cffay[6]; + + ReadE2Prom( EEPROM_Calibration_Status_MSB, &cnt ); +TRACE("E2prom Read 0x19 = %02x & %02x \n", cnt , (UINT8)(HLLN_CALB_FLG>>8) ); + if( cnt & (UINT8)(HLLN_CALB_FLG>>8) ){ + return; + } + + BurstReadE2Prom( EEPROM_POSITION_1X_LSB , tempL, 32 ); +// BurstReadE2Prom( EEPROM_CROSSTALK_XX_LSB , tempC, 10 ); + +TRACE("\n E2prom POSITION Read \n" ); +TRACE(" %02xh %02xh %02xh %02xh %02xh %02xh %02xh %02xh \n",tempL[0],tempL[1],tempL[2],tempL[3],tempL[4],tempL[5],tempL[6],tempL[7]) ; +TRACE(" %02xh %02xh %02xh %02xh %02xh %02xh %02xh %02xh \n",tempL[8],tempL[9],tempL[10],tempL[11],tempL[12],tempL[13],tempL[14],tempL[15]) ; +TRACE(" %02xh %02xh %02xh %02xh %02xh %02xh %02xh %02xh \n",tempL[16],tempL[17],tempL[18],tempL[19],tempL[20],tempL[21],tempL[22],tempL[23]) ; +TRACE(" %02xh %02xh %02xh %02xh %02xh %02xh %02xh %02xh \n",tempL[24],tempL[25],tempL[26],tempL[27],tempL[28],tempL[29],tempL[30],tempL[31]) ; +TRACE("\n E2prom CROSS TALK Read \n" ); +//TRACE(" %02xh %02xh %02xh %02xh %02xh %02xh %02xh %02xh \n",tempC[0],tempC[1],tempC[2],tempC[3],tempC[4],tempC[5],tempC[6],tempC[7]) ; +//TRACE(" %02xh %02xh \n",tempC[8],tempC[9]) ; + + /****** Linearity ******/ + for( i=0 , n=0 ; n<7 ; n++ ){ + tblX[n] = tempL[i] + (tempL[i+1]<<8); + i += 2; + tblY[n] = tempL[i] + (tempL[i+1]<<8); + i += 2; + } + stpx = (INT16)(tempL[i] + (tempL[i+1]<<8)); + i += 2; + stpy = (INT16)(tempL[i] + (tempL[i+1]<<8)); +TRACE("\n POSITION TBL \n" ); +TRACE("[x] %04xh %04xh %04xh %04xh %04xh %04xh %04xh \n",tblX[0],tblX[1],tblX[2],tblX[3],tblX[4],tblX[5],tblX[6]) ; +TRACE("[y] %04xh %04xh %04xh %04xh %04xh %04xh %04xh \n",tblY[0],tblY[1],tblY[2],tblY[3],tblY[4],tblY[5],tblY[6]) ; +TRACE("[s] %04xh %04xh \n",stpx,stpy) ; + + for( i=0 ; i<7 ; i++ ){ + dacx[i] = (( i - 3 ) * stpx)<<4; /* 2^16/4096 = 2^4 */ + dacy[i] = (( i - 3 ) * stpy)<<4; /* 2^16/4096 = 2^4 */ + pixx[i] = tblX[i] - tblX[3]; + pixy[i] = tblY[i] - tblY[3]; + } + for( i=0 ; i<6 ; i++ ){ + if(i == 3){ +// cfax[i] = (INT16)((float)pixx[i+1] / (float)dacx[i+1] * 524287.0f); +// cfay[i] = (INT16)((float)pixy[i+1] / (float)dacy[i+1] * 524287.0f); + cffax[i] = ((float)pixx[i+1] / (float)dacx[i+1] * 524287.0f); + cffay[i] = ((float)pixy[i+1] / (float)dacy[i+1] * 524287.0f); + cfax[i] = (INT16)cffax[i]; + cfay[i] = (INT16)cffay[i]; + cfbx[i] = (INT16)0; + cfby[i] = (INT16)0; + }else{ +// cfax[i] = (INT16)(( dacx[i] - dacx[i+1] ) / ( pixx[i] - pixx[i+1] )); +// cfay[i] = (INT16)(( dacy[i] - dacy[i+1] ) / ( pixy[i] - pixy[i+1] )); + cffax[i] = (float)( dacx[i] - dacx[i+1] ) / (float)( pixx[i] - pixx[i+1] ); + cffay[i] = (float)( dacy[i] - dacy[i+1] ) / (float)( pixy[i] - pixy[i+1] ); + cfax[i] = (INT16)cffax[i]; + cfay[i] = (INT16)cffay[i]; + if(i == 2){ + cfbx[i] = (INT16)0; + cfby[i] = (INT16)0; + }else{ +// cfbx[i] = (INT16)( dacx[i] - (INT32)cfax[i] * (INT32)pixx[i] ); +// cfby[i] = (INT16)( dacy[i] - (INT32)cfay[i] * (INT32)pixy[i] ); + cfbx[i] = (INT16)( (float)dacx[i] - cffax[i] * (float)pixx[i] ); + cfby[i] = (INT16)( (float)dacy[i] - cffay[i] * (float)pixy[i] ); + } + } + if(i<5){ + cfzx[i] = pixx[i+1]; + cfzy[i] = pixy[i+1]; + } + } +TRACE("\n CALCULATE \n" ); +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n",(int)dacx[0],pixx[0],(int)dacy[0],pixy[0]) ; +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n",(int)dacx[1],pixx[1],(int)dacy[1],pixy[1]) ; +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n",(int)dacx[2],pixx[2],(int)dacy[2],pixy[2]) ; +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n",(int)dacx[3],pixx[3],(int)dacy[3],pixy[3]) ; +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n",(int)dacx[4],pixx[4],(int)dacy[4],pixy[4]) ; +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n",(int)dacx[5],pixx[5],(int)dacy[5],pixy[5]) ; +TRACE(" [%08xh , %04xh] [%08xh , %04xh]\n\n",(int)dacx[6],pixx[6],(int)dacy[6],pixy[6]) ; +TRACE(" [%04xh , %04xh , %04xh] [%04xh , %04xh , %04xh]\n",cfzx[0],cfax[0],cfbx[0],cfzy[0],cfay[0],cfby[0]) ; +TRACE(" [%04xh , %04xh , %04xh] [%04xh , %04xh , %04xh]\n",cfzx[1],cfax[1],cfbx[1],cfzy[1],cfay[1],cfby[1]) ; +TRACE(" [%04xh , %04xh , %04xh] [%04xh , %04xh , %04xh]\n",cfzx[2],cfax[2],cfbx[2],cfzy[2],cfay[2],cfby[2]) ; +TRACE(" [%04xh , %04xh , %04xh] [%04xh , %04xh , %04xh]\n",cfzx[3],cfax[3],cfbx[3],cfzy[3],cfay[3],cfby[3]) ; +TRACE(" [%04xh , %04xh , %04xh] [%04xh , %04xh , %04xh]\n",cfzx[4],cfax[4],cfbx[4],cfzy[4],cfay[4],cfby[4]) ; +TRACE(" [----- , %04xh , %04xh] [----- , %04xh , %04xh]\n" ,cfax[5],cfbx[5] ,cfay[5],cfby[5]) ; + adr = HAL_LN_CORRECT; + RamWrite32A( adr , (UINT32)( (UINT16)cfax[0] + ((UINT16)cfax[1]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfax[2] + ((UINT16)cfax[3]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfax[4] + ((UINT16)cfax[5]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfbx[0] + ((UINT16)cfbx[1]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfbx[2] + ((UINT16)cfbx[3]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfbx[4] + ((UINT16)cfbx[5]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfzx[0] + ((UINT16)cfzx[1]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfzx[2] + ((UINT16)cfzx[3]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfzx[4] + ((UINT16)cfay[0]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfay[1] + ((UINT16)cfay[2]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfay[3] + ((UINT16)cfay[4]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfay[5] + ((UINT16)cfby[0]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfby[1] + ((UINT16)cfby[2]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfby[3] + ((UINT16)cfby[4]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfby[5] + ((UINT16)cfzy[0]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfzy[1] + ((UINT16)cfzy[2]<<16 ))); adr += 0x0004; + RamWrite32A( adr , (UINT32)( (UINT16)cfzy[3] + ((UINT16)cfzy[4]<<16 ))); + + SetLinearityParameter(); + +// /****** Cross talk ******/ +// for( i=0 , n=0 ; n<5 ; n++ ){ +// tblC[n] = tempC[i] + (tempC[i+1]<<8); +// i += 2; +// } +//TRACE("[XX] %04xh [XY]%04xh [SFT]%02xh\n",tblC[0],tblC[1],(unsigned char)(tblC[4]>>0)) ; +//TRACE("[YY] %04xh [YX]%04xh [SFT]%02xh\n",tblC[2],tblC[3],(unsigned char)(tblC[4]>>8)) ; +// RamWrite32A( HF_hx45x , (UINT32)(tblC[0]<<16)); +// RamWrite32A( HF_hx45y , (UINT32)(tblC[1]<<16)); +// RamWrite32A( HF_hy45y , (UINT32)(tblC[2]<<16)); +// RamWrite32A( HF_hy45x , (UINT32)(tblC[3]<<16)); +// RamWrite32A( HF_ShiftX , (UINT32)(tblC[4])); + +} + +void SetLinearityParameter( void ) +{ + UINT32 UlGyroSw; + + + RamRead32A( GYRO_RAM_GYRO_Switch , &UlGyroSw ); + UlGyroSw |= 0x00000008; + RamWrite32A( GYRO_RAM_GYRO_Switch , UlGyroSw ); + +} + +//******************************************************************************** +// Function Name : CrosstalkCalculation +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void CrosstalkCalculation( void ) +{ + UINT16 tblC[5]; + UINT8 tempC[10]; + UINT8 i,n,cnt; + + ReadE2Prom( EEPROM_Calibration_Status_MSB, &cnt ); +TRACE("E2prom Read 0x19 = %02x & %02x \n", cnt , (UINT8)(MIXI_CALB_FLG>>8) ); + if( cnt & (UINT8)(MIXI_CALB_FLG>>8) ){ + return; + } + + BurstReadE2Prom( EEPROM_CROSSTALK_XX_LSB , tempC, 10 ); + +TRACE("\n E2prom CROSS TALK Read \n" ); +TRACE(" %02xh %02xh %02xh %02xh %02xh %02xh %02xh %02xh \n",tempC[0],tempC[1],tempC[2],tempC[3],tempC[4],tempC[5],tempC[6],tempC[7]) ; +TRACE(" %02xh %02xh \n",tempC[8],tempC[9]) ; + + /****** Cross talk ******/ + for( i=0 , n=0 ; n<5 ; n++ ){ + tblC[n] = tempC[i] + (tempC[i+1]<<8); + i += 2; + } +TRACE("[XX] %04xh [XY]%04xh [SFT]%02xh\n",tblC[0],tblC[1],(unsigned char)(tblC[4]>>0)) ; +TRACE("[YY] %04xh [YX]%04xh [SFT]%02xh\n",tblC[2],tblC[3],(unsigned char)(tblC[4]>>8)) ; + RamWrite32A( HF_hx45x , (UINT32)(tblC[0]<<16)); + RamWrite32A( HF_hx45y , (UINT32)(tblC[1]<<16)); + RamWrite32A( HF_hy45y , (UINT32)(tblC[2]<<16)); + RamWrite32A( HF_hy45x , (UINT32)(tblC[3]<<16)); + RamWrite32A( HF_ShiftX , (UINT32)(tblC[4])); + +} + +//******************************************************************************** +// Function Name : SetOpticalOffset +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void SetOpticalOffset( void ) +{ + UINT16 tblC[2]; + UINT8 tempC[4]; + UINT8 i,n,cnt; + + ReadE2Prom( EEPROM_Calibration_Status_MSB, &cnt ); +TRACE("E2prom Read 0x19 = %02x & %02x \n", cnt , (UINT8)(HALL_CALB_FLG>>8) ); + if( cnt & (UINT8)(HALL_CALB_FLG>>8) ){ + return; + } + + BurstReadE2Prom( EEPROM_Optical_LensOffsetX_LSB , tempC, 4 ); + +TRACE("\n EEPROM_Optical_LensOffset Read \n" ); +TRACE(" %02xh %02xh %02xh %02xh \n",tempC[0],tempC[1],tempC[2],tempC[3]) ; + + /****** Cross talk ******/ + for( i=0 , n=0 ; n<2 ; n++ ){ + tblC[n] = tempC[i] + (tempC[i+1]<<8); + i += 2; + } + + if( tblC[ 0 ] == 0xFFFF ) { + tblC[ 0 ] = 0 ; + } + + if( tblC[ 1 ] == 0xFFFF ) { + tblC[ 1 ] = 0 ; + } + +TRACE("[XX] %04xh [XY]%04xh \n", tblC[0], tblC[1]) ; + RamWrite32A( Optical_Offset_X , (UINT32)(tblC[0]<<16)); + RamWrite32A( Optical_Offset_Y , (UINT32)(tblC[1]<<16)); + +} + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Calibration_SO2821.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Calibration_SO2821.h new file mode 100755 index 0000000000000000000000000000000000000000..08a9c8cd9d0fe5229e36a0037132b699fbdb1470 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Calibration_SO2821.h @@ -0,0 +1,178 @@ +//******************************************************************************** +// << LC898124 Evaluation Soft>> +// Program Name : LC898124EP3_Calibration_SO2821.h +// Explanation : LC898124 calibration parameters +// Design : K.abe +// History : First edition +//******************************************************************************** + +// Version Name : 00-00-0000 + +// for "SOXXXX" + +//******************************************************************************** +// defines +//******************************************************************************** +#define XY_BIAS (0x80000000 ) +#define XY_OFST (0x10000000 ) + +#ifdef HALLADJ_FULLCURRENT + #define MARGIN (0x0400 ) // Margin + #define BIAS_RANGE_XY (0x6400 ) // 40% SO2821 + #define SINE_OFFSET (0x00074528 ) /* Freq * 80000000h / 18.0288kHz : 4Hz */ + #define SINE_GAIN (0x7FFFFFFF ) /*“ü—ÍSine”g‚ÌÅ‘å“d—¬*/ +#else //HALLADJ_FULLCURRENT + #define MARGIN (0x1000 ) // VDD-Margin,GND-MARGIN + #define BIAS_RANGE_XY (0x8CCC ) // 55% + #define SINE_OFFSET (0x00074528 ) /* Freq * 80000000h / 18.0288kHz : 4Hz */ + #define SINE_GAIN (0x4D780000 ) /*“ü—ÍSine”g‚ÌÅ‘å“d—¬ 115mA (115mA*7fff/190mA) 190mA(min) */ + + +#if 0 + #define MARGIN_F (0x0300 ) // Margin + #define BIAS_RANGE_XY_F (0xB332 ) // 70% + #define SINE_OFFSET_F (0x00122CE4 ) /* Freq * 80000000h / 18.0288kHz : 10Hz */ + #define SINE_GAIN_F (0x7FFFFFFF ) /*“ü—ÍSine”g‚ÌÅ‘å“d—¬*/ +#endif + + +#endif //HALLADJ_FULLCURRENT + +#define ADJMARG (0x0300 ) // Margin +#define DECRE_CAL (0x0100 ) // decrease value + +#define SXGAIN_LOP (0x30000000 ) // 0.375000 +#define SYGAIN_LOP (0x30000000 ) // 0.375000 + +#define LOOP_NUM (2508 ) // 18.0288kHz/0.130kHz*16times +#define LOOP_FREQ (0x00D10422 ) // Freq * 80000000h / Fs +#define LOOP_GAIN (0x09249249 ) // -22.92dB + +#define LOOP_MAX_X (SXGAIN_LOP << 1) // x2 +#define LOOP_MIN_X (SXGAIN_LOP >> 1) // x0.5 +#define LOOP_MAX_Y (SYGAIN_LOP << 1) // x2 +#define LOOP_MIN_Y (SYGAIN_LOP >> 1) // x0.5 + +#define GAIN_GAP (1000) // 20*log(1000/1000)=0dB + +#define AF_DrvDir 0x01 // AF Drive output signal 0:Pos 1:Neg +#define AF_RRMD1_TM 0x4200 // to Macro RRMD1 +#define AF_RRMD1_TI 0x4400 // to Infini RRMD1 +#define AF_Ft 0x00D9 /* Ft fs/Freq */ + +#define ACT_MAX_DRIVE_X 0x7FFFFFFF +#define ACT_MAX_DRIVE_Y 0x7FFFFFFF +#define ACT_MIN_DRIVE_X 0xD0000000 +#define ACT_MIN_DRIVE_Y 0xC0000000 + +#define MAGNETIC_OFFSET_X 0x0890 +#define MAGNETIC_OFFSET_Y 0x0900 + +#define Xch_Hall_MAX 4 // 4% +#define Ych_Hall_MAX 3 // 3% +#define Xch_Hall_MIN 0 // 0% +#define Ych_Hall_MIN 0 // 0% + +//******************************************************************************** +// structure for calibration +//******************************************************************************** + const ADJ_HALL SO2821_HallCalParameter = { +/* BiasInit */ XY_BIAS, +/* OffsetInit */ XY_OFST, +/* OffsetMargin */ MARGIN, +/* TargetRange */ BIAS_RANGE_XY, +/* TargetMax */ (BIAS_RANGE_XY + ADJMARG), +/* TargetMin */ (BIAS_RANGE_XY - ADJMARG), +/* SinNum */ (4500), // 18.0288/0.004 > x +/* SinFreq */ SINE_OFFSET, +/* SinGain */ SINE_GAIN, +/* DecrementStep */ DECRE_CAL, +/* ActMaxDrive */ ACT_MAX_DRIVE_X, +/* ActMaxDrive */ ACT_MAX_DRIVE_Y, +/* ActMinDrive */ ACT_MIN_DRIVE_X, +/* ActMinDrive */ ACT_MIN_DRIVE_Y, +/* MagneticOff */ MAGNETIC_OFFSET_X, +/* MagneticOff */ MAGNETIC_OFFSET_Y, +/* HallMAX_X */ Xch_Hall_MAX, +/* HallMAX_Y */ Ych_Hall_MAX, +/* HallMIN_X */ Xch_Hall_MIN, +/* HallMIN_Y */ Ych_Hall_MIN, +}; // + +#if 0 + const ADJ_HALL SO2821_HallCalParameter_F = { +/* BiasInit */ XY_BIAS, +/* OffsetInit */ XY_OFST, +/* OffsetMargin */ MARGIN_F, +/* TargetRange */ BIAS_RANGE_XY_F, +/* TargetMax */ (BIAS_RANGE_XY_F + ADJMARG), +/* TargetMin */ (BIAS_RANGE_XY_F - ADJMARG), +/* SinNum */ (1800), // 18.0288/0.01 > x +/* SinFreq */ SINE_OFFSET_F, +/* SinGain */ SINE_GAIN_F, +/* DecrementStep */ DECRE_CAL, +}; // +#endif + +const ADJ_LOPGAN SO2821_LoopGainParameter = { +/* Hxgain */ SXGAIN_LOP, +/* Hygain */ SYGAIN_LOP, +/* NoiseNum */ LOOP_NUM, +/* NoiseFreq */ LOOP_FREQ, +/* NoiseGain */ LOOP_GAIN, +/* Gap */ GAIN_GAP, +/* XJudgeHigh */ LOOP_MAX_X, +/* XJudgeLow */ LOOP_MIN_X, +/* YJudgeHigh */ LOOP_MAX_Y, +/* YJudgeLow */ LOOP_MIN_Y, +}; // + + const AF_PARA SO2821_OpenAfParameter = { +/* DriveDir*/ AF_DrvDir, +/* RRMD1 to Mcr*/ AF_RRMD1_TM, +/* RRMD1 to Inf*/ AF_RRMD1_TI, +/* resonance frq*/ AF_Ft, +}; // + +#undef OFFSET_DIV +#undef IME_OUT +#undef BIAS_HLMT +#undef BIAS_LLMT +#undef XY_BIAS +#undef XY_OFST +#undef MARGIN +#undef BIAS_RANGE_XY +#undef SINE_OFFSET +#undef SINE_GAIN +#undef ADJMARG +#undef DECRE_CAL + +#undef SXGAIN_LOP +#undef SYGAIN_LOP +#undef LOOP_NUM +#undef LOOP_FREQ +#undef LOOP_GAIN +#undef GAIN_GAP +#undef LOOP_MAX_X +#undef LOOP_MIN_X +#undef LOOP_MAX_Y +#undef LOOP_MIN_Y + +#undef AF_DrvDir +#undef AF_RRMD1_TM +#undef AF_RRMD1_TI +#undef AF_Ft + +#undef ACT_MAX_DRIVE_X +#undef ACT_MAX_DRIVE_Y +#undef ACT_MIN_DRIVE_X +#undef ACT_MIN_DRIVE_Y + +#undef MAGNETIC_OFFSET_X +#undef MAGNETIC_OFFSET_Y + +#undef Xch_Hall_MAX +#undef Xch_Hall_MIN +#undef Ych_Hall_MAX +#undef Ych_Hall_MIN + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Code_2_1_0_3_2_0.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Code_2_1_0_3_2_0.h new file mode 100755 index 0000000000000000000000000000000000000000..5a70068b20498abba0a7967b995d27f64ab199cb --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Code_2_1_0_3_2_0.h @@ -0,0 +1,2327 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/* Time Stamp : 2020/03/13 16:30:19 */ + +/* VERNUM [011b0202] [02010003] */ + +/* #define SEL_MODEL 2 */ +/* #define SELECT_VENDOR 1 */ +/* #define SELECT_ACT 0 */ +/* #define SELECT_GYRO 3 */ +/* #define MASTER_SLAVE 2 */ +/* #define FRA_ENABLE 0 */ + +#define CHECKSUM_COMMAND_DMA_2_1_0_3_2_0 0x00041834 +#define CHECKSUM_COMMAND_DMB_2_1_0_3_2_0 0x0004186e + +#define LC898124EP3_DMA_ByteSize_2_1_0_3_2_0 0x0054 +#define LC898124EP3_DMA_CheckSum_2_1_0_3_2_0 0x0800650D + +#define LC898124EP3_DMB_ByteSize_2_1_0_3_2_0 0x0498 +#define LC898124EP3_DMB_CheckSum_2_1_0_3_2_0 0xE8239C30 + +#define LC898124EP3_PMCheckSum_2_1_0_3_2_0 0x000B9138 +#define LC898124EP3_PMSize_2_1_0_3_2_0 1982 + +const unsigned char LC898124EP3_DM_2_1_0_3_2_0[] = { +0x20, 0xC0, 0x00, 0x80, 0x06, 0x30, +0x20, 0xC4, 0x00, 0x80, 0x06, 0x34, +0x20, 0xC8, 0x00, 0x80, 0x06, 0x38, +0x20, 0xCC, 0x00, 0x80, 0x06, 0x3c, +0x20, 0xD0, 0x00, 0x80, 0x06, 0x40, +0x20, 0xD4, 0x00, 0x80, 0x06, 0x44, +0x20, 0xD8, 0x00, 0x80, 0x06, 0x48, +0x20, 0xDC, 0x00, 0x80, 0x06, 0x4c, +0x20, 0xE0, 0x00, 0x80, 0x06, 0x4c, +0x20, 0xE4, 0x00, 0x80, 0x06, 0x50, +0x20, 0xE8, 0x00, 0x80, 0x06, 0x54, +0x20, 0xEC, 0x00, 0x80, 0x06, 0x58, +0x20, 0xF0, 0x00, 0x80, 0x06, 0xec, +0x20, 0xF4, 0x00, 0x80, 0x06, 0x5c, +0x20, 0xF8, 0x00, 0x80, 0x06, 0x5c, +0x20, 0xFC, 0x00, 0x80, 0x06, 0x2c, +0x27, 0x68, 0x00, 0x00, 0x00, 0x05, +0x27, 0x6C, 0x80, 0x00, 0x00, 0x01, +0x27, 0x70, 0x7f, 0xff, 0xff, 0xff, +0x27, 0x74, 0x80, 0x00, 0x00, 0x01, +0x27, 0x78, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0x00, 0x01, 0x1b, 0x02, 0x02, +0xA0, 0x04, 0x02, 0x01, 0x00, 0x03, +0xA0, 0x90, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0x94, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0x98, 0x80, 0x00, 0x00, 0x01, +0xA0, 0xA4, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xAC, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xB0, 0x02, 0x07, 0x56, 0x79, +0xA0, 0xB4, 0x8a, 0xdf, 0xbd, 0x3f, +0xA0, 0xB8, 0x6b, 0x7b, 0xa9, 0x6d, +0xA0, 0xBC, 0x76, 0x5b, 0x66, 0xab, +0xA0, 0xC0, 0x84, 0xbd, 0xe2, 0xd3, +0xA0, 0xC4, 0x77, 0x60, 0xef, 0x39, +0xA0, 0xC8, 0x7c, 0x1e, 0xd2, 0x0d, +0xA0, 0xD8, 0x5a, 0x9d, 0xf7, 0xab, +0xA0, 0xDC, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xE4, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xE8, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xEC, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xF0, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xF4, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x00, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x14, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x18, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0x1C, 0xca, 0x3d, 0x97, 0xb5, +0xA1, 0x20, 0x00, 0x39, 0x1a, 0x59, +0xA1, 0x24, 0x75, 0x50, 0x33, 0x99, +0xA1, 0x28, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0x2C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x30, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x34, 0x80, 0x00, 0x00, 0x01, +0xA1, 0x40, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x48, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x4C, 0x02, 0x07, 0x56, 0x79, +0xA1, 0x50, 0x8a, 0xdf, 0xbd, 0x3f, +0xA1, 0x54, 0x6b, 0x7b, 0xa9, 0x6d, +0xA1, 0x58, 0x76, 0x5b, 0x66, 0xab, +0xA1, 0x5C, 0x84, 0xbd, 0xe2, 0xd3, +0xA1, 0x60, 0x77, 0x60, 0xef, 0x39, +0xA1, 0x64, 0x7c, 0x1e, 0xd2, 0x0d, +0xA1, 0x74, 0x5a, 0x9d, 0xf7, 0xab, +0xA1, 0x78, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x7C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x80, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x84, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x88, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x8C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x90, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x9C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xB0, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xB4, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0xB8, 0xca, 0x3d, 0x97, 0xb5, +0xA1, 0xBC, 0x00, 0x39, 0x1a, 0x59, +0xA1, 0xC0, 0x75, 0x50, 0x33, 0x99, +0xA1, 0xC4, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0xC8, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xCC, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xD0, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xD4, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xD8, 0x38, 0x00, 0x00, 0x00, +0xA1, 0xDC, 0xc8, 0x00, 0x00, 0x00, +0xA1, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xE4, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xE8, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xEC, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xF0, 0x38, 0x00, 0x00, 0x00, +0xA1, 0xF4, 0xc8, 0x00, 0x00, 0x00, +0xA1, 0xF8, 0x03, 0x05, 0x00, 0x01, +0xA1, 0xFC, 0x00, 0x01, 0x01, 0x00, +0xA2, 0x00, 0x01, 0x00, 0x03, 0x05, +0xA2, 0x04, 0x00, 0x12, 0x74, 0x74, +0xA2, 0x14, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0x1C, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0x6C, 0x00, 0x07, 0xff, 0xff, +0xA2, 0x70, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0x78, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0x7C, 0x47, 0xae, 0xfe, 0x3f, +0xA2, 0x80, 0xc5, 0x50, 0x45, 0x8b, +0xA2, 0x84, 0x6f, 0x51, 0xae, 0x5d, +0xA2, 0x88, 0x3d, 0x41, 0xd9, 0x4f, +0xA2, 0x8C, 0xad, 0x72, 0xde, 0x6b, +0xA2, 0x90, 0x7f, 0xf6, 0xdd, 0x87, +0xA2, 0x94, 0x52, 0x96, 0x44, 0x0d, +0xA2, 0x98, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0xA0, 0x7f, 0xfe, 0x20, 0x00, +0xA2, 0xA4, 0x0c, 0xdc, 0x61, 0x39, +0xA2, 0xA8, 0x00, 0xe2, 0xd1, 0x41, +0xA2, 0xAC, 0x7e, 0x3a, 0x5d, 0x7d, +0xA2, 0xB0, 0x00, 0xe2, 0xd1, 0x41, +0xA2, 0xB4, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0xB8, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0xBC, 0x5f, 0xfc, 0x88, 0x91, +0xA2, 0xC0, 0x16, 0x22, 0xf6, 0x0f, +0xA2, 0xC4, 0x53, 0xba, 0x13, 0xe3, +0xA2, 0xC8, 0x16, 0x22, 0xf6, 0x0f, +0xA2, 0xCC, 0x3f, 0xff, 0xff, 0xff, +0xA2, 0xD0, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0xD8, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0xDC, 0x47, 0xae, 0xfe, 0x3f, +0xA2, 0xE0, 0xc5, 0x50, 0x45, 0x8b, +0xA2, 0xE4, 0x6f, 0x51, 0xae, 0x5d, +0xA2, 0xE8, 0x3d, 0x41, 0xd9, 0x4f, +0xA2, 0xEC, 0xad, 0x72, 0xde, 0x6b, +0xA2, 0xF0, 0x7f, 0xf6, 0xdd, 0x87, +0xA2, 0xF4, 0x52, 0x96, 0x44, 0x0d, +0xA2, 0xF8, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0x00, 0x7f, 0xfe, 0x20, 0x00, +0xA3, 0x04, 0x0c, 0xdc, 0x61, 0x39, +0xA3, 0x08, 0x00, 0xe2, 0xd1, 0x41, +0xA3, 0x0C, 0x7e, 0x3a, 0x5d, 0x7d, +0xA3, 0x10, 0x00, 0xe2, 0xd1, 0x41, +0xA3, 0x14, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0x18, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0x1C, 0x5f, 0xfc, 0x88, 0x91, +0xA3, 0x20, 0x16, 0x22, 0xf6, 0x0f, +0xA3, 0x24, 0x53, 0xba, 0x13, 0xe3, +0xA3, 0x28, 0x16, 0x22, 0xf6, 0x0f, +0xA3, 0x2C, 0x3f, 0xff, 0xff, 0xff, +0xA3, 0x38, 0x01, 0x00, 0x02, 0x01, +0xA3, 0x3C, 0x01, 0x00, 0x02, 0x01, +0xA3, 0x40, 0x00, 0x0b, 0x6a, 0x7b, +0xA3, 0x44, 0x7f, 0xe9, 0x2b, 0x09, +0xA3, 0x48, 0x00, 0x0b, 0x6a, 0x7b, +0xA3, 0x60, 0x28, 0x00, 0x00, 0x00, +0xA3, 0x64, 0x0c, 0x99, 0x97, 0x19, +0xA3, 0x68, 0x0a, 0xcc, 0xca, 0xa8, +0xA3, 0x6C, 0x0e, 0x66, 0x63, 0x8a, +0xA3, 0x70, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0x74, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0xF4, 0x00, 0x64, 0x00, 0x05, +0xA4, 0x0C, 0x00, 0x00, 0x02, 0xd8, +0xA4, 0x24, 0x00, 0x00, 0x02, 0xfc, +0xA4, 0x34, 0x80, 0x00, 0x00, 0x01, +0xA4, 0x38, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0x3C, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0x44, 0x00, 0x30, 0x77, 0xae, +0xA4, 0x48, 0x1c, 0x66, 0x20, 0x7e, +0xA4, 0x4C, 0x00, 0x00, 0x00, 0x1e, +0xA4, 0x50, 0x00, 0x00, 0x00, 0x01, +0xA4, 0x54, 0x00, 0x04, 0x00, 0x00, +0xA4, 0x58, 0x00, 0x00, 0x00, 0x80, +0xA4, 0x60, 0x00, 0x10, 0x00, 0x00, +0xA4, 0x64, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0x68, 0x00, 0x00, 0x40, 0x00, +0xA4, 0x6C, 0x00, 0x10, 0x00, 0x00, +0xA4, 0x70, 0x00, 0x00, 0x03, 0xe8, +0xA4, 0x74, 0x00, 0x00, 0x00, 0x04, +0xA4, 0x78, 0x00, 0x00, 0x32, 0x00, +0xA4, 0x7C, 0x0a, 0x3d, 0x00, 0x00, +0xA4, 0x80, 0x00, 0x00, 0x06, 0x29, +0xA4, 0x84, 0x00, 0x30, 0x00, 0x00, +0xA4, 0x88, 0x28, 0x00, 0x00, 0x00, +0xA4, 0x8C, 0x00, 0x00, 0x80, 0x00, +0xA4, 0x98, 0x00, 0x04, 0x00, 0x00, +0xA4, 0x9C, 0x00, 0x40, 0x00, 0x00, +0xA4, 0xA0, 0x7f, 0xfe, 0x20, 0x00, +0xA4, 0xA4, 0x00, 0x07, 0x69, 0x8a, +0xA4, 0xA8, 0x54, 0x91, 0x9a, 0x57, +0xA4, 0xAC, 0x00, 0x00, 0x00, 0xec, +0xA4, 0xB8, 0x00, 0x02, 0x6c, 0x62, +0xA4, 0xBC, 0xad, 0x99, 0x86, 0xfc, +0xA4, 0xC0, 0x7c, 0x7a, 0xf7, 0x9f, +0xA4, 0xC4, 0x55, 0xeb, 0x81, 0x65, +0xA4, 0xC8, 0x00, 0x00, 0x91, 0x9e, +0xA4, 0xCC, 0x00, 0x00, 0x06, 0x99, +0xA4, 0xD0, 0xad, 0x72, 0xde, 0x6b, +0xA4, 0xD4, 0x52, 0x96, 0x44, 0x0d, +0xA4, 0xD8, 0x00, 0x00, 0x01, 0x14, +0xA4, 0xDC, 0x00, 0x00, 0x08, 0xcd, +0xA4, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0xE8, 0x28, 0x00, 0x00, 0x00, +0xA4, 0xEC, 0x61, 0x86, 0x18, 0x60, +0xA4, 0xF0, 0x00, 0x00, 0x0a, 0x30, +0xA4, 0xF8, 0x02, 0x60, 0x00, 0x00, +0xA4, 0xFC, 0x00, 0xbe, 0x00, 0x00, +0xA5, 0x00, 0x00, 0xe6, 0x00, 0x00, +0xA5, 0x04, 0x01, 0x1d, 0x00, 0x00, +0xA5, 0x88, 0x5f, 0x37, 0x59, 0xdf, +0xA5, 0x8C, 0x5f, 0xff, 0xff, 0xff, +0xA5, 0x9C, 0x00, 0xb4, 0x00, 0xb4, +0xA5, 0xA0, 0x06, 0x00, 0x00, 0x00, +0xA5, 0xEC, 0x00, 0x00, 0x08, 0xe0, +0xA5, 0xF0, 0x00, 0x04, 0x18, 0xac, +0xA5, 0xF4, 0x00, 0x00, 0x0b, 0xc2, +0xA5, 0xF8, 0x00, 0x04, 0x18, 0xf4, +0xA5, 0xFC, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x00, 0x00, 0x04, 0x1a, 0x80, +0xA6, 0x04, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x08, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x0C, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x10, 0x00, 0x00, 0x09, 0x9e, +0xA6, 0x14, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x18, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x1C, 0x00, 0x00, 0x09, 0x7c, +0xA6, 0x20, 0x00, 0x04, 0x1b, 0xbe, +0xA6, 0x24, 0x00, 0x04, 0x1b, 0xbe, +0xA6, 0x28, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x78, 0x47, 0xae, 0xfe, 0x3f, +0xA6, 0xBC, 0x16, 0x22, 0xf6, 0x0f, +0xA6, 0xC0, 0x53, 0xba, 0x13, 0xe3, +0xA6, 0xC4, 0x16, 0x22, 0xf6, 0x0f, +0xA6, 0xDC, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xE4, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xE8, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xF0, 0x82, 0x35, 0xee, 0x09, +0xA6, 0xF4, 0x7d, 0x6c, 0xb0, 0xcd, +0xA6, 0xF8, 0x7f, 0xa2, 0x9e, 0xd5, +0xA6, 0xFC, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x00, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x04, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x08, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x0C, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x10, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x14, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x18, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x1C, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x20, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x24, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x28, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x2C, 0x00, 0x74, 0x52, 0x6f, +0xA7, 0x30, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x34, 0x3a, 0x99, 0x29, 0xc5, +0xA7, 0x38, 0x00, 0x00, 0x00, 0x02, +0xA7, 0x3C, 0x01, 0xff, 0xff, 0xff, +0xA7, 0x4C, 0x01, 0xff, 0xff, 0xff, +0xA7, 0x5C, 0x01, 0xff, 0xff, 0xff, +0xA7, 0x60, 0x03, 0xc5, 0x18, 0xe6, +0xA7, 0x64, 0x00, 0x00, 0x1a, 0x68, +0xA7, 0x68, 0x00, 0x13, 0x9d, 0x01, +0xA7, 0x6C, 0x00, 0x0f, 0xff, 0xff, +0xA7, 0x7C, 0x13, 0xff, 0xff, 0xff, +0xA7, 0x80, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x84, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x8C, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x90, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x98, 0x00, 0x00, 0x00, 0xe1, +0xA7, 0x9C, 0x00, 0x00, 0xf0, 0xe3, +0xA7, 0xA0, 0x00, 0x7d, 0x86, 0x6e, +0xA7, 0xAC, 0x00, 0x00, 0x00, 0x04, +0xA7, 0xB0, 0x00, 0x08, 0xbe, 0x1d, +0xA7, 0xB4, 0x00, 0x00, 0x27, 0x10, +0xA7, 0xB8, 0x00, 0x00, 0x00, 0x0a, +0xA7, 0xF8, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0xFC, 0x04, 0xcc, 0xcc, 0xd0, +0xA8, 0x00, 0x7f, 0xff, 0xff, 0xff, +0xA8, 0x04, 0x80, 0x00, 0x00, 0x01, +0xA8, 0x10, 0x7f, 0xff, 0xff, 0xff, +0xA8, 0x14, 0x05, 0x1e, 0xb8, 0x50, +0xA8, 0x18, 0x7f, 0xff, 0xff, 0xff, +0xA8, 0x1C, 0x80, 0x00, 0x00, 0x01, +0xA8, 0x20, 0x00, 0x05, 0x24, 0x28, +0xA8, 0x24, 0x7f, 0xf5, 0xb7, 0xaf, +0xA8, 0x28, 0x00, 0x05, 0x24, 0x28, +0xA8, 0x2C, 0x33, 0x33, 0x33, 0x40, +0xA8, 0x30, 0x19, 0x99, 0x99, 0xa0, +0xA8, 0x38, 0xe0, 0x00, 0x00, 0x01, +0xA8, 0x40, 0x26, 0x66, 0x66, 0x80, +0xA8, 0x44, 0x33, 0x33, 0x33, 0x40, +0xA8, 0x4C, 0xe0, 0x00, 0x00, 0x01, +0xA8, 0x54, 0x80, 0x02, 0x92, 0x21, +0xA8, 0x58, 0x7f, 0xfa, 0xdb, 0xbd, +0xA8, 0x5C, 0x7f, 0xfd, 0x6d, 0xdf, +0xA8, 0x60, 0x00, 0x40, 0x00, 0x00, +0xA9, 0x18, 0x01, 0x00, 0x00, 0x00, +0xA9, 0x1C, 0x00, 0x16, 0xd2, 0xed, +0xA9, 0x20, 0x7f, 0xd2, 0x5a, 0x25, +0xA9, 0x24, 0x00, 0x16, 0xd2, 0xed, +0xA9, 0x28, 0x00, 0x06, 0x00, 0x0a, +0xA9, 0x3C, 0x77, 0x0a, 0x3d, 0x80, +0xA9, 0x40, 0x04, 0x00, 0x00, 0x00, +0xA9, 0x44, 0x7f, 0xfe, 0x20, 0x00, +0xA9, 0x48, 0x7f, 0xb0, 0x00, 0x00, +0xA9, 0x4C, 0x00, 0x00, 0x20, 0x00, +0xA9, 0x50, 0x03, 0x00, 0x00, 0x00, +0xA9, 0x54, 0x7f, 0xf4, 0x00, 0x00, +0xA9, 0x60, 0x00, 0x48, 0x00, 0x00, +0xA9, 0x64, 0x7f, 0xf0, 0x00, 0x00, +0xA9, 0x68, 0x00, 0x00, 0x04, 0x00, +0xA9, 0x6C, 0x1f, 0xff, 0xff, 0xff, +0xA9, 0x70, 0x7f, 0x00, 0x00, 0x00, +0xA9, 0x74, 0x00, 0x00, 0x02, 0x8c, +0xA9, 0x7C, 0x0c, 0xdc, 0x61, 0x39, +0xA9, 0x80, 0x0a, 0x49, 0xe7, 0x60, +0xA9, 0x84, 0x00, 0xa0, 0x00, 0x00, +0xA9, 0xCC, 0x01, 0x20, 0x00, 0x00, +0xA9, 0xD4, 0x00, 0x0c, 0x00, 0x00, +0xA9, 0xD8, 0x00, 0x00, 0x07, 0x0a, +0xA9, 0xE4, 0xbd, 0x2b, 0x06, 0x35, +0xA9, 0xE8, 0x7f, 0xa4, 0xc4, 0x91, +0xA9, 0xEC, 0x43, 0x30, 0x35, 0x39, +0xA9, 0xF0, 0x00, 0x00, 0x00, 0x90, +0xA9, 0xF8, 0x00, 0x00, 0x00, 0x90, +}; + +const unsigned char LC898124EP3_PM_2_1_0_3_2_0[] = { +0x64, 0x00, 0x00, 0x02, 0x07, +0x64, 0x00, 0x00, 0xbe, 0xa7, +0x64, 0x00, 0x40, 0x1d, 0x87, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x64, 0x00, 0x00, 0xc2, 0x27, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x64, 0x00, 0x40, 0x23, 0x47, +0x64, 0x00, 0x40, 0x27, 0x87, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, 0x00, +0x66, 0x00, 0x00, 0x88, 0x68, +0x40, 0x00, 0x02, 0xbf, 0xc0, +0x5c, 0x00, 0x62, 0xfe, 0x22, +0x6c, 0x70, 0x28, 0x06, 0x48, +0x68, 0x34, 0x00, 0x1b, 0x20, +0x68, 0x03, 0xf9, 0xff, 0xc9, +0x5c, 0x81, 0x00, 0x40, 0x0a, +0x54, 0x4b, 0xaa, 0xc0, 0x61, +0x5c, 0x10, 0xf0, 0x40, 0x49, +0x5c, 0x02, 0xf9, 0xc1, 0x00, +0x5c, 0x00, 0x68, 0x00, 0x48, +0x80, 0x04, 0x88, 0x02, 0xc8, +0x5c, 0x00, 0xb0, 0x02, 0x4a, +0xb0, 0x62, 0x08, 0x40, 0x50, +0xa0, 0x22, 0x08, 0x40, 0x00, +0x68, 0x00, 0x06, 0x00, 0x02, +0x54, 0x84, 0x13, 0x1d, 0xf0, +0x5c, 0x0d, 0x90, 0x00, 0xd2, +0x6c, 0x68, 0x08, 0x08, 0x4b, +0x5c, 0x0e, 0x38, 0x40, 0x50, +0xa0, 0x08, 0x0b, 0x08, 0x08, +0x68, 0x34, 0x08, 0x4a, 0x24, +0x80, 0x05, 0x08, 0x40, 0x50, +0xa2, 0x02, 0x08, 0x60, 0x48, +0x80, 0x04, 0x98, 0x00, 0x4a, +0x68, 0x00, 0x00, 0x2b, 0x24, +0xac, 0x7e, 0x08, 0x00, 0x4a, +0x68, 0x20, 0x01, 0x4f, 0x21, +0x86, 0x00, 0x85, 0x20, 0xf2, +0x2c, 0x58, 0x08, 0x02, 0x4a, +0xac, 0x40, 0x08, 0x48, 0x0b, +0x52, 0x45, 0xf3, 0x06, 0x07, +0x86, 0x04, 0x88, 0x02, 0x4b, +0x84, 0x84, 0xa8, 0x40, 0x4b, +0xb0, 0x01, 0xc6, 0x60, 0x04, +0x03, 0x66, 0x8a, 0x40, 0xc0, +0x5c, 0x81, 0x02, 0x40, 0xc0, +0x94, 0x02, 0xdb, 0x07, 0xfc, +0x30, 0x12, 0x8b, 0xc1, 0x08, +0x68, 0x20, 0x00, 0x1b, 0x24, +0x23, 0x4e, 0xd8, 0x20, 0x49, +0x88, 0x06, 0x46, 0x60, 0x04, +0x03, 0x66, 0x85, 0xc0, 0x06, +0xb0, 0x03, 0xca, 0x40, 0xc0, +0x94, 0x02, 0xd5, 0x1a, 0x76, +0x88, 0x02, 0x0b, 0xc0, 0x6f, +0x40, 0x00, 0x00, 0x40, 0x49, +0x6c, 0x40, 0x00, 0x36, 0x7a, +0x40, 0x00, 0x00, 0x60, 0xfa, +0x66, 0x00, 0x40, 0x42, 0xa0, +0x6e, 0x00, 0x01, 0xae, 0x2d, +0x38, 0x11, 0xc2, 0x59, 0x28, +0xbc, 0x05, 0x06, 0x60, 0x04, +0x02, 0xdc, 0x0b, 0xc0, 0xcf, +0x5c, 0x00, 0x6b, 0x80, 0x00, +0x66, 0x00, 0x40, 0x2d, 0xc0, +0x6e, 0x00, 0x01, 0xae, 0x2c, +0x5c, 0x08, 0xf3, 0x00, 0x0d, +0x52, 0x0d, 0x03, 0x80, 0x00, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x6c, 0x40, 0x03, 0x1e, 0x49, +0x6c, 0x40, 0x03, 0x1a, 0x49, +0x66, 0x00, 0x00, 0x4b, 0x00, +0x66, 0x00, 0x00, 0xf5, 0x00, +0x6e, 0x00, 0x00, 0x8c, 0xad, +0x38, 0x1b, 0xc3, 0x01, 0x28, +0x40, 0x00, 0x03, 0xc0, 0x40, +0x68, 0x00, 0x3f, 0xff, 0xc9, +0x6e, 0x40, 0x00, 0x08, 0x75, +0x66, 0x00, 0x41, 0x38, 0x40, +0x6e, 0x40, 0x00, 0x08, 0x3d, +0x68, 0x00, 0x01, 0x00, 0x08, +0x28, 0x92, 0xc3, 0x20, 0x20, +0xbc, 0x09, 0x93, 0x81, 0x1d, +0x6e, 0x00, 0x01, 0xae, 0x2c, +0x24, 0x16, 0x06, 0xe0, 0x00, +0x1a, 0xe6, 0x06, 0x60, 0x00, +0x09, 0xbc, 0x83, 0x80, 0x04, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x66, 0x00, 0x41, 0x46, 0x80, +0x66, 0x00, 0x00, 0xc5, 0x60, +0x68, 0x00, 0x01, 0x30, 0x20, +0x6c, 0x40, 0x02, 0x4e, 0x08, +0x6c, 0x40, 0x02, 0x2a, 0x48, +0x5c, 0x00, 0x73, 0x01, 0x6d, +0x6c, 0x40, 0x01, 0x5a, 0x7a, +0x6c, 0x40, 0x01, 0x8a, 0x7a, +0x5c, 0x04, 0x21, 0x46, 0x66, +0x5c, 0x0d, 0xf8, 0x40, 0x49, +0x66, 0x00, 0x40, 0x2e, 0xe8, +0x5c, 0x1f, 0x6b, 0x03, 0x6e, +0x6c, 0x00, 0x00, 0x56, 0x09, +0x38, 0x1d, 0x62, 0x59, 0xa8, +0xbc, 0x05, 0x83, 0x81, 0xc4, +0x52, 0x49, 0x6b, 0x80, 0x00, +0x6c, 0x00, 0x00, 0x56, 0x49, +0x68, 0x00, 0x00, 0x65, 0x20, +0x6c, 0x00, 0x01, 0xb0, 0x60, +0x66, 0x00, 0x00, 0xca, 0xc0, +0x68, 0x00, 0x00, 0xe0, 0x20, +0x6c, 0x40, 0x04, 0xe6, 0x09, +0x39, 0x02, 0x08, 0x00, 0x49, +0x84, 0x0f, 0xa8, 0x40, 0x7a, +0x6c, 0x00, 0x00, 0x8e, 0x7a, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x66, 0x00, 0x41, 0x46, 0xe8, +0x5c, 0x01, 0x23, 0x80, 0x00, +0x68, 0x38, 0x08, 0x46, 0x20, +0x5c, 0x0e, 0xa2, 0xfa, 0xc0, +0x9c, 0x00, 0x08, 0x80, 0x60, +0xa0, 0x02, 0x08, 0x80, 0xe0, +0xa0, 0x02, 0x08, 0x81, 0x60, +0xa0, 0x02, 0x0a, 0x00, 0x20, +0x6c, 0x40, 0x03, 0x2a, 0x7a, +0x88, 0x1e, 0x0b, 0xc0, 0x4f, +0x5c, 0x00, 0xea, 0xc4, 0xc0, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x02, 0xc6, 0x0a, +0x32, 0xa3, 0x0b, 0xff, 0xa1, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x6c, 0x00, 0x02, 0xc6, 0x7a, +0xa0, 0x00, 0x48, 0x02, 0x0a, +0x25, 0x93, 0x0b, 0xc0, 0x89, +0x88, 0x26, 0x02, 0x49, 0x34, +0x82, 0x24, 0x86, 0x80, 0x00, +0x23, 0x82, 0x06, 0xc4, 0x00, +0x31, 0x84, 0x98, 0x60, 0x60, +0x38, 0x13, 0xc6, 0xe0, 0x00, +0x1a, 0xea, 0xd2, 0x59, 0x28, +0xbc, 0x39, 0x06, 0x80, 0x00, +0x06, 0x52, 0x09, 0x88, 0x08, +0x6c, 0x00, 0x01, 0xb0, 0x09, +0x30, 0x12, 0x86, 0x80, 0x00, +0x09, 0xa2, 0x0b, 0xc0, 0x88, +0x98, 0x80, 0x83, 0x01, 0x28, +0xbc, 0x2d, 0x16, 0x60, 0x00, +0x0c, 0xfc, 0x89, 0x8e, 0x88, +0x40, 0x00, 0x03, 0xc2, 0x87, +0x6c, 0x70, 0x10, 0x8c, 0x08, +0x5c, 0x08, 0x28, 0x80, 0x20, +0x52, 0x0b, 0x20, 0x80, 0xa4, +0x6c, 0x70, 0x10, 0x8c, 0x48, +0x5c, 0x81, 0x02, 0xfc, 0xc2, +0x5c, 0x87, 0x08, 0x40, 0x0a, +0x5c, 0x00, 0x58, 0x40, 0x88, +0x86, 0x08, 0x08, 0x81, 0x20, +0x88, 0x1a, 0x48, 0x40, 0x8b, +0x82, 0x00, 0x28, 0x21, 0x01, +0x68, 0x00, 0x01, 0x8e, 0x20, +0xac, 0x7e, 0x28, 0x02, 0xd0, +0x82, 0x15, 0x38, 0x40, 0xd2, +0x68, 0x00, 0x01, 0x7c, 0x21, +0x86, 0x00, 0x06, 0xc0, 0x00, +0x2f, 0x84, 0xa5, 0x24, 0xa2, +0x80, 0x04, 0xb8, 0x48, 0xc8, +0x84, 0x15, 0x18, 0x60, 0x49, +0x66, 0x00, 0x00, 0xc7, 0x80, +0x66, 0x00, 0x00, 0xc2, 0x40, +0x66, 0x00, 0x00, 0x6d, 0x80, +0x88, 0x22, 0x00, 0x00, 0x00, +0x84, 0x02, 0x0b, 0xa0, 0x80, +0x6c, 0x00, 0x00, 0xf0, 0x09, +0x6c, 0x00, 0x01, 0x1a, 0x08, +0x22, 0x86, 0xd6, 0x83, 0x40, +0x80, 0x02, 0x06, 0xc4, 0x00, +0x49, 0xa0, 0xa2, 0x28, 0x64, +0x6c, 0x68, 0x10, 0x00, 0x49, +0x59, 0x41, 0x80, 0x44, 0x48, +0xbc, 0x07, 0x06, 0xc0, 0x00, +0x1b, 0x02, 0x0b, 0xa0, 0x80, +0x6c, 0x00, 0x02, 0xea, 0x20, +0x40, 0x00, 0x03, 0xa0, 0x80, +0x66, 0x00, 0x41, 0xca, 0x40, +0x6c, 0x00, 0x02, 0x3c, 0x20, +0x40, 0x00, 0x03, 0xa0, 0x80, +0x68, 0x00, 0x01, 0x16, 0x20, +0x68, 0x20, 0x00, 0xf1, 0x24, +0x68, 0x00, 0x01, 0x1a, 0x21, +0x68, 0x20, 0x00, 0xf7, 0x25, +0x68, 0x00, 0x01, 0x00, 0x22, +0x66, 0x00, 0x40, 0x5d, 0x00, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x66, 0x00, 0x41, 0x48, 0x20, +0x46, 0x0e, 0x03, 0x80, 0x00, +0xbf, 0x74, 0xf3, 0x81, 0xd4, +0xab, 0xfc, 0x08, 0x82, 0x76, +0x66, 0x00, 0x00, 0x6c, 0x00, +0x68, 0x00, 0x00, 0xce, 0x20, +0x5c, 0x81, 0x01, 0x8e, 0x8a, +0x5c, 0x08, 0x20, 0x00, 0x01, +0x55, 0x01, 0xa8, 0x00, 0x03, +0x55, 0x01, 0x52, 0x00, 0xe1, +0x94, 0x82, 0x85, 0x2c, 0x80, +0x04, 0x00, 0xbb, 0xc0, 0x89, +0x55, 0x01, 0x62, 0x0c, 0x60, +0x68, 0x00, 0x00, 0xc4, 0x21, +0x00, 0x00, 0x08, 0x08, 0x08, +0x84, 0x88, 0x98, 0x48, 0x0a, +0x4b, 0x8b, 0x9b, 0x01, 0x0c, +0x52, 0xc8, 0x00, 0x00, 0x41, +0x57, 0x0f, 0x48, 0x00, 0x43, +0x5c, 0x82, 0x0b, 0xc0, 0x79, +0x5c, 0x00, 0x28, 0x02, 0xc1, +0x68, 0x00, 0x00, 0xc7, 0x21, +0x00, 0x00, 0x08, 0x48, 0x89, +0x84, 0x80, 0x23, 0x91, 0x82, +0x80, 0x00, 0x85, 0x40, 0x50, +0x00, 0x30, 0x85, 0x40, 0xb1, +0x18, 0x00, 0x96, 0xc4, 0x00, +0x13, 0xe0, 0x84, 0x42, 0x00, +0x18, 0x08, 0x96, 0xe4, 0x00, +0x19, 0xd2, 0x42, 0x01, 0x00, +0x6c, 0x40, 0x01, 0x6e, 0x0a, +0x6e, 0x40, 0x01, 0x9f, 0x24, +0x44, 0x30, 0x00, 0x00, 0x40, +0x20, 0x10, 0x06, 0xc4, 0x00, +0x33, 0xc0, 0x88, 0x01, 0x40, +0x68, 0x20, 0x01, 0x16, 0x21, +0x84, 0x00, 0x94, 0x42, 0x00, +0x04, 0x80, 0x96, 0xe4, 0x00, +0x48, 0xd2, 0x66, 0xc4, 0x00, +0x27, 0x80, 0x85, 0x00, 0xc0, +0x20, 0x56, 0x05, 0x80, 0x94, +0x00, 0x2c, 0x0b, 0xc1, 0x3d, +0x88, 0x2e, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x02, 0x6c, 0x09, +0x6c, 0x00, 0x01, 0xb4, 0x0a, +0x2e, 0x17, 0x56, 0xc0, 0x00, +0x1b, 0x44, 0x92, 0x29, 0x6d, +0x30, 0x12, 0x8b, 0xc0, 0x7b, +0x6c, 0x40, 0x02, 0x2c, 0x49, +0x80, 0xa4, 0x80, 0x00, 0x00, +0x6c, 0x40, 0x02, 0x4c, 0x09, +0x84, 0x84, 0x9a, 0x00, 0x21, +0x40, 0x00, 0x00, 0x83, 0x61, +0x68, 0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x40, 0xb8, 0xe0, +0x6c, 0x00, 0x01, 0x6e, 0x48, +0x68, 0x20, 0x00, 0xb4, 0x24, +0x88, 0x2a, 0x18, 0x83, 0x20, +0x66, 0x00, 0x40, 0xb8, 0xe0, +0x88, 0x2a, 0x06, 0x82, 0x00, +0x0d, 0xe2, 0x38, 0x41, 0x0a, +0x68, 0x20, 0x00, 0xdf, 0xac, +0x68, 0x20, 0x00, 0xdc, 0x2d, +0x88, 0x16, 0x36, 0xc0, 0x00, +0x18, 0x04, 0x86, 0xc0, 0x00, +0x31, 0x64, 0xa6, 0x80, 0x00, +0x0b, 0x22, 0x06, 0x80, 0x00, +0x09, 0xe2, 0x16, 0x82, 0x00, +0x09, 0xc2, 0x46, 0x80, 0x00, +0x0d, 0xc2, 0x26, 0x82, 0x00, +0x0d, 0x32, 0x58, 0x80, 0x6c, +0x40, 0x00, 0x00, 0x80, 0xed, +0x68, 0x00, 0x00, 0xe1, 0x23, +0x66, 0x00, 0x00, 0x4c, 0x28, +0x6c, 0x00, 0x01, 0x6e, 0x09, +0x68, 0x20, 0x00, 0xe0, 0x2c, +0x68, 0x00, 0x00, 0xe1, 0x21, +0x68, 0x00, 0x00, 0xb2, 0x20, +0x88, 0x06, 0xca, 0x08, 0x23, +0x84, 0x34, 0x86, 0x82, 0x00, +0x0d, 0xd2, 0xc6, 0x82, 0x00, +0x0d, 0xea, 0xd6, 0x80, 0x00, +0x0b, 0xb2, 0x06, 0x80, 0x00, +0x0a, 0x82, 0x16, 0x82, 0x00, +0x0b, 0x42, 0x46, 0x80, 0x00, +0x0d, 0xe2, 0x26, 0x82, 0x00, +0x0d, 0x52, 0x58, 0x80, 0xec, +0x40, 0x00, 0x00, 0x81, 0x6d, +0x66, 0x00, 0x00, 0x4c, 0x28, +0x6c, 0x00, 0x01, 0x80, 0x09, +0x68, 0x00, 0x00, 0xbb, 0x20, +0x68, 0x20, 0x01, 0xb6, 0x23, +0x84, 0x34, 0x86, 0x82, 0x00, +0x0e, 0x0a, 0xc6, 0x82, 0x00, +0x1b, 0x52, 0xd8, 0x81, 0x63, +0x68, 0x00, 0x01, 0x86, 0x20, +0x68, 0x00, 0x01, 0x76, 0x21, +0x68, 0x20, 0x01, 0x9b, 0x24, +0x68, 0x00, 0x01, 0x80, 0x22, +0x68, 0x20, 0x01, 0xb3, 0x25, +0x88, 0x06, 0xc8, 0x80, 0xed, +0x68, 0x00, 0x00, 0x47, 0x23, +0x66, 0x00, 0x00, 0x4c, 0x28, +0x6c, 0x00, 0x03, 0x16, 0x09, +0x68, 0x00, 0x01, 0x0a, 0xa0, +0x6c, 0x00, 0x01, 0xb0, 0x60, +0x68, 0x00, 0x01, 0x86, 0x21, +0x88, 0x23, 0x6b, 0xa1, 0x48, +0x84, 0xb4, 0x8a, 0x80, 0x40, +0x68, 0x00, 0x00, 0xb8, 0x20, +0x5c, 0x85, 0x02, 0xbf, 0xb0, +0x80, 0x20, 0x98, 0x81, 0x60, +0x68, 0x20, 0x01, 0xb7, 0x2c, +0x88, 0x1f, 0x66, 0x82, 0x00, +0x09, 0xc2, 0x46, 0x82, 0x00, +0x0c, 0xe2, 0x56, 0x80, 0x00, +0x18, 0x22, 0x08, 0x80, 0x6c, +0x66, 0x00, 0x40, 0xde, 0x80, +0x68, 0x00, 0x00, 0xc1, 0x20, +0x39, 0x0a, 0x08, 0x02, 0x09, +0x88, 0x26, 0x06, 0x82, 0x00, +0x1b, 0x92, 0xc6, 0xc0, 0x00, +0x30, 0x44, 0x86, 0x82, 0x00, +0x0b, 0x42, 0x46, 0x82, 0x00, +0x0c, 0xf2, 0x56, 0x80, 0x00, +0x18, 0x42, 0x08, 0x80, 0x6c, +0x66, 0x00, 0x40, 0xde, 0x80, +0x68, 0x20, 0x00, 0xdc, 0x2c, +0x6c, 0x00, 0x03, 0x08, 0x48, +0x68, 0x00, 0x00, 0x9e, 0x20, +0x68, 0x20, 0x00, 0x9c, 0x24, +0x68, 0x20, 0x00, 0xce, 0x25, +0x88, 0x06, 0xc6, 0x60, 0x04, +0x0d, 0xfe, 0x86, 0xc0, 0x00, +0x30, 0x40, 0x98, 0x81, 0x20, +0x68, 0x20, 0x00, 0xdd, 0x2c, +0x84, 0x04, 0x86, 0x80, 0x00, +0x0a, 0x82, 0x06, 0x82, 0x00, +0x0b, 0x42, 0x46, 0x82, 0x00, +0x0c, 0xf2, 0x58, 0x80, 0x6c, +0x66, 0x00, 0x40, 0xdf, 0xe8, +0x6c, 0x00, 0x03, 0x08, 0x09, +0x55, 0x01, 0x28, 0x81, 0x20, +0x5c, 0x81, 0x00, 0x82, 0x21, +0x80, 0x20, 0x88, 0x48, 0x49, +0x40, 0x00, 0x00, 0x81, 0x60, +0x68, 0x00, 0x00, 0x9e, 0x21, +0x68, 0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x00, 0x5f, 0x80, +0x5c, 0x81, 0x00, 0x82, 0x20, +0x68, 0x00, 0x00, 0xa8, 0x21, +0x80, 0x20, 0x88, 0x82, 0x60, +0x68, 0x20, 0x00, 0xb4, 0x24, +0x66, 0x00, 0x00, 0x5f, 0x80, +0x40, 0x00, 0x00, 0x81, 0x20, +0x68, 0x00, 0x00, 0x9e, 0x21, +0x68, 0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x00, 0x63, 0xa0, +0x68, 0x00, 0x00, 0xd1, 0x21, +0x5c, 0x81, 0x00, 0x82, 0x20, +0x80, 0x84, 0x88, 0x82, 0xe1, +0x68, 0x00, 0x00, 0xa8, 0x21, +0x68, 0x20, 0x00, 0xb4, 0x24, +0x66, 0x00, 0x00, 0x63, 0xa0, +0x68, 0x20, 0x00, 0xd7, 0x20, +0x5c, 0x81, 0x00, 0x82, 0xa4, +0x5c, 0x85, 0x00, 0x00, 0x09, +0x5d, 0x0a, 0x2a, 0x20, 0x03, +0x51, 0x85, 0x60, 0x20, 0x48, +0x98, 0x22, 0x88, 0x83, 0x60, +0x9c, 0x00, 0x08, 0x40, 0x08, +0x68, 0x20, 0x00, 0xcc, 0x20, +0x68, 0x20, 0x00, 0xcd, 0x21, +0x84, 0x04, 0x88, 0x48, 0x48, +0x40, 0x00, 0x00, 0x83, 0xe4, +0x68, 0x00, 0x00, 0xd1, 0x22, +0x66, 0x00, 0x40, 0xc6, 0x80, +0x5c, 0x09, 0x20, 0x83, 0xa0, +0x00, 0x00, 0x09, 0x40, 0x2d, +0x25, 0x92, 0x8b, 0xc0, 0x88, +0x39, 0x06, 0x06, 0xc4, 0x00, +0x25, 0x00, 0xb6, 0xc4, 0x00, +0x4b, 0xe0, 0xab, 0xc0, 0x8f, +0x6c, 0x40, 0x04, 0xa8, 0x08, +0x68, 0x20, 0x02, 0x58, 0x20, +0x6c, 0x40, 0x04, 0xc0, 0x0a, +0x80, 0x20, 0x88, 0x40, 0x0b, +0x5c, 0x09, 0x40, 0x82, 0xa0, +0x52, 0xc1, 0x40, 0x84, 0xc8, +0x42, 0x08, 0x40, 0x84, 0x4a, +0x88, 0x2c, 0xb6, 0x82, 0x00, +0x0a, 0x82, 0x48, 0x82, 0x88, +0x6c, 0x40, 0x01, 0x50, 0x48, +0x6c, 0x40, 0x01, 0x80, 0x48, +0x68, 0x20, 0x00, 0xc0, 0x21, +0x88, 0x40, 0x98, 0x60, 0xc9, +0x00, 0x00, 0x04, 0x22, 0xbf, +0x88, 0x3a, 0x08, 0x48, 0xc9, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0xa2, 0x0a, +0x66, 0x00, 0x00, 0x65, 0xc8, +0x5c, 0x00, 0x28, 0x40, 0x0b, +0x6e, 0x00, 0x02, 0x66, 0x25, +0x32, 0x02, 0x8b, 0xc3, 0x01, +0x6e, 0x40, 0x01, 0xbf, 0x2d, +0x32, 0x02, 0x8b, 0xc2, 0xc1, +0x6e, 0x40, 0x01, 0xc0, 0x2d, +0x32, 0x02, 0x8b, 0xc2, 0x81, +0x6c, 0x40, 0x01, 0xae, 0x09, +0x5d, 0x0a, 0x28, 0x83, 0x20, +0x51, 0x85, 0x71, 0x8e, 0x82, +0x98, 0x2a, 0x89, 0xc0, 0x00, +0x6c, 0x40, 0x04, 0x9e, 0x0a, +0x84, 0x00, 0xb0, 0x8e, 0x00, +0x98, 0x00, 0xa2, 0xe1, 0xa6, +0x32, 0x03, 0x0b, 0xc0, 0x5d, +0x55, 0x00, 0x80, 0x82, 0x89, +0x55, 0x01, 0xb8, 0x84, 0x8a, +0x08, 0xe2, 0x02, 0xe0, 0xaa, +0x6c, 0x40, 0x01, 0x50, 0x09, +0x98, 0x08, 0xa3, 0x01, 0xa8, +0xbc, 0x0b, 0x56, 0xc4, 0x00, +0x4a, 0x00, 0x92, 0xe1, 0x2d, +0x32, 0x02, 0x8b, 0xc0, 0x63, +0x6c, 0x40, 0x01, 0x80, 0x4a, +0x6c, 0x40, 0x01, 0x50, 0x4a, +0xbc, 0x05, 0xf8, 0x83, 0xa0, +0xbc, 0x03, 0xf8, 0x83, 0xa0, +0x5c, 0x00, 0x00, 0x83, 0xa0, +0x38, 0x12, 0x59, 0x40, 0x2e, +0x25, 0x97, 0x0b, 0xc1, 0x41, +0x6c, 0x40, 0x04, 0xbc, 0x09, +0x57, 0x0b, 0x28, 0x84, 0x08, +0x6c, 0x40, 0x01, 0x52, 0x48, +0x32, 0x02, 0x8b, 0xc0, 0x6d, +0x6c, 0x40, 0x01, 0x82, 0x48, +0x00, 0x00, 0x06, 0xc4, 0x00, +0x4c, 0x20, 0xa0, 0x86, 0x00, +0x57, 0x01, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x01, 0x82, 0x40, +0x6c, 0x40, 0x01, 0x52, 0x40, +0x5c, 0x81, 0x02, 0x04, 0xc1, +0x88, 0x12, 0x08, 0x08, 0x09, +0x88, 0x16, 0x16, 0x80, 0x00, +0x09, 0xe2, 0x16, 0x82, 0x00, +0x09, 0xc2, 0x46, 0x82, 0x00, +0x0c, 0xe2, 0x56, 0x60, 0x04, +0x0b, 0xbe, 0x89, 0x82, 0x48, +0x5c, 0x85, 0x00, 0x81, 0x21, +0x88, 0x22, 0x08, 0x08, 0x09, +0x88, 0x16, 0x16, 0x80, 0x00, +0x0a, 0x82, 0x16, 0x82, 0x00, +0x0b, 0x42, 0x46, 0x82, 0x00, +0x0c, 0xf2, 0x56, 0x60, 0x04, +0x0b, 0xbe, 0x89, 0x82, 0x48, +0x5c, 0x08, 0xa0, 0x81, 0x20, +0x00, 0x00, 0x09, 0x40, 0x2d, +0x25, 0x92, 0x8b, 0xc0, 0x40, +0x6c, 0x00, 0x01, 0x74, 0x7a, +0x6c, 0x00, 0x01, 0x86, 0x7a, +0x38, 0x13, 0x42, 0x59, 0x28, +0xbc, 0x0d, 0x06, 0x80, 0x00, +0x13, 0x32, 0x06, 0xc4, 0x00, +0x21, 0xc0, 0x85, 0xc8, 0x10, +0x18, 0xe8, 0x99, 0x42, 0x45, +0x6c, 0x40, 0x01, 0x5a, 0x48, +0x6c, 0x40, 0x01, 0x8a, 0x48, +0x42, 0x1a, 0x38, 0x40, 0x7a, +0x68, 0x00, 0x00, 0xb6, 0x20, +0x68, 0x00, 0x00, 0xbf, 0x21, +0x66, 0x00, 0x40, 0xee, 0x40, +0x6e, 0x00, 0x02, 0x66, 0x24, +0x32, 0x06, 0x0b, 0xc1, 0xa1, +0x68, 0x20, 0x01, 0x11, 0x21, +0x68, 0x20, 0x00, 0xad, 0x20, +0xa0, 0xc2, 0x28, 0x81, 0x62, +0x66, 0x00, 0x40, 0xf3, 0x40, +0x88, 0x12, 0x26, 0x82, 0x00, +0x0c, 0x52, 0x06, 0x82, 0x00, +0x11, 0x12, 0x16, 0x60, 0x04, +0x0f, 0x34, 0x08, 0x81, 0x20, +0x6c, 0x40, 0x02, 0x78, 0x08, +0x84, 0x30, 0x93, 0x01, 0x28, +0xbc, 0x15, 0x16, 0xc0, 0x00, +0x1b, 0x27, 0xa6, 0xc0, 0x00, +0x1c, 0x67, 0xab, 0xc1, 0x07, +0x68, 0x20, 0x00, 0xad, 0x20, +0x68, 0x20, 0x01, 0x12, 0x21, +0x68, 0x20, 0x01, 0x0f, 0x22, +0x66, 0x00, 0x40, 0xf3, 0x40, +0x68, 0x20, 0x01, 0x0f, 0x22, +0x68, 0x20, 0x00, 0xc5, 0x20, +0x66, 0x00, 0x40, 0xf3, 0x48, +0x40, 0x00, 0x02, 0x10, 0x61, +0x6c, 0x40, 0x02, 0x78, 0x08, +0x6c, 0x40, 0x02, 0x2c, 0x09, +0x30, 0x12, 0x8b, 0xc4, 0x20, +0x6e, 0x00, 0x02, 0x66, 0x24, +0x32, 0x06, 0x0b, 0xc3, 0xe0, +0x6c, 0x00, 0x01, 0x70, 0x08, +0x32, 0x02, 0x0b, 0xc0, 0x63, +0x6c, 0x00, 0x01, 0xb6, 0x09, +0x38, 0x10, 0x62, 0x41, 0xad, +0x6c, 0x00, 0x01, 0xb6, 0x49, +0x32, 0x02, 0x0b, 0xc0, 0x65, +0x6c, 0x00, 0x01, 0xb6, 0x08, +0x38, 0x10, 0xd2, 0x41, 0x64, +0x6c, 0x00, 0x01, 0xb6, 0x48, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x18, 0x20, 0x83, 0x20, 0x20, +0xbc, 0x06, 0xb3, 0x81, 0x25, +0x6c, 0x00, 0x01, 0xb6, 0x0a, +0x24, 0x17, 0x56, 0xc0, 0x00, +0x1b, 0x64, 0x93, 0x20, 0x20, +0xbc, 0x07, 0xd3, 0x81, 0x2c, +0x6c, 0x00, 0x01, 0xb6, 0x09, +0x24, 0x12, 0xc6, 0xc0, 0x00, +0x1b, 0x64, 0x80, 0x00, 0x00, +0x6c, 0x00, 0x01, 0xb6, 0x08, +0x2a, 0x8e, 0x53, 0x20, 0xe8, +0xbc, 0x03, 0x0b, 0xc0, 0x6f, +0x6c, 0x40, 0x01, 0x5a, 0x7a, +0x6c, 0x40, 0x02, 0x1c, 0x09, +0x6c, 0x40, 0x01, 0x5a, 0x49, +0x38, 0x18, 0x52, 0x89, 0x64, +0x30, 0x16, 0x0b, 0xc0, 0x40, +0x40, 0x00, 0x03, 0xc0, 0x6f, +0x6c, 0x40, 0x01, 0x8a, 0x7a, +0x6c, 0x40, 0x02, 0x1c, 0x08, +0x6c, 0x40, 0x01, 0x8a, 0x48, +0x68, 0x00, 0x00, 0x65, 0x20, +0x88, 0x1b, 0x6b, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0xb0, 0x60, +0x40, 0x00, 0x02, 0x80, 0x50, +0x68, 0x00, 0x01, 0x0c, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x06, 0x00, 0x00, 0x00, +0x6c, 0x00, 0x01, 0xc0, 0x0a, +0x6c, 0x40, 0x02, 0x36, 0x09, +0x58, 0x0b, 0x82, 0xbf, 0xf0, +0xbc, 0x71, 0x88, 0x80, 0x4a, +0x38, 0x11, 0x46, 0xe0, 0x00, +0x1a, 0xe2, 0xf2, 0x59, 0x38, +0xbc, 0x6b, 0x16, 0xc4, 0x00, +0x22, 0xe0, 0xb6, 0xc4, 0x00, +0x24, 0x00, 0x06, 0xc0, 0x00, +0x16, 0xa0, 0x16, 0xc0, 0x00, +0x17, 0xc0, 0x83, 0x00, 0x38, +0xbc, 0x45, 0xd8, 0x80, 0xd1, +0x30, 0x17, 0x0b, 0xc3, 0xc8, +0x6c, 0x40, 0x02, 0x2e, 0x7a, +0x68, 0x00, 0x01, 0xee, 0x21, +0x5c, 0x83, 0x0b, 0x01, 0x00, +0x5c, 0x81, 0x02, 0x08, 0x00, +0x6c, 0x00, 0x03, 0xde, 0x0a, +0x50, 0x41, 0x90, 0x08, 0x8b, +0x20, 0x83, 0x94, 0xa5, 0x1b, +0xb0, 0x1f, 0xe5, 0x04, 0xc5, +0x80, 0xa0, 0xb2, 0xc8, 0x5b, +0x54, 0x06, 0x58, 0x0a, 0x01, +0x68, 0x00, 0x00, 0xe1, 0x22, +0x22, 0x85, 0xb5, 0x04, 0x1d, +0x85, 0x04, 0xf2, 0x08, 0x08, +0x28, 0x01, 0x82, 0x09, 0x83, +0x2c, 0x85, 0xb3, 0x68, 0x82, +0x54, 0x06, 0x19, 0x80, 0x82, +0x6c, 0x40, 0x02, 0x42, 0x00, +0x30, 0x01, 0x02, 0x28, 0x5a, +0x85, 0x0c, 0xeb, 0xc1, 0x0b, +0x88, 0x00, 0xa2, 0xe0, 0x7f, +0x36, 0x9c, 0x19, 0x80, 0x4b, +0x30, 0x03, 0x8b, 0xc0, 0xa3, +0x5c, 0x00, 0xfb, 0xa1, 0x11, +0x44, 0x58, 0x00, 0x80, 0x8a, +0x98, 0x30, 0xb2, 0x28, 0xbf, +0x57, 0x4b, 0xeb, 0xc0, 0x3f, +0x6c, 0x00, 0x01, 0xc0, 0x49, +0x88, 0x08, 0xa8, 0x0a, 0x4a, +0x80, 0x8c, 0xa8, 0x0a, 0x48, +0x42, 0x06, 0x38, 0x48, 0x48, +0x68, 0x00, 0x01, 0xee, 0x20, +0x5c, 0x83, 0x0b, 0xc0, 0x8f, +0x5c, 0x81, 0x00, 0x80, 0x8a, +0x68, 0x00, 0x01, 0xee, 0x20, +0x5c, 0x81, 0x00, 0x80, 0x8a, +0x5c, 0x83, 0x0b, 0x80, 0x00, +0x6c, 0x00, 0x03, 0xdc, 0x09, +0x2f, 0x1a, 0xd8, 0x00, 0xc9, +0x00, 0x00, 0x08, 0x40, 0x09, +0x2e, 0x92, 0xd8, 0x02, 0x49, +0x00, 0x00, 0x06, 0xc4, 0x00, +0x22, 0xe0, 0x95, 0x50, 0x36, +0x84, 0x00, 0x06, 0xc0, 0x00, +0x3d, 0xe0, 0xb2, 0xf1, 0x04, +0x57, 0x4d, 0xf0, 0x40, 0x48, +0x6c, 0x00, 0x03, 0xde, 0x4a, +0x6c, 0x40, 0x02, 0x2e, 0x49, +0x68, 0x00, 0x00, 0x9a, 0x20, +0x40, 0x00, 0x03, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0xb0, 0x60, +0x46, 0x08, 0x0a, 0x80, 0x10, +0x5c, 0x81, 0x01, 0x8e, 0x88, +0x68, 0x00, 0x01, 0x76, 0x20, +0x2a, 0x06, 0x43, 0xa1, 0x04, +0x32, 0x2a, 0x0b, 0xff, 0xca, +0x80, 0x07, 0xa6, 0xc0, 0x00, +0x1c, 0x67, 0xa0, 0x00, 0x00, +0x6c, 0x40, 0x02, 0x78, 0x08, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x24, 0x80, 0x00, 0x00, +0xab, 0xfc, 0x08, 0x80, 0x64, +0xa0, 0x90, 0x1a, 0x22, 0x84, +0x88, 0x0e, 0x38, 0x81, 0x65, +0x88, 0x1e, 0x28, 0x82, 0x60, +0x88, 0x2f, 0x66, 0x60, 0x04, +0x05, 0x34, 0x8a, 0x08, 0x00, +0x88, 0x22, 0x48, 0x81, 0xa0, +0xa2, 0x0e, 0x48, 0x60, 0x48, +0xa2, 0x48, 0x48, 0x83, 0x64, +0x68, 0x20, 0x00, 0xd0, 0x24, +0x66, 0x00, 0x40, 0x53, 0x48, +0x40, 0x00, 0x01, 0x82, 0x09, +0x5c, 0x83, 0x00, 0x83, 0x20, +0x6c, 0x40, 0x01, 0xae, 0x09, +0x5d, 0x0a, 0x28, 0x02, 0x48, +0x23, 0x0a, 0xd6, 0x82, 0x00, +0x13, 0xe2, 0x48, 0x40, 0x0a, +0x57, 0x0d, 0x01, 0x82, 0x69, +0x9e, 0x08, 0x49, 0x80, 0x02, +0x5b, 0x44, 0x28, 0x60, 0x01, +0x58, 0x03, 0x40, 0x80, 0x22, +0x88, 0x52, 0x4a, 0x10, 0x81, +0x6e, 0x00, 0x01, 0xae, 0x2f, +0x6c, 0x40, 0x02, 0x1c, 0x08, +0x96, 0x03, 0x8a, 0x08, 0x62, +0xa0, 0x8a, 0x34, 0x20, 0x25, +0x20, 0x0c, 0x08, 0x02, 0x09, +0x38, 0x12, 0xb2, 0x58, 0xf8, +0xbc, 0x7c, 0x08, 0x84, 0x26, +0x88, 0x12, 0x59, 0x70, 0x2f, +0x59, 0x03, 0xc0, 0x68, 0x7a, +0x00, 0x00, 0x04, 0x20, 0x84, +0x88, 0x1a, 0x58, 0x82, 0x27, +0x86, 0x88, 0xb3, 0x01, 0xb8, +0xbc, 0x07, 0xb8, 0x7b, 0x8b, +0x30, 0x1f, 0x0b, 0xc0, 0x94, +0x98, 0xe8, 0xb8, 0x68, 0xca, +0x97, 0x06, 0x7b, 0xc0, 0x57, +0x30, 0x1f, 0x0b, 0xc0, 0x3a, +0x98, 0xe8, 0xb9, 0x70, 0x67, +0x86, 0x8c, 0xa0, 0x00, 0x00, +0x84, 0x98, 0x26, 0xc4, 0x00, +0x26, 0x80, 0xb3, 0x01, 0xd0, +0xbc, 0x25, 0x83, 0x90, 0x21, +0x68, 0x20, 0x01, 0x32, 0x27, +0x5c, 0x82, 0x10, 0x4a, 0x82, +0x83, 0x88, 0x15, 0x70, 0x29, +0xa1, 0x80, 0x65, 0x90, 0x04, +0x01, 0xb5, 0x30, 0x00, 0x00, +0x87, 0x80, 0x28, 0x58, 0x01, +0x57, 0x04, 0x48, 0x79, 0x02, +0x85, 0x85, 0x1b, 0xc0, 0x6c, +0x84, 0xa8, 0x13, 0x00, 0x88, +0xbc, 0x08, 0x28, 0x49, 0xcb, +0x85, 0x15, 0x2b, 0xc0, 0x57, +0x30, 0x08, 0x8b, 0xc0, 0x34, +0x84, 0x9c, 0xb8, 0x51, 0x52, +0x00, 0x00, 0x08, 0x58, 0x02, +0x6c, 0x40, 0x02, 0x70, 0x0b, +0x57, 0x05, 0xd0, 0x32, 0x8b, +0x57, 0x0e, 0x90, 0x84, 0xa2, +0xbc, 0x03, 0xf8, 0x70, 0x42, +0x88, 0x4a, 0x20, 0x00, 0x00, +0x00, 0x00, 0x08, 0x50, 0x0b, +0x30, 0x13, 0x8b, 0xc0, 0xb3, +0x6c, 0x40, 0x02, 0x52, 0x02, +0x28, 0x0b, 0xf3, 0x09, 0x38, +0xbc, 0x03, 0x4b, 0xc0, 0x6f, +0x5c, 0x0b, 0xe0, 0x50, 0x4b, +0xbc, 0x03, 0xf5, 0xc0, 0xbe, +0x05, 0x04, 0x83, 0x81, 0x7c, +0x25, 0x90, 0x0b, 0xc0, 0x28, +0x38, 0x16, 0x7b, 0xc0, 0x27, +0x25, 0x9c, 0x0b, 0xc1, 0x31, +0x25, 0x90, 0x0b, 0xc0, 0x20, +0xbc, 0x1c, 0xf3, 0x81, 0x74, +0x25, 0x9c, 0x0b, 0xc1, 0x99, +0x38, 0x17, 0x42, 0x59, 0x00, +0xbc, 0x03, 0x99, 0x8e, 0x88, +0x32, 0x02, 0x8b, 0xc0, 0x54, +0x38, 0x17, 0x72, 0x59, 0xc0, +0xbc, 0x10, 0x03, 0x20, 0x28, +0xbc, 0x0e, 0x39, 0x60, 0x74, +0xbc, 0x0c, 0x73, 0x81, 0x74, +0x25, 0x90, 0x0b, 0xc0, 0x21, +0x32, 0x02, 0x8b, 0xc0, 0x52, +0x38, 0x17, 0x42, 0x59, 0x00, +0xbc, 0x04, 0x03, 0x20, 0x28, +0xbc, 0x02, 0x52, 0x41, 0xc0, +0x96, 0x07, 0x0b, 0xc3, 0xdf, +0x88, 0x12, 0x33, 0x20, 0x10, +0xbc, 0x04, 0xc8, 0x81, 0xa5, +0x57, 0x03, 0x93, 0xc0, 0x4f, +0x86, 0x8c, 0x22, 0x81, 0x8a, +0x40, 0x00, 0x00, 0x68, 0xc2, +0x68, 0x20, 0x01, 0x37, 0x21, +0x5c, 0x88, 0x08, 0x81, 0x23, +0x80, 0xa8, 0x28, 0x58, 0x01, +0x55, 0x02, 0x48, 0x84, 0x26, +0x58, 0x04, 0x40, 0x58, 0x51, +0x42, 0x02, 0xeb, 0x00, 0x09, +0x5c, 0x81, 0x09, 0x70, 0x61, +0xbc, 0x03, 0xf5, 0xc0, 0xbd, +0x05, 0x85, 0x23, 0x81, 0x7a, +0x52, 0xc4, 0x02, 0xc0, 0xe2, +0x80, 0x88, 0x18, 0x08, 0x83, +0x81, 0x0d, 0x18, 0x50, 0x53, +0x00, 0x00, 0x08, 0x0b, 0x01, +0x88, 0x4a, 0x68, 0x48, 0x03, +0x42, 0x05, 0x40, 0x50, 0xd1, +0x5c, 0x00, 0x00, 0x70, 0x53, +0x24, 0x08, 0x25, 0x90, 0x14, +0x16, 0x07, 0x2b, 0xc0, 0x4d, +0x38, 0x17, 0x09, 0x60, 0x3a, +0x24, 0x01, 0x09, 0x60, 0x70, +0x5c, 0x09, 0x20, 0x49, 0x48, +0x25, 0x93, 0x8b, 0xc0, 0x70, +0x6c, 0x40, 0x04, 0xa4, 0x08, +0x6c, 0x40, 0x01, 0x50, 0x48, +0x6c, 0x40, 0x01, 0x80, 0x48, +0x00, 0x00, 0x08, 0x68, 0x8b, +0x80, 0x24, 0xb8, 0x80, 0x60, +0x66, 0x00, 0x00, 0x67, 0x88, +0x40, 0x00, 0x00, 0x58, 0x00, +0x6e, 0x00, 0x01, 0xae, 0x2e, +0x5c, 0x08, 0xa8, 0x80, 0x20, +0x25, 0x97, 0x0b, 0xc2, 0xf9, +0x84, 0x04, 0x80, 0x00, 0x00, +0x6c, 0x40, 0x02, 0x2c, 0x09, +0x6c, 0x40, 0x02, 0x78, 0x08, +0x30, 0x12, 0x8b, 0xc2, 0x79, +0x88, 0x0a, 0x46, 0xc0, 0x00, +0x1c, 0x00, 0x86, 0xc4, 0x00, +0x23, 0x60, 0xb3, 0x01, 0xe0, +0xbc, 0x20, 0x95, 0xc0, 0x97, +0x86, 0x00, 0x02, 0x59, 0xf0, +0xbc, 0x0d, 0x98, 0x82, 0x22, +0x28, 0x10, 0x28, 0x50, 0x0a, +0x98, 0x08, 0xb3, 0x01, 0xf0, +0xbc, 0x01, 0x58, 0x50, 0x4b, +0x2e, 0x10, 0x28, 0x50, 0x0a, +0x98, 0x08, 0x83, 0x01, 0x30, +0xbc, 0x01, 0x38, 0x50, 0x48, +0x00, 0x00, 0x08, 0x50, 0x08, +0x86, 0x00, 0xa3, 0x01, 0xa0, +0xbc, 0x03, 0xb2, 0x29, 0x6d, +0x2e, 0x14, 0x28, 0x60, 0x42, +0x00, 0x00, 0x08, 0x50, 0x0a, +0x86, 0x00, 0x83, 0x01, 0x30, +0xbc, 0x02, 0x52, 0x81, 0x40, +0x86, 0x04, 0x00, 0x00, 0x00, +0x88, 0x2b, 0x68, 0x43, 0x8a, +0x46, 0x0a, 0x40, 0x40, 0x09, +0x57, 0x0b, 0x82, 0x80, 0x40, +0x40, 0x00, 0x01, 0x80, 0x08, +0x55, 0x01, 0x2a, 0xbf, 0xd0, +0xa2, 0x16, 0x4a, 0x08, 0x81, +0x88, 0x06, 0x4a, 0x20, 0x64, +0x88, 0x0e, 0x1a, 0x08, 0x41, +0x88, 0x16, 0x48, 0x81, 0xc9, +0x88, 0x26, 0x08, 0x82, 0xf6, +0x66, 0x00, 0x40, 0x53, 0x48, +0x40, 0x00, 0x02, 0x08, 0x00, +0x5c, 0x82, 0x00, 0x81, 0x20, +0x88, 0x22, 0x4a, 0x00, 0x61, +0xa2, 0x08, 0x08, 0x48, 0x09, +0x88, 0x18, 0xa4, 0x44, 0x80, +0x00, 0x24, 0x88, 0x02, 0x40, +0x66, 0x00, 0x40, 0xb9, 0xa8, +0x40, 0x00, 0x02, 0x0e, 0x24, +0x6e, 0x00, 0x02, 0x66, 0x24, +0x59, 0x03, 0x00, 0x80, 0xa4, +0xbc, 0x10, 0x8a, 0x20, 0x20, +0x6e, 0x00, 0x01, 0xae, 0x2c, +0x38, 0x12, 0x52, 0x59, 0x60, +0xbc, 0x15, 0x88, 0x80, 0x24, +0x6c, 0x40, 0x02, 0x50, 0x09, +0x66, 0x00, 0x00, 0x64, 0x88, +0x86, 0x08, 0xa8, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0xc8, +0xbc, 0x0b, 0x78, 0x60, 0x88, +0x6c, 0x40, 0x02, 0x32, 0x09, +0x36, 0x90, 0x43, 0x01, 0x28, +0xbc, 0x05, 0x58, 0x80, 0x20, +0x6c, 0x40, 0x02, 0x70, 0x08, +0x84, 0x0c, 0x80, 0x00, 0x00, +0x88, 0x2b, 0x6b, 0xa1, 0x48, +0xa8, 0x03, 0x00, 0x00, 0x00, +0x5c, 0x81, 0x02, 0x08, 0x81, +0xa2, 0x16, 0x4d, 0x20, 0x80, +0x44, 0x10, 0x00, 0x20, 0x08, +0x84, 0x80, 0xa4, 0x44, 0x40, +0x04, 0x10, 0x84, 0x60, 0xa4, +0x06, 0x00, 0xa0, 0x82, 0x80, +0x40, 0x00, 0x01, 0x80, 0x08, +0x30, 0x1a, 0x8b, 0xc0, 0xe8, +0x6c, 0x40, 0x04, 0xb6, 0x08, +0x84, 0x00, 0xb3, 0x69, 0xc0, +0x98, 0x00, 0xb3, 0x09, 0x38, +0xbc, 0x06, 0x46, 0xc4, 0x00, +0x4b, 0x40, 0x82, 0x81, 0x30, +0x42, 0x01, 0x79, 0x80, 0x0a, +0x2f, 0x17, 0x59, 0x82, 0x89, +0xba, 0x14, 0x89, 0x82, 0x48, +0x40, 0x00, 0x03, 0x80, 0x00, +0x46, 0x08, 0x8a, 0xbf, 0xe0, +0x51, 0x61, 0xb0, 0x80, 0x49, +0x51, 0x61, 0xe0, 0x80, 0xf6, +0x1a, 0x0a, 0x29, 0x83, 0x09, +0x98, 0x38, 0x82, 0x81, 0x2d, +0x88, 0x14, 0x96, 0x60, 0x04, +0x0c, 0x2e, 0x8b, 0xa1, 0x01, +0x88, 0x10, 0x94, 0x40, 0x80, +0x08, 0x00, 0x99, 0x80, 0x08, +0x23, 0x42, 0x43, 0x01, 0x60, +0xbc, 0x02, 0x5b, 0xc0, 0x2f, +0x2e, 0x16, 0x49, 0x8e, 0x88, +0x88, 0x0b, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, 0x00, +0x6e, 0x00, 0x01, 0xae, 0x2c, +0x38, 0x12, 0x26, 0xc4, 0x00, +0x22, 0xc0, 0x12, 0x58, 0xa0, +0x40, 0x00, 0x03, 0xc0, 0x49, +0x55, 0x00, 0x79, 0x82, 0xc2, +0x6c, 0x40, 0x04, 0xba, 0x01, +0x6c, 0x40, 0x02, 0x78, 0x03, +0x30, 0x0f, 0x8b, 0xc0, 0x70, +0x68, 0x00, 0x01, 0x52, 0x08, +0x30, 0x10, 0x0b, 0xc0, 0x4c, +0x98, 0xe8, 0x89, 0x82, 0xc8, +0xbc, 0x01, 0x72, 0xa0, 0x0c, +0x6e, 0x00, 0x02, 0x66, 0x27, +0x32, 0x03, 0x8b, 0xc1, 0x91, +0x30, 0x0e, 0x0b, 0xc1, 0x71, +0x6c, 0x00, 0x01, 0xb2, 0x00, +0x30, 0x10, 0x0b, 0xc1, 0x33, +0x6c, 0x00, 0x01, 0xb2, 0x00, +0x30, 0x10, 0x0b, 0xc0, 0xc3, +0x6c, 0x00, 0x01, 0xc6, 0x08, +0x2a, 0x06, 0x43, 0x22, 0xa0, +0x6c, 0x00, 0x01, 0xc6, 0x48, +0xbc, 0x05, 0x52, 0xa0, 0x44, +0x6c, 0x00, 0x01, 0xb2, 0x48, +0x6c, 0x00, 0x01, 0xc6, 0x7a, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x1b, 0x20, 0x83, 0x20, 0x78, +0x48, 0xb3, 0xa3, 0xc0, 0x88, +0x9a, 0x04, 0x13, 0x01, 0x90, +0xbc, 0x0b, 0x43, 0x01, 0x90, +0xbc, 0x09, 0xb9, 0x82, 0x88, +0x98, 0x2c, 0x8b, 0xa1, 0x40, +0x32, 0x02, 0x8b, 0xc0, 0x44, +0x32, 0x02, 0x8b, 0xc0, 0x2b, +0x98, 0x28, 0x89, 0x82, 0xc8, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x6c, 0x00, 0x01, 0xe0, 0x0b, +0x6c, 0x00, 0x01, 0xec, 0x01, +0x6c, 0x00, 0x01, 0xe2, 0x0a, +0x6c, 0x00, 0x01, 0xee, 0x03, +0x2e, 0x1f, 0x22, 0xe0, 0x59, +0x6c, 0x00, 0x01, 0xd4, 0x09, +0x6c, 0x00, 0x01, 0xd6, 0x08, +0x6c, 0x00, 0x03, 0x8c, 0x42, +0x6c, 0x00, 0x03, 0xa2, 0x41, +0x57, 0x0b, 0x03, 0xa1, 0x48, +0x6c, 0x00, 0x03, 0x76, 0x40, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x20, 0x00, 0x24, 0x21, +0x68, 0x00, 0x00, 0x9a, 0x20, +0x5c, 0x82, 0x02, 0xc0, 0x21, +0x5c, 0x08, 0xa0, 0x08, 0x0b, +0x80, 0x08, 0x96, 0x82, 0x00, +0x04, 0xb2, 0x44, 0x43, 0x80, +0x04, 0x00, 0x98, 0x20, 0x0a, +0x6e, 0x00, 0x01, 0xae, 0x2f, +0x44, 0x31, 0x02, 0xbf, 0x70, +0x52, 0xc9, 0xc0, 0x81, 0x64, +0x88, 0x1e, 0x18, 0x82, 0x76, +0x88, 0x2d, 0x69, 0x04, 0x58, +0x42, 0x04, 0x48, 0x85, 0x54, +0x90, 0x35, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x86, 0x0a, +0x40, 0x00, 0x03, 0xc0, 0x7f, +0x6c, 0x00, 0x01, 0x74, 0x09, +0x68, 0x00, 0x00, 0x9c, 0x20, +0x00, 0x00, 0x08, 0x40, 0x8a, +0x84, 0x00, 0x98, 0x85, 0xca, +0x40, 0x00, 0x00, 0x86, 0x49, +0x68, 0x20, 0x00, 0x85, 0x24, +0x66, 0x00, 0x40, 0x88, 0xe8, +0x6e, 0x40, 0x01, 0x12, 0x27, +0x68, 0x20, 0x00, 0x85, 0x20, +0x88, 0x84, 0x8a, 0x00, 0x88, +0x94, 0x02, 0x78, 0x86, 0x0a, +0x88, 0x58, 0x96, 0x60, 0x04, +0x08, 0x8e, 0x8a, 0x04, 0x4c, +0x6e, 0x00, 0x01, 0xae, 0x2d, +0x5c, 0x08, 0xf0, 0x85, 0xc8, +0x52, 0xcd, 0x40, 0x88, 0xc8, +0xbc, 0x21, 0x98, 0x88, 0x09, +0x68, 0x20, 0x00, 0x90, 0x2c, +0x68, 0x20, 0x00, 0x8a, 0x24, +0x68, 0x20, 0x00, 0x8d, 0x25, +0x40, 0x00, 0x00, 0x80, 0x6c, +0x66, 0x00, 0x40, 0x78, 0x80, +0x6c, 0x40, 0x00, 0x4a, 0x09, +0x44, 0x08, 0x00, 0x85, 0x89, +0x68, 0x20, 0x00, 0x98, 0xac, +0x88, 0x84, 0x86, 0x82, 0x00, +0x09, 0x2a, 0x46, 0x82, 0x00, +0x09, 0x5a, 0x58, 0x80, 0x6c, +0x90, 0x65, 0x88, 0x85, 0xd4, +0x66, 0x00, 0x40, 0x78, 0x80, +0x6c, 0x40, 0x00, 0x98, 0x09, +0x40, 0x00, 0x03, 0xc0, 0xcf, +0x44, 0x08, 0x00, 0x88, 0xc8, +0x6c, 0x40, 0x00, 0x4a, 0x08, +0x44, 0x21, 0x00, 0x85, 0x89, +0x6c, 0x40, 0x00, 0x98, 0x08, +0x44, 0x20, 0x01, 0x06, 0x5a, +0x40, 0x00, 0x00, 0x85, 0xd6, +0x68, 0x00, 0x00, 0x7d, 0x20, +0x90, 0x61, 0x2a, 0x04, 0x21, +0x88, 0x59, 0x68, 0x85, 0xe1, +0x90, 0x65, 0x88, 0x87, 0x54, +0x66, 0x00, 0x40, 0x52, 0x08, +0x5c, 0x00, 0x71, 0x80, 0x89, +0x90, 0x61, 0x06, 0x80, 0x00, +0x09, 0x22, 0x08, 0x87, 0x14, +0xa0, 0x42, 0x18, 0x86, 0xc8, +0x40, 0x00, 0x00, 0x86, 0x61, +0x66, 0x00, 0x40, 0x52, 0x08, +0x5c, 0x00, 0x71, 0x80, 0x09, +0x5c, 0x84, 0x10, 0x81, 0xa1, +0x5c, 0x83, 0x00, 0x85, 0xa0, +0x5c, 0x81, 0x08, 0x81, 0xc8, +0xa0, 0x58, 0x49, 0x04, 0x10, +0x84, 0x80, 0x98, 0x21, 0x08, +0x88, 0x51, 0x44, 0x40, 0xc0, +0x08, 0x62, 0x08, 0x81, 0x25, +0xa0, 0x58, 0x16, 0xc0, 0x00, +0x1d, 0xe0, 0x85, 0x40, 0x80, +0x10, 0x31, 0x28, 0x68, 0x09, +0x80, 0x90, 0x88, 0x82, 0x96, +0x44, 0x0d, 0x41, 0x80, 0x09, +0x6c, 0x00, 0x01, 0xea, 0x0a, +0x54, 0x0c, 0x80, 0x22, 0x49, +0x98, 0x00, 0xa8, 0x0a, 0x4a, +0x88, 0x2c, 0x98, 0x81, 0x4a, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x82, 0x28, 0x85, 0x70, 0x94, +0x00, 0xa8, 0x96, 0xc0, 0x00, +0x2b, 0x60, 0x86, 0xc0, 0x00, +0x2b, 0x80, 0xb4, 0x92, 0x1a, +0x88, 0x36, 0x15, 0x70, 0xe9, +0x08, 0x3e, 0x46, 0xc4, 0x00, +0x4d, 0x04, 0x06, 0xc4, 0x00, +0x4d, 0x24, 0x26, 0x60, 0x04, +0x14, 0x78, 0x03, 0x20, 0x20, +0x40, 0x00, 0x03, 0xc0, 0xf1, +0x6c, 0x40, 0x04, 0xd2, 0x09, +0x68, 0x20, 0x01, 0x95, 0x24, +0x68, 0x20, 0x02, 0x6b, 0x25, +0x66, 0x00, 0x00, 0x85, 0xc8, +0x6c, 0x40, 0x04, 0xd0, 0x08, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x66, 0x00, 0x41, 0x46, 0xe8, +0x38, 0x02, 0x48, 0x83, 0xa0, +0x68, 0x00, 0x01, 0x34, 0x21, +0x68, 0x20, 0x01, 0xfc, 0x24, +0x66, 0x00, 0x00, 0x84, 0x40, +0x88, 0x84, 0x86, 0x80, 0x00, +0x13, 0xa2, 0x18, 0x83, 0x20, +0x68, 0x20, 0x02, 0x02, 0x24, +0x66, 0x00, 0x00, 0x84, 0x40, +0x88, 0x18, 0x98, 0x81, 0x0a, +0x54, 0x0b, 0x80, 0x86, 0x82, +0x54, 0x08, 0x00, 0x82, 0x89, +0x54, 0x05, 0x50, 0x83, 0x21, +0x88, 0x80, 0x95, 0x40, 0xa9, +0x08, 0x3a, 0x08, 0x49, 0x40, +0x68, 0x20, 0x00, 0x7e, 0x2c, +0x88, 0x8c, 0x88, 0x41, 0x42, +0x68, 0x00, 0x00, 0x48, 0x21, +0x68, 0x20, 0x00, 0x24, 0x24, +0x68, 0x20, 0x00, 0x72, 0x25, +0x40, 0x00, 0x00, 0x80, 0x6c, +0x66, 0x00, 0x00, 0x80, 0x08, +0x6c, 0x00, 0x02, 0xb6, 0x09, +0x68, 0x20, 0x00, 0x7f, 0xac, +0x88, 0x84, 0x86, 0x80, 0x00, +0x05, 0xc2, 0x18, 0x83, 0x20, +0x68, 0x20, 0x00, 0x4b, 0x24, +0x68, 0x20, 0x00, 0x78, 0x25, +0x88, 0x06, 0xc6, 0x60, 0x00, +0x08, 0x00, 0x86, 0xc0, 0x00, +0x2b, 0x80, 0x98, 0x88, 0xc8, +0x68, 0x20, 0x00, 0x83, 0x20, +0x68, 0x20, 0x00, 0x84, 0x21, +0xa4, 0x22, 0x36, 0x60, 0x04, +0x0c, 0x68, 0x8a, 0x42, 0x02, +0x5c, 0x8d, 0x00, 0x83, 0xa0, +0x5c, 0x08, 0x61, 0x8e, 0x89, +0xa0, 0x28, 0x09, 0x42, 0x0f, +0x25, 0x93, 0x8b, 0xc0, 0x39, +0x55, 0x01, 0x70, 0x83, 0x21, +0x88, 0x80, 0xa8, 0x40, 0x0b, +0x54, 0x0f, 0x82, 0x0a, 0x81, +0x94, 0xa0, 0xe2, 0x59, 0x30, +0xbc, 0x03, 0x98, 0x40, 0xc0, +0x00, 0x00, 0x08, 0x88, 0x89, +0x00, 0x00, 0x08, 0x48, 0x08, +0x54, 0x09, 0x40, 0x82, 0x36, +0xba, 0x14, 0x88, 0x48, 0xc0, +0x40, 0x00, 0x02, 0x80, 0x90, +0x98, 0x84, 0x8a, 0x28, 0x01, +0xa0, 0x04, 0x5a, 0x2c, 0x22, +0x86, 0x80, 0xaa, 0x10, 0x45, +0xab, 0xfb, 0x08, 0x81, 0xe2, +0x88, 0x16, 0x09, 0x82, 0x20, +0x85, 0x00, 0x85, 0x70, 0x98, +0x20, 0x82, 0x25, 0x50, 0x00, +0x21, 0x02, 0x35, 0x70, 0xa0, +0x21, 0x82, 0x68, 0x80, 0x66, +0x88, 0x2e, 0x68, 0x82, 0x65, +0xa2, 0x06, 0x48, 0x85, 0x25, +0x88, 0x36, 0x48, 0x83, 0xe0, +0x88, 0x47, 0x66, 0x60, 0x04, +0x06, 0xa6, 0x89, 0x80, 0x09, +0x5c, 0x08, 0x28, 0x82, 0x20, +0x88, 0x1a, 0x1a, 0x02, 0x20, +0x94, 0x02, 0xf5, 0x2c, 0xbc, +0x04, 0x94, 0x8a, 0x05, 0xe1, +0x42, 0x02, 0xc8, 0x83, 0x24, +0x5c, 0x00, 0x30, 0x83, 0xa0, +0x88, 0x12, 0x50, 0x00, 0x00, +0x86, 0x98, 0xa8, 0x48, 0x09, +0x54, 0x0b, 0x82, 0x01, 0x40, +0x98, 0x00, 0x9a, 0x22, 0xe4, +0x84, 0x8c, 0x98, 0x81, 0x64, +0x88, 0x1e, 0x06, 0x60, 0x04, +0x07, 0x0c, 0x08, 0x82, 0xa1, +0x88, 0x52, 0x58, 0x81, 0x24, +0x88, 0x1a, 0x08, 0x84, 0x36, +0xa2, 0x82, 0x5a, 0x80, 0x50, +0xa0, 0x04, 0x0a, 0x20, 0x64, +0x40, 0x00, 0x02, 0x08, 0x21, +0x64, 0x00, 0x40, 0x71, 0xaf, +0x55, 0x01, 0x2a, 0x08, 0x22, +0xa2, 0x08, 0x4a, 0x20, 0x22, +0x84, 0x40, 0x98, 0x60, 0x0a, +0x57, 0x8b, 0xaa, 0xbf, 0xe0, +0xa1, 0x4a, 0x4a, 0x08, 0x00, +0x85, 0x00, 0x88, 0x80, 0x64, +0x88, 0x0e, 0x08, 0x81, 0x76, +0x66, 0x00, 0x40, 0x53, 0x48, +0x2e, 0x96, 0x58, 0x80, 0x20, +0x88, 0x0a, 0x48, 0x41, 0x89, +0x44, 0x08, 0x00, 0x81, 0x36, +0x46, 0x0a, 0x41, 0x80, 0x08, +0x86, 0x14, 0x8a, 0x80, 0x20, +0x98, 0xe8, 0x02, 0xa0, 0x42, +0x23, 0x08, 0x05, 0x18, 0x48, +0x98, 0x42, 0x95, 0xd0, 0x40, +0x18, 0x46, 0x85, 0x90, 0xc0, +0x1e, 0x80, 0x09, 0xe8, 0x81, +0x43, 0xfa, 0xd0, 0x40, 0x02, +0x84, 0x85, 0x25, 0x16, 0x12, +0x22, 0x8c, 0x55, 0x16, 0x16, +0x86, 0x88, 0x02, 0x34, 0x22, +0x68, 0x00, 0x3f, 0xff, 0xc1, +0x68, 0x3f, 0xc0, 0x00, 0x03, +0x28, 0x86, 0x92, 0x88, 0xd2, +0x29, 0x05, 0x25, 0x18, 0x80, +0x06, 0x85, 0x20, 0x00, 0x00, +0x86, 0x00, 0x22, 0x31, 0x12, +0x29, 0x08, 0x08, 0x68, 0xd0, +0x00, 0x00, 0x08, 0x60, 0x00, +0x2a, 0x04, 0x53, 0x2b, 0xe8, +0xbc, 0x04, 0xd8, 0x60, 0x49, +0xba, 0x14, 0x88, 0x60, 0x7a, +0x00, 0x00, 0x0b, 0xa1, 0x40, +0x68, 0x00, 0x00, 0x2c, 0x20, +0x5c, 0x81, 0x03, 0x02, 0x74, +0x68, 0x01, 0x05, 0xdb, 0x2c, +0x80, 0x06, 0xc6, 0x80, 0x00, +0x22, 0x62, 0x18, 0x00, 0x61, +0x68, 0x01, 0x05, 0x47, 0xa1, +0x6c, 0x00, 0x02, 0xcc, 0x48, +0x46, 0x0a, 0x40, 0x00, 0x61, +0x84, 0x06, 0x10, 0x00, 0x00, +0x68, 0x00, 0x00, 0x07, 0x60, +0xab, 0xff, 0x09, 0x40, 0x2c, +0x55, 0x5f, 0x22, 0x04, 0x10, +0x59, 0x01, 0x00, 0x80, 0x76, +0xbc, 0x29, 0x89, 0x40, 0x2e, +0x32, 0x06, 0x0b, 0xc1, 0x40, +0x32, 0x0a, 0x0b, 0xc3, 0x51, +0x32, 0x0b, 0x0b, 0xc0, 0x88, +0x68, 0x20, 0x02, 0x74, 0x20, +0x68, 0x00, 0x00, 0x07, 0xa1, +0x66, 0x00, 0x41, 0x53, 0x60, +0x40, 0x00, 0x03, 0xc2, 0xb7, +0x68, 0x00, 0x00, 0x07, 0x21, +0x66, 0x00, 0x41, 0x54, 0x40, +0x66, 0x00, 0x41, 0x52, 0x08, +0xb0, 0x02, 0x4b, 0xc2, 0x37, +0x32, 0x0b, 0x0b, 0xc0, 0x88, +0x68, 0x20, 0x02, 0x4d, 0x20, +0x68, 0x00, 0x00, 0x07, 0xa1, +0x66, 0x00, 0x41, 0x53, 0x60, +0x40, 0x00, 0x03, 0xc1, 0x97, +0x68, 0x00, 0x00, 0x07, 0x21, +0x66, 0x00, 0x41, 0x54, 0x40, +0x66, 0x00, 0x41, 0x52, 0x08, +0xb0, 0x02, 0x4b, 0xc1, 0x17, +0x32, 0x0b, 0x0b, 0xc0, 0x88, +0x68, 0x00, 0x01, 0x8f, 0x20, +0x68, 0x00, 0x00, 0x07, 0xa1, +0x66, 0x00, 0x41, 0x53, 0x60, +0x40, 0x00, 0x03, 0xc0, 0x77, +0x68, 0x00, 0x00, 0x07, 0x21, +0x66, 0x00, 0x41, 0x54, 0x40, +0x66, 0x00, 0x41, 0x52, 0x08, +0xb0, 0x02, 0x48, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x03, 0x18, 0x09, +0x5d, 0x0a, 0x23, 0x01, 0xc6, +0x52, 0x0d, 0x72, 0xbf, 0xe0, +0x59, 0x01, 0x00, 0x80, 0xfa, +0x6c, 0x40, 0x03, 0x18, 0x4a, +0x88, 0x17, 0x64, 0x20, 0x74, +0x18, 0xe8, 0x95, 0x50, 0x16, +0x08, 0x04, 0x89, 0x8e, 0x88, +0x88, 0x00, 0x93, 0x20, 0x68, +0xbc, 0x07, 0x8b, 0x00, 0x0d, +0x88, 0x00, 0x95, 0x90, 0x54, +0x30, 0x00, 0xdb, 0xc0, 0x29, +0x98, 0x24, 0x89, 0x8e, 0x89, +0x88, 0x0c, 0x93, 0x20, 0x68, +0xbc, 0x09, 0x98, 0x81, 0xc8, +0x66, 0x00, 0x40, 0x77, 0x00, +0x68, 0x00, 0x00, 0x72, 0x20, +0x5c, 0x81, 0x00, 0x81, 0x88, +0x80, 0x20, 0x98, 0x40, 0x49, +0x32, 0x06, 0x0b, 0xc0, 0x71, +0x66, 0x00, 0x40, 0x77, 0xc0, +0x68, 0x00, 0x00, 0x87, 0x20, +0x39, 0x02, 0x08, 0x02, 0x09, +0x84, 0x04, 0x99, 0x8e, 0x88, +0x68, 0x00, 0x00, 0x84, 0x20, +0x68, 0x00, 0x00, 0x99, 0x21, +0x66, 0x00, 0x41, 0x44, 0xe8, +0x88, 0x08, 0x9b, 0x00, 0x0c, +0x68, 0x00, 0x00, 0x84, 0x20, +0x68, 0x00, 0x00, 0x99, 0x21, +0x66, 0x00, 0x41, 0x44, 0xe8, +0x88, 0x18, 0x98, 0x80, 0x09, +0x32, 0x02, 0x8b, 0xc1, 0x01, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x5c, 0x0e, 0x2a, 0xc4, 0xc0, +0x84, 0x00, 0x82, 0x51, 0x64, +0x6c, 0x40, 0x03, 0x18, 0x0a, +0x52, 0x8b, 0xa8, 0x02, 0x48, +0x6c, 0x40, 0x03, 0x18, 0x49, +0x68, 0x01, 0x05, 0x47, 0xa1, +0xbc, 0x05, 0xf8, 0x40, 0x61, +0x68, 0x00, 0x02, 0x4f, 0x20, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x00, 0x00, 0x08, 0x81, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x00, 0x71, 0x20, +0x68, 0x20, 0x00, 0x82, 0x22, +0x84, 0x00, 0x88, 0x50, 0x0a, +0x58, 0x0d, 0x02, 0xbf, 0xf0, +0x68, 0x20, 0x00, 0x81, 0x21, +0xbc, 0x03, 0x88, 0x80, 0x76, +0x66, 0x00, 0x40, 0xf3, 0x40, +0x68, 0x00, 0x00, 0x86, 0x20, +0x6c, 0x40, 0x01, 0x04, 0x08, +0x84, 0x00, 0xa3, 0x01, 0x30, +0x68, 0x20, 0x00, 0x82, 0x22, +0x40, 0x00, 0x03, 0xc0, 0x48, +0x68, 0x20, 0x00, 0x81, 0x21, +0x66, 0x00, 0x40, 0xf3, 0x40, +0x6c, 0x00, 0x00, 0xe2, 0x08, +0x6c, 0x40, 0x01, 0x04, 0x0a, +0x30, 0x1a, 0x0b, 0xc0, 0x41, +0x6c, 0x00, 0x01, 0x0c, 0x08, +0x30, 0x1a, 0x0b, 0xc0, 0x60, +0x68, 0x00, 0x02, 0x4f, 0x20, +0x40, 0x00, 0x03, 0xc1, 0x1f, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x5c, 0x0e, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0xa2, 0x49, 0x36, +0x6c, 0x40, 0x03, 0x18, 0x00, +0x52, 0x88, 0x20, 0x02, 0x4a, +0x68, 0x01, 0x05, 0x47, 0xa2, +0x6c, 0x40, 0x03, 0x18, 0x48, +0x84, 0x06, 0x20, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x01, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x03, 0x76, 0x08, +0x5c, 0x0e, 0x33, 0x01, 0x05, +0x24, 0x1a, 0x46, 0xe0, 0x00, +0x1a, 0xe2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x03, 0x76, 0x48, +0xbc, 0x05, 0x83, 0x81, 0x3d, +0x52, 0x4b, 0xc3, 0xc0, 0x6f, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x52, 0x0b, 0xc3, 0x80, 0x00, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x52, 0x4d, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0x92, 0x49, 0xae, +0x6c, 0x40, 0x03, 0x76, 0x48, +0x68, 0x01, 0x05, 0x47, 0xa1, +0x46, 0x0a, 0x40, 0x02, 0x4a, +0x84, 0x06, 0x10, 0x00, 0x00, +0x6c, 0x40, 0x03, 0x28, 0x08, +0x5c, 0x0e, 0x32, 0xbf, 0xf0, +0x52, 0x0d, 0x20, 0x80, 0x76, +0x6c, 0x40, 0x03, 0x28, 0x48, +0x66, 0x00, 0x00, 0x9b, 0xc8, +0x5c, 0x00, 0x63, 0x80, 0x00, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x5c, 0x0e, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0xa5, 0x24, 0x9b, +0x08, 0x03, 0x66, 0xc4, 0x00, +0x32, 0x80, 0x05, 0x24, 0x82, +0x00, 0x24, 0xa6, 0xc4, 0x00, +0x32, 0x84, 0x86, 0x80, 0x10, +0x54, 0x7a, 0xcb, 0xa1, 0x48, +0x84, 0x06, 0xca, 0x80, 0x10, +0x59, 0x01, 0x02, 0xbf, 0x40, +0xbc, 0x0f, 0x96, 0x80, 0x00, +0x15, 0xa2, 0x06, 0x80, 0x00, +0x15, 0x32, 0x25, 0xc8, 0x10, +0x18, 0xe8, 0x86, 0x80, 0x00, +0x1f, 0x22, 0x02, 0xa0, 0x64, +0x5d, 0x48, 0x20, 0x00, 0x00, +0x32, 0x1e, 0x0b, 0xff, 0xba, +0x40, 0x00, 0x00, 0x10, 0x50, +0x68, 0x00, 0x01, 0x56, 0x22, +0x5c, 0x81, 0x00, 0x40, 0x02, +0x5c, 0x00, 0x2a, 0x10, 0x10, +0x95, 0x03, 0x69, 0x40, 0x31, +0xa0, 0x47, 0x18, 0x81, 0x52, +0xa4, 0x14, 0x06, 0x80, 0x00, +0x15, 0x32, 0x22, 0x30, 0xac, +0x55, 0x03, 0x61, 0x82, 0x29, +0x5d, 0x48, 0x29, 0xd0, 0x83, +0x59, 0x0f, 0x41, 0x58, 0x37, +0x57, 0x0d, 0xd9, 0x58, 0xb4, +0x57, 0x03, 0x01, 0xc0, 0x84, +0x43, 0xf9, 0xd1, 0x60, 0x73, +0x96, 0x0f, 0x05, 0x1a, 0x0a, +0x24, 0x22, 0x35, 0xb0, 0x81, +0x2c, 0x0c, 0x15, 0x15, 0x88, +0x20, 0x02, 0x25, 0x70, 0x89, +0x08, 0x26, 0x15, 0x70, 0x89, +0x88, 0x37, 0x65, 0x15, 0x8d, +0x88, 0x1c, 0x85, 0x15, 0x89, +0x01, 0x84, 0x35, 0x15, 0x93, +0x01, 0x84, 0x25, 0x40, 0x90, +0x01, 0x84, 0x05, 0x40, 0x81, +0x01, 0x87, 0xa5, 0x15, 0x80, +0x01, 0x84, 0xa5, 0x15, 0x88, +0x01, 0x84, 0x08, 0x1a, 0xc0, +0x88, 0x06, 0x38, 0x82, 0xe3, +0x88, 0x3e, 0x2a, 0x41, 0x41, +0x68, 0x20, 0x00, 0x90, 0x23, +0x68, 0x20, 0x00, 0x8a, 0x24, +0x68, 0x20, 0x00, 0x8d, 0x25, +0x66, 0x00, 0x00, 0xb1, 0xe8, +0x40, 0x00, 0x02, 0x00, 0x60, +0x5c, 0x07, 0xc0, 0x81, 0x88, +0x51, 0x61, 0x23, 0x00, 0x51, +0x5b, 0x48, 0x10, 0x82, 0x20, +0x37, 0x08, 0x35, 0x70, 0x60, +0x18, 0xe8, 0x35, 0x04, 0x09, +0x08, 0x1d, 0x03, 0x68, 0x40, +0x68, 0x20, 0x02, 0x62, 0x22, +0x55, 0x02, 0xf3, 0x00, 0xfd, +0x23, 0x09, 0xb5, 0x18, 0x59, +0x98, 0x4e, 0x89, 0x84, 0xe9, +0x9c, 0x00, 0x19, 0xc0, 0x83, +0x94, 0x83, 0x39, 0x58, 0x31, +0x2e, 0x0c, 0xb3, 0x68, 0xc1, +0x37, 0x04, 0x72, 0xe1, 0xed, +0x62, 0x00, 0x00, 0x00, 0x15, +0x50, 0x4a, 0x49, 0x8e, 0xb5, +0x00, 0x00, 0x02, 0xf8, 0x09, +0x55, 0xd4, 0xd8, 0x81, 0x8b, +0x32, 0x01, 0x8b, 0xc0, 0x2b, +0x98, 0x34, 0x93, 0x61, 0x45, +0x62, 0x00, 0x00, 0x00, 0x27, +0x2a, 0x01, 0x15, 0xb4, 0xa1, +0x98, 0xeb, 0x52, 0xf8, 0xc9, +0x29, 0x96, 0x33, 0x20, 0x18, +0xbc, 0x03, 0xb9, 0x83, 0x41, +0x36, 0x04, 0x52, 0xa0, 0x29, +0x5d, 0x4c, 0x19, 0xd0, 0x01, +0x32, 0x19, 0x8b, 0xfd, 0x6a, +0x94, 0x87, 0x15, 0xc8, 0x10, +0x2c, 0x0c, 0x18, 0x81, 0x08, +0x51, 0x61, 0x20, 0x82, 0xa3, +0x51, 0xa1, 0x21, 0x01, 0x58, +0x5b, 0x08, 0x00, 0x82, 0xd4, +0x57, 0x08, 0x10, 0x84, 0x48, +0x2e, 0x11, 0x35, 0x15, 0x8d, +0x88, 0x3a, 0x05, 0x15, 0x89, +0x01, 0x84, 0x35, 0x15, 0x80, +0x01, 0x84, 0x25, 0x40, 0x90, +0x01, 0x84, 0x05, 0x15, 0x93, +0x01, 0x87, 0xa5, 0x40, 0x81, +0x01, 0x84, 0xa5, 0x15, 0x80, +0x20, 0x05, 0x05, 0x15, 0x88, +0x01, 0x84, 0x08, 0x1a, 0xc0, +0x88, 0x06, 0x3a, 0x04, 0x61, +0x68, 0x20, 0x00, 0x98, 0xa3, +0x68, 0x20, 0x00, 0x92, 0xa4, +0x68, 0x20, 0x00, 0x95, 0xa5, +0x66, 0x00, 0x00, 0xb1, 0xe8, +0x40, 0x00, 0x02, 0x08, 0x22, +0x5c, 0x07, 0xc0, 0x84, 0x08, +0x51, 0x61, 0x20, 0x82, 0x20, +0x5b, 0x48, 0x13, 0x80, 0x00, +0x5b, 0x84, 0x1a, 0x00, 0x10, +0x57, 0x06, 0x19, 0x01, 0x10, +0x68, 0x20, 0x02, 0x62, 0xa2, +0x50, 0x46, 0x90, 0x82, 0x94, +0x5c, 0x00, 0x18, 0x81, 0x53, +0x55, 0x02, 0xf3, 0x00, 0xfd, +0x23, 0x09, 0xb5, 0x18, 0x59, +0x98, 0x4e, 0x89, 0x84, 0xe9, +0x9c, 0x00, 0x19, 0xc0, 0x83, +0x94, 0x83, 0x39, 0x58, 0x31, +0x2e, 0x0c, 0xb3, 0x68, 0xc1, +0x37, 0x04, 0x72, 0xe1, 0xed, +0x62, 0x00, 0x00, 0x00, 0x15, +0x50, 0x4a, 0x49, 0x8e, 0xb5, +0x00, 0x00, 0x02, 0xf8, 0x09, +0x55, 0xd4, 0xd8, 0x81, 0x0b, +0x32, 0x01, 0x8b, 0xc0, 0x2b, +0x98, 0x34, 0x93, 0x61, 0x45, +0x62, 0x00, 0x00, 0x00, 0x27, +0x2a, 0x01, 0x15, 0xb4, 0xa1, +0x98, 0xeb, 0x52, 0xf8, 0xc9, +0x29, 0x96, 0x33, 0x20, 0x18, +0xbc, 0x03, 0xb9, 0x83, 0x41, +0x36, 0x04, 0x52, 0xa0, 0x29, +0x5d, 0x4c, 0x19, 0xd0, 0x01, +0x32, 0x19, 0x8b, 0xfd, 0x6a, +0x94, 0x87, 0x10, 0x00, 0x00, +0x6e, 0x40, 0x04, 0xc4, 0x34, +0x6e, 0x40, 0x04, 0xc5, 0x30, +0x51, 0xa1, 0x20, 0x83, 0x36, +0x54, 0x81, 0x23, 0xa1, 0x48, +0x6c, 0x40, 0x03, 0x2c, 0x48, +0x40, 0x00, 0x02, 0x80, 0xc0, +0xba, 0x14, 0x82, 0xe1, 0xa8, +0x40, 0x00, 0x01, 0x80, 0x08, +0x59, 0x06, 0x42, 0xbf, 0xd0, +0x49, 0xa9, 0xb8, 0x80, 0x76, +0xbc, 0x19, 0x89, 0xa0, 0x00, +0x32, 0x03, 0x0b, 0xc0, 0x29, +0x38, 0x10, 0x02, 0xa0, 0x76, +0x68, 0x00, 0x09, 0xc4, 0x09, +0x50, 0x41, 0x83, 0xa1, 0x11, +0x44, 0x08, 0x81, 0x01, 0x58, +0x5b, 0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x42, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x19, 0x02, 0x12, +0x29, 0x85, 0x13, 0x20, 0x08, +0xbc, 0x1a, 0x33, 0x60, 0x00, +0x37, 0x80, 0x0b, 0xc1, 0x77, +0x32, 0x02, 0x0b, 0xc0, 0x29, +0x38, 0x10, 0x02, 0xa0, 0x64, +0x68, 0x01, 0xff, 0xff, 0xc9, +0x50, 0x41, 0x03, 0xa1, 0x11, +0x44, 0x48, 0x81, 0x01, 0x58, +0x5b, 0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x42, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x19, 0x02, 0x12, +0x29, 0x85, 0x13, 0x20, 0x08, +0xbc, 0x02, 0x33, 0x60, 0x00, +0x37, 0x80, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, 0x00, +0x5b, 0x02, 0x03, 0x01, 0x01, +0x50, 0x43, 0x11, 0x84, 0x0a, +0x46, 0x08, 0x89, 0x83, 0x88, +0x44, 0x41, 0x09, 0x84, 0x8b, +0x98, 0x30, 0xa4, 0x47, 0x44, +0xab, 0xfe, 0x05, 0x08, 0x20, +0x08, 0x07, 0x60, 0x88, 0x82, +0x37, 0x80, 0x06, 0x80, 0x00, +0x9c, 0x40, 0x80, 0x84, 0x80, +0x6a, 0x00, 0x09, 0xc4, 0x02, +0x5b, 0x44, 0x11, 0x01, 0x58, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x40, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x26, 0xa0, 0x00, +0x9c, 0x40, 0x12, 0x98, 0x52, +0x32, 0x01, 0x0b, 0xc0, 0x3b, +0x88, 0x03, 0x63, 0x60, 0x00, +0x37, 0x80, 0x0b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, 0x00, +0xab, 0xf8, 0x09, 0x40, 0x36, +0x88, 0x04, 0xa8, 0x80, 0xe5, +0x88, 0x16, 0x48, 0x81, 0xe3, +0x88, 0x26, 0x28, 0x82, 0xf6, +0x66, 0x00, 0x00, 0xab, 0xa8, +0x40, 0x00, 0x01, 0x48, 0x35, +0x6a, 0x00, 0x09, 0xc4, 0x00, +0x5b, 0x40, 0x00, 0x83, 0x48, +0x5c, 0x00, 0x21, 0x05, 0x58, +0x88, 0x3c, 0x88, 0x84, 0x54, +0x00, 0x00, 0x08, 0x80, 0x0a, +0x51, 0x85, 0x20, 0x82, 0x22, +0x98, 0x22, 0x89, 0xd0, 0x02, +0x88, 0x4e, 0x86, 0x60, 0x00, +0x0a, 0xba, 0x89, 0x50, 0x35, +0x5b, 0x48, 0x3b, 0x01, 0xfe, +0x25, 0x9a, 0x06, 0x80, 0x01, +0xff, 0xfc, 0xab, 0xc0, 0x88, +0x55, 0x01, 0x00, 0x86, 0x48, +0x30, 0x1b, 0x8b, 0xc0, 0xcd, +0x88, 0x38, 0x16, 0x80, 0x01, +0xff, 0xfc, 0x0b, 0xc0, 0x87, +0x68, 0x00, 0x20, 0x00, 0x0a, +0x30, 0x1b, 0x8b, 0xc0, 0x4d, +0x40, 0x00, 0x00, 0x83, 0x81, +0x68, 0x00, 0x20, 0x00, 0x00, +0x59, 0x0a, 0x40, 0x81, 0xa2, +0xbc, 0x03, 0xb5, 0x50, 0x13, +0xac, 0x01, 0x09, 0x50, 0x50, +0x55, 0x02, 0x60, 0x81, 0xe2, +0x00, 0x00, 0x08, 0x84, 0xa8, +0x88, 0x82, 0x35, 0x18, 0x52, +0x08, 0x4c, 0x89, 0xd8, 0x04, +0x98, 0x22, 0x88, 0x60, 0x08, +0x9d, 0x80, 0x38, 0x83, 0x0a, +0x88, 0x6e, 0x46, 0x60, 0x00, +0x0a, 0xbe, 0x88, 0x58, 0x09, +0x88, 0x38, 0x83, 0x20, 0xe0, +0xbc, 0x13, 0x85, 0xc0, 0xfe, +0x19, 0x20, 0x19, 0x05, 0x12, +0x40, 0x00, 0x01, 0x07, 0x58, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x40, 0x08, 0x84, 0x16, +0x55, 0x00, 0x09, 0x07, 0x10, +0x6a, 0x00, 0x09, 0xc4, 0x02, +0x29, 0x88, 0x23, 0x20, 0x10, +0xbc, 0x03, 0xb3, 0x81, 0xfc, +0x36, 0x04, 0x13, 0x78, 0x41, +0x52, 0xc8, 0x41, 0x83, 0x48, +0x68, 0x00, 0x1f, 0xff, 0xcb, +0xbc, 0x07, 0x83, 0x69, 0x04, +0x30, 0x1e, 0x0b, 0xc0, 0xa5, +0x6a, 0x00, 0x1f, 0xff, 0xc1, +0x40, 0x00, 0x03, 0xc0, 0x67, +0x68, 0x00, 0x20, 0x00, 0x0b, +0x30, 0x1e, 0x0b, 0xc0, 0x25, +0x6a, 0x00, 0x20, 0x00, 0x01, +0x5c, 0x80, 0x80, 0x81, 0x22, +0x98, 0x34, 0x19, 0x50, 0x51, +0x88, 0x16, 0x20, 0x00, 0x00, +0x88, 0x6a, 0x38, 0x83, 0x08, +0x66, 0x00, 0x00, 0xaf, 0x88, +0x55, 0x00, 0x08, 0x58, 0x09, +0x5c, 0x0f, 0xf9, 0x83, 0x08, +0x25, 0x9c, 0x05, 0xb4, 0x82, +0x3c, 0x09, 0x86, 0x80, 0x01, +0xff, 0xfc, 0xb3, 0x01, 0xe0, +0xbc, 0x0d, 0xd8, 0x84, 0x88, +0x6a, 0x00, 0x1f, 0xff, 0xc0, +0x40, 0x00, 0x03, 0xc0, 0x87, +0x68, 0x00, 0x20, 0x00, 0x0b, +0x30, 0x1e, 0x0b, 0xc0, 0x4d, +0x40, 0x00, 0x00, 0x84, 0x88, +0x6a, 0x00, 0x20, 0x00, 0x00, +0x5c, 0x80, 0x80, 0x80, 0xa2, +0x5d, 0x88, 0x21, 0x83, 0x00, +0x59, 0x0d, 0x00, 0x86, 0x0b, +0x95, 0x05, 0x08, 0x83, 0x4b, +0x88, 0x3c, 0x88, 0x80, 0xe2, +0xbf, 0x77, 0xa8, 0x80, 0x0a, +0x88, 0x2b, 0x6b, 0xa1, 0x48, +0xa8, 0x08, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x03, 0x1c, 0x08, +0x5c, 0x0e, 0x33, 0x01, 0x05, +0x24, 0x1a, 0x46, 0xe0, 0x00, +0x1a, 0xe2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x03, 0x1c, 0x48, +0xbc, 0x05, 0x83, 0x81, 0x15, +0x52, 0x4b, 0xc3, 0xc0, 0xcf, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x52, 0x0b, 0xc3, 0x01, 0x0d, +0x25, 0x96, 0x0b, 0xc0, 0x68, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x6c, 0x00, 0x01, 0x46, 0x7a, +0x6c, 0x00, 0x01, 0x5a, 0x7a, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x52, 0x8d, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0x92, 0x51, 0xae, +0x6c, 0x40, 0x03, 0x1c, 0x48, +0x68, 0x01, 0x05, 0x47, 0xa1, +0x46, 0x0a, 0x40, 0x02, 0x4a, +0x84, 0x06, 0x10, 0x00, 0x00, +0xab, 0xfd, 0x08, 0x80, 0xc9, +0x5c, 0x09, 0xf8, 0x80, 0x4b, +0x88, 0x17, 0x59, 0x02, 0x5b, +0x88, 0x1d, 0x70, 0x00, 0x00, +0x6e, 0x00, 0x01, 0x08, 0x2d, +0x25, 0x9e, 0x8b, 0xc0, 0x60, +0x6c, 0x68, 0x08, 0x10, 0x03, +0x6c, 0x00, 0x01, 0x34, 0x53, +0x40, 0x00, 0x03, 0xc0, 0x67, +0x6c, 0x68, 0x08, 0x16, 0x03, +0x6c, 0x00, 0x01, 0x34, 0x53, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6e, 0x00, 0x01, 0x32, 0x2b, +0x25, 0x9d, 0x8b, 0xc0, 0x50, +0x6c, 0x68, 0x08, 0x12, 0x09, +0x6c, 0x00, 0x01, 0x36, 0x49, +0xbc, 0x07, 0x72, 0x59, 0xe8, +0xbc, 0x05, 0x06, 0xc6, 0x80, +0x81, 0x60, 0x96, 0xc0, 0x00, +0x13, 0x64, 0x90, 0x00, 0x00, +0x5c, 0x02, 0x29, 0x02, 0x13, +0x68, 0x00, 0x00, 0x00, 0x75, +0x6c, 0x68, 0x08, 0x06, 0x75, +0x6c, 0x00, 0x02, 0xc6, 0x49, +0x00, 0x00, 0x08, 0x81, 0x97, +0x88, 0x00, 0xb4, 0x60, 0xb4, +0x08, 0x13, 0x58, 0x80, 0x89, +0x40, 0x00, 0x02, 0x80, 0x30, +0x40, 0x00, 0x03, 0xa1, 0x60, +0x68, 0x20, 0x02, 0x4d, 0x20, +0x00, 0x00, 0x08, 0x40, 0x08, +0x32, 0x82, 0x0b, 0xc2, 0xa1, +0x6c, 0x00, 0x01, 0x88, 0x08, +0x6c, 0x40, 0x04, 0x98, 0x0a, +0x30, 0x93, 0x0b, 0xc1, 0x29, +0x5c, 0x80, 0x81, 0x8e, 0x8a, +0x68, 0x20, 0x02, 0x4b, 0xa0, +0x39, 0x02, 0x19, 0x40, 0x3c, +0x55, 0x03, 0x22, 0x00, 0x01, +0x3a, 0x90, 0x49, 0x42, 0xd4, +0x00, 0x00, 0x09, 0x40, 0x38, +0x30, 0x02, 0x0b, 0xc1, 0x62, +0x46, 0x0a, 0x41, 0x4a, 0x56, +0x94, 0x87, 0x60, 0x00, 0x00, +0x68, 0x20, 0x02, 0x4b, 0x21, +0x39, 0x04, 0x19, 0x48, 0x1a, +0x55, 0x02, 0x91, 0x48, 0x56, +0x5d, 0x44, 0x20, 0x0a, 0xc8, +0x00, 0x00, 0x09, 0x48, 0x3a, +0x30, 0x0a, 0x0b, 0xc0, 0x6a, +0x5c, 0x00, 0x41, 0x49, 0x74, +0x80, 0x2d, 0x09, 0x40, 0x56, +0x94, 0x05, 0x68, 0x40, 0x7a, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x68, 0x20, 0x01, 0x3c, 0x20, +0x5c, 0x0b, 0x62, 0xc0, 0x20, +0x5c, 0x00, 0x30, 0x40, 0x09, +0x51, 0x87, 0x7a, 0x04, 0x41, +0x68, 0x00, 0x01, 0x30, 0x20, +0x51, 0x8b, 0xc0, 0x08, 0x09, +0x84, 0x04, 0x86, 0x80, 0x00, +0x0d, 0xa2, 0x28, 0x48, 0x08, +0xa0, 0x06, 0x08, 0x10, 0x50, +0x6c, 0x40, 0x01, 0x98, 0x49, +0x6c, 0x40, 0x01, 0x9a, 0x49, +0x6c, 0x40, 0x02, 0x2c, 0x4b, +0x6c, 0x40, 0x01, 0x06, 0x48, +0x6c, 0x40, 0x01, 0x08, 0x48, +0x94, 0x24, 0x64, 0x60, 0xa4, +0x05, 0x07, 0xa8, 0x40, 0x7a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x20, 0x01, 0xad, 0x21, +0x68, 0x00, 0x01, 0x7c, 0x22, +0x5c, 0x81, 0x02, 0x08, 0x23, +0xa1, 0xde, 0x48, 0x50, 0x88, +0x86, 0x00, 0x94, 0x40, 0x80, +0x22, 0x02, 0x08, 0x50, 0x0a, +0x80, 0x00, 0x96, 0x80, 0x00, +0x18, 0xe2, 0x54, 0x44, 0xc0, +0x04, 0x80, 0x94, 0x44, 0x88, +0x22, 0xce, 0x1a, 0x01, 0x04, +0xda, 0x08, 0x04, 0x43, 0x10, +0x05, 0x80, 0xa4, 0x41, 0x4a, +0x04, 0x80, 0x88, 0x20, 0x0a, +0x44, 0x15, 0x40, 0x20, 0x0a, +0x6c, 0x00, 0x01, 0xe2, 0x40, +0x08, 0x20, 0x08, 0x60, 0x08, +0x68, 0x00, 0x00, 0xc4, 0x22, +0x44, 0x24, 0x00, 0x68, 0x08, +0x84, 0x00, 0x94, 0x40, 0x90, +0x01, 0x04, 0x26, 0xc0, 0x00, +0x1d, 0x64, 0x16, 0xc0, 0x00, +0x1e, 0xe4, 0x28, 0x10, 0x40, +0x00, 0x00, 0x08, 0x49, 0x08, +0x86, 0x30, 0x94, 0x40, 0x80, +0x3a, 0x14, 0x88, 0x50, 0x40, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x08, 0x08, 0x20, +0x5c, 0x08, 0x33, 0x01, 0x65, +0x5c, 0x00, 0xa0, 0x40, 0x00, +0x52, 0x0c, 0x02, 0xc0, 0x62, +0x68, 0x34, 0x00, 0x17, 0x21, +0x5c, 0x8c, 0x08, 0x40, 0x50, +0x5c, 0x82, 0x18, 0x48, 0x7a, +0x5c, 0x81, 0x02, 0x08, 0x81, +0x5c, 0x00, 0xd0, 0x48, 0x00, +0x52, 0x4a, 0x02, 0x0b, 0x22, +0x5c, 0x00, 0x40, 0x48, 0x50, +0xa0, 0x0e, 0x08, 0x50, 0x0b, +0x52, 0x0d, 0xcb, 0x04, 0xc7, +0x85, 0x05, 0x10, 0x00, 0x00, +0x84, 0x80, 0x12, 0x41, 0x49, +0x84, 0x85, 0x15, 0xc8, 0xb1, +0x00, 0x34, 0x88, 0x02, 0xc9, +0x5c, 0x88, 0x18, 0x01, 0xfa, +0x80, 0x07, 0xa8, 0x40, 0x4b, +0x80, 0x17, 0xa8, 0x03, 0xd2, +0xa0, 0x00, 0x18, 0x00, 0x50, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x10, 0x0e, 0x02, +0x25, 0x99, 0x0b, 0xff, 0xc1, +0x5c, 0x04, 0x50, 0x48, 0xd0, +0xa0, 0x4c, 0x08, 0x00, 0x09, +0x80, 0x0d, 0x08, 0x03, 0xd0, +0x80, 0x05, 0x26, 0xc4, 0x00, +0x4e, 0x84, 0x90, 0x00, 0x00, +0x6c, 0x70, 0x10, 0x0e, 0x02, +0x25, 0x99, 0x0b, 0xff, 0xc1, +0x5c, 0x83, 0x18, 0x01, 0xd0, +0x5c, 0x02, 0x20, 0x03, 0xc8, +0x5c, 0x82, 0x08, 0x02, 0xc8, +0x5c, 0x88, 0x08, 0x00, 0xfa, +0x5c, 0x03, 0xa2, 0x00, 0x01, +0x80, 0x07, 0xab, 0x04, 0x66, +0x84, 0x8c, 0xa8, 0x01, 0x7a, +0x46, 0x0a, 0x40, 0x02, 0xc8, +0x84, 0x05, 0x00, 0x00, 0x00, +0x32, 0x02, 0x0b, 0xc0, 0xc0, +0x68, 0x38, 0x08, 0x02, 0x20, +0x5c, 0x03, 0xa2, 0xc1, 0x00, +0x5c, 0x04, 0x70, 0x40, 0x48, +0xa0, 0x18, 0x04, 0x60, 0xa4, +0x00, 0x24, 0x88, 0x40, 0x4a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x08, 0x03, 0x20, +0x5c, 0x03, 0xe3, 0x04, 0x66, +0x5c, 0x88, 0x00, 0x40, 0x4a, +0x5c, 0x00, 0x70, 0x40, 0x7a, +0xa0, 0x16, 0x04, 0x60, 0xa4, +0x00, 0x24, 0x88, 0x40, 0x4a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x03, 0x47, 0xa0, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x00, 0x00, 0x00, +0x68, 0x00, 0x01, 0xc6, 0x20, +0x5c, 0x81, 0x0a, 0xc0, 0xc0, +0x6c, 0x40, 0x03, 0xa6, 0x09, +0x80, 0x08, 0x86, 0x80, 0x00, +0x1b, 0xb2, 0x46, 0x80, 0x00, +0x1d, 0x12, 0x14, 0x40, 0x90, +0x02, 0x08, 0x96, 0xc4, 0x00, +0x39, 0xe0, 0x84, 0x42, 0x08, +0x00, 0x88, 0x96, 0xc4, 0x00, +0x3a, 0xe0, 0x84, 0x42, 0x00, +0x3a, 0x11, 0x16, 0xc4, 0x00, +0x3b, 0x40, 0x8a, 0xbf, 0xd0, +0x88, 0x2f, 0x69, 0xa0, 0x02, +0x4d, 0x25, 0x00, 0x02, 0x4a, +0x51, 0x62, 0x09, 0x80, 0x4a, +0x44, 0x40, 0x00, 0x0a, 0x49, +0x51, 0x62, 0x00, 0x22, 0x4a, +0x51, 0x62, 0x91, 0x83, 0x09, +0x88, 0x26, 0x48, 0x80, 0x4d, +0x84, 0x84, 0xe8, 0x81, 0x49, +0x88, 0x0e, 0x18, 0x81, 0xe0, +0x68, 0x20, 0x01, 0xe0, 0x24, +0x66, 0x00, 0x40, 0xf7, 0xe8, +0x46, 0x08, 0x08, 0x80, 0x0a, +0x88, 0x22, 0x08, 0x80, 0x09, +0x84, 0x04, 0x86, 0x82, 0x00, +0x1e, 0x32, 0x46, 0x60, 0x04, +0x0f, 0x7e, 0x88, 0x81, 0x0a, +0x5c, 0x82, 0x00, 0x82, 0x20, +0x88, 0x1a, 0x48, 0x00, 0x09, +0x86, 0x04, 0x88, 0x80, 0x60, +0x68, 0x20, 0x01, 0xbf, 0x24, +0x68, 0x00, 0x01, 0x92, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x82, 0x00, 0x81, 0xa0, +0x88, 0x22, 0x48, 0x00, 0x09, +0x86, 0x14, 0x88, 0x81, 0x60, +0x68, 0x20, 0x01, 0xbf, 0x24, +0x68, 0x00, 0x01, 0x9e, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x82, 0x00, 0x80, 0xa0, +0x88, 0x1a, 0x48, 0x00, 0x09, +0x86, 0x14, 0x88, 0x81, 0xe0, +0x68, 0x20, 0x01, 0xbf, 0x24, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x81, 0x00, 0x80, 0x21, +0x68, 0x20, 0x01, 0xbf, 0x20, +0x88, 0x0a, 0x2a, 0x00, 0x64, +0x80, 0x80, 0x98, 0x51, 0x48, +0x88, 0x0e, 0x48, 0x82, 0x61, +0x68, 0x00, 0x01, 0x92, 0x23, +0x66, 0x00, 0x40, 0x53, 0x48, +0x40, 0x00, 0x02, 0x18, 0x40, +0x5c, 0x81, 0x00, 0x80, 0x20, +0x88, 0x12, 0x16, 0x80, 0x00, +0x19, 0xe2, 0x48, 0x40, 0xc8, +0xa2, 0x04, 0x08, 0x08, 0x09, +0x88, 0x0a, 0x48, 0x80, 0x61, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x81, 0x00, 0x81, 0x20, +0x68, 0x00, 0x01, 0xaa, 0x24, +0x84, 0x0c, 0x8a, 0x20, 0x40, +0x88, 0x1a, 0x18, 0x80, 0xa4, +0x80, 0x80, 0x98, 0x80, 0xe1, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x83, 0x00, 0x81, 0xa0, +0x88, 0x22, 0x48, 0x40, 0xc8, +0xa2, 0x4a, 0x08, 0x22, 0x09, +0x66, 0x00, 0x40, 0xf7, 0x68, +0x40, 0x00, 0x00, 0x60, 0x08, +0x5c, 0x83, 0x00, 0x80, 0x24, +0x00, 0x00, 0x0a, 0x20, 0x00, +0xa0, 0x4a, 0x08, 0x22, 0x09, +0x66, 0x00, 0x40, 0xf7, 0x68, +0x40, 0x00, 0x00, 0x60, 0x08, +0x5c, 0x83, 0x00, 0x80, 0xa4, +0x00, 0x00, 0x0a, 0x20, 0x00, +0xa0, 0x4a, 0x08, 0x22, 0x09, +0x66, 0x00, 0x40, 0xf7, 0x68, +0x86, 0x00, 0x88, 0x82, 0xb6, +0x68, 0x00, 0x03, 0x71, 0xa0, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x0a, 0x80, 0x30, +0x68, 0x00, 0x01, 0xc5, 0x24, +0x6c, 0x00, 0x03, 0xa0, 0x09, +0x5b, 0x0a, 0x22, 0xbf, 0x90, +0x5c, 0x81, 0x00, 0x60, 0x09, +0x68, 0x00, 0x01, 0xba, 0x20, +0xa4, 0x10, 0x48, 0x40, 0x0a, +0x5b, 0x0c, 0x38, 0x20, 0x49, +0x82, 0x04, 0x88, 0x20, 0x4b, +0x82, 0x04, 0x88, 0x20, 0x4a, +0x86, 0x04, 0x98, 0x81, 0xf6, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x17, 0x00, 0x86, 0xc0, 0x00, +0x18, 0x20, 0x96, 0xc0, 0x00, +0x31, 0x80, 0xa8, 0x80, 0x4a, +0x88, 0x0c, 0x98, 0x81, 0x48, +0x66, 0x00, 0x40, 0xfd, 0x68, +0x40, 0x00, 0x02, 0x24, 0xa0, +0x68, 0x00, 0x01, 0xba, 0x20, +0x68, 0x20, 0x01, 0xdc, 0x24, +0x39, 0x06, 0x06, 0x80, 0x00, +0x1c, 0x52, 0x18, 0x02, 0x08, +0x86, 0x00, 0x95, 0x70, 0xb0, +0x00, 0xa0, 0x98, 0x60, 0x88, +0x57, 0x09, 0x50, 0x82, 0xe0, +0x88, 0x24, 0x28, 0x83, 0x61, +0x68, 0x20, 0x01, 0xbc, 0x24, +0x68, 0x00, 0x01, 0x90, 0x20, +0x66, 0x00, 0x40, 0x53, 0x48, +0x40, 0x00, 0x01, 0x80, 0x09, +0x68, 0x20, 0x01, 0xbc, 0x24, +0x68, 0x00, 0x01, 0x9c, 0x20, +0x66, 0x00, 0x40, 0x53, 0x48, +0x40, 0x00, 0x00, 0x82, 0x09, +0x68, 0x00, 0x01, 0x90, 0x20, +0x68, 0x20, 0x02, 0x79, 0x24, +0x84, 0x08, 0x96, 0x80, 0x00, +0x1e, 0x82, 0x06, 0x60, 0x04, +0x05, 0x34, 0x08, 0x82, 0xa4, +0x68, 0x00, 0x01, 0x9c, 0x20, +0x86, 0x04, 0x86, 0x82, 0x00, +0x27, 0x92, 0x48, 0x40, 0x89, +0x68, 0x00, 0x01, 0xea, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x86, 0x00, 0x82, 0xa4, +0x55, 0x01, 0x28, 0x83, 0x20, +0x82, 0x00, 0x88, 0x40, 0x49, +0x40, 0x00, 0x00, 0x82, 0x64, +0x68, 0x00, 0x01, 0x90, 0x20, +0x68, 0x20, 0x01, 0xbc, 0x24, +0x66, 0x00, 0x40, 0xf8, 0x60, +0x5c, 0x86, 0x00, 0x83, 0x24, +0x68, 0x00, 0x01, 0x9c, 0x20, +0x82, 0x00, 0x88, 0x83, 0xe4, +0x68, 0x20, 0x01, 0xbc, 0x24, +0x66, 0x00, 0x40, 0xf8, 0x60, +0x68, 0x00, 0x01, 0x97, 0x24, +0x68, 0x00, 0x01, 0x90, 0x20, +0x40, 0x00, 0x00, 0x60, 0x08, +0x68, 0x20, 0x01, 0xbc, 0x24, +0x66, 0x00, 0x40, 0xf9, 0x80, +0x68, 0x00, 0x01, 0xa3, 0x24, +0x68, 0x00, 0x01, 0x9c, 0x20, +0x40, 0x00, 0x00, 0x60, 0x08, +0x68, 0x20, 0x01, 0xbc, 0x24, +0x66, 0x00, 0x40, 0xf9, 0x80, +0x68, 0x00, 0x01, 0x97, 0x24, +0x00, 0x00, 0x08, 0x62, 0x0a, +0x68, 0x20, 0x02, 0x7c, 0x24, +0x66, 0x00, 0x00, 0xf2, 0xe8, +0x6c, 0x00, 0x03, 0x2e, 0x09, +0x88, 0x2a, 0x46, 0xc0, 0x00, +0x34, 0x60, 0x98, 0x63, 0x48, +0x68, 0x00, 0x01, 0xa3, 0x20, +0x68, 0x20, 0x02, 0x7e, 0x24, +0x66, 0x00, 0x00, 0xf2, 0xe8, +0x40, 0x00, 0x00, 0x42, 0x0a, +0x5c, 0x83, 0x00, 0x82, 0x24, +0x88, 0x32, 0x08, 0x22, 0x09, +0x84, 0x34, 0x88, 0x82, 0x64, +0x68, 0x20, 0x02, 0x47, 0x24, +0x68, 0x00, 0x01, 0xe4, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x5c, 0x83, 0x00, 0x83, 0xa0, +0x68, 0x20, 0x02, 0x47, 0x24, +0x80, 0x20, 0x98, 0x82, 0xe0, +0x68, 0x00, 0x01, 0xe6, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x88, 0x10, 0x93, 0x69, 0x44, +0x6c, 0x40, 0x03, 0xb0, 0x0a, +0x58, 0x0d, 0x01, 0x8e, 0x88, +0xbc, 0x03, 0xa5, 0x50, 0x13, +0x88, 0x08, 0x9b, 0x00, 0x0c, +0x36, 0x94, 0x03, 0x01, 0x80, +0xbc, 0x03, 0xa5, 0x50, 0x1c, +0x08, 0x00, 0x9b, 0x00, 0x08, +0x36, 0x94, 0x53, 0x01, 0xa8, +0xbc, 0x01, 0x2b, 0x00, 0x0f, +0x32, 0x02, 0x0b, 0xc0, 0x69, +0x88, 0x22, 0x43, 0x20, 0x38, +0xbc, 0x03, 0x13, 0x20, 0x00, +0x40, 0x00, 0x03, 0xc0, 0x60, +0x6c, 0x40, 0x03, 0xb2, 0x09, +0x6c, 0x00, 0x03, 0xaa, 0x49, +0x6c, 0x00, 0x03, 0xac, 0x49, +0x68, 0x00, 0x01, 0xe0, 0x20, +0x86, 0x00, 0x96, 0x82, 0x00, +0x0a, 0xa2, 0x46, 0x60, 0x04, +0x05, 0x34, 0x08, 0x82, 0xa0, +0x88, 0x04, 0x86, 0x82, 0x00, +0x0c, 0x22, 0x48, 0x40, 0x09, +0x68, 0x00, 0x01, 0xe2, 0x20, +0x66, 0x00, 0x40, 0x53, 0x40, +0x66, 0x00, 0x41, 0x01, 0x48, +0x55, 0x01, 0x28, 0x80, 0x08, +0x6c, 0x00, 0x03, 0xaa, 0x09, +0x32, 0x02, 0x8b, 0xc0, 0xac, +0x39, 0x04, 0x16, 0x80, 0x00, +0x1b, 0xd2, 0x40, 0x00, 0x00, +0x40, 0x00, 0x00, 0x60, 0x09, +0x42, 0x08, 0x78, 0x60, 0xc9, +0x5c, 0x81, 0x02, 0xc0, 0x62, +0x68, 0x00, 0x01, 0x97, 0x24, +0x5c, 0x81, 0x02, 0xc0, 0x62, +0x55, 0x3f, 0x68, 0x20, 0xfa, +0x82, 0x27, 0xa8, 0x21, 0x7a, +0x82, 0x27, 0xa6, 0xc0, 0x00, +0x3a, 0xa4, 0x96, 0xc0, 0x00, +0x37, 0xc7, 0xa8, 0x60, 0x7a, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x3a, 0xc0, 0x93, 0x20, 0x28, +0xbc, 0x07, 0x46, 0x80, 0x00, +0x1c, 0x82, 0x40, 0x00, 0x00, +0x40, 0x00, 0x00, 0x60, 0x09, +0x42, 0x06, 0x38, 0x60, 0xc9, +0x68, 0x00, 0x01, 0xa3, 0x24, +0x2a, 0x7e, 0xd8, 0x20, 0xfa, +0x82, 0x27, 0xa8, 0x21, 0x7a, +0x82, 0x27, 0xa6, 0xc0, 0x00, +0x3a, 0xc4, 0x96, 0xc0, 0x00, +0x39, 0x27, 0xa8, 0x60, 0x7a, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x3b, 0x20, 0x93, 0x20, 0x28, +0xbc, 0x04, 0x06, 0xc0, 0x00, +0x37, 0xc7, 0xa6, 0xc0, 0x00, +0x39, 0x27, 0xa3, 0x81, 0x2c, +0x6e, 0x00, 0x01, 0xae, 0x2d, +0x25, 0x92, 0x8b, 0xc2, 0x89, +0x88, 0x22, 0x43, 0x81, 0x3c, +0x25, 0x92, 0x8b, 0xc2, 0x41, +0x6c, 0x00, 0x03, 0xca, 0x09, +0x36, 0x94, 0x06, 0xc4, 0x00, +0x4e, 0xa0, 0x99, 0x80, 0x08, +0x30, 0x96, 0x0b, 0xc1, 0x24, +0x6c, 0x00, 0x03, 0xce, 0x08, +0x36, 0x90, 0x09, 0x80, 0x08, +0x30, 0x96, 0x0b, 0xc0, 0xc4, +0x6c, 0x40, 0x04, 0xee, 0x09, +0x32, 0x02, 0x8b, 0xc1, 0x20, +0x2a, 0x7e, 0xd6, 0xc0, 0x00, +0x39, 0x27, 0xa6, 0xc0, 0x00, +0x37, 0xc7, 0xa6, 0xc4, 0x00, +0x4e, 0xe4, 0x9b, 0xc0, 0xa7, +0x68, 0x20, 0x02, 0x76, 0x20, +0x6c, 0x00, 0x03, 0x7c, 0x7a, +0x6c, 0x00, 0x03, 0x92, 0x7a, +0x00, 0x00, 0x08, 0x40, 0x09, +0x40, 0x00, 0x00, 0x40, 0xc9, +0x66, 0x00, 0x40, 0xfb, 0x68, +0x86, 0x20, 0x98, 0x82, 0xa4, +0x6c, 0x00, 0x03, 0x06, 0x48, +0x66, 0x00, 0x40, 0xfb, 0x68, +0x40, 0x00, 0x00, 0x62, 0x09, +0x6c, 0x00, 0x03, 0x0a, 0x48, +0x68, 0x00, 0x03, 0xca, 0x24, +0x88, 0x1b, 0x6b, 0xa1, 0x48, +0x6c, 0x00, 0x02, 0xea, 0x64, +0x40, 0x00, 0x02, 0x80, 0x70, +0x68, 0x00, 0x03, 0x46, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x00, 0x00, 0x00, +0x57, 0x0d, 0x40, 0x60, 0x89, +0x2e, 0x14, 0x09, 0x80, 0x08, +0x32, 0x02, 0x0b, 0xc0, 0xe4, +0x32, 0x02, 0x0b, 0xc1, 0x83, +0x86, 0x00, 0xa2, 0xe1, 0xad, +0x5b, 0x4a, 0x00, 0x60, 0xc9, +0x98, 0x00, 0x96, 0xc4, 0x00, +0x24, 0x60, 0xa3, 0x01, 0xa8, +0xbc, 0x0f, 0x53, 0x61, 0x85, +0x86, 0x0c, 0x9b, 0xa1, 0x40, +0x86, 0x00, 0xa2, 0x81, 0xad, +0x5b, 0x4a, 0x00, 0x60, 0xc9, +0x98, 0x00, 0x96, 0xc4, 0x00, +0x24, 0x60, 0xa3, 0x01, 0xa8, +0xbc, 0x03, 0x5b, 0xa1, 0x48, +0x86, 0x0c, 0xa0, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x5c, 0x81, 0x01, 0x8e, 0x88, +0x68, 0x00, 0x01, 0x90, 0x20, +0x68, 0x00, 0x01, 0x9c, 0x21, +0x68, 0x00, 0x01, 0xa8, 0x22, +0x55, 0x01, 0x33, 0x80, 0x00, +0x55, 0x03, 0xb0, 0x00, 0x7a, +0x5d, 0x0c, 0x30, 0x08, 0x7a, +0x32, 0x2b, 0x0b, 0xff, 0xaa, +0x40, 0x00, 0x00, 0x10, 0x7a, +0x68, 0x00, 0x01, 0xc1, 0x22, +0x68, 0x00, 0x01, 0xcc, 0x21, +0x68, 0x00, 0x01, 0xb6, 0x20, +0x55, 0x03, 0x20, 0x10, 0x7a, +0x5d, 0x08, 0x20, 0x08, 0x7a, +0x32, 0x26, 0x0b, 0xff, 0xaa, +0x80, 0x07, 0xa6, 0x80, 0x00, +0x1d, 0x52, 0x06, 0x80, 0x00, +0x34, 0x62, 0x16, 0xc4, 0x00, +0x3b, 0x20, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x14, 0x60, 0xa4, +0x04, 0x04, 0x88, 0x40, 0xc8, +0x40, 0x00, 0x03, 0x80, 0x00, +}; diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Code_2_1_0_3_2_1.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Code_2_1_0_3_2_1.h new file mode 100755 index 0000000000000000000000000000000000000000..7b9a3c8adadfb6c48fa1778f5768117a5b41c18f --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/LC898124EP3_Code_2_1_0_3_2_1.h @@ -0,0 +1,1969 @@ +// Time Stamp : 2019/09/05 20:09:45 + +//VERNUM [011b0201] [02000003] + +//#define SEL_MODEL 2 +//#define SELECT_VENDOR 1 +//#define SELECT_ACT 0 +//#define SELECT_GYRO 3 +//#define MASTER_SLAVE 2 +//#define FRA_ENABLE 1 + +#define CHECKSUM_COMMAND_DMA_2_1_0_3_2_1 0x00041834 +#define CHECKSUM_COMMAND_DMB_2_1_0_3_2_1 0x0004186e + +#define LC898124EP3_DMA_ByteSize_2_1_0_3_2_1 0x0054 +#define LC898124EP3_DMA_CheckSum_2_1_0_3_2_1 0x0800650D + +#define LC898124EP3_DMB_ByteSize_2_1_0_3_2_1 0x0470 +#define LC898124EP3_DMB_CheckSum_2_1_0_3_2_1 0x9F29251C + +#define LC898124EP3_PMCheckSum_2_1_0_3_2_1 0x00095D1D +#define LC898124EP3_PMSize_2_1_0_3_2_1 1636 + +const unsigned char LC898124EP3_DM_2_1_0_3_2_1[] = { +0x20, 0xC0, 0x00, 0x80, 0x06, 0x30, +0x20, 0xC4, 0x00, 0x80, 0x06, 0x34, +0x20, 0xC8, 0x00, 0x80, 0x06, 0x38, +0x20, 0xCC, 0x00, 0x80, 0x06, 0x3c, +0x20, 0xD0, 0x00, 0x80, 0x06, 0x40, +0x20, 0xD4, 0x00, 0x80, 0x06, 0x44, +0x20, 0xD8, 0x00, 0x80, 0x06, 0x48, +0x20, 0xDC, 0x00, 0x80, 0x06, 0x4c, +0x20, 0xE0, 0x00, 0x80, 0x06, 0x4c, +0x20, 0xE4, 0x00, 0x80, 0x06, 0x50, +0x20, 0xE8, 0x00, 0x80, 0x06, 0x54, +0x20, 0xEC, 0x00, 0x80, 0x06, 0x58, +0x20, 0xF0, 0x00, 0x80, 0x06, 0xec, +0x20, 0xF4, 0x00, 0x80, 0x06, 0x5c, +0x20, 0xF8, 0x00, 0x80, 0x06, 0x5c, +0x20, 0xFC, 0x00, 0x80, 0x06, 0x2c, +0x27, 0x68, 0x00, 0x00, 0x00, 0x05, +0x27, 0x6C, 0x80, 0x00, 0x00, 0x01, +0x27, 0x70, 0x7f, 0xff, 0xff, 0xff, +0x27, 0x74, 0x80, 0x00, 0x00, 0x01, +0x27, 0x78, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0x00, 0x01, 0x1b, 0x02, 0x01, +0xA0, 0x04, 0x02, 0x00, 0x00, 0x03, +0xA0, 0x90, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0x94, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0x98, 0x80, 0x00, 0x00, 0x01, +0xA0, 0xA4, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xAC, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xB0, 0x02, 0x07, 0x56, 0x79, +0xA0, 0xB4, 0x8a, 0xdf, 0xbd, 0x3f, +0xA0, 0xB8, 0x6b, 0x7b, 0xa9, 0x6d, +0xA0, 0xBC, 0x76, 0x5b, 0x66, 0xab, +0xA0, 0xC0, 0x84, 0xbd, 0xe2, 0xd3, +0xA0, 0xC4, 0x77, 0x60, 0xef, 0x39, +0xA0, 0xC8, 0x7c, 0x1e, 0xd2, 0x0d, +0xA0, 0xD8, 0x5a, 0x9d, 0xf7, 0xab, +0xA0, 0xDC, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xE4, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xE8, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xEC, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xF0, 0x7f, 0xff, 0xff, 0xff, +0xA0, 0xF4, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x00, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x14, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x18, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0x1C, 0xca, 0x3d, 0x97, 0xb5, +0xA1, 0x20, 0x00, 0x39, 0x1a, 0x59, +0xA1, 0x24, 0x75, 0x50, 0x33, 0x99, +0xA1, 0x28, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0x2C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x30, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x34, 0x80, 0x00, 0x00, 0x01, +0xA1, 0x40, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x48, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x4C, 0x02, 0x07, 0x56, 0x79, +0xA1, 0x50, 0x8a, 0xdf, 0xbd, 0x3f, +0xA1, 0x54, 0x6b, 0x7b, 0xa9, 0x6d, +0xA1, 0x58, 0x76, 0x5b, 0x66, 0xab, +0xA1, 0x5C, 0x84, 0xbd, 0xe2, 0xd3, +0xA1, 0x60, 0x77, 0x60, 0xef, 0x39, +0xA1, 0x64, 0x7c, 0x1e, 0xd2, 0x0d, +0xA1, 0x74, 0x5a, 0x9d, 0xf7, 0xab, +0xA1, 0x78, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x7C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x80, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x84, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x88, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x8C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x90, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0x9C, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xB0, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xB4, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0xB8, 0xca, 0x3d, 0x97, 0xb5, +0xA1, 0xBC, 0x00, 0x39, 0x1a, 0x59, +0xA1, 0xC0, 0x75, 0x50, 0x33, 0x99, +0xA1, 0xC4, 0x00, 0x1c, 0x8d, 0x2d, +0xA1, 0xC8, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xCC, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xD0, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xD4, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xD8, 0x38, 0x00, 0x00, 0x00, +0xA1, 0xDC, 0xc8, 0x00, 0x00, 0x00, +0xA1, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xE4, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xE8, 0x7f, 0xff, 0xff, 0xff, +0xA1, 0xEC, 0x80, 0x00, 0x00, 0x01, +0xA1, 0xF0, 0x38, 0x00, 0x00, 0x00, +0xA1, 0xF4, 0xc8, 0x00, 0x00, 0x00, +0xA1, 0xF8, 0x03, 0x05, 0x00, 0x01, +0xA1, 0xFC, 0x00, 0x01, 0x01, 0x00, +0xA2, 0x00, 0x01, 0x00, 0x03, 0x05, +0xA2, 0x04, 0x00, 0x12, 0x74, 0x74, +0xA2, 0x14, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0x1C, 0x7f, 0xff, 0xff, 0xff, +0xA2, 0x6C, 0x00, 0x07, 0xff, 0xff, +0xA3, 0x38, 0x01, 0x00, 0x02, 0x01, +0xA3, 0x3C, 0x01, 0x00, 0x02, 0x01, +0xA3, 0x40, 0x00, 0x0b, 0x6a, 0x7b, +0xA3, 0x44, 0x7f, 0xe9, 0x2b, 0x09, +0xA3, 0x48, 0x00, 0x0b, 0x6a, 0x7b, +0xA3, 0x60, 0x28, 0x00, 0x00, 0x00, +0xA3, 0x64, 0x0c, 0x99, 0x97, 0x19, +0xA3, 0x68, 0x0a, 0xcc, 0xca, 0xa8, +0xA3, 0x6C, 0x0e, 0x66, 0x63, 0x8a, +0xA3, 0x70, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0x74, 0x7f, 0xff, 0xff, 0xff, +0xA3, 0xF4, 0x00, 0x64, 0x00, 0x05, +0xA4, 0x0C, 0x00, 0x00, 0x02, 0xd8, +0xA4, 0x24, 0x00, 0x00, 0x02, 0xfc, +0xA4, 0x34, 0x80, 0x00, 0x00, 0x01, +0xA4, 0x38, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0x3C, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0x44, 0x00, 0x30, 0x77, 0xae, +0xA4, 0x48, 0x1c, 0x66, 0x20, 0x7e, +0xA4, 0x4C, 0x00, 0x00, 0x00, 0x1e, +0xA4, 0x50, 0x00, 0x00, 0x00, 0x01, +0xA4, 0x54, 0x00, 0x04, 0x00, 0x00, +0xA4, 0x58, 0x00, 0x00, 0x00, 0x80, +0xA4, 0x60, 0x00, 0x10, 0x00, 0x00, +0xA4, 0x64, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0x68, 0x00, 0x00, 0x40, 0x00, +0xA4, 0x6C, 0x00, 0x10, 0x00, 0x00, +0xA4, 0x70, 0x00, 0x00, 0x03, 0xe8, +0xA4, 0x74, 0x00, 0x00, 0x00, 0x04, +0xA4, 0x78, 0x00, 0x00, 0x32, 0x00, +0xA4, 0x7C, 0x0a, 0x3d, 0x00, 0x00, +0xA4, 0x80, 0x00, 0x00, 0x06, 0x29, +0xA4, 0x84, 0x00, 0x30, 0x00, 0x00, +0xA4, 0x88, 0x28, 0x00, 0x00, 0x00, +0xA4, 0x8C, 0x00, 0x00, 0x80, 0x00, +0xA4, 0x98, 0x00, 0x04, 0x00, 0x00, +0xA4, 0x9C, 0x00, 0x40, 0x00, 0x00, +0xA4, 0xA0, 0x7f, 0xfe, 0x20, 0x00, +0xA4, 0xA4, 0x00, 0x07, 0x69, 0x8a, +0xA4, 0xA8, 0x54, 0x91, 0x9a, 0x57, +0xA4, 0xAC, 0x00, 0x00, 0x00, 0xec, +0xA4, 0xB8, 0x00, 0x02, 0x6c, 0x62, +0xA4, 0xBC, 0xad, 0x99, 0x86, 0xfc, +0xA4, 0xC0, 0x7c, 0x7a, 0xf7, 0x9f, +0xA4, 0xC4, 0x55, 0xeb, 0x81, 0x65, +0xA4, 0xC8, 0x00, 0x00, 0x91, 0x9e, +0xA4, 0xCC, 0x00, 0x00, 0x06, 0x99, +0xA4, 0xD0, 0xad, 0x72, 0xde, 0x6b, +0xA4, 0xD4, 0x52, 0x96, 0x44, 0x0d, +0xA4, 0xD8, 0x00, 0x00, 0x01, 0x14, +0xA4, 0xDC, 0x00, 0x00, 0x08, 0xcd, +0xA4, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA4, 0xE8, 0x28, 0x00, 0x00, 0x00, +0xA4, 0xEC, 0x61, 0x86, 0x18, 0x60, +0xA4, 0xF0, 0x00, 0x00, 0x0a, 0x30, +0xA4, 0xF8, 0x01, 0xc0, 0x00, 0x00, +0xA4, 0xFC, 0x00, 0xbe, 0x00, 0x00, +0xA5, 0x00, 0x00, 0xe6, 0x00, 0x00, +0xA5, 0x04, 0x01, 0x1d, 0x00, 0x00, +0xA5, 0x88, 0x5f, 0x37, 0x59, 0xdf, +0xA5, 0x8C, 0x5f, 0xff, 0xff, 0xff, +0xA5, 0x9C, 0x00, 0xb4, 0x00, 0xb4, +0xA5, 0xA0, 0x06, 0x00, 0x00, 0x00, +0xA5, 0xEC, 0x00, 0x00, 0x03, 0x98, +0xA5, 0xF0, 0x00, 0x04, 0x18, 0xac, +0xA5, 0xF4, 0x00, 0x00, 0x06, 0x7a, +0xA5, 0xF8, 0x00, 0x04, 0x18, 0xf4, +0xA5, 0xFC, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x00, 0x00, 0x04, 0x1a, 0x80, +0xA6, 0x04, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x08, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x0C, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x10, 0x00, 0x00, 0x04, 0x56, +0xA6, 0x14, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x18, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x1C, 0x00, 0x00, 0x04, 0x34, +0xA6, 0x20, 0x00, 0x04, 0x1b, 0xbe, +0xA6, 0x24, 0x00, 0x04, 0x1b, 0xbe, +0xA6, 0x28, 0x00, 0x04, 0x15, 0x1e, +0xA6, 0x78, 0x47, 0xae, 0xfe, 0x3f, +0xA6, 0xBC, 0x16, 0x22, 0xf6, 0x0f, +0xA6, 0xC0, 0x53, 0xba, 0x13, 0xe3, +0xA6, 0xC4, 0x16, 0x22, 0xf6, 0x0f, +0xA6, 0xDC, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xE0, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xE4, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xE8, 0x7f, 0xff, 0xff, 0xff, +0xA6, 0xF0, 0x82, 0x35, 0xee, 0x09, +0xA6, 0xF4, 0x7d, 0x6c, 0xb0, 0xcd, +0xA6, 0xF8, 0x7f, 0xa2, 0x9e, 0xd5, +0xA6, 0xFC, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x00, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x04, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x08, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x0C, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x10, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x14, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x18, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x1C, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x20, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x24, 0x7f, 0xa9, 0x52, 0xcb, +0xA7, 0x28, 0x00, 0x2b, 0x56, 0x9b, +0xA7, 0x2C, 0x00, 0x74, 0x52, 0x6f, +0xA7, 0x30, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x34, 0x3a, 0x99, 0x29, 0xc5, +0xA7, 0x38, 0x00, 0x00, 0x00, 0x02, +0xA7, 0x3C, 0x01, 0xff, 0xff, 0xff, +0xA7, 0x4C, 0x01, 0xff, 0xff, 0xff, +0xA7, 0x5C, 0x01, 0xff, 0xff, 0xff, +0xA7, 0x60, 0x03, 0xc5, 0x18, 0xe6, +0xA7, 0x64, 0x00, 0x00, 0x1a, 0x68, +0xA7, 0x68, 0x00, 0x13, 0x9d, 0x01, +0xA7, 0x6C, 0x00, 0x0f, 0xff, 0xff, +0xA7, 0x7C, 0x13, 0xff, 0xff, 0xff, +0xA7, 0x80, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x84, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x8C, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x90, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0x98, 0x00, 0x00, 0x00, 0xe1, +0xA7, 0x9C, 0x00, 0x00, 0xf0, 0xe3, +0xA7, 0xA0, 0x00, 0x7d, 0x86, 0x6e, +0xA7, 0xAC, 0x00, 0x00, 0x00, 0x04, +0xA7, 0xB0, 0x00, 0x08, 0xbe, 0x1d, +0xA7, 0xB4, 0x00, 0x00, 0x27, 0x10, +0xA7, 0xB8, 0x00, 0x00, 0x00, 0x0a, +0xA7, 0xF8, 0x7f, 0xff, 0xff, 0xff, +0xA7, 0xFC, 0x04, 0xcc, 0xcc, 0xd0, +0xA8, 0x00, 0x7f, 0xff, 0xff, 0xff, +0xA8, 0x04, 0x80, 0x00, 0x00, 0x01, +0xA8, 0x10, 0x7f, 0xff, 0xff, 0xff, +0xA8, 0x14, 0x05, 0x1e, 0xb8, 0x50, +0xA8, 0x18, 0x7f, 0xff, 0xff, 0xff, +0xA8, 0x1C, 0x80, 0x00, 0x00, 0x01, +0xA8, 0x20, 0x00, 0x05, 0x24, 0x28, +0xA8, 0x24, 0x7f, 0xf5, 0xb7, 0xaf, +0xA8, 0x28, 0x00, 0x05, 0x24, 0x28, +0xA8, 0x2C, 0x33, 0x33, 0x33, 0x40, +0xA8, 0x30, 0x19, 0x99, 0x99, 0xa0, +0xA8, 0x38, 0xe0, 0x00, 0x00, 0x01, +0xA8, 0x40, 0x26, 0x66, 0x66, 0x80, +0xA8, 0x44, 0x33, 0x33, 0x33, 0x40, +0xA8, 0x4C, 0xe0, 0x00, 0x00, 0x01, +0xA8, 0x54, 0x80, 0x02, 0x92, 0x21, +0xA8, 0x58, 0x7f, 0xfa, 0xdb, 0xbd, +0xA8, 0x5C, 0x7f, 0xfd, 0x6d, 0xdf, +0xA8, 0x60, 0x00, 0x40, 0x00, 0x00, +0xA8, 0x64, 0x5f, 0x37, 0x59, 0xdf, +0xA8, 0x68, 0x5f, 0xff, 0xff, 0xff, +0xA8, 0x6C, 0x00, 0x58, 0xb9, 0x0b, +0xA8, 0x70, 0x10, 0x00, 0x00, 0x00, +0xA8, 0x74, 0x2a, 0xaa, 0xaa, 0xaa, +0xA8, 0x78, 0x19, 0x99, 0x99, 0x99, +0xA8, 0x7C, 0x12, 0x49, 0x24, 0x92, +0xA8, 0x80, 0x0e, 0x38, 0xe3, 0x8e, +0xA8, 0x84, 0x0b, 0xa2, 0xe8, 0xba, +0xA8, 0x88, 0x09, 0xd8, 0x9d, 0x89, +0xA8, 0x8C, 0x08, 0x88, 0x88, 0x88, +0xA8, 0x90, 0x07, 0x87, 0x87, 0x87, +0xA8, 0x94, 0x37, 0x96, 0xf6, 0x29, +0xA8, 0x98, 0x2a, 0xaa, 0xaa, 0xaa, +0xA8, 0x9C, 0x19, 0x99, 0x99, 0x99, +0xA8, 0xA0, 0x12, 0x49, 0x24, 0x92, +0xA8, 0xA4, 0x0e, 0x38, 0xe3, 0x8e, +0xA8, 0xA8, 0x0b, 0xa2, 0xe8, 0xba, +0xA8, 0xAC, 0x09, 0xd8, 0x9d, 0x89, +0xA8, 0xB0, 0x08, 0x88, 0x88, 0x88, +0xA8, 0xB4, 0x07, 0x87, 0x87, 0x87, +0xA8, 0xB8, 0x32, 0x43, 0xf6, 0xa6, +0xA8, 0xBC, 0x64, 0x87, 0xed, 0x4d, +0xA8, 0xC0, 0x32, 0x43, 0xf6, 0xa7, +0xA8, 0xC4, 0xcd, 0xbc, 0x09, 0x59, +0xA8, 0xC8, 0x80, 0x00, 0x00, 0x00, +0xA8, 0xCC, 0x00, 0x0c, 0x90, 0xfe, +0xA8, 0xD0, 0x00, 0x19, 0x21, 0xfb, +0xA8, 0xD4, 0x1f, 0xff, 0xff, 0xff, +0xA8, 0xD8, 0x61, 0x89, 0x37, 0x4b, +0xA8, 0xDC, 0x1e, 0x76, 0xc8, 0xb4, +0xA8, 0xE0, 0x64, 0x87, 0xed, 0x4d, +0xA8, 0xE4, 0x9b, 0x78, 0x12, 0xb3, +0xA8, 0xE8, 0x32, 0x43, 0xf6, 0xa9, +0xA8, 0xEC, 0x64, 0x87, 0xed, 0x51, +0xA8, 0xF0, 0x00, 0x2d, 0x82, 0xd8, +0xA8, 0xF4, 0xfa, 0xaa, 0xaa, 0xab, +0xA8, 0xF8, 0x40, 0x00, 0x00, 0x00, +0xA8, 0xFC, 0x1c, 0xa5, 0xdb, 0xe1, +0xA9, 0x00, 0x16, 0x7f, 0xff, 0x4c, +0xA9, 0x04, 0x2c, 0xff, 0xfe, 0x98, +0xA9, 0x18, 0x01, 0x00, 0x00, 0x00, +0xA9, 0x1C, 0x00, 0x16, 0xd2, 0xed, +0xA9, 0x20, 0x7f, 0xd2, 0x5a, 0x25, +0xA9, 0x24, 0x00, 0x16, 0xd2, 0xed, +0xA9, 0x28, 0x00, 0x06, 0x00, 0x0a, +0xA9, 0x3C, 0x77, 0x0a, 0x3d, 0x80, +0xA9, 0x40, 0x04, 0x00, 0x00, 0x00, +0xA9, 0x44, 0x7f, 0xfe, 0x20, 0x00, +0xA9, 0x48, 0x7f, 0xb0, 0x00, 0x00, +0xA9, 0x4C, 0x00, 0x00, 0x20, 0x00, +0xA9, 0x50, 0x03, 0x00, 0x00, 0x00, +0xA9, 0x54, 0x7f, 0xf4, 0x00, 0x00, +0xA9, 0x60, 0x00, 0x48, 0x00, 0x00, +0xA9, 0x64, 0x7f, 0xf0, 0x00, 0x00, +0xA9, 0x68, 0x00, 0x00, 0x04, 0x00, +0xA9, 0x6C, 0x1f, 0xff, 0xff, 0xff, +0xA9, 0x70, 0x7f, 0x00, 0x00, 0x00, +0xA9, 0x74, 0x00, 0x00, 0x02, 0x8c, +0xA9, 0x7C, 0x0c, 0xdc, 0x61, 0x39, +0xA9, 0x80, 0x0a, 0x49, 0xe7, 0x60, +0xA9, 0x84, 0x00, 0xa0, 0x00, 0x00, +0xA9, 0xA8, 0x01, 0x20, 0x00, 0x00, +}; + +const unsigned char LC898124EP3_PM_2_1_0_3_2_1[] = { +0x64, 0x00, 0x00, 0x02, 0x07, +0x64, 0x00, 0x00, 0x6a, 0x27, +0x64, 0x00, 0x40, 0x1d, 0x87, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x64, 0x00, 0x00, 0x6d, 0xa7, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x64, 0x00, 0x40, 0x23, 0x47, +0x64, 0x00, 0x40, 0x27, 0x87, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, 0x00, +0x66, 0x00, 0x00, 0x33, 0xe8, +0x40, 0x00, 0x02, 0xbf, 0xc0, +0x5c, 0x00, 0x62, 0xfe, 0x22, +0x6c, 0x70, 0x28, 0x06, 0x48, +0x68, 0x34, 0x00, 0x1b, 0x20, +0x68, 0x03, 0xf9, 0xff, 0xc9, +0x5c, 0x81, 0x00, 0x40, 0x0a, +0x54, 0x4b, 0xaa, 0xc0, 0x61, +0x5c, 0x10, 0xf0, 0x40, 0x49, +0x5c, 0x02, 0xf9, 0xc1, 0x00, +0x5c, 0x00, 0x68, 0x00, 0x48, +0x80, 0x04, 0x88, 0x02, 0xc8, +0x5c, 0x00, 0xb0, 0x02, 0x4a, +0xb0, 0x62, 0x08, 0x40, 0x50, +0xa0, 0x22, 0x08, 0x40, 0x00, +0x68, 0x00, 0x06, 0x00, 0x02, +0x54, 0x84, 0x13, 0x1d, 0xf0, +0x5c, 0x0d, 0x90, 0x00, 0xd2, +0x6c, 0x68, 0x08, 0x08, 0x4b, +0x5c, 0x0e, 0x38, 0x40, 0x50, +0xa0, 0x08, 0x0b, 0x08, 0x08, +0x68, 0x34, 0x08, 0x4a, 0x24, +0x80, 0x05, 0x08, 0x40, 0x50, +0xa2, 0x02, 0x08, 0x60, 0x48, +0x80, 0x04, 0x98, 0x00, 0x4a, +0x68, 0x00, 0x00, 0x2b, 0x24, +0xac, 0x7e, 0x08, 0x00, 0x4a, +0x68, 0x20, 0x01, 0x4f, 0x21, +0x86, 0x00, 0x85, 0x20, 0xf2, +0x2c, 0x58, 0x08, 0x02, 0x4a, +0xac, 0x40, 0x08, 0x48, 0x0b, +0x52, 0x45, 0xf3, 0x06, 0x07, +0x86, 0x04, 0x88, 0x02, 0x4b, +0x84, 0x84, 0xa8, 0x40, 0x4b, +0xb0, 0x01, 0xc6, 0x60, 0x04, +0x03, 0x66, 0x8a, 0x40, 0xc0, +0x5c, 0x81, 0x02, 0x40, 0xc0, +0x94, 0x02, 0xdb, 0x07, 0xfc, +0x30, 0x12, 0x8b, 0xc1, 0x08, +0x68, 0x20, 0x00, 0x1b, 0x24, +0x23, 0x4e, 0xd8, 0x20, 0x49, +0x88, 0x06, 0x46, 0x60, 0x04, +0x03, 0x66, 0x85, 0xc0, 0x06, +0xb0, 0x03, 0xca, 0x40, 0xc0, +0x94, 0x02, 0xd5, 0x1a, 0x76, +0x88, 0x02, 0x0b, 0xc0, 0x6f, +0x40, 0x00, 0x00, 0x40, 0x49, +0x6c, 0x40, 0x00, 0x36, 0x7a, +0x40, 0x00, 0x00, 0x60, 0xfa, +0x66, 0x00, 0x40, 0x42, 0xa0, +0x6e, 0x00, 0x01, 0xae, 0x2d, +0x38, 0x11, 0xc2, 0x59, 0x28, +0xbc, 0x05, 0x06, 0x60, 0x04, +0x02, 0xdc, 0x0b, 0xc0, 0xcf, +0x5c, 0x00, 0x6b, 0x80, 0x00, +0x66, 0x00, 0x40, 0x2d, 0xc0, +0x6e, 0x00, 0x01, 0xae, 0x2c, +0x5c, 0x08, 0xf3, 0x00, 0x0d, +0x52, 0x0d, 0x03, 0x80, 0x00, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x6c, 0x40, 0x03, 0x1e, 0x49, +0x6c, 0x40, 0x03, 0x1a, 0x49, +0x66, 0x00, 0x00, 0x1a, 0xe0, +0x66, 0x00, 0x00, 0x7e, 0x80, +0x6e, 0x00, 0x00, 0x8c, 0xad, +0x38, 0x1b, 0xc3, 0x01, 0x28, +0x40, 0x00, 0x03, 0xc0, 0x40, +0x68, 0x00, 0x3f, 0xff, 0xc9, +0x6e, 0x40, 0x00, 0x08, 0x75, +0x66, 0x00, 0x41, 0x38, 0x40, +0x6e, 0x40, 0x00, 0x08, 0x3d, +0x68, 0x00, 0x01, 0x00, 0x08, +0x28, 0x92, 0xc3, 0x20, 0x20, +0xbc, 0x09, 0x93, 0x81, 0x1d, +0x6e, 0x00, 0x01, 0xae, 0x2c, +0x24, 0x16, 0x06, 0xe0, 0x00, +0x1a, 0xe6, 0x06, 0x60, 0x00, +0x04, 0x74, 0x83, 0x80, 0x04, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x66, 0x00, 0x41, 0x46, 0x80, +0x66, 0x00, 0x00, 0x70, 0xe0, +0x68, 0x00, 0x01, 0x30, 0x20, +0x6c, 0x40, 0x02, 0x4e, 0x08, +0x6c, 0x40, 0x02, 0x2a, 0x48, +0x5c, 0x00, 0x73, 0x01, 0x6d, +0x6c, 0x40, 0x01, 0x5a, 0x7a, +0x6c, 0x40, 0x01, 0x8a, 0x7a, +0x5c, 0x04, 0x21, 0x46, 0x66, +0x5c, 0x0d, 0xf8, 0x40, 0x49, +0x66, 0x00, 0x40, 0x2e, 0xe8, +0x5c, 0x1f, 0x6b, 0x03, 0x6e, +0x6c, 0x00, 0x00, 0x56, 0x09, +0x38, 0x1d, 0x62, 0x59, 0xa8, +0xbc, 0x05, 0x83, 0x81, 0xc4, +0x52, 0x49, 0x6b, 0x80, 0x00, +0x6c, 0x00, 0x00, 0x56, 0x49, +0x68, 0x00, 0x00, 0x65, 0xa0, +0x6c, 0x00, 0x01, 0xb0, 0x60, +0x66, 0x00, 0x00, 0x76, 0x40, +0x68, 0x00, 0x00, 0xe0, 0x20, +0x6c, 0x40, 0x04, 0xd4, 0x09, +0x39, 0x02, 0x08, 0x00, 0x49, +0x6c, 0x00, 0x00, 0x8e, 0x7a, +0x84, 0x0f, 0xa8, 0x40, 0x7a, +0x66, 0x00, 0x00, 0x94, 0x00, +0x68, 0x38, 0x08, 0x46, 0x20, +0x5c, 0x0e, 0xa2, 0xfa, 0xc0, +0x9c, 0x00, 0x08, 0x80, 0x60, +0xa0, 0x02, 0x08, 0x80, 0xe0, +0xa0, 0x02, 0x08, 0x81, 0x60, +0xa0, 0x02, 0x0a, 0x00, 0x20, +0x88, 0x1e, 0x0b, 0xc0, 0x4f, +0x5c, 0x00, 0xea, 0xc4, 0xc0, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x02, 0xc6, 0x0a, +0x32, 0xa3, 0x0b, 0xff, 0xa1, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x6c, 0x00, 0x02, 0xc6, 0x7a, +0xa0, 0x00, 0x48, 0x02, 0x0a, +0x25, 0x93, 0x0b, 0xc0, 0x89, +0x88, 0x26, 0x02, 0x49, 0x34, +0x82, 0x24, 0x86, 0x80, 0x00, +0x0e, 0x62, 0x06, 0xc4, 0x00, +0x31, 0x84, 0x98, 0x60, 0x60, +0x38, 0x13, 0xc6, 0xe0, 0x00, +0x1a, 0xea, 0xd2, 0x59, 0x28, +0xbc, 0x39, 0x06, 0x80, 0x00, +0x06, 0x5a, 0x09, 0x88, 0x08, +0x6c, 0x00, 0x01, 0xb0, 0x09, +0x30, 0x12, 0x86, 0x80, 0x00, +0x06, 0x72, 0x0b, 0xc0, 0x88, +0x98, 0x80, 0x83, 0x01, 0x28, +0xbc, 0x2d, 0x16, 0x60, 0x00, +0x07, 0xb4, 0x89, 0x8e, 0x88, +0x40, 0x00, 0x03, 0xc2, 0x87, +0x6c, 0x70, 0x10, 0x8c, 0x08, +0x5c, 0x08, 0x28, 0x80, 0x20, +0x52, 0x0b, 0x20, 0x80, 0xa4, +0x6c, 0x70, 0x10, 0x8c, 0x48, +0x5c, 0x81, 0x02, 0xfc, 0xc2, +0x5c, 0x87, 0x08, 0x40, 0x0a, +0x5c, 0x00, 0x58, 0x40, 0x88, +0x86, 0x08, 0x08, 0x81, 0x20, +0x88, 0x1a, 0x48, 0x40, 0x8b, +0x82, 0x00, 0x28, 0x21, 0x01, +0x68, 0x00, 0x01, 0x8e, 0x20, +0xac, 0x7e, 0x28, 0x02, 0xd0, +0x82, 0x15, 0x38, 0x40, 0xd2, +0x68, 0x00, 0x01, 0x7c, 0x21, +0x86, 0x00, 0x06, 0xc0, 0x00, +0x2f, 0x84, 0xa5, 0x24, 0xa2, +0x80, 0x04, 0xb8, 0x48, 0xc8, +0x84, 0x15, 0x18, 0x60, 0x49, +0x66, 0x00, 0x00, 0x73, 0x00, +0x66, 0x00, 0x00, 0x6d, 0xc0, +0x66, 0x00, 0x00, 0x1c, 0x00, +0x88, 0x22, 0x00, 0x00, 0x00, +0x84, 0x02, 0x0b, 0xa0, 0x80, +0x6c, 0x00, 0x00, 0xf0, 0x09, +0x6c, 0x00, 0x01, 0x1a, 0x08, +0x22, 0x86, 0xd6, 0x83, 0x40, +0x80, 0x02, 0x06, 0xc4, 0x00, +0x49, 0xa0, 0xa2, 0x28, 0x64, +0x6c, 0x68, 0x10, 0x00, 0x49, +0x59, 0x41, 0x80, 0x44, 0x48, +0xbc, 0x07, 0x06, 0xc0, 0x00, +0x1b, 0x02, 0x0b, 0xa0, 0x80, +0x6c, 0x00, 0x02, 0xea, 0x20, +0x40, 0x00, 0x03, 0xa0, 0x80, +0x66, 0x00, 0x41, 0xca, 0x40, +0x6c, 0x00, 0x02, 0x3c, 0x20, +0x40, 0x00, 0x03, 0xa0, 0x80, +0x68, 0x00, 0x01, 0x16, 0x20, +0x68, 0x20, 0x00, 0xf1, 0x24, +0x68, 0x00, 0x01, 0x1a, 0x21, +0x68, 0x20, 0x00, 0xf7, 0x25, +0x68, 0x00, 0x01, 0x00, 0x22, +0x66, 0x00, 0x40, 0x5d, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x09, +0x38, 0x10, 0x42, 0x59, 0x28, +0xbc, 0x03, 0x16, 0xc0, 0x00, +0x13, 0xc2, 0x0b, 0xa0, 0x80, +0x68, 0x00, 0x01, 0x2b, 0x20, +0x66, 0x00, 0x41, 0x48, 0x20, +0x46, 0x0e, 0x03, 0x80, 0x00, +0xbf, 0x6c, 0xf3, 0x81, 0xd4, +0x68, 0x00, 0x00, 0x68, 0xa0, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x06, 0x00, 0x00, 0x00, +0x68, 0x00, 0x00, 0x65, 0xa0, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x06, 0x00, 0x00, 0x00, +0x68, 0x00, 0x00, 0x6a, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x06, 0x00, 0x00, 0x00, +0x68, 0x00, 0x00, 0x67, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x06, 0x00, 0x00, 0x00, +0x5c, 0x81, 0x01, 0x8e, 0x88, +0x68, 0x00, 0x01, 0x76, 0x20, +0x2a, 0x06, 0x43, 0xa1, 0x04, +0x32, 0x2a, 0x0b, 0xff, 0xca, +0x80, 0x07, 0xa6, 0xc0, 0x00, +0x1c, 0x67, 0xa0, 0x00, 0x00, +0x6c, 0x40, 0x02, 0x78, 0x08, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x1b, 0x24, 0x80, 0x00, 0x00, +0x68, 0x20, 0x00, 0x24, 0x21, +0x68, 0x00, 0x00, 0x9a, 0x20, +0x5c, 0x82, 0x02, 0xc0, 0x21, +0x5c, 0x08, 0xa0, 0x08, 0x0b, +0x80, 0x08, 0x96, 0x82, 0x00, +0x04, 0xb2, 0x44, 0x43, 0x80, +0x04, 0x00, 0x98, 0x20, 0x0a, +0x6e, 0x00, 0x01, 0xae, 0x2f, +0x44, 0x31, 0x02, 0xbf, 0x70, +0x52, 0xc9, 0xc0, 0x81, 0x64, +0x88, 0x1e, 0x18, 0x82, 0x76, +0x88, 0x2d, 0x69, 0x04, 0x58, +0x42, 0x04, 0x48, 0x85, 0x54, +0x90, 0x35, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x86, 0x0a, +0x40, 0x00, 0x03, 0xc0, 0x7f, +0x6c, 0x00, 0x01, 0x74, 0x09, +0x68, 0x00, 0x00, 0x9c, 0x20, +0x00, 0x00, 0x08, 0x40, 0x8a, +0x84, 0x00, 0x98, 0x85, 0xca, +0x40, 0x00, 0x00, 0x86, 0x49, +0x68, 0x20, 0x00, 0x85, 0x24, +0x66, 0x00, 0x40, 0x88, 0xe8, +0x6e, 0x40, 0x01, 0x12, 0x27, +0x68, 0x20, 0x00, 0x85, 0x20, +0x88, 0x84, 0x8a, 0x00, 0x88, +0x94, 0x02, 0x78, 0x86, 0x0a, +0x88, 0x58, 0x96, 0x60, 0x04, +0x08, 0x8e, 0x8a, 0x04, 0x4c, +0x6e, 0x00, 0x01, 0xae, 0x2d, +0x5c, 0x08, 0xf0, 0x85, 0xc8, +0x52, 0xcd, 0x40, 0x88, 0xc8, +0xbc, 0x21, 0x98, 0x88, 0x09, +0x68, 0x20, 0x00, 0x90, 0x2c, +0x68, 0x20, 0x00, 0x8a, 0x24, +0x68, 0x20, 0x00, 0x8d, 0x25, +0x40, 0x00, 0x00, 0x80, 0x6c, +0x66, 0x00, 0x40, 0x78, 0x80, +0x6c, 0x40, 0x00, 0x4a, 0x09, +0x44, 0x08, 0x00, 0x85, 0x89, +0x68, 0x20, 0x00, 0x98, 0xac, +0x88, 0x84, 0x86, 0x82, 0x00, +0x09, 0x2a, 0x46, 0x82, 0x00, +0x09, 0x5a, 0x58, 0x80, 0x6c, +0x90, 0x65, 0x88, 0x85, 0xd4, +0x66, 0x00, 0x40, 0x78, 0x80, +0x6c, 0x40, 0x00, 0x98, 0x09, +0x40, 0x00, 0x03, 0xc0, 0xcf, +0x44, 0x08, 0x00, 0x88, 0xc8, +0x6c, 0x40, 0x00, 0x4a, 0x08, +0x44, 0x21, 0x00, 0x85, 0x89, +0x6c, 0x40, 0x00, 0x98, 0x08, +0x44, 0x20, 0x01, 0x06, 0x5a, +0x40, 0x00, 0x00, 0x85, 0xd6, +0x68, 0x00, 0x00, 0x7d, 0x20, +0x90, 0x61, 0x2a, 0x04, 0x21, +0x88, 0x59, 0x68, 0x85, 0xe1, +0x90, 0x65, 0x88, 0x87, 0x54, +0x66, 0x00, 0x40, 0x52, 0x08, +0x5c, 0x00, 0x71, 0x80, 0x89, +0x90, 0x61, 0x06, 0x80, 0x00, +0x09, 0x22, 0x08, 0x87, 0x14, +0xa0, 0x42, 0x18, 0x86, 0xc8, +0x40, 0x00, 0x00, 0x86, 0x61, +0x66, 0x00, 0x40, 0x52, 0x08, +0x5c, 0x00, 0x71, 0x80, 0x09, +0x5c, 0x84, 0x10, 0x81, 0xa1, +0x5c, 0x83, 0x00, 0x85, 0xa0, +0x5c, 0x81, 0x08, 0x48, 0x09, +0x88, 0x1c, 0x8a, 0x05, 0x80, +0x90, 0x41, 0x08, 0x01, 0x08, +0x88, 0x51, 0x44, 0x40, 0xc0, +0x08, 0x62, 0x46, 0xc0, 0x00, +0x1d, 0xe0, 0x85, 0x40, 0x80, +0x22, 0x58, 0x18, 0x81, 0x25, +0x90, 0x31, 0x28, 0x68, 0x09, +0x80, 0x90, 0x88, 0x82, 0x96, +0x44, 0x0d, 0x41, 0x80, 0x09, +0x6c, 0x00, 0x01, 0xea, 0x0a, +0x54, 0x0c, 0x80, 0x02, 0x49, +0x98, 0x00, 0x88, 0x02, 0x8a, +0x57, 0x0d, 0x50, 0x0a, 0x48, +0x98, 0x08, 0xa8, 0x0a, 0x80, +0x57, 0x01, 0x00, 0x81, 0x49, +0x51, 0x61, 0xa0, 0x82, 0xc8, +0x51, 0xa1, 0x21, 0x80, 0x09, +0x6c, 0x40, 0x04, 0xd0, 0x4a, +0x6c, 0x40, 0x04, 0xd2, 0x49, +0x51, 0x61, 0x68, 0x83, 0x61, +0x68, 0x00, 0x3f, 0xff, 0xcb, +0x68, 0x3f, 0xc0, 0x00, 0x0a, +0x54, 0x4f, 0x68, 0x83, 0xe0, +0x28, 0x9a, 0x42, 0x91, 0x65, +0x6c, 0x40, 0x03, 0x2a, 0x49, +0x68, 0x00, 0x01, 0x34, 0x21, +0x68, 0x20, 0x01, 0xfc, 0x24, +0x66, 0x00, 0x00, 0x32, 0x60, +0x88, 0x84, 0x86, 0x80, 0x00, +0x13, 0xa2, 0x18, 0x83, 0x20, +0x68, 0x20, 0x02, 0x02, 0x24, +0x66, 0x00, 0x00, 0x32, 0x60, +0x88, 0x18, 0x98, 0x82, 0x8a, +0x54, 0x0b, 0x80, 0x86, 0x82, +0x54, 0x08, 0x00, 0x81, 0x09, +0x54, 0x05, 0x50, 0x83, 0x21, +0x88, 0x80, 0x95, 0x40, 0xa9, +0x08, 0x3a, 0x08, 0x49, 0x40, +0x68, 0x20, 0x00, 0x7e, 0x2c, +0x88, 0x8c, 0x88, 0x41, 0x42, +0x68, 0x00, 0x00, 0x48, 0x21, +0x68, 0x20, 0x00, 0x24, 0x24, +0x68, 0x20, 0x00, 0x72, 0x25, +0x40, 0x00, 0x00, 0x80, 0x6c, +0x68, 0x00, 0x01, 0x5d, 0x22, +0x66, 0x00, 0x00, 0x2d, 0xe8, +0x6c, 0x00, 0x02, 0xb6, 0x09, +0x68, 0x20, 0x00, 0x7f, 0xac, +0x88, 0x84, 0x86, 0x80, 0x00, +0x05, 0xc2, 0x18, 0x83, 0x20, +0x68, 0x20, 0x00, 0x4b, 0x24, +0x68, 0x20, 0x00, 0x78, 0x25, +0x88, 0x06, 0xc6, 0x80, 0x00, +0x16, 0x02, 0x26, 0x60, 0x00, +0x02, 0xde, 0x86, 0xc0, 0x00, +0x2b, 0x80, 0x98, 0x88, 0xc8, +0x68, 0x20, 0x00, 0x83, 0x20, +0x68, 0x20, 0x00, 0x84, 0x21, +0xa4, 0x22, 0x36, 0x60, 0x04, +0x0c, 0x68, 0x8a, 0x42, 0x02, +0x5c, 0x8d, 0x00, 0x83, 0xa0, +0x5c, 0x08, 0x61, 0x8e, 0x89, +0xa0, 0x28, 0x09, 0x42, 0x0f, +0x25, 0x93, 0x8b, 0xc0, 0x39, +0x55, 0x01, 0x70, 0x83, 0x21, +0x88, 0x80, 0xa8, 0x40, 0x0b, +0x54, 0x0f, 0x82, 0x0a, 0x81, +0x94, 0xa0, 0xe2, 0x59, 0x30, +0xbc, 0x03, 0x98, 0x40, 0xc0, +0x00, 0x00, 0x08, 0x88, 0x89, +0x00, 0x00, 0x08, 0x48, 0x08, +0x54, 0x09, 0x40, 0x82, 0x36, +0xba, 0x14, 0x88, 0x48, 0xc0, +0x40, 0x00, 0x02, 0x80, 0x90, +0x5c, 0x81, 0x02, 0xbf, 0xb0, +0x88, 0x16, 0x0a, 0x00, 0x43, +0xa0, 0x80, 0x0a, 0x10, 0x01, +0x81, 0xa0, 0x88, 0x58, 0x0a, +0x57, 0x0d, 0x00, 0x10, 0x0a, +0x49, 0x28, 0x80, 0x81, 0xe3, +0x57, 0x0a, 0x92, 0x18, 0x43, +0x98, 0x08, 0x98, 0x49, 0x49, +0xa2, 0x80, 0x1a, 0x28, 0x26, +0x88, 0x52, 0x58, 0x82, 0x63, +0xa3, 0x02, 0x3a, 0x18, 0x27, +0xa2, 0x06, 0x48, 0x50, 0x40, +0x88, 0x06, 0x78, 0x82, 0xe7, +0x88, 0x36, 0x48, 0x83, 0xe0, +0x88, 0x47, 0x66, 0x60, 0x04, +0x06, 0xa6, 0x8a, 0x30, 0x02, +0x5c, 0x08, 0x28, 0x82, 0x20, +0x88, 0x1a, 0x4a, 0x02, 0x20, +0x94, 0x02, 0xf5, 0x2c, 0xbc, +0x06, 0x14, 0x8a, 0x05, 0xe5, +0x42, 0x02, 0xc8, 0x83, 0x24, +0x5c, 0x00, 0x30, 0x83, 0xa0, +0x88, 0x12, 0x20, 0x00, 0x00, +0x85, 0x18, 0xa8, 0x68, 0x09, +0x54, 0x0b, 0x82, 0x01, 0x40, +0x98, 0x00, 0x9a, 0x22, 0xe4, +0x86, 0x8c, 0x98, 0x81, 0x64, +0x88, 0x1e, 0x06, 0x60, 0x04, +0x07, 0x0c, 0x08, 0x82, 0xa5, +0x88, 0x52, 0x28, 0x81, 0x24, +0x88, 0x1a, 0x0a, 0x28, 0x21, +0x88, 0x43, 0x6a, 0x10, 0x25, +0xa8, 0x05, 0x0a, 0x00, 0x40, +0x40, 0x00, 0x02, 0x20, 0x64, +0x64, 0x00, 0x40, 0x71, 0xaf, +0x55, 0x01, 0x2a, 0x08, 0x22, +0xa2, 0x08, 0x4a, 0x20, 0x22, +0x84, 0x40, 0x98, 0x60, 0x0a, +0x57, 0x8b, 0xaa, 0xbf, 0xe0, +0xa1, 0x4a, 0x4a, 0x08, 0x00, +0x85, 0x00, 0x88, 0x80, 0x64, +0x88, 0x0e, 0x08, 0x81, 0x76, +0x66, 0x00, 0x40, 0x53, 0x48, +0x2e, 0x96, 0x58, 0x80, 0x20, +0x88, 0x0a, 0x48, 0x41, 0x89, +0x44, 0x08, 0x00, 0x81, 0x36, +0x46, 0x0a, 0x41, 0x80, 0x08, +0x86, 0x14, 0x8a, 0x80, 0x20, +0x68, 0x00, 0x00, 0x2c, 0x20, +0x5c, 0x81, 0x03, 0x02, 0x74, +0x68, 0x01, 0x05, 0xdb, 0x2c, +0x80, 0x06, 0xc6, 0x80, 0x00, +0x0d, 0x42, 0x18, 0x00, 0x61, +0x68, 0x01, 0x05, 0x47, 0xa1, +0x6c, 0x00, 0x02, 0xcc, 0x48, +0x46, 0x0a, 0x40, 0x00, 0x61, +0x84, 0x06, 0x10, 0x00, 0x00, +0x68, 0x00, 0x00, 0x07, 0x60, +0xab, 0xff, 0x09, 0x40, 0x2c, +0x55, 0x5f, 0x22, 0x04, 0x10, +0x59, 0x01, 0x00, 0x80, 0x76, +0xbc, 0x29, 0x89, 0x40, 0x2e, +0x32, 0x06, 0x0b, 0xc1, 0x40, +0x32, 0x0a, 0x0b, 0xc3, 0x51, +0x32, 0x0b, 0x0b, 0xc0, 0x88, +0x68, 0x20, 0x02, 0x6b, 0x20, +0x68, 0x00, 0x00, 0x07, 0xa1, +0x66, 0x00, 0x41, 0x53, 0x60, +0x40, 0x00, 0x03, 0xc2, 0xb7, +0x68, 0x00, 0x00, 0x07, 0x21, +0x66, 0x00, 0x41, 0x54, 0x40, +0x66, 0x00, 0x41, 0x52, 0x08, +0xb0, 0x02, 0x4b, 0xc2, 0x37, +0x32, 0x0b, 0x0b, 0xc0, 0x88, +0x68, 0x20, 0x02, 0x4d, 0x20, +0x68, 0x00, 0x00, 0x07, 0xa1, +0x66, 0x00, 0x41, 0x53, 0x60, +0x40, 0x00, 0x03, 0xc1, 0x97, +0x68, 0x00, 0x00, 0x07, 0x21, +0x66, 0x00, 0x41, 0x54, 0x40, +0x66, 0x00, 0x41, 0x52, 0x08, +0xb0, 0x02, 0x4b, 0xc1, 0x17, +0x32, 0x0b, 0x0b, 0xc0, 0x88, +0x68, 0x00, 0x01, 0x8f, 0x20, +0x68, 0x00, 0x00, 0x07, 0xa1, +0x66, 0x00, 0x41, 0x53, 0x60, +0x40, 0x00, 0x03, 0xc0, 0x77, +0x68, 0x00, 0x00, 0x07, 0x21, +0x66, 0x00, 0x41, 0x54, 0x40, +0x66, 0x00, 0x41, 0x52, 0x08, +0xb0, 0x02, 0x48, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x03, 0x18, 0x09, +0x5d, 0x0a, 0x23, 0x01, 0xc6, +0x52, 0x0d, 0x72, 0xbf, 0xe0, +0x59, 0x01, 0x00, 0x80, 0xfa, +0x6c, 0x40, 0x03, 0x18, 0x4a, +0x88, 0x17, 0x64, 0x20, 0x74, +0x18, 0xe8, 0x95, 0x50, 0x16, +0x08, 0x04, 0x89, 0x8e, 0x88, +0x88, 0x00, 0x93, 0x20, 0x68, +0xbc, 0x07, 0x8b, 0x00, 0x0d, +0x88, 0x00, 0x95, 0x90, 0x54, +0x30, 0x00, 0xdb, 0xc0, 0x29, +0x98, 0x24, 0x89, 0x8e, 0x89, +0x88, 0x0c, 0x93, 0x20, 0x68, +0xbc, 0x09, 0x98, 0x81, 0xc8, +0x66, 0x00, 0x40, 0x77, 0x00, +0x68, 0x00, 0x00, 0x72, 0x20, +0x5c, 0x81, 0x00, 0x81, 0x88, +0x80, 0x20, 0x98, 0x40, 0x49, +0x32, 0x06, 0x0b, 0xc0, 0x71, +0x66, 0x00, 0x40, 0x77, 0xc0, +0x68, 0x00, 0x00, 0x87, 0x20, +0x39, 0x02, 0x08, 0x02, 0x09, +0x84, 0x04, 0x99, 0x8e, 0x88, +0x68, 0x00, 0x00, 0x84, 0x20, +0x68, 0x00, 0x00, 0x99, 0x21, +0x66, 0x00, 0x41, 0x44, 0xe8, +0x88, 0x08, 0x9b, 0x00, 0x0c, +0x68, 0x00, 0x00, 0x84, 0x20, +0x68, 0x00, 0x00, 0x99, 0x21, +0x66, 0x00, 0x41, 0x44, 0xe8, +0x88, 0x18, 0x98, 0x80, 0x09, +0x32, 0x02, 0x8b, 0xc1, 0x01, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x5c, 0x0e, 0x2a, 0xc4, 0xc0, +0x84, 0x00, 0x82, 0x51, 0x64, +0x6c, 0x40, 0x03, 0x18, 0x0a, +0x52, 0x8b, 0xa8, 0x02, 0x48, +0x6c, 0x40, 0x03, 0x18, 0x49, +0x68, 0x01, 0x05, 0x47, 0xa1, +0xbc, 0x05, 0xf8, 0x40, 0x61, +0x68, 0x00, 0x00, 0xfd, 0x20, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x00, 0x00, 0x08, 0x81, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x00, 0x71, 0x20, +0x68, 0x20, 0x00, 0x82, 0x22, +0x84, 0x00, 0x88, 0x50, 0x0a, +0x58, 0x0d, 0x02, 0xbf, 0xf0, +0x68, 0x20, 0x00, 0x81, 0x21, +0xbc, 0x03, 0x88, 0x80, 0x76, +0x66, 0x00, 0x40, 0xf3, 0x40, +0x68, 0x00, 0x00, 0x86, 0x20, +0x6c, 0x40, 0x01, 0x04, 0x08, +0x84, 0x00, 0xa3, 0x01, 0x30, +0x68, 0x20, 0x00, 0x82, 0x22, +0x40, 0x00, 0x03, 0xc0, 0x48, +0x68, 0x20, 0x00, 0x81, 0x21, +0x66, 0x00, 0x40, 0xf3, 0x40, +0x6c, 0x00, 0x00, 0xe2, 0x08, +0x6c, 0x40, 0x01, 0x04, 0x0a, +0x30, 0x1a, 0x0b, 0xc0, 0x41, +0x6c, 0x00, 0x01, 0x0c, 0x08, +0x30, 0x1a, 0x0b, 0xc0, 0x60, +0x68, 0x00, 0x00, 0xfd, 0x20, +0x40, 0x00, 0x03, 0xc1, 0x1f, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x5c, 0x0e, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0xa2, 0x49, 0x36, +0x6c, 0x40, 0x03, 0x18, 0x00, +0x52, 0x88, 0x20, 0x02, 0x4a, +0x68, 0x01, 0x05, 0x47, 0xa2, +0x6c, 0x40, 0x03, 0x18, 0x48, +0x84, 0x06, 0x20, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x01, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x03, 0x76, 0x08, +0x5c, 0x0e, 0x33, 0x01, 0x05, +0x24, 0x1a, 0x46, 0xe0, 0x00, +0x1a, 0xe2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x03, 0x76, 0x48, +0xbc, 0x05, 0x83, 0x81, 0x3d, +0x52, 0x4b, 0xc3, 0xc0, 0x6f, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x52, 0x0b, 0xc3, 0x80, 0x00, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x52, 0x4d, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0x92, 0x49, 0xae, +0x6c, 0x40, 0x03, 0x76, 0x48, +0x68, 0x01, 0x05, 0x47, 0xa1, +0x46, 0x0a, 0x40, 0x02, 0x4a, +0x84, 0x06, 0x10, 0x00, 0x00, +0x6c, 0x40, 0x03, 0x28, 0x08, +0x5c, 0x0e, 0x32, 0xbf, 0xf0, +0x52, 0x0d, 0x20, 0x80, 0x76, +0x6c, 0x40, 0x03, 0x28, 0x48, +0x66, 0x00, 0x00, 0x47, 0x48, +0x5c, 0x00, 0x63, 0x80, 0x00, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x5c, 0x0e, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0xa5, 0x24, 0x9b, +0x08, 0x03, 0x66, 0xc4, 0x00, +0x32, 0x80, 0x05, 0x24, 0x82, +0x00, 0x24, 0xa6, 0xc4, 0x00, +0x32, 0x84, 0x86, 0x80, 0x10, +0x54, 0x7a, 0xcb, 0xa1, 0x48, +0x84, 0x06, 0xca, 0x80, 0x10, +0x59, 0x01, 0x02, 0xbf, 0x40, +0xbc, 0x0f, 0x96, 0x80, 0x00, +0x15, 0xa2, 0x06, 0x80, 0x00, +0x15, 0x32, 0x25, 0xc8, 0x10, +0x18, 0xe8, 0x86, 0x80, 0x00, +0x1f, 0x22, 0x02, 0xa0, 0x64, +0x5d, 0x48, 0x20, 0x00, 0x00, +0x32, 0x1e, 0x0b, 0xff, 0xba, +0x40, 0x00, 0x00, 0x10, 0x50, +0x68, 0x00, 0x01, 0x56, 0x22, +0x5c, 0x81, 0x00, 0x40, 0x02, +0x5c, 0x00, 0x2a, 0x10, 0x10, +0x95, 0x03, 0x69, 0x40, 0x31, +0xa0, 0x47, 0x18, 0x81, 0x52, +0xa4, 0x14, 0x06, 0x80, 0x00, +0x15, 0x32, 0x22, 0x30, 0xac, +0x55, 0x03, 0x61, 0x82, 0x29, +0x5d, 0x48, 0x29, 0xd0, 0x83, +0x59, 0x0f, 0x41, 0x58, 0x37, +0x57, 0x0d, 0xd9, 0x58, 0xb4, +0x57, 0x03, 0x01, 0xc0, 0x84, +0x43, 0xf9, 0xd1, 0x60, 0x73, +0x96, 0x0f, 0x05, 0x1a, 0x0a, +0x24, 0x22, 0x35, 0xb0, 0x81, +0x2c, 0x0c, 0x15, 0x15, 0x88, +0x20, 0x02, 0x25, 0x70, 0x89, +0x08, 0x26, 0x15, 0x70, 0x89, +0x88, 0x37, 0x65, 0x15, 0x8d, +0x88, 0x1c, 0x85, 0x15, 0x89, +0x01, 0x84, 0x35, 0x15, 0x93, +0x01, 0x84, 0x25, 0x40, 0x90, +0x01, 0x84, 0x05, 0x40, 0x81, +0x01, 0x87, 0xa5, 0x15, 0x80, +0x01, 0x84, 0xa5, 0x15, 0x88, +0x01, 0x84, 0x08, 0x1a, 0xc0, +0x88, 0x06, 0x38, 0x82, 0xe3, +0x88, 0x3e, 0x2a, 0x41, 0x41, +0x68, 0x20, 0x00, 0x90, 0x23, +0x68, 0x20, 0x00, 0x8a, 0x24, +0x68, 0x20, 0x00, 0x8d, 0x25, +0x66, 0x00, 0x00, 0x5d, 0x68, +0x40, 0x00, 0x02, 0x00, 0x60, +0x5c, 0x07, 0xc0, 0x81, 0x88, +0x51, 0x61, 0x23, 0x00, 0x51, +0x5b, 0x48, 0x10, 0x82, 0x20, +0x37, 0x08, 0x35, 0x70, 0x60, +0x18, 0xe8, 0x35, 0x04, 0x09, +0x08, 0x1d, 0x03, 0x68, 0x40, +0x68, 0x20, 0x02, 0x62, 0x22, +0x55, 0x02, 0xf3, 0x00, 0xfd, +0x23, 0x09, 0xb5, 0x18, 0x59, +0x98, 0x4e, 0x89, 0x84, 0xe9, +0x9c, 0x00, 0x19, 0xc0, 0x83, +0x94, 0x83, 0x39, 0x58, 0x31, +0x2e, 0x0c, 0xb3, 0x68, 0xc1, +0x37, 0x04, 0x72, 0xe1, 0xed, +0x62, 0x00, 0x00, 0x00, 0x15, +0x50, 0x4a, 0x49, 0x8e, 0xb5, +0x00, 0x00, 0x02, 0xf8, 0x09, +0x55, 0xd4, 0xd8, 0x81, 0x8b, +0x32, 0x01, 0x8b, 0xc0, 0x2b, +0x98, 0x34, 0x93, 0x61, 0x45, +0x62, 0x00, 0x00, 0x00, 0x27, +0x2a, 0x01, 0x15, 0xb4, 0xa1, +0x98, 0xeb, 0x52, 0xf8, 0xc9, +0x29, 0x96, 0x33, 0x20, 0x18, +0xbc, 0x03, 0xb9, 0x83, 0x41, +0x36, 0x04, 0x52, 0xa0, 0x29, +0x5d, 0x4c, 0x19, 0xd0, 0x01, +0x32, 0x19, 0x8b, 0xfd, 0x6a, +0x94, 0x87, 0x15, 0xc8, 0x10, +0x2c, 0x0c, 0x18, 0x81, 0x08, +0x51, 0x61, 0x20, 0x82, 0xa3, +0x51, 0xa1, 0x21, 0x01, 0x58, +0x5b, 0x08, 0x00, 0x82, 0xd4, +0x57, 0x08, 0x10, 0x84, 0x48, +0x2e, 0x11, 0x35, 0x15, 0x8d, +0x88, 0x3a, 0x05, 0x15, 0x89, +0x01, 0x84, 0x35, 0x15, 0x80, +0x01, 0x84, 0x25, 0x40, 0x90, +0x01, 0x84, 0x05, 0x15, 0x93, +0x01, 0x87, 0xa5, 0x40, 0x81, +0x01, 0x84, 0xa5, 0x15, 0x80, +0x20, 0x05, 0x05, 0x15, 0x88, +0x01, 0x84, 0x08, 0x1a, 0xc0, +0x88, 0x06, 0x3a, 0x04, 0x61, +0x68, 0x20, 0x00, 0x98, 0xa3, +0x68, 0x20, 0x00, 0x92, 0xa4, +0x68, 0x20, 0x00, 0x95, 0xa5, +0x66, 0x00, 0x00, 0x5d, 0x68, +0x40, 0x00, 0x02, 0x08, 0x22, +0x5c, 0x07, 0xc0, 0x84, 0x08, +0x51, 0x61, 0x20, 0x82, 0x20, +0x5b, 0x48, 0x13, 0x80, 0x00, +0x5b, 0x84, 0x1a, 0x00, 0x10, +0x57, 0x06, 0x19, 0x01, 0x10, +0x68, 0x20, 0x02, 0x62, 0xa2, +0x50, 0x46, 0x90, 0x82, 0x94, +0x5c, 0x00, 0x18, 0x81, 0x53, +0x55, 0x02, 0xf3, 0x00, 0xfd, +0x23, 0x09, 0xb5, 0x18, 0x59, +0x98, 0x4e, 0x89, 0x84, 0xe9, +0x9c, 0x00, 0x19, 0xc0, 0x83, +0x94, 0x83, 0x39, 0x58, 0x31, +0x2e, 0x0c, 0xb3, 0x68, 0xc1, +0x37, 0x04, 0x72, 0xe1, 0xed, +0x62, 0x00, 0x00, 0x00, 0x15, +0x50, 0x4a, 0x49, 0x8e, 0xb5, +0x00, 0x00, 0x02, 0xf8, 0x09, +0x55, 0xd4, 0xd8, 0x81, 0x0b, +0x32, 0x01, 0x8b, 0xc0, 0x2b, +0x98, 0x34, 0x93, 0x61, 0x45, +0x62, 0x00, 0x00, 0x00, 0x27, +0x2a, 0x01, 0x15, 0xb4, 0xa1, +0x98, 0xeb, 0x52, 0xf8, 0xc9, +0x29, 0x96, 0x33, 0x20, 0x18, +0xbc, 0x03, 0xb9, 0x83, 0x41, +0x36, 0x04, 0x52, 0xa0, 0x29, +0x5d, 0x4c, 0x19, 0xd0, 0x01, +0x32, 0x19, 0x8b, 0xfd, 0x6a, +0x94, 0x87, 0x10, 0x00, 0x00, +0x6e, 0x40, 0x04, 0xc4, 0x34, +0x6e, 0x40, 0x04, 0xc5, 0x30, +0x51, 0xa1, 0x20, 0x83, 0x36, +0x54, 0x81, 0x23, 0xa1, 0x48, +0x6c, 0x40, 0x03, 0x2c, 0x48, +0x40, 0x00, 0x02, 0x80, 0xc0, +0xba, 0x14, 0x82, 0xe1, 0xa8, +0x40, 0x00, 0x01, 0x80, 0x08, +0x59, 0x06, 0x42, 0xbf, 0xd0, +0x49, 0xa9, 0xb8, 0x80, 0x76, +0xbc, 0x19, 0x89, 0xa0, 0x00, +0x32, 0x03, 0x0b, 0xc0, 0x29, +0x38, 0x10, 0x02, 0xa0, 0x76, +0x68, 0x00, 0x09, 0xc4, 0x09, +0x50, 0x41, 0x83, 0xa1, 0x11, +0x44, 0x08, 0x81, 0x01, 0x58, +0x5b, 0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x42, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x19, 0x02, 0x12, +0x29, 0x85, 0x13, 0x20, 0x08, +0xbc, 0x1a, 0x33, 0x60, 0x00, +0x37, 0x80, 0x0b, 0xc1, 0x77, +0x32, 0x02, 0x0b, 0xc0, 0x29, +0x38, 0x10, 0x02, 0xa0, 0x64, +0x68, 0x01, 0xff, 0xff, 0xc9, +0x50, 0x41, 0x03, 0xa1, 0x11, +0x44, 0x48, 0x81, 0x01, 0x58, +0x5b, 0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x42, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x19, 0x02, 0x12, +0x29, 0x85, 0x13, 0x20, 0x08, +0xbc, 0x02, 0x33, 0x60, 0x00, +0x37, 0x80, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, 0x00, +0x5b, 0x02, 0x03, 0x01, 0x01, +0x50, 0x43, 0x11, 0x84, 0x0a, +0x46, 0x08, 0x89, 0x83, 0x88, +0x44, 0x41, 0x09, 0x84, 0x8b, +0x98, 0x30, 0xa4, 0x47, 0x44, +0xab, 0xfe, 0x05, 0x08, 0x20, +0x08, 0x07, 0x60, 0x88, 0x82, +0x37, 0x80, 0x06, 0x80, 0x00, +0x9c, 0x40, 0x80, 0x84, 0x80, +0x6a, 0x00, 0x09, 0xc4, 0x02, +0x5b, 0x44, 0x11, 0x01, 0x58, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x40, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x26, 0xa0, 0x00, +0x9c, 0x40, 0x12, 0x98, 0x52, +0x32, 0x01, 0x0b, 0xc0, 0x3b, +0x88, 0x03, 0x63, 0x60, 0x00, +0x37, 0x80, 0x0b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, 0x00, +0xab, 0xf8, 0x09, 0x40, 0x36, +0x88, 0x04, 0xa8, 0x80, 0xe5, +0x88, 0x16, 0x48, 0x81, 0xe3, +0x88, 0x26, 0x28, 0x82, 0xf6, +0x66, 0x00, 0x00, 0x57, 0x28, +0x40, 0x00, 0x01, 0x48, 0x35, +0x6a, 0x00, 0x09, 0xc4, 0x00, +0x5b, 0x40, 0x00, 0x83, 0x48, +0x5c, 0x00, 0x21, 0x05, 0x58, +0x88, 0x3c, 0x88, 0x84, 0x54, +0x00, 0x00, 0x08, 0x80, 0x0a, +0x51, 0x85, 0x20, 0x82, 0x22, +0x98, 0x22, 0x89, 0xd0, 0x02, +0x88, 0x4e, 0x86, 0x60, 0x00, +0x05, 0x72, 0x89, 0x50, 0x35, +0x5b, 0x48, 0x3b, 0x01, 0xfe, +0x25, 0x9a, 0x06, 0x80, 0x01, +0xff, 0xfc, 0xab, 0xc0, 0x88, +0x55, 0x01, 0x00, 0x86, 0x48, +0x30, 0x1b, 0x8b, 0xc0, 0xcd, +0x88, 0x38, 0x16, 0x80, 0x01, +0xff, 0xfc, 0x0b, 0xc0, 0x87, +0x68, 0x00, 0x20, 0x00, 0x0a, +0x30, 0x1b, 0x8b, 0xc0, 0x4d, +0x40, 0x00, 0x00, 0x83, 0x81, +0x68, 0x00, 0x20, 0x00, 0x00, +0x59, 0x0a, 0x40, 0x81, 0xa2, +0xbc, 0x03, 0xb5, 0x50, 0x13, +0xac, 0x01, 0x09, 0x50, 0x50, +0x55, 0x02, 0x60, 0x81, 0xe2, +0x00, 0x00, 0x08, 0x84, 0xa8, +0x88, 0x82, 0x35, 0x18, 0x52, +0x08, 0x4c, 0x89, 0xd8, 0x04, +0x98, 0x22, 0x88, 0x60, 0x08, +0x9d, 0x80, 0x38, 0x83, 0x0a, +0x88, 0x6e, 0x46, 0x60, 0x00, +0x05, 0x76, 0x88, 0x58, 0x09, +0x88, 0x38, 0x83, 0x20, 0xe0, +0xbc, 0x13, 0x85, 0xc0, 0xfe, +0x19, 0x20, 0x19, 0x05, 0x12, +0x40, 0x00, 0x01, 0x07, 0x58, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x40, 0x08, 0x84, 0x16, +0x55, 0x00, 0x09, 0x07, 0x10, +0x6a, 0x00, 0x09, 0xc4, 0x02, +0x29, 0x88, 0x23, 0x20, 0x10, +0xbc, 0x03, 0xb3, 0x81, 0xfc, +0x36, 0x04, 0x13, 0x78, 0x41, +0x52, 0xc8, 0x41, 0x83, 0x48, +0x68, 0x00, 0x1f, 0xff, 0xcb, +0xbc, 0x07, 0x83, 0x69, 0x04, +0x30, 0x1e, 0x0b, 0xc0, 0xa5, +0x6a, 0x00, 0x1f, 0xff, 0xc1, +0x40, 0x00, 0x03, 0xc0, 0x67, +0x68, 0x00, 0x20, 0x00, 0x0b, +0x30, 0x1e, 0x0b, 0xc0, 0x25, +0x6a, 0x00, 0x20, 0x00, 0x01, +0x5c, 0x80, 0x80, 0x81, 0x22, +0x98, 0x34, 0x19, 0x50, 0x51, +0x88, 0x16, 0x20, 0x00, 0x00, +0x88, 0x6a, 0x38, 0x83, 0x08, +0x66, 0x00, 0x00, 0x5b, 0x08, +0x55, 0x00, 0x08, 0x58, 0x09, +0x5c, 0x0f, 0xf9, 0x83, 0x08, +0x25, 0x9c, 0x05, 0xb4, 0x82, +0x3c, 0x09, 0x86, 0x80, 0x01, +0xff, 0xfc, 0xb3, 0x01, 0xe0, +0xbc, 0x0d, 0xd8, 0x84, 0x88, +0x6a, 0x00, 0x1f, 0xff, 0xc0, +0x40, 0x00, 0x03, 0xc0, 0x87, +0x68, 0x00, 0x20, 0x00, 0x0b, +0x30, 0x1e, 0x0b, 0xc0, 0x4d, +0x40, 0x00, 0x00, 0x84, 0x88, +0x6a, 0x00, 0x20, 0x00, 0x00, +0x5c, 0x80, 0x80, 0x80, 0xa2, +0x5d, 0x88, 0x21, 0x83, 0x00, +0x59, 0x0d, 0x00, 0x86, 0x0b, +0x95, 0x05, 0x08, 0x83, 0x4b, +0x88, 0x3c, 0x88, 0x80, 0xe2, +0xbf, 0x77, 0xa8, 0x80, 0x0a, +0x88, 0x2b, 0x6b, 0xa1, 0x48, +0xa8, 0x08, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x03, 0x1c, 0x08, +0x5c, 0x0e, 0x33, 0x01, 0x05, +0x24, 0x1a, 0x46, 0xe0, 0x00, +0x1a, 0xe2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x03, 0x1c, 0x48, +0xbc, 0x05, 0x83, 0x81, 0x15, +0x52, 0x4b, 0xc3, 0xc0, 0xcf, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x52, 0x0b, 0xc3, 0x01, 0x0d, +0x25, 0x96, 0x0b, 0xc0, 0x68, +0x6e, 0x00, 0x01, 0xae, 0x60, +0x6c, 0x00, 0x01, 0x46, 0x7a, +0x6c, 0x00, 0x01, 0x5a, 0x7a, +0x68, 0x00, 0x00, 0x2b, 0x20, +0x52, 0x8d, 0x22, 0xc4, 0xc0, +0x84, 0x00, 0x92, 0x51, 0xae, +0x6c, 0x40, 0x03, 0x1c, 0x48, +0x68, 0x01, 0x05, 0x47, 0xa1, +0x46, 0x0a, 0x40, 0x02, 0x4a, +0x84, 0x06, 0x10, 0x00, 0x00, +0xab, 0xfd, 0x08, 0x80, 0xc9, +0x5c, 0x09, 0xf8, 0x80, 0x4b, +0x88, 0x17, 0x59, 0x02, 0x5b, +0x88, 0x1d, 0x70, 0x00, 0x00, +0x6e, 0x00, 0x01, 0x08, 0x2d, +0x25, 0x9e, 0x8b, 0xc0, 0x60, +0x6c, 0x68, 0x08, 0x10, 0x03, +0x6c, 0x00, 0x01, 0x34, 0x53, +0x40, 0x00, 0x03, 0xc0, 0x67, +0x6c, 0x68, 0x08, 0x16, 0x03, +0x6c, 0x00, 0x01, 0x34, 0x53, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6e, 0x00, 0x01, 0x32, 0x2b, +0x25, 0x9d, 0x8b, 0xc0, 0x50, +0x6c, 0x68, 0x08, 0x12, 0x09, +0x6c, 0x00, 0x01, 0x36, 0x49, +0xbc, 0x07, 0x72, 0x59, 0xe8, +0xbc, 0x05, 0x06, 0xc6, 0x80, +0x81, 0x60, 0x96, 0xc0, 0x00, +0x13, 0x64, 0x90, 0x00, 0x00, +0x5c, 0x02, 0x29, 0x02, 0x13, +0x68, 0x00, 0x00, 0x00, 0x75, +0x6c, 0x68, 0x08, 0x06, 0x75, +0x6c, 0x00, 0x02, 0xc6, 0x49, +0x00, 0x00, 0x08, 0x81, 0x97, +0x88, 0x00, 0xb4, 0x60, 0xb4, +0x08, 0x13, 0x58, 0x80, 0x89, +0x40, 0x00, 0x02, 0x80, 0x30, +0x40, 0x00, 0x03, 0xa1, 0x60, +0x68, 0x20, 0x02, 0x4d, 0x20, +0x00, 0x00, 0x08, 0x40, 0x08, +0x32, 0x82, 0x0b, 0xc2, 0xa1, +0x6c, 0x00, 0x01, 0x88, 0x08, +0x6c, 0x40, 0x04, 0x98, 0x0a, +0x30, 0x93, 0x0b, 0xc1, 0x29, +0x5c, 0x80, 0x81, 0x8e, 0x8a, +0x68, 0x20, 0x02, 0x4b, 0xa0, +0x39, 0x02, 0x19, 0x40, 0x3c, +0x55, 0x03, 0x22, 0x00, 0x01, +0x3a, 0x90, 0x49, 0x42, 0xd4, +0x00, 0x00, 0x09, 0x40, 0x38, +0x30, 0x02, 0x0b, 0xc1, 0x62, +0x46, 0x0a, 0x41, 0x4a, 0x56, +0x94, 0x87, 0x60, 0x00, 0x00, +0x68, 0x20, 0x02, 0x4b, 0x21, +0x39, 0x04, 0x19, 0x48, 0x1a, +0x55, 0x02, 0x91, 0x48, 0x56, +0x5d, 0x44, 0x20, 0x0a, 0xc8, +0x00, 0x00, 0x09, 0x48, 0x3a, +0x30, 0x0a, 0x0b, 0xc0, 0x6a, +0x5c, 0x00, 0x41, 0x49, 0x74, +0x80, 0x2d, 0x09, 0x40, 0x56, +0x94, 0x05, 0x68, 0x40, 0x7a, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x68, 0x20, 0x01, 0x3c, 0x20, +0x5c, 0x0b, 0x62, 0xc0, 0x20, +0x5c, 0x00, 0x30, 0x40, 0x09, +0x51, 0x87, 0x7a, 0x04, 0x41, +0x68, 0x00, 0x01, 0x30, 0x20, +0x51, 0x8b, 0xc0, 0x08, 0x09, +0x84, 0x04, 0x86, 0x80, 0x00, +0x0d, 0xa2, 0x28, 0x48, 0x08, +0xa0, 0x06, 0x08, 0x10, 0x50, +0x6c, 0x40, 0x01, 0x98, 0x49, +0x6c, 0x40, 0x01, 0x9a, 0x49, +0x6c, 0x40, 0x02, 0x2c, 0x4b, +0x6c, 0x40, 0x01, 0x06, 0x48, +0x6c, 0x40, 0x01, 0x08, 0x48, +0x94, 0x24, 0x64, 0x60, 0xa4, +0x05, 0x07, 0xa8, 0x40, 0x7a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x20, 0x01, 0xad, 0x21, +0x68, 0x00, 0x01, 0x7c, 0x22, +0x5c, 0x81, 0x02, 0x08, 0x23, +0xa1, 0xde, 0x48, 0x50, 0x88, +0x86, 0x00, 0x94, 0x40, 0x80, +0x22, 0x02, 0x08, 0x50, 0x0a, +0x80, 0x00, 0x96, 0x80, 0x00, +0x18, 0xe2, 0x54, 0x44, 0xc0, +0x04, 0x80, 0x94, 0x44, 0x88, +0x22, 0xce, 0x1a, 0x01, 0x04, +0xda, 0x08, 0x04, 0x43, 0x10, +0x05, 0x80, 0xa4, 0x41, 0x4a, +0x04, 0x80, 0x88, 0x20, 0x0a, +0x44, 0x15, 0x40, 0x20, 0x0a, +0x6c, 0x00, 0x01, 0xe2, 0x40, +0x08, 0x20, 0x08, 0x60, 0x08, +0x68, 0x00, 0x00, 0xc4, 0x22, +0x44, 0x24, 0x00, 0x68, 0x08, +0x84, 0x00, 0x94, 0x40, 0x90, +0x01, 0x04, 0x26, 0xc0, 0x00, +0x1d, 0x64, 0x16, 0xc0, 0x00, +0x1e, 0xe4, 0x28, 0x10, 0x40, +0x00, 0x00, 0x08, 0x49, 0x08, +0x86, 0x30, 0x94, 0x40, 0x80, +0x3a, 0x14, 0x88, 0x50, 0x40, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x08, 0x08, 0x20, +0x5c, 0x08, 0x33, 0x01, 0x65, +0x5c, 0x00, 0xa0, 0x40, 0x00, +0x52, 0x0c, 0x02, 0xc0, 0x62, +0x68, 0x34, 0x00, 0x17, 0x21, +0x5c, 0x8c, 0x08, 0x40, 0x50, +0x5c, 0x82, 0x18, 0x48, 0x7a, +0x5c, 0x81, 0x02, 0x08, 0x81, +0x5c, 0x00, 0xd0, 0x48, 0x00, +0x52, 0x4a, 0x02, 0x0b, 0x22, +0x5c, 0x00, 0x40, 0x48, 0x50, +0xa0, 0x0e, 0x08, 0x50, 0x0b, +0x52, 0x0d, 0xcb, 0x04, 0xc7, +0x85, 0x05, 0x10, 0x00, 0x00, +0x84, 0x80, 0x12, 0x41, 0x49, +0x84, 0x85, 0x15, 0xc8, 0xb1, +0x00, 0x34, 0x88, 0x02, 0xc9, +0x5c, 0x88, 0x18, 0x01, 0xfa, +0x80, 0x07, 0xa8, 0x40, 0x4b, +0x80, 0x17, 0xa8, 0x03, 0xd2, +0xa0, 0x00, 0x18, 0x00, 0x50, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x10, 0x0e, 0x02, +0x25, 0x99, 0x0b, 0xff, 0xc1, +0x5c, 0x04, 0x50, 0x48, 0xd0, +0xa0, 0x4c, 0x08, 0x00, 0x09, +0x80, 0x0d, 0x08, 0x03, 0xd0, +0x80, 0x05, 0x26, 0xc4, 0x00, +0x4d, 0x64, 0x90, 0x00, 0x00, +0x6c, 0x70, 0x10, 0x0e, 0x02, +0x25, 0x99, 0x0b, 0xff, 0xc1, +0x5c, 0x83, 0x18, 0x01, 0xd0, +0x5c, 0x02, 0x20, 0x03, 0xc8, +0x5c, 0x82, 0x08, 0x02, 0xc8, +0x5c, 0x88, 0x08, 0x00, 0xfa, +0x5c, 0x03, 0xa2, 0x00, 0x01, +0x80, 0x07, 0xab, 0x04, 0x66, +0x84, 0x8c, 0xa8, 0x01, 0x7a, +0x46, 0x0a, 0x40, 0x02, 0xc8, +0x84, 0x05, 0x00, 0x00, 0x00, +0x32, 0x02, 0x0b, 0xc0, 0xc0, +0x68, 0x38, 0x08, 0x02, 0x20, +0x5c, 0x03, 0xa2, 0xc1, 0x00, +0x5c, 0x04, 0x70, 0x40, 0x48, +0xa0, 0x18, 0x04, 0x60, 0xa4, +0x00, 0x24, 0x88, 0x40, 0x4a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x08, 0x03, 0x20, +0x5c, 0x03, 0xe3, 0x04, 0x66, +0x5c, 0x88, 0x00, 0x40, 0x4a, +0x5c, 0x00, 0x70, 0x40, 0x7a, +0xa0, 0x16, 0x04, 0x60, 0xa4, +0x00, 0x24, 0x88, 0x40, 0x4a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x01, 0xf5, 0xa0, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x00, 0x00, 0x00, +0x68, 0x00, 0x01, 0xf7, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x00, 0x00, 0x00, +0x68, 0x00, 0x01, 0xf8, 0xa0, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x00, 0x00, 0x00, +0x68, 0x00, 0x01, 0xf4, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x00, 0x00, 0x00, +0x5c, 0x81, 0x01, 0x8e, 0x88, +0x68, 0x00, 0x01, 0x90, 0x20, +0x68, 0x00, 0x01, 0x9c, 0x21, +0x68, 0x00, 0x01, 0xa8, 0x22, +0x55, 0x01, 0x33, 0x80, 0x00, +0x55, 0x03, 0xb0, 0x00, 0x7a, +0x5d, 0x0c, 0x30, 0x08, 0x7a, +0x32, 0x2b, 0x0b, 0xff, 0xaa, +0x40, 0x00, 0x00, 0x10, 0x7a, +0x68, 0x00, 0x01, 0xc1, 0x22, +0x68, 0x00, 0x01, 0xcc, 0x21, +0x68, 0x00, 0x01, 0xb6, 0x20, +0x55, 0x03, 0x20, 0x10, 0x7a, +0x5d, 0x08, 0x20, 0x08, 0x7a, +0x32, 0x26, 0x0b, 0xff, 0xaa, +0x80, 0x07, 0xa6, 0x80, 0x00, +0x1d, 0x52, 0x06, 0x80, 0x00, +0x1f, 0x42, 0x16, 0xc4, 0x00, +0x3b, 0x20, 0x86, 0xc0, 0x00, +0x2e, 0xa6, 0x14, 0x60, 0xa4, +0x04, 0x04, 0x88, 0x40, 0xc8, +0x40, 0x00, 0x03, 0x80, 0x00, +0x44, 0x28, 0x02, 0xc0, 0x20, +0x5c, 0x04, 0x29, 0x80, 0x08, +0x22, 0x8e, 0x09, 0x80, 0x0a, +0x68, 0x3f, 0xcb, 0xfc, 0xcb, +0x68, 0x20, 0x02, 0x3c, 0x20, +0x08, 0xe0, 0x05, 0x10, 0x20, +0x00, 0x00, 0xb5, 0x40, 0xe0, +0x80, 0x00, 0x29, 0x80, 0x4b, +0x44, 0x70, 0x80, 0x40, 0x00, +0x22, 0x04, 0x92, 0x80, 0x8a, +0x98, 0x08, 0xb0, 0x8e, 0x20, +0x22, 0x05, 0x22, 0x80, 0x12, +0x98, 0x08, 0xa0, 0x82, 0x20, +0x22, 0x05, 0x29, 0x80, 0x88, +0x28, 0x16, 0x52, 0x29, 0x6d, +0x2e, 0x14, 0x50, 0x81, 0x20, +0x22, 0x05, 0x29, 0x80, 0x88, +0x2a, 0x12, 0x52, 0x28, 0xed, +0x2e, 0x14, 0x50, 0x81, 0x20, +0x51, 0x02, 0x93, 0xa1, 0x48, +0x98, 0x08, 0x82, 0xe1, 0x04, +0x5b, 0x4a, 0x02, 0xbf, 0xf0, +0x6c, 0x40, 0x04, 0x74, 0x02, +0x30, 0x08, 0x0b, 0xc0, 0x7a, +0x5c, 0x00, 0x10, 0x80, 0x76, +0x00, 0x00, 0x06, 0xc4, 0x00, +0x47, 0x60, 0x25, 0x70, 0x40, +0x30, 0x00, 0xa8, 0x80, 0xd2, +0x66, 0x00, 0x00, 0x81, 0x48, +0x23, 0x04, 0x58, 0x80, 0x80, +0x32, 0x00, 0x0b, 0xc0, 0x38, +0x51, 0x43, 0x20, 0x80, 0x36, +0x36, 0x10, 0x4b, 0xa1, 0x48, +0xa8, 0x01, 0x00, 0x00, 0x00, +0xab, 0xff, 0x08, 0x80, 0x76, +0x66, 0x00, 0x00, 0x83, 0xe8, +0x6c, 0x00, 0x01, 0x46, 0x09, +0x68, 0x20, 0x02, 0x35, 0x20, +0x44, 0x00, 0x02, 0xc0, 0x20, +0x51, 0x06, 0x00, 0x02, 0x09, +0x57, 0x0a, 0x12, 0x00, 0x41, +0x51, 0x85, 0x28, 0x08, 0x08, +0x57, 0x0b, 0x01, 0x80, 0x88, +0x51, 0x85, 0x20, 0x08, 0x09, +0x6c, 0x00, 0x01, 0x46, 0x02, +0x44, 0x24, 0x00, 0x40, 0x0a, +0x54, 0x0c, 0x90, 0x08, 0x08, +0x58, 0x08, 0x80, 0x48, 0x09, +0xbc, 0x03, 0xd9, 0x81, 0x08, +0x28, 0x15, 0x02, 0x81, 0x42, +0x88, 0x03, 0x6b, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0x46, 0x42, +0x40, 0x00, 0x02, 0x80, 0x10, +0xab, 0xfe, 0x08, 0x80, 0x49, +0x88, 0x0c, 0x88, 0x81, 0x76, +0x66, 0x00, 0x00, 0x85, 0x80, +0x5c, 0x81, 0x00, 0x80, 0x09, +0x68, 0x00, 0x00, 0xb1, 0x20, +0x44, 0x20, 0x00, 0x80, 0x89, +0x44, 0x21, 0x00, 0x02, 0x08, +0x6c, 0x40, 0x04, 0x84, 0x0a, +0x44, 0x10, 0x80, 0x40, 0x09, +0xa0, 0x00, 0x18, 0x00, 0x48, +0x51, 0x02, 0x41, 0xa0, 0x01, +0x51, 0x63, 0xd0, 0x81, 0x36, +0x28, 0x01, 0x02, 0xe1, 0x40, +0x51, 0x63, 0x10, 0x40, 0x40, +0xa0, 0x06, 0x08, 0x02, 0x08, +0x44, 0x10, 0x00, 0x49, 0x40, +0x22, 0x04, 0x05, 0x40, 0x08, +0x04, 0x00, 0x92, 0xe1, 0x40, +0x84, 0x14, 0x04, 0x60, 0xa4, +0x00, 0x04, 0x88, 0x40, 0x40, +0x40, 0x00, 0x02, 0x80, 0x20, +0x68, 0x00, 0x00, 0xb2, 0x25, +0x68, 0x20, 0x02, 0x42, 0x27, +0x5c, 0x81, 0x02, 0x2c, 0x44, +0x86, 0x80, 0x08, 0x78, 0x08, +0x86, 0x00, 0xa4, 0x44, 0x60, +0x23, 0x82, 0x65, 0x10, 0x80, +0x07, 0x00, 0x84, 0x44, 0x10, +0x23, 0x02, 0x5a, 0x28, 0x07, +0x82, 0x80, 0xa5, 0x10, 0x88, +0x18, 0x00, 0x84, 0x41, 0x10, +0x06, 0x80, 0x99, 0x80, 0x0a, +0x44, 0x4c, 0x42, 0x20, 0xa4, +0x51, 0x08, 0x02, 0x24, 0x46, +0x84, 0x04, 0x0a, 0x2c, 0x60, +0x87, 0x80, 0x94, 0x44, 0x80, +0x06, 0x80, 0xa4, 0x41, 0x60, +0x20, 0x02, 0x52, 0x21, 0x00, +0x84, 0x84, 0x00, 0x00, 0x00, +0x86, 0x00, 0x08, 0x70, 0x08, +0x84, 0x00, 0xa4, 0x41, 0x60, +0x02, 0x80, 0xa4, 0x41, 0x10, +0x22, 0x80, 0x15, 0x10, 0x80, +0x02, 0x80, 0x95, 0x10, 0x88, +0x18, 0x00, 0x84, 0x40, 0x80, +0x18, 0x00, 0xb8, 0x68, 0x0a, +0x08, 0xe8, 0x02, 0x21, 0x00, +0x85, 0x04, 0x00, 0x00, 0x00, +0x84, 0x80, 0xa4, 0x47, 0x00, +0x06, 0x80, 0xa0, 0x82, 0xc0, +0x51, 0x08, 0x03, 0xa1, 0x48, +0x85, 0x84, 0x00, 0x00, 0x00, +0x84, 0x00, 0x94, 0x42, 0x80, +0x04, 0x80, 0x94, 0x42, 0xc0, +0x2b, 0xff, 0x08, 0x80, 0x76, +0x66, 0x00, 0x00, 0xb0, 0x08, +0x98, 0x00, 0x98, 0x80, 0x36, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x17, 0x84, 0x8a, 0x80, 0x10, +0xab, 0xff, 0x08, 0x40, 0x0a, +0x88, 0x07, 0x66, 0x60, 0x00, +0x0c, 0x40, 0x88, 0x48, 0x09, +0x6c, 0x40, 0x04, 0x7e, 0x09, +0x44, 0x08, 0x00, 0x80, 0x36, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x17, 0xa4, 0x0a, 0x80, 0x10, +0x84, 0x00, 0x94, 0x42, 0x80, +0x04, 0x80, 0x94, 0x42, 0xc0, +0x2b, 0xff, 0x08, 0x80, 0x76, +0x66, 0x00, 0x00, 0xb0, 0x08, +0x98, 0x00, 0x98, 0x80, 0x36, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x17, 0xc4, 0x8a, 0x80, 0x10, +0xab, 0xff, 0x08, 0x40, 0x0a, +0x88, 0x07, 0x66, 0x60, 0x00, +0x0c, 0x40, 0x88, 0x48, 0x09, +0x6c, 0x40, 0x04, 0x7e, 0x09, +0x44, 0x08, 0x00, 0x80, 0x36, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x17, 0xe4, 0x0a, 0x80, 0x10, +0x68, 0x00, 0x00, 0xbe, 0x20, +0x39, 0x04, 0x08, 0x02, 0x0a, +0x80, 0x20, 0x95, 0x70, 0xb8, +0x20, 0x0a, 0x18, 0x0a, 0x0a, +0x80, 0xa0, 0x96, 0xc4, 0x00, +0x48, 0x00, 0x85, 0x70, 0xb8, +0x04, 0x05, 0x03, 0x01, 0x00, +0xbc, 0x07, 0xd8, 0x48, 0x50, +0x00, 0x00, 0x06, 0xc4, 0x00, +0x48, 0x20, 0xa2, 0xe1, 0x86, +0x6c, 0x00, 0x01, 0x76, 0x4a, +0x36, 0x10, 0x68, 0x48, 0x08, +0x30, 0x1a, 0x0b, 0xc0, 0x73, +0x6c, 0x40, 0x04, 0x82, 0x0a, +0x54, 0x0d, 0x23, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0x76, 0x48, +0x00, 0x00, 0x0b, 0xa1, 0x40, +0x68, 0x00, 0x00, 0xa2, 0x20, +0x68, 0x00, 0x02, 0x53, 0x2c, +0x84, 0x07, 0xaa, 0x04, 0x60, +0x84, 0x07, 0xa4, 0x60, 0xa4, +0x20, 0x42, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x38, 0x10, 0x62, 0x59, 0xa0, +0xbc, 0x1c, 0x16, 0x80, 0x00, +0x0a, 0x02, 0x05, 0xc8, 0x30, +0x98, 0xe8, 0x06, 0xc4, 0x00, +0x46, 0x60, 0x85, 0xc8, 0x20, +0x00, 0x0f, 0xa5, 0xc8, 0x10, +0x80, 0x0c, 0x88, 0xc0, 0x58, +0x8c, 0x05, 0x88, 0xc0, 0x58, +0x8c, 0x05, 0x88, 0x00, 0xfa, +0x80, 0x0f, 0xa8, 0x00, 0xfa, +0x80, 0x0f, 0xa8, 0x00, 0xfa, +0x80, 0x0f, 0xa8, 0x00, 0xfa, +0x84, 0x07, 0xa6, 0x80, 0x00, +0x25, 0xba, 0x14, 0x60, 0xa4, +0x20, 0x6e, 0x08, 0x40, 0x61, +0x00, 0x00, 0x0b, 0xa1, 0x40, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x2a, 0xbf, 0xf0, +0x25, 0x96, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc4, 0x1f, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x00, 0x00, 0xa4, 0x20, +0x5c, 0x82, 0x02, 0xc0, 0x21, +0x80, 0x02, 0x18, 0xc0, 0x30, +0x84, 0x80, 0x82, 0x09, 0x62, +0x28, 0x01, 0x08, 0xc2, 0xd8, +0x00, 0x00, 0x08, 0x40, 0x21, +0xa0, 0x0a, 0x08, 0x48, 0x08, +0x50, 0x4b, 0x10, 0xc0, 0x31, +0x28, 0x05, 0x28, 0xc0, 0x7a, +0xa0, 0x52, 0x08, 0x40, 0x08, +0x32, 0x02, 0x05, 0x53, 0xf2, +0xbc, 0x28, 0x98, 0x40, 0x49, +0x68, 0x00, 0x00, 0xa2, 0x20, +0x38, 0x00, 0xc8, 0x02, 0x89, +0x21, 0x16, 0x42, 0xa7, 0xe4, +0x84, 0x04, 0x8a, 0x00, 0xe0, +0x8c, 0x03, 0x15, 0x70, 0x20, +0x0c, 0x07, 0x85, 0x04, 0xa0, +0x20, 0x0c, 0x09, 0x83, 0x08, +0x80, 0x24, 0x80, 0x00, 0x00, +0x8c, 0x03, 0x05, 0x70, 0x08, +0x0c, 0x07, 0xa5, 0x04, 0xa0, +0x20, 0x06, 0x09, 0x83, 0x09, +0x84, 0x04, 0x9a, 0x05, 0xe0, +0x88, 0x0e, 0x06, 0x60, 0x00, +0x08, 0x7e, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x01, 0xff, 0xc8, +0x84, 0x00, 0x92, 0xa0, 0x6d, +0x30, 0x12, 0x8b, 0xc0, 0x5d, +0x84, 0x04, 0x96, 0x80, 0x00, +0x27, 0x02, 0x06, 0xc0, 0x00, +0x13, 0xc6, 0x00, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x01, 0x00, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc1, 0x0f, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x00, 0x00, 0xb6, 0x20, +0x00, 0x00, 0x0a, 0x00, 0x21, +0xa0, 0x82, 0x2a, 0x10, 0x23, +0x88, 0x0e, 0x36, 0x60, 0x00, +0x08, 0xa8, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x02, 0x78, 0xa1, +0xa0, 0x76, 0x08, 0x40, 0x61, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc0, 0xef, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x00, 0x00, 0xb6, 0x20, +0x00, 0x00, 0x0a, 0x00, 0x21, +0x88, 0x0e, 0x16, 0x60, 0x00, +0x08, 0xe6, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x02, 0x80, 0xa1, +0xa0, 0x72, 0x08, 0x40, 0x61, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x09, +0x5c, 0x08, 0x22, 0xbf, 0xf0, +0x25, 0x92, 0x8b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc1, 0x1f, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x20, 0x02, 0x1b, 0x20, +0x66, 0x00, 0x00, 0xb7, 0xe8, +0x6c, 0x00, 0x01, 0x78, 0x09, +0x5c, 0x05, 0x2b, 0xa1, 0x11, +0x08, 0x10, 0x06, 0x80, 0x00, +0x28, 0x9a, 0x06, 0xc0, 0x00, +0x13, 0xc6, 0x06, 0xc0, 0x00, +0x17, 0x84, 0xc0, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, 0x48, +0x46, 0x08, 0x0a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x2b, 0xc1, 0x0f, +0x6c, 0x00, 0x01, 0x3c, 0x62, +0x68, 0x00, 0x00, 0xb6, 0x22, +0x00, 0x00, 0x0a, 0x10, 0x23, +0x88, 0x0e, 0x3a, 0x10, 0x00, +0x66, 0x00, 0x00, 0xbc, 0xe8, +0xa1, 0x80, 0x18, 0x80, 0xa2, +0x68, 0x00, 0x02, 0x92, 0x23, +0xa1, 0x72, 0x28, 0x50, 0x63, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc0, 0xef, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x00, 0x00, 0xb6, 0x20, +0x00, 0x00, 0x0a, 0x00, 0x21, +0x88, 0x0e, 0x16, 0x60, 0x00, +0x08, 0xf4, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x02, 0x9a, 0x21, +0xa0, 0x72, 0x08, 0x40, 0x61, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc0, 0xef, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x00, 0x00, 0xb8, 0x20, +0x00, 0x00, 0x0a, 0x00, 0x21, +0x88, 0x0e, 0x16, 0x60, 0x00, +0x09, 0x02, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x02, 0xa2, 0x21, +0xa0, 0x76, 0x08, 0x40, 0x61, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x09, +0x5c, 0x08, 0x22, 0xbf, 0xf0, +0x25, 0x92, 0x8b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc1, 0x1f, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x20, 0x02, 0x1b, 0x20, +0x66, 0x00, 0x00, 0xb7, 0xe8, +0x6c, 0x00, 0x01, 0x7c, 0x09, +0x5c, 0x05, 0x2b, 0xa1, 0x11, +0x08, 0x10, 0x06, 0x80, 0x00, +0x2a, 0xb2, 0x06, 0xc0, 0x00, +0x13, 0xc6, 0x06, 0xc0, 0x00, +0x17, 0xc4, 0xc0, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, 0x48, +0x46, 0x08, 0x0a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x2b, 0xc1, 0x0f, +0x6c, 0x00, 0x01, 0x3c, 0x62, +0x68, 0x00, 0x00, 0xb8, 0x22, +0x00, 0x00, 0x0a, 0x10, 0x23, +0x88, 0x0e, 0x3a, 0x10, 0x00, +0x66, 0x00, 0x00, 0xbc, 0xe8, +0xa1, 0x80, 0x18, 0x80, 0xa2, +0x68, 0x00, 0x02, 0xb3, 0xa3, +0xa1, 0x76, 0x28, 0x50, 0x63, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x5c, 0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0x80, 0x00, +0x25, 0x32, 0x0b, 0xc0, 0xef, +0x6c, 0x00, 0x01, 0x3c, 0x60, +0x68, 0x00, 0x00, 0xb8, 0x20, +0x00, 0x00, 0x0a, 0x00, 0x21, +0x88, 0x0e, 0x16, 0x60, 0x00, +0x09, 0x10, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x02, 0xbb, 0xa1, +0xa0, 0x76, 0x08, 0x40, 0x61, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x3e, 0x08, +0x38, 0x10, 0x62, 0x59, 0xa0, +0xbc, 0x05, 0x9a, 0xbf, 0xf0, +0x88, 0x07, 0x66, 0x60, 0x00, +0x09, 0x1e, 0x08, 0x80, 0x36, +0x6c, 0x00, 0x01, 0x3e, 0x7a, +0x68, 0x00, 0x02, 0x53, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x13, 0xc6, 0x0a, 0x80, 0x10, +0x5b, 0x8a, 0x3b, 0x00, 0xf0, +0x57, 0x0e, 0x03, 0x00, 0x0e, +0x50, 0x81, 0x83, 0x04, 0xea, +0x55, 0x33, 0xe3, 0x3c, 0x09, +0x13, 0x82, 0x72, 0x01, 0x07, +0x68, 0x20, 0x02, 0x19, 0x20, +0x23, 0x5d, 0x45, 0x40, 0xf0, +0x04, 0x00, 0xb5, 0x14, 0x22, +0x04, 0x08, 0x02, 0xe1, 0x3a, +0x22, 0xdd, 0x72, 0x80, 0x79, +0x68, 0x1f, 0xff, 0xff, 0xc8, +0x54, 0x48, 0xbb, 0x00, 0xfc, +0x36, 0x84, 0x22, 0x81, 0x09, +0x23, 0x23, 0xf2, 0x10, 0x74, +0x20, 0x8b, 0xf2, 0x28, 0x6e, +0x28, 0x1e, 0x70, 0x8b, 0x20, +0x22, 0x3d, 0x29, 0x80, 0x88, +0x08, 0x32, 0x02, 0x23, 0xd2, +0x2e, 0x08, 0x29, 0x80, 0x88, +0x08, 0xc2, 0x02, 0x20, 0x52, +0x98, 0x08, 0xb0, 0x8b, 0x20, +0x22, 0x3d, 0x29, 0x80, 0x8a, +0x08, 0xb2, 0x02, 0x23, 0xd2, +0x2e, 0x08, 0x09, 0x80, 0x0a, +0x08, 0xe0, 0x02, 0x20, 0x40, +0x46, 0x0a, 0x41, 0x80, 0x0a, +0x08, 0x90, 0x09, 0x80, 0x08, +0x32, 0x02, 0x8b, 0xc3, 0x58, +0x22, 0x86, 0xe5, 0xb8, 0xa2, +0x30, 0x0f, 0x05, 0x70, 0x80, +0x30, 0x00, 0xf5, 0x08, 0x1c, +0x30, 0x4e, 0xa2, 0xa6, 0x63, +0x4b, 0xc1, 0x23, 0x3c, 0x08, +0x20, 0x0c, 0xd2, 0x35, 0xd4, +0x68, 0x20, 0x02, 0x19, 0x20, +0x28, 0x16, 0x25, 0x14, 0x2a, +0x84, 0x00, 0x85, 0x70, 0xb0, +0xb0, 0x0f, 0xa5, 0x16, 0xe6, +0x04, 0x08, 0x92, 0x80, 0x20, +0x68, 0x1f, 0xff, 0xff, 0xc8, +0x36, 0x80, 0x35, 0x44, 0x84, +0x98, 0x0c, 0x82, 0x32, 0x09, +0x28, 0x08, 0x02, 0x10, 0x3f, +0x20, 0x90, 0xc2, 0x81, 0x3f, +0x08, 0xb0, 0x02, 0x23, 0xc0, +0x98, 0x00, 0x80, 0x83, 0x00, +0x22, 0x3c, 0x02, 0xe0, 0x28, +0x98, 0x00, 0x80, 0x8c, 0x00, +0x22, 0x04, 0x09, 0x80, 0x0b, +0x08, 0xb0, 0x02, 0x23, 0xc0, +0x98, 0x00, 0xa0, 0x8b, 0x00, +0x22, 0x3c, 0x02, 0xe0, 0x28, +0x98, 0x00, 0xa4, 0x47, 0x00, +0x3a, 0x14, 0x82, 0x20, 0x40, +0x98, 0x00, 0x8b, 0xa1, 0x48, +0x98, 0xe8, 0x80, 0x00, 0x00, +0x60, 0x00, 0x20, 0x00, 0x20, +0x2a, 0x02, 0x85, 0xc0, 0x02, +0x18, 0xeb, 0x52, 0xf9, 0x80, +0x32, 0x03, 0x0b, 0xc0, 0x48, +0x98, 0x30, 0x9b, 0xa1, 0x48, +0x23, 0x86, 0xc0, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x59, 0x01, 0x42, 0xbf, 0xc0, +0x84, 0x50, 0x84, 0x22, 0x2c, +0x08, 0x0f, 0x68, 0x80, 0x48, +0x5b, 0x8a, 0x23, 0x00, 0xf0, +0x57, 0x08, 0x23, 0x00, 0x08, +0x50, 0x88, 0x02, 0xc0, 0x20, +0x46, 0x08, 0x88, 0x00, 0x0a, +0x58, 0x01, 0x40, 0x81, 0x60, +0x44, 0x40, 0x83, 0xc3, 0x18, +0x88, 0x1c, 0xd3, 0x81, 0x04, +0x20, 0x92, 0x92, 0x09, 0x00, +0x51, 0xb8, 0x49, 0x02, 0x58, +0x5b, 0x40, 0x11, 0x03, 0x59, +0x66, 0x00, 0x41, 0x49, 0x68, +0x5b, 0x42, 0x0b, 0xa1, 0x01, +0x90, 0x21, 0x19, 0x03, 0x12, +0x29, 0x85, 0x13, 0x20, 0x08, +0xbc, 0x03, 0xb8, 0x81, 0x20, +0x36, 0x00, 0x03, 0x78, 0x00, +0x5c, 0x81, 0x01, 0x83, 0x09, +0x55, 0x3f, 0x68, 0x00, 0x08, +0x54, 0x09, 0x70, 0x81, 0x60, +0x66, 0x00, 0x00, 0xb7, 0x08, +0x57, 0x09, 0x6b, 0x80, 0x00, +0x44, 0x00, 0x00, 0x81, 0x20, +0x39, 0x02, 0x06, 0x00, 0x00, +0x00, 0x03, 0x85, 0x50, 0x10, +0x18, 0x00, 0xa4, 0x44, 0x10, +0x00, 0x00, 0x99, 0x80, 0x88, +0x4c, 0xa4, 0x00, 0x00, 0x09, +0x51, 0x02, 0x00, 0x81, 0x88, +0x98, 0x00, 0x95, 0x15, 0x17, +0x3c, 0x05, 0xf5, 0x40, 0xd2, +0x08, 0x00, 0x9b, 0xa1, 0x01, +0x88, 0x18, 0x88, 0x80, 0x09, +0x44, 0x08, 0x03, 0xc0, 0x4f, +0x40, 0x00, 0x01, 0x80, 0x08, +0x46, 0x08, 0x09, 0x8e, 0x88, +0x88, 0x0b, 0x6b, 0xa1, 0x48, +0xa8, 0x04, 0x00, 0x00, 0x00, +0x84, 0x00, 0x85, 0xb4, 0x80, +0x04, 0x80, 0x95, 0xb4, 0xa0, +0x18, 0x00, 0xa5, 0xb8, 0xc0, +0x18, 0x00, 0x25, 0xb8, 0x43, +0xab, 0xfd, 0x05, 0x80, 0xe0, +0x08, 0x0e, 0x24, 0x20, 0x35, +0x88, 0x17, 0x68, 0x80, 0x63, +0x32, 0x03, 0x0b, 0xc0, 0x10, +0x2a, 0x00, 0x7b, 0xc0, 0x4f, +0x2a, 0x03, 0x83, 0x20, 0x10, +0xbc, 0x01, 0x02, 0xa0, 0x38, +0x20, 0x02, 0x25, 0x00, 0x14, +0x18, 0x08, 0x84, 0x40, 0x00, +0x18, 0x00, 0x94, 0x42, 0xc0, +0x08, 0x24, 0x98, 0x81, 0xc8, +0x66, 0x00, 0x00, 0xb3, 0x68, +0x98, 0x10, 0x98, 0x81, 0x89, +0x44, 0x20, 0x00, 0x82, 0x09, +0x44, 0x21, 0x00, 0x80, 0xa2, +0x51, 0x1e, 0x00, 0x80, 0x23, +0x51, 0x1e, 0x90, 0x81, 0x36, +0x46, 0x0a, 0x40, 0x50, 0x40, +0x85, 0x84, 0x2a, 0x80, 0x30, +0x60, 0x00, 0x20, 0x00, 0x20, +0x36, 0x98, 0x45, 0xb4, 0xa0, +0x18, 0xeb, 0x52, 0xf9, 0x00, +0xba, 0x14, 0x89, 0x83, 0x08, +0x51, 0xc3, 0x23, 0x80, 0x00, +0x59, 0x01, 0x42, 0xbf, 0xf0, +0xbc, 0x07, 0xb8, 0x80, 0x76, +0x66, 0x00, 0x00, 0xbf, 0xc0, +0x5c, 0x3f, 0xeb, 0xc0, 0x4f, +0x54, 0xcb, 0x23, 0x80, 0x00, +0x66, 0x00, 0x00, 0xbf, 0xc0, +0x44, 0x00, 0x02, 0xc0, 0x20, +0x55, 0x01, 0x01, 0x80, 0x09, +0x44, 0x08, 0x80, 0x80, 0x36, +0x98, 0x04, 0x80, 0x81, 0x10, +0x68, 0x20, 0x02, 0x26, 0x20, +0x98, 0x04, 0xa4, 0x44, 0x88, +0x00, 0x00, 0xb4, 0x46, 0x60, +0x18, 0x04, 0x80, 0x81, 0x10, +0x98, 0x04, 0xb4, 0x46, 0x90, +0x18, 0x2c, 0x18, 0x00, 0x0b, +0x44, 0x74, 0x01, 0x80, 0x8a, +0x44, 0x49, 0x80, 0x00, 0x0b, +0x44, 0x67, 0x01, 0x80, 0xc8, +0x44, 0x08, 0x01, 0x82, 0x03, +0x55, 0x00, 0x78, 0x00, 0x08, +0x44, 0x1c, 0xc0, 0x00, 0x08, +0x44, 0x16, 0xa0, 0x00, 0x08, +0x55, 0x00, 0xf1, 0x80, 0x0b, +0x4f, 0xbd, 0x00, 0x00, 0x09, +0x44, 0x3e, 0x20, 0x40, 0x09, +0x46, 0x0a, 0x41, 0x80, 0x8a, +0x44, 0x34, 0x02, 0x80, 0x10, +0x40, 0x00, 0x01, 0x80, 0x08, +0x68, 0x20, 0x02, 0x2e, 0x23, +0x5c, 0x81, 0x02, 0xbf, 0xc0, +0x81, 0x80, 0x88, 0x18, 0x00, +0x81, 0x80, 0x28, 0x58, 0x0b, +0x88, 0x06, 0x3a, 0x40, 0xc2, +0xa4, 0x0e, 0x38, 0x50, 0x4a, +0x85, 0x84, 0x98, 0x80, 0xcb, +0x88, 0x15, 0x28, 0x81, 0xd0, +0x88, 0x24, 0x88, 0x82, 0xf6, +0xa1, 0x00, 0x06, 0x60, 0x00, +0x0b, 0xce, 0x8a, 0x18, 0x01, +0x88, 0x02, 0x28, 0x83, 0x0a, +0x85, 0x08, 0x93, 0x01, 0x70, +0xbc, 0x03, 0x12, 0xa0, 0x76, +0x88, 0x34, 0xa0, 0x00, 0x00, +0x88, 0x38, 0xa3, 0x01, 0x70, +0xbc, 0x02, 0x12, 0xa0, 0x76, +0x88, 0x3c, 0xa0, 0x00, 0x00, +0x88, 0x30, 0x93, 0x20, 0x28, +0xbc, 0x55, 0x88, 0x83, 0x8a, +0x32, 0x02, 0x8b, 0xc2, 0xfc, +0x36, 0x18, 0x43, 0x20, 0x30, +0xbc, 0x15, 0xc3, 0x61, 0x45, +0x30, 0x12, 0x8b, 0xc0, 0x84, +0x66, 0x00, 0x00, 0xc0, 0x60, +0x51, 0x45, 0x30, 0x82, 0x09, +0x28, 0x1a, 0x84, 0x22, 0x6f, +0x98, 0x00, 0xa3, 0x61, 0x84, +0x66, 0x00, 0x00, 0xc0, 0x68, +0x55, 0x01, 0x71, 0x82, 0x09, +0x51, 0x45, 0x30, 0x81, 0x89, +0x2e, 0x1a, 0x84, 0x22, 0x1f, +0x98, 0x00, 0xa3, 0x61, 0x84, +0x30, 0x1a, 0x8b, 0xc0, 0xca, +0x55, 0x01, 0x71, 0x82, 0x88, +0x66, 0x00, 0x00, 0xc0, 0x68, +0x40, 0x00, 0x01, 0x82, 0x09, +0x51, 0x45, 0x30, 0x81, 0x89, +0x57, 0x0d, 0x43, 0xc3, 0x6f, +0x40, 0x00, 0x01, 0x80, 0x08, +0x66, 0x00, 0x00, 0xc0, 0x68, +0x55, 0x01, 0x31, 0x82, 0x89, +0x51, 0x45, 0x30, 0x82, 0x09, +0x54, 0x0d, 0x43, 0xc2, 0xcf, +0x98, 0x00, 0x83, 0x20, 0x30, +0xbc, 0x11, 0x43, 0x01, 0x28, +0x40, 0x00, 0x03, 0xc0, 0x84, +0x66, 0x00, 0x00, 0xc0, 0x60, +0x51, 0x45, 0x30, 0x82, 0x09, +0x2e, 0x1a, 0x84, 0x20, 0xff, +0x98, 0x00, 0xa3, 0x61, 0x84, +0x66, 0x00, 0x00, 0xc0, 0x68, +0x55, 0x01, 0x71, 0x82, 0x89, +0xbc, 0x19, 0xf2, 0x28, 0xa4, +0x30, 0x1a, 0x8b, 0xc0, 0x84, +0x66, 0x00, 0x00, 0xc0, 0x60, +0x51, 0x45, 0x30, 0x82, 0x09, +0x57, 0x0d, 0x43, 0xc1, 0x0f, +0x40, 0x00, 0x01, 0x80, 0x08, +0x66, 0x00, 0x00, 0xc0, 0x68, +0x55, 0x01, 0x71, 0x82, 0x89, +0xbc, 0x09, 0xf2, 0x28, 0xa4, +0x32, 0x03, 0x0b, 0xc0, 0x50, +0x32, 0x03, 0x0b, 0xc0, 0x4c, +0x88, 0x10, 0x88, 0x80, 0x88, +0xbc, 0x01, 0x79, 0x8e, 0x88, +0x88, 0x2b, 0x6b, 0xa1, 0x48, +0xa8, 0x04, 0x00, 0x00, 0x00, +}; diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e132575c561131d92bebc3e6a88d9d4018289ed8 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_ois/ + +obj-$(CONFIG_SPECTRA_CAMERA) += HighLevelCmd.o DownloadCmd.o E2PromCmd.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Ois.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Ois.h new file mode 100755 index 0000000000000000000000000000000000000000..885b0c56249ab7ebde67a0c2fa3f8b11b9fd90ef --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Ois.h @@ -0,0 +1,592 @@ +//******************************************************************************** +// << LC898124 Evaluation Soft>> +// Program Name : Ois.h +// Explanation : LC898124 Global Declaration & ProtType Declaration +// Design : Y.Yamada +// History : First edition +//******************************************************************************** + +#ifndef OIS_H_ +#define OIS_H_ + + +#include "OisLc898124EP3.h" +#include <linux/types.h> +#include "cam_sensor_util.h" +#include "cam_debug_util.h" + +//**************************************************** +// MODE SELECTORS (Compile Switches) +//**************************************************** +#define __OIS_UIOIS_GYRO_USE__ +//#define UP_SIDE_GYRO + +//#define __OIS_BIG_ENDIAN__ + +//#define EEPROM_FULL_ERASE // E2Prom full erase + +#define SELECT_MODEL 2 // --- select model ---// + // 0 : OnePlus L + // 1 : OnePlus L+ + // 2 : OnePlus W + +#define SELECT_VENDOR 0x01 // --- select vender ---// + // 0bit : SEMCO + // 1bit : OFILM + // 7bit : OnePlus + +#define MASTER_SLAVE 0 // --- select spi i/f mode ---// + // 0 : only master + // 1 : there are master&slave (for dual ) + +#define EP3_ES 2 // --- LC898124EP3 ES ---// + // 0 : none + // 1 : ES1 + // 2 : ES2 + +#if (SELECT_VENDOR == 0x01) // SEMCO + #define FW_VER 0x01 //ATMEL Version + #define SUB_VER 0x00 //ATMEL SUB Version +#else //(SELECT_VENDOR == 0x03) // ALL + #define FW_VER 0x00 //ATMEL Version for ALL + #define SUB_VER 0x00 //ATMEL SUB Version +#endif + + +//#define ZERO_SERVO +#define ACCEL_SERVO +#define SEL_SHIFT_COR +#define LIN_CRSTLK + +#define USE_FRA // uncomment if use FRA function +#define USE_BOSCH 1 + +//**************************************************** +// TYPE +//**************************************************** +#define INT8 int8_t//char +#define INT16 int16_t//short +#define INT32 int32_t//long +#define INT64 int64_t//long long +#define UINT8 uint8_t//unsigned char +#define UINT16 uint16_t//unsigned short +#define UINT32 uint32_t//unsigned long +#define UINT64 uint64_t//unsigned long long + +//**************************************************** +// Defines +//**************************************************** +/**************** Filter sampling **************/ +#define FS_FREQ 18038.84615F // 45[MHz]/4/624 + +#define SLT_OFFSET_HORIZONTAL_SO2821 (-2218L) +#define SLT_OFFSET_VERTICAL_SO2821 (2218L) + +// Command Status +#define EXE_END 0x00000002L // Execute End (Adjust OK) +#define EXE_ERROR 0x00000003L // Adjust NG : Execution Failure +#define EXE_HXADJ 0x00000006L // Adjust NG : X Hall NG (Gain or Offset) +#define EXE_HYADJ 0x0000000AL // Adjust NG : Y Hall NG (Gain or Offset) +#define EXE_LXADJ 0x00000012L // Adjust NG : X Loop NG (Gain) +#define EXE_LYADJ 0x00000022L // Adjust NG : Y Loop NG (Gain) +#define EXE_GXADJ 0x00000042L // Adjust NG : X Gyro NG (offset) +#define EXE_GYADJ 0x00000082L // Adjust NG : Y Gyro NG (offset) + +#ifdef SEL_SHIFT_COR +#define EXE_GZADJ 0x00400002L // Adjust NG : Z Gyro NG (offset) +#endif //SEL_SHIFT_COR + +#define EXE_HXMVER 0x06 // X Err +#define EXE_HYMVER 0x0A // Y Err +// Gyro Examination of Acceptance +#define EXE_GXABOVE 0x06 // X Above +#define EXE_GXBELOW 0x0A // X Below +#define EXE_GYABOVE 0x12 // Y Above +#define EXE_GYBELOW 0x22 // Y Below + +// Common Define +#define SUCCESS 0x00 // Success +#define FAILURE 0x01 // Failure + +#ifndef ON + #define ON 0x01 // ON + #define OFF 0x00 // OFF +#endif + +#define X_DIR 0x00 // X Direction +#define Y_DIR 0x01 // Y Direction +#define Z_DIR 0x02 // Z Direction + +// mode +#define GEA_MINMAX_MODE 0x00 // min, max mode +#define GEA_MEAN_MODE 0x01 // mean mode + +#define BOTH_ON 0x00 +#define XONLY_ON 0x01 +#define YONLY_ON 0x02 +#define BOTH_OFF 0x03 + +#ifdef SEL_SHIFT_COR +//#define ZEROG_MRGN_Z (204 << 16) // Zero G tolerance for Z +//#define ZEROG_MRGN_XY (204 << 16) // Zero G tolerance for XY +//#define ACCL_SENS 2048 +#define ZEROG_MRGN_Z (409 << 16) // Zero G tolerance for Z +#define ZEROG_MRGN_XY (409 << 16) // Zero G tolerance for XY +#define ACCL_SENS 4096 +#define ACCL_SENS_M -4096 +#endif //SEL_SHIFT_COR + +#define CHECK_SUM_NUM 109 // 0x6D + +//**************************************************** +// Command +//**************************************************** +#define OIS_POS_FLG 0x00000100 // OIS position by AF measurement + +//============================================================================== +// Calibration Data Memory Map +//============================================================================== +// Calibration Status +#define CALIBRATION_STATUS ( 0 ) +// Hall amplitude Calibration X +#define HALL_MAX_BEFORE_X ( 1 ) +#define HALL_MIN_BEFORE_X ( 2 ) +#define HALL_MAX_AFTER_X ( 3 ) +#define HALL_MIN_AFTER_X ( 4 ) +// Hall amplitude Calibration Y +#define HALL_MAX_BEFORE_Y ( 5 ) +#define HALL_MIN_BEFORE_Y ( 6 ) +#define HALL_MAX_AFTER_Y ( 7 ) +#define HALL_MIN_AFTER_Y ( 8 ) +// Hall Bias/Offset +#define HALL_BIAS_DAC_X ( 9 ) +#define HALL_OFFSET_DAC_X ( 10 ) +#define HALL_BIAS_DAC_Y ( 11 ) +#define HALL_OFFSET_DAC_Y ( 12 ) +// Loop Gain Calibration X +#define LOOP_GAIN_X ( 13 ) +// Loop Gain Calibration Y +#define LOOP_GAIN_Y ( 14 ) +// Lens Center Calibration +#define MECHA_CENTER_X ( 15 ) +#define MECHA_CENTER_Y ( 16 ) +// Optical Center Calibration +#define OPT_CENTER_X ( 17 ) +#define OPT_CENTER_Y ( 18 ) +// Gyro Offset Calibration +#define GYRO_OFFSET_X ( 19 ) +#define GYRO_OFFSET_Y ( 20 ) +// Gyro Gain Calibration +#define GYRO_GAIN_X ( 21 ) +#define GYRO_GAIN_Y ( 22 ) +// AF calibration +#define OIS_POS_BY_AF_X1 ( 23 ) +#define OIS_POS_BY_AF_X2 ( 24 ) +#define OIS_POS_BY_AF_X3 ( 25 ) +#define OIS_POS_BY_AF_X4 ( 26 ) +#define OIS_POS_BY_AF_X5 ( 27 ) +#define OIS_POS_BY_AF_X6 ( 28 ) +#define OIS_POS_BY_AF_X7 ( 29 ) +#define OIS_POS_BY_AF_X8 ( 30 ) +#define OIS_POS_BY_AF_X9 ( 31 ) +// Gyro mixing correction +#define MIXING_HX45X ( 32 ) +#define MIXING_HX45Y ( 33 ) +#define MIXING_HY45Y ( 34 ) +#define MIXING_HY45X ( 35 ) +#define MIXING_HXSX ( 36 ) +#define MIXING_HYSX ( 36 ) +// Gyro angle correction +#define MIXING_GX45X ( 37 ) +#define MIXING_GX45Y ( 38 ) +#define MIXING_GY45Y ( 39 ) +#define MIXING_GY45X ( 40 ) +// Liniearity correction +#define LN_POS1 ( 41 ) +#define LN_POS2 ( 42 ) +#define LN_POS3 ( 43 ) +#define LN_POS4 ( 44 ) +#define LN_POS5 ( 45 ) +#define LN_POS6 ( 46 ) +#define LN_POS7 ( 47 ) +#define LN_STEP ( 48 ) +// Factory Gyro Gain Calibration +#define GYRO_FCTRY_OFST_X ( 49 ) +#define GYRO_FCTRY_OFST_Y ( 50 ) +// Gyro Offset Calibration +#define GYRO_OFFSET_Z ( 51 ) +// Accl offset +//#define ACCL_OFFSET_X ( 52 ) +//#define ACCL_OFFSET_Y ( 53 ) +#define DEFAULT_GAIN_X ( 52 ) +#define DEFAULT_GAIN_Y ( 53 ) +#define ACCL_OFFSET_Z ( 54 ) +#define OIS_POS_BY_AF_Y1 ( 55 ) +#define OIS_POS_BY_AF_Y2 ( 56 ) +#define OIS_POS_BY_AF_Y3 ( 57 ) +#define OIS_POS_BY_AF_Y4 ( 58 ) +#define OIS_POS_BY_AF_Y5 ( 59 ) +#define OIS_POS_BY_AF_Y6 ( 60 ) +#define OIS_POS_BY_AF_Y7 ( 61 ) +#define OIS_POS_BY_AF_Y8 ( 62 ) +#define OIS_POS_BY_AF_Y9 ( 63 ) + + +//**************************************************** +// Generic memory +//**************************************************** +#ifdef __OIS_BIG_ENDIAN__ +// Big endian +// Word Data Union +union WRDVAL{ + INT16 SsWrdVal ; + UINT16 UsWrdVal ; + UINT8 UcWrkVal[ 2 ] ; + signed char ScWrkVal[ 2 ] ; + struct { + UINT8 UcHigVal ; + UINT8 UcLowVal ; + } StWrdVal ; +} ; + + +union DWDVAL { + UINT32 UlDwdVal ; + UINT16 UsDwdVal[ 2 ] ; + struct { + UINT16 UsHigVal ; + UINT16 UsLowVal ; + } StDwdVal ; + struct { + UINT8 UcRamVa3 ; + UINT8 UcRamVa2 ; + UINT8 UcRamVa1 ; + UINT8 UcRamVa0 ; + } StCdwVal ; +} ; + +union ULLNVAL { + UINT64 UllnValue ; + UINT32 UlnValue[ 2 ] ; + struct { + UINT32 UlHigVal ; + UINT32 UlLowVal ; + } StUllnVal ; +} ; + + +// Float Data Union +union FLTVAL { + float SfFltVal ; + UINT32 UlLngVal ; + UINT16 UsDwdVal[ 2 ] ; + struct { + UINT16 UsHigVal ; + UINT16 UsLowVal ; + } StFltVal ; +} ; + +#else // BIG_ENDDIAN +// Little endian +// Word Data Union +union WRDVAL{ + INT16 SsWrdVal ; + UINT16 UsWrdVal ; + UINT8 UcWrkVal[ 2 ] ; + signed char ScWrkVal[ 2 ] ; + struct { + UINT8 UcLowVal ; + UINT8 UcHigVal ; + } StWrdVal ; +} ; + +union DWDVAL { + UINT32 UlDwdVal ; + UINT16 UsDwdVal[ 2 ] ; + struct { + UINT16 UsLowVal ; + UINT16 UsHigVal ; + } StDwdVal ; + struct { + UINT8 UcRamVa0 ; + UINT8 UcRamVa1 ; + UINT8 UcRamVa2 ; + UINT8 UcRamVa3 ; + } StCdwVal ; +} ; + +union ULLNVAL { + UINT64 UllnValue ; + UINT32 UlnValue[ 2 ] ; + struct { + UINT32 UlLowVal ; + UINT32 UlHigVal ; + } StUllnVal ; +} ; + +// Float Data Union +union FLTVAL { + float SfFltVal ; + UINT32 UlLngVal ; + UINT16 UsDwdVal[ 2 ] ; + struct { + UINT16 UsLowVal ; + UINT16 UsHigVal ; + } StFltVal ; +} ; +#endif // __OIS_BIG_ENDIAN__ + +typedef union WRDVAL UnWrdVal ; +typedef union DWDVAL UnDwdVal; +typedef union ULLNVAL UnllnVal; +typedef union FLTVAL UnFltVal ; + + +typedef struct STMESRAM { + INT32 SlMeasureMaxValue ; + INT32 SlMeasureMinValue ; + INT32 SlMeasureAmpValue ; + INT32 SlMeasureAveValue ; +} stMesRam124 ; // Struct Measure Ram + +typedef struct { + UINT8 DrvDir; + UINT16 Rrmd1ToMacro; + UINT16 Rrmd1ToInfini; + UINT16 Freq; +} AF_PARA; + +typedef struct { + UINT32 BiasInit; + UINT32 OffsetInit; + UINT32 OffsetMargin; + UINT32 TargetRange; + UINT32 TargetMax; + UINT32 TargetMin; + UINT32 SinNum; + UINT32 SinFreq; + UINT32 SinGain; + UINT32 DecrementStep; + UINT32 ActMaxDrive_X; + UINT32 ActMaxDrive_Y; + UINT32 ActMinDrive_X; + UINT32 ActMinDrive_Y; + UINT16 MagneticOffset_X; + UINT16 MagneticOffset_Y; + UINT16 HallMax_X; + UINT16 HallMax_Y; + UINT16 HallMin_X; + UINT16 HallMin_Y; +} ADJ_HALL; + +typedef struct { + UINT32 Hxgain; + UINT32 Hygain; + UINT32 NoiseNum; + UINT32 NoiseFreq; + UINT32 NoiseGain; + UINT32 Gap; + UINT32 XJudgeHigh; + UINT32 XJudgeLow; + UINT32 YJudgeHigh; + UINT32 YJudgeLow; +} ADJ_LOPGAN; + +typedef struct { + UINT8 Vendor; + UINT8 User; + UINT8 Model; + UINT8 Version; + UINT8 SpiMode; + UINT8 Reserve1; + UINT8 ActType; + UINT8 GyroType; +} DSPVER; + +typedef struct { + UINT16 Cmd ; // ActSelect|GyroSelect + UINT8 FWType ; // 1: Normal OIS FW, 2: Servo ON FW + const UINT8* DataPM; + UINT32 LengthPM; + UINT32 Parity; + const UINT8* DataDM; + UINT32 LengthDMA; + UINT32 LengthDMB; +}DOWNLOAD_TBL ; + +//**************************************************** +// Structure of calibration data for GUI +//**************************************************** +typedef struct STADJPAR { + struct { + UINT32 UlAdjPhs ; // Hall Adjust Phase + + UINT16 UsHlxCna ; // Hall Center Value after Hall Adjust + UINT16 UsHlxMax ; // Hall Max Value + UINT16 UsHlxMxa ; // Hall Max Value after Hall Adjust + UINT16 UsHlxMin ; // Hall Min Value + UINT16 UsHlxMna ; // Hall Min Value after Hall Adjust + UINT16 UsHlxGan ; // Hall Gain Value + UINT16 UsHlxOff ; // Hall Offset Value + UINT16 UsAdxOff ; // Hall A/D Offset Value + UINT16 UsHlxCen ; // Hall Center Value + + UINT16 UsHlyCna ; // Hall Center Value after Hall Adjust + UINT16 UsHlyMax ; // Hall Max Value + UINT16 UsHlyMxa ; // Hall Max Value after Hall Adjust + UINT16 UsHlyMin ; // Hall Min Value + UINT16 UsHlyMna ; // Hall Min Value after Hall Adjust + UINT16 UsHlyGan ; // Hall Gain Value + UINT16 UsHlyOff ; // Hall Offset Value + UINT16 UsAdyOff ; // Hall A/D Offset Value + UINT16 UsHlyCen ; // Hall Center Value + } StHalAdj ; + + struct { + UINT32 UlLxgVal ; // Loop Gain X + UINT32 UlLygVal ; // Loop Gain Y + } StLopGan ; + + struct { + UINT16 UsGxoVal ; // Gyro A/D Offset X + UINT16 UsGyoVal ; // Gyro A/D Offset Y + UINT16 UsGxoSts ; // Gyro Offset X Status + UINT16 UsGyoSts ; // Gyro Offset Y Status + } StGvcOff ; + + UINT8 UcOscVal ; // OSC value + +} stAdjPar ; + +#ifdef ZERO_SERVO +typedef struct STZEROSERVO { + INT32 SlOffset ; // + INT32 SlG45m ; // + INT32 SlG45s ; // + INT32 SlGcora ; // + INT32 SlGaina ; // + INT32 SlShift ; // +} stZeroServo ; +#endif //ZERO_SERVO + +#ifdef SEL_SHIFT_COR +typedef struct STPOSOFF { + struct { + INT32 Pos[6][3]; + } StPos; + UINT32 UlAclOfSt ; //!< accel offset status + +} stPosOff ; + +typedef struct STACLVAL { + struct { + INT32 SlOffsetX ; + INT32 SlOffsetY ; + INT32 SlOffsetZ ; + } StAccel ; + + INT32 SlInvMatrix[9] ; + +} stAclVal ; +#endif //SEL_SHIFT_COR + +struct tagMlMixingValue +{ + double radianX; + double radianY; + + double hx45x; + double hy45x; + double hy45y; + double hx45y; + + UINT8 hxsx; + UINT8 hysx; + + INT32 hx45xL; //! for Fixed point + INT32 hy45xL; //! for Fixed point + INT32 hy45yL; //! for Fixed point + INT32 hx45yL; //! for Fixed point + + double XonXmove[7]; + double YonXmove[7]; + double XonYmove[7]; + double YonYmove[7]; +}; +typedef struct tagMlMixingValue mlMixingValue; + +struct tagMlLinearityValue +{ + INT32 measurecount; //! input parameter + UINT32 *dacX; //! input parameter + UINT32 *dacY; //! input parameter + + double *positionX; + double *positionY; + UINT16 *thresholdX; + UINT16 *thresholdY; + + UINT32 *coefAXL; //! for Fixed point + UINT32 *coefBXL; //! for Fixed point + UINT32 *coefAYL; //! for Fixed point + UINT32 *coefBYL; //! for Fixed point +}; +typedef struct tagMlLinearityValue mlLinearityValue; + +struct ACT_MOV_t { + int startcode ; + int endcode ; + int step ; +} ; + +typedef struct ACT_MOV_t Act_Mov_t ; + + + +// for SetSinWavePara +#define SINEWAVE 0 +#define XHALWAVE 1 +#define YHALWAVE 2 +#define ZHALWAVE 3 +#define XACTTEST 10 +#define YACTTEST 11 +#define CIRCWAVE 255 + + +//**************************************************** +// Debug +//**************************************************** +#if 0 + +#ifdef DEBUG +#include <AT91SAM7S.h> +#include <us.h> + #define TRACE_INIT(x) dbgu_init(x) + #define TRACE(fmt, ...) dbgu_printf(fmt, ## __VA_ARGS__) + #define TRACE_DUMP(x,y) dbg_Dump(x,y) + #define TRACE_USB(fmt, ...) dbg_UsbData(fmt, ## __VA_ARGS__) +#else + #define TRACE_INIT(x) + #define TRACE(...) + #define TRACE_DUMP(x,y) + #define TRACE_USB(...) +#endif + +#else + +#define DEBUG 1 +#ifdef DEBUG + #define TRACE_INIT(x) + #define TRACE(...) CAM_ERR(CAM_OIS, ## __VA_ARGS__) + #define TRACE_DUMP(x,y) + #define TRACE_USB(...) +#else + #define TRACE_INIT(x) + #define TRACE(...) + #define TRACE_DUMP(x,y) + #define TRACE_USB(...) +#endif + +#endif + +#endif /* #ifndef OIS_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisAPI.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisAPI.h new file mode 100755 index 0000000000000000000000000000000000000000..a06279e9fda5e92de84a0aa8e238fe3a30439dc3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisAPI.h @@ -0,0 +1,101 @@ +//******************************************************************************** +// << LC898124EP3 Evaluation Soft>> +// Program Name : OisAPI +// Explanation : API List for customers +// History : First edition 2016.03.15 K.abe +//******************************************************************************** +//**************************************************** +// MODE SELECTORS (Compile Switches) +//**************************************************** +#define __MIX_LIB_METHOD__ + +//**************************************************** +// API FUNCTION LIST +//**************************************************** +/* Program Download & Start */ +extern void RemapMain( void ); // make download code start. +extern unsigned char SelectDownload( UINT8 GyroSelect, UINT8 ActSelect, UINT8 MasterSlave ); // download + +/* Code information check such as version */ +extern UINT8 GetInfomationAfterDownload( DSPVER* Info ); // get code information after download. + +/* Power off for SPI interface */ +extern void PreparationForPowerOff124( void ); // SPI interface stop before power off + +/* E2Prom Access */ +extern UINT8 E2PromVerification( void ); // E2Prom verification for user area by using check sum. O:SUCCESS, 1:FAUILRE +extern UINT8 E2PromVerificationONSEMI( void ); // E2Prom verification for ONSEMI area by using check sum. O:SUCCESS, 1:FAUILRE +extern void BurstReadE2Prom( UINT8 address, UINT8 * val, UINT8 cnt ); // E2Prom reading continuously for every area. +extern void ReadE2Prom( unsigned char address, unsigned char * val ); // Read data from E2Prom +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +extern UINT8 WriteE2Prom( UINT8 address, UINT8 data ); // E2Prom writing for user area 1byte. +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + +/* Gyro Offset Adjustment */ +extern void GyroOffsetMeasureStart124( void ); // start the gyro offset adjustment +extern UINT8 GetGyroOffset124( UINT16* GyroOffsetX, UINT16* GyroOffsetY, INT16 GYROF_UPPER, INT16 GYROF_LOWER ); // get the gyro offset values. +extern void SetGyroOffset124( UINT16 GyroOffsetX, UINT16 GyroOffsetY, UINT16 GyroOffsetZ ); // set the gyro offset data. before do this before Remapmain. + +/* Angle correction for 45deg*/ +extern UINT8 SetAngleCorrection124( float DegreeGap, UINT8 SelectAct, unsigned char Arrangement ); + +extern void SetGyroAccelCoef( UINT8 ); + +/* AF position Control [mandatory] */ +extern void SetTregAf( UINT16 UsTregAf ); // Bi-direction : Min:000h Max:7FFh (11bit) + +/* Status Read and OIS enable [mandatory] */ +extern UINT8 RdStatus124( UINT8 UcStBitChk ); // Status Read whether initialization finish or not. +extern void OisEna124( void ); // OIS Enable Function + +/* Others [option] */ +extern UINT8 RtnCen124( UINT8 UcCmdPar ) ; // Return to Center Function. Hall servo on/off +extern UINT8 ZscCnt( UINT8 ) ; // Zero servo control +extern UINT8 AfStbyRls( void ); // Af Standby release Command Function +extern void SetPanTiltMode124( UINT8 UcPnTmod ); // default ON. +extern void SetSinWavePara( UINT8 , UINT8 ) ; // Circle movement + +extern UINT8 RunHea124( void ) ; // Hall Examination of Acceptance +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +extern UINT8 RunGea124( void ) ; // Gyro Examination of Acceptance +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + +extern void GyroOffsetMeasureStartZ124( void ); // start the gyro Z offset adjustment +extern UINT32 TneZeroServo( UINT8 , float ); /* zero servo adjustment command */ +extern UINT8 ZeroServoLmt( UINT8 UCMODE ); +extern UINT32 TneAvc( UINT8 ucposture ); // Accel offset adjustment + +/* Accl Offset Adjustment */ +extern void SetAcclOffset124( UINT16 AcclOffsetX, UINT16 AcclOffsetY, UINT16 AcclOffsetZ ); // set the accl offset data. before do this before Remapmain. +extern void GetAcclOffset124( UINT16* AcclOffsetX, UINT16* AcclOffsetY, UINT16* AcclOffsetZ ); // get the accl offset values. + +extern void LinearityCalculation( void ); // Linearity correction +extern void CrosstalkCalculation( void ); // Crosstalk correction +extern void SetOpticalOffset( void ); // optical offset + + +//**************************************************** +// API FUNCTION LIST for module maker +//**************************************************** +/* Calibration Main [mandatory] */ +extern UINT32 TneRun( void ); // calibration for bi-direction AF + +/* E2Prom Access */ +extern UINT8 WrHallCalData124( void ); // upload the calibration data except gyro gain to eeprom +extern UINT8 WrOptOffsetData( void ); // upload the opt offset data +extern UINT8 WrGyroGainData124( void ); // upload the gyro gain to eeprom +extern UINT8 WrAfParameter( UINT8 ); // upload af parameter to eeprom +extern UINT8 WrZeroServoData( void ); // upload the servo servo parameter to eepom + +//extern UINT8 WrLinCrsData( UINT8 writemode ); // upload linearity & cross talk parameter to eeprom +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +extern UINT8 WrHallLnData( UINT8 UcMode, mlLinearityValue *linval ); // upload linearity position to eeprom +extern UINT8 WrMixCalData124( UINT8 UcMode, mlMixingValue *mixval ); // upload cross talk to eeprom +extern UINT8 CalcSetMizxAndLinearityData( mlLinearityValue *, mlMixingValue * ) ; +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + +/* NOTEST */ +//extern UINT8 NotestMain( void ); // for NOTEST (E2prom erase & data set) +//extern void TimPro( void ); // for NOTEST (OSC measurement function for 1msec interruption) + + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisCmd.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisCmd.c new file mode 100755 index 0000000000000000000000000000000000000000..ce1b623cb8e94cfe31ba392bf7817262ce78a05b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisCmd.c @@ -0,0 +1,2988 @@ +//******************************************************************************** +// << LC898124 Evaluation Soft >> +// Program Name : OisCmd.c +// Design : Y.Shigoeka +// History : First edition +//******************************************************************************** +//************************** +// Include Header File +//************************** +#include <stdlib.h> /* use for abs() */ +#include <math.h> /* use for sqrt() */ + +#include "Ois.h" +#include "OisAPI.h" +#include "OisLc898124EP3.h" + +#if USE_BOSCH +#include "Ois_BOSCH.h" +#include "bmi2_defs.h" +#include "bmi260.h" +#include "bmi2.h" +#endif + +//**************************************************** +// MODE SELECTORS (Compile Switches) +//**************************************************** +//#define NEUTRAL_CENTER // Upper Position Current 0mA Measurement +//#define NEUTRAL_CENTER_FINE // Optimize natural center current + +#define HALL_ADJ_SERVO_ON // + +#define HALLADJ_FULLCURRENT + +#define TNE_PTP_NO_SIN + +//**************************************************** +// LC898124 calibration parameters +//**************************************************** +#if (((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) // SEMCO or Oneplus + #include "LC898124EP3_Calibration_SO2821.h" +#endif +#if (((SELECT_VENDOR&0x02) == 0x02) || ((SELECT_VENDOR&0x80) == 0x80)) // OFILM or Oneplus + #include "LC898124EP3_Calibration_M12337.h" +#endif +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A(int addr, int data); +extern void RamRead32A( unsigned short addr, void * data ); +extern void WitTim( unsigned short UsWitTim ); +extern void ClearLaser( void ) ; +extern short GetLaser( void ) ; +extern void OisDis124( void ); + +#if USE_BOSCH +extern int8_t bmi2_i2c_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len); +extern int8_t bmi2_i2c_write(uint8_t dev_addr, uint8_t reg_addr, const uint8_t *data, uint16_t len); +extern void bmi2_delay_milli_sec(uint32_t period); +#endif + +//**************************************************** +// extern Function LIST +//**************************************************** +extern void MesFil124( UINT8 ) ; // Measure Filter Setting +extern void MeasureStart124( INT32 , UINT32 , UINT32 ) ; // Measure Start Function +extern void MeasureStart2( INT32, INT32, INT32, UINT16 ); +extern void MeasureWait124( void ) ; // Measure Wait +extern void SetTransDataAdr124( UINT16 UsLowAddress , UINT32 UlLowAdrBeforeTrans ); + +extern void SetSinWavGenInt124( void ); + +extern stAdjPar StAdjPar124 ; // Execute Command Parameter +extern UINT16 UsGzoVal ; // Gyro A/D Offset X + +#ifdef SEL_SHIFT_COR +extern stPosOff StPosOff124 ; //!< Execute Command Parameter +extern stAclVal StAclVal124 ; //!< Execute Command Parameter +#endif //SEL_SHIFT_COR + +extern void DMIOWrite32( UINT32 IOadrs, UINT32 IOdata ); + +#ifdef ZERO_SERVO + +extern stZeroServo StZeroServoX; +extern stZeroServo StZeroServoY; +extern stZeroServo StZeroServoZ; + +INT32 GYROZ_OFFSET; + +typedef struct STZEROSERVOMES{ + INT32 SlHallP ; // + INT32 SlAcclP ; // +} stZeroServoMes ; + +stZeroServoMes StZeroServoMesX; +stZeroServoMes StZeroServoMesY; + +INT32 UlPostureSt; + +#endif //ZERO_SERVO + +//**************************************************** +// Local Function LIST +//**************************************************** +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +UINT32 TnePtp ( UINT8 UcDirSel, UINT8 UcBfrAft, ADJ_HALL* p, UINT8 UcSrvSwitch ); +UINT32 TneCen( UINT8 UcTneAxs, ADJ_HALL* ptr, UINT8 UcSrvSwitch ); +void TneOff( UnDwdVal, UINT8 ) ; // Hall Offset Tuning +void TneBia( UnDwdVal, UINT8, UINT16, UINT8 ) ; // Hall Bias Tuning +UINT32 LopGan( UINT8 UcDirSel, ADJ_LOPGAN* ptr ); +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) +void TneHvc( void ); +UINT32 TneGvc( void ); +void TneFin( ADJ_LOPGAN* ptr ); + +//**************************************************** +// Parameter LIST +//**************************************************** +//#define HALL_ADJ 0 +//#define LOOPGAIN 1 +#define THROUGH 2 +#define NOISE 3 +#define OSCCHK 4 +// Measure Mode + +#define PTP_BEFORE 0 +#define PTP_AFTER 1 + +#define TNE 80 // Waiting Time For Movement +#define OFFSET_DIV 2 // Divide Difference For Offset Step +#define TIME_OUT 20 // Time Out Count + +#define BIAS_HLMT (0xBF000000 ) +#define BIAS_LLMT (0x20000000 ) + +//#ifdef ZERO_SERVO +/************** posture check ************/ +#define SENSITIVITY 4096 // LSB/g +#define PSENS_MARG (SENSITIVITY / 4) // 1/4g +#define POSTURETH_P (SENSITIVITY - PSENS_MARG) // LSB/g +#define POSTURETH_M (-POSTURETH_P) // LSB/g +/************** posture check ************/ +//#endif //ZERO_SERVO + + + + +#define HAll_SCAILING + + + + +//**************************************************** +// LOCAL RAM LIST +//**************************************************** +INT16 SsNvcX = 1 ; // NVC move direction X +INT16 SsNvcY = 1 ; // NVC move direction Y + +UINT8 BeforeControl; + +Act_Mov_t StActMov = { + 0x19998000, + 0xE6668000, + 0xFCCD0000 +} ; + +//UINT32 UlHall_ActMov[ 16 ] ; + +//******************************************************************************** +// Function Name : DacControl +// Retun Value : Firmware version +// Argment Value : NON +// Explanation : Dac Control Function +// History : First edition +//******************************************************************************** +void DacControl( UINT32 UiChannel, UINT32 PuiData ) +{ + DMIOWrite32( ADDA_DASEL, UiChannel ); + DMIOWrite32( ADDA_DAO, PuiData ); +} + +#ifndef __OIS_UIOIS_GYRO_USE__ +//******************************************************************************** +// Function Name : GetGyroOffset124 +// Retun Value : NON +// Argment Value : NON +// Explanation : start the gyro offset adjustment and get result +// History : First edition +//******************************************************************************** +#define GYROF_NUM 2048 // 2048times +#define GYROF_UPPER 0x06D6 // +#define GYROF_LOWER 0xF92A // +UINT32 TneGvc( void ) +{ + UINT32 UlRsltSts; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + INT32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureAveValueA , SlMeasureAveValueB ; + + + //•½‹Ï’l‘ª’è + + MesFil124( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = GYROF_NUM ; // Measurement times + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address + + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + +TRACE("Read Adr = %04x, %04xh \n",StMeasFunc_MFA_LLiIntegral1 + 4 , StMeasFunc_MFA_LLiIntegral1) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + +TRACE("GX_OFT = %08x, %08xh \n",(unsigned int)StMeasValueA.StUllnVal.UlHigVal,(unsigned int)StMeasValueA.StUllnVal.UlLowVal) ; +TRACE("GY_OFT = %08x, %08xh \n",(unsigned int)StMeasValueB.StUllnVal.UlHigVal,(unsigned int)StMeasValueB.StUllnVal.UlLowVal) ; + SlMeasureAveValueA = (INT32)( (INT64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT32)( (INT64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; +TRACE("GX_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueA) ; +TRACE("GY_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueB) ; + + SlMeasureAveValueA = ( SlMeasureAveValueA >> 16 ) & 0x0000FFFF ; + SlMeasureAveValueB = ( SlMeasureAveValueB >> 16 ) & 0x0000FFFF ; + // EP1‚ł͔½“]ˆ—‚µ‚È‚¢B +// SlMeasureAveValueA = 0x00010000 - SlMeasureAveValueA ; +// SlMeasureAveValueB = 0x00010000 - SlMeasureAveValueB ; + + UlRsltSts = EXE_END ; + StAdjPar124.StGvcOff.UsGxoVal = ( UINT16 )( SlMeasureAveValueA & 0x0000FFFF ); //Measure Result Store + if(( (INT16)StAdjPar124.StGvcOff.UsGxoVal > (INT16)GYROF_UPPER ) || ( (INT16)StAdjPar124.StGvcOff.UsGxoVal < (INT16)GYROF_LOWER )){ + UlRsltSts |= EXE_GXADJ ; + } + RamWrite32A( GYRO_RAM_GXOFFZ , (( SlMeasureAveValueA << 16 ) & 0xFFFF0000 ) ) ; // X axis Gyro offset + + StAdjPar124.StGvcOff.UsGyoVal = ( UINT16 )( SlMeasureAveValueB & 0x0000FFFF ); //Measure Result Store + if(( (INT16)StAdjPar124.StGvcOff.UsGyoVal > (INT16)GYROF_UPPER ) || ( (INT16)StAdjPar124.StGvcOff.UsGyoVal < (INT16)GYROF_LOWER )){ + UlRsltSts |= EXE_GYADJ ; + } + RamWrite32A( GYRO_RAM_GYOFFZ , (( SlMeasureAveValueB << 16 ) & 0xFFFF0000 ) ) ; // Y axis Gyro offset + +TRACE("GX_AVEOFT_RV = %08xh \n",(unsigned int)SlMeasureAveValueA) ; +TRACE("GY_AVEOFT_RV = %08xh \n",(unsigned int)SlMeasureAveValueB) ; + + RamWrite32A( GYRO_RAM_GYROX_OFFSET , 0x00000000 ) ; // X axis Drift Gyro offset + RamWrite32A( GYRO_RAM_GYROY_OFFSET , 0x00000000 ) ; // Y axis Drift Gyro offset + RamWrite32A( GyroFilterDelayX_GXH1Z2 , 0x00000000 ) ; // X axis H1Z2 Clear + RamWrite32A( GyroFilterDelayY_GYH1Z2 , 0x00000000 ) ; // Y axis H1Z2 Clear + + return( UlRsltSts ); + + +} +#endif + + +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +//******************************************************************************** +// Function Name : HallAdj +// Retun Value : Hall Tuning SUCCESS or FAILURE +// Argment Value : NON +// Explanation : Hall System Auto Adjustment Function +// History : First edition +//******************************************************************************** +UINT32 HallAdj( ADJ_HALL* Ptr, ADJ_LOPGAN *LopgainPtr ) +{ + UINT32 UlHlxSts, UlHlySts, UlReadVal; + + RtnCen124( BOTH_OFF ) ; // Both OFF + WitTim( TNE ) ; +#ifdef HALL_ADJ_SERVO_ON + RamWrite32A( HALL_RAM_HXOFF, 0x00000000 ) ; // X Offset Clr + RamWrite32A( HALL_RAM_HYOFF, 0x00000000 ) ; // Y Offset Clr + RamWrite32A( HallFilterCoeffX_hxgain0 , LopgainPtr->Hxgain ) ; + RamWrite32A( HallFilterCoeffY_hygain0 , LopgainPtr->Hygain ) ; +#endif + DacControl( HLXBO , Ptr->BiasInit ) ; + RamWrite32A( StCaliData_UiHallBias_X , Ptr->BiasInit ) ; + DacControl( HLYBO , Ptr->BiasInit ) ; + RamWrite32A( StCaliData_UiHallBias_Y , Ptr->BiasInit ) ; + DacControl( HLXO, Ptr->OffsetInit ) ; + RamWrite32A( StCaliData_UiHallOffset_X , Ptr->OffsetInit ) ; + DacControl( HLYO, Ptr->OffsetInit ) ; + RamWrite32A( StCaliData_UiHallOffset_Y , Ptr->OffsetInit ) ; + + BeforeControl=1; +#if ( (SELECT_VENDOR&0x02) == 0x02 ) //JAHWA + + UlHlySts = TneCen( Y_DIR, Ptr, OFF ) ; + + WitTim( TNE ) ; + BeforeControl=1; + UlHlxSts = TneCen( X_DIR, Ptr, OFF ) ; + + StAdjPar.StHalAdj.UsHlyCna = ( UINT16 )( ( INT16 )StAdjPar.StHalAdj.UsHlyCna - ( INT16 )(Ptr->MagneticOffset_Y) ) ; + RamWrite32A( HALL_RAM_HYOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlyCna << 16 ) & 0xFFFF0000 ) ) ; + StAdjPar.StHalAdj.UsHlxCna = ( UINT16 )( ( INT16 )StAdjPar.StHalAdj.UsHlxCna - ( INT16 )(Ptr->MagneticOffset_X) ) ; + RamWrite32A( HALL_RAM_HXOFF, ( ( ( UINT32 )StAdjPar.StHalAdj.UsHlxCna << 16 ) & 0xFFFF0000 ) ) ; + +#ifdef HALL_ADJ_SERVO_ON + RtnCen124( BOTH_ON ) ; // Y ON / X OFF +#endif + WitTim( TNE ) ; + + UlHlySts = TneCen( Y_DIR, Ptr, ON ) ; + StAdjPar.StHalAdj.UsHlyCna = ( UINT16 )( ( INT16 )StAdjPar124.StHalAdj.UsHlyCna - ( INT16 )Ptr->MagneticOffset_Y ) ; + RamWrite32A( HALL_RAM_HYOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlyCna << 16 ) & 0xFFFF0000 ) ) ; + + WitTim( TNE ) ; + UlHlxSts = TneCen( X_DIR, Ptr, ON ) ; + StAdjPar.StHalAdj.UsHlxCna = ( UINT16 )( ( INT16 )StAdjPar124.StHalAdj.UsHlxCna - ( INT16 )Ptr->MagneticOffset_X ) ; + RamWrite32A( HALL_RAM_HXOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlxCna << 16 ) & 0xFFFF0000 ) ) ; +#ifdef HALL_ADJ_SERVO_ON + RtnCen124( BOTH_OFF ) ; // Y OFF / X ON +#endif + WitTim( TNE ) ; +#else + UlHlySts = TneCen( Y_DIR, Ptr, OFF ) ; + StAdjPar.StHalAdj.UsHlyCna -= Ptr->MagneticOffset_Y ; + StAdjPar.StHalAdj.UsHlyCna = ( UINT16 )( ( INT16 )StAdjPar124.StHalAdj.UsHlyCna - ( INT16 )Ptr->MagneticOffset_Y ) ; + RamWrite32A( HALL_RAM_HYOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlyCna << 16 ) & 0xFFFF0000 ) ) ; + + WitTim( TNE ) ; + + BeforeControl=1; + UlHlxSts = TneCen( X_DIR, Ptr, OFF ) ; + StAdjPar.StHalAdj.UsHlxCna = ( UINT16 )( ( INT16 )StAdjPar124.StHalAdj.UsHlxCna - ( INT16 )Ptr->MagneticOffset_X ) ; + RamWrite32A( HALL_RAM_HXOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlxCna << 16 ) & 0xFFFF0000 ) ) ; + + if( (UlHlxSts != EXE_HXADJ) && (UlHlySts != EXE_HYADJ) ){ +#ifdef HALL_ADJ_SERVO_ON + RtnCen124( BOTH_ON ) ; // Y ON / X OFF +#endif + WitTim( TNE ) ; + + UlHlySts = TneCen( Y_DIR, Ptr, ON ) ; + StAdjPar.StHalAdj.UsHlyCna = ( UINT16 )( ( INT16 )StAdjPar124.StHalAdj.UsHlyCna - ( INT16 )Ptr->MagneticOffset_Y ) ; + RamWrite32A( HALL_RAM_HYOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlyCna << 16 ) & 0xFFFF0000 ) ) ; + + WitTim( TNE ) ; + UlHlxSts = TneCen( X_DIR, Ptr, ON ) ; + StAdjPar.StHalAdj.UsHlxCna = ( UINT16 )( ( INT16 )StAdjPar124.StHalAdj.UsHlxCna - ( INT16 )Ptr->MagneticOffset_X ) ; + RamWrite32A( HALL_RAM_HXOFF, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlxCna << 16 ) & 0xFFFF0000 ) ) ; +#ifdef HALL_ADJ_SERVO_ON + RtnCen124( BOTH_OFF ) ; // Both OFF +#endif + WitTim( TNE ) ; + } +#endif + + + RamRead32A( StCaliData_UiHallOffset_X , &UlReadVal ) ; + StAdjPar124.StHalAdj.UsHlxOff = (UINT16)( UlReadVal >> 16 ) ; + + RamRead32A( StCaliData_UiHallBias_X , &UlReadVal ) ; + StAdjPar124.StHalAdj.UsHlxGan = (UINT16)( UlReadVal >> 16 ) ; + + RamRead32A( StCaliData_UiHallOffset_Y , &UlReadVal ) ; + StAdjPar124.StHalAdj.UsHlyOff = (UINT16)( UlReadVal >> 16 ) ; + + RamRead32A( StCaliData_UiHallBias_Y , &UlReadVal ) ; + StAdjPar124.StHalAdj.UsHlyGan = (UINT16)( UlReadVal >> 16 ) ; + +#if ((SELECT_VENDOR&0x01) == 0x01) // SEMCO +#ifdef HAll_SCAILING // start : Calculation Hall Min/max Cut - added 2018/11/16 + UINT16 UsMax_hall_cut_X, UsMin_hall_cut_X ; + UINT16 UsMax_hall_cut_Y, UsMin_hall_cut_Y ; + INT16 SsTmp ; + + UsMax_hall_cut_X = Ptr->HallMax_X ; + UsMin_hall_cut_X = Ptr->HallMin_X ; + + UsMax_hall_cut_Y = Ptr->HallMax_Y ; + UsMin_hall_cut_Y = Ptr->HallMin_Y ; + + // Xch hall Cut + SsTmp = ( INT16 )StAdjPar.StHalAdj.UsHlxMxa ; + TRACE( "Hall X Max = %d\n", SsTmp ) ; + SsTmp = ( INT16 )( ( INT32 )SsTmp * ( 100 - UsMax_hall_cut_X * 2 ) / 100 ) ; + TRACE( "Hall X Max Cut = %d\n", SsTmp ) ; + StAdjPar124.StHalAdj.UsHlxMxa = ( UINT16 )SsTmp ; + RamWrite32A( StCaliData_SiHallMax_After_X, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlxMxa << 16 ) & 0xFFFF0000 ) ) ; + + SsTmp = ( INT16 )StAdjPar.StHalAdj.UsHlxMna ; + TRACE( "Hall X Min = %d\n", SsTmp ) ; + SsTmp = ( INT16 )( ( INT32 )SsTmp * ( 100 - UsMin_hall_cut_X * 2 ) / 100 ) ; + TRACE( "Hall X Min Cut = %d\n", SsTmp ) ; + StAdjPar124.StHalAdj.UsHlxMna = ( UINT16 )SsTmp ; + RamWrite32A( StCaliData_SiHallMin_After_X, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlxMna << 16 ) & 0xFFFF0000 ) ) ; + + // Ych hall Cut + SsTmp = ( INT16 )StAdjPar124.StHalAdj.UsHlyMxa ; + TRACE( "Hall Y Max = %d\n", SsTmp ) ; + SsTmp = ( INT16 )( ( INT32 )SsTmp * ( 100 - UsMax_hall_cut_Y * 2 ) / 100 ) ; + TRACE( "Hall Y Max Cut = %d\n", SsTmp ) ; + StAdjPar124.StHalAdj.UsHlyMxa = ( UINT16 )SsTmp ; + RamWrite32A( StCaliData_SiHallMax_After_Y, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlyMxa << 16 ) & 0xFFFF0000 ) ) ; + + SsTmp = ( INT16 )StAdjPar124.StHalAdj.UsHlyMna ; + TRACE( "Hall Y Min = %d\n", SsTmp ) ; + SsTmp = ( INT16 )( ( INT32 )SsTmp * ( 100 - UsMin_hall_cut_Y * 2 ) / 100 ) ; + TRACE( "Hall Y Min Cut = %d\n", SsTmp ) ; + StAdjPar124.StHalAdj.UsHlyMna = ( UINT16 )SsTmp ; + RamWrite32A( StCaliData_SiHallMin_After_Y, ( ( ( UINT32 )StAdjPar124.StHalAdj.UsHlyMna << 16 ) & 0xFFFF0000 ) ) ; +#endif // end : Calculation Hall Min/max Cut - added 2018/11/16 +#endif + +#ifdef HALL_ADJ_SERVO_ON + RtnCen124( BOTH_OFF ) ; // Both OFF + WitTim( TNE ) ; +#endif + return ( UlHlySts | UlHlxSts ); +} + + +//******************************************************************************** +// Function Name : TneRun +// Retun Value : Hall Tuning SUCCESS or FAILURE +// Argment Value : NON +// Explanation : Hall System Auto Adjustment Function +// History : First edition +//******************************************************************************** +UINT32 TneRun( void ) +{ + UINT32 UlFinSts, UlReadVal; + ADJ_HALL* HallPtr; + ADJ_LOPGAN* LopgainPtr; + DSPVER Info; + + // Check the status + RamWrite32A( CMD_IO_ADR_ACCESS , ROMINFO ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + if( UlReadVal != 0x01) return( EXE_ERROR ); + + // Select parameter + if( GetInfomationAfterDownload( &Info ) != 0){ + return( EXE_ERROR ); +#if (((SELECT_VENDOR&0x01) == 0x01) || ((SELECT_VENDOR&0x80) == 0x80)) // SEMCO or Oneplus + + }else if( Info.ActType == ACT_SO2821 ) { + HallPtr = (ADJ_HALL*)&SO2821_HallCalParameter; + LopgainPtr = (ADJ_LOPGAN* )&SO2821_LoopGainParameter; +#endif +#if (((SELECT_VENDOR&0x02) == 0x02) || ((SELECT_VENDOR&0x80) == 0x80)) // OFILM or Oneplus + }else if( Info.ActType == ACT_M12337_A1 ){ + HallPtr = (ADJ_HALL*)&M12337_HallCalParameter; + LopgainPtr = (ADJ_LOPGAN* )&M12337_LoopGainParameter; +TRACE("Act:M12337\n") ; +#endif + }else{ + return( EXE_ERROR ); + } + + /* Hall Adjustment */ + UlFinSts = HallAdj( HallPtr, LopgainPtr ); +// if( Info.ActType == ACT_SEMCO ) { +// if( ((UlFinSts & EXE_HXADJ) == EXE_HXADJ) || ((UlFinSts & EXE_HYADJ) == EXE_HYADJ) ){ +// HallPtr = (ADJ_HALL*)&SO_HallCalParameter_F; +// UlFinSts = HallAdj( HallPtr ); +// } +// }else{ + if( ((UlFinSts & EXE_HXADJ) == EXE_HXADJ) || ((UlFinSts & EXE_HYADJ) == EXE_HYADJ) ) return ( UlFinSts ); +// } + + /* Hall Offser (neutral center)*/ +#ifdef NEUTRAL_CENTER + TneHvc(); +#endif + +#ifdef NEUTRAL_CENTER_FINE + TneFin( LopgainPtr ); +#endif + +//20180906 Komori + StAdjPar124.StHalAdj.UsAdxOff = StAdjPar124.StHalAdj.UsHlxCna ; + StAdjPar124.StHalAdj.UsAdyOff = StAdjPar124.StHalAdj.UsHlyCna ; +TRACE(" Xadof = %04xh \n", StAdjPar124.StHalAdj.UsAdxOff ) ; +TRACE(" Yadof = %04xh \n", StAdjPar124.StHalAdj.UsAdyOff ) ; + + RamWrite32A( HALL_RAM_HXOFF, (UINT32)((StAdjPar124.StHalAdj.UsAdxOff << 16 ) & 0xFFFF0000 )) ; + RamWrite32A( HALL_RAM_HYOFF, (UINT32)((StAdjPar124.StHalAdj.UsAdyOff << 16 ) & 0xFFFF0000 )) ; +//20180906 Komori + + /* Loop gain Adjustment */ + RamWrite32A( HallFilterCoeffX_hxgain0 , LopgainPtr->Hxgain ) ; + RamWrite32A( HallFilterCoeffY_hygain0 , LopgainPtr->Hygain ) ; + RtnCen124( BOTH_ON ) ; // Y ON / X ON + WitTim( TNE ) ; + UlFinSts |= LopGan( X_DIR, LopgainPtr ) ; // X Loop Gain Adjust + UlFinSts |= LopGan( Y_DIR, LopgainPtr ) ; // Y Loop Gain Adjust + + /* Gyro DC offset Adjustment */ +#ifdef __OIS_UIOIS_GYRO_USE__ +#else + UlFinSts |= TneGvc() ; +#endif + StAdjPar124.StHalAdj.UlAdjPhs = UlFinSts ; + return( UlFinSts ) ; +} + + +//******************************************************************************** +// Function Name : TnePtp +// Retun Value : Hall Top & Bottom Gaps +// Argment Value : X,Y Direction, Adjust Before After Parameter +// Explanation : Measuring Hall Paek To Peak +// History : First edition +//******************************************************************************** +UINT32 TnePtp ( UINT8 UcDirSel, UINT8 UcBfrAft, ADJ_HALL* p, UINT8 UcSrvSwitch ) +{ + UnDwdVal StTneVal ; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + INT32 SlMeasureMaxValue , SlMeasureMinValue ; + UINT16 UsSinAdr ; + + INT32 SlMeasureParameterNum ; + INT32 sl_act_min_drv, sl_act_max_drv ; + + +TRACE("TnePtp\n ") ; +#ifdef HALLADJ_FULLCURRENT + if( UcSrvSwitch != ON ) { + DMIOWrite32( OISDRVFC1 , 0x00000003 ); + } +#endif //HALLADJ_FULLCURRENT + + if( UcDirSel == X_DIR ) { // X axis + SlMeasureParameterA = HALL_RAM_HXIDAT ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HYIDAT ; // Set Measure RAM Address + if( UcSrvSwitch != ON ) { + UsSinAdr = HALL_RAM_SINDX1; + } else { + UsSinAdr = HALL_RAM_HXOFF1; + } + sl_act_max_drv = p->ActMaxDrive_X ; + sl_act_min_drv = p->ActMinDrive_X ; + } else if( UcDirSel == Y_DIR ) { // Y axis + SlMeasureParameterA = HALL_RAM_HYIDAT ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HXIDAT ; // Set Measure RAM Address + if( UcSrvSwitch != ON ) { + UsSinAdr = HALL_RAM_SINDY1; + } else { + UsSinAdr = HALL_RAM_HYOFF1; + } + sl_act_max_drv = p->ActMaxDrive_Y ; + sl_act_min_drv = p->ActMinDrive_Y ; + } + + MesFil124( THROUGH ) ; // Filter setting for measurement + + if( UcSrvSwitch != ON ) { + RamWrite32A( UsSinAdr, 0x7FFFFFFF ) ; + } else { + RamWrite32A( UsSinAdr, sl_act_min_drv ) ; + } + +#if ( (SELECT_VENDOR&0x02) == 0x02 ) //JAHWA + SlMeasureParameterNum = 256 ; + WitTim(30); +#else + SlMeasureParameterNum = 2000 ; +#endif + MeasureStart2124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB, 50 ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_SiMin1 , ( UINT32 * )&SlMeasureMinValue ) ; // Min value + + if( UcSrvSwitch != ON ) { + RamWrite32A( UsSinAdr, 0x80000001 ) ; + } else { + RamWrite32A( UsSinAdr, sl_act_max_drv) ; + } + +#if ( (SELECT_VENDOR&0x02) == 0x02 ) //JAHWA + SlMeasureParameterNum = 256 ; + WitTim(30); +#else + SlMeasureParameterNum = 2000 ; +#endif + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_SiMax1 , ( UINT32 * )&SlMeasureMaxValue ) ; // Max value + + StTneVal.StDwdVal.UsHigVal = (UINT16)((SlMeasureMaxValue >> 16) & 0x0000FFFF ); + StTneVal.StDwdVal.UsLowVal = (UINT16)((SlMeasureMinValue >> 16) & 0x0000FFFF ); + + RamWrite32A( UsSinAdr, 0 ) ; + + +#ifdef HALLADJ_FULLCURRENT + if( UcSrvSwitch != ON ) { + DMIOWrite32( OISDRVFC1 , 0x00000000 ); + } +#endif //HALLADJ_FULLCURRENT + +TRACE("\nPTP topbtm H = %04xh , L = %04xh , AXIS = %02x \n", StTneVal.StDwdVal.UsHigVal,StTneVal.StDwdVal.UsLowVal ,UcDirSel ) ; + + if( UcBfrAft == 0 ) { + if( UcDirSel == X_DIR ) { + StAdjPar124.StHalAdj.UsHlxCen = ( ( INT16 )StTneVal.StDwdVal.UsHigVal + ( INT16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar124.StHalAdj.UsHlxMax = StTneVal.StDwdVal.UsHigVal ; + StAdjPar124.StHalAdj.UsHlxMin = StTneVal.StDwdVal.UsLowVal ; + } else if( UcDirSel == Y_DIR ){ + StAdjPar124.StHalAdj.UsHlyCen = ( ( INT16 )StTneVal.StDwdVal.UsHigVal + ( INT16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar124.StHalAdj.UsHlyMax = StTneVal.StDwdVal.UsHigVal ; + StAdjPar124.StHalAdj.UsHlyMin = StTneVal.StDwdVal.UsLowVal ; + } + } else { + if( UcDirSel == X_DIR ){ + StAdjPar124.StHalAdj.UsHlxCna = ( ( INT16 )StTneVal.StDwdVal.UsHigVal + ( INT16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar124.StHalAdj.UsHlxMxa = StTneVal.StDwdVal.UsHigVal ; + StAdjPar124.StHalAdj.UsHlxMna = StTneVal.StDwdVal.UsLowVal ; + } else if( UcDirSel == Y_DIR ){ + StAdjPar124.StHalAdj.UsHlyCna = ( ( INT16 )StTneVal.StDwdVal.UsHigVal + ( INT16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar124.StHalAdj.UsHlyMxa = StTneVal.StDwdVal.UsHigVal ; + StAdjPar124.StHalAdj.UsHlyMna = StTneVal.StDwdVal.UsLowVal ; + } + } + +TRACE(" ADJ(%d) MAX = %04x, MIN = %04x, CNT = %04x, ", UcDirSel, StTneVal.StDwdVal.UsHigVal, StTneVal.StDwdVal.UsLowVal, ( ( signed int )StTneVal.StDwdVal.UsHigVal + ( signed int )StTneVal.StDwdVal.UsLowVal ) / 2 ) ; + StTneVal.StDwdVal.UsHigVal = 0x7fff - StTneVal.StDwdVal.UsHigVal ; // Maximum Gap = Maximum - Hall Peak Top + StTneVal.StDwdVal.UsLowVal = StTneVal.StDwdVal.UsLowVal - 0x8000 ; // Minimum Gap = Hall Peak Bottom - Minimum + +TRACE(" GapH = %04x, GapL = %04x\n", StTneVal.StDwdVal.UsHigVal, StTneVal.StDwdVal.UsLowVal ) ; +TRACE(" Raw MAX = %08x, MIN = %08x\n", (unsigned int)SlMeasureMaxValue , (unsigned int)SlMeasureMinValue ) ; + + return( StTneVal.UlDwdVal ) ; +} + +//******************************************************************************** +// Function Name : TneCen +// Retun Value : Hall Center Tuning Result +// Argment Value : X,Y Direction, Hall Top & Bottom Gaps +// Explanation : Hall Center Tuning Function +// History : First edition +//******************************************************************************** +UINT32 TneCen( UINT8 UcTneAxs, ADJ_HALL* ptr, UINT8 UcSrvSwtich ) +{ + UnDwdVal StTneVal ; + UINT8 UcTmeOut =1, UcTofRst= FAILURE ; + UINT16 UsBiasVal ; +#if ( (SELECT_VENDOR&0x02) == 0x02 ) //JAHWA + UINT32 UlTneRst = FAILURE, UlValNow ; +#else + UINT32 UlTneRst = FAILURE, UlBiasVal , UlValNow ; +#endif + UINT16 UsValBef,UsValNow ; + UINT32 UlBiaBef,UlBiaNow ; + + if( BeforeControl != 0 ) { + StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_BEFORE, ptr, UcSrvSwtich ) ; + } else { + StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_AFTER, ptr, UcSrvSwtich ) ; + } + BeforeControl=0; +#if ( (SELECT_VENDOR&0x02) == 0x02 ) //JAHWA + UcTofRst = SUCCESS ; /* Žb’è‚ÅOK‚É‚·‚é */ + while ( UlTneRst && (UINT32)UcTmeOut ) + { + if ( UcTmeOut == 1 && (UcSrvSwtich != ON) ){ +TRACE("1st PtoP =%08x \n", ((UINT16)0xFFFF - (StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal)) ) ; + // ‰‰ñ‚ÌPtp‚ÅŠù‚ÉTarget Range‚É“ü‚Á‚Ä‚¢‚é‚È‚çI—¹B + if((( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) < ptr->TargetMax ) + && (( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) > ptr->TargetMin ) ) { + UlTneRst = (UINT32)SUCCESS ; + break ; + } + } + + if( UcTofRst == FAILURE ) { + UcTofRst = SUCCESS ; /* Žb’è‚ÅOK‚É‚·‚é */ + }else{ + UlValNow = ( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )); + if( UcTneAxs == X_DIR ) UsValNow = StAdjPar.StHalAdj.UsHlxMxa; + else if( UcTneAxs == Y_DIR ) UsValNow = StAdjPar.StHalAdj.UsHlyMxa; + + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiaBef ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlBiaBef ) ; + } + TneBia( StTneVal, UcTneAxs, ptr->TargetRange, UcSrvSwtich ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiaNow ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlBiaNow ) ; + } + if((( UlBiaBef == BIAS_HLMT ) && ( UlBiaNow == BIAS_HLMT )) + || (( UlBiaBef == BIAS_LLMT ) && ( UlBiaNow == BIAS_LLMT ))){ + UcTmeOut += 10; + } + } + StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_AFTER, ptr, UcSrvSwtich ) ; + if( UcTneAxs == X_DIR ) UsValBef = StAdjPar.StHalAdj.UsHlxMxa; + else if( UcTneAxs == Y_DIR ) UsValBef = StAdjPar.StHalAdj.UsHlyMxa; + + if(( ((StTneVal.StDwdVal.UsHigVal > (0xFFFF - ptr->OffsetMargin) ) && (StTneVal.StDwdVal.UsLowVal > (0xFFFF - ptr->OffsetMargin ) )) + || ((StTneVal.StDwdVal.UsHigVal < ptr->OffsetMargin ) && (StTneVal.StDwdVal.UsLowVal < ptr->OffsetMargin )) )){ /* position check */ + UcTmeOut += 10; +TRACE("------OFFSETMARGIN-------\n"); + }else if( (UsValBef > (0x7FFF - ptr->OffsetMargin) ) ){ +TRACE("------CLOSELY MAX RANGE-------\n"); + }else{ + // AD11bit => upper 12bit detection. + if((( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) < ( ptr->TargetMax & 0xFFF0)) + && (( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) > ( ptr->TargetMin & 0xFFF0)) ) { +TRACE("Final PtoP =%08x \n", ((UINT16)0xFFFF - (StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal)) ) ; + UlTneRst = (UINT32)SUCCESS ; + break ; + } + } + //Recovery +TRACE("BeforeMax=%04x, AfterMax=%04x, ValNow=%08x PtoP =%08x \n", UsValNow, UsValBef, UlValNow, ((UINT16)0xFFFF - (StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal)) ) ; + if( (UcSrvSwtich == ON) && (UlValNow > ((UINT16)0xFFFF - (StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal))) ){ + if( (((UsValNow - UsValBef) < 0x0100) && ((UsValNow - UsValBef) >0)) || (((UsValBef - UsValNow) < 0x0100) && ((UsValBef - UsValNow) >0)) ){ +TRACE("---------!!Saturation!!---------\n" ) ; + if( (UlBiaBef > (BIAS_LLMT + ( UINT32 )(ptr->DecrementStep<<16) )) && (UlBiaNow != BIAS_HLMT) ){ + UsBiasVal = (UINT16)( UlBiaBef >> 16 ) ; + UsBiasVal -= ptr->DecrementStep; + UlBiaNow = ( UINT32 )( UsBiasVal << 16 ) ; + if( UcTneAxs == X_DIR ) { + DacControl( HLXBO , UlBiaNow ) ; + RamWrite32A( StCaliData_UiHallBias_X , UlBiaNow ) ; + }else if( UcTneAxs == Y_DIR ){ + DacControl( HLYBO , UlBiaNow ) ; + RamWrite32A( StCaliData_UiHallBias_Y , UlBiaNow ) ; + } + UcTofRst= FAILURE; +TRACE("new BIAS=%04x \n", UsBiasVal) ; + } + } + } + +#else + + TneOff( StTneVal, UcTneAxs ) ; + UcTofRst = SUCCESS ; /* Žb’è‚ÅOK‚É‚·‚é */ + + while ( UlTneRst && (UINT32)UcTmeOut ) + { + if( UcTofRst == FAILURE ) { +TRACE(" UcTofRst == FAILURE\n" ) ; + TneOff( StTneVal, UcTneAxs ) ; + StTneVal.UlDwdVal = TnePtp( UcTneAxs, PTP_AFTER, ptr, UcSrvSwtich ) ; + } else { +TRACE(" else\n" ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiaBef ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlBiaBef ) ; + } + TneBia( StTneVal, UcTneAxs, ptr->TargetRange, UcSrvSwtich ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiaNow ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlBiaNow ) ; + } + if((( UlBiaBef == BIAS_HLMT ) && ( UlBiaNow == BIAS_HLMT )) + || (( UlBiaBef == BIAS_LLMT ) && ( UlBiaNow == BIAS_LLMT ))){ + UcTmeOut += 10; +TRACE(" No = %04d (bias count up)\n", UcTmeOut ) ; + } + StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_AFTER, ptr, UcSrvSwtich ) ; + + UcTofRst = FAILURE ; +// if( UcTneAxs == X_DIR ) { +// RamRead32A( StCaliData_UiHallBias_X , &UlBiasVal ) ; +// }else if( UcTneAxs == Y_DIR ){ +// RamRead32A( StCaliData_UiHallBias_Y , &UlBiasVal ) ; +// } +// if(UlBiasVal == 0x00000000){ +// UcTmeOut = TIME_OUT; +// } + } + + if( (StTneVal.StDwdVal.UsHigVal > ptr->OffsetMargin ) && (StTneVal.StDwdVal.UsLowVal > ptr->OffsetMargin ) ) /* position check */ + { + UcTofRst = SUCCESS ; +TRACE(" TofR = SUCC\n" ) ; + UsValBef = UsValNow = 0x0000 ; + }else if( (StTneVal.StDwdVal.UsHigVal <= ptr->OffsetMargin ) && (StTneVal.StDwdVal.UsLowVal <= ptr->OffsetMargin ) ){ + UcTofRst = SUCCESS ; + UlTneRst = (UINT32)FAILURE ; + }else{ + UcTofRst = FAILURE ; +TRACE(" TofR = FAIL\n" ) ; + + UsValBef = UsValNow ; + + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallOffset_X , &UlValNow ) ; + UsValNow = (UINT16)( UlValNow >> 16 ) ; + }else if( UcTneAxs == Y_DIR ){ + RamRead32A( StCaliData_UiHallOffset_Y , &UlValNow ) ; + UsValNow = (UINT16)( UlValNow >> 16 ) ; + } + if( ((( UsValBef & 0xFF00 ) == 0x1000 ) && ( UsValNow & 0xFF00 ) == 0x1000 ) + || ((( UsValBef & 0xFF00 ) == 0xEF00 ) && ( UsValNow & 0xFF00 ) == 0xEF00 ) ) + { + UcTmeOut += 10; +TRACE(" No = %04d (offset count up)\n", UcTmeOut ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiasVal ) ; + UsBiasVal = (UINT16)( UlBiasVal >> 16 ) ; + }else if( UcTneAxs == Y_DIR ){ + RamRead32A( StCaliData_UiHallBias_Y , &UlBiasVal ) ; + UsBiasVal = (UINT16)( UlBiasVal >> 16 ) ; + } + + if( UsBiasVal > ptr->DecrementStep ) + { + UsBiasVal -= ptr->DecrementStep ; + } + + if( UcTneAxs == X_DIR ) { + UlBiasVal = ( UINT32 )( UsBiasVal << 16 ) ; + DacControl( HLXBO , UlBiasVal ) ; + RamWrite32A( StCaliData_UiHallBias_X , UlBiasVal ) ; + }else if( UcTneAxs == Y_DIR ){ + UlBiasVal = ( UINT32 )( UsBiasVal << 16 ) ; + DacControl( HLYBO , UlBiasVal ) ; + RamWrite32A( StCaliData_UiHallBias_Y , UlBiasVal ) ; + } + } + + } + if((( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) < ptr->TargetMax ) + && (( (UINT16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) > ptr->TargetMin ) ) { + if(UcTofRst == SUCCESS) + { + UlTneRst = (UINT32)SUCCESS ; + break ; + } + } +#endif + UlTneRst = (UINT32)FAILURE ; + UcTmeOut++ ; +TRACE(" Tne = FAIL\n" ) ; + +TRACE(" No = %04d", UcTmeOut ) ; + if ( UcTmeOut >= TIME_OUT ) { + UcTmeOut = 0 ; + } // Set Time Out Count + } + + SetSinWavGenInt124() ; // + + if( UlTneRst == (UINT32)FAILURE ) { + if( UcTneAxs == X_DIR ) { + UlTneRst = EXE_HXADJ ; + StAdjPar124.StHalAdj.UsHlxGan = 0xFFFF ; + StAdjPar124.StHalAdj.UsHlxOff = 0xFFFF ; + }else if( UcTneAxs == Y_DIR ) { + UlTneRst = EXE_HYADJ ; + StAdjPar124.StHalAdj.UsHlyGan = 0xFFFF ; + StAdjPar124.StHalAdj.UsHlyOff = 0xFFFF ; + } + } else { + UlTneRst = EXE_END ; + } + + return( UlTneRst ) ; +} + + + +//******************************************************************************** +// Function Name : TneBia +// Retun Value : Hall Top & Bottom Gaps +// Argment Value : Hall Top & Bottom Gaps , X,Y Direction +// Explanation : Hall Bias Tuning Function +// History : First edition +//******************************************************************************** +void TneBia( UnDwdVal StTneVal, UINT8 UcTneAxs, UINT16 UsHalAdjRange, UINT8 UcSrvSwitch ) +{ + UINT32 UlSetBia, UlOldBias ; + float SfAmp ; + +TRACE("TneBia\n " ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlSetBia ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlSetBia ) ; + } + +TRACE(" UlSetBia = %08x\n ", (unsigned int)UlSetBia ) ; + if( UlSetBia == 0x00000000 ) UlSetBia = 0x01000000 ; + UlSetBia = (( UlSetBia >> 16 ) & (UINT32)0x0000FF00 ) ; + UlOldBias = UlSetBia ; + UlSetBia *= (UINT32)UsHalAdjRange ; + if(( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal ) == 0xFFFF ){ + UlSetBia = BIAS_HLMT ; + }else{ + UlSetBia /= (UINT32)( 0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal ) ) ; +#if ( (SELECT_VENDOR&0x02) == 0x02 ) //JAHWA +// if( (UlSetBia > UlOldBias ) && ( UcSrvSwitch != OFF) ){ + if( 0 ){ +#else + if( UcSrvSwitch != OFF ) { +#endif + SfAmp = ( ( float )UlSetBia / ( float )UlOldBias - 1.0f ) ; + SfAmp = ( SfAmp / 2.0f ) + 1.0f ; + UlSetBia = ( UINT32 )( ( float )UlOldBias * SfAmp ) ; + } + if( UlSetBia > (UINT32)0x0000FFFF ) UlSetBia = 0x0000FFFF ; + UlSetBia = ( UlSetBia << 16 ) ; + if( UlSetBia > BIAS_HLMT ) UlSetBia = BIAS_HLMT ; + if( UlSetBia < BIAS_LLMT ) UlSetBia = BIAS_LLMT ; + } + + if( UcTneAxs == X_DIR ) { + DacControl( HLXBO , UlSetBia ) ; +TRACE(" HLXBO = %08x\n ", (unsigned int)UlSetBia ) ; + RamWrite32A( StCaliData_UiHallBias_X , UlSetBia) ; + } else if( UcTneAxs == Y_DIR ){ + DacControl( HLYBO , UlSetBia ) ; +TRACE(" HLYBO = %08x\n ", (unsigned int)UlSetBia ) ; + RamWrite32A( StCaliData_UiHallBias_Y , UlSetBia) ; + } +TRACE(" ( AXIS = %02x , BIAS = %08xh ) , \n", UcTneAxs , (unsigned int)UlSetBia ) ; +} + + +//******************************************************************************** +// Function Name : TneOff +// Retun Value : Hall Top & Bottom Gaps +// Argment Value : Hall Top & Bottom Gaps , X,Y Direction +// Explanation : Hall Offset Tuning Function +// History : First edition +//******************************************************************************** +void TneOff( UnDwdVal StTneVal, UINT8 UcTneAxs ) +{ + UINT32 UlSetOff ; + UINT32 UlSetVal ; + +TRACE("TneOff\n ") ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallOffset_X , &UlSetOff ) ; + } else if( UcTneAxs == Y_DIR ){ + RamRead32A( StCaliData_UiHallOffset_Y , &UlSetOff ) ; + } + UlSetOff = ( UlSetOff >> 16 ) ; + + if ( StTneVal.StDwdVal.UsHigVal > StTneVal.StDwdVal.UsLowVal ) { + UlSetVal = ( UINT32 )(( StTneVal.StDwdVal.UsHigVal - StTneVal.StDwdVal.UsLowVal ) / OFFSET_DIV ) ; // Calculating Value For Increase Step + UlSetOff += UlSetVal ; // Calculating Value For Increase Step + if( UlSetOff > 0x0000FFFF ) UlSetOff = 0x0000FFFF ; + } else { + UlSetVal = ( UINT32 )(( StTneVal.StDwdVal.UsLowVal - StTneVal.StDwdVal.UsHigVal ) / OFFSET_DIV ) ; // Calculating Value For Decrease Step + if( UlSetOff < UlSetVal ){ + UlSetOff = 0x00000000 ; + }else{ + UlSetOff -= UlSetVal ; // Calculating Value For Decrease Step + } + } + +TRACE(" UlSetOff = %08x\n ", (unsigned int)UlSetOff ) ; + if( UlSetOff > ( INT32 )0x0000EFFF ) { + UlSetOff = 0x0000EFFF ; + } else if( UlSetOff < ( INT32 )0x00001000 ) { + UlSetOff = 0x00001000 ; + } + + UlSetOff = ( UlSetOff << 16 ) ; + + if( UcTneAxs == X_DIR ) { + DacControl( HLXO, UlSetOff ) ; +TRACE(" HLXO = %08x\n ", (unsigned int)UlSetOff ) ; + RamWrite32A( StCaliData_UiHallOffset_X , UlSetOff ) ; + } else if( UcTneAxs == Y_DIR ){ + DacControl( HLYO, UlSetOff ) ; +TRACE(" HLYO = %08x\n ", (unsigned int)UlSetOff ) ; + RamWrite32A( StCaliData_UiHallOffset_Y , UlSetOff ) ; + } +TRACE(" ( AXIS = %02x , OFST = %08xh ) , \n", UcTneAxs , (unsigned int)UlSetOff ) ; + +} + + +//******************************************************************************** +// Function Name : LopGan +// Retun Value : Execute Result +// Argment Value : X,Y Direction +// Explanation : Loop Gain Adjust Function +// History : First edition +//******************************************************************************** +UINT32 LopGan( UINT8 UcDirSel, ADJ_LOPGAN* ptr ) +{ +#if 1 + UINT32 UlReturnState ; + + if( UcDirSel == X_DIR ) { // X axis + RamWrite32A( HallFilterCoeffX_hxgain0 , ptr->Hxgain ) ; + StAdjPar124.StLopGan.UlLxgVal = ptr->Hxgain ; + UlReturnState = EXE_END ; + } else if( UcDirSel == Y_DIR ){ // Y axis + RamWrite32A( HallFilterCoeffY_hygain0 , ptr->Hygain ) ; + StAdjPar124.StLopGan.UlLygVal = ptr->Hygain ; + UlReturnState = EXE_END ; + } + + return( UlReturnState ) ; +#else + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + UINT64 UllCalculateVal ; + UINT32 UlReturnState ; + UINT16 UsSinAdr ; + + if( UcDirSel == X_DIR ) { // X axis +TRACE("LopGain X_DIR \n") ; + SlMeasureParameterA = HALL_RAM_HXOUT1 ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HXLOP ; // Set Measure RAM Address + UsSinAdr = HALL_RAM_SINDX0; + } else if( UcDirSel == Y_DIR ){ // Y axis +TRACE("LopGain Y_DIR \n") ; + SlMeasureParameterA = HALL_RAM_HYOUT1 ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HYLOP ; // Set Measure RAM Address + UsSinAdr = HALL_RAM_SINDY0; + } + + SetSinWavGenInt124(); + RamWrite32A( SinWave_Offset , ptr->NoiseFreq ) ; // Freq Setting + RamWrite32A( SinWave_Gain , ptr->NoiseGain ) ; // Set Sine Wave Gain + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + +TRACE("LopGain NoiseFreq = %08xh \n", (unsigned int)ptr->NoiseFreq ) ; +TRACE("LopGain NoiseGain = %08xh \n", (unsigned int)ptr->NoiseGain ) ; + + SetTransDataAdr124( SinWave_OutAddr , ( UINT32 )UsSinAdr ) ; // Set Sine Wave Input RAM + + MesFil124( 1/*LOOPGAIN*/ ) ; // Filter setting for measurement + MeasureStart124( ptr->NoiseNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + MeasureWait124() ; // Wait complete of measurement + + SetSinWavGenInt124(); // Sine wave stop + + SetTransDataAdr124( SinWave_OutAddr , (UINT32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( UsSinAdr , 0x00000000 ) ; // DelayRam Clear + + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + +TRACE("LopGain StMeasValueA.UllnValue = %08xh \n", (unsigned int)StMeasValueA.StUllnVal.UlHigVal ) ; +TRACE("LopGain StMeasValueB.UllnValue = %08xh \n", (unsigned int)StMeasValueB.StUllnVal.UlHigVal ) ; + + if( UcDirSel == X_DIR ) { // X axis + UllCalculateVal = ( StMeasValueB.UllnValue * 1000 / StMeasValueA.UllnValue ) * ptr->Hxgain / ptr->Gap ; + if( UllCalculateVal > (UINT64)0x000000007FFFFFFF ) UllCalculateVal = (UINT64)0x000000007FFFFFFF ; + StAdjPar124.StLopGan.UlLxgVal = (UINT32)UllCalculateVal ; + RamWrite32A( HallFilterCoeffX_hxgain0 , StAdjPar124.StLopGan.UlLxgVal ) ; +TRACE("LopGain UlLxgVal = %08xh \n", (unsigned int)StAdjPar124.StLopGan.UlLxgVal ) ; + if( (UllCalculateVal > ptr->XJudgeHigh) || ( UllCalculateVal < ptr->XJudgeLow ) ){ + UlReturnState = EXE_LXADJ ; + }else{ + UlReturnState = EXE_END ; + } + + }else if( UcDirSel == Y_DIR ){ // Y axis + UllCalculateVal = ( StMeasValueB.UllnValue * 1000 / StMeasValueA.UllnValue ) * ptr->Hygain / ptr->Gap ; + if( UllCalculateVal > (UINT64)0x000000007FFFFFFF ) UllCalculateVal = (UINT64)0x000000007FFFFFFF ; + StAdjPar124.StLopGan.UlLygVal = (UINT32)UllCalculateVal ; + RamWrite32A( HallFilterCoeffY_hygain0 , StAdjPar124.StLopGan.UlLygVal ) ; +TRACE("LopGain UlLygVal = %08xh \n", (unsigned int)StAdjPar124.StLopGan.UlLygVal ) ; + if( (UllCalculateVal > ptr->YJudgeHigh) || ( UllCalculateVal < ptr->YJudgeLow ) ){ + UlReturnState = EXE_LYADJ ; + }else{ + UlReturnState = EXE_END ; + } + } + +TRACE("LopGain UlReturnState = %08xh \n", (unsigned int)UlReturnState ) ; + return( UlReturnState ) ; +#endif +} +#endif //((SELECT_VENDOR & 0x80 ) != 0x80) + +//******************************************************************************** +// Function Name : SetSinWavePara +// Retun Value : NON +// Argment Value : NON +// Explanation : Sine wave Test Function +// History : First edition +//******************************************************************************** +/* Servo Sampling Clock = 18.0288kHz */ +/* Freq = SinFreq*80000000h/Fs */ +/* 05 00 XX MM XX:Freq MM:Sin or Circle */ +const UINT32 CucFreqVal[ 17 ] = { + 0xFFFFFFFF, // 0: Stop + 0x0001D14A, // 1: 1Hz + 0x0003A294, // 2: 2Hz + 0x000573DE, // 3: 3Hz + 0x00074528, // 4: 4Hz + 0x00091672, // 5: 5Hz + 0x000AE7BC, // 6: 6Hz + 0x000CB906, // 7: 7Hz + 0x000E8A50, // 8: 8Hz + 0x00105B9A, // 9: 9Hz + 0x00122CE4, // A: 10Hz + 0x0013FE2E, // B: 11Hz + 0x0015CF78, // C: 12Hz + 0x0017A0C2, // D: 13Hz + 0x0019720C, // E: 14Hz + 0x001B4356, // F: 15Hz + 0x001D14A0 // 10: 16Hz + } ; + +void SetSinWavePara( UINT8 UcTableVal , UINT8 UcMethodVal ) +{ + UINT32 UlFreqDat ; + + if(UcTableVal > 0x10 ) UcTableVal = 0x10 ; /* Limit */ + UlFreqDat = CucFreqVal[ UcTableVal ] ; + + if( UcMethodVal == 255/*CIRCWAVE*/) { + RamWrite32A( SinWave_Phase , 0x60000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( CosWave_Phase , 0x00000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + }else{ + RamWrite32A( SinWave_Phase , 0x60000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( CosWave_Phase , 0x60000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + } + + if( UlFreqDat == 0xFFFFFFFF ) /* Sine”g’†Ž~ */ + { + RamWrite32A( SinWave_Offset , 0x00000000 ) ; // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( SinWave_Phase , 0x60000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + + RamWrite32A( CosWave_Offset , 0x00000000 ); // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( CosWave_Phase , 0x60000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + SetTransDataAdr124( SinWave_OutAddr , 0x00000000 ) ; // o—ÍæƒAƒhƒŒƒX + SetTransDataAdr124( CosWave_OutAddr , 0x00000000 ); // o—ÍæƒAƒhƒŒƒX + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; // DelayRam Clear + }else{ + RamWrite32A( SinWave_Offset , UlFreqDat ) ; // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( CosWave_Offset , UlFreqDat ); // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_HXOFF1 ) ; // o—ÍæƒAƒhƒŒƒX + SetTransDataAdr124( CosWave_OutAddr , (UINT32)HALL_RAM_HYOFF1 ) ; // o—ÍæƒAƒhƒŒƒX + + } +} + +//******************************************************************************** +// Function Name : TneHvc +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Hall VC offset +// History : First edition +//******************************************************************************** +#define ADOFF_ROUGH_NUM 64 +void TneHvc( void ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureAveValueA , SlMeasureAveValueB ; + + RamWrite32A( HALL_RAM_HXOFF, 0x00000000 ) ; // X Offset Clr + RamWrite32A( HALL_RAM_HYOFF, 0x00000000 ) ; // Y Offset Clr + + RtnCen124( BOTH_OFF ) ; // Both OFF + WitTim( 500 ) ; + + MesFil124( THROUGH ) ; // Set Measure Filter + MeasureStart124( ADOFF_ROUGH_NUM , HALL_RAM_HXIDAT , HALL_RAM_HYIDAT ) ; // Start measure + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT32)((( (INT64)StMeasValueA.UllnValue * 100 ) / ADOFF_ROUGH_NUM ) / 100 ) ; + SlMeasureAveValueB = (INT32)((( (INT64)StMeasValueB.UllnValue * 100 ) / ADOFF_ROUGH_NUM ) / 100 ) ; + + StAdjPar124.StHalAdj.UsHlxCna = ( UINT16 )(( SlMeasureAveValueA >> 16 ) & 0x0000FFFF ); //Measure Result Store + StAdjPar124.StHalAdj.UsHlxCen = StAdjPar124.StHalAdj.UsHlxCna; //Measure Result Store + + StAdjPar124.StHalAdj.UsHlyCna = ( UINT16 )(( SlMeasureAveValueB >> 16 ) & 0x0000FFFF ); //Measure Result Store + StAdjPar124.StHalAdj.UsHlyCen = StAdjPar124.StHalAdj.UsHlyCna; //Measure Result Store + + StAdjPar124.StHalAdj.UsAdxOff = StAdjPar124.StHalAdj.UsHlxCna ; + StAdjPar124.StHalAdj.UsAdyOff = StAdjPar124.StHalAdj.UsHlyCna ; +TRACE(" Xadof = %04xh \n", StAdjPar124.StHalAdj.UsAdxOff ) ; +TRACE(" Yadof = %04xh \n", StAdjPar124.StHalAdj.UsAdyOff ) ; + + RamWrite32A( HALL_RAM_HXOFF, (UINT32)((StAdjPar124.StHalAdj.UsAdxOff << 16 ) & 0xFFFF0000 )) ; + RamWrite32A( HALL_RAM_HYOFF, (UINT32)((StAdjPar124.StHalAdj.UsAdyOff << 16 ) & 0xFFFF0000 )) ; + +} + +//******************************************************************************** +// Function Name : TneFin +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Hall VC offset current optimize +// History : First edition +//******************************************************************************** +#define ADOFF_FINE_NUM 2000 +void TneFin( ADJ_LOPGAN* ptr ) +{ + UINT32 UlReadVal ; + UINT16 UsAdxOff, UsAdyOff ; + INT32 SlMeasureAveValueA , SlMeasureAveValueB ; + UnllnVal StMeasValueA , StMeasValueB ; + UINT32 UlMinimumValueA, UlMinimumValueB ; + UINT16 UsAdxMin, UsAdyMin ; + UINT8 UcFin ; + + // Loop gain set for servo + RamWrite32A( HallFilterCoeffX_hxgain0 , ptr->Hxgain ) ; + RamWrite32A( HallFilterCoeffY_hygain0 , ptr->Hygain ) ; + + // Get natural center offset + RamRead32A( HALL_RAM_HXOFF, &UlReadVal ) ; + UsAdxOff = UsAdxMin = (UINT16)( UlReadVal >> 16 ) ; + + RamRead32A( HALL_RAM_HYOFF, &UlReadVal ) ; + UsAdyOff = UsAdyMin = (UINT16)( UlReadVal >> 16 ) ; +//TRACE("*****************************************************\n" ); +//TRACE("TneFin: Before Adx=%04X, Ady=%04X\n", UsAdxOff, UsAdyOff ); + + // Servo ON + RtnCen124( BOTH_ON ) ; + WitTim( TNE ) ; + + MesFil124( THROUGH ) ; // Filter setting for measurement + MeasureStart124( ADOFF_FINE_NUM , HALL_RAM_HALL_X_OUT , HALL_RAM_HALL_Y_OUT ) ; // Start measure + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + SlMeasureAveValueA = (INT32)((( (INT64)StMeasValueA.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; + + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + SlMeasureAveValueB = (INT32)((( (INT64)StMeasValueB.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; + + UlMinimumValueA = abs(SlMeasureAveValueA) ; + UlMinimumValueB = abs(SlMeasureAveValueB) ; + UcFin = 0x11 ; + + while( UcFin ) { + if( UcFin & 0x01 ) { + if( UlMinimumValueA >= abs(SlMeasureAveValueA) ) { + UlMinimumValueA = abs(SlMeasureAveValueA) ; + UsAdxMin = UsAdxOff ; + // Žû‘©‚ð‘‚߂邽‚ß‚ÉAo—Í’l‚É”ä—Ⴓ‚¹‚é + if( SlMeasureAveValueA > 0 ) + UsAdxOff = (INT16)UsAdxOff + (SlMeasureAveValueA >> 17) + 1 ; + else + UsAdxOff = (INT16)UsAdxOff + (SlMeasureAveValueA >> 17) - 1 ; + + RamWrite32A( HALL_RAM_HXOFF, (UINT32)((UsAdxOff << 16 ) & 0xFFFF0000 )) ; + } else { +//TRACE("X fine\n"); + UcFin &= 0xFE ; + } + } + + if( UcFin & 0x10 ) { + if( UlMinimumValueB >= abs(SlMeasureAveValueB) ) { + UlMinimumValueB = abs(SlMeasureAveValueB) ; + UsAdyMin = UsAdyOff ; + // Žû‘©‚ð‘‚߂邽‚ß‚ÉAo—Í’l‚É”ä—Ⴓ‚¹‚é + if( SlMeasureAveValueB > 0 ) + UsAdyOff = (INT16)UsAdyOff + (SlMeasureAveValueB >> 17) + 1 ; + else + UsAdyOff = (INT16)UsAdyOff + (SlMeasureAveValueB >> 17) - 1 ; + + RamWrite32A( HALL_RAM_HYOFF, (UINT32)((UsAdyOff << 16 ) & 0xFFFF0000 )) ; + } else { +//TRACE("Y fine\n"); + UcFin &= 0xEF ; + } + } + + MeasureStart124( ADOFF_FINE_NUM , HALL_RAM_HALL_X_OUT , HALL_RAM_HALL_Y_OUT ) ; // Start measure + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + SlMeasureAveValueA = (INT32)((( (INT64)StMeasValueA.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; + + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + SlMeasureAveValueB = (INT32)((( (INT64)StMeasValueB.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; +//TRACE("-->Adx %04X, Ady %04X\n", UsAdxOff, UsAdyOff ); + } // while +//TRACE("TneFin: After Adx=%04X, Ady=%04X\n", UsAdxMin, UsAdyMin ); + StAdjPar124.StHalAdj.UsHlxCna = UsAdxMin; //Measure Result Store + StAdjPar124.StHalAdj.UsHlxCen = StAdjPar124.StHalAdj.UsHlxCna; //Measure Result Store + + StAdjPar124.StHalAdj.UsHlyCna = UsAdyMin; //Measure Result Store + StAdjPar124.StHalAdj.UsHlyCen = StAdjPar124.StHalAdj.UsHlyCna; //Measure Result Store + + StAdjPar124.StHalAdj.UsAdxOff = StAdjPar124.StHalAdj.UsHlxCna ; + StAdjPar124.StHalAdj.UsAdyOff = StAdjPar124.StHalAdj.UsHlyCna ; + + // Servo OFF + RtnCen124( BOTH_OFF ) ; // Both OFF + + +TRACE(" XadofFin = %04xh \n", StAdjPar124.StHalAdj.UsAdxOff ) ; +TRACE(" YadofFin = %04xh \n", StAdjPar124.StHalAdj.UsAdyOff ) ; + RamWrite32A( HALL_RAM_HXOFF, (UINT32)((StAdjPar124.StHalAdj.UsAdxOff << 16 ) & 0xFFFF0000 )) ; + RamWrite32A( HALL_RAM_HYOFF, (UINT32)((StAdjPar124.StHalAdj.UsAdyOff << 16 ) & 0xFFFF0000 )) ; + +} + +/***************************************/ +#define SLT_OFFSET (0x1000) +#define LENS_MARGIN (0x0800) +#define PIXEL_SIZE (1.12f) // pixel size 1.12um +#define SPEC_RANGE (120.0f) // spec need movable range 130um +#define SPEC_PIXEL (PIXEL_SIZE / SPEC_RANGE) // spec need movable range pixel +/***************************************/ +//******************************************************************************** +// Function Name : IniNvc +// Retun Value : NON +// Argment Value : direction +// Explanation : Set each direction sign function +//******************************************************************************** +void IniNvc( INT16 SsX, INT16 SsY ) +{ + SsNvcX = SsX ; + SsNvcY = SsY ; +} + +//******************************************************************************** +// Function Name : TneSltPos +// Retun Value : NON +// Argment Value : Position number(1, 2, 3, 4, 5, 6, 7, 0:reset) +// Explanation : Move measurement position function +//******************************************************************************** +void TneSltPos( UINT8 UcPos ) +{ + INT16 SsOff = 0x0000 ; + + UcPos &= 0x07 ; + + if ( UcPos ) { + SsOff = SLT_OFFSET * (UcPos - 4); + } + +//TRACE("X = %04X, Y = %04X \n", SsOff, SsOff ); + + RamWrite32A( HALL_RAM_HXOFF1, (INT32)((SsOff * SsNvcX) << 16) ) ; + RamWrite32A( HALL_RAM_HYOFF1, (INT32)((SsOff * SsNvcY) << 16) ) ; + +} + +//******************************************************************************** +// Function Name : TneVrtPos +// Retun Value : NON +// Argment Value : Position number(1, 2, 3, 4, 5, 6, 7, 0:reset) +// Explanation : Move measurement position function +//******************************************************************************** +void TneVrtPos( UINT8 UcPos ) +{ + INT16 SsOff = 0x0000 ; + + UcPos &= 0x07 ; + + if ( UcPos ) { + SsOff = SLT_OFFSET * (UcPos - 4); + } + +//TRACE("X = %04X, Y = %04X \n", SsOff, SsOff ); + + RamWrite32A( HALL_RAM_HXOFF1, (INT32)0 ) ; + RamWrite32A( HALL_RAM_HYOFF1, (INT32)((SsOff * SsNvcY) << 16) ) ; +} + +//******************************************************************************** +// Function Name : TneHrzPos +// Retun Value : NON +// Argment Value : Position number(1, 2, 3, 4, 5, 6, 7, 0:reset) +// Explanation : Move measurement position function +//******************************************************************************** +void TneHrzPos( UINT8 UcPos ) +{ + INT16 SsOff = 0x0000 ; + + UcPos &= 0x07 ; + + if ( UcPos ) { + SsOff = SLT_OFFSET * (UcPos - 4); + } + +//TRACE("X = %04X, Y = %04X \n", SsOff, SsOff ); + + RamWrite32A( HALL_RAM_HXOFF1, (INT32)((SsOff * SsNvcX) << 16) ) ; + RamWrite32A( HALL_RAM_HYOFF1, (INT32)0 ) ; +} + + + + +//******************************************************************************** +// Function Name : TneADO +// Retun Value : 0x0000:PASS, 0x0001:X MAX OVER, 0x0002:Y MAX OVER, 0x0003:X MIN OVER, 0x0004:Y MIN OVER, FFFF:Verify error +// : 0x0100:X MAX RANGE ERROR, 0x0200:Y MAX RANGE ERROR, 0x0300:X MIN RANGE ERROR, 0x0400:Y MIN ERROR +// Argment Value : +// Explanation : calculation margin Function +// History : First edition +//******************************************************************************** +UINT16 TneADO( ) +{ + UINT16 UsSts = 0 ; +#if 0 + INT32 iRetVal; + INT32 limit ; + INT32 gxgain ; + INT32 gygain ; + INT16 gout_x_marginp ; + INT16 gout_x_marginm ; + INT16 gout_y_marginp ; + INT16 gout_y_marginm ; + + INT16 x_max ; + INT16 x_min ; + INT16 x_off ; + INT16 y_max ; + INT16 y_min ; + INT16 y_off ; + INT16 x_max_after ; + INT16 x_min_after ; + INT16 y_max_after ; + INT16 y_min_after ; + INT16 gout_x ; + INT16 gout_y ; + + // + // Flash update procedure + // + // Read calibration sector to buffer + iRetVal = Calibration_VerifyUpdate_PreRead(); + if(iRetVal != 0) return(iRetVal); + + // Read calibration data + RdHallCalData(); + + x_max = (INT16)StAdjPar124.StHalAdj.UsHlxMxa ; + x_min = (INT16)StAdjPar124.StHalAdj.UsHlxMna ; + x_off = (INT16)StAdjPar124.StHalAdj.UsAdxOff ; + y_max = (INT16)StAdjPar124.StHalAdj.UsHlyMxa ; + y_min = (INT16)StAdjPar124.StHalAdj.UsHlyMna ; + y_off = (INT16)StAdjPar124.StHalAdj.UsAdyOff ; + + RamRead32A( GF_LimitX_HLIMT, &limit ) ; + RamRead32A( StCaliData_SiGyroGain_X, &gxgain ) ; + RamRead32A( StCaliData_SiGyroGain_Y, &gygain ) ; + + x_max_after = (x_max - x_off) ; + if (x_off < 0) + { + if ((0x7FFF - abs(x_max)) < abs(x_off)) x_max_after = 0x7FFF ; + } + + x_min_after = (x_min - x_off) ; + if (x_off > 0) + { + if ((0x7FFF - abs(x_min)) < abs(x_off)) x_min_after = 0x8001 ; + } + + y_max_after = (y_max - y_off) ; + if (y_off < 0) + { + if ((0x7FFF - abs(y_max)) < abs(y_off)) y_max_after = 0x7FFF ; + } + + y_min_after = (y_min - y_off); + if (y_off > 0) + { + if ((0x7FFF - abs(y_min)) < abs(y_off)) y_min_after = 0x8001 ; + } + + gout_x = (INT16)((INT32)(((float)gxgain / 0x7FFFFFFF) * limit * 4) >> 16); + gout_y = (INT16)((INT32)(((float)gygain / 0x7FFFFFFF) * limit * 4) >> 16); + +//TRACE( "ADOFF X\t=\t0x%04X\r\n", x_off ) ; +//TRACE( "ADOFF Y\t=\t0x%04X\r\n", y_off ) ; +//TRACE( "MAX GOUT X\t=\t0x%04X\r\n", gout_x ) ; +//TRACE( "MIN GOUT X\t=\t0x%04X\r\n", (gout_x * -1) ) ; +//TRACE( "MAX GOUT Y\t=\t0x%04X\r\n", gout_y) ; +//TRACE( "MIN GOUT Y\t=\t0x%04X\r\n", (gout_y * -1) ) ; + + gout_x_marginp = (INT16)(gout_x + LENS_MARGIN); // MARGIN X+ + gout_x_marginm = (INT16)((gout_x + LENS_MARGIN) * -1); // MARGIN X- + gout_y_marginp = (INT16)(gout_y + LENS_MARGIN); // MARGIN Y+ + gout_y_marginm = (INT16)((gout_y + LENS_MARGIN) * -1); // MARGIN Y- + +//TRACE( "MAX GOUT with margin X\t=\t0x%04X\r\n", gout_x_marginp ) ; +//TRACE( "MIN GOUT with margin X\t=\t0x%04X\r\n", gout_x_marginm ) ; +//TRACE( "MAX GOUT with margin Y\t=\t0x%04X\r\n", gout_y_marginp ) ; +//TRACE( "MIN GOUT with margin Y\t=\t0x%04X\r\n", gout_y_marginm ) ; + +//TRACE( "MAX AFTER X\t=\t0x%04X\r\n", x_max_after ) ; +//TRACE( "MIN AFTER X\t=\t0x%04X\r\n", x_min_after ) ; +//TRACE( "MAX AFTER Y\t=\t0x%04X\r\n", y_max_after ) ; +//TRACE( "MIN AFTER Y\t=\t0x%04X\r\n", y_min_after ) ; + + // ƒ}[ƒWƒ“‚ª‚Ü‚Á‚½‚­‚È‚¢‚à‚͕̂s—ǂƂ·‚é + if (x_max_after < gout_x) { + UsSts = 1 ; + } + else if (y_max_after < gout_y) { + UsSts = 2 ; + } + else if (x_min_after > (gout_x * -1)) { + UsSts = 3 ; + } + else if (y_min_after > (gout_y * -1)) { + UsSts = 4 ; + } + else { + // ƒ}[ƒWƒ“ƒI[ƒo[‚Å‚ ‚ê‚ÎAADOFFSET‚ðXV‚·‚é + if (x_max_after < gout_x_marginp) { + x_off -= (gout_x_marginp - x_max_after); +//TRACE( "UPDATE ADOFF X\t=\t0x%04X\r\n", x_off ) ; + } + if (x_min_after > gout_x_marginm) { + x_off += abs(x_min_after - gout_x_marginm); +//TRACE( "UPDATE ADOFF X\t=\t0x%04X\r\n", x_off ) ; + } + if (y_max_after < gout_y_marginp) { + y_off -= (gout_y_marginp - y_max_after); +//TRACE( "UPDATE ADOFF Y\t=\t0x%04X\r\n", y_off ) ; + } + if (y_min_after > gout_y_marginm) { + y_off += abs(y_min_after - gout_y_marginm); +//TRACE( "UPDATE ADOFF X\t=\t0x%04X\r\n", y_off ) ; + } + + if ( (StAdjPar124.StHalAdj.UsAdxOff != (UINT16)x_off) || (StAdjPar124.StHalAdj.UsAdyOff != (UINT16)y_off) ) { + StAdjPar124.StHalAdj.UsAdxOff = x_off ; + StAdjPar124.StHalAdj.UsAdyOff = y_off ; + + RamWrite32A( StCaliData_SiLensCen_Offset_X , (UINT32)(StAdjPar124.StHalAdj.UsAdxOff << 16) ) ; + RamWrite32A( StCaliData_SiLensCen_Offset_Y , (UINT32)(StAdjPar124.StHalAdj.UsAdyOff << 16) ) ; + + _PUT_UINT32( (UINT32)(StAdjPar124.StHalAdj.UsAdxOff << 16), LENS_CENTER_VALUE_X ) ; + _PUT_UINT32( (UINT32)(StAdjPar124.StHalAdj.UsAdyOff << 16), LENS_CENTER_VALUE_Y ) ; + iRetVal = Calibration_VerifyUpdate(); + } + } + + // ******************************* + // effective range check + // ******************************* + if (UsSts == 0) { + UINT16 UsReadVal ; + float flDistanceX, flDistanceY ; + float flDistanceAD = SLT_OFFSET * 6 ; + + // effective range check + _GET_UINT16( UsReadVal, DISTANCE_X ) ; + flDistanceX = (float)UsReadVal / 10.0f ; +//TRACE("DISTANCE (X, Y) pixel = (%04X", UsReadVal ); + + _GET_UINT16( UsReadVal, DISTANCE_Y ) ; + flDistanceY = (float)UsReadVal / 10.0f ; +//TRACE(", %04X)\r\n", UsReadVal ); + +//TRACE("DISTANCE (X, Y) pixel = (%x, %x)\r\n", (int)(flDistanceX * 10.0), (int)(flDistanceY * 10.0) ); +//TRACE("X MAX um = %d\r\n", (int)((x_max_after * (flDistanceX / flDistanceAD)) * PIXEL_SIZE) ) ; +//TRACE("Y MAX um = %d\r\n", (int)((y_max_after * (flDistanceY / flDistanceAD)) * PIXEL_SIZE) ) ; +//TRACE("X MIN um = %d\r\n", (int)((abs(x_min_after) * (flDistanceX / flDistanceAD)) * PIXEL_SIZE) ) ; +//TRACE("Y MIN um = %d\r\n", (int)((abs(y_min_after) * (flDistanceY / flDistanceAD)) * PIXEL_SIZE) ) ; +//TRACE("SPEC PIXEL = %d\r\n", (int)SPEC_PIXEL ) ; + + if ( (x_max_after * (flDistanceX / flDistanceAD)) < SPEC_PIXEL ) { +//TRACE("X MAX < 85um\r\n"); + // error + UsSts |= 0x0100 ; + } + else if ( (y_max_after * (flDistanceY / flDistanceAD)) < SPEC_PIXEL ) { +//TRACE("Y MAX < 85um\r\n"); + // error + UsSts |= 0x0200 ; + } + else if ( (abs(x_min_after) * (flDistanceX / flDistanceAD)) < SPEC_PIXEL ) { +//TRACE("X MIN < 85um\r\n"); + // error + UsSts |= 0x0300 ; + } + else if ( (abs(y_min_after) * (flDistanceY / flDistanceAD)) < SPEC_PIXEL ) { +//TRACE("Y MAX < 85um\r\n"); + // error + UsSts |= 0x0400 ; + } + } +#endif + return( UsSts ) ; + +} + +#if 0 +//******************************************************************************** +// Function Name : FrqDet +// Retun Value : 0:PASS, 1:OIS X NG, 2:OIS Y NG, 4:CLAF NG +// Argment Value : NON +// Explanation : Module Check +// History : First edition +//******************************************************************************** +// Threshold of osciration amplitude +#define ULTHDVAL 0x01000000 // Threshold of the hale value +UINT8 FrqDet( void ) +{ + INT32 SlMeasureParameterA , SlMeasureParameterB ; + INT32 SlMeasureParameterNum ; + UINT32 UlXasP_P , UlYasP_P ; + UINT8 UcRtnVal; + + UcRtnVal = 0; + + //Measurement Setup + MesFil124( OSCCHK ) ; // Set Measure Filter + + SlMeasureParameterNum = 1000 ; // 1000times( 50ms ) + SlMeasureParameterA = (UINT32)HALL_RAM_HXOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = (UINT32)HALL_RAM_HYOUT0 ; // Set Measure RAM Address + + // impulse Set +// RamWrite32A( HALL_RAM_HXOFF1 , STEP1 ) ; // X manual +// RamWrite32A( HALL_RAM_HYOFF1 , STEP1 ) ; // Y manual + +// RamWrite32A( HALL_RAM_HXOFF1 , STEP2 ) ; // X manual +// RamWrite32A( HALL_RAM_HYOFF1 , STEP2 ) ; // Y manual + WitTim( 300 ) ; + + // Start measure + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; + MeasureWait124() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_UiAmp1, &UlXasP_P ) ; // X Axis Peak to Peak + RamRead32A( StMeasFunc_MFB_UiAmp2, &UlYasP_P ) ; // Y Axis Peak to Peak +//TRACE("UlXasP_P = %X\r\n", (unsigned int)UlXasP_P ) ; +//TRACE("UlYasP_P = %X\r\n", (unsigned int)UlYasP_P ) ; + + WitTim( 50 ) ; + + // Osc Value Check X + if( UlXasP_P > ULTHDVAL ){ + UcRtnVal = 1; + } + // Osc Value Check Y + if( UlYasP_P > ULTHDVAL ){ + UcRtnVal |= 2; + } + + + return(UcRtnVal); // Retun Status value +} +#endif + +#ifdef ZERO_SERVO +//******************************************************************************** +// Function Name : TneZeroServo +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes Zero Servo Parameter +// History : First edition +//******************************************************************************** +#define ZERO_SERVO_NUM 4096 // 4096times +UINT32 TneZeroServo( UINT8 ucposture , float DegreeGap ) +{ + UINT32 UlRsltSts; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + INT32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureAveValueA , SlMeasureAveValueB ; + double dTemp; + UINT8 i; + UINT32 UlRdVal; + double OffsetAngle; + + UlRsltSts = EXE_END ; + if( ucposture < 0x80 ){ + RamRead32A( CMD_RETURN_TO_CENTER , &UlRdVal ); + if( UlRdVal != 0x00000000 ){ + RtnCen124( BOTH_OFF ) ; + } + + RamRead32A( CMD_ZSRV_MODE , &UlRdVal ); + if( ( UlRdVal & 0x00000001) == ZSRV_ENABLE ){ + RamWrite32A( CMD_ZSRV_MODE , ZSRV_DISABLE ); + } + + //•½‹Ï’l‘ª’è + MesFil124( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = ZERO_SERVO_NUM ; // Measurement times + + if( ucposture != 0 && ucposture != 2 ){ + UlRsltSts = EXE_ERROR; +TRACE(" Result = %08x\n",(int)UlRsltSts ) ; + return( UlRsltSts ); + } + + for( i=ucposture ; i< (ucposture+2) ; i++ ) + { + switch( i ){ + case 0: /* +Y */ + SlMeasureParameterA = ZeroServoRAM_X_IN ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_RAM_GZ_ADIDAT ; // Set Measure RAM Address + break; + case 1: + SlMeasureParameterA = HALL_RAM_HYOUT2 ; // Set Measure RAM Address + SlMeasureParameterB = ZeroServoRAM_Y_IN ; // Set Measure RAM Address + break; + case 2: /* +X */ + SlMeasureParameterA = ZeroServoRAM_Y_IN ; // Set Measure RAM Address + SlMeasureParameterB = ZeroServoRAM_Z_IN ; // Set Measure RAM Address + break; + case 3: + SlMeasureParameterA = HALL_RAM_HXOUT2 ; // Set Measure RAM Address + SlMeasureParameterB = ZeroServoRAM_X_IN ; // Set Measure RAM Address + break; + } + + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT32)( (INT64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT32)( (INT64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; + + switch( i ){ + case 0: + StZeroServoX.SlOffset = SlMeasureAveValueA ; // i case 0 : ZeroServoRAM_X_IN + GYROZ_OFFSET = SlMeasureAveValueB ; + break; + case 2: + StZeroServoY.SlOffset = SlMeasureAveValueA ; // i case 2 : ZeroServoRAM_Y_IN + StZeroServoZ.SlOffset = SlMeasureAveValueB ; + break; + default : + break; + } + } + +TRACE("VAL(H,A) pos = \t%08xh\t%08xh\t%d \n",(int)SlMeasureAveValueA, (int)SlMeasureAveValueB, ucposture ) ; + + + switch( ucposture ){ + case 0: /* +Y */ + if( SlMeasureAveValueB < (int)(POSTURETH_P<<16) ){ + UlRsltSts = EXE_ERROR ; + StZeroServoX.SlOffset = 0 ; + }else{ + StZeroServoMesY.SlHallP = SlMeasureAveValueA ; // i case 1 : HALL_RAM_HYOUT2 + StZeroServoMesY.SlAcclP = SlMeasureAveValueB ; // i case 1 : ZeroServoRAM_Y_IN + UlPostureSt |= 0x00000001; + } + break; + case 2: /* +X */ + if( SlMeasureAveValueB < (int)(POSTURETH_P<<16) ){ + UlRsltSts = EXE_ERROR ; + StZeroServoY.SlOffset = 0 ; + }else{ + StZeroServoMesX.SlHallP = SlMeasureAveValueA ; // i case 3 : HALL_RAM_HXOUT2 + StZeroServoMesX.SlAcclP = SlMeasureAveValueB ; // i case 3 : ZeroServoRAM_X_IN + UlPostureSt |= 0x00000004; + } + break; + } + }else{ + switch(ucposture){ + case 0x80: /* ŒvŽZ */ + + if( UlPostureSt == 0x05L ){ + // ( Xhp ) / ( Xap) + StZeroServoMesX.SlAcclP -= StZeroServoX.SlOffset; + dTemp = (double)2147483647.0 / (double)( StZeroServoMesX.SlAcclP ); + for( StZeroServoX.SlShift = 0 ; StZeroServoX.SlShift <= 5; StZeroServoX.SlShift++){ + if( fabs(dTemp) <= 1 ){ + break; + } + dTemp = dTemp / (double)2 ; + } + StZeroServoX.SlGcora = (INT32)(dTemp * (double)2147483647.0); + StZeroServoX.SlShift = StZeroServoX.SlShift << 8; + + // ( Yhp ) / ( Yap ) + StZeroServoMesY.SlAcclP -= StZeroServoY.SlOffset; + dTemp = (double)2147483647.0 / (double)( StZeroServoMesY.SlAcclP ); + for( StZeroServoY.SlShift = 0 ; StZeroServoY.SlShift <= 5; StZeroServoY.SlShift++){ + if( fabs(dTemp) <= 1 ){ + break; + } + dTemp = dTemp / 2 ; + } + StZeroServoY.SlGcora = (INT32)(dTemp * (double)2147483647.0); + StZeroServoY.SlShift = StZeroServoY.SlShift << 8; + + OffsetAngle = (double)( DegreeGap ) * 3.141592653589793238 / 180.0f ; + + + + + StZeroServoX.SlGaina = (INT32)( (float)StZeroServoMesX.SlHallP / cos( OffsetAngle ) ) ; + StZeroServoY.SlGaina = (INT32)( (float)StZeroServoMesY.SlHallP / cos( OffsetAngle ) ) ; + +TRACE(" X , Y , angle = %f \n", DegreeGap ) ; +TRACE("%08xh,%08xh(Offset)\n",(int)StZeroServoX.SlOffset, (int)StZeroServoY.SlOffset) ; +TRACE("%08xh,%08xh(Gcora)\n",(int)StZeroServoX.SlGcora, (int)StZeroServoY.SlGcora) ; +TRACE("%08xh,%08xh(Gaina)\n",(int)StZeroServoX.SlGaina, (int)StZeroServoY.SlGaina) ; +TRACE("%08xh,%08xh(Shift)\n",(int)StZeroServoX.SlShift, (int)StZeroServoY.SlShift) ; +TRACE("%08xh,%08xh(AZ , GZ)\n",(int)StZeroServoZ.SlOffset, (int)GYROZ_OFFSET) ; + RamWrite32A( ZeroServoRAM_X_OFFSET , StZeroServoX.SlOffset ); + RamWrite32A( ZeroServoFilterTableX_gcora , StZeroServoX.SlGcora ); + RamWrite32A( ZeroServoFilterTableX_gaina , StZeroServoX.SlGaina ); + RamWrite32A( ZeroServoFilterTableX_shift , StZeroServoX.SlShift ); + + RamWrite32A( ZeroServoRAM_Y_OFFSET , StZeroServoY.SlOffset ); + RamWrite32A( ZeroServoFilterTableY_gcora , StZeroServoY.SlGcora ); + RamWrite32A( ZeroServoFilterTableY_gaina , StZeroServoY.SlGaina ); + RamWrite32A( ZeroServoFilterTableY_shift , StZeroServoY.SlShift ); + + RamWrite32A( ZeroServoRAM_Z_OFFSET , StZeroServoZ.SlOffset ); + RamWrite32A( GYRO_RAM_GZOFFZ , GYROZ_OFFSET ); + + }else{ + UlRsltSts = EXE_ERROR ; + } + break; + case 0xFF: /* RAM clear */ + UlPostureSt = 0L; + break; + } + } + +TRACE(" Result = %08x\n",(int)UlRsltSts ) ; + return( UlRsltSts ); +} + +//******************************************************************************** +// Function Name : ZeroServoLmt +// Retun Value : NON +// Argment Value : NON +// Explanation : Zero Servo Limit Parameter +// History : First edition +//******************************************************************************** +UINT8 ZeroServoLmt( UINT8 UCMODE ) +{ + UINT32 UlRsltSts; +#if (EP3_ES == 2) + double dTemp1; +#else + double dTemp1, dTemp2; + UINT32 UlFilCoef; + UINT16 Usshift , UsShiftx , UsShifty; + UINT32 Ulcoef , Ulgainx , Ulgainy; +#endif + +TRACE(" ZSRV LMT ( %d )%\n" , UCMODE ) ; + UlRsltSts = EXE_END ; + if(( UCMODE > 0x64 ) || ( UCMODE < 0x0A )){ +TRACE(" error \n" ) ; + return( EXE_ERROR ) ; + } + +#if (EP3_ES == 2) + dTemp1 = (double)UCMODE /(double)100.0 * (double)2147483647; + + RamWrite32A( ZS_LMT_limitx , (INT32)dTemp1 ); + RamWrite32A( ZS_LMT_limity , (INT32)dTemp1 ); + +#else // ES1 + RamRead32A( ZeroServoFilterTableX_gcora , &StZeroServoX.SlGcora ); + RamRead32A( ZeroServoFilterTableX_shift , &StZeroServoX.SlShift ); + RamRead32A( ZeroServoFilterTableY_gcora , &StZeroServoY.SlGcora ); + RamRead32A( ZeroServoFilterTableY_shift , &StZeroServoY.SlShift ); + RamRead32A( ZeroServoFilterTableX_coeff1_0 , &UlFilCoef ); + +TRACE(" before X (gain , shift , coeff) = ( %08x , %08x , %08x )\n",(int)StZeroServoX.SlGcora ,(int)StZeroServoX.SlShift ,(int)UlFilCoef ) ; +TRACE(" before Y (gain , shift , coeff) = ( %08x , %08x , %08x )\n",(int)StZeroServoY.SlGcora ,(int)StZeroServoY.SlShift ,(int)UlFilCoef ) ; + dTemp1 = (double)100.0 / (double)UCMODE; + dTemp2 = (double)UCMODE / (double)100.0; + + for( Usshift = 0 ; Usshift <= 4; Usshift++){ + if( fabs(dTemp1) <= 1 ){ + break; + } + dTemp1 = dTemp1 / (double)2 ; + } + + Ulgainx = (INT32)(dTemp1 * (double)StZeroServoX.SlGcora); + Ulgainy = (INT32)(dTemp1 * (double)StZeroServoY.SlGcora); + UsShiftx = (UINT16)StZeroServoX.SlShift + (UINT16)(Usshift<<8); + UsShifty = (UINT16)StZeroServoY.SlShift + (UINT16)(Usshift<<8); + Ulcoef = (INT32)(dTemp2 * (double)UlFilCoef); +TRACE(" after X (gain , shift , coeff) = ( %08x , %08x , %08x )\n",(int)Ulgainx ,(int)UsShiftx ,(int)Ulcoef ) ; +TRACE(" after Y (gain , shift , coeff) = ( %08x , %08x , %08x )\n",(int)Ulgainy ,(int)UsShifty ,(int)Ulcoef ) ; + + RamWrite32A( ZeroServoFilterTableX_gcora , Ulgainx ); + RamWrite32A( ZeroServoFilterTableX_shift , (UINT32)UsShiftx ); + RamWrite32A( ZeroServoFilterTableY_gcora , Ulgainy ); + RamWrite32A( ZeroServoFilterTableY_shift , (UINT32)UsShifty ); + RamWrite32A( ZeroServoFilterTableX_coeff1_0 , Ulcoef ); + RamWrite32A( ZeroServoFilterTableX_coeff1_2 , Ulcoef ); + RamWrite32A( ZeroServoFilterTableY_coeff1_0 , Ulcoef ); + RamWrite32A( ZeroServoFilterTableY_coeff1_2 , Ulcoef ); +#endif + +TRACE(" Result = %08x\n",(int)UlRsltSts ) ; + return( UlRsltSts ); +} +#endif //ZERO_SERVO + +#ifdef SEL_SHIFT_COR +//******************************************************************************** +// Function Name : MemClr +// Retun Value : void +// Argment Value : Clear Target Pointer, Clear Byte Number +// Explanation : Memory Clear Function +// History : First edition +//******************************************************************************** +void MemClr( UINT8 *NcTgtPtr, UINT16 UsClrSiz ) +{ + UINT16 UsClrIdx ; + + for ( UsClrIdx = 0 ; UsClrIdx < UsClrSiz ; UsClrIdx++ ) + { + *NcTgtPtr = 0 ; + NcTgtPtr++ ; + } +} + +//******************************************************************************** +// Function Name : TneAvc +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Accel VC offset for All +// History : First edition +//******************************************************************************** +#define ACCLOF_NUM 4096 // 4096times +UINT32 TneAvc( UINT8 ucposture ) +{ + UINT32 UlRsltSts; + INT32 SlMeasureParameterA , SlMeasureParameterB ; + INT32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT32 SlMeasureAveValueA , SlMeasureAveValueB ; + INT32 SlMeasureRetValueX , SlMeasureRetValueY , SlMeasureRetValueZ; + UINT8 j , k; +// UINT8 i , j , k; +// INT32 mtrx[9] , imtrx[9]; +// float detA; + INT32 SlDiff[3] ; + + UlRsltSts = EXE_END ; + if( ucposture < 0x7f ){ + //•½‹Ï’l‘ª’è + MesFil124( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = ACCLOF_NUM ; // Measurement times + /******* 1st *******/ + SlMeasureParameterA = ZeroServoRAM_X_IN ; // Set Measure RAM Address + SlMeasureParameterB = ZeroServoRAM_Y_IN ; // Set Measure RAM Address + + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT32)( (INT64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT32)( (INT64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; + + SlMeasureRetValueX = SlMeasureAveValueA ; + SlMeasureRetValueY = SlMeasureAveValueB ; + + /******* 2nd *******/ + SlMeasureParameterA = ZeroServoRAM_Z_IN ; // Set Measure RAM Address + SlMeasureParameterB = ZeroServoRAM_Z_IN ; // Set Measure RAM Address + + MeasureStart124( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait124() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT32)( (INT64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT32)( (INT64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; + + SlMeasureRetValueZ = SlMeasureAveValueA ; + + + +TRACE("VAL(X,Y,Z) pos = \t%08xh\t%08xh\t%08xh\t%d \n", (unsigned int)SlMeasureRetValueX, (unsigned int)SlMeasureRetValueY, (unsigned int)SlMeasureRetValueZ, ucposture ) ; + if(( SlMeasureRetValueZ < (INT32)(POSTURETH_P<<16)) && (ucposture == 0x10)){ + UlRsltSts = EXE_ERROR ; +TRACE(" POS14 [ERROR] \t%08xh < %08xh\n", (unsigned int)(SlMeasureRetValueZ), (unsigned int)(POSTURETH_P<<16) ) ; + }else if(( SlMeasureRetValueZ > (INT32)(POSTURETH_M<<16)) && (ucposture == 0x11)){ + UlRsltSts = EXE_ERROR ; +TRACE(" POS14 [ERROR] \t%08xh > %08xh\n", (unsigned int)(SlMeasureRetValueZ), (unsigned int)(POSTURETH_M<<16) ) ; + }else{ +TRACE("DEBUG = \t%08xh\t \n", abs( (INT32)(ACCL_SENS << 16) - abs(SlMeasureRetValueZ) ) ) ; + if( abs(SlMeasureRetValueX) > ZEROG_MRGN_XY ) UlRsltSts |= EXE_GXADJ ; + if( abs(SlMeasureRetValueY) > ZEROG_MRGN_XY ) UlRsltSts |= EXE_GYADJ ; + if( abs( (INT32)(ACCL_SENS << 16) - abs(SlMeasureRetValueZ)) > ZEROG_MRGN_Z ) UlRsltSts |= EXE_GZADJ ; + if( UlRsltSts == EXE_END ){ +// StPosOff124.StPos.Pos[4][0] = SlMeasureRetValueX; +// StPosOff124.StPos.Pos[4][1] = SlMeasureRetValueY; +// StPosOff124.StPos.Pos[4][2] = SlMeasureRetValueZ; + StPosOff124.UlAclOfSt |= 0x0000003F; +TRACE("POS14(X,Y,Z) st = \t%08xh\t%08xh\t%08xh\t%08xh \n", (unsigned int)StPosOff124.StPos.Pos[4][0], (unsigned int)StPosOff124124124.StPos.Pos[4][1], (unsigned int)StPosOff124124124.StPos.Pos[4][2], (unsigned int)StPosOff124124124.UlAclOfSt ) ; + + SlDiff[0] = SlMeasureRetValueX - (INT32)0; + SlDiff[1] = SlMeasureRetValueY - (INT32)0; + if(ucposture == 0x10){ + SlDiff[2] = SlMeasureRetValueZ - (INT32)(ACCL_SENS << 16); + }else{ + SlDiff[2] = SlMeasureRetValueZ - (INT32)(ACCL_SENS_M << 16); + } + StPosOff124.StPos.Pos[4][0] = SlDiff[0]; + StPosOff124.StPos.Pos[4][1] = SlDiff[1]; + StPosOff124.StPos.Pos[4][2] = SlDiff[2]; + } + } + }else{ + switch(ucposture){ + case 0x80: /* ŒvŽZ */ + + if(StPosOff124.UlAclOfSt == 0x3fL ){ + /*X offset*/ + StAclVal124.StAccel.SlOffsetX = StPosOff124.StPos.Pos[4][0] ; + /*Y offset*/ + StAclVal124.StAccel.SlOffsetY = StPosOff124.StPos.Pos[4][1] ; + /*Z offset*/ + StAclVal124.StAccel.SlOffsetZ = StPosOff124.StPos.Pos[4][2] ; +#ifdef DEBUG +TRACE("ACLOFST(X,Y,Z) = \t%08xh\t%08xh\t%08xh \n", (unsigned int)StAclVal124.StAccel.SlOffsetX, (unsigned int)StAclVal124124124.StAccel.SlOffsetY, (unsigned int)StAclVal124124124.StAccel.SlOffsetZ ) ; +#endif //DEBUG + + RamWrite32A( ZeroServoRAM_X_OFFSET , StAclVal124.StAccel.SlOffsetX ) ; // X axis Accel offset + RamWrite32A( ZeroServoRAM_Y_OFFSET , StAclVal124.StAccel.SlOffsetY ) ; // Y axis Accel offset + RamWrite32A( ZeroServoRAM_Z_OFFSET , StAclVal124.StAccel.SlOffsetZ ) ; // Z axis Accel offset + + StAclVal124.StAccel.SlOffsetX = ( StAclVal124.StAccel.SlOffsetX >> 16 ) & 0x0000FFFF; + StAclVal124.StAccel.SlOffsetY = ( StAclVal124.StAccel.SlOffsetY >> 16 ) & 0x0000FFFF; + StAclVal124.StAccel.SlOffsetZ = ( StAclVal124.StAccel.SlOffsetZ >> 16 ) & 0x0000FFFF; + + for( j=0 ; j < 6 ; j++ ){ + k = 4 * j; + RamWrite32A( AcclFilDly_X + k , 0x00000000 ) ; // X axis Accl LPF Clear + RamWrite32A( AcclFilDly_Y + k , 0x00000000 ) ; // Y axis Accl LPF Clear + RamWrite32A( AcclFilDly_Z + k , 0x00000000 ) ; // Z axis Accl LPF Clear + } + + }else{ + UlRsltSts = EXE_ERROR ; + } + break; + case 0xFF: /* RAM clear */ + MemClr( ( UINT8 * )&StPosOff124, sizeof( stPosOff ) ) ; // Adjust Parameter Clear + MemClr( ( UINT8 * )&StAclVal124, sizeof( stAclVal ) ) ; // Adjust Parameter Clear +// StPosOff124.UlAclOfSt = 0L; + break; + } + } + +TRACE(" Result = %08x\n", (unsigned int)UlRsltSts ) ; + return( UlRsltSts ); + + +} +#endif //SEL_SHIFT_COR + + + +//******************************************************************************** +// Function Name : Actuator_Moving +// Retun Value : Status +// Argment Value : X or Y axis, Actuator Moving Parameter Pointer, Hall Data Pointer +// Explanation : Actuator Moving Test Function +// History : First edition +//******************************************************************************** +UINT8 Actuator_Moving( UINT8 uc_axis, Act_Mov_t *pt_parameter, int *ul_readval ) +{ + UINT8 uc_status = SUCCESS ; + UnllnVal StMeasValueA, StMeasValueB ; + int targetcode ; + + // Initialize + uc_status = RtnCen124( BOTH_ON ) ; // X,Y Servo On + + if( uc_status != SUCCESS ) { + return( uc_status ) ; + } + + MesFil124( NOISE ) ; // Measure Filter Setting + + targetcode = pt_parameter->startcode ; // Set Initial Position + + while( targetcode > pt_parameter->endcode ) { + // Move to measuring porision + if( !uc_axis ) { // X Axis + RamWrite32A( HALL_RAM_GYROX_OUT, targetcode ) ; + } else { // Y Axis + RamWrite32A( HALL_RAM_GYROY_OUT, targetcode ) ; + } + + // Measure position + WitTim( 100 ) ; // Wait 100ms + + MeasureStart124( 1024, HALL_RAM_HXIDAT, HALL_RAM_HYIDAT ) ; // Measurement Starting + + MeasureWait124() ; // Wait for finishing measure + + RamRead32A( StMeasFunc_MFA_LLiIntegral1, &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4, &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2, &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4, &StMeasValueB.StUllnVal.UlHigVal ) ; + + if( !uc_axis ) { // X Axis + *ul_readval = ( INT32 )( ( INT64 )StMeasValueA.UllnValue / 1024 ) ; + } else { // Y Axis + *ul_readval = ( INT32 )( ( INT64 )StMeasValueB.UllnValue / 1024 ) ; + } + +// if( ( *( ul_readval - 1 ) - *ul_readval ) < abs( pt_parameter->step / 2 ) ) { +// uc_status = FAILURE ; +// } + + targetcode += pt_parameter->step ; + ul_readval++ ; + } + + // Move to center position + RamWrite32A( HALL_RAM_GYROX_OUT, 0 ) ; + RamWrite32A( HALL_RAM_GYROY_OUT, 0 ) ; + return( uc_status ) ; +} + + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+= ‚±‚±‚©‚ç’ljÁ by K.Otake += +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//******************************************************************************** +// Function Name : Laser_LinearityCorrection +// Retun Value : Status +// Argment Value : None +// Explanation : Linearity correction by laser displacement meter Function +// History : First edition +//******************************************************************************** +#define RATED_STROKE_RANGE 80L +UINT8 Laser_LinearityCorrection( void ) +{ + UINT16 us_peak_to_peak_x, us_rated_peak_to_peak_x, us_peak_to_peak_y, us_rated_peak_to_peak_y ; + INT32 sl_step_x, sl_position_x[ 7 ], sl_step_y, sl_position_y[ 7 ] ; + INT16 ss_laser_x[ 7 ], ss_laser_y[ 7 ] ; + UINT8 i, us_status = SUCCESS ; + INT32 sl_gyro_switch, sl_calib_status ; + + // Initialize + if( ( short )StAdjPar124.StHalAdj.UsHlxMxa < ( short )StAdjPar124.StHalAdj.UsHlxMna ) { + us_status = FAILURE ; + return( us_status ) ; + } + + if( ( short )StAdjPar124.StHalAdj.UsHlyMxa < ( short )StAdjPar124.StHalAdj.UsHlyMna ) { + us_status = FAILURE ; + return( us_status ) ; + } + + // Linearity correction disable + RamRead32A( GYRO_RAM_GYRO_Switch, &sl_gyro_switch ) ; + sl_gyro_switch &= 0xFFFFFFF7 ; + RamWrite32A( GYRO_RAM_GYRO_Switch, sl_gyro_switch ) ; + + // Servo ON + RamWrite32A( CMD_RETURN_TO_CENTER, BOTH_SRV_ON ) ; + WitTim( 100 ) ; + + // Calculate the moving position + us_peak_to_peak_x = ( unsigned short )( ( long )StAdjPar124.StHalAdj.UsHlxMxa - ( long )StAdjPar124.StHalAdj.UsHlxMna ) ; + us_rated_peak_to_peak_x = ( unsigned short )( ( long )us_peak_to_peak_x * RATED_STROKE_RANGE / 100L ) ; + sl_step_x = us_rated_peak_to_peak_x / 6 ; + + us_peak_to_peak_y = ( unsigned short )( ( long )StAdjPar124.StHalAdj.UsHlyMxa - ( long )StAdjPar124.StHalAdj.UsHlyMna ) ; + us_rated_peak_to_peak_y = ( unsigned short )( ( long )us_peak_to_peak_y * RATED_STROKE_RANGE / 100L ) ; + sl_step_y = us_rated_peak_to_peak_y / 6 ; + for( i = 0 ; i < 7 ; i++ ) { + sl_position_x[ i ] = ( long )( 0 + ( sl_step_x * ( i - 3 ) ) ) << 16 ; + sl_position_y[ i ] = ( long )( 0 + ( sl_step_y * ( i - 3 ) ) ) << 16 ; + } + + // Move the position x to initial position + RamWrite32A( HALL_RAM_GYROX_OUT, ( unsigned long )sl_position_x[ 0 ] ) ; + WitTim( 100 ) ; + + // Please set laser displacement meter to 0um + ClearLaser() ; + + // Please take laser displacement data while the actuator move + // Please take X axis laser data + for( i = 0 ; i < 7 ; i++ ) { + RamWrite32A( HALL_RAM_GYROX_OUT, ( unsigned long )sl_position_x[ i ] ) ; + WitTim( 100 ) ; + ss_laser_x[ i ] = GetLaser() ; + } + + RamWrite32A( HALL_RAM_GYROX_OUT, 0 ) ; // Return to center position + WitTim( 100 ) ; + + // Move the position y to initial position + RamWrite32A( HALL_RAM_GYROY_OUT, ( unsigned long )sl_position_y[ 0 ] ) ; + WitTim( 100 ) ; + + // Please set laser displacement meter to 0um + ClearLaser() ; + + // Please take Y axis laser data + for( i = 0 ; i < 7 ; i++ ) { + RamWrite32A( HALL_RAM_GYROY_OUT, ( unsigned long )sl_position_y[ i ] ) ; + WitTim( 100 ) ; + ss_laser_y[ i ] = GetLaser() ; + } + + RamWrite32A( HALL_RAM_GYROY_OUT, 0 ) ; // Return to center position + +#if 0 + // Test + ss_laser_x[ 0 ] = 0 ; + ss_laser_x[ 1 ] = 60 ; + ss_laser_x[ 2 ] = 123 ; + ss_laser_x[ 3 ] = 191 ; + ss_laser_x[ 4 ] = 262 ; + ss_laser_x[ 5 ] = 341 ; + ss_laser_x[ 6 ] = 427 ; + sl_step_x = 4003 ; + + ss_laser_y[ 0 ] = 0 ; + ss_laser_y[ 1 ] = 51 ; + ss_laser_y[ 2 ] = 91 ; + ss_laser_y[ 3 ] = 146 ; + ss_laser_y[ 4 ] = 201 ; + ss_laser_y[ 5 ] = 267 ; + ss_laser_y[ 6 ] = 330 ; + sl_step_y = 3482 ; +#endif + + // Send laser displacement data to DSP + RamWrite32A( StPosition_0, ( unsigned long )( ( long )( ( ss_laser_y[ 0 ] * 10 ) << 16 ) | ( ss_laser_x[ 0 ] * 10 ) ) ) ; + RamWrite32A( StPosition_1, ( unsigned long )( ( long )( ( ss_laser_y[ 1 ] * 10 ) << 16 ) | ( ss_laser_x[ 1 ] * 10 ) ) ) ; + RamWrite32A( StPosition_2, ( unsigned long )( ( long )( ( ss_laser_y[ 2 ] * 10 ) << 16 ) | ( ss_laser_x[ 2 ] * 10 ) ) ) ; + RamWrite32A( StPosition_3, ( unsigned long )( ( long )( ( ss_laser_y[ 3 ] * 10 ) << 16 ) | ( ss_laser_x[ 3 ] * 10 ) ) ) ; + RamWrite32A( StPosition_4, ( unsigned long )( ( long )( ( ss_laser_y[ 4 ] * 10 ) << 16 ) | ( ss_laser_x[ 4 ] * 10 ) ) ) ; + RamWrite32A( StPosition_5, ( unsigned long )( ( long )( ( ss_laser_y[ 5 ] * 10 ) << 16 ) | ( ss_laser_x[ 5 ] * 10 ) ) ) ; + RamWrite32A( StPosition_6, ( unsigned long )( ( long )( ( ss_laser_y[ 6 ] * 10 ) << 16 ) | ( ss_laser_x[ 6 ] * 10 ) ) ) ; + RamWrite32A( SiStepXY, ( unsigned long )( sl_step_y << 16 | sl_step_x ) ) ; + + // Linearity correction enable + RamRead32A( GYRO_RAM_GYRO_Switch, &sl_gyro_switch ) ; + sl_gyro_switch |= 0x00000008 ; + RamWrite32A( GYRO_RAM_GYRO_Switch, sl_gyro_switch ) ; + + // Linearity Data enable + RamRead32A( StCaliData_UsCalibrationStatus, &sl_calib_status ) ; + sl_calib_status &= 0xFFFFFBFF ; + RamWrite32A( StCaliData_UsCalibrationStatus, sl_calib_status ) ; + + // Calculate the coefficient for linearity correction + RamWrite32A( CMD_LASER_LINEAR_DATA, 0 ) ; + + return( us_status ) ; +} + + + +//******************************************************************************** +// Function Name : CircleTest +// Retun Value : Status +// Argment Value : Frequency, XX% Mechanical Stroke +// Explanation : Sine Wave Test Function +// History : First edition +//******************************************************************************** +#define TRACKING_THRESHOLD 0x08000000 +UINT8 CircleTest( UINT8 uc_freq, UINT8 us_amp ) +{ + UINT16 us_amplitude_x, us_amplitude_y ; + UINT32 ul_gain_x, ul_gain_y ; + UINT8 uc_status = SUCCESS ; + INT32 sl_sample_num, sl_ach_max, sl_ach_min, sl_bch_max, sl_bch_min ; + + // Initialize + uc_status = RtnCen124( BOTH_ON ) ; + + if( uc_status != SUCCESS ) { + return( uc_status ) ; + } + + OisDis124() ; + + // Sine wave amplitude setting + SetSinWavGenInt124() ; + + if( StAdjPar124.StHalAdj.UsHlxMxa > 32767 ) { + sl_ach_max = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlxMxa ; + } else { + sl_ach_max = ( INT32 )StAdjPar124.StHalAdj.UsHlxMxa ; + } + + if( StAdjPar124.StHalAdj.UsHlxMna > 32767 ) { + sl_ach_min = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlxMna ; + } else { + sl_ach_min = ( INT32 )StAdjPar124.StHalAdj.UsHlxMna ; + } + + us_amplitude_x = ( UINT16 )( ( sl_ach_max - sl_ach_min ) / 2 ) ; + + if( StAdjPar124.StHalAdj.UsHlyMxa > 32767 ) { + sl_ach_max = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlyMxa ; + } else { + sl_ach_max = ( INT32 )StAdjPar124.StHalAdj.UsHlyMxa ; + } + + if( StAdjPar124.StHalAdj.UsHlyMna > 32767 ) { + sl_ach_min = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlyMna ; + } else { + sl_ach_min = ( INT32 )StAdjPar124.StHalAdj.UsHlyMna ; + } + + us_amplitude_y = ( UINT16 )( ( sl_ach_max - sl_ach_min ) / 2 ) ; + + ul_gain_x = ( UINT32 )( ( UINT32 )us_amplitude_x * us_amp / 100 ) << 16 ; + ul_gain_y = ( UINT32 )( ( UINT32 )us_amplitude_y * us_amp / 100 ) << 16 ; + + // Sine wave generation + SetSinWavePara( uc_freq, CIRCWAVE ) ; + + RamWrite32A( SinWave_Gain, ul_gain_x ) ; // Sine wave gain + RamWrite32A( CosWave_Gain, ul_gain_y ) ; // Cosine wave gain + + // Measurement initialize + MesFil124( NOISE ) ; + + sl_sample_num = ( INT32 )( FS_FREQ / ( float )uc_freq ) ; + + // Start peak to peak measurement + MeasureStart124( sl_sample_num, HALL_RAM_HXOUT0, HALL_RAM_HYOUT0 ) ; + + MeasureWait124() ; + + // Check tracking + RamRead32A( StMeasFunc_MFA_SiMax1, &sl_ach_max ) ; + RamRead32A( StMeasFunc_MFA_SiMin1, &sl_ach_min ) ; + RamRead32A( StMeasFunc_MFB_SiMax2, &sl_bch_max ) ; + RamRead32A( StMeasFunc_MFB_SiMin2, &sl_bch_min ) ; + + if( ( ( sl_ach_max - sl_ach_min ) > TRACKING_THRESHOLD ) || ( ( sl_bch_max - sl_bch_min ) > TRACKING_THRESHOLD ) ) { + uc_status = FAILURE ; + } + + // Step sine wave + SetSinWavePara( 0, CIRCWAVE ) ; + + return( uc_status ) ; +} + + + +//******************************************************************************** +// Function Name : OscillationDetection +// Retun Value : Status +// Argment Value : XX% X axis Mechanical Stroke, XX% Y axis Mechanical Stroke +// Explanation : Sine Wave Test Function +// History : First edition +//******************************************************************************** +#define OSCILLATION_THRESHOLD 0x01000000 +UINT8 OscillationDetection( INT8 sc_offset_x, INT8 sc_offset_y, UINT16 us_wait_time ) +{ + UINT16 us_amplitude_x, us_amplitude_y ; + INT32 sl_offset_x, sl_offset_y ; + UINT8 uc_status = SUCCESS ; + INT32 sl_ach_max, sl_ach_min, sl_bch_max, sl_bch_min ; + + // Initialize + uc_status = RtnCen124( BOTH_ON ) ; + + if( uc_status != SUCCESS ) { + return( uc_status ) ; + } + + OisDis124() ; + + // Add Offset + if( StAdjPar124.StHalAdj.UsHlxMxa > 32767 ) { + sl_ach_max = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlxMxa ; + } else { + sl_ach_max = ( INT32 )StAdjPar124.StHalAdj.UsHlxMxa ; + } + + if( StAdjPar124.StHalAdj.UsHlxMna > 32767 ) { + sl_ach_min = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlxMna ; + } else { + sl_ach_min = ( INT32 )StAdjPar124.StHalAdj.UsHlxMna ; + } + + us_amplitude_x = ( UINT16 )( ( sl_ach_max - sl_ach_min ) / 2 ) ; + + if( StAdjPar124.StHalAdj.UsHlyMxa > 32767 ) { + sl_ach_max = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlyMxa ; + } else { + sl_ach_max = ( INT32 )StAdjPar124.StHalAdj.UsHlyMxa ; + } + + if( StAdjPar124.StHalAdj.UsHlyMna > 32767 ) { + sl_ach_min = ( INT32 )0xFFFF0000 | StAdjPar124.StHalAdj.UsHlyMna ; + } else { + sl_ach_min = ( INT32 )StAdjPar124.StHalAdj.UsHlyMna ; + } + + us_amplitude_y = ( UINT16 )( ( sl_ach_max - sl_ach_min ) / 2 ) ; + + sl_offset_x = ( UINT32 )( ( UINT32 )us_amplitude_x * sc_offset_x / 100 ) << 16 ; + sl_offset_y = ( UINT32 )( ( UINT32 )us_amplitude_y * sc_offset_y / 100 ) << 16 ; + TRACE( "Offset X = %x\n", sl_offset_x ) ; + TRACE( "Offset Y = %x\n", sl_offset_y ) ; + + RamWrite32A( HALL_RAM_GYROX_OUT, ( UINT32 )sl_offset_x ) ; + RamWrite32A( HALL_RAM_GYROY_OUT, ( UINT32 )sl_offset_y ) ; + + WitTim( 100 ) ; + + RamWrite32A( HALL_RAM_GYROX_OUT, 0 ) ; + RamWrite32A( HALL_RAM_GYROY_OUT, 0 ) ; + + WitTim( us_wait_time ) ; + + // Measurement initialize + MesFil124( NOISE ) ; + + // Start peak to peak measurement + MeasureStart124( 1024, HALL_RAM_HXIDAT, HALL_RAM_HYIDAT ) ; + + MeasureWait124() ; + + // Check Oscillation + RamRead32A( StMeasFunc_MFA_SiMax1, &sl_ach_max ) ; + RamRead32A( StMeasFunc_MFA_SiMin1, &sl_ach_min ) ; + RamRead32A( StMeasFunc_MFB_SiMax2, &sl_bch_max ) ; + RamRead32A( StMeasFunc_MFB_SiMin2, &sl_bch_min ) ; + TRACE( "sl_ach_max = %x\n", sl_ach_max ) ; + TRACE( "sl_ach_min = %x\n", sl_ach_min ) ; + TRACE( "sl_bch_max = %x\n", sl_bch_max ) ; + TRACE( "sl_bch_min = %x\n", sl_bch_min ) ; + + if( ( ( sl_ach_max - sl_ach_min ) > OSCILLATION_THRESHOLD ) || ( ( sl_bch_max - sl_bch_min ) > OSCILLATION_THRESHOLD ) ) { + uc_status = FAILURE ; + } + + return( uc_status ) ; +} + + + +//******************************************************************************** +// Function Name : OIS_PosMes_by_AF +// Retun Value : Status +// Argment Value : None +// Explanation : OIS Position Measurement by AF Function +// History : First edition +//******************************************************************************** +#define OIS_POSITION_THRESHOLD 0x15000000 + +#if (SELECT_VENDOR == 0x01) +//For ONSEMI 217 +UINT16 Us_Af_Position[ 9 ] = { 0x0000, 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, 0x03FF } ; +#elif (SELECT_VENDOR == 0x02) +//For AKM7374 +INT16 Us_Af_Position[ 9 ] = { 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000, 0xE000, 0xFFFF } ; +extern int TWI_WriteMultiple( int SlaveAddr, char *data, unsigned int NumOfBytes); +#endif +UINT32 UlBufDat[ 64 ] ; +INT32 Sl_Hall_X_by_AF[ 9 ] ; +INT32 Sl_Hall_Y_by_AF[ 9 ] ; +INT32 Sl_Hall_X_Slope_by_AF[ 8 ] ; +INT32 Sl_Hall_Y_Slope_by_AF[ 8 ] ; + +UINT8 OIS_PosMes_by_AF( void ) +{ + UINT8 uc_status, i ; + INT32 sl_hall_x[ 9 ], sl_hall_y[ 9 ], sl_default_x, sl_default_y ; + UnllnVal StMeasValueA, StMeasValueB ; +#if (SELECT_VENDOR == 0x02) //AKM7374 + unsigned char data[3]; +#endif + // Initialize + uc_status = RtnCen124( BOTH_OFF ) ; // X,Y Servo Off + + if( uc_status != SUCCESS ) { + return( uc_status ) ; + } + + OisDis124() ; // OIS disable + + MesFil124( NOISE ) ; // Measure filter setting + +#if (SELECT_VENDOR == 0x02) //AKM7374 + data[0] = 0x02; + data[1] = 0x00; + TWI_WriteMultiple( 0x18, (char *)data, 2 ); + WitTim( 400 ) ; + data[0] = 0x00; + data[1] = (unsigned char) (Us_Af_Position[4] >>8); + data[2] = (unsigned char) (Us_Af_Position[4] & 0x00ff); + TWI_WriteMultiple( 0x18, (char *)data, 3 ); + WitTim( 400 ) ; // Wait 100ms +#endif + + // Measure default position + WitTim( 100 ) ; // Wait 100ms + + MeasureStart124( 1024, HALL_RAM_HXIDAT, HALL_RAM_HYIDAT ) ; // Measurement Starting + + MeasureWait124() ; // Wait for finishing measure + + RamRead32A( StMeasFunc_MFA_LLiIntegral1, &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4, &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2, &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4, &StMeasValueB.StUllnVal.UlHigVal ) ; +TRACE(" StMeasValueA.StUllnVal.UlLowVal = %08x\n", StMeasValueA.StUllnVal.UlLowVal ) ; +TRACE(" StMeasValueA.StUllnVal.UlHigVal = %08x\n", StMeasValueA.StUllnVal.UlHigVal ) ; +TRACE(" StMeasValueB.StUllnVal.UlLowVal = %08x\n", StMeasValueB.StUllnVal.UlLowVal ) ; +TRACE(" StMeasValueB.StUllnVal.UlHigVal = %08x\n", StMeasValueB.StUllnVal.UlHigVal ) ; + + sl_default_x = ( INT32 )( ( INT64 )StMeasValueA.UllnValue / 1024 ) ; + sl_default_y = ( INT32 )( ( INT64 )StMeasValueB.UllnValue / 1024 ) ; + +TRACE(" X[default] = %08x\n", (unsigned int)sl_default_x ) ; +TRACE(" Y[default] = %08x\n", (unsigned int)sl_default_y) ; + + // OIS position measurement while moving AF + for( i = 0 ; i < 9 ; i++ ) { + // Please insert AF moving code here +#if (SELECT_VENDOR == 0x02) //AKM7374 + data[0] = 0x00; + data[1] = (unsigned char) (Us_Af_Position[i] >>8); + data[2] = (unsigned char) (Us_Af_Position[i] & 0x00ff); + TWI_WriteMultiple( 0x18, (char *)data, 3 ); + WitTim( 400 ) ; // Wait 100ms +#endif + WitTim( 100 ) ; // Wait 100ms + + MeasureStart124( 1024, HALL_RAM_HXIDAT, HALL_RAM_HYIDAT ) ; // Measurement Starting + + MeasureWait124() ; // Wait for finishing measure + + RamRead32A( StMeasFunc_MFA_LLiIntegral1, &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4, &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2, &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4, &StMeasValueB.StUllnVal.UlHigVal ) ; + + sl_hall_x[ i ] = ( INT32 )( ( INT64 )StMeasValueA.UllnValue / 1024 ) - sl_default_x ; + sl_hall_y[ i ] = ( INT32 )( ( INT64 )StMeasValueB.UllnValue / 1024 ) - sl_default_y ; +TRACE(" X[%02x] = %08x\n", i, (unsigned int)sl_hall_x[ i ] ) ; +TRACE(" Y[%02x] = %08x\n", i, (unsigned int)sl_hall_y[ i ] ) ; + } + + for( i = 1 ; i < 9 ; i++ ) { + if( abs( sl_hall_x[ i ] - sl_hall_x[ i - 1 ] ) > OIS_POSITION_THRESHOLD ) { + return( FAILURE ) ; + } + + if( abs( sl_hall_y[ i ] - sl_hall_y[ i - 1 ] ) > OIS_POSITION_THRESHOLD ) { + return( FAILURE ) ; + } + } + + // Please store the measurement data in external EEPROM +#if 1 + UlBufDat[ OIS_POS_BY_AF_X1 ] = sl_hall_x[0]; + UlBufDat[ OIS_POS_BY_AF_X2 ] = sl_hall_x[1]; + UlBufDat[ OIS_POS_BY_AF_X3 ] = sl_hall_x[2]; + UlBufDat[ OIS_POS_BY_AF_X4 ] = sl_hall_x[3]; + UlBufDat[ OIS_POS_BY_AF_X5 ] = sl_hall_x[4]; + UlBufDat[ OIS_POS_BY_AF_X6 ] = sl_hall_x[5]; + UlBufDat[ OIS_POS_BY_AF_X7 ] = sl_hall_x[6]; + UlBufDat[ OIS_POS_BY_AF_X8 ] = sl_hall_x[7]; + UlBufDat[ OIS_POS_BY_AF_X9 ] = sl_hall_x[8]; + + UlBufDat[ OIS_POS_BY_AF_Y1 ] = sl_hall_y[0]; + UlBufDat[ OIS_POS_BY_AF_Y2 ] = sl_hall_y[1]; + UlBufDat[ OIS_POS_BY_AF_Y3 ] = sl_hall_y[2]; + UlBufDat[ OIS_POS_BY_AF_Y4 ] = sl_hall_y[3]; + UlBufDat[ OIS_POS_BY_AF_Y5 ] = sl_hall_y[4]; + UlBufDat[ OIS_POS_BY_AF_Y6 ] = sl_hall_y[5]; + UlBufDat[ OIS_POS_BY_AF_Y7 ] = sl_hall_y[6]; + UlBufDat[ OIS_POS_BY_AF_Y8 ] = sl_hall_y[7]; + UlBufDat[ OIS_POS_BY_AF_Y9 ] = sl_hall_y[8]; +#endif + + return( uc_status ) ; +} + + + +//******************************************************************************** +// Function Name : Read_OIS_PosData_by_AF +// Retun Value : None +// Argment Value : None +// Explanation : Read OIS Position Data by AF Function +// History : First edition +//******************************************************************************** +void Read_OIS_PosData_by_AF( void ) +{ + UINT8 i ; + + // Please insert the function what reads OIS shift cal data from external EEPROM + +//------------------------------------------------------------------------------------------------ +// Read Calibration data +//------------------------------------------------------------------------------------------------ + // Here is Inputing the dummy data + // But, Actually, Please input OIS shift cal data + Sl_Hall_X_by_AF[ 0 ] = UlBufDat[ OIS_POS_BY_AF_X1 ] ; + Sl_Hall_X_by_AF[ 1 ] = UlBufDat[ OIS_POS_BY_AF_X2 ] ; + Sl_Hall_X_by_AF[ 2 ] = UlBufDat[ OIS_POS_BY_AF_X3 ] ; + Sl_Hall_X_by_AF[ 3 ] = UlBufDat[ OIS_POS_BY_AF_X4 ] ; + Sl_Hall_X_by_AF[ 4 ] = UlBufDat[ OIS_POS_BY_AF_X5 ] ; + Sl_Hall_X_by_AF[ 5 ] = UlBufDat[ OIS_POS_BY_AF_X6 ] ; + Sl_Hall_X_by_AF[ 6 ] = UlBufDat[ OIS_POS_BY_AF_X7 ] ; + Sl_Hall_X_by_AF[ 7 ] = UlBufDat[ OIS_POS_BY_AF_X8 ] ; + Sl_Hall_X_by_AF[ 8 ] = UlBufDat[ OIS_POS_BY_AF_X9 ] ; + + Sl_Hall_Y_by_AF[ 0 ] = UlBufDat[ OIS_POS_BY_AF_Y1 ] ; + Sl_Hall_Y_by_AF[ 1 ] = UlBufDat[ OIS_POS_BY_AF_Y2 ] ; + Sl_Hall_Y_by_AF[ 2 ] = UlBufDat[ OIS_POS_BY_AF_Y3 ] ; + Sl_Hall_Y_by_AF[ 3 ] = UlBufDat[ OIS_POS_BY_AF_Y4 ] ; + Sl_Hall_Y_by_AF[ 4 ] = UlBufDat[ OIS_POS_BY_AF_Y5 ] ; + Sl_Hall_Y_by_AF[ 5 ] = UlBufDat[ OIS_POS_BY_AF_Y6 ] ; + Sl_Hall_Y_by_AF[ 6 ] = UlBufDat[ OIS_POS_BY_AF_Y7 ] ; + Sl_Hall_Y_by_AF[ 7 ] = UlBufDat[ OIS_POS_BY_AF_Y8 ] ; + Sl_Hall_Y_by_AF[ 8 ] = UlBufDat[ OIS_POS_BY_AF_Y9 ] ; + +//------------------------------------------------------------------------------------------------ +// Calculate the slope +//------------------------------------------------------------------------------------------------ + for( i = 0 ; i < 8 ; i++ ) { +#if (SELECT_VENDOR == 0x02) + Sl_Hall_X_Slope_by_AF[ i ] = ( Sl_Hall_X_by_AF[ i + 1 ] - Sl_Hall_X_by_AF[ i ] ) / (INT32)( Us_Af_Position[ i + 1 ] - Us_Af_Position[ i ] ) ; + Sl_Hall_Y_Slope_by_AF[ i ] = ( Sl_Hall_Y_by_AF[ i + 1 ] - Sl_Hall_Y_by_AF[ i ] ) / (INT32)( Us_Af_Position[ i + 1 ] - Us_Af_Position[ i ] ) ; +#else + Sl_Hall_X_Slope_by_AF[ i ] = ( INT32 )( ( Sl_Hall_X_by_AF[ i + 1 ] - Sl_Hall_X_by_AF[ i ] ) / ( Us_Af_Position[ i + 1 ] - Us_Af_Position[ i ] ) ) ; + Sl_Hall_Y_Slope_by_AF[ i ] = ( INT32 )( ( Sl_Hall_Y_by_AF[ i + 1 ] - Sl_Hall_Y_by_AF[ i ] ) / ( Us_Af_Position[ i + 1 ] - Us_Af_Position[ i ] ) ) ; +#endif + } + + return ; +} + + + +//******************************************************************************** +// Function Name : OIS_Pos_Correction_by_AF +// Retun Value : None +// Argment Value : AF Code +// Explanation : OIS Position Correction by AF Function +// History : First edition +//******************************************************************************** +void OIS_Pos_Correction_by_AF( UINT16 us_af_code ) +{ + UINT8 i ; + INT32 sl_offset_x, sl_offset_y ; + + for( i = 1 ; i < 9 ; i++ ) { + if( us_af_code < Us_Af_Position[ i ] + 1 ) { +#if (SELECT_VENDOR == 0x02) + sl_offset_x = ( INT32 )( Sl_Hall_X_Slope_by_AF[ i - 1 ] * ( (INT32)us_af_code - (INT32)Us_Af_Position[ i - 1 ] ) + Sl_Hall_X_by_AF[ i - 1 ] ) ; + sl_offset_y = ( INT32 )( Sl_Hall_Y_Slope_by_AF[ i - 1 ] * ( (INT32)us_af_code - (INT32)Us_Af_Position[ i - 1 ] ) + Sl_Hall_Y_by_AF[ i - 1 ] ) ; +#else + sl_offset_x = ( INT32 )( Sl_Hall_X_Slope_by_AF[ i - 1 ] * ( us_af_code - Us_Af_Position[ i - 1 ] ) + ( Sl_Hall_X_by_AF[ i - 1 ] - Sl_Hall_X_by_AF[ 0 ] ) ) ; + sl_offset_y = ( INT32 )( Sl_Hall_Y_Slope_by_AF[ i - 1 ] * ( us_af_code - Us_Af_Position[ i - 1 ] ) + ( Sl_Hall_Y_by_AF[ i - 1 ] - Sl_Hall_Y_by_AF[ 0 ] ) ) ; +#endif + break ; + } + } + + RamWrite32A( HALL_RAM_HXOFF1, sl_offset_x ) ; + RamWrite32A( HALL_RAM_HYOFF1, sl_offset_y ) ; +} + + +#if ((SELECT_VENDOR & 0x80 ) != 0x80) +//******************************************************************************** +// Function Name : CalcSetMizxAndLinearityData +// Retun Value : 0:OK, 1:NG +// Argment Value : UcMode 0:disable 1:enable +// : mlLinearityValue *linval +// Explanation : Flash write linearity correction data function +// History : First edition +//******************************************************************************** +#define N 7 /* ƒf[ƒ^” */ + +UINT8 CalcSetMizxAndLinearityData( mlLinearityValue *linval , mlMixingValue *mixval ) +{ + int i; + double Xa = 0, Ya = 0; + double Xsum_xy = 0, Xsum_x = 0, Xsum_y = 0, Xsum_x2 = 0; + double Ysum_xy = 0, Ysum_x = 0, Ysum_y = 0, Ysum_x2 = 0; + UINT8 ans; + + // ************************************************** + // Ŭ2æ–@ + // ************************************************** +#ifdef __MIX_LIB_METHOD__ // TESTAPP library method + for (i=0; i<N; i++) { + Xsum_xy += i * mixval->XonXmove[i]; + Xsum_x += i; + Xsum_y += mixval->XonXmove[i]; + + Ysum_xy += i * mixval->YonXmove[i]; + Ysum_y += mixval->YonXmove[i]; + } + Xa = ((N * Ysum_xy) - (Xsum_x * Ysum_y)) / ((N * Xsum_xy) - (Xsum_x * Xsum_y)); + + Xsum_xy = Xsum_x = Xsum_y = Xsum_x2 = 0; + Ysum_xy = Ysum_x = Ysum_y = Ysum_x2 = 0; + + for (i=0; i<N; i++) { + Xsum_xy += i * mixval->XonYmove[i]; + Xsum_x += i; + Xsum_y += mixval->XonYmove[i]; + + Ysum_xy += i * mixval->YonYmove[i]; + Ysum_y += mixval->YonYmove[i]; + } + Ya = ((N * Xsum_xy) - (Xsum_x * Xsum_y)) / ((N * Ysum_xy) - (Xsum_x * Ysum_y)); +#else + for (i=0; i<N; i++) { + Xsum_xy += mixval->XonXmove[i] * mixval->YonXmove[i]; + Xsum_x += mixval->XonXmove[i]; + Xsum_y += mixval->YonXmove[i]; + Xsum_x2 += pow(mixval->XonXmove[i], 2); + + Ysum_xy += mixval->YonYmove[i] * mixval->XonYmove[i]; + Ysum_x += mixval->YonYmove[i]; + Ysum_y += mixval->XonYmove[i]; + Ysum_x2 += pow(mixval->YonYmove[i], 2); + } + Xa = ((N * Xsum_xy) - (Xsum_x * Xsum_y)) / ((N * Xsum_x2) - pow(Xsum_x, 2)); + Ya = ((N * Ysum_xy) - (Ysum_x * Ysum_y)) / ((N * Ysum_x2) - pow(Ysum_x, 2)); +#endif + +TRACE("Xa = %f\n", Xa); +TRACE("Ya = %f\n", Ya); + + // ************************************************** + // MIXINGŒW”ŒvŽZ + // ************************************************** +TRACE("degreeX = %f\n", -atan(Xa)*180/3.14159265358979323846 ); +TRACE("degreeY = %f\n", +atan(Ya)*180/3.14159265358979323846 ); +#if (SLT_XY_SWAP ==1) + mixval->radianX = +atan(Ya); + mixval->radianY = -atan(Xa); +#else + mixval->radianX = -atan(Xa); + mixval->radianY = +atan(Ya); +#endif +//TRACE("radianX = %f\n", mixval->radianX); +//TRACE("radianY = %f\n", mixval->radianY); + + mixval->hx45x = +(cos(mixval->radianY) / cos(mixval->radianX - mixval->radianY)); + mixval->hx45y = -(sin(mixval->radianY) / cos(mixval->radianX - mixval->radianY)); +// mixval->hy45y = -(cos(mixval->radianX) / cos(mixval->radianX - mixval->radianY)); +// mixval->hy45x = -(sin(mixval->radianX) / cos(mixval->radianX - mixval->radianY)); + mixval->hy45y = +(cos(mixval->radianX) / cos(mixval->radianX - mixval->radianY)); + mixval->hy45x = +(sin(mixval->radianX) / cos(mixval->radianX - mixval->radianY)); + + mixval->hxsx = (unsigned char)abs(mixval->hx45x); // >1‚È‚ç‚΃Vƒtƒg”‚Æ‚µ‚ÄÝ’è + mixval->hysx = (unsigned char)abs(mixval->hy45y); // >1‚È‚ç‚΃Vƒtƒg”‚Æ‚µ‚ÄÝ’è + + mixval->hx45x = mixval->hx45x / pow(2, (double)mixval->hxsx); // ƒVƒtƒg‚ð‰Á–¡‚µ‚ÄÄŒvŽZ + mixval->hy45y = mixval->hy45y / pow(2, (double)mixval->hysx); // ƒVƒtƒg‚ð‰Á–¡‚µ‚ÄÄŒvŽZ + +TRACE("hx45x = %f\n", mixval->hx45x); +TRACE("hx45y = %f\n", mixval->hx45y); +TRACE("hy45y = %f\n", mixval->hy45y); +TRACE("hy45x = %f\n", mixval->hy45x); +TRACE("hxsx = %02X\n", mixval->hxsx); +TRACE("hysx = %02X\n", mixval->hysx); + + mixval->hx45xL = (long)(mixval->hx45x * 0x7FFFFFFF); + mixval->hx45yL = (long)(mixval->hx45y * 0x7FFFFFFF); + mixval->hy45yL = (long)(mixval->hy45y * 0x7FFFFFFF); + mixval->hy45xL = (long)(mixval->hy45x * 0x7FFFFFFF); + +TRACE("hx45xL = %08X\n", mixval->hx45xL); +TRACE("hx45yL = %08X\n", mixval->hx45yL); +TRACE("hy45yL = %08X\n", mixval->hy45yL); +TRACE("hy45xL = %08X\n", mixval->hy45xL); + + // ************************************************** + // RAM‚ɃZƒbƒg‚·‚é + // ************************************************** + RamWrite32A( HF_hx45x, mixval->hx45xL ) ; + RamWrite32A( HF_hx45y, mixval->hx45yL ) ; + RamWrite32A( HF_hy45y, mixval->hy45yL ) ; + RamWrite32A( HF_hy45x, mixval->hy45xL ) ; + RamWrite32A( HF_ShiftX, ( (UINT32) mixval->hxsx << 0) | ((UINT32)mixval->hysx << 8) ) ; + + ans = WrHallLnData( 1, linval ) ; + + if( ans ) { + return( ans ) ; // CheckSum OK + } + + ans = WrMixCalData124( 1, mixval ) ; + + return( ans ) ; // CheckSum OK +} +#endif + +#if USE_BOSCH +//******************************************************************************** +// Function Name : Read_BMI260_CHIP_ID +// Retun Value : None +// Argment Value : None +// Explanation : Read CHIP_ID from BOSCH BMI260 +// History : First edition +//******************************************************************************** +UINT8 Read_BMI260_CHIP_ID( void ) +{ + unsigned char ReadData; + + struct bmi2_dev dev = { + .dev_id = BMI2_I2C_PRIM_ADDR, + .intf = BMI2_I2C_INTERFACE, + .read = bmi2_i2c_read, + .write = bmi2_i2c_write, + .delay_ms = bmi2_delay_milli_sec, + .read_write_len = 2, + .config_file_ptr = NULL + }; + + bmi2_get_regs( CHIP_ID_260, &ReadData, 1, &dev ); + + return ReadData; +} + +//******************************************************************************** +// Function Name : Configuring_BMI260 +// Retun Value : None +// Argment Value : None +// Explanation : Initialize BOSCH BMI260 +// History : First edition +//******************************************************************************** +UINT8 Configuring_BMI260( void ) +{ + unsigned char WriteData; + unsigned char ReadData; + char Count; + unsigned char Status = FAILURE; // 0x01=NG 0x00=OK + + struct bmi2_dev dev = { + .dev_id = BMI2_I2C_PRIM_ADDR, + .intf = BMI2_I2C_INTERFACE, + .read = bmi2_i2c_read, + .write = bmi2_i2c_write, + .delay_ms = bmi2_delay_milli_sec, + .read_write_len = 2, + .config_file_ptr = NULL + }; + + // PWR_CTRL(0x7D) to set bit ACC_EN and GYR_EN to neable them + Count = 0; + do { + WriteData = 0x0E; + bmi2_set_regs( PWR_CTRL_260, &WriteData, 1, &dev ); // write to BMI260 + bmi2_get_regs( PWR_CTRL_260, &ReadData, 1, &dev ); // read from BMI260 + + if( WriteData == ReadData ) { + Status = SUCCESS; + break; + } + } while( Count++ < 20 ); + + if( Status == FAILURE ) return Status; + + // Please set as necessary. + // Setting accelerometer interface + WriteData = 0xA8; // ACC_CONF(0x40) ODR=100, OSR = normal mode + bmi2_set_regs( ACC_CONF_260, &WriteData, 1, &dev ); + WriteData = 0x02; // ACC_RANGE(0x41) +/- 8g + bmi2_set_regs( ACC_RANGE_260, &WriteData, 1, &dev ); + WriteData = 0x03; // GYR_RANGE(0x43) +/- 250dps + bmi2_set_regs( GYR_RANGE_260, &WriteData, 1, &dev ); + WriteData = 0xE9; // GYR_CONF(0x42) + bmi2_set_regs( GYR_CONF_260, &WriteData, 1, &dev ); + WriteData = 0x02; // PWR_CONF(0x7C) + bmi2_set_regs( PWR_CONF_260, &WriteData, 1, &dev ); + WriteData = 0x10; // IF_CONF(0x6B) + bmi2_set_regs( IF_CONF_260, &WriteData, 1, &dev ); + + return Status; +} + +//******************************************************************************** +// Function Name : PerformingInitialization_BMI260 +// Retun Value : None +// Argment Value : None +// Explanation : Performing Initialization sequence BOSCH BMI260 +// History : First edition +//******************************************************************************** +UINT8 PerformingInitialization_BMI260( void ) +{ + int8_t rslt; + + struct bmi2_dev dev = { + .dev_id = BMI2_I2C_PRIM_ADDR, + .intf = BMI2_I2C_INTERFACE, + .read = bmi2_i2c_read, + .write = bmi2_i2c_write, + .delay_ms = bmi2_delay_milli_sec, +// .read_write_len = 2, + .read_write_len = 60, + .config_file_ptr = NULL + }; + + rslt = bmi2_init(&dev); + if (rslt != BMI2_OK) { // BMI2_OK(0x00) + rslt = FAILURE; // 0x01=NG 0x00=OK + } + + return rslt; +} + +//******************************************************************************** +// Function Name : Read_InternalStatus_BMI260 +// Retun Value : None +// Argment Value : None +// Explanation : Checking the correct initialization status BOSCH BMI260 +// History : First edition +//******************************************************************************** +UINT8 Read_InternalStatus_BMI260( void ) +{ + unsigned char ReadData; + + struct bmi2_dev dev = { + .dev_id = BMI2_I2C_PRIM_ADDR, + .intf = BMI2_I2C_INTERFACE, + .read = bmi2_i2c_read, + .write = bmi2_i2c_write, + .delay_ms = bmi2_delay_milli_sec, + .read_write_len = 2, + .config_file_ptr = NULL + }; + + bmi2_get_regs( INTERNAL_STATUS_260, &ReadData, 1, &dev ); + + return ReadData; +} +#endif + + +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+= ‚±‚±‚܂Šby K.Otake += +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= +//+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisFRA.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisFRA.c new file mode 100755 index 0000000000000000000000000000000000000000..ad19104b669a31fdb9c8de1f265071ffd69b86d1 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisFRA.c @@ -0,0 +1,445 @@ +/** + * @brief FRA measurement command for LC898123 F40 + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file OisFRA.c + * @date svn:$Date:: 2016-06-17 16:42:32 +0900#$ + * @version svn:$Revision: 54 $ + * @attention + **/ + +//************************** +// Include Header File +//************************** +#define __OISFRA__ + +#include <math.h> +#include "Ois.h" +#include "OisAPI.h" +#include "OisFRA.h" + + +#define ACT_THROUGH_CLOSE // for ball type +//#define CLOSED_RESPONSE // for openloop measurement + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A( INT32, INT32 ); +extern void RamRead32A( UINT16, void * ); +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( UINT16 ); + +//************************** +// External Function Prototype +//************************** +extern void SetSineWave( UINT8 , UINT8 ); +extern void SetSinWavGenInt124( void ); +extern void SetTransDataAdr124( UINT16, UINT32 ) ; +extern void MeasureWait124( void ) ; +extern void ClrMesFil124( void ) ; +extern void SetWaitTime124( UINT16 ) ; + +#ifdef ACT_THROUGH_CLOSE +UINT_32 BackupParameter[30]; +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : SetThroughParameter */ +/* input parameter : */ +/* output parameter : */ +/* comment : DFT‚ÌŒW””­¶ */ +/* 2018.01.18 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +void SetThroughParameter(UINT_8 UcDirSel ) +{ + if( UcDirSel == X_DIR ) { + BackupParameter[29] = X_DIR; + RamRead32A( HallFilterCoeffX_hxdgain0, &BackupParameter[0]); + RamRead32A( HallFilterCoeffX_hxpgain0, &BackupParameter[1]); + RamRead32A( HallFilterCoeffX_hxpgain1, &BackupParameter[2]); + RamRead32A( HallFilterCoeffX_hxigain0, &BackupParameter[3]); + RamRead32A( HallFilterCoeffX_hxgain0, &BackupParameter[4]); + RamRead32A( HallFilterShiftX, &BackupParameter[5]); + RamRead32A( (HallFilterShiftX+4), &BackupParameter[6]); + RamRead32A( HallFilterCoeffX_hxsa, &BackupParameter[7]); + RamRead32A( HallFilterCoeffX_hxsb, &BackupParameter[8]); + RamRead32A( HallFilterCoeffX_hxsc, &BackupParameter[9]); + RamRead32A( HallFilterCoeffX_hxoa, &BackupParameter[10]); + RamRead32A( HallFilterCoeffX_hxob, &BackupParameter[11]); + RamRead32A( HallFilterCoeffX_hxoc, &BackupParameter[12]); + RamRead32A( HallFilterCoeffX_hxod, &BackupParameter[13]); + RamRead32A( HallFilterCoeffX_hxoe, &BackupParameter[14]); + RamRead32A( HallFilterCoeffX_hxpa, &BackupParameter[15]); + RamRead32A( HallFilterCoeffX_hxpb, &BackupParameter[16]); + RamRead32A( HallFilterCoeffX_hxpc, &BackupParameter[17]); + RamRead32A( HallFilterCoeffX_hxpd, &BackupParameter[18]); + RamRead32A( HallFilterCoeffX_hxpe, &BackupParameter[19]); + + RamWrite32A( HallFilterCoeffX_hxdgain0, 0x00000000); //RAMW32 80EC 00000000 + RamWrite32A( HallFilterCoeffX_hxpgain0, 0x7fffffff); //RAMW32 80D8 7fffffff + RamWrite32A( HallFilterCoeffX_hxpgain1, 0x7fffffff); //RAMW32 80E4 7fffffff + RamWrite32A( HallFilterCoeffX_hxigain0, 0x00000000); //RAMW32 80E8 00000000 + RamWrite32A( HallFilterCoeffX_hxgain0, 0x7fffffff); //RAMW32 80F0 7fffffff + RamWrite32A( HallFilterShiftX, 0x00000000); //RAMW32 81F8 00000000 + RamWrite32A( (HallFilterShiftX+4), 0x00000000); //RAMW32 81FC 00000000 + RamWrite32A( HallFilterCoeffX_hxsa, 0x7fffffff); //RAMW32 8100 7fffffff + RamWrite32A( HallFilterCoeffX_hxsb, 0x00000000); //RAMW32 80F8 00000000 + RamWrite32A( HallFilterCoeffX_hxsc, 0x00000000); //RAMW32 80FC 00000000 + RamWrite32A( HallFilterCoeffX_hxoa, 0x7fffffff); //RAMW32 8114 7fffffff + RamWrite32A( HallFilterCoeffX_hxob, 0x00000000); //RAMW32 8104 00000000 + RamWrite32A( HallFilterCoeffX_hxoc, 0x00000000); //RAMW32 8108 00000000 + RamWrite32A( HallFilterCoeffX_hxod, 0x00000000); //RAMW32 810C 00000000 + RamWrite32A( HallFilterCoeffX_hxoe, 0x00000000); //RAMW32 8110 00000000 + RamWrite32A( HallFilterCoeffX_hxpa, 0x7fffffff); //RAMW32 8128 7fffffff + RamWrite32A( HallFilterCoeffX_hxpb, 0x00000000); //RAMW32 8118 00000000 + RamWrite32A( HallFilterCoeffX_hxpc, 0x00000000); //RAMW32 811C 00000000 + RamWrite32A( HallFilterCoeffX_hxpd, 0x00000000); //RAMW32 8120 00000000 + RamWrite32A( HallFilterCoeffX_hxpe, 0x00000000); //RAMW32 8124 00000000 + }else if( UcDirSel == Y_DIR ){ + BackupParameter[29] = Y_DIR; + RamRead32A( HallFilterCoeffY_hydgain0, &BackupParameter[0]); + RamRead32A( HallFilterCoeffY_hypgain0, &BackupParameter[1]); + RamRead32A( HallFilterCoeffY_hypgain1, &BackupParameter[2]); + RamRead32A( HallFilterCoeffY_hyigain0, &BackupParameter[3]); + RamRead32A( HallFilterCoeffY_hygain0, &BackupParameter[4]); + RamRead32A( HallFilterShiftY, &BackupParameter[5]); + RamRead32A( HallFilterCoeffY_hysa, &BackupParameter[6]); + RamRead32A( HallFilterCoeffY_hysb, &BackupParameter[7]); + RamRead32A( HallFilterCoeffY_hysc, &BackupParameter[8]); + RamRead32A( HallFilterCoeffY_hyoa, &BackupParameter[9]); + RamRead32A( HallFilterCoeffY_hyob, &BackupParameter[10]); + RamRead32A( HallFilterCoeffY_hyoc, &BackupParameter[11]); + RamRead32A( HallFilterCoeffY_hyod, &BackupParameter[12]); + RamRead32A( HallFilterCoeffY_hyoe, &BackupParameter[13]); + RamRead32A( HallFilterCoeffY_hypa, &BackupParameter[14]); + RamRead32A( HallFilterCoeffY_hypb, &BackupParameter[15]); + RamRead32A( HallFilterCoeffY_hypc, &BackupParameter[16]); + RamRead32A( HallFilterCoeffY_hypd, &BackupParameter[17]); + RamRead32A( HallFilterCoeffY_hype, &BackupParameter[18]); + + RamWrite32A( HallFilterCoeffY_hydgain0, 0x00000000); //RAMW32 8188 00000000 + RamWrite32A( HallFilterCoeffY_hypgain0, 0x7fffffff); //RAMW32 8174 7fffffff + RamWrite32A( HallFilterCoeffY_hypgain1, 0x7fffffff); //RAMW32 8180 7fffffff + RamWrite32A( HallFilterCoeffY_hyigain0, 0x00000000); //RAMW32 8184 00000000 + RamWrite32A( HallFilterCoeffY_hygain0, 0x7fffffff); //RAMW32 818C 7fffffff + RamWrite32A( HallFilterShiftY, 0x00000000); //RAMW32 8200 00000000 + RamWrite32A( HallFilterCoeffY_hysa, 0x7fffffff); //RAMW32 819C 7fffffff + RamWrite32A( HallFilterCoeffY_hysb, 0x00000000); //RAMW32 8194 00000000 + RamWrite32A( HallFilterCoeffY_hysc, 0x00000000); //RAMW32 8198 00000000 + RamWrite32A( HallFilterCoeffY_hyoa, 0x7fffffff); //RAMW32 81B0 7fffffff + RamWrite32A( HallFilterCoeffY_hyob, 0x00000000); //RAMW32 81A0 00000000 + RamWrite32A( HallFilterCoeffY_hyoc, 0x00000000); //RAMW32 81A4 00000000 + RamWrite32A( HallFilterCoeffY_hyod, 0x00000000); //RAMW32 81A8 00000000 + RamWrite32A( HallFilterCoeffY_hyoe, 0x00000000); //RAMW32 81AC 00000000 + RamWrite32A( HallFilterCoeffY_hypa, 0x7fffffff); //RAMW32 81C4 7fffffff + RamWrite32A( HallFilterCoeffY_hypb, 0x00000000); //RAMW32 81B4 00000000 + RamWrite32A( HallFilterCoeffY_hypc, 0x00000000); //RAMW32 81B8 00000000 + RamWrite32A( HallFilterCoeffY_hypd, 0x00000000); //RAMW32 81BC 00000000 + RamWrite32A( HallFilterCoeffY_hype, 0x00000000); //RAMW32 81C0 00000000 + }else if( UcDirSel == Z_DIR ){ + } + } + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : ResetThroughParameter */ +/* input parameter : */ +/* output parameter : */ +/* comment : DFT‚ÌŒW””­¶ */ +/* 2018.01.18 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +void ResetThroughParameter(void) +{ + if( BackupParameter[29] == X_DIR ) { + RamWrite32A( HallFilterCoeffX_hxdgain0, BackupParameter[0]); + RamWrite32A( HallFilterCoeffX_hxpgain0, BackupParameter[1]); + RamWrite32A( HallFilterCoeffX_hxpgain1, BackupParameter[2]); + RamWrite32A( HallFilterCoeffX_hxigain0, BackupParameter[3]); + RamWrite32A( HallFilterCoeffX_hxgain0, BackupParameter[4]); + RamWrite32A( HallFilterShiftX, BackupParameter[5]); + RamWrite32A( (HallFilterShiftX+4), BackupParameter[6]); + RamWrite32A( HallFilterCoeffX_hxsa, BackupParameter[7]); + RamWrite32A( HallFilterCoeffX_hxsb, BackupParameter[8]); + RamWrite32A( HallFilterCoeffX_hxsc, BackupParameter[9]); + RamWrite32A( HallFilterCoeffX_hxoa, BackupParameter[10]); + RamWrite32A( HallFilterCoeffX_hxob, BackupParameter[11]); + RamWrite32A( HallFilterCoeffX_hxoc, BackupParameter[12]); + RamWrite32A( HallFilterCoeffX_hxod, BackupParameter[13]); + RamWrite32A( HallFilterCoeffX_hxoe, BackupParameter[14]); + RamWrite32A( HallFilterCoeffX_hxpa, BackupParameter[15]); + RamWrite32A( HallFilterCoeffX_hxpb, BackupParameter[16]); + RamWrite32A( HallFilterCoeffX_hxpc, BackupParameter[17]); + RamWrite32A( HallFilterCoeffX_hxpd, BackupParameter[18]); + RamWrite32A( HallFilterCoeffX_hxpe, BackupParameter[19]); + }else if( BackupParameter[29] == Y_DIR ){ + RamWrite32A( HallFilterCoeffY_hydgain0, BackupParameter[0]); + RamWrite32A( HallFilterCoeffY_hypgain0, BackupParameter[1]); + RamWrite32A( HallFilterCoeffY_hypgain1, BackupParameter[2]); + RamWrite32A( HallFilterCoeffY_hyigain0, BackupParameter[3]); + RamWrite32A( HallFilterCoeffY_hygain0, BackupParameter[4]); + RamWrite32A( HallFilterShiftY, BackupParameter[5]); + RamWrite32A( HallFilterCoeffY_hysa, BackupParameter[6]); + RamWrite32A( HallFilterCoeffY_hysb, BackupParameter[7]); + RamWrite32A( HallFilterCoeffY_hysc, BackupParameter[8]); + RamWrite32A( HallFilterCoeffY_hyoa, BackupParameter[9]); + RamWrite32A( HallFilterCoeffY_hyob, BackupParameter[10]); + RamWrite32A( HallFilterCoeffY_hyoc, BackupParameter[11]); + RamWrite32A( HallFilterCoeffY_hyod, BackupParameter[12]); + RamWrite32A( HallFilterCoeffY_hyoe, BackupParameter[13]); + RamWrite32A( HallFilterCoeffY_hypa, BackupParameter[14]); + RamWrite32A( HallFilterCoeffY_hypb, BackupParameter[15]); + RamWrite32A( HallFilterCoeffY_hypc, BackupParameter[16]); + RamWrite32A( HallFilterCoeffY_hypd, BackupParameter[17]); + RamWrite32A( HallFilterCoeffY_hype, BackupParameter[18]); + }else if( BackupParameter[29] == Z_DIR ){ + } +} +#endif +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : CoeffGenerate */ +/* input parameter : */ +/* output parameter : */ +/* comment : DFT‚ÌŒW””­¶ */ +/* 2018.01.18 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#define Q31 ( 0x7FFFFFFF ) +#define Q23 ( 0x007FFFFF ) +#define Q21 ( 0x001FFFFF ) +#define PAI ( 3.14159265358979323846 ) +#define N ( 2048 ) +int nDivision; + +void CoeffGenerate( double fc ) +{ + double df, fs; + int point, C0, S0, CN, SN; + double theta; // theta = 2*Pi*f/Fs + + if ( fc > 40 ){ nDivision = 0; fs = (FS_FREQ ); } + else if ( fc > 20 ){ nDivision = 1; fs = (FS_FREQ / 2); } + else if ( fc > 10 ){ nDivision = 2; fs = (FS_FREQ / 4); } + else if ( fc > 5 ){ nDivision = 3; fs = (FS_FREQ / 8); } + else { nDivision = 4; fs = (FS_FREQ /16); } + + //***** Žæ“¾‚µ‚½Žü”g”ƒe[ƒuƒ‹‚©‚ç”»’èƒ|ƒCƒ“ƒg‚Æ”»’ètheta‚ÌŽZo ***** + df = fs / (double)N; // FFT‚Ì1ƒ|ƒCƒ“ƒg“–‚½‚è‚ÌŽü”g” + point = (int)(fc / df + 0.5); // ”»’èƒ|ƒCƒ“ƒg‚ÌŽZo + theta = 2.0 * PAI * (double)point * df / fs; // ”»’èƒ|ƒCƒ“ƒg‚Å‚ÌˆÊ‘Š‚ÌŽZo + + C0 = (int)((double)Q31 * cos(theta) + 0.5); + S0 = (int)((double)Q31 * sin(theta) + 0.5); + CN = (int)((double)Q31 * cos(((double)N - 1.0) * theta) + 0.5); + SN = (int)((double)Q31 * sin(((double)N - 1.0) * theta) + 0.5); + + RamWrite32A( FRA_DMA_DeciShift, nDivision ); + RamWrite32A( FRA_DMB_C0, C0 ) ; + RamWrite32A( FRA_DMB_S0, S0 ) ; + RamWrite32A( FRA_DMB_CN, CN ) ; + RamWrite32A( FRA_DMB_SN, SN ) ; + +TRACE("0x%08X, 0x%08X, 0x%08X, 0x%08X,\n", C0, S0, CN, SN); +} + +//******************************************************************************** +// Function Name : Freq_Convert +// Retun Value : Phase Step Value +// Argment Value : Frequency +// Explanation : Convert Frequency +// History : First edition +//******************************************************************************** +UINT32 Freq_Convert( float SfFreq ) +{ + UINT32 UlPhsStep; + + UlPhsStep = ( UINT32 )( ( SfFreq * ( float )0x100000000 / FS_FREQ + 0.5F ) / 2.0F ) ; + + return( UlPhsStep ) ; +} + + +//******************************************************************************** +// Function Name : MesStart_FRA_Single +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void MesStart_FRA_Single( UINT8 UcDirSel ) +{ + float SfTmp ; + INT32 GainQ23, PhaseQ21 ; + UINT32 UlReadVal ; + + + SetSinWavGenInt124() ; + // Change Frequency + RamWrite32A( SinWave_Offset, Freq_Convert( StFRAParam.StHostCom.SfFrqCom.SfFltVal ) ) ; // Freq Setting = Freq * 80000000h / Fs : 10Hz + + SfTmp = StFRAParam.StHostCom.SfAmpCom.SfFltVal / 1400.0F ; // AVDD 2800mV / 2 = 1400mV + RamWrite32A( SinWave_Gain, ( UINT32 )( ( float )0x7FFFFFFF * SfTmp ) ) ; // Set Sine Wave Gain + + if ( StFRAParam.StHostCom.UcAvgCycl == 10) { // Actuator Through +#ifdef ACT_THROUGH_CLOSE + SetThroughParameter( UcDirSel ); + + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_FRA_XSININ ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HALL_FRA_XHOUTA ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_FRA_XHOUTB ) ; + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_FRA_YSININ ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HALL_FRA_YHOUTA ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_FRA_YHOUTB ) ; + }else if( UcDirSel == Z_DIR ){ + } +#else + RtnCen124( BOTH_OFF ) ; + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_SINDX1 ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HALL_RAM_SINDX1 ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HXIDAT ) ; + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_RAM_SINDY1 ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HALL_RAM_SINDY1 ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HXIDAT ) ; + } + #ifdef SEL_CLOSED_AF + else if( UcDirSel == Z_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)CLAF_RAMA_AFOUT ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, CLAF_RAMA_AFOUT ) ; + RamWrite32A( FRA_DMA_OutputData, CLAF_RAMA_AFADIN ) ; + } + #endif +#endif + } else { + if( UcDirSel == X_DIR ) { + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_FRA_XSININ ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address +#ifdef CLOSED_RESPONSE + RamWrite32A( FRA_DMA_InputData, HALL_FRA_XSININ ) ; +#else + RamWrite32A( FRA_DMA_InputData, HALL_FRA_XHOUTA ) ; +#endif + RamWrite32A( FRA_DMA_OutputData, HALL_FRA_XHOUTB ) ; + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)HALL_FRA_YSININ ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address +#ifdef CLOSED_RESPONSE + RamWrite32A( FRA_DMA_InputData, HALL_FRA_YSININ ) ; +#else + RamWrite32A( FRA_DMA_InputData, HALL_FRA_YHOUTA ) ; +#endif + RamWrite32A( FRA_DMA_OutputData, HALL_FRA_YHOUTB ) ; + } +#ifdef SEL_CLOSED_AF + else if( UcDirSel == Z_DIR ){ + SetTransDataAdr124( SinWave_OutAddr , (UINT32)CLAF_RAMA_AFSINE ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address +#ifdef CLOSED_RESPONSE + RamWrite32A( FRA_DMA_InputData, CLAF_RAMA_AFSINE ) ; +#else + RamWrite32A( FRA_DMA_InputData, CLAF_DELAY_AFDZ0 ) ; +#endif + RamWrite32A( FRA_DMA_OutputData, CLAF_RAMA_AFDEV ) ; + } +#endif // SEL_CLOSED_AF + } + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + + + CoeffGenerate( StFRAParam.StHostCom.SfFrqCom.SfFltVal ); +// WitTim(10); + // Start to measure + RamWrite32A( FRA_DMA_Control,1 ) ; + + if (nDivision == 0) WitTim(100); + if (nDivision == 1) WitTim(200); + if (nDivision == 2) WitTim(400); + if (nDivision == 3) WitTim(800); + if (nDivision == 4) WitTim(1600); + do{ + WitTim(10); + RamRead32A( FRA_DMA_Control , &UlReadVal ) ; + }while (UlReadVal == 1); + // Read answer + RamRead32A( FRA_DMA_Gain , &GainQ23 ) ; // Gain + RamRead32A( FRA_DMA_Phase , &PhaseQ21 ) ; // Phase + StFRAParam.StMesRslt.SfGainAvg = (float)GainQ23 / Q23; //0x007FFFFF; + StFRAParam.StMesRslt.SfPhaseAvg = (float)PhaseQ21 / Q21; //0x001FFFFF; + + TRACE("Phase %f deg : Gain %f dB\n", StFRAParam.StMesRslt.SfPhaseAvg, StFRAParam.StMesRslt.SfGainAvg ); + +} + + + +//******************************************************************************** +// Function Name : MesStart_FRA_Continue +// Retun Value : NON +// Argment Value : NON +// Explanation : Continue Measurement Function +// History : First edition +//******************************************************************************** +void MesStart_FRA_Continue( void ) +{ + INT32 GainQ23, PhaseQ21 ; + UINT32 UlReadVal ; + + // Change Frequency + RamWrite32A( SinWave_Offset, Freq_Convert( StFRAParam.StHostCom.SfFrqCom.SfFltVal ) ) ; + // Set parameter + CoeffGenerate( StFRAParam.StHostCom.SfFrqCom.SfFltVal ); +// WitTim(10) + // Start to measure + RamWrite32A( FRA_DMA_Control,1 ) ; // Integral Value Clear + if (nDivision == 0) WitTim(100); + if (nDivision == 1) WitTim(200); + if (nDivision == 2) WitTim(400); + if (nDivision == 3) WitTim(800); + if (nDivision == 4) WitTim(1600); + do{ + WitTim(10); + RamRead32A( FRA_DMA_Control , &UlReadVal ) ; + }while (UlReadVal == 1); + // Read answer + RamRead32A( FRA_DMA_Gain , &GainQ23 ) ; // Gain + RamRead32A( FRA_DMA_Phase , &PhaseQ21 ) ; // Phase + StFRAParam.StMesRslt.SfGainAvg = (float)GainQ23 / Q23; + StFRAParam.StMesRslt.SfPhaseAvg = (float)PhaseQ21 / Q21; + + TRACE("Phase %f deg : Gain %f dB\n", StFRAParam.StMesRslt.SfPhaseAvg, StFRAParam.StMesRslt.SfGainAvg ); +} + + + +//******************************************************************************** +// Function Name : MesEnd_FRA_Sweep +// Retun Value : NON +// Argment Value : NON +// Explanation : Stop Measurement Function +// History : First edition +//******************************************************************************** +void MesEnd_FRA_Sweep( void ) +{ + // Stop Sine Wave + RamWrite32A( SinWaveC_Regsiter, 0x00000000 ) ; // Sine Wave Stop + SetTransDataAdr124( SinWave_OutAddr, ( UINT32 )0x00000000 ) ; // Set Sine Wave Input RAM + + if ( StFRAParam.StHostCom.UcAvgCycl == 10) { // Actuator Through +#ifdef ACT_THROUGH_CLOSE + ResetThroughParameter( ); +#else + RtnCen124( BOTH_ON ) ; +#endif + } + RamWrite32A( HALL_RAM_SINDX0, 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_RAM_SINDY0, 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_FRA_XSININ, 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_FRA_YSININ, 0x00000000 ) ; // DelayRam Clear + +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisFRA.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisFRA.h new file mode 100644 index 0000000000000000000000000000000000000000..0bef3ccdfec16f39539d4279b45e82058d89b47e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisFRA.h @@ -0,0 +1,62 @@ +/** + * @brief FRA measurement header for LC898123 F40 + * API List for customers + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file OisAPI.h + * @date svn:$Date:: 2016-04-28 14:30:21 +0900#$ + * @version svn:$Revision: 43 $ + * @attention + **/ +#ifndef OISFRA_H_ +#define OISFRA_H_ + +//**************************************************** +// extern selector for API +//**************************************************** +#ifdef __OISFRA__ + #define __OIS_FRA_HEADER__ +#else + #define __OIS_FRA_HEADER__ extern +#endif + +typedef struct STFRA_PARAM { + struct { + UnFltVal SfFrqCom ; + UnFltVal SfAmpCom ; + unsigned char UcAvgCycl ; + } StHostCom ; + + float SfGain[ 10 ] ; + float SfPhase[ 10 ] ; + + struct { + float SfGainAvg ; + float SfPhaseAvg ; + } StMesRslt ; +} StFRAParam_t ; + +__OIS_FRA_HEADER__ StFRAParam_t StFRAParam ; +/* +typedef struct STFRA_MES { + UINT_64 UllCumulAdd1 ; + UINT_64 UllCumulAdd2 ; + UINT_16 UsFsCount ; +} StFRAMes_t ; + +__OIS_FRA_HEADER__ StFRAMes_t StFRAMes ; + +typedef struct { + INT_32 a1 ; + INT_32 b1 ; + INT_32 c1 ; + INT_32 a2 ; + INT_32 b2 ; + INT_32 c2 ; +} StMesFCoeff_t ; + +*/ + + +#endif // OISFRA_H_ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisLc898124EP3.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisLc898124EP3.h new file mode 100755 index 0000000000000000000000000000000000000000..377da3c61afd3fb527e653df50e28fa833690904 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/OisLc898124EP3.h @@ -0,0 +1,897 @@ +//******************************************************************************** +// +// << LC898124EP3 Evaluation Soft>> +// Program Name : OisLC898124EP1.h +// Explanation : LC898124 Global Declaration & ProtType Declaration +// Design : K.abe +// History : First edition +//******************************************************************************** +/************************************************/ +/* Command */ +/************************************************/ +#define CMD_IO_ADR_ACCESS 0xC000 // IO Write Access +#define CMD_IO_DAT_ACCESS 0xD000 // IO Read Access +#define CMD_REMAP 0xF001 // Remap +#define CMD_REBOOT 0xF003 // Reboot +#define CMD_ROMVER 0xF00F // Rom code version read + #define OLD_VER 0x20161121 + #define CUR_VER 0x20170410 +#define CMD_RETURN_TO_CENTER 0xF010 // Center Servo ON/OFF choose axis + #define BOTH_SRV_OFF 0x00000000 // Both Servo OFF + #define XAXS_SRV_ON 0x00000001 // X axis Servo ON + #define YAXS_SRV_ON 0x00000002 // Y axis Servo ON + #define BOTH_SRV_ON 0x00000003 // Both Servo ON + #define ZAXS_SRV_OFF 0x00000004 // Z axis Servo OFF + #define ZAXS_SRV_ON 0x00000005 // Z axis Servo ON +#define CMD_PAN_TILT 0xF011 // Pan Tilt Enable/Disable + #define PAN_TILT_OFF 0x00000000 // Pan/Tilt OFF + #define PAN_TILT_ON 0x00000001 // Pan/Tilt ON +#define CMD_OIS_ENABLE 0xF012 // Ois Enable/Disable + #define OIS_DISABLE 0x00000000 // OIS Disable + #define OIS_ENABLE 0x00000001 // OIS Enable + #define OIS_ENA_NCL 0x00000002 // OIS Enable ( none Delay clear ) + #define OIS_ENA_DOF 0x00000004 // OIS Enable ( Drift offset exec ) +#define CMD_MOVE_STILL_MODE 0xF013 // Select mode + #define MOVIE_MODE 0x00000000 // Movie mode + #define STILL_MODE 0x00000001 // Still mode + #define MOVIE_MODE1 0x00000002 // Movie Preview mode 1 + #define STILL_MODE1 0x00000003 // Still Preview mode 1 + #define MOVIE_MODE2 0x00000004 // Movie Preview mode 2 + #define STILL_MODE2 0x00000005 // Still Preview mode 2 + #define MOVIE_MODE3 0x00000006 // Movie Preview mode 3 + #define STILL_MODE3 0x00000007 // Still Preview mode 3 +#define CMD_CHASE_CONFIRMATION 0xF015 // Hall Chase confirmation +#define CMD_GYRO_SIG_CONFIRMATION 0xF016 // Gyro Signal confirmation +#define CMD_FLASH_LOAD 0xF017 // Flash Load + #define HALL_CALB_FLG 0x00008000 + #define HALL_CALB_BIT 0x00FF00FF + #define GYRO_GAIN_FLG 0x00004000 + #define ANGL_CORR_FLG 0x00002000 + #define FOCL_GAIN_FLG 0x00001000 + #define ZSRV_CAL_FLG 0x00000800 // ZeroServo calibration data + #define HLLN_CALB_FLG 0x00000400 // Hall linear calibration + #define MIXI_CALB_FLG 0x00000200 // Mixing calibration + #define CROS_TALK_FLG 0x00000200 //!< Cross talk calibration +#define CMD_LASER_LINEAR_DATA 0xF019 +#define CMD_AF_POSITION 0xF01A // AF Position +#define CMD_SSC_ENABLE 0xF01C //!< Select mode + #define SSC_DISABLE 0x00000000 //!< Ssc Disable + #define SSC_ENABLE 0x00000001 //!< Ssc Enable +#define CMD_GYRO_RD_ACCS 0xF01D // Gyro Read Acess +#define CMD_GYRO_WR_ACCS 0xF01E // Gyro Write Acess + +#define CMD_READ_STATUS 0xF100 // Status Read + #define READ_STATUS_INI 0x01000000 + +#define CMD_ZSRV_MODE 0xF01F + #define ZSRV_DISABLE 0x00000000 + #define ZSRV_ENABLE 0x00000001 + #define ZSRV_HOLD 0x00000003 + +#define OIS_POS_FLG 0x00000100 // OIS position by AF measurement + +//============================================================================== +//E2PROM +//============================================================================== +#define EEPROM_ONSEMI_LDO 0x00 +#define EEPROM_ONSEMI_CP1 0x01 +#define EEPROM_ONSEMI_CP2 0x02 +#define EEPROM_ONSEMI_CP3 0x03 +#define EEPROM_ONSEMI_OSCS 0x04 +#define EEPROM_ONSEMI_DRVGAINAF 0x05 +#define EEPROM_ONSEMI_DRVOFSTAF 0x06 +#define EEPROM_ONSEMI_DRVOFSTAFM 0x07 +#define EEPROM_ONSEMI_DRVGAINX 0x08 +#define EEPROM_ONSEMI_DRVOFSTX 0x09 +#define EEPROM_ONSEMI_DRVOFSTXM 0x0A +#define EEPROM_ONSEMI_DRVGAINY 0x0B +#define EEPROM_ONSEMI_DRVOFSTY 0x0C +#define EEPROM_ONSEMI_DRVOFSTYM 0x0D +#define EEPROM_ONSEMI_MARK 0x0E +#define EEPROM_ONSEMI_CHECKSUM 0x0F /* target area 0x00~0x0E */ + +#define EEPROM_ONSEMI_IDSEL 0x10 +#define EEPROM_DrvZdir 0x11 +#define EEPROM_AfUcoef_LSB 0x12 +#define EEPROM_AfUcoef_MSB 0x13 +#define EEPROM_AfDcoef_LSB 0x14 +#define EEPROM_AfDcoef_MSB 0x15 +#define EEPROM_AfFrq_LSB 0x16 +#define EEPROM_AfFrq_MSB 0x17 + +#define EEPROM_Calibration_Status_LSB 0x18 +#define EEPROM_Calibration_Status_MSB 0x19 +#define EEPROM_Calibration_HallMaxX_LSB 0x1A +#define EEPROM_Calibration_HallMaxX_MSB 0x1B +#define EEPROM_Calibration_HallMinX_LSB 0x1C +#define EEPROM_Calibration_HallMinX_MSB 0x1D +#define EEPROM_Calibration_HallMaxY_LSB 0x1E +#define EEPROM_Calibration_HallMaxY_MSB 0x1F + +#define EEPROM_Calibration_HallMinY_LSB 0x20 +#define EEPROM_Calibration_HallMinY_MSB 0x21 +#define EEPROM_Calibration_HallBiasX 0x22 +#define EEPROM_Calibration_HallOffsetX 0x23 +#define EEPROM_Calibration_HallBiasY 0x24 +#define EEPROM_Calibration_HallOffsetY 0x25 +#define EEPROM_Calibration_LoopGainX_LSB 0x26 +#define EEPROM_Calibration_LoopGainX_MSB 0x27 + +#define EEPROM_Calibration_LoopGainY_LSB 0x28 +#define EEPROM_Calibration_LoopGainY_MSB 0x29 +#define EEPROM_Calibration_LensOffsetX_LSB 0x2A +#define EEPROM_Calibration_LensOffsetX_MSB 0x2B +#define EEPROM_Calibration_LensOffsetY_LSB 0x2C +#define EEPROM_Calibration_LensOffsetY_MSB 0x2D + +#define EEPROM_Calibration_GyroGainX_0Byte 0x2E +#define EEPROM_Calibration_GyroGainX_1Byte 0x2F +#define EEPROM_Calibration_GyroGainX_2Byte 0x30 +#define EEPROM_Calibration_GyroGainX_3Byte 0x31 +#define EEPROM_Calibration_GyroGainY_0Byte 0x32 +#define EEPROM_Calibration_GyroGainY_1Byte 0x33 +#define EEPROM_Calibration_GyroGainY_2Byte 0x34 +#define EEPROM_Calibration_GyroGainY_3Byte 0x35 + +#if 0 +#define EEPROM_Calibration_ZSX_offset_0Byte 0x36 +#define EEPROM_Calibration_ZSX_offset_1Byte 0x37 +#define EEPROM_Calibration_ZSX_shift_0Byte 0x38 +#define EEPROM_Calibration_ZSX_shift_1Byte 0x39 +#define EEPROM_Calibration_ZSX_gcore_0Byte 0x3A +#define EEPROM_Calibration_ZSX_gcore_1Byte 0x3B +#define EEPROM_Calibration_ZSX_gaina_0Byte 0x3C +#define EEPROM_Calibration_ZSX_gaina_1Byte 0x3D + +#define EEPROM_Calibration_ZSY_offset_0Byte 0x3E +#define EEPROM_Calibration_ZSY_offset_1Byte 0x3F +#define EEPROM_Calibration_ZSY_shift_0Byte 0x40 +#define EEPROM_Calibration_ZSY_shift_1Byte 0x41 +#define EEPROM_Calibration_ZSY_gcore_0Byte 0x42 +#define EEPROM_Calibration_ZSY_gcore_1Byte 0x43 +#define EEPROM_Calibration_ZSY_gaina_0Byte 0x44 +#define EEPROM_Calibration_ZSY_gaina_1Byte 0x45 + +#define EEPROM_Calibration_ZSZ_offset_0Byte 0x46 +#define EEPROM_Calibration_ZSZ_offset_1Byte 0x47 +#endif + +#define EEPROM_POSITION_1X_LSB 0x48 +#define EEPROM_POSITION_1X_MSB 0x49 +#define EEPROM_POSITION_1Y_LSB 0x4A +#define EEPROM_POSITION_1Y_MSB 0x4B +#define EEPROM_POSITION_2X_LSB 0x4C +#define EEPROM_POSITION_2X_MSB 0x4D +#define EEPROM_POSITION_2Y_LSB 0x4E +#define EEPROM_POSITION_2Y_MSB 0x4F + +#define EEPROM_POSITION_3X_LSB 0x50 +#define EEPROM_POSITION_3X_MSB 0x51 +#define EEPROM_POSITION_3Y_LSB 0x52 +#define EEPROM_POSITION_3Y_MSB 0x53 +#define EEPROM_POSITION_4X_LSB 0x54 +#define EEPROM_POSITION_4X_MSB 0x55 +#define EEPROM_POSITION_4Y_LSB 0x56 +#define EEPROM_POSITION_4Y_MSB 0x57 + +#define EEPROM_POSITION_5X_LSB 0x58 +#define EEPROM_POSITION_5X_MSB 0x59 +#define EEPROM_POSITION_5Y_LSB 0x5A +#define EEPROM_POSITION_5Y_MSB 0x5B +#define EEPROM_POSITION_6X_LSB 0x5C +#define EEPROM_POSITION_6X_MSB 0x5D +#define EEPROM_POSITION_6Y_LSB 0x5E +#define EEPROM_POSITION_6Y_MSB 0x5F + +#define EEPROM_POSITION_7X_LSB 0x60 +#define EEPROM_POSITION_7X_MSB 0x61 +#define EEPROM_POSITION_7Y_LSB 0x62 +#define EEPROM_POSITION_7Y_MSB 0x63 +#define EEPROM_STEPX_0Byte 0x64 +#define EEPROM_STEPX_1Byte 0x65 +#define EEPROM_STEPY_0Byte 0x66 +#define EEPROM_STEPY_1Byte 0x67 + +#define EEPROM_CROSSTALK_XX_LSB 0x68 +#define EEPROM_CROSSTALK_XX_MSB 0x69 +#define EEPROM_CROSSTALK_XY_LSB 0x6A +#define EEPROM_CROSSTALK_XY_MSB 0x6B +#define EEPROM_CROSSTALK_YY_LSB 0x6C +#define EEPROM_CROSSTALK_YY_MSB 0x6D +#define EEPROM_CROSSTALK_YX_LSB 0x6E +#define EEPROM_CROSSTALK_YX_MSB 0x6F + +#define EEPROM_CROSSTALK_XSHIFT 0x70 +#define EEPROM_CROSSTALK_YSHIFT 0x71 + +#define EEPROM_Optical_LensOffsetX_LSB 0x72 +#define EEPROM_Optical_LensOffsetX_MSB 0x73 +#define EEPROM_Optical_LensOffsetY_LSB 0x74 +#define EEPROM_Optical_LensOffsetY_MSB 0x75 + +//////////////////////////////////////////////////// + +//#define EEPROM_Calibration_Reserve_78 0x78 +//#define EEPROM_Calibration_Reserve_79 0x79 +//#define EEPROM_Calibration_Reserve_7A 0x7A +//#define EEPROM_Calibration_Reserve_7B 0x7B +//#define EEPROM_Calibration_Reserve_7C 0x7C + +#define EEPROM_CheckSum 0x7D /* target area 0x10~0x7c */ +#define EEPROM_CheckCode1 0x7E +#define EEPROM_CheckCode2 0x7F + +//============================================================================== +//DMA +//============================================================================== + +#define DmCheck_CheckSumDMA 0x0100 +#define DmCheck_CheckSumDMB 0x0104 + +#define PmCheck 0x0108 +#define PmCheck_PmemAddr (0x0000 + PmCheck) // 0x0108 +#define PmCheck_Size (0x0004 + PmCheck_PmemAddr) // 0x010C +#define PmCheck_CheckSum (0x0004 + PmCheck_Size) // 0x0110 +#define PmCheck_EndFlag (0x0004 + PmCheck_CheckSum) // 0x0114 + +#define HallFilterD_HXDAZ1 0x0130 //0x0080 +#define HallFilterD_HYDAZ1 0x0180 //0x00D0 + +#define HALL_RAM_X_COMMON 0x01C0 //0x0110 +#define HALL_RAM_HXOFF (0x0000 + HALL_RAM_X_COMMON) // 0x01C0 +#define HALL_RAM_HXOFF1 (0x0004 + HALL_RAM_X_COMMON) // 0x01C4 +#define HALL_RAM_HXOUT0 (0x0008 + HALL_RAM_X_COMMON) // 0x01C8 +#define HALL_RAM_HXOUT1 (0x000C + HALL_RAM_X_COMMON) // 0x01CC +#define HALL_RAM_HXOUT2 (0x0010 + HALL_RAM_X_COMMON) // 0x01D0 +#define HALL_RAM_SINDX0 (0x0014 + HALL_RAM_X_COMMON) // 0x01D4 +#define HALL_RAM_HXLOP (0x0018 + HALL_RAM_X_COMMON) // 0x01D8 +#define HALL_RAM_SINDX1 (0x001C + HALL_RAM_X_COMMON) // 0x01DC +#define HALL_RAM_HALL_X_OUT (0x0020 + HALL_RAM_X_COMMON) // 0x01E0 +#define HALL_RAM_HALL_SwitchX 0x0210 //0x015c + +#define HALL_RAM_Y_COMMON 0x0214 //0x0160 +#define HALL_RAM_HYOFF (0x0000 + HALL_RAM_Y_COMMON) // 0x0214 +#define HALL_RAM_HYOFF1 (0x0004 + HALL_RAM_Y_COMMON) // 0x0218 +#define HALL_RAM_HYOUT0 (0x0008 + HALL_RAM_Y_COMMON) // 0x021C +#define HALL_RAM_HYOUT1 (0x000C + HALL_RAM_Y_COMMON) // 0x0220 +#define HALL_RAM_HYOUT2 (0x0010 + HALL_RAM_Y_COMMON) // 0x0224 +#define HALL_RAM_SINDY0 (0x0014 + HALL_RAM_Y_COMMON) // 0x0228 +#define HALL_RAM_HYLOP (0x0018 + HALL_RAM_Y_COMMON) // 0x022C +#define HALL_RAM_SINDY1 (0x001C + HALL_RAM_Y_COMMON) // 0x0230 +#define HALL_RAM_HALL_Y_OUT (0x0020 + HALL_RAM_Y_COMMON) // 0x0234 +#define HALL_RAM_HALL_SwitchY 0x0264 //0x01AC + + +#define HALL_RAM_COMMON 0x0268 //0x01B0 + // HallFilterDelay.h HALL_RAM_COMMON_t +#define HALL_RAM_HXIDAT (0x0000 + HALL_RAM_COMMON) // 0x0268 +#define HALL_RAM_HYIDAT (0x0004 + HALL_RAM_COMMON) // 0x026C +#define HALL_RAM_GYROX_OUT (0x0008 + HALL_RAM_COMMON) // 0x0270 +#define HALL_RAM_GYROY_OUT (0x000C + HALL_RAM_COMMON) // 0x0274 + +#define GyroFilterDelayX_delay2 0x278 +#define GyroFilterDelayX_delay3 0x288 //0x1D0 +#define GyroFilterDelayX_GXH1Z1 (0x0000 + GyroFilterDelayX_delay3) // 0x0288 +#define GyroFilterDelayX_GXH1Z2 (0x0004 + GyroFilterDelayX_delay3) // 0x028C +#define GyroFilterDelayX_GXK1Z1 (0x0008 + GyroFilterDelayX_delay3) // 0x0290 +#define GyroFilterDelayX_GXK1Z2 (0x000C + GyroFilterDelayX_delay3) // 0x0294 +#define GyroFilterDelayX_delay4 0x298 + +#define GyroFilterDelayY_delay2 0x2A0 +#define GyroFilterDelayY_delay3 0x2B0 //0x1F8 +#define GyroFilterDelayY_GYH1Z1 (0x0000 + GyroFilterDelayY_delay3) // 0x02B0 +#define GyroFilterDelayY_GYH1Z2 (0x0004 + GyroFilterDelayY_delay3) // 0x02B4 +#define GyroFilterDelayY_GYK1Z1 (0x0008 + GyroFilterDelayY_delay3) // 0x02B8 +#define GyroFilterDelayY_GYK1Z2 (0x000C + GyroFilterDelayY_delay3) // 0x02BC +#define GyroFilterDelayY_delay4 0x2C0 + +#define GYRO_RAM_X 0x02C8 //0x0210 + // GyroFilterDelay.h GYRO_RAM_t +#define GYRO_RAM_GYROX_OFFSET (0x0000 + GYRO_RAM_X) // 0x02C8 +#define GYRO_RAM_GX2X4XF_IN (0x0004 + GYRO_RAM_GYROX_OFFSET) // 0x02CC +#define GYRO_RAM_GX2X4XF_OUT (0x0004 + GYRO_RAM_GX2X4XF_IN) // 0x02D0 +#define GYRO_RAM_GXFAST (0x0004 + GYRO_RAM_GX2X4XF_OUT) // 0x02D4 +#define GYRO_RAM_GXSLOW (0x0004 + GYRO_RAM_GXFAST) // 0x02D8 +#define GYRO_RAM_GYROX_G1OUT (0x0004 + GYRO_RAM_GXSLOW) // 0x02DC +#define GYRO_RAM_GYROX_G2OUT (0x0004 + GYRO_RAM_GYROX_G1OUT) // 0x02E0 +#define GYRO_RAM_GYROX_G3OUT (0x0004 + GYRO_RAM_GYROX_G2OUT) // 0x02E4 +#define GYRO_RAM_GYROX_OUT (0x0004 + GYRO_RAM_GYROX_G3OUT) // 0x02E8 +#define GYRO_RAM_Y 0x02EC //0x0234 + // GyroFilterDelay.h GYRO_RAM_t +#define GYRO_RAM_GYROY_OFFSET (0x0000 + GYRO_RAM_Y) // 0x02EC +#define GYRO_RAM_GY2X4XF_IN (0x0004 + GYRO_RAM_GYROY_OFFSET) // 0x02F0 +#define GYRO_RAM_GY2X4XF_OUT (0x0004 + GYRO_RAM_GY2X4XF_IN) // 0x02F4 +#define GYRO_RAM_GYFAST (0x0004 + GYRO_RAM_GY2X4XF_OUT) // 0x02F8 +#define GYRO_RAM_GYSLOW (0x0004 + GYRO_RAM_GYFAST) // 0x02FC +#define GYRO_RAM_GYROY_G1OUT (0x0004 + GYRO_RAM_GYSLOW) // 0x0300 +#define GYRO_RAM_GYROY_G2OUT (0x0004 + GYRO_RAM_GYROY_G1OUT) // 0x0304 +#define GYRO_RAM_GYROY_G3OUT (0x0004 + GYRO_RAM_GYROY_G2OUT) // 0x0308 +#define GYRO_RAM_GYROY_OUT (0x0004 + GYRO_RAM_GYROY_G3OUT) // 0x030C + +#define GYRO_RAM_COMMON 0x0310 //0x0258 + // GyroFilterDelay.h GYRO_RAM_COMMON_t +#define GYRO_RAM_GX_ADIDAT (0x0000 + GYRO_RAM_COMMON) // 0x0310 +#define GYRO_RAM_GY_ADIDAT (0x0004 + GYRO_RAM_GX_ADIDAT) // 0x0314 +#define GYRO_RAM_GZ_ADIDAT (0x0004 + GYRO_RAM_GY_ADIDAT) // 0x0318 +#define GYRO_RAM_SINDX (0x0004 + GYRO_RAM_GZ_ADIDAT) // 0x031C +#define GYRO_RAM_SINDY (0x0004 + GYRO_RAM_SINDX) // 0x0320 +#define GYRO_RAM_GXLENSZ (0x0004 + GYRO_RAM_SINDY) // 0x0324 +#define GYRO_RAM_GYLENSZ (0x0004 + GYRO_RAM_GXLENSZ) // 0x0328 +#define GYRO_RAM_GZLENSZ (0x0004 + GYRO_RAM_GYLENSZ) // 0x032C +#define GYRO_RAM_GXOX_OUT (0x0004 + GYRO_RAM_GZLENSZ) // 0x0330 +#define GYRO_RAM_GYOX_OUT (0x0004 + GYRO_RAM_GXOX_OUT) // 0x0334 +#define GYRO_RAM_GXOFFZ (0x0004 + GYRO_RAM_GYOX_OUT) // 0x0338 +#define GYRO_RAM_GYOFFZ (0x0004 + GYRO_RAM_GXOFFZ) // 0x033C +#define GYRO_RAM_GZOFFZ (0x0004 + GYRO_RAM_GYOFFZ) // 0x0340 +#define GYRO_RAM_LIMITX (0x0004 + GYRO_RAM_GZOFFZ) // 0x0344 +#define GYRO_RAM_LIMITY (0x0004 + GYRO_RAM_LIMITX) // 0x0348 +#define GYRO_RAM_LIMITZ (0x0004 + GYRO_RAM_LIMITY) // 0x034C +#define GXFILIN (0x0004 + GYRO_RAM_LIMITZ) // 0x0350 +#define GYFILIN (0x0004 + GXFILIN) // 0x0354 +#define GZFILIN (0x0004 + GYFILIN) // 0x0358 +#define GYRO_RAM_GYRO_Switch (0x0004 + GZFILIN) // 0x035C +#define GYRO_RAM_GYRO_AF_Switch (0x0001 + GYRO_RAM_GYRO_Switch) // 0x035D + +//#ifdef ZERO_SERVO +#define ZeroServoRAM_X 0x03A8 +#define ZeroServoRAM_X_OFFSET (0x0000 + ZeroServoRAM_X) // 0x03A8 +#define ZeroServoRAM_X_IN (0x0004 + ZeroServoRAM_X_OFFSET) // 0x03AC +#define ZeroServoRAM_X_LPFIN (0x0004 + ZeroServoRAM_X_IN ) // 0x03B0 +#define ZeroServoRAM_X_LPFOUT (0x0004 + ZeroServoRAM_X_LPFIN) // 0x03B4 +#define ZeroServoRAM_X_ANGOUT (0x0004 + ZeroServoRAM_X_LPFOUT) // 0x03B8 +#define ZeroServoRAM_X_OUT (0x0004 + ZeroServoRAM_X_ANGOUT) // 0x03BC +#define ZeroServoRAM_Y 0x03C0 +#define ZeroServoRAM_Y_OFFSET (0x0000 + ZeroServoRAM_Y) // 0x03C0 +#define ZeroServoRAM_Y_IN (0x0004 + ZeroServoRAM_Y_OFFSET) // 0x03C4 +#define ZeroServoRAM_Y_LPFIN (0x0004 + ZeroServoRAM_Y_IN ) // 0x03C8 +#define ZeroServoRAM_Y_LPFOUT (0x0004 + ZeroServoRAM_Y_LPFIN) // 0x03CC +#define ZeroServoRAM_Y_ANGOUT (0x0004 + ZeroServoRAM_Y_LPFOUT) // 0x03D0 +#define ZeroServoRAM_Y_OUT (0x0004 + ZeroServoRAM_Y_ANGOUT) // 0x03D4 +#define ZeroServoRAM_Z 0x03D8 +#define ZeroServoRAM_Z_OFFSET (0x0000 + ZeroServoRAM_Z) // 0x03D8 +#define ZeroServoRAM_Z_IN (0x0004 + ZeroServoRAM_Z_OFFSET) // 0x03DC +#define ZeroServoRAM_Z_LPFIN (0x0004 + ZeroServoRAM_Z_IN ) // 0x03E0 +#define ZeroServoRAM_Z_LPFOUT (0x0004 + ZeroServoRAM_Z_LPFIN) // 0x03E4 +#define ZeroServoRAM_Z_ANGOUT (0x0004 + ZeroServoRAM_Z_LPFOUT) // 0x03E8 +#define ZeroServoRAM_Z_OUT (0x0004 + ZeroServoRAM_Z_ANGOUT) // 0x03EC +//#endif //ZERO_SERVO + +#define StMeasureFunc 0x0400 //0x02B0 +#define StMeasFunc_SiSampleNum (0x0000 + StMeasureFunc ) // 0x0400 +#define StMeasFunc_SiSampleMax (0x0004 + StMeasFunc_SiSampleNum) // 0x0404 + +#define StMeasureFunc_MFA 0x0408 //0x02B8 +#define StMeasFunc_MFA_SiMax1 (0x0000 + StMeasureFunc_MFA ) // 0x0408 +#define StMeasFunc_MFA_SiMin1 (0x0004 + StMeasFunc_MFA_SiMax1 ) // 0x040C +#define StMeasFunc_MFA_UiAmp1 (0x0004 + StMeasFunc_MFA_SiMin1 ) // 0x0410 +#define StMeasFunc_MFA_UiDUMMY1 (0x0004 + StMeasFunc_MFA_UiAmp1 ) // 0x0414 +#define StMeasFunc_MFA_LLiIntegral1 (0x0004 + StMeasFunc_MFA_UiDUMMY1) // 0x0418 // 8Byte +#define StMeasFunc_MFA_LLiAbsInteg1 (0x0008 + StMeasFunc_MFA_LLiIntegral1) // 0x0420 // 8Byte +#define StMeasFunc_MFA_PiMeasureRam1 (0x0008 + StMeasFunc_MFA_LLiAbsInteg1) // 0x0428 +#define StMeasFunc_MFA_UiDUMMY2 (0x0004 + StMeasFunc_MFA_PiMeasureRam1) // 0x042C + +#define StMeasureFunc_MFB 0x0430 //0x02E0 +#define StMeasFunc_MFB_SiMax2 (0x0000 + StMeasureFunc_MFB ) // 0x0430 +#define StMeasFunc_MFB_SiMin2 (0x0004 + StMeasFunc_MFB_SiMax2 ) // 0x0434 +#define StMeasFunc_MFB_UiAmp2 (0x0004 + StMeasFunc_MFB_SiMin2 ) // 0x0438 +#define StMeasFunc_MFB_UiDUMMY1 (0x0004 + StMeasFunc_MFB_UiAmp2 ) // 0x043C +#define StMeasFunc_MFB_LLiIntegral2 (0x0004 + StMeasFunc_MFB_UiDUMMY1 ) // 0x0440 // 8Byte +#define StMeasFunc_MFB_LLiAbsInteg2 (0x0008 + StMeasFunc_MFB_LLiIntegral2) // 0x0448 // 8Byte +#define StMeasFunc_MFB_PiMeasureRam2 (0x0008 + StMeasFunc_MFB_LLiAbsInteg2) // 0x0450 + +#define MeasureFilterA_Delay 0x0458 //0x0308 + // MeasureFilter.h MeasureFilter_Delay_Type +#define MeasureFilterA_Delay_z11 (0x0000 + MeasureFilterA_Delay) // 0x0458 +#define MeasureFilterA_Delay_z12 (0x0004 + MeasureFilterA_Delay_z11) // 0x045C +#define MeasureFilterA_Delay_z21 (0x0004 + MeasureFilterA_Delay_z12) // 0x0460 +#define MeasureFilterA_Delay_z22 (0x0004 + MeasureFilterA_Delay_z21) // 0x0464 + +#define MeasureFilterB_Delay 0x0468 //0x0318 + // MeasureFilter.h MeasureFilter_Delay_Type +#define MeasureFilterB_Delay_z11 (0x0000 + MeasureFilterB_Delay) // 0x0468 +#define MeasureFilterB_Delay_z12 (0x0004 + MeasureFilterB_Delay_z11) // 0x046C +#define MeasureFilterB_Delay_z21 (0x0004 + MeasureFilterB_Delay_z12) // 0x0470 +#define MeasureFilterB_Delay_z22 (0x0004 + MeasureFilterB_Delay_z21) // 0x0474 + +#define SinWaveC 0x0478 //0x0328 +#define SinWaveC_Pt (0x0000 + SinWaveC) // 0x0478 +#define SinWaveC_Regsiter (0x0004 + SinWaveC_Pt) // 0x047C +#define SinWaveC_SignFlag (0x0004 + SinWaveC_Regsiter) // 0x0480 + +#define SinWave 0x0484 //0x0334 + // SinGenerator.h SinWave_t +#define SinWave_Offset (0x0000 + SinWave) // 0x0484 +#define SinWave_Phase (0x0004 + SinWave_Offset) // 0x0488 +#define SinWave_Gain (0x0004 + SinWave_Phase) // 0x048C +#define SinWave_Output (0x0004 + SinWave_Gain) // 0x0490 +#define SinWave_OutAddr (0x0004 + SinWave_Output) // 0x0494 +#define CosWave 0x0498 //0x0348 + // SinGenerator.h SinWave_t +#define CosWave_Offset (0x0000 + CosWave) // 0x0498 +#define CosWave_Phase (0x0004 + CosWave_Offset) // 0x049C +#define CosWave_Gain (0x0004 + CosWave_Phase) // 0x04A0 +#define CosWave_Output (0x0004 + CosWave_Gain) // 0x04A4 +#define CosWave_OutAddr (0x0004 + CosWave_Output) // 0x04A8 + +#define WaitTimerData 0x04AC //0x035C + // CommonLibrary.h WaitTimer_Type +#define WaitTimerData_UiWaitCounter (0x0000 + WaitTimerData ) // 0x04AC +#define WaitTimerData_UiTargetCount (0x0004 + WaitTimerData_UiWaitCounter) // 0x04B0 +#define WaitTimerData_UiBaseCount (0x0004 + WaitTimerData_UiTargetCount) // 0x04B4 + +#define PanTilt_DMA_ScTpdSts 0x04CC //0x037C + + + +#define StPosition 0x054C + // StPosition[8] +#define StPosition_0 (0x0000 + StPosition ) // 0x054C +#define StPosition_1 (0x0004 + StPosition ) // 0x0550 +#define StPosition_2 (0x0008 + StPosition ) // 0x0554 +#define StPosition_3 (0x000C + StPosition ) // 0x0558 +#define StPosition_4 (0x0010 + StPosition ) // 0x055C +#define StPosition_5 (0x0014 + StPosition ) // 0x0560 +#define StPosition_6 (0x0018 + StPosition ) // 0x0564 +#define SiStepXY (0x001C + StPosition ) // 0x0568 + +#define Optical_Offset 0x056C +#define Optical_Offset_X (0x0000 + Optical_Offset ) // 0x056C +#define Optical_Offset_Y (0x0004 + Optical_Offset ) // 0x0570 + +#define GYRO_RAM_Z 0x0618 //0x0618 +#define GYRO_RAM_GYROZ_OFFSET (0x0000 + GYRO_RAM_Z) // 0x0618 + +#define GyroTemp 0x063C + +#define AcclFilDly_X 0x0640 +#define AcclFilDly_Y 0x0670 +#define AcclFilDly_Z 0x06A0 + +#define AcclRAM_X 0x06D0 +#define ACCLRAM_X_AC_ADIDAT 0x0000 + AcclRAM_X +#define ACCLRAM_X_AC_OFFSET 0x0004 + AcclRAM_X + +#define AcclRAM_Y 0x06FC +#define ACCLRAM_Y_AC_ADIDAT 0x0000 + AcclRAM_Y +#define ACCLRAM_Y_AC_OFFSET 0x0004 + AcclRAM_Y + +#define AcclRAM_Z 0x0728 +#define ACCLRAM_Z_AC_ADIDAT 0x0000 + AcclRAM_Z +#define ACCLRAM_Z_AC_OFFSET 0x0004 + AcclRAM_Z + + +#define FRA_DMA (0x278) +#define FRA_DMA_Control (0x04 + FRA_DMA ) +//#define FRA_DMA_DeciCount (0x0C + FRA_DMA ) +#define FRA_DMA_DeciShift (0x10 + FRA_DMA ) +#define FRA_DMA_InputData (0x18 + FRA_DMA ) +#define FRA_DMA_OutputData (0x1C + FRA_DMA ) + +#define FRA_DMA_Gain (0x70 + FRA_DMA ) +#define FRA_DMA_Phase (0x74 + FRA_DMA ) + +#define HALL_FRA_X_COMMON 0x0574 +#define HALL_FRA_XSININ 0x0000 + HALL_FRA_X_COMMON +#define HALL_FRA_XHOUTB 0x0004 + HALL_FRA_XSININ +#define HALL_FRA_XHOUTA 0x0004 + HALL_FRA_XHOUTB + +#define HALL_FRA_Y_COMMON 0x0580 +#define HALL_FRA_YSININ 0x0000 + HALL_FRA_Y_COMMON +#define HALL_FRA_YHOUTB 0x0004 + HALL_FRA_YSININ +#define HALL_FRA_YHOUTA 0x0004 + HALL_FRA_YHOUTB + + + +//============================================================================== +//DMB +//============================================================================== +#define SiVerNum 0x8000 + #define SPI_MST 0x00 + #define SPI_SLV 0x01 + #define SPI_SNGL 0x02 + + #define ACT_SO2821 0x00 // SEMCO SO2821 + #define ACT_M12337_A1 0x01 // JAHWA M12337 + + #define ACT_45DEG 0xff // dummy + + #define GYRO_ICM20690 0x00 + #define GYRO_LSM6DSM 0x02 + +#define StCalibrationData 0x8010 + // Calibration.h CalibrationData_Type +#define StCaliData_UsCalibrationStatus (0x0000 + StCalibrationData) +#define StCaliData_SiHallMax_Before_X (0x0004 + StCaliData_UsCalibrationStatus) +#define StCaliData_SiHallMin_Before_X (0x0004 + StCaliData_SiHallMax_Before_X) +#define StCaliData_SiHallMax_After_X (0x0004 + StCaliData_SiHallMin_Before_X) +#define StCaliData_SiHallMin_After_X (0x0004 + StCaliData_SiHallMax_After_X) +#define StCaliData_SiHallMax_Before_Y (0x0004 + StCaliData_SiHallMin_After_X) +#define StCaliData_SiHallMin_Before_Y (0x0004 + StCaliData_SiHallMax_Before_Y) +#define StCaliData_SiHallMax_After_Y (0x0004 + StCaliData_SiHallMin_Before_Y) +#define StCaliData_SiHallMin_After_Y (0x0004 + StCaliData_SiHallMax_After_Y) +#define StCaliData_UiHallBias_X (0x0004 + StCaliData_SiHallMin_After_Y) +#define StCaliData_UiHallOffset_X (0x0004 + StCaliData_UiHallBias_X) +#define StCaliData_UiHallBias_Y (0x0004 + StCaliData_UiHallOffset_X) +#define StCaliData_UiHallOffset_Y (0x0004 + StCaliData_UiHallBias_Y) +#define StCaliData_SiLoopGain_X (0x0004 + StCaliData_UiHallOffset_Y) +#define StCaliData_SiLoopGain_Y (0x0004 + StCaliData_SiLoopGain_X) +#define StCaliData_SiLensCen_Offset_X (0x0004 + StCaliData_SiLoopGain_Y) +#define StCaliData_SiLensCen_Offset_Y (0x0004 + StCaliData_SiLensCen_Offset_X) +#define StCaliData_SiOtpCen_Offset_X (0x0004 + StCaliData_SiLensCen_Offset_Y) +#define StCaliData_SiOtpCen_Offset_Y (0x0004 + StCaliData_SiOtpCen_Offset_X) +#define StCaliData_SiGyroOffset_X (0x0004 + StCaliData_SiOtpCen_Offset_Y) +#define StCaliData_SiGyroOffset_Y (0x0004 + StCaliData_SiGyroOffset_X) +#define StCaliData_SiGyroGain_X (0x0004 + StCaliData_SiGyroOffset_Y) +#define StCaliData_SiGyroGain_Y (0x0004 + StCaliData_SiGyroGain_X) +#define StCaliData_UiHallBias_AF (0x0004 + StCaliData_SiGyroGain_Y) +#define StCaliData_UiHallOffset_AF (0x0004 + StCaliData_UiHallBias_AF) +#define StCaliData_SiLoopGain_AF (0x0004 + StCaliData_UiHallOffset_AF) +#define StCaliData_SiAD_Offset_AF (0x0004 + StCaliData_SiLoopGain_AF) +#define StCaliData_SiMagnification_AF (0x0004 + StCaliData_SiAD_Offset_AF) +#define StCaliData_SiHallMax_Before_AF (0x0004 + StCaliData_SiMagnification_AF) +#define StCaliData_SiHallMin_Before_AF (0x0004 + StCaliData_SiHallMax_Before_AF) +#define StCaliData_SiHallMax_After_AF (0x0004 + StCaliData_SiHallMin_Before_AF) +#define StCaliData_SiHallMin_After_AF (0x0004 + StCaliData_SiHallMax_After_AF) + +#define HallFilterCoeffX 0x8090 + // HallFilterCoeff.h DM_HFC_t +#define HallFilterCoeffX_HXIGAIN (0x0000 + HallFilterCoeffX) +#define HallFilterCoeffX_GYROXOUTGAIN (0x0004 + HallFilterCoeffX_HXIGAIN) +#define HallFilterCoeffX_HXOFFGAIN (0x0004 + HallFilterCoeffX_GYROXOUTGAIN) + +#define HallFilterCoeffX_hxiab (0x0004 + HallFilterCoeffX_HXOFFGAIN) +#define HallFilterCoeffX_hxiac (0x0004 + HallFilterCoeffX_hxiab) +#define HallFilterCoeffX_hxiaa (0x0004 + HallFilterCoeffX_hxiac) +#define HallFilterCoeffX_hxibb (0x0004 + HallFilterCoeffX_hxiaa) +#define HallFilterCoeffX_hxibc (0x0004 + HallFilterCoeffX_hxibb) +#define HallFilterCoeffX_hxiba (0x0004 + HallFilterCoeffX_hxibc) +#define HallFilterCoeffX_hxdab (0x0004 + HallFilterCoeffX_hxiba) +#define HallFilterCoeffX_hxdac (0x0004 + HallFilterCoeffX_hxdab) +#define HallFilterCoeffX_hxdaa (0x0004 + HallFilterCoeffX_hxdac) +#define HallFilterCoeffX_hxdbb (0x0004 + HallFilterCoeffX_hxdaa) +#define HallFilterCoeffX_hxdbc (0x0004 + HallFilterCoeffX_hxdbb) +#define HallFilterCoeffX_hxdba (0x0004 + HallFilterCoeffX_hxdbc) +#define HallFilterCoeffX_hxdcc (0x0004 + HallFilterCoeffX_hxdba) +#define HallFilterCoeffX_hxdcb (0x0004 + HallFilterCoeffX_hxdcc) +#define HallFilterCoeffX_hxdca (0x0004 + HallFilterCoeffX_hxdcb) +#define HallFilterCoeffX_hxpgain0 (0x0004 + HallFilterCoeffX_hxdca) +#define HallFilterCoeffX_hxigain0 (0x0004 + HallFilterCoeffX_hxpgain0) +#define HallFilterCoeffX_hxdgain0 (0x0004 + HallFilterCoeffX_hxigain0) +#define HallFilterCoeffX_hxpgain1 (0x0004 + HallFilterCoeffX_hxdgain0) +#define HallFilterCoeffX_hxigain1 (0x0004 + HallFilterCoeffX_hxpgain1) +#define HallFilterCoeffX_hxdgain1 (0x0004 + HallFilterCoeffX_hxigain1) +#define HallFilterCoeffX_hxgain0 (0x0004 + HallFilterCoeffX_hxdgain1) +#define HallFilterCoeffX_hxgain1 (0x0004 + HallFilterCoeffX_hxgain0) + +#define HallFilterCoeffX_hxsb (0x0004 + HallFilterCoeffX_hxgain1) +#define HallFilterCoeffX_hxsc (0x0004 + HallFilterCoeffX_hxsb) +#define HallFilterCoeffX_hxsa (0x0004 + HallFilterCoeffX_hxsc) + +#define HallFilterCoeffX_hxob (0x0004 + HallFilterCoeffX_hxsa) +#define HallFilterCoeffX_hxoc (0x0004 + HallFilterCoeffX_hxob) +#define HallFilterCoeffX_hxod (0x0004 + HallFilterCoeffX_hxoc) +#define HallFilterCoeffX_hxoe (0x0004 + HallFilterCoeffX_hxod) +#define HallFilterCoeffX_hxoa (0x0004 + HallFilterCoeffX_hxoe) +#define HallFilterCoeffX_hxpb (0x0004 + HallFilterCoeffX_hxoa) +#define HallFilterCoeffX_hxpc (0x0004 + HallFilterCoeffX_hxpb) +#define HallFilterCoeffX_hxpd (0x0004 + HallFilterCoeffX_hxpc) +#define HallFilterCoeffX_hxpe (0x0004 + HallFilterCoeffX_hxpd) +#define HallFilterCoeffX_hxpa (0x0004 + HallFilterCoeffX_hxpe) + +#define HallFilterCoeffY 0x812c + // HallFilterCoeff.h DM_HFC_t +#define HallFilterCoeffY_HYIGAIN (0x0000 + HallFilterCoeffY) +#define HallFilterCoeffY_GYROYOUTGAIN (0x0004 + HallFilterCoeffY_HYIGAIN) +#define HallFilterCoeffY_HYOFFGAIN (0x0004 + HallFilterCoeffY_GYROYOUTGAIN) + +#define HallFilterCoeffY_hyiab (0x0004 + HallFilterCoeffY_HYOFFGAIN) +#define HallFilterCoeffY_hyiac (0x0004 + HallFilterCoeffY_hyiab) +#define HallFilterCoeffY_hyiaa (0x0004 + HallFilterCoeffY_hyiac) +#define HallFilterCoeffY_hyibb (0x0004 + HallFilterCoeffY_hyiaa) +#define HallFilterCoeffY_hyibc (0x0004 + HallFilterCoeffY_hyibb) +#define HallFilterCoeffY_hyiba (0x0004 + HallFilterCoeffY_hyibc) +#define HallFilterCoeffY_hydab (0x0004 + HallFilterCoeffY_hyiba) +#define HallFilterCoeffY_hydac (0x0004 + HallFilterCoeffY_hydab) +#define HallFilterCoeffY_hydaa (0x0004 + HallFilterCoeffY_hydac) +#define HallFilterCoeffY_hydbb (0x0004 + HallFilterCoeffY_hydaa) +#define HallFilterCoeffY_hydbc (0x0004 + HallFilterCoeffY_hydbb) +#define HallFilterCoeffY_hydba (0x0004 + HallFilterCoeffY_hydbc) +#define HallFilterCoeffY_hydcc (0x0004 + HallFilterCoeffY_hydba) +#define HallFilterCoeffY_hydcb (0x0004 + HallFilterCoeffY_hydcc) +#define HallFilterCoeffY_hydca (0x0004 + HallFilterCoeffY_hydcb) +#define HallFilterCoeffY_hypgain0 (0x0004 + HallFilterCoeffY_hydca) +#define HallFilterCoeffY_hyigain0 (0x0004 + HallFilterCoeffY_hypgain0) +#define HallFilterCoeffY_hydgain0 (0x0004 + HallFilterCoeffY_hyigain0) +#define HallFilterCoeffY_hypgain1 (0x0004 + HallFilterCoeffY_hydgain0) +#define HallFilterCoeffY_hyigain1 (0x0004 + HallFilterCoeffY_hypgain1) +#define HallFilterCoeffY_hydgain1 (0x0004 + HallFilterCoeffY_hyigain1) +#define HallFilterCoeffY_hygain0 (0x0004 + HallFilterCoeffY_hydgain1) +#define HallFilterCoeffY_hygain1 (0x0004 + HallFilterCoeffY_hygain0) +#define HallFilterCoeffY_hysb (0x0004 + HallFilterCoeffY_hygain1) +#define HallFilterCoeffY_hysc (0x0004 + HallFilterCoeffY_hysb) +#define HallFilterCoeffY_hysa (0x0004 + HallFilterCoeffY_hysc) +#define HallFilterCoeffY_hyob (0x0004 + HallFilterCoeffY_hysa) +#define HallFilterCoeffY_hyoc (0x0004 + HallFilterCoeffY_hyob) +#define HallFilterCoeffY_hyod (0x0004 + HallFilterCoeffY_hyoc) +#define HallFilterCoeffY_hyoe (0x0004 + HallFilterCoeffY_hyod) +#define HallFilterCoeffY_hyoa (0x0004 + HallFilterCoeffY_hyoe) +#define HallFilterCoeffY_hypb (0x0004 + HallFilterCoeffY_hyoa) +#define HallFilterCoeffY_hypc (0x0004 + HallFilterCoeffY_hypb) +#define HallFilterCoeffY_hypd (0x0004 + HallFilterCoeffY_hypc) +#define HallFilterCoeffY_hype (0x0004 + HallFilterCoeffY_hypd) +#define HallFilterCoeffY_hypa (0x0004 + HallFilterCoeffY_hype) + +#define HallFilterLimitX 0x81c8 +#define HallFilterLimitY 0x81e0 +#define HallFilterShiftX 0x81f8 +#define HallFilterShiftY 0x81fe + +#define HF_MIXING 0x8214 +#define HF_hx45x (0x0000 + HF_MIXING ) //0x008005E4 : HallMixingCoeff.hx45x +#define HF_hx45y (0x0004 + HF_MIXING ) //0x008005E8 : HallMixingCoeff.hx45y +#define HF_hy45y (0x0008 + HF_MIXING ) //0x008005EC : HallMixingCoeff.hy45y +#define HF_hy45x (0x000C + HF_MIXING ) //0x008005F0 : HallMixingCoeff.hy45x +#define HF_ShiftX (0x0010 + HF_MIXING ) + +#define HAL_LN_CORRECT 0x8228 +#define HAL_LN_COEFAX (0x0000 + HAL_LN_CORRECT) // HallLinearCorrAX.zone_coef[6] +#define HAL_LN_COEFBX (0x000C + HAL_LN_COEFAX ) // HallLinearCorrBX.zone_coef[6] +#define HAL_LN_ZONEX (0x000C + HAL_LN_COEFBX ) // HallLinearZoneX.zone_area[5] +#define HAL_LN_COEFAY (0x000A + HAL_LN_ZONEX ) // HallLinearCorrAY.zone_coef[6] +#define HAL_LN_COEFBY (0x000C + HAL_LN_COEFAY ) // HallLinearCorrBY.zone_coef[6] +#define HAL_LN_ZONEY (0x000C + HAL_LN_COEFBY ) // HallLinearZoneY.zone_area[5] + +#define GyroFilterTableX 0x8270 + // GyroFilterCoeff.h DM_GFC_t +#define GyroFilterTableX_gx45x (0x0000 + GyroFilterTableX) +#define GyroFilterTableX_gx45y (0x0004 + GyroFilterTableX_gx45x) +#define GyroFilterTableX_gxgyro (0x0004 + GyroFilterTableX_gx45y) +#define GyroFilterTableX_gxsengen (0x0004 + GyroFilterTableX_gxgyro) +#define GyroFilterTableX_gxl1b (0x0004 + GyroFilterTableX_gxsengen) +#define GyroFilterTableX_gxl1c (0x0004 + GyroFilterTableX_gxl1b) +#define GyroFilterTableX_gxl1a (0x0004 + GyroFilterTableX_gxl1c) +#define GyroFilterTableX_gxl2b (0x0004 + GyroFilterTableX_gxl1a) +#define GyroFilterTableX_gxl2c (0x0004 + GyroFilterTableX_gxl2b) +#define GyroFilterTableX_gxl2a (0x0004 + GyroFilterTableX_gxl2c) +#define GyroFilterTableX_gxigain (0x0004 + GyroFilterTableX_gxl2a) +#define GyroFilterTableX_gxh1b (0x0004 + GyroFilterTableX_gxigain) +#define GyroFilterTableX_gxh1c (0x0004 + GyroFilterTableX_gxh1b) +#define GyroFilterTableX_gxh1a (0x0004 + GyroFilterTableX_gxh1c) +#define GyroFilterTableX_gxk1b (0x0004 + GyroFilterTableX_gxh1a) +#define GyroFilterTableX_gxk1c (0x0004 + GyroFilterTableX_gxk1b) +#define GyroFilterTableX_gxk1a (0x0004 + GyroFilterTableX_gxk1c) +#define GyroFilterTableX_gxgain (0x0004 + GyroFilterTableX_gxk1a) +#define GyroFilterTableX_gxzoom (0x0004 + GyroFilterTableX_gxgain) +#define GyroFilterTableX_gxlenz (0x0004 + GyroFilterTableX_gxzoom) +#define GyroFilterTableX_gxt2b (0x0004 + GyroFilterTableX_gxlenz) +#define GyroFilterTableX_gxt2c (0x0004 + GyroFilterTableX_gxt2b) +#define GyroFilterTableX_gxt2a (0x0004 + GyroFilterTableX_gxt2c) +#define GyroFilterTableX_afzoom (0x0004 + GyroFilterTableX_gxt2a) + +#define GyroFilterTableY 0x82D0 + // GyroFilterCoeff.h DM_GFC_t +#define GyroFilterTableY_gy45y (0x0000 + GyroFilterTableY) +#define GyroFilterTableY_gy45x (0x0004 + GyroFilterTableY_gy45y) +#define GyroFilterTableY_gygyro (0x0004 + GyroFilterTableY_gy45x) +#define GyroFilterTableY_gysengen (0x0004 + GyroFilterTableY_gygyro) +#define GyroFilterTableY_gyl1b (0x0004 + GyroFilterTableY_gysengen) +#define GyroFilterTableY_gyl1c (0x0004 + GyroFilterTableY_gyl1b) +#define GyroFilterTableY_gyl1a (0x0004 + GyroFilterTableY_gyl1c) +#define GyroFilterTableY_gyl2b (0x0004 + GyroFilterTableY_gyl1a) +#define GyroFilterTableY_gyl2c (0x0004 + GyroFilterTableY_gyl2b) +#define GyroFilterTableY_gyl2a (0x0004 + GyroFilterTableY_gyl2c) +#define GyroFilterTableY_gyigain (0x0004 + GyroFilterTableY_gyl2a) +#define GyroFilterTableY_gyh1b (0x0004 + GyroFilterTableY_gyigain) +#define GyroFilterTableY_gyh1c (0x0004 + GyroFilterTableY_gyh1b) +#define GyroFilterTableY_gyh1a (0x0004 + GyroFilterTableY_gyh1c) +#define GyroFilterTableY_gyk1b (0x0004 + GyroFilterTableY_gyh1a) +#define GyroFilterTableY_gyk1c (0x0004 + GyroFilterTableY_gyk1b) +#define GyroFilterTableY_gyk1a (0x0004 + GyroFilterTableY_gyk1c) +#define GyroFilterTableY_gygain (0x0004 + GyroFilterTableY_gyk1a) +#define GyroFilterTableY_gyzoom (0x0004 + GyroFilterTableY_gygain) +#define GyroFilterTableY_gylenz (0x0004 + GyroFilterTableY_gyzoom) +#define GyroFilterTableY_gyt2b (0x0004 + GyroFilterTableY_gylenz) +#define GyroFilterTableY_gyt2c (0x0004 + GyroFilterTableY_gyt2b) +#define GyroFilterTableY_gyt2a (0x0004 + GyroFilterTableY_gyt2c) +#define GyroFilterTableY_afzoom (0x0004 + GyroFilterTableY_gyt2a) + +#define Gyro_Limiter_X 0x8330 +#define Gyro_Limiter_Y 0x8334 +#define Gyro_ShiftX_RG 0x8338 +#define Gyro_ShiftY_RG 0x833C + +#define ZeroServoFilterTableX 0x8384 +#define ZeroServoFilterTableX_coeff1_0 (0x0000 + ZeroServoFilterTableX) // 0x8384 +#define ZeroServoFilterTableX_coeff1_1 (0x0004 + ZeroServoFilterTableX_coeff1_0) // 0x8388 +#define ZeroServoFilterTableX_coeff1_2 (0x0004 + ZeroServoFilterTableX_coeff1_1) // 0x838C +#define ZeroServoFilterTableX_g45main (0x0004 + ZeroServoFilterTableX_coeff1_2) // 0x8390 +#define ZeroServoFilterTableX_g45sub (0x0004 + ZeroServoFilterTableX_g45main) // 0x8394 +#define ZeroServoFilterTableX_gcora (0x0004 + ZeroServoFilterTableX_g45sub) // 0x8398 +#define ZeroServoFilterTableX_gaina (0x0004 + ZeroServoFilterTableX_gcora) // 0x839C +#define ZeroServoFilterTableX_shift (0x0004 + ZeroServoFilterTableX_gaina) // 0x83A0 + +#define ZeroServoFilterTableY 0x83A4 +#define ZeroServoFilterTableY_coeff1_0 (0x0000 + ZeroServoFilterTableY) // 0x83A4 +#define ZeroServoFilterTableY_coeff1_1 (0x0004 + ZeroServoFilterTableY_coeff1_0) // 0x83A8 +#define ZeroServoFilterTableY_coeff1_2 (0x0004 + ZeroServoFilterTableY_coeff1_1) // 0x83AC +#define ZeroServoFilterTableY_g45main (0x0004 + ZeroServoFilterTableY_coeff1_2) // 0x83B0 +#define ZeroServoFilterTableY_g45sub (0x0004 + ZeroServoFilterTableY_g45main) // 0x83B4 +#define ZeroServoFilterTableY_gcora (0x0004 + ZeroServoFilterTableY_g45sub) // 0x83B8 +#define ZeroServoFilterTableY_gaina (0x0004 + ZeroServoFilterTableY_gcora) // 0x83BC +#define ZeroServoFilterTableY_shift (0x0004 + ZeroServoFilterTableY_gaina) // 0x83C0 + +#define MeasureFilterA_Coeff 0x83C4 //0x8380 + // MeasureFilter.h MeasureFilter_Type +#define MeasureFilterA_Coeff_b1 (0x0000 + MeasureFilterA_Coeff) +#define MeasureFilterA_Coeff_c1 (0x0004 + MeasureFilterA_Coeff_b1) +#define MeasureFilterA_Coeff_a1 (0x0004 + MeasureFilterA_Coeff_c1) +#define MeasureFilterA_Coeff_b2 (0x0004 + MeasureFilterA_Coeff_a1) +#define MeasureFilterA_Coeff_c2 (0x0004 + MeasureFilterA_Coeff_b2) +#define MeasureFilterA_Coeff_a2 (0x0004 + MeasureFilterA_Coeff_c2) + +#define MeasureFilterB_Coeff 0x83DC //0x8398 + // MeasureFilter.h MeasureFilter_Type +#define MeasureFilterB_Coeff_b1 (0x0000 + MeasureFilterB_Coeff) +#define MeasureFilterB_Coeff_c1 (0x0004 + MeasureFilterB_Coeff_b1) +#define MeasureFilterB_Coeff_a1 (0x0004 + MeasureFilterB_Coeff_c1) +#define MeasureFilterB_Coeff_b2 (0x0004 + MeasureFilterB_Coeff_a1) +#define MeasureFilterB_Coeff_c2 (0x0004 + MeasureFilterB_Coeff_b2) +#define MeasureFilterB_Coeff_a2 (0x0004 + MeasureFilterB_Coeff_c2) + +#define OLAF_DMB_FT 0x8510 + +#define OLAF_COEF 0x854C +#define OLAF_COEF_FSTVAL0 (0x0000 + OLAF_COEF) +#define OLAF_COEF_FSTVAL1 (0x0004 + OLAF_COEF) +#define OLAF_COEF_FSTVAL2 (0x0008 + OLAF_COEF) + + +#define CommandDecodeTable 0x85AC + // Command.cpp CommandTable in Rom +#define CommandDecodeTable_08 (0x0020 + CommandDecodeTable) + +#define GCNV_XX 0x86A4 +#define GCNV_XY 0x86A8 +#define GCNV_YY 0x86AC +#define GCNV_YX 0x86B0 +#define GCNV_ZP 0x86C8 +#define ACNV_XX 0x86B4 +#define ACNV_XY 0x86B8 +#define ACNV_YY 0x867C +#define ACNV_YX 0x8680 +#define ACNV_ZP 0x8684 + +#define Accl45Filter 0x8780 +#define Accl45Filter_XAdir (0x0000 + Accl45Filter ) +#define Accl45Filter_XAmain (0x0004 + Accl45Filter ) +#define Accl45Filter_XAsub (0x0008 + Accl45Filter ) +#define Accl45Filter_YAdir (0x000C + Accl45Filter ) +#define Accl45Filter_YAmain (0x0010 + Accl45Filter ) +#define Accl45Filter_YAsub (0x0014 + Accl45Filter ) + +#define ZS_LMT 0x87A4 +#define ZS_LMT_limitx (0x0000 + ZS_LMT ) +#define ZS_LMT_limity (0x0004 + ZS_LMT ) + + +#define FRA_DMB_C0 0x8908 //FRA_DMB.C0 +#define FRA_DMB_S0 0x890C //FRA_DMB.S0 +#define FRA_DMB_CN 0x8910 //FRA_DMB.CN +#define FRA_DMB_SN 0x8914 //FRA_DMB.SN + + +//============================================================================== +//IO +//============================================================================== +// System Control”z’uƒAƒhƒŒƒX +#define PERICLKON 0xD00000 +#define SYSDSP_DSPDIV 0xD00014 +#define IOPLEV 0xD00020 +#define IOPDIR 0xD00024 +#define IOPUDON 0xD00028 +#define IOPUD 0xD0002C +#define SYSDSP_SOFTRES 0xD0006C +#define SYSDSP_STBOTH 0xD00078 +#define SYSDSP_DACI 0xD00088 +#define SYSDSP_OPGSEL 0xD0008C +#define OSCRSEL 0xD00090 +#define OSCCURSEL 0xD00094 +#define FRQTRM 0xD00098 +#define SYSDSP_REMAP 0xD000AC +#define OSCCNT 0xD000D4 +#define SYSDSP_CVER 0xD00100 +#define IOPLEVR 0xD00104 +#define OSCCKCNT 0xD00108 + +#define ADDA_FSCNT 0xD01004 +#define ADDA_FSCTRL 0xD01008 +#define ADDA_ADDAINT 0xD0100C +#define ADDA_ADE 0xD01010 +#define ADDA_ADAV 0xD01014 +#define ADDA_ADORDER 0xD01018 +#define ADDA_EXTEND 0xD0101C +#define ADDA_AD0O 0xD01020 +#define ADDA_AD1O 0xD01024 +#define ADDA_AD2O 0xD01028 +#define ADDA_AD3O 0xD0102C + +#define ADDA_DASELW 0xD01040 +#define ADDA_DASU 0xD01044 +#define ADDA_DAHD 0xD01048 +#define ADDA_DASWAP 0xD0104C +#define ADDA_DASEL 0xD01050 + #define HLXO 0x00000001 // D/A Converter Channel Select HLXO + #define HLYO 0x00000002 // D/A Converter Channel Select HLYO + #define HLXBO 0x00000004 // D/A Converter Channel Select HLXBO + #define HLYBO 0x00000008 // D/A Converter Channel Select HLYBO + #define HLAFO 0x00000010 // D/A Converter Channel Select HLAFO + #define HLAFBO 0x00000020 // D/A Converter Channel Select HLAFBO + +#define ADDA_DAO 0xD01054 + +// PWM I/F”z’uƒAƒhƒŒƒX +#define OISDRVFC1 0xD02100 +#define OISDRVFC4 0xD0210C +#define OISDRVFC5 0xD02110 +#define OISDRVFC6 0xD02114 +#define OISDRVFC7 0xD02118 +#define OISDRVFC8 0xD0211C +#define OISDRVFC9 0xD02120 + +#define DRVCH1SEL 0xD02128 +#define DRVCH2SEL 0xD0212C + +#define OISGAINAM 0xD02190 +#define OISOFSTAM 0xD02194 +#define OISGAINBM 0xD02198 +#define OISOFSTBM 0xD0219C + +#define AFDRVFC1 0xD02200 +#define AFDRVFC4 0xD0220C +#define AFDRVFC5 0xD02210 +#define AFDRVFC6 0xD02214 +#define AFDRVFC7 0xD02218 + +#define DRVCH3SEL 0xD02220 + +#define AFGAINM 0xD02290 +#define AFSOFSTM 0xD02294 + +//Periphral +#define ROMINFO 0xE0500C +#define SADR 0xE05030 + +// E2PROM ”z’uƒAƒhƒŒƒX +#define E2P_RDAT 0xE07000 +#define E2P_ADR 0xE07008 +#define E2P_ASCNT 0xE0700C +#define E2P_CMD 0xE07010 +#define E2P_WPB 0xE07014 +#define E2P_INT 0xE07018 + +#define E2P_WDAT00 0xE07040 +#define E2P_WDAT01 0xE07044 +#define E2P_WDAT02 0xE07048 +#define E2P_WDAT03 0xE0704C +#define E2P_WDAT04 0xE07050 +#define E2P_WDAT05 0xE07054 +#define E2P_WDAT06 0xE07058 +#define E2P_WDAT07 0xE0705C +#define E2P_WDAT08 0xE07060 +#define E2P_WDAT09 0xE07064 +#define E2P_WDAT10 0xE07068 +#define E2P_WDAT11 0xE0706C +#define E2P_WDAT12 0xE07070 +#define E2P_WDAT13 0xE07074 +#define E2P_WDAT14 0xE07078 +#define E2P_WDAT15 0xE0707C +#define E2P_DFG 0xE07080 + +#define E2P_RSTB 0xE074CC +#define E2P_UNLK_CODE1 0xE07554 +#define E2P_CLKON 0xE07664 +#define E2P_UNLK_CODE2 0xE07AA8 +#define E2P_UNLK_CODE3 0xE07CCC + + + \ No newline at end of file diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Ois_BOSCH.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Ois_BOSCH.h new file mode 100755 index 0000000000000000000000000000000000000000..3820e0d34dbe6a932751a1cd1c252df6941716a4 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/Ois_BOSCH.h @@ -0,0 +1,34 @@ +//******************************************************************************** +// +// << BMI260 Evaluation Soft>> +// Program Name : Ois_BOSCH.h +// Explanation : BMI260 Global Declaration & ProtType Declaration +// Design : K.abe +// History : First edition +//******************************************************************************** +#define BMI260_SlvAddrWr 0xD0 // I2C Slave Address +#define BMI260_SlvAddrRd 0xD1 // I2C Slave Address + +/************************************************/ +/* Command Addrss */ +/************************************************/ +#define CHIP_ID_260 0x00 +#define INTERNAL_STATUS_260 0x21 +#define ACC_CONF_260 0x40 +#define ACC_RANGE_260 0x41 +#define GYR_CONF_260 0x42 +#define GYR_RANGE_260 0x43 +#define INIT_CTRL_260 0x59 +#define INIT_DATA_260 0x5E +#define IF_CONF_260 0x6B +#define PWR_CONF_260 0x7C +#define PWR_CTRL_260 0x7D + +/************************************************/ +/* Data */ +/************************************************/ +#define AUX_EN_260 0 +#define GYR_EN_260 1 +#define ACC_EN_260 2 +#define TEMP_EN_260 3 + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2.c new file mode 100755 index 0000000000000000000000000000000000000000..f4072dc205cd9d08c62c32b77d880bd45978e901 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2.c @@ -0,0 +1,14019 @@ +/** + * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of the + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * The information provided is believed to be accurate and reliable. + * The copyright holder assumes no responsibility + * for the consequences of use + * of such information nor for any infringement of patents or + * other rights of third parties which may result from its use. + * No license is granted by implication or otherwise under any patent or + * patent rights of the copyright holder. + * + * @file bmi2.c + * @date 16 August, 2018 + * @version 1.35.0 + * @brief Sensor driver for BMI2XY sensor + * + */ + +/******************************************************************************/ +/*! @name Header Files */ +/******************************************************************************/ +#include "bmi2.h" + +/******************************************************************************/ +/*! @name Macros */ +/******************************************************************************/ +/*! @name Offsets from feature start address for BMI2 feature enable/disable */ +#define ANY_MOT_FEAT_EN_OFFSET UINT8_C(0x03) +#define NO_MOT_FEAT_EN_OFFSET UINT8_C(0x03) +#define SIG_MOT_FEAT_EN_OFFSET UINT8_C(0x0A) +#define STEP_COUNT_FEAT_EN_OFFSET UINT8_C(0x01) +#define GYR_USER_GAIN_FEAT_EN_OFFSET UINT8_C(0x05) +#define HIGH_G_FEAT_EN_OFFSET UINT8_C(0x03) +#define LOW_G_FEAT_EN_OFFSET UINT8_C(0x03) + +/*! @name Mask definitions for BMI2 feature enable/disable */ +#define ANY_NO_MOT_EN_MASK UINT8_C(0x80) +#define TILT_FEAT_EN_MASK UINT8_C(0x01) +#define ORIENT_FEAT_EN_MASK UINT8_C(0x01) +#define SIG_MOT_FEAT_EN_MASK UINT8_C(0x01) +#define STEP_DET_FEAT_EN_MASK UINT8_C(0x08) +#define STEP_COUNT_FEAT_EN_MASK UINT8_C(0x10) +#define STEP_ACT_FEAT_EN_MASK UINT8_C(0x20) +#define GYR_USER_GAIN_FEAT_EN_MASK UINT8_C(0x08) +#define PICK_UP_FEAT_EN_MASK UINT8_C(0x01) +#define GLANCE_FEAT_EN_MASK UINT8_C(0x01) +#define WAKE_UP_FEAT_EN_MASK UINT8_C(0x01) +#define HIGH_G_FEAT_EN_MASK UINT8_C(0x80) +#define LOW_G_FEAT_EN_MASK UINT8_C(0x10) +#define FLAT_FEAT_EN_MASK UINT8_C(0x01) +#define EXT_SENS_SYNC_FEAT_EN_MASK UINT8_C(0x01) +#define GYR_SELF_OFF_CORR_FEAT_EN_MASK UINT8_C(0x02) +#define WRIST_GEST_FEAT_EN_MASK UINT8_C(0x01) +#define WRIST_WEAR_WAKE_UP_FEAT_EN_MASK UINT8_C(0x01) +#define ACTIVITY_RECOG_EN_MASK UINT8_C(0x01) + +/*! @name Bit position definitions for BMI2 feature enable/disable */ +#define ANY_NO_MOT_EN_POS UINT8_C(0x07) +#define STEP_DET_FEAT_EN_POS UINT8_C(0x03) +#define STEP_COUNT_FEAT_EN_POS UINT8_C(0x04) +#define STEP_ACT_FEAT_EN_POS UINT8_C(0x05) +#define GYR_USER_GAIN_FEAT_EN_POS UINT8_C(0x03) +#define HIGH_G_FEAT_EN_POS UINT8_C(0x07) +#define LOW_G_FEAT_EN_POS UINT8_C(0x04) +#define GYR_SELF_OFF_CORR_FEAT_EN_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 any and no-motion feature configuration */ +#define ANY_NO_MOT_DUR_MASK UINT16_C(0x1FFF) +#define ANY_NO_MOT_X_SEL_MASK UINT16_C(0x2000) +#define ANY_NO_MOT_Y_SEL_MASK UINT16_C(0x4000) +#define ANY_NO_MOT_Z_SEL_MASK UINT16_C(0x8000) +#define ANY_NO_MOT_THRES_MASK UINT16_C(0x07FF) +#define ANY_NO_MOT_OUT_CONF_MASK UINT16_C(0x7800) + +/*! @name Bit position definitions for BMI2 any and no-motion feature + configuration */ +#define ANY_NO_MOT_X_SEL_POS UINT8_C(0x0D) +#define ANY_NO_MOT_Y_SEL_POS UINT8_C(0x0E) +#define ANY_NO_MOT_Z_SEL_POS UINT8_C(0x0F) +#define ANY_NO_MOT_OUT_CONF_POS UINT8_C(0x0B) + +/*! @name Mask definitions for BMI2 tilt feature configuration */ +#define TILT_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 tilt feature configuration */ +#define TILT_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 orientation feature configuration */ +#define ORIENT_UP_DOWN_MASK UINT16_C(0x0002) +#define ORIENT_SYMM_MODE_MASK UINT16_C(0x000C) +#define ORIENT_BLOCK_MODE_MASK UINT16_C(0x0030) +#define ORIENT_THETA_MASK UINT16_C(0x0FC0) +#define ORIENT_HYST_MASK UINT16_C(0x07FF) +#define ORIENT_OUT_CONF_MASK UINT16_C(0x7800) + +/*! @name Bit position definitions for BMI2 orientation feature configuration */ +#define ORIENT_UP_DOWN_POS UINT8_C(0x01) +#define ORIENT_SYMM_MODE_POS UINT8_C(0x02) +#define ORIENT_BLOCK_MODE_POS UINT8_C(0x04) +#define ORIENT_THETA_POS UINT8_C(0x06) +#define ORIENT_OUT_CONF_POS UINT8_C(0x0B) + +/*! @name Mask definitions for BMI2 sig-motion feature configuration */ +#define SIG_MOT_PARAM_1_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_2_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_3_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_4_MASK UINT16_C(0xFFFF) +#define SIG_MOT_PARAM_5_MASK UINT16_C(0xFFFF) +#define SIG_MOT_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 sig-motion feature configuration */ +#define SIG_MOT_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 step-counter/detector feature + configuration */ +#define STEP_COUNT_WM_LEVEL_MASK UINT16_C(0x03FF) +#define STEP_COUNT_RST_CNT_MASK UINT16_C(0x0400) +#define STEP_DET_OUT_CONF_MASK UINT16_C(0x000F) +#define STEP_ACT_OUT_CONF_MASK UINT16_C(0x00F0) + +/*! @name Bit position definitions for BMI2 step-counter/detector feature + configuration */ +#define STEP_COUNT_RST_CNT_POS UINT8_C(0x0A) +#define STEP_ACT_OUT_CONF_POS UINT8_C(0x04) + +/*! @name Mask definitions for BMI2 gyroscope user gain feature + configuration */ +#define GYR_USER_GAIN_RATIO_X_MASK UINT16_C(0x07FF) +#define GYR_USER_GAIN_RATIO_Y_MASK UINT16_C(0x07FF) +#define GYR_USER_GAIN_RATIO_Z_MASK UINT16_C(0x07FF) + +/*! @name Mask definitions for BMI2 gyroscope user gain saturation status */ +#define GYR_USER_GAIN_SAT_STAT_X_MASK UINT8_C(0x01) +#define GYR_USER_GAIN_SAT_STAT_Y_MASK UINT8_C(0x02) +#define GYR_USER_GAIN_SAT_STAT_Z_MASK UINT8_C(0x04) + +/*! @name Bit position definitions for BMI2 gyroscope user gain saturation + status */ +#define GYR_USER_GAIN_SAT_STAT_Y_POS UINT8_C(0x01) +#define GYR_USER_GAIN_SAT_STAT_Z_POS UINT8_C(0x02) + +/*! @name Mask definitions for MSB values of BMI2 gyroscope compensation */ +#define GYR_OFF_COMP_MSB_X_MASK UINT8_C(0x03) +#define GYR_OFF_COMP_MSB_Y_MASK UINT8_C(0x0C) +#define GYR_OFF_COMP_MSB_Z_MASK UINT8_C(0x30) + +/*! @name Bit positions for MSB values of BMI2 gyroscope compensation */ +#define GYR_OFF_COMP_MSB_Y_POS UINT8_C(0x02) +#define GYR_OFF_COMP_MSB_Z_POS UINT8_C(0x04) + +/*! @name Mask definitions for MSB values of BMI2 gyroscope compensation from +user input */ +#define GYR_OFF_COMP_MSB_MASK UINT16_C(0x0300) +#define GYR_OFF_COMP_LSB_MASK UINT16_C(0x00FF) + +/*! @name Mask definitions for BMI2 orientation status */ +#define BMI2_ORIENT_DETECT_MASK UINT8_C(0x03) +#define BMI2_ORIENT_FACE_UP_DWN_MASK UINT8_C(0x04) + +/*! @name Bit position definitions for BMI2 orientation status */ +#define BMI2_ORIENT_FACE_UP_DWN_POS UINT8_C(0x02) + +/*! @name Mask definitions for NVM-VFRM error status */ +#define NVM_LOAD_ERR_STATUS_MASK UINT8_C(0x01) +#define NVM_PROG_ERR_STATUS_MASK UINT8_C(0x02) +#define NVM_ERASE_ERR_STATUS_MASK UINT8_C(0x04) +#define NVM_END_EXCEED_STATUS_MASK UINT8_C(0x08) +#define NVM_PRIV_ERR_STATUS_MASK UINT8_C(0x10) +#define VFRM_LOCK_ERR_STATUS_MASK UINT8_C(0x20) +#define VFRM_WRITE_ERR_STATUS_MASK UINT8_C(0x40) +#define VFRM_FATAL_ERR_STATUS_MASK UINT8_C(0x80) + +/*! @name Bit positions for NVM-VFRM error status */ +#define NVM_PROG_ERR_STATUS_POS UINT8_C(0x01) +#define NVM_ERASE_ERR_STATUS_POS UINT8_C(0x02) +#define NVM_END_EXCEED_STATUS_POS UINT8_C(0x03) +#define NVM_PRIV_ERR_STATUS_POS UINT8_C(0x04) +#define VFRM_LOCK_ERR_STATUS_POS UINT8_C(0x05) +#define VFRM_WRITE_ERR_STATUS_POS UINT8_C(0x06) +#define VFRM_FATAL_ERR_STATUS_POS UINT8_C(0x07) + +/*! @name Mask definitions for BMI2 pick-up feature configuration */ +#define PICK_UP_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 pick-up feature configuration */ +#define PICK_UP_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 glance detector feature configuration */ +#define GLANCE_DET_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for BMI2 glance detector feature + configuration */ +#define GLANCE_DET_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 wake-up feature configuration */ +#define WAKE_UP_SENSITIVITY_MASK UINT16_C(0x000E) +#define WAKE_UP_SINGLE_TAP_EN_MASK UINT16_C(0x0010) +#define WAKE_UP_OUT_CONF_MASK UINT16_C(0x01E0) + +/*! @name Bit position definitions for BMI2 wake-up feature configuration */ +#define WAKE_UP_SENSITIVITY_POS UINT8_C(0x01) +#define WAKE_UP_SINGLE_TAP_EN_POS UINT8_C(0x04) +#define WAKE_UP_OUT_CONF_POS UINT8_C(0x05) + +/*! @name Mask definitions for BMI2 high-g feature configuration */ +#define HIGH_G_THRES_MASK UINT16_C(0x7FFF) +#define HIGH_G_HYST_MASK UINT16_C(0x0FFF) +#define HIGH_G_X_SEL_MASK UINT16_C(0x1000) +#define HIGH_G_Y_SEL_MASK UINT16_C(0x2000) +#define HIGH_G_Z_SEL_MASK UINT16_C(0x4000) +#define HIGH_G_DUR_MASK UINT16_C(0x0FFF) +#define HIGH_G_OUT_CONF_MASK UINT16_C(0xF000) + +/*! @name Bit position definitions for BMI2 high-g feature configuration */ +#define HIGH_G_OUT_CONF_POS UINT8_C(0x0C) +#define HIGH_G_X_SEL_POS UINT8_C(0x0C) +#define HIGH_G_Y_SEL_POS UINT8_C(0x0D) +#define HIGH_G_Z_SEL_POS UINT8_C(0x0E) + +/*! @name Mask definitions for BMI2 low-g feature configuration */ +#define LOW_G_THRES_MASK UINT16_C(0x7FFF) +#define LOW_G_HYST_MASK UINT16_C(0x0FFF) +#define LOW_G_DUR_MASK UINT16_C(0x0FFF) +#define LOW_G_OUT_CONF_MASK UINT16_C(0xF000) + +/*! @name Bit position definitions for BMI2 low-g feature configuration */ +#define LOW_G_OUT_CONF_POS UINT8_C(0x0C) + +/*! @name Mask definitions for BMI2 flat feature configuration */ +#define FLAT_THETA_MASK UINT16_C(0x007E) +#define FLAT_BLOCK_MASK UINT16_C(0x0180) +#define FLAT_OUT_CONF_MASK UINT16_C(0x1E00) +#define FLAT_HYST_MASK UINT16_C(0x003F) +#define FLAT_HOLD_TIME_MASK UINT16_C(0x3FC0) + +/*! @name Bit position definitions for BMI2 flat feature configuration */ +#define FLAT_THETA_POS UINT8_C(0x01) +#define FLAT_BLOCK_POS UINT8_C(0x07) +#define FLAT_OUT_CONF_POS UINT8_C(0x09) +#define FLAT_HOLD_TIME_POS UINT8_C(0x06) + +/*! @name Mask definitions for BMI2 external sensor sync configuration */ +#define EXT_SENS_SYNC_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for external sensor sync configuration */ +#define EXT_SENS_SYNC_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Mask definitions for BMI2 wrist gesture configuration */ +#define WRIST_GEST_WEAR_ARM_MASK UINT16_C(0x0002) +#define WRIST_GEST_OUT_CONF_MASK UINT16_C(0x003C) + +/*! @name Bit position definitions for wrist gesture configuration */ +#define WRIST_GEST_WEAR_ARM_POS UINT8_C(0x01) +#define WRIST_GEST_OUT_CONF_POS UINT8_C(0x02) + +/*! @name Mask definitions for BMI2 wrist wear wake-up configuration */ +#define WRIST_WAKE_UP_OUT_CONF_MASK UINT16_C(0x001E) + +/*! @name Bit position definitions for wrist wear wake-up configuration */ +#define WRIST_WAKE_UP_OUT_CONF_POS UINT8_C(0x01) + +/*! @name Macros to define values of BMI2 axis and its sign for re-map + settings */ +#define MAP_X_AXIS UINT8_C(0x00) +#define MAP_Y_AXIS UINT8_C(0x01) +#define MAP_Z_AXIS UINT8_C(0x02) +#define MAP_POSITIVE UINT8_C(0x00) +#define MAP_NEGATIVE UINT8_C(0x01) + +/*! @name Mask definitions of BMI2 axis re-mapping */ +#define X_AXIS_MASK UINT8_C(0x03) +#define X_AXIS_SIGN_MASK UINT8_C(0x04) +#define Y_AXIS_MASK UINT8_C(0x18) +#define Y_AXIS_SIGN_MASK UINT8_C(0x20) +#define Z_AXIS_MASK UINT8_C(0xC0) +#define Z_AXIS_SIGN_MASK UINT8_C(0x01) + +/*! @name Bit position definitions of BMI2 axis re-mapping */ +#define X_AXIS_SIGN_POS UINT8_C(0x02) +#define Y_AXIS_POS UINT8_C(0x03) +#define Y_AXIS_SIGN_POS UINT8_C(0x05) +#define Z_AXIS_POS UINT8_C(0x06) + +/*! @name Macros to define polarity */ +#define NEG_SIGN INT16_C(-1) +#define POS_SIGN INT16_C(1) + +/*! @name Macro to define start of self-test */ +#define SELF_TEST_START UINT8_C(1) + +/***************************************************************************/ +/*! Local structures +****************************************************************************/ +/*! @name Structure to define the difference in accelerometer values */ +struct selftest_delta_limit { + /*! X data */ + int32_t x; + /*! Y data */ + int32_t y; + /*! Z data */ + int32_t z; +}; + +/*! @name Structure to store the local copy of the re-mapped axis and + the value of its sign for register settings */ +struct axes_remap { + /*! Re-mapped x-axis */ + uint8_t x_axis; + /*! Re-mapped y-axis */ + uint8_t y_axis; + /*! Re-mapped z-axis */ + uint8_t z_axis; + /*! Re-mapped x-axis sign */ + uint8_t x_axis_sign; + /*! Re-mapped y-axis sign */ + uint8_t y_axis_sign; + /*! Re-mapped z-axis sign */ + uint8_t z_axis_sign; +}; + +/*! @name Structure to store temporary accelerometer/gyroscope values */ +struct temp_value_int32 { + /*! X data */ + int32_t x; + /*! Y data */ + int32_t y; + /*! Z data */ + int32_t z; +}; + +/*! @name Structure to store accelerometer data deviation from ideal value */ +struct offset_delta { + /*! X axis */ + int16_t x; + /*! Y axis */ + int16_t y; + /*! Z axis */ + int16_t z; +}; + +/*! @name Structure to store accelerometer offset values */ +struct accel_offset { + /*! offset X data */ + uint8_t x; + /*! offset Y data */ + uint8_t y; + /*! offset Z data */ + uint8_t z; +}; + +/******************************************************************************/ +/*! Local Function Prototypes +******************************************************************************/ + +/*! + * @brief This internal API writes the configuration file. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t write_config_file(struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables the loading of the configuration + * file. + * + * @param[in] enable : To enable/disable configuration load. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_config_load(uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This internal API loads the configuration file. + * + * @param[in] config_data : Pointer to the configuration file. + * @param[in] index : Variable to define array index. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t upload_file(const uint8_t *config_data, uint16_t index, const struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the selected sensor/features. + * + * @param[in] sensor_sel : Selects the desired sensor. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +static int8_t sensor_enable(uint32_t sensor_sel, struct bmi2_dev *dev); + +/*! + * @brief This internal API disables the selected sensor/features. + * + * @param[in] sensor_sel : Selects the desired sensor. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +static int8_t sensor_disable(uint32_t sensor_sel, struct bmi2_dev *dev); + +/*! + * @brief This internal API selects the sensors/features to be enabled or + * disabled. + * + * @param[in] sens_list : Pointer to select the sensor. + * @param[in] n_sens : Number of sensors selected. + * @param[out] sensor_sel : Gets the selected sensor. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t select_sensor(const uint8_t *sens_list, uint8_t n_sens, uint32_t *sensor_sel); + +/*! + * @brief This internal API is used to enable/disable any-motion feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables any-motion. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables any-motion. + * BMI2_ENABLE | Enables any-motion. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_any_motion(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable no-motion feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables no-motion. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables no-motion. + * BMI2_ENABLE | Enables no-motion. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_no_motion(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable sig-motion feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables sig-motion. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables sig-motion. + * BMI2_ENABLE | Enables sig-motion. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_sig_motion(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable step detector feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables step-detector. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables step detector + * BMI2_ENABLE | Enables step detector + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_detector(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable step counter feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables step counter. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables step counter + * BMI2_ENABLE | Enables step counter + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_counter(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable step activity detection. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables step activity. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables step activity + * BMI2_ENABLE | Enables step activity + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_activity(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable tilt feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables tilt. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables tilt + * BMI2_ENABLE | Enables tilt + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_tilt(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable pick-up feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables pick-up. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables pick-up + * BMI2_ENABLE | Enables pick-up + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_pick_up(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable glance detector feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables glance. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables glance detector + * BMI2_ENABLE | Enables glance detector + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_glance_detector(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable wake-up feature through + * single or double tap. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables single or double tap. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables single/double tap. + * BMI2_ENABLE | Enables single/double tap + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wake_up(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable orientation feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables orientation. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables orientation + * BMI2_ENABLE | Enables orientation + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_orientation(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable high-g feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables high-g. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables high-g + * BMI2_ENABLE | Enables high-g + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_high_g(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable low-g feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables low-g. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables low-g + * BMI2_ENABLE | Enables low-g + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_low_g(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable flat feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables flat. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables flat + * BMI2_ENABLE | Enables flat + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_flat(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable ext-sensor-sync feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables ext-sensor-sync. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables ext-sensor-sync + * BMI2_ENABLE | Enables ext-sensor-sync + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_ext_sens_sync(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API gives an option to enable offset correction +* feature of gyroscope, either internally or by the host. + * + * @param[in] enable : Enables/Disables self-offset correction. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | gyroscope offset correction values are set internally + * BMI2_DISABLE | gyroscope offset correction values has to be set by host + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_gyro_self_offset_corr(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to enable/disable gyroscope user gain + * feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables gyroscope user gain. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables gyroscope user gain + * BMI2_ENABLE | Enables gyroscope user gain + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_gyro_user_gain(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the wrist gesture feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables wrist gesture. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables wrist gesture + * BMI2_ENABLE | Enables wrist gesture + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_gesture(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables the wrist wear wake up feature. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in] enable : Enables/Disables wrist wear wake up. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables wrist wear wake up + * BMI2_ENABLE | Enables wrist wear wake up + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_wear_wake_up(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables the activity recognition feature. + * + * @param[in] enable : Enables/Disables activity recognition. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enables activity recognition. + * BMI2_DISABLE | Disables activity recognition. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_act_recog(uint8_t enable, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + * + * @param[in,out] config : Structure instance of bmi2_accel_config. + * @param[in,out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_ACC_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_ACC_GYR_INVALID_CFG - Error: Invalid accelerometer and + * gyroscope configuration + * + */ +static int8_t set_accel_config(struct bmi2_accel_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates bandwidth and performance mode of the + * accelerometer set by the user. + * + * @param[in, out] bandwidth : Pointer to bandwidth value set by the user. + * @param[in, out] perf_mode : Pointer to performance mode set by the user. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t validate_bw_perf_mode(uint8_t *bandwidth, uint8_t *perf_mode, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates ODR and range of the accelerometer set by + * the user. + * + * @param[in, out] odr : Pointer to ODR value set by the user. + * @param[in, out] range : Pointer to range value set by the user. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t validate_odr_range(uint8_t *odr, uint8_t *range, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets gyroscope configurations like ODR, bandwidth, + * low power/high performance mode, performance mode and range. + * + * @param[in,out] config : Structure instance of bmi2_gyro_config. + * @param[in,out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_GYRO_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_ACC_GYR_INVALID_CFG - Error: Invalid accelerometer and + * gyroscope configuration + */ +static int8_t set_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API validates bandwidth, performance mode, low power/ + * high performance mode, ODR, and range set by the user. + * + * @param[in] config : Structure instance of bmi2_gyro_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t validate_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API shows the error status when illegal sensor + * configuration is set. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_ACC_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_GYRO_INVALID_CFG - Error: Invalid accelerometer configuration + * @retval BMI2_E_ACC_GYR_INVALID_CFG - Error: Invalid accelerometer and + * gyroscope configuration + */ +static int8_t cfg_error_status(const struct bmi2_dev *dev); + +/*! + * @brief This internal API: + * 1) Enables/Disables auxiliary interface. + * 2) Sets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3)It maps/un-maps data interrupts to that of hardware interrupt line. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t set_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables auxiliary interface. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_aux_interface(const struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API sets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Auxiliary sensor should not be busy when configuring aux_i2c_addr, + * man_rd_burst_len, aux_rd_burst_len and aux_rd_addr. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t config_aux_interface(const struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API triggers read out offset and sets ODR of the + * auxiliary sensor. + * + * @param[in] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t config_aux(const struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API validates auxiliary configuration set by the user. + * + * @param[in, out] config : Structure instance of bmi2_aux_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @note dev->info contains two warnings: BMI2_I_MIN_VALUE and BMI2_I_MAX_VALUE + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t validate_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets any-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[in] config : Structure instance of bmi2_any_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_any_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_any_motion_config(const struct bmi2_any_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets no-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[in] config : Structure instance of bmi2_no_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_no_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_no_motion_config(const struct bmi2_no_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets sig-motion configurations like block-size, + * output-configuration and other parameters. + * + * @param[in] config : Structure instance of bmi2_sig_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + *---------------------------------------------------------------------------- + * bmi2_sig_motion_config | + * Structure parameters | Description + * -------------------------|--------------------------------------------------- + * | Defines the duration after which the significant + * block_size | motion interrupt is triggered. It is expressed in + * | 50 Hz samples (20 ms). Default value is 0xFA=5sec. + *--------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + *--------------------------|--------------------------------------------------- + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_sig_motion_config(const struct bmi2_sig_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets step counter/detector/activity configurations. + * + * @param[in] config : Structure instance of bmi2_step_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + *--------------------------------------------------------------------------- + * bmi2_step_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | The Step-counter will trigger output every time + * | the number of steps are counted. Holds implicitly + * water-mark level | a 20x factor, so the range is 0 to 10230, + * | with resolution of 20 steps. + * -------------------------|--------------------------------------------------- + * reset counter | Flag to reset the counted steps. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_det_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step detector. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_act_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step activity. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_step_config(const struct bmi2_step_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + * + * @param[in] config : Structure instance of bmi2_gyro_user_gain_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + *bmi2_gyro_user_gain_config| + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * ratio_x | Gain update value for x-axis + * -------------------------|--------------------------------------------------- + * ratio_y | Gain update value for y-axis + * -------------------------|--------------------------------------------------- + * ratio_z | Gain update value for z-axis + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_gyro_user_gain_config(const struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets tilt configurations like output-configuration. + * + * @param[in] config : Structure instance of bmi2_tilt_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_tilt_config | + * Structure parameters | Description + *------------------------- |-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * ------------------------ |--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_tilt_config(const struct bmi2_tilt_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets pick-up configurations like output + * configuration. + * + * @param[in] config : Structure instance of bmi2_pick_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_pick_up_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_pick_up_config(const struct bmi2_pick_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets glance detector configurations like output + * configuration. + * + * @param[in] config : Structure instance of bmi2_glance_det_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_glance_det_config| + * Structure parameters | Description + *-------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * ------------------------|---------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_glance_detect_config(const struct bmi2_glance_det_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + * + * @param[in] config : Structure instance of bmi2_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wake_up_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Configures wake-up sensitivity, the range goes + * sensitivity | from 0 (high sensitive) to 7 (low sensitive). + * -------------------------|--------------------------------------------------- + * | Enable - Single Tap detection + * single_tap_en | Disable- Double Tap detection (Default value) + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wake_up_config(const struct bmi2_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + * + * @param[in] config : Structure instance of bmi2_orient_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_orient_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * upside/down | Enables upside/down detection, if set to 1. + * detection | + * -------------------------|--------------------------------------------------- + * | Sets the mode: + * mode | Values 0 or 3 - symmetrical. + * | Value 1 - high asymmetrical + * | Value 2 - low asymmetrical + * -------------------------|--------------------------------------------------- + * | Enable - no orientation interrupt will be set. + * blocking | Default value: 3, the most restrictive blocking. + * -------------------------|--------------------------------------------------- + * | Threshold angle used in blocking mode. + * theta | Theta = 64 * (tan(angle)^2) + * | Default value: 40, equivalent to 38 degrees angle. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for Orientation detection + * | is expressed in 5.11g format. + * hysteresis | Default value is 128 = 0.0625g. + * | Range is 0 to 1g. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_orient_config(const struct bmi2_orient_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets high-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[in] config : Structure instance of bmi2_high_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_high_g_config | + * Structure parameter | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | high_g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * | Range is 0 to 16g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for high-g detection + * | is expressed in 1.11g format. + * hysteresis | Default value is 256 = 0.125 g. + * | Range is 0 to 2g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 200 Hz samples (5 ms) for + * | which the threshold has to be exceeded. + * duration | Default value 4 = 20 msec. + * | Range is 0 to 20sec. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_high_g_config(const struct bmi2_high_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[in] config : Structure instance of bmi2_low_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_low_g_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | low-g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for low-g detection + * hysteresis | is expressed in 1.11g format. + * | Default value is 512 = 0.250 g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50 Hz samples (20 ms) for + * | which the threshold has to be exceeded. + * duration | Default value 0 = 1 validation sample = (0+1)*20 + * | = 20 ms. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_low_g_config(const struct bmi2_low_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + * + * @param[in] config : Structure instance of bmi2_flat_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_flat_config | + * Structure parameters| Description + *--------------------------|-------------------------------------------------- + * | Sets the theta angle, used for detecting flat + * | position. + * theta | Theta = 64 * (tan(angle)^2); + * | Default value is 8, equivalent to 20 degrees angle + * -------------------------|--------------------------------------------------- + * | Hysteresis for Theta Flat detection. + * hysteresis | Default value is 9 = 2.5 degrees, corresponding + * | to the default Theta angle of 20 degrees. + * -------------------------|--------------------------------------------------- + * | Sets the blocking mode. If blocking is set, no + * | Flat interrupt will be triggered. + * blocking | Default value is 2, the most restrictive blocking + * | mode. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50Hz samples for which the + * | condition has to be respected. + * hold-time | Default value is 32 = 640 m-sec. + * | Range is 0 to 5.1 sec. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_flat_config(const struct bmi2_flat_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets external sensor sync configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_ext_sens_sync_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + *---------------------------------------------------------------------------- + * bmi2_ext_sens_sync_config | + * Structure parameters | Description + * -----------------------------|---------------------------------------------- + * |Enable bits for enabling output into the + * out_conf |register status bits and, if desired, onto the + * |interrupt pin. + * -----------------------------|---------------------------------------------- + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_ext_sens_sync_config(const struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wrist gesture configurations like wearable-arm, + * and output-configuration. + * + * @param[in] config : Structure instance of bmi2_wrist_gest_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_gest_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Device in left (0) or right (1) arm. By default, + * wear_arm | the wearable device is assumed to be in left arm + * | i.e. default value is 0. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_gest_config(const struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets wrist wear wake-up configurations like + * output-configuration. + * + * @param[in] config : Structure instance of + * bmi2_wrist_wear_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_wear_wake_up_config | + * Structure parameters | Description + *----------------------------------|------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto + * | the interrupt pin. + * ---------------------------------|------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_wrist_wear_wake_up_config(const struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + * + * @param[out] config : Structure instance of bmi2_accel_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t get_accel_config(struct bmi2_accel_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets gyroscope configurations like ODR, bandwidth, + * low power/ high performance mode, performance mode and range. + * + * @param[out] config : Structure instance of bmi2_gyro_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_config(struct bmi2_gyro_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API: + * 1) Gets the status of auxiliary interface enable. + * 2) Gets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3) Gets ODR and offset. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the enable status of auxiliary interface. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_interface(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_interface_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets read out offset and ODR of the auxiliary + * sensor. + * + * @param[out] config : Structure instance of bmi2_aux_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_aux_cfg(struct bmi2_aux_config *config, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets any-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[out] config : Structure instance of bmi2_any_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_any_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_any_motion_config(struct bmi2_any_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets no-motion configurations like axes select, + * duration, threshold and output-configuration. + * + * @param[out] config : Structure instance of bmi2_no_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_no_motion_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Defines the number of consecutive data points for + * | which the threshold condition must be respected, + * | for interrupt assertion. It is expressed in 50 Hz + * duration | samples (20 msec). + * | Range is 0 to 163sec. + * | Default value is 5 = 100ms. + * -------------------------|--------------------------------------------------- + * | Slope threshold value for in 5.11g format. + * threshold | Range is 0 to 1g. + * | Default value is 0xAA = 83mg. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_no_motion_config(struct bmi2_no_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets sig-motion configurations like block-size, + * output-configuration and other parameters. + * + * @param[out] config : Structure instance of bmi2_sig_motion_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + *---------------------------------------------------------------------------- + * bmi2_sig_motion_config | + * Structure parameters | Description + * -------------------------|--------------------------------------------------- + * | Defines the duration after which the significant + * block_size | motion interrupt is triggered. It is expressed in + * | 50 Hz samples (20 ms). Default value is 0xFA=5sec. + *--------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + *--------------------------|--------------------------------------------------- + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_sig_motion_config(struct bmi2_sig_motion_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets step counter/detector/activity configurations. + * + * @param[out] config : Structure instance of bmi2_step_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_step_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | The Step-counter will trigger output every time + * | the number of steps are counted. Holds implicitly + * water-mark level | a 20x factor, so the range is 0 to 10230, + * | with resolution of 20 steps. + * -------------------------|--------------------------------------------------- + * reset counter | Flag to reset the counted steps. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_det_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step detector. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * step_act_out_conf | register status bits and, if desired, onto the + * | interrupt pin for step activity. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_config(struct bmi2_step_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + * + * @param[out] config : Structure instance of bmi2_gyro_user_gain_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + *bmi2_gyro_user_gain_config| + * Structure parameters | Description + *-------------------------|-------------------------------------------------- + * ratio_x | Gain update value for x-axis + * ------------------------|--------------------------------------------------- + * ratio_y | Gain update value for y-axis + * ------------------------|--------------------------------------------------- + * ratio_z | Gain update value for z-axis + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_gain_update_config(struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets tilt configurations like output-configuration. + * + * @param[out] config : Structure instance of bmi2_tilt_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_tilt_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_tilt_config(struct bmi2_tilt_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets pick-up configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_pick_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_pick_up_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_pick_up_config(struct bmi2_pick_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets glance detector configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_glance_det_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_glance_det_config| + * Structure parameters | Description + *-------------------------|-------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * ------------------------|---------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_glance_detect_config(struct bmi2_glance_det_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + * + * @param[out] config : Structure instance of bmi2_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wake_up_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Configures wake-up sensitivity, the range goes + * sensitivity | from 0 (high sensitive) to 7 (low sensitive). + * -------------------------|--------------------------------------------------- + * | Enable - Single Tap detection + * single_tap_en | Disable- Double Tap detection (Default value) + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wake_up_config(struct bmi2_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wrist gesture configurations like wearable-arm, + * and output-configuration. + * + * @param[out] config : Structure instance of bmi2_wrist_gest_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_gest_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * | Device in left (0) or right (1) arm. By default, + * wear_arm | the wearable device is assumed to be in left arm + * | i.e. default value is 0. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_gest_config(struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets wrist wear wake-up configurations like + * output-configuration. + * + * @param[out] config : Structure instance of + * bmi2_wrist_wear_wake_up_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_wrist_wear_wake_up_config | + * Structure parameters | Description + *----------------------------------|------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto + * | the interrupt pin. + * ---------------------------------|------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_wear_wake_up_config(struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + * + * @param[out] config : Structure instance of bmi2_orient_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_orient_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * upside/down | Enables upside/down detection, if set to 1. + * detection | + * -------------------------|--------------------------------------------------- + * | Sets the mode: + * mode | Values 0 or 3 - symmetrical. + * | Value 1 - high asymmetrical + * | Value 2 - low asymmetrical + * -------------------------|--------------------------------------------------- + * | Enable - no orientation interrupt will be set. + * blocking | Default value: 3, the most restrictive blocking. + * -------------------------|--------------------------------------------------- + * | Threshold angle used in blocking mode. + * theta | Theta = 64 * (tan(angle)^2) + * | Default value: 40, equivalent to 38 degrees angle. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for Orientation detection + * | is expressed in 5.11g format. + * hysteresis | Default value is 128 = 0.0625g. + * | Range is 0 to 1g. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_orient_config(struct bmi2_orient_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets high-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[out] config : Structure instance of bmi2_high_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *----------------------------------------------------------------------------- + * bmi2_high_g_config | + * Structure parameter | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | high_g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * | Range is 0 to 16g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for high-g detection + * | is expressed in 1.11g format. + * hysteresis | Default value is 256 = 0.125 g. + * | Range is 0 to 2g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 200 Hz samples (5 ms) for + * | which the threshold has to be exceeded. + * duration |Default value 4 = 20 msec. + * | Range is 0 to 20sec. + * -------------------------|--------------------------------------------------- + * x_sel, y_sel, z_sel | Selects the feature on a per-axis basis + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_high_g_config(struct bmi2_high_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + * + * @param[out] config : Structure instance of bmi2_low_g_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + * bmi2_low_g_config | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * threshold | The acceleration threshold above which the + * | low-g motion is signaled. + * | Holds threshold in 5.11 g format. + * | Default is 3072 = 1.5 g. + * -------------------------|--------------------------------------------------- + * | Acceleration hysteresis for low-g detection + * hysteresis | is expressed in 1.11g format. + * | Default value is 512 = 0.250 g. + * | Should be smaller than threshold. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50 Hz samples (20 ms) for + * | which the threshold has to be exceeded. + * duration | Default value 0 = 1 validation sample = (0+1)*20 + * | = 20 ms. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_low_g_config(struct bmi2_low_g_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + * + * @param[out] config : Structure instance of bmi2_flat_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_flat_config | + * Structure parameters| Description + *--------------------------|-------------------------------------------------- + * | Theta angle, used for detecting flat + * | position. + * theta | Theta = 64 * (tan(angle)^2); + * | Default value is 8, equivalent to 20 degrees angle + * -------------------------|--------------------------------------------------- + * | Hysteresis for Theta Flat detection. + * hysteresis | Default value is 9 = 2.5 degrees, corresponding + * | to the default Theta angle of 20 degrees. + * -------------------------|--------------------------------------------------- + * | Sets the blocking mode. If blocking is set, no + * | Flat interrupt will be triggered. + * blocking | Default value is 2, the most restrictive blocking + * | mode. + * -------------------------|--------------------------------------------------- + * | Holds the duration in 50Hz samples for which the + * | condition has to be respected. + * hold-time | Default value is 32 = 640 m-sec. + * | Range is 0 to 5.1 sec. + * -------------------------|--------------------------------------------------- + * | Enable bits for enabling output into the + * out_conf | register status bits and, if desired, onto the + * | interrupt pin. + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_flat_config(struct bmi2_flat_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets external sensor sync configurations like output + * configuration. + * + * @param[out] config : Structure instance of bmi2_ext_sens_sync_config. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @verbatim + *---------------------------------------------------------------------------- + * bmi2_ext_sens_sync_config | + * Structure parameters | Description + * -----------------------------|---------------------------------------------- + * |Enable bits for enabling output into the + * out_conf |register status bits and, if desired, onto the + * |interrupt pin. + * -----------------------------|---------------------------------------------- + * @endverbatim + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_ext_sens_sync_config(struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the accelerometer data from the register. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] reg_addr : Register address where data is stored. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t get_accel_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the gyroscope data from the register. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] reg_addr : Register address where data is stored. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t get_gyro_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the accelerometer/gyroscope data. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] reg_data : Data stored in the register. + * + * @return None + * + * @retval None + */ +static void get_acc_gyr_data(struct bmi2_sens_axes_data *data, const uint8_t *reg_data); + +/*! + * @brief This internal API gets the re-mapped accelerometer/gyroscope data. + * + * @param[out] data : Structure instance of sensor_data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * + * @retval None + */ +static void get_remapped_data(struct bmi2_sens_axes_data *data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in data mode. + * + * @param[out] aux_data : Pointer to the stored auxiliary data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration + */ +static int8_t read_aux_data_mode(uint8_t *aux_data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in manual mode. + * + * @param[in] reg_addr : AUX address from where data is read. + * @param[out] aux_data : Pointer to the stored auxiliary data. + * @param[in] len : Total bytes to be read. + * @param[in] burst_len : Bytes of data to be read in bursts. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t read_aux_data(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, uint8_t burst_len, const struct bmi2_dev *dev); + +/*! + * @brief This internal API checks the busy status of auxiliary sensor and sets + * the auxiliary register addresses when not busy. + * + * @param[in] reg_addr : Address in which AUX register address is + * set. + * @param[in] reg_data : Auxiliary register address to be set when AUX is + * not busy. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t set_if_aux_not_busy(uint8_t reg_addr, uint8_t reg_data, const struct bmi2_dev *dev); + +/*! + * @brief his internal API maps the actual burst read length with that of the + * register value set by user. + * + * @param[out] len : Actual burst length. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration + */ +static int8_t map_read_len(uint8_t *len, const struct bmi2_dev *dev); + +/*! + * @brief This internal API writes AUX write address and the user-defined bytes + * of data to the AUX sensor in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + * + * @param[in] reg_addr : AUX address in which data is to be written. + * @param[in] reg_data : Data to be written + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_AUX_BUSY - Error: Auxiliary sensor is busy + */ +static int8_t write_aux_data(uint8_t reg_addr, uint8_t reg_data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of step counter. + * + * @param[out] step_count : Pointer to the stored step counter data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_counter_output(uint32_t *step_count, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of step activity. + * + * @param[out] step_act : Pointer to the stored step activity data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * *step_act | Output + * -----------|------------ + * 0x00 | STILL + * 0x01 | WALKING + * 0x02 | RUNNING + * 0x03 | UNKNOWN + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_step_activity_output(uint8_t *step_act, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of orientation: portrait- + * landscape and face up-down. + * + * @param[out] orient_out : Structure pointer to the orientation data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * + * portrait | + * landscape | Output + * -----------|------------ + * 0x00 | PORTRAIT UPRIGHT + * 0x01 | LANDSCAPE LEFT + * 0x02 | PORTRAIT UPSIDE DOWN + * 0x03 | LANDSCAPE RIGHT + * + * Face | + * up-down | Output + * -----------|------------ + * 0x00 | FACE-UP + * 0x01 | FACE-DOWN + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_orient_output(struct bmi2_orientation_output *orient_out, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of high-g. + * + * @param[out] high_g_out : Pointer to the stored high-g output. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_high_g_output(uint8_t *high_g_out, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the output values of wrist gesture. + * + * @param[out] wrist_gest : Pointer to the stored wrist gesture. + * @param[in] dev : Structure instance of bmi2_dev. + * + * *wrist_gest | Output + * -------------|------------ + * 0x00 | UNKNOWN + * 0x01 | PUSH_ARM_DOWN + * 0x02 | PIVOT_UP + * 0x03 | WRIST_SHAKE_JIGGLE + * 0x04 | FLICK_IN + * 0x05 | FLICK_OUT + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_wrist_gest_status(uint8_t *wrist_gest, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the cross sensitivity coefficient between + * gyroscope's X and Z axes. + * + * @param[out] cross_sense : Pointer to the stored cross sensitivity + * coefficient. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_cross_sense(int16_t *cross_sense, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the saturation status for the gyroscope user + * gain update. + * + * @param[out] user_gain_stat : Stores the saturation status of the axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_gyro_gain_update_status(struct bmi2_gyr_user_gain_status *user_gain, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the error status related to NVM. + * + * @param[out] nvm_err_stat : Stores the NVM error status. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_nvm_error_status(struct bmi2_nvm_err_status *nvm_err_stat, struct bmi2_dev *dev); + +/*! + * @brief This internal API gets the error status related to virtual frames. + * + * @param[out] vfrm_err_stat : Stores the VFRM related error status. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_vfrm_error_status(struct bmi2_vfrm_err_status *vfrm_err_stat, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse and store the activity recognition + * output from the FIFO data. + * + * @param[out] act_recog : Structure to retrieve output of activity + * recognition frame. + * @param[in] data_index : Index of the FIFO data which contains + * activity recognition frame. + * @param[out] fifo : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_act_recog_output(struct bmi2_act_recog_output *act_recog, uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + + +/*! + * @brief This internal API is used to get enable status of gyroscope user gain + * update. + * + * @param[out] status : Stores status of gyroscope user gain update. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_user_gain_upd_status(uint8_t *status, struct bmi2_dev *dev); + +/*! + * @brief This internal API maps/unmaps feature interrupts to that of interrupt + * pins. + * + * @param[in] int_pin : Interrupt pin selected. + * @param[in] feat_int : Type of feature interrupt to be mapped or the value + * of out_conf. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_FEAT_INT - Error: Invalid feature Interrupt + */ +static int8_t map_feat_int(uint8_t *reg_data_array, enum bmi2_hw_int_pin int_pin, uint8_t int_mask); + +/*! + * @brief This internal API computes the number of bytes of accelerometer FIFO + * data which is to be parsed in header-less mode. + * + * @param[out] start_idx : The start index for parsing data. + * @param[out] len : Number of bytes to be parsed. + * @param[in] acc_count : Number of accelerometer frames to be read. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + */ +static int8_t parse_fifo_accel_len(uint16_t *start_idx, uint16_t *len, const uint16_t *acc_count, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse accelerometer data from the FIFO + * data in header mode. + * + * @param[out] acc : Structure instance of bmi2_sens_axes_data where + * the parsed accelerometer data bytes are stored. + * @param[in] accel_length : Number of accelerometer frames (x,y,z data). + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t extract_accel_header_mode(struct bmi2_sens_axes_data *acc, uint16_t *accel_length, + struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); +/*! + * @brief This internal API is used to parse the accelerometer data from the + * FIFO data in both header and header-less mode. It updates the current data + * byte to be parsed. + * + * @param[in,out] acc : Structure instance of bmi2_sens_axes_data where + * where the parsed data bytes are stored. + * @param[in,out] idx : Index value of number of bytes parsed. + * @param[in,out] acc_idx : Index value of accelerometer data (x,y,z axes) + * frame to be parsed. + * @param[in] frame : Either data is enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_accel_frame(struct bmi2_sens_axes_data *acc, uint16_t *idx, uint16_t *acc_idx, uint8_t frame, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse accelerometer data from the FIFO + * data. + * + * @param[out] acc : Structure instance of bmi2_sens_axes_data + * where the parsed data bytes are stored. + * @param[in] data_start_index : Index value of the accelerometer data bytes + * which is to be parsed from the FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void unpack_accel_data(struct bmi2_sens_axes_data *acc, uint16_t data_start_index, const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API computes the number of bytes of gyroscope FIFO data + * which is to be parsed in header-less mode. + * + * @param[out] start_idx : The start index for parsing data. + * @param[out] len : Number of bytes to be parsed. + * @param[in] gyr_count : Number of gyroscope frames to be read. + * @param[in] frame : Either data enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + */ +static int8_t parse_fifo_gyro_len(uint16_t *start_idx, uint16_t (*len), const uint16_t *gyr_count, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + + +/*! + * @brief This internal API is used to parse the gyroscope data from the FIFO + * data in both header and header-less mode It updates the current data byte to + * be parsed. + * + * @param[in,out] gyr : Structure instance of bmi2_sens_axes_data. + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] gyr_idx : Index value of gyroscope data (x,y,z axes) + * frame to be parsed. + * @param[in] frame : Either data is enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_gyro_frame(struct bmi2_sens_axes_data *gyr, uint16_t *idx, uint16_t *gyr_idx, uint8_t frame, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse gyroscope data from the FIFO data. + * + * @param[out] gyr : Structure instance of bmi2_sens_axes_data where + * the parsed gyroscope data bytes are stored. + * @param[in] data_start_index : Index value of the gyroscope data bytes + * which is to be parsed from the FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void unpack_gyro_data(struct bmi2_sens_axes_data *gyr, uint16_t data_start_index, const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse the gyroscope data from the + * FIFO data in header mode. + * + * @param[out] gyr : Structure instance of bmi2_sens_axes_data where + * the parsed gyroscope data bytes are stored. + * @param[in] gyro_length : Number of gyroscope frames (x,y,z data). + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t extract_gyro_header_mode(struct bmi2_sens_axes_data *gyr, uint16_t *gyro_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API computes the number of bytes of auxiliary FIFO data + * which is to be parsed in header-less mode. + * + * @param[out] start_idx : The start index for parsing data. + * @param[out] len : Number of bytes to be parsed. + * @param[in] aux_count : Number of accelerometer frames to be read. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + */ +static int8_t parse_fifo_aux_len(uint16_t *start_idx, uint16_t (*len), const uint16_t *aux_count, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This API is used to parse auxiliary data from the FIFO data. + * + * @param[out] aux : Pointer to buffer where the parsed auxiliary data + * bytes are stored. + * @param[in] aux_length : Number of auxiliary frames (x,y,z data). + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t extract_aux_header_mode(struct bmi2_aux_fifo_data *aux, uint16_t *aux_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API is used to parse the auxiliary data from the FIFO data in + * both header and header-less mode. It updates the current data byte to be + * parsed. + * + * @param[out] aux : Pointer to structure where the parsed auxiliary data + * bytes are stored. + * @param[in,out] idx : Index value of number of bytes parsed + * @param[in,out] aux_idx : Index value of auxiliary data (x,y,z axes) + * frame to be parsed + * @param[in] frame : Either data is enabled by user in header-less + * mode or header frame value in header mode. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_aux_frame(struct bmi2_aux_fifo_data *aux, uint16_t *idx, uint16_t *aux_idx, uint8_t frame, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This API is used to parse auxiliary data from the FIFO data. + * + * @param[out] aux : Pointer to structure where the parsed + * auxiliary data bytes are stored. + * @param[in] data_start_index : Index value of the auxiliary data bytes which + * is to be parsed from the FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void unpack_aux_data(struct bmi2_aux_fifo_data *aux, uint16_t data_start_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to reset the FIFO related configurations + * in the FIFO frame structure for the next FIFO read. + * + * @param[in, out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void reset_fifo_frame_structure(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * @brief This internal API checks whether the FIFO data read is an empty frame. + * If empty frame, index is moved to the last byte. + * + * @param[in,out] data_index : The index of the current data to be parsed from + * FIFO data. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t check_empty_fifo(uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to move the data index ahead of the + * current frame length parameter when unnecessary FIFO data appears while + * extracting the user specified data. + * + * @param[in,out] data_index : Index of the FIFO data which is to be + * moved ahead of the current frame length + * @param[in] current_frame_length : Number of bytes in the current frame. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to parse and store the sensor time from the + * FIFO data. + * + * @param[in,out] data_index : Index of the FIFO data which has the sensor time. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_sensortime_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API is used to parse and store the skipped frame count + * from the FIFO data. + * + * @param[in,out] data_index : Index of the FIFO data which contains skipped + * frame count. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t unpack_skipped_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API enables and configures the accelerometer which is + * needed for self test operation. It also sets the amplitude for the self-test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t pre_self_test_config(struct bmi2_dev *dev); + +/*! + * @brief This internal API performs the steps needed for self test operation + * before reading the accelerometer self test data. + * + * @param[in] sign : Selects sign of self-test excitation + * @param[in] dev : Structure instance of bmi2_dev. + * + * sign | Description + * -------------|--------------- + * BMI2_ENABLE | positive excitation + * BMI2_DISABLE | negative excitation + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t self_test_config(uint8_t sign, const struct bmi2_dev *dev); + +/*! + * @brief This internal API enables or disables the accelerometer self test + * feature in the sensor. + * + * @param[in] enable : Enables/ Disables self-test. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sign | Description + * -------------|--------------- + * BMI2_ENABLE | Enables self-test + * BMI2_DISABLE | Disables self-test + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_accel_self_test_enable(uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This internal API selects the sign for accelerometer self-test + * excitation. + * + * @param[in] sign : Selects sign of self-test excitation + * @param[in] dev : Structure instance of bmi2_dev. + * + * sign | Description + * -------------|--------------- + * BMI2_ENABLE | positive excitation + * BMI2_DISABLE | negative excitation + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_acc_self_test_sign(uint8_t sign, const struct bmi2_dev *dev); + +/*! + * @brief This internal API sets the amplitude of the accelerometer self test + * deflection in the sensor. + * + * @param[in] amp : Select amplitude of the self-test deflection. + * @param[in] dev : Structure instance of bmi2_dev. + * + * amp | Description + * -------------|--------------- + * BMI2_ENABLE | self-test amplitude is high + * BMI2_DISABLE | self-test amplitude is low + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_accel_self_test_amp(uint8_t amp, const struct bmi2_dev *dev); + +/*! + * @brief This internal API reads the accelerometer data for x,y and z axis from + * the sensor. The data units is in LSB format. + * + * @param[out] accel : Buffer to store the acceleration value. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t read_accel_xyz(struct bmi2_sens_axes_data *accel, const struct bmi2_dev *dev); + +/*! + * @brief This internal API converts LSB value of accelerometer axes to form + * 'g' to 'mg' for self-test. + * + * @param[in] acc_data_diff : Stores the acceleration value difference in g. + * @param[out]acc_data_diff_mg : Stores the acceleration value difference in mg. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return None + * @retval None + */ +static void convert_lsb_g(const struct selftest_delta_limit *acc_data_diff, struct selftest_delta_limit *acc_data_diff_mg, + const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to calculate the power of a value. + * + * @param[in] base : base for power calculation. + * @param[in] resolution : exponent for power calculation. + * + * @return the calculated power + * @retval the power value + */ +static int32_t power(int16_t base, uint8_t resolution); + +/*! + * @brief This internal API validates the accelerometer self-test data and + * decides the result of self test operation. + * + * @param[in] accel_data_diff : Stores the acceleration value difference. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_SELF_TEST_FAIL - Error: Self-test fail + */ +static int8_t validate_self_test(const struct selftest_delta_limit *accel_data_diff); + +/*! + * @brief This internal API gets the re-mapped x, y and z axes from the sensor. + * + * @param[out] remap : Structure that stores local copy of re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_remap_axes(struct axes_remap *remap, struct bmi2_dev *dev); + +/*! + * @brief This internal API sets the re-mapped x, y and z axes in the sensor. + * + * @param[in] remap : Structure that stores local copy of re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t set_remap_axes(const struct axes_remap *remap, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to get the feature configuration from the + * selected page. + * + * @param[in] sw_page : Switches to the desired page. + * @param[out] feat_config : Pointer to the feature configuration. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +static int8_t get_feat_config(uint8_t sw_page, uint8_t *feat_config, struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables compensation of the gain defined + * in the GAIN register. + * + * @param[in] enable : Enables/Disables gain compensation + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enable gain compensation. + * BMI2_DISABLE | Disable gain compensation. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t enable_gyro_gain(uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This internal API parses virtual frame header from the FIFO data. + * + * @param[in, out] frame_header : FIFO frame header. + * @param[in, out] data_index : Index value of the FIFO data bytes + * from which sensor frame header is to be parsed + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void parse_if_virtual_header(uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API gets sensor time from the accelerometer and + * gyroscope virtual frames and updates in the data structure. + * + * @param[out] sens : Sensor data structure + * @param[in, out] idx : Index of FIFO from where the data is to retrieved. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void unpack_virt_sensor_time(struct bmi2_sens_axes_data *sens, uint16_t *idx, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API gets sensor time from the auxiliary virtual + * frames and updates in the data structure. + * + * @param[out] aux : Auxiliary sensor data structure + * @param[in, out] idx : Index of FIFO from where the data is to retrieved. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return None + * @retval None + */ +static void unpack_virt_aux_sensor_time(struct bmi2_aux_fifo_data *aux, uint16_t *idx, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API skips S4S frame in the FIFO data while getting + * activity recognition output. + * + * @param[in, out] frame_header : FIFO frame header. + * @param[in, out] data_index : Index value of the FIFO data bytes + * from which S4S frame header is to be + * skipped. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +static int8_t move_if_s4s_frame(const uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo); + +/*! + * @brief This internal API corrects the gyroscope cross-axis sensitivity + * between the z and the x axis. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[out] gyr_data : Structure instance of gyroscope data + * + * @return Result of API execution status + * + * @return None + * @retval None + */ +static void comp_gyro_cross_axis_sensitivity(struct bmi2_sens_axes_data *gyr_data, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to extract the input feature configuration + * details like page and start address from the look-up table. + * + * @param[out] feat_config : Structure that stores feature configurations. + * @param[in] type : Type of feature or sensor. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Returns the feature found flag. + * + * @retval BMI2_FALSE : Feature not found + * BMI2_TRUE : Feature found + */ +static uint8_t extract_input_feat_config(struct bmi2_feature_config *feat_config, uint8_t type, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to extract the output feature configuration + * details like page and start address from the look-up table. + * + * @param[out] feat_output : Structure that stores output feature + * configurations. + * @param[in] type : Type of feature or sensor. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Returns the feature found flag. + * + * @retval BMI2_FALSE : Feature not found + * BMI2_TRUE : Feature found + */ +static uint8_t extract_output_feat_config(struct bmi2_feature_config *feat_output, uint8_t type, const struct bmi2_dev *dev); + +/*! + * @brief This internal API saves the configurations before performing FOC. + * + * @param[out] acc_cfg : Accelerometer configuration value + * @param[out] aps : Advance power mode value + * @param[out] acc_en : Accelerometer enable value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t save_accel_foc_config(struct bmi2_accel_config *acc_cfg, uint8_t *aps, uint8_t *acc_en, const struct bmi2_dev *dev); + +/*! + * @brief This internal sets configurations for performing accelerometer FOC. + * + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t set_accel_foc_config(struct bmi2_dev *dev); + +/*! + * @brief This internal API enables/disables the offset compensation for + * filtered and un-filtered accelerometer data. + * + * @param[in] offset_en : enables/disables offset compensation. + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t set_accel_offset_comp(uint8_t offset_en, const struct bmi2_dev *dev); + +/*! + * @brief This internal API converts the range value into accelerometer + * corresponding integer value. + * + * @param[in] range_in : Input range value. + * @param[out] range_out : Stores the integer value of range. + * + * @return None + * @retval None + */ +static void map_accel_range(uint8_t range_in, uint8_t *range_out); + +/*! + * @brief This internal API compensate the accelerometer data against gravity. + * + * @param[in] lsb_per_g : LSB value pre 1g. + * @param[in] g_val : G reference value of all axis. + * @param[in] data : Accelerometer data + * @param[out] comp_data : Stores the data that is compensated by taking the + * difference in accelerometer data and lsb_per_g + * value. + * + * @return None + * @retval None + */ +static void comp_for_gravity(uint16_t lsb_per_g, const int16_t g_val[3], const struct bmi2_sens_axes_data *data, + struct offset_delta *comp_data); + +/*! + * @brief This internal API scales the compensated accelerometer data according + * to the offset register resolution. + * + * @param[in] range : G-range of the accelerometer. + * @param[out] comp_data : Data that is compensated by taking the + * difference in accelerometer data and lsb_per_g + * value. + * @param[out] data : Stores offset data + * + * @return None + * @retval None + */ +static void scale_accel_offset(uint8_t range, const struct offset_delta *comp_data, struct accel_offset *data); + +/*! + * @brief This internal API finds the bit position of 3.9mg according to given + * range and resolution. + * + * @param[in] range : G-range of the accelerometer. + * + * @return Result of API execution status + * @retval Bit position of 3.9mg + */ +static int8_t get_bit_pos_3_9mg(uint8_t range); + +/*! + * @brief This internal API inverts the accelerometer offset data. + * + * @param[out] offset_data : Stores the inverted offset data + * + * @return None + * @retval None + */ +static void invert_accel_offset(struct accel_offset *offset_data); + +/*! + * @brief This internal API writes the offset data in the offset compensation + * register. + * + * @param[in] offset : offset data + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t write_accel_offset(const struct accel_offset *offset, const struct bmi2_dev *dev); + +/*! + * @brief This internal API restores the configurations saved before performing + * accelerometer FOC. + * + * @param[in] acc_cfg : Accelerometer configuration value + * @param[in] acc_en : Accelerometer enable value + * @param[in] aps : Advance power mode value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +static int8_t restore_accel_foc_config(struct bmi2_accel_config *acc_cfg, uint8_t aps, uint8_t acc_en, struct bmi2_dev *dev); + +/*! + * @brief This internal API saves the configurations before performing gyroscope + * FOC. + * + * @param[out] gyr_cfg : Gyroscope configuration value + * @param[out] gyr_en : Gyroscope enable value + * @param[out] aps : Advance power mode value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t save_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t *aps, uint8_t *gyr_en, const struct bmi2_dev *dev); + +/*! + * @brief This internal sets configurations for performing gyroscope FOC. + * + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t set_gyro_foc_config(struct bmi2_dev *dev); + +/*! + * @brief This internal API inverts the gyroscope offset data. + * + * @param[out] offset_data : Stores the inverted offset data + * + * @return None + * @retval None + */ +static void invert_gyro_offset(struct bmi2_sens_axes_data *offset_data); + +/*! + * @brief This internal API restores the gyroscope configurations saved + * before performing FOC. + * + * @param[in] gyr_cfg : Gyroscope configuration value + * @param[in] gyr_en : Gyroscope enable value + * @param[in] aps : Advance power mode value + * @param[in] dev : Structure instance of bmi2_dev + * + * @return Result of API execution status + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +static int8_t restore_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t aps, uint8_t gyr_en, struct bmi2_dev *dev); + +/*! + * @brief This internal API saturates the gyroscope data value before writing to + * to 10 bit offset register. + * + * @param[in, out] gyr_off : Gyroscope data to be stored in offset register + * + * @return None + * @retval None + */ +static void saturate_gyro_data(struct bmi2_sens_axes_data *gyr_off); + +/*! + * @brief This internal API reads the gyroscope data for x, y and z axis from + * the sensor. + * + * @param[out] gyro : Buffer to store the gyroscope value. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +static int8_t read_gyro_xyz(struct bmi2_sens_axes_data *gyro, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to check the boundary conditions. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[in,out] val : Pointer to the value to be validated. + * @param[in] min : minimum value. + * @param[in] max : maximum value. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * + */ +static int8_t check_boundary_val(uint8_t *val, uint8_t min, uint8_t max, struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to validate the device pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev); + +/******************************************************************************/ +/*! @name User Interface Definitions */ +/******************************************************************************/ +/*! + * @brief This API is the entry point for bmi2 sensor. It selects between + * I2C/SPI interface, based on user selection. It reads and validates the + * chip-id of the sensor. + */ +int8_t bmi2_sec_init(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to assign chip id */ + uint8_t chip_id = 0; + /* Structure to define the default values for axes re-mapping */ + struct bmi2_axes_remap axes_remap = {.x_axis = MAP_X_AXIS, + .x_axis_sign = POS_SIGN, + .y_axis = MAP_Y_AXIS, + .y_axis_sign = POS_SIGN, + .z_axis = MAP_Z_AXIS, + .z_axis_sign = POS_SIGN }; + + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Perform soft-reset to bring all register values to their + default values */ + rslt = bmi2_soft_reset(dev); + if (rslt == BMI2_OK) { + /* Read chip-id of the BMI2 sensor */ + rslt = bmi2_get_regs(BMI2_CHIP_ID_ADDR, &chip_id, 1, dev); + if (rslt == BMI2_OK) { + /* Validate chip-id */ + if (chip_id == dev->chip_id) { + /* Assign resolution to the structure */ + dev->resolution = 16; + /* Set manual enable flag */ + dev->aux_man_en = 1; + /* Set the default values for axis + re-mapping in the device structure */ + dev->remap = axes_remap; + } else { + /* Storing the chip-id value read from + the register to identify the sensor */ + dev->chip_id = chip_id; + + rslt = BMI2_E_DEV_NOT_FOUND; + } + } + } + } + + return rslt; +} + +/*! + * @brief This API reads the data from the given register address of bmi2 + * sensor. + * + * @note For most of the registers auto address increment applies, with the + * exception of a few special registers, which trap the address. For e.g., + * Register address - 0x26, 0x5E. + */ +int8_t bmi2_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define temporary length */ + uint16_t temp_len = len + dev->dummy_byte; + /* Variable to define temporary buffer */ + uint8_t temp_buf[temp_len]; + /* Variable to define loop */ + uint16_t index = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (data != NULL)) { + /* Configuring reg_addr for SPI Interface */ + if (dev->intf == BMI2_SPI_INTERFACE) + reg_addr = (reg_addr | BMI2_SPI_RD_MASK); + + /* Read from the given bmi2 register */ + rslt = dev->read(dev->dev_id, reg_addr, temp_buf, temp_len); + dev->delay_ms(1); + + if (rslt == BMI2_OK) { + /* Read the data from the position next to dummy byte */ + while (index < len) { + data[index] = temp_buf[index + dev->dummy_byte]; + index++; + } + } else { + rslt = BMI2_E_COM_FAIL; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes data to the given register address of bmi2 sensor. + */ +int8_t bmi2_set_regs(uint8_t reg_addr, const uint8_t *data, uint16_t len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to get APS status */ + uint8_t aps_status = 0; + /* Variable to define loop */ + uint16_t loop = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (data != NULL)) { + /* Configuring reg_addr for SPI Interface */ + if (dev->intf == BMI2_SPI_INTERFACE) + reg_addr = (reg_addr & BMI2_SPI_WR_MASK); + + /* Get the status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_status, dev); + if (rslt == BMI2_OK) { + if (aps_status == BMI2_ENABLE) { + for (loop = 0; loop < len; loop++) { + /* Byte write if APS is enabled */ + rslt = dev->write(dev->dev_id, (uint8_t)((uint16_t)reg_addr + loop), + &data[loop], 1); + dev->delay_ms(1); + } + } else { + /* Burst write if APS is disabled */ + rslt = dev->write(dev->dev_id, reg_addr, data, len); + dev->delay_ms(1); + } + + if (rslt != BMI2_OK) + rslt = BMI2_E_COM_FAIL; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API resets bmi2 sensor. All registers are overwritten with + * their default values. + */ +int8_t bmi2_soft_reset(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define soft reset value */ + uint8_t data = BMI2_SOFT_RESET_CMD; + /* Variable to read the dummy byte */ + uint8_t dummy_read = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Reset bmi2 device */ + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &data, 1, dev); + dev->delay_ms(1); + + /* Performing a dummy read to bring interface back to SPI from + I2C after a soft-reset */ + if ((rslt == BMI2_OK) && (dev->intf == BMI2_SPI_INTERFACE)) + rslt = bmi2_get_regs(BMI2_CHIP_ID_ADDR, &dummy_read, 1, dev); + + /* Reset the sensor status flag in the device structure */ + if (rslt == BMI2_OK) + dev->sens_en_stat = 0; + } + + return rslt; +} + +/*! + * @brief This API selects the sensors/features to be enabled. + */ +int8_t bmi2_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to select sensor */ + uint32_t sensor_sel = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_list != NULL)) { + /* Get the selected sensors */ + rslt = select_sensor(sens_list, n_sens, &sensor_sel); + if (rslt == BMI2_OK) { + /* Enable the selected sensors */ + rslt = sensor_enable(sensor_sel, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API selects the sensors/features to be disabled. + */ +int8_t bmi2_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to select sensor */ + uint32_t sensor_sel = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_list != NULL)) { + /* Get the selected sensors */ + rslt = select_sensor(sens_list, n_sens, &sensor_sel); + if (rslt == BMI2_OK) { + /* Disable the selected sensors */ + rslt = sensor_disable(sensor_sel, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the sensor/feature configuration. + */ +int8_t bmi2_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define loop */ + uint8_t loop; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_cfg != NULL)) { + for (loop = 0; loop < n_sens; loop++) { + /* Disable Advance power save if enabled for auxiliary + and feature configurations */ + if ((sens_cfg[loop].type >= BMI2_MAIN_SENS_MAX_NUM) || (sens_cfg[loop].type == BMI2_AUX)) { + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if + enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + + if (rslt == BMI2_OK) { + switch (sens_cfg[loop].type) { + /* Set accelerometer configuration */ + case BMI2_ACCEL: + rslt = set_accel_config(&sens_cfg[loop].cfg.acc, dev); + break; + /* Set gyroscope configuration */ + case BMI2_GYRO: + rslt = set_gyro_config(&sens_cfg[loop].cfg.gyr, dev); + break; + /* Set auxiliary configuration */ + case BMI2_AUX: + rslt = set_aux_config(&sens_cfg[loop].cfg.aux, dev); + break; + /* Set any motion configuration */ + case BMI2_ANY_MOTION: + rslt = set_any_motion_config(&sens_cfg[loop].cfg.any_motion, dev); + break; + /* Set no motion configuration */ + case BMI2_NO_MOTION: + rslt = set_no_motion_config(&sens_cfg[loop].cfg.no_motion, dev); + break; + /* Set sig-motion configuration */ + case BMI2_SIG_MOTION: + rslt = set_sig_motion_config(&sens_cfg[loop].cfg.sig_motion, dev); + break; + /* Set step counter/detector/activity + configuration */ + case BMI2_STEP_DETECTOR: + case BMI2_STEP_COUNTER: + case BMI2_STEP_ACTIVITY: + rslt = set_step_config(&sens_cfg[loop].cfg.step_counter, dev); + break; + /* Set gyroscope user gain configuration */ + case BMI2_GYRO_GAIN_UPDATE: + rslt = set_gyro_user_gain_config(&sens_cfg[loop].cfg.gyro_gain_update, dev); + break; + /* Set tilt configuration */ + case BMI2_TILT: + rslt = set_tilt_config(&sens_cfg[loop].cfg.tilt, dev); + break; + /* Set pick-up configuration */ + case BMI2_PICK_UP: + rslt = set_pick_up_config(&sens_cfg[loop].cfg.pick_up, dev); + break; + /* Set glance detector configuration */ + case BMI2_GLANCE_DETECTOR: + rslt = set_glance_detect_config(&sens_cfg[loop].cfg.glance_det, dev); + break; + /* Set wake-up configuration */ + case BMI2_WAKE_UP: + rslt = set_wake_up_config(&sens_cfg[loop].cfg.tap, dev); + break; + /* Set orientation configuration */ + case BMI2_ORIENTATION: + rslt = set_orient_config(&sens_cfg[loop].cfg.orientation, dev); + break; + /* Set high-g configuration */ + case BMI2_HIGH_G: + rslt = set_high_g_config(&sens_cfg[loop].cfg.high_g, dev); + break; + /* Set low-g configuration */ + case BMI2_LOW_G: + rslt = set_low_g_config(&sens_cfg[loop].cfg.low_g, dev); + break; + /* Set flat configuration */ + case BMI2_FLAT: + rslt = set_flat_config(&sens_cfg[loop].cfg.flat, dev); + break; + /* Set external sensor sync configuration */ + case BMI2_EXT_SENS_SYNC: + rslt = set_ext_sens_sync_config(&sens_cfg[loop].cfg.ext_sens_sync, dev); + break; + /* Set the wrist gesture configuration */ + case BMI2_WRIST_GESTURE: + rslt = set_wrist_gest_config(&sens_cfg[loop].cfg.wrist_gest, dev); + break; + /* Set the wrist wear wake-up configuration */ + case BMI2_WRIST_WEAR_WAKE_UP: + rslt = set_wrist_wear_wake_up_config(&sens_cfg[loop].cfg.wrist_wear_wake_up, dev); + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + /* Return error if any of the set configurations fail */ + if (rslt != BMI2_OK) + break; + } + + /* Enable Advance power save if disabled while configuring and + not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the sensor/feature configuration. + */ +int8_t bmi2_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define loop */ + uint8_t loop; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_cfg != NULL)) { + for (loop = 0; loop < n_sens; loop++) { + /* Disable Advance power save if enabled for auxiliary + and feature configurations */ + if ((sens_cfg[loop].type >= BMI2_MAIN_SENS_MAX_NUM) || (sens_cfg[loop].type == BMI2_AUX)) { + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if + enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + + if (rslt == BMI2_OK) { + switch (sens_cfg[loop].type) { + /* Get accelerometer configuration */ + case BMI2_ACCEL: + rslt = get_accel_config(&sens_cfg[loop].cfg.acc, dev); + break; + /* Get gyroscope configuration */ + case BMI2_GYRO: + rslt = get_gyro_config(&sens_cfg[loop].cfg.gyr, dev); + break; + /* Get auxiliary configuration */ + case BMI2_AUX: + rslt = get_aux_config(&sens_cfg[loop].cfg.aux, dev); + break; + /* Get sig-motion configuration */ + case BMI2_SIG_MOTION: + rslt = get_sig_motion_config(&sens_cfg[loop].cfg.sig_motion, dev); + break; + /* Get any motion configuration */ + case BMI2_ANY_MOTION: + rslt = get_any_motion_config(&sens_cfg[loop].cfg.any_motion, dev); + break; + /* Get no motion configuration */ + case BMI2_NO_MOTION: + rslt = get_no_motion_config(&sens_cfg[loop].cfg.no_motion, dev); + break; + /* Get step counter/detector/activity + configuration */ + case BMI2_STEP_DETECTOR: + case BMI2_STEP_COUNTER: + case BMI2_STEP_ACTIVITY: + rslt = get_step_config(&sens_cfg[loop].cfg.step_counter, dev); + break; + /* Get gyroscope user gain configuration */ + case BMI2_GYRO_GAIN_UPDATE: + rslt = get_gyro_gain_update_config(&sens_cfg[loop].cfg.gyro_gain_update, dev); + break; + /* Get tilt configuration */ + case BMI2_TILT: + rslt = get_tilt_config(&sens_cfg[loop].cfg.tilt, dev); + break; + /* Get pick-up configuration */ + case BMI2_PICK_UP: + rslt = get_pick_up_config(&sens_cfg[loop].cfg.pick_up, dev); + break; + /* Get glance detector configuration */ + case BMI2_GLANCE_DETECTOR: + rslt = get_glance_detect_config(&sens_cfg[loop].cfg.glance_det, dev); + break; + /* Get wake-up configuration */ + case BMI2_WAKE_UP: + rslt = get_wake_up_config(&sens_cfg[loop].cfg.tap, dev); + break; + /* Get orientation configuration */ + case BMI2_ORIENTATION: + rslt = get_orient_config(&sens_cfg[loop].cfg.orientation, dev); + break; + /* Get high-g configuration */ + case BMI2_HIGH_G: + rslt = get_high_g_config(&sens_cfg[loop].cfg.high_g, dev); + break; + /* Get low-g configuration */ + case BMI2_LOW_G: + rslt = get_low_g_config(&sens_cfg[loop].cfg.low_g, dev); + break; + /* Get flat configuration */ + case BMI2_FLAT: + rslt = get_flat_config(&sens_cfg[loop].cfg.flat, dev); + break; + /* Get external sensor sync configuration */ + case BMI2_EXT_SENS_SYNC: + rslt = get_ext_sens_sync_config(&sens_cfg[loop].cfg.ext_sens_sync, dev); + break; + /* Get the wrist gesture configuration */ + case BMI2_WRIST_GESTURE: + rslt = get_wrist_gest_config(&sens_cfg[loop].cfg.wrist_gest, dev); + break; + /* Get the wrist wear wake-up configuration */ + case BMI2_WRIST_WEAR_WAKE_UP: + rslt = get_wrist_wear_wake_up_config(&sens_cfg[loop].cfg.wrist_wear_wake_up, dev); + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + /* Return error if any of the get configurations fail */ + if (rslt != BMI2_OK) + break; + } + + /* Enable Advance power save if disabled while configuring and + not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the sensor/feature data for accelerometer, gyroscope, + * auxiliary sensor, step counter, high-g, gyroscope user-gain update, + * orientation, gyroscope cross sensitivity and error status for NVM and VFRM. + */ +int8_t bmi2_get_sensor_data(struct bmi2_sensor_data *sensor_data, uint8_t n_sens, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define loop */ + uint8_t loop; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sensor_data != NULL)) { + for (loop = 0; loop < n_sens; loop++) { + /* Disable Advance power save if enabled for feature + configurations */ + if (sensor_data[loop].type >= BMI2_MAIN_SENS_MAX_NUM) { + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if + enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + + if (rslt == BMI2_OK) { + switch (sensor_data[loop].type) { + case BMI2_ACCEL: + /* Get accelerometer data */ + rslt = get_accel_sensor_data(&sensor_data[loop].sens_data.acc, BMI2_ACC_X_LSB_ADDR, dev); + break; + case BMI2_GYRO: + /* Get gyroscope data */ + rslt = get_gyro_sensor_data(&sensor_data[loop].sens_data.gyr, BMI2_GYR_X_LSB_ADDR, dev); + break; + case BMI2_AUX: + /* Get auxiliary sensor data in data + mode */ + rslt = read_aux_data_mode(sensor_data[loop].sens_data.aux_data, dev); + break; + case BMI2_STEP_COUNTER: + /* Get step counter output */ + rslt = get_step_counter_output(&sensor_data[loop].sens_data.step_counter_output, dev); + break; + case BMI2_STEP_ACTIVITY: + /* Get step activity output */ + rslt = get_step_activity_output(&sensor_data[loop].sens_data.activity_output, dev); + break; + case BMI2_ORIENTATION: + /* Get orientation output */ + rslt = get_orient_output(&sensor_data[loop].sens_data.orient_output, dev); + break; + case BMI2_HIGH_G: + /* Get high-g output */ + rslt = get_high_g_output(&sensor_data[loop].sens_data.high_g_output, dev); + break; + case BMI2_GYRO_GAIN_UPDATE: + /* Get saturation status of gyroscope + user gain update */ + rslt = get_gyro_gain_update_status(&sensor_data[loop].sens_data.gyro_user_gain_status, dev); + break; + case BMI2_NVM_STATUS: + /* Get NVM error status */ + rslt = get_nvm_error_status(&sensor_data[loop].sens_data.nvm_status, dev); + break; + case BMI2_VFRM_STATUS: + /* Get VFRM error status */ + rslt = get_vfrm_error_status(&sensor_data[loop].sens_data.vfrm_status, dev); + break; + case BMI2_WRIST_GESTURE: + /* Get wrist gesture status */ + rslt = get_wrist_gest_status(&sensor_data[loop].sens_data.wrist_gest, dev); + break; + case BMI2_GYRO_CROSS_SENSE: + /* Get Gyroscope cross sense value + of z axis */ + rslt = get_gyro_cross_sense(&sensor_data[loop].sens_data.correction_factor_zx, dev); + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + + /* Return error if any of the get sensor data + fails */ + if (rslt != BMI2_OK) + break; + } + + /* Enable Advance power save if disabled while + configuring and not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API enables/disables the advance power save mode in the sensor. + */ +int8_t bmi2_set_adv_power_save(uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_ADV_POW_EN, enable); + rslt = bmi2_set_regs(BMI2_PWR_CONF_ADDR, ®_data, 1, dev); + if (rslt != BMI2_OK) { + /* Return error if enable/disable APS fails */ + rslt = BMI2_E_SET_APS_FAIL; + } + } + } + + return rslt; +} + +/*! + * @brief This API gets the status of advance power save mode in the sensor. + */ +int8_t bmi2_get_adv_power_save(uint8_t *aps_status, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aps_status != NULL)) { + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + *aps_status = BMI2_GET_BIT_POS0(reg_data, BMI2_ADV_POW_EN); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API loads the configuration file into the bmi2 sensor. + */ +int8_t bmi2_write_config_file(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to know the load status */ + uint8_t load_status = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Bytes written are multiples of 2 */ + if ((dev->read_write_len % 2) != 0) + dev->read_write_len = dev->read_write_len - 1; + + /* Write the configuration file */ + rslt = write_config_file(dev); + if (rslt == BMI2_OK) { + /* Check the configuration load status */ + rslt = bmi2_get_internal_status(&load_status, dev); + /* Return error if loading not successful */ + if ((rslt == BMI2_OK) && (!(load_status & BMI2_CONFIG_LOAD_SUCCESS))) + rslt = BMI2_E_CONFIG_LOAD; + } + } + + return rslt; +} + +/*! + * @brief This API sets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + */ +int8_t bmi2_set_int_pin_config(const struct bmi2_int_pin_config *int_cfg, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define data array */ + uint8_t data_array[3] = {0}; + /* Variable to store register data */ + uint8_t reg_data = 0; + /* Variable to define type of interrupt pin */ + uint8_t int_pin = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_cfg != NULL)) { + /* Copy the pin type to a local variable */ + int_pin = int_cfg->pin_type; + + if ((int_pin > BMI2_INT_NONE) && (int_pin < BMI2_INT_PIN_MAX)) { + /* Get the previous configuration data */ + rslt = bmi2_get_regs(BMI2_INT1_IO_CTRL_ADDR, data_array, 3, dev); + if (rslt == BMI2_OK) { + /* Set interrupt pin 1 configuration */ + if ((int_pin == BMI2_INT1) || (int_pin == BMI2_INT_BOTH)) { + /* Configure active low or high */ + reg_data = BMI2_SET_BITS(data_array[0], BMI2_INT_LEVEL, int_cfg->pin_cfg[0].lvl); + /* Configure push-pull or open drain */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OPEN_DRAIN, int_cfg->pin_cfg[0].od); + /* Configure output enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OUTPUT_EN, int_cfg->pin_cfg[0].output_en); + /* Configure input enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_INPUT_EN, int_cfg->pin_cfg[0].input_en); + + /* Copy the data to be written in the + respective array */ + data_array[0] = reg_data; + } + + /* Set interrupt pin 2 configuration */ + if ((int_pin == BMI2_INT2) || (int_pin == BMI2_INT_BOTH)) { + /* Configure active low or high */ + reg_data = BMI2_SET_BITS(data_array[1], BMI2_INT_LEVEL, int_cfg->pin_cfg[1].lvl); + /* Configure push-pull or open drain */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OPEN_DRAIN, int_cfg->pin_cfg[1].od); + /* Configure output enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_OUTPUT_EN, int_cfg->pin_cfg[1].output_en); + /* Configure input enable */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_INT_INPUT_EN, int_cfg->pin_cfg[1].input_en); + + /* Copy the data to be written in the + respective array */ + data_array[1] = reg_data; + } + + /* Configure the interrupt mode */ + data_array[2] = BMI2_SET_BIT_POS0(data_array[2], BMI2_INT_LATCH, int_cfg->int_latch); + + /* Set the configurations simultaneously as + INT1_IO_CTRL, INT2_IO_CTRL, and INT_LATCH lie + in consecutive addresses */ + rslt = bmi2_set_regs(BMI2_INT1_IO_CTRL_ADDR, data_array, 3, dev); + } + } else { + rslt = BMI2_E_INVALID_INT_PIN; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + */ +int8_t bmi2_get_int_pin_config(struct bmi2_int_pin_config *int_cfg, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define data array */ + uint8_t data_array[3] = {0}; + /* Variable to define type of interrupt pin */ + uint8_t int_pin = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_cfg != NULL)) { + /* Copy the pin type to a local variable */ + int_pin = int_cfg->pin_type; + + /* Get the previous configuration data */ + rslt = bmi2_get_regs(BMI2_INT1_IO_CTRL_ADDR, data_array, 3, dev); + if (rslt == BMI2_OK) { + /* Get interrupt pin 1 configuration */ + if ((int_pin == BMI2_INT1) || (int_pin == BMI2_INT_BOTH)) { + /* Get active low or high */ + int_cfg->pin_cfg[0].lvl = BMI2_GET_BITS(data_array[0], BMI2_INT_LEVEL); + /* Get push-pull or open drain */ + int_cfg->pin_cfg[0].od = BMI2_GET_BITS(data_array[0], BMI2_INT_OPEN_DRAIN); + /* Get output enable */ + int_cfg->pin_cfg[0].output_en = BMI2_GET_BITS(data_array[0], BMI2_INT_OUTPUT_EN); + /* Get input enable */ + int_cfg->pin_cfg[0].input_en = BMI2_GET_BITS(data_array[0], BMI2_INT_INPUT_EN); + + } + + /* Get interrupt pin 2 configuration */ + if ((int_pin == BMI2_INT2) || (int_pin == BMI2_INT_BOTH)) { + /* Get active low or high */ + int_cfg->pin_cfg[1].lvl = BMI2_GET_BITS(data_array[1], BMI2_INT_LEVEL); + /* Get push-pull or open drain */ + int_cfg->pin_cfg[1].od = BMI2_GET_BITS(data_array[1], BMI2_INT_OPEN_DRAIN); + /* Get output enable */ + int_cfg->pin_cfg[1].output_en = BMI2_GET_BITS(data_array[1], BMI2_INT_OUTPUT_EN); + /* Get input enable */ + int_cfg->pin_cfg[1].input_en = BMI2_GET_BITS(data_array[1], BMI2_INT_INPUT_EN); + } + + /* Get interrupt mode */ + int_cfg->int_latch = BMI2_GET_BIT_POS0(data_array[2], BMI2_INT_LATCH); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the interrupt status of both feature and data + * interrupts + */ +int8_t bmi2_get_int_status(uint16_t *int_status, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store data */ + uint8_t data_array[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_status != NULL)) { + /* Get the interrupt status */ + rslt = bmi2_get_regs(BMI2_INT_STATUS_0_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) + *int_status = (uint16_t)data_array[0] | ((uint16_t)data_array[1] << 8); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO configuration in the sensor. + */ +int8_t bmi2_set_fifo_config(uint16_t config, uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store data */ + uint8_t data[2] = {0}; + /* Variable to store data of FIFO configuration register 0 */ + uint8_t fifo_config_0 = (uint8_t)(config & BMI2_FIFO_CONFIG_0_MASK); + /* Variable to store data of FIFO configuration register 1 */ + uint8_t fifo_config_1 = (uint8_t)((config & BMI2_FIFO_CONFIG_1_MASK) >> 8); + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + rslt = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, data, BMI2_FIFO_CONFIG_LENGTH, dev); + if (rslt == BMI2_OK) { + /* Get data to set FIFO configuration register 0 */ + if (fifo_config_0 > 0) { + if (enable == BMI2_ENABLE) + data[0] = data[0] | fifo_config_0; + else + data[0] = data[0] & (~fifo_config_0); + } + + /* Get data to set FIFO configuration register 1 */ + if (enable == BMI2_ENABLE) + data[1] = data[1] | fifo_config_1; + else + data[1] = data[1] & (~fifo_config_1); + + /* Set the FIFO configurations */ + rslt = bmi2_set_regs(BMI2_FIFO_CONFIG_0_ADDR, data, 2, dev); + } + } + + return rslt; +} + +/*! + * @brief This API reads the FIFO configuration from the sensor. + */ +int8_t bmi2_get_fifo_config(uint16_t *fifo_config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store data */ + uint8_t data[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_config != NULL)) { + /* Get the FIFO configuration value */ + rslt = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, data, BMI2_FIFO_CONFIG_LENGTH, dev); + if (rslt == BMI2_OK) { + (*fifo_config) = (uint16_t)((uint16_t)data[0] & BMI2_FIFO_CONFIG_0_MASK); + (*fifo_config) |= (uint16_t)(((uint16_t)data[1] << 8) & BMI2_FIFO_CONFIG_1_MASK); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the FIFO data. + */ +int8_t bmi2_read_fifo_data(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store FIFO configuration data */ + uint8_t config_data[2] = {0}; + /* Variable to define FIFO address */ + uint8_t addr = BMI2_FIFO_DATA_ADDR; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo != NULL)) { + /* Clear the FIFO data structure */ + reset_fifo_frame_structure(fifo, dev); + + /* Select the interface */ + if (dev->intf == BMI2_SPI_INTERFACE) + addr = addr | BMI2_SPI_RD_MASK; + + /* Read FIFO data */ + rslt = dev->read(dev->dev_id, addr, fifo->data, fifo->length); + if (rslt == BMI2_OK) { + /* Get the set FIFO frame configurations */ + rslt = bmi2_get_regs(BMI2_FIFO_CONFIG_0_ADDR, config_data, 2, dev); + if (rslt == BMI2_OK) { + /* Get FIFO header status */ + fifo->header_enable = (uint8_t)((config_data[1]) & (BMI2_FIFO_HEADER_EN >> 8)); + + /* Get sensor enable status, of which the data + is to be read */ + fifo->data_enable = (uint16_t)(((config_data[0]) | ((uint16_t)config_data[1] << 8)) + & BMI2_FIFO_ALL_EN); + } + } else { + rslt = BMI2_E_COM_FAIL; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the accelerometer frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in the "accel_data" + * structure instance. + */ +int8_t bmi2_extract_accel(struct bmi2_sens_axes_data *accel_data, uint16_t *accel_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to index the bytes */ + uint16_t data_index = 0; + /* Variable to index accelerometer frames */ + uint16_t accel_index = 0; + /* Variable to store the number of bytes to be read */ + uint16_t data_read_length = 0; + /* Variable to define the data enable byte */ + uint8_t data_enable = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (accel_data != NULL) && (accel_length != NULL) && (fifo != NULL)) { + /* Parsing the FIFO data in header-less mode */ + if (fifo->header_enable == 0) { + /* Get the number of accelerometer bytes to be read */ + rslt = parse_fifo_accel_len(&data_index, &data_read_length, accel_length, fifo, dev); + + /* Convert word to byte since all sensor enables are in + a byte */ + data_enable = (uint8_t)(fifo->data_enable >> 8); + + for (; (data_index < data_read_length) && (rslt != BMI2_W_FIFO_EMPTY);) { + /* Unpack frame to get the accelerometer data */ + rslt = unpack_accel_frame(accel_data, &data_index, &accel_index, data_enable, fifo, dev); + + if (rslt != BMI2_W_FIFO_EMPTY) { + /* Check for the availability of next + two bytes of FIFO data */ + rslt = check_empty_fifo(&data_index, fifo); + } + } + + /* Update number of accelerometer frames to be read */ + (*accel_length) = accel_index; + + /* Update the accelerometer byte index */ + fifo->acc_byte_start_idx = data_index; + } else { + /* Parsing the FIFO data in header mode */ + rslt = extract_accel_header_mode(accel_data, accel_length, fifo, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the gyroscope frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in the "gyro_data" + * structure instance. + */ +int8_t bmi2_extract_gyro(struct bmi2_sens_axes_data *gyro_data, uint16_t *gyro_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to index the bytes */ + uint16_t data_index = 0; + /* Variable to index gyroscope frames */ + uint16_t gyro_index = 0; + /* Variable to store the number of bytes to be read */ + uint16_t data_read_length = 0; + /* Variable to define the data enable byte */ + uint8_t data_enable = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyro_data != NULL) && (gyro_length != NULL) && (fifo != NULL)) { + /* Parsing the FIFO data in header-less mode */ + if (fifo->header_enable == 0) { + rslt = parse_fifo_gyro_len(&data_index, &data_read_length, gyro_length, fifo, dev); + + /* Convert word to byte since all sensor enables are in + a byte */ + data_enable = (uint8_t)(fifo->data_enable >> 8); + + for (; (data_index < data_read_length) && (rslt != BMI2_W_FIFO_EMPTY);) { + /* Unpack frame to get gyroscope data */ + rslt = unpack_gyro_frame(gyro_data, &data_index, &gyro_index, data_enable, fifo, dev); + + if (rslt != BMI2_W_FIFO_EMPTY) { + /* Check for the availability of next + two bytes of FIFO data */ + rslt = check_empty_fifo(&data_index, fifo); + } + } + + /* Update number of gyroscope frames to be read */ + (*gyro_length) = gyro_index; + + /* Update the gyroscope byte index */ + fifo->acc_byte_start_idx = data_index; + } else { + /* Parsing the FIFO data in header mode */ + rslt = extract_gyro_header_mode(gyro_data, gyro_length, fifo, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API parses and extracts the auxiliary frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in "aux_data" buffer. + */ +int8_t bmi2_extract_aux(struct bmi2_aux_fifo_data *aux, uint16_t *aux_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to index the bytes */ + uint16_t data_index = 0; + /* Variable to index auxiliary frames */ + uint16_t aux_index = 0; + /* Variable to store the number of bytes to be read */ + uint16_t data_read_length = 0; + /* Variable to define the data enable byte */ + uint8_t data_enable = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux != NULL) && (aux_length != NULL) && (fifo != NULL)) { + /* Parsing the FIFO data in header-less mode */ + if (fifo->header_enable == 0) { + rslt = parse_fifo_aux_len(&data_index, &data_read_length, aux_length, fifo, dev); + + /* Convert word to byte since all sensor enables are in + a byte */ + data_enable = (uint8_t)(fifo->data_enable >> 8); + + for (; (data_index < data_read_length) && (rslt != BMI2_W_FIFO_EMPTY);) { + /* Unpack frame to get auxiliary data */ + rslt = unpack_aux_frame(aux, &data_index, &aux_index, data_enable, fifo, dev); + + if (rslt != BMI2_W_FIFO_EMPTY) { + /* Check for the availability of next + two bytes of FIFO data */ + rslt = check_empty_fifo(&data_index, fifo); + } + } + + /* Update number of auxiliary frames to be read */ + *aux_length = aux_index; + + /* Update the auxiliary byte index */ + fifo->aux_byte_start_idx = data_index; + } else { + /* Parsing the FIFO data in header mode */ + rslt = extract_aux_header_mode(aux, aux_length, fifo, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! +* @brief This API writes the available sensor specific commands to the sensor. +*/ +int8_t bmi2_set_command_register(uint8_t command, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Set the command in the command register */ + rslt = bmi2_set_regs(BMI2_CMD_REG_ADDR, &command, 1, dev); + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO self wake up functionality in the sensor. + */ +int8_t bmi2_set_fifo_self_wake_up(uint8_t fifo_self_wake_up, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Set FIFO self wake-up */ + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_FIFO_SELF_WAKE_UP, fifo_self_wake_up); + rslt = bmi2_set_regs(BMI2_PWR_CONF_ADDR, &data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API gets the status of FIFO self wake up functionality from + * the sensor. + */ +int8_t bmi2_get_fifo_self_wake_up(uint8_t *fifo_self_wake_up, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_self_wake_up != NULL)) { + /* Get the status of FIFO self wake-up */ + rslt = bmi2_get_regs(BMI2_PWR_CONF_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + (*fifo_self_wake_up) = BMI2_GET_BITS(data, BMI2_FIFO_SELF_WAKE_UP); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the FIFO water-mark level in the sensor. + */ +int8_t bmi2_set_fifo_wm(uint16_t fifo_wm, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store data */ + uint8_t data[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Get LSB value of FIFO water-mark */ + data[0] = BMI2_GET_LSB(fifo_wm); + /* Get MSB value of FIFO water-mark */ + data[1] = BMI2_GET_MSB(fifo_wm); + + /* Set the FIFO water-mark level */ + rslt = bmi2_set_regs(BMI2_FIFO_WTM_0_ADDR, data, 2, dev); + } + + return rslt; +} + +/*! + * @brief This API reads the FIFO water mark level set in the sensor. + */ +int8_t bmi2_get_fifo_wm(uint16_t *fifo_wm, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to to store data */ + uint8_t data[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_wm != NULL)) { + /* Read the FIFO water mark level */ + rslt = bmi2_get_regs(BMI2_FIFO_WTM_0_ADDR, data, BMI2_FIFO_WM_LENGTH, dev); + if (rslt == BMI2_OK) + (*fifo_wm) = (uint16_t)((uint16_t)data[1] << 8) | (data[0]); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets either filtered or un-filtered FIFO accelerometer or + * gyroscope data. + */ +int8_t bmi2_set_fifo_filter_data(uint8_t sens_sel, uint8_t fifo_filter_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + switch (sens_sel) { + case BMI2_ACCEL: + /* Validate filter mode */ + if (fifo_filter_data <= BMI2_MAX_VALUE_FIFO_FILTER) { + /* Set the accelerometer FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_ACC_FIFO_FILT_DATA, fifo_filter_data); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + } else { + rslt = BMI2_E_OUT_OF_RANGE; + } + break; + case BMI2_GYRO: + /* Validate filter mode */ + if (fifo_filter_data <= BMI2_MAX_VALUE_FIFO_FILTER) { + /* Set the gyroscope FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_GYR_FIFO_FILT_DATA, fifo_filter_data); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + } else { + rslt = BMI2_E_OUT_OF_RANGE; + } + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + return rslt; +} + +/*! + * @brief This API gets the FIFO accelerometer or gyroscope filter data. + */ +int8_t bmi2_get_fifo_filter_data(uint8_t sens_sel, uint8_t *fifo_filter_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store FIFO filter mode */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_filter_data != NULL)) { + switch (sens_sel) { + case BMI2_ACCEL: + /* Read the accelerometer FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + (*fifo_filter_data) = BMI2_GET_BITS(data, BMI2_ACC_FIFO_FILT_DATA); + break; + case BMI2_GYRO: + /* Read the gyroscope FIFO filter data */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + (*fifo_filter_data) = BMI2_GET_BITS(data, BMI2_GYR_FIFO_FILT_DATA); + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the down-sampling rates for accelerometer or gyroscope + * FIFO data. + */ +int8_t bmi2_set_fifo_down_sample(uint8_t sens_sel, uint8_t fifo_down_samp, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store sampling rate */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + switch (sens_sel) { + case BMI2_ACCEL: + /* Set the accelerometer FIFO down sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_ACC_FIFO_DOWNS, fifo_down_samp); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + break; + case BMI2_GYRO: + /* Set the gyroscope FIFO down sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BIT_POS0(data, BMI2_GYR_FIFO_DOWNS, fifo_down_samp); + rslt = bmi2_set_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + } + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + return rslt; +} + +/*! + * @brief This API reads the down sampling rates which is configured for + * accelerometer or gyroscope FIFO data. + */ +int8_t bmi2_get_fifo_down_sample(uint8_t sens_sel, uint8_t *fifo_down_samp, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store sampling rate */ + uint8_t data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_down_samp != NULL)) { + switch (sens_sel) { + case BMI2_ACCEL: + /* Read the accelerometer FIFO down data sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + (*fifo_down_samp) = BMI2_GET_BITS(data, BMI2_ACC_FIFO_DOWNS); + break; + case BMI2_GYRO: + /* Read the gyroscope FIFO down data sampling rate */ + rslt = bmi2_get_regs(BMI2_FIFO_DOWNS_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) + (*fifo_down_samp) = BMI2_GET_BIT_POS0(data, BMI2_GYR_FIFO_DOWNS); + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the length of FIFO data available in the sensor in + * bytes. + */ +int8_t bmi2_get_fifo_length(uint16_t *fifo_length, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define byte index */ + uint8_t index = 0; + /* Array to store FIFO data length */ + uint8_t data[BMI2_FIFO_DATA_LENGTH] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (fifo_length != NULL)) { + /* Read FIFO length */ + rslt = bmi2_get_regs(BMI2_FIFO_LENGTH_0_ADDR, data, BMI2_FIFO_DATA_LENGTH, dev); + if (rslt == BMI2_OK) { + /* Get the MSB byte index */ + index = BMI2_FIFO_LENGTH_MSB_BYTE; + + /* Get the MSB byte of FIFO length */ + data[index] = BMI2_GET_BIT_POS0(data[index], BMI2_FIFO_BYTE_COUNTER_MSB); + + /* Get total FIFO length */ + (*fifo_length) = ((data[index] << 8) | data[index - 1]); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the user-defined bytes of data from the given register + * address of auxiliary sensor in manual mode. + * + * @note Change of BMI2_AUX_RD_ADDR is only allowed if AUX is not busy. + */ +int8_t bmi2_read_aux_man_mode(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store burst length */ + uint8_t burst_len = 0; + /* Variable to define APS status */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux_data != NULL)) { + /* Validate if manual mode */ + if (dev->aux_man_en) { + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable APS if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) { + /* Map the register value set to that of burst + length */ + rslt = map_read_len(&burst_len, dev); + if (rslt == BMI2_OK) { + /* Read auxiliary data */ + rslt = read_aux_data(reg_addr, aux_data, len, burst_len, dev); + } + } + + /* Enable Advance power save if disabled for reading + data and not when already disabled */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } else { + rslt = BMI2_E_AUX_INVALID_CFG; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + */ +int8_t bmi2_write_aux_man_mode(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define loop */ + uint8_t loop = 0; + /* Variable to define APS status */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux_data != NULL)) { + /* Validate if manual mode */ + if (dev->aux_man_en) { + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable APS if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + /* Byte write data in the corresponding address */ + if (rslt == BMI2_OK) { + for (; ((loop < len) && (rslt == BMI2_OK)); loop++) { + rslt = write_aux_data((reg_addr + loop), aux_data[loop], dev); + dev->delay_ms(1); + } + } + + /* Enable Advance power save if disabled for writing + data and not when already disabled */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } else { + rslt = BMI2_E_AUX_INVALID_CFG; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written, from an interleaved input, + * in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + */ +int8_t bmi2_write_aux_interleaved(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define loop */ + uint8_t loop = 1; + /* Variable to define APS status */ + uint8_t aps_stat = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (aux_data != NULL)) { + /* Validate if manual mode */ + if (dev->aux_man_en) { + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable APS if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) { + /* Write the start register address extracted + from the interleaved data */ + rslt = write_aux_data(reg_addr, aux_data[0], dev); + + /* Extract the remaining address and data from + the interleaved data and write it in the + corresponding addresses byte by byte */ + for ( ; ((loop < len) && (rslt == BMI2_OK)); loop += 2) { + rslt = write_aux_data(aux_data[loop], aux_data[loop + 1], dev); + dev->delay_ms(1); + } + + /* Enable Advance power save if disabled for + writing data and not when already disabled */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } else { + rslt = BMI2_E_AUX_INVALID_CFG; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets the data ready status of accelerometer, gyroscope, + * auxiliary, command decoder and busy status of auxiliary. + */ +int8_t bmi2_get_status(uint8_t *status, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (status != NULL)) + rslt = bmi2_get_regs(BMI2_STATUS_ADDR, status, 1, dev); + else + rslt = BMI2_E_NULL_PTR; + + return rslt; +} + +/*! + * @brief This API enables/disables OIS interface. + */ +int8_t bmi2_set_ois_interface(uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + rslt = bmi2_get_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Enable/Disable OIS interface */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_OIS_IF_EN, enable); + + if (enable) { + /* Disable auxiliary interface if OIS is + enabled */ + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_AUX_IF_EN); + } + + /* Set the OIS interface configurations */ + rslt = bmi2_set_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This API can be used to write sync commands like ODR, sync period, + * frequency and phase, resolution ratio, sync time and delay time. + */ +int8_t bmi2_write_sync_commands(const uint8_t *command, uint8_t n_comm, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (command != NULL)) + rslt = bmi2_set_regs(BMI2_SYNC_COMMAND_ADDR, command, n_comm, dev); + else + rslt = BMI2_E_NULL_PTR; + + return rslt; +} + +/*! + * @brief This API performs self-test to check the proper functionality of the + * accelerometer sensor. + */ +int8_t bmi2_perform_accel_self_test(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store self-test result */ + int8_t st_rslt = 0; + /* Structure to define positive accelerometer axes */ + struct bmi2_sens_axes_data positive = {0}; + /* Structure to define negative accelerometer axes */ + struct bmi2_sens_axes_data negative = {0}; + /* Structure for difference of accelerometer values in g */ + struct selftest_delta_limit accel_data_diff = {0}; + /* Structure for difference of accelerometer values in mg */ + struct selftest_delta_limit accel_data_diff_mg = {0}; + /* Initialize the polarity of self-test as positive */ + int8_t sign = BMI2_ENABLE; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Sets the configuration required before enabling self-test */ + rslt = pre_self_test_config(dev); + dev->delay_ms(20); + + if (rslt == BMI2_OK) { + do { + /* Select positive first, then negative polarity + after enabling self-test */ + rslt = self_test_config((uint8_t)sign, dev); + if (rslt == BMI2_OK) { + /* Wait for 100 milli-sec */ + dev->delay_ms(100); + + /* If polarity is positive */ + if (sign == BMI2_ENABLE) { + /* Read and store positive + acceleration value */ + rslt = read_accel_xyz(&positive, dev); + + /* If polarity is negative */ + } else if (sign == BMI2_DISABLE) { + /* Read and store negative + acceleration value */ + rslt = read_accel_xyz(&negative, dev); + } + } else { + /* Break if error */ + break; + } + + /* Break if error */ + if (rslt != BMI2_OK) + break; + + /* Turn the polarity of self-test negative */ + sign--; + + } while (sign >= 0); + + if (rslt == BMI2_OK) { + /* Subtract -ve acceleration values from that of + +ve values */ + accel_data_diff.x = (positive.x) - (negative.x); + accel_data_diff.y = (positive.y) - (negative.y); + accel_data_diff.z = (positive.z) - (negative.z); + + /* Convert differences of acceleration values + from 'g' to 'mg' */ + convert_lsb_g(&accel_data_diff, &accel_data_diff_mg, dev); + + /* Validate self test for acceleration values + in mg and get the self-test result */ + st_rslt = validate_self_test(&accel_data_diff_mg); + + /* Trigger a soft reset after performing self- + test */ + rslt = bmi2_soft_reset(dev); + dev->delay_ms(200); + + /* Return the self-test result */ + if (rslt == BMI2_OK) + rslt = st_rslt; + } + } + } + + return rslt; +} + +/*! + * @brief This API maps/unmaps feature interrupts to that of interrupt pins. + */ +int8_t bmi2_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define loop */ + uint8_t loop; + /* Variable to define the value of feature interrupts */ + uint8_t feat_int = 0; + /* Variable to define the mask bits of feature interrupts */ + uint8_t feat_int_mask = 0; + /* Array to store the interrupt mask bits */ + uint8_t data_array[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (sens_int != NULL)) { + /* Read interrupt map1 and map2 and register */ + rslt = bmi2_get_regs(BMI2_INT1_MAP_FEAT_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) { + for (loop = 0; loop < n_sens; loop++) { + switch (sens_int[loop].type) { + case BMI2_SIG_MOTION: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.sig_mot_out_conf; + break; + case BMI2_ANY_MOTION: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.any_mot_out_conf; + break; + case BMI2_NO_MOTION: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.no_mot_out_conf; + break; + case BMI2_STEP_DETECTOR: + case BMI2_STEP_COUNTER: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.step_det_out_conf; + break; + case BMI2_STEP_ACTIVITY: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.step_act_out_conf; + break; + case BMI2_TILT: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.tilt_out_conf; + break; + case BMI2_PICK_UP: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.pick_up_out_conf; + break; + case BMI2_GLANCE_DETECTOR: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.glance_out_conf; + break; + case BMI2_WAKE_UP: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.wake_up_out_conf; + break; + case BMI2_ORIENTATION: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.orient_out_conf; + break; + case BMI2_HIGH_G: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.high_g_out_conf; + break; + case BMI2_LOW_G: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.low_g_out_conf; + break; + case BMI2_FLAT: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.flat_out_conf; + break; + case BMI2_EXT_SENS_SYNC: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.ext_sync_out_conf; + break; + case BMI2_WRIST_GESTURE: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.wrist_gest_out_conf; + break; + case BMI2_WRIST_WEAR_WAKE_UP: + /* Get the value of the feature + interrupt to be mapped */ + feat_int = dev->int_map.wrist_wear_wake_up_out_conf; + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + + /* Map the features to the required interrupt */ + if (rslt != BMI2_E_INVALID_SENSOR) { + if ((feat_int > BMI2_FEAT_INT_DISABLE) && (feat_int < BMI2_FEAT_INT_MAX)) { + /* Get the interrupt mask */ + feat_int_mask = (uint8_t)((uint32_t)1 << (feat_int - 1)); + /* Map the interrupts */ + rslt = map_feat_int(data_array, sens_int[loop].hw_int_pin, feat_int_mask); + } else { + rslt = BMI2_E_INVALID_FEAT_INT; + } + } + + /* Return error if interrupt mapping fails */ + if (rslt != BMI2_OK) + break; + } + + /* Map the interrupts to INT1 and INT2 map register */ + if (rslt == BMI2_OK) + rslt = bmi2_set_regs(BMI2_INT1_MAP_FEAT_ADDR, data_array, 2, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API maps/un-maps data interrupts to that of interrupt pins. + */ +int8_t bmi2_map_data_int(uint8_t data_int, enum bmi2_hw_int_pin int_pin, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to mask interrupt pin 1 - lower nibble */ + uint8_t int1_mask = data_int; + /* Variable to mask interrupt pin 2 - higher nibble */ + uint8_t int2_mask = (uint8_t)(data_int << 4); + /* Variable to store register data */ + uint8_t reg_data = 0; + + /* Read interrupt map1 and map2 and register */ + rslt = bmi2_get_regs(BMI2_INT_MAP_DATA_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + if (int_pin < BMI2_INT_PIN_MAX) { + switch (int_pin) { + case BMI2_INT_NONE: + /* Un-Map the corresponding data + interrupt to both interrupt pin 1 and 2 + */ + reg_data &= ~(int1_mask | int2_mask); + break; + case BMI2_INT1: + /* Map the corresponding data interrupt to + interrupt pin 1 */ + reg_data |= int1_mask; + break; + case BMI2_INT2: + /* Map the corresponding data interrupt to + interrupt pin 2 */ + reg_data |= int2_mask; + break; + case BMI2_INT_BOTH: + /* Map the corresponding data + interrupt to both interrupt pin 1 and 2 + */ + reg_data |= (int1_mask | int2_mask); + break; + default: + break; + } + + /* Set the interrupts in the map register */ + rslt = bmi2_set_regs(BMI2_INT_MAP_DATA_ADDR, ®_data, 1, dev); + } else { + /* Return error if invalid pin selection */ + rslt = BMI2_E_INVALID_INT_PIN; + } + } + + return rslt; +} + +/*! + * @brief This API gets the re-mapped x, y and z axes from the sensor and + * updates the values in the device structure. + */ +int8_t bmi2_get_remap_axes(struct bmi2_remap *remapped_axis, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Initialize the local structure for axis re-mapping */ + struct axes_remap remap = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (remapped_axis != NULL)) { + /* Get the re-mapped axes from the sensor */ + rslt = get_remap_axes(&remap, dev); + + if (rslt == BMI2_OK) { + /* Store the re-mapped x-axis value in device structure + and its user-value in the interface structure */ + switch (remap.x_axis) { + case MAP_X_AXIS: + /* If mapped to x-axis */ + dev->remap.x_axis = MAP_X_AXIS; + remapped_axis->x = BMI2_X; + break; + case MAP_Y_AXIS: + /* If mapped to y-axis */ + dev->remap.x_axis = MAP_Y_AXIS; + remapped_axis->x = BMI2_Y; + break; + case MAP_Z_AXIS: + /* If mapped to z-axis */ + dev->remap.x_axis = MAP_Z_AXIS; + remapped_axis->x = BMI2_Z; + break; + default: + break; + } + + /* Store the re-mapped x-axis sign in device structure + and its user-value in the interface structure */ + if (remap.x_axis_sign) { + /* If x-axis is mapped to -ve sign */ + dev->remap.x_axis_sign = NEG_SIGN; + remapped_axis->x |= BMI2_AXIS_SIGN; + } else + dev->remap.x_axis_sign = POS_SIGN; + + + /* Store the re-mapped y-axis value in device structure + and its user-value in the interface structure */ + switch (remap.y_axis) { + case MAP_X_AXIS: + /* If mapped to x-axis */ + dev->remap.y_axis = MAP_X_AXIS; + remapped_axis->y = BMI2_X; + break; + case MAP_Y_AXIS: + /* If mapped to y-axis */ + dev->remap.y_axis = MAP_Y_AXIS; + remapped_axis->y = BMI2_Y; + break; + case MAP_Z_AXIS: + /* If mapped to z-axis */ + dev->remap.y_axis = MAP_Z_AXIS; + remapped_axis->y = BMI2_Z; + break; + default: + break; + } + + /* Store the re-mapped y-axis sign in device structure + and its user-value in the interface structure */ + if (remap.y_axis_sign) { + /* If y-axis is mapped to -ve sign */ + dev->remap.y_axis_sign = NEG_SIGN; + remapped_axis->y |= BMI2_AXIS_SIGN; + } else + dev->remap.y_axis_sign = POS_SIGN; + + + /* Store the re-mapped z-axis value in device structure + and its user-value in the interface structure */ + switch (remap.z_axis) { + case MAP_X_AXIS: + /* If mapped to x-axis */ + dev->remap.z_axis = MAP_X_AXIS; + remapped_axis->z = BMI2_X; + break; + case MAP_Y_AXIS: + /* If mapped to y-axis */ + dev->remap.z_axis = MAP_Y_AXIS; + remapped_axis->z = BMI2_Y; + break; + case MAP_Z_AXIS: + /* If mapped to z-axis */ + dev->remap.z_axis = MAP_Z_AXIS; + remapped_axis->z = BMI2_Z; + break; + default: + break; + } + + /* Store the re-mapped z-axis sign in device structure + and its user-value in the interface structure */ + if (remap.z_axis_sign) { + /* If z-axis is mapped to -ve sign */ + dev->remap.z_axis_sign = NEG_SIGN; + remapped_axis->z |= BMI2_AXIS_SIGN; + } else + dev->remap.z_axis_sign = POS_SIGN; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API sets the re-mapped x, y and z axes to the sensor and + * updates the them in the device structure. + */ +int8_t bmi2_set_remap_axes(const struct bmi2_remap *remapped_axis, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store all the re-mapped axes */ + uint8_t remap_axes = 0; + /* Variable to store the re-mapped x-axes */ + uint8_t remap_x = 0; + /* Variable to store the re-mapped y-axes */ + uint8_t remap_y = 0; + /* Variable to store the re-mapped z-axes */ + uint8_t remap_z = 0; + /* Initialize the local structure for axis re-mapping */ + struct axes_remap remap = {0}; + + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (remapped_axis != NULL)) { + /* Check whether all the axes are re-mapped */ + remap_axes = remapped_axis->x | remapped_axis->y | remapped_axis->z; + + /* If all the axes are re-mapped */ + if ((remap_axes & BMI2_AXIS_MASK) == BMI2_AXIS_MASK) { + /* Get the re-mapped value of x, y and z axis */ + remap_x = remapped_axis->x & BMI2_AXIS_MASK; + remap_y = remapped_axis->y & BMI2_AXIS_MASK; + remap_z = remapped_axis->z & BMI2_AXIS_MASK; + + /* Store the value of re-mapped x-axis in both + device structure and the local structure */ + switch (remap_x) { + case BMI2_X: + /* If mapped to x-axis */ + dev->remap.x_axis = MAP_X_AXIS; + remap.x_axis = MAP_X_AXIS; + break; + case BMI2_Y: + /* If mapped to y-axis */ + dev->remap.x_axis = MAP_Y_AXIS; + remap.x_axis = MAP_Y_AXIS; + break; + case BMI2_Z: + /* If mapped to z-axis */ + dev->remap.x_axis = MAP_Z_AXIS; + remap.x_axis = MAP_Z_AXIS; + break; + default: + break; + } + + /* Store the re-mapped x-axis sign in the device + structure and its value in local structure */ + if (remapped_axis->x & BMI2_AXIS_SIGN) { + /* If x-axis is mapped to -ve sign */ + dev->remap.x_axis_sign = NEG_SIGN; + remap.x_axis_sign = MAP_NEGATIVE; + } else { + dev->remap.x_axis_sign = POS_SIGN; + remap.x_axis_sign = MAP_POSITIVE; + } + + /* Store the value of re-mapped y-axis in both + device structure and the local structure */ + switch (remap_y) { + case BMI2_X: + /* If mapped to x-axis */ + dev->remap.y_axis = MAP_X_AXIS; + remap.y_axis = MAP_X_AXIS; + break; + case BMI2_Y: + /* If mapped to y-axis */ + dev->remap.y_axis = MAP_Y_AXIS; + remap.y_axis = MAP_Y_AXIS; + break; + case BMI2_Z: + /* If mapped to z-axis */ + dev->remap.y_axis = MAP_Z_AXIS; + remap.y_axis = MAP_Z_AXIS; + + break; + default: + break; + } + + /* Store the re-mapped y-axis sign in the device + structure and its value in local structure */ + if (remapped_axis->y & BMI2_AXIS_SIGN) { + /* If y-axis is mapped to -ve sign */ + dev->remap.y_axis_sign = NEG_SIGN; + remap.y_axis_sign = MAP_NEGATIVE; + } else { + dev->remap.y_axis_sign = POS_SIGN; + remap.y_axis_sign = MAP_POSITIVE; + } + + /* Store the value of re-mapped z-axis in both + device structure and the local structure */ + switch (remap_z) { + case BMI2_X: + /* If mapped to x-axis */ + dev->remap.z_axis = MAP_X_AXIS; + remap.z_axis = MAP_X_AXIS; + break; + case BMI2_Y: + /* If mapped to y-axis */ + dev->remap.z_axis = MAP_Y_AXIS; + remap.z_axis = MAP_Y_AXIS; + break; + case BMI2_Z: + /* If mapped to z-axis */ + dev->remap.z_axis = MAP_Z_AXIS; + remap.z_axis = MAP_Z_AXIS; + break; + default: + break; + } + + /* Store the re-mapped z-axis sign in the device + structure and its value in local structure */ + if (remapped_axis->z & BMI2_AXIS_SIGN) { + /* If z-axis is mapped to -ve sign */ + dev->remap.z_axis_sign = NEG_SIGN; + remap.z_axis_sign = MAP_NEGATIVE; + } else { + dev->remap.z_axis_sign = POS_SIGN; + remap.z_axis_sign = MAP_POSITIVE; + } + + /* Set the re-mapped axes in the sensor */ + rslt = set_remap_axes(&remap, dev); + } else { + rslt = BMI2_E_REMAP_ERROR; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API updates the gyroscope user-gain. + */ +int8_t bmi2_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to select sensor */ + uint8_t sens_sel[2] = {BMI2_GYRO, BMI2_GYRO_GAIN_UPDATE}; + /* Structure to define sensor configurations */ + struct bmi2_sens_config sens_cfg = {0}; + /* Variable to store status of user-gain update module */ + uint8_t status = 0; + /* Variable to define count */ + uint8_t count = 100; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (user_gain != NULL)) { + /* Select type of feature */ + sens_cfg.type = BMI2_GYRO_GAIN_UPDATE; + + /* Get the user gain configurations */ + rslt = bmi2_get_sensor_config(&sens_cfg, 1, dev); + if (rslt == BMI2_OK) { + /* Get the user-defined ratio */ + sens_cfg.cfg.gyro_gain_update = *user_gain; + + /* Set rate ratio for all axes */ + rslt = bmi2_set_sensor_config(&sens_cfg, 1, dev); + } + + /* Disable gyroscope */ + if (rslt == BMI2_OK) + rslt = bmi2_sensor_disable(&sens_sel[0], 1, dev); + + /* Enable gyroscope user-gain update module */ + if (rslt == BMI2_OK) + rslt = bmi2_sensor_enable(&sens_sel[1], 1, dev); + + /* Set the command to trigger the computation */ + if (rslt == BMI2_OK) + rslt = bmi2_set_command_register(BMI2_USR_GAIN_CMD, dev); + + if (rslt == BMI2_OK) { + /* Poll until enable bit of user-gain update is 0 */ + while (count--) { + rslt = get_user_gain_upd_status(&status, dev); + if ((rslt == BMI2_OK) && (status == 0)) { + /* Enable compensation of gain defined + in the GAIN register */ + rslt = enable_gyro_gain(BMI2_ENABLE, dev); + /* Enable gyroscope */ + if (rslt == BMI2_OK) + rslt = bmi2_sensor_enable(&sens_sel[0], 1, dev); + break; + } + + dev->delay_ms(10); + } + + /* Return error if user-gain update is failed */ + if ((rslt == BMI2_OK) && (status != 0)) + rslt = BMI2_E_GYR_USER_GAIN_UPD_FAIL; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the compensated gyroscope user-gain values. + */ +int8_t bmi2_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define register data */ + uint8_t reg_data[3] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyr_usr_gain != NULL)) { + /* Get the gyroscope compensated gain values */ + rslt = bmi2_get_regs(BMI2_GYR_USR_GAIN_0_ADDR, reg_data, 3, dev); + if (rslt == BMI2_OK) { + /* Gyroscope user gain correction X-axis */ + gyr_usr_gain->x = (int8_t)BMI2_GET_BIT_POS0(reg_data[0], BMI2_GYR_USR_GAIN_X); + /* Gyroscope user gain correction Y-axis */ + gyr_usr_gain->y = (int8_t)BMI2_GET_BIT_POS0(reg_data[1], BMI2_GYR_USR_GAIN_Y); + /* Gyroscope user gain correction z-axis */ + gyr_usr_gain->z = (int8_t)BMI2_GET_BIT_POS0(reg_data[2], BMI2_GYR_USR_GAIN_Z); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API enables/disables gyroscope offset compensation. It adds the + * offsets defined in the offset register with gyroscope data. + */ +int8_t bmi2_set_gyro_offset_comp(uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define register data */ + uint8_t reg_data = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Get the status of gyroscope offset enable */ + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_OFF_COMP_EN, enable); + /* Enable/Disable gyroscope offset compensation */ + rslt = bmi2_set_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API reads the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + */ +int8_t bmi2_read_gyro_offset_comp_axes(struct bmi2_sens_axes_data *gyr_off_comp_axes, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define register data */ + uint8_t reg_data[4] = {0}; + /* Variable to store LSB value of offset compensation for x-axis */ + uint8_t gyr_off_lsb_x; + /* Variable to store LSB value of offset compensation for y-axis */ + uint8_t gyr_off_lsb_y; + /* Variable to store LSB value of offset compensation for z-axis */ + uint8_t gyr_off_lsb_z; + /* Variable to store MSB value of offset compensation for x-axis */ + uint8_t gyr_off_msb_x; + /* Variable to store MSB value of offset compensation for y-axis */ + uint8_t gyr_off_msb_y; + /* Variable to store MSB value of offset compensation for z-axis */ + uint8_t gyr_off_msb_z; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyr_off_comp_axes != NULL)) { + /* Get the gyroscope compensated offset values */ + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_3_ADDR, reg_data, 4, dev); + if (rslt == BMI2_OK) { + /* Get LSB and MSB values of offset compensation for + x, y and z axis */ + gyr_off_lsb_x = reg_data[0]; + gyr_off_lsb_y = reg_data[1]; + gyr_off_lsb_z = reg_data[2]; + gyr_off_msb_x = reg_data[3] & GYR_OFF_COMP_MSB_X_MASK; + gyr_off_msb_y = reg_data[3] & GYR_OFF_COMP_MSB_Y_MASK; + gyr_off_msb_z = reg_data[3] & GYR_OFF_COMP_MSB_Z_MASK; + + /* Gyroscope offset compensation value for x-axis */ + gyr_off_comp_axes->x = (int16_t)(((uint16_t)gyr_off_msb_x << 8) | gyr_off_lsb_x); + /* Gyroscope offset compensation value for y-axis */ + gyr_off_comp_axes->y = (int16_t)(((uint16_t)gyr_off_msb_y << 6) | gyr_off_lsb_y); + /* Gyroscope offset compensation value for z-axis */ + gyr_off_comp_axes->z = (int16_t)(((uint16_t)gyr_off_msb_z << 4) | gyr_off_lsb_z); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API writes the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + */ +int8_t bmi2_write_gyro_offset_comp_axes(const struct bmi2_sens_axes_data *gyr_off_comp_axes, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define register data */ + uint8_t reg_data[4] = {0}; + /* Variable to store MSB value of offset compensation for x-axis */ + uint8_t gyr_off_msb_x; + /* Variable to store MSB value of offset compensation for y-axis */ + uint8_t gyr_off_msb_y; + /* Variable to store MSB value of offset compensation for z-axis */ + uint8_t gyr_off_msb_z; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (gyr_off_comp_axes != NULL)) { + /* Get the MSB values of gyroscope compensated offset values */ + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data[3], 1, dev); + if (rslt == BMI2_OK) { + /* Get MSB value of x-axis from user-input */ + gyr_off_msb_x = (uint8_t)((gyr_off_comp_axes->x & GYR_OFF_COMP_MSB_MASK) >> 8); + /* Get MSB value of y-axis from user-input */ + gyr_off_msb_y = (uint8_t)((gyr_off_comp_axes->y & GYR_OFF_COMP_MSB_MASK) >> 8); + /* Get MSB value of z-axis from user-input */ + gyr_off_msb_z = (uint8_t)((gyr_off_comp_axes->z & GYR_OFF_COMP_MSB_MASK) >> 8); + + /* Get LSB value of x-axis from user-input */ + reg_data[0] = (uint8_t)(gyr_off_comp_axes->x & GYR_OFF_COMP_LSB_MASK); + /* Get LSB value of y-axis from user-input */ + reg_data[1] = (uint8_t)(gyr_off_comp_axes->y & GYR_OFF_COMP_LSB_MASK); + /* Get LSB value of z-axis from user-input */ + reg_data[2] = (uint8_t)(gyr_off_comp_axes->z & GYR_OFF_COMP_LSB_MASK); + /* Get MSB value of x-axis to be set */ + reg_data[3] = BMI2_SET_BIT_POS0(reg_data[3], GYR_OFF_COMP_MSB_X, gyr_off_msb_x); + /* Get MSB value of y-axis to be set */ + reg_data[3] = BMI2_SET_BITS(reg_data[3], GYR_OFF_COMP_MSB_Y, gyr_off_msb_y); + /* Get MSB value of z-axis to be set */ + reg_data[3] = BMI2_SET_BITS(reg_data[3], GYR_OFF_COMP_MSB_Z, gyr_off_msb_z); + + /* Set the offset compensation values of axes */ + rslt = bmi2_set_regs(BMI2_GYR_OFF_COMP_3_ADDR, reg_data, 4, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse the activity output from the + * FIFO in header mode. + */ +int8_t bmi2_get_act_recog_output(struct bmi2_act_recog_output *act_recog, uint16_t *act_frm_len, struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define header frame */ + uint8_t frame_header = 0; + /* Variable to index the data bytes */ + uint16_t data_index; + /* Variable to index activity frames */ + uint16_t act_idx = 0; + /* Variable to indicate activity frames read */ + uint16_t frame_to_read = 0; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (act_recog != NULL) && (act_frm_len != NULL) && (fifo != NULL)) { + /* Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI */ + if (fifo->act_recog_byte_start_idx == 0) + fifo->act_recog_byte_start_idx = dev->dummy_byte; + + /* Store the number of frames to be read */ + frame_to_read = *act_frm_len; + + for (data_index = fifo->act_recog_byte_start_idx; data_index < fifo->length;) { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Skip S4S frames if S4S is enabled */ + rslt = move_if_s4s_frame(&frame_header, &data_index, fifo); + + /* Break if FIFO is empty */ + if (rslt == BMI2_W_FIFO_EMPTY) + break; + + /* Index shifted to next byte where data starts */ + data_index++; + + switch (frame_header) { + /* If header defines accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_frm_len, fifo); + break; + /* If header defines accelerometer and auxiliary + frames */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_aux_frm_len, fifo); + break; + /* If header defines accelerometer and gyroscope + frames */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_gyr_frm_len, fifo); + break; + /* If header defines accelerometer, auxiliary + and gyroscope frames */ + case BMI2_FIFO_HEADER_ALL_FRM: + rslt = move_next_frame(&data_index, fifo->all_frm_len, fifo); + break; + /* If header defines only gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->gyr_frm_len, fifo); + break; + /* If header defines only auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + rslt = move_next_frame(&data_index, fifo->aux_frm_len, fifo); + break; + /* If header defines auxiliary and gyroscope frame */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->aux_gyr_frm_len, fifo); + break; + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = move_next_frame(&data_index, BMI2_SENSOR_TIME_LENGTH, fifo); + break; + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_SKIP_FRM_LENGTH, fifo); + break; + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + /* If header defines invalid frame or end of valid + data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + /* Move the data index to the last byte + to mark completion */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + /* If header defines activity recognition frame */ + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + /* Get the activity output */ + rslt = unpack_act_recog_output(&act_recog[(act_idx)], &data_index, fifo); + + /* Update activity frame index */ + (act_idx)++; + break; + default: + /* Move the data index to the last byte in case + of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Number of frames to be read is complete or FIFO is + empty */ + if ((frame_to_read == act_idx) || (rslt == BMI2_W_FIFO_EMPTY)) + break; + } + + /* Update the activity frame index */ + (*act_frm_len) = act_idx; + + /* Update the activity byte index */ + fifo->act_recog_byte_start_idx = data_index; + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API performs the gyroscope MEMS self-test. + */ +int8_t bmi2_gyro_mems_self_test(const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define value in register data */ + uint8_t reg_data = 0; + /* Variable to define start of self-test */ + uint8_t gyr_st_mems_start = 0; + /* Variable to define result of MEMS self-test */ + uint8_t gyr_mems_ok = 0; + /* Variable to define loop */ + uint8_t loop = 10; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Wait until gyroscope becomes stable */ + dev->delay_ms(100); + + /* Start the MEMS self test of the Gyroscope */ + rslt = bmi2_get_regs(BMI2_SELF_TEST_MEMS_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Set the start bit for self-test */ + gyr_st_mems_start = BMI2_SET_BIT_POS0(reg_data, BMI2_GYR_ST_MEMS_START, SELF_TEST_START); + rslt = bmi2_set_regs(BMI2_SELF_TEST_MEMS_ADDR, &gyr_st_mems_start, 1, dev); + } + + if (rslt == BMI2_OK) { + /* Wait for 20 milli-seconds after setting the start bit + */ + dev->delay_ms(20); + + /* Wait until self-test is done */ + while (loop--) { + rslt = bmi2_get_regs(BMI2_SELF_TEST_MEMS_ADDR, ®_data, 1, dev); + gyr_st_mems_start = BMI2_GET_BIT_POS0(reg_data, BMI2_GYR_ST_MEMS_START); + + /* If the self-test is finished */ + if (gyr_st_mems_start == 0) + break; + + /* Wait for 10 milli-seconds */ + dev->delay_ms(10); + } + + + if (!gyr_st_mems_start) { + /* Get the status of MEMS self-test */ + gyr_mems_ok = BMI2_GET_BITS(reg_data, BMI2_GYR_MEMS_OK); + + /* If MEMS self-test is okay */ + if (gyr_mems_ok == BMI2_ENABLE) + rslt = BMI2_OK; + else + rslt = BMI2_E_SELF_TEST_FAIL; + } else { + + rslt = BMI2_E_SELF_TEST_NOT_DONE; + } + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API updates the cross sensitivity coefficient between gyroscope's + * X and Z axes. + */ +int8_t bmi2_get_gyro_cross_sense(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Structure to define the sensor data */ + struct bmi2_sensor_data data = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Select the feature whose data is to be acquired */ + data.type = BMI2_GYRO_CROSS_SENSE; + + /* Get the respective data */ + rslt = bmi2_get_sensor_data(&data, 1, dev); + if (rslt == BMI2_OK) { + + /* Update the gyroscope cross sense value of z axis + in the device structure */ + dev->gyr_cross_sens_zx = data.sens_data.correction_factor_zx; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API gets Error bits and message indicating internal status. + */ +int8_t bmi2_get_internal_status(uint8_t *int_stat, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (int_stat != NULL)) { + /* Delay to read the internal status */ + dev->delay_ms(20); + /* Get the error bits and message */ + rslt = bmi2_get_regs(BMI2_INTERNAL_STATUS_ADDR, int_stat, 1, dev); + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This API performs Fast Offset Compensation for accelerometer. + */ +int8_t bmi2_perform_accel_foc(const int16_t accel_g_value[3], struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Structure to define the accelerometer configurations */ + struct bmi2_accel_config acc_cfg = {0}; + /* Variable to store status of advance power save */ + uint8_t aps = 0; + /* Variable to store status of accelerometer enable */ + uint8_t acc_en = 0; + /* Array of structure to store accelerometer data */ + struct bmi2_sens_axes_data accel_value[128] = { {0} }; + /* Structure to store the average of accelerometer data */ + struct bmi2_sens_axes_data accel_avg = {0}; + /* Structure to store accelerometer data temporarily */ + struct temp_value_int32 temp = {0}; + /* Variable to store status read from the status register */ + uint8_t reg_status = 0; + /* Variable to define count */ + uint8_t loop = 0; + /* Variable to define range */ + uint8_t range = 0; + /* Variable to define LSB per g value */ + uint16_t lsb_per_g = 0; + /* Structure to store accelerometer data deviation from ideal value */ + struct offset_delta delta = {0}; + /* Structure to store accelerometer offset values */ + struct accel_offset offset = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Save accelerometer configurations, accelerometer enable + status and advance power save status */ + rslt = save_accel_foc_config(&acc_cfg, &aps, &acc_en, dev); + + /* Set configurations for FOC */ + if (rslt == BMI2_OK) + rslt = set_accel_foc_config(dev); + + /* Perform FOC */ + if (rslt == BMI2_OK) { + for (loop = 0; loop < 128; loop++) { + /* Giving a delay of more than 20ms since ODR is + configured as 50Hz */ + dev->delay_ms(30); + + /* Get accelerometer data ready interrupt + status */ + rslt = bmi2_get_status(®_status, dev); + + /* Read 100 samples of accelerometer data on + data ready interrupt */ + if ((rslt == BMI2_OK) && (reg_status & BMI2_DRDY_ACC)) { + + rslt = read_accel_xyz(&accel_value[loop], dev); + if (rslt == BMI2_OK) { + /* Store the data in a temporary + structure */ + temp.x = temp.x + (int32_t)accel_value[loop].x; + temp.y = temp.y + (int32_t)accel_value[loop].y; + temp.z = temp.z + (int32_t)accel_value[loop].z; + } + } + } + + if (rslt == BMI2_OK) { + /* Take average of x, y and z data for lesser + noise */ + accel_avg.x = (int16_t)(temp.x / 128); + accel_avg.y = (int16_t)(temp.y / 128); + accel_avg.z = (int16_t)(temp.z / 128); + + /* Get the exact range value */ + map_accel_range(acc_cfg.range, &range); + + /* Get the smallest possible measurable + acceleration level given the range and + resolution */ + lsb_per_g = (uint16_t)(power(2, dev->resolution) / (2 * range)); + + /* Compensate acceleration data against gravity + */ + comp_for_gravity(lsb_per_g, accel_g_value, &accel_avg, &delta); + + /* Scale according to offset register resolution + */ + scale_accel_offset(range, &delta, &offset); + + /* Invert the accelerometer offset data */ + invert_accel_offset(&offset); + + /* Write offset data in the offset compensation + register */ + rslt = write_accel_offset(&offset, dev); + } + + /* Enable offset compensation */ + if (rslt == BMI2_OK) + rslt = set_accel_offset_comp(BMI2_ENABLE, dev); + + /* Restore the saved configurations */ + if (rslt == BMI2_OK) + rslt = restore_accel_foc_config(&acc_cfg, aps, acc_en, dev); + } + } + + return rslt; +} +/*! + * @brief This API performs Fast Offset Compensation for gyroscope. + */ +int8_t bmi2_perform_gyro_foc(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Structure to define the gyroscope configurations */ + struct bmi2_gyro_config gyr_cfg = {0}; + /* Variable to store status of advance power save */ + uint8_t aps = 0; + /* Variable to store status of gyroscope enable */ + uint8_t gyr_en = 0; + /* Array of structure to store gyroscope data */ + struct bmi2_sens_axes_data gyr_value[128] = { {0} }; + /* Structure to store gyroscope data temporarily */ + struct temp_value_int32 temp = {0}; + /* Variable to store status read from the status register */ + uint8_t reg_status = 0; + /* Variable to define count */ + uint8_t loop = 0; + /* Structure to store the offset values to be stored in the register */ + struct bmi2_sens_axes_data gyro_offset = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Save gyroscope configurations, gyroscope enable + status and advance power save status */ + rslt = save_gyro_config(&gyr_cfg, &aps, &gyr_en, dev); + + /* Set configurations for gyroscope FOC */ + if (rslt == BMI2_OK) + rslt = set_gyro_foc_config(dev); + + /* Perform FOC */ + if (rslt == BMI2_OK) { + for (loop = 0; loop < 128; loop++) { + /* Giving a delay of more than 40ms since ODR is + configured as 25Hz */ + dev->delay_ms(50); + + /* Get gyroscope data ready interrupt + status */ + rslt = bmi2_get_status(®_status, dev); + + /* Read 100 samples of gyroscope data on + data ready interrupt */ + if ((rslt == BMI2_OK) && (reg_status & BMI2_DRDY_GYR)) { + + rslt = read_gyro_xyz(&gyr_value[loop], dev); + if (rslt == BMI2_OK) { + /* Store the data in a temporary + structure */ + temp.x = temp.x + (int32_t)gyr_value[loop].x; + temp.y = temp.y + (int32_t)gyr_value[loop].y; + temp.z = temp.z + (int32_t)gyr_value[loop].z; + } + + } + } + + if (rslt == BMI2_OK) { + /* Take average of x, y and z data for lesser + noise. It is same as offset data since lsb/dps + is same for both data and offset register */ + gyro_offset.x = (int16_t)(temp.x / 128); + gyro_offset.y = (int16_t)(temp.y / 128); + gyro_offset.z = (int16_t)(temp.z / 128); + + /* Saturate gyroscope data since the offset + registers are of 10 bit value where as the + gyroscope data is of 16 bit value */ + saturate_gyro_data(&gyro_offset); + + /* Invert the gyroscope offset data */ + invert_gyro_offset(&gyro_offset); + + /* Write offset data in the gyroscope offset + compensation register */ + rslt = bmi2_write_gyro_offset_comp_axes(&gyro_offset, dev); + } + + /* Enable gyroscope offset compensation */ + if (rslt == BMI2_OK) + rslt = bmi2_set_gyro_offset_comp(BMI2_ENABLE, dev); + + /* Restore the saved gyroscope configurations */ + if (rslt == BMI2_OK) + rslt = restore_gyro_config(&gyr_cfg, aps, gyr_en, dev); + } + } + + return rslt; +} + +/***************************************************************************/ +/*! Local Function Definitions +****************************************************************************/ +/*! + * @brief This internal API writes the configuration file. + */ +static int8_t write_config_file(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to update the configuration file index */ + uint16_t index = 0; + /* Variable to get the remainder */ + uint8_t remain = (uint8_t)(BMI2_CONFIG_FILE_SIZE % dev->read_write_len); + /* Variable to get the balance bytes */ + uint16_t bal_byte = 0; + /* Variable to define temporary read/write length */ + uint16_t read_write_len = 0; + + /* Disable advanced power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + dev->delay_ms(1); + + if (rslt == BMI2_OK) { + /* Disable loading of the configuration */ + rslt = set_config_load(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) { + if (!remain) { + /* Write the configuration file */ + for (index = 0; (index < BMI2_CONFIG_FILE_SIZE) && (rslt == BMI2_OK); index += dev->read_write_len) + rslt = upload_file((dev->config_file_ptr + index), index, dev); + } else { + /* Get the balance bytes */ + bal_byte = (uint16_t)BMI2_CONFIG_FILE_SIZE - (uint16_t)remain; + /* Write the configuration file for the balance + bytes */ + for (index = 0; (index < bal_byte) && (rslt == BMI2_OK); index += dev->read_write_len) + rslt = upload_file((dev->config_file_ptr + index), index, dev); + + if (rslt == BMI2_OK) { + /* Update length in a temporary + variable */ + read_write_len = dev->read_write_len; + + /* Write the remaining bytes in 2 bytes + length */ + dev->read_write_len = 2; + /* Write the configuration file for the + remaining bytes */ + for (index = bal_byte; (index < BMI2_CONFIG_FILE_SIZE) && (rslt == BMI2_OK); + index += dev->read_write_len) + rslt = upload_file((dev->config_file_ptr + index), index, dev); + + /* Restore the user set length back + from the temporary variable */ + dev->read_write_len = read_write_len; + } + } + + if (rslt == BMI2_OK) { + /* Enable loading of the configuration */ + rslt = set_config_load(BMI2_ENABLE, dev); + /* Wait till ASIC is initialized */ + dev->delay_ms(150); + + if (rslt == BMI2_OK) { + /* Enable advanced power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + dev->delay_ms(1); + } + } + } + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables the loading of the configuration + * file. + */ +static int8_t set_config_load(uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data = 0; + + rslt = bmi2_get_regs(BMI2_INIT_CTRL_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_CONF_LOAD_EN, enable); + rslt = bmi2_set_regs(BMI2_INIT_CTRL_ADDR, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API loads the configuration file. + */ +static int8_t upload_file(const uint8_t *config_data, uint16_t index, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store address */ + uint8_t addr_array[2] = {0}; + + if (config_data != NULL) { + /* Store 0 to 3 bits of address in first byte */ + addr_array[0] = (uint8_t)((index / 2) & 0x0F); + /* Store 4 to 11 bits of address in the second byte */ + addr_array[1] = (uint8_t)((index / 2) >> 4); + + /* Write the 2 bytes of address in consecutive locations */ + rslt = bmi2_set_regs(BMI2_INIT_ADDR_0, addr_array, 2, dev); + if (rslt == BMI2_OK) { + /* Burst write configuration file data corresponding to + user set length */ + rslt = bmi2_set_regs(BMI2_INIT_DATA_ADDR, (uint8_t *)config_data, dev->read_write_len, dev); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the selected sensor/features. + */ +static int8_t sensor_enable(uint32_t sensor_sel, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store register values */ + uint8_t reg_data = 0; + /* Variable to define loop */ + uint8_t loop = 1; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Enable accelerometer */ + if (sensor_sel & BMI2_ACCEL_SENS_SEL) + reg_data = BMI2_SET_BITS(reg_data, BMI2_ACC_EN, BMI2_ENABLE); + + /* Enable gyroscope */ + if (sensor_sel & BMI2_GYRO_SENS_SEL) + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_EN, BMI2_ENABLE); + + /* Enable auxiliary sensor */ + if (sensor_sel & BMI2_AUX_SENS_SEL) + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_AUX_EN, BMI2_ENABLE); + + /* Enable temperature sensor */ + if (sensor_sel & BMI2_TEMP_SENS_SEL) + reg_data = BMI2_SET_BITS(reg_data, BMI2_TEMP_EN, BMI2_ENABLE); + + /* Enable the sensors that are set in the power control + register */ + if (sensor_sel & BMI2_MAIN_SENSORS) + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + } + + if ((rslt == BMI2_OK) && (sensor_sel & ~(BMI2_MAIN_SENSORS))) { + + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) { + while (loop--) { + /* Enable sig-motion feature */ + if (sensor_sel & BMI2_SIG_MOTION_SEL) { + rslt = set_sig_motion(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_SIG_MOTION_SEL; + else + break; + } + + /* Enable any motion feature */ + if (sensor_sel & BMI2_ANY_MOT_SEL) { + rslt = set_any_motion(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_ANY_MOT_SEL; + else + break; + } + + /* Enable no motion feature */ + if (sensor_sel & BMI2_NO_MOT_SEL) { + rslt = set_no_motion(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_NO_MOT_SEL; + else + break; + } + + /* Enable step detector feature */ + if (sensor_sel & BMI2_STEP_DETECT_SEL) { + rslt = set_step_detector(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_STEP_DETECT_SEL; + else + break; + } + + /* Enable step counter feature */ + if (sensor_sel & BMI2_STEP_COUNT_SEL) { + rslt = set_step_counter(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_STEP_COUNT_SEL; + else + break; + } + + /* Enable step activity feature */ + if (sensor_sel & BMI2_STEP_ACT_SEL) { + rslt = set_step_activity(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_STEP_ACT_SEL; + else + break; + } + + /* Enable gyroscope user gain */ + if (sensor_sel & BMI2_GYRO_GAIN_UPDATE_SEL) { + rslt = set_gyro_user_gain(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_GYRO_GAIN_UPDATE_SEL; + else + break; + } + /* Enable tilt feature */ + if (sensor_sel & BMI2_TILT_SEL) { + rslt = set_tilt(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_TILT_SEL; + else + break; + } + + /* Enable pick-up feature */ + if (sensor_sel & BMI2_PICK_UP_SEL) { + rslt = set_pick_up(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_PICK_UP_SEL; + else + break; + } + + /* Enable glance feature */ + if (sensor_sel & BMI2_GLANCE_DET_SEL) { + rslt = set_glance_detector(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_GLANCE_DET_SEL; + else + break; + } + + /* Enable wake-up feature */ + if (sensor_sel & BMI2_WAKE_UP_SEL) { + rslt = set_wake_up(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_WAKE_UP_SEL; + else + break; + } + + /* Enable orientation feature */ + if (sensor_sel & BMI2_ORIENT_SEL) { + rslt = set_orientation(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_ORIENT_SEL; + else + break; + } + + /* Enable high-g feature */ + if (sensor_sel & BMI2_HIGH_G_SEL) { + rslt = set_high_g(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_HIGH_G_SEL; + else + break; + } + + /* Enable low-g feature */ + if (sensor_sel & BMI2_LOW_G_SEL) { + rslt = set_low_g(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_LOW_G_SEL; + else + break; + } + + /* Enable flat feature */ + if (sensor_sel & BMI2_FLAT_SEL) { + rslt = set_flat(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_FLAT_SEL; + else + break; + } + + /* Enable external sensor feature */ + if (sensor_sel & BMI2_EXT_SENS_SEL) { + rslt = set_ext_sens_sync(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_EXT_SENS_SEL; + else + break; + } + + /* Enable gyroscope self-offset correction + feature */ + if (sensor_sel & BMI2_GYRO_SELF_OFF_SEL) { + rslt = set_gyro_self_offset_corr(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_GYRO_SELF_OFF_SEL; + else + break; + } + + /* Enable wrist gesture feature */ + if (sensor_sel & BMI2_WRIST_GEST_SEL) { + rslt = set_wrist_gesture(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_WRIST_GEST_SEL; + else + break; + } + + /* Enable wrist wear wake-up feature */ + if (sensor_sel & BMI2_WRIST_WEAR_WAKE_UP_SEL) { + rslt = set_wrist_wear_wake_up(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_WRIST_WEAR_WAKE_UP_SEL; + else + break; + } + + /* Enable activity recognition feature */ + if (sensor_sel & BMI2_ACTIVITY_RECOG_SEL) { + rslt = set_act_recog(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_ACTIVITY_RECOG_SEL; + else + break; + } + } + + /* Enable Advance power save if disabled while + configuring and not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API disables the selected sensors/features. + */ +static int8_t sensor_disable(uint32_t sensor_sel, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store register values */ + uint8_t reg_data = 0; + /* Variable to define loop */ + uint8_t loop = 1; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Disable accelerometer */ + if (sensor_sel & BMI2_ACCEL_SENS_SEL) + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_ACC_EN); + + /* Disable gyroscope */ + if (sensor_sel & BMI2_GYRO_SENS_SEL) + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_GYR_EN); + + /* Disable auxiliary sensor */ + if (sensor_sel & BMI2_AUX_SENS_SEL) + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_AUX_EN); + + /* Disable temperature sensor */ + if (sensor_sel & BMI2_TEMP_SENS_SEL) + reg_data = BMI2_SET_BIT_VAL0(reg_data, BMI2_TEMP_EN); + + /* Disable the sensors that are set in the power control + register */ + if (sensor_sel & BMI2_MAIN_SENSORS) + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, ®_data, 1, dev); + } + + if ((rslt == BMI2_OK) && (sensor_sel & ~(BMI2_MAIN_SENSORS))) { + + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) { + while (loop--) { + /* Disable sig-motion feature */ + if (sensor_sel & BMI2_SIG_MOTION_SEL) { + rslt = set_sig_motion(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_SIG_MOTION_SEL; + else + break; + } + + /* Disable any-motion feature */ + if (sensor_sel & BMI2_ANY_MOT_SEL) { + rslt = set_any_motion(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_ANY_MOT_SEL; + else + break; + } + + /* Disable no-motion feature */ + if (sensor_sel & BMI2_NO_MOT_SEL) { + rslt = set_no_motion(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_NO_MOT_SEL; + else + break; + } + + /* Disable step detector feature */ + if (sensor_sel & BMI2_STEP_DETECT_SEL) { + rslt = set_step_detector(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_STEP_DETECT_SEL; + else + break; + } + + /* Disable step counter feature */ + if (sensor_sel & BMI2_STEP_COUNT_SEL) { + rslt = set_step_counter(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_STEP_COUNT_SEL; + else + break; + } + + /* Disable step activity feature */ + if (sensor_sel & BMI2_STEP_ACT_SEL) { + rslt = set_step_activity(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_STEP_ACT_SEL; + else + break; + } + + /* Disable gyroscope user gain */ + if (sensor_sel & BMI2_GYRO_GAIN_UPDATE_SEL) { + rslt = set_gyro_user_gain(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_GYRO_GAIN_UPDATE_SEL; + else + break; + } + + /* Disable tilt feature */ + if (sensor_sel & BMI2_TILT_SEL) { + rslt = set_tilt(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_TILT_SEL; + else + break; + } + + /* Disable pick-up feature */ + if (sensor_sel & BMI2_PICK_UP_SEL) { + rslt = set_pick_up(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_PICK_UP_SEL; + else + break; + } + + /* Disable glance feature */ + if (sensor_sel & BMI2_GLANCE_DET_SEL) { + rslt = set_glance_detector(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_GLANCE_DET_SEL; + else + break; + } + + /* Disable wake-up feature */ + if (sensor_sel & BMI2_WAKE_UP_SEL) { + rslt = set_wake_up(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_WAKE_UP_SEL; + else + break; + } + + /* Disable orientation feature */ + if (sensor_sel & BMI2_ORIENT_SEL) { + rslt = set_orientation(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_ORIENT_SEL; + else + break; + } + + /* Disable high-g feature */ + if (sensor_sel & BMI2_HIGH_G_SEL) { + rslt = set_high_g(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_HIGH_G_SEL; + else + break; + } + + /* Disable low-g feature */ + if (sensor_sel & BMI2_LOW_G_SEL) { + rslt = set_low_g(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_LOW_G_SEL; + else + break; + } + + /* Disable flat feature */ + if (sensor_sel & BMI2_FLAT_SEL) { + rslt = set_flat(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_FLAT_SEL; + else + break; + } + + /* Disable external sensor feature */ + if (sensor_sel & BMI2_EXT_SENS_SEL) { + rslt = set_ext_sens_sync(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_EXT_SENS_SEL; + else + break; + } + + /* Disable gyroscope self-offset correction + feature */ + if (sensor_sel & BMI2_GYRO_SELF_OFF_SEL) { + rslt = set_gyro_self_offset_corr(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_GYRO_SELF_OFF_SEL; + else + break; + } + + /* Disable wrist gesture feature */ + if (sensor_sel & BMI2_WRIST_GEST_SEL) { + rslt = set_wrist_gesture(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_WRIST_GEST_SEL; + else + break; + } + + /* Disable wrist wear wake-up feature */ + if (sensor_sel & BMI2_WRIST_WEAR_WAKE_UP_SEL) { + rslt = set_wrist_wear_wake_up(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat &= ~BMI2_WRIST_WEAR_WAKE_UP_SEL; + else + break; + } + + /* Disable activity recognition feature */ + if (sensor_sel & BMI2_ACTIVITY_RECOG_SEL) { + rslt = set_act_recog(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) + dev->sens_en_stat |= BMI2_ACTIVITY_RECOG_SEL; + else + break; + } + } + + /* Enable Advance power save if disabled while + configuring and not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API selects the sensor/features to be enabled or + * disabled. + */ +static int8_t select_sensor(const uint8_t *sens_list, uint8_t n_sens, uint32_t *sensor_sel) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variable to define loop */ + uint8_t count; + + for (count = 0; count < n_sens; count++) { + switch (sens_list[count]) { + case BMI2_ACCEL: + *sensor_sel |= BMI2_ACCEL_SENS_SEL; + break; + case BMI2_GYRO: + *sensor_sel |= BMI2_GYRO_SENS_SEL; + break; + case BMI2_AUX: + *sensor_sel |= BMI2_AUX_SENS_SEL; + break; + case BMI2_TEMP: + *sensor_sel |= BMI2_TEMP_SENS_SEL; + break; + case BMI2_SIG_MOTION: + *sensor_sel |= BMI2_SIG_MOTION_SEL; + break; + case BMI2_ANY_MOTION: + *sensor_sel |= BMI2_ANY_MOT_SEL; + break; + case BMI2_NO_MOTION: + *sensor_sel |= BMI2_NO_MOT_SEL; + break; + case BMI2_STEP_DETECTOR: + *sensor_sel |= BMI2_STEP_DETECT_SEL; + break; + case BMI2_STEP_COUNTER: + *sensor_sel |= BMI2_STEP_COUNT_SEL; + break; + case BMI2_STEP_ACTIVITY: + *sensor_sel |= BMI2_STEP_ACT_SEL; + break; + case BMI2_GYRO_GAIN_UPDATE: + *sensor_sel |= BMI2_GYRO_GAIN_UPDATE_SEL; + break; + case BMI2_TILT: + *sensor_sel |= BMI2_TILT_SEL; + break; + case BMI2_PICK_UP: + *sensor_sel |= BMI2_PICK_UP_SEL; + break; + case BMI2_GLANCE_DETECTOR: + *sensor_sel |= BMI2_GLANCE_DET_SEL; + break; + case BMI2_WAKE_UP: + *sensor_sel |= BMI2_WAKE_UP_SEL; + break; + case BMI2_ORIENTATION: + *sensor_sel |= BMI2_ORIENT_SEL; + break; + case BMI2_HIGH_G: + *sensor_sel |= BMI2_HIGH_G_SEL; + break; + case BMI2_LOW_G: + *sensor_sel |= BMI2_LOW_G_SEL; + break; + case BMI2_FLAT: + *sensor_sel |= BMI2_FLAT_SEL; + break; + case BMI2_EXT_SENS_SYNC: + *sensor_sel |= BMI2_EXT_SENS_SEL; + break; + case BMI2_GYRO_SELF_OFF: + *sensor_sel |= BMI2_GYRO_SELF_OFF_SEL; + break; + case BMI2_WRIST_GESTURE: + *sensor_sel |= BMI2_WRIST_GEST_SEL; + break; + case BMI2_WRIST_WEAR_WAKE_UP: + *sensor_sel |= BMI2_WRIST_WEAR_WAKE_UP_SEL; + break; + case BMI2_ACTIVITY_RECOG: + *sensor_sel |= BMI2_ACTIVITY_RECOG_SEL; + break; + default: + rslt = BMI2_E_INVALID_SENSOR; + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable any motion feature. + */ +static int8_t set_any_motion(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for any-motion */ + struct bmi2_feature_config any_mot_config = {0}; + + /* Search for any-motion feature and extract its configurations + details */ + feat_found = extract_input_feat_config(&any_mot_config, BMI2_ANY_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where any-motion + feature resides */ + rslt = get_feat_config(any_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of any-motion + axes */ + idx = any_mot_config.start_addr + ANY_MOT_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], ANY_NO_MOT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable no-motion feature. + */ +static int8_t set_no_motion(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for no-motion */ + struct bmi2_feature_config no_mot_config = {0}; + + /* Search for no-motion feature and extract its configurations + details */ + feat_found = extract_input_feat_config(&no_mot_config, BMI2_NO_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where any/no-motion + feature resides */ + rslt = get_feat_config(no_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of no-motion + axes */ + idx = no_mot_config.start_addr + NO_MOT_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], ANY_NO_MOT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable sig-motion feature. + */ +static int8_t set_sig_motion(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for sig-motion */ + struct bmi2_feature_config sig_mot_config = {0}; + + /* Search for sig-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&sig_mot_config, BMI2_SIG_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where sig-motion feature + resides */ + rslt = get_feat_config(sig_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of sig-motion */ + idx = sig_mot_config.start_addr + SIG_MOT_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], SIG_MOT_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable step detector feature. + */ +static int8_t set_step_detector(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for step detector */ + struct bmi2_feature_config step_det_config = {0}; + + /* Search for step detector feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&step_det_config, BMI2_STEP_DETECTOR, dev); + + if (feat_found) { + /* Get the configuration from the page where step detector + feature resides */ + rslt = get_feat_config(step_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of step + detector */ + idx = step_det_config.start_addr + STEP_COUNT_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], STEP_DET_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable step counter feature. + */ +static int8_t set_step_counter(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for step counter */ + struct bmi2_feature_config step_count_config = {0}; + + /* Search for step counter feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&step_count_config, BMI2_STEP_COUNTER, dev); + + if (feat_found) { + /* Get the configuration from the page where step-counter + feature resides */ + rslt = get_feat_config(step_count_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of step - + counter */ + idx = step_count_config.start_addr + STEP_COUNT_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], STEP_COUNT_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable step activity detection. + */ +static int8_t set_step_activity(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for step activity */ + struct bmi2_feature_config step_act_config = {0}; + + /* Search for step activity feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&step_act_config, BMI2_STEP_ACTIVITY, dev); + + if (feat_found) { + /* Get the configuration from the page where step-activity + feature resides */ + rslt = get_feat_config(step_act_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of step - + activity */ + idx = step_act_config.start_addr + STEP_COUNT_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], STEP_ACT_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable tilt feature. + */ +static int8_t set_tilt(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for tilt */ + struct bmi2_feature_config tilt_config = {0}; + + /* Search for tilt feature and extract its configuration details */ + feat_found = extract_input_feat_config(&tilt_config, BMI2_TILT, dev); + + if (feat_found) { + /* Get the configuration from the page where tilt feature + resides */ + rslt = get_feat_config(tilt_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of tilt */ + idx = tilt_config.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], TILT_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable pick-up feature. + */ +static int8_t set_pick_up(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for pick-up */ + struct bmi2_feature_config pick_up_config = {0}; + + /* Search for pick-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&pick_up_config, BMI2_PICK_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where pick-up feature + resides */ + rslt = get_feat_config(pick_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of pick-up */ + idx = pick_up_config.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], PICK_UP_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable glance detector feature. + */ +static int8_t set_glance_detector(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for glance detector */ + struct bmi2_feature_config glance_det_config = {0}; + + /* Search for glance detector feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&glance_det_config, BMI2_GLANCE_DETECTOR, dev); + + if (feat_found) { + /* Get the configuration from the page where glance detector + feature resides */ + rslt = get_feat_config(glance_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of glance */ + idx = glance_det_config.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], GLANCE_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable wake-up feature through + * single or double tap. + */ +static int8_t set_wake_up(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for wake-up */ + struct bmi2_feature_config wake_up_config = {0}; + + /* Search for wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wake_up_config, BMI2_WAKE_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where wake-up feature + resides */ + rslt = get_feat_config(wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of wake-up */ + idx = wake_up_config.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], WAKE_UP_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable orientation feature. + */ +static int8_t set_orientation(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for orientation */ + struct bmi2_feature_config orient_config = {0}; + + /* Search for orientation feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&orient_config, BMI2_ORIENTATION, dev); + + if (feat_found) { + /* Get the configuration from the page where orientation feature + resides */ + rslt = get_feat_config(orient_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of + orientation */ + idx = orient_config.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], ORIENT_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable high-g feature. + */ +static int8_t set_high_g(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for high-g */ + struct bmi2_feature_config high_g_config = {0}; + + /* Search for high-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&high_g_config, BMI2_HIGH_G, dev); + + if (feat_found) { + /* Get the configuration from the page where high-g feature + resides */ + rslt = get_feat_config(high_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of high-g */ + idx = high_g_config.start_addr + HIGH_G_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], HIGH_G_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable low-g feature. + */ +static int8_t set_low_g(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for low-g */ + struct bmi2_feature_config low_g_config = {0}; + + /* Search for low-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&low_g_config, BMI2_LOW_G, dev); + + if (feat_found) { + /* Get the configuration from the page where low-g feature + resides */ + rslt = get_feat_config(low_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of low-g */ + idx = low_g_config.start_addr + LOW_G_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], LOW_G_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable flat feature. + */ +static int8_t set_flat(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for flat */ + struct bmi2_feature_config flat_config = {0}; + + /* Search for flat feature and extract its configuration details */ + feat_found = extract_input_feat_config(&flat_config, BMI2_FLAT, dev); + + if (feat_found) { + /* Get the configuration from the page where flat feature + resides */ + rslt = get_feat_config(flat_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of flat */ + idx = flat_config.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], FLAT_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable external sensor sync + * feature. + */ +static int8_t set_ext_sens_sync(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for external sensor sync */ + struct bmi2_feature_config ext_sens_sync_cfg = {0}; + + /* Search for sync feature and extract its configuration details */ + feat_found = extract_input_feat_config(&ext_sens_sync_cfg, BMI2_EXT_SENS_SYNC, dev); + + if (feat_found) { + /* Get the configuration from the page where sync feature + resides */ + rslt = get_feat_config(ext_sens_sync_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of sync */ + idx = ext_sens_sync_cfg.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], EXT_SENS_SYNC_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gives an option to enable self-offset correction + * feature of gyroscope, either internally or by the host. + */ +static int8_t set_gyro_self_offset_corr(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for self-offset correction */ + struct bmi2_feature_config self_off_corr_cfg = {0}; + + /* Search for self-offset correction and extract its configuration + details */ + feat_found = extract_input_feat_config(&self_off_corr_cfg, BMI2_GYRO_SELF_OFF, dev); + + if (feat_found) { + /* Get the configuration from the page where self-offset + correction feature resides */ + rslt = get_feat_config(self_off_corr_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of self-offset + correction */ + idx = self_off_corr_cfg.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], GYR_SELF_OFF_CORR_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the wrist gesture feature. + */ +static int8_t set_wrist_gesture(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_cfg = {0}; + + /* Search for wrist gesture and extract its configuration details */ + feat_found = extract_input_feat_config(&wrist_gest_cfg, BMI2_WRIST_GESTURE, dev); + + if (feat_found) { + /* Get the configuration from the page where wrist gesture + feature resides */ + rslt = get_feat_config(wrist_gest_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of wrist gesture + */ + idx = wrist_gest_cfg.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], WRIST_GEST_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables the wrist wear wake up feature. + */ +static int8_t set_wrist_wear_wake_up(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for wrist wear wake up */ + struct bmi2_feature_config wrist_wake_up_cfg = {0}; + + /* Search for wrist wear wake up and extract its configuration + details */ + feat_found = extract_input_feat_config(&wrist_wake_up_cfg, BMI2_WRIST_WEAR_WAKE_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where wrist wear wake up + feature resides */ + rslt = get_feat_config(wrist_wake_up_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of wrist wear + wake up */ + idx = wrist_wake_up_cfg.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], WRIST_WEAR_WAKE_UP_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables the activity recognition feature. + */ +static int8_t set_act_recog(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for activity recognition */ + struct bmi2_feature_config act_recog_cfg = {0}; + + /* Search for activity recognition and extract its configuration + details */ + feat_found = extract_input_feat_config(&act_recog_cfg, BMI2_ACTIVITY_RECOG, dev); + + if (feat_found) { + /* Get the configuration from the page where activity + recognition feature resides */ + rslt = get_feat_config(act_recog_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of activity + recognition */ + idx = act_recog_cfg.start_addr; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], ACTIVITY_RECOG_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to enable/disable gyroscope user gain + * feature. + */ +static int8_t set_gyro_user_gain(uint8_t enable, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for gyroscope user gain */ + struct bmi2_feature_config gyr_user_gain_cfg = {0}; + + /* Search for user gain feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&gyr_user_gain_cfg, BMI2_GYRO_GAIN_UPDATE, dev); + + if (feat_found) { + /* Get the configuration from the page where user gain feature + resides */ + rslt = get_feat_config(gyr_user_gain_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of user gain */ + idx = gyr_user_gain_cfg.start_addr + GYR_USER_GAIN_FEAT_EN_OFFSET; + /* Set the feature enable bit */ + feat_config[idx] = BMI2_SET_BITS(feat_config[idx], GYR_USER_GAIN_FEAT_EN, enable); + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets accelerometer configurations like ODR, + * bandwidth, performance mode and g-range. + */ +static int8_t set_accel_config(struct bmi2_accel_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + /* Array to store the default value of accelerometer configuration + reserved registers */ + uint8_t data_array[2] = {0}; + + /* Validate bandwidth and performance mode */ + rslt = validate_bw_perf_mode(&config->bwp, &config->filter_perf, dev); + if (rslt == BMI2_OK) { + /* Validate ODR and range */ + rslt = validate_odr_range(&config->odr, &config->range, dev); + if (rslt == BMI2_OK) { + /* Set accelerometer performance mode */ + reg_data = BMI2_SET_BITS(data_array[0], BMI2_ACC_FILTER_PERF_MODE, config->filter_perf); + + /* Set accelerometer bandwidth */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_ACC_BW_PARAM, config->bwp); + + /* Set accelerometer ODR */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_ACC_ODR, config->odr); + + /* Copy the register data to the array */ + data_array[0] = reg_data; + + /* Set accelerometer range */ + reg_data = BMI2_SET_BIT_POS0(data_array[1], BMI2_ACC_RANGE, config->range); + + /* Copy the register data to the array */ + data_array[1] = reg_data; + + /* Write accelerometer configuration to ACC_CONFand + ACC_RANGE registers simultaneously as they lie in + consecutive places */ + rslt = bmi2_set_regs(BMI2_ACC_CONF_ADDR, data_array, 2, dev); + + /* Get error status to check for invalid + configurations */ + if (rslt == BMI2_OK) + rslt = cfg_error_status(dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API validates bandwidth and performance mode of the + * accelerometer set by the user. + */ +static int8_t validate_bw_perf_mode(uint8_t *bandwidth, uint8_t *perf_mode, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate and auto-correct performance mode */ + rslt = check_boundary_val(perf_mode, BMI2_POWER_OPT_MODE, BMI2_PERF_OPT_MODE, dev); + if (rslt == BMI2_OK) { + /* Validate and auto-correct bandwidth parameter */ + if (*perf_mode == BMI2_PERF_OPT_MODE) { + /* Validate for continuous filter mode */ + rslt = check_boundary_val(bandwidth, BMI2_ACC_OSR4_AVG1, BMI2_ACC_CIC_AVG8, dev); + } else { + /* Validate for CIC averaging mode */ + rslt = check_boundary_val(bandwidth, BMI2_ACC_OSR4_AVG1, BMI2_ACC_RES_AVG128, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API validates ODR and range of the accelerometer set by + * the user. + */ +static int8_t validate_odr_range(uint8_t *odr, uint8_t *range, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate and auto correct ODR */ + rslt = check_boundary_val(odr, BMI2_ACC_ODR_0_78HZ, BMI2_ACC_ODR_1600HZ, dev); + if (rslt == BMI2_OK) { + /* Validate and auto correct Range */ + rslt = check_boundary_val(range, BMI2_ACC_RANGE_2G, BMI2_ACC_RANGE_16G, dev); + } + + return rslt; +} + +/*! + * @brief This internal API sets gyroscope configurations like ODR, bandwidth, + * low power/high performance mode, performance mode and range. It also + * maps/un-maps data interrupts to that of hardware interrupt line. + */ +static int8_t set_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + /* Array to store the default value of gyroscope configuration + reserved registers */ + uint8_t data_array[2] = {0}; + + /* Validate gyroscope configurations */ + rslt = validate_gyro_config(config, dev); + if (rslt == BMI2_OK) { + /* Set gyroscope performance mode */ + reg_data = BMI2_SET_BITS(data_array[0], BMI2_GYR_FILTER_PERF_MODE, config->filter_perf); + + /* Set gyroscope noise performance mode */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_NOISE_PERF_MODE, config->noise_perf); + + /* Set gyroscope bandwidth */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_BW_PARAM, config->bwp); + + /* Set gyroscope ODR */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_GYR_ODR, config->odr); + + /* Copy the register data to the array */ + data_array[0] = reg_data; + + /* Set gyroscope OIS range */ + reg_data = BMI2_SET_BITS(data_array[1], BMI2_GYR_OIS_RANGE, config->ois_range); + + /* Set gyroscope range */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_GYR_RANGE, config->range); + + /* Copy the register data to the array */ + data_array[1] = reg_data; + + /* Write accelerometer configuration to GYR_CONF and GYR_RANGE + registers simultaneously as they lie in consecutive places */ + rslt = bmi2_set_regs(BMI2_GYR_CONF_ADDR, data_array, 2, dev); + + /* Get error status to check for invalid configurations */ + if (rslt == BMI2_OK) + rslt = cfg_error_status(dev); + } + + return rslt; +} + +/*! + * @brief This internal API validates bandwidth, performance mode, low power/ + * high performance mode, ODR, and range set by the user. + */ +static int8_t validate_gyro_config(struct bmi2_gyro_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate and auto-correct performance mode */ + rslt = check_boundary_val(&config->filter_perf, BMI2_POWER_OPT_MODE, BMI2_PERF_OPT_MODE, dev); + if (rslt == BMI2_OK) { + /* Validate and auto-correct bandwidth parameter */ + rslt = check_boundary_val(&config->bwp, BMI2_GYR_OSR4_MODE, BMI2_GYR_CIC_MODE, dev); + if (rslt == BMI2_OK) { + /* Validate and auto-correct low power/high-performance + parameter */ + rslt = check_boundary_val(&config->noise_perf, BMI2_POWER_OPT_MODE, BMI2_PERF_OPT_MODE, dev); + if (rslt == BMI2_OK) { + /* Validate and auto-correct ODR parameter */ + rslt = check_boundary_val(&config->odr, BMI2_GYR_ODR_25HZ, + BMI2_GYR_ODR_3200HZ, dev); + if (rslt == BMI2_OK) { + /* Validate and auto-correct OIS + range */ + rslt = check_boundary_val(&config->ois_range, BMI2_GYR_OIS_250, + BMI2_GYR_OIS_2000, dev); + if (rslt == BMI2_OK) { + /* Validate and auto-correct + range parameter */ + rslt = check_boundary_val(&config->range, BMI2_GYR_RANGE_2000, + BMI2_GYR_RANGE_125, dev); + } + } + } + } + } + + return rslt; +} + +/*! + * @brief This internal API shows the error status when illegal sensor + * configuration is set. + */ +static int8_t cfg_error_status(const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + + /* Get error status of the set sensor configuration */ + rslt = bmi2_get_regs(BMI2_EVENT_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + reg_data = BMI2_GET_BITS(reg_data, BMI2_EVENT_FLAG); + switch (reg_data) { + case BMI2_NO_ERROR: + rslt = BMI2_OK; + break; + case BMI2_ACC_ERROR: + rslt = BMI2_E_ACC_INVALID_CFG; + break; + case BMI2_GYR_ERROR: + rslt = BMI2_E_GYRO_INVALID_CFG; + break; + case BMI2_ACC_GYR_ERROR: + rslt = BMI2_E_ACC_GYR_INVALID_CFG; + break; + default: + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API: + * 1) Enables/Disables auxiliary interface. + * 2) Sets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3)It maps/un-maps data interrupts to that of hardware interrupt line. + */ +static int8_t set_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate auxiliary configurations */ + rslt = validate_aux_config(config, dev); + if (rslt == BMI2_OK) { + /* Enable/Disable auxiliary interface */ + rslt = set_aux_interface(config, dev); + if (rslt == BMI2_OK) { + /* Set the auxiliary interface configurations */ + rslt = config_aux_interface(config, dev); + if (rslt == BMI2_OK) { + /* Set read out offset and ODR */ + rslt = config_aux(config, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables auxiliary interface. + */ +static int8_t set_aux_interface(const struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + reg_data = BMI2_SET_BITS(reg_data, BMI2_AUX_IF_EN, config->aux_en); + + /* Enable/Disable auxiliary interface */ + rslt = bmi2_set_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + + } + + return rslt; +} + +/*! + * @brief This internal API sets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + * + * @note Auxiliary sensor should not be busy when configuring aux_i2c_addr, + * man_rd_burst_len, aux_rd_burst_len and aux_rd_addr. + */ +static int8_t config_aux_interface(const struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data[2] = {0}; + /* Variable to store status */ + uint8_t status = 0; + /* Variable to define count */ + uint8_t count = 0; + + rslt = bmi2_get_regs(BMI2_AUX_DEV_ID_ADDR, reg_data, 2, dev); + if (rslt == BMI2_OK) { + /* Set I2C address for AUX sensor */ + reg_data[0] = BMI2_SET_BITS(reg_data[0], BMI2_AUX_SET_I2C_ADDR, config->i2c_device_addr); + /* Set the AUX IF to either manual or auto mode */ + reg_data[1] = BMI2_SET_BITS(reg_data[1], BMI2_AUX_MAN_MODE_EN, config->manual_en); + /* Enables FCU write command on AUX IF for auxiliary sensors + that need a trigger */ + reg_data[1] = BMI2_SET_BITS(reg_data[1], BMI2_AUX_FCU_WR_EN, config->fcu_write_en); + /* Set the burst read length for manual mode */ + reg_data[1] = BMI2_SET_BITS(reg_data[1], BMI2_AUX_MAN_READ_BURST, config->man_rd_burst); + /* Set the burst read length for data mode */ + reg_data[1] = BMI2_SET_BIT_POS0(reg_data[1], BMI2_AUX_READ_BURST, config->aux_rd_burst); + + for (;;) { + /* Check if auxiliary sensor is busy */ + rslt = bmi2_get_status(&status, dev); + if ((rslt == BMI2_OK) && (!(status & BMI2_AUX_BUSY))) { + /* Set the configurations if AUX is not busy */ + rslt = bmi2_set_regs(BMI2_AUX_DEV_ID_ADDR, reg_data, 2, dev); + dev->delay_ms(1); + + if (rslt == BMI2_OK) { + /* If data mode */ + if (!config->manual_en) { + /* Disable manual enable flag in + device structure */ + dev->aux_man_en = 0; + /* Set the read address of the + AUX sensor */ + rslt = bmi2_set_regs(BMI2_AUX_RD_ADDR, (uint8_t *)&config->read_addr, 1, dev); + dev->delay_ms(1); + } else { + /* Enable manual enable flag in + device structure */ + dev->aux_man_en = 1; + /* Update manual read burst + length in device structure */ + dev->aux_man_rd_burst_len = config->man_rd_burst; + } + } + + /* Break after setting the register */ + break; + } + + /* Increment count after every 10 seconds */ + dev->delay_ms(10); + count++; + + /* Break after 2 seconds if AUX still busy - since + slowest ODR is 0.78Hz*/ + if (count > 20) { + rslt = BMI2_E_AUX_BUSY; + break; + } + } + } + + return rslt; +} + +/*! + * @brief This internal API triggers read out offset and sets ODR of the + * auxiliary sensor. + */ +static int8_t config_aux(const struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_AUX_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Trigger read out offset */ + reg_data = BMI2_SET_BITS(reg_data, BMI2_AUX_OFFSET_READ_OUT, config->offset); + /* Set ODR */ + reg_data = BMI2_SET_BIT_POS0(reg_data, BMI2_AUX_ODR_EN, config->odr); + + /* Set auxiliary configuration register */ + rslt = bmi2_set_regs(BMI2_AUX_CONF_ADDR, ®_data, 1, dev); + dev->delay_ms(1); + } + + return rslt; +} + +/*! + * @brief This internal API checks the busy status of auxiliary sensor and sets + * the auxiliary register addresses when not busy. + */ +static int8_t set_if_aux_not_busy(uint8_t reg_addr, uint8_t reg_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to get status of AUX_BUSY */ + uint8_t status = 0; + /* Variable to define count for time-out */ + uint8_t count = 0; + + for (;;) { + /* Check if AUX is busy */ + rslt = bmi2_get_status(&status, dev); + /* Set the registers if not busy */ + if ((rslt == BMI2_OK) && (!(status & BMI2_AUX_BUSY))) { + rslt = bmi2_set_regs(reg_addr, ®_data, 1, dev); + dev->delay_ms(1); + + /* Break after setting the register */ + break; + } + + /* Increment count after every 10 seconds */ + dev->delay_ms(10); + count++; + + /* Break after 2 seconds if AUX still busy - since slowest ODR + is 0.78Hz*/ + if (count > 20) { + rslt = BMI2_E_AUX_BUSY; + break; + } + } + + return rslt; +} + +/*! + * @brief This internal API validates auxiliary configuration set by the user. + */ +static int8_t validate_aux_config(struct bmi2_aux_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validate ODR for auxiliary sensor */ + rslt = check_boundary_val(&config->odr, BMI2_AUX_ODR_0_78HZ, BMI2_AUX_ODR_800HZ, dev); + + return rslt; +} + + +/*! + * @brief This internal API sets any-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t set_any_motion_config(const struct bmi2_any_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define count */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for any motion */ + struct bmi2_feature_config any_mot_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for any-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&any_mot_config, BMI2_ANY_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where any-motion + feature resides */ + rslt = get_feat_config(any_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for any-motion + select */ + idx = any_mot_config.start_addr; + + /* Get offset in words since all the features are set in + words length */ + idx = idx / 2; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_DUR, config->duration); + + /* Set x-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_X_SEL, config->select_x); + + /* Set y-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Y_SEL, config->select_y); + + /* Set z-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Z_SEL, config->select_z); + + /* Increment offset by 1 word to set threshold and + output configuration */ + idx++; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_THRES, config->threshold); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - any_mot_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[any_mot_config.start_addr + i] + = *((uint8_t *)data_p + any_mot_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.any_mot_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets no-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t set_no_motion_config(const struct bmi2_no_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define count */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for no-motion */ + struct bmi2_feature_config no_mot_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for no-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&no_mot_config, BMI2_NO_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where no-motion + feature resides */ + rslt = get_feat_config(no_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for no-motion + select */ + idx = no_mot_config.start_addr; + + /* Get offset in words since all the features are set in + words length */ + idx = idx / 2; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_DUR, config->duration); + + /* Set x-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_X_SEL, config->select_x); + + /* Set y-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Y_SEL, config->select_y); + + /* Set z-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_Z_SEL, config->select_z); + + /* Increment offset by 1 word to set threshold and + output configuration */ + idx++; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ANY_NO_MOT_THRES, config->threshold); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ANY_NO_MOT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - no_mot_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[no_mot_config.start_addr + i] + = *((uint8_t *)data_p + no_mot_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.no_mot_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets sig-motion configurations like block-size, + * output-configuration and other parameters. + */ +static int8_t set_sig_motion_config(const struct bmi2_sig_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for sig-motion */ + struct bmi2_feature_config sig_mot_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for sig-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&sig_mot_config, BMI2_SIG_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where sig-motion feature + resides */ + rslt = get_feat_config(sig_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for sig-motion select */ + idx = sig_mot_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set parameter 1 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_1, config->block_size); + + /* Increment offset by 1 word to set parameter 2 */ + idx++; + + /* Set parameter 2 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_2, config->param_2); + + /* Increment offset by 1 word to set parameter 3 */ + idx++; + + /* Set parameter 3 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_3, config->param_3); + + /* Increment offset by 1 word to set parameter 4 */ + idx++; + + /* Set parameter 4 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_4, config->param_4); + + /* Increment offset by 1 word to set parameter 5 */ + idx++; + + /* Set parameter 5 */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), SIG_MOT_PARAM_5, config->param_5); + + /* Increment offset by 1 word to set output- + configuration */ + idx++; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), SIG_MOT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - sig_mot_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[sig_mot_config.start_addr + i] + = *((uint8_t *)data_p + sig_mot_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure for mapping */ + dev->int_map.sig_mot_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets step counter configurations like water-mark + * level, reset-counter and output-configuration step detector and + * activity. + */ +static int8_t set_step_config(const struct bmi2_step_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for step counter 4 */ + struct bmi2_feature_config step_count_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for step counter feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&step_count_config, BMI2_STEP_COUNTER, dev); + + if (feat_found) { + /* Get the configuration from the page where step counter + resides */ + rslt = get_feat_config(step_count_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes */ + idx = step_count_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set water-mark level */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), STEP_COUNT_WM_LEVEL, config->watermark_level); + + /* Set reset-counter */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), STEP_COUNT_RST_CNT, config->reset_counter); + + /* Increment offset by 1 word to set output- + configuration of step detector and step activity */ + idx++; + + /* Set output configuration of step-detector */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), STEP_DET_OUT_CONF, config->out_conf_step_detector); + + /* Set output configuration of step-activity */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), STEP_ACT_OUT_CONF, config->out_conf_activity); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - step_count_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[step_count_config.start_addr + i] + = *((uint8_t *)data_p + step_count_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure for step-detector */ + dev->int_map.step_det_out_conf = (uint8_t)config->out_conf_step_detector; + /* Copy out_conf value to a local copy in device + structure for step-activity */ + dev->int_map.step_act_out_conf = (uint8_t)config->out_conf_activity; + + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + */ +static int8_t set_gyro_user_gain_config(const struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for user-gain */ + struct bmi2_feature_config user_gain_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for user-gain feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&user_gain_config, BMI2_GYRO_GAIN_UPDATE, dev); + + if (feat_found) { + /* Get the configuration from the page where user-gain feature + resides */ + rslt = get_feat_config(user_gain_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for user-gain select */ + idx = user_gain_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set ratio_x */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), GYR_USER_GAIN_RATIO_X, config->ratio_x); + + /* Increment offset by 1 word to set ratio_y */ + idx++; + + /* Set ratio_y */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), GYR_USER_GAIN_RATIO_Y, config->ratio_y); + + /* Increment offset by 1 word to set ratio_z */ + idx++; + + /* Set ratio_z */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), GYR_USER_GAIN_RATIO_Z, config->ratio_z); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - user_gain_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[user_gain_config.start_addr + i] + = *((uint8_t *)data_p + user_gain_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets tilt configurations like output-configuration. + */ +static int8_t set_tilt_config(const struct bmi2_tilt_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for tilt */ + struct bmi2_feature_config tilt_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for tilt feature and extract its configuration details */ + feat_found = extract_input_feat_config(&tilt_config, BMI2_TILT, dev); + + if (feat_found) { + /* Get the configuration from the page where tilt feature + resides */ + rslt = get_feat_config(tilt_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for tilt select */ + idx = tilt_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), TILT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - tilt_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[tilt_config.start_addr + i] + = *((uint8_t *)data_p + tilt_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.tilt_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets pick-up configurations like output + * configuration. + */ +static int8_t set_pick_up_config(const struct bmi2_pick_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for pick-up */ + struct bmi2_feature_config pick_up_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for pick-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&pick_up_config, BMI2_PICK_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where pick-up feature + resides */ + rslt = get_feat_config(pick_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for pick-up select */ + idx = pick_up_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), PICK_UP_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - pick_up_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[pick_up_config.start_addr + i] + = *((uint8_t *)data_p + pick_up_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.pick_up_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets glance detector configurations like output + * configuration. + */ +static int8_t set_glance_detect_config(const struct bmi2_glance_det_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for glance detector */ + struct bmi2_feature_config glance_det_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for glance detector feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&glance_det_config, BMI2_GLANCE_DETECTOR, dev); + + if (feat_found) { + /* Get the configuration from the page where glance detector + feature resides */ + rslt = get_feat_config(glance_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for glance detector + select */ + idx = glance_det_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), GLANCE_DET_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - glance_det_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[glance_det_config.start_addr + i] = + *((uint8_t *)data_p + glance_det_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.glance_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + */ +static int8_t set_wake_up_config(const struct bmi2_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for wake-up */ + struct bmi2_feature_config wake_up_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wake_up_config, BMI2_WAKE_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where wake-up feature + resides */ + rslt = get_feat_config(wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for wake-up select */ + idx = wake_up_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set sensitivity */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WAKE_UP_SENSITIVITY, config->sensitivity); + + /* Set single/double tap enable */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WAKE_UP_SINGLE_TAP_EN, config->single_tap_en); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WAKE_UP_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - wake_up_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[wake_up_config.start_addr + i] + = *((uint8_t *)data_p + wake_up_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.wake_up_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + */ +static int8_t set_orient_config(const struct bmi2_orient_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for orient */ + struct bmi2_feature_config orient_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for orient feature and extract its configuration details */ + feat_found = extract_input_feat_config(&orient_config, BMI2_ORIENTATION, dev); + + if (feat_found) { + /* Get the configuration from the page where orient feature + resides */ + rslt = get_feat_config(orient_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for orient select */ + idx = orient_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set upside/down detection */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_UP_DOWN, config->ud_en); + + /* Set symmetrical modes */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_SYMM_MODE, config->mode); + + /* Set blocking mode */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_BLOCK_MODE, config->blocking); + + /* Set theta */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_THETA, config->theta); + + /* Increment offset by 1 more word to set hysteresis and + output configuration */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), ORIENT_HYST, config->hysteresis); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), ORIENT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - orient_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[orient_config.start_addr + i] + = *((uint8_t *)data_p + orient_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.orient_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets high-g configurations like threshold, + * hysteresis, duration, and out0put configuration. + */ +static int8_t set_high_g_config(const struct bmi2_high_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for high-g */ + struct bmi2_feature_config high_g_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for high-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&high_g_config, BMI2_HIGH_G, dev); + + if (feat_found) { + /* Get the configuration from the page where high-g feature + resides */ + rslt = get_feat_config(high_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for high-g select */ + idx = high_g_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), HIGH_G_THRES, config->threshold); + + /* Increment offset by 1 more word to set hysteresis */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), HIGH_G_HYST, config->hysteresis); + + /* Set x-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_X_SEL, config->select_x); + + /* Set y-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_Y_SEL, config->select_y); + + /* Set z-select */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_Z_SEL, config->select_z); + + /* Increment offset by 1 more word to set duration and + output configuration */ + idx++; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), HIGH_G_DUR, config->duration); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), HIGH_G_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - high_g_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[high_g_config.start_addr + i] + = *((uint8_t *)data_p + high_g_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.high_g_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + */ +static int8_t set_low_g_config(const struct bmi2_low_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for low-g */ + struct bmi2_feature_config low_g_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for low-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&low_g_config, BMI2_LOW_G, dev); + + if (feat_found) { + /* Get the configuration from the page where low-g feature + resides */ + rslt = get_feat_config(low_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for low-g select */ + idx = low_g_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set threshold */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LOW_G_THRES, config->threshold); + + /* Increment offset by 1 more word to set hysteresis */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LOW_G_HYST, config->hysteresis); + + /* Increment offset by 1 more word to set duration and + output configuration */ + idx++; + + /* Set duration */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), LOW_G_DUR, config->duration); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), LOW_G_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - low_g_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[low_g_config.start_addr + i] + = *((uint8_t *)data_p + low_g_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.low_g_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + */ +static int8_t set_flat_config(const struct bmi2_flat_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for flat */ + struct bmi2_feature_config flat_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for flat feature and extract its configuration details */ + feat_found = extract_input_feat_config(&flat_config, BMI2_FLAT, dev); + + if (feat_found) { + /* Get the configuration from the page where flat feature + resides */ + rslt = get_feat_config(flat_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for flat select */ + idx = flat_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set theta */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_THETA, config->theta); + + /* Set blocking */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_BLOCK, config->blocking); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to set hysteresis and + hold-time */ + idx++; + + /* Set hysteresis */ + *(data_p + idx) = BMI2_SET_BIT_POS0(*(data_p + idx), FLAT_HYST, config->hysteresis); + + /* Set hold-time */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), FLAT_HOLD_TIME, config->hold_time); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - flat_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[flat_config.start_addr + i] + = *((uint8_t *)data_p + flat_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.flat_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets external sensor sync configurations like output + * configuration. + */ +static int8_t set_ext_sens_sync_config(const struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for external sensor sync */ + struct bmi2_feature_config ext_sens_sync_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for external sensor sync feature and extract its + configuration details */ + feat_found = extract_input_feat_config(&ext_sens_sync_config, BMI2_EXT_SENS_SYNC, dev); + + if (feat_found) { + /* Get the configuration from the page where external sensor + sync feature resides */ + rslt = get_feat_config(ext_sens_sync_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for external sensor sync + select */ + idx = ext_sens_sync_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), EXT_SENS_SYNC_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - ext_sens_sync_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[ext_sens_sync_config.start_addr + i] + = *((uint8_t *)data_p + ext_sens_sync_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.ext_sync_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wrist gesture configurations like wearable-arm, + * and output-configuration. + */ +static int8_t set_wrist_gest_config(const struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for wrist gesture feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&wrist_gest_config, BMI2_WRIST_GESTURE, dev); + + if (feat_found) { + /* Get the configuration from the page where wrist gesture + feature resides */ + rslt = get_feat_config(wrist_gest_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for gesture select */ + idx = wrist_gest_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set wearable arm */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_GEST_WEAR_ARM, config->wear_arm); + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_GEST_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - wrist_gest_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[wrist_gest_config.start_addr + i] + = *((uint8_t *)data_p + wrist_gest_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.wrist_gest_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API sets wrist wear wake-up configurations like + * output-configuration. + */ +static int8_t set_wrist_wear_wake_up_config(const struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define index */ + uint8_t i = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for wrist wear wake-up */ + struct bmi2_feature_config wrist_wake_up_config = {0}; + + /* Copy the feature configuration address to a local pointer */ +// uint16_t *data_p = (uint16_t *)feat_config; + uint16_t *data_p = (uint16_t *)((void *)feat_config); + + /* Search for wrist wear wake-up feature and extract its + configuration details */ + feat_found = extract_input_feat_config(&wrist_wake_up_config, BMI2_WRIST_WEAR_WAKE_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where wrist wear wake-up + feature resides */ + rslt = get_feat_config(wrist_wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for wrist wear wake-up + select */ + idx = wrist_wake_up_config.start_addr; + + /* Get offset in words since all the features are set + in words length */ + idx = idx / 2; + + /* Set output configuration */ + *(data_p + idx) = BMI2_SET_BITS(*(data_p + idx), WRIST_WAKE_UP_OUT_CONF, config->out_conf); + + /* Increment offset by 1 more word to get the total + length in words */ + idx++; + + /* Get total length in bytes to copy from local pointer + to the array */ + idx = (uint8_t)(idx * 2) - wrist_wake_up_config.start_addr; + + /* Copy the bytes to be set back to the array */ + for (i = 0; i < idx; i++) { + feat_config[wrist_wake_up_config.start_addr + i] + = *((uint8_t *)data_p + wrist_wake_up_config.start_addr + i); + } + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + if (rslt == BMI2_OK) { + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.wrist_wear_wake_up_out_conf = (uint8_t)config->out_conf; + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! +* @brief This internal API gets accelerometer configurations like ODR, +* bandwidth, performance mode and g-range. +*/ +static int8_t get_accel_config(struct bmi2_accel_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store data */ + uint8_t data_array[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config != NULL)) { + /* Read the sensor configuration details */ + rslt = bmi2_get_regs(BMI2_ACC_CONF_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) { + /* Get accelerometer performance mode */ + config->filter_perf = BMI2_GET_BITS(data_array[0], BMI2_ACC_FILTER_PERF_MODE); + + /* Get accelerometer bandwidth */ + config->bwp = BMI2_GET_BITS(data_array[0], BMI2_ACC_BW_PARAM); + + /* Get accelerometer ODR */ + config->odr = BMI2_GET_BIT_POS0(data_array[0], BMI2_ACC_ODR); + + /* Get accelerometer range */ + config->range = BMI2_GET_BIT_POS0(data_array[1], BMI2_ACC_RANGE); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! +* @brief This internal API gets gyroscope configurations like ODR, bandwidth, + * low power/high performance mode, performance mode and range. +*/ +static int8_t get_gyro_config(struct bmi2_gyro_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store data */ + uint8_t data_array[2] = {0}; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config != NULL)) { + /* Read the sensor configuration details */ + rslt = bmi2_get_regs(BMI2_GYR_CONF_ADDR, data_array, 2, dev); + if (rslt == BMI2_OK) { + /* Get gyroscope performance mode */ + config->filter_perf = BMI2_GET_BITS(data_array[0], BMI2_GYR_FILTER_PERF_MODE); + + /* Get gyroscope noise performance mode */ + config->noise_perf = BMI2_GET_BITS(data_array[0], BMI2_GYR_NOISE_PERF_MODE); + + /* Get gyroscope bandwidth */ + config->bwp = BMI2_GET_BITS(data_array[0], BMI2_GYR_BW_PARAM); + + /* Get gyroscope ODR */ + config->odr = BMI2_GET_BIT_POS0(data_array[0], BMI2_GYR_ODR); + + /* Get gyroscope OIS range */ + config->ois_range = BMI2_GET_BITS(data_array[1], BMI2_GYR_OIS_RANGE); + + /* Get gyroscope range */ + config->range = BMI2_GET_BIT_POS0(data_array[1], BMI2_GYR_RANGE); + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API: + * 1) Gets the status of auxiliary interface enable. + * 2) Gets auxiliary interface configurations like I2C address, manual/auto + * mode enable, manual burst read length, AUX burst read length and AUX read + * address. + * 3) Gets ODR and offset. +*/ +static int8_t get_aux_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if ((rslt == BMI2_OK) && (config != NULL)) { + /* Get enable status of auxiliary interface */ + rslt = get_aux_interface(config, dev); + if (rslt == BMI2_OK) { + /* Get the auxiliary interface configurations */ + rslt = get_aux_interface_config(config, dev); + if (rslt == BMI2_OK) { + /* Get read out offset and ODR */ + rslt = get_aux_cfg(config, dev); + } + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the enable status of auxiliary interface. + */ +static int8_t get_aux_interface(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + + /* Get the enable status of auxiliary interface */ + rslt = bmi2_get_regs(BMI2_IF_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) + config->aux_en = BMI2_GET_BITS(reg_data, BMI2_AUX_IF_EN); + + return rslt; +} + +/*! + * @brief This internal API gets auxiliary configurations like manual/auto mode + * FCU write command enable and read burst length for both data and manual mode. + */ +static int8_t get_aux_interface_config(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data[2] = {0}; + + rslt = bmi2_get_regs(BMI2_AUX_DEV_ID_ADDR, reg_data, 2, dev); + if (rslt == BMI2_OK) { + /* Get I2C address for auxiliary sensor */ + config->i2c_device_addr = BMI2_GET_BITS(reg_data[0], BMI2_AUX_SET_I2C_ADDR); + /* Get the AUX IF to either manual or auto mode */ + config->manual_en = BMI2_GET_BITS(reg_data[1], BMI2_AUX_MAN_MODE_EN); + /* Enables FCU write command on AUX IF for auxiliary sensors + that need a trigger */ + config->fcu_write_en = BMI2_GET_BITS(reg_data[1], BMI2_AUX_FCU_WR_EN); + /* Get the burst read length for manual mode */ + config->man_rd_burst = BMI2_GET_BITS(reg_data[1], BMI2_AUX_MAN_READ_BURST); + /* Get the burst read length for data mode */ + config->aux_rd_burst = BMI2_GET_BIT_POS0(reg_data[1], BMI2_AUX_READ_BURST); + + /* If data mode, get the read address of the auxiliary sensor + from where data is to be read */ + if (!config->manual_en) + rslt = bmi2_get_regs(BMI2_AUX_RD_ADDR, &config->read_addr, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API gets read out offset and ODR of the auxiliary + * sensor. + */ +static int8_t get_aux_cfg(struct bmi2_aux_config *config, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t reg_data; + + rslt = bmi2_get_regs(BMI2_AUX_CONF_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Get read out offset */ + config->offset = BMI2_GET_BITS(reg_data, BMI2_AUX_OFFSET_READ_OUT); + /* Get ODR */ + config->odr = BMI2_GET_BIT_POS0(reg_data, BMI2_AUX_ODR_EN); + } + + return rslt; +} + +/*! + * @brief This internal API gets any-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t get_any_motion_config(struct bmi2_any_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for any-motion */ + struct bmi2_feature_config any_mot_config = {0}; + + /* Search for any-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&any_mot_config, BMI2_ANY_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where any-motion + feature resides */ + rslt = get_feat_config(any_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for feature enable for + any-motion */ + idx = any_mot_config.start_addr; + + /* Get word to calculate duration, x, y and z select */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & ANY_NO_MOT_DUR_MASK; + + /* Get x-select */ + config->select_x = (lsb_msb & ANY_NO_MOT_X_SEL_MASK) >> ANY_NO_MOT_X_SEL_POS; + + /* Get y-select */ + config->select_y = (lsb_msb & ANY_NO_MOT_Y_SEL_MASK) >> ANY_NO_MOT_Y_SEL_POS; + + /* Get z-select */ + config->select_z = (lsb_msb & ANY_NO_MOT_Z_SEL_MASK) >> ANY_NO_MOT_Z_SEL_POS; + + /* Get word to calculate threshold, output configuration + from the same word */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & ANY_NO_MOT_THRES_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & ANY_NO_MOT_OUT_CONF_MASK) >> ANY_NO_MOT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.any_mot_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets no-motion configurations like axes select, + * duration, threshold and output-configuration. + */ +static int8_t get_no_motion_config(struct bmi2_no_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for no-motion */ + struct bmi2_feature_config no_mot_config = {0}; + + /* Search for no-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&no_mot_config, BMI2_NO_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where no-motion + feature resides */ + rslt = get_feat_config(no_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for feature enable for no-motion */ + idx = no_mot_config.start_addr; + + /* Get word to calculate duration, x, y and z select */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & ANY_NO_MOT_DUR_MASK; + + /* Get x-select */ + config->select_x = (lsb_msb & ANY_NO_MOT_X_SEL_MASK) >> ANY_NO_MOT_X_SEL_POS; + + /* Get y-select */ + config->select_y = (lsb_msb & ANY_NO_MOT_Y_SEL_MASK) >> ANY_NO_MOT_Y_SEL_POS; + + /* Get z-select */ + config->select_z = (lsb_msb & ANY_NO_MOT_Z_SEL_MASK) >> ANY_NO_MOT_Z_SEL_POS; + + /* Get word to calculate threshold, output configuration + from the same word */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & ANY_NO_MOT_THRES_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & ANY_NO_MOT_OUT_CONF_MASK) >> ANY_NO_MOT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.no_mot_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets sig-motion configurations like block-size, + * output-configuration and other parameters. + */ +static int8_t get_sig_motion_config(struct bmi2_sig_motion_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration sig-motion */ + struct bmi2_feature_config sig_mot_config = {0}; + + /* Search for sig-motion feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&sig_mot_config, BMI2_SIG_MOTION, dev); + + if (feat_found) { + /* Get the configuration from the page where sig-motion feature + resides */ + rslt = get_feat_config(sig_mot_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for feature enable for + sig-motion */ + idx = sig_mot_config.start_addr; + + /* Get word to calculate parameter 1 */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 1 */ + config->block_size = lsb_msb & SIG_MOT_PARAM_1_MASK; + + /* Get word to calculate parameter 2 */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 2 */ + config->param_2 = lsb_msb & SIG_MOT_PARAM_2_MASK; + + /* Get word to calculate parameter 3 */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 3 */ + config->param_3 = lsb_msb & SIG_MOT_PARAM_3_MASK; + + /* Get word to calculate parameter 4 */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 4 */ + config->param_4 = lsb_msb & SIG_MOT_PARAM_4_MASK; + + /* Get word to calculate parameter 5 */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get parameter 5 */ + config->param_5 = lsb_msb & SIG_MOT_PARAM_5_MASK; + + /* Get word to calculate and output configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & SIG_MOT_OUT_CONF_MASK) >> SIG_MOT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.sig_mot_out_conf = (uint8_t)config->out_conf; + + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets step counter/detector/activity configurations. + */ +static int8_t get_step_config(struct bmi2_step_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for step counter */ + struct bmi2_feature_config step_count_config = {0}; + + /* Search for step counter 4 feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&step_count_config, BMI2_STEP_COUNTER, dev); + + if (feat_found) { + /* Get the configuration from the page where step counter 4 + parameter resides */ + rslt = get_feat_config(step_count_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for feature enable for step + counter/detector/activity */ + idx = step_count_config.start_addr; + + /* Get word to calculate water-mark level and reset + counter */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get water-mark level */ + config->watermark_level = lsb_msb & STEP_COUNT_WM_LEVEL_MASK; + + /* Get reset counter */ + config->reset_counter = (lsb_msb & STEP_COUNT_RST_CNT_MASK) >> STEP_COUNT_RST_CNT_POS; + + /* Get word to calculate output configuration of step + detector and activity */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration of step detector */ + config->out_conf_step_detector = lsb_msb & STEP_DET_OUT_CONF_MASK; + + /* Get output configuration of step activity */ + config->out_conf_activity = (lsb_msb & STEP_ACT_OUT_CONF_MASK) >> STEP_ACT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.step_det_out_conf = (uint8_t)config->out_conf_step_detector; + dev->int_map.step_act_out_conf = (uint8_t)config->out_conf_activity; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets gyroscope user-gain configurations like gain + * update value for x, y and z-axis. + */ +static int8_t get_gyro_gain_update_config(struct bmi2_gyro_user_gain_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for user-gain */ + struct bmi2_feature_config user_gain_config = {0}; + + /* Search for user-gain feature and extract its configuration details */ + feat_found = extract_input_feat_config(&user_gain_config, BMI2_GYRO_GAIN_UPDATE, dev); + + if (feat_found) { + /* Get the configuration from the page where user-gain feature + resides */ + rslt = get_feat_config(user_gain_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for user-gain select */ + idx = user_gain_config.start_addr; + + /* Get word to calculate ratio_x */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get ratio_x */ + config->ratio_x = lsb_msb & GYR_USER_GAIN_RATIO_X_MASK; + + /* Get word to calculate ratio_y */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get ratio_y */ + config->ratio_y = lsb_msb & GYR_USER_GAIN_RATIO_Y_MASK; + + /* Get word to calculate ratio_z */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get ratio_z */ + config->ratio_z = lsb_msb & GYR_USER_GAIN_RATIO_Z_MASK; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets tilt configurations like output-configuration. + */ +static int8_t get_tilt_config(struct bmi2_tilt_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for tilt */ + struct bmi2_feature_config tilt_config = {0}; + + /* Search for tilt feature and extract its configuration details */ + feat_found = extract_input_feat_config(&tilt_config, BMI2_TILT, dev); + + if (feat_found) { + /* Get the configuration from the page where tilt feature + resides */ + rslt = get_feat_config(tilt_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for tilt select */ + idx = tilt_config.start_addr; + + /* Get word to calculate threshold and output + configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & TILT_OUT_CONF_MASK) >> TILT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.tilt_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets pick-up configurations like output + * configuration. + */ +static int8_t get_pick_up_config(struct bmi2_pick_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for pick-up */ + struct bmi2_feature_config pick_up_config = {0}; + + /* Search for pick-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&pick_up_config, BMI2_PICK_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where pick-up feature + resides */ + rslt = get_feat_config(pick_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for pick-up select */ + idx = pick_up_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & PICK_UP_OUT_CONF_MASK) >> PICK_UP_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.pick_up_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets glance detector configurations like output + * configuration. + */ +static int8_t get_glance_detect_config(struct bmi2_glance_det_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for glance detector */ + struct bmi2_feature_config glance_det_config = {0}; + + /* Search for glance detector feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&glance_det_config, BMI2_GLANCE_DETECTOR, dev); + + if (feat_found) { + /* Get the configuration from the page where glance detector + feature resides */ + rslt = get_feat_config(glance_det_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for glance detector + select */ + idx = glance_det_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & GLANCE_DET_OUT_CONF_MASK) >> GLANCE_DET_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.glance_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wake-up configurations like sensitivity, + * single/double tap enable and output-configuration. + */ +static int8_t get_wake_up_config(struct bmi2_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wake-up */ + struct bmi2_feature_config wake_up_config = {0}; + + /* Search for wake-up feature and extract its configuration details */ + feat_found = extract_input_feat_config(&wake_up_config, BMI2_WAKE_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where wake-up feature + resides */ + rslt = get_feat_config(wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for wake-up select */ + idx = wake_up_config.start_addr; + + /* Get word to calculate sensitivity, single/double tap + enable and output configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get sensitivity */ + config->sensitivity = (lsb_msb & WAKE_UP_SENSITIVITY_MASK) >> WAKE_UP_SENSITIVITY_POS; + + /* Get single/double tap enable */ + config->single_tap_en = (lsb_msb & WAKE_UP_SINGLE_TAP_EN_MASK) >> WAKE_UP_SINGLE_TAP_EN_POS; + + /* Get output configuration */ + config->out_conf = (lsb_msb & WAKE_UP_OUT_CONF_MASK) >> WAKE_UP_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.wake_up_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wrist gesture configurations like wearable-arm, + * and output-configuration. + */ +static int8_t get_wrist_gest_config(struct bmi2_wrist_gest_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist gesture */ + struct bmi2_feature_config wrist_gest_config = {0}; + + /* Search for wrist gesture feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&wrist_gest_config, BMI2_WRIST_GESTURE, dev); + + if (feat_found) { + /* Get the configuration from the page where wrist gesture + feature resides */ + rslt = get_feat_config(wrist_gest_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for wrist gesture + select */ + idx = wrist_gest_config.start_addr; + + /* Get word to calculate wearable arm and output + configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get wearable arm */ + config->wear_arm = (lsb_msb & WRIST_GEST_WEAR_ARM_MASK) >> WRIST_GEST_WEAR_ARM_POS; + + /* Get output configuration */ + config->out_conf = (lsb_msb & WRIST_GEST_OUT_CONF_MASK) >> WRIST_GEST_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.wrist_gest_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets wrist wear wake-up configurations like + * output-configuration. + */ +static int8_t get_wrist_wear_wake_up_config(struct bmi2_wrist_wear_wake_up_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for wrist wear wake-up */ + struct bmi2_feature_config wrist_wake_up_config = {0}; + + /* Search for wrist wear wake-up feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&wrist_wake_up_config, BMI2_WRIST_WEAR_WAKE_UP, dev); + + if (feat_found) { + /* Get the configuration from the page where wrist wear wake-up + feature resides */ + rslt = get_feat_config(wrist_wake_up_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for wrist wear wake-up + select */ + idx = wrist_wake_up_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & WRIST_WAKE_UP_OUT_CONF_MASK) >> WRIST_WAKE_UP_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.wrist_wear_wake_up_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets orientation configurations like upside/down + * detection, symmetrical modes, blocking mode, theta, hysteresis and output + * configuration. + */ +static int8_t get_orient_config(struct bmi2_orient_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for orient */ + struct bmi2_feature_config orient_config = {0}; + + /* Search for orient feature and extract its configuration details */ + feat_found = extract_input_feat_config(&orient_config, BMI2_ORIENTATION, dev); + + if (feat_found) { + /* Get the configuration from the page where orient feature + resides */ + rslt = get_feat_config(orient_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for orient select */ + idx = orient_config.start_addr; + + /* Get word to calculate upside/down detection, + symmetrical modes, blocking mode and theta */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get upside/down detection */ + config->ud_en = (lsb_msb & ORIENT_UP_DOWN_MASK) >> ORIENT_UP_DOWN_POS; + + /* Get symmetrical modes */ + config->mode = (lsb_msb & ORIENT_SYMM_MODE_MASK) >> ORIENT_SYMM_MODE_POS; + + /* Get blocking mode */ + config->blocking = (lsb_msb & ORIENT_BLOCK_MODE_MASK) >> ORIENT_BLOCK_MODE_POS; + + /* Get theta */ + config->theta = (lsb_msb & ORIENT_THETA_MASK) >> ORIENT_THETA_POS; + + /* Get the next word to calculate hysteresis and output + configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & ORIENT_HYST_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & ORIENT_OUT_CONF_MASK) >> ORIENT_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.orient_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets high-g configurations like threshold, + * hysteresis, duration, and output configuration. + */ +static int8_t get_high_g_config(struct bmi2_high_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for high-g */ + struct bmi2_feature_config high_g_config = {0}; + + /* Search for high-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&high_g_config, BMI2_HIGH_G, dev); + + if (feat_found) { + /* Get the configuration from the page where high-g feature + resides */ + rslt = get_feat_config(high_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for high-g select */ + idx = high_g_config.start_addr; + + /* Get word to calculate threshold */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & HIGH_G_THRES_MASK; + + /* Get word to calculate hysteresis */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & HIGH_G_HYST_MASK; + + /* Get x_select */ + config->select_x = (lsb_msb & HIGH_G_X_SEL_MASK) >> HIGH_G_X_SEL_POS; + + /* Get y_select */ + config->select_y = (lsb_msb & HIGH_G_Y_SEL_MASK) >> HIGH_G_Y_SEL_POS; + + /* Get z_select */ + config->select_z = (lsb_msb & HIGH_G_Z_SEL_MASK) >> HIGH_G_Z_SEL_POS; + + /* Get word to calculate duration and output + configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & HIGH_G_DUR_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & HIGH_G_OUT_CONF_MASK) >> HIGH_G_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.high_g_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets low-g configurations like threshold, + * hysteresis, duration, and output configuration. + */ +static int8_t get_low_g_config(struct bmi2_low_g_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for low-g */ + struct bmi2_feature_config low_g_config = {0}; + + /* Search for low-g feature and extract its configuration details */ + feat_found = extract_input_feat_config(&low_g_config, BMI2_LOW_G, dev); + + if (feat_found) { + /* Get the configuration from the page where low-g feature + resides */ + rslt = get_feat_config(low_g_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for low-g select */ + idx = low_g_config.start_addr; + + /* Get word to calculate threshold */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get threshold */ + config->threshold = lsb_msb & LOW_G_THRES_MASK; + + /* Get word to calculate hysteresis */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & LOW_G_HYST_MASK; + + /* Get word to calculate duration and output + configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get duration */ + config->duration = lsb_msb & LOW_G_DUR_MASK; + + /* Get output configuration */ + config->out_conf = (lsb_msb & LOW_G_OUT_CONF_MASK) >> LOW_G_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.low_g_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets flat configurations like theta, blocking, + * hold-time, hysteresis, and output configuration. + */ +static int8_t get_flat_config(struct bmi2_flat_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for flat */ + struct bmi2_feature_config flat_config = {0}; + + /* Search for flat feature and extract its configuration details */ + feat_found = extract_input_feat_config(&flat_config, BMI2_FLAT, dev); + + if (feat_found) { + /* Get the configuration from the page where flat feature + resides */ + rslt = get_feat_config(flat_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for flat select */ + idx = flat_config.start_addr; + + /* Get word to calculate theta, blocking mode and output + configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get theta */ + config->theta = (lsb_msb & FLAT_THETA_MASK) >> FLAT_THETA_POS; + + /* Get blocking mode */ + config->blocking = (lsb_msb & FLAT_BLOCK_MASK) >> FLAT_BLOCK_POS; + + /* Get output configuration */ + config->out_conf = (lsb_msb & FLAT_OUT_CONF_MASK) >> FLAT_OUT_CONF_POS; + + /* Get word to calculate hysteresis and hold-time */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get hysteresis */ + config->hysteresis = lsb_msb & FLAT_HYST_MASK; + + /* Get hold-time */ + config->hold_time = (lsb_msb & FLAT_HOLD_TIME_MASK) >> FLAT_HOLD_TIME_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.flat_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets external sensor sync configurations like output + * configuration. + */ +static int8_t get_ext_sens_sync_config(struct bmi2_ext_sens_sync_config *config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Variable to define a word */ + uint16_t lsb_msb = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature configuration for external sensor sync */ + struct bmi2_feature_config ext_sens_sync_config = {0}; + + /* Search for external sensor sync feature and extract its configuration + details */ + feat_found = extract_input_feat_config(&ext_sens_sync_config, BMI2_EXT_SENS_SYNC, dev); + + if (feat_found) { + /* Get the configuration from the page where external sensor + sync feature resides */ + rslt = get_feat_config(ext_sens_sync_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for external sensor + sync select */ + idx = ext_sens_sync_config.start_addr; + + /* Get word to calculate output configuration */ + lsb = (uint16_t)feat_config[idx++]; + msb = ((uint16_t)feat_config[idx++] << 8); + lsb_msb = lsb | msb; + + /* Get output configuration */ + config->out_conf = (lsb_msb & EXT_SENS_SYNC_OUT_CONF_MASK) >> EXT_SENS_SYNC_OUT_CONF_POS; + + /* Copy out_conf value to a local copy in device + structure */ + dev->int_map.ext_sync_out_conf = (uint8_t)config->out_conf; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API maps/un-maps feature interrupts to that of interrupt + * pins. + */ +static int8_t map_feat_int(uint8_t *reg_data_array, enum bmi2_hw_int_pin int_pin, uint8_t int_mask) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Check for NULL error */ + if (reg_data_array != NULL) { + /* Check validity on interrupt pin selection */ + if (int_pin < BMI2_INT_PIN_MAX) { + switch (int_pin) { + case BMI2_INT_NONE: + /* Un-Map the corresponding feature interrupt to + interrupt pin 1 and 2 */ + reg_data_array[0] &= ~(int_mask); + reg_data_array[1] &= ~(int_mask); + break; + case BMI2_INT1: + /* Map the corresponding feature interrupt to + interrupt pin 1 */ + reg_data_array[0] |= int_mask; + /* Un-map the corresponding feature interrupt to + interrupt pin 2 */ + reg_data_array[1] &= ~(int_mask); + break; + case BMI2_INT2: + /* Map the corresponding feature interrupt to + interrupt pin 2 */ + reg_data_array[1] |= int_mask; + /* Un-map the corresponding feature interrupt to + interrupt pin 1 */ + reg_data_array[0] &= ~(int_mask); + break; + case BMI2_INT_BOTH: + /* Map the corresponding feature interrupt to + interrupt pin 1 and 2*/ + reg_data_array[0] |= int_mask; + reg_data_array[1] |= int_mask; + break; + default: + break; + } + } else { + /* Return error if invalid pin selection */ + rslt = BMI2_E_INVALID_INT_PIN; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the accelerometer data from the register. + */ +static int8_t get_accel_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define data stored in register */ + uint8_t reg_data[BMI2_ACC_GYR_NUM_BYTES] = {0}; + + + /* Read the sensor data */ + rslt = bmi2_get_regs(reg_addr, reg_data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) { + /* Get accelerometer data from the register */ + get_acc_gyr_data(data, reg_data); + + /* Get the re-mapped accelerometer data */ + get_remapped_data(data, dev); + } + + return rslt; +} + +/*! + * @brief This internal API gets the gyroscope data from the register. + */ +static int8_t get_gyro_sensor_data(struct bmi2_sens_axes_data *data, uint8_t reg_addr, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define data stored in register */ + uint8_t reg_data[BMI2_ACC_GYR_NUM_BYTES] = {0}; + + /* Read the sensor data */ + rslt = bmi2_get_regs(reg_addr, reg_data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) { + /* Get gyroscope data from the register */ + get_acc_gyr_data(data, reg_data); + + /* Get the re-mapped gyroscope data */ + get_remapped_data(data, dev); + + /* Get the compensated gyroscope data */ + comp_gyro_cross_axis_sensitivity(data, dev); + } + + return rslt; +} + +/*! + * @brief This internal API gets the accelerometer/gyroscope data. + */ +static void get_acc_gyr_data(struct bmi2_sens_axes_data *data, const uint8_t *reg_data) +{ + /* Variables to store msb value */ + uint8_t msb; + /* Variables to store lsb value */ + uint8_t lsb; + /* Variables to store both msb and lsb value */ + uint16_t msb_lsb; + /* Variables to define index */ + uint8_t index = 0; + + /* Read x-axis data */ + lsb = reg_data[index++]; + msb = reg_data[index++]; + msb_lsb = ((uint16_t)msb << 8) | (uint16_t)lsb; + data->x = (int16_t)msb_lsb; + + /* Read y-axis data */ + lsb = reg_data[index++]; + msb = reg_data[index++]; + msb_lsb = ((uint16_t)msb << 8) | (uint16_t)lsb; + data->y = (int16_t)msb_lsb; + + /* Read z-axis data */ + lsb = reg_data[index++]; + msb = reg_data[index++]; + msb_lsb = ((uint16_t)msb << 8) | (uint16_t)lsb; + data->z = (int16_t)msb_lsb; +} + +/*! + * @brief This internal API gets the re-mapped accelerometer/gyroscope data. + */ +static void get_remapped_data(struct bmi2_sens_axes_data *data, const struct bmi2_dev *dev) +{ + /* Array to defined the re-mapped sensor data */ + int16_t remap_data[3] = {0}; + + /* Fill the array with the un-mapped sensor data */ + remap_data[0] = data->x; + remap_data[1] = data->y; + remap_data[2] = data->z; + + /* Get the re-mapped x, y and z axes data */ + data->x = (int16_t)(remap_data[dev->remap.x_axis] * dev->remap.x_axis_sign); + data->y = (int16_t)(remap_data[dev->remap.y_axis] * dev->remap.y_axis_sign); + data->z = (int16_t)(remap_data[dev->remap.z_axis] * dev->remap.z_axis_sign); +} + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in manual mode. + */ +static int8_t read_aux_data(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, uint8_t burst_len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Array to store the register data */ + uint8_t reg_data[15] = {0}; + /* Variable to define number of bytes to read */ + uint16_t read_length = 0; + /* Variable to define loop */ + uint8_t loop = 0; + /* Variable to define counts to get the correct array index */ + uint8_t count = 0; + /* Variable to define index for the array */ + uint8_t idx = 0; + + while (len > 0) { + /* Set the read address if AUX is not busy */ + rslt = set_if_aux_not_busy(BMI2_AUX_RD_ADDR, reg_addr, dev); + if (rslt == BMI2_OK) { + /* Read data from bmi2 data register */ + rslt = bmi2_get_regs(BMI2_AUX_X_LSB_ADDR, reg_data, (uint16_t)burst_len, dev); + dev->delay_ms(1); + + if (rslt == BMI2_OK) { + /* Get number of bytes to be read */ + if (len < burst_len) + read_length = (uint8_t)len; + else + read_length = burst_len; + + /* Update array index and store the data */ + for (loop = 0; loop < read_length; loop++) { + idx = loop + count; + aux_data[idx] = reg_data[loop]; + } + } + } + + /* Update address for the next read */ + reg_addr += burst_len; + /* Update count for the array index */ + count += burst_len; + /* Update no of bytes left to read */ + len -= read_length; + }; + + return rslt; +} + +/*! + * @brief This internal API writes AUX write address and the user-defined bytes + * of data to the AUX sensor in manual mode. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + */ +static int8_t write_aux_data(uint8_t reg_addr, uint8_t reg_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Write data to be written to the AUX sensor in bmi2 register */ + rslt = bmi2_set_regs(BMI2_AUX_WR_DATA_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + /* Write the AUX address where data is to be stored when AUX + is not busy */ + rslt = set_if_aux_not_busy(BMI2_AUX_WR_ADDR, reg_addr, dev); + } + + return rslt; +} + +/*! + * @brief This internal API reads the user-defined bytes of data from the given + * register address of auxiliary sensor in data mode. + */ +static int8_t read_aux_data_mode(uint8_t *aux_data, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variables to define loop */ + uint8_t count = 0; + /* Variables to define index */ + uint8_t index = 0; + /* Array to define data stored in register */ + uint8_t reg_data[BMI2_AUX_NUM_BYTES] = {0}; + + /* Check if data mode */ + if (!dev->aux_man_en) { + /* Read the auxiliary sensor data */ + rslt = bmi2_get_regs(BMI2_AUX_X_LSB_ADDR, reg_data, BMI2_AUX_NUM_BYTES, dev); + if (rslt == BMI2_OK) { + /* Get the 8 bytes of auxiliary data */ + do { + *(aux_data + count++) = *(reg_data + index++); + } while (count < BMI2_AUX_NUM_BYTES); + } + } else { + rslt = BMI2_E_AUX_INVALID_CFG; + } + + return rslt; +} + +/*! + * @brief This internal API maps the actual burst read length with that of the + * register value set by user. + */ +static int8_t map_read_len(uint8_t *len, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Get the burst read length against the values set by the user */ + switch (dev->aux_man_rd_burst_len) { + case BMI2_AUX_READ_LEN_0: + *len = 1; + break; + case BMI2_AUX_READ_LEN_1: + *len = 2; + break; + case BMI2_AUX_READ_LEN_2: + *len = 6; + break; + case BMI2_AUX_READ_LEN_3: + *len = 8; + break; + default: + rslt = BMI2_E_AUX_INVALID_CFG; + break; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of step counter. + */ +static int8_t get_step_counter_output(uint32_t *step_count, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for step counter */ + struct bmi2_feature_config step_cnt_out_config = {0}; + + /* Search for step counter output feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&step_cnt_out_config, BMI2_STEP_COUNTER, dev); + + if (feat_found) { + /* Get the feature output configuration for step-counter */ + rslt = get_feat_config(step_cnt_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for step counter output */ + idx = step_cnt_out_config.start_addr; + + /* Get the step counter output in 4 bytes */ + *step_count = (uint32_t)feat_config[idx++]; + *step_count |= ((uint32_t)feat_config[idx++] << 8); + *step_count |= ((uint32_t)feat_config[idx++] << 16); + *step_count |= ((uint32_t)feat_config[idx++] << 24); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of step activity. + */ +static int8_t get_step_activity_output(uint8_t *step_act, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for step activity */ + struct bmi2_feature_config step_act_out_config = {0}; + + /* Search for step activity output feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&step_act_out_config, BMI2_STEP_ACTIVITY, dev); + + if (feat_found) { + /* Get the feature output configuration for step-activity */ + rslt = get_feat_config(step_act_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for step activity + output */ + idx = step_act_out_config.start_addr; + + /* Get the step activity output */ + *step_act = feat_config[idx]; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of orientation: portrait- + * landscape and face up-down. + */ +static int8_t get_orient_output(struct bmi2_orientation_output *orient_out, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for orientation */ + struct bmi2_feature_config orient_out_config = {0}; + + /* Search for orientation output feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&orient_out_config, BMI2_ORIENTATION, dev); + + if (feat_found) { + /* Get the feature output configuration for orientation */ + rslt = get_feat_config(orient_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for orientation output */ + idx = orient_out_config.start_addr; + + /* Get the output value of the orientation detection + feature */ + orient_out->portrait_landscape = BMI2_GET_BIT_POS0(feat_config[idx], BMI2_ORIENT_DETECT); + /* Get the output value of the orientation face up-down + feature */ + orient_out->faceup_down = BMI2_GET_BITS(feat_config[idx], BMI2_ORIENT_FACE_UP_DWN); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of high-g. + */ +static int8_t get_high_g_output(uint8_t *high_g_out, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for high-g */ + struct bmi2_feature_config high_g_out_config = {0}; + + /* Search for high-g output feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&high_g_out_config, BMI2_HIGH_G, dev); + + if (feat_found) { + /* Get the feature output configuration for high-g */ + rslt = get_feat_config(high_g_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for high-g output */ + idx = high_g_out_config.start_addr; + + /* Get the high-g output byte */ + *high_g_out = feat_config[idx]; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the saturation status for the gyroscope user + * gain update. + */ +static int8_t get_gyro_gain_update_status(struct bmi2_gyr_user_gain_status *user_gain_stat, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for gyroscope user gain status */ + struct bmi2_feature_config user_gain_cfg = {0}; + + /* Search for gyroscope user gain status output feature and extract its + configuration details */ + feat_found = extract_output_feat_config(&user_gain_cfg, BMI2_GYRO_GAIN_UPDATE, dev); + + if (feat_found) { + /* Get the feature output configuration for gyroscope user gain + status */ + rslt = get_feat_config(user_gain_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for gyroscope user gain + status */ + idx = user_gain_cfg.start_addr; + + /* Get the saturation status for x-axis */ + user_gain_stat->sat_x = BMI2_GET_BIT_POS0(feat_config[idx], GYR_USER_GAIN_SAT_STAT_X); + /* Get the saturation status for y-axis */ + user_gain_stat->sat_y = BMI2_GET_BITS(feat_config[idx], GYR_USER_GAIN_SAT_STAT_Y); + /* Get the saturation status for z-axis */ + user_gain_stat->sat_z = BMI2_GET_BITS(feat_config[idx], GYR_USER_GAIN_SAT_STAT_Z); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the error status related to NVM. + */ +static int8_t get_nvm_error_status(struct bmi2_nvm_err_status *nvm_err_stat, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for NVM error status */ + struct bmi2_feature_config nvm_err_cfg = {0}; + + /* Search for NVM error status feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&nvm_err_cfg, BMI2_NVM_STATUS, dev); + + if (feat_found) { + /* Get the feature output configuration for NVM error + status */ + rslt = get_feat_config(nvm_err_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for NVM error status */ + idx = nvm_err_cfg.start_addr; + + /* Increment index to get the error status */ + idx++; + + /* Error when NVM load action fails */ + nvm_err_stat->load_error = BMI2_GET_BIT_POS0(feat_config[idx], NVM_LOAD_ERR_STATUS); + /* Error when NVM program action fails */ + nvm_err_stat->prog_error = BMI2_GET_BITS(feat_config[idx], NVM_PROG_ERR_STATUS); + /* Error when NVM erase action fails */ + nvm_err_stat->erase_error = BMI2_GET_BITS(feat_config[idx], NVM_ERASE_ERR_STATUS); + /* Error when NVM program limit is exceeded */ + nvm_err_stat->exceed_error = BMI2_GET_BITS(feat_config[idx], NVM_END_EXCEED_STATUS); + /* Error when NVM privilege mode is not acquired */ + nvm_err_stat->privil_error = BMI2_GET_BITS(feat_config[idx], NVM_PRIV_ERR_STATUS); + + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the error status related to virtual frames. + */ +static int8_t get_vfrm_error_status(struct bmi2_vfrm_err_status *vfrm_err_stat, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for VFRM error status */ + struct bmi2_feature_config vfrm_err_cfg = {0}; + + /* Search for VFRM error status feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&vfrm_err_cfg, BMI2_VFRM_STATUS, dev); + + if (feat_found) { + /* Get the feature output configuration for VFRM error + status */ + rslt = get_feat_config(vfrm_err_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for VFRM error status */ + idx = vfrm_err_cfg.start_addr; + + /* Increment index to get the error status */ + idx++; + + /* Internal error while acquiring lock for FIFO */ + vfrm_err_stat->lock_error = BMI2_GET_BITS(feat_config[idx], VFRM_LOCK_ERR_STATUS); + /* Internal error while writing byte into FIFO */ + vfrm_err_stat->write_error = BMI2_GET_BITS(feat_config[idx], VFRM_WRITE_ERR_STATUS); + /* Internal error while writing into FIFO */ + vfrm_err_stat->fatal_error = BMI2_GET_BITS(feat_config[idx], VFRM_FATAL_ERR_STATUS); + + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the output values of the wrist gesture. + */ +static int8_t get_wrist_gest_status(uint8_t *wrist_gest, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variables to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + + /* Initialize feature output for wrist gesture */ + struct bmi2_feature_config wrist_gest_out_config = {0}; + + /* Search for wrist gesture feature and extract its configuration + details */ + feat_found = extract_output_feat_config(&wrist_gest_out_config, BMI2_WRIST_GESTURE, dev); + + if (feat_found) { + /* Get the feature output configuration for wrist gesture */ + rslt = get_feat_config(wrist_gest_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for wrist gesture + output */ + idx = wrist_gest_out_config.start_addr; + + /* Get the wrist gesture output */ + *wrist_gest = feat_config[idx]; + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API gets the cross sensitivity coefficient between + * gyroscope's X and Z axes. + */ +static int8_t get_gyro_cross_sense(int16_t *cross_sense, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define index */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature output for gyroscope cross sensitivity */ + struct bmi2_feature_config cross_sense_out_config = {0}; + + /* Search for gyroscope cross sensitivity feature and extract its + configuration details */ + feat_found = extract_output_feat_config(&cross_sense_out_config, BMI2_GYRO_CROSS_SENSE, dev); + + if (feat_found) { + /* Get the feature output configuration for gyroscope cross + sensitivity feature */ + rslt = get_feat_config(cross_sense_out_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes for gyroscope cross + sensitivity output */ + idx = cross_sense_out_config.start_addr; + + /* Get the gyroscope cross sensitivity coefficient */ + *cross_sense = (int16_t)((uint16_t)feat_config[idx] << 9); + *cross_sense = (int16_t)((*cross_sense) / 512); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + return rslt; +} + +/*! + * @brief This internal API is used to get enable status of gyroscope user gain + * update. + */ +static int8_t get_user_gain_upd_status(uint8_t *status, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Variable to check APS status */ + uint8_t aps_stat = 0; + /* Initialize feature configuration for gyroscope user gain */ + struct bmi2_feature_config gyr_user_gain_cfg = {0}; + + /* Search for user gain feature and extract its configuration details */ + feat_found = extract_input_feat_config(&gyr_user_gain_cfg, BMI2_GYRO_GAIN_UPDATE, dev); + + if (feat_found) { + /* Disable advance power save */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + + if (rslt == BMI2_OK) { + /* Get the configuration from the page where user gain + feature resides */ + rslt = get_feat_config(gyr_user_gain_cfg.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for enable/disable of user + gain */ + idx = gyr_user_gain_cfg.start_addr + GYR_USER_GAIN_FEAT_EN_OFFSET; + /* Set the feature enable status */ + *status = BMI2_GET_BITS(feat_config[idx], GYR_USER_GAIN_FEAT_EN); + } + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + not when already disabled */ + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + + return rslt; +} + +/*! + * @brief This internal API computes the number of bytes of accelerometer FIFO + * data which is to be parsed in header-less mode. + */ +static int8_t parse_fifo_accel_len(uint16_t *start_idx, uint16_t *len, const uint16_t *acc_count, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to define dummy byte in SPI interface */ + uint8_t dummy_byte_spi = 0; + + /* Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI */ + if (fifo->acc_byte_start_idx == 0) + dummy_byte_spi = dev->dummy_byte; + + /* Data start index */ + (*start_idx) = fifo->acc_byte_start_idx + dummy_byte_spi; + + /* If only accelerometer is enabled */ + if (fifo->data_enable == BMI2_FIFO_ACC_EN) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*acc_count) * BMI2_FIFO_ACC_LENGTH) + dummy_byte_spi); + /* If only accelerometer and auxiliary are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_AUX_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*acc_count) * BMI2_FIFO_ACC_AUX_LENGTH) + dummy_byte_spi); + /* If only accelerometer and gyroscope are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_GYR_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*acc_count) * BMI2_FIFO_ACC_GYR_LENGTH) + dummy_byte_spi); + /* If only accelerometer, gyroscope and auxiliary are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_GYR_EN | BMI2_FIFO_AUX_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*acc_count) * BMI2_FIFO_ALL_LENGTH) + dummy_byte_spi); + } else { + /* Move the data index to the last byte to mark completion when + no sensors or sensors apart from accelerometer are enabled */ + (*start_idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + + /* If more data is requested than available */ + if ((*len) > fifo->length) + (*len) = fifo->length; + + return rslt; +} + +/*! + * @brief This internal API is used to parse the accelerometer data from the + * FIFO in header mode. + */ +static int8_t extract_accel_header_mode(struct bmi2_sens_axes_data *acc, uint16_t *accel_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variable to define header frame */ + uint8_t frame_header = 0; + /* Variable to index the data bytes */ + uint16_t data_index; + /* Variable to index accelerometer frames */ + uint16_t accel_index = 0; + /* Variable to indicate accelerometer frames read */ + uint16_t frame_to_read = *accel_length; + + /* Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI */ + if (fifo->acc_byte_start_idx == 0) + fifo->acc_byte_start_idx = dev->dummy_byte; + + for (data_index = fifo->acc_byte_start_idx; data_index < fifo->length;) { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Parse virtual header if S4S is enabled */ + parse_if_virtual_header(&frame_header, &data_index, fifo); + + /* Index shifted to next byte where data starts */ + data_index++; + + switch (frame_header) { + /* If header defines accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEADER_ALL_FRM: + /* Unpack from normal frames */ + rslt = unpack_accel_frame(acc, &data_index, &accel_index, frame_header, fifo, dev); + break; + /* If header defines only gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->gyr_frm_len, fifo); + break; + /* If header defines only auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + rslt = move_next_frame(&data_index, fifo->aux_frm_len, fifo); + break; + /* If header defines only auxiliary and gyroscope frame */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->aux_gyr_frm_len, fifo); + break; + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = unpack_sensortime_frame(&data_index, fifo); + break; + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = unpack_skipped_frame(&data_index, fifo); + break; + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + /* Move the data index to the last byte to mark + completion */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_VIRT_ACT_DATA_LENGTH, fifo); + break; + default: + /* Move the data index to the last byte in case + of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Break if Number of frames to be read is complete or FIFO is + empty */ + if ((frame_to_read == accel_index) || (rslt == BMI2_W_FIFO_EMPTY)) + break; + } + + /* Update the accelerometer frame index */ + (*accel_length) = accel_index; + + /* Update the accelerometer byte index */ + fifo->acc_byte_start_idx = data_index; + + return rslt; +} + +/*! + * @brief This internal API is used to parse the accelerometer data from the + * FIFO data in both header and header-less mode. It updates the current data + * byte to be parsed. + */ +static int8_t unpack_accel_frame(struct bmi2_sens_axes_data *acc, uint16_t *idx, uint16_t *acc_idx, uint8_t frame, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) + +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + switch (frame) { + /* If frame contains only accelerometer data */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_ACC_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_frm_len) > fifo->length) { + /* Update the data index as complete*/ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], *idx, fifo, dev); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer and gyroscope data */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_gyr_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], ((*idx) + BMI2_FIFO_GYR_LENGTH), fifo, dev); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_GYR_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_aux_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], ((*idx) + BMI2_FIFO_AUX_LENGTH), fifo, dev); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer, gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_ALL_FRM: + case BMI2_FIFO_HEAD_LESS_ALL_FRM: + /* Partially read, then skip the data*/ + if ((*idx + fifo->all_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the accelerometer data */ + unpack_accel_data(&acc[(*acc_idx)], ((*idx) + BMI2_FIFO_GYR_AUX_LENGTH), fifo, dev); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ALL_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&acc[(*acc_idx)], idx, fifo); + + /* Update accelerometer frame index */ + (*acc_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->aux_gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains only auxiliary data */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->aux_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains only gyroscope data */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + default: + /* Move the data index to the last byte in case of + invalid values */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse accelerometer data from the + * FIFO data. + */ +static void unpack_accel_data(struct bmi2_sens_axes_data *acc, uint16_t data_start_index, const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variables to store LSB value */ + uint16_t data_lsb; + /* Variables to store MSB value */ + uint16_t data_msb; + /* Array to defined the re-mapped accelerometer data */ + int16_t remap_data[3] = {0}; + + /* Accelerometer raw x data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + acc->x = (int16_t)((data_msb << 8) | data_lsb); + + /* Accelerometer raw y data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + acc->y = (int16_t)((data_msb << 8) | data_lsb); + + /* Accelerometer raw z data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + acc->z = (int16_t)((data_msb << 8) | data_lsb); + + /* Fill the array with the un-mapped accelerometer data */ + remap_data[0] = acc->x; + remap_data[1] = acc->y; + remap_data[2] = acc->z; + + /* Get the re-mapped x, y and z accelerometer data */ + acc->x = (int16_t)(remap_data[dev->remap.x_axis] * dev->remap.x_axis_sign); + acc->y = (int16_t)(remap_data[dev->remap.y_axis] * dev->remap.y_axis_sign); + acc->z = (int16_t)(remap_data[dev->remap.z_axis] * dev->remap.z_axis_sign); +} + +/*! + * @brief This internal API computes the number of bytes of gyroscope FIFO data + * which is to be parsed in header-less mode. + */ +static int8_t parse_fifo_gyro_len(uint16_t *start_idx, uint16_t (*len), const uint16_t *gyr_count, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + /* Variable to define dummy byte in SPI interface */ + uint8_t dummy_byte_spi = 0; + + /* Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI */ + if (fifo->gyr_byte_start_idx == 0) + dummy_byte_spi = dev->dummy_byte; + + /* Data start index */ + (*start_idx) = fifo->gyr_byte_start_idx + dummy_byte_spi; + + /* If only gyroscope is enabled */ + if (fifo->data_enable == BMI2_FIFO_GYR_EN) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*gyr_count) * BMI2_FIFO_GYR_LENGTH) + dummy_byte_spi); + /* If only gyroscope and auxiliary are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_GYR_EN | BMI2_FIFO_AUX_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*gyr_count) * BMI2_FIFO_GYR_AUX_LENGTH) + dummy_byte_spi); + /* If only accelerometer and gyroscope are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_ACC_EN | BMI2_FIFO_GYR_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*gyr_count) * BMI2_FIFO_ACC_GYR_LENGTH) + dummy_byte_spi); + /* If only accelerometer, gyroscope and auxiliary are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_GYR_EN | BMI2_FIFO_AUX_EN | BMI2_FIFO_ACC_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*gyr_count) * BMI2_FIFO_ALL_LENGTH) + dummy_byte_spi); + } else { + /* Move the data index to the last byte to mark completion when + no sensors or sensors apart from gyroscope are enabled */ + (*start_idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + + /* If more data is requested than available */ + if (((*len)) > fifo->length) + (*len) = fifo->length; + + return rslt; +} + +/*! + * @brief This internal API is used to parse the gyroscope data from the + * FIFO data in header mode. + */ +static int8_t extract_gyro_header_mode(struct bmi2_sens_axes_data *gyr, uint16_t *gyro_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variable to define header frame */ + uint8_t frame_header = 0; + /* Variable to index the data bytes */ + uint16_t data_index; + /* Variable to index gyroscope frames */ + uint16_t gyro_index = 0; + /* Variable to indicate gyroscope frames read */ + uint16_t frame_to_read = (*gyro_length); + + /* Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI */ + if (fifo->gyr_byte_start_idx == 0) + fifo->gyr_byte_start_idx = dev->dummy_byte; + + for (data_index = fifo->gyr_byte_start_idx; data_index < fifo->length;) { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Parse virtual header if S4S is enabled */ + parse_if_virtual_header(&frame_header, &data_index, fifo); + + /* Index shifted to next byte where data starts */ + data_index++; + + switch (frame_header) { + /* If header defines gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEADER_ALL_FRM: + /* Unpack from normal frames */ + rslt = unpack_gyro_frame(gyr, &data_index, &gyro_index, frame_header, fifo, dev); + break; + /* If header defines only accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_frm_len, fifo); + break; + /* If header defines only auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + rslt = move_next_frame(&data_index, fifo->aux_frm_len, fifo); + break; + /* If header defines only auxiliary and accelerometer frame */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_aux_frm_len, fifo); + break; + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = unpack_sensortime_frame(&data_index, fifo); + break; + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = unpack_skipped_frame(&data_index, fifo); + break; + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + /* Move the data index to the last byte */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_VIRT_ACT_DATA_LENGTH, fifo); + break; + default: + /* Move the data index to the last byte in case + of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Break if number of frames to be read is complete or FIFO is + empty */ + if ((frame_to_read == gyro_index) || (rslt == BMI2_W_FIFO_EMPTY)) + break; + } + + /* Update the gyroscope frame index */ + (*gyro_length) = gyro_index; + + /* Update the gyroscope byte index */ + fifo->gyr_byte_start_idx = data_index; + + return rslt; +} + +/*! + * @brief This internal API is used to parse the gyroscope data from the FIFO + * data in both header and header-less mode. It updates the current data byte to + * be parsed. + */ +static int8_t unpack_gyro_frame(struct bmi2_sens_axes_data *gyr, uint16_t *idx, uint16_t *gyr_idx, uint8_t frame, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + switch (frame) { + /* If frame contains only gyroscope data */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->gyr_frm_len) > fifo->length) { + /* Update the data index as complete*/ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], *idx, fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_GYR_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer and gyroscope data */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_gyr_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], (*idx), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_GYR_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->aux_gyr_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], ((*idx) + BMI2_FIFO_AUX_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_GYR_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer, gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_ALL_FRM: + case BMI2_FIFO_HEAD_LESS_ALL_FRM: + /* Partially read, then skip the data*/ + if ((*idx + fifo->all_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the gyroscope data */ + unpack_gyro_data(&gyr[(*gyr_idx)], ((*idx) + BMI2_FIFO_AUX_LENGTH), fifo, dev); + + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ALL_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_sensor_time(&gyr[(*gyr_idx)], idx, fifo); + + /* Update gyroscope frame index */ + (*gyr_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->acc_aux_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains only auxiliary data */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->aux_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains only accelerometer data */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_ACC_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->acc_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + default: + /* Move the data index to the last byte in case of + invalid values */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse gyroscope data from the FIFO data. + */ +static void unpack_gyro_data(struct bmi2_sens_axes_data *gyr, uint16_t data_start_index, const struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variables to store LSB value */ + uint16_t data_lsb; + /* Variables to store MSB value */ + uint16_t data_msb; + /* Array to defined the re-mapped gyroscope data */ + int16_t remap_data[3] = {0}; + + /* Gyroscope raw x data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + gyr->x = (int16_t)((data_msb << 8) | data_lsb); + + /* Gyroscope raw y data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + gyr->y = (int16_t)((data_msb << 8) | data_lsb); + + /* Gyroscope raw z data */ + data_lsb = fifo->data[data_start_index++]; + data_msb = fifo->data[data_start_index++]; + gyr->z = (int16_t)((data_msb << 8) | data_lsb); + + /* Get the compensated gyroscope data */ + comp_gyro_cross_axis_sensitivity(gyr, dev); + + /* Fill the array with the un-mapped gyroscope data */ + remap_data[0] = gyr->x; + remap_data[1] = gyr->y; + remap_data[2] = gyr->z; + + /* Get the re-mapped x, y and z gyroscope data */ + gyr->x = (int16_t)(remap_data[dev->remap.x_axis] * dev->remap.x_axis_sign); + gyr->y = (int16_t)(remap_data[dev->remap.y_axis] * dev->remap.y_axis_sign); + gyr->z = (int16_t)(remap_data[dev->remap.z_axis] * dev->remap.z_axis_sign); +} + +/*! + * @brief This API computes the number of bytes of auxiliary FIFO data which is + * to be parsed in header-less mode. + */ +static int8_t parse_fifo_aux_len(uint16_t *start_idx, uint16_t (*len), const uint16_t *aux_count, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variable to define dummy byte in SPI interface */ + uint8_t dummy_byte_spi = 0; + + /*Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI*/ + if (fifo->aux_byte_start_idx == 0) + dummy_byte_spi = dev->dummy_byte; + + /* Data start index */ + *start_idx = fifo->aux_byte_start_idx + dummy_byte_spi; + + /* If only auxiliary is enabled */ + if (fifo->data_enable == BMI2_FIFO_AUX_EN) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*aux_count) * BMI2_FIFO_AUX_LENGTH) + dummy_byte_spi); + /* If only accelerometer and auxiliary are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_AUX_EN | BMI2_FIFO_ACC_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*aux_count) * BMI2_FIFO_ACC_AUX_LENGTH) + dummy_byte_spi); + /* If only accelerometer and gyroscope are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_AUX_EN | BMI2_FIFO_GYR_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*aux_count) * BMI2_FIFO_GYR_AUX_LENGTH) + dummy_byte_spi); + /* If only accelerometer, gyroscope and auxiliary are enabled */ + } else if (fifo->data_enable == (BMI2_FIFO_AUX_EN | BMI2_FIFO_GYR_EN | BMI2_FIFO_ACC_EN)) { + /* Number of bytes to be read */ + (*len) = (uint16_t)(((*aux_count) * BMI2_FIFO_ALL_LENGTH) + dummy_byte_spi); + } else { + /* Move the data index to the last byte to mark completion when + no sensors or sensors apart from gyroscope are enabled */ + (*start_idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } + + /* If more data is requested than available */ + if (((*len)) > fifo->length) + (*len) = fifo->length; + + return rslt; +} + +/*! + * @brief This API is used to parse the auxiliary data from the FIFO data in + * header mode. + */ +static int8_t extract_aux_header_mode(struct bmi2_aux_fifo_data *aux, uint16_t *aux_len, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variable to define header frame */ + uint8_t frame_header = 0; + /* Variable to index the data bytes */ + uint16_t data_index; + /* Variable to index gyroscope frames */ + uint16_t aux_index = 0; + /* Variable to indicate auxiliary frames read */ + uint16_t frame_to_read = *aux_len; + + /*Check if this is the first iteration of data unpacking + if yes, then consider dummy byte on SPI*/ + if (fifo->aux_byte_start_idx == 0) + fifo->aux_byte_start_idx = dev->dummy_byte; + + for (data_index = fifo->aux_byte_start_idx; data_index < fifo->length;) { + /* Get frame header byte */ + frame_header = fifo->data[data_index] & BMI2_FIFO_TAG_INTR_MASK; + + /* Parse virtual header if S4S is enabled */ + parse_if_virtual_header(&frame_header, &data_index, fifo); + + /* Index shifted to next byte where data starts */ + data_index++; + + switch (frame_header) { + /* If header defines auxiliary frame */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEADER_ALL_FRM: + /* Unpack from normal frames */ + rslt = unpack_aux_frame(aux, &data_index, &aux_index, frame_header, fifo, dev); + break; + /* If header defines only accelerometer frame */ + case BMI2_FIFO_HEADER_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_frm_len, fifo); + break; + /* If header defines only gyroscope frame */ + case BMI2_FIFO_HEADER_GYR_FRM: + rslt = move_next_frame(&data_index, fifo->gyr_frm_len, fifo); + break; + /* If header defines only gyroscope and accelerometer frame */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + rslt = move_next_frame(&data_index, fifo->acc_gyr_frm_len, fifo); + break; + /* If header defines sensor time frame */ + case BMI2_FIFO_HEADER_SENS_TIME_FRM: + rslt = unpack_sensortime_frame(&data_index, fifo); + break; + /* If header defines skip frame */ + case BMI2_FIFO_HEADER_SKIP_FRM: + rslt = unpack_skipped_frame(&data_index, fifo); + break; + /* If header defines Input configuration frame */ + case BMI2_FIFO_HEADER_INPUT_CFG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_INPUT_CFG_LENGTH, fifo); + break; + /* If header defines invalid frame or end of valid data */ + case BMI2_FIFO_HEAD_OVER_READ_MSB: + /* Move the data index to the last byte */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + case BMI2_FIFO_VIRT_ACT_RECOG_FRM: + rslt = move_next_frame(&data_index, BMI2_FIFO_VIRT_ACT_DATA_LENGTH, fifo); + break; + default: + /* Move the data index to the last byte in case + of invalid values */ + data_index = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Break if number of frames to be read is complete or FIFO is + empty */ + if ((frame_to_read == aux_index) || (rslt == BMI2_W_FIFO_EMPTY)) + break; + } + + /* Update the gyroscope frame index */ + (*aux_len) = aux_index; + + /* Update the gyroscope byte index */ + fifo->aux_byte_start_idx = data_index; + + return rslt; +} + +/*! + * @brief This API is used to parse the auxiliary frame from the FIFO data in + * both header mode and header-less mode and update the data_index value which + * is used to store the index of the current data byte which is parsed. + */ +static int8_t unpack_aux_frame(struct bmi2_aux_fifo_data *aux, uint16_t *idx, uint16_t *aux_idx, uint8_t frame, + const struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + switch (frame) { + /* If frame contains only auxiliary data */ + case BMI2_FIFO_HEADER_AUX_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->aux_frm_len) > fifo->length) { + /* Update the data index as complete*/ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->acc_aux_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ACC_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_AUX_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM: + /* Partially read, then skip the data */ + if (((*idx) + fifo->aux_gyr_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_GYR_AUX_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer, gyroscope and auxiliary data */ + case BMI2_FIFO_HEADER_ALL_FRM: + case BMI2_FIFO_HEAD_LESS_ALL_FRM: + /* Partially read, then skip the data*/ + if ((*idx + fifo->all_frm_len) > fifo->length) { + /* Move the data index to the last byte */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + /* Get the auxiliary data */ + unpack_aux_data(&aux[(*aux_idx)], (*idx), fifo); + /* Update data index */ + (*idx) = (*idx) + BMI2_FIFO_ALL_LENGTH; + + /* Get virtual sensor time if S4S is enabled */ + if (dev->sens_en_stat & BMI2_EXT_SENS_SEL) + unpack_virt_aux_sensor_time(&aux[(*aux_idx)], idx, fifo); + + /* Update auxiliary frame index */ + (*aux_idx)++; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains only accelerometer data */ + case BMI2_FIFO_HEADER_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_ACC_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->acc_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains only gyroscope data */ + case BMI2_FIFO_HEADER_GYR_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + /* If frame contains accelerometer and gyroscope data */ + case BMI2_FIFO_HEADER_GYR_ACC_FRM: + case BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM: + /* Update data index */ + (*idx) = (*idx) + fifo->acc_gyr_frm_len; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + break; + default: + /* Move the data index to the last byte in case of + invalid values */ + (*idx) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + break; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse auxiliary data from the FIFO data. + */ +static void unpack_aux_data(struct bmi2_aux_fifo_data *aux, uint16_t data_start_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to store index */ + uint16_t idx = 0; + + /* Get auxiliary data */ + for (; idx < 8; idx++) + aux->data[idx] = fifo->data[data_start_index++]; +} + +/*! + * @brief This internal API parses virtual frame header from the FIFO data. + */ +static void parse_if_virtual_header(uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variable to extract virtual header byte */ + uint8_t virtual_header_mode; + + /* Extract virtual header mode from the frame header */ + virtual_header_mode = BMI2_GET_BITS(*frame_header, BMI2_FIFO_VIRT_FRM_MODE); + + /* If the extracted header byte is a virtual header */ + if (virtual_header_mode == BMI2_FIFO_VIRT_FRM_MODE) { + /* If frame header is not activity recognition header */ + if (*frame_header != 0xC8) { + /* Index shifted to next byte where sensor frame is + present */ + (*data_index) = (*data_index) + 1; + + /* Get the sensor frame header */ + *frame_header = fifo->data[*data_index] & BMI2_FIFO_TAG_INTR_MASK; + } + } +} + +/*! + * @brief This internal API gets sensor time from the accelerometer and + * gyroscope virtual frames and updates in the data structure. + */ +static void unpack_virt_sensor_time(struct bmi2_sens_axes_data *sens, uint16_t *idx, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define 3 bytes of sensor time */ + uint32_t sensor_time_byte3; + uint16_t sensor_time_byte2; + uint8_t sensor_time_byte1; + + /* Get sensor time from the FIFO data */ + sensor_time_byte3 = (uint32_t)(fifo->data[(*idx) + BMI2_SENSOR_TIME_MSB_BYTE] << 16); + sensor_time_byte2 = (uint16_t)fifo->data[(*idx) + BMI2_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = fifo->data[(*idx)]; + + /* Store sensor time in the sensor data structure */ + sens->virt_sens_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + + /* Move the data index by 3 bytes */ + (*idx) = (*idx) + BMI2_SENSOR_TIME_LENGTH; +} + +/*! + * @brief This internal API gets sensor time from the auxiliary virtual + * frames and updates in the data structure. + */ +static void unpack_virt_aux_sensor_time(struct bmi2_aux_fifo_data *aux, uint16_t *idx, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define 3 bytes of sensor time */ + uint32_t sensor_time_byte3; + uint16_t sensor_time_byte2; + uint8_t sensor_time_byte1; + + /* Get sensor time from the FIFO data */ + sensor_time_byte3 = (uint32_t)(fifo->data[(*idx) + BMI2_SENSOR_TIME_MSB_BYTE] << 16); + sensor_time_byte2 = (uint16_t)fifo->data[(*idx) + BMI2_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = fifo->data[(*idx)]; + + /* Store sensor time in the sensor data structure */ + aux->virt_sens_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + + /* Move the data index by 3 bytes */ + (*idx) = (*idx) + BMI2_SENSOR_TIME_LENGTH; +} + +/*! + * @brief This internal API is used to reset the FIFO related configurations in + * the FIFO frame structure for the next FIFO read. + */ +static void reset_fifo_frame_structure(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev) +{ + /* Reset FIFO data structure */ + fifo->acc_byte_start_idx = 0; + fifo->aux_byte_start_idx = 0; + fifo->gyr_byte_start_idx = 0; + fifo->sensor_time = 0; + fifo->skipped_frame_count = 0; + fifo->act_recog_byte_start_idx = 0; + + /* If S4S is enabled */ + if ((dev->sens_en_stat & BMI2_EXT_SENS_SEL) == BMI2_EXT_SENS_SEL) { + fifo->acc_frm_len = BMI2_FIFO_VIRT_ACC_LENGTH; + fifo->gyr_frm_len = BMI2_FIFO_VIRT_GYR_LENGTH; + fifo->aux_frm_len = BMI2_FIFO_VIRT_AUX_LENGTH; + fifo->acc_gyr_frm_len = BMI2_FIFO_VIRT_ACC_GYR_LENGTH; + fifo->acc_aux_frm_len = BMI2_FIFO_VIRT_ACC_AUX_LENGTH; + fifo->aux_gyr_frm_len = BMI2_FIFO_VIRT_GYR_AUX_LENGTH; + fifo->all_frm_len = BMI2_FIFO_VIRT_ALL_LENGTH; + /* If S4S is not enabled */ + } else { + fifo->acc_frm_len = BMI2_FIFO_ACC_LENGTH; + fifo->gyr_frm_len = BMI2_FIFO_GYR_LENGTH; + fifo->aux_frm_len = BMI2_FIFO_AUX_LENGTH; + fifo->acc_gyr_frm_len = BMI2_FIFO_ACC_GYR_LENGTH; + fifo->acc_aux_frm_len = BMI2_FIFO_ACC_AUX_LENGTH; + fifo->aux_gyr_frm_len = BMI2_FIFO_GYR_AUX_LENGTH; + fifo->all_frm_len = BMI2_FIFO_ALL_LENGTH; + } +} + +/*! + * @brief This API internal checks whether the FIFO data read is an empty frame. + * If empty frame, index is moved to the last byte. + */ +static int8_t check_empty_fifo(uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Validate data index */ + if (((*data_index) + 2) < fifo->length) { + /* Check if FIFO is empty */ + if ((fifo->data[(*data_index)] == BMI2_FIFO_MSB_CONFIG_CHECK) + && (fifo->data[(*data_index) + 1] == BMI2_FIFO_LSB_CONFIG_CHECK)) { + /* Move the data index to the last byte to mark + completion */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } else { + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + } + + return rslt; +} + +/*! + * @brief This internal API is used to move the data index ahead of the + * current_frame_length parameter when unnecessary FIFO data appears while + * extracting the user specified data. + */ +static int8_t move_next_frame(uint16_t *data_index, uint8_t current_frame_length, const struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Validate data index */ + if (((*data_index) + current_frame_length) > fifo->length) { + /* Move the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + + } else { + /* Move the data index to next frame */ + (*data_index) = (*data_index) + current_frame_length; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse and store the sensor time from the + * FIFO data. + */ +static int8_t unpack_sensortime_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + /* Variables to define 3 bytes of sensor time */ + uint32_t sensor_time_byte3 = 0; + uint16_t sensor_time_byte2 = 0; + uint8_t sensor_time_byte1 = 0; + + /* Validate data index */ + if (((*data_index) + BMI2_SENSOR_TIME_LENGTH) > fifo->length) { + /* Move the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } else { + /* Get sensor time from the FIFO data */ + sensor_time_byte3 = fifo->data[(*data_index) + BMI2_SENSOR_TIME_MSB_BYTE] << 16; + sensor_time_byte2 = fifo->data[(*data_index) + BMI2_SENSOR_TIME_XLSB_BYTE] << 8; + sensor_time_byte1 = fifo->data[(*data_index)]; + + /* Update sensor time in the FIFO structure */ + fifo->sensor_time = (uint32_t)(sensor_time_byte3 | sensor_time_byte2 | sensor_time_byte1); + + /* Move the data index by 3 bytes */ + (*data_index) = (*data_index) + BMI2_SENSOR_TIME_LENGTH; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse and store the skipped frame count + * from the FIFO data. + */ +static int8_t unpack_skipped_frame(uint16_t *data_index, struct bmi2_fifo_frame *fifo) +{ + /* Variables to define error */ + int8_t rslt = BMI2_OK; + + /* Validate data index */ + if ((*data_index) >= fifo->length) { + /* Update the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } else { + /* Update skipped frame count in the FIFO structure */ + fifo->skipped_frame_count = fifo->data[(*data_index)]; + + /* Move the data index by 1 byte */ + (*data_index) = (*data_index) + 1; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API is used to parse and store the activity recognition + * output from the FIFO data. + */ +static int8_t unpack_act_recog_output(struct bmi2_act_recog_output *act_recog, uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variables to define 4 bytes of sensor time */ + uint32_t time_stamp_byte4 = 0; + uint32_t time_stamp_byte3 = 0; + uint32_t time_stamp_byte2 = 0; + uint32_t time_stamp_byte1 = 0; + + /* Validate data index */ + if ((*data_index + BMI2_FIFO_VIRT_ACT_DATA_LENGTH) >= fifo->length) { + /* Update the data index to the last byte */ + (*data_index) = fifo->length; + + /* FIFO is empty */ + rslt = BMI2_W_FIFO_EMPTY; + } else { + /* Get time-stamp from the activity recognition frame */ + time_stamp_byte4 = ((uint32_t)(fifo->data[(*data_index) + 3]) << 24); + time_stamp_byte3 = ((uint32_t)(fifo->data[(*data_index) + 2]) << 16); + time_stamp_byte2 = fifo->data[(*data_index) + 1] << 8; + time_stamp_byte1 = fifo->data[(*data_index)]; + + /* Update time-stamp from the virtual frame */ + act_recog->time_stamp = (time_stamp_byte4 | time_stamp_byte3 | time_stamp_byte2 | time_stamp_byte1); + + /* Move the data index by 4 bytes */ + (*data_index) = (*data_index) + BMI2_FIFO_VIRT_ACT_TIME_LENGTH; + + /* Update type of activity from the virtual frame */ + act_recog->type = fifo->data[(*data_index)]; + + /* Move the data index by 1 byte */ + (*data_index) = (*data_index) + BMI2_FIFO_VIRT_ACT_TYPE_LENGTH; + + /* Update status of activity from the virtual frame */ + act_recog->stat = fifo->data[(*data_index)]; + + /* Move the data index by 1 byte */ + (*data_index) = (*data_index) + BMI2_FIFO_VIRT_ACT_STAT_LENGTH; + + /* More frames could be read */ + rslt = BMI2_W_PARTIAL_READ; + } + + return rslt; +} + +/*! + * @brief This internal API enables and configures the accelerometer which is + * needed for self test operation. It also sets the amplitude for the self-test. + */ +static int8_t pre_self_test_config(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Structure to define sensor configurations */ + struct bmi2_sens_config sens_cfg = {0}; + /* List the sensors to be selected */ + uint8_t sens_sel = BMI2_ACCEL; + + /* Enable accelerometer */ + rslt = bmi2_sensor_enable(&sens_sel, 1, dev); + dev->delay_ms(1); + + /* Set self test amplitude low */ + if (rslt == BMI2_OK) + rslt = set_accel_self_test_amp(BMI2_DISABLE, dev); + + if (rslt == BMI2_OK) { + /* Select accelerometer for sensor configurations */ + sens_cfg.type = BMI2_ACCEL; + + /* Get the default values */ + rslt = bmi2_get_sensor_config(&sens_cfg, 1, dev); + if (rslt == BMI2_OK) { + /* Set the configurations required for self-test */ + sens_cfg.cfg.acc.odr = BMI2_ACC_ODR_1600HZ; + sens_cfg.cfg.acc.bwp = BMI2_ACC_NORMAL_AVG4; + sens_cfg.cfg.acc.filter_perf = BMI2_PERF_OPT_MODE; + sens_cfg.cfg.acc.range = BMI2_ACC_RANGE_16G; + + /* Set accelerometer configurations */ + rslt = bmi2_set_sensor_config(&sens_cfg, 1, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API performs the steps needed for self test operation + * before reading the accelerometer self test data. + */ +static int8_t self_test_config(uint8_t sign, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Enable the accelerometer self test feature */ + rslt = set_accel_self_test_enable(BMI2_ENABLE, dev); + if (rslt == BMI2_OK) { + /* Selects the sign of accelerometer self-test excitation */ + rslt = set_acc_self_test_sign(sign, dev); + } + + return rslt; +} + +/*! + * @brief This internal API enables or disables the accelerometer self test + * feature in the sensor. + */ +static int8_t set_accel_self_test_enable(uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define data */ + uint8_t data = 0; + + /* Enable/Disable self-test feature */ + rslt = bmi2_get_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BIT_POS0(data, BMI2_ACC_SELF_TEST_EN, enable); + rslt = bmi2_set_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API selects the sign for accelerometer self-test + * excitation. + */ +static int8_t set_acc_self_test_sign(uint8_t sign, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define data */ + uint8_t data = 0; + + /* Select the sign for self-test excitation */ + rslt = bmi2_get_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_ACC_SELF_TEST_SIGN, sign); + rslt = bmi2_set_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API sets the amplitude of the accelerometer self test + * deflection in the sensor. + */ +static int8_t set_accel_self_test_amp(uint8_t amp, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define data */ + uint8_t data = 0; + + /* Select amplitude of the self test deflection */ + rslt = bmi2_get_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_ACC_SELF_TEST_AMP, amp); + rslt = bmi2_set_regs(BMI2_ACC_SELF_TEST_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API reads the accelerometer data for x,y and z axis from + * the sensor. The data units is in LSB format. + */ +static int8_t read_accel_xyz(struct bmi2_sens_axes_data *accel, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Array to define data buffer */ + uint8_t data[BMI2_ACC_GYR_NUM_BYTES] = {0}; + + rslt = bmi2_get_regs(BMI2_ACC_X_LSB_ADDR, data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) { + /* Accelerometer data x axis */ + msb = data[1]; + lsb = data[0]; + accel->x = (int16_t)((msb << 8) | lsb); + + /* Accelerometer data y axis */ + msb = data[3]; + lsb = data[2]; + accel->y = (int16_t)((msb << 8) | lsb); + + /* Accelerometer data z axis */ + msb = data[5]; + lsb = data[4]; + accel->z = (int16_t)((msb << 8) | lsb); + } + + return rslt; +} + +/*! + * @brief This internal API reads the gyroscope data for x, y and z axis from + * the sensor. The data units is in LSB format. + */ +static int8_t read_gyro_xyz(struct bmi2_sens_axes_data *gyro, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define LSB */ + uint16_t lsb = 0; + /* Variable to define MSB */ + uint16_t msb = 0; + /* Array to define data buffer */ + uint8_t data[BMI2_ACC_GYR_NUM_BYTES] = {0}; + + rslt = bmi2_get_regs(BMI2_GYR_X_LSB_ADDR, data, BMI2_ACC_GYR_NUM_BYTES, dev); + if (rslt == BMI2_OK) { + /* Gyroscope data x axis */ + msb = data[1]; + lsb = data[0]; + gyro->x = (int16_t)((msb << 8) | lsb); + + /* Gyroscope data y axis */ + msb = data[3]; + lsb = data[2]; + gyro->y = (int16_t)((msb << 8) | lsb); + + /* Gyroscope data z axis */ + msb = data[5]; + lsb = data[4]; + gyro->z = (int16_t)((msb << 8) | lsb); + + } + + return rslt; +} + +/*! + * @brief This internal API skips S4S frame in the FIFO data while getting + * step activity output. + */ +static int8_t move_if_s4s_frame(const uint8_t *frame_header, uint16_t *data_index, const struct bmi2_fifo_frame *fifo) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + /* Variable to extract virtual header byte */ + uint8_t virtual_header_mode; + /* Variable to define pay-load in words */ + uint8_t payload_word = 0; + /* Variable to define pay-load in bytes */ + uint8_t payload_bytes = 0; + + /* Extract virtual header mode from the frame header */ + virtual_header_mode = BMI2_GET_BITS(*frame_header, BMI2_FIFO_VIRT_FRM_MODE); + + /* If the extracted header byte is a virtual header */ + if (virtual_header_mode == BMI2_FIFO_VIRT_FRM_MODE) { + /* If frame header is not activity recognition header */ + if (*frame_header != 0xC8) { + /* Extract pay-load in words from the header byte */ + payload_word = BMI2_GET_BITS(*frame_header, BMI2_FIFO_VIRT_PAYLOAD) + 1; + /* Convert to bytes */ + payload_bytes = (uint8_t)(payload_word * 2); + + /* Move the data index by those pay-load bytes */ + rslt = move_next_frame(data_index, payload_bytes, fifo); + } + } + + return rslt; +} + +/*! + * @brief This internal API converts LSB value of accelerometer axes to form + * 'g' to 'mg' for self-test. + */ +static void convert_lsb_g(const struct selftest_delta_limit *acc_data_diff, struct selftest_delta_limit *acc_data_diff_mg, + const struct bmi2_dev *dev) +{ + /* Variable to define LSB/g value of axes */ + uint32_t lsb_per_g; + /* Range considered for self-test is +/-16g */ + uint8_t range = BMI2_ACC_SELF_TEST_RANGE; + + /* lsb_per_g for the respective resolution and 16g range */ + lsb_per_g = (uint32_t)(power(2, dev->resolution) / (2 * range)); + /* Accelerometer x value in mg */ + acc_data_diff_mg->x = (acc_data_diff->x / (int32_t)lsb_per_g) * 1000; + /* Accelerometer y value in mg */ + acc_data_diff_mg->y = (acc_data_diff->y / (int32_t)lsb_per_g) * 1000; + /* Accelerometer z value in mg */ + acc_data_diff_mg->z = (acc_data_diff->z / (int32_t)lsb_per_g) * 1000; +} + +/*! + * @brief This internal API is used to calculate the power of a value. + */ +static int32_t power(int16_t base, uint8_t resolution) +{ + /* Initialize loop */ + uint8_t loop = 1; + /* Initialize variable to store the power of 2 value */ + int32_t value = 1; + + for (; loop <= resolution; loop++) + value = (int32_t)(value * base); + + return value; +} + +/*! + * @brief This internal API validates the accelerometer self-test data and + * decides the result of self test operation. + */ +static int8_t validate_self_test(const struct selftest_delta_limit *accel_data_diff) +{ + /* Variable to define error */ + int8_t rslt; + + /* Validating accelerometer data by comparing with minimum and maximum + difference signal value of the axes in mg */ + if (((accel_data_diff->x > BMI2_ST_ACC_X_SIG_MIN_DIFF) && + (accel_data_diff->x < BMI2_ST_ACC_X_SIG_MAX_DIFF)) + && ((accel_data_diff->y > BMI2_ST_ACC_Y_SIG_MIN_DIFF) && + (accel_data_diff->y < BMI2_ST_ACC_Y_SIG_MAX_DIFF)) + && ((accel_data_diff->z > BMI2_ST_ACC_Z_SIG_MIN_DIFF) && + (accel_data_diff->z < BMI2_ST_ACC_Z_SIG_MAX_DIFF))) { + + /* Self-test pass */ + rslt = BMI2_OK; + } else { + /* Self-test fail*/ + rslt = BMI2_E_SELF_TEST_FAIL; + } + + return rslt; +} + +/*! + * @brief This internal API gets the re-mapped x, y and z axes from the sensor. + */ +static int8_t get_remap_axes(struct axes_remap *remap, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for axis re-mapping */ + struct bmi2_feature_config remap_config = {0}; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if + enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) { + /* Search for axis re-mapping and extract its configuration + details */ + feat_found = extract_input_feat_config(&remap_config, BMI2_AXIS_MAP, dev); + + if (feat_found) { + rslt = get_feat_config(remap_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset for axis re-mapping */ + idx = remap_config.start_addr; + + /* Get the re-mapped x-axis */ + remap->x_axis = BMI2_GET_BIT_POS0(feat_config[idx], X_AXIS); + /* Get the re-mapped x-axis polarity */ + remap->x_axis_sign = BMI2_GET_BITS(feat_config[idx], X_AXIS_SIGN); + /* Get the re-mapped y-axis */ + remap->y_axis = BMI2_GET_BITS(feat_config[idx], Y_AXIS); + /* Get the re-mapped y-axis polarity */ + remap->y_axis_sign = BMI2_GET_BITS(feat_config[idx], Y_AXIS_SIGN); + /* Get the re-mapped z-axis */ + remap->z_axis = BMI2_GET_BITS(feat_config[idx], Z_AXIS); + + /* Increment byte to fetch the next data */ + idx++; + + /* Get the re-mapped z-axis polarity */ + remap->z_axis_sign = BMI2_GET_BIT_POS0(feat_config[idx], Z_AXIS_SIGN); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + + return rslt; +} + +/*! + * @brief This internal API sets the re-mapped x, y and z axes in the sensor. + */ +static int8_t set_remap_axes(const struct axes_remap *remap, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to define the feature configuration */ + uint8_t feat_config[BMI2_FEAT_SIZE_IN_BYTES] = {0}; + /* Variable to define the array offset */ + uint8_t idx = 0; + /* Variable to define the register address */ + uint8_t reg_addr = 0; + /* Variable to set the re-mapped x-axes in the sensor */ + uint8_t x_axis = 0; + /* Variable to set the re-mapped y-axes in the sensor */ + uint8_t y_axis = 0; + /* Variable to set the re-mapped z-axes in the sensor */ + uint8_t z_axis = 0; + /* Variable to set the re-mapped x-axes sign in the sensor */ + uint8_t x_axis_sign = 0; + /* Variable to set the re-mapped y-axes sign in the sensor */ + uint8_t y_axis_sign = 0; + /* Variable to set the re-mapped z-axes sign in the sensor */ + uint8_t z_axis_sign = 0; + /* Variable to set flag */ + uint8_t feat_found; + /* Initialize feature configuration for axis re-mapping */ + struct bmi2_feature_config remap_config = {0}; + /* Variable to get the status of advance power save */ + uint8_t aps_stat = 0; + + /* Get status of advance power save mode */ + rslt = bmi2_get_adv_power_save(&aps_stat, dev); + if ((rslt == BMI2_OK) && (aps_stat == BMI2_ENABLE)) { + /* Disable advance power save if + enabled */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + + if (rslt == BMI2_OK) { + /* Search for axis-re-mapping and extract its configuration + details */ + feat_found = extract_input_feat_config(&remap_config, BMI2_AXIS_MAP, dev); + + if (feat_found) { + /* Get the configuration from the page where axis + re-mapping feature resides */ + rslt = get_feat_config(remap_config.page, feat_config, dev); + if (rslt == BMI2_OK) { + /* Define the offset in bytes */ + idx = remap_config.start_addr; + + /* Set the value of re-mapped x-axis */ + x_axis = remap->x_axis & X_AXIS_MASK; + /* Set the value of re-mapped x-axis sign */ + x_axis_sign = ((remap->x_axis_sign << X_AXIS_SIGN_POS) & X_AXIS_SIGN_MASK); + /* Set the value of re-mapped y-axis */ + y_axis = ((remap->y_axis << Y_AXIS_POS) & Y_AXIS_MASK); + /* Set the value of re-mapped y-axis sign */ + y_axis_sign = ((remap->y_axis_sign << Y_AXIS_SIGN_POS) & Y_AXIS_SIGN_MASK); + /* Set the value of re-mapped z-axis */ + z_axis = ((remap->z_axis << Z_AXIS_POS) & Z_AXIS_MASK); + /* Set the value of re-mapped z-axis sign */ + z_axis_sign = remap->z_axis_sign & Z_AXIS_SIGN_MASK; + + /* Arrange axes in the first byte */ + feat_config[idx] = x_axis | x_axis_sign | y_axis | y_axis_sign | z_axis; + + /* Increment the index */ + idx++; + + /* Cannot OR in the second byte since it holds + gyroscope self-offset correction bit */ + feat_config[idx] = BMI2_SET_BIT_POS0(feat_config[idx], Z_AXIS_SIGN, z_axis_sign); + + /* Update the register address */ + reg_addr = BMI2_FEATURES_REG_ADDR + remap_config.start_addr; + + /* Set the configuration back to the page */ + rslt = bmi2_set_regs(reg_addr, &feat_config[remap_config.start_addr], 2, dev); + } + } else { + rslt = BMI2_E_INVALID_SENSOR; + } + + /* Enable Advance power save if disabled while configuring and + not when already disabled */ + if ((aps_stat == BMI2_ENABLE) && (rslt == BMI2_OK)) + rslt = bmi2_set_adv_power_save(BMI2_ENABLE, dev); + } + + return rslt; +} + +/*! + * @brief This internal API is used to get the feature configuration from the + * selected page. + */ +static int8_t get_feat_config(uint8_t sw_page, uint8_t *feat_config, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define bytes remaining to read */ + uint8_t bytes_remain = BMI2_FEAT_SIZE_IN_BYTES; + /* Variable to define the read-write length */ + uint8_t read_write_len = 0; + /* Variable to define the feature configuration address */ + uint8_t addr = BMI2_FEATURES_REG_ADDR; + /* Variable to define index */ + uint8_t index = 0; + + if (feat_config != NULL) { + /* Check whether the page is valid */ + if (sw_page < dev->page_max) { + /* Switch page */ + rslt = bmi2_set_regs(BMI2_FEAT_PAGE_ADDR, &sw_page, 1, dev); + /* If user length is less than feature length */ + if ((rslt == BMI2_OK) && (dev->read_write_len < BMI2_FEAT_SIZE_IN_BYTES)) { + /* Read-write should be even */ + if ((dev->read_write_len % 2) != 0) + dev->read_write_len--; + + while (bytes_remain > 0) { + if (bytes_remain >= dev->read_write_len) { + /* Read from the page */ + rslt = bmi2_get_regs(addr, &feat_config[index], dev->read_write_len, dev); + + /* Update index */ + index += (uint8_t)dev->read_write_len; + /* Update address */ + addr += (uint8_t)dev->read_write_len; + + /* Update read-write length */ + read_write_len += (uint8_t)dev->read_write_len; + } else { + /* Read from the page */ + rslt = bmi2_get_regs(addr, (uint8_t *)(feat_config + index), + (uint16_t)bytes_remain, dev); + + /* Update read-write length */ + read_write_len += bytes_remain; + + } + + /* Remaining bytes */ + bytes_remain = BMI2_FEAT_SIZE_IN_BYTES - read_write_len; + + if (rslt != BMI2_OK) + break; + } + /* Burst read 16 bytes */ + } else { + if (rslt == BMI2_OK) { + /* Get configuration from the page */ + rslt = bmi2_get_regs(BMI2_FEATURES_REG_ADDR, feat_config, BMI2_FEAT_SIZE_IN_BYTES, dev); + } + } + + } else { + rslt = BMI2_E_INVALID_PAGE; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables compensation of the gain defined + * in the GAIN register. + */ +static int8_t enable_gyro_gain(uint8_t enable, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to define register data */ + uint8_t reg_data = 0; + + rslt = bmi2_get_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + if (rslt == BMI2_OK) { + reg_data = BMI2_SET_BITS(reg_data, BMI2_GYR_GAIN_EN, enable); + + rslt = bmi2_set_regs(BMI2_GYR_OFF_COMP_6_ADDR, ®_data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API corrects the gyroscope cross-axis sensitivity + * between the z and the x axis. + */ +static void comp_gyro_cross_axis_sensitivity(struct bmi2_sens_axes_data *gyr_data, const struct bmi2_dev *dev) +{ + /* Get the compensated gyroscope x-axis */ + gyr_data->x = gyr_data->x - (int16_t)(((int32_t)dev->gyr_cross_sens_zx * (int32_t)gyr_data->z) / 512); +} + +/*! + * @brief This internal API is used to extract the input feature configuration + * details from the look-up table. + */ +static uint8_t extract_input_feat_config(struct bmi2_feature_config *feat_config, uint8_t type, const struct bmi2_dev *dev) +{ + /* Variable to define loop */ + uint8_t loop = 0; + /* Variable to set flag */ + uint8_t feat_found = BMI2_FALSE; + + /* Search for the input feature from the input configuration array */ + while (loop < dev->input_sens) { + if (dev->feat_config[loop].type == type) { + *feat_config = dev->feat_config[loop]; + feat_found = BMI2_TRUE; + break; + } + + loop++; + } + + /* Return flag */ + return feat_found; +} + +/*! + * @brief This internal API is used to extract the output feature configuration + * details from the look-up table. + */ +static uint8_t extract_output_feat_config(struct bmi2_feature_config *feat_output, uint8_t type, const struct bmi2_dev *dev) +{ + /* Variable to define loop */ + uint8_t loop = 0; + /* Variable to set flag */ + uint8_t feat_found = BMI2_FALSE; + + /* Search for the output feature from the output configuration array */ + while (loop < dev->out_sens) { + if (dev->feat_output[loop].type == type) { + *feat_output = dev->feat_output[loop]; + feat_found = BMI2_TRUE; + break; + } + + loop++; + } + + /* Return flag */ + return feat_found; +} + +/*! + * @brief This internal API is used to validate the boundary conditions. + */ +static int8_t check_boundary_val(uint8_t *val, uint8_t min, uint8_t max, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + if (val != NULL) { + /* Check if value is below minimum value */ + if (*val < min) { + /* Auto correct the invalid value to minimum value */ + *val = min; + dev->info |= BMI2_I_MIN_VALUE; + } + + /* Check if value is above maximum value */ + if (*val > max) { + /* Auto correct the invalid value to maximum value */ + *val = max; + dev->info |= BMI2_I_MAX_VALUE; + } + } else { + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + +/*! + * @brief This internal API saves the configurations before performing FOC. + */ +static int8_t save_accel_foc_config(struct bmi2_accel_config *acc_cfg, uint8_t *aps, uint8_t *acc_en, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Get accelerometer configurations to be saved */ + rslt = get_accel_config(acc_cfg, dev); + if (rslt == BMI2_OK) { + + /* Get accelerometer enable status to be saved */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + *acc_en = BMI2_GET_BITS(pwr_ctrl_data, BMI2_ACC_EN); + + /* Get advance power save mode to be saved */ + if (rslt == BMI2_OK) + rslt = bmi2_get_adv_power_save(aps, dev); + } + + return rslt; +} + +/*! + * @brief This internal sets configurations for performing accelerometer FOC. + */ +static int8_t set_accel_foc_config(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to set the accelerometer configuration value */ + uint8_t acc_conf_data = BMI2_FOC_ACC_CONF_VAL; + /* Variable to select the sensor */ + uint8_t sens_list = BMI2_ACCEL; + + /* Disabling offset compensation */ + rslt = set_accel_offset_comp(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) { + /* Set accelerometer configurations to 50Hz, continuous mode, + CIC mode */ + rslt = bmi2_set_regs(BMI2_ACC_CONF_ADDR, &acc_conf_data, 1, dev); + if (rslt == BMI2_OK) { + /* Set accelerometer to normal mode by enabling it */ + rslt = bmi2_sensor_enable(&sens_list, 1, dev); + if (rslt == BMI2_OK) { + /* Disable advance power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API enables/disables the offset compensation for + * filtered and un-filtered accelerometer data. + */ +static int8_t set_accel_offset_comp(uint8_t offset_en, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to store data */ + uint8_t data = 0; + + /* Enable/Disable offset compensation */ + rslt = bmi2_get_regs(BMI2_NV_CONF_ADDR, &data, 1, dev); + if (rslt == BMI2_OK) { + data = BMI2_SET_BITS(data, BMI2_NV_ACC_OFFSET, offset_en); + rslt = bmi2_set_regs(BMI2_NV_CONF_ADDR, &data, 1, dev); + } + + return rslt; +} + +/*! + * @brief This internal API converts the accelerometer range value into + * corresponding integer value. + */ +static void map_accel_range(uint8_t range_in, uint8_t *range_out) +{ + switch (range_in) { + case BMI2_ACC_RANGE_2G: + *range_out = 2; + break; + case BMI2_ACC_RANGE_4G: + *range_out = 4; + break; + case BMI2_ACC_RANGE_8G: + *range_out = 8; + break; + case BMI2_ACC_RANGE_16G: + *range_out = 16; + break; + default: + break; + } +} + +/*! + * @brief This internal API compensate the accelerometer data against gravity. + */ +static void comp_for_gravity(uint16_t lsb_per_g, const int16_t g_val[3], const struct bmi2_sens_axes_data *data, + struct offset_delta *comp_data) +{ + /* Array to store the accelerometer values in LSB */ + int16_t accel_value_lsb[3] = {0}; + /* Variable to store the index */ + uint8_t index; + + for (index = 0; index < 3; index++) { + /* Convert g-value to LSB */ + accel_value_lsb[index] = (int16_t)(lsb_per_g * g_val[index]); + } + + /* Get the compensated values for X, Y and Z axis */ + comp_data->x = (data->x - accel_value_lsb[BMI2_X_AXIS]); + comp_data->y = (data->y - accel_value_lsb[BMI2_Y_AXIS]); + comp_data->z = (data->z - accel_value_lsb[BMI2_Z_AXIS]); +} + +/*! + * @brief This internal API scales the compensated accelerometer data according + * to the offset register resolution. + * + * @note The bit position is always greater than 0 since accelerometer data is + * 16 bit wide. + */ +static void scale_accel_offset(uint8_t range, const struct offset_delta *comp_data, struct accel_offset *data) +{ + /* Variable to store the position of bit having 3.9mg resolution */ + int8_t bit_pos_3_9mg; + /* Variable to store the position previous of bit having 3.9mg + resolution */ + int8_t bit_pos_3_9mg_prev_bit; + /* Variable to store the round-off value */ + uint8_t round_off; + + /* Find the bit position of 3.9mg */ + bit_pos_3_9mg = get_bit_pos_3_9mg(range); + + /* Round off, consider if the next bit is high */ + bit_pos_3_9mg_prev_bit = bit_pos_3_9mg - 1; + round_off = (uint8_t)(power(2, ((uint8_t) bit_pos_3_9mg_prev_bit))); + + /* Scale according to offset register resolution */ + data->x = (uint8_t)((comp_data->x + round_off) / power(2, ((uint8_t)bit_pos_3_9mg))); + data->y = (uint8_t)((comp_data->y + round_off) / power(2, ((uint8_t)bit_pos_3_9mg))); + data->z = (uint8_t)((comp_data->z + round_off) / power(2, ((uint8_t)bit_pos_3_9mg))); + +} + +/*! + * @brief This internal API finds the bit position of 3.9mg according to given + * range and resolution. + */ +static int8_t get_bit_pos_3_9mg(uint8_t range) +{ + /* Variable to store the bit position of 3.9mg resolution*/ + int8_t bit_pos_3_9mg; + /* Variable to shift the bits according to the resolution */ + uint32_t divisor = 1; + /* Scaling factor to get the bit position of 3.9 mg resolution */ + int16_t scale_factor = -1; + /* Variable to store temporary value */ + uint16_t temp; + + /* Shift left by the times of resolution */ + divisor = divisor << 16; + + /* Get the bit position to be shifted */ + temp = (uint16_t)(divisor / (range * 256)); + + /* Get the scaling factor until bit position is shifted to last bit */ + while (temp != 1) { + scale_factor++; + temp = temp >> 1; + } + + /* Scaling factor is the bit position of 3.9 mg resolution */ + bit_pos_3_9mg = (int8_t) scale_factor; + + return bit_pos_3_9mg; +} + +/*! + * @brief This internal API inverts the accelerometer offset data. + */ +static void invert_accel_offset(struct accel_offset *offset_data) +{ + /* Get the offset data */ + offset_data->x = (uint8_t)((offset_data->x) * (-1)); + offset_data->y = (uint8_t)((offset_data->y) * (-1)); + offset_data->z = (uint8_t)((offset_data->z) * (-1)); +} + +/*! + * @brief This internal API writes the offset data in the offset compensation + * register. + */ +static int8_t write_accel_offset(const struct accel_offset *offset, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to store the offset data */ + uint8_t data_array[3] = {0}; + + data_array[0] = offset->x; + data_array[1] = offset->y; + data_array[2] = offset->z; + + /* Offset values are written in the offset register */ + rslt = bmi2_set_regs(BMI2_ACC_OFF_COMP_0_ADDR, data_array, 3, dev); + + return rslt; +} + +/*! + * @brief This internal API restores the configurations saved before performing + * accelerometer FOC. + */ +static int8_t restore_accel_foc_config(struct bmi2_accel_config *acc_cfg, uint8_t aps, uint8_t acc_en, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Restore the saved accelerometer configurations */ + rslt = set_accel_config(acc_cfg, dev); + + if (rslt == BMI2_OK) { + /* Restore the saved accelerometer enable status */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + if (rslt == BMI2_OK) { + pwr_ctrl_data = BMI2_SET_BITS(pwr_ctrl_data, BMI2_ACC_EN, acc_en); + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + + /* Restore the saved advance power save */ + if (rslt == BMI2_OK) + rslt = bmi2_set_adv_power_save(aps, dev); + } + } + + return rslt; +} +/*! + * @brief This internal API saves the configurations before performing gyroscope + * FOC. + */ +static int8_t save_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t *aps, uint8_t *gyr_en, const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Get gyroscope configurations to be saved */ + rslt = get_gyro_config(gyr_cfg, dev); + if (rslt == BMI2_OK) { + + /* Get gyroscope enable status to be saved */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + *gyr_en = BMI2_GET_BITS(pwr_ctrl_data, BMI2_GYR_EN); + + /* Get advance power save mode to be saved */ + if (rslt == BMI2_OK) + rslt = bmi2_get_adv_power_save(aps, dev); + } + + return rslt; +} + +/*! + * @brief This internal sets configurations for performing gyroscope FOC. + */ +static int8_t set_gyro_foc_config(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Array to set the gyroscope configuration value (ODR, Performance mode + and bandwidth) and gyroscope range */ + uint8_t gyr_conf_data[2] = { BMI2_FOC_GYR_CONF_VAL, BMI2_GYR_RANGE_2000 }; + /* Variable to select the sensor */ + uint8_t sens_list = BMI2_GYRO; + + /* Disabling gyroscope offset compensation */ + rslt = bmi2_set_gyro_offset_comp(BMI2_DISABLE, dev); + if (rslt == BMI2_OK) { + /* Set gyroscope configurations to 25Hz, continuous mode, + CIC mode, and 2000 dps range */ + rslt = bmi2_set_regs(BMI2_GYR_CONF_ADDR, gyr_conf_data, 2, dev); + if (rslt == BMI2_OK) { + /* Set gyroscope to normal mode by enabling it */ + rslt = bmi2_sensor_enable(&sens_list, 1, dev); + if (rslt == BMI2_OK) { + /* Disable advance power save mode */ + rslt = bmi2_set_adv_power_save(BMI2_DISABLE, dev); + } + } + } + + return rslt; +} + +/*! + * @brief This internal API inverts the gyroscope offset data. + */ +static void invert_gyro_offset(struct bmi2_sens_axes_data *offset_data) +{ + /* Invert the values */ + offset_data->x = (int16_t)((offset_data->x) * (-1)); + offset_data->y = (int16_t)((offset_data->y) * (-1)); + offset_data->z = (int16_t)((offset_data->z) * (-1)); +} + +/*! + * @brief This internal API restores the gyroscope configurations saved + * before performing FOC. + */ +static int8_t restore_gyro_config(struct bmi2_gyro_config *gyr_cfg, uint8_t aps, uint8_t gyr_en, struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + /* Variable to get the status from PWR_CTRL register */ + uint8_t pwr_ctrl_data = 0; + + /* Restore the saved gyroscope configurations */ + rslt = set_gyro_config(gyr_cfg, dev); + + if (rslt == BMI2_OK) { + /* Restore the saved gyroscope enable status */ + rslt = bmi2_get_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + if (rslt == BMI2_OK) { + pwr_ctrl_data = BMI2_SET_BITS(pwr_ctrl_data, BMI2_GYR_EN, gyr_en); + rslt = bmi2_set_regs(BMI2_PWR_CTRL_ADDR, &pwr_ctrl_data, 1, dev); + + /* Restore the saved advance power save */ + if (rslt == BMI2_OK) + rslt = bmi2_set_adv_power_save(aps, dev); + } + } + + return rslt; +} + +/*! + * @brief This internal API saturates the gyroscope data value before writing to + * to 10 bit offset register. + */ +static void saturate_gyro_data(struct bmi2_sens_axes_data *gyr_off) +{ + if (gyr_off->x > 511) + gyr_off->x = 511; + + if (gyr_off->x < -512) + gyr_off->x = -512; + + if (gyr_off->y > 511) + gyr_off->y = 511; + + if (gyr_off->y < -512) + gyr_off->y = -512; + + if (gyr_off->z > 511) + gyr_off->z = 511; + + if (gyr_off->z < -512) + gyr_off->z = -512; +} + +/*! + * @brief This internal API is used to validate the device structure pointer for + * null conditions. + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) { + /* Device structure pointer is not valid */ + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2.h new file mode 100755 index 0000000000000000000000000000000000000000..451d3cb03ee93acbf8ac115954e9cb01ad8f7416 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2.h @@ -0,0 +1,1250 @@ +/** + * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of the + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * The information provided is believed to be accurate and reliable. + * The copyright holder assumes no responsibility + * for the consequences of use + * of such information nor for any infringement of patents or + * other rights of third parties which may result from its use. + * No license is granted by implication or otherwise under any patent or + * patent rights of the copyright holder. + * + * @file bmi2.h + * @date 16 August, 2018 + * @version 1.35.0 + * @brief Sensor driver for BMI2XY sensor + * + */ + +#ifndef BMI2_H_ +#define BMI2_H_ + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************/ +/*! Header files +****************************************************************************/ +#include "bmi2_defs.h" + +/***************************************************************************/ +/*! BMI2XY User Interface function prototypes +****************************************************************************/ +/*! + * @brief This API is the entry point for bmi2 sensor. It selects between + * I2C/SPI interface, based on user selection. It also reads the chip-id of + * the sensor. + * + * @param[in,out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_DEV_NOT_FOUND - Invalid device + */ +int8_t bmi2_sec_init(struct bmi2_dev *dev); + +/*! + * @brief This API reads the data from the given register address of bmi2 + * sensor. + * + * @param[in] reg_addr : Register address from which data is read. + * @param[out] data : Pointer to data buffer where read data is stored. + * @param[in] len : No. of bytes of data to be read. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note For most of the registers auto address increment applies, with the + * exception of a few special registers, which trap the address. For e.g., + * Register address - 0x26, 0x5E. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_regs(uint8_t reg_addr, uint8_t *data, uint16_t len, const struct bmi2_dev *dev); + +/*! + * @brief This API writes data to the given register address of bmi2 sensor. + * + * @param[in] reg_addr : Register address to which the data is written. + * @param[in] data : Pointer to data buffer in which data to be written + * is stored. + * @param[in] len : No. of bytes of data to be written. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_regs(uint8_t reg_addr, const uint8_t *data, uint16_t len, const struct bmi2_dev *dev); + +/*! + * @brief This API resets bmi2 sensor. All registers are overwritten with + * their default values. + * + * @note If selected interface is SPI, an extra dummy byte is read to bring the + * interface back to SPI from default, after the soft reset command. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_soft_reset(struct bmi2_dev *dev); + +/*! + * @brief This API selects the sensors/features to be enabled. + * + * @param[in] sens_list : Pointer to select the sensor/feature. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features that can be enabled. + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_PICK_UP | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_GYRO_SELF_OFF | 20 + * BMI2_WRIST_GESTURE | 21 + * BMI2_WRIST_WEAR_WAKE_UP | 22 + * BMI2_ACTIVITY_RECOG | 23 + * + * @example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO}; + * uint8_t n_sens = 2; + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_sensor_enable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API selects the sensors/features to be disabled. + * + * @param[in] sens_list : Pointer to select the sensor/feature. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features that can be disabled. + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_PICK_UP | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_GYRO_SELF_OFF | 20 + * BMI2_WRIST_GESTURE | 21 + * BMI2_WRIST_WEAR_WAKE_UP | 22 + * BMI2_ACTIVITY_RECOG | 23 + * + * @example uint8_t sens_list[2] = {BMI2_ACCEL, BMI2_GYRO}; + * uint8_t n_sens = 2; + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_sensor_disable(const uint8_t *sens_list, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API sets the sensor/feature configuration. + * + * @param[in] sens_cfg : Structure instance of bmi2_sens_config. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features that can be configured + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_PICK_UP | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_WRIST_GESTURE | 21 + * BMI2_WRIST_WEAR_WAKE_UP | 22 + * BMI2_STEP_CNT_PARAMS | 25 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_set_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API gets the sensor/feature configuration. + * + * @param[in] sens_cfg : Structure instance of bmi2_sens_config. + * @param[in] n_sens : Number of sensors selected. + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features whose configurations can be read. + * + * sens_list | Values + * -------------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_TEMP | 3 + * BMI2_ANY_MOTION | 4 + * BMI2_NO_MOTION | 5 + * BMI2_TILT | 6 + * BMI2_ORIENTATION | 7 + * BMI2_SIG_MOTION | 8 + * BMI2_STEP_DETECTOR | 9 + * BMI2_STEP_COUNTER | 10 + * BMI2_STEP_ACTIVITY | 11 + * BMI2_GYRO_GAIN_UPDATE | 12 + * BMI2_PICK_UP | 13 + * BMI2_GLANCE_DETECTOR | 14 + * BMI2_WAKE_UP | 15 + * BMI2_HIGH_G | 16 + * BMI2_LOW_G | 17 + * BMI2_FLAT | 18 + * BMI2_EXT_SENS_SYNC | 19 + * BMI2_WRIST_GESTURE | 21 + * BMI2_WRIST_WEAR_WAKE_UP | 22 + * BMI2_STEP_CNT_PARAMS | 25 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_get_sensor_config(struct bmi2_sens_config *sens_cfg, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API gets the sensor/feature data for accelerometer, gyroscope, + * auxiliary sensor, step counter, high-g, gyroscope user-gain update, + * orientation, gyroscope cross sensitivity and error status for NVM and VFRM. + * + * @param[out] sensor_data : Structure instance of bmi2_sensor_data. + * @param[in] n_sens : Number of sensors selected. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Sensors/features whose data can be read + * + * sens_list | Values + * ---------------------|----------- + * BMI2_ACCEL | 0 + * BMI2_GYRO | 1 + * BMI2_AUX | 2 + * BMI2_ORIENTATION | 7 + * BMI2_STEP_COUNTER | 10 + * BMI2_GYRO_GAIN_UPDATE| 12 + * BMI2_HIGH_G | 16 + * BMI2_NVM_STATUS | 26 + * BMI2_VFRM_STATUS | 27 + * BMI2_GYRO_CROSS_SENSE| 28 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_get_sensor_data(struct bmi2_sensor_data *sensor_data, uint8_t n_sens, struct bmi2_dev *dev); + +/*! + * @brief This API enables/disables the advance power save mode in the sensor. + * + * @param[in] enable : To enable/disable advance power mode. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables advance power save. + * BMI2_ENABLE | Enables advance power save. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_set_adv_power_save(uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the status of advance power save mode in the sensor. + * + * @param[out] aps_status : Pointer to get the status of APS mode. + * @param[in] dev : Structure instance of bmi2_dev. + * + * aps_status | Description + * -------------|--------------- + * BMI2_DISABLE | Advance power save disabled. + * BMI2_ENABLE | Advance power save enabled. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_get_adv_power_save(uint8_t *aps_status, const struct bmi2_dev *dev); + +/*! + * @brief This API loads the configuration file to the bmi2 sensor. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_CONFIG_LOAD - Configuration load fail + */ +int8_t bmi2_write_config_file(struct bmi2_dev *dev); + +/*! + * @brief This API sets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + * + * @param[in] int_cfg : Structure instance of bmi2_int_pin_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_INT_PIN - Error: Invalid interrupt pin + */ +int8_t bmi2_set_int_pin_config(const struct bmi2_int_pin_config *int_cfg, const struct bmi2_dev *dev); + +/*! + * @brief This API gets: + * 1) The input output configuration of the selected interrupt pin: + * INT1 or INT2. + * 2) The interrupt mode: permanently latched or non-latched. + * + * @param[in,out] int_cfg : Structure instance of bmi2_int_pin_config. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_INT_PIN - Error: Invalid interrupt pin + */ +int8_t bmi2_get_int_pin_config(struct bmi2_int_pin_config *int_cfg, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the interrupt status of both feature and data + * interrupts. + * + * @param[out] int_status : Pointer to get the status of the interrupts. + * @param[in] dev : Structure instance of bmi2_dev. + * + * int_status | Status + * -----------|------------ + * 0x00 | INTA + * 0x01 | INTB + * 0x02 | INTC + * 0x03 | INTD + * 0x04 | INTE + * 0x05 | INTF + * 0x06 | INTG + * 0x07 | INTH + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_int_status(uint16_t *int_status, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the FIFO configuration in the sensor. + * + * @param[in] config : FIFO configurations to be enabled/disabled. + * @param[in] enable : Enable/Disable FIFO configurations. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables FIFO configuration. + * BMI2_ENABLE | Enables FIFO configuration. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_fifo_config(uint16_t config, uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO configuration from the sensor. + * + * @param[out] fifo_config : Pointer variable to get FIFO configuration value. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_config(uint16_t *fifo_config, const struct bmi2_dev *dev); + +/*! + * @brief This API reads FIFO data. + * + * @param[in, out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note APS has to be disabled before calling this function. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_read_fifo_data(struct bmi2_fifo_frame *fifo, const struct bmi2_dev *dev); + +/*! + * This API parses and extracts the accelerometer frames from FIFO data read by + * the "bmi2_read_fifo_data" API and stores it in the "accel_data" structure + * instance. + * + * @param[out] accel_data : Structure instance of bmi2_sens_axes_data + * where the parsed data bytes are stored. + * @param[in,out] accel_length : Number of accelerometer frames. + * @param[in,out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_extract_accel(struct bmi2_sens_axes_data *accel_data, uint16_t *accel_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API parses and extracts the auxiliary frames from FIFO data + * read by the "bmi2_read_fifo_data" API and stores it in "aux_data" buffer. + + * @param[out] aux : Pointer to structure where the parsed auxiliary + * data bytes are stored. + * @param[in,out] aux_length : Number of auxiliary frames. + * @param[in,out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_extract_aux(struct bmi2_aux_fifo_data *aux, uint16_t *aux_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * This API parses and extracts the gyroscope frames from FIFO data read by the + * "bmi2_read_fifo_data" API and stores it in the "gyro_data" + * structure instance. + * + * @param[out] gyro_data : Structure instance of bmi2_sens_axes_data + * where the parsed data bytes are stored. + * @param[in,out] gyro_length : Number of gyroscope frames. + * @param[in,out] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_extract_gyro(struct bmi2_sens_axes_data *gyro_data, uint16_t *gyro_length, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); +/*! + * @brief This API writes the available sensor specific commands to the sensor. + * + * @param[in] command : Commands to be given to the sensor. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Commands | Values + * ---------------------|--------------------- + * BMI2_SOFT_RESET_CMD | 0xB6 + * BMI2_FIFO_FLUSH_CMD | 0xB0 + * BMI2_USR_GAIN_CMD | 0x03 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_command_register(uint8_t command, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the FIFO self wake up functionality in the sensor. + * + * @param[in] fifo_self_wake_up : Variable to set FIFO self wake-up. + * @param[in] dev : Structure instance of bmi2_dev. + * + * fifo_self_wake_up | Description + * -------------------|--------------- + * BMI2_DISABLE | Disables self wake-up. + * BMI2_ENABLE | Enables self wake-up. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_fifo_self_wake_up(uint8_t fifo_self_wake_up, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO self wake up functionality from the sensor. + * + * @param[out] fifo_self_wake_up : Pointer variable to get the status of FIFO + * self wake-up. + * @param[in] dev : Structure instance of bmi2_dev. + * + * fifo_self_wake_up | Description + * -------------------|--------------- + * BMI2_DISABLE | Self wake-up disabled + * BMI2_ENABLE | Self wake-up enabled. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_self_wake_up(uint8_t *fifo_self_wake_up, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the FIFO water mark level which is set in the sensor. + * + * @param[in] fifo_wm : Variable to set FIFO water-mark level. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_fifo_wm(uint16_t fifo_wm, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO water mark level which is set in the sensor. + * + * @param[out] fifo_wm : Pointer variable to store FIFO water-mark level. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_wm(uint16_t *fifo_wm, const struct bmi2_dev *dev); + +/*! + * @brief This API sets either filtered or un-filtered FIFO accelerometer or + * gyroscope data. + * + * @param[in] sens_sel : Selects either accelerometer or + * gyroscope sensor. + * @param[in] fifo_filter_data : Variable to set the filter data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * -----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * + * Value | fifo_filter_data + * ---------|--------------------- + * 0x00 | Un-filtered data + * 0x01 | Filtered data + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_OUT_OF_RANGE - Error: Out of range + */ +int8_t bmi2_set_fifo_filter_data(uint8_t sens_sel, uint8_t fifo_filter_data, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the FIFO accelerometer or gyroscope filter data. + * + * @param[in] sens_sel : Selects either accelerometer or + * gyroscope sensor. + * @param[out] fifo_filter_data : Pointer variable to get the filter data. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * -----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * + * Value | fifo_filter_data + * ---------|--------------------- + * 0x00 | Un-filtered data + * 0x01 | Filtered data + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_get_fifo_filter_data(uint8_t sens_sel, uint8_t *fifo_filter_data, const struct bmi2_dev *dev); + +/*! + * @brief This API sets the down sampling rate for FIFO accelerometer or + * gyroscope FIFO data. + * + * @param[in] sens_sel : Selects either either accelerometer or + * gyroscope sensor. + * @param[in] fifo_down_samp : Variable to set the down sampling rate. + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * ----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_OUT_OF_RANGE - Error: Out of range + */ +int8_t bmi2_set_fifo_down_sample(uint8_t sens_sel, uint8_t fifo_down_samp, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the down sampling rate, configured for FIFO + * accelerometer or gyroscope data. + * + * @param[in] sens_sel : Selects either either accelerometer or + * gyroscope sensor. + * @param[out] fifo_down_samp : Pointer variable to store the down sampling rate + * @param[in] dev : Structure instance of bmi2_dev. + * + * sens_sel | values + * ----------------|---------- + * BMI2_ACCEL | 0x01 + * BMI2_GYRO | 0x02 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + */ +int8_t bmi2_get_fifo_down_sample(uint8_t sens_sel, uint8_t *fifo_down_samp, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the length of FIFO data available in the sensor in + * bytes. + * + * @param[out] fifo_length : Pointer variable to store the value of FIFO byte + * counter. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note The byte counter is updated each time a complete frame is read or + * written. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_fifo_length(uint16_t *fifo_length, const struct bmi2_dev *dev); + +/*! + * @brief This API reads the user-defined bytes of data from the given register + * address of auxiliary sensor in manual mode. + * + * @param[in] reg_addr : Address from where data is read. + * @param[out] aux_data : Pointer to the stored buffer. + * @param[in] len : Total length of data to be read. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_RD_ADDR is only allowed if AUX is not busy. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration. + */ +int8_t bmi2_read_aux_man_mode(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, const struct bmi2_dev *dev); + +/*! + * @brief This API enables/disables OIS interface. + * + * @param[in] enable : To enable/disable OIS interface. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Enable | Description + * -------------|--------------- + * BMI2_DISABLE | Disables OIS interface. + * BMI2_ENABLE | Enables OIS interface. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_ois_interface(uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written in manual mode. + * + * @param[in] reg_addr : AUX address where data is to be written. + * @param[in] aux_data : Pointer to data to be written. + * @param[in] len : Total length of data to be written. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration. + */ +int8_t bmi2_write_aux_man_mode(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, const struct bmi2_dev *dev); + +/*! + * @brief This API writes the user-defined bytes of data and the address of + * auxiliary sensor where data is to be written, from an interleaved input, + * in manual mode. + * + * @param[in] reg_addr : AUX address where data is to be written. + * @param[in] aux_data : Pointer to data to be written. + * @param[in] len : Total length of data to be written. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @note Change of BMI2_AUX_WR_ADDR is only allowed if AUX is not busy. + + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + * @retval BMI2_E_AUX_INVALID_CFG - Error: Invalid auxiliary configuration. + */ +int8_t bmi2_write_aux_interleaved(uint8_t reg_addr, const uint8_t *aux_data, uint16_t len, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the data ready status of accelerometer, gyroscope, + * auxiliary, ready status of command decoder and busy status of auxiliary. + * + * @param[out] status : Pointer variable to the status. + * @param[in] dev : Structure instance of bmi2_dev. + * + * Value | Status + * ---------|--------------------- + * 0x80 | DRDY_ACC + * 0x40 | DRDY_GYR + * 0x20 | DRDY_AUX + * 0x10 | CMD_RDY + * 0x04 | AUX_BUSY + + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_status(uint8_t *status, const struct bmi2_dev *dev); + +/*! + * @brief This API can be used to write sync commands like ODR, sync period, + * frequency and phase, resolution ratio, sync time and delay time. + * + * @param[in] command : Sync command to be written. + * @param[in] n_comm : Length of the command. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_write_sync_commands(const uint8_t *command, uint8_t n_comm, const struct bmi2_dev *dev); + +/*! + * @brief This API performs self-test to check the proper functionality of the + * accelerometer sensor. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SELF_TEST_FAIL - Error: Self test fail + */ +int8_t bmi2_perform_accel_self_test(struct bmi2_dev *dev); + +/*! + * @brief This API maps/unmaps feature interrupts to that of interrupt pins. + * + * @param[in] sens_int : Structure instance of bmi2_sens_int_config. + * @param[in] n_sens : Number of features to be mapped. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_FEAT_INT - Error: Invalid feature Interrupt + */ +int8_t bmi2_map_feat_int(const struct bmi2_sens_int_config *sens_int, uint8_t n_sens, const struct bmi2_dev *dev); + +/*! + * @brief This API maps/un-maps data interrupts to that of interrupt pins. + * + * @param[in] int_pin : Interrupt pin selected. + * @param[in] data_int : Type of data interrupt to be mapped. + * @param[in] dev : Structure instance of bmi2_dev. + * + * data_int | Mask values + * ---------------------|--------------------- + * BMI2_FFULL_INT | 0x01 + * BMI2_FWM_INT | 0x02 + * BMI2_DRDY_INT | 0x04 + * BMI2_ERR_INT | 0x08 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_INT_PIN - Error: Invalid interrupt pin + */ +int8_t bmi2_map_data_int(uint8_t data_int, enum bmi2_hw_int_pin int_pin, const struct bmi2_dev *dev); + +/*! + * @brief This API gets the re-mapped x, y and z axes from the sensor and + * updates the values in the device structure. + * + * @param[out] remapped_axis : Structure that stores re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_get_remap_axes(struct bmi2_remap *remapped_axis, struct bmi2_dev *dev); + +/*! + * @brief This API sets the re-mapped x, y and z axes to the sensor and + * updates them in the device structure. + * + * @param[in] remapped_axis : Structure that stores re-mapped axes. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_INVALID_PAGE - Error: Invalid Page + */ +int8_t bmi2_set_remap_axes(const struct bmi2_remap *remapped_axis, struct bmi2_dev *dev); + +/*! + * @brief This API updates the gyroscope user-gain. + * + * @param[in] user_gain : Structure that stores user-gain configurations. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_GYR_USER_GAIN_UPD_FAIL - Gyroscope user gain update fail + */ +int8_t bmi2_update_gyro_user_gain(const struct bmi2_gyro_user_gain_config *user_gain, struct bmi2_dev *dev); + +/*! + * @brief This API reads the compensated gyroscope user-gain values. + * + * @param[out] gyr_usr_gain : Structure that stores gain values. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_read_gyro_user_gain(struct bmi2_gyro_user_gain_data *gyr_usr_gain, const struct bmi2_dev *dev); + +/*! + * @brief This API enables/disables gyroscope offset compensation. It adds the + * offsets defined in the offset register with gyroscope data. + * + * @param[in] enable : Enables/Disables gyroscope offset compensation. + * @param[in] dev : Structure instance of bmi2_dev. + * + * enable | Description + * -------------|--------------- + * BMI2_ENABLE | Enables gyroscope offset compensation. + * BMI2_DISABLE | Disables gyroscope offset compensation. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_set_gyro_offset_comp(uint8_t enable, const struct bmi2_dev *dev); + +/*! + * @brief This API reads the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + * + * @param[out] gyr_off_comp_axes: Structure to store gyroscope offset + * compensated values. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_read_gyro_offset_comp_axes(struct bmi2_sens_axes_data *gyr_off_comp_axes, const struct bmi2_dev *dev); + +/*! + * @brief This API writes the gyroscope bias values for each axis which is used + * for gyroscope offset compensation. + * + * @param[in] gyr_off_comp_axes : Structure to store gyroscope offset + * compensated values. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_write_gyro_offset_comp_axes(const struct bmi2_sens_axes_data *gyr_off_comp_axes, const struct bmi2_dev *dev); + +/*! + * @brief This internal API is used to parse the activity output from the + * FIFO in header mode. + * + * @param[out] act_recog : Pointer to buffer where the parsed activity data + * bytes are stored. + * @param[in] act_frm_len : Number of activity frames parsed. + * @param[in] fifo : Structure instance of bmi2_fifo_frame. + * @param[in] dev : Structure instance of bmi2_dev. + * + * @verbatim + * bmi2_act_rec_output | + * Structure parameters | Description + *--------------------------|-------------------------------------------------- + * time_stamp | time-stamp (expressed in 50Hz ticks) + * -------------------------|--------------------------------------------------- + * type | Type of activity + * -------------------------|--------------------------------------------------- + * stat | Activity status + * -------------------------|--------------------------------------------------- + * @endverbatim + * + * type | Activities + *----------|--------------------- + * 0 | UNKNOWN + * 1 | STILL + * 2 | WALK + * 3 | RUN + * 4 | BIKE + * 5 | VEHICLE + * 6 | TILTED + * + * + * stat | Activity status + *----------|--------------------- + * 1 | START + * 2 | END + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_W_FIFO_EMPTY - Warning : FIFO is empty + * @retval BMI2_W_PARTIAL_READ - Warning : There are more frames to be read + */ +int8_t bmi2_get_act_recog_output(struct bmi2_act_recog_output *act_recog, uint16_t *act_frm_len, struct bmi2_fifo_frame *fifo, + const struct bmi2_dev *dev); + +/*! + * @brief This API performs the gyroscope MEMS self-test. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_SELF_TEST_FAIL - Error: Self-test fail + * @retval BMI2_E_SELF_TEST_NOT_DONE - Error: Self-test not done + */ +int8_t bmi2_gyro_mems_self_test(const struct bmi2_dev *dev); + +/*! + * @brief This API updates the cross sensitivity coefficient between gyroscope's + * X and Z axes. + * + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_gyro_cross_sense(struct bmi2_dev *dev); + +/*! + * @brief This API gets error bits and message indicating internal status. + * + * @param[in] dev : Structure instance of bmi2_dev. + * @param[out] int_stat : Pointer variable to store error bits and + * message. + * + * Internal status | *int_stat + * ---------------------|--------------------- + * BMI2_NOT_INIT | 0x00 + * BMI2_INIT_OK | 0x01 + * BMI2_INIT_ERR | 0x02 + * BMI2_DRV_ERR | 0x03 + * BMI2_SNS_STOP | 0x04 + * BMI2_NVM_ERROR | 0x05 + * BMI2_START_UP_ERROR | 0x06 + * BMI2_COMPAT_ERROR | 0x07 + * BMI2_VFM_SKIPPED | 0x10 + * BMI2_AXES_MAP_ERROR | 0x20 + * BMI2_ODR_50_HZ_ERROR | 0x40 + * BMI2_ODR_HIGH_ERROR | 0x80 + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + */ +int8_t bmi2_get_internal_status(uint8_t *int_stat, const struct bmi2_dev *dev); + +/*! + * @brief This API performs Fast Offset Compensation for accelerometer. + * + * @param[in] accel_g_value : Accel g value indicates device orientation. + * + * accel_g_value | Description + * --------------------------|---------------------- + * accel_g_value[0] | x axis g units + * accel_g_value[1] | y axis g units + * accel_g_value[2] | z axis g units + * + * @note For FOC, one axis should be parallel to G-vector. + * + * @example If -z-axis of BMI2 is parallel to G-vector, + * then accel_g_value[3] = {0, 0, 1} + * + * If +z-axis of BMI2 is parallel to G-vector, + * then accel_g_value[3] = {0, 0, -1} + * + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_perform_accel_foc(const int16_t accel_g_value[3], struct bmi2_dev *dev); + +/*! + * @brief This API performs Fast Offset Compensation for gyroscope. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success. + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_INVALID_SENSOR - Error: Invalid sensor + * @retval BMI2_E_SET_APS_FAIL - Error: Set Advance Power Save Fail + */ +int8_t bmi2_perform_gyro_foc(struct bmi2_dev *dev); + +/******************************************************************************/ +/*! @name C++ Guard Macros */ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* BMI2_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi260.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi260.c new file mode 100755 index 0000000000000000000000000000000000000000..2038be57fcb8e51714278b6422022f351df86917 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi260.c @@ -0,0 +1,878 @@ +/** + * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of the + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * The information provided is believed to be accurate and reliable. + * The copyright holder assumes no responsibility + * for the consequences of use + * of such information nor for any infringement of patents or + * other rights of third parties which may result from its use. + * No license is granted by implication or otherwise under any patent or + * patent rights of the copyright holder. + * + * @file bmi260.c + * @date 1 September, 2018 + * @version 0.5.0 + * @brief Sensor driver for BMI260 sensor + * + */ + +/***************************************************************************/ +/*! Header files +****************************************************************************/ +#include "bmi260.h" +#include "bmi2.h" + +/***************************************************************************/ +/*! Global Variable +****************************************************************************/ +/*! @name Global array that stores the configuration file of BMI260 */ +const uint8_t bmi260_config_file[] = { + 0x80, 0x2e, 0x3a, 0xb3, 0x80, 0x2e, 0x5a, 0xb3, 0xc8, 0x2e, 0x00, 0x2e, + 0x80, 0x2e, 0x2a, 0xb4, 0x80, 0x2e, 0x54, 0xb4, 0x80, 0x2e, 0x36, 0xb5, + 0x80, 0x2e, 0x3b, 0xb3, 0x80, 0x2e, 0x95, 0xb3, 0x50, 0x32, 0x21, 0x2e, + 0x59, 0xf5, 0x10, 0x30, 0x21, 0x2e, 0x4a, 0xf1, 0x21, 0x2e, 0x6a, 0xf5, + 0x80, 0x2e, 0x42, 0x03, 0x00, 0x00, 0x01, 0x00, 0x22, 0x00, 0x77, 0x00, + 0x00, 0x0c, 0xff, 0x0f, 0xc8, 0x00, 0x82, 0xd8, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0d, 0x00, 0x00, + 0x88, 0x00, 0x05, 0xe0, 0xaa, 0x38, 0x05, 0xe0, 0x90, 0x30, 0x86, 0x00, + 0x30, 0x0a, 0x80, 0x40, 0x10, 0x27, 0xe8, 0x73, 0x04, 0x30, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x30, 0x10, 0x0b, 0x09, 0x08, 0xfa, 0x00, 0x96, 0x00, + 0x4b, 0x09, 0x11, 0x00, 0x11, 0x00, 0x02, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x47, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x9a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x8b, 0x00, + 0x90, 0x00, 0x8f, 0x00, 0x95, 0x00, 0x92, 0x00, 0x98, 0x00, 0x8d, 0x00, + 0xa2, 0x00, 0x75, 0x01, 0x64, 0x01, 0x71, 0x01, 0x60, 0x01, 0x78, 0x00, + 0xb9, 0x00, 0x2d, 0xf5, 0xca, 0xf5, 0x91, 0x00, 0x1e, 0xf2, 0xff, 0x00, + 0x00, 0xff, 0x80, 0x00, 0xa0, 0x00, 0x5f, 0xff, 0xcd, 0x00, 0x00, 0x08, + 0x00, 0xf8, 0x4c, 0x04, 0xe8, 0x03, 0xeb, 0x07, 0xae, 0x07, 0x81, 0x00, + 0x82, 0x00, 0xd7, 0x00, 0xda, 0x00, 0xda, 0x00, 0xe3, 0x00, 0xc0, 0x00, + 0xff, 0x03, 0x00, 0xfc, 0xf0, 0x3f, 0x69, 0xf5, 0x3f, 0xff, 0x19, 0xf4, + 0x58, 0xf5, 0x66, 0xf5, 0x63, 0x01, 0xc0, 0xf1, 0xba, 0xf1, 0x78, 0x01, + 0x74, 0x01, 0xa0, 0x00, 0xf0, 0x00, 0x7b, 0x01, 0xf2, 0x00, 0x7a, 0x01, + 0xff, 0x3f, 0xff, 0xfb, 0x00, 0x38, 0x00, 0x10, 0x00, 0x30, 0x00, 0x20, + 0x8c, 0x01, 0x93, 0x01, 0x95, 0x01, 0x9b, 0x01, 0xa3, 0x01, 0xff, 0x7f, + 0xff, 0x01, 0x6a, 0x01, 0x74, 0xf7, 0x32, 0x01, 0xe6, 0x78, 0x84, 0x00, + 0x9c, 0x6c, 0x07, 0x00, 0x64, 0x75, 0xaa, 0x7e, 0x5f, 0x05, 0xbe, 0x0a, + 0x5f, 0x05, 0x96, 0xe8, 0xef, 0x41, 0x01, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x4a, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xf0, 0x3c, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x50, 0x31, 0x30, + 0x11, 0x42, 0x7b, 0x30, 0x0b, 0x42, 0x02, 0x80, 0x11, 0x30, 0x01, 0x42, + 0x21, 0x33, 0x40, 0x50, 0x01, 0x00, 0xf0, 0x7f, 0x98, 0x2e, 0x19, 0xb3, + 0x05, 0x2e, 0x80, 0x03, 0x01, 0x52, 0xe0, 0x7f, 0xd2, 0x7f, 0x98, 0x2e, + 0x1c, 0xb3, 0xd1, 0x6f, 0x08, 0x0a, 0x1a, 0x25, 0x7c, 0x86, 0xd0, 0x7f, + 0x01, 0x33, 0x12, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xd1, 0x6f, 0x08, 0x0a, + 0x00, 0xb2, 0x0d, 0x2f, 0xe2, 0x6f, 0x01, 0x2e, 0x80, 0x03, 0x51, 0x30, + 0x87, 0x84, 0x23, 0x2e, 0x21, 0xf2, 0x08, 0xbc, 0x80, 0x42, 0x98, 0x2e, + 0x07, 0xb3, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0xc0, 0x6f, 0x0b, 0xb8, + 0x03, 0x2e, 0x1b, 0x00, 0x08, 0x1a, 0xc0, 0x7f, 0x70, 0x30, 0x04, 0x2f, + 0x21, 0x2e, 0x21, 0xf2, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x98, 0x2e, + 0x6d, 0xc0, 0x98, 0x2e, 0x5d, 0xc0, 0x98, 0x2e, 0x65, 0xc4, 0x21, 0x2e, + 0x89, 0x00, 0x03, 0x50, 0x98, 0x2e, 0x46, 0xc3, 0x05, 0x50, 0x98, 0x2e, + 0xfc, 0xc5, 0x07, 0x50, 0x98, 0x2e, 0x46, 0x03, 0x98, 0x2e, 0x1c, 0xb6, + 0x09, 0x50, 0x98, 0x2e, 0xfd, 0x03, 0x0b, 0x50, 0x98, 0x2e, 0x4d, 0x03, + 0x0d, 0x50, 0x98, 0x2e, 0x83, 0xb2, 0x0f, 0x50, 0x98, 0x2e, 0x53, 0xc7, + 0x11, 0x50, 0x98, 0x2e, 0x44, 0xcb, 0x10, 0x30, 0x98, 0x2e, 0xf4, 0xb6, + 0x20, 0x26, 0xf0, 0x6f, 0x03, 0x31, 0x13, 0x42, 0x03, 0x42, 0x21, 0x30, + 0x01, 0x42, 0x0b, 0x32, 0x0b, 0x42, 0x37, 0x80, 0x01, 0x30, 0x01, 0x42, + 0xf0, 0x37, 0x21, 0x52, 0xe2, 0x6f, 0x44, 0x40, 0xe3, 0x0a, 0x43, 0x42, + 0x24, 0x33, 0x07, 0x2e, 0x5e, 0xf7, 0x86, 0x84, 0x4c, 0x00, 0x18, 0x08, + 0x80, 0x42, 0xf1, 0x7f, 0x98, 0x2e, 0x07, 0xb3, 0xf0, 0x6f, 0x81, 0x30, + 0x01, 0x42, 0x01, 0x30, 0x1d, 0x54, 0x03, 0x30, 0x00, 0x2e, 0x00, 0x2e, + 0xc1, 0x86, 0x5a, 0x0e, 0xfa, 0x2f, 0x01, 0x42, 0x10, 0x30, 0x21, 0x2e, + 0x21, 0xf2, 0x00, 0x30, 0x21, 0x2e, 0x69, 0xf5, 0x00, 0x2e, 0x00, 0x2e, + 0xd0, 0x2e, 0x07, 0x2e, 0x8c, 0x00, 0x09, 0x2e, 0x8e, 0x00, 0x01, 0x2e, + 0xa0, 0x00, 0xcf, 0xba, 0x03, 0xbe, 0xbf, 0xb9, 0x05, 0x2e, 0xa0, 0x00, + 0xdd, 0x0a, 0x4f, 0xba, 0xa4, 0xbe, 0xdc, 0x0a, 0x03, 0x2e, 0xa0, 0x00, + 0x5f, 0xba, 0x92, 0xbe, 0xdc, 0x0a, 0x01, 0x2e, 0x96, 0x00, 0x5f, 0xba, + 0x05, 0x2e, 0x98, 0x00, 0x83, 0xbe, 0x03, 0x2e, 0x90, 0x00, 0x1c, 0x0b, + 0xdf, 0xba, 0x2f, 0xbd, 0x01, 0x2e, 0x9f, 0x00, 0x65, 0x0b, 0x2f, 0xb9, + 0x9f, 0xbc, 0x07, 0x2e, 0x8f, 0x00, 0x9f, 0xb8, 0x0f, 0xbc, 0xaa, 0x0a, + 0x0f, 0xb8, 0x51, 0x0a, 0x09, 0x2e, 0x93, 0x00, 0xbf, 0xbd, 0x08, 0x0a, + 0xbf, 0xb9, 0x4f, 0xba, 0x5c, 0x0a, 0x21, 0x2e, 0x7c, 0x00, 0x23, 0x2e, + 0x7d, 0x00, 0x98, 0x2e, 0xd2, 0xb6, 0x03, 0x2e, 0x78, 0x01, 0x21, 0x2e, + 0x7e, 0x00, 0x40, 0x90, 0x03, 0x2f, 0x01, 0x2e, 0x63, 0x01, 0x00, 0xb2, + 0x03, 0x2f, 0x98, 0x2e, 0xa8, 0xcf, 0x21, 0x2e, 0x7f, 0x00, 0x01, 0x2e, + 0xeb, 0x00, 0x00, 0xb2, 0x04, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0xeb, 0x00, + 0x98, 0x2e, 0x16, 0xb0, 0x01, 0x2e, 0x78, 0x01, 0x00, 0xb2, 0x18, 0x2f, + 0x01, 0x2e, 0x7d, 0x00, 0x00, 0xb2, 0x14, 0x2f, 0x00, 0x30, 0x21, 0x2e, + 0x78, 0x01, 0x05, 0x2e, 0x8a, 0x00, 0x13, 0x52, 0x98, 0x2e, 0xc7, 0xc1, + 0x21, 0x2e, 0x7b, 0x00, 0x13, 0x50, 0x98, 0x2e, 0x2d, 0xb0, 0x13, 0x52, + 0x98, 0x2e, 0x82, 0xb1, 0x11, 0x30, 0x21, 0x2e, 0x1a, 0x00, 0x23, 0x2e, + 0xc8, 0x00, 0x01, 0x2e, 0x74, 0x01, 0x00, 0xb2, 0x0a, 0x2f, 0x01, 0x2e, + 0x7e, 0x00, 0x00, 0xb2, 0x06, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x74, 0x01, + 0x15, 0x50, 0x17, 0x52, 0x98, 0x2e, 0x07, 0xcc, 0x01, 0x2e, 0x63, 0x01, + 0x00, 0xb2, 0x5d, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x63, 0x01, 0x05, 0x2e, + 0x8a, 0x00, 0x19, 0x52, 0x98, 0x2e, 0xc7, 0xc1, 0x03, 0x2e, 0x6f, 0x01, + 0x21, 0x2e, 0x7b, 0x00, 0x40, 0xb2, 0x09, 0x2f, 0x01, 0x2e, 0x7e, 0x00, + 0x00, 0xb2, 0x05, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x6f, 0x01, 0x19, 0x50, + 0x98, 0x2e, 0x6e, 0xb6, 0x01, 0x2e, 0x7c, 0x00, 0x00, 0xb2, 0x41, 0x2f, + 0x19, 0x54, 0x98, 0x2e, 0x45, 0xb5, 0x1b, 0x54, 0x00, 0x2e, 0x90, 0x42, + 0x81, 0x42, 0x00, 0x2e, 0x19, 0x50, 0x98, 0x2e, 0x1f, 0xb6, 0x19, 0x50, + 0x98, 0x2e, 0x4d, 0xc3, 0x19, 0x50, 0x98, 0x2e, 0x5a, 0xc7, 0x19, 0x50, + 0x98, 0x2e, 0x30, 0xb2, 0x23, 0x54, 0x19, 0x52, 0xa0, 0x40, 0x82, 0x40, + 0x01, 0xbc, 0x2e, 0xbd, 0x0c, 0xb8, 0x2f, 0xb9, 0xf2, 0x7f, 0xe0, 0x7f, + 0x98, 0x2e, 0xff, 0xc5, 0xf1, 0x6f, 0x40, 0x90, 0x01, 0x30, 0xb3, 0x3f, + 0x12, 0x30, 0x10, 0x2f, 0xc3, 0x08, 0x27, 0x2e, 0x58, 0x03, 0x23, 0x2e, + 0x5a, 0x03, 0x09, 0x2e, 0xc9, 0x00, 0x01, 0x91, 0xd3, 0x7f, 0x05, 0x2f, + 0x58, 0x1a, 0x51, 0x22, 0xe0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xd3, 0x6f, + 0x03, 0x25, 0x21, 0x2e, 0x7a, 0x00, 0xf1, 0x6f, 0x23, 0x2e, 0xc9, 0x00, + 0x19, 0x50, 0x98, 0x2e, 0x8a, 0xb2, 0x10, 0x30, 0x21, 0x2e, 0xc8, 0x00, + 0x01, 0x2e, 0xe8, 0x00, 0x00, 0xb2, 0x0d, 0x2f, 0x01, 0x2e, 0xe8, 0x00, + 0x01, 0x31, 0x01, 0x08, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x47, 0xcb, + 0x10, 0x30, 0x21, 0x2e, 0xc8, 0x00, 0x00, 0x30, 0x21, 0x2e, 0xe8, 0x00, + 0x01, 0x2e, 0xc8, 0x00, 0x00, 0xb2, 0x90, 0x2e, 0x41, 0x02, 0x98, 0x2e, + 0x91, 0x03, 0x00, 0x30, 0x21, 0x2e, 0xc8, 0x00, 0x80, 0x2e, 0x41, 0x02, + 0x1a, 0x24, 0x22, 0x00, 0x80, 0x2e, 0xb4, 0x01, 0xc0, 0x2e, 0x21, 0x2e, + 0xf8, 0x00, 0x00, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0xca, 0x00, 0xc0, 0x2e, + 0x21, 0x2e, 0xfa, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01, 0x34, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x19, 0xb3, 0x1b, 0x54, + 0x29, 0x56, 0x91, 0x40, 0x11, 0x42, 0xcb, 0x08, 0x82, 0x40, 0x12, 0x42, + 0x38, 0xb9, 0x07, 0x2e, 0xee, 0x00, 0x13, 0x42, 0xe2, 0x7f, 0x00, 0x2e, + 0x05, 0x2e, 0x7a, 0x00, 0x27, 0x56, 0x12, 0x42, 0x4b, 0x08, 0x05, 0x2e, + 0x1a, 0x00, 0x12, 0x42, 0xd0, 0x7f, 0xc1, 0x7f, 0x98, 0x2e, 0xf5, 0xcb, + 0xd2, 0x6f, 0xf3, 0x37, 0xc4, 0x6f, 0xe5, 0x6f, 0x90, 0x42, 0x01, 0x32, + 0x01, 0x2e, 0x5e, 0xf7, 0x03, 0x08, 0x80, 0x42, 0xf0, 0x3d, 0x25, 0x54, + 0x07, 0x2e, 0xee, 0x00, 0x94, 0x42, 0x95, 0x42, 0xb3, 0xbd, 0x09, 0x2e, + 0x7a, 0x00, 0xe3, 0x0a, 0x09, 0x2e, 0x7b, 0x00, 0x93, 0x42, 0xe2, 0x7f, + 0x00, 0x91, 0x82, 0x40, 0x10, 0x08, 0x51, 0x0a, 0x48, 0x22, 0x01, 0x2e, + 0x7f, 0x00, 0x00, 0x90, 0x06, 0xbd, 0xf3, 0x33, 0x4b, 0x08, 0x0a, 0x0a, + 0x01, 0x22, 0xd0, 0x7f, 0x98, 0x2e, 0x07, 0xb3, 0xe0, 0x6f, 0xd1, 0x6f, + 0xfb, 0x6f, 0xc0, 0x5f, 0x01, 0x42, 0x80, 0x2e, 0x87, 0xcf, 0x01, 0x2e, + 0xfd, 0xf5, 0x0d, 0xbc, 0x0f, 0xb8, 0x00, 0x90, 0x10, 0x30, 0x07, 0x2f, + 0x03, 0x2e, 0xfc, 0xf5, 0x98, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x01, 0x2f, + 0x00, 0x30, 0xb8, 0x2e, 0xb8, 0x2e, 0x01, 0x30, 0x11, 0x42, 0x23, 0x2e, + 0xcb, 0x00, 0x33, 0x54, 0x12, 0x42, 0x23, 0x2e, 0xcc, 0x00, 0x35, 0x54, + 0x12, 0x42, 0x11, 0x42, 0x11, 0x42, 0x11, 0x42, 0x11, 0x42, 0x01, 0x42, + 0xb8, 0x2e, 0xc0, 0x2e, 0x21, 0x2e, 0xfb, 0x00, 0x01, 0x2e, 0xfc, 0xf5, + 0x09, 0xbc, 0x0f, 0xb8, 0x00, 0x90, 0x10, 0x30, 0x0d, 0x2f, 0x03, 0x2e, + 0xfd, 0xf5, 0x9e, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, 0x05, 0x2f, 0x03, 0x2e, + 0xc2, 0xf5, 0x98, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x01, 0x2f, 0x00, 0x30, + 0xb8, 0x2e, 0xb8, 0x2e, 0x01, 0x2e, 0xc0, 0xf8, 0x2b, 0x54, 0x03, 0x2e, + 0xfc, 0xf5, 0x2d, 0x56, 0x82, 0x08, 0xcb, 0x0a, 0x2f, 0x58, 0x80, 0x90, + 0x4c, 0x08, 0x59, 0x22, 0x03, 0x34, 0xc3, 0x08, 0xf2, 0x3a, 0x0a, 0x08, + 0x02, 0x35, 0xc0, 0x90, 0x4a, 0x0a, 0x08, 0x22, 0xc0, 0x2e, 0x21, 0x2e, + 0xfc, 0xf5, 0x05, 0x2e, 0xf8, 0x00, 0x81, 0x40, 0x82, 0x40, 0x9f, 0xbc, + 0x27, 0xbd, 0x20, 0x50, 0x9f, 0xb8, 0x2c, 0xb9, 0x40, 0xb2, 0xf2, 0x7f, + 0xeb, 0x7f, 0x2d, 0x2f, 0x30, 0x25, 0x01, 0x2e, 0xca, 0x00, 0x00, 0x90, + 0x07, 0x2f, 0x31, 0x50, 0x98, 0x2e, 0xed, 0x03, 0x01, 0x2e, 0xca, 0x00, + 0x01, 0x80, 0x21, 0x2e, 0xca, 0x00, 0x01, 0x2e, 0xf8, 0x00, 0x00, 0x40, + 0x0c, 0xbc, 0x0d, 0xb8, 0x21, 0x2e, 0xf9, 0x00, 0x31, 0x52, 0x23, 0x25, + 0x98, 0x2e, 0x9e, 0xb0, 0x10, 0x25, 0x01, 0x2e, 0xf8, 0x00, 0x00, 0x40, + 0x0b, 0xbc, 0x0f, 0xb8, 0x00, 0x90, 0x06, 0x2f, 0xeb, 0x6f, 0xf0, 0x6f, + 0x12, 0x30, 0xe0, 0x5f, 0x4a, 0x08, 0x80, 0x2e, 0x95, 0xcf, 0xeb, 0x6f, + 0xf0, 0x6f, 0x22, 0x30, 0xe0, 0x5f, 0x4a, 0x08, 0x80, 0x2e, 0x95, 0xcf, + 0xf0, 0x6f, 0x01, 0x30, 0x98, 0x2e, 0x95, 0xcf, 0x00, 0x30, 0x21, 0x2e, + 0xca, 0x00, 0xeb, 0x6f, 0xe0, 0x5f, 0xb8, 0x2e, 0x07, 0x86, 0xfc, 0x88, + 0xc6, 0x40, 0x05, 0x41, 0x31, 0x1a, 0x12, 0x2f, 0x80, 0x91, 0x22, 0x2f, + 0x01, 0x35, 0x29, 0x0f, 0x0a, 0x2f, 0x06, 0x80, 0x00, 0x2e, 0x00, 0x40, + 0x00, 0xb2, 0x01, 0x2f, 0x44, 0xa9, 0x03, 0x2f, 0x00, 0x30, 0xc0, 0x42, + 0x00, 0x43, 0xb8, 0x2e, 0xc2, 0x42, 0x01, 0x43, 0xb8, 0x2e, 0x01, 0x35, + 0xa9, 0x0e, 0x0e, 0x2f, 0x03, 0x3b, 0xeb, 0x00, 0xcc, 0xa8, 0x0a, 0x2f, + 0x05, 0x86, 0xc2, 0x80, 0xc3, 0x40, 0x02, 0x42, 0x3c, 0x84, 0xc1, 0x80, + 0x81, 0x42, 0x82, 0x84, 0xc0, 0x2e, 0x80, 0x42, 0x00, 0x2e, 0xb8, 0x2e, + 0xb0, 0x50, 0x82, 0x84, 0x07, 0x2e, 0xcc, 0x00, 0x84, 0x40, 0x23, 0x05, + 0x2d, 0x5a, 0x07, 0x2e, 0xf9, 0x00, 0x1d, 0x18, 0x46, 0x80, 0xf0, 0x7f, + 0x44, 0x80, 0xe0, 0x7f, 0x43, 0x80, 0x03, 0x86, 0x0b, 0x2e, 0xcb, 0x00, + 0x29, 0x2e, 0xcb, 0x00, 0x25, 0x05, 0xc5, 0x40, 0x40, 0xb3, 0x37, 0x5e, + 0xb7, 0x01, 0xdb, 0x7f, 0xc5, 0x7f, 0xfb, 0x8e, 0x8b, 0x40, 0x02, 0x40, + 0x39, 0x5a, 0x81, 0x84, 0xb6, 0x7f, 0x37, 0x2e, 0xcc, 0x00, 0x70, 0x7f, + 0x87, 0x7f, 0x94, 0x7f, 0xa1, 0x7f, 0x02, 0x42, 0x75, 0x01, 0x05, 0x2f, + 0xe2, 0x6f, 0x00, 0x2e, 0x86, 0x40, 0x81, 0x8d, 0x86, 0x42, 0x00, 0x2e, + 0xe2, 0x41, 0x22, 0x0f, 0x47, 0x84, 0x67, 0x7f, 0x42, 0x82, 0xcb, 0x41, + 0x45, 0x2f, 0x46, 0x40, 0x26, 0x0e, 0x35, 0x2f, 0x01, 0x40, 0x00, 0x35, + 0x88, 0x0e, 0x0b, 0x30, 0x02, 0x2f, 0x80, 0x40, 0x00, 0xb2, 0x27, 0x2f, + 0xc0, 0x35, 0x88, 0x0e, 0x5b, 0x7f, 0x42, 0x2f, 0xa1, 0x6f, 0x45, 0x86, + 0x01, 0x30, 0xc0, 0x40, 0x3f, 0x80, 0x03, 0xa2, 0x02, 0x2f, 0x00, 0x2e, + 0x0d, 0x2c, 0x00, 0x30, 0xc0, 0x6f, 0x00, 0xb2, 0xf2, 0x6f, 0x10, 0x30, + 0x01, 0x2f, 0x81, 0x42, 0x02, 0x2d, 0x80, 0x42, 0x20, 0x30, 0xe2, 0x6f, + 0x00, 0x2e, 0x81, 0x42, 0x02, 0xb2, 0x04, 0x2f, 0x01, 0xb2, 0x02, 0x2f, + 0xf2, 0x6f, 0x30, 0x30, 0x81, 0x42, 0xfe, 0x84, 0xc1, 0x42, 0x81, 0x42, + 0x84, 0x88, 0x50, 0x7f, 0x20, 0x2c, 0x01, 0x43, 0xcb, 0x42, 0x5b, 0x7f, + 0x00, 0x35, 0x71, 0x6f, 0x1a, 0x2c, 0x40, 0x42, 0x0b, 0x25, 0x05, 0x04, + 0x93, 0x6f, 0x18, 0x1e, 0x40, 0x42, 0x11, 0x30, 0xa0, 0x6f, 0x22, 0x30, + 0x98, 0x2e, 0x72, 0xb0, 0x01, 0x30, 0x0d, 0x2c, 0x51, 0x7f, 0x1b, 0x25, + 0xa0, 0x6f, 0x4d, 0x00, 0x01, 0x86, 0x61, 0x1c, 0xc1, 0x42, 0x21, 0x30, + 0x12, 0x30, 0x98, 0x2e, 0x72, 0xb0, 0x01, 0x30, 0x51, 0x7f, 0xb3, 0x30, + 0xc1, 0x41, 0x3b, 0x54, 0x98, 0x2e, 0x0f, 0xca, 0x91, 0x6f, 0xc0, 0x7f, + 0x42, 0x31, 0xb3, 0x30, 0x98, 0x2e, 0x0f, 0xca, 0xc3, 0x6f, 0x62, 0x6f, + 0x18, 0x00, 0x81, 0x6f, 0x80, 0x42, 0xc0, 0x7f, 0xb3, 0x30, 0x41, 0x40, + 0x48, 0x04, 0x3d, 0x54, 0x98, 0x2e, 0x0f, 0xca, 0x61, 0x6f, 0xc2, 0x6f, + 0x41, 0x40, 0x90, 0x00, 0xb3, 0x6f, 0xcb, 0x00, 0x80, 0x6f, 0xd3, 0x1e, + 0x13, 0x42, 0xc0, 0x7f, 0x3e, 0x86, 0x00, 0x40, 0x93, 0x7f, 0xa1, 0x7f, + 0x48, 0x04, 0x3d, 0x54, 0xb3, 0x30, 0x98, 0x2e, 0x0f, 0xca, 0x91, 0x6f, + 0xa3, 0x6f, 0x18, 0x04, 0x41, 0x40, 0xb2, 0x6f, 0xca, 0x04, 0xc1, 0x6f, + 0x03, 0x1c, 0x40, 0x42, 0x44, 0x82, 0x00, 0x30, 0x41, 0x40, 0x40, 0xb2, + 0xf1, 0x6f, 0x09, 0x2f, 0xe2, 0x6f, 0x03, 0x35, 0x82, 0x40, 0x93, 0x0e, + 0x04, 0x2f, 0x7e, 0x84, 0x83, 0x86, 0x40, 0x42, 0xc0, 0x42, 0x80, 0x42, + 0x00, 0x2e, 0x51, 0x6f, 0x73, 0x6f, 0x40, 0xb2, 0x02, 0x2f, 0xc4, 0x84, + 0xc0, 0x42, 0x80, 0x42, 0x41, 0xb2, 0x05, 0x2f, 0x42, 0x90, 0x04, 0x2f, + 0xdb, 0x6f, 0xc0, 0x2e, 0x41, 0x50, 0x50, 0x5f, 0x3f, 0x50, 0xdb, 0x6f, + 0x50, 0x5f, 0xb8, 0x2e, 0x00, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0xd5, 0x00, + 0xf0, 0x50, 0x01, 0x2e, 0xfa, 0x00, 0xf0, 0x7f, 0x01, 0x80, 0xe1, 0x7f, + 0x1a, 0x25, 0x02, 0x40, 0x05, 0x40, 0x23, 0xbf, 0x71, 0x88, 0x03, 0x40, + 0x20, 0x25, 0x11, 0x40, 0x6f, 0xbb, 0xd2, 0xbe, 0xdf, 0xba, 0xb1, 0xbd, + 0x06, 0x43, 0x9f, 0xb8, 0x00, 0x40, 0x40, 0xb2, 0xbf, 0xb9, 0x0c, 0xb8, + 0x25, 0x7f, 0x33, 0x7f, 0xdb, 0x7f, 0xc0, 0x7f, 0x01, 0x30, 0x7f, 0x2f, + 0x10, 0x6f, 0x00, 0x90, 0x05, 0x2f, 0x20, 0x6f, 0x00, 0x90, 0x02, 0x2f, + 0x30, 0x6f, 0x00, 0xb2, 0x76, 0x2f, 0x07, 0x2e, 0xd5, 0x00, 0xc0, 0x90, + 0x43, 0x5a, 0x45, 0x50, 0x47, 0x5c, 0x07, 0x2f, 0x45, 0x5e, 0x51, 0x43, + 0xd1, 0x43, 0x6e, 0x0e, 0xfb, 0x2f, 0xc1, 0x86, 0x27, 0x2e, 0xd5, 0x00, + 0x82, 0x40, 0xf3, 0x6f, 0x24, 0xbd, 0xc5, 0x40, 0xd1, 0xbe, 0xc2, 0x86, + 0xd1, 0xba, 0xc3, 0x40, 0xf5, 0x7f, 0xb4, 0xbd, 0x24, 0xb9, 0x6a, 0x05, + 0x34, 0xbb, 0xe3, 0x6f, 0x43, 0x54, 0xb1, 0x7f, 0xa1, 0x7f, 0xe6, 0x7f, + 0x95, 0x7f, 0x00, 0x2e, 0x15, 0x41, 0x40, 0xb3, 0x43, 0x2f, 0x61, 0x7f, + 0x74, 0x7f, 0x50, 0x7f, 0x42, 0x7f, 0x83, 0x7f, 0x00, 0x2e, 0xc1, 0x40, + 0x98, 0x2e, 0x74, 0xc0, 0x83, 0x6f, 0x42, 0x6f, 0xc1, 0x40, 0x40, 0xa0, + 0x11, 0x30, 0x05, 0x30, 0x84, 0x40, 0x4d, 0x23, 0x00, 0x91, 0x02, 0x2f, + 0xf6, 0x6f, 0x46, 0x0f, 0x27, 0x2f, 0x96, 0x6f, 0xc6, 0x0e, 0x50, 0x6f, + 0x00, 0x2e, 0x06, 0x40, 0x01, 0x2f, 0x35, 0x1a, 0x02, 0x2f, 0x01, 0x30, + 0x21, 0x2c, 0x81, 0x42, 0x61, 0x28, 0xe4, 0x6f, 0x81, 0x42, 0xcc, 0x0e, + 0x1a, 0x2f, 0xb1, 0x6f, 0x40, 0x90, 0x17, 0x2f, 0x67, 0x6f, 0x11, 0x30, + 0x0f, 0x15, 0xe3, 0xbe, 0xb4, 0x7f, 0x2c, 0x0b, 0x43, 0x5a, 0xaf, 0x01, + 0x47, 0x5e, 0x0b, 0x30, 0x2e, 0x1a, 0x00, 0x2f, 0x4b, 0x43, 0x41, 0x8b, + 0x29, 0x2e, 0xd6, 0x00, 0x6f, 0x0e, 0xf7, 0x2f, 0x00, 0x2e, 0x04, 0x2c, + 0xa1, 0x7f, 0x50, 0x6f, 0x81, 0x42, 0x05, 0x42, 0x00, 0x2e, 0x74, 0x6f, + 0x61, 0x6f, 0x41, 0x82, 0xc1, 0x86, 0x81, 0x84, 0x01, 0x80, 0x43, 0xa2, + 0xb2, 0x2f, 0xc0, 0x6f, 0xa1, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x01, 0x2e, + 0xd6, 0x00, 0x09, 0x2d, 0x23, 0x2e, 0xd5, 0x00, 0x23, 0x2e, 0xd6, 0x00, + 0xc0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x01, 0x2e, 0xd6, 0x00, 0xdb, 0x6f, + 0x10, 0x5f, 0xb8, 0x2e, 0x00, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0xdd, 0x00, + 0x03, 0x2e, 0xfb, 0x00, 0x41, 0x88, 0x24, 0x25, 0x13, 0x41, 0x50, 0x50, + 0x04, 0x41, 0xb3, 0xbd, 0xbf, 0xb9, 0x4c, 0xba, 0xfb, 0x7f, 0xc0, 0xb2, + 0xe4, 0x7f, 0x0b, 0x30, 0x39, 0x2f, 0x07, 0x2e, 0xdd, 0x00, 0xc0, 0x90, + 0x04, 0x2f, 0xc1, 0x86, 0x27, 0x2e, 0xdd, 0x00, 0x37, 0x2e, 0xde, 0x00, + 0x83, 0x40, 0x42, 0x40, 0x42, 0x82, 0xb4, 0xbd, 0x41, 0x40, 0x94, 0xbc, + 0x21, 0xbd, 0x94, 0xb8, 0xb4, 0xb9, 0x21, 0xb9, 0xd1, 0x7f, 0xc2, 0x7f, + 0xb3, 0x7f, 0x10, 0x25, 0x98, 0x2e, 0xb3, 0xc0, 0xb1, 0x6f, 0xc2, 0x6f, + 0x51, 0x28, 0x41, 0x0f, 0x11, 0x30, 0x0d, 0x2f, 0xc2, 0x0e, 0x07, 0x2e, + 0xde, 0x00, 0x19, 0x28, 0x04, 0x2f, 0xc0, 0xa6, 0x04, 0x2f, 0x21, 0x2e, + 0xde, 0x00, 0x02, 0x2d, 0x21, 0x2e, 0xde, 0x00, 0x04, 0x2c, 0x02, 0x30, + 0x02, 0x30, 0x25, 0x2e, 0xde, 0x00, 0xd0, 0x6f, 0x07, 0x2e, 0xde, 0x00, + 0x58, 0x0f, 0xfb, 0x6f, 0xe0, 0x6f, 0xb0, 0x5f, 0x4a, 0x22, 0x80, 0x2e, + 0x95, 0xcf, 0xe0, 0x6f, 0x01, 0x30, 0x98, 0x2e, 0x95, 0xcf, 0x00, 0x30, + 0x21, 0x2e, 0xdd, 0x00, 0xfb, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0xc0, 0x2e, + 0x21, 0x2e, 0xfc, 0x00, 0x00, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0xdf, 0x00, + 0x05, 0x2e, 0xfc, 0x00, 0x83, 0x40, 0x81, 0x40, 0xa0, 0x50, 0xbf, 0xbd, + 0x93, 0xbc, 0xbf, 0xb9, 0x9c, 0xb8, 0xfb, 0x7f, 0xe1, 0x7f, 0xd0, 0x7f, + 0xc0, 0xb2, 0x0b, 0x30, 0x64, 0x2f, 0x07, 0x2e, 0xdf, 0x00, 0x49, 0x52, + 0xc0, 0x90, 0x0b, 0x2f, 0x5b, 0x42, 0x5b, 0x42, 0xc1, 0x86, 0x27, 0x2e, + 0xdf, 0x00, 0x37, 0x2e, 0xe0, 0x00, 0x37, 0x2e, 0xe1, 0x00, 0x37, 0x2e, + 0xe2, 0x00, 0x4b, 0x42, 0x60, 0x7f, 0x00, 0x2e, 0x84, 0x40, 0x93, 0x40, + 0xc9, 0xbe, 0x81, 0x40, 0x82, 0x40, 0x37, 0xbe, 0xaa, 0xbd, 0x4e, 0xb9, + 0x92, 0xbc, 0x18, 0xba, 0xda, 0xba, 0xba, 0xb9, 0x1a, 0x25, 0x17, 0x2e, + 0xe0, 0x00, 0x76, 0x82, 0x75, 0x7f, 0x9b, 0x7f, 0x83, 0x7f, 0xc4, 0x7f, + 0xb2, 0x7f, 0x98, 0x2e, 0xd1, 0xc3, 0x03, 0x2e, 0xe0, 0x00, 0x08, 0x1a, + 0xa0, 0x7f, 0x00, 0x30, 0x01, 0x2f, 0x21, 0x2e, 0xe2, 0x00, 0x03, 0x2e, + 0xe2, 0x00, 0xc0, 0x6f, 0x48, 0x0e, 0x14, 0x2f, 0xb1, 0x6f, 0x40, 0xb2, + 0x0b, 0x2f, 0x43, 0xb2, 0x09, 0x2f, 0xd2, 0x6f, 0x49, 0x56, 0x98, 0x2e, + 0x0b, 0xc4, 0x00, 0x90, 0x06, 0x2f, 0xa0, 0x6f, 0x21, 0x2e, 0xe1, 0x00, + 0x03, 0x2d, 0xa0, 0x6f, 0x21, 0x2e, 0xe1, 0x00, 0xc0, 0x6f, 0x21, 0x2e, + 0xe2, 0x00, 0x01, 0x2e, 0xe2, 0x00, 0x01, 0x80, 0x21, 0x2e, 0xe2, 0x00, + 0xd1, 0x6f, 0x49, 0x50, 0x52, 0x40, 0x12, 0x42, 0x00, 0x2e, 0x52, 0x40, + 0x12, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x01, 0x42, 0x00, 0x2e, 0x03, 0x2e, + 0xe1, 0x00, 0xe0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xa0, 0x6f, 0x21, 0x2e, + 0xe0, 0x00, 0x06, 0x2d, 0x37, 0x2e, 0xdf, 0x00, 0x01, 0x30, 0xe0, 0x6f, + 0x98, 0x2e, 0x95, 0xcf, 0xfb, 0x6f, 0x60, 0x5f, 0xb8, 0x2e, 0x03, 0x2e, + 0xe6, 0x00, 0x2b, 0x50, 0x08, 0x1a, 0x05, 0x2f, 0x21, 0x2e, 0xe6, 0x00, + 0x31, 0x30, 0xc0, 0x2e, 0x23, 0x2e, 0x2d, 0xf5, 0x20, 0x30, 0x21, 0x2e, + 0x2d, 0xf5, 0x4b, 0x52, 0xc0, 0x2e, 0x23, 0x2e, 0xe6, 0x00, 0xc0, 0x2e, + 0x01, 0x2e, 0xe6, 0x00, 0x40, 0x50, 0xf1, 0x7f, 0x0a, 0x25, 0x3c, 0x86, + 0xeb, 0x7f, 0x41, 0x33, 0x22, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xf4, 0x30, + 0xd3, 0x6f, 0xdc, 0x09, 0x4f, 0x58, 0xc2, 0x6f, 0x94, 0x09, 0x4d, 0x5a, + 0x95, 0x08, 0x51, 0x58, 0xf1, 0x6f, 0xf6, 0xbf, 0x6a, 0xbb, 0x77, 0x0b, + 0x52, 0x42, 0xdc, 0x08, 0xeb, 0x6f, 0x55, 0x42, 0xb4, 0xb9, 0xc0, 0x2e, + 0x43, 0x42, 0xc0, 0x5f, 0xc8, 0x2e, 0x20, 0x50, 0xf6, 0x7f, 0xe7, 0x7f, + 0x00, 0x2e, 0x53, 0x5c, 0x00, 0x2e, 0x87, 0x41, 0xff, 0xbf, 0xff, 0xbb, + 0xc0, 0x91, 0x02, 0x2f, 0x37, 0x30, 0x2f, 0x2e, 0x69, 0xf5, 0x0f, 0x2e, + 0xa4, 0xf1, 0xfd, 0xbf, 0xff, 0xbb, 0xb7, 0x8d, 0xc0, 0xb3, 0x02, 0x2f, + 0x17, 0x30, 0x2f, 0x2e, 0xe7, 0x00, 0x47, 0x30, 0x87, 0x43, 0x00, 0x2e, + 0xf6, 0x6f, 0xe7, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e, 0xd0, 0x50, 0x81, 0x7f, + 0x90, 0x7f, 0xd7, 0x7f, 0xc5, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0xe4, 0x7f, + 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x53, 0x52, 0x00, 0x2e, 0x40, 0x40, + 0x0f, 0xbc, 0x0f, 0xb8, 0x00, 0x90, 0x02, 0x2f, 0x30, 0x30, 0x21, 0x2e, + 0x69, 0xf5, 0x78, 0x80, 0x60, 0x7f, 0x21, 0x30, 0x00, 0x40, 0x21, 0x2e, + 0xe8, 0x00, 0x01, 0x2e, 0xe8, 0x00, 0x41, 0x08, 0x40, 0xb2, 0x0b, 0x2f, + 0x01, 0x50, 0x1a, 0x25, 0x12, 0x40, 0x32, 0x7f, 0x73, 0x82, 0x12, 0x40, + 0x42, 0x7f, 0x00, 0x2e, 0x00, 0x40, 0x50, 0x7f, 0x98, 0x2e, 0x6a, 0xd6, + 0x61, 0x6f, 0xe0, 0x31, 0x40, 0x42, 0x00, 0x2e, 0xf6, 0x6f, 0xe4, 0x6f, + 0x81, 0x6f, 0x90, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc5, 0x6f, 0xd7, 0x6f, + 0x7b, 0x6f, 0x30, 0x5f, 0xc8, 0x2e, 0xa0, 0x50, 0x80, 0x7f, 0x91, 0x7f, + 0xd7, 0x7f, 0xc5, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0xe4, 0x7f, 0xf6, 0x7f, + 0x7b, 0x7f, 0x00, 0x2e, 0x53, 0x50, 0x00, 0x2e, 0x01, 0x40, 0x9f, 0xbc, + 0x9f, 0xb8, 0x40, 0x90, 0x02, 0x2f, 0x31, 0x30, 0x23, 0x2e, 0x69, 0xf5, + 0x37, 0x80, 0x60, 0x7f, 0x98, 0x2e, 0xdd, 0x03, 0x00, 0xb2, 0x6a, 0x2f, + 0x01, 0x2e, 0xc1, 0xf5, 0x0e, 0xbc, 0x0e, 0xb8, 0x03, 0x2e, 0x7e, 0x00, + 0x32, 0x30, 0x10, 0x04, 0x41, 0xb2, 0x03, 0x2f, 0x03, 0x2e, 0x7c, 0x00, + 0x41, 0x90, 0x15, 0x2f, 0x57, 0x52, 0x19, 0x54, 0x5d, 0x56, 0x65, 0x40, + 0x44, 0x40, 0xd8, 0xbe, 0x2c, 0x0b, 0x20, 0x11, 0x94, 0x42, 0x43, 0x82, + 0x53, 0x0e, 0xf6, 0x2f, 0x01, 0x2e, 0xe9, 0x00, 0x00, 0xb2, 0x10, 0x30, + 0x02, 0x2f, 0x21, 0x2e, 0x63, 0x01, 0x02, 0x2d, 0x21, 0x2e, 0xe9, 0x00, + 0x98, 0x2e, 0x00, 0xb0, 0x00, 0xb2, 0x20, 0x30, 0x22, 0x30, 0x03, 0x2f, + 0x03, 0x2e, 0x7e, 0x00, 0x40, 0x90, 0x05, 0x2f, 0x03, 0x2e, 0x7d, 0x00, + 0x41, 0xb2, 0x31, 0x30, 0x02, 0x30, 0x8a, 0x22, 0x03, 0x2e, 0x70, 0x01, + 0x11, 0x1a, 0x0e, 0x2f, 0x25, 0x2e, 0x70, 0x01, 0x33, 0x30, 0x59, 0x52, + 0x13, 0x09, 0x42, 0x40, 0x55, 0x56, 0x46, 0xbe, 0x93, 0x08, 0x94, 0x0a, + 0x42, 0x42, 0x4a, 0x82, 0x2b, 0x54, 0x42, 0x42, 0x00, 0x2e, 0x03, 0x2e, + 0x7c, 0x00, 0x40, 0xb2, 0x1f, 0x2f, 0x05, 0x2e, 0xc0, 0xf5, 0xf1, 0x30, + 0x91, 0x08, 0x87, 0xaa, 0x74, 0x30, 0x07, 0x2e, 0xea, 0x00, 0xa2, 0x22, + 0x53, 0x1a, 0x05, 0x2f, 0x07, 0x2e, 0x66, 0xf5, 0xbf, 0xbd, 0xbf, 0xb9, + 0xc0, 0x90, 0x0b, 0x2f, 0x5b, 0x56, 0x04, 0x30, 0xd4, 0x42, 0xd0, 0x42, + 0x0a, 0x04, 0x04, 0xbc, 0xfe, 0x82, 0x01, 0x80, 0xc4, 0x42, 0x25, 0x2e, + 0xea, 0x00, 0x40, 0x42, 0x00, 0x32, 0x21, 0x2e, 0x62, 0xf5, 0x60, 0x6f, + 0x01, 0x31, 0x01, 0x42, 0x00, 0x2e, 0xf6, 0x6f, 0xe4, 0x6f, 0x80, 0x6f, + 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc5, 0x6f, 0xd7, 0x6f, 0x7b, 0x6f, + 0x60, 0x5f, 0xc8, 0x2e, 0x50, 0x50, 0xd3, 0x7f, 0xe4, 0x7f, 0xf6, 0x7f, + 0xc5, 0x7f, 0xb7, 0x7f, 0x00, 0x2e, 0x53, 0x56, 0x00, 0x2e, 0xc4, 0x40, + 0x4f, 0xbe, 0x4f, 0xba, 0x00, 0x91, 0x02, 0x2f, 0x34, 0x30, 0x29, 0x2e, + 0x69, 0xf5, 0xf8, 0x8c, 0x2d, 0x56, 0x04, 0x32, 0x15, 0x30, 0x0a, 0x2c, + 0x86, 0x41, 0xb4, 0x09, 0x80, 0xb3, 0x03, 0x2f, 0x2b, 0x2e, 0xeb, 0x00, + 0x29, 0x2e, 0x61, 0xf5, 0x0d, 0x2e, 0x61, 0xf5, 0xf3, 0x09, 0xc0, 0x91, + 0xf3, 0x2f, 0xf6, 0x6f, 0xe4, 0x6f, 0xd3, 0x6f, 0xc5, 0x6f, 0xb7, 0x6f, + 0xb0, 0x5f, 0xc8, 0x2e, 0xc0, 0x50, 0x80, 0x7f, 0x91, 0x7f, 0xd5, 0x7f, + 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0xe7, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, + 0x00, 0x2e, 0x53, 0x50, 0x00, 0x2e, 0x01, 0x40, 0x9f, 0xbc, 0x9f, 0xb8, + 0x40, 0x90, 0x02, 0x2f, 0x31, 0x30, 0x23, 0x2e, 0x69, 0xf5, 0x37, 0x80, + 0x00, 0x2e, 0x00, 0x40, 0x60, 0x7f, 0x98, 0x2e, 0xdd, 0x03, 0x63, 0x6f, + 0x01, 0x30, 0x61, 0x7f, 0x50, 0x7f, 0x01, 0x32, 0x2b, 0x54, 0x80, 0x2e, + 0x23, 0xb5, 0x19, 0x09, 0x00, 0xb3, 0x1d, 0x2f, 0x00, 0xb2, 0x03, 0x2f, + 0x09, 0x2e, 0x7c, 0x00, 0x00, 0x91, 0x08, 0x2f, 0x43, 0x7f, 0x98, 0x2e, + 0x62, 0xb6, 0x01, 0x32, 0x23, 0x2e, 0x64, 0xf5, 0x43, 0x6f, 0x50, 0x6f, + 0x2b, 0x54, 0x00, 0xb2, 0x07, 0x2f, 0x09, 0x2e, 0x7c, 0x00, 0x00, 0x91, + 0x06, 0x2f, 0x09, 0x2e, 0x7e, 0x00, 0x00, 0x91, 0x02, 0x2f, 0x04, 0x30, + 0x29, 0x2e, 0xe9, 0x00, 0x23, 0x2e, 0x60, 0xf5, 0xda, 0x08, 0xc0, 0xb2, + 0x90, 0x2e, 0x21, 0xb5, 0x98, 0x2e, 0x00, 0xb0, 0x00, 0xb2, 0x06, 0x2f, + 0x01, 0x2e, 0x7e, 0x00, 0x00, 0xb2, 0x02, 0x2f, 0x50, 0x6f, 0x00, 0x90, + 0x11, 0x2f, 0x01, 0x2e, 0xed, 0x00, 0x00, 0x90, 0x26, 0x2f, 0x10, 0x30, + 0x21, 0x2e, 0xed, 0x00, 0x00, 0x30, 0x98, 0x2e, 0xf4, 0xb6, 0x01, 0x2e, + 0x7c, 0x00, 0x00, 0x90, 0x1c, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0xe9, 0x00, + 0x19, 0x2d, 0x01, 0x2e, 0xc3, 0xf5, 0x0c, 0xbc, 0x8f, 0xb8, 0x10, 0x30, + 0x41, 0x04, 0x43, 0xb0, 0x5f, 0x52, 0x17, 0x54, 0x65, 0x56, 0x65, 0x40, + 0x44, 0x40, 0xd8, 0xbe, 0x2c, 0x0b, 0x26, 0x11, 0x94, 0x42, 0x43, 0x82, + 0x53, 0x0e, 0xf6, 0x2f, 0x21, 0x2e, 0x74, 0x01, 0x01, 0x30, 0x60, 0x7f, + 0x23, 0x2e, 0xed, 0x00, 0x50, 0x6f, 0x00, 0x90, 0x05, 0x2f, 0x01, 0x30, + 0x23, 0x2e, 0x79, 0x01, 0x23, 0x2e, 0xe9, 0x00, 0x39, 0x2d, 0x03, 0x2e, + 0x7d, 0x00, 0x40, 0x90, 0x0c, 0x2f, 0x03, 0x2e, 0xec, 0x00, 0x40, 0x90, + 0x30, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0xec, 0x00, 0x98, 0x2e, 0x49, 0x03, + 0x98, 0x2e, 0x7e, 0xb1, 0x29, 0x2c, 0x50, 0x6f, 0x03, 0x2e, 0x79, 0x01, + 0x41, 0x84, 0x25, 0x2e, 0x79, 0x01, 0x11, 0x30, 0x91, 0x08, 0x80, 0xb2, + 0x05, 0x2f, 0x05, 0x2e, 0x58, 0xf5, 0x28, 0xbd, 0x2e, 0xb9, 0x83, 0x90, + 0x16, 0x2f, 0x05, 0x2e, 0xc1, 0xf5, 0x2e, 0xbd, 0xae, 0xb9, 0x34, 0x30, + 0xe3, 0x04, 0x61, 0x54, 0x13, 0x58, 0x63, 0x5a, 0xa6, 0x40, 0x87, 0x40, + 0x68, 0xbf, 0xf7, 0x0b, 0xfb, 0x11, 0x17, 0x43, 0x83, 0x84, 0x65, 0x0e, + 0xf6, 0x2f, 0x23, 0x2e, 0x78, 0x01, 0x02, 0x30, 0x25, 0x2e, 0xec, 0x00, + 0x61, 0x7f, 0x00, 0x2e, 0x61, 0x6f, 0x40, 0x90, 0x05, 0x2f, 0x01, 0x30, + 0x23, 0x2e, 0x70, 0x01, 0x2b, 0x52, 0x23, 0x2e, 0x64, 0xf5, 0x2b, 0x54, + 0x25, 0x2e, 0x60, 0xf5, 0x01, 0x32, 0x07, 0x2e, 0x60, 0xf5, 0x19, 0x09, + 0x00, 0x91, 0x90, 0x2e, 0x77, 0xb4, 0x1a, 0x09, 0x00, 0x91, 0x90, 0x2e, + 0x77, 0xb4, 0x80, 0x6f, 0x91, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, + 0xd5, 0x6f, 0x7b, 0x6f, 0xf6, 0x6f, 0xe7, 0x6f, 0x40, 0x5f, 0xc8, 0x2e, + 0x10, 0x50, 0xf7, 0x7f, 0x00, 0x2e, 0x0f, 0x2e, 0x69, 0xf5, 0xff, 0xbf, + 0xff, 0xbb, 0xc0, 0x91, 0x02, 0x2f, 0x37, 0x30, 0x2f, 0x2e, 0x69, 0xf5, + 0xf7, 0x6f, 0xf0, 0x5f, 0xc8, 0x2e, 0x67, 0x52, 0x75, 0x56, 0x50, 0x40, + 0x46, 0x40, 0x44, 0x40, 0x0b, 0x2e, 0x9f, 0x00, 0x10, 0x51, 0xdf, 0xbf, + 0xc3, 0x08, 0x7f, 0xb8, 0x1a, 0x25, 0x71, 0x8e, 0x6f, 0x8a, 0xfb, 0x7f, + 0x6c, 0xbf, 0x48, 0xbe, 0xe0, 0x7f, 0x0b, 0x30, 0x6c, 0xbb, 0x4c, 0xba, + 0x18, 0x0a, 0x0b, 0x7f, 0xcb, 0x43, 0x4b, 0x43, 0x00, 0xb2, 0xb4, 0x7f, + 0xa6, 0x7f, 0xd5, 0x7f, 0xc7, 0x7f, 0x93, 0x7f, 0x90, 0x2e, 0x07, 0xb6, + 0x01, 0x2e, 0xf4, 0x00, 0x01, 0x90, 0x0b, 0x2f, 0x6b, 0x52, 0x01, 0x2e, + 0xef, 0x00, 0x82, 0x7f, 0x98, 0x2e, 0xbb, 0xcc, 0x0b, 0x30, 0x37, 0x2e, + 0xf4, 0x00, 0x82, 0x6f, 0x93, 0x6f, 0x1a, 0x25, 0xc0, 0xb2, 0x8b, 0x7f, + 0x02, 0x25, 0x18, 0x2f, 0x0b, 0x2e, 0xa0, 0x00, 0x05, 0x2e, 0xa0, 0x00, + 0xd6, 0xbe, 0x25, 0xbd, 0xd6, 0xba, 0x2f, 0xb9, 0x80, 0xb2, 0x54, 0xb1, + 0x0c, 0x2f, 0x69, 0x54, 0x6d, 0x5a, 0x0b, 0x30, 0x09, 0x2e, 0xa0, 0x00, + 0x73, 0x5e, 0x9b, 0x42, 0x5b, 0x43, 0x27, 0x09, 0x29, 0x2e, 0xa0, 0x00, + 0x8b, 0x42, 0x4b, 0x43, 0x86, 0x7f, 0x00, 0x2e, 0x77, 0x54, 0x9a, 0x08, + 0x72, 0x7f, 0x80, 0xb2, 0x05, 0x2f, 0x69, 0x5a, 0x00, 0x2e, 0x52, 0x41, + 0x45, 0x41, 0x05, 0x7f, 0xf2, 0x7e, 0x72, 0x84, 0x79, 0x5a, 0xdd, 0x08, + 0x71, 0x52, 0x62, 0x7f, 0x53, 0x7f, 0x98, 0x2e, 0xc2, 0xc0, 0xe2, 0x6f, + 0x51, 0x6f, 0xca, 0x0a, 0x01, 0x2e, 0xef, 0x00, 0xc5, 0x6f, 0xd4, 0x6f, + 0x62, 0x6f, 0x6b, 0x52, 0x6f, 0x5c, 0x98, 0x2e, 0x06, 0xcd, 0x10, 0x6f, + 0x00, 0xb2, 0x92, 0x6f, 0x33, 0x52, 0xd1, 0x08, 0x00, 0x30, 0x09, 0x2f, + 0xc0, 0xb2, 0x00, 0x30, 0x06, 0x2f, 0x69, 0x5a, 0x6d, 0x52, 0x50, 0x41, + 0x45, 0x41, 0x50, 0x42, 0x45, 0x42, 0x10, 0x30, 0x71, 0x6f, 0x40, 0xb2, + 0x1e, 0x2f, 0x69, 0x58, 0xc0, 0x90, 0xf1, 0x6e, 0x03, 0x6f, 0x6d, 0x5a, + 0x11, 0x43, 0x03, 0x43, 0x14, 0x2f, 0x6d, 0x5c, 0x00, 0x2e, 0x94, 0x41, + 0x86, 0x41, 0x0c, 0x05, 0x9e, 0x07, 0x80, 0xab, 0x04, 0x2f, 0x80, 0x91, + 0x0a, 0x2f, 0x86, 0x6f, 0x74, 0x0f, 0x07, 0x2f, 0x84, 0x6f, 0x00, 0xb3, + 0x04, 0x2f, 0x51, 0x43, 0x43, 0x43, 0x10, 0x30, 0x04, 0x2c, 0x11, 0x30, + 0x02, 0x2c, 0x11, 0x30, 0x11, 0x30, 0x7b, 0x56, 0x93, 0x08, 0xe0, 0x7f, + 0x80, 0x90, 0x04, 0x2f, 0x32, 0x30, 0x25, 0x2e, 0xee, 0x00, 0x0b, 0x2c, + 0x01, 0x30, 0x05, 0x2e, 0x7a, 0x01, 0x01, 0x2e, 0xee, 0x00, 0x02, 0x1a, + 0x02, 0x2f, 0x25, 0x2e, 0xee, 0x00, 0x01, 0x2d, 0x01, 0x30, 0xb0, 0x6f, + 0x98, 0x2e, 0x95, 0xcf, 0xe1, 0x6f, 0xa0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, + 0x69, 0x54, 0x00, 0x2e, 0x90, 0x40, 0x13, 0x2c, 0x81, 0x40, 0x10, 0x30, + 0x21, 0x2e, 0xf4, 0x00, 0x32, 0x30, 0x25, 0x2e, 0xee, 0x00, 0xb0, 0x6f, + 0x01, 0x30, 0x98, 0x2e, 0x95, 0xcf, 0xa0, 0x6f, 0x01, 0x30, 0x98, 0x2e, + 0x95, 0xcf, 0x69, 0x54, 0x00, 0x2e, 0x90, 0x40, 0x81, 0x40, 0xfb, 0x6f, + 0xf0, 0x5e, 0xb8, 0x2e, 0x7d, 0x50, 0x80, 0x2e, 0x64, 0xcf, 0x03, 0x2e, + 0x9f, 0x00, 0x07, 0x2e, 0x9f, 0x00, 0x9f, 0xbc, 0xbb, 0xbd, 0x70, 0x50, + 0x9f, 0xb8, 0xbc, 0xb9, 0xf3, 0x7f, 0xe0, 0x7f, 0x40, 0xb2, 0xdb, 0x7f, + 0x2d, 0x2f, 0x07, 0x2e, 0xf5, 0x00, 0xc3, 0x40, 0x01, 0x2e, 0xf6, 0x00, + 0x03, 0x1a, 0x11, 0x2f, 0x7f, 0x52, 0x27, 0x2e, 0xf6, 0x00, 0x50, 0x40, + 0x90, 0x7f, 0x78, 0x80, 0x43, 0x40, 0xc0, 0x7f, 0xa3, 0x7f, 0x98, 0x2e, + 0x64, 0xcf, 0xc0, 0x6f, 0x07, 0x80, 0x93, 0x6f, 0x13, 0x42, 0x00, 0x2e, + 0xa3, 0x6f, 0x03, 0x42, 0x03, 0x30, 0x01, 0x2e, 0x7a, 0x01, 0x01, 0xb2, + 0x01, 0x2f, 0x02, 0x90, 0x00, 0x2f, 0x13, 0x30, 0x1a, 0x25, 0x7b, 0x88, + 0x01, 0x2e, 0xf5, 0x00, 0xe2, 0x6f, 0x7d, 0x52, 0x98, 0x2e, 0xc4, 0xce, + 0xb1, 0x6f, 0xf0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x04, 0x2d, 0x01, 0x30, + 0xf0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xdb, 0x6f, 0x90, 0x5f, 0xb8, 0x2e, + 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x56, 0xc7, 0x98, 0x2e, 0x49, 0xc3, + 0x98, 0x2e, 0x2c, 0xb2, 0xfb, 0x6f, 0xf0, 0x5f, 0x80, 0x2e, 0x86, 0xb2, + 0x60, 0x51, 0x2a, 0x25, 0xb6, 0x88, 0xe0, 0x7f, 0xf4, 0x7f, 0xdb, 0x7f, + 0x00, 0x32, 0x8b, 0x52, 0x32, 0x30, 0x13, 0x30, 0x98, 0x2e, 0x15, 0xcb, + 0x0a, 0x25, 0x33, 0x84, 0xe0, 0x6f, 0xe2, 0x7f, 0x43, 0x30, 0x87, 0x52, + 0x98, 0x2e, 0x95, 0xc1, 0xe2, 0x6f, 0x81, 0x52, 0x98, 0x2e, 0xd7, 0xc7, + 0x2a, 0x25, 0xb0, 0x86, 0xc0, 0x7f, 0xe3, 0x7f, 0xaf, 0x84, 0x83, 0x50, + 0xf1, 0x6f, 0x98, 0x2e, 0x4d, 0xc8, 0x2a, 0x25, 0xae, 0x8a, 0xaa, 0x88, + 0xf2, 0x6e, 0x85, 0x50, 0xc1, 0x6f, 0xe3, 0x6f, 0xf4, 0x7f, 0x98, 0x2e, + 0xb6, 0xc8, 0xe0, 0x6e, 0x00, 0xb2, 0x32, 0x2f, 0x8d, 0x54, 0x83, 0x88, + 0xf1, 0x6f, 0xc4, 0x7f, 0x03, 0x30, 0x30, 0x30, 0xf3, 0x7f, 0xe0, 0x7f, + 0xb2, 0x7f, 0xe4, 0x30, 0xc5, 0x6f, 0x56, 0x40, 0x45, 0x41, 0x28, 0x08, + 0x04, 0x14, 0x0e, 0xb4, 0x08, 0xbc, 0x82, 0x40, 0x10, 0x0a, 0x89, 0x54, + 0xde, 0x04, 0x91, 0x7f, 0x43, 0x28, 0xa4, 0x7f, 0x98, 0x2e, 0xd9, 0xc0, + 0x08, 0xb5, 0x34, 0x30, 0x54, 0x09, 0xc1, 0x6f, 0xe4, 0x6f, 0xf3, 0x6f, + 0x84, 0x17, 0x47, 0x40, 0x6b, 0x15, 0xb2, 0x6f, 0xbe, 0x09, 0x75, 0x0b, + 0x90, 0x42, 0x45, 0x42, 0x51, 0x0e, 0x42, 0xbc, 0xc2, 0x86, 0xa1, 0x6f, + 0x7e, 0x88, 0xf3, 0x7f, 0xe0, 0x7f, 0xb2, 0x7f, 0x03, 0x30, 0x91, 0x6f, + 0xd6, 0x2f, 0xdb, 0x6f, 0xa0, 0x5e, 0xb8, 0x2e, 0x01, 0x2e, 0x77, 0xf7, + 0x09, 0xbc, 0x0f, 0xb8, 0x00, 0xb2, 0x10, 0x50, 0xfb, 0x7f, 0x10, 0x30, + 0x0b, 0x2f, 0x03, 0x2e, 0x8a, 0x00, 0x96, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, + 0x05, 0x2f, 0x03, 0x2e, 0x68, 0xf7, 0x9e, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, + 0x07, 0x2f, 0x03, 0x2e, 0xf7, 0x00, 0x41, 0x90, 0x01, 0x2f, 0x98, 0x2e, + 0xf4, 0xb6, 0x03, 0x2c, 0x00, 0x30, 0x21, 0x2e, 0xf7, 0x00, 0xfb, 0x6f, + 0xf0, 0x5f, 0xb8, 0x2e, 0x20, 0x50, 0xe0, 0x7f, 0xfb, 0x7f, 0x00, 0x2e, + 0x81, 0x50, 0x98, 0x2e, 0x3b, 0xc8, 0x83, 0x50, 0x98, 0x2e, 0xa7, 0xc8, + 0x15, 0x50, 0x98, 0x2e, 0x55, 0xcc, 0xe1, 0x6f, 0x85, 0x50, 0x98, 0x2e, + 0xe0, 0xc9, 0xfb, 0x6f, 0x00, 0x30, 0xe0, 0x5f, 0x21, 0x2e, 0xf7, 0x00, + 0xb8, 0x2e, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, + 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xfd, 0x2d +}; + +/*! @name Global array that stores the feature input configuration of BMI260 */ +const struct bmi2_feature_config feat_in[BMI260_MAX_FEAT_IN] = { + { .type = BMI2_AXIS_MAP, .page = BMI2_PAGE_1, .start_addr = BMI260_AXIS_MAP_STRT_ADDR}, + { .type = BMI2_GYRO_SELF_OFF, .page = BMI2_PAGE_1, .start_addr = BMI260_GYRO_SELF_OFF_STRT_ADDR }, + { .type = BMI2_ANY_MOTION, .page = BMI2_PAGE_1, .start_addr = BMI260_ANY_MOT_STRT_ADDR}, + { .type = BMI2_NO_MOTION, .page = BMI2_PAGE_1, .start_addr = BMI260_NO_MOT_STRT_ADDR}, + { .type = BMI2_WAKE_UP, .page = BMI2_PAGE_1, .start_addr = BMI260_WAKE_UP_STRT_ADDR}, + { .type = BMI2_ORIENTATION, .page = BMI2_PAGE_2, .start_addr = BMI260_ORIENT_STRT_ADDR}, + { .type = BMI2_HIGH_G, .page = BMI2_PAGE_2, .start_addr = BMI260_HIGH_G_STRT_ADDR}, + { .type = BMI2_LOW_G, .page = BMI2_PAGE_2, .start_addr = BMI260_LOW_G_STRT_ADDR}, + { .type = BMI2_FLAT, .page = BMI2_PAGE_3, .start_addr = BMI260_FLAT_STRT_ADDR}, + { .type = BMI2_SIG_MOTION, .page = BMI2_PAGE_3, .start_addr = BMI260_SIG_MOT_STRT_ADDR}, + { .type = BMI2_STEP_DETECTOR, .page = BMI2_PAGE_4, .start_addr = BMI260_STEP_COUNT_STRT_ADDR}, + { .type = BMI2_STEP_COUNTER, .page = BMI2_PAGE_4, .start_addr = BMI260_STEP_COUNT_STRT_ADDR}, + { .type = BMI2_STEP_ACTIVITY, .page = BMI2_PAGE_4, .start_addr = BMI260_STEP_COUNT_STRT_ADDR}, + { .type = BMI2_GYRO_GAIN_UPDATE, .page = BMI2_PAGE_4, .start_addr = BMI260_GYRO_GAIN_UPDATE_STRT_ADDR}, +}; + +/*! @name Global array that stores the feature output configuration */ +const struct bmi2_feature_config feat_out[BMI260_MAX_FEAT_OUT] = { + { .type = BMI2_STEP_COUNTER, .page = BMI2_PAGE_0, .start_addr = BMI260_STEP_CNT_OUT_STRT_ADDR}, + { .type = BMI2_STEP_ACTIVITY, .page = BMI2_PAGE_0, .start_addr = BMI260_STEP_ACT_OUT_STRT_ADDR}, + { .type = BMI2_ORIENTATION, .page = BMI2_PAGE_0, .start_addr = BMI260_ORIENT_OUT_STRT_ADDR}, + { .type = BMI2_HIGH_G, .page = BMI2_PAGE_0, .start_addr = BMI260_HIGH_G_OUT_STRT_ADDR}, + { .type = BMI2_GYRO_GAIN_UPDATE, .page = BMI2_PAGE_0, .start_addr = BMI260_GYR_USER_GAIN_OUT_STRT_ADDR}, + { .type = BMI2_GYRO_CROSS_SENSE, .page = BMI2_PAGE_0, .start_addr = BMI260_GYRO_CROSS_SENSE_STRT_ADDR}, + { .type = BMI2_NVM_STATUS, .page = BMI2_PAGE_0, .start_addr = BMI260_NVM_VFRM_OUT_STRT_ADDR}, + { .type = BMI2_VFRM_STATUS, .page = BMI2_PAGE_0, .start_addr = BMI260_NVM_VFRM_OUT_STRT_ADDR} +}; + +/******************************************************************************/ +/*! Local Function Prototypes +******************************************************************************/ +/*! + * @brief This internal API is used to validate the device pointer for + * null conditions. + * + * @param[in] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * @retval zero -> Success / +ve value -> Warning / -ve value -> Error + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev); + +/***************************************************************************/ +/*! User Interface Definitions +****************************************************************************/ +/*! + * @brief This API: + * 1) updates the device structure with address of the configuration file. + * 2) Initializes BMI260 sensor. + * 3) Writes the configuration file. + * 4) Updates the feature offset parameters in the device structure. + * 5) Updates the maximum number of pages, in the device structure. + */ +int8_t bmi2_init(struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt; + + /* Null-pointer check */ + rslt = null_ptr_check(dev); + if (rslt == BMI2_OK) { + /* Assign chip id of BMI260 */ + dev->chip_id = BMI260_CHIP_ID; + + /* An extra dummy byte is read during SPI read */ + if (dev->intf == BMI2_SPI_INTERFACE) + dev->dummy_byte = 1; + else + dev->dummy_byte = 0; + + /* If configuration file pointer is not assigned any address */ + if (!dev->config_file_ptr) { + /* Give the address of the configuration file array to + the device pointer */ + dev->config_file_ptr = bmi260_config_file; + } + + /* Initialize BMI2 sensor */ + rslt = bmi2_sec_init(dev); + if (rslt == BMI2_OK) { + /* Write the configuration file */ + rslt = bmi2_write_config_file(dev); + if (rslt == BMI2_OK) { + /* Assign the offsets of the feature input + configuration to the device structure */ + dev->feat_config = feat_in; + + /* Assign the offsets of the feature output to + the device structure */ + dev->feat_output = feat_out; + + /* Assign the maximum number of pages to the + device structure */ + dev->page_max = BMI260_MAX_PAGE_NUM; + + /* Assign maximum number of input sensors + /features to device structure */ + dev->input_sens = BMI260_MAX_FEAT_IN; + + /* Assign maximum number of output sensors + /features to device structure */ + dev->out_sens = BMI260_MAX_FEAT_OUT; + + /* Get the gyroscope cross axis sensitivity */ + rslt = bmi2_get_gyro_cross_sense(dev); + } + } + } + + return rslt; +} + +/***************************************************************************/ +/*! Local Function Definitions +****************************************************************************/ +/*! + * @brief This internal API is used to validate the device structure pointer for + * null conditions. + */ +static int8_t null_ptr_check(const struct bmi2_dev *dev) +{ + /* Variable to define error */ + int8_t rslt = BMI2_OK; + + if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) { + /* Device structure pointer is not valid */ + rslt = BMI2_E_NULL_PTR; + } + + return rslt; +} + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi260.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi260.h new file mode 100755 index 0000000000000000000000000000000000000000..6ea426b6e3737c09dc17d3cf07fcee8cdbecbca5 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi260.h @@ -0,0 +1,141 @@ +/** + * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of the + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * The information provided is believed to be accurate and reliable. + * The copyright holder assumes no responsibility + * for the consequences of use + * of such information nor for any infringement of patents or + * other rights of third parties which may result from its use. + * No license is granted by implication or otherwise under any patent or + * patent rights of the copyright holder. + * + * @file bmi260.h + * @date 1 September, 2018 + * @version 0.5.0 + * @brief Sensor driver for BMI260 sensor + * + */ + +#ifndef BMI260_H_ +#define BMI260_H_ + +/*! CPP guard */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/***************************************************************************/ +/*! Header files +****************************************************************************/ +#include "bmi2.h" + +/***************************************************************************/ +/*! Macro definitions +****************************************************************************/ +/*! @name BMI260 chip identifier */ +#define BMI260_CHIP_ID UINT8_C(0x27) + +/*! @name BMI260 feature input start addresses */ +#define BMI260_AXIS_MAP_STRT_ADDR UINT8_C(0x04) +#define BMI260_GYRO_SELF_OFF_STRT_ADDR UINT8_C(0x05) +#define BMI260_ANY_MOT_STRT_ADDR UINT8_C(0x06) +#define BMI260_NO_MOT_STRT_ADDR UINT8_C(0x0A) +#define BMI260_WAKE_UP_STRT_ADDR UINT8_C(0x0E) +#define BMI260_ORIENT_STRT_ADDR UINT8_C(0x00) +#define BMI260_HIGH_G_STRT_ADDR UINT8_C(0x04) +#define BMI260_LOW_G_STRT_ADDR UINT8_C(0x0A) +#define BMI260_FLAT_STRT_ADDR UINT8_C(0x00) +#define BMI260_SIG_MOT_STRT_ADDR UINT8_C(0x04) +#define BMI260_STEP_COUNT_STRT_ADDR UINT8_C(0x00) +#define BMI260_GYRO_GAIN_UPDATE_STRT_ADDR UINT8_C(0x04) + +/*! @name BMI260 feature output start addresses */ +#define BMI260_STEP_CNT_OUT_STRT_ADDR UINT8_C(0x00) +#define BMI260_STEP_ACT_OUT_STRT_ADDR UINT8_C(0x04) +#define BMI260_ORIENT_OUT_STRT_ADDR UINT8_C(0x06) +#define BMI260_HIGH_G_OUT_STRT_ADDR UINT8_C(0x08) +#define BMI260_GYR_USER_GAIN_OUT_STRT_ADDR UINT8_C(0x0A) +#define BMI260_GYRO_CROSS_SENSE_STRT_ADDR UINT8_C(0x0C) +#define BMI260_NVM_VFRM_OUT_STRT_ADDR UINT8_C(0x0E) + +/*! @name Defines maximum number of pages */ +#define BMI260_MAX_PAGE_NUM UINT8_C(8) + +/*! @name Defines maximum number of feature input configurations */ +#define BMI260_MAX_FEAT_IN UINT8_C(14) + +/*! @name Defines maximum number of feature outputs */ +#define BMI260_MAX_FEAT_OUT UINT8_C(8) + +/*! @name Mask definitions for feature interrupt status bits */ +#define BMI260_SIG_MOT_STATUS_MASK UINT8_C(0x01) +#define BMI260_STEP_CNT_STATUS_MASK UINT8_C(0x02) +#define BMI260_HIGH_G_STATUS_MASK UINT8_C(0x04) +#define BMI260_LOW_G_STATUS_MASK UINT8_C(0x04) +#define BMI260_WAKE_UP_STATUS_MASK UINT8_C(0x08) +#define BMI260_FLAT_STATUS_MASK UINT8_C(0x10) +#define BMI260_NO_MOT_STATUS_MASK UINT8_C(0x20) +#define BMI260_ANY_MOT_STATUS_MASK UINT8_C(0x40) +#define BMI260_ORIENT_STATUS_MASK UINT8_C(0x80) + +/***************************************************************************/ +/*! BMI260 User Interface function prototypes +****************************************************************************/ +/*! + * @brief This API: + * 1) updates the device structure with address of the configuration file. + * 2) Initializes BMI260 sensor. + * 3) Writes the configuration file. + * 4) Updates the feature offset parameters in the device structure. + * 5) Updates the maximum number of pages, in the device structure. + * + * @param[in, out] dev : Structure instance of bmi2_dev. + * + * @return Result of API execution status + * + * @retval BMI2_OK - Success + * @retval BMI2_E_NULL_PTR - Error: Null pointer error + * @retval BMI2_E_COM_FAIL - Error: Communication fail + * @retval BMI2_E_DEV_NOT_FOUND - Invalid device + */ +extern int8_t bmi2_init(struct bmi2_dev *dev); + +/******************************************************************************/ +/*! @name C++ Guard Macros */ +/******************************************************************************/ +#ifdef __cplusplus +} +#endif /* End of CPP guard */ + +#endif /* BMI260_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2_defs.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2_defs.h new file mode 100755 index 0000000000000000000000000000000000000000..363754696d58779ab8aff619260c05b4ae03be4d --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898124/bmi2_defs.h @@ -0,0 +1,1448 @@ +/** + * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of the copyright holder nor the names of the + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + * OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE + * + * The information provided is believed to be accurate and reliable. + * The copyright holder assumes no responsibility + * for the consequences of use + * of such information nor for any infringement of patents or + * other rights of third parties which may result from its use. + * No license is granted by implication or otherwise under any patent or + * patent rights of the copyright holder. + * + * @file bmi2_defs.h + * @date 16 August, 2018 + * @version 1.35.0 + * @brief Sensor driver for BMI2XY sensor + * + */ + +#ifndef BMI2_DEFS_H_ +#define BMI2_DEFS_H_ + +/******************************************************************************/ +/*! @name Header includes */ +/******************************************************************************/ +#ifdef __KERNEL__ +#include <linux/types.h> +#include <linux/kernel.h> +#else +#include <stdint.h> +#include <stddef.h> +#endif + +/******************************************************************************/ +/*! @name Common macros */ +/******************************************************************************/ +#ifdef __KERNEL__ +#if !defined(UINT8_C) && !defined(INT8_C) +#define INT8_C(x) S8_C(x) +#define UINT8_C(x) U8_C(x) +#endif + +#if !defined(UINT16_C) && !defined(INT16_C) +#define INT16_C(x) S16_C(x) +#define UINT16_C(x) U16_C(x) +#endif + +#if !defined(INT32_C) && !defined(UINT32_C) +#define INT32_C(x) S32_C(x) +#define UINT32_C(x) U32_C(x) +#endif + +#if !defined(INT64_C) && !defined(UINT64_C) +#define INT64_C(x) S64_C(x) +#define UINT64_C(x) U64_C(x) +#endif +#endif + +/*! @name C standard macros */ +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *) 0) +#endif +#endif + +/******************************************************************************/ +/*! @name General Macro Definitions */ +/******************************************************************************/ +/*! @name Utility macros */ +#define BMI2_SET_BITS(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MASK)) | \ + ((data << bitname##_POS) & bitname##_MASK)) + +#define BMI2_GET_BITS(reg_data, bitname) \ + ((reg_data & (bitname##_MASK)) >> \ + (bitname##_POS)) + +#define BMI2_SET_BIT_POS0(reg_data, bitname, data) \ + ((reg_data & ~(bitname##_MASK)) | \ + (data & bitname##_MASK)) + +#define BMI2_GET_BIT_POS0(reg_data, bitname) (reg_data & (bitname##_MASK)) +#define BMI2_SET_BIT_VAL0(reg_data, bitname) (reg_data & ~(bitname##_MASK)) + +/*! @name For getting LSB and MSB */ +#define BMI2_GET_LSB(var) (uint8_t)(var & BMI2_SET_LOW_BYTE) +#define BMI2_GET_MSB(var) (uint8_t)((var & BMI2_SET_HIGH_BYTE) >> 8) + +/*! @name For defining absolute values */ +#define BMI2_ABS(a) ((a) > 0 ? (a) : -(a)) + +/*! @name LSB and MSB mask definitions */ +#define BMI2_SET_LOW_BYTE UINT16_C(0x00FF) +#define BMI2_SET_HIGH_BYTE UINT16_C(0xFF00) +#define BMI2_SET_LOW_NIBBLE UINT8_C(0x0F) + +/*! @name For enable and disable */ +#define BMI2_ENABLE UINT8_C(1) +#define BMI2_DISABLE UINT8_C(0) + +/*! @name To define TRUE or FALSE */ +#define BMI2_TRUE UINT8_C(1) +#define BMI2_FALSE UINT8_C(0) + +/*! @name To define success code */ +#define BMI2_OK INT8_C(0) + +/*! @name To define error codes */ +#define BMI2_E_NULL_PTR INT8_C(-1) +#define BMI2_E_COM_FAIL INT8_C(-2) +#define BMI2_E_DEV_NOT_FOUND INT8_C(-3) +#define BMI2_E_OUT_OF_RANGE INT8_C(-4) +#define BMI2_E_ACC_INVALID_CFG INT8_C(-5) +#define BMI2_E_GYRO_INVALID_CFG INT8_C(-6) +#define BMI2_E_ACC_GYR_INVALID_CFG INT8_C(-7) +#define BMI2_E_INVALID_SENSOR INT8_C(-8) +#define BMI2_E_CONFIG_LOAD INT8_C(-9) +#define BMI2_E_INVALID_PAGE INT8_C(-10) +#define BMI2_E_INVALID_FEAT_INT INT8_C(-11) +#define BMI2_E_INVALID_INT_PIN INT8_C(-12) +#define BMI2_E_SET_APS_FAIL INT8_C(-13) +#define BMI2_E_AUX_INVALID_CFG INT8_C(-14) +#define BMI2_E_AUX_BUSY INT8_C(-15) +#define BMI2_E_SELF_TEST_FAIL INT8_C(-16) +#define BMI2_E_REMAP_ERROR INT8_C(-17) +#define BMI2_E_GYR_USER_GAIN_UPD_FAIL INT8_C(-18) +#define BMI2_E_SELF_TEST_NOT_DONE INT8_C(-19) + +/*! @name To define warnings for FIFO activity */ +#define BMI2_W_FIFO_EMPTY INT8_C(1) +#define BMI2_W_PARTIAL_READ INT8_C(2) + +/*! @name Bit wise to define information */ +#define BMI2_I_MIN_VALUE UINT8_C(1) +#define BMI2_I_MAX_VALUE UINT8_C(2) + +/*! @name BMI2 register addresses */ +#define BMI2_CHIP_ID_ADDR UINT8_C(0x00) +#define BMI2_STATUS_ADDR UINT8_C(0x03) +#define BMI2_AUX_X_LSB_ADDR UINT8_C(0x04) +#define BMI2_ACC_X_LSB_ADDR UINT8_C(0x0C) +#define BMI2_GYR_X_LSB_ADDR UINT8_C(0x12) +#define BMI2_EVENT_ADDR UINT8_C(0x1B) +#define BMI2_INT_STATUS_0_ADDR UINT8_C(0x1C) +#define BMI2_INT_STATUS_1_ADDR UINT8_C(0x1D) +#define BMI2_STEP_COUNT_OUT_0_ADDR UINT8_C(0x1E) +#define BMI2_SYNC_COMMAND_ADDR UINT8_C(0x1E) +#define BMI2_INTERNAL_STATUS_ADDR UINT8_C(0x21) +#define BMI2_FIFO_LENGTH_0_ADDR UINT8_C(0X24) +#define BMI2_FIFO_DATA_ADDR UINT8_C(0X26) +#define BMI2_FEAT_PAGE_ADDR UINT8_C(0x2F) +#define BMI2_FEATURES_REG_ADDR UINT8_C(0x30) +#define BMI2_ACC_CONF_ADDR UINT8_C(0x40) +#define BMI2_GYR_CONF_ADDR UINT8_C(0x42) +#define BMI2_AUX_CONF_ADDR UINT8_C(0x44) +#define BMI2_FIFO_DOWNS_ADDR UINT8_C(0X45) +#define BMI2_FIFO_WTM_0_ADDR UINT8_C(0X46) +#define BMI2_FIFO_WTM_1_ADDR UINT8_C(0X47) +#define BMI2_FIFO_CONFIG_0_ADDR UINT8_C(0X48) +#define BMI2_FIFO_CONFIG_1_ADDR UINT8_C(0X49) +#define BMI2_AUX_DEV_ID_ADDR UINT8_C(0x4B) +#define BMI2_AUX_IF_CONF_ADDR UINT8_C(0x4C) +#define BMI2_AUX_RD_ADDR UINT8_C(0x4D) +#define BMI2_AUX_WR_ADDR UINT8_C(0x4E) +#define BMI2_AUX_WR_DATA_ADDR UINT8_C(0x4F) +#define BMI2_INT1_IO_CTRL_ADDR UINT8_C(0x53) +#define BMI2_INT2_IO_CTRL_ADDR UINT8_C(0x54) +#define BMI2_INT1_MAP_FEAT_ADDR UINT8_C(0x56) +#define BMI2_INT2_MAP_FEAT_ADDR UINT8_C(0x57) +#define BMI2_INT_MAP_DATA_ADDR UINT8_C(0x58) +#define BMI2_INIT_CTRL_ADDR UINT8_C(0x59) +#define BMI2_INIT_ADDR_0 UINT8_C(0x5B) +#define BMI2_INIT_ADDR_1 UINT8_C(0x5C) +#define BMI2_INIT_DATA_ADDR UINT8_C(0x5E) +#define BMI2_IF_CONF_ADDR UINT8_C(0X6B) +#define BMI2_ACC_SELF_TEST_ADDR UINT8_C(0X6D) +#define BMI2_SELF_TEST_MEMS_ADDR UINT8_C(0X6F) +#define BMI2_NV_CONF_ADDR UINT8_C(0x70) +#define BMI2_ACC_OFF_COMP_0_ADDR UINT8_C(0X71) +#define BMI2_GYR_OFF_COMP_3_ADDR UINT8_C(0X74) +#define BMI2_GYR_OFF_COMP_6_ADDR UINT8_C(0X77) +#define BMI2_GYR_USR_GAIN_0_ADDR UINT8_C(0X78) +#define BMI2_PWR_CONF_ADDR UINT8_C(0x7C) +#define BMI2_PWR_CTRL_ADDR UINT8_C(0x7D) +#define BMI2_CMD_REG_ADDR UINT8_C(0x7E) + +/*! @name BMI2 I2C address */ +#define BMI2_I2C_PRIM_ADDR UINT8_C(0x68) +#define BMI2_I2C_SEC_ADDR UINT8_C(0x69) + +/*! @name BMI2 Commands */ +#define BMI2_USR_GAIN_CMD UINT8_C(0x03) +#define BMI2_SOFT_RESET_CMD UINT8_C(0xB6) +#define BMI2_FIFO_FLUSH_CMD UINT8_C(0xB0) + +/*! @name BMI2 sensor data bytes */ +#define BMI2_ACC_GYR_NUM_BYTES UINT8_C(6) +#define BMI2_AUX_NUM_BYTES UINT8_C(8) +#define BMI2_CONFIG_FILE_SIZE UINT16_C(8192) +#define BMI2_FEAT_SIZE_IN_BYTES UINT8_C(16) +#define BMI2_ACC_CONFIG_LENGTH UINT8_C(2) + +/*! @name BMI2 configuration load status */ +#define BMI2_CONFIG_LOAD_SUCCESS UINT8_C(1) + +/*! @name To define BMI2 pages */ +#define BMI2_PAGE_0 UINT8_C(0) +#define BMI2_PAGE_1 UINT8_C(1) +#define BMI2_PAGE_2 UINT8_C(2) +#define BMI2_PAGE_3 UINT8_C(3) +#define BMI2_PAGE_4 UINT8_C(4) +#define BMI2_PAGE_5 UINT8_C(5) +#define BMI2_PAGE_6 UINT8_C(6) +#define BMI2_PAGE_7 UINT8_C(7) + +/*! @name Array Parameter DefinItions */ +#define BMI2_SENSOR_TIME_LSB_BYTE UINT8_C(0) +#define BMI2_SENSOR_TIME_XLSB_BYTE UINT8_C(1) +#define BMI2_SENSOR_TIME_MSB_BYTE UINT8_C(2) + +/*! @name Mask definitions for SPI read/write address */ +#define BMI2_SPI_RD_MASK UINT8_C(0x80) +#define BMI2_SPI_WR_MASK UINT8_C(0x7F) + +/*! @name Mask definitions for power configuration register */ +#define BMI2_ADV_POW_EN_MASK UINT8_C(0x01) + +/*! @name Mask definitions for initialization control register */ +#define BMI2_CONF_LOAD_EN_MASK UINT8_C(0x01) + +/*! @name Mask definitions for power control register */ +#define BMI2_AUX_EN_MASK UINT8_C(0x01) +#define BMI2_GYR_EN_MASK UINT8_C(0x02) +#define BMI2_ACC_EN_MASK UINT8_C(0x04) +#define BMI2_TEMP_EN_MASK UINT8_C(0x08) + +/*! @name Bit position definitions for power control register */ +#define BMI2_GYR_EN_POS UINT8_C(0x01) +#define BMI2_ACC_EN_POS UINT8_C(0x02) +#define BMI2_TEMP_EN_POS UINT8_C(0x03) + +/*! @name Mask definitions for sensor event flags */ +#define BMI2_EVENT_FLAG_MASK UINT8_C(0x1C) + +/*! @name Bit position definitions for sensor event flags */ +#define BMI2_EVENT_FLAG_POS UINT8_C(0x02) + +/*! @name Mask definitions to switch page */ +#define BMI2_SWITCH_PAGE_EN_MASK UINT8_C(0x07) + +/*! @name Accelerometer and Gyroscope Filter/Noise performance modes */ +/* Power optimized mode */ +#define BMI2_POWER_OPT_MODE UINT8_C(0) +/* Performance optimized */ +#define BMI2_PERF_OPT_MODE UINT8_C(1) + +/*! @name Mask definitions of NVM register */ +#define BMI2_NV_ACC_OFFSET_MASK UINT8_C(0x08) + +/*! @name Bit position definitions of NVM register */ +#define BMI2_NV_ACC_OFFSET_POS UINT8_C(0x03) + +/*! @name Sensor status */ +#define BMI2_DRDY_ACC UINT8_C(0x80) +#define BMI2_DRDY_GYR UINT8_C(0x40) +#define BMI2_DRDY_AUX UINT8_C(0x20) +#define BMI2_CMD_RDY UINT8_C(0x10) +#define BMI2_AUX_BUSY UINT8_C(0x04) + +/*! @name Macro to define accelerometer configuration value for FOC */ +#define BMI2_FOC_ACC_CONF_VAL UINT8_C(0xB7) + +/*! @name Macro to define gyroscope configuration value for FOC */ +#define BMI2_FOC_GYR_CONF_VAL UINT8_C(0xB6) + +/*! @name Macro to define X Y and Z axis for an array */ +#define BMI2_X_AXIS UINT8_C(0) +#define BMI2_Y_AXIS UINT8_C(1) +#define BMI2_Z_AXIS UINT8_C(2) + +/******************************************************************************/ +/*! @name Sensor Macro Definitions */ +/******************************************************************************/ +/*! @name Macros to define BMI2 sensor/feature types */ +#define BMI2_ACCEL UINT8_C(0) +#define BMI2_GYRO UINT8_C(1) +#define BMI2_AUX UINT8_C(2) +#define BMI2_TEMP UINT8_C(3) +#define BMI2_ANY_MOTION UINT8_C(4) +#define BMI2_NO_MOTION UINT8_C(5) +#define BMI2_TILT UINT8_C(6) +#define BMI2_ORIENTATION UINT8_C(7) +#define BMI2_SIG_MOTION UINT8_C(8) +#define BMI2_STEP_DETECTOR UINT8_C(9) +#define BMI2_STEP_COUNTER UINT8_C(10) +#define BMI2_STEP_ACTIVITY UINT8_C(11) +#define BMI2_GYRO_GAIN_UPDATE UINT8_C(12) +#define BMI2_PICK_UP UINT8_C(13) +#define BMI2_GLANCE_DETECTOR UINT8_C(14) +#define BMI2_WAKE_UP UINT8_C(15) +#define BMI2_HIGH_G UINT8_C(16) +#define BMI2_LOW_G UINT8_C(17) +#define BMI2_FLAT UINT8_C(18) +#define BMI2_EXT_SENS_SYNC UINT8_C(19) +#define BMI2_GYRO_SELF_OFF UINT8_C(20) +#define BMI2_WRIST_GESTURE UINT8_C(21) +#define BMI2_WRIST_WEAR_WAKE_UP UINT8_C(22) +#define BMI2_ACTIVITY_RECOG UINT8_C(23) + +/*! @name Bit wise for selecting BMI2 sensors/features */ +#define BMI2_ACCEL_SENS_SEL (1) +#define BMI2_GYRO_SENS_SEL (1 << BMI2_GYRO) +#define BMI2_AUX_SENS_SEL (1 << BMI2_AUX) +#define BMI2_TEMP_SENS_SEL (1 << BMI2_TEMP) +#define BMI2_ANY_MOT_SEL (1 << BMI2_ANY_MOTION) +#define BMI2_NO_MOT_SEL (1 << BMI2_NO_MOTION) +#define BMI2_TILT_SEL (1 << BMI2_TILT) +#define BMI2_ORIENT_SEL (1 << BMI2_ORIENTATION) +#define BMI2_SIG_MOTION_SEL (1 << BMI2_SIG_MOTION) +#define BMI2_STEP_DETECT_SEL (1 << BMI2_STEP_DETECTOR) +#define BMI2_STEP_COUNT_SEL (1 << BMI2_STEP_COUNTER) +#define BMI2_STEP_ACT_SEL (1 << BMI2_STEP_ACTIVITY) +#define BMI2_GYRO_GAIN_UPDATE_SEL (1 << BMI2_GYRO_GAIN_UPDATE) +#define BMI2_PICK_UP_SEL (1 << BMI2_PICK_UP) +#define BMI2_GLANCE_DET_SEL (1 << BMI2_GLANCE_DETECTOR) +#define BMI2_WAKE_UP_SEL (1 << BMI2_WAKE_UP) +#define BMI2_HIGH_G_SEL (1 << BMI2_HIGH_G) +#define BMI2_LOW_G_SEL (1 << BMI2_LOW_G) +#define BMI2_FLAT_SEL (1 << BMI2_FLAT) +#define BMI2_EXT_SENS_SEL (1 << BMI2_EXT_SENS_SYNC) +#define BMI2_GYRO_SELF_OFF_SEL (1 << BMI2_GYRO_SELF_OFF) +#define BMI2_WRIST_GEST_SEL (1 << BMI2_WRIST_GESTURE) +#define BMI2_WRIST_WEAR_WAKE_UP_SEL (1 << BMI2_WRIST_WEAR_WAKE_UP) +#define BMI2_ACTIVITY_RECOG_SEL (1 << BMI2_ACTIVITY_RECOG) + +/*! @name Bit wise selection of BMI2 sensors */ +#define BMI2_MAIN_SENSORS (BMI2_ACCEL_SENS_SEL | BMI2_GYRO_SENS_SEL \ + | BMI2_AUX_SENS_SEL | BMI2_TEMP_SENS_SEL) + +/*! @name Macro to define axis-re-mapping feature for BMI2 */ +#define BMI2_AXIS_MAP UINT8_C(24) + +/*! @name Macro to define the step counter/detector parameters for BMI2 */ +#define BMI2_STEP_CNT_PARAMS UINT8_C(25) + +/*! @name Macro to define error status for NVM and virtual frames */ +#define BMI2_NVM_STATUS UINT8_C(26) +#define BMI2_VFRM_STATUS UINT8_C(27) + +/*! @name Macro to define gyroscope cross-sensitivity */ +#define BMI2_GYRO_CROSS_SENSE UINT8_C(28) + +/*! @name Macro to define maximum number of available sensors/features */ +#define BMI2_SENS_MAX_NUM UINT8_C(29) + +/*! @name Maximum number of BMI2 main sensors */ +#define BMI2_MAIN_SENS_MAX_NUM UINT8_C(4) + +/*! @name Macro to select between single and double tap */ +#define BMI2_DOUBLE_TAP_SEL UINT8_C(0) +#define BMI2_SINGLE_TAP_SEL UINT8_C(1) + +/******************************************************************************/ +/*! @name Accelerometer Macro Definitions */ +/******************************************************************************/ +/*! @name Accelerometer Bandwidth parameters */ +#define BMI2_ACC_OSR4_AVG1 UINT8_C(0x00) +#define BMI2_ACC_OSR2_AVG2 UINT8_C(0x01) +#define BMI2_ACC_NORMAL_AVG4 UINT8_C(0x02) +#define BMI2_ACC_CIC_AVG8 UINT8_C(0x03) +#define BMI2_ACC_RES_AVG16 UINT8_C(0x04) +#define BMI2_ACC_RES_AVG32 UINT8_C(0x05) +#define BMI2_ACC_RES_AVG64 UINT8_C(0x06) +#define BMI2_ACC_RES_AVG128 UINT8_C(0x07) + +/*! @name Accelerometer Output Data Rate */ +#define BMI2_ACC_ODR_0_78HZ UINT8_C(0x01) +#define BMI2_ACC_ODR_1_56HZ UINT8_C(0x02) +#define BMI2_ACC_ODR_3_12HZ UINT8_C(0x03) +#define BMI2_ACC_ODR_6_25HZ UINT8_C(0x04) +#define BMI2_ACC_ODR_12_5HZ UINT8_C(0x05) +#define BMI2_ACC_ODR_25HZ UINT8_C(0x06) +#define BMI2_ACC_ODR_50HZ UINT8_C(0x07) +#define BMI2_ACC_ODR_100HZ UINT8_C(0x08) +#define BMI2_ACC_ODR_200HZ UINT8_C(0x09) +#define BMI2_ACC_ODR_400HZ UINT8_C(0x0A) +#define BMI2_ACC_ODR_800HZ UINT8_C(0x0B) +#define BMI2_ACC_ODR_1600HZ UINT8_C(0x0C) + +/*! @name Accelerometer G Range */ +#define BMI2_ACC_RANGE_2G UINT8_C(0x00) +#define BMI2_ACC_RANGE_4G UINT8_C(0x01) +#define BMI2_ACC_RANGE_8G UINT8_C(0x02) +#define BMI2_ACC_RANGE_16G UINT8_C(0x03) + +/*! @name Mask definitions for accelerometer configuration register */ +#define BMI2_ACC_RANGE_MASK UINT8_C(0x03) +#define BMI2_ACC_ODR_MASK UINT8_C(0x0F) +#define BMI2_ACC_BW_PARAM_MASK UINT8_C(0x70) +#define BMI2_ACC_FILTER_PERF_MODE_MASK UINT8_C(0x80) + +/*! @name Bit position definitions for accelerometer configuration register */ +#define BMI2_ACC_BW_PARAM_POS UINT8_C(0x04) +#define BMI2_ACC_FILTER_PERF_MODE_POS UINT8_C(0x07) + +/*! @name Self test macro to define range */ +#define BMI2_ACC_SELF_TEST_RANGE UINT8_C(16) + +/*! @name Self test macro to show resulting minimum and maximum difference + signal of the axes in mg */ +#define BMI2_ST_ACC_X_SIG_MIN_DIFF INT16_C(1800) +#define BMI2_ST_ACC_X_SIG_MAX_DIFF INT16_C(10200) + +#define BMI2_ST_ACC_Y_SIG_MIN_DIFF INT16_C(-10200) +#define BMI2_ST_ACC_Y_SIG_MAX_DIFF INT16_C(-1800) + +#define BMI2_ST_ACC_Z_SIG_MIN_DIFF INT16_C(800) +#define BMI2_ST_ACC_Z_SIG_MAX_DIFF INT16_C(10200) + +/*! @name Mask definitions for accelerometer self-test */ +#define BMI2_ACC_SELF_TEST_EN_MASK UINT8_C(0x01) +#define BMI2_ACC_SELF_TEST_SIGN_MASK UINT8_C(0x04) +#define BMI2_ACC_SELF_TEST_AMP_MASK UINT8_C(0x08) + +/*! @name Bit Positions for accelerometer self-test */ +#define BMI2_ACC_SELF_TEST_SIGN_POS UINT8_C(0x02) +#define BMI2_ACC_SELF_TEST_AMP_POS UINT8_C(0x03) + +/*! @name Mask definitions for gyroscope MEMS self-test */ +#define BMI2_GYR_ST_MEMS_START_MASK UINT8_C(0x01) +#define BMI2_GYR_MEMS_OK_MASK UINT8_C(0x02) + +/*! @name Bit Positions for gyroscope MEMS self-test */ +#define BMI2_GYR_MEMS_OK_POS UINT8_C(0x01) + +/******************************************************************************/ +/*! @name Gyroscope Macro Definitions */ +/******************************************************************************/ +/*! @name Gyroscope Bandwidth parameters */ +#define BMI2_GYR_OSR4_MODE UINT8_C(0x00) +#define BMI2_GYR_OSR2_MODE UINT8_C(0x01) +#define BMI2_GYR_NORMAL_MODE UINT8_C(0x02) +#define BMI2_GYR_CIC_MODE UINT8_C(0x03) + +/*! @name Gyroscope Output Data Rate */ +#define BMI2_GYR_ODR_25HZ UINT8_C(0x06) +#define BMI2_GYR_ODR_50HZ UINT8_C(0x07) +#define BMI2_GYR_ODR_100HZ UINT8_C(0x08) +#define BMI2_GYR_ODR_200HZ UINT8_C(0x09) +#define BMI2_GYR_ODR_400HZ UINT8_C(0x0A) +#define BMI2_GYR_ODR_800HZ UINT8_C(0x0B) +#define BMI2_GYR_ODR_1600HZ UINT8_C(0x0C) +#define BMI2_GYR_ODR_3200HZ UINT8_C(0x0D) + +/*! @name Gyroscope OIS Range */ +#define BMI2_GYR_OIS_250 UINT8_C(0x00) +#define BMI2_GYR_OIS_2000 UINT8_C(0x01) + +/*! @name Gyroscope Angular Rate Measurement Range */ +#define BMI2_GYR_RANGE_2000 UINT8_C(0x00) +#define BMI2_GYR_RANGE_1000 UINT8_C(0x01) +#define BMI2_GYR_RANGE_500 UINT8_C(0x02) +#define BMI2_GYR_RANGE_250 UINT8_C(0x03) +#define BMI2_GYR_RANGE_125 UINT8_C(0x04) + +/*! @name Mask definitions for gyroscope configuration register */ +#define BMI2_GYR_RANGE_MASK UINT8_C(0x07) +#define BMI2_GYR_OIS_RANGE_MASK UINT8_C(0x08) +#define BMI2_GYR_ODR_MASK UINT8_C(0x0F) +#define BMI2_GYR_BW_PARAM_MASK UINT8_C(0x30) +#define BMI2_GYR_NOISE_PERF_MODE_MASK UINT8_C(0x40) +#define BMI2_GYR_FILTER_PERF_MODE_MASK UINT8_C(0x80) + +/*! @name Bit position definitions for gyroscope configuration register */ +#define BMI2_GYR_OIS_RANGE_POS UINT8_C(0x03) +#define BMI2_GYR_BW_PARAM_POS UINT8_C(0x04) +#define BMI2_GYR_NOISE_PERF_MODE_POS UINT8_C(0x06) +#define BMI2_GYR_FILTER_PERF_MODE_POS UINT8_C(0x07) + +/******************************************************************************/ +/*! @name Auxiliary Macro Definitions */ +/******************************************************************************/ +/*! @name Auxiliary Output Data Rate */ +#define BMI2_AUX_ODR_RESERVED UINT8_C(0x00) +#define BMI2_AUX_ODR_0_78HZ UINT8_C(0x01) +#define BMI2_AUX_ODR_1_56HZ UINT8_C(0x02) +#define BMI2_AUX_ODR_3_12HZ UINT8_C(0x03) +#define BMI2_AUX_ODR_6_25HZ UINT8_C(0x04) +#define BMI2_AUX_ODR_12_5HZ UINT8_C(0x05) +#define BMI2_AUX_ODR_25HZ UINT8_C(0x06) +#define BMI2_AUX_ODR_50HZ UINT8_C(0x07) +#define BMI2_AUX_ODR_100HZ UINT8_C(0x08) +#define BMI2_AUX_ODR_200HZ UINT8_C(0x09) +#define BMI2_AUX_ODR_400HZ UINT8_C(0x0A) +#define BMI2_AUX_ODR_800HZ UINT8_C(0x0B) + +/*! @name Macro to define burst read lengths for both manual and auto modes */ +#define BMI2_AUX_READ_LEN_0 UINT8_C(0x00) +#define BMI2_AUX_READ_LEN_1 UINT8_C(0x01) +#define BMI2_AUX_READ_LEN_2 UINT8_C(0x02) +#define BMI2_AUX_READ_LEN_3 UINT8_C(0x03) + +/*! @name Mask definitions for auxiliary interface configuration register */ +#define BMI2_AUX_SET_I2C_ADDR_MASK UINT8_C(0xFE) +#define BMI2_AUX_MAN_MODE_EN_MASK UINT8_C(0x80) +#define BMI2_AUX_FCU_WR_EN_MASK UINT8_C(0x40) +#define BMI2_AUX_MAN_READ_BURST_MASK UINT8_C(0x0C) +#define BMI2_AUX_READ_BURST_MASK UINT8_C(0x03) +#define BMI2_AUX_ODR_EN_MASK UINT8_C(0x0F) +#define BMI2_AUX_OFFSET_READ_OUT_MASK UINT8_C(0xF0) + +/*! @name Bit positions for auxiliary interface configuration register */ +#define BMI2_AUX_SET_I2C_ADDR_POS UINT8_C(0x01) +#define BMI2_AUX_MAN_MODE_EN_POS UINT8_C(0x07) +#define BMI2_AUX_FCU_WR_EN_POS UINT8_C(0x06) +#define BMI2_AUX_MAN_READ_BURST_POS UINT8_C(0x02) +#define BMI2_AUX_OFFSET_READ_OUT_POS UINT8_C(0x04) + +/******************************************************************************/ +/*! @name FIFO Macro Definitions */ +/******************************************************************************/ +/*! @name Macros to define virtual FIFO frame mode */ +#define BMI2_FIFO_VIRT_FRM_MODE UINT8_C(0x03) + +/*! @name FIFO Header Mask definitions */ +#define BMI2_FIFO_HEADER_ACC_FRM UINT8_C(0x84) +#define BMI2_FIFO_HEADER_AUX_FRM UINT8_C(0x90) +#define BMI2_FIFO_HEADER_GYR_FRM UINT8_C(0x88) +#define BMI2_FIFO_HEADER_GYR_ACC_FRM UINT8_C(0x8C) +#define BMI2_FIFO_HEADER_AUX_ACC_FRM UINT8_C(0x94) +#define BMI2_FIFO_HEADER_AUX_GYR_FRM UINT8_C(0x98) +#define BMI2_FIFO_HEADER_ALL_FRM UINT8_C(0x9C) +#define BMI2_FIFO_HEADER_SENS_TIME_FRM UINT8_C(0x44) +#define BMI2_FIFO_HEADER_SKIP_FRM UINT8_C(0x40) +#define BMI2_FIFO_HEADER_INPUT_CFG_FRM UINT8_C(0x48) +#define BMI2_FIFO_HEAD_OVER_READ_MSB UINT8_C(0x80) +#define BMI2_FIFO_VIRT_ACT_RECOG_FRM UINT8_C(0xC8) + +/*! @name BMI2 sensor selection for header-less frames */ +#define BMI2_FIFO_HEAD_LESS_ACC_FRM UINT8_C(0x40) +#define BMI2_FIFO_HEAD_LESS_AUX_FRM UINT8_C(0x20) +#define BMI2_FIFO_HEAD_LESS_GYR_FRM UINT8_C(0x80) +#define BMI2_FIFO_HEAD_LESS_GYR_AUX_FRM UINT8_C(0xA0) +#define BMI2_FIFO_HEAD_LESS_GYR_ACC_FRM UINT8_C(0xC0) +#define BMI2_FIFO_HEAD_LESS_AUX_ACC_FRM UINT8_C(0x60) +#define BMI2_FIFO_HEAD_LESS_ALL_FRM UINT8_C(0xE0) + +/*! @name Mask definitions for FIFO frame content configuration */ +#define BMI2_FIFO_STOP_ON_FULL UINT16_C(0x0001) +#define BMI2_FIFO_TIME_EN UINT16_C(0x0002) +#define BMI2_FIFO_TAG_INT1 UINT16_C(0x0300) +#define BMI2_FIFO_TAG_INT2 UINT16_C(0x0C00) +#define BMI2_FIFO_HEADER_EN UINT16_C(0x1000) +#define BMI2_FIFO_AUX_EN UINT16_C(0x2000) +#define BMI2_FIFO_ACC_EN UINT16_C(0x4000) +#define BMI2_FIFO_GYR_EN UINT16_C(0x8000) +#define BMI2_FIFO_ALL_EN UINT16_C(0xE000) + +/*! @name FIFO sensor data lengths */ +#define BMI2_FIFO_ACC_LENGTH UINT8_C(6) +#define BMI2_FIFO_GYR_LENGTH UINT8_C(6) +#define BMI2_FIFO_AUX_LENGTH UINT8_C(8) +#define BMI2_FIFO_ACC_AUX_LENGTH UINT8_C(14) +#define BMI2_FIFO_GYR_AUX_LENGTH UINT8_C(14) +#define BMI2_FIFO_ACC_GYR_LENGTH UINT8_C(12) +#define BMI2_FIFO_ALL_LENGTH UINT8_C(20) +#define BMI2_SENSOR_TIME_LENGTH UINT8_C(3) +#define BMI2_FIFO_CONFIG_LENGTH UINT8_C(2) +#define BMI2_FIFO_WM_LENGTH UINT8_C(2) +#define BMI2_MAX_VALUE_FIFO_FILTER UINT8_C(1) +#define BMI2_FIFO_DATA_LENGTH UINT8_C(2) +#define BMI2_FIFO_LENGTH_MSB_BYTE UINT8_C(1) +#define BMI2_FIFO_INPUT_CFG_LENGTH UINT8_C(4) +#define BMI2_FIFO_SKIP_FRM_LENGTH UINT8_C(1) + +/*! @name FIFO sensor virtual data lengths: sensor data plus sensor time */ +#define BMI2_FIFO_VIRT_ACC_LENGTH UINT8_C(9) +#define BMI2_FIFO_VIRT_GYR_LENGTH UINT8_C(9) +#define BMI2_FIFO_VIRT_AUX_LENGTH UINT8_C(11) +#define BMI2_FIFO_VIRT_ACC_AUX_LENGTH UINT8_C(17) +#define BMI2_FIFO_VIRT_GYR_AUX_LENGTH UINT8_C(17) +#define BMI2_FIFO_VIRT_ACC_GYR_LENGTH UINT8_C(15) +#define BMI2_FIFO_VIRT_ALL_LENGTH UINT8_C(23) + +/*! @name FIFO sensor virtual data lengths: activity recognition */ +#define BMI2_FIFO_VIRT_ACT_DATA_LENGTH UINT8_C(6) +#define BMI2_FIFO_VIRT_ACT_TIME_LENGTH UINT8_C(4) +#define BMI2_FIFO_VIRT_ACT_TYPE_LENGTH UINT8_C(1) +#define BMI2_FIFO_VIRT_ACT_STAT_LENGTH UINT8_C(1) + +/*! @name BMI2 FIFO data filter modes */ +#define BMI2_FIFO_UNFILTERED_DATA UINT8_C(0) +#define BMI2_FIFO_FILTERED_DATA UINT8_C(1) + +/*! @name FIFO frame masks */ +#define BMI2_FIFO_LSB_CONFIG_CHECK UINT8_C(0x00) +#define BMI2_FIFO_MSB_CONFIG_CHECK UINT8_C(0x80) +#define BMI2_FIFO_TAG_INTR_MASK UINT8_C(0xFF) + +/*! @name BMI2 Mask definitions of FIFO configuration registers */ +#define BMI2_FIFO_CONFIG_0_MASK UINT16_C(0x0003) +#define BMI2_FIFO_CONFIG_1_MASK UINT16_C(0xFF00) + +/*! @name FIFO self wake-up mask definition */ +#define BMI2_FIFO_SELF_WAKE_UP_MASK UINT8_C(0x02) + +/*! @name FIFO down sampling mask definition */ +#define BMI2_ACC_FIFO_DOWNS_MASK UINT8_C(0x70) +#define BMI2_GYR_FIFO_DOWNS_MASK UINT8_C(0x07) + +/*! @name FIFO down sampling bit positions */ +#define BMI2_ACC_FIFO_DOWNS_POS UINT8_C(0x04) + +/*! @name FIFO filter mask definition */ +#define BMI2_ACC_FIFO_FILT_DATA_MASK UINT8_C(0x80) +#define BMI2_GYR_FIFO_FILT_DATA_MASK UINT8_C(0x08) + +/*! @name FIFO filter bit positions */ +#define BMI2_ACC_FIFO_FILT_DATA_POS UINT8_C(0x07) +#define BMI2_GYR_FIFO_FILT_DATA_POS UINT8_C(0x03) + +/*! @name FIFO byte counter mask definition */ +#define BMI2_FIFO_BYTE_COUNTER_MSB_MASK UINT8_C(0x3F) + +/*! @name FIFO self wake-up bit positions */ +#define BMI2_FIFO_SELF_WAKE_UP_POS UINT8_C(0x01) + +/*! @name Mask Definitions for Virtual FIFO frames */ +#define BMI2_FIFO_VIRT_FRM_MODE_MASK UINT8_C(0xC0) +#define BMI2_FIFO_VIRT_PAYLOAD_MASK UINT8_C(0x3C) + +/*! @name Bit Positions for Virtual FIFO frames */ +#define BMI2_FIFO_VIRT_FRM_MODE_POS UINT8_C(0x06) +#define BMI2_FIFO_VIRT_PAYLOAD_POS UINT8_C(0x02) + +/******************************************************************************/ +/*! @name Interrupt Macro Definitions */ +/******************************************************************************/ +/*! @name BMI2 Interrupt Modes */ +/* Non latched */ +#define BMI2_INT_NON_LATCH UINT8_C(0) +/* Permanently latched */ +#define BMI2_INT_LATCH UINT8_C(1) + +/*! @name BMI2 Interrupt Pin Behavior */ +#define BMI2_INT_PUSH_PULL UINT8_C(0) +#define BMI2_INT_OPEN_DRAIN UINT8_C(1) + +/*! @name BMI2 Interrupt Pin Level */ +#define BMI2_INT_ACTIVE_LOW UINT8_C(0) +#define BMI2_INT_ACTIVE_HIGH UINT8_C(1) + +/*! @name BMI2 Interrupt Output Enable */ +#define BMI2_INT_OUTPUT_DISABLE UINT8_C(0) +#define BMI2_INT_OUTPUT_ENABLE UINT8_C(1) + +/*! @name BMI2 Interrupt Input Enable */ +#define BMI2_INT_INPUT_DISABLE UINT8_C(0) +#define BMI2_INT_INPUT_ENABLE UINT8_C(1) + +/*! @name Mask definitions for interrupt pin configuration */ +#define BMI2_INT_LATCH_MASK UINT8_C(0x01) +#define BMI2_INT_LEVEL_MASK UINT8_C(0x02) +#define BMI2_INT_OPEN_DRAIN_MASK UINT8_C(0x04) +#define BMI2_INT_OUTPUT_EN_MASK UINT8_C(0x08) +#define BMI2_INT_INPUT_EN_MASK UINT8_C(0x10) + +/*! @name Bit position definitions for interrupt pin configuration */ +#define BMI2_INT_LEVEL_POS UINT8_C(0x01) +#define BMI2_INT_OPEN_DRAIN_POS UINT8_C(0x02) +#define BMI2_INT_OUTPUT_EN_POS UINT8_C(0x03) +#define BMI2_INT_INPUT_EN_POS UINT8_C(0x04) + +/*! @name Mask definitions for data interrupt mapping */ +#define BMI2_FFULL_INT UINT8_C(0x01) +#define BMI2_FWM_INT UINT8_C(0x02) +#define BMI2_DRDY_INT UINT8_C(0x04) +#define BMI2_ERR_INT UINT8_C(0x08) + +/*! @name Mask definitions for data interrupt status bits */ +#define BMI2_FFULL_INT_STATUS_MASK UINT16_C(0x0100) +#define BMI2_FWM_INT_STATUS_MASK UINT16_C(0x0200) +#define BMI2_ERR_INT_STATUS_MASK UINT16_C(0x0400) +#define BMI2_AUX_DRDY_INT_MASK UINT16_C(0x2000) +#define BMI2_GYR_DRDY_INT_MASK UINT16_C(0x4000) +#define BMI2_ACC_DRDY_INT_MASK UINT16_C(0x8000) + +/*! @name Maximum number of interrupt pins */ +#define BMI2_INT_PIN_MAX_NUM UINT8_C(2) + +/*! @name Macro for mapping feature interrupts */ +#define BMI2_FEAT_INT_DISABLE UINT8_C(0) +#define BMI2_FEAT_INTA UINT8_C(1) +#define BMI2_FEAT_INTB UINT8_C(2) +#define BMI2_FEAT_INTC UINT8_C(3) +#define BMI2_FEAT_INTD UINT8_C(4) +#define BMI2_FEAT_INTE UINT8_C(5) +#define BMI2_FEAT_INTF UINT8_C(6) +#define BMI2_FEAT_INTG UINT8_C(7) +#define BMI2_FEAT_INTH UINT8_C(8) +#define BMI2_FEAT_INT_MAX UINT8_C(9) + +/******************************************************************************/ +/*! @name OIS Interface Macro Definitions */ +/******************************************************************************/ +/*! @name Mask definitions for interface configuration register */ +#define BMI2_OIS_IF_EN_MASK UINT8_C(0x10) +#define BMI2_AUX_IF_EN_MASK UINT8_C(0x20) + +/*! @name Bit positions for OIS interface enable */ +#define BMI2_OIS_IF_EN_POS UINT8_C(0x04) +#define BMI2_AUX_IF_EN_POS UINT8_C(0x05) + +/******************************************************************************/ +/*! @name Macro Definitions for Axes re-mapping */ +/******************************************************************************/ +/*! @name Macros for the user-defined values of axes and their polarities */ +#define BMI2_X UINT8_C(0x01) +#define BMI2_NEG_X UINT8_C(0x09) +#define BMI2_Y UINT8_C(0x02) +#define BMI2_NEG_Y UINT8_C(0x0A) +#define BMI2_Z UINT8_C(0x04) +#define BMI2_NEG_Z UINT8_C(0x0C) +#define BMI2_AXIS_MASK UINT8_C(0x07) +#define BMI2_AXIS_SIGN UINT8_C(0x08) + +/******************************************************************************/ +/*! @name Macro Definitions for offset and gain compensation */ +/******************************************************************************/ +/*! @name Mask definitions of gyroscope offset compensation registers */ +#define BMI2_GYR_GAIN_EN_MASK UINT8_C(0x80) +#define BMI2_GYR_OFF_COMP_EN_MASK UINT8_C(0x40) + +/*! @name Bit positions of gyroscope offset compensation registers */ +#define BMI2_GYR_OFF_COMP_EN_POS UINT8_C(0x06) + +/*! @name Mask definitions of gyroscope user-gain registers */ +#define BMI2_GYR_USR_GAIN_X_MASK UINT8_C(0x7F) +#define BMI2_GYR_USR_GAIN_Y_MASK UINT8_C(0x7F) +#define BMI2_GYR_USR_GAIN_Z_MASK UINT8_C(0x7F) + +/*! @name Bit positions of gyroscope offset compensation registers */ +#define BMI2_GYR_GAIN_EN_POS UINT8_C(0x07) + +/******************************************************************************/ +/*! @name Macro Definitions for internal status */ +/******************************************************************************/ +#define BMI2_NOT_INIT UINT8_C(0x00) +#define BMI2_INIT_OK UINT8_C(0x01) +#define BMI2_INIT_ERR UINT8_C(0x02) +#define BMI2_DRV_ERR UINT8_C(0x03) +#define BMI2_SNS_STOP UINT8_C(0x04) +#define BMI2_NVM_ERROR UINT8_C(0x05) +#define BMI2_START_UP_ERROR UINT8_C(0x06) +#define BMI2_COMPAT_ERROR UINT8_C(0x07) +#define BMI2_VFM_SKIPPED UINT8_C(0x10) +#define BMI2_AXES_MAP_ERROR UINT8_C(0x20) +#define BMI2_ODR_50_HZ_ERROR UINT8_C(0x40) +#define BMI2_ODR_HIGH_ERROR UINT8_C(0x80) + +/******************************************************************************/ +/*! @name Function Pointers */ +/******************************************************************************/ +/*! For interfacing to the I2C or SPI read functions */ +typedef int8_t (*bmi2_read_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len); +/*! For interfacing to the I2C or SPI write functions */ +typedef int8_t (*bmi2_write_fptr_t)(uint8_t dev_addr, uint8_t reg_addr, const uint8_t *data, uint16_t len); +/*! For interfacing to the delay function */ +typedef void (*bmi2_delay_fptr_t)(uint32_t period); + +/******************************************************************************/ +/*! @name Enum Declarations */ +/******************************************************************************/ +/*! @name Enum to define BMI2 sensor interfaces */ +enum bmi2_intf_type { + BMI2_SPI_INTERFACE = 1, + BMI2_I2C_INTERFACE +}; + +/*! @name Enum to define BMI2 sensor configuration errors for accelerometer + * and gyroscope + */ +enum bmi2_sensor_config_error { + BMI2_NO_ERROR, + BMI2_ACC_ERROR, + BMI2_GYR_ERROR, + BMI2_ACC_GYR_ERROR +}; + +/*! @name Enum to define interrupt lines */ +enum bmi2_hw_int_pin { + BMI2_INT_NONE, + BMI2_INT1, + BMI2_INT2, + BMI2_INT_BOTH, + BMI2_INT_PIN_MAX +}; + +/*! @name Enum for the position of the wearable device */ +enum bmi2_wear_arm_pos { + BMI2_ARM_LEFT, + BMI2_ARM_RIGHT +}; + +/*! @name Enum to display type of activity recognition */ +enum bmi2_act_recog_type { + BMI2_ACT_UNKNOWN, + BMI2_ACT_STILL, + BMI2_ACT_WALK, + BMI2_ACT_RUN, + BMI2_ACT_BIKE, + BMI2_ACT_VEHICLE, + BMI2_ACT_TILTED +}; + +/*! @name Enum to display activity recognition status */ +enum bmi2_act_recog_stat { + BMI2_ACT_START = 1, + BMI2_ACT_END +}; + +/******************************************************************************/ +/*! @name Structure Declarations */ +/******************************************************************************/ +/*! @name Structure to store the compensated user-gain data of gyroscope */ +struct bmi2_gyro_user_gain_data { + /*! x-axis */ + int8_t x; + /*! y-axis */ + int8_t y; + /*! z-axis */ + int8_t z; +}; + +/*! @name Structure to store the re-mapped axis */ +struct bmi2_remap { + /*! Re-mapped x-axis */ + uint8_t x; + /*! Re-mapped y-axis */ + uint8_t y; + /*! Re-mapped z-axis */ + uint8_t z; +}; + +/*! @name Structure to store the value of re-mapped axis and its sign */ +struct bmi2_axes_remap { + /*! Re-mapped x-axis */ + uint8_t x_axis; + /*! Re-mapped y-axis */ + uint8_t y_axis; + /*! Re-mapped z-axis */ + uint8_t z_axis; + /*! Re-mapped x-axis sign */ + int16_t x_axis_sign; + /*! Re-mapped y-axis sign */ + int16_t y_axis_sign; + /*! Re-mapped z-axis sign */ + int16_t z_axis_sign; +}; + +/*! @name Structure to define the type of sensor and its interrupt pin */ +struct bmi2_sens_int_config { + /*! Defines the type of sensor */ + uint8_t type; + /*! Type of interrupt pin */ + enum bmi2_hw_int_pin hw_int_pin; +}; + +/*! @name Structure to define the output configuration value of features */ +struct bmi2_int_map { + /*! Output configuration value of sig-motion */ + uint8_t sig_mot_out_conf; + /*! Output configuration value of any-motion */ + uint8_t any_mot_out_conf; + /*! Output configuration value of no-motion */ + uint8_t no_mot_out_conf; + /*! Output configuration value of step-detector */ + uint8_t step_det_out_conf; + /*! Output configuration value of step-activity */ + uint8_t step_act_out_conf; + /*! Output configuration value of tilt */ + uint8_t tilt_out_conf; + /*! Output configuration value of pick-up */ + uint8_t pick_up_out_conf; + /*! Output configuration value of glance */ + uint8_t glance_out_conf; + /*! Output configuration value of wake-up */ + uint8_t wake_up_out_conf; + /*! Output configuration value of orientation */ + uint8_t orient_out_conf; + /*! Output configuration value of high-g */ + uint8_t high_g_out_conf; + /*! Output configuration value of low-g */ + uint8_t low_g_out_conf; + /*! Output configuration value of flat */ + uint8_t flat_out_conf; + /*! Output configuration value of S4S */ + uint8_t ext_sync_out_conf; + /*! Output configuration value of wrist gesture */ + uint8_t wrist_gest_out_conf; + /*! Output configuration value of wrist wear wake-up */ + uint8_t wrist_wear_wake_up_out_conf; +}; + +/*! @name Structure to define output for activity recognition */ +struct bmi2_act_recog_output { + /*! Time stamp */ + uint32_t time_stamp; + /*! Type of activity */ + uint8_t type; + /*! Status of the activity */ + uint8_t stat; +}; + +/*! @name Structure to define FIFO frame configuration */ +struct bmi2_fifo_frame { + /*! Pointer to FIFO data */ + uint8_t *data; + /*! Number of user defined bytes of FIFO to be read */ + uint16_t length; + /*! Defines header/header-less mode */ + uint8_t header_enable; + /*! Enables type of data to be streamed - accelerometer, auxiliary or + gyroscope */ + uint16_t data_enable; + /*! To index accelerometer bytes */ + uint16_t acc_byte_start_idx; + /*! To index activity output bytes */ + uint16_t act_recog_byte_start_idx; + /*! To index auxiliary bytes */ + uint16_t aux_byte_start_idx; + /*! To index gyroscope bytes */ + uint16_t gyr_byte_start_idx; + /*! FIFO sensor time */ + uint32_t sensor_time; + /*! Skipped frame count */ + uint8_t skipped_frame_count; + /*! Type of data interrupt to be mapped */ + uint8_t data_int_map; + /*! Water-mark level for water-mark interrupt */ + uint16_t wm_lvl; + /*! Accelerometer frame length */ + uint8_t acc_frm_len; + /*! Gyroscope frame length */ + uint8_t gyr_frm_len; + /*! Auxiliary frame length */ + uint8_t aux_frm_len; + /*! Accelerometer and gyroscope frame length */ + uint8_t acc_gyr_frm_len; + /*! Accelerometer and auxiliary frame length */ + uint8_t acc_aux_frm_len; + /*! Gyroscope and auxiliary frame length */ + uint8_t aux_gyr_frm_len; + /*! Accelerometer, Gyroscope and auxiliary frame length */ + uint8_t all_frm_len; +}; + +/*! @name Structure to define Interrupt pin configuration */ +struct bmi2_int_pin_cfg { + /*! Configure level of interrupt pin */ + uint8_t lvl; + /*! Configure behavior of interrupt pin */ + uint8_t od; + /*! Output enable for interrupt pin */ + uint8_t output_en; + /*! Input enable for interrupt pin */ + uint8_t input_en; +}; + +/*! @name Structure to define interrupt pin type, mode and configurations */ +struct bmi2_int_pin_config { + /*! Interrupt pin type: INT1 or INT2 or BOTH */ + uint8_t pin_type; + /*! Latched or non-latched mode*/ + uint8_t int_latch; + /*! Structure to define Interrupt pin configuration */ + struct bmi2_int_pin_cfg pin_cfg[BMI2_INT_PIN_MAX_NUM]; +}; + +/*! @name Structure to define an array of 8 auxiliary data bytes */ +struct bmi2_aux_fifo_data { + /*! Auxiliary data */ + uint8_t data[8]; + /*! Sensor time for virtual frames */ + uint32_t virt_sens_time; +}; + +/*! @name Structure to define accelerometer and gyroscope sensor axes and + sensor time for virtual frames */ +struct bmi2_sens_axes_data { + /*! Data in x-axis */ + int16_t x; + /*! Data in y-axis */ + int16_t y; + /*! Data in z-axis */ + int16_t z; + /*! Sensor time for virtual frames */ + uint32_t virt_sens_time; +}; + +/*! @name Structure to define gyroscope saturation status of user gain */ +struct bmi2_gyr_user_gain_status { + /*! Status in x-axis */ + uint8_t sat_x; + /*! Status in y-axis */ + uint8_t sat_y; + /*! Status in z-axis */ + uint8_t sat_z; +}; + +/*! @name Structure to define NVM error status */ +struct bmi2_nvm_err_status { + /*! NVM load action error */ + uint8_t load_error; + /*! NVM program action error */ + uint8_t prog_error; + /*! NVM erase action error */ + uint8_t erase_error; + /*! NVM program limit exceeded */ + uint8_t exceed_error; + /*! NVM privilege error */ + uint8_t privil_error; +}; + +/*! @name Structure to define VFRM error status */ +struct bmi2_vfrm_err_status { + /*! VFRM lock acquire error */ + uint8_t lock_error; + /*! VFRM write error */ + uint8_t write_error; + /*! VFRM fatal err */ + uint8_t fatal_error; +}; + +/*! @name Structure to define orientation output */ +struct bmi2_orientation_output { + /*! Orientation portrait landscape */ + uint8_t portrait_landscape; + /*! Orientation face-up down */ + uint8_t faceup_down; +}; + +/*! @name Union to define BMI2 sensor data */ +union bmi2_sens_data { + /*! Accelerometer axes data */ + struct bmi2_sens_axes_data acc; + /*! Gyroscope axes data */ + struct bmi2_sens_axes_data gyr; + /*! Auxiliary sensor data */ + uint8_t aux_data[BMI2_AUX_NUM_BYTES]; + /*! Step counter output */ + uint32_t step_counter_output; + /*! Step activity output */ + uint8_t activity_output; + /*! Orientation output */ + struct bmi2_orientation_output orient_output; + /*! High-g output */ + uint8_t high_g_output; + /*! Gyroscope user gain saturation status */ + struct bmi2_gyr_user_gain_status gyro_user_gain_status; + /*! NVM error status */ + struct bmi2_nvm_err_status nvm_status; + /*! Virtual frame error status */ + struct bmi2_vfrm_err_status vfrm_status; + /*! Wrist gesture output */ + uint8_t wrist_gest; + /*! Gyroscope cross sense value of z axis */ + int16_t correction_factor_zx; +}; + +/*! @name Structure to define type of sensor and their respective data */ +struct bmi2_sensor_data { + /*! Defines the type of sensor */ + uint8_t type; + /*! Defines various sensor data */ + union bmi2_sens_data sens_data; +}; + +/*! @name Structure to define accelerometer configuration */ +struct bmi2_accel_config { + /*! Output data rate in Hz */ + uint8_t odr; + /*! Bandwidth parameter */ + uint8_t bwp; + /*! Filter performance mode */ + uint8_t filter_perf; + /*! g-range */ + uint8_t range; +}; + +/*! @name Structure to define gyroscope configuration */ +struct bmi2_gyro_config { + /*! Output data rate in Hz */ + uint8_t odr; + /*! Bandwidth parameter */ + uint8_t bwp; + /*! Filter performance mode */ + uint8_t filter_perf; + /*! OIS Range */ + uint8_t ois_range; + /*! Gyroscope Range */ + uint8_t range; + /*! Selects noise performance */ + uint8_t noise_perf; +}; + +/*! @name Structure to define auxiliary sensor configuration */ +struct bmi2_aux_config { + /*! Enable/Disable auxiliary interface */ + uint8_t aux_en; + /*! Manual or Auto mode*/ + uint8_t manual_en; + /*! Enables FCU write command on auxiliary interface */ + uint8_t fcu_write_en; + /*! Read burst length for manual mode */ + uint8_t man_rd_burst; + /*! Read burst length for data mode */ + uint8_t aux_rd_burst; + /*! Output data rate */ + uint8_t odr; + /*! Read-out offset */ + uint8_t offset; + /*! I2c address of auxiliary sensor */ + uint8_t i2c_device_addr; + /*! Read address of auxiliary sensor */ + uint8_t read_addr; +}; + +/*! @name Structure to define any-motion configuration */ +struct bmi2_any_motion_config { + /*! Duration in 50Hz samples(20msec) */ + uint16_t duration; + /*! Acceleration slope threshold */ + uint16_t threshold; + /*! To select per x-axis */ + uint16_t select_x; + /*! To select per y-axis */ + uint16_t select_y; + /*! To select per z-axis */ + uint16_t select_z; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define no-motion configuration */ +struct bmi2_no_motion_config { + /*! Duration in 50Hz samples(20msec) */ + uint16_t duration; + /*! Acceleration slope threshold */ + uint16_t threshold; + /*! To select per x-axis */ + uint16_t select_x; + /*! To select per y-axis */ + uint16_t select_y; + /*! To select per z-axis */ + uint16_t select_z; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define sig-motion configuration */ +struct bmi2_sig_motion_config { + /*! Block size */ + uint16_t block_size; + /*! Parameter 2 */ + uint16_t param_2; + /*! Parameter 3 */ + uint16_t param_3; + /*! Parameter 4 */ + uint16_t param_4; + /*! Parameter 5 */ + uint16_t param_5; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define step counter/detector/activity configuration */ +struct bmi2_step_config { + /*! Water-mark level */ + uint16_t watermark_level; + /*! Reset counter */ + uint16_t reset_counter; + /*! Enable bits for enabling output into the register status bits + for step-detector */ + uint16_t out_conf_step_detector; + /*! Enable bits for enabling output into the register status bits + for step-activity */ + uint16_t out_conf_activity; +}; + +/*! @name Structure to define gyroscope user gain configuration */ +struct bmi2_gyro_user_gain_config { + /*! Gain update value for x-axis */ + uint16_t ratio_x; + /*! Gain update value for y-axis */ + uint16_t ratio_y; + /*! Gain update value for z-axis */ + uint16_t ratio_z; +}; + +/*! @name Structure to define tilt configuration */ +struct bmi2_tilt_config { + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define pick-up configuration */ +struct bmi2_pick_up_config { + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define glance detector configuration */ +struct bmi2_glance_det_config { + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define wake-up configuration */ +struct bmi2_wake_up_config { + /*! Wake-up sensitivity */ + uint16_t sensitivity; + /*! Enable -> Single Tap; Disable -> Double Tap */ + uint16_t single_tap_en; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define orientation configuration */ +struct bmi2_orient_config { + /*! Upside/down detection */ + uint16_t ud_en; + /*! Symmetrical, high or low Symmetrical */ + uint16_t mode; + /*! Blocking mode */ + uint16_t blocking; + /*! Threshold angle */ + uint16_t theta; + /*! Acceleration hysteresis for orientation detection */ + uint16_t hysteresis; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define high-g configuration */ +struct bmi2_high_g_config { + /*! Acceleration threshold */ + uint16_t threshold; + /*! Hysteresis */ + uint16_t hysteresis; + /*! To select per x-axis */ + uint16_t select_x; + /*! To select per y-axis */ + uint16_t select_y; + /*! To select per z-axis */ + uint16_t select_z; + /*! Duration interval */ + uint16_t duration; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define low-g configuration */ +struct bmi2_low_g_config { + /*! Acceleration threshold */ + uint16_t threshold; + /*! Hysteresis */ + uint16_t hysteresis; + /*! Duration interval */ + uint16_t duration; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define flat configuration */ +struct bmi2_flat_config { + /*! Theta angle for flat detection */ + uint16_t theta; + /*! Blocking mode */ + uint16_t blocking; + /*! Hysteresis for theta flat detection */ + uint16_t hysteresis; + /*! Holds the duration in 50Hz samples(20msec) */ + uint16_t hold_time; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define external sensor sync configuration */ +struct bmi2_ext_sens_sync_config { + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define wrist gesture configuration */ +struct bmi2_wrist_gest_config { + /*! Wearable arm (left or right) */ + uint16_t wear_arm; + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Structure to define wrist wear wake-up configuration */ +struct bmi2_wrist_wear_wake_up_config { + /*! Enable bits for enabling output into the register status bits */ + uint16_t out_conf; +}; + +/*! @name Union to define the sensor configurations */ +union bmi2_sens_config_types { + /*! Accelerometer configuration */ + struct bmi2_accel_config acc; + /*! Gyroscope configuration */ + struct bmi2_gyro_config gyr; + /*! Auxiliary configuration */ + struct bmi2_aux_config aux; + /*! Any-motion configuration */ + struct bmi2_any_motion_config any_motion; + /*! No-motion configuration */ + struct bmi2_no_motion_config no_motion; + /*! Sig_motion configuration */ + struct bmi2_sig_motion_config sig_motion; + /*! Step counter/detector/activity configuration */ + struct bmi2_step_config step_counter; + /*! Gyroscope user gain configuration */ + struct bmi2_gyro_user_gain_config gyro_gain_update; + /*! Tilt configuration */ + struct bmi2_tilt_config tilt; + /*! Pick-up configuration */ + struct bmi2_pick_up_config pick_up; + /*! Glance detector configuration */ + struct bmi2_glance_det_config glance_det; + /*! Wake-up configuration */ + struct bmi2_wake_up_config tap; + /*! Orientation configuration */ + struct bmi2_orient_config orientation; + /*! High-g configuration */ + struct bmi2_high_g_config high_g; + /*! Low-g configuration */ + struct bmi2_low_g_config low_g; + /*! Flat configuration */ + struct bmi2_flat_config flat; + /*! External sensor sync configuration */ + struct bmi2_ext_sens_sync_config ext_sens_sync; + /*! Wrist gesture configuration */ + struct bmi2_wrist_gest_config wrist_gest; + /*! Wrist wear wake-up configuration */ + struct bmi2_wrist_wear_wake_up_config wrist_wear_wake_up; +}; + +/*! @name Structure to define the type of the sensor and its configurations */ +struct bmi2_sens_config { + /*! Defines the type of sensor */ + uint8_t type; + /*! Defines various sensor configurations */ + union bmi2_sens_config_types cfg; +}; + +/*! @name Structure to define the feature configuration */ +struct bmi2_feature_config { + /*! Defines the type of sensor */ + uint8_t type; + /*! Page to where the feature is mapped */ + uint8_t page; + /*! Address of the feature */ + uint8_t start_addr; +}; + +/*! @name Structure to define BMI2 sensor configurations */ +struct bmi2_dev { + /*! Chip id of BMI2 */ + uint8_t chip_id; + /*! Device id of BMI2 */ + uint8_t dev_id; + /*! To store warnings */ + uint8_t info; + /*! Type of Interface */ + enum bmi2_intf_type intf; + /*! For switching from I2C to SPI */ + uint8_t dummy_byte; + /*! Resolution for FOC */ + uint8_t resolution; + /*! User set read/write length */ + uint16_t read_write_len; + /*! Pointer to the configuration data buffer address */ + const uint8_t *config_file_ptr; + /*! To define maximum page number */ + uint8_t page_max; + /*! To define maximum number of input sensors/features */ + uint8_t input_sens; + /*! To define maximum number of output sensors/features */ + uint8_t out_sens; + /*! Indicate manual enable for auxiliary communication */ + uint8_t aux_man_en; + /*! Defines manual read burst length for auxiliary communication */ + uint8_t aux_man_rd_burst_len; + /*! Array of feature input configuration structure */ + const struct bmi2_feature_config *feat_config; + /*! Array of feature output configuration structure */ + const struct bmi2_feature_config *feat_output; + /*! Structure to maintain a copy of feature out_conf values */ + struct bmi2_int_map int_map; + /*! Structure to maintain a copy of the re-mapped axis */ + struct bmi2_axes_remap remap; + /*! Flag to hold enable status of sensors */ + uint32_t sens_en_stat; + /*! Read function pointer */ + bmi2_read_fptr_t read; + /*! Write function pointer */ + bmi2_write_fptr_t write; + /*! Delay function pointer */ + bmi2_delay_fptr_t delay_ms; + /*! To store the gyroscope cross sensitivity value */ + int16_t gyr_cross_sens_zx; +}; + +#endif /* BMI2_DEFS_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Accuracy.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Accuracy.c new file mode 100755 index 0000000000000000000000000000000000000000..ae4a75e72be3aa10268112068f95eabe0b9fbf90 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Accuracy.c @@ -0,0 +1,922 @@ +/*======================================================================= + Accuracy Test Sample code for LC898128 +========================================================================*/ +#define __OISACCURACY__ + +//#include "math.h" +#include <linux/kernel.h> +#include "OisLc898128.h" +#include "Ois.h" +#include "Accuracy.h" + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A(int addr, int data); +extern void RamRead32A( unsigned short addr, void * data ); +extern void WitTim( unsigned short UsWitTim ); +extern UINT_8 FlashMultiRead( UINT_8 , UINT_32 , UINT_32 * , UINT_8 ); + +/* Raw data buffers */ +//Dual_Axis_t xy_raw_data[360/DEGSTEP + 1]; +//Dual_Axis_t xy_raw_data[360/3 + 1]; +//float xMaxAcc, yMaxAcc; +//float xLimit, yLimit; +#if 0 +#define ANGLE_LIMIT 0.105929591F +#define LIMIT_RANGE 190.0F +#else +#define ANGLE_LIMIT 0.091805644F +#define LIMIT_RANGE 170.0F +#define ANGLE_LIMIT_SMA 0.098867618F +#endif + +// Checking radius +#define DEGREE 0.65F // 0.65 degree +//#define ACCURACY 0.02F // Accuracy (2.6% of LMTDEG) 100um * 2% = 2um +#define ACCURACY 0.015F // Accuracy 0.75deg(100um)/50 = 2um + +// Parameter define +#define DEGSTEP 3 // Degree of one step (3‹) +#define WAIT_MSEC 10 // Each step wait time(msec) +#define LOOPTIME 3 // Read times at each step + +// Loop Gain Up +#define LPGSET 1.40 // 1.40(+3dB); 0.158(+4dB); 0.177(+5dB) + +// Constants +#define PI 3.14159 // ƒÎ +#define LMTDEG 0.75F // Limit degree by LGYROLMT + +#define HallX_hs 0x81F8 +#define HallY_hs 0x8200 + +static float fix2float(unsigned int fix) +{ + if((fix & 0x80000000) > 0) + { + return ((float)fix-(float)0x100000000)/(float)0x7FFFFFFF; + } else { + return (float)fix/(float)0x7FFFFFFF; + } +} + +static unsigned int float2fix(float f) +{ + if(f < 0) + { + return (unsigned int)(f * (float)0x7FFFFFFF + 0x100000000); + } else { + return (unsigned int)(f * (float)0x7FFFFFFF); + } +} + +void LoopGainSet(unsigned char flag, float db) +{ + static UINT_32 xHs, yHs; + static UINT_32 xLpGan, yLpGan; + + //Gain Change + if(flag) // 1:Gain Up + { + //Get Hs + RamRead32A(HallX_hs, &xHs); + RamRead32A(HallY_hs, &yHs); + + RamWrite32A(HallX_hs, (xHs & 0xFF000000) + 0x01000000 + (xHs & 0x00FFFFFF)); // Shift 2 bits + RamWrite32A(HallY_hs, (yHs & 0x0000FF00) + 0x00000100 + (yHs & 0xFFFF00FF)); // Shift 2 bits + + //Get LoopGain1 + RamRead32A(HallFilterCoeffX_hxgain1, &xLpGan); + RamRead32A(HallFilterCoeffY_hygain1, &yLpGan); + + RamWrite32A(HallFilterCoeffX_hxgain1, float2fix( fix2float(xLpGan) * db / 2)); // gain1 /2 + RamWrite32A(HallFilterCoeffY_hygain1, float2fix( fix2float(xLpGan) * db / 2)); // gain1 /2 + + } else { // 0:Restore + + // Restore Hs + RamWrite32A(HallX_hs, xHs); + RamWrite32A(HallY_hs, yHs); + + //Restore LoopGain1 + RamWrite32A(HallFilterCoeffX_hxgain1, xLpGan); + RamWrite32A(HallFilterCoeffY_hygain1, yLpGan); + } +} + +/*------------------------------------------------------------------- + Function Name: Accuracy + Param: none + Return: value = 0 (no NG point) + value > 0 (High byte: X total NG points; + Low byte: Y total NG points) +--------------------------------------------------------------------*/ +//unsigned short Accuracy() +#if 0 +unsigned short Accuracy(float ACCURACY, unsigned short RADIUS, unsigned short DEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3) +{ + float xpos, ypos; + unsigned int xhall_value, yhall_value; + float xMaxHall, yMaxHall; + unsigned short xng = 0, yng = 0; + unsigned short deg; + float xRadius, yRadius; + unsigned int xGyrogain, yGyrogain; + unsigned int xGLenz, yGLenz; + unsigned int xG2x4xb, yG2x4xb; + unsigned int xGoutG, yGoutG; + + // Get Gyro gain + RamRead32A(GyroFilterTableX_gxzoom, &xGyrogain); + RamRead32A(GyroFilterTableY_gyzoom, &yGyrogain); + + // Get Lenz + RamRead32A(GyroFilterTableX_gxlenz, &xGLenz); + RamRead32A(GyroFilterTableY_gylenz, &yGLenz); + + // Get Shift + RamRead32A(GyroFilterShiftX, &xG2x4xb); + RamRead32A(GyroFilterShiftY, &yG2x4xb); + + // Get Gyro out gain + RamRead32A(HallFilterCoeffX_hxgoutg, &xGoutG); + RamRead32A(HallFilterCoeffY_hygoutg, &yGoutG); + + // Calculate Radius (LIMIT_RANGE) /* •s–¾ */ +// xRadius = ANGLE_LIMIT * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * 8 * fabsf(fix2float(xGoutG)); +// yRadius = ANGLE_LIMIT * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * 8 * fabsf(fix2float(yGoutG)); + xRadius = ANGLE_LIMIT * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * (1 << (unsigned char)( xG2x4xb >> 8 )) * fabsf(fix2float(xGoutG)); + yRadius = ANGLE_LIMIT * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * (1 << (unsigned char)( yG2x4xb >> 8 )) * fabsf(fix2float(yGoutG)); + + // Calculate Limit + xLimit = ACCURACY / LIMIT_RANGE * xRadius; + yLimit = ACCURACY / LIMIT_RANGE * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * RADIUS / LIMIT_RANGE; + yRadius = yRadius * RADIUS / LIMIT_RANGE; + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check + xpos = xRadius * cos(0); + ypos = yRadius * sin(0); + RamWrite32A(HALL_RAM_HXOFF1, float2fix(xpos)); + RamWrite32A(HALL_RAM_HYOFF1, float2fix(ypos)); + WitTim(WAIT_MSEC1); + + for( deg = 0; deg <= 360; deg += DEGSTEP ) // 0-360 degree + { + xpos = xRadius * cos(deg * PI/180); + ypos = yRadius * sin(deg * PI/180); + RamWrite32A(HALL_RAM_HXOFF1, float2fix(xpos)); + RamWrite32A(HALL_RAM_HYOFF1, float2fix(ypos)); + + xMaxHall = 0; + yMaxHall = 0; + WitTim(WAIT_MSEC2); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim(WAIT_MSEC3); + RamRead32A( HALL_RAM_HXOUT0, &xhall_value ); + RamRead32A( HALL_RAM_HYOUT0, &yhall_value ); + if(fabsf(fix2float(xhall_value) - xpos) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value) - xpos; + if(fabsf(fix2float(yhall_value) - ypos) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value) - ypos; + } + + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + + // Save raw data + xy_raw_data[deg/DEGSTEP].xpos = xpos; + xy_raw_data[deg/DEGSTEP].xhall = xMaxHall + xpos; + xy_raw_data[deg/DEGSTEP].ypos = ypos; + xy_raw_data[deg/DEGSTEP].yhall = yMaxHall + ypos; + + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + + } + RamWrite32A(HALL_RAM_HXOFF1, 0); // x = center + RamWrite32A(HALL_RAM_HYOFF1, 0); // y = center + + return (xng << 8) | yng; +} +#endif +unsigned short Accuracy() +{ + float xpos, ypos; + UINT_32 xhall_value, yhall_value; + float xMaxHall, yMaxHall; + unsigned short xng = 0, yng = 0; + unsigned short deg; + float xRadius, yRadius; + UINT_32 xGyroLimit, yGyroLimit; + UINT_32 xGyrogain, yGyrogain; + UINT_32 xGLenz, yGLenz; + UINT_32 xShiftRG, yShiftRG; + UINT_32 xHav2, yHav2; + + + // Get GYROLIMT + RamRead32A(Gyro_Limiter_X, &xGyroLimit); + RamRead32A(Gyro_Limiter_Y, &yGyroLimit); + + // Get Gyro gain + RamRead32A(GyroFilterTableX_gxzoom, &xGyrogain); + RamRead32A(GyroFilterTableY_gyzoom, &yGyrogain); + + // Get Lenz + RamRead32A(GyroFilterTableX_gxlenz, &xGLenz); + RamRead32A(GyroFilterTableY_gylenz, &yGLenz); + + // Get ShiftRG + RamRead32A(GyroFilterShiftX, &xShiftRG); + RamRead32A(GyroFilterShiftY, &yShiftRG); + xShiftRG = 1 << ((xShiftRG & 0xFF00) >> 8); + yShiftRG = 1 << ((yShiftRG & 0xFF00) >> 8); + + // Calculate moving Range + xRadius = fabsf(fix2float(xGyroLimit)) * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * xShiftRG ; + yRadius = fabsf(fix2float(yGyroLimit)) * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * yShiftRG ; + + // Calculate Limit + xLimit = ACCURACY * xRadius; + yLimit = ACCURACY * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * DEGREE / LMTDEG; + yRadius = yRadius * DEGREE / LMTDEG; + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check +// xpos = xRadius * cos(0); +// ypos = yRadius * sin(0); + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + WitTim(100); + + for( deg = 0; deg <= 360; deg += DEGSTEP ) // 0-360 degree + { +// xpos = xRadius * cos(deg * PI/180); +// ypos = yRadius * sin(deg * PI/180); + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + + xMaxHall = 0; + yMaxHall = 0; + + RamRead32A( XMoveAvg_D2, &xHav2 ); + RamRead32A( YMoveAvg_D2, &yHav2 ); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim( WAIT_MSEC ); + RamRead32A( HALL_RAM_HXOUT2, &xhall_value ); + RamRead32A( HALL_RAM_HYOUT2, &yhall_value ); + if(fabsf(fix2float(xhall_value) + fix2float(xHav2)) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value) + fix2float(xHav2); + if(fabsf(fix2float(yhall_value) + fix2float(yHav2)) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value) + fix2float(yHav2); + } + + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + + // Save raw data + xy_raw_data[deg/DEGSTEP].xpos = fix2float(xHav2); + xy_raw_data[deg/DEGSTEP].xhall = xMaxHall + fix2float(xHav2); + xy_raw_data[deg/DEGSTEP].ypos = fix2float(yHav2); + xy_raw_data[deg/DEGSTEP].yhall = yMaxHall + fix2float(yHav2); + + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + + } + RamWrite32A(HALL_RAM_GYROX_OUT, 0); // x = center + RamWrite32A(HALL_RAM_GYROY_OUT, 0); // y = center + +TRACE(" xGyroLimit=%08x, xGyrogain=%08x, xGLenz=%08x, xShiftRG=%08x, xLimit=%f\n", xGyroLimit , xGyrogain , xGLenz , xShiftRG , xLimit); +TRACE(" yGyroLimit=%08x, yGyrogain=%08x, yGLenz=%08x, yShiftRG=%08x, yLimit=%f\n", yGyroLimit , yGyrogain , yGLenz , yShiftRG , yLimit); + return (xng << 8) | yng; +} + +UINT_16 HallCheck(void) +{ + short i; + unsigned short ret; + + // Change Loop Gain + LoopGainSet( 1, LPGSET ); + + // do Hall Accuracy test + ret = Accuracy(); + + // Restore Loop Gain + LoopGainSet( 0, LPGSET ); + + if(ret) + { + TRACE("\n VCM has NG points: X = %d, Y = %d", ret >> 8, ret & 0xff); + } else { + TRACE("\n VCM is good!"); + } + + // Max Accuracy + TRACE("\n X Max Accuracy = %f, Y Max Accuracy = %f", xMaxAcc, yMaxAcc); + + // Limit vale + TRACE("\n xLimit = %f, yLimit = %f", xLimit, yLimit); + + // Circle + for(i=0; i<=(360/DEGSTEP); i++) + { + TRACE("\n xPos = %f, xHall = %f, yPos = %f, yHall = %f", xy_raw_data[i].xpos, xy_raw_data[i].xhall, xy_raw_data[i].ypos, xy_raw_data[i].yhall); + } + return(ret); +} + +unsigned short AccuracyH(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3) +{ + float xpos, ypos; + unsigned int xhall_value, yhall_value; + float xMaxHall, yMaxHall; + unsigned short xng = 0, yng = 0; + unsigned short deg; + float xRadius, yRadius; + unsigned int xGyrogain, yGyrogain; + unsigned int xGLenz, yGLenz; + unsigned int xG2x4xb, yG2x4xb; + unsigned int xGoutG, yGoutG; + + // Get Gyro gain + RamRead32A(GyroFilterTableX_gxzoom, &xGyrogain); + RamRead32A(GyroFilterTableY_gyzoom, &yGyrogain); + + // Get Lenz + RamRead32A(GyroFilterTableX_gxlenz, &xGLenz); + RamRead32A(GyroFilterTableY_gylenz, &yGLenz); + + // Get Shift + RamRead32A(GyroFilterShiftX, &xG2x4xb); + RamRead32A(GyroFilterShiftY, &yG2x4xb); + + // Get Gyro out gain + RamRead32A(HallFilterCoeffX_hxgoutg, &xGoutG); + RamRead32A(HallFilterCoeffY_hygoutg, &yGoutG); + + // Calculate Radius (LIMIT_RANGE) /* •s–¾ */ +// xRadius = ANGLE_LIMIT * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * 8 * fabsf(fix2float(xGoutG)); +// yRadius = ANGLE_LIMIT * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * 8 * fabsf(fix2float(yGoutG)); + xRadius = ANGLE_LIMIT * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * (1 << (unsigned char)( xG2x4xb >> 8 )) * fabsf(fix2float(xGoutG)); + yRadius = ANGLE_LIMIT * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * (1 << (unsigned char)( yG2x4xb >> 8 )) * fabsf(fix2float(yGoutG)); + + // Calculate Limit + xLimit = flACCURACY / LIMIT_RANGE * xRadius; + yLimit = flACCURACY / LIMIT_RANGE * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * RADIUS / LIMIT_RANGE; + yRadius = yRadius * RADIUS / LIMIT_RANGE; + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check + xpos = xRadius * cos(0); + ypos = yRadius * sin(0); + RamWrite32A(HALL_RAM_HXOFF1, float2fix(xpos)); + RamWrite32A(HALL_RAM_HYOFF1, float2fix(ypos)); + WitTim(WAIT_MSEC1); + + for( deg = 0; deg <= 360; deg += usDEGSTEP ) // 0-360 degree + { + xpos = xRadius * cos(deg * PI/180); + ypos = yRadius * sin(deg * PI/180); + RamWrite32A(HALL_RAM_HXOFF1, float2fix(xpos)); + RamWrite32A(HALL_RAM_HYOFF1, float2fix(ypos)); + + xMaxHall = 0; + yMaxHall = 0; + WitTim(WAIT_MSEC2); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim(WAIT_MSEC3); + RamRead32A( HALL_RAM_HXOUT0, &xhall_value ); + RamRead32A( HALL_RAM_HYOUT0, &yhall_value ); + if(fabsf(fix2float(xhall_value) - xpos) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value) - xpos; + if(fabsf(fix2float(yhall_value) - ypos) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value) - ypos; + } + + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + + // Save raw data + xy_raw_data[deg/usDEGSTEP].xpos = xpos; + xy_raw_data[deg/usDEGSTEP].xhall = xMaxHall + xpos; + xy_raw_data[deg/usDEGSTEP].ypos = ypos; + xy_raw_data[deg/usDEGSTEP].yhall = yMaxHall + ypos; + + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + + } + RamWrite32A(HALL_RAM_HXOFF1, 0); // x = center + RamWrite32A(HALL_RAM_HYOFF1, 0); // y = center + + return (xng << 8) | yng; +} + +//unsigned short HallCheck(void) +UINT_16 HallCheckH(float flACCURACY, UINT_16 RADIUS, UINT_16 usDEGSTEP, UINT_16 WAIT_MSEC1, UINT_16 WAIT_MSEC2, UINT_16 WAIT_MSEC3) +{ + INT_16 i; +// unsigned short ret = Accuracy(); + UINT_16 ret = AccuracyH(flACCURACY, RADIUS, usDEGSTEP, WAIT_MSEC1, WAIT_MSEC2, WAIT_MSEC3); + + if(ret) + { + TRACE("\n VCM has NG points: X = %d, Y = %d", ret >> 8, ret & 0xff); + } else { + TRACE("\n VCM is good!"); + } + + // Max Accuracy + //TRACE("\n X Max Accuracy = %f, Y Max Accuracy = %f", xMaxAcc, yMaxAcc); + TRACE("\n X Max Accuracy = %d, Y Max Accuracy = %d", (int)(xMaxAcc*1000), (int)(yMaxAcc*1000)); + + // Limit vale + //TRACE("\n xLimit = %f, yLimit = %f", xLimit, yLimit); + TRACE("\n xLimit = %d, yLimit = %d", (int)(xLimit*1000), (int)(yLimit*1000)); + + // Circle + for(i=0; i<=(360/usDEGSTEP); i++) + { + //TRACE("\n xPos = %f, xHall = %f, yPos = %f, yHall = %f", xy_raw_data[i].xpos, xy_raw_data[i].xhall, xy_raw_data[i].ypos, xy_raw_data[i].yhall); + TRACE("\n xPos = %d, xHall = %d, yPos = %d, yHall = %d", (int)(xy_raw_data[i].xpos*1000), (int)(xy_raw_data[i].xhall*1000), (int)(xy_raw_data[i].ypos*1000), (int)(xy_raw_data[i].yhall*1000)); + } + + return( ret ); +} + +unsigned short AccuracyG(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3) +{ + float xpos, ypos; + unsigned int xhall_value, yhall_value; + float xMaxHall, yMaxHall; + unsigned short xng = 0, yng = 0; + unsigned short deg; + float xRadius, yRadius; + unsigned int xGyroLimit, yGyroLimit; + unsigned int xGyrogain, yGyrogain; + unsigned int xGLenz, yGLenz; + unsigned int xShiftRG, yShiftRG; + unsigned int xHav2, yHav2; + + // Get GYROLIMT + RamRead32A(Gyro_Limiter_X, &xGyroLimit); + RamRead32A(Gyro_Limiter_Y, &yGyroLimit); + + // Get Gyro gain + RamRead32A(GyroFilterTableX_gxzoom, &xGyrogain); + RamRead32A(GyroFilterTableY_gyzoom, &yGyrogain); + + // Get Lenz + RamRead32A(GyroFilterTableX_gxlenz, &xGLenz); + RamRead32A(GyroFilterTableY_gylenz, &yGLenz); + + // Get Shift + RamRead32A(GyroFilterShiftX, &xShiftRG); + RamRead32A(GyroFilterShiftY, &yShiftRG); + xShiftRG = 1 << ((xShiftRG & 0x0000FF00) >> 8); + yShiftRG = 1 << ((yShiftRG & 0x0000FF00) >> 8); + + // Calculate Radius (LIMIT_RANGE) /* •s–¾ */ + xRadius = fabsf(fix2float(xGyroLimit)) * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * xShiftRG ; + yRadius = fabsf(fix2float(yGyroLimit)) * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * yShiftRG ; + + // Calculate Limit + xLimit = flACCURACY / LIMIT_RANGE * xRadius; + yLimit = flACCURACY / LIMIT_RANGE * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * RADIUS / LIMIT_RANGE; + yRadius = yRadius * RADIUS / LIMIT_RANGE; + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check + xpos = xRadius * cos(0); + ypos = yRadius * sin(0); + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + WitTim(WAIT_MSEC1); + + for( deg = 0; deg <= 360; deg += usDEGSTEP ) // 0-360 degree + { + xpos = xRadius * cos(deg * PI/180); + ypos = yRadius * sin(deg * PI/180); + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + + xMaxHall = 0; + yMaxHall = 0; + WitTim(WAIT_MSEC2); + RamRead32A( XMoveAvg_D2, &xHav2 ); + RamRead32A( YMoveAvg_D2, &yHav2 ); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim(WAIT_MSEC3); + RamRead32A( HALL_RAM_HXOUT2, &xhall_value ); + RamRead32A( HALL_RAM_HYOUT2, &yhall_value ); + if(fabsf(fix2float(xhall_value) + fix2float(xHav2)) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value) + fix2float(xHav2); + if(fabsf(fix2float(yhall_value) + fix2float(yHav2)) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value) + fix2float(yHav2); + } +TRACE( "( xpos, xHax2, xhall, xMax ) = ( %f, %f, %f, %f)\n", xpos , fix2float(xHav2) , fix2float(xhall_value), xMaxHall ); +TRACE( "( ypos, yHax2, yhall, yMax ) = ( %f, %f, %f, %f)\n", ypos , fix2float(yHav2) , fix2float(yhall_value), yMaxHall ); + + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + + // Save raw data + xy_raw_data[deg/usDEGSTEP].xpos = fix2float(xHav2); + xy_raw_data[deg/usDEGSTEP].xhall = xMaxHall + fix2float(xHav2); + xy_raw_data[deg/usDEGSTEP].ypos = fix2float(yHav2); + xy_raw_data[deg/usDEGSTEP].yhall = yMaxHall + fix2float(yHav2); + + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + + } + RamWrite32A(HALL_RAM_GYROX_OUT, 0); // x = center + RamWrite32A(HALL_RAM_GYROY_OUT, 0); // y = center + + return (xng << 8) | yng; +} + +//unsigned short HallCheck(void) +UINT_16 HallCheckG(float flACCURACY, UINT_16 RADIUS, UINT_16 usDEGSTEP, UINT_16 WAIT_MSEC1, UINT_16 WAIT_MSEC2, UINT_16 WAIT_MSEC3) +{ + INT_16 i; + UINT_16 ret; + + // Change Loop Gain + LoopGainSet( 1, LPGSET ); + + // unsigned short ret = Accuracy(); + ret = AccuracyG(flACCURACY, RADIUS, usDEGSTEP, WAIT_MSEC1, WAIT_MSEC2, WAIT_MSEC3); + + // Restore Loop Gain + LoopGainSet( 0, LPGSET ); + + if(ret) + { + TRACE("\n VCM has NG points: X = %d, Y = %d", ret >> 8, ret & 0xff); + } else { + TRACE("\n VCM is good!"); + } + + // Max Accuracy + //TRACE("\n X Max Accuracy = %f, Y Max Accuracy = %f", xMaxAcc, yMaxAcc); + TRACE("\n X Max Accuracy = %d, Y Max Accuracy = %d", (int)(xMaxAcc*1000), (int)(yMaxAcc*1000)); + + // Limit vale + //TRACE("\n xLimit = %f, yLimit = %f", xLimit, yLimit); + TRACE("\n xLimit = %d, yLimit = %d", (int)(xLimit*1000), (int)(yLimit*1000)); + + // Circle + for(i=0; i<=(360/usDEGSTEP); i++) + { + //TRACE("\n xPos = %f, xHall = %f, yPos = %f, yHall = %f", xy_raw_data[i].xpos, xy_raw_data[i].xhall, xy_raw_data[i].ypos, xy_raw_data[i].yhall); + TRACE("\n xPos = %d, xHall = %d, yPos = %d, yHall = %d", (int)(xy_raw_data[i].xpos*1000), (int)(xy_raw_data[i].xhall*1000), (int)(xy_raw_data[i].ypos*1000), (int)(xy_raw_data[i].yhall*1000)); + } + + return( ret ); +} +/************************************************************************/ +/***** calculate by use linearity correction data *****/ +/************************************************************************/ +#define pixelsize 1.22f // um/pixel +UINT_16 AccuracyL(float flACCURACY, UINT_16 RADIUS, UINT_16 usDEGSTEP, UINT_16 WAIT_MSEC1, UINT_16 WAIT_MSEC2, UINT_16 WAIT_MSEC3) +{ + float xpos, ypos; + UINT_32 xhall_value, yhall_value; + float xMaxHall, yMaxHall; + UINT_16 xng = 0, yng = 0; + UINT_16 deg; + float xRadius, yRadius; + UINT_32 uixpxl,uiypxl; + INT_32 sixstp,siystp; + UINT_32 linbuf[8]; /* pos1`pos7, step */ + UINT_32 calibdata; + UINT_8 ans = 0; + + // Get Linearity data + RamRead32A( StCaliData_UsCalibrationStatus , &calibdata ) ; + if( calibdata & HLLN_CALB_FLG ){ + return ( 0xFFFF ); + } + + ans =FlashMultiRead( INF_MAT0, LN_POS1 , linbuf , 8 ); + if( ans ) return( 0xFFFE ); + + uixpxl = (( linbuf[4] & 0x0000FFFF ) - ( linbuf[3] & 0x0000FFFF )) >> 0; + uiypxl = (( linbuf[4] & 0xFFFF0000 ) - ( linbuf[3] & 0xFFFF0000 )) >> 16; + sixstp = ( INT_32 )( linbuf[7] & 0x0000FFFF ) << 16; + siystp = ( INT_32 )( linbuf[7] & 0xFFFF0000 ) << 0; +TRACE( "uixpxl %08x, uiypxl %08x \n", uixpxl , uiypxl ); +TRACE( "sixstp %08x, siystp %08x \n", sixstp , siystp ); + + // Calculate Radius (100um) + xRadius = ( fabsf(fix2float(sixstp)) * 10.0f) / ((float)uixpxl * pixelsize); + yRadius = ( fabsf(fix2float(siystp)) * 10.0f) / ((float)uiypxl * pixelsize); +TRACE( "xRadiusA %f, yRadiusA %f \n", xRadius , yRadius ); + + // Calculate Limit + xLimit = flACCURACY * xRadius; + yLimit = flACCURACY * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * RADIUS ; + yRadius = yRadius * RADIUS ; +TRACE( "xRadiusM %f, yRadiusM %f \n", xRadius , yRadius ); +TRACE( "xRadiusM %08x, yRadiusM %08x \n", float2fix(xRadius) , float2fix(yRadius) ); + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check + xpos = xRadius * cos(0); + ypos = yRadius * sin(0); + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + WitTim(WAIT_MSEC1); + + for( deg = 0; deg <= 360; deg += usDEGSTEP ) // 0-360 degree + { + xpos = xRadius * cos(deg * PI/180); + ypos = yRadius * sin(deg * PI/180); + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + + xMaxHall = 0; + yMaxHall = 0; + WitTim(WAIT_MSEC2); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim(WAIT_MSEC3); + RamRead32A( HALL_RAM_HXOUT0, &xhall_value ); + RamRead32A( HALL_RAM_HYOUT0, &yhall_value ); + if(fabsf(fix2float(xhall_value)) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value); + if(fabsf(fix2float(yhall_value)) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value); + } + + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + + // Save raw data + xy_raw_data[deg/usDEGSTEP].xpos = xpos; + xy_raw_data[deg/usDEGSTEP].xhall = xMaxHall; /* gap */ + xy_raw_data[deg/usDEGSTEP].ypos = ypos; + xy_raw_data[deg/usDEGSTEP].yhall = yMaxHall; /* gap */ + + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + + } + RamWrite32A(HALL_RAM_GYROX_OUT, 0); // x = center + RamWrite32A(HALL_RAM_GYROY_OUT, 0); // y = center + + return (xng << 8) | yng; +} + +//unsigned short HallCheck(void) +UINT_16 HallCheckL(float flACCURACY, UINT_16 RADIUS, UINT_16 usDEGSTEP, UINT_16 WAIT_MSEC1, UINT_16 WAIT_MSEC2, UINT_16 WAIT_MSEC3) +{ + INT_16 i; + UINT_16 ret = AccuracyL(flACCURACY, RADIUS, usDEGSTEP, WAIT_MSEC1, WAIT_MSEC2, WAIT_MSEC3); + + if(ret) + { + TRACE("\n VCM has NG points: X = %d, Y = %d", ret >> 8, ret & 0xff); + } else { + TRACE("\n VCM is good!"); + } + + // Max Accuracy + //TRACE("\n X Max Accuracy = %f, Y Max Accuracy = %f", xMaxAcc, yMaxAcc); + TRACE("\n X Max Accuracy = %d, Y Max Accuracy = %d", (int)(xMaxAcc*1000), (int)(yMaxAcc*1000)); + + // Limit vale + //TRACE("\n xLimit = %f, yLimit = %f", xLimit, yLimit); + TRACE("\n xLimit = %d, yLimit = %d", (int)(xLimit*1000), (int)(yLimit*1000)); + + // Circle + for(i=0; i<=(360/usDEGSTEP); i++) + { + //TRACE("\n xPos = %f, xHall = %f, yPos = %f, yHall = %f", xy_raw_data[i].xpos, xy_raw_data[i].xhall, xy_raw_data[i].ypos, xy_raw_data[i].yhall); + TRACE("\n xPos = %d, xHall = %d, yPos = %d, yHall = %d", (int)(xy_raw_data[i].xpos*1000), (int)(xy_raw_data[i].xhall*1000), (int)(xy_raw_data[i].ypos*1000), (int)(xy_raw_data[i].yhall*1000)); + } + + return( ret ); +} + +unsigned short AccuracyS(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3 , unsigned char ACT_AXIS) +{ + float xpos, ypos; + unsigned int xhall_value, yhall_value; + float xMaxHall, yMaxHall; + unsigned short xng = 0, yng = 0; + unsigned short deg; + float xRadius, yRadius; + unsigned int xGyroLimit, yGyroLimit; + unsigned int xGyrogain, yGyrogain; + unsigned int xGLenz, yGLenz; + unsigned int xShiftRG, yShiftRG; + unsigned int xHav2, yHav2; + + // Get GYROLIMT + RamRead32A(Gyro_Limiter_X, &xGyroLimit); + RamRead32A(Gyro_Limiter_Y, &yGyroLimit); + + // Get Gyro gain + RamRead32A(GyroFilterTableX_gxzoom, &xGyrogain); + RamRead32A(GyroFilterTableY_gyzoom, &yGyrogain); + + // Get Lenz + RamRead32A(GyroFilterTableX_gxlenz, &xGLenz); + RamRead32A(GyroFilterTableY_gylenz, &yGLenz); + + // Get Shift + RamRead32A(GyroFilterShiftX, &xShiftRG); + RamRead32A(GyroFilterShiftY, &yShiftRG); + xShiftRG = 1 << ((xShiftRG & 0x0000FF00) >> 8); + yShiftRG = 1 << ((yShiftRG & 0x0000FF00) >> 8); + + // Calculate Radius (LIMIT_RANGE) /* •s–¾ */ + xRadius = fabsf(fix2float(xGyroLimit)) * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * xShiftRG ; + yRadius = fabsf(fix2float(yGyroLimit)) * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * yShiftRG ; + + // Calculate Limit + xLimit = flACCURACY / LIMIT_RANGE * xRadius; + yLimit = flACCURACY / LIMIT_RANGE * yRadius; + + // Radius change (by RADIUS value) + xRadius = xRadius * RADIUS / LIMIT_RANGE; + yRadius = yRadius * RADIUS / LIMIT_RANGE; + + xMaxAcc = 0; + yMaxAcc = 0; + + // Circle check + xpos = xRadius * sin(0); + ypos = yRadius * sin(0); + if(ACT_AXIS == X_DIR){ + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + }else{ + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + } + WitTim(WAIT_MSEC1); + + for( deg = 0; deg <= 360; deg += usDEGSTEP ) // 0-360 degree + { +// xpos = xRadius * cos(deg * PI/180); + xpos = xRadius * sin(deg * PI/180); + ypos = yRadius * sin(deg * PI/180); + if(ACT_AXIS == X_DIR){ + RamWrite32A(HALL_RAM_GYROX_OUT, float2fix(xpos)); + }else{ + RamWrite32A(HALL_RAM_GYROY_OUT, float2fix(ypos)); + } + + xMaxHall = 0; + yMaxHall = 0; + WitTim(WAIT_MSEC2); + RamRead32A( XMoveAvg_D2, &xHav2 ); + RamRead32A( YMoveAvg_D2, &yHav2 ); + + for(short i=0; i<LOOPTIME; i++) + { + WitTim(WAIT_MSEC3); + if(ACT_AXIS == X_DIR){ + RamRead32A( HALL_RAM_HXOUT2, &xhall_value ); + if(fabsf(fix2float(xhall_value) + fix2float(xHav2)) > fabsf(xMaxHall)) + xMaxHall = fix2float(xhall_value) + fix2float(xHav2); + }else{ + RamRead32A( HALL_RAM_HYOUT2, &yhall_value ); + if(fabsf(fix2float(yhall_value) + fix2float(yHav2)) > fabsf(yMaxHall)) + yMaxHall = fix2float(yhall_value) + fix2float(yHav2); + } + } + + if(ACT_AXIS == X_DIR){ + if(fabsf(xMaxHall) > xMaxAcc) xMaxAcc = fabsf(xMaxHall); + xy_raw_data[deg/usDEGSTEP].xpos = fix2float(xHav2); + xy_raw_data[deg/usDEGSTEP].xhall = xMaxHall + fix2float(xHav2); + xy_raw_data[deg/usDEGSTEP].ypos = 0; + xy_raw_data[deg/usDEGSTEP].yhall = 0; + if(fabsf(xMaxHall) > xLimit) xng++; // Have NG point; + }else{ + if(fabsf(yMaxHall) > yMaxAcc) yMaxAcc = fabsf(yMaxHall); + // Save raw data + xy_raw_data[deg/usDEGSTEP].ypos = fix2float(yHav2); + xy_raw_data[deg/usDEGSTEP].yhall = yMaxHall + fix2float(yHav2); + xy_raw_data[deg/usDEGSTEP].xpos = 0; + xy_raw_data[deg/usDEGSTEP].xhall = 0; + if(fabsf(yMaxHall) > yLimit) yng++; // Have NG point; + } + + + } + RamWrite32A(HALL_RAM_GYROX_OUT, 0); // x = center + RamWrite32A(HALL_RAM_GYROY_OUT, 0); // y = center + + return (xng << 8) | yng; +} + +//unsigned short HallCheck(void) +UINT_16 HallCheckS(float flACCURACY, UINT_16 RADIUS, UINT_16 usDEGSTEP, UINT_16 WAIT_MSEC1, UINT_16 WAIT_MSEC2, UINT_16 WAIT_MSEC3 , UINT_8 ACT_AXIS) +{ + INT_16 i; +// unsigned short ret = Accuracy(); + UINT_16 ret = AccuracyS(flACCURACY, RADIUS, usDEGSTEP, WAIT_MSEC1, WAIT_MSEC2, WAIT_MSEC3, ACT_AXIS); + + if(ret) + { + TRACE("\n VCM has NG points: X = %d, Y = %d", ret >> 8, ret & 0xff); + } else { + TRACE("\n VCM is good!"); + } + + // Max Accuracy + //TRACE("\n X Max Accuracy = %f, Y Max Accuracy = %f", xMaxAcc, yMaxAcc); + TRACE("\n X Max Accuracy = %d, Y Max Accuracy = %d", (int)(xMaxAcc*1000), (int)(yMaxAcc*1000)); + + // Limit vale + //TRACE("\n xLimit = %f, yLimit = %f", xLimit, yLimit); + TRACE("\n xLimit = %d, yLimit = %d", (int)(xLimit*1000), (int)(yLimit*1000)); + + // Circle + for(i=0; i<=(360/usDEGSTEP); i++) + { + //TRACE("\n xPos = %f, xHall = %f, yPos = %f, yHall = %f", xy_raw_data[i].xpos, xy_raw_data[i].xhall, xy_raw_data[i].ypos, xy_raw_data[i].yhall); + TRACE("\n xPos = %d, xHall = %d, yPos = %d, yHall = %d", (int)(xy_raw_data[i].xpos*1000), (int)(xy_raw_data[i].xhall*1000), (int)(xy_raw_data[i].ypos*1000), (int)(xy_raw_data[i].yhall*1000)); + } + + return( ret ); +} + +#if 0 +unsigned char SMA_Sensitivity( unsigned short LIMIT_RANGE_SMA, unsigned short RADIUS, unsigned short DEGREE, unsigned short WAIT_MSEC1) +{ + float xpos, ypos; + float xRadius, yRadius; + unsigned int xGyrogain, yGyrogain; + unsigned int xGLenz, yGLenz; + + // Get Gyro gain + RamRead32A(0x8890, &xGyrogain); + RamRead32A(0x88C4, &yGyrogain); + + // Get Lenz + RamRead32A(0x8894, &xGLenz); + RamRead32A(0x88C8, &yGLenz); + + // Calculate Radius (LIMIT_RANGE) /* •s–¾ */ + xRadius = ANGLE_LIMIT_SMA * fabsf(fix2float(xGyrogain)) * fabsf(fix2float(xGLenz)) * 1 ; + yRadius = ANGLE_LIMIT_SMA * fabsf(fix2float(yGyrogain)) * fabsf(fix2float(yGLenz)) * 1 ; + + + // Radius change (by RADIUS value) + xRadius = xRadius * (float)RADIUS / (float)LIMIT_RANGE_SMA; + yRadius = yRadius * (float)RADIUS / (float)LIMIT_RANGE_SMA; + + xpos = xRadius * cos(DEGREE * PI/180); + ypos = yRadius * sin(DEGREE * PI/180); + + RamWrite32A(0x610, float2fix(xpos)); + RamWrite32A(0x61C, float2fix(ypos)); + + WitTim(WAIT_MSEC1); + + return (1); +} +#endif diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Accuracy.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Accuracy.h new file mode 100755 index 0000000000000000000000000000000000000000..400ddfdc43308d6a051bc2a0b1d0c05fea87b15f --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Accuracy.h @@ -0,0 +1,60 @@ +/*======================================================================= + Accuracy Test Sample code for LC898124 + by Rex.Tang + 2016.03.27 +========================================================================*/ +#ifndef __OISACCURACY_H__ +#define __OISACCURACY_H__ + +#ifdef __OISACCURACY__ + #define __OISACCURACY_HEADER__ +#else + #define __OISACCURACY_HEADER__ extern +#endif + +// Checking radius +//#define RADIUS 75 // 75um + +// Parameter define +//#define DEGSTEP 3 // Degree of one step (3‹) +//#define ACCURACY 3.0F // Accuracy (}3.0um) +//#define WAIT_MSEC 10 // Each step wait time(msec) +#define LOOPTIME 3 // Read times at each step + + + +union FLTVAL2 { + float SfFltVal ; + struct { + unsigned char UcDataHH; + unsigned char UcDataHL; + unsigned char UcDataLH; + unsigned char UcDataLL; + } StFltVal ; +} ; + +typedef union FLTVAL2 UnFltVal2 ; + +typedef struct tag_Dual_Axis +{ + float xpos; + float xhall; + float ypos; + float yhall; +}Dual_Axis_t; + +/* Raw data buffers */ +//Dual_Axis_t xy_raw_data[360/DEGSTEP + 1]; +__OISACCURACY_HEADER__ Dual_Axis_t xy_raw_data[360/3 + 1]; +__OISACCURACY_HEADER__ float xMaxAcc, yMaxAcc; +__OISACCURACY_HEADER__ float xLimit, yLimit; + +//__OISACCURACY_HEADER__ unsigned short HallCheck(float ACCURACY, unsigned short RADIUS, unsigned short DEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3); +__OISACCURACY_HEADER__ unsigned short HallCheck(void); +__OISACCURACY_HEADER__ unsigned short HallCheckH(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3); +__OISACCURACY_HEADER__ unsigned short HallCheckL(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3); +__OISACCURACY_HEADER__ unsigned short HallCheckS(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3 , unsigned char ACT_AXIS); +__OISACCURACY_HEADER__ unsigned short HallCheckG(float flACCURACY, unsigned short RADIUS, unsigned short usDEGSTEP, unsigned short WAIT_MSEC1, unsigned short WAIT_MSEC2, unsigned short WAIT_MSEC3); +//__OISACCURACY_HEADER__ unsigned char SMA_Sensitivity( unsigned short LIMIT_RANGE_SMA, unsigned short RADIUS, unsigned short DEGREE, unsigned short WAIT_MSEC1); + +#endif //__OISACCURACY_H__ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FlsCmd.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FlsCmd.c new file mode 100755 index 0000000000000000000000000000000000000000..e2b5e4243b591d80891549f8a19cb663d95b91b5 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FlsCmd.c @@ -0,0 +1,1960 @@ +//******************************************************************************** +// +// << LC898128 Evaluation Soft >> +// Program Name : FlsCmd.c +// Design : K.abe +// History : First edition +//******************************************************************************** +#define __OISFLSH__ +//************************** +// Include Header File +//************************** +#include "Ois.h" +//#include <stdlib.h> +//#include <math.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#define SEL_MODEL 0 + + +#if (SELECT_VENDOR == 0x01) // SUNNY FAB only + +#define BURST_LENGTH_UC ( 12*20 ) // 240 Total:242Byte +#define BURST_LENGTH_FC ( 3*64 ) // 192 Total:194~195Byte + +#else + +/* Burst Length for updating to PMEM Max:256*/ +#define BURST_LENGTH_UC ( 20 ) // 120 Total:122Byte +//#define BURST_LENGTH_UC ( 6*20 ) // 120 Total:122Byte +/* Burst Length for updating to Flash */ +//#define BURST_LENGTH_FC ( 32 ) // 32 Total: 34~35Byte +#define BURST_LENGTH_FC ( 64 ) // 64 Total: 66~67Byte + +#endif + +//**************************************************** +// CUSTOMER NECESSARY CREATING FUNCTION LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A( UINT_16, UINT_32 ); +extern void RamRead32A( UINT_16, void * ); +/* for I2C Multi Translation : Burst Mode*/ +extern void CntWrt( void *, UINT_16) ; +extern void CntRd( UINT_32, void *, UINT_16 ) ; + +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( UINT_16 ); + +//************************** +// Local Function Prototype +//************************** +UINT_8 FlashSingleRead( UINT_8 SelMat, UINT_32 UlAddress, UINT_32 *PulData ); +UINT_8 FlashMultiRead( UINT_8 SelMat, UINT_32 UlAddress, UINT_32 *PulData , UINT_8 UcLength ); +INT_32 lstsq( double x[], double y[], INT_32 , INT_32 , double c[] ); + +extern UINT_8 GetInfomationAfterStartUp( DSPVER* Info ); + +extern const LINCRS ACT01_LinCrsParameter; + +//******************************************************************************** +// Function Name : IOWrite32A +// Retun Value : None +// Argment Value : IOadrs, IOdata +// Explanation : Write data to IO area Command +// History : First edition +//******************************************************************************** +void IORead32A( UINT_32 IOadrs, UINT_32 *IOdata ) +{ + RamWrite32A( CMD_IO_ADR_ACCESS, IOadrs ) ; + RamRead32A ( CMD_IO_DAT_ACCESS, IOdata ) ; +} + +//******************************************************************************** +// Function Name : IOWrite32A +// Retun Value : None +// Argment Value : IOadrs, IOdata +// Explanation : Write data to IO area Command +// History : First edition +//******************************************************************************** +void IOWrite32A( UINT_32 IOadrs, UINT_32 IOdata ) +{ + RamWrite32A( CMD_IO_ADR_ACCESS, IOadrs ) ; + RamWrite32A( CMD_IO_DAT_ACCESS, IOdata ) ; +} + +//******************************************************************************** +// Function Name : UnlockCodeSet +// Retun Value : NON +// Argment Value : NON +// Explanation : <Flash Memory> Unlock Code Set +// History : First edition +//******************************************************************************** +UINT_8 UnlockCodeSet( void ) +{ + UINT_32 UlReadVal, UlCnt=0; + + do { + IOWrite32A( 0xE07554, 0xAAAAAAAA ); // UNLK_CODE1(E0_7554h) = AAAA_AAAAh + IOWrite32A( 0xE07AA8, 0x55555555 ); // UNLK_CODE2(E0_7AA8h) = 5555_5555h + IORead32A( 0xE07014, &UlReadVal ); + if( (UlReadVal & 0x00000080) != 0 ) return ( 0 ) ; // Check UNLOCK(E0_7014h[7]) ? + WitTim( 1 ); + } while( UlCnt++ < 10 ); + return ( 1 ); +} + +//******************************************************************************** +// Function Name : UnlockCodeClear +// Retun Value : NON +// Argment Value : NON +// Explanation : <Flash Memory> Clear Unlock Code +// History : First edition +//******************************************************************************** +UINT_8 UnlockCodeClear(void) +{ + UINT_32 UlDataVal, UlCnt=0; + + do { + IOWrite32A( 0xE07014, 0x00000010 ); // UNLK_CODE3(E0_7014h[4]) = 1 + IORead32A( 0xE07014, &UlDataVal ); + if( (UlDataVal & 0x00000080) == 0 ) return ( 0 ) ; // Check UNLOCK(E0_7014h[7]) ? + WitTim( 1 ); + } while( UlCnt++ < 10 ); + return ( 3 ); +} + + +//******************************************************************************** +// Function Name : WritePermission +// Retun Value : NON +// Argment Value : NON +// Explanation : LC898128 Command +// History : First edition 2018.05.15 +//******************************************************************************** +void WritePermission( void ) +{ + IOWrite32A( 0xE074CC, 0x00000001 ); // RSTB_FLA_WR(E0_74CCh[0])=1 + IOWrite32A( 0xE07664, 0x00000010 ); // FLA_WR_ON(E0_7664h[4])=1 +} + +//******************************************************************************** +// Function Name : AddtionalUnlockCodeSet +// Retun Value : NON +// Argment Value : NON +// Explanation : LC898128 Command +// History : First edition 2018.05.15 +//******************************************************************************** +void AddtionalUnlockCodeSet( void ) +{ + IOWrite32A( 0xE07CCC, 0x0000ACD5 ); // UNLK_CODE3(E0_7CCCh) = 0000_ACD5h +} + +//******************************************************************************** +// Function Name : CoreResetwithoutMC128 +// Retun Value : 0:Non error +// Argment Value : None +// Explanation : Program code Update to PMEM directly +// History : First edition +//******************************************************************************** +UINT_8 CoreResetwithoutMC128( void ) +{ + UINT_32 UlReadVal ; + + IOWrite32A( 0xE07554, 0xAAAAAAAA); + IOWrite32A( 0xE07AA8, 0x55555555); + + IOWrite32A( 0xE074CC, 0x00000001); + IOWrite32A( 0xE07664, 0x00000010); + IOWrite32A( 0xE07CCC, 0x0000ACD5); + IOWrite32A( 0xE0700C, 0x00000000); + IOWrite32A( 0xE0701C, 0x00000000); + IOWrite32A( 0xE07010, 0x00000004); + + WitTim(100);//neo: need to reduce this time + + IOWrite32A( 0xE0701C, 0x00000002); + IOWrite32A( 0xE07014, 0x00000010); + + IOWrite32A( 0xD00060, 0x00000001 ) ; + WitTim( 15 ) ;//neo: need to reduce this time + + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + switch ( (UINT_8)UlReadVal ){ + case 0x08: + case 0x0D: + break; + + default: + return( 0xE0 | (UINT_8)UlReadVal ); + } + +#if 0 // 1MHz Test + IOWrite32A( 0xD00014, 0x00000002); + IOWrite32A( 0xE07020, 0x00000014); +#endif + return( 0 ); +} + +//******************************************************************************** +// Function Name : PmemUpdate128 +// Retun Value : 0:Non error +// Argment Value : None +// Explanation : Program code Update to PMEM directly +// History : First edition +//******************************************************************************** +UINT_8 PmemUpdate128( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_8 data[BURST_LENGTH_UC +2 ]; + UINT_16 Remainder; // —]‚è + const UINT_8 *NcDataVal = ptr->UpdataCode; + UINT_8 ReadData[8]; + long long CheckSumCode = ptr->SizeUpdataCodeCksm; + UINT_8 *p = (UINT_8 *)&CheckSumCode; + UINT_32 i, j; + UINT_32 UlReadVal, UlCnt , UlNum ; +//-------------------------------------------------------------------------------- +// 1. Write updata code to Pmem +//-------------------------------------------------------------------------------- + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + RamWrite32A( 0x3000, 0x00080000 ); // Pmem address set + + // Pmem data burst write + data[0] = 0x40; // CmdH + data[1] = 0x00; // CmdL + + // XXbyte–ˆ‚Ì“]‘— + Remainder = ( (ptr->SizeUpdataCode*5) / BURST_LENGTH_UC ); + for(i=0 ; i< Remainder ; i++) + { + UlNum = 2; + for(j=0 ; j < BURST_LENGTH_UC; j++){ + data[UlNum] = *NcDataVal++; +// if( ( j % 5) == 4) TRACE("\n"); + UlNum++; + } + + CntWrt( data, BURST_LENGTH_UC+2 ); // Cmd 2Byte. + } + Remainder = ( (ptr->SizeUpdataCode*5) % BURST_LENGTH_UC); + if (Remainder != 0 ) + { + UlNum = 2; + for(j=0 ; j < Remainder; j++){ + data[UlNum++] = *NcDataVal++; + } + CntWrt( data, Remainder+2 ); // Cmd 2Byte + } + +//-------------------------------------------------------------------------------- +// 2. Verify +//-------------------------------------------------------------------------------- + + // Program RAM‚ÌCheckSum‚Ì‹N“® + data[0] = 0xF0; //CmdID + data[1] = 0x0E; //CmdID + data[2] = (unsigned char)((ptr->SizeUpdataCode >> 8) & 0x000000FF); //‘‚«ž‚݃f[ƒ^(MSB) + data[3] = (unsigned char)(ptr->SizeUpdataCode & 0x000000FF); //‘‚«ž‚݃f[ƒ^ + data[4] = 0x00; //‘‚«ž‚݃f[ƒ^ + data[5] = 0x00; //‘‚«ž‚݃f[ƒ^(LSB) + + CntWrt( data, 6 ) ; + + // CheckSum‚ÌI—¹”»’è + UlCnt = 0; + do{ + WitTim( 1 ); + if( UlCnt++ > 10 ) { + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + return (0x21) ; // No enough memory + } + RamRead32A( 0x0088, &UlReadVal ); // PmCheck.ExecFlag‚̓ǂÝo‚µ + }while ( UlReadVal != 0 ); + +#if 0 + // CheckSum’l‚̓ǂÝo‚µ + data[0] = 0xF0; // CmdID + data[1] = 0x0E; // CmdID + CntWrt( data, 2 ) ; + CntRd( 0, ReadData , 8 ); +#else + CntRd( 0xF00E, ReadData , 8 ); +#endif + + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + // CheckSum’l‚Ì”»’è(Šú‘Ò’l‚ÍAHeader‚Édefine‚³‚ê‚Ä‚¢‚é) + for( i=0; i<8; i++) { + if(ReadData[7-i] != *p++ ) { // CheckSum Code‚Ì”»’è +TRACE("[2] PMEM verify Error %02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x\n",ReadData[0],ReadData[1],ReadData[2],ReadData[3],ReadData[4],ReadData[5],ReadData[6],ReadData[7]); + return (0x22) ; // verify ng + } + } +TRACE("[2] PMEM verify End\n"); + return( 0 ); +} +//******************************************************************************** +// Function Name : EraseUserMat128 +// Retun Value : NON +// Argment Value : NON +// Explanation : User Mat All Erase + +// History : First edition +//******************************************************************************** +UINT_8 EraseUserMat128(UINT_8 StartBlock, UINT_8 EndBlock ) +{ + UINT_32 i; + UINT_32 UlReadVal, UlCnt ; + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0xF007, 0x00000000 ); // FlashAccess Setup + + //***** User Mat‚̃uƒƒbƒNÁ‹Ž ***** + for( i=StartBlock ; i<EndBlock ; i++) { + RamWrite32A( 0xF00A, ( i << 10 ) ); // FromCmd.Addr‚ÌÝ’è + RamWrite32A( 0xF00C, 0x00000020 ); // FromCmd.Control‚ÌÝ’è(ƒuƒƒbƒNÁ‹Ž) + + // ƒuƒƒbƒNÁ‹Ž‚ÌI—¹”»’è + WitTim( 5 ); + UlCnt = 0; + do{ +// WitTim( 4 ); + WitTim( 1 ); + if( UlCnt++ > 10 ){ + IOWrite32A( 0xE0701C , 0x00000002); + return (0x31) ; // block erase timeout ng + } + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + }while ( UlReadVal != 0 ); + } + IOWrite32A( 0xE0701C , 0x00000002); + return(0); + +} + +//******************************************************************************** +// Function Name : ProgramFlash128_LongBurst +// Retun Value : NON +// Argment Value : NON +// Explanation : User Mat All Erase + +// History : First edition +//******************************************************************************** +UINT_8 ProgramFlash128_LongBurst( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_32 UlReadVal, UlCnt , UlNum ; + UINT_8 data[(BURST_LENGTH_FC + 2)]; + UINT_32 i, j; + UINT_16 Remainder; // —]‚è + const UINT_8 *NcFromVal = ptr->FromCode+BURST_LENGTH_FC; + const UINT_8 *NcFromVal1st = ptr->FromCode; + UINT_8 UcOddEvn; + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0x067C, 0x000800ac ); // F008 Update + RamWrite32A( 0x0680, 0x000800be ); // F009 Update + + RamWrite32A( 0xF007, 0x00000000 ); // FlashAccess Setup +// RamWrite32A( 0xF00A, 0x00000000 ); // FromCmd.Addr‚ÌÝ’è + RamWrite32A( 0xF00A, 0x00000030 ); // FromCmd.Addr‚ÌÝ’è + + data[0] = 0xF0; // CmdH + data[1] = 0x08; // CmdL + + for(i=1 ; i< ( ptr->SizeFromCode / BURST_LENGTH_FC ) ; i++) + { + if( ++UcOddEvn >1 ) UcOddEvn = 0; // Šï”‹ô”Check + if (UcOddEvn == 0) data[1] = 0x08; + else data[1] = 0x09; + + UlNum = 2; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + + UlCnt = 0; + if(UcOddEvn == 0){ + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 100 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( (UlReadVal & 0x00000004) != 0 ); + }else{ + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 100 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( (UlReadVal & 0x00000008) != 0 ); + } + + CntWrt( data, BURST_LENGTH_FC+2 ); // Cmd 2Byte. + } + Remainder = ( ptr->SizeFromCode % BURST_LENGTH_FC ) / 64; + for(i=0 ; i< Remainder ; i++) + { + if( ++UcOddEvn >1 ) UcOddEvn = 0; // Šï”‹ô”Check + if (UcOddEvn == 0) data[1] = 0x08; + else data[1] = 0x09; + + UlNum = 2; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + + UlCnt = 0; + if(UcOddEvn == 0){ + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 100 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( (UlReadVal & 0x00000004) != 0 ); + }else{ + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 100 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( (UlReadVal & 0x00000008) != 0 ); + } + + CntWrt( data, BURST_LENGTH_FC+2 ); // Cmd 2Byte. + } + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è +// WitTim( 4 ); + WitTim( 1 ); + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x42) ; // write ng + } + }while ( (UlReadVal & 0x0000000C) != 0 ); + + /* write magic code */ + RamWrite32A( 0xF00A, 0x00000000 ); // FromCmd.Addr‚ÌÝ’è + data[1] = 0x08; // CmdL + UlNum = 2; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 100 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( UlReadVal != 0 ); + + CntWrt( data, BURST_LENGTH_FC+2 ); // Cmd 2Byte. + + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + WitTim( 1 ); + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x42) ; // write ng + } + }while ( (UlReadVal & 0x0000000C) != 0 ); + + IOWrite32A( 0xE0701C , 0x00000002); + return( 0 ); +} + +//******************************************************************************** +// Function Name : ProgramFlash128_Standard +// Retun Value : NON +// Argment Value : NON +// Explanation : User Mat All Erase + +// History : First edition +//******************************************************************************** +#if (BURST_LENGTH_FC == 32) || (BURST_LENGTH_FC == 64) +UINT_8 ProgramFlash128_Standard( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_32 UlReadVal, UlCnt , UlNum ; + UINT_8 data[(BURST_LENGTH_FC + 3)]; + UINT_32 i, j; + + const UINT_8 *NcFromVal = ptr->FromCode + 64; + const UINT_8 *NcFromVal1st = ptr->FromCode; + UINT_8 UcOddEvn; + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0xF007, 0x00000000 ); // FlashAccess Setup + RamWrite32A( 0xF00A, 0x00000010 ); // FromCmd.Addr‚ÌÝ’è + data[0] = 0xF0; // CmdH + data[1] = 0x08; // CmdL + data[2] = 0x00; // FromCmd.BufferA‚̃AƒhƒŒƒX + + for(i=1 ; i< ( ptr->SizeFromCode / 64 ) ; i++) + { + if( ++UcOddEvn >1 ) UcOddEvn = 0; // Šï”‹ô”Check + if (UcOddEvn == 0) data[1] = 0x08; + else data[1] = 0x09; +TRACE("[%d]UcOddEvn= %d , data[1]= %d \n", i, data[1], NcFromVal ); + +#if (BURST_LENGTH_FC == 32) + // 32Byte‚È‚ç‚ÎA2‰ñ‚É•ª‚¯‚Ä‘—‚ç‚È‚¢‚Æ‚¢‚¯‚È‚¢B + data[2] = 0x00; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); // Cmd 3Byte. + data[2] = 0x20; //+32Byte + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); // Cmd 3Byte. +#elif (BURST_LENGTH_FC == 64) + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); // Cmd 3Byte. +#endif + + RamWrite32A( 0xF00B, 0x00000010 ); // FromCmd.Length‚ÌÝ’è + UlCnt = 0; + if (UcOddEvn == 0){ + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( UlReadVal != 0 ); + RamWrite32A( 0xF00C, 0x00000004 ); // FromCmd.Control‚ÌÝ’è(‘‚«ž‚Ý) + }else{ + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( UlReadVal != 0 ); + RamWrite32A( 0xF00C, 0x00000008 ); // FromCmd.Control‚ÌÝ’è(‘‚«ž‚Ý) + } + } + + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + WitTim( 1 ); + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( (UlReadVal & 0x0000000C) != 0 ); + + { /* write magic code */ + RamWrite32A( 0xF00A, 0x00000000 ); // FromCmd.Addr‚ÌÝ’è + data[1] = 0x08; +// data[1] = 0x09; +TRACE("[%d]UcOddEvn= %d , data[1]= %d \n", 0, data[1], NcFromVal1st ); + +#if (BURST_LENGTH_FC == 32) + // 32Byte‚È‚ç‚ÎA2‰ñ‚É•ª‚¯‚Ä‘—‚ç‚È‚¢‚Æ‚¢‚¯‚È‚¢B + data[2] = 0x00; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); // Cmd 3Byte. + data[2] = 0x20; //+32Byte + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); // Cmd 3Byte. +#elif (BURST_LENGTH_FC == 64) + data[2] = 0x00; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); // Cmd 3Byte. +#endif + + RamWrite32A( 0xF00B, 0x00000010 ); // FromCmd.Length‚ÌÝ’è + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( UlReadVal != 0 ); + RamWrite32A( 0xF00C, 0x00000004 ); // FromCmd.Control‚ÌÝ’è(‘‚«ž‚Ý) +// RamWrite32A( 0xF00C, 0x00000008 ); // FromCmd.Control‚ÌÝ’è(‘‚«ž‚Ý) + } + + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + WitTim( 1 ); + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; // write ng + } + }while ( (UlReadVal & 0x0000000C) != 0 ); + + IOWrite32A( 0xE0701C , 0x00000002); + return( 0 ); +} +#endif + + +//******************************************************************************** +// Function Name : CheckDrvOffAdj +// Retun Value : Driver Offset Re-adjustment +// Argment Value : NON +// Explanation : Driver Offset Re-adjustment +// History : First edition +//******************************************************************************** +//extern UINT_8 CoreResetwithoutMC128( void ); +//extern void IOWrite32A( UINT_32 IOadrs, UINT_32 IOdata ); +//extern void IORead32A( UINT_32 IOadrs, UINT_32 *IOdata ); +//extern UINT_8 PmemUpdate128( DOWNLOAD_TBL_EXT* ptr ); + + +UINT_32 CheckDrvOffAdj( void ) +{ + UINT_32 UlReadDrvOffx, UlReadDrvOffy, UlReadDrvOffaf; + + IOWrite32A( FLASHROM_ACSCNT, 2 ); //3word + IOWrite32A( FLASHROM_FLA_ADR, ((UINT_32)INF_MAT1 << 16) | 0xD ); + + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + IOWrite32A( FLASHROM_CMD, 0x00000001 ); + IORead32A( FLASHROM_FLA_RDAT, &UlReadDrvOffaf ) ; // #13 + IORead32A( FLASHROM_FLA_RDAT, &UlReadDrvOffx ) ; // #14 + IORead32A( FLASHROM_FLA_RDAT, &UlReadDrvOffy ) ; // #15 + + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + if( ((UlReadDrvOffx & 0x000FF00) == 0x0000100) + || ((UlReadDrvOffy & 0x000FF00) == 0x0000100) + || ((UlReadDrvOffaf & 0x000FF00) == 0x0000800) ){ //error + return( 0x93 ); + } + + if( ((UlReadDrvOffx & 0x0000080) == 0) + && ((UlReadDrvOffy & 0x00000080) ==0) + && ((UlReadDrvOffaf & 0x00008000) ==0) ){ + +#if 0 //Erase : Test for repeatablity + if( FlashBlockErase( INF_MAT1 , 0 ) != 0 ) return( 0x92 ) ; // Erase Error + return( 1 ); // 0 : Uppdated +#else + return( 0 ); // 0 : Uppdated +#endif + } + return( 1 ); // 1 : Still not. +} + +//******************************************************************************** +// Function Name : DrvOffAdj +// Retun Value : Driver Offset Re-adjustment +// Argment Value : NON +// Explanation : Driver Offset Re-adjustment +// History : First edition +//******************************************************************************** +#include "PmemCode128.h" +const DOWNLOAD_TBL_EXT Adj_Dtbl[] = { + {0xEEEE, 0, 0, LC898128_PM, LC898128_PmemCodeSize, LC898128_PmemCodeCheckSum, (void*)0, 0, 0, 0} +}; + + +UINT_32 DrvOffAdj( void ) +{ + UINT_8 ans=0; + UINT_32 UlReadVal; +TRACE("DrvOffAdj \n"); + +//Infomat‚ÌŠm”FB‚à‚µRe-Adjust‚µ‚Ä‚¢‚È‚¢‚È‚çÄŽÀsB + ans = CheckDrvOffAdj(); + if( ans == 1 ){ + + ans = CoreResetwithoutMC128(); // Start up to boot exection + if(ans != 0) return( ans ); + + ans = PmemUpdate128( (DOWNLOAD_TBL_EXT *)Adj_Dtbl ); // Update the special program for updating the flash memory. + if(ans != 0) return( ans ); + + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + RamWrite32A( 0xF001, 0x00000000 ) ; // + WitTim( 1 ) ; + + IOWrite32A( 0xE07CCC, 0x0000C5AD ); // additional unlock for INFO + IOWrite32A( 0xE07CCC, 0x0000ACD5 ); // UNLK_CODE3(E0_7CCCh) = 0000_ACD5h + WitTim( 10 ) ;//neo: need to reduce this time + + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + IOWrite32A( SYSDSP_REMAP, 0x00001000 ) ; // CORE_RST[12], MC_IGNORE2[10] = 1 PRAMSEL[7:6]=01b + WitTim( 15 ) ; // BootƒvƒƒOƒ‰ƒ€‚ð‰ñ‚·‚Ì‚É15msec•K—vB +//neo: need to reduce this time + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; +TRACE("[%08x]DrvOffAdj \n",(unsigned int)UlReadVal ); + if( UlReadVal != 0x08) return( 0x90 ); + + ans = CheckDrvOffAdj(); + + } + return(ans); +} + +//******************************************************************************** +// Function Name : FlashUpdate128 +// Retun Value : NON +// Argment Value : chiperase +// Explanation : Flash Update for LC898128 +// History : First edition +//******************************************************************************** +UINT_8 FlashUpdate128( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_8 ans=0; + UINT_32 UlReadVal, UlCnt ; + +//-------------------------------------------------------------------------------- +// 0. <Info Mat1> Driver Offset +//-------------------------------------------------------------------------------- + ans = DrvOffAdj(); + if(ans != 0) return( ans ); + + ans = CoreResetwithoutMC128(); // Start up to boot exection + if(ans != 0) return( ans ); + + ans = Mat2ReWrite(); // MAT2 re-write process + if(ans != 0 && ans != 1) return( ans ); + + ans = PmemUpdate128( ptr ); // Update the special program for updating the flash memory. + if(ans != 0) return( ans ); + +//-------------------------------------------------------------------------------- +// <User Mat> Erase +//-------------------------------------------------------------------------------- + if( UnlockCodeSet() != 0 ) return (0x33) ; // Unlock Code set ng + WritePermission(); // Write Permission + AddtionalUnlockCodeSet(); // Additional Unlock Code Set + +#if (SEL_MODEL == 0x10) + ans = EraseUserMat128(0, 10); // Full Block. +#else + ans = EraseUserMat128(0, 7); // 0-6 Block for use user area. +#endif + if(ans != 0){ + if( UnlockCodeClear() != 0 ) return (0x32) ; // unlock code clear ng + else return( ans ); + } + +// if( UnlockCodeClear() != 0 ) return (0x32) ; // unlock code clear ng + +//-------------------------------------------------------------------------------- +// 4. <User Mat> Write +//-------------------------------------------------------------------------------- +// if( UnlockCodeSet() != 0 ) return (0x44) ; // Unlock Code set ng +// WritePermission(); // Write Permission +// AddtionalUnlockCodeSet(); // Additional Unlock Code Set + +#if (SELECT_VENDOR == 0x01) // SUNNY FAB only + ans = ProgramFlash128_LongBurst( ptr ); + if(ans != 0){ + if( UnlockCodeClear() != 0 ) return (0x43) ; // unlock code clear ng + else return( ans ); + } +#else + ans = ProgramFlash128_Standard( ptr ); + if(ans != 0){ + if( UnlockCodeClear() != 0 ) return (0x43) ; // unlock code clear ng + else return( ans ); + } +#endif +TRACE("[%d]ProgramFlash end \n", ans ); + + if( UnlockCodeClear() != 0 ) return (0x43) ; // unlock code clear ng + +//-------------------------------------------------------------------------------- +// 5. <User Mat> Verify +//-------------------------------------------------------------------------------- + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0xF00A, 0x00000000 ); // FromCmd.Addr‚ÌÝ’è + RamWrite32A( 0xF00D, ptr->SizeFromCodeValid ); // —LŒøCheckSumƒTƒCƒY‚ÌÝ’è + + RamWrite32A( 0xF00C, 0x00000100 ); // FromCmd.Control‚ÌÝ’è(CheckSumŽÀs) + WitTim( 6 ); + UlCnt = 0; + do{ // ‘‚«ž‚Ý‚ÌI—¹”»’è + RamRead32A( 0xF00C, &UlReadVal ); // FromCmd.Control‚̓ǂÝo‚µ + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x51) ; // check sum excute ng + } + WitTim( 1 ); + }while ( UlReadVal != 0 ); + + RamRead32A( 0xF00D, &UlReadVal ); // CheckSum’l‚̓ǂÝo‚µ + + if( UlReadVal != ptr->SizeFromCodeCksm ) { + IOWrite32A( 0xE0701C , 0x00000002); + return( 0x52 ); + } + +TRACE("[]UserMat Verify OK \n" ); +// CoreReset + IOWrite32A( SYSDSP_REMAP, 0x00001000 ) ; // CORE_RST[12], MC_IGNORE2[10] = 1 PRAMSEL[7:6]=01b + WitTim( 15 ) ; // BootƒvƒƒOƒ‰ƒ€‚ð‰ñ‚·‚Ì‚É15msec•K—vB + //neo: need to reduce this time + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + if( UlReadVal != 0x0A) return( 0x53 ); + +TRACE("[]Remap OK \n" ); + return ( 0 ); + +} + +//******************************************************************************** +// Function Name : FlashBlockErase +// Retun Value : 0 : Success, 1 : Unlock Error, 2 : Time Out Error +// Argment Value : Use Mat , Flash Address +// Explanation : <Flash Memory> Block Erase +// History : First edition +// Unit of erase : informaton mat 128 Byte +// : user mat 4k Byte +//******************************************************************************** +UINT_8 FlashBlockErase( UINT_8 SelMat , UINT_32 SetAddress ) +{ + UINT_32 UlReadVal, UlCnt; + UINT_8 ans = 0 ; + + // fail safe + // reject irregular mat + if( SelMat != USER_MAT && SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; // INF_MAT2‚àAccess‚µ‚È‚¢ + // reject command if address inner NVR3 + if( SetAddress > 0x000003FF ) return 9; + + // Flash write€”õ + ans = UnlockCodeSet(); + if( ans != 0 ) return( ans ) ; // Unlock Code Set + + WritePermission(); // Write permission + if( SelMat != USER_MAT ){ + if( SelMat == INF_MAT2 ) IOWrite32A( 0xE07CCC, 0x00006A4B ); + else IOWrite32A( 0xE07CCC, 0x0000C5AD ); // additional unlock for INFO + } + AddtionalUnlockCodeSet(); // common additional unlock code set + + IOWrite32A( FLASHROM_FLA_ADR, ((UINT_32)SelMat << 16) | ( SetAddress & 0x00003C00 )) ; + // Sector Erase Start + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + IOWrite32A( FLASHROM_CMD, 4 ) ; + + WitTim( 5 ) ; + + UlCnt = 0 ; + + do { + if( UlCnt++ > 100 ){ ans = 2; break; } ; + + IORead32A( FLASHROM_FLAINT, &UlReadVal ) ; + } while( ( UlReadVal & 0x00000080 ) != 0 ) ; + + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + ans = UnlockCodeClear(); // Unlock Code Clear + if( ans != 0 ) return( ans ) ; // Unlock Code Set + + return( ans ) ; +} + +//******************************************************************************** +// Function Name : FlashSingleRead +// Retun Value : NON +// Argment Value : NON +// Explanation : <Flash Memory> Flash Single Read( 4 Byte read ) +// History : First edition +//******************************************************************************** +UINT_8 FlashSingleRead( UINT_8 SelMat, UINT_32 UlAddress, UINT_32 *PulData ) +{ + + // fail safe + // reject irregular mat + if( SelMat != USER_MAT && SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; // INF_MAT2‚àAccess‚µ‚È‚¢ + // reject command if address inner NVR3 + if( UlAddress > 0x000003FF ) return 9; + + IOWrite32A( FLASHROM_ACSCNT, 0x00000000 ); + IOWrite32A( FLASHROM_FLA_ADR, ((UINT_32)SelMat << 16) | ( UlAddress & 0x00003FFF ) ); + + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + IOWrite32A( FLASHROM_CMD, 0x00000001 ); + + IORead32A( FLASHROM_FLA_RDAT, PulData ) ; + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + + return( 0 ) ; +} + +//******************************************************************************** +// Function Name : FlashMultiRead +// Retun Value : NON +// Argment Value : NON +// Explanation : <Flash Memory> Flash Multi Read( 4 Byte * length max read : 128byte) +// History : First edition +//******************************************************************************** +UINT_8 FlashMultiRead( UINT_8 SelMat, UINT_32 UlAddress, UINT_32 *PulData , UINT_8 UcLength ) +{ + UINT_8 i ; + + // fail safe + // reject irregular mat + if( SelMat != USER_MAT && SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; // INF_MAT2‚ÍRead only Access‚µ‚È‚¢ + // reject command if address inner NVR3 + if( UlAddress > 0x000003FF ) return 9; + + IOWrite32A( FLASHROM_ACSCNT, 0x00000000 | (UINT_32)(UcLength-1) ); + IOWrite32A( FLASHROM_FLA_ADR, ((UINT_32)SelMat << 16) | ( UlAddress & 0x00003FFF ) ); + + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + IOWrite32A( FLASHROM_CMD, 0x00000001 ); + for( i=0 ; i < UcLength ; i++ ){ + IORead32A( FLASHROM_FLA_RDAT, &PulData[i] ) ; +TRACE("Read Data[%02x] = %08x\n", i , PulData[i] ); + } + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + + return( 0 ) ; +} + +//******************************************************************************** +// Function Name : FlashBlockWrite +// Retun Value : 0 : Success, 1 : Unlock Error, 2 : Time Out Error +// Argment Value : Info Mat , Flash Address +// Explanation : <Flash Memory> Block Erase +// History : First edition +// Unit of erase : informaton mat 64 Byte +// : user mat 64 Byte +//******************************************************************************** +UINT_8 FlashBlockWrite( UINT_8 SelMat , UINT_32 SetAddress , UINT_32 *PulData) +{ + UINT_32 UlReadVal, UlCnt; + UINT_8 ans = 0 ; + UINT_8 i ; + + // fail safe + // reject irregular mat +// if( SelMat != INF_MAT0 && SelMat != INF_MAT1 ) return 10; // USR MAT,INF_MAT2‚àAccess‚µ‚È‚¢ + if( SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; // USR MAT‚ÍAccess‚µ‚È‚¢ + // + if( SetAddress > 0x000003FF ) return 9; + + // Flash write€”õ + ans = UnlockCodeSet(); + if( ans != 0 ) return( ans ) ; // Unlock Code Set + + WritePermission(); // Write permission + if( SelMat != USER_MAT ){ + if( SelMat == INF_MAT2 ) IOWrite32A( 0xE07CCC, 0x00006A4B ); + else IOWrite32A( 0xE07CCC, 0x0000C5AD ); // additional unlock for INFO + } + AddtionalUnlockCodeSet(); // common additional unlock code set + + IOWrite32A( FLASHROM_FLA_ADR, ((UINT_32)SelMat << 16) | ( SetAddress & 0x000010 )) ;// address‚Ípage‚̂ݎw’è + // page write Start + IOWrite32A( FLASHROM_FLAMODE , 0x00000000); + IOWrite32A( FLASHROM_CMD, 2 ) ; + +// WitTim( 5 ) ; + + UlCnt = 0 ; + + for( i=0 ; i< 16 ; i++ ){ + IOWrite32A( FLASHROM_FLA_WDAT, PulData[i] ); // Write data +TRACE("Write Data[%d] = %08x\n", i , PulData[i] ); + } + do { + if( UlCnt++ > 100 ){ ans = 2; break; } ; + + IORead32A( FLASHROM_FLAINT, &UlReadVal ) ; + } while( ( UlReadVal & 0x00000080 ) != 0 ) ; + + // page program + IOWrite32A( FLASHROM_CMD, 8 ); + + do { + if( UlCnt++ > 100 ){ ans = 2; break; } ; + + IORead32A( FLASHROM_FLAINT, &UlReadVal ) ; + } while( ( UlReadVal & 0x00000080 ) != 0 ) ; + + IOWrite32A( FLASHROM_FLAMODE , 0x00000002); + ans = UnlockCodeClear(); // Unlock Code Clear + return( ans ) ; + +} + + + + + +//******************************************************************************** +// Function Name : WrHallCalData +// Retun Value : NON +// Argment Value : NON +// Explanation : Flash write hall calibration data +// History : First edition +//******************************************************************************** +UINT_8 WrHallCalData( UINT_8 UcMode ) +{ + UINT_32 UlMAT0[32]; + UINT_8 ans = 0, i; + UINT_16 UsCkVal,UsCkVal_Bk ; + +TRACE( "WrHallCalData : Mode = %d\n", UcMode); + /* Back up ******************************************************/ + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 1 ); + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT0 , 0 ); // all erase + if( ans != 0 ) return( 2 ) ; // Unlock Code Set + +#if DEBUG == 1 + for(i=0;i<32;i++){ +TRACE( "[ %d ] = %08x\n", i, UlMAT0[i] ); + } +#endif //DEBUG == 1 + /* modify *****************************************************/ + if( UcMode ){ // write + UlMAT0[CALIBRATION_STATUS] &= ~( HALL_CALB_FLG | HALL_CALB_BIT ); + UlMAT0[CALIBRATION_STATUS] |= (StAdjPar.StHalAdj.UlAdjPhs | GYRO_GAIN_FLG) ; // Calibration Status + UlMAT0[HALL_BIAS_OFFSET] = (UINT_32)(((UINT_32)(StAdjPar.StHalAdj.UsHlyOff&0xFF00)<<16) | ((UINT_32)(StAdjPar.StHalAdj.UsHlyGan & 0xFF00)<<8) | ((UINT_32)(StAdjPar.StHalAdj.UsHlxOff & 0xFF00)>>0) | ((UINT_32)(StAdjPar.StHalAdj.UsHlxGan & 0xFF00)>>8 )); + UlMAT0[LOOP_GAIN_XY] = ((StAdjPar.StLopGan.UlLygVal & 0xFFFF0000) | (StAdjPar.StLopGan.UlLxgVal>>16)); + UlMAT0[LENS_OFFSET] = (UINT_32)(((UINT_32)(StAdjPar.StHalAdj.UsAdyOff )<<16) | (UINT_32)(StAdjPar.StHalAdj.UsAdxOff )); + UlMAT0[GYRO_GAIN_X] = 0x3FFFFFFF; + UlMAT0[GYRO_GAIN_Y] = 0x3FFFFFFF; + UlMAT0[HL_XMAXMIN] = (UINT_32)(((UINT_32)StAdjPar.StHalAdj.UsHlxMxa<<16) | (UINT_32)StAdjPar.StHalAdj.UsHlxMna); + UlMAT0[HL_YMAXMIN] = (UINT_32)(((UINT_32)StAdjPar.StHalAdj.UsHlyMxa<<16) | (UINT_32)StAdjPar.StHalAdj.UsHlyMna); +//// UlMAT0[G_OFFSET_XY] = (UINT_32)(((UINT_32)StAdjPar.StGvcOff.UsGyoVal<<16) | (UINT_32)StAdjPar.StGvcOff.UsGxoVal); +//#ifdef SEL_SHIFT_COR +//// UlMAT0[G_OFFSET_Z_AX] = (UINT_32)(((UINT_32)(StAclVal.StAccel.SlOffsetX )<<16) | (UINT_32)(StAdjPar.StGvcOff.UsGzoVal )); +//// UlMAT0[A_OFFSET_YZ] = (UINT_32)(((UINT_32)(StAclVal.StAccel.SlOffsetZ )<<16) | (UINT_32)(StAclVal.StAccel.SlOffsetY )); +//#endif +// UlMAT0[LENS_OFFSET_BK] = (UINT_32)(((UINT_32)(StAdjPar.StHalAdj.UsAdyOff )<<16) | (UINT_32)(StAdjPar.StHalAdj.UsAdxOff )); + }else{ + UlMAT0[CALIBRATION_STATUS] |= ( HALL_CALB_FLG | 0x000000FF | GYRO_GAIN_FLG ); + UlMAT0[HALL_BIAS_OFFSET] = 0xFFFFFFFF; + UlMAT0[LOOP_GAIN_XY] = 0xFFFFFFFF; + UlMAT0[LENS_OFFSET] = 0xFFFFFFFF; + UlMAT0[GYRO_GAIN_X] = 0xFFFFFFFF; + UlMAT0[GYRO_GAIN_Y] = 0xFFFFFFFF; + UlMAT0[HL_XMAXMIN] = 0xFFFFFFFF; + UlMAT0[HL_YMAXMIN] = 0xFFFFFFFF; +// UlMAT0[G_OFFSET_XY] = 0xFFFFFFFF; +//#ifdef SEL_SHIFT_COR +// UlMAT0[G_OFFSET_Z_AX] = 0xFFFFFFFF; +// UlMAT0[A_OFFSET_YZ] = 0xFFFFFFFF; +//#endif +// UlMAT0[LENS_OFFSET_BK] = 0xFFFFFFFF; + } + /* calcurate check sum ******************************************/ + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UlMAT0[MAT0_CKSM] = ((UINT_32)UsCkVal<<16) | ( UlMAT0[MAT0_CKSM] & 0x0000FFFF); + + /* update ******************************************************/ + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x00 , UlMAT0 ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x10 , &UlMAT0[0x10] ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + + /* Verify ******************************************************/ + UsCkVal_Bk = UsCkVal; + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 4 ); + + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UsCkVal, UsCkVal_Bk ); + if( UsCkVal != UsCkVal_Bk ) return(5); + +TRACE( "WrHallCalData____COMPLETE\n" ); + return(0); +} + +//******************************************************************************** +// Function Name : WrGyroGainData +// Retun Value : NON +// Argment Value : NON +// Explanation : Flash write gyro gain data +// History : First edition +//******************************************************************************** +UINT_8 WrGyroGainData( UINT_8 UcMode ) +{ + UINT_32 UlMAT0[32]; + UINT_32 UlReadGxzoom , UlReadGyzoom; + UINT_8 ans = 0, i; + UINT_16 UsCkVal,UsCkVal_Bk ; + +TRACE( "WrGyroGainData : Mode = %d\n", UcMode); + /* Back up ******************************************************/ + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 1 ); + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT0 , 0 ); // all erase + if( ans != 0 ) return( 2 ) ; // Unlock Code Set + +#if DEBUG == 1 + for(i=0;i<32;i++){ +TRACE( "[ %d ] = %08x\n", i, UlMAT0[i] ); + } +#endif //DEBUG == 1 + /* modify *****************************************************/ + if( UcMode ){ // write + RamRead32A( GyroFilterTableX_gxzoom , &UlReadGxzoom ) ; + RamRead32A( GyroFilterTableY_gyzoom , &UlReadGyzoom ) ; + + UlMAT0[CALIBRATION_STATUS] &= ~( GYRO_GAIN_FLG ); + UlMAT0[GYRO_GAIN_X] = UlReadGxzoom; + UlMAT0[GYRO_GAIN_Y] = UlReadGyzoom; + }else{ + UlMAT0[CALIBRATION_STATUS] |= GYRO_GAIN_FLG; + UlMAT0[GYRO_GAIN_X] = 0x3FFFFFFF; + UlMAT0[GYRO_GAIN_Y] = 0x3FFFFFFF; + } + /* calcurate check sum ******************************************/ + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UlMAT0[MAT0_CKSM] = ((UINT_32)UsCkVal<<16) | ( UlMAT0[MAT0_CKSM] & 0x0000FFFF); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + + /* update ******************************************************/ + ans = FlashBlockWrite( INF_MAT0 , 0 , UlMAT0 ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x10 , &UlMAT0[0x10] ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + + /* Verify ******************************************************/ + UsCkVal_Bk = UsCkVal; + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 4 ); + + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UsCkVal, UsCkVal_Bk ); + if( UsCkVal != UsCkVal_Bk ) return(5); + +TRACE( "WrGyroGainData____COMPLETE\n" ); + return(0); +} + +//******************************************************************************** +// Function Name : WrLinCalData +// Retun Value : NON +// Argment Value : NON +// Explanation : Flash write Hall Linearity data +// History : First edition +//******************************************************************************** +UINT_8 WrLinCalData( UINT_8 UcMode, mlLinearityValue *linval ) +{ + UINT_32 UlMAT0[32]; + UINT_8 ans = 0, i; + UINT_16 UsCkVal,UsCkVal_Bk ; + double *pPosX, *pPosY; + UINT_32 PosDifX, PosDifY; + DSPVER Info; + LINCRS* LnCsPtr; + + GetInfomationAfterStartUp( &Info ); + if( Info.ActType == 0x01 ) { + LnCsPtr = (LINCRS*)&ACT01_LinCrsParameter; + } +TRACE( "WrLinCalData : Mode = %d\n", UcMode); + /* Back up ******************************************************/ + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 1 ); + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT0 , 0 ); // all erase + if( ans != 0 ) return( 2 ) ; // Unlock Code Set + +#if DEBUG == 1 + for(i=0;i<32;i++){ +TRACE( "[ %d ] = %08x\n", i, UlMAT0[i] ); + } +#endif //DEBUG == 1 + /* modify *****************************************************/ + if( UcMode ){ // write + if( LnCsPtr->XY_SWAP ==1 ){ + pPosX = linval->positionY; + pPosY = linval->positionX; + }else{ + pPosX = linval->positionX; + pPosY = linval->positionY; + } + UlMAT0[CALIBRATION_STATUS] &= ~( HLLN_CALB_FLG ); + UlMAT0[LN_POS1] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS2] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS3] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS4] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS5] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS6] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS7] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + if( LnCsPtr->XY_SWAP ==1 ){ + PosDifX = LnCsPtr->STEPY; + PosDifY = LnCsPtr->STEPX; + }else{ + PosDifX = LnCsPtr->STEPX; + PosDifY = LnCsPtr->STEPY; + } + UlMAT0[LN_STEP] = (UINT_32)(((UINT_32)PosDifY << 16) | (UINT_32)PosDifX); + }else{ + UlMAT0[CALIBRATION_STATUS] |= HLLN_CALB_FLG; + UlMAT0[LN_POS1] = 0xFFFFFFFF; + UlMAT0[LN_POS2] = 0xFFFFFFFF; + UlMAT0[LN_POS3] = 0xFFFFFFFF; + UlMAT0[LN_POS4] = 0xFFFFFFFF; + UlMAT0[LN_POS5] = 0xFFFFFFFF; + UlMAT0[LN_POS6] = 0xFFFFFFFF; + UlMAT0[LN_POS7] = 0xFFFFFFFF; + UlMAT0[LN_STEP] = 0xFFFFFFFF; + } + /* calcurate check sum ******************************************/ + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UlMAT0[MAT0_CKSM] = ((UINT_32)UsCkVal<<16) | ( UlMAT0[MAT0_CKSM] & 0x0000FFFF); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + + /* update ******************************************************/ + ans = FlashBlockWrite( INF_MAT0 , 0 , UlMAT0 ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x10 , &UlMAT0[0x10] ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + + /* Verify ******************************************************/ + UsCkVal_Bk = UsCkVal; + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 4 ); + + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UsCkVal, UsCkVal_Bk ); + if( UsCkVal != UsCkVal_Bk ) return(5); + +TRACE( "WrLinCalData____COMPLETE\n" ); + return(0); +} + +//******************************************************************************** +// Function Name : WrMixCalData +// Retun Value : NON +// Argment Value : NON +// Explanation : Flash write cross talk data +// History : First edition +//******************************************************************************** +UINT_8 WrMixCalData( UINT_8 UcMode, mlMixingValue *mixval ) +{ + UINT_32 UlMAT0[32]; + UINT_8 ans = 0, i; + UINT_16 UsCkVal,UsCkVal_Bk ; + DSPVER Info; + LINCRS* LnCsPtr; + + GetInfomationAfterStartUp( &Info ); + if( Info.ActType == 0x01 ) { + LnCsPtr = (LINCRS*)&ACT01_LinCrsParameter; + } + +TRACE( "WrMixCalData : Mode = %d\n", UcMode); + /* Back up ******************************************************/ + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 1 ); + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT0 , 0 ); // all erase + if( ans != 0 ) return( 2 ) ; // Unlock Code Set + +#if DEBUG == 1 + for(i=0;i<32;i++){ +TRACE( "[ %d ] = %08x\n", i, UlMAT0[i] ); + } +#endif //DEBUG + /* modify *****************************************************/ + if( UcMode ){ // write + mixval->hx45yL = (-1)*mixval->hx45yL; + mixval->hy45xL = (-1)*mixval->hy45xL; + + if(mixval->hy45yL<0){ /* for MeasurementLibrary 1.X */ + mixval->hy45yL = (-1)*mixval->hy45yL; + mixval->hx45yL = (-1)*mixval->hx45yL; + } + + if(( LnCsPtr->STEPX*LnCsPtr->DRIVEX > 0 && LnCsPtr->STEPY*LnCsPtr->DRIVEY < 0 ) + || ( LnCsPtr->STEPX*LnCsPtr->DRIVEX < 0 && LnCsPtr->STEPY*LnCsPtr->DRIVEY > 0 )){ + mixval->hx45yL = (-1)*mixval->hx45yL; + mixval->hy45xL = (-1)*mixval->hy45xL; + } + + UlMAT0[CALIBRATION_STATUS] &= ~( MIXI_CALB_FLG ); + UlMAT0[MIXING_X] = (UINT_32)((mixval->hx45yL & 0xFFFF0000) | (( mixval->hx45xL >> 16) & 0x0000FFFF)); + UlMAT0[MIXING_Y] = (UINT_32)((mixval->hy45xL & 0xFFFF0000) | (( mixval->hy45yL >> 16) & 0x0000FFFF)); + UlMAT0[MIXING_SFT] = (UINT_32)((((UINT_32)mixval->hysx << 8) & 0x0000FF00) | ((UINT_32)mixval->hxsx & 0x000000FF )); + }else{ + UlMAT0[CALIBRATION_STATUS] |= MIXI_CALB_FLG; + UlMAT0[MIXING_X] = 0xFFFFFFFF; + UlMAT0[MIXING_Y] = 0xFFFFFFFF; + UlMAT0[MIXING_SFT] = 0xFFFFFFFF; + } + /* calcurate check sum ******************************************/ + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UlMAT0[MAT0_CKSM] = ((UINT_32)UsCkVal<<16) | ( UlMAT0[MAT0_CKSM] & 0x0000FFFF); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + + /* update ******************************************************/ + ans = FlashBlockWrite( INF_MAT0 , 0 , UlMAT0 ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x10 , &UlMAT0[0x10] ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + + /* Verify ******************************************************/ + UsCkVal_Bk = UsCkVal; + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 4 ); + + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UsCkVal, UsCkVal_Bk ); + if( UsCkVal != UsCkVal_Bk ) return(5); + +TRACE( "WrMixCalData____COMPLETE\n" ); + return(0); +} + +//******************************************************************************** +// Function Name : WrLinMixCalData +// Retun Value : NON +// Argment Value : NON +// Explanation : Flash write cross talk & Linearity data +// History : First edition +//******************************************************************************** +UINT_8 WrLinMixCalData( UINT_8 UcMode, mlMixingValue *mixval , mlLinearityValue *linval ) +{ + UINT_32 UlMAT0[32]; + UINT_8 ans = 0 , i ; + UINT_16 UsCkVal,UsCkVal_Bk ; + double *pPosX, *pPosY; + UINT_32 PosDifX, PosDifY; + DSPVER Info; + LINCRS* LnCsPtr; + + GetInfomationAfterStartUp( &Info ); + + if( Info.ActType == 0x01 ) { + LnCsPtr = (LINCRS*)&ACT01_LinCrsParameter; + } + +TRACE( "WrLinMixCalData : Mode = %d\n", UcMode); + /* Back up ******************************************************/ + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 1 ); + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT0 , 0 ); // all erase + if( ans != 0 ) return( 2 ) ; // Unlock Code Set + +#if DEBUG == 1 + for(i=0;i<32;i++){ +TRACE( "[ %d ] = %08x\n", i, UlMAT0[i] ); + } +#endif //DEBUG == 1 + /* modify *****************************************************/ + if( UcMode ){ // write + if( LnCsPtr->XY_SWAP ==1 ){ + pPosX = linval->positionY; + pPosY = linval->positionX; + }else{ + pPosX = linval->positionX; + pPosY = linval->positionY; + } + UlMAT0[CALIBRATION_STATUS] &= ~( HLLN_CALB_FLG | MIXI_CALB_FLG ); + UlMAT0[LN_POS1] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS2] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS3] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS4] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS5] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS6] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + UlMAT0[LN_POS7] = (UINT_32)((UINT_32)(*pPosY++ * 10)<<16) | (UINT_32)(*pPosX++ * 10); + if( LnCsPtr->XY_SWAP ==1 ){ + PosDifX = (linval->dacY[4]>>16); + PosDifY = (linval->dacX[4]>>16); + }else{ + PosDifX = (linval->dacX[4]>>16); + PosDifY = (linval->dacY[4]>>16); + } + UlMAT0[LN_STEP] = (UINT_32)(((UINT_32)PosDifY << 16) | (UINT_32)PosDifX); + + mixval->hx45yL = (-1)*mixval->hx45yL; + mixval->hy45xL = (-1)*mixval->hy45xL; + + if(mixval->hy45yL<0){ /* for MeasurementLibrary 1.X */ + mixval->hy45yL = (-1)*mixval->hy45yL; + mixval->hx45yL = (-1)*mixval->hx45yL; + } + + //*****************************************************// + /* X ‚Æ Y ‚ÅStep ‹É«‚ªˆá‚¤Žž */ + if(( (INT_32)linval->dacY[4] > 0 && (INT_32)linval->dacX[4] < 0 ) || ( (INT_32)linval->dacY[4] < 0 && (INT_32)linval->dacX[4] > 0 )){ + mixval->hx45yL = (-1)*mixval->hx45yL; + mixval->hy45xL = (-1)*mixval->hy45xL; + } + //****************************************************// + + UlMAT0[MIXING_X] = (UINT_32)((mixval->hx45yL & 0xFFFF0000) | (( mixval->hx45xL >> 16) & 0x0000FFFF)); + UlMAT0[MIXING_Y] = (UINT_32)((mixval->hy45xL & 0xFFFF0000) | (( mixval->hy45yL >> 16) & 0x0000FFFF)); + UlMAT0[MIXING_SFT] = (UINT_32)((((UINT_32)mixval->hysx << 8) & 0x0000FF00) | ((UINT_32)mixval->hxsx & 0x000000FF )); + }else{ + UlMAT0[CALIBRATION_STATUS] |= ( HLLN_CALB_FLG | MIXI_CALB_FLG ); + UlMAT0[LN_POS1] = 0xFFFFFFFF; + UlMAT0[LN_POS2] = 0xFFFFFFFF; + UlMAT0[LN_POS3] = 0xFFFFFFFF; + UlMAT0[LN_POS4] = 0xFFFFFFFF; + UlMAT0[LN_POS5] = 0xFFFFFFFF; + UlMAT0[LN_POS6] = 0xFFFFFFFF; + UlMAT0[LN_POS7] = 0xFFFFFFFF; + UlMAT0[LN_STEP] = 0xFFFFFFFF; + UlMAT0[MIXING_X] = 0xFFFFFFFF; + UlMAT0[MIXING_Y] = 0xFFFFFFFF; + UlMAT0[MIXING_SFT] = 0xFFFFFFFF; + } + /* calcurate check sum ******************************************/ + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UlMAT0[MAT0_CKSM] = ((UINT_32)UsCkVal<<16) | ( UlMAT0[MAT0_CKSM] & 0x0000FFFF); +TRACE( "UlMAT0[ %d ] = %08x\n", i, UlMAT0[i] ); + + /* update ******************************************************/ + ans = FlashBlockWrite( INF_MAT0 , 0 , UlMAT0 ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x10 , &UlMAT0[0x10] ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + + /* Verify ******************************************************/ + UsCkVal_Bk = UsCkVal; + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 4 ); + + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UsCkVal, UsCkVal_Bk ); + if( UsCkVal != UsCkVal_Bk ) return(5); + +TRACE( "WrLinMixCalData____COMPLETE\n" ); + return(0); +} + + + +//******************************************************************************** +// Function Name : WrOptCenerData +// Retun Value : NON +// Argment Value : NON +// Explanation : Flash write hall calibration data +// History : First edition +//******************************************************************************** +UINT_8 WrOptCenerData( UINT_8 UcMode ) +{ + UINT_32 UlMAT0[32]; + UINT_8 ans = 0, i; + UINT_16 UsCkVal,UsCkVal_Bk ; + UINT_32 UlReadLensxoffset,UlReadLensyoffset; + +TRACE( "WrOptCenerData : Mode = %d\n", UcMode); + /* Back up ******************************************************/ + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 1 ); + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT0 , 0 ); // all erase + if( ans != 0 ) return( 2 ) ; // Unlock Code Set + +#if DEBUG == 1 + for(i=0;i<32;i++){ +TRACE( "[ %d ] = %08x\n", i, UlMAT0[i] ); + } +#endif //DEBUG == 1 + /* modify *****************************************************/ + if( UcMode ){ // write + RamRead32A( OpticalOffset_X , &UlReadLensxoffset ) ; + RamRead32A( OpticalOffset_Y , &UlReadLensyoffset ) ; + UlMAT0[OPTCENTER] = (UINT_32)((UlReadLensyoffset & 0xFFFF0000) | ((UlReadLensxoffset >> 16 ) & 0x0000FFFF)); + }else{ + UlMAT0[OPTCENTER] = 0x00000000; + } + /* calcurate check sum ******************************************/ + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UlMAT0[MAT0_CKSM] = ((UINT_32)UsCkVal<<16) | ( UlMAT0[MAT0_CKSM] & 0x0000FFFF); + + /* update ******************************************************/ + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x00 , UlMAT0 ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT0 , (UINT_32)0x10 , &UlMAT0[0x10] ); + if( ans != 0 ) return( 3 ) ; // Unlock Code Set + + /* Verify ******************************************************/ + UsCkVal_Bk = UsCkVal; + ans =FlashMultiRead( INF_MAT0, 0, UlMAT0, 32 ); // check sum ˆÈŠO + if( ans ) return( 4 ); + + UsCkVal = 0; + for( i=0; i < 31; i++ ){ + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + UsCkVal += (UINT_8)(UlMAT0[i]>>16); + UsCkVal += (UINT_8)(UlMAT0[i]>>24); + } + // Remainder + UsCkVal += (UINT_8)(UlMAT0[i]>>0); + UsCkVal += (UINT_8)(UlMAT0[i]>>8); + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UsCkVal, UsCkVal_Bk ); + if( UsCkVal != UsCkVal_Bk ) return(5); + +TRACE( "WrOptCenerData____COMPLETE\n" ); + return(0); +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : lstsq */ +/* input parameter : double x[] X޲‚Ì”z—ñƒf[ƒ^ */ +/* double y[] Y޲‚Ì”z—ñƒf[ƒ^ */ +/* int n ƒf[ƒ^ŒÂ” */ +/* int m ‹ßŽ—‘½€Ž®ŽŸ” */ +/* output parameter : double c[] ‹ßŽ—‚µ‚½Še€‚ÌŒW””z—ñ */ +/* –ß‚è’l‚ÍA0‚ųíA-1‚ÅŽû‘©Ž¸”s */ +/* comment : Ŭ2æ‹ßŽ—–@ */ +/* 2018.03.07 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +INT_32 lstsq( double x[], double y[], INT_32 n, INT_32 m, double c[] ) +{ + INT_32 i, j, k, m2, mp1, mp2; + double *a, aik, pivot, *w, w1, w2, w3; + + if(m >= n || m < 1) { + return -1; + } + + mp1 = m + 1; + mp2 = m + 2; + m2 = 2 * m; + a = (double *)kzalloc(mp1 * mp2 * sizeof(double), GFP_KERNEL); + if(a == NULL) { + return -1; + } + w = (double *)kzalloc(mp1 * 2 * sizeof(double), GFP_KERNEL); + if(w == NULL) { + kfree(a); + return -1; + } + + for(i = 0; i < m2; i++) { + w1 = 0.; + for(j = 0; j < n; j++) { + w2 = w3 = x[j]; + for(k = 0; k < i; k++) w2 *= w3; + w1 += w2; + } + w[i] = w1; + } + a[0] = n; + for(i = 0; i < mp1; i++) + for(j = 0; j < mp1; j++) if(i || j) a[i * mp2 + j] = w[i + j - 1]; + + w1 = 0.; + for(i = 0; i < n; i++) w1 += y[i]; + a[mp1] = w1; + for(i = 0; i < m; i++) { + w1 = 0.; + for(j = 0; j < n; j++) { + w2 = w3 = x[j]; + for(k = 0; k < i; k++) w2 *= w3; + w1 += y[j] * w2; + } + a[mp2 * (i + 1) + mp1] = w1; + } + + for(k = 0; k < mp1; k++) { + pivot = a[mp2 * k + k]; + a[mp2 * k + k] = 1.0; + for(j = k + 1; j < mp2; j++) a[mp2 * k + j] /= pivot; + for(i = 0; i < mp1; i++) { + if(i != k) { + aik = a[mp2 * i + k]; + for(j = k; j < mp2; j++) a[mp2 * i + j] -= aik * a[mp2 * k + j]; + } + } + } + for(i = 0; i < mp1; i++) c[i] = a[mp2 * i + mp1]; + + kfree(w); + kfree(a); + return 0; +} + +//******************************************************************************** +// Function Name : Mat2ReWrite +// Retun Value : NON +// Argment Value : NON +// Explanation : Mat2 re-write function +// History : First edition +//******************************************************************************** +UINT_8 Mat2ReWrite( void ) +{ + UINT_32 UlMAT2[32]; + UINT_32 UlCKSUM=0; + UINT_8 ans , i ; + UINT_32 UlCkVal ,UlCkVal_Bk; + + ans = FlashMultiRead( INF_MAT2, 0, UlMAT2, 32 ); + if(ans) return( 0xA0 ); + /* FT_REPRG check *****/ +// if( UlMAT2[FT_REPRG] == PRDCT_WR || UlMAT2[FT_REPRG] == USER_WR ){ + if( UlMAT2[FT_REPRG] == USER_WR ){ +TRACE( "Already re-write\n" ); + return( 0x00 ); // not need + } + + /* Check code check *****/ + if( UlMAT2[CHECKCODE1] != CHECK_CODE1 ) return( 0xA1 ); + if( UlMAT2[CHECKCODE2] != CHECK_CODE2 ) return( 0xA2 ); + + /* Check sum check *****/ + for( i=16 ; i<MAT2_CKSM ; i++){ + UlCKSUM += UlMAT2[i]; + } + if(UlCKSUM != UlMAT2[MAT2_CKSM]) return( 0xA3 ); + + /* registor re-write flag *****/ + UlMAT2[FT_REPRG] = USER_WR; + + /* backup sum check before re-write *****/ + UlCkVal_Bk = 0; + for( i=0; i < 32; i++ ){ // ‘S—̈æ + UlCkVal_Bk += UlMAT2[i]; + } + + /* Erase ******************************************************/ + ans = FlashBlockErase( INF_MAT2 , 0 ); // all erase + if( ans != 0 ) return( 0xA4 ) ; // Unlock Code Set + + /* excute re-write *****/ + ans = FlashBlockWrite( INF_MAT2 , 0 , UlMAT2 ); + if( ans != 0 ) return( 0xA5 ) ; // Unlock Code Set + ans = FlashBlockWrite( INF_MAT2 , (UINT_32)0x10 , &UlMAT2[0x10] ); + if( ans != 0 ) return( 0xA5 ) ; // Unlock Code Set + + ans =FlashMultiRead( INF_MAT2, 0, UlMAT2, 32 ); + if( ans ) return( 0xA0 ); + + UlCkVal = 0; + for( i=0; i < 32; i++ ){ // ‘S—̈æ + UlCkVal += UlMAT2[i]; + } + +TRACE( "[RVAL]:[BVal]=[%04x]:[%04x]\n",UlCkVal, UlCkVal_Bk ); + if( UlCkVal != UlCkVal_Bk ) return( 0xA6 ); // write data != writen data + + return( 0x01 ); // re-write ok +} + + +//#ifdef TRNT +//******************************************************************************** +// Function Name : LoadUareToPM +// Retun Value : NON +// Argment Value : chiperase +// Explanation : load user area data from Flash memory to PM +// History : First edition +//******************************************************************************** +UINT_8 LoadUareToPM( DOWNLOAD_TBL_EXT* ptr , UINT_8 mode ) +{ + UINT_8 ans=0; + UINT_32 UlReadVal=0; + UINT_32 UlReadVer; + UINT_32 UlCnt=0; + + if( !mode ){ + RamRead32A( 0x8000 , &UlReadVer ); + if( (UlReadVer & 0xFFFFFF00) == 0x01120000 ){ + RamWrite32A( 0xE000 , 0x00000000 ); // to boot + WitTim( 15 ) ; // BootƒvƒƒOƒ‰ƒ€‚ð‰ñ‚·‚Ì‚É15msec•K—vB +//neo: need to reduce this time + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + }else{ + return( 0x01 ); // NG + } + if( UlReadVal != 0x0B ){ + IOWrite32A( SYSDSP_REMAP, 0x00001400 ) ; // CORE_RST[12], MC_IGNORE2[10] = 1 + WitTim( 15 ) ; // BootƒvƒƒOƒ‰ƒ€‚ð‰ñ‚·‚Ì‚É15msec•K—vB +//neo: need to reduce this time + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + if( UlReadVal != 0x0B) { + return( 0x02 ); + } + } + + ans = PmemUpdate128( ptr ); // Update the special program for updating the flash memory. + if(ans != 0) return( ans ); + } + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0xF007, 0x00000000 ); // boot command Access Setup + RamWrite32A( 0x5004 , 0x00000000 ); // Trans user data from flash memory to pm + + do{ + WitTim( 1 ); + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x10) ; // trans ng + } + RamRead32A( 0x5004, &UlReadVal ); // PmCheck.ExecFlag‚̓ǂÝo‚µ + }while ( UlReadVal != 0 ); + IOWrite32A( 0xE0701C , 0x00000002); + + return( 0 ); +} + +//******************************************************************************** +// Function Name : RdUareaFromPm +// Retun Value : NON +// Argment Value : chiperase +// Explanation : Read user area data from program memory +// History : First edition +//******************************************************************************** +UINT_8 RdBurstUareaFromPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ) +{ + if(!UcLength) return(0xff); + if( !mode ){ + RamWrite32A( 0x5000 , UlAddress ); + } + RamWrite32A( 0x5002 , (UINT_32)UcLength ); + WitTim( 1 ) ; // 1ms Wait for prepare trans data + CntRd( 0x5002 , PucData , (UINT_16)UcLength+1); + + return( 0 ); +} +UINT_8 RdSingleUareaFromPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ) +{ + UINT_8 i; + UINT_32 ReadData; + if(!UcLength) return(0xff); + if( !mode ){ + RamWrite32A( 0x5000 , UlAddress ); + } + for( i=0 ; i <= UcLength ; ) + { + RamRead32A( 0x5001 , &ReadData ); +//TRACE("[%02x]%08x\n",i,ReadData); + PucData[i++] = (UINT_8)(ReadData >> 24); + PucData[i++] = (UINT_8)(ReadData >> 16); + PucData[i++] = (UINT_8)(ReadData >> 8); + PucData[i++] = (UINT_8)(ReadData >> 0); + } + + return( 0 ); +} + +//******************************************************************************** +// Function Name : WrUareaToPm +// Retun Value : NON +// Argment Value : chiperase +// Explanation : Write user area data to PM +// History : First edition +//******************************************************************************** +UINT_8 WrUareaToPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ) +{ + UINT_8 i; + UINT_8 PucBuf[254]; // address2Byte + data252Byte + + if(!UcLength) return(0xff); + + PucBuf[0] = 0x50; + PucBuf[1] = 0x01; + + for(i=0 ; i<=UcLength ; i++) + { + PucBuf[i+2] = PucData[i]; +TRACE("[%02x:%02x]",i+2,PucBuf[i+2]); + } +TRACE("\n"); + if( !mode ){ + RamWrite32A( 0x5000 , UlAddress ); + } + CntWrt( PucBuf , (UINT_16)UcLength+3 ); + + return( 0 ); +} + +//******************************************************************************** +// Function Name : WrUareaToFlash +// Retun Value : NON +// Argment Value : chiperase +// Explanation : Update user area data from PM to Flash memory +// History : First edition +//******************************************************************************** +UINT_8 WrUareaToFlash( void ) +{ + UINT_32 UlReadVal; + UINT_32 UlCntE=0; + UINT_32 UlCntW=0; + UINT_8 ans=0; + + ans = UnlockCodeSet(); + if( ans != 0 ) return( ans ) ; // Unlock Code Set + WritePermission(); // Write Permission + AddtionalUnlockCodeSet(); // Additional Unlock Code Set + + IOWrite32A( 0xE0701C , 0x00000000); // +// RamWrite32A( 0xF007, 0x00000000 ); // FlashAccess Setup + + RamWrite32A( 0x5005 , 0x00000000 ); // erase User area data on flash memory + + WitTim( 10 );//neo: need to reduce this time + do{ + WitTim( 1 ); + if( UlCntE++ > 20 ) { + IOWrite32A( 0xE0701C , 0x00000002); + if( UnlockCodeClear() != 0 ) return (0x11) ; // unlock code clear ng + return (0x10) ; // erase ng + } + RamRead32A( 0x5005, &UlReadVal ); // complite Flag‚̓ǂÝo‚µ + }while ( UlReadVal != 0 ); + + RamWrite32A( 0x5006 , 0x00000000 ); // write user area data from PM to flash memory + + WitTim( 300 );//neo: need to reduce this time + do{ + WitTim( 1 ); + if( UlCntW++ > 300 ) { + IOWrite32A( 0xE0701C , 0x00000002); + if( UnlockCodeClear() != 0 ) return (0x21) ; // unlock code clear ng + return (0x20) ; // write ng + } + RamRead32A( 0x5006, &UlReadVal ); // complite Flag‚̓ǂÝo‚µ + }while ( UlReadVal != 0 ); + IOWrite32A( 0xE0701C , 0x00000002); + if( UnlockCodeClear() != 0 ) return (0x31) ; // unlock code clear ng + +TRACE("[E-CNT: %d] [W-CNT: %d]\n",UlCntE,UlCntW); + return( 0 ); +} +//#endif diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FlsDownload.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FlsDownload.c new file mode 100755 index 0000000000000000000000000000000000000000..9941bc65ab995b1b7811850dedcec9a1ec02491e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FlsDownload.c @@ -0,0 +1,114 @@ +//******************************************************************************** +// +// << LC898128 Evaluation Soft >> +// Program Name : FlsDownload.c +// History : First edition +//******************************************************************************** +#define __OISDWL__ +//************************** +// Include Header File +//************************** +#include "Ois.h" + +#include "OisAPI.h" + +// 19811 Wide +#include "FromCode_01_02_01_00.h" + +// 19811 Tele +#include "FromCode_01_02_02_01.h" + +#include "OisDWL.h" + +//**************************************************** +// CUSTOMER NECESSARY CREATING FUNCTION LIST +//**************************************************** +//#ifdef TRNT +extern INT_32 RamRead32A( UINT_16, void * ); +//#endif + +//******************************************************************************** +// Function Name : FlashUpload128 +// Retun Value : NON +// Argment Value : chiperase +// Explanation : Flash Update for LC898128 +// History : First edition +//******************************************************************************** +const DOWNLOAD_TBL_EXT DTbl[] = { + {0x0101, 0, 1, CcUpdataCode128_01_02_01_00, UpDataCodeSize_01_02_01_00, UpDataCodeCheckSum_01_02_01_00, CcFromCode128_01_02_01_00, sizeof(CcFromCode128_01_02_01_00), FromCheckSum_01_02_01_00, FromCheckSumSize_01_02_01_00 }, + {0x0101, 1, 1, CcUpdataCode128_01_02_02_01, UpDataCodeSize_01_02_02_01, UpDataCodeCheckSum_01_02_02_01, CcFromCode128_01_02_02_01, sizeof(CcFromCode128_01_02_02_01), FromCheckSum_01_02_02_01, FromCheckSumSize_01_02_02_01 }, + {0xFFFF, 0, 0, (void*)0, 0, 0, (void*)0, 0, 0, 0} +}; + +UINT_8 FlashUpload128( UINT_8 ModuleVendor, UINT_8 ActVer, UINT_8 MasterSlave, UINT_8 FWType) +{ + DOWNLOAD_TBL_EXT* ptr ; + UINT_32 data; + + ptr = ( DOWNLOAD_TBL_EXT * )DTbl ; + + do { + if( (ptr->Index == ( ((UINT_16)ModuleVendor<<8) + ActVer)) && (ptr->FWType == FWType) && (ptr->MasterSlave == MasterSlave)) { + + // UploadFile‚ª64Byte‚Ý‚ÉPadding‚³‚ê‚Ä‚¢‚È‚¢‚È‚ç‚ÎAErrorB + if( ( ptr->SizeFromCode % 64 ) != 0 ) return (0xF1) ; + + if(!RamRead32A(0x8000, &data)) { + if (data == (ptr->FromCode[153] << 24 | + ptr->FromCode[154] << 16 | + ptr->FromCode[155] << 8 | + ptr->FromCode[156])) { + TRACE("The FW is the latest, no need to upload\n"); + return 0; + } else { + TRACE("The FW 0x%x is not the latest 0x%x, will upload\n", data, (ptr->FromCode[153] << 24 | + ptr->FromCode[154] << 16 | + ptr->FromCode[155] << 8 | + ptr->FromCode[156])); + } + } else { + TRACE("Read 0x8000 failed\n"); + return 0xF2; + } + + return FlashUpdate128( ptr ); + } + ptr++ ; + } while (ptr->Index != 0xFFFF ) ; + + return 0xF0 ; +} + +//#ifdef TRNT +UINT_8 LoadUserAreaToPM( void ) +{ + DOWNLOAD_TBL_EXT* ptr ; + UINT_32 UlReadVernum; + UINT_8 ModuleVendor; + UINT_8 ActVer; + + ptr = ( DOWNLOAD_TBL_EXT * )DTbl ; + + RamRead32A( 0x8000 , &UlReadVernum ); + ModuleVendor = (UINT_8)((UlReadVernum & 0xFF000000) >> 24); + RamRead32A( 0x8004 , &UlReadVernum ); + ActVer = (UINT_8)((UlReadVernum & 0x0000FF00) >> 8); + +TRACE(" VENDER = %02x , ACT = %02x \n", ModuleVendor , ActVer ); + do { + if( ptr->Index == ( ((UINT_16)ModuleVendor<<8) + ActVer) ) { + + if( ( ptr->SizeFromCode % 64 ) != 0 ) return (0xF1) ; + + return LoadUareToPM( ptr , 0 ); + } + ptr++ ; + } while (ptr->Index != 0xFFFF ) ; + + return 0xF0 ; +} + +//#endif + + + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_01.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_01.h new file mode 100755 index 0000000000000000000000000000000000000000..09c74c907d4a2fd89d71d737caa265e27c81c5b9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_01.h @@ -0,0 +1,6430 @@ +/** + * @brief LC898128 OIS PRODUCT + * + * @author Copyright (C) 2018 ON Semiconductor All Rights Reserved. + * + **/ + +// Version Name : "01-31-2018" +// Time Stamp : 2019/08/20 13:32:41 + +#define FromCodeBlockSize_01_01 6 + +#define FromCheckSumSize_01_01 0x00001797 +#define FromCheckSum_01_01 0xea467741 + +#define UpDataCodeSize_01_01 0x0000015e +#define UpDataCodeCheckSum_01_01 0x00007a7a646642d9 + +// [0001120002] [0000000102] [0000000000] [0000000000] + +//#define SELECT_VENDOR 1 +//#define SELECT_ACT 1 + +const unsigned char CcFromCode128_01_01[] = { +0x00, 0x01, 0x02, 0x03, +0x04, 0x05, 0x06, 0x07, +0x58, 0x10, 0x00, 0x00, +0xf6, 0x64, 0x3b, 0x57, +0x48, 0xe2, 0x05, 0x00, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, + +0x64, 0x00, 0x00, 0x03, +0x87, 0x64, 0x00, 0x00, +0x15, 0xa7, 0x64, 0x00, +0x00, 0x19, 0x27, 0x64, +0x00, 0x00, 0x1d, 0x47, +0x64, 0x00, 0x00, 0x1d, +0x67, 0x46, 0x0b, 0x03, +0x80, 0x00, 0x64, 0x00, +0x00, 0x20, 0x47, 0x64, +0x00, 0x00, 0x20, 0x67, +0x46, 0x0b, 0x03, 0x80, +0x00, 0x64, 0x00, 0x00, +0x20, 0x87, 0x64, 0x00, +0x00, 0x20, 0xa7, 0x64, +0x00, 0x00, 0x20, 0xc7, +0x64, 0x00, 0x00, 0x20, +0xe7, 0x46, 0x0b, 0x03, +0x80, 0x00, 0x64, 0x00, +0x00, 0x21, 0x07, 0x46, +0x0b, 0x03, 0x80, 0x00, +0x00, 0x20, 0x08, 0x20, +0x19, 0x00, 0x00, 0x13, +0x32, 0x41, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x14, 0x76, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x03, 0x21, 0x00, 0x00, +0x00, 0x14, 0x76, 0x00, +0x00, 0x80, 0x00, 0x6c, +0x00, 0x01, 0x12, 0x00, +0x02, 0x00, 0x00, 0x00, +0x01, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xba, 0x11, 0x2b, 0xa1, +0x13, 0x68, 0x00, 0x04, +0x00, 0x38, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x34, 0x00, 0x09, 0x20, +0x5c, 0x81, 0x01, 0x8e, +0xb9, 0x5c, 0x01, 0x03, +0x06, 0x02, 0x84, 0x05, +0x2a, 0x00, 0x20, 0xb0, +0x42, 0x28, 0x00, 0x52, +0x84, 0x05, 0x0a, 0x05, +0x60, 0x68, 0x00, 0x05, +0x07, 0x00, 0x84, 0x05, +0x0a, 0x03, 0x60, 0x68, +0x00, 0xc5, 0x8f, 0xc0, +0x84, 0x05, 0x06, 0x60, +0x00, 0x01, 0x4e, 0x8a, +0xbf, 0xd0, 0x68, 0x20, +0x00, 0x00, 0x24, 0x68, +0x00, 0x00, 0x0c, 0x20, +0x40, 0x00, 0x01, 0x89, +0x09, 0x66, 0x00, 0x00, +0x2f, 0x28, 0x5c, 0x00, +0xb1, 0x88, 0x08, 0x66, +0x00, 0x00, 0x68, 0x40, +0x66, 0x00, 0x00, 0xc6, +0xa0, 0x68, 0x34, 0x04, +0x07, 0x20, 0x68, 0x3a, +0x9a, 0xc2, 0xec, 0x5c, +0xba, 0x00, 0x40, 0x6c, +0x9c, 0x00, 0x0b, 0x13, +0x00, 0x40, 0x00, 0x00, +0x40, 0x50, 0x68, 0x00, +0x03, 0x93, 0x00, 0x6c, +0x68, 0x10, 0x9e, 0x50, +0x68, 0x00, 0x00, 0x04, +0x20, 0x68, 0x20, 0x03, +0xa0, 0x21, 0x66, 0x00, +0x00, 0x38, 0x20, 0x66, +0x00, 0x00, 0x22, 0xc0, +0x66, 0x00, 0x00, 0x23, +0xe0, 0x38, 0x18, 0x06, +0xc7, 0x02, 0x84, 0xc5, +0x06, 0x80, 0x00, 0x00, +0x8b, 0x9b, 0xa1, 0x10, +0x40, 0x00, 0x03, 0x80, +0x00, 0x66, 0x00, 0x00, +0x6b, 0x80, 0x66, 0x00, +0x00, 0x21, 0x20, 0x66, +0x00, 0x00, 0x6b, 0xa0, +0x66, 0x00, 0x01, 0xfb, +0x00, 0x66, 0x00, 0x01, +0x3c, 0x00, 0x66, 0x00, +0x00, 0xc7, 0x40, 0x66, +0x00, 0x01, 0xd3, 0x00, +0x66, 0x00, 0x01, 0x59, +0x20, 0x68, 0x20, 0x00, +0x04, 0x20, 0x66, 0x00, +0x00, 0xfb, 0x00, 0x66, +0x00, 0x00, 0xcb, 0x00, +0x68, 0x00, 0x00, 0xc9, +0x20, 0x66, 0x00, 0x00, +0x65, 0x20, 0x68, 0x00, +0x05, 0x69, 0x20, 0x6c, +0x00, 0x01, 0x2e, 0x60, +0x66, 0x00, 0x01, 0xeb, +0xc0, 0x6e, 0x40, 0x00, +0x08, 0x38, 0x68, 0x00, +0x20, 0x00, 0x02, 0x28, +0x88, 0x03, 0x20, 0x00, +0xbc, 0x07, 0x16, 0xc0, +0x00, 0x01, 0x80, 0x03, +0x81, 0xd2, 0x52, 0x04, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x00, 0x18, 0x50, +0x66, 0x00, 0x00, 0x74, +0x80, 0x68, 0x38, 0x08, +0x10, 0x20, 0x6c, 0x00, +0x06, 0x1a, 0x7a, 0x5c, +0x0f, 0xc2, 0x00, 0x20, +0x5c, 0x08, 0x10, 0x80, +0x60, 0x5c, 0x87, 0x02, +0x00, 0x20, 0x88, 0x0e, +0x0a, 0x00, 0x40, 0x88, +0x16, 0x0a, 0x00, 0x20, +0x6c, 0x00, 0x00, 0x18, +0x03, 0x52, 0x40, 0xc1, +0x8e, 0x41, 0x52, 0x04, +0x52, 0x00, 0x20, 0x88, +0x1e, 0x06, 0xc0, 0x00, +0x01, 0x85, 0x09, 0x84, +0xb9, 0x68, 0x00, 0x00, +0x0c, 0x20, 0x40, 0x00, +0x03, 0xc0, 0x4f, 0x5c, +0x0e, 0x93, 0x00, 0x18, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x00, 0x06, +0x1a, 0x01, 0x32, 0xa0, +0x8b, 0xff, 0xa1, 0xa0, +0x00, 0x48, 0x02, 0x01, +0x25, 0x88, 0x8b, 0xc0, +0xc9, 0x88, 0x26, 0x02, +0x48, 0x8a, 0x6c, 0x40, +0x00, 0x42, 0x50, 0x68, +0x00, 0x04, 0x15, 0x25, +0x68, 0x00, 0x05, 0x69, +0x20, 0x42, 0x02, 0x78, +0x22, 0x52, 0x40, 0x00, +0x00, 0x60, 0x65, 0x68, +0x00, 0x05, 0x69, 0x20, +0x98, 0x80, 0x26, 0xc0, +0x00, 0x12, 0xe0, 0x03, +0x00, 0x80, 0xbc, 0x1b, +0x15, 0xcb, 0x10, 0x08, +0x02, 0x06, 0xc7, 0x01, +0x02, 0x00, 0x15, 0xc8, +0x10, 0x84, 0x00, 0x35, +0xc0, 0x04, 0x04, 0x08, +0x28, 0x80, 0xa4, 0x88, +0x12, 0x08, 0x61, 0x0a, +0x84, 0x08, 0x88, 0x81, +0xa4, 0x68, 0x00, 0x00, +0x89, 0x20, 0x82, 0x00, +0x98, 0x02, 0xca, 0x6c, +0x00, 0x02, 0x24, 0x51, +0x6c, 0x00, 0x02, 0x3a, +0x53, 0x6c, 0x00, 0x02, +0x50, 0x52, 0x84, 0x04, +0x86, 0xc0, 0x00, 0x1c, +0xa4, 0x98, 0x60, 0x50, +0x6c, 0x00, 0x06, 0x1a, +0x7a, 0x66, 0x00, 0x01, +0xb6, 0xc0, 0x5c, 0x81, +0x00, 0x82, 0x20, 0x6c, +0x00, 0x00, 0x7a, 0x00, +0x51, 0x42, 0x20, 0x02, +0x24, 0x6c, 0x68, 0x10, +0x00, 0x48, 0x68, 0x34, +0x08, 0x00, 0x25, 0x6c, +0x00, 0x00, 0xa2, 0x00, +0x51, 0x42, 0x23, 0xa0, +0xc8, 0x86, 0xc4, 0x80, +0x00, 0x00, 0x6c, 0x00, +0x01, 0x2e, 0x20, 0x40, +0x00, 0x03, 0xa0, 0x80, +0x6c, 0x00, 0x02, 0x98, +0x20, 0x40, 0x00, 0x03, +0xa0, 0x80, 0x66, 0x00, +0x00, 0x8e, 0xe0, 0x6c, +0x00, 0x01, 0x78, 0x20, +0x40, 0x00, 0x03, 0xa0, +0x80, 0x6c, 0x00, 0x05, +0xa2, 0x00, 0x38, 0x10, +0x22, 0x58, 0x80, 0x68, +0x20, 0x00, 0xe6, 0x25, +0x68, 0x00, 0x00, 0x9e, +0x22, 0xbc, 0x09, 0x86, +0x82, 0x00, 0x0e, 0x02, +0x46, 0x80, 0x00, 0x0b, +0x42, 0x06, 0x80, 0x00, +0x0b, 0x82, 0x16, 0x60, +0x00, 0x1e, 0x28, 0x0b, +0xc0, 0x47, 0x6c, 0x00, +0x05, 0xa0, 0x20, 0x40, +0x00, 0x03, 0xa0, 0x80, +0x68, 0x00, 0x00, 0xc9, +0x20, 0x66, 0x00, 0x00, +0x66, 0x20, 0x6c, 0x00, +0x06, 0x1a, 0x00, 0x32, +0x80, 0x06, 0x80, 0x00, +0x00, 0xc2, 0x0b, 0xf8, +0x29, 0x39, 0x0e, 0x04, +0x60, 0xe0, 0x38, 0x00, +0x0b, 0xf7, 0xe7, 0x60, +0x03, 0x80, 0x00, 0x10, +0x98, 0xea, 0x03, 0x90, +0x20, 0x80, 0x07, 0xa6, +0x00, 0x40, 0x00, 0x01, +0x06, 0x82, 0x00, 0x00, +0x02, 0x00, 0x00, 0x00, +0x80, 0x07, 0xab, 0xa1, +0x40, 0xab, 0xfd, 0x08, +0x80, 0xc9, 0x5c, 0x09, +0xf8, 0x80, 0x4b, 0x88, +0x17, 0x59, 0x02, 0x5b, +0x88, 0x1d, 0x70, 0x00, +0x00, 0x6e, 0x00, 0x00, +0x92, 0x2d, 0x25, 0x9e, +0x8b, 0xc0, 0x60, 0x6c, +0x68, 0x08, 0x10, 0x03, +0x6c, 0x00, 0x00, 0xbc, +0x53, 0x40, 0x00, 0x03, +0xc0, 0x67, 0x6c, 0x68, +0x08, 0x16, 0x03, 0x6c, +0x00, 0x00, 0xbc, 0x53, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6e, 0x00, 0x00, +0xba, 0x2b, 0x25, 0x9d, +0x8b, 0xc0, 0x50, 0x6c, +0x68, 0x08, 0x12, 0x09, +0x6c, 0x00, 0x00, 0xbe, +0x49, 0xbc, 0x07, 0x72, +0x59, 0xe8, 0xbc, 0x05, +0x06, 0xc6, 0x80, 0x81, +0x60, 0x96, 0xc0, 0x00, +0x0b, 0xe4, 0x90, 0x00, +0x00, 0x5c, 0x02, 0x29, +0x02, 0x13, 0x68, 0x00, +0x00, 0x00, 0x75, 0x6c, +0x68, 0x08, 0x06, 0x75, +0x6c, 0x00, 0x06, 0x1a, +0x49, 0x00, 0x00, 0x08, +0x81, 0x97, 0x88, 0x00, +0xb4, 0x60, 0xb4, 0x08, +0x13, 0x58, 0x80, 0x89, +0x40, 0x00, 0x02, 0x80, +0x30, 0xab, 0xef, 0x08, +0x80, 0x75, 0x88, 0x0f, +0x68, 0x81, 0x6f, 0x88, +0x1e, 0xe8, 0x82, 0x6d, +0x88, 0x2e, 0xc8, 0x83, +0x6b, 0x88, 0x3e, 0xa8, +0x84, 0x69, 0x88, 0x4e, +0x88, 0x85, 0x67, 0x88, +0x5e, 0x68, 0x86, 0x65, +0x88, 0x6e, 0x48, 0x87, +0x63, 0x88, 0x7e, 0x28, +0x88, 0x61, 0x88, 0x8e, +0x08, 0x89, 0x4b, 0x88, +0x9c, 0x98, 0x8a, 0x4a, +0x88, 0xac, 0x89, 0x0b, +0x5b, 0x88, 0xc5, 0x79, +0x0d, 0x59, 0x88, 0xcd, +0x59, 0x0e, 0x5a, 0x88, +0xf5, 0x69, 0x10, 0x58, +0x88, 0xfd, 0x46, 0x60, +0x00, 0x02, 0x48, 0x8b, +0xa1, 0x01, 0x90, 0xe1, +0x29, 0x0d, 0x11, 0x90, +0xb1, 0x38, 0x88, 0xa0, +0x88, 0x82, 0x18, 0x87, +0xa2, 0x88, 0x72, 0x38, +0x86, 0xa4, 0x88, 0x62, +0x58, 0x85, 0xa6, 0x88, +0x52, 0x78, 0x84, 0xa8, +0x88, 0x42, 0x98, 0x83, +0xaa, 0x88, 0x32, 0xb8, +0x8a, 0x88, 0x88, 0xa0, +0xa8, 0x89, 0x89, 0x88, +0x90, 0xb8, 0x82, 0xac, +0x88, 0x22, 0xd8, 0x81, +0xae, 0x88, 0x12, 0xf8, +0x80, 0xb6, 0x88, 0x03, +0x59, 0x10, 0x10, 0x88, +0xf1, 0x68, 0x8c, 0x95, +0x46, 0x0b, 0x40, 0x8c, +0x17, 0x88, 0xf9, 0x4a, +0x81, 0x10, 0x40, 0x00, +0x03, 0xa1, 0x60, 0xab, +0xfc, 0x08, 0x80, 0xc9, +0x5c, 0x08, 0x38, 0x80, +0x4b, 0x88, 0x17, 0x50, +0x00, 0x00, 0x6c, 0x00, +0x06, 0x00, 0x09, 0x25, +0x9e, 0x8b, 0xc1, 0x81, +0x88, 0x1e, 0x78, 0x82, +0x6b, 0x90, 0x35, 0xb8, +0x82, 0xd7, 0x00, 0x00, +0x06, 0xc0, 0x00, 0x60, +0x22, 0x7b, 0xc0, 0x8f, +0x5c, 0x80, 0x59, 0x8e, +0x89, 0x6c, 0x70, 0x10, +0x02, 0x03, 0x55, 0x03, +0x69, 0x79, 0xc3, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x06, 0x04, +0x0b, 0x30, 0x1e, 0x8b, +0xff, 0x62, 0x90, 0x31, +0x38, 0x81, 0xa7, 0x88, +0x22, 0xb8, 0x82, 0x97, +0x5c, 0x02, 0x3b, 0x00, +0x0d, 0x6c, 0x00, 0x06, +0x20, 0x4b, 0x6c, 0x70, +0x10, 0x0e, 0x49, 0x00, +0x00, 0x08, 0x81, 0x35, +0x46, 0x0b, 0x40, 0x80, +0x0b, 0x88, 0x08, 0x9a, +0x80, 0x40, 0x40, 0x00, +0x03, 0xa1, 0x60, 0x40, +0x00, 0x03, 0xa1, 0x60, +0x40, 0x00, 0x03, 0xa1, +0x60, 0x40, 0x00, 0x03, +0xa1, 0x60, 0x40, 0x00, +0x03, 0xa1, 0x60, 0x40, +0x00, 0x03, 0xa1, 0x60, +0x40, 0x00, 0x03, 0xa1, +0x60, 0x68, 0x34, 0x04, +0x04, 0x20, 0x5c, 0x02, +0xe2, 0xff, 0xc0, 0x5c, +0x00, 0x60, 0x40, 0x48, +0x9c, 0x00, 0x0b, 0x04, +0x86, 0x84, 0x04, 0xa6, +0x83, 0x40, 0x01, 0xe2, +0x1b, 0x19, 0xf6, 0x84, +0x84, 0xaa, 0x08, 0x81, +0xa0, 0x22, 0x08, 0x48, +0x7a, 0x68, 0x15, 0x0c, +0x84, 0x0a, 0x84, 0x04, +0xab, 0x08, 0x0e, 0xa0, +0x60, 0x04, 0x60, 0xa4, +0x04, 0x8c, 0xa8, 0x40, +0x48, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x00, +0x00, 0x08, 0x20, 0x68, +0x00, 0x03, 0xff, 0x08, +0x84, 0x00, 0xa5, 0x44, +0x9b, 0x20, 0x42, 0x06, +0x83, 0x40, 0xc0, 0x02, +0x18, 0x41, 0x00, 0x54, +0x48, 0x20, 0x48, 0x4a, +0xa0, 0x82, 0x18, 0x40, +0x0a, 0x46, 0x0a, 0x40, +0x48, 0x4a, 0x84, 0xbc, +0x80, 0x00, 0x00, 0x68, +0x38, 0x14, 0x07, 0x20, +0x5c, 0xbc, 0x03, 0x00, +0x0c, 0x84, 0x07, 0xa4, +0x60, 0xa4, 0x1c, 0x00, +0x08, 0x40, 0x48, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x28, 0x0c, +0x08, 0x38, 0x10, 0x62, +0x59, 0xa0, 0xbc, 0x0d, +0x06, 0xc7, 0x02, 0x80, +0xc0, 0x83, 0x81, 0x0e, +0x25, 0x9a, 0x0b, 0xc0, +0x60, 0x5c, 0x04, 0x23, +0xa1, 0x48, 0x6c, 0x70, +0x28, 0x0c, 0x48, 0x40, +0x00, 0x03, 0x80, 0x00, +0x64, 0x00, 0x00, 0x29, +0xc7, 0x64, 0x00, 0x00, +0x25, 0xc7, 0xab, 0xff, +0x06, 0x83, 0x40, 0xc0, +0x02, 0x06, 0x82, 0x00, +0x00, 0x02, 0xc8, 0x40, +0x2d, 0xa0, 0x04, 0x08, +0x40, 0x00, 0x59, 0x04, +0x01, 0x8b, 0x0a, 0x98, +0xb4, 0x85, 0x40, 0xd2, +0x08, 0x06, 0x06, 0x80, +0x00, 0x00, 0x82, 0x19, +0x82, 0x2c, 0x84, 0x86, +0xca, 0x0c, 0x39, 0x94, +0x86, 0x06, 0x80, 0x00, +0x00, 0x42, 0x08, 0x80, +0xf6, 0x42, 0x08, 0x42, +0x0c, 0x49, 0x84, 0x82, +0x16, 0xc7, 0x02, 0x81, +0x20, 0xa3, 0x81, 0x04, +0x25, 0x93, 0x0b, 0xc0, +0x40, 0x5c, 0x04, 0x23, +0xc0, 0x4f, 0x6c, 0x70, +0x28, 0x14, 0x48, 0x6c, +0x70, 0x28, 0x10, 0x7a, +0xba, 0x09, 0x0b, 0xc0, +0xef, 0x5c, 0x00, 0x62, +0xff, 0xe0, 0x40, 0x00, +0x03, 0xa0, 0x90, 0x66, +0x00, 0x00, 0x2d, 0xe0, +0x68, 0x38, 0x14, 0x09, +0x20, 0x5c, 0x00, 0x62, +0xff, 0xe0, 0x6c, 0x70, +0x28, 0x12, 0x48, 0x9c, +0x00, 0x08, 0x40, 0x7a, +0x68, 0x38, 0x14, 0x07, +0x20, 0x88, 0x02, 0x18, +0x80, 0xb6, 0x84, 0x87, +0xa8, 0x40, 0x7a, 0x9c, +0x00, 0x04, 0x60, 0xa4, +0x04, 0x04, 0x88, 0x42, +0x48, 0x40, 0x00, 0x02, +0x80, 0x10, 0xab, 0xff, +0x06, 0x83, 0x40, 0xc0, +0x02, 0x06, 0x82, 0x00, +0x00, 0x02, 0xc8, 0x40, +0x2d, 0xa0, 0x02, 0x08, +0x40, 0x28, 0x84, 0x10, +0x05, 0x90, 0x40, 0x18, +0xb0, 0xa9, 0x8b, 0x48, +0x54, 0x0d, 0x20, 0x80, +0x60, 0x98, 0x22, 0x16, +0x80, 0x00, 0x00, 0x82, +0x29, 0xc8, 0x01, 0x85, +0x06, 0x1a, 0x14, 0x39, +0x94, 0x86, 0x06, 0x80, +0x00, 0x00, 0x42, 0x08, +0x80, 0xf6, 0x42, 0x08, +0x42, 0x0c, 0x49, 0x84, +0x82, 0x16, 0xc7, 0x02, +0x81, 0x20, 0xa3, 0x81, +0x04, 0x25, 0x93, 0x0b, +0xc0, 0x40, 0x40, 0x00, +0x03, 0xc0, 0x4f, 0x6c, +0x70, 0x28, 0x14, 0x48, +0x6c, 0x70, 0x28, 0x10, +0x7a, 0xba, 0x09, 0x0b, +0xc0, 0xef, 0x5c, 0x00, +0x62, 0xff, 0xe0, 0x40, +0x00, 0x03, 0xa0, 0x90, +0x66, 0x00, 0x00, 0x2d, +0xe0, 0x68, 0x38, 0x14, +0x09, 0x20, 0x5c, 0x00, +0x62, 0xff, 0xe0, 0x6c, +0x70, 0x28, 0x12, 0x48, +0x9c, 0x00, 0x08, 0x40, +0x7a, 0x68, 0x38, 0x14, +0x07, 0x20, 0x5c, 0x00, +0xb0, 0x80, 0x21, 0x88, +0x0b, 0x68, 0x49, 0x7a, +0x84, 0x07, 0xa9, 0xc0, +0x00, 0x46, 0x0a, 0x40, +0x40, 0x4a, 0x84, 0x24, +0x8a, 0x80, 0x10, 0x68, +0x00, 0x00, 0x09, 0x20, +0x68, 0x00, 0x03, 0xff, +0x08, 0x5c, 0x81, 0x00, +0x40, 0x0a, 0x68, 0x34, +0x0c, 0x08, 0x21, 0x54, +0x49, 0xa2, 0x04, 0x60, +0x5c, 0x00, 0x60, 0x48, +0x48, 0xa0, 0x82, 0x19, +0x40, 0x2e, 0x80, 0x84, +0xa4, 0x60, 0xa4, 0x00, +0x87, 0xa8, 0x48, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x62, 0x00, 0x00, +0x00, 0x36, 0x5c, 0x81, +0x09, 0x82, 0x24, 0x5c, +0x80, 0x81, 0x82, 0x60, +0xbb, 0x00, 0x08, 0x00, +0xcc, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x38, 0x00, +0xe2, 0x11, 0x34, 0x32, +0x02, 0x0b, 0xc0, 0x6d, +0x84, 0x86, 0x06, 0x20, +0x00, 0x00, 0x01, 0x43, +0x90, 0x20, 0x00, 0x00, +0x08, 0x00, 0x7a, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x5c, 0x00, 0x61, 0x88, +0x2c, 0x50, 0x8d, 0x20, +0x48, 0x20, 0x51, 0x85, +0x3a, 0xc0, 0x20, 0x98, +0x2e, 0xe0, 0x00, 0x00, +0x9c, 0x40, 0x08, 0x40, +0x49, 0x62, 0x00, 0x00, +0x00, 0x24, 0x84, 0x86, +0x09, 0x8e, 0x80, 0x80, +0x40, 0x92, 0x81, 0x40, +0xba, 0x14, 0x85, 0x04, +0xc0, 0x04, 0x86, 0x09, +0x80, 0x08, 0x5c, 0x81, +0x00, 0xc0, 0x2a, 0x82, +0x00, 0xb4, 0x41, 0x80, +0x02, 0x00, 0x84, 0x44, +0x40, 0x06, 0x00, 0x84, +0x42, 0x50, 0x18, 0x24, +0x04, 0x60, 0xa4, 0x18, +0x08, 0x28, 0xc0, 0x60, +0x55, 0x00, 0xa3, 0x80, +0x00, 0x5c, 0x81, 0x00, +0xc0, 0x2a, 0x82, 0x00, +0xb4, 0x41, 0x80, 0x02, +0x00, 0x84, 0x44, 0x40, +0x02, 0x00, 0x84, 0x42, +0x50, 0x18, 0x24, 0x09, +0x80, 0x82, 0x55, 0x00, +0xb8, 0x20, 0x08, 0x8c, +0x06, 0x0a, 0x20, 0x01, +0x8c, 0x12, 0xe4, 0x42, +0x00, 0x02, 0x00, 0x84, +0x44, 0x40, 0x04, 0x88, +0x94, 0x46, 0xc8, 0x06, +0x08, 0x85, 0xb0, 0x82, +0x98, 0x04, 0xa5, 0x78, +0x9a, 0x18, 0x48, 0x05, +0x74, 0xb1, 0x3a, 0x14, +0x88, 0xc1, 0x60, 0x55, +0x00, 0xa3, 0x80, 0x00, +0x32, 0x02, 0x8b, 0xc3, +0x58, 0x22, 0x86, 0xe5, +0xb8, 0xa2, 0x30, 0x0f, +0x05, 0x70, 0x80, 0x30, +0x00, 0xf5, 0x08, 0x1c, +0x30, 0x4e, 0xa2, 0xa6, +0x63, 0x4b, 0xc1, 0x23, +0x3c, 0x08, 0x20, 0x0c, +0xd2, 0x35, 0xd4, 0x68, +0x20, 0x01, 0x2c, 0x20, +0x28, 0x16, 0x25, 0x14, +0x2a, 0x84, 0x00, 0x85, +0x70, 0xb0, 0xb0, 0x0f, +0xa5, 0x16, 0xe6, 0x04, +0x08, 0x92, 0x80, 0x20, +0x68, 0x1f, 0xff, 0xff, +0xc8, 0x36, 0x80, 0x35, +0x44, 0x84, 0x98, 0x0c, +0x82, 0x32, 0x09, 0x28, +0x08, 0x02, 0x10, 0x3f, +0x20, 0x90, 0xc2, 0x81, +0x3f, 0x08, 0xb0, 0x02, +0x23, 0xc0, 0x98, 0x00, +0x80, 0x83, 0x00, 0x22, +0x3c, 0x02, 0xe0, 0x28, +0x98, 0x00, 0x80, 0x8c, +0x00, 0x22, 0x04, 0x09, +0x80, 0x0b, 0x08, 0xb0, +0x02, 0x23, 0xc0, 0x98, +0x00, 0xa0, 0x8b, 0x00, +0x22, 0x3c, 0x02, 0xe0, +0x28, 0x98, 0x00, 0xa4, +0x47, 0x00, 0x3a, 0x14, +0x82, 0x20, 0x40, 0x98, +0x00, 0x8b, 0xa1, 0x48, +0x98, 0xe8, 0x80, 0x00, +0x00, 0x5c, 0x82, 0x02, +0x00, 0x48, 0x5c, 0x00, +0x31, 0x8e, 0x88, 0x5c, +0x0f, 0xc1, 0x40, 0x64, +0x52, 0x01, 0xb2, 0x00, +0x38, 0x80, 0x26, 0x17, +0x60, 0x02, 0x00, 0x80, +0x29, 0x40, 0x64, 0xa0, +0x06, 0x18, 0x0a, 0x62, +0xb0, 0x40, 0x48, 0x48, +0x48, 0xa0, 0x8a, 0x18, +0x48, 0x4a, 0xa0, 0xd0, +0x16, 0x80, 0x00, 0x0e, +0xc2, 0xc8, 0x48, 0xec, +0x68, 0x00, 0x00, 0xe7, +0xac, 0xba, 0x14, 0x88, +0x48, 0x6c, 0x40, 0x00, +0x03, 0x80, 0x00, 0x94, +0x4a, 0x83, 0x20, 0x00, +0xbc, 0x0b, 0x58, 0x42, +0x21, 0x68, 0x20, 0x01, +0xf4, 0x22, 0x94, 0x82, +0x82, 0x29, 0x04, 0x2a, +0xbe, 0x02, 0x30, 0x80, +0x98, 0x42, 0x89, 0xd0, +0x01, 0x84, 0x82, 0x1b, +0xa0, 0x10, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x39, 0x00, 0x89, +0x48, 0x0c, 0x51, 0xb1, +0x21, 0x48, 0x0e, 0x51, +0xa1, 0xb1, 0x48, 0x08, +0x51, 0x90, 0x11, 0x48, +0x28, 0x29, 0x1a, 0x42, +0x90, 0xa4, 0x54, 0x81, +0x23, 0xa1, 0x48, 0x84, +0x04, 0x80, 0x00, 0x00, +0x5c, 0x80, 0x40, 0x40, +0x00, 0x51, 0xf0, 0x23, +0x07, 0xfa, 0x28, 0x8a, +0x15, 0x1e, 0x02, 0x14, +0x84, 0x12, 0x88, 0xa1, +0x51, 0xd0, 0x21, 0x48, +0x41, 0x28, 0x8a, 0x15, +0x44, 0x40, 0x14, 0x84, +0x1b, 0xa1, 0x48, 0x94, +0x86, 0x00, 0x00, 0x00, +0x5c, 0x80, 0x48, 0x43, +0xa4, 0x5c, 0x80, 0x93, +0x80, 0x00, 0x62, 0x00, +0x00, 0x00, 0xb4, 0x5c, +0x81, 0x02, 0xbf, 0xf0, +0x5c, 0x00, 0x02, 0x40, +0x02, 0x60, 0x00, 0x00, +0x00, 0x35, 0x8d, 0x05, +0x80, 0x00, 0x00, 0x94, +0x88, 0xc9, 0x52, 0xc4, +0x00, 0x00, 0x0a, 0x10, +0x0a, 0x8d, 0x03, 0x2b, +0xb1, 0x82, 0xba, 0x14, +0x88, 0x43, 0xe4, 0x40, +0x00, 0x02, 0x80, 0x10, +0x5c, 0x80, 0x52, 0xbf, +0xf0, 0xa0, 0x0a, 0x0a, +0x40, 0x02, 0x62, 0x00, +0x00, 0x00, 0xa4, 0x5c, +0x81, 0x08, 0x41, 0x24, +0x5c, 0x80, 0x80, 0x40, +0x21, 0xbb, 0x00, 0x06, +0x00, 0x00, 0x00, 0x03, +0x58, 0xd0, 0xd8, 0x00, +0x00, 0x09, 0x53, 0x0c, +0x94, 0x94, 0x40, 0x00, +0x00, 0xa1, 0x00, 0xab, +0xa1, 0x48, 0x84, 0x16, +0x4a, 0x80, 0x10, 0xa0, +0x08, 0x18, 0x48, 0x22, +0xa0, 0xc3, 0x99, 0x50, +0x28, 0x55, 0x5e, 0x12, +0xbf, 0xe0, 0x51, 0x90, +0x89, 0x48, 0x2a, 0x59, +0x04, 0x81, 0x50, 0xa8, +0x54, 0x00, 0x60, 0x80, +0x76, 0xbc, 0x1a, 0x89, +0x82, 0x23, 0x32, 0x0d, +0x0b, 0xc1, 0x48, 0xa1, +0x01, 0x12, 0xa7, 0x90, +0x22, 0x88, 0x63, 0x20, +0x30, 0xbc, 0x1c, 0x56, +0x20, 0x00, 0x00, 0x08, +0x60, 0x00, 0x00, 0x00, +0x00, 0x09, 0x82, 0x20, +0x88, 0x0c, 0x88, 0x81, +0x61, 0x66, 0x00, 0x00, +0x3b, 0x20, 0x88, 0x12, +0x08, 0x80, 0x80, 0x55, +0x08, 0x22, 0x00, 0x21, +0x40, 0x00, 0x03, 0xc0, +0xd7, 0x42, 0x05, 0xf9, +0x51, 0x28, 0x95, 0x86, +0x0a, 0x00, 0xa1, 0xa0, +0xc6, 0x28, 0x48, 0x21, +0x88, 0x0e, 0x26, 0x60, +0x00, 0x03, 0xc0, 0x8a, +0x18, 0x00, 0x88, 0x0a, +0x0b, 0x00, 0x20, 0x94, +0x06, 0x00, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, +0x48, 0xa8, 0x02, 0x00, +0x00, 0x00, 0x94, 0x4a, +0xc5, 0x90, 0x50, 0x2b, +0xff, 0x0b, 0xc0, 0x98, +0x88, 0x07, 0x6a, 0x00, +0x80, 0x84, 0x02, 0x18, +0x80, 0x36, 0xa8, 0x01, +0x0a, 0x00, 0x60, 0x64, +0x00, 0x00, 0x3b, 0x2f, +0xa0, 0x81, 0x1a, 0x00, +0xa1, 0xa0, 0x84, 0x08, +0x48, 0x21, 0x88, 0x0e, +0x06, 0x60, 0x00, 0x03, +0xc0, 0x08, 0x80, 0xa0, +0xb0, 0x02, 0x4a, 0x04, +0xa0, 0x94, 0x06, 0x40, +0x00, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0xa0, 0x08, 0x1a, 0x0c, +0x3a, 0x95, 0x02, 0xc5, +0x90, 0x50, 0x2b, 0xff, +0x0b, 0xc1, 0x68, 0x84, +0x82, 0x15, 0x53, 0xd2, +0x30, 0x0f, 0xe5, 0xb4, +0x81, 0x30, 0x02, 0x83, +0x70, 0x85, 0x2e, 0x17, +0x66, 0x20, 0x00, 0x00, +0x02, 0x63, 0x68, 0x00, +0x50, 0x4c, 0x91, 0x8e, +0xb5, 0x2f, 0x81, 0x22, +0xb9, 0x66, 0x32, 0x03, +0x0b, 0xc0, 0x2b, 0x98, +0x38, 0x83, 0x61, 0x04, +0xa0, 0x81, 0x16, 0x40, +0x00, 0x03, 0xd0, 0xfa, +0x80, 0x10, 0x88, 0x07, +0x68, 0x80, 0xe0, 0x66, +0x00, 0x00, 0x3e, 0x88, +0x38, 0x00, 0xcb, 0x00, +0x2c, 0x88, 0x0a, 0x08, +0x80, 0x36, 0x94, 0x46, +0x4b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0xa0, 0x08, 0x18, 0x48, +0x22, 0x68, 0x20, 0x00, +0x00, 0x2c, 0x95, 0x02, +0x85, 0x55, 0xe1, 0x15, +0x0a, 0x85, 0x19, 0x09, +0x20, 0xc3, 0x95, 0x40, +0x0a, 0x18, 0xb0, 0x05, +0x40, 0x12, 0x14, 0x82, +0x85, 0x90, 0x40, 0x2b, +0xfe, 0x04, 0x20, 0xd4, +0x08, 0x07, 0x69, 0x82, +0x23, 0x32, 0x0c, 0x0b, +0xc1, 0x48, 0xa1, 0x01, +0x12, 0xa7, 0x80, 0x22, +0x88, 0x63, 0x20, 0x30, +0xbc, 0x1c, 0x56, 0x20, +0x00, 0x00, 0x08, 0x60, +0x00, 0x00, 0x00, 0x00, +0x09, 0x82, 0x20, 0x88, +0x0c, 0x88, 0x81, 0x61, +0x66, 0x00, 0x00, 0x3b, +0x20, 0x88, 0x12, 0x08, +0x80, 0x80, 0x55, 0x08, +0x22, 0x00, 0x21, 0x40, +0x00, 0x03, 0xc0, 0xd7, +0x42, 0x05, 0xf9, 0x51, +0x28, 0x95, 0x86, 0x0a, +0x00, 0xa1, 0xa0, 0xc6, +0x28, 0x48, 0x21, 0x88, +0x0e, 0x26, 0x60, 0x00, +0x03, 0xc0, 0x8a, 0x18, +0x00, 0x88, 0x0a, 0x0b, +0x00, 0x20, 0x94, 0x06, +0x00, 0x00, 0x00, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0xa0, 0x08, 0x1a, +0x0c, 0x3a, 0xab, 0xfe, +0x09, 0x50, 0x28, 0x59, +0x04, 0x00, 0x80, 0x60, +0xa0, 0x0c, 0x08, 0x48, +0x21, 0x42, 0x10, 0x40, +0x81, 0x76, 0x88, 0x0e, +0x03, 0x21, 0x80, 0xbc, +0x18, 0x8a, 0x08, 0x11, +0x2a, 0x78, 0x02, 0x28, +0xc4, 0x32, 0x02, 0x0b, +0xc2, 0x45, 0x62, 0x00, +0x00, 0x00, 0xe4, 0x00, +0x00, 0x00, 0x00, 0x00, +0x88, 0x0a, 0x08, 0x81, +0xe1, 0x66, 0x00, 0x00, +0x3b, 0x20, 0x88, 0x1a, +0x18, 0x80, 0x20, 0xa0, +0x82, 0x18, 0x43, 0x20, +0x88, 0x1e, 0x16, 0x60, +0x00, 0x03, 0xb2, 0x08, +0x81, 0xa1, 0x00, 0x00, +0x0a, 0x08, 0x21, 0xbc, +0x11, 0x78, 0x81, 0x36, +0x88, 0x0a, 0x06, 0x40, +0x00, 0x03, 0xb2, 0xfa, +0x80, 0x20, 0x39, 0x02, +0x08, 0x80, 0x21, 0x00, +0x00, 0x0a, 0x08, 0xa0, +0x80, 0x02, 0x18, 0x80, +0x60, 0x66, 0x00, 0x00, +0x3c, 0x00, 0x88, 0x02, +0x1b, 0x00, 0x20, 0xa0, +0xc8, 0x19, 0x48, 0x60, +0x00, 0x00, 0x08, 0x81, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x20, 0x40, 0x00, +0x03, 0x80, 0x00, 0xa0, +0x04, 0x99, 0x48, 0x2c, +0x59, 0x05, 0x02, 0x08, +0x7a, 0xab, 0xff, 0x08, +0x80, 0x76, 0x42, 0x03, +0xc2, 0x00, 0x01, 0x85, +0x02, 0x08, 0x80, 0x36, +0xa8, 0x01, 0x08, 0x4a, +0x21, 0x64, 0x00, 0x00, +0x3b, 0x2f, 0xa0, 0x81, +0x1a, 0x08, 0xa1, 0xa0, +0xc6, 0x28, 0x48, 0x21, +0x88, 0x0e, 0x26, 0x60, +0x00, 0x03, 0xc0, 0x08, +0x80, 0xa0, 0xb0, 0x02, +0x49, 0x40, 0x64, 0x00, +0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, +0x10, 0x40, 0x00, 0x03, +0x80, 0x00, 0x98, 0x80, +0x86, 0x80, 0x00, 0x00, +0x40, 0xa3, 0x01, 0xa0, +0xbc, 0x0d, 0x18, 0x42, +0x21, 0xb0, 0x78, 0x49, +0x48, 0x2e, 0x30, 0x13, +0x0b, 0xc0, 0x60, 0xb0, +0x78, 0xc3, 0x01, 0x30, +0x40, 0x00, 0x03, 0xc0, +0x41, 0x64, 0x00, 0x00, +0x5e, 0x47, 0x64, 0x00, +0x00, 0x53, 0x47, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x84, 0x22, 0x1a, 0xbf, +0xe0, 0x94, 0x8a, 0xc5, +0x55, 0xf2, 0x08, 0x07, +0x63, 0x20, 0x20, 0xbc, +0x09, 0x1a, 0x08, 0x11, +0x66, 0x00, 0x00, 0x3b, +0x28, 0xa4, 0x04, 0x08, +0x81, 0x08, 0x32, 0x82, +0x0b, 0xc0, 0x21, 0x66, +0x00, 0x01, 0x28, 0x80, +0x88, 0x03, 0x6b, 0xa1, +0x48, 0xa8, 0x02, 0x00, +0x00, 0x00, 0x84, 0x22, +0x1b, 0x07, 0x84, 0x94, +0x8a, 0xe2, 0x89, 0x34, +0x32, 0x02, 0x0b, 0xc0, +0x60, 0x38, 0x08, 0x63, +0x01, 0xa0, 0x40, 0x00, +0x03, 0xc0, 0x41, 0x64, +0x00, 0x00, 0x57, 0xc7, +0x64, 0x00, 0x00, 0x54, +0x47, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x84, 0x22, +0x1a, 0x00, 0xa2, 0x94, +0x8a, 0xe5, 0x90, 0xf8, +0x2b, 0xfe, 0x0b, 0xc1, +0x88, 0x88, 0x07, 0x63, +0x23, 0xf0, 0xbc, 0x2a, +0x98, 0x80, 0xe2, 0xa4, +0x04, 0x16, 0x80, 0x00, +0x00, 0xc2, 0x09, 0x88, +0x49, 0x66, 0x00, 0x00, +0x2f, 0x28, 0x5c, 0x00, +0x71, 0x88, 0x08, 0x5c, +0x83, 0x00, 0x80, 0xa2, +0x00, 0x00, 0x08, 0x12, +0x21, 0x88, 0x0e, 0x26, +0x60, 0x00, 0x03, 0xc0, +0x8a, 0x40, 0x40, 0x88, +0x0a, 0x0b, 0x00, 0x26, +0x94, 0x06, 0x6b, 0xc1, +0x57, 0x00, 0x00, 0x09, +0x44, 0xae, 0x32, 0x0b, +0x0b, 0xc0, 0x60, 0xa4, +0x04, 0x06, 0x60, 0x00, +0x03, 0xb2, 0x8a, 0x08, +0x11, 0xbc, 0x0c, 0xf8, +0x81, 0x39, 0x5c, 0x83, +0x00, 0x81, 0x79, 0x00, +0x00, 0x08, 0x12, 0x21, +0x88, 0x0e, 0x26, 0x60, +0x00, 0x03, 0xc0, 0x8a, +0x40, 0x40, 0x88, 0x0a, +0x0b, 0x00, 0x26, 0x94, +0x06, 0x60, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, +0x48, 0xa8, 0x02, 0x00, +0x00, 0x00, 0x5c, 0x81, +0x02, 0xbf, 0x70, 0x5c, +0x07, 0xe2, 0x40, 0x41, +0x68, 0x20, 0x00, 0x21, +0x2c, 0x84, 0x22, 0x28, +0x08, 0x6c, 0x68, 0x20, +0x00, 0x22, 0x2c, 0x95, +0x0a, 0xe5, 0x52, 0x18, +0x00, 0x86, 0xc6, 0x82, +0x00, 0x02, 0x32, 0xc5, +0x18, 0x40, 0x00, 0x86, +0xc6, 0x82, 0x00, 0x21, +0x42, 0xc5, 0x80, 0x98, +0x00, 0x86, 0xc6, 0x82, +0x00, 0x21, 0x52, 0xc8, +0x08, 0x6c, 0x80, 0x87, +0xa6, 0x82, 0x00, 0x21, +0x62, 0xc8, 0x08, 0x7a, +0x80, 0x86, 0xc8, 0x08, +0x7a, 0x80, 0x87, 0xa6, +0x82, 0x00, 0x21, 0x72, +0xc8, 0x08, 0x7a, 0x80, +0x86, 0xc6, 0x82, 0x00, +0x21, 0x82, 0xc8, 0x08, +0x6c, 0x68, 0x20, 0x02, +0x19, 0x2c, 0x80, 0x86, +0xc8, 0x08, 0x6c, 0x84, +0x87, 0xa9, 0x84, 0x28, +0xa0, 0xde, 0x1a, 0x00, +0x03, 0x9c, 0x80, 0x14, +0x21, 0xa6, 0x04, 0x82, +0x09, 0x88, 0x08, 0x32, +0x02, 0x0b, 0xc2, 0xe0, +0x95, 0xca, 0xc3, 0x20, +0xa0, 0xbc, 0x1f, 0x03, +0x21, 0xa0, 0xbc, 0x2c, +0x15, 0xc0, 0xe2, 0x21, +0x90, 0x18, 0x48, 0x0a, +0x25, 0x93, 0x0b, 0xc0, +0x49, 0xa0, 0xce, 0x1b, +0xa1, 0x48, 0xa8, 0x09, +0x00, 0x00, 0x00, 0x68, +0x20, 0x02, 0x04, 0x24, +0x68, 0x00, 0x00, 0xec, +0x2c, 0x9e, 0x00, 0x48, +0x60, 0x00, 0x98, 0xb0, +0x23, 0x00, 0x80, 0xbc, +0x05, 0x98, 0x48, 0x50, +0xba, 0x14, 0x8a, 0x80, +0x90, 0x40, 0x00, 0x03, +0x80, 0x00, 0x52, 0x09, +0xa2, 0x10, 0x11, 0x85, +0xc4, 0x86, 0x40, 0x00, +0x03, 0xb2, 0xfa, 0x80, +0x90, 0xa1, 0x8a, 0x1a, +0x0c, 0x62, 0x84, 0x82, +0x18, 0x80, 0x62, 0x88, +0x0f, 0x66, 0x60, 0x00, +0x03, 0xc0, 0x08, 0x80, +0x20, 0x88, 0x0b, 0x64, +0x20, 0x27, 0xb0, 0x02, +0x49, 0x40, 0x64, 0xba, +0x14, 0x8a, 0x80, 0x90, +0x00, 0x00, 0x0b, 0xa1, +0x48, 0xa8, 0x09, 0x00, +0x00, 0x00, 0x84, 0x22, +0x1b, 0x07, 0x84, 0x94, +0x8a, 0xe2, 0x89, 0x34, +0x32, 0x02, 0x0b, 0xc0, +0x60, 0x38, 0x10, 0x63, +0x01, 0xa0, 0x40, 0x00, +0x03, 0xc0, 0x41, 0x64, +0x00, 0x00, 0x60, 0x47, +0x64, 0x00, 0x00, 0x5f, +0x47, 0x40, 0x00, 0x03, +0xa1, 0x40, 0xa0, 0x0a, +0x1a, 0x08, 0x60, 0xab, +0xff, 0x08, 0x48, 0x21, +0x88, 0x06, 0x08, 0x80, +0xf6, 0x66, 0x00, 0x00, +0x3c, 0x00, 0x88, 0x02, +0x08, 0x80, 0xb6, 0xa0, +0x4c, 0x04, 0x60, 0xa4, +0x30, 0x02, 0x49, 0x40, +0x64, 0x40, 0x00, 0x02, +0x80, 0x10, 0xab, 0xfe, +0x0a, 0x00, 0xa1, 0x6c, +0x40, 0x03, 0xba, 0x08, +0x68, 0x00, 0xf0, 0x03, +0x0a, 0x54, 0x4d, 0x22, +0x0c, 0x62, 0xa4, 0x04, +0x08, 0x48, 0x21, 0x84, +0x04, 0x88, 0x80, 0x62, +0x88, 0x0f, 0x66, 0x60, +0x00, 0x03, 0xc0, 0x08, +0x80, 0x20, 0x88, 0x0b, +0x64, 0x60, 0xa4, 0x30, +0x02, 0x49, 0x40, 0x64, +0x40, 0x00, 0x02, 0x80, +0x20, 0x32, 0x02, 0x0b, +0xc1, 0x68, 0x68, 0x34, +0x04, 0x14, 0x21, 0x6c, +0x68, 0x08, 0x28, 0x49, +0x00, 0x00, 0x08, 0x48, +0x89, 0x84, 0x04, 0x94, +0x00, 0x00, 0x38, 0x00, +0x04, 0x00, 0x00, 0x38, +0x00, 0x0b, 0xc0, 0x4f, +0x5c, 0x09, 0xab, 0x80, +0x00, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x68, +0x08, 0x06, 0x08, 0x25, +0x96, 0x0b, 0xff, 0xa0, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x6c, 0x68, 0x08, +0x28, 0x49, 0x00, 0x00, +0x08, 0x40, 0x09, 0x84, +0x8c, 0x94, 0x00, 0x00, +0x38, 0x00, 0x04, 0x00, +0x00, 0x38, 0x00, 0x0b, +0xc0, 0x4f, 0x5c, 0x09, +0xab, 0x80, 0x00, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x08, 0x06, +0x08, 0x25, 0x96, 0x0b, +0xff, 0xa0, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x32, +0x02, 0x0b, 0xc0, 0x69, +0x5c, 0x08, 0x71, 0x40, +0x2c, 0x52, 0x4d, 0x03, +0xa1, 0x48, 0x94, 0x06, +0x00, 0x00, 0x00, 0x52, +0x0d, 0x03, 0xa1, 0x48, +0x94, 0x06, 0x00, 0x00, +0x00, 0x5c, 0x05, 0x20, +0x40, 0x7a, 0x46, 0x0a, +0x40, 0x40, 0xfa, 0x84, +0x14, 0x80, 0x00, 0x00, +0x84, 0x00, 0x88, 0x40, +0x8a, 0x30, 0x93, 0x0b, +0xc0, 0x4b, 0xb0, 0x00, +0xcb, 0xa1, 0x48, 0x84, +0x0f, 0xa9, 0x8e, 0x88, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x84, 0x08, 0x03, +0x28, 0x00, 0xbc, 0x05, +0x08, 0x40, 0x00, 0x55, +0x02, 0x23, 0xa1, 0x48, +0x84, 0x04, 0x80, 0x00, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x68, 0x38, +0x1c, 0x03, 0x21, 0x55, +0x3f, 0x72, 0xff, 0xe0, +0x59, 0x03, 0x40, 0x48, +0x48, 0x5c, 0x00, 0x61, +0xc8, 0x01, 0x42, 0x02, +0x58, 0x48, 0x4a, 0x55, +0x03, 0xb0, 0x49, 0x48, +0x5c, 0x00, 0x73, 0x80, +0x00, 0x62, 0x00, 0x00, +0x00, 0x46, 0x39, 0x02, +0x00, 0x00, 0x00, 0x6c, +0x70, 0x38, 0x00, 0x09, +0x80, 0x04, 0x90, 0x00, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0xab, 0xfb, +0x06, 0x80, 0x00, 0x00, +0x82, 0x18, 0x80, 0x76, +0xa4, 0x04, 0x09, 0x88, +0x48, 0x66, 0x00, 0x00, +0x2f, 0x28, 0x5c, 0x02, +0x31, 0x88, 0x09, 0x5c, +0x81, 0x02, 0x40, 0x40, +0xa0, 0x00, 0x18, 0x00, +0x00, 0x51, 0x60, 0x28, +0x00, 0x00, 0x51, 0xd0, +0x30, 0x80, 0xe0, 0x23, +0x42, 0xa6, 0x80, 0x03, +0xff, 0xfc, 0x05, 0x44, +0x18, 0x04, 0x00, 0x93, +0x28, 0x28, 0x54, 0x80, +0x83, 0xc0, 0x9d, 0x6c, +0x40, 0x00, 0x04, 0x50, +0xa0, 0x86, 0x18, 0x48, +0xa0, 0x66, 0x00, 0x00, +0x66, 0xc8, 0x84, 0x80, +0x8b, 0xc0, 0x3f, 0x88, +0x0a, 0x00, 0x00, 0x00, +0x88, 0x0a, 0x00, 0x00, +0x00, 0x84, 0x18, 0x93, +0x28, 0x28, 0xbc, 0x06, +0xda, 0x40, 0x41, 0xa0, +0x8c, 0x18, 0x48, 0xa0, +0x66, 0x00, 0x00, 0x66, +0xc8, 0x84, 0x80, 0x88, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x50, 0x40, +0x00, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x68, 0x34, 0x08, +0x4a, 0x20, 0x5c, 0x00, +0x62, 0xbf, 0xf0, 0x84, +0x04, 0x88, 0x40, 0xc8, +0x40, 0x00, 0x00, 0x80, +0x76, 0x66, 0x00, 0x00, +0x6d, 0x20, 0x68, 0x00, +0x01, 0xad, 0x20, 0x88, +0x03, 0x6a, 0x00, 0x81, +0xa0, 0xc2, 0x28, 0x50, +0x61, 0xa0, 0xc4, 0x3a, +0x0c, 0x62, 0x84, 0x06, +0x14, 0x60, 0xa4, 0x05, +0x86, 0x18, 0x50, 0x61, +0x40, 0x00, 0x02, 0x80, +0x10, 0x68, 0x34, 0x08, +0x4c, 0x20, 0x6c, 0x68, +0x00, 0x04, 0x7a, 0x5c, +0x00, 0xa2, 0xc9, 0xa0, +0x84, 0x04, 0x8a, 0x00, +0x20, 0x80, 0x24, 0x88, +0x40, 0x7a, 0xa0, 0x10, +0x0a, 0xcb, 0x00, 0x80, +0x07, 0xa4, 0x60, 0xa4, +0x30, 0x60, 0x48, 0x40, +0x48, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x38, +0x08, 0x0f, 0x20, 0x39, +0x7a, 0x08, 0x40, 0x48, +0x46, 0x0a, 0x41, 0xc0, +0x00, 0x84, 0x04, 0x90, +0x00, 0x00, 0x68, 0x38, +0x08, 0x00, 0x21, 0xb0, +0x40, 0x68, 0x48, 0x4a, +0xa0, 0x84, 0x16, 0x20, +0x00, 0x00, 0x04, 0x48, +0x48, 0x7a, 0x39, 0x00, +0x89, 0x40, 0x0e, 0x6c, +0x70, 0x10, 0x06, 0x4a, +0x00, 0x00, 0x05, 0x90, +0x14, 0x04, 0xe4, 0x8b, +0xc0, 0x68, 0x6c, 0x00, +0x06, 0x20, 0x7a, 0x5c, +0x04, 0x6b, 0xc0, 0x5f, +0x6c, 0x70, 0x10, 0x0c, +0x49, 0x38, 0x00, 0xd6, +0xc7, 0x01, 0x00, 0xc4, +0x9b, 0xa1, 0x48, 0x6c, +0x00, 0x06, 0x00, 0x7a, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x38, 0x08, +0x00, 0x22, 0x00, 0x00, +0x08, 0x50, 0x7a, 0xa1, +0x04, 0x26, 0x20, 0x00, +0x00, 0x04, 0x48, 0x50, +0x7a, 0x39, 0x00, 0x89, +0x40, 0x08, 0x6c, 0x70, +0x10, 0x06, 0x50, 0x00, +0x00, 0x02, 0x81, 0x64, +0x59, 0x01, 0x80, 0x56, +0x48, 0xbc, 0x06, 0x86, +0xc0, 0x00, 0x62, 0x07, +0xa5, 0xc0, 0x47, 0x3c, +0x05, 0xf6, 0xc7, 0x01, +0x00, 0xc4, 0xa3, 0x80, +0x0e, 0x6c, 0x70, 0x10, +0x0c, 0x4a, 0x68, 0x00, +0x03, 0x00, 0x20, 0x5c, +0x81, 0x03, 0x00, 0x0e, +0x80, 0x04, 0xa4, 0x60, +0xa4, 0x00, 0x06, 0x18, +0x40, 0x49, 0x40, 0x00, +0x03, 0x80, 0x00, 0x5c, +0x00, 0x63, 0x00, 0x16, +0x68, 0x38, 0x08, 0x0f, +0x20, 0x6c, 0x68, 0x00, +0x1c, 0x48, 0x5c, 0xbd, +0x00, 0x40, 0x4a, 0x5c, +0x01, 0x71, 0xc0, 0x00, +0x5c, 0x03, 0x70, 0x40, +0x4a, 0xa0, 0x58, 0x08, +0x40, 0x7a, 0xa0, 0x04, +0x08, 0x40, 0x7a, 0xa0, +0x02, 0x0b, 0x05, 0x10, +0x84, 0x05, 0x0a, 0x01, +0x60, 0x84, 0x04, 0xa4, +0x60, 0xa4, 0x20, 0x50, +0x08, 0x40, 0x48, 0x40, +0x00, 0x03, 0x80, 0x00, +0x64, 0x00, 0x00, 0x72, +0xe7, 0x5b, 0x8a, 0x3b, +0x00, 0xf0, 0x57, 0x0e, +0x03, 0x00, 0x0e, 0x50, +0x81, 0x83, 0x04, 0xea, +0x55, 0x33, 0xe3, 0x3c, +0x09, 0x13, 0x82, 0x72, +0x01, 0x07, 0x68, 0x20, +0x01, 0x2c, 0x20, 0x23, +0x5d, 0x45, 0x40, 0xf0, +0x04, 0x00, 0xb5, 0x14, +0x22, 0x04, 0x08, 0x02, +0xe1, 0x3a, 0x22, 0xdd, +0x72, 0x80, 0x79, 0x68, +0x1f, 0xff, 0xff, 0xc8, +0x54, 0x48, 0xbb, 0x00, +0xfc, 0x36, 0x84, 0x22, +0x81, 0x09, 0x23, 0x23, +0xf2, 0x10, 0x74, 0x20, +0x8b, 0xf2, 0x28, 0x6e, +0x28, 0x1e, 0x70, 0x8b, +0x20, 0x22, 0x3d, 0x29, +0x80, 0x88, 0x08, 0x32, +0x02, 0x23, 0xd2, 0x2e, +0x08, 0x29, 0x80, 0x88, +0x08, 0xc2, 0x02, 0x20, +0x52, 0x98, 0x08, 0xb0, +0x8b, 0x20, 0x22, 0x3d, +0x29, 0x80, 0x8a, 0x08, +0xb2, 0x02, 0x23, 0xd2, +0x2e, 0x08, 0x09, 0x80, +0x0a, 0x08, 0xe0, 0x02, +0x20, 0x40, 0x46, 0x0a, +0x41, 0x80, 0x0a, 0x08, +0x90, 0x09, 0x80, 0x08, +0x32, 0x03, 0x0b, 0xc0, +0xa8, 0x2a, 0x02, 0x86, +0x00, 0x02, 0x00, 0x01, +0x04, 0x00, 0x00, 0x18, +0xeb, 0x50, 0x00, 0x00, +0x2f, 0x98, 0x0b, 0xa1, +0x48, 0x98, 0x30, 0x82, +0x38, 0x64, 0xba, 0x14, +0x89, 0x8e, 0x88, 0x40, +0x00, 0x03, 0x80, 0x00, +0x59, 0x01, 0x42, 0xbf, +0xc0, 0x84, 0x50, 0x84, +0x22, 0x2c, 0x08, 0x0f, +0x68, 0x80, 0x48, 0x5b, +0x8a, 0x23, 0x00, 0xf0, +0x57, 0x08, 0x23, 0x00, +0x08, 0x50, 0x88, 0x02, +0xc0, 0x20, 0x46, 0x08, +0x88, 0x00, 0x0a, 0x58, +0x01, 0x40, 0x81, 0x60, +0x44, 0x40, 0x83, 0xc3, +0x18, 0x88, 0x1c, 0xd3, +0x81, 0x04, 0x20, 0x92, +0x92, 0x09, 0x00, 0x51, +0xb8, 0x49, 0x02, 0x58, +0x5b, 0x40, 0x11, 0x03, +0x59, 0x66, 0x00, 0x02, +0x09, 0x08, 0x5b, 0x42, +0x0b, 0xa1, 0x01, 0x90, +0x21, 0x19, 0x03, 0x12, +0x29, 0x85, 0x13, 0x20, +0x08, 0xbc, 0x03, 0xb8, +0x81, 0x20, 0x36, 0x00, +0x03, 0x78, 0x00, 0x5c, +0x81, 0x01, 0x83, 0x09, +0x55, 0x3f, 0x68, 0x00, +0x08, 0x54, 0x09, 0x70, +0x81, 0x60, 0x66, 0x00, +0x00, 0x78, 0x08, 0x57, +0x09, 0x6b, 0x80, 0x00, +0x44, 0x00, 0x00, 0x81, +0x20, 0x39, 0x02, 0x06, +0x00, 0x00, 0x00, 0x03, +0x85, 0x50, 0x10, 0x18, +0x00, 0xa4, 0x44, 0x10, +0x00, 0x00, 0x99, 0x80, +0x88, 0x4c, 0xa4, 0x00, +0x00, 0x09, 0x51, 0x02, +0x00, 0x81, 0x88, 0x98, +0x00, 0x95, 0x15, 0x17, +0x3c, 0x05, 0xf5, 0x40, +0xd2, 0x08, 0x00, 0x9b, +0xa1, 0x01, 0x88, 0x18, +0x88, 0x80, 0x09, 0x44, +0x08, 0x03, 0xc0, 0x4f, +0x40, 0x00, 0x01, 0x80, +0x08, 0x46, 0x08, 0x09, +0x8e, 0x88, 0x88, 0x0b, +0x6b, 0xa1, 0x48, 0xa8, +0x04, 0x00, 0x00, 0x00, +0x84, 0x00, 0x85, 0xb4, +0x80, 0x04, 0x80, 0x95, +0xb4, 0xa0, 0x18, 0x00, +0xa5, 0xb8, 0xc0, 0x18, +0x00, 0x25, 0xb8, 0x43, +0xab, 0xfd, 0x05, 0x80, +0xe0, 0x08, 0x0e, 0x24, +0x20, 0x35, 0x88, 0x17, +0x68, 0x80, 0x63, 0x32, +0x03, 0x0b, 0xc0, 0x10, +0x2a, 0x00, 0x7b, 0xc0, +0x4f, 0x2a, 0x03, 0x83, +0x20, 0x10, 0xbc, 0x01, +0x02, 0xa0, 0x38, 0x20, +0x02, 0x25, 0x00, 0x14, +0x18, 0x08, 0x84, 0x40, +0x00, 0x18, 0x00, 0x94, +0x42, 0xc0, 0x08, 0x24, +0x98, 0x81, 0xc8, 0x66, +0x00, 0x00, 0x34, 0x88, +0x98, 0x10, 0x98, 0x81, +0x89, 0x44, 0x20, 0x00, +0x80, 0xa2, 0x51, 0x1e, +0x00, 0x82, 0x09, 0x44, +0x21, 0x00, 0x80, 0x23, +0x51, 0x1e, 0x80, 0x50, +0x40, 0x85, 0x84, 0x00, +0x00, 0x00, 0x6c, 0x40, +0x00, 0x36, 0x08, 0x85, +0x00, 0x93, 0x01, 0x28, +0xbc, 0x03, 0x16, 0xc4, +0x00, 0x03, 0x80, 0x88, +0x50, 0x48, 0x00, 0x00, +0x08, 0x58, 0x08, 0x6c, +0x40, 0x00, 0x36, 0x09, +0x30, 0x16, 0x0b, 0xc0, +0x31, 0x6c, 0x40, 0x00, +0x38, 0x08, 0x85, 0x84, +0x80, 0x00, 0x00, 0x88, +0x13, 0x6b, 0xa1, 0x48, +0xa8, 0x03, 0x00, 0x00, +0x00, 0x60, 0x00, 0x20, +0x00, 0x20, 0x36, 0x98, +0x45, 0xb4, 0xa0, 0x18, +0xeb, 0x52, 0xf9, 0x00, +0xba, 0x14, 0x89, 0x83, +0x08, 0x51, 0xc3, 0x23, +0x80, 0x00, 0x59, 0x01, +0x42, 0xbf, 0xf0, 0xbc, +0x07, 0xb8, 0x80, 0x76, +0x66, 0x00, 0x00, 0x82, +0x20, 0x5c, 0x3f, 0xeb, +0xc0, 0x4f, 0x54, 0xcb, +0x23, 0x80, 0x00, 0x66, +0x00, 0x00, 0x82, 0x20, +0x44, 0x00, 0x02, 0xc0, +0x20, 0x55, 0x01, 0x01, +0x80, 0x09, 0x44, 0x08, +0x80, 0x80, 0x36, 0x98, +0x04, 0x80, 0x81, 0x10, +0x68, 0x20, 0x01, 0x39, +0x20, 0x98, 0x04, 0xa4, +0x44, 0x88, 0x00, 0x00, +0xb4, 0x46, 0x60, 0x18, +0x04, 0x80, 0x81, 0x10, +0x98, 0x04, 0xb4, 0x46, +0x90, 0x18, 0x2c, 0x18, +0x00, 0x0b, 0x44, 0x74, +0x01, 0x80, 0x8a, 0x44, +0x49, 0x80, 0x00, 0x0b, +0x44, 0x67, 0x01, 0x80, +0xc8, 0x44, 0x08, 0x01, +0x82, 0x03, 0x55, 0x00, +0x78, 0x00, 0x08, 0x44, +0x1c, 0xc0, 0x00, 0x08, +0x44, 0x16, 0xa0, 0x00, +0x08, 0x55, 0x00, 0xf1, +0x80, 0x0b, 0x4f, 0xbd, +0x00, 0x00, 0x09, 0x44, +0x3e, 0x20, 0x40, 0x09, +0x46, 0x0a, 0x41, 0x80, +0x8a, 0x44, 0x34, 0x02, +0x80, 0x10, 0x40, 0x00, +0x01, 0x80, 0x08, 0x68, +0x20, 0x01, 0x41, 0x23, +0x5c, 0x81, 0x02, 0xbf, +0xc0, 0x81, 0x80, 0x88, +0x18, 0x00, 0x81, 0x80, +0x28, 0x58, 0x0b, 0x88, +0x06, 0x3a, 0x40, 0xc2, +0xa4, 0x0e, 0x38, 0x50, +0x4a, 0x85, 0x84, 0x98, +0x80, 0xcb, 0x88, 0x15, +0x28, 0x81, 0xd0, 0x88, +0x24, 0x88, 0x82, 0xf6, +0xa1, 0x00, 0x06, 0x60, +0x00, 0x07, 0xe0, 0x8a, +0x18, 0x01, 0x88, 0x02, +0x28, 0x83, 0x0a, 0x85, +0x08, 0x93, 0x01, 0x70, +0xbc, 0x03, 0x12, 0xa0, +0x76, 0x88, 0x34, 0xa0, +0x00, 0x00, 0x88, 0x38, +0xa3, 0x01, 0x70, 0xbc, +0x02, 0x12, 0xa0, 0x76, +0x88, 0x3c, 0xa0, 0x00, +0x00, 0x88, 0x30, 0x93, +0x20, 0x28, 0xbc, 0x55, +0x88, 0x83, 0x8a, 0x32, +0x02, 0x8b, 0xc2, 0xfc, +0x36, 0x18, 0x43, 0x20, +0x30, 0xbc, 0x15, 0xc3, +0x61, 0x45, 0x30, 0x12, +0x8b, 0xc0, 0x84, 0x66, +0x00, 0x00, 0x82, 0xc0, +0x51, 0x45, 0x30, 0x82, +0x09, 0x28, 0x1a, 0x84, +0x22, 0x6f, 0x98, 0x00, +0xa3, 0x61, 0x84, 0x66, +0x00, 0x00, 0x82, 0xc8, +0x55, 0x01, 0x71, 0x82, +0x09, 0x51, 0x45, 0x30, +0x81, 0x89, 0x2e, 0x1a, +0x84, 0x22, 0x1f, 0x98, +0x00, 0xa3, 0x61, 0x84, +0x30, 0x1a, 0x8b, 0xc0, +0xca, 0x55, 0x01, 0x71, +0x82, 0x88, 0x66, 0x00, +0x00, 0x82, 0xc8, 0x40, +0x00, 0x01, 0x82, 0x09, +0x51, 0x45, 0x30, 0x81, +0x89, 0x57, 0x0d, 0x43, +0xc3, 0x6f, 0x40, 0x00, +0x01, 0x80, 0x08, 0x66, +0x00, 0x00, 0x82, 0xc8, +0x55, 0x01, 0x31, 0x82, +0x89, 0x51, 0x45, 0x30, +0x82, 0x09, 0x54, 0x0d, +0x43, 0xc2, 0xcf, 0x98, +0x00, 0x83, 0x20, 0x30, +0xbc, 0x11, 0x43, 0x01, +0x28, 0x40, 0x00, 0x03, +0xc0, 0x84, 0x66, 0x00, +0x00, 0x82, 0xc0, 0x51, +0x45, 0x30, 0x82, 0x09, +0x2e, 0x1a, 0x84, 0x20, +0xff, 0x98, 0x00, 0xa3, +0x61, 0x84, 0x66, 0x00, +0x00, 0x82, 0xc8, 0x55, +0x01, 0x71, 0x82, 0x89, +0xbc, 0x19, 0xf2, 0x28, +0xa4, 0x30, 0x1a, 0x8b, +0xc0, 0x84, 0x66, 0x00, +0x00, 0x82, 0xc0, 0x51, +0x45, 0x30, 0x82, 0x09, +0x57, 0x0d, 0x43, 0xc1, +0x0f, 0x40, 0x00, 0x01, +0x80, 0x08, 0x66, 0x00, +0x00, 0x82, 0xc8, 0x55, +0x01, 0x71, 0x82, 0x89, +0xbc, 0x09, 0xf2, 0x28, +0xa4, 0x32, 0x03, 0x0b, +0xc0, 0x50, 0x32, 0x03, +0x0b, 0xc0, 0x4c, 0x88, +0x10, 0x88, 0x80, 0x88, +0xbc, 0x01, 0x79, 0x8e, +0x88, 0x88, 0x2b, 0x6b, +0xa1, 0x48, 0xa8, 0x04, +0x00, 0x00, 0x00, 0x6c, +0x00, 0x06, 0xf0, 0x00, +0x32, 0x00, 0x0b, 0xc4, +0xc0, 0x38, 0x10, 0x22, +0x58, 0x80, 0xbc, 0x10, +0x16, 0x80, 0x00, 0x37, +0x42, 0x05, 0xc8, 0x50, +0xac, 0x12, 0x05, 0xc8, +0x98, 0x80, 0x0a, 0x10, +0x00, 0x00, 0x84, 0x80, +0x22, 0x2c, 0x14, 0x94, +0x25, 0x40, 0x00, 0x00, +0x80, 0x0a, 0x10, 0x00, +0x00, 0x84, 0x80, 0x22, +0x2c, 0x14, 0x94, 0x07, +0x43, 0x81, 0x0a, 0x25, +0x88, 0x0b, 0xc1, 0x01, +0x68, 0x00, 0x03, 0x75, +0x20, 0x5c, 0x85, 0x0a, +0xc1, 0x20, 0x5c, 0x89, +0x88, 0x00, 0xa1, 0x00, +0x00, 0x08, 0x48, 0x02, +0x22, 0xc1, 0x49, 0x42, +0x54, 0x00, 0x00, 0x08, +0x00, 0xa1, 0x00, 0x00, +0x08, 0x48, 0x02, 0x22, +0xc1, 0x49, 0x40, 0x74, +0x38, 0x11, 0x22, 0x58, +0x80, 0xbc, 0x10, 0x16, +0x80, 0x00, 0x37, 0x62, +0x05, 0xc8, 0x50, 0xac, +0x12, 0x05, 0xc8, 0x98, +0x80, 0x0a, 0x10, 0x00, +0x00, 0x84, 0x80, 0x22, +0x2c, 0x14, 0x94, 0x25, +0x40, 0x00, 0x00, 0x80, +0x0a, 0x10, 0x00, 0x00, +0x84, 0x80, 0x22, 0x2c, +0x14, 0x94, 0x07, 0x43, +0x81, 0x1a, 0x25, 0x88, +0x0b, 0xc1, 0x09, 0x39, +0x0a, 0x16, 0x80, 0x00, +0x37, 0x72, 0x05, 0xc8, +0x91, 0x2c, 0x13, 0x08, +0x00, 0xa1, 0x00, 0x00, +0x08, 0x48, 0x00, 0x22, +0xc0, 0x49, 0x43, 0x54, +0x00, 0x00, 0x08, 0x00, +0x21, 0x00, 0x00, 0x08, +0x48, 0x00, 0x22, 0xc0, +0x49, 0x40, 0x74, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x68, 0x00, 0x02, 0x51, +0xa0, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x29, 0x86, +0x00, 0x00, 0x00, 0xab, +0xfd, 0x08, 0x80, 0x76, +0x68, 0x00, 0x01, 0x12, +0x20, 0x66, 0x00, 0x00, +0xb3, 0x80, 0x68, 0x00, +0x01, 0x1d, 0x20, 0x66, +0x00, 0x00, 0xb3, 0x80, +0x68, 0x00, 0x01, 0x28, +0x20, 0x66, 0x00, 0x00, +0xb3, 0x80, 0x68, 0x00, +0x01, 0x1d, 0x20, 0x5c, +0x81, 0x0a, 0xc0, 0xc0, +0xa0, 0x0e, 0x06, 0x80, +0x00, 0x11, 0x22, 0x46, +0xc4, 0x00, 0x39, 0x40, +0x98, 0x00, 0x88, 0x44, +0x09, 0x02, 0x20, 0xe4, +0x68, 0x00, 0x01, 0x28, +0x21, 0x6c, 0x40, 0x03, +0x8c, 0x09, 0x82, 0x08, +0x84, 0x40, 0x88, 0x20, +0x8e, 0x16, 0xc4, 0x00, +0x39, 0xc0, 0x98, 0x08, +0x88, 0x44, 0x08, 0x01, +0x80, 0x8a, 0x6c, 0x40, +0x00, 0x3e, 0x08, 0x46, +0x08, 0x89, 0x80, 0x09, +0x4d, 0x25, 0x00, 0x02, +0x4a, 0x51, 0x62, 0x09, +0x80, 0x4a, 0x44, 0x40, +0x00, 0x0a, 0x49, 0x51, +0x62, 0x00, 0x22, 0x4a, +0x51, 0x62, 0x91, 0x83, +0x09, 0x88, 0x2e, 0x48, +0x80, 0xcd, 0x84, 0x84, +0xe8, 0x81, 0xc9, 0x88, +0x16, 0x18, 0x82, 0x60, +0x68, 0x20, 0x01, 0x90, +0x24, 0x66, 0x00, 0x00, +0xb3, 0xe8, 0x46, 0x08, +0x08, 0x80, 0x8a, 0x88, +0x2a, 0x08, 0x80, 0x89, +0x84, 0x04, 0x86, 0x82, +0x00, 0x19, 0x22, 0x46, +0x60, 0x00, 0x0b, 0x3e, +0x88, 0x81, 0x8a, 0x5c, +0x82, 0x00, 0x82, 0xa0, +0x88, 0x22, 0x48, 0x00, +0x09, 0x86, 0x04, 0x88, +0x80, 0xe0, 0x68, 0x20, +0x01, 0x80, 0x24, 0x68, +0x00, 0x00, 0xf0, 0x20, +0x66, 0x00, 0x00, 0x31, +0xc0, 0x5c, 0x82, 0x00, +0x82, 0x20, 0x88, 0x2a, +0x48, 0x00, 0x09, 0x86, +0x14, 0x88, 0x81, 0xe0, +0x68, 0x20, 0x01, 0x80, +0x24, 0x68, 0x00, 0x00, +0xfc, 0x20, 0x66, 0x00, +0x00, 0x31, 0xc0, 0x5c, +0x82, 0x00, 0x81, 0x20, +0x88, 0x22, 0x48, 0x00, +0x09, 0x86, 0x14, 0x88, +0x82, 0x60, 0x68, 0x20, +0x01, 0x80, 0x24, 0x68, +0x00, 0x01, 0x08, 0x20, +0x66, 0x00, 0x00, 0x31, +0xc0, 0x5c, 0x81, 0x00, +0x80, 0xa1, 0x68, 0x20, +0x01, 0x80, 0x20, 0x88, +0x12, 0x2a, 0x00, 0x64, +0x80, 0x80, 0x98, 0x51, +0x48, 0x88, 0x0e, 0x48, +0x81, 0x61, 0x68, 0x00, +0x00, 0xf0, 0x23, 0x66, +0x00, 0x00, 0x31, 0xc8, +0x40, 0x00, 0x02, 0x18, +0x40, 0x5c, 0x85, 0x08, +0x81, 0x21, 0x5c, 0x81, +0x00, 0x81, 0xa2, 0x80, +0xac, 0x88, 0x81, 0x61, +0x68, 0x00, 0x00, 0xfc, +0x20, 0x81, 0x00, 0x98, +0x80, 0xa4, 0x88, 0x1e, +0x26, 0x60, 0x00, 0x03, +0x1c, 0x8a, 0x00, 0x40, +0x5c, 0x85, 0x08, 0x82, +0x21, 0x5c, 0x81, 0x00, +0x81, 0xa2, 0x80, 0x80, +0x98, 0x12, 0xc8, 0x88, +0x1e, 0x26, 0x80, 0x00, +0x10, 0x82, 0x08, 0x80, +0xa4, 0x88, 0x0e, 0x16, +0x60, 0x00, 0x03, 0x1c, +0x8a, 0x00, 0x40, 0x5c, +0x85, 0x00, 0x80, 0xa4, +0x88, 0x12, 0x08, 0x22, +0x48, 0x88, 0x0e, 0x46, +0x60, 0x00, 0x0b, 0x44, +0x08, 0x81, 0xa0, 0x66, +0x00, 0x00, 0xb4, 0x40, +0x88, 0x0a, 0x06, 0x60, +0x00, 0x0b, 0x44, 0x08, +0x80, 0x36, 0x68, 0x00, +0x02, 0x7c, 0xa0, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x29, 0x86, 0x0a, 0x80, +0x30, 0x68, 0x00, 0x01, +0x23, 0x24, 0xab, 0xfc, +0x06, 0xc0, 0x00, 0x0f, +0x80, 0xb6, 0xc0, 0x00, +0x10, 0xa0, 0x06, 0xc0, +0x00, 0x1c, 0x40, 0x16, +0xc0, 0x00, 0x25, 0xc0, +0xa8, 0x60, 0x09, 0x88, +0x05, 0x18, 0x80, 0xd0, +0x88, 0x14, 0xb8, 0x81, +0xf6, 0x68, 0x00, 0x01, +0x18, 0x20, 0x66, 0x00, +0x00, 0xba, 0x68, 0x40, +0x00, 0x00, 0x40, 0x08, +0x68, 0x00, 0x01, 0x18, +0x20, 0x68, 0x20, 0x01, +0xcf, 0x24, 0x5c, 0x83, +0x02, 0xc0, 0x21, 0x68, +0x00, 0x01, 0x23, 0x21, +0xd8, 0x8c, 0x15, 0x70, +0xf4, 0x80, 0xa0, 0x08, +0x60, 0x09, 0x57, 0x0a, +0x00, 0x83, 0x60, 0x88, +0x24, 0x08, 0x82, 0xe1, +0x68, 0x20, 0x01, 0x7d, +0x24, 0x68, 0x00, 0x00, +0xee, 0x20, 0x66, 0x00, +0x00, 0x31, 0xc8, 0x40, +0x00, 0x01, 0x80, 0x49, +0x68, 0x20, 0x01, 0x7d, +0x24, 0x68, 0x00, 0x00, +0xfa, 0x20, 0x66, 0x00, +0x00, 0x31, 0xc8, 0x40, +0x00, 0x00, 0x82, 0x09, +0x68, 0x00, 0x00, 0xee, +0x20, 0x68, 0x20, 0x01, +0x94, 0x24, 0x84, 0x08, +0x96, 0x80, 0x00, 0x14, +0xe2, 0x06, 0x60, 0x00, +0x03, 0x1c, 0x08, 0x83, +0x20, 0x68, 0x00, 0x00, +0xfa, 0x21, 0x84, 0x04, +0x86, 0x82, 0x00, 0x19, +0x42, 0x46, 0x80, 0x00, +0x15, 0x02, 0x06, 0x60, +0x00, 0x03, 0x1c, 0x88, +0x48, 0x89, 0x55, 0x01, +0x28, 0x83, 0x20, 0x5c, +0x83, 0x00, 0x82, 0xa4, +0x80, 0x20, 0x88, 0x60, +0x49, 0x40, 0x00, 0x00, +0x82, 0x60, 0x68, 0x00, +0x00, 0xee, 0x21, 0x68, +0x20, 0x01, 0x7d, 0x24, +0x68, 0x00, 0x01, 0x39, +0x22, 0x66, 0x00, 0x00, +0xb4, 0xc0, 0x5c, 0x83, +0x00, 0x82, 0xa0, 0x68, +0x00, 0x00, 0xfa, 0x21, +0x80, 0x20, 0x88, 0x82, +0xe0, 0x68, 0x20, 0x01, +0x7d, 0x24, 0x68, 0x00, +0x01, 0x3b, 0x22, 0x66, +0x00, 0x00, 0xb4, 0xc0, +0x5c, 0x83, 0x00, 0x82, +0x20, 0x68, 0x20, 0x01, +0xde, 0x24, 0xa0, 0x12, +0x08, 0x02, 0x09, 0x40, +0x00, 0x00, 0x82, 0x60, +0x68, 0x00, 0x01, 0x52, +0x20, 0x66, 0x00, 0x00, +0x31, 0xc0, 0x5c, 0x83, +0x00, 0x82, 0xa0, 0x68, +0x20, 0x01, 0xde, 0x24, +0xa0, 0x12, 0x08, 0x02, +0x09, 0x88, 0x2e, 0x06, +0x80, 0x00, 0x15, 0x42, +0x06, 0x60, 0x00, 0x03, +0x1c, 0x08, 0x81, 0x09, +0x36, 0x94, 0x46, 0xc4, +0x00, 0x03, 0xa0, 0xb5, +0x80, 0xf0, 0x18, 0xe8, +0x8b, 0xc0, 0x3a, 0x55, +0x01, 0x00, 0x80, 0x89, +0xb0, 0x00, 0xc3, 0x69, +0x41, 0x30, 0x1c, 0x8b, +0xc0, 0x3a, 0x55, 0x00, +0x08, 0x80, 0x09, 0xb0, +0x00, 0x93, 0x69, 0x45, +0x30, 0x1e, 0x8b, 0xc0, +0x12, 0xb0, 0x00, 0x83, +0x20, 0x20, 0xbc, 0x05, +0x98, 0x82, 0x20, 0x32, +0x00, 0x0b, 0xc0, 0x21, +0x32, 0x00, 0x8b, 0xc0, +0x60, 0x6c, 0x40, 0x00, +0x3c, 0x09, 0x6c, 0x00, +0x02, 0x84, 0x49, 0x6c, +0x00, 0x02, 0x86, 0x49, +0x39, 0x0c, 0x08, 0x02, +0x09, 0x40, 0x00, 0x00, +0x80, 0x60, 0x68, 0x20, +0x00, 0xaa, 0x24, 0x68, +0x00, 0x01, 0x3e, 0x20, +0x66, 0x00, 0x00, 0x31, +0xc0, 0x5c, 0x86, 0x00, +0x82, 0xa0, 0x88, 0x0c, +0x86, 0x82, 0x00, 0x0c, +0x22, 0x48, 0x02, 0x09, +0x40, 0x00, 0x00, 0x81, +0x60, 0x68, 0x00, 0x01, +0x40, 0x20, 0x66, 0x00, +0x00, 0x31, 0xc0, 0x66, +0x00, 0x00, 0xbd, 0xc8, +0x55, 0x01, 0x28, 0x80, +0x88, 0x6c, 0x00, 0x02, +0x84, 0x09, 0x32, 0x02, +0x8b, 0xc0, 0x84, 0x68, +0x00, 0x01, 0x1b, 0x20, +0x39, 0x06, 0x28, 0x40, +0x09, 0x42, 0x08, 0xf8, +0x40, 0xc9, 0x5c, 0x81, +0x02, 0xc0, 0x41, 0x68, +0x00, 0x00, 0xf5, 0x20, +0x5c, 0x82, 0x0a, 0xc0, +0x20, 0x5c, 0x83, 0x10, +0x00, 0xfa, 0x55, 0x3f, +0x68, 0x02, 0x7a, 0x80, +0x17, 0xa8, 0x02, 0x7a, +0x6c, 0x00, 0x02, 0x84, +0x49, 0x6c, 0x00, 0x02, +0x38, 0x7a, 0x84, 0x07, +0xa0, 0x00, 0x00, 0x6c, +0x00, 0x02, 0x86, 0x09, +0x32, 0x02, 0x8b, 0xc0, +0x64, 0x68, 0x00, 0x01, +0x26, 0x20, 0x00, 0x00, +0x08, 0x40, 0x09, 0x42, +0x06, 0x38, 0x40, 0xc9, +0x68, 0x00, 0x01, 0x01, +0x20, 0x2a, 0x7e, 0xd8, +0x00, 0xfa, 0x80, 0x27, +0xa8, 0x01, 0x7a, 0x80, +0x27, 0xa6, 0xc0, 0x00, +0x28, 0x64, 0x96, 0xc0, +0x00, 0x24, 0xe7, 0xa8, +0x40, 0x7a, 0x00, 0x00, +0x06, 0xc0, 0x00, 0x28, +0xc0, 0x93, 0x20, 0x28, +0xbc, 0x04, 0x06, 0xc0, +0x00, 0x23, 0x87, 0xa6, +0xc0, 0x00, 0x24, 0xe7, +0xa3, 0x81, 0x2c, 0x6e, +0x00, 0x01, 0x2c, 0x2d, +0x25, 0x92, 0x8b, 0xc2, +0xc9, 0x88, 0x02, 0x03, +0x81, 0x3c, 0x25, 0x92, +0x8b, 0xc2, 0x81, 0x6c, +0x00, 0x02, 0xa6, 0x09, +0x36, 0x94, 0x06, 0xc4, +0x00, 0x3b, 0x20, 0x99, +0x80, 0x08, 0x30, 0x96, +0x0b, 0xc1, 0x24, 0x6c, +0x00, 0x02, 0xaa, 0x08, +0x36, 0x90, 0x09, 0x80, +0x08, 0x30, 0x96, 0x0b, +0xc0, 0xc4, 0x6c, 0x40, +0x03, 0xb6, 0x09, 0x32, +0x02, 0x8b, 0xc1, 0x60, +0x2a, 0x7e, 0xd6, 0xc0, +0x00, 0x24, 0xe7, 0xa6, +0xc0, 0x00, 0x23, 0x87, +0xa6, 0xc4, 0x00, 0x3b, +0x64, 0x9b, 0xc0, 0xe7, +0x68, 0x20, 0x01, 0xda, +0x24, 0x6c, 0x40, 0x02, +0xc4, 0x09, 0x86, 0x00, +0x86, 0xc0, 0x00, 0x24, +0xe7, 0xa6, 0xc0, 0x00, +0x23, 0x87, 0xa6, 0xc4, +0x00, 0x15, 0x04, 0x96, +0xc4, 0x00, 0x18, 0x04, +0x98, 0x60, 0xc8, 0x68, +0x00, 0x00, 0xe9, 0x21, +0x66, 0x00, 0x00, 0xb9, +0x80, 0x88, 0x12, 0x06, +0x80, 0x00, 0x0e, 0xb2, +0x16, 0x60, 0x00, 0x0b, +0x98, 0x08, 0x81, 0xb6, +0x68, 0x00, 0x02, 0xc9, +0xa0, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x29, 0x86, +0x0a, 0x80, 0x40, 0x68, +0x00, 0x02, 0xcb, 0x20, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x29, 0x86, 0x00, +0x00, 0x00, 0x68, 0x00, +0x02, 0xcc, 0xa0, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x29, 0x86, 0x00, 0x00, +0x00, 0x68, 0x00, 0x02, +0x50, 0x20, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x29, +0x86, 0x00, 0x00, 0x00, +0x84, 0x00, 0x88, 0x40, +0x8a, 0x57, 0x0d, 0x03, +0xa1, 0x48, 0x84, 0x3c, +0x00, 0x00, 0x00, 0x86, +0x00, 0x84, 0x42, 0x00, +0x06, 0x08, 0x9b, 0xa1, +0x48, 0x08, 0x98, 0x09, +0x80, 0x08, 0xa0, 0x04, +0x0a, 0x00, 0x61, 0x84, +0x00, 0x88, 0x48, 0x0a, +0x57, 0x0d, 0x03, 0xa1, +0x48, 0x84, 0x8c, 0x00, +0x00, 0x00, 0x5c, 0x81, +0x02, 0x22, 0x23, 0x81, +0x80, 0x94, 0x40, 0x80, +0x05, 0x80, 0x95, 0x00, +0xa0, 0x20, 0x8c, 0x19, +0x80, 0x09, 0x80, 0x84, +0x9a, 0x1c, 0x64, 0x82, +0x00, 0x84, 0x42, 0x00, +0x06, 0x00, 0x98, 0x48, +0x08, 0x44, 0x0c, 0x02, +0xbf, 0xd0, 0x98, 0x00, +0x9a, 0x24, 0xe4, 0x80, +0x84, 0x98, 0x80, 0x61, +0x88, 0x0e, 0x48, 0x81, +0x62, 0x88, 0x1e, 0x08, +0x82, 0x76, 0x66, 0x00, +0x00, 0x31, 0xc8, 0xa0, +0x80, 0x08, 0x80, 0x20, +0x88, 0x0a, 0x2a, 0x00, +0x40, 0x88, 0x06, 0x06, +0x60, 0x00, 0x03, 0x1c, +0x85, 0x50, 0x12, 0xa1, +0x06, 0x48, 0x80, 0x20, +0x88, 0x12, 0x2a, 0x04, +0x60, 0x84, 0x00, 0x95, +0x70, 0x94, 0x05, 0x08, +0x95, 0x70, 0xa0, 0x08, +0x1a, 0x09, 0x80, 0x08, +0x59, 0x01, 0x00, 0x44, +0xc8, 0xbc, 0x0e, 0x43, +0x20, 0x20, 0xbc, 0x17, +0x38, 0x50, 0x08, 0x2e, +0x12, 0xd5, 0xb4, 0xa0, +0x05, 0x0c, 0x99, 0x80, +0x09, 0x6c, 0x40, 0x02, +0x02, 0x08, 0x30, 0x12, +0x8b, 0xc0, 0xe5, 0x36, +0x10, 0x58, 0x50, 0xc9, +0xbc, 0x0b, 0x78, 0x50, +0x08, 0x28, 0x12, 0xd5, +0xb4, 0xa0, 0x05, 0x0c, +0x99, 0x80, 0x09, 0x6c, +0x40, 0x02, 0x02, 0x08, +0x30, 0x12, 0x8b, 0xc0, +0x25, 0x85, 0x0c, 0x80, +0x00, 0x00, 0x88, 0x23, +0x6b, 0xa1, 0x48, 0xa8, +0x03, 0x00, 0x00, 0x00, +0x84, 0x50, 0x86, 0xc4, +0x00, 0x34, 0x20, 0xa4, +0x41, 0x00, 0x3a, 0x11, +0x19, 0x80, 0x08, 0x68, +0x03, 0x94, 0xbb, 0x8a, +0x08, 0x20, 0x05, 0x15, +0xc0, 0x3a, 0x14, 0x88, +0x48, 0xcc, 0x40, 0x00, +0x03, 0xa1, 0x01, 0x55, +0x01, 0x12, 0xbf, 0xf0, +0x5b, 0x0c, 0x30, 0x80, +0x4a, 0x44, 0x58, 0x81, +0x84, 0x48, 0x44, 0x21, +0x81, 0x80, 0x41, 0x5b, +0x04, 0x32, 0xc0, 0x20, +0x44, 0x40, 0x81, 0x84, +0x48, 0x5b, 0x0a, 0x29, +0x84, 0x8a, 0x44, 0x58, +0x01, 0x84, 0x0b, 0x44, +0x39, 0x00, 0x80, 0x09, +0x44, 0x39, 0x81, 0x80, +0xca, 0x5c, 0x01, 0xeb, +0xa1, 0x11, 0x2a, 0x02, +0x74, 0x46, 0x88, 0x1a, +0x14, 0x14, 0x46, 0x88, +0x18, 0x34, 0x34, 0xc0, +0xc0, 0x9a, 0x00, 0x09, +0x83, 0x8b, 0x44, 0x08, +0x01, 0x83, 0x08, 0x54, +0x0e, 0xd1, 0x83, 0x41, +0x54, 0x08, 0x41, 0x83, +0x0b, 0x44, 0x48, 0x83, +0xa1, 0x01, 0x6c, 0x40, +0x00, 0x40, 0x08, 0x9a, +0x00, 0x24, 0xc2, 0x40, +0x18, 0x34, 0x96, 0x82, +0x00, 0x1c, 0xf2, 0x02, +0x81, 0x79, 0x80, 0x04, +0x29, 0x80, 0x4b, 0x44, +0x60, 0x00, 0x00, 0x40, +0xba, 0x14, 0x88, 0x40, +0x40, 0x40, 0x00, 0x02, +0x80, 0x10, 0x6e, 0x00, +0x01, 0x2c, 0x2e, 0x38, +0x13, 0x22, 0x58, 0xb0, +0xbc, 0x05, 0x82, 0xa0, +0x2a, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x28, 0xc7, +0xa0, 0x00, 0x00, 0x68, +0x00, 0x01, 0x44, 0x21, +0x68, 0x20, 0x01, 0xd2, +0x24, 0x5c, 0x81, 0x08, +0x48, 0x0b, 0x5c, 0x82, +0x00, 0x20, 0x8a, 0x68, +0x00, 0x01, 0x48, 0x20, +0x30, 0x1b, 0x84, 0x20, +0xec, 0x00, 0x00, 0x08, +0x02, 0x89, 0x68, 0x00, +0x01, 0x44, 0x20, 0x55, +0x03, 0xf2, 0xc0, 0xa0, +0x58, 0x01, 0x00, 0x00, +0x4a, 0xbc, 0x03, 0x56, +0xc0, 0x00, 0x29, 0x04, +0x80, 0x00, 0x00, 0x84, +0x00, 0xa3, 0x01, 0xa0, +0xbc, 0x02, 0x36, 0xc0, +0x00, 0x29, 0x24, 0x83, +0x01, 0x50, 0xbc, 0x03, +0x56, 0xc0, 0x00, 0x29, +0x45, 0x20, 0x00, 0x00, +0x84, 0x10, 0x83, 0x01, +0x10, 0xbc, 0x04, 0x3b, +0xa1, 0x48, 0x6c, 0x00, +0x02, 0x96, 0x52, 0x00, +0x00, 0x0b, 0xa1, 0x40, +0x80, 0x00, 0x25, 0x70, +0x40, 0x86, 0x00, 0x35, +0x84, 0x64, 0x00, 0x28, +0x84, 0x20, 0x1d, 0x98, +0xe8, 0xa5, 0x70, 0x94, +0x98, 0x28, 0xbb, 0x00, +0x0e, 0x30, 0x8c, 0x8b, +0xc0, 0x23, 0x40, 0x00, +0x03, 0x00, 0x0f, 0x5b, +0x40, 0x00, 0x60, 0x83, +0x36, 0x88, 0x22, 0xf0, +0x82, 0x30, 0x8d, 0x03, +0x69, 0x45, 0x5b, 0x48, +0x23, 0xc3, 0x6b, 0x2f, +0x12, 0xc3, 0x08, 0xe0, +0xbc, 0x33, 0x33, 0x20, +0x30, 0xbc, 0x04, 0x86, +0xc4, 0x00, 0x3a, 0xa0, +0x83, 0x20, 0x38, 0xbc, +0x0f, 0x13, 0x20, 0x30, +0xbc, 0x17, 0x13, 0x20, +0x38, 0xbc, 0x15, 0x16, +0xc0, 0x00, 0x28, 0xe0, +0x93, 0x20, 0x28, 0xbc, +0x11, 0x56, 0xc4, 0x00, +0x3a, 0xe0, 0xa2, 0xe1, +0xad, 0x6c, 0x00, 0x02, +0x8e, 0x49, 0x40, 0x00, +0x03, 0xc0, 0xa7, 0x6c, +0x00, 0x02, 0x8e, 0x09, +0x30, 0x12, 0x8b, 0xc0, +0x63, 0x6c, 0x40, 0x03, +0xac, 0x0a, 0x28, 0x1a, +0xd6, 0xc0, 0x00, 0x28, +0xe4, 0x90, 0x00, 0x00, +0x6c, 0x00, 0x02, 0x8e, +0x09, 0x32, 0x06, 0x8b, +0xc0, 0x63, 0x68, 0x00, +0x01, 0x46, 0x21, 0x6c, +0x00, 0x02, 0x8c, 0x7a, +0x84, 0x8f, 0xa0, 0x00, +0x00, 0x6c, 0x00, 0x02, +0x8e, 0x09, 0x30, 0x12, +0x8b, 0xc0, 0x6a, 0x38, +0x00, 0xd6, 0x80, 0x00, +0x14, 0x62, 0x16, 0xc0, +0x00, 0x28, 0xc4, 0x98, +0x48, 0xc8, 0x68, 0x20, +0x00, 0xec, 0x21, 0x39, +0x0a, 0x18, 0x48, 0x08, +0x80, 0x24, 0x88, 0x40, +0x48, 0xa0, 0x06, 0x08, +0x48, 0x88, 0x80, 0x24, +0x84, 0x60, 0xa4, 0x00, +0x2c, 0x88, 0x40, 0x7a, +0x40, 0x00, 0x03, 0x80, +0x00, 0xb0, 0x50, 0x46, +0xc0, 0x00, 0x27, 0x64, +0x86, 0xc0, 0x00, 0x36, +0x44, 0x8b, 0xa1, 0x48, +0x6c, 0x00, 0x02, 0x72, +0x48, 0x40, 0x00, 0x03, +0x80, 0x00, 0x5c, 0x81, +0x01, 0x8e, 0x88, 0x68, +0x00, 0x00, 0xee, 0x20, +0x68, 0x00, 0x00, 0xfa, +0x21, 0x68, 0x00, 0x01, +0x06, 0x22, 0x55, 0x01, +0x33, 0x80, 0x00, 0x55, +0x03, 0xb0, 0x00, 0x7a, +0x5d, 0x0c, 0x30, 0x08, +0x7a, 0x32, 0x2b, 0x0b, +0xff, 0xaa, 0x40, 0x00, +0x00, 0x10, 0x7a, 0x68, +0x00, 0x01, 0x1f, 0x22, +0x68, 0x00, 0x01, 0x2a, +0x21, 0x68, 0x00, 0x01, +0x14, 0x20, 0x55, 0x03, +0x20, 0x10, 0x7a, 0x5d, +0x08, 0x20, 0x08, 0x7a, +0x32, 0x26, 0x0b, 0xff, +0xaa, 0x80, 0x07, 0xa6, +0x80, 0x00, 0x14, 0x42, +0x06, 0x82, 0x00, 0x0e, +0xc2, 0x15, 0xc8, 0x20, +0x80, 0x07, 0xa5, 0xc0, +0x16, 0x04, 0x0f, 0xa8, +0x00, 0x7a, 0xa0, 0x08, +0x08, 0x48, 0x0a, 0x80, +0x2c, 0xa8, 0x40, 0x4a, +0xa0, 0x06, 0x08, 0x48, +0x8a, 0x80, 0x2c, 0xa6, +0x80, 0x00, 0x14, 0x22, +0x16, 0x80, 0x00, 0x25, +0x02, 0xc8, 0x02, 0xca, +0x6c, 0x00, 0x02, 0x98, +0x6c, 0x84, 0x87, 0xa4, +0x60, 0xa4, 0x04, 0x04, +0x88, 0x48, 0xfa, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6e, 0x40, 0x00, 0x08, +0x3c, 0x5c, 0x0b, 0xea, +0xbf, 0xe0, 0x25, 0x96, +0x0b, 0xc5, 0xb8, 0x5c, +0x00, 0x28, 0x80, 0x76, +0x68, 0x20, 0x00, 0x05, +0x20, 0x5c, 0x81, 0x02, +0xc1, 0x61, 0x84, 0x00, +0x85, 0x1d, 0x13, 0xa0, +0x10, 0x05, 0xd0, 0x80, +0x08, 0x0c, 0x92, 0x3c, +0x26, 0x3a, 0x1c, 0x72, +0x36, 0x00, 0x51, 0xf1, +0x20, 0x00, 0x50, 0x23, +0x63, 0xf5, 0x1b, 0x12, +0x00, 0x04, 0xb5, 0xd0, +0xc3, 0x04, 0x0c, 0x82, +0x36, 0x34, 0x80, 0x04, +0x8a, 0x05, 0x40, 0x80, +0x08, 0x83, 0xa9, 0x06, +0x23, 0xc2, 0x42, 0x34, +0x36, 0x51, 0xa1, 0x20, +0x00, 0x4a, 0x80, 0x2c, +0x86, 0x80, 0x04, 0x00, +0x48, 0x88, 0x40, 0x0b, +0x51, 0xe1, 0xf2, 0x01, +0x80, 0x51, 0xa1, 0xb0, +0x81, 0x48, 0x5d, 0x4e, +0x38, 0x40, 0xca, 0x23, +0x43, 0xe8, 0x00, 0x4a, +0xa0, 0x5e, 0x08, 0x81, +0xe0, 0x23, 0x0a, 0xd9, +0x82, 0x68, 0x68, 0x20, +0x00, 0x05, 0x20, 0x66, +0x00, 0x01, 0x58, 0x08, +0x9c, 0x00, 0x08, 0x80, +0x88, 0x55, 0x03, 0x28, +0x81, 0x08, 0x3b, 0x14, +0x55, 0x90, 0x74, 0x08, +0x0c, 0x95, 0x50, 0x32, +0x3f, 0xf1, 0xa8, 0x81, +0x48, 0x5c, 0x92, 0x0a, +0xc0, 0x20, 0x88, 0x1a, +0x00, 0x00, 0x00, 0x80, +0x08, 0x83, 0xa9, 0x05, +0x23, 0xc2, 0x42, 0x34, +0x2d, 0x51, 0xa1, 0x20, +0x00, 0x49, 0x80, 0x2c, +0x80, 0x00, 0x00, 0x84, +0x08, 0x85, 0xd4, 0x82, +0x84, 0x00, 0xb2, 0x3c, +0x3e, 0x23, 0xc2, 0x42, +0x34, 0x2d, 0x23, 0x43, +0x62, 0x34, 0x24, 0x3a, +0x9c, 0x76, 0xc0, 0x00, +0x23, 0xc4, 0x96, 0xc0, +0x00, 0x22, 0x64, 0xa6, +0xc0, 0x00, 0x25, 0x24, +0x85, 0x1a, 0x1f, 0xbc, +0x0a, 0xf6, 0xc0, 0x00, +0x1d, 0x04, 0xb3, 0x90, +0x20, 0x68, 0x20, 0x00, +0x0d, 0x20, 0x2a, 0x06, +0xc3, 0xb1, 0x05, 0x32, +0x32, 0x8b, 0xff, 0xca, +0x80, 0x07, 0xa3, 0x81, +0x76, 0x6e, 0x40, 0x00, +0x08, 0x3d, 0x25, 0x9a, +0x8b, 0xc0, 0xa8, 0x38, +0x06, 0x46, 0x82, 0x00, +0x00, 0x82, 0x03, 0x92, +0x20, 0x80, 0x00, 0x8a, +0x06, 0x01, 0x80, 0x80, +0x94, 0x20, 0x4f, 0x84, +0x04, 0x88, 0x48, 0x49, +0x68, 0x20, 0x00, 0x19, +0x20, 0x2a, 0x06, 0x43, +0xb1, 0x04, 0x32, 0x3a, +0x0b, 0xff, 0xca, 0x40, +0x00, 0x00, 0x00, 0x7a, +0x68, 0x20, 0x00, 0x0d, +0x20, 0x66, 0x00, 0x00, +0x61, 0xa8, 0x5c, 0x02, +0x29, 0x8e, 0x88, 0x68, +0x20, 0x00, 0x0d, 0x20, +0x00, 0x00, 0x0a, 0x00, +0x40, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x06, 0x1a, +0x85, 0xc0, 0x42, 0x98, +0xe8, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x04, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x06, 0x1a, +0x85, 0xc0, 0x06, 0x98, +0xe8, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x40, 0x40, 0x00, 0x00, +0x80, 0xe0, 0x66, 0x00, +0x00, 0x61, 0xa8, 0x5c, +0x00, 0xa9, 0x8e, 0x88, +0x5c, 0x81, 0x00, 0x80, +0xa0, 0x68, 0x00, 0x00, +0x36, 0x21, 0xa0, 0x02, +0x08, 0x00, 0x00, 0x80, +0x00, 0x28, 0x00, 0x01, +0x80, 0x00, 0xa8, 0x00, +0x08, 0x80, 0x00, 0x96, +0xc4, 0x00, 0x07, 0x85, +0x06, 0xc4, 0x00, 0x0c, +0x65, 0x28, 0x48, 0x51, +0x68, 0x00, 0x00, 0x4a, +0x22, 0x80, 0x00, 0xb8, +0x00, 0x00, 0x84, 0x08, +0x28, 0x00, 0x01, 0x6c, +0x40, 0x01, 0x5c, 0x51, +0xa0, 0x6c, 0x09, 0x40, +0x39, 0xb1, 0x00, 0x36, +0x80, 0x00, 0x09, 0x02, +0x35, 0x44, 0x67, 0x05, +0x04, 0xa6, 0xc4, 0x00, +0x18, 0xc5, 0x25, 0x90, +0x18, 0x05, 0x0c, 0x98, +0x48, 0xc8, 0x85, 0x8d, +0x04, 0x20, 0x3c, 0x85, +0x84, 0xb8, 0x80, 0xe0, +0x66, 0x00, 0x00, 0xdc, +0x88, 0x68, 0x00, 0x40, +0x03, 0x88, 0x5c, 0x81, +0x00, 0x80, 0xa0, 0x68, +0x00, 0x01, 0x00, 0x08, +0x94, 0x03, 0xd2, 0x89, +0x2c, 0x32, 0x02, 0x0b, +0xc0, 0xa1, 0x6e, 0x00, +0x01, 0x2c, 0x2c, 0x38, +0x11, 0xd2, 0x41, 0x60, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x66, 0x00, 0x00, +0xdf, 0xc0, 0x5c, 0x81, +0x00, 0x80, 0xa0, 0x68, +0x00, 0x02, 0x00, 0x08, +0x94, 0x03, 0xd2, 0x89, +0x2c, 0x32, 0x02, 0x0b, +0xc0, 0x61, 0x66, 0x00, +0x00, 0xf8, 0x28, 0x68, +0x00, 0x40, 0x05, 0x48, +0x5c, 0x81, 0x00, 0x80, +0xa0, 0xb0, 0x80, 0x49, +0x40, 0x1d, 0x28, 0x92, +0xc3, 0x20, 0x20, 0xbc, +0x07, 0x16, 0xe0, 0x00, +0x12, 0xca, 0xc3, 0x81, +0x05, 0x52, 0x0b, 0x03, +0x80, 0x00, 0x6e, 0x00, +0x01, 0x2c, 0xe0, 0x66, +0x00, 0x01, 0x58, 0x08, +0x68, 0x00, 0x40, 0x07, +0x48, 0x88, 0x0a, 0x06, +0x80, 0x03, 0xff, 0xfc, +0x88, 0x40, 0x89, 0x3a, +0x94, 0x63, 0x01, 0x30, +0x40, 0x00, 0x03, 0xc0, +0x40, 0x51, 0xa1, 0xb3, +0xc0, 0x4f, 0x6c, 0x00, +0x02, 0xac, 0x4a, 0x6c, +0x00, 0x02, 0xac, 0x7a, +0x23, 0xc2, 0xd3, 0x01, +0x28, 0x40, 0x00, 0x03, +0xc0, 0x40, 0x51, 0xa1, +0x63, 0xc0, 0x4f, 0x6c, +0x00, 0x02, 0xae, 0x48, +0x6c, 0x00, 0x02, 0xae, +0x7a, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x20, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5c, 0x00, 0x32, 0xbf, +0xd0, 0x88, 0x04, 0x88, +0x80, 0xf6, 0x88, 0x17, +0xa2, 0x30, 0xb6, 0x98, +0x2a, 0x86, 0x82, 0x00, +0x00, 0x52, 0x06, 0x60, +0x00, 0x15, 0x80, 0x89, +0xc0, 0x00, 0x88, 0x10, +0xa5, 0x50, 0x3b, 0x08, +0x00, 0x03, 0xa9, 0x86, +0x2a, 0x04, 0x45, 0x90, +0x58, 0x08, 0x04, 0x8b, +0xff, 0x1a, 0x88, 0x14, +0xa6, 0x60, 0x00, 0x15, +0x80, 0x8a, 0x40, 0x80, +0x6c, 0x40, 0x00, 0x0a, +0x0a, 0x5d, 0x4c, 0x02, +0xc0, 0x20, 0x68, 0x20, +0x00, 0x05, 0x20, 0x68, +0x20, 0x00, 0x85, 0x21, +0x51, 0xa0, 0x00, 0x40, +0x82, 0x51, 0xe1, 0xb0, +0x82, 0x01, 0x51, 0xa1, +0xb0, 0x80, 0xb6, 0x5d, +0x44, 0x38, 0x08, 0x50, +0x51, 0xe0, 0xb0, 0x08, +0x4a, 0x23, 0x43, 0x85, +0x1a, 0x1b, 0x00, 0x85, +0x05, 0x15, 0x06, 0x00, +0x84, 0xa4, 0x60, 0xa4, +0x14, 0x86, 0x19, 0x48, +0xe4, 0x40, 0x00, 0x02, +0x80, 0x30, 0x5c, 0x00, +0x22, 0xbf, 0x20, 0x88, +0x1c, 0x8a, 0x40, 0xc0, +0x88, 0x16, 0x08, 0x82, +0x76, 0x68, 0x00, 0x40, +0x01, 0x88, 0x88, 0x2c, +0x86, 0x60, 0x00, 0x15, +0x80, 0x08, 0x81, 0x88, +0x55, 0x03, 0x20, 0x81, +0x20, 0x5d, 0x48, 0x30, +0x82, 0x88, 0x59, 0x0f, +0x82, 0x00, 0x20, 0x43, +0xfa, 0x50, 0x81, 0x60, +0x55, 0x03, 0x20, 0x81, +0xca, 0x66, 0x00, 0x01, +0x58, 0x08, 0x40, 0x00, +0x02, 0x42, 0x80, 0x5c, +0x81, 0x02, 0x40, 0xc2, +0x5c, 0x00, 0x0a, 0x10, +0x60, 0x94, 0x03, 0x79, +0x40, 0xb5, 0xa4, 0x1a, +0x02, 0x30, 0x8c, 0x55, +0x02, 0x61, 0x82, 0x29, +0x5d, 0x48, 0x09, 0xd0, +0x81, 0x59, 0x0e, 0x41, +0x48, 0x36, 0x57, 0x0f, +0x91, 0x48, 0xb4, 0x57, +0x0b, 0x01, 0xc0, 0x83, +0x43, 0xf9, 0xd1, 0x58, +0x72, 0x95, 0x8f, 0x05, +0xc8, 0x60, 0xa4, 0x2a, +0x38, 0x8a, 0x08, 0x51, +0xa1, 0x22, 0x00, 0x22, +0x5b, 0x08, 0x10, 0x81, +0x62, 0x51, 0x58, 0x82, +0x41, 0xa1, 0x2e, 0x11, +0x22, 0xe1, 0x11, 0x22, +0xb0, 0x95, 0x15, 0x89, +0x01, 0x84, 0x15, 0x15, +0x93, 0x01, 0x84, 0x25, +0x40, 0x90, 0x01, 0x84, +0x05, 0x40, 0x81, 0x01, +0x87, 0xa5, 0x15, 0x80, +0x01, 0x84, 0xa5, 0x15, +0x88, 0x01, 0x84, 0x08, +0x1a, 0xc0, 0x88, 0x06, +0x38, 0x81, 0xe3, 0x68, +0x20, 0x00, 0x90, 0x23, +0x68, 0x20, 0x00, 0x8a, +0x24, 0x68, 0x20, 0x00, +0x8d, 0x25, 0x66, 0x00, +0x00, 0xed, 0xe8, 0x40, +0x00, 0x02, 0x00, 0x60, +0x5c, 0x81, 0x00, 0x8a, +0x08, 0x51, 0x61, 0x20, +0x81, 0xa3, 0x51, 0xa1, +0x22, 0xc0, 0xc1, 0x5b, +0x08, 0x10, 0x81, 0x20, +0x22, 0xb1, 0x05, 0x70, +0x89, 0x20, 0x05, 0x05, +0x70, 0x88, 0xa0, 0x46, +0x12, 0x2b, 0x09, 0x51, +0x58, 0x90, 0x18, 0x41, +0x51, 0x59, 0x30, 0x18, +0x42, 0x54, 0x09, 0x00, +0x18, 0x40, 0x54, 0x08, +0x10, 0x18, 0x7a, 0x51, +0x58, 0x00, 0x18, 0x4a, +0x51, 0x58, 0x80, 0x18, +0x40, 0x81, 0xac, 0x08, +0x80, 0x63, 0x68, 0x20, +0x00, 0x98, 0xa3, 0x68, +0x20, 0x00, 0x92, 0xa4, +0x68, 0x20, 0x00, 0x95, +0xa5, 0x66, 0x00, 0x00, +0xed, 0xe8, 0xa0, 0x82, +0x28, 0x82, 0x36, 0xba, +0x14, 0x8a, 0x80, 0xe0, +0x40, 0x00, 0x03, 0x80, +0x00, 0xba, 0x14, 0x82, +0xe1, 0xa8, 0x40, 0x00, +0x01, 0x80, 0x08, 0x59, +0x06, 0x42, 0xbf, 0xd0, +0x49, 0xa9, 0xb8, 0x80, +0x76, 0xbc, 0x19, 0x89, +0xa0, 0x00, 0x32, 0x03, +0x0b, 0xc0, 0x29, 0x38, +0x10, 0x02, 0xa0, 0x76, +0x68, 0x00, 0x09, 0xc4, +0x09, 0x50, 0x41, 0x83, +0xa1, 0x11, 0x44, 0x08, +0x81, 0x01, 0x58, 0x5b, +0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x02, 0x09, +0x08, 0x5b, 0x42, 0x0b, +0xa1, 0x01, 0x90, 0x11, +0x19, 0x02, 0x12, 0x29, +0x85, 0x13, 0x20, 0x08, +0xbc, 0x1a, 0x33, 0x60, +0x00, 0x37, 0x80, 0x0b, +0xc1, 0x77, 0x32, 0x02, +0x0b, 0xc0, 0x29, 0x38, +0x10, 0x02, 0xa0, 0x64, +0x68, 0x07, 0xff, 0xff, +0xc9, 0x50, 0x41, 0x03, +0xa1, 0x11, 0x44, 0x48, +0x81, 0x01, 0x58, 0x5b, +0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x02, 0x09, +0x08, 0x5b, 0x42, 0x0b, +0xa1, 0x01, 0x90, 0x11, +0x19, 0x02, 0x12, 0x29, +0x85, 0x13, 0x20, 0x08, +0xbc, 0x02, 0x33, 0x60, +0x00, 0x37, 0x80, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x30, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5b, 0x02, 0x03, 0x01, +0x01, 0x50, 0x43, 0x11, +0x84, 0x0a, 0x46, 0x08, +0x89, 0x83, 0x88, 0x44, +0x41, 0x09, 0x84, 0x8b, +0x98, 0x30, 0xa4, 0x47, +0x44, 0xab, 0xfe, 0x05, +0x08, 0x20, 0x08, 0x07, +0x60, 0x88, 0x82, 0x37, +0x80, 0x06, 0x80, 0x00, +0x9c, 0x40, 0x80, 0x84, +0x80, 0x6a, 0x00, 0x4e, +0x20, 0x02, 0x5b, 0x44, +0x11, 0x01, 0x58, 0x66, +0x00, 0x02, 0x09, 0x08, +0x5b, 0x40, 0x0b, 0xa1, +0x01, 0x90, 0x11, 0x26, +0xa0, 0x04, 0xe2, 0x00, +0x12, 0x98, 0x52, 0x32, +0x01, 0x0b, 0xc0, 0x3b, +0x88, 0x03, 0x63, 0x60, +0x00, 0x37, 0x80, 0x0b, +0xa1, 0x48, 0xa8, 0x02, +0x00, 0x00, 0x00, 0xab, +0xf8, 0x09, 0x40, 0x36, +0x88, 0x04, 0xa8, 0x80, +0xe5, 0x88, 0x16, 0x48, +0x81, 0xe3, 0x88, 0x26, +0x28, 0x82, 0xf6, 0x66, +0x00, 0x00, 0xe7, 0xa8, +0x40, 0x00, 0x01, 0x48, +0x35, 0x6a, 0x00, 0x02, +0x71, 0x00, 0x5b, 0x40, +0x00, 0x83, 0x48, 0x5c, +0x00, 0x21, 0x05, 0x58, +0x88, 0x3c, 0x88, 0x84, +0x54, 0x00, 0x00, 0x08, +0x80, 0x0a, 0x51, 0x85, +0x20, 0x82, 0x22, 0x98, +0x22, 0x89, 0xd0, 0x02, +0x88, 0x4e, 0x86, 0x60, +0x00, 0x0e, 0x7a, 0x89, +0x50, 0x35, 0x5b, 0x48, +0x3b, 0x01, 0xfe, 0x25, +0x9a, 0x06, 0x80, 0x01, +0xff, 0xfc, 0xab, 0xc0, +0x88, 0x55, 0x01, 0x00, +0x86, 0x48, 0x30, 0x1b, +0x8b, 0xc0, 0xcd, 0x88, +0x38, 0x16, 0x80, 0x01, +0xff, 0xfc, 0x0b, 0xc0, +0x87, 0x68, 0x00, 0x20, +0x00, 0x0a, 0x30, 0x1b, +0x8b, 0xc0, 0x4d, 0x40, +0x00, 0x00, 0x83, 0x81, +0x68, 0x00, 0x20, 0x00, +0x00, 0x59, 0x0a, 0x40, +0x81, 0xa2, 0xbc, 0x03, +0xb5, 0x50, 0x13, 0xac, +0x01, 0x09, 0x50, 0x50, +0x55, 0x02, 0x60, 0x81, +0xe2, 0x00, 0x00, 0x08, +0x84, 0xa8, 0x88, 0x82, +0x35, 0x18, 0x52, 0x08, +0x4c, 0x89, 0xd8, 0x04, +0x98, 0x22, 0x88, 0x60, +0x08, 0x9d, 0x80, 0x38, +0x83, 0x0a, 0x88, 0x6e, +0x46, 0x60, 0x00, 0x0e, +0x7e, 0x88, 0x58, 0x09, +0x88, 0x38, 0x83, 0x20, +0xe0, 0xbc, 0x13, 0x85, +0xc0, 0xfe, 0x19, 0x20, +0x19, 0x05, 0x12, 0x40, +0x00, 0x01, 0x07, 0x58, +0x66, 0x00, 0x02, 0x09, +0x08, 0x5b, 0x40, 0x08, +0x84, 0x16, 0x55, 0x00, +0x09, 0x07, 0x10, 0x6a, +0x00, 0x02, 0x71, 0x02, +0x29, 0x88, 0x23, 0x20, +0x10, 0xbc, 0x03, 0xb3, +0x81, 0xfc, 0x36, 0x04, +0x13, 0x78, 0x41, 0x52, +0xc8, 0x41, 0x83, 0x48, +0x68, 0x00, 0x1f, 0xff, +0xcb, 0xbc, 0x07, 0x83, +0x69, 0x04, 0x30, 0x1e, +0x0b, 0xc0, 0xa5, 0x6a, +0x00, 0x1f, 0xff, 0xc1, +0x40, 0x00, 0x03, 0xc0, +0x67, 0x68, 0x00, 0x20, +0x00, 0x0b, 0x30, 0x1e, +0x0b, 0xc0, 0x25, 0x6a, +0x00, 0x20, 0x00, 0x01, +0x5c, 0x80, 0x80, 0x81, +0x22, 0x98, 0x34, 0x19, +0x50, 0x51, 0x88, 0x16, +0x20, 0x00, 0x00, 0x88, +0x6a, 0x38, 0x83, 0x08, +0x66, 0x00, 0x00, 0xeb, +0x88, 0x55, 0x00, 0x08, +0x58, 0x09, 0x5c, 0x0f, +0xf9, 0x83, 0x08, 0x25, +0x9c, 0x05, 0xb4, 0x82, +0x3c, 0x09, 0x86, 0x80, +0x01, 0xff, 0xfc, 0xb3, +0x01, 0xe0, 0xbc, 0x0d, +0xd8, 0x84, 0x88, 0x6a, +0x00, 0x1f, 0xff, 0xc0, +0x40, 0x00, 0x03, 0xc0, +0x87, 0x68, 0x00, 0x20, +0x00, 0x0b, 0x30, 0x1e, +0x0b, 0xc0, 0x4d, 0x40, +0x00, 0x00, 0x84, 0x88, +0x6a, 0x00, 0x20, 0x00, +0x00, 0x5c, 0x80, 0x80, +0x80, 0xa2, 0x5d, 0x88, +0x21, 0x83, 0x00, 0x59, +0x0d, 0x00, 0x86, 0x0b, +0x95, 0x05, 0x08, 0x83, +0x4b, 0x88, 0x3c, 0x88, +0x80, 0xe2, 0xbf, 0x77, +0xa8, 0x80, 0x0a, 0x88, +0x2b, 0x6b, 0xa1, 0x48, +0xa8, 0x08, 0x00, 0x00, +0x00, 0x5c, 0x00, 0x02, +0xbf, 0xe0, 0x88, 0x04, +0x88, 0x80, 0xf6, 0x88, +0x17, 0xa2, 0x30, 0x80, +0x98, 0x42, 0x86, 0x82, +0x00, 0x00, 0x52, 0x06, +0x60, 0x00, 0x15, 0x80, +0x89, 0xc0, 0x00, 0x88, +0x10, 0x05, 0x50, 0x20, +0x08, 0x00, 0x23, 0xa8, +0x00, 0x2a, 0x05, 0x45, +0x90, 0x40, 0x08, 0x04, +0x8b, 0xff, 0x1a, 0x88, +0x15, 0x06, 0x82, 0x00, +0x00, 0x52, 0x06, 0xc4, +0x00, 0x00, 0xa0, 0x05, +0x1e, 0x02, 0x04, 0x08, +0x26, 0x82, 0x00, 0x1b, +0xa2, 0x05, 0xd4, 0x00, +0x08, 0x0b, 0x62, 0x3c, +0x16, 0x68, 0x20, 0x01, +0xbc, 0x21, 0x3a, 0x88, +0x12, 0x34, 0x00, 0x51, +0xa1, 0x10, 0x40, 0x50, +0x51, 0xa1, 0x80, 0x40, +0xd2, 0x51, 0xa0, 0x50, +0x48, 0xd0, 0xba, 0x14, +0x88, 0x48, 0x52, 0x40, +0x00, 0x02, 0x80, 0x20, +0xab, 0xfd, 0x08, 0x80, +0x60, 0x88, 0x0f, 0x66, +0x80, 0x10, 0x00, 0x4c, +0x86, 0x60, 0x00, 0x15, +0x80, 0x8a, 0x40, 0x80, +0x5c, 0x09, 0xc2, 0x40, +0x80, 0x94, 0x02, 0xa2, +0x58, 0x10, 0xbc, 0x05, +0x06, 0x83, 0x40, 0x84, +0x02, 0x19, 0x41, 0x28, +0x84, 0x85, 0x28, 0x48, +0xd0, 0x66, 0x00, 0x01, +0x58, 0x08, 0x68, 0x00, +0x80, 0x03, 0x88, 0x5c, +0x09, 0xc2, 0x40, 0x80, +0x94, 0x02, 0xa2, 0x58, +0x10, 0xbc, 0x07, 0x86, +0x83, 0x40, 0x84, 0x22, +0x15, 0xc0, 0x80, 0x94, +0x0a, 0x82, 0x58, 0x40, +0x40, 0x00, 0x03, 0xc1, +0x01, 0x66, 0x00, 0x01, +0x58, 0x08, 0x68, 0x01, +0x00, 0x05, 0x08, 0x5c, +0x09, 0xc2, 0x40, 0x80, +0x94, 0x02, 0xa2, 0x58, +0x10, 0xbc, 0x0b, 0x06, +0x83, 0x40, 0x84, 0x22, +0x19, 0x41, 0x28, 0x6c, +0x68, 0x10, 0x84, 0x52, +0x84, 0x8d, 0x0b, 0xc0, +0x47, 0x94, 0x12, 0x86, +0xc6, 0x81, 0x08, 0x45, +0x28, 0x48, 0xd0, 0x66, +0x00, 0x01, 0x58, 0x08, +0x68, 0x01, 0x00, 0x05, +0x48, 0x5c, 0x09, 0xc2, +0x40, 0x80, 0x94, 0x02, +0xa2, 0x58, 0x10, 0xbc, +0x05, 0x06, 0x83, 0x40, +0x84, 0x42, 0x19, 0x41, +0x28, 0x84, 0x85, 0x28, +0x48, 0xd0, 0x66, 0x00, +0x01, 0x58, 0x08, 0x68, +0x00, 0x80, 0x03, 0xc8, +0x5c, 0x09, 0xc2, 0x40, +0x80, 0x94, 0x02, 0xa2, +0x58, 0x10, 0xbc, 0x07, +0x86, 0x83, 0x40, 0x84, +0x62, 0x15, 0xc0, 0x80, +0x94, 0x0a, 0x82, 0x58, +0x40, 0x40, 0x00, 0x03, +0xc1, 0x01, 0x66, 0x00, +0x01, 0x58, 0x08, 0x68, +0x01, 0x00, 0x05, 0x88, +0x5c, 0x09, 0xd2, 0x40, +0x80, 0x94, 0x02, 0x82, +0x58, 0x80, 0xbc, 0x0b, +0x06, 0x83, 0x40, 0x84, +0x62, 0x19, 0x41, 0x2a, +0x6c, 0x68, 0x10, 0x8c, +0x50, 0x84, 0x8d, 0x2b, +0xc0, 0x47, 0x94, 0x12, +0x86, 0xc6, 0x81, 0x08, +0xc5, 0x28, 0x48, 0xd0, +0x66, 0x00, 0x01, 0x58, +0x08, 0x68, 0x01, 0x00, +0x05, 0xc8, 0x5c, 0x09, +0xc2, 0x40, 0x80, 0x94, +0x02, 0xa2, 0x58, 0x10, +0xbc, 0x05, 0x06, 0x83, +0x40, 0x88, 0x02, 0x19, +0x41, 0x28, 0x84, 0x85, +0x28, 0x48, 0xd0, 0x66, +0x00, 0x01, 0x58, 0x08, +0x68, 0x01, 0x00, 0x06, +0x08, 0x5c, 0x09, 0xc2, +0x40, 0x80, 0x94, 0x0a, +0xa2, 0x58, 0x10, 0xbc, +0x0d, 0x05, 0xc8, 0x04, +0x20, 0x01, 0x95, 0x19, +0x08, 0x14, 0x02, 0x95, +0x48, 0x20, 0x94, 0xa0, +0xa6, 0x83, 0x40, 0x88, +0x22, 0x05, 0x19, 0x09, +0x14, 0x82, 0x85, 0x48, +0x08, 0x04, 0x05, 0x18, +0x40, 0xd0, 0x68, 0x00, +0x40, 0x00, 0x08, 0x88, +0x02, 0x08, 0x81, 0x7a, +0x88, 0x1c, 0x86, 0x60, +0x00, 0x15, 0x80, 0x08, +0x81, 0x00, 0x55, 0x02, +0x00, 0x80, 0x20, 0x5d, +0x00, 0x00, 0x81, 0x82, +0x59, 0x0c, 0x02, 0x00, +0x20, 0x43, 0xfa, 0x50, +0x80, 0x60, 0x55, 0x02, +0xa0, 0x81, 0x50, 0x00, +0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, +0x30, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x00, 0x42, 0x08, 0x5d, +0x08, 0x33, 0x01, 0xc0, +0x52, 0x01, 0x02, 0xbf, +0xd0, 0x6c, 0x40, 0x00, +0x42, 0x50, 0x59, 0x01, +0x81, 0x8e, 0x88, 0x88, +0x0e, 0x04, 0x20, 0x64, +0x08, 0x17, 0x65, 0x50, +0x13, 0x08, 0x04, 0xa0, +0x00, 0x00, 0x88, 0x00, +0x03, 0x20, 0x40, 0xbc, +0x06, 0x8b, 0x00, 0x0c, +0x88, 0x00, 0xa3, 0x20, +0xb0, 0xbc, 0x02, 0x92, +0xa0, 0x26, 0x98, 0xe8, +0x83, 0x20, 0x60, 0xbc, +0x0b, 0x98, 0x81, 0xc8, +0x40, 0x00, 0x00, 0x82, +0x4a, 0x66, 0x00, 0x01, +0xd4, 0x60, 0x68, 0x00, +0x00, 0x38, 0x20, 0x5c, +0x81, 0x00, 0x82, 0x0a, +0x80, 0x20, 0x88, 0x40, +0x48, 0x32, 0x07, 0x0b, +0xc0, 0xa9, 0x40, 0x00, +0x00, 0x82, 0x4a, 0x66, +0x00, 0x01, 0xd5, 0x20, +0x68, 0x00, 0x00, 0x4c, +0x20, 0x39, 0x02, 0x08, +0x02, 0x08, 0x40, 0x00, +0x00, 0x40, 0x48, 0x68, +0x00, 0x00, 0x49, 0x20, +0x66, 0x00, 0x00, 0x64, +0x68, 0x40, 0x00, 0x00, +0x81, 0x88, 0x68, 0x00, +0x00, 0x5d, 0x20, 0x66, +0x00, 0x00, 0x64, 0x68, +0x88, 0x20, 0x88, 0x80, +0x08, 0x32, 0x02, 0x0b, +0xc1, 0x09, 0x88, 0x0a, +0x03, 0x81, 0xc4, 0xa0, +0x10, 0x08, 0x40, 0x0a, +0x24, 0x93, 0x66, 0xc4, +0x00, 0x04, 0x20, 0x05, +0x24, 0x82, 0x04, 0x04, +0xa6, 0xc4, 0x00, 0x04, +0x24, 0x86, 0x80, 0x00, +0x0e, 0xc2, 0xc4, 0x20, +0x2f, 0xa0, 0x4e, 0x08, +0x40, 0x6c, 0x68, 0x00, +0x04, 0x2b, 0xa0, 0x6c, +0x00, 0x00, 0x0a, 0x60, +0x00, 0x00, 0x08, 0x81, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x30, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x00, 0x00, 0x37, 0x23, +0x68, 0x20, 0x00, 0x82, +0x22, 0x85, 0x80, 0x88, +0x50, 0x0a, 0x58, 0x0d, +0x02, 0xbf, 0xf0, 0x68, +0x20, 0x00, 0x81, 0x21, +0x42, 0x02, 0x40, 0x80, +0xf6, 0x88, 0x06, 0x06, +0x60, 0x00, 0x1f, 0x96, +0x8a, 0x18, 0x00, 0x68, +0x00, 0x00, 0x4b, 0x20, +0x6c, 0x40, 0x01, 0x04, +0x08, 0x84, 0x00, 0xa3, +0x01, 0x30, 0x68, 0x20, +0x00, 0x82, 0x22, 0x40, +0x00, 0x03, 0xc0, 0x48, +0x68, 0x20, 0x00, 0x81, +0x21, 0x66, 0x00, 0x01, +0xf9, 0x60, 0x6c, 0x00, +0x00, 0x6e, 0x08, 0x6c, +0x40, 0x01, 0x04, 0x0a, +0x30, 0x1a, 0x0b, 0xc0, +0x69, 0x88, 0x02, 0x06, +0xc0, 0x00, 0x09, 0x60, +0x83, 0x01, 0xa0, 0x40, +0x00, 0x03, 0xc0, 0x40, +0x68, 0x00, 0x04, 0x2b, +0xa2, 0xbc, 0x0f, 0xf8, +0x40, 0xe2, 0x5c, 0x0e, +0x22, 0x01, 0x00, 0x84, +0x00, 0xa2, 0x49, 0x36, +0x6c, 0x40, 0x00, 0x42, +0x00, 0x52, 0x48, 0x20, +0x40, 0x4a, 0xa0, 0x4e, +0x06, 0x80, 0x00, 0x0e, +0xc2, 0xc8, 0x40, 0x6c, +0x6c, 0x40, 0x00, 0x42, +0x48, 0x00, 0x00, 0x08, +0x80, 0xb6, 0xba, 0x14, +0x8a, 0x80, 0x10, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x00, 0x44, +0x08, 0x5c, 0x0e, 0x33, +0x01, 0x05, 0x24, 0x1a, +0x46, 0xe0, 0x00, 0x12, +0xc2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x00, 0x44, +0x48, 0xbc, 0x05, 0x83, +0x81, 0x2d, 0x52, 0x4b, +0xc3, 0xc0, 0x5f, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x24, 0x17, 0x86, 0xe0, +0x00, 0x12, 0xc6, 0x03, +0x81, 0x0d, 0x25, 0x96, +0x0b, 0xc0, 0x30, 0xbc, +0x05, 0xf6, 0xc4, 0x00, +0x20, 0x67, 0xa3, 0x80, +0x0d, 0x6c, 0x40, 0x02, +0x06, 0x49, 0x52, 0x4d, +0x22, 0x01, 0x00, 0x84, +0x00, 0x92, 0x49, 0xae, +0x84, 0x04, 0xa6, 0xc4, +0x00, 0x04, 0x44, 0x86, +0x80, 0x00, 0x0e, 0xc2, +0xc4, 0x60, 0xa4, 0x20, +0x4e, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x00, +0x46, 0x08, 0x5c, 0x0e, +0x33, 0x01, 0x05, 0x24, +0x1a, 0x46, 0xe0, 0x00, +0x12, 0xc2, 0xf2, 0x59, +0x60, 0x6c, 0x40, 0x00, +0x46, 0x48, 0xbc, 0x05, +0x83, 0x81, 0x15, 0x52, +0x4b, 0xc3, 0xc1, 0xaf, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x25, 0x97, 0x8b, +0xc1, 0x60, 0x38, 0x10, +0x82, 0x58, 0x20, 0xbc, +0x04, 0x06, 0xc0, 0x00, +0x0c, 0xe7, 0xa6, 0xc0, +0x00, 0x0e, 0x27, 0xa2, +0x59, 0x60, 0xbc, 0x08, +0x16, 0xc4, 0x00, 0x23, +0x60, 0x02, 0x31, 0x00, +0x6c, 0x40, 0x01, 0xea, +0x50, 0x23, 0x14, 0x06, +0xc0, 0x00, 0x13, 0x05, +0x02, 0x41, 0x78, 0x6c, +0x00, 0x01, 0x32, 0x7a, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x52, 0x4d, 0x22, +0x01, 0x00, 0x84, 0x00, +0x92, 0x49, 0xae, 0x84, +0x04, 0xa6, 0xc4, 0x00, +0x04, 0x64, 0x86, 0x80, +0x00, 0x0e, 0xc2, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x04, 0x28, +0x08, 0x5c, 0x0e, 0x33, +0x01, 0x00, 0x24, 0x1a, +0x46, 0xe0, 0x00, 0x12, +0xc2, 0xa2, 0x58, 0x20, +0x6c, 0x40, 0x04, 0x28, +0x48, 0xbc, 0x05, 0x83, +0x81, 0x20, 0x52, 0x00, +0x83, 0xc0, 0x6f, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x52, 0x40, 0x83, 0x80, +0x00, 0x6e, 0x00, 0x01, +0x2c, 0x60, 0x51, 0xc3, +0x2a, 0x01, 0x00, 0x68, +0x20, 0x00, 0xd7, 0x21, +0x5d, 0x0a, 0x10, 0x40, +0x00, 0x51, 0x84, 0x90, +0x48, 0x52, 0x52, 0x4d, +0x22, 0x08, 0x21, 0x52, +0x4c, 0x31, 0x84, 0xa8, +0x9c, 0x80, 0x18, 0x48, +0x00, 0x84, 0x04, 0xa6, +0xc4, 0x00, 0x42, 0x84, +0x86, 0xc4, 0x00, 0x19, +0x85, 0x06, 0xc4, 0x00, +0x19, 0xa5, 0x06, 0xc4, +0x00, 0x2f, 0x85, 0x06, +0xc4, 0x00, 0x2f, 0x25, +0x06, 0x80, 0x00, 0x0e, +0xc2, 0xc4, 0x60, 0xa4, +0x20, 0x4e, 0x08, 0x40, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x04, 0x2e, 0x08, 0x68, +0x00, 0x47, 0xff, 0xca, +0x68, 0x38, 0x1c, 0x03, +0x21, 0x54, 0x4d, 0x22, +0xff, 0xe0, 0x5c, 0x00, +0x40, 0x48, 0x48, 0x5c, +0x00, 0x21, 0xc8, 0x01, +0x5c, 0x09, 0xf0, 0x48, +0x7a, 0x84, 0x95, 0x00, +0x00, 0x00, 0x6c, 0x70, +0x38, 0x0c, 0x00, 0x25, +0x98, 0x0b, 0xc0, 0x50, +0x6c, 0x70, 0x38, 0x06, +0x08, 0xbc, 0x05, 0xf6, +0xc4, 0x00, 0x42, 0xe4, +0x83, 0x22, 0xa0, 0xbf, +0xf5, 0xa2, 0xa0, 0x64, +0x5c, 0x0e, 0x22, 0x01, +0x00, 0x84, 0x00, 0xa2, +0x49, 0x34, 0x84, 0x04, +0x86, 0x80, 0x00, 0x0e, +0xc2, 0xc4, 0x60, 0xa4, +0x20, 0x4e, 0x08, 0x40, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x04, 0x30, 0x08, 0x5c, +0x0e, 0x33, 0x01, 0x05, +0x24, 0x1a, 0x46, 0xe0, +0x00, 0x12, 0xc2, 0xf2, +0x59, 0x60, 0x6c, 0x40, +0x04, 0x30, 0x48, 0xbc, +0x05, 0x83, 0x81, 0x3d, +0x52, 0x4b, 0xc3, 0xc0, +0x6f, 0x6e, 0x00, 0x01, +0x2c, 0x60, 0x52, 0x0b, +0xc3, 0x80, 0x00, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x52, 0x4d, 0x22, 0x01, +0x00, 0x84, 0x00, 0x92, +0x49, 0xae, 0x84, 0x04, +0xa6, 0xc4, 0x00, 0x43, +0x04, 0x86, 0x80, 0x00, +0x0e, 0xc2, 0xc4, 0x60, +0xa4, 0x20, 0x4e, 0x08, +0x40, 0x6c, 0x40, 0x00, +0x03, 0x80, 0x00, 0x5c, +0x07, 0x62, 0x00, 0x80, +0x84, 0x02, 0x10, 0x00, +0x00, 0x94, 0x8a, 0xe3, +0x01, 0x30, 0xbc, 0x07, +0x9a, 0x04, 0x60, 0x6c, +0x40, 0x04, 0x32, 0x08, +0x38, 0x1b, 0xe2, 0x41, +0xa4, 0x6c, 0x40, 0x04, +0x32, 0x48, 0x68, 0x00, +0x04, 0x78, 0xa1, 0xba, +0x14, 0x88, 0x40, 0x61, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x05, +0x69, 0x21, 0x6c, 0x00, +0x01, 0x2e, 0x08, 0x98, +0x84, 0x95, 0x80, 0xb0, +0x2b, 0xff, 0x04, 0x24, +0x0c, 0x88, 0x07, 0x68, +0x80, 0xe0, 0xb0, 0x7f, +0xd6, 0xc4, 0x00, 0x43, +0x20, 0x02, 0x3e, 0x06, +0x28, 0x97, 0x53, 0x28, +0x28, 0xbc, 0x2f, 0x8b, +0x00, 0x14, 0x66, 0x00, +0x00, 0x6e, 0x48, 0x40, +0x00, 0x03, 0x01, 0xbd, +0x6c, 0x40, 0x04, 0x32, +0x08, 0x51, 0xd1, 0x2b, +0x01, 0xba, 0x52, 0xc5, +0x03, 0x07, 0xf8, 0x23, +0xc2, 0x65, 0x44, 0x16, +0xbc, 0x11, 0x82, 0x88, +0x36, 0x68, 0x00, 0x03, +0x03, 0x20, 0x5c, 0x80, +0x43, 0x07, 0xf8, 0x54, +0x41, 0x21, 0x40, 0x46, +0xa0, 0x00, 0x19, 0x40, +0x45, 0x94, 0x8e, 0x4a, +0x04, 0x10, 0xb0, 0x08, +0x56, 0x60, 0x00, 0x06, +0xec, 0x8b, 0x00, 0x1c, +0x40, 0x00, 0x03, 0xc5, +0x67, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x09, +0xe2, 0xc0, 0x80, 0x52, +0x09, 0x82, 0x08, 0x00, +0x94, 0x84, 0x06, 0xc0, +0x00, 0x62, 0x07, 0xa9, +0x40, 0xe5, 0xb0, 0x01, +0x4b, 0x00, 0x86, 0x66, +0x00, 0x00, 0x70, 0xa8, +0xb0, 0x00, 0xdb, 0xc4, +0x67, 0x6c, 0x40, 0x00, +0x02, 0x09, 0xb0, 0x7f, +0xe2, 0x89, 0xad, 0x32, +0x02, 0x8b, 0xc1, 0xc0, +0x32, 0x0a, 0x8b, 0xc1, +0x60, 0x32, 0x1a, 0x8b, +0xc1, 0x00, 0x23, 0xc0, +0x52, 0x89, 0xae, 0x32, +0x83, 0x0b, 0xc0, 0x60, +0x32, 0x8a, 0x8b, 0xc1, +0x69, 0xb0, 0x1b, 0xd6, +0x60, 0x00, 0x06, 0xe4, +0x0b, 0xc1, 0x27, 0xb0, +0x1b, 0xd6, 0x60, 0x00, +0x06, 0xe4, 0x8b, 0x00, +0x54, 0x40, 0x00, 0x03, +0xc0, 0xc7, 0x66, 0x00, +0x00, 0x6e, 0x48, 0xb0, +0x1b, 0xdb, 0xc0, 0x87, +0x66, 0x00, 0x00, 0x6e, +0x48, 0xb0, 0x1b, 0xdb, +0xc0, 0x47, 0xb0, 0x1b, +0xd6, 0x60, 0x00, 0x06, +0xe4, 0x8b, 0x00, 0x54, +0x6c, 0x40, 0x04, 0x32, +0x08, 0x51, 0xd1, 0x2b, +0x01, 0xbe, 0x52, 0xcd, +0x03, 0x07, 0xfe, 0x68, +0x00, 0x03, 0x03, 0x20, +0x5c, 0x84, 0x03, 0xc0, +0xc8, 0x54, 0x4d, 0x6b, +0x01, 0x3e, 0xb0, 0x7f, +0xe6, 0xe0, 0x00, 0x60, +0x66, 0x55, 0x44, 0xd3, +0x18, 0xe8, 0x99, 0x40, +0xe6, 0x66, 0x00, 0x00, +0x6e, 0xc8, 0xb0, 0x01, +0x4b, 0xc0, 0xa7, 0x52, +0x0d, 0x42, 0x00, 0x01, +0x6c, 0x00, 0x06, 0x20, +0x7a, 0x94, 0x84, 0x0b, +0x00, 0x0d, 0x66, 0x00, +0x00, 0x70, 0xa8, 0x55, +0x01, 0x61, 0x8e, 0x8a, +0x88, 0x0a, 0x06, 0x80, +0x00, 0x49, 0xca, 0x18, +0x40, 0xe1, 0x00, 0x00, +0x08, 0x80, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x04, +0x32, 0x08, 0x38, 0x1b, +0xe2, 0x59, 0xa0, 0x40, +0x00, 0x03, 0xc0, 0x41, +0x6e, 0x00, 0x06, 0x0e, +0x2c, 0x6c, 0x40, 0x04, +0x32, 0x48, 0x5c, 0x0e, +0x22, 0x01, 0x00, 0x84, +0x00, 0xa2, 0x49, 0x34, +0x84, 0x04, 0x86, 0x80, +0x00, 0x0e, 0xc2, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x05, 0x00, +0x08, 0x6c, 0x68, 0x00, +0x56, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x40, +0x00, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x44, 0x28, +0x02, 0xc0, 0x20, 0x5c, +0x04, 0x29, 0x80, 0x08, +0x22, 0x8e, 0x09, 0x80, +0x0a, 0x68, 0x3f, 0xcb, +0xfc, 0xcb, 0x68, 0x20, +0x03, 0x36, 0x20, 0x08, +0xe0, 0x05, 0x10, 0x20, +0x00, 0x00, 0xb5, 0x40, +0xe0, 0x80, 0x00, 0x29, +0x80, 0x4b, 0x44, 0x70, +0x80, 0x40, 0x00, 0x22, +0x04, 0x92, 0x80, 0x8a, +0x98, 0x08, 0xb0, 0x8e, +0x20, 0x22, 0x05, 0x22, +0x80, 0x12, 0x98, 0x08, +0xa0, 0x82, 0x20, 0x22, +0x05, 0x29, 0x80, 0x88, +0x28, 0x16, 0x52, 0x29, +0x6d, 0x2e, 0x14, 0x50, +0x81, 0x20, 0x22, 0x05, +0x29, 0x80, 0x88, 0x2a, +0x12, 0x52, 0x28, 0xed, +0x2e, 0x14, 0x50, 0x81, +0x20, 0x51, 0x02, 0x93, +0xa1, 0x48, 0x98, 0x08, +0x82, 0xe1, 0x04, 0x5b, +0x4a, 0x02, 0xbf, 0xf0, +0x6c, 0x40, 0x06, 0x68, +0x02, 0x30, 0x08, 0x0b, +0xc0, 0x7a, 0x5c, 0x00, +0x10, 0x80, 0x76, 0x00, +0x00, 0x06, 0xc4, 0x00, +0x66, 0xa0, 0x25, 0x70, +0x40, 0x30, 0x00, 0xa8, +0x80, 0xd2, 0x66, 0x00, +0x01, 0x29, 0x48, 0x23, +0x04, 0x58, 0x80, 0x80, +0x32, 0x00, 0x0b, 0xc0, +0x38, 0x51, 0x43, 0x20, +0x80, 0x36, 0x36, 0x10, +0x4b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0xab, 0xff, 0x08, 0x80, +0x76, 0x66, 0x00, 0x01, +0x2b, 0xe8, 0x6c, 0x00, +0x05, 0xaa, 0x09, 0x68, +0x20, 0x03, 0x2f, 0x20, +0x44, 0x00, 0x02, 0xc0, +0x20, 0x51, 0x06, 0x00, +0x02, 0x09, 0x57, 0x0a, +0x12, 0x00, 0x41, 0x51, +0x85, 0x28, 0x08, 0x08, +0x57, 0x0b, 0x01, 0x80, +0x88, 0x51, 0x85, 0x20, +0x08, 0x09, 0x6c, 0x00, +0x05, 0xaa, 0x02, 0x44, +0x24, 0x00, 0x40, 0x0a, +0x54, 0x0c, 0x90, 0x08, +0x08, 0x58, 0x08, 0x80, +0x48, 0x09, 0xbc, 0x03, +0xd9, 0x81, 0x08, 0x28, +0x15, 0x02, 0x81, 0x42, +0x88, 0x03, 0x6b, 0xa1, +0x48, 0x6c, 0x00, 0x05, +0xaa, 0x42, 0x40, 0x00, +0x02, 0x80, 0x10, 0xab, +0xfe, 0x08, 0x80, 0x49, +0x88, 0x0c, 0x88, 0x81, +0x76, 0x66, 0x00, 0x01, +0x2d, 0x80, 0x5c, 0x81, +0x00, 0x80, 0x09, 0x68, +0x00, 0x02, 0xe3, 0x20, +0x44, 0x20, 0x00, 0x80, +0x89, 0x44, 0x21, 0x00, +0x02, 0x08, 0x6c, 0x40, +0x06, 0x78, 0x0a, 0x44, +0x10, 0x80, 0x40, 0x09, +0xa0, 0x00, 0x18, 0x00, +0x48, 0x51, 0x02, 0x41, +0xa0, 0x01, 0x51, 0x63, +0xd0, 0x81, 0x36, 0x28, +0x01, 0x02, 0xe1, 0x40, +0x51, 0x63, 0x10, 0x40, +0x40, 0xa0, 0x06, 0x08, +0x02, 0x08, 0x44, 0x10, +0x00, 0x49, 0x40, 0x22, +0x04, 0x05, 0x40, 0x08, +0x04, 0x00, 0x92, 0xe1, +0x40, 0x84, 0x14, 0x04, +0x60, 0xa4, 0x00, 0x04, +0x88, 0x40, 0x40, 0x40, +0x00, 0x02, 0x80, 0x20, +0x68, 0x00, 0x02, 0xe4, +0x25, 0x68, 0x20, 0x03, +0x3c, 0x27, 0x5c, 0x81, +0x02, 0x2c, 0x44, 0x86, +0x80, 0x08, 0x78, 0x08, +0x86, 0x00, 0xa4, 0x44, +0x60, 0x23, 0x82, 0x65, +0x10, 0x80, 0x07, 0x00, +0x84, 0x44, 0x10, 0x23, +0x02, 0x5a, 0x28, 0x07, +0x82, 0x80, 0xa5, 0x10, +0x88, 0x18, 0x00, 0x84, +0x41, 0x10, 0x06, 0x80, +0x99, 0x80, 0x0a, 0x44, +0x4c, 0x42, 0x20, 0xa4, +0x51, 0x08, 0x02, 0x24, +0x46, 0x84, 0x04, 0x0a, +0x2c, 0x60, 0x87, 0x80, +0x94, 0x44, 0x80, 0x06, +0x80, 0xa4, 0x41, 0x60, +0x20, 0x02, 0x52, 0x21, +0x00, 0x84, 0x84, 0x00, +0x00, 0x00, 0x86, 0x00, +0x08, 0x70, 0x08, 0x84, +0x00, 0xa4, 0x41, 0x60, +0x02, 0x80, 0xa4, 0x41, +0x10, 0x22, 0x80, 0x15, +0x10, 0x80, 0x02, 0x80, +0x95, 0x10, 0x88, 0x18, +0x00, 0x84, 0x40, 0x80, +0x18, 0x00, 0xb8, 0x68, +0x0a, 0x08, 0xe8, 0x02, +0x21, 0x00, 0x85, 0x04, +0x00, 0x00, 0x00, 0x84, +0x80, 0xa4, 0x47, 0x00, +0x06, 0x80, 0xa0, 0x82, +0xc0, 0x51, 0x08, 0x03, +0xa1, 0x48, 0x85, 0x84, +0x00, 0x00, 0x00, 0x84, +0x00, 0x94, 0x42, 0x80, +0x04, 0x80, 0x94, 0x42, +0xc0, 0x2b, 0xff, 0x08, +0x80, 0x76, 0x66, 0x00, +0x00, 0x74, 0xa8, 0x98, +0x00, 0x98, 0x80, 0x36, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x5d, 0xc4, 0x8a, +0x80, 0x10, 0xab, 0xff, +0x08, 0x40, 0x0a, 0x88, +0x07, 0x66, 0x60, 0x00, +0x08, 0x66, 0x88, 0x48, +0x09, 0x6c, 0x40, 0x06, +0x72, 0x09, 0x44, 0x08, +0x00, 0x80, 0x36, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x5d, 0xe4, 0x0a, 0x80, +0x10, 0x84, 0x00, 0x94, +0x42, 0x80, 0x04, 0x80, +0x94, 0x42, 0xc0, 0x2b, +0xff, 0x08, 0x80, 0x76, +0x66, 0x00, 0x00, 0x74, +0xa8, 0x98, 0x00, 0x98, +0x80, 0x36, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x5e, +0x04, 0x8a, 0x80, 0x10, +0xab, 0xff, 0x08, 0x40, +0x0a, 0x88, 0x07, 0x66, +0x60, 0x00, 0x08, 0x66, +0x88, 0x48, 0x09, 0x6c, +0x40, 0x06, 0x72, 0x09, +0x44, 0x08, 0x00, 0x80, +0x36, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x5e, 0x24, +0x0a, 0x80, 0x10, 0x68, +0x00, 0x02, 0xf0, 0x20, +0x39, 0x04, 0x08, 0x02, +0x0a, 0x80, 0x20, 0x95, +0x70, 0xb8, 0x20, 0x0a, +0x18, 0x0a, 0x0a, 0x80, +0xa0, 0x96, 0xc4, 0x00, +0x67, 0x40, 0x85, 0x70, +0xb8, 0x04, 0x05, 0x03, +0x01, 0x00, 0xbc, 0x07, +0xd8, 0x48, 0x50, 0x00, +0x00, 0x06, 0xc4, 0x00, +0x67, 0x60, 0xa2, 0xe1, +0x86, 0x6c, 0x00, 0x05, +0xda, 0x4a, 0x36, 0x10, +0x68, 0x48, 0x08, 0x30, +0x1a, 0x0b, 0xc0, 0x73, +0x6c, 0x40, 0x06, 0x76, +0x0a, 0x54, 0x0d, 0x23, +0xa1, 0x48, 0x6c, 0x00, +0x05, 0xda, 0x48, 0x00, +0x00, 0x0b, 0xa1, 0x40, +0x68, 0x00, 0x02, 0xd4, +0x20, 0x68, 0x00, 0x04, +0xf3, 0x2c, 0x84, 0x07, +0xaa, 0x04, 0x60, 0x84, +0x07, 0xa4, 0x60, 0xa4, +0x20, 0x42, 0x08, 0x40, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x00, +0x05, 0xa2, 0x08, 0x38, +0x10, 0x62, 0x59, 0xa0, +0xbc, 0x1c, 0x16, 0x80, +0x00, 0x2d, 0x22, 0x05, +0xc8, 0x30, 0x98, 0xe8, +0x06, 0xc4, 0x00, 0x65, +0xa0, 0x85, 0xc8, 0x20, +0x00, 0x0f, 0xa5, 0xc8, +0x10, 0x80, 0x0c, 0x88, +0xc0, 0x58, 0x8c, 0x05, +0x88, 0xc0, 0x58, 0x8c, +0x05, 0x88, 0x00, 0xfa, +0x80, 0x0f, 0xa8, 0x00, +0xfa, 0x80, 0x0f, 0xa8, +0x00, 0xfa, 0x80, 0x0f, +0xa8, 0x00, 0xfa, 0x84, +0x07, 0xa6, 0x80, 0x00, +0x4f, 0xba, 0x14, 0x60, +0xa4, 0x20, 0x6e, 0x08, +0x40, 0x61, 0x00, 0x00, +0x0b, 0xa1, 0x40, 0x6c, +0x00, 0x05, 0xa2, 0x08, +0x5c, 0x08, 0x2a, 0xbf, +0xf0, 0x25, 0x96, 0x0b, +0xc0, 0x88, 0x88, 0x07, +0x66, 0xc0, 0x00, 0x5a, +0x27, 0xa6, 0x80, 0x00, +0x4f, 0x32, 0x0b, 0xc4, +0x1f, 0x6c, 0x00, 0x05, +0xa0, 0x60, 0x68, 0x00, +0x02, 0xd6, 0x20, 0x5c, +0x82, 0x02, 0xc0, 0x21, +0x80, 0x02, 0x18, 0xc0, +0x30, 0x84, 0x80, 0x82, +0x09, 0x62, 0x28, 0x01, +0x08, 0xc2, 0xd8, 0x00, +0x00, 0x08, 0x40, 0x21, +0xa0, 0x0a, 0x08, 0x48, +0x08, 0x50, 0x4b, 0x10, +0xc0, 0x31, 0x28, 0x05, +0x28, 0xc0, 0x7a, 0xa0, +0x52, 0x08, 0x40, 0x08, +0x32, 0x02, 0x05, 0x53, +0xf2, 0xbc, 0x28, 0x98, +0x40, 0x49, 0x68, 0x00, +0x02, 0xd4, 0x20, 0x38, +0x00, 0xc8, 0x02, 0x89, +0x21, 0x16, 0x42, 0xa7, +0xe4, 0x84, 0x04, 0x8a, +0x00, 0xe0, 0x8c, 0x03, +0x15, 0x70, 0x20, 0x0c, +0x07, 0x85, 0x04, 0xa0, +0x20, 0x0c, 0x09, 0x83, +0x08, 0x80, 0x24, 0x80, +0x00, 0x00, 0x8c, 0x03, +0x05, 0x70, 0x08, 0x0c, +0x07, 0xa5, 0x04, 0xa0, +0x20, 0x06, 0x09, 0x83, +0x09, 0x84, 0x04, 0x9a, +0x05, 0xe0, 0x88, 0x0e, +0x06, 0x60, 0x00, 0x12, +0xfe, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x01, 0xff, +0xc8, 0x84, 0x00, 0x92, +0xa0, 0x6d, 0x30, 0x12, +0x8b, 0xc0, 0x5d, 0x84, +0x04, 0x96, 0x80, 0x00, +0x51, 0x02, 0x06, 0xc0, +0x00, 0x5a, 0x06, 0x00, +0x00, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0x6c, 0x00, 0x05, 0xa2, +0x08, 0x5c, 0x08, 0x32, +0xbf, 0xf0, 0x25, 0x9a, +0x0b, 0xc0, 0x88, 0x88, +0x07, 0x66, 0xc0, 0x00, +0x5a, 0x27, 0xa6, 0x80, +0x00, 0x4f, 0x32, 0x0b, +0xc1, 0x0f, 0x6c, 0x00, +0x05, 0xa0, 0x60, 0x68, +0x00, 0x02, 0xe8, 0x20, +0x00, 0x00, 0x0a, 0x00, +0x21, 0xa0, 0x82, 0x2a, +0x10, 0x23, 0x88, 0x0e, +0x36, 0x60, 0x00, 0x13, +0x28, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x05, 0x18, +0xa1, 0xa0, 0x76, 0x08, +0x40, 0x61, 0x00, 0x00, +0x08, 0x80, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x00, 0x05, +0xa2, 0x08, 0x5c, 0x08, +0x32, 0xbf, 0xf0, 0x25, +0x9a, 0x0b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, +0x00, 0x5a, 0x27, 0xa6, +0x80, 0x00, 0x4f, 0x32, +0x0b, 0xc0, 0xef, 0x6c, +0x00, 0x05, 0xa0, 0x60, +0x68, 0x00, 0x02, 0xe8, +0x20, 0x00, 0x00, 0x0a, +0x00, 0x21, 0x88, 0x0e, +0x16, 0x60, 0x00, 0x13, +0x66, 0x08, 0x80, 0xa0, +0x68, 0x00, 0x05, 0x20, +0xa1, 0xa0, 0x72, 0x08, +0x40, 0x61, 0x00, 0x00, +0x08, 0x80, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x00, 0x05, +0xa2, 0x09, 0x5c, 0x08, +0x22, 0xbf, 0xf0, 0x25, +0x92, 0x8b, 0xc0, 0x88, +0x88, 0x07, 0x66, 0xc0, +0x00, 0x5a, 0x27, 0xa6, +0x80, 0x00, 0x4f, 0x32, +0x0b, 0xc1, 0x1f, 0x6c, +0x00, 0x05, 0xa0, 0x60, +0x68, 0x20, 0x01, 0x2e, +0x20, 0x66, 0x00, 0x00, +0x79, 0x08, 0x6c, 0x00, +0x05, 0xdc, 0x09, 0x5c, +0x05, 0x2b, 0xa1, 0x11, +0x08, 0x10, 0x06, 0x80, +0x00, 0x52, 0x9a, 0x06, +0xc0, 0x00, 0x5a, 0x06, +0x06, 0xc0, 0x00, 0x5d, +0xc4, 0xc0, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, +0x48, 0x46, 0x08, 0x0a, +0x80, 0x10, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x05, 0xa2, 0x08, +0x5c, 0x08, 0x32, 0xbf, +0xf0, 0x25, 0x9a, 0x0b, +0xc0, 0x88, 0x88, 0x07, +0x66, 0xc0, 0x00, 0x5a, +0x27, 0xa6, 0x80, 0x00, +0x4f, 0x32, 0x2b, 0xc1, +0x0f, 0x6c, 0x00, 0x05, +0xa0, 0x62, 0x68, 0x00, +0x02, 0xe8, 0x22, 0x00, +0x00, 0x0a, 0x10, 0x23, +0x88, 0x0e, 0x3a, 0x10, +0x00, 0x66, 0x00, 0x00, +0x7e, 0x08, 0xa1, 0x80, +0x18, 0x80, 0xa2, 0x68, +0x00, 0x05, 0x32, 0x23, +0xa1, 0x72, 0x28, 0x50, +0x63, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x10, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x05, 0xa2, +0x08, 0x5c, 0x08, 0x32, +0xbf, 0xf0, 0x25, 0x9a, +0x0b, 0xc0, 0x88, 0x88, +0x07, 0x66, 0xc0, 0x00, +0x5a, 0x27, 0xa6, 0x80, +0x00, 0x4f, 0x32, 0x0b, +0xc0, 0xef, 0x6c, 0x00, +0x05, 0xa0, 0x60, 0x68, +0x00, 0x02, 0xe8, 0x20, +0x00, 0x00, 0x0a, 0x00, +0x21, 0x88, 0x0e, 0x16, +0x60, 0x00, 0x13, 0x74, +0x08, 0x80, 0xa0, 0x68, +0x00, 0x05, 0x3a, 0x21, +0xa0, 0x72, 0x08, 0x40, +0x61, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x10, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x05, 0xa2, +0x08, 0x5c, 0x08, 0x32, +0xbf, 0xf0, 0x25, 0x9a, +0x0b, 0xc0, 0x88, 0x88, +0x07, 0x66, 0xc0, 0x00, +0x5a, 0x27, 0xa6, 0x80, +0x00, 0x4f, 0x32, 0x0b, +0xc0, 0xef, 0x6c, 0x00, +0x05, 0xa0, 0x60, 0x68, +0x00, 0x02, 0xea, 0x20, +0x00, 0x00, 0x0a, 0x00, +0x21, 0x88, 0x0e, 0x16, +0x60, 0x00, 0x13, 0x82, +0x08, 0x80, 0xa0, 0x68, +0x00, 0x05, 0x42, 0x21, +0xa0, 0x76, 0x08, 0x40, +0x61, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x10, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x05, 0xa2, +0x09, 0x5c, 0x08, 0x22, +0xbf, 0xf0, 0x25, 0x92, +0x8b, 0xc0, 0x88, 0x88, +0x07, 0x66, 0xc0, 0x00, +0x5a, 0x27, 0xa6, 0x80, +0x00, 0x4f, 0x32, 0x0b, +0xc1, 0x1f, 0x6c, 0x00, +0x05, 0xa0, 0x60, 0x68, +0x20, 0x01, 0x2e, 0x20, +0x66, 0x00, 0x00, 0x79, +0x08, 0x6c, 0x00, 0x05, +0xe0, 0x09, 0x5c, 0x05, +0x2b, 0xa1, 0x11, 0x08, +0x10, 0x06, 0x80, 0x00, +0x54, 0xb2, 0x06, 0xc0, +0x00, 0x5a, 0x06, 0x06, +0xc0, 0x00, 0x5e, 0x04, +0xc0, 0x00, 0x00, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0x46, 0x08, 0x0a, 0x80, +0x10, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x00, +0x05, 0xa2, 0x08, 0x5c, +0x08, 0x32, 0xbf, 0xf0, +0x25, 0x9a, 0x0b, 0xc0, +0x88, 0x88, 0x07, 0x66, +0xc0, 0x00, 0x5a, 0x27, +0xa6, 0x80, 0x00, 0x4f, +0x32, 0x2b, 0xc1, 0x0f, +0x6c, 0x00, 0x05, 0xa0, +0x62, 0x68, 0x00, 0x02, +0xea, 0x22, 0x00, 0x00, +0x0a, 0x10, 0x23, 0x88, +0x0e, 0x3a, 0x10, 0x00, +0x66, 0x00, 0x00, 0x7e, +0x08, 0xa1, 0x80, 0x18, +0x80, 0xa2, 0x68, 0x00, +0x05, 0x53, 0xa3, 0xa1, +0x76, 0x28, 0x50, 0x63, +0x00, 0x00, 0x08, 0x80, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x10, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x05, 0xa2, 0x08, +0x5c, 0x08, 0x32, 0xbf, +0xf0, 0x25, 0x9a, 0x0b, +0xc0, 0x88, 0x88, 0x07, +0x66, 0xc0, 0x00, 0x5a, +0x27, 0xa6, 0x80, 0x00, +0x4f, 0x32, 0x0b, 0xc0, +0xef, 0x6c, 0x00, 0x05, +0xa0, 0x60, 0x68, 0x00, +0x02, 0xea, 0x20, 0x00, +0x00, 0x0a, 0x00, 0x21, +0x88, 0x0e, 0x16, 0x60, +0x00, 0x13, 0x90, 0x08, +0x80, 0xa0, 0x68, 0x00, +0x05, 0x5b, 0xa1, 0xa0, +0x76, 0x08, 0x40, 0x61, +0x00, 0x00, 0x08, 0x80, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x10, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x05, 0xa2, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x05, 0x9a, +0xbf, 0xf0, 0x88, 0x07, +0x66, 0x60, 0x00, 0x13, +0x9e, 0x08, 0x80, 0x36, +0x6c, 0x00, 0x05, 0xa2, +0x7a, 0x68, 0x00, 0x04, +0xf3, 0x20, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x5a, +0x06, 0x0a, 0x80, 0x10, +0x68, 0x38, 0x1c, 0x07, +0x21, 0x5c, 0xbc, 0x03, +0x00, 0x0e, 0x5c, 0x00, +0x80, 0x48, 0x7a, 0x9c, +0x80, 0x18, 0x48, 0x48, +0xa0, 0xc2, 0x18, 0x48, +0x7a, 0xa0, 0x84, 0x18, +0x48, 0x4a, 0xa0, 0xc8, +0x18, 0x48, 0x08, 0x46, +0x0a, 0x40, 0x40, 0x48, +0x84, 0xbd, 0x00, 0x00, +0x00, 0x68, 0x20, 0x00, +0xd7, 0x20, 0x38, 0x00, +0xc8, 0x40, 0x8a, 0x6c, +0x40, 0x04, 0x28, 0x48, +0x6c, 0x40, 0x01, 0x9a, +0x4a, 0x6c, 0x40, 0x02, +0xf8, 0x4a, 0x6c, 0x40, +0x02, 0xf2, 0x4a, 0x46, +0x0a, 0x40, 0x40, 0x7a, +0x6c, 0x40, 0x01, 0x98, +0x4a, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x00, +0x00, 0x90, 0x20, 0x5c, +0x81, 0x02, 0xbf, 0xc0, +0x5c, 0x00, 0x28, 0x00, +0x01, 0x5c, 0x08, 0x22, +0x00, 0xa1, 0x55, 0x01, +0x51, 0x48, 0x2f, 0x52, +0xc9, 0xc2, 0x0d, 0x41, +0x68, 0x00, 0x00, 0xe8, +0x24, 0x55, 0x01, 0x58, +0x40, 0x0a, 0x82, 0x20, +0x88, 0x82, 0xe1, 0x42, +0x04, 0x48, 0x83, 0x76, +0x55, 0x01, 0x60, 0x82, +0x48, 0x68, 0x00, 0x00, +0x88, 0x20, 0x6c, 0x00, +0x01, 0xca, 0x09, 0x84, +0x08, 0x28, 0x40, 0x03, +0x38, 0x10, 0x82, 0x58, +0x38, 0xbc, 0x09, 0x95, +0x50, 0x13, 0x98, 0x20, +0x06, 0x80, 0x00, 0x08, +0xa2, 0x06, 0xc0, 0x00, +0x1c, 0xc0, 0xb8, 0x40, +0x88, 0x40, 0x00, 0x00, +0x40, 0x00, 0x57, 0x02, +0xc8, 0x82, 0x03, 0x57, +0x0c, 0x92, 0x08, 0x00, +0x10, 0x80, 0x45, 0x70, +0x75, 0x9a, 0x00, 0x22, +0x81, 0xd8, 0x6c, 0x40, +0x01, 0x3e, 0x08, 0x44, +0x20, 0x81, 0x80, 0x09, +0x6c, 0x40, 0x03, 0x4a, +0x0b, 0x6e, 0x40, 0x01, +0x9d, 0x23, 0x6c, 0x40, +0x01, 0x6e, 0x08, 0x18, +0x28, 0x52, 0x00, 0xc9, +0x6c, 0x40, 0x02, 0x36, +0x09, 0x51, 0x8b, 0x48, +0x08, 0x41, 0x88, 0x26, +0x10, 0x00, 0x00, 0x6e, +0x40, 0x01, 0x9f, 0x24, +0x6c, 0x00, 0x01, 0x30, +0x0b, 0x20, 0x10, 0x06, +0xe4, 0x00, 0x3b, 0x12, +0x65, 0x80, 0x3c, 0x04, +0x84, 0x05, 0x00, 0xc8, +0x3c, 0x0d, 0xd8, 0x60, +0x40, 0x22, 0x96, 0xc2, +0xe1, 0x3c, 0x6c, 0x00, +0x01, 0x30, 0x48, 0x22, +0x96, 0x43, 0x01, 0x60, +0x40, 0x00, 0x03, 0xc0, +0x4c, 0x6c, 0x40, 0x01, +0xea, 0x48, 0x6c, 0x40, +0x01, 0xea, 0x49, 0x68, +0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x01, 0xb6, +0x40, 0x68, 0x00, 0x00, +0x7b, 0x20, 0x88, 0x2a, +0x18, 0x40, 0x48, 0x68, +0x20, 0x00, 0xb4, 0x24, +0x40, 0x00, 0x00, 0x82, +0x20, 0x66, 0x00, 0x01, +0xb6, 0x40, 0x68, 0x00, +0x00, 0x84, 0x20, 0x68, +0x00, 0x00, 0x7b, 0x21, +0x5c, 0x82, 0x00, 0x40, +0x48, 0x68, 0x00, 0x00, +0x62, 0x20, 0x80, 0x80, +0x98, 0x82, 0x61, 0x68, +0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x01, 0x8e, +0x20, 0x68, 0x20, 0x00, +0xdf, 0x2c, 0x5c, 0x87, +0x00, 0x82, 0x20, 0x68, +0x20, 0x02, 0x1b, 0x21, +0x88, 0x06, 0xc8, 0x02, +0x48, 0x88, 0x1e, 0x16, +0x82, 0x00, 0x0d, 0xc2, +0xc6, 0x82, 0x00, 0x0d, +0xe2, 0xd8, 0x82, 0x60, +0x68, 0x20, 0x00, 0x9c, +0x24, 0x68, 0x00, 0x00, +0x9a, 0x21, 0x68, 0x20, +0x00, 0xd3, 0x25, 0x88, +0x0e, 0xc8, 0x81, 0x6d, +0x66, 0x00, 0x01, 0x8f, +0xc8, 0x40, 0x00, 0x01, +0x82, 0x09, 0x5c, 0x82, +0x00, 0x82, 0x20, 0x68, +0x00, 0x00, 0x84, 0x21, +0x84, 0x34, 0x86, 0x80, +0x00, 0x06, 0xc2, 0x08, +0x08, 0x09, 0x40, 0x00, +0x00, 0x82, 0x61, 0x68, +0x20, 0x00, 0xb4, 0x24, +0x66, 0x00, 0x01, 0x8e, +0x20, 0x68, 0x20, 0x02, +0x1b, 0x21, 0x68, 0x20, +0x00, 0xdf, 0xac, 0x5c, +0x87, 0x00, 0x82, 0x20, +0xa0, 0x82, 0x18, 0x80, +0x6c, 0x80, 0x24, 0x88, +0x81, 0xe1, 0x68, 0x20, +0x00, 0xdd, 0x2c, 0x68, +0x20, 0x00, 0xde, 0xad, +0x88, 0x26, 0x06, 0x82, +0x00, 0x0b, 0x42, 0x46, +0x80, 0x00, 0x09, 0xc2, +0x16, 0x82, 0x00, 0x0d, +0x52, 0x58, 0x80, 0xec, +0x88, 0x16, 0xd6, 0x60, +0x00, 0x18, 0xfc, 0x89, +0x82, 0x09, 0x68, 0x20, +0x00, 0x9c, 0x21, 0x6c, +0x40, 0x03, 0xc2, 0x09, +0x84, 0xb8, 0xb5, 0x80, +0xbc, 0x08, 0x22, 0x16, +0xc4, 0x00, 0x3b, 0xa0, +0xbb, 0xc0, 0x69, 0x5c, +0x09, 0x30, 0x4b, 0x48, +0x52, 0x4d, 0xe3, 0xc0, +0x6f, 0x6c, 0x40, 0x03, +0xba, 0x48, 0x52, 0x0d, +0xe3, 0x80, 0x00, 0x6c, +0x40, 0x03, 0xba, 0x48, +0x68, 0x20, 0x00, 0xb4, +0x21, 0x6c, 0x40, 0x03, +0xba, 0x08, 0x84, 0xb8, +0xb3, 0x01, 0x78, 0xbc, +0x05, 0x93, 0x81, 0x2e, +0x52, 0x4d, 0x2b, 0xc0, +0x5f, 0x6c, 0x40, 0x03, +0xba, 0x49, 0x24, 0x1a, +0x56, 0xc4, 0x00, 0x3b, +0xa4, 0x93, 0x81, 0x35, +0x6c, 0x40, 0x01, 0xb8, +0x08, 0x6c, 0x40, 0x01, +0xda, 0x0a, 0x30, 0x1a, +0x0b, 0xc0, 0x69, 0x6c, +0x40, 0x03, 0xba, 0x08, +0x52, 0x4b, 0x2b, 0xc0, +0x5f, 0x6c, 0x40, 0x03, +0xba, 0x49, 0x24, 0x16, +0x56, 0xc4, 0x00, 0x3b, +0xa4, 0x93, 0x81, 0x3d, +0x6c, 0x40, 0x01, 0xba, +0x08, 0x30, 0x1a, 0x0b, +0xc0, 0x69, 0x6c, 0x40, +0x03, 0xba, 0x08, 0x52, +0x4b, 0x2b, 0xc0, 0x6f, +0x6c, 0x40, 0x03, 0xba, +0x49, 0x52, 0x0b, 0x2b, +0x80, 0x00, 0x6c, 0x40, +0x03, 0xba, 0x49, 0x68, +0x00, 0x06, 0x27, 0xa1, +0x88, 0x33, 0x6b, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0x2e, 0x61, 0x40, 0x00, +0x02, 0x80, 0x40, 0xab, +0xfb, 0x06, 0x82, 0x00, +0x1c, 0x22, 0xc8, 0x81, +0x76, 0x68, 0x20, 0x00, +0x9c, 0x24, 0x68, 0x20, +0x00, 0xce, 0x25, 0x68, +0x00, 0x00, 0xe9, 0x20, +0x40, 0x00, 0x00, 0x80, +0x6c, 0x66, 0x00, 0x01, +0xa2, 0xa8, 0x6c, 0x00, +0x00, 0xf8, 0x09, 0x68, +0x20, 0x01, 0xc4, 0x2c, +0x6c, 0x00, 0x01, 0xd2, +0x48, 0x68, 0x20, 0x00, +0xb4, 0x24, 0x68, 0x20, +0x00, 0xcf, 0x25, 0x68, +0x00, 0x00, 0xeb, 0x20, +0x40, 0x00, 0x00, 0x80, +0x6c, 0x66, 0x00, 0x01, +0xa2, 0xa8, 0x6c, 0x00, +0x01, 0x0a, 0x09, 0x6c, +0x00, 0x01, 0xd6, 0x48, +0x68, 0x00, 0x00, 0x76, +0x20, 0x68, 0x00, 0x00, +0x62, 0x21, 0x68, 0x20, +0x00, 0x9c, 0x24, 0x66, +0x00, 0x01, 0xa4, 0x08, +0x6c, 0x00, 0x01, 0xd2, +0x09, 0x68, 0x00, 0x00, +0x76, 0x20, 0x68, 0x00, +0x00, 0x6c, 0x21, 0xa0, +0x02, 0x08, 0x40, 0x48, +0x40, 0x00, 0x00, 0x81, +0xe0, 0x68, 0x00, 0x00, +0x7f, 0x20, 0x68, 0x20, +0x00, 0xb4, 0x24, 0x66, +0x00, 0x01, 0xa4, 0x08, +0x6c, 0x00, 0x01, 0xd6, +0x09, 0x68, 0x00, 0x00, +0x7f, 0x20, 0x5c, 0x81, +0x00, 0x81, 0xa4, 0xa0, +0x02, 0x08, 0x20, 0x09, +0x84, 0x04, 0x88, 0x82, +0x60, 0x88, 0x2e, 0x46, +0x82, 0x00, 0x0d, 0xc2, +0xc6, 0x80, 0x00, 0x06, +0x22, 0x06, 0x82, 0x00, +0x09, 0xc2, 0x46, 0x82, +0x00, 0x0c, 0xe2, 0x58, +0x80, 0x6c, 0x66, 0x00, +0x01, 0x8e, 0x60, 0x5c, +0x81, 0x00, 0x82, 0x20, +0x88, 0x1a, 0x48, 0x00, +0x09, 0x86, 0x0c, 0x88, +0x83, 0x60, 0x68, 0x20, +0x00, 0xdd, 0x2c, 0x68, +0x00, 0x00, 0x6c, 0x20, +0x68, 0x20, 0x00, 0xb4, +0x24, 0x68, 0x20, 0x00, +0xcf, 0x25, 0x40, 0x00, +0x00, 0x80, 0x6c, 0x66, +0x00, 0x01, 0x8e, 0x60, +0x68, 0x20, 0x00, 0x9c, +0x24, 0x6c, 0x40, 0x02, +0xb4, 0x09, 0x86, 0x60, +0x35, 0x80, 0xac, 0x08, +0x22, 0x06, 0xc4, 0x00, +0x3b, 0xa0, 0x3b, 0xc0, +0x6a, 0x5c, 0x08, 0x10, +0x40, 0xc8, 0x52, 0x44, +0xe3, 0xc0, 0x6f, 0x6c, +0x40, 0x03, 0xba, 0x48, +0x52, 0x04, 0xe3, 0x80, +0x00, 0x6c, 0x40, 0x03, +0xba, 0x48, 0x68, 0x20, +0x00, 0xb4, 0x20, 0x6c, +0x40, 0x03, 0xba, 0x08, +0x84, 0x60, 0x33, 0x01, +0x58, 0xbc, 0x05, 0xa3, +0x81, 0x0a, 0x52, 0x45, +0x23, 0xc0, 0x6f, 0x6c, +0x40, 0x03, 0xba, 0x48, +0x52, 0x05, 0x23, 0x80, +0x00, 0x6c, 0x40, 0x03, +0xba, 0x48, 0x68, 0x00, +0x00, 0x62, 0x20, 0x88, +0x1a, 0x16, 0x82, 0x00, +0x0d, 0xe2, 0x56, 0x60, +0x00, 0x1a, 0x74, 0x88, +0x48, 0x89, 0x88, 0x22, +0x06, 0x80, 0x00, 0x09, +0x22, 0x48, 0x40, 0x89, +0x40, 0x00, 0x00, 0x60, +0x48, 0x68, 0x00, 0x00, +0x6c, 0x20, 0x68, 0x20, +0x00, 0xb4, 0x24, 0x68, +0x20, 0x00, 0xde, 0xa5, +0x66, 0x00, 0x01, 0xa7, +0x40, 0x68, 0x00, 0x00, +0x92, 0x23, 0x68, 0x20, +0x01, 0x03, 0x24, 0x5c, +0x81, 0x02, 0x18, 0x02, +0xc6, 0x08, 0x06, 0xc4, +0x00, 0x1a, 0xe0, 0x95, +0x90, 0x38, 0x08, 0x26, +0x48, 0x83, 0xe3, 0x88, +0x45, 0x04, 0x20, 0x4c, +0x08, 0x1c, 0x88, 0x58, +0x48, 0x3a, 0x14, 0x42, +0x30, 0xa4, 0x68, 0x20, +0x00, 0xd8, 0x20, 0x98, +0x22, 0x84, 0x20, 0x2f, +0x9c, 0x00, 0x08, 0x40, +0x02, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x02, 0x0c, 0x02, 0x68, +0x20, 0x00, 0xcd, 0x21, +0x32, 0x0a, 0x86, 0x82, +0x00, 0x0c, 0xc2, 0x04, +0x20, 0xbd, 0x04, 0x85, +0x28, 0x40, 0x52, 0x5b, +0x04, 0x29, 0x8e, 0x88, +0x88, 0x40, 0x35, 0x78, +0x4f, 0x08, 0x18, 0x32, +0xe9, 0x76, 0x2f, 0x09, +0xb2, 0xe9, 0x5d, 0x5b, +0x4c, 0x28, 0x58, 0x49, +0x30, 0x8a, 0x8b, 0xc0, +0x88, 0x6c, 0x00, 0x01, +0x24, 0x4a, 0x00, 0x00, +0x06, 0xc0, 0x00, 0x12, +0x60, 0x93, 0x69, 0x45, +0x30, 0x8a, 0x8b, 0xc0, +0x41, 0xb0, 0x00, 0xcb, +0xc0, 0x27, 0x66, 0x00, +0x01, 0xaf, 0x00, 0x68, +0x00, 0x00, 0x92, 0x20, +0x38, 0x12, 0xda, 0x00, +0x84, 0x96, 0x02, 0xa6, +0x82, 0x00, 0x0a, 0x82, +0x16, 0xc4, 0x00, 0x2b, +0x40, 0x36, 0xc4, 0x00, +0x2d, 0x40, 0xa2, 0x59, +0x50, 0xbc, 0x0a, 0x88, +0x84, 0xe4, 0x6c, 0x40, +0x01, 0x50, 0x53, 0x6c, +0x40, 0x01, 0x80, 0x53, +0x68, 0x20, 0x00, 0xc0, +0x24, 0x42, 0x09, 0x78, +0x48, 0xca, 0x86, 0x0c, +0xa3, 0x20, 0x20, 0xbc, +0x0b, 0x06, 0xc4, 0x00, +0x15, 0x00, 0x86, 0xc4, +0x00, 0x2b, 0x60, 0x93, +0x01, 0x60, 0x40, 0x00, +0x03, 0xc0, 0x45, 0x6c, +0x40, 0x01, 0x50, 0x49, +0x6c, 0x40, 0x01, 0x80, +0x49, 0x6c, 0x40, 0x01, +0x82, 0x4a, 0x6c, 0x40, +0x01, 0x52, 0x4a, 0x00, +0x00, 0x06, 0xc0, 0x00, +0x12, 0x40, 0x95, 0xb4, +0xa1, 0x08, 0x40, 0x33, +0x68, 0xc3, 0x30, 0x89, +0x86, 0xc4, 0x00, 0x3b, +0xa0, 0xab, 0xc0, 0x5c, +0x38, 0x11, 0x45, 0x24, +0x9a, 0x3c, 0x05, 0xf6, +0xc4, 0x00, 0x3b, 0xa4, +0x82, 0x41, 0x34, 0x6c, +0x40, 0x03, 0xba, 0x48, +0x38, 0x11, 0xc8, 0x83, +0xa1, 0x88, 0x18, 0x25, +0xb4, 0x41, 0x84, 0x80, +0x23, 0x68, 0x86, 0x30, +0x99, 0x8b, 0xc0, 0x6c, +0x6c, 0x40, 0x03, 0xba, +0x03, 0x52, 0x48, 0xe3, +0xc0, 0x6f, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x52, +0x08, 0xe3, 0x80, 0x00, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x68, 0x00, 0x00, +0x6c, 0x23, 0x68, 0x00, +0x00, 0x62, 0x24, 0x88, +0x22, 0x58, 0x5a, 0xd2, +0x86, 0x2c, 0x96, 0x60, +0x00, 0x1a, 0x8c, 0x88, +0x68, 0x08, 0x88, 0x3a, +0x16, 0x82, 0x00, 0x1b, +0xa2, 0x46, 0x80, 0x00, +0x09, 0x22, 0x06, 0x60, +0x00, 0x1b, 0x64, 0x08, +0x83, 0xa0, 0x88, 0x1c, +0x86, 0x82, 0x00, 0x1b, +0xc2, 0x46, 0x80, 0x00, +0x09, 0x22, 0x16, 0x60, +0x00, 0x1b, 0x64, 0x08, +0x81, 0x89, 0x88, 0x1c, +0x86, 0x82, 0x00, 0x09, +0xc2, 0x46, 0x82, 0x00, +0x0c, 0xe2, 0x56, 0x60, +0x00, 0x1a, 0x82, 0x08, +0x82, 0xa0, 0x68, 0x20, +0x00, 0xb4, 0x24, 0x84, +0x34, 0x86, 0x82, 0x00, +0x0c, 0xf2, 0x56, 0x60, +0x00, 0x1a, 0x82, 0x88, +0x81, 0x89, 0x5c, 0x08, +0xa8, 0x84, 0xa0, 0x88, +0x32, 0x49, 0x40, 0x2a, +0x25, 0x95, 0x0b, 0xc0, +0x58, 0x86, 0x34, 0x86, +0xc0, 0x00, 0x0f, 0xc7, +0xa6, 0xc0, 0x00, 0x10, +0xe7, 0xa3, 0x81, 0x34, +0x25, 0x91, 0x0b, 0xc0, +0xe0, 0x68, 0x00, 0x00, +0xcf, 0x20, 0x6c, 0x40, +0x01, 0xda, 0x08, 0x5c, +0x81, 0x01, 0x8e, 0x89, +0x40, 0x00, 0x01, 0x42, +0x45, 0x6c, 0x40, 0x01, +0x5a, 0x48, 0x6c, 0x40, +0x01, 0x8a, 0x48, 0x42, +0x1d, 0x38, 0x40, 0x7a, +0x68, 0x00, 0x00, 0x7a, +0x20, 0x68, 0x00, 0x00, +0x83, 0x21, 0x66, 0x00, +0x01, 0xef, 0xc0, 0x6e, +0x00, 0x01, 0x9e, 0x24, +0x32, 0x06, 0x0b, 0xc0, +0x60, 0x6c, 0x00, 0x01, +0x32, 0x08, 0x38, 0x19, +0xd2, 0x89, 0x64, 0x30, +0x16, 0x0b, 0xc1, 0xa0, +0x68, 0x20, 0x00, 0xf0, +0x21, 0x68, 0x20, 0x00, +0xad, 0x20, 0xa0, 0xc2, +0x28, 0x81, 0xe2, 0x66, +0x00, 0x01, 0xf9, 0x60, +0x88, 0x1a, 0x26, 0x82, +0x00, 0x0c, 0x52, 0x06, +0x82, 0x00, 0x0f, 0x02, +0x16, 0x60, 0x00, 0x1f, +0x96, 0x08, 0x81, 0xa0, +0x6c, 0x40, 0x02, 0x36, +0x08, 0x84, 0x30, 0x93, +0x01, 0x28, 0xbc, 0x15, +0x16, 0xc0, 0x00, 0x61, +0x67, 0xa6, 0xc0, 0x00, +0x61, 0x87, 0xab, 0xc1, +0x07, 0x68, 0x20, 0x00, +0xad, 0x20, 0x68, 0x20, +0x00, 0xf1, 0x21, 0x68, +0x20, 0x00, 0xee, 0x22, +0x66, 0x00, 0x01, 0xf9, +0x60, 0x68, 0x20, 0x00, +0xee, 0x22, 0x68, 0x20, +0x00, 0xc5, 0x20, 0x66, +0x00, 0x01, 0xf9, 0x68, +0x40, 0x00, 0x02, 0x10, +0x61, 0x6e, 0x00, 0x01, +0x9e, 0x24, 0x32, 0x06, +0x0b, 0xc4, 0x80, 0x6c, +0x00, 0x01, 0x32, 0x08, +0x2a, 0x8e, 0x53, 0x20, +0xe8, 0xbc, 0x1e, 0x06, +0xc0, 0x00, 0x0f, 0x80, +0x96, 0xc4, 0x00, 0x1e, +0xe0, 0x22, 0x80, 0xae, +0x32, 0x03, 0x0b, 0xc0, +0x4b, 0x38, 0x10, 0x32, +0x40, 0xe4, 0x6c, 0x00, +0x01, 0x32, 0x48, 0x2e, +0x0a, 0xd3, 0x20, 0x28, +0xbc, 0x07, 0xd3, 0x81, +0x0c, 0x6c, 0x00, 0x01, +0x32, 0x09, 0x24, 0x12, +0xc6, 0xc0, 0x00, 0x13, +0x24, 0x80, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x32, +0x08, 0x2a, 0x8e, 0x43, +0x20, 0xe0, 0xbc, 0x04, +0x16, 0xc4, 0x00, 0x1d, +0xa0, 0x86, 0xc4, 0x00, +0x15, 0xa4, 0x83, 0x81, +0x85, 0x6c, 0x00, 0x01, +0x32, 0x08, 0x28, 0x96, +0x23, 0x01, 0x50, 0xbc, +0x1f, 0x06, 0xc0, 0x00, +0x10, 0xa0, 0x26, 0xc4, +0x00, 0x1e, 0xe0, 0x32, +0x80, 0xd6, 0x32, 0x03, +0x0b, 0xc0, 0x43, 0x38, +0x12, 0x62, 0x41, 0xa4, +0x6c, 0x00, 0x01, 0x32, +0x48, 0x2e, 0x0d, 0x23, +0x20, 0x10, 0xbc, 0x07, +0xd3, 0x81, 0x2c, 0x6c, +0x00, 0x01, 0x32, 0x02, +0x24, 0x11, 0x46, 0xc0, +0x00, 0x13, 0x24, 0x80, +0x00, 0x00, 0x6c, 0x00, +0x01, 0x32, 0x08, 0x28, +0x96, 0x43, 0x01, 0x60, +0x40, 0x00, 0x03, 0xc0, +0x41, 0x6c, 0x40, 0x01, +0xda, 0x08, 0x6c, 0x40, +0x01, 0x8a, 0x48, 0x68, +0x00, 0x06, 0x35, 0xa0, +0x88, 0x13, 0x6b, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0x2e, 0x60, 0x40, 0x00, +0x02, 0x80, 0x50, 0x68, +0x00, 0x00, 0xe1, 0x20, +0x6c, 0x00, 0x01, 0xce, +0x09, 0x84, 0x04, 0x9a, +0xbf, 0xd0, 0xa0, 0x04, +0x08, 0x82, 0x60, 0x88, +0x2f, 0x66, 0x80, 0x00, +0x0d, 0x02, 0x06, 0x82, +0x00, 0x1a, 0x22, 0x46, +0x60, 0x00, 0x18, 0xe2, +0x08, 0x82, 0x20, 0x68, +0x20, 0x02, 0x20, 0x2c, +0x84, 0x04, 0x88, 0x80, +0x6c, 0xa0, 0x4e, 0x06, +0x82, 0x00, 0x22, 0x12, +0xc6, 0x82, 0x00, 0x22, +0x0a, 0x26, 0x82, 0x00, +0x21, 0xd2, 0xd8, 0x82, +0x60, 0x68, 0x20, 0x01, +0xa2, 0x24, 0x68, 0x00, +0x00, 0xda, 0x21, 0x68, +0x20, 0x02, 0x1e, 0x25, +0x88, 0x0e, 0xc8, 0x81, +0x62, 0x88, 0x1e, 0xd6, +0x60, 0x00, 0x18, 0xfc, +0x89, 0x82, 0x09, 0x68, +0x00, 0x06, 0x34, 0x24, +0x88, 0x22, 0x08, 0x82, +0xb6, 0x6c, 0x00, 0x01, +0x2e, 0x64, 0xba, 0x14, +0x88, 0x43, 0x48, 0x40, +0x00, 0x02, 0x80, 0x30, +0x68, 0x00, 0x05, 0xa9, +0xa0, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x12, 0xe6, +0x00, 0x00, 0x00, 0x68, +0x00, 0x06, 0x37, 0x20, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x12, 0xe6, 0x00, +0x00, 0x00, 0x68, 0x00, +0x05, 0x69, 0x20, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x12, 0xe6, 0x00, 0x00, +0x00, 0xa2, 0x28, 0x46, +0x40, 0x00, 0x03, 0x1c, +0xfa, 0x01, 0x00, 0xab, +0xfe, 0x0a, 0x20, 0x84, +0x88, 0x06, 0x48, 0x80, +0xe5, 0x88, 0x17, 0x66, +0x60, 0x00, 0x03, 0x2a, +0x08, 0x80, 0xa0, 0x88, +0x22, 0x49, 0x40, 0x25, +0x50, 0x0b, 0x00, 0x60, +0x09, 0x98, 0x00, 0x84, +0x40, 0x80, 0x08, 0x02, +0x08, 0x81, 0x36, 0x84, +0x68, 0x94, 0x60, 0xa4, +0x18, 0x00, 0x84, 0x40, +0x80, 0x28, 0x02, 0x09, +0x80, 0x08, 0xab, 0xfd, +0x08, 0x81, 0xe4, 0x88, +0x04, 0x98, 0x80, 0xe5, +0x88, 0x16, 0x18, 0x82, +0x60, 0x88, 0x2f, 0x66, +0x82, 0x00, 0x0d, 0x02, +0x46, 0x60, 0x00, 0x03, +0x1c, 0x8a, 0x08, 0x00, +0x5c, 0x83, 0x00, 0x82, +0x21, 0x6c, 0x40, 0x01, +0xae, 0x09, 0x5d, 0x0a, +0x2a, 0x08, 0x07, 0x51, +0x85, 0x68, 0x83, 0x26, +0x80, 0x80, 0xa5, 0x70, +0xd0, 0x08, 0x1a, 0x46, +0x82, 0x00, 0x11, 0xd2, +0x08, 0x48, 0x48, 0x98, +0x26, 0x99, 0x70, 0x2f, +0x59, 0x03, 0xc2, 0x20, +0x82, 0x9c, 0x08, 0x1a, +0x10, 0x64, 0x98, 0x00, +0x24, 0x20, 0x4c, 0x04, +0x80, 0x95, 0x50, 0x14, +0xa3, 0x8c, 0x08, 0x51, +0x89, 0x6c, 0x40, 0x03, +0xc2, 0x08, 0x30, 0x12, +0x8b, 0xc0, 0x28, 0x2a, +0x00, 0xd2, 0x30, 0x4d, +0x5b, 0x44, 0x20, 0x84, +0x21, 0x58, 0x4b, 0x00, +0x80, 0xa5, 0x6c, 0x40, +0x01, 0xda, 0x08, 0x94, +0x83, 0x84, 0x20, 0x45, +0x21, 0x0a, 0x38, 0x02, +0x09, 0x6e, 0x00, 0x01, +0x2c, 0x2b, 0x5c, 0x09, +0x68, 0x80, 0xc9, 0x25, +0x95, 0x8b, 0xc7, 0x38, +0x88, 0x08, 0x93, 0x20, +0x78, 0xbc, 0x14, 0x98, +0x68, 0x7a, 0x00, 0x00, +0x08, 0x7b, 0x8b, 0x88, +0x12, 0x70, 0x00, 0x00, +0x87, 0x88, 0x23, 0x01, +0x90, 0xbc, 0x06, 0x33, +0x01, 0xf0, 0xbc, 0x0c, +0x49, 0x8e, 0x8b, 0x87, +0x8c, 0xa9, 0x70, 0x67, +0xbc, 0x08, 0x73, 0x01, +0xf0, 0xbc, 0x06, 0xa9, +0x8e, 0x8b, 0x87, 0x8c, +0xa9, 0x70, 0x67, 0xbc, +0x02, 0x70, 0x00, 0x00, +0x88, 0x12, 0x78, 0x51, +0x82, 0x6c, 0x40, 0x03, +0xc2, 0x0b, 0x30, 0x1d, +0x0b, 0xc2, 0x48, 0x39, +0x0a, 0x26, 0x82, 0x00, +0x1e, 0x62, 0x65, 0xc8, +0x10, 0x85, 0x28, 0x15, +0xc8, 0x21, 0x83, 0x08, +0x35, 0x90, 0x0c, 0x03, +0x30, 0x25, 0x70, 0x65, +0x87, 0x00, 0x1a, 0x18, +0x06, 0x81, 0xbd, 0x30, +0x00, 0x00, 0x85, 0x80, +0x32, 0xe0, 0x9a, 0x85, +0x85, 0x2b, 0xc0, 0x6c, +0x85, 0x28, 0x23, 0x00, +0x50, 0xbc, 0x08, 0x28, +0x51, 0xcb, 0x86, 0x15, +0x1b, 0xc0, 0x57, 0x30, +0x05, 0x0b, 0xc0, 0x34, +0x85, 0x1c, 0xb8, 0x61, +0x51, 0x00, 0x00, 0x08, +0x58, 0x0b, 0x57, 0x0f, +0x10, 0x32, 0x8b, 0x57, +0x0e, 0x90, 0x83, 0xa4, +0xbc, 0x03, 0xf8, 0x70, +0x42, 0x88, 0x3a, 0x40, +0x00, 0x00, 0x00, 0x00, +0x08, 0x60, 0x0b, 0x30, +0x13, 0x8b, 0xc0, 0xb3, +0x6c, 0x40, 0x02, 0x10, +0x02, 0x28, 0x0b, 0xf3, +0x09, 0x38, 0xbc, 0x03, +0x4b, 0xc0, 0x6f, 0x5c, +0x0b, 0xe0, 0x60, 0x4b, +0xbc, 0x03, 0xf5, 0xc0, +0xbe, 0x06, 0x04, 0x83, +0x81, 0x7c, 0x25, 0x90, +0x0b, 0xc5, 0x71, 0x38, +0x16, 0x72, 0x59, 0xc0, +0xbc, 0x0d, 0x93, 0x81, +0x74, 0x25, 0x90, 0x0b, +0xc0, 0x39, 0x98, 0xe8, +0x83, 0x20, 0x28, 0xbc, +0x05, 0x43, 0x81, 0x77, +0x25, 0x9c, 0x0b, 0xc4, +0xb0, 0x32, 0x02, 0x8b, +0xc4, 0x93, 0x94, 0x87, +0x4b, 0xc4, 0x77, 0x25, +0x90, 0x0b, 0xc0, 0x39, +0x38, 0x16, 0x43, 0x20, +0x28, 0xbc, 0x05, 0x23, +0x81, 0x77, 0x25, 0x9c, +0x0b, 0xc3, 0xf0, 0x32, +0x02, 0x8b, 0xc3, 0xd5, +0x24, 0x10, 0x09, 0x48, +0x70, 0xbc, 0x3a, 0x73, +0x20, 0x10, 0xbc, 0x04, +0xc8, 0x81, 0x27, 0x57, +0x03, 0x93, 0xc0, 0x3f, +0x87, 0x8c, 0x22, 0x81, +0x8a, 0x87, 0x8c, 0x2b, +0x00, 0x0f, 0x86, 0x80, +0x23, 0x01, 0x10, 0xbc, +0x03, 0xb9, 0x70, 0x67, +0x2a, 0x05, 0x78, 0x68, +0x4b, 0x68, 0x20, 0x01, +0xe3, 0x23, 0x5c, 0x81, +0x13, 0x01, 0x7f, 0x5c, +0x82, 0x08, 0x19, 0x02, +0x52, 0xce, 0x00, 0x21, +0x52, 0x68, 0x20, 0x01, +0x09, 0x22, 0x85, 0x80, +0x18, 0x58, 0x83, 0x86, +0x05, 0x18, 0x60, 0xd3, +0x00, 0x00, 0x08, 0x83, +0xa6, 0x42, 0x06, 0xc0, +0x12, 0x82, 0x5c, 0x00, +0x00, 0x70, 0x52, 0x24, +0x1c, 0x03, 0x20, 0x28, +0x5d, 0x40, 0x03, 0xc0, +0x5c, 0x5c, 0x0b, 0xb9, +0x48, 0x70, 0x52, 0x4e, +0x03, 0xc0, 0x3f, 0x94, +0x87, 0x02, 0x41, 0xc0, +0x94, 0x87, 0x00, 0x00, +0x00, 0x6c, 0x40, 0x01, +0x50, 0x0b, 0x6c, 0x40, +0x02, 0xc4, 0x00, 0x30, +0x03, 0x8b, 0xc0, 0x5d, +0x85, 0x04, 0x86, 0xc4, +0x00, 0x15, 0x05, 0x06, +0xc4, 0x00, 0x18, 0x05, +0x00, 0x00, 0x00, 0x87, +0x88, 0xb8, 0x02, 0x4b, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x1a, 0xae, 0x88, +0x68, 0x00, 0x6c, 0x40, +0x01, 0xea, 0x09, 0x6c, +0x40, 0x02, 0x36, 0x0a, +0x58, 0x0d, 0x40, 0x80, +0xa0, 0x42, 0x04, 0x40, +0x84, 0xa4, 0x5c, 0x09, +0x70, 0x40, 0x48, 0x00, +0x00, 0x08, 0x82, 0x21, +0x00, 0x00, 0x08, 0x48, +0x09, 0x42, 0x13, 0xb8, +0x60, 0x49, 0x00, 0x00, +0x06, 0xe0, 0x00, 0x12, +0xc2, 0xc5, 0x2c, 0xd0, +0x08, 0x22, 0x1b, 0xc0, +0xf9, 0x86, 0x00, 0xa6, +0xc4, 0x00, 0x43, 0x40, +0x85, 0x40, 0x98, 0x04, +0x80, 0xb9, 0x80, 0x00, +0x30, 0x03, 0x8b, 0xc0, +0x15, 0x84, 0x85, 0x02, +0xe1, 0x30, 0x84, 0x80, +0x89, 0x80, 0x0b, 0x30, +0x1e, 0x0b, 0xc0, 0x13, +0x84, 0x84, 0xb0, 0x00, +0x00, 0x86, 0x00, 0x88, +0x48, 0x0b, 0x30, 0x13, +0x86, 0xc4, 0x00, 0x22, +0xa0, 0x0b, 0xc0, 0x3b, +0x20, 0x82, 0xd2, 0xe1, +0x70, 0x86, 0x04, 0x00, +0x00, 0x00, 0x84, 0x80, +0x88, 0x60, 0x0b, 0x30, +0x1e, 0x0b, 0xc0, 0x35, +0x28, 0x17, 0x08, 0x60, +0x40, 0x00, 0x00, 0x08, +0x82, 0xb6, 0x84, 0x00, +0xa4, 0x60, 0xa4, 0x08, +0x00, 0x95, 0x70, 0xd4, +0x28, 0x03, 0x09, 0x80, +0x08, 0x5c, 0x09, 0xe2, +0x22, 0xe4, 0x86, 0x00, +0xa4, 0x43, 0x00, 0x16, +0x9a, 0x55, 0x00, 0xa0, +0x08, 0x02, 0x56, 0xe0, +0x00, 0x12, 0xc2, 0xd5, +0x2c, 0x94, 0x06, 0x80, +0x94, 0x20, 0x24, 0x18, +0x00, 0x80, 0x81, 0x00, +0xba, 0x14, 0x89, 0x80, +0x08, 0x00, 0x00, 0x08, +0x40, 0x89, 0x46, 0x0a, +0x40, 0x68, 0x88, 0x08, +0x48, 0x09, 0x80, 0x08, +0xab, 0xfd, 0x0a, 0x21, +0x64, 0xa0, 0x88, 0x18, +0x80, 0x61, 0x88, 0x0e, +0x4a, 0x20, 0x64, 0xa0, +0x84, 0x18, 0x81, 0x49, +0x88, 0x1e, 0x08, 0x82, +0x76, 0x66, 0x00, 0x00, +0x31, 0xc8, 0xa0, 0x80, +0x08, 0x80, 0x24, 0x6e, +0x00, 0x01, 0x9e, 0x25, +0x59, 0x03, 0x40, 0x81, +0xa1, 0x42, 0x05, 0xc2, +0x20, 0x20, 0x84, 0xa4, +0x80, 0x00, 0x00, 0x6c, +0x40, 0x02, 0xb4, 0x09, +0x88, 0x0a, 0x46, 0x60, +0x00, 0x1e, 0xea, 0x88, +0x60, 0x8a, 0x88, 0x0a, +0x0b, 0xc1, 0x1f, 0x84, +0x0c, 0x80, 0x00, 0x00, +0x86, 0x08, 0x96, 0xc4, +0x00, 0x1f, 0x00, 0x83, +0x69, 0x45, 0x30, 0x96, +0x0b, 0xc0, 0x54, 0x6c, +0x40, 0x02, 0xb6, 0x09, +0x88, 0x0a, 0x0b, 0xc0, +0x5f, 0x84, 0x0c, 0x98, +0x80, 0xa0, 0x6c, 0x40, +0x01, 0xda, 0x09, 0x84, +0x0c, 0x90, 0x00, 0x00, +0x88, 0x23, 0x6b, 0xa1, +0x48, 0x88, 0x10, 0x8a, +0x80, 0x30, 0x5c, 0x81, +0x02, 0x00, 0x80, 0xa2, +0x16, 0x48, 0x20, 0x0a, +0x84, 0x00, 0x84, 0x41, +0x00, 0x02, 0x00, 0xa8, +0x40, 0x88, 0x44, 0x14, +0x00, 0x60, 0x08, 0xba, +0x14, 0x84, 0x42, 0x40, +0x04, 0x04, 0x99, 0x80, +0x08, 0xa2, 0x24, 0x48, +0x60, 0x08, 0x44, 0x20, +0x00, 0x60, 0x89, 0x98, +0x00, 0x84, 0x40, 0x80, +0x16, 0x8a, 0x5b, 0xa1, +0x48, 0x20, 0x14, 0x09, +0x80, 0x08, 0x6c, 0x40, +0x02, 0x06, 0x0a, 0x32, +0x07, 0x0b, 0xc1, 0xc1, +0x84, 0x00, 0x93, 0x01, +0x28, 0xbc, 0x08, 0xc3, +0x61, 0x06, 0x30, 0x1a, +0x8b, 0xc0, 0x22, 0x42, +0x03, 0x38, 0x40, 0x7a, +0x28, 0x12, 0x84, 0x20, +0x1b, 0x84, 0x04, 0x02, +0xe1, 0x28, 0x84, 0x04, +0x00, 0x00, 0x00, 0x84, +0x80, 0x93, 0x01, 0x28, +0xbc, 0x09, 0x43, 0x01, +0xa8, 0xbc, 0x03, 0x2b, +0xa1, 0x48, 0x84, 0x87, +0xa0, 0x00, 0x00, 0x54, +0x09, 0x43, 0xa1, 0x48, +0x84, 0x84, 0x00, 0x00, +0x00, 0x2e, 0x12, 0x88, +0x48, 0x40, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x6e, +0x00, 0x01, 0x9e, 0x22, +0x6c, 0x40, 0x01, 0xea, +0x03, 0x32, 0x01, 0x0b, +0xc0, 0xa9, 0x55, 0x01, +0xca, 0xbf, 0xf0, 0x6c, +0x40, 0x02, 0x36, 0x08, +0x30, 0x11, 0x8b, 0xc0, +0x41, 0x6c, 0x00, 0x06, +0x16, 0x08, 0x30, 0x0e, +0x0b, 0xc0, 0xa2, 0x6c, +0x40, 0x02, 0x36, 0x08, +0x30, 0x11, 0x8b, 0xc0, +0x48, 0x98, 0xe8, 0x8b, +0x17, 0x7f, 0x30, 0x1c, +0x0b, 0xc1, 0x54, 0x2a, +0x01, 0xcb, 0xc1, 0x37, +0x6c, 0x00, 0x06, 0x16, +0x08, 0x30, 0x0e, 0x0b, +0xc0, 0xc3, 0x6c, 0x00, +0x06, 0x18, 0x0b, 0x2a, +0x07, 0xf3, 0x22, 0xf8, +0xbc, 0x07, 0xd6, 0xc0, +0x00, 0x61, 0x84, 0xb2, +0xa0, 0x64, 0x6c, 0x00, +0x06, 0x16, 0x48, 0x6c, +0x00, 0x06, 0x18, 0x7a, +0x00, 0x00, 0x06, 0xc0, +0x00, 0x61, 0x60, 0x83, +0x20, 0x50, 0x48, 0xb3, +0xa3, 0xc0, 0x98, 0x9a, +0x04, 0x13, 0x01, 0x88, +0xbc, 0x0c, 0xc8, 0x80, +0x4b, 0x30, 0x18, 0x8b, +0xc0, 0x9b, 0x98, 0x28, +0x88, 0x80, 0x08, 0xbc, +0x06, 0x73, 0x20, 0x28, +0xbc, 0x04, 0x43, 0x20, +0x28, 0xbc, 0x02, 0xb9, +0x82, 0x88, 0x98, 0x2c, +0x8b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0x85, 0x00, 0x88, 0x40, +0x09, 0x57, 0x8b, 0x22, +0xbf, 0xd0, 0x85, 0x04, +0x88, 0x80, 0x63, 0x88, +0x0e, 0x28, 0x81, 0x61, +0x88, 0x1e, 0x08, 0x82, +0x76, 0x00, 0x00, 0x08, +0x40, 0x09, 0x36, 0x14, +0x52, 0xe9, 0x64, 0x85, +0x04, 0x80, 0x00, 0x00, +0x85, 0x80, 0x88, 0x48, +0x09, 0x2f, 0x16, 0x48, +0x58, 0x48, 0x00, 0x00, +0x08, 0x48, 0x09, 0x36, +0x14, 0x52, 0xe9, 0x64, +0x44, 0x00, 0x00, 0x58, +0x48, 0x98, 0x00, 0x98, +0x50, 0x08, 0x44, 0x00, +0x00, 0x48, 0x08, 0x44, +0x01, 0x00, 0x40, 0x08, +0x44, 0x01, 0x01, 0xa0, +0x00, 0x44, 0x40, 0x01, +0x80, 0x88, 0x08, 0x18, +0x06, 0x60, 0x00, 0x03, +0x48, 0x89, 0x81, 0x09, +0x88, 0x12, 0x08, 0x81, +0xa1, 0x84, 0x00, 0x98, +0x48, 0x0a, 0x44, 0x48, +0x00, 0x80, 0xa0, 0x88, +0x02, 0x19, 0x80, 0x0b, +0x84, 0x00, 0x94, 0x46, +0x80, 0x04, 0x80, 0xa4, +0x47, 0x10, 0x18, 0x00, +0xb4, 0x46, 0x00, 0x18, +0x28, 0xb5, 0x11, 0xe0, +0x18, 0x08, 0xa4, 0x44, +0x10, 0x18, 0x00, 0x83, +0x20, 0x20, 0x51, 0x1e, +0x83, 0xc0, 0x29, 0x98, +0x00, 0xa9, 0x82, 0x48, +0x32, 0x03, 0x0b, 0xc0, +0x11, 0x98, 0x2c, 0xa3, +0x69, 0x40, 0x5b, 0x48, +0x01, 0x80, 0x09, 0x98, +0x00, 0x03, 0x00, 0x28, +0xbc, 0x06, 0x43, 0x69, +0xc0, 0x5b, 0x4c, 0x01, +0x80, 0x09, 0x98, 0x00, +0xb3, 0x01, 0xe8, 0xbc, +0x04, 0x58, 0x40, 0x48, +0x42, 0x01, 0x7b, 0x00, +0x0c, 0x84, 0x84, 0xa9, +0x8e, 0x88, 0x00, 0x00, +0x08, 0x82, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x00, +0x62, 0x20, 0x5c, 0x81, +0x01, 0x8e, 0x88, 0x68, +0x00, 0x00, 0x6c, 0x21, +0x55, 0x03, 0x20, 0x00, +0x7a, 0x3a, 0x10, 0x43, +0x22, 0xa0, 0xbf, 0xfb, +0xa8, 0x08, 0x7a, 0x68, +0x00, 0x00, 0xd8, 0x20, +0x00, 0x00, 0x08, 0x40, +0x7a, 0x84, 0x0f, 0xa6, +0xc0, 0x00, 0x61, 0x87, +0xa0, 0x00, 0x00, 0x6c, +0x40, 0x02, 0x36, 0x08, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x61, 0x64, 0x80, +0x00, 0x00, 0x84, 0x00, +0xa8, 0x60, 0x08, 0x44, +0x40, 0x00, 0x48, 0x08, +0x46, 0x0a, 0x40, 0x60, +0x8a, 0x08, 0x28, 0x09, +0x80, 0x08, 0x68, 0x20, +0x00, 0x24, 0x21, 0x68, +0x00, 0x00, 0x5e, 0x20, +0x5c, 0x82, 0x02, 0xc0, +0x21, 0x68, 0x20, 0x00, +0x4b, 0x24, 0x5c, 0x08, +0xa8, 0x08, 0x0b, 0xd0, +0x28, 0x06, 0x80, 0x00, +0x09, 0x62, 0x54, 0x41, +0x80, 0x04, 0x00, 0x84, +0x41, 0x08, 0x16, 0x82, +0xc5, 0x2c, 0xb0, 0x2b, +0xf7, 0x08, 0x81, 0x64, +0x88, 0x1e, 0x18, 0x82, +0x76, 0x88, 0x2d, 0x59, +0x04, 0x58, 0x42, 0x04, +0x48, 0x85, 0x54, 0x90, +0x35, 0x90, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x0e, +0x0a, 0x40, 0x00, 0x03, +0xc0, 0x7f, 0x6c, 0x00, +0x00, 0xfc, 0x09, 0x68, +0x00, 0x00, 0x60, 0x20, +0x00, 0x00, 0x08, 0x40, +0x8a, 0x84, 0x00, 0x98, +0x85, 0xca, 0x40, 0x00, +0x00, 0x86, 0x49, 0x68, +0x20, 0x00, 0x85, 0x24, +0x66, 0x00, 0x01, 0xcd, +0xa8, 0x6e, 0x40, 0x01, +0x12, 0x27, 0x68, 0x20, +0x00, 0x85, 0x20, 0x88, +0x84, 0x8a, 0x00, 0x88, +0x94, 0x02, 0x78, 0x86, +0x0a, 0x88, 0x58, 0x96, +0x60, 0x00, 0x1c, 0xda, +0x8a, 0x04, 0x4c, 0x6e, +0x00, 0x01, 0x2c, 0x2d, +0x5c, 0x08, 0xf0, 0x85, +0xc8, 0x68, 0x00, 0x00, +0x96, 0x20, 0x52, 0xcd, +0x40, 0x88, 0x09, 0x88, +0x8c, 0x84, 0x21, 0x04, +0xa0, 0x00, 0x88, 0x86, +0x60, 0x68, 0x20, 0x00, +0x90, 0x2c, 0x68, 0x20, +0x00, 0x8a, 0x24, 0x68, +0x20, 0x00, 0x8d, 0x25, +0x40, 0x00, 0x00, 0x80, +0x6c, 0x66, 0x00, 0x01, +0xce, 0x20, 0x6c, 0x40, +0x00, 0x4a, 0x09, 0x44, +0x08, 0x00, 0x85, 0x89, +0x68, 0x20, 0x00, 0x98, +0xac, 0x88, 0x84, 0x86, +0x82, 0x00, 0x09, 0x2a, +0x46, 0x82, 0x00, 0x09, +0x5a, 0x58, 0x80, 0x6c, +0x90, 0x75, 0x88, 0x85, +0xd4, 0x66, 0x00, 0x01, +0xce, 0x20, 0x6c, 0x40, +0x00, 0x98, 0x09, 0xbc, +0x0d, 0xf4, 0x40, 0x80, +0x08, 0x8c, 0x80, 0x00, +0x00, 0x6c, 0x40, 0x00, +0x4a, 0x08, 0x44, 0x20, +0x80, 0x85, 0x88, 0x6c, +0x40, 0x00, 0x98, 0x09, +0x44, 0x08, 0x01, 0x07, +0x59, 0x40, 0x00, 0x00, +0x85, 0xd5, 0x68, 0x00, +0x00, 0x42, 0x20, 0x90, +0x71, 0x1a, 0x04, 0x21, +0x88, 0x59, 0x58, 0x85, +0xe1, 0x90, 0x75, 0x88, +0x86, 0xd4, 0x66, 0x00, +0x00, 0x30, 0x88, 0x5c, +0x00, 0x71, 0x80, 0x49, +0x68, 0x00, 0x00, 0x56, +0x20, 0x90, 0x71, 0x0a, +0x04, 0x21, 0x88, 0x69, +0x48, 0x86, 0xe1, 0x40, +0x00, 0x00, 0x87, 0x48, +0x66, 0x00, 0x00, 0x30, +0x88, 0x5c, 0x00, 0x71, +0x80, 0x09, 0x5c, 0x08, +0x28, 0x85, 0xa0, 0x88, +0x1a, 0x58, 0x86, 0xa1, +0x88, 0x12, 0x4a, 0x05, +0x60, 0x90, 0x41, 0x08, +0x81, 0x48, 0xa0, 0xd6, +0x18, 0x68, 0x0a, 0x84, +0x00, 0xb8, 0x85, 0x14, +0x44, 0x74, 0x01, 0x03, +0x11, 0x88, 0x62, 0x28, +0x60, 0x08, 0x88, 0x29, +0x58, 0x48, 0x0a, 0x44, +0x44, 0xa1, 0x50, 0x2c, +0x52, 0xcb, 0x01, 0x80, +0x00, 0x84, 0x75, 0x09, +0x80, 0x41, 0x88, 0x1e, +0x14, 0x20, 0xec, 0x88, +0x2e, 0x05, 0x50, 0x01, +0x04, 0xf5, 0x16, 0x82, +0x00, 0x22, 0x72, 0x45, +0xc8, 0x10, 0x18, 0x44, +0x86, 0x82, 0x00, 0x22, +0x42, 0x15, 0x50, 0x0b, +0x02, 0x20, 0x04, 0xe0, +0x61, 0x02, 0x20, 0x94, +0x40, 0x90, 0x00, 0xa0, +0xb8, 0x0a, 0x08, 0x44, +0x41, 0x81, 0xa1, 0x40, +0x51, 0x02, 0x89, 0x82, +0xc2, 0x51, 0x02, 0xd8, +0x48, 0x09, 0x48, 0x40, +0x50, 0x60, 0x0b, 0x08, +0x9a, 0x80, 0x83, 0x90, +0x6c, 0x00, 0x00, 0x80, +0x42, 0x6c, 0x00, 0x00, +0xa8, 0x41, 0x68, 0x00, +0x01, 0x5a, 0x21, 0x68, +0x20, 0x01, 0xe8, 0x24, +0x90, 0x35, 0x98, 0x84, +0x55, 0x90, 0x55, 0xa8, +0x84, 0xd6, 0x66, 0x00, +0x01, 0xd1, 0x80, 0x88, +0x84, 0x86, 0x80, 0x00, +0x16, 0x02, 0x18, 0x81, +0xa0, 0x68, 0x20, 0x01, +0xee, 0x24, 0x66, 0x00, +0x01, 0xd1, 0x80, 0x90, +0x31, 0x08, 0x81, 0x09, +0x88, 0x41, 0x45, 0x40, +0xa1, 0x10, 0x51, 0x15, +0x40, 0x89, 0x08, 0x70, +0x98, 0x84, 0x95, 0x54, +0x0a, 0x40, 0x88, 0x09, +0x54, 0x0a, 0x00, 0x88, +0xc8, 0x68, 0x20, 0x00, +0x7e, 0x2c, 0x6c, 0x00, +0x02, 0xac, 0x0a, 0x6c, +0x00, 0x02, 0xae, 0x01, +0x48, 0x52, 0x80, 0x81, +0xa1, 0x6c, 0x00, 0x02, +0xb2, 0x09, 0x6c, 0x00, +0x02, 0xb0, 0x08, 0x49, +0x29, 0x60, 0x82, 0xa0, +0x84, 0x94, 0x08, 0x41, +0x42, 0x68, 0x00, 0x00, +0x0e, 0x21, 0x68, 0x20, +0x00, 0x24, 0x24, 0x68, +0x20, 0x00, 0x72, 0x25, +0x40, 0x00, 0x00, 0x80, +0x6c, 0x66, 0x00, 0x01, +0xc9, 0x80, 0x68, 0x20, +0x00, 0x7f, 0xac, 0x88, +0x84, 0x86, 0x80, 0x00, +0x02, 0x22, 0x18, 0x81, +0xa0, 0x68, 0x20, 0x00, +0x4b, 0x24, 0x68, 0x20, +0x00, 0x78, 0x25, 0x88, +0x06, 0xc6, 0x60, 0x00, +0x1c, 0x98, 0x08, 0x88, +0xc8, 0x68, 0x20, 0x00, +0x83, 0x20, 0x68, 0x20, +0x00, 0x84, 0x21, 0xa4, +0x22, 0x36, 0x60, 0x00, +0x1a, 0xf0, 0x8a, 0x42, +0x02, 0x5c, 0x81, 0x00, +0x82, 0xa0, 0x5c, 0x08, +0x61, 0x8e, 0x80, 0xa0, +0x26, 0x09, 0x42, 0x0d, +0x25, 0x92, 0x8b, 0xc0, +0x39, 0x55, 0x00, 0x08, +0x81, 0xa1, 0x88, 0x80, +0x03, 0x91, 0x81, 0x80, +0x2c, 0x0a, 0x0a, 0x61, +0x84, 0x00, 0x95, 0x40, +0xa0, 0x14, 0xa0, 0xd2, +0x59, 0x28, 0xbc, 0x03, +0x98, 0x40, 0xc0, 0x00, +0x00, 0x08, 0x88, 0x81, +0x80, 0xac, 0x10, 0x00, +0x00, 0x84, 0x80, 0x85, +0x40, 0x84, 0x08, 0x23, +0x6b, 0xa1, 0x48, 0x84, +0x8c, 0x0a, 0x80, 0x90, +0xab, 0xfb, 0x08, 0x81, +0x60, 0xa0, 0x04, 0x6a, +0x08, 0x00, 0xa2, 0x80, +0x1a, 0x34, 0x25, 0x86, +0x80, 0x88, 0x81, 0xe5, +0xa2, 0x84, 0x58, 0x82, +0x65, 0xa0, 0x82, 0x28, +0x85, 0x25, 0xa1, 0x02, +0x3a, 0x18, 0x27, 0xa2, +0x06, 0x48, 0x70, 0x09, +0x57, 0x09, 0x40, 0x80, +0x67, 0x88, 0x2e, 0x78, +0x83, 0x64, 0x88, 0x3e, +0x08, 0x84, 0x76, 0x66, +0x00, 0x01, 0xd7, 0xe8, +0x40, 0x00, 0x01, 0x80, +0x09, 0x5c, 0x08, 0x28, +0x82, 0x20, 0x88, 0x1a, +0x1a, 0x02, 0x00, 0x94, +0x02, 0xf5, 0x2c, 0xbc, +0x04, 0x94, 0x8a, 0x05, +0xe1, 0x42, 0x02, 0xc8, +0x83, 0x24, 0x5c, 0x00, +0x30, 0x83, 0xa0, 0x88, +0x12, 0x50, 0x00, 0x00, +0x86, 0x98, 0xa8, 0x48, +0x08, 0x54, 0x09, 0x82, +0x01, 0x40, 0x98, 0x00, +0x9a, 0x22, 0xe4, 0x84, +0x8c, 0x98, 0x81, 0x64, +0x88, 0x1e, 0x06, 0x60, +0x00, 0x1d, 0xe2, 0x08, +0x82, 0xa1, 0x88, 0x52, +0x58, 0x81, 0x24, 0x88, +0x1a, 0x08, 0x84, 0x36, +0xa2, 0x82, 0x5a, 0x80, +0x50, 0xa0, 0x04, 0x0a, +0x20, 0x64, 0x40, 0x00, +0x02, 0x08, 0x21, 0x64, +0x00, 0x01, 0xdf, 0x0f, +0x55, 0x01, 0x2a, 0x08, +0x22, 0x86, 0x00, 0x84, +0x42, 0x00, 0x06, 0x08, +0x95, 0x00, 0xe0, 0x3a, +0x14, 0x80, 0x89, 0x80, +0x40, 0x00, 0x01, 0x80, +0x08, 0x6e, 0x40, 0x00, +0x08, 0x3c, 0x38, 0x15, +0x62, 0x59, 0xa0, 0xbc, +0x2d, 0x05, 0x15, 0x96, +0x16, 0x1b, 0x65, 0x19, +0x5b, 0x08, 0x02, 0x04, +0x41, 0x00, 0x18, 0xe8, +0x85, 0xc8, 0x08, 0x18, +0x00, 0xa9, 0x40, 0x17, +0x30, 0x1f, 0x0b, 0xc0, +0x32, 0x2a, 0x06, 0x43, +0x21, 0x60, 0xbf, 0xfa, +0x23, 0x20, 0xe0, 0xbc, +0x1d, 0x05, 0x18, 0x32, +0xb0, 0x10, 0x05, 0x04, +0x19, 0x18, 0x26, 0x85, +0x50, 0x0b, 0x1e, 0x00, +0x44, 0x60, 0x88, 0x96, +0x03, 0x55, 0x04, 0x14, +0x98, 0x38, 0x95, 0x50, +0x07, 0x98, 0x34, 0x84, +0x44, 0x10, 0x9e, 0x80, +0x54, 0x46, 0xd4, 0x96, +0x83, 0x62, 0x10, 0x10, +0x08, 0x48, 0x23, 0x78, +0x00, 0x22, 0x88, 0x06, +0xc4, 0x00, 0x13, 0x60, +0x95, 0x18, 0x7b, 0x18, +0x30, 0x83, 0x61, 0x47, +0x28, 0x1a, 0x42, 0xf1, +0x65, 0x2e, 0x9e, 0xd2, +0x33, 0x2d, 0xba, 0x14, +0x84, 0x60, 0x80, 0x98, +0x24, 0x80, 0x00, 0x00, +0xa2, 0x08, 0x4a, 0x20, +0x22, 0x84, 0x38, 0x98, +0x60, 0x0a, 0x57, 0x8b, +0xaa, 0xbf, 0xe0, 0xa1, +0x4a, 0x4a, 0x08, 0x00, +0x85, 0x00, 0x88, 0x80, +0x64, 0x88, 0x0e, 0x08, +0x81, 0x76, 0x66, 0x00, +0x00, 0x31, 0xc8, 0x2e, +0x96, 0x58, 0x80, 0x20, +0x88, 0x0a, 0x48, 0x41, +0x89, 0x44, 0x08, 0x00, +0x81, 0x36, 0x46, 0x0a, +0x41, 0x80, 0x08, 0x86, +0x14, 0x8a, 0x80, 0x20, +0xab, 0xff, 0x08, 0x80, +0x76, 0x66, 0x00, 0x01, +0xd5, 0xe0, 0x40, 0x00, +0x03, 0x00, 0x0c, 0x6e, +0x00, 0x00, 0x92, 0x64, +0x6e, 0x00, 0x00, 0xba, +0x64, 0x66, 0x00, 0x01, +0xb4, 0xa0, 0x5c, 0x00, +0x73, 0x03, 0x0c, 0x88, +0x03, 0x66, 0xe0, 0x00, +0x12, 0xc6, 0x4b, 0xa1, +0x48, 0x6c, 0x40, 0x00, +0x44, 0x4a, 0x40, 0x00, +0x02, 0x80, 0x10, 0x5c, +0x81, 0x01, 0x8e, 0x8a, +0x68, 0x00, 0x00, 0x0e, +0x20, 0x38, 0x0a, 0x42, +0xa0, 0x76, 0x3a, 0x18, +0x63, 0x01, 0x30, 0xbf, +0xfc, 0xa8, 0x00, 0x7a, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x5c, 0x81, 0x01, +0x8e, 0x8a, 0x68, 0x00, +0x00, 0x22, 0x20, 0x38, +0x0a, 0x42, 0xa0, 0x76, +0x3a, 0x18, 0x63, 0x01, +0x30, 0xbf, 0xfc, 0xa8, +0x00, 0x7a, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x68, +0x00, 0x00, 0x36, 0x20, +0x5c, 0x81, 0x02, 0xbf, +0xf0, 0x68, 0x00, 0x00, +0x4a, 0x21, 0x88, 0x07, +0x69, 0x8e, 0x88, 0x40, +0x00, 0x02, 0x00, 0x02, +0x55, 0x03, 0x20, 0x08, +0x7a, 0x3a, 0x10, 0x43, +0x22, 0x20, 0xbf, 0xfb, +0xa8, 0x10, 0x7a, 0x40, +0x00, 0x02, 0x01, 0x80, +0x66, 0x00, 0x00, 0x2f, +0xc8, 0x5c, 0x00, 0x62, +0x04, 0x21, 0x68, 0x00, +0x00, 0x4a, 0x20, 0x88, +0x03, 0x6a, 0x80, 0x10, +0x40, 0x00, 0x02, 0x01, +0x80, 0x64, 0x00, 0x00, +0x2f, 0xcf, 0x5c, 0x00, +0x62, 0x04, 0x21, 0x55, +0x01, 0x40, 0x60, 0x0b, +0x5c, 0x82, 0x0a, 0x20, +0x26, 0x5c, 0x81, 0x00, +0xc0, 0x2a, 0x44, 0x18, +0x82, 0x30, 0x27, 0x87, +0x00, 0x84, 0x44, 0x4a, +0x07, 0x80, 0x84, 0x42, +0x4a, 0x23, 0x82, 0x49, +0x80, 0x42, 0x8c, 0x0c, +0x0a, 0x20, 0x26, 0x86, +0x00, 0xb8, 0xc0, 0x2a, +0x44, 0x18, 0x82, 0x30, +0x27, 0x55, 0x00, 0xa0, +0x70, 0x0b, 0x44, 0x5d, +0x20, 0x78, 0x0a, 0x44, +0x15, 0x40, 0x48, 0x0b, +0x55, 0x01, 0x09, 0x80, +0x8a, 0x57, 0x8f, 0xb0, +0x50, 0x08, 0x57, 0x49, +0x92, 0x38, 0x24, 0x8c, +0x0c, 0x4a, 0x20, 0x22, +0x86, 0x00, 0xa8, 0xc0, +0x2b, 0x44, 0x10, 0x82, +0x10, 0x21, 0x85, 0x00, +0x84, 0x46, 0x4a, 0x04, +0x80, 0x84, 0x42, 0x4a, +0x20, 0x82, 0x49, 0x80, +0x43, 0x8c, 0x0c, 0x1a, +0x20, 0x22, 0x86, 0x00, +0xb8, 0xc0, 0x2a, 0x44, +0x18, 0x00, 0x50, 0x0b, +0x55, 0x00, 0xa2, 0x10, +0x21, 0x44, 0x5c, 0x01, +0x84, 0xca, 0x84, 0x80, +0xb4, 0x45, 0xc8, 0x20, +0x88, 0x25, 0x50, 0x18, +0x18, 0x04, 0x2a, 0x10, +0x21, 0x8c, 0x06, 0x0a, +0x28, 0x08, 0x80, 0x80, +0xa4, 0x41, 0x08, 0x05, +0x00, 0xa4, 0x43, 0x00, +0x16, 0x82, 0x55, 0x00, +0xa0, 0x20, 0x00, 0xd5, +0x50, 0x0a, 0x04, 0x80, +0x94, 0x40, 0x90, 0x14, +0x02, 0x55, 0x00, 0xa4, +0x96, 0x82, 0x45, 0x00, +0x89, 0x20, 0x82, 0x28, +0x10, 0x09, 0x98, 0x00, +0x84, 0x40, 0x80, 0x01, +0x00, 0x89, 0xa1, 0x02, +0x44, 0x24, 0x00, 0x10, +0x09, 0x44, 0x4c, 0x00, +0x80, 0x20, 0x85, 0x80, +0x99, 0x80, 0x08, 0x57, +0x8b, 0x28, 0x40, 0x08, +0x57, 0x49, 0x68, 0x50, +0x08, 0x44, 0x20, 0x01, +0x68, 0xa5, 0x50, 0x0a, +0x00, 0x50, 0x89, 0x46, +0x0a, 0x41, 0x80, 0x08, +0x08, 0x10, 0x09, 0x80, +0x08, 0x5c, 0x81, 0x00, +0xc0, 0x2a, 0x82, 0x00, +0xb4, 0x41, 0x80, 0x02, +0x00, 0x84, 0x44, 0x40, +0x06, 0x00, 0x84, 0x42, +0x50, 0x18, 0x24, 0x04, +0x60, 0xa4, 0x18, 0x08, +0x28, 0xc0, 0x60, 0x55, +0x00, 0xa3, 0x80, 0x00, +0x5c, 0x82, 0x09, 0x8e, +0x82, 0x5c, 0x81, 0x00, +0xc0, 0x8a, 0x55, 0x00, +0x98, 0x20, 0x0b, 0x44, +0x1d, 0xe0, 0x20, 0x08, +0x55, 0x00, 0x80, 0x20, +0x0b, 0x44, 0x44, 0x00, +0xc0, 0x8a, 0x44, 0x1d, +0xe0, 0x20, 0x08, 0x44, +0x44, 0x00, 0x20, 0x08, +0x44, 0x25, 0xe1, 0x68, +0x24, 0x54, 0x00, 0xda, +0x04, 0x80, 0x50, 0x08, +0xd8, 0xc0, 0x30, 0x55, +0x01, 0x48, 0xc1, 0x78, +0x5c, 0x00, 0x01, 0x80, +0xc3, 0x8c, 0x06, 0x5a, +0x00, 0x80, 0x8c, 0x08, +0xe8, 0x20, 0x08, 0x44, +0x25, 0x40, 0x20, 0x09, +0x44, 0x4c, 0x00, 0xc0, +0x8e, 0x82, 0x00, 0x84, +0x42, 0x54, 0x02, 0x00, +0x94, 0x44, 0xc0, 0x18, +0x4c, 0x98, 0x60, 0x08, +0x44, 0x25, 0x41, 0x68, +0xa5, 0x54, 0x00, 0x92, +0x04, 0x85, 0x50, 0x0a, +0x90, 0xe8, 0x30, 0x55, +0x00, 0xc0, 0xe9, 0x78, +0x98, 0x08, 0x28, 0x50, +0x08, 0x46, 0x0a, 0x40, +0x48, 0x09, 0x57, 0x8a, +0xa8, 0xe8, 0x60, 0x57, +0x49, 0x63, 0x80, 0x00, +0x85, 0x08, 0x85, 0x90, +0x10, 0x2b, 0xfc, 0x04, +0x24, 0x4c, 0x08, 0x07, +0x65, 0xc8, 0x10, 0x08, +0x0e, 0x2a, 0x10, 0x43, +0xa1, 0x90, 0x68, 0xc0, +0x2a, 0x82, 0x00, 0x94, +0x40, 0x90, 0x07, 0x02, +0x78, 0x20, 0x08, 0x44, +0x45, 0x40, 0x78, 0x08, +0x55, 0x01, 0x00, 0x20, +0x0a, 0x44, 0x15, 0x40, +0x20, 0x09, 0x98, 0x08, +0x25, 0x50, 0x0b, 0x8c, +0x06, 0x05, 0x50, 0x08, +0x23, 0x14, 0x78, 0xc1, +0x2a, 0x44, 0x09, 0x80, +0x60, 0x08, 0x44, 0x45, +0x60, 0x60, 0x89, 0x44, +0x6d, 0x40, 0x28, 0x09, +0x98, 0x08, 0x28, 0xc1, +0x60, 0xa1, 0x18, 0x08, +0xc8, 0x2a, 0x44, 0x09, +0x80, 0x75, 0x22, 0x82, +0x80, 0x84, 0x44, 0x5e, +0x05, 0x00, 0xa5, 0x50, +0x18, 0x02, 0x80, 0x84, +0x44, 0x5e, 0x02, 0x80, +0x99, 0x80, 0xc3, 0x55, +0x00, 0xc0, 0xc8, 0x61, +0x88, 0x1d, 0x2a, 0x3e, +0x82, 0x8c, 0x92, 0xa4, +0x40, 0x90, 0x06, 0x80, +0x84, 0x44, 0x54, 0x06, +0x88, 0xa5, 0x50, 0x0e, +0x08, 0x16, 0x04, 0x41, +0x54, 0x08, 0x2e, 0x39, +0x80, 0x82, 0x8c, 0x96, +0x08, 0x83, 0x52, 0x88, +0x26, 0x26, 0x80, 0x00, +0x0c, 0x92, 0x06, 0x60, +0x00, 0x06, 0x58, 0x03, +0x20, 0x20, 0xbc, 0x05, +0x88, 0x82, 0x21, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x04, 0x00, 0x00, +0x00, 0x88, 0x0a, 0x58, +0x48, 0x08, 0x55, 0x03, +0x20, 0x48, 0x82, 0x58, +0x05, 0x00, 0x48, 0x48, +0xbc, 0x39, 0xc8, 0x81, +0x88, 0x86, 0x90, 0x25, +0x80, 0x88, 0x08, 0x2a, +0x0b, 0xc0, 0x13, 0x86, +0x94, 0x8a, 0x00, 0x21, +0x84, 0x80, 0x23, 0x01, +0x10, 0xbc, 0x01, 0x58, +0x40, 0xc8, 0x5c, 0x08, +0x1a, 0xc0, 0x21, 0x5c, +0x82, 0x00, 0x08, 0x8a, +0x5b, 0x48, 0x10, 0xc9, +0x30, 0x50, 0x47, 0x08, +0x69, 0x08, 0x57, 0x0d, +0x20, 0x83, 0x0a, 0x54, +0x02, 0x00, 0x08, 0x48, +0x50, 0x46, 0x92, 0x08, +0x00, 0x8c, 0x85, 0x8a, +0x08, 0x82, 0xa1, 0x00, +0x48, 0x10, 0x88, 0x58, +0x0d, 0x00, 0xc1, 0x30, +0x54, 0x04, 0x13, 0xc0, +0x2b, 0x8c, 0x17, 0xa8, +0x6e, 0x4a, 0x00, 0x00, +0x08, 0x60, 0x88, 0x58, +0x0d, 0x00, 0x81, 0x25, +0xbc, 0x01, 0x58, 0x68, +0xca, 0x36, 0x98, 0x25, +0x04, 0x69, 0x04, 0xa0, +0x15, 0x04, 0x78, 0x01, +0x08, 0x85, 0x70, 0x86, +0x21, 0x00, 0x18, 0xd1, +0x31, 0x54, 0x00, 0x58, +0x10, 0x48, 0x8c, 0x97, +0xb0, 0x00, 0x00, 0x8d, +0x13, 0x05, 0x40, 0x41, +0x3c, 0x05, 0xf8, 0xd1, +0x7a, 0x88, 0x03, 0x6b, +0xa1, 0x48, 0x86, 0x8f, +0xaa, 0x80, 0x40, 0x00, +0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, +0x40, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x20, +0x01, 0x1b, 0x20, 0x5c, +0x81, 0x03, 0x00, 0xcc, +0x68, 0x00, 0x00, 0xcc, +0x21, 0x5c, 0x00, 0x30, +0x02, 0x09, 0x51, 0x87, +0x60, 0x48, 0x48, 0x68, +0x20, 0x02, 0x1a, 0x22, +0x6c, 0x40, 0x01, 0xf4, +0x00, 0x6c, 0x40, 0x01, +0xea, 0x48, 0x51, 0x8b, +0x00, 0x10, 0x50, 0x68, +0x00, 0x00, 0x98, 0x23, +0x6c, 0x40, 0x01, 0xb0, +0x09, 0x84, 0x00, 0x88, +0x10, 0x7a, 0xa0, 0x86, +0x08, 0x10, 0x7a, 0x81, +0x85, 0x06, 0xc4, 0x00, +0x2f, 0x24, 0x96, 0xc4, +0x00, 0x2f, 0x84, 0x96, +0xc4, 0x00, 0x19, 0x84, +0x96, 0xc4, 0x00, 0x19, +0xa4, 0x96, 0xc4, 0x00, +0x10, 0x64, 0x86, 0xc4, +0x00, 0x10, 0x84, 0x89, +0x42, 0x46, 0x85, 0x87, +0xa4, 0x60, 0xa4, 0x05, +0x07, 0xa8, 0x40, 0x7a, +0x40, 0x00, 0x03, 0x80, +0x00, 0x30, 0x1a, 0x8b, +0xc0, 0xd0, 0x84, 0x00, +0x83, 0x69, 0x04, 0x6c, +0x40, 0x02, 0xc8, 0x0b, +0x30, 0x9e, 0x0b, 0xc0, +0x64, 0x6c, 0x40, 0x02, +0xc6, 0x08, 0x28, 0x13, +0x04, 0x20, 0x17, 0x98, +0x00, 0xa2, 0xf1, 0x75, +0x98, 0x28, 0x9b, 0xa1, +0x48, 0x98, 0x24, 0x80, +0x00, 0x00, 0x68, 0x00, +0x00, 0xcd, 0x22, 0x6c, +0x00, 0x01, 0x98, 0x08, +0x85, 0x00, 0xa3, 0x01, +0x30, 0xbc, 0x8d, 0x19, +0x54, 0x24, 0x32, 0x06, +0x06, 0xc4, 0x00, 0x1e, +0x80, 0x86, 0xc0, 0x00, +0x19, 0xa7, 0xab, 0xc2, +0x69, 0x5b, 0x48, 0x22, +0xc0, 0x40, 0x84, 0x00, +0xa3, 0x69, 0x86, 0x30, +0x93, 0x0b, 0xc0, 0x84, +0x84, 0x80, 0xa3, 0x69, +0x86, 0x30, 0x93, 0x0b, +0xc0, 0x44, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x19, +0xc7, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x9c, +0x08, 0x6c, 0x40, 0x01, +0xe6, 0x0a, 0x2a, 0x06, +0x43, 0x01, 0xa0, 0xbc, +0x76, 0x96, 0xc0, 0x00, +0x19, 0xc4, 0x85, 0xc0, +0xb8, 0x18, 0xe8, 0xa6, +0xc4, 0x00, 0x3b, 0xa0, +0x85, 0x24, 0x12, 0x2c, +0x02, 0x06, 0x80, 0x00, +0x0c, 0xf2, 0x16, 0xc4, +0x00, 0x3b, 0xa4, 0x84, +0x60, 0xa4, 0x14, 0xa4, +0x68, 0x48, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x68, 0x20, 0x01, 0x15, +0x22, 0x00, 0x00, 0x08, +0x12, 0x0a, 0x85, 0x00, +0x03, 0x00, 0x30, 0xbc, +0x2a, 0x36, 0xc4, 0x00, +0x1e, 0xa0, 0xa6, 0xc4, +0x00, 0x23, 0x60, 0x03, +0x00, 0x30, 0xbc, 0x24, +0x16, 0x82, 0x00, 0x10, +0x02, 0x28, 0x40, 0x0a, +0x5b, 0x4c, 0x00, 0x50, +0x0a, 0x30, 0x98, 0x0b, +0xc0, 0x5b, 0xa1, 0x20, +0x28, 0x48, 0x00, 0x36, +0x80, 0x03, 0x09, 0x80, +0xbc, 0x03, 0x2b, 0xc0, +0x7f, 0x6c, 0x40, 0x02, +0x20, 0x7a, 0x6c, 0x40, +0x02, 0x20, 0x0a, 0x2a, +0x07, 0x66, 0xc4, 0x00, +0x22, 0x04, 0xa0, 0x00, +0x00, 0x6c, 0x40, 0x01, +0xe4, 0x0a, 0x51, 0x83, +0xb0, 0x50, 0x00, 0x30, +0x18, 0x0b, 0xc0, 0x99, +0x68, 0x20, 0x01, 0x10, +0x23, 0x6c, 0x40, 0x02, +0x20, 0x7a, 0x00, 0x00, +0x08, 0x5a, 0x8a, 0x2a, +0x07, 0x68, 0x5a, 0xca, +0x00, 0x00, 0x08, 0x40, +0x0a, 0x36, 0x98, 0x63, +0x09, 0x30, 0xbc, 0x04, +0x38, 0x48, 0x0a, 0x36, +0x98, 0x63, 0x09, 0x30, +0xbc, 0x05, 0x2b, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0x9c, 0x7a, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x01, 0x9c, 0x08, +0x6c, 0x40, 0x01, 0xe4, +0x0a, 0x2a, 0x06, 0x43, +0x01, 0xa0, 0xbc, 0x20, +0x96, 0xc0, 0x00, 0x19, +0xc4, 0x85, 0xc0, 0xb8, +0x30, 0x00, 0xe6, 0xc4, +0x00, 0x3b, 0xa0, 0x85, +0x20, 0x12, 0x2c, 0x02, +0x06, 0xc4, 0x00, 0x1e, +0xa0, 0x06, 0xc4, 0x00, +0x23, 0x60, 0x26, 0x80, +0x00, 0x0c, 0xf2, 0x16, +0xc4, 0x00, 0x3b, 0xa4, +0x85, 0x80, 0x40, 0x14, +0xa4, 0x6b, 0xc0, 0xd9, +0x84, 0x87, 0xa6, 0x82, +0x00, 0x11, 0x42, 0x10, +0x00, 0x00, 0x84, 0x80, +0x88, 0x48, 0xc8, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x55, 0x03, 0xa3, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0x9a, 0x48, 0x00, 0x00, +0x0b, 0xa1, 0x40, 0x85, +0x00, 0x88, 0x40, 0x0a, +0x30, 0x1a, 0x0b, 0xc1, +0x50, 0x30, 0x13, 0x0b, +0xc0, 0xbd, 0x84, 0x80, +0x82, 0xe1, 0x30, 0x98, +0x00, 0x88, 0x40, 0x48, +0x00, 0x00, 0x08, 0x50, +0x0a, 0x30, 0x1a, 0x0b, +0xc0, 0xb4, 0xba, 0x14, +0x88, 0x40, 0x4a, 0x00, +0x00, 0x02, 0x81, 0x30, +0x98, 0x00, 0x88, 0x40, +0x48, 0x00, 0x00, 0x08, +0x50, 0x0a, 0x30, 0x1a, +0x0b, 0xc0, 0x12, 0x84, +0x04, 0xab, 0xa1, 0x40, +0x68, 0x20, 0x01, 0x21, +0x21, 0x68, 0x00, 0x00, +0xbf, 0x22, 0x39, 0x02, +0x08, 0x08, 0x08, 0x81, +0x07, 0xa8, 0x10, 0x48, +0x68, 0x00, 0x00, 0xc4, +0x20, 0x84, 0x80, 0x88, +0x00, 0x7a, 0x81, 0x04, +0x88, 0x00, 0x7a, 0x68, +0x00, 0x00, 0xbc, 0x23, +0x80, 0x04, 0x86, 0x80, +0x00, 0x7f, 0x3a, 0xca, +0x10, 0x01, 0x81, 0x86, +0xc8, 0x10, 0x7a, 0xa0, +0x00, 0x48, 0x58, 0x7a, +0x85, 0x06, 0x14, 0x60, +0xa4, 0x00, 0x07, 0xa8, +0x40, 0x64, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x01, 0x7a, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0c, 0x16, +0xc0, 0x00, 0x18, 0x62, +0x06, 0x80, 0x00, 0x7f, +0x82, 0xc6, 0xc0, 0x00, +0x19, 0x02, 0x16, 0xc0, +0x00, 0x17, 0x86, 0xc4, +0x60, 0xa4, 0x04, 0x07, +0xa8, 0x48, 0x7a, 0x00, +0x00, 0x0b, 0xa1, 0x40, +0x6c, 0x00, 0x01, 0x7a, +0x08, 0x38, 0x10, 0x62, +0x59, 0xa0, 0xbc, 0x0c, +0x8a, 0xbf, 0xf0, 0x6c, +0x00, 0x01, 0x86, 0x20, +0x68, 0x00, 0x07, 0xf3, +0xac, 0x6c, 0x00, 0x01, +0x90, 0x21, 0x6c, 0x00, +0x01, 0x78, 0x6c, 0x42, +0x09, 0xf8, 0x40, 0x7a, +0x84, 0x87, 0xa8, 0x80, +0x76, 0x66, 0x00, 0x02, +0x01, 0xa0, 0x6c, 0x00, +0x01, 0x8e, 0x08, 0x32, +0x02, 0x0b, 0xc0, 0x65, +0x6c, 0x00, 0x01, 0x90, +0x20, 0x42, 0x03, 0xf8, +0x80, 0x36, 0x40, 0x00, +0x00, 0x40, 0x7a, 0x68, +0x00, 0x08, 0x01, 0xa0, +0x88, 0x03, 0x66, 0xc0, +0x00, 0x17, 0x86, 0x0b, +0xa1, 0x48, 0xa8, 0x01, +0x00, 0x00, 0x00, 0x6c, +0x00, 0x01, 0x7a, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0d, 0x06, +0xc0, 0x00, 0x18, 0x62, +0x06, 0x80, 0x00, 0x7f, +0x3a, 0xc6, 0xc0, 0x00, +0x19, 0x02, 0x16, 0xc0, +0x00, 0x17, 0x86, 0xc4, +0x60, 0xa4, 0x04, 0x07, +0xa8, 0x48, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x64, 0x00, 0x02, 0x01, +0xa7, 0x68, 0x00, 0x00, +0xc0, 0x20, 0x68, 0x20, +0x01, 0x23, 0x21, 0xab, +0xfe, 0x08, 0x40, 0x08, +0x84, 0x80, 0x94, 0x40, +0x80, 0x08, 0x07, 0x66, +0x60, 0x00, 0x20, 0x5a, +0x89, 0x80, 0x09, 0x5c, +0x81, 0x00, 0x80, 0xc8, +0x68, 0x20, 0x01, 0x23, +0x20, 0x68, 0x00, 0x00, +0xc5, 0x21, 0x80, 0x00, +0x88, 0x48, 0x09, 0x44, +0x20, 0x00, 0x81, 0x60, +0x66, 0x00, 0x02, 0x05, +0xa8, 0x40, 0x00, 0x01, +0x80, 0x09, 0x5c, 0x81, +0x00, 0x81, 0x20, 0x6c, +0x00, 0x01, 0x80, 0x09, +0x84, 0x00, 0x06, 0xc0, +0x00, 0x17, 0xe0, 0xa5, +0x40, 0xd6, 0x88, 0x03, +0x66, 0x80, 0x00, 0x0c, +0x02, 0x05, 0x44, 0x17, +0x08, 0x08, 0x96, 0xc0, +0x00, 0x18, 0xa0, 0xb6, +0xc0, 0x00, 0x18, 0x80, +0x25, 0x40, 0x5f, 0x80, +0x04, 0xa5, 0x44, 0x1f, +0xa0, 0x00, 0x28, 0x00, +0x0a, 0x68, 0x00, 0x00, +0xc5, 0x21, 0x44, 0x30, +0x00, 0x40, 0xa0, 0x80, +0x84, 0xb8, 0x50, 0xc0, +0x84, 0x04, 0x0a, 0x08, +0x00, 0x80, 0x80, 0x94, +0x40, 0x80, 0x04, 0x8a, +0x14, 0x60, 0xa4, 0x04, +0x0c, 0x08, 0x48, 0x40, +0x40, 0x00, 0x02, 0x80, +0x20, 0x44, 0x29, 0x02, +0xc0, 0x20, 0x68, 0x20, +0x01, 0x25, 0x20, 0x51, +0x48, 0x9b, 0x3f, 0xc4, +0x80, 0x00, 0x29, 0x80, +0xc9, 0x44, 0x0d, 0xc0, +0x00, 0x02, 0x98, 0x0c, +0x84, 0x40, 0xdc, 0x00, +0x00, 0x29, 0x80, 0xc8, +0x44, 0x0d, 0xc0, 0x00, +0x02, 0x98, 0x0c, 0x84, +0x40, 0xdc, 0x00, 0x00, +0x29, 0x80, 0xc8, 0x44, +0x0d, 0x40, 0x00, 0x03, +0x98, 0x08, 0x84, 0x40, +0x90, 0x04, 0x00, 0x85, +0x14, 0x69, 0x18, 0x08, +0xa2, 0xe0, 0x9a, 0x55, +0x00, 0xd1, 0x80, 0x89, +0x1a, 0x0d, 0x99, 0xa0, +0x42, 0x08, 0x63, 0x02, +0x20, 0xdb, 0x57, 0x06, +0x99, 0x80, 0xc9, 0x98, +0x0c, 0xa0, 0x86, 0x30, +0x22, 0x0d, 0xb5, 0x70, +0x69, 0x98, 0x0c, 0x99, +0x80, 0xca, 0x08, 0x63, +0x02, 0x20, 0xdb, 0x57, +0x06, 0x91, 0x80, 0xc9, +0x98, 0x08, 0xa0, 0x86, +0x20, 0x22, 0x0d, 0x25, +0x70, 0x51, 0x3a, 0x14, +0x82, 0x20, 0x92, 0x40, +0x00, 0x01, 0x80, 0x88, +0x37, 0x08, 0x63, 0x70, +0x44, 0x2e, 0x13, 0x42, +0xa0, 0x64, 0x32, 0x02, +0x0b, 0xc1, 0x55, 0x38, +0x20, 0x63, 0x01, 0xa0, +0xbc, 0x0e, 0x06, 0x20, +0x00, 0x00, 0x01, 0x45, +0x00, 0x88, 0x18, 0xeb, +0x50, 0x00, 0x00, 0x2f, +0x80, 0x9b, 0xc0, 0x13, +0x28, 0x00, 0x92, 0x09, +0x08, 0x57, 0x09, 0xa3, +0xa1, 0x48, 0x20, 0x10, +0x95, 0x0c, 0x84, 0x19, +0x20, 0x3b, 0xa1, 0x48, +0x5b, 0xc2, 0x01, 0x8e, +0x83, 0x00, 0x00, 0x0b, +0xa1, 0x48, 0x55, 0x00, +0x59, 0x8e, 0x80, 0x40, +0x00, 0x03, 0x80, 0x00, +0x00, 0x00, 0x00, 0x80, +0x01, 0x00, 0x00, 0x80, +0xe6, 0x18, 0xc5, 0x03, +0xac, 0x0e, 0x00, 0x00, +0x01, 0x9d, 0x13, 0x00, +0xff, 0xff, 0x0f, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x53, 0x4a, 0x6a, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x3d, 0x38, 0x25, 0x83, +0x99, 0xf7, 0xc1, 0x7a, +0xd7, 0x2f, 0xe7, 0x7d, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x38, +0xff, 0xff, 0xff, 0x7f, +0xd9, 0x11, 0x1d, 0x0c, +0x4d, 0xdc, 0xc5, 0x67, +0xd9, 0x11, 0x1d, 0x0c, +0xa7, 0xd4, 0xee, 0x9d, +0x59, 0x2b, 0x11, 0x62, +0xe5, 0xd1, 0x95, 0x2c, +0x59, 0x11, 0xbc, 0xd6, +0xc1, 0x1c, 0xae, 0x3c, +0xf9, 0x07, 0x9c, 0x8b, +0x07, 0xf8, 0x63, 0x74, +0xe8, 0x23, 0x8b, 0x38, +0x25, 0xc5, 0x38, 0xf2, +0xf1, 0x16, 0x3c, 0x55, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x53, 0x4a, 0x6a, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x3d, 0x38, 0x25, 0x83, +0x99, 0xf7, 0xc1, 0x7a, +0xd7, 0x2f, 0xe7, 0x7d, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x38, +0xff, 0xff, 0xff, 0x7f, +0xd9, 0x11, 0x1d, 0x0c, +0x4d, 0xdc, 0xc5, 0x67, +0xd9, 0x11, 0x1d, 0x0c, +0xa7, 0xd4, 0xee, 0x9d, +0x59, 0x2b, 0x11, 0x62, +0xe5, 0xd1, 0x95, 0x2c, +0x59, 0x11, 0xbc, 0xd6, +0xc1, 0x1c, 0xae, 0x3c, +0xf9, 0x07, 0x9c, 0x8b, +0x07, 0xf8, 0x63, 0x74, +0xe8, 0x23, 0x8b, 0x38, +0x25, 0xc5, 0x38, 0xf2, +0xf1, 0x16, 0x3c, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x03, 0x03, +0x01, 0x00, 0x00, 0x00, +0x03, 0x03, 0x01, 0x00, +0x00, 0x00, 0x50, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0x07, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x92, 0xe6, 0xbb, 0x47, +0x5b, 0x0d, 0x72, 0xc4, +0x0b, 0xe3, 0xc4, 0x73, +0xb5, 0x95, 0x9e, 0x3e, +0x37, 0x5d, 0xb8, 0xaa, +0x24, 0x90, 0xef, 0x7f, +0xa5, 0x12, 0x58, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xf8, 0x7f, +0xb2, 0x61, 0x8d, 0x17, +0x55, 0xef, 0x95, 0x01, +0x55, 0x21, 0xd4, 0x7c, +0x55, 0xef, 0x95, 0x01, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xab, 0xf7, 0x9d, 0x5a, +0x67, 0x58, 0xff, 0x22, +0x2f, 0x4f, 0x01, 0x3a, +0x67, 0x58, 0xff, 0x22, +0xf5, 0xff, 0xff, 0x3f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x92, 0xe6, 0xbb, 0x47, +0x5b, 0x0d, 0x72, 0xc4, +0x0b, 0xe3, 0xc4, 0x73, +0xb5, 0x95, 0x9e, 0x3e, +0x37, 0x5d, 0xb8, 0xaa, +0x24, 0x90, 0xef, 0x7f, +0xa5, 0x12, 0x58, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xf8, 0x7f, +0xb2, 0x61, 0x8d, 0x17, +0x55, 0xef, 0x95, 0x01, +0x55, 0x21, 0xd4, 0x7c, +0x55, 0xef, 0x95, 0x01, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xab, 0xf7, 0x9d, 0x5a, +0x67, 0x58, 0xff, 0x22, +0x2f, 0x4f, 0x01, 0x3a, +0x67, 0x58, 0xff, 0x22, +0xf5, 0xff, 0xff, 0x3f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x02, 0x00, 0x01, +0x00, 0x02, 0x00, 0x01, +0xd9, 0x89, 0x14, 0x00, +0x4f, 0xec, 0xd6, 0x7f, +0xd9, 0x89, 0x14, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xce, 0x19, 0x8f, 0x0d, +0xaf, 0xb1, 0xa7, 0x0c, +0xaf, 0xb1, 0xa7, 0x0c, +0x91, 0x49, 0xc0, 0x0b, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x32, 0xaf, 0x8d, 0x19, +0x64, 0x5e, 0x1b, 0x33, +0x1e, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x10, 0x00, +0x00, 0x02, 0x00, 0x00, +0x00, 0x00, 0x20, 0x01, +0x00, 0x00, 0x20, 0x00, +0x00, 0x00, 0x04, 0x00, +0x00, 0x00, 0xaf, 0x00, +0x67, 0x7b, 0x49, 0x00, +0x00, 0x00, 0x00, 0x02, +0x00, 0x0f, 0x00, 0x00, +0xe3, 0x04, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x28, 0x00, +0x00, 0x00, 0x50, 0x00, +0x00, 0x80, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x68, 0x22, 0x14, 0x12, +0x91, 0x49, 0xc0, 0x0b, +0xff, 0xff, 0xff, 0x7f, +0x30, 0x86, 0x05, 0x00, +0xa8, 0x82, 0xc3, 0x54, +0xea, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x04, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, +0xe4, 0x04, 0x00, 0x00, +0x0c, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x30, 0x0c, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x0b, 0xf4, 0xd2, 0x00, +0xc6, 0xe3, 0xc4, 0x00, +0xc6, 0xe3, 0xc4, 0x00, +0xc6, 0xe3, 0xc4, 0x00, +0x00, 0x00, 0x00, 0x60, +0xff, 0xff, 0xff, 0x7f, +0x4a, 0xed, 0x87, 0x64, +0xff, 0xff, 0xff, 0x7f, +0xa0, 0x04, 0x00, 0x00, +0xe7, 0x5f, 0xfe, 0xff, +0xb0, 0x05, 0x5b, 0x00, +0x56, 0x55, 0x55, 0xf5, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x40, +0xff, 0xff, 0xff, 0x1f, +0xdf, 0x59, 0x37, 0x5f, +0xff, 0xff, 0xff, 0x5f, +0x0b, 0xb9, 0x58, 0x00, +0x00, 0x00, 0x00, 0x10, +0xaa, 0xaa, 0xaa, 0x2a, +0x99, 0x99, 0x99, 0x19, +0x92, 0x24, 0x49, 0x12, +0x8e, 0xe3, 0x38, 0x0e, +0xba, 0xe8, 0xa2, 0x0b, +0x89, 0x9d, 0xd8, 0x09, +0x88, 0x88, 0x88, 0x08, +0x87, 0x87, 0x87, 0x07, +0x29, 0xf6, 0x96, 0x37, +0xaa, 0xaa, 0xaa, 0x2a, +0x99, 0x99, 0x99, 0x19, +0x92, 0x24, 0x49, 0x12, +0x8e, 0xe3, 0x38, 0x0e, +0xba, 0xe8, 0xa2, 0x0b, +0x89, 0x9d, 0xd8, 0x09, +0x88, 0x88, 0x88, 0x08, +0x87, 0x87, 0x87, 0x07, +0xa6, 0xf6, 0x43, 0x32, +0x4d, 0xed, 0x87, 0x64, +0xa7, 0xf6, 0x43, 0x32, +0x59, 0x09, 0xbc, 0xcd, +0x00, 0x00, 0x00, 0x08, +0x78, 0x78, 0x78, 0x00, +0xc0, 0x09, 0x9c, 0x00, +0x20, 0x0d, 0xd2, 0x00, +0x12, 0xe4, 0x29, 0x01, +0x71, 0x1c, 0xc7, 0x01, +0xc3, 0x30, 0x0c, 0x03, +0x66, 0x66, 0x66, 0x06, +0x55, 0x55, 0x55, 0x15, +0x00, 0x00, 0x00, 0x08, +0x88, 0x88, 0x88, 0x00, +0x40, 0x0b, 0xb4, 0x00, +0x0f, 0x3e, 0xf8, 0x00, +0xc1, 0x16, 0x6c, 0x01, +0x92, 0x24, 0x49, 0x02, +0x44, 0x44, 0x44, 0x04, +0xaa, 0xaa, 0xaa, 0x0a, +0xff, 0xff, 0xff, 0x3f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x40, 0x00, +0x00, 0x00, 0xf8, 0x7f, +0x00, 0x80, 0xea, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xf2, 0x7f, +0x00, 0x80, 0xea, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x00, +0x00, 0x80, 0xe1, 0x7f, +0x87, 0x0d, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xb2, 0x61, 0x8d, 0x17, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0xc4, 0x41, 0x16, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x10, 0x12, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0xd0, 0x1d, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0xd0, 0x1d, +0x9d, 0x52, 0xf2, 0x83, +0xd5, 0xf8, 0x66, 0x7b, +0x73, 0x4b, 0x59, 0x7f, +0xcf, 0xe8, 0x4d, 0x00, +0x63, 0x2e, 0x64, 0x7f, +0xcf, 0xe8, 0x4d, 0x00, +0xcf, 0xe8, 0x4d, 0x00, +0x63, 0x2e, 0x64, 0x7f, +0xcf, 0xe8, 0x4d, 0x00, +0xcf, 0xe8, 0x4d, 0x00, +0x63, 0x2e, 0x64, 0x7f, +0xcf, 0xe8, 0x4d, 0x00, +0xcf, 0xe8, 0x4d, 0x00, +0x63, 0x2e, 0x64, 0x7f, +0xcf, 0xe8, 0x4d, 0x00, +0x7a, 0x55, 0xd1, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xc5, 0x29, 0x99, 0x3a, +0x02, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x96, 0xe3, 0x8e, 0xb9, +0xfd, 0xd8, 0xa4, 0x7f, +0x6d, 0x43, 0xcc, 0x46, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x0e, 0x0f, 0x0f, 0x2f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x92, 0xe6, 0xbb, 0x47, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x67, 0x58, 0xff, 0x22, +0x2f, 0x4f, 0x01, 0x3a, +0x67, 0x58, 0xff, 0x22, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x7d, 0x00, 0x00, 0x00, +0x02, 0xf1, 0x00, 0x00, +0x6e, 0x86, 0x7d, 0x00, +0x0a, 0x00, 0x00, 0x00, +0x02, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, +0x01, 0x03, 0x00, 0x01, +0x00, 0x00, 0x0c, 0x00, +0xd1, 0x07, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x1b, 0x0d, 0x29, 0x00, +0xcb, 0xe5, 0xad, 0x7f, +0x1b, 0x0d, 0x29, 0x00, +0x37, 0x5d, 0xb8, 0xaa, +0xa5, 0x12, 0x58, 0x55, +0xd7, 0x94, 0x40, 0xb1, +0x1f, 0x21, 0xbc, 0x79, +0x09, 0x4a, 0x03, 0x55, +0x2d, 0x3e, 0x00, 0x00, +0x14, 0x05, 0x01, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xfe, 0x03, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0x34, 0x04, 0x00, 0x00, +0x50, 0x04, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0x78, 0x04, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0xae, 0x03, 0x00, 0x00, +0xb2, 0x04, 0x00, 0x00, +0xee, 0x04, 0x00, 0x00, +0x20, 0x05, 0x00, 0x00, +0x0c, 0x05, 0x00, 0x00, +0x54, 0x10, 0x00, 0x00, +0xf0, 0x10, 0x00, 0x00, +0x1a, 0x11, 0x00, 0x00, +0x50, 0x11, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0x84, 0x11, 0x00, 0x00, +0xac, 0x11, 0x00, 0x00, +0xce, 0x11, 0x00, 0x00, +0xce, 0x11, 0x00, 0x00, +0xb0, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x6c, 0x09, 0xf9, 0xe8, +0x03, 0x56, 0x0e, 0x41, +0x51, 0xb8, 0x1e, 0x05, +0x32, 0x08, 0xac, 0xe4, +0x83, 0xd3, 0x82, 0x41, +0x66, 0x66, 0x66, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xfe, 0x90, 0x0c, 0x00, +0xfb, 0x21, 0x19, 0x00, +0xff, 0xff, 0xff, 0x1f, +0x4b, 0x37, 0x89, 0x61, +0xb4, 0xc8, 0x76, 0x1e, +0x4d, 0xed, 0x87, 0x64, +0xb3, 0x12, 0x78, 0x9b, +0xa9, 0xf6, 0x43, 0x32, +0x51, 0xed, 0x87, 0x64, +0xd8, 0x82, 0x2d, 0x00, +0xab, 0xaa, 0xaa, 0xfa, +0x00, 0x00, 0x00, 0x40, +0xe1, 0xdb, 0xa5, 0x1c, +0x4c, 0xff, 0x7f, 0x16, +0x98, 0xfe, 0xff, 0x2c, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; + +const unsigned char CcUpdataCode128_01_01[] = { +0x5c, 0x81, 0x02, 0xbf, 0xb0, +0x68, 0x01, 0x01, 0xc5, 0xac, +0xa4, 0x00, 0x08, 0x00, 0x6c, +0x80, 0x06, 0xc6, 0x80, 0x20, +0x01, 0x12, 0x18, 0x00, 0x61, +0x80, 0x06, 0x16, 0x80, 0x10, +0x1c, 0x22, 0x18, 0x00, 0x61, +0x68, 0x02, 0x00, 0x08, 0xac, +0x80, 0x06, 0xc8, 0x00, 0x61, +0x80, 0x06, 0x16, 0x80, 0x10, +0x1d, 0x02, 0xc6, 0x80, 0x00, +0x02, 0x62, 0x16, 0x00, 0x00, +0x00, 0x03, 0x98, 0x40, 0x6c, +0xa0, 0x50, 0x08, 0x00, 0x08, +0x80, 0x84, 0x80, 0x00, 0x00, +0x64, 0x00, 0x80, 0x0d, 0x0f, +0x40, 0x00, 0x02, 0x80, 0x50, +0x76, 0x00, 0x00, 0x10, 0x60, +0x5c, 0x01, 0x20, 0x40, 0x0a, +0x68, 0x38, 0x1c, 0x03, 0x21, +0xa0, 0x46, 0x06, 0x80, 0x20, +0x00, 0xc2, 0xc8, 0x40, 0x6c, +0x46, 0x0a, 0x40, 0x48, 0x4a, +0x84, 0x8c, 0x80, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x08, +0x38, 0x13, 0xe2, 0x59, 0xa0, +0xbc, 0x0d, 0x07, 0x60, 0x00, +0x01, 0x0a, 0x0a, 0x04, 0x61, +0x84, 0x80, 0xa8, 0x40, 0x08, +0x54, 0x4d, 0x22, 0x04, 0xa1, +0x68, 0x01, 0x01, 0xba, 0x2c, +0x46, 0x0a, 0x40, 0x40, 0x48, +0x84, 0x86, 0xc0, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x76, 0x00, 0x00, 0x10, 0xa1, +0x5c, 0x08, 0xb0, 0x48, 0x08, +0x76, 0x00, 0x00, 0x10, 0x22, +0x25, 0x9a, 0x0b, 0xc0, 0x58, +0xa0, 0xca, 0x17, 0x60, 0x05, +0x00, 0x82, 0x0b, 0xc0, 0x2f, +0x85, 0x06, 0x08, 0x50, 0x60, +0x68, 0x02, 0x00, 0x16, 0x20, +0xba, 0x14, 0x88, 0x48, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +0x76, 0x00, 0x00, 0x10, 0x81, +0x5c, 0x81, 0x02, 0x08, 0x02, +0x5c, 0x00, 0x48, 0x08, 0x02, +0x55, 0x3e, 0x93, 0x01, 0x38, +0x51, 0x48, 0xa2, 0xc0, 0x41, +0x2a, 0x06, 0x37, 0x60, 0x00, +0x01, 0x06, 0x02, 0xe8, 0x5c, +0x68, 0x38, 0x1c, 0x03, 0x23, +0x62, 0x00, 0x00, 0x01, 0xd4, +0x5c, 0x00, 0x92, 0x18, 0x23, +0x5c, 0x02, 0x0b, 0x00, 0x83, +0xa0, 0x00, 0x48, 0x22, 0x88, +0x86, 0x02, 0x56, 0xc7, 0x03, +0x80, 0x64, 0x86, 0x00, 0x01, +0x00, 0x04, 0x08, 0x58, 0x52, +0x00, 0x00, 0x08, 0x28, 0x0a, +0x6c, 0x70, 0x38, 0x02, 0x4a, +0x00, 0x00, 0x08, 0x60, 0x65, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x83, 0x0b, 0xff, 0xc0, +0x85, 0x85, 0x10, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x83, 0x0b, 0xff, 0xc0, +0x28, 0x0e, 0x48, 0x40, 0x48, +0xa0, 0xc6, 0x08, 0x40, 0x02, +0x85, 0x08, 0x05, 0x44, 0x40, +0x20, 0xca, 0x06, 0x80, 0x10, +0x1b, 0xa2, 0xc4, 0x60, 0xa4, +0x05, 0x0d, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x00, 0x09, 0x21, +0x00, 0x00, 0x0a, 0x0c, 0x62, +0x85, 0x00, 0x05, 0x53, 0xc1, +0x04, 0x82, 0x12, 0x2f, 0xd4, +0x2a, 0x8e, 0x02, 0x80, 0x10, +0x22, 0x88, 0x46, 0x20, 0x00, +0x00, 0x04, 0x26, 0xc0, 0x00, +0x16, 0x64, 0x85, 0xc8, 0x04, +0x20, 0x81, 0x19, 0x48, 0x08, +0x94, 0x04, 0x00, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0xab, 0xff, 0x08, 0x80, 0x76, +0x68, 0x00, 0x00, 0x2f, 0x20, +0x66, 0x00, 0x80, 0x09, 0x60, +0x68, 0x00, 0x00, 0x2f, 0x20, +0x5c, 0x08, 0xa0, 0x80, 0x36, +0x76, 0x00, 0x00, 0x10, 0xa0, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0xab, 0xff, 0x08, 0x80, 0x76, +0x68, 0x00, 0x00, 0x6f, 0x20, +0x66, 0x00, 0x80, 0x09, 0x60, +0x68, 0x00, 0x00, 0x6f, 0x20, +0x5c, 0x08, 0xe0, 0x80, 0x36, +0x76, 0x00, 0x00, 0x08, 0xa0, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x39, 0x02, 0x06, 0x80, 0x20, +0x03, 0x72, 0xc8, 0x00, 0x7a, +0x6c, 0x00, 0x00, 0x26, 0x6c, +0x46, 0x0a, 0x40, 0x00, 0x7a, +0x84, 0x07, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x00, 0x12, 0x20, +0x00, 0x00, 0x09, 0x40, 0xac, +0x32, 0x02, 0x0b, 0xc1, 0xe0, +0x32, 0x06, 0x0b, 0xc1, 0x80, +0x32, 0x0a, 0x0b, 0xc1, 0x20, +0x32, 0x12, 0x0b, 0xc0, 0xc0, +0x32, 0x16, 0x0b, 0xc0, 0x60, +0x32, 0x1a, 0x0b, 0xc1, 0x89, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x21, 0x27, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x1b, 0xc7, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x26, 0xc7, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x17, 0x67, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x13, 0x87, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x10, 0x67, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x84, 0x10, 0x05, 0x90, 0x40, +0x2b, 0xfe, 0x08, 0x80, 0x76, +0x42, 0x0a, 0x42, 0x00, 0x01, +0xa4, 0x04, 0x08, 0x4a, 0xa1, +0x66, 0x00, 0x40, 0x3b, 0x68, +0xa0, 0x81, 0x18, 0x81, 0x00, +0x23, 0x84, 0x46, 0x80, 0x00, +0x7f, 0xfc, 0x02, 0x88, 0x20, +0x68, 0x00, 0x05, 0xff, 0xc2, +0x30, 0x88, 0x0b, 0xc1, 0x83, +0x68, 0x02, 0x08, 0x00, 0x02, +0x28, 0x08, 0x46, 0xc0, 0x00, +0x35, 0x44, 0x8b, 0xc1, 0x27, +0x6c, 0x00, 0x03, 0x54, 0x00, +0x68, 0x3d, 0xf8, 0x00, 0x02, +0x54, 0x04, 0x22, 0x08, 0xc1, +0x51, 0x83, 0x02, 0x0c, 0x62, +0x84, 0x82, 0x18, 0x81, 0x50, +0x40, 0x00, 0x00, 0x80, 0xe2, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x00, 0x80, 0xa0, +0x00, 0x00, 0x08, 0x40, 0x50, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x5c, 0x80, 0x80, 0x41, 0x00, +0x32, 0x08, 0x0b, 0xc2, 0x28, +0x6c, 0x00, 0x03, 0x54, 0x24, +0x6c, 0x00, 0x00, 0x0c, 0x00, +0x55, 0x3c, 0x00, 0x42, 0xa0, +0x22, 0xfc, 0x42, 0xa8, 0xe2, +0x28, 0x08, 0x02, 0x28, 0x86, +0x32, 0x03, 0x0b, 0xc2, 0x9d, +0x5c, 0x80, 0x4a, 0x00, 0x10, +0x62, 0x00, 0x00, 0x00, 0xf6, +0x38, 0x10, 0x40, 0x00, 0x00, +0x94, 0x08, 0x85, 0x04, 0x80, +0x14, 0x08, 0xa5, 0x04, 0x89, +0x14, 0x08, 0x95, 0x04, 0x85, +0x94, 0x08, 0x92, 0x32, 0x12, +0x29, 0x08, 0x02, 0x09, 0x09, +0x23, 0x41, 0xb2, 0x36, 0x0a, +0x29, 0x0c, 0x02, 0x90, 0x80, +0xbb, 0x10, 0x0b, 0xc1, 0x37, +0x5c, 0x80, 0x4a, 0x00, 0xc0, +0x5c, 0x01, 0x0b, 0xb0, 0x80, +0x51, 0xd0, 0x98, 0x40, 0x21, +0x51, 0xe0, 0x81, 0x83, 0x8a, +0x51, 0xf0, 0x91, 0x48, 0xc6, +0x98, 0x3c, 0x3a, 0x08, 0x02, +0x98, 0x30, 0x09, 0x48, 0xc3, +0x98, 0x38, 0x89, 0x50, 0xe0, +0xa0, 0x46, 0x09, 0x48, 0xe4, +0x84, 0x05, 0x1b, 0xa1, 0x48, +0x6c, 0x00, 0x03, 0x54, 0x64, +0x40, 0x00, 0x03, 0x80, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xfe, 0x0b, 0xc1, 0x38, +0x88, 0x07, 0x6a, 0x00, 0xa0, +0xa0, 0x48, 0x18, 0x40, 0x20, +0x88, 0x0e, 0x1a, 0x00, 0x11, +0x66, 0x00, 0x40, 0x3b, 0x68, +0xa4, 0x04, 0x08, 0x81, 0x08, +0xb0, 0x7f, 0xe5, 0x44, 0xd2, +0x08, 0x0a, 0x06, 0xc0, 0x00, +0x35, 0x64, 0x86, 0x80, 0x20, +0x06, 0x62, 0x1b, 0xc0, 0x6f, +0x84, 0x06, 0x10, 0x00, 0x00, +0x6c, 0x00, 0x03, 0x56, 0x08, +0x2a, 0x06, 0x48, 0x41, 0xc8, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x68, 0x00, 0x00, 0x0a, 0x22, +0x5c, 0x00, 0x40, 0x40, 0x82, +0x51, 0x44, 0xa2, 0x14, 0xa1, +0x2a, 0x06, 0x22, 0xe8, 0x13, +0x62, 0x00, 0x00, 0x00, 0xd3, +0x5c, 0x80, 0x88, 0x40, 0x24, +0x5c, 0x80, 0x40, 0x50, 0x22, +0xbb, 0x04, 0x15, 0x1d, 0x04, +0x18, 0x34, 0xa5, 0x1e, 0x05, +0x18, 0x30, 0x05, 0x1f, 0x04, +0x95, 0x04, 0x69, 0x83, 0x82, +0x95, 0x04, 0x09, 0x83, 0x48, +0x95, 0x04, 0x29, 0x50, 0x44, +0x6c, 0x00, 0x03, 0x54, 0x64, +0x68, 0x01, 0x00, 0xed, 0x2c, +0x46, 0x0a, 0x40, 0x41, 0x7a, +0x84, 0x86, 0xc0, 0x00, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0x7a, 0x21, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x00, 0x07, 0x00, 0x08, +0x5c, 0x01, 0x30, 0x40, 0x48, +0x5c, 0x09, 0xe2, 0x00, 0x20, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x00, +0x25, 0x90, 0x0b, 0xff, 0xc0, +0x68, 0x00, 0x08, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x06, 0x50, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x00, +0x25, 0x90, 0x0b, 0xff, 0xc0, +0x68, 0x00, 0x09, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x06, 0x50, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x93, 0x0b, 0xff, 0xc0, +0x6c, 0x00, 0x03, 0x58, 0x7a, +0x68, 0x01, 0x00, 0xed, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x00, 0xa6, 0x00, 0x00, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0x8f, 0xa1, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x02, 0x08, 0x00, 0x24, +0x68, 0x00, 0x07, 0x00, 0x09, +0x5c, 0x09, 0xe3, 0x00, 0x16, +0x60, 0x00, 0xc0, 0x01, 0x80, +0x5c, 0x02, 0x3a, 0xc0, 0x10, +0x5c, 0x04, 0x02, 0x00, 0x20, +0x60, 0x00, 0x10, 0x00, 0x20, +0x6c, 0x70, 0x38, 0x06, 0x49, +0x84, 0x04, 0xab, 0xb0, 0x80, +0x6c, 0x70, 0x38, 0x02, 0x4e, +0x40, 0x00, 0x03, 0xc0, 0x27, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xa0, +0x84, 0x04, 0xb0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xc0, +0x28, 0x02, 0xd6, 0xc0, 0x00, +0x35, 0x87, 0xa6, 0x80, 0x10, +0x0e, 0xd2, 0x0b, 0xa1, 0x48, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0xa6, 0x21, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x00, 0x07, 0x00, 0x08, +0x5c, 0xbf, 0x00, 0x40, 0x48, +0x5c, 0x00, 0x71, 0xc0, 0x00, +0x68, 0x00, 0x02, 0xff, 0xc8, +0x5c, 0x08, 0x20, 0x40, 0x48, +0x40, 0x00, 0x00, 0x41, 0x4a, +0x68, 0x02, 0x08, 0x00, 0x24, +0x60, 0x0b, 0xf0, 0x00, 0x4f, +0x6c, 0x70, 0x38, 0x00, 0x0a, +0x50, 0xc9, 0x82, 0xc0, 0x10, +0x6c, 0x70, 0x38, 0x00, 0x0a, +0x50, 0xc9, 0x83, 0xb1, 0x00, +0x6c, 0x00, 0x03, 0x58, 0x7a, +0x68, 0x01, 0x00, 0xed, 0x20, +0xbb, 0x10, 0x0b, 0xa1, 0x48, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +}; + +#define VERNUM_01_01 0x0001120002 +#define CAL_ID_01_01 0x0000000102 diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_02_01_00.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_02_01_00.h new file mode 100755 index 0000000000000000000000000000000000000000..aff2022b69a00108e6f4f074efa037d95ee6c97c --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_02_01_00.h @@ -0,0 +1,7442 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * @brief LC898128 OIS PRODUCT + * + * @author Copyright (C) 2018 ON Semiconductor All Rights Reserved. + * + **/ + +/* Version Name : "01-31-2018" */ +/* Time Stamp : 2020/05/22 18:42:29 */ + +#define FromCodeBlockSize_01_02_01_00 7 + +#define FromCheckSumSize_01_02_01_00 0x00001b8e +#define FromCheckSum_01_02_01_00 0xdbef202e + +#define UpDataCodeSize_01_02_01_00 0x0000015e +#define UpDataCodeCheckSum_01_02_01_00 0x00007a7a646642d9 + +/* [00011b020b] [00003801ff] [0000000000] [0000000000] */ + +/*#define SELECT_VENDOR 1 */ +/*#define SEL_MODEL 2 */ +/*#define SELECT_ACT 1 */ +/*#define MASTER_SLAVE 0 */ + +const unsigned char CcFromCode128_01_02_01_00[] = { +0x00, 0x01, 0x02, 0x03, +0x04, 0x05, 0x06, 0x07, +0xbc, 0x13, 0x00, 0x00, +0x66, 0x03, 0x33, 0xb3, +0x9a, 0x38, 0x07, 0x00, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, + +0x64, 0x00, 0x00, 0x03, +0x87, 0x64, 0x00, 0x00, +0x2b, 0x87, 0x64, 0x00, +0x00, 0x2f, 0x07, 0x64, +0x00, 0x00, 0x33, 0x27, +0x64, 0x00, 0x00, 0x33, +0x47, 0x46, 0x0b, 0x03, +0x80, 0x00, 0x64, 0x00, +0x00, 0x36, 0x27, 0x64, +0x00, 0x00, 0x36, 0x47, +0x46, 0x0b, 0x03, 0x80, +0x00, 0x64, 0x00, 0x00, +0x36, 0x67, 0x64, 0x00, +0x00, 0x36, 0x87, 0x64, +0x00, 0x00, 0x36, 0xa7, +0x64, 0x00, 0x00, 0x36, +0xc7, 0x46, 0x0b, 0x03, +0x80, 0x00, 0x64, 0x00, +0x00, 0x36, 0xe7, 0x46, +0x0b, 0x03, 0x80, 0x00, +0x00, 0x22, 0x05, 0x20, +0x20, 0x00, 0x00, 0x18, +0x42, 0x29, 0x00, 0x00, +0x00, 0x00, 0x03, 0x00, +0x00, 0x00, 0x18, 0xb3, +0x00, 0x00, 0x00, 0x07, +0xa8, 0x00, 0x00, 0x00, +0x02, 0xd8, 0x00, 0x00, +0x00, 0x18, 0xb6, 0x00, +0x00, 0x80, 0x00, 0x7c, +0x00, 0x01, 0x1b, 0x02, +0x0b, 0x00, 0x00, 0x38, +0x01, 0xff, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xba, 0x11, 0x2b, 0xa1, +0x13, 0x68, 0x00, 0x04, +0x00, 0x38, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x34, 0x00, 0x09, 0x20, +0x5c, 0x81, 0x01, 0x8e, +0xb9, 0x5c, 0x01, 0x03, +0x06, 0x02, 0x84, 0x05, +0x2a, 0x00, 0x20, 0xb0, +0x42, 0x28, 0x00, 0x52, +0x84, 0x05, 0x0a, 0x05, +0x60, 0x68, 0x00, 0x05, +0x07, 0x00, 0x84, 0x05, +0x0a, 0x03, 0x60, 0x68, +0x00, 0xc5, 0x8f, 0xc0, +0x84, 0x05, 0x06, 0x60, +0x00, 0x02, 0xac, 0x8a, +0xbf, 0xc0, 0x68, 0x20, +0x00, 0x00, 0x21, 0x68, +0x00, 0x00, 0x0c, 0x20, +0x40, 0x00, 0x01, 0x88, +0x49, 0x66, 0x00, 0x00, +0x46, 0x08, 0x5c, 0x00, +0xb1, 0x88, 0x08, 0x66, +0x00, 0x00, 0x56, 0x40, +0x66, 0x00, 0x01, 0x04, +0xe0, 0x68, 0x3a, 0x9a, +0xc2, 0xe0, 0x6c, 0x68, +0x08, 0x0e, 0x60, 0x40, +0x00, 0x03, 0x07, 0xf8, +0x6c, 0x40, 0x05, 0x22, +0x50, 0x68, 0x00, 0x00, +0x04, 0x20, 0x68, 0x20, +0x03, 0xa0, 0x21, 0x66, +0x00, 0x00, 0x95, 0x80, +0x66, 0x00, 0x00, 0x38, +0xa0, 0x66, 0x00, 0x00, +0x39, 0xc0, 0x38, 0x18, +0x06, 0xc7, 0x02, 0x84, +0xc5, 0x06, 0x80, 0x00, +0x00, 0x8b, 0x9b, 0xa1, +0x10, 0x40, 0x00, 0x03, +0x80, 0x00, 0x66, 0x00, +0x00, 0x59, 0x80, 0x66, +0x00, 0x00, 0x37, 0x00, +0x66, 0x00, 0x00, 0x59, +0xa0, 0x66, 0x00, 0x02, +0x67, 0x80, 0x66, 0x00, +0x01, 0x05, 0x80, 0x66, +0x00, 0x02, 0x40, 0xc0, +0x66, 0x00, 0x01, 0x6e, +0xc0, 0x68, 0x20, 0x00, +0x04, 0x20, 0x66, 0x00, +0x00, 0x8a, 0x20, 0x66, +0x00, 0x00, 0x69, 0x20, +0x68, 0x00, 0x00, 0xc9, +0x20, 0x66, 0x00, 0x00, +0x52, 0x80, 0x68, 0x00, +0x05, 0xbf, 0xa0, 0x6c, +0x00, 0x01, 0x2e, 0x60, +0x66, 0x00, 0x02, 0x59, +0x80, 0xb0, 0x00, 0xd6, +0x60, 0x00, 0x05, 0xc4, +0x8b, 0x00, 0x8c, 0x5c, +0x08, 0x11, 0x8e, 0x40, +0x68, 0x00, 0x00, 0x05, +0x20, 0x52, 0x04, 0x03, +0xc0, 0x4f, 0x5c, 0x81, +0x01, 0x84, 0x39, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x06, 0x1a, +0x00, 0x32, 0xa0, 0x0b, +0xff, 0xa1, 0x80, 0x22, +0x1b, 0xa0, 0x98, 0x6c, +0x00, 0x06, 0x1a, 0x7a, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x00, +0xc9, 0x20, 0x66, 0x00, +0x00, 0x53, 0x80, 0x6c, +0x00, 0x06, 0x1a, 0x00, +0x32, 0x80, 0x0b, 0xc0, +0x49, 0x40, 0x00, 0x03, +0x07, 0xf8, 0x46, 0x0e, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x00, 0x02, 0x02, +0x28, 0x81, 0x23, 0x00, +0x10, 0x68, 0x00, 0x00, +0x05, 0x20, 0xbf, 0xe3, +0x83, 0x90, 0x20, 0x6e, +0x40, 0x00, 0x08, 0x38, +0x68, 0x00, 0x20, 0x00, +0x02, 0x28, 0x88, 0x03, +0x20, 0x00, 0xbc, 0x09, +0x16, 0xc0, 0x00, 0x01, +0x80, 0x05, 0xc0, 0xe8, +0xb0, 0x1c, 0x22, 0x40, +0x40, 0x52, 0x04, 0x03, +0x80, 0x00, 0x6c, 0x00, +0x00, 0x18, 0x50, 0x66, +0x00, 0x02, 0x17, 0x80, +0x66, 0x00, 0x02, 0x27, +0xe0, 0x68, 0x20, 0x02, +0x33, 0xa0, 0x68, 0x00, +0x1d, 0xdd, 0xc0, 0x5c, +0x80, 0x82, 0xc6, 0x41, +0x5c, 0x0f, 0xd1, 0x40, +0x50, 0x5c, 0x09, 0x09, +0x40, 0x50, 0x68, 0x00, +0x1d, 0xc0, 0x03, 0x94, +0x0d, 0x39, 0x40, 0x50, +0x94, 0x05, 0x0a, 0xcc, +0xd0, 0x6c, 0x00, 0x00, +0x18, 0x00, 0x52, 0x44, +0x01, 0x42, 0x53, 0x6c, +0x00, 0x00, 0x18, 0x50, +0x88, 0x06, 0x00, 0x00, +0x00, 0x6c, 0x40, 0x02, +0xbc, 0x08, 0x6c, 0x40, +0x02, 0x06, 0x09, 0x6c, +0x40, 0x00, 0x32, 0x00, +0x6c, 0x40, 0x01, 0x50, +0x48, 0x6c, 0x40, 0x01, +0x80, 0x48, 0x6c, 0x40, +0x00, 0x78, 0x49, 0x6c, +0x40, 0x00, 0xc6, 0x49, +0x32, 0x00, 0x0b, 0xc0, +0x68, 0x5c, 0x81, 0x08, +0x40, 0x00, 0x6c, 0x40, +0x00, 0x34, 0x02, 0x32, +0x01, 0x0b, 0xc0, 0xd1, +0x68, 0x20, 0x02, 0x01, +0x24, 0x24, 0x84, 0x08, +0x20, 0xd0, 0x88, 0x0e, +0x46, 0x60, 0x00, 0x23, +0xe4, 0x08, 0x80, 0xa0, +0x66, 0x00, 0x02, 0x3e, +0x48, 0x76, 0x00, 0x00, +0x06, 0x64, 0xbc, 0x03, +0x72, 0x40, 0x40, 0x6c, +0x40, 0x04, 0x02, 0x50, +0x5c, 0x0b, 0x11, 0x8e, +0x80, 0x5c, 0x80, 0x40, +0x80, 0x20, 0x6c, 0x00, +0x06, 0x22, 0x01, 0x59, +0x00, 0x40, 0x40, 0x01, +0x24, 0x88, 0x98, 0x40, +0x51, 0xa0, 0x43, 0x89, +0x40, 0x40, 0x42, 0x03, +0x41, 0x40, 0x40, 0x5c, +0x00, 0x51, 0x40, 0x60, +0x40, 0x00, 0x03, 0xc0, +0x4f, 0x6c, 0x00, 0x03, +0x5a, 0x7a, 0x6c, 0x00, +0x03, 0x5a, 0x52, 0x68, +0x38, 0x08, 0x10, 0x20, +0x6c, 0x00, 0x03, 0x5c, +0x7a, 0x5c, 0x87, 0x02, +0x00, 0x20, 0x88, 0x06, +0x0a, 0x00, 0x20, 0xa0, +0x02, 0x18, 0x80, 0xe0, +0xa0, 0x04, 0x08, 0x81, +0xe0, 0xa0, 0x02, 0x08, +0x81, 0x61, 0xa0, 0x82, +0x18, 0x82, 0xe0, 0x6c, +0x00, 0x03, 0x5e, 0x7a, +0x88, 0x26, 0x16, 0x80, +0x00, 0x00, 0xc2, 0x0b, +0xc0, 0x4f, 0x5c, 0x0e, +0x93, 0x00, 0x18, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x06, 0x1a, +0x01, 0x32, 0xa0, 0x8b, +0xff, 0xa1, 0xa0, 0x00, +0x18, 0x02, 0x01, 0x25, +0x88, 0x8b, 0xc0, 0xc9, +0x88, 0x36, 0x02, 0x48, +0x8a, 0x6c, 0x40, 0x00, +0x46, 0x50, 0x68, 0x00, +0x04, 0xa4, 0xa4, 0x68, +0x00, 0x06, 0xa2, 0x20, +0x42, 0x02, 0x78, 0x0a, +0x52, 0x40, 0x00, 0x00, +0x48, 0x64, 0x68, 0x00, +0x06, 0xa2, 0x20, 0x98, +0x80, 0x26, 0xc0, 0x00, +0x12, 0xe0, 0x03, 0x00, +0x80, 0x68, 0x00, 0x05, +0xbf, 0xa0, 0xbc, 0x91, +0x89, 0x88, 0x02, 0x30, +0x08, 0x06, 0x80, 0x00, +0x6a, 0xea, 0x0b, 0xc3, +0xc8, 0x98, 0x80, 0x23, +0x00, 0x80, 0x68, 0x00, +0x06, 0x17, 0x20, 0xbc, +0x1b, 0x89, 0x88, 0x02, +0x30, 0x08, 0x0b, 0xcf, +0xc1, 0x6c, 0x40, 0x00, +0x02, 0x00, 0xb0, 0x7f, +0xa2, 0x88, 0x80, 0x32, +0x08, 0x0b, 0xcf, 0x61, +0x6e, 0x00, 0x06, 0x0e, +0x28, 0x38, 0x18, 0xa3, +0x00, 0x80, 0xbc, 0x05, +0x16, 0xe0, 0x00, 0x60, +0xea, 0x83, 0x20, 0x80, +0x40, 0x00, 0x03, 0xce, +0xc0, 0x6c, 0x00, 0x03, +0x5c, 0x00, 0x6c, 0x00, +0x03, 0x5e, 0x50, 0x66, +0x00, 0x00, 0xc5, 0x20, +0x40, 0x00, 0x03, 0xce, +0x47, 0x6c, 0x00, 0x03, +0x5c, 0x00, 0x6c, 0x40, +0x01, 0xda, 0x02, 0x55, +0x02, 0x03, 0x00, 0x14, +0x30, 0x08, 0x0b, 0xc0, +0x4a, 0x6c, 0x00, 0x03, +0x5c, 0x50, 0x6c, 0x00, +0x03, 0x5c, 0x7a, 0x66, +0x00, 0x00, 0x5f, 0x68, +0x40, 0x00, 0x03, 0x00, +0x2d, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x84, +0x03, 0x07, 0x80, 0xa0, +0x80, 0x09, 0x48, 0x40, +0xb0, 0x01, 0x59, 0x8e, +0x8a, 0x66, 0x00, 0x00, +0x61, 0xc8, 0xb0, 0x00, +0xcb, 0xcc, 0x87, 0x6c, +0x40, 0x00, 0x02, 0x00, +0xb0, 0x7f, 0xa2, 0x88, +0x80, 0x32, 0x00, 0x0b, +0xc3, 0xa0, 0x32, 0x08, +0x0b, 0xc2, 0x80, 0x32, +0x0c, 0x0b, 0xc1, 0x60, +0x32, 0x18, 0x0b, 0xcb, +0xc1, 0xb0, 0x02, 0xd6, +0x60, 0x00, 0x05, 0xf6, +0x8b, 0x00, 0x14, 0x68, +0x00, 0x03, 0x03, 0x21, +0x5c, 0x84, 0x03, 0x04, +0x60, 0xa0, 0x80, 0x09, +0x48, 0x40, 0xb0, 0x2a, +0x89, 0x40, 0xe0, 0x68, +0x00, 0x03, 0x03, 0x20, +0xb0, 0x06, 0x59, 0x8e, +0x8a, 0x66, 0x00, 0x00, +0x61, 0xc8, 0xb0, 0x01, +0x4b, 0xca, 0x87, 0xb0, +0x02, 0xd6, 0x60, 0x00, +0x05, 0xf6, 0x8b, 0x00, +0x14, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x84, +0x03, 0x06, 0x18, 0xa0, +0x80, 0x09, 0x48, 0x40, +0xb0, 0x02, 0x59, 0x8e, +0x8a, 0x66, 0x00, 0x00, +0x61, 0xc8, 0xb0, 0x00, +0xcb, 0xc9, 0x87, 0xb0, +0x02, 0xd6, 0x60, 0x00, +0x05, 0xf6, 0x8b, 0x00, +0x14, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x84, +0x03, 0x05, 0x10, 0xa0, +0x80, 0x09, 0x48, 0x40, +0xb0, 0x06, 0x59, 0x8e, +0x8a, 0x66, 0x00, 0x00, +0x61, 0xc8, 0xb0, 0x00, +0xcb, 0xc8, 0x87, 0xb0, +0x02, 0xd6, 0x60, 0x00, +0x05, 0xf6, 0x8b, 0x00, +0x54, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x84, +0x03, 0x04, 0x00, 0xa0, +0x80, 0x09, 0x48, 0x40, +0xb0, 0x07, 0x59, 0x8e, +0x8a, 0x66, 0x00, 0x00, +0x61, 0xc8, 0xb0, 0x00, +0xcb, 0xc7, 0x87, 0x6c, +0x40, 0x00, 0x02, 0x00, +0xb0, 0x7f, 0xa2, 0x88, +0x80, 0x32, 0x00, 0x0b, +0xc4, 0xc0, 0x32, 0x08, +0x0b, 0xc3, 0x00, 0x32, +0x0c, 0x0b, 0xc1, 0xe0, +0x32, 0x18, 0x0b, 0xc5, +0xd1, 0x5c, 0x81, 0x00, +0x80, 0x20, 0x6c, 0x70, +0x10, 0x20, 0x00, 0x5c, +0x82, 0x08, 0x40, 0x02, +0x5b, 0x04, 0x08, 0x40, +0x82, 0x68, 0x00, 0x01, +0x39, 0x20, 0x5c, 0x85, +0x10, 0x80, 0xa1, 0x80, +0x25, 0x08, 0x00, 0xd1, +0x80, 0x35, 0x20, 0x00, +0x00, 0x88, 0x12, 0x48, +0x48, 0x83, 0x86, 0x08, +0x05, 0xb0, 0x01, 0x20, +0x00, 0x18, 0x82, 0x25, +0x80, 0x05, 0x38, 0x48, +0xd2, 0x00, 0x00, 0x08, +0x68, 0x80, 0x84, 0x0d, +0x0b, 0xc4, 0x17, 0x6c, +0x70, 0x10, 0x20, 0x00, +0x5c, 0x81, 0x00, 0x80, +0x20, 0x68, 0x00, 0x01, +0x36, 0x21, 0x5c, 0x82, +0x08, 0x40, 0x02, 0x80, +0xa5, 0x08, 0x08, 0xd2, +0x80, 0x87, 0xaa, 0x08, +0x00, 0x80, 0x87, 0xa8, +0x40, 0xfa, 0x84, 0x8f, +0xab, 0xc3, 0x17, 0x68, +0x00, 0x01, 0x36, 0x21, +0x5c, 0x81, 0x00, 0x80, +0x20, 0x6c, 0x70, 0x10, +0x20, 0x00, 0x5c, 0x82, +0x08, 0x40, 0x02, 0x80, +0xa5, 0x08, 0x08, 0xd2, +0x00, 0x00, 0x08, 0x80, +0xa4, 0x84, 0x08, 0x08, +0x60, 0x82, 0x80, 0x85, +0x0a, 0x08, 0x04, 0x88, +0x12, 0x08, 0x08, 0x52, +0x00, 0x00, 0x08, 0x82, +0x25, 0x84, 0x08, 0x08, +0x68, 0x82, 0x86, 0x0d, +0x08, 0x48, 0xd2, 0x40, +0x00, 0x03, 0xc1, 0x77, +0x68, 0x00, 0x01, 0x38, +0x21, 0x5c, 0x81, 0x00, +0x80, 0x20, 0x6c, 0x70, +0x10, 0x20, 0x00, 0x5c, +0x84, 0x08, 0x40, 0x02, +0x80, 0x85, 0x08, 0x08, +0x52, 0x00, 0x00, 0x08, +0x80, 0xa4, 0x84, 0x08, +0x08, 0x61, 0x02, 0x80, +0xad, 0x08, 0x0a, 0x52, +0x00, 0x00, 0x08, 0x81, +0xa0, 0x88, 0x2a, 0x48, +0x40, 0x80, 0x86, 0x08, +0x28, 0x48, 0x50, 0x84, +0x95, 0x23, 0x81, 0x00, +0x6c, 0x00, 0x03, 0x5a, +0x01, 0x6c, 0x70, 0x10, +0x4e, 0x02, 0x59, 0x00, +0x43, 0x80, 0x00, 0x52, +0x40, 0x83, 0xc0, 0x48, +0x6c, 0x70, 0x10, 0x4e, +0x50, 0x66, 0x00, 0x00, +0xc4, 0x40, 0x66, 0x00, +0x01, 0xec, 0xe0, 0x6c, +0x00, 0x06, 0x1a, 0x7a, +0x66, 0x00, 0x01, 0xf3, +0x60, 0x5c, 0x81, 0x00, +0x83, 0x20, 0x6c, 0x00, +0x00, 0x7a, 0x00, 0x51, +0x42, 0x20, 0x02, 0x21, +0x6c, 0x68, 0x10, 0x00, +0x48, 0x68, 0x34, 0x08, +0x00, 0x24, 0x6c, 0x00, +0x00, 0xa2, 0x00, 0x51, +0x42, 0x23, 0xa0, 0x98, +0x86, 0x44, 0x80, 0x00, +0x00, 0x6c, 0x00, 0x01, +0x2e, 0x20, 0x40, 0x00, +0x03, 0xa0, 0x80, 0x6c, +0x00, 0x02, 0x9c, 0x20, +0x40, 0x00, 0x03, 0xa0, +0x80, 0x66, 0x00, 0x00, +0x64, 0x00, 0x6c, 0x00, +0x01, 0x78, 0x20, 0x40, +0x00, 0x03, 0xa0, 0x80, +0x68, 0x00, 0x00, 0xb4, +0x20, 0x68, 0x20, 0x00, +0xe0, 0x24, 0x68, 0x00, +0x00, 0xb8, 0x21, 0x68, +0x20, 0x00, 0xe6, 0x25, +0x68, 0x00, 0x00, 0x9e, +0x22, 0x66, 0x00, 0x02, +0x50, 0x40, 0x66, 0x00, +0x02, 0x18, 0xa0, 0x68, +0x00, 0x00, 0xc9, 0x20, +0x66, 0x00, 0x00, 0x53, +0x80, 0x6c, 0x00, 0x06, +0x1a, 0x00, 0x32, 0x80, +0x06, 0x80, 0x00, 0x00, +0xc2, 0x0b, 0xe9, 0xb9, +0x39, 0x0e, 0x04, 0x60, +0xe0, 0x38, 0x00, 0x0b, +0xe9, 0x77, 0x60, 0x03, +0x80, 0x00, 0x10, 0x98, +0xea, 0x03, 0x90, 0x20, +0x80, 0x07, 0xa6, 0x00, +0x40, 0x00, 0x01, 0x06, +0x82, 0x00, 0x00, 0x02, +0x00, 0x00, 0x00, 0x80, +0x07, 0xab, 0xa1, 0x40, +0xab, 0xfd, 0x08, 0x80, +0xc9, 0x5c, 0x09, 0xf8, +0x80, 0x4b, 0x88, 0x17, +0x59, 0x02, 0x5b, 0x88, +0x1d, 0x70, 0x00, 0x00, +0x6e, 0x00, 0x00, 0x92, +0x2d, 0x25, 0x9e, 0x8b, +0xc0, 0x60, 0x6c, 0x68, +0x08, 0x10, 0x03, 0x6c, +0x00, 0x00, 0xbc, 0x53, +0x40, 0x00, 0x03, 0xc0, +0x67, 0x6c, 0x68, 0x08, +0x16, 0x03, 0x6c, 0x00, +0x00, 0xbc, 0x53, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6e, 0x00, 0x00, 0xba, +0x2b, 0x25, 0x9d, 0x8b, +0xc0, 0x50, 0x6c, 0x68, +0x08, 0x12, 0x09, 0x6c, +0x00, 0x00, 0xbe, 0x49, +0xbc, 0x07, 0x72, 0x59, +0xe8, 0xbc, 0x05, 0x06, +0xc6, 0x80, 0x81, 0x60, +0x96, 0xc0, 0x00, 0x0b, +0xe4, 0x90, 0x00, 0x00, +0x5c, 0x02, 0x29, 0x02, +0x13, 0x68, 0x00, 0x00, +0x00, 0x75, 0x6c, 0x68, +0x08, 0x06, 0x75, 0x6c, +0x00, 0x06, 0x1a, 0x49, +0x00, 0x00, 0x08, 0x81, +0x97, 0x88, 0x00, 0xb4, +0x60, 0xb4, 0x08, 0x13, +0x58, 0x80, 0x89, 0x40, +0x00, 0x02, 0x80, 0x30, +0xab, 0xef, 0x08, 0x80, +0x75, 0x88, 0x0f, 0x68, +0x81, 0x6f, 0x88, 0x1e, +0xe8, 0x82, 0x6d, 0x88, +0x2e, 0xc8, 0x83, 0x6b, +0x88, 0x3e, 0xa8, 0x84, +0x69, 0x88, 0x4e, 0x88, +0x85, 0x67, 0x88, 0x5e, +0x68, 0x86, 0x65, 0x88, +0x6e, 0x48, 0x87, 0x63, +0x88, 0x7e, 0x28, 0x88, +0x61, 0x88, 0x8e, 0x08, +0x89, 0x4b, 0x88, 0x9c, +0x98, 0x8a, 0x4a, 0x88, +0xac, 0x89, 0x0b, 0x5b, +0x88, 0xc5, 0x79, 0x0d, +0x59, 0x88, 0xcd, 0x59, +0x0e, 0x5a, 0x88, 0xf5, +0x69, 0x10, 0x58, 0x88, +0xfd, 0x46, 0x60, 0x00, +0x03, 0xa6, 0x8b, 0xa1, +0x01, 0x90, 0xe1, 0x29, +0x0d, 0x11, 0x90, 0xb1, +0x38, 0x88, 0xa0, 0x88, +0x82, 0x18, 0x87, 0xa2, +0x88, 0x72, 0x38, 0x86, +0xa4, 0x88, 0x62, 0x58, +0x85, 0xa6, 0x88, 0x52, +0x78, 0x84, 0xa8, 0x88, +0x42, 0x98, 0x83, 0xaa, +0x88, 0x32, 0xb8, 0x8a, +0x88, 0x88, 0xa0, 0xa8, +0x89, 0x89, 0x88, 0x90, +0xb8, 0x82, 0xac, 0x88, +0x22, 0xd8, 0x81, 0xae, +0x88, 0x12, 0xf8, 0x80, +0xb6, 0x88, 0x03, 0x59, +0x10, 0x10, 0x88, 0xf1, +0x68, 0x8c, 0x95, 0x46, +0x0b, 0x40, 0x8c, 0x17, +0x88, 0xf9, 0x4a, 0x81, +0x10, 0x40, 0x00, 0x03, +0xa1, 0x60, 0xab, 0xfc, +0x08, 0x80, 0xc9, 0x5c, +0x08, 0x38, 0x80, 0x4b, +0x88, 0x17, 0x50, 0x00, +0x00, 0x6c, 0x00, 0x06, +0x00, 0x09, 0x25, 0x9e, +0x8b, 0xc1, 0x81, 0x88, +0x1e, 0x78, 0x82, 0x6b, +0x90, 0x35, 0xb8, 0x82, +0xd7, 0x00, 0x00, 0x06, +0xc0, 0x00, 0x60, 0x22, +0x7b, 0xc0, 0x8f, 0x5c, +0x80, 0x59, 0x8e, 0x89, +0x6c, 0x70, 0x10, 0x02, +0x03, 0x55, 0x03, 0x69, +0x79, 0xc3, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x06, 0x04, 0x0b, +0x30, 0x1e, 0x8b, 0xff, +0x62, 0x90, 0x31, 0x38, +0x81, 0xa7, 0x88, 0x22, +0xb8, 0x82, 0x97, 0x5c, +0x02, 0x3b, 0x00, 0x0d, +0x6c, 0x00, 0x06, 0x20, +0x4b, 0x6c, 0x70, 0x10, +0x0e, 0x49, 0x00, 0x00, +0x08, 0x81, 0x35, 0x46, +0x0b, 0x40, 0x80, 0x0b, +0x88, 0x08, 0x9a, 0x80, +0x40, 0x40, 0x00, 0x03, +0xa1, 0x60, 0x40, 0x00, +0x03, 0xa1, 0x60, 0x40, +0x00, 0x03, 0xa1, 0x60, +0x40, 0x00, 0x03, 0xa1, +0x60, 0x40, 0x00, 0x03, +0xa1, 0x60, 0x40, 0x00, +0x03, 0xa1, 0x60, 0x40, +0x00, 0x03, 0xa1, 0x60, +0x68, 0x34, 0x04, 0x04, +0x20, 0x5c, 0x02, 0xe2, +0xff, 0xc0, 0x5c, 0x00, +0x60, 0x40, 0x48, 0x9c, +0x00, 0x0b, 0x04, 0x86, +0x84, 0x04, 0xa6, 0x83, +0x40, 0x01, 0xe2, 0x1b, +0x19, 0xf6, 0x84, 0x84, +0xaa, 0x08, 0x81, 0xa0, +0x22, 0x08, 0x48, 0x7a, +0x68, 0x15, 0x0c, 0x84, +0x0a, 0x84, 0x04, 0xab, +0x08, 0x0e, 0xa0, 0x60, +0x04, 0x60, 0xa4, 0x04, +0x8c, 0xa8, 0x40, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x00, +0x08, 0x20, 0x68, 0x00, +0x03, 0xff, 0x08, 0x84, +0x00, 0xa5, 0x44, 0x9b, +0x20, 0x42, 0x06, 0x83, +0x40, 0xc0, 0x02, 0x18, +0x41, 0x00, 0x54, 0x48, +0x20, 0x48, 0x4a, 0xa0, +0x82, 0x18, 0x40, 0x0a, +0x46, 0x0a, 0x40, 0x48, +0x4a, 0x84, 0xbc, 0x80, +0x00, 0x00, 0x68, 0x38, +0x14, 0x07, 0x20, 0x5c, +0xbc, 0x03, 0x00, 0x0c, +0x84, 0x07, 0xa4, 0x60, +0xa4, 0x1c, 0x00, 0x08, +0x40, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x70, 0x28, 0x0c, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0d, 0x06, +0xc7, 0x02, 0x80, 0xc0, +0x83, 0x81, 0x0e, 0x25, +0x9a, 0x0b, 0xc0, 0x60, +0x5c, 0x04, 0x23, 0xa1, +0x48, 0x6c, 0x70, 0x28, +0x0c, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x64, +0x00, 0x00, 0x40, 0x27, +0x64, 0x00, 0x00, 0x3b, +0xa7, 0x68, 0x34, 0x0c, +0x00, 0x20, 0x68, 0x20, +0x00, 0x00, 0x2c, 0x84, +0x02, 0xda, 0xbf, 0xf0, +0x98, 0xb4, 0x89, 0x8b, +0x0a, 0x54, 0x0d, 0x20, +0x80, 0x76, 0x68, 0x00, +0x00, 0x08, 0x21, 0x98, +0x23, 0x6a, 0x00, 0x40, +0x84, 0x87, 0x6a, 0x0c, +0x39, 0x84, 0x00, 0x05, +0x90, 0x40, 0x08, 0x0e, +0x09, 0x48, 0x60, 0x68, +0x00, 0x00, 0x04, 0x20, +0x42, 0x08, 0x42, 0x0c, +0x49, 0x84, 0x82, 0x16, +0xc7, 0x02, 0x81, 0x20, +0x83, 0x81, 0x06, 0x25, +0x9a, 0x0b, 0xc0, 0x40, +0x5c, 0x04, 0x23, 0xc0, +0x4f, 0x6c, 0x70, 0x28, +0x14, 0x48, 0x6c, 0x70, +0x28, 0x10, 0x7a, 0xba, +0x09, 0x0b, 0xc1, 0x6f, +0x5c, 0xbf, 0x03, 0x00, +0x0c, 0x40, 0x00, 0x03, +0xa0, 0x90, 0x6c, 0x40, +0x04, 0x02, 0x08, 0x38, +0x10, 0x62, 0x59, 0xa0, +0xbc, 0x03, 0x16, 0x60, +0x00, 0x0c, 0x16, 0x0b, +0xc0, 0x27, 0x66, 0x00, +0x00, 0x44, 0xc0, 0x68, +0x38, 0x14, 0x09, 0x20, +0x5c, 0x00, 0x62, 0xff, +0xe0, 0x6c, 0x70, 0x28, +0x12, 0x48, 0x9c, 0x00, +0x08, 0x40, 0x7a, 0x68, +0x38, 0x14, 0x07, 0x20, +0x88, 0x0a, 0x18, 0x80, +0x36, 0x84, 0x87, 0xa8, +0x40, 0x7a, 0x9c, 0x00, +0x04, 0x60, 0xa4, 0x04, +0x04, 0x88, 0x42, 0x48, +0x40, 0x00, 0x02, 0x80, +0x10, 0xab, 0xff, 0x06, +0x83, 0x40, 0xc0, 0x02, +0x06, 0x82, 0x00, 0x00, +0x02, 0xc8, 0x40, 0x2d, +0xa0, 0x02, 0x08, 0x40, +0x28, 0x84, 0x10, 0x05, +0x90, 0x40, 0x18, 0xb0, +0xa9, 0x8b, 0x48, 0x54, +0x0d, 0x20, 0x80, 0x60, +0x98, 0x22, 0x16, 0x80, +0x00, 0x00, 0x82, 0x29, +0xc8, 0x01, 0x85, 0x06, +0x1a, 0x14, 0x39, 0x94, +0x86, 0x06, 0x80, 0x00, +0x00, 0x42, 0x08, 0x80, +0xf6, 0x42, 0x08, 0x42, +0x0c, 0x49, 0x84, 0x82, +0x16, 0xc7, 0x02, 0x81, +0x20, 0xa3, 0x81, 0x04, +0x25, 0x93, 0x0b, 0xc0, +0x40, 0x40, 0x00, 0x03, +0xc0, 0x4f, 0x6c, 0x70, +0x28, 0x14, 0x48, 0x6c, +0x70, 0x28, 0x10, 0x7a, +0xba, 0x09, 0x0b, 0xc1, +0x6f, 0x5c, 0x00, 0x62, +0xff, 0xe0, 0x40, 0x00, +0x03, 0xa0, 0x90, 0x6c, +0x40, 0x04, 0x02, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x03, 0x16, +0x60, 0x00, 0x0c, 0x16, +0x0b, 0xc0, 0x27, 0x66, +0x00, 0x00, 0x44, 0xc0, +0x68, 0x38, 0x14, 0x09, +0x20, 0x5c, 0x00, 0x62, +0xff, 0xe0, 0x6c, 0x70, +0x28, 0x12, 0x48, 0x9c, +0x00, 0x08, 0x40, 0x7a, +0x68, 0x38, 0x14, 0x07, +0x20, 0x5c, 0x00, 0xb0, +0x80, 0x21, 0x88, 0x0b, +0x68, 0x49, 0x7a, 0x84, +0x07, 0xa9, 0xc0, 0x00, +0x46, 0x0a, 0x40, 0x40, +0x4a, 0x84, 0x24, 0x8a, +0x80, 0x10, 0x68, 0x00, +0x00, 0x09, 0x20, 0x68, +0x00, 0x03, 0xff, 0x08, +0x5c, 0x81, 0x00, 0x40, +0x0a, 0x68, 0x34, 0x0c, +0x08, 0x21, 0x54, 0x49, +0xa2, 0x04, 0x60, 0x5c, +0x00, 0x60, 0x48, 0x48, +0xa0, 0x82, 0x19, 0x40, +0x2e, 0x80, 0x84, 0xa4, +0x60, 0xa4, 0x00, 0x87, +0xa8, 0x48, 0x48, 0x40, +0x00, 0x03, 0x80, 0x00, +0x62, 0x00, 0x00, 0x00, +0x36, 0x5c, 0x81, 0x09, +0x82, 0x24, 0x5c, 0x80, +0x81, 0x82, 0x60, 0xbb, +0x00, 0x08, 0x00, 0xcc, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x38, 0x00, 0xe2, +0x11, 0x34, 0x32, 0x02, +0x0b, 0xc0, 0x6d, 0x84, +0x86, 0x06, 0x20, 0x00, +0x00, 0x01, 0x43, 0x90, +0x20, 0x00, 0x00, 0x08, +0x00, 0x7a, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x5c, +0x00, 0x61, 0x88, 0x2c, +0x50, 0x8d, 0x20, 0x48, +0x20, 0x51, 0x85, 0x3a, +0xc0, 0x20, 0x98, 0x2e, +0xe0, 0x00, 0x00, 0x9c, +0x40, 0x08, 0x40, 0x49, +0x62, 0x00, 0x00, 0x00, +0x24, 0x84, 0x86, 0x09, +0x8e, 0x80, 0x80, 0x40, +0x92, 0x81, 0x40, 0xba, +0x14, 0x85, 0x04, 0xc0, +0x04, 0x86, 0x09, 0x80, +0x08, 0x5c, 0x81, 0x00, +0xc0, 0x2a, 0x82, 0x00, +0xb4, 0x41, 0x80, 0x02, +0x00, 0x84, 0x44, 0x40, +0x06, 0x00, 0x84, 0x42, +0x50, 0x18, 0x24, 0x04, +0x60, 0xa4, 0x18, 0x08, +0x28, 0xc0, 0x60, 0x55, +0x00, 0xa3, 0x80, 0x00, +0x5c, 0x81, 0x00, 0xc0, +0x2a, 0x82, 0x00, 0xb4, +0x41, 0x80, 0x02, 0x00, +0x84, 0x44, 0x40, 0x02, +0x00, 0x84, 0x42, 0x50, +0x18, 0x24, 0x09, 0x80, +0x82, 0x55, 0x00, 0xb8, +0x20, 0x08, 0x8c, 0x06, +0x0a, 0x20, 0x01, 0x8c, +0x12, 0xe4, 0x42, 0x00, +0x02, 0x00, 0x84, 0x44, +0x40, 0x04, 0x88, 0x94, +0x46, 0xc8, 0x06, 0x08, +0x85, 0xb0, 0x82, 0x98, +0x04, 0xa5, 0x78, 0x9a, +0x18, 0x48, 0x05, 0x74, +0xb1, 0x3a, 0x14, 0x88, +0xc1, 0x60, 0x55, 0x00, +0xa3, 0x80, 0x00, 0x32, +0x02, 0x8b, 0xc3, 0x58, +0x22, 0x86, 0xe5, 0xb8, +0xa2, 0x30, 0x0f, 0x05, +0x70, 0x80, 0x30, 0x00, +0xf5, 0x08, 0x1c, 0x30, +0x4e, 0xa2, 0xa6, 0x63, +0x4b, 0xc1, 0x23, 0x3c, +0x08, 0x20, 0x0c, 0xd2, +0x35, 0xd4, 0x68, 0x20, +0x01, 0x2c, 0x20, 0x28, +0x16, 0x25, 0x14, 0x2a, +0x84, 0x00, 0x85, 0x70, +0xb0, 0xb0, 0x0f, 0xa5, +0x16, 0xe6, 0x04, 0x08, +0x92, 0x80, 0x20, 0x68, +0x1f, 0xff, 0xff, 0xc8, +0x36, 0x80, 0x35, 0x44, +0x84, 0x98, 0x0c, 0x82, +0x32, 0x09, 0x28, 0x08, +0x02, 0x10, 0x3f, 0x20, +0x90, 0xc2, 0x81, 0x3f, +0x08, 0xb0, 0x02, 0x23, +0xc0, 0x98, 0x00, 0x80, +0x83, 0x00, 0x22, 0x3c, +0x02, 0xe0, 0x28, 0x98, +0x00, 0x80, 0x8c, 0x00, +0x22, 0x04, 0x09, 0x80, +0x0b, 0x08, 0xb0, 0x02, +0x23, 0xc0, 0x98, 0x00, +0xa0, 0x8b, 0x00, 0x22, +0x3c, 0x02, 0xe0, 0x28, +0x98, 0x00, 0xa4, 0x47, +0x00, 0x3a, 0x14, 0x82, +0x20, 0x40, 0x98, 0x00, +0x8b, 0xa1, 0x48, 0x98, +0xe8, 0x80, 0x00, 0x00, +0x32, 0x02, 0x0b, 0xc1, +0x68, 0x68, 0x34, 0x04, +0x14, 0x21, 0x6c, 0x68, +0x08, 0x28, 0x49, 0x00, +0x00, 0x08, 0x48, 0x89, +0x84, 0x04, 0x94, 0x00, +0x00, 0x38, 0x00, 0x04, +0x00, 0x00, 0x38, 0x00, +0x0b, 0xc0, 0x4f, 0x5c, +0x09, 0xab, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x68, 0x08, +0x06, 0x08, 0x25, 0x96, +0x0b, 0xff, 0xa0, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x6c, 0x68, 0x08, 0x28, +0x49, 0x00, 0x00, 0x08, +0x40, 0x09, 0x84, 0x8c, +0x94, 0x00, 0x00, 0x38, +0x00, 0x04, 0x00, 0x00, +0x38, 0x00, 0x0b, 0xc0, +0x4f, 0x5c, 0x09, 0xab, +0x80, 0x00, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x68, 0x08, 0x06, 0x08, +0x25, 0x96, 0x0b, 0xff, +0xa0, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x32, 0x02, +0x0b, 0xc0, 0x69, 0x5c, +0x08, 0x71, 0x40, 0x2c, +0x52, 0x4d, 0x03, 0xa1, +0x48, 0x94, 0x06, 0x00, +0x00, 0x00, 0x52, 0x0d, +0x03, 0xa1, 0x48, 0x94, +0x06, 0x00, 0x00, 0x00, +0x5c, 0x04, 0xa0, 0x40, +0x7a, 0x46, 0x0a, 0x40, +0x40, 0xfa, 0x84, 0x14, +0x80, 0x00, 0x00, 0x84, +0x00, 0x88, 0x40, 0x8a, +0x30, 0x93, 0x0b, 0xc0, +0x4b, 0xb0, 0x00, 0xcb, +0xa1, 0x48, 0x84, 0x0f, +0xa9, 0x8e, 0x88, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x84, 0x08, 0x03, 0x28, +0x00, 0xbc, 0x05, 0x08, +0x40, 0x00, 0x55, 0x02, +0x23, 0xa1, 0x48, 0x84, +0x04, 0x80, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x5c, 0x81, 0x02, +0x00, 0x40, 0x46, 0x08, +0x88, 0x02, 0x0a, 0x08, +0x80, 0x04, 0x60, 0xa4, +0x00, 0x24, 0xc8, 0x40, +0x7a, 0x40, 0x00, 0x03, +0xa1, 0x01, 0x68, 0x38, +0x1c, 0x03, 0x21, 0x55, +0x3f, 0x72, 0xff, 0xe0, +0x59, 0x03, 0x40, 0x48, +0x48, 0x5c, 0x00, 0x61, +0xc8, 0x01, 0x42, 0x02, +0x58, 0x48, 0x4a, 0x55, +0x03, 0xb0, 0x49, 0x48, +0x5c, 0x00, 0x73, 0x80, +0x00, 0x62, 0x00, 0x00, +0x00, 0x46, 0x39, 0x02, +0x00, 0x00, 0x00, 0x6c, +0x70, 0x38, 0x00, 0x09, +0x80, 0x04, 0x90, 0x00, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0xab, 0xfb, +0x06, 0x80, 0x00, 0x00, +0x82, 0x18, 0x80, 0x76, +0xa4, 0x04, 0x09, 0x88, +0x48, 0x66, 0x00, 0x00, +0x46, 0x08, 0x5c, 0x02, +0x31, 0x88, 0x09, 0x5c, +0x81, 0x02, 0x40, 0x40, +0xa0, 0x00, 0x18, 0x00, +0x00, 0x51, 0x60, 0x28, +0x00, 0x00, 0x51, 0xd0, +0x30, 0x80, 0xe0, 0x23, +0x42, 0xa6, 0x80, 0x03, +0xff, 0xfc, 0x05, 0x44, +0x18, 0x04, 0x00, 0x93, +0x28, 0x28, 0x54, 0x80, +0x83, 0xc0, 0x9d, 0x6c, +0x40, 0x00, 0x04, 0x50, +0xa0, 0x86, 0x18, 0x48, +0xa0, 0x66, 0x00, 0x00, +0x54, 0xc8, 0x84, 0x80, +0x8b, 0xc0, 0x3f, 0x88, +0x0a, 0x00, 0x00, 0x00, +0x88, 0x0a, 0x00, 0x00, +0x00, 0x84, 0x18, 0x93, +0x28, 0x28, 0xbc, 0x06, +0xda, 0x40, 0x41, 0xa0, +0x8c, 0x18, 0x48, 0xa0, +0x66, 0x00, 0x00, 0x54, +0xc8, 0x84, 0x80, 0x88, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x50, 0x40, +0x00, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x68, 0x34, 0x08, +0x4a, 0x20, 0x5c, 0x00, +0x62, 0xbf, 0xf0, 0x84, +0x04, 0x88, 0x40, 0xc8, +0x40, 0x00, 0x00, 0x80, +0x76, 0x66, 0x00, 0x00, +0x5b, 0x20, 0x68, 0x00, +0x01, 0xb0, 0x20, 0x88, +0x03, 0x6a, 0x00, 0x81, +0xa0, 0xc2, 0x28, 0x50, +0x61, 0xa0, 0xc4, 0x3a, +0x0c, 0x62, 0x84, 0x06, +0x14, 0x60, 0xa4, 0x05, +0x86, 0x18, 0x50, 0x61, +0x40, 0x00, 0x02, 0x80, +0x10, 0x68, 0x34, 0x08, +0x4c, 0x20, 0x6c, 0x68, +0x00, 0x04, 0x7a, 0x5c, +0x00, 0xa2, 0xc9, 0xa0, +0x84, 0x04, 0x8a, 0x00, +0x20, 0x80, 0x24, 0x88, +0x40, 0x7a, 0xa0, 0x10, +0x0a, 0xcb, 0x00, 0x80, +0x07, 0xa4, 0x60, 0xa4, +0x30, 0x60, 0x48, 0x40, +0x48, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x34, +0x00, 0x00, 0x20, 0x5c, +0x0b, 0x32, 0xc3, 0x20, +0x5c, 0x09, 0x00, 0x40, +0x02, 0x52, 0x0c, 0x92, +0xc5, 0x01, 0x84, 0x05, +0x2a, 0x03, 0x60, 0x84, +0x00, 0x25, 0x24, 0xc9, +0x2c, 0x4e, 0x28, 0x00, +0x52, 0x80, 0x2c, 0x88, +0x40, 0x7a, 0xa0, 0x02, +0x08, 0x01, 0x7a, 0x00, +0x00, 0x08, 0x02, 0x08, +0x25, 0x82, 0x0b, 0xc0, +0x89, 0x68, 0x34, 0x00, +0x0e, 0x21, 0x5c, 0x00, +0x43, 0x00, 0x34, 0x6c, +0x68, 0x00, 0x1c, 0x50, +0xbc, 0x04, 0xf8, 0x48, +0xc8, 0x6c, 0x68, 0x00, +0x1c, 0x7a, 0x84, 0x8f, +0xa3, 0x20, 0x28, 0x84, +0x00, 0x85, 0x20, 0xd2, +0x3c, 0x06, 0x85, 0xc0, +0x8e, 0x84, 0x04, 0x89, +0x8e, 0x48, 0x52, 0x0b, +0x2b, 0xc0, 0x4f, 0x98, +0x27, 0x99, 0x8e, 0x48, +0x24, 0x96, 0x59, 0x82, +0x79, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x62, 0x27, +0xa0, 0x00, 0x00, 0x68, +0x38, 0x08, 0x0f, 0x20, +0x39, 0x7a, 0x08, 0x40, +0x48, 0x46, 0x0a, 0x41, +0xc0, 0x00, 0x84, 0x04, +0x90, 0x00, 0x00, 0x68, +0x38, 0x08, 0x00, 0x21, +0xb0, 0x40, 0x68, 0x48, +0x4a, 0xa0, 0x84, 0x16, +0x20, 0x00, 0x00, 0x04, +0x48, 0x48, 0x7a, 0x39, +0x00, 0x89, 0x40, 0x0e, +0x6c, 0x70, 0x10, 0x06, +0x4a, 0x00, 0x00, 0x05, +0x90, 0x14, 0x04, 0xe4, +0x8b, 0xc0, 0x68, 0x6c, +0x00, 0x06, 0x20, 0x7a, +0x5c, 0x04, 0x6b, 0xc0, +0x5f, 0x6c, 0x70, 0x10, +0x0c, 0x49, 0x38, 0x00, +0xd6, 0xc7, 0x01, 0x00, +0xc4, 0x9b, 0xa1, 0x48, +0x6c, 0x00, 0x06, 0x00, +0x7a, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x38, +0x08, 0x00, 0x22, 0x00, +0x00, 0x08, 0x50, 0x7a, +0xa1, 0x04, 0x26, 0x20, +0x00, 0x00, 0x04, 0x48, +0x50, 0x7a, 0x39, 0x00, +0x89, 0x40, 0x08, 0x6c, +0x70, 0x10, 0x06, 0x50, +0x00, 0x00, 0x02, 0x81, +0x64, 0x59, 0x01, 0x80, +0x56, 0x48, 0xbc, 0x06, +0x86, 0xc0, 0x00, 0x62, +0x07, 0xa5, 0xc0, 0x47, +0x3c, 0x05, 0xf6, 0xc7, +0x01, 0x00, 0xc4, 0xa3, +0x80, 0x0e, 0x6c, 0x70, +0x10, 0x0c, 0x4a, 0x68, +0x00, 0x03, 0x00, 0x20, +0x5c, 0x81, 0x03, 0x00, +0x0e, 0x80, 0x04, 0xa4, +0x60, 0xa4, 0x00, 0x06, +0x18, 0x40, 0x49, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x06, 0xf0, +0x00, 0x32, 0x00, 0x0b, +0xc4, 0xc0, 0x38, 0x10, +0x22, 0x58, 0x80, 0xbc, +0x10, 0x16, 0x80, 0x00, +0x37, 0x42, 0x05, 0xc8, +0x50, 0xac, 0x12, 0x05, +0xc8, 0x98, 0x80, 0x0a, +0x10, 0x00, 0x00, 0x84, +0x80, 0x22, 0x2c, 0x14, +0x94, 0x25, 0x40, 0x00, +0x00, 0x80, 0x0a, 0x10, +0x00, 0x00, 0x84, 0x80, +0x22, 0x2c, 0x14, 0x94, +0x07, 0x43, 0x81, 0x0a, +0x25, 0x88, 0x0b, 0xc1, +0x01, 0x68, 0x00, 0x03, +0x75, 0x20, 0x5c, 0x85, +0x0a, 0xc1, 0x20, 0x5c, +0x89, 0x88, 0x00, 0xa1, +0x00, 0x00, 0x08, 0x48, +0x02, 0x22, 0xc1, 0x49, +0x42, 0x54, 0x00, 0x00, +0x08, 0x00, 0xa1, 0x00, +0x00, 0x08, 0x48, 0x02, +0x22, 0xc1, 0x49, 0x40, +0x74, 0x38, 0x11, 0x22, +0x58, 0x80, 0xbc, 0x10, +0x16, 0x80, 0x00, 0x37, +0x62, 0x05, 0xc8, 0x50, +0xac, 0x12, 0x05, 0xc8, +0x98, 0x80, 0x0a, 0x10, +0x00, 0x00, 0x84, 0x80, +0x22, 0x2c, 0x14, 0x94, +0x25, 0x40, 0x00, 0x00, +0x80, 0x0a, 0x10, 0x00, +0x00, 0x84, 0x80, 0x22, +0x2c, 0x14, 0x94, 0x07, +0x43, 0x81, 0x1a, 0x25, +0x88, 0x0b, 0xc1, 0x09, +0x39, 0x0a, 0x16, 0x80, +0x00, 0x37, 0x72, 0x05, +0xc8, 0x91, 0x2c, 0x13, +0x08, 0x00, 0xa1, 0x00, +0x00, 0x08, 0x48, 0x00, +0x22, 0xc0, 0x49, 0x43, +0x54, 0x00, 0x00, 0x08, +0x00, 0x21, 0x00, 0x00, +0x08, 0x48, 0x00, 0x22, +0xc0, 0x49, 0x40, 0x74, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x6e, 0x40, 0x00, +0x08, 0x3c, 0x5c, 0x0b, +0xea, 0xbf, 0xd0, 0x25, +0x96, 0x0b, 0xc5, 0xe8, +0x5c, 0x00, 0x28, 0x80, +0x76, 0x68, 0x20, 0x00, +0x05, 0x20, 0x5c, 0x88, +0x0a, 0xc0, 0x20, 0x5c, +0x8a, 0x08, 0x00, 0x88, +0x51, 0xd1, 0x32, 0xc1, +0x63, 0x5d, 0x08, 0x02, +0xc1, 0x82, 0x5d, 0x0c, +0x10, 0x80, 0xc9, 0x23, +0x60, 0x05, 0x1e, 0x13, +0x00, 0x05, 0x02, 0x36, +0x10, 0x5d, 0x0c, 0x00, +0x00, 0x50, 0x23, 0x60, +0x05, 0x1f, 0x12, 0x00, +0x05, 0x02, 0x36, 0x24, +0x80, 0x2c, 0x86, 0x82, +0x00, 0x01, 0xb2, 0x18, +0x01, 0x88, 0x3a, 0x90, +0x02, 0x3c, 0x24, 0x23, +0x40, 0x05, 0x1a, 0x12, +0x00, 0x05, 0x08, 0x03, +0xc8, 0x68, 0x00, 0x40, +0x04, 0x88, 0x80, 0x10, +0x05, 0x1e, 0x03, 0x08, +0x14, 0x83, 0xa8, 0x02, +0x23, 0x41, 0x05, 0x1a, +0x18, 0x00, 0x05, 0x08, +0x02, 0xd0, 0x00, 0x00, +0x08, 0x00, 0x00, 0x51, +0xe0, 0x30, 0x81, 0xe0, +0x23, 0x43, 0x25, 0xd4, +0x00, 0x00, 0x10, 0x15, +0xd4, 0x21, 0x04, 0x85, +0x25, 0x1a, 0x09, 0x20, +0x86, 0x15, 0x1e, 0x07, +0x00, 0xa5, 0x25, 0x1a, +0x19, 0x08, 0x26, 0x05, +0x1a, 0x00, 0x04, 0x85, +0x26, 0xc4, 0x00, 0x03, +0x85, 0x02, 0x30, 0xad, +0x98, 0x26, 0x86, 0x82, +0x00, 0x00, 0x52, 0x06, +0x60, 0x00, 0x16, 0xda, +0x89, 0xc0, 0x00, 0x88, +0x08, 0x85, 0x50, 0x32, +0x88, 0x10, 0x83, 0xb1, +0x45, 0x59, 0x07, 0x40, +0x80, 0xc9, 0x55, 0x03, +0x23, 0xff, 0x1a, 0x88, +0x14, 0x86, 0xc0, 0x00, +0x1d, 0x47, 0xa6, 0xc0, +0x00, 0x22, 0xa7, 0xa6, +0xc0, 0x00, 0x24, 0x07, +0xa6, 0xc0, 0x00, 0x25, +0x67, 0xa0, 0x00, 0x00, +0x88, 0x22, 0x08, 0x81, +0xa1, 0x42, 0x05, 0x78, +0x40, 0xfa, 0x40, 0x00, +0x00, 0x4e, 0x7a, 0x68, +0x20, 0x00, 0x0d, 0x20, +0x39, 0x02, 0x02, 0xa0, +0x6c, 0x3b, 0x10, 0x53, +0x23, 0x28, 0xbf, 0xfc, +0xa8, 0x00, 0x7a, 0x38, +0x17, 0x06, 0xe4, 0x00, +0x00, 0x83, 0xd2, 0x58, +0x28, 0xbc, 0x0b, 0x85, +0xc0, 0x32, 0x2c, 0x02, +0x06, 0x82, 0x00, 0x00, +0x82, 0x03, 0x92, 0x20, +0x80, 0x00, 0x8a, 0x06, +0x01, 0x80, 0x80, 0x94, +0x20, 0x4f, 0x84, 0x04, +0x88, 0x48, 0x49, 0x68, +0x20, 0x00, 0x19, 0x20, +0x2a, 0x06, 0x43, 0xb1, +0x04, 0x32, 0x3a, 0x0b, +0xff, 0xca, 0x40, 0x00, +0x00, 0x00, 0x7a, 0x68, +0x20, 0x00, 0x0d, 0x20, +0x66, 0x00, 0x00, 0x4f, +0x08, 0x5c, 0x02, 0x29, +0x8e, 0x88, 0x68, 0x20, +0x00, 0x0d, 0x20, 0x00, +0x00, 0x0a, 0x00, 0x40, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x04, 0xf0, 0x85, +0xc0, 0x42, 0x98, 0xe8, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x04, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x04, 0xf0, 0x85, +0xc0, 0x06, 0x98, 0xe8, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x40, +0x40, 0x00, 0x00, 0x80, +0xe0, 0x66, 0x00, 0x00, +0x4f, 0x08, 0x5c, 0x00, +0xa9, 0x8e, 0x88, 0x5c, +0x81, 0x00, 0x80, 0xa0, +0x68, 0x00, 0x00, 0x36, +0x21, 0xa0, 0x02, 0x08, +0x00, 0x01, 0x80, 0x00, +0x38, 0x00, 0x0a, 0x80, +0x00, 0x08, 0x00, 0x08, +0x80, 0x00, 0x96, 0xc4, +0x00, 0x07, 0x85, 0x16, +0xc4, 0x00, 0x0c, 0x65, +0x38, 0x48, 0x4a, 0x68, +0x00, 0x00, 0x4a, 0x22, +0x80, 0x00, 0x28, 0x00, +0x01, 0x84, 0x08, 0x38, +0x00, 0x0a, 0x6c, 0x40, +0x01, 0x5c, 0x4a, 0xa0, +0x6c, 0x09, 0x40, 0x3e, +0xb1, 0x00, 0x76, 0x80, +0x00, 0x09, 0x02, 0x35, +0x44, 0xf8, 0x05, 0x05, +0x06, 0xc4, 0x00, 0x18, +0xc5, 0x35, 0x90, 0x00, +0x05, 0x0c, 0x98, 0x48, +0xc8, 0x85, 0x8d, 0x14, +0x20, 0x3c, 0x85, 0x85, +0x28, 0x80, 0xe0, 0x66, +0x00, 0x01, 0x09, 0x48, +0x68, 0x00, 0x40, 0x03, +0x88, 0x40, 0x00, 0x00, +0x80, 0xa0, 0x68, 0x00, +0x01, 0x00, 0x08, 0x94, +0x03, 0xd2, 0x89, 0x2c, +0x32, 0x02, 0x0b, 0xc0, +0x91, 0x6e, 0x00, 0x01, +0x2c, 0x2d, 0x38, 0x11, +0x82, 0x40, 0x28, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x66, 0x00, 0x01, 0x0c, +0x88, 0x38, 0x00, 0x48, +0x80, 0xa0, 0x68, 0x00, +0x02, 0x00, 0x08, 0x94, +0x03, 0xd2, 0x89, 0x2c, +0x32, 0x02, 0x0b, 0xc0, +0x61, 0x66, 0x00, 0x01, +0x25, 0x88, 0x68, 0x00, +0x40, 0x05, 0x48, 0x40, +0x00, 0x00, 0x80, 0xa0, +0x5c, 0x81, 0x03, 0x08, +0x04, 0x94, 0x01, 0xd2, +0x89, 0x2c, 0x32, 0x02, +0x0b, 0xc0, 0x89, 0x88, +0x16, 0x03, 0x81, 0x05, +0x6e, 0x00, 0x01, 0x2c, +0xac, 0x52, 0x0b, 0x03, +0x80, 0x00, 0x6e, 0x00, +0x01, 0x2c, 0xe0, 0x66, +0x00, 0x01, 0x6d, 0xa8, +0x68, 0x00, 0x40, 0x07, +0x48, 0x88, 0x0a, 0x06, +0x80, 0x03, 0xff, 0xfc, +0x88, 0x40, 0x89, 0x3a, +0x94, 0x03, 0x01, 0x00, +0x40, 0x00, 0x03, 0xc0, +0x40, 0x51, 0xa0, 0x03, +0xc0, 0x4f, 0x6c, 0x00, +0x02, 0xb0, 0x50, 0x6c, +0x00, 0x02, 0xb0, 0x7a, +0x23, 0xc2, 0xd3, 0x01, +0x28, 0x40, 0x00, 0x03, +0xc0, 0x40, 0x51, 0xa1, +0x63, 0xc0, 0x4f, 0x6c, +0x00, 0x02, 0xb2, 0x48, +0x6c, 0x00, 0x02, 0xb2, +0x7a, 0x68, 0x00, 0x01, +0x64, 0x21, 0x60, 0x00, +0x00, 0x00, 0x28, 0x68, +0x00, 0x01, 0x5c, 0x20, +0x39, 0x02, 0x08, 0x00, +0x7a, 0x80, 0x87, 0xa0, +0x00, 0x00, 0x40, 0x00, +0x00, 0x81, 0x20, 0x66, +0x00, 0x01, 0x6d, 0xa8, +0x68, 0x00, 0x80, 0x00, +0x08, 0x5c, 0x81, 0x00, +0x81, 0x20, 0xb0, 0x7f, +0xc8, 0x00, 0x09, 0x28, +0x92, 0xc3, 0x20, 0x60, +0xbc, 0x68, 0x98, 0x80, +0xe0, 0x68, 0x00, 0x01, +0x6c, 0x20, 0x66, 0x00, +0x01, 0x6d, 0xa8, 0x68, +0x00, 0x80, 0x00, 0x48, +0x68, 0x00, 0x01, 0x6c, +0x20, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x08, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x0c, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x10, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x14, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x18, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x1c, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x20, 0x88, 0x81, +0xa0, 0x00, 0x00, 0x0a, +0x00, 0x20, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x16, +0xda, 0x86, 0x80, 0x08, +0x00, 0x24, 0x88, 0x81, +0xa1, 0x68, 0x20, 0x01, +0xf4, 0x20, 0x68, 0x00, +0x01, 0x5c, 0x22, 0x60, +0x00, 0x00, 0x01, 0x78, +0x39, 0x02, 0x05, 0xc0, +0x7e, 0x20, 0xd0, 0x18, +0x48, 0x89, 0x80, 0x80, +0x05, 0x70, 0x14, 0x04, +0x08, 0x95, 0xb4, 0x01, +0x80, 0x00, 0x22, 0xe0, +0xaa, 0x37, 0x0c, 0x12, +0xe0, 0x65, 0x62, 0x00, +0x00, 0x00, 0x25, 0x20, +0x95, 0xb5, 0xb4, 0x40, +0x98, 0xeb, 0x52, 0xf8, +0x5b, 0x29, 0x88, 0x03, +0x20, 0x00, 0xbc, 0x02, +0xb9, 0x83, 0xc9, 0x36, +0x14, 0x58, 0x10, 0x49, +0x00, 0x00, 0x00, 0x00, +0x00, 0x88, 0x0a, 0x06, +0x60, 0x00, 0x16, 0xda, +0x86, 0x80, 0x08, 0x00, +0x40, 0x88, 0x81, 0x20, +0xb0, 0x7f, 0xc8, 0x40, +0x89, 0x28, 0x92, 0xc3, +0x20, 0x60, 0x40, 0x00, +0x03, 0xc6, 0x71, 0x68, +0x00, 0x01, 0x75, 0x20, +0x66, 0x00, 0x01, 0x6d, +0xa8, 0x68, 0x00, 0x80, +0x04, 0x48, 0x68, 0x00, +0x01, 0x75, 0x20, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x48, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x4c, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x50, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x54, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x58, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x5c, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x60, +0x88, 0x80, 0xa0, 0x00, +0x00, 0x0a, 0x00, 0x20, +0x88, 0x0e, 0x06, 0x60, +0x00, 0x16, 0xda, 0x86, +0x80, 0x08, 0x00, 0x64, +0x88, 0x80, 0xa1, 0x68, +0x20, 0x01, 0xf4, 0x20, +0x68, 0x00, 0x01, 0x64, +0x22, 0x60, 0x00, 0x00, +0x01, 0x78, 0x39, 0x02, +0x05, 0xc0, 0x7e, 0x20, +0xd0, 0x18, 0x48, 0x89, +0x80, 0x80, 0x05, 0x70, +0x14, 0x04, 0x08, 0x95, +0xb4, 0x01, 0x80, 0x00, +0x22, 0xe0, 0xaa, 0x37, +0x0c, 0x12, 0xe0, 0x65, +0x62, 0x00, 0x00, 0x00, +0x25, 0x20, 0x95, 0xb5, +0xb4, 0x40, 0x98, 0xeb, +0x52, 0xf8, 0x5b, 0x29, +0x88, 0x03, 0x20, 0x00, +0xbc, 0x02, 0xb9, 0x83, +0xc9, 0x36, 0x14, 0x58, +0x10, 0x49, 0x00, 0x00, +0x08, 0x80, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, +0x00, 0xab, 0xfd, 0x08, +0x80, 0x60, 0x88, 0x0f, +0x66, 0x80, 0x10, 0x00, +0x4c, 0x86, 0x60, 0x00, +0x16, 0xda, 0x8a, 0x40, +0x80, 0x5c, 0x09, 0xc2, +0x40, 0x80, 0x94, 0x02, +0xa2, 0x58, 0x10, 0xbc, +0x05, 0x06, 0x83, 0x40, +0x84, 0x02, 0x19, 0x41, +0x28, 0x84, 0x85, 0x28, +0x48, 0xd0, 0x66, 0x00, +0x01, 0x6d, 0xa8, 0x68, +0x00, 0x80, 0x03, 0x88, +0x5c, 0x09, 0xc2, 0x40, +0x80, 0x94, 0x02, 0xa2, +0x58, 0x10, 0xbc, 0x07, +0x86, 0x83, 0x40, 0x84, +0x22, 0x15, 0xc0, 0x80, +0x94, 0x0a, 0x82, 0x58, +0x40, 0x40, 0x00, 0x03, +0xc1, 0x01, 0x66, 0x00, +0x01, 0x6d, 0xa8, 0x68, +0x01, 0x00, 0x05, 0x08, +0x5c, 0x09, 0xc2, 0x40, +0x80, 0x94, 0x02, 0xa2, +0x58, 0x10, 0xbc, 0x0b, +0x06, 0x83, 0x40, 0x84, +0x22, 0x19, 0x41, 0x28, +0x6c, 0x68, 0x10, 0x84, +0x52, 0x84, 0x8d, 0x0b, +0xc0, 0x47, 0x94, 0x12, +0x86, 0xc6, 0x81, 0x08, +0x45, 0x28, 0x48, 0xd0, +0x66, 0x00, 0x01, 0x6d, +0xa8, 0x68, 0x01, 0x00, +0x05, 0x48, 0x5c, 0x09, +0xc2, 0x40, 0x80, 0x94, +0x02, 0xa2, 0x58, 0x10, +0xbc, 0x05, 0x06, 0x83, +0x40, 0x84, 0x42, 0x19, +0x41, 0x28, 0x84, 0x85, +0x28, 0x48, 0xd0, 0x66, +0x00, 0x01, 0x6d, 0xa8, +0x68, 0x00, 0x80, 0x03, +0xc8, 0x5c, 0x09, 0xc2, +0x40, 0x80, 0x94, 0x02, +0xa2, 0x58, 0x10, 0xbc, +0x07, 0x86, 0x83, 0x40, +0x84, 0x62, 0x15, 0xc0, +0x80, 0x94, 0x0a, 0x82, +0x58, 0x40, 0x40, 0x00, +0x03, 0xc1, 0x01, 0x66, +0x00, 0x01, 0x6d, 0xa8, +0x68, 0x01, 0x00, 0x05, +0x88, 0x5c, 0x09, 0xd2, +0x40, 0x80, 0x94, 0x02, +0x82, 0x58, 0x80, 0xbc, +0x0b, 0x06, 0x83, 0x40, +0x84, 0x62, 0x19, 0x41, +0x2a, 0x6c, 0x68, 0x10, +0x8c, 0x50, 0x84, 0x8d, +0x2b, 0xc0, 0x47, 0x94, +0x12, 0x86, 0xc6, 0x81, +0x08, 0xc5, 0x28, 0x48, +0xd0, 0x66, 0x00, 0x01, +0x6d, 0xa8, 0x68, 0x01, +0x00, 0x05, 0xc8, 0x5c, +0x09, 0xc2, 0x40, 0x80, +0x94, 0x02, 0xa2, 0x58, +0x10, 0xbc, 0x05, 0x06, +0x83, 0x40, 0x88, 0x02, +0x19, 0x41, 0x28, 0x84, +0x85, 0x28, 0x48, 0xd0, +0x66, 0x00, 0x01, 0x6d, +0xa8, 0x68, 0x01, 0x00, +0x06, 0x08, 0x5c, 0x09, +0xc2, 0x40, 0x80, 0x94, +0x0a, 0xa2, 0x58, 0x10, +0xbc, 0x0d, 0x05, 0xc8, +0x04, 0x20, 0x01, 0x95, +0x19, 0x08, 0x14, 0x02, +0x95, 0x48, 0x20, 0x94, +0xa0, 0xa6, 0x83, 0x40, +0x88, 0x22, 0x05, 0x19, +0x09, 0x14, 0x82, 0x85, +0x48, 0x08, 0x04, 0x05, +0x18, 0x40, 0xd0, 0x98, +0xe8, 0x08, 0x81, 0x50, +0x68, 0x00, 0x40, 0x00, +0x08, 0x88, 0x02, 0x08, +0x81, 0xc8, 0x66, 0x00, +0x01, 0x6d, 0xa0, 0x88, +0x10, 0x05, 0x50, 0x20, +0x08, 0x02, 0x05, 0xd0, +0x00, 0x08, 0x18, 0x25, +0x90, 0xc0, 0x20, 0x02, +0x04, 0x3f, 0xa5, 0x08, +0x06, 0x05, 0x50, 0x2a, +0x08, 0x15, 0x06, 0x80, +0x04, 0x00, 0x48, 0x88, +0x81, 0x7a, 0x88, 0x1c, +0x86, 0x60, 0x00, 0x16, +0xda, 0x08, 0x81, 0x00, +0x55, 0x02, 0x00, 0x80, +0x20, 0x5d, 0x00, 0x00, +0x81, 0x82, 0x59, 0x04, +0x02, 0x00, 0x20, 0x43, +0xfa, 0x50, 0x80, 0x60, +0x55, 0x02, 0xa0, 0x81, +0x50, 0x00, 0x00, 0x08, +0x80, 0xb6, 0xba, 0x14, +0x8a, 0x80, 0x30, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5c, 0x82, 0x02, 0x00, +0x48, 0x5c, 0x00, 0x31, +0x8e, 0x88, 0x5c, 0x0f, +0xc1, 0x40, 0x64, 0x52, +0x01, 0xb2, 0x00, 0x38, +0x80, 0x26, 0x17, 0x60, +0x02, 0x00, 0x80, 0x29, +0x40, 0x64, 0xa0, 0x06, +0x18, 0x0a, 0x62, 0xb0, +0x40, 0x48, 0x48, 0x48, +0xa0, 0x8a, 0x18, 0x48, +0x4a, 0xa0, 0xd0, 0x16, +0x80, 0x00, 0x26, 0x1a, +0xc8, 0x48, 0xec, 0x68, +0x00, 0x02, 0x5d, 0x2c, +0xba, 0x14, 0x88, 0x48, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x94, 0x4a, +0x83, 0x20, 0x00, 0xbc, +0x0b, 0x58, 0x42, 0x21, +0x68, 0x20, 0x02, 0x6d, +0x22, 0x94, 0x82, 0x82, +0x29, 0x04, 0x2a, 0xbe, +0x02, 0x30, 0x80, 0x98, +0x42, 0x89, 0xd0, 0x01, +0x84, 0x82, 0x1b, 0xa0, +0x10, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x39, 0x00, 0x89, 0x48, +0x0c, 0x51, 0xb1, 0x21, +0x48, 0x0e, 0x51, 0xa1, +0xb1, 0x48, 0x08, 0x51, +0x90, 0x11, 0x48, 0x28, +0x29, 0x1a, 0x42, 0x90, +0xa4, 0x54, 0x81, 0x23, +0xa1, 0x48, 0x84, 0x04, +0x80, 0x00, 0x00, 0x5c, +0x80, 0x40, 0x40, 0x00, +0x51, 0xf0, 0x23, 0x07, +0xfa, 0x28, 0x8a, 0x15, +0x1e, 0x02, 0x14, 0x84, +0x12, 0x88, 0xa1, 0x51, +0xd0, 0x21, 0x48, 0x41, +0x28, 0x8a, 0x15, 0x44, +0x40, 0x14, 0x84, 0x1b, +0xa1, 0x48, 0x94, 0x86, +0x00, 0x00, 0x00, 0x5c, +0x80, 0x48, 0x43, 0xa4, +0x5c, 0x80, 0x93, 0x80, +0x00, 0x62, 0x00, 0x00, +0x00, 0xb4, 0x5c, 0x81, +0x02, 0xbf, 0xf0, 0x5c, +0x00, 0x02, 0x40, 0x02, +0x60, 0x00, 0x00, 0x00, +0x35, 0x8d, 0x05, 0x80, +0x00, 0x00, 0x94, 0x88, +0xc9, 0x52, 0xc4, 0x00, +0x00, 0x0a, 0x10, 0x0a, +0x8d, 0x03, 0x2b, 0xb1, +0x82, 0xba, 0x14, 0x88, +0x43, 0xe4, 0x40, 0x00, +0x02, 0x80, 0x10, 0x5c, +0x80, 0x52, 0xbf, 0xf0, +0xa0, 0x0a, 0x0a, 0x40, +0x02, 0x62, 0x00, 0x00, +0x00, 0xa4, 0x5c, 0x81, +0x08, 0x41, 0x24, 0x5c, +0x80, 0x80, 0x40, 0x21, +0xbb, 0x00, 0x06, 0x00, +0x00, 0x00, 0x03, 0x58, +0xd0, 0xd8, 0x00, 0x00, +0x09, 0x53, 0x0c, 0x94, +0x94, 0x40, 0x00, 0x00, +0xa1, 0x00, 0xab, 0xa1, +0x48, 0x84, 0x16, 0x4a, +0x80, 0x10, 0xa0, 0x08, +0x18, 0x48, 0x22, 0xa0, +0xc3, 0x99, 0x50, 0x28, +0x55, 0x5e, 0x12, 0xbf, +0xe0, 0x51, 0x90, 0x89, +0x48, 0x2a, 0x59, 0x04, +0x81, 0x50, 0xa8, 0x54, +0x00, 0x60, 0x80, 0x76, +0xbc, 0x1a, 0x89, 0x82, +0x23, 0x32, 0x0d, 0x0b, +0xc1, 0x48, 0xa1, 0x01, +0x12, 0xa7, 0x90, 0x22, +0x88, 0x63, 0x20, 0x30, +0xbc, 0x1c, 0x56, 0x20, +0x00, 0x00, 0x08, 0x60, +0x00, 0x00, 0x00, 0x00, +0x09, 0x82, 0x20, 0x88, +0x0c, 0x88, 0x81, 0x61, +0x66, 0x00, 0x00, 0x98, +0x80, 0x88, 0x12, 0x08, +0x80, 0x80, 0x55, 0x08, +0x22, 0x00, 0x21, 0x40, +0x00, 0x03, 0xc0, 0xd7, +0x42, 0x05, 0xf9, 0x51, +0x28, 0x95, 0x86, 0x0a, +0x00, 0xa1, 0xa0, 0xc6, +0x28, 0x48, 0x21, 0x88, +0x0e, 0x26, 0x60, 0x00, +0x09, 0x96, 0x8a, 0x18, +0x00, 0x88, 0x0a, 0x0b, +0x00, 0x20, 0x94, 0x06, +0x00, 0x00, 0x00, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0x94, 0x4a, 0xc5, +0x90, 0x50, 0x2b, 0xff, +0x0b, 0xc0, 0x98, 0x88, +0x07, 0x6a, 0x00, 0x80, +0x84, 0x02, 0x18, 0x80, +0x36, 0xa8, 0x01, 0x0a, +0x00, 0x60, 0x64, 0x00, +0x00, 0x98, 0x8f, 0xa0, +0x81, 0x1a, 0x00, 0xa1, +0xa0, 0x84, 0x08, 0x48, +0x21, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x09, 0x96, +0x08, 0x80, 0xa0, 0xb0, +0x02, 0x4a, 0x04, 0xa0, +0x94, 0x06, 0x40, 0x00, +0x00, 0x88, 0x03, 0x6b, +0xa1, 0x48, 0xa8, 0x01, +0x00, 0x00, 0x00, 0xa0, +0x08, 0x1a, 0x0c, 0x3a, +0x95, 0x02, 0xc5, 0x90, +0x50, 0x2b, 0xff, 0x0b, +0xc1, 0x68, 0x84, 0x82, +0x15, 0x53, 0xd2, 0x30, +0x0f, 0xe5, 0xb4, 0x81, +0x30, 0x02, 0x83, 0x70, +0x85, 0x2e, 0x17, 0x66, +0x20, 0x00, 0x00, 0x02, +0x63, 0x68, 0x00, 0x50, +0x4c, 0x91, 0x8e, 0xb5, +0x2f, 0x81, 0x22, 0xb9, +0x66, 0x32, 0x03, 0x0b, +0xc0, 0x2b, 0x98, 0x38, +0x83, 0x61, 0x04, 0xa0, +0x81, 0x16, 0x40, 0x00, +0x09, 0xa6, 0xfa, 0x80, +0x10, 0x88, 0x07, 0x68, +0x80, 0xe0, 0x66, 0x00, +0x00, 0x9b, 0xe8, 0x38, +0x00, 0xcb, 0x00, 0x2c, +0x88, 0x0a, 0x08, 0x80, +0x36, 0x94, 0x46, 0x4b, +0xa1, 0x48, 0xa8, 0x01, +0x00, 0x00, 0x00, 0xa0, +0x08, 0x18, 0x48, 0x22, +0x68, 0x20, 0x00, 0x00, +0x2c, 0x95, 0x02, 0x85, +0x55, 0xe1, 0x15, 0x0a, +0x85, 0x19, 0x09, 0x20, +0xc3, 0x95, 0x40, 0x0a, +0x18, 0xb0, 0x05, 0x40, +0x12, 0x14, 0x82, 0x85, +0x90, 0x40, 0x2b, 0xfe, +0x04, 0x20, 0xd4, 0x08, +0x07, 0x69, 0x82, 0x23, +0x32, 0x0c, 0x0b, 0xc1, +0x48, 0xa1, 0x01, 0x12, +0xa7, 0x80, 0x22, 0x88, +0x63, 0x20, 0x30, 0xbc, +0x1c, 0x56, 0x20, 0x00, +0x00, 0x08, 0x60, 0x00, +0x00, 0x00, 0x00, 0x09, +0x82, 0x20, 0x88, 0x0c, +0x88, 0x81, 0x61, 0x66, +0x00, 0x00, 0x98, 0x80, +0x88, 0x12, 0x08, 0x80, +0x80, 0x55, 0x08, 0x22, +0x00, 0x21, 0x40, 0x00, +0x03, 0xc0, 0xd7, 0x42, +0x05, 0xf9, 0x51, 0x28, +0x95, 0x86, 0x0a, 0x00, +0xa1, 0xa0, 0xc6, 0x28, +0x48, 0x21, 0x88, 0x0e, +0x26, 0x60, 0x00, 0x09, +0x96, 0x8a, 0x18, 0x00, +0x88, 0x0a, 0x0b, 0x00, +0x20, 0x94, 0x06, 0x00, +0x00, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x02, 0x00, 0x00, 0x00, +0xa0, 0x08, 0x1a, 0x0c, +0x3a, 0xab, 0xfe, 0x09, +0x50, 0x28, 0x59, 0x04, +0x00, 0x80, 0x60, 0xa0, +0x0c, 0x08, 0x48, 0x21, +0x42, 0x10, 0x40, 0x81, +0x76, 0x88, 0x0e, 0x03, +0x21, 0x80, 0xbc, 0x18, +0x8a, 0x08, 0x11, 0x2a, +0x78, 0x02, 0x28, 0xc4, +0x32, 0x02, 0x0b, 0xc2, +0x45, 0x62, 0x00, 0x00, +0x00, 0xe4, 0x00, 0x00, +0x00, 0x00, 0x00, 0x88, +0x0a, 0x08, 0x81, 0xe1, +0x66, 0x00, 0x00, 0x98, +0x80, 0x88, 0x1a, 0x18, +0x80, 0x20, 0xa0, 0x82, +0x18, 0x43, 0x20, 0x88, +0x1e, 0x16, 0x60, 0x00, +0x09, 0x88, 0x08, 0x81, +0xa1, 0x00, 0x00, 0x0a, +0x08, 0x21, 0xbc, 0x11, +0x78, 0x81, 0x36, 0x88, +0x0a, 0x06, 0x40, 0x00, +0x09, 0x88, 0xfa, 0x80, +0x20, 0x39, 0x02, 0x08, +0x80, 0x21, 0x00, 0x00, +0x0a, 0x08, 0xa0, 0x80, +0x02, 0x18, 0x80, 0x60, +0x66, 0x00, 0x00, 0x99, +0x60, 0x88, 0x02, 0x1b, +0x00, 0x20, 0xa0, 0xc8, +0x19, 0x48, 0x60, 0x00, +0x00, 0x08, 0x81, 0x36, +0xba, 0x14, 0x8a, 0x80, +0x20, 0x40, 0x00, 0x03, +0x80, 0x00, 0xa0, 0x04, +0x99, 0x48, 0x2c, 0x59, +0x05, 0x02, 0x08, 0x7a, +0xab, 0xff, 0x08, 0x80, +0x76, 0x42, 0x06, 0xc2, +0x00, 0x01, 0x85, 0x02, +0x08, 0x4a, 0x21, 0x66, +0x00, 0x00, 0x98, 0x88, +0x40, 0x00, 0x02, 0x08, +0x11, 0x40, 0x00, 0x03, +0x80, 0x00, 0x40, 0x00, +0x03, 0x80, 0x00, 0x40, +0x00, 0x03, 0x80, 0x00, +0xbc, 0x09, 0x7a, 0x08, +0xa1, 0xa0, 0xc6, 0x28, +0x48, 0x21, 0x88, 0x0e, +0x26, 0x60, 0x00, 0x09, +0x96, 0x08, 0x80, 0xa0, +0xb0, 0x02, 0x49, 0x40, +0x64, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x10, 0x40, +0x00, 0x03, 0x80, 0x00, +0x98, 0x80, 0x86, 0x80, +0x00, 0x00, 0x40, 0xa3, +0x01, 0xa0, 0xbc, 0x0d, +0x18, 0x42, 0x21, 0xb0, +0x78, 0x49, 0x48, 0x2e, +0x30, 0x13, 0x0b, 0xc0, +0x60, 0xb0, 0x78, 0xc3, +0x01, 0x30, 0x40, 0x00, +0x03, 0xc0, 0x41, 0x64, +0x00, 0x00, 0xbc, 0xc7, +0x64, 0x00, 0x00, 0xb1, +0x07, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x84, 0x22, +0x1a, 0xbf, 0xe0, 0x94, +0x8a, 0xc5, 0x55, 0xf2, +0x08, 0x07, 0x63, 0x20, +0x20, 0xbc, 0x09, 0x1a, +0x08, 0x11, 0x66, 0x00, +0x00, 0x98, 0x88, 0xa4, +0x04, 0x08, 0x81, 0x08, +0x32, 0x82, 0x0b, 0xc0, +0x21, 0x66, 0x00, 0x01, +0x6b, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x02, 0x00, 0x00, 0x00, +0x84, 0x22, 0x1b, 0x07, +0x84, 0x94, 0x8a, 0xe2, +0x89, 0x34, 0x32, 0x02, +0x0b, 0xc0, 0x60, 0x38, +0x08, 0x63, 0x01, 0xa0, +0x40, 0x00, 0x03, 0xc0, +0x41, 0x64, 0x00, 0x00, +0xb5, 0x87, 0x64, 0x00, +0x00, 0xb2, 0x07, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x84, 0x22, 0x1a, 0x00, +0xa2, 0x94, 0x8a, 0xe5, +0x90, 0xf8, 0x2b, 0xfe, +0x0b, 0xc1, 0x88, 0x88, +0x07, 0x63, 0x23, 0xf0, +0xbc, 0x2a, 0x98, 0x80, +0xe2, 0xa4, 0x04, 0x16, +0x80, 0x00, 0x00, 0xc2, +0x09, 0x88, 0x49, 0x66, +0x00, 0x00, 0x46, 0x08, +0x5c, 0x00, 0x71, 0x88, +0x08, 0x5c, 0x83, 0x00, +0x80, 0xa2, 0x00, 0x00, +0x08, 0x12, 0x21, 0x88, +0x0e, 0x26, 0x60, 0x00, +0x09, 0x96, 0x8a, 0x40, +0x40, 0x88, 0x0a, 0x0b, +0x00, 0x26, 0x94, 0x06, +0x6b, 0xc1, 0x57, 0x00, +0x00, 0x09, 0x44, 0xae, +0x32, 0x0b, 0x0b, 0xc0, +0x60, 0xa4, 0x04, 0x06, +0x60, 0x00, 0x09, 0x88, +0x8a, 0x08, 0x11, 0xbc, +0x0c, 0xf8, 0x81, 0x39, +0x5c, 0x83, 0x00, 0x81, +0x79, 0x00, 0x00, 0x08, +0x12, 0x21, 0x88, 0x0e, +0x26, 0x60, 0x00, 0x09, +0x96, 0x8a, 0x40, 0x40, +0x88, 0x0a, 0x0b, 0x00, +0x26, 0x94, 0x06, 0x60, +0x00, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x02, 0x00, 0x00, 0x00, +0x5c, 0x81, 0x02, 0xbf, +0x70, 0x68, 0x20, 0x00, +0x23, 0x2c, 0x5c, 0x07, +0xe2, 0x40, 0x41, 0x80, +0x86, 0xc6, 0x82, 0x00, +0x28, 0xd2, 0xc8, 0x08, +0x6c, 0x68, 0x20, 0x02, +0x8e, 0x2c, 0x80, 0x86, +0xc6, 0x82, 0x00, 0x28, +0xf2, 0xc8, 0x08, 0x6c, +0x68, 0x20, 0x02, 0x90, +0x2c, 0x80, 0x86, 0xc6, +0x82, 0x00, 0x29, 0x12, +0xc8, 0x08, 0x6c, 0x68, +0x20, 0x02, 0x98, 0x2c, +0x80, 0x86, 0xc6, 0x82, +0x00, 0x29, 0x32, 0xc8, +0x08, 0x6c, 0x68, 0x20, +0x02, 0x92, 0x2c, 0x80, +0x86, 0xc8, 0x08, 0x7a, +0x68, 0x20, 0x02, 0x94, +0x2c, 0x80, 0x86, 0xc6, +0x82, 0x00, 0x29, 0x52, +0xc8, 0x08, 0x6c, 0x68, +0x20, 0x02, 0x96, 0x2c, +0x84, 0x86, 0xca, 0x08, +0x21, 0x68, 0x20, 0x02, +0x97, 0x2c, 0x84, 0x22, +0x28, 0x48, 0x6c, 0xa0, +0x82, 0x19, 0x50, 0xae, +0x55, 0x21, 0x80, 0x48, +0x6c, 0x51, 0x84, 0x02, +0x08, 0x21, 0x58, 0x09, +0x80, 0x48, 0x7a, 0xa0, +0xde, 0x19, 0x84, 0x28, +0x9c, 0x80, 0x1a, 0x00, +0x03, 0x42, 0x1a, 0xe0, +0x48, 0x20, 0x98, 0x80, +0x83, 0x20, 0x20, 0xbc, +0x2f, 0x09, 0x5c, 0xac, +0x32, 0x0a, 0x0b, 0xc2, +0x00, 0x32, 0x1a, 0x0b, +0xc2, 0xd1, 0x5c, 0x0e, +0x22, 0x19, 0x01, 0x84, +0x80, 0xa2, 0x59, 0x30, +0xbc, 0x05, 0x9a, 0x0c, +0xe1, 0xba, 0x14, 0x8a, +0x80, 0x90, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x20, 0x02, 0x7d, 0x24, +0x68, 0x00, 0x02, 0x61, +0xac, 0x9e, 0x00, 0x48, +0x60, 0x00, 0x98, 0xb0, +0x23, 0x00, 0x80, 0xbc, +0x05, 0x98, 0x48, 0x50, +0xba, 0x14, 0x8a, 0x80, +0x90, 0x40, 0x00, 0x03, +0x80, 0x00, 0x52, 0x09, +0xa2, 0x10, 0x11, 0x85, +0xc4, 0x86, 0x40, 0x00, +0x09, 0x88, 0xfa, 0x80, +0x90, 0xa1, 0x8a, 0x1a, +0x0c, 0x62, 0x84, 0x82, +0x18, 0x80, 0x62, 0x88, +0x0f, 0x66, 0x60, 0x00, +0x09, 0x96, 0x08, 0x80, +0x20, 0x88, 0x0b, 0x64, +0x20, 0x27, 0xb0, 0x02, +0x49, 0x40, 0x64, 0xba, +0x14, 0x8a, 0x80, 0x90, +0x00, 0x00, 0x0b, 0xa1, +0x48, 0xa8, 0x09, 0x00, +0x00, 0x00, 0x84, 0x22, +0x1b, 0x07, 0x84, 0x94, +0x8a, 0xe2, 0x89, 0x34, +0x32, 0x02, 0x0b, 0xc0, +0xa0, 0x38, 0x08, 0x63, +0x01, 0xa0, 0xbc, 0x05, +0x03, 0x81, 0x06, 0x30, +0x1a, 0x0b, 0xc0, 0x61, +0x64, 0x00, 0x00, 0xc0, +0x07, 0x64, 0x00, 0x00, +0xbf, 0x07, 0x64, 0x00, +0x00, 0xbe, 0x07, 0x40, +0x00, 0x03, 0xa1, 0x40, +0xa0, 0x0a, 0x1a, 0x08, +0x60, 0xab, 0xff, 0x08, +0x48, 0x21, 0x88, 0x06, +0x08, 0x80, 0xf6, 0x66, +0x00, 0x00, 0x99, 0x60, +0x88, 0x02, 0x08, 0x80, +0xb6, 0xa0, 0x4c, 0x04, +0x60, 0xa4, 0x30, 0x02, +0x49, 0x40, 0x64, 0x40, +0x00, 0x02, 0x80, 0x10, +0x5c, 0x04, 0x60, 0x42, +0x20, 0x00, 0x00, 0x09, +0x40, 0xae, 0x30, 0x13, +0x0b, 0xc0, 0x81, 0x6c, +0x40, 0x04, 0x02, 0x08, +0x38, 0x10, 0x65, 0x20, +0xd2, 0x3a, 0x14, 0x86, +0xc4, 0x00, 0x40, 0x24, +0x80, 0x00, 0x00, 0x40, +0x00, 0x03, 0xa1, 0x40, +0xab, 0xfe, 0x0a, 0x00, +0xa1, 0x6c, 0x40, 0x03, +0xba, 0x08, 0x68, 0x00, +0xf0, 0x03, 0x0a, 0x54, +0x4d, 0x22, 0x0c, 0x62, +0xa4, 0x04, 0x08, 0x48, +0x21, 0x84, 0x04, 0x88, +0x80, 0x62, 0x88, 0x0f, +0x66, 0x60, 0x00, 0x09, +0x96, 0x08, 0x80, 0x20, +0x88, 0x0b, 0x64, 0x60, +0xa4, 0x30, 0x02, 0x49, +0x40, 0x64, 0x40, 0x00, +0x02, 0x80, 0x20, 0x68, +0x20, 0x02, 0x01, 0x20, +0x38, 0x16, 0x48, 0x40, +0x0a, 0x25, 0x93, 0x0b, +0xc0, 0x61, 0x5c, 0x0c, +0x22, 0xc6, 0x80, 0x52, +0x09, 0x82, 0x00, 0x01, +0xbc, 0x07, 0xf8, 0x00, +0x50, 0x5c, 0x0e, 0x22, +0xc0, 0x20, 0x52, 0x09, +0xa2, 0x00, 0x01, 0x40, +0x00, 0x00, 0x00, 0x48, +0x5c, 0x80, 0x49, 0x88, +0x0b, 0x68, 0x34, 0x0c, +0x08, 0x20, 0x5c, 0x81, +0x02, 0x0c, 0x39, 0x5c, +0x00, 0x69, 0x8e, 0x88, +0x68, 0x00, 0x03, 0xff, +0x00, 0x54, 0x41, 0xf9, +0x48, 0xc4, 0x5c, 0x08, +0x30, 0x40, 0x4b, 0xa0, +0x02, 0x0a, 0x00, 0x02, +0x94, 0x8c, 0x49, 0x48, +0x64, 0xb0, 0x66, 0x48, +0x00, 0x48, 0xa0, 0x82, +0x98, 0x48, 0x08, 0x52, +0x4d, 0x20, 0x50, 0xfa, +0x46, 0x0a, 0x40, 0x40, +0xc9, 0x84, 0x84, 0x80, +0x00, 0x00, 0x68, 0x38, +0x08, 0x02, 0x20, 0x5c, +0x03, 0xa3, 0x00, 0x8e, +0x84, 0x04, 0x8a, 0x01, +0x80, 0x84, 0x04, 0x86, +0xc0, 0x00, 0x62, 0x07, +0xa4, 0x60, 0xa4, 0x20, +0x50, 0x08, 0x40, 0x4a, +0x40, 0x00, 0x03, 0x80, +0x00, 0xab, 0xfe, 0x08, +0x80, 0x76, 0xb0, 0x1b, +0xd6, 0x60, 0x00, 0x05, +0xf6, 0x8b, 0x00, 0x14, +0x88, 0x0f, 0xab, 0x03, +0x85, 0x40, 0x00, 0x03, +0x01, 0x8e, 0x68, 0x00, +0x03, 0x03, 0x20, 0x6e, +0x00, 0x06, 0x06, 0x65, +0x94, 0x0e, 0x6b, 0x00, +0x14, 0x66, 0x00, 0x00, +0x5f, 0xe8, 0x40, 0x00, +0x01, 0x8e, 0x89, 0x6c, +0x00, 0x06, 0x20, 0x09, +0x32, 0x22, 0x8b, 0xff, +0xc1, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x84, +0x03, 0x07, 0x85, 0xa0, +0x80, 0x09, 0x48, 0x45, +0x88, 0x16, 0x1b, 0x00, +0x0d, 0x66, 0x00, 0x00, +0x61, 0xc8, 0x55, 0x01, +0x61, 0x8e, 0x8a, 0x6c, +0x00, 0x06, 0x20, 0x09, +0x32, 0x22, 0x8b, 0xff, +0xc1, 0x5c, 0x0c, 0x68, +0x81, 0x21, 0xb0, 0x47, +0xe9, 0x48, 0x2c, 0x30, +0x16, 0x0b, 0xc0, 0x48, +0x88, 0x1f, 0xab, 0x00, +0x0d, 0x40, 0x00, 0x00, +0x81, 0xc9, 0x6e, 0x00, +0x06, 0x06, 0x66, 0xb0, +0x00, 0xd6, 0x80, 0x00, +0x30, 0x32, 0x06, 0x60, +0x00, 0x06, 0x1c, 0x85, +0x50, 0x16, 0x18, 0xe8, +0xa3, 0x83, 0x55, 0x6c, +0x00, 0x06, 0x20, 0x0a, +0x32, 0x23, 0x0b, 0xff, +0xc1, 0x88, 0x12, 0x10, +0x00, 0x00, 0x94, 0x82, +0xe3, 0x01, 0x70, 0xbc, +0x03, 0x88, 0x81, 0x88, +0x40, 0x00, 0x03, 0x00, +0x0c, 0x59, 0x01, 0x00, +0x80, 0x89, 0x5c, 0x19, +0x33, 0xc0, 0x60, 0x55, +0x03, 0x43, 0x03, 0x85, +0x58, 0x0c, 0x00, 0x80, +0xd0, 0xbf, 0xb9, 0xab, +0x01, 0x8e, 0x32, 0x02, +0x0b, 0xc0, 0x48, 0x5c, +0x00, 0x6b, 0x80, 0x00, +0x6c, 0x00, 0x06, 0x22, +0x49, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x80, +0x43, 0x03, 0x8d, 0xa0, +0x80, 0x09, 0x48, 0x45, +0xb0, 0x01, 0x49, 0x48, +0x64, 0x88, 0x0e, 0x16, +0x60, 0x00, 0x05, 0xfe, +0x89, 0x8e, 0x89, 0x6c, +0x00, 0x06, 0x20, 0x09, +0x32, 0x22, 0x8b, 0xff, +0xc1, 0xb0, 0x39, 0x56, +0xe0, 0x00, 0x60, 0x66, +0x5b, 0x03, 0xc5, 0x88, +0x0a, 0x16, 0x80, 0x00, +0x30, 0x32, 0x09, 0x48, +0x65, 0xb0, 0x01, 0x46, +0x60, 0x00, 0x05, 0xfe, +0x89, 0x8e, 0x89, 0x6c, +0x00, 0x06, 0x20, 0x09, +0x32, 0x22, 0x8b, 0xff, +0xc1, 0x88, 0x03, 0x6b, +0xa1, 0x48, 0xa8, 0x02, +0x00, 0x00, 0x00, 0xab, +0xfe, 0x08, 0x80, 0x76, +0xb0, 0x1b, 0xd6, 0x60, +0x00, 0x05, 0xf6, 0x8b, +0x00, 0x14, 0x88, 0x0f, +0xab, 0x00, 0xfd, 0x40, +0x00, 0x03, 0x00, 0x44, +0x68, 0x00, 0x03, 0x03, +0x20, 0x6e, 0x00, 0x06, +0x06, 0x65, 0x94, 0x0e, +0x49, 0x8e, 0x89, 0x66, +0x00, 0x00, 0x5f, 0xe8, +0x40, 0x00, 0x03, 0x00, +0x14, 0x6c, 0x00, 0x06, +0x20, 0x09, 0x32, 0x22, +0x8b, 0xff, 0xc1, 0x68, +0x00, 0x03, 0x03, 0x21, +0x5c, 0x84, 0x03, 0x04, +0x05, 0xa0, 0x80, 0x09, +0x48, 0x45, 0x88, 0x16, +0x1b, 0x00, 0x0d, 0x66, +0x00, 0x00, 0x61, 0xc8, +0x55, 0x01, 0x61, 0x8e, +0x8a, 0x6c, 0x00, 0x06, +0x20, 0x09, 0x32, 0x22, +0x8b, 0xff, 0xc1, 0x88, +0x12, 0x0b, 0x06, 0xcd, +0x94, 0x02, 0xc5, 0x80, +0xb0, 0x08, 0x08, 0x9b, +0xc0, 0x80, 0x55, 0x03, +0x6b, 0x03, 0x24, 0x58, +0x09, 0x40, 0x80, 0xc9, +0x43, 0xeb, 0x53, 0x00, +0x44, 0x40, 0x00, 0x03, +0x00, 0xfd, 0x68, 0x00, +0x03, 0x03, 0x21, 0x5c, +0x80, 0x43, 0x00, 0x6d, +0xa0, 0x80, 0x09, 0x48, +0x45, 0xb0, 0x00, 0xd9, +0x48, 0x65, 0x88, 0x0e, +0x1b, 0x00, 0x14, 0x66, +0x00, 0x00, 0x5f, 0xe8, +0x40, 0x00, 0x01, 0x8e, +0x89, 0x6c, 0x00, 0x06, +0x20, 0x09, 0x32, 0x22, +0x8b, 0xff, 0xc1, 0xb0, +0x06, 0x56, 0xe0, 0x00, +0x60, 0x66, 0x59, 0x8e, +0x89, 0x88, 0x0a, 0x00, +0x00, 0x00, 0x94, 0x06, +0x56, 0x80, 0x00, 0x30, +0x32, 0x06, 0x60, 0x00, +0x05, 0xfe, 0x8b, 0x00, +0x14, 0x6c, 0x00, 0x06, +0x20, 0x09, 0x32, 0x22, +0x8b, 0xff, 0xc1, 0xb0, +0x05, 0xd8, 0x80, 0xa0, +0x6e, 0x00, 0x06, 0x06, +0x65, 0x94, 0x06, 0x56, +0x80, 0x00, 0x30, 0x32, +0x0b, 0x00, 0x14, 0x66, +0x00, 0x00, 0x5f, 0xe8, +0x40, 0x00, 0x01, 0x8e, +0x89, 0x6c, 0x00, 0x06, +0x20, 0x09, 0x32, 0x22, +0x8b, 0xff, 0xc1, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0x68, 0x00, 0x03, +0x50, 0x20, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x29, +0xc6, 0x00, 0x00, 0x00, +0xab, 0xfd, 0x08, 0x80, +0x76, 0x68, 0x00, 0x01, +0x14, 0x20, 0x66, 0x00, +0x00, 0xf2, 0x60, 0x68, +0x00, 0x01, 0x1f, 0x20, +0x66, 0x00, 0x00, 0xf2, +0x60, 0x68, 0x00, 0x01, +0x2a, 0x20, 0x66, 0x00, +0x00, 0xf2, 0x60, 0x68, +0x00, 0x01, 0x1f, 0x20, +0x5c, 0x81, 0x0a, 0xc0, +0xc0, 0xa0, 0x0e, 0x06, +0x80, 0x00, 0x11, 0x42, +0x46, 0xc4, 0x00, 0x39, +0x40, 0x98, 0x00, 0x88, +0x44, 0x09, 0x02, 0x20, +0xe4, 0x68, 0x00, 0x01, +0x2a, 0x21, 0x6c, 0x40, +0x03, 0x8c, 0x09, 0x82, +0x08, 0x84, 0x40, 0x88, +0x20, 0x8e, 0x16, 0xc4, +0x00, 0x39, 0xc0, 0x98, +0x08, 0x88, 0x44, 0x08, +0x01, 0x80, 0x8a, 0x6c, +0x40, 0x00, 0x42, 0x08, +0x46, 0x08, 0x89, 0x80, +0x09, 0x4d, 0x25, 0x00, +0x02, 0x4a, 0x51, 0x62, +0x09, 0x80, 0x4a, 0x44, +0x40, 0x00, 0x0a, 0x49, +0x51, 0x62, 0x00, 0x22, +0x4a, 0x51, 0x62, 0x91, +0x83, 0x09, 0x88, 0x2e, +0x48, 0x80, 0xcd, 0x84, +0x84, 0xe8, 0x81, 0xc9, +0x88, 0x16, 0x18, 0x82, +0x60, 0x68, 0x20, 0x01, +0x90, 0x24, 0x66, 0x00, +0x00, 0xf2, 0xc8, 0x46, +0x08, 0x08, 0x80, 0x8a, +0x88, 0x2a, 0x08, 0x80, +0x89, 0x84, 0x04, 0x86, +0x82, 0x00, 0x19, 0x22, +0x46, 0x60, 0x00, 0x0f, +0x2c, 0x88, 0x81, 0x8a, +0x5c, 0x82, 0x00, 0x82, +0xa0, 0x88, 0x22, 0x48, +0x00, 0x09, 0x86, 0x04, +0x88, 0x80, 0xe0, 0x68, +0x20, 0x01, 0x80, 0x24, +0x68, 0x00, 0x00, 0xf2, +0x20, 0x66, 0x00, 0x00, +0x48, 0xa0, 0x5c, 0x82, +0x00, 0x82, 0x20, 0x88, +0x2a, 0x48, 0x00, 0x09, +0x86, 0x14, 0x88, 0x81, +0xe0, 0x68, 0x20, 0x01, +0x80, 0x24, 0x68, 0x00, +0x00, 0xfe, 0x20, 0x66, +0x00, 0x00, 0x48, 0xa0, +0x5c, 0x82, 0x00, 0x81, +0x20, 0x88, 0x22, 0x48, +0x00, 0x09, 0x86, 0x14, +0x88, 0x82, 0x60, 0x68, +0x20, 0x01, 0x80, 0x24, +0x68, 0x00, 0x01, 0x0a, +0x20, 0x66, 0x00, 0x00, +0x48, 0xa0, 0x5c, 0x81, +0x00, 0x80, 0xa1, 0x68, +0x20, 0x01, 0x80, 0x20, +0x88, 0x12, 0x2a, 0x00, +0x64, 0x80, 0x80, 0x98, +0x51, 0x48, 0x88, 0x0e, +0x48, 0x81, 0x61, 0x68, +0x00, 0x00, 0xf2, 0x23, +0x66, 0x00, 0x00, 0x48, +0xa8, 0x40, 0x00, 0x02, +0x18, 0x40, 0x5c, 0x85, +0x08, 0x81, 0x21, 0x5c, +0x81, 0x00, 0x81, 0xa2, +0x80, 0xac, 0x88, 0x81, +0x61, 0x68, 0x00, 0x00, +0xfe, 0x20, 0x81, 0x00, +0x98, 0x80, 0xa4, 0x88, +0x1e, 0x26, 0x60, 0x00, +0x04, 0x8a, 0x8a, 0x00, +0x40, 0x5c, 0x85, 0x08, +0x82, 0x21, 0x5c, 0x81, +0x00, 0x81, 0xa2, 0x80, +0x80, 0x98, 0x12, 0xc8, +0x88, 0x1e, 0x26, 0x80, +0x00, 0x10, 0xa2, 0x08, +0x80, 0xa4, 0x88, 0x0e, +0x16, 0x60, 0x00, 0x04, +0x8a, 0x8a, 0x00, 0x40, +0x5c, 0x85, 0x00, 0x80, +0xa4, 0x88, 0x12, 0x08, +0x22, 0x48, 0x88, 0x0e, +0x46, 0x60, 0x00, 0x0f, +0x32, 0x08, 0x81, 0xa0, +0x66, 0x00, 0x00, 0xf3, +0x20, 0x88, 0x0a, 0x06, +0x60, 0x00, 0x0f, 0x32, +0x08, 0x80, 0x36, 0x68, +0x00, 0x03, 0x7b, 0x20, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x29, 0xc6, 0x0a, +0x80, 0x30, 0x68, 0x00, +0x01, 0x25, 0x24, 0xab, +0xfc, 0x06, 0xc0, 0x00, +0x0f, 0x80, 0xb6, 0xc0, +0x00, 0x10, 0xa0, 0x06, +0xc0, 0x00, 0x1c, 0x80, +0x16, 0xc0, 0x00, 0x26, +0x00, 0xa8, 0x60, 0x09, +0x88, 0x05, 0x18, 0x80, +0xd0, 0x88, 0x14, 0xb8, +0x81, 0xf6, 0x68, 0x00, +0x01, 0x1a, 0x20, 0x66, +0x00, 0x00, 0xf9, 0x48, +0x40, 0x00, 0x00, 0x40, +0x08, 0x68, 0x00, 0x01, +0x1a, 0x20, 0x68, 0x20, +0x01, 0xcf, 0x24, 0x5c, +0x83, 0x02, 0xc0, 0x21, +0x68, 0x00, 0x01, 0x25, +0x21, 0xd8, 0x8c, 0x15, +0x70, 0xf4, 0x80, 0xa0, +0x08, 0x60, 0x09, 0x57, +0x0a, 0x00, 0x83, 0x60, +0x88, 0x24, 0x08, 0x82, +0xe1, 0x68, 0x20, 0x01, +0x7d, 0x24, 0x68, 0x00, +0x00, 0xf0, 0x20, 0x66, +0x00, 0x00, 0x48, 0xa8, +0x40, 0x00, 0x01, 0x80, +0x49, 0x68, 0x20, 0x01, +0x7d, 0x24, 0x68, 0x00, +0x00, 0xfc, 0x20, 0x66, +0x00, 0x00, 0x48, 0xa8, +0x40, 0x00, 0x00, 0x82, +0x09, 0x68, 0x00, 0x00, +0xf0, 0x20, 0x68, 0x20, +0x01, 0x94, 0x24, 0x84, +0x08, 0x96, 0x80, 0x00, +0x15, 0x02, 0x06, 0x60, +0x00, 0x04, 0x8a, 0x08, +0x83, 0x20, 0x68, 0x00, +0x00, 0xfc, 0x21, 0x84, +0x04, 0x86, 0x82, 0x00, +0x19, 0x42, 0x46, 0x80, +0x00, 0x15, 0x22, 0x06, +0x60, 0x00, 0x04, 0x8a, +0x88, 0x48, 0x89, 0x55, +0x01, 0x28, 0x83, 0x20, +0x5c, 0x83, 0x00, 0x82, +0xa4, 0x80, 0x20, 0x88, +0x60, 0x49, 0x40, 0x00, +0x00, 0x82, 0x60, 0x68, +0x00, 0x00, 0xf0, 0x21, +0x68, 0x20, 0x01, 0x7d, +0x24, 0x68, 0x00, 0x01, +0x3b, 0x22, 0x66, 0x00, +0x00, 0xf3, 0xa0, 0x5c, +0x83, 0x00, 0x82, 0xa0, +0x68, 0x00, 0x00, 0xfc, +0x21, 0x80, 0x20, 0x88, +0x82, 0xe0, 0x68, 0x20, +0x01, 0x7d, 0x24, 0x68, +0x00, 0x01, 0x3d, 0x22, +0x66, 0x00, 0x00, 0xf3, +0xa0, 0x5c, 0x83, 0x00, +0x82, 0x20, 0x68, 0x20, +0x01, 0xde, 0x24, 0xa0, +0x12, 0x08, 0x02, 0x09, +0x40, 0x00, 0x00, 0x82, +0x60, 0x68, 0x00, 0x01, +0x54, 0x20, 0x66, 0x00, +0x00, 0x48, 0xa0, 0x5c, +0x83, 0x00, 0x82, 0xa0, +0x68, 0x20, 0x01, 0xde, +0x24, 0xa0, 0x12, 0x08, +0x02, 0x09, 0x88, 0x2e, +0x06, 0x80, 0x00, 0x15, +0x62, 0x06, 0x60, 0x00, +0x04, 0x8a, 0x08, 0x81, +0x09, 0x36, 0x94, 0x46, +0xc4, 0x00, 0x03, 0xe0, +0xb5, 0x80, 0xf0, 0x18, +0xe8, 0x8b, 0xc0, 0x3a, +0x55, 0x01, 0x00, 0x80, +0x89, 0xb0, 0x00, 0xc3, +0x69, 0x41, 0x30, 0x1c, +0x8b, 0xc0, 0x3a, 0x55, +0x00, 0x08, 0x80, 0x09, +0xb0, 0x00, 0x93, 0x69, +0x45, 0x30, 0x1e, 0x8b, +0xc0, 0x12, 0xb0, 0x00, +0x83, 0x20, 0x20, 0xbc, +0x05, 0x98, 0x82, 0x20, +0x32, 0x00, 0x0b, 0xc0, +0x21, 0x32, 0x00, 0x8b, +0xc0, 0x60, 0x6c, 0x40, +0x00, 0x40, 0x09, 0x6c, +0x00, 0x02, 0x88, 0x49, +0x6c, 0x00, 0x02, 0x8a, +0x49, 0x39, 0x0c, 0x08, +0x02, 0x09, 0x40, 0x00, +0x00, 0x80, 0x60, 0x68, +0x20, 0x00, 0xaa, 0x24, +0x68, 0x00, 0x01, 0x40, +0x20, 0x66, 0x00, 0x00, +0x48, 0xa0, 0x5c, 0x86, +0x00, 0x82, 0xa0, 0x88, +0x0c, 0x86, 0x82, 0x00, +0x0c, 0x22, 0x48, 0x02, +0x09, 0x40, 0x00, 0x00, +0x81, 0x60, 0x68, 0x00, +0x01, 0x42, 0x20, 0x66, +0x00, 0x00, 0x48, 0xa0, +0x66, 0x00, 0x00, 0xfc, +0x08, 0x55, 0x01, 0x28, +0x80, 0x88, 0x6c, 0x00, +0x02, 0x88, 0x09, 0x32, +0x02, 0x8b, 0xc0, 0x84, +0x68, 0x00, 0x01, 0x1d, +0x20, 0x39, 0x06, 0x28, +0x40, 0x09, 0x42, 0x08, +0xf8, 0x40, 0xc9, 0x5c, +0x81, 0x02, 0xc0, 0x41, +0x68, 0x00, 0x00, 0xf7, +0x20, 0x5c, 0x82, 0x0a, +0xc0, 0x20, 0x5c, 0x83, +0x10, 0x00, 0xfa, 0x55, +0x3f, 0x68, 0x02, 0x7a, +0x80, 0x17, 0xa8, 0x02, +0x7a, 0x6c, 0x00, 0x02, +0x88, 0x49, 0x6c, 0x00, +0x02, 0x3c, 0x7a, 0x84, +0x07, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x02, 0x8a, +0x09, 0x32, 0x02, 0x8b, +0xc0, 0x64, 0x68, 0x00, +0x01, 0x28, 0x20, 0x00, +0x00, 0x08, 0x40, 0x09, +0x42, 0x06, 0x38, 0x40, +0xc9, 0x68, 0x00, 0x01, +0x03, 0x20, 0x2a, 0x7e, +0xd8, 0x00, 0xfa, 0x80, +0x27, 0xa8, 0x01, 0x7a, +0x80, 0x27, 0xa6, 0xc0, +0x00, 0x28, 0xa4, 0x96, +0xc0, 0x00, 0x25, 0x27, +0xa8, 0x40, 0x7a, 0x00, +0x00, 0x06, 0xc0, 0x00, +0x29, 0x00, 0x93, 0x20, +0x28, 0xbc, 0x04, 0x06, +0xc0, 0x00, 0x23, 0xc7, +0xa6, 0xc0, 0x00, 0x25, +0x27, 0xa3, 0x81, 0x2c, +0x6e, 0x00, 0x01, 0x2c, +0x2d, 0x25, 0x92, 0x8b, +0xc2, 0xc9, 0x88, 0x02, +0x03, 0x81, 0x3c, 0x25, +0x92, 0x8b, 0xc2, 0x81, +0x6c, 0x00, 0x02, 0xaa, +0x09, 0x36, 0x94, 0x06, +0xc4, 0x00, 0x3b, 0x20, +0x99, 0x80, 0x08, 0x30, +0x96, 0x0b, 0xc1, 0x24, +0x6c, 0x00, 0x02, 0xae, +0x08, 0x36, 0x90, 0x09, +0x80, 0x08, 0x30, 0x96, +0x0b, 0xc0, 0xc4, 0x6c, +0x40, 0x03, 0xb6, 0x09, +0x32, 0x02, 0x8b, 0xc1, +0x60, 0x2a, 0x7e, 0xd6, +0xc0, 0x00, 0x25, 0x27, +0xa6, 0xc0, 0x00, 0x23, +0xc7, 0xa6, 0xc4, 0x00, +0x3b, 0x64, 0x9b, 0xc0, +0xe7, 0x68, 0x20, 0x01, +0xda, 0x24, 0x6c, 0x40, +0x02, 0xc4, 0x09, 0x86, +0x00, 0x86, 0xc0, 0x00, +0x25, 0x27, 0xa6, 0xc0, +0x00, 0x23, 0xc7, 0xa6, +0xc4, 0x00, 0x15, 0x04, +0x96, 0xc4, 0x00, 0x18, +0x04, 0x98, 0x60, 0xc8, +0x68, 0x00, 0x00, 0xeb, +0x21, 0x66, 0x00, 0x00, +0xf8, 0x60, 0x88, 0x12, +0x06, 0x80, 0x00, 0x0e, +0xd2, 0x16, 0x60, 0x00, +0x0f, 0x86, 0x08, 0x81, +0xb6, 0x68, 0x00, 0x03, +0xc8, 0x20, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x29, +0xc6, 0x0a, 0x80, 0x40, +0x68, 0x00, 0x03, 0x4e, +0xa0, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x29, 0xc6, +0x00, 0x00, 0x00, 0x84, +0x00, 0x88, 0x40, 0x8a, +0x57, 0x0d, 0x03, 0xa1, +0x48, 0x84, 0x3c, 0x00, +0x00, 0x00, 0x86, 0x00, +0x84, 0x42, 0x00, 0x06, +0x08, 0x9b, 0xa1, 0x48, +0x08, 0x98, 0x09, 0x80, +0x08, 0xa0, 0x04, 0x0a, +0x00, 0x61, 0x84, 0x00, +0x88, 0x48, 0x0a, 0x57, +0x0d, 0x03, 0xa1, 0x48, +0x84, 0x8c, 0x00, 0x00, +0x00, 0x5c, 0x81, 0x02, +0x22, 0x23, 0x81, 0x80, +0x94, 0x40, 0x80, 0x05, +0x80, 0x95, 0x00, 0xa0, +0x20, 0x8c, 0x19, 0x80, +0x09, 0x80, 0x84, 0x9a, +0x1c, 0x64, 0x82, 0x00, +0x84, 0x42, 0x00, 0x06, +0x00, 0x98, 0x48, 0x08, +0x44, 0x0c, 0x02, 0xbf, +0xd0, 0x98, 0x00, 0x9a, +0x24, 0xe4, 0x80, 0x84, +0x98, 0x80, 0x61, 0x88, +0x0e, 0x48, 0x81, 0x62, +0x88, 0x1e, 0x08, 0x82, +0x76, 0x66, 0x00, 0x00, +0x48, 0xa8, 0xa0, 0x80, +0x08, 0x80, 0x20, 0x88, +0x0a, 0x2a, 0x00, 0x40, +0x88, 0x06, 0x06, 0x60, +0x00, 0x04, 0x8a, 0x85, +0x50, 0x12, 0xa1, 0x06, +0x48, 0x80, 0x20, 0x88, +0x12, 0x2a, 0x04, 0x60, +0x84, 0x00, 0x95, 0x70, +0x94, 0x05, 0x08, 0x95, +0x70, 0xa0, 0x08, 0x1a, +0x09, 0x80, 0x08, 0x59, +0x01, 0x00, 0x44, 0xc8, +0xbc, 0x0e, 0x43, 0x20, +0x20, 0xbc, 0x17, 0x38, +0x50, 0x08, 0x2e, 0x12, +0xd5, 0xb4, 0xa0, 0x05, +0x0c, 0x99, 0x80, 0x09, +0x6c, 0x40, 0x02, 0x02, +0x08, 0x30, 0x12, 0x8b, +0xc0, 0xe5, 0x36, 0x10, +0x58, 0x50, 0xc9, 0xbc, +0x0b, 0x78, 0x50, 0x08, +0x28, 0x12, 0xd5, 0xb4, +0xa0, 0x05, 0x0c, 0x99, +0x80, 0x09, 0x6c, 0x40, +0x02, 0x02, 0x08, 0x30, +0x12, 0x8b, 0xc0, 0x25, +0x85, 0x0c, 0x80, 0x00, +0x00, 0x88, 0x23, 0x6b, +0xa1, 0x48, 0xa8, 0x03, +0x00, 0x00, 0x00, 0x84, +0x50, 0x86, 0xc4, 0x00, +0x34, 0x20, 0xa4, 0x41, +0x00, 0x3a, 0x11, 0x19, +0x80, 0x08, 0x68, 0x03, +0x94, 0xbb, 0x8a, 0x08, +0x20, 0x05, 0x15, 0xc0, +0x3a, 0x14, 0x88, 0x48, +0xcc, 0x40, 0x00, 0x03, +0xa1, 0x01, 0x44, 0x19, +0x81, 0x82, 0x02, 0x5b, +0x0c, 0x22, 0xbf, 0xf0, +0x44, 0x18, 0x81, 0x84, +0x4b, 0x44, 0x39, 0x01, +0x84, 0x88, 0x5b, 0x08, +0x28, 0x80, 0x49, 0x44, +0x38, 0x01, 0x84, 0x09, +0x44, 0x49, 0x81, 0x80, +0xca, 0x51, 0x85, 0xa0, +0x80, 0x0a, 0x5b, 0x0c, +0x31, 0x80, 0x8b, 0x44, +0x48, 0x81, 0xa1, 0x42, +0x55, 0x01, 0x11, 0x80, +0x08, 0x51, 0x85, 0xc2, +0xc0, 0x20, 0x51, 0x85, +0x59, 0x80, 0x49, 0x23, +0x0a, 0x42, 0x30, 0xb6, +0x11, 0x64, 0x85, 0x18, +0x56, 0x1a, 0x04, 0x26, +0xc4, 0x00, 0x04, 0x40, +0xb6, 0x82, 0x00, 0x1c, +0xf2, 0x01, 0x12, 0x83, +0x44, 0x38, 0x01, 0x80, +0x0a, 0x44, 0x58, 0x80, +0x00, 0x42, 0x46, 0x0a, +0x40, 0x00, 0x40, 0x84, +0x04, 0x1a, 0x80, 0x10, +0x6e, 0x00, 0x01, 0x2c, +0x2e, 0x38, 0x13, 0x22, +0x58, 0xb0, 0xbc, 0x05, +0x82, 0xa0, 0x2a, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x29, 0x07, 0xa0, 0x00, +0x00, 0x68, 0x00, 0x01, +0x46, 0x21, 0x68, 0x20, +0x01, 0xd2, 0x24, 0x5c, +0x81, 0x08, 0x48, 0x0b, +0x5c, 0x82, 0x00, 0x20, +0x8a, 0x68, 0x00, 0x01, +0x4a, 0x20, 0x30, 0x1b, +0x84, 0x20, 0xec, 0x00, +0x00, 0x08, 0x02, 0x89, +0x68, 0x00, 0x01, 0x46, +0x20, 0x55, 0x03, 0xf2, +0xc0, 0xa0, 0x58, 0x01, +0x00, 0x00, 0x4a, 0xbc, +0x03, 0x56, 0xc0, 0x00, +0x29, 0x44, 0x80, 0x00, +0x00, 0x84, 0x00, 0xa3, +0x01, 0xa0, 0xbc, 0x02, +0x36, 0xc0, 0x00, 0x29, +0x64, 0x83, 0x01, 0x50, +0xbc, 0x03, 0x56, 0xc0, +0x00, 0x29, 0x85, 0x20, +0x00, 0x00, 0x84, 0x10, +0x83, 0x01, 0x10, 0xbc, +0x04, 0x3b, 0xa1, 0x48, +0x6c, 0x00, 0x02, 0x9a, +0x52, 0x00, 0x00, 0x0b, +0xa1, 0x40, 0x80, 0x00, +0x25, 0x70, 0x40, 0x86, +0x00, 0x35, 0x84, 0x64, +0x00, 0x28, 0x84, 0x20, +0x1d, 0x98, 0xe8, 0xa5, +0x70, 0x94, 0x98, 0x28, +0xbb, 0x00, 0x0e, 0x30, +0x8c, 0x8b, 0xc0, 0x23, +0x40, 0x00, 0x03, 0x00, +0x0f, 0x5b, 0x40, 0x00, +0x60, 0x83, 0x36, 0x88, +0x22, 0xf0, 0x82, 0x30, +0x8d, 0x03, 0x69, 0x45, +0x5b, 0x48, 0x23, 0xc3, +0x6b, 0x2f, 0x12, 0xc3, +0x08, 0xe0, 0xbc, 0x33, +0x33, 0x20, 0x30, 0xbc, +0x04, 0x86, 0xc4, 0x00, +0x3a, 0xa0, 0x83, 0x20, +0x38, 0xbc, 0x0f, 0x13, +0x20, 0x30, 0xbc, 0x17, +0x13, 0x20, 0x38, 0xbc, +0x15, 0x16, 0xc0, 0x00, +0x29, 0x20, 0x93, 0x20, +0x28, 0xbc, 0x11, 0x56, +0xc4, 0x00, 0x3a, 0xe0, +0xa2, 0xe1, 0xad, 0x6c, +0x00, 0x02, 0x92, 0x49, +0x40, 0x00, 0x03, 0xc0, +0xa7, 0x6c, 0x00, 0x02, +0x92, 0x09, 0x30, 0x12, +0x8b, 0xc0, 0x63, 0x6c, +0x40, 0x03, 0xac, 0x0a, +0x28, 0x1a, 0xd6, 0xc0, +0x00, 0x29, 0x24, 0x90, +0x00, 0x00, 0x6c, 0x00, +0x02, 0x92, 0x09, 0x32, +0x06, 0x8b, 0xc0, 0x63, +0x68, 0x00, 0x01, 0x48, +0x21, 0x6c, 0x00, 0x02, +0x90, 0x7a, 0x84, 0x8f, +0xa0, 0x00, 0x00, 0x6c, +0x00, 0x02, 0x92, 0x09, +0x30, 0x12, 0x8b, 0xc0, +0x6a, 0x38, 0x00, 0xd6, +0x80, 0x00, 0x14, 0x82, +0x16, 0xc0, 0x00, 0x29, +0x04, 0x98, 0x48, 0xc8, +0x68, 0x20, 0x00, 0xec, +0x21, 0x39, 0x0a, 0x18, +0x48, 0x08, 0x80, 0x24, +0x88, 0x40, 0x48, 0xa0, +0x06, 0x08, 0x48, 0x88, +0x80, 0x24, 0x84, 0x60, +0xa4, 0x00, 0x2c, 0x88, +0x40, 0x7a, 0x40, 0x00, +0x03, 0x80, 0x00, 0xb0, +0x50, 0x46, 0xc0, 0x00, +0x27, 0xa4, 0x86, 0xc0, +0x00, 0x36, 0xa4, 0x8b, +0xa1, 0x48, 0x6c, 0x00, +0x02, 0x76, 0x48, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5c, 0x81, 0x01, 0x8e, +0x88, 0x68, 0x00, 0x00, +0xf0, 0x20, 0x68, 0x00, +0x00, 0xfc, 0x21, 0x68, +0x00, 0x01, 0x08, 0x22, +0x55, 0x01, 0x33, 0x80, +0x00, 0x55, 0x03, 0xb0, +0x00, 0x7a, 0x5d, 0x0c, +0x30, 0x08, 0x7a, 0x32, +0x2b, 0x0b, 0xff, 0xaa, +0x40, 0x00, 0x00, 0x10, +0x7a, 0x68, 0x00, 0x01, +0x21, 0x22, 0x68, 0x00, +0x01, 0x2c, 0x21, 0x68, +0x00, 0x01, 0x16, 0x20, +0x55, 0x03, 0x20, 0x10, +0x7a, 0x5d, 0x08, 0x20, +0x08, 0x7a, 0x32, 0x26, +0x0b, 0xff, 0xaa, 0x80, +0x07, 0xa6, 0x80, 0x00, +0x14, 0x62, 0x06, 0x82, +0x00, 0x0e, 0xc2, 0x15, +0xc8, 0x20, 0x80, 0x07, +0xa5, 0xc0, 0x16, 0x04, +0x0f, 0xa8, 0x00, 0x7a, +0xa0, 0x08, 0x08, 0x48, +0x0a, 0x80, 0x2c, 0xa8, +0x40, 0x4a, 0xa0, 0x06, +0x08, 0x48, 0x8a, 0x80, +0x2c, 0xa6, 0x80, 0x00, +0x14, 0x42, 0x16, 0x80, +0x00, 0x34, 0xea, 0xc8, +0x02, 0xca, 0x6c, 0x00, +0x02, 0x9c, 0x6c, 0x84, +0x87, 0xa4, 0x60, 0xa4, +0x04, 0x04, 0x88, 0x48, +0xfa, 0x40, 0x00, 0x03, +0x80, 0x00, 0x5c, 0x00, +0x32, 0xbf, 0xd0, 0x88, +0x04, 0x88, 0x80, 0xf6, +0x88, 0x17, 0xa2, 0x30, +0xb6, 0x98, 0x2a, 0x86, +0x82, 0x00, 0x00, 0x52, +0x06, 0x60, 0x00, 0x16, +0xda, 0x89, 0xc0, 0x00, +0x88, 0x10, 0xa5, 0x50, +0x3b, 0x08, 0x00, 0x03, +0xa9, 0x86, 0x2a, 0x04, +0x45, 0x90, 0x58, 0x08, +0x04, 0x8b, 0xff, 0x1a, +0x88, 0x14, 0xa6, 0x60, +0x00, 0x16, 0xda, 0x8a, +0x40, 0x80, 0x6c, 0x40, +0x00, 0x0a, 0x0a, 0x5d, +0x4c, 0x02, 0xc0, 0x20, +0x68, 0x20, 0x00, 0x05, +0x20, 0x68, 0x20, 0x00, +0x85, 0x21, 0x51, 0xa0, +0x00, 0x40, 0x82, 0x51, +0xe1, 0xb0, 0x82, 0x01, +0x51, 0xa1, 0xb0, 0x80, +0xb6, 0x5d, 0x44, 0x38, +0x08, 0x50, 0x51, 0xe0, +0xb0, 0x08, 0x4a, 0x23, +0x43, 0x85, 0x1a, 0x1b, +0x00, 0x85, 0x05, 0x15, +0x06, 0x00, 0x84, 0xa4, +0x60, 0xa4, 0x14, 0x86, +0x19, 0x48, 0xe4, 0x40, +0x00, 0x02, 0x80, 0x30, +0x59, 0x01, 0x02, 0xbf, +0x50, 0x68, 0x00, 0x01, +0x7e, 0x20, 0xbc, 0x07, +0x85, 0xc0, 0x02, 0x08, +0x17, 0x60, 0x00, 0x00, +0x6c, 0x00, 0x03, 0x0a, +0x08, 0xbc, 0x17, 0xf8, +0x86, 0xc8, 0x88, 0x24, +0x88, 0x81, 0xe0, 0x68, +0x00, 0x40, 0x01, 0x88, +0x88, 0x2c, 0x86, 0x60, +0x00, 0x16, 0xda, 0x08, +0x82, 0x08, 0x55, 0x03, +0x20, 0x81, 0xa0, 0x5d, +0x48, 0x30, 0x82, 0x88, +0x59, 0x0f, 0x82, 0x00, +0x20, 0x43, 0xfa, 0x50, +0x81, 0xe0, 0x55, 0x03, +0x20, 0x82, 0x4a, 0x66, +0x00, 0x01, 0x6d, 0xa8, +0x40, 0x00, 0x02, 0x41, +0xa0, 0x68, 0x00, 0x01, +0x81, 0x22, 0x5c, 0x81, +0x02, 0x40, 0xc0, 0x5c, +0x00, 0x09, 0x50, 0x37, +0x95, 0x0b, 0x56, 0x80, +0x00, 0x17, 0xe2, 0x22, +0x30, 0x8c, 0x55, 0x02, +0x61, 0x82, 0x29, 0x5d, +0x48, 0x09, 0xd0, 0x81, +0x59, 0x0e, 0x41, 0x48, +0x36, 0x57, 0x0f, 0x91, +0x48, 0xb4, 0x57, 0x0b, +0x01, 0xc0, 0x83, 0x43, +0xf9, 0xd1, 0x58, 0x72, +0x95, 0x8f, 0x05, 0xc8, +0x60, 0xa4, 0x1c, 0x38, +0x86, 0x88, 0x51, 0xa1, +0x22, 0x00, 0x22, 0x5b, +0x08, 0x10, 0x81, 0xe2, +0x51, 0x58, 0x82, 0x40, +0xc1, 0x2e, 0x11, 0x22, +0xe1, 0x11, 0x22, 0xb0, +0x95, 0x15, 0x89, 0x01, +0x84, 0x15, 0x15, 0x93, +0x01, 0x84, 0x25, 0x40, +0x90, 0x01, 0x84, 0x05, +0x40, 0x81, 0x01, 0x87, +0xa5, 0x15, 0x80, 0x01, +0x84, 0xa5, 0x15, 0x88, +0x01, 0x84, 0x08, 0x1a, +0xc0, 0x88, 0x06, 0x38, +0x82, 0x63, 0x68, 0x20, +0x00, 0x90, 0x23, 0x68, +0x20, 0x00, 0x8a, 0x24, +0x68, 0x20, 0x00, 0x8d, +0x25, 0x66, 0x00, 0x01, +0x1b, 0x48, 0x40, 0x00, +0x02, 0x00, 0x60, 0x5c, +0x81, 0x00, 0x86, 0x88, +0x51, 0x61, 0x20, 0x82, +0x23, 0x51, 0xa1, 0x22, +0xc0, 0xc1, 0x5b, 0x08, +0x10, 0x81, 0xa0, 0x22, +0xb1, 0x05, 0x70, 0x89, +0x20, 0x05, 0x05, 0x70, +0x88, 0xa0, 0x46, 0x12, +0x2b, 0x09, 0x51, 0x58, +0x90, 0x18, 0x41, 0x51, +0x59, 0x30, 0x18, 0x42, +0x54, 0x09, 0x00, 0x18, +0x40, 0x54, 0x08, 0x10, +0x18, 0x7a, 0x51, 0x58, +0x00, 0x18, 0x4a, 0x51, +0x58, 0x80, 0x18, 0x40, +0x81, 0xac, 0x08, 0x80, +0x63, 0x68, 0x20, 0x00, +0x98, 0xa3, 0x68, 0x20, +0x00, 0x92, 0xa4, 0x68, +0x20, 0x00, 0x95, 0xa5, +0x66, 0x00, 0x01, 0x1b, +0x48, 0xa0, 0x82, 0x28, +0x81, 0x36, 0xba, 0x14, +0x8a, 0x80, 0xb0, 0x40, +0x00, 0x03, 0x80, 0x00, +0xba, 0x14, 0x82, 0xe1, +0xa8, 0x40, 0x00, 0x01, +0x80, 0x08, 0x59, 0x06, +0x42, 0xbf, 0xd0, 0x49, +0xa9, 0xb8, 0x80, 0x76, +0xbc, 0x19, 0x89, 0xa0, +0x00, 0x32, 0x03, 0x0b, +0xc0, 0x29, 0x38, 0x10, +0x02, 0xa0, 0x76, 0x68, +0x00, 0x09, 0xc4, 0x09, +0x50, 0x41, 0x83, 0xa1, +0x11, 0x44, 0x08, 0x81, +0x01, 0x58, 0x5b, 0x40, +0x11, 0x02, 0x59, 0x66, +0x00, 0x02, 0x75, 0x88, +0x5b, 0x42, 0x0b, 0xa1, +0x01, 0x90, 0x11, 0x19, +0x02, 0x12, 0x29, 0x85, +0x13, 0x20, 0x08, 0xbc, +0x1a, 0x33, 0x60, 0x00, +0x37, 0x80, 0x0b, 0xc1, +0x77, 0x32, 0x02, 0x0b, +0xc0, 0x29, 0x38, 0x10, +0x02, 0xa0, 0x64, 0x68, +0x07, 0xff, 0xff, 0xc9, +0x50, 0x41, 0x03, 0xa1, +0x11, 0x44, 0x48, 0x81, +0x01, 0x58, 0x5b, 0x40, +0x11, 0x02, 0x59, 0x66, +0x00, 0x02, 0x75, 0x88, +0x5b, 0x42, 0x0b, 0xa1, +0x01, 0x90, 0x11, 0x19, +0x02, 0x12, 0x29, 0x85, +0x13, 0x20, 0x08, 0xbc, +0x02, 0x33, 0x60, 0x00, +0x37, 0x80, 0x08, 0x80, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x30, 0x40, 0x00, +0x03, 0x80, 0x00, 0x5b, +0x02, 0x03, 0x01, 0x01, +0x50, 0x43, 0x11, 0x84, +0x0a, 0x46, 0x08, 0x89, +0x83, 0x88, 0x44, 0x41, +0x09, 0x84, 0x8b, 0x98, +0x30, 0xa4, 0x47, 0x44, +0xab, 0xfe, 0x05, 0x08, +0x20, 0x08, 0x07, 0x60, +0x88, 0x82, 0x37, 0x80, +0x06, 0x80, 0x00, 0x9c, +0x40, 0x80, 0x84, 0x80, +0x6a, 0x00, 0x4e, 0x20, +0x02, 0x5b, 0x44, 0x11, +0x01, 0x58, 0x66, 0x00, +0x02, 0x75, 0x88, 0x5b, +0x40, 0x0b, 0xa1, 0x01, +0x90, 0x11, 0x26, 0xa0, +0x04, 0xe2, 0x00, 0x12, +0x98, 0x52, 0x32, 0x01, +0x0b, 0xc0, 0x3b, 0x88, +0x03, 0x63, 0x60, 0x00, +0x37, 0x80, 0x0b, 0xa1, +0x48, 0xa8, 0x02, 0x00, +0x00, 0x00, 0xab, 0xf8, +0x09, 0x40, 0x36, 0x88, +0x04, 0xa8, 0x80, 0xe5, +0x88, 0x16, 0x48, 0x81, +0xe3, 0x88, 0x26, 0x28, +0x82, 0xf6, 0x66, 0x00, +0x01, 0x15, 0x08, 0x40, +0x00, 0x01, 0x48, 0x35, +0x6a, 0x00, 0x02, 0x71, +0x00, 0x5b, 0x40, 0x00, +0x83, 0x48, 0x5c, 0x00, +0x21, 0x05, 0x58, 0x88, +0x3c, 0x88, 0x84, 0x54, +0x00, 0x00, 0x08, 0x80, +0x0a, 0x51, 0x85, 0x20, +0x82, 0x22, 0x98, 0x22, +0x89, 0xd0, 0x02, 0x88, +0x4e, 0x86, 0x60, 0x00, +0x11, 0x50, 0x89, 0x50, +0x35, 0x5b, 0x48, 0x3b, +0x01, 0xfe, 0x25, 0x9a, +0x06, 0x80, 0x01, 0xff, +0xfc, 0xab, 0xc0, 0x88, +0x55, 0x01, 0x00, 0x86, +0x48, 0x30, 0x1b, 0x8b, +0xc0, 0xcd, 0x88, 0x38, +0x16, 0x80, 0x01, 0xff, +0xfc, 0x0b, 0xc0, 0x87, +0x68, 0x00, 0x20, 0x00, +0x0a, 0x30, 0x1b, 0x8b, +0xc0, 0x4d, 0x40, 0x00, +0x00, 0x83, 0x81, 0x68, +0x00, 0x20, 0x00, 0x00, +0x59, 0x0a, 0x40, 0x81, +0xa2, 0xbc, 0x03, 0xb5, +0x50, 0x13, 0xac, 0x01, +0x09, 0x50, 0x50, 0x55, +0x02, 0x60, 0x81, 0xe2, +0x00, 0x00, 0x08, 0x84, +0xa8, 0x88, 0x82, 0x35, +0x18, 0x52, 0x08, 0x4c, +0x89, 0xd8, 0x04, 0x98, +0x22, 0x88, 0x60, 0x08, +0x9d, 0x80, 0x38, 0x83, +0x0a, 0x88, 0x6e, 0x46, +0x60, 0x00, 0x11, 0x54, +0x88, 0x58, 0x09, 0x88, +0x38, 0x83, 0x20, 0xe0, +0xbc, 0x13, 0x85, 0xc0, +0xfe, 0x19, 0x20, 0x19, +0x05, 0x12, 0x40, 0x00, +0x01, 0x07, 0x58, 0x66, +0x00, 0x02, 0x75, 0x88, +0x5b, 0x40, 0x08, 0x84, +0x16, 0x55, 0x00, 0x09, +0x07, 0x10, 0x6a, 0x00, +0x02, 0x71, 0x02, 0x29, +0x88, 0x23, 0x20, 0x10, +0xbc, 0x03, 0xb3, 0x81, +0xfc, 0x36, 0x04, 0x13, +0x78, 0x41, 0x52, 0xc8, +0x41, 0x83, 0x48, 0x68, +0x00, 0x1f, 0xff, 0xcb, +0xbc, 0x07, 0x83, 0x69, +0x04, 0x30, 0x1e, 0x0b, +0xc0, 0xa5, 0x6a, 0x00, +0x1f, 0xff, 0xc1, 0x40, +0x00, 0x03, 0xc0, 0x67, +0x68, 0x00, 0x20, 0x00, +0x0b, 0x30, 0x1e, 0x0b, +0xc0, 0x25, 0x6a, 0x00, +0x20, 0x00, 0x01, 0x5c, +0x80, 0x80, 0x81, 0x22, +0x98, 0x34, 0x19, 0x50, +0x51, 0x88, 0x16, 0x20, +0x00, 0x00, 0x88, 0x6a, +0x38, 0x83, 0x08, 0x66, +0x00, 0x01, 0x18, 0xe8, +0x55, 0x00, 0x08, 0x58, +0x09, 0x5c, 0x0f, 0xf9, +0x83, 0x08, 0x25, 0x9c, +0x05, 0xb4, 0x82, 0x3c, +0x09, 0x86, 0x80, 0x01, +0xff, 0xfc, 0xb3, 0x01, +0xe0, 0xbc, 0x0d, 0xd8, +0x84, 0x88, 0x6a, 0x00, +0x1f, 0xff, 0xc0, 0x40, +0x00, 0x03, 0xc0, 0x87, +0x68, 0x00, 0x20, 0x00, +0x0b, 0x30, 0x1e, 0x0b, +0xc0, 0x4d, 0x40, 0x00, +0x00, 0x84, 0x88, 0x6a, +0x00, 0x20, 0x00, 0x00, +0x5c, 0x80, 0x80, 0x80, +0xa2, 0x5d, 0x88, 0x21, +0x83, 0x00, 0x59, 0x0d, +0x00, 0x86, 0x0b, 0x95, +0x05, 0x08, 0x83, 0x4b, +0x88, 0x3c, 0x88, 0x80, +0xe2, 0xbf, 0x77, 0xa8, +0x80, 0x0a, 0x88, 0x2b, +0x6b, 0xa1, 0x48, 0xa8, +0x08, 0x00, 0x00, 0x00, +0x5c, 0x00, 0x02, 0xbf, +0xe0, 0x88, 0x04, 0x88, +0x80, 0xf6, 0x88, 0x17, +0xa2, 0x30, 0x80, 0x98, +0x42, 0x86, 0x82, 0x00, +0x00, 0x52, 0x06, 0x60, +0x00, 0x16, 0xda, 0x89, +0xc0, 0x00, 0x88, 0x10, +0x05, 0x50, 0x20, 0x08, +0x00, 0x23, 0xa8, 0x00, +0x2a, 0x05, 0x45, 0x90, +0x40, 0x08, 0x04, 0x8b, +0xff, 0x1a, 0x88, 0x15, +0x06, 0x82, 0x00, 0x00, +0x52, 0x06, 0xc4, 0x00, +0x00, 0xa0, 0x05, 0x1e, +0x02, 0x04, 0x08, 0x26, +0x82, 0x00, 0x1b, 0xa2, +0x05, 0xd4, 0x00, 0x08, +0x0b, 0x62, 0x3c, 0x16, +0x68, 0x20, 0x01, 0xbc, +0x21, 0x3a, 0x88, 0x12, +0x34, 0x00, 0x51, 0xa1, +0x10, 0x40, 0x50, 0x51, +0xa1, 0x80, 0x40, 0xd2, +0x51, 0xa0, 0x50, 0x48, +0xd0, 0xba, 0x14, 0x88, +0x48, 0x52, 0x40, 0x00, +0x02, 0x80, 0x20, 0x39, +0x02, 0x08, 0x00, 0x7a, +0x80, 0x07, 0xa8, 0x08, +0x7a, 0x80, 0x07, 0xa8, +0x08, 0x7a, 0x80, 0x87, +0xa4, 0x60, 0xa4, 0x04, +0x07, 0xa8, 0x48, 0x7a, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x00, +0x46, 0x08, 0x5d, 0x08, +0x33, 0x01, 0xc0, 0x52, +0x01, 0x02, 0xbf, 0xd0, +0x6c, 0x40, 0x00, 0x46, +0x50, 0x59, 0x01, 0x81, +0x8e, 0x88, 0x88, 0x0e, +0x04, 0x20, 0x6c, 0x08, +0x17, 0x65, 0x50, 0x13, +0x08, 0x04, 0xa0, 0x00, +0x00, 0x88, 0x00, 0x03, +0x20, 0x40, 0xbc, 0x07, +0x8b, 0x00, 0x0c, 0x88, +0x00, 0xa3, 0x20, 0xb0, +0xbc, 0x03, 0x92, 0xa0, +0x26, 0x40, 0x00, 0x01, +0x8e, 0x88, 0x59, 0x03, +0x00, 0x81, 0xc8, 0xbc, +0x11, 0x98, 0x82, 0x4a, +0x66, 0x00, 0x02, 0x42, +0x20, 0x6e, 0x00, 0x00, +0x92, 0x2c, 0x38, 0x10, +0x82, 0x58, 0x20, 0xbc, +0x09, 0x88, 0x82, 0x0a, +0x68, 0x20, 0x00, 0x76, +0x20, 0x00, 0x00, 0x08, +0x40, 0x08, 0x84, 0x0f, +0xa6, 0xc4, 0x00, 0x10, +0x44, 0x88, 0x40, 0x7a, +0x32, 0x07, 0x0b, 0xc1, +0x01, 0x66, 0x00, 0x02, +0x42, 0xe0, 0x6e, 0x00, +0x00, 0xba, 0x2c, 0x38, +0x10, 0xe2, 0x59, 0xa0, +0xbc, 0x09, 0x06, 0x82, +0x00, 0x07, 0xc2, 0x00, +0x00, 0x00, 0x84, 0x00, +0x86, 0xc4, 0x00, 0x10, +0x44, 0x88, 0x40, 0xfa, +0x40, 0x00, 0x00, 0x40, +0x7a, 0x68, 0x00, 0x00, +0x49, 0x20, 0x66, 0x00, +0x00, 0x51, 0xc8, 0x40, +0x00, 0x00, 0x81, 0x88, +0x68, 0x00, 0x00, 0x5d, +0x20, 0x66, 0x00, 0x00, +0x51, 0xc8, 0x88, 0x20, +0x88, 0x80, 0x08, 0x32, +0x02, 0x0b, 0xc1, 0x09, +0x88, 0x0a, 0x03, 0x81, +0xc4, 0xa0, 0x10, 0x08, +0x40, 0x0a, 0x24, 0x93, +0x66, 0xc4, 0x00, 0x04, +0x60, 0x05, 0x24, 0x82, +0x04, 0x04, 0xa6, 0xc4, +0x00, 0x04, 0x64, 0x86, +0x80, 0x00, 0x26, 0x1a, +0xc4, 0x20, 0x2f, 0xa0, +0x4e, 0x08, 0x40, 0x6c, +0x68, 0x00, 0x04, 0xbe, +0xa0, 0x6c, 0x00, 0x00, +0x0a, 0x60, 0x00, 0x00, +0x08, 0x81, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x20, 0x00, +0x82, 0x22, 0x68, 0x20, +0x00, 0x76, 0x23, 0x85, +0x00, 0x85, 0xb0, 0x83, +0x05, 0x80, 0x05, 0x80, +0x80, 0x2b, 0xfe, 0x06, +0x82, 0x00, 0x08, 0x12, +0x18, 0x80, 0x60, 0x88, +0x0f, 0x64, 0x20, 0x6c, +0x24, 0x04, 0x48, 0x60, +0x4a, 0x66, 0x00, 0x02, +0x65, 0xe8, 0x40, 0x00, +0x02, 0x18, 0x00, 0x68, +0x20, 0x00, 0x76, 0x20, +0x68, 0x20, 0x00, 0x81, +0x21, 0xa4, 0x04, 0x26, +0x60, 0x00, 0x26, 0x5e, +0x8a, 0x00, 0x20, 0x68, +0x20, 0x00, 0x7c, 0x20, +0x6c, 0x40, 0x01, 0x04, +0x08, 0x84, 0x00, 0xa3, +0x01, 0x30, 0x40, 0x00, +0x03, 0xc0, 0xe0, 0x68, +0x20, 0x00, 0x81, 0x21, +0x68, 0x20, 0x00, 0x82, +0x22, 0x66, 0x00, 0x02, +0x65, 0xe0, 0x68, 0x20, +0x00, 0x7c, 0x20, 0x68, +0x20, 0x00, 0x81, 0x21, +0xa4, 0x04, 0x26, 0x60, +0x00, 0x26, 0x5e, 0x8a, +0x00, 0x20, 0x6c, 0x40, +0x00, 0xec, 0x08, 0x6c, +0x40, 0x01, 0x04, 0x0a, +0x30, 0x1a, 0x0b, 0xc0, +0x69, 0x88, 0x02, 0x06, +0xc4, 0x00, 0x0f, 0x80, +0x83, 0x01, 0xa0, 0x40, +0x00, 0x03, 0xc0, 0x40, +0x68, 0x00, 0x04, 0xbe, +0xa2, 0xbc, 0x15, 0xf8, +0x40, 0xe2, 0x5c, 0x0e, +0x22, 0x01, 0x00, 0x84, +0x00, 0xa2, 0x49, 0x36, +0x6c, 0x40, 0x00, 0x46, +0x02, 0x52, 0x48, 0xa0, +0x40, 0x4a, 0xa0, 0x4e, +0x06, 0xc4, 0x00, 0x20, +0x80, 0x06, 0x80, 0x00, +0x26, 0x1a, 0xc6, 0xc4, +0x00, 0x07, 0x85, 0x06, +0xc4, 0x00, 0x0c, 0x65, +0x08, 0x40, 0x6c, 0x6c, +0x40, 0x00, 0x46, 0x48, +0x00, 0x00, 0x08, 0x80, +0xb6, 0xba, 0x14, 0x8a, +0x80, 0x20, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x05, 0x1a, 0x08, +0x5c, 0x0e, 0x33, 0x01, +0x05, 0x24, 0x1a, 0x46, +0xe0, 0x00, 0x12, 0xc2, +0xf2, 0x59, 0x60, 0x6c, +0x40, 0x05, 0x1a, 0x48, +0xbc, 0x05, 0x83, 0x81, +0x2d, 0x52, 0x4b, 0xc3, +0xc0, 0x6f, 0x6e, 0x00, +0x01, 0x2c, 0x60, 0x52, +0x0b, 0xc3, 0x80, 0x00, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x52, 0x4d, 0x22, +0x01, 0x00, 0x84, 0x00, +0x92, 0x49, 0xae, 0x84, +0x04, 0xa6, 0xc4, 0x00, +0x51, 0xa4, 0x86, 0x80, +0x00, 0x26, 0x1a, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x05, 0x1c, +0x00, 0x5c, 0x0e, 0x32, +0xbf, 0xe0, 0x52, 0x0c, +0x30, 0x80, 0x60, 0x6c, +0x40, 0x05, 0x1c, 0x4a, +0xa0, 0x10, 0x06, 0xc0, +0x00, 0x62, 0x20, 0x05, +0x90, 0x00, 0x08, 0x17, +0x6b, 0xc7, 0x09, 0x88, +0x0e, 0x03, 0x81, 0x04, +0x25, 0x93, 0x06, 0xe0, +0x00, 0x12, 0xc2, 0xdb, +0xc1, 0x48, 0x5c, 0x08, +0xa3, 0x01, 0x18, 0x25, +0x83, 0x0b, 0xc0, 0x40, +0x24, 0x92, 0x86, 0xe0, +0x00, 0x12, 0xc6, 0x0b, +0xc5, 0x27, 0x25, 0x92, +0x8b, 0xc5, 0x09, 0x98, +0xe8, 0xa6, 0xc4, 0x00, +0x15, 0xc0, 0x96, 0xc4, +0x00, 0x18, 0xc0, 0xb6, +0x60, 0x00, 0x22, 0x88, +0x85, 0xc0, 0x04, 0x18, +0x28, 0x8b, 0xc4, 0x67, +0x25, 0x92, 0x8b, 0xc2, +0xe0, 0x38, 0x10, 0x82, +0x58, 0x30, 0xbc, 0x04, +0x06, 0xc0, 0x00, 0x0c, +0xe7, 0xa6, 0xc0, 0x00, +0x0e, 0x27, 0xa2, 0x59, +0x30, 0xbc, 0x09, 0x16, +0xc4, 0x00, 0x23, 0x60, +0xa2, 0x31, 0x36, 0x6c, +0x40, 0x01, 0xea, 0x4a, +0x51, 0x8b, 0xb3, 0x80, +0x00, 0x6c, 0x00, 0x01, +0x30, 0x4a, 0x68, 0x20, +0x00, 0x19, 0x20, 0x6c, +0x40, 0x00, 0x32, 0x08, +0x51, 0x7f, 0x38, 0x40, +0x8a, 0x22, 0xff, 0x52, +0xa8, 0x7f, 0x2a, 0x86, +0xd1, 0x57, 0x15, 0x22, +0x84, 0xd2, 0x28, 0x57, +0x6c, 0x40, 0x01, 0x5c, +0x49, 0x6c, 0x40, 0x01, +0x8c, 0x4b, 0x66, 0x00, +0x02, 0x28, 0x88, 0x5c, +0x00, 0x43, 0x80, 0x00, +0x6e, 0x00, 0x01, 0x2c, +0x2e, 0x38, 0x11, 0x02, +0x40, 0x30, 0x6c, 0x00, +0x01, 0x32, 0x7a, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x38, 0x11, 0xd6, 0xc4, +0x00, 0x51, 0xc0, 0xa6, +0xc4, 0x00, 0x03, 0x20, +0x82, 0x59, 0x70, 0x68, +0x20, 0x00, 0x19, 0x20, +0xbc, 0x07, 0x85, 0xc0, +0x04, 0x04, 0x08, 0xa6, +0xc4, 0x00, 0x15, 0xc4, +0x86, 0xc4, 0x00, 0x18, +0xc4, 0xab, 0xc0, 0x67, +0x6c, 0x40, 0x01, 0x8c, +0x0b, 0x66, 0x00, 0x02, +0x28, 0x88, 0x6c, 0x40, +0x01, 0x5c, 0x09, 0x5c, +0x0e, 0x30, 0x80, 0x20, +0x6c, 0x40, 0x05, 0x1c, +0x00, 0x5c, 0x87, 0x00, +0x44, 0x08, 0x52, 0x4d, +0x20, 0x80, 0xa0, 0x24, +0x98, 0x66, 0xc4, 0x00, +0x51, 0xc4, 0xa6, 0x80, +0x00, 0x26, 0x1a, 0x14, +0x20, 0x77, 0x80, 0x24, +0x88, 0x40, 0x61, 0x5c, +0x0e, 0x02, 0xc0, 0xe0, +0x52, 0x41, 0xb0, 0x80, +0x20, 0x88, 0x0a, 0x18, +0x44, 0x08, 0x24, 0x82, +0x48, 0x0a, 0x48, 0x68, +0x00, 0x02, 0x61, 0xa0, +0x6c, 0x40, 0x05, 0x1c, +0x4a, 0x84, 0x86, 0x00, +0x00, 0x00, 0x88, 0x13, +0x6b, 0xa1, 0x48, 0xa8, +0x02, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x05, 0x1e, +0x08, 0x5c, 0x0e, 0x33, +0x01, 0x05, 0x24, 0x1a, +0x46, 0xe0, 0x00, 0x12, +0xc2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x05, 0x1e, +0x48, 0xbc, 0x15, 0x83, +0x81, 0x25, 0x68, 0x20, +0x01, 0x69, 0x21, 0x52, +0x0b, 0xc2, 0xc0, 0x60, +0x80, 0x80, 0x98, 0x08, +0x0b, 0x6c, 0x40, 0x02, +0xb0, 0x4b, 0x6c, 0x40, +0x01, 0x5e, 0x49, 0x6c, +0x40, 0x01, 0x8e, 0x49, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x68, 0x20, 0x01, +0x58, 0x22, 0x84, 0x80, +0xb4, 0x20, 0xaf, 0x98, +0xe8, 0x98, 0x52, 0xcb, +0x68, 0x20, 0x01, 0x67, +0x21, 0x68, 0x20, 0x01, +0x58, 0x22, 0x52, 0x4b, +0xc2, 0x08, 0x83, 0x84, +0x80, 0xb8, 0x58, 0x09, +0x6c, 0x40, 0x01, 0x5e, +0x4b, 0x6c, 0x40, 0x01, +0x8e, 0x4b, 0x6c, 0x40, +0x02, 0xb0, 0x49, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0xb0, 0x00, 0xd8, 0x59, +0x0b, 0x40, 0x00, 0x00, +0x52, 0xcb, 0x68, 0x20, +0x00, 0xd7, 0x21, 0x52, +0x4d, 0x22, 0x01, 0x00, +0x51, 0x85, 0x68, 0x48, +0x49, 0x98, 0x26, 0x8a, +0x08, 0x21, 0x84, 0x00, +0x95, 0x24, 0xd6, 0x9c, +0x80, 0x18, 0x48, 0x0a, +0x84, 0x04, 0x96, 0xc4, +0x00, 0x51, 0xe4, 0x86, +0xc4, 0x00, 0x19, 0x84, +0xa6, 0xc4, 0x00, 0x19, +0xa4, 0xa6, 0xc4, 0x00, +0x2f, 0x84, 0xa6, 0xc4, +0x00, 0x2f, 0x24, 0xa6, +0x80, 0x00, 0x26, 0x1a, +0xc4, 0x60, 0xa4, 0x20, +0x4e, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x05, +0x22, 0x08, 0x5c, 0x0e, +0x33, 0x07, 0xf8, 0x24, +0x1a, 0x46, 0xc4, 0x00, +0x52, 0x24, 0x82, 0x88, +0x24, 0x32, 0x82, 0x0b, +0xc4, 0xc8, 0xab, 0xff, +0x03, 0x28, 0xa0, 0xbc, +0x2e, 0x03, 0x28, 0xe0, +0xbc, 0x14, 0x03, 0x29, +0xa0, 0xbc, 0x55, 0x16, +0x82, 0x00, 0x2b, 0x32, +0x16, 0xc4, 0x00, 0x00, +0x20, 0x8b, 0x38, 0x00, +0x54, 0x41, 0x00, 0x48, +0x08, 0x55, 0x8c, 0x00, +0x48, 0x82, 0x6c, 0x40, +0x01, 0x3e, 0x48, 0x6c, +0x40, 0x01, 0x6e, 0x52, +0x6c, 0x40, 0x03, 0x4a, +0x48, 0x6c, 0x40, 0x00, +0x02, 0x50, 0xbc, 0x43, +0x78, 0x80, 0x76, 0x40, +0x00, 0x00, 0x80, 0xe0, +0x66, 0x00, 0x00, 0xcc, +0xe0, 0x68, 0x20, 0x02, +0xb1, 0x20, 0x6c, 0x40, +0x00, 0x02, 0x08, 0x84, +0x08, 0x26, 0xc4, 0x00, +0x16, 0xe5, 0x2b, 0x38, +0x02, 0x54, 0x45, 0x20, +0x40, 0x00, 0x55, 0x87, +0x20, 0x80, 0xa0, 0x6c, +0x40, 0x01, 0x3e, 0x50, +0x6c, 0x40, 0x00, 0x02, +0x48, 0xbc, 0x2d, 0xf5, +0xc0, 0xe3, 0x08, 0x03, +0x68, 0x80, 0x76, 0x40, +0x00, 0x00, 0x80, 0xe0, +0x66, 0x00, 0x00, 0xc5, +0x20, 0x68, 0x20, 0x02, +0xaf, 0x20, 0x6c, 0x40, +0x00, 0x02, 0x08, 0x5c, +0x08, 0x40, 0x40, 0x02, +0x6c, 0x40, 0x01, 0x3e, +0x52, 0x6c, 0x40, 0x03, +0x4a, 0x52, 0xb3, 0x80, +0x25, 0x44, 0x52, 0x04, +0x08, 0x95, 0x20, 0x12, +0x08, 0x0a, 0x06, 0xc4, +0x00, 0x16, 0xe4, 0x96, +0xc4, 0x00, 0x00, 0x24, +0x8b, 0xc1, 0x2f, 0x5c, +0x0e, 0x30, 0x80, 0x36, +0x68, 0x20, 0x02, 0xad, +0x21, 0x6c, 0x40, 0x00, +0x02, 0x08, 0xb3, 0x80, +0x25, 0x44, 0x52, 0x04, +0x80, 0x08, 0x48, 0x82, +0x6c, 0x40, 0x01, 0x3e, +0x50, 0x6c, 0x40, 0x03, +0x4a, 0x50, 0x6c, 0x40, +0x00, 0x02, 0x48, 0x6c, +0x40, 0x01, 0x6e, 0x52, +0xa0, 0x10, 0x08, 0x40, +0x08, 0x24, 0x9a, 0x46, +0xc4, 0x00, 0x52, 0x20, +0x05, 0x24, 0xc2, 0x04, +0x04, 0x86, 0xc4, 0x00, +0x52, 0x24, 0x86, 0x80, +0x00, 0x26, 0x1a, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x02, 0x80, 0x10, +0x6c, 0x40, 0x05, 0x24, +0x08, 0x5c, 0x0e, 0x33, +0x01, 0x00, 0x52, 0x0d, +0x22, 0xbf, 0xf0, 0x25, +0x82, 0x0b, 0xc0, 0x98, +0x6c, 0x40, 0x05, 0x24, +0x48, 0x88, 0x07, 0x68, +0x80, 0xe0, 0x66, 0x00, +0x02, 0x17, 0x80, 0x5c, +0x0e, 0x30, 0x80, 0xa0, +0x88, 0x03, 0x6a, 0x01, +0x00, 0x84, 0x00, 0x82, +0x49, 0xa4, 0x6c, 0x40, +0x05, 0x24, 0x00, 0x52, +0x4c, 0x20, 0x40, 0x48, +0x6c, 0x40, 0x05, 0x24, +0x48, 0x68, 0x00, 0x02, +0x61, 0xac, 0x46, 0x0a, +0x42, 0x04, 0xe0, 0x84, +0x06, 0xca, 0x80, 0x10, +0x6c, 0x00, 0x06, 0x22, +0x0a, 0x59, 0x01, 0x82, +0x01, 0x00, 0x6c, 0x40, +0x05, 0x26, 0x00, 0x5c, +0x0e, 0x20, 0x40, 0x0a, +0xbc, 0x1d, 0x92, 0x49, +0x36, 0x52, 0x08, 0x13, +0x07, 0xfd, 0x28, 0x94, +0x03, 0x20, 0x00, 0xbc, +0x07, 0x86, 0xc4, 0x00, +0x52, 0x65, 0x25, 0xc0, +0x04, 0x2c, 0x0e, 0x0b, +0xc0, 0x6f, 0x6c, 0x00, +0x03, 0x5a, 0x50, 0x6c, +0x00, 0x03, 0x5a, 0x7a, +0x5c, 0x87, 0x03, 0x80, +0x00, 0x68, 0x00, 0x02, +0x61, 0xa1, 0x6c, 0x40, +0x05, 0x26, 0x00, 0x52, +0x48, 0x20, 0x02, 0x4a, +0x6c, 0x40, 0x05, 0x26, +0x48, 0xba, 0x14, 0x88, +0x40, 0x61, 0x40, 0x00, +0x03, 0x80, 0x00, 0x52, +0x48, 0x22, 0xc0, 0xe0, +0x6c, 0x40, 0x05, 0x26, +0x48, 0x68, 0x00, 0x02, +0x61, 0xa1, 0x46, 0x0a, +0x40, 0x02, 0x4a, 0x84, +0x06, 0x10, 0x00, 0x00, +0x6c, 0x40, 0x05, 0x28, +0x08, 0x5c, 0x0e, 0x33, +0x00, 0x0a, 0x52, 0x0d, +0x23, 0xa1, 0x11, 0x68, +0x00, 0x3f, 0xff, 0xca, +0x68, 0x00, 0x01, 0x6c, +0x21, 0x68, 0x00, 0x01, +0x75, 0x23, 0x54, 0x4d, +0x28, 0x48, 0x0a, 0x55, +0x01, 0x78, 0x58, 0x00, +0x6c, 0x40, 0x05, 0x28, +0x48, 0x68, 0x20, 0x01, +0xf4, 0x25, 0x68, 0x00, +0x01, 0x5c, 0x22, 0x68, +0x00, 0x01, 0x64, 0x24, +0x23, 0x09, 0x19, 0x84, +0x68, 0x9e, 0x80, 0x68, +0x70, 0x01, 0x2a, 0x04, +0x93, 0x00, 0x78, 0xbc, +0x17, 0x32, 0xa7, 0xd7, +0x23, 0x0b, 0xf9, 0x82, +0xe8, 0x9e, 0x80, 0x58, +0x68, 0x0b, 0x57, 0x0f, +0x69, 0xe0, 0x04, 0x86, +0x00, 0xb4, 0x46, 0x90, +0x1d, 0x80, 0x38, 0x58, +0x0b, 0x57, 0x01, 0xc1, +0xd0, 0x02, 0x85, 0x00, +0xb4, 0x46, 0x88, 0x1c, +0x80, 0x18, 0x48, 0x09, +0x57, 0x0d, 0x59, 0x83, +0x4a, 0x54, 0x07, 0x89, +0x83, 0x8a, 0xbc, 0x05, +0xf2, 0x80, 0x30, 0x2a, +0x05, 0x23, 0xa0, 0x82, +0x32, 0x25, 0x0b, 0xfd, +0xe2, 0x5c, 0x0e, 0x32, +0x01, 0x00, 0x52, 0x4d, +0x20, 0x40, 0x09, 0x24, +0x9a, 0xe8, 0x40, 0x4a, +0x6c, 0x00, 0x02, 0xb4, +0x51, 0x6c, 0x00, 0x02, +0xb6, 0x50, 0x6c, 0x40, +0x05, 0x28, 0x48, 0x68, +0x00, 0x02, 0x61, 0xac, +0x46, 0x0a, 0x42, 0x04, +0xe0, 0x84, 0x06, 0xcb, +0xa1, 0x01, 0x6c, 0x40, +0x05, 0x2a, 0x08, 0x68, +0x00, 0x47, 0xff, 0xca, +0x68, 0x38, 0x1c, 0x03, +0x21, 0x54, 0x4d, 0x22, +0xff, 0xe0, 0x5c, 0x00, +0x40, 0x48, 0x48, 0x5c, +0x00, 0x21, 0xc8, 0x01, +0x5c, 0x09, 0xf0, 0x48, +0x7a, 0x84, 0x95, 0x00, +0x00, 0x00, 0x6c, 0x70, +0x38, 0x0c, 0x00, 0x25, +0x98, 0x0b, 0xc0, 0x50, +0x6c, 0x70, 0x38, 0x06, +0x08, 0xbc, 0x05, 0xf6, +0xc4, 0x00, 0x52, 0xa4, +0x83, 0x22, 0xa0, 0xbf, +0xf5, 0xa2, 0xa0, 0x64, +0x5c, 0x0e, 0x22, 0x01, +0x00, 0x84, 0x00, 0xa2, +0x49, 0x34, 0x84, 0x04, +0x86, 0x80, 0x00, 0x26, +0x1a, 0xc4, 0x60, 0xa4, +0x20, 0x4e, 0x08, 0x40, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x05, 0x2c, 0x08, 0x5c, +0x0e, 0x33, 0x01, 0x05, +0x24, 0x1a, 0x46, 0xe0, +0x00, 0x12, 0xc2, 0xf2, +0x59, 0x60, 0x6c, 0x40, +0x05, 0x2c, 0x48, 0xbc, +0x05, 0x83, 0x81, 0x3d, +0x52, 0x4b, 0xc3, 0xc0, +0x6f, 0x6e, 0x00, 0x01, +0x2c, 0x60, 0x52, 0x0b, +0xc3, 0x80, 0x00, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x52, 0x4d, 0x22, 0x01, +0x00, 0x84, 0x00, 0x92, +0x49, 0xae, 0x84, 0x04, +0xa6, 0xc4, 0x00, 0x52, +0xc4, 0x86, 0x80, 0x00, +0x26, 0x1a, 0xc4, 0x60, +0xa4, 0x20, 0x4e, 0x08, +0x40, 0x6c, 0x40, 0x00, +0x03, 0x80, 0x00, 0x5c, +0x07, 0x62, 0x00, 0x80, +0x84, 0x02, 0x10, 0x00, +0x00, 0x94, 0x8a, 0xe3, +0x01, 0x30, 0xbc, 0x07, +0x9a, 0x04, 0x60, 0x6c, +0x40, 0x05, 0x2e, 0x08, +0x38, 0x1b, 0xe2, 0x41, +0xa4, 0x6c, 0x40, 0x05, +0x2e, 0x48, 0x68, 0x00, +0x05, 0x72, 0xa1, 0xba, +0x14, 0x88, 0x40, 0x61, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x05, +0xbf, 0xa1, 0x6c, 0x00, +0x01, 0x2e, 0x08, 0x98, +0x84, 0x95, 0x80, 0xb0, +0x2b, 0xff, 0x04, 0x24, +0x0c, 0x88, 0x07, 0x68, +0x80, 0xe0, 0xb0, 0x7f, +0xd6, 0xc4, 0x00, 0x52, +0xe0, 0x02, 0x3e, 0x06, +0x28, 0x97, 0x53, 0x28, +0x28, 0xbc, 0x2f, 0x8b, +0x00, 0x14, 0x66, 0x00, +0x00, 0x5f, 0x68, 0x40, +0x00, 0x03, 0x01, 0xbd, +0x6c, 0x40, 0x05, 0x2e, +0x08, 0x51, 0xd1, 0x2b, +0x01, 0xba, 0x52, 0xc5, +0x03, 0x07, 0xf8, 0x23, +0xc2, 0x65, 0x44, 0x16, +0xbc, 0x11, 0x82, 0x88, +0x36, 0x68, 0x00, 0x03, +0x03, 0x20, 0x5c, 0x80, +0x43, 0x07, 0xf8, 0x54, +0x41, 0x21, 0x40, 0x46, +0xa0, 0x00, 0x19, 0x40, +0x45, 0x94, 0x8e, 0x4a, +0x04, 0x10, 0xb0, 0x08, +0x56, 0x60, 0x00, 0x05, +0xfe, 0x8b, 0x00, 0x1c, +0x40, 0x00, 0x03, 0xc5, +0x67, 0x68, 0x00, 0x03, +0x03, 0x21, 0x5c, 0x09, +0xe2, 0xc0, 0x80, 0x52, +0x09, 0x82, 0x08, 0x00, +0x94, 0x84, 0x06, 0xc0, +0x00, 0x62, 0x07, 0xa9, +0x40, 0xe5, 0xb0, 0x01, +0x4b, 0x00, 0x86, 0x66, +0x00, 0x00, 0x61, 0xc8, +0xb0, 0x00, 0xdb, 0xc4, +0x67, 0x6c, 0x40, 0x00, +0x02, 0x09, 0xb0, 0x7f, +0xe2, 0x89, 0xad, 0x32, +0x02, 0x8b, 0xc1, 0xc0, +0x32, 0x0a, 0x8b, 0xc1, +0x60, 0x32, 0x1a, 0x8b, +0xc1, 0x00, 0x23, 0xc0, +0x52, 0x89, 0xae, 0x32, +0x83, 0x0b, 0xc0, 0x60, +0x32, 0x8a, 0x8b, 0xc1, +0x69, 0xb0, 0x1b, 0xd6, +0x60, 0x00, 0x05, 0xf6, +0x0b, 0xc1, 0x27, 0xb0, +0x1b, 0xd6, 0x60, 0x00, +0x05, 0xf6, 0x8b, 0x00, +0x54, 0x40, 0x00, 0x03, +0xc0, 0xc7, 0x66, 0x00, +0x00, 0x5f, 0x68, 0xb0, +0x1b, 0xdb, 0xc0, 0x87, +0x66, 0x00, 0x00, 0x5f, +0x68, 0xb0, 0x1b, 0xdb, +0xc0, 0x47, 0xb0, 0x1b, +0xd6, 0x60, 0x00, 0x05, +0xf6, 0x8b, 0x00, 0x54, +0x6c, 0x40, 0x05, 0x2e, +0x08, 0x51, 0xd1, 0x2b, +0x01, 0xbe, 0x52, 0xcd, +0x03, 0x07, 0xfe, 0x68, +0x00, 0x03, 0x03, 0x20, +0x5c, 0x84, 0x03, 0xc0, +0xc8, 0x54, 0x4d, 0x6b, +0x01, 0x3e, 0xb0, 0x7f, +0xe6, 0xe0, 0x00, 0x60, +0x66, 0x55, 0x44, 0xd3, +0x18, 0xe8, 0x99, 0x40, +0xe6, 0x66, 0x00, 0x00, +0x5f, 0xe8, 0xb0, 0x01, +0x4b, 0xc0, 0xa7, 0x52, +0x0d, 0x42, 0x00, 0x01, +0x6c, 0x00, 0x06, 0x20, +0x7a, 0x94, 0x84, 0x0b, +0x00, 0x0d, 0x66, 0x00, +0x00, 0x61, 0xc8, 0x55, +0x01, 0x61, 0x8e, 0x8a, +0x88, 0x0a, 0x06, 0x80, +0x00, 0x59, 0x6a, 0x18, +0x40, 0xe1, 0x00, 0x00, +0x08, 0x80, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x05, +0x2e, 0x08, 0x38, 0x1b, +0xe2, 0x59, 0xa0, 0x40, +0x00, 0x03, 0xc0, 0x41, +0x6e, 0x00, 0x06, 0x0e, +0x2c, 0x6c, 0x40, 0x05, +0x2e, 0x48, 0x5c, 0x0e, +0x22, 0x01, 0x00, 0x84, +0x00, 0xa2, 0x49, 0x34, +0x84, 0x04, 0x86, 0x80, +0x00, 0x26, 0x1a, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x03, 0x80, 0x00, +0x68, 0x20, 0x00, 0xe0, +0x22, 0x60, 0x00, 0x00, +0x00, 0x2c, 0xab, 0xfe, +0x05, 0xc8, 0x10, 0x08, +0x04, 0x88, 0x10, 0x7a, +0x68, 0x00, 0x00, 0x9e, +0x22, 0x5c, 0x82, 0x01, +0x8e, 0x80, 0x5c, 0x86, +0x10, 0x50, 0x7a, 0x5c, +0x8a, 0x0a, 0x10, 0x82, +0x81, 0x07, 0xa8, 0xd0, +0x58, 0x8d, 0x15, 0x88, +0x10, 0x7a, 0x8d, 0x05, +0x88, 0xd0, 0x78, 0xa1, +0x5e, 0x26, 0xc4, 0x00, +0x1d, 0xa0, 0x88, 0x50, +0x48, 0xa1, 0x14, 0x28, +0x50, 0x48, 0xa1, 0x56, +0x26, 0xc4, 0x00, 0x1d, +0x80, 0xa8, 0x10, 0xca, +0x81, 0x24, 0xa8, 0x10, +0xe0, 0x68, 0x20, 0x00, +0xe2, 0x20, 0x85, 0x06, +0x16, 0x82, 0x00, 0x0e, +0x82, 0x3a, 0x16, 0x61, +0x84, 0x04, 0x88, 0x41, +0xc8, 0x88, 0x0e, 0x18, +0x58, 0x48, 0x85, 0x9c, +0x88, 0x81, 0x76, 0x68, +0x00, 0x00, 0xb4, 0x20, +0x68, 0x00, 0x00, 0xb8, +0x21, 0x66, 0x00, 0x01, +0x28, 0x60, 0x68, 0x00, +0x00, 0xc9, 0x20, 0x66, +0x00, 0x00, 0x54, 0x28, +0x38, 0x00, 0xc8, 0x81, +0x36, 0x88, 0x0a, 0x04, +0x60, 0xa4, 0x08, 0x00, +0x88, 0x40, 0x48, 0x40, +0x00, 0x02, 0x80, 0x20, +0x68, 0x00, 0x05, 0x00, +0x08, 0x6c, 0x68, 0x00, +0x56, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x40, +0x00, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x6c, 0x40, +0x05, 0x30, 0x08, 0x5c, +0x0e, 0x32, 0xbf, 0xf0, +0x52, 0x0d, 0x20, 0x80, +0x60, 0x6c, 0x40, 0x05, +0x30, 0x48, 0x88, 0x0f, +0x66, 0x60, 0x00, 0x10, +0xc8, 0x83, 0x80, 0x0c, +0x5c, 0x0e, 0x20, 0x80, +0x20, 0x6c, 0x40, 0x05, +0x30, 0x0a, 0xa0, 0x10, +0x08, 0x40, 0x00, 0x52, +0x48, 0x00, 0x80, 0xb6, +0x52, 0x49, 0xa0, 0x40, +0x50, 0x6c, 0x40, 0x05, +0x30, 0x48, 0x68, 0x00, +0x02, 0x61, 0xac, 0x46, +0x0a, 0x42, 0x04, 0xe0, +0x84, 0x06, 0xca, 0x80, +0x10, 0x68, 0x38, 0x1c, +0x07, 0x21, 0x5c, 0xbc, +0x03, 0x00, 0x0e, 0x5c, +0x00, 0x80, 0x48, 0x7a, +0x9c, 0x80, 0x18, 0x48, +0x48, 0xa0, 0xc2, 0x18, +0x48, 0x7a, 0xa0, 0x84, +0x18, 0x48, 0x4a, 0xa0, +0xc8, 0x18, 0x48, 0x08, +0x46, 0x0a, 0x40, 0x40, +0x48, 0x84, 0xbd, 0x00, +0x00, 0x00, 0x68, 0x20, +0x00, 0xd7, 0x20, 0x6c, +0x40, 0x05, 0x1e, 0x7a, +0x84, 0x07, 0xa0, 0x00, +0x00, 0x84, 0x08, 0x86, +0xc4, 0x00, 0x19, 0xa4, +0x86, 0xc4, 0x00, 0x2f, +0x84, 0x86, 0xc4, 0x00, +0x2f, 0x24, 0x8b, 0xa1, +0x48, 0x6c, 0x40, 0x01, +0x98, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x00, 0x00, 0x90, 0x20, +0x5c, 0x81, 0x03, 0x01, +0x05, 0x5c, 0x00, 0x08, +0x00, 0x02, 0x55, 0x00, +0x62, 0x00, 0xa1, 0x68, +0x00, 0x00, 0xea, 0x24, +0x55, 0x00, 0x59, 0x48, +0x28, 0x52, 0xca, 0x02, +0xbf, 0xc0, 0x82, 0x20, +0x9a, 0x0d, 0x41, 0x88, +0x24, 0x98, 0x82, 0xe1, +0x88, 0x37, 0x6b, 0xc0, +0x89, 0x55, 0x00, 0x70, +0x40, 0x09, 0x68, 0x00, +0x00, 0x88, 0x20, 0x6c, +0x00, 0x01, 0xce, 0x01, +0x84, 0x08, 0x88, 0x40, +0x03, 0x38, 0x10, 0xf2, +0x59, 0xc0, 0xbc, 0x09, +0x95, 0x50, 0x18, 0x18, +0x28, 0xb6, 0x80, 0x00, +0x08, 0xa2, 0x06, 0xc0, +0x00, 0x1d, 0x00, 0x08, +0x40, 0x8b, 0x40, 0x00, +0x00, 0x40, 0x0a, 0x57, +0x04, 0xd0, 0x82, 0x03, +0x57, 0x06, 0x4a, 0x08, +0x00, 0x2e, 0x16, 0x32, +0x81, 0x92, 0x48, 0x40, +0x79, 0x80, 0x89, 0x6c, +0x40, 0x01, 0x3e, 0x08, +0x44, 0x21, 0x01, 0xa0, +0x02, 0x6c, 0x40, 0x01, +0x6e, 0x08, 0x08, 0x80, +0x06, 0xc4, 0x00, 0x1e, +0xa0, 0x16, 0xc4, 0x00, +0x23, 0x60, 0xb3, 0x01, +0xc8, 0x6e, 0x40, 0x01, +0x9d, 0x24, 0x20, 0x11, +0x16, 0xe4, 0x00, 0x19, +0xf2, 0x46, 0xc4, 0x00, +0x34, 0xa0, 0xa5, 0x00, +0x80, 0x00, 0x84, 0x14, +0x43, 0x08, 0x04, 0x84, +0x08, 0x82, 0x61, 0x00, +0x00, 0x06, 0xe4, 0x00, +0x3b, 0x12, 0x25, 0x00, +0x44, 0x3c, 0x67, 0xd8, +0x60, 0x40, 0x68, 0x00, +0x00, 0x98, 0x24, 0x6c, +0x40, 0x02, 0x18, 0x09, +0x86, 0x00, 0x82, 0xe1, +0x65, 0x51, 0x4b, 0x68, +0x60, 0x49, 0x6c, 0x40, +0x01, 0xea, 0x49, 0x30, +0x1e, 0x8b, 0xc5, 0x64, +0x6c, 0x00, 0x03, 0x86, +0x09, 0x32, 0x02, 0x8b, +0xc0, 0x41, 0x6c, 0x00, +0x03, 0xa0, 0x08, 0x32, +0x02, 0x0b, 0xc4, 0xb0, +0x6c, 0x00, 0x03, 0xa0, +0x08, 0x2e, 0x92, 0xd2, +0xa0, 0x6d, 0x6c, 0x40, +0x01, 0xfc, 0x08, 0x6c, +0x00, 0x03, 0x86, 0x49, +0x30, 0x12, 0x8b, 0xc0, +0xec, 0x6c, 0x00, 0x03, +0xa0, 0x49, 0x23, 0x13, +0xd6, 0x80, 0x00, 0x09, +0x82, 0x46, 0xc4, 0x00, +0x1e, 0xa4, 0x96, 0x82, +0x00, 0x29, 0xa2, 0x75, +0x18, 0xb6, 0x86, 0x0f, +0xab, 0xc3, 0xef, 0x6c, +0x00, 0x01, 0x30, 0x49, +0x68, 0x00, 0x00, 0x62, +0x22, 0x68, 0x00, 0x00, +0x6c, 0x26, 0x5c, 0x82, +0x08, 0x10, 0x7a, 0xa1, +0x00, 0x48, 0x10, 0x7a, +0x86, 0x0f, 0xa8, 0x30, +0x7a, 0xa3, 0x00, 0x56, +0x80, 0x00, 0x0d, 0x22, +0x48, 0x30, 0x7a, 0x86, +0x8f, 0xa8, 0x20, 0x7a, +0xa2, 0x00, 0x78, 0x70, +0xfa, 0x82, 0x07, 0xa6, +0x80, 0x00, 0x1c, 0x12, +0x56, 0x82, 0x00, 0x29, +0xa2, 0x68, 0x78, 0xfa, +0xa3, 0x00, 0x78, 0x28, +0x80, 0x85, 0x0f, 0xa8, +0x30, 0x50, 0x68, 0x00, +0x01, 0xdb, 0x23, 0x6c, +0x00, 0x00, 0xec, 0x50, +0x68, 0x00, 0x01, 0xce, +0x22, 0x81, 0x88, 0x98, +0x10, 0x80, 0x6c, 0x00, +0x01, 0x30, 0x7a, 0x6c, +0x40, 0x01, 0xea, 0x4b, +0x6c, 0x00, 0x00, 0xfe, +0x50, 0x6c, 0x00, 0x01, +0xbc, 0x49, 0x85, 0x87, +0xa8, 0x68, 0x7a, 0x87, +0x0c, 0x98, 0x70, 0x50, +0x42, 0x05, 0x78, 0x60, +0xfa, 0x85, 0x07, 0xab, +0xc0, 0x8f, 0x68, 0x20, +0x02, 0x9a, 0x27, 0x40, +0x00, 0x03, 0xc0, 0x4f, +0x68, 0x20, 0x02, 0x9a, +0x27, 0x68, 0x20, 0x02, +0x9a, 0x27, 0x68, 0x20, +0x00, 0x9c, 0x24, 0xa3, +0x82, 0x58, 0x83, 0xe5, +0x66, 0x00, 0x01, 0xf1, +0xc0, 0x68, 0x00, 0x00, +0x7b, 0x20, 0x88, 0x2a, +0x18, 0x40, 0x48, 0x68, +0x20, 0x00, 0xb4, 0x24, +0x40, 0x00, 0x00, 0x82, +0x20, 0x66, 0x00, 0x01, +0xf1, 0xc0, 0x68, 0x00, +0x00, 0x84, 0x20, 0x68, +0x00, 0x00, 0x7b, 0x21, +0x5c, 0x82, 0x00, 0x40, +0x48, 0x68, 0x00, 0x00, +0x62, 0x20, 0x80, 0x80, +0x98, 0x82, 0x61, 0x68, +0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x01, 0xb8, +0x80, 0x68, 0x20, 0x02, +0x9a, 0x2c, 0x5c, 0x87, +0x00, 0x82, 0x20, 0x88, +0x1e, 0xc8, 0x02, 0x48, +0x68, 0x20, 0x00, 0xdf, +0x2c, 0x68, 0x20, 0x00, +0xdc, 0x2d, 0x68, 0x20, +0x00, 0xde, 0x22, 0x88, +0x26, 0x06, 0x82, 0x00, +0x09, 0xc2, 0x46, 0x80, +0x00, 0x09, 0xa2, 0x16, +0x82, 0x00, 0x0d, 0x32, +0x58, 0x80, 0x6c, 0x88, +0x0e, 0xd8, 0x81, 0x62, +0x66, 0x00, 0x01, 0xb9, +0xe8, 0x40, 0x00, 0x01, +0x82, 0x09, 0x5c, 0x82, +0x00, 0x82, 0x20, 0x68, +0x00, 0x00, 0x84, 0x21, +0x84, 0x34, 0x86, 0x80, +0x00, 0x06, 0xc2, 0x08, +0x08, 0x09, 0x40, 0x00, +0x00, 0x82, 0x61, 0x68, +0x20, 0x00, 0xb4, 0x24, +0x66, 0x00, 0x01, 0xb8, +0x80, 0x5c, 0x87, 0x00, +0x82, 0x20, 0x88, 0x3a, +0x18, 0x02, 0x48, 0x88, +0x1e, 0x16, 0x82, 0x00, +0x0d, 0xfa, 0xc6, 0x82, +0x00, 0x0d, 0xd2, 0xd6, +0x82, 0x00, 0x0d, 0xea, +0x28, 0x82, 0x60, 0x68, +0x20, 0x00, 0xb4, 0x24, +0x68, 0x00, 0x00, 0x9c, +0x21, 0x68, 0x20, 0x00, +0xd5, 0x25, 0x88, 0x06, +0xc8, 0x80, 0xed, 0x88, +0x16, 0x26, 0x60, 0x00, +0x1b, 0x9e, 0x89, 0x82, +0x09, 0x68, 0x20, 0x00, +0x9c, 0x21, 0x6c, 0x40, +0x03, 0xc2, 0x09, 0x84, +0xb8, 0x05, 0x80, 0xa0, +0x08, 0x22, 0x16, 0xc4, +0x00, 0x3b, 0xa0, 0x0b, +0xc0, 0x69, 0x5c, 0x09, +0x30, 0x4b, 0x48, 0x52, +0x4c, 0x23, 0xc0, 0x6f, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x52, 0x0c, 0x23, +0x80, 0x00, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x68, +0x20, 0x00, 0xb4, 0x21, +0x6c, 0x40, 0x03, 0xba, +0x08, 0x84, 0xb8, 0x03, +0x01, 0x40, 0xbc, 0x05, +0x93, 0x81, 0x2e, 0x52, +0x4d, 0x2b, 0xc0, 0x5f, +0x6c, 0x40, 0x03, 0xba, +0x49, 0x24, 0x1a, 0x56, +0xc4, 0x00, 0x3b, 0xa4, +0x93, 0x81, 0x35, 0x6c, +0x40, 0x01, 0xb8, 0x08, +0x6c, 0x40, 0x01, 0xda, +0x0a, 0x30, 0x1a, 0x0b, +0xc0, 0x69, 0x6c, 0x40, +0x03, 0xba, 0x08, 0x52, +0x4b, 0x2b, 0xc0, 0x5f, +0x6c, 0x40, 0x03, 0xba, +0x49, 0x24, 0x16, 0x56, +0xc4, 0x00, 0x3b, 0xa4, +0x93, 0x81, 0x3d, 0x6c, +0x40, 0x01, 0xba, 0x08, +0x30, 0x1a, 0x0b, 0xc0, +0x69, 0x6c, 0x40, 0x03, +0xba, 0x08, 0x52, 0x4b, +0x2b, 0xc0, 0x6f, 0x6c, +0x40, 0x03, 0xba, 0x49, +0x52, 0x0b, 0x2b, 0x80, +0x00, 0x6c, 0x40, 0x03, +0xba, 0x49, 0x68, 0x00, +0x06, 0xa2, 0x21, 0x88, +0x33, 0x6b, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0x2e, +0x61, 0x40, 0x00, 0x02, +0x80, 0x40, 0x68, 0x00, +0x00, 0x7c, 0x20, 0x5c, +0x85, 0x02, 0xbf, 0x90, +0x80, 0x20, 0x98, 0x81, +0x60, 0x68, 0x20, 0x01, +0xc2, 0x2c, 0x88, 0x1f, +0x66, 0x82, 0x00, 0x09, +0xc2, 0x46, 0x82, 0x00, +0x0c, 0xe2, 0x56, 0x80, +0x00, 0x0e, 0xb2, 0x08, +0x80, 0x6c, 0x66, 0x00, +0x01, 0xd0, 0x00, 0x68, +0x00, 0x00, 0x85, 0x20, +0x39, 0x0a, 0x08, 0x02, +0x09, 0x88, 0x26, 0x06, +0x82, 0x00, 0x1c, 0x42, +0xc6, 0xc0, 0x00, 0x1d, +0x64, 0x86, 0x82, 0x00, +0x0b, 0x42, 0x46, 0x82, +0x00, 0x0c, 0xf2, 0x56, +0x80, 0x00, 0x0e, 0xd2, +0x08, 0x80, 0x6c, 0x66, +0x00, 0x01, 0xd0, 0x00, +0x68, 0x20, 0x00, 0xdc, +0x2c, 0x6c, 0x00, 0x01, +0xda, 0x48, 0x68, 0x00, +0x00, 0x62, 0x20, 0x68, +0x20, 0x00, 0x9c, 0x24, +0x68, 0x20, 0x00, 0xce, +0x25, 0x88, 0x06, 0xc6, +0x60, 0x00, 0x1b, 0x8c, +0x86, 0xc0, 0x00, 0x1d, +0x60, 0x98, 0x81, 0x20, +0x68, 0x20, 0x00, 0xdd, +0x2c, 0x84, 0x04, 0x86, +0x80, 0x00, 0x06, 0xc2, +0x06, 0x82, 0x00, 0x0b, +0x42, 0x46, 0x82, 0x00, +0x0c, 0xf2, 0x58, 0x80, +0x6c, 0x66, 0x00, 0x01, +0xb8, 0xc8, 0x6c, 0x00, +0x01, 0xda, 0x09, 0x5c, +0x81, 0x00, 0x81, 0x20, +0x88, 0x22, 0x48, 0x02, +0x09, 0x86, 0x04, 0x88, +0x81, 0x60, 0x68, 0x00, +0x00, 0x62, 0x21, 0x68, +0x20, 0x00, 0x9c, 0x24, +0x66, 0x00, 0x01, 0xd1, +0x60, 0x5c, 0x81, 0x00, +0x81, 0x24, 0x88, 0x22, +0x0a, 0x20, 0x44, 0x80, +0x20, 0x98, 0x60, 0x48, +0x88, 0x2e, 0x48, 0x82, +0x60, 0x68, 0x00, 0x00, +0x6c, 0x21, 0x68, 0x20, +0x00, 0xb4, 0x24, 0x66, +0x00, 0x01, 0xd1, 0x60, +0x88, 0x22, 0x06, 0x82, +0x00, 0x15, 0xa2, 0x5a, +0x00, 0x40, 0x84, 0x04, +0x86, 0x82, 0x00, 0x09, +0xc2, 0x46, 0xc4, 0x00, +0x3b, 0xa0, 0x88, 0x66, +0x02, 0x86, 0x80, 0x33, +0x00, 0xd0, 0xbc, 0x06, +0xa5, 0xc0, 0x82, 0x88, +0x36, 0x05, 0x24, 0xb2, +0x3c, 0x05, 0xf6, 0xc4, +0x00, 0x3b, 0xa4, 0x82, +0x41, 0x64, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x68, +0x20, 0x00, 0xb4, 0x20, +0x6c, 0x40, 0x03, 0xba, +0x08, 0x84, 0x60, 0x23, +0x00, 0xd0, 0xbc, 0x05, +0xa3, 0x81, 0x0d, 0x52, +0x4b, 0x23, 0xc0, 0x6f, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x52, 0x0b, 0x23, +0x80, 0x00, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x68, +0x00, 0x00, 0x62, 0x20, +0x88, 0x12, 0x16, 0x82, +0x00, 0x0d, 0xe2, 0x56, +0x60, 0x00, 0x1d, 0x54, +0x88, 0x49, 0x09, 0x88, +0x22, 0x06, 0x80, 0x00, +0x09, 0x22, 0x48, 0x41, +0x09, 0x40, 0x00, 0x00, +0x60, 0x48, 0x68, 0x00, +0x00, 0x6c, 0x20, 0x68, +0x20, 0x00, 0xb4, 0x24, +0x68, 0x20, 0x00, 0xde, +0xa5, 0x66, 0x00, 0x01, +0xd5, 0x40, 0x5c, 0x81, +0x00, 0x81, 0x48, 0x68, +0x00, 0x00, 0x92, 0x23, +0x68, 0x20, 0x00, 0xd7, +0x24, 0xa1, 0x80, 0x2c, +0x60, 0x80, 0x5d, 0x0c, +0x28, 0x82, 0x64, 0x51, +0x85, 0x68, 0x83, 0xd0, +0x59, 0x05, 0x81, 0x82, +0x68, 0x9e, 0x00, 0x46, +0x82, 0x00, 0x0c, 0xd2, +0x18, 0x60, 0x09, 0x68, +0x20, 0x00, 0xcc, 0x20, +0x88, 0x46, 0x38, 0x48, +0x49, 0x42, 0x06, 0x50, +0x58, 0x48, 0x84, 0x04, +0x93, 0x61, 0x44, 0x88, +0x38, 0x25, 0x78, 0xa9, +0x88, 0x10, 0x22, 0xe9, +0x1b, 0x2f, 0x15, 0x56, +0xc0, 0x00, 0x12, 0x45, +0x35, 0x74, 0x96, 0x3c, +0x03, 0xf8, 0x58, 0x48, +0x66, 0x00, 0x01, 0xe5, +0x80, 0x68, 0x00, 0x00, +0x92, 0x20, 0x5c, 0x09, +0x60, 0x84, 0x21, 0xa0, +0x08, 0x09, 0x40, 0x2d, +0x52, 0xc9, 0x40, 0x84, +0xe0, 0x68, 0x20, 0x01, +0x5a, 0x24, 0x6c, 0x40, +0x02, 0xb4, 0x02, 0x6c, +0x40, 0x02, 0xd4, 0x03, +0x88, 0x55, 0x38, 0x85, +0xd2, 0x00, 0x00, 0x04, +0x20, 0x74, 0x06, 0x18, +0x88, 0x86, 0x48, 0x68, +0x20, 0x00, 0xc0, 0x20, +0x88, 0x58, 0x86, 0x82, +0x00, 0x0a, 0x82, 0x48, +0x85, 0x09, 0x6c, 0x40, +0x01, 0x80, 0x48, 0x6c, +0x40, 0x01, 0x50, 0x48, +0x84, 0x0c, 0x94, 0x22, +0xab, 0x86, 0x0c, 0x90, +0x00, 0x00, 0x6c, 0x00, +0x01, 0x24, 0x0a, 0x66, +0x00, 0x01, 0xeb, 0x28, +0x5c, 0x00, 0x28, 0x48, +0x0b, 0x6e, 0x00, 0x01, +0xa2, 0x25, 0x32, 0x02, +0x8b, 0xc3, 0x01, 0x6e, +0x40, 0x01, 0xbe, 0x2d, +0x32, 0x02, 0x8b, 0xc2, +0xc1, 0x6e, 0x40, 0x01, +0xbf, 0x2d, 0x32, 0x02, +0x8b, 0xc2, 0x81, 0x6c, +0x40, 0x01, 0xae, 0x09, +0x5d, 0x0a, 0x28, 0x82, +0x20, 0x51, 0x85, 0x51, +0x8e, 0x83, 0x98, 0x4a, +0x89, 0xc0, 0x00, 0x6c, +0x40, 0x02, 0xb0, 0x0a, +0x84, 0x00, 0xb0, 0x8e, +0x20, 0x98, 0x08, 0x22, +0xe0, 0xa6, 0x32, 0x03, +0x0b, 0xc0, 0x5d, 0x55, +0x00, 0xd0, 0x85, 0x89, +0x55, 0x01, 0xb8, 0x86, +0x0a, 0x08, 0xe3, 0x02, +0xe0, 0xeb, 0x6c, 0x40, +0x01, 0x50, 0x09, 0x98, +0x0c, 0x33, 0x00, 0xe8, +0xbc, 0x0b, 0x56, 0xc4, +0x00, 0x2b, 0x20, 0x92, +0xe1, 0x2d, 0x32, 0x02, +0x8b, 0xc0, 0x63, 0x6c, +0x40, 0x01, 0x80, 0x53, +0x6c, 0x40, 0x01, 0x50, +0x53, 0xbc, 0x05, 0xf8, +0x84, 0x21, 0xbc, 0x03, +0xf8, 0x84, 0x21, 0x5c, +0x00, 0x10, 0x84, 0x21, +0x38, 0x12, 0x59, 0x4e, +0x2b, 0x25, 0x95, 0x8b, +0xc1, 0x40, 0x6c, 0x40, +0x02, 0xd0, 0x09, 0x57, +0x0b, 0x28, 0x85, 0x08, +0x6c, 0x40, 0x01, 0x52, +0x48, 0x32, 0x02, 0x8b, +0xc0, 0x6d, 0x6c, 0x40, +0x01, 0x82, 0x48, 0x00, +0x00, 0x06, 0xc4, 0x00, +0x2e, 0x20, 0xa0, 0x86, +0x20, 0x2e, 0x0a, 0x26, +0xc4, 0x00, 0x18, 0x24, +0x26, 0xc4, 0x00, 0x15, +0x24, 0x20, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x24, +0x08, 0x5b, 0x48, 0x28, +0x83, 0x82, 0x36, 0x88, +0x36, 0xc4, 0x00, 0x3b, +0xa0, 0xa3, 0x09, 0x58, +0xbc, 0x05, 0xc3, 0x81, +0x12, 0x52, 0x45, 0xab, +0xc0, 0x5f, 0x6c, 0x40, +0x03, 0xba, 0x49, 0x24, +0x0b, 0x56, 0xc4, 0x00, +0x3b, 0xa4, 0x93, 0x81, +0x1d, 0x84, 0x80, 0x25, +0xb4, 0x41, 0x88, 0x10, +0xa3, 0x69, 0x86, 0x30, +0x8f, 0x0b, 0xc0, 0x6c, +0x6c, 0x40, 0x03, 0xba, +0x03, 0x52, 0x4a, 0xeb, +0xc0, 0x6f, 0x6c, 0x40, +0x03, 0xba, 0x49, 0x52, +0x0a, 0xeb, 0x80, 0x00, +0x6c, 0x40, 0x03, 0xba, +0x49, 0x68, 0x00, 0x00, +0x62, 0x20, 0x68, 0x00, +0x00, 0x6c, 0x24, 0x84, +0x2c, 0x88, 0x62, 0xd2, +0x68, 0x20, 0x01, 0xba, +0x24, 0x68, 0x00, 0x00, +0x92, 0x20, 0x66, 0x00, +0x01, 0xf1, 0xc0, 0x88, +0x42, 0x08, 0x81, 0x48, +0x68, 0x20, 0x01, 0xbc, +0x24, 0x68, 0x00, 0x00, +0x92, 0x21, 0x66, 0x00, +0x01, 0xf1, 0xc0, 0x88, +0x10, 0x98, 0x81, 0x48, +0x68, 0x20, 0x00, 0x9c, +0x24, 0x68, 0x20, 0x00, +0xce, 0x25, 0x66, 0x00, +0x01, 0xd6, 0x20, 0x88, +0x2a, 0x06, 0x82, 0x00, +0x0b, 0x42, 0x48, 0x43, +0x48, 0x68, 0x20, 0x00, +0xcf, 0x25, 0x66, 0x00, +0x01, 0xd6, 0x28, 0x40, +0x00, 0x00, 0x81, 0x09, +0x5c, 0x08, 0xa8, 0x84, +0xa0, 0x88, 0x32, 0x49, +0x40, 0x2a, 0x25, 0x95, +0x0b, 0xc0, 0x58, 0x86, +0x34, 0x86, 0xc0, 0x00, +0x0f, 0xc7, 0xa6, 0xc0, +0x00, 0x10, 0xe7, 0xa3, +0x81, 0x34, 0x25, 0x91, +0x0b, 0xc0, 0xe0, 0x68, +0x00, 0x00, 0xd1, 0x20, +0x6c, 0x40, 0x01, 0xda, +0x08, 0x5c, 0x81, 0x01, +0x8e, 0x89, 0x40, 0x00, +0x01, 0x42, 0x45, 0x6c, +0x40, 0x01, 0x5a, 0x48, +0x6c, 0x40, 0x01, 0x8a, +0x48, 0x42, 0x1d, 0x38, +0x40, 0x7a, 0x68, 0x00, +0x00, 0x7a, 0x20, 0x68, +0x00, 0x00, 0x83, 0x21, +0x66, 0x00, 0x02, 0x60, +0x20, 0x6e, 0x00, 0x01, +0xa2, 0x24, 0x32, 0x06, +0x0b, 0xc1, 0xa1, 0x68, +0x20, 0x00, 0xf0, 0x21, +0x68, 0x20, 0x00, 0xad, +0x20, 0xa0, 0xc2, 0x28, +0x81, 0x62, 0x66, 0x00, +0x02, 0x65, 0xe0, 0x88, +0x12, 0x26, 0x82, 0x00, +0x0c, 0x52, 0x06, 0x82, +0x00, 0x0f, 0x02, 0x16, +0x60, 0x00, 0x26, 0x5e, +0x08, 0x81, 0x20, 0x6c, +0x40, 0x02, 0x36, 0x08, +0x84, 0x30, 0x93, 0x01, +0x28, 0xbc, 0x1b, 0x16, +0xc0, 0x00, 0x61, 0x67, +0xa6, 0xc0, 0x00, 0x61, +0x87, 0xab, 0xc1, 0x67, +0x6c, 0x00, 0x01, 0x32, +0x08, 0x38, 0x19, 0xd2, +0x89, 0x64, 0x30, 0x16, +0x0b, 0xc1, 0x01, 0x68, +0x20, 0x00, 0xad, 0x20, +0x68, 0x20, 0x00, 0xf1, +0x21, 0x68, 0x20, 0x00, +0xee, 0x22, 0x66, 0x00, +0x02, 0x65, 0xe0, 0x68, +0x20, 0x00, 0xee, 0x22, +0x68, 0x20, 0x00, 0xc5, +0x20, 0x66, 0x00, 0x02, +0x65, 0xe8, 0x40, 0x00, +0x02, 0x10, 0x61, 0x6e, +0x00, 0x01, 0xa2, 0x24, +0x32, 0x06, 0x0b, 0xc4, +0xe0, 0x68, 0x00, 0x01, +0x91, 0x20, 0x66, 0x00, +0x00, 0x52, 0xe0, 0x32, +0x02, 0x0b, 0xc4, 0x81, +0x6c, 0x00, 0x01, 0x32, +0x08, 0x2a, 0x8e, 0x53, +0x20, 0xe8, 0xbc, 0x1e, +0x06, 0xc0, 0x00, 0x0f, +0x80, 0x96, 0xc4, 0x00, +0x1e, 0xe0, 0x22, 0x80, +0xae, 0x32, 0x03, 0x0b, +0xc0, 0x4b, 0x38, 0x10, +0x32, 0x40, 0xe4, 0x6c, +0x00, 0x01, 0x32, 0x48, +0x2e, 0x0a, 0xd3, 0x20, +0x28, 0xbc, 0x07, 0xd3, +0x81, 0x0c, 0x6c, 0x00, +0x01, 0x32, 0x09, 0x24, +0x12, 0xc6, 0xc0, 0x00, +0x13, 0x24, 0x80, 0x00, +0x00, 0x6c, 0x00, 0x01, +0x32, 0x08, 0x2a, 0x8e, +0x43, 0x20, 0xe0, 0xbc, +0x04, 0x16, 0xc4, 0x00, +0x1d, 0xa0, 0x86, 0xc4, +0x00, 0x15, 0xa4, 0x83, +0x81, 0x85, 0x6c, 0x00, +0x01, 0x32, 0x08, 0x28, +0x96, 0x23, 0x01, 0x50, +0xbc, 0x1f, 0x06, 0xc0, +0x00, 0x10, 0xa0, 0x26, +0xc4, 0x00, 0x1e, 0xe0, +0x32, 0x80, 0xd7, 0x32, +0x03, 0x8b, 0xc0, 0x4b, +0x38, 0x12, 0x62, 0x41, +0xa4, 0x6c, 0x00, 0x01, +0x32, 0x48, 0x2e, 0x0d, +0x23, 0x20, 0x10, 0xbc, +0x07, 0xd3, 0x81, 0x2c, +0x6c, 0x00, 0x01, 0x32, +0x02, 0x24, 0x11, 0x46, +0xc0, 0x00, 0x13, 0x24, +0x80, 0x00, 0x00, 0x6c, +0x00, 0x01, 0x32, 0x08, +0x28, 0x96, 0x43, 0x01, +0x60, 0x40, 0x00, 0x03, +0xc0, 0x41, 0x6c, 0x40, +0x01, 0xda, 0x08, 0x6c, +0x40, 0x01, 0x8a, 0x48, +0x68, 0x00, 0x05, 0xbf, +0xa0, 0x88, 0x1b, 0x6b, +0xa1, 0x48, 0x6c, 0x00, +0x01, 0x2e, 0x60, 0x40, +0x00, 0x02, 0x80, 0x70, +0x68, 0x00, 0x00, 0xe3, +0x20, 0x6c, 0x00, 0x01, +0xd2, 0x09, 0x84, 0x04, +0x9a, 0xbf, 0xd0, 0xa0, +0x04, 0x08, 0x82, 0x60, +0x88, 0x2f, 0x66, 0x80, +0x00, 0x0d, 0x22, 0x06, +0x82, 0x00, 0x1a, 0x22, +0x46, 0x60, 0x00, 0x1b, +0x88, 0x08, 0x82, 0x20, +0x68, 0x20, 0x02, 0xab, +0x2c, 0x84, 0x04, 0x88, +0x80, 0x6c, 0xa0, 0x4e, +0x06, 0x82, 0x00, 0x2a, +0xc2, 0xc6, 0x82, 0x00, +0x2a, 0xba, 0x26, 0x82, +0x00, 0x29, 0xc2, 0xd8, +0x82, 0x60, 0x68, 0x20, +0x01, 0xa2, 0x24, 0x68, +0x00, 0x00, 0xdc, 0x21, +0x68, 0x20, 0x02, 0xa9, +0x25, 0x88, 0x0e, 0xc8, +0x81, 0x62, 0x88, 0x1e, +0xd6, 0x60, 0x00, 0x1b, +0x9e, 0x89, 0x82, 0x09, +0x68, 0x00, 0x06, 0xae, +0xa4, 0x88, 0x22, 0x08, +0x82, 0xb6, 0x6c, 0x00, +0x01, 0x2e, 0x64, 0xba, +0x14, 0x88, 0x43, 0x48, +0x40, 0x00, 0x02, 0x80, +0x30, 0xab, 0xff, 0x08, +0x80, 0x76, 0x68, 0x20, +0x02, 0xa6, 0x24, 0x68, +0x00, 0x01, 0xe4, 0x20, +0x66, 0x00, 0x00, 0x48, +0xa8, 0x6c, 0x00, 0x00, +0xfa, 0x09, 0x6c, 0x00, +0x03, 0x74, 0x48, 0x68, +0x20, 0x02, 0xa6, 0x24, +0x68, 0x00, 0x01, 0xe6, +0x20, 0x66, 0x00, 0x00, +0x48, 0xa8, 0x6c, 0x00, +0x01, 0x0c, 0x09, 0x6c, +0x00, 0x03, 0x8e, 0x48, +0x68, 0x20, 0x02, 0xa6, +0x24, 0x68, 0x00, 0x01, +0xe8, 0x20, 0x66, 0x00, +0x00, 0x48, 0xa8, 0x6c, +0x00, 0x01, 0xca, 0x09, +0x68, 0x20, 0x01, 0x0f, +0x24, 0x6c, 0x40, 0x05, +0xe2, 0x09, 0x86, 0x00, +0xa3, 0x01, 0x70, 0xbc, +0x04, 0xd6, 0xc0, 0x00, +0x3a, 0x84, 0x86, 0xc4, +0x00, 0x21, 0xe7, 0xaa, +0x26, 0xa4, 0x6c, 0x40, +0x02, 0x1e, 0x08, 0x6c, +0x40, 0x05, 0x32, 0x09, +0x55, 0x03, 0x20, 0x60, +0x0a, 0x30, 0x1a, 0x86, +0xc4, 0x00, 0x21, 0xe4, +0x8b, 0xc0, 0x81, 0x6c, +0x00, 0x03, 0x86, 0x08, +0x32, 0x02, 0x0b, 0xc0, +0x41, 0x6c, 0x00, 0x03, +0xa0, 0x08, 0x32, 0x02, +0x0b, 0xc8, 0x60, 0x68, +0x20, 0x02, 0xa3, 0x24, +0x68, 0x00, 0x01, 0xde, +0x20, 0x66, 0x00, 0x00, +0x48, 0xa8, 0x6c, 0x00, +0x00, 0xfa, 0x09, 0x6c, +0x00, 0x03, 0x82, 0x48, +0x68, 0x20, 0x02, 0xa3, +0x24, 0x68, 0x00, 0x01, +0xe0, 0x20, 0x66, 0x00, +0x00, 0x48, 0xa8, 0x6c, +0x00, 0x01, 0x0c, 0x09, +0x6c, 0x00, 0x03, 0x9c, +0x48, 0x68, 0x20, 0x02, +0xa3, 0x24, 0x68, 0x00, +0x01, 0xe2, 0x20, 0x66, +0x00, 0x00, 0x48, 0xa8, +0x6c, 0x00, 0x01, 0xca, +0x09, 0x68, 0x20, 0x01, +0x0b, 0x24, 0x6c, 0x00, +0x03, 0x82, 0x0a, 0x5c, +0x83, 0x02, 0x25, 0xc1, +0x86, 0x00, 0x98, 0x48, +0x0b, 0x6c, 0x00, 0x03, +0x9c, 0x02, 0x30, 0x1e, +0x86, 0x80, 0x00, 0x1d, +0xb2, 0x0b, 0xc3, 0xdd, +0x80, 0x24, 0x8a, 0x26, +0x24, 0x6c, 0x40, 0x05, +0x32, 0x09, 0x86, 0x00, +0x03, 0x00, 0x28, 0xbc, +0x34, 0x86, 0xc4, 0x00, +0x21, 0x67, 0xa6, 0x82, +0x00, 0x29, 0xe2, 0x43, +0x90, 0x21, 0x82, 0x28, +0xb8, 0x60, 0x01, 0x2e, +0x07, 0xf3, 0x69, 0xc1, +0x6c, 0x40, 0x02, 0x00, +0x0b, 0x98, 0x04, 0x13, +0x01, 0xc8, 0xbc, 0x1c, +0x36, 0x82, 0x00, 0x2a, +0x02, 0x10, 0x00, 0x00, +0x80, 0xa8, 0x18, 0x48, +0x03, 0x2e, 0x0c, 0x93, +0x68, 0x41, 0x98, 0x04, +0x13, 0x01, 0xc8, 0xbc, +0x12, 0x36, 0x80, 0x00, +0x1d, 0x82, 0x10, 0x00, +0x00, 0x80, 0xa8, 0x18, +0x48, 0x03, 0x2e, 0x0c, +0x93, 0x68, 0x41, 0x98, +0x04, 0x13, 0x01, 0xc8, +0xbc, 0x08, 0x36, 0x81, +0x66, 0x66, 0x64, 0xb0, +0x87, 0x10, 0x22, 0x20, +0x99, 0x80, 0x49, 0x2e, +0x82, 0xd6, 0xc4, 0x00, +0x53, 0x24, 0x98, 0x20, +0x4a, 0x68, 0x00, 0x01, +0xd8, 0x21, 0x82, 0x2d, +0x26, 0xc4, 0x00, 0x53, +0xc4, 0xa8, 0x0a, 0xc8, +0x42, 0x02, 0x78, 0x60, +0x52, 0x84, 0x84, 0x8b, +0xc0, 0x2f, 0x39, 0x02, +0x13, 0x90, 0x21, 0x68, +0x20, 0x02, 0x9a, 0x24, +0x84, 0x00, 0x95, 0x74, +0x94, 0x02, 0x0c, 0xa8, +0x60, 0xc8, 0xe0, 0xb0, +0x1a, 0x20, 0x44, 0x86, +0x00, 0x85, 0x74, 0xd0, +0x04, 0x00, 0x85, 0x78, +0x52, 0x02, 0x2d, 0x08, +0x40, 0x48, 0x00, 0x00, +0x08, 0x60, 0x09, 0x57, +0x8d, 0x40, 0x61, 0x89, +0x57, 0x45, 0x40, 0x20, +0x50, 0x82, 0x2d, 0x00, +0x00, 0x00, 0x6c, 0x40, +0x02, 0x16, 0x09, 0x55, +0x03, 0x68, 0x60, 0x0a, +0x2f, 0x0b, 0x46, 0xc4, +0x00, 0x21, 0x64, 0x98, +0x60, 0x48, 0x68, 0x00, +0x01, 0x91, 0x20, 0x66, +0x00, 0x00, 0x53, 0x80, +0x88, 0x03, 0x66, 0x80, +0x00, 0x61, 0x72, 0x4b, +0xa1, 0x48, 0x6c, 0x00, +0x01, 0x2e, 0x64, 0x40, +0x00, 0x02, 0x80, 0x10, +0xa2, 0x28, 0x46, 0x40, +0x00, 0x04, 0x8a, 0xfa, +0x01, 0x00, 0xab, 0xff, +0x08, 0x80, 0x65, 0x88, +0x0f, 0x66, 0x60, 0x00, +0x04, 0x98, 0x8a, 0x20, +0x84, 0x88, 0x02, 0x08, +0x81, 0x24, 0x94, 0x02, +0x55, 0x00, 0xb0, 0x08, +0x0b, 0x68, 0x60, 0x09, +0x46, 0x0a, 0x41, 0x80, +0x08, 0x44, 0x08, 0x02, +0x80, 0x10, 0x40, 0x00, +0x01, 0x80, 0x08, 0x98, +0x80, 0x86, 0x80, 0x00, +0x0d, 0xe0, 0xa5, 0x80, +0xd0, 0x2b, 0xfd, 0x08, +0x80, 0x60, 0x88, 0x14, +0x98, 0x81, 0xe5, 0x88, +0x26, 0x44, 0x20, 0x4c, +0x08, 0x2f, 0x68, 0x80, +0xe1, 0x68, 0x20, 0x00, +0xd0, 0x24, 0x88, 0x0a, +0x06, 0x60, 0x00, 0x04, +0x8a, 0x08, 0x80, 0x20, +0xbc, 0x0b, 0xf8, 0x41, +0xc8, 0x68, 0x20, 0x00, +0xd0, 0x24, 0x68, 0x00, +0x00, 0xdc, 0x20, 0x66, +0x00, 0x00, 0x48, 0xa0, +0x88, 0x02, 0x00, 0x00, +0x00, 0x40, 0x00, 0x00, +0x41, 0xc8, 0x68, 0x20, +0x01, 0x1d, 0x24, 0x6c, +0x40, 0x01, 0xae, 0x09, +0x5d, 0x0a, 0x20, 0x41, +0x89, 0x51, 0x85, 0x20, +0x40, 0x0b, 0x57, 0x0f, +0x51, 0x88, 0x09, 0x68, +0x00, 0x00, 0xde, 0x00, +0x58, 0x01, 0x41, 0x82, +0x28, 0x68, 0x20, 0x02, +0x69, 0x21, 0x98, 0x08, +0x24, 0x20, 0x1c, 0x1e, +0x00, 0x59, 0xc8, 0x06, +0xbc, 0x03, 0xf8, 0x68, +0x08, 0x40, 0x00, 0x00, +0x70, 0x08, 0x5b, 0x44, +0x30, 0x82, 0x21, 0x58, +0x49, 0x80, 0x84, 0x24, +0xa0, 0x88, 0x26, 0xc4, +0x00, 0x1d, 0xa0, 0x89, +0x60, 0x3e, 0x42, 0x03, +0x52, 0x10, 0x61, 0xa1, +0x0a, 0x36, 0xe0, 0x00, +0x12, 0xc2, 0x93, 0x81, +0x2b, 0x25, 0x8c, 0x8b, +0xc7, 0x70, 0x88, 0x32, +0x68, 0x81, 0xa7, 0x97, +0x02, 0x85, 0x90, 0x20, +0x08, 0x0a, 0x5b, 0xc1, +0x19, 0x87, 0x87, 0xa0, +0x00, 0x00, 0x86, 0x88, +0x03, 0x01, 0xc0, 0xbc, +0x07, 0xb8, 0x43, 0x80, +0x30, 0x03, 0x8b, 0xc0, +0x94, 0x98, 0xe8, 0x08, +0x68, 0xcb, 0x97, 0x06, +0x0b, 0xc0, 0x57, 0x30, +0x03, 0x8b, 0xc0, 0x3a, +0x98, 0xe8, 0x08, 0x68, +0xcb, 0x97, 0x06, 0x00, +0x00, 0x00, 0x6c, 0x40, +0x03, 0xc2, 0x00, 0x85, +0x18, 0xb3, 0x00, 0x38, +0xbc, 0x24, 0x83, 0x90, +0x20, 0x68, 0x20, 0x01, +0xe6, 0x27, 0x5c, 0x82, +0x08, 0x52, 0x8b, 0x5c, +0x85, 0x10, 0x38, 0x02, +0x57, 0x05, 0xca, 0x18, +0x06, 0x59, 0x00, 0x80, +0x1a, 0xd1, 0x00, 0x00, +0x08, 0x3b, 0x0b, 0x85, +0x80, 0x25, 0x70, 0xe9, +0x07, 0x80, 0xb8, 0x58, +0x52, 0xbc, 0x06, 0xc8, +0x52, 0x82, 0x30, 0x1d, +0x0b, 0xc0, 0x82, 0x85, +0x1d, 0x08, 0x49, 0x4b, +0xbc, 0x05, 0x73, 0x01, +0xd0, 0xbc, 0x03, 0x48, +0x51, 0xd0, 0x84, 0x94, +0xb0, 0x00, 0x00, 0x85, +0x80, 0xb5, 0x70, 0xf0, +0x03, 0x20, 0xb5, 0x70, +0xe0, 0x08, 0x3a, 0x1b, +0xc0, 0x3f, 0x87, 0x04, +0x08, 0x83, 0xa1, 0x00, +0x00, 0x00, 0x00, 0x00, +0x84, 0x80, 0xb3, 0x01, +0x38, 0xbc, 0x0b, 0x36, +0xc4, 0x00, 0x21, 0x00, +0x02, 0x80, 0x3f, 0x30, +0x93, 0x8b, 0xc0, 0x34, +0xbc, 0x06, 0xf5, 0xc0, +0xbe, 0x04, 0x84, 0xbb, +0xc0, 0x3f, 0x5c, 0x0b, +0xe0, 0x48, 0x48, 0x38, +0x17, 0xc2, 0x59, 0x30, +0xbc, 0x20, 0x13, 0x81, +0x67, 0x25, 0x9f, 0x0b, +0xc0, 0xf9, 0x38, 0x17, +0x42, 0x59, 0x30, 0xbc, +0x04, 0x99, 0x8e, 0x88, +0x84, 0x30, 0xb3, 0x20, +0x38, 0xbc, 0x06, 0x43, +0x81, 0x77, 0x25, 0x9f, +0x0b, 0xc1, 0x30, 0x84, +0x30, 0xa3, 0x20, 0x30, +0xbc, 0x10, 0x39, 0x60, +0x74, 0xbc, 0x0e, 0x72, +0x59, 0x30, 0xbc, 0x04, +0x93, 0x81, 0x64, 0x84, +0x30, 0xb3, 0x20, 0x38, +0xbc, 0x06, 0x23, 0x81, +0x77, 0x25, 0x9f, 0x0b, +0xc0, 0x50, 0x84, 0x30, +0xb3, 0x20, 0x38, 0xbc, +0x02, 0x52, 0x41, 0x30, +0x96, 0x07, 0x0b, 0xc4, +0x6f, 0x88, 0x1a, 0x23, +0x00, 0x28, 0xbc, 0x02, +0x0b, 0xc0, 0x2f, 0x86, +0x80, 0x08, 0x70, 0x00, +0x32, 0x01, 0x0b, 0xc0, +0x4c, 0x88, 0x0a, 0x55, +0x70, 0x1c, 0x3c, 0x03, +0xf8, 0x68, 0xc0, 0x28, +0x1c, 0x08, 0x68, 0xc0, +0x68, 0x20, 0x01, 0x16, +0x23, 0x88, 0x1a, 0x28, +0x58, 0x0b, 0x85, 0x00, +0x05, 0x50, 0x20, 0x08, +0x32, 0x65, 0x80, 0xe0, +0x05, 0x05, 0x0a, 0x1d, +0xa3, 0x42, 0x02, 0x6b, +0x00, 0x08, 0x97, 0x06, +0x0b, 0xc0, 0x4f, 0x5c, +0x81, 0x08, 0x50, 0x4b, +0x5c, 0x81, 0x0b, 0x80, +0x00, 0x68, 0x20, 0x01, +0xe3, 0x26, 0x5c, 0x0b, +0xfa, 0xc0, 0x40, 0x52, +0xcf, 0x80, 0x30, 0x8a, +0x87, 0x00, 0x28, 0x08, +0xca, 0x84, 0x85, 0x20, +0x00, 0x00, 0x88, 0x3a, +0x78, 0x1a, 0x0a, 0x87, +0x08, 0x24, 0x20, 0x74, +0x07, 0x84, 0xa5, 0xc0, +0x00, 0x04, 0x8d, 0x22, +0x41, 0xc7, 0x5d, 0x4e, +0x38, 0x43, 0x00, 0x32, +0x00, 0x0b, 0xc0, 0x5c, +0x5c, 0x0b, 0xb1, 0x60, +0x77, 0x52, 0x4d, 0xc3, +0xc0, 0x3f, 0x96, 0x07, +0x02, 0x41, 0xb8, 0x96, +0x07, 0x08, 0x58, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x02, +0xb6, 0x0a, 0x6c, 0x40, +0x01, 0x50, 0x4a, 0x6c, +0x40, 0x01, 0x80, 0x4a, +0x68, 0x00, 0x00, 0x76, +0x08, 0x58, 0x09, 0x40, +0x68, 0x89, 0x84, 0x1c, +0x9b, 0xc1, 0x68, 0x85, +0x00, 0x99, 0x88, 0x08, +0x68, 0x00, 0x00, 0x7f, +0x0a, 0x30, 0x1a, 0x0b, +0xc0, 0x80, 0x68, 0x00, +0x01, 0xd1, 0x21, 0x66, +0x00, 0x01, 0xd6, 0xc0, +0x88, 0x02, 0x0b, 0xc1, +0x1f, 0x40, 0x00, 0x00, +0x40, 0x48, 0x68, 0x00, +0x01, 0xc4, 0x21, 0x66, +0x00, 0x01, 0xd6, 0xc0, +0x88, 0x02, 0x0b, 0xc0, +0x9f, 0x40, 0x00, 0x00, +0x40, 0x48, 0x68, 0x00, +0x01, 0xb7, 0x21, 0x66, +0x00, 0x01, 0xd6, 0xc0, +0x88, 0x02, 0x00, 0x00, +0x00, 0x84, 0x04, 0x80, +0x00, 0x00, 0x6c, 0x40, +0x01, 0xea, 0x09, 0x6c, +0x40, 0x02, 0x36, 0x08, +0x30, 0x12, 0x8b, 0xc0, +0x48, 0x88, 0x4a, 0x44, +0x21, 0x57, 0x84, 0x00, +0x98, 0x60, 0x49, 0x6c, +0x40, 0x05, 0x32, 0x08, +0x6c, 0x40, 0x01, 0xf4, +0x0a, 0x30, 0x1a, 0x0b, +0xc2, 0x39, 0x5c, 0x09, +0x70, 0x60, 0x0b, 0x6e, +0x00, 0x01, 0x2c, 0x28, +0x25, 0x98, 0x0b, 0xc0, +0xc1, 0x54, 0x09, 0xc0, +0x40, 0x0a, 0x98, 0x00, +0x03, 0x00, 0x30, 0xbc, +0x01, 0x58, 0x40, 0x50, +0x2e, 0x13, 0x88, 0x40, +0x08, 0x98, 0x00, 0xa3, +0x01, 0xa0, 0xbc, 0x01, +0x38, 0x40, 0x4a, 0x00, +0x00, 0x08, 0x40, 0x08, +0x86, 0x00, 0xa3, 0x01, +0xa0, 0x6c, 0x40, 0x02, +0x2a, 0x00, 0xbc, 0x03, +0xb2, 0x08, 0x2d, 0x2e, +0x17, 0x88, 0x60, 0x40, +0x00, 0x00, 0x08, 0x40, +0x08, 0x86, 0x00, 0xa3, +0x01, 0xa0, 0xbc, 0x02, +0x52, 0x81, 0x78, 0x86, +0x04, 0x00, 0x00, 0x00, +0x88, 0x2b, 0x68, 0x40, +0x08, 0x46, 0x0a, 0x40, +0x81, 0x09, 0x57, 0x09, +0x42, 0x80, 0x30, 0x40, +0x00, 0x01, 0x80, 0x08, +0x5c, 0x09, 0xe2, 0x22, +0xe4, 0x86, 0x00, 0xa4, +0x43, 0x00, 0x16, 0x9a, +0x55, 0x00, 0xa0, 0x08, +0x02, 0x56, 0xe0, 0x00, +0x12, 0xc2, 0xd5, 0x2c, +0x94, 0x06, 0x80, 0x94, +0x20, 0x24, 0x18, 0x00, +0x80, 0x81, 0x00, 0xba, +0x14, 0x89, 0x80, 0x08, +0x00, 0x00, 0x08, 0x40, +0x89, 0x46, 0x0a, 0x40, +0x68, 0x88, 0x08, 0x48, +0x09, 0x80, 0x08, 0xab, +0xfd, 0x0a, 0x21, 0x64, +0xa0, 0x88, 0x18, 0x80, +0x64, 0xa2, 0x06, 0x48, +0x80, 0xe1, 0xa0, 0x84, +0x18, 0x81, 0x64, 0x88, +0x1c, 0x98, 0x82, 0x60, +0x88, 0x2f, 0x66, 0x60, +0x00, 0x04, 0x8a, 0x8a, +0x08, 0x00, 0x88, 0x12, +0x08, 0x82, 0x21, 0xa0, +0x06, 0x08, 0x40, 0x0a, +0x88, 0x18, 0x94, 0x43, +0x00, 0x04, 0xa4, 0x8a, +0x06, 0x24, 0x66, 0x00, +0x01, 0xf2, 0x48, 0x40, +0x00, 0x01, 0x80, 0x09, +0x6e, 0x00, 0x01, 0xa2, +0x25, 0x59, 0x03, 0x40, +0x80, 0xa4, 0xbc, 0x0f, +0x8a, 0x20, 0x20, 0x6c, +0x40, 0x02, 0xb4, 0x09, +0x88, 0x02, 0x48, 0x80, +0xc8, 0x66, 0x00, 0x02, +0x5e, 0xa8, 0x40, 0x00, +0x00, 0x60, 0x8a, 0x55, +0x01, 0x28, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, +0xc9, 0xbc, 0x0c, 0xf8, +0x80, 0x88, 0x86, 0x08, +0x96, 0xc4, 0x00, 0x1f, +0x00, 0xa3, 0x69, 0x45, +0x30, 0x97, 0x0b, 0xc0, +0x55, 0x88, 0x02, 0x06, +0xc4, 0x00, 0x1d, 0xa0, +0x98, 0x40, 0xc9, 0x00, +0x00, 0x08, 0x82, 0xb6, +0xba, 0x14, 0x8a, 0x80, +0x30, 0x40, 0x00, 0x03, +0x80, 0x00, 0x5c, 0x81, +0x02, 0x00, 0x80, 0xa2, +0x16, 0x48, 0x20, 0x0a, +0x84, 0x00, 0x84, 0x41, +0x00, 0x02, 0x00, 0xa8, +0x40, 0x88, 0x44, 0x14, +0x00, 0x60, 0x08, 0xba, +0x14, 0x84, 0x42, 0x40, +0x04, 0x04, 0x99, 0x80, +0x08, 0xa2, 0x24, 0x48, +0x60, 0x08, 0x44, 0x20, +0x00, 0x60, 0x89, 0x98, +0x00, 0x84, 0x40, 0x80, +0x16, 0x8a, 0x5b, 0xa1, +0x48, 0x20, 0x14, 0x09, +0x80, 0x08, 0x5c, 0x83, +0x10, 0x43, 0x08, 0x98, +0x84, 0xb5, 0x90, 0x1c, +0x2b, 0xfe, 0x08, 0x01, +0x01, 0x6c, 0x40, 0x01, +0xf4, 0x0a, 0x6c, 0x40, +0x05, 0x32, 0x00, 0xa0, +0x94, 0x28, 0x40, 0x02, +0x88, 0x0c, 0x98, 0x81, +0x48, 0x42, 0x1a, 0x40, +0x81, 0xca, 0x88, 0x05, +0x13, 0x01, 0x80, 0xbc, +0x09, 0x16, 0xc0, 0x00, +0x38, 0x60, 0x83, 0x20, +0x20, 0xbc, 0x05, 0x16, +0xc0, 0x00, 0x3a, 0x00, +0x83, 0x20, 0x20, 0x40, +0x00, 0x03, 0xc2, 0x50, +0x68, 0x20, 0x01, 0x0b, +0x20, 0x84, 0xd0, 0x8a, +0x05, 0xc3, 0x84, 0x00, +0x98, 0x58, 0x0a, 0x30, +0x1a, 0x8b, 0xc1, 0x4d, +0x5c, 0x81, 0x02, 0x14, +0x80, 0x5c, 0x08, 0x1a, +0x08, 0xe2, 0x5c, 0x82, +0x08, 0x12, 0x0a, 0x50, +0x47, 0x88, 0x10, 0x89, +0x20, 0x8e, 0xb5, 0x40, +0x64, 0xb0, 0x1f, 0xb2, +0x08, 0xcb, 0x2c, 0x85, +0xb1, 0x4b, 0x75, 0x51, +0x42, 0x48, 0x10, 0x53, +0x81, 0x34, 0xd4, 0x20, +0x17, 0x85, 0x04, 0x88, +0x50, 0xc8, 0x39, 0x04, +0x10, 0x00, 0x00, 0x84, +0x00, 0x95, 0x78, 0x96, +0x84, 0x08, 0xa5, 0x74, +0x9a, 0x04, 0x04, 0x94, +0x20, 0x2b, 0x84, 0x0c, +0x8b, 0xc0, 0x4f, 0x5c, +0x81, 0x02, 0xc0, 0x41, +0x5c, 0x81, 0x02, 0xc0, +0x41, 0x6e, 0x00, 0x01, +0xa2, 0x24, 0x32, 0x02, +0x0b, 0xc0, 0xa9, 0x6c, +0x40, 0x01, 0xea, 0x09, +0x6c, 0x40, 0x02, 0x36, +0x0a, 0x30, 0x1a, 0x8b, +0xc0, 0x41, 0x6c, 0x00, +0x06, 0x16, 0x0a, 0x30, +0x17, 0x0b, 0xc0, 0xe2, +0x6c, 0x40, 0x02, 0x36, +0x0a, 0x30, 0x1a, 0x8b, +0xc0, 0x88, 0x5c, 0x00, +0x08, 0x80, 0x0a, 0x88, +0x08, 0x16, 0x80, 0x00, +0x15, 0x20, 0x33, 0x00, +0xc8, 0xbc, 0x17, 0xc9, +0x8e, 0x81, 0x2a, 0x02, +0x9b, 0xc1, 0x47, 0x6c, +0x00, 0x06, 0x16, 0x0a, +0x30, 0x17, 0x0b, 0xc0, +0xc3, 0x6c, 0x00, 0x06, +0x18, 0x01, 0x2a, 0x04, +0x93, 0x22, 0xc8, 0xbc, +0x07, 0xd6, 0xc0, 0x00, +0x61, 0x85, 0x12, 0xa0, +0x76, 0x6c, 0x00, 0x06, +0x16, 0x4a, 0x6c, 0x00, +0x06, 0x18, 0x7a, 0x00, +0x00, 0x06, 0xc0, 0x00, +0x61, 0x60, 0x18, 0x80, +0x0a, 0x32, 0x06, 0x04, +0xa7, 0x38, 0xbc, 0x0c, +0x85, 0x50, 0x1c, 0x9a, +0x14, 0x13, 0x01, 0x90, +0xbc, 0x06, 0x43, 0x01, +0x90, 0xbc, 0x10, 0xb5, +0x50, 0x1a, 0x08, 0x18, +0x29, 0x82, 0xc8, 0xbc, +0x0c, 0x7b, 0xc0, 0xbf, +0x88, 0x18, 0x28, 0x81, +0x02, 0x32, 0x01, 0x0b, +0xc0, 0x64, 0x32, 0x01, +0x0b, 0xc0, 0x5b, 0x55, +0x01, 0xa0, 0x81, 0x82, +0x98, 0x2c, 0x8b, 0xc0, +0x17, 0x88, 0x18, 0x23, +0x00, 0x80, 0xbc, 0x58, +0x06, 0xc0, 0x00, 0x38, +0x60, 0xa3, 0x20, 0x30, +0xbc, 0x04, 0x16, 0xc0, +0x00, 0x3a, 0x00, 0xa3, +0x20, 0x30, 0xbc, 0x50, +0x03, 0x20, 0x08, 0xbc, +0x4e, 0x06, 0xc0, 0x00, +0x38, 0x60, 0xa3, 0x20, +0x30, 0xbc, 0x05, 0x16, +0xc0, 0x00, 0x3a, 0x00, +0xa3, 0x20, 0x30, 0x40, +0x00, 0x03, 0xc4, 0x50, +0x6c, 0x40, 0x02, 0x36, +0x0a, 0x30, 0x1a, 0x8b, +0xc4, 0x10, 0x68, 0x20, +0x00, 0xfb, 0x20, 0x84, +0xc0, 0x98, 0x00, 0x0b, +0x30, 0x1e, 0x8b, 0xc0, +0x22, 0xbc, 0x04, 0xf8, +0x4d, 0xfa, 0x84, 0xd8, +0x92, 0xa0, 0x6d, 0x84, +0xdc, 0x90, 0x00, 0x00, +0x84, 0x00, 0x96, 0xc0, +0x00, 0x38, 0x40, 0xb3, +0x01, 0x78, 0xbc, 0x04, +0x56, 0xc0, 0x00, 0x39, +0xe0, 0xb3, 0x01, 0x78, +0xbc, 0x03, 0x4b, 0xc2, +0xbf, 0x40, 0x00, 0x00, +0x4d, 0x08, 0x68, 0x00, +0x00, 0x62, 0x22, 0x68, +0x00, 0x00, 0x6c, 0x21, +0x81, 0x07, 0xa8, 0x08, +0x7a, 0xa0, 0x80, 0x4a, +0x10, 0x00, 0x81, 0x07, +0xa8, 0x08, 0x7a, 0x84, +0x0f, 0xa8, 0x60, 0xfa, +0x68, 0x00, 0x00, 0xd2, +0x23, 0x68, 0x00, 0x01, +0xc1, 0x25, 0x81, 0x87, +0xa6, 0x82, 0x00, 0x29, +0xa2, 0x48, 0x28, 0x82, +0x68, 0x00, 0x01, 0xce, +0x26, 0x68, 0x00, 0x01, +0xdb, 0x20, 0xa1, 0x80, +0x7c, 0x03, 0x00, 0x83, +0x08, 0x18, 0x18, 0x7a, +0x87, 0x8f, 0xa6, 0xc4, +0x00, 0x1e, 0xa4, 0xa6, +0xc0, 0x00, 0x13, 0x07, +0xa8, 0x40, 0x7a, 0x87, +0x07, 0xa8, 0x68, 0x7a, +0x86, 0x0d, 0x08, 0x60, +0x51, 0x85, 0x0f, 0xa8, +0x48, 0xfa, 0x85, 0x8f, +0xab, 0xa1, 0x48, 0xa8, +0x02, 0x00, 0x00, 0x00, +0x85, 0x00, 0x88, 0x40, +0x09, 0x57, 0x8b, 0x22, +0xbf, 0xd0, 0x85, 0x04, +0x88, 0x80, 0x63, 0x88, +0x0e, 0x28, 0x81, 0x61, +0x88, 0x1e, 0x08, 0x82, +0x76, 0x00, 0x00, 0x08, +0x40, 0x09, 0x36, 0x14, +0x52, 0xe9, 0x64, 0x85, +0x04, 0x80, 0x00, 0x00, +0x85, 0x80, 0x88, 0x48, +0x09, 0x2f, 0x16, 0x48, +0x58, 0x48, 0x00, 0x00, +0x08, 0x48, 0x09, 0x36, +0x14, 0x52, 0xe9, 0x64, +0x44, 0x00, 0x00, 0x58, +0x48, 0x98, 0x00, 0x98, +0x50, 0x08, 0x44, 0x00, +0x00, 0x48, 0x08, 0x44, +0x01, 0x00, 0x40, 0x08, +0x44, 0x01, 0x01, 0xa0, +0x00, 0x44, 0x40, 0x01, +0x80, 0x88, 0x08, 0x18, +0x06, 0x60, 0x00, 0x04, +0xb6, 0x89, 0x81, 0x09, +0x88, 0x12, 0x08, 0x81, +0xa1, 0x84, 0x00, 0x98, +0x48, 0x0a, 0x44, 0x48, +0x00, 0x80, 0xa0, 0x88, +0x02, 0x19, 0x80, 0x0b, +0x84, 0x00, 0x94, 0x46, +0x80, 0x04, 0x80, 0xa4, +0x47, 0x10, 0x18, 0x00, +0xb4, 0x46, 0x00, 0x18, +0x28, 0xb5, 0x11, 0xe0, +0x18, 0x08, 0xa4, 0x44, +0x10, 0x18, 0x00, 0x83, +0x20, 0x20, 0x51, 0x1e, +0x83, 0xc0, 0x29, 0x98, +0x00, 0xa9, 0x82, 0x48, +0x32, 0x03, 0x0b, 0xc0, +0x11, 0x98, 0x2c, 0xa3, +0x69, 0x40, 0x5b, 0x48, +0x01, 0x80, 0x09, 0x98, +0x00, 0x03, 0x00, 0x28, +0xbc, 0x06, 0x43, 0x69, +0xc0, 0x5b, 0x4c, 0x01, +0x80, 0x09, 0x98, 0x00, +0xb3, 0x01, 0xe8, 0xbc, +0x04, 0x58, 0x40, 0x48, +0x42, 0x01, 0x7b, 0x00, +0x0c, 0x84, 0x84, 0xa9, +0x8e, 0x88, 0x00, 0x00, +0x08, 0x82, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, +0x00, 0x46, 0x08, 0x8a, +0xbf, 0xe0, 0x51, 0x61, +0xb0, 0x80, 0x49, 0x51, +0x61, 0xe0, 0x80, 0xf6, +0x1a, 0x0a, 0x29, 0x83, +0x09, 0x98, 0x38, 0x82, +0x81, 0x2d, 0x88, 0x14, +0x96, 0x60, 0x00, 0x04, +0xb6, 0x8b, 0xa1, 0x01, +0x88, 0x10, 0x94, 0x40, +0x80, 0x08, 0x00, 0x99, +0x80, 0x08, 0x23, 0x42, +0x43, 0x01, 0x60, 0xbc, +0x02, 0x5b, 0xc0, 0x2f, +0x2e, 0x16, 0x49, 0x8e, +0x88, 0x88, 0x0b, 0x6b, +0xa1, 0x48, 0xa8, 0x02, +0x00, 0x00, 0x00, 0x68, +0x20, 0x01, 0x9c, 0x22, +0x68, 0x00, 0x01, 0x38, +0x23, 0x5c, 0x81, 0x02, +0x10, 0x21, 0xa0, 0x82, +0x48, 0x60, 0x0a, 0xa2, +0x02, 0x08, 0x50, 0x08, +0xa0, 0x02, 0x28, 0x58, +0x09, 0x44, 0x20, 0x02, +0x18, 0x25, 0x86, 0x80, +0x84, 0x41, 0x10, 0x04, +0x80, 0xa4, 0x41, 0x40, +0x05, 0x00, 0xaa, 0x28, +0x23, 0x85, 0x80, 0x84, +0x41, 0x08, 0x21, 0x52, +0x46, 0xc0, 0x00, 0x25, +0x44, 0x1a, 0x1c, 0xa1, +0x84, 0x00, 0xb4, 0x43, +0xd4, 0x52, 0x08, 0x04, +0x41, 0x08, 0x00, 0x80, +0xa8, 0x20, 0x09, 0x44, +0x4c, 0xa0, 0x20, 0x09, +0x44, 0x49, 0x80, 0x20, +0x0a, 0x44, 0x15, 0xe0, +0x48, 0x08, 0x86, 0x00, +0xa6, 0x80, 0x00, 0x08, +0x82, 0x06, 0xc0, 0x00, +0x22, 0x84, 0x04, 0x41, +0x08, 0x00, 0x04, 0x16, +0xc0, 0x00, 0x1c, 0xe4, +0x16, 0xc0, 0x00, 0x23, +0xe4, 0x2b, 0xa1, 0x48, +0x84, 0x04, 0x30, 0x00, +0x00, 0x68, 0x00, 0x00, +0x62, 0x20, 0x5c, 0x81, +0x01, 0x8e, 0x88, 0x68, +0x00, 0x00, 0x6c, 0x21, +0x55, 0x03, 0x20, 0x00, +0x7a, 0x3a, 0x10, 0x43, +0x22, 0xa0, 0xbf, 0xfb, +0xa8, 0x08, 0x7a, 0x68, +0x00, 0x00, 0xda, 0x20, +0x00, 0x00, 0x08, 0x40, +0x7a, 0x84, 0x0f, 0xa6, +0xc0, 0x00, 0x61, 0x87, +0xa0, 0x00, 0x00, 0x6c, +0x40, 0x02, 0x36, 0x08, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x61, 0x64, 0x80, +0x00, 0x00, 0x84, 0x00, +0xa8, 0x60, 0x08, 0x44, +0x40, 0x00, 0x48, 0x08, +0x46, 0x0a, 0x40, 0x60, +0x8a, 0x08, 0x28, 0x09, +0x80, 0x08, 0x6e, 0x00, +0x01, 0x2c, 0x2c, 0x38, +0x12, 0x62, 0x59, 0xa0, +0xbc, 0x09, 0x18, 0x63, +0x88, 0x6c, 0x40, 0x03, +0xc2, 0x0a, 0x30, 0x1a, +0x0b, 0xc0, 0x40, 0x6c, +0x40, 0x02, 0x0e, 0x08, +0x08, 0x40, 0x09, 0x80, +0x09, 0xba, 0x14, 0x89, +0x82, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x20, 0x00, 0x24, 0x25, +0x68, 0x00, 0x00, 0x5e, +0x20, 0x5c, 0x82, 0x02, +0xc0, 0x21, 0x68, 0x20, +0x00, 0x4b, 0x24, 0x5c, +0x08, 0xad, 0x02, 0xd0, +0x68, 0x00, 0x00, 0x96, +0x21, 0x44, 0x18, 0x00, +0x20, 0x0a, 0x84, 0x00, +0x84, 0x41, 0x08, 0x14, +0x82, 0xc5, 0x2c, 0xb0, +0x2b, 0xf7, 0x06, 0x82, +0x00, 0x0a, 0xe2, 0x18, +0x81, 0x64, 0x88, 0x1e, +0x58, 0x82, 0x76, 0x88, +0x2d, 0x59, 0x04, 0x58, +0x42, 0x09, 0x48, 0x85, +0x54, 0x40, 0x00, 0x01, +0x03, 0x59, 0x68, 0x00, +0x00, 0x36, 0x20, 0x66, +0x00, 0x02, 0x2d, 0xe0, +0x68, 0x00, 0x00, 0x4a, +0x20, 0x68, 0x20, 0x00, +0xc6, 0x21, 0x66, 0x00, +0x02, 0x2d, 0xe0, 0x6c, +0x00, 0x01, 0x0e, 0x0a, +0x40, 0x00, 0x03, 0xc1, +0x1f, 0x6c, 0x00, 0x00, +0xfc, 0x09, 0x68, 0x00, +0x00, 0x36, 0x20, 0x66, +0x00, 0x02, 0x2d, 0xe0, +0x68, 0x00, 0x00, 0x4a, +0x20, 0x68, 0x20, 0x00, +0xc6, 0x21, 0x66, 0x00, +0x02, 0x2d, 0xe0, 0x68, +0x00, 0x00, 0x60, 0x20, +0x00, 0x00, 0x08, 0x40, +0x8a, 0x84, 0x00, 0x98, +0x85, 0xca, 0x40, 0x00, +0x00, 0x86, 0x49, 0x68, +0x20, 0x00, 0x85, 0x24, +0x66, 0x00, 0x02, 0x13, +0xa8, 0x6e, 0x40, 0x01, +0x12, 0x27, 0x68, 0x20, +0x00, 0x85, 0x20, 0x88, +0x84, 0x8a, 0x00, 0x88, +0x94, 0x02, 0x78, 0x86, +0x0a, 0x88, 0x58, 0x96, +0x60, 0x00, 0x21, 0x3a, +0x8a, 0x04, 0x4c, 0x6e, +0x00, 0x01, 0x2c, 0x2d, +0x5c, 0x08, 0xf0, 0x85, +0xc8, 0x68, 0x00, 0x00, +0x96, 0x20, 0x52, 0xcd, +0x40, 0x88, 0x09, 0x88, +0x8c, 0x84, 0x21, 0x04, +0xa0, 0x00, 0x88, 0x86, +0x60, 0x68, 0x20, 0x00, +0x90, 0x2c, 0x68, 0x20, +0x00, 0x8a, 0x24, 0x68, +0x20, 0x00, 0x8d, 0x25, +0x40, 0x00, 0x00, 0x80, +0x6c, 0x66, 0x00, 0x02, +0x14, 0x20, 0x6c, 0x40, +0x00, 0x4a, 0x09, 0x44, +0x08, 0x00, 0x85, 0x89, +0x68, 0x20, 0x00, 0x98, +0xac, 0x88, 0x84, 0x86, +0x82, 0x00, 0x09, 0x2a, +0x46, 0x82, 0x00, 0x09, +0x5a, 0x58, 0x80, 0x6c, +0x90, 0x75, 0x88, 0x85, +0xd4, 0x66, 0x00, 0x02, +0x14, 0x20, 0x6c, 0x40, +0x00, 0x98, 0x09, 0xbc, +0x0d, 0xf4, 0x40, 0x80, +0x08, 0x8c, 0x80, 0x00, +0x00, 0x6c, 0x40, 0x00, +0x4a, 0x08, 0x44, 0x20, +0x80, 0x85, 0x88, 0x6c, +0x40, 0x00, 0x98, 0x09, +0x44, 0x08, 0x01, 0x07, +0x59, 0x40, 0x00, 0x00, +0x85, 0xd5, 0x68, 0x00, +0x00, 0x42, 0x20, 0x90, +0x71, 0x1a, 0x04, 0x21, +0x88, 0x59, 0x58, 0x85, +0xe1, 0x90, 0x75, 0x88, +0x86, 0xd4, 0x66, 0x00, +0x00, 0x47, 0x68, 0x5c, +0x00, 0x71, 0x80, 0x49, +0x68, 0x00, 0x00, 0x56, +0x20, 0x90, 0x71, 0x0a, +0x04, 0x21, 0x88, 0x69, +0x48, 0x86, 0xe1, 0x40, +0x00, 0x00, 0x87, 0x48, +0x66, 0x00, 0x00, 0x47, +0x68, 0x5c, 0x00, 0x71, +0x80, 0x09, 0x5c, 0x08, +0x00, 0x81, 0x20, 0x88, +0x5a, 0x48, 0x81, 0xa5, +0x88, 0x14, 0x8a, 0x25, +0x64, 0x88, 0x6a, 0x19, +0x04, 0x12, 0x88, 0x62, +0x2a, 0x0d, 0x61, 0x86, +0x80, 0x88, 0x60, 0x0a, +0x88, 0x51, 0x64, 0x44, +0x54, 0x10, 0x31, 0x18, +0x40, 0x09, 0x88, 0x29, +0x59, 0x50, 0x2c, 0x52, +0xc1, 0x00, 0x48, 0x0b, +0x44, 0x6c, 0xa1, 0x80, +0x80, 0x98, 0x04, 0x28, +0x67, 0x50, 0x88, 0x1e, +0x14, 0x20, 0xdc, 0x88, +0x2e, 0x48, 0x4f, 0x52, +0x68, 0x20, 0x02, 0xbf, +0x20, 0x5c, 0x81, 0x01, +0xa0, 0x01, 0x68, 0x20, +0x02, 0xc2, 0x21, 0x4c, +0x04, 0x38, 0x02, 0x03, +0x80, 0x20, 0x94, 0x40, +0x88, 0x00, 0xa0, 0xa5, +0x10, 0x24, 0x80, 0xa0, +0x84, 0x46, 0x00, 0x18, +0x00, 0x85, 0x10, 0x20, +0x04, 0x00, 0x94, 0x85, +0x88, 0x18, 0x08, 0xa4, +0x40, 0xc0, 0x04, 0x80, +0xb0, 0x8b, 0xa8, 0x6c, +0x00, 0x00, 0x80, 0x40, +0x6c, 0x00, 0x00, 0xa8, +0x42, 0x5c, 0x09, 0x20, +0x84, 0x56, 0x90, 0x55, +0x88, 0x84, 0xd4, 0x00, +0x00, 0x06, 0xc4, 0x00, +0x40, 0x20, 0x92, 0x59, +0x28, 0xbc, 0x7d, 0x99, +0x03, 0x5a, 0x38, 0x11, +0xc6, 0xe4, 0x00, 0x3f, +0xe2, 0xe3, 0x01, 0x30, +0xbc, 0x13, 0x36, 0x82, +0x00, 0x23, 0x4a, 0x06, +0x80, 0x03, 0xfc, 0x00, +0x85, 0xd4, 0xc2, 0x94, +0x03, 0xf5, 0x44, 0x9f, +0xac, 0x66, 0x15, 0x48, +0xbf, 0xac, 0xd1, 0x05, +0x50, 0x38, 0x14, 0x0d, +0x70, 0x00, 0x00, 0x94, +0x03, 0xe2, 0x89, 0x34, +0x29, 0x16, 0x44, 0x23, +0x2f, 0x94, 0x25, 0x49, +0x40, 0x60, 0x6c, 0x00, +0x00, 0x6e, 0x08, 0x57, +0x08, 0x02, 0xc0, 0x20, +0x6c, 0x00, 0x00, 0x96, +0x0a, 0x6c, 0x00, 0x02, +0xb4, 0x08, 0x49, 0x21, +0x32, 0xc6, 0xd1, 0x6c, +0x00, 0x02, 0xb6, 0x0b, +0x6c, 0x00, 0x02, 0xb0, +0x0a, 0x6c, 0x00, 0x02, +0xb2, 0x08, 0x2e, 0x1d, +0x26, 0x82, 0x00, 0x1f, +0xd2, 0x04, 0x89, 0x28, +0x30, 0x18, 0x45, 0x2c, +0x94, 0x00, 0x04, 0x34, +0x20, 0xbc, 0x00, 0x0c, +0x08, 0x86, 0x60, 0x38, +0x1c, 0x42, 0x59, 0x28, +0x40, 0x00, 0x03, 0xc0, +0xf9, 0x68, 0x20, 0x02, +0x35, 0x24, 0x66, 0x00, +0x02, 0x3e, 0x40, 0x68, +0x20, 0x02, 0x35, 0x20, +0x5c, 0x0e, 0x2b, 0x01, +0x64, 0x76, 0x00, 0x10, +0x06, 0x80, 0x84, 0x00, +0xa2, 0x49, 0x75, 0x52, +0x09, 0x6b, 0xc1, 0x2f, +0x84, 0x04, 0x9b, 0xc1, +0x0f, 0x5c, 0x0b, 0x23, +0x80, 0x00, 0x68, 0x20, +0x02, 0x02, 0x24, 0x66, +0x00, 0x02, 0x3e, 0x40, +0x68, 0x20, 0x02, 0x02, +0x20, 0x5c, 0x0c, 0x2b, +0x01, 0x64, 0xa0, 0x42, +0x08, 0x40, 0x0a, 0x24, +0x97, 0x52, 0x49, 0x2d, +0x40, 0x00, 0x00, 0x40, +0x49, 0x5c, 0x82, 0x02, +0xc6, 0xb1, 0x88, 0x62, +0x06, 0x80, 0x03, 0xfc, +0x00, 0x9a, 0x00, 0x01, +0x94, 0x29, 0xe5, 0x44, +0xbb, 0x14, 0x02, 0xf5, +0xd4, 0xe3, 0xac, 0x66, +0x25, 0x48, 0xfb, 0x2c, +0xcd, 0x19, 0x49, 0x56, +0x68, 0x20, 0x01, 0xfd, +0x24, 0x94, 0x83, 0xe2, +0x89, 0x75, 0x29, 0x1e, +0xd9, 0x4a, 0xd5, 0x68, +0x20, 0x02, 0x35, 0x20, +0x80, 0xa0, 0x92, 0x59, +0x28, 0xbc, 0x05, 0x98, +0x86, 0x61, 0x66, 0x00, +0x02, 0x39, 0xa0, 0x40, +0x00, 0x03, 0xc0, 0x47, +0x68, 0x20, 0x02, 0x02, +0x20, 0x66, 0x00, 0x02, +0x39, 0xa0, 0x88, 0x62, +0x09, 0x8e, 0x88, 0x40, +0x00, 0x01, 0x40, 0x64, +0x68, 0x00, 0x01, 0x86, +0x21, 0x88, 0x2a, 0x06, +0x82, 0x00, 0x1e, 0x82, +0x46, 0x60, 0x00, 0x23, +0x82, 0x08, 0x88, 0x48, +0x68, 0x00, 0x01, 0x8c, +0x21, 0x88, 0x1a, 0x06, +0x82, 0x00, 0x1e, 0xe2, +0x46, 0x60, 0x00, 0x23, +0x82, 0x09, 0x03, 0x10, +0x88, 0x10, 0x98, 0x84, +0x14, 0x54, 0x0a, 0x11, +0x05, 0x11, 0x54, 0x08, +0x90, 0x87, 0x09, 0x88, +0x49, 0x55, 0x40, 0xa4, +0x08, 0x80, 0x95, 0x40, +0xa0, 0x08, 0x8c, 0x86, +0x82, 0x00, 0x07, 0xe2, +0xc6, 0xc0, 0x00, 0x2b, +0x00, 0xa6, 0xc0, 0x00, +0x2b, 0x20, 0x14, 0x85, +0x28, 0x08, 0x1a, 0x16, +0xc0, 0x00, 0x2b, 0x60, +0x96, 0xc0, 0x00, 0x2b, +0x40, 0x84, 0x92, 0x96, +0x08, 0x2a, 0x08, 0x49, +0x40, 0x84, 0x14, 0x26, +0x80, 0x00, 0x00, 0xe2, +0x16, 0x82, 0x00, 0x02, +0x42, 0x46, 0x82, 0x00, +0x07, 0x22, 0x58, 0x80, +0x6c, 0x66, 0x00, 0x02, +0x0f, 0x80, 0x68, 0x20, +0x00, 0x7f, 0xac, 0x88, +0x84, 0x86, 0x80, 0x00, +0x02, 0x22, 0x18, 0x81, +0xa0, 0x68, 0x20, 0x00, +0x4b, 0x24, 0x68, 0x20, +0x00, 0x78, 0x25, 0x88, +0x06, 0xc6, 0x60, 0x00, +0x20, 0xf8, 0x08, 0x88, +0xc8, 0x68, 0x20, 0x00, +0x83, 0x20, 0x68, 0x20, +0x00, 0x84, 0x21, 0xa4, +0x22, 0x36, 0x60, 0x00, +0x1e, 0x58, 0x8a, 0x42, +0x02, 0x5c, 0x81, 0x00, +0x82, 0xa0, 0x5c, 0x08, +0x61, 0x8e, 0x80, 0xa0, +0x26, 0x09, 0x42, 0x0d, +0x25, 0x92, 0x8b, 0xc0, +0x39, 0x55, 0x00, 0x08, +0x81, 0xa1, 0x88, 0x80, +0x03, 0x91, 0x81, 0x80, +0x2c, 0x0a, 0x0a, 0x61, +0x84, 0x00, 0x95, 0x40, +0xa0, 0x14, 0xa0, 0xd2, +0x59, 0x28, 0xbc, 0x03, +0x98, 0x40, 0xc0, 0x00, +0x00, 0x08, 0x88, 0x81, +0x80, 0xac, 0x10, 0x00, +0x00, 0x84, 0x80, 0x85, +0x40, 0x84, 0x08, 0x23, +0x6b, 0xa1, 0x48, 0x84, +0x8c, 0x0a, 0x80, 0x90, +0xab, 0xfb, 0x08, 0x81, +0x60, 0xa0, 0x04, 0x6a, +0x08, 0x00, 0xa2, 0x80, +0x1a, 0x34, 0x25, 0x86, +0x80, 0x88, 0x81, 0xe5, +0xa2, 0x84, 0x58, 0x82, +0x65, 0xa0, 0x82, 0x28, +0x85, 0x25, 0xa1, 0x02, +0x3a, 0x18, 0x27, 0xa2, +0x06, 0x48, 0x70, 0x09, +0x57, 0x09, 0x40, 0x80, +0x67, 0x88, 0x2e, 0x78, +0x83, 0x64, 0x88, 0x3e, +0x08, 0x84, 0x76, 0x66, +0x00, 0x02, 0x45, 0xa8, +0x40, 0x00, 0x01, 0x80, +0x09, 0x5c, 0x08, 0x28, +0x82, 0x20, 0x88, 0x1a, +0x1a, 0x02, 0x00, 0x94, +0x02, 0xf5, 0x2c, 0xbc, +0x04, 0x94, 0x8a, 0x05, +0xe1, 0x42, 0x02, 0xc8, +0x83, 0x24, 0x5c, 0x00, +0x30, 0x83, 0xa0, 0x88, +0x12, 0x50, 0x00, 0x00, +0x86, 0x98, 0xa8, 0x48, +0x08, 0x54, 0x09, 0x82, +0x01, 0x40, 0x98, 0x00, +0x9a, 0x22, 0xe4, 0x84, +0x8c, 0x98, 0x81, 0x64, +0x88, 0x1e, 0x06, 0x60, +0x00, 0x24, 0xbe, 0x08, +0x82, 0xa1, 0x88, 0x52, +0x58, 0x81, 0x24, 0x88, +0x1a, 0x08, 0x84, 0x36, +0xa2, 0x82, 0x5a, 0x80, +0x50, 0xa0, 0x04, 0x0a, +0x20, 0x64, 0x40, 0x00, +0x02, 0x08, 0x21, 0x64, +0x00, 0x02, 0x4c, 0xcf, +0x55, 0x01, 0x2a, 0x08, +0x22, 0x86, 0x00, 0x84, +0x42, 0x00, 0x06, 0x08, +0x95, 0x00, 0xe0, 0x3a, +0x14, 0x80, 0x89, 0x80, +0x40, 0x00, 0x01, 0x80, +0x08, 0x6e, 0x40, 0x00, +0x08, 0x3c, 0x38, 0x15, +0x62, 0x59, 0xa0, 0xbc, +0x2d, 0x05, 0x15, 0x96, +0x16, 0x1b, 0x65, 0x19, +0x5b, 0x08, 0x02, 0x04, +0x41, 0x00, 0x18, 0xe8, +0x85, 0xc8, 0x08, 0x18, +0x00, 0xa9, 0x40, 0x17, +0x30, 0x1f, 0x0b, 0xc0, +0x32, 0x2a, 0x06, 0x43, +0x21, 0x60, 0xbf, 0xfa, +0x23, 0x20, 0xe0, 0xbc, +0x1d, 0x05, 0x18, 0x32, +0xb0, 0x10, 0x05, 0x04, +0x19, 0x18, 0x26, 0x85, +0x50, 0x0b, 0x1e, 0x00, +0x44, 0x60, 0x88, 0x96, +0x03, 0x55, 0x04, 0x14, +0x98, 0x38, 0x95, 0x50, +0x07, 0x98, 0x34, 0x84, +0x44, 0x10, 0x9e, 0x80, +0x54, 0x46, 0xd4, 0x96, +0x83, 0x62, 0x10, 0x10, +0x08, 0x48, 0x23, 0x78, +0x00, 0x22, 0x88, 0x06, +0xc4, 0x00, 0x13, 0x60, +0x95, 0x18, 0x7b, 0x18, +0x30, 0x83, 0x61, 0x47, +0x28, 0x1a, 0x42, 0xf1, +0x65, 0x2e, 0x9e, 0xd2, +0x33, 0x2d, 0xba, 0x14, +0x84, 0x60, 0x80, 0x98, +0x24, 0x80, 0x00, 0x00, +0x68, 0x00, 0x00, 0xcd, +0x20, 0x6c, 0x40, 0x05, +0x70, 0x0a, 0x68, 0x00, +0x08, 0x69, 0xa1, 0x98, +0xe8, 0x86, 0xc0, 0x00, +0x13, 0xe7, 0xa6, 0xc0, +0x00, 0x19, 0x86, 0x16, +0xc4, 0x00, 0x57, 0x44, +0xa4, 0x60, 0xa4, 0x14, +0x0f, 0x49, 0x40, 0x74, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x05, +0x24, 0x08, 0x38, 0x10, +0x62, 0x59, 0xa0, 0xbc, +0x15, 0x13, 0x81, 0x80, +0x25, 0x82, 0x0b, 0xc1, +0x20, 0x6e, 0x00, 0x00, +0x92, 0x28, 0x38, 0x10, +0xa2, 0x58, 0x80, 0xbc, +0x08, 0x16, 0xe0, 0x00, +0x0b, 0xa2, 0x83, 0x81, +0x0a, 0x25, 0x88, 0x0b, +0xc0, 0x31, 0x6c, 0x00, +0x01, 0x98, 0x20, 0xba, +0x00, 0x02, 0x49, 0xa4, +0x6c, 0x40, 0x05, 0x24, +0x48, 0x64, 0x00, 0x02, +0x17, 0x87, 0x40, 0x00, +0x03, 0xa1, 0x40, 0xab, +0xff, 0x06, 0xe4, 0x00, +0x57, 0x23, 0x88, 0x80, +0x76, 0x68, 0x00, 0x00, +0x38, 0x20, 0x68, 0x00, +0x00, 0x4c, 0x21, 0x66, +0x00, 0x01, 0x67, 0x08, +0x22, 0x84, 0x48, 0x80, +0x36, 0x68, 0x00, 0x08, +0x6e, 0x20, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x19, +0x86, 0x0a, 0x80, 0x10, +0x6c, 0x00, 0x01, 0x3e, +0x08, 0x32, 0x02, 0x0b, +0xcb, 0xf9, 0xab, 0xff, +0x06, 0x80, 0x00, 0x0a, +0x22, 0x06, 0x82, 0x00, +0x2b, 0xb2, 0x18, 0x45, +0x08, 0xa0, 0x82, 0x28, +0x50, 0x48, 0xa1, 0x44, +0x28, 0x40, 0x0a, 0x85, +0x00, 0x05, 0x84, 0x18, +0x04, 0x84, 0xab, 0xc0, +0x5c, 0x88, 0x07, 0x64, +0x20, 0x47, 0x98, 0xe8, +0xa6, 0xe0, 0x00, 0x19, +0xa7, 0x60, 0x00, 0x00, +0x6e, 0x00, 0x01, 0x9a, +0x3e, 0x2a, 0x07, 0x26, +0xe0, 0x00, 0x19, 0xa7, +0x23, 0x08, 0x20, 0x40, +0x00, 0x03, 0xc0, 0x44, +0x42, 0x03, 0xf9, 0x8e, +0x88, 0x6e, 0x00, 0x01, +0x9b, 0x74, 0x6e, 0x00, +0x01, 0x9b, 0x3c, 0x2a, +0x06, 0x06, 0xe0, 0x00, +0x19, 0xb7, 0x03, 0x81, +0x14, 0x6c, 0x40, 0x03, +0xba, 0x0a, 0x25, 0x93, +0x0b, 0xc0, 0x31, 0x98, +0xe8, 0x06, 0xe0, 0x00, +0x19, 0xa7, 0x03, 0x81, +0x18, 0x25, 0x83, 0x0b, +0xc0, 0x31, 0x98, 0xe8, +0x06, 0xe0, 0x00, 0x19, +0xb7, 0x00, 0x00, 0x00, +0x6e, 0x00, 0x01, 0x9a, +0x38, 0x6e, 0x40, 0x05, +0x73, 0x3a, 0x30, 0x08, +0x0b, 0xc0, 0xa2, 0x6c, +0x40, 0x05, 0x24, 0x00, +0x5c, 0x0a, 0x3b, 0x01, +0x85, 0x24, 0x1c, 0x02, +0x41, 0x40, 0x6c, 0x40, +0x05, 0x24, 0x50, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6e, 0x00, 0x01, 0x9b, +0x38, 0x30, 0x08, 0x0b, +0xc0, 0xaa, 0x38, 0x18, +0x06, 0xc4, 0x00, 0x52, +0x40, 0x23, 0x81, 0x4d, +0x24, 0x15, 0x22, 0x40, +0x12, 0x6c, 0x40, 0x05, +0x24, 0x52, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x05, 0x24, 0x02, +0x25, 0x81, 0x0b, 0xc6, +0x41, 0x6e, 0x00, 0x01, +0x2c, 0x28, 0x25, 0x90, +0x0b, 0xc0, 0x51, 0x24, +0x90, 0x06, 0xe0, 0x00, +0x12, 0xc6, 0x0b, 0xc0, +0x2f, 0x38, 0x14, 0x43, +0x81, 0x44, 0x25, 0x91, +0x0b, 0xc1, 0xd1, 0x68, +0x00, 0x03, 0x00, 0x08, +0x28, 0x93, 0x02, 0x3a, +0x85, 0x32, 0x82, 0x8b, +0xc0, 0xc0, 0x32, 0x8a, +0x8b, 0xc1, 0x51, 0x29, +0x13, 0x66, 0xc4, 0x00, +0x3b, 0xa4, 0xa6, 0x80, +0x00, 0x04, 0x92, 0x06, +0x60, 0x00, 0x05, 0x1c, +0x89, 0x8e, 0x88, 0x40, +0x00, 0x03, 0xc0, 0xb7, +0x68, 0x3f, 0xfc, 0xff, +0xc8, 0x54, 0x49, 0xa3, +0x01, 0x5e, 0x24, 0x1a, +0x46, 0xc4, 0x00, 0x56, +0xc0, 0xa6, 0xc4, 0x00, +0x3b, 0xa4, 0x86, 0xc4, +0x00, 0x07, 0xa4, 0xa3, +0x81, 0x48, 0x6c, 0x40, +0x05, 0x24, 0x08, 0x25, +0x82, 0x0b, 0xc2, 0x89, +0x98, 0xe8, 0xa6, 0xc4, +0x00, 0x3b, 0xa0, 0xa6, +0x80, 0x00, 0xc0, 0x00, +0x02, 0x88, 0x34, 0x23, +0xb2, 0x43, 0x28, 0x20, +0xbc, 0x11, 0x03, 0x28, +0xa0, 0xbc, 0x0b, 0x12, +0x90, 0x36, 0x6c, 0x40, +0x03, 0xba, 0x4a, 0x68, +0x00, 0x00, 0x5d, 0x20, +0x66, 0x00, 0x00, 0x51, +0xc8, 0xb0, 0x00, 0xcb, +0xc1, 0x4f, 0x5c, 0x0a, +0x41, 0x8e, 0x8a, 0x40, +0x00, 0x03, 0xc1, 0x0f, +0x5c, 0x0a, 0x41, 0x8e, +0x8a, 0x68, 0x3f, 0xf3, +0xff, 0xc8, 0x54, 0x49, +0xa3, 0x01, 0x6e, 0x6c, +0x40, 0x05, 0x6c, 0x00, +0x52, 0x0d, 0x21, 0x8e, +0x8a, 0x6c, 0x40, 0x00, +0xc8, 0x50, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x5c, +0x0a, 0x43, 0x80, 0x00, +0x5c, 0x0a, 0x2b, 0x01, +0x82, 0x6c, 0x40, 0x05, +0x24, 0x08, 0x24, 0x96, +0x42, 0x48, 0x24, 0x52, +0x45, 0x23, 0x80, 0x00, +0x6e, 0x00, 0x01, 0x9a, +0x76, 0x6e, 0x00, 0x01, +0x9b, 0x76, 0x6c, 0x40, +0x05, 0x24, 0x48, 0x68, +0x00, 0x08, 0x69, 0xa0, +0x88, 0x03, 0x66, 0xc0, +0x00, 0x19, 0x86, 0x0b, +0xa1, 0x48, 0xa8, 0x01, +0x00, 0x00, 0x00, 0x6c, +0x00, 0x03, 0xd8, 0x08, +0x6c, 0x00, 0x03, 0xda, +0x48, 0x5c, 0x00, 0x73, +0xa1, 0x48, 0x6e, 0x00, +0x03, 0xdc, 0x66, 0x40, +0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x01, 0xea, +0x21, 0x58, 0x0b, 0x02, +0xc0, 0x22, 0x68, 0x00, +0x00, 0x45, 0x20, 0x5c, +0x83, 0xc0, 0x09, 0x02, +0x68, 0x00, 0x00, 0x49, +0xa2, 0x80, 0x14, 0x8b, +0x00, 0x09, 0x42, 0x04, +0x60, 0x48, 0x03, 0x5c, +0x8b, 0x88, 0x00, 0x49, +0x54, 0x07, 0x29, 0x52, +0xc1, 0x54, 0x05, 0x20, +0x50, 0xc9, 0xbc, 0x07, +0xf8, 0x50, 0x48, 0x98, +0xe8, 0x95, 0x70, 0x72, +0x95, 0x2c, 0x55, 0x70, +0x52, 0x05, 0x0c, 0x98, +0x50, 0x48, 0x68, 0x00, +0x00, 0x59, 0x21, 0x68, +0x00, 0x00, 0x5d, 0xa2, +0x58, 0x0f, 0x80, 0x09, +0x4a, 0x42, 0x04, 0x61, +0x8e, 0x88, 0x80, 0x84, +0xb5, 0x40, 0x7b, 0x95, +0x2c, 0x15, 0x40, 0x5b, +0x05, 0x0c, 0xbb, 0xc0, +0x8f, 0x40, 0x00, 0x00, +0x50, 0x4a, 0x57, 0x07, +0xb9, 0x52, 0xc4, 0x57, +0x05, 0xb0, 0x50, 0xcb, +0x40, 0x00, 0x00, 0x50, +0x4a, 0x59, 0x00, 0x02, +0xc0, 0x58, 0x6c, 0x00, +0x03, 0xda, 0x0a, 0x94, +0xa4, 0x19, 0x42, 0x41, +0x84, 0x84, 0xa8, 0x40, +0x4a, 0x00, 0x00, 0x04, +0x20, 0x54, 0x94, 0xca, +0xf5, 0xc0, 0x80, 0x14, +0x4a, 0xe2, 0x48, 0x3a, +0x6e, 0x00, 0x00, 0xba, +0xe2, 0x52, 0x41, 0x83, +0xa1, 0x48, 0x6e, 0x00, +0x00, 0x92, 0xe0, 0x00, +0x00, 0x02, 0x40, 0x3a, +0x6c, 0x40, 0x02, 0x06, +0x0b, 0x24, 0x03, 0x06, +0xc4, 0x00, 0x0c, 0x64, +0xb6, 0xe0, 0x00, 0x09, +0x2e, 0x06, 0xe0, 0x00, +0x0b, 0xae, 0x2b, 0xa1, +0x48, 0x6c, 0x40, 0x00, +0x78, 0x4b, 0x40, 0x00, +0x03, 0x80, 0x00, 0x5c, +0x08, 0x22, 0x02, 0x6a, +0x95, 0x02, 0xe5, 0x2c, +0x98, 0x2b, 0xff, 0x04, +0x21, 0x04, 0x88, 0x07, +0x68, 0x80, 0xe1, 0x5c, +0x08, 0x62, 0x02, 0x61, +0x94, 0x82, 0xe2, 0x59, +0x30, 0xbc, 0x1a, 0x1a, +0x02, 0x79, 0x94, 0x82, +0xc3, 0x20, 0x20, 0xbc, +0x16, 0x06, 0xe0, 0x00, +0x3d, 0xc2, 0x43, 0x20, +0x60, 0xbc, 0x0d, 0x03, +0x20, 0xa0, 0xbc, 0x05, +0x06, 0x60, 0x00, 0x23, +0x0a, 0x08, 0x80, 0xa0, +0xbc, 0x0c, 0xf8, 0x40, +0x48, 0x66, 0x00, 0x02, +0x35, 0x00, 0x88, 0x0a, +0x0b, 0xc0, 0x7f, 0x40, +0x00, 0x00, 0x40, 0x48, +0x66, 0x00, 0x02, 0x33, +0x60, 0x88, 0x0a, 0x00, +0x00, 0x00, 0x84, 0x04, +0x80, 0x00, 0x00, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x01, 0x00, 0x00, +0x00, 0x5c, 0x08, 0x22, +0x01, 0xe0, 0xa0, 0x02, +0x18, 0x40, 0x0a, 0x84, +0x84, 0xaa, 0x08, 0x78, +0x98, 0xe8, 0xa9, 0x40, +0x66, 0xa0, 0x41, 0x09, +0x40, 0x2e, 0x24, 0x93, +0x06, 0xc0, 0x00, 0x08, +0xa0, 0x85, 0x90, 0x10, +0x14, 0x06, 0x04, 0x20, +0x5c, 0xa0, 0x66, 0x89, +0x88, 0x08, 0x6c, 0x00, +0x00, 0xb2, 0x0a, 0x32, +0x03, 0x0b, 0xc0, 0x61, +0x6e, 0x00, 0x01, 0x2c, +0x2e, 0x38, 0x11, 0x52, +0x49, 0x70, 0x6e, 0x00, +0x01, 0x2c, 0x60, 0x68, +0x00, 0x00, 0x36, 0x0a, +0x30, 0x1a, 0x0b, 0xc0, +0x68, 0x6c, 0x40, 0x02, +0x08, 0x09, 0x40, 0x00, +0x03, 0xc0, 0x4f, 0x6c, +0x40, 0x00, 0xc6, 0x49, +0x6c, 0x40, 0x00, 0x78, +0x49, 0xba, 0x14, 0x8a, +0x02, 0x00, 0x40, 0x00, +0x00, 0x40, 0x08, 0xa0, +0x20, 0x1a, 0x08, 0x22, +0xa1, 0x05, 0x39, 0x58, +0x2c, 0x59, 0x01, 0x02, +0x1c, 0x93, 0x84, 0x80, +0x84, 0x20, 0x34, 0x05, +0x00, 0xa8, 0x58, 0x09, +0x57, 0x0d, 0x01, 0x82, +0x48, 0x42, 0x02, 0x79, +0x80, 0x09, 0x84, 0x84, +0x92, 0x81, 0xa0, 0x98, +0x00, 0x88, 0x48, 0x48, +0x30, 0x12, 0x8b, 0xc0, +0x45, 0xba, 0x14, 0x88, +0x48, 0x08, 0x40, 0x00, +0x03, 0x80, 0x00, 0x64, +0x00, 0x02, 0x30, 0xa7, +0xa0, 0x27, 0x1a, 0x0d, +0x72, 0xa1, 0x10, 0x39, +0x48, 0x28, 0x59, 0x00, +0x02, 0x1c, 0xe4, 0x85, +0x00, 0x08, 0x58, 0x02, +0x42, 0x03, 0x40, 0x60, +0x01, 0x55, 0x00, 0x9a, +0x21, 0x59, 0x55, 0x00, +0x11, 0x84, 0x80, 0x55, +0x00, 0x59, 0x84, 0x01, +0x94, 0x82, 0xc3, 0x20, +0x60, 0xbc, 0x0d, 0x9a, +0x02, 0x78, 0x30, 0x08, +0x0b, 0xc0, 0xbb, 0x39, +0x27, 0x86, 0xc0, 0x00, +0x3d, 0xa0, 0x05, 0xc8, +0x2c, 0xb0, 0x01, 0x25, +0x14, 0x22, 0x20, 0x00, +0x29, 0x52, 0xc2, 0x85, +0x04, 0x8b, 0xc0, 0x17, +0x39, 0x27, 0x89, 0x4a, +0x08, 0x32, 0x08, 0x0b, +0xc0, 0xa1, 0x30, 0x0c, +0x8b, 0xc0, 0x8c, 0x39, +0x05, 0x86, 0xc0, 0x00, +0x3d, 0xa0, 0x05, 0x14, +0x42, 0x30, 0x01, 0x89, +0x42, 0x40, 0x40, 0x00, +0x00, 0x40, 0x48, 0x64, +0x00, 0x02, 0x33, 0x6f, +0x40, 0x00, 0x02, 0x08, +0x00, 0xa2, 0x08, 0x4a, +0x20, 0x22, 0x84, 0x38, +0x98, 0x60, 0x0a, 0x57, +0x8b, 0xaa, 0xbf, 0xe0, +0xa1, 0x4a, 0x4a, 0x08, +0x00, 0x85, 0x00, 0x88, +0x80, 0x64, 0x88, 0x0e, +0x08, 0x81, 0x76, 0x66, +0x00, 0x00, 0x48, 0xa8, +0x2e, 0x96, 0x58, 0x80, +0x20, 0x88, 0x0a, 0x48, +0x41, 0x89, 0x44, 0x08, +0x00, 0x81, 0x36, 0x46, +0x0a, 0x41, 0x80, 0x08, +0x86, 0x14, 0x8a, 0x80, +0x20, 0x5c, 0x80, 0x81, +0x8e, 0x88, 0x5c, 0x01, +0xb3, 0xa1, 0x11, 0x38, +0x10, 0x52, 0xa0, 0x67, +0x1a, 0x2a, 0x65, 0xd0, +0xe2, 0x18, 0x32, 0x95, +0x80, 0xb0, 0x1c, 0x08, +0x19, 0x48, 0xbf, 0x94, +0x81, 0x89, 0x83, 0xa9, +0x94, 0x8b, 0x99, 0xc0, +0x81, 0x94, 0x8f, 0x74, +0x3f, 0x95, 0x14, 0x85, +0x09, 0x48, 0xf1, 0x76, +0x00, 0x00, 0x06, 0x00, +0x86, 0x00, 0x85, 0x16, +0x12, 0x06, 0x18, 0x05, +0x50, 0x23, 0x94, 0x0f, +0x4a, 0x20, 0x21, 0x84, +0x80, 0xa6, 0x80, 0x03, +0xff, 0xfc, 0x85, 0x80, +0x9c, 0x20, 0x84, 0x15, +0x16, 0x1b, 0x14, 0x05, +0x04, 0x20, 0x16, 0x84, +0x84, 0xb9, 0x40, 0xf6, +0x86, 0x1f, 0xa3, 0x81, +0x66, 0x84, 0x88, 0x82, +0x59, 0xa0, 0xbc, 0x0f, +0x15, 0xc0, 0x86, 0x22, +0x05, 0x89, 0x40, 0x2e, +0x55, 0x03, 0xbb, 0x01, +0x0e, 0x3a, 0x1c, 0x73, +0x01, 0x38, 0xbc, 0x02, +0xd9, 0x40, 0x67, 0x96, +0x5e, 0x60, 0x00, 0x00, +0x42, 0x07, 0xf9, 0x42, +0x0c, 0x40, 0x00, 0x01, +0x40, 0x64, 0x5c, 0x08, +0x62, 0x20, 0x50, 0x94, +0x02, 0xe5, 0x50, 0x3b, +0xb0, 0x10, 0xe3, 0xa1, +0xc7, 0x30, 0x13, 0x8b, +0xc0, 0x2d, 0x94, 0x06, +0x79, 0x65, 0x66, 0xa0, +0x40, 0x89, 0x65, 0x2c, +0x94, 0x06, 0x4b, 0xa1, +0x48, 0xba, 0x10, 0x10, +0x00, 0x00, 0x60, 0x00, +0x30, 0x00, 0x13, 0x39, +0x02, 0x00, 0x00, 0x00, +0x82, 0x07, 0xa3, 0x81, +0x84, 0x6c, 0x40, 0x04, +0x02, 0x0a, 0x25, 0x93, +0x0b, 0xc1, 0x00, 0x38, +0x1c, 0x42, 0x59, 0x30, +0xbc, 0x19, 0x16, 0x82, +0x00, 0x26, 0x6a, 0x46, +0x80, 0x01, 0xdd, 0xdc, +0x83, 0x90, 0x10, 0x96, +0x05, 0x49, 0x60, 0x74, +0x68, 0x00, 0x1d, 0xc0, +0x08, 0xba, 0x14, 0x89, +0x60, 0xf4, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x20, 0x02, 0x33, 0xa4, +0x68, 0x00, 0x1d, 0xdd, +0xc8, 0x39, 0x01, 0x09, +0x60, 0x54, 0x96, 0x07, +0x46, 0x80, 0x01, 0xdc, +0x00, 0x8b, 0xa1, 0x48, +0x96, 0x0f, 0x40, 0x00, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0xab, 0xff, +0x08, 0x80, 0x76, 0x66, +0x00, 0x02, 0x43, 0xa0, +0x40, 0x00, 0x03, 0x00, +0x0c, 0x6e, 0x00, 0x00, +0x92, 0x64, 0x6e, 0x00, +0x00, 0xba, 0x64, 0x66, +0x00, 0x01, 0xf0, 0x20, +0x5c, 0x00, 0x73, 0x03, +0x0c, 0x88, 0x03, 0x66, +0xe0, 0x00, 0x12, 0xc6, +0x4b, 0xa1, 0x48, 0x6c, +0x40, 0x05, 0x1a, 0x4a, +0x40, 0x00, 0x02, 0x80, +0x10, 0x5c, 0x81, 0x01, +0x8e, 0x8a, 0x68, 0x00, +0x00, 0x0e, 0x20, 0x38, +0x0a, 0x42, 0xa0, 0x76, +0x3a, 0x18, 0x63, 0x01, +0x30, 0xbf, 0xfc, 0xa8, +0x00, 0x7a, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x5c, +0x81, 0x01, 0x8e, 0x8a, +0x68, 0x00, 0x00, 0x22, +0x20, 0x38, 0x0a, 0x42, +0xa0, 0x76, 0x3a, 0x18, +0x63, 0x01, 0x30, 0xbf, +0xfc, 0xa8, 0x00, 0x7a, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x68, 0x00, 0x00, +0x36, 0x20, 0x5c, 0x81, +0x02, 0xbf, 0xf0, 0x68, +0x00, 0x00, 0x4a, 0x21, +0x88, 0x07, 0x69, 0x8e, +0x88, 0x40, 0x00, 0x02, +0x00, 0x02, 0x55, 0x03, +0x20, 0x08, 0x7a, 0x3a, +0x10, 0x43, 0x22, 0x20, +0xbf, 0xfb, 0xa8, 0x10, +0x7a, 0x40, 0x00, 0x02, +0x01, 0x80, 0x66, 0x00, +0x00, 0x46, 0xa8, 0x5c, +0x00, 0x62, 0x04, 0x21, +0x68, 0x00, 0x00, 0x4a, +0x20, 0x88, 0x03, 0x6a, +0x80, 0x10, 0x40, 0x00, +0x02, 0x01, 0x80, 0x64, +0x00, 0x00, 0x46, 0xaf, +0x5c, 0x00, 0x62, 0x04, +0x21, 0x55, 0x01, 0x40, +0x60, 0x0b, 0x5c, 0x82, +0x0a, 0x20, 0x26, 0x5c, +0x81, 0x00, 0xc0, 0x2a, +0x44, 0x18, 0x82, 0x30, +0x27, 0x87, 0x00, 0x84, +0x44, 0x4a, 0x07, 0x80, +0x84, 0x42, 0x4a, 0x23, +0x82, 0x49, 0x80, 0x42, +0x8c, 0x0c, 0x0a, 0x20, +0x26, 0x86, 0x00, 0xb8, +0xc0, 0x2a, 0x44, 0x18, +0x82, 0x30, 0x27, 0x55, +0x00, 0xa0, 0x70, 0x0b, +0x44, 0x5d, 0x20, 0x78, +0x0a, 0x44, 0x15, 0x40, +0x48, 0x0b, 0x55, 0x01, +0x09, 0x80, 0x8a, 0x57, +0x8f, 0xb0, 0x50, 0x08, +0x57, 0x49, 0x92, 0x38, +0x24, 0x8c, 0x0c, 0x4a, +0x20, 0x22, 0x86, 0x00, +0xa8, 0xc0, 0x2b, 0x44, +0x10, 0x82, 0x10, 0x21, +0x85, 0x00, 0x84, 0x46, +0x4a, 0x04, 0x80, 0x84, +0x42, 0x4a, 0x20, 0x82, +0x49, 0x80, 0x43, 0x8c, +0x0c, 0x1a, 0x20, 0x22, +0x86, 0x00, 0xb8, 0xc0, +0x2a, 0x44, 0x18, 0x00, +0x50, 0x0b, 0x55, 0x00, +0xa2, 0x10, 0x21, 0x44, +0x5c, 0x01, 0x84, 0xca, +0x84, 0x80, 0xb4, 0x45, +0xc8, 0x20, 0x88, 0x25, +0x50, 0x18, 0x18, 0x04, +0x2a, 0x10, 0x21, 0x8c, +0x06, 0x0a, 0x28, 0x08, +0x80, 0x80, 0xa4, 0x41, +0x08, 0x05, 0x00, 0xa4, +0x43, 0x00, 0x16, 0x82, +0x55, 0x00, 0xa0, 0x20, +0x00, 0xd5, 0x50, 0x0a, +0x04, 0x80, 0x94, 0x40, +0x90, 0x14, 0x02, 0x55, +0x00, 0xa4, 0x96, 0x82, +0x45, 0x00, 0x89, 0x20, +0x82, 0x28, 0x10, 0x09, +0x98, 0x00, 0x84, 0x40, +0x80, 0x01, 0x00, 0x89, +0xa1, 0x02, 0x44, 0x24, +0x00, 0x10, 0x09, 0x44, +0x4c, 0x00, 0x80, 0x20, +0x85, 0x80, 0x99, 0x80, +0x08, 0x57, 0x8b, 0x28, +0x40, 0x08, 0x57, 0x49, +0x68, 0x50, 0x08, 0x44, +0x20, 0x01, 0x68, 0xa5, +0x50, 0x0a, 0x00, 0x50, +0x89, 0x46, 0x0a, 0x41, +0x80, 0x08, 0x08, 0x10, +0x09, 0x80, 0x08, 0x5c, +0x81, 0x00, 0xc0, 0x2a, +0x82, 0x00, 0xb4, 0x41, +0x80, 0x02, 0x00, 0x84, +0x44, 0x40, 0x06, 0x00, +0x84, 0x42, 0x50, 0x18, +0x24, 0x04, 0x60, 0xa4, +0x18, 0x08, 0x28, 0xc0, +0x60, 0x55, 0x00, 0xa3, +0x80, 0x00, 0x5c, 0x82, +0x09, 0x8e, 0x82, 0x5c, +0x81, 0x00, 0xc0, 0x8a, +0x55, 0x00, 0x98, 0x20, +0x0b, 0x44, 0x1d, 0xe0, +0x20, 0x08, 0x55, 0x00, +0x80, 0x20, 0x0b, 0x44, +0x44, 0x00, 0xc0, 0x8a, +0x44, 0x1d, 0xe0, 0x20, +0x08, 0x44, 0x44, 0x00, +0x20, 0x08, 0x44, 0x25, +0xe1, 0x68, 0x24, 0x54, +0x00, 0xda, 0x04, 0x80, +0x50, 0x08, 0xd8, 0xc0, +0x30, 0x55, 0x01, 0x48, +0xc1, 0x78, 0x5c, 0x00, +0x01, 0x80, 0xc3, 0x8c, +0x06, 0x5a, 0x00, 0x80, +0x8c, 0x08, 0xe8, 0x20, +0x08, 0x44, 0x25, 0x40, +0x20, 0x09, 0x44, 0x4c, +0x00, 0xc0, 0x8e, 0x82, +0x00, 0x84, 0x42, 0x54, +0x02, 0x00, 0x94, 0x44, +0xc0, 0x18, 0x4c, 0x98, +0x60, 0x08, 0x44, 0x25, +0x41, 0x68, 0xa5, 0x54, +0x00, 0x92, 0x04, 0x85, +0x50, 0x0a, 0x90, 0xe8, +0x30, 0x55, 0x00, 0xc0, +0xe9, 0x78, 0x98, 0x08, +0x28, 0x50, 0x08, 0x46, +0x0a, 0x40, 0x48, 0x09, +0x57, 0x8a, 0xa8, 0xe8, +0x60, 0x57, 0x49, 0x63, +0x80, 0x00, 0x85, 0x08, +0x85, 0x90, 0x10, 0x2b, +0xfc, 0x04, 0x24, 0x4c, +0x08, 0x07, 0x65, 0xc8, +0x10, 0x08, 0x0e, 0x2a, +0x10, 0x43, 0xa1, 0x90, +0x68, 0xc0, 0x2a, 0x82, +0x00, 0x94, 0x40, 0x90, +0x07, 0x02, 0x78, 0x20, +0x08, 0x44, 0x45, 0x40, +0x78, 0x08, 0x55, 0x01, +0x00, 0x20, 0x0a, 0x44, +0x15, 0x40, 0x20, 0x09, +0x98, 0x08, 0x25, 0x50, +0x0b, 0x8c, 0x06, 0x05, +0x50, 0x08, 0x23, 0x14, +0x78, 0xc1, 0x2a, 0x44, +0x09, 0x80, 0x60, 0x08, +0x44, 0x45, 0x60, 0x60, +0x89, 0x44, 0x6d, 0x40, +0x28, 0x09, 0x98, 0x08, +0x28, 0xc1, 0x60, 0xa1, +0x18, 0x08, 0xc8, 0x2a, +0x44, 0x09, 0x80, 0x75, +0x22, 0x82, 0x80, 0x84, +0x44, 0x5e, 0x05, 0x00, +0xa5, 0x50, 0x18, 0x02, +0x80, 0x84, 0x44, 0x5e, +0x02, 0x80, 0x99, 0x80, +0xc3, 0x55, 0x00, 0xc0, +0xc8, 0x61, 0x88, 0x1d, +0x2a, 0x3e, 0x82, 0x8c, +0x92, 0xa4, 0x40, 0x90, +0x06, 0x80, 0x84, 0x44, +0x54, 0x06, 0x88, 0xa5, +0x50, 0x0e, 0x08, 0x16, +0x04, 0x41, 0x54, 0x08, +0x2e, 0x39, 0x80, 0x82, +0x8c, 0x96, 0x08, 0x83, +0x52, 0x88, 0x26, 0x26, +0x80, 0x00, 0x0c, 0x92, +0x06, 0x60, 0x00, 0x05, +0x2e, 0x03, 0x20, 0x20, +0xbc, 0x05, 0x88, 0x82, +0x21, 0x88, 0x03, 0x6b, +0xa1, 0x48, 0xa8, 0x04, +0x00, 0x00, 0x00, 0x88, +0x0a, 0x58, 0x48, 0x08, +0x55, 0x03, 0x20, 0x48, +0x82, 0x58, 0x05, 0x00, +0x48, 0x48, 0xbc, 0x39, +0xc8, 0x81, 0x88, 0x86, +0x90, 0x25, 0x80, 0x88, +0x08, 0x2a, 0x0b, 0xc0, +0x13, 0x86, 0x94, 0x8a, +0x00, 0x21, 0x84, 0x80, +0x23, 0x01, 0x10, 0xbc, +0x01, 0x58, 0x40, 0xc8, +0x5c, 0x08, 0x1a, 0xc0, +0x21, 0x5c, 0x82, 0x00, +0x08, 0x8a, 0x5b, 0x48, +0x10, 0xc9, 0x30, 0x50, +0x47, 0x08, 0x69, 0x08, +0x57, 0x0d, 0x20, 0x83, +0x0a, 0x54, 0x02, 0x00, +0x08, 0x48, 0x50, 0x46, +0x92, 0x08, 0x00, 0x8c, +0x85, 0x8a, 0x08, 0x82, +0xa1, 0x00, 0x48, 0x10, +0x88, 0x58, 0x0d, 0x00, +0xc1, 0x30, 0x54, 0x04, +0x13, 0xc0, 0x2b, 0x8c, +0x17, 0xa8, 0x6e, 0x4a, +0x00, 0x00, 0x08, 0x60, +0x88, 0x58, 0x0d, 0x00, +0x81, 0x25, 0xbc, 0x01, +0x58, 0x68, 0xca, 0x36, +0x98, 0x25, 0x04, 0x69, +0x04, 0xa0, 0x15, 0x04, +0x78, 0x01, 0x08, 0x85, +0x70, 0x86, 0x21, 0x00, +0x18, 0xd1, 0x31, 0x54, +0x00, 0x58, 0x10, 0x48, +0x8c, 0x97, 0xb0, 0x00, +0x00, 0x8d, 0x13, 0x05, +0x40, 0x41, 0x3c, 0x05, +0xf8, 0xd1, 0x7a, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0x86, 0x8f, 0xaa, 0x80, +0x40, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x40, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5c, 0x81, 0x03, 0x01, +0x6b, 0x68, 0x20, 0x01, +0x1b, 0x20, 0x68, 0x20, +0x00, 0xf5, 0x21, 0x5c, +0x00, 0x38, 0x02, 0x0a, +0x51, 0x89, 0x80, 0x40, +0x0a, 0x51, 0x8a, 0x00, +0x08, 0x50, 0x68, 0x20, +0x02, 0x99, 0x20, 0x5c, +0x00, 0x60, 0x48, 0x02, +0x80, 0x05, 0x28, 0x00, +0x7a, 0x68, 0x20, 0x00, +0xec, 0x21, 0x80, 0x07, +0xa8, 0x40, 0x7a, 0xa0, +0x04, 0x08, 0x48, 0x02, +0x80, 0x25, 0x26, 0x80, +0x00, 0x0c, 0xe2, 0x28, +0x48, 0x89, 0xa0, 0x06, +0x18, 0x40, 0x49, 0x80, +0xa5, 0x26, 0x80, 0x00, +0x09, 0x82, 0x06, 0xc4, +0x00, 0x1b, 0x00, 0x18, +0x50, 0x53, 0xa0, 0x86, +0x4e, 0x01, 0x04, 0xa1, +0x06, 0x28, 0x40, 0x7a, +0x95, 0x24, 0x7a, 0xbf, +0xf0, 0x68, 0x00, 0x01, +0x91, 0x20, 0x88, 0x07, +0x68, 0x60, 0x49, 0x84, +0x84, 0x96, 0xc4, 0x00, +0x10, 0x84, 0xa6, 0xc4, +0x00, 0x10, 0x64, 0xa8, +0x50, 0x7a, 0x6c, 0x40, +0x01, 0x9a, 0x51, 0x6c, +0x40, 0x01, 0x98, 0x51, +0x6c, 0x00, 0x03, 0x86, +0x48, 0x6c, 0x00, 0x03, +0xa0, 0x48, 0x6c, 0x40, +0x01, 0x8a, 0x7a, 0x6c, +0x40, 0x01, 0x5a, 0x7a, +0x6c, 0x40, 0x02, 0xf8, +0x51, 0x6c, 0x40, 0x02, +0xf2, 0x51, 0x66, 0x00, +0x00, 0x52, 0x80, 0x68, +0x00, 0x01, 0x91, 0x21, +0x88, 0x03, 0x68, 0x49, +0x08, 0x51, 0xc5, 0x22, +0x80, 0x10, 0x84, 0x94, +0x8a, 0x08, 0x00, 0x64, +0x00, 0x00, 0x54, 0x2f, +0x40, 0x00, 0x03, 0x09, +0x64, 0x30, 0x1a, 0x8b, +0xc1, 0x30, 0x84, 0x00, +0x83, 0x69, 0x04, 0x6c, +0x40, 0x02, 0xc8, 0x0b, +0x30, 0x9e, 0x0b, 0xc0, +0xc4, 0x6c, 0x40, 0x01, +0xea, 0x08, 0x6c, 0x40, +0x02, 0x36, 0x0b, 0x30, +0x1e, 0x0b, 0xc0, 0x61, +0x6c, 0x40, 0x02, 0xc6, +0x08, 0x28, 0x13, 0x04, +0x20, 0x17, 0x98, 0x00, +0xa2, 0xf1, 0x75, 0x98, +0x28, 0x9b, 0xa1, 0x48, +0x98, 0x24, 0x80, 0x00, +0x00, 0x68, 0x00, 0x00, +0xcf, 0x22, 0x6c, 0x00, +0x01, 0x9c, 0x08, 0x85, +0x00, 0xa3, 0x01, 0x30, +0xbc, 0x4f, 0x19, 0x54, +0x24, 0x6c, 0x00, 0x01, +0x9e, 0x7a, 0x32, 0x06, +0x06, 0xc4, 0x00, 0x1e, +0x80, 0xa5, 0xb4, 0xc3, +0x04, 0x00, 0x8b, 0xc2, +0x39, 0x36, 0x90, 0x43, +0x09, 0xa0, 0xbc, 0x09, +0x48, 0x48, 0x08, 0x36, +0x90, 0x43, 0x09, 0xa0, +0xbc, 0x05, 0x4b, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0xa0, 0x7a, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x01, 0xa0, 0x08, +0x6c, 0x40, 0x01, 0xe6, +0x0a, 0x2a, 0x06, 0x43, +0x01, 0xa0, 0xbc, 0x38, +0x96, 0xc0, 0x00, 0x1a, +0x04, 0x85, 0xc0, 0xb8, +0x18, 0xe8, 0xa6, 0xc4, +0x00, 0x3b, 0xa0, 0x85, +0x24, 0x12, 0x2c, 0x02, +0x06, 0x80, 0x00, 0x0d, +0x12, 0x16, 0xc4, 0x00, +0x3b, 0xa4, 0x84, 0x60, +0xa4, 0x14, 0xa4, 0x68, +0x48, 0x7a, 0x00, 0x00, +0x03, 0x09, 0xa0, 0xbc, +0x04, 0x38, 0x48, 0x08, +0x36, 0x90, 0x43, 0x09, +0xa0, 0xbc, 0x05, 0x2b, +0xa1, 0x48, 0x6c, 0x00, +0x01, 0xa0, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0xa0, +0x08, 0x6c, 0x40, 0x01, +0xe4, 0x0a, 0x2a, 0x06, +0x43, 0x01, 0xa0, 0xbc, +0x16, 0x96, 0xc0, 0x00, +0x1a, 0x04, 0x85, 0xc0, +0xb8, 0x30, 0x00, 0xe6, +0xc4, 0x00, 0x3b, 0xa0, +0x85, 0x20, 0x12, 0x2c, +0x02, 0x06, 0x80, 0x00, +0x0d, 0x12, 0x16, 0xc4, +0x00, 0x3b, 0xa4, 0x84, +0x60, 0xa4, 0x14, 0xa4, +0x68, 0x48, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x55, 0x03, 0xa3, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0x9e, 0x48, 0x00, 0x00, +0x0b, 0xa1, 0x40, 0x85, +0x00, 0x88, 0x40, 0x0a, +0x30, 0x1a, 0x0b, 0xc1, +0x50, 0x30, 0x13, 0x0b, +0xc0, 0xbd, 0x84, 0x80, +0x82, 0xe1, 0x30, 0x98, +0x00, 0x88, 0x40, 0x48, +0x00, 0x00, 0x08, 0x50, +0x0a, 0x30, 0x1a, 0x0b, +0xc0, 0xb4, 0xba, 0x14, +0x88, 0x40, 0x4a, 0x00, +0x00, 0x02, 0x81, 0x30, +0x98, 0x00, 0x88, 0x40, +0x48, 0x00, 0x00, 0x08, +0x50, 0x0a, 0x30, 0x1a, +0x0b, 0xc0, 0x12, 0x84, +0x04, 0xab, 0xa1, 0x40, +0x68, 0x20, 0x01, 0x21, +0x21, 0x68, 0x00, 0x00, +0xbf, 0x22, 0x39, 0x02, +0x08, 0x08, 0x08, 0x81, +0x07, 0xa8, 0x10, 0x48, +0x68, 0x00, 0x00, 0xc4, +0x20, 0x84, 0x80, 0x88, +0x00, 0x7a, 0x81, 0x04, +0x88, 0x00, 0x7a, 0x68, +0x00, 0x00, 0xbc, 0x23, +0x80, 0x04, 0x86, 0x80, +0x00, 0x9a, 0x5a, 0xca, +0x10, 0x01, 0x81, 0x86, +0xc8, 0x10, 0x7a, 0xa0, +0x00, 0x48, 0x58, 0x7a, +0x85, 0x06, 0x14, 0x60, +0xa4, 0x00, 0x07, 0xa8, +0x40, 0x64, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x01, 0x7a, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0c, 0x16, +0xc0, 0x00, 0x18, 0x62, +0x06, 0x80, 0x00, 0x9a, +0xa2, 0xc6, 0xc0, 0x00, +0x19, 0x02, 0x16, 0xc0, +0x00, 0x17, 0x86, 0xc4, +0x60, 0xa4, 0x04, 0x07, +0xa8, 0x48, 0x7a, 0x00, +0x00, 0x0b, 0xa1, 0x40, +0x6c, 0x00, 0x01, 0x7a, +0x08, 0x38, 0x10, 0x62, +0x59, 0xa0, 0xbc, 0x0c, +0x8a, 0xbf, 0xf0, 0x6c, +0x00, 0x01, 0x86, 0x20, +0x68, 0x00, 0x09, 0xa5, +0xac, 0x6c, 0x00, 0x01, +0x90, 0x21, 0x6c, 0x00, +0x01, 0x78, 0x6c, 0x42, +0x09, 0xf8, 0x40, 0x7a, +0x84, 0x87, 0xa8, 0x80, +0x76, 0x66, 0x00, 0x02, +0x6e, 0x20, 0x6c, 0x00, +0x01, 0x8e, 0x08, 0x32, +0x02, 0x0b, 0xc0, 0x65, +0x6c, 0x00, 0x01, 0x90, +0x20, 0x42, 0x03, 0xf8, +0x80, 0x36, 0x40, 0x00, +0x00, 0x40, 0x7a, 0x68, +0x00, 0x09, 0xb3, 0xa0, +0x88, 0x03, 0x66, 0xc0, +0x00, 0x17, 0x86, 0x0b, +0xa1, 0x48, 0xa8, 0x01, +0x00, 0x00, 0x00, 0x6c, +0x00, 0x01, 0x7a, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0d, 0x06, +0xc0, 0x00, 0x18, 0x62, +0x06, 0x80, 0x00, 0x9a, +0x5a, 0xc6, 0xc0, 0x00, +0x19, 0x02, 0x16, 0xc0, +0x00, 0x17, 0x86, 0xc4, +0x60, 0xa4, 0x04, 0x07, +0xa8, 0x48, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x64, 0x00, 0x02, 0x6e, +0x27, 0x68, 0x00, 0x00, +0xc0, 0x20, 0x68, 0x20, +0x01, 0x23, 0x21, 0xab, +0xfe, 0x08, 0x40, 0x08, +0x84, 0x80, 0x94, 0x40, +0x80, 0x08, 0x07, 0x66, +0x60, 0x00, 0x27, 0x22, +0x89, 0x80, 0x09, 0x5c, +0x81, 0x00, 0x80, 0xc8, +0x68, 0x20, 0x01, 0x23, +0x20, 0x68, 0x00, 0x00, +0xc5, 0x21, 0x80, 0x00, +0x88, 0x48, 0x09, 0x44, +0x20, 0x00, 0x81, 0x60, +0x66, 0x00, 0x02, 0x72, +0x28, 0x40, 0x00, 0x01, +0x80, 0x09, 0x5c, 0x81, +0x00, 0x81, 0x20, 0x6c, +0x00, 0x01, 0x80, 0x09, +0x84, 0x00, 0x06, 0xc0, +0x00, 0x17, 0xe0, 0xa5, +0x40, 0xd6, 0x88, 0x03, +0x66, 0x80, 0x00, 0x0c, +0x02, 0x05, 0x44, 0x17, +0x08, 0x08, 0x96, 0xc0, +0x00, 0x18, 0xa0, 0xb6, +0xc0, 0x00, 0x18, 0x80, +0x25, 0x40, 0x5f, 0x80, +0x04, 0xa5, 0x44, 0x1f, +0xa0, 0x00, 0x28, 0x00, +0x0a, 0x68, 0x00, 0x00, +0xc5, 0x21, 0x44, 0x30, +0x00, 0x40, 0xa0, 0x80, +0x84, 0xb8, 0x50, 0xc0, +0x84, 0x04, 0x0a, 0x08, +0x00, 0x80, 0x80, 0x94, +0x40, 0x80, 0x04, 0x8a, +0x14, 0x60, 0xa4, 0x04, +0x0c, 0x08, 0x48, 0x40, +0x40, 0x00, 0x02, 0x80, +0x20, 0x44, 0x29, 0x02, +0xc0, 0x20, 0x68, 0x20, +0x01, 0x25, 0x20, 0x51, +0x48, 0x9b, 0x3f, 0xc4, +0x80, 0x00, 0x29, 0x80, +0xc9, 0x44, 0x0d, 0xc0, +0x00, 0x02, 0x98, 0x0c, +0x84, 0x40, 0xdc, 0x00, +0x00, 0x29, 0x80, 0xc8, +0x44, 0x0d, 0xc0, 0x00, +0x02, 0x98, 0x0c, 0x84, +0x40, 0xdc, 0x00, 0x00, +0x29, 0x80, 0xc8, 0x44, +0x0d, 0x40, 0x00, 0x03, +0x98, 0x08, 0x84, 0x40, +0x90, 0x04, 0x00, 0x85, +0x14, 0x69, 0x18, 0x08, +0xa2, 0xe0, 0x9a, 0x55, +0x00, 0xd1, 0x80, 0x89, +0x1a, 0x0d, 0x99, 0xa0, +0x42, 0x08, 0x63, 0x02, +0x20, 0xdb, 0x57, 0x06, +0x99, 0x80, 0xc9, 0x98, +0x0c, 0xa0, 0x86, 0x30, +0x22, 0x0d, 0xb5, 0x70, +0x69, 0x98, 0x0c, 0x99, +0x80, 0xca, 0x08, 0x63, +0x02, 0x20, 0xdb, 0x57, +0x06, 0x91, 0x80, 0xc9, +0x98, 0x08, 0xa0, 0x86, +0x20, 0x22, 0x0d, 0x25, +0x70, 0x51, 0x3a, 0x14, +0x82, 0x20, 0x92, 0x40, +0x00, 0x01, 0x80, 0x88, +0x37, 0x08, 0x63, 0x70, +0x44, 0x2e, 0x13, 0x42, +0xa0, 0x64, 0x32, 0x02, +0x0b, 0xc1, 0x55, 0x38, +0x20, 0x63, 0x01, 0xa0, +0xbc, 0x0e, 0x06, 0x20, +0x00, 0x00, 0x01, 0x45, +0x00, 0x88, 0x18, 0xeb, +0x50, 0x00, 0x00, 0x2f, +0x80, 0x9b, 0xc0, 0x13, +0x28, 0x00, 0x92, 0x09, +0x08, 0x57, 0x09, 0xa3, +0xa1, 0x48, 0x20, 0x10, +0x95, 0x0c, 0x84, 0x19, +0x20, 0x3b, 0xa1, 0x48, +0x5b, 0xc2, 0x01, 0x8e, +0x83, 0x00, 0x00, 0x0b, +0xa1, 0x48, 0x55, 0x00, +0x59, 0x8e, 0x80, 0x40, +0x00, 0x03, 0x80, 0x00, +0x00, 0x00, 0x00, 0x06, +0x00, 0x00, 0x40, 0x00, +0x38, 0x74, 0x00, 0x00, +0xe6, 0x18, 0xc5, 0x03, +0x6f, 0x1a, 0x00, 0x00, +0x01, 0x9d, 0x13, 0x00, +0xff, 0xff, 0x0f, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xe3, 0xb4, 0x46, 0x02, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x33, 0x46, 0x45, 0x87, +0x2f, 0x4d, 0x17, 0x72, +0x61, 0x93, 0x5c, 0x79, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xd3, 0x35, 0xc3, 0x50, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x38, +0xff, 0xff, 0xff, 0x7f, +0xc1, 0x0d, 0x40, 0x0a, +0x7d, 0xe4, 0x7f, 0x6b, +0xc1, 0x0d, 0x40, 0x0a, +0xd3, 0xed, 0xe0, 0x98, +0x2b, 0x12, 0x1f, 0x67, +0x11, 0xfc, 0x2f, 0x2f, +0x99, 0xfd, 0xaf, 0xd3, +0x55, 0x06, 0x20, 0x3d, +0x43, 0x0b, 0xed, 0xbd, +0xbd, 0xf4, 0x12, 0x42, +0xdb, 0x73, 0x4f, 0x1f, +0x9e, 0xf4, 0x40, 0xf4, +0x85, 0x97, 0x6f, 0x2c, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xe3, 0xb4, 0x46, 0x02, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x33, 0x46, 0x45, 0x87, +0x2f, 0x4d, 0x17, 0x72, +0x61, 0x93, 0x5c, 0x79, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xd3, 0x35, 0xc3, 0x50, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x38, +0xff, 0xff, 0xff, 0x7f, +0xc1, 0x0d, 0x40, 0x0a, +0x7d, 0xe4, 0x7f, 0x6b, +0xc1, 0x0d, 0x40, 0x0a, +0xd3, 0xed, 0xe0, 0x98, +0x2b, 0x12, 0x1f, 0x67, +0x11, 0xfc, 0x2f, 0x2f, +0x99, 0xfd, 0xaf, 0xd3, +0x55, 0x06, 0x20, 0x3d, +0x43, 0x0b, 0xed, 0xbd, +0xbd, 0xf4, 0x12, 0x42, +0xdb, 0x73, 0x4f, 0x1f, +0x9e, 0xf4, 0x40, 0xf4, +0x85, 0x97, 0x6f, 0x2c, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x04, 0x03, +0x01, 0x01, 0x00, 0x00, +0x04, 0x03, 0x01, 0x01, +0x00, 0x00, 0x20, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0x07, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x3b, 0xcb, 0x88, 0x3e, +0xa7, 0xa2, 0x9b, 0xc4, +0x41, 0x2d, 0x55, 0x6f, +0x95, 0x18, 0xab, 0x3d, +0xb0, 0x45, 0xb2, 0xaa, +0x93, 0xdf, 0xf6, 0x7f, +0xbd, 0xda, 0x56, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x7f, +0x39, 0x61, 0xdc, 0x0c, +0xc3, 0x9e, 0xe2, 0x00, +0x79, 0xc2, 0x3a, 0x7e, +0xc3, 0x9e, 0xe2, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xb7, 0x63, 0x68, 0x43, +0x4d, 0xdb, 0x1e, 0x16, +0x65, 0x49, 0xc2, 0x53, +0x4d, 0xdb, 0x1e, 0x16, +0xf5, 0xff, 0xff, 0x3f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x3b, 0xcb, 0x88, 0x3e, +0xa7, 0xa2, 0x9b, 0xc4, +0x41, 0x2d, 0x55, 0x6f, +0x95, 0x18, 0xab, 0x3d, +0xb0, 0x45, 0xb2, 0xaa, +0x93, 0xdf, 0xf6, 0x7f, +0xbd, 0xda, 0x56, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x7f, +0x39, 0x61, 0xdc, 0x0c, +0xc3, 0x9e, 0xe2, 0x00, +0x79, 0xc2, 0x3a, 0x7e, +0xc3, 0x9e, 0xe2, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xb7, 0x63, 0x68, 0x43, +0x4d, 0xdb, 0x1e, 0x16, +0x65, 0x49, 0xc2, 0x53, +0x4d, 0xdb, 0x1e, 0x16, +0xf5, 0xff, 0xff, 0x3f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x01, 0x02, 0x00, 0x01, +0x01, 0x02, 0x00, 0x01, +0x37, 0xb4, 0x05, 0x00, +0x91, 0x97, 0xf4, 0x7f, +0x37, 0xb4, 0x05, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x20, +0x00, 0x00, 0x00, 0x2a, +0xaf, 0xb1, 0xa7, 0x0c, +0x91, 0x49, 0xc0, 0x0b, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x9c, 0xc5, 0x5f, 0x1c, +0x9c, 0xc5, 0x5f, 0x1c, +0x3c, 0x00, 0x00, 0x00, +0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x04, 0x00, +0x80, 0x00, 0x00, 0x00, +0x00, 0x00, 0x42, 0x00, +0x00, 0x00, 0x04, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0xaf, 0x00, +0x00, 0x00, 0x10, 0x00, +0x00, 0x00, 0x00, 0x02, +0xd0, 0x08, 0x00, 0x00, +0x68, 0x04, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x28, 0x00, +0x00, 0x00, 0x30, 0x00, +0x00, 0x80, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, +0x00, 0x00, 0x00, 0x28, +0x00, 0x00, 0x00, 0x38, +0x00, 0x00, 0x04, 0x00, +0x00, 0x00, 0x40, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x8a, 0x69, 0x03, 0x00, +0x57, 0x9a, 0x91, 0x24, +0x1b, 0x58, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x14, 0x01, 0x00, 0x00, +0x62, 0x6c, 0x02, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, +0xcf, 0x08, 0x00, 0x00, +0x8c, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x60, 0x18, 0x86, 0x61, +0x30, 0x0a, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xb0, 0x01, +0x00, 0x00, 0x60, 0x02, +0xc6, 0xe3, 0xc4, 0x00, +0xc6, 0xe3, 0xc4, 0x00, +0x00, 0x00, 0x00, 0x60, +0x00, 0x00, 0x00, 0x00, +0x4a, 0xed, 0x87, 0x64, +0xff, 0xff, 0xff, 0x7f, +0xa0, 0x04, 0x00, 0x00, +0xe7, 0x5f, 0xfe, 0xff, +0xb0, 0x05, 0x5b, 0x00, +0x56, 0x55, 0x55, 0xf5, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x40, +0xff, 0xff, 0xff, 0x1f, +0xdf, 0x59, 0x37, 0x5f, +0xff, 0xff, 0xff, 0x5f, +0x0b, 0xb9, 0x58, 0x00, +0x00, 0x00, 0x00, 0x10, +0xaa, 0xaa, 0xaa, 0x2a, +0x99, 0x99, 0x99, 0x19, +0x92, 0x24, 0x49, 0x12, +0x8e, 0xe3, 0x38, 0x0e, +0xba, 0xe8, 0xa2, 0x0b, +0x89, 0x9d, 0xd8, 0x09, +0x88, 0x88, 0x88, 0x08, +0x87, 0x87, 0x87, 0x07, +0x29, 0xf6, 0x96, 0x37, +0xaa, 0xaa, 0xaa, 0x2a, +0x99, 0x99, 0x99, 0x19, +0x92, 0x24, 0x49, 0x12, +0x8e, 0xe3, 0x38, 0x0e, +0xba, 0xe8, 0xa2, 0x0b, +0x89, 0x9d, 0xd8, 0x09, +0x88, 0x88, 0x88, 0x08, +0x87, 0x87, 0x87, 0x07, +0xa6, 0xf6, 0x43, 0x32, +0x4d, 0xed, 0x87, 0x64, +0xa7, 0xf6, 0x43, 0x32, +0x59, 0x09, 0xbc, 0xcd, +0x00, 0x00, 0x00, 0x08, +0x78, 0x78, 0x78, 0x00, +0xc0, 0x09, 0x9c, 0x00, +0x20, 0x0d, 0xd2, 0x00, +0x12, 0xe4, 0x29, 0x01, +0x71, 0x1c, 0xc7, 0x01, +0xc3, 0x30, 0x0c, 0x03, +0x66, 0x66, 0x66, 0x06, +0x55, 0x55, 0x55, 0x15, +0x00, 0x00, 0x00, 0x08, +0x88, 0x88, 0x88, 0x00, +0x40, 0x0b, 0xb4, 0x00, +0x0f, 0x3e, 0xf8, 0x00, +0xc1, 0x16, 0x6c, 0x01, +0x92, 0x24, 0x49, 0x02, +0x44, 0x44, 0x44, 0x04, +0xaa, 0xaa, 0xaa, 0x0a, +0xff, 0xff, 0xff, 0x3f, +0x00, 0x00, 0x00, 0x00, +0x80, 0x66, 0x66, 0x66, +0x00, 0x00, 0x00, 0x04, +0x00, 0x00, 0xfc, 0x7f, +0x00, 0x00, 0x90, 0x7f, +0x00, 0x20, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, +0x00, 0x00, 0xc0, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x48, 0x00, +0x00, 0x00, 0xf8, 0x7f, +0x00, 0x02, 0x00, 0x00, +0xff, 0xff, 0xff, 0x1f, +0x00, 0x00, 0x00, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x40, 0x8f, 0xc2, 0x35, +0x00, 0x00, 0x00, 0x00, +0xb7, 0x63, 0x68, 0x43, +0x39, 0x61, 0xdc, 0x0c, +0xff, 0xff, 0xff, 0x7f, +0x80, 0x66, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, +0x83, 0x4c, 0x27, 0x0c, +0x00, 0x00, 0x00, 0x03, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xa0, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x28, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x28, +0x00, 0x00, 0x00, 0x28, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x28, +0x75, 0x70, 0x35, 0x82, +0x19, 0x43, 0x6d, 0x7d, +0x8f, 0xb3, 0xa2, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0x4d, 0x52, 0x74, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xc5, 0x29, 0x99, 0x3a, +0x02, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x96, 0xe3, 0x8e, 0xb9, +0xfd, 0xd8, 0xa4, 0x7f, +0x6d, 0x43, 0xcc, 0x46, +0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x0e, 0x0f, 0x0f, 0x2f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x3b, 0xcb, 0x88, 0x3e, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x4d, 0xdb, 0x1e, 0x16, +0x65, 0x49, 0xc2, 0x53, +0x4d, 0xdb, 0x1e, 0x16, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xe1, 0x00, 0x00, 0x00, +0x02, 0xf1, 0x00, 0x00, +0x6e, 0x86, 0x7d, 0x00, +0x0a, 0x00, 0x00, 0x00, +0x02, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, +0x01, 0x02, 0x00, 0x01, +0x00, 0x00, 0x0c, 0x00, +0xd1, 0x07, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xcf, 0xcd, 0x16, 0x00, +0x5f, 0x64, 0xd2, 0x7f, +0xcf, 0xcd, 0x16, 0x00, +0xb0, 0x45, 0xb2, 0xaa, +0xbd, 0xda, 0x56, 0x55, +0xfd, 0xe0, 0x98, 0xad, +0xd1, 0xbe, 0x7b, 0x7c, +0x33, 0x60, 0xeb, 0x55, +0x48, 0x54, 0x00, 0x00, +0x49, 0x3a, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x80, 0x00, 0x00, 0x00, +0x00, 0x01, 0x00, 0x00, +0x80, 0x01, 0x00, 0x00, +0x00, 0x02, 0x00, 0x00, +0x80, 0x02, 0x00, 0x00, +0x00, 0x03, 0x00, 0x00, +0x80, 0x03, 0x00, 0x00, +0xff, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x00, 0x00, 0xd8, 0x00, +0xd4, 0x09, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x0a, 0x0a, 0x00, 0x00, +0x26, 0x0a, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x4e, 0x0a, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x84, 0x09, 0x00, 0x00, +0x88, 0x0a, 0x00, 0x00, +0xc4, 0x0a, 0x00, 0x00, +0xfc, 0x0a, 0x00, 0x00, +0xe8, 0x0a, 0x00, 0x00, +0x92, 0x12, 0x00, 0x00, +0x56, 0x13, 0x00, 0x00, +0x78, 0x13, 0x00, 0x00, +0x08, 0x14, 0x00, 0x00, +0x86, 0x09, 0x00, 0x00, +0x5a, 0x14, 0x00, 0x00, +0xbc, 0x16, 0x00, 0x00, +0xf0, 0x14, 0x00, 0x00, +0xd0, 0x14, 0x00, 0x00, +0x86, 0x09, 0x00, 0x00, +0x20, 0x15, 0x00, 0x00, +0x6c, 0x15, 0x00, 0x00, +0x94, 0x15, 0x00, 0x00, +0xb6, 0x15, 0x00, 0x00, +0xb6, 0x15, 0x00, 0x00, +0x86, 0x09, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xcf, 0xcd, 0x16, 0x00, +0x5f, 0x64, 0xd2, 0x7f, +0xcf, 0xcd, 0x16, 0x00, +0xcf, 0xcd, 0x16, 0x00, +0x5f, 0x64, 0xd2, 0x7f, +0xcf, 0xcd, 0x16, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x41, 0xca, 0x88, 0x3e, +0x41, 0xca, 0x88, 0x3e, +0x29, 0x02, 0xaf, 0x47, +0x29, 0x02, 0xaf, 0x47, +0x3b, 0xcb, 0x88, 0x3e, +0x3b, 0xcb, 0x88, 0x3e, +0x8d, 0xff, 0x7f, 0x3e, +0x8d, 0xff, 0x7f, 0x3e, +0xff, 0xff, 0xff, 0x7f, +0xd0, 0xcc, 0xcc, 0x0c, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, +0x97, 0x00, 0xb4, 0x00, +0x00, 0x00, 0x00, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x6c, 0x09, 0xf9, 0xe8, +0x03, 0x56, 0x0e, 0x41, +0x51, 0xb8, 0x1e, 0x05, +0x32, 0x08, 0xac, 0xe4, +0x83, 0xd3, 0x82, 0x41, +0x66, 0x66, 0x66, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x50, 0x00, +0x00, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x30, 0x01, 0x00, 0x00, +0x00, 0x00, 0x03, 0x00, +0x60, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xa3, 0x0f, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; + +const unsigned char CcUpdataCode128_01_02_01_00[] = { +0x5c, 0x81, 0x02, 0xbf, 0xb0, +0x68, 0x01, 0x01, 0xc5, 0xac, +0xa4, 0x00, 0x08, 0x00, 0x6c, +0x80, 0x06, 0xc6, 0x80, 0x20, +0x01, 0x12, 0x18, 0x00, 0x61, +0x80, 0x06, 0x16, 0x80, 0x10, +0x1c, 0x22, 0x18, 0x00, 0x61, +0x68, 0x02, 0x00, 0x08, 0xac, +0x80, 0x06, 0xc8, 0x00, 0x61, +0x80, 0x06, 0x16, 0x80, 0x10, +0x1d, 0x02, 0xc6, 0x80, 0x00, +0x02, 0x62, 0x16, 0x00, 0x00, +0x00, 0x03, 0x98, 0x40, 0x6c, +0xa0, 0x50, 0x08, 0x00, 0x08, +0x80, 0x84, 0x80, 0x00, 0x00, +0x64, 0x00, 0x80, 0x0d, 0x0f, +0x40, 0x00, 0x02, 0x80, 0x50, +0x76, 0x00, 0x00, 0x10, 0x60, +0x5c, 0x01, 0x20, 0x40, 0x0a, +0x68, 0x38, 0x1c, 0x03, 0x21, +0xa0, 0x46, 0x06, 0x80, 0x20, +0x00, 0xc2, 0xc8, 0x40, 0x6c, +0x46, 0x0a, 0x40, 0x48, 0x4a, +0x84, 0x8c, 0x80, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x08, +0x38, 0x13, 0xe2, 0x59, 0xa0, +0xbc, 0x0d, 0x07, 0x60, 0x00, +0x01, 0x0a, 0x0a, 0x04, 0x61, +0x84, 0x80, 0xa8, 0x40, 0x08, +0x54, 0x4d, 0x22, 0x04, 0xa1, +0x68, 0x01, 0x01, 0xba, 0x2c, +0x46, 0x0a, 0x40, 0x40, 0x48, +0x84, 0x86, 0xc0, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x76, 0x00, 0x00, 0x10, 0xa1, +0x5c, 0x08, 0xb0, 0x48, 0x08, +0x76, 0x00, 0x00, 0x10, 0x22, +0x25, 0x9a, 0x0b, 0xc0, 0x58, +0xa0, 0xca, 0x17, 0x60, 0x05, +0x00, 0x82, 0x0b, 0xc0, 0x2f, +0x85, 0x06, 0x08, 0x50, 0x60, +0x68, 0x02, 0x00, 0x16, 0x20, +0xba, 0x14, 0x88, 0x48, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +0x76, 0x00, 0x00, 0x10, 0x81, +0x5c, 0x81, 0x02, 0x08, 0x02, +0x5c, 0x00, 0x48, 0x08, 0x02, +0x55, 0x3e, 0x93, 0x01, 0x38, +0x51, 0x48, 0xa2, 0xc0, 0x41, +0x2a, 0x06, 0x37, 0x60, 0x00, +0x01, 0x06, 0x02, 0xe8, 0x5c, +0x68, 0x38, 0x1c, 0x03, 0x23, +0x62, 0x00, 0x00, 0x01, 0xd4, +0x5c, 0x00, 0x92, 0x18, 0x23, +0x5c, 0x02, 0x0b, 0x00, 0x83, +0xa0, 0x00, 0x48, 0x22, 0x88, +0x86, 0x02, 0x56, 0xc7, 0x03, +0x80, 0x64, 0x86, 0x00, 0x01, +0x00, 0x04, 0x08, 0x58, 0x52, +0x00, 0x00, 0x08, 0x28, 0x0a, +0x6c, 0x70, 0x38, 0x02, 0x4a, +0x00, 0x00, 0x08, 0x60, 0x65, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x83, 0x0b, 0xff, 0xc0, +0x85, 0x85, 0x10, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x83, 0x0b, 0xff, 0xc0, +0x28, 0x0e, 0x48, 0x40, 0x48, +0xa0, 0xc6, 0x08, 0x40, 0x02, +0x85, 0x08, 0x05, 0x44, 0x40, +0x20, 0xca, 0x06, 0x80, 0x10, +0x1b, 0xa2, 0xc4, 0x60, 0xa4, +0x05, 0x0d, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x00, 0x09, 0x21, +0x00, 0x00, 0x0a, 0x0c, 0x62, +0x85, 0x00, 0x05, 0x53, 0xc1, +0x04, 0x82, 0x12, 0x2f, 0xd4, +0x2a, 0x8e, 0x02, 0x80, 0x10, +0x22, 0x88, 0x46, 0x20, 0x00, +0x00, 0x04, 0x26, 0xc0, 0x00, +0x16, 0x64, 0x85, 0xc8, 0x04, +0x20, 0x81, 0x19, 0x48, 0x08, +0x94, 0x04, 0x00, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0xab, 0xff, 0x08, 0x80, 0x76, +0x68, 0x00, 0x00, 0x2f, 0x20, +0x66, 0x00, 0x80, 0x09, 0x60, +0x68, 0x00, 0x00, 0x2f, 0x20, +0x5c, 0x08, 0xa0, 0x80, 0x36, +0x76, 0x00, 0x00, 0x10, 0xa0, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0xab, 0xff, 0x08, 0x80, 0x76, +0x68, 0x00, 0x00, 0x6f, 0x20, +0x66, 0x00, 0x80, 0x09, 0x60, +0x68, 0x00, 0x00, 0x6f, 0x20, +0x5c, 0x08, 0xe0, 0x80, 0x36, +0x76, 0x00, 0x00, 0x08, 0xa0, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x39, 0x02, 0x06, 0x80, 0x20, +0x03, 0x72, 0xc8, 0x00, 0x7a, +0x6c, 0x00, 0x00, 0x26, 0x6c, +0x46, 0x0a, 0x40, 0x00, 0x7a, +0x84, 0x07, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x00, 0x12, 0x20, +0x00, 0x00, 0x09, 0x40, 0xac, +0x32, 0x02, 0x0b, 0xc1, 0xe0, +0x32, 0x06, 0x0b, 0xc1, 0x80, +0x32, 0x0a, 0x0b, 0xc1, 0x20, +0x32, 0x12, 0x0b, 0xc0, 0xc0, +0x32, 0x16, 0x0b, 0xc0, 0x60, +0x32, 0x1a, 0x0b, 0xc1, 0x89, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x21, 0x27, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x1b, 0xc7, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x26, 0xc7, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x17, 0x67, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x13, 0x87, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x10, 0x67, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x84, 0x10, 0x05, 0x90, 0x40, +0x2b, 0xfe, 0x08, 0x80, 0x76, +0x42, 0x0a, 0x42, 0x00, 0x01, +0xa4, 0x04, 0x08, 0x4a, 0xa1, +0x66, 0x00, 0x40, 0x3b, 0x68, +0xa0, 0x81, 0x18, 0x81, 0x00, +0x23, 0x84, 0x46, 0x80, 0x00, +0x7f, 0xfc, 0x02, 0x88, 0x20, +0x68, 0x00, 0x05, 0xff, 0xc2, +0x30, 0x88, 0x0b, 0xc1, 0x83, +0x68, 0x02, 0x08, 0x00, 0x02, +0x28, 0x08, 0x46, 0xc0, 0x00, +0x35, 0x44, 0x8b, 0xc1, 0x27, +0x6c, 0x00, 0x03, 0x54, 0x00, +0x68, 0x3d, 0xf8, 0x00, 0x02, +0x54, 0x04, 0x22, 0x08, 0xc1, +0x51, 0x83, 0x02, 0x0c, 0x62, +0x84, 0x82, 0x18, 0x81, 0x50, +0x40, 0x00, 0x00, 0x80, 0xe2, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x00, 0x80, 0xa0, +0x00, 0x00, 0x08, 0x40, 0x50, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x5c, 0x80, 0x80, 0x41, 0x00, +0x32, 0x08, 0x0b, 0xc2, 0x28, +0x6c, 0x00, 0x03, 0x54, 0x24, +0x6c, 0x00, 0x00, 0x0c, 0x00, +0x55, 0x3c, 0x00, 0x42, 0xa0, +0x22, 0xfc, 0x42, 0xa8, 0xe2, +0x28, 0x08, 0x02, 0x28, 0x86, +0x32, 0x03, 0x0b, 0xc2, 0x9d, +0x5c, 0x80, 0x4a, 0x00, 0x10, +0x62, 0x00, 0x00, 0x00, 0xf6, +0x38, 0x10, 0x40, 0x00, 0x00, +0x94, 0x08, 0x85, 0x04, 0x80, +0x14, 0x08, 0xa5, 0x04, 0x89, +0x14, 0x08, 0x95, 0x04, 0x85, +0x94, 0x08, 0x92, 0x32, 0x12, +0x29, 0x08, 0x02, 0x09, 0x09, +0x23, 0x41, 0xb2, 0x36, 0x0a, +0x29, 0x0c, 0x02, 0x90, 0x80, +0xbb, 0x10, 0x0b, 0xc1, 0x37, +0x5c, 0x80, 0x4a, 0x00, 0xc0, +0x5c, 0x01, 0x0b, 0xb0, 0x80, +0x51, 0xd0, 0x98, 0x40, 0x21, +0x51, 0xe0, 0x81, 0x83, 0x8a, +0x51, 0xf0, 0x91, 0x48, 0xc6, +0x98, 0x3c, 0x3a, 0x08, 0x02, +0x98, 0x30, 0x09, 0x48, 0xc3, +0x98, 0x38, 0x89, 0x50, 0xe0, +0xa0, 0x46, 0x09, 0x48, 0xe4, +0x84, 0x05, 0x1b, 0xa1, 0x48, +0x6c, 0x00, 0x03, 0x54, 0x64, +0x40, 0x00, 0x03, 0x80, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xfe, 0x0b, 0xc1, 0x38, +0x88, 0x07, 0x6a, 0x00, 0xa0, +0xa0, 0x48, 0x18, 0x40, 0x20, +0x88, 0x0e, 0x1a, 0x00, 0x11, +0x66, 0x00, 0x40, 0x3b, 0x68, +0xa4, 0x04, 0x08, 0x81, 0x08, +0xb0, 0x7f, 0xe5, 0x44, 0xd2, +0x08, 0x0a, 0x06, 0xc0, 0x00, +0x35, 0x64, 0x86, 0x80, 0x20, +0x06, 0x62, 0x1b, 0xc0, 0x6f, +0x84, 0x06, 0x10, 0x00, 0x00, +0x6c, 0x00, 0x03, 0x56, 0x08, +0x2a, 0x06, 0x48, 0x41, 0xc8, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x68, 0x00, 0x00, 0x0a, 0x22, +0x5c, 0x00, 0x40, 0x40, 0x82, +0x51, 0x44, 0xa2, 0x14, 0xa1, +0x2a, 0x06, 0x22, 0xe8, 0x13, +0x62, 0x00, 0x00, 0x00, 0xd3, +0x5c, 0x80, 0x88, 0x40, 0x24, +0x5c, 0x80, 0x40, 0x50, 0x22, +0xbb, 0x04, 0x15, 0x1d, 0x04, +0x18, 0x34, 0xa5, 0x1e, 0x05, +0x18, 0x30, 0x05, 0x1f, 0x04, +0x95, 0x04, 0x69, 0x83, 0x82, +0x95, 0x04, 0x09, 0x83, 0x48, +0x95, 0x04, 0x29, 0x50, 0x44, +0x6c, 0x00, 0x03, 0x54, 0x64, +0x68, 0x01, 0x00, 0xed, 0x2c, +0x46, 0x0a, 0x40, 0x41, 0x7a, +0x84, 0x86, 0xc0, 0x00, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0x7a, 0x21, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x00, 0x07, 0x00, 0x08, +0x5c, 0x01, 0x30, 0x40, 0x48, +0x5c, 0x09, 0xe2, 0x00, 0x20, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x00, +0x25, 0x90, 0x0b, 0xff, 0xc0, +0x68, 0x00, 0x08, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x06, 0x50, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x00, +0x25, 0x90, 0x0b, 0xff, 0xc0, +0x68, 0x00, 0x09, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x06, 0x50, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x93, 0x0b, 0xff, 0xc0, +0x6c, 0x00, 0x03, 0x58, 0x7a, +0x68, 0x01, 0x00, 0xed, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x00, 0xa6, 0x00, 0x00, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0x8f, 0xa1, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x02, 0x08, 0x00, 0x24, +0x68, 0x00, 0x07, 0x00, 0x09, +0x5c, 0x09, 0xe3, 0x00, 0x16, +0x60, 0x00, 0xc0, 0x01, 0x80, +0x5c, 0x02, 0x3a, 0xc0, 0x10, +0x5c, 0x04, 0x02, 0x00, 0x20, +0x60, 0x00, 0x10, 0x00, 0x20, +0x6c, 0x70, 0x38, 0x06, 0x49, +0x84, 0x04, 0xab, 0xb0, 0x80, +0x6c, 0x70, 0x38, 0x02, 0x4e, +0x40, 0x00, 0x03, 0xc0, 0x27, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xa0, +0x84, 0x04, 0xb0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xc0, +0x28, 0x02, 0xd6, 0xc0, 0x00, +0x35, 0x87, 0xa6, 0x80, 0x10, +0x0e, 0xd2, 0x0b, 0xa1, 0x48, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0xa6, 0x21, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x00, 0x07, 0x00, 0x08, +0x5c, 0xbf, 0x00, 0x40, 0x48, +0x5c, 0x00, 0x71, 0xc0, 0x00, +0x68, 0x00, 0x02, 0xff, 0xc8, +0x5c, 0x08, 0x20, 0x40, 0x48, +0x40, 0x00, 0x00, 0x41, 0x4a, +0x68, 0x02, 0x08, 0x00, 0x24, +0x60, 0x0b, 0xf0, 0x00, 0x4f, +0x6c, 0x70, 0x38, 0x00, 0x0a, +0x50, 0xc9, 0x82, 0xc0, 0x10, +0x6c, 0x70, 0x38, 0x00, 0x0a, +0x50, 0xc9, 0x83, 0xb1, 0x00, +0x6c, 0x00, 0x03, 0x58, 0x7a, +0x68, 0x01, 0x00, 0xed, 0x20, +0xbb, 0x10, 0x0b, 0xa1, 0x48, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +}; + +#define VERNUM_01_02_01_00 0x00011b020b +#define CAL_ID_01_02_01_00 0x00003801ff diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_02_02_01.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_02_02_01.h new file mode 100755 index 0000000000000000000000000000000000000000..2f4963060d652674bcbfe6bc7b59da63b58e5f12 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/FromCode_01_02_02_01.h @@ -0,0 +1,7122 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +/** + * @brief LC898128 OIS PRODUCT + * + * @author Copyright (C) 2018 ON Semiconductor All Rights Reserved. + * + **/ + +/* Version Name : "01-31-2018" */ +/* Time Stamp : 2020/05/22 18:43:11 */ + +#define FromCodeBlockSize_01_02_02_01 7 + +#define FromCheckSumSize_01_02_02_01 0x00001a4e +#define FromCheckSum_01_02_02_01 0xd5b52564 + +#define UpDataCodeSize_01_02_02_01 0x0000015e +#define UpDataCodeCheckSum_01_02_02_01 0x00007a7a646642d9 + +/* [00011b020b] [00013802ff] [0000000000] [0000000000] */ + +/*#define SELECT_VENDOR 1 */ +/*#define SEL_MODEL 2 */ +/*#define SELECT_ACT 2 */ +/*#define MASTER_SLAVE 1 */ + +const unsigned char CcFromCode128_01_02_02_01[] = { +0x00, 0x01, 0x02, 0x03, +0x04, 0x05, 0x06, 0x07, +0xbc, 0x12, 0x00, 0x00, +0x12, 0x80, 0x2a, 0x1d, +0x4c, 0xd3, 0x06, 0x00, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, + +0x64, 0x00, 0x00, 0x03, +0x87, 0x64, 0x00, 0x00, +0x20, 0xc7, 0x64, 0x00, +0x00, 0x24, 0x47, 0x64, +0x00, 0x00, 0x28, 0x67, +0x64, 0x00, 0x00, 0x28, +0x87, 0x46, 0x0b, 0x03, +0x80, 0x00, 0x64, 0x00, +0x00, 0x2b, 0x67, 0x64, +0x00, 0x00, 0x2b, 0x87, +0x46, 0x0b, 0x03, 0x80, +0x00, 0x64, 0x00, 0x00, +0x2b, 0xa7, 0x64, 0x00, +0x00, 0x2b, 0xc7, 0x64, +0x00, 0x00, 0x2b, 0xe7, +0x64, 0x00, 0x00, 0x2c, +0x07, 0x46, 0x0b, 0x03, +0x80, 0x00, 0x64, 0x00, +0x00, 0x2c, 0x27, 0x46, +0x0b, 0x03, 0x80, 0x00, +0x00, 0x22, 0x05, 0x20, +0x20, 0x00, 0x00, 0x18, +0x43, 0x10, 0x00, 0x00, +0x00, 0x00, 0x03, 0x00, +0x00, 0x00, 0x17, 0x73, +0x00, 0x00, 0x00, 0x07, +0xa0, 0x00, 0x00, 0x00, +0x02, 0xd8, 0x00, 0x00, +0x00, 0x17, 0x76, 0x00, +0x00, 0x80, 0x00, 0x7c, +0x00, 0x01, 0x1b, 0x02, +0x0b, 0x00, 0x01, 0x38, +0x02, 0xff, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xba, 0x11, 0x2b, 0xa1, +0x13, 0x68, 0x00, 0x04, +0x00, 0x38, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x34, 0x00, 0x09, 0x20, +0x5c, 0x81, 0x01, 0x8e, +0xb9, 0x5c, 0x01, 0x03, +0x06, 0x02, 0x84, 0x05, +0x2a, 0x00, 0x20, 0xb0, +0x42, 0x28, 0x00, 0x52, +0x84, 0x05, 0x0a, 0x05, +0x60, 0x68, 0x00, 0x05, +0x07, 0x00, 0x84, 0x05, +0x0a, 0x03, 0x60, 0x68, +0x00, 0xc5, 0x8f, 0xc0, +0x84, 0x05, 0x06, 0x60, +0x00, 0x02, 0x00, 0x8a, +0xbf, 0xc0, 0x68, 0x20, +0x00, 0x00, 0x24, 0x68, +0x00, 0x00, 0x0c, 0x20, +0x40, 0x00, 0x01, 0x89, +0x09, 0x66, 0x00, 0x00, +0x3b, 0x48, 0x5c, 0x00, +0xb1, 0x88, 0x08, 0x66, +0x00, 0x00, 0x4b, 0x80, +0x66, 0x00, 0x00, 0xea, +0x80, 0x68, 0x3a, 0x9a, +0xc2, 0xe0, 0x6c, 0x68, +0x08, 0x0e, 0x60, 0x40, +0x00, 0x03, 0x07, 0xf8, +0x6c, 0x40, 0x05, 0x22, +0x50, 0x68, 0x00, 0x00, +0x04, 0x20, 0x68, 0x20, +0x03, 0xa0, 0x21, 0x66, +0x00, 0x00, 0x8a, 0xa0, +0x66, 0x00, 0x00, 0x2d, +0xe0, 0x66, 0x00, 0x00, +0x2f, 0x00, 0x38, 0x18, +0x06, 0xc7, 0x02, 0x84, +0xc5, 0x06, 0x80, 0x00, +0x00, 0x8b, 0x9b, 0xa1, +0x10, 0x40, 0x00, 0x03, +0x80, 0x00, 0x66, 0x00, +0x00, 0x4e, 0xc0, 0x66, +0x00, 0x00, 0x2c, 0x40, +0x66, 0x00, 0x00, 0x4e, +0xe0, 0x66, 0x00, 0x02, +0x47, 0x80, 0x66, 0x00, +0x00, 0xeb, 0x20, 0x66, +0x00, 0x02, 0x20, 0xc0, +0x66, 0x00, 0x01, 0x50, +0x00, 0x68, 0x20, 0x00, +0x04, 0x20, 0x66, 0x00, +0x00, 0x7f, 0x40, 0x66, +0x00, 0x00, 0x5e, 0x40, +0x68, 0x00, 0x00, 0xc9, +0x20, 0x66, 0x00, 0x00, +0x47, 0xc0, 0x68, 0x00, +0x05, 0x44, 0xa0, 0x6c, +0x00, 0x01, 0x2e, 0x60, +0x66, 0x00, 0x02, 0x39, +0x80, 0xb0, 0x00, 0xd6, +0x60, 0x00, 0x05, 0x18, +0x89, 0x8e, 0x88, 0x5c, +0x08, 0x11, 0x8e, 0x40, +0x68, 0x00, 0x00, 0x05, +0x20, 0x52, 0x04, 0x03, +0xc0, 0x4f, 0x5c, 0x81, +0x01, 0x84, 0x39, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x06, 0x1a, +0x00, 0x32, 0xa0, 0x0b, +0xff, 0xa1, 0x80, 0x22, +0x4b, 0xa0, 0xc8, 0x6c, +0x00, 0x06, 0x1a, 0x7a, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x00, +0xc9, 0x20, 0x66, 0x00, +0x00, 0x48, 0xc0, 0x6c, +0x00, 0x06, 0x1a, 0x00, +0x32, 0x80, 0x0b, 0xc0, +0x49, 0x40, 0x00, 0x03, +0x07, 0xf8, 0x46, 0x0e, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x00, 0x02, 0x02, +0x28, 0x81, 0x23, 0x00, +0x10, 0x68, 0x00, 0x00, +0x05, 0x20, 0xbf, 0xe3, +0x83, 0x90, 0x20, 0x6e, +0x40, 0x00, 0x08, 0x38, +0x68, 0x00, 0x20, 0x00, +0x02, 0x28, 0x88, 0x03, +0x20, 0x00, 0xbc, 0x09, +0x16, 0xc0, 0x00, 0x01, +0x80, 0x05, 0xc0, 0xe8, +0xb0, 0x1c, 0x22, 0x40, +0x40, 0x52, 0x04, 0x03, +0x80, 0x00, 0x6c, 0x00, +0x00, 0x18, 0x50, 0x66, +0x00, 0x01, 0xf8, 0xc0, +0x66, 0x00, 0x02, 0x09, +0x20, 0x68, 0x20, 0x02, +0x33, 0xa0, 0x68, 0x00, +0x1d, 0xdd, 0xc0, 0x5c, +0x80, 0x82, 0xc6, 0x41, +0x5c, 0x0f, 0xd1, 0x40, +0x50, 0x5c, 0x09, 0x09, +0x40, 0x50, 0x68, 0x00, +0x1d, 0xc0, 0x03, 0x94, +0x0d, 0x39, 0x40, 0x50, +0x94, 0x05, 0x0a, 0xcc, +0xd0, 0x6c, 0x00, 0x00, +0x18, 0x00, 0x52, 0x44, +0x01, 0x42, 0x53, 0x6c, +0x00, 0x00, 0x18, 0x50, +0x88, 0x06, 0x00, 0x00, +0x00, 0x6c, 0x40, 0x02, +0xbc, 0x08, 0x6c, 0x40, +0x00, 0x32, 0x00, 0x6c, +0x40, 0x01, 0x50, 0x48, +0x6c, 0x40, 0x01, 0x80, +0x48, 0x32, 0x00, 0x0b, +0xc0, 0x68, 0x5c, 0x81, +0x08, 0x40, 0x00, 0x6c, +0x40, 0x00, 0x34, 0x02, +0x32, 0x01, 0x0b, 0xc0, +0xd1, 0x68, 0x20, 0x02, +0x01, 0x24, 0x24, 0x84, +0x08, 0x20, 0xd0, 0x88, +0x0e, 0x46, 0x60, 0x00, +0x21, 0xe4, 0x08, 0x80, +0xa0, 0x66, 0x00, 0x02, +0x1e, 0x48, 0x76, 0x00, +0x00, 0x06, 0x64, 0xbc, +0x03, 0x72, 0x40, 0x40, +0x6c, 0x40, 0x04, 0x02, +0x50, 0x68, 0x38, 0x08, +0x10, 0x20, 0x5c, 0x0b, +0x00, 0x80, 0x24, 0x5c, +0x80, 0x4a, 0x00, 0x20, +0x5c, 0x87, 0x00, 0x80, +0x60, 0xa0, 0x02, 0x08, +0x60, 0x02, 0x52, 0x40, +0x82, 0x00, 0x41, 0x88, +0x0e, 0x08, 0x60, 0x50, +0xa0, 0x02, 0x0a, 0x24, +0x3c, 0x88, 0x16, 0x09, +0x8e, 0x80, 0x96, 0x0c, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x19, 0x60, 0xc0, +0xa0, 0x82, 0x18, 0x82, +0x60, 0x96, 0x06, 0x08, +0x82, 0xe1, 0x68, 0x00, +0x00, 0x0c, 0x20, 0x40, +0x00, 0x03, 0xc0, 0x4f, +0x5c, 0x0e, 0x93, 0x00, +0x18, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x00, +0x06, 0x1a, 0x01, 0x32, +0xa0, 0x8b, 0xff, 0xa1, +0xa0, 0x00, 0x48, 0x02, +0x01, 0x25, 0x88, 0x8b, +0xc0, 0xc9, 0x88, 0x36, +0x02, 0x48, 0x8a, 0x6c, +0x40, 0x00, 0x46, 0x50, +0x68, 0x00, 0x04, 0x3b, +0x21, 0x68, 0x00, 0x06, +0x27, 0x20, 0x42, 0x02, +0x78, 0x22, 0x52, 0x40, +0x00, 0x00, 0x60, 0x61, +0x68, 0x00, 0x06, 0x27, +0x20, 0x98, 0x80, 0x26, +0xc0, 0x00, 0x12, 0xe0, +0x03, 0x00, 0x80, 0xbc, +0x73, 0x16, 0xc4, 0x00, +0x00, 0x20, 0x0b, 0x07, +0xfa, 0x28, 0x88, 0x03, +0x20, 0x00, 0xbc, 0x4d, +0x03, 0x20, 0x80, 0xbc, +0x31, 0x03, 0x20, 0xc0, +0xbc, 0x1f, 0x03, 0x21, +0x80, 0xbc, 0x5e, 0x15, +0xc8, 0x10, 0x08, 0x02, +0x06, 0xc7, 0x01, 0x02, +0x00, 0x05, 0xc8, 0x20, +0x84, 0x00, 0x25, 0xb0, +0x40, 0x84, 0x08, 0x26, +0x80, 0x00, 0x13, 0x92, +0x05, 0xc8, 0x51, 0x08, +0x0a, 0x48, 0x02, 0x50, +0x80, 0x0d, 0x18, 0x03, +0x52, 0x00, 0x00, 0x08, +0x81, 0x21, 0x86, 0x08, +0x38, 0x48, 0x80, 0x5b, +0x00, 0x12, 0x00, 0x04, +0x88, 0x22, 0x58, 0x00, +0x53, 0x86, 0x0d, 0x20, +0x00, 0x00, 0x86, 0x88, +0x08, 0x40, 0xd0, 0x40, +0x00, 0x03, 0xc4, 0x17, +0x6c, 0x70, 0x10, 0x20, +0x00, 0x5c, 0x81, 0x00, +0x80, 0x20, 0x68, 0x00, +0x01, 0x36, 0x24, 0x5c, +0x82, 0x08, 0x40, 0x02, +0x82, 0x25, 0x08, 0x20, +0xd2, 0x82, 0x07, 0xaa, +0x20, 0x00, 0x82, 0x07, +0xa8, 0x40, 0xfa, 0x86, +0x0f, 0xab, 0xc3, 0x17, +0x68, 0x00, 0x01, 0x36, +0x24, 0x5c, 0x81, 0x00, +0x80, 0x20, 0x6c, 0x70, +0x10, 0x20, 0x00, 0x5c, +0x82, 0x08, 0x40, 0x02, +0x82, 0x25, 0x08, 0x20, +0xd2, 0x00, 0x00, 0x08, +0x80, 0xa1, 0x84, 0x08, +0x08, 0x48, 0x82, 0x82, +0x05, 0x0a, 0x20, 0x01, +0x88, 0x12, 0x08, 0x20, +0x52, 0x00, 0x00, 0x08, +0x82, 0x25, 0x84, 0x08, +0x08, 0x68, 0x82, 0x84, +0x8d, 0x08, 0x60, 0xd2, +0x40, 0x00, 0x03, 0xc1, +0x77, 0x68, 0x00, 0x01, +0x38, 0x24, 0x5c, 0x81, +0x00, 0x80, 0x20, 0x6c, +0x70, 0x10, 0x20, 0x00, +0x5c, 0x84, 0x08, 0x40, +0x02, 0x82, 0x05, 0x08, +0x20, 0x52, 0x00, 0x00, +0x08, 0x80, 0xa1, 0x84, +0x08, 0x08, 0x49, 0x02, +0x82, 0x2d, 0x08, 0x22, +0x52, 0x00, 0x00, 0x08, +0x81, 0xa0, 0x88, 0x2a, +0x18, 0x40, 0x80, 0x84, +0x88, 0x28, 0x60, 0x50, +0x86, 0x15, 0x23, 0x81, +0x00, 0x6c, 0x70, 0x10, +0x4e, 0x02, 0x52, 0x40, +0x83, 0x80, 0x00, 0x6c, +0x70, 0x10, 0x4e, 0x50, +0x66, 0x00, 0x01, 0xce, +0x20, 0x6c, 0x00, 0x06, +0x1a, 0x7a, 0x66, 0x00, +0x01, 0xd4, 0xa0, 0x5c, +0x81, 0x00, 0x83, 0x20, +0x6c, 0x00, 0x00, 0x7a, +0x00, 0x51, 0x42, 0x20, +0x02, 0x24, 0x6c, 0x68, +0x10, 0x00, 0x48, 0x68, +0x34, 0x08, 0x00, 0x21, +0x6c, 0x00, 0x00, 0xa2, +0x00, 0x51, 0x42, 0x23, +0xa0, 0xc8, 0x84, 0xc4, +0x80, 0x00, 0x00, 0x6c, +0x00, 0x01, 0x2e, 0x20, +0x40, 0x00, 0x03, 0xa0, +0x80, 0x6c, 0x00, 0x02, +0x9c, 0x20, 0x40, 0x00, +0x03, 0xa0, 0x80, 0x66, +0x00, 0x00, 0x59, 0x20, +0x6c, 0x00, 0x01, 0x78, +0x20, 0x40, 0x00, 0x03, +0xa0, 0x80, 0x68, 0x00, +0x00, 0xb4, 0x20, 0x68, +0x20, 0x00, 0xe0, 0x24, +0x68, 0x00, 0x00, 0xb8, +0x21, 0x68, 0x20, 0x00, +0xe6, 0x25, 0x68, 0x00, +0x00, 0x9e, 0x22, 0x66, +0x00, 0x02, 0x30, 0x40, +0x66, 0x00, 0x01, 0xf9, +0xe0, 0x68, 0x00, 0x00, +0xc9, 0x20, 0x66, 0x00, +0x00, 0x48, 0xc0, 0x6c, +0x00, 0x06, 0x1a, 0x00, +0x32, 0x80, 0x06, 0x80, +0x00, 0x00, 0xc2, 0x0b, +0xf3, 0x29, 0x39, 0x0e, +0x04, 0x60, 0xe0, 0x38, +0x00, 0x0b, 0xf2, 0xe7, +0x60, 0x03, 0x80, 0x00, +0x10, 0x98, 0xea, 0x03, +0x90, 0x20, 0x80, 0x07, +0xa6, 0x00, 0x40, 0x00, +0x01, 0x06, 0x82, 0x00, +0x00, 0x02, 0x00, 0x00, +0x00, 0x80, 0x07, 0xab, +0xa1, 0x40, 0xab, 0xfd, +0x08, 0x80, 0xc9, 0x5c, +0x09, 0xf8, 0x80, 0x4b, +0x88, 0x17, 0x59, 0x02, +0x5b, 0x88, 0x1d, 0x70, +0x00, 0x00, 0x6e, 0x00, +0x00, 0x92, 0x2d, 0x25, +0x9e, 0x8b, 0xc0, 0x60, +0x6c, 0x68, 0x08, 0x10, +0x03, 0x6c, 0x00, 0x00, +0xbc, 0x53, 0x40, 0x00, +0x03, 0xc0, 0x67, 0x6c, +0x68, 0x08, 0x16, 0x03, +0x6c, 0x00, 0x00, 0xbc, +0x53, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6e, 0x00, +0x00, 0xba, 0x2b, 0x25, +0x9d, 0x8b, 0xc0, 0x50, +0x6c, 0x68, 0x08, 0x12, +0x09, 0x6c, 0x00, 0x00, +0xbe, 0x49, 0xbc, 0x07, +0x72, 0x59, 0xe8, 0xbc, +0x05, 0x06, 0xc6, 0x80, +0x81, 0x60, 0x96, 0xc0, +0x00, 0x0b, 0xe4, 0x90, +0x00, 0x00, 0x5c, 0x02, +0x29, 0x02, 0x13, 0x68, +0x00, 0x00, 0x00, 0x75, +0x6c, 0x68, 0x08, 0x06, +0x75, 0x6c, 0x00, 0x06, +0x1a, 0x49, 0x00, 0x00, +0x08, 0x81, 0x97, 0x88, +0x00, 0xb4, 0x60, 0xb4, +0x08, 0x13, 0x58, 0x80, +0x89, 0x40, 0x00, 0x02, +0x80, 0x30, 0xab, 0xef, +0x08, 0x80, 0x75, 0x88, +0x0f, 0x68, 0x81, 0x6f, +0x88, 0x1e, 0xe8, 0x82, +0x6d, 0x88, 0x2e, 0xc8, +0x83, 0x6b, 0x88, 0x3e, +0xa8, 0x84, 0x69, 0x88, +0x4e, 0x88, 0x85, 0x67, +0x88, 0x5e, 0x68, 0x86, +0x65, 0x88, 0x6e, 0x48, +0x87, 0x63, 0x88, 0x7e, +0x28, 0x88, 0x61, 0x88, +0x8e, 0x08, 0x89, 0x4b, +0x88, 0x9c, 0x98, 0x8a, +0x4a, 0x88, 0xac, 0x89, +0x0b, 0x5b, 0x88, 0xc5, +0x79, 0x0d, 0x59, 0x88, +0xcd, 0x59, 0x0e, 0x5a, +0x88, 0xf5, 0x69, 0x10, +0x58, 0x88, 0xfd, 0x46, +0x60, 0x00, 0x02, 0xfa, +0x8b, 0xa1, 0x01, 0x90, +0xe1, 0x29, 0x0d, 0x11, +0x90, 0xb1, 0x38, 0x88, +0xa0, 0x88, 0x82, 0x18, +0x87, 0xa2, 0x88, 0x72, +0x38, 0x86, 0xa4, 0x88, +0x62, 0x58, 0x85, 0xa6, +0x88, 0x52, 0x78, 0x84, +0xa8, 0x88, 0x42, 0x98, +0x83, 0xaa, 0x88, 0x32, +0xb8, 0x8a, 0x88, 0x88, +0xa0, 0xa8, 0x89, 0x89, +0x88, 0x90, 0xb8, 0x82, +0xac, 0x88, 0x22, 0xd8, +0x81, 0xae, 0x88, 0x12, +0xf8, 0x80, 0xb6, 0x88, +0x03, 0x59, 0x10, 0x10, +0x88, 0xf1, 0x68, 0x8c, +0x95, 0x46, 0x0b, 0x40, +0x8c, 0x17, 0x88, 0xf9, +0x4a, 0x81, 0x10, 0x40, +0x00, 0x03, 0xa1, 0x60, +0xab, 0xfc, 0x08, 0x80, +0xc9, 0x5c, 0x08, 0x38, +0x80, 0x4b, 0x88, 0x17, +0x50, 0x00, 0x00, 0x6c, +0x00, 0x06, 0x00, 0x09, +0x25, 0x9e, 0x8b, 0xc1, +0x81, 0x88, 0x1e, 0x78, +0x82, 0x6b, 0x90, 0x35, +0xb8, 0x82, 0xd7, 0x00, +0x00, 0x06, 0xc0, 0x00, +0x60, 0x22, 0x7b, 0xc0, +0x8f, 0x5c, 0x80, 0x59, +0x8e, 0x89, 0x6c, 0x70, +0x10, 0x02, 0x03, 0x55, +0x03, 0x69, 0x79, 0xc3, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x00, 0x06, +0x04, 0x0b, 0x30, 0x1e, +0x8b, 0xff, 0x62, 0x90, +0x31, 0x38, 0x81, 0xa7, +0x88, 0x22, 0xb8, 0x82, +0x97, 0x5c, 0x02, 0x3b, +0x00, 0x0d, 0x6c, 0x00, +0x06, 0x20, 0x4b, 0x6c, +0x70, 0x10, 0x0e, 0x49, +0x00, 0x00, 0x08, 0x81, +0x35, 0x46, 0x0b, 0x40, +0x80, 0x0b, 0x88, 0x08, +0x9a, 0x80, 0x40, 0x40, +0x00, 0x03, 0xa1, 0x60, +0x40, 0x00, 0x03, 0xa1, +0x60, 0x40, 0x00, 0x03, +0xa1, 0x60, 0x40, 0x00, +0x03, 0xa1, 0x60, 0x40, +0x00, 0x03, 0xa1, 0x60, +0x40, 0x00, 0x03, 0xa1, +0x60, 0x40, 0x00, 0x03, +0xa1, 0x60, 0x68, 0x34, +0x04, 0x04, 0x20, 0x5c, +0x02, 0xe2, 0xff, 0xc0, +0x5c, 0x00, 0x60, 0x40, +0x48, 0x9c, 0x00, 0x0b, +0x04, 0x86, 0x84, 0x04, +0xa6, 0x83, 0x40, 0x01, +0xe2, 0x1b, 0x19, 0xf6, +0x84, 0x84, 0xaa, 0x08, +0x81, 0xa0, 0x22, 0x08, +0x48, 0x7a, 0x68, 0x15, +0x0c, 0x84, 0x0a, 0x84, +0x04, 0xab, 0x08, 0x0e, +0xa0, 0x60, 0x04, 0x60, +0xa4, 0x04, 0x8c, 0xa8, +0x40, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x00, 0x00, 0x08, 0x20, +0x68, 0x00, 0x03, 0xff, +0x08, 0x84, 0x00, 0xa5, +0x44, 0x9b, 0x20, 0x42, +0x06, 0x83, 0x40, 0xc0, +0x02, 0x18, 0x41, 0x00, +0x54, 0x48, 0x20, 0x48, +0x4a, 0xa0, 0x82, 0x18, +0x40, 0x0a, 0x46, 0x0a, +0x40, 0x48, 0x4a, 0x84, +0xbc, 0x80, 0x00, 0x00, +0x68, 0x38, 0x14, 0x07, +0x20, 0x5c, 0xbc, 0x03, +0x00, 0x0c, 0x84, 0x07, +0xa4, 0x60, 0xa4, 0x1c, +0x00, 0x08, 0x40, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x70, 0x28, +0x0c, 0x08, 0x38, 0x10, +0x62, 0x59, 0xa0, 0xbc, +0x0d, 0x06, 0xc7, 0x02, +0x80, 0xc0, 0x83, 0x81, +0x0e, 0x25, 0x9a, 0x0b, +0xc0, 0x60, 0x5c, 0x04, +0x23, 0xa1, 0x48, 0x6c, +0x70, 0x28, 0x0c, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x64, 0x00, 0x00, +0x35, 0x67, 0x64, 0x00, +0x00, 0x30, 0xe7, 0x68, +0x34, 0x0c, 0x00, 0x20, +0x68, 0x20, 0x00, 0x00, +0x2c, 0x84, 0x02, 0xda, +0xbf, 0xf0, 0x98, 0xb4, +0x89, 0x8b, 0x0a, 0x54, +0x0d, 0x20, 0x80, 0x76, +0x68, 0x00, 0x00, 0x08, +0x21, 0x98, 0x23, 0x6a, +0x00, 0x40, 0x84, 0x87, +0x6a, 0x0c, 0x39, 0x84, +0x00, 0x05, 0x90, 0x40, +0x08, 0x0e, 0x09, 0x48, +0x60, 0x68, 0x00, 0x00, +0x04, 0x20, 0x42, 0x08, +0x42, 0x0c, 0x49, 0x84, +0x82, 0x16, 0xc7, 0x02, +0x81, 0x20, 0x83, 0x81, +0x06, 0x25, 0x9a, 0x0b, +0xc0, 0x40, 0x5c, 0x04, +0x23, 0xc0, 0x4f, 0x6c, +0x70, 0x28, 0x14, 0x48, +0x6c, 0x70, 0x28, 0x10, +0x7a, 0xba, 0x09, 0x0b, +0xc1, 0x6f, 0x5c, 0xbf, +0x03, 0x00, 0x0c, 0x40, +0x00, 0x03, 0xa0, 0x90, +0x6c, 0x40, 0x04, 0x02, +0x08, 0x38, 0x10, 0x62, +0x59, 0xa0, 0xbc, 0x03, +0x16, 0x60, 0x00, 0x0b, +0x66, 0x0b, 0xc0, 0x27, +0x66, 0x00, 0x00, 0x3a, +0x00, 0x68, 0x38, 0x14, +0x09, 0x20, 0x5c, 0x00, +0x62, 0xff, 0xe0, 0x6c, +0x70, 0x28, 0x12, 0x48, +0x9c, 0x00, 0x08, 0x40, +0x7a, 0x68, 0x38, 0x14, +0x07, 0x20, 0x88, 0x0a, +0x18, 0x80, 0x36, 0x84, +0x87, 0xa8, 0x40, 0x7a, +0x9c, 0x00, 0x04, 0x60, +0xa4, 0x04, 0x04, 0x88, +0x42, 0x48, 0x40, 0x00, +0x02, 0x80, 0x10, 0xab, +0xff, 0x06, 0x83, 0x40, +0xc0, 0x02, 0x06, 0x82, +0x00, 0x00, 0x02, 0xc8, +0x40, 0x2d, 0xa0, 0x02, +0x08, 0x40, 0x28, 0x84, +0x10, 0x05, 0x90, 0x40, +0x18, 0xb0, 0xa9, 0x8b, +0x48, 0x54, 0x0d, 0x20, +0x80, 0x60, 0x98, 0x22, +0x16, 0x80, 0x00, 0x00, +0x82, 0x29, 0xc8, 0x01, +0x85, 0x06, 0x1a, 0x14, +0x39, 0x94, 0x86, 0x06, +0x80, 0x00, 0x00, 0x42, +0x08, 0x80, 0xf6, 0x42, +0x08, 0x42, 0x0c, 0x49, +0x84, 0x82, 0x16, 0xc7, +0x02, 0x81, 0x20, 0xa3, +0x81, 0x04, 0x25, 0x93, +0x0b, 0xc0, 0x40, 0x40, +0x00, 0x03, 0xc0, 0x4f, +0x6c, 0x70, 0x28, 0x14, +0x48, 0x6c, 0x70, 0x28, +0x10, 0x7a, 0xba, 0x09, +0x0b, 0xc1, 0x6f, 0x5c, +0x00, 0x62, 0xff, 0xe0, +0x40, 0x00, 0x03, 0xa0, +0x90, 0x6c, 0x40, 0x04, +0x02, 0x08, 0x38, 0x10, +0x62, 0x59, 0xa0, 0xbc, +0x03, 0x16, 0x60, 0x00, +0x0b, 0x66, 0x0b, 0xc0, +0x27, 0x66, 0x00, 0x00, +0x3a, 0x00, 0x68, 0x38, +0x14, 0x09, 0x20, 0x5c, +0x00, 0x62, 0xff, 0xe0, +0x6c, 0x70, 0x28, 0x12, +0x48, 0x9c, 0x00, 0x08, +0x40, 0x7a, 0x68, 0x38, +0x14, 0x07, 0x20, 0x5c, +0x00, 0xb0, 0x80, 0x21, +0x88, 0x0b, 0x68, 0x49, +0x7a, 0x84, 0x07, 0xa9, +0xc0, 0x00, 0x46, 0x0a, +0x40, 0x40, 0x4a, 0x84, +0x24, 0x8a, 0x80, 0x10, +0x68, 0x00, 0x00, 0x09, +0x20, 0x68, 0x00, 0x03, +0xff, 0x08, 0x5c, 0x81, +0x00, 0x40, 0x0a, 0x68, +0x34, 0x0c, 0x08, 0x21, +0x54, 0x49, 0xa2, 0x04, +0x60, 0x5c, 0x00, 0x60, +0x48, 0x48, 0xa0, 0x82, +0x19, 0x40, 0x2e, 0x80, +0x84, 0xa4, 0x60, 0xa4, +0x00, 0x87, 0xa8, 0x48, +0x48, 0x40, 0x00, 0x03, +0x80, 0x00, 0x62, 0x00, +0x00, 0x00, 0x36, 0x5c, +0x81, 0x09, 0x82, 0x24, +0x5c, 0x80, 0x81, 0x82, +0x60, 0xbb, 0x00, 0x08, +0x00, 0xcc, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x38, +0x00, 0xe2, 0x11, 0x34, +0x32, 0x02, 0x0b, 0xc0, +0x6d, 0x84, 0x86, 0x06, +0x20, 0x00, 0x00, 0x01, +0x43, 0x90, 0x20, 0x00, +0x00, 0x08, 0x00, 0x7a, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x5c, 0x00, 0x61, +0x88, 0x2c, 0x50, 0x8d, +0x20, 0x48, 0x20, 0x51, +0x85, 0x3a, 0xc0, 0x20, +0x98, 0x2e, 0xe0, 0x00, +0x00, 0x9c, 0x40, 0x08, +0x40, 0x49, 0x62, 0x00, +0x00, 0x00, 0x24, 0x84, +0x86, 0x09, 0x8e, 0x80, +0x80, 0x40, 0x92, 0x81, +0x40, 0xba, 0x14, 0x85, +0x04, 0xc0, 0x04, 0x86, +0x09, 0x80, 0x08, 0x5c, +0x81, 0x00, 0xc0, 0x2a, +0x82, 0x00, 0xb4, 0x41, +0x80, 0x02, 0x00, 0x84, +0x44, 0x40, 0x06, 0x00, +0x84, 0x42, 0x50, 0x18, +0x24, 0x04, 0x60, 0xa4, +0x18, 0x08, 0x28, 0xc0, +0x60, 0x55, 0x00, 0xa3, +0x80, 0x00, 0x5c, 0x81, +0x00, 0xc0, 0x2a, 0x82, +0x00, 0xb4, 0x41, 0x80, +0x02, 0x00, 0x84, 0x44, +0x40, 0x02, 0x00, 0x84, +0x42, 0x50, 0x18, 0x24, +0x09, 0x80, 0x82, 0x55, +0x00, 0xb8, 0x20, 0x08, +0x8c, 0x06, 0x0a, 0x20, +0x01, 0x8c, 0x12, 0xe4, +0x42, 0x00, 0x02, 0x00, +0x84, 0x44, 0x40, 0x04, +0x88, 0x94, 0x46, 0xc8, +0x06, 0x08, 0x85, 0xb0, +0x82, 0x98, 0x04, 0xa5, +0x78, 0x9a, 0x18, 0x48, +0x05, 0x74, 0xb1, 0x3a, +0x14, 0x88, 0xc1, 0x60, +0x55, 0x00, 0xa3, 0x80, +0x00, 0x32, 0x02, 0x8b, +0xc3, 0x58, 0x22, 0x86, +0xe5, 0xb8, 0xa2, 0x30, +0x0f, 0x05, 0x70, 0x80, +0x30, 0x00, 0xf5, 0x08, +0x1c, 0x30, 0x4e, 0xa2, +0xa6, 0x63, 0x4b, 0xc1, +0x23, 0x3c, 0x08, 0x20, +0x0c, 0xd2, 0x35, 0xd4, +0x68, 0x20, 0x01, 0x2c, +0x20, 0x28, 0x16, 0x25, +0x14, 0x2a, 0x84, 0x00, +0x85, 0x70, 0xb0, 0xb0, +0x0f, 0xa5, 0x16, 0xe6, +0x04, 0x08, 0x92, 0x80, +0x20, 0x68, 0x1f, 0xff, +0xff, 0xc8, 0x36, 0x80, +0x35, 0x44, 0x84, 0x98, +0x0c, 0x82, 0x32, 0x09, +0x28, 0x08, 0x02, 0x10, +0x3f, 0x20, 0x90, 0xc2, +0x81, 0x3f, 0x08, 0xb0, +0x02, 0x23, 0xc0, 0x98, +0x00, 0x80, 0x83, 0x00, +0x22, 0x3c, 0x02, 0xe0, +0x28, 0x98, 0x00, 0x80, +0x8c, 0x00, 0x22, 0x04, +0x09, 0x80, 0x0b, 0x08, +0xb0, 0x02, 0x23, 0xc0, +0x98, 0x00, 0xa0, 0x8b, +0x00, 0x22, 0x3c, 0x02, +0xe0, 0x28, 0x98, 0x00, +0xa4, 0x47, 0x00, 0x3a, +0x14, 0x82, 0x20, 0x40, +0x98, 0x00, 0x8b, 0xa1, +0x48, 0x98, 0xe8, 0x80, +0x00, 0x00, 0x32, 0x02, +0x0b, 0xc1, 0x68, 0x68, +0x34, 0x04, 0x14, 0x21, +0x6c, 0x68, 0x08, 0x28, +0x49, 0x00, 0x00, 0x08, +0x48, 0x89, 0x84, 0x04, +0x94, 0x00, 0x00, 0x38, +0x00, 0x04, 0x00, 0x00, +0x38, 0x00, 0x0b, 0xc0, +0x4f, 0x5c, 0x09, 0xab, +0x80, 0x00, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x68, 0x08, 0x06, 0x08, +0x25, 0x96, 0x0b, 0xff, +0xa0, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x6c, 0x68, +0x08, 0x28, 0x49, 0x00, +0x00, 0x08, 0x40, 0x09, +0x84, 0x8c, 0x94, 0x00, +0x00, 0x38, 0x00, 0x04, +0x00, 0x00, 0x38, 0x00, +0x0b, 0xc0, 0x4f, 0x5c, +0x09, 0xab, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x68, 0x08, +0x06, 0x08, 0x25, 0x96, +0x0b, 0xff, 0xa0, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x32, 0x02, 0x0b, 0xc0, +0x69, 0x5c, 0x08, 0x71, +0x40, 0x2c, 0x52, 0x4d, +0x03, 0xa1, 0x48, 0x94, +0x06, 0x00, 0x00, 0x00, +0x52, 0x0d, 0x03, 0xa1, +0x48, 0x94, 0x06, 0x00, +0x00, 0x00, 0x5c, 0x04, +0xa0, 0x40, 0x7a, 0x46, +0x0a, 0x40, 0x40, 0xfa, +0x84, 0x14, 0x80, 0x00, +0x00, 0x84, 0x00, 0x88, +0x40, 0x8a, 0x30, 0x93, +0x0b, 0xc0, 0x4b, 0xb0, +0x00, 0xcb, 0xa1, 0x48, +0x84, 0x0f, 0xa9, 0x8e, +0x88, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x84, 0x08, +0x03, 0x28, 0x00, 0xbc, +0x05, 0x08, 0x40, 0x00, +0x55, 0x02, 0x23, 0xa1, +0x48, 0x84, 0x04, 0x80, +0x00, 0x00, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x5c, +0x81, 0x02, 0x00, 0x40, +0x46, 0x08, 0x88, 0x02, +0x0a, 0x08, 0x80, 0x04, +0x60, 0xa4, 0x00, 0x24, +0xc8, 0x40, 0x7a, 0x40, +0x00, 0x03, 0xa1, 0x01, +0x68, 0x38, 0x1c, 0x03, +0x21, 0x55, 0x3f, 0x72, +0xff, 0xe0, 0x59, 0x03, +0x40, 0x48, 0x48, 0x5c, +0x00, 0x61, 0xc8, 0x01, +0x42, 0x02, 0x58, 0x48, +0x4a, 0x55, 0x03, 0xb0, +0x49, 0x48, 0x5c, 0x00, +0x73, 0x80, 0x00, 0x62, +0x00, 0x00, 0x00, 0x46, +0x39, 0x02, 0x00, 0x00, +0x00, 0x6c, 0x70, 0x38, +0x00, 0x09, 0x80, 0x04, +0x90, 0x00, 0x00, 0x40, +0x00, 0x03, 0xa1, 0x40, +0xab, 0xfb, 0x06, 0x80, +0x00, 0x00, 0x82, 0x18, +0x80, 0x76, 0xa4, 0x04, +0x09, 0x88, 0x48, 0x66, +0x00, 0x00, 0x3b, 0x48, +0x5c, 0x02, 0x31, 0x88, +0x09, 0x5c, 0x81, 0x02, +0x40, 0x40, 0xa0, 0x00, +0x18, 0x00, 0x00, 0x51, +0x60, 0x28, 0x00, 0x00, +0x51, 0xd0, 0x30, 0x80, +0xe0, 0x23, 0x42, 0xa6, +0x80, 0x03, 0xff, 0xfc, +0x05, 0x44, 0x18, 0x04, +0x00, 0x93, 0x28, 0x28, +0x54, 0x80, 0x83, 0xc0, +0x9d, 0x6c, 0x40, 0x00, +0x04, 0x50, 0xa0, 0x86, +0x18, 0x48, 0xa0, 0x66, +0x00, 0x00, 0x4a, 0x08, +0x84, 0x80, 0x8b, 0xc0, +0x3f, 0x88, 0x0a, 0x00, +0x00, 0x00, 0x88, 0x0a, +0x00, 0x00, 0x00, 0x84, +0x18, 0x93, 0x28, 0x28, +0xbc, 0x06, 0xda, 0x40, +0x41, 0xa0, 0x8c, 0x18, +0x48, 0xa0, 0x66, 0x00, +0x00, 0x4a, 0x08, 0x84, +0x80, 0x88, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, +0x50, 0x40, 0x00, 0x03, +0x80, 0x00, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x68, +0x34, 0x08, 0x4a, 0x20, +0x5c, 0x00, 0x62, 0xbf, +0xf0, 0x84, 0x04, 0x88, +0x40, 0xc8, 0x40, 0x00, +0x00, 0x80, 0x76, 0x66, +0x00, 0x00, 0x50, 0x60, +0x68, 0x00, 0x01, 0xad, +0x20, 0x88, 0x03, 0x6a, +0x00, 0x81, 0xa0, 0xc2, +0x28, 0x50, 0x61, 0xa0, +0xc4, 0x3a, 0x0c, 0x62, +0x84, 0x06, 0x14, 0x60, +0xa4, 0x05, 0x86, 0x18, +0x50, 0x61, 0x40, 0x00, +0x02, 0x80, 0x10, 0x68, +0x34, 0x08, 0x4c, 0x20, +0x6c, 0x68, 0x00, 0x04, +0x7a, 0x5c, 0x00, 0xa2, +0xc9, 0xa0, 0x84, 0x04, +0x8a, 0x00, 0x20, 0x80, +0x24, 0x88, 0x40, 0x7a, +0xa0, 0x10, 0x0a, 0xcb, +0x00, 0x80, 0x07, 0xa4, +0x60, 0xa4, 0x30, 0x60, +0x48, 0x40, 0x48, 0x40, +0x00, 0x03, 0x80, 0x00, +0x68, 0x34, 0x00, 0x00, +0x20, 0x5c, 0x0b, 0x32, +0xc3, 0x20, 0x5c, 0x09, +0x00, 0x40, 0x02, 0x52, +0x0c, 0x92, 0xc5, 0x01, +0x84, 0x05, 0x2a, 0x03, +0x60, 0x84, 0x00, 0x25, +0x24, 0xc9, 0x2c, 0x4e, +0x28, 0x00, 0x52, 0x80, +0x2c, 0x88, 0x40, 0x7a, +0xa0, 0x02, 0x08, 0x01, +0x7a, 0x00, 0x00, 0x08, +0x02, 0x08, 0x25, 0x82, +0x0b, 0xc0, 0x89, 0x68, +0x34, 0x00, 0x0e, 0x21, +0x5c, 0x00, 0x43, 0x00, +0x34, 0x6c, 0x68, 0x00, +0x1c, 0x50, 0xbc, 0x04, +0xf8, 0x48, 0xc8, 0x6c, +0x68, 0x00, 0x1c, 0x7a, +0x84, 0x8f, 0xa3, 0x20, +0x28, 0x84, 0x00, 0x85, +0x20, 0xd2, 0x3c, 0x07, +0x85, 0xc0, 0x8e, 0x84, +0x04, 0x84, 0x60, 0xa4, +0x18, 0xe4, 0x82, 0x41, +0x65, 0x40, 0x00, 0x01, +0x82, 0x79, 0x46, 0x0a, +0x41, 0x8e, 0x48, 0x24, +0x96, 0x59, 0x82, 0x79, +0x68, 0x38, 0x08, 0x0f, +0x20, 0x39, 0x7a, 0x08, +0x40, 0x48, 0x46, 0x0a, +0x41, 0xc0, 0x00, 0x84, +0x04, 0x90, 0x00, 0x00, +0x68, 0x38, 0x08, 0x00, +0x21, 0xb0, 0x40, 0x68, +0x48, 0x4a, 0xa0, 0x84, +0x16, 0x20, 0x00, 0x00, +0x04, 0x48, 0x48, 0x7a, +0x39, 0x00, 0x89, 0x40, +0x0e, 0x6c, 0x70, 0x10, +0x06, 0x4a, 0x00, 0x00, +0x05, 0x90, 0x14, 0x04, +0xe4, 0x8b, 0xc0, 0x68, +0x6c, 0x00, 0x06, 0x20, +0x7a, 0x5c, 0x04, 0x6b, +0xc0, 0x5f, 0x6c, 0x70, +0x10, 0x0c, 0x49, 0x38, +0x00, 0xd6, 0xc7, 0x01, +0x00, 0xc4, 0x9b, 0xa1, +0x48, 0x6c, 0x00, 0x06, +0x00, 0x7a, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x38, 0x08, 0x00, 0x22, +0x00, 0x00, 0x08, 0x50, +0x7a, 0xa1, 0x04, 0x26, +0x20, 0x00, 0x00, 0x04, +0x48, 0x50, 0x7a, 0x39, +0x00, 0x89, 0x40, 0x08, +0x6c, 0x70, 0x10, 0x06, +0x50, 0x00, 0x00, 0x02, +0x81, 0x64, 0x59, 0x01, +0x80, 0x56, 0x48, 0xbc, +0x06, 0x86, 0xc0, 0x00, +0x62, 0x07, 0xa5, 0xc0, +0x47, 0x3c, 0x05, 0xf6, +0xc7, 0x01, 0x00, 0xc4, +0xa3, 0x80, 0x0e, 0x6c, +0x70, 0x10, 0x0c, 0x4a, +0x68, 0x00, 0x03, 0x00, +0x20, 0x5c, 0x81, 0x03, +0x00, 0x0e, 0x80, 0x04, +0xa4, 0x60, 0xa4, 0x00, +0x06, 0x18, 0x40, 0x49, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x00, 0x06, +0xf0, 0x00, 0x32, 0x00, +0x0b, 0xc4, 0xc0, 0x38, +0x10, 0x22, 0x58, 0x80, +0xbc, 0x10, 0x16, 0x80, +0x00, 0x37, 0x42, 0x05, +0xc8, 0x50, 0xac, 0x12, +0x05, 0xc8, 0x98, 0x80, +0x0a, 0x10, 0x00, 0x00, +0x84, 0x80, 0x22, 0x2c, +0x14, 0x94, 0x25, 0x40, +0x00, 0x00, 0x80, 0x0a, +0x10, 0x00, 0x00, 0x84, +0x80, 0x22, 0x2c, 0x14, +0x94, 0x07, 0x43, 0x81, +0x0a, 0x25, 0x88, 0x0b, +0xc1, 0x01, 0x68, 0x00, +0x03, 0x75, 0x20, 0x5c, +0x85, 0x0a, 0xc1, 0x20, +0x5c, 0x89, 0x88, 0x00, +0xa1, 0x00, 0x00, 0x08, +0x48, 0x02, 0x22, 0xc1, +0x49, 0x42, 0x54, 0x00, +0x00, 0x08, 0x00, 0xa1, +0x00, 0x00, 0x08, 0x48, +0x02, 0x22, 0xc1, 0x49, +0x40, 0x74, 0x38, 0x11, +0x22, 0x58, 0x80, 0xbc, +0x10, 0x16, 0x80, 0x00, +0x37, 0x62, 0x05, 0xc8, +0x50, 0xac, 0x12, 0x05, +0xc8, 0x98, 0x80, 0x0a, +0x10, 0x00, 0x00, 0x84, +0x80, 0x22, 0x2c, 0x14, +0x94, 0x25, 0x40, 0x00, +0x00, 0x80, 0x0a, 0x10, +0x00, 0x00, 0x84, 0x80, +0x22, 0x2c, 0x14, 0x94, +0x07, 0x43, 0x81, 0x1a, +0x25, 0x88, 0x0b, 0xc1, +0x09, 0x39, 0x0a, 0x16, +0x80, 0x00, 0x37, 0x72, +0x05, 0xc8, 0x91, 0x2c, +0x13, 0x08, 0x00, 0xa1, +0x00, 0x00, 0x08, 0x48, +0x00, 0x22, 0xc0, 0x49, +0x43, 0x54, 0x00, 0x00, +0x08, 0x00, 0x21, 0x00, +0x00, 0x08, 0x48, 0x00, +0x22, 0xc0, 0x49, 0x40, +0x74, 0x40, 0x00, 0x03, +0xa1, 0x40, 0x6e, 0x40, +0x00, 0x08, 0x3c, 0x5c, +0x0b, 0xea, 0xbf, 0xd0, +0x25, 0x96, 0x0b, 0xc5, +0xe8, 0x5c, 0x00, 0x28, +0x80, 0x76, 0x68, 0x20, +0x00, 0x05, 0x20, 0x5c, +0x88, 0x0a, 0xc0, 0x20, +0x5c, 0x8a, 0x08, 0x00, +0x88, 0x51, 0xd1, 0x32, +0xc1, 0x63, 0x5d, 0x08, +0x02, 0xc1, 0x82, 0x5d, +0x0c, 0x10, 0x80, 0xc9, +0x23, 0x60, 0x05, 0x1e, +0x13, 0x00, 0x05, 0x02, +0x36, 0x10, 0x5d, 0x0c, +0x00, 0x00, 0x50, 0x23, +0x60, 0x05, 0x1f, 0x12, +0x00, 0x05, 0x02, 0x36, +0x24, 0x80, 0x2c, 0x86, +0x82, 0x00, 0x01, 0xb2, +0x18, 0x01, 0x88, 0x3a, +0x90, 0x02, 0x3c, 0x24, +0x23, 0x40, 0x05, 0x1a, +0x12, 0x00, 0x05, 0x08, +0x03, 0xc8, 0x68, 0x00, +0x40, 0x04, 0x88, 0x80, +0x10, 0x05, 0x1e, 0x03, +0x08, 0x14, 0x83, 0xa8, +0x02, 0x23, 0x41, 0x05, +0x1a, 0x18, 0x00, 0x05, +0x08, 0x02, 0xd0, 0x00, +0x00, 0x08, 0x00, 0x00, +0x51, 0xe0, 0x30, 0x81, +0xe0, 0x23, 0x43, 0x25, +0xd4, 0x00, 0x00, 0x10, +0x15, 0xd4, 0x21, 0x04, +0x85, 0x25, 0x1a, 0x09, +0x20, 0x86, 0x15, 0x1e, +0x07, 0x00, 0xa5, 0x25, +0x1a, 0x19, 0x08, 0x26, +0x05, 0x1a, 0x00, 0x04, +0x85, 0x26, 0xc4, 0x00, +0x03, 0x85, 0x02, 0x30, +0xad, 0x98, 0x26, 0x86, +0x82, 0x00, 0x00, 0x52, +0x06, 0x60, 0x00, 0x14, +0xee, 0x89, 0xc0, 0x00, +0x88, 0x08, 0x85, 0x50, +0x32, 0x88, 0x10, 0x83, +0xb1, 0x45, 0x59, 0x07, +0x40, 0x80, 0xc9, 0x55, +0x03, 0x23, 0xff, 0x1a, +0x88, 0x14, 0x86, 0xc0, +0x00, 0x1d, 0x47, 0xa6, +0xc0, 0x00, 0x22, 0xa7, +0xa6, 0xc0, 0x00, 0x24, +0x07, 0xa6, 0xc0, 0x00, +0x25, 0x67, 0xa0, 0x00, +0x00, 0x88, 0x22, 0x08, +0x81, 0xa1, 0x42, 0x05, +0x78, 0x40, 0xfa, 0x40, +0x00, 0x00, 0x4e, 0x7a, +0x68, 0x20, 0x00, 0x0d, +0x20, 0x39, 0x02, 0x02, +0xa0, 0x6c, 0x3b, 0x10, +0x53, 0x23, 0x28, 0xbf, +0xfc, 0xa8, 0x00, 0x7a, +0x38, 0x17, 0x06, 0xe4, +0x00, 0x00, 0x83, 0xd2, +0x58, 0x28, 0xbc, 0x0b, +0x85, 0xc0, 0x32, 0x2c, +0x02, 0x06, 0x82, 0x00, +0x00, 0x82, 0x03, 0x92, +0x20, 0x80, 0x00, 0x8a, +0x06, 0x01, 0x80, 0x80, +0x94, 0x20, 0x4f, 0x84, +0x04, 0x88, 0x48, 0x49, +0x68, 0x20, 0x00, 0x19, +0x20, 0x2a, 0x06, 0x43, +0xb1, 0x04, 0x32, 0x3a, +0x0b, 0xff, 0xca, 0x40, +0x00, 0x00, 0x00, 0x7a, +0x68, 0x20, 0x00, 0x0d, +0x20, 0x66, 0x00, 0x00, +0x44, 0x48, 0x5c, 0x02, +0x29, 0x8e, 0x88, 0x68, +0x20, 0x00, 0x0d, 0x20, +0x00, 0x00, 0x0a, 0x00, +0x40, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x04, 0x44, +0x85, 0xc0, 0x42, 0x98, +0xe8, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x04, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x04, 0x44, +0x85, 0xc0, 0x06, 0x98, +0xe8, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x40, 0x40, 0x00, 0x00, +0x80, 0xe0, 0x66, 0x00, +0x00, 0x44, 0x48, 0x5c, +0x00, 0xa9, 0x8e, 0x88, +0x5c, 0x81, 0x00, 0x80, +0xa0, 0x68, 0x00, 0x00, +0x36, 0x21, 0xa0, 0x02, +0x08, 0x00, 0x01, 0x80, +0x00, 0x38, 0x00, 0x0a, +0x80, 0x00, 0x08, 0x00, +0x08, 0x80, 0x00, 0x96, +0xc4, 0x00, 0x07, 0x85, +0x16, 0xc4, 0x00, 0x0c, +0x65, 0x38, 0x48, 0x4a, +0x68, 0x00, 0x00, 0x4a, +0x22, 0x80, 0x00, 0x28, +0x00, 0x01, 0x84, 0x08, +0x38, 0x00, 0x0a, 0x6c, +0x40, 0x01, 0x5c, 0x4a, +0xa0, 0x6c, 0x09, 0x40, +0x3e, 0xb1, 0x00, 0x76, +0x80, 0x00, 0x09, 0x02, +0x35, 0x44, 0xf8, 0x05, +0x05, 0x06, 0xc4, 0x00, +0x18, 0xc5, 0x35, 0x90, +0x00, 0x05, 0x0c, 0x98, +0x48, 0xc8, 0x85, 0x8d, +0x14, 0x20, 0x3c, 0x85, +0x85, 0x28, 0x80, 0xe0, +0x66, 0x00, 0x00, 0xee, +0xe8, 0x68, 0x00, 0x40, +0x03, 0x88, 0x40, 0x00, +0x00, 0x80, 0xa0, 0x68, +0x00, 0x01, 0x00, 0x08, +0x94, 0x03, 0xd2, 0x89, +0x2c, 0x32, 0x02, 0x0b, +0xc0, 0x91, 0x6e, 0x00, +0x01, 0x2c, 0x2d, 0x38, +0x11, 0x82, 0x40, 0x28, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x66, 0x00, 0x00, +0xf2, 0x28, 0x38, 0x00, +0x48, 0x80, 0xa0, 0x68, +0x00, 0x02, 0x00, 0x08, +0x94, 0x03, 0xd2, 0x89, +0x2c, 0x32, 0x02, 0x0b, +0xc0, 0x61, 0x66, 0x00, +0x01, 0x0b, 0x28, 0x68, +0x00, 0x40, 0x05, 0x48, +0x40, 0x00, 0x00, 0x80, +0xa0, 0x5c, 0x81, 0x03, +0x08, 0x04, 0x94, 0x01, +0xd2, 0x89, 0x2c, 0x32, +0x02, 0x0b, 0xc0, 0x89, +0x88, 0x16, 0x03, 0x81, +0x05, 0x6e, 0x00, 0x01, +0x2c, 0xac, 0x52, 0x0b, +0x03, 0x80, 0x00, 0x6e, +0x00, 0x01, 0x2c, 0xe0, +0x66, 0x00, 0x01, 0x4e, +0xe8, 0x68, 0x00, 0x40, +0x07, 0x48, 0x88, 0x0a, +0x06, 0x80, 0x03, 0xff, +0xfc, 0x88, 0x40, 0x89, +0x3a, 0x94, 0x03, 0x01, +0x00, 0x40, 0x00, 0x03, +0xc0, 0x40, 0x51, 0xa0, +0x03, 0xc0, 0x4f, 0x6c, +0x00, 0x02, 0xb0, 0x50, +0x6c, 0x00, 0x02, 0xb0, +0x7a, 0x23, 0xc2, 0xd3, +0x01, 0x28, 0x40, 0x00, +0x03, 0xc0, 0x40, 0x51, +0xa1, 0x63, 0xc0, 0x4f, +0x6c, 0x00, 0x02, 0xb2, +0x48, 0x6c, 0x00, 0x02, +0xb2, 0x7a, 0x68, 0x00, +0x01, 0x64, 0x21, 0x60, +0x00, 0x00, 0x00, 0x28, +0x68, 0x00, 0x01, 0x5c, +0x20, 0x39, 0x02, 0x08, +0x00, 0x7a, 0x80, 0x87, +0xa0, 0x00, 0x00, 0x40, +0x00, 0x00, 0x81, 0x20, +0x66, 0x00, 0x01, 0x4e, +0xe8, 0x68, 0x00, 0x80, +0x00, 0x08, 0x5c, 0x81, +0x00, 0x81, 0x20, 0xb0, +0x7f, 0xc8, 0x00, 0x09, +0x28, 0x92, 0xc3, 0x20, +0x60, 0xbc, 0x68, 0x98, +0x80, 0xe0, 0x68, 0x00, +0x01, 0x6c, 0x20, 0x66, +0x00, 0x01, 0x4e, 0xe8, +0x68, 0x00, 0x80, 0x00, +0x48, 0x68, 0x00, 0x01, +0x6c, 0x20, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x08, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x0c, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x10, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x14, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x18, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x1c, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x20, 0x88, +0x81, 0xa0, 0x00, 0x00, +0x0a, 0x00, 0x20, 0x88, +0x1e, 0x06, 0x60, 0x00, +0x14, 0xee, 0x86, 0x80, +0x08, 0x00, 0x24, 0x88, +0x81, 0xa1, 0x68, 0x20, +0x01, 0xf4, 0x20, 0x68, +0x00, 0x01, 0x5c, 0x22, +0x60, 0x00, 0x00, 0x01, +0x78, 0x39, 0x02, 0x05, +0xc0, 0x7e, 0x20, 0xd0, +0x18, 0x48, 0x89, 0x80, +0x80, 0x05, 0x70, 0x14, +0x04, 0x08, 0x95, 0xb4, +0x01, 0x80, 0x00, 0x22, +0xe0, 0xaa, 0x37, 0x0c, +0x12, 0xe0, 0x65, 0x62, +0x00, 0x00, 0x00, 0x25, +0x20, 0x95, 0xb5, 0xb4, +0x40, 0x98, 0xeb, 0x52, +0xf8, 0x5b, 0x29, 0x88, +0x03, 0x20, 0x00, 0xbc, +0x02, 0xb9, 0x83, 0xc9, +0x36, 0x14, 0x58, 0x10, +0x49, 0x00, 0x00, 0x00, +0x00, 0x00, 0x88, 0x0a, +0x06, 0x60, 0x00, 0x14, +0xee, 0x86, 0x80, 0x08, +0x00, 0x40, 0x88, 0x81, +0x20, 0xb0, 0x7f, 0xc8, +0x40, 0x89, 0x28, 0x92, +0xc3, 0x20, 0x60, 0x40, +0x00, 0x03, 0xc6, 0x71, +0x68, 0x00, 0x01, 0x75, +0x20, 0x66, 0x00, 0x01, +0x4e, 0xe8, 0x68, 0x00, +0x80, 0x04, 0x48, 0x68, +0x00, 0x01, 0x75, 0x20, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x48, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x4c, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x50, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x54, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x58, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x5c, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x60, 0x88, 0x80, 0xa0, +0x00, 0x00, 0x0a, 0x00, +0x20, 0x88, 0x0e, 0x06, +0x60, 0x00, 0x14, 0xee, +0x86, 0x80, 0x08, 0x00, +0x64, 0x88, 0x80, 0xa1, +0x68, 0x20, 0x01, 0xf4, +0x20, 0x68, 0x00, 0x01, +0x64, 0x22, 0x60, 0x00, +0x00, 0x01, 0x78, 0x39, +0x02, 0x05, 0xc0, 0x7e, +0x20, 0xd0, 0x18, 0x48, +0x89, 0x80, 0x80, 0x05, +0x70, 0x14, 0x04, 0x08, +0x95, 0xb4, 0x01, 0x80, +0x00, 0x22, 0xe0, 0xaa, +0x37, 0x0c, 0x12, 0xe0, +0x65, 0x62, 0x00, 0x00, +0x00, 0x25, 0x20, 0x95, +0xb5, 0xb4, 0x40, 0x98, +0xeb, 0x52, 0xf8, 0x5b, +0x29, 0x88, 0x03, 0x20, +0x00, 0xbc, 0x02, 0xb9, +0x83, 0xc9, 0x36, 0x14, +0x58, 0x10, 0x49, 0x00, +0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, +0x30, 0x40, 0x00, 0x03, +0x80, 0x00, 0xab, 0xfd, +0x08, 0x80, 0x60, 0x88, +0x0f, 0x66, 0x80, 0x10, +0x00, 0x4c, 0x86, 0x60, +0x00, 0x14, 0xee, 0x8a, +0x40, 0x80, 0x5c, 0x09, +0xc2, 0x40, 0x80, 0x94, +0x02, 0xa2, 0x58, 0x10, +0xbc, 0x05, 0x06, 0x83, +0x40, 0x84, 0x02, 0x19, +0x41, 0x28, 0x84, 0x85, +0x28, 0x48, 0xd0, 0x66, +0x00, 0x01, 0x4e, 0xe8, +0x68, 0x00, 0x80, 0x03, +0x88, 0x5c, 0x09, 0xc2, +0x40, 0x80, 0x94, 0x02, +0xa2, 0x58, 0x10, 0xbc, +0x07, 0x86, 0x83, 0x40, +0x84, 0x22, 0x15, 0xc0, +0x80, 0x94, 0x0a, 0x82, +0x58, 0x40, 0x40, 0x00, +0x03, 0xc1, 0x01, 0x66, +0x00, 0x01, 0x4e, 0xe8, +0x68, 0x01, 0x00, 0x05, +0x08, 0x5c, 0x09, 0xc2, +0x40, 0x80, 0x94, 0x02, +0xa2, 0x58, 0x10, 0xbc, +0x0b, 0x06, 0x83, 0x40, +0x84, 0x22, 0x19, 0x41, +0x28, 0x6c, 0x68, 0x10, +0x84, 0x52, 0x84, 0x8d, +0x0b, 0xc0, 0x47, 0x94, +0x12, 0x86, 0xc6, 0x81, +0x08, 0x45, 0x28, 0x48, +0xd0, 0x66, 0x00, 0x01, +0x4e, 0xe8, 0x68, 0x01, +0x00, 0x05, 0x48, 0x5c, +0x09, 0xc2, 0x40, 0x80, +0x94, 0x02, 0xa2, 0x58, +0x10, 0xbc, 0x05, 0x06, +0x83, 0x40, 0x84, 0x42, +0x19, 0x41, 0x28, 0x84, +0x85, 0x28, 0x48, 0xd0, +0x66, 0x00, 0x01, 0x4e, +0xe8, 0x68, 0x00, 0x80, +0x03, 0xc8, 0x5c, 0x09, +0xc2, 0x40, 0x80, 0x94, +0x02, 0xa2, 0x58, 0x10, +0xbc, 0x07, 0x86, 0x83, +0x40, 0x84, 0x62, 0x15, +0xc0, 0x80, 0x94, 0x0a, +0x82, 0x58, 0x40, 0x40, +0x00, 0x03, 0xc1, 0x01, +0x66, 0x00, 0x01, 0x4e, +0xe8, 0x68, 0x01, 0x00, +0x05, 0x88, 0x5c, 0x09, +0xd2, 0x40, 0x80, 0x94, +0x02, 0x82, 0x58, 0x80, +0xbc, 0x0b, 0x06, 0x83, +0x40, 0x84, 0x62, 0x19, +0x41, 0x2a, 0x6c, 0x68, +0x10, 0x8c, 0x50, 0x84, +0x8d, 0x2b, 0xc0, 0x47, +0x94, 0x12, 0x86, 0xc6, +0x81, 0x08, 0xc5, 0x28, +0x48, 0xd0, 0x66, 0x00, +0x01, 0x4e, 0xe8, 0x68, +0x01, 0x00, 0x05, 0xc8, +0x5c, 0x09, 0xc2, 0x40, +0x80, 0x94, 0x02, 0xa2, +0x58, 0x10, 0xbc, 0x05, +0x06, 0x83, 0x40, 0x88, +0x02, 0x19, 0x41, 0x28, +0x84, 0x85, 0x28, 0x48, +0xd0, 0x66, 0x00, 0x01, +0x4e, 0xe8, 0x68, 0x01, +0x00, 0x06, 0x08, 0x5c, +0x09, 0xc2, 0x40, 0x80, +0x94, 0x0a, 0xa2, 0x58, +0x10, 0xbc, 0x0d, 0x05, +0xc8, 0x04, 0x20, 0x01, +0x95, 0x19, 0x08, 0x14, +0x02, 0x95, 0x48, 0x20, +0x94, 0xa0, 0xa6, 0x83, +0x40, 0x88, 0x22, 0x05, +0x19, 0x09, 0x14, 0x82, +0x85, 0x48, 0x08, 0x04, +0x05, 0x18, 0x40, 0xd0, +0x98, 0xe8, 0x08, 0x81, +0x50, 0x68, 0x00, 0x40, +0x00, 0x08, 0x88, 0x02, +0x08, 0x81, 0xc8, 0x66, +0x00, 0x01, 0x4e, 0xe0, +0x88, 0x10, 0x05, 0x50, +0x20, 0x08, 0x02, 0x05, +0xd0, 0x00, 0x08, 0x18, +0x25, 0x90, 0xc0, 0x20, +0x02, 0x04, 0x3f, 0xa5, +0x08, 0x06, 0x05, 0x50, +0x2a, 0x08, 0x15, 0x06, +0x80, 0x04, 0x00, 0x48, +0x88, 0x81, 0x7a, 0x88, +0x1c, 0x86, 0x60, 0x00, +0x14, 0xee, 0x08, 0x81, +0x00, 0x55, 0x02, 0x00, +0x80, 0x20, 0x5d, 0x00, +0x00, 0x81, 0x82, 0x59, +0x04, 0x02, 0x00, 0x20, +0x43, 0xfa, 0x50, 0x80, +0x60, 0x55, 0x02, 0xa0, +0x81, 0x50, 0x00, 0x00, +0x08, 0x80, 0xb6, 0xba, +0x14, 0x8a, 0x80, 0x30, +0x40, 0x00, 0x03, 0x80, +0x00, 0x5c, 0x82, 0x02, +0x00, 0x48, 0x5c, 0x00, +0x31, 0x8e, 0x88, 0x5c, +0x0f, 0xc1, 0x40, 0x64, +0x52, 0x01, 0xb2, 0x00, +0x38, 0x80, 0x26, 0x17, +0x60, 0x02, 0x00, 0x80, +0x29, 0x40, 0x64, 0xa0, +0x06, 0x18, 0x0a, 0x62, +0xb0, 0x40, 0x48, 0x48, +0x48, 0xa0, 0x8a, 0x18, +0x48, 0x4a, 0xa0, 0xd0, +0x16, 0x80, 0x00, 0x23, +0x62, 0xc8, 0x48, 0xec, +0x68, 0x00, 0x02, 0x31, +0xac, 0xba, 0x14, 0x88, +0x48, 0x6c, 0x40, 0x00, +0x03, 0x80, 0x00, 0x94, +0x4a, 0x83, 0x20, 0x00, +0xbc, 0x0b, 0x58, 0x42, +0x21, 0x68, 0x20, 0x02, +0x6d, 0x22, 0x94, 0x82, +0x82, 0x29, 0x04, 0x2a, +0xbe, 0x02, 0x30, 0x80, +0x98, 0x42, 0x89, 0xd0, +0x01, 0x84, 0x82, 0x1b, +0xa0, 0x10, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x39, 0x00, 0x89, +0x48, 0x0c, 0x51, 0xb1, +0x21, 0x48, 0x0e, 0x51, +0xa1, 0xb1, 0x48, 0x08, +0x51, 0x90, 0x11, 0x48, +0x28, 0x29, 0x1a, 0x42, +0x90, 0xa4, 0x54, 0x81, +0x23, 0xa1, 0x48, 0x84, +0x04, 0x80, 0x00, 0x00, +0x5c, 0x80, 0x40, 0x40, +0x00, 0x51, 0xf0, 0x23, +0x07, 0xfa, 0x28, 0x8a, +0x15, 0x1e, 0x02, 0x14, +0x84, 0x12, 0x88, 0xa1, +0x51, 0xd0, 0x21, 0x48, +0x41, 0x28, 0x8a, 0x15, +0x44, 0x40, 0x14, 0x84, +0x1b, 0xa1, 0x48, 0x94, +0x86, 0x00, 0x00, 0x00, +0x5c, 0x80, 0x48, 0x43, +0xa4, 0x5c, 0x80, 0x93, +0x80, 0x00, 0x62, 0x00, +0x00, 0x00, 0xb4, 0x5c, +0x81, 0x02, 0xbf, 0xf0, +0x5c, 0x00, 0x02, 0x40, +0x02, 0x60, 0x00, 0x00, +0x00, 0x35, 0x8d, 0x05, +0x80, 0x00, 0x00, 0x94, +0x88, 0xc9, 0x52, 0xc4, +0x00, 0x00, 0x0a, 0x10, +0x0a, 0x8d, 0x03, 0x2b, +0xb1, 0x82, 0xba, 0x14, +0x88, 0x43, 0xe4, 0x40, +0x00, 0x02, 0x80, 0x10, +0x5c, 0x80, 0x52, 0xbf, +0xf0, 0xa0, 0x0a, 0x0a, +0x40, 0x02, 0x62, 0x00, +0x00, 0x00, 0xa4, 0x5c, +0x81, 0x08, 0x41, 0x24, +0x5c, 0x80, 0x80, 0x40, +0x21, 0xbb, 0x00, 0x06, +0x00, 0x00, 0x00, 0x03, +0x58, 0xd0, 0xd8, 0x00, +0x00, 0x09, 0x53, 0x0c, +0x94, 0x94, 0x40, 0x00, +0x00, 0xa1, 0x00, 0xab, +0xa1, 0x48, 0x84, 0x16, +0x4a, 0x80, 0x10, 0xa0, +0x08, 0x18, 0x48, 0x22, +0xa0, 0xc3, 0x99, 0x50, +0x28, 0x55, 0x5e, 0x12, +0xbf, 0xe0, 0x51, 0x90, +0x89, 0x48, 0x2a, 0x59, +0x04, 0x81, 0x50, 0xa8, +0x54, 0x00, 0x60, 0x80, +0x76, 0xbc, 0x1a, 0x89, +0x82, 0x23, 0x32, 0x0d, +0x0b, 0xc1, 0x48, 0xa1, +0x01, 0x12, 0xa7, 0x90, +0x22, 0x88, 0x63, 0x20, +0x30, 0xbc, 0x1c, 0x56, +0x20, 0x00, 0x00, 0x08, +0x60, 0x00, 0x00, 0x00, +0x00, 0x09, 0x82, 0x20, +0x88, 0x0c, 0x88, 0x81, +0x61, 0x66, 0x00, 0x00, +0x8d, 0xa0, 0x88, 0x12, +0x08, 0x80, 0x80, 0x55, +0x08, 0x22, 0x00, 0x21, +0x40, 0x00, 0x03, 0xc0, +0xd7, 0x42, 0x05, 0xf9, +0x51, 0x28, 0x95, 0x86, +0x0a, 0x00, 0xa1, 0xa0, +0xc6, 0x28, 0x48, 0x21, +0x88, 0x0e, 0x26, 0x60, +0x00, 0x08, 0xe8, 0x8a, +0x18, 0x00, 0x88, 0x0a, +0x0b, 0x00, 0x20, 0x94, +0x06, 0x00, 0x00, 0x00, +0x88, 0x03, 0x6b, 0xa1, +0x48, 0xa8, 0x02, 0x00, +0x00, 0x00, 0x94, 0x4a, +0xc5, 0x90, 0x50, 0x2b, +0xff, 0x0b, 0xc0, 0x98, +0x88, 0x07, 0x6a, 0x00, +0x80, 0x84, 0x02, 0x18, +0x80, 0x36, 0xa8, 0x01, +0x0a, 0x00, 0x60, 0x64, +0x00, 0x00, 0x8d, 0xaf, +0xa0, 0x81, 0x1a, 0x00, +0xa1, 0xa0, 0x84, 0x08, +0x48, 0x21, 0x88, 0x0e, +0x06, 0x60, 0x00, 0x08, +0xe8, 0x08, 0x80, 0xa0, +0xb0, 0x02, 0x4a, 0x04, +0xa0, 0x94, 0x06, 0x40, +0x00, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0xa0, 0x08, 0x1a, 0x0c, +0x3a, 0x95, 0x02, 0xc5, +0x90, 0x50, 0x2b, 0xff, +0x0b, 0xc1, 0x68, 0x84, +0x82, 0x15, 0x53, 0xd2, +0x30, 0x0f, 0xe5, 0xb4, +0x81, 0x30, 0x02, 0x83, +0x70, 0x85, 0x2e, 0x17, +0x66, 0x20, 0x00, 0x00, +0x02, 0x63, 0x68, 0x00, +0x50, 0x4c, 0x91, 0x8e, +0xb5, 0x2f, 0x81, 0x22, +0xb9, 0x66, 0x32, 0x03, +0x0b, 0xc0, 0x2b, 0x98, +0x38, 0x83, 0x61, 0x04, +0xa0, 0x81, 0x16, 0x40, +0x00, 0x08, 0xf8, 0xfa, +0x80, 0x10, 0x88, 0x07, +0x68, 0x80, 0xe0, 0x66, +0x00, 0x00, 0x91, 0x08, +0x38, 0x00, 0xcb, 0x00, +0x2c, 0x88, 0x0a, 0x08, +0x80, 0x36, 0x94, 0x46, +0x4b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0xa0, 0x08, 0x18, 0x48, +0x22, 0x68, 0x20, 0x00, +0x00, 0x2c, 0x95, 0x02, +0x85, 0x55, 0xe1, 0x15, +0x0a, 0x85, 0x19, 0x09, +0x20, 0xc3, 0x95, 0x40, +0x0a, 0x18, 0xb0, 0x05, +0x40, 0x12, 0x14, 0x82, +0x85, 0x90, 0x40, 0x2b, +0xfe, 0x04, 0x20, 0xd4, +0x08, 0x07, 0x69, 0x82, +0x23, 0x32, 0x0c, 0x0b, +0xc1, 0x48, 0xa1, 0x01, +0x12, 0xa7, 0x80, 0x22, +0x88, 0x63, 0x20, 0x30, +0xbc, 0x1c, 0x56, 0x20, +0x00, 0x00, 0x08, 0x60, +0x00, 0x00, 0x00, 0x00, +0x09, 0x82, 0x20, 0x88, +0x0c, 0x88, 0x81, 0x61, +0x66, 0x00, 0x00, 0x8d, +0xa0, 0x88, 0x12, 0x08, +0x80, 0x80, 0x55, 0x08, +0x22, 0x00, 0x21, 0x40, +0x00, 0x03, 0xc0, 0xd7, +0x42, 0x05, 0xf9, 0x51, +0x28, 0x95, 0x86, 0x0a, +0x00, 0xa1, 0xa0, 0xc6, +0x28, 0x48, 0x21, 0x88, +0x0e, 0x26, 0x60, 0x00, +0x08, 0xe8, 0x8a, 0x18, +0x00, 0x88, 0x0a, 0x0b, +0x00, 0x20, 0x94, 0x06, +0x00, 0x00, 0x00, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0xa0, 0x08, 0x1a, +0x0c, 0x3a, 0xab, 0xfe, +0x09, 0x50, 0x28, 0x59, +0x04, 0x00, 0x80, 0x60, +0xa0, 0x0c, 0x08, 0x48, +0x21, 0x42, 0x10, 0x40, +0x81, 0x76, 0x88, 0x0e, +0x03, 0x21, 0x80, 0xbc, +0x18, 0x8a, 0x08, 0x11, +0x2a, 0x78, 0x02, 0x28, +0xc4, 0x32, 0x02, 0x0b, +0xc2, 0x45, 0x62, 0x00, +0x00, 0x00, 0xe4, 0x00, +0x00, 0x00, 0x00, 0x00, +0x88, 0x0a, 0x08, 0x81, +0xe1, 0x66, 0x00, 0x00, +0x8d, 0xa0, 0x88, 0x1a, +0x18, 0x80, 0x20, 0xa0, +0x82, 0x18, 0x43, 0x20, +0x88, 0x1e, 0x16, 0x60, +0x00, 0x08, 0xda, 0x08, +0x81, 0xa1, 0x00, 0x00, +0x0a, 0x08, 0x21, 0xbc, +0x11, 0x78, 0x81, 0x36, +0x88, 0x0a, 0x06, 0x40, +0x00, 0x08, 0xda, 0xfa, +0x80, 0x20, 0x39, 0x02, +0x08, 0x80, 0x21, 0x00, +0x00, 0x0a, 0x08, 0xa0, +0x80, 0x02, 0x18, 0x80, +0x60, 0x66, 0x00, 0x00, +0x8e, 0x80, 0x88, 0x02, +0x1b, 0x00, 0x20, 0xa0, +0xc8, 0x19, 0x48, 0x60, +0x00, 0x00, 0x08, 0x81, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x20, 0x40, 0x00, +0x03, 0x80, 0x00, 0xa0, +0x04, 0x99, 0x48, 0x2c, +0x59, 0x05, 0x02, 0x08, +0x7a, 0xab, 0xff, 0x08, +0x80, 0x76, 0x42, 0x06, +0xc2, 0x00, 0x01, 0x85, +0x02, 0x08, 0x4a, 0x21, +0x66, 0x00, 0x00, 0x8d, +0xa8, 0x40, 0x00, 0x02, +0x08, 0x11, 0x40, 0x00, +0x03, 0x80, 0x00, 0x40, +0x00, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, +0x00, 0xbc, 0x09, 0x7a, +0x08, 0xa1, 0xa0, 0xc6, +0x28, 0x48, 0x21, 0x88, +0x0e, 0x26, 0x60, 0x00, +0x08, 0xe8, 0x08, 0x80, +0xa0, 0xb0, 0x02, 0x49, +0x40, 0x64, 0x00, 0x00, +0x08, 0x80, 0x36, 0xba, +0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, +0x00, 0x98, 0x80, 0x86, +0x80, 0x00, 0x00, 0x40, +0xa3, 0x01, 0xa0, 0xbc, +0x0d, 0x18, 0x42, 0x21, +0xb0, 0x78, 0x49, 0x48, +0x2e, 0x30, 0x13, 0x0b, +0xc0, 0x60, 0xb0, 0x78, +0xc3, 0x01, 0x30, 0x40, +0x00, 0x03, 0xc0, 0x41, +0x64, 0x00, 0x00, 0xb1, +0xc7, 0x64, 0x00, 0x00, +0xa6, 0x27, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x84, +0x22, 0x1a, 0xbf, 0xe0, +0x94, 0x8a, 0xc5, 0x55, +0xf2, 0x08, 0x07, 0x63, +0x20, 0x20, 0xbc, 0x09, +0x1a, 0x08, 0x11, 0x66, +0x00, 0x00, 0x8d, 0xa8, +0xa4, 0x04, 0x08, 0x81, +0x08, 0x32, 0x82, 0x0b, +0xc0, 0x21, 0x66, 0x00, +0x01, 0x4c, 0x40, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0x84, 0x22, 0x1b, +0x07, 0x84, 0x94, 0x8a, +0xe2, 0x89, 0x34, 0x32, +0x02, 0x0b, 0xc0, 0x60, +0x38, 0x08, 0x63, 0x01, +0xa0, 0x40, 0x00, 0x03, +0xc0, 0x41, 0x64, 0x00, +0x00, 0xaa, 0xa7, 0x64, +0x00, 0x00, 0xa7, 0x27, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x84, 0x22, 0x1a, +0x00, 0xa2, 0x94, 0x8a, +0xe5, 0x90, 0xf8, 0x2b, +0xfe, 0x0b, 0xc1, 0x88, +0x88, 0x07, 0x63, 0x23, +0xf0, 0xbc, 0x2a, 0x98, +0x80, 0xe2, 0xa4, 0x04, +0x16, 0x80, 0x00, 0x00, +0xc2, 0x09, 0x88, 0x49, +0x66, 0x00, 0x00, 0x3b, +0x48, 0x5c, 0x00, 0x71, +0x88, 0x08, 0x5c, 0x83, +0x00, 0x80, 0xa2, 0x00, +0x00, 0x08, 0x12, 0x21, +0x88, 0x0e, 0x26, 0x60, +0x00, 0x08, 0xe8, 0x8a, +0x40, 0x40, 0x88, 0x0a, +0x0b, 0x00, 0x26, 0x94, +0x06, 0x6b, 0xc1, 0x57, +0x00, 0x00, 0x09, 0x44, +0xae, 0x32, 0x0b, 0x0b, +0xc0, 0x60, 0xa4, 0x04, +0x06, 0x60, 0x00, 0x08, +0xda, 0x8a, 0x08, 0x11, +0xbc, 0x0c, 0xf8, 0x81, +0x39, 0x5c, 0x83, 0x00, +0x81, 0x79, 0x00, 0x00, +0x08, 0x12, 0x21, 0x88, +0x0e, 0x26, 0x60, 0x00, +0x08, 0xe8, 0x8a, 0x40, +0x40, 0x88, 0x0a, 0x0b, +0x00, 0x26, 0x94, 0x06, +0x60, 0x00, 0x00, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0x5c, 0x81, 0x02, +0xbf, 0x70, 0x68, 0x20, +0x00, 0x23, 0x2c, 0x5c, +0x07, 0xe2, 0x40, 0x41, +0x80, 0x86, 0xc6, 0x82, +0x00, 0x28, 0xd2, 0xc8, +0x08, 0x6c, 0x68, 0x20, +0x02, 0x8e, 0x2c, 0x80, +0x86, 0xc6, 0x82, 0x00, +0x28, 0xf2, 0xc8, 0x08, +0x6c, 0x68, 0x20, 0x02, +0x90, 0x2c, 0x80, 0x86, +0xc6, 0x82, 0x00, 0x29, +0x12, 0xc8, 0x08, 0x6c, +0x68, 0x20, 0x02, 0x97, +0x2c, 0x80, 0x86, 0xc8, +0x08, 0x7a, 0x68, 0x20, +0x02, 0x92, 0x2c, 0x80, +0x86, 0xc8, 0x08, 0x7a, +0x68, 0x20, 0x02, 0x93, +0x2c, 0x80, 0x86, 0xc6, +0x82, 0x00, 0x29, 0x42, +0xc8, 0x08, 0x6c, 0x68, +0x20, 0x02, 0x95, 0x2c, +0x84, 0x86, 0xca, 0x08, +0x21, 0x68, 0x20, 0x02, +0x96, 0x2c, 0x84, 0x22, +0x28, 0x48, 0x6c, 0xa0, +0x82, 0x19, 0x50, 0xae, +0x55, 0x21, 0x80, 0x48, +0x6c, 0x51, 0x84, 0x02, +0x08, 0x21, 0x58, 0x09, +0x80, 0x48, 0x7a, 0xa0, +0xde, 0x19, 0x84, 0x28, +0x9c, 0x80, 0x1a, 0x00, +0x03, 0x42, 0x1a, 0xe0, +0x48, 0x20, 0x98, 0x80, +0x83, 0x20, 0x20, 0xbc, +0x2f, 0x09, 0x5c, 0xac, +0x32, 0x0a, 0x0b, 0xc2, +0x00, 0x32, 0x1a, 0x0b, +0xc2, 0xd1, 0x5c, 0x0e, +0x22, 0x19, 0x01, 0x84, +0x80, 0xa2, 0x59, 0x30, +0xbc, 0x05, 0x9a, 0x0c, +0xe1, 0xba, 0x14, 0x8a, +0x80, 0x90, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x20, 0x02, 0x7d, 0x24, +0x68, 0x00, 0x02, 0x36, +0x2c, 0x9e, 0x00, 0x48, +0x60, 0x00, 0x98, 0xb0, +0x23, 0x00, 0x80, 0xbc, +0x05, 0x98, 0x48, 0x50, +0xba, 0x14, 0x8a, 0x80, +0x90, 0x40, 0x00, 0x03, +0x80, 0x00, 0x52, 0x09, +0xa2, 0x10, 0x11, 0x85, +0xc4, 0x86, 0x40, 0x00, +0x08, 0xda, 0xfa, 0x80, +0x90, 0xa1, 0x8a, 0x1a, +0x0c, 0x62, 0x84, 0x82, +0x18, 0x80, 0x62, 0x88, +0x0f, 0x66, 0x60, 0x00, +0x08, 0xe8, 0x08, 0x80, +0x20, 0x88, 0x0b, 0x64, +0x20, 0x27, 0xb0, 0x02, +0x49, 0x40, 0x64, 0xba, +0x14, 0x8a, 0x80, 0x90, +0x00, 0x00, 0x0b, 0xa1, +0x48, 0xa8, 0x09, 0x00, +0x00, 0x00, 0x84, 0x22, +0x1b, 0x07, 0x84, 0x94, +0x8a, 0xe2, 0x89, 0x34, +0x32, 0x02, 0x0b, 0xc0, +0xa0, 0x38, 0x08, 0x63, +0x01, 0xa0, 0xbc, 0x05, +0x03, 0x81, 0x06, 0x30, +0x1a, 0x0b, 0xc0, 0x61, +0x64, 0x00, 0x00, 0xb5, +0x07, 0x64, 0x00, 0x00, +0xb4, 0x07, 0x64, 0x00, +0x00, 0xb3, 0x07, 0x40, +0x00, 0x03, 0xa1, 0x40, +0xa0, 0x0a, 0x1a, 0x08, +0x60, 0xab, 0xff, 0x08, +0x48, 0x21, 0x88, 0x06, +0x08, 0x80, 0xf6, 0x66, +0x00, 0x00, 0x8e, 0x80, +0x88, 0x02, 0x08, 0x80, +0xb6, 0xa0, 0x4c, 0x04, +0x60, 0xa4, 0x30, 0x02, +0x49, 0x40, 0x64, 0x40, +0x00, 0x02, 0x80, 0x10, +0x5c, 0x04, 0x60, 0x42, +0x20, 0x00, 0x00, 0x09, +0x40, 0xae, 0x30, 0x13, +0x0b, 0xc0, 0x81, 0x6c, +0x40, 0x04, 0x02, 0x08, +0x38, 0x10, 0x65, 0x20, +0xd2, 0x3a, 0x14, 0x86, +0xc4, 0x00, 0x40, 0x24, +0x80, 0x00, 0x00, 0x40, +0x00, 0x03, 0xa1, 0x40, +0xab, 0xfe, 0x0a, 0x00, +0xa1, 0x6c, 0x40, 0x03, +0xba, 0x08, 0x68, 0x00, +0xf0, 0x03, 0x0a, 0x54, +0x4d, 0x22, 0x0c, 0x62, +0xa4, 0x04, 0x08, 0x48, +0x21, 0x84, 0x04, 0x88, +0x80, 0x62, 0x88, 0x0f, +0x66, 0x60, 0x00, 0x08, +0xe8, 0x08, 0x80, 0x20, +0x88, 0x0b, 0x64, 0x60, +0xa4, 0x30, 0x02, 0x49, +0x40, 0x64, 0x40, 0x00, +0x02, 0x80, 0x20, 0x68, +0x20, 0x02, 0x01, 0x20, +0x38, 0x16, 0x48, 0x40, +0x0a, 0x25, 0x93, 0x0b, +0xc0, 0x61, 0x5c, 0x0c, +0x22, 0xc6, 0x80, 0x52, +0x09, 0x82, 0x00, 0x01, +0xbc, 0x07, 0xf8, 0x00, +0x50, 0x5c, 0x0e, 0x22, +0xc0, 0x20, 0x52, 0x09, +0xa2, 0x00, 0x01, 0x40, +0x00, 0x00, 0x00, 0x48, +0x5c, 0x80, 0x49, 0x88, +0x0b, 0x68, 0x34, 0x0c, +0x08, 0x20, 0x5c, 0x81, +0x02, 0x0c, 0x39, 0x5c, +0x00, 0x69, 0x8e, 0x88, +0x68, 0x00, 0x03, 0xff, +0x00, 0x54, 0x41, 0xf9, +0x48, 0xc4, 0x5c, 0x08, +0x30, 0x40, 0x4b, 0xa0, +0x02, 0x0a, 0x00, 0x02, +0x94, 0x8c, 0x49, 0x48, +0x64, 0xb0, 0x66, 0x48, +0x00, 0x48, 0xa0, 0x82, +0x98, 0x48, 0x08, 0x52, +0x4d, 0x20, 0x50, 0xfa, +0x46, 0x0a, 0x40, 0x40, +0xc9, 0x84, 0x84, 0x80, +0x00, 0x00, 0x68, 0x00, +0x02, 0xe6, 0xa0, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x29, 0xc6, 0x00, 0x00, +0x00, 0xab, 0xfd, 0x08, +0x80, 0x76, 0x68, 0x00, +0x01, 0x14, 0x20, 0x66, +0x00, 0x00, 0xd8, 0x00, +0x68, 0x00, 0x01, 0x1f, +0x20, 0x66, 0x00, 0x00, +0xd8, 0x00, 0x68, 0x00, +0x01, 0x2a, 0x20, 0x66, +0x00, 0x00, 0xd8, 0x00, +0x68, 0x00, 0x01, 0x1f, +0x20, 0x5c, 0x81, 0x0a, +0xc0, 0xc0, 0xa0, 0x0e, +0x06, 0x80, 0x00, 0x11, +0x42, 0x46, 0xc4, 0x00, +0x39, 0x40, 0x98, 0x00, +0x88, 0x44, 0x09, 0x02, +0x20, 0xe4, 0x68, 0x00, +0x01, 0x2a, 0x21, 0x6c, +0x40, 0x03, 0x8c, 0x09, +0x82, 0x08, 0x84, 0x40, +0x88, 0x20, 0x8e, 0x16, +0xc4, 0x00, 0x39, 0xc0, +0x98, 0x08, 0x88, 0x44, +0x08, 0x01, 0x80, 0x8a, +0x6c, 0x40, 0x00, 0x42, +0x08, 0x46, 0x08, 0x89, +0x80, 0x09, 0x4d, 0x25, +0x00, 0x02, 0x4a, 0x51, +0x62, 0x09, 0x80, 0x4a, +0x44, 0x40, 0x00, 0x0a, +0x49, 0x51, 0x62, 0x00, +0x22, 0x4a, 0x51, 0x62, +0x91, 0x83, 0x09, 0x88, +0x2e, 0x48, 0x80, 0xcd, +0x84, 0x84, 0xe8, 0x81, +0xc9, 0x88, 0x16, 0x18, +0x82, 0x60, 0x68, 0x20, +0x01, 0x90, 0x24, 0x66, +0x00, 0x00, 0xd8, 0x68, +0x46, 0x08, 0x08, 0x80, +0x8a, 0x88, 0x2a, 0x08, +0x80, 0x89, 0x84, 0x04, +0x86, 0x82, 0x00, 0x19, +0x22, 0x46, 0x60, 0x00, +0x0d, 0x86, 0x88, 0x81, +0x8a, 0x5c, 0x82, 0x00, +0x82, 0xa0, 0x88, 0x22, +0x48, 0x00, 0x09, 0x86, +0x04, 0x88, 0x80, 0xe0, +0x68, 0x20, 0x01, 0x80, +0x24, 0x68, 0x00, 0x00, +0xf2, 0x20, 0x66, 0x00, +0x00, 0x3d, 0xe0, 0x5c, +0x82, 0x00, 0x82, 0x20, +0x88, 0x2a, 0x48, 0x00, +0x09, 0x86, 0x14, 0x88, +0x81, 0xe0, 0x68, 0x20, +0x01, 0x80, 0x24, 0x68, +0x00, 0x00, 0xfe, 0x20, +0x66, 0x00, 0x00, 0x3d, +0xe0, 0x5c, 0x82, 0x00, +0x81, 0x20, 0x88, 0x22, +0x48, 0x00, 0x09, 0x86, +0x14, 0x88, 0x82, 0x60, +0x68, 0x20, 0x01, 0x80, +0x24, 0x68, 0x00, 0x01, +0x0a, 0x20, 0x66, 0x00, +0x00, 0x3d, 0xe0, 0x5c, +0x81, 0x00, 0x80, 0xa1, +0x68, 0x20, 0x01, 0x80, +0x20, 0x88, 0x12, 0x2a, +0x00, 0x64, 0x80, 0x80, +0x98, 0x51, 0x48, 0x88, +0x0e, 0x48, 0x81, 0x61, +0x68, 0x00, 0x00, 0xf2, +0x23, 0x66, 0x00, 0x00, +0x3d, 0xe8, 0x40, 0x00, +0x02, 0x18, 0x40, 0x5c, +0x85, 0x08, 0x81, 0x21, +0x5c, 0x81, 0x00, 0x81, +0xa2, 0x80, 0xac, 0x88, +0x81, 0x61, 0x68, 0x00, +0x00, 0xfe, 0x20, 0x81, +0x00, 0x98, 0x80, 0xa4, +0x88, 0x1e, 0x26, 0x60, +0x00, 0x03, 0xde, 0x8a, +0x00, 0x40, 0x5c, 0x85, +0x08, 0x82, 0x21, 0x5c, +0x81, 0x00, 0x81, 0xa2, +0x80, 0x80, 0x98, 0x12, +0xc8, 0x88, 0x1e, 0x26, +0x80, 0x00, 0x10, 0xa2, +0x08, 0x80, 0xa4, 0x88, +0x0e, 0x16, 0x60, 0x00, +0x03, 0xde, 0x8a, 0x00, +0x40, 0x5c, 0x85, 0x00, +0x80, 0xa4, 0x88, 0x12, +0x08, 0x22, 0x48, 0x88, +0x0e, 0x46, 0x60, 0x00, +0x0d, 0x8c, 0x08, 0x81, +0xa0, 0x66, 0x00, 0x00, +0xd8, 0xc0, 0x88, 0x0a, +0x06, 0x60, 0x00, 0x0d, +0x8c, 0x08, 0x80, 0x36, +0x68, 0x00, 0x03, 0x11, +0xa0, 0xba, 0x14, 0x86, +0xc0, 0x00, 0x29, 0xc6, +0x0a, 0x80, 0x30, 0x68, +0x00, 0x01, 0x25, 0x24, +0xab, 0xfc, 0x06, 0xc0, +0x00, 0x0f, 0x80, 0xb6, +0xc0, 0x00, 0x10, 0xa0, +0x06, 0xc0, 0x00, 0x1c, +0x80, 0x16, 0xc0, 0x00, +0x26, 0x00, 0xa8, 0x60, +0x09, 0x88, 0x05, 0x18, +0x80, 0xd0, 0x88, 0x14, +0xb8, 0x81, 0xf6, 0x68, +0x00, 0x01, 0x1a, 0x20, +0x66, 0x00, 0x00, 0xde, +0xe8, 0x40, 0x00, 0x00, +0x40, 0x08, 0x68, 0x00, +0x01, 0x1a, 0x20, 0x68, +0x20, 0x01, 0xcf, 0x24, +0x5c, 0x83, 0x02, 0xc0, +0x21, 0x68, 0x00, 0x01, +0x25, 0x21, 0xd8, 0x8c, +0x15, 0x70, 0xf4, 0x80, +0xa0, 0x08, 0x60, 0x09, +0x57, 0x0a, 0x00, 0x83, +0x60, 0x88, 0x24, 0x08, +0x82, 0xe1, 0x68, 0x20, +0x01, 0x7d, 0x24, 0x68, +0x00, 0x00, 0xf0, 0x20, +0x66, 0x00, 0x00, 0x3d, +0xe8, 0x40, 0x00, 0x01, +0x80, 0x49, 0x68, 0x20, +0x01, 0x7d, 0x24, 0x68, +0x00, 0x00, 0xfc, 0x20, +0x66, 0x00, 0x00, 0x3d, +0xe8, 0x40, 0x00, 0x00, +0x82, 0x09, 0x68, 0x00, +0x00, 0xf0, 0x20, 0x68, +0x20, 0x01, 0x94, 0x24, +0x84, 0x08, 0x96, 0x80, +0x00, 0x15, 0x02, 0x06, +0x60, 0x00, 0x03, 0xde, +0x08, 0x83, 0x20, 0x68, +0x00, 0x00, 0xfc, 0x21, +0x84, 0x04, 0x86, 0x82, +0x00, 0x19, 0x42, 0x46, +0x80, 0x00, 0x15, 0x22, +0x06, 0x60, 0x00, 0x03, +0xde, 0x88, 0x48, 0x89, +0x55, 0x01, 0x28, 0x83, +0x20, 0x5c, 0x83, 0x00, +0x82, 0xa4, 0x80, 0x20, +0x88, 0x60, 0x49, 0x40, +0x00, 0x00, 0x82, 0x60, +0x68, 0x00, 0x00, 0xf0, +0x21, 0x68, 0x20, 0x01, +0x7d, 0x24, 0x68, 0x00, +0x01, 0x3b, 0x22, 0x66, +0x00, 0x00, 0xd9, 0x40, +0x5c, 0x83, 0x00, 0x82, +0xa0, 0x68, 0x00, 0x00, +0xfc, 0x21, 0x80, 0x20, +0x88, 0x82, 0xe0, 0x68, +0x20, 0x01, 0x7d, 0x24, +0x68, 0x00, 0x01, 0x3d, +0x22, 0x66, 0x00, 0x00, +0xd9, 0x40, 0x5c, 0x83, +0x00, 0x82, 0x20, 0x68, +0x20, 0x01, 0xde, 0x24, +0xa0, 0x12, 0x08, 0x02, +0x09, 0x40, 0x00, 0x00, +0x82, 0x60, 0x68, 0x00, +0x01, 0x54, 0x20, 0x66, +0x00, 0x00, 0x3d, 0xe0, +0x5c, 0x83, 0x00, 0x82, +0xa0, 0x68, 0x20, 0x01, +0xde, 0x24, 0xa0, 0x12, +0x08, 0x02, 0x09, 0x88, +0x2e, 0x06, 0x80, 0x00, +0x15, 0x62, 0x06, 0x60, +0x00, 0x03, 0xde, 0x08, +0x81, 0x09, 0x36, 0x94, +0x46, 0xc4, 0x00, 0x03, +0xe0, 0xb5, 0x80, 0xf0, +0x18, 0xe8, 0x8b, 0xc0, +0x3a, 0x55, 0x01, 0x00, +0x80, 0x89, 0xb0, 0x00, +0xc3, 0x69, 0x41, 0x30, +0x1c, 0x8b, 0xc0, 0x3a, +0x55, 0x00, 0x08, 0x80, +0x09, 0xb0, 0x00, 0x93, +0x69, 0x45, 0x30, 0x1e, +0x8b, 0xc0, 0x12, 0xb0, +0x00, 0x83, 0x20, 0x20, +0xbc, 0x05, 0x98, 0x82, +0x20, 0x32, 0x00, 0x0b, +0xc0, 0x21, 0x32, 0x00, +0x8b, 0xc0, 0x60, 0x6c, +0x40, 0x00, 0x40, 0x09, +0x6c, 0x00, 0x02, 0x88, +0x49, 0x6c, 0x00, 0x02, +0x8a, 0x49, 0x39, 0x0c, +0x08, 0x02, 0x09, 0x40, +0x00, 0x00, 0x80, 0x60, +0x68, 0x20, 0x00, 0xaa, +0x24, 0x68, 0x00, 0x01, +0x40, 0x20, 0x66, 0x00, +0x00, 0x3d, 0xe0, 0x5c, +0x86, 0x00, 0x82, 0xa0, +0x88, 0x0c, 0x86, 0x82, +0x00, 0x0c, 0x22, 0x48, +0x02, 0x09, 0x40, 0x00, +0x00, 0x81, 0x60, 0x68, +0x00, 0x01, 0x42, 0x20, +0x66, 0x00, 0x00, 0x3d, +0xe0, 0x66, 0x00, 0x00, +0xe1, 0xa8, 0x55, 0x01, +0x28, 0x80, 0x88, 0x6c, +0x00, 0x02, 0x88, 0x09, +0x32, 0x02, 0x8b, 0xc0, +0x84, 0x68, 0x00, 0x01, +0x1d, 0x20, 0x39, 0x06, +0x28, 0x40, 0x09, 0x42, +0x08, 0xf8, 0x40, 0xc9, +0x5c, 0x81, 0x02, 0xc0, +0x41, 0x68, 0x00, 0x00, +0xf7, 0x20, 0x5c, 0x82, +0x0a, 0xc0, 0x20, 0x5c, +0x83, 0x10, 0x00, 0xfa, +0x55, 0x3f, 0x68, 0x02, +0x7a, 0x80, 0x17, 0xa8, +0x02, 0x7a, 0x6c, 0x00, +0x02, 0x88, 0x49, 0x6c, +0x00, 0x02, 0x3c, 0x7a, +0x84, 0x07, 0xa0, 0x00, +0x00, 0x6c, 0x00, 0x02, +0x8a, 0x09, 0x32, 0x02, +0x8b, 0xc0, 0x64, 0x68, +0x00, 0x01, 0x28, 0x20, +0x00, 0x00, 0x08, 0x40, +0x09, 0x42, 0x06, 0x38, +0x40, 0xc9, 0x68, 0x00, +0x01, 0x03, 0x20, 0x2a, +0x7e, 0xd8, 0x00, 0xfa, +0x80, 0x27, 0xa8, 0x01, +0x7a, 0x80, 0x27, 0xa6, +0xc0, 0x00, 0x28, 0xa4, +0x96, 0xc0, 0x00, 0x25, +0x27, 0xa8, 0x40, 0x7a, +0x00, 0x00, 0x06, 0xc0, +0x00, 0x29, 0x00, 0x93, +0x20, 0x28, 0xbc, 0x04, +0x06, 0xc0, 0x00, 0x23, +0xc7, 0xa6, 0xc0, 0x00, +0x25, 0x27, 0xa3, 0x81, +0x2c, 0x6e, 0x00, 0x01, +0x2c, 0x2d, 0x25, 0x92, +0x8b, 0xc2, 0xc9, 0x88, +0x02, 0x03, 0x81, 0x3c, +0x25, 0x92, 0x8b, 0xc2, +0x81, 0x6c, 0x00, 0x02, +0xaa, 0x09, 0x36, 0x94, +0x06, 0xc4, 0x00, 0x3b, +0x20, 0x99, 0x80, 0x08, +0x30, 0x96, 0x0b, 0xc1, +0x24, 0x6c, 0x00, 0x02, +0xae, 0x08, 0x36, 0x90, +0x09, 0x80, 0x08, 0x30, +0x96, 0x0b, 0xc0, 0xc4, +0x6c, 0x40, 0x03, 0xb6, +0x09, 0x32, 0x02, 0x8b, +0xc1, 0x60, 0x2a, 0x7e, +0xd6, 0xc0, 0x00, 0x25, +0x27, 0xa6, 0xc0, 0x00, +0x23, 0xc7, 0xa6, 0xc4, +0x00, 0x3b, 0x64, 0x9b, +0xc0, 0xe7, 0x68, 0x20, +0x01, 0xda, 0x24, 0x6c, +0x40, 0x02, 0xc4, 0x09, +0x86, 0x00, 0x86, 0xc0, +0x00, 0x25, 0x27, 0xa6, +0xc0, 0x00, 0x23, 0xc7, +0xa6, 0xc4, 0x00, 0x15, +0x04, 0x96, 0xc4, 0x00, +0x18, 0x04, 0x98, 0x60, +0xc8, 0x68, 0x00, 0x00, +0xeb, 0x21, 0x66, 0x00, +0x00, 0xde, 0x00, 0x88, +0x12, 0x06, 0x80, 0x00, +0x0e, 0xd2, 0x16, 0x60, +0x00, 0x0d, 0xe0, 0x08, +0x81, 0xb6, 0x68, 0x00, +0x03, 0x5e, 0xa0, 0xba, +0x14, 0x86, 0xc0, 0x00, +0x29, 0xc6, 0x0a, 0x80, +0x40, 0x68, 0x00, 0x02, +0xe5, 0x20, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x29, +0xc6, 0x00, 0x00, 0x00, +0x84, 0x00, 0x88, 0x40, +0x8a, 0x57, 0x0d, 0x03, +0xa1, 0x48, 0x84, 0x3c, +0x00, 0x00, 0x00, 0x86, +0x00, 0x84, 0x42, 0x00, +0x06, 0x08, 0x9b, 0xa1, +0x48, 0x08, 0x98, 0x09, +0x80, 0x08, 0xa0, 0x04, +0x0a, 0x00, 0x61, 0x84, +0x00, 0x88, 0x48, 0x0a, +0x57, 0x0d, 0x03, 0xa1, +0x48, 0x84, 0x8c, 0x00, +0x00, 0x00, 0x5c, 0x81, +0x02, 0x22, 0x23, 0x81, +0x80, 0x94, 0x40, 0x80, +0x05, 0x80, 0x95, 0x00, +0xa0, 0x20, 0x8c, 0x19, +0x80, 0x09, 0x80, 0x84, +0x9a, 0x1c, 0x64, 0x82, +0x00, 0x84, 0x42, 0x00, +0x06, 0x00, 0x98, 0x48, +0x08, 0x44, 0x0c, 0x02, +0xbf, 0xd0, 0x98, 0x00, +0x9a, 0x24, 0xe4, 0x80, +0x84, 0x98, 0x80, 0x61, +0x88, 0x0e, 0x48, 0x81, +0x62, 0x88, 0x1e, 0x08, +0x82, 0x76, 0x66, 0x00, +0x00, 0x3d, 0xe8, 0xa0, +0x80, 0x08, 0x80, 0x20, +0x88, 0x0a, 0x2a, 0x00, +0x40, 0x88, 0x06, 0x06, +0x60, 0x00, 0x03, 0xde, +0x85, 0x50, 0x12, 0xa1, +0x06, 0x48, 0x80, 0x20, +0x88, 0x12, 0x2a, 0x04, +0x60, 0x84, 0x00, 0x95, +0x70, 0x94, 0x05, 0x08, +0x95, 0x70, 0xa0, 0x08, +0x1a, 0x09, 0x80, 0x08, +0x59, 0x01, 0x00, 0x44, +0xc8, 0xbc, 0x0e, 0x43, +0x20, 0x20, 0xbc, 0x17, +0x38, 0x50, 0x08, 0x2e, +0x12, 0xd5, 0xb4, 0xa0, +0x05, 0x0c, 0x99, 0x80, +0x09, 0x6c, 0x40, 0x02, +0x02, 0x08, 0x30, 0x12, +0x8b, 0xc0, 0xe5, 0x36, +0x10, 0x58, 0x50, 0xc9, +0xbc, 0x0b, 0x78, 0x50, +0x08, 0x28, 0x12, 0xd5, +0xb4, 0xa0, 0x05, 0x0c, +0x99, 0x80, 0x09, 0x6c, +0x40, 0x02, 0x02, 0x08, +0x30, 0x12, 0x8b, 0xc0, +0x25, 0x85, 0x0c, 0x80, +0x00, 0x00, 0x88, 0x23, +0x6b, 0xa1, 0x48, 0xa8, +0x03, 0x00, 0x00, 0x00, +0x84, 0x50, 0x86, 0xc4, +0x00, 0x34, 0x20, 0xa4, +0x41, 0x00, 0x3a, 0x11, +0x19, 0x80, 0x08, 0x68, +0x03, 0x94, 0xbb, 0x8a, +0x08, 0x20, 0x05, 0x15, +0xc0, 0x3a, 0x14, 0x88, +0x48, 0xcc, 0x40, 0x00, +0x03, 0xa1, 0x01, 0x44, +0x19, 0x81, 0x82, 0x02, +0x5b, 0x0c, 0x22, 0xbf, +0xf0, 0x44, 0x18, 0x81, +0x84, 0x4b, 0x44, 0x39, +0x01, 0x84, 0x88, 0x5b, +0x08, 0x28, 0x80, 0x49, +0x44, 0x38, 0x01, 0x84, +0x09, 0x44, 0x49, 0x81, +0x80, 0xca, 0x51, 0x85, +0xa0, 0x80, 0x0a, 0x5b, +0x0c, 0x31, 0x80, 0x8b, +0x44, 0x48, 0x81, 0xa1, +0x42, 0x55, 0x01, 0x11, +0x80, 0x08, 0x51, 0x85, +0xc2, 0xc0, 0x20, 0x51, +0x85, 0x59, 0x80, 0x49, +0x23, 0x0a, 0x42, 0x30, +0xb6, 0x11, 0x64, 0x85, +0x18, 0x56, 0x1a, 0x04, +0x26, 0xc4, 0x00, 0x04, +0x40, 0xb6, 0x82, 0x00, +0x1c, 0xf2, 0x01, 0x12, +0x83, 0x44, 0x38, 0x01, +0x80, 0x0a, 0x44, 0x58, +0x80, 0x00, 0x42, 0x46, +0x0a, 0x40, 0x00, 0x40, +0x84, 0x04, 0x1a, 0x80, +0x10, 0x6e, 0x00, 0x01, +0x2c, 0x2e, 0x38, 0x13, +0x22, 0x58, 0xb0, 0xbc, +0x05, 0x82, 0xa0, 0x2a, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x29, 0x07, 0xa0, +0x00, 0x00, 0x68, 0x00, +0x01, 0x46, 0x21, 0x68, +0x20, 0x01, 0xd2, 0x24, +0x5c, 0x81, 0x08, 0x48, +0x0b, 0x5c, 0x82, 0x00, +0x20, 0x8a, 0x68, 0x00, +0x01, 0x4a, 0x20, 0x30, +0x1b, 0x84, 0x20, 0xec, +0x00, 0x00, 0x08, 0x02, +0x89, 0x68, 0x00, 0x01, +0x46, 0x20, 0x55, 0x03, +0xf2, 0xc0, 0xa0, 0x58, +0x01, 0x00, 0x00, 0x4a, +0xbc, 0x03, 0x56, 0xc0, +0x00, 0x29, 0x44, 0x80, +0x00, 0x00, 0x84, 0x00, +0xa3, 0x01, 0xa0, 0xbc, +0x02, 0x36, 0xc0, 0x00, +0x29, 0x64, 0x83, 0x01, +0x50, 0xbc, 0x03, 0x56, +0xc0, 0x00, 0x29, 0x85, +0x20, 0x00, 0x00, 0x84, +0x10, 0x83, 0x01, 0x10, +0xbc, 0x04, 0x3b, 0xa1, +0x48, 0x6c, 0x00, 0x02, +0x9a, 0x52, 0x00, 0x00, +0x0b, 0xa1, 0x40, 0x80, +0x00, 0x25, 0x70, 0x40, +0x86, 0x00, 0x35, 0x84, +0x64, 0x00, 0x28, 0x84, +0x20, 0x1d, 0x98, 0xe8, +0xa5, 0x70, 0x94, 0x98, +0x28, 0xbb, 0x00, 0x0e, +0x30, 0x8c, 0x8b, 0xc0, +0x23, 0x40, 0x00, 0x03, +0x00, 0x0f, 0x5b, 0x40, +0x00, 0x60, 0x83, 0x36, +0x88, 0x22, 0xf0, 0x82, +0x30, 0x8d, 0x03, 0x69, +0x45, 0x5b, 0x48, 0x23, +0xc3, 0x6b, 0x2f, 0x12, +0xc3, 0x08, 0xe0, 0xbc, +0x33, 0x33, 0x20, 0x30, +0xbc, 0x04, 0x86, 0xc4, +0x00, 0x3a, 0xa0, 0x83, +0x20, 0x38, 0xbc, 0x0f, +0x13, 0x20, 0x30, 0xbc, +0x17, 0x13, 0x20, 0x38, +0xbc, 0x15, 0x16, 0xc0, +0x00, 0x29, 0x20, 0x93, +0x20, 0x28, 0xbc, 0x11, +0x56, 0xc4, 0x00, 0x3a, +0xe0, 0xa2, 0xe1, 0xad, +0x6c, 0x00, 0x02, 0x92, +0x49, 0x40, 0x00, 0x03, +0xc0, 0xa7, 0x6c, 0x00, +0x02, 0x92, 0x09, 0x30, +0x12, 0x8b, 0xc0, 0x63, +0x6c, 0x40, 0x03, 0xac, +0x0a, 0x28, 0x1a, 0xd6, +0xc0, 0x00, 0x29, 0x24, +0x90, 0x00, 0x00, 0x6c, +0x00, 0x02, 0x92, 0x09, +0x32, 0x06, 0x8b, 0xc0, +0x63, 0x68, 0x00, 0x01, +0x48, 0x21, 0x6c, 0x00, +0x02, 0x90, 0x7a, 0x84, +0x8f, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x02, 0x92, +0x09, 0x30, 0x12, 0x8b, +0xc0, 0x6a, 0x38, 0x00, +0xd6, 0x80, 0x00, 0x14, +0x82, 0x16, 0xc0, 0x00, +0x29, 0x04, 0x98, 0x48, +0xc8, 0x68, 0x20, 0x00, +0xec, 0x21, 0x39, 0x0a, +0x18, 0x48, 0x08, 0x80, +0x24, 0x88, 0x40, 0x48, +0xa0, 0x06, 0x08, 0x48, +0x88, 0x80, 0x24, 0x84, +0x60, 0xa4, 0x00, 0x2c, +0x88, 0x40, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0xb0, 0x50, 0x46, 0xc0, +0x00, 0x27, 0xa4, 0x86, +0xc0, 0x00, 0x36, 0x44, +0x8b, 0xa1, 0x48, 0x6c, +0x00, 0x02, 0x76, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x5c, 0x81, 0x01, +0x8e, 0x88, 0x68, 0x00, +0x00, 0xf0, 0x20, 0x68, +0x00, 0x00, 0xfc, 0x21, +0x68, 0x00, 0x01, 0x08, +0x22, 0x55, 0x01, 0x33, +0x80, 0x00, 0x55, 0x03, +0xb0, 0x00, 0x7a, 0x5d, +0x0c, 0x30, 0x08, 0x7a, +0x32, 0x2b, 0x0b, 0xff, +0xaa, 0x40, 0x00, 0x00, +0x10, 0x7a, 0x68, 0x00, +0x01, 0x21, 0x22, 0x68, +0x00, 0x01, 0x2c, 0x21, +0x68, 0x00, 0x01, 0x16, +0x20, 0x55, 0x03, 0x20, +0x10, 0x7a, 0x5d, 0x08, +0x20, 0x08, 0x7a, 0x32, +0x26, 0x0b, 0xff, 0xaa, +0x80, 0x07, 0xa6, 0x80, +0x00, 0x14, 0x62, 0x06, +0x82, 0x00, 0x0e, 0xc2, +0x15, 0xc8, 0x20, 0x80, +0x07, 0xa5, 0xc0, 0x16, +0x04, 0x0f, 0xa8, 0x00, +0x7a, 0xa0, 0x08, 0x08, +0x48, 0x0a, 0x80, 0x2c, +0xa8, 0x40, 0x4a, 0xa0, +0x06, 0x08, 0x48, 0x8a, +0x80, 0x2c, 0xa6, 0x80, +0x00, 0x14, 0x42, 0x16, +0x80, 0x00, 0x2e, 0x52, +0xc8, 0x02, 0xca, 0x6c, +0x00, 0x02, 0x9c, 0x6c, +0x84, 0x87, 0xa4, 0x60, +0xa4, 0x04, 0x04, 0x88, +0x48, 0xfa, 0x40, 0x00, +0x03, 0x80, 0x00, 0x5c, +0x00, 0x32, 0xbf, 0xd0, +0x88, 0x04, 0x88, 0x80, +0xf6, 0x88, 0x17, 0xa2, +0x30, 0xb6, 0x98, 0x2a, +0x86, 0x82, 0x00, 0x00, +0x52, 0x06, 0x60, 0x00, +0x14, 0xee, 0x89, 0xc0, +0x00, 0x88, 0x10, 0xa5, +0x50, 0x3b, 0x08, 0x00, +0x03, 0xa9, 0x86, 0x2a, +0x04, 0x45, 0x90, 0x58, +0x08, 0x04, 0x8b, 0xff, +0x1a, 0x88, 0x14, 0xa6, +0x60, 0x00, 0x14, 0xee, +0x8a, 0x40, 0x80, 0x6c, +0x40, 0x00, 0x0a, 0x0a, +0x5d, 0x4c, 0x02, 0xc0, +0x20, 0x68, 0x20, 0x00, +0x05, 0x20, 0x68, 0x20, +0x00, 0x85, 0x21, 0x51, +0xa0, 0x00, 0x40, 0x82, +0x51, 0xe1, 0xb0, 0x82, +0x01, 0x51, 0xa1, 0xb0, +0x80, 0xb6, 0x5d, 0x44, +0x38, 0x08, 0x50, 0x51, +0xe0, 0xb0, 0x08, 0x4a, +0x23, 0x43, 0x85, 0x1a, +0x1b, 0x00, 0x85, 0x05, +0x15, 0x06, 0x00, 0x84, +0xa4, 0x60, 0xa4, 0x14, +0x86, 0x19, 0x48, 0xe4, +0x40, 0x00, 0x02, 0x80, +0x30, 0x59, 0x01, 0x02, +0xbf, 0x50, 0x68, 0x00, +0x01, 0x7e, 0x20, 0xbc, +0x07, 0x85, 0xc0, 0x02, +0x08, 0x17, 0x60, 0x00, +0x00, 0x6c, 0x00, 0x03, +0x0a, 0x08, 0xbc, 0x17, +0xf8, 0x86, 0xc8, 0x88, +0x24, 0x88, 0x81, 0xe0, +0x68, 0x00, 0x40, 0x01, +0x88, 0x88, 0x2c, 0x86, +0x60, 0x00, 0x14, 0xee, +0x08, 0x82, 0x08, 0x55, +0x03, 0x20, 0x81, 0xa0, +0x5d, 0x48, 0x30, 0x82, +0x88, 0x59, 0x0f, 0x82, +0x00, 0x20, 0x43, 0xfa, +0x50, 0x81, 0xe0, 0x55, +0x03, 0x20, 0x82, 0x4a, +0x66, 0x00, 0x01, 0x4e, +0xe8, 0x40, 0x00, 0x02, +0x41, 0xa0, 0x68, 0x00, +0x01, 0x81, 0x22, 0x5c, +0x81, 0x02, 0x40, 0xc0, +0x5c, 0x00, 0x09, 0x50, +0x37, 0x95, 0x0b, 0x56, +0x80, 0x00, 0x17, 0xe2, +0x22, 0x30, 0x8c, 0x55, +0x02, 0x61, 0x82, 0x29, +0x5d, 0x48, 0x09, 0xd0, +0x81, 0x59, 0x0e, 0x41, +0x48, 0x36, 0x57, 0x0f, +0x91, 0x48, 0xb4, 0x57, +0x0b, 0x01, 0xc0, 0x83, +0x43, 0xf9, 0xd1, 0x58, +0x72, 0x95, 0x8f, 0x05, +0xc8, 0x60, 0xa4, 0x1c, +0x38, 0x86, 0x88, 0x51, +0xa1, 0x22, 0x00, 0x22, +0x5b, 0x08, 0x10, 0x81, +0xe2, 0x51, 0x58, 0x82, +0x40, 0xc1, 0x2e, 0x11, +0x22, 0xe1, 0x11, 0x22, +0xb0, 0x95, 0x15, 0x89, +0x01, 0x84, 0x15, 0x15, +0x93, 0x01, 0x84, 0x25, +0x40, 0x90, 0x01, 0x84, +0x05, 0x40, 0x81, 0x01, +0x87, 0xa5, 0x15, 0x80, +0x01, 0x84, 0xa5, 0x15, +0x88, 0x01, 0x84, 0x08, +0x1a, 0xc0, 0x88, 0x06, +0x38, 0x82, 0x63, 0x68, +0x20, 0x00, 0x90, 0x23, +0x68, 0x20, 0x00, 0x8a, +0x24, 0x68, 0x20, 0x00, +0x8d, 0x25, 0x66, 0x00, +0x01, 0x00, 0xe8, 0x40, +0x00, 0x02, 0x00, 0x60, +0x5c, 0x81, 0x00, 0x86, +0x88, 0x51, 0x61, 0x20, +0x82, 0x23, 0x51, 0xa1, +0x22, 0xc0, 0xc1, 0x5b, +0x08, 0x10, 0x81, 0xa0, +0x22, 0xb1, 0x05, 0x70, +0x89, 0x20, 0x05, 0x05, +0x70, 0x88, 0xa0, 0x46, +0x12, 0x2b, 0x09, 0x51, +0x58, 0x90, 0x18, 0x41, +0x51, 0x59, 0x30, 0x18, +0x42, 0x54, 0x09, 0x00, +0x18, 0x40, 0x54, 0x08, +0x10, 0x18, 0x7a, 0x51, +0x58, 0x00, 0x18, 0x4a, +0x51, 0x58, 0x80, 0x18, +0x40, 0x81, 0xac, 0x08, +0x80, 0x63, 0x68, 0x20, +0x00, 0x98, 0xa3, 0x68, +0x20, 0x00, 0x92, 0xa4, +0x68, 0x20, 0x00, 0x95, +0xa5, 0x66, 0x00, 0x01, +0x00, 0xe8, 0xa0, 0x82, +0x28, 0x81, 0x36, 0xba, +0x14, 0x8a, 0x80, 0xb0, +0x40, 0x00, 0x03, 0x80, +0x00, 0xba, 0x14, 0x82, +0xe1, 0xa8, 0x40, 0x00, +0x01, 0x80, 0x08, 0x59, +0x06, 0x42, 0xbf, 0xd0, +0x49, 0xa9, 0xb8, 0x80, +0x76, 0xbc, 0x19, 0x89, +0xa0, 0x00, 0x32, 0x03, +0x0b, 0xc0, 0x29, 0x38, +0x10, 0x02, 0xa0, 0x76, +0x68, 0x00, 0x09, 0xc4, +0x09, 0x50, 0x41, 0x83, +0xa1, 0x11, 0x44, 0x08, +0x81, 0x01, 0x58, 0x5b, +0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x02, 0x55, +0x88, 0x5b, 0x42, 0x0b, +0xa1, 0x01, 0x90, 0x11, +0x19, 0x02, 0x12, 0x29, +0x85, 0x13, 0x20, 0x08, +0xbc, 0x1a, 0x33, 0x60, +0x00, 0x37, 0x80, 0x0b, +0xc1, 0x77, 0x32, 0x02, +0x0b, 0xc0, 0x29, 0x38, +0x10, 0x02, 0xa0, 0x64, +0x68, 0x07, 0xff, 0xff, +0xc9, 0x50, 0x41, 0x03, +0xa1, 0x11, 0x44, 0x48, +0x81, 0x01, 0x58, 0x5b, +0x40, 0x11, 0x02, 0x59, +0x66, 0x00, 0x02, 0x55, +0x88, 0x5b, 0x42, 0x0b, +0xa1, 0x01, 0x90, 0x11, +0x19, 0x02, 0x12, 0x29, +0x85, 0x13, 0x20, 0x08, +0xbc, 0x02, 0x33, 0x60, +0x00, 0x37, 0x80, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x30, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5b, 0x02, 0x03, 0x01, +0x01, 0x50, 0x43, 0x11, +0x84, 0x0a, 0x46, 0x08, +0x89, 0x83, 0x88, 0x44, +0x41, 0x09, 0x84, 0x8b, +0x98, 0x30, 0xa4, 0x47, +0x44, 0xab, 0xfe, 0x05, +0x08, 0x20, 0x08, 0x07, +0x60, 0x88, 0x82, 0x37, +0x80, 0x06, 0x80, 0x00, +0x9c, 0x40, 0x80, 0x84, +0x80, 0x6a, 0x00, 0x4e, +0x20, 0x02, 0x5b, 0x44, +0x11, 0x01, 0x58, 0x66, +0x00, 0x02, 0x55, 0x88, +0x5b, 0x40, 0x0b, 0xa1, +0x01, 0x90, 0x11, 0x26, +0xa0, 0x04, 0xe2, 0x00, +0x12, 0x98, 0x52, 0x32, +0x01, 0x0b, 0xc0, 0x3b, +0x88, 0x03, 0x63, 0x60, +0x00, 0x37, 0x80, 0x0b, +0xa1, 0x48, 0xa8, 0x02, +0x00, 0x00, 0x00, 0xab, +0xf8, 0x09, 0x40, 0x36, +0x88, 0x04, 0xa8, 0x80, +0xe5, 0x88, 0x16, 0x48, +0x81, 0xe3, 0x88, 0x26, +0x28, 0x82, 0xf6, 0x66, +0x00, 0x00, 0xfa, 0xa8, +0x40, 0x00, 0x01, 0x48, +0x35, 0x6a, 0x00, 0x02, +0x71, 0x00, 0x5b, 0x40, +0x00, 0x83, 0x48, 0x5c, +0x00, 0x21, 0x05, 0x58, +0x88, 0x3c, 0x88, 0x84, +0x54, 0x00, 0x00, 0x08, +0x80, 0x0a, 0x51, 0x85, +0x20, 0x82, 0x22, 0x98, +0x22, 0x89, 0xd0, 0x02, +0x88, 0x4e, 0x86, 0x60, +0x00, 0x0f, 0xaa, 0x89, +0x50, 0x35, 0x5b, 0x48, +0x3b, 0x01, 0xfe, 0x25, +0x9a, 0x06, 0x80, 0x01, +0xff, 0xfc, 0xab, 0xc0, +0x88, 0x55, 0x01, 0x00, +0x86, 0x48, 0x30, 0x1b, +0x8b, 0xc0, 0xcd, 0x88, +0x38, 0x16, 0x80, 0x01, +0xff, 0xfc, 0x0b, 0xc0, +0x87, 0x68, 0x00, 0x20, +0x00, 0x0a, 0x30, 0x1b, +0x8b, 0xc0, 0x4d, 0x40, +0x00, 0x00, 0x83, 0x81, +0x68, 0x00, 0x20, 0x00, +0x00, 0x59, 0x0a, 0x40, +0x81, 0xa2, 0xbc, 0x03, +0xb5, 0x50, 0x13, 0xac, +0x01, 0x09, 0x50, 0x50, +0x55, 0x02, 0x60, 0x81, +0xe2, 0x00, 0x00, 0x08, +0x84, 0xa8, 0x88, 0x82, +0x35, 0x18, 0x52, 0x08, +0x4c, 0x89, 0xd8, 0x04, +0x98, 0x22, 0x88, 0x60, +0x08, 0x9d, 0x80, 0x38, +0x83, 0x0a, 0x88, 0x6e, +0x46, 0x60, 0x00, 0x0f, +0xae, 0x88, 0x58, 0x09, +0x88, 0x38, 0x83, 0x20, +0xe0, 0xbc, 0x13, 0x85, +0xc0, 0xfe, 0x19, 0x20, +0x19, 0x05, 0x12, 0x40, +0x00, 0x01, 0x07, 0x58, +0x66, 0x00, 0x02, 0x55, +0x88, 0x5b, 0x40, 0x08, +0x84, 0x16, 0x55, 0x00, +0x09, 0x07, 0x10, 0x6a, +0x00, 0x02, 0x71, 0x02, +0x29, 0x88, 0x23, 0x20, +0x10, 0xbc, 0x03, 0xb3, +0x81, 0xfc, 0x36, 0x04, +0x13, 0x78, 0x41, 0x52, +0xc8, 0x41, 0x83, 0x48, +0x68, 0x00, 0x1f, 0xff, +0xcb, 0xbc, 0x07, 0x83, +0x69, 0x04, 0x30, 0x1e, +0x0b, 0xc0, 0xa5, 0x6a, +0x00, 0x1f, 0xff, 0xc1, +0x40, 0x00, 0x03, 0xc0, +0x67, 0x68, 0x00, 0x20, +0x00, 0x0b, 0x30, 0x1e, +0x0b, 0xc0, 0x25, 0x6a, +0x00, 0x20, 0x00, 0x01, +0x5c, 0x80, 0x80, 0x81, +0x22, 0x98, 0x34, 0x19, +0x50, 0x51, 0x88, 0x16, +0x20, 0x00, 0x00, 0x88, +0x6a, 0x38, 0x83, 0x08, +0x66, 0x00, 0x00, 0xfe, +0x88, 0x55, 0x00, 0x08, +0x58, 0x09, 0x5c, 0x0f, +0xf9, 0x83, 0x08, 0x25, +0x9c, 0x05, 0xb4, 0x82, +0x3c, 0x09, 0x86, 0x80, +0x01, 0xff, 0xfc, 0xb3, +0x01, 0xe0, 0xbc, 0x0d, +0xd8, 0x84, 0x88, 0x6a, +0x00, 0x1f, 0xff, 0xc0, +0x40, 0x00, 0x03, 0xc0, +0x87, 0x68, 0x00, 0x20, +0x00, 0x0b, 0x30, 0x1e, +0x0b, 0xc0, 0x4d, 0x40, +0x00, 0x00, 0x84, 0x88, +0x6a, 0x00, 0x20, 0x00, +0x00, 0x5c, 0x80, 0x80, +0x80, 0xa2, 0x5d, 0x88, +0x21, 0x83, 0x00, 0x59, +0x0d, 0x00, 0x86, 0x0b, +0x95, 0x05, 0x08, 0x83, +0x4b, 0x88, 0x3c, 0x88, +0x80, 0xe2, 0xbf, 0x77, +0xa8, 0x80, 0x0a, 0x88, +0x2b, 0x6b, 0xa1, 0x48, +0xa8, 0x08, 0x00, 0x00, +0x00, 0x5c, 0x00, 0x02, +0xbf, 0xe0, 0x88, 0x04, +0x88, 0x80, 0xf6, 0x88, +0x17, 0xa2, 0x30, 0x80, +0x98, 0x42, 0x86, 0x82, +0x00, 0x00, 0x52, 0x06, +0x60, 0x00, 0x14, 0xee, +0x89, 0xc0, 0x00, 0x88, +0x10, 0x05, 0x50, 0x20, +0x08, 0x00, 0x23, 0xa8, +0x00, 0x2a, 0x05, 0x45, +0x90, 0x40, 0x08, 0x04, +0x8b, 0xff, 0x1a, 0x88, +0x15, 0x06, 0x82, 0x00, +0x00, 0x52, 0x06, 0xc4, +0x00, 0x00, 0xa0, 0x05, +0x1e, 0x02, 0x04, 0x08, +0x26, 0x82, 0x00, 0x1b, +0xa2, 0x05, 0xd4, 0x00, +0x08, 0x0b, 0x62, 0x3c, +0x16, 0x68, 0x20, 0x01, +0xbc, 0x21, 0x3a, 0x88, +0x12, 0x34, 0x00, 0x51, +0xa1, 0x10, 0x40, 0x50, +0x51, 0xa1, 0x80, 0x40, +0xd2, 0x51, 0xa0, 0x50, +0x48, 0xd0, 0xba, 0x14, +0x88, 0x48, 0x52, 0x40, +0x00, 0x02, 0x80, 0x20, +0x39, 0x02, 0x08, 0x00, +0x7a, 0x80, 0x07, 0xa8, +0x08, 0x7a, 0x80, 0x07, +0xa8, 0x08, 0x7a, 0x80, +0x87, 0xa4, 0x60, 0xa4, +0x04, 0x07, 0xa8, 0x48, +0x7a, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x00, 0x46, 0x08, 0x5d, +0x08, 0x33, 0x01, 0xc0, +0x52, 0x01, 0x02, 0xbf, +0xd0, 0x6c, 0x40, 0x00, +0x46, 0x50, 0x59, 0x01, +0x81, 0x8e, 0x88, 0x88, +0x0e, 0x04, 0x20, 0x6c, +0x08, 0x17, 0x65, 0x50, +0x13, 0x08, 0x04, 0xa0, +0x00, 0x00, 0x88, 0x00, +0x03, 0x20, 0x40, 0xbc, +0x07, 0x8b, 0x00, 0x0c, +0x88, 0x00, 0xa3, 0x20, +0xb0, 0xbc, 0x03, 0x92, +0xa0, 0x26, 0x40, 0x00, +0x01, 0x8e, 0x88, 0x59, +0x03, 0x00, 0x81, 0xc8, +0xbc, 0x11, 0x98, 0x82, +0x4a, 0x66, 0x00, 0x02, +0x22, 0x20, 0x6e, 0x00, +0x00, 0x92, 0x2c, 0x38, +0x10, 0x82, 0x58, 0x20, +0xbc, 0x09, 0x88, 0x82, +0x0a, 0x68, 0x20, 0x00, +0x76, 0x20, 0x00, 0x00, +0x08, 0x40, 0x08, 0x84, +0x0f, 0xa6, 0xc4, 0x00, +0x10, 0x44, 0x88, 0x40, +0x7a, 0x32, 0x07, 0x0b, +0xc1, 0x01, 0x66, 0x00, +0x02, 0x22, 0xe0, 0x6e, +0x00, 0x00, 0xba, 0x2c, +0x38, 0x10, 0xe2, 0x59, +0xa0, 0xbc, 0x09, 0x06, +0x82, 0x00, 0x07, 0xc2, +0x00, 0x00, 0x00, 0x84, +0x00, 0x86, 0xc4, 0x00, +0x10, 0x44, 0x88, 0x40, +0xfa, 0x40, 0x00, 0x00, +0x40, 0x7a, 0x68, 0x00, +0x00, 0x49, 0x20, 0x66, +0x00, 0x00, 0x47, 0x08, +0x40, 0x00, 0x00, 0x81, +0x88, 0x68, 0x00, 0x00, +0x5d, 0x20, 0x66, 0x00, +0x00, 0x47, 0x08, 0x88, +0x20, 0x88, 0x80, 0x08, +0x32, 0x02, 0x0b, 0xc1, +0x09, 0x88, 0x0a, 0x03, +0x81, 0xc4, 0xa0, 0x10, +0x08, 0x40, 0x0a, 0x24, +0x93, 0x66, 0xc4, 0x00, +0x04, 0x60, 0x05, 0x24, +0x82, 0x04, 0x04, 0xa6, +0xc4, 0x00, 0x04, 0x64, +0x86, 0x80, 0x00, 0x23, +0x62, 0xc4, 0x20, 0x2f, +0xa0, 0x4e, 0x08, 0x40, +0x6c, 0x68, 0x00, 0x04, +0x55, 0x20, 0x6c, 0x00, +0x00, 0x0a, 0x60, 0x00, +0x00, 0x08, 0x81, 0x36, +0xba, 0x14, 0x8a, 0x80, +0x30, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x20, +0x00, 0x82, 0x22, 0x68, +0x20, 0x00, 0x76, 0x23, +0x85, 0x00, 0x85, 0xb0, +0x83, 0x05, 0x80, 0x05, +0x80, 0x80, 0x2b, 0xfe, +0x06, 0x82, 0x00, 0x08, +0x12, 0x18, 0x80, 0x60, +0x88, 0x0f, 0x64, 0x20, +0x6c, 0x24, 0x04, 0x48, +0x60, 0x4a, 0x66, 0x00, +0x02, 0x45, 0xe8, 0x40, +0x00, 0x02, 0x18, 0x00, +0x68, 0x20, 0x00, 0x76, +0x20, 0x68, 0x20, 0x00, +0x81, 0x21, 0xa4, 0x04, +0x26, 0x60, 0x00, 0x24, +0x5e, 0x8a, 0x00, 0x20, +0x68, 0x20, 0x00, 0x7c, +0x20, 0x6c, 0x40, 0x01, +0x04, 0x08, 0x84, 0x00, +0xa3, 0x01, 0x30, 0x40, +0x00, 0x03, 0xc0, 0xe0, +0x68, 0x20, 0x00, 0x81, +0x21, 0x68, 0x20, 0x00, +0x82, 0x22, 0x66, 0x00, +0x02, 0x45, 0xe0, 0x68, +0x20, 0x00, 0x7c, 0x20, +0x68, 0x20, 0x00, 0x81, +0x21, 0xa4, 0x04, 0x26, +0x60, 0x00, 0x24, 0x5e, +0x8a, 0x00, 0x20, 0x6c, +0x40, 0x00, 0xec, 0x08, +0x6c, 0x40, 0x01, 0x04, +0x0a, 0x30, 0x1a, 0x0b, +0xc0, 0x69, 0x88, 0x02, +0x06, 0xc4, 0x00, 0x0f, +0x80, 0x83, 0x01, 0xa0, +0x40, 0x00, 0x03, 0xc0, +0x40, 0x68, 0x00, 0x04, +0x55, 0x22, 0xbc, 0x0f, +0xf8, 0x40, 0xe2, 0x5c, +0x0e, 0x22, 0x01, 0x00, +0x84, 0x00, 0xa2, 0x49, +0x36, 0x6c, 0x40, 0x00, +0x46, 0x00, 0x52, 0x48, +0x20, 0x40, 0x4a, 0xa0, +0x4e, 0x06, 0x80, 0x00, +0x23, 0x62, 0xc8, 0x40, +0x6c, 0x6c, 0x40, 0x00, +0x46, 0x48, 0x00, 0x00, +0x08, 0x80, 0xb6, 0xba, +0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x05, +0x1a, 0x08, 0x5c, 0x0e, +0x33, 0x01, 0x05, 0x24, +0x1a, 0x46, 0xe0, 0x00, +0x12, 0xc2, 0xf2, 0x59, +0x60, 0x6c, 0x40, 0x05, +0x1a, 0x48, 0xbc, 0x05, +0x83, 0x81, 0x2d, 0x52, +0x4b, 0xc3, 0xc0, 0x6f, +0x6e, 0x00, 0x01, 0x2c, +0x60, 0x52, 0x0b, 0xc3, +0x80, 0x00, 0x6e, 0x00, +0x01, 0x2c, 0x60, 0x52, +0x4d, 0x22, 0x01, 0x00, +0x84, 0x00, 0x92, 0x49, +0xae, 0x84, 0x04, 0xa6, +0xc4, 0x00, 0x51, 0xa4, +0x86, 0x80, 0x00, 0x23, +0x62, 0xc4, 0x60, 0xa4, +0x20, 0x4e, 0x08, 0x40, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6c, 0x40, +0x05, 0x1c, 0x0a, 0x5c, +0x0e, 0x23, 0x01, 0x00, +0x52, 0x09, 0xb2, 0xbf, +0xf0, 0x6e, 0x00, 0x01, +0x2c, 0x2c, 0x52, 0xc1, +0x80, 0x80, 0xf6, 0x6c, +0x40, 0x05, 0x1c, 0x4a, +0x5c, 0x08, 0xab, 0xc1, +0x48, 0x5c, 0x08, 0xc0, +0x80, 0x60, 0x25, 0x83, +0x0b, 0xc0, 0x40, 0x24, +0x96, 0x06, 0xe0, 0x00, +0x12, 0xc6, 0x0b, 0xc5, +0x27, 0x25, 0x96, 0x0b, +0xc5, 0x09, 0x98, 0xe8, +0xa6, 0xc4, 0x00, 0x15, +0xc0, 0x96, 0xc4, 0x00, +0x18, 0xc0, 0xb6, 0x60, +0x00, 0x20, 0x9c, 0x85, +0xc0, 0x04, 0x18, 0x28, +0x8b, 0xc4, 0x67, 0x25, +0x96, 0x0b, 0xc2, 0xe0, +0x38, 0x10, 0x82, 0x58, +0x30, 0xbc, 0x04, 0x06, +0xc0, 0x00, 0x0c, 0xe7, +0xa6, 0xc0, 0x00, 0x0e, +0x27, 0xa2, 0x59, 0x70, +0xbc, 0x09, 0x16, 0xc4, +0x00, 0x23, 0x60, 0xa2, +0x31, 0x36, 0x6c, 0x40, +0x01, 0xea, 0x4a, 0x51, +0x8b, 0xb3, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x30, +0x4a, 0x68, 0x20, 0x00, +0x19, 0x20, 0x6c, 0x40, +0x00, 0x32, 0x08, 0x51, +0x7f, 0x38, 0x40, 0x8a, +0x22, 0xff, 0x52, 0xa8, +0x7f, 0x2a, 0x86, 0xd1, +0x57, 0x15, 0x22, 0x84, +0xd2, 0x28, 0x57, 0x6c, +0x40, 0x01, 0x5c, 0x49, +0x6c, 0x40, 0x01, 0x8c, +0x4b, 0x66, 0x00, 0x02, +0x09, 0xc8, 0x5c, 0x00, +0x43, 0x80, 0x00, 0x6e, +0x00, 0x01, 0x2c, 0x2e, +0x38, 0x11, 0x02, 0x40, +0x30, 0x6c, 0x00, 0x01, +0x32, 0x7a, 0x6e, 0x00, +0x01, 0x2c, 0x60, 0x38, +0x11, 0xd6, 0xc4, 0x00, +0x51, 0xc0, 0xa6, 0xc4, +0x00, 0x03, 0x20, 0x82, +0x59, 0x70, 0x68, 0x20, +0x00, 0x19, 0x20, 0xbc, +0x07, 0x85, 0xc0, 0x04, +0x04, 0x08, 0xa6, 0xc4, +0x00, 0x15, 0xc4, 0x86, +0xc4, 0x00, 0x18, 0xc4, +0xab, 0xc0, 0x67, 0x6c, +0x40, 0x01, 0x8c, 0x0b, +0x66, 0x00, 0x02, 0x09, +0xc8, 0x6c, 0x40, 0x01, +0x5c, 0x09, 0x5c, 0x0e, +0x30, 0x80, 0x20, 0x6c, +0x40, 0x05, 0x1c, 0x00, +0xa0, 0x10, 0x08, 0x40, +0x08, 0x52, 0x4d, 0x20, +0x80, 0xb6, 0x52, 0x4c, +0x30, 0x40, 0x48, 0x6c, +0x40, 0x05, 0x1c, 0x4a, +0x68, 0x00, 0x02, 0x36, +0x2c, 0x46, 0x0a, 0x42, +0x04, 0xe0, 0x84, 0x06, +0xca, 0x80, 0x10, 0x6c, +0x40, 0x05, 0x1e, 0x08, +0x5c, 0x0e, 0x33, 0x01, +0x05, 0x24, 0x1a, 0x46, +0xe0, 0x00, 0x12, 0xc2, +0xf2, 0x59, 0x60, 0x6c, +0x40, 0x05, 0x1e, 0x48, +0xbc, 0x15, 0x83, 0x81, +0x25, 0x68, 0x20, 0x01, +0x69, 0x21, 0x52, 0x0b, +0xc2, 0xc0, 0x60, 0x80, +0x80, 0x98, 0x08, 0x0b, +0x6c, 0x40, 0x02, 0xb0, +0x4b, 0x6c, 0x40, 0x01, +0x5e, 0x49, 0x6c, 0x40, +0x01, 0x8e, 0x49, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x68, 0x20, 0x01, 0x58, +0x22, 0x84, 0x80, 0xb4, +0x20, 0xaf, 0x98, 0xe8, +0x98, 0x52, 0xcb, 0x68, +0x20, 0x01, 0x67, 0x21, +0x68, 0x20, 0x01, 0x58, +0x22, 0x52, 0x4b, 0xc2, +0x08, 0x83, 0x84, 0x80, +0xb8, 0x58, 0x09, 0x6c, +0x40, 0x01, 0x5e, 0x4b, +0x6c, 0x40, 0x01, 0x8e, +0x4b, 0x6c, 0x40, 0x02, +0xb0, 0x49, 0x6e, 0x00, +0x01, 0x2c, 0x60, 0xb0, +0x00, 0xd8, 0x59, 0x0b, +0x40, 0x00, 0x00, 0x52, +0xcb, 0x68, 0x20, 0x00, +0xd7, 0x21, 0x52, 0x4d, +0x22, 0x01, 0x00, 0x51, +0x85, 0x68, 0x48, 0x49, +0x98, 0x26, 0x8a, 0x08, +0x21, 0x84, 0x00, 0x95, +0x24, 0xd6, 0x9c, 0x80, +0x18, 0x48, 0x0a, 0x84, +0x04, 0x96, 0xc4, 0x00, +0x51, 0xe4, 0x86, 0xc4, +0x00, 0x19, 0x84, 0xa6, +0xc4, 0x00, 0x19, 0xa4, +0xa6, 0xc4, 0x00, 0x2f, +0x84, 0xa6, 0xc4, 0x00, +0x2f, 0x24, 0xa6, 0x80, +0x00, 0x23, 0x62, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x05, 0x22, +0x08, 0x5c, 0x0e, 0x33, +0x07, 0xfd, 0x52, 0x0d, +0x22, 0xbf, 0xf0, 0x54, +0x4b, 0x28, 0x80, 0x60, +0x59, 0x41, 0x40, 0x80, +0xf6, 0xbc, 0x4a, 0x86, +0xc4, 0x00, 0x52, 0x24, +0x83, 0x28, 0xa8, 0xbc, +0x2f, 0x03, 0x28, 0xe8, +0xbc, 0x15, 0x8b, 0x00, +0x44, 0x32, 0x9a, 0x8b, +0xc5, 0x61, 0x68, 0x20, +0x02, 0xb2, 0x20, 0x6c, +0x40, 0x00, 0x02, 0x08, +0xb3, 0x80, 0x55, 0x44, +0xb2, 0x84, 0x00, 0x85, +0x58, 0xd6, 0x84, 0x08, +0xa6, 0xc4, 0x00, 0x13, +0xe4, 0x86, 0xc4, 0x00, +0x16, 0xe4, 0xa6, 0xc4, +0x00, 0x34, 0xa4, 0x86, +0xc4, 0x00, 0x00, 0x24, +0x9b, 0xc4, 0x47, 0x66, +0x00, 0x00, 0x54, 0x88, +0xb0, 0x02, 0xdb, 0x00, +0x2d, 0x66, 0x00, 0x00, +0x54, 0x88, 0x40, 0x00, +0x01, 0x8e, 0x88, 0x68, +0x20, 0x02, 0xb0, 0x20, +0x6c, 0x40, 0x00, 0x02, +0x08, 0xb3, 0x80, 0x55, +0x44, 0xb2, 0x84, 0x00, +0xa5, 0x58, 0x76, 0x84, +0x08, 0x86, 0xc4, 0x00, +0x13, 0xe4, 0xa6, 0xc4, +0x00, 0x00, 0x24, 0x9b, +0xc2, 0xef, 0x6c, 0x40, +0x01, 0x6e, 0x48, 0xb0, +0x02, 0xd6, 0x60, 0x00, +0x05, 0x48, 0x89, 0x8e, +0x88, 0x68, 0x20, 0x02, +0xae, 0x20, 0x6c, 0x40, +0x00, 0x02, 0x08, 0x5c, +0x08, 0x6b, 0x38, 0x06, +0x54, 0x4d, 0x30, 0x40, +0x08, 0x52, 0x0b, 0xa8, +0x40, 0x8a, 0x6c, 0x40, +0x01, 0x3e, 0x48, 0x6c, +0x40, 0x03, 0x4a, 0x48, +0x6c, 0x40, 0x00, 0x02, +0x49, 0xbc, 0x17, 0xf6, +0xc4, 0x00, 0x16, 0xe4, +0xab, 0x00, 0x2d, 0x66, +0x00, 0x00, 0x54, 0x88, +0x40, 0x00, 0x03, 0x00, +0x44, 0x68, 0x20, 0x02, +0xac, 0x20, 0x6c, 0x40, +0x00, 0x02, 0x08, 0xb3, +0x80, 0x65, 0x44, 0xd2, +0x04, 0x00, 0x98, 0x40, +0x8a, 0x6c, 0x40, 0x01, +0x3e, 0x49, 0x6c, 0x40, +0x01, 0x6e, 0x4a, 0x6c, +0x40, 0x03, 0x4a, 0x49, +0x6c, 0x40, 0x00, 0x02, +0x48, 0x38, 0x1c, 0x48, +0x80, 0x20, 0x6c, 0x40, +0x05, 0x22, 0x09, 0xa0, +0x10, 0x08, 0x40, 0x0a, +0x52, 0x49, 0xb0, 0x80, +0xb6, 0x52, 0x49, 0x60, +0x40, 0x4a, 0x6c, 0x40, +0x05, 0x22, 0x48, 0x68, +0x00, 0x02, 0x36, 0x2c, +0x46, 0x0a, 0x42, 0x04, +0xe0, 0x84, 0x06, 0xca, +0x80, 0x10, 0x6c, 0x40, +0x05, 0x24, 0x08, 0x5c, +0x0e, 0x33, 0x01, 0x00, +0x52, 0x0d, 0x22, 0xbf, +0xf0, 0x25, 0x82, 0x0b, +0xc0, 0x98, 0x6c, 0x40, +0x05, 0x24, 0x48, 0x88, +0x07, 0x68, 0x80, 0xe0, +0x66, 0x00, 0x01, 0xf8, +0xc0, 0x5c, 0x0e, 0x30, +0x80, 0xa0, 0x88, 0x03, +0x6a, 0x01, 0x00, 0x84, +0x00, 0x82, 0x49, 0xa4, +0x6c, 0x40, 0x05, 0x24, +0x00, 0x52, 0x4c, 0x20, +0x40, 0x48, 0x6c, 0x40, +0x05, 0x24, 0x48, 0x68, +0x00, 0x02, 0x36, 0x2c, +0x46, 0x0a, 0x42, 0x04, +0xe0, 0x84, 0x06, 0xca, +0x80, 0x10, 0x6c, 0x40, +0x05, 0x26, 0x08, 0x5c, +0x0e, 0x33, 0x00, 0x0a, +0x52, 0x0d, 0x23, 0xa1, +0x11, 0x68, 0x00, 0x3f, +0xff, 0xca, 0x68, 0x00, +0x01, 0x6c, 0x21, 0x68, +0x00, 0x01, 0x75, 0x23, +0x54, 0x4d, 0x28, 0x48, +0x0a, 0x55, 0x01, 0x78, +0x58, 0x00, 0x6c, 0x40, +0x05, 0x26, 0x48, 0x68, +0x20, 0x01, 0xf4, 0x25, +0x68, 0x00, 0x01, 0x5c, +0x22, 0x68, 0x00, 0x01, +0x64, 0x24, 0x23, 0x09, +0x19, 0x84, 0x68, 0x9e, +0x80, 0x68, 0x70, 0x01, +0x2a, 0x04, 0x93, 0x00, +0x78, 0xbc, 0x17, 0x32, +0xa7, 0xd7, 0x23, 0x0b, +0xf9, 0x82, 0xe8, 0x9e, +0x80, 0x58, 0x68, 0x0b, +0x57, 0x0f, 0x69, 0xe0, +0x04, 0x86, 0x00, 0xb4, +0x46, 0x90, 0x1d, 0x80, +0x38, 0x58, 0x0b, 0x57, +0x01, 0xc1, 0xd0, 0x02, +0x85, 0x00, 0xb4, 0x46, +0x88, 0x1c, 0x80, 0x18, +0x48, 0x09, 0x57, 0x0d, +0x59, 0x83, 0x4a, 0x54, +0x07, 0x89, 0x83, 0x8a, +0xbc, 0x05, 0xf2, 0x80, +0x30, 0x2a, 0x05, 0x23, +0xa0, 0x82, 0x32, 0x25, +0x0b, 0xfd, 0xe2, 0x5c, +0x0e, 0x32, 0x01, 0x00, +0x52, 0x4d, 0x20, 0x40, +0x09, 0x24, 0x9a, 0xe8, +0x40, 0x4a, 0x6c, 0x00, +0x02, 0xb4, 0x51, 0x6c, +0x00, 0x02, 0xb6, 0x50, +0x6c, 0x40, 0x05, 0x26, +0x48, 0x68, 0x00, 0x02, +0x36, 0x2c, 0x46, 0x0a, +0x42, 0x04, 0xe0, 0x84, +0x06, 0xcb, 0xa1, 0x01, +0x6c, 0x40, 0x05, 0x28, +0x08, 0x68, 0x00, 0x47, +0xff, 0xca, 0x68, 0x38, +0x1c, 0x03, 0x21, 0x54, +0x4d, 0x22, 0xff, 0xe0, +0x5c, 0x00, 0x40, 0x48, +0x48, 0x5c, 0x00, 0x21, +0xc8, 0x01, 0x5c, 0x09, +0xf0, 0x48, 0x7a, 0x84, +0x95, 0x00, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, +0x00, 0x25, 0x98, 0x0b, +0xc0, 0x50, 0x6c, 0x70, +0x38, 0x06, 0x08, 0xbc, +0x05, 0xf6, 0xc4, 0x00, +0x52, 0x84, 0x83, 0x22, +0xa0, 0xbf, 0xf5, 0xa2, +0xa0, 0x64, 0x5c, 0x0e, +0x22, 0x01, 0x00, 0x84, +0x00, 0xa2, 0x49, 0x34, +0x84, 0x04, 0x86, 0x80, +0x00, 0x23, 0x62, 0xc4, +0x60, 0xa4, 0x20, 0x4e, +0x08, 0x40, 0x6c, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x40, 0x05, 0x2a, +0x08, 0x5c, 0x0e, 0x33, +0x01, 0x05, 0x24, 0x1a, +0x46, 0xe0, 0x00, 0x12, +0xc2, 0xf2, 0x59, 0x60, +0x6c, 0x40, 0x05, 0x2a, +0x48, 0xbc, 0x05, 0x83, +0x81, 0x3d, 0x52, 0x4b, +0xc3, 0xc0, 0x6f, 0x6e, +0x00, 0x01, 0x2c, 0x60, +0x52, 0x0b, 0xc3, 0x80, +0x00, 0x6e, 0x00, 0x01, +0x2c, 0x60, 0x52, 0x4d, +0x22, 0x01, 0x00, 0x84, +0x00, 0x92, 0x49, 0xae, +0x84, 0x04, 0xa6, 0xc4, +0x00, 0x52, 0xa4, 0x86, +0x80, 0x00, 0x23, 0x62, +0xc4, 0x60, 0xa4, 0x20, +0x4e, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, +0x00, 0x5c, 0x07, 0x62, +0x00, 0x80, 0x84, 0x02, +0x10, 0x00, 0x00, 0x94, +0x8a, 0xe3, 0x01, 0x30, +0xbc, 0x07, 0x9a, 0x04, +0x60, 0x6c, 0x40, 0x05, +0x2c, 0x08, 0x38, 0x1b, +0xe2, 0x41, 0xa4, 0x6c, +0x40, 0x05, 0x2c, 0x48, +0x68, 0x00, 0x04, 0xf7, +0xa1, 0xba, 0x14, 0x88, +0x40, 0x61, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x00, 0x05, 0x44, 0xa1, +0x6c, 0x00, 0x01, 0x2e, +0x08, 0x98, 0x84, 0x95, +0x80, 0xb0, 0x2b, 0xff, +0x04, 0x24, 0x0c, 0x88, +0x07, 0x68, 0x80, 0xe0, +0xb0, 0x7f, 0xd6, 0xc4, +0x00, 0x52, 0xc0, 0x02, +0x3e, 0x06, 0x28, 0x97, +0x53, 0x28, 0x28, 0xbc, +0x2f, 0x8b, 0x00, 0x14, +0x66, 0x00, 0x00, 0x54, +0x88, 0x40, 0x00, 0x03, +0x01, 0xbd, 0x6c, 0x40, +0x05, 0x2c, 0x08, 0x51, +0xd1, 0x2b, 0x01, 0xba, +0x52, 0xc5, 0x03, 0x07, +0xf8, 0x23, 0xc2, 0x65, +0x44, 0x16, 0xbc, 0x11, +0x82, 0x88, 0x36, 0x68, +0x00, 0x03, 0x03, 0x20, +0x5c, 0x80, 0x43, 0x07, +0xf8, 0x54, 0x41, 0x21, +0x40, 0x46, 0xa0, 0x00, +0x19, 0x40, 0x45, 0x94, +0x8e, 0x4a, 0x04, 0x10, +0xb0, 0x08, 0x56, 0x60, +0x00, 0x05, 0x50, 0x8b, +0x00, 0x1c, 0x40, 0x00, +0x03, 0xc5, 0x67, 0x68, +0x00, 0x03, 0x03, 0x21, +0x5c, 0x09, 0xe2, 0xc0, +0x80, 0x52, 0x09, 0x82, +0x08, 0x00, 0x94, 0x84, +0x06, 0xc0, 0x00, 0x62, +0x07, 0xa9, 0x40, 0xe5, +0xb0, 0x01, 0x4b, 0x00, +0x86, 0x66, 0x00, 0x00, +0x56, 0xe8, 0xb0, 0x00, +0xdb, 0xc4, 0x67, 0x6c, +0x40, 0x00, 0x02, 0x09, +0xb0, 0x7f, 0xe2, 0x89, +0xad, 0x32, 0x02, 0x8b, +0xc1, 0xc0, 0x32, 0x0a, +0x8b, 0xc1, 0x60, 0x32, +0x1a, 0x8b, 0xc1, 0x00, +0x23, 0xc0, 0x52, 0x89, +0xae, 0x32, 0x83, 0x0b, +0xc0, 0x60, 0x32, 0x8a, +0x8b, 0xc1, 0x69, 0xb0, +0x1b, 0xd6, 0x60, 0x00, +0x05, 0x48, 0x0b, 0xc1, +0x27, 0xb0, 0x1b, 0xd6, +0x60, 0x00, 0x05, 0x48, +0x8b, 0x00, 0x54, 0x40, +0x00, 0x03, 0xc0, 0xc7, +0x66, 0x00, 0x00, 0x54, +0x88, 0xb0, 0x1b, 0xdb, +0xc0, 0x87, 0x66, 0x00, +0x00, 0x54, 0x88, 0xb0, +0x1b, 0xdb, 0xc0, 0x47, +0xb0, 0x1b, 0xd6, 0x60, +0x00, 0x05, 0x48, 0x8b, +0x00, 0x54, 0x6c, 0x40, +0x05, 0x2c, 0x08, 0x51, +0xd1, 0x2b, 0x01, 0xbe, +0x52, 0xcd, 0x03, 0x07, +0xfe, 0x68, 0x00, 0x03, +0x03, 0x20, 0x5c, 0x84, +0x03, 0xc0, 0xc8, 0x54, +0x4d, 0x6b, 0x01, 0x3e, +0xb0, 0x7f, 0xe6, 0xe0, +0x00, 0x60, 0x66, 0x55, +0x44, 0xd3, 0x18, 0xe8, +0x99, 0x40, 0xe6, 0x66, +0x00, 0x00, 0x55, 0x08, +0xb0, 0x01, 0x4b, 0xc0, +0xa7, 0x52, 0x0d, 0x42, +0x00, 0x01, 0x6c, 0x00, +0x06, 0x20, 0x7a, 0x94, +0x84, 0x0b, 0x00, 0x0d, +0x66, 0x00, 0x00, 0x56, +0xe8, 0x55, 0x01, 0x61, +0x8e, 0x8a, 0x88, 0x0a, +0x06, 0x80, 0x00, 0x51, +0xba, 0x18, 0x40, 0xe1, +0x00, 0x00, 0x08, 0x80, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x10, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x05, 0x2c, 0x08, +0x38, 0x1b, 0xe2, 0x59, +0xa0, 0x40, 0x00, 0x03, +0xc0, 0x41, 0x6e, 0x00, +0x06, 0x0e, 0x2c, 0x6c, +0x40, 0x05, 0x2c, 0x48, +0x5c, 0x0e, 0x22, 0x01, +0x00, 0x84, 0x00, 0xa2, +0x49, 0x34, 0x84, 0x04, +0x86, 0x80, 0x00, 0x23, +0x62, 0xc4, 0x60, 0xa4, +0x20, 0x4e, 0x08, 0x40, +0x6c, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x20, +0x00, 0xe0, 0x22, 0x60, +0x00, 0x00, 0x00, 0x2c, +0xab, 0xfe, 0x05, 0xc8, +0x10, 0x08, 0x04, 0x88, +0x10, 0x7a, 0x68, 0x00, +0x00, 0x9e, 0x22, 0x5c, +0x82, 0x01, 0x8e, 0x80, +0x5c, 0x86, 0x10, 0x50, +0x7a, 0x5c, 0x8a, 0x0a, +0x10, 0x82, 0x81, 0x07, +0xa8, 0xd0, 0x58, 0x8d, +0x15, 0x88, 0x10, 0x7a, +0x8d, 0x05, 0x88, 0xd0, +0x78, 0xa1, 0x5e, 0x26, +0xc4, 0x00, 0x1d, 0xa0, +0x88, 0x50, 0x48, 0xa1, +0x14, 0x28, 0x50, 0x48, +0xa1, 0x56, 0x26, 0xc4, +0x00, 0x1d, 0x80, 0xa8, +0x10, 0xca, 0x81, 0x24, +0xa8, 0x10, 0xe0, 0x68, +0x20, 0x00, 0xe2, 0x20, +0x85, 0x06, 0x16, 0x82, +0x00, 0x0e, 0x82, 0x3a, +0x16, 0x61, 0x84, 0x04, +0x88, 0x41, 0xc8, 0x88, +0x0e, 0x18, 0x58, 0x48, +0x85, 0x9c, 0x88, 0x81, +0x76, 0x68, 0x00, 0x00, +0xb4, 0x20, 0x68, 0x00, +0x00, 0xb8, 0x21, 0x66, +0x00, 0x01, 0x0e, 0x00, +0x68, 0x00, 0x00, 0xc9, +0x20, 0x66, 0x00, 0x00, +0x49, 0x68, 0x38, 0x00, +0xc8, 0x81, 0x36, 0x88, +0x0a, 0x04, 0x60, 0xa4, +0x08, 0x00, 0x88, 0x40, +0x48, 0x40, 0x00, 0x02, +0x80, 0x20, 0x68, 0x00, +0x05, 0x00, 0x08, 0x6c, +0x68, 0x00, 0x56, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x40, 0x00, 0x03, +0x80, 0x00, 0x40, 0x00, +0x03, 0x80, 0x00, 0x40, +0x00, 0x03, 0xa1, 0x40, +0x6c, 0x40, 0x05, 0x2e, +0x08, 0x5c, 0x0e, 0x32, +0xbf, 0xf0, 0x52, 0x0d, +0x20, 0x80, 0x60, 0x6c, +0x40, 0x05, 0x2e, 0x48, +0x88, 0x0f, 0x66, 0x60, +0x00, 0x0f, 0x22, 0x83, +0x80, 0x0c, 0x5c, 0x0e, +0x20, 0x80, 0x20, 0x6c, +0x40, 0x05, 0x2e, 0x0a, +0xa0, 0x10, 0x08, 0x40, +0x00, 0x52, 0x48, 0x00, +0x80, 0xb6, 0x52, 0x49, +0xa0, 0x40, 0x50, 0x6c, +0x40, 0x05, 0x2e, 0x48, +0x68, 0x00, 0x02, 0x36, +0x2c, 0x46, 0x0a, 0x42, +0x04, 0xe0, 0x84, 0x06, +0xca, 0x80, 0x10, 0x68, +0x38, 0x1c, 0x07, 0x21, +0x5c, 0xbc, 0x03, 0x00, +0x0e, 0x5c, 0x00, 0x80, +0x48, 0x7a, 0x9c, 0x80, +0x18, 0x48, 0x48, 0xa0, +0xc2, 0x18, 0x48, 0x7a, +0xa0, 0x84, 0x18, 0x48, +0x4a, 0xa0, 0xc8, 0x18, +0x48, 0x08, 0x46, 0x0a, +0x40, 0x40, 0x48, 0x84, +0xbd, 0x00, 0x00, 0x00, +0x68, 0x20, 0x00, 0xd7, +0x20, 0x6c, 0x40, 0x05, +0x1e, 0x7a, 0x84, 0x07, +0xa0, 0x00, 0x00, 0x84, +0x08, 0x86, 0xc4, 0x00, +0x19, 0xa4, 0x86, 0xc4, +0x00, 0x2f, 0x84, 0x86, +0xc4, 0x00, 0x2f, 0x24, +0x8b, 0xa1, 0x48, 0x6c, +0x40, 0x01, 0x98, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x00, 0x00, +0x90, 0x20, 0x5c, 0x81, +0x03, 0x01, 0x05, 0x5c, +0x00, 0x08, 0x00, 0x02, +0x55, 0x00, 0x62, 0x00, +0xa1, 0x68, 0x00, 0x00, +0xea, 0x24, 0x55, 0x00, +0x59, 0x48, 0x28, 0x52, +0xca, 0x02, 0xbf, 0xc0, +0x82, 0x20, 0x9a, 0x0d, +0x41, 0x88, 0x24, 0x98, +0x82, 0xe1, 0x88, 0x37, +0x6b, 0xc0, 0x89, 0x55, +0x00, 0x70, 0x40, 0x09, +0x68, 0x00, 0x00, 0x88, +0x20, 0x6c, 0x00, 0x01, +0xce, 0x01, 0x84, 0x08, +0x88, 0x40, 0x03, 0x38, +0x10, 0xf2, 0x59, 0xc0, +0xbc, 0x09, 0x95, 0x50, +0x18, 0x18, 0x28, 0xb6, +0x80, 0x00, 0x08, 0xa2, +0x06, 0xc0, 0x00, 0x1d, +0x00, 0x08, 0x40, 0x8b, +0x40, 0x00, 0x00, 0x40, +0x0a, 0x57, 0x04, 0xd0, +0x82, 0x03, 0x57, 0x06, +0x4a, 0x08, 0x00, 0x2e, +0x16, 0x32, 0x81, 0x92, +0x48, 0x40, 0x79, 0x80, +0x89, 0x6c, 0x40, 0x01, +0x3e, 0x08, 0x44, 0x21, +0x01, 0xa0, 0x02, 0x6c, +0x40, 0x01, 0x6e, 0x08, +0x08, 0x80, 0x06, 0xc4, +0x00, 0x1e, 0xa0, 0x16, +0xc4, 0x00, 0x23, 0x60, +0xb3, 0x01, 0xc8, 0x6e, +0x40, 0x01, 0x9d, 0x24, +0x20, 0x11, 0x16, 0xe4, +0x00, 0x19, 0xf2, 0x46, +0xc4, 0x00, 0x34, 0xa0, +0xa5, 0x00, 0x80, 0x00, +0x84, 0x14, 0x43, 0x08, +0x04, 0x84, 0x08, 0x82, +0x61, 0x00, 0x00, 0x06, +0xe4, 0x00, 0x3b, 0x12, +0x25, 0x00, 0x44, 0x3c, +0x67, 0xd8, 0x60, 0x40, +0x68, 0x00, 0x00, 0x98, +0x24, 0x6c, 0x40, 0x02, +0x18, 0x09, 0x86, 0x00, +0x82, 0xe1, 0x65, 0x51, +0x4b, 0x68, 0x60, 0x49, +0x6c, 0x40, 0x01, 0xea, +0x49, 0x30, 0x1e, 0x8b, +0xc5, 0x64, 0x6c, 0x00, +0x03, 0x80, 0x09, 0x32, +0x02, 0x8b, 0xc0, 0x41, +0x6c, 0x00, 0x03, 0x9a, +0x08, 0x32, 0x02, 0x0b, +0xc4, 0xb0, 0x6c, 0x00, +0x03, 0x9a, 0x08, 0x2e, +0x92, 0xd2, 0xa0, 0x6d, +0x6c, 0x40, 0x01, 0xfc, +0x08, 0x6c, 0x00, 0x03, +0x80, 0x49, 0x30, 0x12, +0x8b, 0xc0, 0xec, 0x6c, +0x00, 0x03, 0x9a, 0x49, +0x23, 0x13, 0xd6, 0x80, +0x00, 0x09, 0x82, 0x46, +0xc4, 0x00, 0x1e, 0xa4, +0x96, 0x82, 0x00, 0x29, +0x92, 0x75, 0x18, 0xb6, +0x86, 0x0f, 0xab, 0xc3, +0xef, 0x6c, 0x00, 0x01, +0x30, 0x49, 0x68, 0x00, +0x00, 0x62, 0x22, 0x68, +0x00, 0x00, 0x6c, 0x26, +0x5c, 0x82, 0x08, 0x10, +0x7a, 0xa1, 0x00, 0x48, +0x10, 0x7a, 0x86, 0x0f, +0xa8, 0x30, 0x7a, 0xa3, +0x00, 0x56, 0x80, 0x00, +0x0d, 0x22, 0x48, 0x30, +0x7a, 0x86, 0x8f, 0xa8, +0x20, 0x7a, 0xa2, 0x00, +0x78, 0x70, 0xfa, 0x82, +0x07, 0xa6, 0x80, 0x00, +0x1b, 0xe2, 0x56, 0x82, +0x00, 0x29, 0x92, 0x68, +0x78, 0xfa, 0xa3, 0x00, +0x78, 0x28, 0x80, 0x85, +0x0f, 0xa8, 0x30, 0x50, +0x68, 0x00, 0x01, 0xd8, +0x23, 0x6c, 0x00, 0x00, +0xec, 0x50, 0x68, 0x00, +0x01, 0xcb, 0x22, 0x81, +0x88, 0x98, 0x10, 0x80, +0x6c, 0x00, 0x01, 0x30, +0x7a, 0x6c, 0x40, 0x01, +0xea, 0x4b, 0x6c, 0x00, +0x00, 0xfe, 0x50, 0x6c, +0x00, 0x01, 0xbc, 0x49, +0x85, 0x87, 0xa8, 0x68, +0x7a, 0x87, 0x0c, 0x98, +0x70, 0x50, 0x42, 0x05, +0x78, 0x60, 0xfa, 0x85, +0x07, 0xab, 0xc0, 0x8f, +0x68, 0x20, 0x02, 0x99, +0x27, 0x40, 0x00, 0x03, +0xc0, 0x4f, 0x68, 0x20, +0x02, 0x99, 0x27, 0x68, +0x20, 0x02, 0x99, 0x27, +0x68, 0x20, 0x00, 0x9c, +0x24, 0xa3, 0x82, 0x58, +0x83, 0xe5, 0x66, 0x00, +0x01, 0xd3, 0x00, 0x68, +0x00, 0x00, 0x7b, 0x20, +0x88, 0x2a, 0x18, 0x40, +0x48, 0x68, 0x20, 0x00, +0xb4, 0x24, 0x40, 0x00, +0x00, 0x82, 0x20, 0x66, +0x00, 0x01, 0xd3, 0x00, +0x68, 0x00, 0x00, 0x84, +0x20, 0x68, 0x00, 0x00, +0x7b, 0x21, 0x5c, 0x82, +0x00, 0x40, 0x48, 0x68, +0x00, 0x00, 0x62, 0x20, +0x80, 0x80, 0x98, 0x82, +0x61, 0x68, 0x20, 0x00, +0x9c, 0x24, 0x66, 0x00, +0x01, 0x99, 0xc0, 0x68, +0x20, 0x02, 0x99, 0x2c, +0x5c, 0x87, 0x00, 0x82, +0x20, 0x88, 0x1e, 0xc8, +0x02, 0x48, 0x68, 0x20, +0x00, 0xdf, 0x2c, 0x68, +0x20, 0x00, 0xdc, 0x2d, +0x68, 0x20, 0x00, 0xde, +0x22, 0x88, 0x26, 0x06, +0x82, 0x00, 0x09, 0xc2, +0x46, 0x80, 0x00, 0x09, +0xa2, 0x16, 0x82, 0x00, +0x0d, 0x32, 0x58, 0x80, +0x6c, 0x88, 0x0e, 0xd8, +0x81, 0x62, 0x66, 0x00, +0x01, 0x9b, 0x28, 0x40, +0x00, 0x01, 0x82, 0x09, +0x5c, 0x82, 0x00, 0x82, +0x20, 0x68, 0x00, 0x00, +0x84, 0x21, 0x84, 0x34, +0x86, 0x80, 0x00, 0x06, +0xc2, 0x08, 0x08, 0x09, +0x40, 0x00, 0x00, 0x82, +0x61, 0x68, 0x20, 0x00, +0xb4, 0x24, 0x66, 0x00, +0x01, 0x99, 0xc0, 0x5c, +0x87, 0x00, 0x82, 0x20, +0x88, 0x3a, 0x18, 0x02, +0x48, 0x88, 0x1e, 0x16, +0x82, 0x00, 0x0d, 0xfa, +0xc6, 0x82, 0x00, 0x0d, +0xd2, 0xd6, 0x82, 0x00, +0x0d, 0xea, 0x28, 0x82, +0x60, 0x68, 0x20, 0x00, +0xb4, 0x24, 0x68, 0x00, +0x00, 0x9c, 0x21, 0x68, +0x20, 0x00, 0xd5, 0x25, +0x88, 0x06, 0xc8, 0x80, +0xed, 0x88, 0x16, 0x26, +0x60, 0x00, 0x19, 0xb2, +0x89, 0x82, 0x09, 0x68, +0x20, 0x00, 0x9c, 0x21, +0x6c, 0x40, 0x03, 0xc2, +0x09, 0x84, 0xb8, 0x05, +0x80, 0xa0, 0x08, 0x22, +0x16, 0xc4, 0x00, 0x3b, +0xa0, 0x0b, 0xc0, 0x69, +0x5c, 0x09, 0x30, 0x4b, +0x48, 0x52, 0x4c, 0x23, +0xc0, 0x6f, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x52, +0x0c, 0x23, 0x80, 0x00, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x68, 0x20, 0x00, +0xb4, 0x21, 0x6c, 0x40, +0x03, 0xba, 0x08, 0x84, +0xb8, 0x03, 0x01, 0x40, +0xbc, 0x05, 0x93, 0x81, +0x2e, 0x52, 0x4d, 0x2b, +0xc0, 0x5f, 0x6c, 0x40, +0x03, 0xba, 0x49, 0x24, +0x1a, 0x56, 0xc4, 0x00, +0x3b, 0xa4, 0x93, 0x81, +0x35, 0x6c, 0x40, 0x01, +0xb8, 0x08, 0x6c, 0x40, +0x01, 0xda, 0x0a, 0x30, +0x1a, 0x0b, 0xc0, 0x69, +0x6c, 0x40, 0x03, 0xba, +0x08, 0x52, 0x4b, 0x2b, +0xc0, 0x5f, 0x6c, 0x40, +0x03, 0xba, 0x49, 0x24, +0x16, 0x56, 0xc4, 0x00, +0x3b, 0xa4, 0x93, 0x81, +0x3d, 0x6c, 0x40, 0x01, +0xba, 0x08, 0x30, 0x1a, +0x0b, 0xc0, 0x69, 0x6c, +0x40, 0x03, 0xba, 0x08, +0x52, 0x4b, 0x2b, 0xc0, +0x6f, 0x6c, 0x40, 0x03, +0xba, 0x49, 0x52, 0x0b, +0x2b, 0x80, 0x00, 0x6c, +0x40, 0x03, 0xba, 0x49, +0x68, 0x00, 0x06, 0x27, +0x21, 0x88, 0x33, 0x6b, +0xa1, 0x48, 0x6c, 0x00, +0x01, 0x2e, 0x61, 0x40, +0x00, 0x02, 0x80, 0x40, +0x68, 0x00, 0x00, 0x7c, +0x20, 0x5c, 0x85, 0x02, +0xbf, 0x90, 0x80, 0x20, +0x98, 0x81, 0x60, 0x68, +0x20, 0x01, 0xc2, 0x2c, +0x88, 0x1f, 0x66, 0x82, +0x00, 0x09, 0xc2, 0x46, +0x82, 0x00, 0x0c, 0xe2, +0x56, 0x80, 0x00, 0x0e, +0xb2, 0x08, 0x80, 0x6c, +0x66, 0x00, 0x01, 0xb1, +0x40, 0x68, 0x00, 0x00, +0x85, 0x20, 0x39, 0x0a, +0x08, 0x02, 0x09, 0x88, +0x26, 0x06, 0x82, 0x00, +0x1c, 0x42, 0xc6, 0xc0, +0x00, 0x1d, 0x64, 0x86, +0x82, 0x00, 0x0b, 0x42, +0x46, 0x82, 0x00, 0x0c, +0xf2, 0x56, 0x80, 0x00, +0x0e, 0xd2, 0x08, 0x80, +0x6c, 0x66, 0x00, 0x01, +0xb1, 0x40, 0x68, 0x20, +0x00, 0xdc, 0x2c, 0x6c, +0x00, 0x01, 0xda, 0x48, +0x68, 0x00, 0x00, 0x62, +0x20, 0x68, 0x20, 0x00, +0x9c, 0x24, 0x68, 0x20, +0x00, 0xce, 0x25, 0x88, +0x06, 0xc6, 0x60, 0x00, +0x19, 0xa0, 0x86, 0xc0, +0x00, 0x1d, 0x60, 0x98, +0x81, 0x20, 0x68, 0x20, +0x00, 0xdd, 0x2c, 0x84, +0x04, 0x86, 0x80, 0x00, +0x06, 0xc2, 0x06, 0x82, +0x00, 0x0b, 0x42, 0x46, +0x82, 0x00, 0x0c, 0xf2, +0x58, 0x80, 0x6c, 0x66, +0x00, 0x01, 0x9a, 0x08, +0x6c, 0x00, 0x01, 0xda, +0x09, 0x5c, 0x81, 0x00, +0x81, 0x20, 0x88, 0x22, +0x48, 0x02, 0x09, 0x86, +0x04, 0x88, 0x81, 0x60, +0x68, 0x00, 0x00, 0x62, +0x21, 0x68, 0x20, 0x00, +0x9c, 0x24, 0x66, 0x00, +0x01, 0xb2, 0xa0, 0x5c, +0x81, 0x00, 0x81, 0x24, +0x88, 0x22, 0x0a, 0x20, +0x44, 0x80, 0x20, 0x98, +0x60, 0x48, 0x88, 0x2e, +0x48, 0x82, 0x60, 0x68, +0x00, 0x00, 0x6c, 0x21, +0x68, 0x20, 0x00, 0xb4, +0x24, 0x66, 0x00, 0x01, +0xb2, 0xa0, 0x88, 0x22, +0x06, 0x82, 0x00, 0x15, +0xa2, 0x5a, 0x00, 0x40, +0x84, 0x04, 0x86, 0x82, +0x00, 0x09, 0xc2, 0x46, +0xc4, 0x00, 0x3b, 0xa0, +0x88, 0x66, 0x02, 0x86, +0x80, 0x33, 0x00, 0xd0, +0xbc, 0x06, 0xa5, 0xc0, +0x82, 0x88, 0x36, 0x05, +0x24, 0xb2, 0x3c, 0x05, +0xf6, 0xc4, 0x00, 0x3b, +0xa4, 0x82, 0x41, 0x64, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x68, 0x20, 0x00, +0xb4, 0x20, 0x6c, 0x40, +0x03, 0xba, 0x08, 0x84, +0x60, 0x23, 0x00, 0xd0, +0xbc, 0x05, 0xa3, 0x81, +0x0d, 0x52, 0x4b, 0x23, +0xc0, 0x6f, 0x6c, 0x40, +0x03, 0xba, 0x48, 0x52, +0x0b, 0x23, 0x80, 0x00, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x68, 0x00, 0x00, +0x62, 0x20, 0x88, 0x12, +0x16, 0x82, 0x00, 0x0d, +0xe2, 0x56, 0x60, 0x00, +0x1b, 0x68, 0x88, 0x49, +0x09, 0x88, 0x22, 0x06, +0x80, 0x00, 0x09, 0x22, +0x48, 0x41, 0x09, 0x40, +0x00, 0x00, 0x60, 0x48, +0x68, 0x00, 0x00, 0x6c, +0x20, 0x68, 0x20, 0x00, +0xb4, 0x24, 0x68, 0x20, +0x00, 0xde, 0xa5, 0x66, +0x00, 0x01, 0xb6, 0x80, +0x5c, 0x81, 0x00, 0x81, +0x48, 0x68, 0x00, 0x00, +0x92, 0x23, 0x68, 0x20, +0x00, 0xd7, 0x24, 0xa1, +0x80, 0x2c, 0x60, 0x80, +0x5d, 0x0c, 0x28, 0x82, +0x64, 0x51, 0x85, 0x68, +0x83, 0xd0, 0x59, 0x05, +0x81, 0x82, 0x68, 0x9e, +0x00, 0x46, 0x82, 0x00, +0x0c, 0xd2, 0x18, 0x60, +0x09, 0x68, 0x20, 0x00, +0xcc, 0x20, 0x88, 0x46, +0x38, 0x48, 0x49, 0x42, +0x06, 0x50, 0x58, 0x48, +0x84, 0x04, 0x93, 0x61, +0x44, 0x88, 0x38, 0x25, +0x78, 0xa9, 0x88, 0x10, +0x22, 0xe9, 0x1b, 0x2f, +0x15, 0x56, 0xc0, 0x00, +0x12, 0x45, 0x35, 0x74, +0x96, 0x3c, 0x03, 0xf8, +0x58, 0x48, 0x66, 0x00, +0x01, 0xc6, 0xc0, 0x68, +0x00, 0x00, 0x92, 0x20, +0x5c, 0x09, 0x60, 0x84, +0x21, 0xa0, 0x08, 0x09, +0x40, 0x2d, 0x52, 0xc9, +0x40, 0x84, 0xe0, 0x68, +0x20, 0x01, 0x5a, 0x24, +0x6c, 0x40, 0x02, 0xb4, +0x02, 0x6c, 0x40, 0x02, +0xd4, 0x03, 0x88, 0x55, +0x38, 0x85, 0xd2, 0x00, +0x00, 0x04, 0x20, 0x74, +0x06, 0x18, 0x88, 0x86, +0x48, 0x68, 0x20, 0x00, +0xc0, 0x20, 0x88, 0x58, +0x86, 0x82, 0x00, 0x0a, +0x82, 0x48, 0x85, 0x09, +0x6c, 0x40, 0x01, 0x80, +0x48, 0x6c, 0x40, 0x01, +0x50, 0x48, 0x84, 0x0c, +0x94, 0x22, 0xab, 0x86, +0x0c, 0x90, 0x00, 0x00, +0x6c, 0x00, 0x01, 0x24, +0x0a, 0x66, 0x00, 0x01, +0xcc, 0x68, 0x5c, 0x00, +0x28, 0x48, 0x0b, 0x6e, +0x00, 0x01, 0xa2, 0x25, +0x32, 0x02, 0x8b, 0xc3, +0x01, 0x6e, 0x40, 0x01, +0xbe, 0x2d, 0x32, 0x02, +0x8b, 0xc2, 0xc1, 0x6e, +0x40, 0x01, 0xbf, 0x2d, +0x32, 0x02, 0x8b, 0xc2, +0x81, 0x6c, 0x40, 0x01, +0xae, 0x09, 0x5d, 0x0a, +0x28, 0x82, 0x20, 0x51, +0x85, 0x51, 0x8e, 0x83, +0x98, 0x4a, 0x89, 0xc0, +0x00, 0x6c, 0x40, 0x02, +0xb0, 0x0a, 0x84, 0x00, +0xb0, 0x8e, 0x20, 0x98, +0x08, 0x22, 0xe0, 0xa6, +0x32, 0x03, 0x0b, 0xc0, +0x5d, 0x55, 0x00, 0xd0, +0x85, 0x89, 0x55, 0x01, +0xb8, 0x86, 0x0a, 0x08, +0xe3, 0x02, 0xe0, 0xeb, +0x6c, 0x40, 0x01, 0x50, +0x09, 0x98, 0x0c, 0x33, +0x00, 0xe8, 0xbc, 0x0b, +0x56, 0xc4, 0x00, 0x2b, +0x20, 0x92, 0xe1, 0x2d, +0x32, 0x02, 0x8b, 0xc0, +0x63, 0x6c, 0x40, 0x01, +0x80, 0x53, 0x6c, 0x40, +0x01, 0x50, 0x53, 0xbc, +0x05, 0xf8, 0x84, 0x21, +0xbc, 0x03, 0xf8, 0x84, +0x21, 0x5c, 0x00, 0x10, +0x84, 0x21, 0x38, 0x12, +0x59, 0x4e, 0x2b, 0x25, +0x95, 0x8b, 0xc1, 0x40, +0x6c, 0x40, 0x02, 0xd0, +0x09, 0x57, 0x0b, 0x28, +0x85, 0x08, 0x6c, 0x40, +0x01, 0x52, 0x48, 0x32, +0x02, 0x8b, 0xc0, 0x6d, +0x6c, 0x40, 0x01, 0x82, +0x48, 0x00, 0x00, 0x06, +0xc4, 0x00, 0x2e, 0x20, +0xa0, 0x86, 0x20, 0x2e, +0x0a, 0x26, 0xc4, 0x00, +0x18, 0x24, 0x26, 0xc4, +0x00, 0x15, 0x24, 0x20, +0x00, 0x00, 0x6c, 0x00, +0x01, 0x24, 0x08, 0x5b, +0x48, 0x28, 0x83, 0x82, +0x36, 0x88, 0x36, 0xc4, +0x00, 0x3b, 0xa0, 0xa3, +0x09, 0x58, 0xbc, 0x05, +0xc3, 0x81, 0x12, 0x52, +0x45, 0xab, 0xc0, 0x5f, +0x6c, 0x40, 0x03, 0xba, +0x49, 0x24, 0x0b, 0x56, +0xc4, 0x00, 0x3b, 0xa4, +0x93, 0x81, 0x1d, 0x84, +0x80, 0x25, 0xb4, 0x41, +0x88, 0x10, 0xa3, 0x69, +0x86, 0x30, 0x8f, 0x0b, +0xc0, 0x6c, 0x6c, 0x40, +0x03, 0xba, 0x03, 0x52, +0x4a, 0xeb, 0xc0, 0x6f, +0x6c, 0x40, 0x03, 0xba, +0x49, 0x52, 0x0a, 0xeb, +0x80, 0x00, 0x6c, 0x40, +0x03, 0xba, 0x49, 0x68, +0x00, 0x00, 0x62, 0x20, +0x68, 0x00, 0x00, 0x6c, +0x24, 0x84, 0x2c, 0x88, +0x62, 0xd2, 0x68, 0x20, +0x01, 0xba, 0x24, 0x68, +0x00, 0x00, 0x92, 0x20, +0x66, 0x00, 0x01, 0xd3, +0x00, 0x88, 0x42, 0x08, +0x81, 0x48, 0x68, 0x20, +0x01, 0xbc, 0x24, 0x68, +0x00, 0x00, 0x92, 0x21, +0x66, 0x00, 0x01, 0xd3, +0x00, 0x88, 0x10, 0x98, +0x81, 0x48, 0x68, 0x20, +0x00, 0x9c, 0x24, 0x68, +0x20, 0x00, 0xce, 0x25, +0x66, 0x00, 0x01, 0xb7, +0x60, 0x88, 0x2a, 0x06, +0x82, 0x00, 0x0b, 0x42, +0x48, 0x43, 0x48, 0x68, +0x20, 0x00, 0xcf, 0x25, +0x66, 0x00, 0x01, 0xb7, +0x68, 0x40, 0x00, 0x00, +0x81, 0x09, 0x5c, 0x08, +0xa8, 0x84, 0xa0, 0x88, +0x32, 0x49, 0x40, 0x2a, +0x25, 0x95, 0x0b, 0xc0, +0x58, 0x86, 0x34, 0x86, +0xc0, 0x00, 0x0f, 0xc7, +0xa6, 0xc0, 0x00, 0x10, +0xe7, 0xa3, 0x81, 0x34, +0x25, 0x91, 0x0b, 0xc0, +0xe0, 0x68, 0x00, 0x00, +0xd1, 0x20, 0x6c, 0x40, +0x01, 0xda, 0x08, 0x5c, +0x81, 0x01, 0x8e, 0x89, +0x40, 0x00, 0x01, 0x42, +0x45, 0x6c, 0x40, 0x01, +0x5a, 0x48, 0x6c, 0x40, +0x01, 0x8a, 0x48, 0x42, +0x1d, 0x38, 0x40, 0x7a, +0x68, 0x00, 0x00, 0x7a, +0x20, 0x68, 0x00, 0x00, +0x83, 0x21, 0x66, 0x00, +0x02, 0x40, 0x20, 0x6e, +0x00, 0x01, 0xa2, 0x24, +0x32, 0x06, 0x0b, 0xc1, +0xa1, 0x68, 0x20, 0x00, +0xf0, 0x21, 0x68, 0x20, +0x00, 0xad, 0x20, 0xa0, +0xc2, 0x28, 0x81, 0x62, +0x66, 0x00, 0x02, 0x45, +0xe0, 0x88, 0x12, 0x26, +0x82, 0x00, 0x0c, 0x52, +0x06, 0x82, 0x00, 0x0f, +0x02, 0x16, 0x60, 0x00, +0x24, 0x5e, 0x08, 0x81, +0x20, 0x6c, 0x40, 0x02, +0x36, 0x08, 0x84, 0x30, +0x93, 0x01, 0x28, 0xbc, +0x1b, 0x16, 0xc0, 0x00, +0x61, 0x67, 0xa6, 0xc0, +0x00, 0x61, 0x87, 0xab, +0xc1, 0x67, 0x6c, 0x00, +0x01, 0x32, 0x08, 0x38, +0x19, 0xd2, 0x89, 0x64, +0x30, 0x16, 0x0b, 0xc1, +0x01, 0x68, 0x20, 0x00, +0xad, 0x20, 0x68, 0x20, +0x00, 0xf1, 0x21, 0x68, +0x20, 0x00, 0xee, 0x22, +0x66, 0x00, 0x02, 0x45, +0xe0, 0x68, 0x20, 0x00, +0xee, 0x22, 0x68, 0x20, +0x00, 0xc5, 0x20, 0x66, +0x00, 0x02, 0x45, 0xe8, +0x40, 0x00, 0x02, 0x10, +0x61, 0x6e, 0x00, 0x01, +0xa2, 0x24, 0x32, 0x06, +0x0b, 0xc4, 0xe0, 0x68, +0x00, 0x01, 0x91, 0x20, +0x66, 0x00, 0x00, 0x48, +0x20, 0x32, 0x02, 0x0b, +0xc4, 0x81, 0x6c, 0x00, +0x01, 0x32, 0x08, 0x2a, +0x8e, 0x53, 0x20, 0xe8, +0xbc, 0x1e, 0x06, 0xc0, +0x00, 0x0f, 0x80, 0x96, +0xc4, 0x00, 0x1e, 0xe0, +0x22, 0x80, 0xae, 0x32, +0x03, 0x0b, 0xc0, 0x4b, +0x38, 0x10, 0x32, 0x40, +0xe4, 0x6c, 0x00, 0x01, +0x32, 0x48, 0x2e, 0x0a, +0xd3, 0x20, 0x28, 0xbc, +0x07, 0xd3, 0x81, 0x0c, +0x6c, 0x00, 0x01, 0x32, +0x09, 0x24, 0x12, 0xc6, +0xc0, 0x00, 0x13, 0x24, +0x80, 0x00, 0x00, 0x6c, +0x00, 0x01, 0x32, 0x08, +0x2a, 0x8e, 0x43, 0x20, +0xe0, 0xbc, 0x04, 0x16, +0xc4, 0x00, 0x1d, 0xa0, +0x86, 0xc4, 0x00, 0x15, +0xa4, 0x83, 0x81, 0x85, +0x6c, 0x00, 0x01, 0x32, +0x08, 0x28, 0x96, 0x23, +0x01, 0x50, 0xbc, 0x1f, +0x06, 0xc0, 0x00, 0x10, +0xa0, 0x26, 0xc4, 0x00, +0x1e, 0xe0, 0x32, 0x80, +0xd7, 0x32, 0x03, 0x8b, +0xc0, 0x4b, 0x38, 0x12, +0x62, 0x41, 0xa4, 0x6c, +0x00, 0x01, 0x32, 0x48, +0x2e, 0x0d, 0x23, 0x20, +0x10, 0xbc, 0x07, 0xd3, +0x81, 0x2c, 0x6c, 0x00, +0x01, 0x32, 0x02, 0x24, +0x11, 0x46, 0xc0, 0x00, +0x13, 0x24, 0x80, 0x00, +0x00, 0x6c, 0x00, 0x01, +0x32, 0x08, 0x28, 0x96, +0x43, 0x01, 0x60, 0x40, +0x00, 0x03, 0xc0, 0x41, +0x6c, 0x40, 0x01, 0xda, +0x08, 0x6c, 0x40, 0x01, +0x8a, 0x48, 0x68, 0x00, +0x05, 0x44, 0xa0, 0x88, +0x1b, 0x6b, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0x2e, +0x60, 0x40, 0x00, 0x02, +0x80, 0x70, 0x68, 0x00, +0x00, 0xe3, 0x20, 0x6c, +0x00, 0x01, 0xd2, 0x09, +0x84, 0x04, 0x9a, 0xbf, +0xd0, 0xa0, 0x04, 0x08, +0x82, 0x60, 0x88, 0x2f, +0x66, 0x80, 0x00, 0x0d, +0x22, 0x06, 0x82, 0x00, +0x1a, 0x22, 0x46, 0x60, +0x00, 0x19, 0x9c, 0x08, +0x82, 0x20, 0x68, 0x20, +0x02, 0xaa, 0x2c, 0x84, +0x04, 0x88, 0x80, 0x6c, +0xa0, 0x4e, 0x06, 0x82, +0x00, 0x2a, 0xb2, 0xc6, +0x82, 0x00, 0x2a, 0xaa, +0x26, 0x82, 0x00, 0x29, +0xb2, 0xd8, 0x82, 0x60, +0x68, 0x20, 0x01, 0xa2, +0x24, 0x68, 0x00, 0x00, +0xdc, 0x21, 0x68, 0x20, +0x02, 0xa8, 0x25, 0x88, +0x0e, 0xc8, 0x81, 0x62, +0x88, 0x1e, 0xd6, 0x60, +0x00, 0x19, 0xb2, 0x89, +0x82, 0x09, 0x68, 0x00, +0x06, 0x33, 0xa4, 0x88, +0x22, 0x08, 0x82, 0xb6, +0x6c, 0x00, 0x01, 0x2e, +0x64, 0xba, 0x14, 0x88, +0x43, 0x48, 0x40, 0x00, +0x02, 0x80, 0x30, 0xab, +0xff, 0x08, 0x80, 0x76, +0x68, 0x20, 0x02, 0xa5, +0x24, 0x68, 0x00, 0x01, +0xe2, 0x20, 0x66, 0x00, +0x00, 0x3d, 0xe8, 0x6c, +0x00, 0x00, 0xfa, 0x09, +0x6c, 0x00, 0x03, 0x6e, +0x48, 0x68, 0x20, 0x02, +0xa5, 0x24, 0x68, 0x00, +0x01, 0xe4, 0x20, 0x66, +0x00, 0x00, 0x3d, 0xe8, +0x6c, 0x00, 0x01, 0x0c, +0x09, 0x6c, 0x00, 0x03, +0x88, 0x48, 0x68, 0x20, +0x02, 0xa5, 0x24, 0x68, +0x00, 0x01, 0xe6, 0x20, +0x66, 0x00, 0x00, 0x3d, +0xe8, 0x6c, 0x00, 0x01, +0xca, 0x09, 0x68, 0x20, +0x01, 0x0f, 0x24, 0x6c, +0x40, 0x05, 0xe2, 0x09, +0x86, 0x00, 0xa3, 0x01, +0x70, 0xbc, 0x04, 0xd6, +0xc0, 0x00, 0x3a, 0x24, +0x86, 0xc4, 0x00, 0x21, +0xe7, 0xaa, 0x26, 0xa4, +0x6c, 0x40, 0x02, 0x1e, +0x08, 0x6c, 0x40, 0x05, +0x30, 0x09, 0x55, 0x03, +0x20, 0x60, 0x0a, 0x30, +0x1a, 0x86, 0xc4, 0x00, +0x21, 0xe4, 0x8b, 0xc0, +0x81, 0x6c, 0x00, 0x03, +0x80, 0x08, 0x32, 0x02, +0x0b, 0xc0, 0x41, 0x6c, +0x00, 0x03, 0x9a, 0x08, +0x32, 0x02, 0x0b, 0xc8, +0x60, 0x68, 0x20, 0x02, +0xa2, 0x24, 0x68, 0x00, +0x01, 0xdc, 0x20, 0x66, +0x00, 0x00, 0x3d, 0xe8, +0x6c, 0x00, 0x00, 0xfa, +0x09, 0x6c, 0x00, 0x03, +0x7c, 0x48, 0x68, 0x20, +0x02, 0xa2, 0x24, 0x68, +0x00, 0x01, 0xde, 0x20, +0x66, 0x00, 0x00, 0x3d, +0xe8, 0x6c, 0x00, 0x01, +0x0c, 0x09, 0x6c, 0x00, +0x03, 0x96, 0x48, 0x68, +0x20, 0x02, 0xa2, 0x24, +0x68, 0x00, 0x01, 0xe0, +0x20, 0x66, 0x00, 0x00, +0x3d, 0xe8, 0x6c, 0x00, +0x01, 0xca, 0x09, 0x68, +0x20, 0x01, 0x0b, 0x24, +0x6c, 0x00, 0x03, 0x7c, +0x0a, 0x5c, 0x83, 0x02, +0x25, 0xc1, 0x86, 0x00, +0x98, 0x48, 0x0b, 0x6c, +0x00, 0x03, 0x96, 0x02, +0x30, 0x1e, 0x86, 0x80, +0x00, 0x1d, 0x82, 0x0b, +0xc3, 0xdd, 0x80, 0x24, +0x8a, 0x26, 0x24, 0x6c, +0x40, 0x05, 0x30, 0x09, +0x86, 0x00, 0x03, 0x00, +0x28, 0xbc, 0x34, 0x86, +0xc4, 0x00, 0x21, 0x67, +0xa6, 0x82, 0x00, 0x29, +0xd2, 0x43, 0x90, 0x21, +0x82, 0x28, 0xb8, 0x60, +0x01, 0x2e, 0x07, 0xf3, +0x69, 0xc1, 0x6c, 0x40, +0x02, 0x00, 0x0b, 0x98, +0x04, 0x13, 0x01, 0xc8, +0xbc, 0x1c, 0x36, 0x82, +0x00, 0x29, 0xf2, 0x10, +0x00, 0x00, 0x80, 0xa8, +0x18, 0x48, 0x03, 0x2e, +0x0c, 0x93, 0x68, 0x41, +0x98, 0x04, 0x13, 0x01, +0xc8, 0xbc, 0x12, 0x36, +0x80, 0x00, 0x1d, 0x52, +0x10, 0x00, 0x00, 0x80, +0xa8, 0x18, 0x48, 0x03, +0x2e, 0x0c, 0x93, 0x68, +0x41, 0x98, 0x04, 0x13, +0x01, 0xc8, 0xbc, 0x08, +0x36, 0x81, 0x66, 0x66, +0x64, 0xb0, 0x87, 0x10, +0x22, 0x20, 0x99, 0x80, +0x49, 0x2e, 0x82, 0xd6, +0xc4, 0x00, 0x53, 0x04, +0x98, 0x20, 0x4a, 0x68, +0x00, 0x01, 0xd5, 0x21, +0x82, 0x2d, 0x26, 0xc4, +0x00, 0x53, 0xa4, 0xa8, +0x0a, 0xc8, 0x42, 0x02, +0x78, 0x60, 0x52, 0x84, +0x84, 0x8b, 0xc0, 0x2f, +0x39, 0x02, 0x13, 0x90, +0x21, 0x68, 0x20, 0x02, +0x99, 0x24, 0x84, 0x00, +0x95, 0x74, 0x94, 0x02, +0x0c, 0xa8, 0x60, 0xc8, +0xe0, 0xb0, 0x1a, 0x20, +0x44, 0x86, 0x00, 0x85, +0x74, 0xd0, 0x04, 0x00, +0x85, 0x78, 0x52, 0x02, +0x2d, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x60, +0x09, 0x57, 0x8d, 0x40, +0x61, 0x89, 0x57, 0x45, +0x40, 0x20, 0x50, 0x82, +0x2d, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x02, 0x16, +0x09, 0x55, 0x03, 0x68, +0x60, 0x0a, 0x2f, 0x0b, +0x46, 0xc4, 0x00, 0x21, +0x64, 0x98, 0x60, 0x48, +0x68, 0x00, 0x01, 0x91, +0x20, 0x66, 0x00, 0x00, +0x48, 0xc0, 0x88, 0x03, +0x66, 0x80, 0x00, 0x59, +0xc2, 0x4b, 0xa1, 0x48, +0x6c, 0x00, 0x01, 0x2e, +0x64, 0x40, 0x00, 0x02, +0x80, 0x10, 0xa2, 0x28, +0x46, 0x40, 0x00, 0x03, +0xde, 0xfa, 0x01, 0x00, +0xab, 0xff, 0x08, 0x80, +0x65, 0x88, 0x0f, 0x66, +0x60, 0x00, 0x03, 0xec, +0x8a, 0x20, 0x84, 0x88, +0x02, 0x08, 0x81, 0x24, +0x94, 0x02, 0x55, 0x00, +0xb0, 0x08, 0x0b, 0x68, +0x60, 0x09, 0x46, 0x0a, +0x41, 0x80, 0x08, 0x44, +0x08, 0x02, 0x80, 0x10, +0x40, 0x00, 0x01, 0x80, +0x08, 0x98, 0x80, 0x86, +0x80, 0x00, 0x0d, 0xe0, +0xa5, 0x80, 0xd0, 0x2b, +0xfd, 0x08, 0x80, 0x60, +0x88, 0x14, 0x98, 0x81, +0xe5, 0x88, 0x26, 0x44, +0x20, 0x4c, 0x08, 0x2f, +0x68, 0x80, 0xe1, 0x68, +0x20, 0x00, 0xd0, 0x24, +0x88, 0x0a, 0x06, 0x60, +0x00, 0x03, 0xde, 0x08, +0x80, 0x20, 0xbc, 0x0b, +0xf8, 0x41, 0xc8, 0x68, +0x20, 0x00, 0xd0, 0x24, +0x68, 0x00, 0x00, 0xdc, +0x20, 0x66, 0x00, 0x00, +0x3d, 0xe0, 0x88, 0x02, +0x00, 0x00, 0x00, 0x40, +0x00, 0x00, 0x41, 0xc8, +0x68, 0x20, 0x01, 0x1d, +0x24, 0x6c, 0x40, 0x01, +0xae, 0x09, 0x5d, 0x0a, +0x20, 0x41, 0x89, 0x51, +0x85, 0x20, 0x40, 0x0b, +0x57, 0x0f, 0x51, 0x88, +0x09, 0x68, 0x00, 0x00, +0xde, 0x00, 0x58, 0x01, +0x41, 0x82, 0x28, 0x68, +0x20, 0x02, 0x69, 0x21, +0x98, 0x08, 0x24, 0x20, +0x1c, 0x1e, 0x00, 0x59, +0xc8, 0x06, 0xbc, 0x03, +0xf8, 0x68, 0x08, 0x40, +0x00, 0x00, 0x70, 0x08, +0x5b, 0x44, 0x30, 0x82, +0x21, 0x58, 0x49, 0x80, +0x84, 0x24, 0xa0, 0x88, +0x26, 0xc4, 0x00, 0x1d, +0xa0, 0x89, 0x60, 0x3e, +0x42, 0x03, 0x52, 0x10, +0x61, 0xa1, 0x0a, 0x36, +0xe0, 0x00, 0x12, 0xc2, +0x93, 0x81, 0x2b, 0x25, +0x8c, 0x8b, 0xc7, 0x70, +0x88, 0x32, 0x68, 0x81, +0xa7, 0x97, 0x02, 0x85, +0x90, 0x20, 0x08, 0x0a, +0x5b, 0xc1, 0x19, 0x87, +0x87, 0xa0, 0x00, 0x00, +0x86, 0x88, 0x03, 0x01, +0xc0, 0xbc, 0x07, 0xb8, +0x43, 0x80, 0x30, 0x03, +0x8b, 0xc0, 0x94, 0x98, +0xe8, 0x08, 0x68, 0xcb, +0x97, 0x06, 0x0b, 0xc0, +0x57, 0x30, 0x03, 0x8b, +0xc0, 0x3a, 0x98, 0xe8, +0x08, 0x68, 0xcb, 0x97, +0x06, 0x00, 0x00, 0x00, +0x6c, 0x40, 0x03, 0xc2, +0x00, 0x85, 0x18, 0xb3, +0x00, 0x38, 0xbc, 0x24, +0x83, 0x90, 0x20, 0x68, +0x20, 0x01, 0xe6, 0x27, +0x5c, 0x82, 0x08, 0x52, +0x8b, 0x5c, 0x85, 0x10, +0x38, 0x02, 0x57, 0x05, +0xca, 0x18, 0x06, 0x59, +0x00, 0x80, 0x1a, 0xd1, +0x00, 0x00, 0x08, 0x3b, +0x0b, 0x85, 0x80, 0x25, +0x70, 0xe9, 0x07, 0x80, +0xb8, 0x58, 0x52, 0xbc, +0x06, 0xc8, 0x52, 0x82, +0x30, 0x1d, 0x0b, 0xc0, +0x82, 0x85, 0x1d, 0x08, +0x49, 0x4b, 0xbc, 0x05, +0x73, 0x01, 0xd0, 0xbc, +0x03, 0x48, 0x51, 0xd0, +0x84, 0x94, 0xb0, 0x00, +0x00, 0x85, 0x80, 0xb5, +0x70, 0xf0, 0x03, 0x20, +0xb5, 0x70, 0xe0, 0x08, +0x3a, 0x1b, 0xc0, 0x3f, +0x87, 0x04, 0x08, 0x83, +0xa1, 0x00, 0x00, 0x00, +0x00, 0x00, 0x84, 0x80, +0xb3, 0x01, 0x38, 0xbc, +0x0b, 0x36, 0xc4, 0x00, +0x21, 0x00, 0x02, 0x80, +0x3f, 0x30, 0x93, 0x8b, +0xc0, 0x34, 0xbc, 0x06, +0xf5, 0xc0, 0xbe, 0x04, +0x84, 0xbb, 0xc0, 0x3f, +0x5c, 0x0b, 0xe0, 0x48, +0x48, 0x38, 0x17, 0xc2, +0x59, 0x30, 0xbc, 0x20, +0x13, 0x81, 0x67, 0x25, +0x9f, 0x0b, 0xc0, 0xf9, +0x38, 0x17, 0x42, 0x59, +0x30, 0xbc, 0x04, 0x99, +0x8e, 0x88, 0x84, 0x30, +0xb3, 0x20, 0x38, 0xbc, +0x06, 0x43, 0x81, 0x77, +0x25, 0x9f, 0x0b, 0xc1, +0x30, 0x84, 0x30, 0xa3, +0x20, 0x30, 0xbc, 0x10, +0x39, 0x60, 0x74, 0xbc, +0x0e, 0x72, 0x59, 0x30, +0xbc, 0x04, 0x93, 0x81, +0x64, 0x84, 0x30, 0xb3, +0x20, 0x38, 0xbc, 0x06, +0x23, 0x81, 0x77, 0x25, +0x9f, 0x0b, 0xc0, 0x50, +0x84, 0x30, 0xb3, 0x20, +0x38, 0xbc, 0x02, 0x52, +0x41, 0x30, 0x96, 0x07, +0x0b, 0xc4, 0x6f, 0x88, +0x1a, 0x23, 0x00, 0x28, +0xbc, 0x02, 0x0b, 0xc0, +0x2f, 0x86, 0x80, 0x08, +0x70, 0x00, 0x32, 0x01, +0x0b, 0xc0, 0x4c, 0x88, +0x0a, 0x55, 0x70, 0x1c, +0x3c, 0x03, 0xf8, 0x68, +0xc0, 0x28, 0x1c, 0x08, +0x68, 0xc0, 0x68, 0x20, +0x01, 0x16, 0x23, 0x88, +0x1a, 0x28, 0x58, 0x0b, +0x85, 0x00, 0x05, 0x50, +0x20, 0x08, 0x32, 0x65, +0x80, 0xe0, 0x05, 0x05, +0x0a, 0x1d, 0xa3, 0x42, +0x02, 0x6b, 0x00, 0x08, +0x97, 0x06, 0x0b, 0xc0, +0x4f, 0x5c, 0x81, 0x08, +0x50, 0x4b, 0x5c, 0x81, +0x0b, 0x80, 0x00, 0x68, +0x20, 0x01, 0xe3, 0x26, +0x5c, 0x0b, 0xfa, 0xc0, +0x40, 0x52, 0xcf, 0x80, +0x30, 0x8a, 0x87, 0x00, +0x28, 0x08, 0xca, 0x84, +0x85, 0x20, 0x00, 0x00, +0x88, 0x3a, 0x78, 0x1a, +0x0a, 0x87, 0x08, 0x24, +0x20, 0x74, 0x07, 0x84, +0xa5, 0xc0, 0x00, 0x04, +0x8d, 0x22, 0x41, 0xc7, +0x5d, 0x4e, 0x38, 0x43, +0x00, 0x32, 0x00, 0x0b, +0xc0, 0x5c, 0x5c, 0x0b, +0xb1, 0x60, 0x77, 0x52, +0x4d, 0xc3, 0xc0, 0x3f, +0x96, 0x07, 0x02, 0x41, +0xb8, 0x96, 0x07, 0x08, +0x58, 0x48, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x02, 0xb6, 0x0a, +0x6c, 0x40, 0x01, 0x50, +0x4a, 0x6c, 0x40, 0x01, +0x80, 0x4a, 0x68, 0x00, +0x00, 0x76, 0x08, 0x58, +0x09, 0x40, 0x68, 0x89, +0x84, 0x1c, 0x9b, 0xc1, +0x68, 0x85, 0x00, 0x99, +0x88, 0x08, 0x68, 0x00, +0x00, 0x7f, 0x0a, 0x30, +0x1a, 0x0b, 0xc0, 0x80, +0x68, 0x00, 0x01, 0xce, +0x21, 0x66, 0x00, 0x01, +0xb8, 0x00, 0x88, 0x02, +0x0b, 0xc1, 0x1f, 0x40, +0x00, 0x00, 0x40, 0x48, +0x68, 0x00, 0x01, 0xc1, +0x21, 0x66, 0x00, 0x01, +0xb8, 0x00, 0x88, 0x02, +0x0b, 0xc0, 0x9f, 0x40, +0x00, 0x00, 0x40, 0x48, +0x68, 0x00, 0x01, 0xb4, +0x21, 0x66, 0x00, 0x01, +0xb8, 0x00, 0x88, 0x02, +0x00, 0x00, 0x00, 0x84, +0x04, 0x80, 0x00, 0x00, +0x6c, 0x40, 0x01, 0xea, +0x09, 0x6c, 0x40, 0x02, +0x36, 0x08, 0x30, 0x12, +0x8b, 0xc0, 0x48, 0x88, +0x4a, 0x44, 0x21, 0x57, +0x84, 0x00, 0x98, 0x60, +0x49, 0x6c, 0x40, 0x05, +0x30, 0x08, 0x6c, 0x40, +0x01, 0xf4, 0x0a, 0x30, +0x1a, 0x0b, 0xc2, 0x39, +0x5c, 0x09, 0x70, 0x60, +0x0b, 0x6e, 0x00, 0x01, +0x2c, 0x28, 0x25, 0x98, +0x0b, 0xc0, 0xc1, 0x54, +0x09, 0xc0, 0x40, 0x0a, +0x98, 0x00, 0x03, 0x00, +0x30, 0xbc, 0x01, 0x58, +0x40, 0x50, 0x2e, 0x13, +0x88, 0x40, 0x08, 0x98, +0x00, 0xa3, 0x01, 0xa0, +0xbc, 0x01, 0x38, 0x40, +0x4a, 0x00, 0x00, 0x08, +0x40, 0x08, 0x86, 0x00, +0xa3, 0x01, 0xa0, 0x6c, +0x40, 0x02, 0x2a, 0x00, +0xbc, 0x03, 0xb2, 0x08, +0x2d, 0x2e, 0x17, 0x88, +0x60, 0x40, 0x00, 0x00, +0x08, 0x40, 0x08, 0x86, +0x00, 0xa3, 0x01, 0xa0, +0xbc, 0x02, 0x52, 0x81, +0x78, 0x86, 0x04, 0x00, +0x00, 0x00, 0x88, 0x2b, +0x68, 0x40, 0x08, 0x46, +0x0a, 0x40, 0x81, 0x09, +0x57, 0x09, 0x42, 0x80, +0x30, 0x40, 0x00, 0x01, +0x80, 0x08, 0x5c, 0x09, +0xe2, 0x22, 0xe4, 0x86, +0x00, 0xa4, 0x43, 0x00, +0x16, 0x9a, 0x55, 0x00, +0xa0, 0x08, 0x02, 0x56, +0xe0, 0x00, 0x12, 0xc2, +0xd5, 0x2c, 0x94, 0x06, +0x80, 0x94, 0x20, 0x24, +0x18, 0x00, 0x80, 0x81, +0x00, 0xba, 0x14, 0x89, +0x80, 0x08, 0x00, 0x00, +0x08, 0x40, 0x89, 0x46, +0x0a, 0x40, 0x68, 0x88, +0x08, 0x48, 0x09, 0x80, +0x08, 0xab, 0xfd, 0x0a, +0x21, 0x64, 0xa0, 0x88, +0x18, 0x80, 0x64, 0xa2, +0x06, 0x48, 0x80, 0xe1, +0xa0, 0x84, 0x18, 0x81, +0x64, 0x88, 0x1c, 0x98, +0x82, 0x60, 0x88, 0x2f, +0x66, 0x60, 0x00, 0x03, +0xde, 0x8a, 0x08, 0x00, +0x88, 0x12, 0x08, 0x82, +0x21, 0xa0, 0x06, 0x08, +0x40, 0x0a, 0x88, 0x18, +0x94, 0x43, 0x00, 0x04, +0xa4, 0x8a, 0x06, 0x24, +0x66, 0x00, 0x01, 0xd3, +0x88, 0x40, 0x00, 0x01, +0x80, 0x09, 0x6e, 0x00, +0x01, 0xa2, 0x25, 0x59, +0x03, 0x40, 0x80, 0xa4, +0xbc, 0x0f, 0x8a, 0x20, +0x20, 0x6c, 0x40, 0x02, +0xb4, 0x09, 0x88, 0x02, +0x48, 0x80, 0xc8, 0x66, +0x00, 0x02, 0x3e, 0xa8, +0x40, 0x00, 0x00, 0x60, +0x8a, 0x55, 0x01, 0x28, +0x80, 0x20, 0x00, 0x00, +0x08, 0x40, 0xc9, 0xbc, +0x0c, 0xf8, 0x80, 0x88, +0x86, 0x08, 0x96, 0xc4, +0x00, 0x1f, 0x00, 0xa3, +0x69, 0x45, 0x30, 0x97, +0x0b, 0xc0, 0x55, 0x88, +0x02, 0x06, 0xc4, 0x00, +0x1d, 0xa0, 0x98, 0x40, +0xc9, 0x00, 0x00, 0x08, +0x82, 0xb6, 0xba, 0x14, +0x8a, 0x80, 0x30, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5c, 0x81, 0x02, 0x00, +0x80, 0xa2, 0x16, 0x48, +0x20, 0x0a, 0x84, 0x00, +0x84, 0x41, 0x00, 0x02, +0x00, 0xa8, 0x40, 0x88, +0x44, 0x14, 0x00, 0x60, +0x08, 0xba, 0x14, 0x84, +0x42, 0x40, 0x04, 0x04, +0x99, 0x80, 0x08, 0xa2, +0x24, 0x48, 0x60, 0x08, +0x44, 0x20, 0x00, 0x60, +0x89, 0x98, 0x00, 0x84, +0x40, 0x80, 0x16, 0x8a, +0x5b, 0xa1, 0x48, 0x20, +0x14, 0x09, 0x80, 0x08, +0x5c, 0x83, 0x10, 0x43, +0x08, 0x98, 0x84, 0xb5, +0x90, 0x1c, 0x2b, 0xfe, +0x08, 0x01, 0x01, 0x6c, +0x40, 0x01, 0xf4, 0x0a, +0x6c, 0x40, 0x05, 0x30, +0x00, 0xa0, 0x94, 0x28, +0x40, 0x02, 0x88, 0x0c, +0x98, 0x81, 0x48, 0x42, +0x1a, 0x40, 0x81, 0xca, +0x88, 0x05, 0x13, 0x01, +0x80, 0xbc, 0x09, 0x16, +0xc0, 0x00, 0x38, 0x00, +0x83, 0x20, 0x20, 0xbc, +0x05, 0x16, 0xc0, 0x00, +0x39, 0xa0, 0x83, 0x20, +0x20, 0x40, 0x00, 0x03, +0xc2, 0x50, 0x68, 0x20, +0x01, 0x0b, 0x20, 0x84, +0xd0, 0x8a, 0x05, 0xc3, +0x84, 0x00, 0x98, 0x58, +0x0a, 0x30, 0x1a, 0x8b, +0xc1, 0x4d, 0x5c, 0x81, +0x02, 0x14, 0x80, 0x5c, +0x08, 0x1a, 0x08, 0xe2, +0x5c, 0x82, 0x08, 0x12, +0x0a, 0x50, 0x47, 0x88, +0x10, 0x89, 0x20, 0x8e, +0xb5, 0x40, 0x64, 0xb0, +0x1f, 0xb2, 0x08, 0xcb, +0x2c, 0x85, 0xb1, 0x4b, +0x75, 0x51, 0x42, 0x48, +0x10, 0x53, 0x81, 0x34, +0xd4, 0x20, 0x17, 0x85, +0x04, 0x88, 0x50, 0xc8, +0x39, 0x04, 0x10, 0x00, +0x00, 0x84, 0x00, 0x95, +0x78, 0x96, 0x84, 0x08, +0xa5, 0x74, 0x9a, 0x04, +0x04, 0x94, 0x20, 0x2b, +0x84, 0x0c, 0x8b, 0xc0, +0x4f, 0x5c, 0x81, 0x02, +0xc0, 0x41, 0x5c, 0x81, +0x02, 0xc0, 0x41, 0x6e, +0x00, 0x01, 0xa2, 0x24, +0x32, 0x02, 0x0b, 0xc0, +0xa9, 0x6c, 0x40, 0x01, +0xea, 0x09, 0x6c, 0x40, +0x02, 0x36, 0x0a, 0x30, +0x1a, 0x8b, 0xc0, 0x41, +0x6c, 0x00, 0x06, 0x16, +0x0a, 0x30, 0x17, 0x0b, +0xc0, 0xe2, 0x6c, 0x40, +0x02, 0x36, 0x0a, 0x30, +0x1a, 0x8b, 0xc0, 0x88, +0x5c, 0x00, 0x08, 0x80, +0x0a, 0x88, 0x08, 0x16, +0x80, 0x00, 0x15, 0x20, +0x33, 0x00, 0xc8, 0xbc, +0x17, 0xc9, 0x8e, 0x81, +0x2a, 0x02, 0x9b, 0xc1, +0x47, 0x6c, 0x00, 0x06, +0x16, 0x0a, 0x30, 0x17, +0x0b, 0xc0, 0xc3, 0x6c, +0x00, 0x06, 0x18, 0x01, +0x2a, 0x04, 0x93, 0x22, +0xc8, 0xbc, 0x07, 0xd6, +0xc0, 0x00, 0x61, 0x85, +0x12, 0xa0, 0x76, 0x6c, +0x00, 0x06, 0x16, 0x4a, +0x6c, 0x00, 0x06, 0x18, +0x7a, 0x00, 0x00, 0x06, +0xc0, 0x00, 0x61, 0x60, +0x18, 0x80, 0x0a, 0x32, +0x06, 0x04, 0xa7, 0x38, +0xbc, 0x0c, 0x85, 0x50, +0x1c, 0x9a, 0x14, 0x13, +0x01, 0x90, 0xbc, 0x06, +0x43, 0x01, 0x90, 0xbc, +0x10, 0xb5, 0x50, 0x1a, +0x08, 0x18, 0x29, 0x82, +0xc8, 0xbc, 0x0c, 0x7b, +0xc0, 0xbf, 0x88, 0x18, +0x28, 0x81, 0x02, 0x32, +0x01, 0x0b, 0xc0, 0x64, +0x32, 0x01, 0x0b, 0xc0, +0x5b, 0x55, 0x01, 0xa0, +0x81, 0x82, 0x98, 0x2c, +0x8b, 0xc0, 0x17, 0x88, +0x18, 0x23, 0x00, 0x80, +0xbc, 0x58, 0x06, 0xc0, +0x00, 0x38, 0x00, 0xa3, +0x20, 0x30, 0xbc, 0x04, +0x16, 0xc0, 0x00, 0x39, +0xa0, 0xa3, 0x20, 0x30, +0xbc, 0x50, 0x03, 0x20, +0x08, 0xbc, 0x4e, 0x06, +0xc0, 0x00, 0x38, 0x00, +0xa3, 0x20, 0x30, 0xbc, +0x05, 0x16, 0xc0, 0x00, +0x39, 0xa0, 0xa3, 0x20, +0x30, 0x40, 0x00, 0x03, +0xc4, 0x50, 0x6c, 0x40, +0x02, 0x36, 0x0a, 0x30, +0x1a, 0x8b, 0xc4, 0x10, +0x68, 0x20, 0x00, 0xfb, +0x20, 0x84, 0xc0, 0x98, +0x00, 0x0b, 0x30, 0x1e, +0x8b, 0xc0, 0x22, 0xbc, +0x04, 0xf8, 0x4d, 0xfa, +0x84, 0xd8, 0x92, 0xa0, +0x6d, 0x84, 0xdc, 0x90, +0x00, 0x00, 0x84, 0x00, +0x96, 0xc0, 0x00, 0x37, +0xe0, 0xb3, 0x01, 0x78, +0xbc, 0x04, 0x56, 0xc0, +0x00, 0x39, 0x80, 0xb3, +0x01, 0x78, 0xbc, 0x03, +0x4b, 0xc2, 0xbf, 0x40, +0x00, 0x00, 0x4d, 0x08, +0x68, 0x00, 0x00, 0x62, +0x22, 0x68, 0x00, 0x00, +0x6c, 0x21, 0x81, 0x07, +0xa8, 0x08, 0x7a, 0xa0, +0x80, 0x4a, 0x10, 0x00, +0x81, 0x07, 0xa8, 0x08, +0x7a, 0x84, 0x0f, 0xa8, +0x60, 0xfa, 0x68, 0x00, +0x00, 0xd2, 0x23, 0x68, +0x00, 0x01, 0xbe, 0x25, +0x81, 0x87, 0xa6, 0x82, +0x00, 0x29, 0x92, 0x48, +0x28, 0x82, 0x68, 0x00, +0x01, 0xcb, 0x26, 0x68, +0x00, 0x01, 0xd8, 0x20, +0xa1, 0x80, 0x7c, 0x03, +0x00, 0x83, 0x08, 0x18, +0x18, 0x7a, 0x87, 0x8f, +0xa6, 0xc4, 0x00, 0x1e, +0xa4, 0xa6, 0xc0, 0x00, +0x13, 0x07, 0xa8, 0x40, +0x7a, 0x87, 0x07, 0xa8, +0x68, 0x7a, 0x86, 0x0d, +0x08, 0x60, 0x51, 0x85, +0x0f, 0xa8, 0x48, 0xfa, +0x85, 0x8f, 0xab, 0xa1, +0x48, 0xa8, 0x02, 0x00, +0x00, 0x00, 0x85, 0x00, +0x88, 0x40, 0x09, 0x57, +0x8b, 0x22, 0xbf, 0xd0, +0x85, 0x04, 0x88, 0x80, +0x63, 0x88, 0x0e, 0x28, +0x81, 0x61, 0x88, 0x1e, +0x08, 0x82, 0x76, 0x00, +0x00, 0x08, 0x40, 0x09, +0x36, 0x14, 0x52, 0xe9, +0x64, 0x85, 0x04, 0x80, +0x00, 0x00, 0x85, 0x80, +0x88, 0x48, 0x09, 0x2f, +0x16, 0x48, 0x58, 0x48, +0x00, 0x00, 0x08, 0x48, +0x09, 0x36, 0x14, 0x52, +0xe9, 0x64, 0x44, 0x00, +0x00, 0x58, 0x48, 0x98, +0x00, 0x98, 0x50, 0x08, +0x44, 0x00, 0x00, 0x48, +0x08, 0x44, 0x01, 0x00, +0x40, 0x08, 0x44, 0x01, +0x01, 0xa0, 0x00, 0x44, +0x40, 0x01, 0x80, 0x88, +0x08, 0x18, 0x06, 0x60, +0x00, 0x04, 0x0a, 0x89, +0x81, 0x09, 0x88, 0x12, +0x08, 0x81, 0xa1, 0x84, +0x00, 0x98, 0x48, 0x0a, +0x44, 0x48, 0x00, 0x80, +0xa0, 0x88, 0x02, 0x19, +0x80, 0x0b, 0x84, 0x00, +0x94, 0x46, 0x80, 0x04, +0x80, 0xa4, 0x47, 0x10, +0x18, 0x00, 0xb4, 0x46, +0x00, 0x18, 0x28, 0xb5, +0x11, 0xe0, 0x18, 0x08, +0xa4, 0x44, 0x10, 0x18, +0x00, 0x83, 0x20, 0x20, +0x51, 0x1e, 0x83, 0xc0, +0x29, 0x98, 0x00, 0xa9, +0x82, 0x48, 0x32, 0x03, +0x0b, 0xc0, 0x11, 0x98, +0x2c, 0xa3, 0x69, 0x40, +0x5b, 0x48, 0x01, 0x80, +0x09, 0x98, 0x00, 0x03, +0x00, 0x28, 0xbc, 0x06, +0x43, 0x69, 0xc0, 0x5b, +0x4c, 0x01, 0x80, 0x09, +0x98, 0x00, 0xb3, 0x01, +0xe8, 0xbc, 0x04, 0x58, +0x40, 0x48, 0x42, 0x01, +0x7b, 0x00, 0x0c, 0x84, +0x84, 0xa9, 0x8e, 0x88, +0x00, 0x00, 0x08, 0x82, +0x36, 0xba, 0x14, 0x8a, +0x80, 0x30, 0x40, 0x00, +0x03, 0x80, 0x00, 0x46, +0x08, 0x8a, 0xbf, 0xe0, +0x51, 0x61, 0xb0, 0x80, +0x49, 0x51, 0x61, 0xe0, +0x80, 0xf6, 0x1a, 0x0a, +0x29, 0x83, 0x09, 0x98, +0x38, 0x82, 0x81, 0x2d, +0x88, 0x14, 0x96, 0x60, +0x00, 0x04, 0x0a, 0x8b, +0xa1, 0x01, 0x88, 0x10, +0x94, 0x40, 0x80, 0x08, +0x00, 0x99, 0x80, 0x08, +0x23, 0x42, 0x43, 0x01, +0x60, 0xbc, 0x02, 0x5b, +0xc0, 0x2f, 0x2e, 0x16, +0x49, 0x8e, 0x88, 0x88, +0x0b, 0x6b, 0xa1, 0x48, +0xa8, 0x02, 0x00, 0x00, +0x00, 0x68, 0x20, 0x01, +0x9c, 0x22, 0x68, 0x00, +0x01, 0x38, 0x23, 0x5c, +0x81, 0x02, 0x10, 0x21, +0xa0, 0x82, 0x48, 0x60, +0x0a, 0xa2, 0x02, 0x08, +0x50, 0x08, 0xa0, 0x02, +0x28, 0x58, 0x09, 0x44, +0x20, 0x02, 0x18, 0x25, +0x86, 0x80, 0x84, 0x41, +0x10, 0x04, 0x80, 0xa4, +0x41, 0x40, 0x05, 0x00, +0xaa, 0x28, 0x23, 0x85, +0x80, 0x84, 0x41, 0x08, +0x21, 0x52, 0x46, 0xc0, +0x00, 0x25, 0x44, 0x1a, +0x1c, 0xa1, 0x84, 0x00, +0xb4, 0x43, 0xd4, 0x52, +0x08, 0x04, 0x41, 0x08, +0x00, 0x80, 0xa8, 0x20, +0x09, 0x44, 0x4c, 0xa0, +0x20, 0x09, 0x44, 0x49, +0x80, 0x20, 0x0a, 0x44, +0x15, 0xe0, 0x48, 0x08, +0x86, 0x00, 0xa6, 0x80, +0x00, 0x08, 0x82, 0x06, +0xc0, 0x00, 0x22, 0x84, +0x04, 0x41, 0x08, 0x00, +0x04, 0x16, 0xc0, 0x00, +0x1c, 0xe4, 0x16, 0xc0, +0x00, 0x23, 0xe4, 0x2b, +0xa1, 0x48, 0x84, 0x04, +0x30, 0x00, 0x00, 0x68, +0x00, 0x00, 0x62, 0x20, +0x5c, 0x81, 0x01, 0x8e, +0x88, 0x68, 0x00, 0x00, +0x6c, 0x21, 0x55, 0x03, +0x20, 0x00, 0x7a, 0x3a, +0x10, 0x43, 0x22, 0xa0, +0xbf, 0xfb, 0xa8, 0x08, +0x7a, 0x68, 0x00, 0x00, +0xda, 0x20, 0x00, 0x00, +0x08, 0x40, 0x7a, 0x84, +0x0f, 0xa6, 0xc0, 0x00, +0x61, 0x87, 0xa0, 0x00, +0x00, 0x6c, 0x40, 0x02, +0x36, 0x08, 0xba, 0x14, +0x86, 0xc0, 0x00, 0x61, +0x64, 0x80, 0x00, 0x00, +0x84, 0x00, 0xa8, 0x60, +0x08, 0x44, 0x40, 0x00, +0x48, 0x08, 0x46, 0x0a, +0x40, 0x60, 0x8a, 0x08, +0x28, 0x09, 0x80, 0x08, +0x6e, 0x00, 0x01, 0x2c, +0x2c, 0x38, 0x12, 0x62, +0x59, 0xa0, 0xbc, 0x09, +0x18, 0x63, 0x88, 0x6c, +0x40, 0x03, 0xc2, 0x0a, +0x30, 0x1a, 0x0b, 0xc0, +0x40, 0x6c, 0x40, 0x02, +0x0e, 0x08, 0x08, 0x40, +0x09, 0x80, 0x09, 0xba, +0x14, 0x89, 0x82, 0x48, +0x40, 0x00, 0x03, 0x80, +0x00, 0x68, 0x20, 0x00, +0x24, 0x25, 0x68, 0x00, +0x00, 0x5e, 0x20, 0x5c, +0x82, 0x02, 0xc0, 0x21, +0x68, 0x20, 0x00, 0x4b, +0x24, 0x5c, 0x08, 0xad, +0x02, 0xd0, 0x68, 0x00, +0x00, 0x96, 0x21, 0x44, +0x18, 0x00, 0x20, 0x0a, +0x84, 0x00, 0x84, 0x41, +0x08, 0x14, 0x82, 0xc5, +0x2c, 0xb0, 0x2b, 0xf7, +0x06, 0x82, 0x00, 0x0a, +0xe2, 0x18, 0x81, 0x64, +0x88, 0x1e, 0x58, 0x82, +0x76, 0x88, 0x2d, 0x59, +0x04, 0x58, 0x42, 0x09, +0x48, 0x85, 0x54, 0x40, +0x00, 0x01, 0x03, 0x59, +0x68, 0x00, 0x00, 0x36, +0x20, 0x66, 0x00, 0x02, +0x0e, 0xc0, 0x68, 0x00, +0x00, 0x4a, 0x20, 0x68, +0x20, 0x00, 0xc6, 0x21, +0x66, 0x00, 0x02, 0x0e, +0xc0, 0x6c, 0x00, 0x01, +0x0e, 0x0a, 0x40, 0x00, +0x03, 0xc1, 0x1f, 0x6c, +0x00, 0x00, 0xfc, 0x09, +0x68, 0x00, 0x00, 0x36, +0x20, 0x66, 0x00, 0x02, +0x0e, 0xc0, 0x68, 0x00, +0x00, 0x4a, 0x20, 0x68, +0x20, 0x00, 0xc6, 0x21, +0x66, 0x00, 0x02, 0x0e, +0xc0, 0x68, 0x00, 0x00, +0x60, 0x20, 0x00, 0x00, +0x08, 0x40, 0x8a, 0x84, +0x00, 0x98, 0x85, 0xca, +0x40, 0x00, 0x00, 0x86, +0x49, 0x68, 0x20, 0x00, +0x85, 0x24, 0x66, 0x00, +0x01, 0xf4, 0xe8, 0x6e, +0x40, 0x01, 0x12, 0x27, +0x68, 0x20, 0x00, 0x85, +0x20, 0x88, 0x84, 0x8a, +0x00, 0x88, 0x94, 0x02, +0x78, 0x86, 0x0a, 0x88, +0x58, 0x96, 0x60, 0x00, +0x1f, 0x4e, 0x8a, 0x04, +0x4c, 0x6e, 0x00, 0x01, +0x2c, 0x2d, 0x5c, 0x08, +0xf0, 0x85, 0xc8, 0x68, +0x00, 0x00, 0x96, 0x20, +0x52, 0xcd, 0x40, 0x88, +0x09, 0x88, 0x8c, 0x84, +0x21, 0x04, 0xa0, 0x00, +0x88, 0x86, 0x60, 0x68, +0x20, 0x00, 0x90, 0x2c, +0x68, 0x20, 0x00, 0x8a, +0x24, 0x68, 0x20, 0x00, +0x8d, 0x25, 0x40, 0x00, +0x00, 0x80, 0x6c, 0x66, +0x00, 0x01, 0xf5, 0x60, +0x6c, 0x40, 0x00, 0x4a, +0x09, 0x44, 0x08, 0x00, +0x85, 0x89, 0x68, 0x20, +0x00, 0x98, 0xac, 0x88, +0x84, 0x86, 0x82, 0x00, +0x09, 0x2a, 0x46, 0x82, +0x00, 0x09, 0x5a, 0x58, +0x80, 0x6c, 0x90, 0x75, +0x88, 0x85, 0xd4, 0x66, +0x00, 0x01, 0xf5, 0x60, +0x6c, 0x40, 0x00, 0x98, +0x09, 0xbc, 0x0d, 0xf4, +0x40, 0x80, 0x08, 0x8c, +0x80, 0x00, 0x00, 0x6c, +0x40, 0x00, 0x4a, 0x08, +0x44, 0x20, 0x80, 0x85, +0x88, 0x6c, 0x40, 0x00, +0x98, 0x09, 0x44, 0x08, +0x01, 0x07, 0x59, 0x40, +0x00, 0x00, 0x85, 0xd5, +0x68, 0x00, 0x00, 0x42, +0x20, 0x90, 0x71, 0x1a, +0x04, 0x21, 0x88, 0x59, +0x58, 0x85, 0xe1, 0x90, +0x75, 0x88, 0x86, 0xd4, +0x66, 0x00, 0x00, 0x3c, +0xa8, 0x5c, 0x00, 0x71, +0x80, 0x49, 0x68, 0x00, +0x00, 0x56, 0x20, 0x90, +0x71, 0x0a, 0x04, 0x21, +0x88, 0x69, 0x48, 0x86, +0xe1, 0x40, 0x00, 0x00, +0x87, 0x48, 0x66, 0x00, +0x00, 0x3c, 0xa8, 0x5c, +0x00, 0x71, 0x80, 0x09, +0x5c, 0x08, 0x00, 0x81, +0x20, 0x88, 0x5a, 0x48, +0x81, 0xa5, 0x88, 0x14, +0x8a, 0x25, 0x64, 0x88, +0x6a, 0x19, 0x04, 0x12, +0x88, 0x62, 0x2a, 0x0d, +0x61, 0x86, 0x80, 0x88, +0x60, 0x0a, 0x88, 0x51, +0x64, 0x44, 0x54, 0x10, +0x31, 0x18, 0x40, 0x09, +0x88, 0x29, 0x59, 0x50, +0x2c, 0x52, 0xc1, 0x00, +0x48, 0x0b, 0x44, 0x6c, +0xa1, 0x80, 0x80, 0x98, +0x04, 0x28, 0x67, 0x50, +0x88, 0x1e, 0x14, 0x20, +0xdc, 0x88, 0x2e, 0x48, +0x4f, 0x52, 0x68, 0x20, +0x02, 0xbe, 0x20, 0x5c, +0x81, 0x01, 0xa0, 0x01, +0x68, 0x20, 0x02, 0xc1, +0x21, 0x4c, 0x04, 0x38, +0x02, 0x03, 0x80, 0x20, +0x94, 0x40, 0x88, 0x00, +0xa0, 0xa5, 0x10, 0x24, +0x80, 0xa0, 0x84, 0x46, +0x00, 0x18, 0x00, 0x85, +0x10, 0x20, 0x04, 0x00, +0x94, 0x85, 0x88, 0x18, +0x08, 0xa4, 0x40, 0xc0, +0x04, 0x80, 0xb0, 0x8b, +0xa8, 0x6c, 0x00, 0x00, +0x80, 0x40, 0x6c, 0x00, +0x00, 0xa8, 0x42, 0x5c, +0x09, 0x20, 0x84, 0x56, +0x90, 0x55, 0x88, 0x84, +0xd4, 0x00, 0x00, 0x06, +0xc4, 0x00, 0x40, 0x20, +0x92, 0x59, 0x28, 0xbc, +0x7d, 0x99, 0x03, 0x5a, +0x38, 0x11, 0xc6, 0xe4, +0x00, 0x3f, 0xe2, 0xe3, +0x01, 0x30, 0xbc, 0x13, +0x36, 0x82, 0x00, 0x23, +0x4a, 0x06, 0x80, 0x03, +0xfc, 0x00, 0x85, 0xd4, +0xc2, 0x94, 0x03, 0xf5, +0x44, 0x9f, 0xac, 0x66, +0x15, 0x48, 0xbf, 0xac, +0xd1, 0x05, 0x50, 0x38, +0x14, 0x0d, 0x70, 0x00, +0x00, 0x94, 0x03, 0xe2, +0x89, 0x34, 0x29, 0x16, +0x44, 0x23, 0x2f, 0x94, +0x25, 0x49, 0x40, 0x60, +0x6c, 0x00, 0x00, 0x6e, +0x08, 0x57, 0x08, 0x02, +0xc0, 0x20, 0x6c, 0x00, +0x00, 0x96, 0x0a, 0x6c, +0x00, 0x02, 0xb4, 0x08, +0x49, 0x21, 0x32, 0xc6, +0xd1, 0x6c, 0x00, 0x02, +0xb6, 0x0b, 0x6c, 0x00, +0x02, 0xb0, 0x0a, 0x6c, +0x00, 0x02, 0xb2, 0x08, +0x2e, 0x1d, 0x26, 0x82, +0x00, 0x1f, 0xd2, 0x04, +0x89, 0x28, 0x30, 0x18, +0x45, 0x2c, 0x94, 0x00, +0x04, 0x34, 0x20, 0xbc, +0x00, 0x0c, 0x08, 0x86, +0x60, 0x38, 0x1c, 0x42, +0x59, 0x28, 0x40, 0x00, +0x03, 0xc0, 0xf9, 0x68, +0x20, 0x02, 0x35, 0x24, +0x66, 0x00, 0x02, 0x1e, +0x40, 0x68, 0x20, 0x02, +0x35, 0x20, 0x5c, 0x0e, +0x2b, 0x01, 0x64, 0x76, +0x00, 0x10, 0x06, 0x80, +0x84, 0x00, 0xa2, 0x49, +0x75, 0x52, 0x09, 0x6b, +0xc1, 0x2f, 0x84, 0x04, +0x9b, 0xc1, 0x0f, 0x5c, +0x0b, 0x23, 0x80, 0x00, +0x68, 0x20, 0x02, 0x02, +0x24, 0x66, 0x00, 0x02, +0x1e, 0x40, 0x68, 0x20, +0x02, 0x02, 0x20, 0x5c, +0x0c, 0x2b, 0x01, 0x64, +0xa0, 0x42, 0x08, 0x40, +0x0a, 0x24, 0x97, 0x52, +0x49, 0x2d, 0x40, 0x00, +0x00, 0x40, 0x49, 0x5c, +0x82, 0x02, 0xc6, 0xb1, +0x88, 0x62, 0x06, 0x80, +0x03, 0xfc, 0x00, 0x9a, +0x00, 0x01, 0x94, 0x29, +0xe5, 0x44, 0xbb, 0x14, +0x02, 0xf5, 0xd4, 0xe3, +0xac, 0x66, 0x25, 0x48, +0xfb, 0x2c, 0xcd, 0x19, +0x49, 0x56, 0x68, 0x20, +0x01, 0xfd, 0x24, 0x94, +0x83, 0xe2, 0x89, 0x75, +0x29, 0x1e, 0xd9, 0x4a, +0xd5, 0x68, 0x20, 0x02, +0x35, 0x20, 0x80, 0xa0, +0x92, 0x59, 0x28, 0xbc, +0x05, 0x98, 0x86, 0x61, +0x66, 0x00, 0x02, 0x19, +0xa0, 0x40, 0x00, 0x03, +0xc0, 0x47, 0x68, 0x20, +0x02, 0x02, 0x20, 0x66, +0x00, 0x02, 0x19, 0xa0, +0x88, 0x62, 0x09, 0x8e, +0x88, 0x40, 0x00, 0x01, +0x40, 0x64, 0x68, 0x00, +0x01, 0x86, 0x21, 0x88, +0x2a, 0x06, 0x82, 0x00, +0x1e, 0x82, 0x46, 0x60, +0x00, 0x21, 0x82, 0x08, +0x88, 0x48, 0x68, 0x00, +0x01, 0x8c, 0x21, 0x88, +0x1a, 0x06, 0x82, 0x00, +0x1e, 0xe2, 0x46, 0x60, +0x00, 0x21, 0x82, 0x09, +0x03, 0x10, 0x88, 0x10, +0x98, 0x84, 0x14, 0x54, +0x0a, 0x11, 0x05, 0x11, +0x54, 0x08, 0x90, 0x87, +0x09, 0x88, 0x49, 0x55, +0x40, 0xa4, 0x08, 0x80, +0x95, 0x40, 0xa0, 0x08, +0x8c, 0x86, 0x82, 0x00, +0x07, 0xe2, 0xc6, 0xc0, +0x00, 0x2b, 0x00, 0xa6, +0xc0, 0x00, 0x2b, 0x20, +0x14, 0x85, 0x28, 0x08, +0x1a, 0x16, 0xc0, 0x00, +0x2b, 0x60, 0x96, 0xc0, +0x00, 0x2b, 0x40, 0x84, +0x92, 0x96, 0x08, 0x2a, +0x08, 0x49, 0x40, 0x84, +0x14, 0x26, 0x80, 0x00, +0x00, 0xe2, 0x16, 0x82, +0x00, 0x02, 0x42, 0x46, +0x82, 0x00, 0x07, 0x22, +0x58, 0x80, 0x6c, 0x66, +0x00, 0x01, 0xf0, 0xc0, +0x68, 0x20, 0x00, 0x7f, +0xac, 0x88, 0x84, 0x86, +0x80, 0x00, 0x02, 0x22, +0x18, 0x81, 0xa0, 0x68, +0x20, 0x00, 0x4b, 0x24, +0x68, 0x20, 0x00, 0x78, +0x25, 0x88, 0x06, 0xc6, +0x60, 0x00, 0x1f, 0x0c, +0x08, 0x88, 0xc8, 0x68, +0x20, 0x00, 0x83, 0x20, +0x68, 0x20, 0x00, 0x84, +0x21, 0xa4, 0x22, 0x36, +0x60, 0x00, 0x1c, 0x6c, +0x8a, 0x42, 0x02, 0x5c, +0x81, 0x00, 0x82, 0xa0, +0x5c, 0x08, 0x61, 0x8e, +0x80, 0xa0, 0x26, 0x09, +0x42, 0x0d, 0x25, 0x92, +0x8b, 0xc0, 0x39, 0x55, +0x00, 0x08, 0x81, 0xa1, +0x88, 0x80, 0x03, 0x91, +0x81, 0x80, 0x2c, 0x0a, +0x0a, 0x61, 0x84, 0x00, +0x95, 0x40, 0xa0, 0x14, +0xa0, 0xd2, 0x59, 0x28, +0xbc, 0x03, 0x98, 0x40, +0xc0, 0x00, 0x00, 0x08, +0x88, 0x81, 0x80, 0xac, +0x10, 0x00, 0x00, 0x84, +0x80, 0x85, 0x40, 0x84, +0x08, 0x23, 0x6b, 0xa1, +0x48, 0x84, 0x8c, 0x0a, +0x80, 0x90, 0xab, 0xfb, +0x08, 0x81, 0x60, 0xa0, +0x04, 0x6a, 0x08, 0x00, +0xa2, 0x80, 0x1a, 0x34, +0x25, 0x86, 0x80, 0x88, +0x81, 0xe5, 0xa2, 0x84, +0x58, 0x82, 0x65, 0xa0, +0x82, 0x28, 0x85, 0x25, +0xa1, 0x02, 0x3a, 0x18, +0x27, 0xa2, 0x06, 0x48, +0x70, 0x09, 0x57, 0x09, +0x40, 0x80, 0x67, 0x88, +0x2e, 0x78, 0x83, 0x64, +0x88, 0x3e, 0x08, 0x84, +0x76, 0x66, 0x00, 0x02, +0x25, 0xa8, 0x40, 0x00, +0x01, 0x80, 0x09, 0x5c, +0x08, 0x28, 0x82, 0x20, +0x88, 0x1a, 0x1a, 0x02, +0x00, 0x94, 0x02, 0xf5, +0x2c, 0xbc, 0x04, 0x94, +0x8a, 0x05, 0xe1, 0x42, +0x02, 0xc8, 0x83, 0x24, +0x5c, 0x00, 0x30, 0x83, +0xa0, 0x88, 0x12, 0x50, +0x00, 0x00, 0x86, 0x98, +0xa8, 0x48, 0x08, 0x54, +0x09, 0x82, 0x01, 0x40, +0x98, 0x00, 0x9a, 0x22, +0xe4, 0x84, 0x8c, 0x98, +0x81, 0x64, 0x88, 0x1e, +0x06, 0x60, 0x00, 0x22, +0xbe, 0x08, 0x82, 0xa1, +0x88, 0x52, 0x58, 0x81, +0x24, 0x88, 0x1a, 0x08, +0x84, 0x36, 0xa2, 0x82, +0x5a, 0x80, 0x50, 0xa0, +0x04, 0x0a, 0x20, 0x64, +0x40, 0x00, 0x02, 0x08, +0x21, 0x64, 0x00, 0x02, +0x2c, 0xcf, 0x55, 0x01, +0x2a, 0x08, 0x22, 0x86, +0x00, 0x84, 0x42, 0x00, +0x06, 0x08, 0x95, 0x00, +0xe0, 0x3a, 0x14, 0x80, +0x89, 0x80, 0x40, 0x00, +0x01, 0x80, 0x08, 0x6e, +0x40, 0x00, 0x08, 0x3c, +0x38, 0x15, 0x62, 0x59, +0xa0, 0xbc, 0x2d, 0x05, +0x15, 0x96, 0x16, 0x1b, +0x65, 0x19, 0x5b, 0x08, +0x02, 0x04, 0x41, 0x00, +0x18, 0xe8, 0x85, 0xc8, +0x08, 0x18, 0x00, 0xa9, +0x40, 0x17, 0x30, 0x1f, +0x0b, 0xc0, 0x32, 0x2a, +0x06, 0x43, 0x21, 0x60, +0xbf, 0xfa, 0x23, 0x20, +0xe0, 0xbc, 0x1d, 0x05, +0x18, 0x32, 0xb0, 0x10, +0x05, 0x04, 0x19, 0x18, +0x26, 0x85, 0x50, 0x0b, +0x1e, 0x00, 0x44, 0x60, +0x88, 0x96, 0x03, 0x55, +0x04, 0x14, 0x98, 0x38, +0x95, 0x50, 0x07, 0x98, +0x34, 0x84, 0x44, 0x10, +0x9e, 0x80, 0x54, 0x46, +0xd4, 0x96, 0x83, 0x62, +0x10, 0x10, 0x08, 0x48, +0x23, 0x78, 0x00, 0x22, +0x88, 0x06, 0xc4, 0x00, +0x13, 0x60, 0x95, 0x18, +0x7b, 0x18, 0x30, 0x83, +0x61, 0x47, 0x28, 0x1a, +0x42, 0xf1, 0x65, 0x2e, +0x9e, 0xd2, 0x33, 0x2d, +0xba, 0x14, 0x84, 0x60, +0x80, 0x98, 0x24, 0x80, +0x00, 0x00, 0x68, 0x00, +0x00, 0xcd, 0x20, 0x6c, +0x40, 0x05, 0x6e, 0x0a, +0x68, 0x00, 0x07, 0xee, +0xa1, 0x98, 0xe8, 0x86, +0xc0, 0x00, 0x13, 0xe7, +0xa6, 0xc0, 0x00, 0x19, +0x86, 0x16, 0xc4, 0x00, +0x57, 0x24, 0xa4, 0x60, +0xa4, 0x14, 0x0f, 0x49, +0x40, 0x74, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x40, 0x05, 0x24, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x15, 0x13, +0x81, 0x80, 0x25, 0x82, +0x0b, 0xc1, 0x20, 0x6e, +0x00, 0x00, 0x92, 0x28, +0x38, 0x10, 0xa2, 0x58, +0x80, 0xbc, 0x08, 0x16, +0xe0, 0x00, 0x0b, 0xa2, +0x83, 0x81, 0x0a, 0x25, +0x88, 0x0b, 0xc0, 0x31, +0x6c, 0x00, 0x01, 0x98, +0x20, 0xba, 0x00, 0x02, +0x49, 0xa4, 0x6c, 0x40, +0x05, 0x24, 0x48, 0x64, +0x00, 0x01, 0xf8, 0xc7, +0x40, 0x00, 0x03, 0xa1, +0x40, 0xab, 0xff, 0x06, +0xe4, 0x00, 0x57, 0x03, +0x88, 0x80, 0x76, 0x68, +0x00, 0x00, 0x38, 0x20, +0x68, 0x00, 0x00, 0x4c, +0x21, 0x66, 0x00, 0x01, +0x48, 0x48, 0x22, 0x84, +0x48, 0x80, 0x36, 0x68, +0x00, 0x07, 0xf3, 0x20, +0xba, 0x14, 0x86, 0xc0, +0x00, 0x19, 0x86, 0x0a, +0x80, 0x10, 0x6c, 0x00, +0x01, 0x3e, 0x08, 0x32, +0x02, 0x0b, 0xcb, 0xf9, +0xab, 0xff, 0x06, 0x80, +0x00, 0x0a, 0x22, 0x06, +0x82, 0x00, 0x2b, 0xa2, +0x18, 0x45, 0x08, 0xa0, +0x82, 0x28, 0x50, 0x48, +0xa1, 0x44, 0x28, 0x40, +0x0a, 0x85, 0x00, 0x05, +0x84, 0x18, 0x04, 0x84, +0xab, 0xc0, 0x5c, 0x88, +0x07, 0x64, 0x20, 0x47, +0x98, 0xe8, 0xa6, 0xe0, +0x00, 0x19, 0xa7, 0x60, +0x00, 0x00, 0x6e, 0x00, +0x01, 0x9a, 0x3e, 0x2a, +0x07, 0x26, 0xe0, 0x00, +0x19, 0xa7, 0x23, 0x08, +0x20, 0x40, 0x00, 0x03, +0xc0, 0x44, 0x42, 0x03, +0xf9, 0x8e, 0x88, 0x6e, +0x00, 0x01, 0x9b, 0x74, +0x6e, 0x00, 0x01, 0x9b, +0x3c, 0x2a, 0x06, 0x06, +0xe0, 0x00, 0x19, 0xb7, +0x03, 0x81, 0x14, 0x6c, +0x40, 0x03, 0xba, 0x0a, +0x25, 0x93, 0x0b, 0xc0, +0x31, 0x98, 0xe8, 0x06, +0xe0, 0x00, 0x19, 0xa7, +0x03, 0x81, 0x18, 0x25, +0x83, 0x0b, 0xc0, 0x31, +0x98, 0xe8, 0x06, 0xe0, +0x00, 0x19, 0xb7, 0x00, +0x00, 0x00, 0x6e, 0x00, +0x01, 0x9a, 0x38, 0x6e, +0x40, 0x05, 0x71, 0x3a, +0x30, 0x08, 0x0b, 0xc0, +0xa2, 0x6c, 0x40, 0x05, +0x24, 0x00, 0x5c, 0x0a, +0x3b, 0x01, 0x85, 0x24, +0x1c, 0x02, 0x41, 0x40, +0x6c, 0x40, 0x05, 0x24, +0x50, 0x40, 0x00, 0x03, +0x80, 0x00, 0x6e, 0x00, +0x01, 0x9b, 0x38, 0x30, +0x08, 0x0b, 0xc0, 0xaa, +0x38, 0x18, 0x06, 0xc4, +0x00, 0x52, 0x40, 0x23, +0x81, 0x4d, 0x24, 0x15, +0x22, 0x40, 0x12, 0x6c, +0x40, 0x05, 0x24, 0x52, +0x40, 0x00, 0x03, 0x80, +0x00, 0x6c, 0x40, 0x05, +0x24, 0x02, 0x25, 0x81, +0x0b, 0xc6, 0x41, 0x6e, +0x00, 0x01, 0x2c, 0x28, +0x25, 0x90, 0x0b, 0xc0, +0x51, 0x24, 0x90, 0x06, +0xe0, 0x00, 0x12, 0xc6, +0x0b, 0xc0, 0x2f, 0x38, +0x14, 0x43, 0x81, 0x44, +0x25, 0x91, 0x0b, 0xc1, +0xd1, 0x68, 0x00, 0x03, +0x00, 0x08, 0x28, 0x93, +0x02, 0x3a, 0x85, 0x32, +0x82, 0x8b, 0xc0, 0xc0, +0x32, 0x8a, 0x8b, 0xc1, +0x51, 0x29, 0x13, 0x66, +0xc4, 0x00, 0x3b, 0xa4, +0xa6, 0x80, 0x00, 0x04, +0x92, 0x06, 0x60, 0x00, +0x04, 0x70, 0x89, 0x8e, +0x88, 0x40, 0x00, 0x03, +0xc0, 0xb7, 0x68, 0x3f, +0xfc, 0xff, 0xc8, 0x54, +0x49, 0xa3, 0x01, 0x5e, +0x24, 0x1a, 0x46, 0xc4, +0x00, 0x56, 0xa0, 0xa6, +0xc4, 0x00, 0x3b, 0xa4, +0x86, 0xc4, 0x00, 0x07, +0xa4, 0xa3, 0x81, 0x48, +0x6c, 0x40, 0x05, 0x24, +0x08, 0x25, 0x82, 0x0b, +0xc2, 0x89, 0x98, 0xe8, +0xa6, 0xc4, 0x00, 0x3b, +0xa0, 0xa6, 0x80, 0x00, +0xc0, 0x00, 0x02, 0x88, +0x34, 0x23, 0xb2, 0x43, +0x28, 0x20, 0xbc, 0x11, +0x03, 0x28, 0xa0, 0xbc, +0x0b, 0x12, 0x90, 0x36, +0x6c, 0x40, 0x03, 0xba, +0x4a, 0x68, 0x00, 0x00, +0x5d, 0x20, 0x66, 0x00, +0x00, 0x47, 0x08, 0xb0, +0x00, 0xcb, 0xc1, 0x4f, +0x5c, 0x0a, 0x41, 0x8e, +0x8a, 0x40, 0x00, 0x03, +0xc1, 0x0f, 0x5c, 0x0a, +0x41, 0x8e, 0x8a, 0x68, +0x3f, 0xf3, 0xff, 0xc8, +0x54, 0x49, 0xa3, 0x01, +0x6e, 0x6c, 0x40, 0x05, +0x6a, 0x00, 0x52, 0x0d, +0x21, 0x8e, 0x8a, 0x6c, +0x40, 0x00, 0xc8, 0x50, +0x6c, 0x40, 0x03, 0xba, +0x48, 0x5c, 0x0a, 0x43, +0x80, 0x00, 0x5c, 0x0a, +0x2b, 0x01, 0x82, 0x6c, +0x40, 0x05, 0x24, 0x08, +0x24, 0x96, 0x42, 0x48, +0x24, 0x52, 0x45, 0x23, +0x80, 0x00, 0x6e, 0x00, +0x01, 0x9a, 0x76, 0x6e, +0x00, 0x01, 0x9b, 0x76, +0x6c, 0x40, 0x05, 0x24, +0x48, 0x68, 0x00, 0x07, +0xee, 0xa0, 0x88, 0x03, +0x66, 0xc0, 0x00, 0x19, +0x86, 0x0b, 0xa1, 0x48, +0xa8, 0x01, 0x00, 0x00, +0x00, 0x6c, 0x00, 0x03, +0xd4, 0x08, 0x6c, 0x00, +0x03, 0xd6, 0x48, 0x5c, +0x00, 0x73, 0xa1, 0x48, +0x6e, 0x00, 0x03, 0xd8, +0x66, 0x40, 0x00, 0x03, +0x80, 0x00, 0x68, 0x00, +0x01, 0xe8, 0x21, 0x58, +0x0b, 0x02, 0xc0, 0x22, +0x68, 0x00, 0x00, 0x45, +0x20, 0x5c, 0x83, 0xc0, +0x09, 0x02, 0x68, 0x00, +0x00, 0x49, 0xa2, 0x80, +0x14, 0x8b, 0x00, 0x09, +0x42, 0x04, 0x60, 0x48, +0x03, 0x5c, 0x8b, 0x88, +0x00, 0x49, 0x54, 0x07, +0x29, 0x52, 0xc1, 0x54, +0x05, 0x20, 0x50, 0xc9, +0xbc, 0x07, 0xf8, 0x50, +0x48, 0x98, 0xe8, 0x95, +0x70, 0x72, 0x95, 0x2c, +0x55, 0x70, 0x52, 0x05, +0x0c, 0x98, 0x50, 0x48, +0x68, 0x00, 0x00, 0x59, +0x21, 0x68, 0x00, 0x00, +0x5d, 0xa2, 0x58, 0x0f, +0x80, 0x09, 0x4a, 0x42, +0x04, 0x61, 0x8e, 0x88, +0x80, 0x84, 0xb5, 0x40, +0x7b, 0x95, 0x2c, 0x15, +0x40, 0x5b, 0x05, 0x0c, +0xbb, 0xc0, 0x8f, 0x40, +0x00, 0x00, 0x50, 0x4a, +0x57, 0x07, 0xb9, 0x52, +0xc4, 0x57, 0x05, 0xb0, +0x50, 0xcb, 0x40, 0x00, +0x00, 0x50, 0x4a, 0x59, +0x00, 0x02, 0xc0, 0x58, +0x6c, 0x00, 0x03, 0xd6, +0x0a, 0x94, 0xa4, 0x19, +0x42, 0x41, 0x84, 0x84, +0xa8, 0x40, 0x4a, 0x00, +0x00, 0x04, 0x20, 0x54, +0x94, 0xca, 0xf5, 0xc0, +0x80, 0x14, 0x4a, 0xe2, +0x48, 0x3a, 0x6e, 0x00, +0x00, 0xba, 0xe2, 0x52, +0x41, 0x83, 0xa1, 0x48, +0x6e, 0x00, 0x00, 0x92, +0xe0, 0x00, 0x00, 0x02, +0x40, 0x3a, 0x6e, 0x00, +0x00, 0xba, 0xe2, 0x52, +0x01, 0x83, 0xa1, 0x48, +0x6e, 0x00, 0x00, 0x92, +0xe0, 0x40, 0x00, 0x03, +0x80, 0x00, 0x5c, 0x08, +0x22, 0x02, 0x6a, 0x95, +0x02, 0xe5, 0x2c, 0x98, +0x2b, 0xff, 0x04, 0x21, +0x04, 0x88, 0x07, 0x68, +0x80, 0xe1, 0x5c, 0x08, +0x62, 0x02, 0x61, 0x94, +0x82, 0xe2, 0x59, 0x30, +0xbc, 0x1a, 0x1a, 0x02, +0x79, 0x94, 0x82, 0xc3, +0x20, 0x20, 0xbc, 0x16, +0x06, 0xe0, 0x00, 0x3d, +0x82, 0x43, 0x20, 0x60, +0xbc, 0x0d, 0x03, 0x20, +0xa0, 0xbc, 0x05, 0x06, +0x60, 0x00, 0x21, 0x18, +0x08, 0x80, 0xa0, 0xbc, +0x0c, 0xf8, 0x40, 0x48, +0x66, 0x00, 0x02, 0x15, +0x00, 0x88, 0x0a, 0x0b, +0xc0, 0x7f, 0x40, 0x00, +0x00, 0x40, 0x48, 0x66, +0x00, 0x02, 0x13, 0x60, +0x88, 0x0a, 0x00, 0x00, +0x00, 0x84, 0x04, 0x80, +0x00, 0x00, 0x88, 0x03, +0x6b, 0xa1, 0x48, 0xa8, +0x01, 0x00, 0x00, 0x00, +0x5c, 0x08, 0x22, 0x01, +0xe0, 0xa0, 0x02, 0x18, +0x40, 0x0a, 0x84, 0x84, +0xaa, 0x08, 0x78, 0x98, +0xe8, 0xa9, 0x40, 0x66, +0xa0, 0x41, 0x09, 0x40, +0x2e, 0x24, 0x93, 0x06, +0xc0, 0x00, 0x08, 0xa0, +0x85, 0x90, 0x10, 0x14, +0x06, 0x0b, 0xc0, 0xb9, +0xa0, 0x46, 0x86, 0xc0, +0x00, 0x0b, 0x20, 0x83, +0x20, 0x20, 0xbc, 0x06, +0x16, 0xe0, 0x00, 0x12, +0xc2, 0xc3, 0x81, 0x16, +0x24, 0x9a, 0x06, 0xe0, +0x00, 0x12, 0xc6, 0x0b, +0xa1, 0x48, 0x84, 0x00, +0x80, 0x00, 0x00, 0xa0, +0x20, 0x1a, 0x08, 0x22, +0xa1, 0x05, 0x39, 0x58, +0x2c, 0x59, 0x01, 0x02, +0x1c, 0x93, 0x84, 0x80, +0x84, 0x20, 0x34, 0x05, +0x00, 0xa8, 0x58, 0x09, +0x57, 0x0d, 0x01, 0x82, +0x48, 0x42, 0x02, 0x79, +0x80, 0x09, 0x84, 0x84, +0x92, 0x81, 0xa0, 0x98, +0x00, 0x88, 0x48, 0x48, +0x30, 0x12, 0x8b, 0xc0, +0x45, 0xba, 0x14, 0x88, +0x48, 0x08, 0x40, 0x00, +0x03, 0x80, 0x00, 0x64, +0x00, 0x02, 0x11, 0x87, +0xa0, 0x27, 0x1a, 0x0d, +0x72, 0xa1, 0x10, 0x39, +0x48, 0x28, 0x59, 0x00, +0x02, 0x1c, 0xe4, 0x85, +0x00, 0x08, 0x58, 0x02, +0x42, 0x03, 0x40, 0x60, +0x01, 0x55, 0x00, 0x9a, +0x21, 0x59, 0x55, 0x00, +0x11, 0x84, 0x80, 0x55, +0x00, 0x59, 0x84, 0x01, +0x94, 0x82, 0xc3, 0x20, +0x60, 0xbc, 0x0d, 0x9a, +0x02, 0x78, 0x30, 0x08, +0x0b, 0xc0, 0xbb, 0x39, +0x27, 0x86, 0xc0, 0x00, +0x3d, 0x60, 0x05, 0xc8, +0x2c, 0xb0, 0x01, 0x25, +0x14, 0x22, 0x20, 0x00, +0x29, 0x52, 0xc2, 0x85, +0x04, 0x8b, 0xc0, 0x17, +0x39, 0x27, 0x89, 0x4a, +0x08, 0x32, 0x08, 0x0b, +0xc0, 0xa1, 0x30, 0x0c, +0x8b, 0xc0, 0x8c, 0x39, +0x05, 0x86, 0xc0, 0x00, +0x3d, 0x60, 0x05, 0x14, +0x42, 0x30, 0x01, 0x89, +0x42, 0x40, 0x40, 0x00, +0x00, 0x40, 0x48, 0x64, +0x00, 0x02, 0x13, 0x6f, +0x40, 0x00, 0x02, 0x08, +0x00, 0xa2, 0x08, 0x4a, +0x20, 0x22, 0x84, 0x38, +0x98, 0x60, 0x0a, 0x57, +0x8b, 0xaa, 0xbf, 0xe0, +0xa1, 0x4a, 0x4a, 0x08, +0x00, 0x85, 0x00, 0x88, +0x80, 0x64, 0x88, 0x0e, +0x08, 0x81, 0x76, 0x66, +0x00, 0x00, 0x3d, 0xe8, +0x2e, 0x96, 0x58, 0x80, +0x20, 0x88, 0x0a, 0x48, +0x41, 0x89, 0x44, 0x08, +0x00, 0x81, 0x36, 0x46, +0x0a, 0x41, 0x80, 0x08, +0x86, 0x14, 0x8a, 0x80, +0x20, 0x5c, 0x80, 0x81, +0x8e, 0x88, 0x5c, 0x01, +0xb3, 0xa1, 0x11, 0x38, +0x10, 0x52, 0xa0, 0x67, +0x1a, 0x2a, 0x65, 0xd0, +0xe2, 0x18, 0x32, 0x95, +0x80, 0xb0, 0x1c, 0x08, +0x19, 0x48, 0xbf, 0x94, +0x81, 0x89, 0x83, 0xa9, +0x94, 0x8b, 0x99, 0xc0, +0x81, 0x94, 0x8f, 0x74, +0x3f, 0x95, 0x14, 0x85, +0x09, 0x48, 0xf1, 0x76, +0x00, 0x00, 0x06, 0x00, +0x86, 0x00, 0x85, 0x16, +0x12, 0x06, 0x18, 0x05, +0x50, 0x23, 0x94, 0x0f, +0x4a, 0x20, 0x21, 0x84, +0x80, 0xa6, 0x80, 0x03, +0xff, 0xfc, 0x85, 0x80, +0x9c, 0x20, 0x84, 0x15, +0x16, 0x1b, 0x14, 0x05, +0x04, 0x20, 0x16, 0x84, +0x84, 0xb9, 0x40, 0xf6, +0x86, 0x1f, 0xa3, 0x81, +0x66, 0x84, 0x88, 0x82, +0x59, 0xa0, 0xbc, 0x0f, +0x15, 0xc0, 0x86, 0x22, +0x05, 0x89, 0x40, 0x2e, +0x55, 0x03, 0xbb, 0x01, +0x0e, 0x3a, 0x1c, 0x73, +0x01, 0x38, 0xbc, 0x02, +0xd9, 0x40, 0x67, 0x96, +0x5e, 0x60, 0x00, 0x00, +0x42, 0x07, 0xf9, 0x42, +0x0c, 0x40, 0x00, 0x01, +0x40, 0x64, 0x5c, 0x08, +0x62, 0x20, 0x50, 0x94, +0x02, 0xe5, 0x50, 0x3b, +0xb0, 0x10, 0xe3, 0xa1, +0xc7, 0x30, 0x13, 0x8b, +0xc0, 0x2d, 0x94, 0x06, +0x79, 0x65, 0x66, 0xa0, +0x40, 0x89, 0x65, 0x2c, +0x94, 0x06, 0x4b, 0xa1, +0x48, 0xba, 0x10, 0x10, +0x00, 0x00, 0x60, 0x00, +0x30, 0x00, 0x13, 0x39, +0x02, 0x00, 0x00, 0x00, +0x82, 0x07, 0xa3, 0x81, +0x84, 0x6c, 0x40, 0x04, +0x02, 0x0a, 0x25, 0x93, +0x0b, 0xc1, 0x00, 0x38, +0x1c, 0x42, 0x59, 0x30, +0xbc, 0x19, 0x16, 0x82, +0x00, 0x26, 0x6a, 0x46, +0x80, 0x01, 0xdd, 0xdc, +0x83, 0x90, 0x10, 0x96, +0x05, 0x49, 0x60, 0x74, +0x68, 0x00, 0x1d, 0xc0, +0x08, 0xba, 0x14, 0x89, +0x60, 0xf4, 0x40, 0x00, +0x03, 0x80, 0x00, 0x68, +0x20, 0x02, 0x33, 0xa4, +0x68, 0x00, 0x1d, 0xdd, +0xc8, 0x39, 0x01, 0x09, +0x60, 0x54, 0x96, 0x07, +0x46, 0x80, 0x01, 0xdc, +0x00, 0x8b, 0xa1, 0x48, +0x96, 0x0f, 0x40, 0x00, +0x00, 0x40, 0x00, 0x03, +0xa1, 0x40, 0xab, 0xff, +0x08, 0x80, 0x76, 0x66, +0x00, 0x02, 0x23, 0xa0, +0x40, 0x00, 0x03, 0x00, +0x0c, 0x6e, 0x00, 0x00, +0x92, 0x64, 0x6e, 0x00, +0x00, 0xba, 0x64, 0x66, +0x00, 0x01, 0xd1, 0x60, +0x5c, 0x00, 0x73, 0x03, +0x0c, 0x88, 0x03, 0x66, +0xe0, 0x00, 0x12, 0xc6, +0x4b, 0xa1, 0x48, 0x6c, +0x40, 0x05, 0x1a, 0x4a, +0x40, 0x00, 0x02, 0x80, +0x10, 0x5c, 0x81, 0x01, +0x8e, 0x8a, 0x68, 0x00, +0x00, 0x0e, 0x20, 0x38, +0x0a, 0x42, 0xa0, 0x76, +0x3a, 0x18, 0x63, 0x01, +0x30, 0xbf, 0xfc, 0xa8, +0x00, 0x7a, 0x40, 0x00, +0x03, 0xa1, 0x40, 0x5c, +0x81, 0x01, 0x8e, 0x8a, +0x68, 0x00, 0x00, 0x22, +0x20, 0x38, 0x0a, 0x42, +0xa0, 0x76, 0x3a, 0x18, +0x63, 0x01, 0x30, 0xbf, +0xfc, 0xa8, 0x00, 0x7a, +0x40, 0x00, 0x03, 0xa1, +0x40, 0x68, 0x00, 0x00, +0x36, 0x20, 0x5c, 0x81, +0x02, 0xbf, 0xf0, 0x68, +0x00, 0x00, 0x4a, 0x21, +0x88, 0x07, 0x69, 0x8e, +0x88, 0x40, 0x00, 0x02, +0x00, 0x02, 0x55, 0x03, +0x20, 0x08, 0x7a, 0x3a, +0x10, 0x43, 0x22, 0x20, +0xbf, 0xfb, 0xa8, 0x10, +0x7a, 0x40, 0x00, 0x02, +0x01, 0x80, 0x66, 0x00, +0x00, 0x3b, 0xe8, 0x5c, +0x00, 0x62, 0x04, 0x21, +0x68, 0x00, 0x00, 0x4a, +0x20, 0x88, 0x03, 0x6a, +0x80, 0x10, 0x40, 0x00, +0x02, 0x01, 0x80, 0x64, +0x00, 0x00, 0x3b, 0xef, +0x5c, 0x00, 0x62, 0x04, +0x21, 0x55, 0x01, 0x40, +0x60, 0x0b, 0x5c, 0x82, +0x0a, 0x20, 0x26, 0x5c, +0x81, 0x00, 0xc0, 0x2a, +0x44, 0x18, 0x82, 0x30, +0x27, 0x87, 0x00, 0x84, +0x44, 0x4a, 0x07, 0x80, +0x84, 0x42, 0x4a, 0x23, +0x82, 0x49, 0x80, 0x42, +0x8c, 0x0c, 0x0a, 0x20, +0x26, 0x86, 0x00, 0xb8, +0xc0, 0x2a, 0x44, 0x18, +0x82, 0x30, 0x27, 0x55, +0x00, 0xa0, 0x70, 0x0b, +0x44, 0x5d, 0x20, 0x78, +0x0a, 0x44, 0x15, 0x40, +0x48, 0x0b, 0x55, 0x01, +0x09, 0x80, 0x8a, 0x57, +0x8f, 0xb0, 0x50, 0x08, +0x57, 0x49, 0x92, 0x38, +0x24, 0x8c, 0x0c, 0x4a, +0x20, 0x22, 0x86, 0x00, +0xa8, 0xc0, 0x2b, 0x44, +0x10, 0x82, 0x10, 0x21, +0x85, 0x00, 0x84, 0x46, +0x4a, 0x04, 0x80, 0x84, +0x42, 0x4a, 0x20, 0x82, +0x49, 0x80, 0x43, 0x8c, +0x0c, 0x1a, 0x20, 0x22, +0x86, 0x00, 0xb8, 0xc0, +0x2a, 0x44, 0x18, 0x00, +0x50, 0x0b, 0x55, 0x00, +0xa2, 0x10, 0x21, 0x44, +0x5c, 0x01, 0x84, 0xca, +0x84, 0x80, 0xb4, 0x45, +0xc8, 0x20, 0x88, 0x25, +0x50, 0x18, 0x18, 0x04, +0x2a, 0x10, 0x21, 0x8c, +0x06, 0x0a, 0x28, 0x08, +0x80, 0x80, 0xa4, 0x41, +0x08, 0x05, 0x00, 0xa4, +0x43, 0x00, 0x16, 0x82, +0x55, 0x00, 0xa0, 0x20, +0x00, 0xd5, 0x50, 0x0a, +0x04, 0x80, 0x94, 0x40, +0x90, 0x14, 0x02, 0x55, +0x00, 0xa4, 0x96, 0x82, +0x45, 0x00, 0x89, 0x20, +0x82, 0x28, 0x10, 0x09, +0x98, 0x00, 0x84, 0x40, +0x80, 0x01, 0x00, 0x89, +0xa1, 0x02, 0x44, 0x24, +0x00, 0x10, 0x09, 0x44, +0x4c, 0x00, 0x80, 0x20, +0x85, 0x80, 0x99, 0x80, +0x08, 0x57, 0x8b, 0x28, +0x40, 0x08, 0x57, 0x49, +0x68, 0x50, 0x08, 0x44, +0x20, 0x01, 0x68, 0xa5, +0x50, 0x0a, 0x00, 0x50, +0x89, 0x46, 0x0a, 0x41, +0x80, 0x08, 0x08, 0x10, +0x09, 0x80, 0x08, 0x5c, +0x81, 0x00, 0xc0, 0x2a, +0x82, 0x00, 0xb4, 0x41, +0x80, 0x02, 0x00, 0x84, +0x44, 0x40, 0x06, 0x00, +0x84, 0x42, 0x50, 0x18, +0x24, 0x04, 0x60, 0xa4, +0x18, 0x08, 0x28, 0xc0, +0x60, 0x55, 0x00, 0xa3, +0x80, 0x00, 0x5c, 0x82, +0x09, 0x8e, 0x82, 0x5c, +0x81, 0x00, 0xc0, 0x8a, +0x55, 0x00, 0x98, 0x20, +0x0b, 0x44, 0x1d, 0xe0, +0x20, 0x08, 0x55, 0x00, +0x80, 0x20, 0x0b, 0x44, +0x44, 0x00, 0xc0, 0x8a, +0x44, 0x1d, 0xe0, 0x20, +0x08, 0x44, 0x44, 0x00, +0x20, 0x08, 0x44, 0x25, +0xe1, 0x68, 0x24, 0x54, +0x00, 0xda, 0x04, 0x80, +0x50, 0x08, 0xd8, 0xc0, +0x30, 0x55, 0x01, 0x48, +0xc1, 0x78, 0x5c, 0x00, +0x01, 0x80, 0xc3, 0x8c, +0x06, 0x5a, 0x00, 0x80, +0x8c, 0x08, 0xe8, 0x20, +0x08, 0x44, 0x25, 0x40, +0x20, 0x09, 0x44, 0x4c, +0x00, 0xc0, 0x8e, 0x82, +0x00, 0x84, 0x42, 0x54, +0x02, 0x00, 0x94, 0x44, +0xc0, 0x18, 0x4c, 0x98, +0x60, 0x08, 0x44, 0x25, +0x41, 0x68, 0xa5, 0x54, +0x00, 0x92, 0x04, 0x85, +0x50, 0x0a, 0x90, 0xe8, +0x30, 0x55, 0x00, 0xc0, +0xe9, 0x78, 0x98, 0x08, +0x28, 0x50, 0x08, 0x46, +0x0a, 0x40, 0x48, 0x09, +0x57, 0x8a, 0xa8, 0xe8, +0x60, 0x57, 0x49, 0x63, +0x80, 0x00, 0x85, 0x08, +0x85, 0x90, 0x10, 0x2b, +0xfc, 0x04, 0x24, 0x4c, +0x08, 0x07, 0x65, 0xc8, +0x10, 0x08, 0x0e, 0x2a, +0x10, 0x43, 0xa1, 0x90, +0x68, 0xc0, 0x2a, 0x82, +0x00, 0x94, 0x40, 0x90, +0x07, 0x02, 0x78, 0x20, +0x08, 0x44, 0x45, 0x40, +0x78, 0x08, 0x55, 0x01, +0x00, 0x20, 0x0a, 0x44, +0x15, 0x40, 0x20, 0x09, +0x98, 0x08, 0x25, 0x50, +0x0b, 0x8c, 0x06, 0x05, +0x50, 0x08, 0x23, 0x14, +0x78, 0xc1, 0x2a, 0x44, +0x09, 0x80, 0x60, 0x08, +0x44, 0x45, 0x60, 0x60, +0x89, 0x44, 0x6d, 0x40, +0x28, 0x09, 0x98, 0x08, +0x28, 0xc1, 0x60, 0xa1, +0x18, 0x08, 0xc8, 0x2a, +0x44, 0x09, 0x80, 0x75, +0x22, 0x82, 0x80, 0x84, +0x44, 0x5e, 0x05, 0x00, +0xa5, 0x50, 0x18, 0x02, +0x80, 0x84, 0x44, 0x5e, +0x02, 0x80, 0x99, 0x80, +0xc3, 0x55, 0x00, 0xc0, +0xc8, 0x61, 0x88, 0x1d, +0x2a, 0x3e, 0x82, 0x8c, +0x92, 0xa4, 0x40, 0x90, +0x06, 0x80, 0x84, 0x44, +0x54, 0x06, 0x88, 0xa5, +0x50, 0x0e, 0x08, 0x16, +0x04, 0x41, 0x54, 0x08, +0x2e, 0x39, 0x80, 0x82, +0x8c, 0x96, 0x08, 0x83, +0x52, 0x88, 0x26, 0x26, +0x80, 0x00, 0x0c, 0x92, +0x06, 0x60, 0x00, 0x04, +0x82, 0x03, 0x20, 0x20, +0xbc, 0x05, 0x88, 0x82, +0x21, 0x88, 0x03, 0x6b, +0xa1, 0x48, 0xa8, 0x04, +0x00, 0x00, 0x00, 0x88, +0x0a, 0x58, 0x48, 0x08, +0x55, 0x03, 0x20, 0x48, +0x82, 0x58, 0x05, 0x00, +0x48, 0x48, 0xbc, 0x39, +0xc8, 0x81, 0x88, 0x86, +0x90, 0x25, 0x80, 0x88, +0x08, 0x2a, 0x0b, 0xc0, +0x13, 0x86, 0x94, 0x8a, +0x00, 0x21, 0x84, 0x80, +0x23, 0x01, 0x10, 0xbc, +0x01, 0x58, 0x40, 0xc8, +0x5c, 0x08, 0x1a, 0xc0, +0x21, 0x5c, 0x82, 0x00, +0x08, 0x8a, 0x5b, 0x48, +0x10, 0xc9, 0x30, 0x50, +0x47, 0x08, 0x69, 0x08, +0x57, 0x0d, 0x20, 0x83, +0x0a, 0x54, 0x02, 0x00, +0x08, 0x48, 0x50, 0x46, +0x92, 0x08, 0x00, 0x8c, +0x85, 0x8a, 0x08, 0x82, +0xa1, 0x00, 0x48, 0x10, +0x88, 0x58, 0x0d, 0x00, +0xc1, 0x30, 0x54, 0x04, +0x13, 0xc0, 0x2b, 0x8c, +0x17, 0xa8, 0x6e, 0x4a, +0x00, 0x00, 0x08, 0x60, +0x88, 0x58, 0x0d, 0x00, +0x81, 0x25, 0xbc, 0x01, +0x58, 0x68, 0xca, 0x36, +0x98, 0x25, 0x04, 0x69, +0x04, 0xa0, 0x15, 0x04, +0x78, 0x01, 0x08, 0x85, +0x70, 0x86, 0x21, 0x00, +0x18, 0xd1, 0x31, 0x54, +0x00, 0x58, 0x10, 0x48, +0x8c, 0x97, 0xb0, 0x00, +0x00, 0x8d, 0x13, 0x05, +0x40, 0x41, 0x3c, 0x05, +0xf8, 0xd1, 0x7a, 0x88, +0x03, 0x6b, 0xa1, 0x48, +0x86, 0x8f, 0xaa, 0x80, +0x40, 0x00, 0x00, 0x08, +0x80, 0x36, 0xba, 0x14, +0x8a, 0x80, 0x40, 0x40, +0x00, 0x03, 0x80, 0x00, +0x5c, 0x81, 0x03, 0x01, +0x6b, 0x68, 0x20, 0x01, +0x1b, 0x20, 0x68, 0x20, +0x00, 0xf5, 0x21, 0x5c, +0x00, 0x38, 0x02, 0x0a, +0x51, 0x89, 0x80, 0x40, +0x0a, 0x51, 0x8a, 0x00, +0x08, 0x50, 0x68, 0x20, +0x02, 0x98, 0x20, 0x5c, +0x00, 0x60, 0x48, 0x02, +0x80, 0x05, 0x28, 0x00, +0x7a, 0x68, 0x20, 0x00, +0xec, 0x21, 0x80, 0x07, +0xa8, 0x40, 0x7a, 0xa0, +0x04, 0x08, 0x48, 0x02, +0x80, 0x25, 0x26, 0x80, +0x00, 0x0c, 0xe2, 0x28, +0x48, 0x89, 0xa0, 0x06, +0x18, 0x40, 0x49, 0x80, +0xa5, 0x26, 0x80, 0x00, +0x09, 0x82, 0x06, 0xc4, +0x00, 0x1b, 0x00, 0x18, +0x50, 0x53, 0xa0, 0x86, +0x4e, 0x01, 0x04, 0xa1, +0x06, 0x28, 0x40, 0x7a, +0x95, 0x24, 0x7a, 0xbf, +0xf0, 0x68, 0x00, 0x01, +0x91, 0x20, 0x88, 0x07, +0x68, 0x60, 0x49, 0x84, +0x84, 0x96, 0xc4, 0x00, +0x10, 0x84, 0xa6, 0xc4, +0x00, 0x10, 0x64, 0xa8, +0x50, 0x7a, 0x6c, 0x40, +0x01, 0x9a, 0x51, 0x6c, +0x40, 0x01, 0x98, 0x51, +0x6c, 0x00, 0x03, 0x80, +0x48, 0x6c, 0x00, 0x03, +0x9a, 0x48, 0x6c, 0x40, +0x01, 0x8a, 0x7a, 0x6c, +0x40, 0x01, 0x5a, 0x7a, +0x6c, 0x40, 0x02, 0xf8, +0x51, 0x6c, 0x40, 0x02, +0xf2, 0x51, 0x66, 0x00, +0x00, 0x47, 0xc0, 0x68, +0x00, 0x01, 0x91, 0x21, +0x88, 0x03, 0x68, 0x49, +0x08, 0x51, 0xc5, 0x22, +0x80, 0x10, 0x84, 0x94, +0x8a, 0x08, 0x00, 0x64, +0x00, 0x00, 0x49, 0x6f, +0x40, 0x00, 0x03, 0x09, +0x64, 0x30, 0x1a, 0x8b, +0xc1, 0x30, 0x84, 0x00, +0x83, 0x69, 0x04, 0x6c, +0x40, 0x02, 0xc8, 0x0b, +0x30, 0x9e, 0x0b, 0xc0, +0xc4, 0x6c, 0x40, 0x01, +0xea, 0x08, 0x6c, 0x40, +0x02, 0x36, 0x0b, 0x30, +0x1e, 0x0b, 0xc0, 0x61, +0x6c, 0x40, 0x02, 0xc6, +0x08, 0x28, 0x13, 0x04, +0x20, 0x17, 0x98, 0x00, +0xa2, 0xf1, 0x75, 0x98, +0x28, 0x9b, 0xa1, 0x48, +0x98, 0x24, 0x80, 0x00, +0x00, 0x68, 0x00, 0x00, +0xcf, 0x22, 0x6c, 0x00, +0x01, 0x9c, 0x08, 0x85, +0x00, 0xa3, 0x01, 0x30, +0xbc, 0x4f, 0x19, 0x54, +0x24, 0x6c, 0x00, 0x01, +0x9e, 0x7a, 0x32, 0x06, +0x06, 0xc4, 0x00, 0x1e, +0x80, 0xa5, 0xb4, 0xc3, +0x04, 0x00, 0x8b, 0xc2, +0x39, 0x36, 0x90, 0x43, +0x09, 0xa0, 0xbc, 0x09, +0x48, 0x48, 0x08, 0x36, +0x90, 0x43, 0x09, 0xa0, +0xbc, 0x05, 0x4b, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0xa0, 0x7a, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x01, 0xa0, 0x08, +0x6c, 0x40, 0x01, 0xe6, +0x0a, 0x2a, 0x06, 0x43, +0x01, 0xa0, 0xbc, 0x38, +0x96, 0xc0, 0x00, 0x1a, +0x04, 0x85, 0xc0, 0xb8, +0x18, 0xe8, 0xa6, 0xc4, +0x00, 0x3b, 0xa0, 0x85, +0x24, 0x12, 0x2c, 0x02, +0x06, 0x80, 0x00, 0x0d, +0x12, 0x16, 0xc4, 0x00, +0x3b, 0xa4, 0x84, 0x60, +0xa4, 0x14, 0xa4, 0x68, +0x48, 0x7a, 0x00, 0x00, +0x03, 0x09, 0xa0, 0xbc, +0x04, 0x38, 0x48, 0x08, +0x36, 0x90, 0x43, 0x09, +0xa0, 0xbc, 0x05, 0x2b, +0xa1, 0x48, 0x6c, 0x00, +0x01, 0xa0, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x6c, 0x00, 0x01, 0xa0, +0x08, 0x6c, 0x40, 0x01, +0xe4, 0x0a, 0x2a, 0x06, +0x43, 0x01, 0xa0, 0xbc, +0x16, 0x96, 0xc0, 0x00, +0x1a, 0x04, 0x85, 0xc0, +0xb8, 0x30, 0x00, 0xe6, +0xc4, 0x00, 0x3b, 0xa0, +0x85, 0x20, 0x12, 0x2c, +0x02, 0x06, 0x80, 0x00, +0x0d, 0x12, 0x16, 0xc4, +0x00, 0x3b, 0xa4, 0x84, +0x60, 0xa4, 0x14, 0xa4, +0x68, 0x48, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x55, 0x03, 0xa3, 0xa1, +0x48, 0x6c, 0x00, 0x01, +0x9e, 0x48, 0x00, 0x00, +0x0b, 0xa1, 0x40, 0x85, +0x00, 0x88, 0x40, 0x0a, +0x30, 0x1a, 0x0b, 0xc1, +0x50, 0x30, 0x13, 0x0b, +0xc0, 0xbd, 0x84, 0x80, +0x82, 0xe1, 0x30, 0x98, +0x00, 0x88, 0x40, 0x48, +0x00, 0x00, 0x08, 0x50, +0x0a, 0x30, 0x1a, 0x0b, +0xc0, 0xb4, 0xba, 0x14, +0x88, 0x40, 0x4a, 0x00, +0x00, 0x02, 0x81, 0x30, +0x98, 0x00, 0x88, 0x40, +0x48, 0x00, 0x00, 0x08, +0x50, 0x0a, 0x30, 0x1a, +0x0b, 0xc0, 0x12, 0x84, +0x04, 0xab, 0xa1, 0x40, +0x68, 0x20, 0x01, 0x21, +0x21, 0x68, 0x00, 0x00, +0xbf, 0x22, 0x39, 0x02, +0x08, 0x08, 0x08, 0x81, +0x07, 0xa8, 0x10, 0x48, +0x68, 0x00, 0x00, 0xc4, +0x20, 0x84, 0x80, 0x88, +0x00, 0x7a, 0x81, 0x04, +0x88, 0x00, 0x7a, 0x68, +0x00, 0x00, 0xbc, 0x23, +0x80, 0x04, 0x86, 0x80, +0x00, 0x92, 0x5a, 0xca, +0x10, 0x01, 0x81, 0x86, +0xc8, 0x10, 0x7a, 0xa0, +0x00, 0x48, 0x58, 0x7a, +0x85, 0x06, 0x14, 0x60, +0xa4, 0x00, 0x07, 0xa8, +0x40, 0x64, 0x40, 0x00, +0x03, 0x80, 0x00, 0x6c, +0x00, 0x01, 0x7a, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0c, 0x16, +0xc0, 0x00, 0x18, 0x62, +0x06, 0x80, 0x00, 0x92, +0xa2, 0xc6, 0xc0, 0x00, +0x19, 0x02, 0x16, 0xc0, +0x00, 0x17, 0x86, 0xc4, +0x60, 0xa4, 0x04, 0x07, +0xa8, 0x48, 0x7a, 0x00, +0x00, 0x0b, 0xa1, 0x40, +0x6c, 0x00, 0x01, 0x7a, +0x08, 0x38, 0x10, 0x62, +0x59, 0xa0, 0xbc, 0x0c, +0x8a, 0xbf, 0xf0, 0x6c, +0x00, 0x01, 0x86, 0x20, +0x68, 0x00, 0x09, 0x25, +0xac, 0x6c, 0x00, 0x01, +0x90, 0x21, 0x6c, 0x00, +0x01, 0x78, 0x6c, 0x42, +0x09, 0xf8, 0x40, 0x7a, +0x84, 0x87, 0xa8, 0x80, +0x76, 0x66, 0x00, 0x02, +0x4e, 0x20, 0x6c, 0x00, +0x01, 0x8e, 0x08, 0x32, +0x02, 0x0b, 0xc0, 0x65, +0x6c, 0x00, 0x01, 0x90, +0x20, 0x42, 0x03, 0xf8, +0x80, 0x36, 0x40, 0x00, +0x00, 0x40, 0x7a, 0x68, +0x00, 0x09, 0x33, 0xa0, +0x88, 0x03, 0x66, 0xc0, +0x00, 0x17, 0x86, 0x0b, +0xa1, 0x48, 0xa8, 0x01, +0x00, 0x00, 0x00, 0x6c, +0x00, 0x01, 0x7a, 0x08, +0x38, 0x10, 0x62, 0x59, +0xa0, 0xbc, 0x0d, 0x06, +0xc0, 0x00, 0x18, 0x62, +0x06, 0x80, 0x00, 0x92, +0x5a, 0xc6, 0xc0, 0x00, +0x19, 0x02, 0x16, 0xc0, +0x00, 0x17, 0x86, 0xc4, +0x60, 0xa4, 0x04, 0x07, +0xa8, 0x48, 0x7a, 0x40, +0x00, 0x03, 0x80, 0x00, +0x64, 0x00, 0x02, 0x4e, +0x27, 0x68, 0x00, 0x00, +0xc0, 0x20, 0x68, 0x20, +0x01, 0x23, 0x21, 0xab, +0xfe, 0x08, 0x40, 0x08, +0x84, 0x80, 0x94, 0x40, +0x80, 0x08, 0x07, 0x66, +0x60, 0x00, 0x25, 0x22, +0x89, 0x80, 0x09, 0x5c, +0x81, 0x00, 0x80, 0xc8, +0x68, 0x20, 0x01, 0x23, +0x20, 0x68, 0x00, 0x00, +0xc5, 0x21, 0x80, 0x00, +0x88, 0x48, 0x09, 0x44, +0x20, 0x00, 0x81, 0x60, +0x66, 0x00, 0x02, 0x52, +0x28, 0x40, 0x00, 0x01, +0x80, 0x09, 0x5c, 0x81, +0x00, 0x81, 0x20, 0x6c, +0x00, 0x01, 0x80, 0x09, +0x84, 0x00, 0x06, 0xc0, +0x00, 0x17, 0xe0, 0xa5, +0x40, 0xd6, 0x88, 0x03, +0x66, 0x80, 0x00, 0x0c, +0x02, 0x05, 0x44, 0x17, +0x08, 0x08, 0x96, 0xc0, +0x00, 0x18, 0xa0, 0xb6, +0xc0, 0x00, 0x18, 0x80, +0x25, 0x40, 0x5f, 0x80, +0x04, 0xa5, 0x44, 0x1f, +0xa0, 0x00, 0x28, 0x00, +0x0a, 0x68, 0x00, 0x00, +0xc5, 0x21, 0x44, 0x30, +0x00, 0x40, 0xa0, 0x80, +0x84, 0xb8, 0x50, 0xc0, +0x84, 0x04, 0x0a, 0x08, +0x00, 0x80, 0x80, 0x94, +0x40, 0x80, 0x04, 0x8a, +0x14, 0x60, 0xa4, 0x04, +0x0c, 0x08, 0x48, 0x40, +0x40, 0x00, 0x02, 0x80, +0x20, 0x44, 0x29, 0x02, +0xc0, 0x20, 0x68, 0x20, +0x01, 0x25, 0x20, 0x51, +0x48, 0x9b, 0x3f, 0xc4, +0x80, 0x00, 0x29, 0x80, +0xc9, 0x44, 0x0d, 0xc0, +0x00, 0x02, 0x98, 0x0c, +0x84, 0x40, 0xdc, 0x00, +0x00, 0x29, 0x80, 0xc8, +0x44, 0x0d, 0xc0, 0x00, +0x02, 0x98, 0x0c, 0x84, +0x40, 0xdc, 0x00, 0x00, +0x29, 0x80, 0xc8, 0x44, +0x0d, 0x40, 0x00, 0x03, +0x98, 0x08, 0x84, 0x40, +0x90, 0x04, 0x00, 0x85, +0x14, 0x69, 0x18, 0x08, +0xa2, 0xe0, 0x9a, 0x55, +0x00, 0xd1, 0x80, 0x89, +0x1a, 0x0d, 0x99, 0xa0, +0x42, 0x08, 0x63, 0x02, +0x20, 0xdb, 0x57, 0x06, +0x99, 0x80, 0xc9, 0x98, +0x0c, 0xa0, 0x86, 0x30, +0x22, 0x0d, 0xb5, 0x70, +0x69, 0x98, 0x0c, 0x99, +0x80, 0xca, 0x08, 0x63, +0x02, 0x20, 0xdb, 0x57, +0x06, 0x91, 0x80, 0xc9, +0x98, 0x08, 0xa0, 0x86, +0x20, 0x22, 0x0d, 0x25, +0x70, 0x51, 0x3a, 0x14, +0x82, 0x20, 0x92, 0x40, +0x00, 0x01, 0x80, 0x88, +0x37, 0x08, 0x63, 0x70, +0x44, 0x2e, 0x13, 0x42, +0xa0, 0x64, 0x32, 0x02, +0x0b, 0xc1, 0x55, 0x38, +0x20, 0x63, 0x01, 0xa0, +0xbc, 0x0e, 0x06, 0x20, +0x00, 0x00, 0x01, 0x45, +0x00, 0x88, 0x18, 0xeb, +0x50, 0x00, 0x00, 0x2f, +0x80, 0x9b, 0xc0, 0x13, +0x28, 0x00, 0x92, 0x09, +0x08, 0x57, 0x09, 0xa3, +0xa1, 0x48, 0x20, 0x10, +0x95, 0x0c, 0x84, 0x19, +0x20, 0x3b, 0xa1, 0x48, +0x5b, 0xc2, 0x01, 0x8e, +0x83, 0x00, 0x00, 0x0b, +0xa1, 0x48, 0x55, 0x00, +0x59, 0x8e, 0x80, 0x40, +0x00, 0x03, 0x80, 0x00, +0x00, 0x00, 0x00, 0x06, +0x00, 0x00, 0x40, 0x00, +0x38, 0x74, 0x00, 0x00, +0xe6, 0x18, 0xc5, 0x03, +0x6f, 0x1a, 0x00, 0x00, +0x01, 0x9d, 0x13, 0x00, +0xff, 0xff, 0x0f, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x79, 0x56, 0x07, 0x02, +0x9d, 0xba, 0x85, 0x84, +0x4d, 0xcd, 0x62, 0x77, +0xeb, 0x87, 0xe8, 0x7b, +0x11, 0x04, 0xa9, 0x8a, +0x7d, 0xe4, 0x7f, 0x6b, +0x8d, 0xe8, 0x28, 0x76, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xf1, 0xcc, 0xfa, 0x47, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xd9, 0x19, 0x25, 0x00, +0x4d, 0xcd, 0x62, 0x77, +0xed, 0x8c, 0x12, 0x00, +0xff, 0xfe, 0x52, 0xc8, +0xed, 0x8c, 0x12, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x79, 0x56, 0x07, 0x02, +0x9d, 0xba, 0x85, 0x84, +0x4d, 0xcd, 0x62, 0x77, +0xeb, 0x87, 0xe8, 0x7b, +0x11, 0x04, 0xa9, 0x8a, +0x7d, 0xe4, 0x7f, 0x6b, +0x8d, 0xe8, 0x28, 0x76, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xd9, 0x19, 0x25, 0x00, +0x4d, 0xcd, 0x62, 0x77, +0xed, 0x8c, 0x12, 0x00, +0xff, 0xfe, 0x52, 0xc8, +0xed, 0x8c, 0x12, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x60, +0x00, 0x00, 0x00, 0xa0, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x60, +0x00, 0x00, 0x00, 0xa0, +0x02, 0x00, 0x06, 0x03, +0x00, 0x01, 0x01, 0x00, +0x06, 0x03, 0x00, 0x01, +0x00, 0x00, 0x20, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0x07, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x29, 0x02, 0xaf, 0x47, +0xa7, 0xa2, 0x9b, 0xc4, +0x41, 0x2d, 0x55, 0x6f, +0x95, 0x18, 0xab, 0x3d, +0xb0, 0x45, 0xb2, 0xaa, +0x93, 0xdf, 0xf6, 0x7f, +0xbd, 0xda, 0x56, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x20, 0xfe, 0x7f, +0x39, 0x61, 0xdc, 0x0c, +0xc3, 0x9e, 0xe2, 0x00, +0x79, 0xc2, 0x3a, 0x7e, +0xc3, 0x9e, 0xe2, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x91, 0x88, 0xfc, 0x5f, +0x4d, 0xdb, 0x1e, 0x16, +0x65, 0x49, 0xc2, 0x53, +0x4d, 0xdb, 0x1e, 0x16, +0xf5, 0xff, 0xff, 0x3f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x29, 0x02, 0xaf, 0x47, +0xa7, 0xa2, 0x9b, 0xc4, +0x41, 0x2d, 0x55, 0x6f, +0x95, 0x18, 0xab, 0x3d, +0xb0, 0x45, 0xb2, 0xaa, +0x93, 0xdf, 0xf6, 0x7f, +0xbd, 0xda, 0x56, 0x55, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x20, 0xfe, 0x7f, +0x39, 0x61, 0xdc, 0x0c, +0xc3, 0x9e, 0xe2, 0x00, +0x79, 0xc2, 0x3a, 0x7e, +0xc3, 0x9e, 0xe2, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x91, 0x88, 0xfc, 0x5f, +0x4d, 0xdb, 0x1e, 0x16, +0x65, 0x49, 0xc2, 0x53, +0x4d, 0xdb, 0x1e, 0x16, +0xf5, 0xff, 0xff, 0x3f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x01, 0x02, 0x00, 0x01, +0x01, 0x02, 0x00, 0x01, +0x37, 0xb4, 0x05, 0x00, +0x91, 0x97, 0xf4, 0x7f, +0x37, 0xb4, 0x05, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x20, +0x00, 0x00, 0x00, 0x1a, +0xaf, 0xb1, 0xa7, 0x0c, +0x91, 0x49, 0xc0, 0x0b, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x01, 0x00, 0x00, 0x80, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x9c, 0xc5, 0x5f, 0x1c, +0x9c, 0xc5, 0x5f, 0x1c, +0x3c, 0x00, 0x00, 0x00, +0x08, 0x00, 0x00, 0x00, +0x00, 0x00, 0x04, 0x00, +0x80, 0x00, 0x00, 0x00, +0x00, 0x00, 0x42, 0x00, +0x00, 0x00, 0x04, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0xaf, 0x00, +0x00, 0x00, 0x10, 0x00, +0x00, 0x00, 0x00, 0x02, +0xd0, 0x08, 0x00, 0x00, +0x68, 0x04, 0x00, 0x00, +0x01, 0x00, 0x00, 0x00, +0x00, 0x00, 0x28, 0x00, +0x00, 0x00, 0x30, 0x00, +0x00, 0x80, 0x00, 0x00, +0x00, 0x00, 0x00, 0x01, +0x00, 0x00, 0x00, 0x28, +0x00, 0x00, 0x00, 0x38, +0x00, 0x00, 0x04, 0x00, +0x00, 0x00, 0x40, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x8a, 0x69, 0x03, 0x00, +0x57, 0x9a, 0x91, 0x24, +0x1b, 0x58, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x14, 0x01, 0x00, 0x00, +0x62, 0x6c, 0x02, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, +0xcf, 0x08, 0x00, 0x00, +0x8c, 0x02, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x60, 0x18, 0x86, 0x61, +0x60, 0x14, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xb0, 0x01, +0x00, 0x00, 0x60, 0x02, +0xc6, 0xe3, 0xc4, 0x00, +0xc6, 0xe3, 0xc4, 0x00, +0x00, 0x00, 0x00, 0x60, +0x00, 0x00, 0x00, 0x00, +0x4a, 0xed, 0x87, 0x64, +0xff, 0xff, 0xff, 0x7f, +0xa0, 0x04, 0x00, 0x00, +0xe7, 0x5f, 0xfe, 0xff, +0xb0, 0x05, 0x5b, 0x00, +0x56, 0x55, 0x55, 0xf5, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x40, +0xff, 0xff, 0xff, 0x1f, +0xdf, 0x59, 0x37, 0x5f, +0xff, 0xff, 0xff, 0x5f, +0x0b, 0xb9, 0x58, 0x00, +0x00, 0x00, 0x00, 0x10, +0xaa, 0xaa, 0xaa, 0x2a, +0x99, 0x99, 0x99, 0x19, +0x92, 0x24, 0x49, 0x12, +0x8e, 0xe3, 0x38, 0x0e, +0xba, 0xe8, 0xa2, 0x0b, +0x89, 0x9d, 0xd8, 0x09, +0x88, 0x88, 0x88, 0x08, +0x87, 0x87, 0x87, 0x07, +0x29, 0xf6, 0x96, 0x37, +0xaa, 0xaa, 0xaa, 0x2a, +0x99, 0x99, 0x99, 0x19, +0x92, 0x24, 0x49, 0x12, +0x8e, 0xe3, 0x38, 0x0e, +0xba, 0xe8, 0xa2, 0x0b, +0x89, 0x9d, 0xd8, 0x09, +0x88, 0x88, 0x88, 0x08, +0x87, 0x87, 0x87, 0x07, +0xa6, 0xf6, 0x43, 0x32, +0x4d, 0xed, 0x87, 0x64, +0xa7, 0xf6, 0x43, 0x32, +0x59, 0x09, 0xbc, 0xcd, +0x00, 0x00, 0x00, 0x08, +0x78, 0x78, 0x78, 0x00, +0xc0, 0x09, 0x9c, 0x00, +0x20, 0x0d, 0xd2, 0x00, +0x12, 0xe4, 0x29, 0x01, +0x71, 0x1c, 0xc7, 0x01, +0xc3, 0x30, 0x0c, 0x03, +0x66, 0x66, 0x66, 0x06, +0x55, 0x55, 0x55, 0x15, +0x00, 0x00, 0x00, 0x08, +0x88, 0x88, 0x88, 0x00, +0x40, 0x0b, 0xb4, 0x00, +0x0f, 0x3e, 0xf8, 0x00, +0xc1, 0x16, 0x6c, 0x01, +0x92, 0x24, 0x49, 0x02, +0x44, 0x44, 0x44, 0x04, +0xaa, 0xaa, 0xaa, 0x0a, +0xff, 0xff, 0xff, 0x3f, +0x00, 0x00, 0x00, 0x00, +0x80, 0x66, 0x66, 0x66, +0x00, 0x00, 0x00, 0x04, +0x00, 0x20, 0xfe, 0x7f, +0x00, 0x00, 0xb0, 0x7f, +0x00, 0x20, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, +0x00, 0x00, 0xc0, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x48, 0x00, +0x00, 0x00, 0xf8, 0x7f, +0x00, 0x02, 0x00, 0x00, +0xff, 0xff, 0xff, 0x1f, +0x00, 0x00, 0x00, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x40, 0x8f, 0xc2, 0x35, +0x00, 0x00, 0x00, 0x00, +0x91, 0x88, 0xfc, 0x5f, +0x39, 0x61, 0xdc, 0x0c, +0xff, 0xff, 0xff, 0x7f, +0x80, 0x66, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, +0x83, 0x4c, 0x27, 0x0c, +0x00, 0x00, 0x00, 0x03, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xa0, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x20, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x20, +0x00, 0x00, 0x00, 0x20, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x20, +0x75, 0x70, 0x35, 0x82, +0x19, 0x43, 0x6d, 0x7d, +0x8f, 0xb3, 0xa2, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0xe7, 0x4c, 0x2b, 0x00, +0x33, 0x66, 0xa9, 0x7f, +0xe7, 0x4c, 0x2b, 0x00, +0x4d, 0x52, 0x74, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xc5, 0x29, 0x99, 0x3a, +0x02, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0x96, 0xe3, 0x8e, 0xb9, +0xfd, 0xd8, 0xa4, 0x7f, +0x6d, 0x43, 0xcc, 0x46, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x0e, 0x0f, 0x0f, 0x2f, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x29, 0x02, 0xaf, 0x47, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x4d, 0xdb, 0x1e, 0x16, +0x65, 0x49, 0xc2, 0x53, +0x4d, 0xdb, 0x1e, 0x16, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x7f, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x01, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xe1, 0x00, 0x00, 0x00, +0x02, 0xf1, 0x00, 0x00, +0x6e, 0x86, 0x7d, 0x00, +0x0a, 0x00, 0x00, 0x00, +0x02, 0x00, 0x00, 0x00, +0x05, 0x00, 0x00, 0x00, +0x01, 0x02, 0x00, 0x01, +0x00, 0x00, 0x0c, 0x00, +0xd1, 0x07, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xcf, 0xcd, 0x16, 0x00, +0x5f, 0x64, 0xd2, 0x7f, +0xcf, 0xcd, 0x16, 0x00, +0xb0, 0x45, 0xb2, 0xaa, +0xbd, 0xda, 0x56, 0x55, +0xfd, 0xe0, 0x98, 0xad, +0xd1, 0xbe, 0x7b, 0x7c, +0x33, 0x60, 0xeb, 0x55, +0xd5, 0x4a, 0x03, 0x00, +0x5c, 0xbe, 0x02, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x95, 0x5b, 0x8f, 0x02, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xff, 0xff, 0xff, 0x7f, +0x33, 0x26, 0x70, 0x02, +0xff, 0xff, 0xff, 0x7f, +0x01, 0x00, 0x00, 0x80, +0x00, 0x00, 0x00, 0x00, +0x80, 0x00, 0x00, 0x00, +0x00, 0x01, 0x00, 0x00, +0x80, 0x01, 0x00, 0x00, +0x00, 0x02, 0x00, 0x00, +0x80, 0x02, 0x00, 0x00, +0x00, 0x03, 0x00, 0x00, +0x80, 0x03, 0x00, 0x00, +0xff, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x00, 0x00, 0xd8, 0x00, +0x26, 0x09, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0x5c, 0x09, 0x00, 0x00, +0x78, 0x09, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xa0, 0x09, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xd6, 0x08, 0x00, 0x00, +0xda, 0x09, 0x00, 0x00, +0x16, 0x0a, 0x00, 0x00, +0x4e, 0x0a, 0x00, 0x00, +0x3a, 0x0a, 0x00, 0x00, +0xec, 0x10, 0x00, 0x00, +0xaa, 0x11, 0x00, 0x00, +0xcc, 0x11, 0x00, 0x00, +0x46, 0x12, 0x00, 0x00, +0xd8, 0x08, 0x00, 0x00, +0x98, 0x12, 0x00, 0x00, +0xd0, 0x14, 0x00, 0x00, +0xd8, 0x08, 0x00, 0x00, +0x14, 0x13, 0x00, 0x00, +0xd8, 0x08, 0x00, 0x00, +0x34, 0x13, 0x00, 0x00, +0x80, 0x13, 0x00, 0x00, +0xa8, 0x13, 0x00, 0x00, +0xca, 0x13, 0x00, 0x00, +0xca, 0x13, 0x00, 0x00, +0xd8, 0x08, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xd0, 0xcd, 0x16, 0x00, +0x5f, 0x64, 0xd2, 0x7f, +0xd0, 0xcd, 0x16, 0x00, +0xcf, 0xcd, 0x16, 0x00, +0x5f, 0x64, 0xd2, 0x7f, +0xcf, 0xcd, 0x16, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x41, 0xca, 0x88, 0x3e, +0x41, 0xca, 0x88, 0x3e, +0x29, 0x02, 0xaf, 0x47, +0x29, 0x02, 0xaf, 0x47, +0x3b, 0xcb, 0x88, 0x3e, +0x3b, 0xcb, 0x88, 0x3e, +0x8d, 0xff, 0x7f, 0x3e, +0x8d, 0xff, 0x7f, 0x3e, +0xff, 0xff, 0xff, 0x7f, +0xd0, 0xcc, 0xcc, 0x0c, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x02, +0x97, 0x00, 0xb4, 0x00, +0x00, 0x00, 0x00, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x6c, 0x09, 0xf9, 0xe8, +0x03, 0x56, 0x0e, 0x41, +0x51, 0xb8, 0x1e, 0x05, +0x32, 0x08, 0xac, 0xe4, +0x83, 0xd3, 0x82, 0x41, +0x66, 0x66, 0x66, 0x06, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x50, 0x00, +0x00, 0x03, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x30, 0x01, 0x00, 0x00, +0x00, 0x00, 0x03, 0x00, +0x60, 0x01, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0xa3, 0x0f, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, +}; + +const unsigned char CcUpdataCode128_01_02_02_01[] = { +0x5c, 0x81, 0x02, 0xbf, 0xb0, +0x68, 0x01, 0x01, 0xc5, 0xac, +0xa4, 0x00, 0x08, 0x00, 0x6c, +0x80, 0x06, 0xc6, 0x80, 0x20, +0x01, 0x12, 0x18, 0x00, 0x61, +0x80, 0x06, 0x16, 0x80, 0x10, +0x1c, 0x22, 0x18, 0x00, 0x61, +0x68, 0x02, 0x00, 0x08, 0xac, +0x80, 0x06, 0xc8, 0x00, 0x61, +0x80, 0x06, 0x16, 0x80, 0x10, +0x1d, 0x02, 0xc6, 0x80, 0x00, +0x02, 0x62, 0x16, 0x00, 0x00, +0x00, 0x03, 0x98, 0x40, 0x6c, +0xa0, 0x50, 0x08, 0x00, 0x08, +0x80, 0x84, 0x80, 0x00, 0x00, +0x64, 0x00, 0x80, 0x0d, 0x0f, +0x40, 0x00, 0x02, 0x80, 0x50, +0x76, 0x00, 0x00, 0x10, 0x60, +0x5c, 0x01, 0x20, 0x40, 0x0a, +0x68, 0x38, 0x1c, 0x03, 0x21, +0xa0, 0x46, 0x06, 0x80, 0x20, +0x00, 0xc2, 0xc8, 0x40, 0x6c, +0x46, 0x0a, 0x40, 0x48, 0x4a, +0x84, 0x8c, 0x80, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x08, +0x38, 0x13, 0xe2, 0x59, 0xa0, +0xbc, 0x0d, 0x07, 0x60, 0x00, +0x01, 0x0a, 0x0a, 0x04, 0x61, +0x84, 0x80, 0xa8, 0x40, 0x08, +0x54, 0x4d, 0x22, 0x04, 0xa1, +0x68, 0x01, 0x01, 0xba, 0x2c, +0x46, 0x0a, 0x40, 0x40, 0x48, +0x84, 0x86, 0xc0, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x76, 0x00, 0x00, 0x10, 0xa1, +0x5c, 0x08, 0xb0, 0x48, 0x08, +0x76, 0x00, 0x00, 0x10, 0x22, +0x25, 0x9a, 0x0b, 0xc0, 0x58, +0xa0, 0xca, 0x17, 0x60, 0x05, +0x00, 0x82, 0x0b, 0xc0, 0x2f, +0x85, 0x06, 0x08, 0x50, 0x60, +0x68, 0x02, 0x00, 0x16, 0x20, +0xba, 0x14, 0x88, 0x48, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +0x76, 0x00, 0x00, 0x10, 0x81, +0x5c, 0x81, 0x02, 0x08, 0x02, +0x5c, 0x00, 0x48, 0x08, 0x02, +0x55, 0x3e, 0x93, 0x01, 0x38, +0x51, 0x48, 0xa2, 0xc0, 0x41, +0x2a, 0x06, 0x37, 0x60, 0x00, +0x01, 0x06, 0x02, 0xe8, 0x5c, +0x68, 0x38, 0x1c, 0x03, 0x23, +0x62, 0x00, 0x00, 0x01, 0xd4, +0x5c, 0x00, 0x92, 0x18, 0x23, +0x5c, 0x02, 0x0b, 0x00, 0x83, +0xa0, 0x00, 0x48, 0x22, 0x88, +0x86, 0x02, 0x56, 0xc7, 0x03, +0x80, 0x64, 0x86, 0x00, 0x01, +0x00, 0x04, 0x08, 0x58, 0x52, +0x00, 0x00, 0x08, 0x28, 0x0a, +0x6c, 0x70, 0x38, 0x02, 0x4a, +0x00, 0x00, 0x08, 0x60, 0x65, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x83, 0x0b, 0xff, 0xc0, +0x85, 0x85, 0x10, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x83, 0x0b, 0xff, 0xc0, +0x28, 0x0e, 0x48, 0x40, 0x48, +0xa0, 0xc6, 0x08, 0x40, 0x02, +0x85, 0x08, 0x05, 0x44, 0x40, +0x20, 0xca, 0x06, 0x80, 0x10, +0x1b, 0xa2, 0xc4, 0x60, 0xa4, +0x05, 0x0d, 0x08, 0x40, 0x6c, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x00, 0x09, 0x21, +0x00, 0x00, 0x0a, 0x0c, 0x62, +0x85, 0x00, 0x05, 0x53, 0xc1, +0x04, 0x82, 0x12, 0x2f, 0xd4, +0x2a, 0x8e, 0x02, 0x80, 0x10, +0x22, 0x88, 0x46, 0x20, 0x00, +0x00, 0x04, 0x26, 0xc0, 0x00, +0x16, 0x64, 0x85, 0xc8, 0x04, +0x20, 0x81, 0x19, 0x48, 0x08, +0x94, 0x04, 0x00, 0x00, 0x00, +0x40, 0x00, 0x03, 0xa1, 0x40, +0xab, 0xff, 0x08, 0x80, 0x76, +0x68, 0x00, 0x00, 0x2f, 0x20, +0x66, 0x00, 0x80, 0x09, 0x60, +0x68, 0x00, 0x00, 0x2f, 0x20, +0x5c, 0x08, 0xa0, 0x80, 0x36, +0x76, 0x00, 0x00, 0x10, 0xa0, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0xab, 0xff, 0x08, 0x80, 0x76, +0x68, 0x00, 0x00, 0x6f, 0x20, +0x66, 0x00, 0x80, 0x09, 0x60, +0x68, 0x00, 0x00, 0x6f, 0x20, +0x5c, 0x08, 0xe0, 0x80, 0x36, +0x76, 0x00, 0x00, 0x08, 0xa0, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x39, 0x02, 0x06, 0x80, 0x20, +0x03, 0x72, 0xc8, 0x00, 0x7a, +0x6c, 0x00, 0x00, 0x26, 0x6c, +0x46, 0x0a, 0x40, 0x00, 0x7a, +0x84, 0x07, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x00, 0x12, 0x20, +0x00, 0x00, 0x09, 0x40, 0xac, +0x32, 0x02, 0x0b, 0xc1, 0xe0, +0x32, 0x06, 0x0b, 0xc1, 0x80, +0x32, 0x0a, 0x0b, 0xc1, 0x20, +0x32, 0x12, 0x0b, 0xc0, 0xc0, +0x32, 0x16, 0x0b, 0xc0, 0x60, +0x32, 0x1a, 0x0b, 0xc1, 0x89, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x21, 0x27, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x1b, 0xc7, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x26, 0xc7, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x17, 0x67, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x13, 0x87, +0x68, 0x00, 0x00, 0x04, 0x20, +0x64, 0x00, 0x80, 0x10, 0x67, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x84, 0x10, 0x05, 0x90, 0x40, +0x2b, 0xfe, 0x08, 0x80, 0x76, +0x42, 0x0a, 0x42, 0x00, 0x01, +0xa4, 0x04, 0x08, 0x4a, 0xa1, +0x66, 0x00, 0x40, 0x3b, 0x68, +0xa0, 0x81, 0x18, 0x81, 0x00, +0x23, 0x84, 0x46, 0x80, 0x00, +0x7f, 0xfc, 0x02, 0x88, 0x20, +0x68, 0x00, 0x05, 0xff, 0xc2, +0x30, 0x88, 0x0b, 0xc1, 0x83, +0x68, 0x02, 0x08, 0x00, 0x02, +0x28, 0x08, 0x46, 0xc0, 0x00, +0x35, 0x44, 0x8b, 0xc1, 0x27, +0x6c, 0x00, 0x03, 0x54, 0x00, +0x68, 0x3d, 0xf8, 0x00, 0x02, +0x54, 0x04, 0x22, 0x08, 0xc1, +0x51, 0x83, 0x02, 0x0c, 0x62, +0x84, 0x82, 0x18, 0x81, 0x50, +0x40, 0x00, 0x00, 0x80, 0xe2, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x00, 0x80, 0xa0, +0x00, 0x00, 0x08, 0x40, 0x50, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x5c, 0x80, 0x80, 0x41, 0x00, +0x32, 0x08, 0x0b, 0xc2, 0x28, +0x6c, 0x00, 0x03, 0x54, 0x24, +0x6c, 0x00, 0x00, 0x0c, 0x00, +0x55, 0x3c, 0x00, 0x42, 0xa0, +0x22, 0xfc, 0x42, 0xa8, 0xe2, +0x28, 0x08, 0x02, 0x28, 0x86, +0x32, 0x03, 0x0b, 0xc2, 0x9d, +0x5c, 0x80, 0x4a, 0x00, 0x10, +0x62, 0x00, 0x00, 0x00, 0xf6, +0x38, 0x10, 0x40, 0x00, 0x00, +0x94, 0x08, 0x85, 0x04, 0x80, +0x14, 0x08, 0xa5, 0x04, 0x89, +0x14, 0x08, 0x95, 0x04, 0x85, +0x94, 0x08, 0x92, 0x32, 0x12, +0x29, 0x08, 0x02, 0x09, 0x09, +0x23, 0x41, 0xb2, 0x36, 0x0a, +0x29, 0x0c, 0x02, 0x90, 0x80, +0xbb, 0x10, 0x0b, 0xc1, 0x37, +0x5c, 0x80, 0x4a, 0x00, 0xc0, +0x5c, 0x01, 0x0b, 0xb0, 0x80, +0x51, 0xd0, 0x98, 0x40, 0x21, +0x51, 0xe0, 0x81, 0x83, 0x8a, +0x51, 0xf0, 0x91, 0x48, 0xc6, +0x98, 0x3c, 0x3a, 0x08, 0x02, +0x98, 0x30, 0x09, 0x48, 0xc3, +0x98, 0x38, 0x89, 0x50, 0xe0, +0xa0, 0x46, 0x09, 0x48, 0xe4, +0x84, 0x05, 0x1b, 0xa1, 0x48, +0x6c, 0x00, 0x03, 0x54, 0x64, +0x40, 0x00, 0x03, 0x80, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xfe, 0x0b, 0xc1, 0x38, +0x88, 0x07, 0x6a, 0x00, 0xa0, +0xa0, 0x48, 0x18, 0x40, 0x20, +0x88, 0x0e, 0x1a, 0x00, 0x11, +0x66, 0x00, 0x40, 0x3b, 0x68, +0xa4, 0x04, 0x08, 0x81, 0x08, +0xb0, 0x7f, 0xe5, 0x44, 0xd2, +0x08, 0x0a, 0x06, 0xc0, 0x00, +0x35, 0x64, 0x86, 0x80, 0x20, +0x06, 0x62, 0x1b, 0xc0, 0x6f, +0x84, 0x06, 0x10, 0x00, 0x00, +0x6c, 0x00, 0x03, 0x56, 0x08, +0x2a, 0x06, 0x48, 0x41, 0xc8, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x00, 0x01, 0xaa, 0x20, +0x68, 0x00, 0x00, 0x0a, 0x22, +0x5c, 0x00, 0x40, 0x40, 0x82, +0x51, 0x44, 0xa2, 0x14, 0xa1, +0x2a, 0x06, 0x22, 0xe8, 0x13, +0x62, 0x00, 0x00, 0x00, 0xd3, +0x5c, 0x80, 0x88, 0x40, 0x24, +0x5c, 0x80, 0x40, 0x50, 0x22, +0xbb, 0x04, 0x15, 0x1d, 0x04, +0x18, 0x34, 0xa5, 0x1e, 0x05, +0x18, 0x30, 0x05, 0x1f, 0x04, +0x95, 0x04, 0x69, 0x83, 0x82, +0x95, 0x04, 0x09, 0x83, 0x48, +0x95, 0x04, 0x29, 0x50, 0x44, +0x6c, 0x00, 0x03, 0x54, 0x64, +0x68, 0x01, 0x00, 0xed, 0x2c, +0x46, 0x0a, 0x40, 0x41, 0x7a, +0x84, 0x86, 0xc0, 0x00, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0x7a, 0x21, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x00, 0x07, 0x00, 0x08, +0x5c, 0x01, 0x30, 0x40, 0x48, +0x5c, 0x09, 0xe2, 0x00, 0x20, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x00, +0x25, 0x90, 0x0b, 0xff, 0xc0, +0x68, 0x00, 0x08, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x06, 0x50, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x00, +0x25, 0x90, 0x0b, 0xff, 0xc0, +0x68, 0x00, 0x09, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x06, 0x50, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x93, 0x0b, 0xff, 0xc0, +0x6c, 0x00, 0x03, 0x58, 0x7a, +0x68, 0x01, 0x00, 0xed, 0x20, +0xba, 0x14, 0x86, 0xc0, 0x00, +0x00, 0xa6, 0x00, 0x00, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0x8f, 0xa1, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x02, 0x08, 0x00, 0x24, +0x68, 0x00, 0x07, 0x00, 0x09, +0x5c, 0x09, 0xe3, 0x00, 0x16, +0x60, 0x00, 0xc0, 0x01, 0x80, +0x5c, 0x02, 0x3a, 0xc0, 0x10, +0x5c, 0x04, 0x02, 0x00, 0x20, +0x60, 0x00, 0x10, 0x00, 0x20, +0x6c, 0x70, 0x38, 0x06, 0x49, +0x84, 0x04, 0xab, 0xb0, 0x80, +0x6c, 0x70, 0x38, 0x02, 0x4e, +0x40, 0x00, 0x03, 0xc0, 0x27, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xa0, +0x84, 0x04, 0xb0, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xc0, +0x28, 0x02, 0xd6, 0xc0, 0x00, +0x35, 0x87, 0xa6, 0x80, 0x10, +0x0e, 0xd2, 0x0b, 0xa1, 0x48, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +0x84, 0x10, 0x85, 0x90, 0x50, +0x2b, 0xff, 0x04, 0x20, 0xac, +0x08, 0x0f, 0x68, 0x80, 0x60, +0xa0, 0x00, 0x18, 0x4a, 0xa1, +0x68, 0x00, 0x01, 0xac, 0x20, +0x66, 0x00, 0x40, 0x3b, 0x68, +0x40, 0x00, 0x02, 0x08, 0x11, +0x6c, 0x00, 0x03, 0x58, 0x08, +0x32, 0x02, 0x0b, 0xc1, 0x41, +0x5c, 0x00, 0x60, 0x80, 0x20, +0x68, 0x02, 0x00, 0xa6, 0x21, +0x6c, 0x00, 0x03, 0x58, 0x48, +0x84, 0x0e, 0x1b, 0xc0, 0xc7, +0xa0, 0x0c, 0x1a, 0x0c, 0x60, +0x88, 0x06, 0x06, 0x80, 0x00, +0x1a, 0xc2, 0x08, 0x48, 0x21, +0x66, 0x00, 0x40, 0x3c, 0x40, +0x5c, 0x01, 0x20, 0x80, 0x20, +0x00, 0x00, 0x08, 0x40, 0x48, +0x00, 0x00, 0x08, 0x80, 0xb6, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x68, 0x00, 0x07, 0x00, 0x08, +0x5c, 0xbf, 0x00, 0x40, 0x48, +0x5c, 0x00, 0x71, 0xc0, 0x00, +0x68, 0x00, 0x02, 0xff, 0xc8, +0x5c, 0x08, 0x20, 0x40, 0x48, +0x40, 0x00, 0x00, 0x41, 0x4a, +0x68, 0x02, 0x08, 0x00, 0x24, +0x60, 0x0b, 0xf0, 0x00, 0x4f, +0x6c, 0x70, 0x38, 0x00, 0x0a, +0x50, 0xc9, 0x82, 0xc0, 0x10, +0x6c, 0x70, 0x38, 0x00, 0x0a, +0x50, 0xc9, 0x83, 0xb1, 0x00, +0x6c, 0x00, 0x03, 0x58, 0x7a, +0x68, 0x01, 0x00, 0xed, 0x20, +0xbb, 0x10, 0x0b, 0xa1, 0x48, +0x6c, 0x00, 0x00, 0x0a, 0x60, +0x40, 0x00, 0x03, 0x80, 0x00, +}; + +#define VERNUM_01_02_02_01 0x00011b020b +#define CAL_ID_01_02_02_01 0x00013802ff diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/LC898128_Calibration_ACT01.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/LC898128_Calibration_ACT01.h new file mode 100755 index 0000000000000000000000000000000000000000..d2282be47e87cda752d3331e027865da0152d840 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/LC898128_Calibration_ACT01.h @@ -0,0 +1,217 @@ +//******************************************************************************** +// << LC898128 Evaluation Soft>> +// Program Name : LC898128_Calibration_ACT01.h +// Explanation : LC898128_L_ calibration parameters +// History : First edition +//******************************************************************************** + +// Version Name : 00-00-0000 + +// for "" + +//******************************************************************************** +// defines +//******************************************************************************** +#define X_BIAS (0x40000000 ) +//#define Y_BIAS (0x40000000 ) +//#define X_BIAS (0x48000000 ) //20190815 Komori +#define Y_BIAS (0x38000000 ) //20190815 Komori +#define X_OFST (0x10000000 ) // +#define Y_OFST (0x10000000 ) // + +#define MARGIN (0x0300 ) // Margin + +#define BIAS_ADJ_RANGE_X (0x5999) // 35% +//#define BIAS_ADJ_RANGE_X (0x6666) // 40% //20190814 Komori +//#define BIAS_ADJ_RANGE_Y (0x5999) // 35% +//#define BIAS_ADJ_RANGE_Y (0x51EB) // 32% //20190815 Komori +#define BIAS_ADJ_RANGE_Y (0x4F5B) // 31% +//#define BIAS_ADJ_RANGE_Y (0x4CCC) // 30% +//#define BIAS_ADJ_RANGE_Y (0x4A3D) // 29% +//#define BIAS_ADJ_RANGE_Y (0x48F5) // 28.5% +//#define BIAS_ADJ_RANGE_Y (0x47AD) // 28% +//#define BIAS_ADJ_RANGE_Y (0x3FFF) // 25% + +#define SINE_OFFSET 0x0008B8E5 // Freq Setting = Freq * 80000000h / Fs : 4Hz +//#define SINE_NUM 3756 // 15.027322/0.004 > num +#define SINE_NUM 512 // 15.027322/0.004 > num +#define SINE_GAIN_X 0x4D780000 // Set Sine Wave Gain 115mA (115mA*7fff/190mA) 190mA(min) +#define SINE_GAIN_Y 0x4D780000 // Set Sine Wave Gain 115mA (115mA*7fff/190mA) 190mA(min) + +#define DECRE_CAL (0x0100 ) // decrease value + +//#define ACT_MAX_DRIVE_X 0x33333333 // 80mA /200=0.4 +//#define ACT_MAX_DRIVE_Y 0x33333333 // 80mA /200=0.4 +//#define ACT_MIN_DRIVE_X 0xCCCCCCCC +//#define ACT_MIN_DRIVE_Y 0xCCCCCCCC +#define ACT_MAX_DRIVE_X 0x7FFFFFFF // 200mA Max //20190814 Komori +#define ACT_MAX_DRIVE_Y 0x7FFFFFFF // 200mA Max +#define ACT_MIN_DRIVE_X 0x80000001 +#define ACT_MIN_DRIVE_Y 0x80000001 + +//#define ACT_X_STEP_NUM 0x1F +#define ACT_X_STEP_NUM 0 +#define ACT_X_STEP (ACT_MAX_DRIVE_X/(ACT_X_STEP_NUM+1)) +#define ACT_X_STEP_TIME 2 + +//#define ACT_Y_STEP_NUM 0x1F +#define ACT_Y_STEP_NUM 0 +#define ACT_Y_STEP (ACT_MAX_DRIVE_Y/(ACT_Y_STEP_NUM+1)) +#define ACT_Y_STEP_TIME 2 + +#define MEASURE_WAIT 50 + +#define SXGAIN_LOP (0x38000000 ) // 0.437513 +#define SYGAIN_LOP (0x38000000 ) // 0.437513 + +/******* X ******/ +#define LOOP_NUM_HX 480 // 15.027322kHz/0.500kHz*16times +#define LOOP_FREQ_HX 0x044247E0 // 500Hz = Freq * 80000000h / Fs +//#define LOOP_NUM_HX 2671 // 15.027322kHz/0.090kHz*16times +//#define LOOP_FREQ_HX 0x00C43F60 // 90Hz = Freq * 80000000h / Fs +//#define LOOP_NUM_HX (8014/1) // 15.027322kHz/0.030kHz* 8times +//#define LOOP_FREQ_HX 0x00416AAE // 30Hz = Freq * 80000000h / Fs + +//#define LOOP_GAIN_HX 0x040C3708 // -30dB +//#define LOOP_GAIN_HX 0x08137F40 // -24dB +#define LOOP_GAIN_HX 0x2026F340 // -12dB +//#define GAIN_GAP_HX (2000) // 20*log(1000/1000)=-6dB +//#define GAIN_GAP_HX (1400) // 20*log(1000/1000)=-3dB +#define GAIN_GAP_HX (1000) // 20*log(1000/1000)=0dB +//#define GAIN_GAP_HX (250) // 20*log(1000/250)=12dB + +/******* Y ******/ +#define LOOP_NUM_HY 480 // 15.027322kHz/0.500kHz*16times +#define LOOP_FREQ_HY 0x044247E0 // 500Hz = Freq * 80000000h / Fs +//#define LOOP_NUM_HY 2671 // 15.027322kHz/0.090kHz*16times +//#define LOOP_FREQ_HY 0x00C43F60 // 90Hz = Freq * 80000000h / Fs +//#define LOOP_NUM_HY (8014/1) // 15.027322kHz/0.030kHz* 8times +//#define LOOP_FREQ_HY 0x00416AAE // 30Hz = Freq * 80000000h / Fs + +//#define LOOP_GAIN_HY 0x040C3708 // -30dB +//#define LOOP_GAIN_HY 0x08137F40 // -24dB + #define LOOP_GAIN_HY 0x2026F340 // -12dB +//#define GAIN_GAP_HY (2000) // 20*log(1000/1000)=-6dB +//#define GAIN_GAP_HY (1400) // 20*log(1000/1000)=-3dB +#define GAIN_GAP_HY (1000) // 20*log(1000/1000)=0dB +//#define GAIN_GAP_HY (250) // 20*log(1000/250)=12dB + +#define LOOP_MAX_X (SXGAIN_LOP << 1) // x2 +#define LOOP_MIN_X (SXGAIN_LOP >> 1) // x0.5 +#define LOOP_MAX_Y (SYGAIN_LOP << 1) // x2 +#define LOOP_MIN_Y (SYGAIN_LOP >> 1) // x0.5 + +#define SLT_XY_SWAP 0 // 0: pos 1: swap +#define SLT_OFFSET_X (0xFFFFF400) +#define SLT_OFFSET_Y (0xFFFFF400) +#define SLT_DRIVE_X (1L) +#define SLT_DRIVE_Y (1L) + +//******************************************************************************** +// structure for calibration +//******************************************************************************** +/* const*/ ADJ_HALL ACT01_HallCalParameter = { +/* XBiasInit */ X_BIAS, +/* YBiasInit */ Y_BIAS, +/* XOffsetInit */ X_OFST, +/* YOffsetInit */ Y_OFST, +/* Margin */ MARGIN, +/* XTargetRange */ BIAS_ADJ_RANGE_X, +/* XTargetMax */ (BIAS_ADJ_RANGE_X + (MARGIN/2)), +/* XTargetMin */ (BIAS_ADJ_RANGE_X - (MARGIN/2)), +/* YTargetRange */ BIAS_ADJ_RANGE_Y, +/* YTargetMax */ (BIAS_ADJ_RANGE_Y + (MARGIN/2)), +/* YTargetMin */ (BIAS_ADJ_RANGE_Y - (MARGIN/2)), +/* SinNum */ SINE_NUM, +/* SinFreq */ SINE_OFFSET, +/* XSinGain */ SINE_GAIN_X, +/* YSinGain */ SINE_GAIN_Y, +/* DecrementStep */ DECRE_CAL, +/* ActMaxDrive_X */ ACT_MAX_DRIVE_X, +/* ActMaxDrive_Y */ ACT_MAX_DRIVE_Y, +/* ActMinDrive_X */ ACT_MIN_DRIVE_X, +/* ActMinDrive_Y */ ACT_MIN_DRIVE_Y, +/* ActStep_X */ ACT_X_STEP, +/* ActStep_X_Num*/ ACT_X_STEP_NUM, +/* ActStep_X_time*/ ACT_X_STEP_TIME, +/* ActStep_Y */ ACT_Y_STEP, +/* ActStep_Y_Num*/ ACT_Y_STEP_NUM, +/* ActStep_Y_time*/ ACT_Y_STEP_TIME, +/* WaitTime*/ MEASURE_WAIT, +}; // + + +const ADJ_LOPGAN ACT01_LoopGainParameter = { +/* Hxgain */ SXGAIN_LOP, +/* Hygain */ SYGAIN_LOP, +/* XNoiseNum */ LOOP_NUM_HX, +/* XNoiseFreq */ LOOP_FREQ_HX, +/* XNoiseGain */ LOOP_GAIN_HX, +/* XGap */ GAIN_GAP_HX, +/* YNoiseNum */ LOOP_NUM_HY, +/* YNoiseFreq */ LOOP_FREQ_HY, +/* YNoiseGain */ LOOP_GAIN_HY, +/* YGap */ GAIN_GAP_HY, +/* XJudgeHigh */ LOOP_MAX_X, +/* XJudgeLow */ LOOP_MIN_X, +/* YJudgeHigh */ LOOP_MAX_Y, +/* YJudgeLow */ LOOP_MIN_Y, +}; // + +const LINCRS ACT01_LinCrsParameter = { +/* XY_SWAP */ SLT_XY_SWAP, +/* STEPX */ SLT_OFFSET_X, +/* STEPY */ SLT_OFFSET_Y, +/* DRIVEX */ SLT_DRIVE_X, +/* DRIVEY */ SLT_DRIVE_Y, +}; // + + + +#undef X_BIAS +#undef Y_BIAS +#undef X_OFST +#undef Y_OFST +#undef MARGIN +#undef BIAS_ADJ_RANGE_X +#undef BIAS_ADJ_RANGE_Y +#undef SINE_NUM +#undef SINE_OFFSET +#undef SINE_GAIN_X +#undef SINE_GAIN_Y +#undef DECRE_CAL + +#undef ACT_MAX_DRIVE_X +#undef ACT_MAX_DRIVE_Y +#undef ACT_MIN_DRIVE_X +#undef ACT_MIN_DRIVE_Y +#undef ACT_X_STEP +#undef ACT_X_STEP_NUM +#undef ACT_X_STEP_TIME +#undef ACT_Y_STEP +#undef ACT_Y_STEP_NUM +#undef ACT_Y_STEP_TIME +#undef MEASURE_WAIT + +#undef SXGAIN_LOP +#undef SYGAIN_LOP +#undef LOOP_NUM_HX +#undef LOOP_FREQ_HX +#undef LOOP_GAIN_HX +#undef GAIN_GAP_HX +#undef LOOP_NUM_HY +#undef LOOP_FREQ_HY +#undef LOOP_GAIN_HY +#undef GAIN_GAP_HY +#undef LOOP_MAX_X +#undef LOOP_MIN_X +#undef LOOP_MAX_Y +#undef LOOP_MIN_Y + + +#undef SLT_XY_SWAP +#undef SLT_OFFSET_X +#undef SLT_OFFSET_Y +#undef SLT_DRIVE_X +#undef SLT_DRIVE_Y + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48a93b1c222babbbec0d50d2cc3ef210d951f1b9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_ois/ + +obj-$(CONFIG_SPECTRA_CAMERA) += PhoneUpdate.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/MeasurementLibrary.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/MeasurementLibrary.h new file mode 100755 index 0000000000000000000000000000000000000000..8c9fab7318de5cf4b52a09866366181f92fd105e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/MeasurementLibrary.h @@ -0,0 +1,114 @@ +/** +* @file +* @brief Œv‘ªƒ‰ƒCƒuƒ‰ƒŠ[ Ver 1.0.9.x +*/ +/*============================================================================*/ +#ifndef MEASUREMENT_LIBRARY_H_ +#define MEASUREMENT_LIBRARY_H_ + + +/*----------------------------------------------------------------------*/ +/** +* @brief Mixing coefficientimlCalMixCoefŠÖ”j—p‚Ì“ü—Í’l +*/ +struct tagMlMixingValue +{ + double radianX; + double radianY; + + double hx45x; + double hy45x; + double hy45y; + double hx45y; + + UINT_8 hxsx; + UINT_8 hysx; + + INT_32 hx45xL; //! for Fixed point + INT_32 hy45xL; //! for Fixed point + INT_32 hy45yL; //! for Fixed point + INT_32 hx45yL; //! for Fixed point +}; +/** +* @brief Mixing coefficientimlCalMixCoefŠÖ”j—p‚Ì“ü—Í’l +*/ +typedef struct tagMlMixingValue mlMixingValue; + +/*----------------------------------------------------------------------*/ +/** +* @brief Lineaity correctionimlCalLinearCorrŠÖ”j—p‚Ì“ü—Í’l +*/ +struct tagMlLinearityValue +{ + INT_32 measurecount; //! input parameter + UINT_32 *dacX; //! input parameter + UINT_32 *dacY; //! input parameter + + double *positionX; + double *positionY; + UINT_16 *thresholdX; + UINT_16 *thresholdY; + + UINT_32 *coefAXL; //! for Fixed point + UINT_32 *coefBXL; //! for Fixed point + UINT_32 *coefAYL; //! for Fixed point + UINT_32 *coefBYL; //! for Fixed point +}; +/** +* @brief Linearity correctionimlCalLinearCorrŠÖ”j—p‚Ì“ü—Í’l +*/ +typedef struct tagMlLinearityValue mlLinearityValue; + +struct tagMlPoint +{ + double X; + double Y; +}; +/** +* @brief Linearity correctionimlCalLinearCorrŠÖ”j—p‚Ì“ü—Í’l +*/ +typedef struct tagMlPoint mlPoint; + + +/*----------------------------------------------------------------------*/ +/** +* @brief ƒ‰ƒCƒuƒ‰ƒŠ[ƒGƒ‰[ƒR[ƒh +*/ +enum tagErrorCode +{ + /**! ƒGƒ‰[–³‚µ‚ųíI—¹ */ + ML_OK, + + /**! ƒƒ‚ƒŠ•s‘«“™ƒƒ‚ƒŠ[ŠÖ˜A‚̃Gƒ‰[ */ + ML_MEMORY_ERROR, + /**! ˆø”Žw’è‚̃Gƒ‰[ */ + ML_ARGUMENT_ERROR, + /**! ˆø”‚ÉNULL‚ªŽw—ß‚³‚ê‚Ä‚¢‚éƒGƒ‰[ */ + ML_ARGUMENT_NULL_ERROR, + + /**! Žw’肳‚ꂽƒfƒBƒŒƒNƒgƒŠ‚ª‘¶Ý‚µ‚È‚¢ƒGƒ‰[ */ + ML_DIRECTORY_NOT_EXIST_ERROR, + /**! ‰æ‘œƒtƒ@ƒCƒ‹‚ª‘¶Ý‚µ‚È‚¢ƒGƒ‰[ */ + ML_FILE_NOT_EXIST_ERROR, + /**! ƒtƒ@ƒCƒ‹IOƒGƒ‰[ */ + ML_FILE_IO_ERROR, + /**! –¢ŒŸo‚̃}[ƒN‚ª—L‚è */ + ML_UNDETECTED_MARK_ERROR, + /**! “¯‚¶ˆÊ’u‚ðŽ¦‚·ƒ}[ƒN‚ª‘½dŒŸo‚µ‚½ */ + ML_MULTIPLEX_DETECTION_MARK_ERROR, + /**! •K—v‚ÈDLL‚ªŒ©‚‚©‚ç‚È‚¢‚ȂǎÀs•s‰Â‚Èó‘Ô */ + ML_NOT_EXECUTABLE, + + /**! –¢‰ð͂̉摜‚ª—L‚èƒGƒ‰[ */ + ML_THERE_UNANALYZED_IMAGE_ERROR, + + /**! ã‹LˆÈŠO‚̃Gƒ‰[ */ + ML_ERROR, +}; + +/** +* @brief ƒ‰ƒCƒuƒ‰ƒŠ[ƒGƒ‰[ƒR[ƒh +*/ +typedef enum tagErrorCode mlErrorCode; + +#endif /* #ifndef MEASUREMENT_LIBRARY_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Ois.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Ois.h new file mode 100755 index 0000000000000000000000000000000000000000..4b2f14344697ceb299e4324c10439a4c6c237f78 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/Ois.h @@ -0,0 +1,472 @@ +/** + * @brief OIS system common header for LC898128 + * Defines, Structures, function prototypes + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file Ois.h + * @date svn:$Date:: 2016-06-22 10:57:58 +0900#$ + * @version svn:$Revision: 59 $ + * @attention + **/ +#ifndef OIS_H_ +#define OIS_H_ + +#include <linux/types.h> +#include "cam_sensor_util.h" +#include "cam_debug_util.h" + +#define INT_8 int8_t//char +#define INT_16 int16_t//short +#define INT_32 int32_t//long +#define INT_64 int64_t//long long +#define UINT_8 uint8_t//unsigned char +#define UINT_16 uint16_t//unsigned short +#define UINT_32 uint32_t//unsigned long +#define UINT_64 uint64_t//unsigned long long + + +//#define _BIG_ENDIAN_ + +#include "OisAPI.h" +#include "OisLc898128.h" + +#if 0 + +#ifdef DEBUG +#include <AT91SAM7S.h> +#include <us.h> + #ifndef _CMD_H_ + extern void dbg_printf(const char *, ...); + extern void dbg_Dump(const char *, int); + #endif + #define TRACE(fmt, ...) dbg_printf(fmt, ## __VA_ARGS__) + #define TRACE_DUMP(x,y) dbg_Dump(x,y) +#else + #define TRACE(...) + #define TRACE_DUMP(x,y) +#endif + +#else + +#define DEBUG 1 +#ifdef DEBUG + #define TRACE(fmt, ...) CAM_ERR(CAM_OIS, fmt, ## __VA_ARGS__) + #define TRACE_DUMP(x,y) +#else + #define TRACE(...) + #define TRACE_DUMP(x,y) +#endif + +#endif + +//#define TRNT +//#define WED +/**************** Model name *****************/ +#define SELECT_VENDOR 0x00 // --- select vender ---// + // 0bit : + // 1bit : + // 2bit : + // 3bit : + // 4bit : +/**************** FW version *****************/ + #define FW_VER 0x02 + #define SUB_VER 0x00 // ATMEL SUB Version + +/**************** Select Mode **************/ +#define MODULE_VENDOR 0 + +//#define NEUTRAL_CENTER //!< Upper Position Current 0mA Measurement +//#define NEUTRAL_CENTER_FINE //!< Optimize natural center current +#define SEL_SHIFT_COR //!< Shift correction +#define __OIS_UIOIS_GYRO_USE__ +//#define ACT02_AMP_NARROW +/**************** Filter sampling **************/ +#define FS_MODE 1 // 0 : originally + // 1 : SLOW +#if FS_MODE == 0 +#define FS_FREQ 18044.61942F +#else +#define FS_FREQ 15027.3224F +#endif + +#define GYRO_SENSITIVITY 65.5 //!< Gyro sensitivity LSB/dps + +// Command Status +#define EXE_END 0x00000002L //!< Execute End (Adjust OK) +#define EXE_ERR 0x00000003L //!< Adjust NG : Execution Failure +#define EXE_HXADJ 0x00000006L //!< Adjust NG : X Hall NG (Gain or Offset) +#define EXE_HYADJ 0x0000000AL //!< Adjust NG : Y Hall NG (Gain or Offset) +#define EXE_LXADJ 0x00000012L //!< Adjust NG : X Loop NG (Gain) +#define EXE_LYADJ 0x00000022L //!< Adjust NG : Y Loop NG (Gain) +#define EXE_GXADJ 0x00000042L //!< Adjust NG : X Gyro NG (offset) +#define EXE_GYADJ 0x00000082L //!< Adjust NG : Y Gyro NG (offset) +#ifdef SEL_SHIFT_COR +#define EXE_GZADJ 0x00400002L //!< Adjust NG : Z Gyro NG (offset) +#define EXE_AZADJ 0x00200002L // Adjust NG : Z ACCL NG (offset) +#define EXE_AYADJ 0x00100002L // Adjust NG : Y ACCL NG (offset) +#define EXE_AXADJ 0x00080002L // Adjust NG : X ACCL NG (offset) +#define EXE_XSTRK 0x00040002L // CONFIRM NG : X (offset) +#define EXE_YSTRK 0x00020002L // CONFIRM NG : Y (offset) +#endif //SEL_SHIFT_COR +#define EXE_HXMVER 0x06 +#define EXE_HYMVER 0x0A +#define EXE_GXABOVE 0x06 +#define EXE_GXBELOW 0x0A +#define EXE_GYABOVE 0x12 +#define EXE_GYBELOW 0x22 + + +// Common Define +#define SUCCESS 0x00 //!< Success +#define FAILURE 0x01 //!< Failure + +#ifndef ON + #define ON 0x01 //!< ON + #define OFF 0x00 //!< OFF +#endif + #define SPC 0x02 //!< Special Mode + +#define X_DIR 0x00 //!< X Direction +#define Y_DIR 0x01 //!< Y Direction +#define Z_DIR 0x02 //!< Z Direction(AF) + +struct STFILREG { //!< Register data table + UINT_16 UsRegAdd ; + UINT_8 UcRegDat ; +} ; + +struct STFILRAM { //!< Filter coefficient table + UINT_16 UsRamAdd ; + UINT_32 UlRamDat ; +} ; + +struct STCMDTBL { //!< Command table + UINT_16 Cmd ; + UINT_32 UiCmdStf ; + void ( *UcCmdPtr )( void ) ; +} ; + +/************************************************/ +/* Command */ +/************************************************/ +#define CMD_IO_ADR_ACCESS 0xC000 //!< IO Write Access +#define CMD_IO_DAT_ACCESS 0xD000 //!< IO Read Access +#define CMD_RETURN_TO_CENTER 0xF010 //!< Center Servo ON/OFF choose axis + #define BOTH_SRV_OFF 0x00000000 //!< Both Servo OFF + #define XAXS_SRV_ON 0x00000001 //!< X axis Servo ON + #define YAXS_SRV_ON 0x00000002 //!< Y axis Servo ON + #define BOTH_SRV_ON 0x00000003 //!< Both Servo ON + #define ZAXS_SRV_OFF 0x00000004 //!< Z axis Servo OFF + #define ZAXS_SRV_ON 0x00000005 //!< Z axis Servo ON +#define CMD_PAN_TILT 0xF011 //!< Pan Tilt Enable/Disable + #define PAN_TILT_OFF 0x00000000 //!< Pan/Tilt OFF + #define PAN_TILT_ON 0x00000001 //!< Pan/Tilt ON +#define CMD_OIS_ENABLE 0xF012 //!< Ois Enable/Disable + #define OIS_DISABLE 0x00000000 //!< OIS Disable + #define OIS_DIS_PUS 0x00000008 //!< OIS Disable ( pasue calcuration value ) + #define OIS_ENABLE 0x00000001 //!< OIS Enable + #define OIS_ENA_NCL 0x00000002 //!< OIS Enable ( none Delay clear ) + #define OIS_ENA_DOF 0x00000004 //!< OIS Enable ( Drift offset exec ) +#define CMD_MOVE_STILL_MODE 0xF013 //!< Select mode + #define MOVIE_MODE 0x00000000 //!< Movie mode + #define STILL_MODE 0x00000001 //!< Still mode + #define MOVIE_MODE1 0x00000002 //!< Movie Preview mode 1 + #define STILL_MODE1 0x00000003 //!< Still Preview mode 1 + #define MOVIE_MODE2 0x00000004 //!< Movie Preview mode 2 + #define STILL_MODE2 0x00000005 //!< Still Preview mode 2 + #define MOVIE_MODE3 0x00000006 //!< Movie Preview mode 3 + #define STILL_MODE3 0x00000007 //!< Still Preview mode 3 +#define CMD_CALIBRATION 0xF014 //!< Gyro offset re-calibration +#define CMD_GYROINITIALCOMMAND 0xF015 //!< Select gyro sensor +#define CMD_STANDBY_ENABLE 0xF019 + #define ACTIVE_MODE 0x00000000 //!< Active mode + #define STANDBY_MODE 0x00000001 //!< Standby mode +#define CMD_AF_POSITION 0xF01A // AF Position +#define CMD_SSC_ENABLE 0xF01C //!< Select mode + #define SSC_DISABLE 0x00000000 //!< Ssc Disable + #define SSC_ENABLE 0x00000001 //!< Ssc Enable + +#define CMD_READ_STATUS 0xF100 //!< Status Read + +#define READ_STATUS_INI 0x01000000 + +#define STBOSCPLL 0x00D00074 //!< STB OSC + #define OSC_STB 0x00000002 //!< OSC standby + +// Calibration.h ******************************************************************* +#define HLXO 0x00000001 //!< D/A Converter Channel Select OIS X Offset +#define HLYO 0x00000002 //!< D/A Converter Channel Select OIS Y Offset +#define HLXBO 0x00000008 //!< D/A Converter Channel Select OIS X BIAS +#define HLYBO 0x00000010 //!< D/A Converter Channel Select OIS Y BIAS + +// MeasureFilter.h ******************************************************************* +typedef struct { + INT_32 SiSampleNum ; //!< Measure Sample Number + INT_32 SiSampleMax ; //!< Measure Sample Number Max + + struct { + INT_32 SiMax1 ; //!< Max Measure Result + INT_32 SiMin1 ; //!< Min Measure Result + UINT_32 UiAmp1 ; //!< Amplitude Measure Result + INT_64 LLiIntegral1 ; //!< Integration Measure Result + INT_64 LLiAbsInteg1 ; //!< Absolute Integration Measure Result + INT_32 PiMeasureRam1 ; //!< Measure Delay RAM Address + } MeasureFilterA ; + + struct { + INT_32 SiMax2 ; //!< Max Measure Result + INT_32 SiMin2 ; //!< Min Measure Result + UINT_32 UiAmp2 ; //!< Amplitude Measure Result + INT_64 LLiIntegral2 ; //!< Integration Measure Result + INT_64 LLiAbsInteg2 ; //!< Absolute Integration Measure Result + INT_32 PiMeasureRam2 ; //!< Measure Delay RAM Address + } MeasureFilterB ; +} MeasureFunction_Type ; + + +/*** caution [little-endian] ***/ + +#ifdef _BIG_ENDIAN_ +// Big endian +// Word Data Union +union WRDVAL{ + INT_16 SsWrdVal ; + UINT_16 UsWrdVal ; + UINT_8 UcWrkVal[ 2 ] ; + INT_8 ScWrkVal[ 2 ] ; + struct { + UINT_8 UcHigVal ; + UINT_8 UcLowVal ; + } StWrdVal ; +} ; + + +union DWDVAL { + UINT_32 UlDwdVal ; + UINT_16 UsDwdVal[ 2 ] ; + struct { + UINT_16 UsHigVal ; + UINT_16 UsLowVal ; + } StDwdVal ; + struct { + UINT_8 UcRamVa3 ; + UINT_8 UcRamVa2 ; + UINT_8 UcRamVa1 ; + UINT_8 UcRamVa0 ; + } StCdwVal ; +} ; + +union ULLNVAL { + UINT_64 UllnValue ; + UINT_32 UlnValue[ 2 ] ; + struct { + UINT_32 UlHigVal ; + UINT_32 UlLowVal ; + } StUllnVal ; +} ; + + +// Float Data Union +union FLTVAL { + float SfFltVal ; + UINT_32 UlLngVal ; + UINT_16 UsDwdVal[ 2 ] ; + struct { + UINT_16 UsHigVal ; + UINT_16 UsLowVal ; + } StFltVal ; +} ; + +#else // BIG_ENDDIAN +// Little endian +// Word Data Union +union WRDVAL{ + UINT_16 UsWrdVal ; + UINT_8 UcWrkVal[ 2 ] ; + struct { + UINT_8 UcLowVal ; + UINT_8 UcHigVal ; + } StWrdVal ; +} ; + +typedef union WRDVAL UnWrdVal ; + +union DWDVAL { + UINT_32 UlDwdVal ; + UINT_16 UsDwdVal[ 2 ] ; + struct { + UINT_16 UsLowVal ; + UINT_16 UsHigVal ; + } StDwdVal ; + struct { + UINT_8 UcRamVa0 ; + UINT_8 UcRamVa1 ; + UINT_8 UcRamVa2 ; + UINT_8 UcRamVa3 ; + } StCdwVal ; +} ; + +typedef union DWDVAL UnDwdVal; + +union ULLNVAL { + UINT_64 UllnValue ; + UINT_32 UlnValue[ 2 ] ; + struct { + UINT_32 UlLowVal ; + UINT_32 UlHigVal ; + } StUllnVal ; +} ; + +typedef union ULLNVAL UnllnVal; + + +// Float Data Union +union FLTVAL { + float SfFltVal ; + UINT_32 UlLngVal ; + UINT_16 UsDwdVal[ 2 ] ; + struct { + UINT_16 UsLowVal ; + UINT_16 UsHigVal ; + } StFltVal ; +} ; + +#endif // _BIG_ENDIAN_ +/* +typedef union WRDVAL UnWrdVal ; +typedef union DWDVAL UnDwdVal; +typedef union ULLNVAL UnllnVal; +*/ +typedef union FLTVAL UnFltVal ; + + +typedef struct STADJPAR { + struct { + UINT_32 UlAdjPhs ; //!< Hall Adjust Phase + + UINT_16 UsHlxCna ; //!< Hall Center Value after Hall Adjust + UINT_16 UsHlxMax ; //!< Hall Max Value + UINT_16 UsHlxMxa ; //!< Hall Max Value after Hall Adjust + UINT_16 UsHlxMin ; //!< Hall Min Value + UINT_16 UsHlxMna ; //!< Hall Min Value after Hall Adjust + UINT_16 UsHlxGan ; //!< Hall Gain Value + UINT_16 UsHlxOff ; //!< Hall Offset Value + UINT_16 UsAdxOff ; //!< Hall A/D Offset Value + UINT_16 UsHlxCen ; //!< Hall Center Value + + UINT_16 UsHlyCna ; //!< Hall Center Value after Hall Adjust + UINT_16 UsHlyMax ; //!< Hall Max Value + UINT_16 UsHlyMxa ; //!< Hall Max Value after Hall Adjust + UINT_16 UsHlyMin ; //!< Hall Min Value + UINT_16 UsHlyMna ; //!< Hall Min Value after Hall Adjust + UINT_16 UsHlyGan ; //!< Hall Gain Value + UINT_16 UsHlyOff ; //!< Hall Offset Value + UINT_16 UsAdyOff ; //!< Hall A/D Offset Value + UINT_16 UsHlyCen ; //!< Hall Center Value + + } StHalAdj ; + + struct { + UINT_32 UlLxgVal ; //!< Loop Gain X + UINT_32 UlLygVal ; //!< Loop Gain Y + } StLopGan ; + + struct { + UINT_16 UsGxoVal ; //!< Gyro A/D Offset X + UINT_16 UsGyoVal ; //!< Gyro A/D Offset Y + UINT_16 UsGzoVal ; //!< Gyro A/D Offset Z + } StGvcOff ; +} stAdjPar ; + +__OIS_CMD_HEADER__ stAdjPar StAdjPar ; //!< Calibration data + +typedef struct STHALLINEAR { + UINT_16 XCoefA[6] ; + UINT_16 XCoefB[6] ; + UINT_16 XZone[5] ; + UINT_16 YCoefA[6] ; + UINT_16 YCoefB[6] ; + UINT_16 YZone[5] ; +} stHalLinear ; + +typedef struct STPOSOFF { + struct { + INT_32 Pos[6][3]; + } StPos; + UINT_32 UlAclOfSt ; //!< accel offset status + +} stPosOff ; + +__OIS_CMD_HEADER__ stPosOff StPosOff ; //!< Execute Command Parameter + +typedef struct STACLVAL { + struct { + INT_32 SlOffsetX ; + INT_32 SlOffsetY ; + INT_32 SlOffsetZ ; + } StAccel ; + + INT_32 SlInvMatrix[9] ; + +} stAclVal ; + +__OIS_CMD_HEADER__ stAclVal StAclVal ; //!< Execute Command Parameter + + +// for RtnCen +#define BOTH_ON 0x00 +#define XONLY_ON 0x01 +#define YONLY_ON 0x02 +#define BOTH_OFF 0x03 +#define ZONLY_OFF 0x04 +#define ZONLY_ON 0x05 +// for SetSinWavePara +#define SINEWAVE 0 +#define XHALWAVE 1 +#define YHALWAVE 2 +#define ZHALWAVE 3 +#define XACTTEST 10 +#define YACTTEST 11 +#define CIRCWAVE 255 +// for TnePtp +#define HALL_H_VAL 0x3F800000 //!< 1.0 +// for TneCen +#define OFFDAC_8BIT 0 //!< 8bit Offset DAC select +#define OFFDAC_3BIT 1 //!< 3bit Offset DAC select +#define PTP_BEFORE 0 +#define PTP_AFTER 1 +#define PTP_ACCEPT 2 +// for RunHea +#define ACT_CHK_FRQ 0x0008B8E5 // 4Hz +#define ACT_CHK_NUM 3756 +#define ACT_THR 0x000003E8 +#define ACT_MARGIN 0.75f +// for RunGea +#define GEA_NUM 512 +#define GEA_DIF_HIG 0x0083 +#define GEA_DIF_LOW 0x0001 + +// for RunGea2 +// level of judgement +#define GEA_MAX_LVL 0x0A41 //!< 2030_87.5lsb/‹/s max 30‹/s-p-p +#define GEA_MIN_LVL 0x1482 //!< 2030_87.5lsb/‹/s min 60‹/s-p-p +// mode +#define GEA_MINMAX_MODE 0x00 //!< min, max mode +#define GEA_MEAN_MODE 0x01 //!< mean mode + + +// for Accelerometer offset measurement +#ifdef SEL_SHIFT_COR + +//100mG‚Æ‚·‚é +//#define ZEROG_MRGN_Z (409 << 16) // G tolerance for Z +//#define ZEROG_MRGN_XY (409 << 16) // G tolerance for XY +// XY 250mG , Z 320mG from Huawei +#define ZEROG_MRGN_Z (1310 << 16) // G tolerance for Z +#define ZEROG_MRGN_XY (1024 << 16) // G tolerance for XY + +#define ACCL_SENS 4096 +#endif //SEL_SHIFT_COR + +#endif /* #ifndef OIS_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisAPI.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisAPI.h new file mode 100755 index 0000000000000000000000000000000000000000..40a764dd8d408ff89837dd693847fabbf8ec8e07 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisAPI.h @@ -0,0 +1,264 @@ +/** + * @brief OIS system header for LC898128 + * API List for customers + * + * @author Copyright (C) 2015, ON Semiconductor, all right reserved. + * + * @file OisAPI.h + * @date svn:$Date:: 2016-06-17 16:42:32 +0900#$ + * @version svn:$Revision: 54 $ + * @attention + **/ +#ifndef OISAPI_H_ +#define OISAPI_H_ +#include "MeasurementLibrary.h" + +//**************************************************** +// extern selector for API +//**************************************************** +#ifdef __OISCMD__ + #define __OIS_CMD_HEADER__ +#else + #define __OIS_CMD_HEADER__ extern +#endif + +#ifdef __OISFLSH__ + #define __OIS_FLSH_HEADER__ +#else + #define __OIS_FLSH_HEADER__ extern +#endif + +#ifdef __OISE2PH__ + #define __OIS_E2PR_HEADER__ +#else + #define __OIS_E2PR_HEADER__ extern +#endif +//**************************************************** +// MODE SELECTORS (Compile Switches) +//**************************************************** +#define __OIS_MODULE_CALIBRATION__ //!< for module maker to done the calibration. +//#define __OIS_BIG_ENDIAN__ //!< endian of MPU + +//#define __OIS_CLOSED_AF__ + +//**************************************************** +// STRUCTURE DEFINE +//**************************************************** +typedef struct { + UINT_16 Index; + UINT_8 MasterSlave; // 1: Normal OIS FW, 2: Servo ON FW + UINT_8 FWType; // 1: Normal OIS FW, 2: Servo ON FW + const UINT_8* UpdataCode; + UINT_32 SizeUpdataCode; + UINT_64 SizeUpdataCodeCksm; + const UINT_8* FromCode; + UINT_32 SizeFromCode; + UINT_64 SizeFromCodeCksm; + UINT_32 SizeFromCodeValid; +} DOWNLOAD_TBL_EXT; +typedef struct STRECALIB { + INT_16 SsFctryOffX ; + INT_16 SsFctryOffY ; + INT_16 SsRecalOffX ; + INT_16 SsRecalOffY ; + INT_16 SsDiffX ; + INT_16 SsDiffY ; +} stReCalib ; + +typedef struct STMESRAM { + INT_32 SlMeasureMaxValue ; + INT_32 SlMeasureMinValue ; + INT_32 SlMeasureAmpValue ; + INT_32 SlMeasureAveValue ; +} stMesRam ; // Struct Measure Ram + +typedef struct { + UINT_32 XBiasInit; + UINT_32 YBiasInit; + UINT_32 XOffsetInit; + UINT_32 YOffsetInit; + UINT_32 OffsetMargin; + UINT_32 XTargetRange; + UINT_32 XTargetMax; + UINT_32 XTargetMin; + UINT_32 YTargetRange; + UINT_32 YTargetMax; + UINT_32 YTargetMin; + UINT_32 SinNum; + UINT_32 SinFreq; + UINT_32 XSinGain; + UINT_32 YSinGain; + UINT_32 DecrementStep; + UINT_32 ActMaxDrive_X; + UINT_32 ActMaxDrive_Y; + UINT_32 ActMinDrive_X; + UINT_32 ActMinDrive_Y; + UINT_32 ActStep_X; + UINT_32 ActStep_X_Num; + UINT_32 ActStep_X_time; + UINT_32 ActStep_Y; + UINT_32 ActStep_Y_Num; + UINT_32 ActStep_Y_time; + UINT_32 WaitTime; +} ADJ_HALL; + +typedef struct { + UINT_32 Hxgain; + UINT_32 Hygain; + UINT_32 XNoiseNum; + UINT_32 XNoiseFreq; + UINT_32 XNoiseGain; + UINT_32 XGap; + UINT_32 YNoiseNum; + UINT_32 YNoiseFreq; + UINT_32 YNoiseGain; + UINT_32 YGap; + UINT_32 XJudgeHigh; + UINT_32 XJudgeLow; + UINT_32 YJudgeHigh; + UINT_32 YJudgeLow; +} ADJ_LOPGAN; + +typedef struct { + UINT_8 Vendor; + UINT_8 User; + UINT_8 Model; + UINT_8 Version; + UINT_8 CalbId; + UINT_8 SubVer; + UINT_8 ActType; + UINT_8 GyroType; +} DSPVER; + +typedef struct { + UINT_8 XY_SWAP; + INT_32 STEPX; + INT_32 STEPY; + INT_32 DRIVEX; + INT_32 DRIVEY; +} LINCRS; + +typedef struct STCRSPOINT { + + mlPoint point[7] ; + +} stCrsPoint ; + +typedef struct { + double XonXmove[7]; + double YonXmove[7]; + double XonYmove[7]; + double YonYmove[7]; +} stPixelCoordinate; + +typedef struct { + INT_32 ACTIVE_GG_X_000; + INT_32 ACTIVE_GG_X_090; + INT_32 ACTIVE_GG_X_180; + INT_32 ACTIVE_GG_X_270; + INT_32 ACTIVE_GG_X_UP; + INT_32 ACTIVE_GG_X_DOWN; + INT_32 ACTIVE_GG_Y_000; + INT_32 ACTIVE_GG_Y_090; + INT_32 ACTIVE_GG_Y_180; + INT_32 ACTIVE_GG_Y_270; + INT_32 ACTIVE_GG_Y_UP; + INT_32 ACTIVE_GG_Y_DOWN; +} stAGG; + + +//**************************************************** +// API LIST +//**************************************************** +/* Status Read and OIS enable [mandatory] */ +__OIS_CMD_HEADER__ UINT_8 RdStatus( UINT_8 ) ; //!< Status Read whether initialization finish or not. +__OIS_CMD_HEADER__ void OisEna( void ) ; //!< OIS Enable function +__OIS_CMD_HEADER__ void OisDis( void ) ; //!< OIS Disable function +__OIS_CMD_HEADER__ void OisEnaNCL( void ) ; //!< OIS Enable function w/o delay clear +__OIS_CMD_HEADER__ void OisPause( void ); //!< OIS disable function w/ pause + +/* Others [option] */ +__OIS_CMD_HEADER__ UINT_8 RtnCen( UINT_8 ) ; //!< Return to center function. Hall servo on/off +__OIS_CMD_HEADER__ void OisEnaDrCl( void ) ; //!< OIS Enable function force drift cancel +__OIS_CMD_HEADER__ void OisEnaDrNcl( void ) ; //!< OIS Enable function w/o delay clear and force drift cancel +__OIS_CMD_HEADER__ void SetRec( void ) ; //!< Change to recording mode function +__OIS_CMD_HEADER__ void SetStill( void ) ; //!< Change to still mode function + +__OIS_CMD_HEADER__ void SetStandbyMode( void ); //!< Set Standby mode +__OIS_CMD_HEADER__ void SetActiveMode( void ); //!< Set Active mode + +__OIS_CMD_HEADER__ void SetPanTiltMode( UINT_8 ) ; //!< Pan/Tilt control (default ON) +//__OIS_CMD_HEADER__ void RdHallCalData( void ) ; //!< Read Hall Calibration Data in Data Ram + +__OIS_CMD_HEADER__ UINT_8 RunHea( void ) ; //!< Hall Examination of Acceptance +__OIS_CMD_HEADER__ UINT_8 RunGea( void ) ; //!< Gyro Examination of Acceptance +//__OIS_CMD_HEADER__ UINT_8 RunGea2( UINT_8 ) ; //!< Gyro Examination of Acceptance + + +__OIS_CMD_HEADER__ void OscStb( void ); //!< Standby the oscillator +//__OIS_CMD_HEADER__ UINT_8 GyroReCalib( stReCalib * ) ; //!< Gyro offset re-calibration +__OIS_CMD_HEADER__ UINT_32 ReadCalibID( void ) ; //!< Read calibration ID +//__OIS_CMD_HEADER__ UINT_16 GyrSlf( void ) ; //!< Gyro self test + +__OIS_CMD_HEADER__ UINT_8 GyrWhoAmIRead( void ) ; //!< Gyro Who am I Read +__OIS_CMD_HEADER__ UINT_8 GyrWhoAmICheck( void ) ; //!< Gyro Who am I Check +__OIS_CMD_HEADER__ UINT_8 GyrIdRead( UINT_8 * ) ; //!< Gyro ID Read + +__OIS_CMD_HEADER__ UINT_8 MesRam( INT_32 , INT_32 , INT_32 , stMesRam* , stMesRam* ); + +#ifdef __OIS_MODULE_CALIBRATION__ + + /* Calibration Main [mandatory] */ + __OIS_CMD_HEADER__ UINT_32 TneRun( void ); //!< calibration for bi-direction AF + + __OIS_CMD_HEADER__ void TneSltPos( UINT_8 ) ; //!< for NVC + __OIS_CMD_HEADER__ void TneVrtPos( UINT_8 ) ; //!< for CROSS TALK + __OIS_CMD_HEADER__ void TneHrzPos( UINT_8 ) ; //!< for CROSS TALK + __OIS_CMD_HEADER__ UINT_32 TneAvc( UINT_8 ) ; //!< calibration for 6 axis offset + __OIS_CMD_HEADER__ UINT_8 FrqDet( void ) ; //!< oscillation detect + + __OIS_CMD_HEADER__ UINT_8 WrHallCalData( UINT_8 UcMode ); + __OIS_CMD_HEADER__ UINT_8 WrGyroGainData( UINT_8 ) ; //!< upload the gyro gain to Flash + __OIS_CMD_HEADER__ UINT_8 WrMixingData( void ) ; //!< Flash Write Mixing Data Function + __OIS_CMD_HEADER__ UINT_8 WrMixCalData( UINT_8, mlMixingValue * ) ; + __OIS_CMD_HEADER__ UINT_8 WrGyroOffsetData( void ) ; + + #ifdef HF_LINEAR_ENA +// __OIS_CMD_HEADER__ void SetHalLnData( UINT_16 * ); +// __OIS_CMD_HEADER__ INT_16 WrHalLnData( UINT_8 ); + #endif // HF_LINEAR_ENA + + #ifdef HF_MIXING_ENA + __OIS_CMD_HEADER__ INT_8 WrMixCalData( UINT_8, mlMixingValue * ) ;//!< upload the mixing coefficient to Flash + #endif // HF_MIXING_ENA + __OIS_CMD_HEADER__ UINT_8 WrAclOffsetData( void ) ; //!< accelerator offset and matrix to Flash + + __OIS_CMD_HEADER__ UINT_8 WrLinCalData( UINT_8, mlLinearityValue * ) ; + __OIS_CMD_HEADER__ UINT_8 WrLinMixCalData( UINT_8, mlMixingValue *, mlLinearityValue * ) ; + __OIS_CMD_HEADER__ UINT_32 MeasGain ( UINT_16 , UINT_16 , UINT_32 ); + __OIS_CMD_HEADER__ UINT_8 WrLinMix2ndCalData( UINT_8 , mlMixingValue * , mlLinearityValue * , stCrsPoint * ); + + __OIS_FLSH_HEADER__ UINT_8 CalcSetLinMix2ndData( UINT_8, stPixelCoordinate * ); + __OIS_FLSH_HEADER__ UINT_8 RotationCorrectCalData( UINT_8 , double ); + __OIS_FLSH_HEADER__ UINT_8 AGGCorrectCalData( UINT_8 , stAGG * ); + + __OIS_FLSH_HEADER__ UINT_8 WrOptCenerData( UINT_8 ); + + __OIS_CMD_HEADER__ UINT_8 SetAngleCorrection( float , UINT_8 , UINT_8 ); + + /* Flash Update */ + __OIS_FLSH_HEADER__ UINT_8 UnlockCodeSet( void ) ; //!< <Flash Memory> Unlock Code Set + __OIS_FLSH_HEADER__ UINT_8 UnlockCodeClear(void) ; //!< <Flash Memory> Clear Unlock Code + + __OIS_FLSH_HEADER__ UINT_8 FlashBlockErase( UINT_8 , UINT_32 ) ; + + + __OIS_FLSH_HEADER__ UINT_8 FlashUpdate128( DOWNLOAD_TBL_EXT * ); +//#ifdef TRNT + __OIS_FLSH_HEADER__ UINT_8 LoadUareToPM( DOWNLOAD_TBL_EXT * , UINT_8 ); +//#endif + __OIS_FLSH_HEADER__ UINT_8 Mat2ReWrite( void ); + +#endif // __OIS_MODULE_CALIBRATION__ + +#endif /* #ifndef OISAPI_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisCmd.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisCmd.c new file mode 100755 index 0000000000000000000000000000000000000000..98a7232de37edb41d421eba73827e2627b6800f1 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisCmd.c @@ -0,0 +1,3489 @@ +/** + * @brief OIS system command for LC898128 + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file OisCmd.c + * @date svn:$Date:: 2016-06-22 10:57:58 +0900#$ + * @version svn:$Revision: 59 $ + * @attention + **/ + +//************************** +// Include Header File +//************************** +#define __OISCMD__ + +//#include <stdlib.h> /* use for abs() */ +//#include <math.h> /* use for sqrt() */ +#include <linux/kernel.h> +#include "Ois.h" + +#define SEL_MODEL 0 + +//**************************************************** +// MODE SELECTORS (Compile Switches) +//**************************************************** +//#define NEUTRAL_CENTER // Upper Position Current 0mA Measurement +//#define NEUTRAL_CENTER_FINE // Optimize natural center current +//#define HALL_ADJ_SERVO_ON // +//#define HALLADJ_FULLCURRENT +#define HALLADJ_NON_SINWAVE +#define LOOPGAIN_FIX_VALUE + +//**************************************************** +// LC898128 calibration parameters +//**************************************************** +#include "LC898128_Calibration_ACT01.h" +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A(INT_32 addr, INT_32 data); +extern void RamRead32A( UINT_16 addr, void * data ); +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( UINT_16 ); + + +//************************** +// extern Function LIST +//************************** +UINT_32 UlBufDat[ 64 ] ; //!< Calibration data write buffer(256 bytes) + +//************************** +// Local Function Prototype +//************************** +void IniCmd( void ) ; //!< Command Execute Process Initial +void IniPtAve( void ) ; //!< Average setting +void MesFil( UINT_8 ) ; //!< Measure Filter Setting +void MeasureStart( INT_32 , INT_32 , INT_32 ) ; //!< Measure Start Function +void MeasureStart2( INT_32 , INT_32 , INT_32 , UINT_16 ); //!< Measure Start 2 Function +void MeasureWait( void ) ; //!< Measure Wait +void MemoryClear( UINT_16 , UINT_16 ) ; //!< Memory Cloear +void SetWaitTime( UINT_16 ) ; //!< Set Wait Timer + +void TneOff( UnDwdVal, UINT_8 ) ; //!< Hall Offset Tuning +void TneBia( UnDwdVal StTneVal, UINT_8 UcTneAxs, UINT_16 UsHalAdjRange ) ; //!< Hall Bias Tuning +UINT_32 TnePtp ( UINT_8 UcDirSel, UINT_8 UcBfrAft, ADJ_HALL* p ); +UINT_32 TneCen( UINT_8 UcTneAxs, ADJ_HALL* ptr ); +UINT_32 LopGan( UINT_8 UcDirSel, ADJ_LOPGAN* ptr ); +UINT_32 TneGvc( UINT_8 uc_mode ); +UINT_8 TneHvc( void ); +void DacControl( UINT_8 UcMode, UINT_32 UiChannel, UINT_32 PuiData ); +void MeasAddressSelection( UINT_8 mode , INT_32 * measadr_a , INT_32 * measadr_b ); +UINT_32 MeasGyAcOffset( void ); + +#ifdef NEUTRAL_CENTER_FINE +void TneFin( ADJ_LOPGAN* ptr ) ; //!< Fine tune for natural center offset +#endif // NEUTRAL_CENTER_FINE + +void RdHallCalData( void ) ; +void SetSinWavePara( UINT_8 , UINT_8 ) ; //!< Sin wave test function +void SetSineWave( UINT_8 , UINT_8 ); +void SetSinWavGenInt( void ); +void SetTransDataAdr( UINT_16 , UINT_32 ) ; //!< Hall VC Offset Adjust +//void GetDir( UINT_8 *outX, UINT_8 *outY ) ; +void MesFil2( UINT_16 UsMesFreq ); +UINT_8 GetInfomationAfterStartUp( DSPVER* Info ); +void SetGyroCoef( UINT_8 ); +void SetAccelCoef( UINT_8 ); + + +//************************** +// define +//************************** +#define HALL_ADJ 0 +#define LOOPGAIN 1 +#define THROUGH 2 +#define NOISE 3 +#define OSCCHK 4 +#define GAINCURV 5 +#define SELFTEST 6 +#define LOOPGAIN2 7 + +// Measure Mode +#define PTP_BEFORE 0 +#define PTP_AFTER 1 + + #define TNE 80 //!< Waiting Time For Movement + #define OFFSET_DIV 2 //!< Divide Difference For Offset Step + #define TIME_OUT 40 //!< Time Out Count + + #define BIAS_HLMT (UINT_32)0xBF000000 + #define BIAS_LLMT (UINT_32)0x20000000 + +/************** posture check ************/ +#define SENSITIVITY 4096 // LSB/g +#define PSENS_MARG (4096 / 4) // 1/4g +#define POSTURETH_P (SENSITIVITY - PSENS_MARG) // LSB/g +/************** posture check ************/ + +// Threshold of osciration amplitude +#define ULTHDVAL 0x01000000 // Threshold of the hale value + +//************************** +// Global Variable +//************************** +INT_16 SsNvcX = 1 ; // NVC move direction X +INT_16 SsNvcY = 1 ; // NVC move direction Y +UINT_8 BeforeControl; + +//************************** +// Const +//************************** + +//******************************************************************************** +// Function Name : MemClr +// Retun Value : void +// Argment Value : Clear Target PoINT_32er, Clear Byte Number +// Explanation : Memory Clear Function +// History : First edition +//******************************************************************************** +void MemClr( UINT_8 *NcTgtPtr, UINT_16 UsClrSiz ) +{ + UINT_16 UsClrIdx ; + + for ( UsClrIdx = 0 ; UsClrIdx < UsClrSiz ; UsClrIdx++ ) + { + *NcTgtPtr = 0 ; + NcTgtPtr++ ; + } +} + +//******************************************************************************** +// Function Name : HallAdj +// Retun Value : Hall Tuning SUCCESS or FAILURE +// Argment Value : NON +// Explanation : Hall System Auto Adjustment Function +// History : First edition +//******************************************************************************** +UINT_32 HallAdj( ADJ_HALL* Ptr , ADJ_LOPGAN* LpPtr ) +{ + UINT_32 UlHlxSts, UlHlySts, UlReadVal; + + RtnCen( BOTH_OFF ) ; // Both OFF + WitTim( TNE ) ; + RamWrite32A( HALL_RAM_HXOFF, 0x00000000 ) ; // X Offset Clr + RamWrite32A( HALL_RAM_HYOFF, 0x00000000 ) ; // Y Offset Clr + RamWrite32A( HallFilterCoeffX_hxgain0 , LpPtr->Hxgain ) ; + RamWrite32A( HallFilterCoeffY_hygain0 , LpPtr->Hygain ) ; + + DacControl( 0, HLXBO , Ptr->XBiasInit ) ; + RamWrite32A( StCaliData_UiHallBias_X , Ptr->XBiasInit ) ; + DacControl( 0, HLYBO , Ptr->YBiasInit ) ; + RamWrite32A( StCaliData_UiHallBias_Y , Ptr->YBiasInit ) ; + DacControl( 0, HLXO, Ptr->XOffsetInit ) ; + RamWrite32A( StCaliData_UiHallOffset_X , Ptr->XOffsetInit ) ; + DacControl( 0, HLYO, Ptr->YOffsetInit ) ; + RamWrite32A( StCaliData_UiHallOffset_Y , Ptr->YOffsetInit ) ; + + BeforeControl=1; + UlHlySts = TneCen( Y_DIR, Ptr ) ; + StAdjPar.StHalAdj.UsAdyOff = StAdjPar.StHalAdj.UsHlyCna ; + RamWrite32A( HALL_RAM_HYOFF, (UINT_32)((StAdjPar.StHalAdj.UsAdyOff << 16 ) & 0xFFFF0000 )) ; + RtnCen( YONLY_ON ) ; // Y Servo ON +#if 0 + // Recovery + if( UlHlySts == EXE_HXADJ){ + Ptr->ActMaxDrive_X = 0x7FFFFFFF; + Ptr->ActMinDrive_X = 0x80000000; + } +#endif + WitTim( TNE ) ; + BeforeControl=1; + UlHlxSts = TneCen( X_DIR, Ptr ) ; + StAdjPar.StHalAdj.UsAdxOff = StAdjPar.StHalAdj.UsHlxCna ; + RamWrite32A( HALL_RAM_HXOFF, (UINT_32)((StAdjPar.StHalAdj.UsAdxOff << 16 ) & 0xFFFF0000 )) ; + RtnCen( XONLY_ON ) ; // X Servo ON +#if 0 + // Recovery + if( UlHlxSts == EXE_HXADJ){ + Ptr->ActMaxDrive_X = 0x7FFFFFFF; + Ptr->ActMinDrive_X = 0x80000000; + } +#endif + WitTim( TNE ) ; + UlHlySts = TneCen( Y_DIR, Ptr ) ; + StAdjPar.StHalAdj.UsAdyOff = StAdjPar.StHalAdj.UsHlyCna ; + RamWrite32A( HALL_RAM_HYOFF, (UINT_32)((StAdjPar.StHalAdj.UsAdyOff << 16 ) & 0xFFFF0000 )) ; + RtnCen( YONLY_ON ) ; // Y Servo ON + + WitTim( TNE ) ; + UlHlxSts = TneCen( X_DIR, Ptr ) ; + StAdjPar.StHalAdj.UsAdxOff = StAdjPar.StHalAdj.UsHlxCna ; + RamWrite32A( HALL_RAM_HXOFF, (UINT_32)((StAdjPar.StHalAdj.UsAdxOff << 16 ) & 0xFFFF0000 )) ; + + if( ( UlHlySts | UlHlxSts ) == EXE_END ){ + RtnCen( BOTH_ON ) ; // Both Servo ON + } + else{ + RtnCen( BOTH_OFF ) ; // Both OFF + } + + WitTim( TNE ) ; + + RamRead32A( StCaliData_UiHallOffset_X , &UlReadVal ) ; + StAdjPar.StHalAdj.UsHlxOff = (UINT_16)( UlReadVal >> 16 ) ; + + RamRead32A( StCaliData_UiHallBias_X , &UlReadVal ) ; + StAdjPar.StHalAdj.UsHlxGan = (UINT_16)( UlReadVal >> 16 ) ; + + RamRead32A( StCaliData_UiHallOffset_Y , &UlReadVal ) ; + StAdjPar.StHalAdj.UsHlyOff = (UINT_16)( UlReadVal >> 16 ) ; + + RamRead32A( StCaliData_UiHallBias_Y , &UlReadVal ) ; + StAdjPar.StHalAdj.UsHlyGan = (UINT_16)( UlReadVal >> 16 ) ; +#ifdef NEUTRAL_CENTER + RtnCen( BOTH_OFF ) ; // Both OFF + WitTim( TNE ) ; +#else +#endif + return ( UlHlySts | UlHlxSts ); +} + + +//******************************************************************************** +// Function Name : TneRun +// Retun Value : Hall Tuning SUCCESS or FAILURE +// Argment Value : NON +// Explanation : Hall System Auto Adjustment Function +// History : First edition +//******************************************************************************** +UINT_32 TneRun( void ) +{ + UINT_32 UlFinSts, UlReadVal; + ADJ_HALL* HallPtr; + ADJ_LOPGAN* LopgainPtr; + DSPVER Info; + + // Check the status + RamWrite32A( CMD_IO_ADR_ACCESS , ROMINFO ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + if( UlReadVal != 0x0A) return( EXE_ERR ); // + + // Select parameter + if( GetInfomationAfterStartUp( &Info ) != 0) return( EXE_ERR ); + else if( Info.ActType == 0x01 ) { + HallPtr = (ADJ_HALL*)&ACT01_HallCalParameter; + LopgainPtr = (ADJ_LOPGAN* )&ACT01_LoopGainParameter; + } + else{ + return( EXE_ERR ); + } + // F015 Command Check + if(Info.GyroType == 0xFF) return( EXE_ERR ); + + /* Hall Adjustment */ + UlFinSts = HallAdj( HallPtr , LopgainPtr); + if( ((UlFinSts & EXE_HXADJ) == EXE_HXADJ) || ((UlFinSts & EXE_HYADJ) == EXE_HYADJ) ) return ( UlFinSts ); + + /* Hall Offser (neutral center)*/ +#ifdef NEUTRAL_CENTER + TneHvc(); + #ifdef NEUTRAL_CENTER_FINE + TneFin( LopgainPtr ); + #endif + + RamWrite32A( HallFilterCoeffX_hxgain0 , LopgainPtr->Hxgain ) ; + RamWrite32A( HallFilterCoeffY_hygain0 , LopgainPtr->Hygain ) ; + RtnCen( BOTH_ON ) ; // Y ON / X ON + WitTim( TNE ) ; +#endif + + /* Loop gain Adjustment */ + + UlFinSts |= LopGan( Y_DIR, LopgainPtr ) ; // Y Loop Gain Adjust + UlFinSts |= LopGan( X_DIR, LopgainPtr ) ; // X Loop Gain Adjust + + /* Gyro DC offset Adjustment */ +#ifdef __OIS_UIOIS_GYRO_USE__ +#else + UlFinSts |= TneGvc(0) ; +#ifdef SEL_SHIFT_COR + UlFinSts |= TneGvc(1) ; + UlFinSts |= TneAvc(0x10); +// UlFinSts |= TneAvc(0x11); + if( (UlFinSts & (EXE_AXADJ | EXE_AYADJ | EXE_AZADJ)) == EXE_END ){ + TneAvc(0x80); + } +#endif //SEL_SHIFT_COR +#endif + + /* confirmation of hall stroke */ + StAdjPar.StHalAdj.UlAdjPhs = UlFinSts ; + return( UlFinSts ) ; +} + + +//******************************************************************************** +// Function Name : TnePtp +// Retun Value : Hall Top & Bottom Gaps +// Argment Value : X,Y Direction, Adjust Before After Parameter +// Explanation : Measuring Hall Paek To Peak +// History : First edition +//******************************************************************************** +UINT_32 TnePtp ( UINT_8 UcDirSel, UINT_8 UcBfrAft, ADJ_HALL* p ) +{ +#ifdef HALLADJ_NON_SINWAVE + + UnDwdVal StTneVal ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + INT_32 SlMeasureMaxValue, SlMeasureMinValue ; + UINT_16 us_outaddress ; + INT_32 sl_act_min_drv, sl_act_max_drv ; + +TRACE("TnePtp\n ") ; + + MesFil( THROUGH ) ; // Filter setting for measurement + + if( UcDirSel == X_DIR ) { // X axis + SlMeasureParameterA = HALL_RAM_HXIDAT ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HYIDAT ; // Set Measure RAM Address + us_outaddress = HALL_RAM_SINDX1 ; + sl_act_max_drv = p->ActMinDrive_X ; + sl_act_min_drv = p->ActMaxDrive_X ; + } else if( UcDirSel == Y_DIR ) { // Y axis + SlMeasureParameterA = HALL_RAM_HYIDAT ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HXIDAT ; // Set Measure RAM Address + us_outaddress = HALL_RAM_SINDY1 ; + sl_act_max_drv = p->ActMinDrive_Y ; + sl_act_min_drv = p->ActMaxDrive_Y ; + } + + SlMeasureParameterNum = 2000 ; + + RamWrite32A( us_outaddress, sl_act_min_drv ) ; + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_SiMin1 , ( unsigned long * )&SlMeasureMinValue ) ; // Min value + + RamWrite32A( us_outaddress, sl_act_max_drv ) ; + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_SiMax1 , ( unsigned long * )&SlMeasureMaxValue ) ; // Max value + + StTneVal.StDwdVal.UsHigVal = (unsigned short)((SlMeasureMaxValue >> 16) & 0x0000FFFF ); + StTneVal.StDwdVal.UsLowVal = (unsigned short)((SlMeasureMinValue >> 16) & 0x0000FFFF ); + + RamWrite32A( us_outaddress, 0 ) ; + +#else // HALLADJ_NON_SINWAVE + + UnDwdVal StTneVal ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureMaxValue , SlMeasureMinValue ; + UINT_16 UsSinAdr ; + + INT_32 sl_act_min_drv, sl_act_max_drv; + INT_32 sl_act_num, sl_act_step, sl_act_wait, i ; + +TRACE("TnePtp\n") ; + + SetSinWavGenInt(); + SetTransDataAdr( SinWave_OutAddr , SinWave_Output ) ; // o—ÍæƒAƒhƒŒƒX + SetTransDataAdr( CosWave_OutAddr , CosWave_OutAddr ); // o—ÍæƒAƒhƒŒƒX + + if( UcDirSel == X_DIR ) { // X axis + SlMeasureParameterA = HALL_RAM_HXIDAT ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HYIDAT ; // Set Measure RAM Address + sl_act_max_drv = (INT_32)(p->ActMinDrive_X) ; + sl_act_min_drv = (INT_32)(p->ActMaxDrive_X) ; + sl_act_num = (INT_32)(p->ActStep_X_Num); + sl_act_step = (INT_32)((p->ActStep_X)*(-1)); + sl_act_wait = (INT_32)(p->ActStep_X_time); + UsSinAdr = HALL_RAM_SINDX1; + + } else if( UcDirSel == Y_DIR ) { // Y axis + SlMeasureParameterA = HALL_RAM_HYIDAT ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HXIDAT ; // Set Measure RAM Address + sl_act_max_drv = (INT_32)(p->ActMinDrive_Y) ; + sl_act_min_drv = (INT_32)(p->ActMaxDrive_Y) ; + sl_act_num = (INT_32)(p->ActStep_Y_Num); + sl_act_step = (INT_32)((p->ActStep_Y)*(-1)); + sl_act_wait = (INT_32)(p->ActStep_Y_time); + UsSinAdr = HALL_RAM_SINDY1; + + } + + MesFil( THROUGH ) ; // Filter setting for measurement + + for( i=0 ; i <= sl_act_num; i++ ){ + RamWrite32A( UsSinAdr, (sl_act_min_drv + ((sl_act_step) * (sl_act_num - i))) ); + WitTim(sl_act_wait); +TRACE("Min:%08x-", (sl_act_min_drv + ((sl_act_step) * (sl_act_num - i))) ); + } + + WitTim( p->WaitTime ); + MeasureStart( p->SinNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_SiMin1 , ( UINT_32 * )&SlMeasureMinValue ) ; // Min value + + RamWrite32A( UsSinAdr , 0x00000000 ) ; // DelayRam Clear +TRACE("Min:0x00000000\n"); + + for( i=0 ; i <= sl_act_num; i++ ){ + RamWrite32A( UsSinAdr, (sl_act_max_drv - ((sl_act_step) * (sl_act_num -i))) ); + WitTim(sl_act_wait); +TRACE("Max:%08x-", (sl_act_max_drv - ((sl_act_step) * (sl_act_num -i))) ); + } + + WitTim( p->WaitTime ); + MeasureStart( p->SinNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_SiMin1 , ( UINT_32 * )&SlMeasureMaxValue ) ; // Min value + + RamWrite32A( UsSinAdr , 0x00000000 ) ; // DelayRam Clear +TRACE("Max:0x00000000\n"); + + + StTneVal.StDwdVal.UsHigVal = (UINT_16)((SlMeasureMaxValue >> 16) & 0x0000FFFF ); + StTneVal.StDwdVal.UsLowVal = (UINT_16)((SlMeasureMinValue >> 16) & 0x0000FFFF ); + +#endif // HALLADJ_NON_SINWAVE + + if( UcBfrAft == 0 ) { + if( UcDirSel == X_DIR ) { + StAdjPar.StHalAdj.UsHlxCen = ( ( INT_16 )StTneVal.StDwdVal.UsHigVal + ( INT_16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar.StHalAdj.UsHlxMax = StTneVal.StDwdVal.UsHigVal ; + StAdjPar.StHalAdj.UsHlxMin = StTneVal.StDwdVal.UsLowVal ; + } else if( UcDirSel == Y_DIR ){ + StAdjPar.StHalAdj.UsHlyCen = ( ( INT_16 )StTneVal.StDwdVal.UsHigVal + ( INT_16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar.StHalAdj.UsHlyMax = StTneVal.StDwdVal.UsHigVal ; + StAdjPar.StHalAdj.UsHlyMin = StTneVal.StDwdVal.UsLowVal ; + } + } else { + if( UcDirSel == X_DIR ){ + StAdjPar.StHalAdj.UsHlxCna = ( ( INT_16 )StTneVal.StDwdVal.UsHigVal + ( INT_16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar.StHalAdj.UsHlxMxa = StTneVal.StDwdVal.UsHigVal ; + StAdjPar.StHalAdj.UsHlxMna = StTneVal.StDwdVal.UsLowVal ; + } else if( UcDirSel == Y_DIR ){ + StAdjPar.StHalAdj.UsHlyCna = ( ( INT_16 )StTneVal.StDwdVal.UsHigVal + ( INT_16 )StTneVal.StDwdVal.UsLowVal ) / 2 ; + StAdjPar.StHalAdj.UsHlyMxa = StTneVal.StDwdVal.UsHigVal ; + StAdjPar.StHalAdj.UsHlyMna = StTneVal.StDwdVal.UsLowVal ; + } + } + +TRACE(" ADJ(%d) MAX = %04x, MIN = %04x, CNT = %04x, ", UcDirSel, StTneVal.StDwdVal.UsHigVal, StTneVal.StDwdVal.UsLowVal, ( ( signed int )StTneVal.StDwdVal.UsHigVal + ( signed int )StTneVal.StDwdVal.UsLowVal ) / 2 ) ; + StTneVal.StDwdVal.UsHigVal = 0x7fff - StTneVal.StDwdVal.UsHigVal ; // Maximum Gap = Maximum - Hall Peak Top + StTneVal.StDwdVal.UsLowVal = StTneVal.StDwdVal.UsLowVal - 0x8000 ; // Minimum Gap = Hall Peak Bottom - Minimum + +TRACE(" GapH = %04x, GapL = %04x\n", StTneVal.StDwdVal.UsHigVal, StTneVal.StDwdVal.UsLowVal ) ; +TRACE(" Raw MAX = %08x, MIN = %08x\n", (unsigned int)SlMeasureMaxValue , (unsigned int)SlMeasureMinValue ) ; + + return( StTneVal.UlDwdVal ) ; +} + +//******************************************************************************** +// Function Name : TneCen +// Retun Value : Hall Center Tuning Result +// Argment Value : X,Y Direction, Hall Top & Bottom Gaps +// Explanation : Hall Center Tuning Function +// History : First edition +//******************************************************************************** +UINT_32 TneCen( UINT_8 UcTneAxs, ADJ_HALL* ptr ) +{ + UnDwdVal StTneVal ; + UINT_8 UcTmeOut =1, UcTofRst= FAILURE ; + UINT_16 UsBiasVal ; + UINT_32 UlTneRst = FAILURE, UlBiasVal , UlValNow ; + UINT_16 UsValBef,UsValNow ; + UINT_32 UlBiaBef,UlBiaNow ; + UINT_16 UsTargetMax, UsTargetMin; + UINT_16 UsTargetRange; + + if (BeforeControl != 0) StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_BEFORE, ptr ) ; + else StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_AFTER , ptr ) ; + BeforeControl=0; + + TneOff( StTneVal, UcTneAxs ) ; + UcTofRst = SUCCESS ; /* Žb’è‚ÅOK‚É‚·‚é */ + + while ( UlTneRst && (UINT_32)UcTmeOut ) + { + if( UcTofRst == FAILURE ) { +TRACE(" UcTofRst == FAILURE\n" ) ; + TneOff( StTneVal, UcTneAxs ) ; + StTneVal.UlDwdVal = TnePtp( UcTneAxs, PTP_AFTER, ptr ) ; + } else { +TRACE(" else\n" ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiaBef ) ; + UsTargetRange = (UINT_16)ptr->XTargetRange; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlBiaBef ) ; + UsTargetRange = (UINT_16)ptr->YTargetRange; + } + TneBia( StTneVal, UcTneAxs, UsTargetRange ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiaNow ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlBiaNow ) ; + } + if((( UlBiaBef == BIAS_HLMT ) && ( UlBiaNow == BIAS_HLMT )) + || (( UlBiaBef == BIAS_LLMT ) && ( UlBiaNow == BIAS_LLMT ))){ + UcTmeOut += 10; +TRACE(" No = %04d (bias count up)\n", UcTmeOut ) ; + } + StTneVal.UlDwdVal = TnePtp( UcTneAxs , PTP_AFTER, ptr ) ; + + UcTofRst = FAILURE ; +// if( UcTneAxs == X_DIR ) { +// RamRead32A( StCaliData_UiHallBias_X , &UlBiasVal ) ; +// }else if( UcTneAxs == Y_DIR ){ +// RamRead32A( StCaliData_UiHallBias_Y , &UlBiasVal ) ; +// } +// if(UlBiasVal == 0x00000000){ +// UcTmeOut = TIME_OUT; +// } + } + + if( (StTneVal.StDwdVal.UsHigVal > ptr->OffsetMargin ) && (StTneVal.StDwdVal.UsLowVal > ptr->OffsetMargin ) ) /* position check */ + { + UcTofRst = SUCCESS ; +TRACE(" TofR = SUCC\n" ) ; + UsValBef = UsValNow = 0x0000 ; + }else if( (StTneVal.StDwdVal.UsHigVal <= ptr->OffsetMargin ) && (StTneVal.StDwdVal.UsLowVal <= ptr->OffsetMargin ) ){ + UcTofRst = SUCCESS ; + UlTneRst = (UINT_32)FAILURE ; + }else{ + UcTofRst = FAILURE ; +TRACE(" TofR = FAIL\n" ) ; + + UsValBef = UsValNow ; + + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallOffset_X , &UlValNow ) ; + UsValNow = (UINT_16)( UlValNow >> 16 ) ; + }else if( UcTneAxs == Y_DIR ){ + RamRead32A( StCaliData_UiHallOffset_Y , &UlValNow ) ; + UsValNow = (UINT_16)( UlValNow >> 16 ) ; + } + if( ((( UsValBef & 0xFF00 ) == 0x1000 ) && ( UsValNow & 0xFF00 ) == 0x1000 ) + || ((( UsValBef & 0xFF00 ) == 0xEF00 ) && ( UsValNow & 0xFF00 ) == 0xEF00 ) ) + { + UcTmeOut += 10; +TRACE(" No = %04d (offset count up)\n", UcTmeOut ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlBiasVal ) ; + UsBiasVal = (UINT_16)( UlBiasVal >> 16 ) ; + }else if( UcTneAxs == Y_DIR ){ + RamRead32A( StCaliData_UiHallBias_Y , &UlBiasVal ) ; + UsBiasVal = (UINT_16)( UlBiasVal >> 16 ) ; + } + + if( UsBiasVal > ptr->DecrementStep ) + { + UsBiasVal -= ptr->DecrementStep ; + } + + if( UcTneAxs == X_DIR ) { + UlBiasVal = ( UINT_32 )( UsBiasVal << 16 ) ; + DacControl( 0, HLXBO , UlBiasVal ) ; + RamWrite32A( StCaliData_UiHallBias_X , UlBiasVal ) ; + }else if( UcTneAxs == Y_DIR ){ + UlBiasVal = ( UINT_32 )( UsBiasVal << 16 ) ; + DacControl( 0, HLYBO , UlBiasVal ) ; + RamWrite32A( StCaliData_UiHallBias_Y , UlBiasVal ) ; + } + } + + } + if(UcTneAxs == X_DIR){ + UsTargetMax = (UINT_16)ptr->XTargetMax ; + UsTargetMin = (UINT_16)ptr->XTargetMin ; + }else{ + UsTargetMax = (UINT_16)ptr->YTargetMax ; + UsTargetMin = (UINT_16)ptr->YTargetMin ; + } + + if((( (UINT_16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) < UsTargetMax ) + && (( (UINT_16)0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) > UsTargetMin ) ) { + if(UcTofRst == SUCCESS) + { + UlTneRst = (UINT_32)SUCCESS ; + break ; + } + } + UlTneRst = (UINT_32)FAILURE ; + UcTmeOut++ ; +TRACE(" Tne = FAIL\n" ) ; + +TRACE(" No = %04d", UcTmeOut ) ; + if ( UcTmeOut >= TIME_OUT ) { + UcTmeOut = 0 ; + } // Set Time Out Count + } + + SetSinWavGenInt() ; // + + if( UlTneRst == (UINT_32)FAILURE ) { + if( UcTneAxs == X_DIR ) { + UlTneRst = EXE_HXADJ ; + StAdjPar.StHalAdj.UsHlxGan = 0xFFFF ; + StAdjPar.StHalAdj.UsHlxOff = 0xFFFF ; + }else if( UcTneAxs == Y_DIR ) { + UlTneRst = EXE_HYADJ ; + StAdjPar.StHalAdj.UsHlyGan = 0xFFFF ; + StAdjPar.StHalAdj.UsHlyOff = 0xFFFF ; + } + } else { + UlTneRst = EXE_END ; + } + + return( UlTneRst ) ; +} + + + +//******************************************************************************** +// Function Name : TneBia +// Retun Value : Hall Top & Bottom Gaps +// Argment Value : Hall Top & Bottom Gaps , X,Y Direction +// Explanation : Hall Bias Tuning Function +// History : First edition +//******************************************************************************** +void TneBia( UnDwdVal StTneVal, UINT_8 UcTneAxs, UINT_16 UsHalAdjRange ) +{ + UINT_32 UlSetBia; + +TRACE("TneBia\n " ) ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallBias_X , &UlSetBia ) ; + } else if( UcTneAxs == Y_DIR ) { + RamRead32A( StCaliData_UiHallBias_Y , &UlSetBia ) ; + } + +TRACE(" UlSetBia = %08x\n ", (unsigned int)UlSetBia ) ; + if( UlSetBia == 0x00000000 ) UlSetBia = 0x01000000 ; + UlSetBia = (( UlSetBia >> 16 ) & (UINT_32)0x0000FF00 ) ; + UlSetBia *= (UINT_32)UsHalAdjRange ; + if(( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal ) == 0xFFFF ){ + UlSetBia = BIAS_HLMT ; + }else{ + UlSetBia /= (UINT_32)( 0xFFFF - ( StTneVal.StDwdVal.UsHigVal + StTneVal.StDwdVal.UsLowVal )) ; + if( UlSetBia > (UINT_32)0x0000FFFF ) UlSetBia = 0x0000FFFF ; + UlSetBia = ( UlSetBia << 16 ) ; + if( UlSetBia > BIAS_HLMT ) UlSetBia = BIAS_HLMT ; + if( UlSetBia < BIAS_LLMT ) UlSetBia = BIAS_LLMT ; + } + + if( UcTneAxs == X_DIR ) { + DacControl( 0, HLXBO , UlSetBia ) ; +TRACE(" HLXBO = %08x\n ", (unsigned int)UlSetBia ) ; + RamWrite32A( StCaliData_UiHallBias_X , UlSetBia) ; + } else if( UcTneAxs == Y_DIR ){ + DacControl( 0, HLYBO , UlSetBia ) ; +TRACE(" HLYBO = %08x\n ", (unsigned int)UlSetBia ) ; + RamWrite32A( StCaliData_UiHallBias_Y , UlSetBia) ; + } +TRACE(" ( AXIS = %02x , BIAS = %08xh ) , \n", UcTneAxs , (unsigned int)UlSetBia ) ; +} + + +//******************************************************************************** +// Function Name : TneOff +// Retun Value : Hall Top & Bottom Gaps +// Argment Value : Hall Top & Bottom Gaps , X,Y Direction +// Explanation : Hall Offset Tuning Function +// History : First edition +//******************************************************************************** +void TneOff( UnDwdVal StTneVal, UINT_8 UcTneAxs ) +{ + UINT_32 UlSetOff ; + UINT_32 UlSetVal ; + +TRACE("TneOff\n ") ; + if( UcTneAxs == X_DIR ) { + RamRead32A( StCaliData_UiHallOffset_X , &UlSetOff ) ; + } else if( UcTneAxs == Y_DIR ){ + RamRead32A( StCaliData_UiHallOffset_Y , &UlSetOff ) ; + } + UlSetOff = ( UlSetOff >> 16 ) ; + + if ( StTneVal.StDwdVal.UsHigVal > StTneVal.StDwdVal.UsLowVal ) { + UlSetVal = ( UINT_32 )(( StTneVal.StDwdVal.UsHigVal - StTneVal.StDwdVal.UsLowVal ) / OFFSET_DIV ) ; // Calculating Value For Increase Step + UlSetOff += UlSetVal ; // Calculating Value For Increase Step + if( UlSetOff > 0x0000FFFF ) UlSetOff = 0x0000FFFF ; + } else { + UlSetVal = ( UINT_32 )(( StTneVal.StDwdVal.UsLowVal - StTneVal.StDwdVal.UsHigVal ) / OFFSET_DIV ) ; // Calculating Value For Decrease Step + if( UlSetOff < UlSetVal ){ + UlSetOff = 0x00000000 ; + }else{ + UlSetOff -= UlSetVal ; // Calculating Value For Decrease Step + } + } + +TRACE(" UlSetOff = %08x\n ", (unsigned int)UlSetOff ) ; + if( UlSetOff > ( INT_32 )0x0000EFFF ) { + UlSetOff = 0x0000EFFF ; + } else if( UlSetOff < ( INT_32 )0x00001000 ) { + UlSetOff = 0x00001000 ; + } + + UlSetOff = ( UlSetOff << 16 ) ; + + if( UcTneAxs == X_DIR ) { + DacControl( 0, HLXO, UlSetOff ) ; +TRACE(" HLXO = %08x\n ", (unsigned int)UlSetOff ) ; + RamWrite32A( StCaliData_UiHallOffset_X , UlSetOff ) ; + } else if( UcTneAxs == Y_DIR ){ + DacControl( 0, HLYO, UlSetOff ) ; +TRACE(" HLYO = %08x\n ", (unsigned int)UlSetOff ) ; + RamWrite32A( StCaliData_UiHallOffset_Y , UlSetOff ) ; + } +TRACE(" ( AXIS = %02x , OFST = %08xh ) , \n", UcTneAxs , (unsigned int)UlSetOff ) ; + +} + + +//******************************************************************************** +// Function Name : LopGan +// Retun Value : Execute Result +// Argment Value : X,Y Direction +// Explanation : Loop Gain Adjust Function +// History : First edition +//******************************************************************************** +extern void MesStart_FRA_Single( UINT_8 UcDirSel ); +extern void MesEnd_FRA_Sweep( void ); +#include "OisFRA.h" + +UINT_32 LopGan( UINT_8 UcDirSel, ADJ_LOPGAN* ptr ) +{ + + UINT_32 UlReturnState ; + +#ifdef LOOPGAIN_FIX_VALUE +// UnFltVal UnMesResult ; +/* + StFRAParam.StHostCom.UcAvgCycl = 3 ; + StFRAParam.StHostCom.SfAmpCom.SfFltVal = 100.0f; + StFRAParam.StHostCom.SfFrqCom.SfFltVal = 20.0f ; + MesStart_FRA_Single( UcDirSel ) ; + MesEnd_FRA_Sweep() ; +// StFRAParam.StMesRslt.SfGainAvg ; +*/ + if( UcDirSel == X_DIR ) { // X axis + RamWrite32A( HallFilterCoeffX_hxgain0 , ptr->Hxgain ) ; + StAdjPar.StLopGan.UlLxgVal = ptr->Hxgain ; + UlReturnState = EXE_END ; + } else if( UcDirSel == Y_DIR ){ // Y axis + RamWrite32A( HallFilterCoeffY_hygain0 , ptr->Hygain ) ; + StAdjPar.StLopGan.UlLygVal = ptr->Hygain ; + UlReturnState = EXE_END ; + } + +#else // LOOPGAIN_FIX_VALUE + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + UINT_64 UllCalculateVal ; + UINT_16 UsSinAdr ; + UINT_32 UlFreq, UlGain; + INT_32 SlNum ; + + if( UcDirSel == X_DIR ) { // X axis +// SlMeasureParameterA = HALL_RAM_HXOUT1 ; // Set Measure RAM Address +// SlMeasureParameterB = HALL_RAM_HXLOP ; // Set Measure RAM Address + SlMeasureParameterA = HALL_RAM_HXOUT3 ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HALL_X_OUT ; // Set Measure RAM Address + + RamWrite32A( HallFilterCoeffX_hxgain0 , ptr->Hxgain ) ; + UsSinAdr = HALL_RAM_SINDX1; +// UsSinAdr = HALL_RAM_SINDX0; + UlFreq = ptr->XNoiseFreq; + UlGain = ptr->XNoiseGain; + SlNum = ptr->XNoiseNum; + } else if( UcDirSel == Y_DIR ){ // Y axis +// SlMeasureParameterA = HALL_RAM_HYOUT1 ; // Set Measure RAM Address +// SlMeasureParameterB = HALL_RAM_HYLOP ; // Set Measure RAM Address + SlMeasureParameterA = HALL_RAM_HYOUT3 ; // Set Measure RAM Address + SlMeasureParameterB = HALL_RAM_HALL_Y_OUT ; // Set Measure RAM Address + + RamWrite32A( HallFilterCoeffY_hygain0 , ptr->Hygain ) ; + UsSinAdr = HALL_RAM_SINDY1; +// UsSinAdr = HALL_RAM_SINDY0; + UlFreq = ptr->YNoiseFreq; + UlGain = ptr->YNoiseGain; + SlNum = ptr->YNoiseNum; + } + + SetSinWavGenInt(); + SetTransDataAdr( SinWave_OutAddr , SinWave_Output ) ; // o—ÍæƒAƒhƒŒƒX + SetTransDataAdr( CosWave_OutAddr , CosWave_OutAddr ); // o—ÍæƒAƒhƒŒƒX + + RamWrite32A( SinWave_Offset , UlFreq ) ; // Freq Setting + RamWrite32A( SinWave_Gain , UlGain ) ; // Set Sine Wave Gain +TRACE(" Loop Gain %d , Freq %08xh, Gain %08xh , Num %08xh \n", UcDirSel , UlFreq , UlGain , SlNum ) ; + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + + SetTransDataAdr( SinWave_OutAddr , ( UINT_32 )UsSinAdr ) ; // Set Sine Wave Input RAM + + MesFil( LOOPGAIN2 ) ; // Filter setting for measurement +// MesFil( LOOPGAIN ) ; // Filter setting for measurement + + MeasureStart( SlNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + + SetSinWavGenInt(); // Sine wave stop + + SetTransDataAdr( SinWave_OutAddr , (UINT_32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( UsSinAdr , 0x00000000 ) ; // DelayRam Clear + + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; +TRACE(" MFA %08x%08x, MFB %08x%08x\n", StMeasValueA.StUllnVal.UlHigVal , StMeasValueA.StUllnVal.UlLowVal , StMeasValueB.StUllnVal.UlHigVal , StMeasValueB.StUllnVal.UlHigVal ) ; + + if( UcDirSel == X_DIR ) { // X axis + UllCalculateVal = ( StMeasValueB.UllnValue * 1000 / StMeasValueA.UllnValue ) * ptr->Hxgain / ptr->XGap ; + if( UllCalculateVal > (UINT_64)0x000000007FFFFFFF ) UllCalculateVal = (UINT_64)0x000000007FFFFFFF ; + StAdjPar.StLopGan.UlLxgVal = (UINT_32)UllCalculateVal ; + RamWrite32A( HallFilterCoeffX_hxgain0 , StAdjPar.StLopGan.UlLxgVal ) ; +TRACE(" hxgain0: %08x\n", StAdjPar.StLopGan.UlLxgVal ) ; + if( (UllCalculateVal > ptr->XJudgeHigh) || ( UllCalculateVal < ptr->XJudgeLow ) ){ + UlReturnState = EXE_LXADJ ; + }else{ + UlReturnState = EXE_END ; + } + + }else if( UcDirSel == Y_DIR ){ // Y axis + UllCalculateVal = ( StMeasValueB.UllnValue * 1000 / StMeasValueA.UllnValue ) * ptr->Hygain / ptr->YGap ; + if( UllCalculateVal > (UINT_64)0x000000007FFFFFFF ) UllCalculateVal = (UINT_64)0x000000007FFFFFFF ; + StAdjPar.StLopGan.UlLygVal = (UINT_32)UllCalculateVal ; + RamWrite32A( HallFilterCoeffY_hygain0 , StAdjPar.StLopGan.UlLygVal ) ; +TRACE(" hygain0: %08x\n", StAdjPar.StLopGan.UlLygVal ) ; + if( (UllCalculateVal > ptr->YJudgeHigh) || ( UllCalculateVal < ptr->YJudgeLow ) ){ + UlReturnState = EXE_LYADJ ; + }else{ + UlReturnState = EXE_END ; + } + } +#endif // LOOPGAIN_FIX_VALUE + return( UlReturnState ) ; + +} + + +//******************************************************************************** +// Function Name : MesFil +// Retun Value : NON +// Argment Value : Measure Filter Mode +// Explanation : Measure Filter Setting Function +// History : First edition +//******************************************************************************** +void MesFil( UINT_8 UcMesMod ) // 18.0446kHz/15.027322kHz +{ + UINT_32 UlMeasFilaA , UlMeasFilaB , UlMeasFilaC ; + UINT_32 UlMeasFilbA , UlMeasFilbB , UlMeasFilbC ; + +#if FS_MODE == 0 + if( !UcMesMod ) { // Hall Bias&Offset Adjust + + UlMeasFilaA = 0x0341F6F7 ; // LPF 150Hz + UlMeasFilaB = 0x0341F6F7 ; + UlMeasFilaC = 0x797C1211 ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } else if( UcMesMod == LOOPGAIN ) { // Loop Gain Adjust + + UlMeasFilaA = 0x12FAFFF9 ; // LPF1000Hz + UlMeasFilaB = 0x12FAFFF9 ; + UlMeasFilaC = 0x5A0A000D ; + UlMeasFilbA = 0x7F55BD91 ; // HPF30Hz + UlMeasFilbB = 0x80AA426F ; + UlMeasFilbC = 0x7EAB7B22 ; + + } else if( UcMesMod == LOOPGAIN2 ) { // Loop Gain Adjust2 + + UlMeasFilaA = 0x01F98673 ; // LPF90Hz + UlMeasFilaB = 0x01F98673 ; + UlMeasFilaC = 0x7C0CF31B ; + UlMeasFilbA = 0x7FC70CAF ; // HPF10Hz + UlMeasFilbB = 0x8038F350 ; + UlMeasFilbC = 0x7F8E195F ; + + } else if( UcMesMod == THROUGH ) { // for Through + + UlMeasFilaA = 0x7FFFFFFF ; // Through + UlMeasFilaB = 0x00000000 ; + UlMeasFilaC = 0x00000000 ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } else if( UcMesMod == NOISE ) { // SINE WAVE TEST for NOISE + + UlMeasFilaA = 0x0341F6F7 ; // LPF150Hz + UlMeasFilaB = 0x0341F6F7 ; + UlMeasFilaC = 0x797C1211 ; + UlMeasFilbA = 0x0341F6F7 ; // LPF150Hz + UlMeasFilbB = 0x0341F6F7 ; + UlMeasFilbC = 0x797C1211 ; + + } else if(UcMesMod == OSCCHK) { + UlMeasFilaA = 0x065A887F ; // LPF300Hz + UlMeasFilaB = 0x065A887F ; + UlMeasFilaC = 0x734AEF01 ; + UlMeasFilbA = 0x065A887F ; // LPF300Hz + UlMeasFilbB = 0x065A887F ; + UlMeasFilbC = 0x734AEF01 ; + + } else if( UcMesMod == SELFTEST ) { // GYRO SELF TEST + + UlMeasFilaA = 0x12FAFFF9 ; // LPF1000Hz + UlMeasFilaB = 0x12FAFFF9 ; + UlMeasFilaC = 0x5A0A000D ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } +#else //FS_MODE + if( !UcMesMod ) { // Hall Bias&Offset Adjust + + UlMeasFilaA = 0x03E4526B ; // LPF 150Hz + UlMeasFilaB = 0x03E4526B ; + UlMeasFilaC = 0x78375B2B ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } else if( UcMesMod == LOOPGAIN ) { // Loop Gain Adjust + + UlMeasFilaA = 0x1621ECCD ; // LPF1000Hz + UlMeasFilaB = 0x1621ECCD ; + UlMeasFilaC = 0x53BC2664 ; + UlMeasFilbA = 0x7F33C48F ; // HPF30Hz + UlMeasFilbB = 0x80CC3B71 ; + UlMeasFilbC = 0x7E67891F ; + + } else if( UcMesMod == LOOPGAIN2 ) { // Loop Gain Adjust2 + +// UlMeasFilaA = 0x025D2733 ; // LPF90Hz +// UlMeasFilaB = 0x025D2733 ; +// UlMeasFilaC = 0x7B45B19B ; +// UlMeasFilbA = 0x7FBBA379 ; // HPF10Hz +// UlMeasFilbB = 0x80445C87 ; +// UlMeasFilbC = 0x7F7746F1 ; + UlMeasFilaA = 0x25BD51E6 ; // LPF2000Hz + UlMeasFilaB = 0x25BD51E6 ; + UlMeasFilaC = 0x34855C33 ; + UlMeasFilbA = 0x7D60FBCD ; // HPF100Hz + UlMeasFilbB = 0x829F0433 ; + UlMeasFilbC = 0x7AC1F799 ; + + } else if( UcMesMod == THROUGH ) { // for Through + + UlMeasFilaA = 0x7FFFFFFF ; // Through + UlMeasFilaB = 0x00000000 ; + UlMeasFilaC = 0x00000000 ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } else if( UcMesMod == NOISE ) { // SINE WAVE TEST for NOISE + + UlMeasFilaA = 0x03E4526B ; // LPF150Hz + UlMeasFilaB = 0x03E4526B ; + UlMeasFilaC = 0x78375B2B ; + UlMeasFilbA = 0x03E4526B ; // LPF150Hz + UlMeasFilbB = 0x03E4526B ; + UlMeasFilbC = 0x78375B2B ; + + } else if(UcMesMod == OSCCHK) { + UlMeasFilaA = 0x078DD83D ; // LPF300Hz + UlMeasFilaB = 0x078DD83D ; + UlMeasFilaC = 0x70E44F85 ; + UlMeasFilbA = 0x078DD83D ; // LPF300Hz + UlMeasFilbB = 0x078DD83D ; + UlMeasFilbC = 0x70E44F85 ; + + } else if( UcMesMod == SELFTEST ) { // GYRO SELF TEST + + UlMeasFilaA = 0x1621ECCD ; // LPF1000Hz + UlMeasFilaB = 0x1621ECCD ; + UlMeasFilaC = 0x53BC2664 ; + UlMeasFilbA = 0x7FFFFFFF ; // Through + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + } +#endif //FS_MODE + + RamWrite32A ( MeasureFilterA_Coeff_a1 , UlMeasFilaA ) ; + RamWrite32A ( MeasureFilterA_Coeff_b1 , UlMeasFilaB ) ; + RamWrite32A ( MeasureFilterA_Coeff_c1 , UlMeasFilaC ) ; + + RamWrite32A ( MeasureFilterA_Coeff_a2 , UlMeasFilbA ) ; + RamWrite32A ( MeasureFilterA_Coeff_b2 , UlMeasFilbB ) ; + RamWrite32A ( MeasureFilterA_Coeff_c2 , UlMeasFilbC ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a1 , UlMeasFilaA ) ; + RamWrite32A ( MeasureFilterB_Coeff_b1 , UlMeasFilaB ) ; + RamWrite32A ( MeasureFilterB_Coeff_c1 , UlMeasFilaC ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a2 , UlMeasFilbA ) ; + RamWrite32A ( MeasureFilterB_Coeff_b2 , UlMeasFilbB ) ; + RamWrite32A ( MeasureFilterB_Coeff_c2 , UlMeasFilbC ) ; +} + +//******************************************************************************** +// Function Name : ClrMesFil +// Retun Value : NON +// Argment Value : NON +// Explanation : Clear Measure Filter Function +// History : First edition +//******************************************************************************** +void ClrMesFil( void ) +{ + RamWrite32A ( MeasureFilterA_Delay_z11 , 0 ) ; + RamWrite32A ( MeasureFilterA_Delay_z12 , 0 ) ; + + RamWrite32A ( MeasureFilterA_Delay_z21 , 0 ) ; + RamWrite32A ( MeasureFilterA_Delay_z22 , 0 ) ; + + RamWrite32A ( MeasureFilterB_Delay_z11 , 0 ) ; + RamWrite32A ( MeasureFilterB_Delay_z12 , 0 ) ; + + RamWrite32A ( MeasureFilterB_Delay_z21 , 0 ) ; + RamWrite32A ( MeasureFilterB_Delay_z22 , 0 ) ; +} + +//******************************************************************************** +// Function Name : MeasureStart +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void MeasureStart( INT_32 SlMeasureParameterNum , INT_32 SlMeasureParameterA , INT_32 SlMeasureParameterB ) +{ + MemoryClear( StMeasFunc_SiSampleNum , sizeof( MeasureFunction_Type ) ) ; + RamWrite32A( StMeasFunc_MFA_SiMax1 , 0x80000000 ) ; // Set Min + RamWrite32A( StMeasFunc_MFB_SiMax2 , 0x80000000 ) ; // Set Min + RamWrite32A( StMeasFunc_MFA_SiMin1 , 0x7FFFFFFF ) ; // Set Max + RamWrite32A( StMeasFunc_MFB_SiMin2 , 0x7FFFFFFF ) ; // Set Max + + SetTransDataAdr( StMeasFunc_MFA_PiMeasureRam1 , ( UINT_32 )SlMeasureParameterA ) ; // Set Measure Filter A Ram Address + SetTransDataAdr( StMeasFunc_MFB_PiMeasureRam2 , ( UINT_32 )SlMeasureParameterB ) ; // Set Measure Filter B Ram Address + + RamWrite32A( StMeasFunc_SiSampleNum , 0 ) ; // Clear Measure Counter + + ClrMesFil() ; // Clear Delay Ram +// SetWaitTime(50) ; + SetWaitTime(1) ; + + RamWrite32A( StMeasFunc_SiSampleMax , SlMeasureParameterNum ) ; // Set Measure Max Number + +} + + +//******************************************************************************** +// Function Name : MeasureStart2 +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void MeasureStart2( INT_32 SlMeasureParameterNum , INT_32 SlMeasureParameterA , INT_32 SlMeasureParameterB , UINT_16 UsTime ) +{ + MemoryClear( StMeasFunc_SiSampleNum , sizeof( MeasureFunction_Type ) ) ; + RamWrite32A( StMeasFunc_MFA_SiMax1 , 0x80000001 ) ; // Set Min + RamWrite32A( StMeasFunc_MFB_SiMax2 , 0x80000001 ) ; // Set Min + RamWrite32A( StMeasFunc_MFA_SiMin1 , 0x7FFFFFFF ) ; // Set Max + RamWrite32A( StMeasFunc_MFB_SiMin2 , 0x7FFFFFFF ) ; // Set Max + + SetTransDataAdr( StMeasFunc_MFA_PiMeasureRam1 , ( UINT_32 )SlMeasureParameterA ) ; // Set Measure Filter A Ram Address + SetTransDataAdr( StMeasFunc_MFB_PiMeasureRam2 , ( UINT_32 )SlMeasureParameterB ) ; // Set Measure Filter B Ram Address + + RamWrite32A( StMeasFunc_SiSampleNum , 0 ) ; // Clear Measure Counter + + ClrMesFil() ; // Clear Delay Ram + SetWaitTime(UsTime) ; + + RamWrite32A( StMeasFunc_SiSampleMax , SlMeasureParameterNum ) ; // Set Measure Max Number + + +} + +//******************************************************************************** +// Function Name : MeasureWait +// Retun Value : NON +// Argment Value : NON +// Explanation : Wait complete of Measure Function +// History : First edition +//******************************************************************************** +void MeasureWait( void ) +{ + + UINT_32 SlWaitTimerSt ; + + UINT_16 UsTimeOut = 2000; + + WitTim(10); + + do { + RamRead32A( StMeasFunc_SiSampleMax, &SlWaitTimerSt ) ; + WitTim(1); + } while ( SlWaitTimerSt && --UsTimeOut ); + +} + +//******************************************************************************** +// Function Name : MemoryClear +// Retun Value : NON +// Argment Value : Top poINT_32er , Size +// Explanation : Memory Clear Function +// History : First edition +//******************************************************************************** +void MemoryClear( UINT_16 UsSourceAddress, UINT_16 UsClearSize ) +{ + UINT_16 UsLoopIndex ; + + for ( UsLoopIndex = 0 ; UsLoopIndex < UsClearSize ; ) { + RamWrite32A( UsSourceAddress , 0x00000000 ) ; // 4Byte + UsSourceAddress += 4; + UsLoopIndex += 4 ; + } +} + +//******************************************************************************** +// Function Name : SetWaitTime +// Retun Value : NON +// Argment Value : NON +// Explanation : Set Timer wait Function +// History : First edition +//******************************************************************************** +#if FS_MODE == 0 +#define ONE_MSEC_COUNT 18 // 18.0446kHz * 18 à 1ms +#else //FS_MODE +#define ONE_MSEC_COUNT 15 // 15.0273kHz * 15 à 1ms +#endif //FS_MODE +void SetWaitTime( UINT_16 UsWaitTime ) +{ + RamWrite32A( WaitTimerData_UiWaitCounter , 0 ) ; + RamWrite32A( WaitTimerData_UiTargetCount , (UINT_32)(ONE_MSEC_COUNT * UsWaitTime)) ; +} + + +//******************************************************************************** +// Function Name : TneGvc +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Gyro VC offset +// History : First edition +//******************************************************************************** +#define GYROF_NUM 2048 // 2048times +#define GYROF_UPPER 0x06D6 // +#define GYROF_LOWER 0xF92A // +UINT_32 TneGvc( UINT_8 uc_mode ) +{ + UINT_32 UlRsltSts; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureAveValueA , SlMeasureAveValueB ; + + + //•½‹Ï’l‘ª’è + + MesFil( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = GYROF_NUM ; // Measurement times +#ifdef SEL_SHIFT_COR + if( uc_mode == 0 ){ +#endif //SEL_SHIFT_COR + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address +#ifdef SEL_SHIFT_COR + }else{ + SlMeasureParameterA = GYRO_ZRAM_GZ_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = GYRO_ZRAM_GZ_ADIDAT ; // Set Measure RAM Address + } +#endif //SEL_SHIFT_COR + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait() ; // Wait complete of measurement + +TRACE("Read Adr = %04x, %04xh \n",StMeasFunc_MFA_LLiIntegral1 + 4 , StMeasFunc_MFA_LLiIntegral1) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + +TRACE("GX_OFT = %08x, %08xh \n",(unsigned int)StMeasValueA.StUllnVal.UlHigVal,(unsigned int)StMeasValueA.StUllnVal.UlLowVal) ; +TRACE("GY_OFT = %08x, %08xh \n",(unsigned int)StMeasValueB.StUllnVal.UlHigVal,(unsigned int)StMeasValueB.StUllnVal.UlLowVal) ; + SlMeasureAveValueA = (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; +TRACE("GX_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueA) ; +TRACE("GY_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueB) ; + + SlMeasureAveValueA = ( SlMeasureAveValueA >> 16 ) & 0x0000FFFF ; + SlMeasureAveValueB = ( SlMeasureAveValueB >> 16 ) & 0x0000FFFF ; + + UlRsltSts = EXE_END ; +#ifdef SEL_SHIFT_COR + if( uc_mode == 0){ +#endif //SEL_SHIFT_COR + StAdjPar.StGvcOff.UsGxoVal = ( UINT_16 )( SlMeasureAveValueA & 0x0000FFFF ); //Measure Result Store + if(( (INT_16)StAdjPar.StGvcOff.UsGxoVal > (INT_16)GYROF_UPPER ) || ( (INT_16)StAdjPar.StGvcOff.UsGxoVal < (INT_16)GYROF_LOWER )){ + UlRsltSts |= EXE_GXADJ ; + } + RamWrite32A( GYRO_RAM_GXOFFZ , (( SlMeasureAveValueA << 16 ) & 0xFFFF0000 ) ) ; // X axis Gyro offset + + StAdjPar.StGvcOff.UsGyoVal = ( UINT_16 )( SlMeasureAveValueB & 0x0000FFFF ); //Measure Result Store + if(( (INT_16)StAdjPar.StGvcOff.UsGyoVal > (INT_16)GYROF_UPPER ) || ( (INT_16)StAdjPar.StGvcOff.UsGyoVal < (INT_16)GYROF_LOWER )){ + UlRsltSts |= EXE_GYADJ ; + } + RamWrite32A( GYRO_RAM_GYOFFZ , (( SlMeasureAveValueB << 16 ) & 0xFFFF0000 ) ) ; // Y axis Gyro offset + +TRACE("GX_AVEOFT_RV = %08xh \n",(unsigned int)SlMeasureAveValueA) ; +TRACE("GY_AVEOFT_RV = %08xh \n",(unsigned int)SlMeasureAveValueB) ; + + RamWrite32A( GYRO_RAM_GYROX_OFFSET , 0x00000000 ) ; // X axis Drift Gyro offset + RamWrite32A( GYRO_RAM_GYROY_OFFSET , 0x00000000 ) ; // Y axis Drift Gyro offset + RamWrite32A( GyroFilterDelayX_GXH1Z2 , 0x00000000 ) ; // X axis H1Z2 Clear + RamWrite32A( GyroFilterDelayY_GYH1Z2 , 0x00000000 ) ; // Y axis H1Z2 Clear +#ifdef SEL_SHIFT_COR + }else{ + StAdjPar.StGvcOff.UsGzoVal = ( UINT_16 )( SlMeasureAveValueA & 0x0000FFFF ); //Measure Result Store + if(( (INT_16)StAdjPar.StGvcOff.UsGzoVal > (INT_16)GYROF_UPPER ) || ( (INT_16)StAdjPar.StGvcOff.UsGzoVal < (INT_16)GYROF_LOWER )){ + UlRsltSts |= EXE_GZADJ ; + } + RamWrite32A( GYRO_ZRAM_GZOFFZ , (( SlMeasureAveValueA << 16 ) & 0xFFFF0000 ) ) ; // Z axis Gyro offset + + RamWrite32A( GyroRAM_Z_GYRO_OFFSET , 0x00000000 ) ; // Z axis Drift Gyro offset + } +#endif //SEL_SHIFT_COR + return( UlRsltSts ); + + +} + + +#ifdef SEL_SHIFT_COR +//******************************************************************************** +// Function Name : TneAvc +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Accel VC offset for All +// History : First edition +//******************************************************************************** +#define ACCLOF_NUM 4096 // 4096times +UINT_32 TneAvc( UINT_8 ucposture ) +{ + UINT_32 UlRsltSts; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureAveValueA , SlMeasureAveValueB ; + INT_32 SlMeasureRetValueX , SlMeasureRetValueY , SlMeasureRetValueZ; + UINT_8 i , j , k; + INT_32 SlDiff[3] ; + + UlRsltSts = EXE_END ; + if( ucposture < 0x7f ){ + //•½‹Ï’l‘ª’è + for( i=0 ; i<2 ; i++ ) + { + MesFil( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = ACCLOF_NUM ; // Measurement times + switch(i){ + case 0: + SlMeasureParameterA = ACCLRAM_X_AC_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = ACCLRAM_Y_AC_ADIDAT ; // Set Measure RAM Address + break; + case 1: + SlMeasureParameterA = ACCLRAM_Z_AC_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = ACCLRAM_Z_AC_ADIDAT ; // Set Measure RAM Address + break; + } + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; + + switch(i){ + case 0: + SlMeasureRetValueX = SlMeasureAveValueA ; + SlMeasureRetValueY = SlMeasureAveValueB ; + break; + case 1: + SlMeasureRetValueZ = SlMeasureAveValueA ; + break; + } + + } + + +TRACE("VAL(X,Y,Z) pos = \t%08xh\t%08xh\t%08xh\t%d \n",(INT_32)SlMeasureRetValueX ,(INT_32)SlMeasureRetValueY,(INT_32)SlMeasureRetValueZ, ucposture ) ; + if(( SlMeasureRetValueZ < (INT_32)(POSTURETH_P<<16)) && (ucposture == 0x10)){ + UlRsltSts = EXE_ERR ; +TRACE(" POS14 [ERROR] \t%08xh < %08xh\n", (unsigned int)(SlMeasureRetValueZ), (unsigned int)(POSTURETH_P<<16) ) ; + }else{ +TRACE("DEBUG = \t%08xh\t \n", abs( (INT_32)(ACCL_SENS << 16) - abs(SlMeasureRetValueZ) ) ) ; + if( abs(SlMeasureRetValueX) > ZEROG_MRGN_XY ) UlRsltSts |= EXE_AXADJ ; + if( abs(SlMeasureRetValueY) > ZEROG_MRGN_XY ) UlRsltSts |= EXE_AYADJ ; + if( abs( (INT_32)(ACCL_SENS << 16) - abs(SlMeasureRetValueZ)) > ZEROG_MRGN_Z ) UlRsltSts |= EXE_AZADJ ; + if( UlRsltSts == EXE_END ){ + StPosOff.UlAclOfSt |= 0x0000003F; +TRACE("POS14(X,Y,Z) st = \t%08xh\t%08xh\t%08xh\t%08xh \n", (unsigned int)StPosOff.StPos.Pos[4][0], (unsigned int)StPosOff.StPos.Pos[4][1], (unsigned int)StPosOff.StPos.Pos[4][2], (unsigned int)StPosOff.UlAclOfSt ) ; + + SlDiff[0] = SlMeasureRetValueX - (INT_32)0; + SlDiff[1] = SlMeasureRetValueY - (INT_32)0; +// if(ucposture == 0x10){ + SlDiff[2] = SlMeasureRetValueZ - (INT_32)(ACCL_SENS << 16); +// }else{ +// SlDiff[2] = SlMeasureRetValueZ - (INT_32)(-ACCL_SENS << 16); +// } + StPosOff.StPos.Pos[4][0] = SlDiff[0]; + StPosOff.StPos.Pos[4][1] = SlDiff[1]; + StPosOff.StPos.Pos[4][2] = SlDiff[2]; + } + } + }else{ + switch(ucposture){ + case 0x80: /* ŒvŽZ */ + + if(StPosOff.UlAclOfSt == 0x3fL ){ + /*X offset*/ + StAclVal.StAccel.SlOffsetX = StPosOff.StPos.Pos[4][0] ; + /*Y offset*/ + StAclVal.StAccel.SlOffsetY = StPosOff.StPos.Pos[4][1] ; + /*Z offset*/ + StAclVal.StAccel.SlOffsetZ = StPosOff.StPos.Pos[4][2] ; +#ifdef DEBUG +TRACE("ACLOFST(X,Y,Z) = \t%08xh\t%08xh\t%08xh \n",(INT_32)StAclVal.StAccel.SlOffsetX ,(INT_32)StAclVal.StAccel.SlOffsetY,(INT_32)StAclVal.StAccel.SlOffsetZ ) ; +#endif //DEBUG + RamWrite32A( ACCLRAM_X_AC_OFFSET , StAclVal.StAccel.SlOffsetX ) ; // X axis Accel offset + RamWrite32A( ACCLRAM_Y_AC_OFFSET , StAclVal.StAccel.SlOffsetY ) ; // Y axis Accel offset + RamWrite32A( ACCLRAM_Z_AC_OFFSET , StAclVal.StAccel.SlOffsetZ ) ; // Z axis Accel offset + + StAclVal.StAccel.SlOffsetX = ( StAclVal.StAccel.SlOffsetX >> 16 ) & 0x0000FFFF; + StAclVal.StAccel.SlOffsetY = ( StAclVal.StAccel.SlOffsetY >> 16 ) & 0x0000FFFF; + StAclVal.StAccel.SlOffsetZ = ( StAclVal.StAccel.SlOffsetZ >> 16 ) & 0x0000FFFF; + + for( j=0 ; j < 6 ; j++ ){ + k = 4 * j; + RamWrite32A( AcclFilDly_X + k , 0x00000000 ) ; // X axis Accl LPF Clear + RamWrite32A( AcclFilDly_Y + k , 0x00000000 ) ; // Y axis Accl LPF Clear + RamWrite32A( AcclFilDly_Z + k , 0x00000000 ) ; // Z axis Accl LPF Clear + } + + }else{ + UlRsltSts = EXE_ERR ; + } + break; + + case 0xFF: /* RAM clear */ + MemClr( ( UINT_8 * )&StPosOff, sizeof( stPosOff ) ) ; // Adjust Parameter Clear + MemClr( ( UINT_8 * )&StAclVal, sizeof( stAclVal ) ) ; // Adjust Parameter Clear +// StPosOff.UlAclOfSt = 0L; + break; + } + } + +TRACE(" Result = %08x\n",(INT_32)UlRsltSts ) ; + return( UlRsltSts ); + + +} + + +void MeasAddressSelection( UINT_8 mode , INT_32 * measadr_a , INT_32 * measadr_b ) +{ + if( mode == 0 ){ + *measadr_a = GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + *measadr_b = GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address + }else if( mode == 1 ){ + *measadr_a = GYRO_ZRAM_GZ_ADIDAT ; // Set Measure RAM Address + *measadr_b = ACCLRAM_Z_AC_ADIDAT ; // Set Measure RAM Address + }else{ + *measadr_a = ACCLRAM_X_AC_ADIDAT ; // Set Measure RAM Address + *measadr_b = ACCLRAM_Y_AC_ADIDAT ; // Set Measure RAM Address + } +} + +#define MESOF_NUM 2048 // 2048times +#define GYROFFSET_H ( 0x06D6 << 16 ) // +#define GSENS ( 4096 << 16 ) // LSB/g +#define GSENS_MARG (GSENS / 4) // 1/4g +#define POSTURETH (GSENS - GSENS_MARG) // LSB/g +#define ZG_MRGN (409 << 16) // G tolerance 100mG‚Æ‚·‚é +UINT_32 MeasGyAcOffset( void ) +{ + UINT_32 UlRsltSts; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureAveValueA[3] , SlMeasureAveValueB[3] ; + UINT_8 i ; + + + //•½‹Ï’l‘ª’è + + MesFil( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = MESOF_NUM ; // Measurement times + + for( i=0 ; i<3 ; i++ ) + { + MeasAddressSelection( i, &SlMeasureParameterA , &SlMeasureParameterB ); + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + MeasureWait() ; // Wait complete of measurement + +TRACE("Read Adr = %04x, %04xh \n",StMeasFunc_MFA_LLiIntegral1 + 4 , StMeasFunc_MFA_LLiIntegral1) ; + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + +TRACE("(%d) AOFT = %08x, %08xh \n",i,(unsigned int)StMeasValueA.StUllnVal.UlHigVal,(unsigned int)StMeasValueA.StUllnVal.UlLowVal) ; +TRACE("(%d) BOFT = %08x, %08xh \n",i,(unsigned int)StMeasValueB.StUllnVal.UlHigVal,(unsigned int)StMeasValueB.StUllnVal.UlLowVal) ; + SlMeasureAveValueA[i] = (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB[i] = (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; +TRACE("AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueA[i]) ; +TRACE("AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueB[i]) ; + + } + + UlRsltSts = EXE_END ; + + + if( abs(SlMeasureAveValueA[0]) > GYROFFSET_H ) UlRsltSts |= EXE_GXADJ ; + if( abs(SlMeasureAveValueB[0]) > GYROFFSET_H ) UlRsltSts |= EXE_GYADJ ; + if( abs(SlMeasureAveValueA[1]) > GYROFFSET_H ) UlRsltSts |= EXE_GZADJ ; + if( (SlMeasureAveValueB[1]) < POSTURETH ) UlRsltSts |= EXE_AZADJ ; + if( abs(SlMeasureAveValueA[2]) > ZG_MRGN ) UlRsltSts |= EXE_AXADJ ; + if( abs(SlMeasureAveValueB[2]) > ZG_MRGN ) UlRsltSts |= EXE_AYADJ ; + if( abs( GSENS - SlMeasureAveValueB[1]) > ZG_MRGN ) UlRsltSts |= EXE_AZADJ ; + + + if( UlRsltSts == EXE_END ){ + RamWrite32A( GYRO_RAM_GXOFFZ , SlMeasureAveValueA[0] ) ; // X axis Gyro offset + RamWrite32A( GYRO_RAM_GYOFFZ , SlMeasureAveValueB[0] ) ; // Y axis Gyro offset + RamWrite32A( GYRO_ZRAM_GZOFFZ , SlMeasureAveValueA[1] ) ; // Z axis Gyro offset + RamWrite32A( ACCLRAM_X_AC_OFFSET , SlMeasureAveValueA[2] ) ; // X axis Accel offset + RamWrite32A( ACCLRAM_Y_AC_OFFSET , SlMeasureAveValueB[2] ) ; // Y axis Accel offset + RamWrite32A( ACCLRAM_Z_AC_OFFSET , SlMeasureAveValueB[1] - (INT_32)GSENS ) ; // Z axis Accel offset + + RamWrite32A( GYRO_RAM_GYROX_OFFSET , 0x00000000 ) ; // X axis Drift Gyro offset + RamWrite32A( GYRO_RAM_GYROY_OFFSET , 0x00000000 ) ; // Y axis Drift Gyro offset + RamWrite32A( GyroRAM_Z_GYRO_OFFSET , 0x00000000 ) ; // Z axis Drift Gyro offset + RamWrite32A( GyroFilterDelayX_GXH1Z2 , 0x00000000 ) ; // X axis H1Z2 Clear + RamWrite32A( GyroFilterDelayY_GYH1Z2 , 0x00000000 ) ; // Y axis H1Z2 Clear + RamWrite32A( AcclFilDly_X + 8 , 0x00000000 ) ; // X axis Accl LPF Clear + RamWrite32A( AcclFilDly_Y + 8 , 0x00000000 ) ; // Y axis Accl LPF Clear + RamWrite32A( AcclFilDly_Z + 8 , 0x00000000 ) ; // Z axis Accl LPF Clear + RamWrite32A( AcclFilDly_X + 12 , 0x00000000 ) ; // X axis Accl LPF Clear + RamWrite32A( AcclFilDly_Y + 12 , 0x00000000 ) ; // Y axis Accl LPF Clear + RamWrite32A( AcclFilDly_Z + 12 , 0x00000000 ) ; // Z axis Accl LPF Clear + RamWrite32A( AcclFilDly_X + 16 , 0x00000000 ) ; // X axis Accl LPF Clear + RamWrite32A( AcclFilDly_Y + 16 , 0x00000000 ) ; // Y axis Accl LPF Clear + RamWrite32A( AcclFilDly_Z + 16 , 0x00000000 ) ; // Z axis Accl LPF Clear + RamWrite32A( AcclFilDly_X + 20 , 0x00000000 ) ; // X axis Accl LPF Clear + RamWrite32A( AcclFilDly_Y + 20 , 0x00000000 ) ; // Y axis Accl LPF Clear + RamWrite32A( AcclFilDly_Z + 20 , 0x00000000 ) ; // Z axis Accl LPF Clear + } + return( UlRsltSts ); + + +} +#endif //SEL_SHIFT_COR + +//******************************************************************************** +// Function Name : RtnCen +// Retun Value : Command Status +// Argment Value : Command Parameter +// Explanation : Return to center Command Function +// History : First edition +//******************************************************************************** +UINT_8 RtnCen( UINT_8 UcCmdPar ) +{ + UINT_8 UcSndDat = FAILURE; + + if( !UcCmdPar ){ // X,Y centering + RamWrite32A( CMD_RETURN_TO_CENTER , BOTH_SRV_ON ) ; + }else if( UcCmdPar == XONLY_ON ){ // only X centering + RamWrite32A( CMD_RETURN_TO_CENTER , XAXS_SRV_ON ) ; + }else if( UcCmdPar == YONLY_ON ){ // only Y centering + RamWrite32A( CMD_RETURN_TO_CENTER , YAXS_SRV_ON ) ; + }else{ // Both off + RamWrite32A( CMD_RETURN_TO_CENTER , BOTH_SRV_OFF ) ; + } + + do { + UcSndDat = RdStatus(1); + } while( UcSndDat == FAILURE ); + +TRACE("RtnCen() = %02x\n", UcSndDat ) ; + return( UcSndDat ); +} + + + +//******************************************************************************** +// Function Name : OisEna +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function +// History : First edition +//******************************************************************************** +void OisEna( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" OisEna( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : OisEnaNCL +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function w/o delay clear +// History : First edition +//******************************************************************************** +void OisEnaNCL( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENA_NCL | OIS_ENABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" OisEnaNCL( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : OisEnaDrCl +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function force drift cancel +// History : First edition +//******************************************************************************** +void OisEnaDrCl( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENA_DOF | OIS_ENABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" OisEnaDrCl( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : OisEnaDrNcl +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Enable Control Function w/o delay clear and force drift cancel +// History : First edition +//******************************************************************************** +void OisEnaDrNcl( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_OIS_ENABLE , OIS_ENA_DOF | OIS_ENA_NCL | OIS_ENABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" OisEnaDrCl( Status) = %02x\n", UcStRd ) ; +} +//******************************************************************************** +// Function Name : OisDis +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS Disable Control Function +// History : First edition +//******************************************************************************** +void OisDis( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_OIS_ENABLE , OIS_DISABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" OisDis( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : OisPause +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : OIS pause Control Function +// History : First edition +//******************************************************************************** +void OisPause( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_OIS_ENABLE , OIS_DIS_PUS ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" OisPause( Status , cnt ) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : SscEna +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Ssc Enable Control Function +// History : First edition +//******************************************************************************** +void SscEna( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_SSC_ENABLE , SSC_ENABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" SscEna( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : SscDis +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Ssc Disable Control Function +// History : First edition +//******************************************************************************** +void SscDis( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_SSC_ENABLE , SSC_DISABLE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" SscDis( Status) = %02x\n", UcStRd ) ; +} + + +//******************************************************************************** +// Function Name : SetRec +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Rec Mode Enable Function +// History : First edition +//******************************************************************************** +void SetRec( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" SetRec( Status) = %02x\n", UcStRd ) ; +} + + +//******************************************************************************** +// Function Name : SetStill +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Set Still Mode Enable Function +// History : First edition +//******************************************************************************** +void SetStill( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE ) ; + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" SetRec( Status) = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : SetRecPreview +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Rec Preview Mode Enable Function +// History : First edition +//******************************************************************************** +void SetRecPreview( UINT_8 mode ) +{ + UINT_8 UcStRd = 1; + + switch( mode ){ + case 0: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE ) ; + break; + case 1: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE1 ) ; + break; + case 2: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE2 ) ; + break; + case 3: + RamWrite32A( CMD_MOVE_STILL_MODE , MOVIE_MODE3 ) ; + break; + } + while( UcStRd ) { + UcStRd = RdStatus(1); + } +//TRACE(" SetRec( %02x ) = %02x\n", mode , UcStRd ) ; +} + + +//******************************************************************************** +// Function Name : SetStillPreview +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Set Still Preview Mode Enable Function +// History : First edition +//******************************************************************************** +void SetStillPreview( UINT_8 mode ) +{ + UINT_8 UcStRd = 1; + + switch( mode ){ + case 0: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE ) ; + break; + case 1: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE1 ) ; + break; + case 2: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE2 ) ; + break; + case 3: + RamWrite32A( CMD_MOVE_STILL_MODE , STILL_MODE3 ) ; + break; + } + while( UcStRd ) { + UcStRd = RdStatus(1); + } +//TRACE(" SetRec( %02x ) = %02x\n", mode , UcStRd ) ; +} + + +//******************************************************************************** +// Function Name : SetStandbyMode +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Set Standby mode Function +// History : First edition +//******************************************************************************** +void SetStandbyMode( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_STANDBY_ENABLE , STANDBY_MODE ) ; // Standby + while( UcStRd ) { + UcStRd = RdStatus(1); + } +//TRACE(" SetStandbyMode = %02x\n", UcStRd ) ; +} +//******************************************************************************** +// Function Name : SetActiveMode +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Set Active mode Function +// History : First edition +//******************************************************************************** +void SetActiveMode( void ) +{ + UINT_8 UcStRd = 1; + + RamWrite32A( CMD_IO_ADR_ACCESS, ADDA_FSCTRL ) ; + RamWrite32A( CMD_IO_DAT_ACCESS, 0x00000090 ) ; + RamWrite32A( CMD_STANDBY_ENABLE , ACTIVE_MODE ) ; // Active + while( UcStRd ) { + UcStRd = RdStatus(1); + } +//TRACE(" SetActiveMode = %02x\n", UcStRd ) ; +} + +//******************************************************************************** +// Function Name : SetSinWavePara +// Retun Value : NON +// Argment Value : NON +// Explanation : Sine wave Test Function +// History : First edition +//******************************************************************************** + /********* Parameter Setting *********/ + /* Servo Sampling Clock = 20.0195kHz */ + /* Freq = SinFreq*80000000h/Fs */ + /* 05 00 XX MM XX:Freq MM:Sin or Circle */ +#if FS_MODE == 0 +const UINT_32 CucFreqVal[ 17 ] = { + 0xFFFFFFFF, // 0: Stop + 0x0001D0E1, // 1: 1Hz + 0x0003A1C3, // 2: 2Hz + 0x000572A5, // 3: 3Hz + 0x00074387, // 4: 4Hz + 0x00091468, // 5: 5Hz + 0x000AE54A, // 6: 6Hz + 0x000CB62C, // 7: 7Hz + 0x000E870E, // 8: 8Hz + 0x001057EF, // 9: 9Hz + 0x001228D1, // A: 10Hz + 0x0013F9B3, // B: 11Hz + 0x0015CA95, // C: 12Hz + 0x00179B76, // D: 13Hz + 0x00196C58, // E: 14Hz + 0x001B3D3A, // F: 15Hz + 0x001D0E1C // 10: 16Hz + } ; +#else //FS_MODE +const UINT_32 CucFreqVal[ 17 ] = { + 0xFFFFFFFF, // 0: Stop + 0x00022E39, // 1: 1Hz + 0x00045C72, // 2: 2Hz + 0x00068AAB, // 3: 3Hz + 0x0008B8E5, // 4: 4Hz + 0x000AE71E, // 5: 5Hz + 0x000D1557, // 6: 6Hz + 0x000F4390, // 7: 7Hz + 0x001171CA, // 8: 8Hz + 0x0013A003, // 9: 9Hz + 0x0015CE3C, // A: 10Hz + 0x0017FC76, // B: 11Hz + 0x001A2AAF, // C: 12Hz + 0x001C58E8, // D: 13Hz + 0x001E8721, // E: 14Hz + 0x0020B55B, // F: 15Hz + 0x0022E394 // 10: 16Hz + } ; +#endif //FS_MODE + +// RamWrite32A( SinWave.Gain , 0x00000000 ) ; // Gain‚Í‚»‚ꂼ‚êÝ’è‚·‚邱‚Æ +// RamWrite32A( CosWave.Gain , 0x00000000 ) ; // Gain‚Í‚»‚ꂼ‚êÝ’è‚·‚邱‚Æ +void SetSinWavePara( UINT_8 UcTableVal , UINT_8 UcMethodVal ) +{ + UINT_32 UlFreqDat ; + + + if(UcTableVal > 0x10 ) + UcTableVal = 0x10 ; /* Limit */ + UlFreqDat = CucFreqVal[ UcTableVal ] ; + + if( UcMethodVal == CIRCWAVE) { + RamWrite32A( SinWave_Phase , 0x00000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( CosWave_Phase , 0x20000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + }else{ + RamWrite32A( SinWave_Phase , 0x00000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( CosWave_Phase , 0x00000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + } + + + if( UlFreqDat == 0xFFFFFFFF ) /* Sine”g’†Ž~ */ + { + RamWrite32A( SinWave_Offset , 0x00000000 ) ; // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( SinWave_Phase , 0x00000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê +// RamWrite32A( SinWave_Gain , 0x00000000 ) ; // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚Í0[dB]) +// SetTransDataAdr( SinWave_OutAddr , (UINT_32)SinWave_Output ); // o—ÍæƒAƒhƒŒƒX + + RamWrite32A( CosWave_Offset , 0x00000000 ); // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( CosWave_Phase , 0x00000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê +// RamWrite32A( CosWave_Gain , 0x00000000 ); // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚ÍCut) +// SetTransDataAdr( CosWave_OutAddr , (UINT_32)CosWave_Output ); // o—ÍæƒAƒhƒŒƒX + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + SetTransDataAdr( SinWave_OutAddr , 0x00000000 ) ; // o—ÍæƒAƒhƒŒƒX + SetTransDataAdr( CosWave_OutAddr , 0x00000000 ); // o—ÍæƒAƒhƒŒƒX + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; // DelayRam Clear + } + else + { + RamWrite32A( SinWave_Offset , UlFreqDat ) ; // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( CosWave_Offset , UlFreqDat ); // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HXOFF1 ) ; // o—ÍæƒAƒhƒŒƒX + SetTransDataAdr( CosWave_OutAddr , (UINT_32)HALL_RAM_HYOFF1 ); // o—ÍæƒAƒhƒŒƒX + + } + + +} + + + + +//******************************************************************************** +// Function Name : SetPanTiltMode +// Retun Value : NON +// Argment Value : NON +// Explanation : Pan-Tilt Enable/Disable +// History : First edition +//******************************************************************************** +void SetPanTiltMode( UINT_8 UcPnTmod ) +{ + UINT_8 UcStRd = 1; + + switch ( UcPnTmod ) { + case OFF : + RamWrite32A( CMD_PAN_TILT , PAN_TILT_OFF ) ; + break ; + case ON : + RamWrite32A( CMD_PAN_TILT , PAN_TILT_ON ) ; + break ; + } + + while( UcStRd ) { + UcStRd = RdStatus(1); + } +TRACE(" PanTilt( Status) = %02x , %02x \n", UcStRd , UcPnTmod ) ; +} + + #ifdef NEUTRAL_CENTER +//******************************************************************************** +// Function Name : TneHvc +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Hall VC offset +// History : First edition +//******************************************************************************** +UINT_8 TneHvc( void ) +{ + UINT_8 UcRsltSts; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureAveValueA , SlMeasureAveValueB ; + + RtnCen( BOTH_OFF ) ; // Both OFF + + WitTim( 500 ) ; + + //•½‹Ï’l‘ª’è + + MesFil( THROUGH ) ; // Set Measure Filter + + SlMeasureParameterNum = 64 ; // 64times + SlMeasureParameterA = (UINT_32)HALL_RAM_HXIDAT ; // Set Measure RAM Address + SlMeasureParameterB = (UINT_32)HALL_RAM_HYIDAT ; // Set Measure RAM Address + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; // Start measure + + ClrMesFil(); // Clear Delay RAM + SetWaitTime(50) ; + + MeasureWait() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT_32)((( (INT_64)StMeasValueA.UllnValue * 100 ) / SlMeasureParameterNum ) / 100 ) ; + SlMeasureAveValueB = (INT_32)((( (INT_64)StMeasValueB.UllnValue * 100 ) / SlMeasureParameterNum ) / 100 ) ; + + StAdjPar.StHalAdj.UsHlxCna = ( UINT_16 )(( SlMeasureAveValueA >> 16 ) & 0x0000FFFF ); //Measure Result Store + StAdjPar.StHalAdj.UsHlxCen = StAdjPar.StHalAdj.UsHlxCna; //Measure Result Store + + StAdjPar.StHalAdj.UsHlyCna = ( UINT_16 )(( SlMeasureAveValueB >> 16 ) & 0x0000FFFF ); //Measure Result Store + StAdjPar.StHalAdj.UsHlyCen = StAdjPar.StHalAdj.UsHlyCna; //Measure Result Store + + RamWrite32A( HALL_RAM_HXOFF, (UINT_32)((StAdjPar.StHalAdj.UsHlxCen << 16 ) & 0xFFFF0000 )) ; + RamWrite32A( HALL_RAM_HYOFF, (UINT_32)((StAdjPar.StHalAdj.UsHlyCen << 16 ) & 0xFFFF0000 )) ; + + UcRsltSts = EXE_END ; // Clear Status + + return( UcRsltSts ); +} + #endif //NEUTRAL_CENTER + + #ifdef NEUTRAL_CENTER_FINE +//******************************************************************************** +// Function Name : TneFin +// Retun Value : NON +// Argment Value : NON +// Explanation : Tunes the Hall VC offset current optimize +// History : First edition +//******************************************************************************** +#define ADOFF_FINE_NUM 2000 +void TneFin( ADJ_LOPGAN* ptr ) +{ + UINT_32 UlReadVal ; + UINT_16 UsAdxOff, UsAdyOff ; + INT_32 SlMeasureAveValueA , SlMeasureAveValueB ; + UnllnVal StMeasValueA , StMeasValueB ; + UINT_32 UlMinimumValueA, UlMinimumValueB ; + UINT_16 UsAdxMin, UsAdyMin ; + UINT_8 UcFin ; + + // Loop gain set for servo + RamWrite32A( HallFilterCoeffX_hxgain0 , ptr->Hxgain ) ; + RamWrite32A( HallFilterCoeffY_hygain0 , ptr->Hygain ) ; + + // Get natural center offset + RamRead32A( HALL_RAM_HXOFF, &UlReadVal ) ; + UsAdxOff = UsAdxMin = (UINT_16)( UlReadVal >> 16 ) ; + + RamRead32A( HALL_RAM_HYOFF, &UlReadVal ) ; + UsAdyOff = UsAdyMin = (UINT_16)( UlReadVal >> 16 ) ; +//TRACE("*****************************************************\n" ); +//TRACE("TneFin: Before Adx=%04X, Ady=%04X\n", UsAdxOff, UsAdyOff ); + + // Servo ON + RtnCen( BOTH_ON ) ; + WitTim( TNE ) ; + + MesFil( THROUGH ) ; // Filter setting for measurement + MeasureStart( ADOFF_FINE_NUM , HALL_RAM_HALL_X_OUT , HALL_RAM_HALL_Y_OUT ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + SlMeasureAveValueA = (INT_32)((( (INT_64)StMeasValueA.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; + + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + SlMeasureAveValueB = (INT_32)((( (INT_64)StMeasValueB.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; + + UlMinimumValueA = abs(SlMeasureAveValueA) ; + UlMinimumValueB = abs(SlMeasureAveValueB) ; + UcFin = 0x11 ; + + while( UcFin ) { + if( UcFin & 0x01 ) { + if( UlMinimumValueA >= abs(SlMeasureAveValueA) ) { + UlMinimumValueA = abs(SlMeasureAveValueA) ; + UsAdxMin = UsAdxOff ; + // Žû‘©‚ð‘‚߂邽‚ß‚ÉAo—Í’l‚É”ä—Ⴓ‚¹‚é + if( SlMeasureAveValueA > 0 ) + UsAdxOff = (INT_16)UsAdxOff + (SlMeasureAveValueA >> 17) + 1 ; + else + UsAdxOff = (INT_16)UsAdxOff + (SlMeasureAveValueA >> 17) - 1 ; + + RamWrite32A( HALL_RAM_HXOFF, (UINT_32)((UsAdxOff << 16 ) & 0xFFFF0000 )) ; + } else { +//TRACE("X fine\n"); + UcFin &= 0xFE ; + } + } + + if( UcFin & 0x10 ) { + if( UlMinimumValueB >= abs(SlMeasureAveValueB) ) { + UlMinimumValueB = abs(SlMeasureAveValueB) ; + UsAdyMin = UsAdyOff ; + // Žû‘©‚ð‘‚߂邽‚ß‚ÉAo—Í’l‚É”ä—Ⴓ‚¹‚é + if( SlMeasureAveValueB > 0 ) + UsAdyOff = (INT_16)UsAdyOff + (SlMeasureAveValueB >> 17) + 1 ; + else + UsAdyOff = (INT_16)UsAdyOff + (SlMeasureAveValueB >> 17) - 1 ; + + RamWrite32A( HALL_RAM_HYOFF, (UINT_32)((UsAdyOff << 16 ) & 0xFFFF0000 )) ; + } else { +//TRACE("Y fine\n"); + UcFin &= 0xEF ; + } + } + + MeasureStart( ADOFF_FINE_NUM , HALL_RAM_HALL_X_OUT , HALL_RAM_HALL_Y_OUT ) ; // Start measure + MeasureWait() ; // Wait complete of measurement + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + SlMeasureAveValueA = (INT_32)((( (INT_64)StMeasValueA.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; + + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + SlMeasureAveValueB = (INT_32)((( (INT_64)StMeasValueB.UllnValue * 100 ) / ADOFF_FINE_NUM ) / 100 ) ; +//TRACE("-->Adx %04X, Ady %04X\n", UsAdxOff, UsAdyOff ); + } // while +//TRACE("TneFin: After Adx=%04X, Ady=%04X\n", UsAdxMin, UsAdyMin ); + StAdjPar.StHalAdj.UsHlxCna = UsAdxMin; //Measure Result Store + StAdjPar.StHalAdj.UsHlxCen = StAdjPar.StHalAdj.UsHlxCna; //Measure Result Store + + StAdjPar.StHalAdj.UsHlyCna = UsAdyMin; //Measure Result Store + StAdjPar.StHalAdj.UsHlyCen = StAdjPar.StHalAdj.UsHlyCna; //Measure Result Store + + StAdjPar.StHalAdj.UsAdxOff = StAdjPar.StHalAdj.UsHlxCna ; + StAdjPar.StHalAdj.UsAdyOff = StAdjPar.StHalAdj.UsHlyCna ; + + // Servo OFF + RtnCen( BOTH_OFF ) ; // Both OFF + + +TRACE(" XadofFin = %04xh \n", StAdjPar.StHalAdj.UsAdxOff ) ; +TRACE(" YadofFin = %04xh \n", StAdjPar.StHalAdj.UsAdyOff ) ; + RamWrite32A( HALL_RAM_HXOFF, (UINT_32)((StAdjPar.StHalAdj.UsAdxOff << 16 ) & 0xFFFF0000 )) ; + RamWrite32A( HALL_RAM_HYOFF, (UINT_32)((StAdjPar.StHalAdj.UsAdyOff << 16 ) & 0xFFFF0000 )) ; + +} + #endif //NEUTRAL_CENTER_FINE + + +//******************************************************************************** +// Function Name : TneSltPos +// Retun Value : NON +// Argment Value : Position number(1, 2, 3, 4, 5, 6, 7, 0:reset) +// Explanation : Move measurement position function +//******************************************************************************** +void TneSltPos( UINT_8 UcPos ) +{ + INT_16 SsOff = 0x0000 ; + INT_32 SlX, SlY; + DSPVER Info; + LINCRS TEMP = {0, 0, 0, 0, 0}; //20190718 Komori + LINCRS* LnCsPtr = (LINCRS*)&TEMP; //20190718 Komori + + GetInfomationAfterStartUp( &Info ); + + UcPos &= 0x07 ; + + if ( UcPos ) { + SsOff = LnCsPtr->STEPX * (UcPos - 4); +// SsOff = (INT_16)(SsOff / sqrt(2)); // for circle limit(root2) + } + + SsNvcX = LnCsPtr->DRIVEX; + SsNvcY = LnCsPtr->DRIVEY; + + SlX = (INT_32)((SsOff * SsNvcX) << 16); + SlY = (INT_32)((SsOff * SsNvcY) << 16); + + RamWrite32A( HALL_RAM_GYROX_OUT, SlX ) ; + RamWrite32A( HALL_RAM_GYROY_OUT, SlY ) ; + +} + +//******************************************************************************** +// Function Name : TneVrtPos +// Retun Value : NON +// Argment Value : Position number(1, 2, 3, 4, 5, 6, 7, 0:reset) +// Explanation : Move measurement position function +//******************************************************************************** +void TneVrtPos( UINT_8 UcPos ) +{ + INT_16 SsOff = 0x0000 ; + INT_32 SlX, SlY; + DSPVER Info; + LINCRS TEMP = {0, 0, 0, 0, 0}; //20190718 Komori + LINCRS* LnCsPtr = (LINCRS*)&TEMP; //20190718 Komori + + GetInfomationAfterStartUp( &Info ); + + UcPos &= 0x07 ; + + if ( UcPos ) { + SsOff = (INT_16)LnCsPtr->STEPY * LnCsPtr->DRIVEY * (UcPos - 4); + } + + SlX = 0x00000000; + SlY = (INT_32)(SsOff << 16); + + RamWrite32A( HALL_RAM_GYROX_OUT, SlX ) ; + RamWrite32A( HALL_RAM_GYROY_OUT, SlY ) ; +} + +//******************************************************************************** +// Function Name : TneHrzPos +// Retun Value : NON +// Argment Value : Position number(1, 2, 3, 4, 5, 6, 7, 0:reset) +// Explanation : Move measurement position function +//******************************************************************************** +void TneHrzPos( UINT_8 UcPos ) +{ + INT_16 SsOff = 0x0000 ; + INT_32 SlX, SlY; + DSPVER Info; + LINCRS TEMP = {0, 0, 0, 0, 0}; //20190718 Komori + LINCRS* LnCsPtr = (LINCRS*)&TEMP; //20190718 Komori + + GetInfomationAfterStartUp( &Info ); + + UcPos &= 0x07 ; + + if ( UcPos ) { + SsOff = (INT_16)LnCsPtr->STEPX * LnCsPtr->DRIVEX * (UcPos - 4); + } + + SlX = (INT_32)(SsOff << 16); + SlY = 0x00000000; + + RamWrite32A( HALL_RAM_GYROX_OUT, SlX ) ; + RamWrite32A( HALL_RAM_GYROY_OUT, SlY ) ; +} + +//******************************************************************************** +// Function Name : SetSinWavGenInt +// Retun Value : NON +// Argment Value : NON +// Explanation : Sine wave generator initial Function +// History : First edition +//******************************************************************************** +void SetSinWavGenInt( void ) +{ + + RamWrite32A( SinWave_Offset , 0x00000000 ) ; // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( SinWave_Phase , 0x60000000 ) ; // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( SinWave_Gain , 0x00000000 ) ; // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚Í0[dB]) +// RamWrite32A( SinWave_Gain , 0x7FFFFFFF ) ; // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚ÍCut) +// SetTransDataAdr( SinWave_OutAddr , (UINT_32)SinWave_Output ) ; // ‰Šú’l‚Ìo—ÍæƒAƒhƒŒƒX‚ÍAŽ©•ª‚̃ƒ“ƒo + + RamWrite32A( CosWave_Offset , 0x00000000 ); // ”­¶Žü”g”‚̃IƒtƒZƒbƒg‚ðÝ’è + RamWrite32A( CosWave_Phase , 0x00000000 ); // ³Œ·”g‚ÌˆÊ‘Š—Ê + RamWrite32A( CosWave_Gain , 0x00000000 ); // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚ÍCut) +// RamWrite32A( CosWave_Gain , 0x7FFFFFFF ); // ”­¶Žü”g”‚̃Aƒbƒeƒl[ƒ^(‰Šú’l‚Í0[dB]) +// SetTransDataAdr( CosWave_OutAddr , (UINT_32)CosWave_Output ); // ‰Šú’l‚Ìo—ÍæƒAƒhƒŒƒX‚ÍAŽ©•ª‚̃ƒ“ƒo + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + +} + + +//******************************************************************************** +// Function Name : SetTransDataAdr +// Retun Value : NON +// Argment Value : NON +// Explanation : Trans Address for Data Function +// History : First edition +//******************************************************************************** +void SetTransDataAdr( UINT_16 UsLowAddress , UINT_32 UlLowAdrBeforeTrans ) +{ + UnDwdVal StTrsVal ; + + if( UlLowAdrBeforeTrans < 0x00009000 ){ + StTrsVal.StDwdVal.UsHigVal = (UINT_16)(( UlLowAdrBeforeTrans & 0x0000F000 ) >> 8 ) ; + StTrsVal.StDwdVal.UsLowVal = (UINT_16)( UlLowAdrBeforeTrans & 0x00000FFF ) ; + }else{ + StTrsVal.UlDwdVal = UlLowAdrBeforeTrans ; + } +//TRACE(" TRANS ADR = %04xh , DAT = %08xh \n",UsLowAddress , StTrsVal.UlDwdVal ) ; + RamWrite32A( UsLowAddress , StTrsVal.UlDwdVal ); + +} + + +//******************************************************************************** +// Function Name : RdStatus +// Retun Value : 0:success 1:FAILURE +// Argment Value : bit check 0:ALL 1:bit24 +// Explanation : High level status check Function +// History : First edition +//******************************************************************************** +UINT_8 RdStatus( UINT_8 UcStBitChk ) +{ + UINT_32 UlReadVal ; + + RamRead32A( CMD_READ_STATUS , &UlReadVal ); +TRACE(" (Rd St) = %08x\n", (UINT_32)UlReadVal ) ; + if( UcStBitChk ){ + UlReadVal &= READ_STATUS_INI ; + } + if( !UlReadVal ){ + return( SUCCESS ); + }else{ + return( FAILURE ); + } +} + + +//******************************************************************************** +// Function Name : DacControl +// Retun Value : Firmware version +// Argment Value : NON +// Explanation : Dac Control Function +// History : First edition +//******************************************************************************** +void DacControl( UINT_8 UcMode, UINT_32 UiChannel, UINT_32 PuiData ) +{ + UINT_32 UlAddaInt ; + if( !UcMode ) { + RamWrite32A( CMD_IO_ADR_ACCESS , ADDA_DASEL ) ; + RamWrite32A( CMD_IO_DAT_ACCESS , UiChannel ) ; + RamWrite32A( CMD_IO_ADR_ACCESS , ADDA_DAO ) ; + RamWrite32A( CMD_IO_DAT_ACCESS , PuiData ) ; + ; + ; + UlAddaInt = 0x00000040 ; + while ( (UlAddaInt & 0x00000040) != 0 ) { + RamWrite32A( CMD_IO_ADR_ACCESS , ADDA_ADDAINT ) ; + RamRead32A( CMD_IO_DAT_ACCESS , &UlAddaInt ) ; + ; + } + } else { + RamWrite32A( CMD_IO_ADR_ACCESS , ADDA_DASEL ) ; + RamWrite32A( CMD_IO_DAT_ACCESS , UiChannel ) ; + RamWrite32A( CMD_IO_ADR_ACCESS , ADDA_DAO ) ; + RamRead32A( CMD_IO_DAT_ACCESS , &PuiData ) ; + ; + ; + UlAddaInt = 0x00000040 ; + while ( (UlAddaInt & 0x00000040) != 0 ) { + RamWrite32A( CMD_IO_ADR_ACCESS , ADDA_ADDAINT ) ; + RamRead32A( CMD_IO_DAT_ACCESS , &UlAddaInt ) ; + ; + } + } + + return ; +} + +//******************************************************************************** +// Function Name : RdHallCalData +// Retun Value : Read calibration data +// Argment Value : NON +// Explanation : Read calibration Data Function +// History : First edition +//******************************************************************************** +void RdHallCalData( void ) +{ + UnDwdVal StReadVal ; + + RamRead32A( StCaliData_UsCalibrationStatus, &StAdjPar.StHalAdj.UlAdjPhs ) ; + +// RamRead32A( StCaliData_SiHallMax_Before_X, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlxMax = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMin_Before_X, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlxMin = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMax_After_X, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlxMxa = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMin_After_X, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlxMna = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMax_Before_Y, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlyMax = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMin_Before_Y, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlyMin = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMax_After_Y, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlyMxa = StReadVal.StDwdVal.UsHigVal ; +// RamRead32A( StCaliData_SiHallMin_After_Y, &StReadVal.UlDwdVal ) ; +// StAdjPar.StHalAdj.UsHlyMna = StReadVal.StDwdVal.UsHigVal ; + RamRead32A( StCaliData_UiHallBias_X, &StReadVal.UlDwdVal ) ; + StAdjPar.StHalAdj.UsHlxGan = StReadVal.StDwdVal.UsHigVal ; + RamRead32A( StCaliData_UiHallOffset_X, &StReadVal.UlDwdVal ) ; + StAdjPar.StHalAdj.UsHlxOff = StReadVal.StDwdVal.UsHigVal ; + RamRead32A( StCaliData_UiHallBias_Y, &StReadVal.UlDwdVal ) ; + StAdjPar.StHalAdj.UsHlyGan = StReadVal.StDwdVal.UsHigVal ; + RamRead32A( StCaliData_UiHallOffset_Y, &StReadVal.UlDwdVal ) ; + StAdjPar.StHalAdj.UsHlyOff = StReadVal.StDwdVal.UsHigVal ; + + RamRead32A( StCaliData_SiLoopGain_X, &StAdjPar.StLopGan.UlLxgVal ) ; + RamRead32A( StCaliData_SiLoopGain_Y, &StAdjPar.StLopGan.UlLygVal ) ; + + RamRead32A( StCaliData_SiLensCen_Offset_X, &StReadVal.UlDwdVal ) ; + StAdjPar.StHalAdj.UsAdxOff = StReadVal.StDwdVal.UsHigVal ; + RamRead32A( StCaliData_SiLensCen_Offset_Y, &StReadVal.UlDwdVal ) ; + StAdjPar.StHalAdj.UsAdyOff = StReadVal.StDwdVal.UsHigVal ; + + RamRead32A( StCaliData_SiGyroOffset_X, &StReadVal.UlDwdVal ) ; + StAdjPar.StGvcOff.UsGxoVal = StReadVal.StDwdVal.UsHigVal ; + RamRead32A( StCaliData_SiGyroOffset_Y, &StReadVal.UlDwdVal ) ; + StAdjPar.StGvcOff.UsGyoVal = StReadVal.StDwdVal.UsHigVal ; + +} + + + +//******************************************************************************** +// Function Name : OscStb +// Retun Value : NON +// Argment Value : Command Parameter +// Explanation : Osc Standby Function +// History : First edition +//******************************************************************************** +void OscStb( void ) +{ + RamWrite32A( CMD_IO_ADR_ACCESS , STBOSCPLL ) ; + RamWrite32A( CMD_IO_DAT_ACCESS , OSC_STB ) ; +} + +#if 0 +//******************************************************************************** +// Function Name : GyrSlf +// Retun Value : Gyro self test SUCCESS or FAILURE +// Argment Value : NON +// Explanation : Gyro self test Function +// History : First edition 2016.8.3 +//******************************************************************************** +UINT_8 GyrSlf( void ) +{ + UINT_8 UcFinSts = 0 ; + float flGyrRltX ; + float flGyrRltY ; + float flMeasureAveValueA , flMeasureAveValueB ; + INT_32 SlMeasureParameterNum ; + INT_32 SlMeasureParameterA, SlMeasureParameterB ; + UnllnVal StMeasValueA , StMeasValueB ; + UINT_32 UlReadVal; + + // Setup for self test + RamWrite32A( 0xF01D, 0x75000000 ); // Read who am I + while( RdStatus( 0 ) ) ; + + RamRead32A ( 0xF01D, &UlReadVal ); + + if( (UlReadVal >> 24) != 0x85 ) + { + TRACE("WHO AM I read error %08X\n", UlReadVal ); + return (0xFF); + } + + // Pre test + RamWrite32A( 0xF01E, 0x1B100000 ); // GYRO_CONFIG FS_SEL=2(175LSB/dps) XG_ST=OFF YG_ST=OFF + while( RdStatus( 0 ) ) ; + + MesFil( SELFTEST ) ; + + SlMeasureParameterNum = 20 * 4; // 20 sample * 4FS ( 40ms ) + SlMeasureParameterA = (UINT_32)GYRO_RAM_GX_ADIDAT ; // Set Measure RAM Address + SlMeasureParameterB = (UINT_32)GYRO_RAM_GY_ADIDAT ; // Set Measure RAM Address + + ClrMesFil() ; // Clear Delay Ram + WitTim( 300 ) ; + + RamWrite32A( StMeasFunc_PMC_UcPhaseMesMode, 0x00000000 ) ; // Set Phase Measure Mode + + // Start measure + MeasureStart( SlMeasureParameterNum, SlMeasureParameterA , SlMeasureParameterB ) ; + MeasureWait() ; // Wait complete of measurement + + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + flMeasureAveValueA = (float)((( (INT_64)StMeasValueA.UllnValue >> 16 ) / (float)SlMeasureParameterNum ) ) ; + flMeasureAveValueB = (float)((( (INT_64)StMeasValueB.UllnValue >> 16 ) / (float)SlMeasureParameterNum ) ) ; + + flGyrRltX = flMeasureAveValueA / 175.0 ; // sensitivity 175 dps + flGyrRltY = flMeasureAveValueB / 175.0 ; // sensitivity 175 dps + + TRACE("SlMeasureParameterNum = %08X\n", (UINT_32)SlMeasureParameterNum); + TRACE("StMeasValueA.StUllnVal.UlLowVal = %08X\n", (UINT_32)StMeasValueA.StUllnVal.UlLowVal); + TRACE("StMeasValueA.StUllnVal.UlHigVal = %08X\n", (UINT_32)StMeasValueA.StUllnVal.UlHigVal); + TRACE("StMeasValueB.StUllnVal.UlLowVal = %08X\n", (UINT_32)StMeasValueB.StUllnVal.UlLowVal); + TRACE("StMeasValueB.StUllnVal.UlHigVal = %08X\n", (UINT_32)StMeasValueB.StUllnVal.UlHigVal); + TRACE("flMeasureAveValueA = %f\n", flMeasureAveValueA ); + TRACE("flMeasureAveValueB = %f\n", flMeasureAveValueB ); + TRACE("flGyrRltX = %f dps\n", flGyrRltX ); + TRACE("flGyrRltY = %f dps\n", flGyrRltY ); + + if( fabs(flGyrRltX) >= 25 ){ + UcFinSts |= 0x10; + TRACE( "X self test 175dps NG\n" ); + } + + if( fabs(flGyrRltY) >= 25 ){ + UcFinSts |= 0x01; + TRACE( "Y self test 175dps NG\n" ); + } + + // Self test main + RamWrite32A( 0xF01E, 0x1BDB0000 ); // GYRO_CONFIG FS_SEL=3(87.5LSB/dps) XG_ST=ON YG_ST=ON + while( RdStatus( 0 ) ) ; + + ClrMesFil() ; // Clear Delay Ram + WitTim( 300 ) ; + + RamWrite32A( StMeasFunc_PMC_UcPhaseMesMode, 0x00000000 ) ; // Set Phase Measure Mode + + // Start measure + MeasureStart( SlMeasureParameterNum, SlMeasureParameterA , SlMeasureParameterB ) ; + MeasureWait() ; // Wait complete of measurement + + + RamRead32A( StMeasFunc_MFA_LLiIntegral1 , &StMeasValueA.StUllnVal.UlLowVal ) ; // X axis + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + + RamRead32A( StMeasFunc_MFB_LLiIntegral2 , &StMeasValueB.StUllnVal.UlLowVal ) ; // Y axis + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + flMeasureAveValueA = (float)((( (INT_64)StMeasValueA.UllnValue >> 16 ) / (float)SlMeasureParameterNum ) ) ; + flMeasureAveValueB = (float)((( (INT_64)StMeasValueB.UllnValue >> 16 ) / (float)SlMeasureParameterNum ) ) ; + + flGyrRltX = flMeasureAveValueA / GYRO_SENSITIVITY ; + flGyrRltY = flMeasureAveValueB / GYRO_SENSITIVITY ; + + TRACE("SlMeasureParameterNum = %08X\n", (UINT_32)SlMeasureParameterNum); + TRACE("StMeasValueA.StUllnVal.UlLowVal = %08X\n", (UINT_32)StMeasValueA.StUllnVal.UlLowVal); + TRACE("StMeasValueA.StUllnVal.UlHigVal = %08X\n", (UINT_32)StMeasValueA.StUllnVal.UlHigVal); + TRACE("StMeasValueB.StUllnVal.UlLowVal = %08X\n", (UINT_32)StMeasValueB.StUllnVal.UlLowVal); + TRACE("StMeasValueB.StUllnVal.UlHigVal = %08X\n", (UINT_32)StMeasValueB.StUllnVal.UlHigVal); + TRACE("flMeasureAveValueA = %f\n", flMeasureAveValueA ); + TRACE("flMeasureAveValueB = %f\n", flMeasureAveValueB ); + TRACE("flGyrRltX = %f dps\n", flGyrRltX ); + TRACE("flGyrRltY = %f dps\n", flGyrRltY ); + + + if( UcFinSts != 0 ) { + // error 175 dps + if( fabs(flGyrRltX) >= 60){ + UcFinSts |= 0x20; + TRACE( "X self test 87.5dps NG\n" ); + } + + if( fabs(flGyrRltY) >= 60){ + UcFinSts |= 0x02; + TRACE( "Y self test 87.5dps NG\n" ); + } + } else { + // normal + if( fabs(flGyrRltX) < 60){ + UcFinSts |= 0x20; + TRACE( "X self test 87.5dps NG\n" ); + } + + if( fabs(flGyrRltY) < 60){ + UcFinSts |= 0x02; + TRACE( "Y self test 87.5dps NG\n" ); + } + } + + // Set normal mode + RamWrite32A( 0xF01E, 0x1B180000 ); // GYRO_CONFIG FS_SEL=3(87.5LSB/dps) XG_ST=OFF YG_ST=OFF + while( RdStatus( 0 ) ) ; + + + TRACE("GyrSlf result=%02X\n", UcFinSts ); + return( UcFinSts ) ; +} +#endif + +//******************************************************************************** +// Function Name : GyrWhoAmIRead +// Retun Value : Gyro Who am I Read +// Argment Value : NON +// Explanation : Gyro Who am I Read Function +// History : First edition 2016.11.01 +//******************************************************************************** +UINT_8 GyrWhoAmIRead( void ) +{ + UINT_8 UcRtnVal ; + UINT_32 UlReadVal; + + // Setup for self test + RamWrite32A( 0xF01D, 0x75000000 ); // Read who am I + while( RdStatus( 0 ) ) ; + + RamRead32A ( 0xF01D, &UlReadVal ); + + UcRtnVal = UlReadVal >> 24; + +TRACE("WHO AM I read %02X\n", UcRtnVal ); + + return(UcRtnVal); +} + +//******************************************************************************** +// Function Name : GyrWhoAmICheck +// Retun Value : Gyro Who am I Check +// Argment Value : NON +// Explanation : Gyro Who am I Chek Function +// History : First edition 2016.11.01 +//******************************************************************************** +UINT_8 GyrWhoAmICheck( void ) +{ + UINT_8 UcReadVal ; + + UcReadVal = GyrWhoAmIRead(); + + if( UcReadVal == 0x20 ){ // ICM-20690 +TRACE("WHO AM I read success\n"); + return (FAILURE); + } + else{ +TRACE("WHO AM I read failure\n"); + return (SUCCESS); + } +} + +//******************************************************************************** +// Function Name : GyrIdRead +// Retun Value : Gyro ID Read +// Argment Value : NON +// Explanation : Gyro ID Read Function +// History : First edition 2016.11.07 +//******************************************************************************** +UINT_8 GyrIdRead( UINT_8 *UcGyroID ) +{ + UINT_8 i ; + UINT_32 UlReadVal; + + for( i=0; i<7 ; i++ ){ + + // bank_sel + RamWrite32A( 0xF01E, 0x6D000000 ); + while( RdStatus( 0 ) ) ; + + // start_addr + RamWrite32A( 0xF01E, 0x6E000000 | (i << 16) ); + while( RdStatus( 0 ) ) ; + + // mem_r_w + RamWrite32A( 0xF01D, 0x6F000000 ); + while( RdStatus( 0 ) ) ; + + // ID0[7:0] / ID1[7:0] ... ID6[7:0] + RamRead32A ( 0xF01D, &UlReadVal ); + UcGyroID[i] = UlReadVal >> 24; + } + +TRACE("UcGyroID %02X %02X %02X %02X %02X %02X %02X \n", UcGyroID[0], UcGyroID[1], UcGyroID[2], UcGyroID[3], UcGyroID[4], UcGyroID[5], UcGyroID[6] ); + + return(SUCCESS); +} + + +#if 0 +//******************************************************************************** +// Function Name : GyroReCalib +// Retun Value : Command Status +// Argment Value : Offset information data pointer +// Explanation : Re calibration Command Function +// History : First edition +//******************************************************************************** +UINT_8 GyroReCalib( stReCalib * pReCalib ) +{ + UINT_8 UcSndDat ; + UINT_32 UlRcvDat ; + UINT_32 UlGofX, UlGofY ; + UINT_32 UiChkSum ; + +//------------------------------------------------------------------------------------------------ +// Backup ALL Calibration data +//------------------------------------------------------------------------------------------------ + ReadCalData128( UlBufDat, &UiChkSum ); + + // HighLevelƒRƒ}ƒ“ƒh + RamWrite32A( CMD_CALIBRATION , 0x00000000 ) ; + + do { + UcSndDat = RdStatus(1); + } while (UcSndDat != 0); + + RamRead32A( CMD_CALIBRATION , &UlRcvDat ) ; + UcSndDat = (unsigned char)(UlRcvDat >> 24); // I—¹ƒXƒe[ƒ^ƒX + + // –ß‚è’l‚ð•ÒW + if( UlBufDat[ GYRO_FCTRY_OFST_X ] == 0xFFFFFFFF ) + pReCalib->SsFctryOffX = (UlBufDat[ GYRO_OFFSET_X ] >> 16) ; + else + pReCalib->SsFctryOffX = (UlBufDat[ GYRO_FCTRY_OFST_X ] >> 16) ; + + if( UlBufDat[ GYRO_FCTRY_OFST_Y ] == 0xFFFFFFFF ) + pReCalib->SsFctryOffY = (UlBufDat[ GYRO_OFFSET_Y ] >> 16) ; + else + pReCalib->SsFctryOffY = (UlBufDat[ GYRO_FCTRY_OFST_Y ] >> 16) ; + + // ƒLƒƒƒŠƒuƒŒ[ƒVƒ‡ƒ“Œã‚Ì’l‚ðŽæ“¾ + RamRead32A( GYRO_RAM_GXOFFZ , &UlGofX ) ; + RamRead32A( GYRO_RAM_GYOFFZ , &UlGofY ) ; + + pReCalib->SsRecalOffX = (UlGofX >> 16) ; + pReCalib->SsRecalOffY = (UlGofY >> 16) ; + pReCalib->SsDiffX = abs( pReCalib->SsFctryOffX - pReCalib->SsRecalOffX) ; + pReCalib->SsDiffY = abs( pReCalib->SsFctryOffY - pReCalib->SsRecalOffY) ; + +TRACE("GyroReCalib() = %02x\n", UcSndDat ) ; +TRACE("Factory X = %04X, Y = %04X\n", pReCalib->SsFctryOffX, pReCalib->SsFctryOffY ); +TRACE("Recalib X = %04X, Y = %04X\n", pReCalib->SsRecalOffX, pReCalib->SsRecalOffY ); +TRACE("Diff X = %04X, Y = %04X\n", pReCalib->SsDiffX, pReCalib->SsDiffY ); +TRACE("UlBufDat[19] = %08X, [20] = %08X\n", UlBufDat[19], UlBufDat[20] ); +TRACE("UlBufDat[49] = %08X, [50] = %08X\n", UlBufDat[49], UlBufDat[50] ); + + return( UcSndDat ); +} +#endif +//******************************************************************************** +// Function Name : ReadCalibID +// Retun Value : Calibraion ID +// Argment Value : NONE +// Explanation : Read calibraion ID Function +// History : First edition +//******************************************************************************** +UINT_32 ReadCalibID( void ) +{ + UINT_32 UlCalibId; + + // Read calibration data + RamRead32A( SiCalID, &UlCalibId ); + + return( UlCalibId ); +} + + +//******************************************************************************** +// Function Name : FrqDet +// Retun Value : 0:PASS, 1:OIS X NG, 2:OIS Y NG, 4:CLAF NG +// Argment Value : NON +// Explanation : Module Check +// History : First edition +//******************************************************************************** +UINT_8 FrqDet( void ) +{ + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + UINT_32 UlXasP_P , UlYasP_P ; + + UINT_8 UcRtnVal; + + UcRtnVal = 0; + + //Measurement Setup + MesFil( OSCCHK ) ; // Set Measure Filter + + // waiting for stable the actuator + WitTim( 300 ) ; + +#if FS_MODE == 0 + SlMeasureParameterNum = 902 ; // ( 50ms ) +#else //FS_MODE + SlMeasureParameterNum = 751 ; // ( 50ms ) +#endif //FS_MODE + + SlMeasureParameterA = (UINT_32)HALL_RAM_HXIDAT ; // Set Measure RAM Address + SlMeasureParameterB = (UINT_32)HALL_RAM_HYIDAT ; // Set Measure RAM Address + + // Start measure + MeasureStart2( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB, 50 ) ; + MeasureWait() ; // Wait complete of measurement + RamRead32A( StMeasFunc_MFA_UiAmp1, &UlXasP_P ) ; // X Axis Peak to Peak + RamRead32A( StMeasFunc_MFB_UiAmp2, &UlYasP_P ) ; // Y Axis Peak to Peak +TRACE("UlXasP_P = 0x%08X\r\n", (UINT_32)UlXasP_P ) ; +TRACE("UlYasP_P = 0x%08X\r\n", (UINT_32)UlYasP_P ) ; + + // Amplitude value check X + if( UlXasP_P > ULTHDVAL ){ + UcRtnVal = 1; + } + // Amplitude value check Y + if( UlYasP_P > ULTHDVAL ){ + UcRtnVal |= 2; + } + + + + return(UcRtnVal); // Retun Status value +} + +//******************************************************************************** +// Function Name : MesRam +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure +// History : First edition 2015.07.06 +//******************************************************************************** +UINT_8 MesRam( INT_32 SlMeasureParameterA, INT_32 SlMeasureParameterB, INT_32 SlMeasureParameterNum, stMesRam* pStMesRamA, stMesRam* pStMesRamB ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + + MesFil( THROUGH ) ; // Set Measure Filter + + MeasureStart2( SlMeasureParameterNum, SlMeasureParameterA, SlMeasureParameterB, 1 ) ; // Start measure + + MeasureWait() ; // Wait complete of measurement + + // A : X axis + RamRead32A( StMeasFunc_MFA_SiMax1 , &(pStMesRamA->SlMeasureMaxValue) ) ; // Max value + RamRead32A( StMeasFunc_MFA_SiMin1 , &(pStMesRamA->SlMeasureMinValue) ) ; // Min value + RamRead32A( StMeasFunc_MFA_UiAmp1 , &(pStMesRamA->SlMeasureAmpValue) ) ; // Amp value + RamRead32A( StMeasFunc_MFA_LLiIntegral1, &(StMeasValueA.StUllnVal.UlLowVal) ) ; // Integration Low + RamRead32A( StMeasFunc_MFA_LLiIntegral1 + 4, &(StMeasValueA.StUllnVal.UlHigVal) ) ; // Integration Hig + pStMesRamA->SlMeasureAveValue = + (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; // Ave value + + // B : Y axis + RamRead32A( StMeasFunc_MFB_SiMax2 , &(pStMesRamB->SlMeasureMaxValue) ) ; // Max value + RamRead32A( StMeasFunc_MFB_SiMin2 , &(pStMesRamB->SlMeasureMinValue) ) ; // Min value + RamRead32A( StMeasFunc_MFB_UiAmp2 , &(pStMesRamB->SlMeasureAmpValue) ) ; // Amp value + RamRead32A( StMeasFunc_MFB_LLiIntegral2, &(StMeasValueB.StUllnVal.UlLowVal) ) ; // Integration Low + RamRead32A( StMeasFunc_MFB_LLiIntegral2 + 4, &(StMeasValueB.StUllnVal.UlHigVal) ) ; // Integration Hig + pStMesRamB->SlMeasureAveValue = + (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; // Ave value + + return( 0 ); +} + +//******************************************************************************** +// Function Name : MeasGain +// Retun Value : Hall amp & Sine amp +// Argment Value : X,Y Direction, Freq +// Explanation : Measuring Hall Paek To Peak +// History : First edition +//******************************************************************************** +#if FS_MODE == 0 +#define FS4TIME (UINT_32)0x000119F0 // 18044 * 4 +#define FRQOFST (UINT_32)0x0001D0E5 // 80000000h / 18044 +#else //FS_MODE +#define FS4TIME (UINT_32)0x0000EACC // 15027 * 4 +#define FRQOFST (UINT_32)0x00022E3C // 80000000h / 15027 +#endif //FS_MODE + +UINT_32 MeasGain ( UINT_16 UcDirSel, UINT_16 UsMeasFreq , UINT_32 UlMesAmp ) +{ + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum , SlSineWaveOffset; + UnllnVal StMeasValueA , StMeasValueB ; + UINT_32 UlReturnVal; + + StMeasValueA.UllnValue = 0; + StMeasValueB.UllnValue = 0; + SlMeasureParameterNum = (INT_32)( FS4TIME / (UINT_32)UsMeasFreq) * 2; // + + if( UcDirSel == X_DIR ) { // X axis + SlMeasureParameterA = HALL_RAM_HXOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = HallFilterD_HXDAZ1 ; // Set Measure RAM Address + } else if( UcDirSel == Y_DIR ) { // Y axis + SlMeasureParameterA = HALL_RAM_HYOUT0 ; // Set Measure RAM Address + SlMeasureParameterB = HallFilterD_HYDAZ1 ; // Set Measure RAM Address + } + SetSinWavGenInt(); + + SlSineWaveOffset = (INT_32)( FRQOFST * (UINT_32)UsMeasFreq ); + RamWrite32A( SinWave_Offset , SlSineWaveOffset ) ; // Freq Setting = Freq * 80000000h / Fs + + RamWrite32A( SinWave_Gain , UlMesAmp ) ; // Set Sine Wave Gain + + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + if( UcDirSel == X_DIR ) { + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HXOFF1 ) ; // Set Sine Wave Input RAM + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HYOFF1 ) ; // Set Sine Wave Input RAM + } + + MesFil2( UsMeasFreq ) ; // Filter setting for measurement + + MeasureStart2( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB , 8000/UsMeasFreq ) ; // Start measure + +//#if !LPF_ENA + WitTim( 8000 / UsMeasFreq ) ; +//#endif + MeasureWait() ; // Wait complete of measurement + + RamWrite32A( SinWaveC_Regsiter , 0x00000000 ) ; // Sine Wave Stop + + if( UcDirSel == X_DIR ) { + SetTransDataAdr( SinWave_OutAddr , (UINT_32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; // DelayRam Clear + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr( SinWave_OutAddr , (UINT_32)0x00000000 ) ; // Set Sine Wave Input RAM + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; // DelayRam Clear + } + + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFA_LLiAbsInteg1 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( StMeasFunc_MFB_LLiAbsInteg2 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + + UlReturnVal = (INT_32)((INT_64)StMeasValueA.UllnValue * 100 / (INT_64)StMeasValueB.UllnValue ) ; + + + return( UlReturnVal ) ; +} +//******************************************************************************** +// Function Name : MesFil2 +// Retun Value : NON +// Argment Value : Measure Filter Mode +// Explanation : Measure Filter Setting Function +// History : First edition +//******************************************************************************** +#if FS_MODE == 0 +#define DivOffset 5746.68f /* 18044.6/3.14 */ +#else //FS_MODE +#define DivOffset 4785.76f /* 15027.3/3.14 */ +#endif //FS_MODE + +void MesFil2( UINT_16 UsMesFreq ) +{ + UINT_32 UlMeasFilA1 , UlMeasFilB1 , UlMeasFilC1 , UlTempval ; + UINT_32 UlMeasFilA2 , UlMeasFilC2 ; + + UlTempval = (UINT_32)(2147483647 * (float)UsMesFreq / ((float)UsMesFreq + DivOffset )); + UlMeasFilA1 = 0x7fffffff - UlTempval; + UlMeasFilB1 = ~UlMeasFilA1 + 0x00000001; + UlMeasFilC1 = 0x7FFFFFFF - ( UlTempval << 1 ) ; + + UlMeasFilA2 = UlTempval ; + UlMeasFilC2 = UlMeasFilC1 ; + + + RamWrite32A ( MeasureFilterA_Coeff_a1 , UlMeasFilA1 ) ; + RamWrite32A ( MeasureFilterA_Coeff_b1 , UlMeasFilB1 ) ; + RamWrite32A ( MeasureFilterA_Coeff_c1 , UlMeasFilC1 ) ; + + RamWrite32A ( MeasureFilterA_Coeff_a2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterA_Coeff_b2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterA_Coeff_c2 , UlMeasFilC2 ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a1 , UlMeasFilA1 ) ; + RamWrite32A ( MeasureFilterB_Coeff_b1 , UlMeasFilB1 ) ; + RamWrite32A ( MeasureFilterB_Coeff_c1 , UlMeasFilC1 ) ; + + RamWrite32A ( MeasureFilterB_Coeff_a2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterB_Coeff_b2 , UlMeasFilA2 ) ; + RamWrite32A ( MeasureFilterB_Coeff_c2 , UlMeasFilC2 ) ; +} + + +//******************************************************************************** +// Function Name : MonitorInfo +// Retun Value : NON +// Argment Value : NON +// Explanation : +// History : Second edition +//******************************************************************************** +void MonitorInfo( DSPVER* Dspcode ) +{ +TRACE("Vendor : %02x \n", Dspcode->Vendor ); +TRACE("User : %02x \n", Dspcode->User ); +TRACE("Model : %02x \n", Dspcode->Model ); +TRACE("Version : %02x \n", Dspcode->Version ); + + +if(Dspcode->ActType == 0x00 ) +TRACE("actuator type : \n"); + +TRACE("SubVer : %02x \n", Dspcode->SubVer ); +TRACE("CalibID : %02x \n", Dspcode->CalbId ); + + +if(Dspcode->GyroType == GYRO_ICM20690 ) +TRACE("gyro type : INVEN ICM20690 \n"); +if(Dspcode->GyroType == GYRO_LSM6DSM ) +TRACE("gyro type : ST LSM6DSM \n") ; + +} + + +//******************************************************************************** +// Function Name : GetInfomationAfterStartUp +// Retun Value : NON +// Argment Value : NON +// Explanation : <Pmem Memory> Write Data +// History : First edition +//******************************************************************************** +UINT_8 GetInfomationAfterStartUp( DSPVER* Info ) +{ + UINT_32 Data; + UINT_32 UlReadVal; + + RamWrite32A( CMD_IO_ADR_ACCESS , ROMINFO ); + RamRead32A( CMD_IO_DAT_ACCESS, &UlReadVal ); + if( (UINT_8)UlReadVal != 0x0A ) return( 1 ); + + RamRead32A( (SiVerNum + 0), &Data ); + Info->Vendor = (UINT_8)(Data >> 24 ); + Info->User = (UINT_8)(Data >> 16 ); + Info->Model = (UINT_8)(Data >> 8 ); + Info->Version = (UINT_8)(Data >> 0 ); + RamRead32A( (SiVerNum + 4), &Data ); + Info->CalbId = (UINT_8)(Data >> 24 ); + Info->SubVer = (UINT_8)(Data >> 16 ); + Info->ActType = (UINT_8)(Data >> 8 ); + Info->GyroType = (UINT_8)(Data >> 0 ); + + MonitorInfo( Info ); + return( 0 ); +} + + +//******************************************************************************** +// Function Name : SetAngleCorrection +// Retun Value : True/Fail +// Argment Value : +// Explanation : Angle Correction +// History : First edition +//******************************************************************************** +/* bit7 HX GYR Hall X ‚Æ“¯•ûŒü‚ÌGyroM†‚ªGX? 0:GX 1:GY */ +/* bit6 HX GYR pol Hall X+ ‚Æ“¯•ûŒü‚ÌGyroM†‚ªX+‚ÆG+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit5 HY GYR pol Hall Y+ ‚Æ“¯•ûŒü‚ÌGyroM†‚ªY+‚ÆG+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit4 GZ pol Šî–{‹É«‚ɑ΂µ‚ÄGyroZM†‚ª“¯•ûŒü? 0:NEG 1:POS */ +/* bit3 HX ACL Hall X ‚Æ“¯•ûŒü‚ÌAcclM†‚ªAX? 0:AX 1:AY */ +/* bit2 HX ACL pol Hall X+ ‚Æ“¯•ûŒü‚ÌAcclM†‚ªX+‚ÆA+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit1 HY ACL pol Hall Y+ ‚Æ“¯•ûŒü‚ÌAcclM†‚ªY+‚ÆA+‚Å“¯•ûŒü? 0:NEG 1:POS */ +/* bit0 AZ pol Šî–{‹É«‚ɑ΂µ‚ÄAcclZM†‚ª“¯•ûŒü? 0:NEG 1:POS */ + // top0‹btm0‹// +const UINT_8 PACT0Tbl[] = { 0xFF, 0xFF }; /* Dummy table */ +const UINT_8 PACT1Tbl[] = { 0x20, 0xDF }; /* [ACT_02][ACT_01][ACT_03] */ +const UINT_8 PACT2Tbl[] = { 0x46, 0xB9 }; /* [---] */ + + +UINT_8 SetAngleCorrection( float DegreeGap, UINT_8 SelectAct, UINT_8 Arrangement ) +{ + double OffsetAngle = 0.0f; + double OffsetAngleV_slt = 0.0f; +#if(SEL_MODEL == 0x10) + double OffsetAngleS_slt = 0.0f; +#endif + INT_32 Slgx45x = 0, Slgx45y = 0; + INT_32 Slgy45y = 0, Slgy45x = 0; + INT_32 Slagx45x = 0, Slagx45y = 0; + INT_32 Slagy45y = 0, Slagy45x = 0; + + UINT_8 UcCnvF = 0; + + if( ( DegreeGap > 180.0f) || ( DegreeGap < -180.0f ) ) return ( 1 ); + if( Arrangement >= 2 ) return ( 1 ); + +/************************************************************************/ +/* Gyro angle correction */ +/************************************************************************/ + switch(SelectAct) { +// case 0x00 : +// OffsetAngle = (double)( 45.0f + DegreeGap ) * 3.141592653589793238 / 180.0f ; +// UcCnvF = PACT1Tbl[ Arrangement ]; +// break; +// case 0x01 : +// OffsetAngle = (double)( 0.0f + DegreeGap ) * 3.141592653589793238 / 180.0f ; +// UcCnvF = PACT1Tbl[ Arrangement ]; +// break; +// case 0x02 : +// case 0x03 : +// case 0x05 : +// case 0x06 : +// case 0x07 : +// case 0x08 : + default : + OffsetAngle = (double)( DegreeGap ) * 3.141592653589793238 / 180.0f ; + UcCnvF = PACT1Tbl[ Arrangement ]; + break; +// default : +// break; + } + + SetGyroCoef( UcCnvF ); + SetAccelCoef( UcCnvF ); + + //***********************************************// + // Gyro & Accel rotation correction + //***********************************************// +// Slgx45x = (INT_32)( cos( OffsetAngle )*2147483647.0); +// Slgx45y = (INT_32)(-sin( OffsetAngle )*2147483647.0); +// Slgy45y = (INT_32)( cos( OffsetAngle )*2147483647.0); +// Slgy45x = (INT_32)( sin( OffsetAngle )*2147483647.0); + + RamWrite32A( GyroFilterTableX_gx45x , (UINT_32)Slgx45x ); + RamWrite32A( GyroFilterTableX_gx45y , (UINT_32)Slgx45y ); + RamWrite32A( GyroFilterTableY_gy45y , (UINT_32)Slgy45y ); + RamWrite32A( GyroFilterTableY_gy45x , (UINT_32)Slgy45x ); + RamWrite32A( Accl45Filter_XAmain , (UINT_32)Slgx45x ); + RamWrite32A( Accl45Filter_XAsub , (UINT_32)Slgx45y ); + RamWrite32A( Accl45Filter_YAmain , (UINT_32)Slgy45y ); + RamWrite32A( Accl45Filter_YAsub , (UINT_32)Slgy45x ); + + if(SelectAct == 0x00) { + OffsetAngleV_slt = (double)( 45.0f ) * 3.141592653589793238 / 180.0f ; + }else{ + OffsetAngleV_slt = (double)( 0.0f ) * 3.141592653589793238 / 180.0f ; + } +// Slagx45x = (INT_32)( cos( OffsetAngleV_slt )*2147483647.0); +// Slagx45y = (INT_32)(-sin( OffsetAngleV_slt )*2147483647.0); +// Slagy45y = (INT_32)( cos( OffsetAngleV_slt )*2147483647.0); +// Slagy45x = (INT_32)( sin( OffsetAngleV_slt )*2147483647.0); + RamWrite32A( X_main , (UINT_32)Slagx45x ); + RamWrite32A( X_sub , (UINT_32)Slagx45y ); + RamWrite32A( Y_main , (UINT_32)Slagy45y ); + RamWrite32A( Y_sub , (UINT_32)Slagy45x ); + +#if(SEL_MODEL == 0x10) + OffsetAngleS_slt = (double)( -90.0f ) * 3.141592653589793238 / 180.0f ; +// Slagx45x = (INT_32)( cos( OffsetAngleS_slt )*2147483647.0); +// Slagx45y = (INT_32)(-sin( OffsetAngleS_slt )*2147483647.0); +// Slagy45y = (INT_32)( cos( OffsetAngleS_slt )*2147483647.0); +// Slagy45x = (INT_32)( sin( OffsetAngleS_slt )*2147483647.0); + RamWrite32A( SX_main , (UINT_32)Slagx45x ); + RamWrite32A( SX_sub , (UINT_32)Slagx45y ); + RamWrite32A( SY_main , (UINT_32)Slagy45y ); + RamWrite32A( SY_sub , (UINT_32)Slagy45x ); +#endif + return ( 0 ); +} + +void SetGyroCoef( UINT_8 UcCnvF ) +{ + INT_32 Slgxx = 0, Slgxy = 0; + INT_32 Slgyy = 0, Slgyx = 0; + INT_32 Slgzp = 0; + /************************************************/ + /* signal convet */ + /************************************************/ + switch( UcCnvF & 0xE0 ){ + /* HX <== GX , HY <== GY */ + case 0x00: + Slgxx = 0x7FFFFFFF ; Slgxy = 0x00000000 ; Slgyy = 0x7FFFFFFF ; Slgyx = 0x00000000 ; break; //HX<==GX(NEG), HY<==GY(NEG) + case 0x20: + Slgxx = 0x7FFFFFFF ; Slgxy = 0x00000000 ; Slgyy = 0x80000001 ; Slgyx = 0x00000000 ; break; //HX<==GX(NEG), HY<==GY(POS) + case 0x40: + Slgxx = 0x80000001 ; Slgxy = 0x00000000 ; Slgyy = 0x7FFFFFFF ; Slgyx = 0x00000000 ; break; //HX<==GX(POS), HY<==GY(NEG) + case 0x60: + Slgxx = 0x80000001 ; Slgxy = 0x00000000 ; Slgyy = 0x80000001 ; Slgyx = 0x00000000 ; break; //HX<==GX(POS), HY<==GY(POS) + /* HX <== GY , HY <== GX */ + case 0x80: + Slgxx = 0x00000000 ; Slgxy = 0x7FFFFFFF ; Slgyy = 0x00000000 ; Slgyx = 0x7FFFFFFF ; break; //HX<==GY(NEG), HY<==GX(NEG) + case 0xA0: + Slgxx = 0x00000000 ; Slgxy = 0x7FFFFFFF ; Slgyy = 0x00000000 ; Slgyx = 0x80000001 ; break; //HX<==GY(NEG), HY<==GX(POS) + case 0xC0: + Slgxx = 0x00000000 ; Slgxy = 0x80000001 ; Slgyy = 0x00000000 ; Slgyx = 0x7FFFFFFF ; break; //HX<==GY(POS), HY<==GX(NEG) + case 0xE0: + Slgxx = 0x00000000 ; Slgxy = 0x80000001 ; Slgyy = 0x00000000 ; Slgyx = 0x80000001 ; break; //HX<==GY(NEG), HY<==GX(NEG) + } + switch( UcCnvF & 0x10 ){ + case 0x00: + Slgzp = 0x7FFFFFFF ; break; //GZ(POS) + case 0x10: + Slgzp = 0x80000001 ; break; //GZ(NEG) + } + RamWrite32A( MS_SEL_GX0 , (UINT_32)Slgxx ); + RamWrite32A( MS_SEL_GX1 , (UINT_32)Slgxy ); + RamWrite32A( MS_SEL_GY0 , (UINT_32)Slgyy ); + RamWrite32A( MS_SEL_GY1 , (UINT_32)Slgyx ); + RamWrite32A( MS_SEL_GZ , (UINT_32)Slgzp ); +} + +void SetAccelCoef( UINT_8 UcCnvF ) +{ + INT_32 Slaxx = 0, Slaxy = 0; + INT_32 Slayy = 0, Slayx = 0; + INT_32 Slazp = 0; + + switch( UcCnvF & 0x0E ){ + /* HX <== AX , HY <== AY */ + case 0x00: + Slaxx = 0x7FFFFFFF ; Slaxy = 0x00000000 ; Slayy = 0x7FFFFFFF ; Slayx = 0x00000000 ; break; //HX<==AX(NEG), HY<==AY(NEG) + case 0x02: + Slaxx = 0x7FFFFFFF ; Slaxy = 0x00000000 ; Slayy = 0x80000001 ; Slayx = 0x00000000 ; break; //HX<==AX(NEG), HY<==AY(POS) + case 0x04: + Slaxx = 0x80000001 ; Slaxy = 0x00000000 ; Slayy = 0x7FFFFFFF ; Slayx = 0x00000000 ; break; //HX<==AX(POS), HY<==AY(NEG) + case 0x06: + Slaxx = 0x80000001 ; Slaxy = 0x00000000 ; Slayy = 0x80000001 ; Slayx = 0x00000000 ; break; //HX<==AX(POS), HY<==AY(POS) + /* HX <== AY , HY <== AX */ + case 0x08: + Slaxx = 0x00000000 ; Slaxy = 0x7FFFFFFF ; Slayy = 0x00000000 ; Slayx = 0x7FFFFFFF ; break; //HX<==AY(NEG), HY<==AX(NEG) + case 0x0A: + Slaxx = 0x00000000 ; Slaxy = 0x7FFFFFFF ; Slayy = 0x00000000 ; Slayx = 0x80000001 ; break; //HX<==AY(NEG), HY<==AX(POS) + case 0x0C: + Slaxx = 0x00000000 ; Slaxy = 0x80000001 ; Slayy = 0x00000000 ; Slayx = 0x7FFFFFFF ; break; //HX<==AY(POS), HY<==AX(NEG) + case 0x0E: + Slaxx = 0x00000000 ; Slaxy = 0x80000001 ; Slayy = 0x00000000 ; Slayx = 0x80000001 ; break; //HX<==AY(NEG), HY<==AX(NEG) + } + switch( UcCnvF & 0x01 ){ + case 0x00: + Slazp = 0x7FFFFFFF ; break; //AZ(POS) + case 0x01: + Slazp = 0x80000001 ; break; //AZ(NEG) + } + RamWrite32A( MS_SEL_AX0 , (UINT_32)Slaxx ); + RamWrite32A( MS_SEL_AX1 , (UINT_32)Slaxy ); + RamWrite32A( MS_SEL_AY0 , (UINT_32)Slayy ); + RamWrite32A( MS_SEL_AY1 , (UINT_32)Slayx ); + RamWrite32A( MS_SEL_AZ , (UINT_32)Slazp ); +} + + +//******************************************************************************** +// Function Name : SetGyroOffset +// Retun Value : NON +// Argment Value : NON +// Explanation : set the gyro offset data. before do this before Remapmain. +// History : First edition +//******************************************************************************** +void SetGyroOffset( UINT_16 GyroOffsetX, UINT_16 GyroOffsetY, UINT_16 GyroOffsetZ ) +{ + RamWrite32A( GYRO_RAM_GXOFFZ , (( GyroOffsetX << 16 ) & 0xFFFF0000 ) ) ; // X axis Gyro offset + RamWrite32A( GYRO_RAM_GYOFFZ , (( GyroOffsetY << 16 ) & 0xFFFF0000 ) ) ; // Y axis Gyro offset + RamWrite32A( GYRO_ZRAM_GZOFFZ , (( GyroOffsetZ << 16 ) & 0xFFFF0000 ) ) ; // Z axis Gyro offset +} + + +//******************************************************************************** +// Function Name : SetAcclOffset +// Retun Value : NON +// Argment Value : NON +// Explanation : set the accl offset data. before do this before Remapmain. +// History : First edition +//******************************************************************************** +void SetAcclOffset( UINT_16 AcclOffsetX, UINT_16 AcclOffsetY, UINT_16 AcclOffsetZ ) +{ + RamWrite32A( ACCLRAM_X_AC_OFFSET , ( ( AcclOffsetX << 16 ) & 0xFFFF0000 ) ) ; // X axis Accl offset + RamWrite32A( ACCLRAM_Y_AC_OFFSET , ( ( AcclOffsetY << 16 ) & 0xFFFF0000 ) ) ; // Y axis Accl offset + RamWrite32A( ACCLRAM_Z_AC_OFFSET , ( ( AcclOffsetZ << 16 ) & 0xFFFF0000 ) ) ; // Z axis Accl offset +} + +void GetGyroOffset( UINT_16* GyroOffsetX, UINT_16* GyroOffsetY, UINT_16* GyroOffsetZ ) +{ + UINT_32 ReadValX, ReadValY, ReadValZ; + RamRead32A( GYRO_RAM_GXOFFZ , &ReadValX ); + RamRead32A( GYRO_RAM_GYOFFZ , &ReadValY ); + RamRead32A( GYRO_ZRAM_GZOFFZ , &ReadValZ ); + *GyroOffsetX = ( UINT_16 )(( ReadValX >> 16) & 0x0000FFFF ); + *GyroOffsetY = ( UINT_16 )(( ReadValY >> 16) & 0x0000FFFF ); + *GyroOffsetZ = ( UINT_16 )(( ReadValZ >> 16) & 0x0000FFFF ); +} + +void GetAcclOffset( UINT_16* AcclOffsetX, UINT_16* AcclOffsetY, UINT_16* AcclOffsetZ ) +{ + UINT_32 ReadValX, ReadValY, ReadValZ; + RamRead32A( ACCLRAM_X_AC_OFFSET , &ReadValX ); + RamRead32A( ACCLRAM_Y_AC_OFFSET , &ReadValY ); + RamRead32A( ACCLRAM_Z_AC_OFFSET , &ReadValZ ); + *AcclOffsetX = ( UINT_16 )(( ReadValX >> 16) & 0x0000FFFF ); + *AcclOffsetY = ( UINT_16 )(( ReadValY >> 16) & 0x0000FFFF ); + *AcclOffsetZ = ( UINT_16 )(( ReadValZ >> 16) & 0x0000FFFF ); +} + +UINT_8 TstActMov( UINT_8 UcDirSel ) +{ + UINT_8 UcRsltSts = 0; + INT_32 SlMeasureParameterNum ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + UnllnVal StMeasValueA , StMeasValueB ; + float SfLimit , Sfzoom , Sflenz , Sfshift ; + UINT_32 UlLimit , Ulzoom , Ullenz , Ulshift , UlActChkLvl ; + UINT_8 i; + UINT_32 UlReturnVal; + + if( UcDirSel == 0x00 ) { + RamRead32A( Gyro_Limiter_X , ( UINT_32 * )&UlLimit ) ; + RamRead32A( GyroFilterTableX_gxzoom , ( UINT_32 * )&Ulzoom ) ; + RamRead32A( GyroFilterTableX_gxlenz , ( UINT_32 * )&Ullenz ) ; + RamRead32A( GyroFilterShiftX , ( UINT_32 * )&Ulshift ) ; + }else{ + RamRead32A( Gyro_Limiter_Y , ( UINT_32 * )&UlLimit ) ; + RamRead32A( GyroFilterTableY_gyzoom , ( UINT_32 * )&Ulzoom ) ; + RamRead32A( GyroFilterTableY_gylenz , ( UINT_32 * )&Ullenz ) ; + RamRead32A( GyroFilterShiftY , ( UINT_32 * )&Ulshift ) ; + } + +TRACE(" DIR = %d, lmt = %08x, zom = %08x , lnz = %08x ,sft = %08x \n", UcDirSel, (unsigned int)UlLimit , (unsigned int)Ulzoom , (unsigned int)Ullenz , (unsigned int)Ulshift ) ; + + SfLimit = (float)UlLimit / (float)0x7FFFFFFF; + if( Ulzoom == 0){ + Sfzoom = 0; + }else{ + Sfzoom = (float)abs(Ulzoom) / (float)0x7FFFFFFF; + } + if( Ullenz == 0){ + Sflenz = 0; + }else{ + Sflenz = (float)Ullenz / (float)0x7FFFFFFF; + } + Ulshift = ( Ulshift & 0x0000FF00) >> 8 ; + Sfshift = 1; + for( i = 0 ; i < Ulshift ; i++ ){ + Sfshift *= 2; + } + UlActChkLvl = (UINT_32)( (float)0x7FFFFFFF * SfLimit * Sfzoom * Sflenz * Sfshift * ACT_MARGIN ); +TRACE(" lvl = %08x \n", (unsigned int)UlActChkLvl ) ; + + SlMeasureParameterNum = ACT_CHK_NUM ; + + if( UcDirSel == 0x00 ) { + SlMeasureParameterA = HALL_RAM_HXOFF1 ; + SlMeasureParameterB = HallFilterD_HXDAZ1 ; + } else if( UcDirSel == 0x01 ) { + SlMeasureParameterA = HALL_RAM_HYOFF1 ; + SlMeasureParameterB = HallFilterD_HYDAZ1 ; + } + SetSinWavGenInt(); + + RamWrite32A( 0x02FC , ACT_CHK_FRQ ) ; + RamWrite32A( 0x0304 , UlActChkLvl ) ; + RamWrite32A( 0x02F4 , 0x00000001 ) ; + if( UcDirSel == 0x00 ) { + SetTransDataAdr( 0x030C , (UINT_32)HALL_RAM_HXOFF1 ) ; + }else if( UcDirSel == 0x01 ){ + SetTransDataAdr( 0x030C , (UINT_32)HALL_RAM_HYOFF1 ) ; + } + RamWrite32A ( 0x8388 , 0x03E452C7 ) ; + RamWrite32A ( 0x8380 , 0x03E452C7 ) ; + RamWrite32A ( 0x8384 , 0x78375A71 ) ; + + RamWrite32A ( 0x8394 , 0x03E452C7 ) ; + RamWrite32A ( 0x838C , 0x03E452C7 ) ; + RamWrite32A ( 0x8390 , 0x78375A71 ) ; + + RamWrite32A ( 0x83A0 , 0x03E452C7 ) ; + RamWrite32A ( 0x8398 , 0x03E452C7 ) ; + RamWrite32A ( 0x839C , 0x78375A71 ) ; + + RamWrite32A ( 0x83AC , 0x03E452C7 ) ; + RamWrite32A ( 0x83A4 , 0x03E452C7 ) ; + RamWrite32A ( 0x83A8 , 0x78375A71 ) ; + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; + + MeasureWait() ; + + RamWrite32A( 0x02F4 , 0x00000000 ) ; + + if( UcDirSel == 0x00 ) { + SetTransDataAdr( 0x030C , (UINT_32)0x00000000 ) ; + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; + }else if( UcDirSel == 0x01 ){ + SetTransDataAdr( 0x030C , (UINT_32)0x00000000 ) ; + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; + } + RamRead32A( 0x0298 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( 0x0298 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( 0x02C0 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( 0x02C0 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + + UlReturnVal = (INT_32)((INT_64)StMeasValueA.UllnValue * 100 / (INT_64)StMeasValueB.UllnValue ) ; + + +TRACE(" Ret = %d \n", (unsigned int)UlReturnVal ) ; + + + UcRsltSts = EXE_END ; + if( UlReturnVal < ACT_THR ){ + if ( !UcDirSel ) { + UcRsltSts = EXE_HXMVER ; + }else{ + UcRsltSts = EXE_HYMVER ; + } + } + + return( UcRsltSts ) ; + +} +UINT_8 RunHea( void ) +{ + UINT_8 UcRst ; + UcRst = EXE_END ; + UcRst |= TstActMov( 0x00 ) ; + UcRst |= TstActMov( 0x01 ) ; + +//TRACE("UcRst = %02x\n", UcRst ) ; + return( UcRst ) ; +} + + +UINT_8 RunGea( void ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + UINT_8 UcRst, UcCnt, UcXLowCnt, UcYLowCnt, UcXHigCnt, UcYHigCnt ; + UINT_16 UsGxoVal[10], UsGyoVal[10], UsDif; + INT_32 SlMeasureParameterNum , SlMeasureAveValueA , SlMeasureAveValueB ; + + + UcRst = EXE_END ; + UcXLowCnt = UcYLowCnt = UcXHigCnt = UcYHigCnt = 0 ; + + RamWrite32A ( 0x8388 , 0x7FFFFFFF ) ; + RamWrite32A ( 0x8380 , 0x00000000 ) ; + RamWrite32A ( 0x8384 , 0x00000000 ) ; + + RamWrite32A ( 0x8394 , 0x7FFFFFFF ) ; + RamWrite32A ( 0x838C , 0x00000000 ) ; + RamWrite32A ( 0x8390 , 0x00000000 ) ; + + RamWrite32A ( 0x83A0 , 0x7FFFFFFF ) ; + RamWrite32A ( 0x8398 , 0x00000000 ) ; + RamWrite32A ( 0x839C , 0x00000000 ) ; + + RamWrite32A ( 0x83AC , 0x7FFFFFFF ) ; + RamWrite32A ( 0x83A4 , 0x00000000 ) ; + RamWrite32A ( 0x83A8 , 0x00000000 ) ; + + for( UcCnt = 0 ; UcCnt < 10 ; UcCnt++ ) + { + + + SlMeasureParameterNum = GEA_NUM ; + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; + + MeasureWait() ; + +//TRACE("Read Adr = %04x, %04xh \n",StMeasFunc_MFA_LLiIntegral1 + 4 , StMeasFunc_MFA_LLiIntegral1) ; + RamRead32A( 0x0290 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( 0x0290 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( 0x02B8 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( 0x02B8 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + +TRACE("GX_OFT = %08x, %08xh \n",(unsigned int)StMeasValueA.StUllnVal.UlHigVal,(unsigned int)StMeasValueA.StUllnVal.UlLowVal) ; +TRACE("GY_OFT = %08x, %08xh \n",(unsigned int)StMeasValueB.StUllnVal.UlHigVal,(unsigned int)StMeasValueB.StUllnVal.UlLowVal) ; + SlMeasureAveValueA = (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; +TRACE("GX_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueA) ; +TRACE("GY_AVEOFT = %08xh \n",(unsigned int)SlMeasureAveValueB) ; + // + UsGxoVal[UcCnt] = (UINT_16)( SlMeasureAveValueA >> 16 ); + + // + UsGyoVal[UcCnt] = (UINT_16)( SlMeasureAveValueB >> 16 ); + +TRACE("UcCnt = %02x, UsGxoVal[UcCnt] = %04x\n", UcCnt, UsGxoVal[UcCnt] ) ; +TRACE("UcCnt = %02x, UsGyoVal[UcCnt] = %04x\n", UcCnt, UsGyoVal[UcCnt] ) ; + + + if( UcCnt > 0 ) + { + if ( (INT_16)UsGxoVal[0] > (INT_16)UsGxoVal[UcCnt] ) { + UsDif = (UINT_16)((INT_16)UsGxoVal[0] - (INT_16)UsGxoVal[UcCnt]) ; + } else { + UsDif = (UINT_16)((INT_16)UsGxoVal[UcCnt] - (INT_16)UsGxoVal[0]) ; + } + + if( UsDif > GEA_DIF_HIG ) { + UcXHigCnt ++ ; + } + if( UsDif < GEA_DIF_LOW ) { + UcXLowCnt ++ ; + } +TRACE("CNT = %02x , X diff = %04x ", UcCnt , UsDif ) ; + + if ( (INT_16)UsGyoVal[0] > (INT_16)UsGyoVal[UcCnt] ) { + UsDif = (UINT_16)((INT_16)UsGyoVal[0] - (INT_16)UsGyoVal[UcCnt]) ; + } else { + UsDif = (UINT_16)((INT_16)UsGyoVal[UcCnt] - (INT_16)UsGyoVal[0]) ; + } + + if( UsDif > GEA_DIF_HIG ) { + UcYHigCnt ++ ; + } + if( UsDif < GEA_DIF_LOW ) { + UcYLowCnt ++ ; + } +TRACE(" Y diff = %04x \n", UsDif ) ; + } + } + + if( UcXHigCnt >= 1 ) { + UcRst = UcRst | EXE_GXABOVE ; + } + if( UcXLowCnt > 8 ) { + UcRst = UcRst | EXE_GXBELOW ; + } + + if( UcYHigCnt >= 1 ) { + UcRst = UcRst | EXE_GYABOVE ; + } + if( UcYLowCnt > 8 ) { + UcRst = UcRst | EXE_GYBELOW ; + } + +TRACE("UcRst = %02x\n", UcRst ) ; + + return( UcRst ) ; +} + + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisDWL.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisDWL.h new file mode 100755 index 0000000000000000000000000000000000000000..da35375482772f3291614d4e622086205e8fb8f3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisDWL.h @@ -0,0 +1,25 @@ +/** + * @brief OIS system header for LC898128 + * API List for customers + * + * @author Copyright (C) 2015, ON Semiconductor, all right reserved. + * + * @file OisDWL.h + * @date svn:$Date:: 2016-06-17 16:42:32 +0900#$ + * @version svn:$Revision: 54 $ + * @attention + **/ + +#ifdef __OISDWL__ + #define __OIS_FLDL_HEADER__ +#else + #define __OIS_FLDL_HEADER__ extern +#endif + +#include "Ois.h" + + __OIS_FLDL_HEADER__ UINT_8 FlashUpload128( UINT_8 ModuleVendor, UINT_8 ActVer, UINT_8 MasterSlave, UINT_8 FWType); +//#ifdef TRNT + __OIS_FLDL_HEADER__ UINT_8 LoadUserAreaToPM( void ); +//#endif + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisFRA.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisFRA.c new file mode 100755 index 0000000000000000000000000000000000000000..6708331834de24998639aed3b3046df65744c12e --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisFRA.c @@ -0,0 +1,436 @@ +/** + * @brief FRA measurement command for LC898123 F40 + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file OisFRA.c + * @date svn:$Date:: 2016-06-17 16:42:32 +0900#$ + * @version svn:$Revision: 54 $ + * @attention + **/ + +//************************** +// Include Header File +//************************** +#define __OISFRA__ + +//#include <math.h> +#include "Ois.h" +#include "OisFRA.h" +#include <linux/kernel.h> + +#define ACT_THROUGH_CLOSE // for ball type +//#define CLOSED_RESPONSE // for openloop measurement + +//**************************************************** +// CUSTOMER NECESSARY CREATING LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A( INT_32, INT_32 ); +extern void RamRead32A( UINT_16, void * ); +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( UINT_16 ); + +//************************** +// External Function Prototype +//************************** +extern void SetSineWave( UINT_8 , UINT_8 ); +extern void SetSinWavGenInt( void ); +extern void SetTransDataAdr( UINT_16, UINT_32 ) ; +extern void MeasureWait( void ) ; +extern void ClrMesFil( void ) ; +extern void SetWaitTime( UINT_16 ) ; +extern UINT_8 GetInfomationAfterStartUp( DSPVER* Info ); + +#ifdef ACT_THROUGH_CLOSE +UINT_32 BackupParameter[30]; +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : SetThroughParameter */ +/* input parameter : */ +/* output parameter : */ +/* comment : DFT‚ÌŒW””­¶ */ +/* 2018.01.18 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +void SetThroughParameter(UINT_8 UcDirSel ) +{ + DSPVER Info; + GetInfomationAfterStartUp( &Info ); + + if( UcDirSel == X_DIR ) { + BackupParameter[29] = X_DIR; + RamRead32A( HallFilterCoeffX_hxdgain0, &BackupParameter[0]); + RamRead32A( HallFilterCoeffX_hxpgain0, &BackupParameter[1]); + RamRead32A( HallFilterCoeffX_hxpgain1, &BackupParameter[2]); + RamRead32A( HallFilterCoeffX_hxigain0, &BackupParameter[3]); + RamRead32A( HallFilterCoeffX_hxgain0, &BackupParameter[4]); + RamRead32A( HallFilterShiftX, &BackupParameter[5]); + RamRead32A( (HallFilterShiftX+4), &BackupParameter[6]); + RamRead32A( HallFilterCoeffX_hxsa, &BackupParameter[7]); + RamRead32A( HallFilterCoeffX_hxsb, &BackupParameter[8]); + RamRead32A( HallFilterCoeffX_hxsc, &BackupParameter[9]); + RamRead32A( HallFilterCoeffX_hxoa, &BackupParameter[10]); + RamRead32A( HallFilterCoeffX_hxob, &BackupParameter[11]); + RamRead32A( HallFilterCoeffX_hxoc, &BackupParameter[12]); + RamRead32A( HallFilterCoeffX_hxod, &BackupParameter[13]); + RamRead32A( HallFilterCoeffX_hxoe, &BackupParameter[14]); + RamRead32A( HallFilterCoeffX_hxpa, &BackupParameter[15]); + RamRead32A( HallFilterCoeffX_hxpb, &BackupParameter[16]); + RamRead32A( HallFilterCoeffX_hxpc, &BackupParameter[17]); + RamRead32A( HallFilterCoeffX_hxpd, &BackupParameter[18]); + RamRead32A( HallFilterCoeffX_hxpe, &BackupParameter[19]); + + RamWrite32A( HallFilterCoeffX_hxdgain0, 0x00000000); //RAMW32 80EC 00000000 + RamWrite32A( HallFilterCoeffX_hxpgain0, 0x7fffffff); //RAMW32 80D8 7fffffff + RamWrite32A( HallFilterCoeffX_hxpgain1, 0x7fffffff); //RAMW32 80E4 7fffffff + RamWrite32A( HallFilterCoeffX_hxigain0, 0x00000000); //RAMW32 80E8 00000000 + RamWrite32A( HallFilterCoeffX_hxgain0, 0x7fffffff); //RAMW32 80F0 7fffffff + if(Info.Model == 0x01){ // KW + RamWrite32A( HallFilterShiftX, 0x00000001); //RAMW32 81F8 00000000 +6dB + }else{ + RamWrite32A( HallFilterShiftX, 0x00000000); //RAMW32 81F8 00000000 + } + RamWrite32A( (HallFilterShiftX+4), 0x00000000); //RAMW32 81FC 00000000 + RamWrite32A( HallFilterCoeffX_hxsa, 0x7fffffff); //RAMW32 8100 7fffffff + RamWrite32A( HallFilterCoeffX_hxsb, 0x00000000); //RAMW32 80F8 00000000 + RamWrite32A( HallFilterCoeffX_hxsc, 0x00000000); //RAMW32 80FC 00000000 + RamWrite32A( HallFilterCoeffX_hxoa, 0x7fffffff); //RAMW32 8114 7fffffff + RamWrite32A( HallFilterCoeffX_hxob, 0x00000000); //RAMW32 8104 00000000 + RamWrite32A( HallFilterCoeffX_hxoc, 0x00000000); //RAMW32 8108 00000000 + RamWrite32A( HallFilterCoeffX_hxod, 0x00000000); //RAMW32 810C 00000000 + RamWrite32A( HallFilterCoeffX_hxoe, 0x00000000); //RAMW32 8110 00000000 + RamWrite32A( HallFilterCoeffX_hxpa, 0x7fffffff); //RAMW32 8128 7fffffff + RamWrite32A( HallFilterCoeffX_hxpb, 0x00000000); //RAMW32 8118 00000000 + RamWrite32A( HallFilterCoeffX_hxpc, 0x00000000); //RAMW32 811C 00000000 + RamWrite32A( HallFilterCoeffX_hxpd, 0x00000000); //RAMW32 8120 00000000 + RamWrite32A( HallFilterCoeffX_hxpe, 0x00000000); //RAMW32 8124 00000000 + }else if( UcDirSel == Y_DIR ){ + BackupParameter[29] = Y_DIR; + RamRead32A( HallFilterCoeffY_hydgain0, &BackupParameter[0]); + RamRead32A( HallFilterCoeffY_hypgain0, &BackupParameter[1]); + RamRead32A( HallFilterCoeffY_hypgain1, &BackupParameter[2]); + RamRead32A( HallFilterCoeffY_hyigain0, &BackupParameter[3]); + RamRead32A( HallFilterCoeffY_hygain0, &BackupParameter[4]); + RamRead32A( (HallFilterShiftY & 0xFFFE), &BackupParameter[5]); + RamRead32A( (HallFilterShiftY + 4) &0xFFFE, &BackupParameter[6]); + RamRead32A( HallFilterCoeffY_hysa, &BackupParameter[7]); + RamRead32A( HallFilterCoeffY_hysb, &BackupParameter[8]); + RamRead32A( HallFilterCoeffY_hysc, &BackupParameter[9]); + RamRead32A( HallFilterCoeffY_hyoa, &BackupParameter[10]); + RamRead32A( HallFilterCoeffY_hyob, &BackupParameter[11]); + RamRead32A( HallFilterCoeffY_hyoc, &BackupParameter[12]); + RamRead32A( HallFilterCoeffY_hyod, &BackupParameter[13]); + RamRead32A( HallFilterCoeffY_hyoe, &BackupParameter[14]); + RamRead32A( HallFilterCoeffY_hypa, &BackupParameter[15]); + RamRead32A( HallFilterCoeffY_hypb, &BackupParameter[16]); + RamRead32A( HallFilterCoeffY_hypc, &BackupParameter[17]); + RamRead32A( HallFilterCoeffY_hypd, &BackupParameter[18]); + RamRead32A( HallFilterCoeffY_hype, &BackupParameter[19]); + + RamWrite32A( HallFilterCoeffY_hydgain0, 0x00000000); //RAMW32 8188 00000000 + RamWrite32A( HallFilterCoeffY_hypgain0, 0x7fffffff); //RAMW32 8174 7fffffff + RamWrite32A( HallFilterCoeffY_hypgain1, 0x7fffffff); //RAMW32 8180 7fffffff + RamWrite32A( HallFilterCoeffY_hyigain0, 0x00000000); //RAMW32 8184 00000000 + RamWrite32A( HallFilterCoeffY_hygain0, 0x7fffffff); //RAMW32 818C 7fffffff + if(Info.Model == 0x01){ // KW + RamWrite32A( (HallFilterShiftY & 0xFFFE), 0x00010000); //RAMW32 8200 00000000 + }else{ + RamWrite32A( (HallFilterShiftY & 0xFFFE), 0x00000000); //RAMW32 8200 00000000 + } + RamWrite32A( (HallFilterShiftY + 4) &0xFFFE, 0x00000000); //RAMW32 8200 00000000 + RamWrite32A( HallFilterCoeffY_hysa, 0x7fffffff); //RAMW32 819C 7fffffff + RamWrite32A( HallFilterCoeffY_hysb, 0x00000000); //RAMW32 8194 00000000 + RamWrite32A( HallFilterCoeffY_hysc, 0x00000000); //RAMW32 8198 00000000 + RamWrite32A( HallFilterCoeffY_hyoa, 0x7fffffff); //RAMW32 81B0 7fffffff + RamWrite32A( HallFilterCoeffY_hyob, 0x00000000); //RAMW32 81A0 00000000 + RamWrite32A( HallFilterCoeffY_hyoc, 0x00000000); //RAMW32 81A4 00000000 + RamWrite32A( HallFilterCoeffY_hyod, 0x00000000); //RAMW32 81A8 00000000 + RamWrite32A( HallFilterCoeffY_hyoe, 0x00000000); //RAMW32 81AC 00000000 + RamWrite32A( HallFilterCoeffY_hypa, 0x7fffffff); //RAMW32 81C4 7fffffff + RamWrite32A( HallFilterCoeffY_hypb, 0x00000000); //RAMW32 81B4 00000000 + RamWrite32A( HallFilterCoeffY_hypc, 0x00000000); //RAMW32 81B8 00000000 + RamWrite32A( HallFilterCoeffY_hypd, 0x00000000); //RAMW32 81BC 00000000 + RamWrite32A( HallFilterCoeffY_hype, 0x00000000); //RAMW32 81C0 00000000 + }else if( UcDirSel == Z_DIR ){ + } +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : ResetThroughParameter */ +/* input parameter : */ +/* output parameter : */ +/* comment : DFT‚ÌŒW””­¶ */ +/* 2018.01.18 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +void ResetThroughParameter(void) +{ + if( BackupParameter[29] == X_DIR ) { + RamWrite32A( HallFilterCoeffX_hxdgain0, BackupParameter[0]); + RamWrite32A( HallFilterCoeffX_hxpgain0, BackupParameter[1]); + RamWrite32A( HallFilterCoeffX_hxpgain1, BackupParameter[2]); + RamWrite32A( HallFilterCoeffX_hxigain0, BackupParameter[3]); + RamWrite32A( HallFilterCoeffX_hxgain0, BackupParameter[4]); + RamWrite32A( HallFilterShiftX, BackupParameter[5]); + RamWrite32A( (HallFilterShiftX+4), BackupParameter[6]); + RamWrite32A( HallFilterCoeffX_hxsa, BackupParameter[7]); + RamWrite32A( HallFilterCoeffX_hxsb, BackupParameter[8]); + RamWrite32A( HallFilterCoeffX_hxsc, BackupParameter[9]); + RamWrite32A( HallFilterCoeffX_hxoa, BackupParameter[10]); + RamWrite32A( HallFilterCoeffX_hxob, BackupParameter[11]); + RamWrite32A( HallFilterCoeffX_hxoc, BackupParameter[12]); + RamWrite32A( HallFilterCoeffX_hxod, BackupParameter[13]); + RamWrite32A( HallFilterCoeffX_hxoe, BackupParameter[14]); + RamWrite32A( HallFilterCoeffX_hxpa, BackupParameter[15]); + RamWrite32A( HallFilterCoeffX_hxpb, BackupParameter[16]); + RamWrite32A( HallFilterCoeffX_hxpc, BackupParameter[17]); + RamWrite32A( HallFilterCoeffX_hxpd, BackupParameter[18]); + RamWrite32A( HallFilterCoeffX_hxpe, BackupParameter[19]); + }else if( BackupParameter[29] == Y_DIR ){ + RamWrite32A( HallFilterCoeffY_hydgain0, BackupParameter[0]); + RamWrite32A( HallFilterCoeffY_hypgain0, BackupParameter[1]); + RamWrite32A( HallFilterCoeffY_hypgain1, BackupParameter[2]); + RamWrite32A( HallFilterCoeffY_hyigain0, BackupParameter[3]); + RamWrite32A( HallFilterCoeffY_hygain0, BackupParameter[4]); + RamWrite32A( (HallFilterShiftY & 0xFFFE), BackupParameter[5]); + RamWrite32A( (HallFilterShiftY+4)& 0xFFFE, BackupParameter[6]); + RamWrite32A( HallFilterCoeffY_hysa, BackupParameter[7]); + RamWrite32A( HallFilterCoeffY_hysb, BackupParameter[8]); + RamWrite32A( HallFilterCoeffY_hysc, BackupParameter[9]); + RamWrite32A( HallFilterCoeffY_hyoa, BackupParameter[10]); + RamWrite32A( HallFilterCoeffY_hyob, BackupParameter[11]); + RamWrite32A( HallFilterCoeffY_hyoc, BackupParameter[12]); + RamWrite32A( HallFilterCoeffY_hyod, BackupParameter[13]); + RamWrite32A( HallFilterCoeffY_hyoe, BackupParameter[14]); + RamWrite32A( HallFilterCoeffY_hypa, BackupParameter[15]); + RamWrite32A( HallFilterCoeffY_hypb, BackupParameter[16]); + RamWrite32A( HallFilterCoeffY_hypc, BackupParameter[17]); + RamWrite32A( HallFilterCoeffY_hypd, BackupParameter[18]); + RamWrite32A( HallFilterCoeffY_hype, BackupParameter[19]); + }else if( BackupParameter[29] == Z_DIR ){ + } +} +#endif +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/* function name : CoeffGenerate */ +/* input parameter : */ +/* output parameter : */ +/* comment : DFT‚ÌŒW””­¶ */ +/* 2018.01.18 */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#define Q31 ( 0x7FFFFFFF ) +#define Q23 ( 0x007FFFFF ) +#define Q21 ( 0x001FFFFF ) +#define PAI ( 3.14159265358979323846 ) +#define N ( 2048 ) +int nDivision; + +void CoeffGenerate( double fc ) +{ + double df, fs; + int point, C0, S0, CN, SN; + double theta; // theta = 2*Pi*f/Fs + + if ( fc > 40 ){ nDivision = 0; fs = (FS_FREQ ); } + else if ( fc > 20 ){ nDivision = 1; fs = (FS_FREQ / 2); } + else if ( fc > 10 ){ nDivision = 2; fs = (FS_FREQ / 4); } + else if ( fc > 5 ){ nDivision = 3; fs = (FS_FREQ / 8); } + else { nDivision = 4; fs = (FS_FREQ /16); } + + //***** Žæ“¾‚µ‚½Žü”g”ƒe[ƒuƒ‹‚©‚ç”»’èƒ|ƒCƒ“ƒg‚Æ”»’ètheta‚ÌŽZo ***** + df = fs / (double)N; // FFT‚Ì1ƒ|ƒCƒ“ƒg“–‚½‚è‚ÌŽü”g” + point = (int)(fc / df + 0.5); // ”»’èƒ|ƒCƒ“ƒg‚ÌŽZo + theta = 2.0 * PAI * (double)point * df / fs; // ”»’èƒ|ƒCƒ“ƒg‚Å‚ÌˆÊ‘Š‚ÌŽZo + +// C0 = (int)((double)Q31 * cos(theta) + 0.5); +// S0 = (int)((double)Q31 * sin(theta) + 0.5); +// CN = (int)((double)Q31 * cos(((double)N - 1.0) * theta) + 0.5); +// SN = (int)((double)Q31 * sin(((double)N - 1.0) * theta) + 0.5); + + RamWrite32A( FRA_DMA_DeciShift, nDivision ); + RamWrite32A( FRA_DMB_C0, C0 ) ; + RamWrite32A( FRA_DMB_S0, S0 ) ; + RamWrite32A( FRA_DMB_CN, CN ) ; + RamWrite32A( FRA_DMB_SN, SN ) ; + +TRACE("0x%08X, 0x%08X, 0x%08X, 0x%08X,\n", C0, S0, CN, SN); +} + +//******************************************************************************** +// Function Name : Freq_Convert +// Retun Value : Phase Step Value +// Argment Value : Frequency +// Explanation : Convert Frequency +// History : First edition +//******************************************************************************** +UINT_32 Freq_Convert( float SfFreq ) +{ + UINT_32 UlPhsStep; + + UlPhsStep = ( UINT_32 )( ( SfFreq * ( float )0x100000000 / FS_FREQ + 0.5F ) / 2.0F ) ; + + return( UlPhsStep ) ; +} + + +//******************************************************************************** +// Function Name : MesStart_FRA_Single +// Retun Value : NON +// Argment Value : NON +// Explanation : Measure start setting Function +// History : First edition +//******************************************************************************** +void MesStart_FRA_Single( UINT_8 UcDirSel ) +{ + float SfTmp ; + INT_32 GainQ23, PhaseQ21 ; + UINT_32 UlReadVal ; + + SetSinWavGenInt() ; + // Change Frequency + RamWrite32A( SinWave_Offset, Freq_Convert( StFRAParam.StHostCom.SfFrqCom.SfFltVal ) ) ; // Freq Setting = Freq * 80000000h / Fs : 10Hz + + SfTmp = StFRAParam.StHostCom.SfAmpCom.SfFltVal / 1400.0F ; // AVDD 2800mV / 2 = 1400mV + RamWrite32A( SinWave_Gain, ( UINT_32 )( ( float )0x7FFFFFFF * SfTmp ) ) ; // Set Sine Wave Gain + + if ( StFRAParam.StHostCom.UcAvgCycl == 10) { // Actuator Through +#ifdef ACT_THROUGH_CLOSE + SetThroughParameter( UcDirSel ); + + if( UcDirSel == X_DIR ) { + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HXOFF1) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HallFilterD_HXDAZ1 ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HXOUT0 ) ; + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HYOFF1 ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HallFilterD_HYDAZ1) ; + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HYOUT0 ) ; + }else if( UcDirSel == Z_DIR ){ + } +#else + RtnCen( BOTH_OFF ) ; + if( UcDirSel == X_DIR ) { + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_SINDX1 ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HALL_RAM_SINDX1 ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HXIDAT ) ; + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_SINDY1 ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address + RamWrite32A( FRA_DMA_InputData, HALL_RAM_SINDY1 ) ; + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HYIDAT ) ; + } +#endif + }else{ + if( UcDirSel == X_DIR ) { + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HXOFF1) ; // Set Sine Wave Input RAM + // Set parameter and input/output address +#ifdef CLOSED_RESPONSE + RamWrite32A( FRA_DMA_InputData, HALL_RAM_HXOFF1 ) ; +#else + RamWrite32A( FRA_DMA_InputData, HallFilterD_HXDAZ1 ) ; +#endif + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HXOUT0 ) ; + }else if( UcDirSel == Y_DIR ){ + SetTransDataAdr( SinWave_OutAddr , (UINT_32)HALL_RAM_HYOFF1 ) ; // Set Sine Wave Input RAM + // Set parameter and input/output address +#ifdef CLOSED_RESPONSE + RamWrite32A( FRA_DMA_InputData, HALL_RAM_HYOFF1 ) ; +#else + RamWrite32A( FRA_DMA_InputData, HallFilterD_HYDAZ1) ; +#endif + RamWrite32A( FRA_DMA_OutputData, HALL_RAM_HYOUT0 ) ; + } + } + RamWrite32A( SinWaveC_Regsiter , 0x00000001 ) ; // Sine Wave Start + + CoeffGenerate( StFRAParam.StHostCom.SfFrqCom.SfFltVal ); +// WitTim(10); + // Start to measure + RamWrite32A( FRA_DMA_Control,1 ) ; + + if (nDivision == 0) WitTim(100); + if (nDivision == 1) WitTim(200); + if (nDivision == 2) WitTim(400); + if (nDivision == 3) WitTim(800); + if (nDivision == 4) WitTim(1600); + do{ + WitTim(10); + RamRead32A( FRA_DMA_Control , &UlReadVal ) ; + }while (UlReadVal == 1); + // Read answer + RamRead32A( FRA_DMA_Gain , &GainQ23 ) ; // Gain + RamRead32A( FRA_DMA_Phase , &PhaseQ21 ) ; // Phase + StFRAParam.StMesRslt.SfGainAvg = (float)GainQ23 / Q23; //0x007FFFFF; + StFRAParam.StMesRslt.SfPhaseAvg = (float)PhaseQ21 / Q21; //0x001FFFFF; + + TRACE("Phase %f deg : Gain %f dB\n", StFRAParam.StMesRslt.SfPhaseAvg, StFRAParam.StMesRslt.SfGainAvg ); +} + + + +//******************************************************************************** +// Function Name : MesStart_FRA_Continue +// Retun Value : NON +// Argment Value : NON +// Explanation : Continue Measurement Function +// History : First edition +//******************************************************************************** +void MesStart_FRA_Continue( void ) +{ + INT_32 GainQ23, PhaseQ21 ; + UINT_32 UlReadVal ; + + // Change Frequency + RamWrite32A( SinWave_Offset, Freq_Convert( StFRAParam.StHostCom.SfFrqCom.SfFltVal ) ) ; + // Set parameter + CoeffGenerate( StFRAParam.StHostCom.SfFrqCom.SfFltVal ); +// WitTim(10) + // Start to measure + RamWrite32A( FRA_DMA_Control,1 ) ; // Integral Value Clear + if (nDivision == 0) WitTim(100); + if (nDivision == 1) WitTim(200); + if (nDivision == 2) WitTim(400); + if (nDivision == 3) WitTim(800); + if (nDivision == 4) WitTim(1600); + do{ + WitTim(10); + RamRead32A( FRA_DMA_Control , &UlReadVal ) ; + }while (UlReadVal == 1); + // Read answer + RamRead32A( FRA_DMA_Gain , &GainQ23 ) ; // Gain + RamRead32A( FRA_DMA_Phase , &PhaseQ21 ) ; // Phase + StFRAParam.StMesRslt.SfGainAvg = (float)GainQ23 / Q23; + StFRAParam.StMesRslt.SfPhaseAvg = (float)PhaseQ21 / Q21; + + TRACE("Phase %f deg : Gain %f dB\n", StFRAParam.StMesRslt.SfPhaseAvg, StFRAParam.StMesRslt.SfGainAvg ); +} + + + +//******************************************************************************** +// Function Name : MesEnd_FRA_Sweep +// Retun Value : NON +// Argment Value : NON +// Explanation : Stop Measurement Function +// History : First edition +//******************************************************************************** +void MesEnd_FRA_Sweep( void ) +{ + // Stop Sine Wave + RamWrite32A( SinWaveC_Regsiter, 0x00000000 ) ; // Sine Wave Stop + SetTransDataAdr( SinWave_OutAddr, ( UINT_32 )0x00000000 ) ; // Set Sine Wave Input RAM + + if ( StFRAParam.StHostCom.UcAvgCycl == 10) { // Actuator Through +#ifdef ACT_THROUGH_CLOSE + ResetThroughParameter( ); +#else + RtnCen( BOTH_ON ) ; +#endif + } + RamWrite32A( HALL_RAM_SINDX1, 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_RAM_SINDY1, 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_RAM_HXOFF1, 0x00000000 ) ; // DelayRam Clear + RamWrite32A( HALL_RAM_HYOFF1, 0x00000000 ) ; // DelayRam Clear + +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisFRA.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisFRA.h new file mode 100755 index 0000000000000000000000000000000000000000..d0af28d9675af945e680effe330f318a009de3b4 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisFRA.h @@ -0,0 +1,62 @@ +/** + * @brief FRA measurement header for LC898123 F40 + * API List for customers + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file OisAPI.h + * @date svn:$Date:: 2016-04-28 14:30:21 +0900#$ + * @version svn:$Revision: 43 $ + * @attention + **/ +#ifndef OISFRA_H_ +#define OISFRA_H_ + +//**************************************************** +// extern selector for API +//**************************************************** +#ifdef __OISFRA__ + #define __OIS_FRA_HEADER__ +#else + #define __OIS_FRA_HEADER__ extern +#endif + +typedef struct STFRA_PARAM { + struct { + UnllnVal SfFrqCom ; + UnllnVal SfAmpCom ; + unsigned char UcAvgCycl ; + } StHostCom ; + + float SfGain[ 10 ] ; + float SfPhase[ 10 ] ; + + struct { + float SfGainAvg ; + float SfPhaseAvg ; + } StMesRslt ; +} StFRAParam_t ; + +__OIS_FRA_HEADER__ StFRAParam_t StFRAParam ; +/* +typedef struct STFRA_MES { + UINT_64 UllCumulAdd1 ; + UINT_64 UllCumulAdd2 ; + UINT_16 UsFsCount ; +} StFRAMes_t ; + +__OIS_FRA_HEADER__ StFRAMes_t StFRAMes ; + +typedef struct { + INT_32 a1 ; + INT_32 b1 ; + INT_32 c1 ; + INT_32 a2 ; + INT_32 b2 ; + INT_32 c2 ; +} StMesFCoeff_t ; + +*/ + + +#endif // OISFRA_H_ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisLc898128.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisLc898128.h new file mode 100755 index 0000000000000000000000000000000000000000..0b21c73ee3d266ae15e09eaf3faf0048e8bd43d8 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/OisLc898128.h @@ -0,0 +1,587 @@ +/** + * @brief LC898128 Global declaration & prototype declaration + * + * @author Copyright (C) 2016, ON Semiconductor, all right reserved. + * + * @file OisLc898128.h + * @date svn:$Date:: 2016-06-17 16:42:32 +0900#$ + * @version svn:$Revision: 54 $ + * @attention + **/ + +/************************************************/ +/* Command */ +/************************************************/ + // Calibration flags + #define HALL_CALB_FLG 0x00008000 + #define HALL_CALB_BIT 0x00FF00FF + #define GYRO_GAIN_FLG 0x00004000 + #define CAL_ANGLE_FLG 0x00000800 // angle correct calibration + #define HLLN_CALB_FLG 0x00000400 // Hall linear calibration + #define MIXI_CALB_FLG 0x00000200 // Mixing calibration +//============================================================================== +// Calibration Data Memory Map +//============================================================================== +// Calibration Status +#define CALIBRATION_STATUS ( 0 ) +// Hall Bias/Offset +#define HALL_BIAS_OFFSET ( 1 ) // 0:XBIAS 1:XOFFSET 2:YBIAS 3:YOFFSET +// Loop Gain Calibration +#define LOOP_GAIN_XY ( 2 ) // [1:0]X [3:2]Y +// Lens Center Calibration +#define LENS_OFFSET ( 3 ) // [1:0]X [3:2]Y +// Gyro Gain Calibration +#define GYRO_GAIN_X ( 4 ) +#define GYRO_GAIN_Y ( 5 ) +// Liniearity correction +#define LN_POS1 ( 6 ) // [3:2]Y [1:0]X +#define LN_POS2 ( 7 ) // [3:2]Y [1:0]X +#define LN_POS3 ( 8 ) // [3:2]Y [1:0]X +#define LN_POS4 ( 9 ) // [3:2]Y [1:0]X +#define LN_POS5 ( 10 ) // [3:2]Y [1:0]X +#define LN_POS6 ( 11 ) // [3:2]Y [1:0]X +#define LN_POS7 ( 12 ) // [3:2]Y [1:0]X +#define LN_STEP ( 13 ) // [3:2]Y [1:0]X +// Gyro mixing correction +#define MIXING_X ( 14 ) // [3:2]XY [1:0]XX +#define MIXING_Y ( 15 ) // [3:2]YX [1:0]YY +#define MIXING_SFT ( 16 ) // 1:YSFT 0:XSHT +//// Gyro Offset Calibration +//#define G_OFFSET_XY ( 18 ) // [3:2]GY offset [1:0]GX offset +//#define G_OFFSET_Z_AX ( 19 ) // [3:2]AX offset [1:0]GZ offset +//#define A_OFFSET_YZ ( 20 ) // [3:2]AZ offset [1:0]AY offset +// back up hall max and min +#define HL_XMAXMIN ( 18 ) // [3:2]MAX [1:0]MIN +#define HL_YMAXMIN ( 19) // [3:2]MAX [1:0]MIN +// Angle correct Correction. + +#define OPTCENTER ( 29 ) // [3:2]Y [1:0]X +// include check sum +#define MAT0_CKSM ( 31 ) // [3:2]AZ offset [1:0]AY offset + +#define FT_REPRG ( 15 ) + #define PRDCT_WR 0x55555555 + #define USER_WR 0xAAAAAAAA +#define MAT2_CKSM ( 29 ) +#define CHECKCODE1 ( 30 ) + #define CHECK_CODE1 0x99756768 +#define CHECKCODE2 ( 31 ) + #define CHECK_CODE2 0x01AC28AC + + + +//============================================================================== +//DMA +//============================================================================== +#define HallFilterD_HXDAZ1 0x0048 +#define HallFilterD_HYDAZ1 0x0098 +#define HALL_RAM_X_COMMON 0x00D8 +#define HALL_RAM_HXOFF 0x0000 + HALL_RAM_X_COMMON +#define HALL_RAM_HXOFF1 0x0004 + HALL_RAM_X_COMMON +#define HALL_RAM_HXOUT0 0x0008 + HALL_RAM_X_COMMON +#define HALL_RAM_HXOUT1 0x000C + HALL_RAM_X_COMMON +#define HALL_RAM_SINDX0 0x0010 + HALL_RAM_X_COMMON +#define HALL_RAM_HXLOP 0x0014 + HALL_RAM_X_COMMON +#define HALL_RAM_SINDX1 0x0018 + HALL_RAM_X_COMMON +#define HALL_RAM_HALL_X_OUT 0x001C + HALL_RAM_X_COMMON +#define XMoveAvg_D2 0x0030 + HALL_RAM_X_COMMON +#define HALL_RAM_HXOUT2 0x0038 + HALL_RAM_X_COMMON +#define HALL_RAM_HXOUT3 0x0048 + HALL_RAM_X_COMMON +#define HALL_RAM_HALL_SwitchX 0x0124 + +#define HALL_RAM_Y_COMMON 0x0128 +#define HALL_RAM_HYOFF 0x0000 + HALL_RAM_Y_COMMON +#define HALL_RAM_HYOFF1 0x0004 + HALL_RAM_Y_COMMON +#define HALL_RAM_HYOUT0 0x0008 + HALL_RAM_Y_COMMON +#define HALL_RAM_HYOUT1 0x000C + HALL_RAM_Y_COMMON +#define HALL_RAM_SINDY0 0x0010 + HALL_RAM_Y_COMMON +#define HALL_RAM_HYLOP 0x0014 + HALL_RAM_Y_COMMON +#define HALL_RAM_SINDY1 0x0018 + HALL_RAM_Y_COMMON +#define HALL_RAM_HALL_Y_OUT 0x001C + HALL_RAM_Y_COMMON +#define YMoveAvg_D2 0x0030 + HALL_RAM_Y_COMMON +#define HALL_RAM_HYOUT2 0x0038 + HALL_RAM_Y_COMMON +#define HALL_RAM_HYOUT3 0x0048 + HALL_RAM_Y_COMMON +#define HALL_RAM_HALL_SwitchY 0x0174 + + +#define HALL_RAM_COMMON 0x0178 + // HallFilterDelay.h HALL_RAM_COMMON_t +#define HALL_RAM_HXIDAT 0x0000 + HALL_RAM_COMMON +#define HALL_RAM_HYIDAT 0x0004 + HALL_RAM_COMMON +#define HALL_RAM_GYROX_OUT 0x0008 + HALL_RAM_COMMON +#define HALL_RAM_GYROY_OUT 0x000C + HALL_RAM_COMMON + +#define GyroFilterDelayX_GXH1Z2 0x019C +#define GyroFilterDelayY_GYH1Z2 0x01C4 + +#define GYRO_RAM_X 0x01D8 + // GyroFilterDelay.h GYRO_RAM_t +#define GYRO_RAM_GYROX_OFFSET 0x0000 + GYRO_RAM_X +#define GYRO_RAM_GX2X4XF_IN 0x0004 + GYRO_RAM_X +#define GYRO_RAM_GX2X4XF_OUT 0x0008 + GYRO_RAM_X +#define GYRO_RAM_GXFAST 0x000C + GYRO_RAM_X +#define GYRO_RAM_GXSLOW 0x0010 + GYRO_RAM_X +#define GYRO_RAM_GYROX_G1OUT 0x0014 + GYRO_RAM_X +#define GYRO_RAM_GYROX_G2OUT 0x0018 + GYRO_RAM_X +#define GYRO_RAM_GYROX_G3OUT 0x001C + GYRO_RAM_X +#define GYRO_RAM_GYROX_OUT 0x0020 + GYRO_RAM_X + +#define GYRO_RAM_Y 0x01FC + // GyroFilterDelay.h GYRO_RAM_t +#define GYRO_RAM_GYROY_OFFSET 0x0000 + GYRO_RAM_Y +#define GYRO_RAM_GY2X4XF_IN 0x0004 + GYRO_RAM_Y +#define GYRO_RAM_GY2X4XF_OUT 0x0008 + GYRO_RAM_Y +#define GYRO_RAM_GYFAST 0x000C + GYRO_RAM_Y +#define GYRO_RAM_GYSLOW 0x0010 + GYRO_RAM_Y +#define GYRO_RAM_GYROY_G1OUT 0x0014 + GYRO_RAM_Y +#define GYRO_RAM_GYROY_G2OUT 0x0018 + GYRO_RAM_Y +#define GYRO_RAM_GYROY_G3OUT 0x001C + GYRO_RAM_Y +#define GYRO_RAM_GYROY_OUT 0x0020 + GYRO_RAM_Y + +#define GYRO_RAM_COMMON 0x0220 + // GyroFilterDelay.h GYRO_RAM_COMMON_t +#define GYRO_RAM_GX_ADIDAT 0x0000 + GYRO_RAM_COMMON +#define GYRO_RAM_GY_ADIDAT 0x0004 + GYRO_RAM_COMMON +#define GYRO_RAM_SINDX 0x0008 + GYRO_RAM_COMMON +#define GYRO_RAM_SINDY 0x000C + GYRO_RAM_COMMON +#define GYRO_RAM_GXLENSZ 0x0010 + GYRO_RAM_COMMON +#define GYRO_RAM_GYLENSZ 0x0014 + GYRO_RAM_COMMON +#define GYRO_RAM_GXOX_OUT 0x0018 + GYRO_RAM_COMMON +#define GYRO_RAM_GYOX_OUT 0x001C + GYRO_RAM_COMMON +#define GYRO_RAM_GXOFFZ 0x0020 + GYRO_RAM_COMMON +#define GYRO_RAM_GYOFFZ 0x0024 + GYRO_RAM_COMMON +#define GYRO_RAM_LIMITX 0x0028 + GYRO_RAM_COMMON +#define GYRO_RAM_LIMITY 0x002C + GYRO_RAM_COMMON +#define GYRO_RAM_GYROX_AFCnt 0x0030 + GYRO_RAM_COMMON +#define GYRO_RAM_GYROY_AFCnt 0x0034 + GYRO_RAM_COMMON +#define GYRO_RAM_GYRO_Switch 0x0038 + GYRO_RAM_COMMON // 1Byte + +#define StMeasureFunc 0x0278 + // MeasureFilter.h MeasureFunction_Type +#define StMeasFunc_SiSampleNum 0x0000 + StMeasureFunc // +#define StMeasFunc_SiSampleMax 0x0004 + StMeasureFunc // + +#define StMeasureFunc_MFA 0x0280 +#define StMeasFunc_MFA_SiMax1 0x0000 + StMeasureFunc_MFA +#define StMeasFunc_MFA_SiMin1 0x0004 + StMeasureFunc_MFA +#define StMeasFunc_MFA_UiAmp1 0x0008 + StMeasureFunc_MFA +#define StMeasFunc_MFA_UiDUMMY1 0x000C + StMeasureFunc_MFA +#define StMeasFunc_MFA_LLiIntegral1 0x0010 + StMeasureFunc_MFA +#define StMeasFunc_MFA_LLiAbsInteg1 0x0018 + StMeasureFunc_MFA +#define StMeasFunc_MFA_PiMeasureRam1 0x0020 + StMeasureFunc_MFA + +#define StMeasureFunc_MFB 0x02A8 +#define StMeasFunc_MFB_SiMax2 0x0000 + StMeasureFunc_MFB +#define StMeasFunc_MFB_SiMin2 0x0004 + StMeasureFunc_MFB +#define StMeasFunc_MFB_UiAmp2 0x0008 + StMeasureFunc_MFB +#define StMeasFunc_MFB_UiDUMMY1 0x000C + StMeasureFunc_MFB +#define StMeasFunc_MFB_LLiIntegral2 0x0010 + StMeasureFunc_MFB +#define StMeasFunc_MFB_LLiAbsInteg2 0x0018 + StMeasureFunc_MFB +#define StMeasFunc_MFB_PiMeasureRam2 0x0020 + StMeasureFunc_MFB + +#define MeasureFilterA_Delay 0x02D0 + // MeasureFilter.h MeasureFilter_Delay_Type +#define MeasureFilterA_Delay_z11 0x0000 + MeasureFilterA_Delay +#define MeasureFilterA_Delay_z12 0x0004 + MeasureFilterA_Delay +#define MeasureFilterA_Delay_z21 0x0008 + MeasureFilterA_Delay +#define MeasureFilterA_Delay_z22 0x000C + MeasureFilterA_Delay + +#define MeasureFilterB_Delay 0x02E0 + // MeasureFilter.h MeasureFilter_Delay_Type +#define MeasureFilterB_Delay_z11 0x0000 + MeasureFilterB_Delay +#define MeasureFilterB_Delay_z12 0x0004 + MeasureFilterB_Delay +#define MeasureFilterB_Delay_z21 0x0008 + MeasureFilterB_Delay +#define MeasureFilterB_Delay_z22 0x000C + MeasureFilterB_Delay + +#define SinWaveC 0x02F0 +#define SinWaveC_Pt 0x0000 + SinWaveC +#define SinWaveC_Regsiter 0x0004 + SinWaveC +//#define SinWaveC_SignFlag 0x0004 + SinWaveC_Regsiter + +#define SinWave 0x02FC + // SinGenerator.h SinWave_t +#define SinWave_Offset 0x0000 + SinWave +#define SinWave_Phase 0x0004 + SinWave +#define SinWave_Gain 0x0008 + SinWave +#define SinWave_Output 0x000C + SinWave +#define SinWave_OutAddr 0x0010 + SinWave +#define CosWave 0x0310 + // SinGenerator.h SinWave_t +#define CosWave_Offset 0x0000 + CosWave +#define CosWave_Phase 0x0004 + CosWave +#define CosWave_Gain 0x0008 + CosWave +#define CosWave_Output 0x000C + CosWave +#define CosWave_OutAddr 0x0010 + CosWave + +#define WaitTimerData 0x0324 + // CommonLibrary.h WaitTimer_Type +#define WaitTimerData_UiWaitCounter 0x0000 + WaitTimerData +#define WaitTimerData_UiTargetCount 0x0004 + WaitTimerData + +#define PanTilt_DMA 0x0338 +#define PanTilt_DMA_ScTpdSts 0x000C + PanTilt_DMA + +//#ifdef SEL_SHIFT_COR +#define GyroRAM_Z_GYRO_OFFSET 0x0378 + +#define GYRO_ZRAM_GZ_ADIDAT 0x039C +#define GYRO_ZRAM_GZOFFZ 0x03A8 + +#define AcclFilDly_X 0x03C0 +#define AcclFilDly_Y 0x03F0 +#define AcclFilDly_Z 0x0420 + +#define AcclRAM_X 0x0450 +#define ACCLRAM_X_AC_ADIDAT 0x0000 + AcclRAM_X +#define ACCLRAM_X_AC_OFFSET 0x0004 + AcclRAM_X + +#define AcclRAM_Y 0x047C +#define ACCLRAM_Y_AC_ADIDAT 0x0000 + AcclRAM_Y +#define ACCLRAM_Y_AC_OFFSET 0x0004 + AcclRAM_Y + +#define AcclRAM_Z 0x04A8 +#define ACCLRAM_Z_AC_ADIDAT 0x0000 + AcclRAM_Z +#define ACCLRAM_Z_AC_OFFSET 0x0004 + AcclRAM_Z +//#endif //SEL_SHIFT_COR + +#define OpticalOffset_X (0x558) +#define OpticalOffset_Y (0x55C) + +#define FRA_DMA (0xB40) +#define FRA_DMA_Control (0x04 + FRA_DMA ) +//#define FRA_DMA_DeciCount (0x0C + FRA_DMA ) +#define FRA_DMA_DeciShift (0x10 + FRA_DMA ) +#define FRA_DMA_InputData (0x18 + FRA_DMA ) +#define FRA_DMA_OutputData (0x1C + FRA_DMA ) + +#define FRA_DMA_Gain (0x70 + FRA_DMA ) +#define FRA_DMA_Phase (0x74 + FRA_DMA ) +//============================================================================== +//DMB +//============================================================================== +#define SiVerNum 0x8000 + #define ACT_TVAXXXX 0x01 + #define ACT_45DEG 0xff // dummy + + #define GYRO_ICM20690 0x00 + #define GYRO_LSM6DSM 0x02 +#define SiCalID 0x8004 +#define SiActInf 0x8008 + +#define StCalibrationData 0x8010 + // Calibration.h CalibrationData_Type +#define StCaliData_UsCalibrationStatus 0x0000 + StCalibrationData +#define StCaliData_UiHallValue0 0x0004 + StCalibrationData +#define StCaliData_UiHallValue1 0x0008 + StCalibrationData +#define StCaliData_UiHallValue2 0x000C + StCalibrationData +#define StCaliData_UiHallValue3 0x0010 + StCalibrationData +#define StCaliData_UiHallValue4 0x0014 + StCalibrationData +#define StCaliData_UiHallValue5 0x0018 + StCalibrationData +#define StCaliData_UiHallValue6 0x001C + StCalibrationData +#define StCaliData_UiHallValue7 0x0020 + StCalibrationData +#define StCaliData_UiHallBias_X 0x0024 + StCalibrationData +#define StCaliData_UiHallOffset_X 0x0028 + StCalibrationData +#define StCaliData_UiHallBias_Y 0x002C + StCalibrationData +#define StCaliData_UiHallOffset_Y 0x0030 + StCalibrationData +#define StCaliData_SiLoopGain_X 0x0034 + StCalibrationData +#define StCaliData_SiLoopGain_Y 0x0038 + StCalibrationData +#define StCaliData_SiLensCen_Offset_X 0x003C + StCalibrationData +#define StCaliData_SiLensCen_Offset_Y 0x0040 + StCalibrationData +#define StCaliData_SiOtpCen_Offset_X 0x0044 + StCalibrationData +#define StCaliData_SiOtpCen_Offset_Y 0x0048 + StCalibrationData +#define StCaliData_SiGyroOffset_X 0x004C + StCalibrationData +#define StCaliData_SiGyroOffset_Y 0x0050 + StCalibrationData +#define StCaliData_SiGyroGain_X 0x0054 + StCalibrationData +#define StCaliData_SiGyroGain_Y 0x0058 + StCalibrationData + +#define HallFilterCoeffX_hxgoutg 0x8094 +//#define HallFilterCoeffX_hxgain0 0x80F0 +//#define HallFilterCoeffX_hxgain1 0x80F4 + +#define HallFilterCoeffY_hygoutg 0x8130 +//#define HallFilterCoeffY_hygain0 0x818C +//#define HallFilterCoeffY_hygain1 0x8190 + +#define HallFilterCoeffX 0x8090 + // HallFilterCoeff.h DM_HFC_t +#define HallFilterCoeffX_HXIGAIN 0x0000 + HallFilterCoeffX +#define HallFilterCoeffX_GYROXOUTGAIN 0x0004 + HallFilterCoeffX_HXIGAIN +#define HallFilterCoeffX_HXOFFGAIN 0x0004 + HallFilterCoeffX_GYROXOUTGAIN + +#define HallFilterCoeffX_hxiab 0x0004 + HallFilterCoeffX_HXOFFGAIN +#define HallFilterCoeffX_hxiac 0x0004 + HallFilterCoeffX_hxiab +#define HallFilterCoeffX_hxiaa 0x0004 + HallFilterCoeffX_hxiac +#define HallFilterCoeffX_hxibb 0x0004 + HallFilterCoeffX_hxiaa +#define HallFilterCoeffX_hxibc 0x0004 + HallFilterCoeffX_hxibb +#define HallFilterCoeffX_hxiba 0x0004 + HallFilterCoeffX_hxibc +#define HallFilterCoeffX_hxdab 0x0004 + HallFilterCoeffX_hxiba +#define HallFilterCoeffX_hxdac 0x0004 + HallFilterCoeffX_hxdab +#define HallFilterCoeffX_hxdaa 0x0004 + HallFilterCoeffX_hxdac +#define HallFilterCoeffX_hxdbb 0x0004 + HallFilterCoeffX_hxdaa +#define HallFilterCoeffX_hxdbc 0x0004 + HallFilterCoeffX_hxdbb +#define HallFilterCoeffX_hxdba 0x0004 + HallFilterCoeffX_hxdbc +#define HallFilterCoeffX_hxdcc 0x0004 + HallFilterCoeffX_hxdba +#define HallFilterCoeffX_hxdcb 0x0004 + HallFilterCoeffX_hxdcc +#define HallFilterCoeffX_hxdca 0x0004 + HallFilterCoeffX_hxdcb +#define HallFilterCoeffX_hxpgain0 0x0004 + HallFilterCoeffX_hxdca +#define HallFilterCoeffX_hxigain0 0x0004 + HallFilterCoeffX_hxpgain0 +#define HallFilterCoeffX_hxdgain0 0x0004 + HallFilterCoeffX_hxigain0 +#define HallFilterCoeffX_hxpgain1 0x0004 + HallFilterCoeffX_hxdgain0 +#define HallFilterCoeffX_hxigain1 0x0004 + HallFilterCoeffX_hxpgain1 +#define HallFilterCoeffX_hxdgain1 0x0004 + HallFilterCoeffX_hxigain1 +#define HallFilterCoeffX_hxgain0 0x0004 + HallFilterCoeffX_hxdgain1 +#define HallFilterCoeffX_hxgain1 0x0004 + HallFilterCoeffX_hxgain0 + +#define HallFilterCoeffX_hxsb 0x0004 + HallFilterCoeffX_hxgain1 +#define HallFilterCoeffX_hxsc 0x0004 + HallFilterCoeffX_hxsb +#define HallFilterCoeffX_hxsa 0x0004 + HallFilterCoeffX_hxsc + +#define HallFilterCoeffX_hxob 0x0004 + HallFilterCoeffX_hxsa +#define HallFilterCoeffX_hxoc 0x0004 + HallFilterCoeffX_hxob +#define HallFilterCoeffX_hxod 0x0004 + HallFilterCoeffX_hxoc +#define HallFilterCoeffX_hxoe 0x0004 + HallFilterCoeffX_hxod +#define HallFilterCoeffX_hxoa 0x0004 + HallFilterCoeffX_hxoe +#define HallFilterCoeffX_hxpb 0x0004 + HallFilterCoeffX_hxoa +#define HallFilterCoeffX_hxpc 0x0004 + HallFilterCoeffX_hxpb +#define HallFilterCoeffX_hxpd 0x0004 + HallFilterCoeffX_hxpc +#define HallFilterCoeffX_hxpe 0x0004 + HallFilterCoeffX_hxpd +#define HallFilterCoeffX_hxpa 0x0004 + HallFilterCoeffX_hxpe + +#define HallFilterCoeffY 0x812c + // HallFilterCoeff.h DM_HFC_t +#define HallFilterCoeffY_HYIGAIN 0x0000 + HallFilterCoeffY +#define HallFilterCoeffY_GYROYOUTGAIN 0x0004 + HallFilterCoeffY_HYIGAIN +#define HallFilterCoeffY_HYOFFGAIN 0x0004 + HallFilterCoeffY_GYROYOUTGAIN + +#define HallFilterCoeffY_hyiab 0x0004 + HallFilterCoeffY_HYOFFGAIN +#define HallFilterCoeffY_hyiac 0x0004 + HallFilterCoeffY_hyiab +#define HallFilterCoeffY_hyiaa 0x0004 + HallFilterCoeffY_hyiac +#define HallFilterCoeffY_hyibb 0x0004 + HallFilterCoeffY_hyiaa +#define HallFilterCoeffY_hyibc 0x0004 + HallFilterCoeffY_hyibb +#define HallFilterCoeffY_hyiba 0x0004 + HallFilterCoeffY_hyibc +#define HallFilterCoeffY_hydab 0x0004 + HallFilterCoeffY_hyiba +#define HallFilterCoeffY_hydac 0x0004 + HallFilterCoeffY_hydab +#define HallFilterCoeffY_hydaa 0x0004 + HallFilterCoeffY_hydac +#define HallFilterCoeffY_hydbb 0x0004 + HallFilterCoeffY_hydaa +#define HallFilterCoeffY_hydbc 0x0004 + HallFilterCoeffY_hydbb +#define HallFilterCoeffY_hydba 0x0004 + HallFilterCoeffY_hydbc +#define HallFilterCoeffY_hydcc 0x0004 + HallFilterCoeffY_hydba +#define HallFilterCoeffY_hydcb 0x0004 + HallFilterCoeffY_hydcc +#define HallFilterCoeffY_hydca 0x0004 + HallFilterCoeffY_hydcb +#define HallFilterCoeffY_hypgain0 0x0004 + HallFilterCoeffY_hydca +#define HallFilterCoeffY_hyigain0 0x0004 + HallFilterCoeffY_hypgain0 +#define HallFilterCoeffY_hydgain0 0x0004 + HallFilterCoeffY_hyigain0 +#define HallFilterCoeffY_hypgain1 0x0004 + HallFilterCoeffY_hydgain0 +#define HallFilterCoeffY_hyigain1 0x0004 + HallFilterCoeffY_hypgain1 +#define HallFilterCoeffY_hydgain1 0x0004 + HallFilterCoeffY_hyigain1 +#define HallFilterCoeffY_hygain0 0x0004 + HallFilterCoeffY_hydgain1 +#define HallFilterCoeffY_hygain1 0x0004 + HallFilterCoeffY_hygain0 +#define HallFilterCoeffY_hysb 0x0004 + HallFilterCoeffY_hygain1 +#define HallFilterCoeffY_hysc 0x0004 + HallFilterCoeffY_hysb +#define HallFilterCoeffY_hysa 0x0004 + HallFilterCoeffY_hysc +#define HallFilterCoeffY_hyob 0x0004 + HallFilterCoeffY_hysa +#define HallFilterCoeffY_hyoc 0x0004 + HallFilterCoeffY_hyob +#define HallFilterCoeffY_hyod 0x0004 + HallFilterCoeffY_hyoc +#define HallFilterCoeffY_hyoe 0x0004 + HallFilterCoeffY_hyod +#define HallFilterCoeffY_hyoa 0x0004 + HallFilterCoeffY_hyoe +#define HallFilterCoeffY_hypb 0x0004 + HallFilterCoeffY_hyoa +#define HallFilterCoeffY_hypc 0x0004 + HallFilterCoeffY_hypb +#define HallFilterCoeffY_hypd 0x0004 + HallFilterCoeffY_hypc +#define HallFilterCoeffY_hype 0x0004 + HallFilterCoeffY_hypd +#define HallFilterCoeffY_hypa 0x0004 + HallFilterCoeffY_hype + +#define HallFilterLimitX 0x81c8 +#define HallFilterLimitY 0x81e0 +#define HallFilterShiftX 0x81f8 +#define HallFilterShiftY 0x81fe + +#define HF_MIXING 0x8214 +#define HF_hx45x 0x0000 + HF_MIXING +#define HF_hx45y 0x0004 + HF_MIXING +#define HF_hy45y 0x0008 + HF_MIXING +#define HF_hy45x 0x000C + HF_MIXING +#define HF_ShiftX 0x0010 + HF_MIXING + +#define HAL_LN_CORRECT 0x8228 +#define HAL_LN_COEFAX 0x0000 + HAL_LN_CORRECT +#define HAL_LN_COEFBX 0x000C + HAL_LN_COEFAX +#define HAL_LN_ZONEX 0x000C + HAL_LN_COEFBX +#define HAL_LN_COEFAY 0x000A + HAL_LN_ZONEX +#define HAL_LN_COEFBY 0x000C + HAL_LN_COEFAY +#define HAL_LN_ZONEY 0x000C + HAL_LN_COEFBY + +#define GyroFilterTableX 0x8270 + // GyroFilterCoeff.h DM_GFC_t +#define GyroFilterTableX_gx45x 0x0000 + GyroFilterTableX +#define GyroFilterTableX_gx45y 0x0004 + GyroFilterTableX +#define GyroFilterTableX_gxgyro 0x0008 + GyroFilterTableX +#define GyroFilterTableX_gxsengen 0x000C + GyroFilterTableX +#define GyroFilterTableX_gxl1b 0x0010 + GyroFilterTableX +#define GyroFilterTableX_gxl1c 0x0014 + GyroFilterTableX +#define GyroFilterTableX_gxl1a 0x0018 + GyroFilterTableX +#define GyroFilterTableX_gxl2b 0x001C + GyroFilterTableX +#define GyroFilterTableX_gxl2c 0x0020 + GyroFilterTableX +#define GyroFilterTableX_gxl2a 0x0024 + GyroFilterTableX +#define GyroFilterTableX_gxigain 0x0028 + GyroFilterTableX +#define GyroFilterTableX_gxh1b 0x002C + GyroFilterTableX +#define GyroFilterTableX_gxh1c 0x0030 + GyroFilterTableX +#define GyroFilterTableX_gxh1a 0x0034 + GyroFilterTableX +#define GyroFilterTableX_gxk1b 0x0038 + GyroFilterTableX +#define GyroFilterTableX_gxk1c 0x003C + GyroFilterTableX +#define GyroFilterTableX_gxk1a 0x0040 + GyroFilterTableX +#define GyroFilterTableX_gxgain 0x0044 + GyroFilterTableX +#define GyroFilterTableX_gxzoom 0x0048 + GyroFilterTableX +#define GyroFilterTableX_gxlenz 0x004C + GyroFilterTableX +#define GyroFilterTableX_gxt2b 0x0050 + GyroFilterTableX +#define GyroFilterTableX_gxt2c 0x0054 + GyroFilterTableX +#define GyroFilterTableX_gxt2a 0x0058 + GyroFilterTableX +#define GyroFilterTableX_afzoom 0x005C + GyroFilterTableX + +#define GyroFilterTableY 0x82D0 + // GyroFilterCoeff.h DM_GFC_t +#define GyroFilterTableY_gy45y 0x0000 + GyroFilterTableY +#define GyroFilterTableY_gy45x 0x0004 + GyroFilterTableY +#define GyroFilterTableY_gygyro 0x0008 + GyroFilterTableY +#define GyroFilterTableY_gysengen 0x000C + GyroFilterTableY +#define GyroFilterTableY_gyl1b 0x0010 + GyroFilterTableY +#define GyroFilterTableY_gyl1c 0x0014 + GyroFilterTableY +#define GyroFilterTableY_gyl1a 0x0018 + GyroFilterTableY +#define GyroFilterTableY_gyl2b 0x001C + GyroFilterTableY +#define GyroFilterTableY_gyl2c 0x0020 + GyroFilterTableY +#define GyroFilterTableY_gyl2a 0x0024 + GyroFilterTableY +#define GyroFilterTableY_gyigain 0x0028 + GyroFilterTableY +#define GyroFilterTableY_gyh1b 0x002C + GyroFilterTableY +#define GyroFilterTableY_gyh1c 0x0030 + GyroFilterTableY +#define GyroFilterTableY_gyh1a 0x0034 + GyroFilterTableY +#define GyroFilterTableY_gyk1b 0x0038 + GyroFilterTableY +#define GyroFilterTableY_gyk1c 0x003C + GyroFilterTableY +#define GyroFilterTableY_gyk1a 0x0040 + GyroFilterTableY +#define GyroFilterTableY_gygain 0x0044 + GyroFilterTableY +#define GyroFilterTableY_gyzoom 0x0048 + GyroFilterTableY +#define GyroFilterTableY_gylenz 0x004C + GyroFilterTableY +#define GyroFilterTableY_gyt2b 0x0050 + GyroFilterTableY +#define GyroFilterTableY_gyt2c 0x0054 + GyroFilterTableY +#define GyroFilterTableY_gyt2a 0x0058 + GyroFilterTableY +#define GyroFilterTableY_afzoom 0x005C + GyroFilterTableY + +#define Gyro_Limiter_X 0x8330 +#define Gyro_Limiter_Y 0x8334 + +#define GyroFilterShiftX 0x8338 + // GyroFilterCoeff.h GF_Shift_t +#define RG_GX2X4XF 0x0000 + GyroFilterShiftX +#define RG_GX2X4XB 0x0001 + GyroFilterShiftX +#define RG_GXOX 0x0002 + GyroFilterShiftX +#define RG_GXAFZ 0x0003 + GyroFilterShiftX + +#define GyroFilterShiftY 0x833C + // GyroFilterCoeff.h GF_Shift_t +#define RG_GY2X4XF 0x0000 + GyroFilterShiftY +#define RG_GY2X4XB 0x0001 + GyroFilterShiftY +#define RG_GYOX 0x0002 + GyroFilterShiftY +#define RG_GYAFZ 0x0003 + GyroFilterShiftY + +#define MeasureFilterA_Coeff 0x8380 + // MeasureFilter.h MeasureFilter_Type +#define MeasureFilterA_Coeff_b1 0x0000 + MeasureFilterA_Coeff +#define MeasureFilterA_Coeff_c1 0x0004 + MeasureFilterA_Coeff +#define MeasureFilterA_Coeff_a1 0x0008 + MeasureFilterA_Coeff +#define MeasureFilterA_Coeff_b2 0x000C + MeasureFilterA_Coeff +#define MeasureFilterA_Coeff_c2 0x0010 + MeasureFilterA_Coeff +#define MeasureFilterA_Coeff_a2 0x0014 + MeasureFilterA_Coeff + +#define MeasureFilterB_Coeff 0x8398 + // MeasureFilter.h MeasureFilter_Type +#define MeasureFilterB_Coeff_b1 0x0000 + MeasureFilterB_Coeff +#define MeasureFilterB_Coeff_c1 0x0004 + MeasureFilterB_Coeff +#define MeasureFilterB_Coeff_a1 0x0008 + MeasureFilterB_Coeff +#define MeasureFilterB_Coeff_b2 0x000C + MeasureFilterB_Coeff +#define MeasureFilterB_Coeff_c2 0x0010 + MeasureFilterB_Coeff +#define MeasureFilterB_Coeff_a2 0x0014 + MeasureFilterB_Coeff + + +#define Accl45Filter 0x8640 +#define Accl45Filter_XAmain (0x0000 + Accl45Filter ) +#define Accl45Filter_XAsub (0x0004 + Accl45Filter ) +#define Accl45Filter_YAmain (0x0008 + Accl45Filter ) +#define Accl45Filter_YAsub (0x000C + Accl45Filter ) + +#define MotionSensor_Sel 0x865C +#define MS_SEL_GX0 0x0000 + MotionSensor_Sel +#define MS_SEL_GX1 0x0004 + MotionSensor_Sel +#define MS_SEL_GY0 0x0008 + MotionSensor_Sel +#define MS_SEL_GY1 0x000C + MotionSensor_Sel +#define MS_SEL_GZ 0x0010 + MotionSensor_Sel +#define MS_SEL_AX0 0x0014 + MotionSensor_Sel +#define MS_SEL_AX1 0x0018 + MotionSensor_Sel +#define MS_SEL_AY0 0x001C + MotionSensor_Sel +#define MS_SEL_AY1 0x0020 + MotionSensor_Sel +#define MS_SEL_AZ 0x0024 + MotionSensor_Sel + +#define AngleCorrect 0x86E8 +#define X_main 0x0000 + AngleCorrect +#define X_sub 0x0004 + AngleCorrect +#define Y_main 0x0008 + AngleCorrect +#define Y_sub 0x000C + AngleCorrect +#define SX_main 0x0010 + AngleCorrect +#define SX_sub 0x0014 + AngleCorrect +#define SY_main 0x0018 + AngleCorrect +#define SY_sub 0x001C + AngleCorrect + + + +#define FRA_DMB_C0 0x8CF0 +#define FRA_DMB_S0 0x8CF4 +#define FRA_DMB_CN 0x8CF8 +#define FRA_DMB_SN 0x8CFC + +//============================================================================== +//IO +//============================================================================== +// System Control”z’uƒAƒhƒŒƒX +#define SYSDSP_DSPDIV 0xD00014 +#define SYSDSP_SOFTRES 0xD0006C +#define SYSDSP_REMAP 0xD000AC +#define SYSDSP_CVER 0xD00100 +// A/D D/A interface +#define ADDA_FSCTRL 0xD01008 +#define ADDA_ADDAINT 0xD0100C +#define ADDA_DASEL 0xD01050 +#define ADDA_DAO 0xD01054 + +#define ROMINFO 0xE050D4 + +/************************************************************************/ +/* Flash access */ +/************************************************************************/ +#define FLASHROM_128 0xE07000 // Flash Memory I/F”z’uƒAƒhƒŒƒX +#define FLASHROM_FLA_RDAT (FLASHROM_128 + 0x00) +#define FLASHROM_FLA_WDAT (FLASHROM_128 + 0x04) +#define FLASHROM_ACSCNT (FLASHROM_128 + 0x08) +#define FLASHROM_FLA_ADR (FLASHROM_128 + 0x0C) + #define USER_MAT 0 + #define INF_MAT0 1 + #define INF_MAT1 2 + #define INF_MAT2 4 +#define FLASHROM_CMD (FLASHROM_128 + 0x10) +#define FLASHROM_FLAWP (FLASHROM_128 + 0x14) +#define FLASHROM_FLAINT (FLASHROM_128 + 0x18) +#define FLASHROM_FLAMODE (FLASHROM_128 + 0x1C) +#define FLASHROM_TPECPW (FLASHROM_128 + 0x20) +#define FLASHROM_TACC (FLASHROM_128 + 0x24) + +#define FLASHROM_ERR_FLA (FLASHROM_128 + 0x98) +#define FLASHROM_RSTB_FLA (FLASHROM_128 + 0x4CC) +#define FLASHROM_UNLK_CODE1 (FLASHROM_128 + 0x554) +#define FLASHROM_CLK_FLAON (FLASHROM_128 + 0x664) +#define FLASHROM_UNLK_CODE2 (FLASHROM_128 + 0xAA8) +#define FLASHROM_UNLK_CODE3 (FLASHROM_128 + 0xCCC) + + +#define AREA_ALL 0 // 1,2,4,8 ALL +#define AREA_HALL 1 // HALL,GYRO OFFSET,ACCL OFFSET +#define AREA_GYRO 2 // GYRO GAIN +#define AREA_CRS 4 // CROSS TALK +#define AREA_LIN 8 // LINEARITY + +#define CALIB_STATUS diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PhoneUpdate.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PhoneUpdate.c new file mode 100755 index 0000000000000000000000000000000000000000..63a370a6ff08725d9823b05bf3c029904e4ef40c --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PhoneUpdate.c @@ -0,0 +1,1687 @@ +/** + * LC898128 Flash update + * + * Copyright (C) 2017, ON Semiconductor, all right reserved. + * + **/ + + + +//************************** +// Include Header File +//************************** +#include "PhoneUpdate.h" + +//#include <stdlib.h> +//#include <math.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "FromCode_01_02_01_00.h" +#include "FromCode_01_02_02_01.h" + +/* Burst Length for updating to PMEM */ +#define BURST_LENGTH_UC ( 3*20 ) // 60 Total:63Byte Burst +//#define BURST_LENGTH_UC ( 6*20 ) // 120 Total:123Byte Burst +/* Burst Length for updating to Flash */ +#define BURST_LENGTH_FC ( 32 ) // 32 Total: 35Byte Burst +//#define BURST_LENGTH_FC ( 64 ) // 64 Total: 67Byte Burst + +//**************************************************** +// CUSTOMER NECESSARY CREATING FUNCTION LIST +//**************************************************** +/* for I2C communication */ +extern void RamWrite32A( UINT_16, UINT_32 ); +extern INT_32 RamRead32A( UINT_16, void * ); +/* for I2C Multi Translation : Burst Mode*/ +extern void CntWrt( void *, UINT_16) ; +extern void CntRd( UINT_32, void *, UINT_16 ) ; + +/* for Wait timer [Need to adjust for your system] */ +extern void WitTim( UINT_16 ); + +//************************** +// extern Function LIST +//************************** + +//************************** +// Table of download file +//************************** + +UINT_32 FW_info[][3] = +{ + /* on Module vendor, Actuator Size, on vesion number */ + {0x01, 0x01, VERNUM_01_02_01_00}, + {0x01, 0x02, VERNUM_01_02_02_01} +}; + + +const DOWNLOAD_TBL_EXT DTbl[] = { + {0x010100, 1, CcUpdataCode128_01_02_01_00, UpDataCodeSize_01_02_01_00, UpDataCodeCheckSum_01_02_01_00, CcFromCode128_01_02_01_00, sizeof(CcFromCode128_01_02_01_00), FromCheckSum_01_02_01_00, FromCheckSumSize_01_02_01_00 }, + {0x010201, 1, CcUpdataCode128_01_02_02_01, UpDataCodeSize_01_02_02_01, UpDataCodeCheckSum_01_02_02_01, CcFromCode128_01_02_02_01, sizeof(CcFromCode128_01_02_02_01), FromCheckSum_01_02_02_01, FromCheckSumSize_01_02_02_01 }, + {0xFFFFFF, 0, (void*)0, 0, 0, (void*)0, 0, 0, 0} +}; + + + +//************************** +// Local Function Prototype +//************************** +void SetGyroCoef( UINT_8 ); +void SetAccelCoef( UINT_8 ); + +//******************************************************************************** +// Function Name : IOWrite32A +//******************************************************************************** +void IORead32A( UINT_32 IOadrs, UINT_32 *IOdata ) +{ + RamWrite32A( CMD_IO_ADR_ACCESS, IOadrs ) ; + RamRead32A ( CMD_IO_DAT_ACCESS, IOdata ) ; +} + +//******************************************************************************** +// Function Name : IOWrite32A +//******************************************************************************** +void IOWrite32A( UINT_32 IOadrs, UINT_32 IOdata ) +{ + RamWrite32A( CMD_IO_ADR_ACCESS, IOadrs ) ; + RamWrite32A( CMD_IO_DAT_ACCESS, IOdata ) ; +} + +//******************************************************************************** +// Function Name : UnlockCodeSet +//******************************************************************************** +UINT_8 UnlockCodeSet( void ) +{ + UINT_32 UlReadVal, UlCnt=0; + + do { + IOWrite32A( 0xE07554, 0xAAAAAAAA ); + IOWrite32A( 0xE07AA8, 0x55555555 ); + IORead32A( 0xE07014, &UlReadVal ); + if( (UlReadVal & 0x00000080) != 0 ) return ( 0 ) ; + WitTim( 1 ); + } while( UlCnt++ < 10 ); + return ( 1 ); +} + +//******************************************************************************** +// Function Name : UnlockCodeClear +//******************************************************************************** +UINT_8 UnlockCodeClear(void) +{ + UINT_32 UlDataVal, UlCnt=0; + + do { + IOWrite32A( 0xE07014, 0x00000010 ); + IORead32A( 0xE07014, &UlDataVal ); + if( (UlDataVal & 0x00000080) == 0 ) return ( 0 ) ; + WitTim( 1 ); + } while( UlCnt++ < 10 ); + return ( 3 ); +} +//******************************************************************************** +// Function Name : WritePermission +//******************************************************************************** +void WritePermission( void ) +{ + IOWrite32A( 0xE074CC, 0x00000001 ); + IOWrite32A( 0xE07664, 0x00000010 ); +} + +//******************************************************************************** +// Function Name : AddtionalUnlockCodeSet +//******************************************************************************** +void AddtionalUnlockCodeSet( void ) +{ + IOWrite32A( 0xE07CCC, 0x0000ACD5 ); +} +//******************************************************************************** +// Function Name : CoreResetwithoutMC128 +//******************************************************************************** +UINT_8 CoreResetwithoutMC128( void ) +{ + UINT_32 UlReadVal ; + + IOWrite32A( 0xE07554, 0xAAAAAAAA); + IOWrite32A( 0xE07AA8, 0x55555555); + + IOWrite32A( 0xE074CC, 0x00000001); + IOWrite32A( 0xE07664, 0x00000010); + IOWrite32A( 0xE07CCC, 0x0000ACD5); + IOWrite32A( 0xE0700C, 0x00000000); + IOWrite32A( 0xE0701C, 0x00000000); + IOWrite32A( 0xE07010, 0x00000004); + + WitTim(100); + + IOWrite32A( 0xE0701C, 0x00000002); + IOWrite32A( 0xE07014, 0x00000010); + + IOWrite32A( 0xD00060, 0x00000001 ) ; + WitTim( 15 ) ; + + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + switch ( (UINT_8)UlReadVal ){ + case 0x08: + case 0x0D: + break; + + default: + return( 0xE0 | (UINT_8)UlReadVal ); + } + + return( 0 ); +} + +//******************************************************************************** +// Function Name : PmemUpdate128 +//******************************************************************************** +UINT_8 PmemUpdate128( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_8 data[BURST_LENGTH_UC +2 ]; + UINT_16 Remainder; + const UINT_8 *NcDataVal = ptr->UpdataCode; + UINT_8 ReadData[8]; + long long CheckSumCode = ptr->SizeUpdataCodeCksm; + UINT_8 *p = (UINT_8 *)&CheckSumCode; + UINT_32 i, j; + UINT_32 UlReadVal, UlCnt , UlNum ; +//-------------------------------------------------------------------------------- +// +//-------------------------------------------------------------------------------- + IOWrite32A( 0xE0701C, 0x00000000); + RamWrite32A( 0x3000, 0x00080000 ); + + + data[0] = 0x40; + data[1] = 0x00; + + + Remainder = ( (ptr->SizeUpdataCode*5) / BURST_LENGTH_UC ); + for(i=0 ; i< Remainder ; i++) + { + UlNum = 2; + for(j=0 ; j < BURST_LENGTH_UC; j++){ + data[UlNum] = *NcDataVal++; + if( ( j % 5) == 4) TRACE("\n"); + UlNum++; + } + + CntWrt( data, BURST_LENGTH_UC+2 ); + } + Remainder = ( (ptr->SizeUpdataCode*5) % BURST_LENGTH_UC); + if (Remainder != 0 ) + { + UlNum = 2; + for(j=0 ; j < Remainder; j++){ + data[UlNum++] = *NcDataVal++; + } + CntWrt( data, Remainder+2 ); + } + +//-------------------------------------------------------------------------------- +// +//-------------------------------------------------------------------------------- + + + data[0] = 0xF0; + data[1] = 0x0E; + data[2] = (unsigned char)((ptr->SizeUpdataCode >> 8) & 0x000000FF); + data[3] = (unsigned char)(ptr->SizeUpdataCode & 0x000000FF); + data[4] = 0x00; + data[5] = 0x00; + + CntWrt( data, 6 ) ; + + + UlCnt = 0; + do{ + WitTim( 1 ); + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C, 0x00000002); + return (0x21) ; + } + RamRead32A( 0x0088, &UlReadVal ); + }while ( UlReadVal != 0 ); + + CntRd( 0xF00E, ReadData , 8 ); + + IOWrite32A( 0xE0701C, 0x00000002); + for( i=0; i<8; i++) { + if(ReadData[7-i] != *p++ ) { + return (0x22) ; + } + } + + return( 0 ); +} + +//******************************************************************************** +// Function Name : EraseUserMat128 +//******************************************************************************** +UINT_8 EraseUserMat128(UINT_8 StartBlock, UINT_8 EndBlock ) +{ + UINT_32 i; + UINT_32 UlReadVal, UlCnt ; + + IOWrite32A( 0xE0701C, 0x00000000); + RamWrite32A( 0xF007, 0x00000000 ); + + + for( i=StartBlock ; i<EndBlock ; i++) { + RamWrite32A( 0xF00A, ( i << 10 ) ); + RamWrite32A( 0xF00C, 0x00000020 ); + + + WitTim( 5 ); + UlCnt = 0; + do{ + + WitTim( 1 ); + if( UlCnt++ > 10 ){ + IOWrite32A( 0xE0701C, 0x00000002); + return (0x31) ; + } + RamRead32A( 0xF00C, &UlReadVal ); + }while ( UlReadVal != 0 ); + } + IOWrite32A( 0xE0701C, 0x00000002); + return(0); + +} + +//******************************************************************************** +// Function Name : ProgramFlash128_Standard +//******************************************************************************** +UINT_8 ProgramFlash128_Standard( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_32 UlReadVal, UlCnt , UlNum ; + UINT_8 data[(BURST_LENGTH_FC + 3)]; + UINT_32 i, j; + + const UINT_8 *NcFromVal = ptr->FromCode + 64; + const UINT_8 *NcFromVal1st = ptr->FromCode; + UINT_8 UcOddEvn; + + IOWrite32A( 0xE0701C, 0x00000000); + RamWrite32A( 0xF007, 0x00000000 ); + RamWrite32A( 0xF00A, 0x00000010 ); + data[0] = 0xF0; + data[1] = 0x08; + data[2] = 0x00; + + for(i=1 ; i< ( ptr->SizeFromCode / 64 ) ; i++) + { + if( ++UcOddEvn >1 ) UcOddEvn = 0; + if (UcOddEvn == 0) data[1] = 0x08; + else data[1] = 0x09; + +#if (BURST_LENGTH_FC == 32) + data[2] = 0x00; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); + data[2] = 0x20; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); +#elif (BURST_LENGTH_FC == 64) + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); +#endif + + RamWrite32A( 0xF00B, 0x00000010 ); + UlCnt = 0; + if (UcOddEvn == 0){ + do{ + RamRead32A( 0xF00C, &UlReadVal ); + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C, 0x00000002); + return (0x41) ; + } + }while ( UlReadVal != 0 ); + RamWrite32A( 0xF00C, 0x00000004 ); + }else{ + do{ + RamRead32A( 0xF00C, &UlReadVal ); + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C, 0x00000002); + return (0x41) ; + } + }while ( UlReadVal != 0 ); + RamWrite32A( 0xF00C, 0x00000008 ); + } + } + UlCnt = 0; + do{ + WitTim( 1 ); + RamRead32A( 0xF00C, &UlReadVal ); + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C, 0x00000002); + return (0x41) ; + } + }while ( (UlReadVal & 0x0000000C) != 0 ); + + { + RamWrite32A( 0xF00A, 0x00000000 ); + data[1] = 0x08; + +#if (BURST_LENGTH_FC == 32) + data[2] = 0x00; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); + data[2] = 0x20; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); +#elif (BURST_LENGTH_FC == 64) + data[2] = 0x00; + UlNum = 3; + for(j=0 ; j < BURST_LENGTH_FC; j++){ + data[UlNum++] = *NcFromVal1st++; + } + CntWrt( data, BURST_LENGTH_FC+3 ); +#endif + + RamWrite32A( 0xF00B, 0x00000010 ); + UlCnt = 0; + do{ + RamRead32A( 0xF00C, &UlReadVal ); + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; + } + }while ( UlReadVal != 0 ); + RamWrite32A( 0xF00C, 0x00000004 ); + } + + UlCnt = 0; + do{ + WitTim( 1 ); + RamRead32A( 0xF00C, &UlReadVal ); + if( UlCnt++ > 250 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x41) ; + } + }while ( (UlReadVal & 0x0000000C) != 0 ); + + IOWrite32A( 0xE0701C, 0x00000002); + return( 0 ); +} + + +//******************************************************************************** +// Function Name : FlashMultiRead +//******************************************************************************** +UINT_8 FlashMultiRead( UINT_8 SelMat, UINT_32 UlAddress, UINT_32 *PulData , UINT_8 UcLength ) +{ + UINT_8 i ; + + + + if( SelMat != USER_MAT && SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; + + if( UlAddress > 0x000003FF ) return 9; + + IOWrite32A( 0xE07008 , 0x00000000 | (UINT_32)(UcLength-1) ); + IOWrite32A( 0xE0700C , ((UINT_32)SelMat << 16) | ( UlAddress & 0x00003FFF ) ); + + IOWrite32A( 0xE0701C , 0x00000000); + IOWrite32A( 0xE07010 , 0x00000001 ); + for( i=0 ; i < UcLength ; i++ ){ + IORead32A( 0xE07000 , &PulData[i] ) ; + } + + IOWrite32A( 0xE0701C , 0x00000002); + return( 0 ) ; +} + +//******************************************************************************** +// Function Name : FlashBlockErase +//******************************************************************************** +UINT_8 FlashBlockErase( UINT_8 SelMat , UINT_32 SetAddress ) +{ + UINT_32 UlReadVal, UlCnt; + UINT_8 ans = 0 ; + + + + if( SelMat != USER_MAT && SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; + + if( SetAddress > 0x000003FF ) return 9; + + + ans = UnlockCodeSet(); + if( ans != 0 ) return( ans ) ; + + WritePermission(); + if( SelMat != USER_MAT ){ + if( SelMat == INF_MAT2 ) IOWrite32A( 0xE07CCC, 0x00006A4B ); + else IOWrite32A( 0xE07CCC, 0x0000C5AD ); + } + AddtionalUnlockCodeSet(); + + IOWrite32A( 0xE0700C , ((UINT_32)SelMat << 16) | ( SetAddress & 0x00003C00 )) ; + + IOWrite32A( 0xE0701C , 0x00000000); + IOWrite32A( 0xE07010 , 4 ) ; + + WitTim( 5 ) ; + + UlCnt = 0 ; + + do { + if( UlCnt++ > 100 ){ ans = 2; break; } ; + + IORead32A( FLASHROM_FLAINT, &UlReadVal ) ; + } while( ( UlReadVal & 0x00000080 ) != 0 ) ; + + IOWrite32A( 0xE0701C , 0x00000002); + ans = UnlockCodeClear(); + if( ans != 0 ) return( ans ) ; + + return( ans ) ; +} +//******************************************************************************** +// Function Name : FlashBlockWrite +//******************************************************************************** +UINT_8 FlashBlockWrite( UINT_8 SelMat , UINT_32 SetAddress , UINT_32 *PulData) +{ + UINT_32 UlReadVal, UlCnt; + UINT_8 ans = 0 ; + UINT_8 i ; + + if( SelMat != INF_MAT0 && SelMat != INF_MAT1 && SelMat != INF_MAT2 ) return 10; + // + if( SetAddress > 0x000003FF ) return 9; + + ans = UnlockCodeSet(); + if( ans != 0 ) return( ans ) ; + + WritePermission(); + if( SelMat != USER_MAT ){ + if( SelMat == INF_MAT2 ) IOWrite32A( 0xE07CCC, 0x00006A4B ); + else IOWrite32A( 0xE07CCC, 0x0000C5AD ); + } + AddtionalUnlockCodeSet(); + + IOWrite32A( 0xE0700C , ((UINT_32)SelMat << 16) | ( SetAddress & 0x000010 )) ; + + IOWrite32A( 0xE0701C , 0x00000000); + IOWrite32A( 0xE07010 , 2 ) ; + + + UlCnt = 0 ; + + for( i=0 ; i< 16 ; i++ ){ + IOWrite32A( 0xE07004 , PulData[i] ); + } + do { + if( UlCnt++ > 100 ){ ans = 2; break; } ; + + IORead32A( 0xE07018 , &UlReadVal ) ; + } while( ( UlReadVal & 0x00000080 ) != 0 ) ; + + IOWrite32A( 0xE07010 , 8 ); + + do { + if( UlCnt++ > 100 ){ ans = 2; break; } ; + + IORead32A( 0xE07018 , &UlReadVal ) ; + } while( ( UlReadVal & 0x00000080 ) != 0 ) ; + + IOWrite32A( 0xE0701C , 0x00000002); + ans = UnlockCodeClear(); + return( ans ) ; + +} + +//******************************************************************************** +// Function Name : Mat2ReWrite +//******************************************************************************** +UINT_8 Mat2ReWrite( void ) +{ + UINT_32 UlMAT2[32]; + UINT_32 UlCKSUM=0; + UINT_8 ans , i ; + UINT_32 UlCkVal ,UlCkVal_Bk; + + ans = FlashMultiRead( INF_MAT2, 0, UlMAT2, 32 ); + if(ans) return( 0xA0 ); + + if( UlMAT2[FT_REPRG] == PRDCT_WR || UlMAT2[FT_REPRG] == USER_WR ){ + return( 0x00 ); + } + + if( UlMAT2[CHECKCODE1] != CHECK_CODE1 ) return( 0xA1 ); + if( UlMAT2[CHECKCODE2] != CHECK_CODE2 ) return( 0xA2 ); + + for( i=16 ; i<MAT2_CKSM ; i++){ + UlCKSUM += UlMAT2[i]; + } + if(UlCKSUM != UlMAT2[MAT2_CKSM]) return( 0xA3 ); + + UlMAT2[FT_REPRG] = USER_WR; + + UlCkVal_Bk = 0; + for( i=0; i < 32; i++ ){ + UlCkVal_Bk += UlMAT2[i]; + } + + ans = FlashBlockErase( INF_MAT2 , 0 ); + if( ans != 0 ) return( 0xA4 ) ; + + ans = FlashBlockWrite( INF_MAT2 , 0 , UlMAT2 ); + if( ans != 0 ) return( 0xA5 ) ; + ans = FlashBlockWrite( INF_MAT2 , (UINT_32)0x10 , &UlMAT2[0x10] ); + if( ans != 0 ) return( 0xA5 ) ; + + ans =FlashMultiRead( INF_MAT2, 0, UlMAT2, 32 ); + if( ans ) return( 0xA0 ); + + UlCkVal = 0; + for( i=0; i < 32; i++ ){ + UlCkVal += UlMAT2[i]; + } + + if( UlCkVal != UlCkVal_Bk ) return( 0xA6 ); + + return( 0x01 ); +} + +//******************************************************************************** +// Function Name : FlashUpdate128 +//******************************************************************************** +UINT_8 FlashUpdate128( DOWNLOAD_TBL_EXT* ptr ) +{ + UINT_8 ans=0; + UINT_32 UlReadVal, UlCnt ; + + ans = CoreResetwithoutMC128(); + if(ans != 0) return( ans ); + + ans = Mat2ReWrite(); + if(ans != 0 && ans != 1) return( ans ); + + ans = PmemUpdate128( ptr ); + if(ans != 0) return( ans ); + +//-------------------------------------------------------------------------------- +// +//-------------------------------------------------------------------------------- + if( UnlockCodeSet() != 0 ) return (0x33) ; + WritePermission(); + AddtionalUnlockCodeSet(); + + #if 0 + ans = EraseUserMat128(0, 10); // Full Block. +#else + ans = EraseUserMat128(0, 7); // 0-6 Block for use user area. +#endif + if(ans != 0){ + if( UnlockCodeClear() != 0 ) return (0x32) ; + else return( ans ); + } + + ans = ProgramFlash128_Standard( ptr ); + if(ans != 0){ + if( UnlockCodeClear() != 0 ) return (0x43) ; + else return( ans ); + } + + if( UnlockCodeClear() != 0 ) return (0x43) ; + +//-------------------------------------------------------------------------------- +// +//-------------------------------------------------------------------------------- + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0xF00A, 0x00000000 ); + RamWrite32A( 0xF00D, ptr->SizeFromCodeValid ); + + RamWrite32A( 0xF00C, 0x00000100 ); + WitTim( 6 ); + UlCnt = 0; + do{ + RamRead32A( 0xF00C, &UlReadVal ); + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x51) ; + } + WitTim( 1 ); + }while ( UlReadVal != 0 ); + + RamRead32A( 0xF00D, &UlReadVal ); + + if( UlReadVal != ptr->SizeFromCodeCksm ) { + IOWrite32A( 0xE0701C , 0x00000002); + return( 0x52 ); + } + + IOWrite32A( SYSDSP_REMAP, 0x00001000 ) ; + WitTim( 15 ) ; + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + if( UlReadVal != 0x0A) return( 0x53 ); + + return( 0 ); +} + +//******************************************************************************** +// Function Name : FlashDownload_128 +//******************************************************************************** +UINT_8 FlashDownload128( UINT_8 ModuleVendor, UINT_8 ActVer, UINT_8 MasterSlave, UINT_8 FWType) +{ + DOWNLOAD_TBL_EXT* ptr = NULL; + UINT_32 data1 = 0; + UINT_32 data2 = 0; + + ptr = ( DOWNLOAD_TBL_EXT * )DTbl ; + + do { + if((ptr->Index == ( ((UINT_32)ModuleVendor<<16) + ((UINT_32)ActVer<<8) + MasterSlave)) && (ptr->FWType == FWType)) { + + // UploadFile‚ª64Byte‚Ý‚ÉPadding‚³‚ê‚Ä‚¢‚È‚¢‚È‚ç‚ÎAErrorB + if( ( ptr->SizeFromCode % 64 ) != 0 ) return (0xF1) ; + + if(!RamRead32A(0x8000, &data1)) { + if(!RamRead32A(0x8004, &data2)) { + if ((data1 == (ptr->FromCode[153] << 24 | + ptr->FromCode[154] << 16 | + ptr->FromCode[155] << 8 | + ptr->FromCode[156])) && + ((data2 & 0xFFFFFF00 ) == (ptr->FromCode[158] << 24 | + ptr->FromCode[159] << 16 | + ptr->FromCode[160] << 8 ))) { + TRACE("The FW 0x%x:0x%x is the latest, no need to upload\n", data1, data2); + return 0; + } else { + TRACE("0x8000 = 0x%x 0x8004 = 0x%x is not the latest 0x%x:0x%x, will upload\n", data1, data2, + (ptr->FromCode[153] << 24 | + ptr->FromCode[154] << 16 | + ptr->FromCode[155] << 8 | + ptr->FromCode[156]), + (ptr->FromCode[158] << 24 | + ptr->FromCode[159] << 16 | + ptr->FromCode[160] << 8 | + ptr->FromCode[161])); + } + } else { + TRACE("Read 0x8004 failed\n"); + return 0xF2; + } + } else { + TRACE("Read 0x8000 failed\n"); + return 0xF2; + } + + return FlashUpdate128( ptr ); + } + ptr++ ; + } while (ptr->Index != 0xFFFFFF ) ; + + return 0xF0 ; +} + + +void SetGyroOffset( UINT_16 GyroOffsetX, UINT_16 GyroOffsetY, UINT_16 GyroOffsetZ ) +{ + RamWrite32A( GYRO_RAM_GXOFFZ , (( GyroOffsetX << 16 ) & 0xFFFF0000 ) ) ; + RamWrite32A( GYRO_RAM_GYOFFZ , (( GyroOffsetY << 16 ) & 0xFFFF0000 ) ) ; + RamWrite32A( GYRO_ZRAM_GZOFFZ , (( GyroOffsetZ << 16 ) & 0xFFFF0000 ) ) ; +} + +void SetAcclOffset( UINT_16 AcclOffsetX, UINT_16 AcclOffsetY, UINT_16 AcclOffsetZ ) +{ + RamWrite32A( ACCLRAM_X_AC_OFFSET , ( ( AcclOffsetX << 16 ) & 0xFFFF0000 ) ) ; + RamWrite32A( ACCLRAM_Y_AC_OFFSET , ( ( AcclOffsetY << 16 ) & 0xFFFF0000 ) ) ; + RamWrite32A( ACCLRAM_Z_AC_OFFSET , ( ( AcclOffsetZ << 16 ) & 0xFFFF0000 ) ) ; +} + +void GetGyroOffset( UINT_16* GyroOffsetX, UINT_16* GyroOffsetY, UINT_16* GyroOffsetZ ) +{ + UINT_32 ReadValX, ReadValY, ReadValZ; + RamRead32A( GYRO_RAM_GXOFFZ , &ReadValX ); + RamRead32A( GYRO_RAM_GYOFFZ , &ReadValY ); + RamRead32A( GYRO_ZRAM_GZOFFZ , &ReadValZ ); + *GyroOffsetX = ( UINT_16 )(( ReadValX >> 16) & 0x0000FFFF ); + *GyroOffsetY = ( UINT_16 )(( ReadValY >> 16) & 0x0000FFFF ); + *GyroOffsetZ = ( UINT_16 )(( ReadValZ >> 16) & 0x0000FFFF ); +} + +void GetAcclOffset( UINT_16* AcclOffsetX, UINT_16* AcclOffsetY, UINT_16* AcclOffsetZ ) +{ + UINT_32 ReadValX, ReadValY, ReadValZ; + RamRead32A( ACCLRAM_X_AC_OFFSET , &ReadValX ); + RamRead32A( ACCLRAM_Y_AC_OFFSET , &ReadValY ); + RamRead32A( ACCLRAM_Z_AC_OFFSET , &ReadValZ ); + *AcclOffsetX = ( UINT_16 )(( ReadValX >> 16) & 0x0000FFFF ); + *AcclOffsetY = ( UINT_16 )(( ReadValY >> 16) & 0x0000FFFF ); + *AcclOffsetZ = ( UINT_16 )(( ReadValZ >> 16) & 0x0000FFFF ); +} + +void MeasFil( void ) +{ + UINT_32 UlMeasFilaA , UlMeasFilaB , UlMeasFilaC ; + UINT_32 UlMeasFilbA , UlMeasFilbB , UlMeasFilbC ; + + UlMeasFilaA = 0x7FFFFFFF ; + UlMeasFilaB = 0x00000000 ; + UlMeasFilaC = 0x00000000 ; + UlMeasFilbA = 0x7FFFFFFF ; + UlMeasFilbB = 0x00000000 ; + UlMeasFilbC = 0x00000000 ; + + + RamWrite32A ( 0x8388 , UlMeasFilaA ) ; + RamWrite32A ( 0x8380 , UlMeasFilaB ) ; + RamWrite32A ( 0x8384 , UlMeasFilaC ) ; + + RamWrite32A ( 0x8394 , UlMeasFilbA ) ; + RamWrite32A ( 0x838C , UlMeasFilbB ) ; + RamWrite32A ( 0x8390 , UlMeasFilbC ) ; + + RamWrite32A ( 0x83A0 , UlMeasFilaA ) ; + RamWrite32A ( 0x8398 , UlMeasFilaB ) ; + RamWrite32A ( 0x839C , UlMeasFilaC ) ; + + RamWrite32A ( 0x83AC , UlMeasFilbA ) ; + RamWrite32A ( 0x83A4 , UlMeasFilbB ) ; + RamWrite32A ( 0x83A8 , UlMeasFilbC ) ; +} +void MemoryClear( UINT_16 UsSourceAddress, UINT_16 UsClearSize ) +{ + UINT_16 UsLoopIndex ; + + for ( UsLoopIndex = 0 ; UsLoopIndex < UsClearSize ; ) { + RamWrite32A( UsSourceAddress , 0x00000000 ) ; + UsSourceAddress += 4; + UsLoopIndex += 4 ; + } +} +void SetTransDataAdr( UINT_16 UsLowAddress , UINT_32 UlLowAdrBeforeTrans ) +{ + UnDwdVal StTrsVal ; + + if( UlLowAdrBeforeTrans < 0x00009000 ){ + StTrsVal.StDwdVal.UsHigVal = (UINT_16)(( UlLowAdrBeforeTrans & 0x0000F000 ) >> 8 ) ; + StTrsVal.StDwdVal.UsLowVal = (UINT_16)( UlLowAdrBeforeTrans & 0x00000FFF ) ; + }else{ + StTrsVal.UlDwdVal = UlLowAdrBeforeTrans ; + } + RamWrite32A( UsLowAddress , StTrsVal.UlDwdVal ); + +} +#define ONE_MSEC_COUNT 15 +void SetWaitTime( UINT_16 UsWaitTime ) +{ + RamWrite32A( 0x0324 , 0 ) ; + RamWrite32A( 0x0328 , (UINT_32)(ONE_MSEC_COUNT * UsWaitTime)) ; +} +void ClrMesFil( void ) +{ + RamWrite32A ( 0x02D0 , 0 ) ; + RamWrite32A ( 0x02D4 , 0 ) ; + + RamWrite32A ( 0x02D8 , 0 ) ; + RamWrite32A ( 0x02DC , 0 ) ; + + RamWrite32A ( 0x02E0 , 0 ) ; + RamWrite32A ( 0x02E4 , 0 ) ; + + RamWrite32A ( 0x02E8 , 0 ) ; + RamWrite32A ( 0x02EC , 0 ) ; +} + +void MeasAddressSelection( UINT_8 mode , INT_32 * measadr_a , INT_32 * measadr_b ) +{ + if( mode == 0 ){ + *measadr_a = GYRO_RAM_GX_ADIDAT ; + *measadr_b = GYRO_RAM_GY_ADIDAT ; + }else if( mode == 1 ){ + *measadr_a = GYRO_ZRAM_GZ_ADIDAT ; + *measadr_b = ACCLRAM_Z_AC_ADIDAT ; + }else{ + *measadr_a = ACCLRAM_X_AC_ADIDAT ; + *measadr_b = ACCLRAM_Y_AC_ADIDAT ; + } +} +void MeasureStart( INT_32 SlMeasureParameterNum , INT_32 SlMeasureParameterA , INT_32 SlMeasureParameterB ) +{ + MemoryClear( 0x0278 , sizeof( MeasureFunction_Type ) ) ; + RamWrite32A( 0x0280 , 0x80000000 ) ; + RamWrite32A( 0x02A8 , 0x80000000 ) ; + RamWrite32A( 0x0284 , 0x7FFFFFFF ) ; + RamWrite32A( 0x02AC , 0x7FFFFFFF ) ; + + SetTransDataAdr( 0x02A0 , ( UINT_32 )SlMeasureParameterA ) ; + SetTransDataAdr( 0x02C8 , ( UINT_32 )SlMeasureParameterB ) ; + RamWrite32A( 0x0278 , 0 ) ; + ClrMesFil() ; + SetWaitTime(1) ; + RamWrite32A( 0x027C , SlMeasureParameterNum ) ; +} +void MeasureWait( void ) +{ + UINT_32 SlWaitTimerSt ; + UINT_16 UsTimeOut = 2000; + + do { + RamRead32A( 0x027C, &SlWaitTimerSt ) ; + UsTimeOut--; + } while ( SlWaitTimerSt && UsTimeOut ); + +} +void SetSinWavGenInt( void ) +{ + + RamWrite32A( 0x02FC , 0x00000000 ) ; + RamWrite32A( 0x0300 , 0x60000000 ) ; + RamWrite32A( 0x0304 , 0x00000000 ) ; + + RamWrite32A( 0x0310 , 0x00000000 ); + RamWrite32A( 0x0314 , 0x00000000 ); + RamWrite32A( 0x0318 , 0x00000000 ); + + RamWrite32A( 0x02F4 , 0x00000000 ) ; // Sine Wave Stop + +} + +#define MESOF_NUM 2048 +#define GYROFFSET_H ( 0x06D6 << 16 ) +#define GSENS ( 4096 << 16 ) +#define GSENS_MARG (GSENS / 4) +#define POSTURETH (GSENS - GSENS_MARG) +#define ZG_MRGN (1310 << 16) +#define XYG_MRGN (1024 << 16) +UINT_32 MeasGyAcOffset( void ) +{ + UINT_32 UlRsltSts; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + INT_32 SlMeasureParameterNum ; + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureAveValueA[3] , SlMeasureAveValueB[3] ; + UINT_8 i ; + + + + MeasFil( ) ; + + SlMeasureParameterNum = MESOF_NUM ; + + for( i=0 ; i<3 ; i++ ) + { + MeasAddressSelection( i, &SlMeasureParameterA , &SlMeasureParameterB ); + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; + + MeasureWait() ; + + RamRead32A( 0x0290 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( 0x0290 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( 0x02B8 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( 0x02B8 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA[i] = (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB[i] = (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; + + } + + UlRsltSts = EXE_END ; + + + if( abs(SlMeasureAveValueA[0]) > GYROFFSET_H ) UlRsltSts |= EXE_GXADJ ; + if( abs(SlMeasureAveValueB[0]) > GYROFFSET_H ) UlRsltSts |= EXE_GYADJ ; + if( abs(SlMeasureAveValueA[1]) > GYROFFSET_H ) UlRsltSts |= EXE_GZADJ ; + if( (SlMeasureAveValueB[1]) < POSTURETH ) UlRsltSts |= EXE_AZADJ ; + if( abs(SlMeasureAveValueA[2]) > XYG_MRGN ) UlRsltSts |= EXE_AXADJ ; + if( abs(SlMeasureAveValueB[2]) > XYG_MRGN ) UlRsltSts |= EXE_AYADJ ; + if( abs( GSENS - SlMeasureAveValueB[1]) > ZG_MRGN ) UlRsltSts |= EXE_AZADJ ; + + + if( UlRsltSts == EXE_END ){ + RamWrite32A( GYRO_RAM_GXOFFZ , SlMeasureAveValueA[0] ) ; + RamWrite32A( GYRO_RAM_GYOFFZ , SlMeasureAveValueB[0] ) ; + RamWrite32A( GYRO_ZRAM_GZOFFZ , SlMeasureAveValueA[1] ) ; + RamWrite32A( ACCLRAM_X_AC_OFFSET , SlMeasureAveValueA[2] ) ; + RamWrite32A( ACCLRAM_Y_AC_OFFSET , SlMeasureAveValueB[2] ) ; + RamWrite32A( ACCLRAM_Z_AC_OFFSET , SlMeasureAveValueB[1] - (INT_32)GSENS ) ; + + RamWrite32A( 0x01D8 , 0x00000000 ) ; + RamWrite32A( 0x01FC , 0x00000000 ) ; + RamWrite32A( 0x0378 , 0x00000000 ) ; + RamWrite32A( 0x019C , 0x00000000 ) ; + RamWrite32A( 0x01C4 , 0x00000000 ) ; + RamWrite32A( 0x03C0 + 8 , 0x00000000 ) ; + RamWrite32A( 0x03F0 + 8 , 0x00000000 ) ; + RamWrite32A( 0x0420 + 8 , 0x00000000 ) ; + RamWrite32A( 0x03C0 + 12 , 0x00000000 ) ; + RamWrite32A( 0x03F0 + 12 , 0x00000000 ) ; + RamWrite32A( 0x0420 + 12 , 0x00000000 ) ; + RamWrite32A( 0x03C0 + 16 , 0x00000000 ) ; + RamWrite32A( 0x03F0 + 16 , 0x00000000 ) ; + RamWrite32A( 0x0420 + 16 , 0x00000000 ) ; + RamWrite32A( 0x03C0 + 20 , 0x00000000 ) ; + RamWrite32A( 0x03F0 + 20 , 0x00000000 ) ; + RamWrite32A( 0x0420 + 20 , 0x00000000 ) ; + } + return( UlRsltSts ); + + +} + +const UINT_8 PACT0Tbl[] = { 0xFF, 0xFF }; /* Dummy table */ +const UINT_8 PACT1Tbl[] = { 0x20, 0xDF }; /* [ACT_02][ACT_01][ACT_03][ACT_05] */ + + +UINT_8 SetAngleCorrection( float DegreeGap, UINT_8 SelectAct, UINT_8 Arrangement ) +{ + double OffsetAngle = 0.0f; + double OffsetAngleV_slt = 0.0f; +// double OffsetAngleS_slt = 0.0f; + INT_32 Slgx45x = 0, Slgx45y = 0; + INT_32 Slgy45y = 0, Slgy45x = 0; + INT_32 Slagx45x = 0, Slagx45y = 0; + INT_32 Slagy45y = 0, Slagy45x = 0; + + UINT_8 UcCnvF = 0; + + if( ( DegreeGap > 180.0f) || ( DegreeGap < -180.0f ) ) return ( 1 ); + if( Arrangement >= 2 ) return ( 1 ); + +/************************************************************************/ +/* Gyro angle correction */ +/************************************************************************/ + switch(SelectAct) { +// case 0x00 : +// OffsetAngle = (double)( 45.0f + DegreeGap ) * 3.141592653589793238 / 180.0f ; +// UcCnvF = PACT1Tbl[ Arrangement ]; +// break; +// case 0x01 : +// OffsetAngle = (double)( DegreeGap ) * 3.141592653589793238 / 180.0f ; +// UcCnvF = PACT1Tbl[ Arrangement ]; +// break; +// case 0x02 : +// case 0x03 : +// case 0x05 : +// case 0x06 : +// case 0x07 : +// case 0x08 : +// case 0x09 : + default : + OffsetAngle = (double)( DegreeGap ) * 3.141592653589793238 / 180.0f ; + UcCnvF = PACT1Tbl[ Arrangement ]; + break; +// default : +// break; + } + + SetGyroCoef( UcCnvF ); + SetAccelCoef( UcCnvF ); + + //***********************************************// + // Gyro & Accel rotation correction + //***********************************************// +// Slgx45x = (INT_32)( cos( OffsetAngle )*2147483647.0); +// Slgx45y = (INT_32)(-sin( OffsetAngle )*2147483647.0); +// Slgy45y = (INT_32)( cos( OffsetAngle )*2147483647.0); +// Slgy45x = (INT_32)( sin( OffsetAngle )*2147483647.0); + + RamWrite32A( 0x8270 , (UINT_32)Slgx45x ); + RamWrite32A( 0x8274 , (UINT_32)Slgx45y ); + RamWrite32A( 0x82D0 , (UINT_32)Slgy45y ); + RamWrite32A( 0x82D4 , (UINT_32)Slgy45x ); + RamWrite32A( 0x8640 , (UINT_32)Slgx45x ); + RamWrite32A( 0x8644 , (UINT_32)Slgx45y ); + RamWrite32A( 0x8648 , (UINT_32)Slgy45y ); + RamWrite32A( 0x864C , (UINT_32)Slgy45x ); + + if(SelectAct == 0x00) { + OffsetAngleV_slt = (double)( 45.0f ) * 3.141592653589793238 / 180.0f ; + }else{ + OffsetAngleV_slt = (double)( 0.0f ) * 3.141592653589793238 / 180.0f ; + } +// Slagx45x = (INT_32)( cos( OffsetAngleV_slt )*2147483647.0); +// Slagx45y = (INT_32)(-sin( OffsetAngleV_slt )*2147483647.0); +// Slagy45y = (INT_32)( cos( OffsetAngleV_slt )*2147483647.0); +// Slagy45x = (INT_32)( sin( OffsetAngleV_slt )*2147483647.0); + RamWrite32A( 0x86E8 , (UINT_32)Slagx45x ); + RamWrite32A( 0x86EC , (UINT_32)Slagx45y ); + RamWrite32A( 0x86F0 , (UINT_32)Slagy45y ); + RamWrite32A( 0x86F4 , (UINT_32)Slagy45x ); + +// OffsetAngleS_slt = (double)( -90.0f ) * 3.141592653589793238 / 180.0f ; +// Slagx45x = (INT_32)( cos( OffsetAngleS_slt )*2147483647.0); +// Slagx45y = (INT_32)(-sin( OffsetAngleS_slt )*2147483647.0); +// Slagy45y = (INT_32)( cos( OffsetAngleS_slt )*2147483647.0); +// Slagy45x = (INT_32)( sin( OffsetAngleS_slt )*2147483647.0); +// RamWrite32A( 0x86F8 , (UINT_32)Slagx45x ); +// RamWrite32A( 0x86FC , (UINT_32)Slagx45y ); +// RamWrite32A( 0x8700 , (UINT_32)Slagy45y ); +// RamWrite32A( 0x8704 , (UINT_32)Slagy45x ); + + + return ( 0 ); +} + +void SetGyroCoef( UINT_8 UcCnvF ) +{ + INT_32 Slgxx = 0, Slgxy = 0; + INT_32 Slgyy = 0, Slgyx = 0; + INT_32 Slgzp = 0; + /************************************************/ + /* signal convet */ + /************************************************/ + switch( UcCnvF & 0xE0 ){ + /* HX <== GX , HY <== GY */ + case 0x00: + Slgxx = 0x7FFFFFFF ; Slgxy = 0x00000000 ; Slgyy = 0x7FFFFFFF ; Slgyx = 0x00000000 ; break; //HX<==GX(NEG), HY<==GY(NEG) + case 0x20: + Slgxx = 0x7FFFFFFF ; Slgxy = 0x00000000 ; Slgyy = 0x80000001 ; Slgyx = 0x00000000 ; break; //HX<==GX(NEG), HY<==GY(POS) + case 0x40: + Slgxx = 0x80000001 ; Slgxy = 0x00000000 ; Slgyy = 0x7FFFFFFF ; Slgyx = 0x00000000 ; break; //HX<==GX(POS), HY<==GY(NEG) + case 0x60: + Slgxx = 0x80000001 ; Slgxy = 0x00000000 ; Slgyy = 0x80000001 ; Slgyx = 0x00000000 ; break; //HX<==GX(POS), HY<==GY(POS) + /* HX <== GY , HY <== GX */ + case 0x80: + Slgxx = 0x00000000 ; Slgxy = 0x7FFFFFFF ; Slgyy = 0x00000000 ; Slgyx = 0x7FFFFFFF ; break; //HX<==GY(NEG), HY<==GX(NEG) + case 0xA0: + Slgxx = 0x00000000 ; Slgxy = 0x7FFFFFFF ; Slgyy = 0x00000000 ; Slgyx = 0x80000001 ; break; //HX<==GY(NEG), HY<==GX(POS) + case 0xC0: + Slgxx = 0x00000000 ; Slgxy = 0x80000001 ; Slgyy = 0x00000000 ; Slgyx = 0x7FFFFFFF ; break; //HX<==GY(POS), HY<==GX(NEG) + case 0xE0: + Slgxx = 0x00000000 ; Slgxy = 0x80000001 ; Slgyy = 0x00000000 ; Slgyx = 0x80000001 ; break; //HX<==GY(NEG), HY<==GX(NEG) + } + switch( UcCnvF & 0x10 ){ + case 0x00: + Slgzp = 0x7FFFFFFF ; break; //GZ(POS) + case 0x10: + Slgzp = 0x80000001 ; break; //GZ(NEG) + } + RamWrite32A( 0x865C , (UINT_32)Slgxx ); + RamWrite32A( 0x8660 , (UINT_32)Slgxy ); + RamWrite32A( 0x8664 , (UINT_32)Slgyy ); + RamWrite32A( 0x8668 , (UINT_32)Slgyx ); + RamWrite32A( 0x866C , (UINT_32)Slgzp ); +} + +void SetAccelCoef( UINT_8 UcCnvF ) +{ + INT_32 Slaxx = 0, Slaxy = 0; + INT_32 Slayy = 0, Slayx = 0; + INT_32 Slazp = 0; + + switch( UcCnvF & 0x0E ){ + /* HX <== AX , HY <== AY */ + case 0x00: + Slaxx = 0x7FFFFFFF ; Slaxy = 0x00000000 ; Slayy = 0x7FFFFFFF ; Slayx = 0x00000000 ; break; //HX<==AX(NEG), HY<==AY(NEG) + case 0x02: + Slaxx = 0x7FFFFFFF ; Slaxy = 0x00000000 ; Slayy = 0x80000001 ; Slayx = 0x00000000 ; break; //HX<==AX(NEG), HY<==AY(POS) + case 0x04: + Slaxx = 0x80000001 ; Slaxy = 0x00000000 ; Slayy = 0x7FFFFFFF ; Slayx = 0x00000000 ; break; //HX<==AX(POS), HY<==AY(NEG) + case 0x06: + Slaxx = 0x80000001 ; Slaxy = 0x00000000 ; Slayy = 0x80000001 ; Slayx = 0x00000000 ; break; //HX<==AX(POS), HY<==AY(POS) + /* HX <== AY , HY <== AX */ + case 0x08: + Slaxx = 0x00000000 ; Slaxy = 0x7FFFFFFF ; Slayy = 0x00000000 ; Slayx = 0x7FFFFFFF ; break; //HX<==AY(NEG), HY<==AX(NEG) + case 0x0A: + Slaxx = 0x00000000 ; Slaxy = 0x7FFFFFFF ; Slayy = 0x00000000 ; Slayx = 0x80000001 ; break; //HX<==AY(NEG), HY<==AX(POS) + case 0x0C: + Slaxx = 0x00000000 ; Slaxy = 0x80000001 ; Slayy = 0x00000000 ; Slayx = 0x7FFFFFFF ; break; //HX<==AY(POS), HY<==AX(NEG) + case 0x0E: + Slaxx = 0x00000000 ; Slaxy = 0x80000001 ; Slayy = 0x00000000 ; Slayx = 0x80000001 ; break; //HX<==AY(NEG), HY<==AX(NEG) + } + switch( UcCnvF & 0x01 ){ + case 0x00: + Slazp = 0x7FFFFFFF ; break; //AZ(POS) + case 0x01: + Slazp = 0x80000001 ; break; //AZ(NEG) + } + RamWrite32A( 0x8670 , (UINT_32)Slaxx ); + RamWrite32A( 0x8674 , (UINT_32)Slaxy ); + RamWrite32A( 0x8678 , (UINT_32)Slayy ); + RamWrite32A( 0x867C , (UINT_32)Slayx ); + RamWrite32A( 0x8680 , (UINT_32)Slazp ); +} + +UINT_8 RdStatus( UINT_8 UcStBitChk ) +{ + UINT_32 UlReadVal ; + + RamRead32A( 0xF100 , &UlReadVal ); + if( UcStBitChk ){ + UlReadVal &= READ_STATUS_INI ; + } + if( !UlReadVal ){ + return( SUCCESS ); + }else{ + return( FAILURE ); + } +} +void OisEna( void ) // OIS ( SMA , VCM ) = ( OFF, ON ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF012 , 0x00000001 ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus(1); + } +} +void OisEna_S( void ) // OIS ( SMA , VCM ) = ( ON, OFF ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF012 , 0x00010000 ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus(1); + } +} +void OisEna_SV( void ) // OIS ( SMA , VCM ) = ( ON, ON ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF012 , 0x00010001 ) ; + while( UcStRd && (UlStCnt++ < CNT050MS )) { + UcStRd = RdStatus(1); + } +} + +void OisDis( void ) // OIS ( SMA , VCM ) = ( OFF, OFF ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF012 , 0x00000000 ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + +void OisDis_Slope( void ) // OIS ( SMA , VCM ) = ( OFF, OFF ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF012 , 0x00000008 ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + +void SetPanTiltMode( UINT_8 UcPnTmod ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + switch ( UcPnTmod ) { + case 0 : + RamWrite32A( 0xF011 , 0x00000000 ) ; + break ; + case 1 : + RamWrite32A( 0xF011 , 0x00000001 ) ; + break ; + } + + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + +void SscEna( void ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF01C , 0x00000001 ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + +void SscDis( void ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF01C , 0x00000000 ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + + + + #define ACT_CHK_FRQ 0x0008B8E5 + #define ACT_CHK_NUM 3756 + #define ACT_THR 0x000003E8 + #define ACT_MARGIN 0.75f + +UINT_8 TstActMov( UINT_8 UcDirSel ) +{ + UINT_8 UcRsltSts = 0; + INT_32 SlMeasureParameterNum ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + UnllnVal StMeasValueA , StMeasValueB ; + float SfLimit , Sfzoom , Sflenz , Sfshift ; + UINT_32 UlLimit , Ulzoom , Ullenz , Ulshift , UlActChkLvl ; + UINT_8 i; + UINT_32 UlReturnVal; + + if( UcDirSel == 0x00 ) { + RamRead32A( Gyro_Limiter_X , ( UINT_32 * )&UlLimit ) ; + RamRead32A( GyroFilterTableX_gxzoom , ( UINT_32 * )&Ulzoom ) ; + RamRead32A( GyroFilterTableX_gxlenz , ( UINT_32 * )&Ullenz ) ; + RamRead32A( GyroFilterShiftX , ( UINT_32 * )&Ulshift ) ; + }else{ + RamRead32A( Gyro_Limiter_Y , ( UINT_32 * )&UlLimit ) ; + RamRead32A( GyroFilterTableY_gyzoom , ( UINT_32 * )&Ulzoom ) ; + RamRead32A( GyroFilterTableY_gylenz , ( UINT_32 * )&Ullenz ) ; + RamRead32A( GyroFilterShiftY , ( UINT_32 * )&Ulshift ) ; + } + + + SfLimit = (float)UlLimit / (float)0x7FFFFFFF; + if( Ulzoom == 0){ + Sfzoom = 0; + }else{ + Sfzoom = (float)abs(Ulzoom) / (float)0x7FFFFFFF; + } + if( Ullenz == 0){ + Sflenz = 0; + }else{ + Sflenz = (float)Ullenz / (float)0x7FFFFFFF; + } + Ulshift = ( Ulshift & 0x0000FF00) >> 8 ; + Sfshift = 1; + for( i = 0 ; i < Ulshift ; i++ ){ + Sfshift *= 2; + } + UlActChkLvl = (UINT_32)( (float)0x7FFFFFFF * SfLimit * Sfzoom * Sflenz * Sfshift * ACT_MARGIN ); + + SlMeasureParameterNum = ACT_CHK_NUM ; + + if( UcDirSel == 0x00 ) { + SlMeasureParameterA = HALL_RAM_HXOFF1 ; + SlMeasureParameterB = HallFilterD_HXDAZ1 ; + } else if( UcDirSel == 0x01 ) { + SlMeasureParameterA = HALL_RAM_HYOFF1 ; + SlMeasureParameterB = HallFilterD_HYDAZ1 ; + } + SetSinWavGenInt(); + + RamWrite32A( 0x02FC , ACT_CHK_FRQ ) ; + RamWrite32A( 0x0304 , UlActChkLvl ) ; + RamWrite32A( 0x02F4 , 0x00000001 ) ; + if( UcDirSel == 0x00 ) { + SetTransDataAdr( 0x030C , (UINT_32)HALL_RAM_HXOFF1 ) ; + }else if( UcDirSel == 0x01 ){ + SetTransDataAdr( 0x030C , (UINT_32)HALL_RAM_HYOFF1 ) ; + } + RamWrite32A ( 0x8388 , 0x03E452C7 ) ; + RamWrite32A ( 0x8380 , 0x03E452C7 ) ; + RamWrite32A ( 0x8384 , 0x78375A71 ) ; + + RamWrite32A ( 0x8394 , 0x03E452C7 ) ; + RamWrite32A ( 0x838C , 0x03E452C7 ) ; + RamWrite32A ( 0x8390 , 0x78375A71 ) ; + + RamWrite32A ( 0x83A0 , 0x03E452C7 ) ; + RamWrite32A ( 0x8398 , 0x03E452C7 ) ; + RamWrite32A ( 0x839C , 0x78375A71 ) ; + + RamWrite32A ( 0x83AC , 0x03E452C7 ) ; + RamWrite32A ( 0x83A4 , 0x03E452C7 ) ; + RamWrite32A ( 0x83A8 , 0x78375A71 ) ; + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; + + MeasureWait() ; + + RamWrite32A( 0x02F4 , 0x00000000 ) ; + + if( UcDirSel == 0x00 ) { + SetTransDataAdr( 0x030C , (UINT_32)0x00000000 ) ; + RamWrite32A( HALL_RAM_HXOFF1 , 0x00000000 ) ; + }else if( UcDirSel == 0x01 ){ + SetTransDataAdr( 0x030C , (UINT_32)0x00000000 ) ; + RamWrite32A( HALL_RAM_HYOFF1 , 0x00000000 ) ; + } + RamRead32A( 0x0298 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( 0x0298 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( 0x02C0 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( 0x02C0 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + + UlReturnVal = (INT_32)((INT_64)StMeasValueA.UllnValue * 100 / (INT_64)StMeasValueB.UllnValue ) ; + + + + UcRsltSts = EXE_END ; + if( UlReturnVal < ACT_THR ){ + if ( !UcDirSel ) { + UcRsltSts = EXE_HXMVER ; + }else{ + UcRsltSts = EXE_HYMVER ; + } + } + + return( UcRsltSts ) ; + +} +UINT_8 RunHea( void ) +{ + UINT_8 UcRst ; + UcRst = EXE_END ; + UcRst |= TstActMov( 0x00 ) ; + UcRst |= TstActMov( 0x01 ) ; + + return( UcRst ) ; +} + + + #define GEA_NUM 512 + #define GEA_DIF_HIG 0x0083 + #define GEA_DIF_LOW 0x0001 + +UINT_8 RunGea( void ) +{ + UnllnVal StMeasValueA , StMeasValueB ; + INT_32 SlMeasureParameterA , SlMeasureParameterB ; + UINT_8 UcRst, UcCnt, UcXLowCnt, UcYLowCnt, UcXHigCnt, UcYHigCnt ; + UINT_16 UsGxoVal[10], UsGyoVal[10], UsDif; + INT_32 SlMeasureParameterNum , SlMeasureAveValueA , SlMeasureAveValueB ; + + + UcRst = EXE_END ; + UcXLowCnt = UcYLowCnt = UcXHigCnt = UcYHigCnt = 0 ; + + RamWrite32A ( 0x8388 , 0x7FFFFFFF ) ; + RamWrite32A ( 0x8380 , 0x00000000 ) ; + RamWrite32A ( 0x8384 , 0x00000000 ) ; + + RamWrite32A ( 0x8394 , 0x7FFFFFFF ) ; + RamWrite32A ( 0x838C , 0x00000000 ) ; + RamWrite32A ( 0x8390 , 0x00000000 ) ; + + RamWrite32A ( 0x83A0 , 0x7FFFFFFF ) ; + RamWrite32A ( 0x8398 , 0x00000000 ) ; + RamWrite32A ( 0x839C , 0x00000000 ) ; + + RamWrite32A ( 0x83AC , 0x7FFFFFFF ) ; + RamWrite32A ( 0x83A4 , 0x00000000 ) ; + RamWrite32A ( 0x83A8 , 0x00000000 ) ; + + for( UcCnt = 0 ; UcCnt < 10 ; UcCnt++ ) + { + + + SlMeasureParameterNum = GEA_NUM ; + SlMeasureParameterA = GYRO_RAM_GX_ADIDAT ; + SlMeasureParameterB = GYRO_RAM_GY_ADIDAT ; + + MeasureStart( SlMeasureParameterNum , SlMeasureParameterA , SlMeasureParameterB ) ; + + MeasureWait() ; + + RamRead32A( 0x0290 , &StMeasValueA.StUllnVal.UlLowVal ) ; + RamRead32A( 0x0290 + 4 , &StMeasValueA.StUllnVal.UlHigVal ) ; + RamRead32A( 0x02B8 , &StMeasValueB.StUllnVal.UlLowVal ) ; + RamRead32A( 0x02B8 + 4 , &StMeasValueB.StUllnVal.UlHigVal ) ; + + SlMeasureAveValueA = (INT_32)( (INT_64)StMeasValueA.UllnValue / SlMeasureParameterNum ) ; + SlMeasureAveValueB = (INT_32)( (INT_64)StMeasValueB.UllnValue / SlMeasureParameterNum ) ; + // + UsGxoVal[UcCnt] = (UINT_16)( SlMeasureAveValueA >> 16 ); + + // + UsGyoVal[UcCnt] = (UINT_16)( SlMeasureAveValueB >> 16 ); + + + + if( UcCnt > 0 ) + { + if ( (INT_16)UsGxoVal[0] > (INT_16)UsGxoVal[UcCnt] ) { + UsDif = (UINT_16)((INT_16)UsGxoVal[0] - (INT_16)UsGxoVal[UcCnt]) ; + } else { + UsDif = (UINT_16)((INT_16)UsGxoVal[UcCnt] - (INT_16)UsGxoVal[0]) ; + } + + if( UsDif > GEA_DIF_HIG ) { + UcXHigCnt ++ ; + } + if( UsDif < GEA_DIF_LOW ) { + UcXLowCnt ++ ; + } + + if ( (INT_16)UsGyoVal[0] > (INT_16)UsGyoVal[UcCnt] ) { + UsDif = (UINT_16)((INT_16)UsGyoVal[0] - (INT_16)UsGyoVal[UcCnt]) ; + } else { + UsDif = (UINT_16)((INT_16)UsGyoVal[UcCnt] - (INT_16)UsGyoVal[0]) ; + } + + if( UsDif > GEA_DIF_HIG ) { + UcYHigCnt ++ ; + } + if( UsDif < GEA_DIF_LOW ) { + UcYLowCnt ++ ; + } + } + } + + if( UcXHigCnt >= 1 ) { + UcRst = UcRst | EXE_GXABOVE ; + } + if( UcXLowCnt > 8 ) { + UcRst = UcRst | EXE_GXBELOW ; + } + + if( UcYHigCnt >= 1 ) { + UcRst = UcRst | EXE_GYABOVE ; + } + if( UcYLowCnt > 8 ) { + UcRst = UcRst | EXE_GYBELOW ; + } + + + return( UcRst ) ; +} + + +void PreparationForPowerOff( void ) +{ + UINT_32 UlReadVa; + + RamRead32A( 0x8004, &UlReadVa ); + if( (UINT_8)UlReadVa == 0x02 ){ + RamWrite32A( CMD_GYRO_WR_ACCS, 0x00027000 ); + } +} + +void SrvOn( void ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF010 , 0x00000003 ) ; + + while( UcStRd && ( UlStCnt++ < CNT200MS)) { + UcStRd = RdStatus(1); + } +} + +void SrvOff( void ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF010 , 0x00000000 ) ; + + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + +void VcmStandby( void ) +{ + IOWrite32A( 0xD00078, 0x00000000 ); + IOWrite32A( 0xD00074, 0x00000010 ); + IOWrite32A( 0xD00004, 0x00000005 ); +} + +void VcmActive( void ) +{ + IOWrite32A( 0xD00004, 0x00000007 ); + IOWrite32A( 0xD00074, 0x00000000 ); + IOWrite32A( 0xD00078, 0x00000F3F ); +} + +void SetStandbyMode( void ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + RamWrite32A( 0xF019 , 0x00000001 ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + +void SetActiveMode( void ) +{ + UINT_8 UcStRd = 1; + UINT_32 UlStCnt = 0; + + IOWrite32A( 0xD01008 , 0x00000090 ) ; + RamWrite32A( 0xF019 , 0x00000000 ) ; + while( UcStRd && ( UlStCnt++ < CNT050MS)) { + UcStRd = RdStatus(1); + } +} + + + +UINT_8 LoadUserAreaToPM( void ) +{ + DOWNLOAD_TBL_EXT* ptr ; + UINT_32 UlReadVernum; + UINT_8 ModuleVendor; + UINT_8 ActVer; + UINT_8 MasterSlave; + + ptr = ( DOWNLOAD_TBL_EXT * )DTbl ; + + RamRead32A( 0x8000 , &UlReadVernum ); + switch( UlReadVernum & 0xFF000000 ){ + case 0x01000000: + ModuleVendor = 0x01; + break; + default: + return 0xF0 ; + } + RamRead32A( 0x8004 , &UlReadVernum ); + ActVer = (UINT_8)((UlReadVernum & 0x0000FF00) >> 8); + MasterSlave = (UINT_8)((UlReadVernum & 0xFF000000) >> 24); + do { + if( ptr->Index == ( ((UINT_32)ModuleVendor<<16) + ((UINT_32)ActVer<<8) + MasterSlave ) ) { + + if( ( ptr->SizeFromCode % 64 ) != 0 ) return (0xF1) ; + + return LoadUareToPM( ptr , 0 ); + } + ptr++ ; + } while (ptr->Index != 0xFFFF ) ; + + return 0xF0 ; +} + +UINT_8 LoadUareToPM( DOWNLOAD_TBL_EXT* ptr , UINT_8 mode ) +{ + UINT_8 ans=0; + UINT_32 UlReadVal=0; + UINT_32 UlCnt=0; + + if( !mode ){ + RamWrite32A( 0xE000 , 0x00000000 ); // to boot + WitTim( 15 ) ; // BootƒvƒƒOƒ‰ƒ€‚ð‰ñ‚·‚Ì‚É15msec•K—vB + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + if( UlReadVal != 0x0B ){ + IOWrite32A( SYSDSP_REMAP, 0x00001400 ) ; // CORE_RST[12], MC_IGNORE2[10] = 1 + WitTim( 15 ) ; // BootƒvƒƒOƒ‰ƒ€‚ð‰ñ‚·‚Ì‚É15msec•K—vB + IORead32A( ROMINFO, (UINT_32 *)&UlReadVal ) ; + if( UlReadVal != 0x0B) { + return( 0x02 ); + } + } + + } + + ans = PmemUpdate128( ptr ); // Update the special program for updating the flash memory. + if(ans != 0) return( ans ); + + IOWrite32A( 0xE0701C , 0x00000000); + RamWrite32A( 0xF007, 0x00000000 ); // boot command Access Setup + RamWrite32A( 0x5004 , 0x00000000 ); // Trans user data from flash memory to pm + + do{ + WitTim( 1 ); + if( UlCnt++ > 10 ) { + IOWrite32A( 0xE0701C , 0x00000002); + return (0x10) ; // trans ng + } + RamRead32A( 0x5004, &UlReadVal ); // PmCheck.ExecFlag‚̓ǂÝo‚µ + }while ( UlReadVal != 0 ); + IOWrite32A( 0xE0701C , 0x00000002); + + return( 0 ); +} +UINT_8 RdBurstUareaFromPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ) +{ + if(!UcLength) return(0xff); + if( !mode ){ + RamWrite32A( 0x5000 , UlAddress ); + } + RamWrite32A( 0x5002 , (UINT_32)UcLength ); + WitTim( 1 ) ; // 1ms Wait for prepare trans data + CntRd( 0x5002 , PucData , (UINT_16)UcLength+1); + + return( 0 ); +} +UINT_8 RdSingleUareaFromPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ) +{ + UINT_32 ReadData; + UINT_8 i; + + if(!UcLength) return(0xff); + if( !mode ){ + RamWrite32A( 0x5000 , UlAddress ); + } + for( i=0 ; i <= UcLength ; ) + { + RamRead32A( 0x5001 , &ReadData ); + PucData[i++] = (UINT_8)(ReadData >> 24); + PucData[i++] = (UINT_8)(ReadData >> 16); + PucData[i++] = (UINT_8)(ReadData >> 8); + PucData[i++] = (UINT_8)(ReadData >> 0); + } + + return( 0 ); +} + + + + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PhoneUpdate.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PhoneUpdate.h new file mode 100755 index 0000000000000000000000000000000000000000..59ff88dfa4423e72076cc0a96e403b3c79edc5e1 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PhoneUpdate.h @@ -0,0 +1,353 @@ +/** + * LC898128 Global declaration & prototype declaration + * + * Copyright (C) 2017, ON Semiconductor, all right reserved. + * + **/ + +#ifndef PHONEUPDATE_H_ +#define PHONEUPDATE_H_ + +#include <linux/types.h> +#include "cam_sensor_util.h" +#include "cam_debug_util.h" + +//============================================================================== +// +//============================================================================== +#define MODULE_VENDOR 1 +#define MDL_VER 2 + +#if 0 +#ifdef DEBUG + extern void dbg_printf(const char *, ...); + extern void dbg_Dump(const char *, int); + #define TRACE_INIT(x) dbgu_init(x) + #define TRACE_USB(fmt, ...) dbg_UsbData(fmt, ## __VA_ARGS__) + #define TRACE(fmt, ...) dbg_printf(fmt, ## __VA_ARGS__) + #define TRACE_DUMP(x,y) dbg_Dump(x,y) +#else + #define TRACE_INIT(x) + #define TRACE(...) + #define TRACE_DUMP(x,y) + #define TRACE_USB(...) +#endif + +#else + +#define DEBUG 1 +#ifdef DEBUG + #define TRACE(fmt, ...) CAM_ERR(CAM_OIS, fmt, ## __VA_ARGS__) + #define TRACE_DUMP(x,y) +#else + #define TRACE(...) + #define TRACE_DUMP(x,y) +#endif + +#endif + +#define INT_8 int8_t//char +#define INT_16 int16_t//short +#define INT_32 int32_t//long +#define INT_64 int64_t//long long +#define UINT_8 uint8_t//unsigned char +#define UINT_16 uint16_t//unsigned short +#define UINT_32 uint32_t//unsigned long +#define UINT_64 uint64_t//unsigned long long + +//**************************************************** +// STRUCTURE DEFINE +//**************************************************** +typedef struct { + UINT_32 Index; + UINT_8 FWType; // 1: Normal OIS FW, 2: Servo ON FW + const UINT_8* UpdataCode; + UINT_32 SizeUpdataCode; + UINT_64 SizeUpdataCodeCksm; + const UINT_8* FromCode; + UINT_32 SizeFromCode; + UINT_64 SizeFromCodeCksm; + UINT_32 SizeFromCodeValid; +} DOWNLOAD_TBL_EXT; + +typedef struct STRECALIB { + INT_16 SsFctryOffX ; + INT_16 SsFctryOffY ; + INT_16 SsRecalOffX ; + INT_16 SsRecalOffY ; + INT_16 SsDiffX ; + INT_16 SsDiffY ; +} stReCalib ; + +typedef struct { + INT_32 SiSampleNum ; + INT_32 SiSampleMax ; + + struct { + INT_32 SiMax1 ; + INT_32 SiMin1 ; + UINT_32 UiAmp1 ; + INT_64 LLiIntegral1 ; + INT_64 LLiAbsInteg1 ; + INT_32 PiMeasureRam1 ; + } MeasureFilterA ; + + struct { + INT_32 SiMax2 ; + INT_32 SiMin2 ; + UINT_32 UiAmp2 ; + INT_64 LLiIntegral2 ; + INT_64 LLiAbsInteg2 ; + INT_32 PiMeasureRam2 ; + } MeasureFilterB ; +} MeasureFunction_Type ; + +union DWDVAL { + UINT_32 UlDwdVal ; + UINT_16 UsDwdVal[ 2 ] ; + struct { + UINT_16 UsLowVal ; + UINT_16 UsHigVal ; + } StDwdVal ; + struct { + UINT_8 UcRamVa0 ; + UINT_8 UcRamVa1 ; + UINT_8 UcRamVa2 ; + UINT_8 UcRamVa3 ; + } StCdwVal ; +} ; + +typedef union DWDVAL UnDwdVal; + +union ULLNVAL { + UINT_64 UllnValue ; + UINT_32 UlnValue[ 2 ] ; + struct { + UINT_32 UlLowVal ; + UINT_32 UlHigVal ; + } StUllnVal ; +} ; + +typedef union ULLNVAL UnllnVal; + +#define EXE_END 0x00000002L +#define EXE_GXADJ 0x00000042L +#define EXE_GYADJ 0x00000082L +#define EXE_GZADJ 0x00400002L +#define EXE_AZADJ 0x00200002L +#define EXE_AYADJ 0x00100002L +#define EXE_AXADJ 0x00080002L +#define EXE_HXMVER 0x06 +#define EXE_HYMVER 0x0A +#define EXE_GXABOVE 0x06 +#define EXE_GXBELOW 0x0A +#define EXE_GYABOVE 0x12 +#define EXE_GYBELOW 0x22 + +#define SUCCESS 0x00 +#define FAILURE 0x01 + +#define FT_REPRG ( 15 ) + #define PRDCT_WR 0x55555555 + #define USER_WR 0xAAAAAAAA +#define MAT2_CKSM ( 29 ) +#define CHECKCODE1 ( 30 ) + #define CHECK_CODE1 0x99756768 +#define CHECKCODE2 ( 31 ) + #define CHECK_CODE2 0x01AC28AC + +//============================================================================== +// +//============================================================================== +#define CMD_IO_ADR_ACCESS 0xC000 //!< IO Write Access +#define CMD_IO_DAT_ACCESS 0xD000 //!< IO Read Access +#define SYSDSP_DSPDIV 0xD00014 +#define SYSDSP_SOFTRES 0xD0006C +#define SYSDSP_REMAP 0xD000AC +#define SYSDSP_CVER 0xD00100 +#define ROMINFO 0xE050D4 +#define FLASHROM_128 0xE07000 // Flash Memory I/F”z’uƒAƒhƒŒƒX +#define FLASHROM_FLA_RDAT (FLASHROM_128 + 0x00) +#define FLASHROM_FLA_WDAT (FLASHROM_128 + 0x04) +#define FLASHROM_ACSCNT (FLASHROM_128 + 0x08) +#define FLASHROM_FLA_ADR (FLASHROM_128 + 0x0C) + #define USER_MAT 0 + #define INF_MAT0 1 + #define INF_MAT1 2 + #define INF_MAT2 4 +#define FLASHROM_CMD (FLASHROM_128 + 0x10) +#define FLASHROM_FLAWP (FLASHROM_128 + 0x14) +#define FLASHROM_FLAINT (FLASHROM_128 + 0x18) +#define FLASHROM_FLAMODE (FLASHROM_128 + 0x1C) +#define FLASHROM_TPECPW (FLASHROM_128 + 0x20) +#define FLASHROM_TACC (FLASHROM_128 + 0x24) + +#define FLASHROM_ERR_FLA (FLASHROM_128 + 0x98) +#define FLASHROM_RSTB_FLA (FLASHROM_128 + 0x4CC) +#define FLASHROM_UNLK_CODE1 (FLASHROM_128 + 0x554) +#define FLASHROM_CLK_FLAON (FLASHROM_128 + 0x664) +#define FLASHROM_UNLK_CODE2 (FLASHROM_128 + 0xAA8) +#define FLASHROM_UNLK_CODE3 (FLASHROM_128 + 0xCCC) + +#define READ_STATUS_INI 0x01000000 + +#define HallFilterD_HXDAZ1 0x0048 +#define HallFilterD_HYDAZ1 0x0098 + +#define HALL_RAM_HXOFF 0x00D8 +#define HALL_RAM_HYOFF 0x0128 +#define HALL_RAM_HXOFF1 0x00DC +#define HALL_RAM_HYOFF1 0x012C +#define HALL_RAM_HXOUT0 0x00E0 +#define HALL_RAM_HYOUT0 0x0130 +#define HALL_RAM_SINDX1 0x00F0 +#define HALL_RAM_SINDY1 0x0140 +#define HALL_RAM_HALL_X_OUT 0x00F4 +#define HALL_RAM_HALL_Y_OUT 0x0144 +#define HALL_RAM_HXIDAT 0x0178 +#define HALL_RAM_HYIDAT 0x017C +#define HALL_RAM_GYROX_OUT 0x0180 +#define HALL_RAM_GYROY_OUT 0x0184 +#define HallFilterCoeffX_hxgain0 0x80F0 +#define HallFilterCoeffY_hygain0 0x818C +#define Gyro_Limiter_X 0x8330 +#define Gyro_Limiter_Y 0x8334 +#define GyroFilterTableX_gxzoom 0x82B8 +#define GyroFilterTableY_gyzoom 0x8318 +#define GyroFilterTableX_gxlenz 0x82BC +#define GyroFilterTableY_gylenz 0x831C +#define GyroFilterShiftX 0x8338 +#define GyroFilterShiftY 0x833C + +#define GYRO_RAM_GX_ADIDAT 0x0220 +#define GYRO_RAM_GY_ADIDAT 0x0224 +#define GYRO_RAM_GXOFFZ 0x0240 +#define GYRO_RAM_GYOFFZ 0x0244 +#define GYRO_ZRAM_GZ_ADIDAT 0x0394 +#define GYRO_ZRAM_GZOFFZ 0x03A0 +#define ACCLRAM_X_AC_ADIDAT 0x0448 +#define ACCLRAM_X_AC_OFFSET 0x044C +#define ACCLRAM_Y_AC_ADIDAT 0x0474 +#define ACCLRAM_Y_AC_OFFSET 0x0478 +#define ACCLRAM_Z_AC_ADIDAT 0x04A0 +#define ACCLRAM_Z_AC_OFFSET 0x04A4 + +#define OIS_POS_BY_AF_X 0x05A8 +#define OIS_POS_BY_AF_X1 (0x0000 + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X2 (0x0004 + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X3 (0x0008 + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X4 (0x000C + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X5 (0x0010 + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X6 (0x0014 + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X7 (0x0018 + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X8 (0x001C + OIS_POS_BY_AF_X ) +#define OIS_POS_BY_AF_X9 (0x0020 + OIS_POS_BY_AF_X ) + +#define OIS_POS_BY_AF_Y 0x05CC +#define OIS_POS_BY_AF_Y1 (0x0000 + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y2 (0x0004 + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y3 (0x0008 + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y4 (0x000C + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y5 (0x0010 + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y6 (0x0014 + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y7 (0x0018 + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y8 (0x001C + OIS_POS_BY_AF_Y ) +#define OIS_POS_BY_AF_Y9 (0x0020 + OIS_POS_BY_AF_Y ) + + + +/************************************************/ +/* Command */ +/************************************************/ +#define CMD_IO_ADR_ACCESS 0xC000 +#define CMD_IO_DAT_ACCESS 0xD000 +#define CMD_RETURN_TO_CENTER 0xF010 + #define BOTH_SRV_OFF 0x00000000 + #define XAXS_SRV_ON 0x00000001 + #define YAXS_SRV_ON 0x00000002 + #define BOTH_SRV_ON 0x00000003 +#define CMD_PAN_TILT 0xF011 + #define PAN_TILT_OFF 0x00000000 + #define PAN_TILT_ON 0x00000001 +#define CMD_OIS_ENABLE 0xF012 + #define OIS_DISABLE 0x00000000 + #define OIS_ENABLE 0x00000001 + #define SMA_OIS_ENABLE 0x00010000 + #define BOTH_OIS_ENABLE 0x00010001 + #define OIS_ENABLE_LF 0x00000011 + #define SMA_OIS_ENABLE_LF 0x00010010 + #define BOTH_OIS_ENABLE_LF 0x00010011 +#define CMD_MOVE_STILL_MODE 0xF013 + #define MOVIE_MODE 0x00000000 + #define STILL_MODE 0x00000001 + #define MOVIE_MODE1 0x00000002 + #define STILL_MODE1 0x00000003 + #define MOVIE_MODE2 0x00000004 + #define STILL_MODE2 0x00000005 + #define MOVIE_MODE3 0x00000006 + #define STILL_MODE3 0x00000007 +#define CMD_GYROINITIALCOMMAND 0xF015 + #define SET_ICM20690 0x00000000 + #define SET_LSM6DSM 0x00000002 + #define SET_BMI260 0x00000006 +#define CMD_OSC_DETECTION 0xF017 + #define OSC_DTCT_DISABLE 0x00000000 + #define OSC_DTCT_ENABLE 0x00000001 +#define CMD_SSC_ENABLE 0xF01C + #define SSC_DISABLE 0x00000000 + #define SSC_ENABLE 0x00000001 +#define CMD_GYRO_RD_ACCS 0xF01D +#define CMD_GYRO_WR_ACCS 0xF01E +#define CMD_SMA_CONTROL 0xF01F + #define SMA_STOP 0x00000000 + #define SMA_START 0x00000001 +#define CMD_READ_STATUS 0xF100 +#define READ_STATUS_INI 0x01000000 + +#define CNT050MS 676 +#define CNT100MS 1352 +#define CNT200MS 2703 + +//============================================================================== +// Prototype +//============================================================================== +//extern UINT_8 FlashDownload128( UINT_8 , UINT_8, UINT_8 ); + +extern UINT_8 SetAngleCorrection( float , UINT_8 , UINT_8 ); +extern UINT_8 UnlockCodeSet( void ); +extern UINT_8 UnlockCodeClear(void); +extern UINT_32 MeasGyAcOffset( void ); +extern void SetGyroOffset( UINT_16 GyroOffsetX, UINT_16 GyroOffsetY, UINT_16 GyroOffsetZ ); +extern void SetAcclOffset( UINT_16 AcclOffsetX, UINT_16 AcclOffsetY, UINT_16 AcclOffsetZ ); +extern void GetGyroOffset( UINT_16* GyroOffsetX, UINT_16* GyroOffsetY, UINT_16* GyroOffsetZ ); +extern void GetAcclOffset( UINT_16* AcclOffsetX, UINT_16* AcclOffsetY, UINT_16* AcclOffsetZ ); + +extern UINT_8 RdStatus( UINT_8 UcStBitChk ); +extern void OisEna( void ); +extern void OisDis( void ); +extern void OisDis_Slope( void ); +extern void OisEna_S( void ); +extern void OisEna_SV( void ); +extern void SetPanTiltMode( UINT_8 UcPnTmod ); +extern void SscEna( void ); +extern void SscDis( void ); + +extern UINT_8 RunHea( void ); +extern UINT_8 RunGea( void ); + +extern UINT_32 FW_info[][3]; + +extern void PreparationForPowerOff( void ); +extern void VcmStandby( void ); +extern void VcmActive( void ); +extern void SrvOn( void ); +extern void SrvOff( void ); +extern void SetStandbyMode( void ); +extern void SetActiveMode( void ); + +extern UINT_8 LoadUserAreaToPM( void ); +extern UINT_8 LoadUareToPM( DOWNLOAD_TBL_EXT* ptr , UINT_8 mode ); +extern UINT_8 RdBurstUareaFromPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ); +extern UINT_8 RdSingleUareaFromPm( UINT_32 UlAddress, UINT_8 *PucData , UINT_8 UcLength , UINT_8 mode ); + +#endif /* #ifndef OIS_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PmemCode128.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PmemCode128.h new file mode 100755 index 0000000000000000000000000000000000000000..57aae52f14a71e5dcd4a6faa885f788e12a0493a --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/LC898128/PmemCode128.h @@ -0,0 +1,612 @@ +/** + * @brief LC898128 OIS PRODUCT + * + * @author Copyright (C) 2018 ON Semiconductor All Rights Reserved. + * + **/ + +// Version Name : "01-31-2018" +// Time Stamp : 2019/03/15 10:55:42 + +#define LC898128_PmemCodeSize 0x00000252 +#define LC898128_PmemCodeCheckSum 0x0000ca4568b72f9b + +const unsigned char LC898128_PM[] = { +0x64, 0x00, 0x00, 0x03, 0x87, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x46, 0x0b, 0x03, 0x80, 0x00, +0x00, 0x20, 0x19, 0x03, 0x15, +0x00, 0x00, 0x10, 0x55, 0x42, +0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x04, 0xa4, +0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x04, 0xa4, +0x00, 0x00, 0x80, 0x00, 0x00, +0x00, 0x05, 0x05, 0x05, 0x0d, +0x00, 0x00, 0x00, 0x00, 0x05, +0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, +0xba, 0x11, 0x2b, 0xa1, 0x13, +0x68, 0x00, 0x04, 0x00, 0x38, +0x40, 0x00, 0x03, 0x80, 0x00, +0x66, 0x00, 0x00, 0x04, 0xe8, +0x40, 0x00, 0x01, 0x8e, 0xb9, +0x66, 0x00, 0x00, 0x08, 0x20, +0x68, 0x00, 0x04, 0x00, 0x08, +0x6c, 0x68, 0x00, 0x56, 0x48, +0x46, 0x0e, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, 0x00, +0x40, 0x00, 0x03, 0xff, 0xc7, +0xab, 0xff, 0x06, 0x82, 0x00, +0x00, 0x42, 0x18, 0x80, 0x76, +0x68, 0x00, 0x01, 0x25, 0xa0, +0x40, 0x00, 0x01, 0x88, 0x49, +0x66, 0x00, 0x00, 0x07, 0x88, +0x5c, 0x01, 0xf1, 0x88, 0x08, +0x68, 0x20, 0x00, 0x04, 0x20, +0x5c, 0x81, 0x00, 0x80, 0x36, +0x68, 0x20, 0x00, 0x0b, 0x22, +0x80, 0x00, 0xa8, 0x00, 0x08, +0x81, 0x04, 0xa6, 0x80, 0x00, +0x0b, 0x82, 0x16, 0x00, 0x01, +0x00, 0x01, 0x08, 0x00, 0x0a, +0x85, 0x04, 0x88, 0x08, 0x4a, +0x68, 0x20, 0x00, 0x0d, 0x21, +0x80, 0x00, 0xa8, 0x40, 0x88, +0x80, 0x00, 0x98, 0x08, 0x4a, +0xa0, 0x80, 0x28, 0x40, 0x8a, +0x80, 0x84, 0x94, 0x60, 0xa4, +0x05, 0x0c, 0x88, 0x48, 0xca, +0x40, 0x00, 0x02, 0x80, 0x10, +0x62, 0x00, 0x00, 0x00, 0x36, +0x5c, 0x81, 0x09, 0x82, 0x24, +0x5c, 0x80, 0x81, 0x82, 0x60, +0xbb, 0x00, 0x08, 0x00, 0xcc, +0x40, 0x00, 0x03, 0xa1, 0x40, +0xab, 0xec, 0x08, 0x80, 0x76, +0x66, 0x00, 0x00, 0x3c, 0xe0, +0x68, 0x01, 0x00, 0x04, 0xc8, +0x66, 0x00, 0x00, 0x48, 0x08, +0x5c, 0x01, 0x6a, 0x40, 0x80, +0x88, 0x20, 0x06, 0x83, 0x40, +0x84, 0x12, 0x15, 0x55, 0xe0, +0x24, 0x08, 0x0a, 0x00, 0x40, +0x84, 0x85, 0x0a, 0x08, 0x81, +0x84, 0x00, 0x25, 0x55, 0xe8, +0x04, 0x10, 0x25, 0x55, 0xe9, +0x2c, 0x78, 0x08, 0x08, 0x50, +0x40, 0x00, 0x00, 0x48, 0x52, +0x66, 0x00, 0x00, 0x17, 0x40, +0x5c, 0x01, 0x91, 0x8e, 0x81, +0x6c, 0x68, 0x00, 0x0e, 0x52, +0x5c, 0x00, 0x5b, 0xc0, 0x4f, +0x5c, 0x08, 0x93, 0x01, 0x00, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0a, 0x08, +0x6c, 0x70, 0x38, 0x0a, 0x09, +0x25, 0x82, 0x0b, 0xc0, 0x28, +0x2a, 0x01, 0xc2, 0xa0, 0x0c, +0x25, 0x8a, 0x8b, 0xc0, 0x28, +0x2a, 0x01, 0xd2, 0xa0, 0x0d, +0x28, 0x96, 0x43, 0x20, 0x20, +0xbf, 0xef, 0x06, 0xc4, 0x00, +0x02, 0x60, 0x05, 0xc0, 0x40, +0xb1, 0xff, 0xa2, 0x88, 0x80, +0x68, 0x00, 0x80, 0x00, 0x2c, +0x23, 0x40, 0x36, 0xc0, 0x00, +0x16, 0xc6, 0xc6, 0xc0, 0x00, +0x16, 0xe5, 0x13, 0x00, 0x80, +0x68, 0x00, 0x00, 0xc5, 0x20, +0x54, 0x80, 0xdb, 0xc0, 0x38, +0x84, 0x05, 0x33, 0x20, 0x00, +0xbc, 0x07, 0x13, 0x81, 0x58, +0x6c, 0x00, 0x01, 0x8a, 0x02, +0x52, 0x00, 0x83, 0x80, 0x00, +0x6c, 0x00, 0x01, 0x8a, 0x50, +0x5c, 0x1f, 0xd2, 0xc0, 0x20, +0x6c, 0x40, 0x00, 0x22, 0x00, +0x54, 0x44, 0x00, 0x00, 0x01, +0x68, 0x00, 0x03, 0xff, 0xc8, +0x28, 0x90, 0x95, 0x1a, 0x01, +0x88, 0x0d, 0x13, 0x00, 0x80, +0x54, 0x80, 0xcb, 0xc0, 0x38, +0x84, 0x05, 0x13, 0x20, 0x00, +0xbc, 0x06, 0x13, 0x81, 0x40, +0x6c, 0x00, 0x01, 0x8c, 0x01, +0x24, 0x00, 0x86, 0xc0, 0x00, +0x18, 0xc5, 0x0b, 0x0f, 0xfb, +0x6c, 0x40, 0x00, 0x24, 0x00, +0x54, 0x44, 0x00, 0x40, 0x01, +0x23, 0x40, 0x42, 0x90, 0x25, +0x58, 0x04, 0x00, 0x40, 0xc9, +0x54, 0x46, 0x4b, 0xc0, 0x48, +0x5c, 0x0a, 0x20, 0x81, 0x51, +0x32, 0x00, 0x0b, 0xc0, 0x61, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x18, 0xe0, 0x02, 0x41, 0x00, +0x6c, 0x00, 0x01, 0x8e, 0x50, +0x00, 0x00, 0x08, 0x40, 0x80, +0x28, 0x8c, 0x08, 0x81, 0xd0, +0x66, 0x00, 0x00, 0x45, 0x60, +0x66, 0x00, 0x00, 0x43, 0xe0, +0x68, 0x00, 0x80, 0x03, 0x48, +0x68, 0x00, 0x00, 0xc8, 0x20, +0x66, 0x00, 0x00, 0x48, 0x08, +0x5c, 0x00, 0xab, 0x80, 0x00, +0x68, 0x20, 0x00, 0x0f, 0x20, +0x68, 0x00, 0x00, 0xc8, 0x21, +0x39, 0x02, 0x08, 0x00, 0x00, +0x80, 0x80, 0x25, 0x44, 0x08, +0x84, 0x00, 0x05, 0x44, 0x09, +0x20, 0x46, 0x25, 0x1e, 0x0a, +0x85, 0x00, 0xa6, 0xc4, 0x00, +0x03, 0x25, 0x16, 0xc4, 0x00, +0x03, 0x04, 0x90, 0x00, 0x00, +0x84, 0x80, 0x35, 0x44, 0xcc, +0x84, 0x88, 0x05, 0x44, 0xc2, +0x85, 0x08, 0x26, 0xc4, 0x00, +0x02, 0xa5, 0x12, 0x88, 0x84, +0x6c, 0x40, 0x00, 0x2e, 0x49, +0x28, 0x89, 0xb6, 0xc4, 0x00, +0x03, 0x20, 0x15, 0x1e, 0x0e, +0x88, 0x08, 0x02, 0x3c, 0x24, +0x30, 0x00, 0x86, 0xc4, 0x00, +0x02, 0x84, 0x96, 0xc4, 0x00, +0x02, 0xc4, 0x8b, 0xc1, 0xe9, +0x38, 0x12, 0xa6, 0xc4, 0x00, +0x02, 0x60, 0x06, 0xc4, 0x00, +0x03, 0x00, 0x13, 0x00, 0x08, +0xbc, 0x17, 0x16, 0xc4, 0x00, +0x02, 0xa0, 0x08, 0x81, 0x01, +0x30, 0x04, 0x0b, 0xc1, 0x21, +0x6c, 0x40, 0x00, 0x28, 0x00, +0x6c, 0x40, 0x00, 0x22, 0x01, +0x30, 0x04, 0x0b, 0xc0, 0xc1, +0x6c, 0x40, 0x00, 0x2e, 0x00, +0x88, 0x18, 0x13, 0x00, 0x40, +0xbc, 0x07, 0x16, 0xc4, 0x00, +0x02, 0xc0, 0x06, 0xc4, 0x00, +0x02, 0x40, 0x13, 0x00, 0x40, +0x40, 0x00, 0x03, 0xc0, 0xe0, +0x6c, 0x68, 0x00, 0x10, 0x00, +0x52, 0x04, 0x13, 0x01, 0x20, +0x6c, 0x68, 0x00, 0x10, 0x52, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x00, 0x10, 0x02, +0x52, 0x00, 0x83, 0xc0, 0xef, +0x6c, 0x68, 0x00, 0x10, 0x50, +0x6c, 0x68, 0x00, 0x10, 0x00, +0x52, 0x44, 0x13, 0x01, 0x20, +0x6c, 0x68, 0x00, 0x10, 0x52, +0x00, 0x00, 0x06, 0xc6, 0x80, +0x01, 0x00, 0x22, 0x40, 0x10, +0x6c, 0x68, 0x00, 0x10, 0x50, +0x00, 0x00, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x81, 0x40, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x00, 0x3c, 0x08, +0x5c, 0x0a, 0xc3, 0x01, 0x4e, +0x52, 0x01, 0x03, 0x01, 0x3c, +0x6c, 0x68, 0x00, 0x3c, 0x50, +0x68, 0x34, 0x08, 0x60, 0x20, +0x6c, 0x68, 0x00, 0x3c, 0x00, +0x52, 0x0c, 0x03, 0x01, 0x36, +0x6c, 0x68, 0x00, 0x3c, 0x50, +0x5c, 0x08, 0x02, 0xc8, 0x03, +0x5c, 0x83, 0x00, 0x40, 0x02, +0x52, 0x08, 0x92, 0xd0, 0x02, +0x5c, 0x00, 0x50, 0x40, 0x52, +0xac, 0xfe, 0x18, 0x40, 0x09, +0x52, 0x0d, 0x72, 0xbf, 0xf0, +0x84, 0x04, 0xa9, 0xc1, 0x80, +0x84, 0x00, 0xa5, 0x20, 0x9a, +0x2c, 0xc4, 0x38, 0x01, 0x48, +0xb1, 0xc9, 0x48, 0x40, 0x0a, +0x52, 0x01, 0xb0, 0x80, 0x76, +0x80, 0x04, 0xa0, 0x00, 0x00, +0x84, 0x00, 0xa2, 0x40, 0x36, +0x80, 0x2c, 0xa8, 0x03, 0xd2, +0x6c, 0x68, 0x08, 0x02, 0x48, +0x40, 0x00, 0x00, 0x80, 0xe0, +0x66, 0x00, 0x00, 0x1e, 0x60, +0x66, 0x00, 0x00, 0x2a, 0x40, +0x5c, 0x83, 0x00, 0x80, 0xa0, +0x6c, 0x40, 0x00, 0x22, 0x08, +0x5c, 0x0a, 0xf0, 0x40, 0x48, +0x5c, 0x0a, 0x42, 0x00, 0x20, +0x5c, 0x09, 0x92, 0x00, 0x01, +0x5c, 0x09, 0xe0, 0x00, 0x48, +0x5c, 0x08, 0x3a, 0x00, 0x20, +0x6c, 0x40, 0x00, 0x24, 0x09, +0x84, 0x9c, 0x9a, 0xc7, 0x61, +0x80, 0x0c, 0x9a, 0xc4, 0x61, +0x6c, 0x40, 0x00, 0x26, 0x09, +0x84, 0x04, 0x9a, 0x00, 0x20, +0x80, 0x2c, 0x9a, 0xc8, 0x03, +0x6c, 0x68, 0x00, 0x3c, 0x09, +0x52, 0x4d, 0x72, 0xd0, 0x01, +0x6c, 0x68, 0x00, 0x3c, 0x4a, +0xac, 0xfe, 0x26, 0xc6, 0x80, +0x03, 0xc0, 0xa5, 0x24, 0x1b, +0x08, 0x03, 0x66, 0xc6, 0x80, +0x03, 0xc4, 0xa0, 0x00, 0x00, +0x84, 0x00, 0xa2, 0x49, 0x36, +0x84, 0x04, 0xa0, 0x00, 0x00, +0x84, 0x00, 0xa2, 0x48, 0xb6, +0x80, 0x1c, 0xa0, 0x00, 0x00, +0x84, 0x00, 0xa2, 0x49, 0x34, +0x80, 0x0c, 0x8a, 0x00, 0x01, +0x84, 0x00, 0x82, 0x49, 0xe4, +0x80, 0x04, 0x80, 0x00, 0x00, +0x84, 0x98, 0x82, 0x49, 0xe4, +0x46, 0x0a, 0x40, 0x03, 0x48, +0x84, 0x07, 0xaa, 0x80, 0x10, +0x68, 0x00, 0x00, 0x05, 0x21, +0x5c, 0x10, 0x22, 0xbf, 0xe0, +0x68, 0x00, 0x00, 0x04, 0x20, +0x5c, 0x02, 0x70, 0x48, 0x48, +0x68, 0x00, 0x00, 0x06, 0x22, +0xa4, 0x04, 0x1b, 0x10, 0x00, +0x84, 0x04, 0x88, 0x48, 0x4a, +0x85, 0x05, 0x08, 0x80, 0x76, +0x40, 0x00, 0x02, 0xc7, 0x80, +0x6c, 0x00, 0x00, 0x08, 0x08, +0x68, 0x34, 0x08, 0x43, 0x21, +0x6c, 0x68, 0x10, 0x86, 0x48, +0xa0, 0x88, 0x16, 0xc0, 0x00, +0x00, 0xc0, 0x86, 0xc0, 0x00, +0x00, 0xa0, 0xa8, 0x08, 0x4a, +0x40, 0x00, 0x00, 0x48, 0x48, +0x66, 0x00, 0x00, 0x40, 0x40, +0x66, 0x00, 0x00, 0x40, 0x40, +0x88, 0x10, 0xa3, 0x21, 0xb0, +0xbc, 0x13, 0xd5, 0xc0, 0x83, +0x18, 0xe8, 0x86, 0x00, 0x03, +0x00, 0x08, 0xf6, 0x80, 0x00, +0x00, 0x62, 0x13, 0x81, 0x16, +0x6c, 0x68, 0x12, 0x58, 0x00, +0x25, 0x98, 0x0b, 0xc0, 0x20, +0xbc, 0x02, 0xf2, 0xa7, 0xe4, +0x2a, 0x06, 0x40, 0x00, 0x00, +0x66, 0x00, 0x00, 0x28, 0x48, +0xa4, 0x04, 0x0b, 0xc3, 0x97, +0x60, 0x00, 0x30, 0x00, 0x9f, +0x68, 0x00, 0x00, 0x04, 0x21, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x12, 0x58, 0x00, +0x25, 0x98, 0x0b, 0xc0, 0x20, +0xbc, 0x02, 0xf2, 0xa7, 0xe4, +0x2a, 0x06, 0x40, 0x00, 0x00, +0x66, 0x00, 0x00, 0x26, 0x48, +0x40, 0x00, 0x02, 0x40, 0x40, +0x60, 0x00, 0x30, 0x00, 0x9f, +0x5c, 0x08, 0x71, 0x8e, 0x88, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x12, 0x58, 0x00, +0x25, 0x98, 0x0b, 0xc0, 0x20, +0xbc, 0x02, 0xf2, 0xa7, 0xe4, +0x2a, 0x06, 0x40, 0x00, 0x00, +0x68, 0x00, 0x00, 0x05, 0x21, +0x66, 0x00, 0x00, 0x26, 0x48, +0x40, 0x00, 0x02, 0x40, 0x40, +0x60, 0x00, 0x30, 0x00, 0x9f, +0x5c, 0x08, 0xb1, 0x8e, 0x88, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x12, 0x58, 0x00, +0x25, 0x98, 0x0b, 0xc0, 0x20, +0xbc, 0x02, 0xf2, 0xa7, 0xe4, +0x2a, 0x06, 0x40, 0x00, 0x00, +0x68, 0x00, 0x00, 0x06, 0x21, +0x66, 0x00, 0x00, 0x28, 0x48, +0xa4, 0x04, 0x08, 0x81, 0x08, +0x2a, 0x7e, 0x45, 0x90, 0x10, +0x08, 0x14, 0x8b, 0xf9, 0xab, +0xac, 0x78, 0x08, 0x80, 0x36, +0xba, 0x14, 0x8a, 0x80, 0x20, +0x40, 0x00, 0x03, 0x80, 0x00, +0x59, 0x01, 0x00, 0x40, 0x0a, +0x5c, 0x08, 0x03, 0xc0, 0xfb, +0x54, 0x01, 0xb0, 0x48, 0x08, +0x24, 0x9a, 0x68, 0x48, 0x4a, +0x00, 0x00, 0x08, 0x40, 0x0a, +0x32, 0x03, 0x0b, 0xc1, 0x38, +0x38, 0x0f, 0xc5, 0x40, 0x9a, +0x04, 0x80, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x48, 0x48, +0x00, 0x00, 0x02, 0x41, 0xa4, +0x84, 0x84, 0x80, 0x00, 0x00, +0x84, 0x00, 0x03, 0x20, 0x00, +0xbc, 0x06, 0x83, 0x80, 0xfe, +0x28, 0x18, 0x65, 0x20, 0xd2, +0x3a, 0x14, 0x88, 0x48, 0x48, +0x00, 0x00, 0x0b, 0xa1, 0x40, +0x59, 0x01, 0x00, 0x40, 0x0a, +0x5c, 0x08, 0x03, 0xc0, 0xfb, +0x54, 0x01, 0xb0, 0x48, 0x08, +0x24, 0x9a, 0x68, 0x48, 0x4a, +0x00, 0x00, 0x08, 0x40, 0x0a, +0x32, 0x03, 0x0b, 0xc1, 0x38, +0x38, 0x0f, 0xc5, 0x40, 0x9a, +0x04, 0x80, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x48, 0x48, +0x00, 0x00, 0x02, 0x41, 0xa4, +0x84, 0x84, 0x80, 0x00, 0x00, +0x84, 0x00, 0x03, 0x20, 0x00, +0xbc, 0x06, 0x83, 0x80, 0xfe, +0x28, 0x18, 0x65, 0x20, 0xd2, +0x3a, 0x14, 0x88, 0x48, 0x48, +0x00, 0x00, 0x0b, 0xa1, 0x40, +0x5c, 0x01, 0xa2, 0xbf, 0x20, +0xa4, 0x28, 0x1a, 0x08, 0xc2, +0xa4, 0x0c, 0x0a, 0x00, 0xc0, +0xa4, 0x1a, 0x1a, 0x08, 0xc1, +0x88, 0x06, 0x28, 0x80, 0xe0, +0x88, 0x17, 0x6a, 0xc7, 0x80, +0x6c, 0x00, 0x00, 0x08, 0x0a, +0x55, 0x3b, 0xb0, 0x81, 0xe1, +0x54, 0x09, 0xb0, 0x82, 0x48, +0x32, 0x03, 0x0b, 0xc0, 0x6a, +0x5c, 0x1f, 0xc0, 0x40, 0x4a, +0x30, 0x03, 0x0b, 0xc0, 0x35, +0x84, 0x05, 0x0b, 0xc0, 0x17, +0x84, 0x07, 0xa0, 0x00, 0x00, +0x6c, 0x00, 0x00, 0x0a, 0x0a, +0x2a, 0x77, 0x62, 0x81, 0x36, +0x32, 0x03, 0x0b, 0xc0, 0x6a, +0x84, 0x84, 0xa3, 0x00, 0x30, +0xbc, 0x04, 0x53, 0x83, 0xfe, +0x84, 0x84, 0xab, 0xc0, 0x17, +0x84, 0x87, 0xab, 0x1f, 0xfe, +0x6c, 0x00, 0x00, 0x0c, 0x00, +0x2a, 0x74, 0x02, 0x81, 0x04, +0x32, 0x02, 0x0b, 0xc0, 0x6a, +0x85, 0x04, 0x83, 0x01, 0xa0, +0xbc, 0x05, 0x5b, 0x1f, 0xfc, +0x85, 0x04, 0x8b, 0xc0, 0x27, +0x40, 0x00, 0x00, 0x50, 0x7a, +0x68, 0x34, 0x08, 0x43, 0x23, +0x84, 0x00, 0x86, 0xc6, 0x81, +0x08, 0x64, 0x8a, 0x18, 0x80, +0x84, 0x80, 0xa8, 0x50, 0x08, +0x80, 0x04, 0xa8, 0x40, 0x48, +0x66, 0x00, 0x00, 0x40, 0x40, +0x66, 0x00, 0x00, 0x40, 0x40, +0x88, 0x0a, 0x06, 0x00, 0x03, +0x00, 0x0c, 0xf8, 0x40, 0x7a, +0x5c, 0x08, 0x23, 0x80, 0x00, +0x6c, 0x68, 0x12, 0x58, 0x0a, +0x25, 0x93, 0x0b, 0xc0, 0x48, +0x84, 0x00, 0xa5, 0x53, 0xfb, +0x3c, 0x03, 0xf8, 0x40, 0x4a, +0x2a, 0x07, 0x68, 0x40, 0x4a, +0x00, 0x00, 0x08, 0x81, 0xa1, +0x60, 0x00, 0x30, 0x00, 0xcf, +0x40, 0x00, 0x00, 0x48, 0x7a, +0x5c, 0x08, 0x62, 0x04, 0x20, +0x6c, 0x68, 0x12, 0x58, 0x0a, +0x25, 0x93, 0x0b, 0xc0, 0x48, +0x84, 0x80, 0xa5, 0x53, 0xfb, +0x3c, 0x03, 0xf8, 0x48, 0x4a, +0x2a, 0x07, 0x68, 0x48, 0x4a, +0x00, 0x00, 0x08, 0x80, 0x22, +0x88, 0x20, 0xa6, 0x00, 0x03, +0x00, 0x0c, 0xf8, 0x50, 0x7a, +0x5c, 0x08, 0xa2, 0x0c, 0x21, +0x6c, 0x68, 0x12, 0x58, 0x00, +0x25, 0x90, 0x0b, 0xc0, 0x48, +0x85, 0x00, 0x05, 0x53, 0xe0, +0x3c, 0x03, 0xf8, 0x50, 0x50, +0x2a, 0x04, 0x08, 0x50, 0x50, +0x00, 0x00, 0x05, 0x53, 0xfa, +0x21, 0x42, 0x25, 0x90, 0x10, +0x08, 0x06, 0x24, 0x3c, 0x5d, +0x88, 0x0e, 0x0a, 0xc7, 0x80, +0x84, 0x38, 0x83, 0x20, 0x20, +0xbc, 0x25, 0xba, 0x40, 0xc0, +0x5c, 0x01, 0x22, 0x00, 0xa0, +0x5c, 0x81, 0x01, 0x82, 0x0a, +0xa0, 0x00, 0x18, 0x02, 0x02, +0x32, 0x01, 0x0b, 0xc0, 0x4a, +0x2a, 0x07, 0x08, 0x48, 0x89, +0x32, 0x02, 0x8b, 0xc0, 0x62, +0x32, 0x00, 0x0b, 0xc1, 0x11, +0x6c, 0x40, 0x00, 0x22, 0x7a, +0x40, 0x00, 0x03, 0xc0, 0xd7, +0x5b, 0x44, 0x10, 0x48, 0x89, +0x36, 0x94, 0x53, 0x01, 0x50, +0x40, 0x00, 0x03, 0xc0, 0x42, +0x55, 0x05, 0xb3, 0xc0, 0xff, +0x6c, 0x40, 0x00, 0x22, 0x4a, +0x6c, 0x40, 0x00, 0x22, 0x50, +0xbc, 0x0a, 0x73, 0x20, 0x30, +0xbf, 0xe3, 0xb2, 0xa7, 0xf6, +0x40, 0x00, 0x03, 0xc0, 0x57, +0x5c, 0x01, 0xa2, 0xc0, 0x20, +0x6c, 0x40, 0x00, 0x22, 0x48, +0x38, 0x02, 0x49, 0x8e, 0x80, +0x6c, 0x00, 0x00, 0x08, 0x0a, +0x6c, 0x40, 0x00, 0x22, 0x02, +0x2a, 0x7b, 0x62, 0x80, 0xb2, +0x32, 0x01, 0x0b, 0xc0, 0x4a, +0x55, 0x00, 0x32, 0x41, 0xa0, +0x38, 0x3f, 0x82, 0xf0, 0x10, +0x84, 0x30, 0x23, 0x20, 0x10, +0xbc, 0x22, 0xb6, 0xc4, 0x00, +0x02, 0x25, 0x05, 0x50, 0x10, +0x20, 0x0a, 0x0a, 0x00, 0x01, +0x80, 0x20, 0x93, 0x20, 0x28, +0xbc, 0x04, 0xa2, 0xa0, 0x42, +0x84, 0x88, 0xb3, 0x20, 0x38, +0xbc, 0x05, 0x23, 0x20, 0x10, +0xbc, 0x10, 0x16, 0xc4, 0x00, +0x02, 0x47, 0xab, 0xc0, 0xd7, +0x5b, 0x4a, 0x28, 0x48, 0x8b, +0x36, 0x9c, 0x73, 0x01, 0xe8, +0x40, 0x00, 0x03, 0xc0, 0x42, +0x55, 0x04, 0x03, 0xc0, 0xcf, +0x6c, 0x40, 0x00, 0x24, 0x50, +0x6c, 0x40, 0x00, 0x24, 0x52, +0xbc, 0x07, 0x73, 0x20, 0x00, +0xbf, 0xe4, 0xb2, 0xa7, 0xc0, +0xbc, 0x03, 0x73, 0x80, 0x30, +0x6c, 0x40, 0x00, 0x24, 0x50, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x00, 0xa0, 0x06, 0xc4, 0x00, +0x02, 0x40, 0x22, 0xa7, 0x80, +0x28, 0x08, 0x03, 0x20, 0x00, +0xbc, 0x03, 0xaa, 0x42, 0x80, +0x38, 0x3f, 0xe2, 0xf1, 0x86, +0x84, 0x30, 0x03, 0x20, 0x00, +0xbc, 0x22, 0xb6, 0xc4, 0x00, +0x02, 0x44, 0xaa, 0x00, 0xa0, +0xa0, 0x00, 0x18, 0x02, 0x00, +0x32, 0x00, 0x0b, 0xc0, 0x4a, +0x2a, 0x06, 0x68, 0x48, 0x82, +0x32, 0x01, 0x0b, 0xc0, 0x62, +0x32, 0x03, 0x0b, 0xc1, 0x11, +0x6c, 0x40, 0x00, 0x26, 0x7a, +0x40, 0x00, 0x03, 0xc0, 0xd7, +0x5b, 0x40, 0x00, 0x48, 0x82, +0x36, 0x88, 0x23, 0x00, 0x80, +0x40, 0x00, 0x03, 0xc0, 0x42, +0x55, 0x05, 0x23, 0xc0, 0xcf, +0x6c, 0x40, 0x00, 0x26, 0x48, +0x6c, 0x40, 0x00, 0x26, 0x4a, +0xbc, 0x07, 0x73, 0x20, 0x20, +0xbf, 0xe3, 0xb2, 0xa7, 0xe4, +0xbc, 0x03, 0x73, 0x80, 0x34, +0x6c, 0x40, 0x00, 0x26, 0x48, +0x00, 0x00, 0x06, 0xc0, 0x00, +0x00, 0xc0, 0xa6, 0xc4, 0x00, +0x02, 0x60, 0x02, 0xa7, 0x76, +0x28, 0x03, 0x63, 0x20, 0x30, +0xbc, 0x03, 0xab, 0x1f, 0xfc, +0xbc, 0x02, 0xf2, 0xf1, 0x34, +0x98, 0xe8, 0x88, 0x81, 0x36, +0xba, 0x14, 0x86, 0xc4, 0x00, +0x02, 0x64, 0x8a, 0x80, 0xe0, +0x68, 0x34, 0x00, 0x08, 0x20, +0x5c, 0x09, 0x73, 0x01, 0x24, +0x84, 0x00, 0x05, 0x20, 0xc0, +0x2b, 0xff, 0x08, 0x40, 0x50, +0x88, 0x07, 0x60, 0x00, 0x00, +0x84, 0x00, 0x02, 0x49, 0x00, +0x84, 0x05, 0x0a, 0x00, 0x20, +0x84, 0x00, 0x05, 0x24, 0xc3, +0x20, 0x44, 0x18, 0x40, 0x4a, +0x88, 0x0e, 0x10, 0x00, 0x00, +0x84, 0x00, 0xa2, 0x49, 0x34, +0x40, 0x00, 0x00, 0x40, 0x48, +0x66, 0x00, 0x00, 0x42, 0xa0, +0x66, 0x00, 0x00, 0x44, 0xc0, +0x68, 0x38, 0x14, 0x24, 0x20, +0x5c, 0xa3, 0x03, 0x01, 0x04, +0x5c, 0x03, 0xf0, 0x40, 0x7a, +0x5c, 0x09, 0x01, 0xc0, 0x00, +0x84, 0x00, 0x25, 0x24, 0x89, +0x08, 0x0a, 0x18, 0x40, 0x52, +0xa0, 0x48, 0x08, 0x40, 0x02, +0x52, 0x08, 0xa2, 0x0a, 0xc2, +0x84, 0x04, 0x88, 0x48, 0x4a, +0x00, 0x00, 0x08, 0x50, 0x08, +0x52, 0x01, 0x20, 0x80, 0x36, +0xba, 0x14, 0x88, 0x50, 0x48, +0x40, 0x00, 0x02, 0x80, 0x10, +0x68, 0x34, 0x04, 0x02, 0x20, +0x5c, 0x09, 0xc3, 0x01, 0x26, +0x84, 0x00, 0x22, 0x40, 0x12, +0x84, 0x05, 0x20, 0x00, 0x00, +0x84, 0x00, 0x22, 0x41, 0x92, +0x42, 0x02, 0x78, 0x40, 0x52, +0x5c, 0x08, 0x23, 0x80, 0x00, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x68, 0x08, 0x06, 0x02, +0x25, 0x91, 0x0b, 0xff, 0xa1, +0x6c, 0x68, 0x08, 0x04, 0x02, +0x24, 0x81, 0x06, 0xc6, 0x80, +0x80, 0x45, 0x00, 0x00, 0x00, +0x6c, 0x68, 0x08, 0x04, 0x00, +0x24, 0x98, 0x66, 0xc6, 0x80, +0x80, 0x44, 0xa0, 0x00, 0x00, +0x84, 0x08, 0xa5, 0x20, 0x9a, +0x3a, 0x14, 0x88, 0x40, 0xc8, +0x40, 0x00, 0x03, 0x80, 0x00, +0x68, 0x20, 0x00, 0x0b, 0x20, +0x68, 0x3f, 0xfd, 0x5b, 0x28, +0x5c, 0x09, 0xe0, 0x40, 0x00, +0x40, 0x00, 0x00, 0x40, 0x8a, +0x68, 0x38, 0x1d, 0x55, 0x20, +0x6c, 0x70, 0x3a, 0xaa, 0x50, +0x76, 0x00, 0x00, 0x2a, 0xa1, +0x80, 0x84, 0xa0, 0x00, 0x00, +0x84, 0x80, 0x22, 0x59, 0x10, +0xbf, 0xf7, 0x1b, 0xa1, 0x40, +0x5c, 0x09, 0x23, 0x01, 0x3e, +0x6c, 0x70, 0x38, 0x0a, 0x00, +0x24, 0x10, 0x06, 0xc7, 0x03, +0x80, 0xa5, 0x00, 0x00, 0x00, +0x6c, 0x70, 0x38, 0x0a, 0x00, +0x25, 0x98, 0x0b, 0xff, 0x60, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x68, 0x38, 0x1d, 0x33, 0x20, +0x38, 0x00, 0xc5, 0xc0, 0x42, +0x04, 0x04, 0x87, 0x60, 0x00, +0x00, 0xcc, 0x0b, 0xa1, 0x48, +0x84, 0x04, 0x80, 0x00, 0x00, +0x68, 0x38, 0x1c, 0x03, 0x20, +0x6c, 0x00, 0x01, 0x6c, 0x08, +0x6c, 0x00, 0x01, 0x6e, 0x0a, +0x59, 0x41, 0x80, 0x40, 0x48, +0x5c, 0x00, 0xa2, 0x00, 0x20, +0xbc, 0x0b, 0xd5, 0xc8, 0x10, +0x04, 0x04, 0x86, 0x20, 0x00, +0x00, 0x04, 0x66, 0x80, 0x00, +0x0b, 0x82, 0x10, 0x00, 0x00, +0x80, 0x80, 0x86, 0xc7, 0x03, +0x80, 0x24, 0x80, 0x00, 0x00, +0xbc, 0x03, 0xf3, 0x81, 0x3c, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x93, 0x0b, 0xff, 0xa0, +0x5c, 0x02, 0x33, 0x80, 0x00, +0x42, 0x01, 0x38, 0x40, 0x4a, +0x40, 0x00, 0x03, 0x80, 0x00, +0x6c, 0x70, 0x38, 0x0c, 0x0a, +0x25, 0x93, 0x0b, 0xff, 0xa0, +0x40, 0x00, 0x03, 0xa1, 0x40, +0x68, 0x38, 0x1c, 0x03, 0x21, +0x5c, 0xbf, 0x0b, 0x00, 0x0e, +0x84, 0x84, 0x89, 0xc8, 0x81, +0x55, 0x03, 0x68, 0x48, 0x49, +0x2e, 0x9a, 0xc6, 0x20, 0x00, +0x00, 0x05, 0x48, 0x49, 0x4a, +0x5c, 0x81, 0x02, 0xbf, 0xf0, +0x6c, 0x70, 0x38, 0x00, 0x09, +0x80, 0x04, 0x90, 0x00, 0x00, +0xba, 0x14, 0x8a, 0x80, 0x10, +0x40, 0x00, 0x03, 0x80, 0x00, +0x00, 0xaa, 0xaa, 0xaa, 0xaa, +0x00, 0x55, 0x55, 0x55, 0x55, +0x00, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x01, 0xff, +0x00, 0x00, 0x7f, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0f, 0xff, +0x00, 0x03, 0xff, 0x00, 0x00, +}; + +#define VERNUM 0x000505050d +#define CAL_ID 0x0000000005 diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/Makefile new file mode 100755 index 0000000000000000000000000000000000000000..df96747aa31b46f8e979218d110aa72f9e5aa8ed --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/Makefile @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_ois/ + +obj-$(CONFIG_SPECTRA_CAMERA) += LC898124/ +obj-$(CONFIG_SPECTRA_CAMERA) += LC898128/ + +obj-$(CONFIG_SPECTRA_CAMERA) += fw_download_interface.o + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.c new file mode 100755 index 0000000000000000000000000000000000000000..aa50330fc500caa3110aef16ab3e93ce461b1576 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.c @@ -0,0 +1,1536 @@ +#include <linux/kfifo.h> +#include <asm/arch_timer.h> +#include "fw_download_interface.h" +#include "LC898124/Ois.h" +#include "linux/proc_fs.h" + +extern unsigned char SelectDownload(uint8_t GyroSelect, uint8_t ActSelect, uint8_t MasterSlave, uint8_t FWType); +extern uint8_t FlashDownload128( uint8_t ModuleVendor, uint8_t ActVer, uint8_t MasterSlave, uint8_t FWType); + +#define MAX_DATA_NUM 64 + +struct mutex ois_mutex; +struct cam_ois_ctrl_t *ois_ctrl = NULL; +struct cam_ois_ctrl_t *ois_ctrls[CAM_OIS_TYPE_MAX] = {NULL}; +enum cam_ois_state_vendor ois_state[CAM_OIS_TYPE_MAX] = {0}; + +#define OIS_REGISTER_SIZE 100 +#define OIS_READ_REGISTER_DELAY 100 +#define COMMAND_SIZE 1000 +struct dentry *ois_dentry = NULL; +bool dump_ois_registers = false; +uint32_t ois_registers_124[OIS_REGISTER_SIZE][2] = { + {0xF010, 0x0000},//Servo On/Off + {0xF012, 0x0000},//Enable/Disable OIS + {0xF013, 0x0000},//OIS Mode + {0xF015, 0x0000},//Select Gyro vendor + {0x82B8, 0x0000},//Gyro Gain X + {0x8318, 0x0000},//Gyro Gain Y + {0x0338, 0x0000},//Gyro Offset X + {0x033c, 0x0000},//Gyro Offset Y + {0x01C0, 0x0000},//Hall Offset X + {0x0214, 0x0000},//Hall Offset Y + {0x0310, 0x0000},//Gyro Raw Data X + {0x0314, 0x0000},//Gyro Raw Data Y + {0x0268, 0x0000},//Hall Raw Data X + {0x026C, 0x0000},//Hall Raw Data Y + {0xF100, 0x0000},//OIS status + {0xF112, 0x0000},//spi status + {0x0000, 0x0000}, +}; + +uint32_t ois_registers_128[OIS_REGISTER_SIZE][2] = { + {0xF010, 0x0000},//Servo On/Off + {0xF018, 0x0000},//Damping detection On/Off + {0xF012, 0x0000},//Enable/Disable OIS + {0xF013, 0x0000},//OIS Mode + {0xF015, 0x0000},//Select Gyro vendor + {0x82B8, 0x0000},//Gyro Gain X + {0x8318, 0x0000},//Gyro Gain Y + {0x0240, 0x0000},//Gyro Offset X + {0x0244, 0x0000},//Gyro Offset Y + {0x00D8, 0x0000},//Hall Offset X + {0x0128, 0x0000},//Hall Offset Y + {0x0220, 0x0000},//Gyro Raw Data X + {0x0224, 0x0000},//Gyro Raw Data Y + {0x0178, 0x0000},//Hall Raw Data X + {0x017C, 0x0000},//Hall Raw Data Y + {0xF01D, 0x0000},//SPI IF read access command + {0xF01E, 0x0000},//SPI IF Write access command + {0xF100, 0x0000},//OIS status + {0x04d4, 0x0000}, + {0x04d8, 0x0000}, + {0x0C44, 0x0000}, + {0x06BC, 0x0000}, + {0x0000, 0x0000}, +}; + + +static ssize_t ois_read(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 1; +} + +static ssize_t ois_write(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + char data[COMMAND_SIZE] = {0}; + char* const delim = ":"; + int iIndex = 0; + char *token = NULL, *cur = NULL; + uint32_t addr =0, value = 0; + int result = 0; + uint32_t if_write=0; + + if(puser_buf) { + if (copy_from_user(&data, puser_buf, count)) { + CAM_ERR(CAM_OIS, "copy from user buffer error"); + return -EFAULT; + } + } + + cur = data; + while ((token = strsep(&cur, delim))) { + //CAM_ERR(CAM_OIS, "string = %s iIndex = %d, count = %d", token, iIndex, count); + int ret=0; + if (iIndex == 0) { + ret=kstrtoint(token, 16, &addr); + } else if (iIndex == 1) { + ret=kstrtoint(token, 16, &value); + } else if (iIndex == 2) { + ret=kstrtoint(token, 16, &if_write); + } + if(ret < 0) + CAM_ERR(CAM_OIS,"String conversion to unsigned int failed"); + iIndex++; + } + if (ois_ctrls[CAM_OIS_MASTER] && addr != 0) { + if(if_write == 1){ + result = RamWrite32A_oneplus(ois_ctrls[CAM_OIS_MASTER], addr, value); + if (result < 0) { + CAM_ERR(CAM_OIS, "write addr = 0x%x, value = 0x%x fail", addr, value); + } else { + CAM_INFO(CAM_OIS, "write addr = 0x%x, value = 0x%x success", addr, value); + } + }else if(if_write == 2){ + result = RamRead32A_oneplus(ois_ctrls[CAM_OIS_MASTER], addr, &value); + if (result < 0) { + CAM_ERR(CAM_OIS, "read addr = 0x%x, value = 0x%x fail", addr, value); + } else { + CAM_INFO(CAM_OIS, "read addr = 0x%x, value = 0x%x success", addr, value); + } + } + } + return count; +} + +static ssize_t ois_read_tele(struct file *p_file, + char __user *puser_buf, size_t count, loff_t *p_offset) +{ + return 1; +} + +static ssize_t ois_write_tele(struct file *p_file, + const char __user *puser_buf, + size_t count, loff_t *p_offset) +{ + char data[COMMAND_SIZE] = {0}; + char* const delim = ":"; + int iIndex = 0; + char *token = NULL, *cur = NULL; + uint32_t addr =0, value = 0; + int result = 0; + uint32_t if_write=0; + + if(puser_buf) { + if (copy_from_user(&data, puser_buf, count)) { + CAM_ERR(CAM_OIS, "copy from user buffer error"); + return -EFAULT; + } + } + + cur = data; + while ((token = strsep(&cur, delim))) { + //CAM_ERR(CAM_OIS, "string = %s iIndex = %d, count = %d", token, iIndex, count); + int ret=0; + if (iIndex == 0) { + ret=kstrtoint(token, 16, &addr); + } else if (iIndex == 1) { + ret=kstrtoint(token, 16, &value); + } else if (iIndex == 2) { + ret=kstrtoint(token, 16, &if_write); + } + if(ret < 0) + CAM_ERR(CAM_OIS,"String conversion to unsigned int failed"); + iIndex++; + } + if (ois_ctrls[CAM_OIS_SLAVE] && addr != 0) { + if(if_write == 1){ + result = RamWrite32A_oneplus(ois_ctrls[CAM_OIS_SLAVE], addr, value); + if (result < 0) { + CAM_ERR(CAM_OIS, "write addr = 0x%x, value = 0x%x fail", addr, value); + } else { + CAM_INFO(CAM_OIS, "write addr = 0x%x, value = 0x%x success", addr, value); + } + }else if(if_write == 2){ + result = RamRead32A_oneplus(ois_ctrls[CAM_OIS_SLAVE], addr, &value); + if (result < 0) { + CAM_ERR(CAM_OIS, "read addr = 0x%x, value = 0x%x fail", addr, value); + } else { + CAM_INFO(CAM_OIS, "read addr = 0x%x, value = 0x%x success", addr, value); + } + } + } + return count; +} + + + +static const struct file_operations proc_file_fops = { + .owner = THIS_MODULE, + .read = ois_read, + .write = ois_write, +}; +static const struct file_operations proc_file_fops_tele = { + .owner = THIS_MODULE, + .read = ois_read_tele, + .write = ois_write_tele, +}; + +int ois_start_read(void *arg, bool start) +{ + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "failed: o_ctrl %pK", o_ctrl); + return -EINVAL; + } + + mutex_lock(&(o_ctrl->ois_read_mutex)); + o_ctrl->ois_read_thread_start_to_read = start; + mutex_unlock(&(o_ctrl->ois_read_mutex)); + + msleep(OIS_READ_REGISTER_DELAY); + + return 0; +} + +int ois_read_thread(void *arg) +{ + int rc = 0; + int i; + char buf[OIS_REGISTER_SIZE*2*4] = {0}; + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "failed: o_ctrl %pK", o_ctrl); + return -EINVAL; + } + + CAM_ERR(CAM_OIS, "ois_read_thread created"); + + while (!kthread_should_stop()) { + memset(buf, 0, sizeof(buf)); + mutex_lock(&(o_ctrl->ois_read_mutex)); + if (o_ctrl->ois_read_thread_start_to_read) { + if (strstr(o_ctrl->ois_name, "124")) { + for (i = 0; i < OIS_REGISTER_SIZE; i++) { + if (ois_registers_124[i][0]) { + ois_registers_124[i][1] = 0; + camera_io_dev_read(&(o_ctrl->io_master_info), (uint32_t)ois_registers_124[i][0], (uint32_t *)&ois_registers_124[i][1], + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_DWORD); + } + } + + for (i = 0; i < OIS_REGISTER_SIZE; i++) { + if (ois_registers_124[i][0]) { + snprintf(buf+strlen(buf), sizeof(buf), "0x%x,0x%x,", ois_registers_124[i][0], ois_registers_124[i][1]); + } + } + } else if (strstr(o_ctrl->ois_name, "128")) { + for (i = 0; i < OIS_REGISTER_SIZE; i++) { + if (ois_registers_128[i][0]) { + ois_registers_128[i][1] = 0; + camera_io_dev_read(&(o_ctrl->io_master_info), (uint32_t)ois_registers_128[i][0], (uint32_t *)&ois_registers_128[i][1], + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_DWORD); + } + } + + for (i = 0; i < OIS_REGISTER_SIZE; i++) { + if (ois_registers_128[i][0]) { + snprintf(buf+strlen(buf), sizeof(buf), "0x%x,0x%x,", ois_registers_128[i][0], ois_registers_128[i][1]); + } + } + } + CAM_ERR(CAM_OIS, "%s OIS register data: %s", o_ctrl->ois_name, buf); + } + mutex_unlock(&(o_ctrl->ois_read_mutex)); + + msleep(OIS_READ_REGISTER_DELAY); + } + + CAM_ERR(CAM_OIS, "ois_read_thread exist"); + + return rc; +} + +int ois_start_read_thread(void *arg, bool start) +{ + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + return -1; + } + + if (start) { + if (o_ctrl->ois_read_thread) { + CAM_ERR(CAM_OIS, "ois_read_thread is already created, no need to create again."); + } else { + o_ctrl->ois_read_thread = kthread_run(ois_read_thread, o_ctrl, o_ctrl->ois_name); + if (!o_ctrl->ois_read_thread) { + CAM_ERR(CAM_OIS, "create ois read thread failed"); + mutex_unlock(&(o_ctrl->ois_read_mutex)); + return -2; + } + } + } else { + if (o_ctrl->ois_read_thread) { + mutex_lock(&(o_ctrl->ois_read_mutex)); + o_ctrl->ois_read_thread_start_to_read = 0; + mutex_unlock(&(o_ctrl->ois_read_mutex)); + kthread_stop(o_ctrl->ois_read_thread); + o_ctrl->ois_read_thread = NULL; + } else { + CAM_ERR(CAM_OIS, "ois_read_thread is already stopped, no need to stop again."); + } + } + + return 0; +} + +void WitTim( uint16_t time) +{ + msleep(time); +} + +void CntRd(uint32_t addr, void *data, uint16_t size) +{ + int i = 0; + int32_t rc = 0; + int retry = 3; + struct cam_ois_ctrl_t *o_ctrl = ois_ctrl; + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_read_seq(&(o_ctrl->io_master_info), addr, (uint8_t *)data, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE, + size); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,Continue read failed, rc:%d, retry:%d",o_ctrl->ois_type, rc, i+1); + } else { + break; + } + } +} + +void CntWrt( void *register_data, uint16_t size) +{ + uint8_t *data = (uint8_t *)register_data; + int32_t rc = 0; + int i = 0; + int reg_data_cnt = size - 1; + int continue_cnt = 0; + int retry = 3; + static struct cam_sensor_i2c_reg_array *i2c_write_setting_gl = NULL; + + struct cam_ois_ctrl_t *o_ctrl = ois_ctrl; + + struct cam_sensor_i2c_reg_setting i2c_write; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return; + } + + if (i2c_write_setting_gl == NULL) { + i2c_write_setting_gl = (struct cam_sensor_i2c_reg_array *)kzalloc( + sizeof(struct cam_sensor_i2c_reg_array)*MAX_DATA_NUM*2, GFP_KERNEL); + if(!i2c_write_setting_gl) { + CAM_ERR(CAM_OIS, "Alloc i2c_write_setting_gl failed"); + return; + } + } + + memset(i2c_write_setting_gl, 0, sizeof(struct cam_sensor_i2c_reg_array)*MAX_DATA_NUM*2); + + for(i = 0; i< reg_data_cnt; i++) { + if (i == 0) { + i2c_write_setting_gl[continue_cnt].reg_addr = data[0]; + i2c_write_setting_gl[continue_cnt].reg_data = data[1]; + i2c_write_setting_gl[continue_cnt].delay = 0x00; + i2c_write_setting_gl[continue_cnt].data_mask = 0x00; + } else { + i2c_write_setting_gl[continue_cnt].reg_data = data[i+1]; + i2c_write_setting_gl[continue_cnt].delay = 0x00; + i2c_write_setting_gl[continue_cnt].data_mask = 0x00; + } + continue_cnt++; + } + i2c_write.reg_setting = i2c_write_setting_gl; + i2c_write.size = continue_cnt; + i2c_write.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_write.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_write.delay = 0x00; + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_write, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,Continue write failed, rc:%d, retry:%d",o_ctrl->ois_type, rc, i+1); + } else { + break; + } + } +} + + +int RamWrite32A( uint32_t addr, uint32_t data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + struct cam_ois_ctrl_t *o_ctrl = ois_ctrl; + + struct cam_sensor_i2c_reg_array i2c_write_setting = { + .reg_addr = addr, + .reg_data = data, + .delay = 0x00, + .data_mask = 0x00, + }; + struct cam_sensor_i2c_reg_setting i2c_write = { + .reg_setting = &i2c_write_setting, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_DWORD, + .delay = 0x00, + }; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_write); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,write 0x%04x failed, retry:%d",o_ctrl->ois_type, addr, i+1); + } else { + return rc; + } + } + return rc; +} + +int RamRead32A( uint32_t addr, uint32_t* data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + struct cam_ois_ctrl_t *o_ctrl = ois_ctrl; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + for(i = 0; i < retry; i++) { + rc = camera_io_dev_read(&(o_ctrl->io_master_info), (uint32_t)addr, (uint32_t *)data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_DWORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,read 0x%04x failed, retry:%d",o_ctrl->ois_type, addr, i+1); + } else { + return rc; + } + } + return rc; +} + +int RamWrite32A_oneplus(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, uint32_t data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + struct cam_sensor_i2c_reg_array i2c_write_setting = { + .reg_addr = addr, + .reg_data = data, + .delay = 0x00, + .data_mask = 0x00, + }; + struct cam_sensor_i2c_reg_setting i2c_write = { + .reg_setting = &i2c_write_setting, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_DWORD, + .delay = 0x00, + }; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_write); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,write 0x%04x failed, retry:%d",o_ctrl->ois_type, addr, i+1); + } else { + return rc; + } + } + return rc; +} + +int RamRead32A_oneplus(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, uint32_t* data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + for(i = 0; i < retry; i++) { + rc = camera_io_dev_read(&(o_ctrl->io_master_info), (uint32_t)addr, (uint32_t *)data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_DWORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,read 0x%04x failed, retry:%d",o_ctrl->ois_type, addr, i+1); + } else { + return rc; + } + } + return rc; +} + +void OISCountinueRead(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, void *data, uint16_t size) +{ + int i = 0; + int32_t rc = 0; + int retry = 3; + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_read_seq(&(o_ctrl->io_master_info), addr, (uint8_t *)data, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_WORD, + size); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,Continue read failed, rc:%d, retry:%d",o_ctrl->ois_type, rc, i+1); + } else { + break; + } + } +} + +void OISCountinueWrite( struct cam_ois_ctrl_t *o_ctrl, void *register_data, uint16_t size) +{ + uint32_t *data = (uint32_t *)register_data; + int32_t rc = 0; + int i = 0; + int reg_data_cnt = size - 1; + int continue_cnt = 0; + int retry = 3; + static struct cam_sensor_i2c_reg_array *i2c_write_setting_gl = NULL; + + struct cam_sensor_i2c_reg_setting i2c_write; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return; + } + + if (i2c_write_setting_gl == NULL) { + i2c_write_setting_gl = (struct cam_sensor_i2c_reg_array *)kzalloc( + sizeof(struct cam_sensor_i2c_reg_array)*MAX_DATA_NUM*2, GFP_KERNEL); + if(!i2c_write_setting_gl) { + CAM_ERR(CAM_OIS, "Alloc i2c_write_setting_gl failed"); + return; + } + } + + memset(i2c_write_setting_gl, 0, sizeof(struct cam_sensor_i2c_reg_array)*MAX_DATA_NUM*2); + + for(i = 0; i< reg_data_cnt; i++) { + if (i == 0) { + i2c_write_setting_gl[continue_cnt].reg_addr = data[0]; + i2c_write_setting_gl[continue_cnt].reg_data = data[1]; + i2c_write_setting_gl[continue_cnt].delay = 0x00; + i2c_write_setting_gl[continue_cnt].data_mask = 0x00; + } else { + i2c_write_setting_gl[continue_cnt].reg_data = data[i+1]; + i2c_write_setting_gl[continue_cnt].delay = 0x00; + i2c_write_setting_gl[continue_cnt].data_mask = 0x00; + } + continue_cnt++; + } + i2c_write.reg_setting = i2c_write_setting_gl; + i2c_write.size = continue_cnt; + i2c_write.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + i2c_write.data_type = CAMERA_SENSOR_I2C_TYPE_DWORD; + i2c_write.delay = 0x00; + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_write, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,Continue write failed, rc:%d, retry:%d",o_ctrl->ois_type, rc, i+1); + } else { + break; + } + } + kfree(i2c_write_setting_gl); +} + +int OISWrite(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, uint32_t data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + struct cam_sensor_i2c_reg_array i2c_write_setting = { + .reg_addr = addr, + .reg_data = data, + .delay = 0x00, + .data_mask = 0x00, + }; + struct cam_sensor_i2c_reg_setting i2c_write = { + .reg_setting = &i2c_write_setting, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_DWORD, + .delay = 0x00, + }; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + for(i = 0; i < retry; i++) { + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &i2c_write); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,write 0x%04x failed, retry:%d",o_ctrl->ois_type, addr, i+1); + } else { + return rc; + } + } + return rc; +} + +int OISRead(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, uint32_t* data) +{ + int32_t rc = 0; + int retry = 3; + int i; + + if (o_ctrl == NULL) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + for(i = 0; i < retry; i++) { + rc = camera_io_dev_read(&(o_ctrl->io_master_info), (uint32_t)addr, (uint32_t *)data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_DWORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "ois type=%d,read 0x%04x failed, retry:%d",o_ctrl->ois_type, addr, i+1); + } else { + return rc; + } + } + return rc; +} + +void Set124Or128GyroAccelCoef(struct cam_ois_ctrl_t *o_ctrl) +{ + CAM_ERR(CAM_OIS, "SetGyroAccelCoef SelectAct 0x%x GyroPostion 0x%x\n", o_ctrl->ois_actuator_vendor, o_ctrl->ois_gyro_position); + + if (strstr(o_ctrl->ois_name, "124")) { + if(o_ctrl->ois_gyro_position==3) { + RamWrite32A( GCNV_XX, (UINT32) 0x00000000); + RamWrite32A( GCNV_XY, (UINT32) 0x80000001); + RamWrite32A( GCNV_YY, (UINT32) 0x00000000); + RamWrite32A( GCNV_YX, (UINT32) 0x7FFFFFFF); + RamWrite32A( GCNV_ZP, (UINT32) 0x7FFFFFFF); + + RamWrite32A( ACNV_XX, (UINT32) 0x00000000); + RamWrite32A( ACNV_XY, (UINT32) 0x7FFFFFFF); + RamWrite32A( ACNV_YY, (UINT32) 0x00000000); + RamWrite32A( ACNV_YX, (UINT32) 0x7FFFFFFF); + RamWrite32A( ACNV_ZP, (UINT32) 0x80000001); + } else if(o_ctrl->ois_gyro_position==2) { + RamWrite32A( GCNV_XX, (UINT32) 0x00000000); + RamWrite32A( GCNV_XY, (UINT32) 0x7FFFFFFF); + RamWrite32A( GCNV_YY, (UINT32) 0x00000000); + RamWrite32A( GCNV_YX, (UINT32) 0x7FFFFFFF); + RamWrite32A( GCNV_ZP, (UINT32) 0x7FFFFFFF); + + RamWrite32A( ACNV_XX, (UINT32) 0x00000000); + RamWrite32A( ACNV_XY, (UINT32) 0x7FFFFFFF); + RamWrite32A( ACNV_YY, (UINT32) 0x00000000); + RamWrite32A( ACNV_YX, (UINT32) 0x7FFFFFFF); + RamWrite32A( ACNV_ZP, (UINT32) 0x80000001); + } else if(o_ctrl->ois_gyro_position==4) { + RamWrite32A( GCNV_XX, (UINT32) 0x00000000); + RamWrite32A( GCNV_XY, (UINT32) 0x80000001); + RamWrite32A( GCNV_YY, (UINT32) 0x00000000); + RamWrite32A( GCNV_YX, (UINT32) 0x80000001); + RamWrite32A( GCNV_ZP, (UINT32) 0x7FFFFFFF); + + RamWrite32A( ACNV_XX, (UINT32) 0x00000000); + RamWrite32A( ACNV_XY, (UINT32) 0x7FFFFFFF); + RamWrite32A( ACNV_YY, (UINT32) 0x00000000); + RamWrite32A( ACNV_YX, (UINT32) 0x7FFFFFFF); + RamWrite32A( ACNV_ZP, (UINT32) 0x80000001); + } + } else if (strstr(o_ctrl->ois_name, "128")) { + + } +} + + +static int Download124Or128FW(struct cam_ois_ctrl_t *o_ctrl) +{ + uint32_t UlReadValX, UlReadValY; + uint32_t spi_type; + unsigned char rc = 0; + struct timespec mStartTime, mEndTime, diff; + uint64_t mSpendTime = 0; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + ois_ctrl = o_ctrl; + + getnstimeofday(&mStartTime); + + CAM_INFO(CAM_OIS, "MasterSlave 0x%x, GyroVendor 0x%x, GyroPosition 0x%x, ModuleVendor 0x%x, ActVer 0x%x, FWType 0x%x\n", + o_ctrl->ois_type, o_ctrl->ois_gyro_vendor, o_ctrl->ois_gyro_position, o_ctrl->ois_module_vendor, o_ctrl->ois_actuator_vendor, o_ctrl->ois_fw_flag); + + if (strstr(o_ctrl->ois_name, "124")) { + rc = SelectDownload(o_ctrl->ois_gyro_vendor, o_ctrl->ois_actuator_vendor, o_ctrl->ois_type, o_ctrl->ois_fw_flag); + + if (0 == rc) { + Set124Or128GyroAccelCoef(ois_ctrl); + + //remap + RamWrite32A(0xF000, 0x00000000 ); + //msleep(120); + + //SPI-Master ( Act1 ) Check gyro signal + RamRead32A(0x061C, & UlReadValX ); + RamRead32A(0x0620, & UlReadValY ); + CAM_INFO(CAM_OIS, "Gyro_X:0x%x, Gyro_Y:0x%x", UlReadValX, UlReadValY); + + spi_type = 0; + RamRead32A(0xf112, & spi_type ); + CAM_INFO(CAM_OIS, "spi_type:0x%x", spi_type); + + //SPI-Master ( Act1 ) Check gyro gain + RamRead32A(0x82b8, & UlReadValX ); + RamRead32A(0x8318, & UlReadValY ); + CAM_INFO(CAM_OIS, "Gyro_gain_X:0x%x, Gyro_gain_Y:0x%x", UlReadValX, UlReadValY); + + //SPI-Master ( Act1 ) start gyro signal transfer. ( from Master to slave. ) + if (CAM_OIS_MASTER == o_ctrl->ois_type) { + RamWrite32A(0x8970, 0x00000001 ); + //msleep(5); + RamWrite32A(0xf111, 0x00000001 ); + //msleep(5); + } + } else { + switch (rc) { + case 0x01: + CAM_ERR(CAM_OIS, "H/W error"); + break; + case 0x02: + CAM_ERR(CAM_OIS, "Table Data & Program download verify error"); + break; + case 0xF0: + CAM_ERR(CAM_OIS, "Download code select error"); + break; + case 0xF1: + CAM_ERR(CAM_OIS, "Download code information read error"); + break; + case 0xF2: + CAM_ERR(CAM_OIS, "Download code information disagreement"); + break; + case 0xF3: + CAM_ERR(CAM_OIS, "Download code version error"); + break; + default: + CAM_ERR(CAM_OIS, "Unkown error code"); + break; + } + } + } else if (strstr(o_ctrl->ois_name, "128")) { + rc = FlashDownload128(o_ctrl->ois_module_vendor, o_ctrl->ois_actuator_vendor, o_ctrl->ois_type, o_ctrl->ois_fw_flag); + + if (0 == rc) { + Set124Or128GyroAccelCoef(ois_ctrl); + + //LC898128 don't need to do remap + //RamWrite32A(0xF000, 0x00000000 ); + //msleep(120); + + //select gyro vendor + RamWrite32A(0xF015, o_ctrl->ois_gyro_vendor); + msleep(10); + + //SPI-Master ( Act1 ) Check gyro signal + RamRead32A(0x0220, & UlReadValX ); + RamRead32A(0x0224, & UlReadValY ); + CAM_INFO(CAM_OIS, "Gyro_X:0x%x, Gyro_Y:0x%x", UlReadValX, UlReadValY); + + spi_type = 0; + RamRead32A(0xf112, & spi_type ); + CAM_INFO(CAM_OIS, "spi_type:0x%x", spi_type); + + //SPI-Master ( Act1 ) Check gyro gain + RamRead32A(0x82b8, & UlReadValX ); + RamRead32A(0x8318, & UlReadValY ); + CAM_INFO(CAM_OIS, "Gyro_gain_X:0x%x, Gyro_gain_Y:0x%x", UlReadValX, UlReadValY); + + //open dumping funtion + RamWrite32A(0xF018, 0x01); + + //SPI-Master ( Act1 ) start gyro signal transfer. ( from Master to slave. ) + if (CAM_OIS_MASTER == o_ctrl->ois_type) { + RamWrite32A(0xF017, 0x01); + } + } else { + switch (rc&0xF0) { + case 0x00: + CAM_ERR(CAM_OIS, "Error ; during the rom boot changing. Also including 128 power off issue."); + break; + case 0x20: + CAM_ERR(CAM_OIS, "Error ; during Initial program for updating to program memory."); + break; + case 0x30: + CAM_ERR(CAM_OIS, "Error ; during User Mat area erasing."); + break; + case 0x40: + CAM_ERR(CAM_OIS, "Error ; during User Mat area programing."); + break; + case 0x50: + CAM_ERR(CAM_OIS, "Error ; during the verification."); + break; + case 0x90: + CAM_ERR(CAM_OIS, "Error ; during the drive offset confirmation."); + break; + case 0xA0: + CAM_ERR(CAM_OIS, "Error ; during the MAT2 re-write process."); + break; + case 0xF0: + if (rc == 0xF0) + CAM_ERR(CAM_OIS, "mistake of module vendor designation."); + else if (rc == 0xF1) + CAM_ERR(CAM_OIS, "mistake size of From Code."); + break; + default: + CAM_ERR(CAM_OIS, "Unkown error code"); + break; + } + } + } else { + CAM_ERR(CAM_OIS, "Unsupported OIS"); + } + getnstimeofday(&mEndTime); + diff = timespec_sub(mEndTime, mStartTime); + mSpendTime = (timespec_to_ns(&diff))/1000000; + + CAM_INFO(CAM_OIS, "cam_ois_fw_download rc=%d, (Spend: %d ms)", rc, mSpendTime); + + return 0; +} + +int DownloadFW(struct cam_ois_ctrl_t *o_ctrl) +{ + uint8_t rc = 0; + + if (o_ctrl) { + mutex_lock(&ois_mutex); + + if (CAM_OIS_INVALID == ois_state[o_ctrl->ois_type]) { + + if (CAM_OIS_MASTER == o_ctrl->ois_type) { + rc = Download124Or128FW(ois_ctrls[CAM_OIS_MASTER]); + if (rc) { + CAM_ERR(CAM_OIS, "ois type=%d,Download %s FW failed",o_ctrl->ois_type, o_ctrl->ois_name); + } else { + if (dump_ois_registers && !ois_start_read_thread(ois_ctrls[CAM_OIS_MASTER], 1)) { + ois_start_read(ois_ctrls[CAM_OIS_MASTER], 1); + } + } + } else if (CAM_OIS_SLAVE == o_ctrl->ois_type) { + if (CAM_OIS_INVALID == ois_state[CAM_OIS_MASTER]) { + rc = Download124Or128FW(ois_ctrls[CAM_OIS_MASTER]); + /*donot start main camera thread when switch tele + if (!rc&&dump_ois_registers&&!ois_start_read_thread(ois_ctrls[CAM_OIS_MASTER], 1)) { + ois_start_read(ois_ctrls[CAM_OIS_MASTER], 1); + }*/ + //msleep(120);// Need to check whether we need a long time delay + } + if (rc) { + CAM_ERR(CAM_OIS, "ois type=%d,Download %s FW failed",o_ctrl->ois_type, ois_ctrls[CAM_OIS_MASTER]->ois_name); + } else { + rc = Download124Or128FW(ois_ctrls[CAM_OIS_SLAVE]); + if (rc) { + CAM_ERR(CAM_OIS, "ois type=%d,Download %s FW failed",o_ctrl->ois_type, o_ctrl->ois_name); + } else { + if (dump_ois_registers&&!ois_start_read_thread(ois_ctrls[CAM_OIS_SLAVE], 1)) { + ois_start_read(ois_ctrls[CAM_OIS_SLAVE], 1); + } + } + } + } + ois_state[o_ctrl->ois_type] = CAM_OIS_FW_DOWNLOADED; + } else { + CAM_ERR(CAM_OIS, "ois type=%d,OIS state 0x%x is wrong",o_ctrl->ois_type, ois_state[o_ctrl->ois_type]); + } + mutex_unlock(&ois_mutex); + } else { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + } + + return rc; +} + +int OISPollThread124(void *arg) +{ +#define SAMPLE_COUNT_IN_OIS_124 7 +#define SAMPLE_INTERVAL 4000 + int32_t i = 0; + uint32_t *data = NULL; + uint32_t kfifo_in_len = 0; + uint32_t fifo_size_in_ois = SAMPLE_COUNT_IN_OIS_124*SAMPLE_SIZE_IN_DRIVER; + uint32_t fifo_size_in_driver = SAMPLE_COUNT_IN_DRIVER*SAMPLE_SIZE_IN_DRIVER; + unsigned long long timestampQ = 0; + + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + uint32_t ois_hall_registers[SAMPLE_COUNT_IN_OIS_124] = {0x89C4, 0x89C0, 0x89BC, 0x89B8, 0x89B4, 0x89B0, 0x89AC}; + + mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + kfifo_reset(&(o_ctrl->ois_hall_data_fifo)); + mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); + + data = kzalloc(fifo_size_in_ois, GFP_KERNEL); + if (!data) { + CAM_ERR(CAM_OIS, "failed to kzalloc"); + return -1; + } + + CAM_DBG(CAM_OIS, "ois type=%d,OISPollThread124 creat",o_ctrl->ois_type); + + while(1) { + mutex_lock(&(o_ctrl->ois_poll_thread_mutex)); + if (o_ctrl->ois_poll_thread_exit) { + mutex_unlock(&(o_ctrl->ois_poll_thread_mutex)); + goto exit; + } + mutex_unlock(&(o_ctrl->ois_poll_thread_mutex)); + timestampQ = arch_counter_get_cntvct(); + //CAM_ERR(CAM_OIS, "trace timestamp:%lld in Qtime", timestampQ); + + memset(data, 0, fifo_size_in_ois); + + //Read OIS HALL data + for (i = 0; i < SAMPLE_COUNT_IN_OIS_124; i++) { + data[3*i] = timestampQ >> 32; + data[3*i+1] = timestampQ & 0xFFFFFFFF; + OISRead(o_ctrl, ois_hall_registers[i], &(data[3*i+2])); + timestampQ -= 2*CLOCK_TICKCOUNT_MS; + } + + for (i = SAMPLE_COUNT_IN_OIS_124 - 1; i >= 0; i--) { + CAM_DBG(CAM_OIS, "ois type=%d,OIS HALL data %lld (0x%x 0x%x)",o_ctrl->ois_type, ((uint64_t)data[3*i] << 32)+(uint64_t)data[3*i+1], data[3*i+2]&0xFFFF0000>>16, data[3*i+2]&0xFFFF); + } + + mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + if ((kfifo_len(&(o_ctrl->ois_hall_data_fifo)) + fifo_size_in_ois) > fifo_size_in_driver) { + CAM_DBG(CAM_OIS, "ois type=%d,ois_hall_data_fifo is full, fifo size %d, file len %d, will reset FIFO",o_ctrl->ois_type, kfifo_size(&(o_ctrl->ois_hall_data_fifo)), kfifo_len(&(o_ctrl->ois_hall_data_fifo))); + kfifo_reset(&(o_ctrl->ois_hall_data_fifo)); + } + + if ((kfifo_len(&(o_ctrl->ois_hall_data_fifo)) + fifo_size_in_ois) <= fifo_size_in_driver) { + kfifo_in_len = kfifo_in(&(o_ctrl->ois_hall_data_fifo), data, fifo_size_in_ois); + if (kfifo_in_len != fifo_size_in_ois) { + CAM_DBG(CAM_OIS, "ois type=%d,kfifo_in %d Bytes, FIFO maybe full, some OIS Hall sample maybe dropped.",o_ctrl->ois_type, kfifo_in_len); + } else { + CAM_DBG(CAM_OIS, "ois type=%d,kfifo_in %d Bytes",o_ctrl->ois_type, fifo_size_in_ois); + } + } + mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); + + usleep_range(SAMPLE_COUNT_IN_OIS_124*SAMPLE_INTERVAL-5, SAMPLE_COUNT_IN_OIS_124*SAMPLE_INTERVAL); + } + +exit: + kfree(data); + CAM_DBG(CAM_OIS, "ois type=%d,OISPollThread124 exit",o_ctrl->ois_type); + return 0; +} + + +int OISPollThread128(void *arg) +{ + uint32_t i = 0; + uint32_t j = 0; + uint32_t kfifo_in_len = 0; + uint32_t fifo_size_in_ois = SAMPLE_COUNT_IN_OIS*SAMPLE_SIZE_IN_OIS; + uint32_t fifo_size_in_ois_aligned = SAMPLE_COUNT_IN_OIS*SAMPLE_SIZE_IN_OIS_ALIGNED; + uint32_t fifo_size_in_driver = SAMPLE_COUNT_IN_DRIVER*SAMPLE_SIZE_IN_DRIVER; + uint16_t *p_hall_data_in_ois = NULL; + struct cam_ois_hall_data_in_ois_aligned *p_hall_data_in_ois_aligned = NULL; + struct cam_ois_hall_data_in_driver *p_hall_data_in_driver = NULL; + struct cam_ois_ctrl_t *o_ctrl = (struct cam_ois_ctrl_t *)arg; + uint64_t first_QTimer = 0; // This will be used for the start QTimer to calculate the QTimer interval + uint64_t prev_QTimer = 0; // This is the last QTimer in the last CCI read + uint64_t current_QTimer = 0; // This will be used for the end QTimer to calculate the QTimer interval + uint64_t interval_QTimer = 0; // This is the QTimer interval between two sample + uint64_t sample_offset = 0; // This is timestamp offset between IC and system + uint64_t readout_time = (((1+2+1+SAMPLE_SIZE_IN_OIS*SAMPLE_COUNT_IN_OIS)*8)/1000)*CLOCK_TICKCOUNT_MS; // This is the time of CCI read + uint16_t sample_count = 0; // This is the sample count for one CCI read + uint16_t sample_num = 0; // This will be used to detect whehter some HALL data was dropped + uint32_t total_sample_count = 0;// This will be used to calculate the QTimer interval + uint16_t threshold = 2; // This is the threshold to trigger Timestamp calibration, this means 2ms + uint16_t tmp = 0; + uint64_t real_QTimer; + uint64_t real_QTimer_after; + uint64_t i2c_read_offset; + static uint64_t pre_real_QTimer = 0; + static uint64_t pre_QTimer_offset =0 ; + uint64_t estimate_QTimer = 0; // This is the QTimer interval between two sample + uint32_t vaild_cnt = 0; + uint32_t is_add_Offset = 0; + uint32_t offset_cnt; + mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + kfifo_reset(&(o_ctrl->ois_hall_data_fifo)); + kfifo_reset(&(o_ctrl->ois_hall_data_fifoV2)); + mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); + + p_hall_data_in_ois = kzalloc(fifo_size_in_ois, GFP_KERNEL); + if (!p_hall_data_in_ois) { + CAM_ERR(CAM_OIS, "failed to kzalloc p_hall_data_in_ois"); + return -1; + } + + p_hall_data_in_ois_aligned = kzalloc(fifo_size_in_ois_aligned, GFP_KERNEL); + if (!p_hall_data_in_ois_aligned) { + CAM_ERR(CAM_OIS, "failed to kzalloc p_hall_data_in_ois_aligned"); + kfree(p_hall_data_in_ois); + return -1; + } + + p_hall_data_in_driver = kzalloc(SAMPLE_COUNT_IN_OIS*SAMPLE_SIZE_IN_DRIVER, GFP_KERNEL); + if (!p_hall_data_in_driver) { + CAM_ERR(CAM_OIS, "failed to kzalloc p_hall_data_in_driver"); + kfree(p_hall_data_in_ois); + kfree(p_hall_data_in_ois_aligned); + return -1; + } + + CAM_DBG(CAM_OIS, "ois type=%d,OISPollThread128 creat",o_ctrl->ois_type); + + mutex_lock(&(o_ctrl->ois_power_down_mutex)); + if (o_ctrl->ois_power_state == CAM_OIS_POWER_OFF) { + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + goto exit; + } + mutex_unlock(&(o_ctrl->ois_power_down_mutex)); + + RamWrite32A_oneplus(o_ctrl,0xF110, 0x0);//Clear buffer to all "0" & enable buffer update function. + + while(1) { + + mutex_lock(&(o_ctrl->ois_poll_thread_mutex)); + if (o_ctrl->ois_poll_thread_exit) { + mutex_unlock(&(o_ctrl->ois_poll_thread_mutex)); + goto exit; + } + mutex_unlock(&(o_ctrl->ois_poll_thread_mutex)); + + sample_count = 0; + tmp = sample_num; + memset(p_hall_data_in_ois, 0, fifo_size_in_ois); + memset(p_hall_data_in_ois_aligned, 0, fifo_size_in_ois_aligned); + memset(p_hall_data_in_driver, 0, SAMPLE_COUNT_IN_OIS*SAMPLE_SIZE_IN_DRIVER); + + usleep_range(13995, 14000); + + real_QTimer = arch_counter_get_cntvct(); + + //Read OIS HALL data + OISCountinueRead(o_ctrl, 0xF111, (void *)p_hall_data_in_ois, fifo_size_in_ois); + real_QTimer_after = arch_counter_get_cntvct(); + i2c_read_offset = real_QTimer_after - real_QTimer; + //Covert the data from unaligned to aligned + for(i = 0, j = 0; i < SAMPLE_COUNT_IN_OIS; i++) { + if(((p_hall_data_in_ois[3*i] == 0) && (p_hall_data_in_ois[3*i+1] == 0) && (p_hall_data_in_ois[3*i+2] == 0)) || \ + (p_hall_data_in_ois[3*i] == OIS_MAGIC_NUMBER && p_hall_data_in_ois[3*i+1] == OIS_MAGIC_NUMBER)) { + CAM_DBG(CAM_OIS, "ois type=%d,OIS HALL RAW data %d %d (0x%x 0x%x)",o_ctrl->ois_type, i, + p_hall_data_in_ois[3*i], + p_hall_data_in_ois[3*i+1], + p_hall_data_in_ois[3*i+2]); + } else { + p_hall_data_in_ois_aligned[j].hall_data_cnt = p_hall_data_in_ois[3*i]; + p_hall_data_in_ois_aligned[j].hall_data = ((uint32_t)p_hall_data_in_ois[3*i+1] << 16) + p_hall_data_in_ois[3*i+2]; + CAM_DBG(CAM_OIS, "ois type=%d,OIS HALL RAW data %d %d (0x%x 0x%x)",o_ctrl->ois_type, i, + p_hall_data_in_ois_aligned[j].hall_data_cnt, + p_hall_data_in_ois_aligned[j].hall_data&0xFFFF0000>>16, + p_hall_data_in_ois_aligned[j].hall_data&0xFFFF); + j++; + } + } + + sample_offset = (uint64_t)((p_hall_data_in_ois[3*(SAMPLE_COUNT_IN_OIS-1)+2] & 0xFF) * CLOCK_TICKCOUNT_MS * 2 / OIS_MAX_COUNTER); + + if(first_QTimer == 0) { + //Init some parameters + for(i = 0; i < SAMPLE_COUNT_IN_OIS; i++) { + if((p_hall_data_in_ois_aligned[i].hall_data == 0) && (p_hall_data_in_ois_aligned[i].hall_data_cnt == 0)) { + break; + } + } + if ((i >= 1) && (i <= SAMPLE_COUNT_IN_OIS)) { + first_QTimer = arch_counter_get_cntvct() - readout_time - sample_offset; + prev_QTimer = first_QTimer; + sample_num = p_hall_data_in_ois_aligned[i-1].hall_data_cnt; + } + continue; + } else { + vaild_cnt = 0; + current_QTimer = arch_counter_get_cntvct() - readout_time - sample_offset; + //calculate sample_count and total_sample_count, and detect whether some hall data was dropped. + for(i = 0; i < SAMPLE_COUNT_IN_OIS; i++) { + if((p_hall_data_in_ois_aligned[i].hall_data != 0) || (p_hall_data_in_ois_aligned[i].hall_data_cnt != 0)) { + total_sample_count++; + sample_count++; + while (++tmp != p_hall_data_in_ois_aligned[i].hall_data_cnt) { + total_sample_count++; + CAM_ERR(CAM_OIS, "ois type=%d,One sample was droped, %d %d %d",o_ctrl->ois_type, i, tmp, p_hall_data_in_ois_aligned[i].hall_data_cnt); + } + } + } + if(sample_count > 0) { + if (total_sample_count > 1) { + interval_QTimer = (current_QTimer - first_QTimer)/(total_sample_count - 1); + } else if(total_sample_count == 1) { + interval_QTimer = threshold*CLOCK_TICKCOUNT_MS; + } + + //Calculate the TS for every sample, if some sample were dropped, the TS of this sample will still be calculated, but will not report to UMD. + for(i = 0; i < SAMPLE_COUNT_IN_OIS; i++) { + if((p_hall_data_in_ois_aligned[i].hall_data != 0) || (p_hall_data_in_ois_aligned[i].hall_data_cnt != 0)) { + if (i == 0) { + //p_hall_data_in_driver[i].timestamp = prev_QTimer; + estimate_QTimer = prev_QTimer; + while (++sample_num != p_hall_data_in_ois_aligned[i].hall_data_cnt) { + //p_hall_data_in_driver[i].timestamp += interval_QTimer; + estimate_QTimer += interval_QTimer; + } + //p_hall_data_in_driver[i].timestamp += interval_QTimer; + estimate_QTimer += interval_QTimer; + p_hall_data_in_driver[i].high_dword = estimate_QTimer >> 32; + p_hall_data_in_driver[i].low_dword = estimate_QTimer & 0xFFFFFFFF; + p_hall_data_in_driver[i].hall_data = p_hall_data_in_ois_aligned[i].hall_data; + } else { + //p_hall_data_in_driver[i].timestamp = p_hall_data_in_driver[i-1].timestamp; + estimate_QTimer = ((uint64_t)p_hall_data_in_driver[i-1].high_dword << 32) + (uint64_t)p_hall_data_in_driver[i-1].low_dword; + while (++sample_num != p_hall_data_in_ois_aligned[i].hall_data_cnt) { + //p_hall_data_in_driver[i].timestamp += interval_QTimer; + estimate_QTimer += interval_QTimer; + } + //p_hall_data_in_driver[i].timestamp += interval_QTimer; + estimate_QTimer += interval_QTimer; + p_hall_data_in_driver[i].high_dword = estimate_QTimer >> 32; + p_hall_data_in_driver[i].low_dword = estimate_QTimer & 0xFFFFFFFF; + p_hall_data_in_driver[i].hall_data = p_hall_data_in_ois_aligned[i].hall_data; + } + + CAM_DBG(CAM_OIS, "ois type=%d,OIS HALL data %lld (0x%x 0x%x)",o_ctrl->ois_type, + ((uint64_t)p_hall_data_in_driver[i].high_dword << 32) + (uint64_t)p_hall_data_in_driver[i].low_dword, + (p_hall_data_in_driver[i].hall_data&0xFFFF0000)>>16, + p_hall_data_in_driver[i].hall_data&0xFFFF); + vaild_cnt ++ ; + } else { + break; + } + } + + if ((i >= 1) && (i <= SAMPLE_COUNT_IN_OIS)) { + prev_QTimer = ((uint64_t)p_hall_data_in_driver[i-1].high_dword << 32) + (uint64_t)p_hall_data_in_driver[i-1].low_dword; + } + real_QTimer -= sample_offset; + + + CAM_DBG(CAM_OIS, "OIS HALL data before %lld %lld", + real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer, + pre_real_QTimer - (real_QTimer - (vaild_cnt-1) * interval_QTimer) ); + + if ( pre_real_QTimer != 0 && vaild_cnt > 0 && + ((real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer <= CLOCK_TICKCOUNT_MS) || + (pre_real_QTimer - (real_QTimer - (vaild_cnt-1) * interval_QTimer) <= CLOCK_TICKCOUNT_MS))){ + real_QTimer += interval_QTimer; + } + + for (i =0; i < 5; i++){ + if ( pre_real_QTimer != 0 && vaild_cnt > 0 && + ((int64_t)(real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer )< 0)){ + real_QTimer += interval_QTimer; + is_add_Offset = 1; + } + } + + if ( pre_real_QTimer != 0 && vaild_cnt > 0 && + ((real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer <= CLOCK_TICKCOUNT_MS) || + (pre_real_QTimer - (real_QTimer - (vaild_cnt-1) * interval_QTimer) <= CLOCK_TICKCOUNT_MS))){ + real_QTimer += interval_QTimer; + + } + + if ((pre_real_QTimer != 0) + && ((int64_t)(real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer) > 42000 + || (int64_t)(real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer) < 34000)) { + + if (total_sample_count > 100 ) { + real_QTimer = pre_real_QTimer + vaild_cnt * interval_QTimer; + CAM_DBG(CAM_OIS, "OIS HALL data force calate %d ",offset_cnt); + offset_cnt ++ ; + if (offset_cnt > 3) { + is_add_Offset = 1; + } + } + } else { + offset_cnt = 0; + } + + CAM_DBG(CAM_OIS, "OIS HALL data after %lld %lld", + real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer, + pre_real_QTimer - (real_QTimer - (vaild_cnt-1) * interval_QTimer)); + + pre_QTimer_offset = real_QTimer - pre_real_QTimer - (vaild_cnt-1) * interval_QTimer; + + for (i = 0; i < vaild_cnt ;i++){ + p_hall_data_in_driver[vaild_cnt - i -1].high_dword = real_QTimer >> 32; + p_hall_data_in_driver[vaild_cnt - i -1].low_dword = real_QTimer & 0xFFFFFFFF; + real_QTimer -= interval_QTimer; + } + + for ( i = 0; i < vaild_cnt;i++){ + CAM_DBG(CAM_OIS, "OIS HALL data %lld (0x%x 0x%x) pre :%lld offset reg:%d i2c_read_offset %lld", + ((uint64_t)p_hall_data_in_driver[i].high_dword << 32) + (uint64_t)p_hall_data_in_driver[i].low_dword, + (p_hall_data_in_driver[i].hall_data&0xFFFF0000)>>16, + p_hall_data_in_driver[i].hall_data&0xFFFF, + pre_real_QTimer, + (p_hall_data_in_ois[3*(SAMPLE_COUNT_IN_OIS-1)+2] & 0xFF), + i2c_read_offset); + + } + if (!is_add_Offset){ + pre_real_QTimer = ((uint64_t)p_hall_data_in_driver[vaild_cnt -1].high_dword << 32) | + (uint64_t)p_hall_data_in_driver[vaild_cnt -1].low_dword; + } else { + pre_real_QTimer = 0; + is_add_Offset = 0; + } + //Do Timestamp calibration + //Put the HALL data into the FIFO + mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + if ((kfifo_len(&(o_ctrl->ois_hall_data_fifo)) + vaild_cnt*SAMPLE_SIZE_IN_DRIVER) > fifo_size_in_driver) { + CAM_DBG(CAM_OIS, "ois type=%d,ois_hall_data_fifo is full, fifo size %d, file len %d, will reset FIFO",o_ctrl->ois_type, + kfifo_size(&(o_ctrl->ois_hall_data_fifo)), + kfifo_len(&(o_ctrl->ois_hall_data_fifo))); + kfifo_reset(&(o_ctrl->ois_hall_data_fifo)); + } + + if ((kfifo_len(&(o_ctrl->ois_hall_data_fifoV2)) + vaild_cnt*SAMPLE_SIZE_IN_DRIVER) > fifo_size_in_driver) { + CAM_DBG(CAM_OIS, "ois type=%d,ois_hall_data_fifoV2 is full, fifo size %d, file len %d, will reset FIFO",o_ctrl->ois_type, + kfifo_size(&(o_ctrl->ois_hall_data_fifoV2)), + kfifo_len(&(o_ctrl->ois_hall_data_fifoV2))); + kfifo_reset(&(o_ctrl->ois_hall_data_fifoV2)); + } + //Store ois data for EISV3 + if ((kfifo_len(&(o_ctrl->ois_hall_data_fifo)) + vaild_cnt*SAMPLE_SIZE_IN_DRIVER) <= fifo_size_in_driver) { + kfifo_in_len = kfifo_in(&(o_ctrl->ois_hall_data_fifo), p_hall_data_in_driver, vaild_cnt*SAMPLE_SIZE_IN_DRIVER); + + if (kfifo_in_len != vaild_cnt*SAMPLE_SIZE_IN_DRIVER) { + CAM_DBG(CAM_OIS, "ois type=%d,kfifo_in %d Bytes, FIFO maybe full, some OIS Hall sample maybe dropped.",o_ctrl->ois_type, kfifo_in_len); + } else { + CAM_DBG(CAM_OIS, "ois type=%d,kfifo_in %d Bytes",o_ctrl->ois_type, vaild_cnt*SAMPLE_SIZE_IN_DRIVER); + } + } + //Store ois data for EISv2 + if ((kfifo_len(&(o_ctrl->ois_hall_data_fifoV2)) + vaild_cnt*SAMPLE_SIZE_IN_DRIVER) <= fifo_size_in_driver) { + kfifo_in_len = kfifo_in(&(o_ctrl->ois_hall_data_fifoV2), p_hall_data_in_driver, vaild_cnt*SAMPLE_SIZE_IN_DRIVER); + + if (kfifo_in_len != vaild_cnt*SAMPLE_SIZE_IN_DRIVER) { + CAM_DBG(CAM_OIS, "ois type=%d,kfifo_in %d Bytes, FIFOV2 maybe full, some OIS Hall sample maybe dropped.",o_ctrl->ois_type, kfifo_in_len); + } else { + CAM_DBG(CAM_OIS, "ois type=%d,kfifo_inV2 %d Bytes",o_ctrl->ois_type, vaild_cnt*SAMPLE_SIZE_IN_DRIVER); + } + } + mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); + } + } + } + +exit: + pre_real_QTimer = 0; + is_add_Offset = 0; + total_sample_count = 0; + kfree(p_hall_data_in_ois); + kfree(p_hall_data_in_ois_aligned); + kfree(p_hall_data_in_driver); + CAM_DBG(CAM_OIS, "ois type=%d,OISPollThread128 exit",o_ctrl->ois_type); + return 0; +} + +void ReadOISHALLData(struct cam_ois_ctrl_t *o_ctrl, void *data) +{ + uint32_t data_size = 0; + uint32_t fifo_len_in_ois_driver; + + mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + fifo_len_in_ois_driver = kfifo_len(&(o_ctrl->ois_hall_data_fifo)); + if (fifo_len_in_ois_driver > 0) { + int ret; + if (fifo_len_in_ois_driver > SAMPLE_SIZE_IN_DRIVER*SAMPLE_COUNT_IN_DRIVER) { + fifo_len_in_ois_driver = SAMPLE_SIZE_IN_DRIVER*SAMPLE_COUNT_IN_DRIVER; + } + ret = kfifo_to_user(&(o_ctrl->ois_hall_data_fifo), data, fifo_len_in_ois_driver, &data_size); + CAM_DBG(CAM_OIS, "ois type=%d,Copied %d Bytes to UMD with return value %d",o_ctrl->ois_type, data_size,ret); + } else { + CAM_DBG(CAM_OIS, "ois type=%d,fifo_len is %d, no need copy to UMD",o_ctrl->ois_type, fifo_len_in_ois_driver); + } + + mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); +} + +void ReadOISHALLDataV2(struct cam_ois_ctrl_t *o_ctrl, void *data) +{ + uint32_t data_size = 0; + uint32_t fifo_len_in_ois_driver; + + mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + fifo_len_in_ois_driver = kfifo_len(&(o_ctrl->ois_hall_data_fifoV2)); + if (fifo_len_in_ois_driver > 0) { + int ret; + if (fifo_len_in_ois_driver > SAMPLE_SIZE_IN_DRIVER*SAMPLE_COUNT_IN_DRIVER) { + fifo_len_in_ois_driver = SAMPLE_SIZE_IN_DRIVER*SAMPLE_COUNT_IN_DRIVER; + } + ret = kfifo_to_user(&(o_ctrl->ois_hall_data_fifoV2), data, fifo_len_in_ois_driver, &data_size); + CAM_DBG(CAM_OIS, "ois type=%d,Copied %d Bytes to UMD EISv2 with return value %d",o_ctrl->ois_type, data_size,ret); + } else { + CAM_DBG(CAM_OIS, "ois type=%d,fifo_len is %d, no need copy to UMD EISv2",o_ctrl->ois_type, fifo_len_in_ois_driver); + } + + mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); +} + +void ReadOISHALLDataV3(struct cam_ois_ctrl_t *o_ctrl, void *data) +{ + + //mutex_lock(&(o_ctrl->ois_hall_data_mutex)); + //mutex_unlock(&(o_ctrl->ois_hall_data_mutex)); + +} + +int OISControl(struct cam_ois_ctrl_t *o_ctrl) +{ + if (o_ctrl && (o_ctrl->ois_type != CAM_OIS_MASTER)){ + CAM_INFO(CAM_OIS, "ois type=%d, don't create OIS thread",o_ctrl->ois_type); + return 0; + } + if (o_ctrl && (CAM_OIS_READY == ois_state[o_ctrl->ois_type])) { + switch (o_ctrl->ois_poll_thread_control_cmd) { + case CAM_OIS_START_POLL_THREAD: + mutex_lock(&(o_ctrl->ois_poll_thread_mutex)); + if (o_ctrl->ois_poll_thread) { + CAM_INFO(CAM_OIS, "ois type=%d,ois_poll_thread is already created, no need to create again.",o_ctrl->ois_type); + } else { + o_ctrl->ois_poll_thread_exit = false; + if (strstr(o_ctrl->ois_name, "128")) { + o_ctrl->ois_poll_thread = kthread_run(OISPollThread128, o_ctrl, o_ctrl->ois_name); + } else if (strstr(o_ctrl->ois_name, "124")) { + //o_ctrl->ois_poll_thread = kthread_run(OISPollThread124, o_ctrl, o_ctrl->ois_name); + } + if (!o_ctrl->ois_poll_thread) { + o_ctrl->ois_poll_thread_exit = true; + CAM_DBG(CAM_OIS, "ois type=%d,create ois poll thread failed",o_ctrl->ois_type); + } + } + mutex_unlock(&(o_ctrl->ois_poll_thread_mutex)); + + break; + case CAM_OIS_STOP_POLL_THREAD: + mutex_lock(&(o_ctrl->ois_poll_thread_mutex)); + if (o_ctrl->ois_poll_thread) { + o_ctrl->ois_poll_thread_exit = true; + o_ctrl->ois_poll_thread = NULL; + } + mutex_unlock(&(o_ctrl->ois_poll_thread_mutex)); + + break; + } + } else { + CAM_ERR(CAM_OIS, "o_ctrl=%p,ois_type=%d ois_state=%d",o_ctrl,o_ctrl->ois_type,ois_state[o_ctrl->ois_type]); + return -1; + } + + return 0; +} + +bool IsOISReady(struct cam_ois_ctrl_t *o_ctrl) +{ + uint32_t temp, retry_cnt; + retry_cnt = 3; + + if (o_ctrl) { + if (CAM_OIS_READY == ois_state[o_ctrl->ois_type]) { + CAM_INFO(CAM_OIS, "OIS %d is ready", o_ctrl->ois_type); + return true; + } else { + do { + RamRead32A_oneplus(o_ctrl,0xF100, &temp); + CAM_ERR(CAM_OIS, "OIS %d 0xF100 = 0x%x", o_ctrl->ois_type, temp); + if (temp == 0) { + ois_state[o_ctrl->ois_type] = CAM_OIS_READY; + return true; + } + retry_cnt--; + msleep(10); + } while(retry_cnt); + return false; + } + } else { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + return false; + } +} + +void InitOIS(struct cam_ois_ctrl_t *o_ctrl) +{ + if (o_ctrl) { + if (o_ctrl->ois_type == CAM_OIS_MASTER) { + ois_state[CAM_OIS_MASTER] = CAM_OIS_INVALID; + } else if (o_ctrl->ois_type == CAM_OIS_SLAVE) { + ois_state[CAM_OIS_SLAVE] = CAM_OIS_INVALID; + if (ois_ctrls[CAM_OIS_MASTER]) { + if (camera_io_init(&(ois_ctrls[CAM_OIS_MASTER]->io_master_info))) { + CAM_ERR(CAM_OIS, "cci_init failed"); + } + } + } else { + CAM_ERR(CAM_OIS, "ois_type 0x%x is wrong", o_ctrl->ois_type); + } + } else { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + } +} + +void DeinitOIS(struct cam_ois_ctrl_t *o_ctrl) +{ + if (o_ctrl) { + if (o_ctrl->ois_type == CAM_OIS_MASTER) { + if (o_ctrl->ois_read_thread_start_to_read&&ois_ctrls[CAM_OIS_MASTER]) { + ois_start_read_thread(ois_ctrls[CAM_OIS_MASTER], 0); + } + ois_state[CAM_OIS_MASTER] = CAM_OIS_INVALID; + } else if (o_ctrl->ois_type == CAM_OIS_SLAVE) { + if (ois_ctrls[CAM_OIS_MASTER]) { + /*donot start main camera thread when switch tele + if(o_ctrl->ois_read_thread_start_to_read) { + ois_start_read_thread(ois_ctrls[CAM_OIS_MASTER], 0); + }*/ + if (camera_io_release(&(ois_ctrls[CAM_OIS_MASTER]->io_master_info))) { + CAM_ERR(CAM_OIS, "ois type=%d,cci_deinit failed",o_ctrl->ois_type); + } + } + if (ois_ctrls[CAM_OIS_SLAVE]) { + if(o_ctrl->ois_read_thread_start_to_read) { + ois_start_read_thread(ois_ctrls[CAM_OIS_SLAVE], 0); + } + } + ois_state[CAM_OIS_SLAVE] = CAM_OIS_INVALID; + + } else { + CAM_ERR(CAM_OIS, "ois_type 0x%x is wrong", o_ctrl->ois_type); + } + } else { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + } +} + +void InitOISResource(struct cam_ois_ctrl_t *o_ctrl) +{ + struct proc_dir_entry *face_common_dir = NULL; + struct proc_dir_entry *proc_file_entry = NULL; + struct proc_dir_entry *proc_file_entry_tele = NULL; + mutex_init(&ois_mutex); + if (o_ctrl) { + if (o_ctrl->ois_type == CAM_OIS_MASTER) { + ois_ctrls[CAM_OIS_MASTER] = o_ctrl; + //Hardcode the parameters of main OIS, and those parameters will be overrided when open main camera + o_ctrl->io_master_info.cci_client->sid = 0x24; + o_ctrl->io_master_info.cci_client->i2c_freq_mode = I2C_FAST_PLUS_MODE; + o_ctrl->io_master_info.cci_client->retries = 3; + o_ctrl->io_master_info.cci_client->id_map = 0; + CAM_INFO(CAM_OIS, "ois type=%d,ois_ctrls[%d] = %p",o_ctrl->ois_type, CAM_OIS_MASTER, ois_ctrls[CAM_OIS_MASTER]); + } else if (o_ctrl->ois_type == CAM_OIS_SLAVE) { + ois_ctrls[CAM_OIS_SLAVE] = o_ctrl; + CAM_INFO(CAM_OIS, "ois type=%d,ois_ctrls[%d] = %p",o_ctrl->ois_type, CAM_OIS_SLAVE, ois_ctrls[CAM_OIS_SLAVE]); + } else { + CAM_ERR(CAM_OIS, "ois_type 0x%x is wrong", o_ctrl->ois_type); + } + + if (!ois_dentry) { + ois_dentry = debugfs_create_dir("camera_ois", NULL); + if (ois_dentry) { + debugfs_create_bool("dump_registers", 0777, ois_dentry, &dump_ois_registers); + } else { + CAM_ERR(CAM_OIS, "failed to create dump_registers node"); + } + } else { + CAM_ERR(CAM_OIS, "dump_registers node exist"); + } + } else { + CAM_ERR(CAM_OIS, "o_ctrl is NULL"); + } + + //Create OIS control node + face_common_dir = proc_mkdir("OIS", NULL); + if(!face_common_dir) { + CAM_ERR(CAM_OIS, "create dir fail CAM_ERROR API"); + //return FACE_ERROR_GENERAL; + } + + proc_file_entry = proc_create("OISControl", 0777, face_common_dir, &proc_file_fops); + if(proc_file_entry == NULL) { + CAM_ERR(CAM_OIS, "Create fail"); + } else { + CAM_INFO(CAM_OIS, "Create successs"); + } + proc_file_entry_tele = proc_create("OISControl_tele", 0777, face_common_dir, &proc_file_fops_tele); + if(proc_file_entry_tele == NULL) { + CAM_ERR(CAM_OIS, "Create fail"); + } else { + CAM_INFO(CAM_OIS, "Create successs"); + } +} + + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.h new file mode 100755 index 0000000000000000000000000000000000000000..99deda4ef277c255e020f24ad51391d72ef6bf28 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/onsemi_fw/fw_download_interface.h @@ -0,0 +1,35 @@ +#ifndef _DOWNLOAD_OIS_FW_H_ +#define _DOWNLOAD_OIS_FW_H_ + +#include <linux/module.h> +#include <linux/firmware.h> +#include <cam_sensor_cmn_header.h> +#include "cam_ois_dev.h" +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_res_mgr_api.h" +#include "cam_common_util.h" + +#include <linux/string.h> +#include <linux/time.h> +#include <linux/types.h> + +//int RamWrite32A(uint32_t addr, uint32_t data); +//int RamRead32A(uint32_t addr, uint32_t* data); +int RamWrite32A_oneplus(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, uint32_t data); +int RamRead32A_oneplus(struct cam_ois_ctrl_t *o_ctrl, uint32_t addr, uint32_t* data); +int DownloadFW(struct cam_ois_ctrl_t *o_ctrl); +int OISControl(struct cam_ois_ctrl_t *o_ctrl); +void ReadOISHALLData(struct cam_ois_ctrl_t *o_ctrl, void *data); +void ReadOISHALLDataV2(struct cam_ois_ctrl_t *o_ctrl, void *data); +void ReadOISHALLDataV3(struct cam_ois_ctrl_t *o_ctrl, void *data); +bool IsOISReady(struct cam_ois_ctrl_t *o_ctrl); +void InitOIS(struct cam_ois_ctrl_t *o_ctrl); +void DeinitOIS(struct cam_ois_ctrl_t *o_ctrl); +void InitOISResource(struct cam_ois_ctrl_t *o_ctrl); + +#endif +/* _DOWNLOAD_OIS_FW_H_ */ + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1c8ccb0e3bf44473106a930c5493fd3226e803e9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +#ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_res_mgr.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c new file mode 100644 index 0000000000000000000000000000000000000000..c87540f7950f69c0d49d9aadf0fb2500552beedc --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -0,0 +1,739 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include "cam_debug_util.h" +#include "cam_res_mgr_api.h" +#include "cam_res_mgr_private.h" + +static struct cam_res_mgr *cam_res; + +static void cam_res_mgr_free_res(void) +{ + struct cam_dev_res *dev_res, *dev_temp; + struct cam_gpio_res *gpio_res, *gpio_temp; + struct cam_flash_res *flash_res, *flash_temp; + + if (!cam_res) + return; + + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry_safe(gpio_res, gpio_temp, + &cam_res->gpio_res_list, list) { + list_for_each_entry_safe(dev_res, dev_temp, + &gpio_res->dev_list, list) { + list_del_init(&dev_res->list); + kfree(dev_res); + } + list_del_init(&gpio_res->list); + kfree(gpio_res); + } + mutex_unlock(&cam_res->gpio_res_lock); + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry_safe(flash_res, flash_temp, + &cam_res->flash_res_list, list) { + list_del_init(&flash_res->list); + kfree(flash_res); + } + mutex_unlock(&cam_res->flash_res_lock); + + mutex_lock(&cam_res->clk_res_lock); + cam_res->shared_clk_ref_count = 0; + mutex_unlock(&cam_res->clk_res_lock); +} + +void cam_res_mgr_led_trigger_register(const char *name, struct led_trigger **tp) +{ + bool found = false; + struct cam_flash_res *flash_res; + + if (!cam_res) { + /* + * If this driver not probed, then just register the + * led trigger. + */ + led_trigger_register_simple(name, tp); + return; + } + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry(flash_res, &cam_res->flash_res_list, list) { + if (!strcmp(flash_res->name, name)) { + found = true; + break; + } + } + mutex_unlock(&cam_res->flash_res_lock); + + if (found) { + *tp = flash_res->trigger; + } else { + flash_res = kzalloc(sizeof(struct cam_flash_res), GFP_KERNEL); + if (!flash_res) { + CAM_ERR(CAM_RES, + "Failed to malloc memory for flash_res:%s", + name); + *tp = NULL; + return; + } + + led_trigger_register_simple(name, tp); + INIT_LIST_HEAD(&flash_res->list); + flash_res->trigger = *tp; + flash_res->name = name; + + mutex_lock(&cam_res->flash_res_lock); + list_add_tail(&flash_res->list, &cam_res->flash_res_list); + mutex_unlock(&cam_res->flash_res_lock); + } +} +EXPORT_SYMBOL(cam_res_mgr_led_trigger_register); + +void cam_res_mgr_led_trigger_unregister(struct led_trigger *tp) +{ + bool found = false; + struct cam_flash_res *flash_res; + + if (!cam_res) { + /* + * If this driver not probed, then just unregister the + * led trigger. + */ + led_trigger_unregister_simple(tp); + return; + } + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry(flash_res, &cam_res->flash_res_list, list) { + if (flash_res->trigger == tp) { + found = true; + break; + } + } + + if (found) { + led_trigger_unregister_simple(tp); + list_del_init(&flash_res->list); + kfree(flash_res); + } + mutex_unlock(&cam_res->flash_res_lock); +} +EXPORT_SYMBOL(cam_res_mgr_led_trigger_unregister); + +void cam_res_mgr_led_trigger_event(struct led_trigger *trig, + enum led_brightness brightness) +{ + bool found = false; + struct cam_flash_res *flash_res; + + if (!cam_res) { + /* + * If this driver not probed, then just trigger + * the led event. + */ + led_trigger_event(trig, brightness); + return; + } + + mutex_lock(&cam_res->flash_res_lock); + list_for_each_entry(flash_res, &cam_res->flash_res_list, list) { + if (flash_res->trigger == trig) { + found = true; + break; + } + } + mutex_unlock(&cam_res->flash_res_lock); + + if (found) + led_trigger_event(trig, brightness); +} +EXPORT_SYMBOL(cam_res_mgr_led_trigger_event); + +int cam_res_mgr_shared_pinctrl_init(void) +{ + struct cam_soc_pinctrl_info *pinctrl_info; + + /* + * We allow the cam_res is NULL or shared_gpio_enabled + * is false, it means this driver no probed or doesn't + * have shared gpio in this device. + */ + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return 0; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus != PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl already been got."); + mutex_unlock(&cam_res->gpio_res_lock); + return 0; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + pinctrl_info->pinctrl = + devm_pinctrl_get(cam_res->dev); + if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) { + CAM_ERR(CAM_RES, "Pinctrl not available"); + cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); + return -EINVAL; + } + + pinctrl_info->gpio_state_active = + pinctrl_lookup_state(pinctrl_info->pinctrl, + CAM_RES_MGR_DEFAULT); + if (IS_ERR_OR_NULL(pinctrl_info->gpio_state_active)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); + return -EINVAL; + } + + pinctrl_info->gpio_state_suspend = + pinctrl_lookup_state(pinctrl_info->pinctrl, + CAM_RES_MGR_SLEEP); + if (IS_ERR_OR_NULL(pinctrl_info->gpio_state_suspend)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); + return -EINVAL; + } + + cam_res->pstatus = PINCTRL_STATUS_GOT; + mutex_unlock(&cam_res->gpio_res_lock); + + return 0; +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_init); + +static bool cam_res_mgr_shared_pinctrl_check_hold(void) +{ + int index = 0; + int dev_num = 0; + bool hold = false; + struct list_head *list; + struct cam_gpio_res *gpio_res; + struct cam_res_mgr_dt *dt = &cam_res->dt; + + for (; index < dt->num_shared_gpio; index++) { + list_for_each_entry(gpio_res, + &cam_res->gpio_res_list, list) { + + if (gpio_res->gpio == + dt->shared_gpio[index]) { + list_for_each(list, &gpio_res->dev_list) + dev_num++; + + if (dev_num >= 2) { + hold = true; + break; + } + } + } + } + + if (cam_res->shared_clk_ref_count > 1) + hold = true; + + return hold; +} + +void cam_res_mgr_shared_pinctrl_put(void) +{ + struct cam_soc_pinctrl_info *pinctrl_info; + + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus == PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl already been put"); + mutex_unlock(&cam_res->gpio_res_lock); + return; + } + + if (cam_res_mgr_shared_pinctrl_check_hold()) { + CAM_INFO(CAM_RES, "Need hold put this pinctrl"); + mutex_unlock(&cam_res->gpio_res_lock); + return; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + devm_pinctrl_put(pinctrl_info->pinctrl); + + cam_res->pstatus = PINCTRL_STATUS_PUT; + mutex_unlock(&cam_res->gpio_res_lock); +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_put); + +int cam_res_mgr_shared_pinctrl_select_state(bool active) +{ + int rc = 0; + struct cam_soc_pinctrl_info *pinctrl_info; + + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return 0; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus == PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl alerady been put.!"); + mutex_unlock(&cam_res->gpio_res_lock); + return 0; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + if (active && (cam_res->pstatus != PINCTRL_STATUS_ACTIVE)) { + rc = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->gpio_state_active); + cam_res->pstatus = PINCTRL_STATUS_ACTIVE; + } else if (!active && + !cam_res_mgr_shared_pinctrl_check_hold()) { + rc = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->gpio_state_suspend); + cam_res->pstatus = PINCTRL_STATUS_SUSPEND; + } + + mutex_unlock(&cam_res->gpio_res_lock); + + return rc; +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_select_state); + +int cam_res_mgr_shared_pinctrl_post_init(void) +{ + int ret = 0; + struct cam_soc_pinctrl_info *pinctrl_info; + + if (!cam_res || !cam_res->shared_gpio_enabled) { + CAM_DBG(CAM_RES, "Not support shared gpio."); + return ret; + } + + mutex_lock(&cam_res->gpio_res_lock); + if (cam_res->pstatus == PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl alerady been put.!"); + mutex_unlock(&cam_res->gpio_res_lock); + return ret; + } + + pinctrl_info = &cam_res->dt.pinctrl_info; + + /* + * If no gpio resource in gpio_res_list, and + * no shared clk now, it means this device + * don't have shared gpio. + */ + if (list_empty(&cam_res->gpio_res_list) && + cam_res->shared_clk_ref_count < 1) { + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->gpio_state_suspend); + devm_pinctrl_put(pinctrl_info->pinctrl); + cam_res->pstatus = PINCTRL_STATUS_PUT; + } + mutex_unlock(&cam_res->gpio_res_lock); + + return ret; +} +EXPORT_SYMBOL(cam_res_mgr_shared_pinctrl_post_init); + +static int cam_res_mgr_add_device(struct device *dev, + struct cam_gpio_res *gpio_res) +{ + struct cam_dev_res *dev_res = NULL; + + dev_res = kzalloc(sizeof(struct cam_dev_res), GFP_KERNEL); + if (!dev_res) + return -ENOMEM; + + dev_res->dev = dev; + INIT_LIST_HEAD(&dev_res->list); + + list_add_tail(&dev_res->list, &gpio_res->dev_list); + + return 0; +} + +static bool cam_res_mgr_gpio_is_shared(uint gpio) +{ + int index = 0; + bool found = false; + struct cam_res_mgr_dt *dt = &cam_res->dt; + + mutex_lock(&cam_res->gpio_res_lock); + for (; index < dt->num_shared_gpio; index++) { + if (gpio == dt->shared_gpio[index]) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + + return found; +} + +int cam_res_mgr_gpio_request(struct device *dev, uint gpio, + unsigned long flags, const char *label) +{ + int rc = 0; + bool found = false; + struct cam_gpio_res *gpio_res = NULL; + + if (cam_res && cam_res->shared_gpio_enabled) { + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(gpio_res, &cam_res->gpio_res_list, list) { + if (gpio == gpio_res->gpio) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + /* + * found equal to false has two situation: + * 1. shared gpio not enabled + * 2. shared gpio enabled, but not find this gpio + * from the gpio_res_list + * These two situation both need request gpio. + */ + if (!found) { + rc = gpio_request_one(gpio, flags, label); + if (rc) { + CAM_ERR(CAM_RES, "gpio %d:%s request fails", + gpio, label); + return rc; + } + } + + /* + * If the gpio is in the shared list, and not find + * from gpio_res_list, then insert a cam_gpio_res + * to gpio_res_list. + */ + if (!found && cam_res + && cam_res->shared_gpio_enabled && + cam_res_mgr_gpio_is_shared(gpio)) { + + gpio_res = kzalloc(sizeof(struct cam_gpio_res), GFP_KERNEL); + if (!gpio_res) + return -ENOMEM; + + gpio_res->gpio = gpio; + gpio_res->power_on_count = 0; + INIT_LIST_HEAD(&gpio_res->list); + INIT_LIST_HEAD(&gpio_res->dev_list); + + mutex_lock(&cam_res->gpio_res_lock); + rc = cam_res_mgr_add_device(dev, gpio_res); + if (rc) { + kfree(gpio_res); + mutex_unlock(&cam_res->gpio_res_lock); + return rc; + } + + list_add_tail(&gpio_res->list, &cam_res->gpio_res_list); + mutex_unlock(&cam_res->gpio_res_lock); + } + + if (found && cam_res + && cam_res->shared_gpio_enabled) { + struct cam_dev_res *dev_res = NULL; + + found = 0; + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(dev_res, &gpio_res->dev_list, list) { + if (dev_res->dev == dev) { + found = 1; + break; + } + } + + if (!found) + rc = cam_res_mgr_add_device(dev, gpio_res); + + mutex_unlock(&cam_res->gpio_res_lock); + } + + return rc; +} +EXPORT_SYMBOL(cam_res_mgr_gpio_request); + +static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) +{ + bool found = false; + bool need_free = true; + int dev_num = 0; + struct cam_gpio_res *gpio_res = NULL; + + if (cam_res && cam_res->shared_gpio_enabled) { + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(gpio_res, &cam_res->gpio_res_list, list) { + if (gpio == gpio_res->gpio) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + if (found && cam_res + && cam_res->shared_gpio_enabled) { + struct list_head *list; + struct cam_dev_res *dev_res = NULL; + + mutex_lock(&cam_res->gpio_res_lock); + /* Count the dev number in the dev_list */ + list_for_each(list, &gpio_res->dev_list) + dev_num++; + + /* + * Need free the gpio if only has last 1 device + * in the dev_list, otherwise, not free this + * gpio. + */ + if (dev_num == 1) { + dev_res = list_first_entry(&gpio_res->dev_list, + struct cam_dev_res, list); + list_del_init(&dev_res->list); + kfree(dev_res); + + list_del_init(&gpio_res->list); + kfree(gpio_res); + } else { + list_for_each_entry(dev_res, + &gpio_res->dev_list, list) { + if (dev_res->dev == dev) { + list_del_init(&dev_res->list); + kfree(dev_res); + need_free = false; + break; + } + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + if (need_free) + gpio_free(gpio); +} + +void cam_res_mgr_gpio_free_arry(struct device *dev, + const struct gpio *array, size_t num) +{ + while (num--) + cam_res_mgr_gpio_free(dev, (array[num]).gpio); +} +EXPORT_SYMBOL(cam_res_mgr_gpio_free_arry); + +int cam_res_mgr_gpio_set_value(unsigned int gpio, int value) +{ + int rc = 0; + bool found = false; + struct cam_gpio_res *gpio_res = NULL; + + if (cam_res && cam_res->shared_gpio_enabled) { + mutex_lock(&cam_res->gpio_res_lock); + list_for_each_entry(gpio_res, &cam_res->gpio_res_list, list) { + if (gpio == gpio_res->gpio) { + found = true; + break; + } + } + mutex_unlock(&cam_res->gpio_res_lock); + } + + /* + * Set the value directly if can't find the gpio from + * gpio_res_list, otherwise, need add ref count support + **/ + if (!found) { + gpio_set_value_cansleep(gpio, value); + } else { + if (value) { + gpio_res->power_on_count++; + if (gpio_res->power_on_count < 2) { + gpio_set_value_cansleep(gpio, value); + CAM_DBG(CAM_RES, + "Shared GPIO(%d) : HIGH", gpio); + } + } else { + gpio_res->power_on_count--; + if (gpio_res->power_on_count < 1) { + gpio_set_value_cansleep(gpio, value); + CAM_DBG(CAM_RES, + "Shared GPIO(%d) : LOW", gpio); + } + } + } + + return rc; +} +EXPORT_SYMBOL(cam_res_mgr_gpio_set_value); + +void cam_res_mgr_shared_clk_config(bool value) +{ + if (!cam_res) + return; + + mutex_lock(&cam_res->clk_res_lock); + if (value) + cam_res->shared_clk_ref_count++; + else + cam_res->shared_clk_ref_count--; + mutex_unlock(&cam_res->clk_res_lock); +} +EXPORT_SYMBOL(cam_res_mgr_shared_clk_config); + +static int cam_res_mgr_parse_dt(struct device *dev) +{ + int rc = 0; + struct device_node *of_node = NULL; + struct cam_res_mgr_dt *dt = &cam_res->dt; + + of_node = dev->of_node; + + dt->num_shared_gpio = of_property_count_u32_elems(of_node, + "shared-gpios"); + + if (dt->num_shared_gpio > MAX_SHARED_GPIO_SIZE || + dt->num_shared_gpio <= 0) { + /* + * Not really an error, it means dtsi not configure + * the shared gpio. + */ + CAM_DBG(CAM_RES, "Invalid GPIO number %d. No shared gpio.", + dt->num_shared_gpio); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "shared-gpios", + dt->shared_gpio, dt->num_shared_gpio); + if (rc) { + CAM_ERR(CAM_RES, "Get shared gpio array failed."); + return -EINVAL; + } + + dt->pinctrl_info.pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(dt->pinctrl_info.pinctrl)) { + CAM_ERR(CAM_RES, "Pinctrl not available"); + return -EINVAL; + } + + /* + * Check the pinctrl state to make sure the gpio + * shared enabled. + */ + dt->pinctrl_info.gpio_state_active = + pinctrl_lookup_state(dt->pinctrl_info.pinctrl, + CAM_RES_MGR_DEFAULT); + if (IS_ERR_OR_NULL(dt->pinctrl_info.gpio_state_active)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + return -EINVAL; + } + + dt->pinctrl_info.gpio_state_suspend = + pinctrl_lookup_state(dt->pinctrl_info.pinctrl, + CAM_RES_MGR_SLEEP); + if (IS_ERR_OR_NULL(dt->pinctrl_info.gpio_state_suspend)) { + CAM_ERR(CAM_RES, + "Failed to get the active state pinctrl handle"); + return -EINVAL; + } + + devm_pinctrl_put(dt->pinctrl_info.pinctrl); + + return rc; +} + +static int cam_res_mgr_probe(struct platform_device *pdev) +{ + int rc = 0; + + cam_res = kzalloc(sizeof(*cam_res), GFP_KERNEL); + if (!cam_res) + return -ENOMEM; + + cam_res->dev = &pdev->dev; + mutex_init(&cam_res->flash_res_lock); + mutex_init(&cam_res->gpio_res_lock); + mutex_init(&cam_res->clk_res_lock); + + rc = cam_res_mgr_parse_dt(&pdev->dev); + if (rc) { + CAM_INFO(CAM_RES, "Disable shared gpio support."); + cam_res->shared_gpio_enabled = false; + } else { + CAM_INFO(CAM_RES, "Enable shared gpio support."); + cam_res->shared_gpio_enabled = true; + } + + cam_res->shared_clk_ref_count = 0; + cam_res->pstatus = PINCTRL_STATUS_PUT; + + INIT_LIST_HEAD(&cam_res->gpio_res_list); + INIT_LIST_HEAD(&cam_res->flash_res_list); + + return 0; +} + +static int cam_res_mgr_remove(struct platform_device *pdev) +{ + if (cam_res) { + cam_res_mgr_free_res(); + kfree(cam_res); + cam_res = NULL; + } + + return 0; +} + +static const struct of_device_id cam_res_mgr_dt_match[] = { + {.compatible = "qcom,cam-res-mgr"}, + {} +}; +MODULE_DEVICE_TABLE(of, cam_res_mgr_dt_match); + +static struct platform_driver cam_res_mgr_driver = { + .probe = cam_res_mgr_probe, + .remove = cam_res_mgr_remove, + .driver = { + .name = "cam_res_mgr", + .owner = THIS_MODULE, + .of_match_table = cam_res_mgr_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_res_mgr_init(void) +{ + return platform_driver_register(&cam_res_mgr_driver); +} + +static void __exit cam_res_mgr_exit(void) +{ + platform_driver_unregister(&cam_res_mgr_driver); +} + +module_init(cam_res_mgr_init); +module_exit(cam_res_mgr_exit); +MODULE_DESCRIPTION("Camera resource manager driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h new file mode 100644 index 0000000000000000000000000000000000000000..e259ba7f2c7893d20fb8718933bc4ba1f297233d --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_RES_MGR_API_H__ +#define __CAM_RES_MGR_API_H__ + +#include <linux/leds.h> + +/** + * @brief: Register the led trigger + * + * The newly registered led trigger is assigned to flash_res_list. + * + * @name : Pointer to int led trigger name + * @tp : Save the returned led trigger + * + * @return None + */ +void cam_res_mgr_led_trigger_register(const char *name, + struct led_trigger **tp); + +/** + * @brief: Unregister the led trigger + * + * Free the flash_res if this led trigger isn't used by other device . + * + * @tp : Pointer to the led trigger + * + * @return None + */ +void cam_res_mgr_led_trigger_unregister(struct led_trigger *tp); + +/** + * @brief: Trigger the event to led core + * + * @trig : Pointer to the led trigger + * @brightness : The brightness need to fire + * + * @return None + */ +void cam_res_mgr_led_trigger_event(struct led_trigger *trig, + enum led_brightness brightness); + +/** + * @brief: Get the corresponding pinctrl of dev + * + * Init the shared pinctrl if shared pinctrl enabled. + * + * @return None + */ +int cam_res_mgr_shared_pinctrl_init(void); + +/** + * @brief: Put the pinctrl + * + * Put the shared pinctrl. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +void cam_res_mgr_shared_pinctrl_put(void); + +/** + * @brief: Select the corresponding state + * + * Active state can be selected directly, but need hold to suspend the + * pinctrl if the gpios in this pinctrl also held by other pinctrl. + * + * @active : The flag to indicate whether active or suspend + * the shared pinctrl. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_res_mgr_shared_pinctrl_select_state(bool active); + +/** + * @brief: Post init shared pinctrl + * + * Post init to check if the device really has shared gpio, + * suspend and put the pinctrl if not use shared gpio. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_res_mgr_shared_pinctrl_post_init(void); + +/** + * @brief: Request a gpio + * + * Will alloc a gpio_res for the new gpio, other find the corresponding + * gpio_res. + * + * @dev : Pointer to the device + * @gpio : The GPIO number + * @flags : GPIO configuration as specified by GPIOF_* + * @label : A literal description string of this GPIO + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_res_mgr_gpio_request(struct device *dev, unsigned int gpio, + unsigned long flags, const char *label); + +/** + * @brief: Free a array GPIO + * + * Free the GPIOs and release corresponding gpio_res. + * + * @dev : Pointer to the device + * @gpio : Array of the GPIO number + * @num : The number of gpio + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +void cam_res_mgr_gpio_free_arry(struct device *dev, + const struct gpio *array, size_t num); + +/** + * @brief: Set GPIO power level + * + * Add ref count support for shared GPIOs. + * + * @gpio : The GPIO number + * @value : The power level need to setup + * + * @return Status of operation. Negative in case of error. Zero otherwise. + * -EINVAL will be returned if the gpio can't be found in gpio_res_list. + */ +int cam_res_mgr_gpio_set_value(unsigned int gpio, int value); + +/** + * @brief: Config the shared clk ref count + * + * Config the shared clk ref count.. + * + * @value : get or put the shared clk. + * + * @return None + */ +void cam_res_mgr_shared_clk_config(bool value); + +#endif /* __CAM_RES_MGR_API_H__ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h new file mode 100644 index 0000000000000000000000000000000000000000..48611f6fbd7ecbecdffc11b7230bb0b64d1fe99c --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_RES_MGR_PRIVATE_H__ +#define __CAM_RES_MGR_PRIVATE_H__ + +#include <linux/list.h> +#include <linux/leds.h> +#include "cam_soc_util.h" + +#define MAX_SHARED_GPIO_SIZE 16 + +/* pinctrl states name */ +#define CAM_RES_MGR_SLEEP "cam_res_mgr_suspend" +#define CAM_RES_MGR_DEFAULT "cam_res_mgr_default" + +/** + * enum pinctrl_status - Enum for pinctrl status + */ +enum pinctrl_status { + PINCTRL_STATUS_GOT = 0, + PINCTRL_STATUS_ACTIVE, + PINCTRL_STATUS_SUSPEND, + PINCTRL_STATUS_PUT, +}; + +/** + * struct cam_dev_res + * + * @list : List member used to append this node to a dev list + * @dev : Device pointer associated with device + */ +struct cam_dev_res { + struct list_head list; + struct device *dev; +}; + +/** + * struct cam_gpio_res + * + * @list : List member used to append this node to a gpio list + * @dev_list : List the device which request this gpio + * @gpio : Gpio value + * @power_on_count : Record the power on times of this gpio + */ +struct cam_gpio_res { + struct list_head list; + struct list_head dev_list; + unsigned int gpio; + int power_on_count; +}; + +/** + * struct cam_pinctrl_res + * + * @list : List member used to append this node to a linked list + * @name : Pointer to the flash trigger's name. + * @trigger : Pointer to the flash trigger + */ +struct cam_flash_res { + struct list_head list; + const char *name; + struct led_trigger *trigger; +}; + +/** + * struct cam_res_mgr_dt + * + * @shared_gpio : Shared gpios list in the device tree + * @num_shared_gpio : The number of shared gpio + * @pinctrl_info : Pinctrl information + */ +struct cam_res_mgr_dt { + uint shared_gpio[MAX_SHARED_GPIO_SIZE]; + int num_shared_gpio; + struct cam_soc_pinctrl_info pinctrl_info; +}; + +/** + * struct cam_pinctrl_res + * + * @dev : Pointer to the device + * @dt : Device tree resource + * @shared_gpio_enabled : The flag to indicate if support shared gpio + * @pstatus : Shared pinctrl status + * @gpio_res_list : List head of the gpio resource + * @flash_res_list : List head of the flash resource + * @gpio_res_lock : GPIO resource lock + * @flash_res_lock : Flash resource lock + * @clk_res_lock : Clk resource lock + */ +struct cam_res_mgr { + struct device *dev; + struct cam_res_mgr_dt dt; + + bool shared_gpio_enabled; + enum pinctrl_status pstatus; + + uint shared_clk_ref_count; + + struct list_head gpio_res_list; + struct list_head flash_res_list; + struct mutex gpio_res_lock; + struct mutex flash_res_lock; + struct mutex clk_res_lock; +}; + +#endif /* __CAM_RES_MGR_PRIVATE_H__ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h new file mode 100755 index 0000000000000000000000000000000000000000..5dec8e3c76312b84ecfdb97b656040433e2363e3 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h @@ -0,0 +1,4475 @@ +.imx586_setting0 = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0111, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3702, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3706, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3707, .reg_data = 0x6F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C00, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C01, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C02, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C03, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C04, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C05, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C07, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C08, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C09, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0E, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0F, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F86, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F89, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D14, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D29, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D45, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D49, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D53, .reg_data = 0xB1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D55, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D5C, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D71, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D7B, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D8D, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D91, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D99, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D9B, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D9D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DA4, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DB9, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DD5, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DD9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DE3, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DEC, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E01, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E1D, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E2B, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E2D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E34, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E49, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E65, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E69, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E73, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E75, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E81, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E85, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E87, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E95, .reg_data = 0xBF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E97, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5282, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5715, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5717, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5729, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x572B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x572D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x572F, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x57BF, .reg_data = 0x5C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5855, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5857, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x585B, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x585F, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5861, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5863, .reg_data = 0x9E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x586F, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C49, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C4A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C4B, .reg_data = 0x9C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D0A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D0B, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D28, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D29, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D4A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D4B, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D68, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D69, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x646F, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6607, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6630, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6659, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6682, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x66AB, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x66D4, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x66FD, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6726, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x674F, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6778, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C1C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C1D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C1E, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C1F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C5C, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C5D, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C5E, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C60, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C61, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C63, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C64, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C65, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C66, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C67, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C68, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C6A, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C6B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C6C, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C6D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C6E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C6F, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C71, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C72, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C73, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C74, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C76, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C77, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C79, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C7A, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C7B, .reg_data = 0x8E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C7D, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C7E, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C80, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C81, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C82, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C83, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C84, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C85, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C87, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C88, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C89, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C8A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C8B, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C8C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C8E, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C8F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C90, .reg_data = 0xA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C91, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C92, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C94, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C96, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C97, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C98, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C99, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C9A, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C9B, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C9C, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C9D, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C9E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6C9F, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA0, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA1, .reg_data = 0xE5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA2, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA4, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA5, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA6, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA8, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CA9, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CAB, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CAC, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CAD, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CAE, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CAF, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB0, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB1, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB2, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB4, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB5, .reg_data = 0x8A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB6, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB7, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CB8, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CBA, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CBB, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CBC, .reg_data = 0xE2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CBD, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CBE, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CBF, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC2, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC3, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC4, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC5, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC6, .reg_data = 0x96, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CC9, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CCA, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CCB, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CCC, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CCD, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CCE, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD0, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD1, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD2, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD4, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD5, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD6, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD7, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD8, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CD9, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CDA, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CDB, .reg_data = 0xE5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CDC, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CDE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CDF, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE0, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE1, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE2, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE3, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE5, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE6, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE7, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE8, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CE9, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CEA, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CEB, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CED, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CEE, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CEF, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF0, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF1, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF2, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF4, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF5, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF6, .reg_data = 0xE2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF7, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF8, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CF9, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6CFB, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6E47, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F29, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F2A, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7100, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7101, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7102, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7103, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7104, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7106, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7107, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7108, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7109, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710A, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710B, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710C, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710F, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7110, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7111, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7112, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7113, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7114, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7115, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7116, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7117, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7118, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7119, .reg_data = 0xE5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711C, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711D, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711E, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7120, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7121, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7123, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7124, .reg_data = 0xA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7125, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7126, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7127, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7128, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7129, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712B, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712C, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712F, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7130, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7132, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7133, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7134, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7135, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7136, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7137, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7139, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713A, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 300, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, + +}, + +.imx586_setting1 = +{ + .reg_setting = + { + {.reg_addr = 0x713B, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713C, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713D, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713E, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7140, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7141, .reg_data = 0xA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7142, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7143, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7144, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7145, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7146, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7148, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7149, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714C, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714E, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714F, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7150, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7151, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7152, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7153, .reg_data = 0xE5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7154, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7156, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7157, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7158, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7159, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715B, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715D, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715E, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715F, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7160, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7161, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7162, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7163, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7165, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7166, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7167, .reg_data = 0x8E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7168, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7169, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716A, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716C, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716D, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716E, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716F, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7170, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7171, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7173, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7174, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7175, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7176, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7177, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7178, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7180, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7189, .reg_data = 0xA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71C4, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71C9, .reg_data = 0xC9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71CB, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71CD, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71CE, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71D0, .reg_data = 0xC9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71D2, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71D4, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71D5, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71D7, .reg_data = 0xC9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71D9, .reg_data = 0xE2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71DA, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71E7, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71EC, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x895C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x895D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8962, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8967, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x896B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x896F, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8976, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8977, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9004, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9200, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9201, .reg_data = 0xA7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9202, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9203, .reg_data = 0xAA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9204, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9205, .reg_data = 0xAD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9206, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9207, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9208, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9209, .reg_data = 0xB3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920A, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920B, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920C, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920D, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920E, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920F, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9210, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9211, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9212, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9213, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9214, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9215, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9216, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9217, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9218, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9219, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921A, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921B, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921C, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921D, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921E, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921F, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9222, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9223, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9224, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9225, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9226, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9227, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9385, .reg_data = 0xE6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9387, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9389, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938B, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938D, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938F, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9391, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9393, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9395, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9397, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9399, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939B, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939D, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939F, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A1, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A3, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A5, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A7, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A9, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93AB, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93AD, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93AF, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B1, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B3, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B5, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B7, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B9, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93BB, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93BD, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93BF, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C1, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C3, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C5, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C7, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C9, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93CB, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93CD, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93CF, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93D1, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93D3, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93D5, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93D7, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93D9, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93DB, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93DD, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93DF, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93E1, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93E3, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93E5, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93E7, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9810, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9814, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99B2, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99B3, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99B4, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99B5, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99B6, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99E4, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99E5, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99E6, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99E7, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99E8, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99E9, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99EA, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99EB, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99EC, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99ED, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC76, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC77, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC79, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC7B, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC7C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC7D, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC7F, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC020, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC027, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC13C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC140, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC141, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC142, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC143, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC145, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC146, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC149, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC448, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC44B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC44C, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC44D, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC44F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC451, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC452, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC455, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC61D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC625, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC638, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC63B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE286, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE2A6, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE2C6, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xEC00, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0x6F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0220, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0222, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0901, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3140, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3246, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3247, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0401, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0404, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0405, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0409, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040C, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0301, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3620, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3621, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C11, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C12, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C13, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F0C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F80, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F81, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8D, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FF8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FF9, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFF, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0xCC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0224, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0225, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE1, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0216, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0217, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0218, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0219, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0210, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0211, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0212, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0213, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0214, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0215, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE3, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 308, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, + +}, + +.streamoff = +{ + .reg_setting = + { + {.reg_addr = 0x0100, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.s5k3m5_setting = +{ + .reg_setting = + { + {.reg_addr = 0x6028, .reg_data = 0x4000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0000, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0000, .reg_data = 0x30D5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6214, .reg_data = 0x7971, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6218, .reg_data = 0x7150, .delay = 0x03, .data_mask = 0x00}, + {.reg_addr = 0x0A02, .reg_data = 0x7800, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6028, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x3EAC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0549, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0448, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x054A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC1F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC804, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x101A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA1F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xCC04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1BB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4210, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2E50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x10B5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4FF9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9949, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0120, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0880, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x10BD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2DE9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF041, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x974C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x954F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0026, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB4F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6A52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3888, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x08B1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA4F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6A62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x43F9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3E80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA4F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6A52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xBDE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF081, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2DE9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF041, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0746, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8C48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0E46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4068, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x84B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x050C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2146, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2846, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x36F9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3146, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3846, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x37F9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x874F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4DF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0C26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4FF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8061, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3A78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3046, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x29F9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7878, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB8B3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8021, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3046, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x22F9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8048, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0088, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x804B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5C02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7E48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x001D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0088, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5E02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5C02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5E12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4218, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x02D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8002, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB0FB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF2F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x91B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x784A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6012, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB2F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1602, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB2F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1422, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9805, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9A25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8018, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x04D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9202, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB2FB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF0F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9C05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9C05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0A18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x01FB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x40F3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9510, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1028, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x06DC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0028, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x05DA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x03E0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xFFE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0122, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC5E7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6849, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0880, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2146, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2846, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xBDE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF041, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0122, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xE2B8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF0B5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x644C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xDDE9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0565, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x08B1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2788, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0760, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x09B1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6088, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0860, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x12B1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA088, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x401C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1060, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0BB1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xE088, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1860, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0EB1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA07B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3060, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x002D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x01D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xE07B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2860, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF0BD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x70B5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0646, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5048, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8068, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x84B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x050C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2146, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2846, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xBEF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3046, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC5F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5248, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0368, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7401, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x010A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5048, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4268, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5010, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7511, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5210, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7811, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x090A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5810, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7911, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5A10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x33F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF01F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0068, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x090A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xCE1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5978, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8170, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5988, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x090A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0171, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xD978, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8171, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x988C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9074, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2500, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1075, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xD88C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9075, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2700, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1076, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB3F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7E00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2F48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x90F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB313, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8210, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x90F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB103, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8400, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xB400, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8600, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8800, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6211, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9610, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0112, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9E10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0212, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA010, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA200, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA400, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0512, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA610, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0612, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA810, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0712, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAA10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAC00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x5A20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAD00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x93F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0902, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAE00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2146, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2846, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xBDE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0122, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x47B8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x10B5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0F4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2080, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAFF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3321, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1748, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0161, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAFF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2D21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x8161, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAFF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1121, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1448, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x45F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAFF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2911, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6060, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1148, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3EF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xAFF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6B11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA060, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0F48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x37F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xE060, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x10BD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4200, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2E50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x41D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x9404, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x38E0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xD000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xA410, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2C66, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0890, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3620, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0840, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x020D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x67CD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3AE1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x45F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x250C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC0F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6047, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x45F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xF31C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC0F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6047, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4AF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xD74C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC0F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6047, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x40F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0D2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC0F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x010C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6047, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x46F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xCD7C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC0F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6047, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x4AF6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xE75C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0xC0F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x6047, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x30D5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x00FC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x41D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x1662, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x1E00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x1C9A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x0FF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x0EF6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x23B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x0FE4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0107, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x07D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x12F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x3D09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x0E18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x1066, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x13DE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x12F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0F0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x13DC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x806F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xF46E, .reg_data = 0x00C3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xF46C, .reg_data = 0xBFA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xF44A, .reg_data = 0x0007, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xF456, .reg_data = 0x000A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6028, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x12F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x7008, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0BC6, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B36, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6214, .reg_data = 0x7971, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6218, .reg_data = 0x7150, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x0008, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x1077, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x0C37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x1070, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x0C30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x0CF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x12DC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x0011, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0380, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0382, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0384, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0386, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0402, .reg_data = 0x1010, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0404, .reg_data = 0x1000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0350, .reg_data = 0x0008, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0352, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0136, .reg_data = 0x1333, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013E, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0300, .reg_data = 0x0008, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0302, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0304, .reg_data = 0x0005, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x00FB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0308, .reg_data = 0x0008, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030A, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030C, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x0003, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x0071, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0312, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B06, .reg_data = 0x0101, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6028, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x1FF6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021E, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0D00, .reg_data = 0x0101, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0D02, .reg_data = 0x0101, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x0301, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0D06, .reg_data = 0x0208, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0D08, .reg_data = 0x0300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6028, .reg_data = 0x2000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x0F10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0003, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x0F12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0200, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x602A, .reg_data = 0x2BC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6F12, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B30, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B32, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B34, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 503, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .delay = 1, +}, + +.imx471_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x300A, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E35, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E36, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4431, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x531C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x531D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x531E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5928, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5929, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592B, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5930, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5931, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5932, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5933, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5938, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5939, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593B, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593D, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593F, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5940, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5941, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5942, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5943, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E12, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E13, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F06, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F07, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0B, .reg_data = 0xEB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0C, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0D, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0E, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F10, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F11, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F12, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F13, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F14, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F17, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F18, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F19, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1A, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1B, .reg_data = 0xC7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1C, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1D, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F20, .reg_data = 0xA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F21, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F22, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F23, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F24, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F25, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F26, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F27, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F28, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F29, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2A, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2B, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2C, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2D, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2E, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2F, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F30, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F31, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F32, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F33, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F34, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F35, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F36, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F37, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F38, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F39, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3A, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3B, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3C, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3D, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3E, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3F, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F40, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F41, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F42, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F43, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F44, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F45, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F46, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F47, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F48, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F49, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F4A, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F4B, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F75, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F76, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F77, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F78, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F79, .reg_data = 0xE5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7990, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7993, .reg_data = 0x5D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7994, .reg_data = 0x5D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7995, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x799A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x799D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8169, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8359, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9300, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9301, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9302, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9304, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9305, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9306, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9308, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9309, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930C, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930D, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930E, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9310, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9311, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9312, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9314, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9315, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9316, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9317, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB046, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB048, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0xA7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0381, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0383, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0385, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0387, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0901, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F4C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F4D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0409, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040C, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0301, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F78, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F79, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFF, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0A, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 198, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.gc5035_setting = +{ + .reg_setting = + { + {.reg_addr = 0xfc, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf5, .reg_data = 0xc1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf6, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf8, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf9, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfa, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x36, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd3, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x36, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01, .reg_data = 0xe7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xee, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x87, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06, .reg_data = 0xda, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9d, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x09, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0b, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0c, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0d, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0e, .reg_data = 0xa8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0f, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x10, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x11, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x17, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x19, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x30, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x31, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd9, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1b, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x28, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x44, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4b, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4e, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x50, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x52, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x53, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x55, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc5, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x32, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x91, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x95, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x96, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd5, .reg_data = 0xfc, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x16, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1a, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1f, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x46, .reg_data = 0xe3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x54, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x72, .reg_data = 0xcf, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x73, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7a, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7d, .reg_data = 0xcc, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x90, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xce, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd0, .reg_data = 0xb2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd2, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe6, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x12, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x13, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0xfc, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb0, .reg_data = 0x6e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x53, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x89, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x60, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x42, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x49, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4b, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x55, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x41, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4c, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4d, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4e, .reg_data = 0x3c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x44, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x48, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x91, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x94, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x95, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x96, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x98, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03, .reg_data = 0xb7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x18, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x24, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x25, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x26, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2a, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3e, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf5, .reg_data = 0xc1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf6, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf8, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf9, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfa, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x36, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd3, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x36, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01, .reg_data = 0xe7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xee, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x87, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06, .reg_data = 0xda, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9d, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x09, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0b, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0c, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0d, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0e, .reg_data = 0xa8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0f, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x10, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd9, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x44, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4e, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x91, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x95, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x96, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd5, .reg_data = 0xfc, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1f, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xce, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd0, .reg_data = 0xb2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x49, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4b, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4e, .reg_data = 0x3c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x44, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x91, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x94, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x95, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x96, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x98, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x26, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3e, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 249, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, + +}, + + +.imx481_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x531C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x531D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x531E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5928, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5929, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592B, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x592F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5930, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5931, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5932, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5933, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5938, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5939, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593B, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593D, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x593F, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5940, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5941, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5942, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5943, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E12, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E13, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F06, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F07, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0B, .reg_data = 0xEB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0C, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0D, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0E, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F10, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F11, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F12, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F13, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F14, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F17, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F18, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F19, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1A, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1B, .reg_data = 0xC7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1C, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1D, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F20, .reg_data = 0xA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F21, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F22, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F23, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F24, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F25, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F26, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F27, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F28, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F29, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2A, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2B, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2C, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2D, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2E, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2F, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F30, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F31, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F32, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F33, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F34, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F35, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F36, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F37, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F38, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F39, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3A, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3B, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3C, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3D, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3E, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3F, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F40, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F41, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F42, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F43, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F44, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F45, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F46, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F47, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F48, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F49, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F4A, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F4B, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F75, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F76, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F77, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F78, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F79, .reg_data = 0xE5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7990, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7993, .reg_data = 0x5D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7994, .reg_data = 0x5D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7995, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x799A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x799D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8169, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8359, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x88C7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x88D4, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9300, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9301, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9302, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9304, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9305, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9306, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9308, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9309, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930C, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930D, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x930E, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9310, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9311, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9312, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9314, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9315, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9316, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9317, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9960, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9963, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9964, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA391, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB046, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB048, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0xA7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0381, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0383, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0385, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0387, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0901, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F4C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F4D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0409, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040C, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0301, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0xAB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E20, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E37, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F78, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F79, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFF, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F0A, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA828, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA829, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA84F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA850, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB2DF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB2E5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 206, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.imx689_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33F0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33F1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0111, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3078, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3079, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x307A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x307B, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3A20, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x459F, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x45ED, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x461C, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D01, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D0F, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D1A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D1B, .reg_data = 0xB3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D82, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D97, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4D99, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DBB, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DBD, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DDF, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4DE1, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E19, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E1B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E3D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E3F, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E77, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E79, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4E9D, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4EB7, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4F45, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BB7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D08, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D09, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D1D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D20, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D23, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D24, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D28, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D2B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D40, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D5A, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D5B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5D71, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6565, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6568, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x656B, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x656F, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6570, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6574, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6577, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x657A, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6581, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6584, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6587, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x658B, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x658C, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6590, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6593, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6596, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6767, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6769, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x676B, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x676C, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x676D, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x676E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x676F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6770, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6771, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6791, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6794, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6796, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6797, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6798, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x679C, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x679F, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67B1, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67B2, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67B3, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67CC, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67CD, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67CE, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67D7, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67D8, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67DB, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67DE, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67E8, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67E9, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67EA, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67EB, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67EE, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67F1, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67F5, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67F8, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67FE, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67FF, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6800, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6801, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6804, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6807, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6808, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6809, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x680A, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x680B, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6814, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6815, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6817, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6818, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x681E, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x681F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6820, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6821, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x682D, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6833, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6837, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6839, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x683B, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6843, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6849, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6861, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6863, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6867, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6869, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x686D, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x686F, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6871, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6873, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6875, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6877, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6879, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x687D, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x687F, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6883, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6885, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x688B, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x688D, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6891, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6893, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6897, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68A1, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68A7, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68AB, .reg_data = 0x96, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68AD, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68AF, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68B7, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68BD, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68C1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68C3, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68C9, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68CF, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68D3, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68D9, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68DB, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68DF, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68E1, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68E7, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68E9, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68EB, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68ED, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68EF, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68F1, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68F3, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68F5, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68F7, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68F9, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6901, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6917, .reg_data = 0x96, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x691B, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x691D, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6923, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6929, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x692B, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x692D, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x692F, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6931, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6933, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6945, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6947, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x694B, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x694D, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6957, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6959, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x696B, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x696D, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6971, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6973, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69AD, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69B3, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69B7, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69B9, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69BB, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69C3, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69C9, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69E1, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69E3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69E7, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69E9, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69ED, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69EF, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69F1, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69F3, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69F5, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69F7, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69F9, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69FD, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69FF, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A03, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A05, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A0B, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A0D, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A11, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A13, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A17, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A21, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A27, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A2B, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A2D, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A2F, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A37, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A3D, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A41, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A43, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A49, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A4F, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A53, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A59, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A5B, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A5F, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A61, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A67, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A69, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A6B, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A6D, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A6F, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A71, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A73, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A75, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A77, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A79, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A81, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A97, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A9B, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6A9D, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AA3, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AA9, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AAB, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AAD, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AAF, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AB1, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AB3, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AC5, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AC7, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6ACB, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6ACD, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AD7, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AD9, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AEB, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AED, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AF1, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6AF3, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B2B, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B2D, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B2F, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B31, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B33, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B39, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B41, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B45, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B47, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B49, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B4B, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B4D, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B4F, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B53, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B57, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B59, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B5F, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B61, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B63, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B65, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B67, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B6D, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B6F, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B77, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B79, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B7B, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B7F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B81, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B83, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B85, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B87, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B8D, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B95, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B99, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6B9F, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6BA1, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6BAF, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6BB1, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6BC3, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6BC5, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7021, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7045, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7069, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x708D, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E2, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E3, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E4, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E5, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E6, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E7, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70E8, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70EE, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70EF, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F0, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F1, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F2, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F3, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F4, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F5, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F6, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F7, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70F8, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70FD, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70FE, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x70FF, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7100, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7106, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7107, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7108, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7109, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x710C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7112, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7113, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7114, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7115, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7116, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7117, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7118, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7119, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x711C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7121, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7122, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7123, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7124, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712A, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712D, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x712F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7130, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7136, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7137, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7138, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7139, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713D, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x713F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7140, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7145, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7146, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7147, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7148, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714E, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x714F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7150, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7151, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7152, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7153, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7154, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715A, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715B, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715C, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715D, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x715F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7160, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7161, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7162, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7163, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7164, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7169, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x716C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7172, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7173, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7174, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7175, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7178, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7179, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717A, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717D, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x717F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7180, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7181, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7186, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7187, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x718A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x718B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x718C, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x718D, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7190, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7191, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7192, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7193, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7194, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7195, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7196, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7197, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7198, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7199, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x719E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x719F, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71A2, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71A3, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71A4, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71A5, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71A8, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71A9, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71AA, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x71AB, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7754, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7755, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7756, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7757, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7758, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x775A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x775B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x775C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x775D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x775E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x775F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7760, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7761, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7764, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7765, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7768, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7769, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9004, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9200, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9201, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9202, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9203, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9204, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9205, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9206, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9207, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9208, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9209, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920A, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920B, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920C, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920D, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920E, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920F, .reg_data = 0xBE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9210, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9211, .reg_data = 0xBF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9212, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9213, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9214, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9215, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9216, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9217, .reg_data = 0xCA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9218, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9219, .reg_data = 0xCB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921A, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921B, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921C, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921D, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0x6F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0220, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0221, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0222, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0901, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3005, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x30D8, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x30E0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3200, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3201, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x350C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0401, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0404, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0405, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0409, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040C, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0301, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x30E1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x32D5, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x32D6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BF6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BF7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BF8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BF9, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BFA, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BFC, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BFD, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C01, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C02, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C03, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C21, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C23, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C24, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C26, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C27, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C2C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C2D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC006, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC007, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0224, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0225, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3116, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3117, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0216, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0217, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0218, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0219, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3118, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3119, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x311A, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x311B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x309B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 579, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.gc2375_setting = +{ + .reg_setting = + { + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf8, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf9, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfa, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x88, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06, .reg_data = 0x5a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x07, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x08, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x09, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0b, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0c, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0d, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0e, .reg_data = 0xb8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0f, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x10, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x17, .reg_data = 0xd4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1c, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1d, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20, .reg_data = 0x0b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x6d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x25, .reg_data = 0xc1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x26, .reg_data = 0x0e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x27, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x5f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2f, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x38, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3d, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xcd, .reg_data = 0xa3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xce, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd0, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd1, .reg_data = 0xca, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd2, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd3, .reg_data = 0xbb, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd8, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe0, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe1, .reg_data = 0x1f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe4, .reg_data = 0xf8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe5, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe6, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe7, .reg_data = 0xcc, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe8, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe9, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xea, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xeb, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x90, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x94, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x95, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x96, .reg_data = 0xb0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x98, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x18, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1a, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x28, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3f, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x40, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x41, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x43, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4e, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4f, .reg_data = 0x3c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x66, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x67, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb0, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xef, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x11, .reg_data = 0x2b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x12, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x13, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x24, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x25, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x26, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2a, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x86, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06, .reg_data = 0x5a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x07, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x08, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xef, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 112, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, + +}, + +.hi846_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0066, .reg_data = 0x0101, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2000, .reg_data = 0x98E8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2002, .reg_data = 0x00FF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2004, .reg_data = 0x0006, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2008, .reg_data = 0x3FFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x200A, .reg_data = 0xC314, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2022, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2034, .reg_data = 0x1292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2036, .reg_data = 0xC02E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2038, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x206E, .reg_data = 0xF0B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2070, .reg_data = 0xFFBF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2072, .reg_data = 0x2004, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2074, .reg_data = 0x43C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2076, .reg_data = 0x82FA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2078, .reg_data = 0x12B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x207A, .reg_data = 0xCAB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x207C, .reg_data = 0x42A2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x207E, .reg_data = 0x7324, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2080, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2082, .reg_data = 0x120B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2084, .reg_data = 0x425B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2086, .reg_data = 0x008C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2088, .reg_data = 0x4292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x208A, .reg_data = 0x7300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x208C, .reg_data = 0x82F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x208E, .reg_data = 0x4292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2090, .reg_data = 0x7302, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2092, .reg_data = 0x82F4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2094, .reg_data = 0x1292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2096, .reg_data = 0xC006, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2098, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x209A, .reg_data = 0x0710, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x209C, .reg_data = 0x523F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x209E, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20A0, .reg_data = 0x82E4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20A2, .reg_data = 0x93C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20A4, .reg_data = 0x829F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20A6, .reg_data = 0x241E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20A8, .reg_data = 0x403E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20AA, .reg_data = 0xFFFE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20AC, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20AE, .reg_data = 0xEC78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20B0, .reg_data = 0x82EC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20B2, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20B4, .reg_data = 0xEC78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20B6, .reg_data = 0x82EE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20B8, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20BA, .reg_data = 0xEC78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20BC, .reg_data = 0x82F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20BE, .reg_data = 0x934B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20C0, .reg_data = 0x2405, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20C2, .reg_data = 0x4E0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20C4, .reg_data = 0x503F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20C6, .reg_data = 0xFFD8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20C8, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20CA, .reg_data = 0x82EC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20CC, .reg_data = 0x907B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20CE, .reg_data = 0x0003, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20D0, .reg_data = 0x200B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20D2, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20D4, .reg_data = 0x82EC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20D6, .reg_data = 0x5E0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20D8, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20DA, .reg_data = 0x82EE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20DC, .reg_data = 0x5E0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20DE, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20E0, .reg_data = 0x82F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20E2, .reg_data = 0x3C02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20E4, .reg_data = 0x432E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20E6, .reg_data = 0x3FE2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20E8, .reg_data = 0x413B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20EA, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20EC, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20EE, .reg_data = 0x7100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20F0, .reg_data = 0x4F0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20F2, .reg_data = 0x503E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20F4, .reg_data = 0xFFD8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20F6, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20F8, .reg_data = 0x7A04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20FA, .reg_data = 0x421E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20FC, .reg_data = 0x82EC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20FE, .reg_data = 0x5F0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2100, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2102, .reg_data = 0x7A06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2104, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2106, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2108, .reg_data = 0x0050, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x210A, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x210C, .reg_data = 0xD081, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x210E, .reg_data = 0x0B88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2110, .reg_data = 0x421E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2112, .reg_data = 0x82EE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2114, .reg_data = 0x5F0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2116, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2118, .reg_data = 0x7A0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x211A, .reg_data = 0x521F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x211C, .reg_data = 0x82F0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x211E, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2120, .reg_data = 0x7A10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2122, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2124, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2126, .reg_data = 0x007A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2128, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x212A, .reg_data = 0x0081, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x212C, .reg_data = 0x0B88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x212E, .reg_data = 0x4392, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2130, .reg_data = 0x7A0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2132, .reg_data = 0x0800, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2134, .reg_data = 0x7A0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2136, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2138, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x213A, .reg_data = 0x022B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x213C, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x213E, .reg_data = 0xD081, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2140, .reg_data = 0x0B88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2142, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2144, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2146, .reg_data = 0x0255, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2148, .reg_data = 0x40B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x214A, .reg_data = 0x0081, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x214C, .reg_data = 0x0B88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x214E, .reg_data = 0x9382, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2150, .reg_data = 0x7112, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2152, .reg_data = 0x2402, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2154, .reg_data = 0x4392, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2156, .reg_data = 0x760E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2158, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x215A, .reg_data = 0x120B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x215C, .reg_data = 0x120A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x215E, .reg_data = 0x4E0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2160, .reg_data = 0x4F0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2162, .reg_data = 0x4C0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2164, .reg_data = 0x4D0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2166, .reg_data = 0x8A0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2168, .reg_data = 0x7B0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x216A, .reg_data = 0x2C02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x216C, .reg_data = 0x4A0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x216E, .reg_data = 0x4B0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2170, .reg_data = 0x4C0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2172, .reg_data = 0x4D0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2174, .reg_data = 0x413A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2176, .reg_data = 0x413B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2178, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x217A, .reg_data = 0x120B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x217C, .reg_data = 0x120A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x217E, .reg_data = 0x1209, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2180, .reg_data = 0x1208, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2182, .reg_data = 0x1207, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2184, .reg_data = 0x1206, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2186, .reg_data = 0x1205, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2188, .reg_data = 0x42D2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x218A, .reg_data = 0x82FA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x218C, .reg_data = 0x82A0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x218E, .reg_data = 0x403B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2190, .reg_data = 0x00C1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2192, .reg_data = 0x4B6F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2194, .reg_data = 0x4FC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2196, .reg_data = 0x82D4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2198, .reg_data = 0x43C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x219A, .reg_data = 0x82D5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x219C, .reg_data = 0x1292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x219E, .reg_data = 0xC046, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21A0, .reg_data = 0x4292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21A2, .reg_data = 0x7560, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21A4, .reg_data = 0x82F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21A6, .reg_data = 0x4292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21A8, .reg_data = 0x7562, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21AA, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21AC, .reg_data = 0x93CB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21AE, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21B0, .reg_data = 0x2452, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21B2, .reg_data = 0x4215, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21B4, .reg_data = 0x7316, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21B6, .reg_data = 0x4216, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21B8, .reg_data = 0x7318, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21BA, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21BC, .reg_data = 0x0710, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21BE, .reg_data = 0x4F0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21C0, .reg_data = 0x430F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21C2, .reg_data = 0x4507, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21C4, .reg_data = 0x4608, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21C6, .reg_data = 0x8E07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21C8, .reg_data = 0x7F08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21CA, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21CC, .reg_data = 0x82E2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21CE, .reg_data = 0x522F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21D0, .reg_data = 0x4F09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21D2, .reg_data = 0x430A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21D4, .reg_data = 0x470D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21D6, .reg_data = 0x480E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21D8, .reg_data = 0x490B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21DA, .reg_data = 0x4A0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21DC, .reg_data = 0x870B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21DE, .reg_data = 0x780C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21E0, .reg_data = 0x2C02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21E2, .reg_data = 0x490D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21E4, .reg_data = 0x4A0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21E6, .reg_data = 0x4D0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21E8, .reg_data = 0x43D2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21EA, .reg_data = 0x01B3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21EC, .reg_data = 0x4D82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21EE, .reg_data = 0x7324, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21F0, .reg_data = 0x4292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21F2, .reg_data = 0x7540, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21F4, .reg_data = 0x82E8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21F6, .reg_data = 0x4292, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21F8, .reg_data = 0x7542, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21FA, .reg_data = 0x82EA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21FC, .reg_data = 0x434B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21FE, .reg_data = 0x823F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2200, .reg_data = 0x4F0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2202, .reg_data = 0x430D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2204, .reg_data = 0x421E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2206, .reg_data = 0x82E8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2208, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x220A, .reg_data = 0x82EA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x220C, .reg_data = 0x5E0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x220E, .reg_data = 0x6F0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2210, .reg_data = 0x870C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2212, .reg_data = 0x780D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2214, .reg_data = 0x2801, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2216, .reg_data = 0x435B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2218, .reg_data = 0x4BC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x221A, .reg_data = 0x82FA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x221C, .reg_data = 0x93C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x221E, .reg_data = 0x829A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2220, .reg_data = 0x201A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2222, .reg_data = 0x93C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2224, .reg_data = 0x82A0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2226, .reg_data = 0x2404, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2228, .reg_data = 0x43B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x222A, .reg_data = 0x7540, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x222C, .reg_data = 0x43B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x222E, .reg_data = 0x7542, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2230, .reg_data = 0x93C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2232, .reg_data = 0x82FA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2234, .reg_data = 0x2410, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2236, .reg_data = 0x503E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2238, .reg_data = 0x0003, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x223A, .reg_data = 0x630F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x223C, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x223E, .reg_data = 0x82E8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2240, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2242, .reg_data = 0x82EA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2244, .reg_data = 0x450C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2246, .reg_data = 0x460D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2248, .reg_data = 0x8E0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x224A, .reg_data = 0x7F0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x224C, .reg_data = 0x2C04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x224E, .reg_data = 0x4582, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2250, .reg_data = 0x82E8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2252, .reg_data = 0x4682, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2254, .reg_data = 0x82EA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2256, .reg_data = 0x4135, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2258, .reg_data = 0x4136, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x225A, .reg_data = 0x4137, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x225C, .reg_data = 0x4138, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x225E, .reg_data = 0x4139, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2260, .reg_data = 0x413A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2262, .reg_data = 0x413B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2264, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2266, .reg_data = 0x403E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2268, .reg_data = 0x00C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x226A, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x226C, .reg_data = 0x7314, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x226E, .reg_data = 0xF07F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2270, .reg_data = 0x000C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2272, .reg_data = 0x5F4F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2274, .reg_data = 0x5F4F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2276, .reg_data = 0xDFCE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2278, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x227A, .reg_data = 0xF0FE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x227C, .reg_data = 0x000F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x227E, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2280, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2282, .reg_data = 0x120B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2284, .reg_data = 0x120A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2286, .reg_data = 0x1209, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2288, .reg_data = 0x1208, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x228A, .reg_data = 0x1207, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x228C, .reg_data = 0x1206, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x228E, .reg_data = 0x93C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2290, .reg_data = 0x00C1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2292, .reg_data = 0x249F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2294, .reg_data = 0x425E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2296, .reg_data = 0x00C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2298, .reg_data = 0xC35E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x229A, .reg_data = 0x425F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x229C, .reg_data = 0x82A0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x229E, .reg_data = 0xDF4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22A0, .reg_data = 0x4EC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22A2, .reg_data = 0x00C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22A4, .reg_data = 0x934F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22A6, .reg_data = 0x248F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22A8, .reg_data = 0x4217, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22AA, .reg_data = 0x7316, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22AC, .reg_data = 0x4218, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22AE, .reg_data = 0x7318, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22B0, .reg_data = 0x4326, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22B2, .reg_data = 0xB3E2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22B4, .reg_data = 0x00C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22B6, .reg_data = 0x2482, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22B8, .reg_data = 0x0900, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22BA, .reg_data = 0x731C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22BC, .reg_data = 0x0800, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22BE, .reg_data = 0x731C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22C0, .reg_data = 0x421A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22C2, .reg_data = 0x7300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22C4, .reg_data = 0x421B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22C6, .reg_data = 0x7302, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22C8, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22CA, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22CC, .reg_data = 0x9F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22CE, .reg_data = 0x829C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22D0, .reg_data = 0x2C02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22D2, .reg_data = 0x531A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22D4, .reg_data = 0x630B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22D6, .reg_data = 0x4A0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22D8, .reg_data = 0x4B0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22DA, .reg_data = 0x821E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22DC, .reg_data = 0x82F2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22DE, .reg_data = 0x721F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22E0, .reg_data = 0x82F4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22E2, .reg_data = 0x2C68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22E4, .reg_data = 0x4A09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22E6, .reg_data = 0x9339, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22E8, .reg_data = 0x3460, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22EA, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22EC, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22EE, .reg_data = 0x0320, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22F0, .reg_data = 0x421E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22F2, .reg_data = 0x7300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22F4, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22F6, .reg_data = 0x7302, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22F8, .reg_data = 0x531E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22FA, .reg_data = 0x630F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22FC, .reg_data = 0x4E0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22FE, .reg_data = 0x4F0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2300, .reg_data = 0x821C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2302, .reg_data = 0x82F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2304, .reg_data = 0x721D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2306, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2308, .reg_data = 0x2C0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x230A, .reg_data = 0x93B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x230C, .reg_data = 0x7560, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x230E, .reg_data = 0x2003, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2310, .reg_data = 0x93B2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2312, .reg_data = 0x7562, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2314, .reg_data = 0x2408, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2316, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2318, .reg_data = 0x7540, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x231A, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x231C, .reg_data = 0x7542, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x231E, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2320, .reg_data = 0x82F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2322, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2324, .reg_data = 0x82F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2326, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2328, .reg_data = 0x7316, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x232A, .reg_data = 0x12B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x232C, .reg_data = 0xFE66, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x232E, .reg_data = 0x0900, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2330, .reg_data = 0x730E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2332, .reg_data = 0x403F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2334, .reg_data = 0x7316, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2336, .reg_data = 0x4A09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2338, .reg_data = 0x8F29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x233A, .reg_data = 0x478F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x233C, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x233E, .reg_data = 0x460C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2340, .reg_data = 0x430D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2342, .reg_data = 0x421E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2344, .reg_data = 0x7300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2346, .reg_data = 0x421F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2348, .reg_data = 0x7302, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x234A, .reg_data = 0x9C0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x234C, .reg_data = 0x23F8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x234E, .reg_data = 0x9D0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2350, .reg_data = 0x23F6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2352, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2354, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2356, .reg_data = 0x01F4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2358, .reg_data = 0x5036, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x235A, .reg_data = 0x0006, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x235C, .reg_data = 0x460C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x235E, .reg_data = 0x430D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2360, .reg_data = 0x490E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2362, .reg_data = 0x4E0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2364, .reg_data = 0x5F0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2366, .reg_data = 0x7F0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2368, .reg_data = 0xE33F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x236A, .reg_data = 0x521E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x236C, .reg_data = 0x82E8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x236E, .reg_data = 0x621F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2370, .reg_data = 0x82EA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2372, .reg_data = 0x12B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2374, .reg_data = 0xFD5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2376, .reg_data = 0x4E82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2378, .reg_data = 0x7540, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x237A, .reg_data = 0x4F82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x237C, .reg_data = 0x7542, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x237E, .reg_data = 0x403B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2380, .reg_data = 0x7316, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2382, .reg_data = 0x421C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2384, .reg_data = 0x82E4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2386, .reg_data = 0x430D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2388, .reg_data = 0x4B2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x238A, .reg_data = 0x590F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x238C, .reg_data = 0x4F0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x238E, .reg_data = 0x430F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2390, .reg_data = 0x12B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2392, .reg_data = 0xFD5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2394, .reg_data = 0x4E8B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2396, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2398, .reg_data = 0x4BA2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x239A, .reg_data = 0x82CE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x239C, .reg_data = 0x4382, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x239E, .reg_data = 0x82D0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23A0, .reg_data = 0x12B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23A2, .reg_data = 0xFE66, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23A4, .reg_data = 0xD3D2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23A6, .reg_data = 0x00C2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23A8, .reg_data = 0x3C16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23AA, .reg_data = 0x9329, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23AC, .reg_data = 0x3BC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23AE, .reg_data = 0x4906, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23B0, .reg_data = 0x5326, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23B2, .reg_data = 0x3FC5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23B4, .reg_data = 0x4A09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23B6, .reg_data = 0x8219, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23B8, .reg_data = 0x82CE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23BA, .reg_data = 0x3F95, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23BC, .reg_data = 0x0800, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23BE, .reg_data = 0x731C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23C0, .reg_data = 0x0900, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23C2, .reg_data = 0x731C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23C4, .reg_data = 0x3F7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23C6, .reg_data = 0x0900, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23C8, .reg_data = 0x730C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23CA, .reg_data = 0x0B00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23CC, .reg_data = 0x7304, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23CE, .reg_data = 0x01F4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23D0, .reg_data = 0x3FE9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23D2, .reg_data = 0x0900, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23D4, .reg_data = 0x732C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23D6, .reg_data = 0x425F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23D8, .reg_data = 0x0788, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23DA, .reg_data = 0x4136, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23DC, .reg_data = 0x4137, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23DE, .reg_data = 0x4138, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23E0, .reg_data = 0x4139, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23E2, .reg_data = 0x413A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23E4, .reg_data = 0x413B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23E6, .reg_data = 0x4130, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23FE, .reg_data = 0xC056, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3236, .reg_data = 0xFC22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x323A, .reg_data = 0xFCEC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x323C, .reg_data = 0xFC82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x323E, .reg_data = 0xFD7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3246, .reg_data = 0xFE82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3248, .reg_data = 0xFC34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x324E, .reg_data = 0xFC6E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x326A, .reg_data = 0xC374, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x326C, .reg_data = 0xC37C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x326E, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3270, .reg_data = 0xC378, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x32E2, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A00, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0E04, .reg_data = 0x0012, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002E, .reg_data = 0x1111, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0032, .reg_data = 0x1111, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0022, .reg_data = 0x0008, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0026, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0028, .reg_data = 0x0017, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002C, .reg_data = 0x09CF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005C, .reg_data = 0x2101, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0006, .reg_data = 0x0AC3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0008, .reg_data = 0x0ED8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000E, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000C, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A22, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A24, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0804, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A12, .reg_data = 0x0CC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A14, .reg_data = 0x0990, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0710, .reg_data = 0x09B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0074, .reg_data = 0x0ABD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0076, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051E, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0200, .reg_data = 0x0400, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A1A, .reg_data = 0x0C00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A0C, .reg_data = 0x0010, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A1E, .reg_data = 0x0CCF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0402, .reg_data = 0x0110, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0404, .reg_data = 0x00F4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0410, .reg_data = 0x008D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0412, .reg_data = 0x011A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0414, .reg_data = 0x864C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021C, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0C00, .reg_data = 0x9950, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0C06, .reg_data = 0x0021, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0C10, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0C12, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0C14, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0C16, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A02, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A04, .reg_data = 0x014A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0418, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0128, .reg_data = 0x0028, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012A, .reg_data = 0xFFFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0120, .reg_data = 0x0046, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0122, .reg_data = 0x0376, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012C, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012E, .reg_data = 0xFFFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0124, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0126, .reg_data = 0x0378, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0746, .reg_data = 0x0050, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0748, .reg_data = 0x01D5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x074A, .reg_data = 0x022B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x074C, .reg_data = 0x03B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0756, .reg_data = 0x043F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0758, .reg_data = 0x3F1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B02, .reg_data = 0xE04D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B10, .reg_data = 0x6821, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B12, .reg_data = 0x0120, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B14, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2008, .reg_data = 0x38FD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x326E, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x0300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0xC319, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0914, .reg_data = 0xC109, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0916, .reg_data = 0x061A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0918, .reg_data = 0x0407, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x091A, .reg_data = 0x0A0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x091C, .reg_data = 0x0E08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x091E, .reg_data = 0x0A00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x090C, .reg_data = 0x0427, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x090E, .reg_data = 0x0059, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0954, .reg_data = 0x0089, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0956, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0958, .reg_data = 0xCA80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x095A, .reg_data = 0x9240, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0040, .reg_data = 0x0200, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0042, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0D04, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F08, .reg_data = 0x2F04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F30, .reg_data = 0x001F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F36, .reg_data = 0x001F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F04, .reg_data = 0x3A00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F32, .reg_data = 0x0396, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F38, .reg_data = 0x0396, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F2A, .reg_data = 0x4124, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006A, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004C, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0044, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002E, .reg_data = 0x1111, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0032, .reg_data = 0x1111, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0026, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002C, .reg_data = 0x09CF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005C, .reg_data = 0x2101, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0006, .reg_data = 0x09DE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0008, .reg_data = 0x0ED8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000C, .reg_data = 0x0022, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A22, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A24, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0804, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A12, .reg_data = 0x0CC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A14, .reg_data = 0x0990, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0074, .reg_data = 0x09D8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021C, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A04, .reg_data = 0x014A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0418, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0128, .reg_data = 0x0028, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012A, .reg_data = 0xFFFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0120, .reg_data = 0x0046, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0122, .reg_data = 0x0376, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012C, .reg_data = 0x0020, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012E, .reg_data = 0xFFFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0124, .reg_data = 0x0040, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0126, .reg_data = 0x0378, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B02, .reg_data = 0xE04D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B10, .reg_data = 0x6821, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B12, .reg_data = 0x0120, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B14, .reg_data = 0x0001, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2008, .reg_data = 0x38FD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x326E, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0710, .reg_data = 0x09B0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x0300, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0xC319, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0914, .reg_data = 0xC109, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0916, .reg_data = 0x061A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0918, .reg_data = 0x0407, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x091A, .reg_data = 0x0A0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x091C, .reg_data = 0x0E08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x091E, .reg_data = 0x0A00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x090C, .reg_data = 0x0427, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x090E, .reg_data = 0x0059, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0954, .reg_data = 0x0089, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0956, .reg_data = 0x0000, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0958, .reg_data = 0xCA80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x095A, .reg_data = 0x9240, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F32, .reg_data = 0x0396, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F38, .reg_data = 0x0396, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0F2A, .reg_data = 0x4124, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004C, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0A00, .reg_data = 0x0100, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 608, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .delay = 1, +}, + +.imx616_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0111, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C00, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C01, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C02, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C03, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C04, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C05, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C07, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C08, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C09, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0D, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0E, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0F, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C10, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C11, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C16, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C18, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C19, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C1A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C1B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C1C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C1D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C1E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F89, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x53B9, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62C4, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x658F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6590, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6591, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6592, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6593, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6594, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6595, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6596, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6597, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6598, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6599, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x659A, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x659B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x659C, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x659D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x659E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x659F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A4, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A6, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A8, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65A9, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65AA, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65AB, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65AC, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65AD, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65AE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65AF, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B0, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B2, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B4, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B5, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B7, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B8, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65B9, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65BA, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65BB, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65BC, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65BD, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65BE, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65BF, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65C0, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65C1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65C2, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65C3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65C4, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x65C5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6E1C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6E1D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6E25, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6E38, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x895C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x895D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8966, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8967, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x896A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x896B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x896F, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8976, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8977, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9004, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9200, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9201, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9202, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9203, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9204, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9205, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9206, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9207, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9208, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9209, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920A, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920B, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920C, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920D, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920E, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920F, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9210, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9211, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9212, .reg_data = 0xB7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9213, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9214, .reg_data = 0xF6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9215, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9216, .reg_data = 0xF6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9217, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9218, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9219, .reg_data = 0xA7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921A, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921B, .reg_data = 0xAA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921C, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921D, .reg_data = 0xAD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921E, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x921F, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9220, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9221, .reg_data = 0xB3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9222, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9223, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9224, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9225, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9226, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9227, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9228, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9229, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x922A, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x922B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x922C, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x922D, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x922E, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x922F, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9230, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9231, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9232, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9233, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9234, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9235, .reg_data = 0x6B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9236, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9237, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9238, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9239, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x923A, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x923B, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x923C, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x923D, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9810, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9814, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC020, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC026, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC027, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC448, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC44F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC450, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC451, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC452, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xC455, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE206, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE226, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE266, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE2A6, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE2C6, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE2E6, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x88D6, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9852, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA569, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA56A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA56B, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA56C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA678, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA679, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA812, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA813, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA814, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA830, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA831, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA832, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA833, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA834, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA835, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA837, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA838, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA854, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA855, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA856, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA857, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA85A, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA85B, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA85C, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xA85D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA55, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA56, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA57, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA58, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA59, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC72, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC73, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC74, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC75, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC76, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC77, .reg_data = 0xC4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE09, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE0A, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE12, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE13, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE15, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE16, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAF05, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB069, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xEA4B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xEA4C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xEA4D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xEA4E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x9F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0220, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0222, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0900, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0901, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0902, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3140, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3246, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3247, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0401, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0404, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0405, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0409, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040C, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0301, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0xE1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3620, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3621, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C12, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C13, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C14, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F0C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F80, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F81, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F8D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFD, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FFF, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0224, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0225, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE1, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0216, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0217, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0218, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0219, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0210, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0211, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0212, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0213, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0214, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0215, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE3, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E20, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 327, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.gc8054_setting = +{ + .reg_setting = + { + {.reg_addr = 0x031c, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0320, .reg_data = 0xbb, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0337, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0335, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0336, .reg_data = 0x8c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031a, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0321, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0327, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0325, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0326, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0314, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0315, .reg_data = 0xe9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0317, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0115, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0180, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0334, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0324, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x9f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0288, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0084, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0265, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04e0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0101, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034a, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034b, .reg_data = 0x9c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0257, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0290, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0291, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0292, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0295, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0213, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02a9, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0221, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028b, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028c, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0229, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024b, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0255, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0280, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0500, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0501, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0502, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0211, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0216, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0219, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021f, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0224, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0234, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0220, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024a, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0281, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0282, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028d, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028f, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0390, .reg_data = 0x6f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0392, .reg_data = 0x5c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0394, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039a, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0506, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0514, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0515, .reg_data = 0x1c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x9f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x9f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0360, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0360, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0317, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a67, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a54, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a65, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a68, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a59, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00be, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00a9, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00d7, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00d8, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009c, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009d, .reg_data = 0x9c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009e, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009f, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a82, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a83, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a84, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a85, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a88, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a89, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a8a, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a71, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a72, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a73, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a75, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a70, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0313, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0080, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0087, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0089, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0096, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0040, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0041, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0043, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0044, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0046, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0048, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0049, .reg_data = 0xf0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004a, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004c, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004d, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0414, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0415, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0416, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0417, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009a, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00c0, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00c1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00c2, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0470, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0471, .reg_data = 0x1c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0472, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0473, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0474, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0475, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0476, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0477, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0480, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0481, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0482, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0483, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0484, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0485, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0486, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0487, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0478, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0479, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047a, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047b, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047c, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047d, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047e, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047f, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0488, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0489, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048b, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048c, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048d, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048e, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048f, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0320, .reg_data = 0xbb, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0337, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0335, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0336, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031a, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0321, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0327, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0325, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0326, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0314, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0315, .reg_data = 0xe4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0317, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0115, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0180, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0334, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0324, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x9f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xf2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0xd0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034a, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034b, .reg_data = 0x9c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0291, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0292, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0213, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02a9, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0221, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028b, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028c, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0229, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024b, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0255, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0280, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021f, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0224, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0234, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0282, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028d, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039a, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x9f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03fe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031c, .reg_data = 0x9f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00d3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00d4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00d5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00d6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05a0, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05a3, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05a4, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0597, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059a, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059b, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059c, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05ab, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05ae, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05af, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05ac, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05ad, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x1c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x1c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0xd9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0xf8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x9e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0xf0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x0b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x3d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0xc6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05b1, .reg_data = 0x6d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05ac, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029f, .reg_data = 0xc4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05a0, .reg_data = 0xc3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02b0, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0206, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02b3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02b4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0099, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0352, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0353, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0354, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034c, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034d, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034e, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034f, .reg_data = 0xc8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0108, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0181, .reg_data = 0xf0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0185, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0188, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0121, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0122, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0123, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0124, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0125, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0126, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0129, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012a, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012b, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a70, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0313, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0aff, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a70, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00be, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0317, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a67, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0084, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0102, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 374, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.ov02b10_setting = +{ + .reg_setting = + { + {.reg_addr = 0xfd, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x24, .reg_data = 0x3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x25, .reg_data = 0x0c, .delay = 0x03, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2a, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1e, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33, .reg_data = 0x7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x35, .reg_data = 0x7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3a, .reg_data = 0x5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3b, .reg_data = 0x2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3e, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x46, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6d, .reg_data = 0x3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0e, .reg_data = 0x2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0f, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x18, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23, .reg_data = 0x2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x17, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x19, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1b, .reg_data = 0x6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1c, .reg_data = 0x4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x20, .reg_data = 0x3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x30, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x31, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x32, .reg_data = 0x9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x38, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x39, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3a, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3b, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4f, .reg_data = 0x4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4e, .reg_data = 0x5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x50, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x35, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x45, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x46, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x47, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x48, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4b, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4c, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4d, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x56, .reg_data = 0x3a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x57, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x58, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x59, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5a, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x42, .reg_data = 0x0e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x68, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x69, .reg_data = 0xcd, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6a, .reg_data = 0x8f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7c, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7d, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7e, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7f, .reg_data = 0x8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x83, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x84, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x86, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x87, .reg_data = 0x7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x88, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x94, .reg_data = 0x2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x98, .reg_data = 0xd1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x6c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x98, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x99, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9a, .reg_data = 0x6c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xa1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xaf, .reg_data = 0x4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xae, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x88, .reg_data = 0x5b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x89, .reg_data = 0x7c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb4, .reg_data = 0x5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8e, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x90, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9b, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xac, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5a, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x74, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x50, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x52, .reg_data = 0xb0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x07, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x09, .reg_data = 0xb0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x14, .reg_data = 0x0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc2, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfb, .reg_data = 0x1, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 106, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.ov8856_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0103, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0302, .reg_data = 0x4b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030b, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030d, .reg_data = 0x4b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031e, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3000, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x300e, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3010, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3015, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3018, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3021, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3033, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3500, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3501, .reg_data = 0x9a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3502, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3503, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3505, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3508, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3509, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x350c, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x350d, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x350e, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x350f, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3510, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3511, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3512, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3600, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3601, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3602, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3610, .reg_data = 0xc5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3611, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3612, .reg_data = 0x5c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3613, .reg_data = 0xca, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3614, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3628, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3629, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x362a, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3633, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3634, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3635, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3636, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3663, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3669, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x366e, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3706, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x370b, .reg_data = 0x7e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3714, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3730, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3733, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3764, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3765, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3769, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x376a, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x376b, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3780, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3781, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3782, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3783, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3798, .reg_data = 0x2f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37a1, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37a8, .reg_data = 0x6a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37ab, .reg_data = 0x3f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37c2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37c3, .reg_data = 0xf1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37c9, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37cb, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37cc, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37cd, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37ce, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3800, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3801, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3802, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3803, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3804, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3805, .reg_data = 0xdf, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3806, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3807, .reg_data = 0xa3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3808, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3809, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380a, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380b, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380c, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380d, .reg_data = 0x8c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380e, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380f, .reg_data = 0xb2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3810, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3811, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3812, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3813, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3814, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3815, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3816, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3817, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3818, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3819, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3820, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3821, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x382a, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x382b, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3830, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3836, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3862, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3863, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3cc0, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3d85, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3d8c, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3d8d, .reg_data = 0xde, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4001, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4003, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4008, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4009, .reg_data = 0x0b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x400a, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x400b, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x400f, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4010, .reg_data = 0xf0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4011, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4012, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4013, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4014, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4015, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4042, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4043, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4044, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4045, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4046, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4047, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4048, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4049, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4041, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x404c, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x404d, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x404e, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4203, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4307, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4317, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4503, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4601, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4800, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4816, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x481b, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x481f, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4837, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x483c, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x484b, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5000, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5001, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5004, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x502e, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5030, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5795, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5796, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5797, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5798, .reg_data = 0xd5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5799, .reg_data = 0xd5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579a, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579b, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579c, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579d, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579e, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579f, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x57a0, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x57a1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5780, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5781, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5782, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5783, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5784, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5785, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5786, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5787, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5788, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5789, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578a, .reg_data = 0xfd, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578b, .reg_data = 0xf5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578c, .reg_data = 0xf5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578d, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578e, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x578f, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5790, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5791, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5792, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5793, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5794, .reg_data = 0xa3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x59f8, .reg_data = 0x3d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5a08, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b00, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b01, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b02, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b03, .reg_data = 0xcf, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b05, .reg_data = 0x6c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0302, .reg_data = 0x4b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3501, .reg_data = 0x9a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3502, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x366e, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3714, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x37c2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3800, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3801, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3802, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3803, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3804, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3805, .reg_data = 0xdf, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3806, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3807, .reg_data = 0xa3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3808, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3809, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380a, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380b, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380e, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x380f, .reg_data = 0xb2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3811, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3813, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3814, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3820, .reg_data = 0xc6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3821, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x382a, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4009, .reg_data = 0x0b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4837, .reg_data = 0x0b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x502e, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5001, .reg_data = 0x0e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5004, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x376b, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5795, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5796, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5797, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5798, .reg_data = 0xd5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5799, .reg_data = 0xd5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579b, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579d, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579e, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x579f, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x57a0, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x57a1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 237, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, + +.gc02m1b_setting = +{ + .reg_setting = + { + {.reg_addr = 0xfc, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf4, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf5, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf6, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf8, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf9, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfa, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfd, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01, .reg_data = 0x0b, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xf7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x87, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xee, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x90, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04, .reg_data = 0x7d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x41, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x42, .reg_data = 0xf4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x07, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x08, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9d, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x09, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0a, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0d, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0e, .reg_data = 0xbc, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x17, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x19, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x24, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x56, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5b, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5e, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x3c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x44, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xcc, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1a, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1f, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x27, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x33, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x53, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe6, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x39, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x43, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x46, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7c, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd0, .reg_data = 0xbe, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd1, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd2, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd3, .reg_data = 0xf3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xde, .reg_data = 0x1d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xcd, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xce, .reg_data = 0x6f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfc, .reg_data = 0x8e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xe0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x53, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x87, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x89, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb0, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb1, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xb6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xd8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x2a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x1a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x2c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xc0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xe0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x3c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0xa0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xc0, .reg_data = 0x5c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9f, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x26, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x40, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x46, .reg_data = 0x7f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x49, .reg_data = 0x0f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4a, .reg_data = 0xf0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x14, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x16, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x17, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x41, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4c, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4d, .reg_data = 0x0c, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x44, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x48, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x90, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x91, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x92, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x94, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x95, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x96, .reg_data = 0xb0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x97, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x98, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03, .reg_data = 0xce, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x21, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x22, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x23, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x25, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x26, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x29, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2a, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x2b, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8c, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xfe, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3e, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 200, + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, \ No newline at end of file diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_sensor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d3a6fbb6c3e42bc6da9d813c76c6705144dc3df9 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c new file mode 100755 index 0000000000000000000000000000000000000000..58953caa6536f8c3642abaf448c3caa26dea5be0 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -0,0 +1,1577 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <cam_sensor_cmn_header.h> +#include "cam_sensor_core.h" +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" +#ifdef CONFIG_OEM_BOOT_MODE +#include <linux/oem/boot_mode.h> +#endif +#ifdef CONFIG_PROJECT_INFO +#include <linux/oem/project_info.h> +#endif + +struct camera_vendor_match_tbl { + uint16_t sensor_id; + char sensor_name[32]; + char vendor_name[32]; +}; + +static struct camera_vendor_match_tbl match_tbl[] = { + {0x586, "imx586", "Sony" }, + {0x30d5, "s5k3m5", "Samsung" }, + {0x5035, "gc5035", "Galaxyc" }, + {0x471, "imx471", "Sony" }, + {0x481, "imx481", "Sony" }, + {0x2375, "gc2375", "Galaxyc" }, + {0x689, "imx689", "Sony" }, + {0x0616, "imx616", "Sony" }, + {0x4608, "hi846", "Hynix" }, + {0x8054, "gc8054", "Galaxyc" }, + {0x2b, "ov02b10","OmniVision" }, + {0x88, "ov8856", "OmniVision" }, + {0x02, "gc02m1b", "Galaxyc" }, +}; + + + +static void cam_sensor_update_req_mgr( + struct cam_sensor_ctrl_t *s_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = s_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + CAM_DBG(CAM_SENSOR, " Rxed Req Id: %lld", + csl_packet->header.request_id); + add_req.dev_hdl = s_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + if (s_ctrl->bridge_intf.crm_cb && + s_ctrl->bridge_intf.crm_cb->add_req) + s_ctrl->bridge_intf.crm_cb->add_req(&add_req); + + CAM_DBG(CAM_SENSOR, " add req to req mgr: %lld", + add_req.req_id); +} + +static void cam_sensor_release_stream_rsc( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int rc; + + i2c_set = &(s_ctrl->i2c_data.streamoff_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting Streamoff settings"); + } + + i2c_set = &(s_ctrl->i2c_data.streamon_settings); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed while deleting Streamon settings"); + } +} + +static void cam_sensor_release_per_frame_resource( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int i, rc; + + if (s_ctrl->i2c_data.per_frame != NULL) { + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(s_ctrl->i2c_data.per_frame[i]); + if (i2c_set->is_settings_valid == 1) { + i2c_set->is_settings_valid = -1; + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + } + } + } +} + +static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, + void *arg) +{ + int32_t rc = 0; + uintptr_t generic_ptr; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct i2c_settings_array *i2c_reg_settings = NULL; + size_t len_of_buff = 0; + size_t remain_len = 0; + uint32_t *offset = NULL; + struct cam_config_dev_cmd config; + struct i2c_data_settings *i2c_data = NULL; + + ioctl_ctrl = (struct cam_control *)arg; + + if (ioctl_ctrl->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid Handle Type"); + return -EINVAL; + } + + if (copy_from_user(&config, + u64_to_user_ptr(ioctl_ctrl->handle), + sizeof(config))) + return -EFAULT; + + rc = cam_mem_get_cpu_buf( + config.packet_handle, + &generic_ptr, + &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed in getting the packet: %d", rc); + return rc; + } + + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_SENSOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto end; + } + + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *)(generic_ptr + + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_SENSOR, "Invalid packet params"); + rc = -EINVAL; + goto end; + + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG && + csl_packet->header.request_id <= s_ctrl->last_flush_req + && s_ctrl->last_flush_req != 0) { + CAM_ERR(CAM_SENSOR, + "reject request %lld, last request to flush %u", + csl_packet->header.request_id, s_ctrl->last_flush_req); + rc = -EINVAL; + goto end; + } + + if (csl_packet->header.request_id > s_ctrl->last_flush_req) + s_ctrl->last_flush_req = 0; + + i2c_data = &(s_ctrl->i2c_data); + CAM_DBG(CAM_SENSOR, "Header OpCode: %d", csl_packet->header.op_code); + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { + i2c_reg_settings = &i2c_data->init_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { + i2c_reg_settings = &i2c_data->config_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { + if (s_ctrl->streamon_count > 0) + goto end; + + s_ctrl->streamon_count = s_ctrl->streamon_count + 1; + i2c_reg_settings = &i2c_data->streamon_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { + if (s_ctrl->streamoff_count > 0) + goto end; + + s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1; + i2c_reg_settings = &i2c_data->streamoff_settings; + i2c_reg_settings->request_id = 0; + i2c_reg_settings->is_settings_valid = 1; + break; + } + + case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { + CAM_WARN(CAM_SENSOR, + "Rxed Update packets without linking"); + goto end; + } + + i2c_reg_settings = + &i2c_data->per_frame[csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY]; + CAM_DBG(CAM_SENSOR, "Received Packet: %lld req: %lld", + csl_packet->header.request_id % MAX_PER_FRAME_ARRAY, + csl_packet->header.request_id); + if (i2c_reg_settings->is_settings_valid == 1) { + CAM_ERR(CAM_SENSOR, + "Already some pkt in offset req : %lld", + csl_packet->header.request_id); + /* + * Update req mgr even in case of failure. + * This will help not to wait indefinitely + * and freeze. If this log is triggered then + * fix it. + */ + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + goto end; + } + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { + CAM_WARN(CAM_SENSOR, + "Rxed NOP packets without linking"); + goto end; + } + + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + goto end; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Packet Header"); + rc = -EINVAL; + goto end; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += csl_packet->cmd_buf_offset / 4; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + + rc = cam_sensor_i2c_command_parser(&s_ctrl->io_master_info, + i2c_reg_settings, cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); + goto end; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) == + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE) { + i2c_reg_settings->request_id = + csl_packet->header.request_id; + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + } + +end: + return rc; +} + +static int32_t cam_sensor_i2c_modes_util( + struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list) +{ + int32_t rc = 0; + uint32_t i, size; + + if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to random write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 0); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to seq write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_BURST) { + rc = camera_io_dev_write_continuous( + io_master_info, + &(i2c_list->i2c_settings), + 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to burst write I2C settings: %d", + rc); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + io_master_info, + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "i2c poll apply setting Fail: %d", rc); + return rc; + } + } + } + + return rc; +} + +int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info, + struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_cci_client *cci_client = NULL; + + if (s_ctrl->io_master_info.master_type == CCI_MASTER) { + cci_client = s_ctrl->io_master_info.cci_client; + if (!cci_client) { + CAM_ERR(CAM_SENSOR, "failed: cci_client %pK", + cci_client); + return -EINVAL; + } + cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; + cci_client->sid = i2c_info->slave_addr >> 1; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + CAM_DBG(CAM_SENSOR, " Master: %d sid: %d freq_mode: %d", + cci_client->cci_i2c_master, i2c_info->slave_addr, + i2c_info->i2c_freq_mode); + } + + s_ctrl->sensordata->slave_info.sensor_slave_addr = + i2c_info->slave_addr; + return rc; +} + +int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, + struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + + s_ctrl->sensordata->slave_info.sensor_id_reg_addr = + probe_info->reg_addr; + s_ctrl->sensordata->slave_info.sensor_id = + probe_info->expected_data; + s_ctrl->sensordata->slave_info.sensor_id_mask = + probe_info->data_mask; + /* Userspace passes the pipeline delay in reserved field */ + s_ctrl->pipeline_delay = + probe_info->reserved; + s_ctrl->sensordata->slave_info.addr_type = + probe_info->addr_type; + s_ctrl->sensordata->slave_info.data_type = + probe_info->data_type; + + s_ctrl->sensor_probe_addr_type = probe_info->addr_type; + s_ctrl->sensor_probe_data_type = probe_info->data_type; + CAM_DBG(CAM_SENSOR, + "Sensor Addr: 0x%x Sensor Addr Type: 0x%x Sensor Data Type: 0x%x sensor_id: 0x%x sensor_mask: 0x%x sensor_pipeline_delay:0x%x", + s_ctrl->sensordata->slave_info.sensor_id_reg_addr, + s_ctrl->sensordata->slave_info.addr_type, + s_ctrl->sensordata->slave_info.data_type, + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_id_mask, + s_ctrl->pipeline_delay); + return rc; +} + +int32_t cam_sensor_update_id_info(struct cam_cmd_probe *probe_info, + struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + + s_ctrl->sensordata->id_info.sensor_slave_addr = + probe_info->reserved; + s_ctrl->sensordata->id_info.sensor_id_reg_addr = + probe_info->reg_addr; + s_ctrl->sensordata->id_info.sensor_id_mask = + probe_info->data_mask; + s_ctrl->sensordata->id_info.sensor_id = + probe_info->expected_data; + s_ctrl->sensordata->id_info.sensor_addr_type = + probe_info->addr_type; + s_ctrl->sensordata->id_info.sensor_data_type = + probe_info->data_type; + + CAM_ERR(CAM_SENSOR, + "vendor_slave_addr: 0x%x, vendor_id_Addr: 0x%x, vendorID: 0x%x, vendor_mask: 0x%x", + s_ctrl->sensordata->id_info.sensor_slave_addr, + s_ctrl->sensordata->id_info.sensor_id_reg_addr, + s_ctrl->sensordata->id_info.sensor_id, + s_ctrl->sensordata->id_info.sensor_id_mask); + return rc; +} + +int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, + struct cam_sensor_ctrl_t *s_ctrl, + int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) +{ + int32_t rc = 0; + + switch (cmd_buf_num) { + case 0: { + struct cam_cmd_i2c_info *i2c_info = NULL; + struct cam_cmd_probe *probe_info; + + if (remain_len < + (sizeof(struct cam_cmd_i2c_info) + + sizeof(struct cam_cmd_probe))) { + CAM_ERR(CAM_SENSOR, + "not enough buffer for cam_cmd_i2c_info"); + return -EINVAL; + } + i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed in Updating the i2c Info"); + return rc; + } + probe_info = (struct cam_cmd_probe *) + (cmd_buf + sizeof(struct cam_cmd_i2c_info)); + rc = cam_sensor_update_slave_info(probe_info, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Updating the slave Info"); + return rc; + } + + probe_info = (struct cam_cmd_probe *) + (cmd_buf + sizeof(struct cam_cmd_i2c_info) + sizeof(struct cam_cmd_probe)); + rc = cam_sensor_update_id_info(probe_info, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Updating the id Info"); + return rc; + } + cmd_buf = probe_info; + } + break; + case 1: { + rc = cam_sensor_update_power_settings(cmd_buf, + cmd_buf_length, &s_ctrl->sensordata->power_info, + remain_len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in updating power settings"); + return rc; + } + } + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid command buffer"); + break; + } + return rc; +} + +int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0, i; + uint32_t *cmd_buf; + void *ptr; + size_t len; + struct cam_packet *pkt = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cmd_buf1 = 0; + uintptr_t packet = 0; + size_t remain_len = 0; + + rc = cam_mem_get_cpu_buf(handle, + &packet, &len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); + return -EINVAL; + } + + pkt = (struct cam_packet *)packet; + if (pkt == NULL) { + CAM_ERR(CAM_SENSOR, "packet pos is invalid"); + rc = -EINVAL; + goto end; + } + + if ((len < sizeof(struct cam_packet)) || + (pkt->cmd_buf_offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_SENSOR, "Not enough buf provided"); + rc = -EINVAL; + goto end; + } + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4); + if (cmd_desc == NULL) { + CAM_ERR(CAM_SENSOR, "command descriptor pos is invalid"); + rc = -EINVAL; + goto end; + } + if (pkt->num_cmd_buf != 2) { + CAM_ERR(CAM_SENSOR, "Expected More Command Buffers : %d", + pkt->num_cmd_buf); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < pkt->num_cmd_buf; i++) { + if (!(cmd_desc[i].length)) + continue; + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &cmd_buf1, &len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to parse the command Buffer Header"); + goto end; + } + if (cmd_desc[i].offset >= len) { + CAM_ERR(CAM_SENSOR, + "offset past length of buffer"); + rc = -EINVAL; + goto end; + } + remain_len = len - cmd_desc[i].offset; + if (cmd_desc[i].length > remain_len) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided for cmd"); + rc = -EINVAL; + goto end; + } + cmd_buf = (uint32_t *)cmd_buf1; + cmd_buf += cmd_desc[i].offset/4; + ptr = (void *) cmd_buf; + + rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl, + i, cmd_desc[i].length, remain_len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to parse the command Buffer Header"); + goto end; + } + } + +end: + return rc; +} + +void cam_sensor_query_cap(struct cam_sensor_ctrl_t *s_ctrl, + struct cam_sensor_query_cap *query_cap) +{ + query_cap->pos_roll = s_ctrl->sensordata->pos_roll; + query_cap->pos_pitch = s_ctrl->sensordata->pos_pitch; + query_cap->pos_yaw = s_ctrl->sensordata->pos_yaw; + query_cap->secure_camera = 0; + query_cap->actuator_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_ACTUATOR]; + query_cap->csiphy_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]; + query_cap->eeprom_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_EEPROM]; + query_cap->flash_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_LED_FLASH]; + query_cap->ois_slot_id = + s_ctrl->sensordata->subdev_id[SUB_MODULE_OIS]; + query_cap->slot_info = + s_ctrl->soc_info.index; +} + +static uint16_t cam_sensor_id_by_mask(struct cam_sensor_ctrl_t *s_ctrl, + uint32_t chipid) +{ + uint16_t sensor_id = (uint16_t)(chipid & 0xFFFF); + int16_t sensor_id_mask = s_ctrl->sensordata->slave_info.sensor_id_mask; + + if (!sensor_id_mask) + sensor_id_mask = ~sensor_id_mask; + + sensor_id &= sensor_id_mask; + sensor_id_mask &= -sensor_id_mask; + sensor_id_mask -= 1; + while (sensor_id_mask) { + sensor_id_mask >>= 1; + sensor_id >>= 1; + } + return sensor_id; +} + +void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) +{ + struct cam_sensor_power_ctrl_t *power_info = + &s_ctrl->sensordata->power_info; + int rc = 0; + + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) && + (s_ctrl->is_probe_succeed == 0)) + return; + + cam_sensor_release_stream_rsc(s_ctrl); + cam_sensor_release_per_frame_resource(s_ctrl); + + if (s_ctrl->sensor_state != CAM_SENSOR_INIT) + cam_sensor_power_down(s_ctrl); + + if (s_ctrl->bridge_intf.device_hdl != -1) { + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "dhdl already destroyed: rc = %d", rc); + } + + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.session_hdl = -1; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 0; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + s_ctrl->sensor_state = CAM_SENSOR_INIT; +} + +int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint32_t chipid = 0; + uint32_t vendor_id = 0; + struct cam_camera_slave_info *slave_info; + int hb_id=0; + uint32_t slave_sid = 0; + uint32_t addr=0,data=0; + + struct cam_sensor_i2c_reg_array i2c_write_setting = { + .reg_addr = addr, + .reg_data = data, + .delay = 0x00, + .data_mask = 0x00, + }; + struct cam_sensor_i2c_reg_setting i2c_write = { + .reg_setting = &i2c_write_setting, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 0x00, + }; + + slave_info = &(s_ctrl->sensordata->slave_info); + +#ifdef CONFIG_OEM_BOOT_MODE + hb_id = get_hw_board_version(); +#endif + if (!slave_info) { + CAM_ERR(CAM_SENSOR, " failed: %pK", + slave_info); + return -EINVAL; + } + + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + slave_info->sensor_id_reg_addr, + &chipid,slave_info->addr_type, + slave_info->data_type); + + CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + + if (cam_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { + CAM_WARN(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + return -ENODEV; + } + + if(chipid==0x689){ + camera_io_dev_read( + &(s_ctrl->io_master_info), + s_ctrl->sensordata->id_info.sensor_id_reg_addr, + &vendor_id,s_ctrl->sensordata->id_info.sensor_addr_type, + CAMERA_SENSOR_I2C_TYPE_BYTE); + CAM_INFO(CAM_SENSOR, "read vendor_id_addr=0x%x vendor_id: 0x%x expected vendor_id 0x%x: rc=%d", + s_ctrl->sensordata->id_info.sensor_id_reg_addr,vendor_id, s_ctrl->sensordata->id_info.sensor_id,rc); + if((vendor_id>>4)==1) + strcpy(match_tbl[6].sensor_name,"imx689_MP"); + if((vendor_id>>4) != s_ctrl->sensordata->id_info.sensor_id ) + return -1; + } + if((chipid==0x2375||chipid==0x5035)&&(s_ctrl->sensordata->id_info.sensor_slave_addr!=0)){ + CAM_INFO(CAM_SENSOR, "id_info.sensor_slave_addr=%d hb_id=%d",s_ctrl->sensordata->id_info.sensor_slave_addr,hb_id); + if(((s_ctrl->sensordata->id_info.sensor_slave_addr>11)&&(hb_id>11))|| + ((s_ctrl->sensordata->id_info.sensor_slave_addr==11)&&(hb_id==11))) + return rc; + else + return -1; + } + + if(chipid == 0x586){ + if(s_ctrl->sensordata->id_info.sensor_id_reg_addr != 0){ + slave_sid = s_ctrl->io_master_info.cci_client->sid; + s_ctrl->io_master_info.cci_client->sid = (s_ctrl->sensordata->id_info.sensor_slave_addr>>1); + camera_io_dev_read( + &(s_ctrl->io_master_info), + s_ctrl->sensordata->id_info.sensor_id_reg_addr, + &vendor_id,CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + s_ctrl->io_master_info.cci_client->sid = slave_sid; + CAM_INFO(CAM_SENSOR, "read vendor_id_addr=0x%x vendor_id: 0x%x expected vendor_id 0x%x: rc=%d", + s_ctrl->sensordata->id_info.sensor_id_reg_addr,vendor_id, s_ctrl->sensordata->id_info.sensor_id,rc); + if((vendor_id>>4) == 1) + strcpy(match_tbl[0].sensor_name,"imx586_BG"); + if((vendor_id>>4) != s_ctrl->sensordata->id_info.sensor_id) + return -1; + } + } + + if(chipid == 0x481){ + if(s_ctrl->sensordata->id_info.sensor_id_reg_addr != 0){ + i2c_write_setting.reg_addr = 0x0A02; + i2c_write_setting.reg_data = 0x1B; + rc=camera_io_dev_write(&(s_ctrl->io_master_info), &i2c_write); + if(rc<0) { + CAM_ERR(CAM_SENSOR, "imx481 write otp failed"); + return rc; + } + i2c_write_setting.reg_addr = 0x0A00; + i2c_write_setting.reg_data = 0x01; + rc=camera_io_dev_write(&(s_ctrl->io_master_info), &i2c_write); + if(rc<0) { + CAM_ERR(CAM_SENSOR, "imx481 write otp failed"); + return rc; + } + i2c_write_setting.reg_addr = 0x0A01; + i2c_write_setting.reg_data = 0x01; + i2c_write_setting.delay = 100; + rc = camera_io_dev_poll( + &(s_ctrl->io_master_info), + i2c_write_setting.reg_addr, + i2c_write_setting.reg_data, + i2c_write_setting.data_mask, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE, + i2c_write_setting.delay); + if (rc < 0) { + CAM_ERR(CAM_SENSOR,"poll otp status failed ,non fatal"); + } + rc=camera_io_dev_read( + &(s_ctrl->io_master_info), + s_ctrl->sensordata->id_info.sensor_id_reg_addr, + &vendor_id,CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + CAM_INFO(CAM_SENSOR, "read vendor_id_addr=0x%x vendor_id: 0x%x expected vendor_id 0x%x: rc=%d", + s_ctrl->sensordata->id_info.sensor_id_reg_addr,vendor_id, s_ctrl->sensordata->id_info.sensor_id,rc); + if(vendor_id == 0x2) + strcpy(match_tbl[0].sensor_name,"imx481_SFK"); + if(vendor_id != s_ctrl->sensordata->id_info.sensor_id){ + if(vendor_id == 0){ + CAM_ERR(CAM_SENSOR,"read imx481 module vendor failed"); + return 0; + } + return -1; + } + } + } + + return rc; +} + +int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, + void *arg) +{ + int rc = 0; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_sensor_power_ctrl_t *power_info = + &s_ctrl->sensordata->power_info; +#ifdef CONFIG_PROJECT_INFO + enum COMPONENT_TYPE CameraID; +#endif + uint32_t count = 0, i; + if (!s_ctrl || !arg) { + CAM_ERR(CAM_SENSOR, "s_ctrl is NULL"); + return -EINVAL; + } + + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + switch (cmd->op_code) { + case CAM_SENSOR_PROBE_CMD: { + if (s_ctrl->is_probe_succeed == 1) { + CAM_ERR(CAM_SENSOR, + "Already Sensor Probed in the slot"); + break; + } + + if (cmd->handle_type == + CAM_HANDLE_MEM_HANDLE) { + rc = cam_handle_mem_ptr(cmd->handle, s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Get Buffer Handle Failed"); + goto release_mutex; + } + } else { + CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", + cmd->handle_type); + rc = -EINVAL; + goto release_mutex; + } + + /* Parse and fill vreg params for powerup settings */ + rc = msm_camera_fill_vreg_params( + &s_ctrl->soc_info, + s_ctrl->sensordata->power_info.power_setting, + s_ctrl->sensordata->power_info.power_setting_size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in filling vreg params for PUP rc %d", + rc); + goto free_power_settings; + } + + /* Parse and fill vreg params for powerdown settings*/ + rc = msm_camera_fill_vreg_params( + &s_ctrl->soc_info, + s_ctrl->sensordata->power_info.power_down_setting, + s_ctrl->sensordata->power_info.power_down_setting_size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in filling vreg params for PDOWN rc %d", + rc); + goto free_power_settings; + } + + /* Power up and probe sensor */ + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + goto free_power_settings; + } + + /* Match sensor ID */ + rc = cam_sensor_match_id(s_ctrl); + if (rc < 0) { + cam_sensor_power_down(s_ctrl); + msleep(20); + goto free_power_settings; + } + + CAM_INFO(CAM_SENSOR, + "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", + s_ctrl->soc_info.index, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensordata->slave_info.sensor_id); + + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); + goto free_power_settings; + } + /* + * Set probe succeeded flag to 1 so that no other camera shall + * probed on this slot + */ + s_ctrl->is_probe_succeed = 1; + s_ctrl->sensor_state = CAM_SENSOR_INIT; + +#ifdef CONFIG_PROJECT_INFO + if (s_ctrl->id == 0) + CameraID = R_CAMERA; + else if (s_ctrl->id == 1) + CameraID = SECOND_R_CAMERA; + else if (s_ctrl->id == 2) + CameraID = F_CAMERA; + else if (s_ctrl->id == 3) + CameraID = THIRD_R_CAMERA; + else if (s_ctrl->id == 4) + CameraID = FORTH_R_CAMERA; + else if (s_ctrl->id == 5) + CameraID = SECOND_F_CAMERA; + else + CameraID = -1; +#endif + count = ARRAY_SIZE(match_tbl); + for (i = 0; i < count; i++) { + if (s_ctrl->sensordata->slave_info.sensor_id + == match_tbl[i].sensor_id) + break; + } + if (i >= count) + CAM_ERR(CAM_SENSOR, "current sensor name is 0x%x", + s_ctrl->sensordata->slave_info.sensor_id); +#ifdef CONFIG_PROJECT_INFO + else + push_component_info(CameraID, match_tbl[i].sensor_name,match_tbl[i].vendor_name); +#endif + } + break; + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev sensor_acq_dev; + struct cam_create_dev_hdl bridge_params; + + if ((s_ctrl->is_probe_succeed == 0) || + (s_ctrl->sensor_state != CAM_SENSOR_INIT)) { + CAM_WARN(CAM_SENSOR, + "Not in right state to aquire %d", + s_ctrl->sensor_state); + rc = -EINVAL; + goto release_mutex; + } + + if (s_ctrl->bridge_intf.device_hdl != -1) { + CAM_ERR(CAM_SENSOR, "Device is already acquired"); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&sensor_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(sensor_acq_dev)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed Copying from user"); + goto release_mutex; + } + + bridge_params.session_hdl = sensor_acq_dev.session_handle; + bridge_params.ops = &s_ctrl->bridge_intf.ops; + bridge_params.v4l2_sub_dev_flag = 0; + bridge_params.media_entity_flag = 0; + bridge_params.priv = s_ctrl; + + sensor_acq_dev.device_handle = + cam_create_device_hdl(&bridge_params); + s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; + s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle; + + CAM_DBG(CAM_SENSOR, "Device Handle: %d", + sensor_acq_dev.device_handle); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &sensor_acq_dev, + sizeof(struct cam_sensor_acquire_dev))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power up failed"); + goto release_mutex; + } + + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + s_ctrl->last_flush_req = 0; + CAM_INFO(CAM_SENSOR, + "CAM_ACQUIRE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_RELEASE_DEV: { + + /*STOP DEV when sensor is START DEV and RELEASE called*/ + if (s_ctrl->sensor_state == CAM_SENSOR_START) + { + CAM_WARN(CAM_SENSOR, + "Unbalance Release called with out STOP: %d", + s_ctrl->sensor_state); + if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid && + (s_ctrl->i2c_data.streamoff_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF); + if (rc < 0) { + /*Even Stream off failure do force power down*/ + CAM_ERR(CAM_SENSOR, + "cannot apply streamoff settings"); + } + } + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + } + + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_START)) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to release : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->bridge_intf.link_hdl != -1) { + CAM_ERR(CAM_SENSOR, + "Device [%d] still active on link 0x%x", + s_ctrl->sensor_state, + s_ctrl->bridge_intf.link_hdl); + rc = -EAGAIN; + goto release_mutex; + } + + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Sensor Power Down failed"); + goto release_mutex; + } + + cam_sensor_release_per_frame_resource(s_ctrl); + cam_sensor_release_stream_rsc(s_ctrl); + if (s_ctrl->bridge_intf.device_hdl == -1) { + CAM_ERR(CAM_SENSOR, + "Invalid Handles: link hdl: %d device hdl: %d", + s_ctrl->bridge_intf.device_hdl, + s_ctrl->bridge_intf.link_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "failed in destroying the device hdl"); + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.session_hdl = -1; + + s_ctrl->sensor_state = CAM_SENSOR_INIT; + CAM_INFO(CAM_SENSOR, + "CAM_RELEASE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 0; + s_ctrl->last_flush_req = 0; + } + break; + case CAM_QUERY_CAP: { + struct cam_sensor_query_cap sensor_cap; + + cam_sensor_query_cap(s_ctrl, &sensor_cap); + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &sensor_cap, sizeof(struct cam_sensor_query_cap))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + break; + } + case CAM_START_DEV: { + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) || + (s_ctrl->sensor_state == CAM_SENSOR_START)) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to start : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->i2c_data.streamon_settings.is_settings_valid && + (s_ctrl->i2c_data.streamon_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply streamon settings"); + goto release_mutex; + } + } + s_ctrl->sensor_state = CAM_SENSOR_START; + CAM_INFO(CAM_SENSOR, + "CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_STOP_DEV: { + if (s_ctrl->sensor_state != CAM_SENSOR_START) { + rc = -EINVAL; + CAM_WARN(CAM_SENSOR, + "Not in right state to stop : %d", + s_ctrl->sensor_state); + goto release_mutex; + } + + if (s_ctrl->i2c_data.streamoff_settings.is_settings_valid && + (s_ctrl->i2c_data.streamoff_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply streamoff settings"); + } + } + + cam_sensor_release_per_frame_resource(s_ctrl); + s_ctrl->last_flush_req = 0; + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + CAM_INFO(CAM_SENSOR, + "CAM_STOP_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + } + break; + case CAM_CONFIG_DEV: { + rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); + goto release_mutex; + } + if (s_ctrl->i2c_data.init_settings.is_settings_valid && + (s_ctrl->i2c_data.init_settings.request_id == 0)) { + + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG); + + if ((rc == -EAGAIN) && + (s_ctrl->io_master_info.master_type == CCI_MASTER)) { + /* If CCI hardware is resetting we need to wait for sometime + * before reapply + */ + CAM_WARN(CAM_SENSOR, + "Reapplying the Init settings due to cci hw reset"); + usleep_range(5000, 5010); + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG); + } + s_ctrl->i2c_data.init_settings.request_id = -1; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply init settings rc= %d", + rc); + delete_request(&s_ctrl->i2c_data.init_settings); + goto release_mutex; + } + rc = delete_request(&s_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the Init settings"); + goto release_mutex; + } + } + + if (s_ctrl->i2c_data.config_settings.is_settings_valid && + (s_ctrl->i2c_data.config_settings.request_id == 0)) { + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG); + + s_ctrl->i2c_data.config_settings.request_id = -1; + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply config settings"); + delete_request( + &s_ctrl->i2c_data.config_settings); + goto release_mutex; + } + rc = delete_request(&s_ctrl->i2c_data.config_settings); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Fail in deleting the config settings"); + goto release_mutex; + } + s_ctrl->sensor_state = CAM_SENSOR_CONFIG; + } + } + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + goto release_mutex; + } + +release_mutex: + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + +free_power_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} + +int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!info) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(info->dev_hdl); + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + + info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR; + strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name)); + if (s_ctrl->pipeline_delay >= 1 && s_ctrl->pipeline_delay <= 3) + info->p_delay = s_ctrl->pipeline_delay; + else + info->p_delay = 2; + info->trigger = CAM_TRIGGER_POINT_SOF; + + return rc; +} + +int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link) +{ + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!link) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(link->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&s_ctrl->cam_sensor_mutex); + if (link->link_enable) { + s_ctrl->bridge_intf.link_hdl = link->link_hdl; + s_ctrl->bridge_intf.crm_cb = link->crm_cb; + } else { + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.crm_cb = NULL; + } + mutex_unlock(&s_ctrl->cam_sensor_mutex); + + return 0; +} + +int cam_sensor_power(struct v4l2_subdev *sd, int on) +{ + struct cam_sensor_ctrl_t *s_ctrl = v4l2_get_subdevdata(sd); + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if (!on && s_ctrl->sensor_state == CAM_SENSOR_START) { + cam_sensor_power_down(s_ctrl); + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + } + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + + return 0; +} + +int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc; + struct cam_sensor_power_ctrl_t *power_info; + struct cam_camera_slave_info *slave_info; + struct cam_hw_soc_info *soc_info = + &s_ctrl->soc_info; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "failed: %pK", s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + slave_info = &(s_ctrl->sensordata->slave_info); + + if (!power_info || !slave_info) { + CAM_ERR(CAM_SENSOR, "failed: %pK %pK", power_info, slave_info); + return -EINVAL; + } + + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, true); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + + rc = cam_sensor_core_power_up(power_info, soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up the core is failed:%d", rc); + return rc; + } + + rc = camera_io_init(&(s_ctrl->io_master_info)); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "cci_init failed: rc: %d", rc); + + return rc; +} + +int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl) +{ + struct cam_sensor_power_ctrl_t *power_info; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "failed: s_ctrl %pK", s_ctrl); + return -EINVAL; + } + + power_info = &s_ctrl->sensordata->power_info; + soc_info = &s_ctrl->soc_info; + + if (!power_info) { + CAM_ERR(CAM_SENSOR, "failed: power_info %pK", power_info); + return -EINVAL; + } + rc = cam_sensor_util_power_down(power_info, soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power down the core is failed:%d", rc); + return rc; + } + + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, false); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + + camera_io_release(&(s_ctrl->io_master_info)); + + return rc; +} + +int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, + int64_t req_id, enum cam_sensor_packet_opcodes opcode) +{ + int rc = 0, offset, i; + uint64_t top = 0, del_req_id = 0; + struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list; + + if (req_id == 0) { + switch (opcode) { + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { + i2c_set = &s_ctrl->i2c_data.streamon_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { + i2c_set = &s_ctrl->i2c_data.init_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { + i2c_set = &s_ctrl->i2c_data.config_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { + i2c_set = &s_ctrl->i2c_data.streamoff_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: + case CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE: + default: + return 0; + } + if (i2c_set->is_settings_valid == 1) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_i2c_modes_util( + &(s_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + } + } else { + offset = req_id % MAX_PER_FRAME_ARRAY; + i2c_set = &(s_ctrl->i2c_data.per_frame[offset]); + if (i2c_set->is_settings_valid == 1 && + i2c_set->request_id == req_id) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_i2c_modes_util( + &(s_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + } else { + CAM_DBG(CAM_SENSOR, + "Invalid/NOP request to apply: %lld", req_id); + } + + /* Change the logic dynamically */ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((req_id >= + s_ctrl->i2c_data.per_frame[i].request_id) && + (top < + s_ctrl->i2c_data.per_frame[i].request_id) && + (s_ctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + del_req_id = top; + top = s_ctrl->i2c_data.per_frame[i].request_id; + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return rc; + + CAM_DBG(CAM_SENSOR, "top: %llu, del_req_id:%llu", + top, del_req_id); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((del_req_id > + s_ctrl->i2c_data.per_frame[i].request_id) && ( + s_ctrl->i2c_data.per_frame[i].is_settings_valid + == 1)) { + s_ctrl->i2c_data.per_frame[i].request_id = 0; + rc = delete_request( + &(s_ctrl->i2c_data.per_frame[i])); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "Delete request Fail:%lld rc:%d", + del_req_id, rc); + } + } + } + + return rc; +} + +int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int32_t rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!apply) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(apply->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + CAM_DBG(CAM_REQ, " Sensor update req id: %lld", apply->request_id); + trace_cam_apply_req("Sensor", apply->request_id); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} + +int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) +{ + int32_t rc = 0, i; + uint32_t cancel_req_id_found = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct i2c_settings_array *i2c_set = NULL; + + if (!flush_req) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(flush_req->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if (s_ctrl->sensor_state != CAM_SENSOR_START || + s_ctrl->sensor_state != CAM_SENSOR_CONFIG) { + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + } + + if (s_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return -EINVAL; + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + s_ctrl->last_flush_req = flush_req->req_id; + CAM_DBG(CAM_SENSOR, "last reqest to flush is %lld", + flush_req->req_id); + } + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + i2c_set = &(s_ctrl->i2c_data.per_frame[i]); + + if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) + && (i2c_set->request_id != flush_req->req_id)) + continue; + + if (i2c_set->is_settings_valid == 1) { + rc = delete_request(i2c_set); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "delete request: %lld rc: %d", + i2c_set->request_id, rc); + + if (flush_req->type == + CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + cancel_req_id_found = 1; + break; + } + } + } + + if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && + !cancel_req_id_found) + CAM_DBG(CAM_SENSOR, + "Flush request id:%lld not found in the pending list", + flush_req->req_id); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h new file mode 100644 index 0000000000000000000000000000000000000000..b7a5923a6a70079243fbe9f1de7b381a31960233 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_CORE_H_ +#define _CAM_SENSOR_CORE_H_ + +#include "cam_sensor_dev.h" + +/** + * @s_ctrl: Sensor ctrl structure + * + * This API powers up the camera sensor module + */ +int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl); + +/** + * @s_ctrl: Sensor ctrl structure + * + * This API powers down the camera sensor module + */ +int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl); + +/** + * @sd: V4L2 subdevice + * @on: Turn off/on flag + * + * This API powers down the sensor module + */ +int cam_sensor_power(struct v4l2_subdev *sd, int on); + +/** + * @s_ctrl: Sensor ctrl structure + * @req_id: Request id + * @opcode: opcode for settings + * + * This API applies the req_id settings to sensor + */ +int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, int64_t req_id, + enum cam_sensor_packet_opcodes opcode); + +/** + * @apply: Req mgr structure for applying request + * + * This API applies the request that is mentioned + */ +int cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply); + +/** + * @flush: Req mgr structure for flushing request + * + * This API flushes the request that is mentioned + */ +int cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush); + +/** + * @info: Sub device info to req mgr + * + * Publish the subdevice info + */ +int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info); + +/** + * @link: Link setup info + * + * This API establishes link with sensor subdevice with req mgr + */ +int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link); + +/** + * @s_ctrl: Sensor ctrl structure + * @arg: Camera control command argument + * + * This API handles the camera control argument reached to sensor + */ +int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg); + +/** + * @s_ctrl: Sensor ctrl structure + * + * This API handles the camera sensor close/shutdown + */ +void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl); + +#endif /* _CAM_SENSOR_CORE_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c new file mode 100755 index 0000000000000000000000000000000000000000..c908e7404882810f29840a14cf41832b7c51c4b8 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_sensor_soc.h" +#include "cam_sensor_core.h" +struct cam_sensor_i2c_reg_setting_array { + struct cam_sensor_i2c_reg_array reg_setting[1024]; + unsigned short size; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + unsigned short delay; +}; + +struct cam_sensor_settings { + struct cam_sensor_i2c_reg_setting_array imx586_setting0; + struct cam_sensor_i2c_reg_setting_array imx586_setting1; + struct cam_sensor_i2c_reg_setting_array streamoff; + struct cam_sensor_i2c_reg_setting_array s5k3m5_setting; + struct cam_sensor_i2c_reg_setting_array imx471_setting; + struct cam_sensor_i2c_reg_setting_array imx481_setting; + struct cam_sensor_i2c_reg_setting_array gc5035_setting; + struct cam_sensor_i2c_reg_setting_array imx689_setting; + struct cam_sensor_i2c_reg_setting_array gc2375_setting; + + struct cam_sensor_i2c_reg_setting_array hi846_setting; //Rear_UW + struct cam_sensor_i2c_reg_setting_array imx616_setting; //Front_Main + struct cam_sensor_i2c_reg_setting_array gc8054_setting; //Front_UW + struct cam_sensor_i2c_reg_setting_array ov02b10_setting; + struct cam_sensor_i2c_reg_setting_array ov8856_setting; + struct cam_sensor_i2c_reg_setting_array gc02m1b_setting; +}; + +struct cam_sensor_settings sensor_settings = { +#include "CAM_SENSOR_SETTINGS.h" +}; +static bool is_ftm_current_test = false; + +static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + /* Add for AT camera test */ + struct cam_sensor_i2c_reg_setting sensor_setting; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_driver_cmd(s_ctrl, arg); + break; + /* Add for AT camera test */ + case VIDIOC_CAM_FTM_POWNER_DOWN: + CAM_ERR(CAM_SENSOR, "FTM stream off"); + if (s_ctrl->sensordata->slave_info.sensor_id == 0x586 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x30d5 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x471 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x481 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x5035 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x689 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x2375 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x4608 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x0616 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x8054 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x88 + ||s_ctrl->sensordata->slave_info.sensor_id == 0x2b + ||s_ctrl->sensordata->slave_info.sensor_id == 0x02) { + sensor_setting.reg_setting = sensor_settings.streamoff.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.streamoff.size; + sensor_setting.delay = sensor_settings.streamoff.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + /* If the I2C reg write failed for the first section reg, send + the result instead of keeping writing the next section of reg. */ + CAM_ERR(CAM_SENSOR, "FTM Failed to stream off setting,rc=%d.",rc); + } else { + CAM_ERR(CAM_SENSOR, "FTM successfully to stream off"); + } + } + rc = cam_sensor_power_down(s_ctrl); + CAM_ERR(CAM_SENSOR, "FTM power down.rc=%d",rc); + break; + case VIDIOC_CAM_FTM_POWNER_UP: + rc = cam_sensor_power_up(s_ctrl); + CAM_ERR(CAM_SENSOR, "FTM power up sensor id 0x%x,result %d",s_ctrl->sensordata->slave_info.sensor_id,rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "FTM power up failed!"); + break; + } + is_ftm_current_test = true; + if (s_ctrl->sensordata->slave_info.sensor_id == 0x586) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.imx586_setting0.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx586_setting0.size; + sensor_setting.delay = sensor_settings.imx586_setting0.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + /* If the I2C reg write failed for the first section reg, send + the result instead of keeping writing the next section of reg. */ + CAM_ERR(CAM_SENSOR, "FTM Failed to write sensor setting 1/2"); + goto power_down; + } else { + CAM_ERR(CAM_SENSOR, "FTM successfully to write sensor setting 1/2"); + } + sensor_setting.reg_setting = sensor_settings.imx586_setting1.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx586_setting1.size; + sensor_setting.delay = sensor_settings.imx586_setting1.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "FTM Failed to write sensor setting 2/2"); + goto power_down; + } else { + CAM_ERR(CAM_SENSOR, "FTM successfully to write sensor setting 2/2"); + } + } else { + if (s_ctrl->sensordata->slave_info.sensor_id == 0x30d5) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.s5k3m5_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.size = sensor_settings.s5k3m5_setting.size; + sensor_setting.delay = sensor_settings.s5k3m5_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x5035) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.gc5035_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.gc5035_setting.size; + sensor_setting.delay = sensor_settings.gc5035_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x471) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.imx471_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx471_setting.size; + sensor_setting.delay = sensor_settings.imx471_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x481) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.imx481_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx481_setting.size; + sensor_setting.delay = sensor_settings.imx481_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x689) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.imx689_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx689_setting.size; + sensor_setting.delay = sensor_settings.imx689_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x2375) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.gc2375_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.gc2375_setting.size; + sensor_setting.delay = sensor_settings.gc2375_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x4608) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.hi846_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.size = sensor_settings.hi846_setting.size; + sensor_setting.delay = sensor_settings.hi846_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x0616) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.imx616_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx616_setting.size; + sensor_setting.delay = sensor_settings.imx616_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x8054) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.gc8054_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.gc8054_setting.size; + sensor_setting.delay = sensor_settings.gc8054_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + }else if (s_ctrl->sensordata->slave_info.sensor_id == 0x88) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.imx616_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.imx616_setting.size; + sensor_setting.delay = sensor_settings.imx616_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x2b) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.gc8054_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.gc8054_setting.size; + sensor_setting.delay = sensor_settings.gc8054_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x02) { + CAM_ERR(CAM_SENSOR, "FTM sensor setting 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + sensor_setting.reg_setting = sensor_settings.gc02m1b_setting.reg_setting; + sensor_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + sensor_setting.size = sensor_settings.gc02m1b_setting.size; + sensor_setting.delay = sensor_settings.gc02m1b_setting.delay; + rc = camera_io_dev_write(&(s_ctrl->io_master_info), &sensor_setting); + }else { + CAM_ERR(CAM_SENSOR, "FTM unknown sensor id 0x%x",s_ctrl->sensordata->slave_info.sensor_id); + rc = -1; + } + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "FTM Failed to write sensor setting"); + goto power_down; + } else { + CAM_ERR(CAM_SENSOR, "FTM successfully to write sensor setting"); + } + } + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); + rc = -EINVAL; + break; + } + return rc; +power_down: + CAM_ERR(CAM_SENSOR, "FTM wirte setting failed,do power down"); + cam_sensor_power_down(s_ctrl); + return rc; +} + +static int cam_sensor_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_sensor_ctrl_t *s_ctrl = + v4l2_get_subdevdata(sd); + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "s_ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if(!is_ftm_current_test) + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + + return 0; +} + +#ifdef CONFIG_COMPAT +static long cam_sensor_init_subdev_do_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + struct cam_control cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + CAM_ERR(CAM_SENSOR, "Failed to copy from user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_subdev_ioctl(sd, cmd, &cmd_data); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "cam_sensor_subdev_ioctl failed"); + break; + default: + CAM_ERR(CAM_SENSOR, "Invalid compat ioctl cmd_type: %d", cmd); + rc = -EINVAL; + } + + if (!rc) { + if (copy_to_user((void __user *)arg, &cmd_data, + sizeof(cmd_data))) { + CAM_ERR(CAM_SENSOR, + "Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} + +#endif +static struct v4l2_subdev_core_ops cam_sensor_subdev_core_ops = { + .ioctl = cam_sensor_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_sensor_init_subdev_do_ioctl, +#endif + .s_power = cam_sensor_power, +}; + +static struct v4l2_subdev_ops cam_sensor_subdev_ops = { + .core = &cam_sensor_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_sensor_internal_ops = { + .close = cam_sensor_subdev_close, +}; + +static int cam_sensor_init_subdev_params(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + + s_ctrl->v4l2_dev_str.internal_ops = + &cam_sensor_internal_ops; + s_ctrl->v4l2_dev_str.ops = + &cam_sensor_subdev_ops; + strlcpy(s_ctrl->device_name, CAMX_SENSOR_DEV_NAME, + sizeof(s_ctrl->device_name)); + s_ctrl->v4l2_dev_str.name = + s_ctrl->device_name; + s_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + s_ctrl->v4l2_dev_str.ent_function = + CAM_SENSOR_DEVICE_TYPE; + s_ctrl->v4l2_dev_str.token = s_ctrl; + + rc = cam_register_subdev(&(s_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_SENSOR, "Fail with cam_register_subdev rc: %d", rc); + + return rc; +} + +static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int32_t rc = 0; + int i = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + CAM_ERR(CAM_SENSOR, + "%s :i2c_check_functionality failed", client->name); + return -EFAULT; + } + + /* Create sensor control structure */ + s_ctrl = kzalloc(sizeof(*s_ctrl), GFP_KERNEL); + if (!s_ctrl) + return -ENOMEM; + + i2c_set_clientdata(client, s_ctrl); + + s_ctrl->io_master_info.client = client; + soc_info = &s_ctrl->soc_info; + soc_info->dev = &client->dev; + soc_info->dev_name = client->name; + + /* Initialize sensor device type */ + s_ctrl->of_node = client->dev.of_node; + s_ctrl->io_master_info.master_type = I2C_MASTER; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + + rc = cam_sensor_parse_dt(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "cam_sensor_parse_dt rc %d", rc); + goto free_s_ctrl; + } + + rc = cam_sensor_init_subdev_params(s_ctrl); + if (rc) + goto free_s_ctrl; + + s_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (s_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(s_ctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); + + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info; + s_ctrl->bridge_intf.ops.link_setup = cam_sensor_establish_link; + s_ctrl->bridge_intf.ops.apply_req = cam_sensor_apply_request; + s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request; + + s_ctrl->sensordata->power_info.dev = soc_info->dev; + + return rc; +unreg_subdev: + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); +free_s_ctrl: + kfree(s_ctrl); + return rc; +} + +static int cam_sensor_platform_remove(struct platform_device *pdev) +{ + int i; + struct cam_sensor_ctrl_t *s_ctrl; + struct cam_hw_soc_info *soc_info; + + s_ctrl = platform_get_drvdata(pdev); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "sensor device is NULL"); + return 0; + } + + CAM_INFO(CAM_SENSOR, "platform remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); + soc_info = &s_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + kfree(s_ctrl->i2c_data.per_frame); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); + devm_kfree(&pdev->dev, s_ctrl); + + return 0; +} + +static int cam_sensor_driver_i2c_remove(struct i2c_client *client) +{ + int i; + struct cam_sensor_ctrl_t *s_ctrl = i2c_get_clientdata(client); + struct cam_hw_soc_info *soc_info; + + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "sensor device is NULL"); + return 0; + } + + CAM_INFO(CAM_SENSOR, "i2c remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); + soc_info = &s_ctrl->soc_info; + for (i = 0; i < soc_info->num_clk; i++) + devm_clk_put(soc_info->dev, soc_info->clk[i]); + + kfree(s_ctrl->i2c_data.per_frame); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); + kfree(s_ctrl); + + return 0; +} + +static const struct of_device_id cam_sensor_driver_dt_match[] = { + {.compatible = "qcom,cam-sensor"}, + {} +}; + +static int32_t cam_sensor_driver_platform_probe( + struct platform_device *pdev) +{ + int32_t rc = 0, i = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + struct cam_hw_soc_info *soc_info = NULL; + + /* Create sensor control structure */ + s_ctrl = devm_kzalloc(&pdev->dev, + sizeof(struct cam_sensor_ctrl_t), GFP_KERNEL); + if (!s_ctrl) + return -ENOMEM; + + soc_info = &s_ctrl->soc_info; + soc_info->pdev = pdev; + soc_info->dev = &pdev->dev; + soc_info->dev_name = pdev->name; + + /* Initialize sensor device type */ + s_ctrl->of_node = pdev->dev.of_node; + s_ctrl->is_probe_succeed = 0; + s_ctrl->last_flush_req = 0; + + /*fill in platform device*/ + s_ctrl->pdev = pdev; + + s_ctrl->io_master_info.master_type = CCI_MASTER; + + rc = cam_sensor_parse_dt(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed: cam_sensor_parse_dt rc %d", rc); + goto free_s_ctrl; + } + + /* Fill platform device id*/ + pdev->id = soc_info->index; + + rc = cam_sensor_init_subdev_params(s_ctrl); + if (rc) + goto free_s_ctrl; + + s_ctrl->i2c_data.per_frame = + kzalloc(sizeof(struct i2c_settings_array) * + MAX_PER_FRAME_ARRAY, GFP_KERNEL); + if (s_ctrl->i2c_data.per_frame == NULL) { + rc = -ENOMEM; + goto unreg_subdev; + } + + INIT_LIST_HEAD(&(s_ctrl->i2c_data.init_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.config_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamon_settings.list_head)); + INIT_LIST_HEAD(&(s_ctrl->i2c_data.streamoff_settings.list_head)); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) + INIT_LIST_HEAD(&(s_ctrl->i2c_data.per_frame[i].list_head)); + + s_ctrl->bridge_intf.device_hdl = -1; + s_ctrl->bridge_intf.link_hdl = -1; + s_ctrl->bridge_intf.ops.get_dev_info = cam_sensor_publish_dev_info; + s_ctrl->bridge_intf.ops.link_setup = cam_sensor_establish_link; + s_ctrl->bridge_intf.ops.apply_req = cam_sensor_apply_request; + s_ctrl->bridge_intf.ops.flush_req = cam_sensor_flush_request; + + s_ctrl->sensordata->power_info.dev = &pdev->dev; + platform_set_drvdata(pdev, s_ctrl); + s_ctrl->sensor_state = CAM_SENSOR_INIT; + + return rc; +unreg_subdev: + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); +free_s_ctrl: + devm_kfree(&pdev->dev, s_ctrl); + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_sensor_driver_dt_match); + +static struct platform_driver cam_sensor_platform_driver = { + .probe = cam_sensor_driver_platform_probe, + .driver = { + .name = "qcom,camera", + .owner = THIS_MODULE, + .of_match_table = cam_sensor_driver_dt_match, + .suppress_bind_attrs = true, + }, + .remove = cam_sensor_platform_remove, +}; + +static const struct i2c_device_id i2c_id[] = { + {SENSOR_DRIVER_I2C, (kernel_ulong_t)NULL}, + { } +}; + +static struct i2c_driver cam_sensor_driver_i2c = { + .id_table = i2c_id, + .probe = cam_sensor_driver_i2c_probe, + .remove = cam_sensor_driver_i2c_remove, + .driver = { + .name = SENSOR_DRIVER_I2C, + }, +}; + +static int __init cam_sensor_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_sensor_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "platform_driver_register Failed: rc = %d", + rc); + return rc; + } + + rc = i2c_add_driver(&cam_sensor_driver_i2c); + if (rc) + CAM_ERR(CAM_SENSOR, "i2c_add_driver failed rc = %d", rc); + + return rc; +} + +static void __exit cam_sensor_driver_exit(void) +{ + platform_driver_unregister(&cam_sensor_platform_driver); + i2c_del_driver(&cam_sensor_driver_i2c); +} + +module_init(cam_sensor_driver_init); +module_exit(cam_sensor_driver_exit); +MODULE_DESCRIPTION("cam_sensor_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..b1963e15eb5954c4ce8fcd62b47190184dcc8b23 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_DEV_H_ +#define _CAM_SENSOR_DEV_H_ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/module.h> +#include <linux/irqreturn.h> +#include <linux/iommu.h> +#include <linux/timer.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <cam_cci_dev.h> +#include <cam_sensor_cmn_header.h> +#include <cam_subdev.h> +#include <cam_sensor_io.h> +#include "cam_debug_util.h" +#include "cam_context.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#undef CDBG +#ifdef CAM_SENSOR_DEBUG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define SENSOR_DRIVER_I2C "i2c_camera" +#define CAMX_SENSOR_DEV_NAME "cam-sensor-driver" + +enum cam_sensor_state_t { + CAM_SENSOR_INIT, + CAM_SENSOR_ACQUIRE, + CAM_SENSOR_CONFIG, + CAM_SENSOR_START, +}; + +/** + * struct intf_params + * @device_hdl: Device Handle + * @session_hdl: Session Handle + * @link_hdl: Link Handle + * @ops: KMD operations + * @crm_cb: Callback API pointers + */ +struct intf_params { + int32_t device_hdl; + int32_t session_hdl; + int32_t link_hdl; + struct cam_req_mgr_kmd_ops ops; + struct cam_req_mgr_crm_cb *crm_cb; +}; + +/** + * struct cam_sensor_ctrl_t: Camera control structure + * @device_name: Sensor device name + * @pdev: Platform device + * @cam_sensor_mutex: Sensor mutex + * @sensordata: Sensor board Information + * @cci_i2c_master: I2C structure + * @io_master_info: Information about the communication master + * @sensor_state: Sensor states + * @is_probe_succeed: Probe succeeded or not + * @id: Cell Index + * @of_node: Of node ptr + * @v4l2_dev_str: V4L2 device structure + * @sensor_probe_addr_type: Sensor probe address type + * @sensor_probe_data_type: Sensor probe data type + * @i2c_data: Sensor I2C register settings + * @sensor_info: Sensor query cap structure + * @bridge_intf: Bridge interface structure + * @streamon_count: Count to hold the number of times stream on called + * @streamoff_count: Count to hold the number of times stream off called + * @bob_reg_index: Hold to BoB regulator index + * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator + * @last_flush_req: Last request to flush + * @pipeline_delay: Sensor pipeline delay + */ +struct cam_sensor_ctrl_t { + char device_name[CAM_CTX_DEV_NAME_MAX_LENGTH]; + struct platform_device *pdev; + struct cam_hw_soc_info soc_info; + struct mutex cam_sensor_mutex; + struct cam_sensor_board_info *sensordata; + enum cci_i2c_master_t cci_i2c_master; + enum cci_device_num cci_num; + struct camera_io_master io_master_info; + enum cam_sensor_state_t sensor_state; + uint8_t is_probe_succeed; + uint32_t id; + struct device_node *of_node; + struct cam_subdev v4l2_dev_str; + uint8_t sensor_probe_addr_type; + uint8_t sensor_probe_data_type; + struct i2c_data_settings i2c_data; + struct cam_sensor_query_cap sensor_info; + struct intf_params bridge_intf; + uint32_t streamon_count; + uint32_t streamoff_count; + int bob_reg_index; + bool bob_pwm_switch; + uint32_t last_flush_req; + uint16_t pipeline_delay; +}; + +#endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c new file mode 100644 index 0000000000000000000000000000000000000000..2c25ee0aa6f0433ef9e2e912f31e979761f0892d --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <cam_sensor_cmn_header.h> +#include <cam_sensor_util.h> +#include <cam_sensor_io.h> +#include <cam_req_mgr_util.h> +#include "cam_sensor_soc.h" +#include "cam_soc_util.h" + +int32_t cam_sensor_get_sub_module_index(struct device_node *of_node, + struct cam_sensor_board_info *s_info) +{ + int rc = 0, i = 0; + uint32_t val = 0; + struct device_node *src_node = NULL; + struct cam_sensor_board_info *sensor_info; + + sensor_info = s_info; + + for (i = 0; i < SUB_MODULE_MAX; i++) + sensor_info->subdev_id[i] = -1; + + src_node = of_parse_phandle(of_node, "actuator-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "actuator cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_ACTUATOR] = val; + of_node_put(src_node); + } + + src_node = of_parse_phandle(of_node, "ois-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, " ois cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_OIS] = val; + of_node_put(src_node); + } + + src_node = of_parse_phandle(of_node, "eeprom-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, "eeprom src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "eeprom cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_EEPROM] = val; + of_node_put(src_node); + } + + src_node = of_parse_phandle(of_node, "led-flash-src", 0); + if (!src_node) { + CAM_DBG(CAM_SENSOR, " src_node NULL"); + } else { + rc = of_property_read_u32(src_node, "cell-index", &val); + CAM_DBG(CAM_SENSOR, "led flash cell index %d, rc %d", val, rc); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + of_node_put(src_node); + return rc; + } + sensor_info->subdev_id[SUB_MODULE_LED_FLASH] = val; + of_node_put(src_node); + } + + rc = of_property_read_u32(of_node, "csiphy-sd-index", &val); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "paring the dt node for csiphy rc %d", rc); + else + sensor_info->subdev_id[SUB_MODULE_CSIPHY] = val; + + return rc; +} + +static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t rc = 0; + int i = 0; + struct cam_sensor_board_info *sensordata = NULL; + struct device_node *of_node = s_ctrl->of_node; + struct device_node *of_parent = NULL; + struct cam_hw_soc_info *soc_info = &s_ctrl->soc_info; + + s_ctrl->sensordata = kzalloc(sizeof(*sensordata), GFP_KERNEL); + if (!s_ctrl->sensordata) + return -ENOMEM; + + sensordata = s_ctrl->sensordata; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to read DT properties rc %d", rc); + goto FREE_SENSOR_DATA; + } + + rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, + &sensordata->power_info.gpio_num_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to read gpios %d", rc); + goto FREE_SENSOR_DATA; + } + + s_ctrl->id = soc_info->index; + + /* Validate cell_id */ + if (s_ctrl->id >= MAX_CAMERAS) { + CAM_ERR(CAM_SENSOR, "Failed invalid cell_id %d", s_ctrl->id); + rc = -EINVAL; + goto FREE_SENSOR_DATA; + } + + /* Store the index of BoB regulator if it is available */ + for (i = 0; i < soc_info->num_rgltr; i++) { + if (!strcmp(soc_info->rgltr_name[i], + "cam_bob")) { + CAM_DBG(CAM_SENSOR, + "i: %d cam_bob", i); + s_ctrl->bob_reg_index = i; + soc_info->rgltr[i] = devm_regulator_get(soc_info->dev, + soc_info->rgltr_name[i]); + if (IS_ERR_OR_NULL(soc_info->rgltr[i])) { + CAM_WARN(CAM_SENSOR, + "Regulator: %s get failed", + soc_info->rgltr_name[i]); + soc_info->rgltr[i] = NULL; + } else { + if (!of_property_read_bool(of_node, + "pwm-switch")) { + CAM_DBG(CAM_SENSOR, + "No BoB PWM switch param defined"); + s_ctrl->bob_pwm_switch = false; + } else { + s_ctrl->bob_pwm_switch = true; + } + } + } + } + + /* Read subdev info */ + rc = cam_sensor_get_sub_module_index(of_node, sensordata); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed to get sub module index, rc=%d", + rc); + goto FREE_SENSOR_DATA; + } + + if (s_ctrl->io_master_info.master_type == CCI_MASTER) { + /* Get CCI master */ + rc = of_property_read_u32(of_node, "cci-master", + &s_ctrl->cci_i2c_master); + CAM_DBG(CAM_SENSOR, "cci-master %d, rc %d", + s_ctrl->cci_i2c_master, rc); + if (rc < 0) { + /* Set default master 0 */ + s_ctrl->cci_i2c_master = MASTER_0; + rc = 0; + } + + of_parent = of_get_parent(of_node); + if (of_property_read_u32(of_parent, "cell-index", + &s_ctrl->cci_num) < 0) + /* Set default master 0 */ + s_ctrl->cci_num = CCI_DEVICE_0; + + CAM_DBG(CAM_SENSOR, "cci-index %d", s_ctrl->cci_num); + } + + if (of_property_read_u32(of_node, "sensor-position-pitch", + &sensordata->pos_pitch) < 0) { + CAM_DBG(CAM_SENSOR, "Invalid sensor position"); + sensordata->pos_pitch = 360; + } + if (of_property_read_u32(of_node, "sensor-position-roll", + &sensordata->pos_roll) < 0) { + CAM_DBG(CAM_SENSOR, "Invalid sensor position"); + sensordata->pos_roll = 360; + } + if (of_property_read_u32(of_node, "sensor-position-yaw", + &sensordata->pos_yaw) < 0) { + CAM_DBG(CAM_SENSOR, "Invalid sensor position"); + sensordata->pos_yaw = 360; + } + + return rc; + +FREE_SENSOR_DATA: + kfree(sensordata); + return rc; +} + +int32_t msm_sensor_init_default_params(struct cam_sensor_ctrl_t *s_ctrl) +{ + /* Validate input parameters */ + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "failed: invalid params s_ctrl %pK", + s_ctrl); + return -EINVAL; + } + + CAM_DBG(CAM_SENSOR, + "master_type: %d", s_ctrl->io_master_info.master_type); + /* Initialize cci_client */ + if (s_ctrl->io_master_info.master_type == CCI_MASTER) { + s_ctrl->io_master_info.cci_client = kzalloc(sizeof( + struct cam_sensor_cci_client), GFP_KERNEL); + if (!(s_ctrl->io_master_info.cci_client)) + return -ENOMEM; + + s_ctrl->io_master_info.cci_client->cci_device + = s_ctrl->cci_num; + } else if (s_ctrl->io_master_info.master_type == I2C_MASTER) { + if (!(s_ctrl->io_master_info.client)) + return -EINVAL; + } else { + CAM_ERR(CAM_SENSOR, + "Invalid master / Master type Not supported"); + return -EINVAL; + } + + return 0; +} + +int32_t cam_sensor_parse_dt(struct cam_sensor_ctrl_t *s_ctrl) +{ + int32_t i, rc = 0; + struct cam_hw_soc_info *soc_info = &s_ctrl->soc_info; + + /* Parse dt information and store in sensor control structure */ + rc = cam_sensor_driver_get_dt_data(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to get dt data rc %d", rc); + return rc; + } + + /* Initialize mutex */ + mutex_init(&(s_ctrl->cam_sensor_mutex)); + + /* Initialize default parameters */ + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = devm_clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_SENSOR, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + return rc; + } + } + rc = msm_sensor_init_default_params(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "failed: msm_sensor_init_default_params rc %d", rc); + goto FREE_DT_DATA; + } + + return rc; + +FREE_DT_DATA: + kfree(s_ctrl->sensordata); + s_ctrl->sensordata = NULL; + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h new file mode 100644 index 0000000000000000000000000000000000000000..99862da046ffa2e48c5cbf1ce6f68eb5d676994b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_SOC_H_ +#define _CAM_SENSOR_SOC_H_ + +#include "cam_sensor_dev.h" + +/** + * @s_ctrl: Sensor ctrl structure + * + * Parses sensor dt + */ +int cam_sensor_parse_dt(struct cam_sensor_ctrl_t *s_ctrl); + +#endif /* _CAM_SENSOR_SOC_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5b11171fa0875b3d11beaafc5da66a0bac8e47ac --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io.o cam_sensor_cci_i2c.o cam_sensor_qup_i2c.o cam_sensor_spi.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..a5e780a2e119122f198b54b794cdf5aef1520006 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_cmn_header.h" +#include "cam_sensor_i2c.h" +#include "cam_cci_dev.h" + +int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int32_t rc = -EINVAL; + unsigned char buf[CAMERA_SENSOR_I2C_TYPE_DWORD]; + struct cam_cci_ctrl cci_ctrl; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + return rc; + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "rc = %d", rc); + return rc; + } + + rc = cci_ctrl.status; + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + *data = buf[0]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) + *data = buf[0] << 8 | buf[1]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) + *data = buf[0] << 16 | buf[1] << 8 | buf[2]; + else + *data = buf[0] << 24 | buf[1] << 16 | + buf[2] << 8 | buf[3]; + + return rc; +} + +int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char *buf = NULL; + int i = 0; + struct cam_cci_ctrl cci_ctrl; + + if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (num_byte > I2C_REG_DATA_MAX)) { + CAM_ERR(CAM_SENSOR, "addr_type %d num_byte %d", addr_type, + num_byte); + return rc; + } + + buf = kzalloc(num_byte, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = buf; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; + cci_ctrl.status = -EFAULT; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + rc = cci_ctrl.status; + CAM_DBG(CAM_SENSOR, "addr = 0x%x, rc = %d", addr, rc); + for (i = 0; i < num_byte; i++) { + data[i] = buf[i]; + CAM_DBG(CAM_SENSOR, "Byte %d: Data: 0x%x\n", i, data[i]); + } + kfree(buf); + return rc; +} + +static int32_t cam_cci_i2c_write_table_cmd( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + enum cam_cci_cmd_type cmd) +{ + int32_t rc = -EINVAL; + struct cam_cci_ctrl cci_ctrl; + + if (!client || !write_setting) + return rc; + + if (write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + return rc; + + cci_ctrl.cmd = cmd; + cci_ctrl.cci_info = client->cci_client; + cci_ctrl.cfg.cci_i2c_write_cfg.reg_setting = + write_setting->reg_setting; + cci_ctrl.cfg.cci_i2c_write_cfg.data_type = write_setting->data_type; + cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = write_setting->addr_type; + cci_ctrl.cfg.cci_i2c_write_cfg.size = write_setting->size; + rc = v4l2_subdev_call(client->cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); + return rc; + } + rc = cci_ctrl.status; + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + + +int32_t cam_cci_i2c_write_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + return cam_cci_i2c_write_table_cmd(client, write_setting, + MSM_CCI_I2C_WRITE); +} + +int32_t cam_cci_i2c_write_continuous_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag) +{ + int32_t rc = 0; + + if (cam_sensor_i2c_write_flag == 1) + rc = cam_cci_i2c_write_table_cmd(client, write_setting, + MSM_CCI_I2C_WRITE_BURST); + else if (cam_sensor_i2c_write_flag == 0) + rc = cam_cci_i2c_write_table_cmd(client, write_setting, + MSM_CCI_I2C_WRITE_SEQ); + + return rc; +} + +static int32_t cam_cci_i2c_compare(struct cam_sensor_cci_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type) +{ + int32_t rc; + uint32_t reg_data = 0; + + rc = cam_cci_i2c_read(client, addr, ®_data, + addr_type, data_type); + if (rc < 0) + return rc; + + reg_data = reg_data & 0xFFFF; + if (data == (reg_data & ~data_mask)) + return I2C_COMPARE_MATCH; + return I2C_COMPARE_MISMATCH; +} + +int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type, + uint32_t delay_ms) +{ + int32_t rc = -EINVAL; + int32_t i = 0; + + CAM_DBG(CAM_SENSOR, "addr: 0x%x data: 0x%x dt: %d", + addr, data, data_type); + + if (delay_ms > MAX_POLL_DELAY_MS) { + CAM_ERR(CAM_SENSOR, "invalid delay = %d max_delay = %d", + delay_ms, MAX_POLL_DELAY_MS); + return -EINVAL; + } + for (i = 0; i < delay_ms; i++) { + rc = cam_cci_i2c_compare(client, + addr, data, data_mask, data_type, addr_type); + if (!rc) + return rc; + + usleep_range(1000, 1010); + } + + /* If rc is 1 then read is successful but poll is failure */ + if (rc == 1) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d(non-fatal)", rc); + + if (rc < 0) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d", rc); + + return rc; +} + +int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client, + uint16_t cci_cmd) +{ + int32_t rc = 0; + struct cam_cci_ctrl cci_ctrl; + + cci_ctrl.cmd = cci_cmd; + cci_ctrl.cci_info = cci_client; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed rc = %d", rc); + return rc; + } + return cci_ctrl.status; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h new file mode 100644 index 0000000000000000000000000000000000000000..def8be55bc8b1022037a247efdf61c779e138713 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -0,0 +1,174 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_I2C_H_ +#define _CAM_SENSOR_I2C_H_ + +#include <linux/delay.h> +#include <media/v4l2-subdev.h> +#include <media/cam_sensor.h> +#include "cam_cci_dev.h" +#include "cam_sensor_io.h" + +#define I2C_POLL_TIME_MS 5 +#define MAX_POLL_DELAY_MS 100 + +#define I2C_COMPARE_MATCH 0 +#define I2C_COMPARE_MISMATCH 1 + +#define I2C_REG_DATA_MAX (8*1024) + +/** + * @client: CCI client structure + * @data: I2C data + * @addr_type: I2c address type + * @data_type: I2C data type + * + * This API handles CCI read + */ +int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +/** + * @client: CCI client structure + * @addr: I2c address + * @data: I2C data + * @addr_type: I2c address type + * @data_type: I2c data type + * @num_byte: number of bytes + * + * This API handles CCI sequential read + */ +int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t num_byte); + +/** + * @client: CCI client structure + * @write_setting: I2C register setting + * + * This API handles CCI random write + */ +int32_t cam_cci_i2c_write_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting); + +/** + * @client: CCI client structure + * @write_setting: I2C register setting + * @cam_sensor_i2c_write_flag: burst or seq write + * + * This API handles CCI continuous write + */ +int32_t cam_cci_i2c_write_continuous_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag); + +/** + * @cci_client: CCI client structure + * @cci_cmd: CCI command type + * + * Does I2C call to I2C functionalities + */ +int32_t cam_sensor_cci_i2c_util(struct cam_sensor_cci_client *cci_client, + uint16_t cci_cmd); + +/** + * @client: CCI client structure + * @addr: I2C address + * @data: I2C data + * @data_mask: I2C data mask + * @data_type: I2C data type + * @addr_type: I2C addr type + * @delay_ms: Delay in milli seconds + * + * This API implements CCI based I2C poll + */ +int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type, + uint32_t delay_ms); + + +/** + * cam_qup_i2c_read : QUP based i2c read + * @client : QUP I2C client structure + * @data : I2C data + * @addr_type : I2c address type + * @data_type : I2C data type + * + * This API handles QUP I2C read + */ + +int32_t cam_qup_i2c_read(struct i2c_client *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +/** + * cam_qup_i2c_read_seq : QUP based I2C sequential read + * @client : QUP I2C client structure + * @data : I2C data + * @addr_type : I2c address type + * @num_bytes : number of bytes to read + * This API handles QUP I2C Sequential read + */ + +int32_t cam_qup_i2c_read_seq(struct i2c_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte); + +/** + * cam_qup_i2c_poll : QUP based I2C poll operation + * @client : QUP I2C client structure + * @addr : I2C address + * @data : I2C data + * @data_mask : I2C data mask + * @data_type : I2C data type + * @addr_type : I2C addr type + * @delay_ms : Delay in milli seconds + * + * This API implements QUP based I2C poll + */ + +int32_t cam_qup_i2c_poll(struct i2c_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms); + +/** + * cam_qup_i2c_write_table : QUP based I2C write random + * @client : QUP I2C client structure + * @write_setting : I2C register settings + * + * This API handles QUP I2C random write + */ + +int32_t cam_qup_i2c_write_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting); + +/** + * cam_qup_i2c_write_continuous_write: QUP based I2C write continuous(Burst/Seq) + * @client: QUP I2C client structure + * @write_setting: I2C register setting + * @cam_sensor_i2c_write_flag: burst or seq write + * + * This API handles QUP continuous write + */ +int32_t cam_qup_i2c_write_continuous_table( + struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag); + +#endif /*_CAM_SENSOR_I2C_H*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c new file mode 100644 index 0000000000000000000000000000000000000000..108c47923eb72e5c6d792dadeb054817ec481dfc --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_io.h" +#include "cam_sensor_i2c.h" + +int32_t camera_io_dev_poll(struct camera_io_master *io_master_info, + uint32_t addr, uint16_t data, uint32_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms) +{ + int16_t mask = data_mask & 0xFF; + + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_poll(io_master_info->cci_client, + addr, data, mask, data_type, addr_type, delay_ms); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_poll(io_master_info->client, + addr, data, data_mask, addr_type, data_type, + delay_ms); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} + +int32_t camera_io_dev_erase(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t size) +{ + int rc = 0; + + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (size == 0) + return rc; + + if (io_master_info->master_type == SPI_MASTER) { + CAM_DBG(CAM_SENSOR, "Calling SPI Erase"); + return cam_spi_erase(io_master_info, addr, + CAMERA_SENSOR_I2C_TYPE_WORD, size); + } else if (io_master_info->master_type == I2C_MASTER || + io_master_info->master_type == CCI_MASTER) { + CAM_ERR(CAM_SENSOR, "Erase not supported on master :%d", + io_master_info->master_type); + rc = -EINVAL; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + rc = -EINVAL; + } + return rc; +} + +int32_t camera_io_dev_read(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_read(io_master_info->cci_client, + addr, data, addr_type, data_type); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_read(io_master_info->client, + addr, data, addr_type, data_type); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_read(io_master_info, + addr, data, addr_type, data_type); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } + return 0; +} + +int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, int32_t num_bytes) +{ + if (io_master_info->master_type == CCI_MASTER) { + return cam_camera_cci_i2c_read_seq(io_master_info->cci_client, + addr, data, addr_type, data_type, num_bytes); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_read_seq(io_master_info->client, + addr, data, addr_type, num_bytes); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_read_seq(io_master_info, + addr, data, addr_type, num_bytes); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_seq(io_master_info, + addr, data, addr_type, num_bytes); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } + return 0; +} + +int32_t camera_io_dev_write(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + if (!write_setting || !io_master_info) { + CAM_ERR(CAM_SENSOR, + "Input parameters not valid ws: %pK ioinfo: %pK", + write_setting, io_master_info); + return -EINVAL; + } + + if (!write_setting->reg_setting) { + CAM_ERR(CAM_SENSOR, "Invalid Register Settings"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_write_table(io_master_info, + write_setting); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_write_table(io_master_info, + write_setting); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_table(io_master_info, + write_setting); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} + +int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag) +{ + if (!write_setting || !io_master_info) { + CAM_ERR(CAM_SENSOR, + "Input parameters not valid ws: %pK ioinfo: %pK", + write_setting, io_master_info); + return -EINVAL; + } + + if (!write_setting->reg_setting) { + CAM_ERR(CAM_SENSOR, "Invalid Register Settings"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_cci_i2c_write_continuous_table(io_master_info, + write_setting, cam_sensor_i2c_write_flag); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_write_continuous_table(io_master_info, + write_setting, cam_sensor_i2c_write_flag); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_table(io_master_info, + write_setting); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} + +int32_t camera_io_init(struct camera_io_master *io_master_info) +{ + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + io_master_info->cci_client->cci_subdev = + cam_cci_get_subdev(io_master_info->cci_client->cci_device); + return cam_sensor_cci_i2c_util(io_master_info->cci_client, + MSM_CCI_INIT); + } else if ((io_master_info->master_type == I2C_MASTER) || + (io_master_info->master_type == SPI_MASTER)) { + return 0; + } + + return -EINVAL; +} + +int32_t camera_io_release(struct camera_io_master *io_master_info) +{ + if (!io_master_info) { + CAM_ERR(CAM_SENSOR, "Invalid Args"); + return -EINVAL; + } + + if (io_master_info->master_type == CCI_MASTER) { + return cam_sensor_cci_i2c_util(io_master_info->cci_client, + MSM_CCI_RELEASE); + } else if ((io_master_info->master_type == I2C_MASTER) || + (io_master_info->master_type == SPI_MASTER)) { + return 0; + } + + return -EINVAL; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h new file mode 100644 index 0000000000000000000000000000000000000000..f70709997e692dc503887bb887035ee975c72d65 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_IO_H_ +#define _CAM_SENSOR_IO_H_ + +#include <media/cam_sensor.h> + +#include "cam_sensor_cmn_header.h" + +#define CCI_MASTER 1 +#define I2C_MASTER 2 +#define SPI_MASTER 3 + +/** + * @master_type: CCI master type + * @client: I2C client information structure + * @cci_client: CCI client information structure + * @spi_client: SPI client information structure + */ +struct camera_io_master { + int master_type; + struct i2c_client *client; + struct cam_sensor_cci_client *cci_client; + struct cam_sensor_spi_client *spi_client; +}; + +/** + * @io_master_info: I2C/SPI master information + * @addr: I2C address + * @data: I2C data + * @addr_type: I2C addr_type + * @data_type: I2C data type + * + * This API abstracts read functionality based on master type + */ +int32_t camera_io_dev_read(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +/** + * @io_master_info: I2C/SPI master information + * @addr: I2C address + * @data: I2C data + * @addr_type: I2C addr type + * @data_type: I2C data type + * @num_bytes: number of bytes + * + * This API abstracts read functionality based on master type + */ +int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + int32_t num_bytes); + +/** + * @io_master_info: I2C/SPI master information + * + * This API initializes the I2C/SPI master based on master type + */ +int32_t camera_io_init(struct camera_io_master *io_master_info); + +/** + * @io_master_info: I2C/SPI master information + * + * This API releases the I2C/SPI master based on master type + */ +int32_t camera_io_release(struct camera_io_master *io_master_info); + +/** + * @io_master_info: I2C/SPI master information + * @write_setting: write settings information + * + * This API abstracts write functionality based on master type + */ +int32_t camera_io_dev_write(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting); + +/** + * @io_master_info: I2C/SPI master information + * @write_setting: write settings information + * @cam_sensor_i2c_write_flag: differentiate between burst & seq + * + * This API abstracts write functionality based on master type and + * write flag for continuous write + */ +int32_t camera_io_dev_write_continuous(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting, + uint8_t cam_sensor_i2c_write_flag); + +int32_t camera_io_dev_erase(struct camera_io_master *io_master_info, + uint32_t addr, uint32_t size); +/** + * @io_master_info: I2C/SPI master information + * @addr: I2C address + * @data: I2C data + * @data_mask: I2C data mask + * @data_type: I2C data type + * @addr_type: I2C address type + * @delay_ms: delay in milli seconds + * + * This API abstracts poll functionality based on master type + */ +int32_t camera_io_dev_poll(struct camera_io_master *io_master_info, + uint32_t addr, uint16_t data, uint32_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms); + +#include "cam_sensor_i2c.h" +#include "cam_sensor_spi.h" +#endif /* _CAM_SENSOR_IO_H_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..a9fd0881aabf94aead46402abfc178b0bfb87c64 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sensor_cmn_header.h" +#include "cam_sensor_i2c.h" +#include "cam_sensor_io.h" + +#define I2C_REG_DATA_MAX (8*1024) +#define I2C_REG_MAX_BUF_SIZE 8 + +static int32_t cam_qup_i2c_rxdata( + struct i2c_client *dev_client, unsigned char *rxdata, + enum camera_sensor_i2c_type addr_type, + int data_length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->addr >> 1; + struct i2c_msg msgs[] = { + { + .addr = saddr, + .flags = 0, + .len = addr_type, + .buf = rxdata, + }, + { + .addr = saddr, + .flags = I2C_M_RD, + .len = data_length, + .buf = rxdata, + }, + }; + rc = i2c_transfer(dev_client->adapter, msgs, 2); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr); + return rc; +} + + +static int32_t cam_qup_i2c_txdata( + struct camera_io_master *dev_client, unsigned char *txdata, + int length) +{ + int32_t rc = 0; + uint16_t saddr = dev_client->client->addr >> 1; + struct i2c_msg msg[] = { + { + .addr = saddr, + .flags = 0, + .len = length, + .buf = txdata, + }, + }; + rc = i2c_transfer(dev_client->client->adapter, msg, 1); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed 0x%x", saddr); + return rc; +} + +int32_t cam_qup_i2c_read(struct i2c_client *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int32_t rc = -EINVAL; + unsigned char *buf = NULL; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "Failed with addr/data_type verfication"); + return rc; + } + + buf = kzalloc(addr_type + data_type, GFP_KERNEL); + + if (!buf) + return -ENOMEM; + + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = addr >> 8; + buf[1] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = addr >> 16; + buf[1] = addr >> 8; + buf[2] = addr; + } else { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + buf[2] = addr >> 8; + buf[3] = addr; + } + + rc = cam_qup_i2c_rxdata(client, buf, addr_type, data_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + goto read_fail; + } + + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + *data = buf[0]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) + *data = buf[0] << 8 | buf[1]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) + *data = buf[0] << 16 | buf[1] << 8 | buf[2]; + else + *data = buf[0] << 24 | buf[1] << 16 | + buf[2] << 8 | buf[3]; + + CAM_DBG(CAM_SENSOR, "addr = 0x%x data: 0x%x", addr, *data); +read_fail: + kfree(buf); + buf = NULL; + return rc; +} + +int32_t cam_qup_i2c_read_seq(struct i2c_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte) +{ + int32_t rc = -EFAULT; + unsigned char *buf = NULL; + int i; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "Failed with addr_type verification"); + return rc; + } + + if ((num_byte == 0) || (num_byte > I2C_REG_DATA_MAX)) { + CAM_ERR(CAM_SENSOR, "num_byte:0x%x max supported:0x%x", + num_byte, I2C_REG_DATA_MAX); + return rc; + } + + buf = kzalloc(addr_type + num_byte, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = addr >> BITS_PER_BYTE; + buf[1] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = addr >> 16; + buf[1] = addr >> 8; + buf[2] = addr; + } else { + buf[0] = addr >> 24; + buf[1] = addr >> 16; + buf[2] = addr >> 8; + buf[3] = addr; + } + + rc = cam_qup_i2c_rxdata(client, buf, addr_type, num_byte); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + goto read_seq_fail; + } + + for (i = 0; i < num_byte; i++) + data[i] = buf[i]; + +read_seq_fail: + kfree(buf); + buf = NULL; + return rc; +} + +static int32_t cam_qup_i2c_compare(struct i2c_client *client, + uint32_t addr, uint32_t data, uint16_t data_mask, + enum camera_sensor_i2c_type data_type, + enum camera_sensor_i2c_type addr_type) +{ + int32_t rc; + uint32_t reg_data = 0; + + rc = cam_qup_i2c_read(client, addr, ®_data, + addr_type, data_type); + if (rc < 0) + return rc; + + reg_data = reg_data & 0xFFFF; + if (data != (reg_data & ~data_mask)) + return I2C_COMPARE_MISMATCH; + + return I2C_COMPARE_MATCH; +} + +int32_t cam_qup_i2c_poll(struct i2c_client *client, + uint32_t addr, uint16_t data, uint16_t data_mask, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t delay_ms) +{ + int32_t rc = 0; + int i = 0; + + if ((delay_ms > MAX_POLL_DELAY_MS) || (delay_ms == 0)) { + CAM_ERR(CAM_SENSOR, "invalid delay = %d max_delay = %d", + delay_ms, MAX_POLL_DELAY_MS); + return -EINVAL; + } + + if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) + return -EINVAL; + + for (i = 0; i < delay_ms; i++) { + rc = cam_qup_i2c_compare(client, + addr, data, data_mask, data_type, addr_type); + if (rc == I2C_COMPARE_MATCH) + return rc; + + usleep_range(1000, 1010); + } + /* If rc is MISMATCH then read is successful but poll is failure */ + if (rc == I2C_COMPARE_MISMATCH) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d(non-fatal)", rc); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "poll failed rc=%d", rc); + + return rc; +} + +static int32_t cam_qup_i2c_write(struct camera_io_master *client, + struct cam_sensor_i2c_reg_array *reg_setting, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int32_t rc = 0; + unsigned char *buf = NULL; + uint8_t len = 0; + + buf = kzalloc(I2C_REG_MAX_BUF_SIZE, GFP_KERNEL | GFP_DMA); + if (!buf) { + CAM_ERR(CAM_SENSOR, "Buffer memory allocation failed"); + return -ENOMEM; + } + + CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d", + reg_setting->reg_addr, data_type); + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + len = 1; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = reg_setting->reg_addr >> 8; + buf[1] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]); + len = 2; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = reg_setting->reg_addr >> 16; + buf[1] = reg_setting->reg_addr >> 8; + buf[2] = reg_setting->reg_addr; + len = 3; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[0] = reg_setting->reg_addr >> 24; + buf[1] = reg_setting->reg_addr >> 16; + buf[2] = reg_setting->reg_addr >> 8; + buf[3] = reg_setting->reg_addr; + len = 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); + rc = -EINVAL; + goto deallocate_buffer; + } + + CAM_DBG(CAM_SENSOR, "Data: 0x%x", reg_setting->reg_data); + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[len] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + len += 1; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[len] = reg_setting->reg_data >> 8; + buf[len+1] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]); + len += 2; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[len] = reg_setting->reg_data >> 16; + buf[len + 1] = reg_setting->reg_data >> 8; + buf[len + 2] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+2, buf[len+2]); + len += 3; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[len] = reg_setting->reg_data >> 24; + buf[len + 1] = reg_setting->reg_data >> 16; + buf[len + 2] = reg_setting->reg_data >> 8; + buf[len + 3] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+2, buf[len+2]); + CAM_DBG(CAM_SENSOR, "Byte %d: 0x%x", len+3, buf[len+3]); + len += 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Data Type"); + rc = -EINVAL; + goto deallocate_buffer; + } + + rc = cam_qup_i2c_txdata(client, buf, len); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + +deallocate_buffer: + kfree(buf); + return rc; +} + +int32_t cam_qup_i2c_write_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = -EINVAL; + struct cam_sensor_i2c_reg_array *reg_setting; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))) + return rc; + + reg_setting = write_setting->reg_setting; + + for (i = 0; i < write_setting->size; i++) { + CAM_DBG(CAM_SENSOR, "addr 0x%x data 0x%x", + reg_setting->reg_addr, reg_setting->reg_data); + + rc = cam_qup_i2c_write(client, reg_setting, + write_setting->addr_type, write_setting->data_type); + if (rc < 0) + break; + reg_setting++; + } + + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + +static int32_t cam_qup_i2c_write_seq(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = 0; + struct cam_sensor_i2c_reg_array *reg_setting; + + reg_setting = write_setting->reg_setting; + + for (i = 0; i < write_setting->size; i++) { + reg_setting->reg_addr += i; + rc = cam_qup_i2c_write(client, reg_setting, + write_setting->addr_type, write_setting->data_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Sequential i2c write failed: rc: %d", rc); + break; + } + reg_setting++; + } + + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, (write_setting->delay + * 1000) + 1000); + + return rc; +} + +static int32_t cam_qup_i2c_write_burst(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int32_t rc = 0; + uint32_t len = 0; + unsigned char *buf = NULL; + struct cam_sensor_i2c_reg_array *reg_setting; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + + buf = kzalloc((write_setting->addr_type + + (write_setting->size * write_setting->data_type)), + GFP_KERNEL); + + if (!buf) { + CAM_ERR(CAM_SENSOR, "BUF is NULL"); + return -ENOMEM; + } + + reg_setting = write_setting->reg_setting; + addr_type = write_setting->addr_type; + data_type = write_setting->data_type; + + CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d", + reg_setting->reg_addr, data_type); + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + len = 1; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = reg_setting->reg_addr >> 8; + buf[1] = reg_setting->reg_addr; + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, "byte %d: 0x%x", len+1, buf[len+1]); + len = 2; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = reg_setting->reg_addr >> 16; + buf[1] = reg_setting->reg_addr >> 8; + buf[2] = reg_setting->reg_addr; + len = 3; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[0] = reg_setting->reg_addr >> 24; + buf[1] = reg_setting->reg_addr >> 16; + buf[2] = reg_setting->reg_addr >> 8; + buf[3] = reg_setting->reg_addr; + len = 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); + rc = -EINVAL; + goto free_res; + } + + for (i = 0; i < write_setting->size; i++) { + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[len] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + len += 1; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[len] = reg_setting->reg_data >> 8; + buf[len+1] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+1, buf[len+1]); + len += 2; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[len] = reg_setting->reg_data >> 16; + buf[len + 1] = reg_setting->reg_data >> 8; + buf[len + 2] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+2, buf[len+2]); + len += 3; + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) { + buf[len] = reg_setting->reg_data >> 24; + buf[len + 1] = reg_setting->reg_data >> 16; + buf[len + 2] = reg_setting->reg_data >> 8; + buf[len + 3] = reg_setting->reg_data; + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len, buf[len]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+1, buf[len+1]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+2, buf[len+2]); + CAM_DBG(CAM_SENSOR, + "Byte %d: 0x%x", len+3, buf[len+3]); + len += 4; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Data Type"); + rc = -EINVAL; + goto free_res; + } + reg_setting++; + } + + if (len > (write_setting->addr_type + + (write_setting->size * write_setting->data_type))) { + CAM_ERR(CAM_SENSOR, "Invalid Length: %u | Expected length: %u", + len, (write_setting->addr_type + + (write_setting->size * write_setting->data_type))); + rc = -EINVAL; + goto free_res; + } + + rc = cam_qup_i2c_txdata(client, buf, len); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + +free_res: + kfree(buf); + return rc; +} + +int32_t cam_qup_i2c_write_continuous_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_settings, + uint8_t cam_sensor_i2c_write_flag) +{ + int32_t rc = 0; + + if (!client || !write_settings) + return -EINVAL; + + if ((write_settings->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_settings->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || (write_settings->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || write_settings->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))) + return -EINVAL; + + if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_BURST) + rc = cam_qup_i2c_write_burst(client, write_settings); + else if (cam_sensor_i2c_write_flag == CAM_SENSOR_I2C_WRITE_SEQ) + rc = cam_qup_i2c_write_seq(client, write_settings); + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..cf6987b09eacfb2c7f483daa29a785e97923595d --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c @@ -0,0 +1,615 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/dma-contiguous.h> +#include "cam_sensor_spi.h" +#include "cam_debug_util.h" + +static int cam_spi_txfr(struct spi_device *spi, char *txbuf, + char *rxbuf, int num_byte) +{ + struct spi_transfer txfr; + struct spi_message msg; + + memset(&txfr, 0, sizeof(txfr)); + txfr.tx_buf = txbuf; + txfr.rx_buf = rxbuf; + txfr.len = num_byte; + spi_message_init(&msg); + spi_message_add_tail(&txfr, &msg); + + return spi_sync(spi, &msg); +} + +static int cam_spi_txfr_read(struct spi_device *spi, char *txbuf, + char *rxbuf, int txlen, int rxlen) +{ + struct spi_transfer tx; + struct spi_transfer rx; + struct spi_message m; + + memset(&tx, 0, sizeof(tx)); + memset(&rx, 0, sizeof(rx)); + tx.tx_buf = txbuf; + rx.rx_buf = rxbuf; + tx.len = txlen; + rx.len = rxlen; + spi_message_init(&m); + spi_message_add_tail(&tx, &m); + spi_message_add_tail(&rx, &m); + return spi_sync(spi, &m); +} + +/** + * cam_set_addr() - helper function to set transfer address + * @addr: device address + * @addr_len: the addr field length of an instruction + * @type: type (i.e. byte-length) of @addr + * @str: shifted address output, must be zeroed when passed in + * + * This helper function sets @str based on the addr field length of an + * instruction and the data length. + */ +static void cam_set_addr(uint32_t addr, uint8_t addr_len, + enum camera_sensor_i2c_type addr_type, + char *str) +{ + if (!addr_len) + return; + + if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + str[0] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + str[0] = addr >> 8; + str[1] = addr; + } else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) { + str[0] = addr >> 16; + str[1] = addr >> 8; + str[2] = addr; + } else { + str[0] = addr >> 24; + str[1] = addr >> 16; + str[2] = addr >> 8; + str[3] = addr; + } +} + +/** + * cam_spi_tx_helper() - wrapper for SPI transaction + * @client: io client + * @inst: inst of this transaction + * @addr: device addr following the inst + * @data: output byte array (could be NULL) + * @num_byte: size of @data + * @tx, rx: optional transfer buffer. It must be at least header + * + @num_byte long. + * + * This is the core function for SPI transaction, except for writes. It first + * checks address type, then allocates required memory for tx/rx buffers. + * It sends out <opcode><addr>, and optionally receives @num_byte of response, + * if @data is not NULL. This function does not check for wait conditions, + * and will return immediately once bus transaction finishes. + * + * This function will allocate buffers of header + @num_byte long. For + * large transfers, the allocation could fail. External buffer @tx, @rx + * should be passed in to bypass allocation. The size of buffer should be + * at least header + num_byte long. Since buffer is managed externally, + * @data will be ignored, and read results will be in @rx. + * @tx, @rx also can be used for repeated transfers to improve performance. + */ +static int32_t cam_spi_tx_helper(struct camera_io_master *client, + struct cam_camera_spi_inst *inst, uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte, char *tx, char *rx) +{ + int32_t rc = -EINVAL; + struct spi_device *spi = client->spi_client->spi_master; + struct device *dev = NULL; + char *ctx = NULL, *crx = NULL; + uint32_t len, hlen; + uint8_t retries = client->spi_client->retries; + uint32_t txr = 0, rxr = 0; + struct page *page_tx = NULL, *page_rx = NULL; + + hlen = cam_camera_spi_get_hlen(inst); + len = hlen + num_byte; + dev = &(spi->dev); + + if (!dev) { + CAM_ERR(CAM_SENSOR, "Invalid arguments"); + return -EINVAL; + } + + if (tx) { + ctx = tx; + } else { + txr = PAGE_ALIGN(len) >> PAGE_SHIFT; + page_tx = cma_alloc(dev_get_cma_area(dev), + txr, 0, GFP_KERNEL); + if (!page_tx) + return -ENOMEM; + + ctx = page_address(page_tx); + } + + if (num_byte) { + if (rx) { + crx = rx; + } else { + rxr = PAGE_ALIGN(len) >> PAGE_SHIFT; + page_rx = cma_alloc(dev_get_cma_area(dev), + rxr, 0, GFP_KERNEL); + if (!page_rx) { + if (!tx) + cma_release(dev_get_cma_area(dev), + page_tx, txr); + + return -ENOMEM; + } + crx = page_address(page_rx); + } + } else { + crx = NULL; + } + + ctx[0] = inst->opcode; + cam_set_addr(addr, inst->addr_len, addr_type, ctx + 1); + while ((rc = cam_spi_txfr(spi, ctx, crx, len)) && retries) { + retries--; + msleep(client->spi_client->retry_delay); + } + if (rc < 0) { + CAM_ERR(CAM_EEPROM, "failed: spi txfr rc %d", rc); + goto out; + } + if (data && num_byte && !rx) + memcpy(data, crx + hlen, num_byte); + +out: + if (!tx) + cma_release(dev_get_cma_area(dev), page_tx, txr); + if (!rx) + cma_release(dev_get_cma_area(dev), page_rx, rxr); + return rc; +} + +static int32_t cam_spi_tx_read(struct camera_io_master *client, + struct cam_camera_spi_inst *inst, uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint32_t num_byte, char *tx, char *rx) +{ + int32_t rc = -EINVAL; + struct spi_device *spi = client->spi_client->spi_master; + char *ctx = NULL, *crx = NULL; + uint32_t hlen; + uint8_t retries = client->spi_client->retries; + + hlen = cam_camera_spi_get_hlen(inst); + if (tx) { + ctx = tx; + } else { + ctx = kzalloc(hlen, GFP_KERNEL | GFP_DMA); + if (!ctx) + return -ENOMEM; + } + if (num_byte) { + if (rx) { + crx = rx; + } else { + crx = kzalloc(num_byte, GFP_KERNEL | GFP_DMA); + if (!crx) { + if (!tx) + kfree(ctx); + return -ENOMEM; + } + } + } else { + crx = NULL; + } + + ctx[0] = inst->opcode; + cam_set_addr(addr, inst->addr_len, addr_type, ctx + 1); + + CAM_DBG(CAM_EEPROM, "tx(%u): %02x %02x %02x %02x", hlen, ctx[0], + ctx[1], ctx[2], ctx[3]); + while ((rc = cam_spi_txfr_read(spi, ctx, crx, hlen, num_byte)) + && retries) { + retries--; + msleep(client->spi_client->retry_delay); + } + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + goto out; + } + if (data && num_byte && !rx) + memcpy(data, crx, num_byte); +out: + if (!tx) + kfree(ctx); + if (!rx) + kfree(crx); + return rc; +} + +int cam_spi_read(struct camera_io_master *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + int rc = -EINVAL; + uint8_t temp[CAMERA_SENSOR_I2C_TYPE_MAX]; + + if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX + || data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID + || data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "Failed with addr/data_type verification"); + return rc; + } + + rc = cam_spi_tx_read(client, + &client->spi_client->cmd_tbl.read, addr, &temp[0], + addr_type, data_type, NULL, NULL); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + return rc; + } + + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) + *data = temp[0]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) + *data = (temp[0] << BITS_PER_BYTE) | temp[1]; + else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) + *data = (temp[0] << 16 | temp[1] << 8 | temp[2]); + else + *data = (temp[0] << 24 | temp[1] << 16 | temp[2] << 8 | + temp[3]); + + CAM_DBG(CAM_SENSOR, "addr 0x%x, data %u", addr, *data); + return rc; +} + +int32_t cam_spi_read_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, int32_t num_bytes) +{ + if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) { + CAM_ERR(CAM_SENSOR, "Failed with addr_type verification"); + return -EINVAL; + } + + if (num_bytes == 0) { + CAM_ERR(CAM_SENSOR, "num_byte: 0x%x", num_bytes); + return -EINVAL; + } + + CAM_DBG(CAM_SENSOR, "Read Seq addr: 0x%x NB:%d", + addr, num_bytes); + return cam_spi_tx_helper(client, + &client->spi_client->cmd_tbl.read_seq, addr, data, + addr_type, num_bytes, NULL, NULL); +} + +int cam_spi_query_id(struct camera_io_master *client, + uint32_t addr, enum camera_sensor_i2c_type addr_type, + uint8_t *data, uint32_t num_byte) +{ + CAM_DBG(CAM_SENSOR, "SPI Queryid : 0x%x, addr: 0x%x", + client->spi_client->cmd_tbl.query_id, addr); + return cam_spi_tx_helper(client, + &client->spi_client->cmd_tbl.query_id, + addr, data, addr_type, num_byte, NULL, NULL); +} + +static int32_t cam_spi_read_status_reg( + struct camera_io_master *client, uint8_t *status, + enum camera_sensor_i2c_type addr_type) +{ + struct cam_camera_spi_inst *rs = + &client->spi_client->cmd_tbl.read_status; + + if (rs->addr_len != 0) { + CAM_ERR(CAM_SENSOR, "not implemented yet"); + return -ENXIO; + } + return cam_spi_tx_helper(client, rs, 0, status, + addr_type, 1, NULL, NULL); +} + +static int32_t cam_spi_device_busy(struct camera_io_master *client, + uint8_t *busy, enum camera_sensor_i2c_type addr_type) +{ + int rc; + uint8_t st = 0; + + rc = cam_spi_read_status_reg(client, &st, addr_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed to read status reg"); + return rc; + } + *busy = st & client->spi_client->busy_mask; + return 0; +} + +static int32_t cam_spi_wait(struct camera_io_master *client, + struct cam_camera_spi_inst *inst, + enum camera_sensor_i2c_type addr_type) +{ + uint8_t busy; + int i, rc; + + CAM_DBG(CAM_SENSOR, "op 0x%x wait start", inst->opcode); + for (i = 0; i < inst->delay_count; i++) { + rc = cam_spi_device_busy(client, &busy, addr_type); + if (rc < 0) + return rc; + if (!busy) + break; + msleep(inst->delay_intv); + CAM_DBG(CAM_SENSOR, "op 0x%x wait", inst->opcode); + } + if (i > inst->delay_count) { + CAM_ERR(CAM_SENSOR, "op %x timed out", inst->opcode); + return -ETIMEDOUT; + } + CAM_DBG(CAM_SENSOR, "op %x finished", inst->opcode); + return 0; +} + +static int32_t cam_spi_write_enable(struct camera_io_master *client, + enum camera_sensor_i2c_type addr_type) +{ + struct cam_camera_spi_inst *we = + &client->spi_client->cmd_tbl.write_enable; + int rc; + + if (we->opcode == 0) + return 0; + if (we->addr_len != 0) { + CAM_ERR(CAM_SENSOR, "not implemented yet"); + return -EINVAL; + } + rc = cam_spi_tx_helper(client, we, 0, NULL, addr_type, + 0, NULL, NULL); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "write enable failed"); + return rc; +} + +/** + * cam_spi_page_program() - core function to perform write + * @client: need for obtaining SPI device + * @addr: address to program on device + * @data: data to write + * @len: size of data + * @tx: tx buffer, size >= header + len + * + * This function performs SPI write, and has no boundary check. Writing range + * should not cross page boundary, or data will be corrupted. Transaction is + * guaranteed to be finished when it returns. This function should never be + * used outside cam_spi_write_seq(). + */ +static int32_t cam_spi_page_program(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + uint16_t len, uint8_t *tx) +{ + int rc; + struct cam_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + struct spi_device *spi = client->spi_client->spi_master; + uint8_t retries = client->spi_client->retries; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + + CAM_DBG(CAM_SENSOR, "addr 0x%x, size 0x%x", addr, len); + rc = cam_spi_write_enable(client, addr_type); + if (rc < 0) + return rc; + memset(tx, 0, header_len); + tx[0] = pg->opcode; + cam_set_addr(addr, pg->addr_len, addr_type, tx + 1); + memcpy(tx + header_len, data, len); + CAM_DBG(CAM_SENSOR, "tx(%u): %02x %02x %02x %02x", + len, tx[0], tx[1], tx[2], tx[3]); + while ((rc = spi_write(spi, tx, len + header_len)) && retries) { + rc = cam_spi_wait(client, pg, addr_type); + msleep(client->spi_client->retry_delay); + retries--; + } + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed %d", rc); + return rc; + } + rc = cam_spi_wait(client, pg, addr_type); + return rc; +} + +int cam_spi_write(struct camera_io_master *client, + uint32_t addr, uint32_t data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type) +{ + struct cam_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + uint16_t len = 0; + char buf[CAMERA_SENSOR_I2C_TYPE_MAX]; + char *tx; + int rc = -EINVAL; + + if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (data_type != CAMERA_SENSOR_I2C_TYPE_MAX)) + return rc; + + CAM_DBG(CAM_EEPROM, "Data: 0x%x", data); + len = header_len + (uint8_t)data_type; + tx = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!tx) + goto NOMEM; + + if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { + buf[0] = data; + CAM_DBG(CAM_EEPROM, "Byte %d: 0x%x", len, buf[0]); + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + buf[0] = (data >> BITS_PER_BYTE) & 0x00FF; + buf[1] = (data & 0x00FF); + } else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) { + buf[0] = (data >> 16) & 0x00FF; + buf[1] = (data >> 8) & 0x00FF; + buf[2] = (data & 0x00FF); + } else { + buf[0] = (data >> 24) & 0x00FF; + buf[1] = (data >> 16) & 0x00FF; + buf[2] = (data >> 8) & 0x00FF; + buf[3] = (data & 0x00FF); + } + + rc = cam_spi_page_program(client, addr, buf, + addr_type, data_type, tx); + if (rc < 0) + goto ERROR; + goto OUT; +NOMEM: + CAM_ERR(CAM_SENSOR, "memory allocation failed"); + return -ENOMEM; +ERROR: + CAM_ERR(CAM_SENSOR, "error write"); +OUT: + kfree(tx); + return rc; +} + +int32_t cam_spi_write_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, uint32_t num_byte) +{ + struct cam_camera_spi_inst *pg = + &client->spi_client->cmd_tbl.page_program; + const uint32_t page_size = client->spi_client->page_size; + uint8_t header_len = sizeof(pg->opcode) + pg->addr_len + pg->dummy_len; + uint16_t len; + uint32_t cur_len, end; + char *tx, *pdata = data; + int rc = -EINVAL; + + if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) || + (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID)) + return rc; + /* single page write */ + if ((addr % page_size) + num_byte <= page_size) { + len = header_len + num_byte; + tx = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!tx) + goto NOMEM; + rc = cam_spi_page_program(client, addr, data, addr_type, + num_byte, tx); + if (rc < 0) + goto ERROR; + goto OUT; + } + /* multi page write */ + len = header_len + page_size; + tx = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!tx) + goto NOMEM; + while (num_byte) { + end = min(page_size, (addr % page_size) + num_byte); + cur_len = end - (addr % page_size); + CAM_ERR(CAM_SENSOR, "Addr: 0x%x curr_len: 0x%x pgSize: %d", + addr, cur_len, page_size); + rc = cam_spi_page_program(client, addr, pdata, addr_type, + cur_len, tx); + if (rc < 0) + goto ERROR; + addr += cur_len; + pdata += cur_len; + num_byte -= cur_len; + } + goto OUT; +NOMEM: + pr_err("%s: memory allocation failed\n", __func__); + return -ENOMEM; +ERROR: + pr_err("%s: error write\n", __func__); +OUT: + kfree(tx); + return rc; +} + +int cam_spi_write_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + int i; + int rc = -EFAULT; + struct cam_sensor_i2c_reg_array *reg_setting; + uint16_t client_addr_type; + enum camera_sensor_i2c_type addr_type; + + if (!client || !write_setting) + return rc; + + if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID) + || (write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)) + return rc; + + reg_setting = write_setting->reg_setting; + client_addr_type = write_setting->addr_type; + addr_type = write_setting->addr_type; + for (i = 0; i < write_setting->size; i++) { + CAM_DBG(CAM_SENSOR, "addr %x data %x", + reg_setting->reg_addr, reg_setting->reg_data); + rc = cam_spi_write(client, + reg_setting->reg_addr, reg_setting->reg_data, + write_setting->addr_type, write_setting->data_type); + if (rc < 0) + break; + reg_setting++; + } + if (write_setting->delay > 20) + msleep(write_setting->delay); + else if (write_setting->delay) + usleep_range(write_setting->delay * 1000, + (write_setting->delay + * 1000) + 1000); + addr_type = client_addr_type; + return rc; +} + +int cam_spi_erase(struct camera_io_master *client, uint32_t addr, + enum camera_sensor_i2c_type addr_type, uint32_t size) +{ + struct cam_camera_spi_inst *se = &client->spi_client->cmd_tbl.erase; + int rc = 0; + uint32_t cur; + uint32_t end = addr + size; + uint32_t erase_size = client->spi_client->erase_size; + + end = addr + size; + for (cur = rounddown(addr, erase_size); cur < end; cur += erase_size) { + CAM_ERR(CAM_SENSOR, "%s: erasing 0x%x size: %d\n", + __func__, cur, erase_size); + rc = cam_spi_write_enable(client, addr_type); + if (rc < 0) + return rc; + rc = cam_spi_tx_helper(client, se, cur, NULL, addr_type, 0, + NULL, NULL); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "%s: erase failed\n", __func__); + return rc; + } + rc = cam_spi_wait(client, se, addr_type); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "%s: erase timedout\n", __func__); + return rc; + } + } + + return rc; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h new file mode 100644 index 0000000000000000000000000000000000000000..73d7ea9456bad9b33adea82ff5d818d442824763 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_SPI_H_ +#define _CAM_SENSOR_SPI_H_ + +#include <linux/spi/spi.h> +#include <linux/cma.h> +#include <media/cam_sensor.h> +#include "cam_sensor_i2c.h" + +#define MAX_SPI_SIZE 110 +#define SPI_DYNAMIC_ALLOC + +struct cam_camera_spi_inst { + uint8_t opcode; + uint8_t addr_len; + uint8_t dummy_len; + uint8_t delay_intv; + uint8_t delay_count; +}; + +struct cam_spi_write_burst_data { + u8 data_msb; + u8 data_lsb; +}; + +struct cam_spi_write_burst_packet { + u8 cmd; + u8 addr_msb; + u8 addr_lsb; + struct cam_spi_write_burst_data data_arr[MAX_SPI_SIZE]; +}; + +struct cam_camera_burst_info { + uint32_t burst_addr; + uint32_t burst_start; + uint32_t burst_len; + uint32_t chunk_size; +}; + +struct cam_camera_spi_inst_tbl { + struct cam_camera_spi_inst read; + struct cam_camera_spi_inst read_seq; + struct cam_camera_spi_inst query_id; + struct cam_camera_spi_inst page_program; + struct cam_camera_spi_inst write_enable; + struct cam_camera_spi_inst read_status; + struct cam_camera_spi_inst erase; +}; + +struct cam_sensor_spi_client { + struct spi_device *spi_master; + struct cam_camera_spi_inst_tbl cmd_tbl; + uint8_t device_id0; + uint8_t device_id1; + uint8_t mfr_id0; + uint8_t mfr_id1; + uint8_t retry_delay; + uint8_t retries; + uint8_t busy_mask; + uint16_t page_size; + uint32_t erase_size; +}; +static __always_inline +uint16_t cam_camera_spi_get_hlen(struct cam_camera_spi_inst *inst) +{ + return sizeof(inst->opcode) + inst->addr_len + inst->dummy_len; +} + +int cam_spi_read(struct camera_io_master *client, + uint32_t addr, uint32_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +int cam_spi_read_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + int32_t num_bytes); + +int cam_spi_query_id(struct camera_io_master *client, + uint32_t addr, + enum camera_sensor_i2c_type addr_type, + uint8_t *data, uint32_t num_byte); + +int cam_spi_write(struct camera_io_master *client, + uint32_t addr, uint32_t data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type); + +int cam_spi_write_table(struct camera_io_master *client, + struct cam_sensor_i2c_reg_setting *write_setting); + +int cam_spi_erase(struct camera_io_master *client, + uint32_t addr, enum camera_sensor_i2c_type addr_type, + uint32_t size); + +int cam_spi_write_seq(struct camera_io_master *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, uint32_t num_byte); +#endif diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/Makefile b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d822b2a733cfdc97b16c2fb333dd7525bc73d43c --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_sensor_io +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_cci +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_sensor_module/cam_res_mgr +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_cpas/include +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_util.o diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h new file mode 100755 index 0000000000000000000000000000000000000000..b9368fbfa9ba6e8342e3d5ad9d2152a8b7344d02 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_CMN_HEADER_ +#define _CAM_SENSOR_CMN_HEADER_ + +#include <linux/i2c.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/list.h> +#include <media/cam_sensor.h> +#include <media/cam_req_mgr.h> + +#define MAX_REGULATOR 5 +#define MAX_POWER_CONFIG 12 + +#define MAX_PER_FRAME_ARRAY 32 +#define BATCH_SIZE_MAX 16 + +#define CAM_SENSOR_NAME "cam-sensor" +#define CAM_ACTUATOR_NAME "cam-actuator" +#define CAM_CSIPHY_NAME "cam-csiphy" +#define CAM_FLASH_NAME "cam-flash" +#define CAM_EEPROM_NAME "cam-eeprom" +#define CAM_OIS_NAME "cam-ois" + +#define MAX_SYSTEM_PIPELINE_DELAY 2 + +#define CAM_PKT_NOP_OPCODE 127 + +enum camera_sensor_cmd_type { + CAMERA_SENSOR_CMD_TYPE_INVALID, + CAMERA_SENSOR_CMD_TYPE_PROBE, + CAMERA_SENSOR_CMD_TYPE_PWR_UP, + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN, + CAMERA_SENSOR_CMD_TYPE_I2C_INFO, + CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR, + CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_RD, + CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR, + CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD, + CAMERA_SENSOR_CMD_TYPE_WAIT, + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO, + CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE, + CAMERA_SENSOR_FLASH_CMD_TYPE_RER, + CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR, + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET, + CAMERA_SENSOR_CMD_TYPE_RD_DATA, + CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE, + CAMERA_SENSOR_CMD_TYPE_MAX, +}; + +enum camera_sensor_i2c_op_code { + CAMERA_SENSOR_I2C_OP_INVALID, + CAMERA_SENSOR_I2C_OP_RNDM_WR, + CAMERA_SENSOR_I2C_OP_RNDM_WR_VERF, + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST, + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST_VERF, + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN, + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN_VERF, + CAMERA_SENSOR_I2C_OP_MAX, +}; + +enum camera_sensor_wait_op_code { + CAMERA_SENSOR_WAIT_OP_INVALID, + CAMERA_SENSOR_WAIT_OP_COND, + CAMERA_SENSOR_WAIT_OP_HW_UCND, + CAMERA_SENSOR_WAIT_OP_SW_UCND, + CAMERA_SENSOR_WAIT_OP_MAX, +}; + +enum camera_flash_opcode { + CAMERA_SENSOR_FLASH_OP_INVALID, + CAMERA_SENSOR_FLASH_OP_OFF, + CAMERA_SENSOR_FLASH_OP_FIRELOW, + CAMERA_SENSOR_FLASH_OP_FIREHIGH, + CAMERA_SENSOR_FLASH_OP_MAX, +}; + +enum camera_sensor_i2c_type { + CAMERA_SENSOR_I2C_TYPE_INVALID, + CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_3B, + CAMERA_SENSOR_I2C_TYPE_DWORD, + CAMERA_SENSOR_I2C_TYPE_MAX, +}; + +enum i2c_freq_mode { + I2C_STANDARD_MODE, + I2C_FAST_MODE, + I2C_CUSTOM_MODE, + I2C_FAST_PLUS_MODE, + I2C_MAX_MODES, +}; + +enum position_roll { + ROLL_0 = 0, + ROLL_90 = 90, + ROLL_180 = 180, + ROLL_270 = 270, + ROLL_INVALID = 360, +}; + +enum position_yaw { + FRONT_CAMERA_YAW = 0, + REAR_CAMERA_YAW = 180, + INVALID_YAW = 360, +}; + +enum position_pitch { + LEVEL_PITCH = 0, + INVALID_PITCH = 360, +}; + +enum sensor_sub_module { + SUB_MODULE_SENSOR, + SUB_MODULE_ACTUATOR, + SUB_MODULE_EEPROM, + SUB_MODULE_LED_FLASH, + SUB_MODULE_CSID, + SUB_MODULE_CSIPHY, + SUB_MODULE_OIS, + SUB_MODULE_EXT, + SUB_MODULE_MAX, +}; + +enum msm_camera_power_seq_type { + SENSOR_MCLK, + SENSOR_VANA, + SENSOR_VDIG, + SENSOR_VIO, + SENSOR_VAF, + SENSOR_VAF_PWDM, + SENSOR_CUSTOM_REG1, + SENSOR_CUSTOM_REG2, + SENSOR_RESET, + SENSOR_STANDBY, + SENSOR_CUSTOM_GPIO1, + SENSOR_CUSTOM_GPIO2, + SENSOR_SEQ_TYPE_MAX, +}; + +enum cam_sensor_packet_opcodes { + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON, + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE, + CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG, + CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE, + CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF, + CAM_SENSOR_PACKET_OPCODE_SENSOR_NOP = 127 +}; + +enum cam_actuator_packet_opcodes { + CAM_ACTUATOR_PACKET_OPCODE_INIT, + CAM_ACTUATOR_PACKET_AUTO_MOVE_LENS, + CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS +}; + +enum cam_eeprom_packet_opcodes { + CAM_EEPROM_PACKET_OPCODE_INIT, + CAM_EEPROM_WRITE +}; + +enum cam_ois_packet_opcodes { + CAM_OIS_PACKET_OPCODE_INIT, + CAM_OIS_PACKET_OPCODE_OIS_CONTROL +}; + +enum msm_bus_perf_setting { + S_INIT, + S_PREVIEW, + S_VIDEO, + S_CAPTURE, + S_ZSL, + S_STEREO_VIDEO, + S_STEREO_CAPTURE, + S_DEFAULT, + S_LIVESHOT, + S_DUAL, + S_EXIT +}; + +enum msm_camera_device_type_t { + MSM_CAMERA_I2C_DEVICE, + MSM_CAMERA_PLATFORM_DEVICE, + MSM_CAMERA_SPI_DEVICE, +}; + +enum cam_flash_device_type { + CAMERA_FLASH_DEVICE_TYPE_PMIC = 0, + CAMERA_FLASH_DEVICE_TYPE_I2C, + CAMERA_FLASH_DEVICE_TYPE_GPIO, +}; + +enum cci_i2c_master_t { + MASTER_0, + MASTER_1, + MASTER_MAX, +}; + +enum cci_device_num { + CCI_DEVICE_0, + CCI_DEVICE_1, + CCI_DEVICE_MAX, +}; + +enum camera_vreg_type { + VREG_TYPE_DEFAULT, + VREG_TYPE_CUSTOM, +}; + +enum cam_sensor_i2c_cmd_type { + CAM_SENSOR_I2C_WRITE_RANDOM, + CAM_SENSOR_I2C_WRITE_BURST, + CAM_SENSOR_I2C_WRITE_SEQ, + CAM_SENSOR_I2C_READ, + CAM_SENSOR_I2C_POLL +}; + +struct common_header { + uint32_t first_word; + uint8_t fifth_byte; + uint8_t cmd_type; + uint16_t reserved; +}; + +struct camera_vreg_t { + const char *reg_name; + int min_voltage; + int max_voltage; + int op_mode; + uint32_t delay; + const char *custom_vreg_name; + enum camera_vreg_type type; +}; + +struct msm_camera_gpio_num_info { + uint16_t gpio_num[SENSOR_SEQ_TYPE_MAX]; + uint8_t valid[SENSOR_SEQ_TYPE_MAX]; +}; + +struct msm_cam_clk_info { + const char *clk_name; + long clk_rate; + uint32_t delay; +}; + +struct msm_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + bool use_pinctrl; +}; + +struct cam_sensor_i2c_reg_array { + uint32_t reg_addr; + uint32_t reg_data; + uint32_t delay; + uint32_t data_mask; +}; + +struct cam_sensor_i2c_reg_setting { + struct cam_sensor_i2c_reg_array *reg_setting; + uint32_t size; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + unsigned short delay; +}; + +struct cam_sensor_i2c_seq_reg { + uint32_t reg_addr; + uint8_t *reg_data; + uint32_t size; + enum camera_sensor_i2c_type addr_type; +}; + +struct i2c_settings_list { + struct cam_sensor_i2c_reg_setting i2c_settings; + struct cam_sensor_i2c_seq_reg seq_settings; + enum cam_sensor_i2c_cmd_type op_code; + struct list_head list; +}; + +struct i2c_settings_array { + struct list_head list_head; + int32_t is_settings_valid; + int64_t request_id; +}; + +struct i2c_data_settings { + struct i2c_settings_array init_settings; + struct i2c_settings_array config_settings; + struct i2c_settings_array streamon_settings; + struct i2c_settings_array streamoff_settings; + struct i2c_settings_array *per_frame; +}; + +struct cam_sensor_power_ctrl_t { + struct device *dev; + struct cam_sensor_power_setting *power_setting; + uint16_t power_setting_size; + struct cam_sensor_power_setting *power_down_setting; + uint16_t power_down_setting_size; + struct msm_camera_gpio_num_info *gpio_num_info; + struct msm_pinctrl_info pinctrl_info; + uint8_t cam_pinctrl_status; +}; + +struct cam_camera_slave_info { + uint16_t sensor_slave_addr; + uint16_t sensor_id_reg_addr; + uint16_t sensor_id; + uint16_t sensor_id_mask; + uint8_t addr_type; + uint8_t data_type; +}; + +struct cam_camera_id_info { + uint16_t sensor_slave_addr; + uint16_t sensor_id_mask; + uint32_t sensor_id_reg_addr; + uint32_t sensor_id; + uint8_t sensor_addr_type; + uint8_t sensor_data_type; +}; + +struct msm_sensor_init_params { + int modes_supported; + unsigned int sensor_mount_angle; +}; + +enum msm_sensor_camera_id_t { + CAMERA_0, + CAMERA_1, + CAMERA_2, + CAMERA_3, + CAMERA_4, + CAMERA_5, + CAMERA_6, + MAX_CAMERAS, +}; + +struct msm_sensor_id_info_t { + unsigned short sensor_id_reg_addr; + unsigned short sensor_id; + unsigned short sensor_id_mask; +}; + +enum msm_sensor_output_format_t { + MSM_SENSOR_BAYER, + MSM_SENSOR_YCBCR, + MSM_SENSOR_META, +}; + +struct cam_sensor_power_setting { + enum msm_camera_power_seq_type seq_type; + unsigned short seq_val; + long config_val; + unsigned short delay; + void *data[10]; +}; + +struct cam_sensor_board_info { + struct cam_camera_slave_info slave_info; + struct cam_camera_id_info id_info; + int32_t sensor_mount_angle; + int32_t secure_mode; + int modes_supported; + int32_t pos_roll; + int32_t pos_yaw; + int32_t pos_pitch; + int32_t subdev_id[SUB_MODULE_MAX]; + int32_t subdev_intf[SUB_MODULE_MAX]; + const char *misc_regulator; + struct cam_sensor_power_ctrl_t power_info; +}; + +enum msm_camera_vreg_name_t { + CAM_VDIG, + CAM_VIO, + CAM_VANA, + CAM_VAF, + CAM_V_CUSTOM1, + CAM_V_CUSTOM2, + CAM_VREG_MAX, +}; + +struct msm_camera_gpio_conf { + void *cam_gpiomux_conf_tbl; + uint8_t cam_gpiomux_conf_tbl_size; + struct gpio *cam_gpio_common_tbl; + uint8_t cam_gpio_common_tbl_size; + struct gpio *cam_gpio_req_tbl; + uint8_t cam_gpio_req_tbl_size; + uint32_t gpio_no_mux; + uint32_t *camera_off_table; + uint8_t camera_off_table_size; + uint32_t *camera_on_table; + uint8_t camera_on_table_size; + struct msm_camera_gpio_num_info *gpio_num_info; +}; + +#endif /* _CAM_SENSOR_CMN_HEADER_ */ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c new file mode 100644 index 0000000000000000000000000000000000000000..0d82579e7999dcdeb8843dfccd93de1a1ad2bedc --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -0,0 +1,2057 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/kernel.h> +#include "cam_sensor_util.h" +#include "cam_mem_mgr.h" +#include "cam_res_mgr_api.h" + +#define CAM_SENSOR_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SENSOR_PINCTRL_STATE_DEFAULT "cam_default" + +#define VALIDATE_VOLTAGE(min, max, config_val) ((config_val) && \ + (config_val >= min) && (config_val <= max)) + +static struct i2c_settings_list* + cam_sensor_get_i2c_ptr(struct i2c_settings_array *i2c_reg_settings, + uint32_t size) +{ + struct i2c_settings_list *tmp; + + tmp = kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL); + + if (tmp != NULL) + list_add_tail(&(tmp->list), + &(i2c_reg_settings->list_head)); + else + return NULL; + + tmp->i2c_settings.reg_setting = (struct cam_sensor_i2c_reg_array *) + vzalloc(size * sizeof(struct cam_sensor_i2c_reg_array)); + if (tmp->i2c_settings.reg_setting == NULL) { + list_del(&(tmp->list)); + kfree(tmp); + return NULL; + } + tmp->i2c_settings.size = size; + + return tmp; +} + +int32_t delete_request(struct i2c_settings_array *i2c_array) +{ + struct i2c_settings_list *i2c_list = NULL, *i2c_next = NULL; + int32_t rc = 0; + + if (i2c_array == NULL) { + CAM_ERR(CAM_SENSOR, "FATAL:: Invalid argument"); + return -EINVAL; + } + + list_for_each_entry_safe(i2c_list, i2c_next, + &(i2c_array->list_head), list) { + vfree(i2c_list->i2c_settings.reg_setting); + list_del(&(i2c_list->list)); + kfree(i2c_list); + } + INIT_LIST_HEAD(&(i2c_array->list_head)); + i2c_array->is_settings_valid = 0; + + return rc; +} + +int32_t cam_sensor_handle_delay( + uint32_t **cmd_buf, + uint16_t generic_op_code, + struct i2c_settings_array *i2c_reg_settings, + uint32_t offset, uint32_t *byte_cnt, + struct list_head *list_ptr) +{ + int32_t rc = 0; + struct cam_cmd_unconditional_wait *cmd_uncond_wait = + (struct cam_cmd_unconditional_wait *) *cmd_buf; + struct i2c_settings_list *i2c_list = NULL; + + if (list_ptr == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid list ptr"); + return -EINVAL; + } + + if (offset > 0) { + i2c_list = + list_entry(list_ptr, struct i2c_settings_list, list); + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND) + i2c_list->i2c_settings.reg_setting[offset - 1].delay = + cmd_uncond_wait->delay; + else + i2c_list->i2c_settings.delay = cmd_uncond_wait->delay; + (*cmd_buf) += + sizeof( + struct cam_cmd_unconditional_wait) / sizeof(uint32_t); + (*byte_cnt) += + sizeof( + struct cam_cmd_unconditional_wait); + } else { + CAM_ERR(CAM_SENSOR, "Delay Rxed Before any buffer: %d", offset); + return -EINVAL; + } + + return rc; +} + +int32_t cam_sensor_handle_poll( + uint32_t **cmd_buf, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *byte_cnt, int32_t *offset, + struct list_head **list_ptr) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0; + struct cam_cmd_conditional_wait *cond_wait + = (struct cam_cmd_conditional_wait *) *cmd_buf; + + i2c_list = + cam_sensor_get_i2c_ptr(i2c_reg_settings, 1); + if (!i2c_list || !i2c_list->i2c_settings.reg_setting) { + CAM_ERR(CAM_SENSOR, "Failed in allocating mem for list"); + return -ENOMEM; + } + + i2c_list->op_code = CAM_SENSOR_I2C_POLL; + i2c_list->i2c_settings.data_type = + cond_wait->data_type; + i2c_list->i2c_settings.addr_type = + cond_wait->addr_type; + i2c_list->i2c_settings.reg_setting->reg_addr = + cond_wait->reg_addr; + i2c_list->i2c_settings.reg_setting->reg_data = + cond_wait->reg_data; + i2c_list->i2c_settings.reg_setting->delay = + cond_wait->timeout; + + (*cmd_buf) += sizeof(struct cam_cmd_conditional_wait) / + sizeof(uint32_t); + (*byte_cnt) += sizeof(struct cam_cmd_conditional_wait); + + *offset = 1; + *list_ptr = &(i2c_list->list); + + return rc; +} + +int32_t cam_sensor_handle_random_write( + struct cam_cmd_i2c_random_wr *cam_cmd_i2c_random_wr, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, + cam_cmd_i2c_random_wr->header.count); + if (i2c_list == NULL || + i2c_list->i2c_settings.reg_setting == NULL) { + CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); + return -ENOMEM; + } + + *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + + sizeof(struct i2c_random_wr_payload) * + (cam_cmd_i2c_random_wr->header.count)); + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_RANDOM; + i2c_list->i2c_settings.addr_type = + cam_cmd_i2c_random_wr->header.addr_type; + i2c_list->i2c_settings.data_type = + cam_cmd_i2c_random_wr->header.data_type; + + for (cnt = 0; cnt < (cam_cmd_i2c_random_wr->header.count); + cnt++) { + i2c_list->i2c_settings.reg_setting[cnt].reg_addr = + cam_cmd_i2c_random_wr->random_wr_payload[cnt].reg_addr; + i2c_list->i2c_settings.reg_setting[cnt].reg_data = + cam_cmd_i2c_random_wr->random_wr_payload[cnt].reg_data; + i2c_list->i2c_settings.reg_setting[cnt].data_mask = 0; + } + *offset = cnt; + *list = &(i2c_list->list); + + return rc; +} + +static int32_t cam_sensor_handle_continuous_write( + struct cam_cmd_i2c_continuous_wr *cam_cmd_i2c_continuous_wr, + struct i2c_settings_array *i2c_reg_settings, + uint32_t *cmd_length_in_bytes, int32_t *offset, + struct list_head **list) +{ + struct i2c_settings_list *i2c_list; + int32_t rc = 0, cnt; + + i2c_list = cam_sensor_get_i2c_ptr(i2c_reg_settings, + cam_cmd_i2c_continuous_wr->header.count); + if (i2c_list == NULL || + i2c_list->i2c_settings.reg_setting == NULL) { + CAM_ERR(CAM_SENSOR, "Failed in allocating i2c_list"); + return -ENOMEM; + } + + *cmd_length_in_bytes = (sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + sizeof(struct cam_cmd_read) * + (cam_cmd_i2c_continuous_wr->header.count)); + if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_BRST) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_BURST; + else if (cam_cmd_i2c_continuous_wr->header.op_code == + CAMERA_SENSOR_I2C_OP_CONT_WR_SEQN) + i2c_list->op_code = CAM_SENSOR_I2C_WRITE_SEQ; + else + return -EINVAL; + + i2c_list->i2c_settings.addr_type = + cam_cmd_i2c_continuous_wr->header.addr_type; + i2c_list->i2c_settings.data_type = + cam_cmd_i2c_continuous_wr->header.data_type; + i2c_list->i2c_settings.size = + cam_cmd_i2c_continuous_wr->header.count; + + for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count); + cnt++) { + i2c_list->i2c_settings.reg_setting[cnt].reg_addr = + cam_cmd_i2c_continuous_wr->reg_addr; + i2c_list->i2c_settings.reg_setting[cnt].reg_data = + cam_cmd_i2c_continuous_wr->data_read[cnt].reg_data; + i2c_list->i2c_settings.reg_setting[cnt].data_mask = 0; + } + *offset = cnt; + *list = &(i2c_list->list); + + return rc; +} + +static int cam_sensor_handle_slave_info( + struct camera_io_master *io_master, + uint32_t *cmd_buf) +{ + int rc = 0; + struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + + if (io_master == NULL || cmd_buf == NULL) { + CAM_ERR(CAM_SENSOR, "Invalid args"); + return -EINVAL; + } + + switch (io_master->master_type) { + case CCI_MASTER: + io_master->cci_client->sid = (i2c_info->slave_addr >> 1); + io_master->cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; + break; + + case I2C_MASTER: + io_master->client->addr = i2c_info->slave_addr; + break; + + case SPI_MASTER: + break; + + default: + CAM_ERR(CAM_SENSOR, "Invalid master type: %d", + io_master->master_type); + rc = -EINVAL; + break; + } + + return rc; +} + +/** + * Name : cam_sensor_i2c_command_parser + * Description : Parse CSL CCI packet and apply register settings + * Parameters : s_ctrl input/output sub_device + * arg input cam_control + * Description : + * Handle multiple I2C RD/WR and WAIT cmd formats in one command + * buffer, for example, a command buffer of m x RND_WR + 1 x HW_ + * WAIT + n x RND_WR with num_cmd_buf = 1. Do not exepect RD/WR + * with different cmd_type and op_code in one command buffer. + */ +int cam_sensor_i2c_command_parser( + struct camera_io_master *io_master, + struct i2c_settings_array *i2c_reg_settings, + struct cam_cmd_buf_desc *cmd_desc, + int32_t num_cmd_buffers) +{ + int16_t rc = 0, i = 0; + size_t len_of_buff = 0; + uintptr_t generic_ptr; + uint16_t cmd_length_in_bytes = 0; + size_t remain_len = 0; + size_t tot_size = 0; + + for (i = 0; i < num_cmd_buffers; i++) { + uint32_t *cmd_buf = NULL; + struct common_header *cmm_hdr; + uint16_t generic_op_code; + uint32_t byte_cnt = 0; + uint32_t j = 0; + struct list_head *list = NULL; + + /* + * It is not expected the same settings to + * be spread across multiple cmd buffers + */ + CAM_DBG(CAM_SENSOR, "Total cmd Buf in Bytes: %d", + cmd_desc[i].length); + + if (!cmd_desc[i].length) + continue; + + rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, + &generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cmd hdl failed:%d, Err: %d, Buffer_len: %zd", + cmd_desc[i].mem_handle, rc, len_of_buff); + return rc; + } + + remain_len = len_of_buff; + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buff - sizeof(struct common_header)))) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + cmd_buf = (uint32_t *)generic_ptr; + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + remain_len -= cmd_desc[i].offset; + if (remain_len < cmd_desc[i].length) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + + while (byte_cnt < cmd_desc[i].length) { + if ((remain_len - byte_cnt) < + sizeof(struct common_header)) { + CAM_ERR(CAM_SENSOR, "Not enough buffer"); + rc = -EINVAL; + goto end; + } + cmm_hdr = (struct common_header *)cmd_buf; + generic_op_code = cmm_hdr->fifth_byte; + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: { + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_random_wr + *cam_cmd_i2c_random_wr = + (struct cam_cmd_i2c_random_wr *)cmd_buf; + + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_random_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct i2c_random_wr_payload) * + cam_cmd_i2c_random_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_random_write( + cam_cmd_i2c_random_wr, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in random write %d", rc); + rc = -EINVAL; + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: { + uint32_t cmd_length_in_bytes = 0; + struct cam_cmd_i2c_continuous_wr + *cam_cmd_i2c_continuous_wr = + (struct cam_cmd_i2c_continuous_wr *) + cmd_buf; + + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + (sizeof(struct cam_cmd_read) * + cam_cmd_i2c_continuous_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto end; + } + + rc = cam_sensor_handle_continuous_write( + cam_cmd_i2c_continuous_wr, + i2c_reg_settings, + &cmd_length_in_bytes, &j, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed in continuous write %d", rc); + goto end; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_WAIT: { + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_unconditional_wait)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_HW_UCND || + generic_op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) { + rc = cam_sensor_handle_delay( + &cmd_buf, generic_op_code, + i2c_reg_settings, j, &byte_cnt, + list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "delay hdl failed: %d", + rc); + goto end; + } + + } else if (generic_op_code == + CAMERA_SENSOR_WAIT_OP_COND) { + rc = cam_sensor_handle_poll( + &cmd_buf, i2c_reg_settings, + &byte_cnt, &j, &list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Random read fail: %d", + rc); + goto end; + } + } else { + CAM_ERR(CAM_SENSOR, + "Wrong Wait Command: %d", + generic_op_code); + rc = -EINVAL; + goto end; + } + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto end; + } + rc = cam_sensor_handle_slave_info( + io_master, cmd_buf); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Handle slave info failed with rc: %d", + rc); + goto end; + } + cmd_length_in_bytes = + sizeof(struct cam_cmd_i2c_info); + cmd_buf += + cmd_length_in_bytes / sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", + cmm_hdr->cmd_type); + rc = -EINVAL; + goto end; + } + } + i2c_reg_settings->is_settings_valid = 1; + } + +end: + return rc; +} + +int cam_sensor_util_i2c_apply_setting( + struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list) +{ + int32_t rc = 0; + uint32_t i, size; + + switch (i2c_list->op_code) { + case CAM_SENSOR_I2C_WRITE_RANDOM: { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to random write I2C settings: %d", + rc); + return rc; + } + break; + } + case CAM_SENSOR_I2C_WRITE_SEQ: { + rc = camera_io_dev_write_continuous( + io_master_info, &(i2c_list->i2c_settings), 0); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to seq write I2C settings: %d", + rc); + return rc; + } + break; + } + case CAM_SENSOR_I2C_WRITE_BURST: { + rc = camera_io_dev_write_continuous( + io_master_info, &(i2c_list->i2c_settings), 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to burst write I2C settings: %d", + rc); + return rc; + } + break; + } + case CAM_SENSOR_I2C_POLL: { + size = i2c_list->i2c_settings.size; + for (i = 0; i < size; i++) { + rc = camera_io_dev_poll( + io_master_info, + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data, + i2c_list->i2c_settings.reg_setting[i].data_mask, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "i2c poll apply setting Fail: %d", rc); + return rc; + } + } + break; + } + default: + CAM_ERR(CAM_SENSOR, "Wrong Opcode: %d", i2c_list->op_code); + rc = -EINVAL; + break; + } + + return rc; +} + +int32_t msm_camera_fill_vreg_params( + struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_setting *power_setting, + uint16_t power_setting_size) +{ + int32_t rc = 0, j = 0, i = 0; + int num_vreg; + + /* Validate input parameters */ + if (!soc_info || !power_setting) { + CAM_ERR(CAM_SENSOR, "failed: soc_info %pK power_setting %pK", + soc_info, power_setting); + return -EINVAL; + } + + num_vreg = soc_info->num_rgltr; + + if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) { + CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + for (i = 0; i < power_setting_size; i++) { + + if (power_setting[i].seq_type < SENSOR_MCLK || + power_setting[i].seq_type >= SENSOR_SEQ_TYPE_MAX) { + CAM_ERR(CAM_SENSOR, "failed: Invalid Seq type: %d", + power_setting[i].seq_type); + return -EINVAL; + } + + switch (power_setting[i].seq_type) { + case SENSOR_VDIG: + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], + "cam_vdig")) { + + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vdig", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_VIO: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_vio")) { + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vio", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_VANA: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_vana")) { + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vana", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_VAF: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_vaf")) { + CAM_DBG(CAM_SENSOR, + "i: %d j: %d cam_vaf", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + + case SENSOR_CUSTOM_REG1: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_v_custom1")) { + CAM_DBG(CAM_SENSOR, + "i:%d j:%d cam_vcustom1", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + case SENSOR_CUSTOM_REG2: + for (j = 0; j < num_vreg; j++) { + + if (!strcmp(soc_info->rgltr_name[j], + "cam_v_custom2")) { + CAM_DBG(CAM_SENSOR, + "i:%d j:%d cam_vcustom2", i, j); + power_setting[i].seq_val = j; + + if (VALIDATE_VOLTAGE( + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + power_setting[i].config_val)) { + soc_info->rgltr_min_volt[j] = + soc_info->rgltr_max_volt[j] = + power_setting[i].config_val; + } + break; + } + } + if (j == num_vreg) + power_setting[i].seq_val = INVALID_VREG; + break; + default: + break; + } + } + + return rc; +} + +int cam_sensor_util_request_gpio_table( + struct cam_hw_soc_info *soc_info, int gpio_en) +{ + int rc = 0, i = 0; + uint8_t size = 0; + struct cam_soc_gpio_data *gpio_conf = + soc_info->gpio_data; + struct gpio *gpio_tbl = NULL; + + if (!gpio_conf) { + CAM_INFO(CAM_SENSOR, "No GPIO data"); + return 0; + } + + if (gpio_conf->cam_gpio_common_tbl_size <= 0) { + CAM_INFO(CAM_SENSOR, "No GPIO entry"); + return -EINVAL; + } + + gpio_tbl = gpio_conf->cam_gpio_req_tbl; + size = gpio_conf->cam_gpio_req_tbl_size; + + if (!gpio_tbl || !size) { + CAM_ERR(CAM_SENSOR, "invalid gpio_tbl %pK / size %d", + gpio_tbl, size); + return -EINVAL; + } + + for (i = 0; i < size; i++) { + CAM_DBG(CAM_SENSOR, "i: %d, gpio %d dir %ld", i, + gpio_tbl[i].gpio, gpio_tbl[i].flags); + } + + if (gpio_en) { + for (i = 0; i < size; i++) { + rc = cam_res_mgr_gpio_request(soc_info->dev, + gpio_tbl[i].gpio, + gpio_tbl[i].flags, gpio_tbl[i].label); + if (rc) { + /* + * After GPIO request fails, contine to + * apply new gpios, outout a error message + * for driver bringup debug + */ + CAM_ERR(CAM_SENSOR, "gpio %d:%s request fails", + gpio_tbl[i].gpio, gpio_tbl[i].label); + } + } + } else { + cam_res_mgr_gpio_free_arry(soc_info->dev, gpio_tbl, size); + } + + return rc; +} + + +static int32_t cam_sensor_validate(void *ptr, size_t remain_buf) +{ + struct common_header *cmm_hdr = (struct common_header *)ptr; + size_t validate_size = 0; + + if (remain_buf < sizeof(struct common_header)) + return -EINVAL; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP || + cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) + validate_size = sizeof(struct cam_cmd_power); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf < validate_size) { + CAM_ERR(CAM_SENSOR, "Invalid cmd_buf len %zu min %zu", + remain_buf, validate_size); + return -EINVAL; + } + return 0; +} + +int32_t cam_sensor_update_power_settings(void *cmd_buf, + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len) +{ + int32_t rc = 0, tot_size = 0, last_cmd_type = 0; + int32_t i = 0, pwr_up = 0, pwr_down = 0; + struct cam_sensor_power_setting *pwr_settings; + void *ptr = cmd_buf, *scr; + struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf; + struct common_header *cmm_hdr = (struct common_header *)cmd_buf; + + if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || + cam_sensor_validate(cmd_buf, cmd_buf_len)) { + CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", + pwr_cmd, cmd_length); + return -EINVAL; + } + + power_info->power_setting_size = 0; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_down_setting_size = 0; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_down_setting) { + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return -ENOMEM; + } + + while (tot_size < cmd_length) { + if (cam_sensor_validate(ptr, (cmd_length - tot_size))) { + rc = -EINVAL; + goto free_power_settings; + } + if (cmm_hdr->cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_UP) { + struct cam_cmd_power *pwr_cmd = + (struct cam_cmd_power *)ptr; + + if ((U16_MAX - power_info->power_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow occurs"); + rc = -EINVAL; + goto free_power_settings; + } + + power_info->power_setting_size += pwr_cmd->count; + if ((power_info->power_setting_size > MAX_POWER_CONFIG) + || (pwr_cmd->count >= SENSOR_SEQ_TYPE_MAX)) { + CAM_ERR(CAM_SENSOR, + "pwr_up setting size %d, pwr_cmd->count: %d", + power_info->power_setting_size, + pwr_cmd->count); + rc = -EINVAL; + goto free_power_settings; + } + scr = ptr + sizeof(struct cam_cmd_power); + tot_size = tot_size + sizeof(struct cam_cmd_power); + + if (pwr_cmd->count == 0) + CAM_WARN(CAM_SENSOR, "pwr_up_size is zero"); + + for (i = 0; i < pwr_cmd->count; i++, pwr_up++) { + power_info->power_setting[pwr_up].seq_type = + pwr_cmd->power_settings[i].power_seq_type; + power_info->power_setting[pwr_up].config_val = + pwr_cmd->power_settings[i].config_val_low; + power_info->power_setting[pwr_up].delay = 0; + if (i) { + scr = scr + + sizeof( + struct cam_power_settings); + tot_size = tot_size + + sizeof( + struct cam_power_settings); + } + if (tot_size > cmd_length) { + CAM_ERR(CAM_SENSOR, + "Error: Cmd Buffer is wrong"); + rc = -EINVAL; + goto free_power_settings; + } + CAM_DBG(CAM_SENSOR, + "Seq Type[%d]: %d Config_val: %ld", pwr_up, + power_info->power_setting[pwr_up].seq_type, + power_info->power_setting[pwr_up].config_val); + } + last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; + ptr = (void *) scr; + cmm_hdr = (struct common_header *)ptr; + } else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) { + struct cam_cmd_unconditional_wait *wait_cmd = + (struct cam_cmd_unconditional_wait *)ptr; + if ((wait_cmd->op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) && + (last_cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_UP)) { + if (pwr_up > 0) { + pwr_settings = + &power_info->power_setting[pwr_up - 1]; + pwr_settings->delay += + wait_cmd->delay; + } else { + CAM_ERR(CAM_SENSOR, + "Delay is expected only after valid power up setting"); + } + } else if ((wait_cmd->op_code == + CAMERA_SENSOR_WAIT_OP_SW_UCND) && + (last_cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN)) { + if (pwr_down > 0) { + pwr_settings = + &power_info->power_down_setting[ + pwr_down - 1]; + pwr_settings->delay += + wait_cmd->delay; + } else { + CAM_ERR(CAM_SENSOR, + "Delay is expected only after valid power up setting"); + } + } else { + CAM_DBG(CAM_SENSOR, "Invalid op code: %d", + wait_cmd->op_code); + } + + tot_size = tot_size + + sizeof(struct cam_cmd_unconditional_wait); + if (tot_size > cmd_length) { + CAM_ERR(CAM_SENSOR, "Command Buffer is wrong"); + return -EINVAL; + } + scr = (void *) (wait_cmd); + ptr = (void *) + (scr + + sizeof(struct cam_cmd_unconditional_wait)); + CAM_DBG(CAM_SENSOR, "ptr: %pK sizeof: %d Next: %pK", + scr, (int32_t)sizeof( + struct cam_cmd_unconditional_wait), ptr); + + cmm_hdr = (struct common_header *)ptr; + } else if (cmm_hdr->cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) { + struct cam_cmd_power *pwr_cmd = + (struct cam_cmd_power *)ptr; + + scr = ptr + sizeof(struct cam_cmd_power); + tot_size = tot_size + sizeof(struct cam_cmd_power); + if ((U16_MAX - power_info->power_down_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow"); + rc = -EINVAL; + goto free_power_settings; + } + + power_info->power_down_setting_size += pwr_cmd->count; + if ((power_info->power_down_setting_size > + MAX_POWER_CONFIG) || (pwr_cmd->count >= + SENSOR_SEQ_TYPE_MAX)) { + CAM_ERR(CAM_SENSOR, + "pwr_down_setting_size %d, pwr_cmd->count: %d", + power_info->power_down_setting_size, + pwr_cmd->count); + rc = -EINVAL; + goto free_power_settings; + } + + if (pwr_cmd->count == 0) + CAM_ERR(CAM_SENSOR, "pwr_down size is zero"); + + for (i = 0; i < pwr_cmd->count; i++, pwr_down++) { + pwr_settings = + &power_info->power_down_setting[pwr_down]; + pwr_settings->seq_type = + pwr_cmd->power_settings[i].power_seq_type; + pwr_settings->config_val = + pwr_cmd->power_settings[i].config_val_low; + power_info->power_down_setting[pwr_down].delay + = 0; + if (i) { + scr = scr + + sizeof( + struct cam_power_settings); + tot_size = + tot_size + + sizeof( + struct cam_power_settings); + } + if (tot_size > cmd_length) { + CAM_ERR(CAM_SENSOR, + "Command Buffer is wrong"); + rc = -EINVAL; + goto free_power_settings; + } + CAM_DBG(CAM_SENSOR, + "Seq Type[%d]: %d Config_val: %ld", + pwr_down, pwr_settings->seq_type, + pwr_settings->config_val); + } + last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN; + ptr = (void *) scr; + cmm_hdr = (struct common_header *)ptr; + } else { + CAM_ERR(CAM_SENSOR, + "Error: Un expected Header Type: %d", + cmm_hdr->cmd_type); + rc = -EINVAL; + goto free_power_settings; + } + } + + return rc; +free_power_settings: + kfree(power_info->power_down_setting); + kfree(power_info->power_setting); + power_info->power_down_setting = NULL; + power_info->power_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + return rc; +} + +int cam_get_dt_power_setting_data(struct device_node *of_node, + struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0, i; + int count = 0; + const char *seq_name = NULL; + uint32_t *array = NULL; + struct cam_sensor_power_setting *ps; + int c, end; + + if (!power_info) + return -EINVAL; + + count = of_property_count_strings(of_node, "qcom,cam-power-seq-type"); + power_info->power_setting_size = count; + + CAM_DBG(CAM_SENSOR, "qcom,cam-power-seq-type count %d", count); + + if (count <= 0) + return 0; + + ps = kcalloc(count, sizeof(*ps), GFP_KERNEL); + if (!ps) + return -ENOMEM; + power_info->power_setting = ps; + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "qcom,cam-power-seq-type", i, &seq_name); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed"); + goto ERROR1; + } + CAM_DBG(CAM_SENSOR, "seq_name[%d] = %s", i, seq_name); + if (!strcmp(seq_name, "cam_vio")) { + ps[i].seq_type = SENSOR_VIO; + } else if (!strcmp(seq_name, "cam_vana")) { + ps[i].seq_type = SENSOR_VANA; + } else if (!strcmp(seq_name, "cam_clk")) { + ps[i].seq_type = SENSOR_MCLK; + } else { + CAM_ERR(CAM_SENSOR, "unrecognized seq-type %s", + seq_name); + rc = -EILSEQ; + goto ERROR1; + } + CAM_DBG(CAM_SENSOR, "seq_type[%d] %d", i, ps[i].seq_type); + } + + array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); + if (!array) { + rc = -ENOMEM; + goto ERROR1; + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val", + array, count); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed "); + goto ERROR2; + } + + for (i = 0; i < count; i++) { + ps[i].config_val = array[i]; + CAM_DBG(CAM_SENSOR, "power_setting[%d].config_val = %ld", i, + ps[i].config_val); + } + + rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay", + array, count); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "failed"); + goto ERROR2; + } + for (i = 0; i < count; i++) { + ps[i].delay = array[i]; + CAM_DBG(CAM_SENSOR, "power_setting[%d].delay = %d", i, + ps[i].delay); + } + kfree(array); + + power_info->power_down_setting = + kcalloc(count, sizeof(*ps), GFP_KERNEL); + + if (!power_info->power_down_setting) { + CAM_ERR(CAM_SENSOR, "failed"); + rc = -ENOMEM; + goto ERROR1; + } + + power_info->power_down_setting_size = count; + + end = count - 1; + + for (c = 0; c < count; c++) { + power_info->power_down_setting[c] = ps[end]; + end--; + } + return rc; +ERROR2: + kfree(array); +ERROR1: + kfree(ps); + return rc; +} + +int cam_sensor_util_init_gpio_pin_tbl( + struct cam_hw_soc_info *soc_info, + struct msm_camera_gpio_num_info **pgpio_num_info) +{ + int rc = 0, val = 0; + uint32_t gpio_array_size; + struct device_node *of_node = NULL; + struct cam_soc_gpio_data *gconf = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + if (!soc_info->dev) { + CAM_ERR(CAM_SENSOR, "device node NULL"); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + + gconf = soc_info->gpio_data; + if (!gconf) { + CAM_ERR(CAM_SENSOR, "No gpio_common_table is found"); + return -EINVAL; + } + + if (!gconf->cam_gpio_common_tbl) { + CAM_ERR(CAM_SENSOR, "gpio_common_table is not initialized"); + return -EINVAL; + } + + gpio_array_size = gconf->cam_gpio_common_tbl_size; + + if (!gpio_array_size) { + CAM_ERR(CAM_SENSOR, "invalid size of gpio table"); + return -EINVAL; + } + + *pgpio_num_info = kzalloc(sizeof(struct msm_camera_gpio_num_info), + GFP_KERNEL); + if (!*pgpio_num_info) + return -ENOMEM; + gpio_num_info = *pgpio_num_info; + + rc = of_property_read_u32(of_node, "gpio-vana", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vana failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vana invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VANA] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VANA] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vana %d", + gpio_num_info->gpio_num[SENSOR_VANA]); + } + + rc = of_property_read_u32(of_node, "gpio-vio", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vio failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vio invalid %d", val); + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VIO] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VIO] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vio %d", + gpio_num_info->gpio_num[SENSOR_VIO]); + } + + rc = of_property_read_u32(of_node, "gpio-vaf", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vaf failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vaf invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VAF] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VAF] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vaf %d", + gpio_num_info->gpio_num[SENSOR_VAF]); + } + + rc = of_property_read_u32(of_node, "gpio-vdig", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-vdig failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-vdig invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VDIG] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VDIG] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-vdig %d", + gpio_num_info->gpio_num[SENSOR_VDIG]); + } + + rc = of_property_read_u32(of_node, "gpio-reset", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "read gpio-reset failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-reset invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_RESET] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_RESET] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-reset %d", + gpio_num_info->gpio_num[SENSOR_RESET]); + } + + rc = of_property_read_u32(of_node, "gpio-standby", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-standby failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-standby invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_STANDBY] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_STANDBY] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-standby %d", + gpio_num_info->gpio_num[SENSOR_STANDBY]); + } + + rc = of_property_read_u32(of_node, "gpio-af-pwdm", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-af-pwdm failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-af-pwdm invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_VAF_PWDM] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_VAF_PWDM] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-af-pwdm %d", + gpio_num_info->gpio_num[SENSOR_VAF_PWDM]); + } + + rc = of_property_read_u32(of_node, "gpio-custom1", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-custom1 failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-custom1 invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO1] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_CUSTOM_GPIO1] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-custom1 %d", + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO1]); + } + + rc = of_property_read_u32(of_node, "gpio-custom2", &val); + if (rc != -EINVAL) { + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "read gpio-custom2 failed rc %d", rc); + goto free_gpio_info; + } else if (val >= gpio_array_size) { + CAM_ERR(CAM_SENSOR, "gpio-custom2 invalid %d", val); + rc = -EINVAL; + goto free_gpio_info; + } + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO2] = + gconf->cam_gpio_common_tbl[val].gpio; + gpio_num_info->valid[SENSOR_CUSTOM_GPIO2] = 1; + + CAM_DBG(CAM_SENSOR, "gpio-custom2 %d", + gpio_num_info->gpio_num[SENSOR_CUSTOM_GPIO2]); + } else { + rc = 0; + } + + return rc; + +free_gpio_info: + kfree(gpio_num_info); + gpio_num_info = NULL; + return rc; +} + +int msm_camera_pinctrl_init( + struct msm_pinctrl_info *sensor_pctrl, struct device *dev) +{ + + sensor_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(sensor_pctrl->pinctrl)) { + CAM_DBG(CAM_SENSOR, "Getting pinctrl handle failed"); + return -EINVAL; + } + sensor_pctrl->gpio_state_active = + pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_active)) { + CAM_ERR(CAM_SENSOR, + "Failed to get the active state pinctrl handle"); + return -EINVAL; + } + sensor_pctrl->gpio_state_suspend + = pinctrl_lookup_state(sensor_pctrl->pinctrl, + CAM_SENSOR_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(sensor_pctrl->gpio_state_suspend)) { + CAM_ERR(CAM_SENSOR, + "Failed to get the suspend state pinctrl handle"); + return -EINVAL; + } + + return 0; +} + +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag) +{ + int rc = 0; + uint32_t op_current = + (flag == true) ? soc_info->rgltr_op_mode[bob_reg_idx] : 0; + + if (soc_info->rgltr[bob_reg_idx] != NULL) { + rc = regulator_set_load(soc_info->rgltr[bob_reg_idx], + op_current); + if (rc) + CAM_WARN(CAM_SENSOR, + "BoB PWM SetLoad failed rc: %d", rc); + } + + return rc; +} + +int msm_cam_sensor_handle_reg_gpio(int seq_type, + struct msm_camera_gpio_num_info *gpio_num_info, int val) +{ + int gpio_offset = -1; + + if (!gpio_num_info) { + CAM_INFO(CAM_SENSOR, "Input Parameters are not proper"); + return 0; + } + + CAM_DBG(CAM_SENSOR, "Seq type: %d, config: %d", seq_type, val); + + gpio_offset = seq_type; + + if (gpio_num_info->valid[gpio_offset] == 1) { + CAM_DBG(CAM_SENSOR, "VALID GPIO offset: %d, seqtype: %d", + gpio_offset, seq_type); + cam_res_mgr_gpio_set_value( + gpio_num_info->gpio_num + [gpio_offset], val); + } + + return 0; +} + +static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info, int32_t index) +{ + int32_t num_vreg = 0, j = 0, rc = 0, idx = 0; + struct cam_sensor_power_setting *ps = NULL; + struct cam_sensor_power_setting *pd = NULL; + + num_vreg = soc_info->num_rgltr; + + pd = &ctrl->power_down_setting[index]; + + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { + ps = NULL; + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + if (ctrl->power_setting[idx].seq_type == + pd->seq_type) { + ps = &ctrl->power_setting[idx]; + break; + } + } + + if (ps != NULL) { + CAM_DBG(CAM_SENSOR, "Disable MCLK Regulator"); + rc = cam_soc_util_regulator_disable( + soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + + if (rc) { + CAM_ERR(CAM_SENSOR, + "MCLK REG DISALBE FAILED: %d", + rc); + return rc; + } + + ps->data[0] = + soc_info->rgltr[j]; + + regulator_put( + soc_info->rgltr[j]); + soc_info->rgltr[j] = NULL; + } + } + } + + return rc; +} + +int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info) +{ + int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0, i = 0; + int32_t vreg_idx = -1; + struct cam_sensor_power_setting *power_setting = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + CAM_DBG(CAM_SENSOR, "Enter"); + if (!ctrl) { + CAM_ERR(CAM_SENSOR, "Invalid ctrl handle"); + return -EINVAL; + } + + gpio_num_info = ctrl->gpio_num_info; + num_vreg = soc_info->num_rgltr; + + if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) { + CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(true); + + ret = msm_camera_pinctrl_init(&(ctrl->pinctrl_info), ctrl->dev); + if (ret < 0) { + /* Some sensor subdev no pinctrl. */ + CAM_DBG(CAM_SENSOR, "Initialization of pinctrl failed"); + ctrl->cam_pinctrl_status = 0; + } else { + ctrl->cam_pinctrl_status = 1; + } + + if (cam_res_mgr_shared_pinctrl_init()) { + CAM_ERR(CAM_SENSOR, + "Failed to init shared pinctrl"); + return -EINVAL; + } + + rc = cam_sensor_util_request_gpio_table(soc_info, 1); + if (rc < 0) + no_gpio = rc; + + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state( + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_active); + if (ret) + CAM_ERR(CAM_SENSOR, "cannot set pin to active state"); + } + + ret = cam_res_mgr_shared_pinctrl_select_state(true); + if (ret) + CAM_ERR(CAM_SENSOR, + "Cannot set shared pin to active state"); + + CAM_DBG(CAM_SENSOR, "power setting size: %d", ctrl->power_setting_size); + + for (index = 0; index < ctrl->power_setting_size; index++) { + CAM_DBG(CAM_SENSOR, "index: %d", index); + power_setting = &ctrl->power_setting[index]; + if (!power_setting) { + CAM_ERR(CAM_SENSOR, + "Invalid power up settings for index %d", + index); + return -EINVAL; + } + + CAM_DBG(CAM_SENSOR, "seq_type %d", power_setting->seq_type); + + switch (power_setting->seq_type) { + case SENSOR_MCLK: + if (power_setting->seq_val >= soc_info->num_clk) { + CAM_ERR(CAM_SENSOR, "clk index %d >= max %u", + power_setting->seq_val, + soc_info->num_clk); + goto power_up_failed; + } + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], + "cam_clk")) { + CAM_DBG(CAM_SENSOR, + "Enable cam_clk: %d", j); + + soc_info->rgltr[j] = + regulator_get( + soc_info->dev, + soc_info->rgltr_name[j]); + + if (IS_ERR_OR_NULL( + soc_info->rgltr[j])) { + rc = PTR_ERR( + soc_info->rgltr[j]); + rc = rc ? rc : -EINVAL; + CAM_ERR(CAM_SENSOR, + "vreg %s %d", + soc_info->rgltr_name[j], + rc); + soc_info->rgltr[j] = NULL; + goto power_up_failed; + } + + rc = cam_soc_util_regulator_enable( + soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg enable failed"); + goto power_up_failed; + } + power_setting->data[0] = + soc_info->rgltr[j]; + } + } + if (power_setting->config_val) + soc_info->clk_rate[0][power_setting->seq_val] = + power_setting->config_val; + + for (j = 0; j < soc_info->num_clk; j++) { + rc = cam_soc_util_clk_enable(soc_info->clk[j], + soc_info->clk_name[j], + soc_info->clk_rate[0][j]); + if (rc) + break; + } + + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "clk enable failed"); + goto power_up_failed; + } + break; + case SENSOR_RESET: + case SENSOR_STANDBY: + case SENSOR_CUSTOM_GPIO1: + case SENSOR_CUSTOM_GPIO2: + if (no_gpio) { + CAM_ERR(CAM_SENSOR, "request gpio failed"); + goto power_up_failed; + } + if (!gpio_num_info) { + CAM_ERR(CAM_SENSOR, "Invalid gpio_num_info"); + goto power_up_failed; + } + CAM_DBG(CAM_SENSOR, "gpio set val %d", + gpio_num_info->gpio_num + [power_setting->seq_type]); + + rc = msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, + (int) power_setting->config_val); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Error in handling VREG GPIO"); + goto power_up_failed; + } + break; + case SENSOR_VANA: + case SENSOR_VDIG: + case SENSOR_VIO: + case SENSOR_VAF: + case SENSOR_VAF_PWDM: + case SENSOR_CUSTOM_REG1: + case SENSOR_CUSTOM_REG2: + if (power_setting->seq_val == INVALID_VREG) + break; + + if (power_setting->seq_val >= CAM_VREG_MAX) { + CAM_ERR(CAM_SENSOR, "vreg index %d >= max %d", + power_setting->seq_val, + CAM_VREG_MAX); + goto power_up_failed; + } + if (power_setting->seq_val < num_vreg) { + CAM_DBG(CAM_SENSOR, "Enable Regulator"); + vreg_idx = power_setting->seq_val; + + soc_info->rgltr[vreg_idx] = + regulator_get(soc_info->dev, + soc_info->rgltr_name[vreg_idx]); + if (IS_ERR_OR_NULL( + soc_info->rgltr[vreg_idx])) { + rc = PTR_ERR(soc_info->rgltr[vreg_idx]); + rc = rc ? rc : -EINVAL; + + CAM_ERR(CAM_SENSOR, "%s get failed %d", + soc_info->rgltr_name[vreg_idx], + rc); + + soc_info->rgltr[vreg_idx] = NULL; + goto power_up_failed; + } + + rc = cam_soc_util_regulator_enable( + soc_info->rgltr[vreg_idx], + soc_info->rgltr_name[vreg_idx], + soc_info->rgltr_min_volt[vreg_idx], + soc_info->rgltr_max_volt[vreg_idx], + soc_info->rgltr_op_mode[vreg_idx], + soc_info->rgltr_delay[vreg_idx]); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg Enable failed for %s", + soc_info->rgltr_name[vreg_idx]); + goto power_up_failed; + } + power_setting->data[0] = + soc_info->rgltr[vreg_idx]; + } else { + CAM_ERR(CAM_SENSOR, "usr_idx:%d dts_idx:%d", + power_setting->seq_val, num_vreg); + } + + rc = msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Error in handling VREG GPIO"); + goto power_up_failed; + } + break; + default: + CAM_ERR(CAM_SENSOR, "error power seq type %d", + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) + msleep(power_setting->delay); + else if (power_setting->delay) + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + + ret = cam_res_mgr_shared_pinctrl_post_init(); + if (ret) + CAM_ERR(CAM_SENSOR, + "Failed to post init shared pinctrl"); + + return 0; +power_up_failed: + CAM_ERR(CAM_SENSOR, "failed"); + for (index--; index >= 0; index--) { + CAM_DBG(CAM_SENSOR, "index %d", index); + power_setting = &ctrl->power_setting[index]; + CAM_DBG(CAM_SENSOR, "type %d", + power_setting->seq_type); + switch (power_setting->seq_type) { + case SENSOR_MCLK: + for (i = soc_info->num_clk - 1; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } + break; + case SENSOR_RESET: + case SENSOR_STANDBY: + case SENSOR_CUSTOM_GPIO1: + case SENSOR_CUSTOM_GPIO2: + if (!gpio_num_info) + continue; + if (!gpio_num_info->valid + [power_setting->seq_type]) + continue; + cam_res_mgr_gpio_set_value( + gpio_num_info->gpio_num + [power_setting->seq_type], GPIOF_OUT_INIT_LOW); + break; + case SENSOR_VANA: + case SENSOR_VDIG: + case SENSOR_VIO: + case SENSOR_VAF: + case SENSOR_VAF_PWDM: + case SENSOR_CUSTOM_REG1: + case SENSOR_CUSTOM_REG2: + if (power_setting->seq_val < num_vreg) { + CAM_DBG(CAM_SENSOR, "Disable Regulator"); + vreg_idx = power_setting->seq_val; + + rc = cam_soc_util_regulator_disable( + soc_info->rgltr[vreg_idx], + soc_info->rgltr_name[vreg_idx], + soc_info->rgltr_min_volt[vreg_idx], + soc_info->rgltr_max_volt[vreg_idx], + soc_info->rgltr_op_mode[vreg_idx], + soc_info->rgltr_delay[vreg_idx]); + + if (rc) { + CAM_ERR(CAM_SENSOR, + "Fail to disalbe reg: %s", + soc_info->rgltr_name[vreg_idx]); + soc_info->rgltr[vreg_idx] = NULL; + msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } + power_setting->data[0] = + soc_info->rgltr[vreg_idx]; + + regulator_put(soc_info->rgltr[vreg_idx]); + soc_info->rgltr[vreg_idx] = NULL; + } else { + CAM_ERR(CAM_SENSOR, "seq_val:%d > num_vreg: %d", + power_setting->seq_val, num_vreg); + } + + msm_cam_sensor_handle_reg_gpio(power_setting->seq_type, + gpio_num_info, GPIOF_OUT_INIT_LOW); + + break; + default: + CAM_ERR(CAM_SENSOR, "error power seq type %d", + power_setting->seq_type); + break; + } + if (power_setting->delay > 20) { + msleep(power_setting->delay); + } else if (power_setting->delay) { + usleep_range(power_setting->delay * 1000, + (power_setting->delay * 1000) + 1000); + } + } + + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state( + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(false); + + cam_res_mgr_shared_pinctrl_select_state(false); + cam_res_mgr_shared_pinctrl_put(); + + ctrl->cam_pinctrl_status = 0; + + cam_sensor_util_request_gpio_table(soc_info, 0); + + return rc; +} + +static struct cam_sensor_power_setting* +msm_camera_get_power_settings(struct cam_sensor_power_ctrl_t *ctrl, + enum msm_camera_power_seq_type seq_type, + uint16_t seq_val) +{ + struct cam_sensor_power_setting *power_setting, *ps = NULL; + int idx; + + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + power_setting = &ctrl->power_setting[idx]; + if (power_setting->seq_type == seq_type && + power_setting->seq_val == seq_val) { + ps = power_setting; + return ps; + } + + } + + return ps; +} + +int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info) +{ + int index = 0, ret = 0, num_vreg = 0, i; + struct cam_sensor_power_setting *pd = NULL; + struct cam_sensor_power_setting *ps = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + CAM_DBG(CAM_SENSOR, "Enter"); + if (!ctrl || !soc_info) { + CAM_ERR(CAM_SENSOR, "failed ctrl %pK", ctrl); + return -EINVAL; + } + + gpio_num_info = ctrl->gpio_num_info; + num_vreg = soc_info->num_rgltr; + + if ((num_vreg <= 0) || (num_vreg > CAM_SOC_MAX_REGULATOR)) { + CAM_ERR(CAM_SENSOR, "failed: num_vreg %d", num_vreg); + return -EINVAL; + } + + if (ctrl->power_down_setting_size > MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, "Invalid: power setting size %d", + ctrl->power_setting_size); + return -EINVAL; + } + + for (index = 0; index < ctrl->power_down_setting_size; index++) { + CAM_DBG(CAM_SENSOR, "power_down_index %d", index); + pd = &ctrl->power_down_setting[index]; + if (!pd) { + CAM_ERR(CAM_SENSOR, + "Invalid power down settings for index %d", + index); + return -EINVAL; + } + + ps = NULL; + CAM_DBG(CAM_SENSOR, "seq_type %d", pd->seq_type); + switch (pd->seq_type) { + case SENSOR_MCLK: + for (i = soc_info->num_clk - 1; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } + break; + case SENSOR_RESET: + case SENSOR_STANDBY: + case SENSOR_CUSTOM_GPIO1: + case SENSOR_CUSTOM_GPIO2: + + if (!gpio_num_info->valid[pd->seq_type]) + continue; + + cam_res_mgr_gpio_set_value( + gpio_num_info->gpio_num + [pd->seq_type], + (int) pd->config_val); + + break; + case SENSOR_VANA: + case SENSOR_VDIG: + case SENSOR_VIO: + case SENSOR_VAF: + case SENSOR_VAF_PWDM: + case SENSOR_CUSTOM_REG1: + case SENSOR_CUSTOM_REG2: + if (pd->seq_val == INVALID_VREG) + break; + + ps = msm_camera_get_power_settings( + ctrl, pd->seq_type, + pd->seq_val); + if (ps) { + if (pd->seq_val < num_vreg) { + CAM_DBG(CAM_SENSOR, + "Disable Regulator"); + ret = cam_soc_util_regulator_disable( + soc_info->rgltr[ps->seq_val], + soc_info->rgltr_name[ps->seq_val], + soc_info->rgltr_min_volt[ps->seq_val], + soc_info->rgltr_max_volt[ps->seq_val], + soc_info->rgltr_op_mode[ps->seq_val], + soc_info->rgltr_delay[ps->seq_val]); + if (ret) { + CAM_ERR(CAM_SENSOR, + "Reg: %s disable failed", + soc_info->rgltr_name[ + ps->seq_val]); + soc_info->rgltr[ps->seq_val] = + NULL; + msm_cam_sensor_handle_reg_gpio( + pd->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } + ps->data[0] = + soc_info->rgltr[ps->seq_val]; + regulator_put( + soc_info->rgltr[ps->seq_val]); + soc_info->rgltr[ps->seq_val] = NULL; + } else { + CAM_ERR(CAM_SENSOR, + "seq_val:%d > num_vreg: %d", + pd->seq_val, + num_vreg); + } + } else + CAM_ERR(CAM_SENSOR, + "error in power up/down seq"); + + ret = msm_cam_sensor_handle_reg_gpio(pd->seq_type, + gpio_num_info, GPIOF_OUT_INIT_LOW); + + if (ret < 0) + CAM_ERR(CAM_SENSOR, + "Error disabling VREG GPIO"); + break; + default: + CAM_ERR(CAM_SENSOR, "error power seq type %d", + pd->seq_type); + break; + } + if (pd->delay > 20) + msleep(pd->delay); + else if (pd->delay) + usleep_range(pd->delay * 1000, + (pd->delay * 1000) + 1000); + } + + if (ctrl->cam_pinctrl_status) { + ret = pinctrl_select_state( + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); + if (ret) + CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); + + devm_pinctrl_put(ctrl->pinctrl_info.pinctrl); + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(false); + + cam_res_mgr_shared_pinctrl_select_state(false); + cam_res_mgr_shared_pinctrl_put(); + + ctrl->cam_pinctrl_status = 0; + + cam_sensor_util_request_gpio_table(soc_info, 0); + + return 0; +} diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h new file mode 100644 index 0000000000000000000000000000000000000000..c923efe61dc533bbc01e96c293660a469b8c3a54 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SENSOR_UTIL_H_ +#define _CAM_SENSOR_UTIL_H_ + +#include <linux/kernel.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/of.h> +#include "cam_sensor_cmn_header.h" +#include "cam_req_mgr_util.h" +#include "cam_req_mgr_interface.h" +#include <cam_mem_mgr.h> +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_sensor_io.h" + +#define INVALID_VREG 100 + +int cam_get_dt_power_setting_data(struct device_node *of_node, + struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_ctrl_t *power_info); + +int msm_camera_pinctrl_init + (struct msm_pinctrl_info *sensor_pctrl, struct device *dev); + +int cam_sensor_i2c_command_parser(struct camera_io_master *io_master, + struct i2c_settings_array *i2c_reg_settings, + struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers); + +int cam_sensor_util_i2c_apply_setting(struct camera_io_master *io_master_info, + struct i2c_settings_list *i2c_list); + +int32_t delete_request(struct i2c_settings_array *i2c_array); +int cam_sensor_util_request_gpio_table( + struct cam_hw_soc_info *soc_info, int gpio_en); + +int cam_sensor_util_init_gpio_pin_tbl( + struct cam_hw_soc_info *soc_info, + struct msm_camera_gpio_num_info **pgpio_num_info); +int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info); + +int cam_sensor_util_power_down(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info); + +int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, + struct cam_sensor_power_setting *power_setting, + uint16_t power_setting_size); + +int32_t cam_sensor_update_power_settings(void *cmd_buf, + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len); + +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag); +#endif /* _CAM_SENSOR_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_smmu/Makefile b/techpack/camera/drivers/cam_smmu/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b674b48ceb2db2e9e2eeb2dec7d03ec18667b10a --- /dev/null +++ b/techpack/camera/drivers/cam_smmu/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o diff --git a/techpack/camera/drivers/cam_smmu/cam_smmu_api.c b/techpack/camera/drivers/cam_smmu/cam_smmu_api.c new file mode 100644 index 0000000000000000000000000000000000000000..090d01dcd5d5848832b5f8710d9750e29e32ce26 --- /dev/null +++ b/techpack/camera/drivers/cam_smmu/cam_smmu_api.c @@ -0,0 +1,3821 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/dma-buf.h> +#include <linux/dma-direction.h> +#include <linux/of_platform.h> +#include <linux/iommu.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/msm_dma_iommu_mapping.h> +#include <linux/workqueue.h> +#include <linux/genalloc.h> +#include <linux/debugfs.h> +#include <linux/dma-iommu.h> + +#include <soc/qcom/scm.h> +#include <soc/qcom/secure_buffer.h> +#include <media/cam_req_mgr.h> +#include "cam_smmu_api.h" +#include "cam_debug_util.h" + +#define SHARED_MEM_POOL_GRANULARITY 16 + +#define IOMMU_INVALID_DIR -1 +#define BYTE_SIZE 8 +#define COOKIE_NUM_BYTE 2 +#define COOKIE_SIZE (BYTE_SIZE*COOKIE_NUM_BYTE) +#define COOKIE_MASK ((1<<COOKIE_SIZE)-1) +#define HANDLE_INIT (-1) +#define CAM_SMMU_CB_MAX 5 + +#define GET_SMMU_HDL(x, y) (((x) << COOKIE_SIZE) | ((y) & COOKIE_MASK)) +#define GET_SMMU_TABLE_IDX(x) (((x) >> COOKIE_SIZE) & COOKIE_MASK) + +static int g_num_pf_handled = 4; +module_param(g_num_pf_handled, int, 0644); + +struct firmware_alloc_info { + struct device *fw_dev; + void *fw_kva; + dma_addr_t fw_dma_hdl; +}; + +struct firmware_alloc_info icp_fw; + +struct cam_smmu_work_payload { + int idx; + struct iommu_domain *domain; + struct device *dev; + unsigned long iova; + int flags; + void *token; + struct list_head list; +}; + +enum cam_protection_type { + CAM_PROT_INVALID, + CAM_NON_SECURE, + CAM_SECURE, + CAM_PROT_MAX, +}; + +enum cam_iommu_type { + CAM_SMMU_INVALID, + CAM_QSMMU, + CAM_ARM_SMMU, + CAM_SMMU_MAX, +}; + +enum cam_smmu_buf_state { + CAM_SMMU_BUFF_EXIST, + CAM_SMMU_BUFF_NOT_EXIST, +}; + +enum cam_smmu_init_dir { + CAM_SMMU_TABLE_INIT, + CAM_SMMU_TABLE_DEINIT, +}; + +struct scratch_mapping { + void *bitmap; + size_t bits; + unsigned int order; + dma_addr_t base; +}; + +struct secheap_buf_info { + struct dma_buf *buf; + struct dma_buf_attachment *attach; + struct sg_table *table; +}; + +struct cam_context_bank_info { + struct device *dev; + struct iommu_domain *domain; + dma_addr_t va_start; + size_t va_len; + const char *name; + bool is_secure; + uint8_t scratch_buf_support; + uint8_t firmware_support; + uint8_t shared_support; + uint8_t io_support; + uint8_t secheap_support; + uint8_t qdss_support; + dma_addr_t qdss_phy_addr; + bool is_fw_allocated; + bool is_secheap_allocated; + bool is_qdss_allocated; + + struct scratch_mapping scratch_map; + struct gen_pool *shared_mem_pool; + + struct cam_smmu_region_info scratch_info; + struct cam_smmu_region_info firmware_info; + struct cam_smmu_region_info shared_info; + struct cam_smmu_region_info io_info; + struct cam_smmu_region_info secheap_info; + struct cam_smmu_region_info qdss_info; + struct secheap_buf_info secheap_buf; + + struct list_head smmu_buf_list; + struct list_head smmu_buf_kernel_list; + struct mutex lock; + int handle; + enum cam_smmu_ops_param state; + + cam_smmu_client_page_fault_handler handler[CAM_SMMU_CB_MAX]; + void *token[CAM_SMMU_CB_MAX]; + int cb_count; + int secure_count; + int pf_count; + + size_t io_mapping_size; + size_t shared_mapping_size; + + /* discard iova - non-zero values are valid */ + dma_addr_t discard_iova_start; + size_t discard_iova_len; +}; + +struct cam_iommu_cb_set { + struct cam_context_bank_info *cb_info; + u32 cb_num; + u32 cb_init_count; + struct work_struct smmu_work; + struct mutex payload_list_lock; + struct list_head payload_list; + u32 non_fatal_fault; + struct dentry *dentry; + bool cb_dump_enable; +}; + +static const struct of_device_id msm_cam_smmu_dt_match[] = { + { .compatible = "qcom,msm-cam-smmu", }, + { .compatible = "qcom,msm-cam-smmu-cb", }, + { .compatible = "qcom,msm-cam-smmu-fw-dev", }, + {} +}; + +struct cam_dma_buff_info { + struct dma_buf *buf; + struct dma_buf_attachment *attach; + struct sg_table *table; + enum dma_data_direction dir; + enum cam_smmu_region_id region_id; + int iommu_dir; + int ref_count; + dma_addr_t paddr; + struct list_head list; + int ion_fd; + size_t len; + size_t phys_len; +}; + +struct cam_sec_buff_info { + struct dma_buf *buf; + enum dma_data_direction dir; + int ref_count; + dma_addr_t paddr; + struct list_head list; + int ion_fd; + size_t len; +}; + +static const char *qdss_region_name = "qdss"; + +static struct cam_iommu_cb_set iommu_cb_set; + +static enum dma_data_direction cam_smmu_translate_dir( + enum cam_smmu_map_dir dir); + +static int cam_smmu_check_handle_unique(int hdl); + +static int cam_smmu_create_iommu_handle(int idx); + +static int cam_smmu_create_add_handle_in_table(char *name, + int *hdl); + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, + int ion_fd); + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_dma_buf(int idx, + struct dma_buf *buf); + +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd); + +static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, + dma_addr_t base, size_t size, + int order); + +static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping, + size_t size, + dma_addr_t *iova); + +static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping, + dma_addr_t addr, size_t size); + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, + dma_addr_t virt_addr); + +static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, + bool dis_delayed_unmap, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, + struct dma_buf *buf, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, + size_t virt_len, + size_t phys_len, + unsigned int iommu_dir, + dma_addr_t *virt_addr); + +static int cam_smmu_unmap_buf_and_remove_from_list( + struct cam_dma_buff_info *mapping_info, int idx); + +static int cam_smmu_free_scratch_buffer_remove_from_list( + struct cam_dma_buff_info *mapping_info, + int idx); + +static void cam_smmu_clean_user_buffer_list(int idx); + +static void cam_smmu_clean_kernel_buffer_list(int idx); + +static void cam_smmu_dump_cb_info(int idx); + +static void cam_smmu_print_user_list(int idx); + +static void cam_smmu_print_kernel_list(int idx); + +static void cam_smmu_print_table(void); + +static int cam_smmu_probe(struct platform_device *pdev); + +static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr); + +static void cam_smmu_page_fault_work(struct work_struct *work) +{ + int j; + int idx; + struct cam_smmu_work_payload *payload; + uint32_t buf_info; + + mutex_lock(&iommu_cb_set.payload_list_lock); + if (list_empty(&iommu_cb_set.payload_list)) { + CAM_ERR(CAM_SMMU, "Payload list empty"); + mutex_unlock(&iommu_cb_set.payload_list_lock); + return; + } + + payload = list_first_entry(&iommu_cb_set.payload_list, + struct cam_smmu_work_payload, + list); + list_del(&payload->list); + mutex_unlock(&iommu_cb_set.payload_list_lock); + + /* Dereference the payload to call the handler */ + idx = payload->idx; + buf_info = cam_smmu_find_closest_mapping(idx, (void *)payload->iova); + if (buf_info != 0) + CAM_INFO(CAM_SMMU, "closest buf 0x%x idx %d", buf_info, idx); + + for (j = 0; j < CAM_SMMU_CB_MAX; j++) { + if ((iommu_cb_set.cb_info[idx].handler[j])) { + iommu_cb_set.cb_info[idx].handler[j]( + payload->domain, + payload->dev, + payload->iova, + payload->flags, + iommu_cb_set.cb_info[idx].token[j], + buf_info); + } + } + cam_smmu_dump_cb_info(idx); + kfree(payload); +} + +static void cam_smmu_dump_cb_info(int idx) +{ + struct cam_dma_buff_info *mapping, *mapping_temp; + size_t shared_reg_len = 0, io_reg_len = 0; + size_t shared_free_len = 0, io_free_len = 0; + uint32_t i = 0; + struct cam_context_bank_info *cb_info = + &iommu_cb_set.cb_info[idx]; + + if (cb_info->shared_support) { + shared_reg_len = cb_info->shared_info.iova_len; + shared_free_len = shared_reg_len - cb_info->shared_mapping_size; + } + + if (cb_info->io_support) { + io_reg_len = cb_info->io_info.iova_len; + io_free_len = io_reg_len - cb_info->io_mapping_size; + } + + CAM_ERR(CAM_SMMU, + "********** Context bank dump for %s **********", + cb_info->name); + CAM_ERR(CAM_SMMU, + "Usage: shared_usage=%u io_usage=%u shared_free=%u io_free=%u", + (unsigned int)cb_info->shared_mapping_size, + (unsigned int)cb_info->io_mapping_size, + (unsigned int)shared_free_len, + (unsigned int)io_free_len); + + if (iommu_cb_set.cb_dump_enable) { + list_for_each_entry_safe(mapping, mapping_temp, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + i++; + CAM_ERR(CAM_SMMU, + "%u. ion_fd=%d start=0x%x end=0x%x len=%u region=%d", + i, mapping->ion_fd, (void *)mapping->paddr, + ((uint64_t)mapping->paddr + + (uint64_t)mapping->len), + (unsigned int)mapping->len, + mapping->region_id); + } + } +} + +static void cam_smmu_print_user_list(int idx) +{ + struct cam_dma_buff_info *mapping; + + CAM_ERR(CAM_SMMU, "index = %d", idx); + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + CAM_ERR(CAM_SMMU, + "ion_fd = %d, paddr= 0x%pK, len = %u, region = %d", + mapping->ion_fd, (void *)mapping->paddr, + (unsigned int)mapping->len, + mapping->region_id); + } +} + +static void cam_smmu_print_kernel_list(int idx) +{ + struct cam_dma_buff_info *mapping; + + CAM_ERR(CAM_SMMU, "index = %d", idx); + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, list) { + CAM_ERR(CAM_SMMU, + "dma_buf = %pK, paddr= 0x%pK, len = %u, region = %d", + mapping->buf, (void *)mapping->paddr, + (unsigned int)mapping->len, + mapping->region_id); + } +} + +static void cam_smmu_print_table(void) +{ + int i; + + for (i = 0; i < iommu_cb_set.cb_num; i++) { + CAM_ERR(CAM_SMMU, "i= %d, handle= %d, name_addr=%pK", i, + (int)iommu_cb_set.cb_info[i].handle, + (void *)iommu_cb_set.cb_info[i].name); + CAM_ERR(CAM_SMMU, "dev = %pK", iommu_cb_set.cb_info[i].dev); + } +} + +static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) +{ + struct cam_dma_buff_info *mapping, *closest_mapping = NULL; + unsigned long start_addr, end_addr, current_addr; + uint32_t buf_handle = 0; + + long delta = 0, lowest_delta = 0; + + current_addr = (unsigned long)vaddr; + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + start_addr = (unsigned long)mapping->paddr; + end_addr = (unsigned long)mapping->paddr + mapping->len; + + if (start_addr <= current_addr && current_addr <= end_addr) { + closest_mapping = mapping; + CAM_INFO(CAM_SMMU, + "Found va 0x%lx in:0x%lx-0x%lx, fd %d cb:%s", + current_addr, start_addr, + end_addr, mapping->ion_fd, + iommu_cb_set.cb_info[idx].name); + goto end; + } else { + if (start_addr > current_addr) + delta = start_addr - current_addr; + else + delta = current_addr - end_addr - 1; + + if (delta < lowest_delta || lowest_delta == 0) { + lowest_delta = delta; + closest_mapping = mapping; + } + CAM_DBG(CAM_SMMU, + "approx va %lx not in range: %lx-%lx fd = %0x", + current_addr, start_addr, + end_addr, mapping->ion_fd); + } + } + +end: + if (closest_mapping) { + buf_handle = GET_MEM_HANDLE(idx, closest_mapping->ion_fd); + CAM_INFO(CAM_SMMU, + "Closest map fd %d 0x%lx %llu-%llu 0x%lx-0x%lx buf=%pK mem %0x", + closest_mapping->ion_fd, current_addr, + mapping->len, closest_mapping->len, + (unsigned long)closest_mapping->paddr, + (unsigned long)closest_mapping->paddr + mapping->len, + closest_mapping->buf, + buf_handle); + } else + CAM_INFO(CAM_SMMU, + "Cannot find vaddr:%lx in SMMU %s virt address", + current_addr, iommu_cb_set.cb_info[idx].name); + + return buf_handle; +} + +void cam_smmu_set_client_page_fault_handler(int handle, + cam_smmu_client_page_fault_handler handler_cb, void *token) +{ + int idx, i = 0; + + if (!token || (handle == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: token is NULL or invalid handle"); + return; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return; + } + + if (handler_cb) { + if (iommu_cb_set.cb_info[idx].cb_count == CAM_SMMU_CB_MAX) { + CAM_ERR(CAM_SMMU, + "%s Should not regiester more handlers", + iommu_cb_set.cb_info[idx].name); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return; + } + + iommu_cb_set.cb_info[idx].cb_count++; + + for (i = 0; i < iommu_cb_set.cb_info[idx].cb_count; i++) { + if (iommu_cb_set.cb_info[idx].token[i] == NULL) { + iommu_cb_set.cb_info[idx].token[i] = token; + iommu_cb_set.cb_info[idx].handler[i] = + handler_cb; + break; + } + } + } else { + for (i = 0; i < CAM_SMMU_CB_MAX; i++) { + if (iommu_cb_set.cb_info[idx].token[i] == token) { + iommu_cb_set.cb_info[idx].token[i] = NULL; + iommu_cb_set.cb_info[idx].handler[i] = + NULL; + iommu_cb_set.cb_info[idx].cb_count--; + break; + } + } + if (i == CAM_SMMU_CB_MAX) + CAM_ERR(CAM_SMMU, + "Error: hdl %x no matching tokens: %s", + handle, iommu_cb_set.cb_info[idx].name); + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +} + +void cam_smmu_unset_client_page_fault_handler(int handle, void *token) +{ + int idx, i = 0; + + if (!token || (handle == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: token is NULL or invalid handle"); + return; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return; + } + + for (i = 0; i < CAM_SMMU_CB_MAX; i++) { + if (iommu_cb_set.cb_info[idx].token[i] == token) { + iommu_cb_set.cb_info[idx].token[i] = NULL; + iommu_cb_set.cb_info[idx].handler[i] = + NULL; + iommu_cb_set.cb_info[idx].cb_count--; + break; + } + } + if (i == CAM_SMMU_CB_MAX) + CAM_ERR(CAM_SMMU, "Error: hdl %x no matching tokens: %s", + handle, iommu_cb_set.cb_info[idx].name); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +} + +static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, + int flags, void *token) +{ + char *cb_name; + int idx; + struct cam_smmu_work_payload *payload; + + if (!token) { + CAM_ERR(CAM_SMMU, "Error: token is NULL"); + CAM_ERR(CAM_SMMU, "Error: domain = %pK, device = %pK", + domain, dev); + CAM_ERR(CAM_SMMU, "iova = %lX, flags = %d", iova, flags); + return -EINVAL; + } + + cb_name = (char *)token; + /* Check whether it is in the table */ + for (idx = 0; idx < iommu_cb_set.cb_num; idx++) { + if (!strcmp(iommu_cb_set.cb_info[idx].name, cb_name)) + break; + } + + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: index is not valid, index = %d, token = %s", + idx, cb_name); + return -EINVAL; + } + + if (++iommu_cb_set.cb_info[idx].pf_count > g_num_pf_handled) { + CAM_INFO_RATE_LIMIT(CAM_SMMU, "PF already handled %d %d %d", + g_num_pf_handled, idx, + iommu_cb_set.cb_info[idx].pf_count); + return -EINVAL; + } + + payload = kzalloc(sizeof(struct cam_smmu_work_payload), GFP_ATOMIC); + if (!payload) + return -EINVAL; + + payload->domain = domain; + payload->dev = dev; + payload->iova = iova; + payload->flags = flags; + payload->token = token; + payload->idx = idx; + + mutex_lock(&iommu_cb_set.payload_list_lock); + list_add_tail(&payload->list, &iommu_cb_set.payload_list); + mutex_unlock(&iommu_cb_set.payload_list_lock); + + cam_smmu_page_fault_work(&iommu_cb_set.smmu_work); + + return -EINVAL; +} + +static int cam_smmu_translate_dir_to_iommu_dir( + enum cam_smmu_map_dir dir) +{ + switch (dir) { + case CAM_SMMU_MAP_READ: + return IOMMU_READ; + case CAM_SMMU_MAP_WRITE: + return IOMMU_WRITE; + case CAM_SMMU_MAP_RW: + return IOMMU_READ|IOMMU_WRITE; + case CAM_SMMU_MAP_INVALID: + default: + CAM_ERR(CAM_SMMU, "Error: Direction is invalid. dir = %d", dir); + break; + }; + return IOMMU_INVALID_DIR; +} + +static enum dma_data_direction cam_smmu_translate_dir( + enum cam_smmu_map_dir dir) +{ + switch (dir) { + case CAM_SMMU_MAP_READ: + return DMA_FROM_DEVICE; + case CAM_SMMU_MAP_WRITE: + return DMA_TO_DEVICE; + case CAM_SMMU_MAP_RW: + return DMA_BIDIRECTIONAL; + case CAM_SMMU_MAP_INVALID: + default: + CAM_ERR(CAM_SMMU, "Error: Direction is invalid. dir = %d", + (int)dir); + break; + } + return DMA_NONE; +} + +void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops) +{ + unsigned int i; + int j = 0; + + for (i = 0; i < iommu_cb_set.cb_num; i++) { + iommu_cb_set.cb_info[i].handle = HANDLE_INIT; + INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_list); + INIT_LIST_HEAD(&iommu_cb_set.cb_info[i].smmu_buf_kernel_list); + iommu_cb_set.cb_info[i].state = CAM_SMMU_DETACH; + iommu_cb_set.cb_info[i].dev = NULL; + iommu_cb_set.cb_info[i].cb_count = 0; + iommu_cb_set.cb_info[i].pf_count = 0; + for (j = 0; j < CAM_SMMU_CB_MAX; j++) { + iommu_cb_set.cb_info[i].token[j] = NULL; + iommu_cb_set.cb_info[i].handler[j] = NULL; + } + if (ops == CAM_SMMU_TABLE_INIT) + mutex_init(&iommu_cb_set.cb_info[i].lock); + else + mutex_destroy(&iommu_cb_set.cb_info[i].lock); + } +} + +static int cam_smmu_check_handle_unique(int hdl) +{ + int i; + + if (hdl == HANDLE_INIT) { + CAM_DBG(CAM_SMMU, + "iommu handle is init number. Need to try again"); + return 1; + } + + for (i = 0; i < iommu_cb_set.cb_num; i++) { + if (iommu_cb_set.cb_info[i].handle == HANDLE_INIT) + continue; + + if (iommu_cb_set.cb_info[i].handle == hdl) { + CAM_DBG(CAM_SMMU, "iommu handle %d conflicts", + (int)hdl); + return 1; + } + } + return 0; +} + +/** + * use low 2 bytes for handle cookie + */ +static int cam_smmu_create_iommu_handle(int idx) +{ + int rand, hdl = 0; + + get_random_bytes(&rand, COOKIE_NUM_BYTE); + hdl = GET_SMMU_HDL(idx, rand); + CAM_DBG(CAM_SMMU, "create handle value = %x", (int)hdl); + return hdl; +} + +static int cam_smmu_attach_device(int idx) +{ + int rc; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + /* attach the mapping to device */ + rc = iommu_attach_device(cb->domain, cb->dev); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: ARM IOMMU attach failed. ret = %d", + rc); + rc = -ENODEV; + } + + return rc; +} + +static int cam_smmu_create_add_handle_in_table(char *name, + int *hdl) +{ + int i; + int handle; + + /* create handle and add in the iommu hardware table */ + for (i = 0; i < iommu_cb_set.cb_num; i++) { + if (!strcmp(iommu_cb_set.cb_info[i].name, name)) { + mutex_lock(&iommu_cb_set.cb_info[i].lock); + if (iommu_cb_set.cb_info[i].handle != HANDLE_INIT) { + if (iommu_cb_set.cb_info[i].is_secure) + iommu_cb_set.cb_info[i].secure_count++; + + mutex_unlock(&iommu_cb_set.cb_info[i].lock); + if (iommu_cb_set.cb_info[i].is_secure) { + *hdl = iommu_cb_set.cb_info[i].handle; + return 0; + } + + CAM_ERR(CAM_SMMU, + "Error: %s already got handle 0x%x", + name, iommu_cb_set.cb_info[i].handle); + + return -EINVAL; + } + + /* make sure handle is unique */ + do { + handle = cam_smmu_create_iommu_handle(i); + } while (cam_smmu_check_handle_unique(handle)); + + /* put handle in the table */ + iommu_cb_set.cb_info[i].handle = handle; + iommu_cb_set.cb_info[i].cb_count = 0; + if (iommu_cb_set.cb_info[i].is_secure) + iommu_cb_set.cb_info[i].secure_count++; + *hdl = handle; + CAM_DBG(CAM_SMMU, "%s creates handle 0x%x", + name, handle); + mutex_unlock(&iommu_cb_set.cb_info[i].lock); + return 0; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find name %s or all handle exist", + name); + cam_smmu_print_table(); + return -EINVAL; +} + +static int cam_smmu_init_scratch_map(struct scratch_mapping *scratch_map, + dma_addr_t base, size_t size, + int order) +{ + unsigned int count = size >> (PAGE_SHIFT + order); + unsigned int bitmap_size = BITS_TO_LONGS(count) * sizeof(long); + int err = 0; + + if (!count) { + err = -EINVAL; + CAM_ERR(CAM_SMMU, "Page count is zero, size passed = %zu", + size); + goto bail; + } + + scratch_map->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!scratch_map->bitmap) { + err = -ENOMEM; + goto bail; + } + + scratch_map->base = base; + scratch_map->bits = BITS_PER_BYTE * bitmap_size; + scratch_map->order = order; + +bail: + return err; +} + +static int cam_smmu_alloc_scratch_va(struct scratch_mapping *mapping, + size_t size, + dma_addr_t *iova) +{ + unsigned int order = get_order(size); + unsigned int align = 0; + unsigned int count, start; + + count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) + + (1 << mapping->order) - 1) >> mapping->order; + + /* + * Transparently, add a guard page to the total count of pages + * to be allocated + */ + count++; + + if (order > mapping->order) + align = (1 << (order - mapping->order)) - 1; + + start = bitmap_find_next_zero_area(mapping->bitmap, mapping->bits, 0, + count, align); + + if (start > mapping->bits) + return -ENOMEM; + + bitmap_set(mapping->bitmap, start, count); + *iova = mapping->base + (start << (mapping->order + PAGE_SHIFT)); + + return 0; +} + +static int cam_smmu_free_scratch_va(struct scratch_mapping *mapping, + dma_addr_t addr, size_t size) +{ + unsigned int start = (addr - mapping->base) >> + (mapping->order + PAGE_SHIFT); + unsigned int count = ((size >> PAGE_SHIFT) + + (1 << mapping->order) - 1) >> mapping->order; + + if (!addr) { + CAM_ERR(CAM_SMMU, "Error: Invalid address"); + return -EINVAL; + } + + if (start + count > mapping->bits) { + CAM_ERR(CAM_SMMU, "Error: Invalid page bits in scratch map"); + return -EINVAL; + } + + /* + * Transparently, add a guard page to the total count of pages + * to be freed + */ + count++; + bitmap_clear(mapping->bitmap, start, count); + + return 0; +} + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_virt_address(int idx, + dma_addr_t virt_addr) +{ + struct cam_dma_buff_info *mapping; + + list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->paddr == virt_addr) { + CAM_DBG(CAM_SMMU, "Found virtual address %lx", + (unsigned long)virt_addr); + return mapping; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find virtual address %lx by index %d", + (unsigned long)virt_addr, idx); + return NULL; +} + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_ion_index(int idx, + int ion_fd) +{ + struct cam_dma_buff_info *mapping; + + if (ion_fd < 0) { + CAM_ERR(CAM_SMMU, "Invalid fd %d", ion_fd); + return NULL; + } + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + CAM_DBG(CAM_SMMU, "find ion_fd %d", ion_fd); + return mapping; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find entry by index %d", idx); + + return NULL; +} + +static struct cam_dma_buff_info *cam_smmu_find_mapping_by_dma_buf(int idx, + struct dma_buf *buf) +{ + struct cam_dma_buff_info *mapping; + + if (!buf) { + CAM_ERR(CAM_SMMU, "Invalid dma_buf"); + return NULL; + } + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, + list) { + if (mapping->buf == buf) { + CAM_DBG(CAM_SMMU, "find dma_buf %pK", buf); + return mapping; + } + } + + CAM_ERR(CAM_SMMU, "Error: Cannot find entry by index %d", idx); + + return NULL; +} + +static struct cam_sec_buff_info *cam_smmu_find_mapping_by_sec_buf_idx(int idx, + int ion_fd) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + CAM_DBG(CAM_SMMU, "find ion_fd %d", ion_fd); + return mapping; + } + } + CAM_ERR(CAM_SMMU, "Error: Cannot find fd %d by index %d", + ion_fd, idx); + return NULL; +} + +static void cam_smmu_clean_user_buffer_list(int idx) +{ + int ret; + struct cam_dma_buff_info *mapping_info, *temp; + + list_for_each_entry_safe(mapping_info, temp, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + CAM_DBG(CAM_SMMU, "Free mapping address %pK, i = %d, fd = %d", + (void *)mapping_info->paddr, idx, + mapping_info->ion_fd); + + if (mapping_info->ion_fd == 0xDEADBEEF) + /* Clean up scratch buffers */ + ret = cam_smmu_free_scratch_buffer_remove_from_list( + mapping_info, idx); + else + /* Clean up regular mapped buffers */ + ret = cam_smmu_unmap_buf_and_remove_from_list( + mapping_info, + idx); + + if (ret < 0) { + CAM_ERR(CAM_SMMU, "Buffer delete failed: idx = %d", + idx); + CAM_ERR(CAM_SMMU, + "Buffer delete failed: addr = %lx, fd = %d", + (unsigned long)mapping_info->paddr, + mapping_info->ion_fd); + /* + * Ignore this error and continue to delete other + * buffers in the list + */ + continue; + } + } +} + +static void cam_smmu_clean_kernel_buffer_list(int idx) +{ + int ret; + struct cam_dma_buff_info *mapping_info, *temp; + + list_for_each_entry_safe(mapping_info, temp, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, list) { + CAM_DBG(CAM_SMMU, + "Free mapping address %pK, i = %d, dma_buf = %pK", + (void *)mapping_info->paddr, idx, + mapping_info->buf); + + /* Clean up regular mapped buffers */ + ret = cam_smmu_unmap_buf_and_remove_from_list( + mapping_info, + idx); + + if (ret < 0) { + CAM_ERR(CAM_SMMU, + "Buffer delete in kernel list failed: idx = %d", + idx); + CAM_ERR(CAM_SMMU, + "Buffer delete failed: addr = %lx, dma_buf = %pK", + (unsigned long)mapping_info->paddr, + mapping_info->buf); + /* + * Ignore this error and continue to delete other + * buffers in the list + */ + continue; + } + } +} + +static int cam_smmu_attach(int idx) +{ + int ret; + + if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) { + ret = -EALREADY; + } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) { + ret = cam_smmu_attach_device(idx); + if (ret < 0) { + CAM_ERR(CAM_SMMU, "Error: ATTACH fail"); + return -ENODEV; + } + iommu_cb_set.cb_info[idx].state = CAM_SMMU_ATTACH; + ret = 0; + } else { + CAM_ERR(CAM_SMMU, "Error: Not detach/attach: %d", + iommu_cb_set.cb_info[idx].state); + ret = -EINVAL; + } + + return ret; +} + +static int cam_smmu_detach_device(int idx) +{ + int rc = 0; + struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; + + /* detach the mapping to device if not already detached */ + if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_DETACH) { + rc = -EALREADY; + } else if (iommu_cb_set.cb_info[idx].state == CAM_SMMU_ATTACH) { + iommu_detach_device(cb->domain, cb->dev); + iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; + } + + return rc; +} + +static int cam_smmu_alloc_iova(size_t size, + int32_t smmu_hdl, uint32_t *iova) +{ + int rc = 0; + int idx; + uint32_t vaddr = 0; + + if (!iova || !size || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + CAM_DBG(CAM_SMMU, "Allocating iova size = %zu for smmu hdl=%X", + size, smmu_hdl); + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, smmu_hdl); + rc = -EINVAL; + goto get_addr_end; + } + + if (!iommu_cb_set.cb_info[idx].shared_support) { + CAM_ERR(CAM_SMMU, + "Error: Shared memory not supported for hdl = %X", + smmu_hdl); + rc = -EINVAL; + goto get_addr_end; + } + + vaddr = gen_pool_alloc(iommu_cb_set.cb_info[idx].shared_mem_pool, size); + if (!vaddr) + return -ENOMEM; + + *iova = vaddr; + +get_addr_end: + return rc; +} + +static int cam_smmu_free_iova(uint32_t addr, size_t size, + int32_t smmu_hdl) +{ + int rc = 0; + int idx; + + if (!size || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].handle != smmu_hdl) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, smmu_hdl); + rc = -EINVAL; + goto get_addr_end; + } + + gen_pool_free(iommu_cb_set.cb_info[idx].shared_mem_pool, addr, size); + +get_addr_end: + return rc; +} + +int cam_smmu_alloc_firmware(int32_t smmu_hdl, + dma_addr_t *iova, + uintptr_t *cpuva, + size_t *len) +{ + int rc; + int32_t idx; + size_t firmware_len = 0; + size_t firmware_start = 0; + struct iommu_domain *domain; + + if (!iova || !len || !cpuva || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].firmware_support) { + CAM_ERR(CAM_SMMU, + "Firmware memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_fw_allocated) { + CAM_ERR(CAM_SMMU, "Trying to allocate twice"); + rc = -ENOMEM; + goto unlock_and_end; + } + + firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len; + firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start; + CAM_DBG(CAM_SMMU, "Firmware area len from DT = %zu", firmware_len); + + icp_fw.fw_kva = dma_alloc_coherent(icp_fw.fw_dev, + firmware_len, + &icp_fw.fw_dma_hdl, + GFP_KERNEL); + if (!icp_fw.fw_kva) { + CAM_ERR(CAM_SMMU, "FW memory alloc failed"); + rc = -ENOMEM; + goto unlock_and_end; + } else { + CAM_DBG(CAM_SMMU, "DMA alloc returned fw = %pK, hdl = %pK", + icp_fw.fw_kva, (void *)icp_fw.fw_dma_hdl); + } + + domain = iommu_cb_set.cb_info[idx].domain; + rc = iommu_map(domain, + firmware_start, + icp_fw.fw_dma_hdl, + firmware_len, + IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV); + + if (rc) { + CAM_ERR(CAM_SMMU, "Failed to map FW into IOMMU"); + rc = -ENOMEM; + goto alloc_fail; + } + iommu_cb_set.cb_info[idx].is_fw_allocated = true; + + *iova = iommu_cb_set.cb_info[idx].firmware_info.iova_start; + *cpuva = (uintptr_t)icp_fw.fw_kva; + *len = firmware_len; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return rc; + +alloc_fail: + dma_free_coherent(icp_fw.fw_dev, + firmware_len, + icp_fw.fw_kva, + icp_fw.fw_dma_hdl); +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_alloc_firmware); + +int cam_smmu_dealloc_firmware(int32_t smmu_hdl) +{ + int rc = 0; + int32_t idx; + size_t firmware_len = 0; + size_t firmware_start = 0; + struct iommu_domain *domain; + size_t unmapped = 0; + + if (smmu_hdl == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].firmware_support) { + CAM_ERR(CAM_SMMU, + "Firmware memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (!iommu_cb_set.cb_info[idx].is_fw_allocated) { + CAM_ERR(CAM_SMMU, + "Trying to deallocate firmware that is not allocated"); + rc = -ENOMEM; + goto unlock_and_end; + } + + firmware_len = iommu_cb_set.cb_info[idx].firmware_info.iova_len; + firmware_start = iommu_cb_set.cb_info[idx].firmware_info.iova_start; + domain = iommu_cb_set.cb_info[idx].domain; + unmapped = iommu_unmap(domain, + firmware_start, + firmware_len); + + if (unmapped != firmware_len) { + CAM_ERR(CAM_SMMU, "Only %zu unmapped out of total %zu", + unmapped, + firmware_len); + rc = -EINVAL; + } + + dma_free_coherent(icp_fw.fw_dev, + firmware_len, + icp_fw.fw_kva, + icp_fw.fw_dma_hdl); + + icp_fw.fw_kva = 0; + icp_fw.fw_dma_hdl = 0; + + iommu_cb_set.cb_info[idx].is_fw_allocated = false; + +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_dealloc_firmware); + +int cam_smmu_alloc_qdss(int32_t smmu_hdl, + dma_addr_t *iova, + size_t *len) +{ + int rc; + int32_t idx; + size_t qdss_len = 0; + size_t qdss_start = 0; + dma_addr_t qdss_phy_addr; + struct iommu_domain *domain; + + if (!iova || !len || (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].qdss_support) { + CAM_ERR(CAM_SMMU, + "QDSS memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_qdss_allocated) { + CAM_ERR(CAM_SMMU, "Trying to allocate twice"); + rc = -ENOMEM; + goto unlock_and_end; + } + + qdss_len = iommu_cb_set.cb_info[idx].qdss_info.iova_len; + qdss_start = iommu_cb_set.cb_info[idx].qdss_info.iova_start; + qdss_phy_addr = iommu_cb_set.cb_info[idx].qdss_phy_addr; + CAM_DBG(CAM_SMMU, "QDSS area len from DT = %zu", qdss_len); + + domain = iommu_cb_set.cb_info[idx].domain; + rc = iommu_map(domain, + qdss_start, + qdss_phy_addr, + qdss_len, + IOMMU_READ|IOMMU_WRITE); + + if (rc) { + CAM_ERR(CAM_SMMU, "Failed to map QDSS into IOMMU"); + goto unlock_and_end; + } + + iommu_cb_set.cb_info[idx].is_qdss_allocated = true; + + *iova = iommu_cb_set.cb_info[idx].qdss_info.iova_start; + *len = qdss_len; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return rc; + +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_alloc_qdss); + +int cam_smmu_dealloc_qdss(int32_t smmu_hdl) +{ + int rc = 0; + int32_t idx; + size_t qdss_len = 0; + size_t qdss_start = 0; + struct iommu_domain *domain; + size_t unmapped = 0; + + if (smmu_hdl == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + rc = -EINVAL; + goto end; + } + + if (!iommu_cb_set.cb_info[idx].qdss_support) { + CAM_ERR(CAM_SMMU, + "QDSS memory not supported for this SMMU handle"); + rc = -EINVAL; + goto end; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (!iommu_cb_set.cb_info[idx].is_qdss_allocated) { + CAM_ERR(CAM_SMMU, + "Trying to deallocate qdss that is not allocated"); + rc = -ENOMEM; + goto unlock_and_end; + } + + qdss_len = iommu_cb_set.cb_info[idx].qdss_info.iova_len; + qdss_start = iommu_cb_set.cb_info[idx].qdss_info.iova_start; + domain = iommu_cb_set.cb_info[idx].domain; + unmapped = iommu_unmap(domain, qdss_start, qdss_len); + + if (unmapped != qdss_len) { + CAM_ERR(CAM_SMMU, "Only %zu unmapped out of total %zu", + unmapped, + qdss_len); + rc = -EINVAL; + } + + iommu_cb_set.cb_info[idx].is_qdss_allocated = false; + +unlock_and_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); +end: + return rc; +} +EXPORT_SYMBOL(cam_smmu_dealloc_qdss); + +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len, + dma_addr_t *discard_iova_start, size_t *discard_iova_len) +{ + int32_t idx; + + if (!iova || !len || !discard_iova_start || !discard_iova_len || + (smmu_hdl == HANDLE_INIT)) { + CAM_ERR(CAM_SMMU, "Error: Input args are invalid"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].io_support) { + CAM_ERR(CAM_SMMU, + "I/O memory not supported for this SMMU handle"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + *iova = iommu_cb_set.cb_info[idx].io_info.iova_start; + *len = iommu_cb_set.cb_info[idx].io_info.iova_len; + *discard_iova_start = + iommu_cb_set.cb_info[idx].io_info.discard_iova_start; + *discard_iova_len = + iommu_cb_set.cb_info[idx].io_info.discard_iova_len; + + CAM_DBG(CAM_SMMU, + "I/O area for hdl = %x Region:[%pK %zu] Discard:[%pK %zu]", + smmu_hdl, *iova, *len, + *discard_iova_start, *discard_iova_len); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return 0; +} + +int cam_smmu_get_region_info(int32_t smmu_hdl, + enum cam_smmu_region_id region_id, + struct cam_smmu_region_info *region_info) +{ + int32_t idx; + struct cam_context_bank_info *cb = NULL; + + if (!region_info) { + CAM_ERR(CAM_SMMU, "Invalid region_info pointer"); + return -EINVAL; + } + + if (smmu_hdl == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "Handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + cb = &iommu_cb_set.cb_info[idx]; + if (!cb) { + CAM_ERR(CAM_SMMU, "SMMU context bank pointer invalid"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + switch (region_id) { + case CAM_SMMU_REGION_FIRMWARE: + if (!cb->firmware_support) { + CAM_ERR(CAM_SMMU, "Firmware not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->firmware_info.iova_start; + region_info->iova_len = cb->firmware_info.iova_len; + break; + case CAM_SMMU_REGION_SHARED: + if (!cb->shared_support) { + CAM_ERR(CAM_SMMU, "Shared mem not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->shared_info.iova_start; + region_info->iova_len = cb->shared_info.iova_len; + break; + case CAM_SMMU_REGION_SCRATCH: + if (!cb->scratch_buf_support) { + CAM_ERR(CAM_SMMU, "Scratch memory not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->scratch_info.iova_start; + region_info->iova_len = cb->scratch_info.iova_len; + break; + case CAM_SMMU_REGION_IO: + if (!cb->io_support) { + CAM_ERR(CAM_SMMU, "IO memory not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->io_info.iova_start; + region_info->iova_len = cb->io_info.iova_len; + break; + case CAM_SMMU_REGION_SECHEAP: + if (!cb->secheap_support) { + CAM_ERR(CAM_SMMU, "Secondary heap not supported"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENODEV; + } + region_info->iova_start = cb->secheap_info.iova_start; + region_info->iova_len = cb->secheap_info.iova_len; + break; + default: + CAM_ERR(CAM_SMMU, "Invalid region id: %d for smmu hdl: %X", + smmu_hdl, region_id); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; +} +EXPORT_SYMBOL(cam_smmu_get_region_info); + +int cam_smmu_reserve_sec_heap(int32_t smmu_hdl, + struct dma_buf *buf, + dma_addr_t *iova, + size_t *request_len) +{ + struct secheap_buf_info *secheap_buf = NULL; + size_t size = 0; + uint32_t sec_heap_iova = 0; + size_t sec_heap_iova_len = 0; + int idx; + int rc = 0; + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].secheap_support) { + CAM_ERR(CAM_SMMU, "Secondary heap not supported"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + + if (iommu_cb_set.cb_info[idx].is_secheap_allocated) { + CAM_ERR(CAM_SMMU, "Trying to allocate secheap twice"); + rc = -ENOMEM; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; + } + + if (IS_ERR_OR_NULL(buf)) { + rc = PTR_ERR(buf); + CAM_ERR(CAM_SMMU, + "Error: dma get buf failed. rc = %d", rc); + goto err_out; + } + + secheap_buf = &iommu_cb_set.cb_info[idx].secheap_buf; + secheap_buf->buf = buf; + secheap_buf->attach = dma_buf_attach(secheap_buf->buf, + iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(secheap_buf->attach)) { + rc = PTR_ERR(secheap_buf->attach); + CAM_ERR(CAM_SMMU, "Error: dma buf attach failed"); + goto err_put; + } + + secheap_buf->table = dma_buf_map_attachment(secheap_buf->attach, + DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(secheap_buf->table)) { + rc = PTR_ERR(secheap_buf->table); + CAM_ERR(CAM_SMMU, "Error: dma buf map attachment failed"); + goto err_detach; + } + + sec_heap_iova = iommu_cb_set.cb_info[idx].secheap_info.iova_start; + sec_heap_iova_len = iommu_cb_set.cb_info[idx].secheap_info.iova_len; + size = iommu_map_sg(iommu_cb_set.cb_info[idx].domain, + sec_heap_iova, + secheap_buf->table->sgl, + secheap_buf->table->nents, + IOMMU_READ | IOMMU_WRITE); + if (size != sec_heap_iova_len) { + CAM_ERR(CAM_SMMU, "IOMMU mapping failed"); + goto err_unmap_sg; + } + + iommu_cb_set.cb_info[idx].is_secheap_allocated = true; + *iova = (uint32_t)sec_heap_iova; + *request_len = sec_heap_iova_len; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return rc; + +err_unmap_sg: + dma_buf_unmap_attachment(secheap_buf->attach, + secheap_buf->table, + DMA_BIDIRECTIONAL); +err_detach: + dma_buf_detach(secheap_buf->buf, + secheap_buf->attach); +err_put: + dma_buf_put(secheap_buf->buf); +err_out: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_reserve_sec_heap); + +int cam_smmu_release_sec_heap(int32_t smmu_hdl) +{ + int idx; + size_t size = 0; + uint32_t sec_heap_iova = 0; + size_t sec_heap_iova_len = 0; + struct secheap_buf_info *secheap_buf = NULL; + + idx = GET_SMMU_TABLE_IDX(smmu_hdl); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, smmu_hdl); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].secheap_support) { + CAM_ERR(CAM_SMMU, "Secondary heap not supported"); + return -EINVAL; + } + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + + if (!iommu_cb_set.cb_info[idx].is_secheap_allocated) { + CAM_ERR(CAM_SMMU, "Trying to release secheap twice"); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -ENOMEM; + } + + secheap_buf = &iommu_cb_set.cb_info[idx].secheap_buf; + sec_heap_iova = iommu_cb_set.cb_info[idx].secheap_info.iova_start; + sec_heap_iova_len = iommu_cb_set.cb_info[idx].secheap_info.iova_len; + + size = iommu_unmap(iommu_cb_set.cb_info[idx].domain, + sec_heap_iova, + sec_heap_iova_len); + if (size != sec_heap_iova_len) { + CAM_ERR(CAM_SMMU, "Failed: Unmapped = %zu, requested = %zu", + size, + sec_heap_iova_len); + } + + dma_buf_unmap_attachment(secheap_buf->attach, + secheap_buf->table, DMA_BIDIRECTIONAL); + dma_buf_detach(secheap_buf->buf, secheap_buf->attach); + dma_buf_put(secheap_buf->buf); + iommu_cb_set.cb_info[idx].is_secheap_allocated = false; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + + return 0; +} +EXPORT_SYMBOL(cam_smmu_release_sec_heap); + +static int cam_smmu_map_buffer_validate(struct dma_buf *buf, + int idx, enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id, + bool dis_delayed_unmap, struct cam_dma_buff_info **mapping_info) +{ + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + struct iommu_domain *domain; + size_t size = 0; + uint32_t iova = 0; + int rc = 0; + + if (IS_ERR_OR_NULL(buf)) { + rc = PTR_ERR(buf); + CAM_ERR(CAM_SMMU, + "Error: dma get buf failed. rc = %d", rc); + goto err_out; + } + + if (!mapping_info) { + rc = -EINVAL; + CAM_ERR(CAM_SMMU, "Error: mapping_info is invalid"); + goto err_out; + } + + attach = dma_buf_attach(buf, iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach); + CAM_ERR(CAM_SMMU, "Error: dma buf attach failed"); + goto err_put; + } + + if (region_id == CAM_SMMU_REGION_SHARED) { + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + CAM_ERR(CAM_SMMU, "Error: dma map attachment failed"); + goto err_detach; + } + + domain = iommu_cb_set.cb_info[idx].domain; + if (!domain) { + CAM_ERR(CAM_SMMU, "CB has no domain set"); + goto err_unmap_sg; + } + + rc = cam_smmu_alloc_iova(*len_ptr, + iommu_cb_set.cb_info[idx].handle, + &iova); + + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "IOVA alloc failed for shared memory, size=%zu, idx=%d, handle=%d", + *len_ptr, idx, + iommu_cb_set.cb_info[idx].handle); + goto err_unmap_sg; + } + + size = iommu_map_sg(domain, iova, table->sgl, table->nents, + IOMMU_READ | IOMMU_WRITE); + + if (size < 0) { + CAM_ERR(CAM_SMMU, "IOMMU mapping failed"); + rc = cam_smmu_free_iova(iova, + size, iommu_cb_set.cb_info[idx].handle); + if (rc) + CAM_ERR(CAM_SMMU, "IOVA free failed"); + rc = -ENOMEM; + goto err_unmap_sg; + } else { + CAM_DBG(CAM_SMMU, + "iommu_map_sg returned iova=%pK, size=%zu", + iova, size); + *paddr_ptr = iova; + *len_ptr = size; + } + iommu_cb_set.cb_info[idx].shared_mapping_size += *len_ptr; + } else if (region_id == CAM_SMMU_REGION_IO) { + if (!dis_delayed_unmap) + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + CAM_ERR(CAM_SMMU, "Error: dma map attachment failed"); + goto err_detach; + } + + *paddr_ptr = sg_dma_address(table->sgl); + *len_ptr = (size_t)buf->size; + iommu_cb_set.cb_info[idx].io_mapping_size += *len_ptr; + } else { + CAM_ERR(CAM_SMMU, "Error: Wrong region id passed"); + rc = -EINVAL; + goto err_unmap_sg; + } + + CAM_DBG(CAM_SMMU, + "iova=%pK, region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", + iova, region_id, *paddr_ptr, *len_ptr, attach->dma_map_attrs); + + if (table->sgl) { + CAM_DBG(CAM_SMMU, + "DMA buf: %pK, device: %pK, attach: %pK, table: %pK", + (void *)buf, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)attach, (void *)table); + CAM_DBG(CAM_SMMU, "table sgl: %pK, rc: %d, dma_address: 0x%x", + (void *)table->sgl, rc, + (unsigned int)table->sgl->dma_address); + } else { + rc = -EINVAL; + CAM_ERR(CAM_SMMU, "Error: table sgl is null"); + goto err_unmap_sg; + } + + /* fill up mapping_info */ + *mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); + if (!(*mapping_info)) { + rc = -ENOSPC; + goto err_alloc; + } + + (*mapping_info)->buf = buf; + (*mapping_info)->attach = attach; + (*mapping_info)->table = table; + (*mapping_info)->paddr = *paddr_ptr; + (*mapping_info)->len = *len_ptr; + (*mapping_info)->dir = dma_dir; + (*mapping_info)->ref_count = 1; + (*mapping_info)->region_id = region_id; + + if (!*paddr_ptr || !*len_ptr) { + CAM_ERR(CAM_SMMU, "Error: Space Allocation failed"); + kfree(*mapping_info); + *mapping_info = NULL; + rc = -ENOSPC; + goto err_alloc; + } + CAM_DBG(CAM_SMMU, "idx=%d, dma_buf=%pK, dev=%pK, paddr=%pK, len=%u", + idx, buf, (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + return 0; + +err_alloc: + if (region_id == CAM_SMMU_REGION_SHARED) { + cam_smmu_free_iova(iova, + size, + iommu_cb_set.cb_info[idx].handle); + + iommu_unmap(iommu_cb_set.cb_info[idx].domain, + *paddr_ptr, + *len_ptr); + } +err_unmap_sg: + dma_buf_unmap_attachment(attach, table, dma_dir); +err_detach: + dma_buf_detach(buf, attach); +err_put: + dma_buf_put(buf); +err_out: + return rc; +} + + +static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, + bool dis_delayed_unmap, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) +{ + int rc = -1; + struct cam_dma_buff_info *mapping_info = NULL; + struct dma_buf *buf = NULL; + + /* returns the dma_buf structure related to an fd */ + buf = dma_buf_get(ion_fd); + + rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, + region_id, dis_delayed_unmap, &mapping_info); + + if (rc) { + CAM_ERR(CAM_SMMU, "buffer validation failure"); + return rc; + } + + mapping_info->ion_fd = ion_fd; + /* add to the list */ + list_add(&mapping_info->list, + &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return 0; +} + +static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, + struct dma_buf *buf, enum dma_data_direction dma_dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) +{ + int rc = -1; + struct cam_dma_buff_info *mapping_info = NULL; + + rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, + region_id, false, &mapping_info); + + if (rc) { + CAM_ERR(CAM_SMMU, "buffer validation failure"); + return rc; + } + + mapping_info->ion_fd = -1; + + /* add to the list */ + list_add(&mapping_info->list, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list); + + return 0; +} + + +static int cam_smmu_unmap_buf_and_remove_from_list( + struct cam_dma_buff_info *mapping_info, + int idx) +{ + int rc; + size_t size; + struct iommu_domain *domain; + + if ((!mapping_info->buf) || (!mapping_info->table) || + (!mapping_info->attach)) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params dev = %pK, table = %pK", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)mapping_info->table); + CAM_ERR(CAM_SMMU, "Error:dma_buf = %pK, attach = %pK", + (void *)mapping_info->buf, + (void *)mapping_info->attach); + return -EINVAL; + } + + CAM_DBG(CAM_SMMU, + "region_id=%d, paddr=%pK, len=%d, dma_map_attrs=%d", + mapping_info->region_id, mapping_info->paddr, mapping_info->len, + mapping_info->attach->dma_map_attrs); + + if (mapping_info->region_id == CAM_SMMU_REGION_SHARED) { + CAM_DBG(CAM_SMMU, + "Removing SHARED buffer paddr = %pK, len = %zu", + (void *)mapping_info->paddr, mapping_info->len); + + domain = iommu_cb_set.cb_info[idx].domain; + + size = iommu_unmap(domain, + mapping_info->paddr, + mapping_info->len); + + if (size != mapping_info->len) { + CAM_ERR(CAM_SMMU, "IOMMU unmap failed"); + CAM_ERR(CAM_SMMU, "Unmapped = %zu, requested = %zu", + size, + mapping_info->len); + } + + rc = cam_smmu_free_iova(mapping_info->paddr, + mapping_info->len, + iommu_cb_set.cb_info[idx].handle); + + if (rc) + CAM_ERR(CAM_SMMU, "IOVA free failed"); + + iommu_cb_set.cb_info[idx].shared_mapping_size -= + mapping_info->len; + } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) { + iommu_cb_set.cb_info[idx].io_mapping_size -= mapping_info->len; + } + + dma_buf_unmap_attachment(mapping_info->attach, + mapping_info->table, mapping_info->dir); + dma_buf_detach(mapping_info->buf, mapping_info->attach); + dma_buf_put(mapping_info->buf); + + mapping_info->buf = NULL; + + list_del_init(&mapping_info->list); + + /* free one buffer */ + kfree(mapping_info); + return 0; +} + +static enum cam_smmu_buf_state cam_smmu_check_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + struct cam_dma_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, list) { + if (mapping->ion_fd == ion_fd) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +static enum cam_smmu_buf_state cam_smmu_check_dma_buf_in_list(int idx, + struct dma_buf *buf, dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + struct cam_dma_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list, list) { + if (mapping->buf == buf) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +static enum cam_smmu_buf_state cam_smmu_check_secure_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + mapping->ref_count++; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +static enum cam_smmu_buf_state cam_smmu_validate_secure_fd_in_list(int idx, + int ion_fd, dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + struct cam_sec_buff_info *mapping; + + list_for_each_entry(mapping, + &iommu_cb_set.cb_info[idx].smmu_buf_list, + list) { + if (mapping->ion_fd == ion_fd) { + *paddr_ptr = mapping->paddr; + *len_ptr = mapping->len; + return CAM_SMMU_BUFF_EXIST; + } + } + + return CAM_SMMU_BUFF_NOT_EXIST; +} + +int cam_smmu_get_handle(char *identifier, int *handle_ptr) +{ + int ret = 0; + + if (!identifier) { + CAM_ERR(CAM_SMMU, "Error: iommu hardware name is NULL"); + return -EINVAL; + } + + if (!handle_ptr) { + CAM_ERR(CAM_SMMU, "Error: handle pointer is NULL"); + return -EINVAL; + } + + /* create and put handle in the table */ + ret = cam_smmu_create_add_handle_in_table(identifier, handle_ptr); + if (ret < 0) + CAM_ERR(CAM_SMMU, "Error: %s get handle fail", identifier); + + return ret; +} +EXPORT_SYMBOL(cam_smmu_get_handle); + +int cam_smmu_ops(int handle, enum cam_smmu_ops_param ops) +{ + int ret = 0, idx; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "Error: Index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + switch (ops) { + case CAM_SMMU_ATTACH: { + ret = cam_smmu_attach(idx); + break; + } + case CAM_SMMU_DETACH: { + ret = cam_smmu_detach_device(idx); + break; + } + case CAM_SMMU_VOTE: + case CAM_SMMU_DEVOTE: + default: + CAM_ERR(CAM_SMMU, "Error: idx = %d, ops = %d", idx, ops); + ret = -EINVAL; + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return ret; +} +EXPORT_SYMBOL(cam_smmu_ops); + +static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, + size_t virt_len, + size_t phys_len, + unsigned int iommu_dir, + dma_addr_t *virt_addr) +{ + unsigned long nents = virt_len / phys_len; + struct cam_dma_buff_info *mapping_info = NULL; + size_t unmapped; + dma_addr_t iova = 0; + struct scatterlist *sg; + int i = 0; + int rc; + struct iommu_domain *domain = NULL; + struct page *page; + struct sg_table *table = NULL; + + CAM_DBG(CAM_SMMU, "nents = %lu, idx = %d, virt_len = %zx", + nents, idx, virt_len); + CAM_DBG(CAM_SMMU, "phys_len = %zx, iommu_dir = %d, virt_addr = %pK", + phys_len, iommu_dir, virt_addr); + + /* + * This table will go inside the 'mapping' structure + * where it will be held until put_scratch_buffer is called + */ + table = kzalloc(sizeof(struct sg_table), GFP_KERNEL); + if (!table) { + rc = -ENOMEM; + goto err_table_alloc; + } + + rc = sg_alloc_table(table, nents, GFP_KERNEL); + if (rc < 0) { + rc = -EINVAL; + goto err_sg_alloc; + } + + page = alloc_pages(GFP_KERNEL, get_order(phys_len)); + if (!page) { + rc = -ENOMEM; + goto err_page_alloc; + } + + /* Now we create the sg list */ + for_each_sg(table->sgl, sg, table->nents, i) + sg_set_page(sg, page, phys_len, 0); + + + /* Get the domain from within our cb_set struct and map it*/ + domain = iommu_cb_set.cb_info[idx].domain; + + rc = cam_smmu_alloc_scratch_va(&iommu_cb_set.cb_info[idx].scratch_map, + virt_len, &iova); + + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Could not find valid iova for scratch buffer"); + goto err_iommu_map; + } + + if (iommu_map_sg(domain, + iova, + table->sgl, + table->nents, + iommu_dir) != virt_len) { + CAM_ERR(CAM_SMMU, "iommu_map_sg() failed"); + goto err_iommu_map; + } + + /* Now update our mapping information within the cb_set struct */ + mapping_info = kzalloc(sizeof(struct cam_dma_buff_info), GFP_KERNEL); + if (!mapping_info) { + rc = -ENOMEM; + goto err_mapping_info; + } + + mapping_info->ion_fd = 0xDEADBEEF; + mapping_info->buf = NULL; + mapping_info->attach = NULL; + mapping_info->table = table; + mapping_info->paddr = iova; + mapping_info->len = virt_len; + mapping_info->iommu_dir = iommu_dir; + mapping_info->ref_count = 1; + mapping_info->phys_len = phys_len; + mapping_info->region_id = CAM_SMMU_REGION_SCRATCH; + + CAM_DBG(CAM_SMMU, "paddr = %pK, len = %zx, phys_len = %zx", + (void *)mapping_info->paddr, + mapping_info->len, mapping_info->phys_len); + + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + *virt_addr = (dma_addr_t)iova; + + CAM_DBG(CAM_SMMU, "mapped virtual address = %lx", + (unsigned long)*virt_addr); + return 0; + +err_mapping_info: + unmapped = iommu_unmap(domain, iova, virt_len); + if (unmapped != virt_len) + CAM_ERR(CAM_SMMU, "Unmapped only %zx instead of %zx", + unmapped, virt_len); +err_iommu_map: + __free_pages(page, get_order(phys_len)); +err_page_alloc: + sg_free_table(table); +err_sg_alloc: + kfree(table); +err_table_alloc: + return rc; +} + +static int cam_smmu_free_scratch_buffer_remove_from_list( + struct cam_dma_buff_info *mapping_info, + int idx) +{ + int rc = 0; + size_t unmapped; + struct iommu_domain *domain = + iommu_cb_set.cb_info[idx].domain; + struct scratch_mapping *scratch_map = + &iommu_cb_set.cb_info[idx].scratch_map; + + if (!mapping_info->table) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params: dev = %pK, table = %pK", + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)mapping_info->table); + return -EINVAL; + } + + /* Clean up the mapping_info struct from the list */ + unmapped = iommu_unmap(domain, mapping_info->paddr, mapping_info->len); + if (unmapped != mapping_info->len) + CAM_ERR(CAM_SMMU, "Unmapped only %zx instead of %zx", + unmapped, mapping_info->len); + + rc = cam_smmu_free_scratch_va(scratch_map, + mapping_info->paddr, + mapping_info->len); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: Invalid iova while freeing scratch buffer"); + rc = -EINVAL; + } + + __free_pages(sg_page(mapping_info->table->sgl), + get_order(mapping_info->phys_len)); + sg_free_table(mapping_info->table); + kfree(mapping_info->table); + list_del_init(&mapping_info->list); + + kfree(mapping_info); + mapping_info = NULL; + + return rc; +} + +int cam_smmu_get_scratch_iova(int handle, + enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, + size_t virt_len, + size_t phys_len) +{ + int idx, rc; + unsigned int iommu_dir; + + if (!paddr_ptr || !virt_len || !phys_len) { + CAM_ERR(CAM_SMMU, "Error: Input pointer or lengths invalid"); + return -EINVAL; + } + + if (virt_len < phys_len) { + CAM_ERR(CAM_SMMU, "Error: virt_len > phys_len"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + iommu_dir = cam_smmu_translate_dir_to_iommu_dir(dir); + if (iommu_dir == IOMMU_INVALID_DIR) { + CAM_ERR(CAM_SMMU, + "Error: translate direction failed. dir = %d", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto error; + } + + if (!iommu_cb_set.cb_info[idx].scratch_buf_support) { + CAM_ERR(CAM_SMMU, + "Error: Context bank does not support scratch bufs"); + rc = -EINVAL; + goto error; + } + + CAM_DBG(CAM_SMMU, "smmu handle = %x, idx = %d, dir = %d", + handle, idx, dir); + CAM_DBG(CAM_SMMU, "virt_len = %zx, phys_len = %zx", + phys_len, virt_len); + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + CAM_ERR(CAM_SMMU, + "Err:Dev %s should call SMMU attach before map buffer", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto error; + } + + if (!IS_ALIGNED(virt_len, PAGE_SIZE)) { + CAM_ERR(CAM_SMMU, + "Requested scratch buffer length not page aligned"); + rc = -EINVAL; + goto error; + } + + if (!IS_ALIGNED(virt_len, phys_len)) { + CAM_ERR(CAM_SMMU, + "Requested virt length not aligned with phys length"); + rc = -EINVAL; + goto error; + } + + rc = cam_smmu_alloc_scratch_buffer_add_to_list(idx, + virt_len, + phys_len, + iommu_dir, + paddr_ptr); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: mapping or add list fail"); + +error: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +int cam_smmu_put_scratch_iova(int handle, + dma_addr_t paddr) +{ + int idx; + int rc = -1; + struct cam_dma_buff_info *mapping_info; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto handle_err; + } + + if (!iommu_cb_set.cb_info[idx].scratch_buf_support) { + CAM_ERR(CAM_SMMU, + "Error: Context bank does not support scratch buffers"); + rc = -EINVAL; + goto handle_err; + } + + /* Based on virtual address and index, we can find mapping info + * of the scratch buffer + */ + mapping_info = cam_smmu_find_mapping_by_virt_address(idx, paddr); + if (!mapping_info) { + CAM_ERR(CAM_SMMU, "Error: Invalid params"); + rc = -ENODEV; + goto handle_err; + } + + /* unmapping one buffer from device */ + rc = cam_smmu_free_scratch_buffer_remove_from_list(mapping_info, idx); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + goto handle_err; + } + +handle_err: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} + +static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = 0; + struct dma_buf *dmabuf = NULL; + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + struct cam_sec_buff_info *mapping_info; + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + dmabuf = dma_buf_get(ion_fd); + if (IS_ERR_OR_NULL((void *)(dmabuf))) { + CAM_ERR(CAM_SMMU, + "Error: dma buf get failed, idx=%d, ion_fd=%d", + idx, ion_fd); + rc = PTR_ERR(dmabuf); + goto err_out; + } + + /* + * ion_phys() is deprecated. call dma_buf_attach() and + * dma_buf_map_attachment() to get the buffer's physical + * address. + */ + attach = dma_buf_attach(dmabuf, iommu_cb_set.cb_info[idx].dev); + if (IS_ERR_OR_NULL(attach)) { + CAM_ERR(CAM_SMMU, + "Error: dma buf attach failed, idx=%d, ion_fd=%d", + idx, ion_fd); + rc = PTR_ERR(attach); + goto err_put; + } + + attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + CAM_ERR(CAM_SMMU, "Error: dma buf map attachment failed"); + rc = PTR_ERR(table); + goto err_detach; + } + + /* return addr and len to client */ + *paddr_ptr = sg_phys(table->sgl); + *len_ptr = (size_t)sg_dma_len(table->sgl); + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL); + if (!mapping_info) { + rc = -ENOMEM; + goto err_unmap_sg; + } + + mapping_info->ion_fd = ion_fd; + mapping_info->paddr = *paddr_ptr; + mapping_info->len = *len_ptr; + mapping_info->dir = dma_dir; + mapping_info->ref_count = 1; + mapping_info->buf = dmabuf; + + CAM_DBG(CAM_SMMU, "idx=%d, ion_fd=%d, dev=%pK, paddr=%pK, len=%u", + idx, ion_fd, + (void *)iommu_cb_set.cb_info[idx].dev, + (void *)*paddr_ptr, (unsigned int)*len_ptr); + + /* add to the list */ + list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); + + return 0; + +err_unmap_sg: + dma_buf_unmap_attachment(attach, table, dma_dir); +err_detach: + dma_buf_detach(dmabuf, attach); +err_put: + dma_buf_put(dmabuf); +err_out: + return rc; +} + +int cam_smmu_map_stage2_iova(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + int idx, rc; + enum dma_data_direction dma_dir; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, + "Error: Invalid inputs, paddr_ptr:%pK, len_ptr: %pK", + paddr_ptr, len_ptr); + return -EINVAL; + } + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + CAM_ERR(CAM_SMMU, + "Error: translate direction failed. dir = %d", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if ((handle == HANDLE_INIT) || + (idx < 0) || + (idx >= iommu_cb_set.cb_num)) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't map secure mem to non secure cb, idx=%d", + idx); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, idx=%d, table_hdl=%x, hdl=%x", + idx, iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_secure_fd_in_list(idx, ion_fd, paddr_ptr, + len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_DBG(CAM_SMMU, + "fd:%d already in list idx:%d, handle=%d give same addr back", + ion_fd, idx, handle); + rc = 0; + goto get_addr_end; + } + rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir, + paddr_ptr, len_ptr); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: mapping or add list fail, idx=%d, handle=%d, fd=%d, rc=%d", + idx, handle, ion_fd, rc); + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_map_stage2_iova); + +static int cam_smmu_secure_unmap_buf_and_remove_from_list( + struct cam_sec_buff_info *mapping_info, + int idx) +{ + if (!mapping_info) { + CAM_ERR(CAM_SMMU, "Error: List doesn't exist"); + return -EINVAL; + } + dma_buf_put(mapping_info->buf); + list_del_init(&mapping_info->list); + + CAM_DBG(CAM_SMMU, "unmap fd: %d, idx : %d", mapping_info->ion_fd, idx); + + /* free one buffer */ + kfree(mapping_info); + return 0; +} + +int cam_smmu_unmap_stage2_iova(int handle, int ion_fd) +{ + int idx, rc; + struct cam_sec_buff_info *mapping_info; + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if ((handle == HANDLE_INIT) || + (idx < 0) || + (idx >= iommu_cb_set.cb_num)) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't unmap secure mem from non secure cb"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto put_addr_end; + } + + /* based on ion fd and index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_sec_buf_idx(idx, ion_fd); + if (!mapping_info) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params! idx = %d, fd = %d", + idx, ion_fd); + rc = -EINVAL; + goto put_addr_end; + } + + mapping_info->ref_count--; + if (mapping_info->ref_count > 0) { + CAM_DBG(CAM_SMMU, + "idx: %d fd = %d ref_count: %d", + idx, ion_fd, mapping_info->ref_count); + rc = 0; + goto put_addr_end; + } + mapping_info->ref_count = 0; + + /* unmapping one buffer from device */ + rc = cam_smmu_secure_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc) { + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + goto put_addr_end; + } + +put_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_unmap_stage2_iova); + +static int cam_smmu_map_iova_validate_params(int handle, + enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, size_t *len_ptr, + enum cam_smmu_region_id region_id) +{ + int idx, rc = 0; + enum dma_data_direction dma_dir; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, "Input pointers are invalid"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Invalid handle"); + return -EINVAL; + } + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + if (region_id != CAM_SMMU_REGION_SHARED) + *len_ptr = (size_t)0; + + dma_dir = cam_smmu_translate_dir(dir); + if (dma_dir == DMA_NONE) { + CAM_ERR(CAM_SMMU, "translate direction failed. dir = %d", dir); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + return rc; +} + +int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, + enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + enum dma_data_direction dma_dir; + + rc = cam_smmu_map_iova_validate_params(handle, dir, paddr_ptr, + len_ptr, region_id); + if (rc) { + CAM_ERR(CAM_SMMU, "initial checks failed, unable to proceed"); + return rc; + } + + dma_dir = (enum dma_data_direction)dir; + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't map non-secure mem to secure cb idx=%d", + idx); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "hdl is not valid, idx=%d, table_hdl = %x, hdl = %x", + idx, iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + CAM_ERR(CAM_SMMU, + "Err:Dev %s should call SMMU attach before map buffer", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_ERR(CAM_SMMU, + "fd:%d already in list idx:%d, handle=%d, give same addr back", + ion_fd, idx, handle); + rc = -EALREADY; + goto get_addr_end; + } + + rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, + dis_delayed_unmap, dma_dir, paddr_ptr, len_ptr, region_id); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "mapping or add list fail, idx=%d, fd=%d, region=%d, rc=%d", + idx, ion_fd, region_id, rc); + cam_smmu_dump_cb_info(idx); + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_map_user_iova); + +int cam_smmu_map_kernel_iova(int handle, struct dma_buf *buf, + enum cam_smmu_map_dir dir, dma_addr_t *paddr_ptr, + size_t *len_ptr, enum cam_smmu_region_id region_id) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + enum dma_data_direction dma_dir; + + rc = cam_smmu_map_iova_validate_params(handle, dir, paddr_ptr, + len_ptr, region_id); + if (rc) { + CAM_ERR(CAM_SMMU, "initial checks failed, unable to proceed"); + return rc; + } + + dma_dir = cam_smmu_translate_dir(dir); + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't map non-secure mem to secure cb"); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, "hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + if (iommu_cb_set.cb_info[idx].state != CAM_SMMU_ATTACH) { + CAM_ERR(CAM_SMMU, + "Err:Dev %s should call SMMU attach before map buffer", + iommu_cb_set.cb_info[idx].name); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_dma_buf_in_list(idx, buf, + paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_ERR(CAM_SMMU, + "dma_buf :%pK already in the list", buf); + rc = -EALREADY; + goto get_addr_end; + } + + rc = cam_smmu_map_kernel_buffer_and_add_to_list(idx, buf, dma_dir, + paddr_ptr, len_ptr, region_id); + if (rc < 0) + CAM_ERR(CAM_SMMU, "mapping or add list fail"); + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_map_kernel_iova); + +int cam_smmu_get_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, "Error: Input pointers are invalid"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't get non-secure mem from secure cb"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_check_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { + CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); + rc = -EINVAL; + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_get_iova); + +int cam_smmu_get_stage2_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr) +{ + int idx, rc = 0; + enum cam_smmu_buf_state buf_state; + + if (!paddr_ptr || !len_ptr) { + CAM_ERR(CAM_SMMU, "Error: Input pointers are invalid"); + return -EINVAL; + } + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + if (!iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't get secure mem from non secure cb"); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto get_addr_end; + } + + buf_state = cam_smmu_validate_secure_fd_in_list(idx, + ion_fd, + paddr_ptr, + len_ptr); + + if (buf_state == CAM_SMMU_BUFF_NOT_EXIST) { + CAM_ERR(CAM_SMMU, "ion_fd:%d not in the mapped list", ion_fd); + rc = -EINVAL; + goto get_addr_end; + } + +get_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_get_stage2_iova); + +static int cam_smmu_unmap_validate_params(int handle) +{ + int idx; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + return 0; +} + +int cam_smmu_unmap_user_iova(int handle, + int ion_fd, enum cam_smmu_region_id region_id) +{ + int idx, rc; + struct cam_dma_buff_info *mapping_info; + + rc = cam_smmu_unmap_validate_params(handle); + if (rc) { + CAM_ERR(CAM_SMMU, "unmap util validation failure"); + return rc; + } + + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't unmap non-secure mem from secure cb"); + rc = -EINVAL; + goto unmap_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto unmap_end; + } + + /* Based on ion_fd & index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd); + + if (!mapping_info) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params idx = %d, fd = %d", + idx, ion_fd); + rc = -EINVAL; + goto unmap_end; + } + + /* Unmapping one buffer from device */ + CAM_DBG(CAM_SMMU, "SMMU: removing buffer idx = %d", idx); + rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + +unmap_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_unmap_user_iova); + +int cam_smmu_unmap_kernel_iova(int handle, + struct dma_buf *buf, enum cam_smmu_region_id region_id) +{ + int idx, rc; + struct cam_dma_buff_info *mapping_info; + + rc = cam_smmu_unmap_validate_params(handle); + if (rc) { + CAM_ERR(CAM_SMMU, "unmap util validation failure"); + return rc; + } + + idx = GET_SMMU_TABLE_IDX(handle); + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].is_secure) { + CAM_ERR(CAM_SMMU, + "Error: can't unmap non-secure mem from secure cb"); + rc = -EINVAL; + goto unmap_end; + } + + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto unmap_end; + } + + /* Based on dma_buf & index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_dma_buf(idx, buf); + + if (!mapping_info) { + CAM_ERR(CAM_SMMU, + "Error: Invalid params idx = %d, dma_buf = %pK", + idx, buf); + rc = -EINVAL; + goto unmap_end; + } + + /* Unmapping one buffer from device */ + CAM_DBG(CAM_SMMU, "SMMU: removing buffer idx = %d", idx); + rc = cam_smmu_unmap_buf_and_remove_from_list(mapping_info, idx); + if (rc < 0) + CAM_ERR(CAM_SMMU, "Error: unmap or remove list fail"); + +unmap_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_unmap_kernel_iova); + + +int cam_smmu_put_iova(int handle, int ion_fd) +{ + int idx; + int rc = 0; + struct cam_dma_buff_info *mapping_info; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + /* find index in the iommu_cb_set.cb_info */ + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + rc = -EINVAL; + goto put_addr_end; + } + + /* based on ion fd and index, we can find mapping info of buffer */ + mapping_info = cam_smmu_find_mapping_by_ion_index(idx, ion_fd); + if (!mapping_info) { + CAM_ERR(CAM_SMMU, "Error: Invalid params idx = %d, fd = %d", + idx, ion_fd); + rc = -EINVAL; + goto put_addr_end; + } + +put_addr_end: + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return rc; +} +EXPORT_SYMBOL(cam_smmu_put_iova); + +int cam_smmu_destroy_handle(int handle) +{ + int idx; + + if (handle == HANDLE_INIT) { + CAM_ERR(CAM_SMMU, "Error: Invalid handle"); + return -EINVAL; + } + + idx = GET_SMMU_TABLE_IDX(handle); + if (idx < 0 || idx >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, + "Error: handle or index invalid. idx = %d hdl = %x", + idx, handle); + return -EINVAL; + } + + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + if (iommu_cb_set.cb_info[idx].handle != handle) { + CAM_ERR(CAM_SMMU, + "Error: hdl is not valid, table_hdl = %x, hdl = %x", + iommu_cb_set.cb_info[idx].handle, handle); + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EINVAL; + } + + if (!list_empty_careful(&iommu_cb_set.cb_info[idx].smmu_buf_list)) { + CAM_ERR(CAM_SMMU, "UMD %s buffer list is not clean", + iommu_cb_set.cb_info[idx].name); + cam_smmu_print_user_list(idx); + cam_smmu_clean_user_buffer_list(idx); + } + + if (!list_empty_careful( + &iommu_cb_set.cb_info[idx].smmu_buf_kernel_list)) { + CAM_ERR(CAM_SMMU, "KMD %s buffer list is not clean", + iommu_cb_set.cb_info[idx].name); + cam_smmu_print_kernel_list(idx); + cam_smmu_clean_kernel_buffer_list(idx); + } + + if (iommu_cb_set.cb_info[idx].is_secure) { + if (iommu_cb_set.cb_info[idx].secure_count == 0) { + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return -EPERM; + } + + iommu_cb_set.cb_info[idx].secure_count--; + if (iommu_cb_set.cb_info[idx].secure_count == 0) { + iommu_cb_set.cb_info[idx].cb_count = 0; + iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; + } + + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; + } + + iommu_cb_set.cb_info[idx].cb_count = 0; + iommu_cb_set.cb_info[idx].handle = HANDLE_INIT; + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + return 0; +} +EXPORT_SYMBOL(cam_smmu_destroy_handle); + +static void cam_smmu_deinit_cb(struct cam_context_bank_info *cb) +{ + if (cb->io_support && cb->domain) { + cb->domain = NULL; + } + + if (cb->shared_support) { + gen_pool_destroy(cb->shared_mem_pool); + cb->shared_mem_pool = NULL; + } + + if (cb->scratch_buf_support) { + kfree(cb->scratch_map.bitmap); + cb->scratch_map.bitmap = NULL; + } +} + +static void cam_smmu_release_cb(struct platform_device *pdev) +{ + int i = 0; + + for (i = 0; i < iommu_cb_set.cb_num; i++) + cam_smmu_deinit_cb(&iommu_cb_set.cb_info[i]); + + devm_kfree(&pdev->dev, iommu_cb_set.cb_info); + iommu_cb_set.cb_num = 0; +} + +static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, + struct device *dev) +{ + int rc = 0; + + if (!cb || !dev) { + CAM_ERR(CAM_SMMU, "Error: invalid input params"); + return -EINVAL; + } + + cb->dev = dev; + cb->is_fw_allocated = false; + cb->is_secheap_allocated = false; + + /* Create a pool with 64K granularity for supporting shared memory */ + if (cb->shared_support) { + cb->shared_mem_pool = gen_pool_create( + SHARED_MEM_POOL_GRANULARITY, -1); + + if (!cb->shared_mem_pool) + return -ENOMEM; + + rc = gen_pool_add(cb->shared_mem_pool, + cb->shared_info.iova_start, + cb->shared_info.iova_len, + -1); + + CAM_DBG(CAM_SMMU, "Shared mem start->%lX", + (unsigned long)cb->shared_info.iova_start); + CAM_DBG(CAM_SMMU, "Shared mem len->%zu", + cb->shared_info.iova_len); + + if (rc) { + CAM_ERR(CAM_SMMU, "Genpool chunk creation failed"); + gen_pool_destroy(cb->shared_mem_pool); + cb->shared_mem_pool = NULL; + return rc; + } + } + + if (cb->scratch_buf_support) { + rc = cam_smmu_init_scratch_map(&cb->scratch_map, + cb->scratch_info.iova_start, + cb->scratch_info.iova_len, + 0); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: failed to create scratch map"); + rc = -ENODEV; + goto end; + } + } + + /* create a virtual mapping */ + if (cb->io_support) { + cb->domain = iommu_get_domain_for_dev(dev); + if (IS_ERR(cb->domain)) { + CAM_ERR(CAM_SMMU, "Error: create domain Failed"); + rc = -ENODEV; + goto end; + } + + iommu_dma_enable_best_fit_algo(dev); + + if (cb->discard_iova_start) + iommu_dma_reserve_iova(dev, cb->discard_iova_start, + cb->discard_iova_len); + + cb->state = CAM_SMMU_ATTACH; + } else { + CAM_ERR(CAM_SMMU, "Context bank does not have IO region"); + rc = -ENODEV; + goto end; + } + + return rc; +end: + if (cb->shared_support) { + gen_pool_destroy(cb->shared_mem_pool); + cb->shared_mem_pool = NULL; + } + + if (cb->scratch_buf_support) { + kfree(cb->scratch_map.bitmap); + cb->scratch_map.bitmap = NULL; + } + + return rc; +} + +static int cam_alloc_smmu_context_banks(struct device *dev) +{ + struct device_node *domains_child_node = NULL; + + if (!dev) { + CAM_ERR(CAM_SMMU, "Error: Invalid device"); + return -ENODEV; + } + + iommu_cb_set.cb_num = 0; + + /* traverse thru all the child nodes and increment the cb count */ + for_each_available_child_of_node(dev->of_node, domains_child_node) { + if (of_device_is_compatible(domains_child_node, + "qcom,msm-cam-smmu-cb")) + iommu_cb_set.cb_num++; + + if (of_device_is_compatible(domains_child_node, + "qcom,qsmmu-cam-cb")) + iommu_cb_set.cb_num++; + } + + if (iommu_cb_set.cb_num == 0) { + CAM_ERR(CAM_SMMU, "Error: no context banks present"); + return -ENOENT; + } + + /* allocate memory for the context banks */ + iommu_cb_set.cb_info = devm_kzalloc(dev, + iommu_cb_set.cb_num * sizeof(struct cam_context_bank_info), + GFP_KERNEL); + + if (!iommu_cb_set.cb_info) { + CAM_ERR(CAM_SMMU, "Error: cannot allocate context banks"); + return -ENOMEM; + } + + cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_INIT); + iommu_cb_set.cb_init_count = 0; + + CAM_DBG(CAM_SMMU, "no of context banks :%d", iommu_cb_set.cb_num); + return 0; +} + +static int cam_smmu_get_discard_memory_regions(struct device_node *of_node, + dma_addr_t *discard_iova_start, size_t *discard_iova_len) +{ + uint32_t discard_iova[2] = { 0 }; + int num_values = 0; + int rc = 0; + + if (!discard_iova_start || !discard_iova_len) + return -EINVAL; + + *discard_iova_start = 0; + *discard_iova_len = 0; + + num_values = of_property_count_u32_elems(of_node, + "iova-region-discard"); + if (num_values <= 0) { + CAM_DBG(CAM_UTIL, "No discard region specified"); + return 0; + } else if (num_values != 2) { + CAM_ERR(CAM_UTIL, "Invalid discard region specified %d", + num_values); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, + "iova-region-discard", + discard_iova, num_values); + if (rc) { + CAM_ERR(CAM_UTIL, "Can not read discard region %d", num_values); + return rc; + } else if (!discard_iova[0] || !discard_iova[1]) { + CAM_ERR(CAM_UTIL, + "Incorrect Discard region specified [0x%x 0x%x]", + discard_iova[0], discard_iova[1]); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "Discard region [0x%x 0x%x]", + discard_iova[0], discard_iova[0] + discard_iova[1]); + + *discard_iova_start = discard_iova[0]; + *discard_iova_len = discard_iova[1]; + + return 0; +} + +static int cam_smmu_get_memory_regions_info(struct device_node *of_node, + struct cam_context_bank_info *cb) +{ + int rc = 0; + struct device_node *mem_map_node = NULL; + struct device_node *child_node = NULL; + const char *region_name; + int num_regions = 0; + + if (!of_node || !cb) { + CAM_ERR(CAM_SMMU, "Invalid argument(s)"); + return -EINVAL; + } + + mem_map_node = of_get_child_by_name(of_node, "iova-mem-map"); + cb->is_secure = of_property_read_bool(of_node, "qcom,secure-cb"); + + /* + * We always expect a memory map node, except when it is a secure + * context bank. + */ + if (!mem_map_node) { + if (cb->is_secure) + return 0; + CAM_ERR(CAM_SMMU, "iova-mem-map not present"); + return -EINVAL; + } + + for_each_available_child_of_node(mem_map_node, child_node) { + uint32_t region_start; + uint32_t region_len; + uint32_t region_id; + uint32_t qdss_region_phy_addr = 0; + + num_regions++; + rc = of_property_read_string(child_node, + "iova-region-name", ®ion_name); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "IOVA region not found"); + return -EINVAL; + } + + rc = of_property_read_u32(child_node, + "iova-region-start", ®ion_start); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "Failed to read iova-region-start"); + return -EINVAL; + } + + rc = of_property_read_u32(child_node, + "iova-region-len", ®ion_len); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "Failed to read iova-region-len"); + return -EINVAL; + } + + rc = of_property_read_u32(child_node, + "iova-region-id", ®ion_id); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, "Failed to read iova-region-id"); + return -EINVAL; + } + + if (strcmp(region_name, qdss_region_name) == 0) { + rc = of_property_read_u32(child_node, + "qdss-phy-addr", &qdss_region_phy_addr); + if (rc < 0) { + of_node_put(mem_map_node); + CAM_ERR(CAM_SMMU, + "Failed to read qdss phy addr"); + return -EINVAL; + } + } + + switch (region_id) { + case CAM_SMMU_REGION_FIRMWARE: + cb->firmware_support = 1; + cb->firmware_info.iova_start = region_start; + cb->firmware_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_SHARED: + cb->shared_support = 1; + cb->shared_info.iova_start = region_start; + cb->shared_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_SCRATCH: + cb->scratch_buf_support = 1; + cb->scratch_info.iova_start = region_start; + cb->scratch_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_IO: + cb->io_support = 1; + cb->io_info.iova_start = region_start; + cb->io_info.iova_len = region_len; + rc = cam_smmu_get_discard_memory_regions(child_node, + &cb->io_info.discard_iova_start, + &cb->io_info.discard_iova_len); + if (rc) { + CAM_ERR(CAM_SMMU, + "Invalid Discard region specified in IO region, rc=%d", + rc); + of_node_put(mem_map_node); + return -EINVAL; + } + break; + case CAM_SMMU_REGION_SECHEAP: + cb->secheap_support = 1; + cb->secheap_info.iova_start = region_start; + cb->secheap_info.iova_len = region_len; + break; + case CAM_SMMU_REGION_QDSS: + cb->qdss_support = 1; + cb->qdss_info.iova_start = region_start; + cb->qdss_info.iova_len = region_len; + cb->qdss_phy_addr = qdss_region_phy_addr; + break; + default: + CAM_ERR(CAM_SMMU, + "Incorrect region id present in DT file: %d", + region_id); + } + + CAM_DBG(CAM_SMMU, "Found label -> %s", cb->name); + CAM_DBG(CAM_SMMU, "Found region -> %s", region_name); + CAM_DBG(CAM_SMMU, "region_start -> %X", region_start); + CAM_DBG(CAM_SMMU, "region_len -> %X", region_len); + CAM_DBG(CAM_SMMU, "region_id -> %X", region_id); + } + + if (cb->io_support) { + rc = cam_smmu_get_discard_memory_regions(of_node, + &cb->discard_iova_start, + &cb->discard_iova_len); + if (rc) { + CAM_ERR(CAM_SMMU, + "Invalid Discard region specified in CB, rc=%d", + rc); + of_node_put(mem_map_node); + return -EINVAL; + } + + /* Make sure Discard region is properly specified */ + if ((cb->discard_iova_start != + cb->io_info.discard_iova_start) || + (cb->discard_iova_len != + cb->io_info.discard_iova_len)) { + CAM_ERR(CAM_SMMU, + "Mismatch Discard region specified, [0x%x 0x%x] [0x%x 0x%x]", + cb->discard_iova_start, + cb->discard_iova_len, + cb->io_info.discard_iova_start, + cb->io_info.discard_iova_len); + of_node_put(mem_map_node); + return -EINVAL; + } else if (cb->discard_iova_start && cb->discard_iova_len) { + if ((cb->discard_iova_start <= + cb->io_info.iova_start) || + (cb->discard_iova_start >= + cb->io_info.iova_start + cb->io_info.iova_len) || + (cb->discard_iova_start + cb->discard_iova_len >= + cb->io_info.iova_start + cb->io_info.iova_len)) { + CAM_ERR(CAM_SMMU, + "[%s] : Incorrect Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", + cb->name, + cb->discard_iova_start, + cb->discard_iova_start + cb->discard_iova_len, + cb->io_info.iova_start, + cb->io_info.iova_start + cb->io_info.iova_len); + of_node_put(mem_map_node); + return -EINVAL; + } + + CAM_INFO(CAM_SMMU, + "[%s] : Discard region specified [0x%x 0x%x] in [0x%x 0x%x]", + cb->name, + cb->discard_iova_start, + cb->discard_iova_start + cb->discard_iova_len, + cb->io_info.iova_start, + cb->io_info.iova_start + cb->io_info.iova_len); + } + } + + of_node_put(mem_map_node); + + if (!num_regions) { + CAM_ERR(CAM_SMMU, + "No memory regions found, at least one needed"); + rc = -ENODEV; + } + + return rc; +} + +static int cam_populate_smmu_context_banks(struct device *dev, + enum cam_iommu_type type) +{ + int rc = 0; + struct cam_context_bank_info *cb; + struct device *ctx = NULL; + + if (!dev) { + CAM_ERR(CAM_SMMU, "Error: Invalid device"); + return -ENODEV; + } + + /* check the bounds */ + if (iommu_cb_set.cb_init_count >= iommu_cb_set.cb_num) { + CAM_ERR(CAM_SMMU, "Error: populate more than allocated cb"); + rc = -EBADHANDLE; + goto cb_init_fail; + } + + /* read the context bank from cb set */ + cb = &iommu_cb_set.cb_info[iommu_cb_set.cb_init_count]; + + /* set the name of the context bank */ + rc = of_property_read_string(dev->of_node, "label", &cb->name); + if (rc < 0) { + CAM_ERR(CAM_SMMU, + "Error: failed to read label from sub device"); + goto cb_init_fail; + } + + rc = cam_smmu_get_memory_regions_info(dev->of_node, + cb); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: Getting region info"); + return rc; + } + + if (cb->is_secure) { + /* increment count to next bank */ + cb->dev = dev; + iommu_cb_set.cb_init_count++; + return 0; + } + + /* set up the iommu mapping for the context bank */ + if (type == CAM_QSMMU) { + CAM_ERR(CAM_SMMU, "Error: QSMMU ctx not supported for : %s", + cb->name); + return -ENODEV; + } + + ctx = dev; + CAM_DBG(CAM_SMMU, "getting Arm SMMU ctx : %s", cb->name); + + rc = cam_smmu_setup_cb(cb, ctx); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", cb->name); + goto cb_init_fail; + } + if (cb->io_support && cb->domain) + iommu_set_fault_handler(cb->domain, + cam_smmu_iommu_fault_handler, + (void *)cb->name); + + if (!dev->dma_parms) + dev->dma_parms = devm_kzalloc(dev, + sizeof(*dev->dma_parms), GFP_KERNEL); + + if (!dev->dma_parms) { + CAM_WARN(CAM_SMMU, + "Failed to allocate dma_params"); + dev->dma_parms = NULL; + goto end; + } + + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64)); + +end: + /* increment count to next bank */ + iommu_cb_set.cb_init_count++; + CAM_DBG(CAM_SMMU, "X: cb init count :%d", iommu_cb_set.cb_init_count); + +cb_init_fail: + return rc; +} + +static int cam_smmu_create_debug_fs(void) +{ + iommu_cb_set.dentry = debugfs_create_dir("camera_smmu", + NULL); + + if (!iommu_cb_set.dentry) { + CAM_ERR(CAM_SMMU, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("cb_dump_enable", + 0644, + iommu_cb_set.dentry, + &iommu_cb_set.cb_dump_enable)) { + CAM_ERR(CAM_SMMU, + "failed to create dump_enable_debug"); + goto err; + } + + return 0; +err: + debugfs_remove_recursive(iommu_cb_set.dentry); + return -ENOMEM; +} + +static int cam_smmu_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + + dev->dma_parms = NULL; + if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu")) { + rc = cam_alloc_smmu_context_banks(dev); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: allocating context banks"); + return -ENOMEM; + } + } + if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-cb")) { + rc = cam_populate_smmu_context_banks(dev, CAM_ARM_SMMU); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: populating context banks"); + cam_smmu_release_cb(pdev); + return -ENOMEM; + } + return rc; + } + if (of_device_is_compatible(dev->of_node, "qcom,qsmmu-cam-cb")) { + rc = cam_populate_smmu_context_banks(dev, CAM_QSMMU); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: populating context banks"); + return -ENOMEM; + } + return rc; + } + + if (of_device_is_compatible(dev->of_node, "qcom,msm-cam-smmu-fw-dev")) { + icp_fw.fw_dev = &pdev->dev; + icp_fw.fw_kva = NULL; + icp_fw.fw_dma_hdl = 0; + return rc; + } + + /* probe through all the subdevices */ + rc = of_platform_populate(pdev->dev.of_node, msm_cam_smmu_dt_match, + NULL, &pdev->dev); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: populating devices"); + } else { + INIT_WORK(&iommu_cb_set.smmu_work, cam_smmu_page_fault_work); + mutex_init(&iommu_cb_set.payload_list_lock); + INIT_LIST_HEAD(&iommu_cb_set.payload_list); + } + + cam_smmu_create_debug_fs(); + return rc; +} + +static int cam_smmu_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + /* release all the context banks and memory allocated */ + cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT); + if (dev && dev->dma_parms) { + devm_kfree(dev, dev->dma_parms); + dev->dma_parms = NULL; + } + + if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu")) + cam_smmu_release_cb(pdev); + + debugfs_remove_recursive(iommu_cb_set.dentry); + iommu_cb_set.dentry = NULL; + return 0; +} + +static struct platform_driver cam_smmu_driver = { + .probe = cam_smmu_probe, + .remove = cam_smmu_remove, + .driver = { + .name = "msm_cam_smmu", + .owner = THIS_MODULE, + .of_match_table = msm_cam_smmu_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_smmu_init_module(void) +{ + return platform_driver_register(&cam_smmu_driver); +} + +static void __exit cam_smmu_exit_module(void) +{ + platform_driver_unregister(&cam_smmu_driver); +} + +module_init(cam_smmu_init_module); +module_exit(cam_smmu_exit_module); +MODULE_DESCRIPTION("MSM Camera SMMU driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_smmu/cam_smmu_api.h b/techpack/camera/drivers/cam_smmu/cam_smmu_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4a4a0d312f9d8ff3a1e32375edfd606fbf08fca3 --- /dev/null +++ b/techpack/camera/drivers/cam_smmu/cam_smmu_api.h @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SMMU_API_H_ +#define _CAM_SMMU_API_H_ + +#include <linux/dma-direction.h> +#include <linux/module.h> +#include <linux/dma-buf.h> +#include <linux/dma-direction.h> +#include <linux/of_platform.h> +#include <linux/iommu.h> +#include <linux/random.h> +#include <linux/spinlock_types.h> +#include <linux/mutex.h> +#include <linux/msm_ion.h> + +/*Enum for possible CAM SMMU operations */ +enum cam_smmu_ops_param { + CAM_SMMU_ATTACH, + CAM_SMMU_DETACH, + CAM_SMMU_VOTE, + CAM_SMMU_DEVOTE, + CAM_SMMU_OPS_INVALID +}; + +enum cam_smmu_map_dir { + CAM_SMMU_MAP_READ, + CAM_SMMU_MAP_WRITE, + CAM_SMMU_MAP_RW, + CAM_SMMU_MAP_INVALID +}; + +enum cam_smmu_region_id { + CAM_SMMU_REGION_FIRMWARE, + CAM_SMMU_REGION_SHARED, + CAM_SMMU_REGION_SCRATCH, + CAM_SMMU_REGION_IO, + CAM_SMMU_REGION_SECHEAP, + CAM_SMMU_REGION_QDSS +}; + +/** + * @brief : Callback function type that gets called back on cam + * smmu page fault. + * + * @param domain : Iommu domain received in iommu page fault handler + * @param dev : Device received in iommu page fault handler + * @param iova : IOVA where page fault occurred + * @param flags : Flags received in iommu page fault handler + * @param token : Userdata given during callback registration + * @param buf_info : Closest mapped buffer info + */ +typedef void (*cam_smmu_client_page_fault_handler)(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token, + uint32_t buf_info); + +/** + * @brief : Structure to store region information + * + * @param iova_start : Start address of region + * @param iova_len : length of region + * @param discard_iova_start : iova addr start from where should not be used + * @param discard_iova_len : length of discard iova region + */ +struct cam_smmu_region_info { + dma_addr_t iova_start; + size_t iova_len; + dma_addr_t discard_iova_start; + size_t discard_iova_len; +}; + +/** + * @brief : Gets an smmu handle + * + * @param identifier: Unique identifier to be used by clients which they + * should get from device tree. CAM SMMU driver will + * not enforce how this string is obtained and will + * only validate this against the list of permitted + * identifiers + * @param handle_ptr: Based on the indentifier, CAM SMMU drivier will + * fill the handle pointed by handle_ptr + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_handle(char *identifier, int *handle_ptr); + +/** + * @brief : Performs IOMMU operations + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param op : Operation to be performed. Can be either CAM_SMMU_ATTACH + * or CAM_SMMU_DETACH + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); + +/** + * @brief : Maps user space IOVA for calling driver + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param ion_fd: ION handle identifying the memory buffer. + * @param dis_delayed_unmap: Whether to disable Delayed Unmap feature + * for this mapping + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE + * @dma_addr : Pointer to physical address where mapped address will be + * returned if region_id is CAM_SMMU_REGION_IO. If region_id is + * CAM_SMMU_REGION_SHARED, dma_addr is used as an input parameter + * which specifies the cpu virtual address to map. + * @len_ptr : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_map_user_iova(int handle, int ion_fd, bool dis_delayed_unmap, + enum cam_smmu_map_dir dir, dma_addr_t *dma_addr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +/** + * @brief : Maps kernel space IOVA for calling driver + * + * @param handle : Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param buf : dma_buf allocated for kernel usage in mem_mgr + * @dir : Mapping direction: which will traslate toDMA_BIDIRECTIONAL, + * DMA_TO_DEVICE or DMA_FROM_DEVICE + * @dma_addr : Pointer to physical address where mapped address will be + * returned if region_id is CAM_SMMU_REGION_IO. If region_id is + * CAM_SMMU_REGION_SHARED, dma_addr is used as an input + * parameter which specifies the cpu virtual address to map. + * @len_ptr : Length of buffer mapped returned by CAM SMMU driver. + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_map_kernel_iova(int handle, + struct dma_buf *buf, enum cam_smmu_map_dir dir, + dma_addr_t *dma_addr, size_t *len_ptr, + enum cam_smmu_region_id region_id); + +/** + * @brief : Unmaps user space IOVA for calling driver + * + * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param ion_fd: ION handle identifying the memory buffer. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_unmap_user_iova(int handle, + int ion_fd, enum cam_smmu_region_id region_id); + +/** + * @brief : Unmaps kernel IOVA for calling driver + * + * @param handle: Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param buf : dma_buf allocated for the kernel + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_unmap_kernel_iova(int handle, + struct dma_buf *buf, enum cam_smmu_region_id region_id); + +/** + * @brief : Allocates a scratch buffer + * + * This function allocates a scratch virtual buffer of length virt_len in the + * device virtual address space mapped to phys_len physically contiguous bytes + * in that device's SMMU. + * + * virt_len and phys_len are expected to be aligned to PAGE_SIZE and with each + * other, otherwise -EINVAL is returned. + * + * -EINVAL will be returned if virt_len is less than phys_len. + * + * Passing a too large phys_len might also cause failure if that much size is + * not available for allocation in a physically contiguous way. + * + * @param handle : Handle to identify the CAMSMMU client (VFE, CPP, FD etc.) + * @param dir : Direction of mapping which will translate to IOMMU_READ + * IOMMU_WRITE or a bit mask of both. + * @param paddr_ptr: Device virtual address that the client device will be + * able to read from/write to + * @param virt_len : Virtual length of the scratch buffer + * @param phys_len : Physical length of the scratch buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ + +int cam_smmu_get_scratch_iova(int handle, + enum cam_smmu_map_dir dir, + dma_addr_t *paddr_ptr, + size_t virt_len, + size_t phys_len); + +/** + * @brief : Frees a scratch buffer + * + * This function frees a scratch buffer and releases the corresponding SMMU + * mappings. + * + * @param handle : Handle to identify the CAMSMMU client (IFE, ICP, etc.) + * @param paddr : Device virtual address of client's scratch buffer that + * will be freed. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ + +int cam_smmu_put_scratch_iova(int handle, + dma_addr_t paddr); + +/** + *@brief : Destroys an smmu handle + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_destroy_handle(int handle); + +/** + * @brief : Finds index by handle in the smmu client table + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @return Index of SMMU client. Nagative in case of error. + */ +int cam_smmu_find_index_by_handle(int hdl); + +/** + * @brief : Registers smmu fault handler for client + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param handler_cb: It is triggered in IOMMU page fault + * @param token: It is input param when trigger page fault handler + */ +void cam_smmu_set_client_page_fault_handler(int handle, + cam_smmu_client_page_fault_handler handler_cb, void *token); + +/** + * @brief : Unregisters smmu fault handler for client + * + * @param handle: Handle to identify the CAM SMMU client (VFE, CPP, FD etc.) + * @param token: It is input param when trigger page fault handler + */ +void cam_smmu_unset_client_page_fault_handler(int handle, void *token); + +/** + * @brief Maps memory from an ION fd into IOVA space + * + * @param handle: SMMU handle identifying the context bank to map to + * @param ion_fd: ION fd of memory to map to + * @param paddr_ptr: Pointer IOVA address that will be returned + * @param len_ptr: Length of memory mapped + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr); + +/** + * @brief Maps memory from an ION fd into IOVA space + * + * @param handle: SMMU handle identifying the secure context bank to map to + * @param ion_fd: ION fd of memory to map to + * @param paddr_ptr: Pointer IOVA address that will be returned + * @param len_ptr: Length of memory mapped + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_stage2_iova(int handle, int ion_fd, + dma_addr_t *paddr_ptr, size_t *len_ptr); + +/** + * @brief Unmaps memory from context bank + * + * @param handle: SMMU handle identifying the context bank + * @param ion_fd: ION fd of memory to unmap + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_put_iova(int handle, int ion_fd); + +/** + * @brief Maps secure memory for SMMU handle + * + * @param handle: SMMU handle identifying secure context bank + * @param ion_fd: ION fd to map securely + * @param dir: DMA Direction for the mapping + * @param dma_addr: Returned IOVA address after mapping + * @param len_ptr: Length of memory mapped + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_map_stage2_iova(int handle, + int ion_fd, enum cam_smmu_map_dir dir, dma_addr_t *dma_addr, + size_t *len_ptr); + +/** + * @brief Unmaps secure memopry for SMMU handle + * + * @param handle: SMMU handle identifying secure context bank + * @param ion_fd: ION fd to unmap + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_unmap_stage2_iova(int handle, int ion_fd); + +/** + * @brief Allocates firmware for context bank + * + * @param smmu_hdl: SMMU handle identifying context bank + * @param iova: IOVA address of allocated firmware + * @param kvaddr: CPU mapped address of allocated firmware + * @param len: Length of allocated firmware memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_alloc_firmware(int32_t smmu_hdl, + dma_addr_t *iova, + uintptr_t *kvaddr, + size_t *len); + +/** + * @brief Deallocates firmware memory for context bank + * + * @param smmu_hdl: SMMU handle identifying the context bank + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_dealloc_firmware(int32_t smmu_hdl); + +/** + * @brief Gets region information specified by smmu handle and region id + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param region_id: Region id for which information is desired + * @param region_info: Struct populated with region information + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_region_info(int32_t smmu_hdl, + enum cam_smmu_region_id region_id, + struct cam_smmu_region_info *region_info); + +/** + * @brief Reserves secondary heap + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param iova: IOVA of secondary heap after reservation has completed + * @param buf: Allocated dma_buf for secondary heap + * @param request_len: Length of secondary heap after reservation has completed + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_reserve_sec_heap(int32_t smmu_hdl, + struct dma_buf *buf, + dma_addr_t *iova, + size_t *request_len); + +/** + * @brief Releases secondary heap + * + * @param smmu_hdl: SMMU handle identifying the context bank + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_release_sec_heap(int32_t smmu_hdl); + +/** + * @brief Allocates qdss for context bank + * + * @param smmu_hdl: SMMU handle identifying context bank + * @param iova: IOVA address of allocated qdss + * @param len: Length of allocated qdss memory + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_alloc_qdss(int32_t smmu_hdl, + dma_addr_t *iova, + size_t *len); + +/** + * @brief Deallocates qdss memory for context bank + * + * @param smmu_hdl: SMMU handle identifying the context bank + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_dealloc_qdss(int32_t smmu_hdl); + +/** + * @brief Get start addr & len of I/O region for a given cb + * + * @param smmu_hdl: SMMU handle identifying the context bank + * @param iova: IOVA address of allocated I/O region + * @param len: Length of allocated I/O memory + * @param discard_iova_start: Start address of io space to discard + * @param discard_iova_len: Length of io space to discard + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_smmu_get_io_region_info(int32_t smmu_hdl, + dma_addr_t *iova, size_t *len, + dma_addr_t *discard_iova_start, size_t *discard_iova_len); + +#endif /* _CAM_SMMU_API_H_ */ diff --git a/techpack/camera/drivers/cam_sync/Makefile b/techpack/camera/drivers/cam_sync/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..40efdf4dd794ff5c80099114492a25ed999b5d3b --- /dev/null +++ b/techpack/camera/drivers/cam_sync/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_utils +ccflags-$(CONFIG_MSM_GLOBAL_SYNX) += -I$(srctree)/drivers/media/platform/msm/synx +ccflags-y += -I$(src) + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync.o cam_sync_util.o diff --git a/techpack/camera/drivers/cam_sync/cam_sync.c b/techpack/camera/drivers/cam_sync/cam_sync.c new file mode 100644 index 0000000000000000000000000000000000000000..33b14f17ceb79b86885dd4e39e7971821bfc7e8d --- /dev/null +++ b/techpack/camera/drivers/cam_sync/cam_sync.c @@ -0,0 +1,1156 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/irqflags.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/debugfs.h> +#include "cam_sync_util.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +#ifdef CONFIG_MSM_GLOBAL_SYNX +#include <synx_api.h> +#endif +struct sync_device *sync_dev; + +/* + * Flag to determine whether to enqueue cb of a + * signaled fence onto the workq or invoke it + * directly in the same context + */ +static bool trigger_cb_without_switch; + +static void cam_sync_print_fence_table(void) +{ + int idx; + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) { + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + CAM_INFO(CAM_SYNC, + "index[%u]: sync_id=%d, name=%s, type=%d, state=%d, ref_cnt=%d", + idx, + sync_dev->sync_table[idx].sync_id, + sync_dev->sync_table[idx].name, + sync_dev->sync_table[idx].type, + sync_dev->sync_table[idx].state, + sync_dev->sync_table[idx].ref_cnt); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + } +} + +int cam_sync_create(int32_t *sync_obj, const char *name) +{ + int rc; + long idx; + bool bit; + + do { + idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + if (idx >= CAM_SYNC_MAX_OBJS) { + CAM_ERR(CAM_SYNC, + "Error: Unable to create sync idx = %d reached max!", + idx); + cam_sync_print_fence_table(); + return -ENOMEM; + } + CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx); + bit = test_and_set_bit(idx, sync_dev->bitmap); + } while (bit); + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + rc = cam_sync_init_row(sync_dev->sync_table, idx, name, + CAM_SYNC_TYPE_INDV); + if (rc) { + CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", + idx); + clear_bit(idx, sync_dev->bitmap); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + return -EINVAL; + } + + *sync_obj = idx; + CAM_DBG(CAM_SYNC, "sync_obj: %i", *sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + return rc; +} + +int cam_sync_register_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj) +{ + struct sync_callback_info *sync_cb; + struct sync_table_row *row = NULL; + int status = 0; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func) + return -EINVAL; + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EINVAL; + } + + sync_cb = kzalloc(sizeof(*sync_cb), GFP_ATOMIC); + if (!sync_cb) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -ENOMEM; + } + + /* Trigger callback if sync object is already in SIGNALED state */ + if ((row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS || + row->state == CAM_SYNC_STATE_SIGNALED_ERROR) && + (!row->remaining)) { + if (trigger_cb_without_switch) { + CAM_DBG(CAM_SYNC, "Invoke callback for sync object:%d", + sync_obj); + status = row->state; + kfree(sync_cb); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + cb_func(sync_obj, status, userdata); + } else { + sync_cb->callback_func = cb_func; + sync_cb->cb_data = userdata; + sync_cb->sync_obj = sync_obj; + INIT_WORK(&sync_cb->cb_dispatch_work, + cam_sync_util_cb_dispatch); + sync_cb->status = row->state; + CAM_DBG(CAM_SYNC, "Enqueue callback for sync object:%d", + sync_cb->sync_obj); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + } + + return 0; + } + + sync_cb->callback_func = cb_func; + sync_cb->cb_data = userdata; + sync_cb->sync_obj = sync_obj; + INIT_WORK(&sync_cb->cb_dispatch_work, cam_sync_util_cb_dispatch); + list_add_tail(&sync_cb->list, &row->callback_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + return 0; +} + +int cam_sync_deregister_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + struct sync_callback_info *sync_cb, *temp; + bool found = false; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EINVAL; + } + + CAM_DBG(CAM_SYNC, "deregistered callback for sync object:%d", + sync_obj); + list_for_each_entry_safe(sync_cb, temp, &row->callback_list, list) { + if (sync_cb->callback_func == cb_func && + sync_cb->cb_data == userdata) { + list_del_init(&sync_cb->list); + kfree(sync_cb); + found = true; + } + } + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return found ? 0 : -ENOENT; +} + +int cam_sync_signal(int32_t sync_obj, uint32_t status) +{ + struct sync_table_row *row = NULL; + struct sync_table_row *parent_row = NULL; + struct sync_parent_info *parent_info, *temp_parent_info; + struct list_head parents_list; + int rc = 0; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { + CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)", + sync_obj, CAM_SYNC_MAX_OBJS); + return -EINVAL; + } + row = sync_dev->sync_table + sync_obj; + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + + if (row->type == CAM_SYNC_TYPE_GROUP) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: Signaling a GROUP sync object = %d", + sync_obj); + return -EINVAL; + } + + if (row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: Sync object already signaled sync_obj = %d", + sync_obj); + return -EALREADY; + } + + if (status != CAM_SYNC_STATE_SIGNALED_SUCCESS && + status != CAM_SYNC_STATE_SIGNALED_ERROR) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: signaling with undefined status = %d", + status); + return -EINVAL; + } + + if (!atomic_dec_and_test(&row->ref_cnt)) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; + } + + row->state = status; + cam_sync_util_dispatch_signaled_cb(sync_obj, status); + + /* copy parent list to local and release child lock */ + INIT_LIST_HEAD(&parents_list); + list_splice_init(&row->parents_list, &parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + if (list_empty(&parents_list)) + return 0; + + /* + * Now iterate over all parents of this object and if they too need to + * be signaled dispatch cb's + */ + list_for_each_entry_safe(parent_info, + temp_parent_info, + &parents_list, + list) { + parent_row = sync_dev->sync_table + parent_info->sync_id; + spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + parent_row->remaining--; + + rc = cam_sync_util_update_parent_state( + parent_row, + status); + if (rc) { + CAM_ERR(CAM_SYNC, "Invalid parent state %d", + parent_row->state); + spin_unlock_bh( + &sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); + continue; + } + + if (!parent_row->remaining) + cam_sync_util_dispatch_signaled_cb( + parent_info->sync_id, parent_row->state); + + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + list_del_init(&parent_info->list); + kfree(parent_info); + } + + return 0; +} + +int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) +{ + int rc; + long idx = 0; + bool bit; + + if (!sync_obj || !merged_obj) { + CAM_ERR(CAM_SYNC, "Invalid pointer(s)"); + return -EINVAL; + } + + if (num_objs <= 1) { + CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); + return -EINVAL; + } + + if (cam_common_util_remove_duplicate_arr(sync_obj, num_objs) + != num_objs) { + CAM_ERR(CAM_SYNC, "The obj list has duplicate fence"); + return -EINVAL; + } + + do { + idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + if (idx >= CAM_SYNC_MAX_OBJS) + return -ENOMEM; + bit = test_and_set_bit(idx, sync_dev->bitmap); + } while (bit); + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + rc = cam_sync_init_group_object(sync_dev->sync_table, + idx, sync_obj, + num_objs); + if (rc < 0) { + CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", + idx); + clear_bit(idx, sync_dev->bitmap); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + return -EINVAL; + } + CAM_DBG(CAM_SYNC, "Init row at idx:%ld to merge objects", idx); + *merged_obj = idx; + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + return 0; +} + +int cam_sync_get_obj_ref(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + spin_lock(&sync_dev->row_spinlocks[sync_obj]); + + if (row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + + atomic_inc(&row->ref_cnt); + spin_unlock(&sync_dev->row_spinlocks[sync_obj]); + CAM_DBG(CAM_SYNC, "get ref for obj %d", sync_obj); + + return 0; +} + +int cam_sync_put_obj_ref(int32_t sync_obj) +{ + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + atomic_dec(&row->ref_cnt); + CAM_DBG(CAM_SYNC, "put ref for obj %d", sync_obj); + + return 0; +} + +int cam_sync_destroy(int32_t sync_obj) +{ + CAM_DBG(CAM_SYNC, "sync_obj: %i", sync_obj); + return cam_sync_deinit_object(sync_dev->sync_table, sync_obj); +} + +int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms) +{ + unsigned long timeleft; + int rc = -EINVAL; + struct sync_table_row *row = NULL; + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + return -EINVAL; + } + + timeleft = wait_for_completion_timeout(&row->signaled, + msecs_to_jiffies(timeout_ms)); + + if (!timeleft) { + CAM_ERR(CAM_SYNC, + "Error: timed out for sync obj = %d", sync_obj); + rc = -ETIMEDOUT; + } else { + switch (row->state) { + case CAM_SYNC_STATE_INVALID: + case CAM_SYNC_STATE_ACTIVE: + case CAM_SYNC_STATE_SIGNALED_ERROR: + CAM_ERR(CAM_SYNC, + "Error: Wait on invalid state = %d, obj = %d", + row->state, sync_obj); + rc = -EINVAL; + break; + case CAM_SYNC_STATE_SIGNALED_SUCCESS: + rc = 0; + break; + default: + rc = -EINVAL; + break; + } + } + + return rc; +} + +static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_info sync_create; + int result; + + if (k_ioctl->size != sizeof(struct cam_sync_info)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_create, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + result = cam_sync_create(&sync_create.sync_obj, + sync_create.name); + + if (!result) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->ioctl_ptr), + &sync_create, + k_ioctl->size)) + return -EFAULT; + + return result; +} + +static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) +{ + int rc = 0; + struct cam_sync_signal sync_signal; + + if (k_ioctl->size != sizeof(struct cam_sync_signal)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_signal, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + /* need to get ref for UMD signaled fences */ + rc = cam_sync_get_obj_ref(sync_signal.sync_obj); + if (rc) { + CAM_DBG(CAM_SYNC, + "Error: cannot signal an uninitialized sync obj = %d", + sync_signal.sync_obj); + return rc; + } + + return cam_sync_signal(sync_signal.sync_obj, + sync_signal.sync_state); +} + +static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_merge sync_merge; + uint32_t *sync_objs; + uint32_t num_objs; + uint32_t size; + int result; + + if (k_ioctl->size != sizeof(struct cam_sync_merge)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_merge, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + if (sync_merge.num_objs >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + size = sizeof(uint32_t) * sync_merge.num_objs; + sync_objs = kzalloc(size, GFP_ATOMIC); + + if (!sync_objs) + return -ENOMEM; + + if (copy_from_user(sync_objs, + u64_to_user_ptr(sync_merge.sync_objs), + sizeof(uint32_t) * sync_merge.num_objs)) { + kfree(sync_objs); + return -EFAULT; + } + + num_objs = sync_merge.num_objs; + + result = cam_sync_merge(sync_objs, + num_objs, + &sync_merge.merged); + + if (!result) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->ioctl_ptr), + &sync_merge, + k_ioctl->size)) { + kfree(sync_objs); + return -EFAULT; + } + + kfree(sync_objs); + + return result; +} + +static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_wait sync_wait; + + if (k_ioctl->size != sizeof(struct cam_sync_wait)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_wait, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + k_ioctl->result = cam_sync_wait(sync_wait.sync_obj, + sync_wait.timeout_ms); + + return 0; +} + +static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_info sync_create; + + if (k_ioctl->size != sizeof(struct cam_sync_info)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&sync_create, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + return cam_sync_destroy(sync_create.sync_obj); +} + +static int cam_sync_handle_register_user_payload( + struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_userpayload_info userpayload_info; + struct sync_user_payload *user_payload_kernel; + struct sync_user_payload *user_payload_iter; + struct sync_user_payload *temp_upayload_kernel; + uint32_t sync_obj; + struct sync_table_row *row = NULL; + + if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) + return -EINVAL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + + if (copy_from_user(&userpayload_info, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + sync_obj = userpayload_info.sync_obj; + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + user_payload_kernel = kzalloc(sizeof(*user_payload_kernel), GFP_KERNEL); + if (!user_payload_kernel) + return -ENOMEM; + + memcpy(user_payload_kernel->payload_data, + userpayload_info.payload, + CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + kfree(user_payload_kernel); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS || + row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + + cam_sync_util_send_v4l2_event(CAM_SYNC_V4L_EVENT_ID_CB_TRIG, + sync_obj, + row->state, + user_payload_kernel->payload_data, + CAM_SYNC_USER_PAYLOAD_SIZE * sizeof(__u64)); + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + kfree(user_payload_kernel); + return 0; + } + + list_for_each_entry_safe(user_payload_iter, + temp_upayload_kernel, + &row->user_payload_list, + list) { + if (user_payload_iter->payload_data[0] == + user_payload_kernel->payload_data[0] && + user_payload_iter->payload_data[1] == + user_payload_kernel->payload_data[1]) { + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + kfree(user_payload_kernel); + return -EALREADY; + } + } + + list_add_tail(&user_payload_kernel->list, &row->user_payload_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; +} + +static int cam_sync_handle_deregister_user_payload( + struct cam_private_ioctl_arg *k_ioctl) +{ + struct cam_sync_userpayload_info userpayload_info; + struct sync_user_payload *user_payload_kernel, *temp; + uint32_t sync_obj; + struct sync_table_row *row = NULL; + + if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) { + CAM_ERR(CAM_SYNC, "Incorrect ioctl size"); + return -EINVAL; + } + + if (!k_ioctl->ioctl_ptr) { + CAM_ERR(CAM_SYNC, "Invalid embedded ioctl ptr"); + return -EINVAL; + } + + if (copy_from_user(&userpayload_info, + u64_to_user_ptr(k_ioctl->ioctl_ptr), + k_ioctl->size)) + return -EFAULT; + + sync_obj = userpayload_info.sync_obj; + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) + return -EINVAL; + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + row = sync_dev->sync_table + sync_obj; + + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj = %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EINVAL; + } + + list_for_each_entry_safe(user_payload_kernel, temp, + &row->user_payload_list, list) { + if (user_payload_kernel->payload_data[0] == + userpayload_info.payload[0] && + user_payload_kernel->payload_data[1] == + userpayload_info.payload[1]) { + list_del_init(&user_payload_kernel->list); + kfree(user_payload_kernel); + } + } + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; +} + +static long cam_sync_dev_ioctl(struct file *filep, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + int32_t rc; + struct sync_device *sync_dev = video_drvdata(filep); + struct cam_private_ioctl_arg k_ioctl; + + if (!sync_dev) { + CAM_ERR(CAM_SYNC, "sync_dev NULL"); + return -EINVAL; + } + + if (!arg) + return -EINVAL; + + if (cmd != CAM_PRIVATE_IOCTL_CMD) + return -ENOIOCTLCMD; + + k_ioctl = *(struct cam_private_ioctl_arg *)arg; + + switch (k_ioctl.id) { + case CAM_SYNC_CREATE: + rc = cam_sync_handle_create(&k_ioctl); + break; + case CAM_SYNC_DESTROY: + rc = cam_sync_handle_destroy(&k_ioctl); + break; + case CAM_SYNC_REGISTER_PAYLOAD: + rc = cam_sync_handle_register_user_payload( + &k_ioctl); + break; + case CAM_SYNC_DEREGISTER_PAYLOAD: + rc = cam_sync_handle_deregister_user_payload( + &k_ioctl); + break; + case CAM_SYNC_SIGNAL: + rc = cam_sync_handle_signal(&k_ioctl); + break; + case CAM_SYNC_MERGE: + rc = cam_sync_handle_merge(&k_ioctl); + break; + case CAM_SYNC_WAIT: + rc = cam_sync_handle_wait(&k_ioctl); + ((struct cam_private_ioctl_arg *)arg)->result = + k_ioctl.result; + break; + default: + rc = -ENOIOCTLCMD; + } + + return rc; +} + +static unsigned int cam_sync_poll(struct file *f, + struct poll_table_struct *pll_table) +{ + int rc = 0; + struct v4l2_fh *eventq = f->private_data; + + if (!eventq) + return -EINVAL; + + poll_wait(f, &eventq->wait, pll_table); + + if (v4l2_event_pending(eventq)) + rc = POLLPRI; + + return rc; +} + +static int cam_sync_open(struct file *filep) +{ + int rc; + struct sync_device *sync_dev = video_drvdata(filep); + + if (!sync_dev) { + CAM_ERR(CAM_SYNC, "Sync device NULL"); + return -ENODEV; + } + + mutex_lock(&sync_dev->table_lock); + if (sync_dev->open_cnt >= 1) { + mutex_unlock(&sync_dev->table_lock); + return -EALREADY; + } + + rc = v4l2_fh_open(filep); + if (!rc) { + sync_dev->open_cnt++; + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + sync_dev->cam_sync_eventq = filep->private_data; + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + } else { + CAM_ERR(CAM_SYNC, "v4l2_fh_open failed : %d", rc); + } + mutex_unlock(&sync_dev->table_lock); + + return rc; +} + +static int cam_sync_close(struct file *filep) +{ + int rc = 0; + int i; + struct sync_device *sync_dev = video_drvdata(filep); + + if (!sync_dev) { + CAM_ERR(CAM_SYNC, "Sync device NULL"); + rc = -ENODEV; + return rc; + } + mutex_lock(&sync_dev->table_lock); + sync_dev->open_cnt--; + if (!sync_dev->open_cnt) { + for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) { + struct sync_table_row *row = + sync_dev->sync_table + i; + + /* + * Signal all ACTIVE objects as ERR, but we don't + * care about the return status here apart from logging + * it. + */ + if (row->state == CAM_SYNC_STATE_ACTIVE) { + rc = cam_sync_signal(i, + CAM_SYNC_STATE_SIGNALED_ERROR); + if (rc < 0) + CAM_ERR(CAM_SYNC, + "Cleanup signal fail idx:%d\n", + i); + } + } + + /* + * Flush the work queue to wait for pending signal callbacks to + * finish + */ + flush_workqueue(sync_dev->work_queue); + + /* + * Now that all callbacks worker threads have finished, + * destroy the sync objects + */ + for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) { + struct sync_table_row *row = + sync_dev->sync_table + i; + + if (row->state != CAM_SYNC_STATE_INVALID) { + rc = cam_sync_destroy(i); + if (rc < 0) + CAM_ERR(CAM_SYNC, + "Cleanup destroy fail:idx:%d\n", + i); + } + } + } + mutex_unlock(&sync_dev->table_lock); + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + sync_dev->cam_sync_eventq = NULL; + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + v4l2_fh_release(filep); + + return rc; +} + +static void cam_sync_event_queue_notify_error(const struct v4l2_event *old, + struct v4l2_event *new) +{ + struct cam_sync_ev_header *ev_header; + + ev_header = CAM_SYNC_GET_HEADER_PTR((*old)); + CAM_ERR(CAM_CRM, "Failed to notify event id %d fence %d statue %d", + old->id, ev_header->sync_obj, ev_header->status); +} + +static struct v4l2_subscribed_event_ops cam_sync_v4l2_ops = { + .merge = cam_sync_event_queue_notify_error, +}; + +int cam_sync_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, + &cam_sync_v4l2_ops); +} + +int cam_sync_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +static const struct v4l2_ioctl_ops g_cam_sync_ioctl_ops = { + .vidioc_subscribe_event = cam_sync_subscribe_event, + .vidioc_unsubscribe_event = cam_sync_unsubscribe_event, + .vidioc_default = cam_sync_dev_ioctl, +}; + +static struct v4l2_file_operations cam_sync_v4l2_fops = { + .owner = THIS_MODULE, + .open = cam_sync_open, + .release = cam_sync_close, + .poll = cam_sync_poll, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = video_ioctl2, +#endif +}; + +#if defined(CONFIG_MEDIA_CONTROLLER) +static int cam_sync_media_controller_init(struct sync_device *sync_dev, + struct platform_device *pdev) +{ + int rc; + + sync_dev->v4l2_dev.mdev = kzalloc(sizeof(struct media_device), + GFP_KERNEL); + if (!sync_dev->v4l2_dev.mdev) + return -ENOMEM; + + media_device_init(sync_dev->v4l2_dev.mdev); + strlcpy(sync_dev->v4l2_dev.mdev->model, CAM_SYNC_DEVICE_NAME, + sizeof(sync_dev->v4l2_dev.mdev->model)); + sync_dev->v4l2_dev.mdev->dev = &(pdev->dev); + + rc = media_device_register(sync_dev->v4l2_dev.mdev); + if (rc < 0) + goto register_fail; + + rc = media_entity_pads_init(&sync_dev->vdev->entity, 0, NULL); + if (rc < 0) + goto entity_fail; + + return 0; + +entity_fail: + media_device_unregister(sync_dev->v4l2_dev.mdev); +register_fail: + media_device_cleanup(sync_dev->v4l2_dev.mdev); + return rc; +} + +static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev) +{ + media_entity_cleanup(&sync_dev->vdev->entity); + media_device_unregister(sync_dev->v4l2_dev.mdev); + media_device_cleanup(sync_dev->v4l2_dev.mdev); + kfree(sync_dev->v4l2_dev.mdev); +} + +static void cam_sync_init_entity(struct sync_device *sync_dev) +{ + sync_dev->vdev->entity.function = CAM_SYNC_DEVICE_TYPE; + sync_dev->vdev->entity.name = + video_device_node_name(sync_dev->vdev); +} +#else +static int cam_sync_media_controller_init(struct sync_device *sync_dev, + struct platform_device *pdev) +{ + return 0; +} + +static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev) +{ +} + +static void cam_sync_init_entity(struct sync_device *sync_dev) +{ +} +#endif + +static int cam_sync_create_debugfs(void) +{ + sync_dev->dentry = debugfs_create_dir("camera_sync", NULL); + + if (!sync_dev->dentry) { + CAM_ERR(CAM_SYNC, "Failed to create sync dir"); + return -ENOMEM; + } + + if (!debugfs_create_bool("trigger_cb_without_switch", + 0644, sync_dev->dentry, + &trigger_cb_without_switch)) { + CAM_ERR(CAM_SYNC, + "failed to create trigger_cb_without_switch entry"); + return -ENOMEM; + } + + return 0; +} + +#ifdef CONFIG_MSM_GLOBAL_SYNX +static void cam_sync_register_synx_bind_ops(void) +{ + int rc = 0; + struct synx_register_params params; + + params.name = CAM_SYNC_NAME; + params.type = SYNX_TYPE_CSL; + params.ops.register_callback = cam_sync_register_callback; + params.ops.deregister_callback = cam_sync_deregister_callback; + params.ops.enable_signaling = cam_sync_get_obj_ref; + params.ops.signal = cam_sync_signal; + + rc = synx_register_ops(¶ms); + if (rc) + CAM_ERR(CAM_SYNC, "synx registration fail with %d", rc); +} +#endif + +static int cam_sync_probe(struct platform_device *pdev) +{ + int rc; + int idx; + + sync_dev = kzalloc(sizeof(*sync_dev), GFP_KERNEL); + if (!sync_dev) + return -ENOMEM; + + mutex_init(&sync_dev->table_lock); + spin_lock_init(&sync_dev->cam_sync_eventq_lock); + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) + spin_lock_init(&sync_dev->row_spinlocks[idx]); + + sync_dev->vdev = video_device_alloc(); + if (!sync_dev->vdev) { + rc = -ENOMEM; + goto vdev_fail; + } + + rc = cam_sync_media_controller_init(sync_dev, pdev); + if (rc < 0) + goto mcinit_fail; + + sync_dev->vdev->v4l2_dev = &sync_dev->v4l2_dev; + + rc = v4l2_device_register(&(pdev->dev), sync_dev->vdev->v4l2_dev); + if (rc < 0) + goto register_fail; + + strlcpy(sync_dev->vdev->name, CAM_SYNC_NAME, + sizeof(sync_dev->vdev->name)); + sync_dev->vdev->release = video_device_release; + sync_dev->vdev->fops = &cam_sync_v4l2_fops; + sync_dev->vdev->ioctl_ops = &g_cam_sync_ioctl_ops; + sync_dev->vdev->minor = -1; + sync_dev->vdev->vfl_type = VFL_TYPE_GRABBER; + rc = video_register_device(sync_dev->vdev, + VFL_TYPE_GRABBER, -1); + if (rc < 0) + goto v4l2_fail; + + cam_sync_init_entity(sync_dev); + video_set_drvdata(sync_dev->vdev, sync_dev); + memset(&sync_dev->sync_table, 0, sizeof(sync_dev->sync_table)); + memset(&sync_dev->bitmap, 0, sizeof(sync_dev->bitmap)); + bitmap_zero(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + + /* + * We treat zero as invalid handle, so we will keep the 0th bit set + * always + */ + set_bit(0, sync_dev->bitmap); + + sync_dev->work_queue = alloc_workqueue(CAM_SYNC_WORKQUEUE_NAME, + WQ_HIGHPRI | WQ_UNBOUND, 1); + + if (!sync_dev->work_queue) { + CAM_ERR(CAM_SYNC, + "Error: high priority work queue creation failed"); + rc = -ENOMEM; + goto v4l2_fail; + } + + trigger_cb_without_switch = false; + cam_sync_create_debugfs(); +#ifdef CONFIG_MSM_GLOBAL_SYNX + cam_sync_register_synx_bind_ops(); +#endif + return rc; + +v4l2_fail: + v4l2_device_unregister(sync_dev->vdev->v4l2_dev); +register_fail: + cam_sync_media_controller_cleanup(sync_dev); +mcinit_fail: + video_device_release(sync_dev->vdev); +vdev_fail: + mutex_destroy(&sync_dev->table_lock); + kfree(sync_dev); + return rc; +} + +static int cam_sync_remove(struct platform_device *pdev) +{ + v4l2_device_unregister(sync_dev->vdev->v4l2_dev); + cam_sync_media_controller_cleanup(sync_dev); + video_device_release(sync_dev->vdev); + debugfs_remove_recursive(sync_dev->dentry); + sync_dev->dentry = NULL; + kfree(sync_dev); + sync_dev = NULL; + + return 0; +} + +static struct platform_device cam_sync_device = { + .name = "cam_sync", + .id = -1, +}; + +static struct platform_driver cam_sync_driver = { + .probe = cam_sync_probe, + .remove = cam_sync_remove, + .driver = { + .name = "cam_sync", + .owner = THIS_MODULE, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_sync_init(void) +{ + int rc; + + rc = platform_device_register(&cam_sync_device); + if (rc) + return -ENODEV; + + return platform_driver_register(&cam_sync_driver); +} + +static void __exit cam_sync_exit(void) +{ + int idx; + + for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++) + spin_lock_init(&sync_dev->row_spinlocks[idx]); + platform_driver_unregister(&cam_sync_driver); + platform_device_unregister(&cam_sync_device); + kfree(sync_dev); +} + +module_init(cam_sync_init); +module_exit(cam_sync_exit); +MODULE_DESCRIPTION("Camera sync driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sync/cam_sync_api.h b/techpack/camera/drivers/cam_sync/cam_sync_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3d99bc15eb183241c8eb3f15b08d5e7d44c06cd4 --- /dev/null +++ b/techpack/camera/drivers/cam_sync/cam_sync_api.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_SYNC_API_H__ +#define __CAM_SYNC_API_H__ + +#include <linux/mutex.h> +#include <linux/list.h> +#include <linux/completion.h> +#include <linux/videodev2.h> +#include <media/cam_sync.h> + +#define SYNC_DEBUG_NAME_LEN 63 +typedef void (*sync_callback)(int32_t sync_obj, int status, void *data); + +/* Kernel APIs */ + +/** + * @brief: Creates a sync object + * + * The newly created sync obj is assigned to sync_obj. + * sync object. + * + * @param sync_obj : Pointer to int referencing the sync object. + * @param name : Optional parameter associating a name with the sync object for + * debug purposes. Only first SYNC_DEBUG_NAME_LEN bytes are accepted, + * rest will be ignored. + * + * @return Status of operation. Zero in case of success. + * -EINVAL will be returned if sync_obj is an invalid pointer. + * -ENOMEM will be returned if the kernel can't allocate space for + * sync object. + */ +int cam_sync_create(int32_t *sync_obj, const char *name); + +/** + * @brief: Registers a callback with a sync object + * + * @param cb_func: Pointer to callback to be registered + * @param userdata: Opaque pointer which will be passed back with callback. + * @param sync_obj: int referencing the sync object. + * + * @return Status of operation. Zero in case of success. + * -EINVAL will be returned if userdata is invalid. + * -ENOMEM will be returned if cb_func is invalid. + * + */ +int cam_sync_register_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj); + +/** + * @brief: De-registers a callback with a sync object + * + * @param cb_func: Pointer to callback to be de-registered + * @param userdata: Opaque pointer which will be passed back with callback. + * @param sync_obj: int referencing the sync object. + * + * @return Status of operation. Zero in case of success. + * -EINVAL will be returned if userdata is invalid. + * -ENOMEM will be returned if cb_func is invalid. + */ +int cam_sync_deregister_callback(sync_callback cb_func, + void *userdata, int32_t sync_obj); + +/** + * @brief: Signals a sync object with the status argument. + * + * This function will signal the sync object referenced by the sync_obj + * parameter and when doing so, will trigger callbacks in both user space and + * kernel. Callbacks will triggered asynchronously and their order of execution + * is not guaranteed. The status parameter will indicate whether the entity + * performing the signaling wants to convey an error case or a success case. + * + * @param sync_obj: int referencing the sync object. + * @param status: Status of the signaling. Can be either SYNC_SIGNAL_ERROR or + * SYNC_SIGNAL_SUCCESS. + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_signal(int32_t sync_obj, uint32_t status); + +/** + * @brief: Merges multiple sync objects + * + * This function will merge multiple sync objects into a sync group. + * + * @param sync_obj: pointer to a block of ints to be merged + * @param num_objs: Number of ints in the block + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj); + +/** + * @brief: get ref count of sync obj + * + * This function will increment ref count for the sync object, and the ref + * count will be decremented when this sync object is signaled. + * + * @param sync_obj: sync object + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_get_obj_ref(int32_t sync_obj); + +/** + * @brief: put ref count of sync obj + * + * This function will decrement ref count for the sync object. + * + * @param sync_obj: sync object + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_put_obj_ref(int32_t sync_obj); + +/** + * @brief: Destroys a sync object + * + * @param sync_obj: int referencing the sync object to be destroyed + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_destroy(int32_t sync_obj); + +/** + * @brief: Waits for a sync object synchronously + * + * Does a wait on the sync object identified by sync_obj for a maximum + * of timeout_ms milliseconds. Must not be called from interrupt context as + * this API can sleep. Should be called from process context only. + * + * @param sync_obj: int referencing the sync object to be waited upon + * @timeout_ms sync_obj: Timeout in ms. + * + * @return 0 upon success, -EINVAL if sync object is in bad state or arguments + * are invalid, -ETIMEDOUT if wait times out. + */ +int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms); + + +#endif /* __CAM_SYNC_API_H__ */ diff --git a/techpack/camera/drivers/cam_sync/cam_sync_private.h b/techpack/camera/drivers/cam_sync/cam_sync_private.h new file mode 100644 index 0000000000000000000000000000000000000000..a8612fdcd7c5be11eaadc874d25196bfeb2febe6 --- /dev/null +++ b/techpack/camera/drivers/cam_sync/cam_sync_private.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_SYNC_PRIVATE_H__ +#define __CAM_SYNC_PRIVATE_H__ + +#include <linux/bitmap.h> +#include <linux/videodev2.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#include <linux/debugfs.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> + +#ifdef CONFIG_CAM_SYNC_DBG +#define CDBG(fmt, args...) pr_err(fmt, ##args) +#else +#define CDBG(fmt, args...) pr_debug(fmt, ##args) +#endif + +#define CAM_SYNC_OBJ_NAME_LEN 64 +#define CAM_SYNC_MAX_OBJS 1024 +#define CAM_SYNC_MAX_V4L2_EVENTS 100 +#define CAM_SYNC_DEBUG_FILENAME "cam_debug" +#define CAM_SYNC_DEBUG_BASEDIR "cam" +#define CAM_SYNC_DEBUG_BUF_SIZE 32 +#define CAM_SYNC_PAYLOAD_WORDS 2 +#define CAM_SYNC_NAME "cam_sync" +#define CAM_SYNC_WORKQUEUE_NAME "HIPRIO_SYNC_WORK_QUEUE" + +#define CAM_SYNC_TYPE_INDV 0 +#define CAM_SYNC_TYPE_GROUP 1 + +/** + * enum sync_type - Enum to indicate the type of sync object, + * i.e. individual or group. + * + * @SYNC_TYPE_INDV : Object is an individual sync object + * @SYNC_TYPE_GROUP : Object is a group sync object + */ +enum sync_type { + SYNC_TYPE_INDV, + SYNC_TYPE_GROUP +}; + +/** + * enum sync_list_clean_type - Enum to indicate the type of list clean action + * to be peformed, i.e. specific sync ID or all list sync ids. + * + * @SYNC_CLEAN_ONE : Specific object to be cleaned in the list + * @SYNC_CLEAN_ALL : Clean all objects in the list + */ +enum sync_list_clean_type { + SYNC_LIST_CLEAN_ONE, + SYNC_LIST_CLEAN_ALL +}; + +/** + * struct sync_parent_info - Single node of information about a parent + * of a sync object, usually part of the parents linked list + * + * @sync_id : Sync object id of parent + * @list : List member used to append this node to a linked list + */ +struct sync_parent_info { + int32_t sync_id; + struct list_head list; +}; + +/** + * struct sync_parent_info - Single node of information about a child + * of a sync object, usually part of the children linked list + * + * @sync_id : Sync object id of child + * @list : List member used to append this node to a linked list + */ +struct sync_child_info { + int32_t sync_id; + struct list_head list; +}; + + +/** + * struct sync_callback_info - Single node of information about a kernel + * callback registered on a sync object + * + * @callback_func : Callback function, registered by client driver + * @cb_data : Callback data, registered by client driver + * @status........ : Status with which callback will be invoked in client + * @sync_obj : Sync id of the object for which callback is registered + * @cb_dispatch_work : Work representing the call dispatch + * @list : List member used to append this node to a linked list + */ +struct sync_callback_info { + sync_callback callback_func; + void *cb_data; + int status; + int32_t sync_obj; + struct work_struct cb_dispatch_work; + struct list_head list; +}; + +/** + * struct sync_user_payload - Single node of information about a user space + * payload registered from user space + * + * @payload_data : Payload data, opaque to kernel + * @list : List member used to append this node to a linked list + */ +struct sync_user_payload { + uint64_t payload_data[CAM_SYNC_PAYLOAD_WORDS]; + struct list_head list; +}; + +/** + * struct sync_table_row - Single row of information about a sync object, used + * for internal book keeping in the sync driver + * + * @name : Optional string representation of the sync object + * @type : Type of the sync object (individual or group) + * @sync_id : Integer id representing this sync object + * @parents_list : Linked list of parents of this sync object + * @children_list : Linked list of children of this sync object + * @state : State (INVALID, ACTIVE, SIGNALED_SUCCESS or + * SIGNALED_ERROR) + * @remaining : Count of remaining children that not been signaled + * @signaled : Completion variable on which block calls will wait + * @callback_list : Linked list of kernel callbacks registered + * @user_payload_list : LInked list of user space payloads registered + * @ref_cnt : ref count of the number of usage of the fence. + */ +struct sync_table_row { + char name[CAM_SYNC_OBJ_NAME_LEN]; + enum sync_type type; + int32_t sync_id; + /* List of parents, which are merged objects */ + struct list_head parents_list; + /* List of children, which constitute the merged object */ + struct list_head children_list; + uint32_t state; + uint32_t remaining; + struct completion signaled; + struct list_head callback_list; + struct list_head user_payload_list; + atomic_t ref_cnt; +}; + +/** + * struct cam_signalable_info - Information for a single sync object that is + * ready to be signaled + * + * @sync_obj : Sync object id of signalable object + * @status : Status with which to signal + * @list : List member used to append this node to a linked list + */ +struct cam_signalable_info { + int32_t sync_obj; + uint32_t status; + struct list_head list; +}; + +/** + * struct sync_device - Internal struct to book keep sync driver details + * + * @vdev : Video device + * @v4l2_dev : V4L2 device + * @sync_table : Table of all sync objects + * @row_spinlocks : Spinlock array, one for each row in the table + * @table_lock : Mutex used to lock the table + * @open_cnt : Count of file open calls made on the sync driver + * @dentry : Debugfs entry + * @work_queue : Work queue used for dispatching kernel callbacks + * @cam_sync_eventq : Event queue used to dispatch user payloads to user space + * @bitmap : Bitmap representation of all sync objects + */ +struct sync_device { + struct video_device *vdev; + struct v4l2_device v4l2_dev; + struct sync_table_row sync_table[CAM_SYNC_MAX_OBJS]; + spinlock_t row_spinlocks[CAM_SYNC_MAX_OBJS]; + struct mutex table_lock; + int open_cnt; + struct dentry *dentry; + struct workqueue_struct *work_queue; + struct v4l2_fh *cam_sync_eventq; + spinlock_t cam_sync_eventq_lock; + DECLARE_BITMAP(bitmap, CAM_SYNC_MAX_OBJS); +}; + + +#endif /* __CAM_SYNC_PRIVATE_H__ */ diff --git a/techpack/camera/drivers/cam_sync/cam_sync_util.c b/techpack/camera/drivers/cam_sync/cam_sync_util.c new file mode 100644 index 0000000000000000000000000000000000000000..f971f7e25dc571ebcf05d5cc9a7459a29a9cffc1 --- /dev/null +++ b/techpack/camera/drivers/cam_sync/cam_sync_util.c @@ -0,0 +1,458 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#include "cam_sync_util.h" + +int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, + long *idx) +{ + int rc = 0; + + mutex_lock(&sync_dev->table_lock); + + *idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS); + + if (*idx < CAM_SYNC_MAX_OBJS) + set_bit(*idx, sync_dev->bitmap); + else + rc = -1; + + mutex_unlock(&sync_dev->table_lock); + + return rc; +} + +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type) +{ + struct sync_table_row *row = table + idx; + + if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + memset(row, 0, sizeof(*row)); + + if (name) + strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN); + INIT_LIST_HEAD(&row->parents_list); + INIT_LIST_HEAD(&row->children_list); + row->type = type; + row->sync_id = idx; + row->state = CAM_SYNC_STATE_ACTIVE; + row->remaining = 0; + atomic_set(&row->ref_cnt, 0); + init_completion(&row->signaled); + INIT_LIST_HEAD(&row->callback_list); + INIT_LIST_HEAD(&row->user_payload_list); + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u ", + row->name, row->sync_id, idx, row->state); + + return 0; +} + +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, + uint32_t *sync_objs, + uint32_t num_objs) +{ + int i, rc = 0; + struct sync_child_info *child_info; + struct sync_parent_info *parent_info; + struct sync_table_row *row = table + idx; + struct sync_table_row *child_row = NULL; + + cam_sync_init_row(table, idx, "merged_fence", CAM_SYNC_TYPE_GROUP); + + /* + * While traversing for children, parent's row list is updated with + * child info and each child's row is updated with parent info. + * If any child state is ERROR or SUCCESS, it will not be added to list. + */ + for (i = 0; i < num_objs; i++) { + child_row = table + sync_objs[i]; + + if (idx == sync_objs[i]) { + CAM_ERR(CAM_SYNC, "invalid fence:%d should be released", + sync_objs[i]); + rc = -EINVAL; + goto clean_children_info; + } + + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + + /* validate child */ + if ((child_row->type == CAM_SYNC_TYPE_GROUP) || + (child_row->state == CAM_SYNC_STATE_INVALID)) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + CAM_ERR(CAM_SYNC, + "Invalid child fence:%i state:%u type:%u", + child_row->sync_id, child_row->state, + child_row->type); + rc = -EINVAL; + goto clean_children_info; + } + + /* check for child's state */ + if (child_row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + row->state = CAM_SYNC_STATE_SIGNALED_ERROR; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + if (child_row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + + row->remaining++; + + /* Add child info */ + child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC); + if (!child_info) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; + } + child_info->sync_id = sync_objs[i]; + list_add_tail(&child_info->list, &row->children_list); + + /* Add parent info */ + parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC); + if (!parent_info) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; + } + parent_info->sync_id = idx; + list_add_tail(&parent_info->list, &child_row->parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } + + if (!row->remaining) { + if (row->state != CAM_SYNC_STATE_SIGNALED_ERROR) + row->state = CAM_SYNC_STATE_SIGNALED_SUCCESS; + complete_all(&row->signaled); + } + + return 0; + +clean_children_info: + row->state = CAM_SYNC_STATE_INVALID; + for (i = i-1; i >= 0; i--) { + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + child_row = table + sync_objs[i]; + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } + + cam_sync_util_cleanup_children_list(row, SYNC_LIST_CLEAN_ALL, 0); + return rc; +} + +int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) +{ + struct sync_table_row *row = table + idx; + struct sync_child_info *child_info, *temp_child; + struct sync_callback_info *sync_cb, *temp_cb; + struct sync_parent_info *parent_info, *temp_parent; + struct sync_user_payload *upayload_info, *temp_upayload; + struct sync_table_row *child_row = NULL, *parent_row = NULL; + struct list_head temp_child_list, temp_parent_list; + + if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u", + row->name, row->sync_id, idx, row->state); + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj: idx = %d", + idx); + return -EINVAL; + } + + if (row->state == CAM_SYNC_STATE_ACTIVE) + CAM_DBG(CAM_SYNC, + "Destroying an active sync object name:%s id:%i", + row->name, row->sync_id); + + row->state = CAM_SYNC_STATE_INVALID; + + /* Object's child and parent objects will be added into this list */ + INIT_LIST_HEAD(&temp_child_list); + INIT_LIST_HEAD(&temp_parent_list); + + list_for_each_entry_safe(child_info, temp_child, &row->children_list, + list) { + if (child_info->sync_id <= 0) + continue; + + list_del_init(&child_info->list); + list_add_tail(&child_info->list, &temp_child_list); + } + + list_for_each_entry_safe(parent_info, temp_parent, &row->parents_list, + list) { + if (parent_info->sync_id <= 0) + continue; + + list_del_init(&parent_info->list); + list_add_tail(&parent_info->list, &temp_parent_list); + } + + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + /* Cleanup the child to parent link from child list */ + while (!list_empty(&temp_child_list)) { + child_info = list_first_entry(&temp_child_list, + struct sync_child_info, list); + child_row = sync_dev->sync_table + child_info->sync_id; + + spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); + + if (child_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&child_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[ + child_info->sync_id]); + kfree(child_info); + continue; + } + + if (child_row->state == CAM_SYNC_STATE_ACTIVE) + CAM_DBG(CAM_SYNC, + "Warning: destroying active child sync obj = %d", + child_info->sync_id); + + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + + list_del_init(&child_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); + kfree(child_info); + } + + /* Cleanup the parent to child link */ + while (!list_empty(&temp_parent_list)) { + parent_info = list_first_entry(&temp_parent_list, + struct sync_parent_info, list); + parent_row = sync_dev->sync_table + parent_info->sync_id; + + spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + + if (parent_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&parent_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[ + parent_info->sync_id]); + kfree(parent_info); + continue; + } + + if (parent_row->state == CAM_SYNC_STATE_ACTIVE) + CAM_DBG(CAM_SYNC, + "Warning: destroying active parent sync obj = %d", + parent_info->sync_id); + + cam_sync_util_cleanup_children_list(parent_row, + SYNC_LIST_CLEAN_ONE, idx); + + list_del_init(&parent_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); + } + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + list_for_each_entry_safe(upayload_info, temp_upayload, + &row->user_payload_list, list) { + list_del_init(&upayload_info->list); + kfree(upayload_info); + } + + list_for_each_entry_safe(sync_cb, temp_cb, + &row->callback_list, list) { + list_del_init(&sync_cb->list); + kfree(sync_cb); + } + + memset(row, 0, sizeof(*row)); + clear_bit(idx, sync_dev->bitmap); + INIT_LIST_HEAD(&row->callback_list); + INIT_LIST_HEAD(&row->parents_list); + INIT_LIST_HEAD(&row->children_list); + INIT_LIST_HEAD(&row->user_payload_list); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + + CAM_DBG(CAM_SYNC, "Destroying sync obj:%d successful", idx); + return 0; +} + +void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work) +{ + struct sync_callback_info *cb_info = container_of(cb_dispatch_work, + struct sync_callback_info, + cb_dispatch_work); + + cb_info->callback_func(cb_info->sync_obj, + cb_info->status, + cb_info->cb_data); + + kfree(cb_info); +} + +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status) +{ + struct sync_callback_info *sync_cb; + struct sync_user_payload *payload_info; + struct sync_callback_info *temp_sync_cb; + struct sync_table_row *signalable_row; + struct sync_user_payload *temp_payload_info; + + signalable_row = sync_dev->sync_table + sync_obj; + if (signalable_row->state == CAM_SYNC_STATE_INVALID) { + CAM_DBG(CAM_SYNC, + "Accessing invalid sync object:%i", sync_obj); + return; + } + + /* Dispatch kernel callbacks if any were registered earlier */ + list_for_each_entry_safe(sync_cb, + temp_sync_cb, &signalable_row->callback_list, list) { + sync_cb->status = status; + list_del_init(&sync_cb->list); + queue_work(sync_dev->work_queue, + &sync_cb->cb_dispatch_work); + } + + /* Dispatch user payloads if any were registered earlier */ + list_for_each_entry_safe(payload_info, temp_payload_info, + &signalable_row->user_payload_list, list) { + spin_lock_bh(&sync_dev->cam_sync_eventq_lock); + if (!sync_dev->cam_sync_eventq) { + spin_unlock_bh( + &sync_dev->cam_sync_eventq_lock); + break; + } + spin_unlock_bh(&sync_dev->cam_sync_eventq_lock); + cam_sync_util_send_v4l2_event( + CAM_SYNC_V4L_EVENT_ID_CB_TRIG, + sync_obj, + status, + payload_info->payload_data, + CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64)); + + list_del_init(&payload_info->list); + /* + * We can free the list node here because + * sending V4L event will make a deep copy + * anyway + */ + kfree(payload_info); + } + + /* + * This needs to be done because we want to unblock anyone + * who might be blocked and waiting on this sync object + */ + complete_all(&signalable_row->signaled); +} + +void cam_sync_util_send_v4l2_event(uint32_t id, + uint32_t sync_obj, + int status, + void *payload, + int len) +{ + struct v4l2_event event; + __u64 *payload_data = NULL; + struct cam_sync_ev_header *ev_header = NULL; + + event.id = id; + event.type = CAM_SYNC_V4L_EVENT; + + ev_header = CAM_SYNC_GET_HEADER_PTR(event); + ev_header->sync_obj = sync_obj; + ev_header->status = status; + + payload_data = CAM_SYNC_GET_PAYLOAD_PTR(event, __u64); + memcpy(payload_data, payload, len); + + v4l2_event_queue(sync_dev->vdev, &event); + CAM_DBG(CAM_SYNC, "send v4l2 event for sync_obj :%d", + sync_obj); +} + +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, + int new_state) +{ + int rc = 0; + + switch (parent_row->state) { + case CAM_SYNC_STATE_ACTIVE: + case CAM_SYNC_STATE_SIGNALED_SUCCESS: + parent_row->state = new_state; + break; + + case CAM_SYNC_STATE_SIGNALED_ERROR: + break; + + case CAM_SYNC_STATE_INVALID: + default: + rc = -EINVAL; + break; + } + + return rc; +} + +void cam_sync_util_cleanup_children_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj) +{ + struct sync_child_info *child_info = NULL; + struct sync_child_info *temp_child_info = NULL; + uint32_t curr_sync_obj; + + list_for_each_entry_safe(child_info, + temp_child_info, &row->children_list, list) { + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (child_info->sync_id != sync_obj)) + continue; + + curr_sync_obj = child_info->sync_id; + list_del_init(&child_info->list); + kfree(child_info); + + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (curr_sync_obj == sync_obj)) + break; + } +} + +void cam_sync_util_cleanup_parents_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj) +{ + struct sync_parent_info *parent_info = NULL; + struct sync_parent_info *temp_parent_info = NULL; + uint32_t curr_sync_obj; + + list_for_each_entry_safe(parent_info, + temp_parent_info, &row->parents_list, list) { + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (parent_info->sync_id != sync_obj)) + continue; + + curr_sync_obj = parent_info->sync_id; + list_del_init(&parent_info->list); + kfree(parent_info); + + if ((list_clean_type == SYNC_LIST_CLEAN_ONE) && + (curr_sync_obj == sync_obj)) + break; + } +} diff --git a/techpack/camera/drivers/cam_sync/cam_sync_util.h b/techpack/camera/drivers/cam_sync/cam_sync_util.h new file mode 100644 index 0000000000000000000000000000000000000000..e114c33c655a839e19748a6df97b257d12209e58 --- /dev/null +++ b/techpack/camera/drivers/cam_sync/cam_sync_util.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __CAM_SYNC_UTIL_H__ +#define __CAM_SYNC_UTIL_H__ + + +#include <cam_sync_api.h> +#include "cam_sync_private.h" +#include "cam_debug_util.h" + +extern struct sync_device *sync_dev; + +/** + * @brief: Finds an empty row in the sync table and sets its corresponding bit + * in the bit array + * + * @param sync_dev : Pointer to the sync device instance + * @param idx : Pointer to an long containing the index found in the bit + * array + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, + long *idx); + +/** + * @brief: Function to initialize an empty row in the sync table. This should be + * called only for individual sync objects. + * + * @param table : Pointer to the sync objects table + * @param idx : Index of row to initialize + * @param name : Optional string representation of the sync object. Should be + * 63 characters or less + * @param type : type of row to be initialized + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type); + +/** + * @brief: Function to uninitialize a row in the sync table + * + * @param table : Pointer to the sync objects table + * @param idx : Index of row to initialize + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx); + +/** + * @brief: Function to initialize a row in the sync table when the object is a + * group object, also known as a merged sync object + * + * @param table : Pointer to the sync objects table + * @param idx : Index of row to initialize + * @param sync_objs : Array of sync objects which will merged + * or grouped together + * @param num_objs : Number of sync objects in the array + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, + uint32_t *sync_objs, + uint32_t num_objs); + +int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx); + +/** + * @brief: Function to dispatch a kernel callback for a sync callback + * + * @param cb_dispatch_work : Pointer to the work_struct that needs to be + * dispatched + * + * @return None + */ +void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work); + +/** + * @brief: Function to dispatch callbacks for a signaled sync object + * + * @sync_obj : Sync object that is signaled + * @status : Status of the signaled object + * + * @return None + */ +void cam_sync_util_dispatch_signaled_cb(int32_t sync_obj, + uint32_t status); + +/** + * @brief: Function to send V4L event to user space + * @param id : V4L event id to send + * @param sync_obj : Sync obj for which event needs to be sent + * @param status : Status of the event + * @payload : Payload that needs to be sent to user space + * @len : Length of the payload + * + * @return None + */ +void cam_sync_util_send_v4l2_event(uint32_t id, + uint32_t sync_obj, + int status, + void *payload, + int len); + +/** + * @brief: Function which gets the next state of the sync object based on the + * current state and the new state + * + * @param current_state : Current state of the sync object + * @param new_state : New state of the sync object + * + * @return Next state of the sync object + */ +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, + int new_state); + +/** + * @brief: Function to clean up the children of a sync object + * @row : Row whose child list to clean + * @list_clean_type : Clean specific object or clean all objects + * @sync_obj : Sync object to be clean if list clean type is + * SYNC_LIST_CLEAN_ONE + * + * @return None + */ +void cam_sync_util_cleanup_children_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj); + +/** + * @brief: Function to clean up the parents of a sync object + * @row : Row whose parent list to clean + * @list_clean_type : Clean specific object or clean all objects + * @sync_obj : Sync object to be clean if list clean type is + * SYNC_LIST_CLEAN_ONE + * + * @return None + */ +void cam_sync_util_cleanup_parents_list(struct sync_table_row *row, + uint32_t list_clean_type, uint32_t sync_obj); + +#endif /* __CAM_SYNC_UTIL_H__ */ diff --git a/techpack/camera/drivers/cam_utils/Makefile b/techpack/camera/drivers/cam_utils/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..e17c2f50bb95178dc41400708856b42220679542 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(srctree)/techpack/camera/include/uapi +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_core/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_req_mgr/ +ccflags-y += -I$(srctree)/techpack/camera/drivers/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_soc_util.o cam_io_util.o cam_packet_util.o cam_debug_util.o cam_trace.o cam_common_util.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cx_ipeak.o diff --git a/techpack/camera/drivers/cam_utils/cam_common_util.c b/techpack/camera/drivers/cam_utils/cam_common_util.c new file mode 100644 index 0000000000000000000000000000000000000000..dbcb31d7bf0ec49b9f8fcaa17e5ab11d5915682e --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_common_util.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/string.h> +#include <linux/types.h> +#include <linux/slab.h> + +#include "cam_common_util.h" +#include "cam_debug_util.h" + +int cam_common_util_get_string_index(const char **strings, + uint32_t num_strings, const char *matching_string, uint32_t *index) +{ + int i; + + for (i = 0; i < num_strings; i++) { + if (strnstr(strings[i], matching_string, strlen(strings[i]))) { + CAM_DBG(CAM_UTIL, "matched %s : %d\n", + matching_string, i); + *index = i; + return 0; + } + } + + return -EINVAL; +} + +uint32_t cam_common_util_remove_duplicate_arr(int32_t *arr, uint32_t num) +{ + int i, j; + uint32_t wr_idx = 1; + + if (!arr) { + CAM_ERR(CAM_UTIL, "Null input array"); + return 0; + } + + for (i = 1; i < num; i++) { + for (j = 0; j < wr_idx ; j++) { + if (arr[i] == arr[j]) + break; + } + if (j == wr_idx) + arr[wr_idx++] = arr[i]; + } + + return wr_idx; +} diff --git a/techpack/camera/drivers/cam_utils/cam_common_util.h b/techpack/camera/drivers/cam_utils/cam_common_util.h new file mode 100644 index 0000000000000000000000000000000000000000..e202bae5b7610d6a27d81b953b86c8bb2f04f526 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_common_util.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_COMMON_UTIL_H_ +#define _CAM_COMMON_UTIL_H_ + +#include <linux/types.h> +#include <linux/kernel.h> + +#define CAM_BITS_MASK_SHIFT(x, mask, shift) (((x) & (mask)) >> shift) + +#define PTR_TO_U64(ptr) ((uint64_t)(uintptr_t)ptr) +#define U64_TO_PTR(ptr) ((void *)(uintptr_t)ptr) + +/** + * cam_common_util_get_string_index() + * + * @brief Match the string from list of strings to return + * matching index + * + * @strings: Pointer to list of strings + * @num_strings: Number of strings in 'strings' + * @matching_string: String to match + * @index: Pointer to index to return matching index + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_common_util_get_string_index(const char **strings, + uint32_t num_strings, const char *matching_string, uint32_t *index); + +/** + * cam_common_util_remove_duplicate_arr() + * + * @brief Move all the unique integers to the start of + * the array and return the number of unique integers + * + * @array: Pointer to the first integer of array + * @num: Number of elements in array + * + * @return: Number of unique integers in array + */ +uint32_t cam_common_util_remove_duplicate_arr(int32_t *array, + uint32_t num); + +#endif /* _CAM_COMMON_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_utils/cam_cx_ipeak.c b/techpack/camera/drivers/cam_utils/cam_cx_ipeak.c new file mode 100644 index 0000000000000000000000000000000000000000..b0f93ba045e0cd7e0c375ab161f74a276143326a --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_cx_ipeak.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <soc/qcom/cx_ipeak.h> + +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static struct cx_ipeak_client *cam_cx_ipeak; +static int cx_ipeak_level = CAM_NOMINAL_VOTE; +static int cx_default_ipeak_mask; +static int cx_current_ipeak_mask; +static int cam_cx_client_cnt; + +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + soc_info->cam_cx_ipeak_enable = true; + soc_info->cam_cx_ipeak_bit = 1 << cam_cx_client_cnt++; + cx_default_ipeak_mask |= soc_info->cam_cx_ipeak_bit; + + if (cam_cx_ipeak) + goto exit; + + cam_cx_ipeak = cx_ipeak_register(soc_info->dev->of_node, + "qcom,cam-cx-ipeak"); + + if (cam_cx_ipeak) { + goto exit; + } else { + rc = -EINVAL; + goto exit; + } + +exit: + CAM_DBG(CAM_UTIL, "cam_cx_ipeak is enabled for %s\n" + "mask = %x cx_default_ipeak_mask = %x", + soc_info->dev_name, soc_info->cam_cx_ipeak_bit, + cx_default_ipeak_mask); + return rc; +} + +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + int ret = 0; + + CAM_DBG(CAM_UTIL, "E: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + + if (apply_level < cx_ipeak_level && + (cx_current_ipeak_mask & soc_cx_ipeak_bit)) { + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, false); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s UNVOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s DISABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + goto exit; + } else if (apply_level < cx_ipeak_level) { + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x NO AI", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + goto exit; + } + + cx_current_ipeak_mask |= soc_cx_ipeak_bit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s ENABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, true); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s VOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + +exit: + return ret; +} + +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + + CAM_DBG(CAM_UTIL, "E:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + if (cam_cx_ipeak) + cx_ipeak_update(cam_cx_ipeak, false); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x UNVOTE", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + + return 0; +} diff --git a/techpack/camera/drivers/cam_utils/cam_cx_ipeak.h b/techpack/camera/drivers/cam_utils/cam_cx_ipeak.h new file mode 100644 index 0000000000000000000000000000000000000000..ab06952b86a8c649758bb95019643cb351c057e5 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_cx_ipeak.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_CX_IPEAK_H_ +#define _CAM_CX_IPEAK_H_ + +#include "cam_soc_util.h" + +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info); + +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level); +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info); + +#endif /* _CAM_CX_IPEAK_H_ */ diff --git a/techpack/camera/drivers/cam_utils/cam_debug_util.c b/techpack/camera/drivers/cam_utils/cam_debug_util.c new file mode 100755 index 0000000000000000000000000000000000000000..593e2a724850cfaaf09bb4f90c8f8e4957a60a62 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_debug_util.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundataion. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/module.h> + +#include "cam_debug_util.h" + +static uint debug_mdl; +module_param(debug_mdl, uint, 0644); + +const char *cam_get_module_name(unsigned int module_id) +{ + const char *name = NULL; + + switch (module_id) { + case CAM_CDM: + name = "CAM-CDM"; + break; + case CAM_CORE: + name = "CAM-CORE"; + break; + case CAM_CRM: + name = "CAM-CRM"; + break; + case CAM_CPAS: + name = "CAM-CPAS"; + break; + case CAM_ISP: + name = "CAM-ISP"; + break; + case CAM_SENSOR: + name = "CAM-SENSOR"; + break; + case CAM_SMMU: + name = "CAM-SMMU"; + break; + case CAM_SYNC: + name = "CAM-SYNC"; + break; + case CAM_ICP: + name = "CAM-ICP"; + break; + case CAM_JPEG: + name = "CAM-JPEG"; + break; + case CAM_FD: + name = "CAM-FD"; + break; + case CAM_LRME: + name = "CAM-LRME"; + break; + case CAM_FLASH: + name = "CAM-FLASH"; + break; + case CAM_ACTUATOR: + name = "CAM-ACTUATOR"; + break; + case CAM_CCI: + name = "CAM-CCI"; + break; + case CAM_CSIPHY: + name = "CAM-CSIPHY"; + break; + case CAM_EEPROM: + name = "CAM-EEPROM"; + break; + case CAM_UTIL: + name = "CAM-UTIL"; + break; + case CAM_CTXT: + name = "CAM-CTXT"; + break; + case CAM_HFI: + name = "CAM-HFI"; + break; + case CAM_OIS: + name = "CAM-OIS"; + break; + case CAM_IRQ_CTRL: + name = "CAM-IRQ-CTRL"; + break; + case CAM_MEM: + name = "CAM-MEM"; + break; + case CAM_PERF: + name = "CAM-PERF"; + break; + case CAM_REQ: + name = "CAM-REQ"; + break; + case CAM_CUSTOM: + name = "CAM-CUSTOM"; + break; + default: + name = "CAM"; + break; + } + + return name; +} + +void cam_debug_log(unsigned int module_id, const char *func, const int line, + const char *fmt, ...) +{ + char str_buffer[STR_BUFFER_MAX_LENGTH]; + va_list args; + + va_start(args, fmt); + + if (debug_mdl & module_id) { + vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args); + pr_info("[%d %d] CAM_DBG: %s: %s: %d: %s\n", + task_tgid_nr(current), task_pid_nr(current), + cam_get_module_name(module_id), + func, line, str_buffer); + } + + va_end(args); +} + +bool cam_is_log_enabled(unsigned int module_id) +{ + return (debug_mdl & module_id); +} + diff --git a/techpack/camera/drivers/cam_utils/cam_debug_util.h b/techpack/camera/drivers/cam_utils/cam_debug_util.h new file mode 100755 index 0000000000000000000000000000000000000000..3b567c16227f6fa81ed28c9831a27fb2bfd2d52e --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_debug_util.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/io.h> +#include <linux/module.h> + +#ifndef _CAM_DEBUG_UTIL_H_ +#define _CAM_DEBUG_UTIL_H_ + +#define CAM_CDM (1 << 0) +#define CAM_CORE (1 << 1) +#define CAM_CPAS (1 << 2) +#define CAM_ISP (1 << 3) +#define CAM_CRM (1 << 4) +#define CAM_SENSOR (1 << 5) +#define CAM_SMMU (1 << 6) +#define CAM_SYNC (1 << 7) +#define CAM_ICP (1 << 8) +#define CAM_JPEG (1 << 9) +#define CAM_FD (1 << 10) +#define CAM_LRME (1 << 11) +#define CAM_FLASH (1 << 12) +#define CAM_ACTUATOR (1 << 13) +#define CAM_CCI (1 << 14) +#define CAM_CSIPHY (1 << 15) +#define CAM_EEPROM (1 << 16) +#define CAM_UTIL (1 << 17) +#define CAM_HFI (1 << 18) +#define CAM_CTXT (1 << 19) +#define CAM_OIS (1 << 20) +#define CAM_RES (1 << 21) +#define CAM_MEM (1 << 22) + +/* CAM_IRQ_CTRL: For events in irq controller */ +#define CAM_IRQ_CTRL (1 << 23) + +/* CAM_REQ: Tracks a request submitted to KMD */ +#define CAM_REQ (1 << 24) + +/* CAM_PERF: Used for performance (clock, BW etc) logs */ +#define CAM_PERF (1 << 25) +#define CAM_CUSTOM (1 << 26) + +#define STR_BUFFER_MAX_LENGTH 1024 + +/* + * cam_debug_log() + * + * @brief : Get the Module name from module ID and print + * respective debug logs + * + * @module_id : Respective Module ID which is calling this function + * @func : Function which is calling to print logs + * @line : Line number associated with the function which is calling + * to print log + * @fmt : Formatted string which needs to be print in the log + * + */ +void cam_debug_log(unsigned int module_id, const char *func, const int line, + const char *fmt, ...); + +/* + * cam_get_module_name() + * + * @brief : Get the module name from module ID + * + * @module_id : Module ID which is using this function + */ +const char *cam_get_module_name(unsigned int module_id); + +bool cam_is_log_enabled(unsigned int module_id); + +/* + * CAM_ERR + * @brief : This Macro will print error logs + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_ERR(__module, fmt, args...) \ + pr_err("[%d %d] CAM_ERR: %s: %s: %d " fmt "\n", \ + task_tgid_nr(current), task_pid_nr(current), \ + cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_WARN + * @brief : This Macro will print warning logs + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_WARN(__module, fmt, args...) \ + pr_warn("[%d %d] CAM_WARN: %s: %s: %d " fmt "\n", \ + task_tgid_nr(current), task_pid_nr(current), \ + cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_INFO + * @brief : This Macro will print Information logs + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO(__module, fmt, args...) \ + pr_info("[%d %d] CAM_INFO: %s: %s: %d " fmt "\n", \ + task_tgid_nr(current), task_pid_nr(current), \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +/* + * CAM_INFO_RATE_LIMIT + * @brief : This Macro will print info logs with ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO_RATE_LIMIT(__module, fmt, args...) \ + pr_info_ratelimited("CAM_INFO: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +/* + * CAM_DBG + * @brief : This Macro will print debug logs when enabled using GROUP + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_DBG(__module, fmt, args...) \ + cam_debug_log(__module, __func__, __LINE__, fmt, ##args) + +/* + * CAM_ERR_RATE_LIMIT + * @brief : This Macro will print error print logs with ratelimit + */ +#define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \ + pr_info_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) +/* + * CAM_WARN_RATE_LIMIT + * @brief : This Macro will print warning logs with ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_WARN_RATE_LIMIT(__module, fmt, args...) \ + pr_info_ratelimited("CAM_WARN: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +/* + * CAM_WARN_RATE_LIMIT_CUSTOM + * @brief : This Macro will print warn logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_WARN_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_info( \ + "CAM_WARN: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, \ + __LINE__, ##args); \ + }) + +/* + * CAM_INFO_RATE_LIMIT_CUSTOM + * @brief : This Macro will print info logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_INFO_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_info( \ + "CAM_INFO: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, \ + __LINE__, ##args); \ + }) + +/* + * CAM_ERR_RATE_LIMIT_CUSTOM + * @brief : This Macro will print error logs with custom ratelimit + * + * @__module : Respective module id which is been calling this Macro + * @interval : Time interval in seconds + * @burst : No of logs to print in interval time + * @fmt : Formatted string which needs to be print in log + * @args : Arguments which needs to be print in log + */ +#define CAM_ERR_RATE_LIMIT_CUSTOM(__module, interval, burst, fmt, args...) \ + ({ \ + static DEFINE_RATELIMIT_STATE(_rs, \ + (interval * HZ), \ + burst); \ + if (__ratelimit(&_rs)) \ + pr_info( \ + "CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, \ + __LINE__, ##args); \ + }) + +#endif /* _CAM_DEBUG_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_utils/cam_io_util.c b/techpack/camera/drivers/cam_utils/cam_io_util.c new file mode 100644 index 0000000000000000000000000000000000000000..d35320e7e4874bb6b48826ad8927e6ea54069dd5 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_io_util.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2011-2014, 2017-2018, The Linux Foundation. + * All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/err.h> +#include "cam_io_util.h" +#include "cam_debug_util.h" + +int cam_io_w(uint32_t data, void __iomem *addr) +{ + if (!addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + writel_relaxed_no_log(data, addr); + + return 0; +} + +int cam_io_w_mb(uint32_t data, void __iomem *addr) +{ + if (!addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + /* Ensure previous writes are done */ + wmb(); + writel_relaxed_no_log(data, addr); + /* Ensure previous writes are done */ + wmb(); + + return 0; +} + +uint32_t cam_io_r(void __iomem *addr) +{ + uint32_t data; + + if (!addr) { + CAM_ERR(CAM_UTIL, "Invalid args"); + return 0; + } + + data = readl_relaxed(addr); + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + + return data; +} + +uint32_t cam_io_r_mb(void __iomem *addr) +{ + uint32_t data; + + if (!addr) { + CAM_ERR(CAM_UTIL, "Invalid args"); + return 0; + } + + /* Ensure previous read is done */ + rmb(); + data = readl_relaxed(addr); + CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); + /* Ensure previous read is done */ + rmb(); + + return data; +} + +int cam_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len) +{ + int i; + uint32_t *d = (uint32_t *) dest_addr; + uint32_t *s = (uint32_t *) src_addr; + + if (!dest_addr || !src_addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "%pK %pK %d", dest_addr, src_addr, len); + + for (i = 0; i < len/4; i++) { + CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s); + writel_relaxed(*s++, d++); + } + + return 0; +} + +int cam_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len) +{ + int i; + uint32_t *d = (uint32_t *) dest_addr; + uint32_t *s = (uint32_t *) src_addr; + + if (!dest_addr || !src_addr) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "%pK %pK %d", dest_addr, src_addr, len); + + /* + * Do not use cam_io_w_mb to avoid double wmb() after a write + * and before the next write. + */ + wmb(); + for (i = 0; i < (len / 4); i++) { + CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s); + writel_relaxed(*s++, d++); + } + /* Ensure previous writes are done */ + wmb(); + + return 0; +} + +int cam_io_poll_value(void __iomem *addr, uint32_t wait_data, uint32_t retry, + unsigned long min_usecs, unsigned long max_usecs) +{ + uint32_t tmp, cnt = 0; + int rc = 0; + + if (!addr) + return -EINVAL; + + tmp = readl_relaxed(addr); + while ((tmp != wait_data) && (cnt++ < retry)) { + if (min_usecs > 0 && max_usecs > 0) + usleep_range(min_usecs, max_usecs); + tmp = readl_relaxed(addr); + } + + if (cnt > retry) { + CAM_DBG(CAM_UTIL, "Poll failed by value"); + rc = -EINVAL; + } + + return rc; +} + +int cam_io_poll_value_wmask(void __iomem *addr, uint32_t wait_data, + uint32_t bmask, uint32_t retry, unsigned long min_usecs, + unsigned long max_usecs) +{ + uint32_t tmp, cnt = 0; + int rc = 0; + + if (!addr) + return -EINVAL; + + tmp = readl_relaxed(addr); + while (((tmp & bmask) != wait_data) && (cnt++ < retry)) { + if (min_usecs > 0 && max_usecs > 0) + usleep_range(min_usecs, max_usecs); + tmp = readl_relaxed(addr); + } + + if (cnt > retry) { + CAM_DBG(CAM_UTIL, "Poll failed with mask"); + rc = -EINVAL; + } + + return rc; +} + +int cam_io_w_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len) +{ + int i; + + if (!data || !len || !addr) + return -EINVAL; + + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr =%pK", + i, len, data[i], addr); + writel_relaxed(data[i], addr); + } + + return 0; +} + +int cam_io_w_mb_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len) +{ + int i; + + if (!data || !len || !addr) + return -EINVAL; + + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr =%pK", + i, len, data[i], addr); + /* Ensure previous writes are done */ + wmb(); + writel_relaxed(data[i], addr); + } + + return 0; +} + +#define __OFFSET(__i) (data[__i][0]) +#define __VAL(__i) (data[__i][1]) +int cam_io_w_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len) +{ + int i; + + if (!data || !len || !addr_base) + return -EINVAL; + + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr_base =%pK reg=%x", + i, len, __VAL(i), addr_base, __OFFSET(i)); + writel_relaxed(__VAL(i), addr_base + __OFFSET(i)); + } + + return 0; +} + +int cam_io_w_mb_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len) +{ + int i; + + if (!data || !len || !addr_base) + return -EINVAL; + + /* Ensure write is done */ + wmb(); + for (i = 0; i < len; i++) { + CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr_base =%pK reg=%x", + i, len, __VAL(i), addr_base, __OFFSET(i)); + writel_relaxed(__VAL(i), addr_base + __OFFSET(i)); + } + + return 0; +} + +#define BYTES_PER_REGISTER 4 +#define NUM_REGISTER_PER_LINE 4 +#define REG_OFFSET(__start, __i) (__start + (__i * BYTES_PER_REGISTER)) +int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size) +{ + char line_str[128]; + char *p_str; + int i; + uint32_t data; + + CAM_DBG(CAM_UTIL, "addr=%pK offset=0x%x size=%d", + base_addr, start_offset, size); + + if (!base_addr || (size <= 0)) + return -EINVAL; + + line_str[0] = '\0'; + p_str = line_str; + for (i = 0; i < size; i++) { + if (i % NUM_REGISTER_PER_LINE == 0) { + snprintf(p_str, 12, "0x%08x: ", + REG_OFFSET(start_offset, i)); + p_str += 11; + } + data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); + snprintf(p_str, 9, "%08x ", data); + p_str += 8; + if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { + CAM_ERR(CAM_UTIL, "%s", line_str); + line_str[0] = '\0'; + p_str = line_str; + } + } + if (line_str[0] != '\0') + CAM_ERR(CAM_UTIL, "%s", line_str); + + return 0; +} diff --git a/techpack/camera/drivers/cam_utils/cam_io_util.h b/techpack/camera/drivers/cam_utils/cam_io_util.h new file mode 100644 index 0000000000000000000000000000000000000000..66aaeaa45d55eb571d6581442902e47f033d9155 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_io_util.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2011-2014, 2017-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_IO_UTIL_H_ +#define _CAM_IO_UTIL_H_ + +#include <linux/types.h> + +/** + * cam_io_w() + * + * @brief: Camera IO util for register write + * + * @data: Value to be written + * @addr: Address used to write the value + * + * @return: Success or Failure + */ +int cam_io_w(uint32_t data, void __iomem *addr); + +/** + * cam_io_w_mb() + * + * @brief: Camera IO util for register write with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @data: Value to be written + * @addr: Address used to write the value + * + * @return: Success or Failure + */ +int cam_io_w_mb(uint32_t data, void __iomem *addr); + +/** + * cam_io_r() + * + * @brief: Camera IO util for register read + * + * @addr: Address of register to be read + * + * @return: Value read from the register address + */ +uint32_t cam_io_r(void __iomem *addr); + +/** + * cam_io_r_mb() + * + * @brief: Camera IO util for register read with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call rmb() independently in the caller. + * + * @addr: Address of register to be read + * + * @return: Value read from the register address + */ +uint32_t cam_io_r_mb(void __iomem *addr); + +/** + * cam_io_memcpy() + * + * @brief: Camera IO util for memory to register copy + * + * @dest_addr: Destination register address + * @src_addr: Source regiser address + * @len: Range to be copied + * + * @return: Success or Failure + */ +int cam_io_memcpy(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len); + +/** + * cam_io_memcpy_mb() + * + * @brief: Camera IO util for memory to register copy + * with barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @dest_addr: Destination register address + * @src_addr: Source regiser address + * @len: Range to be copied + * + * @return: Success or Failure + */ +int cam_io_memcpy_mb(void __iomem *dest_addr, + void __iomem *src_addr, uint32_t len); + +/** + * cam_io_poll_value_wmask() + * + * @brief: Poll register value with bitmask. + * + * @addr: Register address to be polled + * @wait_data: Wait until @bmask read from @addr matches this data + * @bmask: Bit mask + * @retry: Number of retry + * @min_usecs: Minimum time to wait for retry + * @max_usecs: Maximum time to wait for retry + * + * @return: Success or Failure + * + * This function can sleep so it should not be called from interrupt + * handler, spin_lock etc. + */ +int cam_io_poll_value_wmask(void __iomem *addr, uint32_t wait_data, + uint32_t bmask, uint32_t retry, unsigned long min_usecs, + unsigned long max_usecs); + +/** + * cam_io_poll_value() + * + * @brief: Poll register value + * + * @addr: Register address to be polled + * @wait_data: Wait until value read from @addr matches this data + * @retry: Number of retry + * @min_usecs: Minimum time to wait for retry + * @max_usecs: Maximum time to wait for retry + * + * @return: Success or Failure + * + * This function can sleep so it should not be called from interrupt + * handler, spin_lock etc. + */ +int cam_io_poll_value(void __iomem *addr, uint32_t wait_data, uint32_t retry, + unsigned long min_usecs, unsigned long max_usecs); + +/** + * cam_io_w_same_offset_block() + * + * @brief: Write a block of data to same address + * + * @data: Block data to be written + * @addr: Register offset to be written. + * @len: Number of the data to be written + * + * @return: Success or Failure + */ +int cam_io_w_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len); + +/** + * cam_io_w_mb_same_offset_block() + * + * @brief: Write a block of data to same address with barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @data: Block data to be written + * @addr: Register offset to be written. + * @len: Number of the data to be written + * + * @return: Success or Failure + */ +int cam_io_w_mb_same_offset_block(const uint32_t *data, void __iomem *addr, + uint32_t len); + +/** + * cam_io_w_offset_val_block() + * + * @brief: This API is to write a block of registers + * represented by a 2 dimensional array table with + * register offset and value pair + * + * offset0, value0, + * offset1, value1, + * offset2, value2, + * and so on... + * + * @data: Pointer to 2-dimensional offset-value array + * @addr_base: Base address to which offset will be added to + * get the register address + * @len: Length of offset-value pair array to be written in + * number of uin32_t + * + * @return: Success or Failure + * + */ +int32_t cam_io_w_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len); + +/** + * cam_io_w_mb_offset_val_block() + * + * @brief: This API is to write a block of registers + * represented by a 2 dimensional array table with + * register offset and value pair with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * The OFFSETS NEED to be different because of the way + * barrier is used here. + * + * offset0, value0, + * offset1, value1, + * offset2, value2, + * and so on... + * + * @data: Pointer to 2-dimensional offset-value array + * @addr_base: Base address to which offset will be added to + * get the register address + * @len: Length of offset-value pair array to be written in + * number of uin32_t + * + * @return: Success or Failure + * + */ +int32_t cam_io_w_mb_offset_val_block(const uint32_t data[][2], + void __iomem *addr_base, uint32_t len); + +/** + * cam_io_dump() + * + * @brief: Camera IO util for dumping a range of register + * + * @base_addr: Start register address for the dumping + * @start_offset: Start register offset for the dump + * @size: Size specifying the range for dumping + * + * @return: Success or Failure + */ +int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size); + +#endif /* _CAM_IO_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_utils/cam_packet_util.c b/techpack/camera/drivers/cam_utils/cam_packet_util.c new file mode 100644 index 0000000000000000000000000000000000000000..75a47ca136a47bc4fff0b7cde9773ea6ce2767a6 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_packet_util.c @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/types.h> +#include <linux/slab.h> + +#include "cam_mem_mgr.h" +#include "cam_packet_util.h" +#include "cam_debug_util.h" + +int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, + size_t *len) +{ + int rc = 0; + uintptr_t kmd_buf_addr = 0; + + rc = cam_mem_get_cpu_buf(handle, &kmd_buf_addr, len); + if (rc) { + CAM_ERR(CAM_UTIL, "Unable to get the virtual address %d", rc); + } else { + if (kmd_buf_addr && *len) { + *buf_addr = (uint32_t *)kmd_buf_addr; + } else { + CAM_ERR(CAM_UTIL, "Invalid addr and length :%zd", *len); + rc = -ENOMEM; + } + } + return rc; +} + +int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) +{ + if ((cmd_desc->length > cmd_desc->size) || + (cmd_desc->mem_handle <= 0)) { + CAM_ERR(CAM_UTIL, "invalid cmd arg %d %d %d %d", + cmd_desc->offset, cmd_desc->length, + cmd_desc->mem_handle, cmd_desc->size); + return -EINVAL; + } + + return 0; +} + +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len) +{ + size_t sum_cmd_desc = 0; + size_t sum_io_cfgs = 0; + size_t sum_patch_desc = 0; + size_t pkt_wo_payload = 0; + + if (!packet) + return -EINVAL; + + if ((size_t)packet->header.size > remain_len) { + CAM_ERR(CAM_UTIL, + "Invalid packet size: %zu, CPU buf length: %zu", + (size_t)packet->header.size, remain_len); + return -EINVAL; + } + + + CAM_DBG(CAM_UTIL, "num cmd buf:%d num of io config:%d kmd buf index:%d", + packet->num_cmd_buf, packet->num_io_configs, + packet->kmd_cmd_buf_index); + + sum_cmd_desc = packet->num_cmd_buf * sizeof(struct cam_cmd_buf_desc); + sum_io_cfgs = packet->num_io_configs * sizeof(struct cam_buf_io_cfg); + sum_patch_desc = packet->num_patches * sizeof(struct cam_patch_desc); + pkt_wo_payload = offsetof(struct cam_packet, payload); + + if ((!packet->header.size) || + ((pkt_wo_payload + (size_t)packet->cmd_buf_offset + + sum_cmd_desc) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->io_configs_offset + + sum_io_cfgs) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->patch_offset + + sum_patch_desc) > (size_t)packet->header.size)) { + CAM_ERR(CAM_UTIL, "params not within mem len:%zu %zu %zu %zu", + (size_t)packet->header.size, sum_cmd_desc, + sum_io_cfgs, sum_patch_desc); + return -EINVAL; + } + + return 0; +} + +int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, + struct cam_kmd_buf_info *kmd_buf) +{ + int rc = 0; + size_t len = 0; + size_t remain_len = 0; + struct cam_cmd_buf_desc *cmd_desc; + uint32_t *cpu_addr; + + if (!packet || !kmd_buf) { + CAM_ERR(CAM_UTIL, "Invalid arg %pK %pK", packet, kmd_buf); + return -EINVAL; + } + + if ((packet->kmd_cmd_buf_index < 0) || + (packet->kmd_cmd_buf_index >= packet->num_cmd_buf)) { + CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d", + packet->kmd_cmd_buf_index); + return -EINVAL; + } + + /* Take first command descriptor and add offset to it for kmd*/ + cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *) + &packet->payload + packet->cmd_buf_offset); + cmd_desc += packet->kmd_cmd_buf_index; + + rc = cam_packet_util_validate_cmd_desc(cmd_desc); + if (rc) + return rc; + + rc = cam_packet_util_get_cmd_mem_addr(cmd_desc->mem_handle, &cpu_addr, + &len); + if (rc) + return rc; + + remain_len = len; + if (((size_t)cmd_desc->offset >= len) || + ((size_t)cmd_desc->size > (len - (size_t)cmd_desc->offset))) { + CAM_ERR(CAM_UTIL, "invalid memory len:%zd and cmd desc size:%d", + len, cmd_desc->size); + return -EINVAL; + } + + remain_len -= (size_t)cmd_desc->offset; + if ((size_t)packet->kmd_cmd_buf_offset >= remain_len) { + CAM_ERR(CAM_UTIL, "Invalid kmd cmd buf offset: %zu", + (size_t)packet->kmd_cmd_buf_offset); + return -EINVAL; + } + + cpu_addr += (cmd_desc->offset / 4) + (packet->kmd_cmd_buf_offset / 4); + CAM_DBG(CAM_UTIL, "total size %d, cmd size: %d, KMD buffer size: %d", + cmd_desc->size, cmd_desc->length, + cmd_desc->size - cmd_desc->length); + CAM_DBG(CAM_UTIL, "hdl 0x%x, cmd offset %d, kmd offset %d, addr 0x%pK", + cmd_desc->mem_handle, cmd_desc->offset, + packet->kmd_cmd_buf_offset, cpu_addr); + + kmd_buf->cpu_addr = cpu_addr; + kmd_buf->handle = cmd_desc->mem_handle; + kmd_buf->offset = cmd_desc->offset + packet->kmd_cmd_buf_offset; + kmd_buf->size = cmd_desc->size - cmd_desc->length; + kmd_buf->used_bytes = 0; + + return rc; +} + +void cam_packet_dump_patch_info(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl) +{ + struct cam_patch_desc *patch_desc = NULL; + dma_addr_t iova_addr; + size_t dst_buf_len; + size_t src_buf_size; + int i, rc = 0; + int32_t hdl; + uintptr_t cpu_addr = 0; + uint32_t *dst_cpu_addr; + uint64_t value = 0; + + patch_desc = (struct cam_patch_desc *) + ((uint32_t *) &packet->payload + + packet->patch_offset/4); + + for (i = 0; i < packet->num_patches; i++) { + hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? + sec_mmu_hdl : iommu_hdl; + rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, + hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, + "unable to get src buf address for hdl 0x%x", + hdl); + return; + } + + rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, + &cpu_addr, &dst_buf_len); + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { + CAM_ERR(CAM_UTIL, "unable to get dst buf address"); + return; + } + + dst_cpu_addr = (uint32_t *)cpu_addr; + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + + patch_desc[i].dst_offset); + value = *((uint64_t *)dst_cpu_addr); + CAM_ERR(CAM_UTIL, + "i = %d src_buf 0x%llx src_hdl 0x%x src_buf_with_offset 0x%llx size 0x%llx dst %p dst_offset %u dst_hdl 0x%x value 0x%llx", + i, iova_addr, patch_desc[i].src_buf_hdl, + (iova_addr + patch_desc[i].src_offset), + src_buf_size, dst_cpu_addr, + patch_desc[i].dst_offset, + patch_desc[i].dst_buf_hdl, value); + + if (!(*dst_cpu_addr)) + CAM_ERR(CAM_ICP, "Null at dst addr %p", dst_cpu_addr); + } +} + +int cam_packet_util_process_patches(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl) +{ + struct cam_patch_desc *patch_desc = NULL; + dma_addr_t iova_addr; + uintptr_t cpu_addr = 0; + uint32_t temp; + uint32_t *dst_cpu_addr; + uint32_t *src_buf_iova_addr; + size_t dst_buf_len; + size_t src_buf_size; + int i; + int rc = 0; + int32_t hdl; + + /* process patch descriptor */ + patch_desc = (struct cam_patch_desc *) + ((uint32_t *) &packet->payload + + packet->patch_offset/4); + CAM_DBG(CAM_UTIL, "packet = %pK patch_desc = %pK size = %lu", + (void *)packet, (void *)patch_desc, + sizeof(struct cam_patch_desc)); + + for (i = 0; i < packet->num_patches; i++) { + hdl = cam_mem_is_secure_buf(patch_desc[i].src_buf_hdl) ? + sec_mmu_hdl : iommu_hdl; + rc = cam_mem_get_io_buf(patch_desc[i].src_buf_hdl, + hdl, &iova_addr, &src_buf_size); + if (rc < 0) { + CAM_ERR(CAM_UTIL, "unable to get src buf address"); + return rc; + } + src_buf_iova_addr = (uint32_t *)iova_addr; + temp = iova_addr; + + rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, + &cpu_addr, &dst_buf_len); + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { + CAM_ERR(CAM_UTIL, "unable to get dst buf address"); + return rc; + } + dst_cpu_addr = (uint32_t *)cpu_addr; + + CAM_DBG(CAM_UTIL, "i = %d patch info = %x %x %x %x", i, + patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, + patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); + + if ((size_t)patch_desc[i].src_offset >= src_buf_size) { + CAM_ERR(CAM_UTIL, + "Invalid src buf patch offset"); + return -EINVAL; + } + + if ((dst_buf_len < sizeof(void *)) || + ((dst_buf_len - sizeof(void *)) < + (size_t)patch_desc[i].dst_offset)) { + CAM_ERR(CAM_UTIL, + "Invalid dst buf patch offset"); + return -EINVAL; + } + + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + + patch_desc[i].dst_offset); + temp += patch_desc[i].src_offset; + + *dst_cpu_addr = temp; + + CAM_DBG(CAM_UTIL, + "patch is done for dst %pK with src %pK value %llx", + dst_cpu_addr, src_buf_iova_addr, + *((uint64_t *)dst_cpu_addr)); + } + + return rc; +} + +int cam_packet_util_process_generic_cmd_buffer( + struct cam_cmd_buf_desc *cmd_buf, + cam_packet_generic_blob_handler blob_handler_cb, void *user_data) +{ + int rc = 0; + uintptr_t cpu_addr = 0; + size_t buf_size; + size_t remain_len = 0; + uint32_t *blob_ptr; + uint32_t blob_type, blob_size, blob_block_size, len_read; + + if (!cmd_buf || !blob_handler_cb) { + CAM_ERR(CAM_UTIL, "Invalid args %pK %pK", + cmd_buf, blob_handler_cb); + return -EINVAL; + } + + if (!cmd_buf->length || !cmd_buf->size) { + CAM_ERR(CAM_UTIL, "Invalid cmd buf size %d %d", + cmd_buf->length, cmd_buf->size); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(cmd_buf->mem_handle, &cpu_addr, &buf_size); + if (rc || !cpu_addr || (buf_size == 0)) { + CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK", + rc, (void *)cpu_addr); + return rc; + } + + remain_len = buf_size; + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_buf->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_buf->offset); + return -EINVAL; + } + remain_len -= (size_t)cmd_buf->offset; + + if (remain_len < (size_t)cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_buf->length); + return -EINVAL; + } + + blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) + + cmd_buf->offset); + + CAM_DBG(CAM_UTIL, + "GenericCmdBuffer cpuaddr=%pK, blobptr=%pK, len=%d", + (void *)cpu_addr, (void *)blob_ptr, cmd_buf->length); + + len_read = 0; + while (len_read < cmd_buf->length) { + blob_type = + ((*blob_ptr) & CAM_GENERIC_BLOB_CMDBUFFER_TYPE_MASK) >> + CAM_GENERIC_BLOB_CMDBUFFER_TYPE_SHIFT; + blob_size = + ((*blob_ptr) & CAM_GENERIC_BLOB_CMDBUFFER_SIZE_MASK) >> + CAM_GENERIC_BLOB_CMDBUFFER_SIZE_SHIFT; + + blob_block_size = sizeof(uint32_t) + + (((blob_size + sizeof(uint32_t) - 1) / + sizeof(uint32_t)) * sizeof(uint32_t)); + + CAM_DBG(CAM_UTIL, + "Blob type=%d size=%d block_size=%d len_read=%d total=%d", + blob_type, blob_size, blob_block_size, len_read, + cmd_buf->length); + + if (len_read + blob_block_size > cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid Blob %d %d %d %d", + blob_type, blob_size, len_read, + cmd_buf->length); + rc = -EINVAL; + goto end; + } + + len_read += blob_block_size; + + rc = blob_handler_cb(user_data, blob_type, blob_size, + (uint8_t *)(blob_ptr + 1)); + if (rc) { + CAM_ERR(CAM_UTIL, "Error in handling blob type %d %d", + blob_type, blob_size); + goto end; + } + + blob_ptr += (blob_block_size / sizeof(uint32_t)); + } + +end: + return rc; +} diff --git a/techpack/camera/drivers/cam_utils/cam_packet_util.h b/techpack/camera/drivers/cam_utils/cam_packet_util.h new file mode 100644 index 0000000000000000000000000000000000000000..21a192357b11030dcb64766df9cc179ea092f562 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_packet_util.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_PACKET_UTIL_H_ +#define _CAM_PACKET_UTIL_H_ + +#include <media/cam_defs.h> + +/** + * @brief KMD scratch buffer information + * + * @handle: Memory handle + * @cpu_addr: Cpu address + * @offset: Offset from the start of the buffer + * @size: Size of the buffer + * @used_bytes: Used memory in bytes + * + */ +struct cam_kmd_buf_info { + int handle; + uint32_t *cpu_addr; + uint32_t offset; + uint32_t size; + uint32_t used_bytes; +}; + +/* Generic Cmd Buffer blob callback function type */ +typedef int (*cam_packet_generic_blob_handler)(void *user_data, + uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data); + +/** + * cam_packet_util_get_cmd_mem_addr() + * + * @brief Get command buffer address + * + * @handle: Command buffer memory handle + * @buf_addr: Command buffer cpu mapped address + * @len: Command buffer length + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, + size_t *len); + +/** + * cam_packet_util_validate_packet() + * + * @brief Validate the packet + * + * @packet: Packet to be validated + * + * @remain_len: CPU buff length after config offset + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len); + +/** + * cam_packet_util_validate_cmd_desc() + * + * @brief Validate the packet + * + * @cmd_desc: Command descriptor to be validated + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc); + +/** + * cam_packet_util_get_kmd_buffer() + * + * @brief Get the kmd buffer from the packet command descriptor + * + * @packet: Packet data + * @kmd_buf: Extracted the KMD buffer information + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, + struct cam_kmd_buf_info *kmd_buf_info); + +/** + * cam_packet_dump_patch_info() + * + * @brief: Dump patch info in case of page fault + * + * @packet: Input packet containing Command Buffers and Patches + * @iommu_hdl: IOMMU handle of the HW Device that received the packet + * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that + * received the packet + * + */ +void cam_packet_dump_patch_info(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl); + +/** + * cam_packet_util_process_patches() + * + * @brief: Replace the handle in Packet to Address using the + * information from patches. + * + * @packet: Input packet containing Command Buffers and Patches + * @iommu_hdl: IOMMU handle of the HW Device that received the packet + * @sec_iommu_hdl: Secure IOMMU handle of the HW Device that + * received the packet + * + * @return: 0: Success + * Negative: Failure + */ +int cam_packet_util_process_patches(struct cam_packet *packet, + int32_t iommu_hdl, int32_t sec_mmu_hdl); + +/** + * cam_packet_util_process_generic_cmd_buffer() + * + * @brief: Process Generic Blob command buffer. This utility + * function process the command buffer and calls the + * blob_handle_cb callback for each blob that exists + * in the command buffer. + * + * @cmd_buf: Generic Blob Cmd Buffer handle + * @blob_handler_cb: Callback pointer to call for each blob exists in the + * command buffer + * @user_data: User data to be passed while callback + * + * @return: 0: Success + * Negative: Failure + */ +int cam_packet_util_process_generic_cmd_buffer( + struct cam_cmd_buf_desc *cmd_buf, + cam_packet_generic_blob_handler blob_handler_cb, void *user_data); + +#endif /* _CAM_PACKET_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_utils/cam_soc_util.c b/techpack/camera/drivers/cam_utils/cam_soc_util.c new file mode 100644 index 0000000000000000000000000000000000000000..6c564fd8337fbc4f79307e488825fec68592551d --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_soc_util.c @@ -0,0 +1,2218 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include "cam_soc_util.h" +#include "cam_debug_util.h" +#include "cam_cx_ipeak.h" +#include "cam_mem_mgr.h" + +static char supported_clk_info[256]; +static char debugfs_dir_name[64]; + +int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int64_t clk_rate, int clk_idx, int32_t *clk_lvl) +{ + int i; + long clk_rate_round; + + if (!soc_info || (clk_idx < 0) || (clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid src_clk_idx: %d", clk_idx); + *clk_lvl = -1; + return -EINVAL; + } + + clk_rate_round = clk_round_rate(soc_info->clk[clk_idx], clk_rate); + if (clk_rate_round < 0) { + CAM_ERR(CAM_UTIL, "round failed rc = %ld", + clk_rate_round); + *clk_lvl = -1; + return -EINVAL; + } + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if ((soc_info->clk_level_valid[i]) && + (soc_info->clk_rate[i][clk_idx] >= + clk_rate_round)) { + CAM_DBG(CAM_UTIL, + "soc = %d round rate = %ld actual = %lld", + soc_info->clk_rate[i][clk_idx], + clk_rate_round, clk_rate); + *clk_lvl = i; + return 0; + } + } + + CAM_WARN(CAM_UTIL, "Invalid clock rate %ld", clk_rate_round); + *clk_lvl = -1; + return -EINVAL; +} + +/** + * cam_soc_util_get_string_from_level() + * + * @brief: Returns the string for a given clk level + * + * @level: Clock level + * + * @return: String corresponding to the clk level + */ +static const char *cam_soc_util_get_string_from_level( + enum cam_vote_level level) +{ + switch (level) { + case CAM_SUSPEND_VOTE: + return ""; + case CAM_MINSVS_VOTE: + return "MINSVS[1]"; + case CAM_LOWSVS_VOTE: + return "LOWSVS[2]"; + case CAM_SVS_VOTE: + return "SVS[3]"; + case CAM_SVSL1_VOTE: + return "SVSL1[4]"; + case CAM_NOMINAL_VOTE: + return "NOM[5]"; + case CAM_NOMINALL1_VOTE: + return "NOML1[6]"; + case CAM_TURBO_VOTE: + return "TURBO[7]"; + default: + return ""; + } +} + +/** + * cam_soc_util_get_supported_clk_levels() + * + * @brief: Returns the string of all the supported clk levels for + * the given device + * + * @soc_info: Device soc information + * + * @return: String containing all supported clk levels + */ +static const char *cam_soc_util_get_supported_clk_levels( + struct cam_hw_soc_info *soc_info) +{ + int i = 0; + + memset(supported_clk_info, 0, sizeof(supported_clk_info)); + strlcat(supported_clk_info, "Supported levels: ", + sizeof(supported_clk_info)); + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_level_valid[i] == true) { + strlcat(supported_clk_info, + cam_soc_util_get_string_from_level(i), + sizeof(supported_clk_info)); + strlcat(supported_clk_info, " ", + sizeof(supported_clk_info)); + } + } + + strlcat(supported_clk_info, "\n", sizeof(supported_clk_info)); + return supported_clk_info; +} + +static int cam_soc_util_clk_lvl_options_open(struct inode *inode, + struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t cam_soc_util_clk_lvl_options_read(struct file *file, + char __user *clk_info, size_t size_t, loff_t *loff_t) +{ + struct cam_hw_soc_info *soc_info = + (struct cam_hw_soc_info *)file->private_data; + const char *display_string = + cam_soc_util_get_supported_clk_levels(soc_info); + + return simple_read_from_buffer(clk_info, size_t, loff_t, display_string, + strlen(display_string)); +} + +static const struct file_operations cam_soc_util_clk_lvl_options = { + .open = cam_soc_util_clk_lvl_options_open, + .read = cam_soc_util_clk_lvl_options_read, +}; + +static int cam_soc_util_set_clk_lvl(void *data, u64 val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + if (val <= CAM_SUSPEND_VOTE || val >= CAM_MAX_VOTE) + return 0; + + if (soc_info->clk_level_valid[val] == true) + soc_info->clk_level_override = val; + else + soc_info->clk_level_override = 0; + + return 0; +} + +static int cam_soc_util_get_clk_lvl(void *data, u64 *val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + *val = soc_info->clk_level_override; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_soc_util_clk_lvl_control, + cam_soc_util_get_clk_lvl, cam_soc_util_set_clk_lvl, "%08llu"); + +/** + * cam_soc_util_create_clk_lvl_debugfs() + * + * @brief: Creates debugfs files to view/control device clk rates + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +static int cam_soc_util_create_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + struct dentry *dentry = NULL; + + if (!soc_info) { + CAM_ERR(CAM_UTIL, "soc info is NULL"); + return -EINVAL; + } + + if (soc_info->dentry) + return 0; + + memset(debugfs_dir_name, 0, sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, "clk_dir_", sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, soc_info->dev_name, sizeof(debugfs_dir_name)); + + dentry = soc_info->dentry; + dentry = debugfs_create_dir(debugfs_dir_name, NULL); + if (!dentry) { + CAM_ERR(CAM_UTIL, "failed to create debug directory"); + return -ENOMEM; + } + + if (!debugfs_create_file("clk_lvl_options", 0444, + dentry, soc_info, &cam_soc_util_clk_lvl_options)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_options"); + goto err; + } + + if (!debugfs_create_file("clk_lvl_control", 0644, + dentry, soc_info, &cam_soc_util_clk_lvl_control)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_control"); + goto err; + } + + CAM_DBG(CAM_UTIL, "clk lvl debugfs for %s successfully created", + soc_info->dev_name); + + return 0; + +err: + debugfs_remove_recursive(dentry); + dentry = NULL; + return -ENOMEM; +} + +/** + * cam_soc_util_remove_clk_lvl_debugfs() + * + * @brief: Removes the debugfs files used to view/control + * device clk rates + * + * @soc_info: Device soc information + * + */ +static void cam_soc_util_remove_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + debugfs_remove_recursive(soc_info->dentry); + soc_info->dentry = NULL; +} + +int cam_soc_util_get_level_from_string(const char *string, + enum cam_vote_level *level) +{ + if (!level) + return -EINVAL; + + if (!strcmp(string, "suspend")) { + *level = CAM_SUSPEND_VOTE; + } else if (!strcmp(string, "minsvs")) { + *level = CAM_MINSVS_VOTE; + } else if (!strcmp(string, "lowsvs")) { + *level = CAM_LOWSVS_VOTE; + } else if (!strcmp(string, "svs")) { + *level = CAM_SVS_VOTE; + } else if (!strcmp(string, "svs_l1")) { + *level = CAM_SVSL1_VOTE; + } else if (!strcmp(string, "nominal")) { + *level = CAM_NOMINAL_VOTE; + } else if (!strcmp(string, "nominal_l1")) { + *level = CAM_NOMINALL1_VOTE; + } else if (!strcmp(string, "turbo")) { + *level = CAM_TURBO_VOTE; + } else { + CAM_ERR(CAM_UTIL, "Invalid string %s", string); + return -EINVAL; + } + + return 0; +} + +/** + * cam_soc_util_get_clk_level_to_apply() + * + * @brief: Get the clock level to apply. If the requested level + * is not valid, bump the level to next available valid + * level. If no higher level found, return failure. + * + * @soc_info: Device soc struct to be populated + * @req_level: Requested level + * @apply_level Level to apply + * + * @return: success or failure + */ +static int cam_soc_util_get_clk_level_to_apply( + struct cam_hw_soc_info *soc_info, enum cam_vote_level req_level, + enum cam_vote_level *apply_level) +{ + if (req_level >= CAM_MAX_VOTE) { + CAM_ERR(CAM_UTIL, "Invalid clock level parameter %d", + req_level); + return -EINVAL; + } + + if (soc_info->clk_level_valid[req_level] == true) { + *apply_level = req_level; + } else { + int i; + + for (i = (req_level + 1); i < CAM_MAX_VOTE; i++) + if (soc_info->clk_level_valid[i] == true) { + *apply_level = i; + break; + } + + if (i == CAM_MAX_VOTE) { + CAM_ERR(CAM_UTIL, + "No valid clock level found to apply, req=%d", + req_level); + return -EINVAL; + } + } + + CAM_DBG(CAM_UTIL, "Req level %d, Applying %d", + req_level, *apply_level); + + return 0; +} + +int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info) +{ + if (!soc_info) { + CAM_ERR(CAM_UTIL, "Invalid arguments"); + return -EINVAL; + } + + if (!soc_info->irq_line) { + CAM_ERR(CAM_UTIL, "No IRQ line available"); + return -ENODEV; + } + + enable_irq(soc_info->irq_line->start); + + return 0; +} + +int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info) +{ + if (!soc_info) { + CAM_ERR(CAM_UTIL, "Invalid arguments"); + return -EINVAL; + } + + if (!soc_info->irq_line) { + CAM_ERR(CAM_UTIL, "No IRQ line available"); + return -ENODEV; + } + + disable_irq(soc_info->irq_line->start); + + return 0; +} + +long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long clk_rate) +{ + if (!soc_info || (clk_index >= soc_info->num_clk) || (clk_rate == 0)) { + CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d %lu", + soc_info, clk_index, clk_rate); + return clk_rate; + } + + return clk_round_rate(soc_info->clk[clk_index], clk_rate); +} + +/** + * cam_soc_util_set_clk_rate() + * + * @brief: Sets the given rate for the clk requested for + * + * @clk: Clock structure information for which rate is to be set + * @clk_name: Name of the clock for which rate is being set + * @clk_rate Clock rate to be set + * + * @return: Success or failure + */ +static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, + int64_t clk_rate) +{ + int rc = 0; + long clk_rate_round; + + if (!clk || !clk_name) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "set %s, rate %lld", clk_name, clk_rate); + if (clk_rate > 0) { + clk_rate_round = clk_round_rate(clk, clk_rate); + CAM_DBG(CAM_UTIL, "new_rate %ld", clk_rate_round); + if (clk_rate_round < 0) { + CAM_ERR(CAM_UTIL, "round failed for clock %s rc = %ld", + clk_name, clk_rate_round); + return clk_rate_round; + } + rc = clk_set_rate(clk, clk_rate_round); + if (rc) { + CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name); + return rc; + } + } else if (clk_rate == INIT_RATE) { + clk_rate_round = clk_get_rate(clk); + CAM_DBG(CAM_UTIL, "init new_rate %ld", clk_rate_round); + if (clk_rate_round == 0) { + clk_rate_round = clk_round_rate(clk, 0); + if (clk_rate_round <= 0) { + CAM_ERR(CAM_UTIL, "round rate failed on %s", + clk_name); + return clk_rate_round; + } + } + rc = clk_set_rate(clk, clk_rate_round); + if (rc) { + CAM_ERR(CAM_UTIL, "set_rate failed on %s", clk_name); + return rc; + } + } + + return rc; +} + +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, + int64_t clk_rate) +{ + int rc = 0; + int i = 0; + int32_t src_clk_idx; + int32_t scl_clk_idx; + struct clk *clk = NULL; + int32_t apply_level; + uint32_t clk_level_override = 0; + + if (!soc_info || (soc_info->src_clk_idx < 0) || + (soc_info->src_clk_idx >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid src_clk_idx: %d", + soc_info ? soc_info->src_clk_idx : -1); + return -EINVAL; + } + + src_clk_idx = soc_info->src_clk_idx; + clk_level_override = soc_info->clk_level_override; + if (clk_level_override && clk_rate) + clk_rate = + soc_info->clk_rate[clk_level_override][src_clk_idx]; + + clk = soc_info->clk[src_clk_idx]; + rc = cam_soc_util_get_clk_level(soc_info, clk_rate, src_clk_idx, + &apply_level); + if (rc || (apply_level < 0) || (apply_level >= CAM_MAX_VOTE)) { + CAM_ERR(CAM_UTIL, + "set %s, rate %lld dev_name = %s apply level = %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, apply_level); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "set %s, rate %lld dev_name = %s apply level = %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, apply_level); + + if ((soc_info->cam_cx_ipeak_enable) && (clk_rate >= 0)) { + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, + apply_level); + } + + rc = cam_soc_util_set_clk_rate(clk, + soc_info->clk_name[src_clk_idx], clk_rate); + if (rc) { + CAM_ERR(CAM_UTIL, + "SET_RATE Failed: src clk: %s, rate %lld, dev_name = %s rc: %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, rc); + return rc; + } + + /* set clk rate for scalable clk if available */ + + for (i = 0; i < soc_info->scl_clk_count; i++) { + scl_clk_idx = soc_info->scl_clk_idx[i]; + if (scl_clk_idx < 0) { + CAM_DBG(CAM_UTIL, "Scl clk index invalid"); + continue; + } + clk = soc_info->clk[scl_clk_idx]; + rc = cam_soc_util_set_clk_rate(clk, + soc_info->clk_name[scl_clk_idx], + soc_info->clk_rate[apply_level][scl_clk_idx]); + if (rc) { + CAM_WARN(CAM_UTIL, + "SET_RATE Failed: scl clk: %s, rate %d dev_name = %s, rc: %d", + soc_info->clk_name[scl_clk_idx], + soc_info->clk_rate[apply_level][scl_clk_idx], + soc_info->dev_name, rc); + } + } + + return 0; +} + +int cam_soc_util_clk_put(struct clk **clk) +{ + if (!(*clk)) { + CAM_ERR(CAM_UTIL, "Invalid params clk"); + return -EINVAL; + } + + clk_put(*clk); + *clk = NULL; + + return 0; +} + +static struct clk *cam_soc_util_option_clk_get(struct device_node *np, + int index) +{ + struct of_phandle_args clkspec; + struct clk *clk; + int rc; + + if (index < 0) + return ERR_PTR(-EINVAL); + + rc = of_parse_phandle_with_args(np, "clocks-option", "#clock-cells", + index, &clkspec); + if (rc) + return ERR_PTR(rc); + + clk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); + + return clk; +} + +int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info, + const char *clk_name, struct clk **clk, int32_t *clk_index, + int32_t *clk_rate) +{ + int index = 0; + int rc = 0; + struct device_node *of_node = NULL; + + if (!soc_info || !clk_name || !clk) { + CAM_ERR(CAM_UTIL, + "Invalid params soc_info %pK clk_name %s clk %pK", + soc_info, clk_name, clk); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + + index = of_property_match_string(of_node, "clock-names-option", + clk_name); + + if (index < 0) { + CAM_INFO(CAM_UTIL, "No clk data for %s", clk_name); + *clk_index = -1; + *clk = ERR_PTR(-EINVAL); + return -EINVAL; + } + + *clk = cam_soc_util_option_clk_get(of_node, index); + if (IS_ERR(*clk)) { + CAM_ERR(CAM_UTIL, "No clk named %s found. Dev %s", clk_name, + soc_info->dev_name); + *clk_index = -1; + return -EFAULT; + } + *clk_index = index; + + rc = of_property_read_u32_index(of_node, "clock-rates-option", + index, clk_rate); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading clock-rates clk_name %s index %d", + clk_name, index); + cam_soc_util_clk_put(clk); + *clk_rate = 0; + return rc; + } + + /* + * Option clocks are assumed to be available to single Device here. + * Hence use INIT_RATE instead of NO_SET_RATE. + */ + *clk_rate = (*clk_rate == 0) ? (int32_t)INIT_RATE : *clk_rate; + + CAM_DBG(CAM_UTIL, "clk_name %s index %d clk_rate %d", + clk_name, *clk_index, *clk_rate); + + return 0; +} + +int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name, + int32_t clk_rate) +{ + int rc = 0; + + if (!clk || !clk_name) + return -EINVAL; + + rc = cam_soc_util_set_clk_rate(clk, clk_name, clk_rate); + if (rc) + return rc; + + rc = clk_prepare_enable(clk); + if (rc) { + CAM_ERR(CAM_UTIL, "enable failed for %s: rc(%d)", clk_name, rc); + return rc; + } + + return rc; +} + +int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name) +{ + if (!clk || !clk_name) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "disable %s", clk_name); + clk_disable_unprepare(clk); + + return 0; +} + +/** + * cam_soc_util_clk_enable_default() + * + * @brief: This function enables the default clocks present + * in soc_info + * + * @soc_info: Device soc struct to be populated + * @clk_level: Clk level to apply while enabling + * + * @return: success or failure + */ +int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level) +{ + int i, rc = 0; + enum cam_vote_level apply_level; + + if ((soc_info->num_clk == 0) || + (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid number of clock %d", + soc_info->num_clk); + return -EINVAL; + } + + rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level, + &apply_level); + if (rc) + return rc; + + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + + for (i = 0; i < soc_info->num_clk; i++) { + rc = cam_soc_util_clk_enable(soc_info->clk[i], + soc_info->clk_name[i], + soc_info->clk_rate[apply_level][i]); + if (rc) + goto clk_disable; + if (soc_info->cam_cx_ipeak_enable) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk name = %s idx = %d\n" + "apply_level = %d clc idx = %d", + soc_info->dev_name, soc_info->clk_name[i], i, + apply_level, i); + } + + } + + return rc; + +clk_disable: + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); + for (i--; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + + return rc; +} + +/** + * cam_soc_util_clk_disable_default() + * + * @brief: This function disables the default clocks present + * in soc_info + * + * @soc_info: device soc struct to be populated + * + * @return: success or failure + */ +void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info) +{ + int i; + + if (soc_info->num_clk == 0) + return; + + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_unvote_cx_ipeak(soc_info); + for (i = soc_info->num_clk - 1; i >= 0; i--) + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); +} + +/** + * cam_soc_util_get_dt_clk_info() + * + * @brief: Parse the DT and populate the Clock properties + * + * @soc_info: device soc struct to be populated + * @src_clk_str name of src clock that has rate control + * + * @return: success or failure + */ +static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = NULL; + int count; + int num_clk_rates, num_clk_levels; + int i, j, rc; + int32_t num_clk_level_strings; + const char *src_clk_str = NULL; + const char *scl_clk_str = NULL; + const char *clk_control_debugfs = NULL; + const char *clk_cntl_lvl_string = NULL; + enum cam_vote_level level; + + if (!soc_info || !soc_info->dev) + return -EINVAL; + + of_node = soc_info->dev->of_node; + + if (!of_property_read_bool(of_node, "use-shared-clk")) { + CAM_DBG(CAM_UTIL, "No shared clk parameter defined"); + soc_info->use_shared_clk = false; + } else { + soc_info->use_shared_clk = true; + } + + count = of_property_count_strings(of_node, "clock-names"); + + CAM_DBG(CAM_UTIL, "E: dev_name = %s count = %d", + soc_info->dev_name, count); + if (count > CAM_SOC_MAX_CLK) { + CAM_ERR(CAM_UTIL, "invalid count of clocks, count=%d", count); + rc = -EINVAL; + return rc; + } + if (count <= 0) { + CAM_DBG(CAM_UTIL, "No clock-names found"); + count = 0; + soc_info->num_clk = count; + return 0; + } + soc_info->num_clk = count; + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, "clock-names", + i, &(soc_info->clk_name[i])); + CAM_DBG(CAM_UTIL, "clock-names[%d] = %s", + i, soc_info->clk_name[i]); + if (rc) { + CAM_ERR(CAM_UTIL, + "i= %d count= %d reading clock-names failed", + i, count); + return rc; + } + } + + num_clk_rates = of_property_count_u32_elems(of_node, "clock-rates"); + if (num_clk_rates <= 0) { + CAM_ERR(CAM_UTIL, "reading clock-rates count failed"); + return -EINVAL; + } + + if ((num_clk_rates % soc_info->num_clk) != 0) { + CAM_ERR(CAM_UTIL, + "mismatch clk/rates, No of clocks=%d, No of rates=%d", + soc_info->num_clk, num_clk_rates); + return -EINVAL; + } + + num_clk_levels = (num_clk_rates / soc_info->num_clk); + + num_clk_level_strings = of_property_count_strings(of_node, + "clock-cntl-level"); + if (num_clk_level_strings != num_clk_levels) { + CAM_ERR(CAM_UTIL, + "Mismatch No of levels=%d, No of level string=%d", + num_clk_levels, num_clk_level_strings); + return -EINVAL; + } + + for (i = 0; i < num_clk_levels; i++) { + rc = of_property_read_string_index(of_node, + "clock-cntl-level", i, &clk_cntl_lvl_string); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading clock-cntl-level, rc=%d", rc); + return rc; + } + + rc = cam_soc_util_get_level_from_string(clk_cntl_lvl_string, + &level); + if (rc) + return rc; + + CAM_DBG(CAM_UTIL, + "[%d] : %s %d", i, clk_cntl_lvl_string, level); + soc_info->clk_level_valid[level] = true; + for (j = 0; j < soc_info->num_clk; j++) { + rc = of_property_read_u32_index(of_node, "clock-rates", + ((i * soc_info->num_clk) + j), + &soc_info->clk_rate[level][j]); + if (rc) { + CAM_ERR(CAM_UTIL, + "Error reading clock-rates, rc=%d", + rc); + return rc; + } + + soc_info->clk_rate[level][j] = + (soc_info->clk_rate[level][j] == 0) ? + (int32_t)NO_SET_RATE : + soc_info->clk_rate[level][j]; + + CAM_DBG(CAM_UTIL, "soc_info->clk_rate[%d][%d] = %d", + level, j, + soc_info->clk_rate[level][j]); + } + } + + soc_info->src_clk_idx = -1; + rc = of_property_read_string_index(of_node, "src-clock-name", 0, + &src_clk_str); + if (rc || !src_clk_str) { + CAM_DBG(CAM_UTIL, "No src_clk_str found"); + rc = 0; + goto end; + } + + for (i = 0; i < soc_info->num_clk; i++) { + if (strcmp(soc_info->clk_name[i], src_clk_str) == 0) { + soc_info->src_clk_idx = i; + CAM_DBG(CAM_UTIL, "src clock = %s, index = %d", + src_clk_str, i); + break; + } + } + + /* scalable clk info parsing */ + soc_info->scl_clk_count = 0; + soc_info->scl_clk_count = of_property_count_strings(of_node, + "scl-clk-names"); + if ((soc_info->scl_clk_count <= 0) || + (soc_info->scl_clk_count > CAM_SOC_MAX_CLK)) { + if (soc_info->scl_clk_count == -EINVAL) { + CAM_DBG(CAM_UTIL, "scl_clk_name prop not avialable"); + } else if ((soc_info->scl_clk_count == -ENODATA) || + (soc_info->scl_clk_count > CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid scl_clk_count: %d", + soc_info->scl_clk_count); + return -EINVAL; + } + CAM_DBG(CAM_UTIL, "Invalid scl_clk count: %d", + soc_info->scl_clk_count); + soc_info->scl_clk_count = -1; + } else { + CAM_DBG(CAM_UTIL, "No of scalable clocks: %d", + soc_info->scl_clk_count); + for (i = 0; i < soc_info->scl_clk_count; i++) { + rc = of_property_read_string_index(of_node, + "scl-clk-names", i, + (const char **)&scl_clk_str); + if (rc || !scl_clk_str) { + CAM_WARN(CAM_UTIL, "scl_clk_str is NULL"); + soc_info->scl_clk_idx[i] = -1; + continue; + } + for (j = 0; j < soc_info->num_clk; j++) { + if (strnstr(scl_clk_str, soc_info->clk_name[j], + strlen(scl_clk_str))) { + soc_info->scl_clk_idx[i] = j; + CAM_DBG(CAM_UTIL, + "scl clock = %s, index = %d", + scl_clk_str, j); + break; + } + } + } + } + + rc = of_property_read_string_index(of_node, + "clock-control-debugfs", 0, &clk_control_debugfs); + if (rc || !clk_control_debugfs) { + CAM_DBG(CAM_UTIL, "No clock_control_debugfs property found"); + rc = 0; + goto end; + } + + if (strcmp("true", clk_control_debugfs) == 0) + soc_info->clk_control_enable = true; + + CAM_DBG(CAM_UTIL, "X: dev_name = %s count = %d", + soc_info->dev_name, count); +end: + return rc; +} + +int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level) +{ + int i, rc = 0; + enum cam_vote_level apply_level; + + if ((soc_info->num_clk == 0) || + (soc_info->num_clk >= CAM_SOC_MAX_CLK)) { + CAM_ERR(CAM_UTIL, "Invalid number of clock %d", + soc_info->num_clk); + return -EINVAL; + } + + rc = cam_soc_util_get_clk_level_to_apply(soc_info, clk_level, + &apply_level); + if (rc) + return rc; + + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + + for (i = 0; i < soc_info->num_clk; i++) { + rc = cam_soc_util_set_clk_rate(soc_info->clk[i], + soc_info->clk_name[i], + soc_info->clk_rate[apply_level][i]); + if (rc < 0) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk_name = %s idx = %d\n" + "apply_level = %d", + soc_info->dev_name, soc_info->clk_name[i], + i, apply_level); + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); + break; + } + } + + return rc; +}; + +static int cam_soc_util_get_dt_gpio_req_tbl(struct device_node *of_node, + struct cam_soc_gpio_data *gconf, uint16_t *gpio_array, + uint16_t gpio_array_size) +{ + int32_t rc = 0, i = 0; + uint32_t count = 0; + uint32_t *val_array = NULL; + + if (!of_get_property(of_node, "gpio-req-tbl-num", &count)) + return 0; + + count /= sizeof(uint32_t); + if (!count) { + CAM_ERR(CAM_UTIL, "gpio-req-tbl-num 0"); + return 0; + } + + val_array = kcalloc(count, sizeof(uint32_t), GFP_KERNEL); + if (!val_array) + return -ENOMEM; + + gconf->cam_gpio_req_tbl = kcalloc(count, sizeof(struct gpio), + GFP_KERNEL); + if (!gconf->cam_gpio_req_tbl) { + rc = -ENOMEM; + goto free_val_array; + } + gconf->cam_gpio_req_tbl_size = count; + + rc = of_property_read_u32_array(of_node, "gpio-req-tbl-num", + val_array, count); + if (rc) { + CAM_ERR(CAM_UTIL, "failed in reading gpio-req-tbl-num, rc = %d", + rc); + goto free_gpio_req_tbl; + } + + for (i = 0; i < count; i++) { + if (val_array[i] >= gpio_array_size) { + CAM_ERR(CAM_UTIL, "gpio req tbl index %d invalid", + val_array[i]); + goto free_gpio_req_tbl; + } + gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]]; + CAM_DBG(CAM_UTIL, "cam_gpio_req_tbl[%d].gpio = %d", i, + gconf->cam_gpio_req_tbl[i].gpio); + } + + rc = of_property_read_u32_array(of_node, "gpio-req-tbl-flags", + val_array, count); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed in gpio-req-tbl-flags, rc %d", rc); + goto free_gpio_req_tbl; + } + + for (i = 0; i < count; i++) { + gconf->cam_gpio_req_tbl[i].flags = val_array[i]; + CAM_DBG(CAM_UTIL, "cam_gpio_req_tbl[%d].flags = %ld", i, + gconf->cam_gpio_req_tbl[i].flags); + } + + for (i = 0; i < count; i++) { + rc = of_property_read_string_index(of_node, + "gpio-req-tbl-label", i, + &gconf->cam_gpio_req_tbl[i].label); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed rc %d", rc); + goto free_gpio_req_tbl; + } + CAM_DBG(CAM_UTIL, "cam_gpio_req_tbl[%d].label = %s", i, + gconf->cam_gpio_req_tbl[i].label); + } + + kfree(val_array); + + return rc; + +free_gpio_req_tbl: + kfree(gconf->cam_gpio_req_tbl); +free_val_array: + kfree(val_array); + gconf->cam_gpio_req_tbl_size = 0; + + return rc; +} + +static int cam_soc_util_get_gpio_info(struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0, i = 0; + uint16_t *gpio_array = NULL; + int16_t gpio_array_size = 0; + struct cam_soc_gpio_data *gconf = NULL; + struct device_node *of_node = NULL; + + if (!soc_info || !soc_info->dev) + return -EINVAL; + + of_node = soc_info->dev->of_node; + + /* Validate input parameters */ + if (!of_node) { + CAM_ERR(CAM_UTIL, "Invalid param of_node"); + return -EINVAL; + } + + gpio_array_size = of_gpio_count(of_node); + + if (gpio_array_size <= 0) + return 0; + + CAM_DBG(CAM_UTIL, "gpio count %d", gpio_array_size); + + gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL); + if (!gpio_array) + goto free_gpio_conf; + + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CAM_DBG(CAM_UTIL, "gpio_array[%d] = %d", i, gpio_array[i]); + } + + gconf = kzalloc(sizeof(*gconf), GFP_KERNEL); + if (!gconf) + return -ENOMEM; + + rc = cam_soc_util_get_dt_gpio_req_tbl(of_node, gconf, gpio_array, + gpio_array_size); + if (rc) { + CAM_ERR(CAM_UTIL, "failed in msm_camera_get_dt_gpio_req_tbl"); + goto free_gpio_array; + } + + gconf->cam_gpio_common_tbl = kcalloc(gpio_array_size, + sizeof(struct gpio), GFP_KERNEL); + if (!gconf->cam_gpio_common_tbl) { + rc = -ENOMEM; + goto free_gpio_array; + } + + for (i = 0; i < gpio_array_size; i++) + gconf->cam_gpio_common_tbl[i].gpio = gpio_array[i]; + + gconf->cam_gpio_common_tbl_size = gpio_array_size; + soc_info->gpio_data = gconf; + kfree(gpio_array); + + return rc; + +free_gpio_array: + kfree(gpio_array); +free_gpio_conf: + kfree(gconf); + soc_info->gpio_data = NULL; + + return rc; +} + +static int cam_soc_util_request_gpio_table( + struct cam_hw_soc_info *soc_info, bool gpio_en) +{ + int rc = 0, i = 0; + uint8_t size = 0; + struct cam_soc_gpio_data *gpio_conf = + soc_info->gpio_data; + struct gpio *gpio_tbl = NULL; + + + if (!gpio_conf) { + CAM_DBG(CAM_UTIL, "No GPIO entry"); + return 0; + } + if (gpio_conf->cam_gpio_common_tbl_size <= 0) { + CAM_ERR(CAM_UTIL, "GPIO table size is invalid"); + return -EINVAL; + } + size = gpio_conf->cam_gpio_req_tbl_size; + gpio_tbl = gpio_conf->cam_gpio_req_tbl; + + if (!gpio_tbl || !size) { + CAM_ERR(CAM_UTIL, "Invalid gpio_tbl %pK / size %d", + gpio_tbl, size); + return -EINVAL; + } + for (i = 0; i < size; i++) { + CAM_DBG(CAM_UTIL, "i=%d, gpio=%d dir=%ld", i, + gpio_tbl[i].gpio, gpio_tbl[i].flags); + } + if (gpio_en) { + for (i = 0; i < size; i++) { + rc = gpio_request_one(gpio_tbl[i].gpio, + gpio_tbl[i].flags, gpio_tbl[i].label); + if (rc) { + /* + * After GPIO request fails, contine to + * apply new gpios, outout a error message + * for driver bringup debug + */ + CAM_ERR(CAM_UTIL, "gpio %d:%s request fails", + gpio_tbl[i].gpio, gpio_tbl[i].label); + } + } + } else { + gpio_free_array(gpio_tbl, size); + } + + return rc; +} + +static int cam_soc_util_get_dt_regulator_info + (struct cam_hw_soc_info *soc_info) +{ + int rc = 0, count = 0, i = 0; + struct device_node *of_node = NULL; + + if (!soc_info || !soc_info->dev) { + CAM_ERR(CAM_UTIL, "Invalid parameters"); + return -EINVAL; + } + + of_node = soc_info->dev->of_node; + + soc_info->num_rgltr = 0; + count = of_property_count_strings(of_node, "regulator-names"); + if (count != -EINVAL) { + if (count <= 0) { + CAM_ERR(CAM_UTIL, "no regulators found"); + count = 0; + return -EINVAL; + } + + soc_info->num_rgltr = count; + + } else { + CAM_DBG(CAM_UTIL, "No regulators node found"); + return 0; + } + + for (i = 0; i < soc_info->num_rgltr; i++) { + rc = of_property_read_string_index(of_node, + "regulator-names", i, &soc_info->rgltr_name[i]); + CAM_DBG(CAM_UTIL, "rgltr_name[%d] = %s", + i, soc_info->rgltr_name[i]); + if (rc) { + CAM_ERR(CAM_UTIL, "no regulator resource at cnt=%d", i); + return -ENODEV; + } + } + + if (!of_property_read_bool(of_node, "rgltr-cntrl-support")) { + CAM_DBG(CAM_UTIL, "No regulator control parameter defined"); + soc_info->rgltr_ctrl_support = false; + return 0; + } + + soc_info->rgltr_ctrl_support = true; + + rc = of_property_read_u32_array(of_node, "rgltr-min-voltage", + soc_info->rgltr_min_volt, soc_info->num_rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "No minimum volatage value found, rc=%d", rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "rgltr-max-voltage", + soc_info->rgltr_max_volt, soc_info->num_rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "No maximum volatage value found, rc=%d", rc); + return -EINVAL; + } + + rc = of_property_read_u32_array(of_node, "rgltr-load-current", + soc_info->rgltr_op_mode, soc_info->num_rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "No Load curent found rc=%d", rc); + return -EINVAL; + } + + return rc; +} + +int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = NULL; + int count = 0, i = 0, rc = 0; + + if (!soc_info || !soc_info->dev) + return -EINVAL; + + of_node = soc_info->dev->of_node; + + rc = of_property_read_u32(of_node, "cell-index", &soc_info->index); + if (rc) { + CAM_ERR(CAM_UTIL, "device %s failed to read cell-index", + soc_info->dev_name); + return rc; + } + + count = of_property_count_strings(of_node, "reg-names"); + if (count <= 0) { + CAM_DBG(CAM_UTIL, "no reg-names found for: %s", + soc_info->dev_name); + count = 0; + } + soc_info->num_mem_block = count; + + for (i = 0; i < soc_info->num_mem_block; i++) { + rc = of_property_read_string_index(of_node, "reg-names", i, + &soc_info->mem_block_name[i]); + if (rc) { + CAM_ERR(CAM_UTIL, "failed to read reg-names at %d", i); + return rc; + } + soc_info->mem_block[i] = + platform_get_resource_byname(soc_info->pdev, + IORESOURCE_MEM, soc_info->mem_block_name[i]); + + if (!soc_info->mem_block[i]) { + CAM_ERR(CAM_UTIL, "no mem resource by name %s", + soc_info->mem_block_name[i]); + rc = -ENODEV; + return rc; + } + } + + if (soc_info->num_mem_block > 0) { + rc = of_property_read_u32_array(of_node, "reg-cam-base", + soc_info->mem_block_cam_base, soc_info->num_mem_block); + if (rc) { + CAM_ERR(CAM_UTIL, "Error reading register offsets"); + return rc; + } + } + + rc = of_property_read_string_index(of_node, "interrupt-names", 0, + &soc_info->irq_name); + if (rc) { + CAM_DBG(CAM_UTIL, "No interrupt line preset for: %s", + soc_info->dev_name); + rc = 0; + } else { + soc_info->irq_line = + platform_get_resource_byname(soc_info->pdev, + IORESOURCE_IRQ, soc_info->irq_name); + if (!soc_info->irq_line) { + CAM_ERR(CAM_UTIL, "no irq resource"); + rc = -ENODEV; + return rc; + } + } + + rc = of_property_read_string_index(of_node, "compatible", 0, + (const char **)&soc_info->compatible); + if (rc) { + CAM_DBG(CAM_UTIL, "No compatible string present for: %s", + soc_info->dev_name); + rc = 0; + } + + rc = cam_soc_util_get_dt_regulator_info(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_get_dt_clk_info(soc_info); + if (rc) + return rc; + + rc = cam_soc_util_get_gpio_info(soc_info); + if (rc) + return rc; + + if (of_find_property(of_node, "qcom,cam-cx-ipeak", NULL)) + rc = cam_cx_ipeak_register_cx_ipeak(soc_info); + + return rc; +} + +/** + * cam_soc_util_get_regulator() + * + * @brief: Get regulator resource named vdd + * + * @dev: Device associated with regulator + * @reg: Return pointer to be filled with regulator on success + * @rgltr_name: Name of regulator to get + * + * @return: 0 for Success, negative value for failure + */ +static int cam_soc_util_get_regulator(struct device *dev, + struct regulator **reg, const char *rgltr_name) +{ + int rc = 0; + *reg = regulator_get(dev, rgltr_name); + if (IS_ERR_OR_NULL(*reg)) { + rc = PTR_ERR(*reg); + rc = rc ? rc : -EINVAL; + CAM_ERR(CAM_UTIL, "Regulator %s get failed %d", rgltr_name, rc); + *reg = NULL; + } + return rc; +} + +int cam_soc_util_regulator_disable(struct regulator *rgltr, + const char *rgltr_name, uint32_t rgltr_min_volt, + uint32_t rgltr_max_volt, uint32_t rgltr_op_mode, + uint32_t rgltr_delay_ms) +{ + int32_t rc = 0; + + if (!rgltr) { + CAM_ERR(CAM_UTIL, "Invalid NULL parameter"); + return -EINVAL; + } + + rc = regulator_disable(rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "%s regulator disable failed", rgltr_name); + return rc; + } + + if (rgltr_delay_ms > 20) + msleep(rgltr_delay_ms); + else if (rgltr_delay_ms) + usleep_range(rgltr_delay_ms * 1000, + (rgltr_delay_ms * 1000) + 1000); + + if (regulator_count_voltages(rgltr) > 0) { + regulator_set_load(rgltr, 0); + regulator_set_voltage(rgltr, 0, rgltr_max_volt); + } + + return rc; +} + + +int cam_soc_util_regulator_enable(struct regulator *rgltr, + const char *rgltr_name, + uint32_t rgltr_min_volt, uint32_t rgltr_max_volt, + uint32_t rgltr_op_mode, uint32_t rgltr_delay) +{ + int32_t rc = 0; + + if (!rgltr) { + CAM_ERR(CAM_UTIL, "Invalid NULL parameter"); + return -EINVAL; + } + + if (regulator_count_voltages(rgltr) > 0) { + CAM_DBG(CAM_UTIL, "voltage min=%d, max=%d", + rgltr_min_volt, rgltr_max_volt); + + rc = regulator_set_voltage( + rgltr, rgltr_min_volt, rgltr_max_volt); + if (rc) { + CAM_ERR(CAM_UTIL, "%s set voltage failed", rgltr_name); + return rc; + } + + rc = regulator_set_load(rgltr, rgltr_op_mode); + if (rc) { + CAM_ERR(CAM_UTIL, "%s set optimum mode failed", + rgltr_name); + return rc; + } + } + + rc = regulator_enable(rgltr); + if (rc) { + CAM_ERR(CAM_UTIL, "%s regulator_enable failed", rgltr_name); + return rc; + } + + if (rgltr_delay > 20) + msleep(rgltr_delay); + else if (rgltr_delay) + usleep_range(rgltr_delay * 1000, + (rgltr_delay * 1000) + 1000); + + return rc; +} + +static int cam_soc_util_request_pinctrl( + struct cam_hw_soc_info *soc_info) +{ + + struct cam_soc_pinctrl_info *device_pctrl = &soc_info->pinctrl_info; + struct device *dev = soc_info->dev; + + device_pctrl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(device_pctrl->pinctrl)) { + CAM_DBG(CAM_UTIL, "Pinctrl not available"); + device_pctrl->pinctrl = NULL; + return 0; + } + device_pctrl->gpio_state_active = + pinctrl_lookup_state(device_pctrl->pinctrl, + CAM_SOC_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_active)) { + CAM_ERR(CAM_UTIL, + "Failed to get the active state pinctrl handle"); + device_pctrl->gpio_state_active = NULL; + return -EINVAL; + } + device_pctrl->gpio_state_suspend + = pinctrl_lookup_state(device_pctrl->pinctrl, + CAM_SOC_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(device_pctrl->gpio_state_suspend)) { + CAM_ERR(CAM_UTIL, + "Failed to get the suspend state pinctrl handle"); + device_pctrl->gpio_state_suspend = NULL; + return -EINVAL; + } + return 0; +} + +static void cam_soc_util_regulator_disable_default( + struct cam_hw_soc_info *soc_info) +{ + int j = 0; + uint32_t num_rgltr = soc_info->num_rgltr; + + for (j = num_rgltr-1; j >= 0; j--) { + if (soc_info->rgltr_ctrl_support == true) { + cam_soc_util_regulator_disable(soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + } else { + if (soc_info->rgltr[j]) + regulator_disable(soc_info->rgltr[j]); + } + } +} + +static int cam_soc_util_regulator_enable_default( + struct cam_hw_soc_info *soc_info) +{ + int j = 0, rc = 0; + uint32_t num_rgltr = soc_info->num_rgltr; + + for (j = 0; j < num_rgltr; j++) { + if (soc_info->rgltr_ctrl_support == true) { + rc = cam_soc_util_regulator_enable(soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + } else { + if (soc_info->rgltr[j]) + rc = regulator_enable(soc_info->rgltr[j]); + } + + if (rc) { + CAM_ERR(CAM_UTIL, "%s enable failed", + soc_info->rgltr_name[j]); + goto disable_rgltr; + } + } + + return rc; +disable_rgltr: + + for (j--; j >= 0; j--) { + if (soc_info->rgltr_ctrl_support == true) { + cam_soc_util_regulator_disable(soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + } else { + if (soc_info->rgltr[j]) + regulator_disable(soc_info->rgltr[j]); + } + } + + return rc; +} + +int cam_soc_util_request_platform_resource( + struct cam_hw_soc_info *soc_info, + irq_handler_t handler, void *irq_data) +{ + int i = 0, rc = 0; + + if (!soc_info || !soc_info->dev) { + CAM_ERR(CAM_UTIL, "Invalid parameters"); + return -EINVAL; + } + + for (i = 0; i < soc_info->num_mem_block; i++) { + if (soc_info->reserve_mem) { + if (!request_mem_region(soc_info->mem_block[i]->start, + resource_size(soc_info->mem_block[i]), + soc_info->mem_block_name[i])){ + CAM_ERR(CAM_UTIL, + "Error Mem region request Failed:%s", + soc_info->mem_block_name[i]); + rc = -ENOMEM; + goto unmap_base; + } + } + soc_info->reg_map[i].mem_base = ioremap( + soc_info->mem_block[i]->start, + resource_size(soc_info->mem_block[i])); + if (!soc_info->reg_map[i].mem_base) { + CAM_ERR(CAM_UTIL, "i= %d base NULL", i); + rc = -ENOMEM; + goto unmap_base; + } + soc_info->reg_map[i].mem_cam_base = + soc_info->mem_block_cam_base[i]; + soc_info->reg_map[i].size = + resource_size(soc_info->mem_block[i]); + soc_info->num_reg_map++; + } + + for (i = 0; i < soc_info->num_rgltr; i++) { + if (soc_info->rgltr_name[i] == NULL) { + CAM_ERR(CAM_UTIL, "can't find regulator name"); + goto put_regulator; + } + + rc = cam_soc_util_get_regulator(soc_info->dev, + &soc_info->rgltr[i], + soc_info->rgltr_name[i]); + if (rc) + goto put_regulator; + } + + if (soc_info->irq_line) { + rc = devm_request_irq(soc_info->dev, soc_info->irq_line->start, + handler, IRQF_TRIGGER_RISING, + soc_info->irq_name, irq_data); + if (rc) { + CAM_ERR(CAM_UTIL, "irq request fail"); + rc = -EBUSY; + goto put_regulator; + } + disable_irq(soc_info->irq_line->start); + soc_info->irq_data = irq_data; + } + + /* Get Clock */ + for (i = 0; i < soc_info->num_clk; i++) { + soc_info->clk[i] = clk_get(soc_info->dev, + soc_info->clk_name[i]); + if (!soc_info->clk[i]) { + CAM_ERR(CAM_UTIL, "get failed for %s", + soc_info->clk_name[i]); + rc = -ENOENT; + goto put_clk; + } + } + + rc = cam_soc_util_request_pinctrl(soc_info); + if (rc) + CAM_DBG(CAM_UTIL, "Failed in request pinctrl, rc=%d", rc); + + rc = cam_soc_util_request_gpio_table(soc_info, true); + if (rc) { + CAM_ERR(CAM_UTIL, "Failed in request gpio table, rc=%d", rc); + goto put_clk; + } + + if (soc_info->clk_control_enable) + cam_soc_util_create_clk_lvl_debugfs(soc_info); + + return rc; + +put_clk: + if (i == -1) + i = soc_info->num_clk; + for (i = i - 1; i >= 0; i--) { + if (soc_info->clk[i]) { + clk_put(soc_info->clk[i]); + soc_info->clk[i] = NULL; + } + } + + if (soc_info->irq_line) { + disable_irq(soc_info->irq_line->start); + devm_free_irq(soc_info->dev, + soc_info->irq_line->start, irq_data); + } + +put_regulator: + if (i == -1) + i = soc_info->num_rgltr; + for (i = i - 1; i >= 0; i--) { + if (soc_info->rgltr[i]) { + regulator_disable(soc_info->rgltr[i]); + regulator_put(soc_info->rgltr[i]); + soc_info->rgltr[i] = NULL; + } + } + +unmap_base: + if (i == -1) + i = soc_info->num_reg_map; + for (i = i - 1; i >= 0; i--) { + if (soc_info->reserve_mem) + release_mem_region(soc_info->mem_block[i]->start, + resource_size(soc_info->mem_block[i])); + iounmap(soc_info->reg_map[i].mem_base); + soc_info->reg_map[i].mem_base = NULL; + soc_info->reg_map[i].size = 0; + } + + return rc; +} + +int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info) +{ + int i; + + if (!soc_info || !soc_info->dev) { + CAM_ERR(CAM_UTIL, "Invalid parameter"); + return -EINVAL; + } + + for (i = soc_info->num_clk - 1; i >= 0; i--) { + clk_put(soc_info->clk[i]); + soc_info->clk[i] = NULL; + } + + for (i = soc_info->num_rgltr - 1; i >= 0; i--) { + if (soc_info->rgltr[i]) { + regulator_put(soc_info->rgltr[i]); + soc_info->rgltr[i] = NULL; + } + } + + for (i = soc_info->num_reg_map - 1; i >= 0; i--) { + iounmap(soc_info->reg_map[i].mem_base); + soc_info->reg_map[i].mem_base = NULL; + soc_info->reg_map[i].size = 0; + } + + if (soc_info->irq_line) { + disable_irq(soc_info->irq_line->start); + devm_free_irq(soc_info->dev, + soc_info->irq_line->start, soc_info->irq_data); + } + + if (soc_info->pinctrl_info.pinctrl) + devm_pinctrl_put(soc_info->pinctrl_info.pinctrl); + + + /* release for gpio */ + cam_soc_util_request_gpio_table(soc_info, false); + + if (soc_info->clk_control_enable) + cam_soc_util_remove_clk_lvl_debugfs(soc_info); + + return 0; +} + +int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, + bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq) +{ + int rc = 0; + + if (!soc_info) + return -EINVAL; + + rc = cam_soc_util_regulator_enable_default(soc_info); + if (rc) { + CAM_ERR(CAM_UTIL, "Regulators enable failed"); + return rc; + } + + if (enable_clocks) { + rc = cam_soc_util_clk_enable_default(soc_info, clk_level); + if (rc) + goto disable_regulator; + } + + if (enable_irq) { + rc = cam_soc_util_irq_enable(soc_info); + if (rc) + goto disable_clk; + } + + if (soc_info->pinctrl_info.pinctrl && + soc_info->pinctrl_info.gpio_state_active) { + rc = pinctrl_select_state(soc_info->pinctrl_info.pinctrl, + soc_info->pinctrl_info.gpio_state_active); + + if (rc) + goto disable_irq; + } + + return rc; + +disable_irq: + if (enable_irq) + cam_soc_util_irq_disable(soc_info); + +disable_clk: + if (enable_clocks) + cam_soc_util_clk_disable_default(soc_info); + +disable_regulator: + cam_soc_util_regulator_disable_default(soc_info); + + + return rc; +} + +int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq) +{ + int rc = 0; + + if (!soc_info) + return -EINVAL; + + if (disable_irq) + rc |= cam_soc_util_irq_disable(soc_info); + + if (disable_clocks) + cam_soc_util_clk_disable_default(soc_info); + + cam_soc_util_regulator_disable_default(soc_info); + + if (soc_info->pinctrl_info.pinctrl && + soc_info->pinctrl_info.gpio_state_suspend) + rc = pinctrl_select_state(soc_info->pinctrl_info.pinctrl, + soc_info->pinctrl_info.gpio_state_suspend); + + return rc; +} + +int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, int size) +{ + void __iomem *base_addr = NULL; + + CAM_DBG(CAM_UTIL, "base_idx %u size=%d", base_index, size); + + if (!soc_info || base_index >= soc_info->num_reg_map || + size <= 0 || (offset + size) >= + CAM_SOC_GET_REG_MAP_SIZE(soc_info, base_index)) + return -EINVAL; + + base_addr = CAM_SOC_GET_REG_MAP_START(soc_info, base_index); + + /* + * All error checking already done above, + * hence ignoring the return value below. + */ + cam_io_dump(base_addr, offset, size); + + return 0; +} + +static int cam_soc_util_dump_cont_reg_range( + struct cam_hw_soc_info *soc_info, + struct cam_reg_range_read_desc *reg_read, uint32_t base_idx, + struct cam_reg_dump_out_buffer *dump_out_buf, uintptr_t cmd_buf_end) +{ + int i = 0, rc = 0; + uint32_t write_idx = 0; + + if (!soc_info || !dump_out_buf || !reg_read || !cmd_buf_end) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK reg_read: %pK cmd_buf_end: %pK", + soc_info, dump_out_buf, reg_read, cmd_buf_end); + rc = -EINVAL; + goto end; + } + + if ((reg_read->num_values) && ((reg_read->num_values > U32_MAX / 2) || + (sizeof(uint32_t) > ((U32_MAX - + sizeof(struct cam_reg_dump_out_buffer) - + dump_out_buf->bytes_written) / + (reg_read->num_values * 2))))) { + CAM_ERR(CAM_UTIL, + "Integer Overflow bytes_written: [%u] num_values: [%u]", + dump_out_buf->bytes_written, reg_read->num_values); + rc = -EOVERFLOW; + goto end; + } + + if ((cmd_buf_end - (uintptr_t)dump_out_buf) <= + (uintptr_t)(sizeof(struct cam_reg_dump_out_buffer) + - sizeof(uint32_t) + dump_out_buf->bytes_written + + (reg_read->num_values * 2 * sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, + "Insufficient space in out buffer num_values: [%d] cmd_buf_end: %pK dump_out_buf: %pK", + reg_read->num_values, cmd_buf_end, + (uintptr_t)dump_out_buf); + rc = -EINVAL; + goto end; + } + + write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); + for (i = 0; i < reg_read->num_values; i++) { + if ((reg_read->offset + (i * sizeof(uint32_t))) > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + (reg_read->offset + (i * sizeof(uint32_t))), + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + dump_out_buf->dump_data[write_idx++] = reg_read->offset + + (i * sizeof(uint32_t)); + dump_out_buf->dump_data[write_idx++] = + cam_soc_util_r(soc_info, base_idx, + (reg_read->offset + (i * sizeof(uint32_t)))); + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + +end: + return rc; +} + +static int cam_soc_util_dump_dmi_reg_range( + struct cam_hw_soc_info *soc_info, + struct cam_dmi_read_desc *dmi_read, uint32_t base_idx, + struct cam_reg_dump_out_buffer *dump_out_buf, uintptr_t cmd_buf_end) +{ + int i = 0, rc = 0; + uint32_t write_idx = 0; + + if (!soc_info || !dump_out_buf || !dmi_read || !cmd_buf_end) { + CAM_ERR(CAM_UTIL, + "Invalid input args soc_info: %pK, dump_out_buffer: %pK", + soc_info, dump_out_buf); + rc = -EINVAL; + goto end; + } + + if (dmi_read->num_pre_writes > CAM_REG_DUMP_DMI_CONFIG_MAX || + dmi_read->num_post_writes > CAM_REG_DUMP_DMI_CONFIG_MAX) { + CAM_ERR(CAM_UTIL, + "Invalid number of requested writes, pre: %d post: %d", + dmi_read->num_pre_writes, dmi_read->num_post_writes); + rc = -EINVAL; + goto end; + } + + if ((dmi_read->num_pre_writes + dmi_read->dmi_data_read.num_values) + && ((dmi_read->num_pre_writes > U32_MAX / 2) || + (dmi_read->dmi_data_read.num_values > U32_MAX / 2) || + ((dmi_read->num_pre_writes * 2) > U32_MAX - + (dmi_read->dmi_data_read.num_values * 2)) || + (sizeof(uint32_t) > ((U32_MAX - + sizeof(struct cam_reg_dump_out_buffer) - + dump_out_buf->bytes_written) / ((dmi_read->num_pre_writes + + dmi_read->dmi_data_read.num_values) * 2))))) { + CAM_ERR(CAM_UTIL, + "Integer Overflow bytes_written: [%u] num_pre_writes: [%u] num_values: [%u]", + dump_out_buf->bytes_written, dmi_read->num_pre_writes, + dmi_read->dmi_data_read.num_values); + rc = -EOVERFLOW; + goto end; + } + + if ((cmd_buf_end - (uintptr_t)dump_out_buf) <= + (uintptr_t)( + sizeof(struct cam_reg_dump_out_buffer) - sizeof(uint32_t) + + (dump_out_buf->bytes_written + + (dmi_read->num_pre_writes * 2 * sizeof(uint32_t)) + + (dmi_read->dmi_data_read.num_values * 2 * + sizeof(uint32_t))))) { + CAM_ERR(CAM_UTIL, + "Insufficient space in out buffer num_read_val: [%d] num_write_val: [%d] cmd_buf_end: %pK dump_out_buf: %pK", + dmi_read->dmi_data_read.num_values, + dmi_read->num_pre_writes, cmd_buf_end, + (uintptr_t)dump_out_buf); + rc = -EINVAL; + goto end; + } + + write_idx = dump_out_buf->bytes_written / sizeof(uint32_t); + for (i = 0; i < dmi_read->num_pre_writes; i++) { + if (dmi_read->pre_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->pre_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->pre_read_config[i].offset, + dmi_read->pre_read_config[i].value); + dump_out_buf->dump_data[write_idx++] = + dmi_read->pre_read_config[i].offset; + dump_out_buf->dump_data[write_idx++] = + dmi_read->pre_read_config[i].value; + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + if (dmi_read->dmi_data_read.offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->dmi_data_read.offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < dmi_read->dmi_data_read.num_values; i++) { + dump_out_buf->dump_data[write_idx++] = + dmi_read->dmi_data_read.offset; + dump_out_buf->dump_data[write_idx++] = + cam_soc_util_r_mb(soc_info, base_idx, + dmi_read->dmi_data_read.offset); + dump_out_buf->bytes_written += (2 * sizeof(uint32_t)); + } + + for (i = 0; i < dmi_read->num_post_writes; i++) { + if (dmi_read->post_read_config[i].offset > + (uint32_t)soc_info->reg_map[base_idx].size) { + CAM_ERR(CAM_UTIL, + "Reg offset out of range, offset: 0x%X reg_map size: 0x%X", + dmi_read->post_read_config[i].offset, + (uint32_t)soc_info->reg_map[base_idx].size); + rc = -EINVAL; + goto end; + } + + cam_soc_util_w_mb(soc_info, base_idx, + dmi_read->post_read_config[i].offset, + dmi_read->post_read_config[i].value); + } + +end: + return rc; +} + +int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, + struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, + cam_soc_util_regspace_data_cb reg_data_cb) +{ + int rc = 0, i, j; + uintptr_t cpu_addr = 0; + uintptr_t cmd_buf_start = 0; + uintptr_t cmd_in_data_end = 0; + uintptr_t cmd_buf_end = 0; + uint32_t reg_base_type = 0; + size_t buf_size = 0, remain_len = 0; + struct cam_reg_dump_input_info *reg_input_info = NULL; + struct cam_reg_dump_desc *reg_dump_desc = NULL; + struct cam_reg_dump_out_buffer *dump_out_buf = NULL; + struct cam_reg_read_info *reg_read_info = NULL; + struct cam_hw_soc_info *soc_info; + uint32_t reg_base_idx = 0; + + if (!ctx || !cmd_desc || !reg_data_cb) { + CAM_ERR(CAM_UTIL, "Invalid args to reg dump [%pK] [%pK]", + cmd_desc, reg_data_cb); + return -EINVAL; + } + + if (!cmd_desc->length || !cmd_desc->size) { + CAM_ERR(CAM_UTIL, "Invalid cmd buf size %d %d", + cmd_desc->length, cmd_desc->size); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &cpu_addr, &buf_size); + if (rc || !cpu_addr || (buf_size == 0)) { + CAM_ERR(CAM_UTIL, "Failed in Get cpu addr, rc=%d, cpu_addr=%pK", + rc, (void *)cpu_addr); + goto end; + } + + CAM_DBG(CAM_UTIL, "Get cpu buf success req_id: %llu buf_size: %zu", + req_id, buf_size); + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_desc->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_desc->offset); + rc = -EINVAL; + goto end; + } + + remain_len = buf_size - (size_t)cmd_desc->offset; + if ((remain_len < (size_t)cmd_desc->size) || (cmd_desc->size < + cmd_desc->length)) { + CAM_ERR(CAM_UTIL, + "Invalid params for cmd buf len: %zu size: %zu remain_len: %zu", + (size_t)cmd_desc->length, (size_t)cmd_desc->length, + remain_len); + rc = -EINVAL; + goto end; + } + + cmd_buf_start = cpu_addr + (uintptr_t)cmd_desc->offset; + cmd_in_data_end = cmd_buf_start + (uintptr_t)cmd_desc->length; + cmd_buf_end = cmd_buf_start + (uintptr_t)cmd_desc->size; + if ((cmd_buf_end <= cmd_buf_start) || + (cmd_in_data_end <= cmd_buf_start)) { + CAM_ERR(CAM_UTIL, + "Invalid length or size for cmd buf: [%zu] [%zu]", + (size_t)cmd_desc->length, (size_t)cmd_desc->size); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_UTIL, + "Buffer params start [%pK] input_end [%pK] buf_end [%pK]", + cmd_buf_start, cmd_in_data_end, cmd_buf_end); + reg_input_info = (struct cam_reg_dump_input_info *) cmd_buf_start; + if ((reg_input_info->num_dump_sets > 1) && (sizeof(uint32_t) > + ((U32_MAX - sizeof(struct cam_reg_dump_input_info)) / + (reg_input_info->num_dump_sets - 1)))) { + CAM_ERR(CAM_UTIL, + "Integer Overflow req_id: [%llu] num_dump_sets: [%u]", + req_id, reg_input_info->num_dump_sets); + rc = -EOVERFLOW; + goto end; + } + + if ((!reg_input_info->num_dump_sets) || + ((cmd_in_data_end - cmd_buf_start) <= (uintptr_t) + (sizeof(struct cam_reg_dump_input_info) + + ((reg_input_info->num_dump_sets - 1) * sizeof(uint32_t))))) { + CAM_ERR(CAM_UTIL, + "Invalid number of dump sets, req_id: [%llu] num_dump_sets: [%u]", + req_id, reg_input_info->num_dump_sets); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_UTIL, + "reg_input_info req_id: %llu ctx %pK num_dump_sets: %d", + req_id, ctx, reg_input_info->num_dump_sets); + for (i = 0; i < reg_input_info->num_dump_sets; i++) { + if ((cmd_in_data_end - cmd_buf_start) <= (uintptr_t) + reg_input_info->dump_set_offsets[i]) { + CAM_ERR(CAM_UTIL, + "Invalid dump set offset: [%pK], cmd_buf_start: [%pK] cmd_in_data_end: [%pK]", + (uintptr_t)reg_input_info->dump_set_offsets[i], + cmd_buf_start, cmd_in_data_end); + rc = -EINVAL; + goto end; + } + + reg_dump_desc = (struct cam_reg_dump_desc *) + (cmd_buf_start + + (uintptr_t)reg_input_info->dump_set_offsets[i]); + if ((reg_dump_desc->num_read_range > 1) && + (sizeof(struct cam_reg_read_info) > ((U32_MAX - + sizeof(struct cam_reg_dump_desc)) / + (reg_dump_desc->num_read_range - 1)))) { + CAM_ERR(CAM_UTIL, + "Integer Overflow req_id: [%llu] num_read_range: [%u]", + req_id, reg_dump_desc->num_read_range); + rc = -EOVERFLOW; + goto end; + } + + if ((!reg_dump_desc->num_read_range) || + ((cmd_in_data_end - (uintptr_t)reg_dump_desc) <= + (uintptr_t)(sizeof(struct cam_reg_dump_desc) + + ((reg_dump_desc->num_read_range - 1) * + sizeof(struct cam_reg_read_info))))) { + CAM_ERR(CAM_UTIL, + "Invalid number of read ranges, req_id: [%llu] num_read_range: [%d]", + req_id, reg_dump_desc->num_read_range); + rc = -EINVAL; + goto end; + } + + if ((cmd_buf_end - cmd_buf_start) <= (uintptr_t) + (reg_dump_desc->dump_buffer_offset + + sizeof(struct cam_reg_dump_out_buffer))) { + CAM_ERR(CAM_UTIL, + "Invalid out buffer offset: [%pK], cmd_buf_start: [%pK] cmd_buf_end: [%pK]", + (uintptr_t)reg_dump_desc->dump_buffer_offset, + cmd_buf_start, cmd_buf_end); + rc = -EINVAL; + goto end; + } + + dump_out_buf = (struct cam_reg_dump_out_buffer *) + (cmd_buf_start + + (uintptr_t)reg_dump_desc->dump_buffer_offset); + dump_out_buf->req_id = req_id; + dump_out_buf->bytes_written = 0; + + reg_base_type = reg_dump_desc->reg_base_type; + if (reg_base_type == 0 || reg_base_type > + CAM_REG_DUMP_BASE_TYPE_CAMNOC) { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump base type: %d", + reg_base_type); + rc = -EINVAL; + goto end; + } + + rc = reg_data_cb(reg_base_type, ctx, &soc_info, ®_base_idx); + if (rc || !soc_info) { + CAM_ERR(CAM_UTIL, + "Reg space data callback failed rc: %d soc_info: [%pK]", + rc, soc_info); + rc = -EINVAL; + goto end; + } + + if (reg_base_idx > soc_info->num_reg_map) { + CAM_ERR(CAM_UTIL, + "Invalid reg base idx: %d num reg map: %d", + reg_base_idx, soc_info->num_reg_map); + rc = -EINVAL; + goto end; + } + + CAM_DBG(CAM_UTIL, + "Reg data callback success req_id: %llu base_type: %d base_idx: %d num_read_range: %d", + req_id, reg_base_type, reg_base_idx, + reg_dump_desc->num_read_range); + for (j = 0; j < reg_dump_desc->num_read_range; j++) { + CAM_DBG(CAM_UTIL, + "Number of bytes written to cmd buffer: %u req_id: %llu", + dump_out_buf->bytes_written, req_id); + reg_read_info = ®_dump_desc->read_range[j]; + if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_CONT_RANGE) { + rc = cam_soc_util_dump_cont_reg_range(soc_info, + ®_read_info->reg_read, reg_base_idx, + dump_out_buf, cmd_buf_end); + } else if (reg_read_info->type == + CAM_REG_DUMP_READ_TYPE_DMI) { + rc = cam_soc_util_dump_dmi_reg_range(soc_info, + ®_read_info->dmi_read, reg_base_idx, + dump_out_buf, cmd_buf_end); + } else { + CAM_ERR(CAM_UTIL, + "Invalid Reg dump read type: %d", + reg_read_info->type); + rc = -EINVAL; + goto end; + } + + if (rc) { + CAM_ERR(CAM_UTIL, + "Reg range read failed rc: %d reg_base_idx: %d dump_out_buf: %pK", + rc, reg_base_idx, dump_out_buf); + goto end; + } + } + } + +end: + return rc; +} diff --git a/techpack/camera/drivers/cam_utils/cam_soc_util.h b/techpack/camera/drivers/cam_utils/cam_soc_util.h new file mode 100755 index 0000000000000000000000000000000000000000..cc82bd67cd67fcbbb1cb4b31b77d14cdc37d9774 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_soc_util.h @@ -0,0 +1,652 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CAM_SOC_UTIL_H_ +#define _CAM_SOC_UTIL_H_ + +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> +#include <linux/debugfs.h> +#include <linux/of_fdt.h> + +#include "cam_io_util.h" +#include <uapi/media/cam_defs.h> + +#define NO_SET_RATE -1 +#define INIT_RATE -2 + +/* maximum number of device block */ +#define CAM_SOC_MAX_BLOCK 7 + +/* maximum number of device base */ +#define CAM_SOC_MAX_BASE CAM_SOC_MAX_BLOCK + +/* maximum number of device regulator */ +#define CAM_SOC_MAX_REGULATOR 10 /*sensor max regulator + af*/ + +/* maximum number of device clock */ +#define CAM_SOC_MAX_CLK 32 + +/* DDR device types */ +#define DDR_TYPE_LPDDR4 6 +#define DDR_TYPE_LPDDR4X 7 +#define DDR_TYPE_LPDDR5 8 +#define DDR_TYPE_LPDDR5X 9 + +/** + * enum cam_vote_level - Enum for voting level + * + * @CAM_SUSPEND_VOTE : Suspend vote + * @CAM_MINSVS_VOTE : Min SVS vote + * @CAM_LOWSVS_VOTE : Low SVS vote + * @CAM_SVS_VOTE : SVS vote + * @CAM_SVSL1_VOTE : SVS Plus vote + * @CAM_NOMINAL_VOTE : Nominal vote + * @CAM_NOMINALL1_VOTE: Nominal plus vote + * @CAM_TURBO_VOTE : Turbo vote + * @CAM_MAX_VOTE : Max voting level, This is invalid level. + */ +enum cam_vote_level { + CAM_SUSPEND_VOTE, + CAM_MINSVS_VOTE, + CAM_LOWSVS_VOTE, + CAM_SVS_VOTE, + CAM_SVSL1_VOTE, + CAM_NOMINAL_VOTE, + CAM_NOMINALL1_VOTE, + CAM_TURBO_VOTE, + CAM_MAX_VOTE, +}; + +/* pinctrl states */ +#define CAM_SOC_PINCTRL_STATE_SLEEP "cam_suspend" +#define CAM_SOC_PINCTRL_STATE_DEFAULT "cam_default" + +/** + * struct cam_soc_reg_map: Information about the mapped register space + * + * @mem_base: Starting location of MAPPED register space + * @mem_cam_base: Starting offset of this register space compared + * to ENTIRE Camera register space + * @size: Size of register space + **/ +struct cam_soc_reg_map { + void __iomem *mem_base; + uint32_t mem_cam_base; + resource_size_t size; +}; + +/** + * struct cam_soc_pinctrl_info: Information about pinctrl data + * + * @pinctrl: pintrl object + * @gpio_state_active: default pinctrl state + * @gpio_state_suspend suspend state of pinctrl + **/ +struct cam_soc_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; +}; + +/** + * struct cam_soc_gpio_data: Information about the gpio pins + * + * @cam_gpio_common_tbl: It is list of al the gpios present in gpios node + * @cam_gpio_common_tbl_size: It is equal to number of gpios prsent in + * gpios node in DTSI + * @cam_gpio_req_tbl It is list of al the requesetd gpios + * @cam_gpio_req_tbl_size: It is size of requested gpios + **/ +struct cam_soc_gpio_data { + struct gpio *cam_gpio_common_tbl; + uint8_t cam_gpio_common_tbl_size; + struct gpio *cam_gpio_req_tbl; + uint8_t cam_gpio_req_tbl_size; +}; + +/** + * struct cam_hw_soc_info: Soc information pertaining to specific instance of + * Camera hardware driver module + * + * @pdev: Platform device pointer + * @device: Device pointer + * @hw_version: Camera device version + * @index: Instance id for the camera device + * @dev_name: Device Name + * @irq_name: Name of the irq associated with the device + * @irq_line: Irq resource + * @irq_data: Private data that is passed when IRQ is requested + * @compatible: Compatible string associated with the device + * @num_mem_block: Number of entry in the "reg-names" + * @mem_block_name: Array of the reg block name + * @mem_block_cam_base: Array of offset of this register space compared + * to ENTIRE Camera register space + * @mem_block: Associated resource structs + * @reg_map: Array of Mapped register info for the "reg-names" + * @num_reg_map: Number of mapped register space associated + * with mem_block. num_reg_map = num_mem_block in + * most cases + * @reserve_mem: Whether to reserve memory for Mem blocks + * @num_rgltr: Number of regulators + * @rgltr_name: Array of regulator names + * @rgltr_ctrl_support: Whether regulator control is supported + * @rgltr_min_volt: Array of minimum regulator voltage + * @rgltr_max_volt: Array of maximum regulator voltage + * @rgltr_op_mode: Array of regulator operation mode + * @rgltr_type: Array of regulator names + * @rgltr: Array of associated regulator resources + * @rgltr_delay: Array of regulator delay values + * @num_clk: Number of clocks + * @clk_name: Array of clock names + * @clk: Array of associated clock resources + * @clk_rate: 2D array of clock rates representing clock rate + * values at different vote levels + * @prev_clk_level Last vote level + * @src_clk_idx: Source clock index that is rate-controllable + * @clk_level_valid: Indicates whether corresponding level is valid + * @scl_clk_count: Number of scalable clocks present + * @scl_clk_idx: Index of scalable clocks + * @gpio_data: Pointer to gpio info + * @pinctrl_info: Pointer to pinctrl info + * @dentry: Debugfs entry + * @clk_level_override: Clk level set from debugfs + * @clk_control: Enable/disable clk rate control through debugfs + * @cam_cx_ipeak_enable cx-ipeak enable/disable flag + * @cam_cx_ipeak_bit cx-ipeak mask for driver + * @soc_private: Soc private data + */ +struct cam_hw_soc_info { + struct platform_device *pdev; + struct device *dev; + uint32_t hw_version; + uint32_t index; + const char *dev_name; + const char *irq_name; + struct resource *irq_line; + void *irq_data; + const char *compatible; + + uint32_t num_mem_block; + const char *mem_block_name[CAM_SOC_MAX_BLOCK]; + uint32_t mem_block_cam_base[CAM_SOC_MAX_BLOCK]; + struct resource *mem_block[CAM_SOC_MAX_BLOCK]; + struct cam_soc_reg_map reg_map[CAM_SOC_MAX_BASE]; + uint32_t num_reg_map; + uint32_t reserve_mem; + + uint32_t num_rgltr; + const char *rgltr_name[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_ctrl_support; + uint32_t rgltr_min_volt[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_max_volt[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_op_mode[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_type[CAM_SOC_MAX_REGULATOR]; + struct regulator *rgltr[CAM_SOC_MAX_REGULATOR]; + uint32_t rgltr_delay[CAM_SOC_MAX_REGULATOR]; + + uint32_t use_shared_clk; + uint32_t num_clk; + const char *clk_name[CAM_SOC_MAX_CLK]; + struct clk *clk[CAM_SOC_MAX_CLK]; + int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK]; + int32_t prev_clk_level; + int32_t src_clk_idx; + bool clk_level_valid[CAM_MAX_VOTE]; + int32_t scl_clk_count; + int32_t scl_clk_idx[CAM_SOC_MAX_CLK]; + + struct cam_soc_gpio_data *gpio_data; + struct cam_soc_pinctrl_info pinctrl_info; + + struct dentry *dentry; + uint32_t clk_level_override; + bool clk_control_enable; + bool cam_cx_ipeak_enable; + int32_t cam_cx_ipeak_bit; + + void *soc_private; +}; + +/* + * CAM_SOC_GET_REG_MAP_START + * + * @brief: This MACRO will get the mapped starting address + * where the register space can be accessed + * + * @__soc_info: Device soc information + * @__base_index: Index of register space in the HW block + * + * @return: Returns a pointer to the mapped register memory + */ +#define CAM_SOC_GET_REG_MAP_START(__soc_info, __base_index) \ + ((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \ + NULL : __soc_info->reg_map[__base_index].mem_base) + +/* + * CAM_SOC_GET_REG_MAP_CAM_BASE + * + * @brief: This MACRO will get the cam_base of the + * register space + * + * @__soc_info: Device soc information + * @__base_index: Index of register space in the HW block + * + * @return: Returns an int32_t value. + * Failure: -1 + * Success: Starting offset of register space compared + * to entire Camera Register Map + */ +#define CAM_SOC_GET_REG_MAP_CAM_BASE(__soc_info, __base_index) \ + ((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \ + -1 : __soc_info->reg_map[__base_index].mem_cam_base) + +/* + * CAM_SOC_GET_REG_MAP_SIZE + * + * @brief: This MACRO will get the size of the mapped + * register space + * + * @__soc_info: Device soc information + * @__base_index: Index of register space in the HW block + * + * @return: Returns a uint32_t value. + * Failure: 0 + * Success: Non-zero size of mapped register space + */ +#define CAM_SOC_GET_REG_MAP_SIZE(__soc_info, __base_index) \ + ((!__soc_info || __base_index >= __soc_info->num_reg_map) ? \ + 0 : __soc_info->reg_map[__base_index].size) + +/** + * cam_soc_util_get_level_from_string() + * + * @brief: Get the associated vote level for the input string + * + * @string: Input string to compare with. + * @level: Vote level corresponds to input string. + * + * @return: Success or failure + */ +int cam_soc_util_get_level_from_string(const char *string, + enum cam_vote_level *level); + +/** + * cam_soc_util_get_dt_properties() + * + * @brief: Parse the DT and populate the common properties that + * are part of the soc_info structure - register map, + * clocks, regulators, irq, etc. + * + * @soc_info: Device soc struct to be populated + * + * @return: Success or failure + */ +int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_request_platform_resource() + * + * @brief: Request regulator, irq, and clock resources + * + * @soc_info: Device soc information + * @handler: Irq handler function pointer + * @irq_data: Irq handler function CB data + * + * @return: Success or failure + */ +int cam_soc_util_request_platform_resource(struct cam_hw_soc_info *soc_info, + irq_handler_t handler, void *irq_data); + +/** + * cam_soc_util_release_platform_resource() + * + * @brief: Release regulator, irq, and clock resources + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_enable_platform_resource() + * + * @brief: Enable regulator, irq resources + * + * @soc_info: Device soc information + * @enable_clocks: Boolean flag: + * TRUE: Enable all clocks in soc_info Now. + * False: Don't enable clocks Now. Driver will + * enable independently. + * @clk_level: Clock level to be applied. + * Applicable only if enable_clocks is true + * Valid range : 0 to (CAM_MAX_VOTE - 1) + * @enable_irq: Boolean flag: + * TRUE: Enable IRQ in soc_info Now. + * False: Don't enable IRQ Now. Driver will + * enable independently. + * + * @return: Success or failure + */ +int cam_soc_util_enable_platform_resource(struct cam_hw_soc_info *soc_info, + bool enable_clocks, enum cam_vote_level clk_level, bool enable_irq); + +/** + * cam_soc_util_disable_platform_resource() + * + * @brief: Disable regulator, irq resources + * + * @soc_info: Device soc information + * @disable_irq: Boolean flag: + * TRUE: Disable IRQ in soc_info Now. + * False: Don't disable IRQ Now. Driver will + * disable independently. + * + * @return: Success or failure + */ +int cam_soc_util_disable_platform_resource(struct cam_hw_soc_info *soc_info, + bool disable_clocks, bool disable_irq); + +/** + * cam_soc_util_get_clk_round_rate() + * + * @brief: Get the rounded clock rate for the given clock's + * clock rate value + * + * @soc_info: Device soc information + * @clk_index: Clock index in soc_info for which round rate is needed + * @clk_rate: Input clock rate for which rounded rate is needed + * + * @return: Rounded clock rate + */ +long cam_soc_util_get_clk_round_rate(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long clk_rate); + +/** + * cam_soc_util_set_src_clk_rate() + * + * @brief: Set the rate on the source clock. + * + * @soc_info: Device soc information + * @clk_rate: Clock rate associated with the src clk + * + * @return: success or failure + */ +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, + int64_t clk_rate); + +/** + * cam_soc_util_get_option_clk_by_name() + * + * @brief: Get reference to optional clk using name + * + * @soc_info: Device soc information + * @clk_name: Name of clock to find reference for + * @clk: Clock reference pointer to be filled if Success + * @clk_index: Clk index in the option clk array to be returned + * @clk_rate: Clk rate in the option clk array + * + * @return: 0: Success + * Negative: Failure + */ +int cam_soc_util_get_option_clk_by_name(struct cam_hw_soc_info *soc_info, + const char *clk_name, struct clk **clk, int32_t *clk_index, + int32_t *clk_rate); + +/** + * cam_soc_util_clk_put() + * + * @brief: Put clock specified in params + * + * @clk: Reference to the Clock that needs to be put + * + * @return: Success or failure + */ +int cam_soc_util_clk_put(struct clk **clk); + +/** + * cam_soc_util_clk_enable() + * + * @brief: Enable clock specified in params + * + * @clk: Clock that needs to be turned ON + * @clk_name: Clocks name associated with clk + * @clk_rate: Clocks rate associated with clk + * + * @return: Success or failure + */ +int cam_soc_util_clk_enable(struct clk *clk, const char *clk_name, + int32_t clk_rate); + +/** + * cam_soc_util_set_clk_rate_level() + * + * @brief: Apply clock rates for the requested level. + * This applies the new requested level for all + * the clocks listed in DT based on their values. + * + * @soc_info: Device soc information + * @clk_level: Clock level number to set + * + * @return: Success or failure + */ +int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level); + +/** + * cam_soc_util_clk_disable() + * + * @brief: Disable clock specified in params + * + * @clk: Clock that needs to be turned OFF + * @clk_name: Clocks name associated with clk + * + * @return: Success or failure + */ +int cam_soc_util_clk_disable(struct clk *clk, const char *clk_name); + +/** + * cam_soc_util_irq_enable() + * + * @brief: Enable IRQ in SOC + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +int cam_soc_util_irq_enable(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_irq_disable() + * + * @brief: Disable IRQ in SOC + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +int cam_soc_util_irq_disable(struct cam_hw_soc_info *soc_info); + +/** + * cam_soc_util_regulator_enable() + * + * @brief: Enable single regulator + * + * @rgltr Regulator that needs to be turned ON + * @rgltr_name Associated Regulator name + * @rgltr_min_volt: Requested minimum volatage + * @rgltr_max_volt: Requested maximum volatage + * @rgltr_op_mode: Requested Load + * @rgltr_delay: Requested delay needed aaftre enabling regulator + * + * @return: Success or failure + */ +int cam_soc_util_regulator_enable(struct regulator *rgltr, + const char *rgltr_name, + uint32_t rgltr_min_volt, uint32_t rgltr_max_volt, + uint32_t rgltr_op_mode, uint32_t rgltr_delay); + +/** + * cam_soc_util_regulator_enable() + * + * @brief: Disable single regulator + * + * @rgltr Regulator that needs to be turned ON + * @rgltr_name Associated Regulator name + * @rgltr_min_volt: Requested minimum volatage + * @rgltr_max_volt: Requested maximum volatage + * @rgltr_op_mode: Requested Load + * @rgltr_delay: Requested delay needed aaftre enabling regulator + * + * @return: Success or failure + */ +int cam_soc_util_regulator_disable(struct regulator *rgltr, + const char *rgltr_name, + uint32_t rgltr_min_volt, uint32_t rgltr_max_volt, + uint32_t rgltr_op_mode, uint32_t rgltr_delay); + + +/** + * cam_soc_util_w() + * + * @brief: Camera SOC util for register write + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * @data: Value to be written + * + * @return: Success or Failure + */ +static inline int cam_soc_util_w(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, uint32_t data) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return -EINVAL; + return cam_io_w(data, + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_w_mb() + * + * @brief: Camera SOC util for register write with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call wmb() independently in the caller. + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * @data: Value to be written + * + * @return: Success or Failure + */ +static inline int cam_soc_util_w_mb(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, uint32_t data) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return -EINVAL; + return cam_io_w_mb(data, + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_r() + * + * @brief: Camera SOC util for register read + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * + * @return: Value read from the register address + */ +static inline uint32_t cam_soc_util_r(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return 0; + return cam_io_r( + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_r_mb() + * + * @brief: Camera SOC util for register read with memory barrier. + * Memory Barrier is only before the write to ensure the + * order. If need to ensure this write is also flushed + * call rmb() independently in the caller. + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Offset of register to be read + * + * @return: Value read from the register address + */ +static inline uint32_t cam_soc_util_r_mb(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset) +{ + if (!CAM_SOC_GET_REG_MAP_START(soc_info, base_index)) + return 0; + return cam_io_r_mb( + CAM_SOC_GET_REG_MAP_START(soc_info, base_index) + offset); +} + +/** + * cam_soc_util_reg_dump() + * + * @brief: Camera SOC util for dumping a range of register + * + * @soc_info: Device soc information + * @base_index: Index of register space in the HW block + * @offset: Start register offset for the dump + * @size: Size specifying the range for dump + * + * @return: Success or Failure + */ +int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, + uint32_t base_index, uint32_t offset, int size); + +void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info); + +int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, + enum cam_vote_level clk_level); + +int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int64_t clk_rate, int clk_idx, int32_t *clk_lvl); + +/* Callback to get reg space data for specific HW */ +typedef int (*cam_soc_util_regspace_data_cb)(uint32_t reg_base_type, + void *ctx, struct cam_hw_soc_info **soc_info_ptr, + uint32_t *reg_base_idx); + +/** + * cam_soc_util_reg_dump_to_cmd_buf() + * + * @brief: Camera SOC util for dumping sets of register ranges to + * to command buffer + * + * @ctx: Context info from specific hardware manager + * @cmd_desc: Command buffer descriptor + * @req_id: Last applied req id for which reg dump is required + * @reg_data_cb: Callback function to get reg space info based on type + * in command buffer + * + * @return: Success or Failure + */ +int cam_soc_util_reg_dump_to_cmd_buf(void *ctx, + struct cam_cmd_buf_desc *cmd_desc, uint64_t req_id, + cam_soc_util_regspace_data_cb reg_data_cb); + +#endif /* _CAM_SOC_UTIL_H_ */ diff --git a/techpack/camera/drivers/cam_utils/cam_trace.c b/techpack/camera/drivers/cam_utils/cam_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..9b45091b4b85f1cc28fd8cdaefb6cb938cade09b --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_trace.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +/* Instantiate tracepoints */ +#define CREATE_TRACE_POINTS +#include "cam_trace.h" diff --git a/techpack/camera/drivers/cam_utils/cam_trace.h b/techpack/camera/drivers/cam_utils/cam_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..838997590771645842bd633d82e7bbec894b7c29 --- /dev/null +++ b/techpack/camera/drivers/cam_utils/cam_trace.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#if !defined(_CAM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _CAM_TRACE_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM camera +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE ../../techpack/camera/drivers/cam_utils/cam_trace + +#include <linux/tracepoint.h> +#include <media/cam_req_mgr.h> +#include "cam_req_mgr_core.h" +#include "cam_req_mgr_interface.h" +#include "cam_context.h" + +TRACE_EVENT(cam_context_state, + TP_PROTO(const char *name, struct cam_context *ctx), + TP_ARGS(name, ctx), + TP_STRUCT__entry( + __field(void*, ctx) + __field(uint32_t, state) + __string(name, name) + ), + TP_fast_assign( + __entry->ctx = ctx; + __entry->state = ctx->state; + __assign_str(name, name); + ), + TP_printk( + "%s: State ctx=%p ctx_state=%u", + __get_str(name), __entry->ctx, __entry->state + ) +); + +TRACE_EVENT(cam_isp_activated_irq, + TP_PROTO(struct cam_context *ctx, unsigned int substate, + unsigned int event, uint64_t timestamp), + TP_ARGS(ctx, substate, event, timestamp), + TP_STRUCT__entry( + __field(void*, ctx) + __field(uint32_t, state) + __field(uint32_t, substate) + __field(uint32_t, event) + __field(uint64_t, ts) + ), + TP_fast_assign( + __entry->ctx = ctx; + __entry->state = ctx->state; + __entry->substate = substate; + __entry->event = event; + __entry->ts = timestamp; + ), + TP_printk( + "ISP: IRQ ctx=%p ctx_state=%u substate=%u event=%u ts=%llu", + __entry->ctx, __entry->state, __entry->substate, + __entry->event, __entry->ts + ) +); + +TRACE_EVENT(cam_icp_fw_dbg, + TP_PROTO(char *dbg_message, uint64_t timestamp), + TP_ARGS(dbg_message, timestamp), + TP_STRUCT__entry( + __string(dbg_message, dbg_message) + __field(uint64_t, timestamp) + ), + TP_fast_assign( + __assign_str(dbg_message, dbg_message); + __entry->timestamp = timestamp; + ), + TP_printk( + "%llu %s: ", + __entry->timestamp, __get_str(dbg_message) + ) +); + +TRACE_EVENT(cam_buf_done, + TP_PROTO(const char *ctx_type, struct cam_context *ctx, + struct cam_ctx_request *req), + TP_ARGS(ctx_type, ctx, req), + TP_STRUCT__entry( + __string(ctx_type, ctx_type) + __field(void*, ctx) + __field(uint64_t, request) + ), + TP_fast_assign( + __assign_str(ctx_type, ctx_type); + __entry->ctx = ctx; + __entry->request = req->request_id; + ), + TP_printk( + "%5s: BufDone ctx=%p request=%llu", + __get_str(ctx_type), __entry->ctx, __entry->request + ) +); + +TRACE_EVENT(cam_apply_req, + TP_PROTO(const char *entity, uint64_t req_id), + TP_ARGS(entity, req_id), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint64_t, req_id) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->req_id = req_id; + ), + TP_printk( + "%8s: ApplyRequest request=%llu", + __get_str(entity), __entry->req_id + ) +); + +TRACE_EVENT(cam_flush_req, + TP_PROTO(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_flush_info *info), + TP_ARGS(link, info), + TP_STRUCT__entry( + __field(uint32_t, type) + __field(int64_t, req_id) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __entry->type = info->flush_type; + __entry->req_id = info->req_id; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "FlushRequest type=%u request=%llu link=%pK session=%pK", + __entry->type, __entry->req_id, __entry->link, + __entry->session + ) +); + +TRACE_EVENT(cam_req_mgr_connect_device, + TP_PROTO(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_device_info *info), + TP_ARGS(link, info), + TP_STRUCT__entry( + __string(name, info->name) + __field(uint32_t, id) + __field(uint32_t, delay) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __assign_str(name, info->name); + __entry->id = info->dev_id; + __entry->delay = info->p_delay; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "ReqMgr Connect name=%s id=%u pd=%d link=%pK session=%pK", + __get_str(name), __entry->id, __entry->delay, + __entry->link, __entry->session + ) +); + +TRACE_EVENT(cam_req_mgr_apply_request, + TP_PROTO(struct cam_req_mgr_core_link *link, + struct cam_req_mgr_apply_request *req, + struct cam_req_mgr_connected_device *dev), + TP_ARGS(link, req, dev), + TP_STRUCT__entry( + __string(name, dev->dev_info.name) + __field(uint32_t, dev_id) + __field(uint64_t, req_id) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __assign_str(name, dev->dev_info.name); + __entry->dev_id = dev->dev_info.dev_id; + __entry->req_id = req->request_id; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "ReqMgr ApplyRequest devname=%s devid=%u request=%lld link=%pK session=%pK", + __get_str(name), __entry->dev_id, __entry->req_id, + __entry->link, __entry->session + ) +); + +TRACE_EVENT(cam_req_mgr_add_req, + TP_PROTO(struct cam_req_mgr_core_link *link, + int idx, struct cam_req_mgr_add_request *add_req, + struct cam_req_mgr_req_tbl *tbl, + struct cam_req_mgr_connected_device *dev), + TP_ARGS(link, idx, add_req, tbl, dev), + TP_STRUCT__entry( + __string(name, dev->dev_info.name) + __field(uint32_t, dev_id) + __field(uint64_t, req_id) + __field(uint32_t, slot_id) + __field(uint32_t, delay) + __field(uint32_t, readymap) + __field(uint32_t, devicemap) + __field(void*, link) + __field(void*, session) + ), + TP_fast_assign( + __assign_str(name, dev->dev_info.name); + __entry->dev_id = dev->dev_info.dev_id; + __entry->req_id = add_req->req_id; + __entry->slot_id = idx; + __entry->delay = tbl->pd; + __entry->readymap = tbl->slot[idx].req_ready_map; + __entry->devicemap = tbl->dev_mask; + __entry->link = link; + __entry->session = link->parent; + ), + TP_printk( + "ReqMgr AddRequest devname=%s devid=%d request=%lld slot=%d pd=%d readymap=%x devicemap=%d link=%pK session=%pK", + __get_str(name), __entry->dev_id, __entry->req_id, + __entry->slot_id, __entry->delay, __entry->readymap, + __entry->devicemap, __entry->link, __entry->session + ) +); + +TRACE_EVENT(cam_submit_to_hw, + TP_PROTO(const char *entity, uint64_t req_id), + TP_ARGS(entity, req_id), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint64_t, req_id) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->req_id = req_id; + ), + TP_printk( + "%8s: submit request=%llu", + __get_str(entity), __entry->req_id + ) +); + +TRACE_EVENT(cam_irq_activated, + TP_PROTO(const char *entity, uint32_t irq_type), + TP_ARGS(entity, irq_type), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint32_t, irq_type) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->irq_type = irq_type; + ), + TP_printk( + "%8s: got irq type=%d", + __get_str(entity), __entry->irq_type + ) +); + +TRACE_EVENT(cam_irq_handled, + TP_PROTO(const char *entity, uint32_t irq_type), + TP_ARGS(entity, irq_type), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint32_t, irq_type) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->irq_type = irq_type; + ), + TP_printk( + "%8s: handled irq type=%d", + __get_str(entity), __entry->irq_type + ) +); + +TRACE_EVENT(cam_cdm_cb, + TP_PROTO(const char *entity, uint32_t status), + TP_ARGS(entity, status), + TP_STRUCT__entry( + __string(entity, entity) + __field(uint32_t, status) + ), + TP_fast_assign( + __assign_str(entity, entity); + __entry->status = status; + ), + TP_printk( + "%8s: cdm cb status=%d", + __get_str(entity), __entry->status + ) +); + +#endif /* _CAM_TRACE_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/techpack/camera/include/Kbuild b/techpack/camera/include/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..bab1145bc7a7d620c579e60abef2b6652603df78 --- /dev/null +++ b/techpack/camera/include/Kbuild @@ -0,0 +1,2 @@ +# Top-level Makefile calls into asm-$(ARCH) +# List only non-arch directories below diff --git a/techpack/camera/include/uapi/Kbuild b/techpack/camera/include/uapi/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..93dffc4bac8d6c34a0fdccf9cfaf3497d78d74c6 --- /dev/null +++ b/techpack/camera/include/uapi/Kbuild @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note + +header-y += media/ diff --git a/techpack/camera/include/uapi/media/Kbuild b/techpack/camera/include/uapi/media/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..e7971dac10518ef45c5db33df3a700c0673b4b47 --- /dev/null +++ b/techpack/camera/include/uapi/media/Kbuild @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note + +header-y += cam_cpas.h +header-y += cam_defs.h +header-y += cam_fd.h +header-y += cam_icp.h +header-y += cam_isp.h +header-y += cam_isp_vfe.h +header-y += cam_isp_ife.h +header-y += cam_jpeg.h +header-y += cam_req_mgr.h +header-y += cam_sensor.h +header-y += cam_sync.h +header-y += cam_lrme.h diff --git a/techpack/camera/include/uapi/media/cam_cpas.h b/techpack/camera/include/uapi/media/cam_cpas.h new file mode 100644 index 0000000000000000000000000000000000000000..b85ab068f9e8011e4d7747fffce81c55b81590fd --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_cpas.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_CPAS_H__ +#define __UAPI_CAM_CPAS_H__ + +#include <media/cam_defs.h> + +#define CAM_FAMILY_CAMERA_SS 1 +#define CAM_FAMILY_CPAS_SS 2 + +/* AXI BW Voting Version */ +#define CAM_AXI_BW_VOTING_V2 2 + +/* AXI BW Voting Transaction Type */ +#define CAM_AXI_TRANSACTION_READ 0 +#define CAM_AXI_TRANSACTION_WRITE 1 + +/* AXI BW Voting Path Data Type */ +#define CAM_AXI_PATH_DATA_IFE_START_OFFSET 0 +#define CAM_AXI_PATH_DATA_IFE_LINEAR (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_IFE_VID (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_IFE_DISP (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_IFE_STATS (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_IFE_RDI0 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_IFE_RDI1 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 5) +#define CAM_AXI_PATH_DATA_IFE_RDI2 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 6) +#define CAM_AXI_PATH_DATA_IFE_RDI3 (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 7) +#define CAM_AXI_PATH_DATA_IFE_PDAF (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 8) +#define CAM_AXI_PATH_DATA_IFE_PIXEL_RAW \ + (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 9) +#define CAM_AXI_PATH_DATA_IFE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_IFE_START_OFFSET + 31) + +#define CAM_AXI_PATH_DATA_IPE_START_OFFSET 32 +#define CAM_AXI_PATH_DATA_IPE_RD_IN (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 0) +#define CAM_AXI_PATH_DATA_IPE_RD_REF (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 1) +#define CAM_AXI_PATH_DATA_IPE_WR_VID (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 2) +#define CAM_AXI_PATH_DATA_IPE_WR_DISP (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 3) +#define CAM_AXI_PATH_DATA_IPE_WR_REF (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 4) +#define CAM_AXI_PATH_DATA_IPE_MAX_OFFSET \ + (CAM_AXI_PATH_DATA_IPE_START_OFFSET + 31) + +#define CAM_AXI_PATH_DATA_ALL 256 + +/** + * struct cam_cpas_query_cap - CPAS query device capability payload + * + * @camera_family : Camera family type + * @reserved : Reserved field for alignment + * @camera_version : Camera platform version + * @cpas_version : Camera CPAS version within camera platform + * + */ +struct cam_cpas_query_cap { + uint32_t camera_family; + uint32_t reserved; + struct cam_hw_version camera_version; + struct cam_hw_version cpas_version; +}; + +/** + * struct cam_axi_per_path_bw_vote - Per path bandwidth vote information + * + * @usage_data client usage data (left/right/rdi) + * @transac_type Transaction type on the path (read/write) + * @path_data_type Path for which vote is given (video, display, rdi) + * @reserved Reserved for alignment + * @camnoc_bw CAMNOC bw for this path + * @mnoc_ab_bw MNOC AB bw for this path + * @mnoc_ib_bw MNOC IB bw for this path + * @ddr_ab_bw DDR AB bw for this path + * @ddr_ib_bw DDR IB bw for this path + */ +struct cam_axi_per_path_bw_vote { + uint32_t usage_data; + uint32_t transac_type; + uint32_t path_data_type; + uint32_t reserved; + uint64_t camnoc_bw; + uint64_t mnoc_ab_bw; + uint64_t mnoc_ib_bw; + uint64_t ddr_ab_bw; + uint64_t ddr_ib_bw; +}; + +#endif /* __UAPI_CAM_CPAS_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_custom.h b/techpack/camera/include/uapi/media/cam_custom.h new file mode 100644 index 0000000000000000000000000000000000000000..b36891f4a0dcfbd57d4b93c1d7daac5e2ee67061 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_custom.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_CUSTOM_H__ +#define __UAPI_CAM_CUSTOM_H__ + +#include "cam_defs.h" + +/* Custom driver name */ +#define CAM_CUSTOM_DEV_NAME "cam-custom" + +#define CAM_CUSTOM_NUM_SUB_DEVICES 2 + +/* HW type */ +#define CAM_CUSTOM_HW1 0 +#define CAM_CUSTOM_HW2 1 + +/* output path resource id's */ +#define CAM_CUSTOM_OUT_RES_UDI_0 1 +#define CAM_CUSTOM_OUT_RES_UDI_1 2 +#define CAM_CUSTOM_OUT_RES_UDI_2 3 + +/* input resource for custom hw */ +#define CAM_CUSTOM_IN_RES_UDI_0 1 + +/* Resource ID */ +#define CAM_CUSTOM_RES_ID_PORT 0 + +/* Packet opcode for Custom */ +#define CAM_CUSTOM_PACKET_OP_BASE 0 +#define CAM_CUSTOM_PACKET_INIT_DEV 1 +#define CAM_CUSTOM_PACKET_UPDATE_DEV 2 +#define CAM_CUSTOM_PACKET_OP_MAX 3 + +/* max number of vc-dt cfg for a given input */ +#define CAM_CUSTOM_VC_DT_CFG_MAX 4 + +/* phy input resource types */ +#define CAM_CUSTOM_IN_RES_BASE 0x5000 +#define CAM_CUSTOM_IN_RES_PHY_0 (CAM_CUSTOM_IN_RES_BASE + 1) +#define CAM_CUSTOM_IN_RES_PHY_1 (CAM_CUSTOM_IN_RES_BASE + 2) +#define CAM_CUSTOM_IN_RES_PHY_2 (CAM_CUSTOM_IN_RES_BASE + 3) +#define CAM_CUSTOM_IN_RES_PHY_3 (CAM_CUSTOM_IN_RES_BASE + 4) + +/* Query devices */ +/** + * struct cam_custom_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Custom HW type + * @hw_version: Hardware version + * + */ +struct cam_custom_dev_cap_info { + uint32_t hw_type; + uint32_t hw_version; +}; + +/** + * struct cam_custom_query_cap_cmd - Custom HW query device capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_custom_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_custom_dev_cap_info dev_caps[CAM_CUSTOM_NUM_SUB_DEVICES]; +}; + +/* Acquire Device */ +/** + * struct cam_custom_out_port_info - An output port resource info + * + * @res_type: output resource type + * @format: output format of the resource + * @custom_info 1-3: custom params + * @reserved: reserved field for alignment + * + */ +struct cam_custom_out_port_info { + uint32_t res_type; + uint32_t format; + uint32_t custom_info1; + uint32_t custom_info2; + uint32_t custom_info3; + uint32_t reserved; +}; + +/** + * struct cam_custom_in_port_info - An input port resource info + * + * @res_type: input resource type + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @num_valid_vc_dt: number of valid vc-dt + * @format: input format + * @test_pattern: test pattern for the testgen + * @usage_type: whether dual vfe is required + * @left_start: left input start offset in pixels + * @left_stop: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * @right_stop: right input stop offset in pixels. + * @right_width: right input width in pixels. + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @pixel_clk; sensor output clock + * @num_out_byte: number of valid output bytes per cycle + * @custom_info1: custom_info1 + * @custom_info2: custom info 2 + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources + * + */ +struct cam_custom_in_port_info { + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc[CAM_CUSTOM_VC_DT_CFG_MAX]; + uint32_t dt[CAM_CUSTOM_VC_DT_CFG_MAX]; + uint32_t num_valid_vc_dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t num_bytes_out; + uint32_t custom_info1; + uint32_t custom_info2; + uint32_t num_out_res; + struct cam_custom_out_port_info data[1]; +}; + +/** + * struct cam_custom_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array; + */ +struct cam_custom_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_custom_cmd_buf_type_1 - cmd buf type 1 + * + * @custom_info: custom info + * @reserved: reserved + */ +struct cam_custom_cmd_buf_type_1 { + uint32_t custom_info; + uint32_t reserved; +}; + +/** + * struct cam_custom_cmd_buf_type_2 - cmd buf type 2 + * + * @custom_info1: Custom info 1 + * @custom_info2: Custom info 2 + * @custom_info3: Custom info 3 + * @reserved: reserved + */ +struct cam_custom_cmd_buf_type_2 { + uint32_t custom_info1; + uint32_t custom_info2; + uint32_t custom_info3; + uint32_t reserved; +}; +#endif /* __UAPI_CAM_CUSTOM_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_defs.h b/techpack/camera/include/uapi/media/cam_defs.h new file mode 100755 index 0000000000000000000000000000000000000000..6e29b35ace538726b624dd9de5601024f72a7dd0 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_defs.h @@ -0,0 +1,884 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_DEFS_H__ +#define __UAPI_CAM_DEFS_H__ + +#include <linux/videodev2.h> +#include <linux/types.h> +#include <linux/ioctl.h> + + +/* camera op codes */ +#define CAM_COMMON_OPCODE_BASE 0x100 +#define CAM_QUERY_CAP (CAM_COMMON_OPCODE_BASE + 0x1) +#define CAM_ACQUIRE_DEV (CAM_COMMON_OPCODE_BASE + 0x2) +#define CAM_START_DEV (CAM_COMMON_OPCODE_BASE + 0x3) +#define CAM_STOP_DEV (CAM_COMMON_OPCODE_BASE + 0x4) +#define CAM_CONFIG_DEV (CAM_COMMON_OPCODE_BASE + 0x5) +#define CAM_RELEASE_DEV (CAM_COMMON_OPCODE_BASE + 0x6) +#define CAM_SD_SHUTDOWN (CAM_COMMON_OPCODE_BASE + 0x7) +#define CAM_FLUSH_REQ (CAM_COMMON_OPCODE_BASE + 0x8) + +#define CAM_GET_FUSE_ID (CAM_COMMON_OPCODE_BASE + 0x9) +#define CAM_GET_OIS_GYRO_OFFSET (CAM_COMMON_OPCODE_BASE + 0xA) +#define CAM_GET_OIS_HALL_POSITION (CAM_COMMON_OPCODE_BASE + 0xB) +#define CAM_OIS_GYRO_OFFSET_CALIBRATION (CAM_COMMON_OPCODE_BASE + 0xC) +#define CAM_GET_OIS_EIS_HALL (CAM_COMMON_OPCODE_BASE + 0xD) +#define CAM_SET_GYRO_POWER_STATUS (CAM_COMMON_OPCODE_BASE + 0xE) +#define CAM_GET_GYRO_NOISE (CAM_COMMON_OPCODE_BASE + 0xF) +#define CAM_WRITE_CALIBRATION_DATA (CAM_COMMON_OPCODE_BASE + 0x10) +#define CAM_CHECK_CALIBRATION_DATA (CAM_COMMON_OPCODE_BASE + 0x11) +#define CAM_WRITE_AE_SYNC_DATA (CAM_COMMON_OPCODE_BASE + 0x12) +#define CAM_GET_GYRO_ENERGY (CAM_COMMON_OPCODE_BASE + 0x13) +#define CAM_COMMON_OPCODE_MAX (CAM_COMMON_OPCODE_BASE + 0x14) + +#define CAM_COMMON_OPCODE_BASE_v2 0x150 +#define CAM_ACQUIRE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x1) +#define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) +//add dpc read for imx471 +#define CAM_GET_DPC_DATA (CAM_COMMON_OPCODE_BASE_v2 + 0x3) + +#define CAM_EXT_OPCODE_BASE 0x200 +#define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) + +/* camera handle type */ +#define CAM_HANDLE_USER_POINTER 1 +#define CAM_HANDLE_MEM_HANDLE 2 + +/* Generic Blob CmdBuffer header properties */ +#define CAM_GENERIC_BLOB_CMDBUFFER_SIZE_MASK 0xFFFFFF00 +#define CAM_GENERIC_BLOB_CMDBUFFER_SIZE_SHIFT 8 +#define CAM_GENERIC_BLOB_CMDBUFFER_TYPE_MASK 0xFF +#define CAM_GENERIC_BLOB_CMDBUFFER_TYPE_SHIFT 0 + +/* Command Buffer Types */ +#define CAM_CMD_BUF_DMI 0x1 +#define CAM_CMD_BUF_DMI16 0x2 +#define CAM_CMD_BUF_DMI32 0x3 +#define CAM_CMD_BUF_DMI64 0x4 +#define CAM_CMD_BUF_DIRECT 0x5 +#define CAM_CMD_BUF_INDIRECT 0x6 +#define CAM_CMD_BUF_I2C 0x7 +#define CAM_CMD_BUF_FW 0x8 +#define CAM_CMD_BUF_GENERIC 0x9 +#define CAM_CMD_BUF_LEGACY 0xA + +/* UBWC API Version */ +#define CAM_UBWC_CFG_VERSION_1 1 +#define CAM_UBWC_CFG_VERSION_2 2 + +#define CAM_MAX_ACQ_RES 5 +#define CAM_MAX_HW_SPLIT 3 + + +/** + * enum flush_type_t - Identifies the various flush types + * + * @CAM_FLUSH_TYPE_REQ: Flush specific request + * @CAM_FLUSH_TYPE_ALL: Flush all requests belonging to a context + * @CAM_FLUSH_TYPE_MAX: Max enum to validate flush type + * + */ +enum flush_type_t { + CAM_FLUSH_TYPE_REQ, + CAM_FLUSH_TYPE_ALL, + CAM_FLUSH_TYPE_MAX +}; + +/*add for get hall dat for EIS*/ +#define HALL_MAX_NUMBER 12 +struct ois_hall_type { + uint32_t dataNum; + uint32_t mdata[HALL_MAX_NUMBER]; + uint32_t timeStamp; +}; + +/** + * struct cam_control - Structure used by ioctl control for camera + * + * @op_code: This is the op code for camera control + * @size: Control command size + * @handle_type: User pointer or shared memory handle + * @reserved: Reserved field for 64 bit alignment + * @handle: Control command payload + */ +struct cam_control { + uint32_t op_code; + uint32_t size; + uint32_t handle_type; + uint32_t reserved; + uint64_t handle; +}; + +/* camera IOCTL */ +#define VIDIOC_CAM_CONTROL \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct cam_control) + +#define VIDIOC_CAM_FTM_POWNER_UP 0 +#define VIDIOC_CAM_FTM_POWNER_DOWN 1 +/** + * struct cam_hw_version - Structure for HW version of camera devices + * + * @major : Hardware version major + * @minor : Hardware version minor + * @incr : Hardware version increment + * @reserved : Reserved for 64 bit aligngment + */ +struct cam_hw_version { + uint32_t major; + uint32_t minor; + uint32_t incr; + uint32_t reserved; +}; + +/** + * struct cam_iommu_handle - Structure for IOMMU handles of camera hw devices + * + * @non_secure: Device Non Secure IOMMU handle + * @secure: Device Secure IOMMU handle + * + */ +struct cam_iommu_handle { + int32_t non_secure; + int32_t secure; +}; + +/* camera secure mode */ +#define CAM_SECURE_MODE_NON_SECURE 0 +#define CAM_SECURE_MODE_SECURE 1 + +/* Camera Format Type */ +#define CAM_FORMAT_BASE 0 +#define CAM_FORMAT_MIPI_RAW_6 1 +#define CAM_FORMAT_MIPI_RAW_8 2 +#define CAM_FORMAT_MIPI_RAW_10 3 +#define CAM_FORMAT_MIPI_RAW_12 4 +#define CAM_FORMAT_MIPI_RAW_14 5 +#define CAM_FORMAT_MIPI_RAW_16 6 +#define CAM_FORMAT_MIPI_RAW_20 7 +#define CAM_FORMAT_QTI_RAW_8 8 +#define CAM_FORMAT_QTI_RAW_10 9 +#define CAM_FORMAT_QTI_RAW_12 10 +#define CAM_FORMAT_QTI_RAW_14 11 +#define CAM_FORMAT_PLAIN8 12 +#define CAM_FORMAT_PLAIN16_8 13 +#define CAM_FORMAT_PLAIN16_10 14 +#define CAM_FORMAT_PLAIN16_12 15 +#define CAM_FORMAT_PLAIN16_14 16 +#define CAM_FORMAT_PLAIN16_16 17 +#define CAM_FORMAT_PLAIN32_20 18 +#define CAM_FORMAT_PLAIN64 19 +#define CAM_FORMAT_PLAIN128 20 +#define CAM_FORMAT_ARGB 21 +#define CAM_FORMAT_ARGB_10 22 +#define CAM_FORMAT_ARGB_12 23 +#define CAM_FORMAT_ARGB_14 24 +#define CAM_FORMAT_DPCM_10_6_10 25 +#define CAM_FORMAT_DPCM_10_8_10 26 +#define CAM_FORMAT_DPCM_12_6_12 27 +#define CAM_FORMAT_DPCM_12_8_12 28 +#define CAM_FORMAT_DPCM_14_8_14 29 +#define CAM_FORMAT_DPCM_14_10_14 30 +#define CAM_FORMAT_NV21 31 +#define CAM_FORMAT_NV12 32 +#define CAM_FORMAT_TP10 33 +#define CAM_FORMAT_YUV422 34 +#define CAM_FORMAT_PD8 35 +#define CAM_FORMAT_PD10 36 +#define CAM_FORMAT_UBWC_NV12 37 +#define CAM_FORMAT_UBWC_NV12_4R 38 +#define CAM_FORMAT_UBWC_TP10 39 +#define CAM_FORMAT_UBWC_P010 40 +#define CAM_FORMAT_PLAIN8_SWAP 41 +#define CAM_FORMAT_PLAIN8_10 42 +#define CAM_FORMAT_PLAIN8_10_SWAP 43 +#define CAM_FORMAT_YV12 44 +#define CAM_FORMAT_Y_ONLY 45 +#define CAM_FORMAT_DPCM_12_10_12 46 +#define CAM_FORMAT_PLAIN32 47 +#define CAM_FORMAT_ARGB_16 48 +#define CAM_FORMAT_MAX 49 + +/* camera rotaion */ +#define CAM_ROTATE_CW_0_DEGREE 0 +#define CAM_ROTATE_CW_90_DEGREE 1 +#define CAM_RORATE_CW_180_DEGREE 2 +#define CAM_ROTATE_CW_270_DEGREE 3 + +/* camera Color Space */ +#define CAM_COLOR_SPACE_BASE 0 +#define CAM_COLOR_SPACE_BT601_FULL 1 +#define CAM_COLOR_SPACE_BT601625 2 +#define CAM_COLOR_SPACE_BT601525 3 +#define CAM_COLOR_SPACE_BT709 4 +#define CAM_COLOR_SPACE_DEPTH 5 +#define CAM_COLOR_SPACE_MAX 6 + +/* camera buffer direction */ +#define CAM_BUF_INPUT 1 +#define CAM_BUF_OUTPUT 2 +#define CAM_BUF_IN_OUT 3 + +/* camera packet device Type */ +#define CAM_PACKET_DEV_BASE 0 +#define CAM_PACKET_DEV_IMG_SENSOR 1 +#define CAM_PACKET_DEV_ACTUATOR 2 +#define CAM_PACKET_DEV_COMPANION 3 +#define CAM_PACKET_DEV_EEPOM 4 +#define CAM_PACKET_DEV_CSIPHY 5 +#define CAM_PACKET_DEV_OIS 6 +#define CAM_PACKET_DEV_FLASH 7 +#define CAM_PACKET_DEV_FD 8 +#define CAM_PACKET_DEV_JPEG_ENC 9 +#define CAM_PACKET_DEV_JPEG_DEC 10 +#define CAM_PACKET_DEV_VFE 11 +#define CAM_PACKET_DEV_CPP 12 +#define CAM_PACKET_DEV_CSID 13 +#define CAM_PACKET_DEV_ISPIF 14 +#define CAM_PACKET_DEV_IFE 15 +#define CAM_PACKET_DEV_ICP 16 +#define CAM_PACKET_DEV_LRME 17 +#define CAM_PACKET_DEV_MAX 18 + +/* Register base type */ +#define CAM_REG_DUMP_BASE_TYPE_ISP_LEFT 1 +#define CAM_REG_DUMP_BASE_TYPE_ISP_RIGHT 2 +#define CAM_REG_DUMP_BASE_TYPE_CAMNOC 3 + +/* Register dump read type */ +#define CAM_REG_DUMP_READ_TYPE_CONT_RANGE 1 +#define CAM_REG_DUMP_READ_TYPE_DMI 2 + +/* Max number of config writes to read from DMI */ +#define CAM_REG_DUMP_DMI_CONFIG_MAX 5 + + +/* constants */ +#define CAM_PACKET_MAX_PLANES 3 + +/** + * struct cam_plane_cfg - Plane configuration info + * + * @width: Plane width in pixels + * @height: Plane height in lines + * @plane_stride: Plane stride in pixel + * @slice_height: Slice height in line (not used by ISP) + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config: UBWC mode config + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * + */ +struct cam_plane_cfg { + uint32_t width; + uint32_t height; + uint32_t plane_stride; + uint32_t slice_height; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; +}; + +/** + * struct cam_ubwc_plane_cfg_v1 - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config_0: UBWC mode config 0 + * @mode_config_1: UBWC 3 mode config 1 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * + */ +struct cam_ubwc_plane_cfg_v1 { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; +}; + +/** + * struct cam_ubwc_plane_cfg_v2 - UBWC Plane configuration info + * + * @port_type: Port Type + * @meta_stride: UBWC metadata stride + * @meta_size: UBWC metadata plane size + * @meta_offset: UBWC metadata offset + * @packer_config: UBWC packer config + * @mode_config: UBWC mode config + * @static ctrl: UBWC static ctrl + * @ctrl_2: UBWC ctrl 2 + * @tile_config: UBWC tile config + * @h_init: UBWC horizontal initial coordinate in pixels + * @v_init: UBWC vertical initial coordinate in lines + * @stats_ctrl_2: UBWC stats control + * @lossy_threshold0 UBWC lossy threshold 0 + * @lossy_threshold1 UBWC lossy threshold 1 + * @lossy_var_offset UBWC offset variance thrshold + * + */ +struct cam_ubwc_plane_cfg_v2 { + uint32_t port_type; + uint32_t meta_stride; + uint32_t meta_size; + uint32_t meta_offset; + uint32_t packer_config; + uint32_t mode_config_0; + uint32_t mode_config_1; + uint32_t tile_config; + uint32_t h_init; + uint32_t v_init; + uint32_t static_ctrl; + uint32_t ctrl_2; + uint32_t stats_ctrl_2; + uint32_t lossy_threshold_0; + uint32_t lossy_threshold_1; + uint32_t lossy_var_offset; + uint32_t bandwidth_limit; + uint32_t reserved[3]; +}; +/** + * struct cam_cmd_buf_desc - Command buffer descriptor + * + * @mem_handle: Command buffer handle + * @offset: Command start offset + * @size: Size of the command buffer in bytes + * @length: Used memory in command buffer in bytes + * @type: Type of the command buffer + * @meta_data: Data type for private command buffer + * Between UMD and KMD + * + */ +struct cam_cmd_buf_desc { + int32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t length; + uint32_t type; + uint32_t meta_data; +}; + +/** + * struct cam_buf_io_cfg - Buffer io configuration for buffers + * + * @mem_handle: Mem_handle array for the buffers. + * @offsets: Offsets for each planes in the buffer + * @planes: Per plane information + * @width: Main plane width in pixel + * @height: Main plane height in lines + * @format: Format of the buffer + * @color_space: Color space for the buffer + * @color_pattern: Color pattern in the buffer + * @bpp: Bit per pixel + * @rotation: Rotation information for the buffer + * @resource_type: Resource type associated with the buffer + * @fence: Fence handle + * @early_fence: Fence handle for early signal + * @aux_cmd_buf: An auxiliary command buffer that may be + * used for programming the IO + * @direction: Direction of the config + * @batch_size: Batch size in HFR mode + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @flag: Flags for extra information + * @direction: Buffer direction: input or output + * @padding: Padding for the structure + * + */ +struct cam_buf_io_cfg { + int32_t mem_handle[CAM_PACKET_MAX_PLANES]; + uint32_t offsets[CAM_PACKET_MAX_PLANES]; + struct cam_plane_cfg planes[CAM_PACKET_MAX_PLANES]; + uint32_t format; + uint32_t color_space; + uint32_t color_pattern; + uint32_t bpp; + uint32_t rotation; + uint32_t resource_type; + int32_t fence; + int32_t early_fence; + struct cam_cmd_buf_desc aux_cmd_buf; + uint32_t direction; + uint32_t batch_size; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t flag; + uint32_t padding; +}; + +/** + * struct cam_packet_header - Camera packet header + * + * @op_code: Camera packet opcode + * @size: Size of the camera packet in bytes + * @request_id: Request id for this camera packet + * @flags: Flags for the camera packet + * @padding: Padding + * + */ +struct cam_packet_header { + uint32_t op_code; + uint32_t size; + uint64_t request_id; + uint32_t flags; + uint32_t padding; +}; + +/** + * struct cam_patch_desc - Patch structure + * + * @dst_buf_hdl: Memory handle for the dest buffer + * @dst_offset: Offset byte in the dest buffer + * @src_buf_hdl: Memory handle for the source buffer + * @src_offset: Offset byte in the source buffer + * + */ +struct cam_patch_desc { + int32_t dst_buf_hdl; + uint32_t dst_offset; + int32_t src_buf_hdl; + uint32_t src_offset; +}; + +/** + * struct cam_packet - Camera packet structure + * + * @header: Camera packet header + * @cmd_buf_offset: Command buffer start offset + * @num_cmd_buf: Number of the command buffer in the packet + * @io_config_offset: Buffer io configuration start offset + * @num_io_configs: Number of the buffer io configurations + * @patch_offset: Patch offset for the patch structure + * @num_patches: Number of the patch structure + * @kmd_cmd_buf_index: Command buffer index which contains extra + * space for the KMD buffer + * @kmd_cmd_buf_offset: Offset from the beginning of the command + * buffer for KMD usage. + * @payload: Camera packet payload + * + */ +struct cam_packet { + struct cam_packet_header header; + uint32_t cmd_buf_offset; + uint32_t num_cmd_buf; + uint32_t io_configs_offset; + uint32_t num_io_configs; + uint32_t patch_offset; + uint32_t num_patches; + uint32_t kmd_cmd_buf_index; + uint32_t kmd_cmd_buf_offset; + uint64_t payload[1]; + +}; + +/** + * struct cam_release_dev_cmd - Control payload for release devices + * + * @session_handle: Session handle for the release + * @dev_handle: Device handle for the release + */ +struct cam_release_dev_cmd { + int32_t session_handle; + int32_t dev_handle; +}; + +/** + * struct cam_start_stop_dev_cmd - Control payload for start/stop device + * + * @session_handle: Session handle for the start/stop command + * @dev_handle: Device handle for the start/stop command + * + */ +struct cam_start_stop_dev_cmd { + int32_t session_handle; + int32_t dev_handle; +}; + +/** + * struct cam_config_dev_cmd - Command payload for configure device + * + * @session_handle: Session handle for the command + * @dev_handle: Device handle for the command + * @offset: Offset byte in the packet handle. + * @packet_handle: Packet memory handle for the actual packet: + * struct cam_packet. + * + */ +struct cam_config_dev_cmd { + int32_t session_handle; + int32_t dev_handle; + uint64_t offset; + uint64_t packet_handle; +}; + +/** + * struct cam_query_cap_cmd - Payload for query device capability + * + * @size: Handle size + * @handle_type: User pointer or shared memory handle + * @caps_handle: Device specific query command payload + * + */ +struct cam_query_cap_cmd { + uint32_t size; + uint32_t handle_type; + uint64_t caps_handle; +}; + +/** + * struct cam_acquire_dev_cmd - Control payload for acquire devices + * + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @handle_type: Resource handle type: + * 1 = user pointer, 2 = mem handle + * @num_resources: Number of the resources to be acquired + * @resources_hdl: Resource handle that refers to the actual + * resource array. Each item in this + * array is device specific resource structure + * + */ +struct cam_acquire_dev_cmd { + int32_t session_handle; + int32_t dev_handle; + uint32_t handle_type; + uint32_t num_resources; + uint64_t resource_hdl; +}; + +/* + * In old version, while acquiring device the num_resources in + * struct cam_acquire_dev_cmd will be a valid value. During ACQUIRE_DEV + * KMD driver will return dev_handle as well as associate HW to handle. + * If num_resources is set to the constant below, we are using + * the new version and we do not acquire HW in ACQUIRE_DEV IOCTL. + * ACQUIRE_DEV will only return handle and we should receive + * ACQUIRE_HW IOCTL after ACQUIRE_DEV and that is when the HW + * is associated with the dev_handle. + * + * (Data type): uint32_t + */ +#define CAM_API_COMPAT_CONSTANT 0xFEFEFEFE + +#define CAM_ACQUIRE_HW_STRUCT_VERSION_1 1 +#define CAM_ACQUIRE_HW_STRUCT_VERSION_2 2 + +/** + * struct cam_acquire_hw_cmd_v1 - Control payload for acquire HW IOCTL (Ver 1) + * + * @struct_version: = CAM_ACQUIRE_HW_STRUCT_VERSION_1 for this struct + * This value should be the first 32-bits in any structure + * related to this IOCTL. So that if the struct needs to + * change, we can first read the starting 32-bits, get the + * version number and then typecast the data to struct + * accordingly. + * @reserved: Reserved field for 64-bit alignment + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @handle_type: Tells you how to interpret the variable resource_hdl- + * 1 = user pointer, 2 = mem handle + * @data_size: Total size of data contained in memory pointed + * to by resource_hdl + * @resource_hdl: Resource handle that refers to the actual + * resource data. + */ +struct cam_acquire_hw_cmd_v1 { + uint32_t struct_version; + uint32_t reserved; + int32_t session_handle; + int32_t dev_handle; + uint32_t handle_type; + uint32_t data_size; + uint64_t resource_hdl; +}; + +/** + * struct cam_acquired_hw_info - Update the acquired hardware info + * + * @acquired_hw_id: Acquired hardware mask + * @acquired_hw_path: Acquired path mask for an input + * if input splits into multiple paths, + * its updated per hardware + * valid_acquired_hw: Valid num of acquired hardware + */ +struct cam_acquired_hw_info { + uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; + uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; + uint32_t valid_acquired_hw; +}; + +/** + * struct cam_acquire_hw_cmd_v2 - Control payload for acquire HW IOCTL (Ver 2) + * + * @struct_version: = CAM_ACQUIRE_HW_STRUCT_VERSION_2 for this struct + * This value should be the first 32-bits in any structure + * related to this IOCTL. So that if the struct needs to + * change, we can first read the starting 32-bits, get the + * version number and then typecast the data to struct + * accordingly. + * @reserved: Reserved field for 64-bit alignment + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @handle_type: Tells you how to interpret the variable resource_hdl- + * 1 = user pointer, 2 = mem handle + * @data_size: Total size of data contained in memory pointed + * to by resource_hdl + * @resource_hdl: Resource handle that refers to the actual + * resource data. + */ +struct cam_acquire_hw_cmd_v2 { + uint32_t struct_version; + uint32_t reserved; + int32_t session_handle; + int32_t dev_handle; + uint32_t handle_type; + uint32_t data_size; + uint64_t resource_hdl; + struct cam_acquired_hw_info hw_info; +}; + +#define CAM_RELEASE_HW_STRUCT_VERSION_1 1 + +/** + * struct cam_release_hw_cmd_v1 - Control payload for release HW IOCTL (Ver 1) + * + * @struct_version: = CAM_RELEASE_HW_STRUCT_VERSION_1 for this struct + * This value should be the first 32-bits in any structure + * related to this IOCTL. So that if the struct needs to + * change, we can first read the starting 32-bits, get the + * version number and then typecast the data to struct + * accordingly. + * @reserved: Reserved field for 64-bit alignment + * @session_handle: Session handle for the release + * @dev_handle: Device handle for the release + */ +struct cam_release_hw_cmd_v1 { + uint32_t struct_version; + uint32_t reserved; + int32_t session_handle; + int32_t dev_handle; +}; + +/** + * struct cam_flush_dev_cmd - Control payload for flush devices + * + * @version: Version + * @session_handle: Session handle for the acquire command + * @dev_handle: Device handle to be returned + * @flush_type: Flush type: + * 0 = flush specific request + * 1 = flush all + * @reserved: Reserved for 64 bit aligngment + * @req_id: Request id that needs to cancel + * + */ +struct cam_flush_dev_cmd { + uint64_t version; + int32_t session_handle; + int32_t dev_handle; + uint32_t flush_type; + uint32_t reserved; + int64_t req_id; +}; + +/** + * struct cam_ubwc_config - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @num_ports: Number of ports to be configured + * @ubwc_plane_config: Array of UBWC configurations per port + * Size [CAM_PACKET_MAX_PLANES - 1] per port + * as UBWC is supported on Y & C planes + * and therefore a max size of 2 planes + * + */ +struct cam_ubwc_config { + uint32_t api_version; + uint32_t num_ports; + struct cam_ubwc_plane_cfg_v1 + ubwc_plane_cfg[1][CAM_PACKET_MAX_PLANES - 1]; +}; + +/** + * struct cam_ubwc_config_v2 - UBWC Configuration Payload + * + * @api_version: UBWC config api version + * @num_ports: Number of ports to be configured + * @ubwc_plane_config: Array of UBWC configurations per port + * Size [CAM_PACKET_MAX_PLANES - 1] per port + * as UBWC is supported on Y & C planes + * and therefore a max size of 2 planes + * + */ +struct cam_ubwc_config_v2 { + uint32_t api_version; + uint32_t num_ports; + struct cam_ubwc_plane_cfg_v2 + ubwc_plane_cfg[1][CAM_PACKET_MAX_PLANES - 1]; +}; + +/** + * struct cam_cmd_mem_region_info - + * Cmd buffer region info + * + * @mem_handle : Memory handle of the region + * @offset : Offset if any + * @size : Size of the region + * @flags : Flags if any + */ +struct cam_cmd_mem_region_info { + int32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t flags; +}; + +/** + * struct cam_cmd_mem_regions - + * List of multiple memory descriptors of + * of different regions + * + * @version : Version number + * @num_regions : Number of regions + * @map_info_array : Array of all the regions + */ +struct cam_cmd_mem_regions { + uint32_t version; + uint32_t num_regions; + struct cam_cmd_mem_region_info map_info_array[1]; +}; + +/** + * struct cam_reg_write_desc - Register write descriptor + * + * @offset : Register offset at which 'value' needs to written + * @value : Register value to write + */ +struct cam_reg_write_desc { + uint32_t offset; + uint32_t value; +}; + +/** + * struct cam_reg_range_read_desc - Descriptor to provide read info + * + * @offset : Register offset address to start with + * @num_values : Number of values to read + */ +struct cam_reg_range_read_desc { + uint32_t offset; + uint32_t num_values; +}; + +/** + * struct cam_dmi_read_desc - Descriptor to provide DMI read info + * + * @num_pre_writes : Number of registers to write before reading DMI data + * @num_post_writes : Number of registers to write after reading DMI data + * @pre_read_config : Registers to write before reading DMI data + * @dmi_data_read : DMI Register, number of values to read to dump + * DMI data + * @post_read_config : Registers to write after reading DMI data + */ +struct cam_dmi_read_desc { + uint32_t num_pre_writes; + uint32_t num_post_writes; + struct cam_reg_write_desc pre_read_config[ + CAM_REG_DUMP_DMI_CONFIG_MAX]; + struct cam_reg_range_read_desc dmi_data_read; + struct cam_reg_write_desc post_read_config[ + CAM_REG_DUMP_DMI_CONFIG_MAX]; +}; + +/** + * struct cam_reg_read_info - Register read info for both reg continuous read + * or DMI read + * + * @type : Whether Register range read or DMI read + * @reg_read : Range of registers to read + * @dmi_read : DMI data to read + */ +struct cam_reg_read_info { + uint32_t type; + uint32_t reserved; + union { + struct cam_reg_range_read_desc reg_read; + struct cam_dmi_read_desc dmi_read; + }; +}; + +/** + * struct cam_reg_dump_out_buffer -Buffer info for dump data to be provided + * + * @req_id : Request ID corresponding to reg dump data + * @bytes_written : Number of bytes written + * @dump_data : Register dump data + */ +struct cam_reg_dump_out_buffer { + uint64_t req_id; + uint32_t bytes_written; + uint32_t dump_data[1]; +}; + +/** + * struct cam_reg_dump_desc - Descriptor to provide dump info + * + * @reg_base_type : Register base type, e.g. ISP_LEFT, ISP_RIGHT, CAMNOC + * @dump_buffer_offset : Offset from base of mem_handle at which Register dump + * will be written for this set + * @dump_buffer_size : Available size in bytes for writing dump values + * @num_read_range : Number register range reads (Continuous + DMI) + * @read_range : Read range info + */ +struct cam_reg_dump_desc { + uint32_t reg_base_type; + uint32_t dump_buffer_offset; + uint32_t dump_buffer_size; + uint32_t num_read_range; + struct cam_reg_read_info read_range[1]; +}; + +/** + * struct cam_reg_dump_input_info - Info about required dump sets + * + * @num_dump_sets : Number of different dump sets (base types) given + * @dump_set_offsets : Points to the given dump description structures + * (cam_reg_dump_desc) + */ +struct cam_reg_dump_input_info { + uint32_t num_dump_sets; + uint32_t dump_set_offsets[1]; +}; + + +#endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_fd.h b/techpack/camera/include/uapi/media/cam_fd.h new file mode 100644 index 0000000000000000000000000000000000000000..126be4555f69eb5a062ba1a54388285187ae5c38 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_fd.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_FD_H__ +#define __UAPI_CAM_FD_H__ + +#include <media/cam_defs.h> + +#define CAM_FD_MAX_FACES 35 +#define CAM_FD_RAW_RESULT_ENTRIES 512 + +/* FD Op Codes */ +#define CAM_PACKET_OPCODES_FD_FRAME_UPDATE 0x0 + +/* FD Command Buffer identifiers */ +#define CAM_FD_CMD_BUFFER_ID_GENERIC 0x0 +#define CAM_FD_CMD_BUFFER_ID_CDM 0x1 +#define CAM_FD_CMD_BUFFER_ID_MAX 0x2 + +/* FD Blob types */ +#define CAM_FD_BLOB_TYPE_SOC_CLOCK_BW_REQUEST 0x0 +#define CAM_FD_BLOB_TYPE_RAW_RESULTS_REQUIRED 0x1 + +/* FD Resource IDs */ +#define CAM_FD_INPUT_PORT_ID_IMAGE 0x0 +#define CAM_FD_INPUT_PORT_ID_MAX 0x1 + +#define CAM_FD_OUTPUT_PORT_ID_RESULTS 0x0 +#define CAM_FD_OUTPUT_PORT_ID_RAW_RESULTS 0x1 +#define CAM_FD_OUTPUT_PORT_ID_WORK_BUFFER 0x2 +#define CAM_FD_OUTPUT_PORT_ID_MAX 0x3 + +/** + * struct cam_fd_soc_clock_bw_request - SOC clock, bandwidth request info + * + * @clock_rate : Clock rate required while processing frame + * @bandwidth : Bandwidth required while processing frame + * @reserved : Reserved for future use + */ +struct cam_fd_soc_clock_bw_request { + uint64_t clock_rate; + uint64_t bandwidth; + uint64_t reserved[4]; +}; + +/** + * struct cam_fd_face - Face properties + * + * @prop1 : Property 1 of face + * @prop2 : Property 2 of face + * @prop3 : Property 3 of face + * @prop4 : Property 4 of face + * + * Do not change this layout, this is inline with how HW writes + * these values directly when the buffer is programmed to HW + */ +struct cam_fd_face { + uint32_t prop1; + uint32_t prop2; + uint32_t prop3; + uint32_t prop4; +}; + +/** + * struct cam_fd_results - FD results layout + * + * @faces : Array of faces with face properties + * @face_count : Number of faces detected + * @reserved : Reserved for alignment + * + * Do not change this layout, this is inline with how HW writes + * these values directly when the buffer is programmed to HW + */ +struct cam_fd_results { + struct cam_fd_face faces[CAM_FD_MAX_FACES]; + uint32_t face_count; + uint32_t reserved[3]; +}; + +/** + * struct cam_fd_hw_caps - Face properties + * + * @core_version : FD core version + * @wrapper_version : FD wrapper version + * @raw_results_available : Whether raw results are available on this HW + * @supported_modes : Modes supported by this HW. + * @reserved : Reserved for future use + */ +struct cam_fd_hw_caps { + struct cam_hw_version core_version; + struct cam_hw_version wrapper_version; + uint32_t raw_results_available; + uint32_t supported_modes; + uint64_t reserved; +}; + +/** + * struct cam_fd_query_cap_cmd - FD Query capabilities information + * + * @device_iommu : FD IOMMU handles + * @cdm_iommu : CDM iommu handles + * @hw_caps : FD HW capabilities + * @reserved : Reserved for alignment + */ +struct cam_fd_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + struct cam_fd_hw_caps hw_caps; + uint64_t reserved; +}; + +/** + * struct cam_fd_acquire_dev_info - FD acquire device information + * + * @clk_bw_request : SOC clock, bandwidth request + * @priority : Priority for this acquire + * @mode : Mode in which to run FD HW. + * @get_raw_results : Whether this acquire needs face raw results + * while frame processing + * @reserved : Reserved field for 64 bit alignment + */ +struct cam_fd_acquire_dev_info { + struct cam_fd_soc_clock_bw_request clk_bw_request; + uint32_t priority; + uint32_t mode; + uint32_t get_raw_results; + uint32_t reserved[13]; +}; + +#endif /* __UAPI_CAM_FD_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_icp.h b/techpack/camera/include/uapi/media/cam_icp.h new file mode 100644 index 0000000000000000000000000000000000000000..4b5419d2f21de1c12ce86ba52e74b875430adf42 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_icp.h @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ICP_H__ +#define __UAPI_CAM_ICP_H__ + +#include <media/cam_defs.h> +#include <media/cam_cpas.h> + +/* icp, ipe, bps, cdm(ipe/bps) are used in querycap */ +#define CAM_ICP_DEV_TYPE_A5 1 +#define CAM_ICP_DEV_TYPE_IPE 2 +#define CAM_ICP_DEV_TYPE_BPS 3 +#define CAM_ICP_DEV_TYPE_IPE_CDM 4 +#define CAM_ICP_DEV_TYPE_BPS_CDM 5 +#define CAM_ICP_DEV_TYPE_MAX 5 + +/* definitions needed for icp aquire device */ +#define CAM_ICP_RES_TYPE_BPS 1 +#define CAM_ICP_RES_TYPE_IPE_RT 2 +#define CAM_ICP_RES_TYPE_IPE 3 +#define CAM_ICP_RES_TYPE_IPE_SEMI_RT 4 +#define CAM_ICP_RES_TYPE_BPS_RT 5 +#define CAM_ICP_RES_TYPE_BPS_SEMI_RT 6 +#define CAM_ICP_RES_TYPE_MAX 7 + +/* packet opcode types */ +#define CAM_ICP_OPCODE_IPE_UPDATE 0 +#define CAM_ICP_OPCODE_BPS_UPDATE 1 +#define CAM_ICP_OPCODE_IPE_SETTINGS 2 +#define CAM_ICP_OPCODE_BPS_SETTINGS 3 + + +/* IPE input port resource type */ +#define CAM_ICP_IPE_INPUT_IMAGE_FULL 0x0 +#define CAM_ICP_IPE_INPUT_IMAGE_DS4 0x1 +#define CAM_ICP_IPE_INPUT_IMAGE_DS16 0x2 +#define CAM_ICP_IPE_INPUT_IMAGE_DS64 0x3 +#define CAM_ICP_IPE_INPUT_IMAGE_FULL_REF 0x4 +#define CAM_ICP_IPE_INPUT_IMAGE_DS4_REF 0x5 +#define CAM_ICP_IPE_INPUT_IMAGE_DS16_REF 0x6 +#define CAM_ICP_IPE_INPUT_IMAGE_DS64_REF 0x7 + +/* IPE output port resource type */ +#define CAM_ICP_IPE_OUTPUT_IMAGE_DISPLAY 0x8 +#define CAM_ICP_IPE_OUTPUT_IMAGE_VIDEO 0x9 +#define CAM_ICP_IPE_OUTPUT_IMAGE_FULL_REF 0xA +#define CAM_ICP_IPE_OUTPUT_IMAGE_DS4_REF 0xB +#define CAM_ICP_IPE_OUTPUT_IMAGE_DS16_REF 0xC +#define CAM_ICP_IPE_OUTPUT_IMAGE_DS64_REF 0xD + +#define CAM_ICP_IPE_IMAGE_MAX 0xE + +/* BPS input port resource type */ +#define CAM_ICP_BPS_INPUT_IMAGE 0x0 + +/* BPS output port resource type */ +#define CAM_ICP_BPS_OUTPUT_IMAGE_FULL 0x1 +#define CAM_ICP_BPS_OUTPUT_IMAGE_DS4 0x2 +#define CAM_ICP_BPS_OUTPUT_IMAGE_DS16 0x3 +#define CAM_ICP_BPS_OUTPUT_IMAGE_DS64 0x4 +#define CAM_ICP_BPS_OUTPUT_IMAGE_STATS_BG 0x5 +#define CAM_ICP_BPS_OUTPUT_IMAGE_STATS_BHIST 0x6 +#define CAM_ICP_BPS_OUTPUT_IMAGE_REG1 0x7 +#define CAM_ICP_BPS_OUTPUT_IMAGE_REG2 0x8 + +#define CAM_ICP_BPS_IO_IMAGES_MAX 0x9 + +/* Command meta types */ +#define CAM_ICP_CMD_META_GENERIC_BLOB 0x1 + +/* Generic blob types */ +#define CAM_ICP_CMD_GENERIC_BLOB_CLK 0x1 +#define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO 0x2 +#define CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_MAP 0x3 +#define CAM_ICP_CMD_GENERIC_BLOB_FW_MEM_UNMAP 0x4 +#define CAM_ICP_CMD_GENERIC_BLOB_CLK_V2 0x5 + +/** + * struct cam_icp_clk_bw_request_v2 + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: For memory alignment + * @num_paths: Number of axi paths in bw request + * @axi_path: Per path vote info for IPE/BPS + */ +struct cam_icp_clk_bw_request_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +}; + +/** + * struct cam_icp_clk_bw_request + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @uncompressed_bw: Bandwidth required to process frame + * @compressed_bw: Compressed bandwidth to process frame + */ +struct cam_icp_clk_bw_request { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint64_t uncompressed_bw; + uint64_t compressed_bw; +}; + +/** + * struct cam_icp_dev_ver - Device information for particular hw type + * + * This is used to get device version info of + * ICP, IPE, BPS and CDM related IPE and BPS from firmware + * and use this info in CAM_QUERY_CAP IOCTL + * + * @dev_type: hardware type for the cap info(icp, ipe, bps, cdm(ipe/bps)) + * @reserved: reserved field + * @hw_ver: major, minor and incr values of a device version + */ +struct cam_icp_dev_ver { + uint32_t dev_type; + uint32_t reserved; + struct cam_hw_version hw_ver; +}; + +/** + * struct cam_icp_ver - ICP version info + * + * This strcuture is used for fw and api version + * this is used to get firmware version and api version from firmware + * and use this info in CAM_QUERY_CAP IOCTL + * + * @major: FW version major + * @minor: FW version minor + * @revision: FW version increment + */ +struct cam_icp_ver { + uint32_t major; + uint32_t minor; + uint32_t revision; + uint32_t reserved; +}; + +/** + * struct cam_icp_query_cap_cmd - ICP query device capability payload + * + * @dev_iommu_handle: icp iommu handles for secure/non secure modes + * @cdm_iommu_handle: iommu handles for secure/non secure modes + * @fw_version: firmware version info + * @api_version: api version info + * @num_ipe: number of ipes + * @num_bps: number of bps + * @dev_ver: returned device capability array + */ +struct cam_icp_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + struct cam_icp_ver fw_version; + struct cam_icp_ver api_version; + uint32_t num_ipe; + uint32_t num_bps; + struct cam_icp_dev_ver dev_ver[CAM_ICP_DEV_TYPE_MAX]; +}; + +/** + * struct cam_icp_res_info - ICP output resource info + * + * @format: format of the resource + * @width: width in pixels + * @height: height in lines + * @fps: fps + */ +struct cam_icp_res_info { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t fps; +}; + +/** + * struct cam_icp_acquire_dev_info - An ICP device info + * + * @scratch_mem_size: Output param - size of scratch memory + * @dev_type: device type (IPE_RT/IPE_NON_RT/BPS) + * @io_config_cmd_size: size of IO config command + * @io_config_cmd_handle: IO config command for each acquire + * @secure_mode: camera mode (secure/non secure) + * @chain_info: chaining info of FW device handles + * @in_res: resource info used for clock and bandwidth calculation + * @num_out_res: number of output resources + * @out_res: output resource + */ +struct cam_icp_acquire_dev_info { + uint32_t scratch_mem_size; + uint32_t dev_type; + uint32_t io_config_cmd_size; + int32_t io_config_cmd_handle; + uint32_t secure_mode; + int32_t chain_info; + struct cam_icp_res_info in_res; + uint32_t num_out_res; + struct cam_icp_res_info out_res[1]; +} __attribute__((__packed__)); + +#endif /* __UAPI_CAM_ICP_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_isp.h b/techpack/camera/include/uapi/media/cam_isp.h new file mode 100644 index 0000000000000000000000000000000000000000..e4778cfc9cc2fe797e45bb8eb6348732f73155e5 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_isp.h @@ -0,0 +1,711 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_H__ +#define __UAPI_CAM_ISP_H__ + +#include <media/cam_defs.h> +#include <media/cam_isp_vfe.h> +#include <media/cam_isp_ife.h> +#include <media/cam_cpas.h> + +/* ISP driver name */ +#define CAM_ISP_DEV_NAME "cam-isp" + +/* HW type */ +#define CAM_ISP_HW_BASE 0 +#define CAM_ISP_HW_CSID 1 +#define CAM_ISP_HW_VFE 2 +#define CAM_ISP_HW_IFE 3 +#define CAM_ISP_HW_ISPIF 4 +#define CAM_ISP_HW_MAX 5 + +/* Color Pattern */ +#define CAM_ISP_PATTERN_BAYER_RGRGRG 0 +#define CAM_ISP_PATTERN_BAYER_GRGRGR 1 +#define CAM_ISP_PATTERN_BAYER_BGBGBG 2 +#define CAM_ISP_PATTERN_BAYER_GBGBGB 3 +#define CAM_ISP_PATTERN_YUV_YCBYCR 4 +#define CAM_ISP_PATTERN_YUV_YCRYCB 5 +#define CAM_ISP_PATTERN_YUV_CBYCRY 6 +#define CAM_ISP_PATTERN_YUV_CRYCBY 7 +#define CAM_ISP_PATTERN_MAX 8 + +/* Usage Type */ +#define CAM_ISP_RES_USAGE_SINGLE 0 +#define CAM_ISP_RES_USAGE_DUAL 1 +#define CAM_ISP_RES_USAGE_MAX 2 + +/* Resource ID */ +#define CAM_ISP_RES_ID_PORT 0 +#define CAM_ISP_RES_ID_CLK 1 +#define CAM_ISP_RES_ID_MAX 2 + +/* Resource Type - Type of resource for the resource id + * defined in cam_isp_vfe.h, cam_isp_ife.h + */ + +/* Lane Type in input resource for Port */ +#define CAM_ISP_LANE_TYPE_DPHY 0 +#define CAM_ISP_LANE_TYPE_CPHY 1 +#define CAM_ISP_LANE_TYPE_MAX 2 + +/* ISP Resurce Composite Group ID */ +#define CAM_ISP_RES_COMP_GROUP_NONE 0 +#define CAM_ISP_RES_COMP_GROUP_ID_0 1 +#define CAM_ISP_RES_COMP_GROUP_ID_1 2 +#define CAM_ISP_RES_COMP_GROUP_ID_2 3 +#define CAM_ISP_RES_COMP_GROUP_ID_3 4 +#define CAM_ISP_RES_COMP_GROUP_ID_4 5 +#define CAM_ISP_RES_COMP_GROUP_ID_5 6 +#define CAM_ISP_RES_COMP_GROUP_ID_MAX 6 + +/* ISP packet opcode for ISP */ +#define CAM_ISP_PACKET_OP_BASE 0 +#define CAM_ISP_PACKET_INIT_DEV 1 +#define CAM_ISP_PACKET_UPDATE_DEV 2 +#define CAM_ISP_PACKET_OP_MAX 3 + +/* ISP packet meta_data type for command buffer */ +#define CAM_ISP_PACKET_META_BASE 0 +#define CAM_ISP_PACKET_META_LEFT 1 +#define CAM_ISP_PACKET_META_RIGHT 2 +#define CAM_ISP_PACKET_META_COMMON 3 +#define CAM_ISP_PACKET_META_DMI_LEFT 4 +#define CAM_ISP_PACKET_META_DMI_RIGHT 5 +#define CAM_ISP_PACKET_META_DMI_COMMON 6 +#define CAM_ISP_PACKET_META_CLOCK 7 +#define CAM_ISP_PACKET_META_CSID 8 +#define CAM_ISP_PACKET_META_DUAL_CONFIG 9 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_LEFT 10 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_RIGHT 11 +#define CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON 12 +#define CAM_ISP_PACKET_META_REG_DUMP_PER_REQUEST 13 +#define CAM_ISP_PACKET_META_REG_DUMP_ON_FLUSH 14 +#define CAM_ISP_PACKET_META_REG_DUMP_ON_ERROR 15 + +/* DSP mode */ +#define CAM_ISP_DSP_MODE_NONE 0 +#define CAM_ISP_DSP_MODE_ONE_WAY 1 +#define CAM_ISP_DSP_MODE_ROUND 2 + +/* ISP Generic Cmd Buffer Blob types */ +#define CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG 2 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG 3 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 4 +#define CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG 5 +#define CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_IFE_CORE_CONFIG 7 +#define CAM_ISP_GENERIC_BLOB_TYPE_VFE_OUT_CONFIG 8 +#define CAM_ISP_GENERIC_BLOB_TYPE_BW_CONFIG_V2 9 +#define CAM_ISP_GENERIC_BLOB_TYPE_CSID_QCFA_CONFIG 12 + +#define CAM_ISP_VC_DT_CFG 4 + +#define CAM_ISP_IFE0_HW 0x1 +#define CAM_ISP_IFE1_HW 0x2 +#define CAM_ISP_IFE0_LITE_HW 0x4 +#define CAM_ISP_IFE1_LITE_HW 0x8 +#define CAM_ISP_IFE2_LITE_HW 0x10 + +#define CAM_ISP_PXL_PATH 0x1 +#define CAM_ISP_PPP_PATH 0x2 +#define CAM_ISP_LCR_PATH 0x4 +#define CAM_ISP_RDI0_PATH 0x8 +#define CAM_ISP_RDI1_PATH 0x10 +#define CAM_ISP_RDI2_PATH 0x20 +#define CAM_ISP_RDI3_PATH 0x40 + +/* Per Path Usage Data */ +#define CAM_ISP_USAGE_INVALID 0 +#define CAM_ISP_USAGE_LEFT_PX 1 +#define CAM_ISP_USAGE_RIGHT_PX 2 +#define CAM_ISP_USAGE_RDI 3 + +/* Acquire with custom hw */ +#define CAM_ISP_ACQ_CUSTOM_NONE 0 +#define CAM_ISP_ACQ_CUSTOM_PRIMARY 1 +#define CAM_ISP_ACQ_CUSTOM_SECONDARY 2 + +/* Query devices */ +/** + * struct cam_isp_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Hardware type for the cap info + * @reserved: reserved field for alignment + * @hw_version: Hardware version + * + */ +struct cam_isp_dev_cap_info { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_version; +}; + +/** + * struct cam_isp_query_cap_cmd - ISP query device capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_isp_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_isp_dev_cap_info dev_caps[CAM_ISP_HW_MAX]; +}; + +/* Acquire Device */ +/** + * struct cam_isp_out_port_info - An output port resource info + * + * @res_type: output resource type defined in file + * cam_isp_vfe.h or cam_isp_ife.h + * @format: output format of the resource + * @wdith: output width in pixels + * @height: output height in lines + * @comp_grp_id: composite group id for the resource. + * @split_point: split point in pixels for the dual VFE. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @reserved: reserved field for alignment + * + */ +struct cam_isp_out_port_info { + uint32_t res_type; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t comp_grp_id; + uint32_t split_point; + uint32_t secure_mode; + uint32_t reserved; +}; + +/** + * struct cam_isp_out_port_info_v2 - An output port resource info + * + * @res_type: output resource type defined in file + * cam_isp_vfe.h or cam_isp_ife.h + * @format: output format of the resource + * @wdith: output width in pixels + * @height: output height in lines + * @comp_grp_id: composite group id for the resource. + * @split_point: split point in pixels for the dual VFE. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @wm_mode: WM mode + * @out_port_res1: Output reserved field + * @out_port_res2: Output reserved field + * + */ +struct cam_isp_out_port_info_v2 { + uint32_t res_type; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t comp_grp_id; + uint32_t split_point; + uint32_t secure_mode; + uint32_t wm_mode; + uint32_t out_port_res1; + uint32_t out_port_res2; +}; + +/** + * struct cam_isp_in_port_info - An input port resource info + * + * @res_type: input resource type define in file + * cam_isp_vfe.h or cam_isp_ife.h + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @format: input format + * @test_pattern: test pattern for the testgen + * @usage_type: whether dual vfe is required + * @left_start: left input start offset in pixels + * @left_stop: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual VFE + * @right_stop: right input stop offset in pixels. + * Only for Dual VFE + * @right_width: right input width in pixels. + * Only for dual VFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @pixel_clk; sensor output clock + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode (Defines as CAM_ISP_DSP_MODE_*) + * @hbi_cnt: HBI count for the camif input + * @reserved: Reserved field for alignment + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources + * + */ +struct cam_isp_in_port_info { + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc; + uint32_t dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t hbi_cnt; + uint32_t reserved; + uint32_t num_out_res; + struct cam_isp_out_port_info data[1]; +}; + +/** + * struct cam_isp_in_port_info_v2 - An input port resource info + * + * @res_type: input resource type define in file + * cam_isp_vfe.h or cam_isp_ife.h + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @num_valid_vc_dt: valid vc and dt in array + * @format: input format + * @test_pattern: test pattern for the testgen + * @usage_type: whether dual vfe is required + * @left_start: left input start offset in pixels + * @left_stop: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual VFE + * @right_stop: right input stop offset in pixels. + * only for Dual VFE + * @right_width: right input width in pixels. + * only for dual VFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @pixel_clk; sensor output clock + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode (Defines as CAM_ISP_DSP_MODE_*) + * @hbi_cnt: HBI count for the camif input + * @cust_node: if any custom HW block is present before IFE + * @num_out_res: number of the output resource associated + * @horizontal_bin: Horizontal Binning info + * @qcfa_bin: Quadra Binning info + * @csid_res_1: payload for future use + * @csid_res_2: payload for future use + * @ife_res_1: payload for future use + * @ife_res_2: payload for future use + * @data: payload that contains the output resources + * + */ +struct cam_isp_in_port_info_v2 { + uint32_t res_type; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc[CAM_ISP_VC_DT_CFG]; + uint32_t dt[CAM_ISP_VC_DT_CFG]; + uint32_t num_valid_vc_dt; + uint32_t format; + uint32_t test_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_stop; + uint32_t left_width; + uint32_t right_start; + uint32_t right_stop; + uint32_t right_width; + uint32_t line_start; + uint32_t line_stop; + uint32_t height; + uint32_t pixel_clk; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t hbi_cnt; + uint32_t cust_node; + uint32_t num_out_res; + uint32_t offline_mode; + uint32_t horizontal_bin; + uint32_t qcfa_bin; + uint32_t csid_res_1; + uint32_t csid_res_2; + uint32_t ife_res_1; + uint32_t ife_res_2; + struct cam_isp_out_port_info_v2 data[1]; +}; + +/** + * struct cam_isp_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array; + * + */ +struct cam_isp_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_isp_port_hfr_config - HFR configuration for this port + * + * @resource_type: Resource type + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @reserved: Reserved for alignment + */ +struct cam_isp_port_hfr_config { + uint32_t resource_type; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_resource_hfr_config - Resource HFR configuration + * + * @num_ports: Number of ports + * @reserved: Reserved for alignment + * @port_hfr_config: HFR configuration for each IO port + */ +struct cam_isp_resource_hfr_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_port_hfr_config port_hfr_config[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_dual_split_params - dual isp spilt parameters + * + * @split_point: Split point information x, where (0 < x < width) + * left ISP's input ends at x + righ padding and + * Right ISP's input starts at x - left padding + * @right_padding: Padding added past the split point for left + * ISP's input + * @left_padding: Padding added before split point for right + * ISP's input + * @reserved: Reserved filed for alignment + * + */ +struct cam_isp_dual_split_params { + uint32_t split_point; + uint32_t right_padding; + uint32_t left_padding; + uint32_t reserved; +}; + +/** + * struct cam_isp_dual_stripe_config - stripe config per bus client + * + * @offset: Start horizontal offset relative to + * output buffer + * In UBWC mode, this value indicates the H_INIT + * value in pixel + * @width: Width of the stripe in bytes + * @tileconfig Ubwc meta tile config. Contain the partial + * tile info + * @port_id: port id of ISP output + * + */ +struct cam_isp_dual_stripe_config { + uint32_t offset; + uint32_t width; + uint32_t tileconfig; + uint32_t port_id; +}; + +/** + * struct cam_isp_dual_config - dual isp configuration + * + * @num_ports Number of isp output ports + * @reserved Reserved field for alignment + * @split_params: Inpput split parameters + * @stripes: Stripe information + * + */ +struct cam_isp_dual_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_dual_split_params split_params; + struct cam_isp_dual_stripe_config stripes[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_clock_config - Clock configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_hz: Pixel Clock for Left ISP + * @right_pix_hz: Pixel Clock for Right ISP, valid only if Dual + * @rdi_hz: RDI Clock. ISP clock will be max of RDI and + * PIX clocks. For a particular context which ISP + * HW the RDI is allocated to is not known to UMD. + * Hence pass the clock and let KMD decide. + */ +struct cam_isp_clock_config { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_hz; + uint64_t right_pix_hz; + uint64_t rdi_hz[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_csid_clock_config - CSID clock configuration + * + * @csid_clock CSID clock + */ +struct cam_isp_csid_clock_config { + uint64_t csid_clock; +} __attribute__((packed)); + +/** + * struct cam_isp_csid_qcfa_config - CSID qcfa binning support configuration + * + * @csid_binning CSID binning + */ +struct cam_isp_csid_qcfa_config { + uint32_t csid_binning; +} __attribute__((packed)); + +/** + * struct cam_isp_bw_vote - Bandwidth vote information + * + * @resource_id: Resource ID + * @reserved: Reserved field for alignment + * @cam_bw_bps: Bandwidth vote for CAMNOC + * @ext_bw_bps: Bandwidth vote for path-to-DDR after CAMNOC + */ +struct cam_isp_bw_vote { + uint32_t resource_id; + uint32_t reserved; + uint64_t cam_bw_bps; + uint64_t ext_bw_bps; +} __attribute__((packed)); + +/** + * struct cam_isp_bw_config - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_vote: Bandwidth vote for left ISP + * @right_pix_vote: Bandwidth vote for right ISP + * @rdi_vote: RDI bandwidth requirements + */ +struct cam_isp_bw_config { + uint32_t usage_type; + uint32_t num_rdi; + struct cam_isp_bw_vote left_pix_vote; + struct cam_isp_bw_vote right_pix_vote; + struct cam_isp_bw_vote rdi_vote[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_bw_config_v2 - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_paths: Number of axi data paths + * @axi_path Per path vote info + */ +struct cam_isp_bw_config_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +} __attribute__((packed)); + +/** + * struct cam_fe_config - Fetch Engine configuration + * + * @version: fetch engine veriosn + * @min_vbi: require min vbi + * @fs_mode: indicates if fs mode enabled + * @fs_line_sync_en: frame level sync or line level + * sync for fetch engine + * @hbi_count: hbi count + * @fs_sync_enable: indicates if fetch engine working + * wokring in sync with write engine + * @go_cmd_sel: softwrae go_cmd or hw go_cmd + * @client_enable: enable read engine + * @source_addr: adrress of buffer to read from + * @width: buffer width + * @height: buffer height + * @stride: buffer stride (here equal to width) + * @format: format of image in buffer + * @unpacker_cfg: unpacker config type + * @latency_buf_size: latency buffer for read engine + */ +struct cam_fe_config { + uint64_t version; + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t fs_line_sync_en; + uint32_t hbi_count; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; + uint32_t client_enable; + uint32_t source_addr; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t unpacker_cfg; + uint32_t latency_buf_size; +} __attribute__((packed)); + +/** + * struct cam_isp_core_config - ISP core registers configuration + * + * @version: Version info + * @vid_ds16_r2pd: Enables Y and C merging PD output for video DS16 + * @vid_ds4_r2pd: Enables Y and C merging PD output for video DS4 + * @disp_ds16_r2pd: Enables Y and C merging PD output for disp DS16 + * @disp_ds4_r2pd: Enables Y and C merging PD output for disp DS4 + * @dsp_streaming_tap_point: This selects source for DSP streaming interface + * @ihist_src_sel: Selects input for IHIST module + * @hdr_be_src_sel: Selects input for HDR BE module + * @hdr_bhist_src_sel: Selects input for HDR BHIST module + * @input_mux_sel_pdaf: Selects input for PDAF + * @input_mux_sel_pp: Selects input for Pixel Pipe + * @reserved: Reserved + */ +struct cam_isp_core_config { + uint32_t version; + uint32_t vid_ds16_r2pd; + uint32_t vid_ds4_r2pd; + uint32_t disp_ds16_r2pd; + uint32_t disp_ds4_r2pd; + uint32_t dsp_streaming_tap_point; + uint32_t ihist_src_sel; + uint32_t hdr_be_src_sel; + uint32_t hdr_bhist_src_sel; + uint32_t input_mux_sel_pdaf; + uint32_t input_mux_sel_pp; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_acquire_hw_info - ISP acquire HW params + * + * @common_info_version : Version of common info struct used + * @common_info_size : Size of common info struct used + * @common_info_offset : Offset of common info from start of data + * @num_inputs : Number of inputs + * @input_info_version : Version of input info struct used + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @data : Start of data region + */ +struct cam_isp_acquire_hw_info { + uint16_t common_info_version; + uint16_t common_info_size; + uint32_t common_info_offset; + uint32_t num_inputs; + uint32_t input_info_version; + uint32_t input_info_size; + uint32_t input_info_offset; + uint64_t data; +}; + +/** + * struct cam_isp_vfe_wm_config - VFE write master config per port + * + * @port_type : Unique ID of output port + * @wm_mode : Write master mode + * 0x0 - Line based mode + * 0x1 - Frame based mode + * 0x2 - Index based mode, valid for BAF only + * @h_init : Horizontal starting coordinate in pixels. Must be a + * multiple of 3 for TP10 format + * @height : Height in pixels + * @width : Width in pixels + * @virtual_frame_en : Enabling virtual frame will prevent actual request from + * being sent to NOC + * @stride : Write master stride + * @offset : Write master offset + * @reserved_1 : Reserved field for Write master config + * @reserved_2 : Reserved field for Write master config + * @reserved_3 : Reserved field for Write master config + * @reserved_4 : Reserved field for Write master config + */ +struct cam_isp_vfe_wm_config { + uint32_t port_type; + uint32_t wm_mode; + uint32_t h_init; + uint32_t height; + uint32_t width; + uint32_t virtual_frame_en; + uint32_t stride; + uint32_t offset; + uint32_t reserved_1; + uint32_t reserved_2; + uint32_t reserved_3; + uint32_t reserved_4; +}; + +/** + * struct cam_isp_vfe_out_config - VFE write master config + * + * @num_ports : Number of ports + * @reserved : Reserved field + * @wm_config : VFE out config + */ +struct cam_isp_vfe_out_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_vfe_wm_config wm_config[1]; +}; + +#define CAM_ISP_ACQUIRE_COMMON_VER0 0x1000 + +#define CAM_ISP_ACQUIRE_COMMON_SIZE_VER0 0x0 + +#define CAM_ISP_ACQUIRE_INPUT_VER0 0x2000 + +#define CAM_ISP_ACQUIRE_INPUT_SIZE_VER0 sizeof(struct cam_isp_in_port_info) + +#define CAM_ISP_ACQUIRE_OUT_VER0 0x3000 + +#define CAM_ISP_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_out_port_info) + +#endif /* __UAPI_CAM_ISP_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_isp_ife.h b/techpack/camera/include/uapi/media/cam_isp_ife.h new file mode 100644 index 0000000000000000000000000000000000000000..34c1b3bd2bfe5ec6bec97a5c50fca78864085d7f --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_isp_ife.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_IFE_H__ +#define __UAPI_CAM_ISP_IFE_H__ + +/* IFE output port resource type (global unique)*/ +#define CAM_ISP_IFE_OUT_RES_BASE 0x3000 + +#define CAM_ISP_IFE_OUT_RES_FULL (CAM_ISP_IFE_OUT_RES_BASE + 0) +#define CAM_ISP_IFE_OUT_RES_DS4 (CAM_ISP_IFE_OUT_RES_BASE + 1) +#define CAM_ISP_IFE_OUT_RES_DS16 (CAM_ISP_IFE_OUT_RES_BASE + 2) +#define CAM_ISP_IFE_OUT_RES_RAW_DUMP (CAM_ISP_IFE_OUT_RES_BASE + 3) +#define CAM_ISP_IFE_OUT_RES_FD (CAM_ISP_IFE_OUT_RES_BASE + 4) +#define CAM_ISP_IFE_OUT_RES_PDAF (CAM_ISP_IFE_OUT_RES_BASE + 5) +#define CAM_ISP_IFE_OUT_RES_RDI_0 (CAM_ISP_IFE_OUT_RES_BASE + 6) +#define CAM_ISP_IFE_OUT_RES_RDI_1 (CAM_ISP_IFE_OUT_RES_BASE + 7) +#define CAM_ISP_IFE_OUT_RES_RDI_2 (CAM_ISP_IFE_OUT_RES_BASE + 8) +#define CAM_ISP_IFE_OUT_RES_RDI_3 (CAM_ISP_IFE_OUT_RES_BASE + 9) +#define CAM_ISP_IFE_OUT_RES_STATS_HDR_BE (CAM_ISP_IFE_OUT_RES_BASE + 10) +#define CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_IFE_OUT_RES_BASE + 11) +#define CAM_ISP_IFE_OUT_RES_STATS_TL_BG (CAM_ISP_IFE_OUT_RES_BASE + 12) +#define CAM_ISP_IFE_OUT_RES_STATS_BF (CAM_ISP_IFE_OUT_RES_BASE + 13) +#define CAM_ISP_IFE_OUT_RES_STATS_AWB_BG (CAM_ISP_IFE_OUT_RES_BASE + 14) +#define CAM_ISP_IFE_OUT_RES_STATS_BHIST (CAM_ISP_IFE_OUT_RES_BASE + 15) +#define CAM_ISP_IFE_OUT_RES_STATS_RS (CAM_ISP_IFE_OUT_RES_BASE + 16) +#define CAM_ISP_IFE_OUT_RES_STATS_CS (CAM_ISP_IFE_OUT_RES_BASE + 17) +#define CAM_ISP_IFE_OUT_RES_STATS_IHIST (CAM_ISP_IFE_OUT_RES_BASE + 18) +#define CAM_ISP_IFE_OUT_RES_FULL_DISP (CAM_ISP_IFE_OUT_RES_BASE + 19) +#define CAM_ISP_IFE_OUT_RES_DS4_DISP (CAM_ISP_IFE_OUT_RES_BASE + 20) +#define CAM_ISP_IFE_OUT_RES_DS16_DISP (CAM_ISP_IFE_OUT_RES_BASE + 21) +#define CAM_ISP_IFE_OUT_RES_2PD (CAM_ISP_IFE_OUT_RES_BASE + 22) +#define CAM_ISP_IFE_OUT_RES_RDI_RD (CAM_ISP_IFE_OUT_RES_BASE + 23) +#define CAM_ISP_IFE_OUT_RES_LCR (CAM_ISP_IFE_OUT_RES_BASE + 24) + +#define CAM_ISP_IFE_OUT_RES_MAX (CAM_ISP_IFE_OUT_RES_BASE + 25) + + +/* IFE input port resource type (global unique) */ +#define CAM_ISP_IFE_IN_RES_BASE 0x4000 + +#define CAM_ISP_IFE_IN_RES_TPG (CAM_ISP_IFE_IN_RES_BASE + 0) +#define CAM_ISP_IFE_IN_RES_PHY_0 (CAM_ISP_IFE_IN_RES_BASE + 1) +#define CAM_ISP_IFE_IN_RES_PHY_1 (CAM_ISP_IFE_IN_RES_BASE + 2) +#define CAM_ISP_IFE_IN_RES_PHY_2 (CAM_ISP_IFE_IN_RES_BASE + 3) +#define CAM_ISP_IFE_IN_RES_PHY_3 (CAM_ISP_IFE_IN_RES_BASE + 4) +#define CAM_ISP_IFE_IN_RES_PHY_4 (CAM_ISP_IFE_IN_RES_BASE + 5) +#define CAM_ISP_IFE_IN_RES_PHY_5 (CAM_ISP_IFE_IN_RES_BASE + 6) +#define CAM_ISP_IFE_IN_RES_RD (CAM_ISP_IFE_IN_RES_BASE + 7) +#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 8) + +#endif /* __UAPI_CAM_ISP_IFE_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_isp_tfe.h b/techpack/camera/include/uapi/media/cam_isp_tfe.h new file mode 100644 index 0000000000000000000000000000000000000000..407124644bcc66f69dc686d8217d895d83fd0f0e --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_isp_tfe.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_TFE_H__ +#define __UAPI_CAM_ISP_TFE_H__ + +/* TFE output port resource id number */ +#define CAM_ISP_TFE_OUT_RES_BASE 0x1 + +#define CAM_ISP_TFE_OUT_RES_FULL (CAM_ISP_TFE_OUT_RES_BASE + 0) +#define CAM_ISP_TFE_OUT_RES_RAW_DUMP (CAM_ISP_TFE_OUT_RES_BASE + 1) +#define CAM_ISP_TFE_OUT_RES_PDAF (CAM_ISP_TFE_OUT_RES_BASE + 2) +#define CAM_ISP_TFE_OUT_RES_RDI_0 (CAM_ISP_TFE_OUT_RES_BASE + 3) +#define CAM_ISP_TFE_OUT_RES_RDI_1 (CAM_ISP_TFE_OUT_RES_BASE + 4) +#define CAM_ISP_TFE_OUT_RES_RDI_2 (CAM_ISP_TFE_OUT_RES_BASE + 5) +#define CAM_ISP_TFE_OUT_RES_STATS_HDR_BE (CAM_ISP_TFE_OUT_RES_BASE + 6) +#define CAM_ISP_TFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_TFE_OUT_RES_BASE + 7) +#define CAM_ISP_TFE_OUT_RES_STATS_TL_BG (CAM_ISP_TFE_OUT_RES_BASE + 8) +#define CAM_ISP_TFE_OUT_RES_STATS_BF (CAM_ISP_TFE_OUT_RES_BASE + 9) +#define CAM_ISP_TFE_OUT_RES_STATS_AWB_BG (CAM_ISP_TFE_OUT_RES_BASE + 10) +#define CAM_ISP_TFE_OUT_RES_MAX (CAM_ISP_TFE_OUT_RES_BASE + 11) + + +/* TFE input port resource type */ +#define CAM_ISP_TFE_IN_RES_BASE 0x1 + +#define CAM_ISP_TFE_IN_RES_TPG (CAM_ISP_TFE_IN_RES_BASE + 0) +#define CAM_ISP_TFE_IN_RES_PHY_0 (CAM_ISP_TFE_IN_RES_BASE + 1) +#define CAM_ISP_TFE_IN_RES_PHY_1 (CAM_ISP_TFE_IN_RES_BASE + 2) +#define CAM_ISP_TFE_IN_RES_PHY_2 (CAM_ISP_TFE_IN_RES_BASE + 3) +#define CAM_ISP_TFE_IN_RES_MAX (CAM_ISP_TFE_IN_RES_BASE + 4) + +#endif /* __UAPI_CAM_ISP_TFE_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_isp_vfe.h b/techpack/camera/include/uapi/media/cam_isp_vfe.h new file mode 100644 index 0000000000000000000000000000000000000000..497093902ba35f6ba49386c18b284f9d2df8f4ca --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_isp_vfe.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_ISP_VFE_H__ +#define __UAPI_CAM_ISP_VFE_H__ + +/* VFE output port resource type (global unique) */ +#define CAM_ISP_VFE_OUT_RES_BASE 0x1000 + +#define CAM_ISP_VFE_OUT_RES_ENC (CAM_ISP_VFE_OUT_RES_BASE + 0) +#define CAM_ISP_VFE_OUT_RES_VIEW (CAM_ISP_VFE_OUT_RES_BASE + 1) +#define CAM_ISP_VFE_OUT_RES_VID (CAM_ISP_VFE_OUT_RES_BASE + 2) +#define CAM_ISP_VFE_OUT_RES_RDI_0 (CAM_ISP_VFE_OUT_RES_BASE + 3) +#define CAM_ISP_VFE_OUT_RES_RDI_1 (CAM_ISP_VFE_OUT_RES_BASE + 4) +#define CAM_ISP_VFE_OUT_RES_RDI_2 (CAM_ISP_VFE_OUT_RES_BASE + 5) +#define CAM_ISP_VFE_OUT_RES_RDI_3 (CAM_ISP_VFE_OUT_RES_BASE + 6) +#define CAM_ISP_VFE_OUT_RES_STATS_AEC (CAM_ISP_VFE_OUT_RES_BASE + 7) +#define CAM_ISP_VFE_OUT_RES_STATS_AF (CAM_ISP_VFE_OUT_RES_BASE + 8) +#define CAM_ISP_VFE_OUT_RES_STATS_AWB (CAM_ISP_VFE_OUT_RES_BASE + 9) +#define CAM_ISP_VFE_OUT_RES_STATS_RS (CAM_ISP_VFE_OUT_RES_BASE + 10) +#define CAM_ISP_VFE_OUT_RES_STATS_CS (CAM_ISP_VFE_OUT_RES_BASE + 11) +#define CAM_ISP_VFE_OUT_RES_STATS_IHIST (CAM_ISP_VFE_OUT_RES_BASE + 12) +#define CAM_ISP_VFE_OUT_RES_STATS_SKIN (CAM_ISP_VFE_OUT_RES_BASE + 13) +#define CAM_ISP_VFE_OUT_RES_STATS_BG (CAM_ISP_VFE_OUT_RES_BASE + 14) +#define CAM_ISP_VFE_OUT_RES_STATS_BF (CAM_ISP_VFE_OUT_RES_BASE + 15) +#define CAM_ISP_VFE_OUT_RES_STATS_BE (CAM_ISP_VFE_OUT_RES_BASE + 16) +#define CAM_ISP_VFE_OUT_RES_STATS_BHIST (CAM_ISP_VFE_OUT_RES_BASE + 17) +#define CAM_ISP_VFE_OUT_RES_STATS_BF_SCALE (CAM_ISP_VFE_OUT_RES_BASE + 18) +#define CAM_ISP_VFE_OUT_RES_STATS_HDR_BE (CAM_ISP_VFE_OUT_RES_BASE + 19) +#define CAM_ISP_VFE_OUT_RES_STATS_HDR_BHIST (CAM_ISP_VFE_OUT_RES_BASE + 20) +#define CAM_ISP_VFE_OUT_RES_STATS_AEC_BG (CAM_ISP_VFE_OUT_RES_BASE + 21) +#define CAM_ISP_VFE_OUT_RES_CAMIF_RAW (CAM_ISP_VFE_OUT_RES_BASE + 22) +#define CAM_ISP_VFE_OUT_RES_IDEAL_RAW (CAM_ISP_VFE_OUT_RES_BASE + 23) +#define CAM_ISP_VFE_OUT_RES_MAX (CAM_ISP_VFE_OUT_RES_BASE + 24) + +/* VFE input port_ resource type (global unique) */ +#define CAM_ISP_VFE_IN_RES_BASE 0x2000 + +#define CAM_ISP_VFE_IN_RES_TPG (CAM_ISP_VFE_IN_RES_BASE + 0) +#define CAM_ISP_VFE_IN_RES_PHY_0 (CAM_ISP_VFE_IN_RES_BASE + 1) +#define CAM_ISP_VFE_IN_RES_PHY_1 (CAM_ISP_VFE_IN_RES_BASE + 2) +#define CAM_ISP_VFE_IN_RES_PHY_2 (CAM_ISP_VFE_IN_RES_BASE + 3) +#define CAM_ISP_VFE_IN_RES_PHY_3 (CAM_ISP_VFE_IN_RES_BASE + 4) +#define CAM_ISP_VFE_IN_RES_PHY_4 (CAM_ISP_VFE_IN_RES_BASE + 5) +#define CAM_ISP_VFE_IN_RES_PHY_5 (CAM_ISP_VFE_IN_RES_BASE + 6) +#define CAM_ISP_VFE_IN_RES_FE (CAM_ISP_VFE_IN_RES_BASE + 7) +#define CAM_ISP_VFE_IN_RES_MAX (CAM_ISP_VFE_IN_RES_BASE + 8) + +#endif /* __UAPI_CAM_ISP_VFE_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_jpeg.h b/techpack/camera/include/uapi/media/cam_jpeg.h new file mode 100644 index 0000000000000000000000000000000000000000..fd0ed2a2cfdb3d8ce31ee3bd1a8470aeac063860 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_jpeg.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_JPEG_H__ +#define __UAPI_CAM_JPEG_H__ + +#include <media/cam_defs.h> + +/* enc, dma, cdm(enc/dma) are used in querycap */ +#define CAM_JPEG_DEV_TYPE_ENC 0 +#define CAM_JPEG_DEV_TYPE_DMA 1 +#define CAM_JPEG_DEV_TYPE_MAX 2 + +#define CAM_JPEG_NUM_DEV_PER_RES_MAX 1 + +/* definitions needed for jpeg aquire device */ +#define CAM_JPEG_RES_TYPE_ENC 0 +#define CAM_JPEG_RES_TYPE_DMA 1 +#define CAM_JPEG_RES_TYPE_MAX 2 + +/* packet opcode types */ +#define CAM_JPEG_OPCODE_ENC_UPDATE 0 +#define CAM_JPEG_OPCODE_DMA_UPDATE 1 + +/* ENC input port resource type */ +#define CAM_JPEG_ENC_INPUT_IMAGE 0x0 + +/* ENC output port resource type */ +#define CAM_JPEG_ENC_OUTPUT_IMAGE 0x1 + +#define CAM_JPEG_ENC_IO_IMAGES_MAX 0x2 + +/* DMA input port resource type */ +#define CAM_JPEG_DMA_INPUT_IMAGE 0x0 + +/* DMA output port resource type */ +#define CAM_JPEG_DMA_OUTPUT_IMAGE 0x1 + +#define CAM_JPEG_DMA_IO_IMAGES_MAX 0x2 + +#define CAM_JPEG_IMAGE_MAX 0x2 + +/** + * struct cam_jpeg_dev_ver - Device information for particular hw type + * + * This is used to get device version info of JPEG ENC, JPEG DMA + * from hardware and use this info in CAM_QUERY_CAP IOCTL + * + * @size : Size of struct passed + * @dev_type: Hardware type for the cap info(jpeg enc, jpeg dma) + * @hw_ver: Major, minor and incr values of a device version + */ +struct cam_jpeg_dev_ver { + uint32_t size; + uint32_t dev_type; + struct cam_hw_version hw_ver; +}; + +/** + * struct cam_jpeg_query_cap_cmd - JPEG query device capability payload + * + * @dev_iommu_handle: Jpeg iommu handles for secure/non secure + * modes + * @cdm_iommu_handle: Iommu handles for secure/non secure modes + * @num_enc: Number of encoder + * @num_dma: Number of dma + * @dev_ver: Returned device capability array + */ +struct cam_jpeg_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + uint32_t num_enc; + uint32_t num_dma; + struct cam_jpeg_dev_ver dev_ver[CAM_JPEG_DEV_TYPE_MAX]; +}; + +/** + * struct cam_jpeg_res_info - JPEG output resource info + * + * @format: Format of the resource + * @width: Width in pixels + * @height: Height in lines + * @fps: Fps + */ +struct cam_jpeg_res_info { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t fps; +}; + +/** + * struct cam_jpeg_acquire_dev_info - An JPEG device info + * + * @dev_type: Device type (ENC/DMA) + * @reserved: Reserved Bytes + * @in_res: In resource info + * @in_res: Iut resource info + */ +struct cam_jpeg_acquire_dev_info { + uint32_t dev_type; + uint32_t reserved; + struct cam_jpeg_res_info in_res; + struct cam_jpeg_res_info out_res; +}; + +/** + * struct cam_jpeg_config_inout_param_info - JPEG Config time + * input output params + * + * @clk_index: Input Param- clock selection index.(-1 default) + * @output_size: Output Param - jpeg encode/dma output size in + * bytes + */ +struct cam_jpeg_config_inout_param_info { + int32_t clk_index; + int32_t output_size; +}; + +#endif /* __UAPI_CAM_JPEG_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_lrme.h b/techpack/camera/include/uapi/media/cam_lrme.h new file mode 100644 index 0000000000000000000000000000000000000000..e3bd9449f7ef8a8899942d496dad8d96f4d39d43 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_lrme.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_LRME_H__ +#define __UAPI_CAM_LRME_H__ + +#include <media/cam_defs.h> + +/* LRME Resource Types */ + +enum CAM_LRME_IO_TYPE { + CAM_LRME_IO_TYPE_TAR, + CAM_LRME_IO_TYPE_REF, + CAM_LRME_IO_TYPE_RES, + CAM_LRME_IO_TYPE_DS2, +}; + +#define CAM_LRME_INPUT_PORT_TYPE_TAR (1 << 0) +#define CAM_LRME_INPUT_PORT_TYPE_REF (1 << 1) + +#define CAM_LRME_OUTPUT_PORT_TYPE_DS2 (1 << 0) +#define CAM_LRME_OUTPUT_PORT_TYPE_RES (1 << 1) + +#define CAM_LRME_DEV_MAX 1 + + +struct cam_lrme_hw_version { + uint32_t gen; + uint32_t rev; + uint32_t step; +}; + +struct cam_lrme_dev_cap { + struct cam_lrme_hw_version clc_hw_version; + struct cam_lrme_hw_version bus_rd_hw_version; + struct cam_lrme_hw_version bus_wr_hw_version; + struct cam_lrme_hw_version top_hw_version; + struct cam_lrme_hw_version top_titan_version; +}; + +/** + * struct cam_lrme_query_cap_cmd - LRME query device capability payload + * + * @dev_iommu_handle: LRME iommu handles for secure/non secure + * modes + * @cdm_iommu_handle: Iommu handles for secure/non secure modes + * @num_devices: number of hardware devices + * @dev_caps: Returned device capability array + */ +struct cam_lrme_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + uint32_t num_devices; + struct cam_lrme_dev_cap dev_caps[CAM_LRME_DEV_MAX]; +}; + +struct cam_lrme_soc_info { + uint64_t clock_rate; + uint64_t bandwidth; + uint64_t reserved[4]; +}; + +struct cam_lrme_acquire_args { + struct cam_lrme_soc_info lrme_soc_info; +}; + +#endif /* __UAPI_CAM_LRME_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_ope.h b/techpack/camera/include/uapi/media/cam_ope.h new file mode 100644 index 0000000000000000000000000000000000000000..812212f3170b26e176c6520c7c3b15d0845ccd4d --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_ope.h @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_OPE_H__ +#define __UAPI_OPE_H__ + +#include "cam_defs.h" +#include "cam_cpas.h" + +#define OPE_DEV_NAME_SIZE 128 + +/* OPE HW TYPE */ +#define OPE_HW_TYPE_OPE 0x1 +#define OPE_HW_TYPE_OPE_CDM 0x2 +#define OPE_HW_TYPE_MAX 0x3 + +/* OPE Device type */ +#define OPE_DEV_TYPE_OPE_RT 0x1 +#define OPE_DEV_TYPE_OPE_NRT 0x2 +#define OPE_DEV_TYPE_OPE_SEMI_RT 0x3 +#define OPE_DEV_TYPE_MAX 0x4 + +/* OPE Input Res Ports */ +#define OPE_IN_RES_FULL 0x1 +#define OPE_IN_RES_MAX OPE_IN_RES_FULL + +/* OPE Output Res Ports */ +#define OPE_OUT_RES_VIDEO 0x1 +#define OPE_OUT_RES_DISP 0x2 +#define OPE_OUT_RES_ARGB 0x3 +#define OPE_OUT_RES_STATS_RS 0x4 +#define OPE_OUT_RES_STATS_IHIST 0x5 +#define OPE_OUT_RES_STATS_LTM 0x6 +#define OPE_OUT_RES_MAX OPE_OUT_RES_STATS_LTM + +/* OPE packet opcodes */ +#define OPE_OPCODE_CONFIG 0x1 + +/* OPE Command Buffer Scope */ +#define OPE_CMD_BUF_SCOPE_BATCH 0x1 +#define OPE_CMD_BUF_SCOPE_FRAME 0x2 +#define OPE_CMD_BUF_SCOPE_PASS 0x3 +#define OPE_CMD_BUF_SCOPE_STRIPE 0x4 + +/* OPE Command Buffer Types */ +#define OPE_CMD_BUF_TYPE_DIRECT 0x1 +#define OPE_CMD_BUF_TYPE_INDIRECT 0x2 + +/* OPE Command Buffer Usage */ +#define OPE_CMD_BUF_UMD 0x1 +#define OPE_CMD_BUF_KMD 0x2 +#define OPE_CMD_BUF_DEBUG 0x3 + +/* OPE Single/Double Buffered */ +#define OPE_CMD_BUF_SINGLE_BUFFERED 0x1 +#define OPE_CMD_BUF_DOUBLE_BUFFERED 0x2 + +/* Command meta types */ +#define OPE_CMD_META_GENERIC_BLOB 0x1 + +/* Generic blob types */ +#define OPE_CMD_GENERIC_BLOB_CLK_V2 0x1 + +/* Stripe location */ +#define OPE_STRIPE_FULL 0x0 +#define OPE_STRIPE_LEFT 0x1 +#define OPE_STRIPE_RIGHT 0x2 +#define OPE_STRIPE_MIDDLE 0x3 + +#define OPE_MAX_CMD_BUFS 64 +#define OPE_MAX_IO_BUFS (OPE_OUT_RES_MAX + OPE_IN_RES_MAX) +#define OPE_MAX_PASS 1 +#define OPE_MAX_PLANES 2 +#define OPE_MAX_STRIPES 48 +#define OPE_MAX_BATCH_SIZE 16 + +/** + * struct ope_stripe_info - OPE stripe Info + * + * @offset: Offset in Bytes + * @x_init: X_init + * @stripe_location: Stripe location (OPE_STRIPE_XXX) + * @width: Width of a stripe + * @height: Height of a stripe + * @disable_bus: Flag to disable BUS master + * @reserved: Reserved + * + */ +struct ope_stripe_info { + uint32_t offset; + uint32_t x_init; + uint32_t stripe_location; + uint32_t width; + uint32_t height; + uint32_t disable_bus; + uint32_t reserved; +}; + +/** + * struct ope_io_buf_info - OPE IO buffers meta + * + * @direction: Direction of a buffer of a port(Input/Output) + * @resource_type: Port type + * @num_planes: Number of planes for a port + * @reserved: Reserved + * @num_stripes: Stripes per plane + * @mem_handle: Memhandles of each Input/Output Port + * @plane_offset: Offsets of planes + * @length: Length of a plane buffer + * @plane_stride: Plane stride + * @height: Height of a plane buffer + * @format: Format + * @fence: Fence of a Port + * @stripe_info: Stripe Info + * + */ +struct ope_io_buf_info { + uint32_t direction; + uint32_t resource_type; + uint32_t num_planes; + uint32_t reserved; + uint32_t num_stripes[OPE_MAX_PLANES]; + uint32_t mem_handle[OPE_MAX_PLANES]; + uint32_t plane_offset[OPE_MAX_PLANES]; + uint32_t length[OPE_MAX_PLANES]; + uint32_t plane_stride[OPE_MAX_PLANES]; + uint32_t height[OPE_MAX_PLANES]; + uint32_t format; + uint32_t fence; + struct ope_stripe_info stripe_info[OPE_MAX_PLANES][OPE_MAX_STRIPES]; +}; + +/** + * struct ope_frame_set - OPE frameset + * + * @num_io_bufs: Number of I/O buffers + * @reserved: Reserved + * @io_buf: IO buffer info for all Input and Output ports + * + */ +struct ope_frame_set { + uint32_t num_io_bufs; + uint32_t reserved; + struct ope_io_buf_info io_buf[OPE_MAX_IO_BUFS]; +}; + +/** + * struct ope_cmd_buf_info - OPE command buffer meta + * + * @mem_handle: Memory handle for command buffer + * @offset: Offset of a command buffer + * @size: Size of command buffer + * @length: Length of a command buffer + * @cmd_buf_scope : Scope of a command buffer (OPE_CMD_BUF_SCOPE_XXX) + * @type: Command buffer type (OPE_CMD_BUF_TYPE_XXX) + * @cmd_buf_usage: Usage of command buffer ( OPE_CMD_BUF_USAGE_XXX) + * @stripe_idx: Stripe index in a req, It is valid for SCOPE_STRIPE + * @cmd_buf_pass_idx: Pass index + * @prefetch_disable: Prefecth disable flag + * + */ + +struct ope_cmd_buf_info { + uint32_t mem_handle; + uint32_t offset; + uint32_t size; + uint32_t length; + uint32_t cmd_buf_scope; + uint32_t type; + uint32_t cmd_buf_usage; + uint32_t cmd_buf_buffered; + uint32_t stripe_idx; + uint32_t cmd_buf_pass_idx; + uint32_t prefetch_disable; +}; + +/** + * struct ope_packet_payload - payload for a request + * + * @num_cmd_bufs: Number of command buffers + * @batch_size: Batch size in HFR mode + * @ope_cmd_buf_info: Command buffer meta data + * @ope_io_buf_info: Io buffer Info + * + */ +struct ope_frame_process { + uint32_t num_cmd_bufs[OPE_MAX_BATCH_SIZE]; + uint32_t batch_size; + struct ope_cmd_buf_info cmd_buf[OPE_MAX_BATCH_SIZE][OPE_MAX_CMD_BUFS]; + struct ope_frame_set frame_set[OPE_MAX_BATCH_SIZE]; +}; + +/** + * struct ope_clk_bw_request_v2 - clock and bandwidth for a request + * + * @budget_ns: Time required to process frame + * @frame_cycles: Frame cycles needed to process the frame + * @rt_flag: Flag to indicate real time stream + * @reserved: For memory alignment + * @axi_path: Per path vote info for OPE + * + */ +struct ope_clk_bw_request_v2 { + uint64_t budget_ns; + uint32_t frame_cycles; + uint32_t rt_flag; + uint32_t reserved; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +}; + +/** + * struct ope_hw_ver - Device information for OPE + * + * This is used to get device version info of + * OPE, CDM and use this info in CAM_QUERY_CAP IOCTL + * + * @hw_type: Hardware type for the cap info(OPE_HW_TYPE_XXX) + * @reserved: Reserved field + * @hw_ver: Major, minor and incr values of a hardware version + * + */ +struct ope_hw_ver { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_ver; +}; + +/** + * struct ope_query_cap_cmd - OPE query device capability payload + * + * @dev_iommu_handle: OPE iommu handles for secure/non secure modes + * @cdm_iommu_handle: CDM iommu handles for secure/non secure modes + * @num_ope: Number of OPEs + * @reserved: Reserved Parameter + * @hw_ver: Hardware capability array + */ +struct ope_query_cap_cmd { + struct cam_iommu_handle dev_iommu_handle; + struct cam_iommu_handle cdm_iommu_handle; + uint32_t num_ope; + uint32_t reserved; + struct ope_hw_ver hw_ver[OPE_DEV_TYPE_MAX]; +}; + +/** + * struct ope_out_res_info - OPE Output resource info + * + * @res_id: Resource ID + * @format: Output resource format + * @width: Output width + * @height: Output Height + * @alignment: Alignment + * @packer_format: Packer format + * @subsample_period: Subsample period in HFR + * @subsample_pattern: Subsample pattern in HFR + * @pixel_pattern: Pixel pattern + * @reserved: Reserved Parameter + * + */ +struct ope_out_res_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t alignment; + uint32_t packer_format; + uint32_t subsample_period; + uint32_t subsample_pattern; + uint32_t pixel_pattern; + uint32_t reserved; +}; + +/** + * struct ope_in_res_info - OPE Input resource info + * + * @res_id: Resource ID + * @format: Input resource format + * @width: Input width + * @height: Input Height + * @pixel_pattern: Pixel pattern + * @alignment: Alignment + * @unpacker_format: Unpacker format + * @max_stripe_size: Max stripe size supported for this instance configuration + * @fps: Frames per second + * @reserved: Reserved Parameter + * + */ +struct ope_in_res_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t pixel_pattern; + uint32_t alignment; + uint32_t unpacker_format; + uint32_t max_stripe_size; + uint32_t fps; + uint32_t reserved; +}; + +/** + * struct ope_acquire_dev_info - OPE Acquire Info + * + * @hw_type: OPE HW Types (OPE) + * @dev_type: Nature of Device Instance (RT/NRT) + * @dev_name: Name of Device Instance + * @nrt_stripes_for_arb: Program num stripes in OPE CDM for NRT device + * before setting ARB bit + * @secure_mode: Mode of Device operation (Secure or Non Secure) + * @batch_size: Batch size + * @num_in_res: Number of input resources (OPE_IN_RES_XXX) + * @in_res: Input resource info + * @num_out_res: Number of output resources (OPE_OUT_RES_XXX) + * @reserved: Reserved Parameter + * @out_res: Output resource info + * + */ +struct ope_acquire_dev_info { + uint32_t hw_type; + uint32_t dev_type; + char dev_name[OPE_DEV_NAME_SIZE]; + uint32_t nrt_stripes_for_arb; + uint32_t secure_mode; + uint32_t batch_size; + uint32_t num_in_res; + struct ope_in_res_info in_res[OPE_IN_RES_MAX]; + uint32_t num_out_res; + uint32_t reserved; + struct ope_out_res_info out_res[OPE_OUT_RES_MAX]; +} __attribute__((__packed__)); + +#endif /* __UAPI_OPE_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_req_mgr.h b/techpack/camera/include/uapi/media/cam_req_mgr.h new file mode 100644 index 0000000000000000000000000000000000000000..5bab420a7b023a3f425de2e7a5cb2443cb08e4c2 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_req_mgr.h @@ -0,0 +1,476 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_LINUX_CAM_REQ_MGR_H +#define __UAPI_LINUX_CAM_REQ_MGR_H + +#include <linux/videodev2.h> +#include <linux/types.h> +#include <linux/ioctl.h> +#include <linux/media.h> +#include <media/cam_defs.h> + +#define CAM_REQ_MGR_VNODE_NAME "cam-req-mgr-devnode" + +#define CAM_DEVICE_TYPE_BASE (MEDIA_ENT_F_OLD_BASE) +#define CAM_VNODE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE) +#define CAM_SENSOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 1) +#define CAM_IFE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 2) +#define CAM_ICP_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 3) +#define CAM_LRME_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 4) +#define CAM_JPEG_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 5) +#define CAM_FD_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 6) +#define CAM_CPAS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 7) +#define CAM_CSIPHY_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 8) +#define CAM_ACTUATOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 9) +#define CAM_CCI_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 10) +#define CAM_FLASH_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 11) +#define CAM_EEPROM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 12) +#define CAM_OIS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 13) +#define CAM_CUSTOM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 14) + +/* cam_req_mgr hdl info */ +#define CAM_REQ_MGR_HDL_IDX_POS 8 +#define CAM_REQ_MGR_HDL_IDX_MASK ((1 << CAM_REQ_MGR_HDL_IDX_POS) - 1) +#define CAM_REQ_MGR_GET_HDL_IDX(hdl) (hdl & CAM_REQ_MGR_HDL_IDX_MASK) + +/** + * Max handles supported by cam_req_mgr + * It includes both session and device handles + */ +#define CAM_REQ_MGR_MAX_HANDLES 64 +#define CAM_REQ_MGR_MAX_HANDLES_V2 128 +#define MAX_LINKS_PER_SESSION 2 + +/* V4L event type which user space will subscribe to */ +#define V4L_EVENT_CAM_REQ_MGR_EVENT (V4L2_EVENT_PRIVATE_START + 0) + +/* Specific event ids to get notified in user space */ +#define V4L_EVENT_CAM_REQ_MGR_SOF 0 +#define V4L_EVENT_CAM_REQ_MGR_ERROR 1 +#define V4L_EVENT_CAM_REQ_MGR_SOF_BOOT_TS 2 + +/* SOF Event status */ +#define CAM_REQ_MGR_SOF_EVENT_SUCCESS 0 +#define CAM_REQ_MGR_SOF_EVENT_ERROR 1 + +/* Link control operations */ +#define CAM_REQ_MGR_LINK_ACTIVATE 0 +#define CAM_REQ_MGR_LINK_DEACTIVATE 1 + +/** + * Request Manager : flush_type + * @CAM_REQ_MGR_FLUSH_TYPE_ALL: Req mgr will remove all the pending + * requests from input/processing queue. + * @CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ: Req mgr will remove only particular + * request id from input/processing queue. + * @CAM_REQ_MGR_FLUSH_TYPE_MAX: Max number of the flush type + * @opcode: CAM_REQ_MGR_FLUSH_REQ + */ +#define CAM_REQ_MGR_FLUSH_TYPE_ALL 0 +#define CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ 1 +#define CAM_REQ_MGR_FLUSH_TYPE_MAX 2 + +/** + * Request Manager : Sync Mode type + * @CAM_REQ_MGR_SYNC_MODE_NO_SYNC: Req mgr will apply non-sync mode for this + * request. + * @CAM_REQ_MGR_SYNC_MODE_SYNC: Req mgr will apply sync mode for this request. + */ +#define CAM_REQ_MGR_SYNC_MODE_NO_SYNC 0 +#define CAM_REQ_MGR_SYNC_MODE_SYNC 1 + +/** + * struct cam_req_mgr_event_data + * @session_hdl: session handle + * @link_hdl: link handle + * @frame_id: frame id + * @reserved: reserved for 64 bit aligngment + * @req_id: request id + * @tv_sec: timestamp in seconds + * @tv_usec: timestamp in micro seconds + */ +struct cam_req_mgr_event_data { + int32_t session_hdl; + int32_t link_hdl; + int32_t frame_id; + int32_t reserved; + int64_t req_id; + uint64_t tv_sec; + uint64_t tv_usec; +}; + +/** + * struct cam_req_mgr_session_info + * @session_hdl: In/Output param - session_handle + * @opcode1: CAM_REQ_MGR_CREATE_SESSION + * @opcode2: CAM_REQ_MGR_DESTROY_SESSION + */ +struct cam_req_mgr_session_info { + int32_t session_hdl; + int32_t reserved; +}; + +/** + * struct cam_req_mgr_link_info + * @session_hdl: Input param - Identifier for CSL session + * @num_devices: Input Param - Num of devices to be linked + * @dev_hdls: Input param - List of device handles to be linked + * @link_hdl: Output Param -Identifier for link + * @opcode: CAM_REQ_MGR_LINK + */ +struct cam_req_mgr_link_info { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES]; + int32_t link_hdl; +}; + +struct cam_req_mgr_link_info_v2 { + int32_t session_hdl; + uint32_t num_devices; + int32_t dev_hdls[CAM_REQ_MGR_MAX_HANDLES_V2]; + int32_t link_hdl; +}; + +struct cam_req_mgr_ver_info { + uint32_t version; + union { + struct cam_req_mgr_link_info link_info_v1; + struct cam_req_mgr_link_info_v2 link_info_v2; + } u; +}; +/** + * struct cam_req_mgr_unlink_info + * @session_hdl: input param - session handle + * @link_hdl: input param - link handle + * @opcode: CAM_REQ_MGR_UNLINK + */ +struct cam_req_mgr_unlink_info { + int32_t session_hdl; + int32_t link_hdl; +}; + +/** + * struct cam_req_mgr_flush_info + * @brief: User can tell drivers to flush a particular request id or + * flush all requests from its pending processing queue. Flush is a + * blocking call and driver shall ensure all requests are flushed + * before returning. + * @session_hdl: Input param - Identifier for CSL session + * @link_hdl: Input Param -Identifier for link + * @flush_type: User can cancel a particular req id or can flush + * all requests in queue + * @reserved: reserved for 64 bit aligngment + * @req_id: field is valid only if flush type is cancel request + * for flush all this field value is not considered. + * @opcode: CAM_REQ_MGR_FLUSH_REQ + */ +struct cam_req_mgr_flush_info { + int32_t session_hdl; + int32_t link_hdl; + uint32_t flush_type; + uint32_t reserved; + int64_t req_id; +}; + +/** struct cam_req_mgr_sched_info + * @session_hdl: Input param - Identifier for CSL session + * @link_hdl: Input Param -Identifier for link + * inluding itself. + * @bubble_enable: Input Param - Cam req mgr will do bubble recovery if this + * flag is set. + * @sync_mode: Type of Sync mode for this request + * @additional_timeout: Additional timeout value (in ms) associated with + * this request. This value needs to be 0 in cases where long exposure is + * not configured for the sensor.The max timeout that will be supported + * is 50000 ms + * @reserved: Reserved + * @req_id: Input Param - Request Id from which all requests will be flushed + */ +struct cam_req_mgr_sched_request { + int32_t session_hdl; + int32_t link_hdl; + int32_t bubble_enable; + int32_t sync_mode; + int32_t additional_timeout; + int32_t reserved; + int64_t req_id; +}; + +/** + * struct cam_req_mgr_sync_mode + * @session_hdl: Input param - Identifier for CSL session + * @sync_mode: Input Param - Type of sync mode + * @num_links: Input Param - Num of links in sync mode (Valid only + * when sync_mode is one of SYNC enabled modes) + * @link_hdls: Input Param - Array of link handles to be in sync mode + * (Valid only when sync_mode is one of SYNC + * enabled modes) + * @master_link_hdl: Input Param - To dictate which link's SOF drives system + * (Valid only when sync_mode is one of SYNC + * enabled modes) + * + * @opcode: CAM_REQ_MGR_SYNC_MODE + */ +struct cam_req_mgr_sync_mode { + int32_t session_hdl; + int32_t sync_mode; + int32_t num_links; + int32_t link_hdls[MAX_LINKS_PER_SESSION]; + int32_t master_link_hdl; + int32_t reserved; +}; + +/** + * struct cam_req_mgr_link_control + * @ops: Link operations: activate/deactive + * @session_hdl: Input param - Identifier for CSL session + * @num_links: Input Param - Num of links + * @reserved: reserved field + * @link_hdls: Input Param - Links to be activated/deactivated + * + * @opcode: CAM_REQ_MGR_LINK_CONTROL + */ +struct cam_req_mgr_link_control { + int32_t ops; + int32_t session_hdl; + int32_t num_links; + int32_t reserved; + int32_t link_hdls[MAX_LINKS_PER_SESSION]; +}; + +/** + * cam_req_mgr specific opcode ids + */ +#define CAM_REQ_MGR_CREATE_DEV_NODES (CAM_COMMON_OPCODE_MAX + 1) +#define CAM_REQ_MGR_CREATE_SESSION (CAM_COMMON_OPCODE_MAX + 2) +#define CAM_REQ_MGR_DESTROY_SESSION (CAM_COMMON_OPCODE_MAX + 3) +#define CAM_REQ_MGR_LINK (CAM_COMMON_OPCODE_MAX + 4) +#define CAM_REQ_MGR_UNLINK (CAM_COMMON_OPCODE_MAX + 5) +#define CAM_REQ_MGR_SCHED_REQ (CAM_COMMON_OPCODE_MAX + 6) +#define CAM_REQ_MGR_FLUSH_REQ (CAM_COMMON_OPCODE_MAX + 7) +#define CAM_REQ_MGR_SYNC_MODE (CAM_COMMON_OPCODE_MAX + 8) +#define CAM_REQ_MGR_ALLOC_BUF (CAM_COMMON_OPCODE_MAX + 9) +#define CAM_REQ_MGR_MAP_BUF (CAM_COMMON_OPCODE_MAX + 10) +#define CAM_REQ_MGR_RELEASE_BUF (CAM_COMMON_OPCODE_MAX + 11) +#define CAM_REQ_MGR_CACHE_OPS (CAM_COMMON_OPCODE_MAX + 12) +#define CAM_REQ_MGR_LINK_CONTROL (CAM_COMMON_OPCODE_MAX + 13) +#define CAM_REQ_MGR_LINK_V2 (CAM_COMMON_OPCODE_MAX + 14) +/* end of cam_req_mgr opcodes */ + +#define CAM_MEM_FLAG_HW_READ_WRITE (1<<0) +#define CAM_MEM_FLAG_HW_READ_ONLY (1<<1) +#define CAM_MEM_FLAG_HW_WRITE_ONLY (1<<2) +#define CAM_MEM_FLAG_KMD_ACCESS (1<<3) +#define CAM_MEM_FLAG_UMD_ACCESS (1<<4) +#define CAM_MEM_FLAG_PROTECTED_MODE (1<<5) +#define CAM_MEM_FLAG_CMD_BUF_TYPE (1<<6) +#define CAM_MEM_FLAG_PIXEL_BUF_TYPE (1<<7) +#define CAM_MEM_FLAG_STATS_BUF_TYPE (1<<8) +#define CAM_MEM_FLAG_PACKET_BUF_TYPE (1<<9) +#define CAM_MEM_FLAG_CACHE (1<<10) +#define CAM_MEM_FLAG_HW_SHARED_ACCESS (1<<11) +#define CAM_MEM_FLAG_CDSP_OUTPUT (1<<12) +#define CAM_MEM_FLAG_DISABLE_DELAYED_UNMAP (1<<13) + +#define CAM_MEM_MMU_MAX_HANDLE 16 + +/* Maximum allowed buffers in existence */ +#define CAM_MEM_BUFQ_MAX 1024 + +#define CAM_MEM_MGR_SECURE_BIT_POS 15 +#define CAM_MEM_MGR_HDL_IDX_SIZE 15 +#define CAM_MEM_MGR_HDL_FD_SIZE 16 +#define CAM_MEM_MGR_HDL_IDX_END_POS 16 +#define CAM_MEM_MGR_HDL_FD_END_POS 32 + +#define CAM_MEM_MGR_HDL_IDX_MASK ((1 << CAM_MEM_MGR_HDL_IDX_SIZE) - 1) + +#define GET_MEM_HANDLE(idx, fd) \ + ((idx & CAM_MEM_MGR_HDL_IDX_MASK) | \ + (fd << (CAM_MEM_MGR_HDL_FD_END_POS - CAM_MEM_MGR_HDL_FD_SIZE))) \ + +#define GET_FD_FROM_HANDLE(hdl) \ + (hdl >> (CAM_MEM_MGR_HDL_FD_END_POS - CAM_MEM_MGR_HDL_FD_SIZE)) \ + +#define CAM_MEM_MGR_GET_HDL_IDX(hdl) (hdl & CAM_MEM_MGR_HDL_IDX_MASK) + +#define CAM_MEM_MGR_SET_SECURE_HDL(hdl, flag) \ + ((flag) ? (hdl |= (1 << CAM_MEM_MGR_SECURE_BIT_POS)) : \ + ((hdl) &= ~(1 << CAM_MEM_MGR_SECURE_BIT_POS))) + +#define CAM_MEM_MGR_IS_SECURE_HDL(hdl) \ + (((hdl) & \ + (1<<CAM_MEM_MGR_SECURE_BIT_POS)) >> CAM_MEM_MGR_SECURE_BIT_POS) + +/** + * memory allocation type + */ +#define CAM_MEM_DMA_NONE 0 +#define CAM_MEM_DMA_BIDIRECTIONAL 1 +#define CAM_MEM_DMA_TO_DEVICE 2 +#define CAM_MEM_DMA_FROM_DEVICE 3 + + +/** + * memory cache operation + */ +#define CAM_MEM_CLEAN_CACHE 1 +#define CAM_MEM_INV_CACHE 2 +#define CAM_MEM_CLEAN_INV_CACHE 3 + + +/** + * struct cam_mem_alloc_out_params + * @buf_handle: buffer handle + * @fd: output buffer file descriptor + * @vaddr: virtual address pointer + */ +struct cam_mem_alloc_out_params { + uint32_t buf_handle; + int32_t fd; + uint64_t vaddr; +}; + +/** + * struct cam_mem_map_out_params + * @buf_handle: buffer handle + * @reserved: reserved for future + * @vaddr: virtual address pointer + */ +struct cam_mem_map_out_params { + uint32_t buf_handle; + uint32_t reserved; + uint64_t vaddr; +}; + +/** + * struct cam_mem_mgr_alloc_cmd + * @len: size of buffer to allocate + * @align: alignment of the buffer + * @mmu_hdls: array of mmu handles + * @num_hdl: number of handles + * @flags: flags of the buffer + * @out: out params + */ +/* CAM_REQ_MGR_ALLOC_BUF */ +struct cam_mem_mgr_alloc_cmd { + uint64_t len; + uint64_t align; + int32_t mmu_hdls[CAM_MEM_MMU_MAX_HANDLE]; + uint32_t num_hdl; + uint32_t flags; + struct cam_mem_alloc_out_params out; +}; + +/** + * struct cam_mem_mgr_map_cmd + * @mmu_hdls: array of mmu handles + * @num_hdl: number of handles + * @flags: flags of the buffer + * @fd: output buffer file descriptor + * @reserved: reserved field + * @out: out params + */ + +/* CAM_REQ_MGR_MAP_BUF */ +struct cam_mem_mgr_map_cmd { + int32_t mmu_hdls[CAM_MEM_MMU_MAX_HANDLE]; + uint32_t num_hdl; + uint32_t flags; + int32_t fd; + uint32_t reserved; + struct cam_mem_map_out_params out; +}; + +/** + * struct cam_mem_mgr_map_cmd + * @buf_handle: buffer handle + * @reserved: reserved field + */ +/* CAM_REQ_MGR_RELEASE_BUF */ +struct cam_mem_mgr_release_cmd { + int32_t buf_handle; + uint32_t reserved; +}; + +/** + * struct cam_mem_mgr_map_cmd + * @buf_handle: buffer handle + * @ops: cache operations + */ +/* CAM_REQ_MGR_CACHE_OPS */ +struct cam_mem_cache_ops_cmd { + int32_t buf_handle; + uint32_t mem_cache_ops; +}; + +/** + * Request Manager : error message type + * @CAM_REQ_MGR_ERROR_TYPE_DEVICE: Device error message, fatal to session + * @CAM_REQ_MGR_ERROR_TYPE_REQUEST: Error on a single request, not fatal + * @CAM_REQ_MGR_ERROR_TYPE_BUFFER: Buffer was not filled, not fatal + * @CAM_REQ_MGR_ERROR_TYPE_RECOVERY: Fatal error, can be recovered + * @CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE: SOF freeze, can be recovered + */ +#define CAM_REQ_MGR_ERROR_TYPE_DEVICE 0 +#define CAM_REQ_MGR_ERROR_TYPE_REQUEST 1 +#define CAM_REQ_MGR_ERROR_TYPE_BUFFER 2 +#define CAM_REQ_MGR_ERROR_TYPE_RECOVERY 3 +#define CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE 4 + +/** + * struct cam_req_mgr_error_msg + * @error_type: type of error + * @request_id: request id of frame + * @device_hdl: device handle + * @linke_hdl: link_hdl + * @resource_size: size of the resource + */ +struct cam_req_mgr_error_msg { + uint32_t error_type; + uint32_t request_id; + int32_t device_hdl; + int32_t link_hdl; + uint64_t resource_size; +}; + +/** + * struct cam_req_mgr_frame_msg + * @request_id: request id of the frame + * @frame_id: frame id of the frame + * @timestamp: timestamp of the frame + * @link_hdl: link handle associated with this message + * @sof_status: sof status success or fail + * @frame_id_meta: refers to the meta for + * that frame in specific usecases + * @reserved: reserved + */ +struct cam_req_mgr_frame_msg { + uint64_t request_id; + uint64_t frame_id; + uint64_t timestamp; + int32_t link_hdl; + uint32_t sof_status; + uint32_t frame_id_meta; + uint32_t reserved; +}; + +/** + * struct cam_req_mgr_message + * @session_hdl: session to which the frame belongs to + * @reserved: reserved field + * @u: union which can either be error or frame message + */ +struct cam_req_mgr_message { + int32_t session_hdl; + int32_t reserved; + union { + struct cam_req_mgr_error_msg err_msg; + struct cam_req_mgr_frame_msg frame_msg; + } u; +}; +#endif /* __UAPI_LINUX_CAM_REQ_MGR_H */ diff --git a/techpack/camera/include/uapi/media/cam_sensor.h b/techpack/camera/include/uapi/media/cam_sensor.h new file mode 100644 index 0000000000000000000000000000000000000000..cc86f2706c6321705ae1a6fbddf3c05370f30c77 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_sensor.h @@ -0,0 +1,486 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_SENSOR_H__ +#define __UAPI_CAM_SENSOR_H__ + +#include <linux/types.h> +#include <linux/ioctl.h> +#include <media/cam_defs.h> + +#define CAM_SENSOR_PROBE_CMD (CAM_COMMON_OPCODE_MAX + 1) +#define CAM_FLASH_MAX_LED_TRIGGERS 3 +#define MAX_OIS_NAME_SIZE 32 +#define CAM_CSIPHY_SECURE_MODE_ENABLED 1 +/** + * struct cam_sensor_query_cap - capabilities info for sensor + * + * @slot_info : Indicates about the slotId or cell Index + * @secure_camera : Camera is in secure/Non-secure mode + * @pos_pitch : Sensor position pitch + * @pos_roll : Sensor position roll + * @pos_yaw : Sensor position yaw + * @actuator_slot_id : Actuator slot id which connected to sensor + * @eeprom_slot_id : EEPROM slot id which connected to sensor + * @ois_slot_id : OIS slot id which connected to sensor + * @flash_slot_id : Flash slot id which connected to sensor + * @csiphy_slot_id : CSIphy slot id which connected to sensor + * + */ +struct cam_sensor_query_cap { + uint32_t slot_info; + uint32_t secure_camera; + uint32_t pos_pitch; + uint32_t pos_roll; + uint32_t pos_yaw; + uint32_t actuator_slot_id; + uint32_t eeprom_slot_id; + uint32_t ois_slot_id; + uint32_t flash_slot_id; + uint32_t csiphy_slot_id; +} __attribute__((packed)); + +/** + * struct cam_csiphy_query_cap - capabilities info for csiphy + * + * @slot_info : Indicates about the slotId or cell Index + * @version : CSIphy version + * @clk lane : Of the 5 lanes, informs lane configured + * as clock lane + * @reserved + */ +struct cam_csiphy_query_cap { + uint32_t slot_info; + uint32_t version; + uint32_t clk_lane; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_actuator_query_cap - capabilities info for actuator + * + * @slot_info : Indicates about the slotId or cell Index + * @reserved + */ +struct cam_actuator_query_cap { + uint32_t slot_info; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_eeprom_query_cap_t - capabilities info for eeprom + * + * @slot_info : Indicates about the slotId or cell Index + * @eeprom_kernel_probe : Indicates about the kernel or userspace probe + */ +struct cam_eeprom_query_cap_t { + uint32_t slot_info; + uint16_t eeprom_kernel_probe; + uint16_t is_multimodule_mode; +} __attribute__((packed)); + +/** + * struct cam_ois_query_cap_t - capabilities info for ois + * + * @slot_info : Indicates about the slotId or cell Index + */ +struct cam_ois_query_cap_t { + uint32_t slot_info; + uint16_t reserved; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_info - Contains slave I2C related info + * + * @slave_addr : Slave address + * @i2c_freq_mode : 4 bits are used for I2c freq mode + * @cmd_type : Explains type of command + */ +struct cam_cmd_i2c_info { + uint32_t slave_addr; + uint8_t i2c_freq_mode; + uint8_t cmd_type; + uint16_t reserved; +} __attribute__((packed)); + +/** + * struct cam_ois_opcode - Contains OIS opcode + * + * @prog : OIS FW prog register address + * @coeff : OIS FW coeff register address + * @pheripheral : OIS pheripheral + * @memory : OIS memory + */ +struct cam_ois_opcode { + uint32_t prog; + uint32_t coeff; + uint32_t pheripheral; + uint32_t memory; +} __attribute__((packed)); + +/** + * struct cam_cmd_ois_info - Contains OIS slave info + * + * @slave_addr : OIS i2c slave address + * @i2c_freq_mode : i2c frequency mode + * @cmd_type : Explains type of command + * @ois_fw_flag : indicates if fw is present or not + * @is_ois_calib : indicates the calibration data is available + * @ois_name : OIS name + * @opcode : opcode + */ +struct cam_cmd_ois_info { + uint32_t slave_addr; + uint8_t i2c_freq_mode; + uint8_t cmd_type; + uint8_t ois_fw_flag; + uint8_t is_ois_calib; + char ois_name[MAX_OIS_NAME_SIZE]; + struct cam_ois_opcode opcode; +} __attribute__((packed)); + +/** + * struct cam_cmd_probe - Contains sensor slave info + * + * @data_type : Slave register data type + * @addr_type : Slave register address type + * @op_code : Don't Care + * @cmd_type : Explains type of command + * @reg_addr : Slave register address + * @expected_data : Data expected at slave register address + * @data_mask : Data mask if only few bits are valid + * @camera_id : Indicates the slot to which camera + * needs to be probed + * @reserved + */ +struct cam_cmd_probe { + uint8_t data_type; + uint8_t addr_type; + uint8_t op_code; + uint8_t cmd_type; + uint32_t reg_addr; + uint32_t expected_data; + uint32_t data_mask; + uint16_t camera_id; + uint16_t reserved; +} __attribute__((packed)); + +/** + * struct cam_power_settings - Contains sensor power setting info + * + * @power_seq_type : Type of power sequence + * @reserved + * @config_val_low : Lower 32 bit value configuration value + * @config_val_high : Higher 32 bit value configuration value + * + */ +struct cam_power_settings { + uint16_t power_seq_type; + uint16_t reserved; + uint32_t config_val_low; + uint32_t config_val_high; +} __attribute__((packed)); + +/** + * struct cam_cmd_power - Explains about the power settings + * + * @count : Number of power settings follows + * @reserved + * @cmd_type : Explains type of command + * @power_settings : Contains power setting info + */ +struct cam_cmd_power { + uint32_t count; + uint8_t reserved; + uint8_t cmd_type; + uint16_t more_reserved; + struct cam_power_settings power_settings[1]; +} __attribute__((packed)); + +/** + * struct i2c_rdwr_header - header of READ/WRITE I2C command + * + * @ count : Number of registers / data / reg-data pairs + * @ op_code : Operation code + * @ cmd_type : Command buffer type + * @ data_type : I2C data type + * @ addr_type : I2C address type + * @ reserved + */ +struct i2c_rdwr_header { + uint32_t count; + uint8_t op_code; + uint8_t cmd_type; + uint8_t data_type; + uint8_t addr_type; +} __attribute__((packed)); + +/** + * struct i2c_random_wr_payload - payload for I2C random write + * + * @ reg_addr : Register address + * @ reg_data : Register data + * + */ +struct i2c_random_wr_payload { + uint32_t reg_addr; + uint32_t reg_data; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_random_wr - I2C random write command + * @ header : header of READ/WRITE I2C command + * @ random_wr_payload : payload for I2C random write + */ +struct cam_cmd_i2c_random_wr { + struct i2c_rdwr_header header; + struct i2c_random_wr_payload random_wr_payload[1]; +} __attribute__((packed)); + +/** + * struct cam_cmd_read - I2C read command + * @ reg_data : Register data + * @ reserved + */ +struct cam_cmd_read { + uint32_t reg_data; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_continuous_wr - I2C continuous write command + * @ header : header of READ/WRITE I2C command + * @ reg_addr : Register address + * @ data_read : I2C read command + */ +struct cam_cmd_i2c_continuous_wr { + struct i2c_rdwr_header header; + uint32_t reg_addr; + struct cam_cmd_read data_read[1]; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_random_rd - I2C random read command + * @ header : header of READ/WRITE I2C command + * @ data_read : I2C read command + */ +struct cam_cmd_i2c_random_rd { + struct i2c_rdwr_header header; + struct cam_cmd_read data_read[1]; +} __attribute__((packed)); + +/** + * struct cam_cmd_i2c_continuous_rd - I2C continuous continuous read command + * @ header : header of READ/WRITE I2C command + * @ reg_addr : Register address + * + */ +struct cam_cmd_i2c_continuous_rd { + struct i2c_rdwr_header header; + uint32_t reg_addr; +} __attribute__((packed)); + +/** + * struct cam_cmd_conditional_wait - Conditional wait command + * @data_type : Data type + * @addr_type : Address type + * @op_code : Opcode + * @cmd_type : Explains type of command + * @timeout : Timeout for retries + * @reserved + * @reg_addr : Register Address + * @reg_data : Register data + * @data_mask : Data mask if only few bits are valid + * @camera_id : Indicates the slot to which camera + * needs to be probed + * + */ +struct cam_cmd_conditional_wait { + uint8_t data_type; + uint8_t addr_type; + uint16_t reserved; + uint8_t op_code; + uint8_t cmd_type; + uint16_t timeout; + uint32_t reg_addr; + uint32_t reg_data; + uint32_t data_mask; +} __attribute__((packed)); + +/** + * struct cam_cmd_unconditional_wait - Un-conditional wait command + * @delay : Delay + * @op_code : Opcode + * @cmd_type : Explains type of command + */ +struct cam_cmd_unconditional_wait { + int16_t delay; + int16_t reserved; + uint8_t op_code; + uint8_t cmd_type; + uint16_t reserved1; +} __attribute__((packed)); + +/** + * cam_csiphy_info: Provides cmdbuffer structre + * @lane_mask : Lane mask details + * @lane_assign : Lane sensor will be using + * @csiphy_3phase : Total number of lanes + * @combo_mode : Info regarding combo_mode is enable / disable + * @lane_cnt : Total number of lanes + * @secure_mode : Secure mode flag to enable / disable + * @3phase : Details whether 3Phase / 2Phase operation + * @settle_time : Settling time in ms + * @data_rate : Data rate + * + */ +struct cam_csiphy_info { + uint16_t lane_mask; + uint16_t lane_assign; + uint8_t csiphy_3phase; + uint8_t combo_mode; + uint8_t lane_cnt; + uint8_t secure_mode; + uint64_t settle_time; + uint64_t data_rate; +} __attribute__((packed)); + +/** + * cam_csiphy_acquire_dev_info : Information needed for + * csiphy at the time of acquire + * @combo_mode : Indicates the device mode of operation + * @reserved + * + */ +struct cam_csiphy_acquire_dev_info { + uint32_t combo_mode; + uint32_t reserved; +} __attribute__((packed)); + +/** + * cam_sensor_acquire_dev : Updates sensor acuire cmd + * @device_handle : Updates device handle + * @session_handle : Session handle for acquiring device + * @handle_type : Resource handle type + * @reserved + * @info_handle : Handle to additional info + * needed for sensor sub modules + * + */ +struct cam_sensor_acquire_dev { + uint32_t session_handle; + uint32_t device_handle; + uint32_t handle_type; + uint32_t reserved; + uint64_t info_handle; +} __attribute__((packed)); + +/** + * cam_sensor_streamon_dev : StreamOn command for the sensor + * @session_handle : Session handle for acquiring device + * @device_handle : Updates device handle + * @handle_type : Resource handle type + * @reserved + * @info_handle : Information Needed at the time of streamOn + * + */ +struct cam_sensor_streamon_dev { + uint32_t session_handle; + uint32_t device_handle; + uint32_t handle_type; + uint32_t reserved; + uint64_t info_handle; +} __attribute__((packed)); + +/** + * struct cam_flash_init : Init command for the flash + * @flash_type : flash hw type + * @reserved + * @cmd_type : command buffer type + */ +struct cam_flash_init { + uint32_t flash_type; + uint8_t reserved; + uint8_t cmd_type; + uint16_t reserved1; +} __attribute__((packed)); + +/** + * struct cam_flash_set_rer : RedEyeReduction command buffer + * + * @count : Number of flash leds + * @opcode : Command buffer opcode + * CAM_FLASH_FIRE_RER + * @cmd_type : command buffer operation type + * @num_iteration : Number of led turn on/off sequence + * @reserved + * @led_on_delay_ms : flash led turn on time in ms + * @led_off_delay_ms : flash led turn off time in ms + * @led_current_ma : flash led current in ma + * + */ +struct cam_flash_set_rer { + uint32_t count; + uint8_t opcode; + uint8_t cmd_type; + uint16_t num_iteration; + uint32_t led_on_delay_ms; + uint32_t led_off_delay_ms; + uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; +} __attribute__((packed)); + +/** + * struct cam_flash_set_on_off : led turn on/off command buffer + * + * @count : Number of Flash leds + * @opcode : command buffer opcodes + * CAM_FLASH_FIRE_LOW + * CAM_FLASH_FIRE_HIGH + * CAM_FLASH_OFF + * @cmd_type : command buffer operation type + * @led_current_ma : flash led current in ma + * + */ +struct cam_flash_set_on_off { + uint32_t count; + uint8_t opcode; + uint8_t cmd_type; + uint16_t reserved; + uint32_t led_current_ma[CAM_FLASH_MAX_LED_TRIGGERS]; +} __attribute__((packed)); + +/** + * struct cam_flash_query_curr : query current command buffer + * + * @reserved + * @opcode : command buffer opcode + * @cmd_type : command buffer operation type + * @query_current_ma : battery current in ma + * + */ +struct cam_flash_query_curr { + uint16_t reserved; + uint8_t opcode; + uint8_t cmd_type; + uint32_t query_current_ma; +} __attribute__ ((packed)); + +/** + * struct cam_flash_query_cap : capabilities info for flash + * + * @slot_info : Indicates about the slotId or cell Index + * @max_current_flash : max supported current for flash + * @max_duration_flash : max flash turn on duration + * @max_current_torch : max supported current for torch + * + */ +struct cam_flash_query_cap_info { + uint32_t slot_info; + uint32_t max_current_flash[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t max_duration_flash[CAM_FLASH_MAX_LED_TRIGGERS]; + uint32_t max_current_torch[CAM_FLASH_MAX_LED_TRIGGERS]; +} __attribute__ ((packed)); + +#endif diff --git a/techpack/camera/include/uapi/media/cam_sync.h b/techpack/camera/include/uapi/media/cam_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..d1ab63fd4294e7a0621ebbc136cde299ef8a5914 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_sync.h @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_SYNC_H__ +#define __UAPI_CAM_SYNC_H__ + +#include <linux/videodev2.h> +#include <linux/types.h> +#include <linux/ioctl.h> +#include <linux/media.h> + +#define CAM_SYNC_DEVICE_NAME "cam_sync_device" + +/* V4L event which user space will subscribe to */ +#define CAM_SYNC_V4L_EVENT (V4L2_EVENT_PRIVATE_START + 0) + +/* Specific event ids to get notified in user space */ +#define CAM_SYNC_V4L_EVENT_ID_CB_TRIG 0 + +/* Size of opaque payload sent to kernel for safekeeping until signal time */ +#define CAM_SYNC_USER_PAYLOAD_SIZE 2 + +/* Device type for sync device needed for device discovery */ +#define CAM_SYNC_DEVICE_TYPE (MEDIA_ENT_F_OLD_BASE) + +#define CAM_SYNC_GET_PAYLOAD_PTR(ev, type) \ + (type *)((char *)ev.u.data + sizeof(struct cam_sync_ev_header)) + +#define CAM_SYNC_GET_HEADER_PTR(ev) \ + ((struct cam_sync_ev_header *)ev.u.data) + +#define CAM_SYNC_STATE_INVALID 0 +#define CAM_SYNC_STATE_ACTIVE 1 +#define CAM_SYNC_STATE_SIGNALED_SUCCESS 2 +#define CAM_SYNC_STATE_SIGNALED_ERROR 3 + +/** + * struct cam_sync_ev_header - Event header for sync event notification + * + * @sync_obj: Sync object + * @status: Status of the object + */ +struct cam_sync_ev_header { + int32_t sync_obj; + int32_t status; +}; + +/** + * struct cam_sync_info - Sync object creation information + * + * @name: Optional string representation of the sync object + * @sync_obj: Sync object returned after creation in kernel + */ +struct cam_sync_info { + char name[64]; + int32_t sync_obj; +}; + +/** + * struct cam_sync_signal - Sync object signaling struct + * + * @sync_obj: Sync object to be signaled + * @sync_state: State of the sync object to which it should be signaled + */ +struct cam_sync_signal { + int32_t sync_obj; + uint32_t sync_state; +}; + +/** + * struct cam_sync_merge - Merge information for sync objects + * + * @sync_objs: Pointer to sync objects + * @num_objs: Number of objects in the array + * @merged: Merged sync object + */ +struct cam_sync_merge { + __u64 sync_objs; + uint32_t num_objs; + int32_t merged; +}; + +/** + * struct cam_sync_userpayload_info - Payload info from user space + * + * @sync_obj: Sync object for which payload has to be registered for + * @reserved: Reserved + * @payload: Pointer to user payload + */ +struct cam_sync_userpayload_info { + int32_t sync_obj; + uint32_t reserved; + __u64 payload[CAM_SYNC_USER_PAYLOAD_SIZE]; +}; + +/** + * struct cam_sync_wait - Sync object wait information + * + * @sync_obj: Sync object to wait on + * @reserved: Reserved + * @timeout_ms: Timeout in milliseconds + */ +struct cam_sync_wait { + int32_t sync_obj; + uint32_t reserved; + uint64_t timeout_ms; +}; + +/** + * struct cam_private_ioctl_arg - Sync driver ioctl argument + * + * @id: IOCTL command id + * @size: Size of command payload + * @result: Result of command execution + * @reserved: Reserved + * @ioctl_ptr: Pointer to user data + */ +struct cam_private_ioctl_arg { + __u32 id; + __u32 size; + __u32 result; + __u32 reserved; + __u64 ioctl_ptr; +}; + +#define CAM_PRIVATE_IOCTL_CMD \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct cam_private_ioctl_arg) + +#define CAM_SYNC_CREATE 0 +#define CAM_SYNC_DESTROY 1 +#define CAM_SYNC_SIGNAL 2 +#define CAM_SYNC_MERGE 3 +#define CAM_SYNC_REGISTER_PAYLOAD 4 +#define CAM_SYNC_DEREGISTER_PAYLOAD 5 +#define CAM_SYNC_WAIT 6 + +#endif /* __UAPI_CAM_SYNC_H__ */ diff --git a/techpack/camera/include/uapi/media/cam_tfe.h b/techpack/camera/include/uapi/media/cam_tfe.h new file mode 100644 index 0000000000000000000000000000000000000000..7da5493466b06a3fc350534700b3612ffe2b1012 --- /dev/null +++ b/techpack/camera/include/uapi/media/cam_tfe.h @@ -0,0 +1,396 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __UAPI_CAM_TFE_H__ +#define __UAPI_CAM_TFE_H__ + +#include "cam_defs.h" +#include "cam_isp_tfe.h" +#include "cam_cpas.h" + + +/* ISP TFE driver name */ +#define CAM_ISP_TFE_DEV_NAME "cam-isp" + +/* HW type */ +#define CAM_ISP_TFE_HW_BASE 0 +#define CAM_ISP_TFE_HW_CSID 1 +#define CAM_ISP_TFE_HW_TFE 2 +#define CAM_ISP_TFE_HW_MAX 3 + +/* Color Pattern */ +#define CAM_ISP_TFE_PATTERN_BAYER_RGRGRG 0 +#define CAM_ISP_TFE_PATTERN_BAYER_GRGRGR 1 +#define CAM_ISP_TFE_PATTERN_BAYER_BGBGBG 2 +#define CAM_ISP_TFE_PATTERN_BAYER_GBGBGB 3 +#define CAM_ISP_TFE_PATTERN_YUV_YCBYCR 4 +#define CAM_ISP_TFE_PATTERN_YUV_YCRYCB 5 +#define CAM_ISP_TFE_PATTERN_YUV_CBYCRY 6 +#define CAM_ISP_TFE_PATTERN_YUV_CRYCBY 7 +#define CAM_ISP_TFE_PATTERN_MAX 8 + +/* Usage Type */ +#define CAM_ISP_TFE_IN_RES_USAGE_SINGLE 0 +#define CAM_ISP_TFE_IN_RES_USAGE_DUAL 1 +#define CAM_ISP_TFE_IN_RES_USAGE_MAX 2 + +/* Resource ID */ +#define CAM_ISP_TFE_RES_ID_PORT 0 +#define CAM_ISP_TFE_RES_ID_MAX 1 + +/* Resource Type - Type of resource for the resource id + * defined in cam_isp_tfe.h + */ + +/* Lane Type in input resource for Port */ +#define CAM_ISP_TFE_IN_LANE_TYPE_DPHY 0 +#define CAM_ISP_TFE_IN_LANE_TYPE_CPHY 1 +#define CAM_ISP_TFE_IN_LANE_TYPE_MAX 2 + +/* ISP TFE packet opcode */ +#define CAM_ISP_TFE_PACKET_OP_BASE 0 +#define CAM_ISP_TFE_PACKET_INIT_DEV 1 +#define CAM_ISP_TFE_PACKET_CONFIG_DEV 2 +#define CAM_ISP_TFE_PACKET_OP_MAX 3 + +/* ISP TFE packet meta_data type for command buffer */ +#define CAM_ISP_TFE_PACKET_META_BASE 0 +#define CAM_ISP_TFE_PACKET_META_LEFT 1 +#define CAM_ISP_TFE_PACKET_META_RIGHT 2 +#define CAM_ISP_TFE_PACKET_META_COMMON 3 +#define CAM_ISP_TFE_PACKET_META_DUAL_CONFIG 4 +#define CAM_ISP_TFE_PACKET_META_GENERIC_BLOB_COMMON 5 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_PER_REQUEST 6 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_FLUSH 7 +#define CAM_ISP_TFE_PACKET_META_REG_DUMP_ON_ERROR 8 + +/* ISP TFE Generic Cmd Buffer Blob types */ +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_HFR_CONFIG 0 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_CLOCK_CONFIG 1 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_BW_CONFIG_V2 2 +#define CAM_ISP_TFE_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG 3 + +/* DSP mode */ +#define CAM_ISP_TFE_DSP_MODE_NONE 0 +#define CAM_ISP_TFE_DSP_MODE_ONE_WAY 1 +#define CAM_ISP_TFE_DSP_MODE_ROUND 2 + +/* Per Path Usage Data */ +#define CAM_ISP_TFE_USAGE_INVALID 0 +#define CAM_ISP_TFE_USAGE_LEFT_PX 1 +#define CAM_ISP_TFE_USAGE_RIGHT_PX 2 +#define CAM_ISP_TFE_USAGE_RDI 3 + +/* Bus write master modes */ +#define CAM_ISP_TFE_WM_FRAME_BASED_MODE 0 +#define CAM_ISP_TFE_WM_LINE_BASED_MODE 1 +#define CAM_ISP_TFE_WM_INDEX_BASED_MODE 2 + +/* Query devices */ +/** + * struct cam_isp_tfe_dev_cap_info - A cap info for particular hw type + * + * @hw_type: Hardware type for the cap info + * @reserved: reserved field for alignment + * @hw_version: Hardware version + * + */ +struct cam_isp_tfe_dev_cap_info { + uint32_t hw_type; + uint32_t reserved; + struct cam_hw_version hw_version; +}; + +/** + * struct cam_isp_tfe_query_cap_cmd - ISP TFE query device + * capability payload + * + * @device_iommu: returned iommu handles for device + * @cdm_iommu: returned iommu handles for cdm + * @num_dev: returned number of device capabilities + * @reserved: reserved field for alignment + * @dev_caps: returned device capability array + * + */ +struct cam_isp_tfe_query_cap_cmd { + struct cam_iommu_handle device_iommu; + struct cam_iommu_handle cdm_iommu; + int32_t num_dev; + uint32_t reserved; + struct cam_isp_tfe_dev_cap_info dev_caps[CAM_ISP_TFE_HW_MAX]; +}; + +/* Acquire Device */ +/** + * struct cam_isp_tfe_out_port_info - An output port resource info + * + * @res_id: output resource id defined in file + * cam_isp_tfe.h + * @format: output format of the resource + * @width: output width in pixels + * @height: output height in lines + * @stride: output stride + * @comp_grp_id: composite group id for the resource. + * @secure_mode: flag to tell if output should be run in secure + * mode or not. See cam_defs.h for definition + * @wm_mode: wm mode + * @reserved: reserved field for alignment + * + */ +struct cam_isp_tfe_out_port_info { + uint32_t res_id; + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t comp_grp_id; + uint32_t secure_mode; + uint32_t wm_mode; + uint32_t reserved; +}; + +/** + * struct cam_isp_tfe_in_port_info - An input port resource info + * + * @res_id: input resource id CAM_ISP_TFE_IN_RES_XXX + * @lane_type: lane type: c-phy or d-phy. + * @lane_num: active lane number + * @lane_cfg: lane configurations: 4 bits per lane + * @vc: input virtual channel number + * @dt: input data type number + * @format: input format + * @pix_pattern: pixel pattern + * @usage_type: whether dual tfe is required + * @left_start: left input start offset in pixels + * @left_end: left input stop offset in pixels + * @left_width: left input width in pixels + * @right_start: right input start offset in pixels. + * Only for Dual TFE + * @right_end: right input stop offset in + * pixels. Only for Dual TFE + * @right_width: right input width in pixels. + * Only for dual TFE + * @line_start: top of the line number + * @line_stop: bottome of the line number + * @height: input height in lines + * @batch_size: batch size for HFR mode + * @dsp_mode: DSP stream mode(Defines as + * CAM_ISP_TFE_DSP_MODE_*) + * @sensor_width: sensor width + * @sensor_height: sensor height + * @hbi_value: sensor HBI value + * @vbi_value: sensor VBI value + * @sensor_fps: sensor fps + * @init_frame_drop init frame drop value. + * @num_out_res: number of the output resource associated + * @data: payload that contains the output resources, + * array of cam_isp_tfe_out_port_info data + * + */ +struct cam_isp_tfe_in_port_info { + uint32_t res_id; + uint32_t lane_type; + uint32_t lane_num; + uint32_t lane_cfg; + uint32_t vc; + uint32_t dt; + uint32_t format; + uint32_t pix_pattern; + uint32_t usage_type; + uint32_t left_start; + uint32_t left_end; + uint32_t left_width; + uint32_t right_start; + uint32_t right_end; + uint32_t right_width; + uint32_t line_start; + uint32_t line_end; + uint32_t height; + uint32_t batch_size; + uint32_t dsp_mode; + uint32_t sensor_width; + uint32_t sensor_height; + uint32_t sensor_hbi; + uint32_t sensor_vbi; + uint32_t sensor_fps; + uint32_t init_frame_drop; + uint32_t num_out_res; + struct cam_isp_tfe_out_port_info data[1]; +}; + +/** + * struct cam_isp_tfe_resource - A resource bundle + * + * @resoruce_id: resource id for the resource bundle + * @length: length of the while resource blob + * @handle_type: type of the resource handle + * @reserved: reserved field for alignment + * @res_hdl: resource handle that points to the + * resource array + * + */ +struct cam_isp_tfe_resource { + uint32_t resource_id; + uint32_t length; + uint32_t handle_type; + uint32_t reserved; + uint64_t res_hdl; +}; + +/** + * struct cam_isp_tfe_port_hfr_config - HFR configuration for + * this port + * + * @resource_type: Resource type + * @subsample_pattern: Subsample pattern. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @subsample_period: Subsample period. Used in HFR mode. It + * should be consistent with batchSize and + * CAMIF programming. + * @framedrop_pattern: Framedrop pattern + * @framedrop_period: Framedrop period + * @reserved: Reserved for alignment + */ +struct cam_isp_tfe_port_hfr_config { + uint32_t resource_type; + uint32_t subsample_pattern; + uint32_t subsample_period; + uint32_t framedrop_pattern; + uint32_t framedrop_period; + uint32_t reserved; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_resource_hfr_config - Resource HFR + * configuration + * + * @num_ports: Number of ports + * @reserved: Reserved for alignment + * @port_hfr_config: HFR configuration for each IO port + */ +struct cam_isp_tfe_resource_hfr_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_tfe_port_hfr_config port_hfr_config[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_dual_stripe_config - stripe config per bus + * client + * + * @offset: Start horizontal offset relative to + * output buffer + * @width: Width of the stripe in pixels + * @port_id: Port id of ISP TFE output + * @reserved: Reserved for alignment + * + */ +struct cam_isp_tfe_dual_stripe_config { + uint32_t offset; + uint32_t width; + uint32_t port_id; + uint32_t reserved; +}; + +/** + * struct cam_isp_tfe_dual_config - dual isp configuration + * + * @num_ports Number of isp output ports + * @reserved Reserved field for alignment + * @stripes: Stripe information + * + */ +struct cam_isp_tfe_dual_config { + uint32_t num_ports; + uint32_t reserved; + struct cam_isp_tfe_dual_stripe_config stripes[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_clock_config - Clock configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_hz: Pixel Clock for Left ISP + * @right_pix_hz: Pixel Clock for Right ISP + * valid only if Dual + * @rdi_hz: RDI Clock. ISP TFE clock will be + * max of RDI and PIX clocks. For a + * particular context which ISP TFE + * HW the RDI is allocated to is + * not known to UMD. Hence pass the + * clock and let KMD decide. + */ +struct cam_isp_tfe_clock_config { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_hz; + uint64_t right_pix_hz; + uint64_t rdi_hz[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_csid_clock_config - CSID clock + * configuration + * + * @csid_clock CSID clock + * @csi_phy_clock Phy clock valid if tpg is selected + */ +struct cam_isp_tfe_csid_clock_config { + uint64_t csid_clock; + uint64_t phy_clock; +} __attribute__((packed)); + +/** + * struct cam_isp_tfe_bw_config_v2 - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_paths: Number of axi data paths + * @axi_path Per path vote info + */ +struct cam_isp_tfe_bw_config_v2 { + uint32_t usage_type; + uint32_t num_paths; + struct cam_axi_per_path_bw_vote axi_path[1]; +} __attribute__((packed)); + +/** + * struct cam_isp_acquire_hw_info - ISP TFE acquire HW params + * + * @common_info_version : Version of common info struct used + * @common_info_size : Size of common info struct used + * @common_info_offset : Offset of common info from start of data + * @num_inputs : Number of inputs + * @input_info_version : Version of input info struct used + * @input_info_size : Size of input info struct used + * @input_info_offset : Offset of input info from start of data + * @data : Data pointer to point the cam_isp_tfe_in_port_info + * structure + */ +struct cam_isp_tfe_acquire_hw_info { + uint16_t common_info_version; + uint16_t common_info_size; + uint32_t common_info_offset; + uint32_t num_inputs; + uint32_t input_info_version; + uint32_t input_info_size; + uint32_t input_info_offset; + uint64_t data; +}; + +#define CAM_TFE_ACQUIRE_COMMON_VER0 0x1000 + +#define CAM_TFE_ACQUIRE_COMMON_SIZE_VER0 0x0 + +#define CAM_TFE_ACQUIRE_INPUT_VER0 0x2000 + +#define CAM_TFE_ACQUIRE_INPUT_SIZE_VER0 sizeof(struct cam_isp_tfe_in_port_info) + +#define CAM_TFE_ACQUIRE_OUT_VER0 0x3000 + +#define CAM_TFE_ACQUIRE_OUT_SIZE_VER0 sizeof(struct cam_isp_tfe_out_port_info) + +#endif /* __UAPI_CAM_TFE_H__ */ diff --git a/techpack/display/Makefile b/techpack/display/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b2829628ff1343c3b25122b0e3e42d44e1439b3e --- /dev/null +++ b/techpack/display/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# auto-detect subdirs +ifeq ($(CONFIG_ARCH_KONA), y) +include $(srctree)/techpack/display/config/konadisp.conf +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +LINUXINCLUDE += -include $(srctree)/techpack/display/config/konadispconf.h +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +include $(srctree)/techpack/display/config/saipdisp.conf +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +LINUXINCLUDE += -include $(srctree)/techpack/display/config/saipdispconf.h +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +include $(srctree)/techpack/display/config/bengaldisp.conf +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +LINUXINCLUDE += -include $(srctree)/techpack/display/config/bengaldispconf.h +endif + +obj-$(CONFIG_DRM_MSM) += msm/ +obj-$(CONFIG_MSM_SDE_ROTATOR) += rotator/ +obj-$(CONFIG_QCOM_MDSS_PLL) += pll/ diff --git a/techpack/display/NOTICE b/techpack/display/NOTICE new file mode 100644 index 0000000000000000000000000000000000000000..987146bb6ddb370d39cbb30b250227b4c7f97c72 --- /dev/null +++ b/techpack/display/NOTICE @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +*/ + +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Copyright (C) 2014 Red Hat + * Copyright (C) 2016 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +/* + * Copyright © 2014 Red Hatt. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ diff --git a/techpack/display/config/bengaldisp.conf b/techpack/display/config/bengaldisp.conf new file mode 100644 index 0000000000000000000000000000000000000000..1ef288bd41827e888fe8280fefc510e6b5fa3998 --- /dev/null +++ b/techpack/display/config/bengaldisp.conf @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2019, The Linux Foundation. All rights reserved. + +export CONFIG_DRM_MSM=y +export CONFIG_DRM_MSM_SDE=y +export CONFIG_SYNC_FILE=y +export CONFIG_DRM_MSM_DSI=y +export CONFIG_DRM_MSM_DP=n +export CONFIG_QCOM_MDSS_DP_PLL=n +export CONFIG_DSI_PARSER=y +export CONFIG_DRM_SDE_WB=n +export CONFIG_DRM_MSM_REGISTER_LOGGING=y +export CONFIG_QCOM_MDSS_PLL=y +export CONFIG_MSM_SDE_ROTATOR=y +export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +export CONFIG_DRM_SDE_RSC=n diff --git a/techpack/display/config/bengaldispconf.h b/techpack/display/config/bengaldispconf.h new file mode 100644 index 0000000000000000000000000000000000000000..c76a073ecccd99fa18165a0c3e0df00592d61b71 --- /dev/null +++ b/techpack/display/config/bengaldispconf.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_DRM_MSM 1 +#define CONFIG_DRM_MSM_SDE 1 +#define CONFIG_SYNC_FILE 1 +#define CONFIG_DRM_MSM_DSI 1 +#define CONFIG_DSI_PARSER 1 +#define CONFIG_DRM_MSM_REGISTER_LOGGING 1 +#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1 +#define CONFIG_QCOM_MDSS_PLL 1 +#define CONFIG_MSM_SDE_ROTATOR 1 +#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1 diff --git a/techpack/display/config/konadisp.conf b/techpack/display/config/konadisp.conf new file mode 100644 index 0000000000000000000000000000000000000000..dbbf3c847dbb7f4d5688f02fc0030228fb9246e5 --- /dev/null +++ b/techpack/display/config/konadisp.conf @@ -0,0 +1,13 @@ +export CONFIG_DRM_MSM=y +export CONFIG_DRM_MSM_SDE=y +export CONFIG_SYNC_FILE=y +export CONFIG_DRM_MSM_DSI=y +export CONFIG_DRM_MSM_DP=y +export CONFIG_QCOM_MDSS_DP_PLL=y +export CONFIG_DSI_PARSER=y +export CONFIG_DRM_SDE_WB=y +export CONFIG_DRM_MSM_REGISTER_LOGGING=y +export CONFIG_QCOM_MDSS_PLL=y +export CONFIG_MSM_SDE_ROTATOR=y +export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +export CONFIG_DRM_SDE_RSC=y diff --git a/techpack/display/config/konadispconf.h b/techpack/display/config/konadispconf.h new file mode 100644 index 0000000000000000000000000000000000000000..690d4ec79f41ae9cf7e4c1065a0e6c89f51d9fd7 --- /dev/null +++ b/techpack/display/config/konadispconf.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_DRM_MSM 1 +#define CONFIG_DRM_MSM_SDE 1 +#define CONFIG_SYNC_FILE 1 +#define CONFIG_DRM_MSM_DSI 1 +#define CONFIG_DRM_MSM_DP 1 +#define CONFIG_QCOM_MDSS_DP_PLL 1 +#define CONFIG_DSI_PARSER 1 +#define CONFIG_DRM_SDE_WB 1 +#define CONFIG_DRM_MSM_REGISTER_LOGGING 1 +#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1 +#define CONFIG_QCOM_MDSS_PLL 1 +#define CONFIG_MSM_SDE_ROTATOR 1 +#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1 +#define CONFIG_DRM_SDE_RSC 1 + diff --git a/techpack/display/config/saipdisp.conf b/techpack/display/config/saipdisp.conf new file mode 100644 index 0000000000000000000000000000000000000000..dbbf3c847dbb7f4d5688f02fc0030228fb9246e5 --- /dev/null +++ b/techpack/display/config/saipdisp.conf @@ -0,0 +1,13 @@ +export CONFIG_DRM_MSM=y +export CONFIG_DRM_MSM_SDE=y +export CONFIG_SYNC_FILE=y +export CONFIG_DRM_MSM_DSI=y +export CONFIG_DRM_MSM_DP=y +export CONFIG_QCOM_MDSS_DP_PLL=y +export CONFIG_DSI_PARSER=y +export CONFIG_DRM_SDE_WB=y +export CONFIG_DRM_MSM_REGISTER_LOGGING=y +export CONFIG_QCOM_MDSS_PLL=y +export CONFIG_MSM_SDE_ROTATOR=y +export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +export CONFIG_DRM_SDE_RSC=y diff --git a/techpack/display/config/saipdispconf.h b/techpack/display/config/saipdispconf.h new file mode 100644 index 0000000000000000000000000000000000000000..0490248397010294c922921b4cbf29f8128ccf4a --- /dev/null +++ b/techpack/display/config/saipdispconf.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_DRM_MSM 1 +#define CONFIG_DRM_MSM_SDE 1 +#define CONFIG_SYNC_FILE 1 +#define CONFIG_DRM_MSM_DSI 1 +#define CONFIG_DRM_MSM_DP 1 +#define CONFIG_QCOM_MDSS_DP_PLL 1 +#define CONFIG_DSI_PARSER 1 +#define CONFIG_DRM_SDE_WB 1 +#define CONFIG_DRM_MSM_REGISTER_LOGGING 1 +#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1 +#define CONFIG_QCOM_MDSS_PLL 1 +#define CONFIG_MSM_SDE_ROTATOR 1 +#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1 +#define CONFIG_DRM_SDE_RSC 1 diff --git a/techpack/display/msm/Makefile b/techpack/display/msm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b7ac4dfb12b2d6ea6a8be987f4ca03d6b44367da --- /dev/null +++ b/techpack/display/msm/Makefile @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: GPL-2.0 +ccflags-y := -I$(srctree)/include/drm -I$(srctree)/techpack/display/msm -I$(srctree)/techpack/display/msm/dsi -I$(srctree)/techpack/display/msm/dp +ccflags-y += -I$(srctree)/techpack/display/msm/sde +ccflags-y += -I$(srctree)/techpack/display/rotator + +msm_drm-$(CONFIG_DRM_MSM_DP) += dp/dp_usbpd.o \ + dp/dp_parser.o \ + dp/dp_power.o \ + dp/dp_catalog.o \ + dp/dp_catalog_v420.o \ + dp/dp_catalog_v200.o \ + dp/dp_aux.o \ + dp/dp_panel.o \ + dp/dp_link.o \ + dp/dp_ctrl.o \ + dp/dp_audio.o \ + dp/dp_debug.o \ + dp/dp_hpd.o \ + dp/dp_gpio_hpd.o \ + dp/dp_lphw_hpd.o \ + dp/dp_display.o \ + dp/dp_drm.o \ + dp/dp_hdcp2p2.o \ + dp/dp_mst_drm.o \ + +msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \ + sde/sde_encoder.o \ + sde/sde_encoder_phys_vid.o \ + sde/sde_encoder_phys_cmd.o \ + sde/sde_irq.o \ + sde/sde_core_irq.o \ + sde/sde_core_perf.o \ + sde/sde_rm.o \ + sde/sde_kms_utils.o \ + sde/sde_kms.o \ + sde/sde_plane.o \ + sde/sde_connector.o \ + sde/sde_color_processing.o \ + sde/sde_vbif.o \ + sde_io_util.o \ + sde/sde_hw_reg_dma_v1_color_proc.o \ + sde/sde_hw_color_proc_v4.o \ + sde/sde_hw_ad4.o \ + sde/sde_hw_uidle.o \ + sde_edid_parser.o \ + sde_hdcp_1x.o \ + sde_hdcp_2x.o \ + sde/sde_hw_catalog.o \ + sde/sde_hw_cdm.o \ + sde/sde_hw_dspp.o \ + sde/sde_hw_intf.o \ + sde/sde_hw_lm.o \ + sde/sde_hw_ctl.o \ + sde/sde_hw_util.o \ + sde/sde_hw_sspp.o \ + sde/sde_hw_wb.o \ + sde/sde_hw_pingpong.o \ + sde/sde_hw_top.o \ + sde/sde_hw_interrupts.o \ + sde/sde_hw_vbif.o \ + sde/sde_hw_blk.o \ + sde/sde_formats.o \ + sde_power_handle.o \ + sde/sde_hw_color_processing_v1_7.o \ + sde/sde_reg_dma.o \ + sde/sde_hw_reg_dma_v1.o \ + sde/sde_hw_dsc.o \ + sde/sde_hw_ds.o \ + sde/sde_fence.o \ + sde/sde_hw_qdss.o \ + +msm_drm-$(CONFIG_DEBUG_FS) += sde_dbg.o \ + sde_dbg_evtlog.o \ + +msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \ + sde/sde_encoder_phys_wb.o \ + +msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \ + sde_rsc_hw.o \ + sde_rsc_hw_v3.o \ + +msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \ + dsi/dsi_pwr.o \ + dsi/dsi_phy.o \ + dsi/dsi_phy_hw_v2_0.o \ + dsi/dsi_phy_hw_v3_0.o \ + dsi/dsi_phy_hw_v4_0.o \ + dsi/dsi_phy_timing_calc.o \ + dsi/dsi_phy_timing_v2_0.o \ + dsi/dsi_phy_timing_v3_0.o \ + dsi/dsi_phy_timing_v4_0.o \ + dsi/dsi_ctrl_hw_cmn.o \ + dsi/dsi_ctrl_hw_1_4.o \ + dsi/dsi_ctrl_hw_2_0.o \ + dsi/dsi_ctrl_hw_2_2.o \ + dsi/dsi_ctrl.o \ + dsi/dsi_catalog.o \ + dsi/dsi_drm.o \ + dsi/dsi_display.o \ + dsi/dsi_panel.o \ + dsi/dsi_clk_manager.o \ + dsi/dsi_display_test.o \ + +msm_drm-$(CONFIG_DSI_PARSER) += dsi/dsi_parser.o \ + +msm_drm-$(CONFIG_DRM_MSM) += \ + msm_atomic.o \ + msm_fb.o \ + msm_iommu.o \ + msm_drv.o \ + msm_gem.o \ + msm_gem_prime.o \ + msm_gem_vma.o \ + msm_smmu.o \ + msm_prop.o \ + msm_notifier.o\ + +obj-$(CONFIG_DRM_MSM) += msm_drm.o + +obj-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o diff --git a/techpack/display/msm/dp/dp_audio.c b/techpack/display/msm/dp/dp_audio.c new file mode 100644 index 0000000000000000000000000000000000000000..90c3ad16dba6245475fe600421d7fdac044cd5a8 --- /dev/null +++ b/techpack/display/msm/dp/dp_audio.c @@ -0,0 +1,889 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of_platform.h> +#include <linux/msm_ext_display.h> + +#include <drm/drm_dp_helper.h> + +#include "dp_catalog.h" +#include "dp_audio.h" +#include "dp_panel.h" +#include "dp_debug.h" + +struct dp_audio_private { + struct platform_device *ext_pdev; + struct platform_device *pdev; + struct dp_catalog_audio *catalog; + struct msm_ext_disp_init_data ext_audio_data; + struct dp_panel *panel; + + bool ack_enabled; + atomic_t session_on; + bool engine_on; + + u32 channels; + + struct completion hpd_comp; + struct workqueue_struct *notify_workqueue; + struct delayed_work notify_delayed_work; + struct mutex ops_lock; + + struct dp_audio dp_audio; + + atomic_t acked; +}; + +static u32 dp_audio_get_header(struct dp_catalog_audio *catalog, + enum dp_catalog_audio_sdp_type sdp, + enum dp_catalog_audio_header_type header) +{ + catalog->sdp_type = sdp; + catalog->sdp_header = header; + catalog->get_header(catalog); + + return catalog->data; +} + +static void dp_audio_set_header(struct dp_catalog_audio *catalog, + u32 data, + enum dp_catalog_audio_sdp_type sdp, + enum dp_catalog_audio_header_type header) +{ + catalog->sdp_type = sdp; + catalog->sdp_header = header; + catalog->data = data; + catalog->set_header(catalog); +} + +static void dp_audio_stream_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x02; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + new_value = 0x0; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = audio->channels - 1; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x1; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x17; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = (0x0 | (0x11 << 2)); + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x84; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x1b; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = (0x0 | (0x11 << 2)); + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + new_value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x05; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x0F; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); + + /* Config header and parity byte 3 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); + value &= 0x0000ffff; + + new_value = 0x0; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); +} + +static void dp_audio_isrc_sdp(struct dp_audio_private *audio) +{ + struct dp_catalog_audio *catalog = audio->catalog; + u32 value, new_value; + u8 parity_byte; + + /* Config header and parity byte 1 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); + value &= 0x0000ffff; + + new_value = 0x06; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); + + /* Config header and parity byte 2 */ + value = dp_audio_get_header(catalog, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); + value &= 0xffff0000; + + new_value = 0x0F; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_audio_set_header(catalog, value, + DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); +} + +static void dp_audio_setup_sdp(struct dp_audio_private *audio) +{ + if (!atomic_read(&audio->session_on)) { + DP_WARN("session inactive\n"); + return; + } + + /* always program stream 0 first before actual stream cfg */ + audio->catalog->stream_id = DP_STREAM_0; + audio->catalog->config_sdp(audio->catalog); + + if (audio->panel->stream_id == DP_STREAM_1) { + audio->catalog->stream_id = DP_STREAM_1; + audio->catalog->config_sdp(audio->catalog); + } + + dp_audio_stream_sdp(audio); + dp_audio_timestamp_sdp(audio); + dp_audio_infoframe_sdp(audio); + dp_audio_copy_management_sdp(audio); + dp_audio_isrc_sdp(audio); +} + +static void dp_audio_setup_acr(struct dp_audio_private *audio) +{ + u32 select = 0; + struct dp_catalog_audio *catalog = audio->catalog; + + if (!atomic_read(&audio->session_on)) { + DP_WARN("session inactive\n"); + return; + } + + switch (audio->dp_audio.bw_code) { + case DP_LINK_BW_1_62: + select = 0; + break; + case DP_LINK_BW_2_7: + select = 1; + break; + case DP_LINK_BW_5_4: + select = 2; + break; + case DP_LINK_BW_8_1: + select = 3; + break; + default: + DP_DEBUG("Unknown link rate\n"); + select = 0; + break; + } + + catalog->data = select; + catalog->config_acr(catalog); +} + +static void dp_audio_enable(struct dp_audio_private *audio, bool enable) +{ + struct dp_catalog_audio *catalog = audio->catalog; + + audio->engine_on = enable; + if (!atomic_read(&audio->session_on)) { + DP_WARN("session inactive. enable=%d\n", enable); + return; + } + catalog->data = enable; + catalog->enable(catalog); + +} + +static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev) +{ + struct msm_ext_disp_data *ext_data; + struct dp_audio *dp_audio; + + if (!pdev) { + DP_ERR("invalid input\n"); + return ERR_PTR(-ENODEV); + } + + ext_data = platform_get_drvdata(pdev); + if (!ext_data) { + DP_ERR("invalid ext disp data\n"); + return ERR_PTR(-EINVAL); + } + + dp_audio = ext_data->intf_data; + if (!dp_audio) { + DP_ERR("invalid intf data\n"); + return ERR_PTR(-EINVAL); + } + + return container_of(dp_audio, struct dp_audio_private, dp_audio); +} + +static int dp_audio_info_setup(struct platform_device *pdev, + struct msm_ext_disp_audio_setup_params *params) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + return rc; + } + + mutex_lock(&audio->ops_lock); + + audio->channels = params->num_of_channels; + + if (audio->panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id: %d\n", + audio->panel->stream_id); + rc = -EINVAL; + mutex_unlock(&audio->ops_lock); + return rc; + } + + dp_audio_setup_sdp(audio); + dp_audio_setup_acr(audio); + dp_audio_enable(audio, true); + + mutex_unlock(&audio->ops_lock); + + DP_DEBUG("audio stream configured\n"); + + return rc; +} + +static int dp_audio_get_edid_blk(struct platform_device *pdev, + struct msm_ext_disp_audio_edid_blk *blk) +{ + int rc = 0; + struct dp_audio_private *audio; + struct sde_edid_ctrl *edid; + + if (!blk) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + if (!audio->panel || !audio->panel->edid_ctrl) { + DP_ERR("invalid panel data\n"); + rc = -EINVAL; + goto end; + } + + edid = audio->panel->edid_ctrl; + + blk->audio_data_blk = edid->audio_data_block; + blk->audio_data_blk_size = edid->adb_size; + + blk->spk_alloc_data_blk = edid->spkr_alloc_data_block; + blk->spk_alloc_data_blk_size = edid->sadb_size; +end: + return rc; +} + +static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + return atomic_read(&audio->session_on); +end: + return rc; +} + +static int dp_audio_get_intf_id(struct platform_device *pdev) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + return EXT_DISPLAY_TYPE_DP; +end: + return rc; +} + +static void dp_audio_teardown_done(struct platform_device *pdev) +{ + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) + return; + + mutex_lock(&audio->ops_lock); + dp_audio_enable(audio, false); + mutex_unlock(&audio->ops_lock); + + atomic_set(&audio->acked, 1); + complete_all(&audio->hpd_comp); + + DP_DEBUG("audio engine disabled\n"); +} + +static int dp_audio_ack_done(struct platform_device *pdev, u32 ack) +{ + int rc = 0, ack_hpd; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + rc = PTR_ERR(audio); + goto end; + } + + if (ack & AUDIO_ACK_SET_ENABLE) { + audio->ack_enabled = ack & AUDIO_ACK_ENABLE ? + true : false; + + DP_DEBUG("audio ack feature %s\n", + audio->ack_enabled ? "enabled" : "disabled"); + goto end; + } + + if (!audio->ack_enabled) + goto end; + + ack_hpd = ack & AUDIO_ACK_CONNECT; + + DP_DEBUG("acknowledging audio (%d)\n", ack_hpd); + + if (!audio->engine_on) { + atomic_set(&audio->acked, 1); + complete_all(&audio->hpd_comp); + } +end: + return rc; +} + +static int dp_audio_codec_ready(struct platform_device *pdev) +{ + int rc = 0; + struct dp_audio_private *audio; + + audio = dp_audio_get_data(pdev); + if (IS_ERR(audio)) { + DP_ERR("invalid input\n"); + rc = PTR_ERR(audio); + goto end; + } + + queue_delayed_work(audio->notify_workqueue, + &audio->notify_delayed_work, HZ/4); +end: + return rc; +} + +static int dp_audio_register_ext_disp(struct dp_audio_private *audio) +{ + int rc = 0; + struct device_node *pd = NULL; + const char *phandle = "qcom,ext-disp"; + struct msm_ext_disp_init_data *ext; + struct msm_ext_disp_audio_codec_ops *ops; + + ext = &audio->ext_audio_data; + ops = &ext->codec_ops; + + ext->codec.type = EXT_DISPLAY_TYPE_DP; + ext->codec.ctrl_id = 0; + ext->codec.stream_id = audio->panel->stream_id; + ext->pdev = audio->pdev; + ext->intf_data = &audio->dp_audio; + + ops->audio_info_setup = dp_audio_info_setup; + ops->get_audio_edid_blk = dp_audio_get_edid_blk; + ops->cable_status = dp_audio_get_cable_status; + ops->get_intf_id = dp_audio_get_intf_id; + ops->teardown_done = dp_audio_teardown_done; + ops->acknowledge = dp_audio_ack_done; + ops->ready = dp_audio_codec_ready; + + if (!audio->pdev->dev.of_node) { + DP_ERR("cannot find audio dev.of_node\n"); + rc = -ENODEV; + goto end; + } + + pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0); + if (!pd) { + DP_ERR("cannot parse %s handle\n", phandle); + rc = -ENODEV; + goto end; + } + + audio->ext_pdev = of_find_device_by_node(pd); + if (!audio->ext_pdev) { + DP_ERR("cannot find %s pdev\n", phandle); + rc = -ENODEV; + goto end; + } +#if defined(CONFIG_MSM_EXT_DISPLAY) + rc = msm_ext_disp_register_intf(audio->ext_pdev, ext); + if (rc) + DP_ERR("failed to register disp\n"); +#endif +end: + if (pd) + of_node_put(pd); + + return rc; +} + +static int dp_audio_deregister_ext_disp(struct dp_audio_private *audio) +{ + int rc = 0; + struct device_node *pd = NULL; + const char *phandle = "qcom,ext-disp"; + struct msm_ext_disp_init_data *ext; + + ext = &audio->ext_audio_data; + + if (!audio->pdev->dev.of_node) { + DP_ERR("cannot find audio dev.of_node\n"); + rc = -ENODEV; + goto end; + } + + pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0); + if (!pd) { + DP_ERR("cannot parse %s handle\n", phandle); + rc = -ENODEV; + goto end; + } + + audio->ext_pdev = of_find_device_by_node(pd); + if (!audio->ext_pdev) { + DP_ERR("cannot find %s pdev\n", phandle); + rc = -ENODEV; + goto end; + } + +#if defined(CONFIG_MSM_EXT_DISPLAY) + rc = msm_ext_disp_deregister_intf(audio->ext_pdev, ext); + if (rc) + DP_ERR("failed to deregister disp\n"); +#endif + +end: + return rc; +} + +static int dp_audio_notify(struct dp_audio_private *audio, u32 state) +{ + int rc = 0; + struct msm_ext_disp_init_data *ext = &audio->ext_audio_data; + + atomic_set(&audio->acked, 0); + + if (!ext->intf_ops.audio_notify) { + DP_ERR("audio notify not defined\n"); + goto end; + } + + reinit_completion(&audio->hpd_comp); + rc = ext->intf_ops.audio_notify(audio->ext_pdev, + &ext->codec, state); + if (rc) + goto end; + + if (atomic_read(&audio->acked)) + goto end; + + if (state == EXT_DISPLAY_CABLE_DISCONNECT && !audio->engine_on) + goto end; + + if (state == EXT_DISPLAY_CABLE_CONNECT) + goto end; + + rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 4); + if (!rc) { + DP_ERR("timeout. state=%d err=%d\n", state, rc); + rc = -ETIMEDOUT; + goto end; + } + + DP_DEBUG("success\n"); +end: + return rc; +} + +static int dp_audio_config(struct dp_audio_private *audio, u32 state) +{ + int rc = 0; + struct msm_ext_disp_init_data *ext = &audio->ext_audio_data; + + if (!ext || !ext->intf_ops.audio_config) { + DP_ERR("audio_config not defined\n"); + goto end; + } + + /* + * DP Audio sets default STREAM_0 only, other streams are + * set by audio driver based on the hardware/software support. + */ + if (audio->panel->stream_id == DP_STREAM_0) { + rc = ext->intf_ops.audio_config(audio->ext_pdev, + &ext->codec, state); + if (rc) + DP_ERR("failed to config audio, err=%d\n", + rc); + } +end: + return rc; +} + +static int dp_audio_on(struct dp_audio *dp_audio) +{ + int rc = 0; + struct dp_audio_private *audio; + struct msm_ext_disp_init_data *ext; + + if (!dp_audio) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + if (IS_ERR(audio)) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp_audio_register_ext_disp(audio); + + ext = &audio->ext_audio_data; + + atomic_set(&audio->session_on, 1); + + rc = dp_audio_config(audio, EXT_DISPLAY_CABLE_CONNECT); + if (rc) + goto end; + + rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT); + if (rc) + goto end; + + DP_DEBUG("success\n"); +end: + return rc; +} + +static int dp_audio_off(struct dp_audio *dp_audio) +{ + int rc = 0; + struct dp_audio_private *audio; + struct msm_ext_disp_init_data *ext; + bool work_pending = false; + + if (!dp_audio) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + + if (!atomic_read(&audio->session_on)) { + DP_DEBUG("audio already off\n"); + return rc; + } + + ext = &audio->ext_audio_data; + + work_pending = cancel_delayed_work_sync(&audio->notify_delayed_work); + if (work_pending) + DP_DEBUG("pending notification work completed\n"); + + rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT); + if (rc) + goto end; + + DP_DEBUG("success\n"); +end: + dp_audio_config(audio, EXT_DISPLAY_CABLE_DISCONNECT); + + atomic_set(&audio->session_on, 0); + audio->engine_on = false; + + dp_audio_deregister_ext_disp(audio); + + return rc; +} + +static void dp_audio_notify_work_fn(struct work_struct *work) +{ + struct dp_audio_private *audio; + struct delayed_work *dw = to_delayed_work(work); + + audio = container_of(dw, struct dp_audio_private, notify_delayed_work); + + dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT); +} + +static int dp_audio_create_notify_workqueue(struct dp_audio_private *audio) +{ + audio->notify_workqueue = create_workqueue("sdm_dp_audio_notify"); + if (IS_ERR_OR_NULL(audio->notify_workqueue)) { + DP_ERR("Error creating notify_workqueue\n"); + return -EPERM; + } + + INIT_DELAYED_WORK(&audio->notify_delayed_work, dp_audio_notify_work_fn); + + return 0; +} + +static void dp_audio_destroy_notify_workqueue(struct dp_audio_private *audio) +{ + if (audio->notify_workqueue) + destroy_workqueue(audio->notify_workqueue); +} + +struct dp_audio *dp_audio_get(struct platform_device *pdev, + struct dp_panel *panel, + struct dp_catalog_audio *catalog) +{ + int rc = 0; + struct dp_audio_private *audio; + struct dp_audio *dp_audio; + + if (!pdev || !panel || !catalog) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL); + if (!audio) { + rc = -ENOMEM; + goto error; + } + + rc = dp_audio_create_notify_workqueue(audio); + if (rc) + goto error_notify_workqueue; + + init_completion(&audio->hpd_comp); + + audio->pdev = pdev; + audio->panel = panel; + audio->catalog = catalog; + + atomic_set(&audio->acked, 0); + + dp_audio = &audio->dp_audio; + + mutex_init(&audio->ops_lock); + + dp_audio->on = dp_audio_on; + dp_audio->off = dp_audio_off; + + catalog->init(catalog); + + return dp_audio; + +error_notify_workqueue: + devm_kfree(&pdev->dev, audio); +error: + return ERR_PTR(rc); +} + +void dp_audio_put(struct dp_audio *dp_audio) +{ + struct dp_audio_private *audio; + + if (!dp_audio) + return; + + audio = container_of(dp_audio, struct dp_audio_private, dp_audio); + + mutex_destroy(&audio->ops_lock); + + dp_audio_destroy_notify_workqueue(audio); + + devm_kfree(&audio->pdev->dev, audio); +} diff --git a/techpack/display/msm/dp/dp_audio.h b/techpack/display/msm/dp/dp_audio.h new file mode 100644 index 0000000000000000000000000000000000000000..882551e0fefc970a473e27e275adb04b2a9c9c66 --- /dev/null +++ b/techpack/display/msm/dp/dp_audio.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_AUDIO_H_ +#define _DP_AUDIO_H_ + +#include <linux/platform_device.h> + +#include "dp_panel.h" +#include "dp_catalog.h" + +/** + * struct dp_audio + * @lane_count: number of lanes configured in current session + * @bw_code: link rate's bandwidth code for current session + */ +struct dp_audio { + u32 lane_count; + u32 bw_code; + + /** + * on() + * + * Enables the audio by notifying the user module. + * + * @dp_audio: an instance of struct dp_audio. + * + * Returns the error code in case of failure, 0 in success case. + */ + int (*on)(struct dp_audio *dp_audio); + + /** + * off() + * + * Disables the audio by notifying the user module. + * + * @dp_audio: an instance of struct dp_audio. + * + * Returns the error code in case of failure, 0 in success case. + */ + int (*off)(struct dp_audio *dp_audio); +}; + +/** + * dp_audio_get() + * + * Creates and instance of dp audio. + * + * @pdev: caller's platform device instance. + * @panel: an instance of dp_panel module. + * @catalog: an instance of dp_catalog_audio module. + * + * Returns the error code in case of failure, otherwize + * an instance of newly created dp_module. + */ +struct dp_audio *dp_audio_get(struct platform_device *pdev, + struct dp_panel *panel, + struct dp_catalog_audio *catalog); + +/** + * dp_audio_put() + * + * Cleans the dp_audio instance. + * + * @dp_audio: an instance of dp_audio. + */ +void dp_audio_put(struct dp_audio *dp_audio); +#endif /* _DP_AUDIO_H_ */ diff --git a/techpack/display/msm/dp/dp_aux.c b/techpack/display/msm/dp/dp_aux.c new file mode 100644 index 0000000000000000000000000000000000000000..b9ae7386bee244478392e9f8b08fbdf292eb8342 --- /dev/null +++ b/techpack/display/msm/dp/dp_aux.c @@ -0,0 +1,866 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/soc/qcom/fsa4480-i2c.h> +#include <linux/usb/usbpd.h> +#include <linux/delay.h> + +#include "dp_aux.h" +#include "dp_debug.h" + +#define DP_AUX_ENUM_STR(x) #x + +enum { + DP_AUX_DATA_INDEX_WRITE = BIT(31), +}; + +struct dp_aux_private { + struct device *dev; + struct dp_aux dp_aux; + struct dp_catalog_aux *catalog; + struct dp_aux_cfg *cfg; + struct device_node *aux_switch_node; + struct mutex mutex; + struct completion comp; + struct drm_dp_aux drm_aux; + + bool cmd_busy; + bool native; + bool read; + bool no_send_addr; + bool no_send_stop; + bool enabled; + + u32 offset; + u32 segment; + u32 aux_error_num; + u32 retry_cnt; + + atomic_t aborted; + + u8 *dpcd; + u8 *edid; +}; + +#ifdef CONFIG_DYNAMIC_DEBUG +static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) +{ + char prefix[64]; + int i, linelen, remaining = msg->size; + const int rowsize = 16; + u8 linebuf[64]; + struct dp_aux_private *aux = container_of(drm_aux, + struct dp_aux_private, drm_aux); + + snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ", + aux->native ? "NAT" : "I2C", + aux->read ? "RD" : "WR", + msg->address, msg->size); + + for (i = 0; i < msg->size; i += rowsize) { + linelen = min(remaining, rowsize); + remaining -= rowsize; + + hex_dump_to_buffer(msg->buffer + i, linelen, rowsize, 1, + linebuf, sizeof(linebuf), false); + + DP_DEBUG("%s%s\n", prefix, linebuf); + } +} +#else +static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) +{ +} +#endif + +static char *dp_aux_get_error(u32 aux_error) +{ + switch (aux_error) { + case DP_AUX_ERR_NONE: + return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE); + case DP_AUX_ERR_ADDR: + return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR); + case DP_AUX_ERR_TOUT: + return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT); + case DP_AUX_ERR_NACK: + return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK); + case DP_AUX_ERR_DEFER: + return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER); + case DP_AUX_ERR_NACK_DEFER: + return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER); + default: + return "unknown"; + } +} + +static u32 dp_aux_write(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg) +{ + u32 data[4], reg, len; + u8 *msgdata = msg->buffer; + int const aux_cmd_fifo_len = 128; + int i = 0; + + if (aux->read) + len = 4; + else + len = msg->size + 4; + + /* + * cmd fifo only has depth of 144 bytes + * limit buf length to 128 bytes here + */ + if (len > aux_cmd_fifo_len) { + DP_ERR("buf len error\n"); + return 0; + } + + /* Pack cmd and write to HW */ + data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */ + if (aux->read) + data[0] |= BIT(4); /* R/W */ + + data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */ + data[2] = msg->address & 0xff; /* addr[7:0] */ + data[3] = (msg->size - 1) & 0xff; /* len[7:0] */ + + for (i = 0; i < len; i++) { + reg = (i < 4) ? data[i] : msgdata[i - 4]; + reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */ + if (i == 0) + reg |= DP_AUX_DATA_INDEX_WRITE; + aux->catalog->data = reg; + aux->catalog->write_data(aux->catalog); + } + + aux->catalog->clear_trans(aux->catalog, false); + aux->catalog->clear_hw_interrupts(aux->catalog); + + reg = 0; /* Transaction number == 1 */ + if (!aux->native) { /* i2c */ + reg |= BIT(8); + + if (aux->no_send_addr) + reg |= BIT(10); + + if (aux->no_send_stop) + reg |= BIT(11); + } + + reg |= BIT(9); + aux->catalog->data = reg; + aux->catalog->write_trans(aux->catalog); + + return len; +} + +static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg) +{ + u32 ret = 0, len = 0, timeout; + int const aux_timeout_ms = HZ/4; + + reinit_completion(&aux->comp); + + len = dp_aux_write(aux, msg); + if (len == 0) { + DP_ERR("DP AUX write failed\n"); + return -EINVAL; + } + + timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms); + if (!timeout) { + DP_ERR("aux %s timeout\n", (aux->read ? "read" : "write")); + return -ETIMEDOUT; + } + + if (aux->aux_error_num == DP_AUX_ERR_NONE) { + ret = len; + } else { + pr_err_ratelimited("aux err: %s\n", + dp_aux_get_error(aux->aux_error_num)); + + ret = -EINVAL; + } + + return ret; +} + +static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg) +{ + u32 data; + u8 *dp; + u32 i, actual_i; + u32 len = msg->size; + + aux->catalog->clear_trans(aux->catalog, true); + + data = 0; + data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */ + data |= BIT(0); /* read */ + + aux->catalog->data = data; + aux->catalog->write_data(aux->catalog); + + dp = msg->buffer; + + /* discard first byte */ + data = aux->catalog->read_data(aux->catalog); + + for (i = 0; i < len; i++) { + data = aux->catalog->read_data(aux->catalog); + *dp++ = (u8)((data >> 8) & 0xff); + + actual_i = (data >> 16) & 0xFF; + if (i != actual_i) + DP_WARN("Index mismatch: expected %d, found %d\n", + i, actual_i); + } +} + +static void dp_aux_native_handler(struct dp_aux_private *aux) +{ + u32 isr = aux->catalog->isr; + + if (isr & DP_INTR_AUX_I2C_DONE) + aux->aux_error_num = DP_AUX_ERR_NONE; + else if (isr & DP_INTR_WRONG_ADDR) + aux->aux_error_num = DP_AUX_ERR_ADDR; + else if (isr & DP_INTR_TIMEOUT) + aux->aux_error_num = DP_AUX_ERR_TOUT; + if (isr & DP_INTR_NACK_DEFER) + aux->aux_error_num = DP_AUX_ERR_NACK; + if (isr & DP_INTR_AUX_ERROR) { + aux->aux_error_num = DP_AUX_ERR_PHY; + aux->catalog->clear_hw_interrupts(aux->catalog); + } + + complete(&aux->comp); +} + +static void dp_aux_i2c_handler(struct dp_aux_private *aux) +{ + u32 isr = aux->catalog->isr; + + if (isr & DP_INTR_AUX_I2C_DONE) { + if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER)) + aux->aux_error_num = DP_AUX_ERR_NACK; + else + aux->aux_error_num = DP_AUX_ERR_NONE; + } else { + if (isr & DP_INTR_WRONG_ADDR) + aux->aux_error_num = DP_AUX_ERR_ADDR; + else if (isr & DP_INTR_TIMEOUT) + aux->aux_error_num = DP_AUX_ERR_TOUT; + if (isr & DP_INTR_NACK_DEFER) + aux->aux_error_num = DP_AUX_ERR_NACK_DEFER; + if (isr & DP_INTR_I2C_NACK) + aux->aux_error_num = DP_AUX_ERR_NACK; + if (isr & DP_INTR_I2C_DEFER) + aux->aux_error_num = DP_AUX_ERR_DEFER; + if (isr & DP_INTR_AUX_ERROR) { + aux->aux_error_num = DP_AUX_ERR_PHY; + aux->catalog->clear_hw_interrupts(aux->catalog); + } + } + + complete(&aux->comp); +} + +static void dp_aux_isr(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->catalog->get_irq(aux->catalog, aux->cmd_busy); + + if (!aux->cmd_busy) + return; + + if (aux->native) + dp_aux_native_handler(aux); + else + dp_aux_i2c_handler(aux); +} + +static void dp_aux_reconfig(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->catalog->update_aux_cfg(aux->catalog, + aux->cfg, PHY_AUX_CFG1); + aux->catalog->reset(aux->catalog); +} + +static void dp_aux_abort_transaction(struct dp_aux *dp_aux, bool abort) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + atomic_set(&aux->aborted, abort); +} + +static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, + struct drm_dp_aux_msg *input_msg) +{ + u32 const edid_address = 0x50; + u32 const segment_address = 0x30; + bool i2c_read = input_msg->request & + (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + u8 *data = NULL; + + if (aux->native || i2c_read || ((input_msg->address != edid_address) && + (input_msg->address != segment_address))) + return; + + + data = input_msg->buffer; + if (input_msg->address == segment_address) + aux->segment = *data; + else + aux->offset = *data; +} + +/** + * dp_aux_transfer_helper() - helper function for EDID read transactions + * + * @aux: DP AUX private structure + * @input_msg: input message from DRM upstream APIs + * @send_seg: send the seg to sink + * + * return: void + * + * This helper function is used to fix EDID reads for non-compliant + * sinks that do not handle the i2c middle-of-transaction flag correctly. + */ +static void dp_aux_transfer_helper(struct dp_aux_private *aux, + struct drm_dp_aux_msg *input_msg, bool send_seg) +{ + struct drm_dp_aux_msg helper_msg; + u32 const message_size = 0x10; + u32 const segment_address = 0x30; + u32 const edid_block_length = 0x80; + bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT; + bool i2c_read = input_msg->request & + (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + + if (!i2c_mot || !i2c_read || (input_msg->size == 0)) + return; + + /* + * Sending the segment value and EDID offset will be performed + * from the DRM upstream EDID driver for each block. Avoid + * duplicate AUX transactions related to this while reading the + * first 16 bytes of each block. + */ + if (!(aux->offset % edid_block_length) || !send_seg) + goto end; + + aux->read = false; + aux->cmd_busy = true; + aux->no_send_addr = true; + aux->no_send_stop = true; + + /* + * Send the segment address for i2c reads for segment > 0 and for which + * the middle-of-transaction flag is set. This is required to support + * EDID reads of more than 2 blocks as the segment address is reset to 0 + * since we are overriding the middle-of-transaction flag for read + * transactions. + */ + if (aux->segment) { + memset(&helper_msg, 0, sizeof(helper_msg)); + helper_msg.address = segment_address; + helper_msg.buffer = &aux->segment; + helper_msg.size = 1; + dp_aux_cmd_fifo_tx(aux, &helper_msg); + } + + /* + * Send the offset address for every i2c read in which the + * middle-of-transaction flag is set. This will ensure that the sink + * will update its read pointer and return the correct portion of the + * EDID buffer in the subsequent i2c read trasntion triggered in the + * native AUX transfer function. + */ + memset(&helper_msg, 0, sizeof(helper_msg)); + helper_msg.address = input_msg->address; + helper_msg.buffer = &aux->offset; + helper_msg.size = 1; + dp_aux_cmd_fifo_tx(aux, &helper_msg); +end: + aux->offset += message_size; + if (aux->offset == 0x80 || aux->offset == 0x100) + aux->segment = 0x0; /* reset segment at end of block */ +} + +static int dp_aux_transfer_ready(struct dp_aux_private *aux, + struct drm_dp_aux_msg *msg, bool send_seg) +{ + int ret = 0; + int const aux_cmd_native_max = 16; + int const aux_cmd_i2c_max = 128; + + if (atomic_read(&aux->aborted)) { + ret = -ETIMEDOUT; + goto error; + } + + aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); + + /* Ignore address only message */ + if ((msg->size == 0) || (msg->buffer == NULL)) { + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + goto error; + } + + /* msg sanity check */ + if ((aux->native && (msg->size > aux_cmd_native_max)) || + (msg->size > aux_cmd_i2c_max)) { + DP_ERR("%s: invalid msg: size(%zu), request(%x)\n", + __func__, msg->size, msg->request); + ret = -EINVAL; + goto error; + } + + dp_aux_update_offset_and_segment(aux, msg); + + dp_aux_transfer_helper(aux, msg, send_seg); + + aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); + + if (aux->read) { + aux->no_send_addr = true; + aux->no_send_stop = false; + } else { + aux->no_send_addr = true; + aux->no_send_stop = true; + } + + aux->cmd_busy = true; +error: + return ret; +} + +static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) +{ + u32 timeout; + ssize_t ret; + struct dp_aux_private *aux = container_of(drm_aux, + struct dp_aux_private, drm_aux); + + mutex_lock(&aux->mutex); + + ret = dp_aux_transfer_ready(aux, msg, false); + if (ret) + goto end; + + aux->aux_error_num = DP_AUX_ERR_NONE; + + if (!aux->dpcd || !aux->edid) { + DP_ERR("invalid aux/dpcd structure\n"); + goto end; + } + + if ((msg->address + msg->size) > SZ_4K) { + DP_DEBUG("invalid dpcd access: addr=0x%x, size=0x%lx\n", + msg->address, msg->size); + goto address_error; + } + + if (aux->native) { + mutex_lock(aux->dp_aux.access_lock); + aux->dp_aux.reg = msg->address; + aux->dp_aux.read = aux->read; + aux->dp_aux.size = msg->size; + + if (!aux->read) + memcpy(aux->dpcd + msg->address, + msg->buffer, msg->size); + + reinit_completion(&aux->comp); + mutex_unlock(aux->dp_aux.access_lock); + + timeout = wait_for_completion_timeout(&aux->comp, HZ * 2); + if (!timeout) { + DP_ERR("%s timeout: 0x%x\n", + aux->read ? "read" : "write", + msg->address); + atomic_set(&aux->aborted, 1); + ret = -ETIMEDOUT; + goto end; + } + + mutex_lock(aux->dp_aux.access_lock); + if (aux->read) + memcpy(msg->buffer, aux->dpcd + msg->address, + msg->size); + mutex_unlock(aux->dp_aux.access_lock); + + aux->aux_error_num = DP_AUX_ERR_NONE; + } else { + if (aux->read && msg->address == 0x50) { + memcpy(msg->buffer, + aux->edid + aux->offset - 16, + msg->size); + } + } + + if (aux->aux_error_num == DP_AUX_ERR_NONE) { + dp_aux_hex_dump(drm_aux, msg); + + if (!aux->read) + memset(msg->buffer, 0, msg->size); + + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + } else { + /* Reply defer to retry */ + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; + } + + ret = msg->size; + goto end; + +address_error: + memset(msg->buffer, 0, msg->size); + ret = msg->size; +end: + if (ret == -ETIMEDOUT) + aux->dp_aux.state |= DP_STATE_AUX_TIMEOUT; + aux->dp_aux.reg = 0xFFFF; + aux->dp_aux.read = true; + aux->dp_aux.size = 0; + + mutex_unlock(&aux->mutex); + return ret; +} + +/* + * This function does the real job to process an AUX transaction. + * It will call aux_reset() function to reset the AUX channel, + * if the waiting is timeout. + */ +static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, + struct drm_dp_aux_msg *msg) +{ + ssize_t ret; + int const retry_count = 5; + struct dp_aux_private *aux = container_of(drm_aux, + struct dp_aux_private, drm_aux); + + mutex_lock(&aux->mutex); + + ret = dp_aux_transfer_ready(aux, msg, true); + if (ret) + goto unlock_exit; + + if (!aux->cmd_busy) { + ret = msg->size; + goto unlock_exit; + } + + ret = dp_aux_cmd_fifo_tx(aux, msg); + if ((ret < 0) && !atomic_read(&aux->aborted)) { + aux->retry_cnt++; + if (!(aux->retry_cnt % retry_count)) + aux->catalog->update_aux_cfg(aux->catalog, + aux->cfg, PHY_AUX_CFG1); + aux->catalog->reset(aux->catalog); + goto unlock_exit; + } else if (ret < 0) { + goto unlock_exit; + } + + if (aux->aux_error_num == DP_AUX_ERR_NONE) { + if (aux->read) + dp_aux_cmd_fifo_rx(aux, msg); + + dp_aux_hex_dump(drm_aux, msg); + + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; + } else { + /* Reply defer to retry */ + msg->reply = aux->native ? + DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; + } + + /* Return requested size for success or retry */ + ret = msg->size; + aux->retry_cnt = 0; + +unlock_exit: + aux->cmd_busy = false; + mutex_unlock(&aux->mutex); + return ret; +} + +static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg) +{ + int i = 0; + + for (i = 0; i < PHY_AUX_CFG_MAX; i++) + aux_cfg[i].current_index = 0; +} + +static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) +{ + struct dp_aux_private *aux; + + if (!dp_aux || !aux_cfg) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + if (aux->enabled) + return; + + dp_aux_reset_phy_config_indices(aux_cfg); + aux->catalog->setup(aux->catalog, aux_cfg); + aux->catalog->reset(aux->catalog); + aux->catalog->enable(aux->catalog, true); + atomic_set(&aux->aborted, 0); + aux->retry_cnt = 0; + aux->enabled = true; +} + +static void dp_aux_deinit(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + if (!aux->enabled) + return; + + atomic_set(&aux->aborted, 1); + aux->catalog->enable(aux->catalog, false); + aux->enabled = false; +} + +static int dp_aux_register(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + int ret = 0; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + ret = -EINVAL; + goto exit; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + aux->drm_aux.name = "sde_dp_aux"; + aux->drm_aux.dev = aux->dev; + aux->drm_aux.transfer = dp_aux_transfer; + ret = drm_dp_aux_register(&aux->drm_aux); + if (ret) { + DP_ERR("%s: failed to register drm aux: %d\n", __func__, ret); + goto exit; + } + dp_aux->drm_aux = &aux->drm_aux; +exit: + return ret; +} + +static void dp_aux_deregister(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + drm_dp_aux_unregister(&aux->drm_aux); +} + +static void dp_aux_dpcd_updated(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + /* make sure wait has started */ + usleep_range(20, 30); + complete(&aux->comp); +} + +static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en, + u8 *edid, u8 *dpcd) +{ + struct dp_aux_private *aux; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + return; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + mutex_lock(&aux->mutex); + + aux->edid = edid; + aux->dpcd = dpcd; + + if (en) { + atomic_set(&aux->aborted, 0); + aux->drm_aux.transfer = dp_aux_transfer_debug; + } else { + aux->drm_aux.transfer = dp_aux_transfer; + } + + mutex_unlock(&aux->mutex); +} + +static int dp_aux_configure_aux_switch(struct dp_aux *dp_aux, + bool enable, int orientation) +{ + struct dp_aux_private *aux; + int rc = 0; + enum fsa_function event = FSA_USBC_DISPLAYPORT_DISCONNECTED; + + if (!dp_aux) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + if (!aux->aux_switch_node) { + DP_DEBUG("undefined fsa4480 handle\n"); + rc = -EINVAL; + goto end; + } + + if (enable) { + switch (orientation) { + case ORIENTATION_CC1: + event = FSA_USBC_ORIENTATION_CC1; + break; + case ORIENTATION_CC2: + event = FSA_USBC_ORIENTATION_CC2; + break; + default: + DP_ERR("invalid orientation\n"); + rc = -EINVAL; + goto end; + } + } + + DP_DEBUG("enable=%d, orientation=%d, event=%d\n", + enable, orientation, event); + + rc = fsa4480_switch_event(aux->aux_switch_node, event); + if (rc) + DP_ERR("failed to configure fsa4480 i2c device (%d)\n", rc); +end: + return rc; +} + +struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, + struct dp_parser *parser, struct device_node *aux_switch) +{ + int rc = 0; + struct dp_aux_private *aux; + struct dp_aux *dp_aux; + + if (!catalog || !parser || + (!parser->no_aux_switch && + !aux_switch && + !parser->gpio_aux_switch)) { + DP_ERR("invalid input\n"); + rc = -ENODEV; + goto error; + } + + aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL); + if (!aux) { + rc = -ENOMEM; + goto error; + } + + init_completion(&aux->comp); + aux->cmd_busy = false; + mutex_init(&aux->mutex); + + aux->dev = dev; + aux->catalog = catalog; + aux->cfg = parser->aux_cfg; + aux->aux_switch_node = aux_switch; + dp_aux = &aux->dp_aux; + aux->retry_cnt = 0; + aux->dp_aux.reg = 0xFFFF; + + dp_aux->isr = dp_aux_isr; + dp_aux->init = dp_aux_init; + dp_aux->deinit = dp_aux_deinit; + dp_aux->drm_aux_register = dp_aux_register; + dp_aux->drm_aux_deregister = dp_aux_deregister; + dp_aux->reconfig = dp_aux_reconfig; + dp_aux->abort = dp_aux_abort_transaction; + dp_aux->dpcd_updated = dp_aux_dpcd_updated; + dp_aux->set_sim_mode = dp_aux_set_sim_mode; + dp_aux->aux_switch = dp_aux_configure_aux_switch; + + return dp_aux; +error: + return ERR_PTR(rc); +} + +void dp_aux_put(struct dp_aux *dp_aux) +{ + struct dp_aux_private *aux; + + if (!dp_aux) + return; + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + mutex_destroy(&aux->mutex); + + devm_kfree(aux->dev, aux); +} diff --git a/techpack/display/msm/dp/dp_aux.h b/techpack/display/msm/dp/dp_aux.h new file mode 100644 index 0000000000000000000000000000000000000000..cd0d9714b922af45a88ccabdd546d430cb4a2148 --- /dev/null +++ b/techpack/display/msm/dp/dp_aux.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_AUX_H_ +#define _DP_AUX_H_ + +#include "dp_catalog.h" +#include "drm_dp_helper.h" + +#define DP_STATE_NOTIFICATION_SENT BIT(0) +#define DP_STATE_TRAIN_1_STARTED BIT(1) +#define DP_STATE_TRAIN_1_SUCCEEDED BIT(2) +#define DP_STATE_TRAIN_1_FAILED BIT(3) +#define DP_STATE_TRAIN_2_STARTED BIT(4) +#define DP_STATE_TRAIN_2_SUCCEEDED BIT(5) +#define DP_STATE_TRAIN_2_FAILED BIT(6) +#define DP_STATE_CTRL_POWERED_ON BIT(7) +#define DP_STATE_CTRL_POWERED_OFF BIT(8) +#define DP_STATE_LINK_MAINTENANCE_STARTED BIT(9) +#define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10) +#define DP_STATE_LINK_MAINTENANCE_FAILED BIT(11) +#define DP_STATE_AUX_TIMEOUT BIT(12) + +enum dp_aux_error { + DP_AUX_ERR_NONE = 0, + DP_AUX_ERR_ADDR = -1, + DP_AUX_ERR_TOUT = -2, + DP_AUX_ERR_NACK = -3, + DP_AUX_ERR_DEFER = -4, + DP_AUX_ERR_NACK_DEFER = -5, + DP_AUX_ERR_PHY = -6, +}; + +struct dp_aux { + u32 reg; + u32 size; + u32 state; + + bool read; + + struct mutex *access_lock; + + struct drm_dp_aux *drm_aux; + int (*drm_aux_register)(struct dp_aux *aux); + void (*drm_aux_deregister)(struct dp_aux *aux); + void (*isr)(struct dp_aux *aux); + void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg); + void (*deinit)(struct dp_aux *aux); + void (*reconfig)(struct dp_aux *aux); + void (*abort)(struct dp_aux *aux, bool abort); + void (*dpcd_updated)(struct dp_aux *aux); + void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd); + int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation); +}; + +struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, + struct dp_parser *parser, struct device_node *aux_switch); +void dp_aux_put(struct dp_aux *aux); + +#endif /*__DP_AUX_H_*/ diff --git a/techpack/display/msm/dp/dp_catalog.c b/techpack/display/msm/dp/dp_catalog.c new file mode 100644 index 0000000000000000000000000000000000000000..f67302bbc90dce6e5ed9f600e6b6e06be3010279 --- /dev/null +++ b/techpack/display/msm/dp/dp_catalog.c @@ -0,0 +1,2799 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + + +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include "dp_catalog.h" +#include "dp_reg.h" +#include "dp_debug.h" + +#define DP_GET_MSB(x) (x >> 8) +#define DP_GET_LSB(x) (x & 0xff) + +#define DP_PHY_READY BIT(1) + +#define dp_catalog_get_priv(x) ({ \ + struct dp_catalog *dp_catalog; \ + dp_catalog = container_of(x, struct dp_catalog, x); \ + container_of(dp_catalog, struct dp_catalog_private, \ + dp_catalog); \ +}) + +#define DP_INTERRUPT_STATUS1 \ + (DP_INTR_AUX_I2C_DONE| \ + DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \ + DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \ + DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \ + DP_INTR_PLL_UNLOCKED | DP_INTR_AUX_ERROR) + +#define DP_INTR_MASK1 (DP_INTERRUPT_STATUS1 << 2) + +#define DP_INTERRUPT_STATUS2 \ + (DP_INTR_READY_FOR_VIDEO | DP_INTR_IDLE_PATTERN_SENT | \ + DP_INTR_FRAME_END | DP_INTR_CRC_UPDATED) + +#define DP_INTR_MASK2 (DP_INTERRUPT_STATUS2 << 2) + +#define DP_INTERRUPT_STATUS5 \ + (DP_INTR_MST_DP0_VCPF_SENT | DP_INTR_MST_DP1_VCPF_SENT) + +#define DP_INTR_MASK5 (DP_INTERRUPT_STATUS5 << 2) + +#define dp_catalog_fill_io(x) { \ + catalog->io.x = parser->get_io(parser, #x); \ +} + +#define dp_catalog_fill_io_buf(x) { \ + parser->get_io_buf(parser, #x); \ +} + +#define dp_read(x) ({ \ + catalog->read(catalog, io_data, x); \ +}) + +#define dp_write(x, y) ({ \ + catalog->write(catalog, io_data, x, y); \ +}) + +static u8 const vm_pre_emphasis[4][4] = { + {0x00, 0x0B, 0x12, 0xFF}, /* pe0, 0 db */ + {0x00, 0x0A, 0x12, 0xFF}, /* pe1, 3.5 db */ + {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ +}; + +/* voltage swing, 0.2v and 1.0v are not support */ +static u8 const vm_voltage_swing[4][4] = { + {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v */ + {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */ + {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ + {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ +}; + +static u8 const vm_pre_emphasis_hbr3_hbr2[4][4] = { + {0x00, 0x0C, 0x15, 0x1A}, + {0x02, 0x0E, 0x16, 0xFF}, + {0x02, 0x11, 0xFF, 0xFF}, + {0x04, 0xFF, 0xFF, 0xFF} +}; + +static u8 const vm_voltage_swing_hbr3_hbr2[4][4] = { + {0x02, 0x12, 0x16, 0x1A}, + {0x09, 0x19, 0x1F, 0xFF}, + {0x10, 0x1F, 0xFF, 0xFF}, + {0x1F, 0xFF, 0xFF, 0xFF} +}; + +static u8 const vm_pre_emphasis_hbr_rbr[4][4] = { + {0x00, 0x0C, 0x14, 0x19}, + {0x00, 0x0B, 0x12, 0xFF}, + {0x00, 0x0B, 0xFF, 0xFF}, + {0x04, 0xFF, 0xFF, 0xFF} +}; + +static u8 const vm_voltage_swing_hbr_rbr[4][4] = { + {0x08, 0x0F, 0x16, 0x1F}, + {0x11, 0x1E, 0x1F, 0xFF}, + {0x19, 0x1F, 0xFF, 0xFF}, + {0x1F, 0xFF, 0xFF, 0xFF} +}; + +enum dp_flush_bit { + DP_PPS_FLUSH, + DP_DHDR_FLUSH, +}; + +/* audio related catalog functions */ +struct dp_catalog_private { + struct device *dev; + struct dp_catalog_io io; + struct dp_parser *parser; + + u32 (*read)(struct dp_catalog_private *catalog, + struct dp_io_data *io_data, u32 offset); + void (*write)(struct dp_catalog_private *catlog, + struct dp_io_data *io_data, u32 offset, u32 data); + + u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX]; + struct dp_catalog dp_catalog; + + char exe_mode[SZ_4]; +}; + +static u32 dp_read_sw(struct dp_catalog_private *catalog, + struct dp_io_data *io_data, u32 offset) +{ + u32 data = 0; + + if (io_data->buf) + memcpy(&data, io_data->buf + offset, sizeof(offset)); + + return data; +} + +static void dp_write_sw(struct dp_catalog_private *catalog, + struct dp_io_data *io_data, u32 offset, u32 data) +{ + if (io_data->buf) + memcpy(io_data->buf + offset, &data, sizeof(data)); +} + +static u32 dp_read_hw(struct dp_catalog_private *catalog, + struct dp_io_data *io_data, u32 offset) +{ + u32 data = 0; + + data = readl_relaxed(io_data->io.base + offset); + + return data; +} + +static void dp_write_hw(struct dp_catalog_private *catalog, + struct dp_io_data *io_data, u32 offset, u32 data) +{ + writel_relaxed(data, io_data->io.base + offset); +} + +static u32 dp_read_sub_sw(struct dp_catalog *dp_catalog, + struct dp_io_data *io_data, u32 offset) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + return dp_read_sw(catalog, io_data, offset); +} + +static void dp_write_sub_sw(struct dp_catalog *dp_catalog, + struct dp_io_data *io_data, u32 offset, u32 data) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + dp_write_sw(catalog, io_data, offset, data); +} + +static u32 dp_read_sub_hw(struct dp_catalog *dp_catalog, + struct dp_io_data *io_data, u32 offset) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + return dp_read_hw(catalog, io_data, offset); +} + +static void dp_write_sub_hw(struct dp_catalog *dp_catalog, + struct dp_io_data *io_data, u32 offset, u32 data) +{ + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + dp_write_hw(catalog, io_data, offset, data); +} + +/* aux related catalog functions */ +static u32 dp_catalog_aux_read_data(struct dp_catalog_aux *aux) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + goto end; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_aux; + + return dp_read(DP_AUX_DATA); +end: + return 0; +} + +static int dp_catalog_aux_write_data(struct dp_catalog_aux *aux) +{ + int rc = 0; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_aux; + + dp_write(DP_AUX_DATA, aux->data); +end: + return rc; +} + +static int dp_catalog_aux_write_trans(struct dp_catalog_aux *aux) +{ + int rc = 0; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_aux; + + dp_write(DP_AUX_TRANS_CTRL, aux->data); +end: + return rc; +} + +static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read) +{ + int rc = 0; + u32 data = 0; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_aux; + + if (read) { + data = dp_read(DP_AUX_TRANS_CTRL); + data &= ~BIT(9); + dp_write(DP_AUX_TRANS_CTRL, data); + } else { + dp_write(DP_AUX_TRANS_CTRL, 0); + } +end: + return rc; +} + +static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 data = 0; + + if (!aux) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_phy; + + data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS); + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f); + wmb(); /* make sure 0x1f is written before next write */ + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR, 0x9f); + wmb(); /* make sure 0x9f is written before next write */ + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR, 0); + wmb(); /* make sure register is cleared */ +} + +static void dp_catalog_aux_reset(struct dp_catalog_aux *aux) +{ + u32 aux_ctrl; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_aux; + + aux_ctrl = dp_read(DP_AUX_CTRL); + + aux_ctrl |= BIT(1); + dp_write(DP_AUX_CTRL, aux_ctrl); + usleep_range(1000, 1010); /* h/w recommended delay */ + + aux_ctrl &= ~BIT(1); + + dp_write(DP_AUX_CTRL, aux_ctrl); + wmb(); /* make sure AUX reset is done here */ +} + +static void dp_catalog_aux_enable(struct dp_catalog_aux *aux, bool enable) +{ + u32 aux_ctrl; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_aux; + + aux_ctrl = dp_read(DP_AUX_CTRL); + + if (enable) { + aux_ctrl |= BIT(0); + dp_write(DP_AUX_CTRL, aux_ctrl); + wmb(); /* make sure AUX module is enabled */ + + dp_write(DP_TIMEOUT_COUNT, 0xffff); + dp_write(DP_AUX_LIMITS, 0xffff); + } else { + aux_ctrl &= ~BIT(0); + dp_write(DP_AUX_CTRL, aux_ctrl); + } +} + +static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type) +{ + struct dp_catalog_private *catalog; + u32 new_index = 0, current_index = 0; + struct dp_io_data *io_data; + + if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(aux); + + io_data = catalog->io.dp_phy; + + current_index = cfg[type].current_index; + new_index = (current_index + 1) % cfg[type].cfg_cnt; + DP_DEBUG("Updating %s from 0x%08x to 0x%08x\n", + dp_phy_aux_config_type_to_string(type), + cfg[type].lut[current_index], cfg[type].lut[new_index]); + + dp_write(cfg[type].offset, cfg[type].lut[new_index]); + cfg[type].current_index = new_index; +} + +static void dp_catalog_aux_setup(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + int i = 0; + + if (!aux || !cfg) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(aux); + + io_data = catalog->io.dp_phy; + dp_write(DP_PHY_PD_CTL, 0x65); + wmb(); /* make sure PD programming happened */ + + /* Turn on BIAS current for PHY/PLL */ + io_data = catalog->io.dp_pll; + dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b); + + io_data = catalog->io.dp_phy; + dp_write(DP_PHY_PD_CTL, 0x02); + wmb(); /* make sure PD programming happened */ + dp_write(DP_PHY_PD_CTL, 0x7d); + + /* Turn on BIAS current for PHY/PLL */ + io_data = catalog->io.dp_pll; + dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f); + + /* DP AUX CFG register programming */ + io_data = catalog->io.dp_phy; + for (i = 0; i < PHY_AUX_CFG_MAX; i++) + dp_write(cfg[i].offset, cfg[i].lut[cfg[i].current_index]); + + dp_write(DP_PHY_AUX_INTERRUPT_MASK, 0x1F); + wmb(); /* make sure AUX configuration is done before enabling it */ +} + +static void dp_catalog_aux_get_irq(struct dp_catalog_aux *aux, bool cmd_busy) +{ + u32 ack; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!aux) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(aux); + io_data = catalog->io.dp_ahb; + + aux->isr = dp_read(DP_INTR_STATUS); + aux->isr &= ~DP_INTR_MASK1; + ack = aux->isr & DP_INTERRUPT_STATUS1; + ack <<= 1; + ack |= DP_INTR_MASK1; + dp_write(DP_INTR_STATUS, ack); +} + +/* controller related catalog functions */ +static int dp_catalog_ctrl_late_phy_init(struct dp_catalog_ctrl *ctrl, + u8 lane_cnt, bool flipped) +{ + return 0; +} + +static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_ahb; + + return dp_read(DP_HDCP_STATUS); +} + +static void dp_catalog_panel_sdp_update(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 sdp_cfg3_off = 0; + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + if (panel->stream_id == DP_STREAM_1) + sdp_cfg3_off = MMSS_DP1_SDP_CFG3 - MMSS_DP_SDP_CFG3; + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + dp_write(MMSS_DP_SDP_CFG3 + sdp_cfg3_off, 0x01); + dp_write(MMSS_DP_SDP_CFG3 + sdp_cfg3_off, 0x00); +} + +static void dp_catalog_panel_setup_vsif_infoframe_sdp( + struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct drm_msm_ext_hdr_metadata *hdr; + struct dp_io_data *io_data; + u32 header, parity, data, mst_offset = 0; + u8 buf[SZ_64], off = 0; + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + if (panel->stream_id == DP_STREAM_1) + mst_offset = MMSS_DP1_VSCEXT_0 - MMSS_DP_VSCEXT_0; + + catalog = dp_catalog_get_priv(panel); + hdr = &panel->hdr_meta; + io_data = catalog->io.dp_link; + + /* HEADER BYTE 1 */ + header = panel->dhdr_vsif_sdp.HB1; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_1_BIT) + | (parity << PARITY_BYTE_1_BIT)); + dp_write(MMSS_DP_VSCEXT_0 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + /* HEADER BYTE 2 */ + header = panel->dhdr_vsif_sdp.HB2; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_2_BIT) + | (parity << PARITY_BYTE_2_BIT)); + dp_write(MMSS_DP_VSCEXT_1 + mst_offset, data); + + /* HEADER BYTE 3 */ + header = panel->dhdr_vsif_sdp.HB3; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_3_BIT) + | (parity << PARITY_BYTE_3_BIT)); + data |= dp_read(MMSS_DP_VSCEXT_1 + mst_offset); + dp_write(MMSS_DP_VSCEXT_1 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + print_hex_dump(KERN_DEBUG, "[drm-dp] VSCEXT: ", + DUMP_PREFIX_NONE, 16, 4, buf, off, false); +} + +static void dp_catalog_panel_setup_hdr_infoframe_sdp( + struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct drm_msm_ext_hdr_metadata *hdr; + struct dp_io_data *io_data; + u32 header, parity, data, mst_offset = 0; + u8 buf[SZ_64], off = 0; + u32 const version = 0x01; + u32 const length = 0x1a; + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + if (panel->stream_id == DP_STREAM_1) + mst_offset = MMSS_DP1_GENERIC2_0 - MMSS_DP_GENERIC2_0; + + catalog = dp_catalog_get_priv(panel); + hdr = &panel->hdr_meta; + io_data = catalog->io.dp_link; + + /* HEADER BYTE 1 */ + header = panel->shdr_if_sdp.HB1; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_1_BIT) + | (parity << PARITY_BYTE_1_BIT)); + dp_write(MMSS_DP_GENERIC2_0 + mst_offset, + data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + /* HEADER BYTE 2 */ + header = panel->shdr_if_sdp.HB2; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_2_BIT) + | (parity << PARITY_BYTE_2_BIT)); + dp_write(MMSS_DP_GENERIC2_1 + mst_offset, data); + + /* HEADER BYTE 3 */ + header = panel->shdr_if_sdp.HB3; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_3_BIT) + | (parity << PARITY_BYTE_3_BIT)); + data |= dp_read(MMSS_DP_VSCEXT_1 + mst_offset); + dp_write(MMSS_DP_GENERIC2_1 + mst_offset, + data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = version; + data |= length << 8; + data |= hdr->eotf << 16; + dp_write(MMSS_DP_GENERIC2_2 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->display_primaries_x[0]) | + (DP_GET_MSB(hdr->display_primaries_x[0]) << 8) | + (DP_GET_LSB(hdr->display_primaries_y[0]) << 16) | + (DP_GET_MSB(hdr->display_primaries_y[0]) << 24)); + dp_write(MMSS_DP_GENERIC2_3 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->display_primaries_x[1]) | + (DP_GET_MSB(hdr->display_primaries_x[1]) << 8) | + (DP_GET_LSB(hdr->display_primaries_y[1]) << 16) | + (DP_GET_MSB(hdr->display_primaries_y[1]) << 24)); + dp_write(MMSS_DP_GENERIC2_4 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->display_primaries_x[2]) | + (DP_GET_MSB(hdr->display_primaries_x[2]) << 8) | + (DP_GET_LSB(hdr->display_primaries_y[2]) << 16) | + (DP_GET_MSB(hdr->display_primaries_y[2]) << 24)); + dp_write(MMSS_DP_GENERIC2_5 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->white_point_x) | + (DP_GET_MSB(hdr->white_point_x) << 8) | + (DP_GET_LSB(hdr->white_point_y) << 16) | + (DP_GET_MSB(hdr->white_point_y) << 24)); + dp_write(MMSS_DP_GENERIC2_6 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->max_luminance) | + (DP_GET_MSB(hdr->max_luminance) << 8) | + (DP_GET_LSB(hdr->min_luminance) << 16) | + (DP_GET_MSB(hdr->min_luminance) << 24)); + dp_write(MMSS_DP_GENERIC2_7 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (DP_GET_LSB(hdr->max_content_light_level) | + (DP_GET_MSB(hdr->max_content_light_level) << 8) | + (DP_GET_LSB(hdr->max_average_light_level) << 16) | + (DP_GET_MSB(hdr->max_average_light_level) << 24)); + dp_write(MMSS_DP_GENERIC2_8 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = 0; + dp_write(MMSS_DP_GENERIC2_9 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + print_hex_dump(KERN_DEBUG, "[drm-dp] HDR: ", + DUMP_PREFIX_NONE, 16, 4, buf, off, false); +} + +static void dp_catalog_panel_setup_vsc_sdp(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 header, parity, data, mst_offset = 0; + u8 off = 0; + u8 buf[SZ_128]; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + if (panel->stream_id == DP_STREAM_1) + mst_offset = MMSS_DP1_GENERIC0_0 - MMSS_DP_GENERIC0_0; + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + /* HEADER BYTE 1 */ + header = panel->vsc_colorimetry.header.HB1; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_1_BIT) + | (parity << PARITY_BYTE_1_BIT)); + dp_write(MMSS_DP_GENERIC0_0 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + /* HEADER BYTE 2 */ + header = panel->vsc_colorimetry.header.HB2; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_2_BIT) + | (parity << PARITY_BYTE_2_BIT)); + dp_write(MMSS_DP_GENERIC0_1 + mst_offset, data); + + /* HEADER BYTE 3 */ + header = panel->vsc_colorimetry.header.HB3; + parity = dp_header_get_parity(header); + data = ((header << HEADER_BYTE_3_BIT) + | (parity << PARITY_BYTE_3_BIT)); + data |= dp_read(MMSS_DP_GENERIC0_1 + mst_offset); + dp_write(MMSS_DP_GENERIC0_1 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = 0; + dp_write(MMSS_DP_GENERIC0_2 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(MMSS_DP_GENERIC0_3 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(MMSS_DP_GENERIC0_4 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(MMSS_DP_GENERIC0_5 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = (panel->vsc_colorimetry.data[16] & 0xFF) | + ((panel->vsc_colorimetry.data[17] & 0xFF) << 8) | + ((panel->vsc_colorimetry.data[18] & 0x7) << 16); + + dp_write(MMSS_DP_GENERIC0_6 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + data = 0; + dp_write(MMSS_DP_GENERIC0_7 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(MMSS_DP_GENERIC0_8 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + dp_write(MMSS_DP_GENERIC0_9 + mst_offset, data); + memcpy(buf + off, &data, sizeof(data)); + off += sizeof(data); + + print_hex_dump(KERN_DEBUG, "[drm-dp] VSC: ", + DUMP_PREFIX_NONE, 16, 4, buf, off, false); +} + +static void dp_catalog_panel_config_sdp(struct dp_catalog_panel *panel, + bool en) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 cfg, cfg2; + u32 sdp_cfg_off = 0; + u32 sdp_cfg2_off = 0; + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) { + sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + } + + cfg = dp_read(MMSS_DP_SDP_CFG + sdp_cfg_off); + cfg2 = dp_read(MMSS_DP_SDP_CFG2 + sdp_cfg2_off); + + if (en) { + /* GEN0_SDP_EN */ + cfg |= BIT(17); + dp_write(MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); + + /* GENERIC0_SDPSIZE */ + cfg2 |= BIT(16); + dp_write(MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); + + /* setup the GENERIC0 in case of en = true */ + dp_catalog_panel_setup_vsc_sdp(panel); + + } else { + /* GEN0_SDP_EN */ + cfg &= ~BIT(17); + dp_write(MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); + + /* GENERIC0_SDPSIZE */ + cfg2 &= ~BIT(16); + dp_write(MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); + } + + dp_catalog_panel_sdp_update(panel); +} + +static void dp_catalog_panel_config_misc(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 reg_offset = 0; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) + reg_offset = DP1_MISC1_MISC0 - DP_MISC1_MISC0; + + DP_DEBUG("misc settings = 0x%x\n", panel->misc_val); + dp_write(DP_MISC1_MISC0 + reg_offset, panel->misc_val); +} + +static int dp_catalog_panel_set_colorspace(struct dp_catalog_panel *panel, +bool vsc_supported) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return -EINVAL; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (vsc_supported) { + dp_catalog_panel_setup_vsc_sdp(panel); + dp_catalog_panel_sdp_update(panel); + } else + dp_catalog_panel_config_misc(panel); + + return 0; +} + +static void dp_catalog_panel_config_hdr(struct dp_catalog_panel *panel, bool en, + u32 dhdr_max_pkts, bool flush) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 cfg, cfg2, cfg4, misc; + u32 sdp_cfg_off = 0; + u32 sdp_cfg2_off = 0; + u32 sdp_cfg4_off = 0; + u32 misc1_misc0_off = 0; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) { + sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + sdp_cfg4_off = MMSS_DP1_SDP_CFG4 - MMSS_DP_SDP_CFG4; + misc1_misc0_off = DP1_MISC1_MISC0 - DP_MISC1_MISC0; + } + + cfg = dp_read(MMSS_DP_SDP_CFG + sdp_cfg_off); + cfg2 = dp_read(MMSS_DP_SDP_CFG2 + sdp_cfg2_off); + misc = dp_read(DP_MISC1_MISC0 + misc1_misc0_off); + + if (en) { + if (dhdr_max_pkts) { + /* VSCEXT_SDP_EN */ + cfg |= BIT(16); + /* DHDR_EN, DHDR_PACKET_LIMIT */ + cfg4 = (dhdr_max_pkts << 1) | BIT(0); + dp_write(MMSS_DP_SDP_CFG4 + sdp_cfg4_off, cfg4); + dp_catalog_panel_setup_vsif_infoframe_sdp(panel); + } + + /* GEN2_SDP_EN */ + cfg |= BIT(19); + dp_write(MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); + + /* GENERIC2_SDPSIZE */ + cfg2 |= BIT(20); + dp_write(MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); + + dp_catalog_panel_setup_hdr_infoframe_sdp(panel); + + if (panel->hdr_meta.eotf) + DP_DEBUG("Enabled\n"); + else + DP_DEBUG("Reset\n"); + } else { + /* VSCEXT_SDP_ENG */ + cfg &= ~BIT(16) & ~BIT(19); + dp_write(MMSS_DP_SDP_CFG + sdp_cfg_off, cfg); + + /* GENERIC0_SDPSIZE GENERIC2_SDPSIZE */ + cfg2 &= ~BIT(20); + dp_write(MMSS_DP_SDP_CFG2 + sdp_cfg2_off, cfg2); + + /* DHDR_EN, DHDR_PACKET_LIMIT */ + cfg4 = 0; + dp_write(MMSS_DP_SDP_CFG4 + sdp_cfg4_off, cfg4); + + DP_DEBUG("Disabled\n"); + } + + if (flush) { + DP_DEBUG("flushing HDR metadata\n"); + dp_catalog_panel_sdp_update(panel); + } +} + +static void dp_catalog_panel_update_transfer_unit( + struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!panel || panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + dp_write(DP_VALID_BOUNDARY, panel->valid_boundary); + dp_write(DP_TU, panel->dp_tu); + dp_write(DP_VALID_BOUNDARY_2, panel->valid_boundary2); +} + +static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + dp_write(DP_STATE_CTRL, state); + /* make sure to change the hw state */ + wmb(); +} + +static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u8 ln_cnt) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 cfg; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + cfg = dp_read(DP_CONFIGURATION_CTRL); + cfg &= ~(BIT(4) | BIT(5)); + cfg |= (ln_cnt - 1) << 4; + dp_write(DP_CONFIGURATION_CTRL, cfg); + + cfg = dp_read(DP_MAINLINK_CTRL); + cfg |= 0x02000000; + dp_write(DP_MAINLINK_CTRL, cfg); + + DP_DEBUG("DP_MAINLINK_CTRL=0x%x\n", cfg); +} + +static void dp_catalog_panel_config_ctrl(struct dp_catalog_panel *panel, + u32 cfg) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 strm_reg_off = 0, mainlink_ctrl; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) + strm_reg_off = DP1_CONFIGURATION_CTRL - DP_CONFIGURATION_CTRL; + + DP_DEBUG("DP_CONFIGURATION_CTRL=0x%x\n", cfg); + + dp_write(DP_CONFIGURATION_CTRL + strm_reg_off, cfg); + + mainlink_ctrl = dp_read(DP_MAINLINK_CTRL); + + if (panel->stream_id == DP_STREAM_0) + io_data = catalog->io.dp_p0; + else if (panel->stream_id == DP_STREAM_1) + io_data = catalog->io.dp_p1; + + if (mainlink_ctrl & BIT(8)) + dp_write(MMSS_DP_ASYNC_FIFO_CONFIG, 0x01); + else + dp_write(MMSS_DP_ASYNC_FIFO_CONFIG, 0x00); +} + +static void dp_catalog_panel_config_dto(struct dp_catalog_panel *panel, + bool ack) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 dsc_dto; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + switch (panel->stream_id) { + case DP_STREAM_0: + io_data = catalog->io.dp_p0; + break; + case DP_STREAM_1: + io_data = catalog->io.dp_p1; + break; + default: + DP_ERR("invalid stream id\n"); + return; + } + + dsc_dto = dp_read(MMSS_DP_DSC_DTO); + if (ack) + dsc_dto = BIT(1); + else + dsc_dto &= ~BIT(1); + dp_write(MMSS_DP_DSC_DTO, dsc_dto); +} + +static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl, + bool flipped, char *lane_map) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + dp_write(DP_LOGICAL2PHYSICAL_LANE_MAPPING, 0xe4); +} + +static void dp_catalog_ctrl_lane_pnswap(struct dp_catalog_ctrl *ctrl, + u8 ln_pnswap) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 cfg0, cfg1; + + catalog = dp_catalog_get_priv(ctrl); + + cfg0 = 0x0a; + cfg1 = 0x0a; + + cfg0 |= ((ln_pnswap >> 0) & 0x1) << 0; + cfg0 |= ((ln_pnswap >> 1) & 0x1) << 2; + cfg1 |= ((ln_pnswap >> 2) & 0x1) << 0; + cfg1 |= ((ln_pnswap >> 3) & 0x1) << 2; + + io_data = catalog->io.dp_ln_tx0; + dp_write(TXn_TX_POL_INV, cfg0); + + io_data = catalog->io.dp_ln_tx1; + dp_write(TXn_TX_POL_INV, cfg1); +} + +static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl, + bool enable) +{ + u32 mainlink_ctrl, reg; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + if (enable) { + reg = dp_read(DP_MAINLINK_CTRL); + mainlink_ctrl = reg & ~(0x03); + dp_write(DP_MAINLINK_CTRL, mainlink_ctrl); + wmb(); /* make sure mainlink is turned off before reset */ + mainlink_ctrl = reg | 0x02; + dp_write(DP_MAINLINK_CTRL, mainlink_ctrl); + wmb(); /* make sure mainlink entered reset */ + mainlink_ctrl = reg & ~(0x03); + dp_write(DP_MAINLINK_CTRL, mainlink_ctrl); + wmb(); /* make sure mainlink reset done */ + mainlink_ctrl = reg | 0x01; + dp_write(DP_MAINLINK_CTRL, mainlink_ctrl); + wmb(); /* make sure mainlink turned on */ + } else { + mainlink_ctrl = dp_read(DP_MAINLINK_CTRL); + mainlink_ctrl &= ~BIT(0); + dp_write(DP_MAINLINK_CTRL, mainlink_ctrl); + } +} + +static void dp_catalog_panel_config_msa(struct dp_catalog_panel *panel, + u32 rate, u32 stream_rate_khz) +{ + u32 pixel_m, pixel_n; + u32 mvid, nvid; + u32 const nvid_fixed = 0x8000; + u32 const link_rate_hbr2 = 540000; + u32 const link_rate_hbr3 = 810000; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 strm_reg_off = 0; + u32 mvid_reg_off = 0, nvid_reg_off = 0; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_mmss_cc; + + if (panel->stream_id == DP_STREAM_1) + strm_reg_off = MMSS_DP_PIXEL1_M - MMSS_DP_PIXEL_M; + + pixel_m = dp_read(MMSS_DP_PIXEL_M + strm_reg_off); + pixel_n = dp_read(MMSS_DP_PIXEL_N + strm_reg_off); + DP_DEBUG("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); + + mvid = (pixel_m & 0xFFFF) * 5; + nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); + + if (nvid < nvid_fixed) { + u32 temp; + + temp = (nvid_fixed / nvid) * nvid; + mvid = (nvid_fixed / nvid) * mvid; + nvid = temp; + } + + DP_DEBUG("rate = %d\n", rate); + + if (panel->widebus_en) + mvid <<= 1; + + if (link_rate_hbr2 == rate) + nvid *= 2; + + if (link_rate_hbr3 == rate) + nvid *= 3; + + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) { + mvid_reg_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID; + nvid_reg_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID; + } + + DP_DEBUG("mvid=0x%x, nvid=0x%x\n", mvid, nvid); + dp_write(DP_SOFTWARE_MVID + mvid_reg_off, mvid); + dp_write(DP_SOFTWARE_NVID + nvid_reg_off, nvid); +} + +static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl, + u32 pattern) +{ + int bit, cnt = 10; + u32 data; + const u32 link_training_offset = 3; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + switch (pattern) { + case DP_TRAINING_PATTERN_4: + bit = 3; + break; + case DP_TRAINING_PATTERN_3: + case DP_TRAINING_PATTERN_2: + case DP_TRAINING_PATTERN_1: + bit = pattern - 1; + break; + default: + DP_ERR("invalid pattern\n"); + return; + } + + DP_DEBUG("hw: bit=%d train=%d\n", bit, pattern); + dp_write(DP_STATE_CTRL, BIT(bit)); + + bit += link_training_offset; + + while (cnt--) { + data = dp_read(DP_MAINLINK_READY); + if (data & BIT(bit)) + break; + } + + if (cnt == 0) + DP_ERR("set link_train=%d failed\n", pattern); +} + +static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.usb3_dp_com; + + DP_DEBUG("Program PHYMODE to DP only\n"); + dp_write(USB3_DP_COM_RESET_OVRD_CTRL, 0x0a); + dp_write(USB3_DP_COM_PHY_MODE_CTRL, 0x02); + dp_write(USB3_DP_COM_SW_RESET, 0x01); + /* make sure usb3 com phy software reset is done */ + wmb(); + + if (!flip) /* CC1 */ + dp_write(USB3_DP_COM_TYPEC_CTRL, 0x02); + else /* CC2 */ + dp_write(USB3_DP_COM_TYPEC_CTRL, 0x03); + + dp_write(USB3_DP_COM_SWI_CTRL, 0x00); + dp_write(USB3_DP_COM_SW_RESET, 0x00); + /* make sure the software reset is done */ + wmb(); + + dp_write(USB3_DP_COM_POWER_DOWN_CTRL, 0x01); + dp_write(USB3_DP_COM_RESET_OVRD_CTRL, 0x00); + /* make sure phy is brought out of reset */ + wmb(); +} + +static void dp_catalog_panel_tpg_cfg(struct dp_catalog_panel *panel, + bool enable) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + + if (panel->stream_id == DP_STREAM_0) + io_data = catalog->io.dp_p0; + else if (panel->stream_id == DP_STREAM_1) + io_data = catalog->io.dp_p1; + + if (!enable) { + dp_write(MMSS_DP_TPG_MAIN_CONTROL, 0x0); + dp_write(MMSS_DP_BIST_ENABLE, 0x0); + dp_write(MMSS_DP_TIMING_ENGINE_EN, 0x0); + wmb(); /* ensure Timing generator is turned off */ + return; + } + + dp_write(MMSS_DP_INTF_CONFIG, 0x0); + dp_write(MMSS_DP_INTF_HSYNC_CTL, + panel->hsync_ctl); + dp_write(MMSS_DP_INTF_VSYNC_PERIOD_F0, + panel->vsync_period * panel->hsync_period); + dp_write(MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0, + panel->v_sync_width * panel->hsync_period); + dp_write(MMSS_DP_INTF_VSYNC_PERIOD_F1, 0); + dp_write(MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1, 0); + dp_write(MMSS_DP_INTF_DISPLAY_HCTL, panel->display_hctl); + dp_write(MMSS_DP_INTF_ACTIVE_HCTL, 0); + dp_write(MMSS_INTF_DISPLAY_V_START_F0, panel->display_v_start); + dp_write(MMSS_DP_INTF_DISPLAY_V_END_F0, panel->display_v_end); + dp_write(MMSS_INTF_DISPLAY_V_START_F1, 0); + dp_write(MMSS_DP_INTF_DISPLAY_V_END_F1, 0); + dp_write(MMSS_DP_INTF_ACTIVE_V_START_F0, 0); + dp_write(MMSS_DP_INTF_ACTIVE_V_END_F0, 0); + dp_write(MMSS_DP_INTF_ACTIVE_V_START_F1, 0); + dp_write(MMSS_DP_INTF_ACTIVE_V_END_F1, 0); + dp_write(MMSS_DP_INTF_POLARITY_CTL, 0); + wmb(); /* ensure TPG registers are programmed */ + + dp_write(MMSS_DP_TPG_MAIN_CONTROL, 0x100); + dp_write(MMSS_DP_TPG_VIDEO_CONFIG, 0x5); + wmb(); /* ensure TPG config is programmed */ + dp_write(MMSS_DP_BIST_ENABLE, 0x1); + dp_write(MMSS_DP_TIMING_ENGINE_EN, 0x1); + wmb(); /* ensure Timing generator is turned on */ +} + +static void dp_catalog_panel_dsc_cfg(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 reg, offset; + int i; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + + if (panel->stream_id == DP_STREAM_0) + io_data = catalog->io.dp_p0; + else + io_data = catalog->io.dp_p1; + + dp_write(MMSS_DP_DSC_DTO_COUNT, panel->dsc.dto_count); + + reg = dp_read(MMSS_DP_DSC_DTO); + if (panel->dsc.dto_en) { + reg |= BIT(0); + reg |= (panel->dsc.dto_n << 8); + reg |= (panel->dsc.dto_d << 16); + } + dp_write(MMSS_DP_DSC_DTO, reg); + + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_0) + offset = 0; + else + offset = DP1_COMPRESSION_MODE_CTRL - DP_COMPRESSION_MODE_CTRL; + + dp_write(DP_PPS_HB_0_3 + offset, 0x7F1000); + dp_write(DP_PPS_PB_0_3 + offset, 0xA22300); + + for (i = 0; i < panel->dsc.parity_word_len; i++) + dp_write(DP_PPS_PB_4_7 + (i << 2) + offset, + panel->dsc.parity_word[i]); + + for (i = 0; i < panel->dsc.pps_word_len; i++) + dp_write(DP_PPS_PPS_0_3 + (i << 2) + offset, + panel->dsc.pps_word[i]); + + reg = 0; + if (panel->dsc.dsc_en) { + reg = BIT(0); + reg |= (panel->dsc.eol_byte_num << 3); + reg |= (panel->dsc.slice_per_pkt << 5); + reg |= (panel->dsc.bytes_per_pkt << 16); + reg |= (panel->dsc.be_in_lane << 10); + } + dp_write(DP_COMPRESSION_MODE_CTRL + offset, reg); + + DP_DEBUG("compression:0x%x for stream:%d\n", + reg, panel->stream_id); +} + +static void dp_catalog_panel_dp_flush(struct dp_catalog_panel *panel, + enum dp_flush_bit flush_bit) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 dp_flush, offset; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_0) + offset = 0; + else + offset = MMSS_DP1_FLUSH - MMSS_DP_FLUSH; + + dp_flush = dp_read(MMSS_DP_FLUSH + offset); + dp_flush |= BIT(flush_bit); + dp_write(MMSS_DP_FLUSH + offset, dp_flush); +} + +static void dp_catalog_panel_pps_flush(struct dp_catalog_panel *panel) +{ + dp_catalog_panel_dp_flush(panel, DP_PPS_FLUSH); + DP_DEBUG("pps flush for stream:%d\n", panel->stream_id); +} + +static void dp_catalog_panel_dhdr_flush(struct dp_catalog_panel *panel) +{ + dp_catalog_panel_dp_flush(panel, DP_DHDR_FLUSH); + DP_DEBUG("dhdr flush for stream:%d\n", panel->stream_id); +} + + +static bool dp_catalog_panel_dhdr_busy(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 dp_flush, offset; + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return false; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_0) + offset = 0; + else + offset = MMSS_DP1_FLUSH - MMSS_DP_FLUSH; + + dp_flush = dp_read(MMSS_DP_FLUSH + offset); + + return dp_flush & BIT(DP_DHDR_FLUSH) ? true : false; +} + +static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl) +{ + u32 sw_reset; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_ahb; + + sw_reset = dp_read(DP_SW_RESET); + + sw_reset |= BIT(0); + dp_write(DP_SW_RESET, sw_reset); + usleep_range(1000, 1010); /* h/w recommended delay */ + + sw_reset &= ~BIT(0); + dp_write(DP_SW_RESET, sw_reset); +} + +static bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog_ctrl *ctrl) +{ + u32 data; + int cnt = 10; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + goto end; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + while (--cnt) { + /* DP_MAINLINK_READY */ + data = dp_read(DP_MAINLINK_READY); + if (data & BIT(0)) + return true; + + usleep_range(1000, 1010); /* 1ms wait before next reg read */ + } + DP_ERR("mainlink not ready\n"); +end: + return false; +} + +static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl, + bool enable) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_ahb; + + if (enable) { + dp_write(DP_INTR_STATUS, DP_INTR_MASK1); + dp_write(DP_INTR_STATUS2, DP_INTR_MASK2); + dp_write(DP_INTR_STATUS5, DP_INTR_MASK5); + } else { + dp_write(DP_INTR_STATUS, 0x00); + dp_write(DP_INTR_STATUS2, 0x00); + dp_write(DP_INTR_STATUS5, 0x00); + } +} + +static void dp_catalog_ctrl_get_interrupt(struct dp_catalog_ctrl *ctrl) +{ + u32 ack = 0; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_ahb; + + ctrl->isr = dp_read(DP_INTR_STATUS2); + ctrl->isr &= ~DP_INTR_MASK2; + ack = ctrl->isr & DP_INTERRUPT_STATUS2; + ack <<= 1; + ack |= DP_INTR_MASK2; + dp_write(DP_INTR_STATUS2, ack); + + ctrl->isr5 = dp_read(DP_INTR_STATUS5); + ctrl->isr5 &= ~DP_INTR_MASK5; + ack = ctrl->isr5 & DP_INTERRUPT_STATUS5; + ack <<= 1; + ack |= DP_INTR_MASK5; + dp_write(DP_INTR_STATUS5, ack); +} + +static void dp_catalog_ctrl_phy_reset(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_ahb; + + dp_write(DP_PHY_CTRL, 0x5); /* bit 0 & 2 */ + usleep_range(1000, 1010); /* h/w recommended delay */ + dp_write(DP_PHY_CTRL, 0x0); + wmb(); /* make sure PHY reset done */ +} + +static void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog_ctrl *ctrl, + bool flipped, u8 ln_cnt) +{ + u32 info = 0x0; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u8 orientation = BIT(!!flipped); + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_phy; + + info |= (ln_cnt & 0x0F); + info |= ((orientation & 0x0F) << 4); + DP_DEBUG("Shared Info = 0x%x\n", info); + + dp_write(DP_PHY_SPARE0, info); +} + +static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl, + u8 v_level, u8 p_level, bool high) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u8 value0, value1; + u32 version; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + DP_DEBUG("hw: v=%d p=%d\n", v_level, p_level); + + io_data = catalog->io.dp_ahb; + version = dp_read(DP_HW_VERSION); + + if (version == 0x10020004) { + if (high) { + value0 = vm_voltage_swing_hbr3_hbr2[v_level][p_level]; + value1 = vm_pre_emphasis_hbr3_hbr2[v_level][p_level]; + } else { + value0 = vm_voltage_swing_hbr_rbr[v_level][p_level]; + value1 = vm_pre_emphasis_hbr_rbr[v_level][p_level]; + } + } else { + value0 = vm_voltage_swing[v_level][p_level]; + value1 = vm_pre_emphasis[v_level][p_level]; + } + + /* program default setting first */ + + io_data = catalog->io.dp_ln_tx0; + dp_write(TXn_TX_DRV_LVL, 0x2A); + dp_write(TXn_TX_EMP_POST1_LVL, 0x20); + + io_data = catalog->io.dp_ln_tx1; + dp_write(TXn_TX_DRV_LVL, 0x2A); + dp_write(TXn_TX_EMP_POST1_LVL, 0x20); + + /* Enable MUX to use Cursor values from these registers */ + value0 |= BIT(5); + value1 |= BIT(5); + + /* Configure host and panel only if both values are allowed */ + if (value0 != 0xFF && value1 != 0xFF) { + io_data = catalog->io.dp_ln_tx0; + dp_write(TXn_TX_DRV_LVL, value0); + dp_write(TXn_TX_EMP_POST1_LVL, value1); + + io_data = catalog->io.dp_ln_tx1; + dp_write(TXn_TX_DRV_LVL, value0); + dp_write(TXn_TX_EMP_POST1_LVL, value1); + + DP_DEBUG("hw: vx_value=0x%x px_value=0x%x\n", + value0, value1); + } else { + DP_ERR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n", + v_level, value0, p_level, value1); + } +} + +static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl, + u32 pattern) +{ + struct dp_catalog_private *catalog; + u32 value = 0x0; + struct dp_io_data *io_data = NULL; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + dp_write(DP_STATE_CTRL, 0x0); + + switch (pattern) { + case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: + dp_write(DP_STATE_CTRL, 0x1); + break; + case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: + value &= ~(1 << 16); + dp_write(DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + value |= 0xFC; + dp_write(DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + dp_write(DP_MAINLINK_LEVELS, 0x2); + dp_write(DP_STATE_CTRL, 0x10); + break; + case DP_TEST_PHY_PATTERN_PRBS7: + dp_write(DP_STATE_CTRL, 0x20); + break; + case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: + dp_write(DP_STATE_CTRL, 0x40); + /* 00111110000011111000001111100000 */ + dp_write(DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0); + /* 00001111100000111110000011111000 */ + dp_write(DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8); + /* 1111100000111110 */ + dp_write(DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E); + break; + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1: + value = dp_read(DP_MAINLINK_CTRL); + value &= ~BIT(4); + dp_write(DP_MAINLINK_CTRL, value); + + value = BIT(16); + dp_write(DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + value |= 0xFC; + dp_write(DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); + dp_write(DP_MAINLINK_LEVELS, 0x2); + dp_write(DP_STATE_CTRL, 0x10); + + value = dp_read(DP_MAINLINK_CTRL); + value |= BIT(0); + dp_write(DP_MAINLINK_CTRL, value); + break; + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3: + dp_write(DP_MAINLINK_CTRL, 0x01); + dp_write(DP_STATE_CTRL, 0x8); + break; + default: + DP_DEBUG("No valid test pattern requested: 0x%x\n", pattern); + return; + } + + /* Make sure the test pattern is programmed in the hardware */ + wmb(); +} + +static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return 0; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + return dp_read(DP_MAINLINK_READY); +} + +static void dp_catalog_ctrl_fec_config(struct dp_catalog_ctrl *ctrl, + bool enable) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + u32 reg; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + io_data = catalog->io.dp_link; + + reg = dp_read(DP_MAINLINK_CTRL); + + /* + * fec_en = BIT(12) + * fec_seq_mode = BIT(22) + * sde_flush = BIT(23) | BIT(24) + * fb_boundary_sel = BIT(25) + */ + if (enable) + reg |= BIT(12) | BIT(22) | BIT(23) | BIT(24) | BIT(25); + else + reg &= ~BIT(12); + + dp_write(DP_MAINLINK_CTRL, reg); + /* make sure mainlink configuration is updated with fec sequence */ + wmb(); +} + +static int dp_catalog_reg_dump(struct dp_catalog *dp_catalog, + char *name, u8 **out_buf, u32 *out_buf_len) +{ + int ret = 0; + u8 *buf; + u32 len; + struct dp_io_data *io_data; + struct dp_catalog_private *catalog; + struct dp_parser *parser; + + if (!dp_catalog) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + catalog = container_of(dp_catalog, struct dp_catalog_private, + dp_catalog); + + parser = catalog->parser; + parser->get_io_buf(parser, name); + io_data = parser->get_io(parser, name); + if (!io_data) { + DP_ERR("IO %s not found\n", name); + ret = -EINVAL; + goto end; + } + + buf = io_data->buf; + len = io_data->io.len; + + if (!buf || !len) { + DP_ERR("no buffer available\n"); + ret = -ENOMEM; + goto end; + } + + if (!strcmp(catalog->exe_mode, "hw") || + !strcmp(catalog->exe_mode, "all")) { + u32 i, data; + u32 const rowsize = 4; + void __iomem *addr = io_data->io.base; + + memset(buf, 0, len); + + for (i = 0; i < len / rowsize; i++) { + data = readl_relaxed(addr); + memcpy(buf + (rowsize * i), &data, sizeof(u32)); + + addr += rowsize; + } + } + + *out_buf = buf; + *out_buf_len = len; +end: + if (ret) + parser->clear_io_buf(parser); + + return ret; +} + +static void dp_catalog_ctrl_mst_config(struct dp_catalog_ctrl *ctrl, + bool enable) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + u32 reg; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + reg = dp_read(DP_MAINLINK_CTRL); + if (enable) + reg |= (0x04000100); + else + reg &= ~(0x04000100); + + dp_write(DP_MAINLINK_CTRL, reg); + /* make sure mainlink MST configuration is updated */ + wmb(); +} + +static void dp_catalog_ctrl_trigger_act(struct dp_catalog_ctrl *ctrl) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + dp_write(DP_MST_ACT, 0x1); + /* make sure ACT signal is performed */ + wmb(); +} + +static void dp_catalog_ctrl_read_act_complete_sts(struct dp_catalog_ctrl *ctrl, + bool *sts) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + u32 reg; + + if (!ctrl || !sts) { + DP_ERR("invalid input\n"); + return; + } + + *sts = false; + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + reg = dp_read(DP_MST_ACT); + + if (!reg) + *sts = true; +} + +static void dp_catalog_ctrl_channel_alloc(struct dp_catalog_ctrl *ctrl, + u32 ch, u32 ch_start_slot, u32 tot_slot_cnt) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + u32 i, slot_reg_1, slot_reg_2, slot; + u32 reg_off = 0; + int const num_slots_per_reg = 32; + + if (!ctrl || ch >= DP_STREAM_MAX) { + DP_ERR("invalid input. ch %d\n", ch); + return; + } + + if (ch_start_slot > DP_MAX_TIME_SLOTS || + (ch_start_slot + tot_slot_cnt > DP_MAX_TIME_SLOTS)) { + DP_ERR("invalid slots start %d, tot %d\n", + ch_start_slot, tot_slot_cnt); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + DP_DEBUG("ch %d, start_slot %d, tot_slot %d\n", + ch, ch_start_slot, tot_slot_cnt); + + if (ch == DP_STREAM_1) + reg_off = DP_DP1_TIMESLOT_1_32 - DP_DP0_TIMESLOT_1_32; + + slot_reg_1 = 0; + slot_reg_2 = 0; + + if (ch_start_slot && tot_slot_cnt) { + ch_start_slot--; + for (i = 0; i < tot_slot_cnt; i++) { + if (ch_start_slot < num_slots_per_reg) { + slot_reg_1 |= BIT(ch_start_slot); + } else { + slot = ch_start_slot - num_slots_per_reg; + slot_reg_2 |= BIT(slot); + } + ch_start_slot++; + } + } + + DP_DEBUG("ch:%d slot_reg_1:%d, slot_reg_2:%d\n", ch, + slot_reg_1, slot_reg_2); + + dp_write(DP_DP0_TIMESLOT_1_32 + reg_off, slot_reg_1); + dp_write(DP_DP0_TIMESLOT_33_63 + reg_off, slot_reg_2); +} + +static void dp_catalog_ctrl_channel_dealloc(struct dp_catalog_ctrl *ctrl, + u32 ch, u32 ch_start_slot, u32 tot_slot_cnt) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + u32 i, slot_reg_1, slot_reg_2, slot; + u32 reg_off = 0; + + if (!ctrl || ch >= DP_STREAM_MAX) { + DP_ERR("invalid input. ch %d\n", ch); + return; + } + + if (ch_start_slot > DP_MAX_TIME_SLOTS || + (ch_start_slot + tot_slot_cnt > DP_MAX_TIME_SLOTS)) { + DP_ERR("invalid slots start %d, tot %d\n", + ch_start_slot, tot_slot_cnt); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + DP_DEBUG("dealloc ch %d, start_slot %d, tot_slot %d\n", + ch, ch_start_slot, tot_slot_cnt); + + if (ch == DP_STREAM_1) + reg_off = DP_DP1_TIMESLOT_1_32 - DP_DP0_TIMESLOT_1_32; + + slot_reg_1 = dp_read(DP_DP0_TIMESLOT_1_32 + reg_off); + slot_reg_2 = dp_read(DP_DP0_TIMESLOT_33_63 + reg_off); + + ch_start_slot = ch_start_slot - 1; + for (i = 0; i < tot_slot_cnt; i++) { + if (ch_start_slot < 33) { + slot_reg_1 &= ~BIT(ch_start_slot); + } else { + slot = ch_start_slot - 33; + slot_reg_2 &= ~BIT(slot); + } + ch_start_slot++; + } + + DP_DEBUG("dealloc ch:%d slot_reg_1:%d, slot_reg_2:%d\n", ch, + slot_reg_1, slot_reg_2); + + dp_write(DP_DP0_TIMESLOT_1_32 + reg_off, slot_reg_1); + dp_write(DP_DP0_TIMESLOT_33_63 + reg_off, slot_reg_2); +} + +static void dp_catalog_ctrl_update_rg(struct dp_catalog_ctrl *ctrl, u32 ch, + u32 x_int, u32 y_frac_enum) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data = NULL; + u32 rg, reg_off = 0; + + if (!ctrl || ch >= DP_STREAM_MAX) { + DP_ERR("invalid input. ch %d\n", ch); + return; + } + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + rg = y_frac_enum; + rg |= (x_int << 16); + + DP_DEBUG("ch: %d x_int:%d y_frac_enum:%d rg:%d\n", ch, x_int, + y_frac_enum, rg); + + if (ch == DP_STREAM_1) + reg_off = DP_DP1_RG - DP_DP0_RG; + + dp_write(DP_DP0_RG + reg_off, rg); +} + +static void dp_catalog_ctrl_mainlink_levels(struct dp_catalog_ctrl *ctrl, + u8 lane_cnt) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 mainlink_levels, safe_to_exit_level = 14; + + catalog = dp_catalog_get_priv(ctrl); + + io_data = catalog->io.dp_link; + + switch (lane_cnt) { + case 1: + safe_to_exit_level = 14; + break; + case 2: + safe_to_exit_level = 8; + break; + case 4: + safe_to_exit_level = 5; + break; + default: + DP_DEBUG("setting the default safe_to_exit_level = %u\n", + safe_to_exit_level); + break; + } + + mainlink_levels = dp_read(DP_MAINLINK_LEVELS); + mainlink_levels &= 0xFE0; + mainlink_levels |= safe_to_exit_level; + + DP_DEBUG("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n", + mainlink_levels, safe_to_exit_level); + + dp_write(DP_MAINLINK_LEVELS, mainlink_levels); +} + + +/* panel related catalog functions */ +static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 offset = 0, reg; + + if (!panel) { + DP_ERR("invalid input\n"); + goto end; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + goto end; + } + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) + offset = DP1_TOTAL_HOR_VER - DP_TOTAL_HOR_VER; + + dp_write(DP_TOTAL_HOR_VER + offset, panel->total); + dp_write(DP_START_HOR_VER_FROM_SYNC + offset, panel->sync_start); + dp_write(DP_HSYNC_VSYNC_WIDTH_POLARITY + offset, panel->width_blanking); + dp_write(DP_ACTIVE_HOR_VER + offset, panel->dp_active); + + if (panel->stream_id == DP_STREAM_0) + io_data = catalog->io.dp_p0; + else + io_data = catalog->io.dp_p1; + + reg = dp_read(MMSS_DP_INTF_CONFIG); + + if (panel->widebus_en) + reg |= BIT(4); + else + reg &= ~BIT(4); + + dp_write(MMSS_DP_INTF_CONFIG, reg); +end: + return 0; +} + +static void dp_catalog_hpd_config_hpd(struct dp_catalog_hpd *hpd, bool en) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!hpd) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv(hpd); + io_data = catalog->io.dp_aux; + + if (en) { + u32 reftimer = dp_read(DP_DP_HPD_REFTIMER); + + /* Arm only the UNPLUG and HPD_IRQ interrupts */ + dp_write(DP_DP_HPD_INT_ACK, 0xF); + dp_write(DP_DP_HPD_INT_MASK, 0xA); + + /* Enable REFTIMER to count 1ms */ + reftimer |= BIT(16); + dp_write(DP_DP_HPD_REFTIMER, reftimer); + + /* Connect_time is 250us & disconnect_time is 2ms */ + dp_write(DP_DP_HPD_EVENT_TIME_0, 0x3E800FA); + dp_write(DP_DP_HPD_EVENT_TIME_1, 0x1F407D0); + + /* Enable HPD */ + dp_write(DP_DP_HPD_CTRL, 0x1); + + } else { + /* Disable HPD */ + dp_write(DP_DP_HPD_CTRL, 0x0); + } +} + +static u32 dp_catalog_hpd_get_interrupt(struct dp_catalog_hpd *hpd) +{ + u32 isr = 0; + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + + if (!hpd) { + DP_ERR("invalid input\n"); + return isr; + } + + catalog = dp_catalog_get_priv(hpd); + + io_data = catalog->io.dp_aux; + isr = dp_read(DP_DP_HPD_INT_STATUS); + dp_write(DP_DP_HPD_INT_ACK, (isr & 0xf)); + + return isr; +} + +static void dp_catalog_audio_init(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = { + { + MMSS_DP_AUDIO_STREAM_0, + MMSS_DP_AUDIO_STREAM_1, + MMSS_DP_AUDIO_STREAM_1, + }, + { + MMSS_DP_AUDIO_TIMESTAMP_0, + MMSS_DP_AUDIO_TIMESTAMP_1, + MMSS_DP_AUDIO_TIMESTAMP_1, + }, + { + MMSS_DP_AUDIO_INFOFRAME_0, + MMSS_DP_AUDIO_INFOFRAME_1, + MMSS_DP_AUDIO_INFOFRAME_1, + }, + { + MMSS_DP_AUDIO_COPYMANAGEMENT_0, + MMSS_DP_AUDIO_COPYMANAGEMENT_1, + MMSS_DP_AUDIO_COPYMANAGEMENT_1, + }, + { + MMSS_DP_AUDIO_ISRC_0, + MMSS_DP_AUDIO_ISRC_1, + MMSS_DP_AUDIO_ISRC_1, + }, + }; + + if (!audio) + return; + + catalog = dp_catalog_get_priv(audio); + + catalog->audio_map = sdp_map; +} + +static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 sdp_cfg = 0, sdp_cfg_off = 0; + u32 sdp_cfg2 = 0, sdp_cfg2_off = 0; + + if (!audio) + return; + + if (audio->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id:%d\n", audio->stream_id); + return; + } + + if (audio->stream_id == DP_STREAM_1) { + sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + } + + catalog = dp_catalog_get_priv(audio); + io_data = catalog->io.dp_link; + + sdp_cfg = dp_read(MMSS_DP_SDP_CFG + sdp_cfg_off); + + /* AUDIO_TIMESTAMP_SDP_EN */ + sdp_cfg |= BIT(1); + /* AUDIO_STREAM_SDP_EN */ + sdp_cfg |= BIT(2); + /* AUDIO_COPY_MANAGEMENT_SDP_EN */ + sdp_cfg |= BIT(5); + /* AUDIO_ISRC_SDP_EN */ + sdp_cfg |= BIT(6); + /* AUDIO_INFOFRAME_SDP_EN */ + sdp_cfg |= BIT(20); + + DP_DEBUG("sdp_cfg = 0x%x\n", sdp_cfg); + dp_write(MMSS_DP_SDP_CFG + sdp_cfg_off, sdp_cfg); + + sdp_cfg2 = dp_read(MMSS_DP_SDP_CFG2 + sdp_cfg_off); + /* IFRM_REGSRC -> Do not use reg values */ + sdp_cfg2 &= ~BIT(0); + /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */ + sdp_cfg2 &= ~BIT(1); + + DP_DEBUG("sdp_cfg2 = 0x%x\n", sdp_cfg2); + dp_write(MMSS_DP_SDP_CFG2 + sdp_cfg_off, sdp_cfg2); +} + +static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; + struct dp_io_data *io_data; + enum dp_catalog_audio_sdp_type sdp; + enum dp_catalog_audio_header_type header; + + if (!audio) + return; + + catalog = dp_catalog_get_priv(audio); + + io_data = catalog->io.dp_link; + sdp_map = catalog->audio_map; + sdp = audio->sdp_type; + header = audio->sdp_header; + + audio->data = dp_read(sdp_map[sdp][header]); +} + +static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; + struct dp_io_data *io_data; + enum dp_catalog_audio_sdp_type sdp; + enum dp_catalog_audio_header_type header; + u32 data; + + if (!audio) + return; + + catalog = dp_catalog_get_priv(audio); + + io_data = catalog->io.dp_link; + sdp_map = catalog->audio_map; + sdp = audio->sdp_type; + header = audio->sdp_header; + data = audio->data; + + dp_write(sdp_map[sdp][header], data); +} + +static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 acr_ctrl, select; + + catalog = dp_catalog_get_priv(audio); + + select = audio->data; + io_data = catalog->io.dp_link; + + acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14); + + DP_DEBUG("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl); + + dp_write(MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl); +} + +static void dp_catalog_audio_enable(struct dp_catalog_audio *audio) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + bool enable; + u32 audio_ctrl; + + catalog = dp_catalog_get_priv(audio); + + io_data = catalog->io.dp_link; + enable = !!audio->data; + + audio_ctrl = dp_read(MMSS_DP_AUDIO_CFG); + + if (enable) + audio_ctrl |= BIT(0); + else + audio_ctrl &= ~BIT(0); + + DP_DEBUG("dp_audio_cfg = 0x%x\n", audio_ctrl); + dp_write(MMSS_DP_AUDIO_CFG, audio_ctrl); + + /* make sure audio engine is disabled */ + wmb(); +} + +static void dp_catalog_config_spd_header(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 value, new_value, offset = 0; + u8 parity_byte; + + if (!panel || panel->stream_id >= DP_STREAM_MAX) + return; + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) + offset = MMSS_DP1_GENERIC0_0 - MMSS_DP_GENERIC0_0; + + /* Config header and parity byte 1 */ + value = dp_read(MMSS_DP_GENERIC1_0 + offset); + + new_value = 0x83; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_1_BIT) + | (parity_byte << PARITY_BYTE_1_BIT)); + DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_write(MMSS_DP_GENERIC1_0 + offset, value); + + /* Config header and parity byte 2 */ + value = dp_read(MMSS_DP_GENERIC1_1 + offset); + + new_value = 0x1b; + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_2_BIT) + | (parity_byte << PARITY_BYTE_2_BIT)); + DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n", + value, parity_byte); + dp_write(MMSS_DP_GENERIC1_1 + offset, value); + + /* Config header and parity byte 3 */ + value = dp_read(MMSS_DP_GENERIC1_1 + offset); + + new_value = (0x0 | (0x12 << 2)); + parity_byte = dp_header_get_parity(new_value); + value |= ((new_value << HEADER_BYTE_3_BIT) + | (parity_byte << PARITY_BYTE_3_BIT)); + DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n", + new_value, parity_byte); + dp_write(MMSS_DP_GENERIC1_1 + offset, value); +} + +static void dp_catalog_panel_config_spd(struct dp_catalog_panel *panel) +{ + struct dp_catalog_private *catalog; + struct dp_io_data *io_data; + u32 spd_cfg = 0, spd_cfg2 = 0; + u8 *vendor = NULL, *product = NULL; + u32 offset = 0; + u32 sdp_cfg_off = 0; + u32 sdp_cfg2_off = 0; + + /* + * Source Device Information + * 00h unknown + * 01h Digital STB + * 02h DVD + * 03h D-VHS + * 04h HDD Video + * 05h DVC + * 06h DSC + * 07h Video CD + * 08h Game + * 09h PC general + * 0ah Bluray-Disc + * 0bh Super Audio CD + * 0ch HD DVD + * 0dh PMP + * 0eh-ffh reserved + */ + u32 device_type = 0; + + if (!panel || panel->stream_id >= DP_STREAM_MAX) + return; + + catalog = dp_catalog_get_priv(panel); + io_data = catalog->io.dp_link; + + if (panel->stream_id == DP_STREAM_1) + offset = MMSS_DP1_GENERIC0_0 - MMSS_DP_GENERIC0_0; + + dp_catalog_config_spd_header(panel); + + vendor = panel->spd_vendor_name; + product = panel->spd_product_description; + + dp_write(MMSS_DP_GENERIC1_2 + offset, + ((vendor[0] & 0x7f) | + ((vendor[1] & 0x7f) << 8) | + ((vendor[2] & 0x7f) << 16) | + ((vendor[3] & 0x7f) << 24))); + dp_write(MMSS_DP_GENERIC1_3 + offset, + ((vendor[4] & 0x7f) | + ((vendor[5] & 0x7f) << 8) | + ((vendor[6] & 0x7f) << 16) | + ((vendor[7] & 0x7f) << 24))); + dp_write(MMSS_DP_GENERIC1_4 + offset, + ((product[0] & 0x7f) | + ((product[1] & 0x7f) << 8) | + ((product[2] & 0x7f) << 16) | + ((product[3] & 0x7f) << 24))); + dp_write(MMSS_DP_GENERIC1_5 + offset, + ((product[4] & 0x7f) | + ((product[5] & 0x7f) << 8) | + ((product[6] & 0x7f) << 16) | + ((product[7] & 0x7f) << 24))); + dp_write(MMSS_DP_GENERIC1_6 + offset, + ((product[8] & 0x7f) | + ((product[9] & 0x7f) << 8) | + ((product[10] & 0x7f) << 16) | + ((product[11] & 0x7f) << 24))); + dp_write(MMSS_DP_GENERIC1_7 + offset, + ((product[12] & 0x7f) | + ((product[13] & 0x7f) << 8) | + ((product[14] & 0x7f) << 16) | + ((product[15] & 0x7f) << 24))); + dp_write(MMSS_DP_GENERIC1_8 + offset, device_type); + dp_write(MMSS_DP_GENERIC1_9 + offset, 0x00); + + if (panel->stream_id == DP_STREAM_1) { + sdp_cfg_off = MMSS_DP1_SDP_CFG - MMSS_DP_SDP_CFG; + sdp_cfg2_off = MMSS_DP1_SDP_CFG2 - MMSS_DP_SDP_CFG2; + } + + spd_cfg = dp_read(MMSS_DP_SDP_CFG + sdp_cfg_off); + /* GENERIC1_SDP for SPD Infoframe */ + spd_cfg |= BIT(18); + dp_write(MMSS_DP_SDP_CFG + sdp_cfg_off, spd_cfg); + + spd_cfg2 = dp_read(MMSS_DP_SDP_CFG2 + sdp_cfg2_off); + /* 28 data bytes for SPD Infoframe with GENERIC1 set */ + spd_cfg2 |= BIT(17); + dp_write(MMSS_DP_SDP_CFG2 + sdp_cfg2_off, spd_cfg2); + + dp_catalog_panel_sdp_update(panel); +} + +static void dp_catalog_get_io_buf(struct dp_catalog_private *catalog) +{ + struct dp_parser *parser = catalog->parser; + + dp_catalog_fill_io_buf(dp_ahb); + dp_catalog_fill_io_buf(dp_aux); + dp_catalog_fill_io_buf(dp_link); + dp_catalog_fill_io_buf(dp_p0); + dp_catalog_fill_io_buf(dp_phy); + dp_catalog_fill_io_buf(dp_ln_tx0); + dp_catalog_fill_io_buf(dp_ln_tx1); + dp_catalog_fill_io_buf(dp_pll); + dp_catalog_fill_io_buf(usb3_dp_com); + dp_catalog_fill_io_buf(dp_mmss_cc); + dp_catalog_fill_io_buf(hdcp_physical); + dp_catalog_fill_io_buf(dp_p1); + dp_catalog_fill_io_buf(dp_tcsr); +} + +static void dp_catalog_get_io(struct dp_catalog_private *catalog) +{ + struct dp_parser *parser = catalog->parser; + + dp_catalog_fill_io(dp_ahb); + dp_catalog_fill_io(dp_aux); + dp_catalog_fill_io(dp_link); + dp_catalog_fill_io(dp_p0); + dp_catalog_fill_io(dp_phy); + dp_catalog_fill_io(dp_ln_tx0); + dp_catalog_fill_io(dp_ln_tx1); + dp_catalog_fill_io(dp_pll); + dp_catalog_fill_io(usb3_dp_com); + dp_catalog_fill_io(dp_mmss_cc); + dp_catalog_fill_io(hdcp_physical); + dp_catalog_fill_io(dp_p1); + dp_catalog_fill_io(dp_tcsr); +} + +static void dp_catalog_set_exe_mode(struct dp_catalog *dp_catalog, char *mode) +{ + struct dp_catalog_private *catalog; + + if (!dp_catalog) { + DP_ERR("invalid input\n"); + return; + } + + catalog = container_of(dp_catalog, struct dp_catalog_private, + dp_catalog); + + strlcpy(catalog->exe_mode, mode, sizeof(catalog->exe_mode)); + + if (!strcmp(catalog->exe_mode, "hw")) + catalog->parser->clear_io_buf(catalog->parser); + else + dp_catalog_get_io_buf(catalog); + + if (!strcmp(catalog->exe_mode, "hw") || + !strcmp(catalog->exe_mode, "all")) { + catalog->read = dp_read_hw; + catalog->write = dp_write_hw; + + dp_catalog->sub->read = dp_read_sub_hw; + dp_catalog->sub->write = dp_write_sub_hw; + } else { + catalog->read = dp_read_sw; + catalog->write = dp_write_sw; + + dp_catalog->sub->read = dp_read_sub_sw; + dp_catalog->sub->write = dp_write_sub_sw; + } +} + +static int dp_catalog_init(struct device *dev, struct dp_catalog *dp_catalog, + struct dp_parser *parser) +{ + int rc = 0; + struct dp_catalog_private *catalog = container_of(dp_catalog, + struct dp_catalog_private, dp_catalog); + + switch (parser->hw_cfg.phy_version) { + case DP_PHY_VERSION_4_2_0: + dp_catalog->sub = dp_catalog_get_v420(dev, dp_catalog, + &catalog->io); + break; + case DP_PHY_VERSION_2_0_0: + dp_catalog->sub = dp_catalog_get_v200(dev, dp_catalog, + &catalog->io); + break; + default: + goto end; + } + + if (IS_ERR(dp_catalog->sub)) { + rc = PTR_ERR(dp_catalog->sub); + dp_catalog->sub = NULL; + } else { + dp_catalog->sub->read = dp_read_sub_hw; + dp_catalog->sub->write = dp_write_sub_hw; + } +end: + return rc; +} + +void dp_catalog_put(struct dp_catalog *dp_catalog) +{ + struct dp_catalog_private *catalog; + + if (!dp_catalog) + return; + + catalog = container_of(dp_catalog, struct dp_catalog_private, + dp_catalog); + + if (dp_catalog->sub && dp_catalog->sub->put) + dp_catalog->sub->put(dp_catalog); + + catalog->parser->clear_io_buf(catalog->parser); + devm_kfree(catalog->dev, catalog); +} + +struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser) +{ + int rc = 0; + struct dp_catalog *dp_catalog; + struct dp_catalog_private *catalog; + struct dp_catalog_aux aux = { + .read_data = dp_catalog_aux_read_data, + .write_data = dp_catalog_aux_write_data, + .write_trans = dp_catalog_aux_write_trans, + .clear_trans = dp_catalog_aux_clear_trans, + .reset = dp_catalog_aux_reset, + .update_aux_cfg = dp_catalog_aux_update_cfg, + .enable = dp_catalog_aux_enable, + .setup = dp_catalog_aux_setup, + .get_irq = dp_catalog_aux_get_irq, + .clear_hw_interrupts = dp_catalog_aux_clear_hw_interrupts, + }; + struct dp_catalog_ctrl ctrl = { + .state_ctrl = dp_catalog_ctrl_state_ctrl, + .config_ctrl = dp_catalog_ctrl_config_ctrl, + .lane_mapping = dp_catalog_ctrl_lane_mapping, + .lane_pnswap = dp_catalog_ctrl_lane_pnswap, + .mainlink_ctrl = dp_catalog_ctrl_mainlink_ctrl, + .set_pattern = dp_catalog_ctrl_set_pattern, + .reset = dp_catalog_ctrl_reset, + .usb_reset = dp_catalog_ctrl_usb_reset, + .mainlink_ready = dp_catalog_ctrl_mainlink_ready, + .enable_irq = dp_catalog_ctrl_enable_irq, + .phy_reset = dp_catalog_ctrl_phy_reset, + .phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg, + .update_vx_px = dp_catalog_ctrl_update_vx_px, + .get_interrupt = dp_catalog_ctrl_get_interrupt, + .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status, + .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern, + .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern, + .mst_config = dp_catalog_ctrl_mst_config, + .trigger_act = dp_catalog_ctrl_trigger_act, + .read_act_complete_sts = dp_catalog_ctrl_read_act_complete_sts, + .channel_alloc = dp_catalog_ctrl_channel_alloc, + .update_rg = dp_catalog_ctrl_update_rg, + .channel_dealloc = dp_catalog_ctrl_channel_dealloc, + .fec_config = dp_catalog_ctrl_fec_config, + .mainlink_levels = dp_catalog_ctrl_mainlink_levels, + .late_phy_init = dp_catalog_ctrl_late_phy_init, + }; + struct dp_catalog_hpd hpd = { + .config_hpd = dp_catalog_hpd_config_hpd, + .get_interrupt = dp_catalog_hpd_get_interrupt, + }; + struct dp_catalog_audio audio = { + .init = dp_catalog_audio_init, + .config_acr = dp_catalog_audio_config_acr, + .enable = dp_catalog_audio_enable, + .config_sdp = dp_catalog_audio_config_sdp, + .set_header = dp_catalog_audio_set_header, + .get_header = dp_catalog_audio_get_header, + }; + struct dp_catalog_panel panel = { + .timing_cfg = dp_catalog_panel_timing_cfg, + .config_hdr = dp_catalog_panel_config_hdr, + .config_sdp = dp_catalog_panel_config_sdp, + .tpg_config = dp_catalog_panel_tpg_cfg, + .config_spd = dp_catalog_panel_config_spd, + .config_misc = dp_catalog_panel_config_misc, + .set_colorspace = dp_catalog_panel_set_colorspace, + .config_msa = dp_catalog_panel_config_msa, + .update_transfer_unit = dp_catalog_panel_update_transfer_unit, + .config_ctrl = dp_catalog_panel_config_ctrl, + .config_dto = dp_catalog_panel_config_dto, + .dsc_cfg = dp_catalog_panel_dsc_cfg, + .pps_flush = dp_catalog_panel_pps_flush, + .dhdr_flush = dp_catalog_panel_dhdr_flush, + .dhdr_busy = dp_catalog_panel_dhdr_busy, + }; + + if (!dev || !parser) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + catalog = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL); + if (!catalog) { + rc = -ENOMEM; + goto error; + } + + catalog->dev = dev; + catalog->parser = parser; + + catalog->read = dp_read_hw; + catalog->write = dp_write_hw; + + dp_catalog_get_io(catalog); + + strlcpy(catalog->exe_mode, "hw", sizeof(catalog->exe_mode)); + + dp_catalog = &catalog->dp_catalog; + + dp_catalog->aux = aux; + dp_catalog->ctrl = ctrl; + dp_catalog->hpd = hpd; + dp_catalog->audio = audio; + dp_catalog->panel = panel; + + rc = dp_catalog_init(dev, dp_catalog, parser); + if (rc) { + dp_catalog_put(dp_catalog); + goto error; + } + + dp_catalog->set_exe_mode = dp_catalog_set_exe_mode; + dp_catalog->get_reg_dump = dp_catalog_reg_dump; + + return dp_catalog; +error: + return ERR_PTR(rc); +} diff --git a/techpack/display/msm/dp/dp_catalog.h b/techpack/display/msm/dp/dp_catalog.h new file mode 100644 index 0000000000000000000000000000000000000000..0b1f00408e43508a7444b0c7e856081aacc4b455 --- /dev/null +++ b/techpack/display/msm/dp/dp_catalog.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_CATALOG_H_ +#define _DP_CATALOG_H_ + +#include <drm/drm_dp_helper.h> +#include <drm/msm_drm.h> + +#include "dp_parser.h" + +/* interrupts */ +#define DP_INTR_HPD BIT(0) +#define DP_INTR_AUX_I2C_DONE BIT(3) +#define DP_INTR_WRONG_ADDR BIT(6) +#define DP_INTR_TIMEOUT BIT(9) +#define DP_INTR_NACK_DEFER BIT(12) +#define DP_INTR_WRONG_DATA_CNT BIT(15) +#define DP_INTR_I2C_NACK BIT(18) +#define DP_INTR_I2C_DEFER BIT(21) +#define DP_INTR_PLL_UNLOCKED BIT(24) +#define DP_INTR_AUX_ERROR BIT(27) + +#define DP_INTR_READY_FOR_VIDEO BIT(0) +#define DP_INTR_IDLE_PATTERN_SENT BIT(3) +#define DP_INTR_FRAME_END BIT(6) +#define DP_INTR_CRC_UPDATED BIT(9) + +#define DP_INTR_MST_DP0_VCPF_SENT BIT(0) +#define DP_INTR_MST_DP1_VCPF_SENT BIT(3) + +#define DP_MAX_TIME_SLOTS 64 + +/* stream id */ +enum dp_stream_id { + DP_STREAM_0, + DP_STREAM_1, + DP_STREAM_MAX, +}; + +struct dp_catalog_vsc_sdp_colorimetry { + struct dp_sdp_header header; + u8 data[32]; +}; + +struct dp_catalog_aux { + u32 data; + u32 isr; + + u32 (*read_data)(struct dp_catalog_aux *aux); + int (*write_data)(struct dp_catalog_aux *aux); + int (*write_trans)(struct dp_catalog_aux *aux); + int (*clear_trans)(struct dp_catalog_aux *aux, bool read); + void (*reset)(struct dp_catalog_aux *aux); + void (*enable)(struct dp_catalog_aux *aux, bool enable); + void (*update_aux_cfg)(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type); + void (*setup)(struct dp_catalog_aux *aux, + struct dp_aux_cfg *aux_cfg); + void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy); + void (*clear_hw_interrupts)(struct dp_catalog_aux *aux); +}; + +struct dp_catalog_ctrl { + u32 isr; + u32 isr5; + + void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state); + void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u8 ln_cnt); + void (*lane_mapping)(struct dp_catalog_ctrl *ctrl, bool flipped, + char *lane_map); + void (*lane_pnswap)(struct dp_catalog_ctrl *ctrl, u8 ln_pnswap); + void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern); + void (*reset)(struct dp_catalog_ctrl *ctrl); + void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip); + bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl); + void (*enable_irq)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*phy_reset)(struct dp_catalog_ctrl *ctrl); + void (*phy_lane_cfg)(struct dp_catalog_ctrl *ctrl, bool flipped, + u8 lane_cnt); + void (*update_vx_px)(struct dp_catalog_ctrl *ctrl, u8 v_level, + u8 p_level, bool high); + void (*get_interrupt)(struct dp_catalog_ctrl *ctrl); + u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl); + void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl, + u32 pattern); + u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); + void (*mst_config)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*trigger_act)(struct dp_catalog_ctrl *ctrl); + void (*read_act_complete_sts)(struct dp_catalog_ctrl *ctrl, bool *sts); + void (*channel_alloc)(struct dp_catalog_ctrl *ctrl, + u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt); + void (*update_rg)(struct dp_catalog_ctrl *ctrl, u32 ch, u32 x_int, + u32 y_frac_enum); + void (*channel_dealloc)(struct dp_catalog_ctrl *ctrl, + u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt); + void (*fec_config)(struct dp_catalog_ctrl *ctrl, bool enable); + void (*mainlink_levels)(struct dp_catalog_ctrl *ctrl, u8 lane_cnt); + + int (*late_phy_init)(struct dp_catalog_ctrl *ctrl, + u8 lane_cnt, bool flipped); +}; + +struct dp_catalog_hpd { + void (*config_hpd)(struct dp_catalog_hpd *hpd, bool en); + u32 (*get_interrupt)(struct dp_catalog_hpd *hpd); +}; + +#define HEADER_BYTE_2_BIT 0 +#define PARITY_BYTE_2_BIT 8 +#define HEADER_BYTE_1_BIT 16 +#define PARITY_BYTE_1_BIT 24 +#define HEADER_BYTE_3_BIT 16 +#define PARITY_BYTE_3_BIT 24 + +enum dp_catalog_audio_sdp_type { + DP_AUDIO_SDP_STREAM, + DP_AUDIO_SDP_TIMESTAMP, + DP_AUDIO_SDP_INFOFRAME, + DP_AUDIO_SDP_COPYMANAGEMENT, + DP_AUDIO_SDP_ISRC, + DP_AUDIO_SDP_MAX, +}; + +enum dp_catalog_audio_header_type { + DP_AUDIO_SDP_HEADER_1, + DP_AUDIO_SDP_HEADER_2, + DP_AUDIO_SDP_HEADER_3, + DP_AUDIO_SDP_HEADER_MAX, +}; + +struct dp_catalog_audio { + enum dp_catalog_audio_sdp_type sdp_type; + enum dp_catalog_audio_header_type sdp_header; + u32 data; + + enum dp_stream_id stream_id; + + void (*init)(struct dp_catalog_audio *audio); + void (*enable)(struct dp_catalog_audio *audio); + void (*config_acr)(struct dp_catalog_audio *audio); + void (*config_sdp)(struct dp_catalog_audio *audio); + void (*set_header)(struct dp_catalog_audio *audio); + void (*get_header)(struct dp_catalog_audio *audio); +}; + +struct dp_dsc_cfg_data { + bool dsc_en; + char pps[128]; + u32 pps_len; + u32 pps_word[32]; + u32 pps_word_len; + u8 parity[32]; + u8 parity_len; + u32 parity_word[8]; + u32 parity_word_len; + u32 slice_per_pkt; + u32 bytes_per_pkt; + u32 eol_byte_num; + u32 be_in_lane; + u32 dto_en; + u32 dto_n; + u32 dto_d; + u32 dto_count; +}; + +struct dp_catalog_panel { + u32 total; + u32 sync_start; + u32 width_blanking; + u32 dp_active; + u8 *spd_vendor_name; + u8 *spd_product_description; + + struct dp_catalog_vsc_sdp_colorimetry vsc_colorimetry; + struct dp_sdp_header dhdr_vsif_sdp; + struct dp_sdp_header shdr_if_sdp; + struct drm_msm_ext_hdr_metadata hdr_meta; + + /* TPG */ + u32 hsync_period; + u32 vsync_period; + u32 display_v_start; + u32 display_v_end; + u32 v_sync_width; + u32 hsync_ctl; + u32 display_hctl; + + /* TU */ + u32 dp_tu; + u32 valid_boundary; + u32 valid_boundary2; + + u32 misc_val; + + enum dp_stream_id stream_id; + + bool widebus_en; + struct dp_dsc_cfg_data dsc; + + int (*timing_cfg)(struct dp_catalog_panel *panel); + void (*config_hdr)(struct dp_catalog_panel *panel, bool en, + u32 dhdr_max_pkts, bool flush); + void (*config_sdp)(struct dp_catalog_panel *panel, bool en); + int (*set_colorspace)(struct dp_catalog_panel *panel, + bool vsc_supported); + void (*tpg_config)(struct dp_catalog_panel *panel, bool enable); + void (*config_spd)(struct dp_catalog_panel *panel); + void (*config_misc)(struct dp_catalog_panel *panel); + void (*config_msa)(struct dp_catalog_panel *panel, + u32 rate, u32 stream_rate_khz); + void (*update_transfer_unit)(struct dp_catalog_panel *panel); + void (*config_ctrl)(struct dp_catalog_panel *panel, u32 cfg); + void (*config_dto)(struct dp_catalog_panel *panel, bool ack); + void (*dsc_cfg)(struct dp_catalog_panel *panel); + void (*pps_flush)(struct dp_catalog_panel *panel); + void (*dhdr_flush)(struct dp_catalog_panel *panel); + bool (*dhdr_busy)(struct dp_catalog_panel *panel); +}; + +struct dp_catalog; +struct dp_catalog_sub { + u32 (*read)(struct dp_catalog *dp_catalog, + struct dp_io_data *io_data, u32 offset); + void (*write)(struct dp_catalog *dp_catalog, + struct dp_io_data *io_data, u32 offset, u32 data); + + void (*put)(struct dp_catalog *catalog); +}; + +struct dp_catalog_io { + struct dp_io_data *dp_ahb; + struct dp_io_data *dp_aux; + struct dp_io_data *dp_link; + struct dp_io_data *dp_p0; + struct dp_io_data *dp_phy; + struct dp_io_data *dp_ln_tx0; + struct dp_io_data *dp_ln_tx1; + struct dp_io_data *dp_mmss_cc; + struct dp_io_data *dp_pll; + struct dp_io_data *usb3_dp_com; + struct dp_io_data *hdcp_physical; + struct dp_io_data *dp_p1; + struct dp_io_data *dp_tcsr; +}; + +struct dp_catalog { + struct dp_catalog_aux aux; + struct dp_catalog_ctrl ctrl; + struct dp_catalog_audio audio; + struct dp_catalog_panel panel; + struct dp_catalog_hpd hpd; + + struct dp_catalog_sub *sub; + + void (*set_exe_mode)(struct dp_catalog *dp_catalog, char *mode); + int (*get_reg_dump)(struct dp_catalog *dp_catalog, + char *mode, u8 **out_buf, u32 *out_buf_len); +}; + +static inline u8 dp_ecc_get_g0_value(u8 data) +{ + u8 c[4]; + u8 g[4]; + u8 ret_data = 0; + u8 i; + + for (i = 0; i < 4; i++) + c[i] = (data >> i) & 0x01; + + g[0] = c[3]; + g[1] = c[0] ^ c[3]; + g[2] = c[1]; + g[3] = c[2]; + + for (i = 0; i < 4; i++) + ret_data = ((g[i] & 0x01) << i) | ret_data; + + return ret_data; +} + +static inline u8 dp_ecc_get_g1_value(u8 data) +{ + u8 c[4]; + u8 g[4]; + u8 ret_data = 0; + u8 i; + + for (i = 0; i < 4; i++) + c[i] = (data >> i) & 0x01; + + g[0] = c[0] ^ c[3]; + g[1] = c[0] ^ c[1] ^ c[3]; + g[2] = c[1] ^ c[2]; + g[3] = c[2] ^ c[3]; + + for (i = 0; i < 4; i++) + ret_data = ((g[i] & 0x01) << i) | ret_data; + + return ret_data; +} + +static inline u8 dp_header_get_parity(u32 data) +{ + u8 x0 = 0; + u8 x1 = 0; + u8 ci = 0; + u8 iData = 0; + u8 i = 0; + u8 parity_byte; + u8 num_byte = (data > 0xFF) ? 8 : 2; + + for (i = 0; i < num_byte; i++) { + iData = (data >> i*4) & 0xF; + + ci = iData ^ x1; + x1 = x0 ^ dp_ecc_get_g1_value(ci); + x0 = dp_ecc_get_g0_value(ci); + } + + parity_byte = x1 | (x0 << 4); + + return parity_byte; +} + +struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser); +void dp_catalog_put(struct dp_catalog *catalog); + +struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev, + struct dp_catalog *catalog, struct dp_catalog_io *io); + +struct dp_catalog_sub *dp_catalog_get_v200(struct device *dev, + struct dp_catalog *catalog, struct dp_catalog_io *io); + +#endif /* _DP_CATALOG_H_ */ diff --git a/techpack/display/msm/dp/dp_catalog_v200.c b/techpack/display/msm/dp/dp_catalog_v200.c new file mode 100644 index 0000000000000000000000000000000000000000..97d78a120bc42c884fcb071dabe024fc92d5619c --- /dev/null +++ b/techpack/display/msm/dp/dp_catalog_v200.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> + +#include "dp_catalog.h" +#include "dp_reg.h" +#include "dp_debug.h" + +#define dp_catalog_get_priv_v200(x) ({ \ + struct dp_catalog *catalog; \ + catalog = container_of(x, struct dp_catalog, x); \ + container_of(catalog->sub, \ + struct dp_catalog_private_v200, sub); \ +}) + +#define dp_read(x) ({ \ + catalog->sub.read(catalog->dpc, io_data, x); \ +}) + +#define dp_write(x, y) ({ \ + catalog->sub.write(catalog->dpc, io_data, x, y); \ +}) + +struct dp_catalog_private_v200 { + struct device *dev; + struct dp_catalog_io *io; + struct dp_catalog *dpc; + struct dp_catalog_sub sub; +}; + +static void dp_catalog_aux_clear_hw_int_v200(struct dp_catalog_aux *aux) +{ + struct dp_catalog_private_v200 *catalog; + struct dp_io_data *io_data; + u32 data = 0; + + if (!aux) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv_v200(aux); + io_data = catalog->io->dp_phy; + + data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V200); + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V200, 0x1f); + wmb(); /* make sure 0x1f is written before next write */ + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V200, 0x9f); + wmb(); /* make sure 0x9f is written before next write */ + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V200, 0); + wmb(); /* make sure register is cleared */ +} + +static void dp_catalog_aux_setup_v200(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg) +{ + struct dp_catalog_private_v200 *catalog; + struct dp_io_data *io_data; + int i = 0, sw_reset = 0; + + if (!aux || !cfg) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv_v200(aux); + io_data = catalog->io->dp_ahb; + + sw_reset = dp_read(DP_SW_RESET); + + sw_reset |= BIT(0); + dp_write(DP_SW_RESET, sw_reset); + usleep_range(1000, 1010); /* h/w recommended delay */ + + sw_reset &= ~BIT(0); + dp_write(DP_SW_RESET, sw_reset); + + dp_write(DP_PHY_CTRL, 0x4); /* bit 2 */ + udelay(1000); + dp_write(DP_PHY_CTRL, 0x0); /* bit 2 */ + wmb(); /* make sure programming happened */ + + io_data = catalog->io->dp_tcsr; + dp_write(0x4c, 0x1); /* bit 0 & 2 */ + wmb(); /* make sure programming happened */ + + io_data = catalog->io->dp_phy; + dp_write(DP_PHY_PD_CTL, 0x3c); + wmb(); /* make sure PD programming happened */ + dp_write(DP_PHY_PD_CTL, 0x3d); + wmb(); /* make sure PD programming happened */ + + /* DP AUX CFG register programming */ + io_data = catalog->io->dp_phy; + for (i = 0; i < PHY_AUX_CFG_MAX; i++) + dp_write(cfg[i].offset, cfg[i].lut[cfg[i].current_index]); + + dp_write(DP_PHY_AUX_INTERRUPT_MASK_V200, 0x1F); + wmb(); /* make sure AUX configuration is done before enabling it */ +} + +static void dp_catalog_panel_config_msa_v200(struct dp_catalog_panel *panel, + u32 rate, u32 stream_rate_khz) +{ + u32 pixel_m, pixel_n; + u32 mvid, nvid; + u32 const nvid_fixed = 0x8000; + u32 const link_rate_hbr2 = 540000; + u32 const link_rate_hbr3 = 810000; + struct dp_catalog_private_v200 *catalog; + struct dp_io_data *io_data; + u32 strm_reg_off = 0; + u32 mvid_reg_off = 0, nvid_reg_off = 0; + + if (!panel) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv_v200(panel); + io_data = catalog->io->dp_mmss_cc; + + if (panel->stream_id == DP_STREAM_1) + strm_reg_off = MMSS_DP_PIXEL1_M_V200 - + MMSS_DP_PIXEL_M_V200; + + pixel_m = dp_read(MMSS_DP_PIXEL_M_V200 + strm_reg_off); + pixel_n = dp_read(MMSS_DP_PIXEL_N_V200 + strm_reg_off); + DP_DEBUG("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); + + mvid = (pixel_m & 0xFFFF) * 5; + nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); + + if (nvid < nvid_fixed) { + u32 temp; + + temp = (nvid_fixed / nvid) * nvid; + mvid = (nvid_fixed / nvid) * mvid; + nvid = temp; + } + + DP_DEBUG("rate = %d\n", rate); + + if (panel->widebus_en) + mvid <<= 1; + + if (link_rate_hbr2 == rate) + nvid *= 2; + + if (link_rate_hbr3 == rate) + nvid *= 3; + + io_data = catalog->io->dp_link; + + if (panel->stream_id == DP_STREAM_1) { + mvid_reg_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID; + nvid_reg_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID; + } + + DP_DEBUG("mvid=0x%x, nvid=0x%x\n", mvid, nvid); + dp_write(DP_SOFTWARE_MVID + mvid_reg_off, mvid); + dp_write(DP_SOFTWARE_NVID + nvid_reg_off, nvid); +} + +static void dp_catalog_ctrl_lane_mapping_v200(struct dp_catalog_ctrl *ctrl, + bool flipped, char *lane_map) +{ + struct dp_catalog_private_v200 *catalog; + struct dp_io_data *io_data; + u8 l_map[4] = { 0 }, i = 0, j = 0; + u32 lane_map_reg = 0; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv_v200(ctrl); + io_data = catalog->io->dp_link; + + /* For flip case, swap phy lanes with ML0 and ML3, ML1 and ML2 */ + if (flipped) { + for (i = 0; i < DP_MAX_PHY_LN; i++) { + if (lane_map[i] == DP_ML0) { + for (j = 0; j < DP_MAX_PHY_LN; j++) { + if (lane_map[j] == DP_ML3) { + l_map[i] = DP_ML3; + l_map[j] = DP_ML0; + break; + } + } + } else if (lane_map[i] == DP_ML1) { + for (j = 0; j < DP_MAX_PHY_LN; j++) { + if (lane_map[j] == DP_ML2) { + l_map[i] = DP_ML2; + l_map[j] = DP_ML1; + break; + } + } + } + } + } else { + /* Normal orientation */ + for (i = 0; i < DP_MAX_PHY_LN; i++) + l_map[i] = lane_map[i]; + } + + lane_map_reg = ((l_map[3]&3)<<6)|((l_map[2]&3)<<4)|((l_map[1]&3)<<2) + |(l_map[0]&3); + + dp_write(DP_LOGICAL2PHYSICAL_LANE_MAPPING, lane_map_reg); +} + +static void dp_catalog_ctrl_usb_reset_v200(struct dp_catalog_ctrl *ctrl, + bool flip) +{ +} + +static void dp_catalog_put_v200(struct dp_catalog *catalog) +{ + struct dp_catalog_private_v200 *catalog_priv; + + if (!catalog) + return; + + catalog_priv = container_of(catalog->sub, + struct dp_catalog_private_v200, sub); + + devm_kfree(catalog_priv->dev, catalog_priv); +} + +struct dp_catalog_sub *dp_catalog_get_v200(struct device *dev, + struct dp_catalog *catalog, struct dp_catalog_io *io) +{ + struct dp_catalog_private_v200 *catalog_priv; + + if (!dev || !catalog) { + DP_ERR("invalid input\n"); + return ERR_PTR(-EINVAL); + } + + catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL); + if (!catalog_priv) + return ERR_PTR(-ENOMEM); + + catalog_priv->dev = dev; + catalog_priv->io = io; + catalog_priv->dpc = catalog; + + catalog_priv->sub.put = dp_catalog_put_v200; + + catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_int_v200; + catalog->aux.setup = dp_catalog_aux_setup_v200; + + catalog->panel.config_msa = dp_catalog_panel_config_msa_v200; + + catalog->ctrl.lane_mapping = dp_catalog_ctrl_lane_mapping_v200; + catalog->ctrl.usb_reset = dp_catalog_ctrl_usb_reset_v200; + + return &catalog_priv->sub; +} diff --git a/techpack/display/msm/dp/dp_catalog_v420.c b/techpack/display/msm/dp/dp_catalog_v420.c new file mode 100644 index 0000000000000000000000000000000000000000..a4f3c456b4585d1e9ac66683e719e81df92313f2 --- /dev/null +++ b/techpack/display/msm/dp/dp_catalog_v420.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/iopoll.h> +#include <linux/iopoll.h> + +#include "dp_catalog.h" +#include "dp_reg.h" +#include "dp_debug.h" + +#define dp_catalog_get_priv_v420(x) ({ \ + struct dp_catalog *catalog; \ + catalog = container_of(x, struct dp_catalog, x); \ + container_of(catalog->sub, \ + struct dp_catalog_private_v420, sub); \ +}) + +#define dp_read(x) ({ \ + catalog->sub.read(catalog->dpc, io_data, x); \ +}) + +#define dp_write(x, y) ({ \ + catalog->sub.write(catalog->dpc, io_data, x, y); \ +}) + +#define DP_PHY_READY BIT(1) +#define MAX_VOLTAGE_LEVELS 4 +#define MAX_PRE_EMP_LEVELS 4 + +static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { + {0x00, 0x0E, 0x16, 0xFF}, /* pe0, 0 db */ + {0x00, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */ + {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ +}; + +/* voltage swing, 0.2v and 1.0v are not support */ +static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { + {0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */ + {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */ + {0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ + {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ +}; + +static u8 const dp_pre_emp_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { + {0x00, 0x0C, 0x15, 0x1A}, /* pe0, 0 db */ + {0x02, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */ + {0x02, 0x11, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0x04, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ +}; + +static u8 const dp_swing_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { + {0x02, 0x12, 0x16, 0x1A}, /* sw0, 0.4v */ + {0x09, 0x19, 0x1F, 0xFF}, /* sw1, 0.6v */ + {0x10, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */ + {0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */ +}; + +static u8 const dp_pre_emp_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { + {0x00, 0x0E, 0x15, 0x1A}, /* pe0, 0 db */ + {0x00, 0x0E, 0x15, 0xFF}, /* pe1, 3.5 db */ + {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0x04, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ +}; + +static u8 const dp_swing_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { + {0x08, 0x0F, 0x16, 0x1F}, /* sw0, 0.4v */ + {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6v */ + {0x16, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */ + {0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */ +}; + +struct dp_catalog_private_v420 { + struct device *dev; + struct dp_catalog_sub sub; + struct dp_catalog_io *io; + struct dp_catalog *dpc; +}; + +static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux, + struct dp_aux_cfg *cfg) +{ + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + int i = 0; + + if (!aux || !cfg) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv_v420(aux); + + io_data = catalog->io->dp_phy; + dp_write(DP_PHY_PD_CTL, 0x67); + wmb(); /* make sure PD programming happened */ + + /* Turn on BIAS current for PHY/PLL */ + io_data = catalog->io->dp_pll; + dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17); + wmb(); /* make sure BIAS programming happened */ + + io_data = catalog->io->dp_phy; + /* DP AUX CFG register programming */ + for (i = 0; i < PHY_AUX_CFG_MAX; i++) { + DP_DEBUG("%s: offset=0x%08x, value=0x%08x\n", + dp_phy_aux_config_type_to_string(i), + cfg[i].offset, cfg[i].lut[cfg[i].current_index]); + dp_write(cfg[i].offset, cfg[i].lut[cfg[i].current_index]); + } + wmb(); /* make sure DP AUX CFG programming happened */ + + dp_write(DP_PHY_AUX_INTERRUPT_MASK_V420, 0x1F); +} + +static void dp_catalog_aux_clear_hw_int_v420(struct dp_catalog_aux *aux) +{ + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + u32 data = 0; + + if (!aux) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv_v420(aux); + io_data = catalog->io->dp_phy; + + data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V420); + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f); + wmb(); /* make sure 0x1f is written before next write */ + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x9f); + wmb(); /* make sure 0x9f is written before next write */ + + dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0); + wmb(); /* make sure register is cleared */ +} + +static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel, + u32 rate, u32 stream_rate_khz) +{ + u32 pixel_m, pixel_n; + u32 mvid, nvid, reg_off = 0, mvid_off = 0, nvid_off = 0; + u32 const nvid_fixed = 0x8000; + u32 const link_rate_hbr2 = 540000; + u32 const link_rate_hbr3 = 810000; + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + + if (!panel || !rate) { + DP_ERR("invalid input\n"); + return; + } + + if (panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id:%d\n", panel->stream_id); + return; + } + + catalog = dp_catalog_get_priv_v420(panel); + io_data = catalog->io->dp_mmss_cc; + + if (panel->stream_id == DP_STREAM_1) + reg_off = MMSS_DP_PIXEL1_M_V420 - MMSS_DP_PIXEL_M_V420; + + pixel_m = dp_read(MMSS_DP_PIXEL_M_V420 + reg_off); + pixel_n = dp_read(MMSS_DP_PIXEL_N_V420 + reg_off); + DP_DEBUG("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); + + mvid = (pixel_m & 0xFFFF) * 5; + nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); + + if (nvid < nvid_fixed) { + u32 temp; + + temp = (nvid_fixed / nvid) * nvid; + mvid = (nvid_fixed / nvid) * mvid; + nvid = temp; + } + + DP_DEBUG("rate = %d\n", rate); + + if (panel->widebus_en) + mvid <<= 1; + + if (link_rate_hbr2 == rate) + nvid *= 2; + + if (link_rate_hbr3 == rate) + nvid *= 3; + + io_data = catalog->io->dp_link; + + if (panel->stream_id == DP_STREAM_1) { + mvid_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID; + nvid_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID; + } + + DP_DEBUG("mvid=0x%x, nvid=0x%x\n", mvid, nvid); + dp_write(DP_SOFTWARE_MVID + mvid_off, mvid); + dp_write(DP_SOFTWARE_NVID + nvid_off, nvid); +} + +static void dp_catalog_ctrl_phy_lane_cfg_v420(struct dp_catalog_ctrl *ctrl, + bool flipped, u8 ln_cnt) +{ + u32 info = 0x0; + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + u8 orientation = BIT(!!flipped); + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + catalog = dp_catalog_get_priv_v420(ctrl); + io_data = catalog->io->dp_phy; + + info |= (ln_cnt & 0x0F); + info |= ((orientation & 0x0F) << 4); + DP_DEBUG("Shared Info = 0x%x\n", info); + + dp_write(DP_PHY_SPARE0_V420, info); +} + +static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl, + u8 v_level, u8 p_level, bool high) +{ + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + u8 value0, value1; + u32 version; + + if (!ctrl || !((v_level < MAX_VOLTAGE_LEVELS) + && (p_level < MAX_PRE_EMP_LEVELS))) { + DP_ERR("invalid input\n"); + return; + } + + DP_DEBUG("hw: v=%d p=%d, high=%d\n", v_level, p_level, high); + + catalog = dp_catalog_get_priv_v420(ctrl); + + io_data = catalog->io->dp_ahb; + version = dp_read(DP_HW_VERSION); + + /* + * For DP controller versions 1.2.3 and 1.2.4 + */ + if ((version == 0x10020003) || (version == 0x10020004)) { + if (high) { + value0 = dp_swing_hbr2_hbr3[v_level][p_level]; + value1 = dp_pre_emp_hbr2_hbr3[v_level][p_level]; + } else { + value0 = dp_swing_hbr_rbr[v_level][p_level]; + value1 = dp_pre_emp_hbr_rbr[v_level][p_level]; + } + } else { + value0 = vm_voltage_swing[v_level][p_level]; + value1 = vm_pre_emphasis[v_level][p_level]; + } + + /* program default setting first */ + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_TX_DRV_LVL_V420, 0x2A); + dp_write(TXn_TX_EMP_POST1_LVL, 0x20); + + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_TX_DRV_LVL_V420, 0x2A); + dp_write(TXn_TX_EMP_POST1_LVL, 0x20); + + /* Enable MUX to use Cursor values from these registers */ + value0 |= BIT(5); + value1 |= BIT(5); + + /* Configure host and panel only if both values are allowed */ + if (value0 != 0xFF && value1 != 0xFF) { + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_TX_DRV_LVL_V420, value0); + dp_write(TXn_TX_EMP_POST1_LVL, value1); + + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_TX_DRV_LVL_V420, value0); + dp_write(TXn_TX_EMP_POST1_LVL, value1); + + DP_DEBUG("hw: vx_value=0x%x px_value=0x%x\n", + value0, value1); + } else { + DP_ERR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n", + v_level, value0, p_level, value1); + } +} + +static bool dp_catalog_ctrl_wait_for_phy_ready_v420( + struct dp_catalog_private_v420 *catalog) +{ + u32 reg = DP_PHY_STATUS_V420, state; + void __iomem *base = catalog->io->dp_phy->io.base; + bool success = true; + u32 const poll_sleep_us = 500; + u32 const pll_timeout_us = 10000; + + if (readl_poll_timeout_atomic((base + reg), state, + ((state & DP_PHY_READY) > 0), + poll_sleep_us, pll_timeout_us)) { + DP_ERR("PHY status failed, status=%x\n", state); + + success = false; + } + + return success; +} + +static int dp_catalog_ctrl_late_phy_init_v420(struct dp_catalog_ctrl *ctrl, + u8 lane_cnt, bool flipped) +{ + int rc = 0; + u32 bias0_en, drvr0_en, bias1_en, drvr1_en; + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + catalog = dp_catalog_get_priv_v420(ctrl); + + switch (lane_cnt) { + case 1: + drvr0_en = flipped ? 0x13 : 0x10; + bias0_en = flipped ? 0x3E : 0x15; + drvr1_en = flipped ? 0x10 : 0x13; + bias1_en = flipped ? 0x15 : 0x3E; + break; + case 2: + drvr0_en = flipped ? 0x10 : 0x10; + bias0_en = flipped ? 0x3F : 0x15; + drvr1_en = flipped ? 0x10 : 0x10; + bias1_en = flipped ? 0x15 : 0x3F; + break; + case 4: + default: + drvr0_en = 0x10; + bias0_en = 0x3F; + drvr1_en = 0x10; + bias1_en = 0x3F; + break; + } + + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_HIGHZ_DRVR_EN_V420, drvr0_en); + dp_write(TXn_TRANSCEIVER_BIAS_EN_V420, bias0_en); + + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_HIGHZ_DRVR_EN_V420, drvr1_en); + dp_write(TXn_TRANSCEIVER_BIAS_EN_V420, bias1_en); + + io_data = catalog->io->dp_phy; + dp_write(DP_PHY_CFG, 0x18); + /* add hardware recommended delay */ + udelay(2000); + dp_write(DP_PHY_CFG, 0x19); + + /* + * Make sure all the register writes are completed before + * doing any other operation + */ + wmb(); + + if (!dp_catalog_ctrl_wait_for_phy_ready_v420(catalog)) { + rc = -EINVAL; + goto lock_err; + } + + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_TX_POL_INV_V420, 0x0a); + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_TX_POL_INV_V420, 0x0a); + + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_TX_DRV_LVL_V420, 0x27); + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_TX_DRV_LVL_V420, 0x27); + + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_TX_EMP_POST1_LVL, 0x20); + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_TX_EMP_POST1_LVL, 0x20); + /* Make sure the PHY register writes are done */ + wmb(); +lock_err: + return rc; +} + +static void dp_catalog_ctrl_lane_pnswap_v420(struct dp_catalog_ctrl *ctrl, + u8 ln_pnswap) +{ + struct dp_catalog_private_v420 *catalog; + struct dp_io_data *io_data; + u32 cfg0, cfg1; + + catalog = dp_catalog_get_priv_v420(ctrl); + + cfg0 = 0x0a; + cfg1 = 0x0a; + + cfg0 |= ((ln_pnswap >> 0) & 0x1) << 0; + cfg0 |= ((ln_pnswap >> 1) & 0x1) << 2; + cfg1 |= ((ln_pnswap >> 2) & 0x1) << 0; + cfg1 |= ((ln_pnswap >> 3) & 0x1) << 2; + + io_data = catalog->io->dp_ln_tx0; + dp_write(TXn_TX_POL_INV_V420, cfg0); + + io_data = catalog->io->dp_ln_tx1; + dp_write(TXn_TX_POL_INV_V420, cfg1); +} + +static void dp_catalog_put_v420(struct dp_catalog *catalog) +{ + struct dp_catalog_private_v420 *catalog_priv; + + if (!catalog) + return; + + catalog_priv = container_of(catalog->sub, + struct dp_catalog_private_v420, sub); + devm_kfree(catalog_priv->dev, catalog_priv); +} + +struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev, + struct dp_catalog *catalog, struct dp_catalog_io *io) +{ + struct dp_catalog_private_v420 *catalog_priv; + + if (!dev || !catalog) { + DP_ERR("invalid input\n"); + return ERR_PTR(-EINVAL); + } + + catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL); + if (!catalog_priv) + return ERR_PTR(-ENOMEM); + + catalog_priv->dev = dev; + catalog_priv->io = io; + catalog_priv->dpc = catalog; + + catalog_priv->sub.put = dp_catalog_put_v420; + + catalog->aux.setup = dp_catalog_aux_setup_v420; + catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_int_v420; + catalog->panel.config_msa = dp_catalog_panel_config_msa_v420; + catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v420; + catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v420; + catalog->ctrl.lane_pnswap = dp_catalog_ctrl_lane_pnswap_v420; + catalog->ctrl.late_phy_init = dp_catalog_ctrl_late_phy_init_v420; + + return &catalog_priv->sub; +} diff --git a/techpack/display/msm/dp/dp_ctrl.c b/techpack/display/msm/dp/dp_ctrl.c new file mode 100644 index 0000000000000000000000000000000000000000..c84ec44e67751a24e1be74d6ed4a8852ac1fdfbd --- /dev/null +++ b/techpack/display/msm/dp/dp_ctrl.c @@ -0,0 +1,1464 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/types.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <drm/drm_fixed.h> + +#include "dp_ctrl.h" +#include "dp_debug.h" + +#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) + +#define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0) +#define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3) + +#define DP_CTRL_INTR_MST_DP0_VCPF_SENT BIT(0) +#define DP_CTRL_INTR_MST_DP1_VCPF_SENT BIT(3) + +/* dp state ctrl */ +#define ST_TRAIN_PATTERN_1 BIT(0) +#define ST_TRAIN_PATTERN_2 BIT(1) +#define ST_TRAIN_PATTERN_3 BIT(2) +#define ST_TRAIN_PATTERN_4 BIT(3) +#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(4) +#define ST_PRBS7 BIT(5) +#define ST_CUSTOM_80_BIT_PATTERN BIT(6) +#define ST_SEND_VIDEO BIT(7) +#define ST_PUSH_IDLE BIT(8) +#define MST_DP0_PUSH_VCPF BIT(12) +#define MST_DP0_FORCE_VCPF BIT(13) +#define MST_DP1_PUSH_VCPF BIT(14) +#define MST_DP1_FORCE_VCPF BIT(15) + +#define MR_LINK_TRAINING1 0x8 +#define MR_LINK_SYMBOL_ERM 0x80 +#define MR_LINK_PRBS7 0x100 +#define MR_LINK_CUSTOM80 0x200 +#define MR_LINK_TRAINING4 0x40 + +#define DP_MAX_LANES 4 + +struct dp_mst_ch_slot_info { + u32 start_slot; + u32 tot_slots; +}; + +struct dp_mst_channel_info { + struct dp_mst_ch_slot_info slot_info[DP_STREAM_MAX]; +}; + +struct dp_ctrl_private { + struct dp_ctrl dp_ctrl; + + struct device *dev; + struct dp_aux *aux; + struct dp_panel *panel; + struct dp_link *link; + struct dp_power *power; + struct dp_parser *parser; + struct dp_catalog_ctrl *catalog; + + struct completion idle_comp; + struct completion video_comp; + + bool orientation; + bool power_on; + bool mst_mode; + bool fec_mode; + bool dsc_mode; + + atomic_t aborted; + + u8 initial_lane_count; + u8 initial_bw_code; + + u32 vic; + u32 stream_count; + u32 training_2_pattern; + struct dp_mst_channel_info mst_ch_info; +}; + +enum notification_status { + NOTIFY_UNKNOWN, + NOTIFY_CONNECT, + NOTIFY_DISCONNECT, + NOTIFY_CONNECT_IRQ_HPD, + NOTIFY_DISCONNECT_IRQ_HPD, +}; + +static void dp_ctrl_idle_patterns_sent(struct dp_ctrl_private *ctrl) +{ + DP_DEBUG("idle_patterns_sent\n"); + complete(&ctrl->idle_comp); +} + +static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl) +{ + DP_DEBUG("dp_video_ready\n"); + complete(&ctrl->video_comp); +} + +static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl, bool abort) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + DP_ERR("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + atomic_set(&ctrl->aborted, abort); +} + +static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state) +{ + ctrl->catalog->state_ctrl(ctrl->catalog, state); +} + +static void dp_ctrl_push_idle(struct dp_ctrl_private *ctrl, + enum dp_stream_id strm) +{ + int const idle_pattern_completion_timeout_ms = HZ / 10; + u32 state = 0x0; + + if (!ctrl->power_on) + return; + + if (!ctrl->mst_mode) { + state = ST_PUSH_IDLE; + goto trigger_idle; + } + + if (strm >= DP_STREAM_MAX) { + DP_ERR("mst push idle, invalid stream:%d\n", strm); + return; + } + + state |= (strm == DP_STREAM_0) ? MST_DP0_PUSH_VCPF : MST_DP1_PUSH_VCPF; + +trigger_idle: + reinit_completion(&ctrl->idle_comp); + dp_ctrl_state_ctrl(ctrl, state); + + if (!wait_for_completion_timeout(&ctrl->idle_comp, + idle_pattern_completion_timeout_ms)) + DP_WARN("time out\n"); + else + DP_DEBUG("mainlink off done\n"); +} + +/** + * dp_ctrl_configure_source_link_params() - configures DP TX source params + * @ctrl: Display Port Driver data + * @enable: enable or disable DP transmitter + * + * Configures the DP transmitter source params including details such as lane + * configuration, output format and sink/panel timing information. + */ +static void dp_ctrl_configure_source_link_params(struct dp_ctrl_private *ctrl, + bool enable) +{ + if (enable) { + ctrl->catalog->lane_mapping(ctrl->catalog, ctrl->orientation, + ctrl->parser->l_map); + ctrl->catalog->lane_pnswap(ctrl->catalog, + ctrl->parser->l_pnswap); + ctrl->catalog->mst_config(ctrl->catalog, ctrl->mst_mode); + ctrl->catalog->config_ctrl(ctrl->catalog, + ctrl->link->link_params.lane_count); + ctrl->catalog->mainlink_levels(ctrl->catalog, + ctrl->link->link_params.lane_count); + ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); + } else { + ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); + } +} + +static void dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl) +{ + if (!wait_for_completion_timeout(&ctrl->video_comp, HZ / 2)) + DP_WARN("SEND_VIDEO time out\n"); +} + +static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl) +{ + int i, ret; + u8 buf[DP_MAX_LANES]; + u8 v_level = ctrl->link->phy_params.v_level; + u8 p_level = ctrl->link->phy_params.p_level; + u8 size = min_t(u8, sizeof(buf), ctrl->link->link_params.lane_count); + u32 max_level_reached = 0; + + if (v_level == DP_LINK_VOLTAGE_MAX) { + DP_DEBUG("max voltage swing level reached %d\n", v_level); + max_level_reached |= DP_TRAIN_MAX_SWING_REACHED; + } + + if (p_level == DP_LINK_PRE_EMPHASIS_MAX) { + DP_DEBUG("max pre-emphasis level reached %d\n", p_level); + max_level_reached |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + } + + p_level <<= DP_TRAIN_PRE_EMPHASIS_SHIFT; + + for (i = 0; i < size; i++) + buf[i] = v_level | p_level | max_level_reached; + + DP_DEBUG("lanes: %d, swing: 0x%x, pre-emp: 0x%x\n", + size, v_level, p_level); + + ret = drm_dp_dpcd_write(ctrl->aux->drm_aux, + DP_TRAINING_LANE0_SET, buf, size); + + return ret <= 0 ? -EINVAL : 0; +} + +static void dp_ctrl_update_hw_vx_px(struct dp_ctrl_private *ctrl) +{ + struct dp_link *link = ctrl->link; + bool high = false; + + if (ctrl->link->link_params.bw_code == DP_LINK_BW_5_4 || + ctrl->link->link_params.bw_code == DP_LINK_BW_8_1) + high = true; + + ctrl->catalog->update_vx_px(ctrl->catalog, + link->phy_params.v_level, link->phy_params.p_level, high); +} + +static int dp_ctrl_update_sink_pattern(struct dp_ctrl_private *ctrl, u8 pattern) +{ + u8 buf = pattern; + int ret; + + DP_DEBUG("sink: pattern=%x\n", pattern); + + if (pattern && pattern != DP_TRAINING_PATTERN_4) + buf |= DP_LINK_SCRAMBLING_DISABLE; + + ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, + DP_TRAINING_PATTERN_SET, buf); + + return ret <= 0 ? -EINVAL : 0; +} + +static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl, + u8 *link_status) +{ + int ret = 0, len; + u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS; + u32 link_status_read_max_retries = 100; + + while (--link_status_read_max_retries) { + len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, + link_status); + if (len != DP_LINK_STATUS_SIZE) { + DP_ERR("DP link status read failed, err: %d\n", len); + ret = len; + break; + } + + if (!(link_status[offset] & DP_LINK_STATUS_UPDATED)) + break; + } + + return ret; +} + +static int dp_ctrl_lane_count_down_shift(struct dp_ctrl_private *ctrl) +{ + int ret = -EAGAIN; + u8 lanes = ctrl->link->link_params.lane_count; + + if (ctrl->panel->link_info.revision != 0x14) + return -EINVAL; + + switch (lanes) { + case 4: + ctrl->link->link_params.lane_count = 2; + break; + case 2: + ctrl->link->link_params.lane_count = 1; + break; + default: + if (lanes != ctrl->initial_lane_count) + ret = -EINVAL; + break; + } + + DP_DEBUG("new lane count=%d\n", ctrl->link->link_params.lane_count); + + return ret; +} + +static bool dp_ctrl_is_link_rate_rbr(struct dp_ctrl_private *ctrl) +{ + return ctrl->link->link_params.bw_code == DP_LINK_BW_1_62; +} + +static u8 dp_ctrl_get_active_lanes(struct dp_ctrl_private *ctrl, + u8 *link_status) +{ + u8 lane, count = 0; + + for (lane = 0; lane < ctrl->link->link_params.lane_count; lane++) { + if (link_status[lane / 2] & (1 << (lane * 4))) + count++; + else + break; + } + + return count; +} + +static int dp_ctrl_link_training_1(struct dp_ctrl_private *ctrl) +{ + int tries, old_v_level, ret = -EINVAL; + u8 link_status[DP_LINK_STATUS_SIZE]; + u8 pattern = 0; + int const maximum_retries = 5; + + ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED; + ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED; + ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED; + + dp_ctrl_state_ctrl(ctrl, 0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + tries = 0; + old_v_level = ctrl->link->phy_params.v_level; + while (!atomic_read(&ctrl->aborted)) { + /* update hardware with current swing/pre-emp values */ + dp_ctrl_update_hw_vx_px(ctrl); + + if (!pattern) { + pattern = DP_TRAINING_PATTERN_1; + + ctrl->catalog->set_pattern(ctrl->catalog, pattern); + + /* update sink with current settings */ + ret = dp_ctrl_update_sink_pattern(ctrl, pattern); + if (ret) + break; + } + + ret = dp_ctrl_update_sink_vx_px(ctrl); + if (ret) + break; + + drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd); + + ret = dp_ctrl_read_link_status(ctrl, link_status); + if (ret) + break; + + if (!drm_dp_clock_recovery_ok(link_status, + ctrl->link->link_params.lane_count)) + ret = -EINVAL; + else + break; + + if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) { + pr_err_ratelimited("max v_level reached\n"); + break; + } + + if (old_v_level == ctrl->link->phy_params.v_level) { + if (++tries >= maximum_retries) { + DP_ERR("max tries reached\n"); + ret = -ETIMEDOUT; + break; + } + } else { + tries = 0; + old_v_level = ctrl->link->phy_params.v_level; + } + + DP_DEBUG("clock recovery not done, adjusting vx px\n"); + + ctrl->link->adjust_levels(ctrl->link, link_status); + } + + if (ret && dp_ctrl_is_link_rate_rbr(ctrl)) { + u8 active_lanes = dp_ctrl_get_active_lanes(ctrl, link_status); + + if (active_lanes) { + ctrl->link->link_params.lane_count = active_lanes; + ctrl->link->link_params.bw_code = ctrl->initial_bw_code; + + /* retry with new settings */ + ret = -EAGAIN; + } + } + + ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED; + + if (ret) + ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED; + else + ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED; + + return ret; +} + +static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + + if (!ctrl) + return -EINVAL; + + switch (ctrl->link->link_params.bw_code) { + case DP_LINK_BW_8_1: + ctrl->link->link_params.bw_code = DP_LINK_BW_5_4; + break; + case DP_LINK_BW_5_4: + ctrl->link->link_params.bw_code = DP_LINK_BW_2_7; + break; + case DP_LINK_BW_2_7: + case DP_LINK_BW_1_62: + default: + ctrl->link->link_params.bw_code = DP_LINK_BW_1_62; + break; + } + + DP_DEBUG("new bw code=0x%x\n", ctrl->link->link_params.bw_code); + + return ret; +} + +static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) +{ + dp_ctrl_update_sink_pattern(ctrl, 0); + drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); +} + +static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) +{ + int tries = 0, ret = -EINVAL; + u8 dpcd_pattern, pattern = 0; + int const maximum_retries = 5; + u8 link_status[DP_LINK_STATUS_SIZE]; + + ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED; + ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED; + ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED; + + dp_ctrl_state_ctrl(ctrl, 0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + dpcd_pattern = ctrl->training_2_pattern; + + while (!atomic_read(&ctrl->aborted)) { + /* update hardware with current swing/pre-emp values */ + dp_ctrl_update_hw_vx_px(ctrl); + + if (!pattern) { + pattern = dpcd_pattern; + + /* program hw to send pattern */ + ctrl->catalog->set_pattern(ctrl->catalog, pattern); + + /* update sink with current pattern */ + ret = dp_ctrl_update_sink_pattern(ctrl, pattern); + if (ret) + break; + } + + ret = dp_ctrl_update_sink_vx_px(ctrl); + if (ret) + break; + + drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); + + ret = dp_ctrl_read_link_status(ctrl, link_status); + if (ret) + break; + + /* check if CR bits still remain set */ + if (!drm_dp_clock_recovery_ok(link_status, + ctrl->link->link_params.lane_count)) { + ret = -EINVAL; + break; + } + + if (!drm_dp_channel_eq_ok(link_status, + ctrl->link->link_params.lane_count)) + ret = -EINVAL; + else + break; + + if (tries >= maximum_retries) { + ret = dp_ctrl_lane_count_down_shift(ctrl); + break; + } + tries++; + + ctrl->link->adjust_levels(ctrl->link, link_status); + } + + ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED; + + if (ret) + ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED; + else + ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED; + return ret; +} + +static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + u8 const encoding = 0x1, downspread = 0x00; + struct drm_dp_link link_info = {0}; + + ctrl->link->phy_params.p_level = 0; + ctrl->link->phy_params.v_level = 0; + + link_info.num_lanes = ctrl->link->link_params.lane_count; + link_info.rate = drm_dp_bw_code_to_link_rate( + ctrl->link->link_params.bw_code); + link_info.capabilities = ctrl->panel->link_info.capabilities; + + ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info); + if (ret) + goto end; + + ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, + DP_DOWNSPREAD_CTRL, downspread); + if (ret <= 0) { + ret = -EINVAL; + goto end; + } + + ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, + DP_MAIN_LINK_CHANNEL_CODING_SET, encoding); + if (ret <= 0) { + ret = -EINVAL; + goto end; + } + + ret = dp_ctrl_link_training_1(ctrl); + if (ret) { + DP_ERR("link training #1 failed\n"); + goto end; + } + + /* print success info as this is a result of user initiated action */ + DP_INFO("link training #1 successful\n"); + + ret = dp_ctrl_link_training_2(ctrl); + if (ret) { + DP_ERR("link training #2 failed\n"); + goto end; + } + + /* print success info as this is a result of user initiated action */ + DP_INFO("link training #2 successful\n"); + +end: + dp_ctrl_state_ctrl(ctrl, 0); + /* Make sure to clear the current pattern before starting a new one */ + wmb(); + + dp_ctrl_clear_training_pattern(ctrl); + return ret; +} + +static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) + goto end; + + /* + * As part of previous calls, DP controller state might have + * transitioned to PUSH_IDLE. In order to start transmitting a link + * training pattern, we have to first to a DP software reset. + */ + ctrl->catalog->reset(ctrl->catalog); + + if (ctrl->fec_mode) + drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_FEC_CONFIGURATION, + 0x01); + + ret = dp_ctrl_link_train(ctrl); + +end: + return ret; +} + +static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl, + char *name, enum dp_pm_type clk_type, u32 rate) +{ + u32 num = ctrl->parser->mp[clk_type].num_clk; + struct dss_clk *cfg = ctrl->parser->mp[clk_type].clk_config; + + while (num && strcmp(cfg->clk_name, name)) { + num--; + cfg++; + } + + DP_DEBUG("setting rate=%d on clk=%s\n", rate, name); + + if (num) + cfg->rate = rate; + else + DP_ERR("%s clock could not be set with rate %d\n", name, rate); +} + +static int dp_ctrl_enable_link_clock(struct dp_ctrl_private *ctrl) +{ + int ret = 0; + u32 rate = drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code); + enum dp_pm_type type = DP_LINK_PM; + + DP_DEBUG("rate=%d\n", rate); + + dp_ctrl_set_clock_rate(ctrl, "link_clk", type, rate); + + ret = ctrl->power->clk_enable(ctrl->power, type, true); + if (ret) { + DP_ERR("Unabled to start link clocks\n"); + ret = -EINVAL; + } + + return ret; +} + +static void dp_ctrl_disable_link_clock(struct dp_ctrl_private *ctrl) +{ + ctrl->power->clk_enable(ctrl->power, DP_LINK_PM, false); +} + +static void dp_ctrl_select_training_pattern(struct dp_ctrl_private *ctrl, + bool downgrade) +{ + u32 pattern; + + if (drm_dp_tps4_supported(ctrl->panel->dpcd)) + pattern = DP_TRAINING_PATTERN_4; + else if (drm_dp_tps3_supported(ctrl->panel->dpcd)) + pattern = DP_TRAINING_PATTERN_3; + else + pattern = DP_TRAINING_PATTERN_2; + + if (!downgrade) + goto end; + + switch (pattern) { + case DP_TRAINING_PATTERN_4: + pattern = DP_TRAINING_PATTERN_3; + break; + case DP_TRAINING_PATTERN_3: + pattern = DP_TRAINING_PATTERN_2; + break; + default: + break; + } +end: + ctrl->training_2_pattern = pattern; +} + +static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow) +{ + int rc = -EINVAL; + bool downgrade = false; + u32 link_train_max_retries = 100; + struct dp_catalog_ctrl *catalog; + struct dp_link_params *link_params; + + catalog = ctrl->catalog; + link_params = &ctrl->link->link_params; + + catalog->phy_lane_cfg(catalog, ctrl->orientation, + link_params->lane_count); + + while (1) { + DP_DEBUG("bw_code=%d, lane_count=%d\n", + link_params->bw_code, link_params->lane_count); + + rc = dp_ctrl_enable_link_clock(ctrl); + if (rc) + break; + + ctrl->catalog->late_phy_init(ctrl->catalog, + ctrl->link->link_params.lane_count, + ctrl->orientation); + + dp_ctrl_configure_source_link_params(ctrl, true); + + if (!(--link_train_max_retries % 10)) { + struct dp_link_params *link = &ctrl->link->link_params; + + link->lane_count = ctrl->initial_lane_count; + link->bw_code = ctrl->initial_bw_code; + downgrade = true; + } + + dp_ctrl_select_training_pattern(ctrl, downgrade); + + rc = dp_ctrl_setup_main_link(ctrl); + if (!rc) + break; + + /* + * Shallow means link training failure is not important. + * If it fails, we still keep the link clocks on. + * In this mode, the system expects DP to be up + * even though the cable is removed. Disconnect interrupt + * will eventually trigger and shutdown DP. + */ + if (shallow) { + rc = 0; + break; + } + + if (!link_train_max_retries || atomic_read(&ctrl->aborted)) { + dp_ctrl_disable_link_clock(ctrl); + break; + } + + if (rc != -EAGAIN) + dp_ctrl_link_rate_down_shift(ctrl); + + dp_ctrl_configure_source_link_params(ctrl, false); + dp_ctrl_disable_link_clock(ctrl); + + /* hw recommended delays before retrying link training */ + msleep(20); + } + + return rc; +} + +static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl, + struct dp_panel *dp_panel) +{ + int ret = 0; + u32 pclk; + enum dp_pm_type clk_type; + char clk_name[32] = ""; + + ret = ctrl->power->set_pixel_clk_parent(ctrl->power, + dp_panel->stream_id); + + if (ret) + return ret; + + if (dp_panel->stream_id == DP_STREAM_0) { + clk_type = DP_STREAM0_PM; + strlcpy(clk_name, "strm0_pixel_clk", 32); + } else if (dp_panel->stream_id == DP_STREAM_1) { + clk_type = DP_STREAM1_PM; + strlcpy(clk_name, "strm1_pixel_clk", 32); + } else { + DP_ERR("Invalid stream:%d for clk enable\n", + dp_panel->stream_id); + return -EINVAL; + } + + pclk = dp_panel->pinfo.widebus_en ? + (dp_panel->pinfo.pixel_clk_khz >> 1) : + (dp_panel->pinfo.pixel_clk_khz); + + dp_ctrl_set_clock_rate(ctrl, clk_name, clk_type, pclk); + + ret = ctrl->power->clk_enable(ctrl->power, clk_type, true); + if (ret) { + DP_ERR("Unabled to start stream:%d clocks\n", + dp_panel->stream_id); + ret = -EINVAL; + } + + return ret; +} + +static int dp_ctrl_disable_stream_clocks(struct dp_ctrl_private *ctrl, + struct dp_panel *dp_panel) +{ + int ret = 0; + + if (dp_panel->stream_id == DP_STREAM_0) { + return ctrl->power->clk_enable(ctrl->power, + DP_STREAM0_PM, false); + } else if (dp_panel->stream_id == DP_STREAM_1) { + return ctrl->power->clk_enable(ctrl->power, + DP_STREAM1_PM, false); + } else { + DP_ERR("Invalid stream:%d for clk disable\n", + dp_panel->stream_id); + ret = -EINVAL; + } + return ret; +} +static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset) +{ + struct dp_ctrl_private *ctrl; + struct dp_catalog_ctrl *catalog; + + if (!dp_ctrl) { + DP_ERR("Invalid input data\n"); + return -EINVAL; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->orientation = flip; + catalog = ctrl->catalog; + + if (reset) { + catalog->usb_reset(ctrl->catalog, flip); + catalog->phy_reset(ctrl->catalog); + } + catalog->enable_irq(ctrl->catalog, true); + atomic_set(&ctrl->aborted, 0); + + return 0; +} + +/** + * dp_ctrl_host_deinit() - Uninitialize DP controller + * @ctrl: Display Port Driver data + * + * Perform required steps to uninitialize DP controller + * and its resources. + */ +static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + DP_ERR("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->catalog->enable_irq(ctrl->catalog, false); + + DP_DEBUG("Host deinitialized successfully\n"); +} + +static void dp_ctrl_send_video(struct dp_ctrl_private *ctrl) +{ + ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO); +} + +static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) +{ + int ret = 0; + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + DP_ERR("Invalid input data\n"); + return -EINVAL; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED; + ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED; + + if (!ctrl->power_on) { + DP_ERR("ctrl off\n"); + ret = -EINVAL; + goto end; + } + + if (atomic_read(&ctrl->aborted)) + goto end; + + ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED; + ret = dp_ctrl_setup_main_link(ctrl); + ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED; + + if (ret) { + ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED; + goto end; + } + + ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED; + + if (ctrl->stream_count) { + dp_ctrl_send_video(ctrl); + dp_ctrl_wait4video_ready(ctrl); + } +end: + return ret; +} + +static void dp_ctrl_process_phy_test_request(struct dp_ctrl *dp_ctrl) +{ + int ret = 0; + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) { + DP_ERR("Invalid input data\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->link->phy_params.phy_test_pattern_sel) { + DP_DEBUG("no test pattern selected by sink\n"); + return; + } + + DP_DEBUG("start\n"); + + /* + * The global reset will need DP link ralated clocks to be + * running. Add the global reset just before disabling the + * link clocks and core clocks. + */ + ctrl->catalog->reset(ctrl->catalog); + ctrl->dp_ctrl.stream_pre_off(&ctrl->dp_ctrl, ctrl->panel); + ctrl->dp_ctrl.stream_off(&ctrl->dp_ctrl, ctrl->panel); + ctrl->dp_ctrl.off(&ctrl->dp_ctrl); + + ctrl->aux->init(ctrl->aux, ctrl->parser->aux_cfg); + + ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl, ctrl->mst_mode, + ctrl->fec_mode, ctrl->dsc_mode, false); + if (ret) + DP_ERR("failed to enable DP controller\n"); + + ctrl->dp_ctrl.stream_on(&ctrl->dp_ctrl, ctrl->panel); + DP_DEBUG("end\n"); +} + +static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) +{ + bool success = false; + u32 pattern_sent = 0x0; + u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; + + dp_ctrl_update_hw_vx_px(ctrl); + ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); + dp_ctrl_update_sink_vx_px(ctrl); + ctrl->link->send_test_response(ctrl->link); + + pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog); + DP_DEBUG("pattern_request: %s. pattern_sent: 0x%x\n", + dp_link_get_phy_test_pattern(pattern_requested), + pattern_sent); + + switch (pattern_sent) { + case MR_LINK_TRAINING1: + if (pattern_requested == + DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING) + success = true; + break; + case MR_LINK_SYMBOL_ERM: + if ((pattern_requested == + DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT) + || (pattern_requested == + DP_TEST_PHY_PATTERN_CP2520_PATTERN_1)) + success = true; + break; + case MR_LINK_PRBS7: + if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7) + success = true; + break; + case MR_LINK_CUSTOM80: + if (pattern_requested == + DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN) + success = true; + break; + case MR_LINK_TRAINING4: + if (pattern_requested == + DP_TEST_PHY_PATTERN_CP2520_PATTERN_3) + success = true; + break; + default: + success = false; + break; + } + + DP_DEBUG("%s: %s\n", success ? "success" : "failed", + dp_link_get_phy_test_pattern(pattern_requested)); +} + +static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl, + struct dp_panel *panel, u32 *p_x_int, u32 *p_y_frac_enum) +{ + u64 min_slot_cnt, max_slot_cnt; + u64 raw_target_sc, target_sc_fixp; + u64 ts_denom, ts_enum, ts_int; + u64 pclk = panel->pinfo.pixel_clk_khz; + u64 lclk = panel->link_info.rate; + u64 lanes = panel->link_info.num_lanes; + u64 bpp = panel->pinfo.bpp; + u64 pbn = panel->pbn; + u64 numerator, denominator, temp, temp1, temp2; + u32 x_int = 0, y_frac_enum = 0; + u64 target_strm_sym, ts_int_fixp, ts_frac_fixp, y_frac_enum_fixp; + + if (panel->pinfo.comp_info.comp_ratio) + bpp = panel->pinfo.comp_info.dsc_info.bpp; + + /* min_slot_cnt */ + numerator = pclk * bpp * 64 * 1000; + denominator = lclk * lanes * 8 * 1000; + min_slot_cnt = drm_fixp_from_fraction(numerator, denominator); + + /* max_slot_cnt */ + numerator = pbn * 54 * 1000; + denominator = lclk * lanes; + max_slot_cnt = drm_fixp_from_fraction(numerator, denominator); + + /* raw_target_sc */ + numerator = max_slot_cnt + min_slot_cnt; + denominator = drm_fixp_from_fraction(2, 1); + raw_target_sc = drm_fixp_div(numerator, denominator); + + DP_DEBUG("raw_target_sc before overhead:0x%llx\n", raw_target_sc); + DP_DEBUG("dsc_overhead_fp:0x%llx\n", panel->pinfo.dsc_overhead_fp); + + /* apply fec and dsc overhead factor */ + if (panel->pinfo.dsc_overhead_fp) + raw_target_sc = drm_fixp_mul(raw_target_sc, + panel->pinfo.dsc_overhead_fp); + + if (panel->fec_overhead_fp) + raw_target_sc = drm_fixp_mul(raw_target_sc, + panel->fec_overhead_fp); + + DP_DEBUG("raw_target_sc after overhead:0x%llx\n", raw_target_sc); + + /* target_sc */ + temp = drm_fixp_from_fraction(256 * lanes, 1); + numerator = drm_fixp_mul(raw_target_sc, temp); + denominator = drm_fixp_from_fraction(256 * lanes, 1); + target_sc_fixp = drm_fixp_div(numerator, denominator); + + ts_enum = 256 * lanes; + ts_denom = drm_fixp_from_fraction(256 * lanes, 1); + ts_int = drm_fixp2int(target_sc_fixp); + + temp = drm_fixp2int_ceil(raw_target_sc); + if (temp != ts_int) { + temp = drm_fixp_from_fraction(ts_int, 1); + temp1 = raw_target_sc - temp; + temp2 = drm_fixp_mul(temp1, ts_denom); + ts_enum = drm_fixp2int(temp2); + } + + /* target_strm_sym */ + ts_int_fixp = drm_fixp_from_fraction(ts_int, 1); + ts_frac_fixp = drm_fixp_from_fraction(ts_enum, drm_fixp2int(ts_denom)); + temp = ts_int_fixp + ts_frac_fixp; + temp1 = drm_fixp_from_fraction(lanes, 1); + target_strm_sym = drm_fixp_mul(temp, temp1); + + /* x_int */ + x_int = drm_fixp2int(target_strm_sym); + + /* y_enum_frac */ + temp = drm_fixp_from_fraction(x_int, 1); + temp1 = target_strm_sym - temp; + temp2 = drm_fixp_from_fraction(256, 1); + y_frac_enum_fixp = drm_fixp_mul(temp1, temp2); + + temp1 = drm_fixp2int(y_frac_enum_fixp); + temp2 = drm_fixp2int_ceil(y_frac_enum_fixp); + + y_frac_enum = (u32)((temp1 == temp2) ? temp1 : temp1 + 1); + + panel->mst_target_sc = raw_target_sc; + *p_x_int = x_int; + *p_y_frac_enum = y_frac_enum; + + DP_DEBUG("x_int: %d, y_frac_enum: %d\n", x_int, y_frac_enum); +} + +static int dp_ctrl_mst_send_act(struct dp_ctrl_private *ctrl) +{ + bool act_complete; + + if (!ctrl->mst_mode) + return 0; + + ctrl->catalog->trigger_act(ctrl->catalog); + msleep(20); /* needs 1 frame time */ + + ctrl->catalog->read_act_complete_sts(ctrl->catalog, &act_complete); + + if (!act_complete) + DP_ERR("mst act trigger complete failed\n"); + else + DP_MST_DEBUG("mst ACT trigger complete SUCCESS\n"); + + return 0; +} + +static void dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl, + struct dp_panel *panel) +{ + u32 x_int, y_frac_enum, lanes, bw_code; + int i; + + if (!ctrl->mst_mode) + return; + + DP_MST_DEBUG("mst stream channel allocation\n"); + + for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { + ctrl->catalog->channel_alloc(ctrl->catalog, + i, + ctrl->mst_ch_info.slot_info[i].start_slot, + ctrl->mst_ch_info.slot_info[i].tot_slots); + } + + lanes = ctrl->link->link_params.lane_count; + bw_code = ctrl->link->link_params.bw_code; + + dp_ctrl_mst_calculate_rg(ctrl, panel, &x_int, &y_frac_enum); + + ctrl->catalog->update_rg(ctrl->catalog, panel->stream_id, + x_int, y_frac_enum); + + DP_MST_DEBUG("mst stream:%d, start_slot:%d, tot_slots:%d\n", + panel->stream_id, + panel->channel_start_slot, panel->channel_total_slots); + + DP_MST_DEBUG("mst lane_cnt:%d, bw:%d, x_int:%d, y_frac:%d\n", + lanes, bw_code, x_int, y_frac_enum); +} + +static void dp_ctrl_fec_dsc_setup(struct dp_ctrl_private *ctrl) +{ + u8 fec_sts = 0; + int rlen; + u32 dsc_enable; + + if (!ctrl->fec_mode) + return; + + ctrl->catalog->fec_config(ctrl->catalog, ctrl->fec_mode); + + /* wait for controller to start fec sequence */ + usleep_range(900, 1000); + drm_dp_dpcd_readb(ctrl->aux->drm_aux, DP_FEC_STATUS, &fec_sts); + DP_DEBUG("sink fec status:%d\n", fec_sts); + + dsc_enable = ctrl->dsc_mode ? 1 : 0; + rlen = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_DSC_ENABLE, + dsc_enable); + if (rlen < 1) + DP_DEBUG("failed to enable sink dsc\n"); +} + +static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) +{ + int rc = 0; + bool link_ready = false; + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl || !panel) + return -EINVAL; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->power_on) { + DP_ERR("ctrl off\n"); + return -EINVAL; + } + + rc = dp_ctrl_enable_stream_clocks(ctrl, panel); + if (rc) { + DP_ERR("failure on stream clock enable\n"); + return rc; + } + + rc = panel->hw_cfg(panel, true); + if (rc) + return rc; + + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { + dp_ctrl_send_phy_test_pattern(ctrl); + return 0; + } + + dp_ctrl_mst_stream_setup(ctrl, panel); + + dp_ctrl_send_video(ctrl); + + dp_ctrl_mst_send_act(ctrl); + + dp_ctrl_wait4video_ready(ctrl); + + ctrl->stream_count++; + + link_ready = ctrl->catalog->mainlink_ready(ctrl->catalog); + DP_DEBUG("mainlink %s\n", link_ready ? "READY" : "NOT READY"); + + /* wait for link training completion before fec config as per spec */ + dp_ctrl_fec_dsc_setup(ctrl); + + return rc; +} + +static void dp_ctrl_mst_stream_pre_off(struct dp_ctrl *dp_ctrl, + struct dp_panel *panel) +{ + struct dp_ctrl_private *ctrl; + bool act_complete; + int i; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->mst_mode) + return; + + for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { + ctrl->catalog->channel_alloc(ctrl->catalog, + i, + ctrl->mst_ch_info.slot_info[i].start_slot, + ctrl->mst_ch_info.slot_info[i].tot_slots); + } + + ctrl->catalog->trigger_act(ctrl->catalog); + msleep(20); /* needs 1 frame time */ + ctrl->catalog->read_act_complete_sts(ctrl->catalog, &act_complete); + + if (!act_complete) + DP_ERR("mst stream_off act trigger complete failed\n"); + else + DP_MST_DEBUG("mst stream_off ACT trigger complete SUCCESS\n"); +} + +static void dp_ctrl_stream_pre_off(struct dp_ctrl *dp_ctrl, + struct dp_panel *panel) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl || !panel) { + DP_ERR("invalid input\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + dp_ctrl_push_idle(ctrl, panel->stream_id); + + dp_ctrl_mst_stream_pre_off(dp_ctrl, panel); +} + +static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl || !panel) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->power_on) + return; + + panel->hw_cfg(panel, false); + + dp_ctrl_disable_stream_clocks(ctrl, panel); + ctrl->stream_count--; +} + +static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode, + bool fec_mode, bool dsc_mode, bool shallow) +{ + int rc = 0; + struct dp_ctrl_private *ctrl; + u32 rate = 0; + + if (!dp_ctrl) { + rc = -EINVAL; + goto end; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (ctrl->power_on) + goto end; + + if (atomic_read(&ctrl->aborted)) { + rc = -EPERM; + goto end; + } + + ctrl->mst_mode = mst_mode; + if (fec_mode) { + ctrl->fec_mode = fec_mode; + ctrl->dsc_mode = dsc_mode; + } + + rate = ctrl->panel->link_info.rate; + + if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { + DP_DEBUG("using phy test link parameters\n"); + } else { + ctrl->link->link_params.bw_code = + drm_dp_link_rate_to_bw_code(rate); + ctrl->link->link_params.lane_count = + ctrl->panel->link_info.num_lanes; + } + + DP_DEBUG("bw_code=%d, lane_count=%d\n", + ctrl->link->link_params.bw_code, + ctrl->link->link_params.lane_count); + + /* backup initial lane count and bw code */ + ctrl->initial_lane_count = ctrl->link->link_params.lane_count; + ctrl->initial_bw_code = ctrl->link->link_params.bw_code; + + rc = dp_ctrl_link_setup(ctrl, shallow); + if (!rc) + ctrl->power_on = true; +end: + return rc; +} + +static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + if (!ctrl->power_on) + return; + + ctrl->catalog->fec_config(ctrl->catalog, false); + dp_ctrl_configure_source_link_params(ctrl, false); + ctrl->catalog->reset(ctrl->catalog); + + /* Make sure DP is disabled before clk disable */ + wmb(); + + dp_ctrl_disable_link_clock(ctrl); + + ctrl->mst_mode = false; + ctrl->fec_mode = false; + ctrl->dsc_mode = false; + ctrl->power_on = false; + memset(&ctrl->mst_ch_info, 0, sizeof(ctrl->mst_ch_info)); + DP_DEBUG("DP off done\n"); +} + +static void dp_ctrl_set_mst_channel_info(struct dp_ctrl *dp_ctrl, + enum dp_stream_id strm, + u32 start_slot, u32 tot_slots) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl || strm >= DP_STREAM_MAX) { + DP_ERR("invalid input\n"); + return; + } + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->mst_ch_info.slot_info[strm].start_slot = start_slot; + ctrl->mst_ch_info.slot_info[strm].tot_slots = tot_slots; +} + +static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + ctrl->catalog->get_interrupt(ctrl->catalog); + + if (ctrl->catalog->isr & DP_CTRL_INTR_READY_FOR_VIDEO) + dp_ctrl_video_ready(ctrl); + + if (ctrl->catalog->isr & DP_CTRL_INTR_IDLE_PATTERN_SENT) + dp_ctrl_idle_patterns_sent(ctrl); + + if (ctrl->catalog->isr5 & DP_CTRL_INTR_MST_DP0_VCPF_SENT) + dp_ctrl_idle_patterns_sent(ctrl); + + if (ctrl->catalog->isr5 & DP_CTRL_INTR_MST_DP1_VCPF_SENT) + dp_ctrl_idle_patterns_sent(ctrl); +} + +struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in) +{ + int rc = 0; + struct dp_ctrl_private *ctrl; + struct dp_ctrl *dp_ctrl; + + if (!in->dev || !in->panel || !in->aux || + !in->link || !in->catalog) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + ctrl = devm_kzalloc(in->dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) { + rc = -ENOMEM; + goto error; + } + + init_completion(&ctrl->idle_comp); + init_completion(&ctrl->video_comp); + + /* in parameters */ + ctrl->parser = in->parser; + ctrl->panel = in->panel; + ctrl->power = in->power; + ctrl->aux = in->aux; + ctrl->link = in->link; + ctrl->catalog = in->catalog; + ctrl->dev = in->dev; + ctrl->mst_mode = false; + ctrl->fec_mode = false; + + dp_ctrl = &ctrl->dp_ctrl; + + /* out parameters */ + dp_ctrl->init = dp_ctrl_host_init; + dp_ctrl->deinit = dp_ctrl_host_deinit; + dp_ctrl->on = dp_ctrl_on; + dp_ctrl->off = dp_ctrl_off; + dp_ctrl->abort = dp_ctrl_abort; + dp_ctrl->isr = dp_ctrl_isr; + dp_ctrl->link_maintenance = dp_ctrl_link_maintenance; + dp_ctrl->process_phy_test_request = dp_ctrl_process_phy_test_request; + dp_ctrl->stream_on = dp_ctrl_stream_on; + dp_ctrl->stream_off = dp_ctrl_stream_off; + dp_ctrl->stream_pre_off = dp_ctrl_stream_pre_off; + dp_ctrl->set_mst_channel_info = dp_ctrl_set_mst_channel_info; + + return dp_ctrl; +error: + return ERR_PTR(rc); +} + +void dp_ctrl_put(struct dp_ctrl *dp_ctrl) +{ + struct dp_ctrl_private *ctrl; + + if (!dp_ctrl) + return; + + ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); + + devm_kfree(ctrl->dev, ctrl); +} diff --git a/techpack/display/msm/dp/dp_ctrl.h b/techpack/display/msm/dp/dp_ctrl.h new file mode 100644 index 0000000000000000000000000000000000000000..a2e20e26fe3041e37cc7eec868ae1efbb1595baf --- /dev/null +++ b/techpack/display/msm/dp/dp_ctrl.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_CTRL_H_ +#define _DP_CTRL_H_ + +#include "dp_aux.h" +#include "dp_panel.h" +#include "dp_link.h" +#include "dp_parser.h" +#include "dp_power.h" +#include "dp_catalog.h" + +struct dp_ctrl { + int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset); + void (*deinit)(struct dp_ctrl *dp_ctrl); + int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en, + bool dsc_en, bool shallow); + void (*off)(struct dp_ctrl *dp_ctrl); + void (*abort)(struct dp_ctrl *dp_ctrl, bool abort); + void (*isr)(struct dp_ctrl *dp_ctrl); + bool (*handle_sink_request)(struct dp_ctrl *dp_ctrl); + void (*process_phy_test_request)(struct dp_ctrl *dp_ctrl); + int (*link_maintenance)(struct dp_ctrl *dp_ctrl); + int (*stream_on)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel); + void (*stream_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel); + void (*stream_pre_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel); + void (*set_mst_channel_info)(struct dp_ctrl *dp_ctrl, + enum dp_stream_id strm, + u32 ch_start_slot, u32 ch_tot_slots); +}; + +struct dp_ctrl_in { + struct device *dev; + struct dp_panel *panel; + struct dp_aux *aux; + struct dp_link *link; + struct dp_parser *parser; + struct dp_power *power; + struct dp_catalog_ctrl *catalog; +}; + +struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in); +void dp_ctrl_put(struct dp_ctrl *dp_ctrl); + +#endif /* _DP_CTRL_H_ */ diff --git a/techpack/display/msm/dp/dp_debug.c b/techpack/display/msm/dp/dp_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..0459adceb1fa854a2f7753ae6118afae1c2bed92 --- /dev/null +++ b/techpack/display/msm/dp/dp_debug.c @@ -0,0 +1,2329 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/slab.h> + +#include "dp_power.h" +#include "dp_catalog.h" +#include "dp_aux.h" +#include "dp_debug.h" +#include "drm_connector.h" +#include "sde_connector.h" +#include "dp_display.h" + +#define DEBUG_NAME "drm_dp" + +struct dp_debug_private { + struct dentry *root; + u8 *edid; + u32 edid_size; + + u8 *dpcd; + u32 dpcd_size; + + u32 mst_con_id; + bool hotplug; + + char exe_mode[SZ_32]; + char reg_dump[SZ_32]; + + struct dp_hpd *hpd; + struct dp_link *link; + struct dp_panel *panel; + struct dp_aux *aux; + struct dp_catalog *catalog; + struct drm_connector **connector; + struct device *dev; + struct dp_debug dp_debug; + struct dp_parser *parser; + struct dp_ctrl *ctrl; + struct mutex lock; +}; + +static int dp_debug_get_edid_buf(struct dp_debug_private *debug) +{ + int rc = 0; + + if (!debug->edid) { + debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL); + if (!debug->edid) { + rc = -ENOMEM; + goto end; + } + + debug->edid_size = SZ_256; + } +end: + return rc; +} + +static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug) +{ + int rc = 0; + + if (!debug->dpcd) { + debug->dpcd = devm_kzalloc(debug->dev, SZ_4K, GFP_KERNEL); + if (!debug->dpcd) { + rc = -ENOMEM; + goto end; + } + + debug->dpcd_size = SZ_4K; + } +end: + return rc; +} + +static ssize_t dp_debug_write_edid(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + u8 *buf = NULL, *buf_t = NULL, *edid = NULL; + const int char_to_nib = 2; + size_t edid_size = 0; + size_t size = 0, edid_buf_index = 0; + ssize_t rc = count; + + if (!debug) + return -ENODEV; + + mutex_lock(&debug->lock); + + if (*ppos) + goto bail; + + size = min_t(size_t, count, SZ_1K); + + buf = kzalloc(size, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) { + rc = -ENOMEM; + goto bail; + } + + if (copy_from_user(buf, user_buff, size)) + goto bail; + + edid_size = size / char_to_nib; + buf_t = buf; + + if (dp_debug_get_edid_buf(debug)) + goto bail; + + if (edid_size != debug->edid_size) { + DP_DEBUG("realloc debug edid\n"); + + if (debug->edid) { + devm_kfree(debug->dev, debug->edid); + + debug->edid = devm_kzalloc(debug->dev, + edid_size, GFP_KERNEL); + if (!debug->edid) { + rc = -ENOMEM; + goto bail; + } + + debug->edid_size = edid_size; + + debug->aux->set_sim_mode(debug->aux, + debug->dp_debug.sim_mode, + debug->edid, debug->dpcd); + } + } + + while (edid_size--) { + char t[3]; + int d; + + memcpy(t, buf_t, sizeof(char) * char_to_nib); + t[char_to_nib] = '\0'; + + if (kstrtoint(t, 16, &d)) { + DP_ERR("kstrtoint error\n"); + goto bail; + } + + if (debug->edid && (edid_buf_index < debug->edid_size)) + debug->edid[edid_buf_index++] = d; + + buf_t += char_to_nib; + } + + edid = debug->edid; +bail: + kfree(buf); + debug->panel->set_edid(debug->panel, edid); + + /* + * print edid status as this code is executed + * only while running in debug mode which is manually + * triggered by a tester or a script. + */ + DP_INFO("[%s]\n", edid ? "SET" : "CLEAR"); + + mutex_unlock(&debug->lock); + return rc; +} + +static ssize_t dp_debug_write_dpcd(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + u8 *buf = NULL, *buf_t = NULL, *dpcd = NULL; + const int char_to_nib = 2; + size_t dpcd_size = 0; + size_t size = 0, dpcd_buf_index = 0; + ssize_t rc = count; + char offset_ch[5]; + u32 offset, data_len; + const u32 dp_receiver_cap_size = 16; + + if (!debug) + return -ENODEV; + + mutex_lock(&debug->lock); + + if (*ppos) + goto bail; + + size = min_t(size_t, count, SZ_2K); + + if (size <= 4) + goto bail; + + buf = kzalloc(size, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) { + rc = -ENOMEM; + goto bail; + } + + if (copy_from_user(buf, user_buff, size)) + goto bail; + + memcpy(offset_ch, buf, 4); + offset_ch[4] = '\0'; + + if (kstrtoint(offset_ch, 16, &offset)) { + DP_ERR("offset kstrtoint error\n"); + goto bail; + } + + if (dp_debug_get_dpcd_buf(debug)) + goto bail; + + if (offset == 0xFFFF) { + DP_ERR("clearing dpcd\n"); + memset(debug->dpcd, 0, debug->dpcd_size); + goto bail; + } + + size -= 4; + if (size == 0) + goto bail; + + dpcd_size = size / char_to_nib; + data_len = dpcd_size; + buf_t = buf + 4; + + dpcd_buf_index = offset; + + while (dpcd_size--) { + char t[3]; + int d; + + memcpy(t, buf_t, sizeof(char) * char_to_nib); + t[char_to_nib] = '\0'; + + if (kstrtoint(t, 16, &d)) { + DP_ERR("kstrtoint error\n"); + goto bail; + } + + if (dpcd_buf_index < debug->dpcd_size) + debug->dpcd[dpcd_buf_index++] = d; + + buf_t += char_to_nib; + } + + dpcd = debug->dpcd; +bail: + kfree(buf); + + if (!dpcd || (size / char_to_nib) >= dp_receiver_cap_size || + offset == 0xffff) { + debug->panel->set_dpcd(debug->panel, dpcd); + /* + * print dpcd status as this code is executed + * only while running in debug mode which is manually + * triggered by a tester or a script. + */ + if (!dpcd || (offset == 0xffff)) + DP_INFO("[%s]\n", "CLEAR"); + else + DP_INFO("[%s]\n", "SET"); + } + + mutex_unlock(&debug->lock); + + debug->aux->dpcd_updated(debug->aux); + return rc; +} + +static ssize_t dp_debug_read_dpcd(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + int const buf_size = SZ_4K; + u32 offset = 0; + u32 len = 0; + bool notify = false; + + if (!debug || !debug->aux || !debug->dpcd) + return -ENODEV; + + mutex_lock(&debug->lock); + if (*ppos) + goto end; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + goto end; + + len += snprintf(buf, buf_size, "0x%x", debug->aux->reg); + + if (!debug->aux->read) { + while (1) { + if (debug->aux->reg + offset >= buf_size || + offset >= debug->aux->size) + break; + + len += snprintf(buf + len, buf_size - len, "0x%x", + debug->dpcd[debug->aux->reg + offset++]); + } + + notify = true; + } + + len = min_t(size_t, count, len); + if (!copy_to_user(user_buff, buf, len)) + *ppos += len; + + kfree(buf); +end: + mutex_unlock(&debug->lock); + + if (notify) + debug->aux->dpcd_updated(debug->aux); + + return len; +} + +static ssize_t dp_debug_write_hpd(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + int const hpd_data_mask = 0x7; + int hpd = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &hpd) != 0) + goto end; + + hpd &= hpd_data_mask; + debug->hotplug = !!(hpd & BIT(0)); + + debug->dp_debug.psm_enabled = !!(hpd & BIT(1)); + + /* + * print hotplug value as this code is executed + * only while running in debug mode which is manually + * triggered by a tester or a script. + */ + DP_INFO("%s\n", debug->hotplug ? "[CONNECT]" : "[DISCONNECT]"); + + debug->hpd->simulate_connect(debug->hpd, debug->hotplug); +end: + return len; +} + +static ssize_t dp_debug_write_edid_modes(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_32]; + size_t len = 0; + int hdisplay = 0, vdisplay = 0, vrefresh = 0, aspect_ratio; + + if (!debug) + return -ENODEV; + + if (*ppos) + goto end; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto clear; + + buf[len] = '\0'; + + if (sscanf(buf, "%d %d %d %d", &hdisplay, &vdisplay, &vrefresh, + &aspect_ratio) != 4) + goto clear; + + if (!hdisplay || !vdisplay || !vrefresh) + goto clear; + + debug->dp_debug.debug_en = true; + debug->dp_debug.hdisplay = hdisplay; + debug->dp_debug.vdisplay = vdisplay; + debug->dp_debug.vrefresh = vrefresh; + debug->dp_debug.aspect_ratio = aspect_ratio; + goto end; +clear: + DP_DEBUG("clearing debug modes\n"); + debug->dp_debug.debug_en = false; +end: + return len; +} + +static ssize_t dp_debug_write_edid_modes_mst(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + struct dp_mst_connector *mst_connector; + char buf[SZ_512]; + char *read_buf; + size_t len = 0; + + int hdisplay = 0, vdisplay = 0, vrefresh = 0, aspect_ratio = 0; + int con_id = 0, offset = 0, debug_en = 0; + bool in_list = false; + + if (!debug) + return -ENODEV; + + if (*ppos) + goto end; + + len = min_t(size_t, count, SZ_512 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + read_buf = buf; + + mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock); + while (sscanf(read_buf, "%d %d %d %d %d %d%n", &debug_en, &con_id, + &hdisplay, &vdisplay, &vrefresh, &aspect_ratio, + &offset) == 6) { + list_for_each_entry(mst_connector, + &debug->dp_debug.dp_mst_connector_list.list, + list) { + if (mst_connector->con_id == con_id) { + in_list = true; + mst_connector->debug_en = (bool) debug_en; + mst_connector->hdisplay = hdisplay; + mst_connector->vdisplay = vdisplay; + mst_connector->vrefresh = vrefresh; + mst_connector->aspect_ratio = aspect_ratio; + } + } + + if (!in_list) + DP_DEBUG("dp connector id %d is invalid\n", con_id); + + in_list = false; + read_buf += offset; + } + mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); +end: + return len; +} + +static ssize_t dp_debug_write_mst_con_id(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + struct dp_mst_connector *mst_connector; + char buf[SZ_32]; + size_t len = 0; + int con_id = 0, status; + bool in_list = false; + const int dp_en = BIT(3), hpd_high = BIT(7), hpd_irq = BIT(8); + int vdo = dp_en | hpd_high | hpd_irq; + + if (!debug) + return -ENODEV; + + if (*ppos) + goto end; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto clear; + + buf[len] = '\0'; + + if (sscanf(buf, "%d %d", &con_id, &status) != 2) { + len = 0; + goto end; + } + + if (!con_id) + goto clear; + + /* Verify that the connector id is for a valid mst connector. */ + mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock); + list_for_each_entry(mst_connector, + &debug->dp_debug.dp_mst_connector_list.list, list) { + if (mst_connector->con_id == con_id) { + in_list = true; + debug->mst_con_id = con_id; + mst_connector->state = status; + break; + } + } + mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); + + if (!in_list) + DP_ERR("invalid connector id %u\n", con_id); + else if (status != connector_status_unknown) { + debug->dp_debug.mst_hpd_sim = true; + debug->hpd->simulate_attention(debug->hpd, vdo); + } + + goto end; +clear: + DP_DEBUG("clearing mst_con_id\n"); + debug->mst_con_id = 0; +end: + return len; +} + +static ssize_t dp_debug_write_mst_con_add(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_32]; + size_t len = 0; + const int dp_en = BIT(3), hpd_high = BIT(7), hpd_irq = BIT(8); + int vdo = dp_en | hpd_high | hpd_irq; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + debug->dp_debug.mst_hpd_sim = true; + debug->dp_debug.mst_sim_add_con = true; + debug->hpd->simulate_attention(debug->hpd, vdo); +end: + return len; +} + +static ssize_t dp_debug_write_mst_con_remove(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + struct dp_mst_connector *mst_connector; + char buf[SZ_32]; + size_t len = 0; + int con_id = 0; + bool in_list = false; + const int dp_en = BIT(3), hpd_high = BIT(7), hpd_irq = BIT(8); + int vdo = dp_en | hpd_high | hpd_irq; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (sscanf(buf, "%d", &con_id) != 1) { + len = 0; + goto end; + } + + if (!con_id) + goto end; + + /* Verify that the connector id is for a valid mst connector. */ + mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock); + list_for_each_entry(mst_connector, + &debug->dp_debug.dp_mst_connector_list.list, list) { + if (mst_connector->con_id == con_id) { + in_list = true; + break; + } + } + mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); + + if (!in_list) { + DRM_ERROR("invalid connector id %u\n", con_id); + goto end; + } + + debug->dp_debug.mst_hpd_sim = true; + debug->dp_debug.mst_sim_remove_con = true; + debug->dp_debug.mst_sim_remove_con_id = con_id; + debug->hpd->simulate_attention(debug->hpd, vdo); +end: + return len; +} + +static ssize_t dp_debug_bw_code_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 max_bw_code = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return 0; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &max_bw_code) != 0) + return 0; + + if (!is_link_rate_valid(max_bw_code)) { + DP_ERR("Unsupported bw code %d\n", max_bw_code); + return len; + } + debug->panel->max_bw_code = max_bw_code; + DP_DEBUG("max_bw_code: %d\n", max_bw_code); + + return len; +} + +static ssize_t dp_debug_mst_mode_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[64]; + ssize_t len; + + len = scnprintf(buf, sizeof(buf), + "mst_mode = %d, mst_state = %d\n", + debug->parser->has_mst, + debug->panel->mst_state); + + return simple_read_from_buffer(user_buff, count, ppos, buf, len); +} + +static ssize_t dp_debug_mst_mode_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 mst_mode = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return 0; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &mst_mode) != 0) + return 0; + + debug->parser->has_mst = mst_mode ? true : false; + DP_DEBUG("mst_enable: %d\n", mst_mode); + + return len; +} + +static ssize_t dp_debug_max_pclk_khz_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 max_pclk = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return 0; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &max_pclk) != 0) + return 0; + + if (max_pclk > debug->parser->max_pclk_khz) + DP_ERR("requested: %d, max_pclk_khz:%d\n", max_pclk, + debug->parser->max_pclk_khz); + else + debug->dp_debug.max_pclk_khz = max_pclk; + + DP_DEBUG("max_pclk_khz: %d\n", max_pclk); + + return len; +} + +static ssize_t dp_debug_max_pclk_khz_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + len += snprintf(buf + len, (SZ_4K - len), + "max_pclk_khz = %d, org: %d\n", + debug->dp_debug.max_pclk_khz, + debug->parser->max_pclk_khz); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static ssize_t dp_debug_mst_sideband_mode_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + int mst_sideband_mode = 0; + u32 mst_port_cnt = 0; + + if (!debug) + return -ENODEV; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (sscanf(buf, "%d %u", &mst_sideband_mode, &mst_port_cnt) != 2) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (mst_port_cnt > DP_MST_SIM_MAX_PORTS) { + DP_ERR("port cnt:%d exceeding max:%d\n", mst_port_cnt, + DP_MST_SIM_MAX_PORTS); + return -EINVAL; + } + + debug->parser->has_mst_sideband = mst_sideband_mode ? true : false; + debug->dp_debug.mst_port_cnt = mst_port_cnt; + DP_DEBUG("mst_sideband_mode: %d port_cnt:%d\n", + mst_sideband_mode, mst_port_cnt); + return count; +} + +static ssize_t dp_debug_widebus_mode_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 widebus_mode = 0; + + if (!debug || !debug->parser) + return -ENODEV; + + if (*ppos) + return 0; + + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &widebus_mode) != 0) + return -EINVAL; + + debug->parser->has_widebus = widebus_mode ? true : false; + DP_DEBUG("widebus_enable: %d\n", widebus_mode); + + return len; +} + +static ssize_t dp_debug_tpg_write(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + u32 tpg_state = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto bail; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &tpg_state) != 0) + goto bail; + + tpg_state &= 0x1; + DP_DEBUG("tpg_state: %d\n", tpg_state); + + if (tpg_state == debug->dp_debug.tpg_state) + goto bail; + + if (debug->panel) + debug->panel->tpg_config(debug->panel, tpg_state); + + debug->dp_debug.tpg_state = tpg_state; +bail: + return len; +} + +static ssize_t dp_debug_write_exe_mode(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_32]; + size_t len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (sscanf(buf, "%3s", debug->exe_mode) != 1) + goto end; + + if (strcmp(debug->exe_mode, "hw") && + strcmp(debug->exe_mode, "sw") && + strcmp(debug->exe_mode, "all")) + goto end; + + debug->catalog->set_exe_mode(debug->catalog, debug->exe_mode); +end: + return len; +} + +static ssize_t dp_debug_read_connected(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len += snprintf(buf, SZ_8, "%d\n", debug->hpd->hpd_high); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) + return -EFAULT; + + *ppos += len; + return len; +} + +static ssize_t dp_debug_write_hdcp(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + int hdcp = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &hdcp) != 0) + goto end; + + debug->dp_debug.hdcp_disabled = !hdcp; +end: + return len; +} + +static ssize_t dp_debug_read_hdcp(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len = sizeof(debug->dp_debug.hdcp_status); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, debug->dp_debug.hdcp_status, len)) + return -EFAULT; + + *ppos += len; + return len; +} + +static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len) +{ + if (rc >= *max_size) { + DP_ERR("buffer overflow\n"); + return -EINVAL; + } + *len += rc; + *max_size = SZ_4K - *len; + + return 0; +} + +static ssize_t dp_debug_read_edid_modes(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0, ret = 0, max_size = SZ_4K; + int rc = 0; + struct drm_connector *connector; + struct drm_display_mode *mode; + + if (!debug) { + DP_ERR("invalid data\n"); + rc = -ENODEV; + goto error; + } + + connector = *debug->connector; + + if (!connector) { + DP_ERR("connector is NULL\n"); + rc = -EINVAL; + goto error; + } + + if (*ppos) + goto error; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) { + rc = -ENOMEM; + goto error; + } + + mutex_lock(&connector->dev->mode_config.mutex); + list_for_each_entry(mode, &connector->modes, head) { + ret = snprintf(buf + len, max_size, + "%s %d %d %d %d %d 0x%x\n", + mode->name, mode->vrefresh, mode->picture_aspect_ratio, + mode->htotal, mode->vtotal, mode->clock, mode->flags); + if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) + break; + } + mutex_unlock(&connector->dev->mode_config.mutex); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + rc = -EFAULT; + goto error; + } + + *ppos += len; + kfree(buf); + + return len; +error: + return rc; +} + +static ssize_t dp_debug_read_edid_modes_mst(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + struct dp_mst_connector *mst_connector; + char *buf; + u32 len = 0, ret = 0, max_size = SZ_4K; + int rc = 0; + struct drm_connector *connector; + struct drm_display_mode *mode; + bool in_list = false; + + if (!debug) { + DP_ERR("invalid data\n"); + rc = -ENODEV; + goto error; + } + + mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock); + list_for_each_entry(mst_connector, + &debug->dp_debug.dp_mst_connector_list.list, list) { + if (mst_connector->con_id == debug->mst_con_id) { + connector = mst_connector->conn; + in_list = true; + } + } + mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); + + if (!in_list) { + DP_ERR("connector %u not in mst list\n", debug->mst_con_id); + rc = -EINVAL; + goto error; + } + + if (!connector) { + DP_ERR("connector is NULL\n"); + rc = -EINVAL; + goto error; + } + + if (*ppos) + goto error; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto error; + } + + mutex_lock(&connector->dev->mode_config.mutex); + list_for_each_entry(mode, &connector->modes, head) { + ret = snprintf(buf + len, max_size, + "%s %d %d %d %d %d 0x%x\n", + mode->name, mode->vrefresh, + mode->picture_aspect_ratio, mode->htotal, + mode->vtotal, mode->clock, mode->flags); + if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) + break; + } + mutex_unlock(&connector->dev->mode_config.mutex); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + rc = -EFAULT; + goto error; + } + + *ppos += len; + kfree(buf); + + return len; +error: + return rc; +} + +static ssize_t dp_debug_read_mst_con_id(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0, ret = 0, max_size = SZ_4K; + int rc = 0; + + if (!debug) { + DP_ERR("invalid data\n"); + rc = -ENODEV; + goto error; + } + + if (*ppos) + goto error; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto error; + } + + ret = snprintf(buf, max_size, "%u\n", debug->mst_con_id); + len += ret; + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + rc = -EFAULT; + goto error; + } + + *ppos += len; + kfree(buf); + + return len; +error: + return rc; +} + +static ssize_t dp_debug_read_mst_conn_info(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + struct dp_mst_connector *mst_connector; + char *buf; + u32 len = 0, ret = 0, max_size = SZ_4K; + int rc = 0; + struct drm_connector *connector; + + if (!debug) { + DP_ERR("invalid data\n"); + rc = -ENODEV; + goto error; + } + + if (*ppos) + goto error; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto error; + } + + mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock); + list_for_each_entry(mst_connector, + &debug->dp_debug.dp_mst_connector_list.list, list) { + /* Do not print info for head node */ + if (mst_connector->con_id == -1) + continue; + + connector = mst_connector->conn; + + if (!connector) { + DP_ERR("connector for id %d is NULL\n", + mst_connector->con_id); + continue; + } + + ret = scnprintf(buf + len, max_size, + "conn name:%s, conn id:%d state:%d\n", + connector->name, connector->base.id, + connector->status); + if (dp_debug_check_buffer_overflow(ret, &max_size, &len)) + break; + } + mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + rc = -EFAULT; + goto error; + } + + *ppos += len; + kfree(buf); + + return len; +error: + return rc; +} + +static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, + size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0, rc = 0; + u32 max_size = SZ_4K; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "\tlink_rate=%u\n", + debug->panel->link_info.rate); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "\tnum_lanes=%u\n", + debug->panel->link_info.num_lanes); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "\tresolution=%dx%d@%dHz\n", + debug->panel->pinfo.h_active, + debug->panel->pinfo.v_active, + debug->panel->pinfo.refresh_rate); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "\tpclock=%dKHz\n", + debug->panel->pinfo.pixel_clk_khz); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "\tbpp=%d\n", + debug->panel->pinfo.bpp); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + /* Link Information */ + rc = snprintf(buf + len, max_size, "\ttest_req=%s\n", + dp_link_get_test_name(debug->link->sink_request)); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tlane_count=%d\n", debug->link->link_params.lane_count); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tbw_code=%d\n", debug->link->link_params.bw_code); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tv_level=%d\n", debug->link->phy_params.v_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "\tp_level=%d\n", debug->link->phy_params.p_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) + goto error; + + *ppos += len; + + kfree(buf); + return len; +error: + kfree(buf); + return -EINVAL; +} + +static ssize_t dp_debug_bw_code_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + len += snprintf(buf + len, (SZ_4K - len), + "max_bw_code = %d\n", debug->panel->max_bw_code); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static ssize_t dp_debug_tpg_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + u32 len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + len += snprintf(buf, SZ_8, "%d\n", debug->dp_debug.tpg_state); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) + return -EFAULT; + + *ppos += len; + return len; +} + +static int dp_debug_print_hdr_params_to_buf(struct drm_connector *connector, + char *buf, u32 size) +{ + int rc; + u32 i, len = 0, max_size = size; + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct drm_msm_ext_hdr_metadata *hdr; + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + + hdr = &c_state->hdr_meta; + + rc = snprintf(buf + len, max_size, + "============SINK HDR PARAMETERS===========\n"); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "eotf = %d\n", + connector->hdr_eotf); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "type_one = %d\n", + connector->hdr_metadata_type_one); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "hdr_plus_app_ver = %d\n", + connector->hdr_plus_app_ver); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "max_luminance = %d\n", + connector->hdr_max_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "avg_luminance = %d\n", + connector->hdr_avg_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "min_luminance = %d\n", + connector->hdr_min_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, + "============VIDEO HDR PARAMETERS===========\n"); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "hdr_state = %d\n", hdr->hdr_state); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "hdr_supported = %d\n", + hdr->hdr_supported); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "eotf = %d\n", hdr->eotf); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "white_point_x = %d\n", + hdr->white_point_x); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "white_point_y = %d\n", + hdr->white_point_y); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "max_luminance = %d\n", + hdr->max_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "min_luminance = %d\n", + hdr->min_luminance); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "max_content_light_level = %d\n", + hdr->max_content_light_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "min_content_light_level = %d\n", + hdr->max_average_light_level); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + for (i = 0; i < HDR_PRIMARIES_COUNT; i++) { + rc = snprintf(buf + len, max_size, "primaries_x[%d] = %d\n", + i, hdr->display_primaries_x[i]); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + + rc = snprintf(buf + len, max_size, "primaries_y[%d] = %d\n", + i, hdr->display_primaries_y[i]); + if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) + goto error; + } + + if (hdr->hdr_plus_payload && hdr->hdr_plus_payload_size) { + u32 rowsize = 16, rem; + struct sde_connector_dyn_hdr_metadata *dhdr = + &c_state->dyn_hdr_meta; + + /** + * Do not use user pointer from hdr->hdr_plus_payload directly, + * instead use kernel's cached copy of payload data. + */ + for (i = 0; i < dhdr->dynamic_hdr_payload_size; i += rowsize) { + rc = snprintf(buf + len, max_size, "DHDR: "); + if (dp_debug_check_buffer_overflow(rc, &max_size, + &len)) + goto error; + + rem = dhdr->dynamic_hdr_payload_size - i; + rc = hex_dump_to_buffer(&dhdr->dynamic_hdr_payload[i], + min(rowsize, rem), rowsize, 1, buf + len, + max_size, false); + if (dp_debug_check_buffer_overflow(rc, &max_size, + &len)) + goto error; + + rc = snprintf(buf + len, max_size, "\n"); + if (dp_debug_check_buffer_overflow(rc, &max_size, + &len)) + goto error; + } + } + + return len; +error: + return -EOVERFLOW; +} + +static ssize_t dp_debug_read_hdr(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf = NULL; + u32 len = 0; + u32 max_size = SZ_4K; + struct drm_connector *connector; + + if (!debug) { + DP_ERR("invalid data\n"); + return -ENODEV; + } + + connector = *debug->connector; + + if (!connector) { + DP_ERR("connector is NULL\n"); + return -EINVAL; + } + + if (*ppos) + return 0; + + buf = kzalloc(max_size, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + len = dp_debug_print_hdr_params_to_buf(connector, buf, max_size); + if (len == -EOVERFLOW) { + kfree(buf); + return len; + } + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static ssize_t dp_debug_read_hdr_mst(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char *buf = NULL; + u32 len = 0, max_size = SZ_4K; + struct dp_mst_connector *mst_connector; + struct drm_connector *connector; + bool in_list = false; + + if (!debug) { + DP_ERR("invalid data\n"); + return -ENODEV; + } + + mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock); + list_for_each_entry(mst_connector, + &debug->dp_debug.dp_mst_connector_list.list, list) { + if (mst_connector->con_id == debug->mst_con_id) { + connector = mst_connector->conn; + in_list = true; + } + } + mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock); + + if (!in_list) { + DP_ERR("connector %u not in mst list\n", debug->mst_con_id); + return -EINVAL; + } + + if (!connector) { + DP_ERR("connector is NULL\n"); + return -EINVAL; + } + + if (*ppos) + return 0; + + + buf = kzalloc(max_size, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + len = dp_debug_print_hdr_params_to_buf(connector, buf, max_size); + if (len == -EOVERFLOW) { + kfree(buf); + return len; + } + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim) +{ + if (sim) { + if (dp_debug_get_edid_buf(debug)) + return; + + if (dp_debug_get_dpcd_buf(debug)) { + devm_kfree(debug->dev, debug->edid); + debug->edid = NULL; + return; + } + + debug->dp_debug.sim_mode = true; + debug->aux->set_sim_mode(debug->aux, true, + debug->edid, debug->dpcd); + } else { + if (debug->hotplug) { + DP_WARN("sim mode off before hotplug disconnect\n"); + debug->hpd->simulate_connect(debug->hpd, false); + debug->hotplug = false; + } + debug->aux->abort(debug->aux, true); + debug->ctrl->abort(debug->ctrl, true); + + debug->aux->set_sim_mode(debug->aux, false, NULL, NULL); + debug->dp_debug.sim_mode = false; + + debug->panel->set_edid(debug->panel, 0); + if (debug->edid) { + devm_kfree(debug->dev, debug->edid); + debug->edid = NULL; + } + + debug->panel->set_dpcd(debug->panel, 0); + if (debug->dpcd) { + devm_kfree(debug->dev, debug->dpcd); + debug->dpcd = NULL; + } + } + + /* + * print simulation status as this code is executed + * only while running in debug mode which is manually + * triggered by a tester or a script. + */ + DP_INFO("%s\n", sim ? "[ON]" : "[OFF]"); +} + +static ssize_t dp_debug_write_sim(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + int sim; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + mutex_lock(&debug->lock); + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &sim) != 0) + goto end; + + dp_debug_set_sim_mode(debug, sim); +end: + mutex_unlock(&debug->lock); + return len; +} + +static ssize_t dp_debug_write_attention(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_8]; + size_t len = 0; + int vdo; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_8 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (kstrtoint(buf, 10, &vdo) != 0) + goto end; + + debug->hpd->simulate_attention(debug->hpd, vdo); +end: + return len; +} + +static ssize_t dp_debug_write_dump(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dp_debug_private *debug = file->private_data; + char buf[SZ_32]; + size_t len = 0; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (sscanf(buf, "%31s", debug->reg_dump) != 1) + goto end; + + /* qfprom register dump not supported */ + if (!strcmp(debug->reg_dump, "qfprom_physical")) + strlcpy(debug->reg_dump, "clear", sizeof(debug->reg_dump)); +end: + return len; +} + +static ssize_t dp_debug_read_dump(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + int rc = 0; + struct dp_debug_private *debug = file->private_data; + u8 *buf = NULL; + u32 len = 0; + char prefix[SZ_32]; + + if (!debug) + return -ENODEV; + + if (*ppos) + return 0; + + if (!debug->hpd->hpd_high || !strlen(debug->reg_dump)) + goto end; + + rc = debug->catalog->get_reg_dump(debug->catalog, + debug->reg_dump, &buf, &len); + if (rc) + goto end; + + snprintf(prefix, sizeof(prefix), "%s: ", debug->reg_dump); + print_hex_dump(KERN_DEBUG, prefix, DUMP_PREFIX_NONE, + 16, 4, buf, len, false); + + len = min_t(size_t, count, len); + if (copy_to_user(user_buff, buf, len)) + return -EFAULT; + + *ppos += len; +end: + return len; +} + +static const struct file_operations dp_debug_fops = { + .open = simple_open, + .read = dp_debug_read_info, +}; + +static const struct file_operations edid_modes_fops = { + .open = simple_open, + .read = dp_debug_read_edid_modes, + .write = dp_debug_write_edid_modes, +}; + +static const struct file_operations edid_modes_mst_fops = { + .open = simple_open, + .read = dp_debug_read_edid_modes_mst, + .write = dp_debug_write_edid_modes_mst, +}; + +static const struct file_operations mst_conn_info_fops = { + .open = simple_open, + .read = dp_debug_read_mst_conn_info, +}; + +static const struct file_operations mst_con_id_fops = { + .open = simple_open, + .read = dp_debug_read_mst_con_id, + .write = dp_debug_write_mst_con_id, +}; + +static const struct file_operations mst_con_add_fops = { + .open = simple_open, + .write = dp_debug_write_mst_con_add, +}; + +static const struct file_operations mst_con_remove_fops = { + .open = simple_open, + .write = dp_debug_write_mst_con_remove, +}; + +static const struct file_operations hpd_fops = { + .open = simple_open, + .write = dp_debug_write_hpd, +}; + +static const struct file_operations edid_fops = { + .open = simple_open, + .write = dp_debug_write_edid, +}; + +static const struct file_operations dpcd_fops = { + .open = simple_open, + .write = dp_debug_write_dpcd, + .read = dp_debug_read_dpcd, +}; + +static const struct file_operations connected_fops = { + .open = simple_open, + .read = dp_debug_read_connected, +}; + +static const struct file_operations bw_code_fops = { + .open = simple_open, + .read = dp_debug_bw_code_read, + .write = dp_debug_bw_code_write, +}; +static const struct file_operations exe_mode_fops = { + .open = simple_open, + .write = dp_debug_write_exe_mode, +}; + +static const struct file_operations tpg_fops = { + .open = simple_open, + .read = dp_debug_tpg_read, + .write = dp_debug_tpg_write, +}; + +static const struct file_operations hdr_fops = { + .open = simple_open, + .read = dp_debug_read_hdr, +}; + +static const struct file_operations hdr_mst_fops = { + .open = simple_open, + .read = dp_debug_read_hdr_mst, +}; + +static const struct file_operations sim_fops = { + .open = simple_open, + .write = dp_debug_write_sim, +}; + +static const struct file_operations attention_fops = { + .open = simple_open, + .write = dp_debug_write_attention, +}; + +static const struct file_operations dump_fops = { + .open = simple_open, + .write = dp_debug_write_dump, + .read = dp_debug_read_dump, +}; + +static const struct file_operations mst_mode_fops = { + .open = simple_open, + .write = dp_debug_mst_mode_write, + .read = dp_debug_mst_mode_read, +}; + +static const struct file_operations mst_sideband_mode_fops = { + .open = simple_open, + .write = dp_debug_mst_sideband_mode_write, +}; + +static const struct file_operations max_pclk_khz_fops = { + .open = simple_open, + .write = dp_debug_max_pclk_khz_write, + .read = dp_debug_max_pclk_khz_read, +}; + +static const struct file_operations hdcp_fops = { + .open = simple_open, + .write = dp_debug_write_hdcp, + .read = dp_debug_read_hdcp, +}; + +static const struct file_operations widebus_mode_fops = { + .open = simple_open, + .write = dp_debug_widebus_mode_write, +}; + +static int dp_debug_init(struct dp_debug *dp_debug) +{ + int rc = 0; + struct dp_debug_private *debug = container_of(dp_debug, + struct dp_debug_private, dp_debug); + struct dentry *dir, *file; + + if (!IS_ENABLED(CONFIG_DEBUG_FS)) { + DP_WARN("Not creating debug root dir."); + debug->root = NULL; + return 0; + } + + dir = debugfs_create_dir(DEBUG_NAME, NULL); + if (IS_ERR_OR_NULL(dir)) { + if (!dir) + rc = -EINVAL; + else + rc = PTR_ERR(dir); + DP_ERR("[%s] debugfs create dir failed, rc = %d\n", + DEBUG_NAME, rc); + goto error; + } + + debug->root = dir; + + file = debugfs_create_file("dp_debug", 0444, dir, + debug, &dp_debug_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs create file failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("edid_modes", 0644, dir, + debug, &edid_modes_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs create edid_modes failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("edid_modes_mst", 0644, dir, + debug, &edid_modes_mst_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs create edid_modes_mst failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("mst_con_id", 0644, dir, + debug, &mst_con_id_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs create mst_con_id failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("mst_con_info", 0644, dir, + debug, &mst_conn_info_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs create mst_conn_info failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("mst_con_add", 0644, dir, + debug, &mst_con_add_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DRM_ERROR("[%s] debugfs create mst_con_add failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("mst_con_remove", 0644, dir, + debug, &mst_con_remove_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DRM_ERROR("[%s] debugfs create mst_con_remove failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("hpd", 0644, dir, + debug, &hpd_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs hpd failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("connected", 0444, dir, + debug, &connected_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs connected failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("max_bw_code", 0644, dir, + debug, &bw_code_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs max_bw_code failed, rc=%d\n", + DEBUG_NAME, rc); + } + + file = debugfs_create_file("exe_mode", 0644, dir, + debug, &exe_mode_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs register failed, rc=%d\n", + DEBUG_NAME, rc); + } + + file = debugfs_create_file("edid", 0644, dir, + debug, &edid_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs edid failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("dpcd", 0644, dir, + debug, &dpcd_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs dpcd failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("tpg_ctrl", 0644, dir, + debug, &tpg_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs tpg failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("hdr", 0400, dir, + debug, &hdr_fops); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs hdr failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("hdr_mst", 0400, dir, + debug, &hdr_mst_fops); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs hdr_mst failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("sim", 0644, dir, + debug, &sim_fops); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs sim failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("attention", 0644, dir, + debug, &attention_fops); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs attention failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("dump", 0644, dir, + debug, &dump_fops); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs dump failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("mst_mode", 0644, dir, + debug, &mst_mode_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs max_bw_code failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("mst_sideband_mode", 0644, dir, + debug, &mst_sideband_mode_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs max_bw_code failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("max_pclk_khz", 0644, dir, + debug, &max_pclk_khz_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs max_pclk_khz failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_bool("force_encryption", 0644, dir, + &debug->dp_debug.force_encryption); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs force_encryption failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_file("hdcp", 0644, dir, + debug, &hdcp_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs hdcp failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_bool("hdcp_wait_sink_sync", 0644, dir, + &debug->dp_debug.hdcp_wait_sink_sync); + + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs hdcp_wait_sink_sync failed, rc=%d\n", + DEBUG_NAME, rc); + goto error_remove_dir; + } + + file = debugfs_create_bool("dsc_feature_enable", 0644, dir, + &debug->parser->dsc_feature_enable); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs dsc_feature failed, rc=%d\n", + DEBUG_NAME, rc); + } + + file = debugfs_create_bool("fec_feature_enable", 0644, dir, + &debug->parser->fec_feature_enable); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs fec_feature_enable failed, rc=%d\n", + DEBUG_NAME, rc); + } + + file = debugfs_create_file("widebus_mode", 0644, dir, + debug, &widebus_mode_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs widebus failed, rc=%d\n", + DEBUG_NAME, rc); + } + + file = debugfs_create_u32("max_lclk_khz", 0644, dir, + &debug->parser->max_lclk_khz); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + DP_ERR("[%s] debugfs max_lclk_khz failed, rc=%d\n", + DEBUG_NAME, rc); + } + + return 0; + +error_remove_dir: + if (!file) + rc = -EINVAL; + debugfs_remove_recursive(dir); +error: + return rc; +} + +u8 *dp_debug_get_edid(struct dp_debug *dp_debug) +{ + struct dp_debug_private *debug; + + if (!dp_debug) + return NULL; + + debug = container_of(dp_debug, struct dp_debug_private, dp_debug); + + return debug->edid; +} + +static void dp_debug_abort(struct dp_debug *dp_debug) +{ + struct dp_debug_private *debug; + + if (!dp_debug) + return; + + debug = container_of(dp_debug, struct dp_debug_private, dp_debug); + + mutex_lock(&debug->lock); + dp_debug_set_sim_mode(debug, false); + mutex_unlock(&debug->lock); +} + +struct dp_debug *dp_debug_get(struct dp_debug_in *in) +{ + int rc = 0; + struct dp_debug_private *debug; + struct dp_debug *dp_debug; + + if (!in->dev || !in->panel || !in->hpd || !in->link || + !in->catalog || !in->ctrl) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + debug = devm_kzalloc(in->dev, sizeof(*debug), GFP_KERNEL); + if (!debug) { + rc = -ENOMEM; + goto error; + } + + debug->dp_debug.debug_en = false; + debug->hpd = in->hpd; + debug->link = in->link; + debug->panel = in->panel; + debug->aux = in->aux; + debug->dev = in->dev; + debug->connector = in->connector; + debug->catalog = in->catalog; + debug->parser = in->parser; + debug->ctrl = in->ctrl; + + dp_debug = &debug->dp_debug; + dp_debug->vdisplay = 0; + dp_debug->hdisplay = 0; + dp_debug->vrefresh = 0; + + mutex_init(&debug->lock); + + rc = dp_debug_init(dp_debug); + if (rc) { + devm_kfree(in->dev, debug); + goto error; + } + + debug->aux->access_lock = &debug->lock; + dp_debug->get_edid = dp_debug_get_edid; + dp_debug->abort = dp_debug_abort; + + INIT_LIST_HEAD(&dp_debug->dp_mst_connector_list.list); + + /* + * Do not associate the head of the list with any connector in order to + * maintain backwards compatibility with the SST use case. + */ + dp_debug->dp_mst_connector_list.con_id = -1; + dp_debug->dp_mst_connector_list.conn = NULL; + dp_debug->dp_mst_connector_list.debug_en = false; + + dp_debug->max_pclk_khz = debug->parser->max_pclk_khz; + + return dp_debug; +error: + return ERR_PTR(rc); +} + +static int dp_debug_deinit(struct dp_debug *dp_debug) +{ + struct dp_debug_private *debug; + + if (!dp_debug) + return -EINVAL; + + debug = container_of(dp_debug, struct dp_debug_private, dp_debug); + + debugfs_remove_recursive(debug->root); + + return 0; +} + +void dp_debug_put(struct dp_debug *dp_debug) +{ + struct dp_debug_private *debug; + + if (!dp_debug) + return; + + debug = container_of(dp_debug, struct dp_debug_private, dp_debug); + + dp_debug_deinit(dp_debug); + + mutex_destroy(&debug->lock); + + if (debug->edid) + devm_kfree(debug->dev, debug->edid); + + if (debug->dpcd) + devm_kfree(debug->dev, debug->dpcd); + + devm_kfree(debug->dev, debug); +} diff --git a/techpack/display/msm/dp/dp_debug.h b/techpack/display/msm/dp/dp_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..aa239be382b809714446b70f3ff6fb9c5eba5d2a --- /dev/null +++ b/techpack/display/msm/dp/dp_debug.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_DEBUG_H_ +#define _DP_DEBUG_H_ + +#include "dp_panel.h" +#include "dp_ctrl.h" +#include "dp_link.h" +#include "dp_usbpd.h" +#include "dp_aux.h" +#include "dp_display.h" + +#define DP_DEBUG(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_KMS)) \ + DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \ + ##__VA_ARGS__); \ + else \ + pr_debug("[drm:%s][msm-dp-debug][%-4d]"fmt, __func__,\ + current->pid, ##__VA_ARGS__); \ + } while (0) + +#define DP_INFO(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_KMS)) \ + DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \ + ##__VA_ARGS__); \ + else \ + pr_info("[drm:%s][msm-dp-info][%-4d]"fmt, __func__, \ + current->pid, ##__VA_ARGS__); \ + } while (0) + +#define DP_WARN(fmt, ...) \ + pr_warn("[drm:%s][msm-dp-warn][%-4d]"fmt, __func__, \ + current->pid, ##__VA_ARGS__) + +#define DP_ERR(fmt, ...) \ + pr_err("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \ + current->pid, ##__VA_ARGS__) + +/** + * struct dp_debug + * @debug_en: specifies whether debug mode enabled + * @sim_mode: specifies whether sim mode enabled + * @psm_enabled: specifies whether psm enabled + * @hdcp_disabled: specifies if hdcp is disabled + * @hdcp_wait_sink_sync: used to wait for sink synchronization before HDCP auth + * @aspect_ratio: used to filter out aspect_ratio value + * @vdisplay: used to filter out vdisplay value + * @hdisplay: used to filter out hdisplay value + * @vrefresh: used to filter out vrefresh value + * @tpg_state: specifies whether tpg feature is enabled + * @max_pclk_khz: max pclk supported + * @force_encryption: enable/disable forced encryption for HDCP 2.2 + * @hdcp_status: string holding hdcp status information + * @dp_mst_connector_list: list containing all dp mst connectors + * @mst_hpd_sim: specifies whether simulated hpd enabled + * @mst_sim_add_con: specifies whether new sim connector is to be added + * @mst_sim_remove_con: specifies whether sim connector is to be removed + * @mst_sim_remove_con_id: specifies id of sim connector to be removed + * @mst_port_cnt: number of mst ports to be added during hpd + */ +struct dp_debug { + bool debug_en; + bool sim_mode; + bool psm_enabled; + bool hdcp_disabled; + bool hdcp_wait_sink_sync; + int aspect_ratio; + int vdisplay; + int hdisplay; + int vrefresh; + bool tpg_state; + u32 max_pclk_khz; + bool force_encryption; + char hdcp_status[SZ_128]; + struct dp_mst_connector dp_mst_connector_list; + bool mst_hpd_sim; + bool mst_sim_add_con; + bool mst_sim_remove_con; + int mst_sim_remove_con_id; + u32 mst_port_cnt; + + u8 *(*get_edid)(struct dp_debug *dp_debug); + void (*abort)(struct dp_debug *dp_debug); +}; + +/** + * struct dp_debug_in + * @dev: device instance of the caller + * @panel: instance of panel module + * @hpd: instance of hpd module + * @link: instance of link module + * @aux: instance of aux module + * @connector: double pointer to display connector + * @catalog: instance of catalog module + * @parser: instance of parser module + */ +struct dp_debug_in { + struct device *dev; + struct dp_panel *panel; + struct dp_hpd *hpd; + struct dp_link *link; + struct dp_aux *aux; + struct drm_connector **connector; + struct dp_catalog *catalog; + struct dp_parser *parser; + struct dp_ctrl *ctrl; +}; + +/** + * dp_debug_get() - configure and get the DisplayPlot debug module data + * + * @in: input structure containing data to initialize the debug module + * return: pointer to allocated debug module data + * + * This function sets up the debug module and provides a way + * for debugfs input to be communicated with existing modules + */ +struct dp_debug *dp_debug_get(struct dp_debug_in *in); + +/** + * dp_debug_put() + * + * Cleans up dp_debug instance + * + * @dp_debug: instance of dp_debug + */ +void dp_debug_put(struct dp_debug *dp_debug); +#endif /* _DP_DEBUG_H_ */ diff --git a/techpack/display/msm/dp/dp_display.c b/techpack/display/msm/dp/dp_display.c new file mode 100644 index 0000000000000000000000000000000000000000..4823fe2e28503b40b0cb1d48ed6a75f3843229b4 --- /dev/null +++ b/techpack/display/msm/dp/dp_display.c @@ -0,0 +1,3282 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/component.h> +#include <linux/of_irq.h> +#include <linux/extcon.h> +#include <linux/soc/qcom/fsa4480-i2c.h> +#include <linux/usb/usbpd.h> + +#include "sde_connector.h" + +#include "msm_drv.h" +#include "dp_hpd.h" +#include "dp_parser.h" +#include "dp_power.h" +#include "dp_catalog.h" +#include "dp_aux.h" +#include "dp_link.h" +#include "dp_panel.h" +#include "dp_ctrl.h" +#include "dp_audio.h" +#include "dp_display.h" +#include "sde_hdcp.h" +#include "dp_debug.h" +#include "sde_dbg.h" + +#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) + +#define dp_display_state_show(x) { \ + DP_ERR("%s: state (0x%x): %s\n", x, dp->state, \ + dp_display_state_name(dp->state)); \ + SDE_EVT32_EXTERNAL(dp->state); } + +#define dp_display_state_log(x) { \ + DP_DEBUG("%s: state (0x%x): %s\n", x, dp->state, \ + dp_display_state_name(dp->state)); \ + SDE_EVT32_EXTERNAL(dp->state); } + +#define dp_display_state_is(x) (dp->state & (x)) +#define dp_display_state_add(x) { \ + (dp->state |= (x)); \ + dp_display_state_log("add "#x); } +#define dp_display_state_remove(x) { \ + (dp->state &= ~(x)); \ + dp_display_state_log("remove "#x); } + +enum dp_display_states { + DP_STATE_DISCONNECTED = 0, + DP_STATE_CONFIGURED = BIT(0), + DP_STATE_INITIALIZED = BIT(1), + DP_STATE_READY = BIT(2), + DP_STATE_CONNECTED = BIT(3), + DP_STATE_CONNECT_NOTIFIED = BIT(4), + DP_STATE_DISCONNECT_NOTIFIED = BIT(5), + DP_STATE_ENABLED = BIT(6), + DP_STATE_SUSPENDED = BIT(7), + DP_STATE_ABORTED = BIT(8), + DP_STATE_HDCP_ABORTED = BIT(9), + DP_STATE_SRC_PWRDN = BIT(10), +}; + +static char *dp_display_state_name(enum dp_display_states state) +{ + static char buf[SZ_1K]; + u32 len = 0; + + memset(buf, 0, SZ_1K); + + if (state & DP_STATE_CONFIGURED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "CONFIGURED"); + + if (state & DP_STATE_INITIALIZED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "INITIALIZED"); + + if (state & DP_STATE_READY) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "READY"); + + if (state & DP_STATE_CONNECTED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "CONNECTED"); + + if (state & DP_STATE_CONNECT_NOTIFIED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "CONNECT_NOTIFIED"); + + if (state & DP_STATE_DISCONNECT_NOTIFIED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "DISCONNECT_NOTIFIED"); + + if (state & DP_STATE_ENABLED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "ENABLED"); + + if (state & DP_STATE_SUSPENDED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "SUSPENDED"); + + if (state & DP_STATE_ABORTED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "ABORTED"); + + if (state & DP_STATE_HDCP_ABORTED) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "HDCP_ABORTED"); + + if (state & DP_STATE_SRC_PWRDN) + len += scnprintf(buf + len, sizeof(buf) - len, "|%s|", + "SRC_PWRDN"); + + if (!strlen(buf)) + return "DISCONNECTED"; + + return buf; +} + +static struct dp_display *g_dp_display; +#define HPD_STRING_SIZE 30 + +struct dp_hdcp_dev { + void *fd; + struct sde_hdcp_ops *ops; + enum sde_hdcp_version ver; +}; + +struct dp_hdcp { + void *data; + struct sde_hdcp_ops *ops; + + u32 source_cap; + + struct dp_hdcp_dev dev[HDCP_VERSION_MAX]; +}; + +struct dp_mst { + bool mst_active; + + bool drm_registered; + struct dp_mst_drm_cbs cbs; +}; + +struct dp_display_private { + char *name; + int irq; + + enum drm_connector_status cached_connector_status; + enum dp_display_states state; + + struct platform_device *pdev; + struct device_node *aux_switch_node; + struct dentry *root; + struct completion notification_comp; + + struct dp_hpd *hpd; + struct dp_parser *parser; + struct dp_power *power; + struct dp_catalog *catalog; + struct dp_aux *aux; + struct dp_link *link; + struct dp_panel *panel; + struct dp_ctrl *ctrl; + struct dp_debug *debug; + + struct dp_panel *active_panels[DP_STREAM_MAX]; + struct dp_hdcp hdcp; + + struct dp_hpd_cb hpd_cb; + struct dp_display_mode mode; + struct dp_display dp_display; + struct msm_drm_private *priv; + + struct workqueue_struct *wq; + struct delayed_work hdcp_cb_work; + struct work_struct connect_work; + struct work_struct attention_work; + struct mutex session_lock; + bool hdcp_delayed_off; + + u32 active_stream_cnt; + struct dp_mst mst; + + u32 tot_dsc_blks_in_use; + + bool process_hpd_connect; + + struct notifier_block usb_nb; +}; + +static const struct of_device_id dp_dt_match[] = { + {.compatible = "qcom,dp-display"}, + {} +}; + +static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp) +{ + return dp->link->hdcp_status.hdcp_version && dp->hdcp.ops; +} + +static irqreturn_t dp_display_irq(int irq, void *dev_id) +{ + struct dp_display_private *dp = dev_id; + + if (!dp) { + DP_ERR("invalid data\n"); + return IRQ_NONE; + } + + /* DP HPD isr */ + if (dp->hpd->type == DP_HPD_LPHW) + dp->hpd->isr(dp->hpd); + + /* DP controller isr */ + dp->ctrl->isr(dp->ctrl); + + /* DP aux isr */ + dp->aux->isr(dp->aux); + + /* HDCP isr */ + if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) { + if (dp->hdcp.ops->isr(dp->hdcp.data)) + DP_ERR("dp_hdcp_isr failed\n"); + } + + return IRQ_HANDLED; +} +static bool dp_display_is_ds_bridge(struct dp_panel *panel) +{ + return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_PRESENT); +} + +static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) +{ + return dp_display_is_ds_bridge(dp->panel) && + (dp->link->sink_count.count == 0); +} + +static bool dp_display_is_ready(struct dp_display_private *dp) +{ + return dp->hpd->hpd_high && dp_display_state_is(DP_STATE_CONNECTED) && + !dp_display_is_sink_count_zero(dp) && + dp->hpd->alt_mode_cfg_done; +} + +static void dp_audio_enable(struct dp_display_private *dp, bool enable) +{ + struct dp_panel *dp_panel; + int idx; + + for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) { + if (!dp->active_panels[idx]) + continue; + dp_panel = dp->active_panels[idx]; + + if (dp_panel->audio_supported) { + if (enable) { + dp_panel->audio->bw_code = + dp->link->link_params.bw_code; + dp_panel->audio->lane_count = + dp->link->link_params.lane_count; + dp_panel->audio->on(dp_panel->audio); + } else { + dp_panel->audio->off(dp_panel->audio); + } + } + } +} + +static void dp_display_update_hdcp_status(struct dp_display_private *dp, + bool reset) +{ + if (reset) { + dp->link->hdcp_status.hdcp_state = HDCP_STATE_INACTIVE; + dp->link->hdcp_status.hdcp_version = HDCP_VERSION_NONE; + } + + memset(dp->debug->hdcp_status, 0, sizeof(dp->debug->hdcp_status)); + + snprintf(dp->debug->hdcp_status, sizeof(dp->debug->hdcp_status), + "%s: %s\ncaps: %d\n", + sde_hdcp_version(dp->link->hdcp_status.hdcp_version), + sde_hdcp_state_name(dp->link->hdcp_status.hdcp_state), + dp->hdcp.source_cap); +} + +static void dp_display_update_hdcp_info(struct dp_display_private *dp) +{ + void *fd = NULL; + struct dp_hdcp_dev *dev = NULL; + struct sde_hdcp_ops *ops = NULL; + int i = HDCP_VERSION_2P2; + + dp_display_update_hdcp_status(dp, true); + + dp->hdcp.data = NULL; + dp->hdcp.ops = NULL; + + if (dp->debug->hdcp_disabled || dp->debug->sim_mode) + return; + + while (i) { + dev = &dp->hdcp.dev[i]; + ops = dev->ops; + fd = dev->fd; + + i >>= 1; + + if (!(dp->hdcp.source_cap & dev->ver)) + continue; + + if (ops->sink_support(fd)) { + dp->hdcp.data = fd; + dp->hdcp.ops = ops; + dp->link->hdcp_status.hdcp_version = dev->ver; + break; + } + } + + DP_DEBUG("HDCP version supported: %s\n", + sde_hdcp_version(dp->link->hdcp_status.hdcp_version)); +} + +static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp) +{ + int i; + struct dp_hdcp_dev *hdcp_dev = dp->hdcp.dev; + + if (dp->debug->hdcp_disabled) { + DP_DEBUG("hdcp disabled\n"); + return; + } + + for (i = 0; i < HDCP_VERSION_MAX; i++) { + struct dp_hdcp_dev *dev = &hdcp_dev[i]; + struct sde_hdcp_ops *ops = dev->ops; + void *fd = dev->fd; + + if (!fd || !ops) + continue; + + if (ops->set_mode && ops->set_mode(fd, dp->mst.mst_active)) + continue; + + if (!(dp->hdcp.source_cap & dev->ver) && + ops->feature_supported && + ops->feature_supported(fd)) + dp->hdcp.source_cap |= dev->ver; + } + + dp_display_update_hdcp_status(dp, false); +} + +static void dp_display_hdcp_register_streams(struct dp_display_private *dp) +{ + int rc; + size_t i; + struct sde_hdcp_ops *ops = dp->hdcp.ops; + void *data = dp->hdcp.data; + + if (dp_display_is_ready(dp) && dp->mst.mst_active && ops && + ops->register_streams){ + struct stream_info streams[DP_STREAM_MAX]; + int index = 0; + + DP_DEBUG("Registering all active panel streams with HDCP\n"); + for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { + if (!dp->active_panels[i]) + continue; + streams[index].stream_id = i; + streams[index].virtual_channel = + dp->active_panels[i]->vcpi; + index++; + } + + if (index > 0) { + rc = ops->register_streams(data, index, streams); + if (rc) + DP_ERR("failed to register streams. rc = %d\n", + rc); + } + } +} + +static void dp_display_hdcp_deregister_stream(struct dp_display_private *dp, + enum dp_stream_id stream_id) +{ + if (dp->hdcp.ops->deregister_streams) { + struct stream_info stream = {stream_id, + dp->active_panels[stream_id]->vcpi}; + + DP_DEBUG("Deregistering stream within HDCP library\n"); + dp->hdcp.ops->deregister_streams(dp->hdcp.data, 1, &stream); + } +} + +static void dp_display_abort_hdcp(struct dp_display_private *dp, + bool abort) +{ + u32 i = HDCP_VERSION_2P2; + struct dp_hdcp_dev *dev = NULL; + + while (i) { + dev = &dp->hdcp.dev[i]; + i >>= 1; + if (!(dp->hdcp.source_cap & dev->ver)) + continue; + + dev->ops->abort(dev->fd, abort); + } +} + +static void dp_display_hdcp_cb_work(struct work_struct *work) +{ + struct dp_display_private *dp; + struct delayed_work *dw = to_delayed_work(work); + struct sde_hdcp_ops *ops; + struct dp_link_hdcp_status *status; + void *data; + int rc = 0; + u32 hdcp_auth_state; + u8 sink_status = 0; + + dp = container_of(dw, struct dp_display_private, hdcp_cb_work); + + if (!dp_display_state_is(DP_STATE_ENABLED | DP_STATE_CONNECTED) || + dp_display_state_is(DP_STATE_ABORTED | DP_STATE_HDCP_ABORTED)) + return; + + if (dp_display_state_is(DP_STATE_SUSPENDED)) { + DP_DEBUG("System suspending. Delay HDCP operations\n"); + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); + return; + } + + if (dp->hdcp_delayed_off) { + if (dp->hdcp.ops && dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + dp_display_update_hdcp_status(dp, true); + dp->hdcp_delayed_off = false; + } + + if (dp->debug->hdcp_wait_sink_sync) { + drm_dp_dpcd_readb(dp->aux->drm_aux, DP_SINK_STATUS, + &sink_status); + sink_status &= (DP_RECEIVE_PORT_0_STATUS | + DP_RECEIVE_PORT_1_STATUS); + if (sink_status < 1) { + DP_DEBUG("Sink not synchronized. Queuing again then exiting\n"); + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); + return; + } + } + + status = &dp->link->hdcp_status; + + if (status->hdcp_state == HDCP_STATE_INACTIVE) { + dp_display_check_source_hdcp_caps(dp); + dp_display_update_hdcp_info(dp); + + if (dp_display_is_hdcp_enabled(dp)) { + if (dp->hdcp.ops && dp->hdcp.ops->on && + dp->hdcp.ops->on(dp->hdcp.data)) { + dp_display_update_hdcp_status(dp, true); + return; + } + } else { + dp_display_update_hdcp_status(dp, true); + return; + } + } + + rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl); + if (rc >= 0) { + hdcp_auth_state = (rc >> 20) & 0x3; + DP_DEBUG("hdcp auth state %d\n", hdcp_auth_state); + } + + ops = dp->hdcp.ops; + data = dp->hdcp.data; + + DP_DEBUG("%s: %s\n", sde_hdcp_version(status->hdcp_version), + sde_hdcp_state_name(status->hdcp_state)); + + dp_display_update_hdcp_status(dp, false); + + if (status->hdcp_state != HDCP_STATE_AUTHENTICATED && + dp->debug->force_encryption && ops && ops->force_encryption) + ops->force_encryption(data, dp->debug->force_encryption); + + switch (status->hdcp_state) { + case HDCP_STATE_INACTIVE: + dp_display_hdcp_register_streams(dp); + if (dp->hdcp.ops && dp->hdcp.ops->authenticate) + rc = dp->hdcp.ops->authenticate(data); + if (!rc) + status->hdcp_state = HDCP_STATE_AUTHENTICATING; + break; + case HDCP_STATE_AUTH_FAIL: + if (dp_display_is_ready(dp) && + dp_display_state_is(DP_STATE_ENABLED)) { + if (ops && ops->on && ops->on(data)) { + dp_display_update_hdcp_status(dp, true); + return; + } + dp_display_hdcp_register_streams(dp); + if (ops && ops->reauthenticate) { + rc = ops->reauthenticate(data); + if (rc) + DP_ERR("failed rc=%d\n", rc); + } + status->hdcp_state = HDCP_STATE_AUTHENTICATING; + } else { + DP_DEBUG("not reauthenticating, cable disconnected\n"); + } + break; + default: + dp_display_hdcp_register_streams(dp); + break; + } +} + +static void dp_display_notify_hdcp_status_cb(void *ptr, + enum sde_hdcp_state state) +{ + struct dp_display_private *dp = ptr; + + if (!dp) { + DP_ERR("invalid input\n"); + return; + } + + dp->link->hdcp_status.hdcp_state = state; + + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4); +} + +static void dp_display_deinitialize_hdcp(struct dp_display_private *dp) +{ + if (!dp) { + DP_ERR("invalid input\n"); + return; + } + + sde_dp_hdcp2p2_deinit(dp->hdcp.data); +} + +static int dp_display_initialize_hdcp(struct dp_display_private *dp) +{ + struct sde_hdcp_init_data hdcp_init_data; + struct dp_parser *parser; + void *fd; + int rc = 0; + + if (!dp) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + parser = dp->parser; + + hdcp_init_data.client_id = HDCP_CLIENT_DP; + hdcp_init_data.drm_aux = dp->aux->drm_aux; + hdcp_init_data.cb_data = (void *)dp; + hdcp_init_data.workq = dp->wq; + hdcp_init_data.sec_access = true; + hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb; + hdcp_init_data.dp_ahb = &parser->get_io(parser, "dp_ahb")->io; + hdcp_init_data.dp_aux = &parser->get_io(parser, "dp_aux")->io; + hdcp_init_data.dp_link = &parser->get_io(parser, "dp_link")->io; + hdcp_init_data.dp_p0 = &parser->get_io(parser, "dp_p0")->io; + hdcp_init_data.hdcp_io = &parser->get_io(parser, + "hdcp_physical")->io; + hdcp_init_data.revision = &dp->panel->link_info.revision; + hdcp_init_data.msm_hdcp_dev = dp->parser->msm_hdcp_dev; + + fd = sde_hdcp_1x_init(&hdcp_init_data); + if (IS_ERR_OR_NULL(fd)) { + DP_ERR("Error initializing HDCP 1.x\n"); + rc = -EINVAL; + goto error; + } + + dp->hdcp.dev[HDCP_VERSION_1X].fd = fd; + dp->hdcp.dev[HDCP_VERSION_1X].ops = sde_hdcp_1x_get(fd); + dp->hdcp.dev[HDCP_VERSION_1X].ver = HDCP_VERSION_1X; + DP_DEBUG("HDCP 1.3 initialized\n"); + + fd = sde_dp_hdcp2p2_init(&hdcp_init_data); + if (IS_ERR_OR_NULL(fd)) { + DP_ERR("Error initializing HDCP 2.x\n"); + rc = -EINVAL; + goto error; + } + + dp->hdcp.dev[HDCP_VERSION_2P2].fd = fd; + dp->hdcp.dev[HDCP_VERSION_2P2].ops = sde_dp_hdcp2p2_get(fd); + dp->hdcp.dev[HDCP_VERSION_2P2].ver = HDCP_VERSION_2P2; + DP_DEBUG("HDCP 2.2 initialized\n"); + + return 0; +error: + dp_display_deinitialize_hdcp(dp); + + return rc; +} + +static int dp_display_bind(struct device *dev, struct device *master, + void *data) +{ + int rc = 0; + struct dp_display_private *dp; + struct drm_device *drm; + struct platform_device *pdev = to_platform_device(dev); + + if (!dev || !pdev || !master) { + DP_ERR("invalid param(s), dev %pK, pdev %pK, master %pK\n", + dev, pdev, master); + rc = -EINVAL; + goto end; + } + + drm = dev_get_drvdata(master); + dp = platform_get_drvdata(pdev); + if (!drm || !dp) { + DP_ERR("invalid param(s), drm %pK, dp %pK\n", + drm, dp); + rc = -EINVAL; + goto end; + } + + dp->dp_display.drm_dev = drm; + dp->priv = drm->dev_private; +end: + return rc; +} + +static void dp_display_unbind(struct device *dev, struct device *master, + void *data) +{ + struct dp_display_private *dp; + struct platform_device *pdev = to_platform_device(dev); + + if (!dev || !pdev) { + DP_ERR("invalid param(s)\n"); + return; + } + + dp = platform_get_drvdata(pdev); + if (!dp) { + DP_ERR("Invalid params\n"); + return; + } + + if (dp->power) + (void)dp->power->power_client_deinit(dp->power); + if (dp->aux) + (void)dp->aux->drm_aux_deregister(dp->aux); + dp_display_deinitialize_hdcp(dp); +} + +static const struct component_ops dp_display_comp_ops = { + .bind = dp_display_bind, + .unbind = dp_display_unbind, +}; + +static void dp_display_send_hpd_event(struct dp_display_private *dp) +{ + struct drm_device *dev = NULL; + struct drm_connector *connector; + char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE], + bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE]; + char *envp[5]; + + if (dp->mst.mst_active) { + DP_DEBUG("skip notification for mst mode\n"); + dp_display_state_remove(DP_STATE_DISCONNECT_NOTIFIED); + return; + } + + connector = dp->dp_display.base_connector; + + if (!connector) { + DP_ERR("connector not set\n"); + return; + } + + connector->status = connector->funcs->detect(connector, false); + if (dp->cached_connector_status == connector->status) { + DP_DEBUG("connector status (%d) unchanged, skipping uevent\n", + dp->cached_connector_status); + return; + } + + dp->cached_connector_status = connector->status; + + dev = connector->dev; + + snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name); + snprintf(status, HPD_STRING_SIZE, "status=%s", + drm_get_connector_status_name(connector->status)); + snprintf(bpp, HPD_STRING_SIZE, "bpp=%d", + dp_link_bit_depth_to_bpp( + dp->link->test_video.test_bit_depth)); + snprintf(pattern, HPD_STRING_SIZE, "pattern=%d", + dp->link->test_video.test_video_pattern); + + DP_DEBUG("[%s]:[%s] [%s] [%s]\n", name, status, bpp, pattern); + envp[0] = name; + envp[1] = status; + envp[2] = bpp; + envp[3] = pattern; + envp[4] = NULL; + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, + envp); + + if (connector->status == connector_status_connected) { + dp_display_state_add(DP_STATE_CONNECT_NOTIFIED); + dp_display_state_remove(DP_STATE_DISCONNECT_NOTIFIED); + } else { + dp_display_state_add(DP_STATE_DISCONNECT_NOTIFIED); + dp_display_state_remove(DP_STATE_CONNECT_NOTIFIED); + } +} + +static int dp_display_send_hpd_notification(struct dp_display_private *dp) +{ + int ret = 0; + bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state, hpd); + + /* + * Send the notification only if there is any change. This check is + * necessary since it is possible that the connect_work may or may not + * skip sending the notification in order to respond to a pending + * attention message. Attention work thread will always attempt to + * send the notification after successfully handling the attention + * message. This check here will avoid any unintended duplicate + * notifications. + */ + if (dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) && hpd) { + DP_DEBUG("connection notified already, skip notification\n"); + goto skip_wait; + } else if (dp_display_state_is(DP_STATE_DISCONNECT_NOTIFIED) && !hpd) { + DP_DEBUG("disonnect notified already, skip notification\n"); + goto skip_wait; + } + + dp->aux->state |= DP_STATE_NOTIFICATION_SENT; + + if (!dp->mst.mst_active) + dp->dp_display.is_sst_connected = hpd; + else + dp->dp_display.is_sst_connected = false; + + reinit_completion(&dp->notification_comp); + dp_display_send_hpd_event(dp); + + if (hpd && dp->mst.mst_active) + goto skip_wait; + + if (!dp->mst.mst_active && + (!!dp_display_state_is(DP_STATE_ENABLED) == hpd)) + goto skip_wait; + + if (!wait_for_completion_timeout(&dp->notification_comp, + HZ * 5)) { + DP_WARN("%s timeout\n", hpd ? "connect" : "disconnect"); + ret = -EINVAL; + } + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, hpd, ret); + return ret; +skip_wait: + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, hpd, ret); + return 0; +} + +static void dp_display_update_mst_state(struct dp_display_private *dp, + bool state) +{ + dp->mst.mst_active = state; + dp->panel->mst_state = state; +} + +static void dp_display_process_mst_hpd_high(struct dp_display_private *dp, + bool mst_probe) +{ + bool is_mst_receiver; + struct dp_mst_hpd_info info; + const unsigned long clear_mstm_ctrl_timeout_us = 100000; + u8 old_mstm_ctrl; + int ret; + + if (!dp->parser->has_mst || !dp->mst.drm_registered) { + DP_MST_DEBUG("mst not enabled. has_mst:%d, registered:%d\n", + dp->parser->has_mst, dp->mst.drm_registered); + return; + } + + DP_MST_DEBUG("mst_hpd_high work. mst_probe:%d\n", mst_probe); + + if (!dp->mst.mst_active) { + is_mst_receiver = dp->panel->read_mst_cap(dp->panel); + + if (!is_mst_receiver) { + DP_MST_DEBUG("sink doesn't support mst\n"); + return; + } + + /* clear sink mst state */ + drm_dp_dpcd_readb(dp->aux->drm_aux, DP_MSTM_CTRL, + &old_mstm_ctrl); + drm_dp_dpcd_writeb(dp->aux->drm_aux, DP_MSTM_CTRL, 0); + + /* add extra delay if MST state is not cleared */ + if (old_mstm_ctrl) { + DP_MST_DEBUG("MSTM_CTRL is not cleared, wait %dus\n", + clear_mstm_ctrl_timeout_us); + usleep_range(clear_mstm_ctrl_timeout_us, + clear_mstm_ctrl_timeout_us + 1000); + } + + ret = drm_dp_dpcd_writeb(dp->aux->drm_aux, DP_MSTM_CTRL, + DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); + if (ret < 0) { + DP_ERR("sink mst enablement failed\n"); + return; + } + + dp_display_update_mst_state(dp, true); + } else if (dp->mst.mst_active && mst_probe) { + info.mst_protocol = dp->parser->has_mst_sideband; + info.mst_port_cnt = dp->debug->mst_port_cnt; + info.edid = dp->debug->get_edid(dp->debug); + + if (dp->mst.cbs.hpd) + dp->mst.cbs.hpd(&dp->dp_display, true, &info); + } + + DP_MST_DEBUG("mst_hpd_high. mst_active:%d\n", dp->mst.mst_active); +} + +static void dp_display_host_init(struct dp_display_private *dp) +{ + bool flip = false; + bool reset; + + if (dp_display_state_is(DP_STATE_INITIALIZED)) { + dp_display_state_log("[already initialized]"); + return; + } + + if (dp->hpd->orientation == ORIENTATION_CC2) + flip = true; + + reset = dp->debug->sim_mode ? false : + (!dp->hpd->multi_func || !dp->hpd->peer_usb_comm); + + dp->power->init(dp->power, flip); + dp->hpd->host_init(dp->hpd, &dp->catalog->hpd); + dp->ctrl->init(dp->ctrl, flip, reset); + enable_irq(dp->irq); + dp_display_abort_hdcp(dp, false); + + dp_display_state_add(DP_STATE_INITIALIZED); + + /* log this as it results from user action of cable connection */ + DP_INFO("[OK]\n"); +} + +static void dp_display_host_ready(struct dp_display_private *dp) +{ + if (!dp_display_state_is(DP_STATE_INITIALIZED)) { + dp_display_state_show("[not initialized]"); + return; + } + + if (dp_display_state_is(DP_STATE_READY)) { + dp_display_state_log("[already ready]"); + return; + } + + /* + * Reset the aborted state for AUX and CTRL modules. This will + * allow these modules to execute normally in response to the + * cable connection event. + * + * One corner case still exists. While the execution flow ensures + * that cable disconnection flushes all pending work items on the DP + * workqueue, and waits for the user module to clean up the DP + * connection session, it is possible that the system delays can + * lead to timeouts in the connect path. As a result, the actual + * connection callback from user modules can come in late and can + * race against a subsequent connection event here which would have + * reset the aborted flags. There is no clear solution for this since + * the connect/disconnect notifications do not currently have any + * sessions IDs. + */ + dp->aux->abort(dp->aux, false); + dp->ctrl->abort(dp->ctrl, false); + + dp->aux->init(dp->aux, dp->parser->aux_cfg); + dp->panel->init(dp->panel); + + dp_display_state_add(DP_STATE_READY); + /* log this as it results from user action of cable connection */ + DP_INFO("[OK]\n"); +} + +static void dp_display_host_unready(struct dp_display_private *dp) +{ + if (!dp_display_state_is(DP_STATE_INITIALIZED)) { + dp_display_state_show("[not initialized]"); + return; + } + + if (!dp_display_state_is(DP_STATE_READY)) { + dp_display_state_show("[not ready]"); + return; + } + + dp_display_state_remove(DP_STATE_READY); + dp->aux->deinit(dp->aux); + /* log this as it results from user action of cable connection */ + DP_INFO("[OK]\n"); +} + +static void dp_display_host_deinit(struct dp_display_private *dp) +{ + if (dp->active_stream_cnt) { + SDE_EVT32_EXTERNAL(dp->state, dp->active_stream_cnt); + DP_DEBUG("active stream present\n"); + return; + } + + if (!dp_display_state_is(DP_STATE_INITIALIZED)) { + dp_display_state_show("[not initialized]"); + return; + } + + dp_display_abort_hdcp(dp, true); + dp->ctrl->deinit(dp->ctrl); + dp->hpd->host_deinit(dp->hpd, &dp->catalog->hpd); + dp->power->deinit(dp->power); + disable_irq(dp->irq); + dp->aux->state = 0; + + dp_display_state_remove(DP_STATE_INITIALIZED); + + /* log this as it results from user action of cable dis-connection */ + DP_INFO("[OK]\n"); +} + +static int dp_display_process_hpd_high(struct dp_display_private *dp) +{ + int rc = -EINVAL; + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + if (dp_display_state_is(DP_STATE_CONNECTED)) { + DP_DEBUG("dp already connected, skipping hpd high\n"); + mutex_unlock(&dp->session_lock); + return -EISCONN; + } + + dp_display_state_add(DP_STATE_CONNECTED); + + dp->dp_display.max_pclk_khz = min(dp->parser->max_pclk_khz, + dp->debug->max_pclk_khz); + + /* + * If dp video session is not restored from a previous session teardown + * by userspace, ensure the host_init is executed, in such a scenario, + * so that all the required DP resources are enabled. + * + * Below is one of the sequences of events which describe the above + * scenario: + * a. Source initiated power down resulting in host_deinit. + * b. Sink issues hpd low attention without physical cable disconnect. + * c. Source initiated power up sequence returns early because hpd is + * not high. + * d. Sink issues a hpd high attention event. + */ + if (dp_display_state_is(DP_STATE_SRC_PWRDN) && + dp_display_state_is(DP_STATE_CONFIGURED)) { + dp_display_host_init(dp); + dp_display_state_remove(DP_STATE_SRC_PWRDN); + } + + dp_display_host_ready(dp); + + dp->link->psm_config(dp->link, &dp->panel->link_info, false); + dp->debug->psm_enabled = false; + + if (!dp->dp_display.base_connector) + goto end; + + rc = dp->panel->read_sink_caps(dp->panel, + dp->dp_display.base_connector, dp->hpd->multi_func); + /* + * ETIMEDOUT --> cable may have been removed + * ENOTCONN --> no downstream device connected + */ + if (rc == -ETIMEDOUT || rc == -ENOTCONN) { + dp_display_state_remove(DP_STATE_CONNECTED); + goto end; + } + + dp->link->process_request(dp->link); + dp->panel->handle_sink_request(dp->panel); + + dp_display_process_mst_hpd_high(dp, false); + + rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, + dp->panel->fec_en, dp->panel->dsc_en, false); + if (rc) { + dp_display_state_remove(DP_STATE_CONNECTED); + goto end; + } + + dp->process_hpd_connect = false; + + dp_display_process_mst_hpd_high(dp, true); +end: + mutex_unlock(&dp->session_lock); + + /* + * Delay the HPD connect notification to see if sink generates any + * IRQ HPDs immediately after the HPD high. + */ + usleep_range(10000, 10100); + + /* + * If an IRQ HPD is pending, then do not send a connect notification. + * Once this work returns, the IRQ HPD would be processed and any + * required actions (such as link maintenance) would be done which + * will subsequently send the HPD notification. To keep things simple, + * do this only for SST use-cases. MST use cases require additional + * care in order to handle the side-band communications as well. + * + * One of the main motivations for this is DP LL 1.4 CTS use case + * where it is possible that we could get a test request right after + * a connection, and the strict timing requriements of the test can + * only be met if we do not wait for the e2e connection to be set up. + */ + if (!dp->mst.mst_active && + (work_busy(&dp->attention_work) == WORK_BUSY_PENDING)) { + SDE_EVT32_EXTERNAL(dp->state, 99); + DP_DEBUG("Attention pending, skip HPD notification\n"); + goto skip_notify; + } + + if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) + dp_display_send_hpd_notification(dp); + +skip_notify: + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, rc); + return rc; +} + +static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) +{ + struct dp_mst_hpd_info info = {0}; + + if (dp->mst.mst_active) { + DP_MST_DEBUG("mst_hpd_low work\n"); + + if (dp->mst.cbs.hpd) { + info.mst_protocol = dp->parser->has_mst_sideband; + dp->mst.cbs.hpd(&dp->dp_display, false, &info); + } + dp_display_update_mst_state(dp, false); + } + + DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active); +} + +static int dp_display_process_hpd_low(struct dp_display_private *dp) +{ + int rc = 0; + + dp_display_state_remove(DP_STATE_CONNECTED); + dp->process_hpd_connect = false; + dp_audio_enable(dp, false); + dp_display_process_mst_hpd_low(dp); + + if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) || + dp_display_state_is(DP_STATE_ENABLED)) && + !dp->mst.mst_active) + rc = dp_display_send_hpd_notification(dp); + + mutex_lock(&dp->session_lock); + if (!dp->active_stream_cnt) + dp->ctrl->off(dp->ctrl); + mutex_unlock(&dp->session_lock); + + dp->panel->video_test = false; + + return rc; +} + +static int dp_display_usbpd_configure_cb(struct device *dev) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dev) { + DP_ERR("invalid dev\n"); + rc = -EINVAL; + goto end; + } + + dp = dev_get_drvdata(dev); + if (!dp) { + DP_ERR("no driver data found\n"); + rc = -ENODEV; + goto end; + } + + if (!dp->debug->sim_mode && !dp->parser->no_aux_switch + && !dp->parser->gpio_aux_switch) { + rc = dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); + if (rc) + goto end; + } + + mutex_lock(&dp->session_lock); + + dp_display_state_remove(DP_STATE_ABORTED); + dp_display_state_add(DP_STATE_CONFIGURED); + + dp_display_host_init(dp); + + /* check for hpd high */ + if (dp->hpd->hpd_high) + queue_work(dp->wq, &dp->connect_work); + else + dp->process_hpd_connect = true; + mutex_unlock(&dp->session_lock); +end: + return rc; +} + +static int dp_display_stream_pre_disable(struct dp_display_private *dp, + struct dp_panel *dp_panel) +{ + dp->ctrl->stream_pre_off(dp->ctrl, dp_panel); + + return 0; +} + +static void dp_display_stream_disable(struct dp_display_private *dp, + struct dp_panel *dp_panel) +{ + if (!dp->active_stream_cnt) { + DP_ERR("invalid active_stream_cnt (%d)\n", + dp->active_stream_cnt); + return; + } + + DP_DEBUG("stream_id=%d, active_stream_cnt=%d\n", + dp_panel->stream_id, dp->active_stream_cnt); + + dp->ctrl->stream_off(dp->ctrl, dp_panel); + dp->active_panels[dp_panel->stream_id] = NULL; + dp->active_stream_cnt--; +} + +static void dp_display_clean(struct dp_display_private *dp) +{ + int idx; + struct dp_panel *dp_panel; + struct dp_link_hdcp_status *status = &dp->link->hdcp_status; + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + + if (dp_display_is_hdcp_enabled(dp) && + status->hdcp_state != HDCP_STATE_INACTIVE) { + cancel_delayed_work_sync(&dp->hdcp_cb_work); + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + + dp_display_update_hdcp_status(dp, true); + } + + for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) { + if (!dp->active_panels[idx]) + continue; + + dp_panel = dp->active_panels[idx]; + if (dp_panel->audio_supported) + dp_panel->audio->off(dp_panel->audio); + + dp_display_stream_pre_disable(dp, dp_panel); + dp_display_stream_disable(dp, dp_panel); + dp_panel->deinit(dp_panel, 0); + } + + dp_display_state_remove(DP_STATE_ENABLED | DP_STATE_CONNECTED); + + dp->ctrl->off(dp->ctrl); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); +} + +static int dp_display_handle_disconnect(struct dp_display_private *dp) +{ + int rc; + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + rc = dp_display_process_hpd_low(dp); + if (rc) { + /* cancel any pending request */ + dp->ctrl->abort(dp->ctrl, true); + dp->aux->abort(dp->aux, true); + } + + mutex_lock(&dp->session_lock); + if (rc && dp_display_state_is(DP_STATE_ENABLED)) + dp_display_clean(dp); + + dp_display_host_unready(dp); + + mutex_unlock(&dp->session_lock); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + return rc; +} + +static void dp_display_disconnect_sync(struct dp_display_private *dp) +{ + /* cancel any pending request */ + dp_display_state_add(DP_STATE_ABORTED); + + dp->ctrl->abort(dp->ctrl, true); + dp->aux->abort(dp->aux, true); + + /* wait for idle state */ + cancel_work_sync(&dp->connect_work); + cancel_work_sync(&dp->attention_work); + flush_workqueue(dp->wq); + + dp_display_handle_disconnect(dp); +} + +static int dp_display_usbpd_disconnect_cb(struct device *dev) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dev) { + DP_ERR("invalid dev\n"); + rc = -EINVAL; + goto end; + } + + dp = dev_get_drvdata(dev); + if (!dp) { + DP_ERR("no driver data found\n"); + rc = -ENODEV; + goto end; + } + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state, + dp->debug->psm_enabled); + + if (dp->debug->psm_enabled && dp_display_state_is(DP_STATE_READY)) + dp->link->psm_config(dp->link, &dp->panel->link_info, true); + + dp_display_disconnect_sync(dp); + + mutex_lock(&dp->session_lock); + dp_display_host_deinit(dp); + dp_display_state_remove(DP_STATE_CONFIGURED); + mutex_unlock(&dp->session_lock); + + if (!dp->debug->sim_mode && !dp->parser->no_aux_switch + && !dp->parser->gpio_aux_switch) + dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); +end: + return rc; +} + +static int dp_display_stream_enable(struct dp_display_private *dp, + struct dp_panel *dp_panel) +{ + int rc = 0; + + rc = dp->ctrl->stream_on(dp->ctrl, dp_panel); + + if (dp->debug->tpg_state) + dp_panel->tpg_config(dp_panel, true); + + if (!rc) { + dp->active_panels[dp_panel->stream_id] = dp_panel; + dp->active_stream_cnt++; + } + + DP_DEBUG("dp active_stream_cnt:%d\n", dp->active_stream_cnt); + + return rc; +} + +static void dp_display_mst_attention(struct dp_display_private *dp) +{ + struct dp_mst_hpd_info hpd_irq = {0}; + + if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) { + hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim; + hpd_irq.mst_sim_add_con = dp->debug->mst_sim_add_con; + hpd_irq.mst_sim_remove_con = dp->debug->mst_sim_remove_con; + hpd_irq.mst_sim_remove_con_id = dp->debug->mst_sim_remove_con_id; + hpd_irq.edid = dp->debug->get_edid(dp->debug); + dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq); + dp->debug->mst_hpd_sim = false; + dp->debug->mst_sim_add_con = false; + dp->debug->mst_sim_remove_con = false; + } + + DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active); +} + +static void dp_display_attention_work(struct work_struct *work) +{ + struct dp_display_private *dp = container_of(work, + struct dp_display_private, attention_work); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + SDE_EVT32_EXTERNAL(dp->state); + + if (dp->debug->mst_hpd_sim || !dp_display_state_is(DP_STATE_READY)) { + mutex_unlock(&dp->session_lock); + goto mst_attention; + } + + if (dp->link->process_request(dp->link)) { + mutex_unlock(&dp->session_lock); + goto cp_irq; + } + + mutex_unlock(&dp->session_lock); + SDE_EVT32_EXTERNAL(dp->state, dp->link->sink_request); + + if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) { + SDE_EVT32_EXTERNAL(dp->state, DS_PORT_STATUS_CHANGED); + if (dp_display_is_sink_count_zero(dp)) { + dp_display_handle_disconnect(dp); + } else { + /* + * connect work should take care of sending + * the HPD notification. + */ + if (!dp->mst.mst_active) + queue_work(dp->wq, &dp->connect_work); + } + + goto mst_attention; + } + + if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { + SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_VIDEO_PATTERN); + dp_display_handle_disconnect(dp); + + dp->panel->video_test = true; + /* + * connect work should take care of sending + * the HPD notification. + */ + queue_work(dp->wq, &dp->connect_work); + + goto mst_attention; + } + + if (dp->link->sink_request & (DP_TEST_LINK_PHY_TEST_PATTERN | + DP_TEST_LINK_TRAINING | DP_LINK_STATUS_UPDATED)) { + + mutex_lock(&dp->session_lock); + dp_audio_enable(dp, false); + + if (dp->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { + SDE_EVT32_EXTERNAL(dp->state, + DP_TEST_LINK_PHY_TEST_PATTERN); + dp->ctrl->process_phy_test_request(dp->ctrl); + } + + if (dp->link->sink_request & DP_TEST_LINK_TRAINING) { + SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_TRAINING); + dp->link->send_test_response(dp->link); + dp->ctrl->link_maintenance(dp->ctrl); + } + + if (dp->link->sink_request & DP_LINK_STATUS_UPDATED) { + SDE_EVT32_EXTERNAL(dp->state, DP_LINK_STATUS_UPDATED); + dp->ctrl->link_maintenance(dp->ctrl); + } + + dp_audio_enable(dp, true); + mutex_unlock(&dp->session_lock); + + if (dp->link->sink_request & (DP_TEST_LINK_PHY_TEST_PATTERN | + DP_TEST_LINK_TRAINING)) + goto mst_attention; + } + +cp_irq: + if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) + dp->hdcp.ops->cp_irq(dp->hdcp.data); + + if (!dp->mst.mst_active) { + /* + * It is possible that the connect_work skipped sending + * the HPD notification if the attention message was + * already pending. Send the notification here to + * account for that. This is not needed if this + * attention work was handling a test request + */ + dp_display_send_hpd_notification(dp); + } + +mst_attention: + dp_display_mst_attention(dp); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); +} + +static int dp_display_usbpd_attention_cb(struct device *dev) +{ + struct dp_display_private *dp; + + if (!dev) { + DP_ERR("invalid dev\n"); + return -EINVAL; + } + + dp = dev_get_drvdata(dev); + if (!dp) { + DP_ERR("no driver data found\n"); + return -ENODEV; + } + + DP_DEBUG("hpd_irq:%d, hpd_high:%d, power_on:%d, is_connected:%d\n", + dp->hpd->hpd_irq, dp->hpd->hpd_high, + !!dp_display_state_is(DP_STATE_ENABLED), + !!dp_display_state_is(DP_STATE_CONNECTED)); + SDE_EVT32_EXTERNAL(dp->state, dp->hpd->hpd_irq, dp->hpd->hpd_high, + !!dp_display_state_is(DP_STATE_ENABLED), + !!dp_display_state_is(DP_STATE_CONNECTED)); + + if (!dp->hpd->hpd_high) { + dp_display_disconnect_sync(dp); + } else if ((dp->hpd->hpd_irq && dp_display_state_is(DP_STATE_READY)) || + dp->debug->mst_hpd_sim) { + queue_work(dp->wq, &dp->attention_work); + } else if (dp->process_hpd_connect || + !dp_display_state_is(DP_STATE_CONNECTED)) { + dp_display_state_remove(DP_STATE_ABORTED); + queue_work(dp->wq, &dp->connect_work); + } else { + DP_DEBUG("ignored\n"); + } + + return 0; +} + +static void dp_display_connect_work(struct work_struct *work) +{ + int rc = 0; + struct dp_display_private *dp = container_of(work, + struct dp_display_private, connect_work); + + if (dp_display_state_is(DP_STATE_ABORTED)) { + DP_WARN("HPD off requested\n"); + return; + } + + if (!dp->hpd->hpd_high) { + DP_WARN("Sink disconnected\n"); + return; + } + + rc = dp_display_process_hpd_high(dp); + + if (!rc && dp->panel->video_test) + dp->link->send_test_response(dp->link); +} + +static int dp_display_usb_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct extcon_dev *edev = ptr; + struct dp_display_private *dp = container_of(nb, + struct dp_display_private, usb_nb); + if (!edev) + goto end; + + if (!event && dp->debug->sim_mode) { + dp_display_disconnect_sync(dp); + dp->debug->abort(dp->debug); + } +end: + return NOTIFY_DONE; +} + +static int dp_display_get_usb_extcon(struct dp_display_private *dp) +{ + struct extcon_dev *edev; + int rc; + + edev = extcon_get_edev_by_phandle(&dp->pdev->dev, 0); + if (IS_ERR(edev)) + return PTR_ERR(edev); + + dp->usb_nb.notifier_call = dp_display_usb_notifier; + dp->usb_nb.priority = 2; + rc = extcon_register_notifier(edev, EXTCON_USB, &dp->usb_nb); + if (rc) + DP_ERR("failed to register for usb event: %d\n", rc); + + return rc; +} + +static void dp_display_deinit_sub_modules(struct dp_display_private *dp) +{ + dp_audio_put(dp->panel->audio); + dp_ctrl_put(dp->ctrl); + dp_link_put(dp->link); + dp_panel_put(dp->panel); + dp_aux_put(dp->aux); + dp_power_put(dp->power); + dp_catalog_put(dp->catalog); + dp_parser_put(dp->parser); + dp_hpd_put(dp->hpd); + mutex_destroy(&dp->session_lock); + dp_debug_put(dp->debug); +} + +static int dp_init_sub_modules(struct dp_display_private *dp) +{ + int rc = 0; + bool hdcp_disabled; + struct device *dev = &dp->pdev->dev; + struct dp_hpd_cb *cb = &dp->hpd_cb; + struct dp_ctrl_in ctrl_in = { + .dev = dev, + }; + struct dp_panel_in panel_in = { + .dev = dev, + }; + struct dp_debug_in debug_in = { + .dev = dev, + }; + + mutex_init(&dp->session_lock); + + dp->parser = dp_parser_get(dp->pdev); + if (IS_ERR(dp->parser)) { + rc = PTR_ERR(dp->parser); + DP_ERR("failed to initialize parser, rc = %d\n", rc); + dp->parser = NULL; + goto error; + } + + rc = dp->parser->parse(dp->parser); + if (rc) { + DP_ERR("device tree parsing failed\n"); + goto error_catalog; + } + + g_dp_display->is_mst_supported = dp->parser->has_mst; + g_dp_display->no_mst_encoder = dp->parser->no_mst_encoder; + + dp->catalog = dp_catalog_get(dev, dp->parser); + if (IS_ERR(dp->catalog)) { + rc = PTR_ERR(dp->catalog); + DP_ERR("failed to initialize catalog, rc = %d\n", rc); + dp->catalog = NULL; + goto error_catalog; + } + + dp->power = dp_power_get(dp->parser); + if (IS_ERR(dp->power)) { + rc = PTR_ERR(dp->power); + DP_ERR("failed to initialize power, rc = %d\n", rc); + dp->power = NULL; + goto error_power; + } + + rc = dp->power->power_client_init(dp->power, &dp->priv->phandle, + dp->dp_display.drm_dev); + if (rc) { + DP_ERR("Power client create failed\n"); + goto error_aux; + } + + dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser, + dp->aux_switch_node); + if (IS_ERR(dp->aux)) { + rc = PTR_ERR(dp->aux); + DP_ERR("failed to initialize aux, rc = %d\n", rc); + dp->aux = NULL; + goto error_aux; + } + + rc = dp->aux->drm_aux_register(dp->aux); + if (rc) { + DP_ERR("DRM DP AUX register failed\n"); + goto error_link; + } + + dp->link = dp_link_get(dev, dp->aux); + if (IS_ERR(dp->link)) { + rc = PTR_ERR(dp->link); + DP_ERR("failed to initialize link, rc = %d\n", rc); + dp->link = NULL; + goto error_link; + } + + panel_in.aux = dp->aux; + panel_in.catalog = &dp->catalog->panel; + panel_in.link = dp->link; + panel_in.connector = dp->dp_display.base_connector; + panel_in.base_panel = NULL; + panel_in.parser = dp->parser; + + dp->panel = dp_panel_get(&panel_in); + if (IS_ERR(dp->panel)) { + rc = PTR_ERR(dp->panel); + DP_ERR("failed to initialize panel, rc = %d\n", rc); + dp->panel = NULL; + goto error_panel; + } + + ctrl_in.link = dp->link; + ctrl_in.panel = dp->panel; + ctrl_in.aux = dp->aux; + ctrl_in.power = dp->power; + ctrl_in.catalog = &dp->catalog->ctrl; + ctrl_in.parser = dp->parser; + + dp->ctrl = dp_ctrl_get(&ctrl_in); + if (IS_ERR(dp->ctrl)) { + rc = PTR_ERR(dp->ctrl); + DP_ERR("failed to initialize ctrl, rc = %d\n", rc); + dp->ctrl = NULL; + goto error_ctrl; + } + + dp->panel->audio = dp_audio_get(dp->pdev, dp->panel, + &dp->catalog->audio); + if (IS_ERR(dp->panel->audio)) { + rc = PTR_ERR(dp->panel->audio); + DP_ERR("failed to initialize audio, rc = %d\n", rc); + dp->panel->audio = NULL; + goto error_audio; + } + + memset(&dp->mst, 0, sizeof(dp->mst)); + dp->active_stream_cnt = 0; + + cb->configure = dp_display_usbpd_configure_cb; + cb->disconnect = dp_display_usbpd_disconnect_cb; + cb->attention = dp_display_usbpd_attention_cb; + + dp->hpd = dp_hpd_get(dev, dp->parser, &dp->catalog->hpd, cb); + if (IS_ERR(dp->hpd)) { + rc = PTR_ERR(dp->hpd); + DP_ERR("failed to initialize hpd, rc = %d\n", rc); + dp->hpd = NULL; + goto error_hpd; + } + + hdcp_disabled = !!dp_display_initialize_hdcp(dp); + + debug_in.panel = dp->panel; + debug_in.hpd = dp->hpd; + debug_in.link = dp->link; + debug_in.aux = dp->aux; + debug_in.connector = &dp->dp_display.base_connector; + debug_in.catalog = dp->catalog; + debug_in.parser = dp->parser; + debug_in.ctrl = dp->ctrl; + + dp->debug = dp_debug_get(&debug_in); + if (IS_ERR(dp->debug)) { + rc = PTR_ERR(dp->debug); + DP_ERR("failed to initialize debug, rc = %d\n", rc); + dp->debug = NULL; + goto error_debug; + } + + dp->cached_connector_status = connector_status_disconnected; + dp->tot_dsc_blks_in_use = 0; + + dp->debug->hdcp_disabled = hdcp_disabled; + dp_display_update_hdcp_status(dp, true); + + dp_display_get_usb_extcon(dp); + + rc = dp->hpd->register_hpd(dp->hpd); + if (rc) { + DP_ERR("failed register hpd\n"); + goto error_hpd_reg; + } + + return rc; +error_hpd_reg: + dp_debug_put(dp->debug); +error_debug: + dp_hpd_put(dp->hpd); +error_hpd: + dp_audio_put(dp->panel->audio); +error_audio: + dp_ctrl_put(dp->ctrl); +error_ctrl: + dp_panel_put(dp->panel); +error_panel: + dp_link_put(dp->link); +error_link: + dp_aux_put(dp->aux); +error_aux: + dp_power_put(dp->power); +error_power: + dp_catalog_put(dp->catalog); +error_catalog: + dp_parser_put(dp->parser); +error: + mutex_destroy(&dp->session_lock); + return rc; +} + +static int dp_display_post_init(struct dp_display *dp_display) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + if (IS_ERR_OR_NULL(dp)) { + DP_ERR("invalid params\n"); + rc = -EINVAL; + goto end; + } + + rc = dp_init_sub_modules(dp); + if (rc) + goto end; + + dp_display->post_init = NULL; +end: + DP_DEBUG("%s\n", rc ? "failed" : "success"); + return rc; +} + +static int dp_display_set_mode(struct dp_display *dp_display, void *panel, + struct dp_display_mode *mode) +{ + const u32 num_components = 3, default_bpp = 24; + struct dp_display_private *dp; + struct dp_panel *dp_panel; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp_panel = panel; + if (!dp_panel->connector) { + DP_ERR("invalid connector input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + if (dp_panel->connector->display_info.max_tmds_clock > 0) + dp->panel->connector->display_info.max_tmds_clock = + dp_panel->connector->display_info.max_tmds_clock; + + mode->timing.bpp = + dp_panel->connector->display_info.bpc * num_components; + if (!mode->timing.bpp) + mode->timing.bpp = default_bpp; + + mode->timing.bpp = dp->panel->get_mode_bpp(dp->panel, + mode->timing.bpp, mode->timing.pixel_clk_khz); + + dp_panel->pinfo = mode->timing; + mutex_unlock(&dp->session_lock); + + return 0; +} + +static int dp_display_prepare(struct dp_display *dp_display, void *panel) +{ + struct dp_display_private *dp; + struct dp_panel *dp_panel; + int rc = 0; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp_panel = panel; + if (!dp_panel->connector) { + DP_ERR("invalid connector input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + /* + * If DP video session is restored by the userspace after display + * disconnect notification from dongle i.e. typeC cable connected to + * source but disconnected at the display side, the DP controller is + * not restored to the desired configured state. So, ensure host_init + * is executed in such a scenario so that all the DP controller + * resources are enabled for the next connection event. + */ + if (dp_display_state_is(DP_STATE_SRC_PWRDN) && + dp_display_state_is(DP_STATE_CONFIGURED)) { + dp_display_host_init(dp); + dp_display_state_remove(DP_STATE_SRC_PWRDN); + } + + /* + * If the physical connection to the sink is already lost by the time + * we try to set up the connection, we can just skip all the steps + * here safely. + */ + if (dp_display_state_is(DP_STATE_ABORTED)) { + dp_display_state_log("[aborted]"); + goto end; + } + + /* + * If DP_STATE_ENABLED, there is nothing left to do. + * However, this should not happen ideally. So, log this. + */ + if (dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[already enabled]"); + goto end; + } + + if (!dp_display_is_ready(dp)) { + dp_display_state_show("[not ready]"); + goto end; + } + + /* For supporting DP_PANEL_SRC_INITIATED_POWER_DOWN case */ + dp_display_host_ready(dp); + + if (dp->debug->psm_enabled) { + dp->link->psm_config(dp->link, &dp->panel->link_info, false); + dp->debug->psm_enabled = false; + } + + /* + * Execute the dp controller power on in shallow mode here. + * In normal cases, controller should have been powered on + * by now. In some cases like suspend/resume or framework + * reboot, we end up here without a powered on controller. + * Cable may have been removed in suspended state. In that + * case, link training is bound to fail on system resume. + * So, we execute in shallow mode here to do only minimal + * and required things. + */ + rc = dp->ctrl->on(dp->ctrl, dp->mst.mst_active, dp_panel->fec_en, + dp_panel->dsc_en, true); + if (rc) + goto end; + +end: + mutex_unlock(&dp->session_lock); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + return rc; +} + +static int dp_display_set_stream_info(struct dp_display *dp_display, + void *panel, u32 strm_id, u32 start_slot, + u32 num_slots, u32 pbn, int vcpi) +{ + int rc = 0; + struct dp_panel *dp_panel; + struct dp_display_private *dp; + const int max_slots = 64; + + if (!dp_display) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (strm_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id:%d\n", strm_id); + return -EINVAL; + } + + if (start_slot + num_slots > max_slots) { + DP_ERR("invalid channel info received. start:%d, slots:%d\n", + start_slot, num_slots); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + dp->ctrl->set_mst_channel_info(dp->ctrl, strm_id, + start_slot, num_slots); + + if (panel) { + dp_panel = panel; + dp_panel->set_stream_info(dp_panel, strm_id, start_slot, + num_slots, pbn, vcpi); + } + + mutex_unlock(&dp->session_lock); + + return rc; +} + +static void dp_display_update_dsc_resources(struct dp_display_private *dp, + struct dp_panel *panel, bool enable) +{ + u32 dsc_blk_cnt = 0; + + if (panel->pinfo.comp_info.comp_type == MSM_DISPLAY_COMPRESSION_DSC && + panel->pinfo.comp_info.comp_ratio) { + dsc_blk_cnt = panel->pinfo.h_active / + dp->parser->max_dp_dsc_input_width_pixs; + if (panel->pinfo.h_active % + dp->parser->max_dp_dsc_input_width_pixs) + dsc_blk_cnt++; + } + + if (enable) { + dp->tot_dsc_blks_in_use += dsc_blk_cnt; + panel->tot_dsc_blks_in_use += dsc_blk_cnt; + } else { + dp->tot_dsc_blks_in_use -= dsc_blk_cnt; + panel->tot_dsc_blks_in_use -= dsc_blk_cnt; + } +} + +static int dp_display_enable(struct dp_display *dp_display, void *panel) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + /* + * If DP_STATE_READY is not set, we should not do any HW + * programming. + */ + if (!dp_display_state_is(DP_STATE_READY)) { + dp_display_state_show("[host not ready]"); + goto end; + } + + /* + * It is possible that by the time we get call back to establish + * the DP pipeline e2e, the physical DP connection to the sink is + * already lost. In such cases, the DP_STATE_ABORTED would be set. + * However, it is necessary to NOT abort the display setup here so as + * to ensure that the rest of the system is in a stable state prior to + * handling the disconnect notification. + */ + if (dp_display_state_is(DP_STATE_ABORTED)) + dp_display_state_log("[aborted, but continue on]"); + + rc = dp_display_stream_enable(dp, panel); + if (rc) + goto end; + + dp_display_update_dsc_resources(dp, panel, true); + dp_display_state_add(DP_STATE_ENABLED); +end: + mutex_unlock(&dp->session_lock); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + return rc; +} + +static void dp_display_stream_post_enable(struct dp_display_private *dp, + struct dp_panel *dp_panel) +{ + dp_panel->spd_config(dp_panel); + dp_panel->setup_hdr(dp_panel, NULL, false, 0, true); +} + +static int dp_display_post_enable(struct dp_display *dp_display, void *panel) +{ + struct dp_display_private *dp; + struct dp_panel *dp_panel; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + dp_panel = panel; + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + /* + * If DP_STATE_READY is not set, we should not do any HW + * programming. + */ + if (!dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[not enabled]"); + goto end; + } + + /* + * If the physical connection to the sink is already lost by the time + * we try to set up the connection, we can just skip all the steps + * here safely. + */ + if (dp_display_state_is(DP_STATE_ABORTED)) { + dp_display_state_log("[aborted]"); + goto end; + } + + if (!dp_display_is_ready(dp) || !dp_display_state_is(DP_STATE_READY)) { + dp_display_state_show("[not ready]"); + goto end; + } + + dp_display_stream_post_enable(dp, dp_panel); + + cancel_delayed_work_sync(&dp->hdcp_cb_work); + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); + + if (dp_panel->audio_supported) { + dp_panel->audio->bw_code = dp->link->link_params.bw_code; + dp_panel->audio->lane_count = dp->link->link_params.lane_count; + dp_panel->audio->on(dp_panel->audio); + } +end: + dp->aux->state |= DP_STATE_CTRL_POWERED_ON; + + complete_all(&dp->notification_comp); + mutex_unlock(&dp->session_lock); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + return 0; +} + +static void dp_display_clear_colorspaces(struct dp_display *dp_display) +{ + struct drm_connector *connector; + + connector = dp_display->base_connector; + connector->color_enc_fmt = 0; +} + +static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) +{ + struct dp_display_private *dp; + struct dp_panel *dp_panel = panel; + struct dp_link_hdcp_status *status; + int rc = 0; + size_t i; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + status = &dp->link->hdcp_status; + + if (!dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[not enabled]"); + goto end; + } + + dp_display_state_add(DP_STATE_HDCP_ABORTED); + cancel_delayed_work_sync(&dp->hdcp_cb_work); + if (dp_display_is_hdcp_enabled(dp) && + status->hdcp_state != HDCP_STATE_INACTIVE) { + bool off = true; + + if (dp_display_state_is(DP_STATE_SUSPENDED)) { + DP_DEBUG("Can't perform HDCP cleanup while suspended. Defer\n"); + dp->hdcp_delayed_off = true; + goto clean; + } + + flush_delayed_work(&dp->hdcp_cb_work); + if (dp->mst.mst_active) { + dp_display_hdcp_deregister_stream(dp, + dp_panel->stream_id); + for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { + if (i != dp_panel->stream_id && + dp->active_panels[i]) { + DP_DEBUG("Streams are still active. Skip disabling HDCP\n"); + off = false; + } + } + } + + if (off) { + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + dp_display_update_hdcp_status(dp, true); + } + } + + dp_display_clear_colorspaces(dp_display); + +clean: + if (dp_panel->audio_supported) + dp_panel->audio->off(dp_panel->audio); + + rc = dp_display_stream_pre_disable(dp, dp_panel); + +end: + mutex_unlock(&dp->session_lock); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + return 0; +} + +static int dp_display_disable(struct dp_display *dp_display, void *panel) +{ + int i; + struct dp_display_private *dp = NULL; + struct dp_panel *dp_panel = NULL; + struct dp_link_hdcp_status *status; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + dp_panel = panel; + status = &dp->link->hdcp_status; + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + if (!dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[not enabled]"); + goto end; + } + + if (!dp_display_state_is(DP_STATE_READY)) { + dp_display_state_show("[not ready]"); + goto end; + } + + dp_display_stream_disable(dp, dp_panel); + dp_display_update_dsc_resources(dp, dp_panel, false); + + dp_display_state_remove(DP_STATE_HDCP_ABORTED); + for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { + if (dp->active_panels[i]) { + if (status->hdcp_state != HDCP_STATE_AUTHENTICATED) + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, + HZ/4); + break; + } + } +end: + mutex_unlock(&dp->session_lock); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + return 0; +} + +static int dp_request_irq(struct dp_display *dp_display) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0); + if (dp->irq < 0) { + rc = dp->irq; + DP_ERR("failed to get irq: %d\n", rc); + return rc; + } + + rc = devm_request_irq(&dp->pdev->dev, dp->irq, dp_display_irq, + IRQF_TRIGGER_HIGH, "dp_display_isr", dp); + if (rc < 0) { + DP_ERR("failed to request IRQ%u: %d\n", + dp->irq, rc); + return rc; + } + disable_irq(dp->irq); + + return 0; +} + +static struct dp_debug *dp_get_debug(struct dp_display *dp_display) +{ + struct dp_display_private *dp; + + if (!dp_display) { + DP_ERR("invalid input\n"); + return ERR_PTR(-EINVAL); + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + return dp->debug; +} + +static int dp_display_unprepare(struct dp_display *dp_display, void *panel) +{ + struct dp_display_private *dp; + struct dp_panel *dp_panel = panel; + u32 flags = 0; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); + mutex_lock(&dp->session_lock); + + /* + * Check if the power off sequence was triggered + * by a source initialated action like framework + * reboot or suspend-resume but not from normal + * hot plug. If connector is in MST mode, skip + * powering down host as aux needs to be kept + * alive to handle hot-plug sideband message. + */ + if (dp_display_is_ready(dp) && + (dp_display_state_is(DP_STATE_SUSPENDED) || + !dp->mst.mst_active)) + flags |= DP_PANEL_SRC_INITIATED_POWER_DOWN; + + if (dp->active_stream_cnt) + goto end; + + if (flags & DP_PANEL_SRC_INITIATED_POWER_DOWN) { + dp->link->psm_config(dp->link, &dp->panel->link_info, true); + dp->debug->psm_enabled = true; + + dp->ctrl->off(dp->ctrl); + dp_display_host_unready(dp); + dp_display_host_deinit(dp); + dp_display_state_add(DP_STATE_SRC_PWRDN); + } + + dp_display_state_remove(DP_STATE_ENABLED); + dp->aux->state = DP_STATE_CTRL_POWERED_OFF; + + complete_all(&dp->notification_comp); + + /* log this as it results from user action of cable dis-connection */ + DP_INFO("[OK]\n"); +end: + dp_panel->deinit(dp_panel, flags); + mutex_unlock(&dp->session_lock); + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); + + return 0; +} + +static enum drm_mode_status dp_display_validate_mode( + struct dp_display *dp_display, + void *panel, struct drm_display_mode *mode, + const struct msm_resource_caps_info *avail_res) +{ + struct dp_display_private *dp; + struct drm_dp_link *link_info; + u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; + struct dp_panel *dp_panel; + struct dp_debug *debug; + enum drm_mode_status mode_status = MODE_BAD; + bool in_list = false; + struct dp_mst_connector *mst_connector; + int hdis, vdis, vref, ar, _hdis, _vdis, _vref, _ar, rate; + struct dp_display_mode dp_mode; + bool dsc_en; + u32 num_lm = 0; + int rc = 0, tmds_max_clock = 0; + + if (!dp_display || !mode || !panel || + !avail_res || !avail_res->max_mixer_width) { + DP_ERR("invalid params\n"); + return mode_status; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + dp_panel = panel; + if (!dp_panel->connector) { + DP_ERR("invalid connector\n"); + goto end; + } + + link_info = &dp->panel->link_info; + + debug = dp->debug; + if (!debug) + goto end; + + dp_display->convert_to_dp_mode(dp_display, panel, mode, &dp_mode); + + dsc_en = dp_mode.timing.comp_info.comp_ratio ? true : false; + mode_bpp = dsc_en ? dp_mode.timing.comp_info.dsc_info.bpp : + dp_mode.timing.bpp; + + mode_rate_khz = mode->clock * mode_bpp; + rate = drm_dp_bw_code_to_link_rate(dp->link->link_params.bw_code); + supported_rate_khz = link_info->num_lanes * rate * 8; + tmds_max_clock = dp_panel->connector->display_info.max_tmds_clock; + + if (mode_rate_khz > supported_rate_khz) { + DP_MST_DEBUG("pclk:%d, supported_rate:%d\n", + mode->clock, supported_rate_khz); + goto end; + } + + if (mode->clock > dp_display->max_pclk_khz) { + DP_MST_DEBUG("clk:%d, max:%d\n", mode->clock, + dp_display->max_pclk_khz); + goto end; + } + + if (tmds_max_clock > 0 && mode->clock > tmds_max_clock) { + DP_MST_DEBUG("clk:%d, max tmds:%d\n", mode->clock, + tmds_max_clock); + goto end; + } + + rc = msm_get_mixer_count(dp->priv, mode, avail_res, &num_lm); + if (rc) { + DP_ERR("error getting mixer count. rc:%d\n", rc); + goto end; + } + + if (num_lm > avail_res->num_lm || + (num_lm == 2 && !avail_res->num_3dmux)) { + DP_MST_DEBUG("num_lm:%d, req lm:%d 3dmux:%d\n", num_lm, + avail_res->num_lm, avail_res->num_3dmux); + goto end; + } + + /* + * If the connector exists in the mst connector list and if debug is + * enabled for that connector, use the mst connector settings from the + * list for validation. Otherwise, use non-mst default settings. + */ + mutex_lock(&debug->dp_mst_connector_list.lock); + + if (list_empty(&debug->dp_mst_connector_list.list)) { + mutex_unlock(&debug->dp_mst_connector_list.lock); + goto verify_default; + } + + list_for_each_entry(mst_connector, &debug->dp_mst_connector_list.list, + list) { + if (mst_connector->con_id == dp_panel->connector->base.id) { + in_list = true; + + if (!mst_connector->debug_en) { + mode_status = MODE_OK; + mutex_unlock( + &debug->dp_mst_connector_list.lock); + goto end; + } + + hdis = mst_connector->hdisplay; + vdis = mst_connector->vdisplay; + vref = mst_connector->vrefresh; + ar = mst_connector->aspect_ratio; + + _hdis = mode->hdisplay; + _vdis = mode->vdisplay; + _vref = mode->vrefresh; + _ar = mode->picture_aspect_ratio; + + if (hdis == _hdis && vdis == _vdis && vref == _vref && + ar == _ar) { + mode_status = MODE_OK; + mutex_unlock( + &debug->dp_mst_connector_list.lock); + goto end; + } + + break; + } + } + + mutex_unlock(&debug->dp_mst_connector_list.lock); + + if (in_list) + goto end; + +verify_default: + if (debug->debug_en && (mode->hdisplay != debug->hdisplay || + mode->vdisplay != debug->vdisplay || + mode->vrefresh != debug->vrefresh || + mode->picture_aspect_ratio != debug->aspect_ratio)) + goto end; + + mode_status = MODE_OK; +end: + mutex_unlock(&dp->session_lock); + return mode_status; +} + +static int dp_display_get_modes(struct dp_display *dp, void *panel, + struct dp_display_mode *dp_mode) +{ + struct dp_display_private *dp_display; + struct dp_panel *dp_panel; + int ret = 0; + + if (!dp || !panel) { + DP_ERR("invalid params\n"); + return 0; + } + + dp_panel = panel; + if (!dp_panel->connector) { + DP_ERR("invalid connector\n"); + return 0; + } + + dp_display = container_of(dp, struct dp_display_private, dp_display); + + ret = dp_panel->get_modes(dp_panel, dp_panel->connector, dp_mode); + if (dp_mode->timing.pixel_clk_khz) + dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz; + return ret; +} + +static void dp_display_convert_to_dp_mode(struct dp_display *dp_display, + void *panel, + const struct drm_display_mode *drm_mode, + struct dp_display_mode *dp_mode) +{ + struct dp_display_private *dp; + struct dp_panel *dp_panel; + u32 free_dsc_blks = 0, required_dsc_blks = 0; + + if (!dp_display || !drm_mode || !dp_mode || !panel) { + DP_ERR("invalid input\n"); + return; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + dp_panel = panel; + + memset(dp_mode, 0, sizeof(*dp_mode)); + + free_dsc_blks = dp->parser->max_dp_dsc_blks - + dp->tot_dsc_blks_in_use + + dp_panel->tot_dsc_blks_in_use; + required_dsc_blks = drm_mode->hdisplay / + dp->parser->max_dp_dsc_input_width_pixs; + if (drm_mode->hdisplay % dp->parser->max_dp_dsc_input_width_pixs) + required_dsc_blks++; + + if (free_dsc_blks >= required_dsc_blks) + dp_mode->capabilities |= DP_PANEL_CAPS_DSC; + + if (dp_mode->capabilities & DP_PANEL_CAPS_DSC) + DP_DEBUG("in_use:%d, max:%d, free:%d, req:%d, caps:0x%x, width:%d\n", + dp->tot_dsc_blks_in_use, dp->parser->max_dp_dsc_blks, + free_dsc_blks, required_dsc_blks, dp_mode->capabilities, + dp->parser->max_dp_dsc_input_width_pixs); + + dp_panel->convert_to_dp_mode(dp_panel, drm_mode, dp_mode); +} + +static int dp_display_config_hdr(struct dp_display *dp_display, void *panel, + struct drm_msm_ext_hdr_metadata *hdr, bool dhdr_update) +{ + struct dp_panel *dp_panel; + struct sde_connector *sde_conn; + struct dp_display_private *dp; + u64 core_clk_rate; + bool flush_hdr; + + if (!dp_display || !panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp_panel = panel; + dp = container_of(dp_display, struct dp_display_private, dp_display); + sde_conn = to_sde_connector(dp_panel->connector); + + core_clk_rate = dp->power->clk_get_rate(dp->power, "core_clk"); + if (!core_clk_rate) { + DP_ERR("invalid rate for core_clk\n"); + return -EINVAL; + } + + if (!dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[not enabled]"); + return 0; + } + + /* + * In rare cases where HDR metadata is updated independently + * flush the HDR metadata immediately instead of relying on + * the colorspace + */ + flush_hdr = !sde_conn->colorspace_updated; + + if (flush_hdr) + DP_DEBUG("flushing the HDR metadata\n"); + else + DP_DEBUG("piggy-backing with colorspace\n"); + + return dp_panel->setup_hdr(dp_panel, hdr, dhdr_update, + core_clk_rate, flush_hdr); +} + +static int dp_display_setup_colospace(struct dp_display *dp_display, + void *panel, + u32 colorspace) +{ + struct dp_panel *dp_panel; + struct dp_display_private *dp; + + if (!dp_display || !panel) { + pr_err("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + if (!dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[not enabled]"); + return 0; + } + + dp_panel = panel; + + return dp_panel->set_colorspace(dp_panel, colorspace); +} + +static int dp_display_create_workqueue(struct dp_display_private *dp) +{ + dp->wq = create_singlethread_workqueue("drm_dp"); + if (IS_ERR_OR_NULL(dp->wq)) { + DP_ERR("Error creating wq\n"); + return -EPERM; + } + + INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work); + INIT_WORK(&dp->connect_work, dp_display_connect_work); + INIT_WORK(&dp->attention_work, dp_display_attention_work); + + return 0; +} + +static int dp_display_fsa4480_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + return 0; +} + +static int dp_display_init_aux_switch(struct dp_display_private *dp) +{ + int rc = 0; + const char *phandle = "qcom,dp-aux-switch"; + struct notifier_block nb; + + if (!dp->pdev->dev.of_node) { + DP_ERR("cannot find dev.of_node\n"); + rc = -ENODEV; + goto end; + } + + dp->aux_switch_node = of_parse_phandle(dp->pdev->dev.of_node, + phandle, 0); + if (!dp->aux_switch_node) { + DP_WARN("cannot parse %s handle\n", phandle); + rc = -ENODEV; + goto end; + } + + nb.notifier_call = dp_display_fsa4480_callback; + nb.priority = 0; + + rc = fsa4480_reg_notifier(&nb, dp->aux_switch_node); + if (rc) { + DP_ERR("failed to register notifier (%d)\n", rc); + goto end; + } + + fsa4480_unreg_notifier(&nb, dp->aux_switch_node); +end: + return rc; +} + +static int dp_display_mst_install(struct dp_display *dp_display, + struct dp_mst_drm_install_info *mst_install_info) +{ + struct dp_display_private *dp; + + if (!dp_display || !mst_install_info) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + if (!mst_install_info->cbs->hpd || !mst_install_info->cbs->hpd_irq) { + DP_ERR("invalid mst cbs\n"); + return -EINVAL; + } + + dp_display->dp_mst_prv_info = mst_install_info->dp_mst_prv_info; + + if (!dp->parser->has_mst) { + DP_DEBUG("mst not enabled\n"); + return -EPERM; + } + + memcpy(&dp->mst.cbs, mst_install_info->cbs, sizeof(dp->mst.cbs)); + dp->mst.drm_registered = true; + + DP_MST_DEBUG("dp mst drm installed\n"); + + return 0; +} + +static int dp_display_mst_uninstall(struct dp_display *dp_display) +{ + struct dp_display_private *dp; + + if (!dp_display) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + return -EPERM; + } + + dp = container_of(dp_display, struct dp_display_private, + dp_display); + memset(&dp->mst.cbs, 0, sizeof(dp->mst.cbs)); + dp->mst.drm_registered = false; + + DP_MST_DEBUG("dp mst drm uninstalled\n"); + + return 0; +} + +static int dp_display_mst_connector_install(struct dp_display *dp_display, + struct drm_connector *connector) +{ + int rc = 0; + struct dp_panel_in panel_in; + struct dp_panel *dp_panel; + struct dp_display_private *dp; + struct dp_mst_connector *mst_connector; + + if (!dp_display || !connector) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + mutex_unlock(&dp->session_lock); + return -EPERM; + } + + panel_in.dev = &dp->pdev->dev; + panel_in.aux = dp->aux; + panel_in.catalog = &dp->catalog->panel; + panel_in.link = dp->link; + panel_in.connector = connector; + panel_in.base_panel = dp->panel; + panel_in.parser = dp->parser; + + dp_panel = dp_panel_get(&panel_in); + if (IS_ERR(dp_panel)) { + rc = PTR_ERR(dp_panel); + DP_ERR("failed to initialize panel, rc = %d\n", rc); + mutex_unlock(&dp->session_lock); + return rc; + } + + dp_panel->audio = dp_audio_get(dp->pdev, dp_panel, &dp->catalog->audio); + if (IS_ERR(dp_panel->audio)) { + rc = PTR_ERR(dp_panel->audio); + DP_ERR("[mst] failed to initialize audio, rc = %d\n", rc); + dp_panel->audio = NULL; + mutex_unlock(&dp->session_lock); + return rc; + } + + DP_MST_DEBUG("dp mst connector installed. conn:%d\n", + connector->base.id); + + mutex_lock(&dp->debug->dp_mst_connector_list.lock); + + mst_connector = kmalloc(sizeof(struct dp_mst_connector), + GFP_KERNEL); + if (!mst_connector) { + mutex_unlock(&dp->debug->dp_mst_connector_list.lock); + mutex_unlock(&dp->session_lock); + return -ENOMEM; + } + + mst_connector->debug_en = false; + mst_connector->conn = connector; + mst_connector->con_id = connector->base.id; + mst_connector->state = connector_status_unknown; + INIT_LIST_HEAD(&mst_connector->list); + + list_add(&mst_connector->list, + &dp->debug->dp_mst_connector_list.list); + + mutex_unlock(&dp->debug->dp_mst_connector_list.lock); + mutex_unlock(&dp->session_lock); + + return 0; +} + +static int dp_display_mst_connector_uninstall(struct dp_display *dp_display, + struct drm_connector *connector) +{ + int rc = 0; + struct sde_connector *sde_conn; + struct dp_panel *dp_panel; + struct dp_display_private *dp; + struct dp_mst_connector *con_to_remove, *temp_con; + + if (!dp_display || !connector) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + mutex_unlock(&dp->session_lock); + return -EPERM; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid panel for connector:%d\n", connector->base.id); + mutex_unlock(&dp->session_lock); + return -EINVAL; + } + + dp_panel = sde_conn->drv_panel; + dp_audio_put(dp_panel->audio); + dp_panel_put(dp_panel); + + DP_MST_DEBUG("dp mst connector uninstalled. conn:%d\n", + connector->base.id); + + mutex_lock(&dp->debug->dp_mst_connector_list.lock); + + list_for_each_entry_safe(con_to_remove, temp_con, + &dp->debug->dp_mst_connector_list.list, list) { + if (con_to_remove->conn == connector) { + list_del(&con_to_remove->list); + kfree(con_to_remove); + } + } + + mutex_unlock(&dp->debug->dp_mst_connector_list.lock); + mutex_unlock(&dp->session_lock); + + return rc; +} + +static int dp_display_mst_get_connector_info(struct dp_display *dp_display, + struct drm_connector *connector, + struct dp_mst_connector *mst_conn) +{ + struct dp_display_private *dp; + struct dp_mst_connector *conn, *temp_conn; + + if (!connector || !mst_conn) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + mutex_unlock(&dp->session_lock); + return -EPERM; + } + + mutex_lock(&dp->debug->dp_mst_connector_list.lock); + list_for_each_entry_safe(conn, temp_conn, + &dp->debug->dp_mst_connector_list.list, list) { + if (conn->con_id == connector->base.id) + memcpy(mst_conn, conn, sizeof(*mst_conn)); + } + mutex_unlock(&dp->debug->dp_mst_connector_list.lock); + mutex_unlock(&dp->session_lock); + return 0; +} + +static int dp_display_mst_connector_update_edid(struct dp_display *dp_display, + struct drm_connector *connector, + struct edid *edid) +{ + int rc = 0; + struct sde_connector *sde_conn; + struct dp_panel *dp_panel; + struct dp_display_private *dp; + + if (!dp_display || !connector || !edid) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + return -EPERM; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid panel for connector:%d\n", connector->base.id); + return -EINVAL; + } + + dp_panel = sde_conn->drv_panel; + rc = dp_panel->update_edid(dp_panel, edid); + + DP_MST_DEBUG("dp mst connector:%d edid updated. mode_cnt:%d\n", + connector->base.id, rc); + + return rc; +} + +static int dp_display_update_pps(struct dp_display *dp_display, + struct drm_connector *connector, char *pps_cmd) +{ + struct sde_connector *sde_conn; + struct dp_panel *dp_panel; + struct dp_display_private *dp; + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid panel for connector:%d\n", connector->base.id); + return -EINVAL; + } + + if (!dp_display_state_is(DP_STATE_ENABLED)) { + dp_display_state_show("[not enabled]"); + return 0; + } + + dp_panel = sde_conn->drv_panel; + dp_panel->update_pps(dp_panel, pps_cmd); + return 0; +} + +static int dp_display_mst_connector_update_link_info( + struct dp_display *dp_display, + struct drm_connector *connector) +{ + int rc = 0; + struct sde_connector *sde_conn; + struct dp_panel *dp_panel; + struct dp_display_private *dp; + + if (!dp_display || !connector) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + return -EPERM; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid panel for connector:%d\n", connector->base.id); + return -EINVAL; + } + + dp_panel = sde_conn->drv_panel; + + memcpy(dp_panel->dpcd, dp->panel->dpcd, + DP_RECEIVER_CAP_SIZE + 1); + memcpy(dp_panel->dsc_dpcd, dp->panel->dsc_dpcd, + DP_RECEIVER_DSC_CAP_SIZE + 1); + memcpy(&dp_panel->link_info, &dp->panel->link_info, + sizeof(dp_panel->link_info)); + + DP_MST_DEBUG("dp mst connector:%d link info updated\n", + connector->base.id); + + return rc; +} + +static int dp_display_mst_get_fixed_topology_port( + struct dp_display *dp_display, + u32 strm_id, u32 *port_num) +{ + struct dp_display_private *dp; + u32 port; + + if (!dp_display) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (strm_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id:%d\n", strm_id); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + port = dp->parser->mst_fixed_port[strm_id]; + + if (!port || port > 255) + return -ENOENT; + + if (port_num) + *port_num = port; + + return 0; +} + +static int dp_display_get_mst_caps(struct dp_display *dp_display, + struct dp_mst_caps *mst_caps) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!dp_display || !mst_caps) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + + mst_caps->has_mst = dp->parser->has_mst; + mst_caps->max_streams_supported = (mst_caps->has_mst) ? 2 : 0; + mst_caps->max_dpcd_transaction_bytes = (mst_caps->has_mst) ? 16 : 0; + mst_caps->drm_aux = dp->aux->drm_aux; + + return rc; +} + +static void dp_display_wakeup_phy_layer(struct dp_display *dp_display, + bool wakeup) +{ + struct dp_display_private *dp; + struct dp_hpd *hpd; + + if (!dp_display) { + DP_ERR("invalid input\n"); + return; + } + + dp = container_of(dp_display, struct dp_display_private, dp_display); + if (!dp->mst.drm_registered) { + DP_DEBUG("drm mst not registered\n"); + return; + } + + hpd = dp->hpd; + if (hpd && hpd->wakeup_phy) + hpd->wakeup_phy(hpd, wakeup); +} + +static int dp_display_probe(struct platform_device *pdev) +{ + int rc = 0; + struct dp_display_private *dp; + + if (!pdev || !pdev->dev.of_node) { + DP_ERR("pdev not found\n"); + rc = -ENODEV; + goto bail; + } + + dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL); + if (!dp) { + rc = -ENOMEM; + goto bail; + } + + init_completion(&dp->notification_comp); + + dp->pdev = pdev; + dp->name = "drm_dp"; + + memset(&dp->mst, 0, sizeof(dp->mst)); + + rc = dp_display_init_aux_switch(dp); + if (rc) { + rc = -EPROBE_DEFER; + goto error; + } + + rc = dp_display_create_workqueue(dp); + if (rc) { + DP_ERR("Failed to create workqueue\n"); + goto error; + } + + platform_set_drvdata(pdev, dp); + + g_dp_display = &dp->dp_display; + + g_dp_display->enable = dp_display_enable; + g_dp_display->post_enable = dp_display_post_enable; + g_dp_display->pre_disable = dp_display_pre_disable; + g_dp_display->disable = dp_display_disable; + g_dp_display->set_mode = dp_display_set_mode; + g_dp_display->validate_mode = dp_display_validate_mode; + g_dp_display->get_modes = dp_display_get_modes; + g_dp_display->prepare = dp_display_prepare; + g_dp_display->unprepare = dp_display_unprepare; + g_dp_display->request_irq = dp_request_irq; + g_dp_display->get_debug = dp_get_debug; + g_dp_display->post_open = NULL; + g_dp_display->post_init = dp_display_post_init; + g_dp_display->config_hdr = dp_display_config_hdr; + g_dp_display->mst_install = dp_display_mst_install; + g_dp_display->mst_uninstall = dp_display_mst_uninstall; + g_dp_display->mst_connector_install = dp_display_mst_connector_install; + g_dp_display->mst_connector_uninstall = + dp_display_mst_connector_uninstall; + g_dp_display->mst_connector_update_edid = + dp_display_mst_connector_update_edid; + g_dp_display->mst_connector_update_link_info = + dp_display_mst_connector_update_link_info; + g_dp_display->get_mst_caps = dp_display_get_mst_caps; + g_dp_display->set_stream_info = dp_display_set_stream_info; + g_dp_display->update_pps = dp_display_update_pps; + g_dp_display->convert_to_dp_mode = dp_display_convert_to_dp_mode; + g_dp_display->mst_get_connector_info = + dp_display_mst_get_connector_info; + g_dp_display->mst_get_fixed_topology_port = + dp_display_mst_get_fixed_topology_port; + g_dp_display->wakeup_phy_layer = + dp_display_wakeup_phy_layer; + g_dp_display->set_colorspace = dp_display_setup_colospace; + + rc = component_add(&pdev->dev, &dp_display_comp_ops); + if (rc) { + DP_ERR("component add failed, rc=%d\n", rc); + goto error; + } + + return 0; +error: + devm_kfree(&pdev->dev, dp); +bail: + return rc; +} + +int dp_display_get_displays(void **displays, int count) +{ + if (!displays) { + DP_ERR("invalid data\n"); + return -EINVAL; + } + + if (count != 1) { + DP_ERR("invalid number of displays\n"); + return -EINVAL; + } + + displays[0] = g_dp_display; + return count; +} + +int dp_display_get_num_of_displays(void) +{ + if (!g_dp_display) + return 0; + + return 1; +} + +int dp_display_get_num_of_streams(void) +{ + if (g_dp_display->no_mst_encoder) + return 0; + + return DP_STREAM_MAX; +} + +static void dp_display_set_mst_state(void *dp_display, + enum dp_drv_state mst_state) +{ + struct dp_display_private *dp; + + if (!g_dp_display) { + DP_DEBUG("dp display not initialized\n"); + return; + } + + dp = container_of(g_dp_display, struct dp_display_private, dp_display); + if (dp->mst.mst_active && dp->mst.cbs.set_drv_state) + dp->mst.cbs.set_drv_state(g_dp_display, mst_state); +} + +static int dp_display_remove(struct platform_device *pdev) +{ + struct dp_display_private *dp; + + if (!pdev) + return -EINVAL; + + dp = platform_get_drvdata(pdev); + + dp_display_deinit_sub_modules(dp); + + if (dp->wq) + destroy_workqueue(dp->wq); + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, dp); + + return 0; +} + +static int dp_pm_prepare(struct device *dev) +{ + struct dp_display_private *dp = container_of(g_dp_display, + struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + dp_display_set_mst_state(g_dp_display, PM_SUSPEND); + + /* + * There are a few instances where the DP is hotplugged when the device + * is in PM suspend state. After hotplug, it is observed the device + * enters and exits the PM suspend multiple times while aux transactions + * are taking place. This may sometimes cause an unclocked register + * access error. So, abort aux transactions when such a situation + * arises i.e. when DP is connected but display not enabled yet. + */ + if (dp_display_state_is(DP_STATE_CONNECTED) && + !dp_display_state_is(DP_STATE_ENABLED)) { + dp->aux->abort(dp->aux, true); + dp->ctrl->abort(dp->ctrl, true); + } + + dp_display_state_add(DP_STATE_SUSPENDED); + mutex_unlock(&dp->session_lock); + + return 0; +} + +static void dp_pm_complete(struct device *dev) +{ + struct dp_display_private *dp = container_of(g_dp_display, + struct dp_display_private, dp_display); + + mutex_lock(&dp->session_lock); + dp_display_set_mst_state(g_dp_display, PM_DEFAULT); + + /* + * There are multiple PM suspend entry and exits observed before + * the connect uevent is issued to userspace. The aux transactions are + * aborted during PM suspend entry in dp_pm_prepare to prevent unclocked + * register access. On PM suspend exit, there will be no host_init call + * to reset the abort flags for ctrl and aux incase DP is connected + * but display not enabled. So, resetting abort flags for aux and ctrl. + */ + if (dp_display_state_is(DP_STATE_CONNECTED) && + !dp_display_state_is(DP_STATE_ENABLED)) { + dp->aux->abort(dp->aux, false); + dp->ctrl->abort(dp->ctrl, false); + } + + dp_display_state_remove(DP_STATE_SUSPENDED); + mutex_unlock(&dp->session_lock); +} + +static const struct dev_pm_ops dp_pm_ops = { + .prepare = dp_pm_prepare, + .complete = dp_pm_complete, +}; + +static struct platform_driver dp_display_driver = { + .probe = dp_display_probe, + .remove = dp_display_remove, + .driver = { + .name = "msm-dp-display", + .of_match_table = dp_dt_match, + .suppress_bind_attrs = true, + .pm = &dp_pm_ops, + }, +}; + +static int __init dp_display_init(void) +{ + int ret; + + ret = platform_driver_register(&dp_display_driver); + if (ret) { + DP_ERR("driver register failed\n"); + return ret; + } + + return ret; +} +late_initcall(dp_display_init); + +static void __exit dp_display_cleanup(void) +{ + platform_driver_unregister(&dp_display_driver); +} +module_exit(dp_display_cleanup); diff --git a/techpack/display/msm/dp/dp_display.h b/techpack/display/msm/dp/dp_display.h new file mode 100644 index 0000000000000000000000000000000000000000..ebfeb1d674238f28f8c5ba4d600488a235f76e37 --- /dev/null +++ b/techpack/display/msm/dp/dp_display.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_DISPLAY_H_ +#define _DP_DISPLAY_H_ + +#include <linux/list.h> +#include <drm/drmP.h> +#include <drm/msm_drm.h> + +#include "dp_panel.h" + +#define DP_MST_SIM_MAX_PORTS 8 + +enum dp_drv_state { + PM_DEFAULT, + PM_SUSPEND, +}; + +struct dp_mst_hpd_info { + bool mst_protocol; + bool mst_hpd_sim; + u32 mst_port_cnt; + u8 *edid; + bool mst_sim_add_con; + bool mst_sim_remove_con; + int mst_sim_remove_con_id; +}; + +struct dp_mst_drm_cbs { + void (*hpd)(void *display, bool hpd_status, + struct dp_mst_hpd_info *info); + void (*hpd_irq)(void *display, struct dp_mst_hpd_info *info); + void (*set_drv_state)(void *dp_display, + enum dp_drv_state mst_state); +}; + +struct dp_mst_drm_install_info { + void *dp_mst_prv_info; + const struct dp_mst_drm_cbs *cbs; +}; + +struct dp_mst_caps { + bool has_mst; + u32 max_streams_supported; + u32 max_dpcd_transaction_bytes; + struct drm_dp_aux *drm_aux; +}; + +struct dp_mst_connector { + bool debug_en; + int con_id; + int hdisplay; + int vdisplay; + int vrefresh; + int aspect_ratio; + struct drm_connector *conn; + struct mutex lock; + struct list_head list; + enum drm_connector_status state; +}; + +struct dp_display { + struct drm_device *drm_dev; + struct dp_bridge *bridge; + struct drm_connector *base_connector; + void *base_dp_panel; + bool is_sst_connected; + bool is_mst_supported; + u32 max_pclk_khz; + u32 no_mst_encoder; + void *dp_mst_prv_info; + + int (*enable)(struct dp_display *dp_display, void *panel); + int (*post_enable)(struct dp_display *dp_display, void *panel); + + int (*pre_disable)(struct dp_display *dp_display, void *panel); + int (*disable)(struct dp_display *dp_display, void *panel); + + int (*set_mode)(struct dp_display *dp_display, void *panel, + struct dp_display_mode *mode); + enum drm_mode_status (*validate_mode)(struct dp_display *dp_display, + void *panel, struct drm_display_mode *mode, + const struct msm_resource_caps_info *avail_res); + int (*get_modes)(struct dp_display *dp_display, void *panel, + struct dp_display_mode *dp_mode); + int (*prepare)(struct dp_display *dp_display, void *panel); + int (*unprepare)(struct dp_display *dp_display, void *panel); + int (*request_irq)(struct dp_display *dp_display); + struct dp_debug *(*get_debug)(struct dp_display *dp_display); + void (*post_open)(struct dp_display *dp_display); + int (*config_hdr)(struct dp_display *dp_display, void *panel, + struct drm_msm_ext_hdr_metadata *hdr_meta, + bool dhdr_update); + int (*set_colorspace)(struct dp_display *dp_display, void *panel, + u32 colorspace); + int (*post_init)(struct dp_display *dp_display); + int (*mst_install)(struct dp_display *dp_display, + struct dp_mst_drm_install_info *mst_install_info); + int (*mst_uninstall)(struct dp_display *dp_display); + int (*mst_connector_install)(struct dp_display *dp_display, + struct drm_connector *connector); + int (*mst_connector_uninstall)(struct dp_display *dp_display, + struct drm_connector *connector); + int (*mst_connector_update_edid)(struct dp_display *dp_display, + struct drm_connector *connector, + struct edid *edid); + int (*mst_connector_update_link_info)(struct dp_display *dp_display, + struct drm_connector *connector); + int (*mst_get_connector_info)(struct dp_display *dp_display, + struct drm_connector *connector, + struct dp_mst_connector *mst_conn); + int (*mst_get_fixed_topology_port)(struct dp_display *dp_display, + u32 strm_id, u32 *port_num); + int (*get_mst_caps)(struct dp_display *dp_display, + struct dp_mst_caps *mst_caps); + int (*set_stream_info)(struct dp_display *dp_display, void *panel, + u32 strm_id, u32 start_slot, u32 num_slots, u32 pbn, + int vcpi); + void (*convert_to_dp_mode)(struct dp_display *dp_display, void *panel, + const struct drm_display_mode *drm_mode, + struct dp_display_mode *dp_mode); + int (*update_pps)(struct dp_display *dp_display, + struct drm_connector *connector, char *pps_cmd); + void (*wakeup_phy_layer)(struct dp_display *dp_display, + bool wakeup); +}; + +#ifdef CONFIG_DRM_MSM_DP +int dp_display_get_num_of_displays(void); +int dp_display_get_displays(void **displays, int count); +int dp_display_get_num_of_streams(void); +#else +static inline int dp_display_get_num_of_displays(void) +{ + return 0; +} +static inline int dp_display_get_displays(void **displays, int count) +{ + return 0; +} +static inline int dp_display_get_num_of_streams(void) +{ + return 0; +} +static inline int dp_connector_update_pps(struct drm_connector *connector, + char *pps_cmd, void *display) +{ + return 0; +} +#endif +#endif /* _DP_DISPLAY_H_ */ diff --git a/techpack/display/msm/dp/dp_drm.c b/techpack/display/msm/dp/dp_drm.c new file mode 100644 index 0000000000000000000000000000000000000000..976e0ebb8faf5a91ba6eebf878f8155ede942b39 --- /dev/null +++ b/techpack/display/msm/dp/dp_drm.c @@ -0,0 +1,682 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic.h> +#include <drm/drm_crtc.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "sde_connector.h" +#include "dp_drm.h" +#include "dp_debug.h" + +#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) + +#define to_dp_bridge(x) container_of((x), struct dp_bridge, base) + +void convert_to_drm_mode(const struct dp_display_mode *dp_mode, + struct drm_display_mode *drm_mode) +{ + u32 flags = 0; + + memset(drm_mode, 0, sizeof(*drm_mode)); + + drm_mode->hdisplay = dp_mode->timing.h_active; + drm_mode->hsync_start = drm_mode->hdisplay + + dp_mode->timing.h_front_porch; + drm_mode->hsync_end = drm_mode->hsync_start + + dp_mode->timing.h_sync_width; + drm_mode->htotal = drm_mode->hsync_end + dp_mode->timing.h_back_porch; + drm_mode->hskew = dp_mode->timing.h_skew; + + drm_mode->vdisplay = dp_mode->timing.v_active; + drm_mode->vsync_start = drm_mode->vdisplay + + dp_mode->timing.v_front_porch; + drm_mode->vsync_end = drm_mode->vsync_start + + dp_mode->timing.v_sync_width; + drm_mode->vtotal = drm_mode->vsync_end + dp_mode->timing.v_back_porch; + + drm_mode->vrefresh = dp_mode->timing.refresh_rate; + drm_mode->clock = dp_mode->timing.pixel_clk_khz; + + if (dp_mode->timing.h_active_low) + flags |= DRM_MODE_FLAG_NHSYNC; + else + flags |= DRM_MODE_FLAG_PHSYNC; + + if (dp_mode->timing.v_active_low) + flags |= DRM_MODE_FLAG_NVSYNC; + else + flags |= DRM_MODE_FLAG_PVSYNC; + + drm_mode->flags = flags; + + drm_mode->type = 0x48; + drm_mode_set_name(drm_mode); +} + +static int dp_bridge_attach(struct drm_bridge *dp_bridge) +{ + struct dp_bridge *bridge = to_dp_bridge(dp_bridge); + + if (!dp_bridge) { + DP_ERR("Invalid params\n"); + return -EINVAL; + } + + DP_DEBUG("[%d] attached\n", bridge->id); + + return 0; +} + +static void dp_bridge_pre_enable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + dp = bridge->display; + + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + if (!bridge->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + return; + } + + /* By this point mode should have been validated through mode_fixup */ + rc = dp->set_mode(dp, bridge->dp_panel, &bridge->dp_mode); + if (rc) { + DP_ERR("[%d] failed to perform a mode set, rc=%d\n", + bridge->id, rc); + return; + } + + rc = dp->prepare(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display prepare failed, rc=%d\n", + bridge->id, rc); + return; + } + + /* for SST force stream id, start slot and total slots to 0 */ + dp->set_stream_info(dp, bridge->dp_panel, 0, 0, 0, 0, 0); + + rc = dp->enable(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display enable failed, rc=%d\n", + bridge->id, rc); + dp->unprepare(dp, bridge->dp_panel); + } +} + +static void dp_bridge_enable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + if (!bridge->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + return; + } + + dp = bridge->display; + + rc = dp->post_enable(dp, bridge->dp_panel); + if (rc) + DP_ERR("[%d] DP display post enable failed, rc=%d\n", + bridge->id, rc); +} + +static void dp_bridge_disable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + if (!bridge->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + return; + } + + dp = bridge->display; + + if (!dp) { + DP_ERR("dp is null\n"); + return; + } + + if (dp) + sde_connector_helper_bridge_disable(bridge->connector); + + rc = dp->pre_disable(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display pre disable failed, rc=%d\n", + bridge->id, rc); + } +} + +static void dp_bridge_post_disable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + if (!bridge->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + return; + } + + dp = bridge->display; + + rc = dp->disable(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display disable failed, rc=%d\n", + bridge->id, rc); + return; + } + + rc = dp->unprepare(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display unprepare failed, rc=%d\n", + bridge->id, rc); + return; + } +} + +static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge || !mode || !adjusted_mode) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + if (!bridge->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + return; + } + + dp = bridge->display; + + dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode, + &bridge->dp_mode); +} + +static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + bool ret = true; + struct dp_display_mode dp_mode; + struct dp_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge || !mode || !adjusted_mode) { + DP_ERR("Invalid params\n"); + ret = false; + goto end; + } + + bridge = to_dp_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + ret = false; + goto end; + } + + if (!bridge->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + ret = false; + goto end; + } + + dp = bridge->display; + + dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode); + convert_to_drm_mode(&dp_mode, adjusted_mode); +end: + return ret; +} + +static const struct drm_bridge_funcs dp_bridge_ops = { + .attach = dp_bridge_attach, + .mode_fixup = dp_bridge_mode_fixup, + .pre_enable = dp_bridge_pre_enable, + .enable = dp_bridge_enable, + .disable = dp_bridge_disable, + .post_disable = dp_bridge_post_disable, + .mode_set = dp_bridge_mode_set, +}; + +int dp_connector_config_hdr(struct drm_connector *connector, void *display, + struct sde_connector_state *c_state) +{ + struct dp_display *dp = display; + struct sde_connector *sde_conn; + + if (!display || !c_state || !connector) { + DP_ERR("invalid params\n"); + return -EINVAL; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid dp panel\n"); + return -EINVAL; + } + + return dp->config_hdr(dp, sde_conn->drv_panel, &c_state->hdr_meta, + c_state->dyn_hdr_meta.dynamic_hdr_update); +} + +int dp_connector_set_colorspace(struct drm_connector *connector, + void *display) +{ + struct dp_display *dp_display = display; + struct sde_connector *sde_conn; + + if (!dp_display || !connector) + return -EINVAL; + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + pr_err("invalid dp panel\n"); + return -EINVAL; + } + + return dp_display->set_colorspace(dp_display, + sde_conn->drv_panel, connector->state->colorspace); +} + +int dp_connector_post_init(struct drm_connector *connector, void *display) +{ + int rc; + struct dp_display *dp_display = display; + struct sde_connector *sde_conn; + + if (!dp_display || !connector) + return -EINVAL; + + dp_display->base_connector = connector; + dp_display->bridge->connector = connector; + + if (dp_display->post_init) { + rc = dp_display->post_init(dp_display); + if (rc) + goto end; + } + + sde_conn = to_sde_connector(connector); + dp_display->bridge->dp_panel = sde_conn->drv_panel; + + rc = dp_mst_init(dp_display); +end: + return rc; +} + +int dp_connector_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res) +{ + const u32 single_intf = 1; + const u32 no_enc = 0; + struct msm_display_topology *topology; + struct sde_connector *sde_conn; + struct dp_panel *dp_panel; + struct dp_display_mode dp_mode; + struct dp_display *dp_disp = display; + struct msm_drm_private *priv; + int rc = 0; + + if (!drm_mode || !mode_info || !avail_res || + !avail_res->max_mixer_width || !connector || !display || + !connector->dev || !connector->dev->dev_private) { + DP_ERR("invalid params\n"); + return -EINVAL; + } + + memset(mode_info, 0, sizeof(*mode_info)); + + sde_conn = to_sde_connector(connector); + dp_panel = sde_conn->drv_panel; + priv = connector->dev->dev_private; + + topology = &mode_info->topology; + + rc = msm_get_mixer_count(priv, drm_mode, avail_res, + &topology->num_lm); + if (rc) { + DP_ERR("error getting mixer count. rc:%d\n", rc); + return rc; + } + + topology->num_enc = no_enc; + topology->num_intf = single_intf; + + mode_info->frame_rate = drm_mode->vrefresh; + mode_info->vtotal = drm_mode->vtotal; + + mode_info->wide_bus_en = dp_panel->widebus_en; + + dp_disp->convert_to_dp_mode(dp_disp, dp_panel, drm_mode, &dp_mode); + + if (dp_mode.timing.comp_info.comp_ratio) { + memcpy(&mode_info->comp_info, + &dp_mode.timing.comp_info, + sizeof(mode_info->comp_info)); + + topology->num_enc = topology->num_lm; + } + + return 0; +} + +int dp_connector_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *data) +{ + struct dp_display *display = data; + + if (!info || !display || !display->drm_dev) { + DP_ERR("invalid params\n"); + return -EINVAL; + } + + info->intf_type = DRM_MODE_CONNECTOR_DisplayPort; + + info->num_of_h_tiles = 1; + info->h_tile_instance[0] = 0; + info->is_connected = display->is_sst_connected; + info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID | + MSM_DISPLAY_CAP_HOT_PLUG; + + return 0; +} + +enum drm_connector_status dp_connector_detect(struct drm_connector *conn, + bool force, + void *display) +{ + enum drm_connector_status status = connector_status_unknown; + struct msm_display_info info; + int rc; + + if (!conn || !display) + return status; + + /* get display dp_info */ + memset(&info, 0x0, sizeof(info)); + rc = dp_connector_get_info(conn, &info, display); + if (rc) { + DP_ERR("failed to get display info, rc=%d\n", rc); + return connector_status_disconnected; + } + + if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) + status = (info.is_connected ? connector_status_connected : + connector_status_disconnected); + else + status = connector_status_connected; + + conn->display_info.width_mm = info.width_mm; + conn->display_info.height_mm = info.height_mm; + + return status; +} + +void dp_connector_post_open(struct drm_connector *connector, void *display) +{ + struct dp_display *dp; + + if (!display) { + DP_ERR("invalid input\n"); + return; + } + + dp = display; + + if (dp->post_open) + dp->post_open(dp); +} + +int dp_connector_atomic_check(struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state) +{ + struct sde_connector *sde_conn; + struct drm_connector_state *old_state; + + if (!connector || !display) + return -EINVAL; + + old_state = + drm_atomic_get_old_connector_state(c_state->state, connector); + + if (!old_state) + return -EINVAL; + + sde_conn = to_sde_connector(connector); + + /* + * Marking the colorspace has been changed + * the flag shall be checked in the pre_kickoff + * to configure the new colorspace in HW + */ + if (c_state->colorspace != old_state->colorspace) { + DP_DEBUG("colorspace has been updated\n"); + sde_conn->colorspace_updated = true; + } + + return 0; +} + +int dp_connector_get_modes(struct drm_connector *connector, + void *display, const struct msm_resource_caps_info *avail_res) +{ + int rc = 0; + struct dp_display *dp; + struct dp_display_mode *dp_mode = NULL; + struct drm_display_mode *m, drm_mode; + struct sde_connector *sde_conn; + + if (!connector || !display) + return 0; + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid dp panel\n"); + return 0; + } + + dp = display; + + dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL); + if (!dp_mode) + return 0; + + /* pluggable case assumes EDID is read when HPD */ + if (dp->is_sst_connected) { + rc = dp->get_modes(dp, sde_conn->drv_panel, dp_mode); + if (!rc) + DP_ERR("failed to get DP sink modes, rc=%d\n", rc); + + if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */ + memset(&drm_mode, 0x0, sizeof(drm_mode)); + convert_to_drm_mode(dp_mode, &drm_mode); + m = drm_mode_duplicate(connector->dev, &drm_mode); + if (!m) { + DP_ERR("failed to add mode %ux%u\n", + drm_mode.hdisplay, + drm_mode.vdisplay); + kfree(dp_mode); + return 0; + } + m->width_mm = connector->display_info.width_mm; + m->height_mm = connector->display_info.height_mm; + drm_mode_probed_add(connector, m); + } + } else { + DP_ERR("No sink connected\n"); + } + kfree(dp_mode); + + return rc; +} + +int dp_drm_bridge_init(void *data, struct drm_encoder *encoder) +{ + int rc = 0; + struct dp_bridge *bridge; + struct drm_device *dev; + struct dp_display *display = data; + struct msm_drm_private *priv = NULL; + + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + if (!bridge) { + rc = -ENOMEM; + goto error; + } + + dev = display->drm_dev; + bridge->display = display; + bridge->base.funcs = &dp_bridge_ops; + bridge->base.encoder = encoder; + + priv = dev->dev_private; + + rc = drm_bridge_attach(encoder, &bridge->base, NULL); + if (rc) { + DP_ERR("failed to attach bridge, rc=%d\n", rc); + goto error_free_bridge; + } + + rc = display->request_irq(display); + if (rc) { + DP_ERR("request_irq failed, rc=%d\n", rc); + goto error_free_bridge; + } + + encoder->bridge = &bridge->base; + priv->bridges[priv->num_bridges++] = &bridge->base; + display->bridge = bridge; + + return 0; +error_free_bridge: + kfree(bridge); +error: + return rc; +} + +void dp_drm_bridge_deinit(void *data) +{ + struct dp_display *display = data; + struct dp_bridge *bridge = display->bridge; + + if (bridge && bridge->base.encoder) + bridge->base.encoder->bridge = NULL; + + kfree(bridge); +} + +enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, void *display, + const struct msm_resource_caps_info *avail_res) +{ + struct dp_display *dp_disp; + struct sde_connector *sde_conn; + + if (!mode || !display || !connector) { + DP_ERR("invalid params\n"); + return MODE_ERROR; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid dp panel\n"); + return MODE_ERROR; + } + + dp_disp = display; + mode->vrefresh = drm_mode_vrefresh(mode); + + return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel, + mode, avail_res); +} + +int dp_connector_update_pps(struct drm_connector *connector, + char *pps_cmd, void *display) +{ + struct dp_display *dp_disp; + struct sde_connector *sde_conn; + + if (!display || !connector) { + DP_ERR("invalid params\n"); + return -EINVAL; + } + + sde_conn = to_sde_connector(connector); + if (!sde_conn->drv_panel) { + DP_ERR("invalid dp panel\n"); + return MODE_ERROR; + } + + dp_disp = display; + return dp_disp->update_pps(dp_disp, connector, pps_cmd); +} diff --git a/techpack/display/msm/dp/dp_drm.h b/techpack/display/msm/dp/dp_drm.h new file mode 100644 index 0000000000000000000000000000000000000000..07f606e8a70bf3f100cfa0e85f306128fcf25b60 --- /dev/null +++ b/techpack/display/msm/dp/dp_drm.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_DRM_H_ +#define _DP_DRM_H_ + +#include <linux/types.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> + +#include "msm_drv.h" +#include "dp_display.h" + +struct dp_bridge { + struct drm_bridge base; + u32 id; + + struct drm_connector *connector; + struct dp_display *display; + struct dp_display_mode dp_mode; + void *dp_panel; +}; + + +#ifdef CONFIG_DRM_MSM_DP +/** + * dp_connector_config_hdr - callback to configure HDR + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @c_state: connect state data + * Returns: Zero on success + */ +int dp_connector_config_hdr(struct drm_connector *connector, + void *display, + struct sde_connector_state *c_state); + +/** + * dp_connector_atomic_check - callback to perform atomic + * check for DP + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @c_state: connect state data + * Returns: Zero on success + */ +int dp_connector_atomic_check(struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state); + +/** + * dp_connector_set_colorspace - callback to set new colorspace + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ +int dp_connector_set_colorspace(struct drm_connector *connector, + void *display); + +/** + * dp_connector_post_init - callback to perform additional initialization steps + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ +int dp_connector_post_init(struct drm_connector *connector, void *display); + +/** + * dp_connector_detect - callback to determine if connector is connected + * @connector: Pointer to drm connector structure + * @force: Force detect setting from drm framework + * @display: Pointer to private display handle + * Returns: Connector 'is connected' status + */ +enum drm_connector_status dp_connector_detect(struct drm_connector *conn, + bool force, + void *display); + +/** + * dp_connector_get_modes - callback to add drm modes via drm_mode_probed_add() + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @avail_res: Pointer with curr available resources + * Returns: Number of modes added + */ +int dp_connector_get_modes(struct drm_connector *connector, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * dp_connector_mode_valid - callback to determine if specified mode is valid + * @connector: Pointer to drm connector structure + * @mode: Pointer to drm mode structure + * @display: Pointer to private display handle + * @avail_res: Pointer with curr available resources + * Returns: Validity status for specified mode + */ +enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * dp_connector_get_mode_info - retrieve information of the mode selected + * @connector: Pointer to drm connector structure + * @drm_mode: Display mode set for the display + * @mode_info: Out parameter. Information of the mode + * @display: Pointer to private display structure + * @avail_res: Pointer with curr available resources + * Returns: zero on success + */ +int dp_connector_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * dp_connector_get_info - retrieve connector display info + * @connector: Pointer to drm connector structure + * @info: Out parameter. Information of the connected display + * @display: Pointer to private display structure + * Returns: zero on success + */ +int dp_connector_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *display); + +/** + * dp_connector_post_open - handle the post open functionalites + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + */ +void dp_connector_post_open(struct drm_connector *connector, void *display); + +int dp_drm_bridge_init(void *display, + struct drm_encoder *encoder); + +void dp_drm_bridge_deinit(void *display); + +/** + * convert_to_drm_mode - convert dp mode to drm mode + * @dp_mode: Point to dp mode + * @drm_mode: Pointer to drm mode + */ +void convert_to_drm_mode(const struct dp_display_mode *dp_mode, + struct drm_display_mode *drm_mode); + +/** + * dp_connector_update_pps - update pps for given connector + * @dp_mode: Point to dp mode + * @pps_cmd: PPS packet + * @display: Pointer to private display structure + */ +int dp_connector_update_pps(struct drm_connector *connector, + char *pps_cmd, void *display); + +/** + * dp_mst_drm_bridge_init - initialize mst bridge + * @display: Pointer to private display structure + * @encoder: Pointer to encoder for mst bridge mapping + */ +int dp_mst_drm_bridge_init(void *display, + struct drm_encoder *encoder); + +/** + * dp_mst_drm_bridge_deinit - de-initialize mst bridges + * @display: Pointer to private display structure + */ +void dp_mst_drm_bridge_deinit(void *display); + +/** + * dp_mst_init - initialize mst objects for the given display + * @display: Pointer to private display structure + */ +int dp_mst_init(struct dp_display *dp_display); + +/** + * dp_mst_deinit - de-initialize mst objects for the given display + * @display: Pointer to private display structure + */ +void dp_mst_deinit(struct dp_display *dp_display); +#else +static inline int dp_connector_config_hdr(struct drm_connector *connector, + void *display, struct sde_connector_state *c_state) +{ + return 0; +} + +int dp_connector_atomic_check(struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state) +{ + return 0; +} + +int dp_connector_set_colorspace(struct drm_connector *connector, + void *display) +{ + return 0; +} + +static inline int dp_connector_post_init(struct drm_connector *connector, + void *display) +{ + return 0; +} + +static inline enum drm_connector_status dp_connector_detect( + struct drm_connector *conn, + bool force, + void *display) +{ + return 0; +} + + +static inline int dp_connector_get_modes(struct drm_connector *connector, + void *display, const struct msm_resource_caps_info *avail_res) +{ + return 0; +} + +static inline enum drm_mode_status dp_connector_mode_valid( + struct drm_connector *connector, + struct drm_display_mode *mode, + void *display, const struct msm_resource_caps_info *avail_res) +{ + return MODE_OK; +} + +static inline int dp_connector_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res) +{ + return 0; +} + +static inline int dp_connector_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *display) +{ + return 0; +} + +static inline void dp_connector_post_open(struct drm_connector *connector, + void *display) +{ +} + +static inline int dp_drm_bridge_init(void *display, struct drm_encoder *encoder) +{ + return 0; +} + +static inline void dp_drm_bridge_deinit(void *display) +{ +} + +static inline void convert_to_drm_mode(const struct dp_display_mode *dp_mode, + struct drm_display_mode *drm_mode) +{ +} + +static inline int dp_mst_drm_bridge_init(void *display, + struct drm_encoder *encoder) +{ + return 0; +} + +static inline void dp_mst_drm_bridge_deinit(void *display) +{ +} + +static inline int dp_mst_init(struct dp_display *dp_display) +{ + return 0; +} + +static inline int dp_mst_deinit(struct dp_display *dp_display) +{ + return 0; +} +#endif + +#endif /* _DP_DRM_H_ */ diff --git a/techpack/display/msm/dp/dp_gpio_hpd.c b/techpack/display/msm/dp/dp_gpio_hpd.c new file mode 100644 index 0000000000000000000000000000000000000000..f11212b63eaeb647b43ed16009b41856c9afb87f --- /dev/null +++ b/techpack/display/msm/dp/dp_gpio_hpd.c @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/sde_io_util.h> +#include <linux/of_gpio.h> +#include "dp_gpio_hpd.h" +#include "dp_debug.h" + +struct dp_gpio_hpd_private { + struct device *dev; + struct dp_hpd base; + struct dss_gpio gpio_cfg; + struct delayed_work work; + struct dp_hpd_cb *cb; + int irq; + bool hpd; +}; + +static int dp_gpio_hpd_connect(struct dp_gpio_hpd_private *gpio_hpd, bool hpd) +{ + int rc = 0; + + if (!gpio_hpd) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + gpio_hpd->base.hpd_high = hpd; + gpio_hpd->base.alt_mode_cfg_done = hpd; + gpio_hpd->base.hpd_irq = false; + + if (!gpio_hpd->cb || + !gpio_hpd->cb->configure || + !gpio_hpd->cb->disconnect) { + DP_ERR("invalid cb\n"); + rc = -EINVAL; + goto error; + } + + if (hpd) + rc = gpio_hpd->cb->configure(gpio_hpd->dev); + else + rc = gpio_hpd->cb->disconnect(gpio_hpd->dev); + +error: + return rc; +} + +static int dp_gpio_hpd_attention(struct dp_gpio_hpd_private *gpio_hpd) +{ + int rc = 0; + + if (!gpio_hpd) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + gpio_hpd->base.hpd_irq = true; + + if (gpio_hpd->cb && gpio_hpd->cb->attention) + rc = gpio_hpd->cb->attention(gpio_hpd->dev); + +error: + return rc; +} + +static irqreturn_t dp_gpio_isr(int unused, void *data) +{ + struct dp_gpio_hpd_private *gpio_hpd = data; + u32 const disconnect_timeout_retry = 50; + bool hpd; + int i; + + if (!gpio_hpd) + return IRQ_NONE; + + hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio); + + if (!gpio_hpd->hpd && hpd) { + gpio_hpd->hpd = true; + queue_delayed_work(system_wq, &gpio_hpd->work, 0); + return IRQ_HANDLED; + } + + if (!gpio_hpd->hpd) + return IRQ_HANDLED; + + /* In DP 1.2 spec, 100msec is recommended for the detection + * of HPD connect event. Here we'll poll HPD status for + * 50x2ms = 100ms and if HPD is always low, we know DP is + * disconnected. If HPD is high, HPD_IRQ will be handled + */ + for (i = 0; i < disconnect_timeout_retry; i++) { + if (hpd) { + dp_gpio_hpd_attention(gpio_hpd); + return IRQ_HANDLED; + } + usleep_range(2000, 2100); + hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio); + } + + gpio_hpd->hpd = false; + queue_delayed_work(system_wq, &gpio_hpd->work, 0); + return IRQ_HANDLED; +} + +static void dp_gpio_hpd_work(struct work_struct *work) +{ + struct delayed_work *dw = to_delayed_work(work); + struct dp_gpio_hpd_private *gpio_hpd = container_of(dw, + struct dp_gpio_hpd_private, work); + int ret; + + if (gpio_hpd->hpd) { + devm_free_irq(gpio_hpd->dev, + gpio_hpd->irq, gpio_hpd); + ret = devm_request_threaded_irq(gpio_hpd->dev, + gpio_hpd->irq, NULL, + dp_gpio_isr, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "dp-gpio-intp", gpio_hpd); + dp_gpio_hpd_connect(gpio_hpd, true); + } else { + devm_free_irq(gpio_hpd->dev, + gpio_hpd->irq, gpio_hpd); + ret = devm_request_threaded_irq(gpio_hpd->dev, + gpio_hpd->irq, NULL, + dp_gpio_isr, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "dp-gpio-intp", gpio_hpd); + dp_gpio_hpd_connect(gpio_hpd, false); + } + + if (ret < 0) + DP_ERR("Cannot claim IRQ dp-gpio-intp\n"); +} + +static int dp_gpio_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd) +{ + int rc = 0; + struct dp_gpio_hpd_private *gpio_hpd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base); + + dp_gpio_hpd_connect(gpio_hpd, hpd); +error: + return rc; +} + +static int dp_gpio_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo) +{ + int rc = 0; + struct dp_gpio_hpd_private *gpio_hpd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base); + + dp_gpio_hpd_attention(gpio_hpd); +error: + return rc; +} + +int dp_gpio_hpd_register(struct dp_hpd *dp_hpd) +{ + struct dp_gpio_hpd_private *gpio_hpd; + int edge; + int rc = 0; + + if (!dp_hpd) + return -EINVAL; + + gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base); + + gpio_hpd->hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio); + + edge = gpio_hpd->hpd ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; + rc = devm_request_threaded_irq(gpio_hpd->dev, gpio_hpd->irq, NULL, + dp_gpio_isr, + edge | IRQF_ONESHOT, + "dp-gpio-intp", gpio_hpd); + if (rc) { + DP_ERR("Failed to request INTP threaded IRQ: %d\n", rc); + return rc; + } + + if (gpio_hpd->hpd) + queue_delayed_work(system_wq, &gpio_hpd->work, 0); + + return rc; +} + +struct dp_hpd *dp_gpio_hpd_get(struct device *dev, + struct dp_hpd_cb *cb) +{ + int rc = 0; + const char *hpd_gpio_name = "qcom,dp-hpd-gpio"; + struct dp_gpio_hpd_private *gpio_hpd; + struct dp_pinctrl pinctrl = {0}; + + if (!dev || !cb) { + DP_ERR("invalid device\n"); + rc = -EINVAL; + goto error; + } + + gpio_hpd = devm_kzalloc(dev, sizeof(*gpio_hpd), GFP_KERNEL); + if (!gpio_hpd) { + rc = -ENOMEM; + goto error; + } + + pinctrl.pin = devm_pinctrl_get(dev); + if (!IS_ERR_OR_NULL(pinctrl.pin)) { + pinctrl.state_hpd_active = pinctrl_lookup_state(pinctrl.pin, + "mdss_dp_hpd_active"); + if (!IS_ERR_OR_NULL(pinctrl.state_hpd_active)) { + rc = pinctrl_select_state(pinctrl.pin, + pinctrl.state_hpd_active); + if (rc) { + DP_ERR("failed to set hpd active state\n"); + goto gpio_error; + } + } + } + + gpio_hpd->gpio_cfg.gpio = of_get_named_gpio(dev->of_node, + hpd_gpio_name, 0); + if (!gpio_is_valid(gpio_hpd->gpio_cfg.gpio)) { + DP_ERR("%s gpio not specified\n", hpd_gpio_name); + rc = -EINVAL; + goto gpio_error; + } + + strlcpy(gpio_hpd->gpio_cfg.gpio_name, hpd_gpio_name, + sizeof(gpio_hpd->gpio_cfg.gpio_name)); + gpio_hpd->gpio_cfg.value = 0; + + rc = gpio_request(gpio_hpd->gpio_cfg.gpio, + gpio_hpd->gpio_cfg.gpio_name); + if (rc) { + DP_ERR("%s: failed to request gpio\n", hpd_gpio_name); + goto gpio_error; + } + gpio_direction_input(gpio_hpd->gpio_cfg.gpio); + + gpio_hpd->dev = dev; + gpio_hpd->cb = cb; + gpio_hpd->irq = gpio_to_irq(gpio_hpd->gpio_cfg.gpio); + INIT_DELAYED_WORK(&gpio_hpd->work, dp_gpio_hpd_work); + + gpio_hpd->base.simulate_connect = dp_gpio_hpd_simulate_connect; + gpio_hpd->base.simulate_attention = dp_gpio_hpd_simulate_attention; + gpio_hpd->base.register_hpd = dp_gpio_hpd_register; + + return &gpio_hpd->base; + +gpio_error: + devm_kfree(dev, gpio_hpd); +error: + return ERR_PTR(rc); +} + +void dp_gpio_hpd_put(struct dp_hpd *dp_hpd) +{ + struct dp_gpio_hpd_private *gpio_hpd; + + if (!dp_hpd) + return; + + gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base); + + gpio_free(gpio_hpd->gpio_cfg.gpio); + devm_kfree(gpio_hpd->dev, gpio_hpd); +} diff --git a/techpack/display/msm/dp/dp_gpio_hpd.h b/techpack/display/msm/dp/dp_gpio_hpd.h new file mode 100644 index 0000000000000000000000000000000000000000..0ed305cb906e10c352933bf8c91f2395ff3f210e --- /dev/null +++ b/techpack/display/msm/dp/dp_gpio_hpd.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef _DP_GPIO_HPD_H_ +#define _DP_GPIO_HPD_H_ + +#include "dp_hpd.h" + +/** + * dp_gpio_hpd_get() - configure and get the DisplayPlot HPD module data + * + * @dev: device instance of the caller + * return: pointer to allocated gpio hpd module data + * + * This function sets up the gpio hpd module + */ +struct dp_hpd *dp_gpio_hpd_get(struct device *dev, + struct dp_hpd_cb *cb); + +/** + * dp_gpio_hpd_put() + * + * Cleans up dp_hpd instance + * + * @hpd: instance of gpio_hpd + */ +void dp_gpio_hpd_put(struct dp_hpd *hpd); + +#endif /* _DP_GPIO_HPD_H_ */ diff --git a/techpack/display/msm/dp/dp_hdcp2p2.c b/techpack/display/msm/dp/dp_hdcp2p2.c new file mode 100644 index 0000000000000000000000000000000000000000..fcbec753ccfc46b218da1cf4a6d7f317b232e10e --- /dev/null +++ b/techpack/display/msm/dp/dp_hdcp2p2.c @@ -0,0 +1,998 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/types.h> +#include <linux/kthread.h> +#include <linux/msm_hdcp.h> +#include <linux/kfifo.h> +#include <drm/drm_dp_helper.h> + +#include "sde_hdcp_2x.h" +#include "dp_debug.h" + +#define DP_INTR_STATUS2 (0x00000024) +#define DP_INTR_STATUS3 (0x00000028) +#define dp_read(offset) readl_relaxed((offset)) +#define dp_write(offset, data) writel_relaxed((data), (offset)) +#define DP_HDCP_RXCAPS_LENGTH 3 + +enum dp_hdcp2p2_sink_status { + SINK_DISCONNECTED, + SINK_CONNECTED +}; + +struct dp_hdcp2p2_ctrl { + DECLARE_KFIFO(cmd_q, enum hdcp_transport_wakeup_cmd, 8); + wait_queue_head_t wait_q; + atomic_t auth_state; + atomic_t abort; + enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */ + struct dp_hdcp2p2_interrupts *intr; + struct sde_hdcp_init_data init_data; + struct mutex mutex; /* mutex to protect access to ctrl */ + struct mutex msg_lock; /* mutex to protect access to msg buffer */ + struct sde_hdcp_ops *ops; + void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */ + struct sde_hdcp_2x_ops *lib; /* Ops for driver to call into TZ */ + + struct task_struct *thread; + struct hdcp2_buffer response; + struct hdcp2_buffer request; + uint32_t total_message_length; + uint32_t transaction_delay; + uint32_t transaction_timeout; + struct sde_hdcp_2x_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS]; + u8 sink_rx_status; + u8 rx_status; + char abort_mask; + + bool polling; +}; + +struct dp_hdcp2p2_int_set { + u32 interrupt; + char *name; + void (*func)(struct dp_hdcp2p2_ctrl *ctrl); +}; + +struct dp_hdcp2p2_interrupts { + u32 reg; + struct dp_hdcp2p2_int_set *int_set; +}; + +static inline int dp_hdcp2p2_valid_handle(struct dp_hdcp2p2_ctrl *ctrl) +{ + if (!ctrl) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (!ctrl->lib_ctx) { + DP_ERR("HDCP library needs to be acquired\n"); + return -EINVAL; + } + + if (!ctrl->lib) { + DP_ERR("invalid lib ops data\n"); + return -EINVAL; + } + return 0; +} + +static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl) +{ + enum hdcp_transport_wakeup_cmd cmd; + + if (kfifo_peek(&ctrl->cmd_q, &cmd) && + cmd == HDCP_TRANSPORT_CMD_AUTHENTICATE) + return true; + + if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) + return true; + + return false; +} + +static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl, + struct hdcp_transport_wakeup_data *data) +{ + int i = 0; + uint32_t num_messages = 0; + + if (!data || !data->message_data) + return 0; + + mutex_lock(&ctrl->msg_lock); + + num_messages = data->message_data->num_messages; + ctrl->total_message_length = 0; /* Total length of all messages */ + + for (i = 0; i < num_messages; i++) + ctrl->total_message_length += + data->message_data->messages[i].length; + + memcpy(ctrl->msg_part, data->message_data->messages, + sizeof(data->message_data->messages)); + + ctrl->rx_status = data->message_data->rx_status; + ctrl->abort_mask = data->abort_mask; + + if (!ctrl->total_message_length) { + mutex_unlock(&ctrl->msg_lock); + return 0; + } + + ctrl->response.data = data->buf; + ctrl->response.length = ctrl->total_message_length; + ctrl->request.data = data->buf; + ctrl->request.length = ctrl->total_message_length; + + ctrl->transaction_delay = data->transaction_delay; + ctrl->transaction_timeout = data->transaction_timeout; + + mutex_unlock(&ctrl->msg_lock); + + return 0; +} + +static void dp_hdcp2p2_send_auth_status(struct dp_hdcp2p2_ctrl *ctrl) +{ + ctrl->init_data.notify_status(ctrl->init_data.cb_data, + atomic_read(&ctrl->auth_state)); +} + +static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable) +{ + void __iomem *base = ctrl->init_data.dp_ahb->base; + struct dp_hdcp2p2_interrupts *intr = ctrl->intr; + + if (atomic_read(&ctrl->abort)) + return; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + u32 interrupts = 0; + + while (int_set && int_set->interrupt) { + interrupts |= int_set->interrupt; + int_set++; + } + + if (enable) + dp_write(base + intr->reg, + dp_read(base + intr->reg) | interrupts); + else + dp_write(base + intr->reg, + dp_read(base + intr->reg) & ~interrupts); + intr++; + } +} + +static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data) +{ + struct dp_hdcp2p2_ctrl *ctrl; + + if (!data) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + ctrl = data->context; + if (!ctrl) { + DP_ERR("invalid ctrl\n"); + return -EINVAL; + } + + if (dp_hdcp2p2_copy_buf(ctrl, data)) + goto exit; + + ctrl->polling = false; + switch (data->cmd) { + case HDCP_TRANSPORT_CMD_STATUS_SUCCESS: + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATED); + kfifo_put(&ctrl->cmd_q, data->cmd); + wake_up(&ctrl->wait_q); + break; + case HDCP_TRANSPORT_CMD_STATUS_FAILED: + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); + kfifo_put(&ctrl->cmd_q, data->cmd); + kthread_park(ctrl->thread); + break; + default: + kfifo_put(&ctrl->cmd_q, data->cmd); + wake_up(&ctrl->wait_q); + break; + } + +exit: + return 0; +} + +static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, + struct sde_hdcp_2x_wakeup_data *data) +{ + int rc = 0; + + if (ctrl && ctrl->lib && ctrl->lib->wakeup && + data && (data->cmd != HDCP_2X_CMD_INVALID)) { + rc = ctrl->lib->wakeup(data); + if (rc) + DP_ERR("error sending %s to lib\n", + sde_hdcp_2x_cmd_to_str(data->cmd)); + } +} + +static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) +{ + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + ctrl->sink_status = SINK_DISCONNECTED; + atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); +} + +static int dp_hdcp2p2_register(void *input, bool mst_enabled) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl = input; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_ENABLE}; + + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return rc; + + if (mst_enabled) + cdata.device_type = HDCP_TXMTR_DP_MST; + else + cdata.device_type = HDCP_TXMTR_DP; + + cdata.context = ctrl->lib_ctx; + rc = ctrl->lib->wakeup(&cdata); + + return rc; +} + +static int dp_hdcp2p2_on(void *input) +{ + int rc = 0; + struct dp_hdcp2p2_ctrl *ctrl = input; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID}; + + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return rc; + + cdata.cmd = HDCP_2X_CMD_START; + cdata.context = ctrl->lib_ctx; + rc = ctrl->lib->wakeup(&cdata); + if (rc) + DP_ERR("Unable to start the HDCP 2.2 library (%d)\n", rc); + + return rc; +} + +static void dp_hdcp2p2_off(void *input) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_DISABLE}; + + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return; + + dp_hdcp2p2_set_interrupts(ctrl, false); + + dp_hdcp2p2_reset(ctrl); + + kthread_park(ctrl->thread); + + cdata.context = ctrl->lib_ctx; + ctrl->lib->wakeup(&cdata); +} + +static int dp_hdcp2p2_authenticate(void *input) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl = input; + struct hdcp_transport_wakeup_data cdata = { + HDCP_TRANSPORT_CMD_AUTHENTICATE}; + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return rc; + + dp_hdcp2p2_set_interrupts(ctrl, true); + + ctrl->sink_status = SINK_CONNECTED; + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); + + kthread_park(ctrl->thread); + kfifo_reset(&ctrl->cmd_q); + kthread_unpark(ctrl->thread); + + cdata.context = input; + dp_hdcp2p2_wakeup(&cdata); + + return rc; +} + +static int dp_hdcp2p2_reauthenticate(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp_hdcp2p2_reset((struct dp_hdcp2p2_ctrl *)input); + + return dp_hdcp2p2_authenticate(input); +} + +static void dp_hdcp2p2_min_level_change(void *client_ctx, + u8 min_enc_level) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx; + struct sde_hdcp_2x_wakeup_data cdata = { + HDCP_2X_CMD_MIN_ENC_LEVEL}; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + cdata.context = ctrl->lib_ctx; + cdata.min_enc_level = min_enc_level; + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0, max_size = 16, read_size = 0, bytes_read = 0; + int size = ctrl->request.length, offset = ctrl->msg_part->offset; + u8 *buf = ctrl->request.data; + s64 diff_ms; + ktime_t start_read, finish_read; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE || + atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL) { + DP_ERR("invalid hdcp state\n"); + rc = -EINVAL; + goto exit; + } + + if (!buf) { + DP_ERR("invalid request buffer\n"); + rc = -EINVAL; + goto exit; + } + + DP_DEBUG("offset(0x%x), size(%d)\n", offset, size); + + start_read = ktime_get(); + do { + read_size = min(size, max_size); + + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + offset, buf, read_size); + if (bytes_read != read_size) { + DP_ERR("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", + offset, read_size, bytes_read); + rc = -EINVAL; + break; + } + + buf += read_size; + offset += read_size; + size -= read_size; + } while (size > 0); + finish_read = ktime_get(); + diff_ms = ktime_ms_delta(finish_read, start_read); + + if (ctrl->transaction_timeout && diff_ms > ctrl->transaction_timeout) { + DP_ERR("HDCP read timeout exceeded (%dms > %dms)\n", diff_ms, + ctrl->transaction_timeout); + rc = -ETIMEDOUT; + } +exit: + return rc; +} + +static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl, + u8 *buf, int size, uint offset, uint timeout) +{ + int const max_size = 16; + int rc = 0, write_size = 0, bytes_written = 0; + + DP_DEBUG("offset(0x%x), size(%d)\n", offset, size); + + do { + write_size = min(size, max_size); + + bytes_written = drm_dp_dpcd_write(ctrl->init_data.drm_aux, + offset, buf, write_size); + if (bytes_written != write_size) { + DP_ERR("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", + offset, write_size, bytes_written); + rc = -EINVAL; + break; + } + + buf += write_size; + offset += write_size; + size -= write_size; + } while (size > 0); + + return rc; +} + +static bool dp_hdcp2p2_feature_supported(void *input) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl = input; + struct sde_hdcp_2x_ops *lib = NULL; + bool supported = false; + + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return supported; + + lib = ctrl->lib; + if (lib->feature_supported) + supported = lib->feature_supported( + ctrl->lib_ctx); + + return supported; +} + +static void dp_hdcp2p2_force_encryption(void *data, bool enable) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl = data; + struct sde_hdcp_2x_ops *lib = NULL; + + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return; + + lib = ctrl->lib; + if (lib->force_encryption) + lib->force_encryption(ctrl->lib_ctx, enable); +} + +static void dp_hdcp2p2_send_msg(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID}; + + if (!ctrl) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto exit; + } + + cdata.context = ctrl->lib_ctx; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + DP_ERR("hdcp is off\n"); + goto exit; + } + + mutex_lock(&ctrl->msg_lock); + + rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->response.data, + ctrl->response.length, ctrl->msg_part->offset, + ctrl->transaction_delay); + if (rc) { + DP_ERR("Error sending msg to sink %d\n", rc); + mutex_unlock(&ctrl->msg_lock); + goto exit; + } + + cdata.cmd = HDCP_2X_CMD_MSG_SEND_SUCCESS; + cdata.timeout = ctrl->transaction_delay; + mutex_unlock(&ctrl->msg_lock); + +exit: + if (rc == -ETIMEDOUT) + cdata.cmd = HDCP_2X_CMD_MSG_SEND_TIMEOUT; + else if (rc) + cdata.cmd = HDCP_2X_CMD_MSG_SEND_FAILED; + + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0; + struct sde_hdcp_2x_wakeup_data cdata = { HDCP_2X_CMD_INVALID }; + + cdata.context = ctrl->lib_ctx; + + rc = dp_hdcp2p2_aux_read_message(ctrl); + if (rc) { + DP_ERR("error reading message %d\n", rc); + goto exit; + } + + cdata.total_message_length = ctrl->total_message_length; + cdata.timeout = ctrl->transaction_delay; +exit: + if (rc == -ETIMEDOUT) + cdata.cmd = HDCP_2X_CMD_MSG_RECV_TIMEOUT; + else if (rc) + cdata.cmd = HDCP_2X_CMD_MSG_RECV_FAILED; + else + cdata.cmd = HDCP_2X_CMD_MSG_RECV_SUCCESS; + + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); + + return rc; +} + +static void dp_hdcp2p2_recv_msg(struct dp_hdcp2p2_ctrl *ctrl) +{ + struct sde_hdcp_2x_wakeup_data cdata = { HDCP_2X_CMD_INVALID }; + + cdata.context = ctrl->lib_ctx; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + DP_ERR("hdcp is off\n"); + return; + } + + if (ctrl->transaction_delay) + msleep(ctrl->transaction_delay); + + dp_hdcp2p2_get_msg_from_sink(ctrl); +} + +static void dp_hdcp2p2_link_check(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0, retries = 10; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID}; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || + atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + DP_ERR("invalid hdcp state\n"); + return; + } + + cdata.context = ctrl->lib_ctx; + + if (ctrl->sink_rx_status & ctrl->abort_mask) { + if (ctrl->sink_rx_status & BIT(3)) + DP_ERR("reauth_req set by sink\n"); + + if (ctrl->sink_rx_status & BIT(4)) + DP_ERR("link failure reported by sink\n"); + + ctrl->sink_rx_status = 0; + ctrl->rx_status = 0; + + rc = -ENOLINK; + + cdata.cmd = HDCP_2X_CMD_LINK_FAILED; + atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); + goto exit; + } + + /* wait for polling to start till spec allowed timeout */ + while (!ctrl->polling && retries--) + msleep(20); + + /* check if sink has made a message available */ + if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) { + ctrl->sink_rx_status = 0; + ctrl->rx_status = 0; + + dp_hdcp2p2_get_msg_from_sink(ctrl); + + ctrl->polling = false; + } +exit: + if (rc) + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static void dp_hdcp2p2_start_auth(struct dp_hdcp2p2_ctrl *ctrl) +{ + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_START_AUTH}; + cdata.context = ctrl->lib_ctx; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING) + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); +} + +static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl, + u8 *rx_status) +{ + u32 const cp_irq_dpcd_offset = 0x201; + u32 const rxstatus_dpcd_offset = 0x69493; + ssize_t const bytes_to_read = 1; + ssize_t bytes_read = 0; + u8 buf = 0; + int rc = 0; + bool cp_irq = false; + + *rx_status = 0; + + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + cp_irq_dpcd_offset, &buf, bytes_to_read); + if (bytes_read != bytes_to_read) { + DP_ERR("cp irq read failed\n"); + rc = bytes_read; + goto error; + } + + cp_irq = buf & BIT(2); + DP_DEBUG("cp_irq=0x%x\n", cp_irq); + buf = 0; + + if (cp_irq) { + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + rxstatus_dpcd_offset, &buf, bytes_to_read); + if (bytes_read != bytes_to_read) { + DP_ERR("rxstatus read failed\n"); + rc = bytes_read; + goto error; + } + *rx_status = buf; + DP_DEBUG("rx_status=0x%x\n", *rx_status); + } + +error: + return rc; +} + +static int dp_hdcp2p2_cp_irq(void *input) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl = input; + + rc = dp_hdcp2p2_valid_handle(ctrl); + if (rc) + return rc; + + if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || + atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { + DP_ERR("invalid hdcp state\n"); + return -EINVAL; + } + + ctrl->sink_rx_status = 0; + rc = dp_hdcp2p2_read_rx_status(ctrl, &ctrl->sink_rx_status); + if (rc) { + DP_ERR("failed to read rx status\n"); + return rc; + } + + DP_DEBUG("sink_rx_status=0x%x\n", ctrl->sink_rx_status); + + if (!ctrl->sink_rx_status) { + DP_DEBUG("not a hdcp 2.2 irq\n"); + return -EINVAL; + } + + + kfifo_put(&ctrl->cmd_q, HDCP_TRANSPORT_CMD_LINK_CHECK); + wake_up(&ctrl->wait_q); + + return 0; +} + +static int dp_hdcp2p2_isr(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + int rc = 0; + struct dss_io_data *io; + struct dp_hdcp2p2_interrupts *intr; + u32 hdcp_int_val = 0; + + if (!ctrl || !ctrl->init_data.dp_ahb) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + io = ctrl->init_data.dp_ahb; + intr = ctrl->intr; + + while (intr && intr->reg) { + struct dp_hdcp2p2_int_set *int_set = intr->int_set; + + hdcp_int_val = dp_read(io->base + intr->reg); + + while (int_set && int_set->interrupt) { + if (hdcp_int_val & (int_set->interrupt >> 2)) { + DP_DEBUG("%s\n", int_set->name); + + if (int_set->func) + int_set->func(ctrl); + + dp_write(io->base + intr->reg, hdcp_int_val | + (int_set->interrupt >> 1)); + } + int_set++; + } + intr++; + } +end: + return rc; +} + +static bool dp_hdcp2p2_supported(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + u32 const rxcaps_dpcd_offset = 0x6921d; + ssize_t bytes_read = 0; + u8 buf[DP_HDCP_RXCAPS_LENGTH]; + + DP_DEBUG("Checking sink capability\n"); + + bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, + rxcaps_dpcd_offset, &buf, DP_HDCP_RXCAPS_LENGTH); + if (bytes_read != DP_HDCP_RXCAPS_LENGTH) { + DP_ERR("RxCaps read failed\n"); + goto error; + } + + DP_DEBUG("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1); + DP_DEBUG("VERSION=%d\n", buf[0]); + + if ((buf[2] & BIT(1)) && (buf[0] == 0x2)) + return true; +error: + return false; +} + +static int dp_hdcp2p2_change_streams(struct dp_hdcp2p2_ctrl *ctrl, + struct sde_hdcp_2x_wakeup_data *cdata) +{ + if (!ctrl || cdata->num_streams == 0 || !cdata->streams) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (!ctrl->lib_ctx) { + DP_ERR("HDCP library needs to be acquired\n"); + return -EINVAL; + } + + if (!ctrl->lib) { + DP_ERR("invalid lib ops data\n"); + return -EINVAL; + } + + cdata->context = ctrl->lib_ctx; + return ctrl->lib->wakeup(cdata); +} + + +static int dp_hdcp2p2_register_streams(void *input, u8 num_streams, + struct stream_info *streams) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_OPEN_STREAMS}; + + cdata.streams = streams; + cdata.num_streams = num_streams; + return dp_hdcp2p2_change_streams(ctrl, &cdata); +} + +static int dp_hdcp2p2_deregister_streams(void *input, u8 num_streams, + struct stream_info *streams) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_CLOSE_STREAMS}; + + cdata.streams = streams; + cdata.num_streams = num_streams; + return dp_hdcp2p2_change_streams(ctrl, &cdata); +} + +void sde_dp_hdcp2p2_deinit(void *input) +{ + struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; + struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID}; + + if (!ctrl) { + DP_ERR("invalid input\n"); + return; + } + + if (atomic_read(&ctrl->auth_state) != HDCP_STATE_AUTH_FAIL) { + cdata.cmd = HDCP_2X_CMD_STOP; + cdata.context = ctrl->lib_ctx; + dp_hdcp2p2_wakeup_lib(ctrl, &cdata); + } + + sde_hdcp_2x_deregister(ctrl->lib_ctx); + + kthread_stop(ctrl->thread); + + mutex_destroy(&ctrl->mutex); + mutex_destroy(&ctrl->msg_lock); + kfree(ctrl); +} + +static int dp_hdcp2p2_main(void *data) +{ + struct dp_hdcp2p2_ctrl *ctrl = data; + enum hdcp_transport_wakeup_cmd cmd; + + while (1) { + wait_event(ctrl->wait_q, + !kfifo_is_empty(&ctrl->cmd_q) || + kthread_should_stop() || + kthread_should_park()); + + if (kthread_should_stop()) + break; + + if (kfifo_is_empty(&ctrl->cmd_q) && kthread_should_park()) { + kthread_parkme(); + continue; + } + + if (!kfifo_get(&ctrl->cmd_q, &cmd)) + continue; + + switch (cmd) { + case HDCP_TRANSPORT_CMD_SEND_MESSAGE: + dp_hdcp2p2_send_msg(ctrl); + break; + case HDCP_TRANSPORT_CMD_RECV_MESSAGE: + if (ctrl->rx_status) + ctrl->polling = true; + else + dp_hdcp2p2_recv_msg(ctrl); + break; + case HDCP_TRANSPORT_CMD_STATUS_SUCCESS: + dp_hdcp2p2_send_auth_status(ctrl); + break; + case HDCP_TRANSPORT_CMD_STATUS_FAILED: + dp_hdcp2p2_set_interrupts(ctrl, false); + dp_hdcp2p2_send_auth_status(ctrl); + break; + case HDCP_TRANSPORT_CMD_LINK_POLL: + ctrl->polling = true; + break; + case HDCP_TRANSPORT_CMD_LINK_CHECK: + dp_hdcp2p2_link_check(ctrl); + break; + case HDCP_TRANSPORT_CMD_AUTHENTICATE: + dp_hdcp2p2_start_auth(ctrl); + break; + default: + break; + } + } + + return 0; +} + +static void dp_hdcp2p2_abort(void *input, bool abort) +{ + struct dp_hdcp2p2_ctrl *ctrl = input; + + atomic_set(&ctrl->abort, abort); +} + +void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data) +{ + int rc; + struct dp_hdcp2p2_ctrl *ctrl; + static struct sde_hdcp_ops ops = { + .isr = dp_hdcp2p2_isr, + .reauthenticate = dp_hdcp2p2_reauthenticate, + .authenticate = dp_hdcp2p2_authenticate, + .feature_supported = dp_hdcp2p2_feature_supported, + .force_encryption = dp_hdcp2p2_force_encryption, + .sink_support = dp_hdcp2p2_supported, + .set_mode = dp_hdcp2p2_register, + .on = dp_hdcp2p2_on, + .off = dp_hdcp2p2_off, + .abort = dp_hdcp2p2_abort, + .cp_irq = dp_hdcp2p2_cp_irq, + .register_streams = dp_hdcp2p2_register_streams, + .deregister_streams = dp_hdcp2p2_deregister_streams, + }; + + static struct hdcp_transport_ops client_ops = { + .wakeup = dp_hdcp2p2_wakeup, + }; + static struct dp_hdcp2p2_int_set int_set1[] = { + {BIT(17), "authentication successful", NULL}, + {BIT(20), "authentication failed", NULL}, + {BIT(24), "encryption enabled", NULL}, + {BIT(27), "encryption disabled", NULL}, + {0}, + }; + static struct dp_hdcp2p2_int_set int_set2[] = { + {BIT(2), "key fifo underflow", NULL}, + {0}, + }; + static struct dp_hdcp2p2_interrupts intr[] = { + {DP_INTR_STATUS2, int_set1}, + {DP_INTR_STATUS3, int_set2}, + {0} + }; + static struct sde_hdcp_2x_ops hdcp2x_ops; + struct sde_hdcp_2x_register_data register_data = {0}; + + if (!init_data || !init_data->cb_data || + !init_data->notify_status || !init_data->drm_aux) { + DP_ERR("invalid input\n"); + return ERR_PTR(-EINVAL); + } + + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return ERR_PTR(-ENOMEM); + + ctrl->init_data = *init_data; + ctrl->lib = &hdcp2x_ops; + ctrl->response.data = NULL; + ctrl->request.data = NULL; + + ctrl->sink_status = SINK_DISCONNECTED; + ctrl->intr = intr; + + INIT_KFIFO(ctrl->cmd_q); + + init_waitqueue_head(&ctrl->wait_q); + atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); + + ctrl->ops = &ops; + mutex_init(&ctrl->mutex); + mutex_init(&ctrl->msg_lock); + + register_data.hdcp_data = &ctrl->lib_ctx; + register_data.client_ops = &client_ops; + register_data.ops = &hdcp2x_ops; + register_data.client_data = ctrl; + + rc = sde_hdcp_2x_register(®ister_data); + if (rc) { + DP_ERR("Unable to register with HDCP 2.2 library\n"); + goto error; + } + + if (IS_ENABLED(CONFIG_HDCP_QSEECOM)) + msm_hdcp_register_cb(init_data->msm_hdcp_dev, ctrl, + dp_hdcp2p2_min_level_change); + + ctrl->thread = kthread_run(dp_hdcp2p2_main, ctrl, "dp_hdcp2p2"); + + if (IS_ERR(ctrl->thread)) { + DP_ERR("unable to start DP hdcp2p2 thread\n"); + rc = PTR_ERR(ctrl->thread); + ctrl->thread = NULL; + goto error; + } + + return ctrl; +error: + kfree(ctrl); + return ERR_PTR(rc); +} + +struct sde_hdcp_ops *sde_dp_hdcp2p2_get(void *input) +{ + return ((struct dp_hdcp2p2_ctrl *)input)->ops; +} diff --git a/techpack/display/msm/dp/dp_hpd.c b/techpack/display/msm/dp/dp_hpd.c new file mode 100644 index 0000000000000000000000000000000000000000..3c96350ccb3e105958e31d996cd4ed364a4afd24 --- /dev/null +++ b/techpack/display/msm/dp/dp_hpd.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> + +#include "dp_hpd.h" +#include "dp_usbpd.h" +#include "dp_gpio_hpd.h" +#include "dp_lphw_hpd.h" +#include "dp_debug.h" + +static void dp_hpd_host_init(struct dp_hpd *dp_hpd, + struct dp_catalog_hpd *catalog) +{ + if (!catalog) { + DP_ERR("invalid input\n"); + return; + } + catalog->config_hpd(catalog, true); +} + +static void dp_hpd_host_deinit(struct dp_hpd *dp_hpd, + struct dp_catalog_hpd *catalog) +{ + if (!catalog) { + DP_ERR("invalid input\n"); + return; + } + catalog->config_hpd(catalog, false); +} + +static void dp_hpd_isr(struct dp_hpd *dp_hpd) +{ +} + +struct dp_hpd *dp_hpd_get(struct device *dev, struct dp_parser *parser, + struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb) +{ + struct dp_hpd *dp_hpd; + + if (parser->no_aux_switch && parser->lphw_hpd) { + dp_hpd = dp_lphw_hpd_get(dev, parser, catalog, cb); + if (IS_ERR(dp_hpd)) { + DP_ERR("failed to get lphw hpd\n"); + return dp_hpd; + } + dp_hpd->type = DP_HPD_LPHW; + } else if (parser->no_aux_switch) { + dp_hpd = dp_gpio_hpd_get(dev, cb); + if (IS_ERR(dp_hpd)) { + DP_ERR("failed to get gpio hpd\n"); + return dp_hpd; + } + dp_hpd->type = DP_HPD_GPIO; + } else { + dp_hpd = dp_usbpd_get(dev, cb); + if (IS_ERR(dp_hpd)) { + DP_ERR("failed to get usbpd\n"); + return dp_hpd; + } + dp_hpd->type = DP_HPD_USBPD; + } + + if (!dp_hpd->host_init) + dp_hpd->host_init = dp_hpd_host_init; + if (!dp_hpd->host_deinit) + dp_hpd->host_deinit = dp_hpd_host_deinit; + if (!dp_hpd->isr) + dp_hpd->isr = dp_hpd_isr; + + return dp_hpd; +} + +void dp_hpd_put(struct dp_hpd *dp_hpd) +{ + if (!dp_hpd) + return; + + switch (dp_hpd->type) { + case DP_HPD_USBPD: + dp_usbpd_put(dp_hpd); + break; + case DP_HPD_GPIO: + dp_gpio_hpd_put(dp_hpd); + break; + case DP_HPD_LPHW: + dp_lphw_hpd_put(dp_hpd); + break; + default: + DP_ERR("unknown hpd type %d\n", dp_hpd->type); + break; + } +} diff --git a/techpack/display/msm/dp/dp_hpd.h b/techpack/display/msm/dp/dp_hpd.h new file mode 100644 index 0000000000000000000000000000000000000000..86806fbdf773413f6d3d29e251fc7d42aed6da20 --- /dev/null +++ b/techpack/display/msm/dp/dp_hpd.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_HPD_H_ +#define _DP_HPD_H_ + +#include <linux/types.h> +#include "dp_parser.h" +#include "dp_catalog.h" + +struct device; + +/** + * enum dp_hpd_type - dp hpd type + * @DP_HPD_USBPD: USB type-c based HPD + * @DP_HPD_GPIO: GPIO based HPD + * @DP_HPD_BUILTIN: Controller built-in HPD + */ + +enum dp_hpd_type { + DP_HPD_USBPD, + DP_HPD_GPIO, + DP_HPD_LPHW, + DP_HPD_BUILTIN, +}; + +/** + * struct dp_hpd_cb - callback functions provided by the client + * + * @configure: called when dp connection is ready. + * @disconnect: notify the cable disconnect event. + * @attention: notify any attention message event. + */ +struct dp_hpd_cb { + int (*configure)(struct device *dev); + int (*disconnect)(struct device *dev); + int (*attention)(struct device *dev); +}; + +/** + * struct dp_hpd - DisplayPort HPD status + * + * @type: type of HPD + * @orientation: plug orientation configuration, USBPD type only. + * @hpd_high: Hot Plug Detect signal is high. + * @hpd_irq: Change in the status since last message + * @alt_mode_cfg_done: bool to specify alt mode status + * @multi_func: multi-function preferred, USBPD type only + * @isr: event interrupt, BUILTIN and LPHW type only + * @register_hpd: register hardware callback + * @host_init: source or host side setup for hpd + * @host_deinit: source or host side de-initializations + * @simulate_connect: simulate disconnect or connect for debug mode + * @simulate_attention: simulate attention messages for debug mode + * @wakeup_phy: wakeup USBPD phy layer + */ +struct dp_hpd { + enum dp_hpd_type type; + u32 orientation; + bool hpd_high; + bool hpd_irq; + bool alt_mode_cfg_done; + bool multi_func; + bool peer_usb_comm; + + void (*isr)(struct dp_hpd *dp_hpd); + int (*register_hpd)(struct dp_hpd *dp_hpd); + void (*host_init)(struct dp_hpd *hpd, struct dp_catalog_hpd *catalog); + void (*host_deinit)(struct dp_hpd *hpd, struct dp_catalog_hpd *catalog); + int (*simulate_connect)(struct dp_hpd *dp_hpd, bool hpd); + int (*simulate_attention)(struct dp_hpd *dp_hpd, int vdo); + void (*wakeup_phy)(struct dp_hpd *dp_hpd, bool wakeup); +}; + +/** + * dp_hpd_get() - configure and get the DisplayPlot HPD module data + * + * @dev: device instance of the caller + * @parser: DP parser + * @cb: callback function for HPD response + * return: pointer to allocated hpd module data + * + * This function sets up the hpd module + */ +struct dp_hpd *dp_hpd_get(struct device *dev, struct dp_parser *parser, + struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb); + +/** + * dp_hpd_put() + * + * Cleans up dp_hpd instance + * + * @dp_hpd: instance of dp_hpd + */ +void dp_hpd_put(struct dp_hpd *dp_hpd); + +#endif /* _DP_HPD_H_ */ diff --git a/techpack/display/msm/dp/dp_link.c b/techpack/display/msm/dp/dp_link.c new file mode 100644 index 0000000000000000000000000000000000000000..20a09cf9bf5fb7466e6d2240196966a5e9c83389 --- /dev/null +++ b/techpack/display/msm/dp/dp_link.c @@ -0,0 +1,1529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include "dp_link.h" +#include "dp_panel.h" +#include "dp_debug.h" + +enum dynamic_range { + DP_DYNAMIC_RANGE_RGB_VESA = 0x00, + DP_DYNAMIC_RANGE_RGB_CEA = 0x01, + DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF, +}; + +enum audio_sample_rate { + AUDIO_SAMPLE_RATE_32_KHZ = 0x00, + AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01, + AUDIO_SAMPLE_RATE_48_KHZ = 0x02, + AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03, + AUDIO_SAMPLE_RATE_96_KHZ = 0x04, + AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05, + AUDIO_SAMPLE_RATE_192_KHZ = 0x06, +}; + +enum audio_pattern_type { + AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00, + AUDIO_TEST_PATTERN_SAWTOOTH = 0x01, +}; + +struct dp_link_request { + u32 test_requested; + u32 test_link_rate; + u32 test_lane_count; +}; + +struct dp_link_private { + u32 prev_sink_count; + struct device *dev; + struct dp_aux *aux; + struct dp_link dp_link; + + struct dp_link_request request; + u8 link_status[DP_LINK_STATUS_SIZE]; +}; + +static char *dp_link_get_audio_test_pattern(u32 pattern) +{ + switch (pattern) { + case AUDIO_TEST_PATTERN_OPERATOR_DEFINED: + return DP_LINK_ENUM_STR(AUDIO_TEST_PATTERN_OPERATOR_DEFINED); + case AUDIO_TEST_PATTERN_SAWTOOTH: + return DP_LINK_ENUM_STR(AUDIO_TEST_PATTERN_SAWTOOTH); + default: + return "unknown"; + } +} + +static char *dp_link_get_audio_sample_rate(u32 rate) +{ + switch (rate) { + case AUDIO_SAMPLE_RATE_32_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_32_KHZ); + case AUDIO_SAMPLE_RATE_44_1_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_44_1_KHZ); + case AUDIO_SAMPLE_RATE_48_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_48_KHZ); + case AUDIO_SAMPLE_RATE_88_2_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_88_2_KHZ); + case AUDIO_SAMPLE_RATE_96_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_96_KHZ); + case AUDIO_SAMPLE_RATE_176_4_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_176_4_KHZ); + case AUDIO_SAMPLE_RATE_192_KHZ: + return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_192_KHZ); + default: + return "unknown"; + } +} + +static int dp_link_get_period(struct dp_link_private *link, int const addr) +{ + int ret = 0; + u8 bp; + u8 data; + u32 const param_len = 0x1; + u32 const max_audio_period = 0xA; + + /* TEST_AUDIO_PERIOD_CH_XX */ + if (drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, + param_len) < param_len) { + DP_ERR("failed to read test_audio_period (0x%x)\n", addr); + ret = -EINVAL; + goto exit; + } + + data = bp; + + /* Period - Bits 3:0 */ + data = data & 0xF; + if ((int)data > max_audio_period) { + DP_ERR("invalid test_audio_period_ch_1 = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + ret = data; +exit: + return ret; +} + +static int dp_link_parse_audio_channel_period(struct dp_link_private *link) +{ + int ret = 0; + struct dp_link_test_audio *req = &link->dp_link.test_audio; + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_1 = ret; + DP_DEBUG("test_audio_period_ch_1 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_2 = ret; + DP_DEBUG("test_audio_period_ch_2 = 0x%x\n", ret); + + /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */ + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_3 = ret; + DP_DEBUG("test_audio_period_ch_3 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_4 = ret; + DP_DEBUG("test_audio_period_ch_4 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_5 = ret; + DP_DEBUG("test_audio_period_ch_5 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_6 = ret; + DP_DEBUG("test_audio_period_ch_6 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_7 = ret; + DP_DEBUG("test_audio_period_ch_7 = 0x%x\n", ret); + + ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8); + if (ret == -EINVAL) + goto exit; + + req->test_audio_period_ch_8 = ret; + DP_DEBUG("test_audio_period_ch_8 = 0x%x\n", ret); +exit: + return ret; +} + +static int dp_link_parse_audio_pattern_type(struct dp_link_private *link) +{ + int ret = 0; + u8 bp; + u8 data; + int rlen; + int const param_len = 0x1; + int const max_audio_pattern_type = 0x1; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, + DP_TEST_AUDIO_PATTERN_TYPE, &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read link audio mode data\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + /* Audio Pattern Type - Bits 7:0 */ + if ((int)data > max_audio_pattern_type) { + DP_ERR("invalid audio pattern type = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_audio.test_audio_pattern_type = data; + DP_DEBUG("audio pattern type = %s\n", + dp_link_get_audio_test_pattern(data)); +exit: + return ret; +} + +static int dp_link_parse_audio_mode(struct dp_link_private *link) +{ + int ret = 0; + u8 bp; + u8 data; + int rlen; + int const param_len = 0x1; + int const max_audio_sampling_rate = 0x6; + int const max_audio_channel_count = 0x8; + int sampling_rate = 0x0; + int channel_count = 0x0; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_AUDIO_MODE, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read link audio mode data\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + /* Sampling Rate - Bits 3:0 */ + sampling_rate = data & 0xF; + if (sampling_rate > max_audio_sampling_rate) { + DP_ERR("sampling rate (0x%x) greater than max (0x%x)\n", + sampling_rate, max_audio_sampling_rate); + ret = -EINVAL; + goto exit; + } + + /* Channel Count - Bits 7:4 */ + channel_count = ((data & 0xF0) >> 4) + 1; + if (channel_count > max_audio_channel_count) { + DP_ERR("channel_count (0x%x) greater than max (0x%x)\n", + channel_count, max_audio_channel_count); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate; + link->dp_link.test_audio.test_audio_channel_count = channel_count; + DP_DEBUG("sampling_rate = %s, channel_count = 0x%x\n", + dp_link_get_audio_sample_rate(sampling_rate), channel_count); +exit: + return ret; +} + +/** + * dp_parse_audio_pattern_params() - parses audio pattern parameters from DPCD + * @link: Display Port Driver data + * + * Returns 0 if it successfully parses the audio link pattern parameters. + */ +static int dp_link_parse_audio_pattern_params(struct dp_link_private *link) +{ + int ret = 0; + + ret = dp_link_parse_audio_mode(link); + if (ret) + goto exit; + + ret = dp_link_parse_audio_pattern_type(link); + if (ret) + goto exit; + + ret = dp_link_parse_audio_channel_period(link); + +exit: + return ret; +} + +/** + * dp_link_is_video_pattern_valid() - validates the video pattern + * @pattern: video pattern requested by the sink + * + * Returns true if the requested video pattern is supported. + */ +static bool dp_link_is_video_pattern_valid(u32 pattern) +{ + switch (pattern) { + case DP_NO_TEST_PATTERN: + case DP_COLOR_RAMP: + case DP_BLACK_AND_WHITE_VERTICAL_LINES: + case DP_COLOR_SQUARE: + return true; + default: + return false; + } +} + +static char *dp_link_video_pattern_to_string(u32 test_video_pattern) +{ + switch (test_video_pattern) { + case DP_NO_TEST_PATTERN: + return DP_LINK_ENUM_STR(DP_NO_TEST_PATTERN); + case DP_COLOR_RAMP: + return DP_LINK_ENUM_STR(DP_COLOR_RAMP); + case DP_BLACK_AND_WHITE_VERTICAL_LINES: + return DP_LINK_ENUM_STR(DP_BLACK_AND_WHITE_VERTICAL_LINES); + case DP_COLOR_SQUARE: + return DP_LINK_ENUM_STR(DP_COLOR_SQUARE); + default: + return "unknown"; + } +} + +/** + * dp_link_is_dynamic_range_valid() - validates the dynamic range + * @bit_depth: the dynamic range value to be checked + * + * Returns true if the dynamic range value is supported. + */ +static bool dp_link_is_dynamic_range_valid(u32 dr) +{ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_VESA: + case DP_DYNAMIC_RANGE_RGB_CEA: + return true; + default: + return false; + } +} + +static char *dp_link_dynamic_range_to_string(u32 dr) +{ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_VESA: + return DP_LINK_ENUM_STR(DP_DYNAMIC_RANGE_RGB_VESA); + case DP_DYNAMIC_RANGE_RGB_CEA: + return DP_LINK_ENUM_STR(DP_DYNAMIC_RANGE_RGB_CEA); + case DP_DYNAMIC_RANGE_UNKNOWN: + default: + return "unknown"; + } +} + +/** + * dp_link_is_bit_depth_valid() - validates the bit depth requested + * @bit_depth: bit depth requested by the sink + * + * Returns true if the requested bit depth is supported. + */ +static bool dp_link_is_bit_depth_valid(u32 tbd) +{ + /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + case DP_TEST_BIT_DEPTH_8: + case DP_TEST_BIT_DEPTH_10: + return true; + default: + return false; + } +} + +static char *dp_link_bit_depth_to_string(u32 tbd) +{ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_6); + case DP_TEST_BIT_DEPTH_8: + return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_8); + case DP_TEST_BIT_DEPTH_10: + return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_10); + case DP_TEST_BIT_DEPTH_UNKNOWN: + default: + return "unknown"; + } +} + +static int dp_link_parse_timing_params1(struct dp_link_private *link, + int const addr, int const len, u32 *val) +{ + u8 bp[2]; + int rlen; + + if (len < 2) + return -EINVAL; + + /* Read the requested video link pattern (Byte 0x221). */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len); + if (rlen < len) { + DP_ERR("failed to read 0x%x\n", addr); + return -EINVAL; + } + + *val = bp[1] | (bp[0] << 8); + + return 0; +} + +static int dp_link_parse_timing_params2(struct dp_link_private *link, + int const addr, int const len, u32 *val1, u32 *val2) +{ + u8 bp[2]; + int rlen; + + if (len < 2) + return -EINVAL; + + /* Read the requested video link pattern (Byte 0x221). */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len); + if (rlen < len) { + DP_ERR("failed to read 0x%x\n", addr); + return -EINVAL; + } + + *val1 = (bp[0] & BIT(7)) >> 7; + *val2 = bp[1] | ((bp[0] & 0x7F) << 8); + + return 0; +} + +static int dp_link_parse_timing_params3(struct dp_link_private *link, + int const addr, u32 *val) +{ + u8 bp; + u32 len = 1; + int rlen; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len); + if (rlen < 1) { + DP_ERR("failed to read 0x%x\n", addr); + return -EINVAL; + } + *val = bp; + + return 0; +} + +/** + * dp_parse_video_pattern_params() - parses video pattern parameters from DPCD + * @link: Display Port Driver data + * + * Returns 0 if it successfully parses the video link pattern and the link + * bit depth requested by the sink and, and if the values parsed are valid. + */ +static int dp_link_parse_video_pattern_params(struct dp_link_private *link) +{ + int ret = 0; + int rlen; + u8 bp; + u8 data; + u32 dyn_range; + int const param_len = 0x1; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PATTERN, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read link video pattern\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + if (!dp_link_is_video_pattern_valid(data)) { + DP_ERR("invalid link video pattern = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_video.test_video_pattern = data; + DP_DEBUG("link video pattern = 0x%x (%s)\n", + link->dp_link.test_video.test_video_pattern, + dp_link_video_pattern_to_string( + link->dp_link.test_video.test_video_pattern)); + + /* Read the requested color bit depth and dynamic range (Byte 0x232) */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read link bit depth\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + /* Dynamic Range */ + dyn_range = (data & DP_TEST_DYNAMIC_RANGE_CEA) >> 3; + if (!dp_link_is_dynamic_range_valid(dyn_range)) { + DP_ERR("invalid link dynamic range = 0x%x\n", dyn_range); + ret = -EINVAL; + goto exit; + } + link->dp_link.test_video.test_dyn_range = dyn_range; + DP_DEBUG("link dynamic range = 0x%x (%s)\n", + link->dp_link.test_video.test_dyn_range, + dp_link_dynamic_range_to_string( + link->dp_link.test_video.test_dyn_range)); + + /* Color bit depth */ + data &= DP_TEST_BIT_DEPTH_MASK; + if (!dp_link_is_bit_depth_valid(data)) { + DP_ERR("invalid link bit depth = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->dp_link.test_video.test_bit_depth = data; + DP_DEBUG("link bit depth = 0x%x (%s)\n", + link->dp_link.test_video.test_bit_depth, + dp_link_bit_depth_to_string( + link->dp_link.test_video.test_bit_depth)); + + /* resolution timing params */ + ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2, + &link->dp_link.test_video.test_h_total); + if (ret) { + DP_ERR("failed to parse test_h_total (DP_TEST_H_TOTAL_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_H_TOTAL = %d\n", link->dp_link.test_video.test_h_total); + + ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2, + &link->dp_link.test_video.test_v_total); + if (ret) { + DP_ERR("failed to parse test_v_total (DP_TEST_V_TOTAL_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_V_TOTAL = %d\n", link->dp_link.test_video.test_v_total); + + ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2, + &link->dp_link.test_video.test_h_start); + if (ret) { + DP_ERR("failed to parse test_h_start (DP_TEST_H_START_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_H_START = %d\n", link->dp_link.test_video.test_h_start); + + ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2, + &link->dp_link.test_video.test_v_start); + if (ret) { + DP_ERR("failed to parse test_v_start (DP_TEST_V_START_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_V_START = %d\n", link->dp_link.test_video.test_v_start); + + ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2, + &link->dp_link.test_video.test_hsync_pol, + &link->dp_link.test_video.test_hsync_width); + if (ret) { + DP_ERR("failed to parse (DP_TEST_HSYNC_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_HSYNC_POL = %d\n", + link->dp_link.test_video.test_hsync_pol); + DP_DEBUG("TEST_HSYNC_WIDTH = %d\n", + link->dp_link.test_video.test_hsync_width); + + ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2, + &link->dp_link.test_video.test_vsync_pol, + &link->dp_link.test_video.test_vsync_width); + if (ret) { + DP_ERR("failed to parse (DP_TEST_VSYNC_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_VSYNC_POL = %d\n", + link->dp_link.test_video.test_vsync_pol); + DP_DEBUG("TEST_VSYNC_WIDTH = %d\n", + link->dp_link.test_video.test_vsync_width); + + ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2, + &link->dp_link.test_video.test_h_width); + if (ret) { + DP_ERR("failed to parse test_h_width (DP_TEST_H_WIDTH_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_H_WIDTH = %d\n", link->dp_link.test_video.test_h_width); + + ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2, + &link->dp_link.test_video.test_v_height); + if (ret) { + DP_ERR("failed to parse test_v_height (DP_TEST_V_HEIGHT_HI)\n"); + goto exit; + } + DP_DEBUG("TEST_V_HEIGHT = %d\n", + link->dp_link.test_video.test_v_height); + + ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1, + &link->dp_link.test_video.test_rr_d); + link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR; + if (ret) { + DP_ERR("failed to parse test_rr_d (DP_TEST_MISC1)\n"); + goto exit; + } + DP_DEBUG("TEST_REFRESH_DENOMINATOR = %d\n", + link->dp_link.test_video.test_rr_d); + + ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR, + &link->dp_link.test_video.test_rr_n); + if (ret) { + DP_ERR("failed to parse test_rr_n (DP_TEST_REFRESH_RATE_NUMERATOR)\n"); + goto exit; + } + DP_DEBUG("TEST_REFRESH_NUMERATOR = %d\n", + link->dp_link.test_video.test_rr_n); +exit: + return ret; +} + +/** + * dp_link_parse_link_training_params() - parses link training parameters from + * DPCD + * @link: Display Port Driver data + * + * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane + * count (Byte 0x220), and if these values parse are valid. + */ +static int dp_link_parse_link_training_params(struct dp_link_private *link) +{ + u8 bp; + u8 data; + int ret = 0; + int rlen; + int const param_len = 0x1; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read link rate\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + + if (!is_link_rate_valid(data)) { + DP_ERR("invalid link rate = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->request.test_link_rate = data; + DP_DEBUG("link rate = 0x%x\n", link->request.test_link_rate); + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read lane count\n"); + ret = -EINVAL; + goto exit; + } + data = bp; + data &= 0x1F; + + if (!is_lane_count_valid(data)) { + DP_ERR("invalid lane count = 0x%x\n", data); + ret = -EINVAL; + goto exit; + } + + link->request.test_lane_count = data; + DP_DEBUG("lane count = 0x%x\n", link->request.test_lane_count); +exit: + return ret; +} + +static bool dp_link_is_phy_test_pattern_supported(u32 phy_test_pattern_sel) +{ + switch (phy_test_pattern_sel) { + case DP_TEST_PHY_PATTERN_NONE: + case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: + case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: + case DP_TEST_PHY_PATTERN_PRBS7: + case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1: + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3: + return true; + default: + return false; + } +} + +/** + * dp_parse_phy_test_params() - parses the phy link parameters + * @link: Display Port Driver data + * + * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being + * requested. + */ +static int dp_link_parse_phy_test_params(struct dp_link_private *link) +{ + u8 bp; + u8 data; + int rlen; + int const param_len = 0x1; + int ret = 0; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PHY_PATTERN, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed to read phy link pattern\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + link->dp_link.phy_params.phy_test_pattern_sel = data; + + DP_DEBUG("phy_test_pattern_sel = %s\n", + dp_link_get_phy_test_pattern(data)); + + if (!dp_link_is_phy_test_pattern_supported(data)) + ret = -EINVAL; +end: + return ret; +} + +/** + * dp_link_is_video_audio_test_requested() - checks for audio/video link request + * @link: link requested by the sink + * + * Returns true if the requested link is a permitted audio/video link. + */ +static bool dp_link_is_video_audio_test_requested(u32 link) +{ + return (link == DP_TEST_LINK_VIDEO_PATTERN) || + (link == (DP_TEST_LINK_AUDIO_PATTERN | + DP_TEST_LINK_VIDEO_PATTERN)) || + (link == DP_TEST_LINK_AUDIO_PATTERN) || + (link == (DP_TEST_LINK_AUDIO_PATTERN | + DP_TEST_LINK_AUDIO_DISABLED_VIDEO)); +} + +/** + * dp_link_supported() - checks if link requested by sink is supported + * @test_requested: link requested by the sink + * + * Returns true if the requested link is supported. + */ +static bool dp_link_is_test_supported(u32 test_requested) +{ + return (test_requested == DP_TEST_LINK_TRAINING) || + (test_requested == DP_TEST_LINK_EDID_READ) || + (test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) || + dp_link_is_video_audio_test_requested(test_requested); +} + +static bool dp_link_is_test_edid_read(struct dp_link_private *link) +{ + return (link->request.test_requested == DP_TEST_LINK_EDID_READ); +} + +/** + * dp_sink_parse_test_request() - parses link request parameters from sink + * @link: Display Port Driver data + * + * Parses the DPCD to check if an automated link is requested (Byte 0x201), + * and what type of link automation is being requested (Byte 0x218). + */ +static int dp_link_parse_request(struct dp_link_private *link) +{ + int ret = 0; + u8 bp; + u8 data; + int rlen; + u32 const param_len = 0x1; + + /** + * Read the device service IRQ vector (Byte 0x201) to determine + * whether an automated link has been requested by the sink. + */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, + DP_DEVICE_SERVICE_IRQ_VECTOR, &bp, param_len); + if (rlen < param_len) { + DP_ERR("aux read failed\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + if (!(data & DP_AUTOMATED_TEST_REQUEST)) + return 0; + + /** + * Read the link request byte (Byte 0x218) to determine what type + * of automated link has been requested by the sink. + */ + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_REQUEST, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("aux read failed\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + if (!dp_link_is_test_supported(data)) { + DP_DEBUG("link 0x%x not supported\n", data); + goto end; + } + + link->request.test_requested = data; + + if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) { + ret = dp_link_parse_phy_test_params(link); + if (ret) + goto end; + ret = dp_link_parse_link_training_params(link); + } + + if (link->request.test_requested == DP_TEST_LINK_TRAINING) + ret = dp_link_parse_link_training_params(link); + + if (dp_link_is_video_audio_test_requested( + link->request.test_requested)) { + ret = dp_link_parse_video_pattern_params(link); + if (ret) + goto end; + + ret = dp_link_parse_audio_pattern_params(link); + } +end: + /** + * Send a DP_TEST_ACK if all link parameters are valid, otherwise send + * a DP_TEST_NAK. + */ + if (ret) { + link->dp_link.test_response = DP_TEST_NAK; + } else { + if (!dp_link_is_test_edid_read(link)) + link->dp_link.test_response = DP_TEST_ACK; + else + link->dp_link.test_response = + DP_TEST_EDID_CHECKSUM_WRITE; + } + + return ret; +} + +/** + * dp_link_parse_sink_count() - parses the sink count + * + * Parses the DPCD to check if there is an update to the sink count + * (Byte 0x200), and whether all the sink devices connected have Content + * Protection enabled. + */ +static int dp_link_parse_sink_count(struct dp_link *dp_link) +{ + int rlen; + int const param_len = 0x1; + struct dp_link_private *link = container_of(dp_link, + struct dp_link_private, dp_link); + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT, + &link->dp_link.sink_count.count, param_len); + if (rlen < param_len) { + DP_ERR("failed to read sink count\n"); + return -EINVAL; + } + + link->dp_link.sink_count.cp_ready = + link->dp_link.sink_count.count & DP_SINK_CP_READY; + /* BIT 7, BIT 5:0 */ + link->dp_link.sink_count.count = + DP_GET_SINK_COUNT(link->dp_link.sink_count.count); + + DP_DEBUG("sink_count = 0x%x, cp_ready = 0x%x\n", + link->dp_link.sink_count.count, + link->dp_link.sink_count.cp_ready); + return 0; +} + +static void dp_link_parse_sink_status_field(struct dp_link_private *link) +{ + int len = 0; + + link->prev_sink_count = link->dp_link.sink_count.count; + dp_link_parse_sink_count(&link->dp_link); + + len = drm_dp_dpcd_read_link_status(link->aux->drm_aux, + link->link_status); + if (len < DP_LINK_STATUS_SIZE) + DP_ERR("DP link status read failed\n"); + dp_link_parse_request(link); +} + +static bool dp_link_is_link_training_requested(struct dp_link_private *link) +{ + return (link->request.test_requested == DP_TEST_LINK_TRAINING); +} + +/** + * dp_link_process_link_training_request() - processes new training requests + * @link: Display Port link data + * + * This function will handle new link training requests that are initiated by + * the sink. In particular, it will update the requested lane count and link + * link rate, and then trigger the link retraining procedure. + * + * The function will return 0 if a link training request has been processed, + * otherwise it will return -EINVAL. + */ +static int dp_link_process_link_training_request(struct dp_link_private *link) +{ + if (!dp_link_is_link_training_requested(link)) + return -EINVAL; + + DP_DEBUG("%s link rate = 0x%x, lane count = 0x%x\n", + dp_link_get_test_name(DP_TEST_LINK_TRAINING), + link->request.test_link_rate, + link->request.test_lane_count); + + link->dp_link.link_params.lane_count = link->request.test_lane_count; + link->dp_link.link_params.bw_code = link->request.test_link_rate; + + return 0; +} + +static void dp_link_send_test_response(struct dp_link *dp_link) +{ + struct dp_link_private *link = NULL; + u32 const response_len = 0x1; + + if (!dp_link) { + DP_ERR("invalid input\n"); + return; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_RESPONSE, + &dp_link->test_response, response_len); +} + +static int dp_link_psm_config(struct dp_link *dp_link, + struct drm_dp_link *link_info, bool enable) +{ + struct dp_link_private *link = NULL; + int ret = 0; + + if (!dp_link) { + DP_ERR("invalid params\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + if (enable) + ret = drm_dp_link_power_down(link->aux->drm_aux, link_info); + else + ret = drm_dp_link_power_up(link->aux->drm_aux, link_info); + + if (ret) + DP_ERR("Failed to %s low power mode\n", + (enable ? "enter" : "exit")); + + return ret; +} + +static void dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum) +{ + struct dp_link_private *link = NULL; + u32 const response_len = 0x1; + + if (!dp_link) { + DP_ERR("invalid input\n"); + return; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_EDID_CHECKSUM, + &checksum, response_len); +} + +static int dp_link_parse_vx_px(struct dp_link_private *link) +{ + u8 bp; + u8 data; + int const param_len = 0x1; + int ret = 0; + u32 v0, p0, v1, p1, v2, p2, v3, p3; + int rlen; + + DP_DEBUG("\n"); + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE0_1, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed reading lanes 0/1\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + DP_DEBUG("lanes 0/1 (Byte 0x206): 0x%x\n", data); + + v0 = data & 0x3; + data = data >> 2; + p0 = data & 0x3; + data = data >> 2; + + v1 = data & 0x3; + data = data >> 2; + p1 = data & 0x3; + data = data >> 2; + + rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE2_3, + &bp, param_len); + if (rlen < param_len) { + DP_ERR("failed reading lanes 2/3\n"); + ret = -EINVAL; + goto end; + } + + data = bp; + + DP_DEBUG("lanes 2/3 (Byte 0x207): 0x%x\n", data); + + v2 = data & 0x3; + data = data >> 2; + p2 = data & 0x3; + data = data >> 2; + + v3 = data & 0x3; + data = data >> 2; + p3 = data & 0x3; + data = data >> 2; + + DP_DEBUG("vx: 0=%d, 1=%d, 2=%d, 3=%d\n", v0, v1, v2, v3); + DP_DEBUG("px: 0=%d, 1=%d, 2=%d, 3=%d\n", p0, p1, p2, p3); + + /** + * Update the voltage and pre-emphasis levels as per DPCD request + * vector. + */ + DP_DEBUG("Current: v_level = 0x%x, p_level = 0x%x\n", + link->dp_link.phy_params.v_level, + link->dp_link.phy_params.p_level); + DP_DEBUG("Requested: v_level = 0x%x, p_level = 0x%x\n", v0, p0); + link->dp_link.phy_params.v_level = v0; + link->dp_link.phy_params.p_level = p0; + + DP_DEBUG("Success\n"); +end: + return ret; +} + +/** + * dp_link_process_phy_test_pattern_request() - process new phy link requests + * @link: Display Port Driver data + * + * This function will handle new phy link pattern requests that are initiated + * by the sink. The function will return 0 if a phy link pattern has been + * processed, otherwise it will return -EINVAL. + */ +static int dp_link_process_phy_test_pattern_request( + struct dp_link_private *link) +{ + u32 test_link_rate = 0, test_lane_count = 0; + + if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) { + DP_DEBUG("no phy test\n"); + return -EINVAL; + } + + test_link_rate = link->request.test_link_rate; + test_lane_count = link->request.test_lane_count; + + if (!is_link_rate_valid(test_link_rate) || + !is_lane_count_valid(test_lane_count)) { + DP_ERR("Invalid params: link rate = 0x%x, lane count = 0x%x\n", + test_link_rate, test_lane_count); + return -EINVAL; + } + + DP_DEBUG("start\n"); + + DP_INFO("Current: bw_code = 0x%x, lane count = 0x%x\n", + link->dp_link.link_params.bw_code, + link->dp_link.link_params.lane_count); + + DP_INFO("Requested: bw_code = 0x%x, lane count = 0x%x\n", + test_link_rate, test_lane_count); + + link->dp_link.link_params.lane_count = link->request.test_lane_count; + link->dp_link.link_params.bw_code = link->request.test_link_rate; + + dp_link_parse_vx_px(link); + + DP_DEBUG("end\n"); + + return 0; +} + +static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) +{ + return link_status[r - DP_LANE0_1_STATUS]; +} + +/** + * dp_link_process_link_status_update() - processes link status updates + * @link: Display Port link module data + * + * This function will check for changes in the link status, e.g. clock + * recovery done on all lanes, and trigger link training if there is a + * failure/error on the link. + * + * The function will return 0 if the a link status update has been processed, + * otherwise it will return -EINVAL. + */ +static int dp_link_process_link_status_update(struct dp_link_private *link) +{ + if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & + DP_LINK_STATUS_UPDATED) || /* link status updated */ + (drm_dp_clock_recovery_ok(link->link_status, + link->dp_link.link_params.lane_count) && + drm_dp_channel_eq_ok(link->link_status, + link->dp_link.link_params.lane_count))) + return -EINVAL; + + DP_DEBUG("channel_eq_done = %d, clock_recovery_done = %d\n", + drm_dp_channel_eq_ok(link->link_status, + link->dp_link.link_params.lane_count), + drm_dp_clock_recovery_ok(link->link_status, + link->dp_link.link_params.lane_count)); + + return 0; +} + +static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link) +{ + if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & + DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */ + return true; + + if (link->prev_sink_count != link->dp_link.sink_count.count) + return true; + + return false; +} + +/** + * dp_link_process_downstream_port_status_change() - process port status changes + * @link: Display Port Driver data + * + * This function will handle downstream port updates that are initiated by + * the sink. If the downstream port status has changed, the EDID is read via + * AUX. + * + * The function will return 0 if a downstream port update has been + * processed, otherwise it will return -EINVAL. + */ +static int dp_link_process_ds_port_status_change(struct dp_link_private *link) +{ + if (!dp_link_is_ds_port_status_changed(link)) + return -EINVAL; + + /* reset prev_sink_count */ + link->prev_sink_count = link->dp_link.sink_count.count; + + return 0; +} + +static bool dp_link_is_video_pattern_requested(struct dp_link_private *link) +{ + return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN) + && !(link->request.test_requested & + DP_TEST_LINK_AUDIO_DISABLED_VIDEO); +} + +static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link) +{ + return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN); +} + +/** + * dp_link_process_video_pattern_request() - process new video pattern request + * @link: Display Port link module's data + * + * This function will handle a new video pattern request that are initiated by + * the sink. This is acheieved by first sending a disconnect notification to + * the sink followed by a subsequent connect notification to the user modules, + * where it is expected that the user modules would draw the required link + * pattern. + */ +static int dp_link_process_video_pattern_request(struct dp_link_private *link) +{ + if (!dp_link_is_video_pattern_requested(link)) + goto end; + + DP_DEBUG("%s: bit depth=%d(%d bpp) pattern=%s\n", + dp_link_get_test_name(DP_TEST_LINK_VIDEO_PATTERN), + link->dp_link.test_video.test_bit_depth, + dp_link_bit_depth_to_bpp( + link->dp_link.test_video.test_bit_depth), + dp_link_video_pattern_to_string( + link->dp_link.test_video.test_video_pattern)); + + return 0; +end: + return -EINVAL; +} + +/** + * dp_link_process_audio_pattern_request() - process new audio pattern request + * @link: Display Port link module data + * + * This function will handle a new audio pattern request that is initiated by + * the sink. This is acheieved by sending the necessary secondary data packets + * to the sink. It is expected that any simulatenous requests for video + * patterns will be handled before the audio pattern is sent to the sink. + */ +static int dp_link_process_audio_pattern_request(struct dp_link_private *link) +{ + if (!dp_link_is_audio_pattern_requested(link)) + return -EINVAL; + + DP_DEBUG("sampling_rate=%s, channel_count=%d, pattern_type=%s\n", + dp_link_get_audio_sample_rate( + link->dp_link.test_audio.test_audio_sampling_rate), + link->dp_link.test_audio.test_audio_channel_count, + dp_link_get_audio_test_pattern( + link->dp_link.test_audio.test_audio_pattern_type)); + + DP_DEBUG("audio_period: ch1=0x%x, ch2=0x%x, ch3=0x%x, ch4=0x%x\n", + link->dp_link.test_audio.test_audio_period_ch_1, + link->dp_link.test_audio.test_audio_period_ch_2, + link->dp_link.test_audio.test_audio_period_ch_3, + link->dp_link.test_audio.test_audio_period_ch_4); + + DP_DEBUG("audio_period: ch5=0x%x, ch6=0x%x, ch7=0x%x, ch8=0x%x\n", + link->dp_link.test_audio.test_audio_period_ch_5, + link->dp_link.test_audio.test_audio_period_ch_6, + link->dp_link.test_audio.test_audio_period_ch_7, + link->dp_link.test_audio.test_audio_period_ch_8); + + return 0; +} + +static void dp_link_reset_data(struct dp_link_private *link) +{ + link->request = (const struct dp_link_request){ 0 }; + link->dp_link.test_video = (const struct dp_link_test_video){ 0 }; + link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN; + link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 }; + link->dp_link.phy_params.phy_test_pattern_sel = 0; + link->dp_link.sink_request = 0; + link->dp_link.test_response = 0; +} + +/** + * dp_link_process_request() - handle HPD IRQ transition to HIGH + * @link: pointer to link module data + * + * This function will handle the HPD IRQ state transitions from LOW to HIGH + * (including cases when there are back to back HPD IRQ HIGH) indicating + * the start of a new link training request or sink status update. + */ +static int dp_link_process_request(struct dp_link *dp_link) +{ + int ret = 0; + struct dp_link_private *link; + + if (!dp_link) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + dp_link_reset_data(link); + + dp_link_parse_sink_status_field(link); + + if (dp_link_is_test_edid_read(link)) { + dp_link->sink_request |= DP_TEST_LINK_EDID_READ; + goto exit; + } + + ret = dp_link_process_ds_port_status_change(link); + if (!ret) { + dp_link->sink_request |= DS_PORT_STATUS_CHANGED; + goto exit; + } + + ret = dp_link_process_link_training_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_TRAINING; + goto exit; + } + + ret = dp_link_process_phy_test_pattern_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN; + goto exit; + } + + ret = dp_link_process_link_status_update(link); + if (!ret) { + dp_link->sink_request |= DP_LINK_STATUS_UPDATED; + goto exit; + } + + ret = dp_link_process_video_pattern_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN; + goto exit; + } + + ret = dp_link_process_audio_pattern_request(link); + if (!ret) { + dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN; + goto exit; + } + + DP_DEBUG("no test requested\n"); + return ret; +exit: + /* + * log this as it can be a use initiated action to run a DP CTS + * test or in normal cases, sink has encountered a problem and + * and want source to redo some part of initialization which can + * be helpful in debugging. + */ + DP_INFO("test requested: %s\n", + dp_link_get_test_name(dp_link->sink_request)); + return 0; +} + +static int dp_link_get_colorimetry_config(struct dp_link *dp_link) +{ + u32 cc; + enum dynamic_range dr; + struct dp_link_private *link; + + if (!dp_link) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + /* unless a video pattern CTS test is ongoing, use CEA_VESA */ + if (dp_link_is_video_pattern_requested(link)) + dr = link->dp_link.test_video.test_dyn_range; + else + dr = DP_DYNAMIC_RANGE_RGB_VESA; + + /* Only RGB_VESA nd RGB_CEA supported for now */ + switch (dr) { + case DP_DYNAMIC_RANGE_RGB_CEA: + cc = BIT(2); + break; + case DP_DYNAMIC_RANGE_RGB_VESA: + default: + cc = 0; + } + + return cc; +} + +static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) +{ + int i; + int max = 0; + u8 data; + struct dp_link_private *link; + u8 buf[8] = {0}, offset = 0; + + if (!dp_link) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + /* use the max level across lanes */ + for (i = 0; i < dp_link->link_params.lane_count; i++) { + data = drm_dp_get_adjust_request_voltage(link_status, i); + data >>= DP_TRAIN_VOLTAGE_SWING_SHIFT; + + offset = i * 2; + if (offset < sizeof(buf)) + buf[offset] = data; + + if (max < data) + max = data; + } + + dp_link->phy_params.v_level = max; + + /* use the max level across lanes */ + max = 0; + for (i = 0; i < dp_link->link_params.lane_count; i++) { + data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); + data >>= DP_TRAIN_PRE_EMPHASIS_SHIFT; + + offset = (i * 2) + 1; + if (offset < sizeof(buf)) + buf[offset] = data; + + if (max < data) + max = data; + } + + dp_link->phy_params.p_level = max; + + print_hex_dump(KERN_DEBUG, "[drm-dp] Req (VxPx): ", + DUMP_PREFIX_NONE, 8, 2, buf, sizeof(buf), false); + + /** + * Adjust the voltage swing and pre-emphasis level combination to within + * the allowable range. + */ + if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) + dp_link->phy_params.v_level = DP_LINK_VOLTAGE_MAX; + + if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) + dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_MAX; + + if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1) + && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) + dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1; + + if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_2) + && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_1)) + dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_2; + + DP_DEBUG("Set (VxPx): %x%x\n", + dp_link->phy_params.v_level, dp_link->phy_params.p_level); + + return 0; +} + +static int dp_link_send_psm_request(struct dp_link *dp_link, bool req) +{ + struct dp_link_private *link; + + if (!dp_link) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + link = container_of(dp_link, struct dp_link_private, dp_link); + + return 0; +} + +static u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) +{ + u32 tbd; + + /* + * Few simplistic rules and assumptions made here: + * 1. Test bit depth is bit depth per color component + * 2. Assume 3 color components + */ + switch (bpp) { + case 18: + tbd = DP_TEST_BIT_DEPTH_6; + break; + case 24: + tbd = DP_TEST_BIT_DEPTH_8; + break; + case 30: + tbd = DP_TEST_BIT_DEPTH_10; + break; + default: + tbd = DP_TEST_BIT_DEPTH_UNKNOWN; + break; + } + + if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN) + tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT); + + return tbd; +} + +struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux) +{ + int rc = 0; + struct dp_link_private *link; + struct dp_link *dp_link; + + if (!dev || !aux) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); + if (!link) { + rc = -EINVAL; + goto error; + } + + link->dev = dev; + link->aux = aux; + + dp_link = &link->dp_link; + + dp_link->process_request = dp_link_process_request; + dp_link->get_test_bits_depth = dp_link_get_test_bits_depth; + dp_link->get_colorimetry_config = dp_link_get_colorimetry_config; + dp_link->adjust_levels = dp_link_adjust_levels; + dp_link->send_psm_request = dp_link_send_psm_request; + dp_link->send_test_response = dp_link_send_test_response; + dp_link->psm_config = dp_link_psm_config; + dp_link->send_edid_checksum = dp_link_send_edid_checksum; + + return dp_link; +error: + return ERR_PTR(rc); +} + +void dp_link_put(struct dp_link *dp_link) +{ + struct dp_link_private *link; + + if (!dp_link) + return; + + link = container_of(dp_link, struct dp_link_private, dp_link); + + devm_kfree(link->dev, link); +} diff --git a/techpack/display/msm/dp/dp_link.h b/techpack/display/msm/dp/dp_link.h new file mode 100644 index 0000000000000000000000000000000000000000..db3456d973e34a5073837319555a67fd73983334 --- /dev/null +++ b/techpack/display/msm/dp/dp_link.h @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_LINK_H_ +#define _DP_LINK_H_ + +#include "dp_aux.h" + +#define DS_PORT_STATUS_CHANGED 0x200 +#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF +#define DP_LINK_ENUM_STR(x) #x + +enum dp_link_voltage_level { + DP_LINK_VOLTAGE_LEVEL_0, + DP_LINK_VOLTAGE_LEVEL_1, + DP_LINK_VOLTAGE_LEVEL_2, + DP_LINK_VOLTAGE_MAX = DP_LINK_VOLTAGE_LEVEL_2, +}; + +enum dp_link_preemaphasis_level { + DP_LINK_PRE_EMPHASIS_LEVEL_0, + DP_LINK_PRE_EMPHASIS_LEVEL_1, + DP_LINK_PRE_EMPHASIS_LEVEL_2, + DP_LINK_PRE_EMPHASIS_LEVEL_3, + DP_LINK_PRE_EMPHASIS_MAX = DP_LINK_PRE_EMPHASIS_LEVEL_3, +}; + +struct dp_link_sink_count { + u32 count; + bool cp_ready; +}; + +struct dp_link_test_video { + u32 test_video_pattern; + u32 test_bit_depth; + u32 test_dyn_range; + u32 test_h_total; + u32 test_v_total; + u32 test_h_start; + u32 test_v_start; + u32 test_hsync_pol; + u32 test_hsync_width; + u32 test_vsync_pol; + u32 test_vsync_width; + u32 test_h_width; + u32 test_v_height; + u32 test_rr_d; + u32 test_rr_n; +}; + +struct dp_link_test_audio { + u32 test_audio_sampling_rate; + u32 test_audio_channel_count; + u32 test_audio_pattern_type; + u32 test_audio_period_ch_1; + u32 test_audio_period_ch_2; + u32 test_audio_period_ch_3; + u32 test_audio_period_ch_4; + u32 test_audio_period_ch_5; + u32 test_audio_period_ch_6; + u32 test_audio_period_ch_7; + u32 test_audio_period_ch_8; +}; + +struct dp_link_hdcp_status { + int hdcp_state; + int hdcp_version; +}; + +struct dp_link_phy_params { + u32 phy_test_pattern_sel; + u8 v_level; + u8 p_level; +}; + +struct dp_link_params { + u32 lane_count; + u32 bw_code; +}; + +static inline char *dp_link_get_test_name(u32 test_requested) +{ + switch (test_requested) { + case DP_TEST_LINK_TRAINING: + return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING); + case DP_TEST_LINK_VIDEO_PATTERN: + return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN); + case DP_TEST_LINK_EDID_READ: + return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ); + case DP_TEST_LINK_PHY_TEST_PATTERN: + return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN); + case DP_TEST_LINK_AUDIO_PATTERN: + return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN); + case DS_PORT_STATUS_CHANGED: + return DP_LINK_ENUM_STR(DS_PORT_STATUS_CHANGED); + case DP_LINK_STATUS_UPDATED: + return DP_LINK_ENUM_STR(DP_LINK_STATUS_UPDATED); + default: + return "unknown"; + } +} + +struct dp_link { + u32 sink_request; + u32 test_response; + + struct dp_link_sink_count sink_count; + struct dp_link_test_video test_video; + struct dp_link_test_audio test_audio; + struct dp_link_phy_params phy_params; + struct dp_link_params link_params; + struct dp_link_hdcp_status hdcp_status; + + u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp); + int (*process_request)(struct dp_link *dp_link); + int (*get_colorimetry_config)(struct dp_link *dp_link); + int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status); + int (*send_psm_request)(struct dp_link *dp_link, bool req); + void (*send_test_response)(struct dp_link *dp_link); + int (*psm_config)(struct dp_link *dp_link, + struct drm_dp_link *link_info, bool enable); + void (*send_edid_checksum)(struct dp_link *dp_link, u8 checksum); +}; + +static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel) +{ + switch (phy_test_pattern_sel) { + case DP_TEST_PHY_PATTERN_NONE: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE); + case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: + return DP_LINK_ENUM_STR( + DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING); + case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: + return DP_LINK_ENUM_STR( + DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT); + case DP_TEST_PHY_PATTERN_PRBS7: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7); + case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: + return DP_LINK_ENUM_STR( + DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN); + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_1); + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_2: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_2); + case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3: + return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_3); + default: + return "unknown"; + } +} + +/** + * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp + * @tbd: test bit depth + * + * Returns the bits per pixel (bpp) to be used corresponding to the + * git bit depth value. This function assumes that bit depth has + * already been validated. + */ +static inline u32 dp_link_bit_depth_to_bpp(u32 tbd) +{ + u32 bpp; + + /* + * Few simplistic rules and assumptions made here: + * 1. Bit depth is per color component + * 2. If bit depth is unknown return 0 + * 3. Assume 3 color components + */ + switch (tbd) { + case DP_TEST_BIT_DEPTH_6: + bpp = 18; + break; + case DP_TEST_BIT_DEPTH_8: + bpp = 24; + break; + case DP_TEST_BIT_DEPTH_10: + bpp = 30; + break; + case DP_TEST_BIT_DEPTH_UNKNOWN: + default: + bpp = 0; + } + + return bpp; +} + +/** + * dp_link_get() - get the functionalities of dp test module + * + * + * return: a pointer to dp_link struct + */ +struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux); + +/** + * dp_link_put() - releases the dp test module's resources + * + * @dp_link: an instance of dp_link module + * + */ +void dp_link_put(struct dp_link *dp_link); + +#endif /* _DP_LINK_H_ */ diff --git a/techpack/display/msm/dp/dp_lphw_hpd.c b/techpack/display/msm/dp/dp_lphw_hpd.c new file mode 100644 index 0000000000000000000000000000000000000000..7fbd01449c2f78ded175cde29bcd3ed45a6f6e88 --- /dev/null +++ b/techpack/display/msm/dp/dp_lphw_hpd.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/sde_io_util.h> +#include <linux/of_gpio.h> +#include "dp_lphw_hpd.h" +#include "dp_debug.h" + +struct dp_lphw_hpd_private { + struct device *dev; + struct dp_hpd base; + struct dp_parser *parser; + struct dp_catalog_hpd *catalog; + struct dss_gpio gpio_cfg; + struct workqueue_struct *connect_wq; + struct delayed_work work; + struct work_struct connect; + struct work_struct disconnect; + struct work_struct attention; + struct dp_hpd_cb *cb; + int irq; + bool hpd; +}; + +static void dp_lphw_hpd_attention(struct work_struct *work) +{ + struct dp_lphw_hpd_private *lphw_hpd = container_of(work, + struct dp_lphw_hpd_private, attention); + + if (!lphw_hpd) { + DP_ERR("invalid input\n"); + return; + } + + lphw_hpd->base.hpd_irq = true; + + if (lphw_hpd->cb && lphw_hpd->cb->attention) + lphw_hpd->cb->attention(lphw_hpd->dev); +} + +static void dp_lphw_hpd_connect(struct work_struct *work) +{ + struct dp_lphw_hpd_private *lphw_hpd = container_of(work, + struct dp_lphw_hpd_private, connect); + + if (!lphw_hpd) { + DP_ERR("invalid input\n"); + return; + } + + lphw_hpd->base.hpd_high = true; + lphw_hpd->base.alt_mode_cfg_done = true; + lphw_hpd->base.hpd_irq = false; + + if (lphw_hpd->cb && lphw_hpd->cb->configure) + lphw_hpd->cb->configure(lphw_hpd->dev); +} + +static void dp_lphw_hpd_disconnect(struct work_struct *work) +{ + struct dp_lphw_hpd_private *lphw_hpd = container_of(work, + struct dp_lphw_hpd_private, disconnect); + + if (!lphw_hpd) { + DP_ERR("invalid input\n"); + return; + } + + lphw_hpd->base.hpd_high = false; + lphw_hpd->base.alt_mode_cfg_done = false; + lphw_hpd->base.hpd_irq = false; + + if (lphw_hpd->cb && lphw_hpd->cb->disconnect) + lphw_hpd->cb->disconnect(lphw_hpd->dev); +} + +static irqreturn_t dp_tlmm_isr(int unused, void *data) +{ + struct dp_lphw_hpd_private *lphw_hpd = data; + bool hpd; + + if (!lphw_hpd) + return IRQ_NONE; + + /* + * According to the DP spec, HPD high event can be confirmed only after + * the HPD line has een asserted continuously for more than 100ms + */ + usleep_range(99000, 100000); + + hpd = gpio_get_value_cansleep(lphw_hpd->gpio_cfg.gpio); + + DP_DEBUG("lphw_hpd state = %d, new hpd state = %d\n", + lphw_hpd->hpd, hpd); + if (!lphw_hpd->hpd && hpd) { + lphw_hpd->hpd = true; + queue_work(lphw_hpd->connect_wq, &lphw_hpd->connect); + } + + return IRQ_HANDLED; +} + +static void dp_lphw_hpd_host_init(struct dp_hpd *dp_hpd, + struct dp_catalog_hpd *catalog) +{ + struct dp_lphw_hpd_private *lphw_hpd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + return; + } + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + lphw_hpd->catalog->config_hpd(lphw_hpd->catalog, true); + + /* + * Changing the gpio function to dp controller for the hpd line is not + * stopping the tlmm interrupts generation on function 0. + * So, as an additional step, disable the gpio interrupt irq also + */ + disable_irq(lphw_hpd->irq); +} + +static void dp_lphw_hpd_host_deinit(struct dp_hpd *dp_hpd, + struct dp_catalog_hpd *catalog) +{ + struct dp_lphw_hpd_private *lphw_hpd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + return; + } + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + /* Enable the tlmm interrupt irq which was disabled in host_init */ + enable_irq(lphw_hpd->irq); + + lphw_hpd->catalog->config_hpd(lphw_hpd->catalog, false); +} + +static void dp_lphw_hpd_isr(struct dp_hpd *dp_hpd) +{ + struct dp_lphw_hpd_private *lphw_hpd; + u32 isr = 0; + int rc = 0; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + return; + } + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + isr = lphw_hpd->catalog->get_interrupt(lphw_hpd->catalog); + + if (isr & DP_HPD_UNPLUG_INT_STATUS) { /* disconnect interrupt */ + + DP_DEBUG("disconnect interrupt, hpd isr state: 0x%x\n", isr); + + if (lphw_hpd->base.hpd_high) { + lphw_hpd->hpd = false; + lphw_hpd->base.hpd_high = false; + lphw_hpd->base.alt_mode_cfg_done = false; + lphw_hpd->base.hpd_irq = false; + + rc = queue_work(lphw_hpd->connect_wq, + &lphw_hpd->disconnect); + if (!rc) + DP_DEBUG("disconnect not queued\n"); + } else { + DP_ERR("already disconnected\n"); + } + + } else if (isr & DP_IRQ_HPD_INT_STATUS) { /* attention interrupt */ + + DP_DEBUG("hpd_irq interrupt, hpd isr state: 0x%x\n", isr); + + rc = queue_work(lphw_hpd->connect_wq, &lphw_hpd->attention); + if (!rc) + DP_DEBUG("attention not queued\n"); + } +} + +static int dp_lphw_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd) +{ + struct dp_lphw_hpd_private *lphw_hpd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + lphw_hpd->base.hpd_high = hpd; + lphw_hpd->base.alt_mode_cfg_done = hpd; + lphw_hpd->base.hpd_irq = false; + + if (!lphw_hpd->cb || !lphw_hpd->cb->configure || + !lphw_hpd->cb->disconnect) { + DP_ERR("invalid callback\n"); + return -EINVAL; + } + + if (hpd) + lphw_hpd->cb->configure(lphw_hpd->dev); + else + lphw_hpd->cb->disconnect(lphw_hpd->dev); + + return 0; +} + +static int dp_lphw_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo) +{ + struct dp_lphw_hpd_private *lphw_hpd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + lphw_hpd->base.hpd_irq = true; + + if (lphw_hpd->cb && lphw_hpd->cb->attention) + lphw_hpd->cb->attention(lphw_hpd->dev); + + return 0; +} + +int dp_lphw_hpd_register(struct dp_hpd *dp_hpd) +{ + struct dp_lphw_hpd_private *lphw_hpd; + int rc = 0; + + if (!dp_hpd) + return -EINVAL; + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + lphw_hpd->hpd = gpio_get_value_cansleep(lphw_hpd->gpio_cfg.gpio); + + rc = devm_request_threaded_irq(lphw_hpd->dev, lphw_hpd->irq, NULL, + dp_tlmm_isr, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "dp-gpio-intp", lphw_hpd); + if (rc) { + DP_ERR("Failed to request INTP threaded IRQ: %d\n", rc); + return rc; + } + enable_irq_wake(lphw_hpd->irq); + + if (lphw_hpd->hpd) + queue_work(lphw_hpd->connect_wq, &lphw_hpd->connect); + + return rc; +} + +static void dp_lphw_hpd_deinit(struct dp_lphw_hpd_private *lphw_hpd) +{ + struct dp_parser *parser = lphw_hpd->parser; + int i = 0; + + for (i = 0; i < parser->mp[DP_PHY_PM].num_vreg; i++) { + + if (!strcmp(parser->mp[DP_PHY_PM].vreg_config[i].vreg_name, + "hpd-pwr")) { + /* disable the hpd-pwr voltage regulator */ + if (msm_dss_enable_vreg( + &parser->mp[DP_PHY_PM].vreg_config[i], 1, + false)) + DP_ERR("hpd-pwr vreg not disabled\n"); + + break; + } + } +} + +static void dp_lphw_hpd_init(struct dp_lphw_hpd_private *lphw_hpd) +{ + struct dp_pinctrl pinctrl = {0}; + struct dp_parser *parser = lphw_hpd->parser; + int i = 0, rc = 0; + + for (i = 0; i < parser->mp[DP_PHY_PM].num_vreg; i++) { + + if (!strcmp(parser->mp[DP_PHY_PM].vreg_config[i].vreg_name, + "hpd-pwr")) { + /* enable the hpd-pwr voltage regulator */ + if (msm_dss_enable_vreg( + &parser->mp[DP_PHY_PM].vreg_config[i], 1, + true)) + DP_ERR("hpd-pwr vreg not enabled\n"); + + break; + } + } + + pinctrl.pin = devm_pinctrl_get(lphw_hpd->dev); + + if (!IS_ERR_OR_NULL(pinctrl.pin)) { + pinctrl.state_hpd_active = pinctrl_lookup_state(pinctrl.pin, + "mdss_dp_hpd_active"); + + if (!IS_ERR_OR_NULL(pinctrl.state_hpd_active)) { + rc = pinctrl_select_state(pinctrl.pin, + pinctrl.state_hpd_active); + if (rc) + DP_ERR("failed to set hpd_active state\n"); + } + } +} + +static int dp_lphw_hpd_create_workqueue(struct dp_lphw_hpd_private *lphw_hpd) +{ + lphw_hpd->connect_wq = create_singlethread_workqueue("dp_lphw_work"); + if (IS_ERR_OR_NULL(lphw_hpd->connect_wq)) { + DP_ERR("Error creating connect_wq\n"); + return -EPERM; + } + + INIT_WORK(&lphw_hpd->connect, dp_lphw_hpd_connect); + INIT_WORK(&lphw_hpd->disconnect, dp_lphw_hpd_disconnect); + INIT_WORK(&lphw_hpd->attention, dp_lphw_hpd_attention); + + return 0; +} + +struct dp_hpd *dp_lphw_hpd_get(struct device *dev, struct dp_parser *parser, + struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb) +{ + int rc = 0; + const char *hpd_gpio_name = "qcom,dp-hpd-gpio"; + struct dp_lphw_hpd_private *lphw_hpd; + + if (!dev || !parser || !cb) { + DP_ERR("invalid device\n"); + rc = -EINVAL; + goto error; + } + + lphw_hpd = devm_kzalloc(dev, sizeof(*lphw_hpd), GFP_KERNEL); + if (!lphw_hpd) { + rc = -ENOMEM; + goto error; + } + + lphw_hpd->gpio_cfg.gpio = of_get_named_gpio(dev->of_node, + hpd_gpio_name, 0); + if (!gpio_is_valid(lphw_hpd->gpio_cfg.gpio)) { + DP_ERR("%s gpio not specified\n", hpd_gpio_name); + rc = -EINVAL; + goto gpio_error; + } + + strlcpy(lphw_hpd->gpio_cfg.gpio_name, hpd_gpio_name, + sizeof(lphw_hpd->gpio_cfg.gpio_name)); + lphw_hpd->gpio_cfg.value = 0; + + rc = gpio_request(lphw_hpd->gpio_cfg.gpio, + lphw_hpd->gpio_cfg.gpio_name); + if (rc) { + DP_ERR("%s: failed to request gpio\n", hpd_gpio_name); + goto gpio_error; + } + gpio_direction_input(lphw_hpd->gpio_cfg.gpio); + + lphw_hpd->dev = dev; + lphw_hpd->cb = cb; + lphw_hpd->irq = gpio_to_irq(lphw_hpd->gpio_cfg.gpio); + + rc = dp_lphw_hpd_create_workqueue(lphw_hpd); + if (rc) { + DP_ERR("Failed to create a dp_hpd workqueue\n"); + goto gpio_error; + } + + lphw_hpd->parser = parser; + lphw_hpd->catalog = catalog; + lphw_hpd->base.isr = dp_lphw_hpd_isr; + lphw_hpd->base.host_init = dp_lphw_hpd_host_init; + lphw_hpd->base.host_deinit = dp_lphw_hpd_host_deinit; + lphw_hpd->base.simulate_connect = dp_lphw_hpd_simulate_connect; + lphw_hpd->base.simulate_attention = dp_lphw_hpd_simulate_attention; + lphw_hpd->base.register_hpd = dp_lphw_hpd_register; + + dp_lphw_hpd_init(lphw_hpd); + + return &lphw_hpd->base; + +gpio_error: + devm_kfree(dev, lphw_hpd); +error: + return ERR_PTR(rc); +} + +void dp_lphw_hpd_put(struct dp_hpd *dp_hpd) +{ + struct dp_lphw_hpd_private *lphw_hpd; + + if (!dp_hpd) + return; + + lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base); + + dp_lphw_hpd_deinit(lphw_hpd); + gpio_free(lphw_hpd->gpio_cfg.gpio); + devm_kfree(lphw_hpd->dev, lphw_hpd); +} diff --git a/techpack/display/msm/dp/dp_lphw_hpd.h b/techpack/display/msm/dp/dp_lphw_hpd.h new file mode 100644 index 0000000000000000000000000000000000000000..9779331bd295eefed4546746974369f7a167760e --- /dev/null +++ b/techpack/display/msm/dp/dp_lphw_hpd.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_LPHW_HPD_H_ +#define _DP_LPHW_HPD_H_ + +#include "dp_hpd.h" + +#define DP_HPD_PLUG_INT_STATUS BIT(0) +#define DP_IRQ_HPD_INT_STATUS BIT(1) +#define DP_HPD_REPLUG_INT_STATUS BIT(2) +#define DP_HPD_UNPLUG_INT_STATUS BIT(3) + +/** + * dp_lphw_hpd_get() - configure and get the DisplayPlot HPD module data + * + * @dev: device instance of the caller + * return: pointer to allocated gpio hpd module data + * + * This function sets up the lphw hpd module + */ +struct dp_hpd *dp_lphw_hpd_get(struct device *dev, struct dp_parser *parser, + struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb); + +/** + * dp_lphw_hpd_put() + * + * Cleans up dp_hpd instance + * + * @hpd: instance of lphw_hpd + */ +void dp_lphw_hpd_put(struct dp_hpd *hpd); + +#endif /* _DP_LPHW_HPD_H_ */ diff --git a/techpack/display/msm/dp/dp_mst_drm.c b/techpack/display/msm/dp/dp_mst_drm.c new file mode 100644 index 0000000000000000000000000000000000000000..508e1034feb46ffc045d5e11856f1a32d025c358 --- /dev/null +++ b/techpack/display/msm/dp/dp_mst_drm.c @@ -0,0 +1,2258 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +/* + * Copyright © 2014 Red Hat. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic.h> +#include <drm/drm_crtc.h> +#include <drm/drm_dp_mst_helper.h> +#include <drm/drm_fixed.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "sde_connector.h" +#include "dp_drm.h" +#include "dp_debug.h" + +#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) +#define DP_MST_INFO_LOG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__) + +#define MAX_DP_MST_DRM_ENCODERS 2 +#define MAX_DP_MST_DRM_BRIDGES 2 +#define HPD_STRING_SIZE 30 + +struct dp_drm_mst_fw_helper_ops { + int (*calc_pbn_mode)(struct dp_display_mode *dp_mode); + int (*find_vcpi_slots)(struct drm_dp_mst_topology_mgr *mgr, int pbn); + int (*atomic_find_vcpi_slots)(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn); + bool (*allocate_vcpi)(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + int pbn, int slots); + int (*update_payload_part1)(struct drm_dp_mst_topology_mgr *mgr); + int (*check_act_status)(struct drm_dp_mst_topology_mgr *mgr); + int (*update_payload_part2)(struct drm_dp_mst_topology_mgr *mgr); + enum drm_connector_status (*detect_port)( + struct drm_connector *connector, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); + struct edid *(*get_edid)(struct drm_connector *connector, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); + int (*topology_mgr_set_mst)(struct drm_dp_mst_topology_mgr *mgr, + bool mst_state); + int (*atomic_release_vcpi_slots)(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + int slots); + void (*get_vcpi_info)(struct drm_dp_mst_topology_mgr *mgr, + int vcpi, int *start_slot, int *num_slots); + void (*reset_vcpi_slots)(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); + void (*deallocate_vcpi)(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); +}; + +struct dp_mst_sim_port_data { + bool input_port; + u8 peer_device_type; + u8 port_number; + bool mcs; + bool ddps; + bool legacy_device_plug_status; + u8 dpcd_revision; + u8 peer_guid[16]; + u8 num_sdp_streams; + u8 num_sdp_stream_sinks; +}; + +struct dp_mst_sim_port_edid { + u8 port_number; + u8 edid[SZ_256]; + bool valid; +}; + +struct dp_mst_sim_mode { + bool mst_state; + struct edid *edid; + struct dp_mst_sim_port_edid port_edids[DP_MST_SIM_MAX_PORTS]; + struct work_struct probe_work; + const struct drm_dp_mst_topology_cbs *cbs; + u32 port_cnt; +}; + +struct dp_mst_bridge { + struct drm_bridge base; + struct drm_private_obj obj; + u32 id; + + bool in_use; + + struct dp_display *display; + struct drm_encoder *encoder; + + struct drm_display_mode drm_mode; + struct dp_display_mode dp_mode; + struct drm_connector *connector; + void *dp_panel; + + int vcpi; + int pbn; + int num_slots; + int start_slot; + + u32 fixed_port_num; + bool fixed_port_added; + struct drm_connector *fixed_connector; +}; + +struct dp_mst_bridge_state { + struct drm_private_state base; + struct drm_connector *connector; + void *dp_panel; + int num_slots; +}; + +struct dp_mst_private { + bool mst_initialized; + struct dp_mst_caps caps; + struct drm_dp_mst_topology_mgr mst_mgr; + struct dp_mst_bridge mst_bridge[MAX_DP_MST_DRM_BRIDGES]; + struct dp_display *dp_display; + const struct dp_drm_mst_fw_helper_ops *mst_fw_cbs; + struct dp_mst_sim_mode simulator; + struct mutex mst_lock; + enum dp_drv_state state; + bool mst_session_state; +}; + +struct dp_mst_encoder_info_cache { + u8 cnt; + struct drm_encoder *mst_enc[MAX_DP_MST_DRM_BRIDGES]; +}; + +#define to_dp_mst_bridge(x) container_of((x), struct dp_mst_bridge, base) +#define to_dp_mst_bridge_priv(x) \ + container_of((x), struct dp_mst_bridge, obj) +#define to_dp_mst_bridge_priv_state(x) \ + container_of((x), struct dp_mst_bridge_state, base) +#define to_dp_mst_bridge_state(x) \ + to_dp_mst_bridge_priv_state((x)->obj.state) + +struct dp_mst_private dp_mst; +struct dp_mst_encoder_info_cache dp_mst_enc_cache; + +static struct drm_private_state *dp_mst_duplicate_bridge_state( + struct drm_private_obj *obj) +{ + struct dp_mst_bridge_state *state; + + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + + return &state->base; +} + +static void dp_mst_destroy_bridge_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + struct dp_mst_bridge_state *priv_state = + to_dp_mst_bridge_priv_state(state); + + kfree(priv_state); +} + +static const struct drm_private_state_funcs dp_mst_bridge_state_funcs = { + .atomic_duplicate_state = dp_mst_duplicate_bridge_state, + .atomic_destroy_state = dp_mst_destroy_bridge_state, +}; + +static struct dp_mst_bridge_state *dp_mst_get_bridge_atomic_state( + struct drm_atomic_state *state, struct dp_mst_bridge *bridge) +{ + struct drm_device *dev = bridge->base.dev; + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + + return to_dp_mst_bridge_priv_state( + drm_atomic_get_private_obj_state(state, &bridge->obj)); +} + +static void dp_mst_sim_destroy_port(struct kref *ref) +{ + struct drm_dp_mst_port *port = container_of(ref, + struct drm_dp_mst_port, kref); + struct drm_dp_mst_topology_mgr *mgr = port->mgr; + + if (port->cached_edid) + kfree(port->cached_edid); + + if (port->connector) { + mutex_lock(&mgr->destroy_connector_lock); + kref_get(&port->parent->kref); + list_add(&port->next, &mgr->destroy_connector_list); + mutex_unlock(&mgr->destroy_connector_lock); + schedule_work(&mgr->destroy_connector_work); + return; + } else { + kfree(port); + } +} + +/* DRM DP MST Framework simulator OPs */ +static void dp_mst_sim_add_port(struct dp_mst_private *mst, + struct dp_mst_sim_port_data *port_msg) +{ + struct drm_dp_mst_branch *mstb; + struct drm_dp_mst_port *port; + + mstb = mst->mst_mgr.mst_primary; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return; + kref_init(&port->kref); + port->parent = mstb; + port->port_num = port_msg->port_number; + port->mgr = mstb->mgr; + port->aux.name = dp_mst.caps.drm_aux->name; + port->aux.dev = mst->dp_display->drm_dev->dev; + + port->pdt = port_msg->peer_device_type; + port->input = port_msg->input_port; + port->mcs = port_msg->mcs; + port->ddps = port_msg->ddps; + port->ldps = port_msg->legacy_device_plug_status; + port->dpcd_rev = port_msg->dpcd_revision; + port->num_sdp_streams = port_msg->num_sdp_streams; + port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks; + + mutex_lock(&mstb->mgr->lock); + kref_get(&port->kref); + list_add(&port->next, &mstb->ports); + mutex_unlock(&mstb->mgr->lock); + + /* use fixed pbn for simulator ports */ + port->available_pbn = 2520; + + if (!port->input) { + port->connector = (*mstb->mgr->cbs->add_connector) + (mstb->mgr, port, NULL); + if (!port->connector) { + /* remove it from the port list */ + mutex_lock(&mstb->mgr->lock); + list_del(&port->next); + mutex_unlock(&mstb->mgr->lock); + kref_put(&port->kref, dp_mst_sim_destroy_port); + goto put_port; + } + (*mstb->mgr->cbs->register_connector)(port->connector); + } + +put_port: + kref_put(&port->kref, dp_mst_sim_destroy_port); +} + +static void dp_mst_sim_link_probe_work(struct work_struct *work) +{ + struct dp_mst_sim_mode *sim; + struct dp_mst_private *mst; + struct dp_mst_sim_port_data port_data; + u8 cnt, i; + + DP_MST_DEBUG("enter\n"); + sim = container_of(work, struct dp_mst_sim_mode, probe_work); + mst = container_of(sim, struct dp_mst_private, simulator); + + port_data.input_port = false; + port_data.peer_device_type = DP_PEER_DEVICE_SST_SINK; + port_data.mcs = false; + port_data.ddps = true; + port_data.legacy_device_plug_status = false; + port_data.dpcd_revision = 0; + port_data.num_sdp_streams = 0; + port_data.num_sdp_stream_sinks = 0; + + for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) + sim->port_edids[i].valid = false; + + for (cnt = 0; cnt < sim->port_cnt; cnt++) { + port_data.port_number = cnt; + + for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { + if (sim->port_edids[i].valid) continue; + + sim->port_edids[i].port_number = port_data.port_number; + memcpy(sim->port_edids[i].edid, sim->edid, SZ_256); + sim->port_edids[i].valid = true; + break; + } + + dp_mst_sim_add_port(mst, &port_data); + } + + mst->mst_mgr.cbs->hotplug(&mst->mst_mgr); + DP_MST_DEBUG("completed\n"); +} + +static int dp_mst_sim_no_action(struct drm_dp_mst_topology_mgr *mgr) +{ + return 0; +} + +static int dp_mst_sim_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) +{ + int i, j; + int cur_slots = 1; + struct drm_dp_payload req_payload; + struct drm_dp_mst_port *port; + + mutex_lock(&mgr->payload_lock); + for (i = 0; i < mgr->max_payloads; i++) { + req_payload.start_slot = cur_slots; + if (mgr->proposed_vcpis[i]) { + port = container_of(mgr->proposed_vcpis[i], + struct drm_dp_mst_port, vcpi); + req_payload.num_slots = + mgr->proposed_vcpis[i]->num_slots; + req_payload.vcpi = mgr->proposed_vcpis[i]->vcpi; + } else { + port = NULL; + req_payload.num_slots = 0; + } + + if (mgr->payloads[i].start_slot != req_payload.start_slot) + mgr->payloads[i].start_slot = req_payload.start_slot; + + if (mgr->payloads[i].num_slots != req_payload.num_slots) { + if (req_payload.num_slots) { + req_payload.payload_state = DP_PAYLOAD_LOCAL; + mgr->payloads[i].num_slots = + req_payload.num_slots; + mgr->payloads[i].vcpi = req_payload.vcpi; + } else if (mgr->payloads[i].num_slots) { + mgr->payloads[i].num_slots = 0; + mgr->payloads[i].payload_state = + DP_PAYLOAD_DELETE_LOCAL; + req_payload.payload_state = + mgr->payloads[i].payload_state; + mgr->payloads[i].start_slot = 0; + } else + req_payload.payload_state = + mgr->payloads[i].payload_state; + + mgr->payloads[i].payload_state = + req_payload.payload_state; + } + cur_slots += req_payload.num_slots; + } + + for (i = 0; i < mgr->max_payloads; i++) { + if (mgr->payloads[i].payload_state == DP_PAYLOAD_DELETE_LOCAL) { + DP_DEBUG("removing payload %d\n", i); + for (j = i; j < mgr->max_payloads - 1; j++) { + memcpy(&mgr->payloads[j], + &mgr->payloads[j + 1], + sizeof(struct drm_dp_payload)); + mgr->proposed_vcpis[j] = + mgr->proposed_vcpis[j + 1]; + if (mgr->proposed_vcpis[j] && + mgr->proposed_vcpis[j]->num_slots) { + set_bit(j + 1, &mgr->payload_mask); + } else { + clear_bit(j + 1, &mgr->payload_mask); + } + } + memset(&mgr->payloads[mgr->max_payloads - 1], 0, + sizeof(struct drm_dp_payload)); + mgr->proposed_vcpis[mgr->max_payloads - 1] = NULL; + clear_bit(mgr->max_payloads, &mgr->payload_mask); + } + } + mutex_unlock(&mgr->payload_lock); + return 0; +} + +static int dp_mst_sim_update_payload_part2(struct drm_dp_mst_topology_mgr *mgr) +{ + struct drm_dp_mst_port *port; + int i; + + mutex_lock(&mgr->payload_lock); + for (i = 0; i < mgr->max_payloads; i++) { + + if (!mgr->proposed_vcpis[i]) + continue; + + port = container_of(mgr->proposed_vcpis[i], + struct drm_dp_mst_port, vcpi); + + DP_DEBUG("payload %d %d\n", i, mgr->payloads[i].payload_state); + if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) + mgr->payloads[i].payload_state = DP_PAYLOAD_REMOTE; + else if (mgr->payloads[i].payload_state == + DP_PAYLOAD_DELETE_LOCAL) + mgr->payloads[i].payload_state = 0; + } + mutex_unlock(&mgr->payload_lock); + return 0; +} + +static struct edid *dp_mst_sim_get_edid(struct drm_connector *connector, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port) +{ + struct dp_mst_private *mst = container_of(mgr, + struct dp_mst_private, mst_mgr); + int i; + + for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { + if (mst->simulator.port_edids[i].valid && + mst->simulator.port_edids[i].port_number == + port->port_num) { + return drm_edid_duplicate((struct edid *) + (mst->simulator.port_edids[i].edid)); + } + } + + DRM_ERROR("edid not found for connector %d\n", connector->base.id); + return NULL; +} + +static int dp_mst_sim_topology_mgr_set_mst( + struct drm_dp_mst_topology_mgr *mgr, + bool mst_state) +{ + int rc; + struct dp_mst_private *mst = container_of(mgr, + struct dp_mst_private, mst_mgr); + + rc = drm_dp_mst_topology_mgr_set_mst(mgr, mst_state); + if (rc < 0) { + DRM_ERROR("unable to set mst topology mgr, rc: %d\n", rc); + return rc; + } + + if (mst_state) + queue_work(system_long_wq, &mst->simulator.probe_work); + + mst->simulator.mst_state = mst_state; + return 0; +} + +static void dp_mst_sim_handle_hpd_irq(void *dp_display, + struct dp_mst_hpd_info *info) +{ + struct dp_display *dp; + struct dp_mst_private *mst; + struct drm_dp_mst_port *port; + struct dp_mst_sim_port_data port_data; + struct drm_dp_mst_branch *mstb; + int i; + bool in_list, port_available; + + dp = dp_display; + mst = dp->dp_mst_prv_info; + + if (info->mst_sim_add_con) { + port_available = false; + for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { + if (mst->simulator.port_edids[i].valid) continue; + + port_data.port_number = i; + mst->simulator.port_edids[i].port_number = i; + memcpy(mst->simulator.port_edids[i].edid, info->edid, + SZ_256); + mst->simulator.port_edids[i].valid = true; + port_available = true; + break; + } + + if (!port_available) { + DRM_ERROR("add port failed, limit (%d) reached\n", + DP_MST_SIM_MAX_PORTS); + return; + } + + port_data.input_port = false; + port_data.peer_device_type = DP_PEER_DEVICE_SST_SINK; + port_data.mcs = false; + port_data.ddps = true; + port_data.legacy_device_plug_status = false; + port_data.dpcd_revision = 0; + port_data.num_sdp_streams = 0; + port_data.num_sdp_stream_sinks = 0; + + dp_mst_sim_add_port(mst, &port_data); + } else if (info->mst_sim_remove_con) { + mstb = mst->mst_mgr.mst_primary; + in_list = false; + + mutex_lock(&mst->mst_mgr.lock); + list_for_each_entry(port, + &mstb->ports, next) { + if (port->connector && port->connector->base.id == + info->mst_sim_remove_con_id) { + in_list = true; + list_del(&port->next); + break; + } + } + mutex_unlock(&mst->mst_mgr.lock); + + if (!in_list) { + DRM_ERROR("invalid connector id %d\n", + info->mst_sim_remove_con_id); + return; + } + + for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) { + if (mst->simulator.port_edids[i].port_number == + port->port_num) { + mst->simulator.port_edids[i].valid = false; + } + } + + kref_put(&port->kref, dp_mst_sim_destroy_port); + } +} + +static void _dp_mst_get_vcpi_info( + struct drm_dp_mst_topology_mgr *mgr, + int vcpi, int *start_slot, int *num_slots) +{ + int i; + + *start_slot = 0; + *num_slots = 0; + + mutex_lock(&mgr->payload_lock); + for (i = 0; i < mgr->max_payloads; i++) { + if (mgr->payloads[i].vcpi == vcpi) { + *start_slot = mgr->payloads[i].start_slot; + *num_slots = mgr->payloads[i].num_slots; + break; + } + } + mutex_unlock(&mgr->payload_lock); + + DP_INFO("vcpi_info. vcpi:%d, start_slot:%d, num_slots:%d\n", + vcpi, *start_slot, *num_slots); +} + +static int dp_mst_calc_pbn_mode(struct dp_display_mode *dp_mode) +{ + int pbn, bpp; + bool dsc_en; + s64 pbn_fp; + + dsc_en = dp_mode->timing.comp_info.comp_ratio ? true : false; + bpp = dsc_en ? dp_mode->timing.comp_info.dsc_info.bpp : + dp_mode->timing.bpp; + + pbn = drm_dp_calc_pbn_mode(dp_mode->timing.pixel_clk_khz, bpp); + pbn_fp = drm_fixp_from_fraction(pbn, 1); + + DP_DEBUG("before overhead pbn:%d, bpp:%d\n", pbn, bpp); + + if (dsc_en) + pbn_fp = drm_fixp_mul(pbn_fp, dp_mode->dsc_overhead_fp); + + if (dp_mode->fec_overhead_fp) + pbn_fp = drm_fixp_mul(pbn_fp, dp_mode->fec_overhead_fp); + + pbn = drm_fixp2int(pbn_fp); + + DP_DEBUG("after overhead pbn:%d, bpp:%d\n", pbn, bpp); + return pbn; +} + +static const struct dp_drm_mst_fw_helper_ops drm_dp_mst_fw_helper_ops = { + .calc_pbn_mode = dp_mst_calc_pbn_mode, + .find_vcpi_slots = drm_dp_find_vcpi_slots, + .atomic_find_vcpi_slots = drm_dp_atomic_find_vcpi_slots, + .allocate_vcpi = drm_dp_mst_allocate_vcpi, + .update_payload_part1 = drm_dp_update_payload_part1, + .check_act_status = drm_dp_check_act_status, + .update_payload_part2 = drm_dp_update_payload_part2, + .detect_port = drm_dp_mst_detect_port, + .get_edid = drm_dp_mst_get_edid, + .topology_mgr_set_mst = drm_dp_mst_topology_mgr_set_mst, + .get_vcpi_info = _dp_mst_get_vcpi_info, + .atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots, + .reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots, + .deallocate_vcpi = drm_dp_mst_deallocate_vcpi, +}; + +static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = { + .calc_pbn_mode = dp_mst_calc_pbn_mode, + .find_vcpi_slots = drm_dp_find_vcpi_slots, + .atomic_find_vcpi_slots = drm_dp_atomic_find_vcpi_slots, + .allocate_vcpi = drm_dp_mst_allocate_vcpi, + .update_payload_part1 = dp_mst_sim_update_payload_part1, + .check_act_status = dp_mst_sim_no_action, + .update_payload_part2 = dp_mst_sim_update_payload_part2, + .detect_port = drm_dp_mst_detect_port, + .get_edid = dp_mst_sim_get_edid, + .topology_mgr_set_mst = dp_mst_sim_topology_mgr_set_mst, + .get_vcpi_info = _dp_mst_get_vcpi_info, + .atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots, + .reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots, + .deallocate_vcpi = drm_dp_mst_deallocate_vcpi, +}; + +/* DP MST Bridge OPs */ + +static int dp_mst_bridge_attach(struct drm_bridge *dp_bridge) +{ + struct dp_mst_bridge *bridge; + + DP_MST_DEBUG("enter\n"); + + if (!dp_bridge) { + DP_ERR("Invalid params\n"); + return -EINVAL; + } + + bridge = to_dp_mst_bridge(dp_bridge); + + DP_MST_DEBUG("mst bridge [%d] attached\n", bridge->id); + + return 0; +} + +static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + bool ret = true; + struct dp_display_mode dp_mode; + struct dp_mst_bridge *bridge; + struct dp_display *dp; + struct drm_crtc_state *crtc_state; + struct dp_mst_bridge_state *bridge_state; + + DP_MST_DEBUG("enter\n"); + + if (!drm_bridge || !mode || !adjusted_mode) { + DP_ERR("Invalid params\n"); + ret = false; + goto end; + } + + bridge = to_dp_mst_bridge(drm_bridge); + + crtc_state = container_of(mode, struct drm_crtc_state, mode); + bridge_state = dp_mst_get_bridge_atomic_state(crtc_state->state, + bridge); + if (IS_ERR(bridge_state)) { + DP_ERR("invalid bridge state\n"); + ret = false; + goto end; + } + + if (!bridge_state->dp_panel) { + DP_ERR("Invalid dp_panel\n"); + ret = false; + goto end; + } + + dp = bridge->display; + + dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode); + convert_to_drm_mode(&dp_mode, adjusted_mode); + + DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); +end: + return ret; +} + +static int _dp_mst_compute_config(struct drm_atomic_state *state, + struct dp_mst_private *mst, struct drm_connector *connector, + struct dp_display_mode *mode) +{ + int slots = 0, pbn; + struct sde_connector *c_conn = to_sde_connector(connector); + + DP_MST_DEBUG("enter\n"); + + pbn = mst->mst_fw_cbs->calc_pbn_mode(mode); + + slots = mst->mst_fw_cbs->atomic_find_vcpi_slots(state, + &mst->mst_mgr, c_conn->mst_port, pbn); + if (slots < 0) { + DP_ERR("mst: failed to find vcpi slots. pbn:%d, slots:%d\n", + pbn, slots); + return slots; + } + + DP_MST_DEBUG("exit\n"); + + return slots; +} + +static void _dp_mst_update_timeslots(struct dp_mst_private *mst, + struct dp_mst_bridge *mst_bridge) +{ + int i; + struct dp_mst_bridge *dp_bridge; + int pbn, start_slot, num_slots; + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + dp_bridge = &mst->mst_bridge[i]; + + pbn = 0; + start_slot = 0; + num_slots = 0; + + if (dp_bridge->vcpi) { + mst->mst_fw_cbs->get_vcpi_info(&mst->mst_mgr, + dp_bridge->vcpi, + &start_slot, &num_slots); + pbn = dp_bridge->pbn; + } + + if (mst_bridge == dp_bridge) + dp_bridge->num_slots = num_slots; + + mst->dp_display->set_stream_info(mst->dp_display, + dp_bridge->dp_panel, + dp_bridge->id, start_slot, num_slots, pbn, + dp_bridge->vcpi); + + DP_INFO("bridge:%d vcpi:%d start_slot:%d num_slots:%d, pbn:%d\n", + dp_bridge->id, dp_bridge->vcpi, + start_slot, num_slots, pbn); + } +} + +static void _dp_mst_update_single_timeslot(struct dp_mst_private *mst, + struct dp_mst_bridge *mst_bridge) +{ + int pbn = 0, start_slot = 0, num_slots = 0; + + if (mst->state == PM_SUSPEND) { + if (mst_bridge->vcpi) { + mst->mst_fw_cbs->get_vcpi_info(&mst->mst_mgr, + mst_bridge->vcpi, + &start_slot, &num_slots); + pbn = mst_bridge->pbn; + } + + mst_bridge->num_slots = num_slots; + + mst->dp_display->set_stream_info(mst->dp_display, + mst_bridge->dp_panel, + mst_bridge->id, start_slot, num_slots, pbn, + mst_bridge->vcpi); + } +} + +static void _dp_mst_bridge_pre_enable_part1(struct dp_mst_bridge *dp_bridge) +{ + struct dp_display *dp_display = dp_bridge->display; + struct sde_connector *c_conn = + to_sde_connector(dp_bridge->connector); + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct drm_dp_mst_port *port = c_conn->mst_port; + bool ret; + int pbn, slots; + + /* skip mst specific disable operations during suspend */ + if (mst->state == PM_SUSPEND) { + dp_display->wakeup_phy_layer(dp_display, true); + drm_dp_send_power_updown_phy(&mst->mst_mgr, port, true); + dp_display->wakeup_phy_layer(dp_display, false); + _dp_mst_update_single_timeslot(mst, dp_bridge); + return; + } + + pbn = mst->mst_fw_cbs->calc_pbn_mode(&dp_bridge->dp_mode); + + slots = mst->mst_fw_cbs->find_vcpi_slots(&mst->mst_mgr, pbn); + + DP_INFO("bridge:%d, pbn:%d, slots:%d\n", dp_bridge->id, + dp_bridge->pbn, dp_bridge->num_slots); + + ret = mst->mst_fw_cbs->allocate_vcpi(&mst->mst_mgr, + port, pbn, slots); + if (!ret) { + DP_ERR("mst: failed to allocate vcpi. bridge:%d\n", + dp_bridge->id); + return; + } + + dp_bridge->vcpi = port->vcpi.vcpi; + dp_bridge->pbn = pbn; + + ret = mst->mst_fw_cbs->update_payload_part1(&mst->mst_mgr); + + _dp_mst_update_timeslots(mst, dp_bridge); +} + +static void _dp_mst_bridge_pre_enable_part2(struct dp_mst_bridge *dp_bridge) +{ + struct dp_display *dp_display = dp_bridge->display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + + DP_MST_DEBUG("enter\n"); + + /* skip mst specific disable operations during suspend */ + if (mst->state == PM_SUSPEND) + return; + + mst->mst_fw_cbs->check_act_status(&mst->mst_mgr); + + mst->mst_fw_cbs->update_payload_part2(&mst->mst_mgr); + + DP_MST_DEBUG("mst bridge [%d] _pre enable part-2 complete\n", + dp_bridge->id); +} + +static void _dp_mst_bridge_pre_disable_part1(struct dp_mst_bridge *dp_bridge) +{ + struct dp_display *dp_display = dp_bridge->display; + struct sde_connector *c_conn = + to_sde_connector(dp_bridge->connector); + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct drm_dp_mst_port *port = c_conn->mst_port; + + DP_MST_DEBUG("enter\n"); + + /* skip mst specific disable operations during suspend */ + if (mst->state == PM_SUSPEND) { + _dp_mst_update_single_timeslot(mst, dp_bridge); + return; + } + + mst->mst_fw_cbs->reset_vcpi_slots(&mst->mst_mgr, port); + + mst->mst_fw_cbs->update_payload_part1(&mst->mst_mgr); + + _dp_mst_update_timeslots(mst, dp_bridge); + + DP_MST_DEBUG("mst bridge [%d] _pre disable part-1 complete\n", + dp_bridge->id); +} + +static void _dp_mst_bridge_pre_disable_part2(struct dp_mst_bridge *dp_bridge) +{ + struct dp_display *dp_display = dp_bridge->display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct sde_connector *c_conn = + to_sde_connector(dp_bridge->connector); + struct drm_dp_mst_port *port = c_conn->mst_port; + + DP_MST_DEBUG("enter\n"); + + /* skip mst specific disable operations during suspend */ + if (mst->state == PM_SUSPEND) { + dp_display->wakeup_phy_layer(dp_display, true); + drm_dp_send_power_updown_phy(&mst->mst_mgr, port, false); + dp_display->wakeup_phy_layer(dp_display, false); + return; + } + + mst->mst_fw_cbs->check_act_status(&mst->mst_mgr); + + mst->mst_fw_cbs->update_payload_part2(&mst->mst_mgr); + + mst->mst_fw_cbs->deallocate_vcpi(&mst->mst_mgr, port); + + dp_bridge->vcpi = 0; + dp_bridge->pbn = 0; + + DP_MST_DEBUG("mst bridge [%d] _pre disable part-2 complete\n", + dp_bridge->id); +} + +static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_mst_bridge *bridge; + struct dp_display *dp; + struct dp_mst_private *mst; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + dp = bridge->display; + + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + mst = dp->dp_mst_prv_info; + + mutex_lock(&mst->mst_lock); + + /* By this point mode should have been validated through mode_fixup */ + rc = dp->set_mode(dp, bridge->dp_panel, &bridge->dp_mode); + if (rc) { + DP_ERR("[%d] failed to perform a mode set, rc=%d\n", + bridge->id, rc); + goto end; + } + + rc = dp->prepare(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display prepare failed, rc=%d\n", + bridge->id, rc); + goto end; + } + + _dp_mst_bridge_pre_enable_part1(bridge); + + rc = dp->enable(dp, bridge->dp_panel); + if (rc) { + DP_ERR("[%d] DP display enable failed, rc=%d\n", + bridge->id, rc); + dp->unprepare(dp, bridge->dp_panel); + goto end; + } else { + _dp_mst_bridge_pre_enable_part2(bridge); + } + + DP_MST_INFO_LOG("mode: id(%d) mode(%s), refresh(%d)\n", + bridge->id, bridge->drm_mode.name, + bridge->drm_mode.vrefresh); + DP_MST_INFO_LOG("dsc: id(%d) dsc(%d)\n", bridge->id, + bridge->dp_mode.timing.comp_info.comp_ratio); + DP_MST_INFO_LOG("channel: id(%d) vcpi(%d) start(%d) tot(%d)\n", + bridge->id, bridge->vcpi, bridge->start_slot, + bridge->num_slots); +end: + mutex_unlock(&mst->mst_lock); +} + +static void dp_mst_bridge_enable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_mst_bridge *bridge; + struct dp_display *dp; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + dp = bridge->display; + + rc = dp->post_enable(dp, bridge->dp_panel); + if (rc) { + DP_ERR("mst bridge [%d] post enable failed, rc=%d\n", + bridge->id, rc); + return; + } + + DP_MST_INFO_LOG("mst bridge [%d] post enable complete\n", + bridge->id); +} + +static void dp_mst_bridge_disable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_mst_bridge *bridge; + struct dp_display *dp; + struct dp_mst_private *mst; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + dp = bridge->display; + + mst = dp->dp_mst_prv_info; + + sde_connector_helper_bridge_disable(bridge->connector); + + mutex_lock(&mst->mst_lock); + + _dp_mst_bridge_pre_disable_part1(bridge); + + rc = dp->pre_disable(dp, bridge->dp_panel); + if (rc) + DP_ERR("[%d] DP display pre disable failed, rc=%d\n", + bridge->id, rc); + + _dp_mst_bridge_pre_disable_part2(bridge); + + DP_MST_INFO_LOG("mst bridge [%d] disable complete\n", bridge->id); + + mutex_unlock(&mst->mst_lock); +} + +static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge) +{ + int rc = 0; + struct dp_mst_bridge *bridge; + struct dp_display *dp; + struct dp_mst_private *mst; + + if (!drm_bridge) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + if (!bridge->connector) { + DP_ERR("Invalid connector\n"); + return; + } + + dp = bridge->display; + mst = dp->dp_mst_prv_info; + + rc = dp->disable(dp, bridge->dp_panel); + if (rc) + DP_INFO("[%d] DP display disable failed, rc=%d\n", + bridge->id, rc); + + rc = dp->unprepare(dp, bridge->dp_panel); + if (rc) + DP_INFO("[%d] DP display unprepare failed, rc=%d\n", + bridge->id, rc); + + bridge->connector = NULL; + bridge->dp_panel = NULL; + + DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n", + bridge->id); +} + +static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dp_mst_bridge *bridge; + struct dp_mst_bridge_state *dp_bridge_state; + struct dp_display *dp; + + DP_MST_DEBUG("enter\n"); + + if (!drm_bridge || !mode || !adjusted_mode) { + DP_ERR("Invalid params\n"); + return; + } + + bridge = to_dp_mst_bridge(drm_bridge); + + dp_bridge_state = to_dp_mst_bridge_state(bridge); + bridge->connector = dp_bridge_state->connector; + bridge->dp_panel = dp_bridge_state->dp_panel; + + dp = bridge->display; + + memset(&bridge->dp_mode, 0x0, sizeof(struct dp_display_mode)); + memcpy(&bridge->drm_mode, adjusted_mode, sizeof(bridge->drm_mode)); + dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode, + &bridge->dp_mode); + + DP_MST_DEBUG("mst bridge [%d] mode set complete\n", bridge->id); +} + +/* DP MST Bridge APIs */ + +static struct drm_connector * +dp_mst_drm_fixed_connector_init(struct dp_display *dp_display, + struct drm_encoder *encoder); + +static const struct drm_bridge_funcs dp_mst_bridge_ops = { + .attach = dp_mst_bridge_attach, + .mode_fixup = dp_mst_bridge_mode_fixup, + .pre_enable = dp_mst_bridge_pre_enable, + .enable = dp_mst_bridge_enable, + .disable = dp_mst_bridge_disable, + .post_disable = dp_mst_bridge_post_disable, + .mode_set = dp_mst_bridge_mode_set, +}; + +int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) +{ + int rc = 0; + struct dp_mst_bridge *bridge = NULL; + struct dp_mst_bridge_state *state; + struct drm_device *dev; + struct dp_display *display = data; + struct msm_drm_private *priv = NULL; + struct dp_mst_private *mst = display->dp_mst_prv_info; + int i; + + if (!mst || !mst->mst_initialized) { + if (dp_mst_enc_cache.cnt >= MAX_DP_MST_DRM_BRIDGES) { + DP_INFO("exceeding max bridge cnt %d\n", + dp_mst_enc_cache.cnt); + return 0; + } + + dp_mst_enc_cache.mst_enc[dp_mst_enc_cache.cnt] = encoder; + dp_mst_enc_cache.cnt++; + DP_INFO("mst not initialized. cache encoder information\n"); + return 0; + } + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (!mst->mst_bridge[i].in_use) { + bridge = &mst->mst_bridge[i]; + bridge->encoder = encoder; + bridge->in_use = true; + bridge->id = i; + break; + } + } + + if (i == MAX_DP_MST_DRM_BRIDGES) { + DP_ERR("mst supports only %d bridges\n", i); + rc = -EACCES; + goto end; + } + + dev = display->drm_dev; + bridge->display = display; + bridge->base.funcs = &dp_mst_bridge_ops; + bridge->base.encoder = encoder; + + priv = dev->dev_private; + + rc = drm_bridge_attach(encoder, &bridge->base, NULL); + if (rc) { + DP_ERR("failed to attach bridge, rc=%d\n", rc); + goto end; + } + + encoder->bridge = &bridge->base; + priv->bridges[priv->num_bridges++] = &bridge->base; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) { + rc = -ENOMEM; + goto end; + } + + drm_atomic_private_obj_init(&bridge->obj, + &state->base, + &dp_mst_bridge_state_funcs); + + DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i); + + /* + * If fixed topology port is defined, connector will be created + * immediately. + */ + rc = display->mst_get_fixed_topology_port(display, bridge->id, + &bridge->fixed_port_num); + if (!rc) { + bridge->fixed_connector = + dp_mst_drm_fixed_connector_init(display, + bridge->encoder); + if (bridge->fixed_connector == NULL) { + DP_ERR("failed to create fixed connector\n"); + kfree(state); + rc = -ENOMEM; + goto end; + } + } + + return 0; + +end: + return rc; +} + +void dp_mst_drm_bridge_deinit(void *display) +{ + DP_MST_DEBUG("mst bridge deinit\n"); +} + +/* DP MST Connector OPs */ + +static enum drm_connector_status +dp_mst_connector_detect(struct drm_connector *connector, bool force, + void *display) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + struct dp_display *dp_display = c_conn->display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + enum drm_connector_status status; + struct dp_mst_connector mst_conn; + + DP_MST_DEBUG("enter:\n"); + + status = mst->mst_fw_cbs->detect_port(connector, + &mst->mst_mgr, + c_conn->mst_port); + + memset(&mst_conn, 0, sizeof(mst_conn)); + dp_display->mst_get_connector_info(dp_display, connector, &mst_conn); + if (mst_conn.conn == connector && + mst_conn.state != connector_status_unknown) { + status = mst_conn.state; + } + + DP_MST_DEBUG("mst connector:%d detect, status:%d\n", + connector->base.id, status); + + DP_MST_DEBUG("exit:\n"); + + return status; +} + +static int dp_mst_connector_get_modes(struct drm_connector *connector, + void *display, const struct msm_resource_caps_info *avail_res) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + struct dp_display *dp_display = display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct edid *edid; + int rc = 0; + + DP_MST_DEBUG("enter:\n"); + + edid = mst->mst_fw_cbs->get_edid(connector, &mst->mst_mgr, + c_conn->mst_port); + + if (edid) + rc = dp_display->mst_connector_update_edid(dp_display, + connector, edid); + + DP_MST_DEBUG("mst connector get modes. id: %d\n", connector->base.id); + + DP_MST_DEBUG("exit:\n"); + + return rc; +} + +enum drm_mode_status dp_mst_connector_mode_valid( + struct drm_connector *connector, + struct drm_display_mode *mode, + void *display, const struct msm_resource_caps_info *avail_res) +{ + struct dp_display *dp_display = display; + struct dp_mst_private *mst; + struct sde_connector *c_conn; + struct drm_dp_mst_port *mst_port; + struct dp_display_mode dp_mode; + uint16_t available_pbn, required_pbn; + int available_slots, required_slots; + struct dp_mst_bridge_state *dp_bridge_state; + int i, slots_in_use = 0, active_enc_cnt = 0; + const u32 tot_slots = 63; + + if (!connector || !mode || !display) { + DP_ERR("invalid input\n"); + return 0; + } + + mst = dp_display->dp_mst_prv_info; + c_conn = to_sde_connector(connector); + mst_port = c_conn->mst_port; + + /* dp bridge state is protected by drm_mode_config.connection_mutex */ + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + dp_bridge_state = to_dp_mst_bridge_state(&mst->mst_bridge[i]); + if (dp_bridge_state->connector && + dp_bridge_state->connector != connector) { + active_enc_cnt++; + slots_in_use += dp_bridge_state->num_slots; + } + } + + if (active_enc_cnt < DP_STREAM_MAX) { + available_pbn = mst_port->available_pbn; + available_slots = tot_slots - slots_in_use; + } else { + pr_debug("all mst streams are active\n"); + return MODE_BAD; + } + + dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, + mode, &dp_mode); + + required_pbn = mst->mst_fw_cbs->calc_pbn_mode(&dp_mode); + required_slots = mst->mst_fw_cbs->find_vcpi_slots( + &mst->mst_mgr, required_pbn); + + if (required_pbn > available_pbn || required_slots > available_slots) { + DP_DEBUG("mode:%s not supported\n", mode->name); + return MODE_BAD; + } + + return dp_connector_mode_valid(connector, mode, display, avail_res); +} + +int dp_mst_connector_get_info(struct drm_connector *connector, + struct msm_display_info *info, + void *display) +{ + int rc; + enum drm_connector_status status = connector_status_unknown; + + DP_MST_DEBUG("enter:\n"); + + rc = dp_connector_get_info(connector, info, display); + + if (!rc) { + status = dp_mst_connector_detect(connector, false, display); + + if (status == connector_status_connected) + info->is_connected = true; + else + info->is_connected = false; + } + + DP_MST_DEBUG("mst connector:%d get info:%d, rc:%d\n", + connector->base.id, status, rc); + + DP_MST_DEBUG("exit:\n"); + + return rc; +} + +int dp_mst_connector_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, + const struct msm_resource_caps_info *avail_res) +{ + int rc; + + DP_MST_DEBUG("enter:\n"); + + rc = dp_connector_get_mode_info(connector, drm_mode, mode_info, + display, avail_res); + + DP_MST_DEBUG("mst connector:%d get mode info. rc:%d\n", + connector->base.id, rc); + + DP_MST_DEBUG("exit:\n"); + + return rc; +} + +static struct drm_encoder * +dp_mst_atomic_best_encoder(struct drm_connector *connector, + void *display, struct drm_connector_state *state) +{ + struct dp_display *dp_display = display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct sde_connector *conn = to_sde_connector(connector); + struct drm_encoder *enc = NULL; + struct dp_mst_bridge_state *bridge_state; + u32 i; + + if (state->best_encoder) + return state->best_encoder; + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + bridge_state = dp_mst_get_bridge_atomic_state( + state->state, &mst->mst_bridge[i]); + if (IS_ERR(bridge_state)) + goto end; + + if (bridge_state->connector == connector) { + enc = mst->mst_bridge[i].encoder; + goto end; + } + } + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (mst->mst_bridge[i].fixed_connector) + continue; + + bridge_state = dp_mst_get_bridge_atomic_state( + state->state, &mst->mst_bridge[i]); + + if (!bridge_state->connector) { + bridge_state->connector = connector; + bridge_state->dp_panel = conn->drv_panel; + enc = mst->mst_bridge[i].encoder; + break; + } + + } + +end: + if (enc) + DP_MST_DEBUG("mst connector:%d atomic best encoder:%d\n", + connector->base.id, i); + else + DP_MST_DEBUG("mst connector:%d atomic best encoder failed\n", + connector->base.id); + + return enc; +} + +static int dp_mst_connector_atomic_check(struct drm_connector *connector, + void *display, struct drm_connector_state *new_conn_state) +{ + int rc = 0, slots, i; + struct drm_atomic_state *state; + struct drm_connector_state *old_conn_state; + struct drm_crtc *old_crtc; + struct drm_crtc_state *crtc_state; + struct dp_mst_bridge *bridge; + struct dp_mst_bridge_state *bridge_state; + struct dp_display *dp_display = display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct sde_connector *c_conn; + struct dp_display_mode dp_mode; + + DP_MST_DEBUG("enter:\n"); + + if (!new_conn_state) + return rc; + + state = new_conn_state->state; + + old_conn_state = drm_atomic_get_old_connector_state(state, connector); + if (!old_conn_state) + goto mode_set; + + old_crtc = old_conn_state->crtc; + if (!old_crtc) + goto mode_set; + + crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + bridge = &mst->mst_bridge[i]; + DP_MST_DEBUG("bridge id:%d, vcpi:%d, pbn:%d, slots:%d\n", + bridge->id, bridge->vcpi, bridge->pbn, + bridge->num_slots); + } + + if (drm_atomic_crtc_needs_modeset(crtc_state)) { + if (WARN_ON(!old_conn_state->best_encoder)) { + rc = -EINVAL; + goto end; + } + + bridge = to_dp_mst_bridge( + old_conn_state->best_encoder->bridge); + + bridge_state = dp_mst_get_bridge_atomic_state(state, bridge); + if (IS_ERR(bridge_state)) { + rc = PTR_ERR(bridge_state); + goto end; + } + + if (WARN_ON(bridge_state->connector != connector)) { + rc = -EINVAL; + goto end; + } + + slots = bridge_state->num_slots; + if (slots > 0) { + rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, + &mst->mst_mgr, slots); + if (rc) { + pr_err("failed releasing %d vcpi slots %d\n", + slots, rc); + goto end; + } + } + + bridge_state->num_slots = 0; + + if (!new_conn_state->crtc && mst->state != PM_SUSPEND) { + bridge_state->connector = NULL; + bridge_state->dp_panel = NULL; + + DP_MST_DEBUG("clear best encoder: %d\n", bridge->id); + } + } + +mode_set: + if (!new_conn_state->crtc) + goto end; + + crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); + + if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) { + c_conn = to_sde_connector(connector); + + if (WARN_ON(!new_conn_state->best_encoder)) { + rc = -EINVAL; + goto end; + } + + bridge = to_dp_mst_bridge( + new_conn_state->best_encoder->bridge); + + bridge_state = dp_mst_get_bridge_atomic_state(state, bridge); + if (IS_ERR(bridge_state)) { + rc = PTR_ERR(bridge_state); + goto end; + } + + if (WARN_ON(bridge_state->connector != connector)) { + rc = -EINVAL; + goto end; + } + + if (WARN_ON(bridge_state->num_slots)) { + rc = -EINVAL; + goto end; + } + + dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, + &crtc_state->mode, &dp_mode); + + slots = _dp_mst_compute_config(state, mst, connector, &dp_mode); + if (slots < 0) { + rc = slots; + goto end; + } + + bridge_state->num_slots = slots; + } + +end: + DP_MST_DEBUG("mst connector:%d atomic check ret %d\n", + connector->base.id, rc); + return rc; +} + +static int dp_mst_connector_config_hdr(struct drm_connector *connector, + void *display, struct sde_connector_state *c_state) +{ + int rc; + + DP_MST_DEBUG("enter:\n"); + + rc = dp_connector_config_hdr(connector, display, c_state); + + DP_MST_DEBUG("mst connector:%d cfg hdr. rc:%d\n", + connector->base.id, rc); + + DP_MST_DEBUG("exit:\n"); + + return rc; +} + +static void dp_mst_connector_pre_destroy(struct drm_connector *connector, + void *display) +{ + struct dp_display *dp_display = display; + + DP_MST_DEBUG("enter:\n"); + dp_display->mst_connector_uninstall(dp_display, connector); + DP_MST_DEBUG("exit:\n"); +} + +/* DRM MST callbacks */ + +static struct drm_connector * +dp_mst_add_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, const char *pathprop) +{ + static const struct sde_connector_ops dp_mst_connector_ops = { + .post_init = NULL, + .detect = dp_mst_connector_detect, + .get_modes = dp_mst_connector_get_modes, + .mode_valid = dp_mst_connector_mode_valid, + .get_info = dp_mst_connector_get_info, + .get_mode_info = dp_mst_connector_get_mode_info, + .atomic_best_encoder = dp_mst_atomic_best_encoder, + .atomic_check = dp_mst_connector_atomic_check, + .config_hdr = dp_mst_connector_config_hdr, + .pre_destroy = dp_mst_connector_pre_destroy, + .update_pps = dp_connector_update_pps, + }; + struct dp_mst_private *dp_mst; + struct drm_device *dev; + struct dp_display *dp_display; + struct drm_connector *connector; + struct sde_connector *c_conn; + int rc, i; + + DP_MST_DEBUG("enter\n"); + + dp_mst = container_of(mgr, struct dp_mst_private, mst_mgr); + + dp_display = dp_mst->dp_display; + dev = dp_display->drm_dev; + + /* make sure connector is not accessed before reset */ + drm_modeset_lock_all(dev); + + connector = sde_connector_init(dev, + dp_mst->mst_bridge[0].encoder, + NULL, + dp_display, + &dp_mst_connector_ops, + DRM_CONNECTOR_POLL_HPD, + DRM_MODE_CONNECTOR_DisplayPort); + + if (!connector) { + DP_ERR("mst sde_connector_init failed\n"); + drm_modeset_unlock_all(dev); + return connector; + } + + rc = dp_display->mst_connector_install(dp_display, connector); + if (rc) { + DP_ERR("mst connector install failed\n"); + sde_connector_destroy(connector); + drm_modeset_unlock_all(dev); + return NULL; + } + + c_conn = to_sde_connector(connector); + c_conn->mst_port = port; + + if (connector->funcs->reset) + connector->funcs->reset(connector); + + for (i = 1; i < MAX_DP_MST_DRM_BRIDGES; i++) { + drm_connector_attach_encoder(connector, + dp_mst->mst_bridge[i].encoder); + } + + drm_object_attach_property(&connector->base, + dev->mode_config.path_property, 0); + drm_object_attach_property(&connector->base, + dev->mode_config.tile_property, 0); + + /* unlock connector and make it accessible */ + drm_modeset_unlock_all(dev); + + DP_MST_INFO_LOG("add mst connector id:%d\n", connector->base.id); + + return connector; +} + +static void dp_mst_register_connector(struct drm_connector *connector) +{ + DP_MST_DEBUG("enter\n"); + + connector->status = connector->funcs->detect(connector, false); + + DP_MST_INFO_LOG("register mst connector id:%d\n", + connector->base.id); + drm_connector_register(connector); +} + +static void dp_mst_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_connector *connector) +{ + DP_MST_DEBUG("enter\n"); + + DP_MST_INFO_LOG("destroy mst connector id:%d\n", connector->base.id); + + drm_connector_unregister(connector); + drm_connector_put(connector); +} + +static enum drm_connector_status +dp_mst_fixed_connector_detect(struct drm_connector *connector, bool force, + void *display) +{ + struct dp_display *dp_display = display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + int i; + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (mst->mst_bridge[i].fixed_connector != connector) + continue; + + if (!mst->mst_bridge[i].fixed_port_added) + break; + + return dp_mst_connector_detect(connector, force, display); + } + + return connector_status_disconnected; +} + +static struct drm_encoder * +dp_mst_fixed_atomic_best_encoder(struct drm_connector *connector, + void *display, struct drm_connector_state *state) +{ + struct dp_display *dp_display = display; + struct dp_mst_private *mst = dp_display->dp_mst_prv_info; + struct sde_connector *conn = to_sde_connector(connector); + struct drm_encoder *enc = NULL; + struct dp_mst_bridge_state *bridge_state; + u32 i; + + if (state->best_encoder) + return state->best_encoder; + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (mst->mst_bridge[i].fixed_connector == connector) { + bridge_state = dp_mst_get_bridge_atomic_state( + state->state, &mst->mst_bridge[i]); + if (IS_ERR(bridge_state)) + goto end; + + bridge_state->connector = connector; + bridge_state->dp_panel = conn->drv_panel; + enc = mst->mst_bridge[i].encoder; + break; + } + } + +end: + if (enc) + DP_MST_DEBUG("mst connector:%d atomic best encoder:%d\n", + connector->base.id, i); + else + DP_MST_DEBUG("mst connector:%d atomic best encoder failed\n", + connector->base.id); + + return enc; +} + +static u32 dp_mst_find_fixed_port_num(struct drm_dp_mst_branch *mstb, + struct drm_dp_mst_port *target) +{ + struct drm_dp_mst_port *port; + u32 port_num = 0; + + /* + * search through reversed order of adding sequence, so the port number + * will be unique once topology is fixed + */ + list_for_each_entry_reverse(port, &mstb->ports, next) { + if (port->mstb) + port_num += dp_mst_find_fixed_port_num(port->mstb, + target); + else if (!port->input) { + ++port_num; + if (port == target) + break; + } + } + + return port_num; +} + +static struct drm_connector * +dp_mst_find_fixed_connector(struct dp_mst_private *dp_mst, + struct drm_dp_mst_port *port) +{ + struct dp_display *dp_display = dp_mst->dp_display; + struct drm_connector *connector = NULL; + struct sde_connector *c_conn; + u32 port_num; + int i; + + mutex_lock(&port->mgr->lock); + port_num = dp_mst_find_fixed_port_num(port->mgr->mst_primary, port); + mutex_unlock(&port->mgr->lock); + + if (!port_num) + return NULL; + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (dp_mst->mst_bridge[i].fixed_port_num == port_num) { + connector = dp_mst->mst_bridge[i].fixed_connector; + c_conn = to_sde_connector(connector); + c_conn->mst_port = port; + dp_display->mst_connector_update_link_info(dp_display, + connector); + dp_mst->mst_bridge[i].fixed_port_added = true; + DP_MST_DEBUG("found fixed connector %d\n", + DRMID(connector)); + break; + } + } + + return connector; +} + +static int +dp_mst_find_first_available_encoder_idx(struct dp_mst_private *dp_mst) +{ + int enc_idx = MAX_DP_MST_DRM_BRIDGES; + int i; + + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (!dp_mst->mst_bridge[i].fixed_connector) { + enc_idx = i; + break; + } + } + + return enc_idx; +} + +static struct drm_connector * +dp_mst_add_fixed_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, const char *pathprop) +{ + struct dp_mst_private *dp_mst; + struct drm_device *dev; + struct dp_display *dp_display; + struct drm_connector *connector; + int i, enc_idx; + + DP_MST_DEBUG("enter\n"); + + dp_mst = container_of(mgr, struct dp_mst_private, mst_mgr); + + dp_display = dp_mst->dp_display; + dev = dp_display->drm_dev; + + if (port->input || port->mstb) + enc_idx = MAX_DP_MST_DRM_BRIDGES; + else { + /* if port is already reserved, return immediately */ + connector = dp_mst_find_fixed_connector(dp_mst, port); + if (connector != NULL) + return connector; + + /* first available bridge index for non-reserved port */ + enc_idx = dp_mst_find_first_available_encoder_idx(dp_mst); + } + + /* add normal connector */ + connector = dp_mst_add_connector(mgr, port, pathprop); + if (!connector) { + DP_MST_DEBUG("failed to add connector\n"); + return NULL; + } + + drm_modeset_lock_all(dev); + + /* clear encoder list */ + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) + connector->encoder_ids[i] = 0; + + /* re-attach encoders from first available encoders */ + for (i = enc_idx; i < MAX_DP_MST_DRM_BRIDGES; i++) + drm_connector_attach_encoder(connector, + dp_mst->mst_bridge[i].encoder); + + drm_modeset_unlock_all(dev); + + DP_MST_DEBUG("add mst connector:%d\n", connector->base.id); + + return connector; +} + +static void dp_mst_register_fixed_connector(struct drm_connector *connector) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + struct dp_display *dp_display = c_conn->display; + struct dp_mst_private *dp_mst = dp_display->dp_mst_prv_info; + int i; + + DP_MST_DEBUG("enter\n"); + + /* skip connector registered for fixed topology ports */ + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (dp_mst->mst_bridge[i].fixed_connector == connector) { + DP_MST_DEBUG("found fixed connector %d\n", + DRMID(connector)); + return; + } + } + + dp_mst_register_connector(connector); +} + +static void dp_mst_destroy_fixed_connector(struct drm_dp_mst_topology_mgr *mgr, + struct drm_connector *connector) +{ + struct dp_mst_private *dp_mst; + int i; + + DP_MST_DEBUG("enter\n"); + + dp_mst = container_of(mgr, struct dp_mst_private, mst_mgr); + + /* skip connector destroy for fixed topology ports */ + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { + if (dp_mst->mst_bridge[i].fixed_connector == connector) { + dp_mst->mst_bridge[i].fixed_port_added = false; + DP_MST_DEBUG("destroy fixed connector %d\n", + DRMID(connector)); + return; + } + } + + dp_mst_destroy_connector(mgr, connector); +} + +static struct drm_connector * +dp_mst_drm_fixed_connector_init(struct dp_display *dp_display, + struct drm_encoder *encoder) +{ + static const struct sde_connector_ops dp_mst_connector_ops = { + .post_init = NULL, + .detect = dp_mst_fixed_connector_detect, + .get_modes = dp_mst_connector_get_modes, + .mode_valid = dp_mst_connector_mode_valid, + .get_info = dp_mst_connector_get_info, + .get_mode_info = dp_mst_connector_get_mode_info, + .atomic_best_encoder = dp_mst_fixed_atomic_best_encoder, + .atomic_check = dp_mst_connector_atomic_check, + .config_hdr = dp_mst_connector_config_hdr, + .pre_destroy = dp_mst_connector_pre_destroy, + }; + struct drm_device *dev; + struct drm_connector *connector; + int rc; + + DP_MST_DEBUG("enter\n"); + + dev = dp_display->drm_dev; + + connector = sde_connector_init(dev, + encoder, + NULL, + dp_display, + &dp_mst_connector_ops, + DRM_CONNECTOR_POLL_HPD, + DRM_MODE_CONNECTOR_DisplayPort); + + if (!connector) { + DP_ERR("mst sde_connector_init failed\n"); + return NULL; + } + + rc = dp_display->mst_connector_install(dp_display, connector); + if (rc) { + DP_ERR("mst connector install failed\n"); + sde_connector_destroy(connector); + return NULL; + } + + drm_object_attach_property(&connector->base, + dev->mode_config.path_property, 0); + drm_object_attach_property(&connector->base, + dev->mode_config.tile_property, 0); + + DP_MST_DEBUG("add mst fixed connector:%d\n", connector->base.id); + + return connector; +} + +static void dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) +{ + struct dp_mst_private *mst = container_of(mgr, struct dp_mst_private, + mst_mgr); + struct drm_device *dev = mst->dp_display->drm_dev; + char event_string[] = "MST_HOTPLUG=1"; + char *envp[2]; + + envp[0] = event_string; + envp[1] = NULL; + + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); + + DP_MST_INFO_LOG("mst hot plug event\n"); +} + +static void dp_mst_hpd_event_notify(struct dp_mst_private *mst, bool hpd_status) +{ + struct drm_device *dev = mst->dp_display->drm_dev; + char event_string[] = "MST_HOTPLUG=1"; + char status[HPD_STRING_SIZE]; + char *envp[3]; + + if (hpd_status) + snprintf(status, HPD_STRING_SIZE, "status=connected"); + else + snprintf(status, HPD_STRING_SIZE, "status=disconnected"); + + envp[0] = event_string; + envp[1] = status; + envp[2] = NULL; + + kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, envp); + + DP_MST_INFO_LOG("%s finished\n", __func__); +} + +/* DP Driver Callback OPs */ + +static void dp_mst_display_hpd(void *dp_display, bool hpd_status, + struct dp_mst_hpd_info *info) +{ + int rc; + struct dp_display *dp = dp_display; + struct dp_mst_private *mst = dp->dp_mst_prv_info; + + mutex_lock(&mst->mst_lock); + mst->mst_session_state = hpd_status; + mutex_unlock(&mst->mst_lock); + + if (!hpd_status) { + rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr, + hpd_status); + if (rc < 0) + goto fail; + } + + if (info && !info->mst_protocol) { + if (hpd_status) { + mst->simulator.edid = (struct edid *)info->edid; + mst->simulator.port_cnt = info->mst_port_cnt; + } + mst->mst_fw_cbs = &drm_dp_sim_mst_fw_helper_ops; + } else { + mst->mst_fw_cbs = &drm_dp_mst_fw_helper_ops; + } + + if (hpd_status) { + rc = mst->mst_fw_cbs->topology_mgr_set_mst(&mst->mst_mgr, + hpd_status); + if (rc < 0) + goto fail; + } + + dp_mst_hpd_event_notify(mst, hpd_status); + + DP_MST_INFO_LOG("mst display hpd success. hpd:%d, rc:%d\n", hpd_status, + rc); + return; +fail: + DRM_ERROR("mst display hpd failed. hpd: %d, rc: %d\n", + hpd_status, rc); +} + +static void dp_mst_display_hpd_irq(void *dp_display, + struct dp_mst_hpd_info *info) +{ + int rc; + struct dp_display *dp = dp_display; + struct dp_mst_private *mst = dp->dp_mst_prv_info; + u8 esi[14]; + unsigned int esi_res = DP_SINK_COUNT_ESI + 1; + bool handled; + + if (info->mst_hpd_sim) { + if (info->mst_sim_add_con || info->mst_sim_remove_con) { + dp_mst_sim_handle_hpd_irq(dp_display, info); + + /* + * When removing a connector, hpd_irq -> sim_destroy -> + * destroy_connector_work will be executed in a thread. + * This thread will perform the dp_mst_hotplug at the + * appropriate time. Do not perform hotplug here + * because it may be too early. + */ + if (info->mst_sim_remove_con) + return; + } + + dp_mst_hotplug(&mst->mst_mgr); + return; + } + + if (!mst->mst_session_state) { + DP_ERR("mst_hpd_irq received before mst session start\n"); + return; + } + + rc = drm_dp_dpcd_read(mst->caps.drm_aux, DP_SINK_COUNT_ESI, + esi, 14); + if (rc != 14) { + DP_ERR("dpcd sink status read failed, rlen=%d\n", rc); + return; + } + + DP_MST_DEBUG("mst irq: esi1[0x%x] esi2[0x%x] esi3[%x]\n", + esi[1], esi[2], esi[3]); + + rc = drm_dp_mst_hpd_irq(&mst->mst_mgr, esi, &handled); + + /* ack the request */ + if (handled) { + rc = drm_dp_dpcd_write(mst->caps.drm_aux, esi_res, &esi[1], 3); + + if (rc != 3) + DP_ERR("dpcd esi_res failed. rlen=%d\n", rc); + } + + DP_MST_DEBUG("mst display hpd_irq handled:%d rc:%d\n", handled, rc); +} + +static void dp_mst_set_state(void *dp_display, enum dp_drv_state mst_state) +{ + struct dp_display *dp = dp_display; + struct dp_mst_private *mst = dp->dp_mst_prv_info; + + if (!mst) { + DP_DEBUG("mst not initialized\n"); + return; + } + + mst->state = mst_state; + DP_MST_INFO_LOG("mst power state:%d\n", mst_state); +} + +/* DP MST APIs */ + +static const struct dp_mst_drm_cbs dp_mst_display_cbs = { + .hpd = dp_mst_display_hpd, + .hpd_irq = dp_mst_display_hpd_irq, + .set_drv_state = dp_mst_set_state, +}; + +static const struct drm_dp_mst_topology_cbs dp_mst_drm_cbs = { + .add_connector = dp_mst_add_connector, + .register_connector = dp_mst_register_connector, + .destroy_connector = dp_mst_destroy_connector, + .hotplug = dp_mst_hotplug, +}; + +static const struct drm_dp_mst_topology_cbs dp_mst_fixed_drm_cbs = { + .add_connector = dp_mst_add_fixed_connector, + .register_connector = dp_mst_register_fixed_connector, + .destroy_connector = dp_mst_destroy_fixed_connector, + .hotplug = dp_mst_hotplug, +}; + +static void dp_mst_sim_init(struct dp_mst_private *mst) +{ + INIT_WORK(&mst->simulator.probe_work, dp_mst_sim_link_probe_work); + mst->simulator.cbs = &dp_mst_drm_cbs; +} + +int dp_mst_init(struct dp_display *dp_display) +{ + struct drm_device *dev; + int conn_base_id = 0; + int ret, i; + struct dp_mst_drm_install_info install_info; + + memset(&dp_mst, 0, sizeof(dp_mst)); + + if (!dp_display) { + DP_ERR("invalid params\n"); + return 0; + } + + dev = dp_display->drm_dev; + + /* register with DP driver */ + install_info.dp_mst_prv_info = &dp_mst; + install_info.cbs = &dp_mst_display_cbs; + dp_display->mst_install(dp_display, &install_info); + + dp_display->get_mst_caps(dp_display, &dp_mst.caps); + + if (!dp_mst.caps.has_mst) { + DP_MST_DEBUG("mst not supported\n"); + return 0; + } + + dp_mst.mst_fw_cbs = &drm_dp_mst_fw_helper_ops; + + memset(&dp_mst.mst_mgr, 0, sizeof(dp_mst.mst_mgr)); + dp_mst.mst_mgr.cbs = &dp_mst_drm_cbs; + conn_base_id = dp_display->base_connector->base.id; + dp_mst.dp_display = dp_display; + + mutex_init(&dp_mst.mst_lock); + + ret = drm_dp_mst_topology_mgr_init(&dp_mst.mst_mgr, dev, + dp_mst.caps.drm_aux, + dp_mst.caps.max_dpcd_transaction_bytes, + dp_mst.caps.max_streams_supported, + conn_base_id); + if (ret) { + DP_ERR("dp drm mst topology manager init failed\n"); + goto error; + } + + dp_mst_sim_init(&dp_mst); + + dp_mst.mst_initialized = true; + + /* create drm_bridges for cached mst encoders and clear cache */ + for (i = 0; i < dp_mst_enc_cache.cnt; i++) { + ret = dp_mst_drm_bridge_init(dp_display, + dp_mst_enc_cache.mst_enc[i]); + } + memset(&dp_mst_enc_cache, 0, sizeof(dp_mst_enc_cache)); + + /* choose fixed callback function if fixed topology is found */ + if (!dp_display->mst_get_fixed_topology_port(dp_display, 0, NULL)) + dp_mst.mst_mgr.cbs = &dp_mst_fixed_drm_cbs; + + DP_MST_INFO_LOG("dp drm mst topology manager init completed\n"); + + return ret; + +error: + mutex_destroy(&dp_mst.mst_lock); + return ret; +} + +void dp_mst_deinit(struct dp_display *dp_display) +{ + struct dp_mst_private *mst; + + if (!dp_display) { + DP_ERR("invalid params\n"); + return; + } + + mst = dp_display->dp_mst_prv_info; + + if (!mst->mst_initialized) + return; + + dp_display->mst_uninstall(dp_display); + + drm_dp_mst_topology_mgr_destroy(&mst->mst_mgr); + + dp_mst.mst_initialized = false; + + mutex_destroy(&mst->mst_lock); + + DP_MST_INFO_LOG("dp drm mst topology manager deinit completed\n"); +} + diff --git a/techpack/display/msm/dp/dp_panel.c b/techpack/display/msm/dp/dp_panel.c new file mode 100644 index 0000000000000000000000000000000000000000..b31103a6cde3dd57104c87e99651abb292fa4dbe --- /dev/null +++ b/techpack/display/msm/dp/dp_panel.c @@ -0,0 +1,3418 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include "dp_panel.h" +#include <linux/unistd.h> +#include <drm/drm_fixed.h> +#include "dp_debug.h" + +#define DP_KHZ_TO_HZ 1000 +#define DP_PANEL_DEFAULT_BPP 24 +#define DP_MAX_DS_PORT_COUNT 1 + +#define DPRX_FEATURE_ENUMERATION_LIST 0x2210 +#define DPRX_EXTENDED_DPCD_FIELD 0x2200 +#define VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED BIT(3) +#define VSC_EXT_VESA_SDP_SUPPORTED BIT(4) +#define VSC_EXT_VESA_SDP_CHAINING_SUPPORTED BIT(5) + +enum dp_panel_hdr_pixel_encoding { + RGB, + YCbCr444, + YCbCr422, + YCbCr420, + YONLY, + RAW, +}; + +enum dp_panel_hdr_rgb_colorimetry { + sRGB, + RGB_WIDE_GAMUT_FIXED_POINT, + RGB_WIDE_GAMUT_FLOATING_POINT, + ADOBERGB, + DCI_P3, + CUSTOM_COLOR_PROFILE, + ITU_R_BT_2020_RGB, +}; + +enum dp_panel_hdr_dynamic_range { + VESA, + CEA, +}; + +enum dp_panel_hdr_content_type { + NOT_DEFINED, + GRAPHICS, + PHOTO, + VIDEO, + GAME, +}; + +enum dp_panel_hdr_state { + HDR_DISABLED, + HDR_ENABLED, +}; + +struct dp_panel_private { + struct device *dev; + struct dp_panel dp_panel; + struct dp_aux *aux; + struct dp_link *link; + struct dp_parser *parser; + struct dp_catalog_panel *catalog; + bool custom_edid; + bool custom_dpcd; + bool panel_on; + bool vsc_supported; + bool vscext_supported; + bool vscext_chaining_supported; + enum dp_panel_hdr_state hdr_state; + u8 spd_vendor_name[8]; + u8 spd_product_description[16]; + u8 major; + u8 minor; +}; + +static const struct dp_panel_info fail_safe = { + .h_active = 640, + .v_active = 480, + .h_back_porch = 48, + .h_front_porch = 16, + .h_sync_width = 96, + .h_active_low = 0, + .v_back_porch = 33, + .v_front_porch = 10, + .v_sync_width = 2, + .v_active_low = 0, + .h_skew = 0, + .refresh_rate = 60, + .pixel_clk_khz = 25200, + .bpp = 24, +}; + +/* OEM NAME */ +static const u8 vendor_name[8] = {81, 117, 97, 108, 99, 111, 109, 109}; + +/* MODEL NAME */ +static const u8 product_desc[16] = {83, 110, 97, 112, 100, 114, 97, 103, + 111, 110, 0, 0, 0, 0, 0, 0}; + +struct dp_dhdr_maxpkt_calc_input { + u32 mdp_clk; + u32 lclk; + u32 pclk; + u32 h_active; + u32 nlanes; + s64 mst_target_sc; + bool mst_en; + bool fec_en; +}; + +struct tu_algo_data { + s64 lclk_fp; + s64 pclk_fp; + s64 lwidth; + s64 lwidth_fp; + s64 hbp_relative_to_pclk; + s64 hbp_relative_to_pclk_fp; + int nlanes; + int bpp; + int pixelEnc; + int dsc_en; + int async_en; + int bpc; + + uint delay_start_link_extra_pixclk; + int extra_buffer_margin; + s64 ratio_fp; + s64 original_ratio_fp; + + s64 err_fp; + s64 n_err_fp; + s64 n_n_err_fp; + int tu_size; + int tu_size_desired; + int tu_size_minus1; + + int valid_boundary_link; + s64 resulting_valid_fp; + s64 total_valid_fp; + s64 effective_valid_fp; + s64 effective_valid_recorded_fp; + int n_tus; + int n_tus_per_lane; + int paired_tus; + int remainder_tus; + int remainder_tus_upper; + int remainder_tus_lower; + int extra_bytes; + int filler_size; + int delay_start_link; + + int extra_pclk_cycles; + int extra_pclk_cycles_in_link_clk; + s64 ratio_by_tu_fp; + s64 average_valid2_fp; + int new_valid_boundary_link; + int remainder_symbols_exist; + int n_symbols; + s64 n_remainder_symbols_per_lane_fp; + s64 last_partial_tu_fp; + s64 TU_ratio_err_fp; + + int n_tus_incl_last_incomplete_tu; + int extra_pclk_cycles_tmp; + int extra_pclk_cycles_in_link_clk_tmp; + int extra_required_bytes_new_tmp; + int filler_size_tmp; + int lower_filler_size_tmp; + int delay_start_link_tmp; + + bool boundary_moderation_en; + int boundary_mod_lower_err; + int upper_boundary_count; + int lower_boundary_count; + int i_upper_boundary_count; + int i_lower_boundary_count; + int valid_lower_boundary_link; + int even_distribution_BF; + int even_distribution_legacy; + int even_distribution; + int min_hblank_violated; + s64 delay_start_time_fp; + s64 hbp_time_fp; + s64 hactive_time_fp; + s64 diff_abs_fp; + + s64 ratio; +}; + +/** + * Mapper function which outputs colorimetry and dynamic range + * to be used for a given colorspace value when the vsc sdp + * packets are used to change the colorimetry. + */ +static void get_sdp_colorimetry_range(struct dp_panel_private *panel, + u32 colorspace, u32 *colorimetry, u32 *dynamic_range) +{ + + u32 cc; + + /* + * Some rules being used for assignment of dynamic + * range for colorimetry using SDP: + * + * 1) If compliance test is ongoing return sRGB with + * CEA primaries + * 2) For BT2020 cases, dynamic range shall be CEA + * 3) For DCI-P3 cases, as per HW team dynamic range + * shall be VESA for RGB and CEA for YUV content + * Hence defaulting to RGB and picking VESA + * 4) Default shall be sRGB with VESA + */ + + cc = panel->link->get_colorimetry_config(panel->link); + + if (cc) { + *colorimetry = sRGB; + *dynamic_range = CEA; + return; + } + + switch (colorspace) { + case DRM_MODE_COLORIMETRY_BT2020_RGB: + *colorimetry = ITU_R_BT_2020_RGB; + *dynamic_range = CEA; + break; + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + *colorimetry = DCI_P3; + *dynamic_range = VESA; + break; + default: + *colorimetry = sRGB; + *dynamic_range = VESA; + } +} + +/** + * Mapper function which outputs colorimetry to be used for a + * given colorspace value when misc field of MSA is used to + * change the colorimetry. Currently only RGB formats have been + * added. This API will be extended to YUV once its supported on DP. + */ +static u8 get_misc_colorimetry_val(struct dp_panel_private *panel, + u32 colorspace) +{ + u8 colorimetry; + u32 cc; + + cc = panel->link->get_colorimetry_config(panel->link); + /* + * If there is a non-zero value then compliance test-case + * is going on, otherwise we can honor the colorspace setting + */ + if (cc) + return cc; + + switch (colorspace) { + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + colorimetry = 0x7; + break; + case DRM_MODE_DP_COLORIMETRY_SRGB: + colorimetry = 0x4; + break; + case DRM_MODE_DP_COLORIMETRY_RGB_WIDE_GAMUT: + colorimetry = 0x3; + break; + case DRM_MODE_DP_COLORIMETRY_SCRGB: + colorimetry = 0xb; + break; + case DRM_MODE_COLORIMETRY_OPRGB: + colorimetry = 0xc; + break; + default: + colorimetry = 0; + } + + return colorimetry; +} + +static int _tu_param_compare(s64 a, s64 b) +{ + u32 a_int, a_frac, a_sign; + u32 b_int, b_frac, b_sign; + s64 a_temp, b_temp, minus_1; + + if (a == b) + return 0; + + minus_1 = drm_fixp_from_fraction(-1, 1); + + a_int = (a >> 32) & 0x7FFFFFFF; + a_frac = a & 0xFFFFFFFF; + a_sign = (a >> 32) & 0x80000000 ? 1 : 0; + + b_int = (b >> 32) & 0x7FFFFFFF; + b_frac = b & 0xFFFFFFFF; + b_sign = (b >> 32) & 0x80000000 ? 1 : 0; + + if (a_sign > b_sign) + return 2; + else if (b_sign > a_sign) + return 1; + + if (!a_sign && !b_sign) { /* positive */ + if (a > b) + return 1; + else + return 2; + } else { /* negative */ + a_temp = drm_fixp_mul(a, minus_1); + b_temp = drm_fixp_mul(b, minus_1); + + if (a_temp > b_temp) + return 2; + else + return 1; + } +} + +static void dp_panel_update_tu_timings(struct dp_tu_calc_input *in, + struct tu_algo_data *tu) +{ + int nlanes = in->nlanes; + int dsc_num_slices = in->num_of_dsc_slices; + int dsc_num_bytes = 0; + int numerator; + s64 pclk_dsc_fp; + s64 dwidth_dsc_fp; + s64 hbp_dsc_fp; + s64 overhead_dsc; + + int tot_num_eoc_symbols = 0; + int tot_num_hor_bytes = 0; + int tot_num_dummy_bytes = 0; + int dwidth_dsc_bytes = 0; + int eoc_bytes = 0; + + s64 temp1_fp, temp2_fp, temp3_fp; + + tu->lclk_fp = drm_fixp_from_fraction(in->lclk, 1); + tu->pclk_fp = drm_fixp_from_fraction(in->pclk_khz, 1000); + tu->lwidth = in->hactive; + tu->hbp_relative_to_pclk = in->hporch; + tu->nlanes = in->nlanes; + tu->bpp = in->bpp; + tu->pixelEnc = in->pixel_enc; + tu->dsc_en = in->dsc_en; + tu->async_en = in->async_en; + tu->lwidth_fp = drm_fixp_from_fraction(in->hactive, 1); + tu->hbp_relative_to_pclk_fp = drm_fixp_from_fraction(in->hporch, 1); + + if (tu->pixelEnc == 420) { + temp1_fp = drm_fixp_from_fraction(2, 1); + tu->pclk_fp = drm_fixp_div(tu->pclk_fp, temp1_fp); + tu->lwidth_fp = drm_fixp_div(tu->lwidth_fp, temp1_fp); + tu->hbp_relative_to_pclk_fp = + drm_fixp_div(tu->hbp_relative_to_pclk_fp, 2); + } + + if (tu->pixelEnc == 422) { + switch (tu->bpp) { + case 24: + tu->bpp = 16; + tu->bpc = 8; + break; + case 30: + tu->bpp = 20; + tu->bpc = 10; + break; + default: + tu->bpp = 16; + tu->bpc = 8; + break; + } + } else + tu->bpc = tu->bpp/3; + + if (!in->dsc_en) + goto fec_check; + + temp1_fp = drm_fixp_from_fraction(in->compress_ratio, 100); + temp2_fp = drm_fixp_from_fraction(in->bpp, 1); + temp3_fp = drm_fixp_div(temp2_fp, temp1_fp); + temp2_fp = drm_fixp_mul(tu->lwidth_fp, temp3_fp); + + temp1_fp = drm_fixp_from_fraction(8, 1); + temp3_fp = drm_fixp_div(temp2_fp, temp1_fp); + + numerator = drm_fixp2int(temp3_fp); + + dsc_num_bytes = numerator / dsc_num_slices; + eoc_bytes = dsc_num_bytes % nlanes; + tot_num_eoc_symbols = nlanes * dsc_num_slices; + tot_num_hor_bytes = dsc_num_bytes * dsc_num_slices; + tot_num_dummy_bytes = (nlanes - eoc_bytes) * dsc_num_slices; + + if (dsc_num_bytes == 0) + DP_INFO("incorrect no of bytes per slice=%d\n", dsc_num_bytes); + + dwidth_dsc_bytes = (tot_num_hor_bytes + + tot_num_eoc_symbols + + (eoc_bytes == 0 ? 0 : tot_num_dummy_bytes)); + overhead_dsc = dwidth_dsc_bytes / tot_num_hor_bytes; + + dwidth_dsc_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, 3); + + temp2_fp = drm_fixp_mul(tu->pclk_fp, dwidth_dsc_fp); + temp1_fp = drm_fixp_div(temp2_fp, tu->lwidth_fp); + pclk_dsc_fp = temp1_fp; + + temp1_fp = drm_fixp_div(pclk_dsc_fp, tu->pclk_fp); + temp2_fp = drm_fixp_mul(tu->hbp_relative_to_pclk_fp, temp1_fp); + hbp_dsc_fp = temp2_fp; + + /* output */ + tu->pclk_fp = pclk_dsc_fp; + tu->lwidth_fp = dwidth_dsc_fp; + tu->hbp_relative_to_pclk_fp = hbp_dsc_fp; + +fec_check: + if (in->fec_en) { + temp1_fp = drm_fixp_from_fraction(976, 1000); /* 0.976 */ + tu->lclk_fp = drm_fixp_mul(tu->lclk_fp, temp1_fp); + } +} + +static void _tu_valid_boundary_calc(struct tu_algo_data *tu) +{ + s64 temp1_fp, temp2_fp, temp, temp1, temp2; + int compare_result_1, compare_result_2, compare_result_3; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); + + tu->new_valid_boundary_link = drm_fixp2int_ceil(temp2_fp); + + temp = (tu->i_upper_boundary_count * + tu->new_valid_boundary_link + + tu->i_lower_boundary_count * + (tu->new_valid_boundary_link-1)); + tu->average_valid2_fp = drm_fixp_from_fraction(temp, + (tu->i_upper_boundary_count + + tu->i_lower_boundary_count)); + + temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); + temp2_fp = tu->lwidth_fp; + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); + tu->n_tus = drm_fixp2int(temp2_fp); + if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000) + tu->n_tus += 1; + + temp1_fp = drm_fixp_from_fraction(tu->n_tus, 1); + temp2_fp = drm_fixp_mul(temp1_fp, tu->average_valid2_fp); + temp1_fp = drm_fixp_from_fraction(tu->n_symbols, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(tu->nlanes, 1); + temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); + tu->n_remainder_symbols_per_lane_fp = temp2_fp; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + tu->last_partial_tu_fp = + drm_fixp_div(tu->n_remainder_symbols_per_lane_fp, + temp1_fp); + + if (tu->n_remainder_symbols_per_lane_fp != 0) + tu->remainder_symbols_exist = 1; + else + tu->remainder_symbols_exist = 0; + + temp1_fp = drm_fixp_from_fraction(tu->n_tus, tu->nlanes); + tu->n_tus_per_lane = drm_fixp2int(temp1_fp); + + tu->paired_tus = (int)((tu->n_tus_per_lane) / + (tu->i_upper_boundary_count + + tu->i_lower_boundary_count)); + + tu->remainder_tus = tu->n_tus_per_lane - tu->paired_tus * + (tu->i_upper_boundary_count + + tu->i_lower_boundary_count); + + if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) { + tu->remainder_tus_upper = tu->i_upper_boundary_count; + tu->remainder_tus_lower = tu->remainder_tus - + tu->i_upper_boundary_count; + } else { + tu->remainder_tus_upper = tu->remainder_tus; + tu->remainder_tus_lower = 0; + } + + temp = tu->paired_tus * (tu->i_upper_boundary_count * + tu->new_valid_boundary_link + + tu->i_lower_boundary_count * + (tu->new_valid_boundary_link - 1)) + + (tu->remainder_tus_upper * + tu->new_valid_boundary_link) + + (tu->remainder_tus_lower * + (tu->new_valid_boundary_link - 1)); + tu->total_valid_fp = drm_fixp_from_fraction(temp, 1); + + if (tu->remainder_symbols_exist) { + temp1_fp = tu->total_valid_fp + + tu->n_remainder_symbols_per_lane_fp; + temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1); + temp2_fp = temp2_fp + tu->last_partial_tu_fp; + temp1_fp = drm_fixp_div(temp1_fp, temp2_fp); + } else { + temp2_fp = drm_fixp_from_fraction(tu->n_tus_per_lane, 1); + temp1_fp = drm_fixp_div(tu->total_valid_fp, temp2_fp); + } + tu->effective_valid_fp = temp1_fp; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); + tu->n_n_err_fp = tu->effective_valid_fp - temp2_fp; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->ratio_fp, temp1_fp); + tu->n_err_fp = tu->average_valid2_fp - temp2_fp; + + tu->even_distribution = tu->n_tus % tu->nlanes == 0 ? 1 : 0; + + temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); + temp2_fp = tu->lwidth_fp; + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, tu->average_valid2_fp); + + if (temp2_fp) + tu->n_tus_incl_last_incomplete_tu = drm_fixp2int_ceil(temp2_fp); + else + tu->n_tus_incl_last_incomplete_tu = 0; + + temp1 = 0; + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + temp1_fp = tu->average_valid2_fp - temp2_fp; + temp2_fp = drm_fixp_from_fraction(tu->n_tus_incl_last_incomplete_tu, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + temp1 = drm_fixp2int_ceil(temp1_fp); + + temp = tu->i_upper_boundary_count * tu->nlanes; + temp1_fp = drm_fixp_from_fraction(tu->tu_size, 1); + temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu->new_valid_boundary_link, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(temp, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + if (temp2_fp) + temp2 = drm_fixp2int_ceil(temp2_fp); + else + temp2 = 0; + tu->extra_required_bytes_new_tmp = (int)(temp1 + temp2); + + temp1_fp = drm_fixp_from_fraction(8, tu->bpp); + temp2_fp = drm_fixp_from_fraction( + tu->extra_required_bytes_new_tmp, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + tu->extra_pclk_cycles_tmp = drm_fixp2int_ceil(temp1_fp); + else + tu->extra_pclk_cycles_tmp = 0; + + temp1_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles_tmp, 1); + temp2_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + if (temp1_fp) + tu->extra_pclk_cycles_in_link_clk_tmp = + drm_fixp2int_ceil(temp1_fp); + else + tu->extra_pclk_cycles_in_link_clk_tmp = 0; + + tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link; + + tu->lower_filler_size_tmp = tu->filler_size_tmp + 1; + + tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp + + tu->lower_filler_size_tmp + + tu->extra_buffer_margin; + + temp1_fp = drm_fixp_from_fraction(tu->delay_start_link_tmp, 1); + tu->delay_start_time_fp = drm_fixp_div(temp1_fp, tu->lclk_fp); + + compare_result_1 = _tu_param_compare(tu->n_n_err_fp, tu->diff_abs_fp); + if (compare_result_1 == 2) + compare_result_1 = 1; + else + compare_result_1 = 0; + + compare_result_2 = _tu_param_compare(tu->n_n_err_fp, tu->err_fp); + if (compare_result_2 == 2) + compare_result_2 = 1; + else + compare_result_2 = 0; + + compare_result_3 = _tu_param_compare(tu->hbp_time_fp, + tu->delay_start_time_fp); + if (compare_result_3 == 2) + compare_result_3 = 0; + else + compare_result_3 = 1; + + if (((tu->even_distribution == 1) || + ((tu->even_distribution_BF == 0) && + (tu->even_distribution_legacy == 0))) && + tu->n_err_fp >= 0 && tu->n_n_err_fp >= 0 && + compare_result_2 && + (compare_result_1 || (tu->min_hblank_violated == 1)) && + (tu->new_valid_boundary_link - 1) > 0 && + compare_result_3 && + (tu->delay_start_link_tmp <= 1023)) { + tu->upper_boundary_count = tu->i_upper_boundary_count; + tu->lower_boundary_count = tu->i_lower_boundary_count; + tu->err_fp = tu->n_n_err_fp; + tu->boundary_moderation_en = true; + tu->tu_size_desired = tu->tu_size; + tu->valid_boundary_link = tu->new_valid_boundary_link; + tu->effective_valid_recorded_fp = tu->effective_valid_fp; + tu->even_distribution_BF = 1; + tu->delay_start_link = tu->delay_start_link_tmp; + } else if (tu->boundary_mod_lower_err == 0) { + compare_result_1 = _tu_param_compare(tu->n_n_err_fp, + tu->diff_abs_fp); + if (compare_result_1 == 2) + tu->boundary_mod_lower_err = 1; + } +} + +static void _dp_calc_boundary(struct tu_algo_data *tu) +{ + + s64 temp1_fp = 0, temp2_fp = 0; + + do { + tu->err_fp = drm_fixp_from_fraction(1000, 1); + + temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); + temp2_fp = drm_fixp_from_fraction( + tu->delay_start_link_extra_pixclk, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + tu->extra_buffer_margin = + drm_fixp2int_ceil(temp1_fp); + else + tu->extra_buffer_margin = 0; + + temp1_fp = drm_fixp_from_fraction(tu->bpp, 8); + temp1_fp = drm_fixp_mul(tu->lwidth_fp, temp1_fp); + + if (temp1_fp) + tu->n_symbols = drm_fixp2int_ceil(temp1_fp); + else + tu->n_symbols = 0; + + for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) { + for (tu->i_upper_boundary_count = 1; + tu->i_upper_boundary_count <= 15; + tu->i_upper_boundary_count++) { + for (tu->i_lower_boundary_count = 1; + tu->i_lower_boundary_count <= 15; + tu->i_lower_boundary_count++) { + _tu_valid_boundary_calc(tu); + } + } + } + tu->delay_start_link_extra_pixclk--; + } while (!tu->boundary_moderation_en && + tu->boundary_mod_lower_err == 1 && + tu->delay_start_link_extra_pixclk != 0); +} + +static void _dp_calc_extra_bytes(struct tu_algo_data *tu) +{ + u64 temp = 0; + s64 temp1_fp = 0, temp2_fp = 0; + + temp1_fp = drm_fixp_from_fraction(tu->tu_size_desired, 1); + temp2_fp = drm_fixp_mul(tu->original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu->valid_boundary_link, 1); + temp2_fp = temp1_fp - temp2_fp; + temp1_fp = drm_fixp_from_fraction(tu->n_tus + 1, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + temp = drm_fixp2int(temp2_fp); + if (temp && temp2_fp) + tu->extra_bytes = drm_fixp2int_ceil(temp2_fp); + else + tu->extra_bytes = 0; + + temp1_fp = drm_fixp_from_fraction(tu->extra_bytes, 1); + temp2_fp = drm_fixp_from_fraction(8, tu->bpp); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + + if (temp1_fp) + tu->extra_pclk_cycles = drm_fixp2int_ceil(temp1_fp); + else + tu->extra_pclk_cycles = drm_fixp2int(temp1_fp); + + temp1_fp = drm_fixp_div(tu->lclk_fp, tu->pclk_fp); + temp2_fp = drm_fixp_from_fraction(tu->extra_pclk_cycles, 1); + temp1_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + if (temp1_fp) + tu->extra_pclk_cycles_in_link_clk = drm_fixp2int_ceil(temp1_fp); + else + tu->extra_pclk_cycles_in_link_clk = drm_fixp2int(temp1_fp); +} + +static void _dp_panel_calc_tu(struct dp_tu_calc_input *in, + struct dp_vc_tu_mapping_table *tu_table) +{ + struct tu_algo_data tu; + int compare_result_1, compare_result_2; + u64 temp = 0; + s64 temp_fp = 0, temp1_fp = 0, temp2_fp = 0; + + s64 LCLK_FAST_SKEW_fp = drm_fixp_from_fraction(6, 10000); /* 0.0006 */ + s64 const_p49_fp = drm_fixp_from_fraction(49, 100); /* 0.49 */ + s64 const_p56_fp = drm_fixp_from_fraction(56, 100); /* 0.56 */ + s64 RATIO_SCALE_fp = drm_fixp_from_fraction(1001, 1000); + + u8 DP_BRUTE_FORCE = 1; + s64 BRUTE_FORCE_THRESHOLD_fp = drm_fixp_from_fraction(1, 10); /* 0.1 */ + uint EXTRA_PIXCLK_CYCLE_DELAY = 4; + uint HBLANK_MARGIN = 4; + + memset(&tu, 0, sizeof(tu)); + + dp_panel_update_tu_timings(in, &tu); + + tu.err_fp = drm_fixp_from_fraction(1000, 1); /* 1000 */ + + temp1_fp = drm_fixp_from_fraction(4, 1); + temp2_fp = drm_fixp_mul(temp1_fp, tu.lclk_fp); + temp_fp = drm_fixp_div(temp2_fp, tu.pclk_fp); + tu.extra_buffer_margin = drm_fixp2int_ceil(temp_fp); + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_mul(tu.pclk_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); + temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); + tu.ratio_fp = drm_fixp_div(temp2_fp, tu.lclk_fp); + + tu.original_ratio_fp = tu.ratio_fp; + tu.boundary_moderation_en = false; + tu.upper_boundary_count = 0; + tu.lower_boundary_count = 0; + tu.i_upper_boundary_count = 0; + tu.i_lower_boundary_count = 0; + tu.valid_lower_boundary_link = 0; + tu.even_distribution_BF = 0; + tu.even_distribution_legacy = 0; + tu.even_distribution = 0; + tu.delay_start_time_fp = 0; + + tu.err_fp = drm_fixp_from_fraction(1000, 1); + tu.n_err_fp = 0; + tu.n_n_err_fp = 0; + + tu.ratio = drm_fixp2int(tu.ratio_fp); + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); + temp2_fp = tu.lwidth_fp % temp1_fp; + if (temp2_fp != 0 && + !tu.ratio && tu.dsc_en == 0) { + tu.ratio_fp = drm_fixp_mul(tu.ratio_fp, RATIO_SCALE_fp); + tu.ratio = drm_fixp2int(tu.ratio_fp); + if (tu.ratio) + tu.ratio_fp = drm_fixp_from_fraction(1, 1); + } + + if (tu.ratio > 1) + tu.ratio = 1; + + if (tu.ratio == 1) + goto tu_size_calc; + + compare_result_1 = _tu_param_compare(tu.ratio_fp, const_p49_fp); + if (!compare_result_1 || compare_result_1 == 1) + compare_result_1 = 1; + else + compare_result_1 = 0; + + compare_result_2 = _tu_param_compare(tu.ratio_fp, const_p56_fp); + if (!compare_result_2 || compare_result_2 == 2) + compare_result_2 = 1; + else + compare_result_2 = 0; + + if (tu.dsc_en && compare_result_1 && compare_result_2) { + HBLANK_MARGIN += 4; + DP_INFO("Info: increase HBLANK_MARGIN to %d\n", HBLANK_MARGIN); + } + +tu_size_calc: + for (tu.tu_size = 32; tu.tu_size <= 64; tu.tu_size++) { + temp1_fp = drm_fixp_from_fraction(tu.tu_size, 1); + temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + temp = drm_fixp2int_ceil(temp2_fp); + temp1_fp = drm_fixp_from_fraction(temp, 1); + tu.n_err_fp = temp1_fp - temp2_fp; + + if (tu.n_err_fp < tu.err_fp) { + tu.err_fp = tu.n_err_fp; + tu.tu_size_desired = tu.tu_size; + } + } + + tu.tu_size_minus1 = tu.tu_size_desired - 1; + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + tu.valid_boundary_link = drm_fixp2int_ceil(temp2_fp); + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = tu.lwidth_fp; + temp2_fp = drm_fixp_mul(temp2_fp, temp1_fp); + + temp1_fp = drm_fixp_from_fraction(tu.valid_boundary_link, 1); + temp2_fp = drm_fixp_div(temp2_fp, temp1_fp); + tu.n_tus = drm_fixp2int(temp2_fp); + if ((temp2_fp & 0xFFFFFFFF) > 0xFFFFF000) + tu.n_tus += 1; + + tu.even_distribution_legacy = tu.n_tus % tu.nlanes == 0 ? 1 : 0; + DP_INFO("Info: n_sym = %d, num_of_tus = %d\n", + tu.valid_boundary_link, tu.n_tus); + + _dp_calc_extra_bytes(&tu); + + tu.filler_size = tu.tu_size_desired - tu.valid_boundary_link; + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + tu.ratio_by_tu_fp = drm_fixp_mul(tu.ratio_fp, temp1_fp); + + tu.delay_start_link = tu.extra_pclk_cycles_in_link_clk + + tu.filler_size + tu.extra_buffer_margin; + + tu.resulting_valid_fp = + drm_fixp_from_fraction(tu.valid_boundary_link, 1); + + temp1_fp = drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = drm_fixp_div(tu.resulting_valid_fp, temp1_fp); + tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; + + temp1_fp = drm_fixp_from_fraction(HBLANK_MARGIN, 1); + temp1_fp = tu.hbp_relative_to_pclk_fp - temp1_fp; + tu.hbp_time_fp = drm_fixp_div(temp1_fp, tu.pclk_fp); + + temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); + tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); + + compare_result_1 = _tu_param_compare(tu.hbp_time_fp, + tu.delay_start_time_fp); + if (compare_result_1 == 2) /* hbp_time_fp < delay_start_time_fp */ + tu.min_hblank_violated = 1; + + tu.hactive_time_fp = drm_fixp_div(tu.lwidth_fp, tu.pclk_fp); + + compare_result_2 = _tu_param_compare(tu.hactive_time_fp, + tu.delay_start_time_fp); + if (compare_result_2 == 2) + tu.min_hblank_violated = 1; + + tu.delay_start_time_fp = 0; + + /* brute force */ + + tu.delay_start_link_extra_pixclk = EXTRA_PIXCLK_CYCLE_DELAY; + tu.diff_abs_fp = tu.resulting_valid_fp - tu.ratio_by_tu_fp; + + temp = drm_fixp2int(tu.diff_abs_fp); + if (!temp && tu.diff_abs_fp <= 0xffff) + tu.diff_abs_fp = 0; + + /* if(diff_abs < 0) diff_abs *= -1 */ + if (tu.diff_abs_fp < 0) + tu.diff_abs_fp = drm_fixp_mul(tu.diff_abs_fp, -1); + + tu.boundary_mod_lower_err = 0; + if ((tu.diff_abs_fp != 0 && + ((tu.diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) || + (tu.even_distribution_legacy == 0) || + (DP_BRUTE_FORCE == 1))) || + (tu.min_hblank_violated == 1)) { + + _dp_calc_boundary(&tu); + + if (tu.boundary_moderation_en) { + temp1_fp = drm_fixp_from_fraction( + (tu.upper_boundary_count * + tu.valid_boundary_link + + tu.lower_boundary_count * + (tu.valid_boundary_link - 1)), 1); + temp2_fp = drm_fixp_from_fraction( + (tu.upper_boundary_count + + tu.lower_boundary_count), 1); + tu.resulting_valid_fp = + drm_fixp_div(temp1_fp, temp2_fp); + + temp1_fp = drm_fixp_from_fraction( + tu.tu_size_desired, 1); + tu.ratio_by_tu_fp = + drm_fixp_mul(tu.original_ratio_fp, temp1_fp); + + tu.valid_lower_boundary_link = + tu.valid_boundary_link - 1; + + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp1_fp = drm_fixp_mul(tu.lwidth_fp, temp1_fp); + temp2_fp = drm_fixp_div(temp1_fp, + tu.resulting_valid_fp); + tu.n_tus = drm_fixp2int(temp2_fp); + + tu.tu_size_minus1 = tu.tu_size_desired - 1; + tu.even_distribution_BF = 1; + + temp1_fp = + drm_fixp_from_fraction(tu.tu_size_desired, 1); + temp2_fp = + drm_fixp_div(tu.resulting_valid_fp, temp1_fp); + tu.TU_ratio_err_fp = temp2_fp - tu.original_ratio_fp; + } + } + + temp2_fp = drm_fixp_mul(LCLK_FAST_SKEW_fp, tu.lwidth_fp); + + if (temp2_fp) + temp = drm_fixp2int_ceil(temp2_fp); + else + temp = 0; + + temp1_fp = drm_fixp_from_fraction(tu.nlanes, 1); + temp2_fp = drm_fixp_mul(tu.original_ratio_fp, temp1_fp); + temp1_fp = drm_fixp_from_fraction(tu.bpp, 8); + temp2_fp = drm_fixp_div(temp1_fp, temp2_fp); + temp1_fp = drm_fixp_from_fraction(temp, 1); + temp2_fp = drm_fixp_mul(temp1_fp, temp2_fp); + temp = drm_fixp2int(temp2_fp); + + if (tu.async_en) + tu.delay_start_link += (int)temp; + + temp1_fp = drm_fixp_from_fraction(tu.delay_start_link, 1); + tu.delay_start_time_fp = drm_fixp_div(temp1_fp, tu.lclk_fp); + + /* OUTPUTS */ + tu_table->valid_boundary_link = tu.valid_boundary_link; + tu_table->delay_start_link = tu.delay_start_link; + tu_table->boundary_moderation_en = tu.boundary_moderation_en; + tu_table->valid_lower_boundary_link = tu.valid_lower_boundary_link; + tu_table->upper_boundary_count = tu.upper_boundary_count; + tu_table->lower_boundary_count = tu.lower_boundary_count; + tu_table->tu_size_minus1 = tu.tu_size_minus1; + + DP_INFO("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link); + DP_INFO("TU: delay_start_link: %d\n", tu_table->delay_start_link); + DP_INFO("TU: boundary_moderation_en: %d\n", + tu_table->boundary_moderation_en); + DP_INFO("TU: valid_lower_boundary_link: %d\n", + tu_table->valid_lower_boundary_link); + DP_INFO("TU: upper_boundary_count: %d\n", + tu_table->upper_boundary_count); + DP_INFO("TU: lower_boundary_count: %d\n", + tu_table->lower_boundary_count); + DP_INFO("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1); +} + +static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel, + struct dp_vc_tu_mapping_table *tu_table) +{ + struct dp_tu_calc_input in; + struct dp_panel_info *pinfo; + struct dp_panel_private *panel; + int bw_code; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + pinfo = &dp_panel->pinfo; + bw_code = panel->link->link_params.bw_code; + + in.lclk = drm_dp_bw_code_to_link_rate(bw_code) / 1000; + in.pclk_khz = pinfo->pixel_clk_khz; + in.hactive = pinfo->h_active; + in.hporch = pinfo->h_back_porch + pinfo->h_front_porch + + pinfo->h_sync_width; + in.nlanes = panel->link->link_params.lane_count; + in.bpp = pinfo->bpp; + in.pixel_enc = 444; + in.dsc_en = dp_panel->dsc_en; + in.async_en = 0; + in.fec_en = dp_panel->fec_en; + in.num_of_dsc_slices = pinfo->comp_info.dsc_info.slice_per_pkt; + + switch (pinfo->comp_info.comp_ratio) { + case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: + in.compress_ratio = 200; + break; + case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: + in.compress_ratio = 300; + break; + default: + in.compress_ratio = 100; + } + + _dp_panel_calc_tu(&in, tu_table); +} + +void dp_panel_calc_tu_test(struct dp_tu_calc_input *in, + struct dp_vc_tu_mapping_table *tu_table) +{ + _dp_panel_calc_tu(in, tu_table); +} + +static void dp_panel_config_tr_unit(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct dp_catalog_panel *catalog; + u32 dp_tu = 0x0; + u32 valid_boundary = 0x0; + u32 valid_boundary2 = 0x0; + struct dp_vc_tu_mapping_table tu_calc_table; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return; + } + + if (dp_panel->stream_id != DP_STREAM_0) + return; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + + dp_panel_calc_tu_parameters(dp_panel, &tu_calc_table); + + dp_tu |= tu_calc_table.tu_size_minus1; + valid_boundary |= tu_calc_table.valid_boundary_link; + valid_boundary |= (tu_calc_table.delay_start_link << 16); + + valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1); + valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16); + valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20); + + if (tu_calc_table.boundary_moderation_en) + valid_boundary2 |= BIT(0); + + DP_DEBUG("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n", + dp_tu, valid_boundary, valid_boundary2); + + catalog->dp_tu = dp_tu; + catalog->valid_boundary = valid_boundary; + catalog->valid_boundary2 = valid_boundary2; + + catalog->update_transfer_unit(catalog); +} + +enum dp_dsc_ratio_type { + DSC_8BPC_8BPP, + DSC_10BPC_8BPP, + DSC_12BPC_8BPP, + DSC_10BPC_10BPP, + DSC_RATIO_TYPE_MAX +}; + +static u32 dp_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, + 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e}; + +/* + * DSC 1.1 + * Rate control - Min QP values for each ratio type in dp_dsc_ratio_type + */ +static char dp_dsc_rc_range_min_qp_1_1[][15] = { + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 13}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, + {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + }; + +/* + * DSC 1.1 SCR + * Rate control - Min QP values for each ratio type in dp_dsc_ratio_type + */ +static char dp_dsc_rc_range_min_qp_1_1_scr1[][15] = { + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, + {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + }; + +/* + * DSC 1.1 + * Rate control - Max QP values for each ratio type in dp_dsc_ratio_type + */ +static char dp_dsc_rc_range_max_qp_1_1[][15] = { + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, + {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, + {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + }; + +/* + * DSC 1.1 SCR + * Rate control - Max QP values for each ratio type in dp_dsc_ratio_type + */ +static char dp_dsc_rc_range_max_qp_1_1_scr1[][15] = { + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, + {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, + {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 21}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + }; + +/* + * DSC 1.1 and DSC 1.1 SCR + * Rate control - bpg offset values + */ +static char dp_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8, + -8, -10, -10, -12, -12, -12, -12}; + +struct dp_dsc_dto_data { + enum msm_display_compression_ratio comp_ratio; + u32 org_bpp; /* bits */ + u32 dto_numerator; + u32 dto_denominator; +}; + +struct dp_dsc_dto_data dto_tbl[] = { + {MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 24, 1, 2}, + {MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, 30, 5, 8}, + {MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 24, 1, 3}, + {MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, 30, 5, 12}, +}; + +static void _dp_panel_get_dto_m_n(enum msm_display_compression_ratio ratio, + u32 org_bpp, u32 *dto_n, u32 *dto_d) +{ + u32 idx; + + for (idx = 0; idx < ARRAY_SIZE(dto_tbl); idx++) { + if (ratio == dto_tbl[idx].comp_ratio && + org_bpp == dto_tbl[idx].org_bpp) { + *dto_n = dto_tbl[idx].dto_numerator; + *dto_d = dto_tbl[idx].dto_denominator; + return; + } + } +} + +static int dp_panel_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, + char *buf, int pps_id) +{ + char *bp = buf; + char data; + int i, bpp; + + *bp++ = (dsc->version & 0xff); /* pps0 */ + *bp++ = (pps_id & 0xff); /* pps1 */ + bp++; /* pps2, reserved */ + + data = dsc->line_buf_depth & 0x0f; + data |= ((dsc->bpc & 0xf) << 4); + *bp++ = data; /* pps3 */ + + bpp = dsc->bpp; + bpp <<= 4; /* 4 fraction bits */ + data = (bpp >> 8); + data &= 0x03; /* upper two bits */ + data |= ((dsc->block_pred_enable & 0x1) << 5); + data |= ((dsc->convert_rgb & 0x1) << 4); + data |= ((dsc->enable_422 & 0x1) << 3); + data |= ((dsc->vbr_enable & 0x1) << 2); + *bp++ = data; /* pps4 */ + *bp++ = (bpp & 0xff); /* pps5 */ + + *bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */ + *bp++ = (dsc->pic_height & 0x0ff); /* pps7 */ + *bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */ + *bp++ = (dsc->pic_width & 0x0ff); /* pps9 */ + + *bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */ + *bp++ = (dsc->slice_height & 0x0ff); /* pps11 */ + *bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */ + *bp++ = (dsc->slice_width & 0x0ff); /* pps13 */ + + *bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */ + *bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */ + + *bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16*/ + *bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */ + + *bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */ + *bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */ + + bp++; /* pps20, reserved */ + + *bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */ + + *bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */ + *bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */ + + *bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */ + *bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */ + + bp++; /* pps26, reserved */ + + *bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */ + + *bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */ + *bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */ + *bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */ + *bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */ + + *bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */ + *bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */ + + *bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */ + *bp++ = (dsc->final_offset & 0x0ff); /* pps35 */ + + *bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */ + *bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */ + + *bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */ + *bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */ + + *bp++ = (dsc->edge_factor & 0x0f); /* pps40 */ + + *bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */ + *bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */ + + data = ((dsc->tgt_offset_hi & 0xf) << 4); + data |= (dsc->tgt_offset_lo & 0x0f); + *bp++ = data; /* pps43 */ + + for (i = 0; i < ARRAY_SIZE(dp_dsc_rc_buf_thresh); i++) + *bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */ + + for (i = 0; i < 15; i++) { /* pps58 - pps87 */ + data = (dsc->range_min_qp[i] & 0x1f); + data <<= 3; + data |= ((dsc->range_max_qp[i] >> 2) & 0x07); + *bp++ = data; + data = (dsc->range_max_qp[i] & 0x03); + data <<= 6; + data |= (dsc->range_bpg_offset[i] & 0x3f); + *bp++ = data; + } + + return 88; +} + +static void dp_panel_dsc_prepare_pps_packet(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct dp_dsc_cfg_data *dsc; + u8 *pps, *parity; + u32 *pps_word, *parity_word; + int i, index_4; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + dsc = &panel->catalog->dsc; + pps = dsc->pps; + pps_word = dsc->pps_word; + parity = dsc->parity; + parity_word = dsc->parity_word; + + memset(parity, 0, sizeof(dsc->parity)); + + dsc->pps_word_len = dsc->pps_len >> 2; + dsc->parity_len = dsc->pps_word_len; + dsc->parity_word_len = (dsc->parity_len >> 2) + 1; + + for (i = 0; i < dsc->pps_word_len; i++) { + index_4 = i << 2; + pps_word[i] = pps[index_4 + 0] << 0 | + pps[index_4 + 1] << 8 | + pps[index_4 + 2] << 16 | + pps[index_4 + 3] << 24; + + parity[i] = dp_header_get_parity(pps_word[i]); + } + + for (i = 0; i < dsc->parity_word_len; i++) { + index_4 = i << 2; + parity_word[i] = parity[index_4 + 0] << 0 | + parity[index_4 + 1] << 8 | + parity[index_4 + 2] << 16 | + parity[index_4 + 3] << 24; + } +} + +static void _dp_panel_dsc_get_num_extra_pclk(struct msm_display_dsc_info *dsc, + enum msm_display_compression_ratio ratio) +{ + unsigned int dto_n = 0, dto_d = 0, remainder; + int ack_required, last_few_ack_required, accum_ack; + int last_few_pclk, last_few_pclk_required; + int start, temp, line_width = dsc->pic_width/2; + s64 temp1_fp, temp2_fp; + + _dp_panel_get_dto_m_n(ratio, dsc->bpc * 3, &dto_n, &dto_d); + + ack_required = dsc->pclk_per_line; + + /* number of pclk cycles left outside of the complete DTO set */ + last_few_pclk = line_width % dto_d; + + /* number of pclk cycles outside of the complete dto */ + temp1_fp = drm_fixp_from_fraction(line_width, dto_d); + temp2_fp = drm_fixp_from_fraction(dto_n, 1); + temp1_fp = drm_fixp_mul(temp1_fp, temp2_fp); + temp = drm_fixp2int(temp1_fp); + last_few_ack_required = ack_required - temp; + + /* + * check how many more pclk is needed to + * accommodate the last few ack required + */ + remainder = dto_n; + accum_ack = 0; + last_few_pclk_required = 0; + while (accum_ack < last_few_ack_required) { + last_few_pclk_required++; + + if (remainder >= dto_n) + start = remainder; + else + start = remainder + dto_d; + + remainder = start - dto_n; + if (remainder < dto_n) + accum_ack++; + } + + /* if fewer pclk than required */ + if (last_few_pclk < last_few_pclk_required) + dsc->extra_width = last_few_pclk_required - last_few_pclk; + else + dsc->extra_width = 0; + + DP_DEBUG("extra pclks required: %d\n", dsc->extra_width); +} + +static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel, + struct msm_display_dsc_info *dsc, + struct dp_display_mode *dp_mode, u32 dsc_byte_cnt) +{ + int num_slices, tot_num_eoc_symbols; + int tot_num_hor_bytes, tot_num_dummy_bytes; + int dwidth_dsc_bytes, eoc_bytes; + u32 num_lanes; + + num_lanes = dp_panel->link_info.num_lanes; + num_slices = dsc->slice_per_pkt; + + eoc_bytes = dsc_byte_cnt % num_lanes; + tot_num_eoc_symbols = num_lanes * num_slices; + tot_num_hor_bytes = dsc_byte_cnt * num_slices; + tot_num_dummy_bytes = (num_lanes - eoc_bytes) * num_slices; + + if (!eoc_bytes) + tot_num_dummy_bytes = 0; + + dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols + + tot_num_dummy_bytes; + + DP_DEBUG("dwidth_dsc_bytes:%d, tot_num_hor_bytes:%d\n", + dwidth_dsc_bytes, tot_num_hor_bytes); + + dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes, + tot_num_hor_bytes); + dp_mode->timing.dsc_overhead_fp = dp_mode->dsc_overhead_fp; +} + +static void dp_panel_dsc_pclk_param_calc(struct dp_panel *dp_panel, + struct msm_display_dsc_info *dsc, + enum msm_display_compression_ratio ratio, + struct dp_display_mode *dp_mode) +{ + int slice_per_pkt, slice_per_intf, intf_width; + int bytes_in_slice, total_bytes_per_intf; + int comp_ratio; + s64 temp1_fp, temp2_fp; + s64 numerator_fp, denominator_fp; + s64 dsc_byte_count_fp; + u32 dsc_byte_count, temp1, temp2; + + intf_width = dp_mode->timing.h_active; + if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || + (intf_width < dsc->slice_width)) + return; + + slice_per_pkt = dsc->slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); + + if (slice_per_pkt > slice_per_intf) + slice_per_pkt = 1; + + bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + dsc->bytes_in_slice = bytes_in_slice; + dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; + dsc->pkt_per_line = slice_per_intf / slice_per_pkt; + + switch (ratio) { + case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: + comp_ratio = 200; + break; + case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: + comp_ratio = 300; + break; + default: + comp_ratio = 100; + break; + } + + temp1_fp = drm_fixp_from_fraction(comp_ratio, 100); + temp2_fp = drm_fixp_from_fraction(slice_per_pkt * 8, 1); + denominator_fp = drm_fixp_mul(temp1_fp, temp2_fp); + numerator_fp = drm_fixp_from_fraction(intf_width * dsc->bpc * 3, 1); + dsc_byte_count_fp = drm_fixp_div(numerator_fp, denominator_fp); + dsc_byte_count = drm_fixp2int_ceil(dsc_byte_count_fp); + + temp1 = dsc_byte_count * slice_per_intf; + temp2 = temp1; + if (temp1 % 3 != 0) + temp1 += 3 - (temp1 % 3); + + dsc->eol_byte_num = temp1 - temp2; + + temp1_fp = drm_fixp_from_fraction(slice_per_intf, 6); + temp2_fp = drm_fixp_mul(dsc_byte_count_fp, temp1_fp); + dsc->pclk_per_line = drm_fixp2int_ceil(temp2_fp); + + _dp_panel_dsc_get_num_extra_pclk(dsc, ratio); + dsc->pclk_per_line--; + + _dp_panel_dsc_bw_overhead_calc(dp_panel, dsc, dp_mode, dsc_byte_count); +} + +static void dp_panel_dsc_populate_static_params( + struct msm_display_dsc_info *dsc, struct dp_panel *panel) +{ + int bpp, bpc; + int mux_words_size; + int groups_per_line, groups_total; + int min_rate_buffer_size; + int hrd_delay; + int pre_num_extra_mux_bits, num_extra_mux_bits; + int slice_bits; + int data; + int final_value, final_scale; + int ratio_index, mod_offset; + int line_buf_depth_raw, line_buf_depth; + + dsc->version = 0x11; + dsc->scr_rev = 0; + dsc->rc_model_size = 8192; + + if (dsc->version == 0x11 && dsc->scr_rev == 0x1) + dsc->first_line_bpg_offset = 15; + else + dsc->first_line_bpg_offset = 12; + + dsc->edge_factor = 6; + dsc->tgt_offset_hi = 3; + dsc->tgt_offset_lo = 3; + dsc->enable_422 = 0; + dsc->convert_rgb = 1; + dsc->vbr_enable = 0; + + dsc->buf_thresh = dp_dsc_rc_buf_thresh; + + bpp = dsc->bpp; + bpc = dsc->bpc; + + if (bpc == 12 && bpp == 8) + ratio_index = DSC_12BPC_8BPP; + else if (bpc == 10 && bpp == 8) + ratio_index = DSC_10BPC_8BPP; + else if (bpc == 10 && bpp == 10) + ratio_index = DSC_10BPC_10BPP; + else + ratio_index = DSC_8BPC_8BPP; + + if (dsc->version == 0x11 && dsc->scr_rev == 0x1) { + dsc->range_min_qp = + dp_dsc_rc_range_min_qp_1_1_scr1[ratio_index]; + dsc->range_max_qp = + dp_dsc_rc_range_max_qp_1_1_scr1[ratio_index]; + } else { + dsc->range_min_qp = dp_dsc_rc_range_min_qp_1_1[ratio_index]; + dsc->range_max_qp = dp_dsc_rc_range_max_qp_1_1[ratio_index]; + } + dsc->range_bpg_offset = dp_dsc_rc_range_bpg_offset; + + if (bpp == 8) { + dsc->initial_offset = 6144; + dsc->initial_xmit_delay = 512; + } else if (bpp == 10) { + dsc->initial_offset = 5632; + dsc->initial_xmit_delay = 410; + } else { + dsc->initial_offset = 2048; + dsc->initial_xmit_delay = 341; + } + + line_buf_depth_raw = panel->dsc_dpcd[5] & 0x0f; + line_buf_depth = (line_buf_depth_raw == 8) ? 8 : + (line_buf_depth_raw + 9); + dsc->line_buf_depth = min(line_buf_depth, dsc->bpc + 1); + + if (bpc == 8) { + dsc->input_10_bits = 0; + dsc->min_qp_flatness = 3; + dsc->max_qp_flatness = 12; + dsc->quant_incr_limit0 = 11; + dsc->quant_incr_limit1 = 11; + mux_words_size = 48; + } else if (bpc == 10) { /* 10bpc */ + dsc->input_10_bits = 1; + dsc->min_qp_flatness = 7; + dsc->max_qp_flatness = 16; + dsc->quant_incr_limit0 = 15; + dsc->quant_incr_limit1 = 15; + mux_words_size = 48; + } else { /* 12 bpc */ + dsc->input_10_bits = 0; + dsc->min_qp_flatness = 11; + dsc->max_qp_flatness = 20; + dsc->quant_incr_limit0 = 19; + dsc->quant_incr_limit1 = 19; + mux_words_size = 64; + } + + mod_offset = dsc->slice_width % 3; + switch (mod_offset) { + case 0: + dsc->slice_last_group_size = 2; + break; + case 1: + dsc->slice_last_group_size = 0; + break; + case 2: + dsc->slice_last_group_size = 1; + break; + default: + break; + } + + dsc->det_thresh_flatness = 2 << (bpc - 8); + + groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); + + dsc->chunk_size = dsc->slice_width * bpp / 8; + if ((dsc->slice_width * bpp) % 8) + dsc->chunk_size++; + + /* rbs-min */ + min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + + dsc->initial_xmit_delay * bpp + + groups_per_line * dsc->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); + + dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; + + dsc->initial_scale_value = 8 * dsc->rc_model_size / + (dsc->rc_model_size - dsc->initial_offset); + + slice_bits = 8 * dsc->chunk_size * dsc->slice_height; + + groups_total = groups_per_line * dsc->slice_height; + + data = dsc->first_line_bpg_offset * 2048; + + dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); + + pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2); + + num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - + ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); + + data = 2048 * (dsc->rc_model_size - dsc->initial_offset + + num_extra_mux_bits); + dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); + + data = dsc->initial_xmit_delay * bpp; + final_value = dsc->rc_model_size - data + num_extra_mux_bits; + + final_scale = 8 * dsc->rc_model_size / + (dsc->rc_model_size - final_value); + + dsc->final_offset = final_value; + + data = (final_scale - 9) * (dsc->nfl_bpg_offset + + dsc->slice_bpg_offset); + dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; + + dsc->scale_decrement_interval = groups_per_line / + (dsc->initial_scale_value - 8); +} + +struct dp_dsc_slices_per_line { + u32 min_ppr; + u32 max_ppr; + u8 num_slices; +}; + +struct dp_dsc_peak_throughput { + u32 index; + u32 peak_throughput; +}; + +struct dp_dsc_slice_caps_bit_map { + u32 num_slices; + u32 bit_index; +}; + +const struct dp_dsc_slices_per_line slice_per_line_tbl[] = { + {0, 340, 1 }, + {340, 680, 2 }, + {680, 1360, 4 }, + {1360, 3200, 8 }, + {3200, 4800, 12 }, + {4800, 6400, 16 }, + {6400, 8000, 20 }, + {8000, 9600, 24 } +}; + +const struct dp_dsc_peak_throughput peak_throughput_mode_0_tbl[] = { + {0, 0}, + {1, 340}, + {2, 400}, + {3, 450}, + {4, 500}, + {5, 550}, + {6, 600}, + {7, 650}, + {8, 700}, + {9, 750}, + {10, 800}, + {11, 850}, + {12, 900}, + {13, 950}, + {14, 1000}, +}; + +const struct dp_dsc_slice_caps_bit_map slice_caps_bit_map_tbl[] = { + {1, 0}, + {2, 1}, + {4, 3}, + {6, 4}, + {8, 5}, + {10, 6}, + {12, 7}, + {16, 0}, + {20, 1}, + {24, 2}, +}; + +static bool dp_panel_check_slice_support(u32 num_slices, u32 raw_data_1, + u32 raw_data_2) +{ + const struct dp_dsc_slice_caps_bit_map *bcap; + u32 raw_data; + int i; + + if (num_slices <= 12) + raw_data = raw_data_1; + else + raw_data = raw_data_2; + + for (i = 0; i < ARRAY_SIZE(slice_caps_bit_map_tbl); i++) { + bcap = &slice_caps_bit_map_tbl[i]; + + if (bcap->num_slices == num_slices) { + raw_data &= (1 << bcap->bit_index); + + if (raw_data) + return true; + else + return false; + } + } + + return false; +} + +static int dp_panel_dsc_prepare_basic_params( + struct msm_compression_info *comp_info, + const struct dp_display_mode *dp_mode, + struct dp_panel *dp_panel) +{ + int i; + const struct dp_dsc_slices_per_line *rec; + const struct dp_dsc_peak_throughput *tput; + u32 slice_width; + u32 ppr = dp_mode->timing.pixel_clk_khz/1000; + u32 max_slice_width; + u32 ppr_max_index; + u32 peak_throughput; + u32 ppr_per_slice; + u32 slice_caps_1; + u32 slice_caps_2; + + comp_info->dsc_info.slice_per_pkt = 0; + for (i = 0; i < ARRAY_SIZE(slice_per_line_tbl); i++) { + rec = &slice_per_line_tbl[i]; + if ((ppr > rec->min_ppr) && (ppr <= rec->max_ppr)) { + comp_info->dsc_info.slice_per_pkt = rec->num_slices; + i++; + break; + } + } + + if (comp_info->dsc_info.slice_per_pkt == 0) + return -EINVAL; + + ppr_max_index = dp_panel->dsc_dpcd[11] &= 0xf; + if (!ppr_max_index || ppr_max_index >= 15) { + DP_DEBUG("Throughput mode 0 not supported"); + return -EINVAL; + } + + tput = &peak_throughput_mode_0_tbl[ppr_max_index]; + peak_throughput = tput->peak_throughput; + + max_slice_width = dp_panel->dsc_dpcd[12] * 320; + slice_width = (dp_mode->timing.h_active / + comp_info->dsc_info.slice_per_pkt); + + ppr_per_slice = ppr/comp_info->dsc_info.slice_per_pkt; + + slice_caps_1 = dp_panel->dsc_dpcd[4]; + slice_caps_2 = dp_panel->dsc_dpcd[13] & 0x7; + + /* + * There are 3 conditions to check for sink support: + * 1. The slice width cannot exceed the maximum. + * 2. The ppr per slice cannot exceed the maximum. + * 3. The number of slices must be explicitly supported. + */ + while (slice_width >= max_slice_width || + ppr_per_slice > peak_throughput || + !dp_panel_check_slice_support( + comp_info->dsc_info.slice_per_pkt, slice_caps_1, + slice_caps_2)) { + if (i == ARRAY_SIZE(slice_per_line_tbl)) + return -EINVAL; + + rec = &slice_per_line_tbl[i]; + comp_info->dsc_info.slice_per_pkt = rec->num_slices; + slice_width = (dp_mode->timing.h_active / + comp_info->dsc_info.slice_per_pkt); + ppr_per_slice = ppr/comp_info->dsc_info.slice_per_pkt; + i++; + } + + comp_info->dsc_info.block_pred_enable = + dp_panel->sink_dsc_caps.block_pred_en; + comp_info->dsc_info.vbr_enable = 0; + comp_info->dsc_info.enable_422 = 0; + comp_info->dsc_info.convert_rgb = 1; + comp_info->dsc_info.input_10_bits = 0; + + comp_info->dsc_info.pic_width = dp_mode->timing.h_active; + comp_info->dsc_info.pic_height = dp_mode->timing.v_active; + comp_info->dsc_info.slice_width = slice_width; + + if (comp_info->dsc_info.pic_height % 16 == 0) + comp_info->dsc_info.slice_height = 16; + else if (comp_info->dsc_info.pic_height % 12 == 0) + comp_info->dsc_info.slice_height = 12; + else + comp_info->dsc_info.slice_height = 15; + + comp_info->dsc_info.bpc = dp_mode->timing.bpp / 3; + comp_info->dsc_info.bpp = comp_info->dsc_info.bpc; + comp_info->dsc_info.full_frame_slices = + DIV_ROUND_UP(dp_mode->timing.h_active, slice_width); + + comp_info->comp_type = MSM_DISPLAY_COMPRESSION_DSC; + comp_info->comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1; + return 0; +} + +static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func) +{ + int rlen, rc = 0; + struct dp_panel_private *panel; + struct drm_dp_link *link_info; + struct drm_dp_aux *drm_aux; + u8 *dpcd, rx_feature, temp; + u32 dfp_count = 0, offset = DP_DPCD_REV; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + dpcd = dp_panel->dpcd; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + drm_aux = panel->aux->drm_aux; + link_info = &dp_panel->link_info; + + /* reset vsc data */ + panel->vsc_supported = false; + panel->vscext_supported = false; + panel->vscext_chaining_supported = false; + + if (panel->custom_dpcd) { + DP_DEBUG("skip dpcd read in debug mode\n"); + goto skip_dpcd_read; + } + + rlen = drm_dp_dpcd_read(drm_aux, DP_TRAINING_AUX_RD_INTERVAL, &temp, 1); + if (rlen != 1) { + DP_ERR("error reading DP_TRAINING_AUX_RD_INTERVAL\n"); + rc = -EINVAL; + goto end; + } + + /* check for EXTENDED_RECEIVER_CAPABILITY_FIELD_PRESENT */ + if (temp & BIT(7)) { + DP_DEBUG("using EXTENDED_RECEIVER_CAPABILITY_FIELD\n"); + offset = DPRX_EXTENDED_DPCD_FIELD; + } + + rlen = drm_dp_dpcd_read(drm_aux, offset, + dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1)); + if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { + DP_ERR("dpcd read failed, rlen=%d\n", rlen); + if (rlen == -ETIMEDOUT) + rc = rlen; + else + rc = -EINVAL; + + goto end; + } + + print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ", + DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false); + + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, + DPRX_FEATURE_ENUMERATION_LIST, &rx_feature, 1); + if (rlen != 1) { + DP_DEBUG("failed to read DPRX_FEATURE_ENUMERATION_LIST\n"); + rx_feature = 0; + } + +skip_dpcd_read: + if (panel->custom_dpcd) + rx_feature = dp_panel->dpcd[DP_RECEIVER_CAP_SIZE + 1]; + + panel->vsc_supported = !!(rx_feature & + VSC_SDP_EXTENSION_FOR_COLORIMETRY_SUPPORTED); + panel->vscext_supported = !!(rx_feature & VSC_EXT_VESA_SDP_SUPPORTED); + panel->vscext_chaining_supported = !!(rx_feature & + VSC_EXT_VESA_SDP_CHAINING_SUPPORTED); + + DP_DEBUG("vsc=%d, vscext=%d, vscext_chaining=%d\n", + panel->vsc_supported, panel->vscext_supported, + panel->vscext_chaining_supported); + + link_info->revision = dpcd[DP_DPCD_REV]; + panel->major = (link_info->revision >> 4) & 0x0f; + panel->minor = link_info->revision & 0x0f; + + /* override link params updated in dp_panel_init_panel_info */ + link_info->rate = min_t(unsigned long, panel->parser->max_lclk_khz, + drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE])); + + link_info->num_lanes = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; + + if (multi_func) + link_info->num_lanes = min_t(unsigned int, + link_info->num_lanes, 2); + + DP_DEBUG("version:%d.%d, rate:%d, lanes:%d\n", panel->major, + panel->minor, link_info->rate, link_info->num_lanes); + + if (drm_dp_enhanced_frame_cap(dpcd)) + link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING; + + dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & + DP_DOWN_STREAM_PORT_COUNT; + + if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) + && (dpcd[DP_DPCD_REV] > 0x10)) { + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, + DP_DOWNSTREAM_PORT_0, dp_panel->ds_ports, + DP_MAX_DOWNSTREAM_PORTS); + if (rlen < DP_MAX_DOWNSTREAM_PORTS) { + DP_ERR("ds port status failed, rlen=%d\n", rlen); + rc = -EINVAL; + goto end; + } + } + + if (dfp_count > DP_MAX_DS_PORT_COUNT) + DP_DEBUG("DS port count %d greater that max (%d) supported\n", + dfp_count, DP_MAX_DS_PORT_COUNT); + +end: + return rc; +} + +static int dp_panel_set_default_link_params(struct dp_panel *dp_panel) +{ + struct drm_dp_link *link_info; + const int default_bw_code = 162000; + const int default_num_lanes = 1; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + link_info = &dp_panel->link_info; + link_info->rate = default_bw_code; + link_info->num_lanes = default_num_lanes; + DP_DEBUG("link_rate=%d num_lanes=%d\n", + link_info->rate, link_info->num_lanes); + + return 0; +} + +static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (edid) { + dp_panel->edid_ctrl->edid = (struct edid *)edid; + panel->custom_edid = true; + } else { + panel->custom_edid = false; + dp_panel->edid_ctrl->edid = NULL; + } + + DP_DEBUG("%d\n", panel->custom_edid); + return 0; +} + +static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd) +{ + struct dp_panel_private *panel; + u8 *dp_dpcd; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + dp_dpcd = dp_panel->dpcd; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dpcd) { + memcpy(dp_dpcd, dpcd, DP_RECEIVER_CAP_SIZE + + DP_RECEIVER_EXT_CAP_SIZE + 1); + panel->custom_dpcd = true; + } else { + panel->custom_dpcd = false; + } + + DP_DEBUG("%d\n", panel->custom_dpcd); + + return 0; +} + +static int dp_panel_read_edid(struct dp_panel *dp_panel, + struct drm_connector *connector) +{ + int ret = 0; + struct dp_panel_private *panel; + struct edid *edid; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (panel->custom_edid) { + DP_DEBUG("skip edid read in debug mode\n"); + goto end; + } + + sde_get_edid(connector, &panel->aux->drm_aux->ddc, + (void **)&dp_panel->edid_ctrl); + if (!dp_panel->edid_ctrl->edid) { + DP_ERR("EDID read failed\n"); + ret = -EINVAL; + goto end; + } +end: + edid = dp_panel->edid_ctrl->edid; + dp_panel->audio_supported = drm_detect_monitor_audio(edid); + + return ret; +} + +static void dp_panel_decode_dsc_dpcd(struct dp_panel *dp_panel) +{ + if (dp_panel->dsc_dpcd[0]) { + dp_panel->sink_dsc_caps.dsc_capable = true; + dp_panel->sink_dsc_caps.version = dp_panel->dsc_dpcd[1]; + dp_panel->sink_dsc_caps.block_pred_en = + dp_panel->dsc_dpcd[6] ? true : false; + dp_panel->sink_dsc_caps.color_depth = + dp_panel->dsc_dpcd[10]; + + if (dp_panel->sink_dsc_caps.version >= 0x11) + dp_panel->dsc_en = true; + } else { + dp_panel->sink_dsc_caps.dsc_capable = false; + dp_panel->dsc_en = false; + } + + dp_panel->widebus_en = dp_panel->dsc_en; +} + +static void dp_panel_read_sink_dsc_caps(struct dp_panel *dp_panel) +{ + int rlen; + struct dp_panel_private *panel; + int dpcd_rev; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return; + } + + dpcd_rev = dp_panel->dpcd[DP_DPCD_REV]; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + if (panel->parser->dsc_feature_enable && dpcd_rev >= 0x14) { + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DSC_SUPPORT, + dp_panel->dsc_dpcd, (DP_RECEIVER_DSC_CAP_SIZE + 1)); + if (rlen < (DP_RECEIVER_DSC_CAP_SIZE + 1)) { + DP_DEBUG("dsc dpcd read failed, rlen=%d\n", rlen); + return; + } + + print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DSC DPCD: ", + DUMP_PREFIX_NONE, 8, 1, dp_panel->dsc_dpcd, rlen, + false); + + dp_panel_decode_dsc_dpcd(dp_panel); + } +} + +static void dp_panel_read_sink_fec_caps(struct dp_panel *dp_panel) +{ + int rlen; + struct dp_panel_private *panel; + s64 fec_overhead_fp = drm_fixp_from_fraction(1, 1); + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + rlen = drm_dp_dpcd_readb(panel->aux->drm_aux, DP_FEC_CAPABILITY, + &dp_panel->fec_dpcd); + if (rlen < 1) { + DP_ERR("fec capability read failed, rlen=%d\n", rlen); + return; + } + + dp_panel->fec_en = dp_panel->fec_dpcd & DP_FEC_CAPABLE; + if (dp_panel->fec_en) + fec_overhead_fp = drm_fixp_from_fraction(100000, 97582); + + dp_panel->fec_overhead_fp = fec_overhead_fp; + + return; +} + +static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, + struct drm_connector *connector, bool multi_func) +{ + int rc = 0, rlen, count, downstream_ports; + const int count_len = 1; + struct dp_panel_private *panel; + + if (!dp_panel || !connector) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + rc = dp_panel_read_dpcd(dp_panel, multi_func); + if (rc || !is_link_rate_valid(drm_dp_link_rate_to_bw_code( + dp_panel->link_info.rate)) || !is_lane_count_valid( + dp_panel->link_info.num_lanes) || + ((drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate)) > + dp_panel->max_bw_code)) { + if ((rc == -ETIMEDOUT) || (rc == -ENODEV)) { + DP_ERR("DPCD read failed, return early\n"); + goto end; + } + DP_ERR("panel dpcd read failed/incorrect, set default params\n"); + dp_panel_set_default_link_params(dp_panel); + } + + downstream_ports = dp_panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & + DP_DWN_STRM_PORT_PRESENT; + + if (downstream_ports) { + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT, + &count, count_len); + if (rlen == count_len) { + count = DP_GET_SINK_COUNT(count); + if (!count) { + DP_ERR("no downstream ports connected\n"); + panel->link->sink_count.count = 0; + rc = -ENOTCONN; + goto end; + } + } + } + + rc = dp_panel_read_edid(dp_panel, connector); + if (rc) { + DP_ERR("panel edid read failed, set failsafe mode\n"); + return rc; + } + + dp_panel->widebus_en = panel->parser->has_widebus; + dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable; + dp_panel->fec_feature_enable = panel->parser->fec_feature_enable; + + dp_panel->fec_en = false; + dp_panel->dsc_en = false; + + if (dp_panel->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && + dp_panel->fec_feature_enable) { + dp_panel_read_sink_fec_caps(dp_panel); + + if (dp_panel->dsc_feature_enable && dp_panel->fec_en) + dp_panel_read_sink_dsc_caps(dp_panel); + } + + DP_INFO("fec_en=%d, dsc_en=%d, widebus_en=%d\n", dp_panel->fec_en, + dp_panel->dsc_en, dp_panel->widebus_en); +end: + return rc; +} + +static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel, + u32 mode_edid_bpp, u32 mode_pclk_khz) +{ + struct drm_dp_link *link_info; + const u32 max_supported_bpp = 30; + u32 min_supported_bpp = 18; + u32 bpp = 0, data_rate_khz = 0, tmds_max_clock = 0; + + if (dp_panel->dsc_en) + min_supported_bpp = 24; + + bpp = min_t(u32, mode_edid_bpp, max_supported_bpp); + + link_info = &dp_panel->link_info; + data_rate_khz = link_info->num_lanes * link_info->rate * 8; + tmds_max_clock = dp_panel->connector->display_info.max_tmds_clock; + + for (; bpp > min_supported_bpp; bpp -= 6) { + if (dp_panel->dsc_en) { + if (bpp == 36 && !(dp_panel->sink_dsc_caps.color_depth + & DP_DSC_12_BPC)) + continue; + else if (bpp == 30 && + !(dp_panel->sink_dsc_caps.color_depth & + DP_DSC_10_BPC)) + continue; + else if (bpp == 24 && + !(dp_panel->sink_dsc_caps.color_depth & + DP_DSC_8_BPC)) + continue; + } + + if (tmds_max_clock > 0 && + mult_frac(mode_pclk_khz, bpp, 24) > tmds_max_clock) + continue; + + if (mode_pclk_khz * bpp <= data_rate_khz) + break; + } + + if (bpp < min_supported_bpp) + DP_ERR("bpp %d is below minimum supported bpp %d\n", bpp, + min_supported_bpp); + if (dp_panel->dsc_en && bpp != 24 && bpp != 30 && bpp != 36) + DP_ERR("bpp %d is not supported when dsc is enabled\n", bpp); + + return bpp; +} + +static u32 dp_panel_get_mode_bpp(struct dp_panel *dp_panel, + u32 mode_edid_bpp, u32 mode_pclk_khz) +{ + struct dp_panel_private *panel; + u32 bpp = mode_edid_bpp; + + if (!dp_panel || !mode_edid_bpp || !mode_pclk_khz) { + DP_ERR("invalid input\n"); + return 0; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dp_panel->video_test) + bpp = dp_link_bit_depth_to_bpp( + panel->link->test_video.test_bit_depth); + else + bpp = dp_panel_get_supported_bpp(dp_panel, mode_edid_bpp, + mode_pclk_khz); + + return bpp; +} + +static void dp_panel_set_test_mode(struct dp_panel_private *panel, + struct dp_display_mode *mode) +{ + struct dp_panel_info *pinfo = NULL; + struct dp_link_test_video *test_info = NULL; + + if (!panel) { + DP_ERR("invalid params\n"); + return; + } + + pinfo = &mode->timing; + test_info = &panel->link->test_video; + + pinfo->h_active = test_info->test_h_width; + pinfo->h_sync_width = test_info->test_hsync_width; + pinfo->h_back_porch = test_info->test_h_start - + test_info->test_hsync_width; + pinfo->h_front_porch = test_info->test_h_total - + (test_info->test_h_start + test_info->test_h_width); + + pinfo->v_active = test_info->test_v_height; + pinfo->v_sync_width = test_info->test_vsync_width; + pinfo->v_back_porch = test_info->test_v_start - + test_info->test_vsync_width; + pinfo->v_front_porch = test_info->test_v_total - + (test_info->test_v_start + test_info->test_v_height); + + pinfo->bpp = dp_link_bit_depth_to_bpp(test_info->test_bit_depth); + pinfo->h_active_low = test_info->test_hsync_pol; + pinfo->v_active_low = test_info->test_vsync_pol; + + pinfo->refresh_rate = test_info->test_rr_n; + pinfo->pixel_clk_khz = test_info->test_h_total * + test_info->test_v_total * pinfo->refresh_rate; + + if (test_info->test_rr_d == 0) + pinfo->pixel_clk_khz /= 1000; + else + pinfo->pixel_clk_khz /= 1001; + + if (test_info->test_h_width == 640) + pinfo->pixel_clk_khz = 25170; +} + +static int dp_panel_get_modes(struct dp_panel *dp_panel, + struct drm_connector *connector, struct dp_display_mode *mode) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (dp_panel->video_test) { + dp_panel_set_test_mode(panel, mode); + return 1; + } else if (dp_panel->edid_ctrl->edid) { + return _sde_edid_update_modes(connector, dp_panel->edid_ctrl); + } + + /* fail-safe mode */ + memcpy(&mode->timing, &fail_safe, + sizeof(fail_safe)); + return 1; +} + +static void dp_panel_handle_sink_request(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { + u8 checksum; + + if (dp_panel->edid_ctrl->edid) + checksum = sde_get_edid_checksum(dp_panel->edid_ctrl); + else + checksum = dp_panel->connector->checksum; + + panel->link->send_edid_checksum(panel->link, checksum); + panel->link->send_test_response(panel->link); + } +} + +static void dp_panel_tpg_config(struct dp_panel *dp_panel, bool enable) +{ + u32 hsync_start_x, hsync_end_x; + struct dp_catalog_panel *catalog; + struct dp_panel_private *panel; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return; + } + + if (dp_panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id:%d\n", dp_panel->stream_id); + return; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + pinfo = &panel->dp_panel.pinfo; + + if (!panel->panel_on) { + DP_DEBUG("DP panel not enabled, handle TPG on next panel on\n"); + return; + } + + if (!enable) { + panel->catalog->tpg_config(catalog, false); + return; + } + + /* TPG config */ + catalog->hsync_period = pinfo->h_sync_width + pinfo->h_back_porch + + pinfo->h_active + pinfo->h_front_porch; + catalog->vsync_period = pinfo->v_sync_width + pinfo->v_back_porch + + pinfo->v_active + pinfo->v_front_porch; + + catalog->display_v_start = ((pinfo->v_sync_width + + pinfo->v_back_porch) * catalog->hsync_period); + catalog->display_v_end = ((catalog->vsync_period - + pinfo->v_front_porch) * catalog->hsync_period) - 1; + + catalog->display_v_start += pinfo->h_sync_width + pinfo->h_back_porch; + catalog->display_v_end -= pinfo->h_front_porch; + + hsync_start_x = pinfo->h_back_porch + pinfo->h_sync_width; + hsync_end_x = catalog->hsync_period - pinfo->h_front_porch - 1; + + catalog->v_sync_width = pinfo->v_sync_width; + + catalog->hsync_ctl = (catalog->hsync_period << 16) | + pinfo->h_sync_width; + catalog->display_hctl = (hsync_end_x << 16) | hsync_start_x; + + panel->catalog->tpg_config(catalog, true); +} + +static int dp_panel_config_timing(struct dp_panel *dp_panel) +{ + int rc = 0; + u32 data, total_ver, total_hor; + struct dp_catalog_panel *catalog; + struct dp_panel_private *panel; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + pinfo = &panel->dp_panel.pinfo; + + DP_DEBUG("width=%d hporch= %d %d %d\n", + pinfo->h_active, pinfo->h_back_porch, + pinfo->h_front_porch, pinfo->h_sync_width); + + DP_DEBUG("height=%d vporch= %d %d %d\n", + pinfo->v_active, pinfo->v_back_porch, + pinfo->v_front_porch, pinfo->v_sync_width); + + total_hor = pinfo->h_active + pinfo->h_back_porch + + pinfo->h_front_porch + pinfo->h_sync_width; + + total_ver = pinfo->v_active + pinfo->v_back_porch + + pinfo->v_front_porch + pinfo->v_sync_width; + + data = total_ver; + data <<= 16; + data |= total_hor; + + catalog->total = data; + + data = (pinfo->v_back_porch + pinfo->v_sync_width); + data <<= 16; + data |= (pinfo->h_back_porch + pinfo->h_sync_width); + + catalog->sync_start = data; + + data = pinfo->v_sync_width; + data <<= 16; + data |= (pinfo->v_active_low << 31); + data |= pinfo->h_sync_width; + data |= (pinfo->h_active_low << 15); + + catalog->width_blanking = data; + + data = pinfo->v_active; + data <<= 16; + data |= pinfo->h_active; + + catalog->dp_active = data; + + catalog->widebus_en = pinfo->widebus_en; + + panel->catalog->timing_cfg(catalog); + panel->panel_on = true; +end: + return rc; +} + +static u32 _dp_panel_calc_be_in_lane(struct dp_panel *dp_panel) +{ + struct dp_panel_info *pinfo; + struct msm_compression_info *comp_info; + u32 dsc_htot_byte_cnt, mod_result; + u32 numerator, denominator; + s64 temp_fp; + u32 be_in_lane = 10; + + pinfo = &dp_panel->pinfo; + comp_info = &pinfo->comp_info; + + if (!dp_panel->mst_state) + return be_in_lane; + + switch (pinfo->comp_info.comp_ratio) { + case MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: + denominator = 16; /* 2 * bits-in-byte */ + break; + case MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: + denominator = 24; /* 3 * bits-in-byte */ + break; + default: + denominator = 8; /* 1 * bits-in-byte */ + } + + numerator = (pinfo->h_active + pinfo->h_back_porch + + pinfo->h_front_porch + pinfo->h_sync_width) * + pinfo->bpp; + temp_fp = drm_fixp_from_fraction(numerator, denominator); + dsc_htot_byte_cnt = drm_fixp2int_ceil(temp_fp); + + mod_result = dsc_htot_byte_cnt % 12; + if (mod_result == 0) + be_in_lane = 8; + else if (mod_result <= 3) + be_in_lane = 1; + else if (mod_result <= 6) + be_in_lane = 2; + else if (mod_result <= 9) + be_in_lane = 4; + else if (mod_result <= 11) + be_in_lane = 8; + else + be_in_lane = 10; + + return be_in_lane; +} + +static void dp_panel_config_dsc(struct dp_panel *dp_panel, bool enable) +{ + struct dp_catalog_panel *catalog; + struct dp_panel_private *panel; + struct dp_panel_info *pinfo; + struct msm_compression_info *comp_info; + struct dp_dsc_cfg_data *dsc; + int pps_len; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + catalog = panel->catalog; + dsc = &catalog->dsc; + pinfo = &dp_panel->pinfo; + comp_info = &pinfo->comp_info; + + if (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC && enable) { + pps_len = dp_panel_dsc_create_pps_buf_cmd(&comp_info->dsc_info, + dsc->pps, 0); + dsc->pps_len = pps_len; + dp_panel_dsc_prepare_pps_packet(dp_panel); + + dsc->slice_per_pkt = comp_info->dsc_info.slice_per_pkt - 1; + dsc->bytes_per_pkt = comp_info->dsc_info.bytes_per_pkt; + dsc->bytes_per_pkt /= comp_info->dsc_info.slice_per_pkt; + dsc->eol_byte_num = comp_info->dsc_info.eol_byte_num; + dsc->dto_count = comp_info->dsc_info.pclk_per_line; + dsc->be_in_lane = _dp_panel_calc_be_in_lane(dp_panel); + dsc->dsc_en = true; + dsc->dto_en = true; + + _dp_panel_get_dto_m_n(comp_info->comp_ratio, pinfo->bpp, + &dsc->dto_n, &dsc->dto_d); + } else { + dsc->dsc_en = false; + dsc->dto_en = false; + dsc->dto_n = 0; + dsc->dto_d = 0; + } + + catalog->stream_id = dp_panel->stream_id; + catalog->dsc_cfg(catalog); + + if (catalog->dsc.dsc_en && enable) + catalog->pps_flush(catalog); +} + +static int dp_panel_edid_register(struct dp_panel_private *panel) +{ + int rc = 0; + + panel->dp_panel.edid_ctrl = sde_edid_init(); + if (!panel->dp_panel.edid_ctrl) { + DP_ERR("sde edid init for DP failed\n"); + rc = -ENOMEM; + } + + return rc; +} + +static void dp_panel_edid_deregister(struct dp_panel_private *panel) +{ + sde_edid_deinit((void **)&panel->dp_panel.edid_ctrl); +} + +static int dp_panel_set_stream_info(struct dp_panel *dp_panel, + enum dp_stream_id stream_id, u32 ch_start_slot, + u32 ch_tot_slots, u32 pbn, int vcpi) +{ + if (!dp_panel || stream_id > DP_STREAM_MAX) { + DP_ERR("invalid input. stream_id: %d\n", stream_id); + return -EINVAL; + } + + dp_panel->vcpi = vcpi; + dp_panel->stream_id = stream_id; + dp_panel->channel_start_slot = ch_start_slot; + dp_panel->channel_total_slots = ch_tot_slots; + dp_panel->pbn = pbn; + + return 0; +} + +static int dp_panel_init_panel_info(struct dp_panel *dp_panel) +{ + int rc = 0; + struct dp_panel_private *panel; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + pinfo = &dp_panel->pinfo; + + drm_dp_dpcd_writeb(panel->aux->drm_aux, DP_SET_POWER, DP_SET_POWER_D3); + /* 200us propagation time for the power down to take effect */ + usleep_range(200, 205); + drm_dp_dpcd_writeb(panel->aux->drm_aux, DP_SET_POWER, DP_SET_POWER_D0); + + /* + * According to the DP 1.1 specification, a "Sink Device must exit the + * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink + * Control Field" (register 0x600). + */ + usleep_range(1000, 2000); +end: + return rc; +} + +static int dp_panel_deinit_panel_info(struct dp_panel *dp_panel, u32 flags) +{ + int rc = 0; + struct dp_panel_private *panel; + struct drm_msm_ext_hdr_metadata *hdr_meta; + struct dp_sdp_header *dhdr_vsif_sdp; + struct sde_connector *sde_conn; + struct dp_sdp_header *shdr_if_sdp; + struct dp_catalog_vsc_sdp_colorimetry *vsc_colorimetry; + struct drm_connector *connector; + struct sde_connector_state *c_state; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (flags & DP_PANEL_SRC_INITIATED_POWER_DOWN) { + DP_DEBUG("retain states in src initiated power down request\n"); + return 0; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + hdr_meta = &panel->catalog->hdr_meta; + dhdr_vsif_sdp = &panel->catalog->dhdr_vsif_sdp; + shdr_if_sdp = &panel->catalog->shdr_if_sdp; + vsc_colorimetry = &panel->catalog->vsc_colorimetry; + + if (!panel->custom_edid && dp_panel->edid_ctrl->edid) + sde_free_edid((void **)&dp_panel->edid_ctrl); + + dp_panel_set_stream_info(dp_panel, DP_STREAM_MAX, 0, 0, 0, 0); + memset(&dp_panel->pinfo, 0, sizeof(dp_panel->pinfo)); + memset(hdr_meta, 0, sizeof(struct drm_msm_ext_hdr_metadata)); + memset(dhdr_vsif_sdp, 0, sizeof(struct dp_sdp_header)); + memset(shdr_if_sdp, 0, sizeof(struct dp_sdp_header)); + memset(vsc_colorimetry, 0, + sizeof(struct dp_catalog_vsc_sdp_colorimetry)); + + panel->panel_on = false; + + connector = dp_panel->connector; + sde_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + + connector->hdr_eotf = 0; + connector->hdr_metadata_type_one = 0; + connector->hdr_max_luminance = 0; + connector->hdr_avg_luminance = 0; + connector->hdr_min_luminance = 0; + connector->hdr_supported = false; + connector->hdr_plus_app_ver = 0; + + sde_conn->colorspace_updated = false; + + memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); + memset(&c_state->dyn_hdr_meta, 0, sizeof(c_state->dyn_hdr_meta)); + + return rc; +} + +static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel) +{ + const u32 encoding_factx10 = 8; + u32 min_link_rate_khz = 0, lane_cnt; + struct dp_panel_info *pinfo; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + goto end; + } + + lane_cnt = dp_panel->link_info.num_lanes; + pinfo = &dp_panel->pinfo; + + /* num_lanes * lane_count * 8 >= pclk * bpp * 10 */ + min_link_rate_khz = pinfo->pixel_clk_khz / + (lane_cnt * encoding_factx10); + min_link_rate_khz *= pinfo->bpp; + + DP_DEBUG("min lclk req=%d khz for pclk=%d khz, lanes=%d, bpp=%d\n", + min_link_rate_khz, pinfo->pixel_clk_khz, lane_cnt, + pinfo->bpp); +end: + return min_link_rate_khz; +} + +static bool dp_panel_hdr_supported(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return false; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + return panel->major >= 1 && panel->vsc_supported && + (panel->minor >= 4 || panel->vscext_supported); +} + +static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel, + struct dp_dhdr_maxpkt_calc_input *input) +{ + s64 mdpclk_fp = drm_fixp_from_fraction(input->mdp_clk, 1000000); + s64 lclk_fp = drm_fixp_from_fraction(input->lclk, 1000); + s64 pclk_fp = drm_fixp_from_fraction(input->pclk, 1000); + s64 nlanes_fp = drm_int2fixp(input->nlanes); + s64 target_sc = input->mst_target_sc; + s64 hactive_fp = drm_int2fixp(input->h_active); + const s64 i1_fp = DRM_FIXED_ONE; + const s64 i2_fp = drm_int2fixp(2); + const s64 i10_fp = drm_int2fixp(10); + const s64 i56_fp = drm_int2fixp(56); + const s64 i64_fp = drm_int2fixp(64); + s64 mst_bw_fp = i1_fp; + s64 fec_factor_fp = i1_fp; + s64 mst_bw64_fp, mst_bw64_ceil_fp, nlanes56_fp; + u32 f1, f2, f3, f4, f5, deploy_period, target_period; + s64 f3_f5_slot_fp; + u32 calc_pkt_limit; + const u32 max_pkt_limit = 64; + + if (input->fec_en && input->mst_en) + fec_factor_fp = drm_fixp_from_fraction(64000, 65537); + + if (input->mst_en) + mst_bw_fp = drm_fixp_div(target_sc, i64_fp); + + f1 = drm_fixp2int_ceil(drm_fixp_div(drm_fixp_mul(i10_fp, lclk_fp), + mdpclk_fp)); + f2 = drm_fixp2int_ceil(drm_fixp_div(drm_fixp_mul(i2_fp, lclk_fp), + mdpclk_fp)) + drm_fixp2int_ceil(drm_fixp_div( + drm_fixp_mul(i1_fp, lclk_fp), mdpclk_fp)); + + mst_bw64_fp = drm_fixp_mul(mst_bw_fp, i64_fp); + if (drm_fixp2int(mst_bw64_fp) == 0) + f3_f5_slot_fp = drm_fixp_div(i1_fp, drm_int2fixp( + drm_fixp2int_ceil(drm_fixp_div( + i1_fp, mst_bw64_fp)))); + else + f3_f5_slot_fp = drm_int2fixp(drm_fixp2int(mst_bw_fp)); + + mst_bw64_ceil_fp = drm_int2fixp(drm_fixp2int_ceil(mst_bw64_fp)); + f3 = drm_fixp2int(drm_fixp_mul(drm_int2fixp(drm_fixp2int( + drm_fixp_div(i2_fp, f3_f5_slot_fp)) + 1), + (i64_fp - mst_bw64_ceil_fp))) + 2; + + if (!input->mst_en) { + f4 = 1 + drm_fixp2int(drm_fixp_div(drm_int2fixp(50), + nlanes_fp)) + drm_fixp2int(drm_fixp_div( + nlanes_fp, i2_fp)); + f5 = 0; + } else { + f4 = 0; + nlanes56_fp = drm_fixp_div(i56_fp, nlanes_fp); + f5 = drm_fixp2int(drm_fixp_mul(drm_int2fixp(drm_fixp2int( + drm_fixp_div(i1_fp + nlanes56_fp, + f3_f5_slot_fp)) + 1), (i64_fp - + mst_bw64_ceil_fp + i1_fp + nlanes56_fp))); + } + + deploy_period = f1 + f2 + f3 + f4 + f5 + 19; + target_period = drm_fixp2int(drm_fixp_mul(fec_factor_fp, drm_fixp_mul( + hactive_fp, drm_fixp_div(lclk_fp, pclk_fp)))); + + calc_pkt_limit = target_period / deploy_period; + + DP_DEBUG("input: %d, %d, %d, %d, %d, 0x%llx, %d, %d\n", + input->mdp_clk, input->lclk, input->pclk, input->h_active, + input->nlanes, input->mst_target_sc, input->mst_en ? 1 : 0, + input->fec_en ? 1 : 0); + DP_DEBUG("factors: %d, %d, %d, %d, %d\n", f1, f2, f3, f4, f5); + DP_DEBUG("d_p: %d, t_p: %d, maxPkts: %d%s\n", deploy_period, + target_period, calc_pkt_limit, calc_pkt_limit > max_pkt_limit ? + " CAPPED" : ""); + + if (calc_pkt_limit > max_pkt_limit) + calc_pkt_limit = max_pkt_limit; + + DP_DEBUG("packet limit per line = %d\n", calc_pkt_limit); + return calc_pkt_limit; +} + +static void dp_panel_setup_colorimetry_sdp(struct dp_panel *dp_panel, + u32 cspace) +{ + struct dp_panel_private *panel; + struct dp_catalog_vsc_sdp_colorimetry *hdr_colorimetry; + u8 bpc; + u32 colorimetry = 0; + u32 dynamic_range = 0; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + hdr_colorimetry = &panel->catalog->vsc_colorimetry; + + hdr_colorimetry->header.HB0 = 0x00; + hdr_colorimetry->header.HB1 = 0x07; + hdr_colorimetry->header.HB2 = 0x05; + hdr_colorimetry->header.HB3 = 0x13; + + get_sdp_colorimetry_range(panel, cspace, &colorimetry, + &dynamic_range); + + /* VSC SDP Payload for DB16 */ + hdr_colorimetry->data[16] = (RGB << 4) | colorimetry; + + /* VSC SDP Payload for DB17 */ + hdr_colorimetry->data[17] = (dynamic_range << 7); + bpc = (dp_panel->pinfo.bpp / 3); + + switch (bpc) { + default: + case 10: + hdr_colorimetry->data[17] |= BIT(1); + break; + case 8: + hdr_colorimetry->data[17] |= BIT(0); + break; + case 6: + hdr_colorimetry->data[17] |= 0; + break; + } + + /* VSC SDP Payload for DB18 */ + hdr_colorimetry->data[18] = GRAPHICS; +} + +static void dp_panel_setup_hdr_if(struct dp_panel_private *panel) +{ + struct dp_sdp_header *shdr_if; + + shdr_if = &panel->catalog->shdr_if_sdp; + + shdr_if->HB0 = 0x00; + shdr_if->HB1 = 0x87; + shdr_if->HB2 = 0x1D; + shdr_if->HB3 = 0x13 << 2; +} + +static void dp_panel_setup_dhdr_vsif(struct dp_panel_private *panel) +{ + struct dp_sdp_header *dhdr_vsif; + + dhdr_vsif = &panel->catalog->dhdr_vsif_sdp; + + dhdr_vsif->HB0 = 0x00; + dhdr_vsif->HB1 = 0x81; + dhdr_vsif->HB2 = 0x1D; + dhdr_vsif->HB3 = 0x13 << 2; +} + +static void dp_panel_setup_misc_colorimetry(struct dp_panel *dp_panel, + u32 colorspace) +{ + struct dp_panel_private *panel; + struct dp_catalog_panel *catalog; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + + catalog->misc_val &= ~0x1e; + + catalog->misc_val |= (get_misc_colorimetry_val(panel, + colorspace) << 1); +} + +static int dp_panel_set_colorspace(struct dp_panel *dp_panel, + u32 colorspace) +{ + int rc = 0; + struct dp_panel_private *panel; + + if (!dp_panel) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + if (panel->vsc_supported) + dp_panel_setup_colorimetry_sdp(dp_panel, + colorspace); + else + dp_panel_setup_misc_colorimetry(dp_panel, + colorspace); + + /* + * During the first frame update panel_on will be false and + * the colorspace will be cached in the connector's state which + * shall be used in the dp_panel_hw_cfg + */ + if (panel->panel_on) { + DP_DEBUG("panel is ON programming colorspace\n"); + rc = panel->catalog->set_colorspace(panel->catalog, + panel->vsc_supported); + } + +end: + return rc; +} + +static int dp_panel_setup_hdr(struct dp_panel *dp_panel, + struct drm_msm_ext_hdr_metadata *hdr_meta, + bool dhdr_update, u64 core_clk_rate, bool flush) +{ + int rc = 0, max_pkts = 0; + struct dp_panel_private *panel; + struct dp_dhdr_maxpkt_calc_input input; + struct drm_msm_ext_hdr_metadata *catalog_hdr_meta; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + catalog_hdr_meta = &panel->catalog->hdr_meta; + + /* use cached meta data in case meta data not provided */ + if (!hdr_meta) { + if (catalog_hdr_meta->hdr_state) + goto cached; + else + goto end; + } + + panel->hdr_state = hdr_meta->hdr_state; + + dp_panel_setup_hdr_if(panel); + + if (panel->hdr_state) { + memcpy(catalog_hdr_meta, hdr_meta, + sizeof(struct drm_msm_ext_hdr_metadata)); + } else { + memset(catalog_hdr_meta, 0, + sizeof(struct drm_msm_ext_hdr_metadata)); + } +cached: + if (dhdr_update) { + dp_panel_setup_dhdr_vsif(panel); + + input.mdp_clk = core_clk_rate; + input.lclk = dp_panel->link_info.rate; + input.nlanes = dp_panel->link_info.num_lanes; + input.pclk = dp_panel->pinfo.pixel_clk_khz; + input.h_active = dp_panel->pinfo.h_active; + input.mst_target_sc = dp_panel->mst_target_sc; + input.mst_en = dp_panel->mst_state; + input.fec_en = dp_panel->fec_en; + max_pkts = dp_panel_calc_dhdr_pkt_limit(dp_panel, &input); + } + + if (panel->panel_on) { + panel->catalog->stream_id = dp_panel->stream_id; + panel->catalog->config_hdr(panel->catalog, panel->hdr_state, + max_pkts, flush); + if (dhdr_update) + panel->catalog->dhdr_flush(panel->catalog); + } +end: + return rc; +} + +static int dp_panel_spd_config(struct dp_panel *dp_panel) +{ + int rc = 0; + struct dp_panel_private *panel; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto end; + } + + if (dp_panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream id:%d\n", dp_panel->stream_id); + return -EINVAL; + } + + if (!dp_panel->spd_enabled) { + DP_DEBUG("SPD Infoframe not enabled\n"); + goto end; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + panel->catalog->spd_vendor_name = panel->spd_vendor_name; + panel->catalog->spd_product_description = + panel->spd_product_description; + + panel->catalog->stream_id = dp_panel->stream_id; + panel->catalog->config_spd(panel->catalog); +end: + return rc; +} + +static void dp_panel_config_ctrl(struct dp_panel *dp_panel) +{ + u32 config = 0, tbd; + u8 *dpcd = dp_panel->dpcd; + struct dp_panel_private *panel; + struct dp_catalog_panel *catalog; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + + config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ + config |= (0 << 11); /* RGB */ + + tbd = panel->link->get_test_bits_depth(panel->link, + dp_panel->pinfo.bpp); + + if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) + tbd = DP_TEST_BIT_DEPTH_8; + + config |= tbd << 8; + + /* Num of Lanes */ + config |= ((panel->link->link_params.lane_count - 1) << 4); + + if (drm_dp_enhanced_frame_cap(dpcd)) + config |= 0x40; + + config |= 0x04; /* progressive video */ + + config |= 0x03; /* sycn clock & static Mvid */ + + catalog->config_ctrl(catalog, config); +} + +static void dp_panel_config_misc(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct dp_catalog_panel *catalog; + struct drm_connector *connector; + u32 misc_val; + u32 tb, cc, colorspace; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + connector = dp_panel->connector; + cc = 0; + + tb = panel->link->get_test_bits_depth(panel->link, dp_panel->pinfo.bpp); + colorspace = connector->state->colorspace; + + + cc = (get_misc_colorimetry_val(panel, colorspace) << 1); + + misc_val = cc; + misc_val |= (tb << 5); + misc_val |= BIT(0); /* Configure clock to synchronous mode */ + + /* if VSC is supported then set bit 6 of MISC1 */ + if (panel->vsc_supported) + misc_val |= BIT(14); + + catalog->misc_val = misc_val; + catalog->config_misc(catalog); +} + +static void dp_panel_config_msa(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct dp_catalog_panel *catalog; + u32 rate; + u32 stream_rate_khz; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + catalog = panel->catalog; + + catalog->widebus_en = dp_panel->widebus_en; + + rate = drm_dp_bw_code_to_link_rate(panel->link->link_params.bw_code); + stream_rate_khz = dp_panel->pinfo.pixel_clk_khz; + + catalog->config_msa(catalog, rate, stream_rate_khz); +} + +static void dp_panel_resolution_info(struct dp_panel_private *panel) +{ + struct dp_panel_info *pinfo = &panel->dp_panel.pinfo; + + /* + * print resolution info as this is a result + * of user initiated action of cable connection + */ + DP_INFO("DP RESOLUTION: active(back|front|width|low)\n"); + DP_INFO("%d(%d|%d|%d|%d)x%d(%d|%d|%d|%d)@%dfps %dbpp %dKhz %dLR %dLn\n", + pinfo->h_active, pinfo->h_back_porch, pinfo->h_front_porch, + pinfo->h_sync_width, pinfo->h_active_low, + pinfo->v_active, pinfo->v_back_porch, pinfo->v_front_porch, + pinfo->v_sync_width, pinfo->v_active_low, + pinfo->refresh_rate, pinfo->bpp, pinfo->pixel_clk_khz, + panel->link->link_params.bw_code, + panel->link->link_params.lane_count); +} + +static void dp_panel_config_sdp(struct dp_panel *dp_panel, + bool en) +{ + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel->catalog->stream_id = dp_panel->stream_id; + + panel->catalog->config_sdp(panel->catalog, en); +} + +static int dp_panel_hw_cfg(struct dp_panel *dp_panel, bool enable) +{ + struct dp_panel_private *panel; + struct drm_connector *connector; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return -EINVAL; + } + + if (dp_panel->stream_id >= DP_STREAM_MAX) { + DP_ERR("invalid stream_id: %d\n", dp_panel->stream_id); + return -EINVAL; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + panel->catalog->stream_id = dp_panel->stream_id; + connector = dp_panel->connector; + + if (enable) { + dp_panel_config_ctrl(dp_panel); + dp_panel_config_misc(dp_panel); + dp_panel_config_msa(dp_panel); + if (panel->vsc_supported) { + dp_panel_setup_colorimetry_sdp(dp_panel, + connector->state->colorspace); + dp_panel_config_sdp(dp_panel, true); + } + dp_panel_config_dsc(dp_panel, enable); + dp_panel_config_tr_unit(dp_panel); + dp_panel_config_timing(dp_panel); + dp_panel_resolution_info(panel); + } else { + dp_panel_config_sdp(dp_panel, false); + } + + panel->catalog->config_dto(panel->catalog, !enable); + + return 0; +} + +static int dp_panel_read_sink_sts(struct dp_panel *dp_panel, u8 *sts, u32 size) +{ + int rlen, rc = 0; + struct dp_panel_private *panel; + + if (!dp_panel || !sts || !size) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + return rc; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_SINK_COUNT_ESI, + sts, size); + if (rlen != size) { + DP_ERR("dpcd sink sts fail rlen:%d size:%d\n", rlen, size); + rc = -EINVAL; + return rc; + } + + return 0; +} + +static int dp_panel_update_edid(struct dp_panel *dp_panel, struct edid *edid) +{ + int rc; + + dp_panel->edid_ctrl->edid = edid; + sde_parse_edid(dp_panel->edid_ctrl); + + rc = _sde_edid_update_modes(dp_panel->connector, dp_panel->edid_ctrl); + dp_panel->audio_supported = drm_detect_monitor_audio(edid); + + return rc; +} + +static bool dp_panel_read_mst_cap(struct dp_panel *dp_panel) +{ + int rlen; + struct dp_panel_private *panel; + u8 dpcd; + bool mst_cap = false; + + if (!dp_panel) { + DP_ERR("invalid input\n"); + return 0; + } + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_MSTM_CAP, + &dpcd, 1); + if (rlen < 1) { + DP_ERR("dpcd mstm_cap read failed, rlen=%d\n", rlen); + goto end; + } + + mst_cap = (dpcd & DP_MST_CAP) ? true : false; + +end: + DP_DEBUG("dp mst-cap: %d\n", mst_cap); + + return mst_cap; +} + +static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel, + const struct drm_display_mode *drm_mode, + struct dp_display_mode *dp_mode) +{ + const u32 num_components = 3, default_bpp = 24; + struct msm_compression_info *comp_info; + bool dsc_cap = (dp_mode->capabilities & DP_PANEL_CAPS_DSC) ? + true : false; + + dp_mode->timing.h_active = drm_mode->hdisplay; + dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; + dp_mode->timing.h_sync_width = drm_mode->htotal - + (drm_mode->hsync_start + dp_mode->timing.h_back_porch); + dp_mode->timing.h_front_porch = drm_mode->hsync_start - + drm_mode->hdisplay; + dp_mode->timing.h_skew = drm_mode->hskew; + + dp_mode->timing.v_active = drm_mode->vdisplay; + dp_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; + dp_mode->timing.v_sync_width = drm_mode->vtotal - + (drm_mode->vsync_start + dp_mode->timing.v_back_porch); + + dp_mode->timing.v_front_porch = drm_mode->vsync_start - + drm_mode->vdisplay; + + dp_mode->timing.refresh_rate = drm_mode->vrefresh; + + dp_mode->timing.pixel_clk_khz = drm_mode->clock; + + dp_mode->timing.v_active_low = + !!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC); + + dp_mode->timing.h_active_low = + !!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC); + + dp_mode->timing.bpp = + dp_panel->connector->display_info.bpc * num_components; + if (!dp_mode->timing.bpp) + dp_mode->timing.bpp = default_bpp; + + dp_mode->timing.bpp = dp_panel_get_mode_bpp(dp_panel, + dp_mode->timing.bpp, dp_mode->timing.pixel_clk_khz); + + dp_mode->timing.widebus_en = dp_panel->widebus_en; + dp_mode->timing.dsc_overhead_fp = 0; + + if (dp_panel->dsc_en && dsc_cap) { + comp_info = &dp_mode->timing.comp_info; + + if (dp_panel_dsc_prepare_basic_params(comp_info, + dp_mode, dp_panel)) { + DP_DEBUG("prepare DSC basic params failed\n"); + return; + } + + dp_panel_dsc_populate_static_params(&comp_info->dsc_info, + dp_panel); + dp_panel_dsc_pclk_param_calc(dp_panel, + &comp_info->dsc_info, + comp_info->comp_ratio, + dp_mode); + } + dp_mode->fec_overhead_fp = dp_panel->fec_overhead_fp; +} + +static void dp_panel_update_pps(struct dp_panel *dp_panel, char *pps_cmd) +{ + struct dp_catalog_panel *catalog; + struct dp_panel_private *panel; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + catalog = panel->catalog; + catalog->stream_id = dp_panel->stream_id; + catalog->pps_flush(catalog); +} + +struct dp_panel *dp_panel_get(struct dp_panel_in *in) +{ + int rc = 0; + struct dp_panel_private *panel; + struct dp_panel *dp_panel; + struct sde_connector *sde_conn; + + if (!in->dev || !in->catalog || !in->aux || + !in->link || !in->connector) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL); + if (!panel) { + rc = -ENOMEM; + goto error; + } + + panel->dev = in->dev; + panel->aux = in->aux; + panel->catalog = in->catalog; + panel->link = in->link; + panel->parser = in->parser; + + dp_panel = &panel->dp_panel; + dp_panel->max_bw_code = DP_LINK_BW_8_1; + dp_panel->spd_enabled = true; + memcpy(panel->spd_vendor_name, vendor_name, (sizeof(u8) * 8)); + memcpy(panel->spd_product_description, product_desc, (sizeof(u8) * 16)); + dp_panel->connector = in->connector; + + dp_panel->dsc_feature_enable = panel->parser->dsc_feature_enable; + dp_panel->fec_feature_enable = panel->parser->fec_feature_enable; + + if (in->base_panel) { + memcpy(dp_panel->dpcd, in->base_panel->dpcd, + DP_RECEIVER_CAP_SIZE + 1); + memcpy(dp_panel->dsc_dpcd, in->base_panel->dsc_dpcd, + DP_RECEIVER_DSC_CAP_SIZE + 1); + memcpy(&dp_panel->link_info, &in->base_panel->link_info, + sizeof(dp_panel->link_info)); + dp_panel->mst_state = in->base_panel->mst_state; + dp_panel->widebus_en = in->base_panel->widebus_en; + dp_panel->fec_en = in->base_panel->fec_en; + dp_panel->dsc_en = in->base_panel->dsc_en; + dp_panel->fec_overhead_fp = in->base_panel->fec_overhead_fp; + } + + dp_panel->init = dp_panel_init_panel_info; + dp_panel->deinit = dp_panel_deinit_panel_info; + dp_panel->hw_cfg = dp_panel_hw_cfg; + dp_panel->read_sink_caps = dp_panel_read_sink_caps; + dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate; + dp_panel->get_mode_bpp = dp_panel_get_mode_bpp; + dp_panel->get_modes = dp_panel_get_modes; + dp_panel->handle_sink_request = dp_panel_handle_sink_request; + dp_panel->set_edid = dp_panel_set_edid; + dp_panel->set_dpcd = dp_panel_set_dpcd; + dp_panel->tpg_config = dp_panel_tpg_config; + dp_panel->spd_config = dp_panel_spd_config; + dp_panel->setup_hdr = dp_panel_setup_hdr; + dp_panel->set_colorspace = dp_panel_set_colorspace; + dp_panel->hdr_supported = dp_panel_hdr_supported; + dp_panel->set_stream_info = dp_panel_set_stream_info; + dp_panel->read_sink_status = dp_panel_read_sink_sts; + dp_panel->update_edid = dp_panel_update_edid; + dp_panel->read_mst_cap = dp_panel_read_mst_cap; + dp_panel->convert_to_dp_mode = dp_panel_convert_to_dp_mode; + dp_panel->update_pps = dp_panel_update_pps; + + sde_conn = to_sde_connector(dp_panel->connector); + sde_conn->drv_panel = dp_panel; + + dp_panel_edid_register(panel); + + return dp_panel; +error: + return ERR_PTR(rc); +} + +void dp_panel_put(struct dp_panel *dp_panel) +{ + struct dp_panel_private *panel; + struct sde_connector *sde_conn; + + if (!dp_panel) + return; + + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); + + dp_panel_edid_deregister(panel); + sde_conn = to_sde_connector(dp_panel->connector); + if (sde_conn) + sde_conn->drv_panel = NULL; + + devm_kfree(panel->dev, panel); +} diff --git a/techpack/display/msm/dp/dp_panel.h b/techpack/display/msm/dp/dp_panel.h new file mode 100644 index 0000000000000000000000000000000000000000..212b61524b22925469425664218cac97b8c1c5a1 --- /dev/null +++ b/techpack/display/msm/dp/dp_panel.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_PANEL_H_ +#define _DP_PANEL_H_ + +#include <drm/msm_drm.h> + +#include "dp_aux.h" +#include "dp_link.h" +#include "dp_usbpd.h" +#include "sde_edid_parser.h" +#include "sde_connector.h" +#include "msm_drv.h" + +#define DP_RECEIVER_DSC_CAP_SIZE 15 +#define DP_RECEIVER_FEC_STATUS_SIZE 3 +#define DP_RECEIVER_EXT_CAP_SIZE 4 +/* + * A source initiated power down flag is set + * when the DP is powered off while physical + * DP cable is still connected i.e. without + * HPD or not initiated by sink like HPD_IRQ. + * This can happen if framework reboots or + * device suspends. + */ +#define DP_PANEL_SRC_INITIATED_POWER_DOWN BIT(0) + +#define DP_EXT_REC_CAP_FIELD BIT(7) + +enum dp_lane_count { + DP_LANE_COUNT_1 = 1, + DP_LANE_COUNT_2 = 2, + DP_LANE_COUNT_4 = 4, +}; + +#define DP_MAX_DOWNSTREAM_PORTS 0x10 + +struct dp_panel_info { + u32 h_active; + u32 v_active; + u32 h_back_porch; + u32 h_front_porch; + u32 h_sync_width; + u32 h_active_low; + u32 v_back_porch; + u32 v_front_porch; + u32 v_sync_width; + u32 v_active_low; + u32 h_skew; + u32 refresh_rate; + u32 pixel_clk_khz; + u32 bpp; + bool widebus_en; + struct msm_compression_info comp_info; + s64 dsc_overhead_fp; +}; + +struct dp_display_mode { + struct dp_panel_info timing; + u32 capabilities; + s64 fec_overhead_fp; + s64 dsc_overhead_fp; +}; + +struct dp_panel; + +struct dp_panel_in { + struct device *dev; + struct dp_aux *aux; + struct dp_link *link; + struct dp_catalog_panel *catalog; + struct drm_connector *connector; + struct dp_panel *base_panel; + struct dp_parser *parser; +}; + +struct dp_dsc_caps { + bool dsc_capable; + u8 version; + bool block_pred_en; + u8 color_depth; +}; + +struct dp_audio; + +#define DP_PANEL_CAPS_DSC BIT(0) + +struct dp_panel { + /* dpcd raw data */ + u8 dpcd[DP_RECEIVER_CAP_SIZE + DP_RECEIVER_EXT_CAP_SIZE + 1]; + u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS]; + u8 dsc_dpcd[DP_RECEIVER_DSC_CAP_SIZE + 1]; + u8 fec_dpcd; + u8 fec_sts_dpcd[DP_RECEIVER_FEC_STATUS_SIZE + 1]; + + struct drm_dp_link link_info; + struct sde_edid_ctrl *edid_ctrl; + struct dp_panel_info pinfo; + bool video_test; + bool spd_enabled; + + u32 vic; + u32 max_pclk_khz; + s64 mst_target_sc; + + /* debug */ + u32 max_bw_code; + + /* By default, stream_id is assigned to DP_INVALID_STREAM. + * Client sets the stream id value using set_stream_id interface. + */ + enum dp_stream_id stream_id; + int vcpi; + + u32 channel_start_slot; + u32 channel_total_slots; + u32 pbn; + + u32 tot_dsc_blks_in_use; + /* DRM connector assosiated with this panel */ + struct drm_connector *connector; + + struct dp_audio *audio; + bool audio_supported; + + struct dp_dsc_caps sink_dsc_caps; + bool dsc_feature_enable; + bool fec_feature_enable; + bool dsc_en; + bool fec_en; + bool widebus_en; + bool mst_state; + + s64 fec_overhead_fp; + + int (*init)(struct dp_panel *dp_panel); + int (*deinit)(struct dp_panel *dp_panel, u32 flags); + int (*hw_cfg)(struct dp_panel *dp_panel, bool enable); + int (*read_sink_caps)(struct dp_panel *dp_panel, + struct drm_connector *connector, bool multi_func); + u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel); + u32 (*get_mode_bpp)(struct dp_panel *dp_panel, u32 mode_max_bpp, + u32 mode_pclk_khz); + int (*get_modes)(struct dp_panel *dp_panel, + struct drm_connector *connector, struct dp_display_mode *mode); + void (*handle_sink_request)(struct dp_panel *dp_panel); + int (*set_edid)(struct dp_panel *dp_panel, u8 *edid); + int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd); + int (*setup_hdr)(struct dp_panel *dp_panel, + struct drm_msm_ext_hdr_metadata *hdr_meta, + bool dhdr_update, u64 core_clk_rate, bool flush); + int (*set_colorspace)(struct dp_panel *dp_panel, + u32 colorspace); + void (*tpg_config)(struct dp_panel *dp_panel, bool enable); + int (*spd_config)(struct dp_panel *dp_panel); + bool (*hdr_supported)(struct dp_panel *dp_panel); + + int (*set_stream_info)(struct dp_panel *dp_panel, + enum dp_stream_id stream_id, u32 ch_start_slot, + u32 ch_tot_slots, u32 pbn, int vcpi); + + int (*read_sink_status)(struct dp_panel *dp_panel, u8 *sts, u32 size); + int (*update_edid)(struct dp_panel *dp_panel, struct edid *edid); + bool (*read_mst_cap)(struct dp_panel *dp_panel); + void (*convert_to_dp_mode)(struct dp_panel *dp_panel, + const struct drm_display_mode *drm_mode, + struct dp_display_mode *dp_mode); + void (*update_pps)(struct dp_panel *dp_panel, char *pps_cmd); +}; + +struct dp_tu_calc_input { + u64 lclk; /* 162, 270, 540 and 810 */ + u64 pclk_khz; /* in KHz */ + u64 hactive; /* active h-width */ + u64 hporch; /* bp + fp + pulse */ + int nlanes; /* no.of.lanes */ + int bpp; /* bits */ + int pixel_enc; /* 444, 420, 422 */ + int dsc_en; /* dsc on/off */ + int async_en; /* async mode */ + int fec_en; /* fec */ + int compress_ratio; /* 2:1 = 200, 3:1 = 300, 3.75:1 = 375 */ + int num_of_dsc_slices; /* number of slices per line */ +}; + +struct dp_vc_tu_mapping_table { + u32 vic; + u8 lanes; + u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */ + u8 bpp; + u32 valid_boundary_link; + u32 delay_start_link; + bool boundary_moderation_en; + u32 valid_lower_boundary_link; + u32 upper_boundary_count; + u32 lower_boundary_count; + u32 tu_size_minus1; +}; + +/** + * is_link_rate_valid() - validates the link rate + * @lane_rate: link rate requested by the sink + * + * Returns true if the requested link rate is supported. + */ +static inline bool is_link_rate_valid(u32 bw_code) +{ + return ((bw_code == DP_LINK_BW_1_62) || + (bw_code == DP_LINK_BW_2_7) || + (bw_code == DP_LINK_BW_5_4) || + (bw_code == DP_LINK_BW_8_1)); +} + +/** + * dp_link_is_lane_count_valid() - validates the lane count + * @lane_count: lane count requested by the sink + * + * Returns true if the requested lane count is supported. + */ +static inline bool is_lane_count_valid(u32 lane_count) +{ + return (lane_count == DP_LANE_COUNT_1) || + (lane_count == DP_LANE_COUNT_2) || + (lane_count == DP_LANE_COUNT_4); +} + +struct dp_panel *dp_panel_get(struct dp_panel_in *in); +void dp_panel_put(struct dp_panel *dp_panel); +void dp_panel_calc_tu_test(struct dp_tu_calc_input *in, + struct dp_vc_tu_mapping_table *tu_table); +#endif /* _DP_PANEL_H_ */ diff --git a/techpack/display/msm/dp/dp_parser.c b/techpack/display/msm/dp/dp_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..40a2401b1c4c4a62af23c657bc510f9cdc9ff1e2 --- /dev/null +++ b/techpack/display/msm/dp/dp_parser.c @@ -0,0 +1,936 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/of_gpio.h> +#include <linux/of_platform.h> + +#include "dp_parser.h" +#include "dp_debug.h" + +static void dp_parser_unmap_io_resources(struct dp_parser *parser) +{ + int i = 0; + struct dp_io *io = &parser->io; + + for (i = 0; i < io->len; i++) + msm_dss_iounmap(&io->data[i].io); +} + +static int dp_parser_reg(struct dp_parser *parser) +{ + int rc = 0, i = 0; + u32 reg_count; + struct platform_device *pdev = parser->pdev; + struct dp_io *io = &parser->io; + struct device *dev = &pdev->dev; + + reg_count = of_property_count_strings(dev->of_node, "reg-names"); + if (reg_count <= 0) { + DP_ERR("no reg defined\n"); + return -EINVAL; + } + + io->len = reg_count; + io->data = devm_kzalloc(dev, sizeof(struct dp_io_data) * reg_count, + GFP_KERNEL); + if (!io->data) + return -ENOMEM; + + for (i = 0; i < reg_count; i++) { + of_property_read_string_index(dev->of_node, + "reg-names", i, &io->data[i].name); + rc = msm_dss_ioremap_byname(pdev, &io->data[i].io, + io->data[i].name); + if (rc) { + DP_ERR("unable to remap %s resources\n", + io->data[i].name); + goto err; + } + } + + return 0; +err: + dp_parser_unmap_io_resources(parser); + return rc; +} + +static const char *dp_get_phy_aux_config_property(u32 cfg_type) +{ + switch (cfg_type) { + case PHY_AUX_CFG0: + return "qcom,aux-cfg0-settings"; + case PHY_AUX_CFG1: + return "qcom,aux-cfg1-settings"; + case PHY_AUX_CFG2: + return "qcom,aux-cfg2-settings"; + case PHY_AUX_CFG3: + return "qcom,aux-cfg3-settings"; + case PHY_AUX_CFG4: + return "qcom,aux-cfg4-settings"; + case PHY_AUX_CFG5: + return "qcom,aux-cfg5-settings"; + case PHY_AUX_CFG6: + return "qcom,aux-cfg6-settings"; + case PHY_AUX_CFG7: + return "qcom,aux-cfg7-settings"; + case PHY_AUX_CFG8: + return "qcom,aux-cfg8-settings"; + case PHY_AUX_CFG9: + return "qcom,aux-cfg9-settings"; + default: + return "unknown"; + } +} + +static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser) +{ + int i = 0; + + for (i = 0; i < PHY_AUX_CFG_MAX; i++) + parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 }; +} + +static int dp_parser_aux(struct dp_parser *parser) +{ + struct device_node *of_node = parser->pdev->dev.of_node; + int len = 0, i = 0, j = 0, config_count = 0; + const char *data; + int const minimum_config_count = 1; + + for (i = 0; i < PHY_AUX_CFG_MAX; i++) { + const char *property = dp_get_phy_aux_config_property(i); + + data = of_get_property(of_node, property, &len); + if (!data) { + DP_ERR("Unable to read %s\n", property); + goto error; + } + + config_count = len - 1; + if ((config_count < minimum_config_count) || + (config_count > DP_AUX_CFG_MAX_VALUE_CNT)) { + DP_ERR("Invalid config count (%d) configs for %s\n", + config_count, property); + goto error; + } + + parser->aux_cfg[i].offset = data[0]; + parser->aux_cfg[i].cfg_cnt = config_count; + DP_DEBUG("%s offset=0x%x, cfg_cnt=%d\n", + property, + parser->aux_cfg[i].offset, + parser->aux_cfg[i].cfg_cnt); + for (j = 1; j < len; j++) { + parser->aux_cfg[i].lut[j - 1] = data[j]; + DP_DEBUG("%s lut[%d]=0x%x\n", + property, + i, + parser->aux_cfg[i].lut[j - 1]); + } + } + return 0; + +error: + dp_parser_phy_aux_cfg_reset(parser); + return -EINVAL; +} + +static int dp_parser_misc(struct dp_parser *parser) +{ + int rc = 0, len = 0, i = 0; + const char *data = NULL; + + struct device_node *of_node = parser->pdev->dev.of_node; + + data = of_get_property(of_node, "qcom,logical2physical-lane-map", &len); + if (data && (len == DP_MAX_PHY_LN)) { + for (i = 0; i < len; i++) + parser->l_map[i] = data[i]; + } + + data = of_get_property(of_node, "qcom,pn-swap-lane-map", &len); + if (data && (len == DP_MAX_PHY_LN)) { + for (i = 0; i < len; i++) + parser->l_pnswap |= (data[i] & 0x01) << i; + } + + rc = of_property_read_u32(of_node, + "qcom,max-pclk-frequency-khz", &parser->max_pclk_khz); + if (rc) + parser->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; + + rc = of_property_read_u32(of_node, + "qcom,max-lclk-frequency-khz", &parser->max_lclk_khz); + if (rc) + parser->max_lclk_khz = DP_MAX_LINK_CLK_KHZ; + + return 0; +} + +static int dp_parser_msm_hdcp_dev(struct dp_parser *parser) +{ + struct device_node *node; + struct platform_device *pdev; + + node = of_find_compatible_node(NULL, NULL, "qcom,msm-hdcp"); + if (!node) { + // This is a non-fatal error, module initialization can proceed + DP_WARN("couldn't find msm-hdcp node\n"); + return 0; + } + + pdev = of_find_device_by_node(node); + if (!pdev) { + // This is a non-fatal error, module initialization can proceed + DP_WARN("couldn't find msm-hdcp pdev\n"); + return 0; + } + + parser->msm_hdcp_dev = &pdev->dev; + + return 0; +} + +static int dp_parser_pinctrl(struct dp_parser *parser) +{ + int rc = 0; + struct dp_pinctrl *pinctrl = &parser->pinctrl; + + pinctrl->pin = devm_pinctrl_get(&parser->pdev->dev); + + if (IS_ERR_OR_NULL(pinctrl->pin)) { + DP_DEBUG("failed to get pinctrl, rc=%d\n", rc); + goto error; + } + + if (parser->no_aux_switch && parser->lphw_hpd) { + pinctrl->state_hpd_tlmm = pinctrl->state_hpd_ctrl = NULL; + + pinctrl->state_hpd_tlmm = pinctrl_lookup_state(pinctrl->pin, + "mdss_dp_hpd_tlmm"); + if (!IS_ERR_OR_NULL(pinctrl->state_hpd_tlmm)) { + pinctrl->state_hpd_ctrl = pinctrl_lookup_state( + pinctrl->pin, "mdss_dp_hpd_ctrl"); + } + + if (!pinctrl->state_hpd_tlmm || !pinctrl->state_hpd_ctrl) { + pinctrl->state_hpd_tlmm = NULL; + pinctrl->state_hpd_ctrl = NULL; + DP_DEBUG("tlmm or ctrl pinctrl state does not exist\n"); + } + } + + pinctrl->state_active = pinctrl_lookup_state(pinctrl->pin, + "mdss_dp_active"); + if (IS_ERR_OR_NULL(pinctrl->state_active)) { + rc = PTR_ERR(pinctrl->state_active); + DP_ERR("failed to get pinctrl active state, rc=%d\n", rc); + goto error; + } + + pinctrl->state_suspend = pinctrl_lookup_state(pinctrl->pin, + "mdss_dp_sleep"); + if (IS_ERR_OR_NULL(pinctrl->state_suspend)) { + rc = PTR_ERR(pinctrl->state_suspend); + DP_ERR("failed to get pinctrl suspend state, rc=%d\n", rc); + goto error; + } +error: + return rc; +} + +static int dp_parser_gpio(struct dp_parser *parser) +{ + int i = 0; + struct device *dev = &parser->pdev->dev; + struct device_node *of_node = dev->of_node; + struct dss_module_power *mp = &parser->mp[DP_CORE_PM]; + static const char * const dp_gpios[] = { + "qcom,aux-en-gpio", + "qcom,aux-sel-gpio", + "qcom,usbplug-cc-gpio", + }; + + if (of_find_property(of_node, "qcom,dp-hpd-gpio", NULL)) { + parser->no_aux_switch = true; + parser->lphw_hpd = of_find_property(of_node, + "qcom,dp-low-power-hw-hpd", NULL); + return 0; + } + + if (of_find_property(of_node, "qcom,dp-gpio-aux-switch", NULL)) + parser->gpio_aux_switch = true; + mp->gpio_config = devm_kzalloc(dev, + sizeof(struct dss_gpio) * ARRAY_SIZE(dp_gpios), GFP_KERNEL); + if (!mp->gpio_config) + return -ENOMEM; + + mp->num_gpio = ARRAY_SIZE(dp_gpios); + + for (i = 0; i < ARRAY_SIZE(dp_gpios); i++) { + mp->gpio_config[i].gpio = of_get_named_gpio(of_node, + dp_gpios[i], 0); + + if (!gpio_is_valid(mp->gpio_config[i].gpio)) { + DP_DEBUG("%s gpio not specified\n", dp_gpios[i]); + /* In case any gpio was not specified, we think gpio + * aux switch also was not specified. + */ + parser->gpio_aux_switch = false; + continue; + } + + strlcpy(mp->gpio_config[i].gpio_name, dp_gpios[i], + sizeof(mp->gpio_config[i].gpio_name)); + + mp->gpio_config[i].value = 0; + } + + return 0; +} + +static const char *dp_parser_supply_node_name(enum dp_pm_type module) +{ + switch (module) { + case DP_CORE_PM: return "qcom,core-supply-entries"; + case DP_CTRL_PM: return "qcom,ctrl-supply-entries"; + case DP_PHY_PM: return "qcom,phy-supply-entries"; + default: return "???"; + } +} + +static int dp_parser_get_vreg(struct dp_parser *parser, + enum dp_pm_type module) +{ + int i = 0, rc = 0; + u32 tmp = 0; + const char *pm_supply_name = NULL; + struct device_node *supply_node = NULL; + struct device_node *of_node = parser->pdev->dev.of_node; + struct device_node *supply_root_node = NULL; + struct dss_module_power *mp = &parser->mp[module]; + + mp->num_vreg = 0; + pm_supply_name = dp_parser_supply_node_name(module); + supply_root_node = of_get_child_by_name(of_node, pm_supply_name); + if (!supply_root_node) { + DP_WARN("no supply entry present: %s\n", pm_supply_name); + goto novreg; + } + + mp->num_vreg = of_get_available_child_count(supply_root_node); + + if (mp->num_vreg == 0) { + DP_DEBUG("no vreg\n"); + goto novreg; + } else { + DP_DEBUG("vreg found. count=%d\n", mp->num_vreg); + } + + mp->vreg_config = devm_kzalloc(&parser->pdev->dev, + sizeof(struct dss_vreg) * mp->num_vreg, GFP_KERNEL); + if (!mp->vreg_config) { + rc = -ENOMEM; + goto error; + } + + for_each_child_of_node(supply_root_node, supply_node) { + const char *st = NULL; + /* vreg-name */ + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + DP_ERR("error reading name. rc=%d\n", + rc); + goto error; + } + snprintf(mp->vreg_config[i].vreg_name, + ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st); + /* vreg-min-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + DP_ERR("error reading min volt. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].min_voltage = tmp; + + /* vreg-max-voltage */ + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + DP_ERR("error reading max volt. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].max_voltage = tmp; + + /* enable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + DP_ERR("error reading enable load. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].enable_load = tmp; + + /* disable-load */ + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + DP_ERR("error reading disable load. rc=%d\n", + rc); + goto error; + } + mp->vreg_config[i].disable_load = tmp; + + DP_DEBUG("%s min=%d, max=%d, enable=%d, disable=%d\n", + mp->vreg_config[i].vreg_name, + mp->vreg_config[i].min_voltage, + mp->vreg_config[i].max_voltage, + mp->vreg_config[i].enable_load, + mp->vreg_config[i].disable_load + ); + ++i; + } + + return rc; + +error: + if (mp->vreg_config) { + devm_kfree(&parser->pdev->dev, mp->vreg_config); + mp->vreg_config = NULL; + } +novreg: + mp->num_vreg = 0; + + return rc; +} + +static void dp_parser_put_vreg_data(struct device *dev, + struct dss_module_power *mp) +{ + if (!mp) { + DEV_ERR("invalid input\n"); + return; + } + + if (mp->vreg_config) { + devm_kfree(dev, mp->vreg_config); + mp->vreg_config = NULL; + } + mp->num_vreg = 0; +} + +static int dp_parser_regulator(struct dp_parser *parser) +{ + int i, rc = 0; + struct platform_device *pdev = parser->pdev; + + /* Parse the regulator information */ + for (i = DP_CORE_PM; i < DP_MAX_PM; i++) { + rc = dp_parser_get_vreg(parser, i); + if (rc) { + DP_ERR("get_dt_vreg_data failed for %s. rc=%d\n", + dp_parser_pm_name(i), rc); + i--; + for (; i >= DP_CORE_PM; i--) + dp_parser_put_vreg_data(&pdev->dev, + &parser->mp[i]); + break; + } + } + + return rc; +} + +static bool dp_parser_check_prefix(const char *clk_prefix, const char *clk_name) +{ + return !!strnstr(clk_name, clk_prefix, strlen(clk_name)); +} + +static void dp_parser_put_clk_data(struct device *dev, + struct dss_module_power *mp) +{ + if (!mp) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (mp->clk_config) { + devm_kfree(dev, mp->clk_config); + mp->clk_config = NULL; + } + + mp->num_clk = 0; +} + +static void dp_parser_put_gpio_data(struct device *dev, + struct dss_module_power *mp) +{ + if (!mp) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + if (mp->gpio_config) { + devm_kfree(dev, mp->gpio_config); + mp->gpio_config = NULL; + } + + mp->num_gpio = 0; +} + +static int dp_parser_init_clk_data(struct dp_parser *parser) +{ + int num_clk = 0, i = 0, rc = 0; + int core_clk_count = 0, link_clk_count = 0; + int strm0_clk_count = 0, strm1_clk_count = 0; + const char *core_clk = "core"; + const char *strm0_clk = "strm0"; + const char *strm1_clk = "strm1"; + const char *link_clk = "link"; + const char *clk_name; + struct device *dev = &parser->pdev->dev; + struct dss_module_power *core_power = &parser->mp[DP_CORE_PM]; + struct dss_module_power *strm0_power = &parser->mp[DP_STREAM0_PM]; + struct dss_module_power *strm1_power = &parser->mp[DP_STREAM1_PM]; + struct dss_module_power *link_power = &parser->mp[DP_LINK_PM]; + + num_clk = of_property_count_strings(dev->of_node, "clock-names"); + if (num_clk <= 0) { + DP_ERR("no clocks are defined\n"); + rc = -EINVAL; + goto exit; + } + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(dev->of_node, + "clock-names", i, &clk_name); + + if (dp_parser_check_prefix(core_clk, clk_name)) + core_clk_count++; + + if (dp_parser_check_prefix(strm0_clk, clk_name)) + strm0_clk_count++; + + if (dp_parser_check_prefix(strm1_clk, clk_name)) + strm1_clk_count++; + + if (dp_parser_check_prefix(link_clk, clk_name)) + link_clk_count++; + } + + /* Initialize the CORE power module */ + if (core_clk_count <= 0) { + DP_ERR("no core clocks are defined\n"); + rc = -EINVAL; + goto exit; + } + + core_power->num_clk = core_clk_count; + core_power->clk_config = devm_kzalloc(dev, + sizeof(struct dss_clk) * core_power->num_clk, + GFP_KERNEL); + if (!core_power->clk_config) { + rc = -EINVAL; + goto exit; + } + + /* Initialize the STREAM0 power module */ + if (strm0_clk_count <= 0) { + DP_DEBUG("no strm0 clocks are defined\n"); + } else { + strm0_power->num_clk = strm0_clk_count; + strm0_power->clk_config = devm_kzalloc(dev, + sizeof(struct dss_clk) * strm0_power->num_clk, + GFP_KERNEL); + if (!strm0_power->clk_config) { + strm0_power->num_clk = 0; + rc = -EINVAL; + goto strm0_clock_error; + } + } + + /* Initialize the STREAM1 power module */ + if (strm1_clk_count <= 0) { + DP_DEBUG("no strm1 clocks are defined\n"); + } else { + strm1_power->num_clk = strm1_clk_count; + strm1_power->clk_config = devm_kzalloc(dev, + sizeof(struct dss_clk) * strm1_power->num_clk, + GFP_KERNEL); + if (!strm1_power->clk_config) { + strm1_power->num_clk = 0; + rc = -EINVAL; + goto strm1_clock_error; + } + } + + /* Initialize the link power module */ + if (link_clk_count <= 0) { + DP_ERR("no link clocks are defined\n"); + rc = -EINVAL; + goto link_clock_error; + } + + link_power->num_clk = link_clk_count; + link_power->clk_config = devm_kzalloc(dev, + sizeof(struct dss_clk) * link_power->num_clk, + GFP_KERNEL); + if (!link_power->clk_config) { + link_power->num_clk = 0; + rc = -EINVAL; + goto link_clock_error; + } + + return rc; + +link_clock_error: + dp_parser_put_clk_data(dev, strm1_power); +strm1_clock_error: + dp_parser_put_clk_data(dev, strm0_power); +strm0_clock_error: + dp_parser_put_clk_data(dev, core_power); +exit: + return rc; +} + +static int dp_parser_clock(struct dp_parser *parser) +{ + int rc = 0, i = 0; + int num_clk = 0; + int core_clk_index = 0, link_clk_index = 0; + int core_clk_count = 0, link_clk_count = 0; + int strm0_clk_index = 0, strm1_clk_index = 0; + int strm0_clk_count = 0, strm1_clk_count = 0; + const char *clk_name; + const char *core_clk = "core"; + const char *strm0_clk = "strm0"; + const char *strm1_clk = "strm1"; + const char *link_clk = "link"; + struct device *dev = &parser->pdev->dev; + struct dss_module_power *core_power; + struct dss_module_power *strm0_power; + struct dss_module_power *strm1_power; + struct dss_module_power *link_power; + + core_power = &parser->mp[DP_CORE_PM]; + strm0_power = &parser->mp[DP_STREAM0_PM]; + strm1_power = &parser->mp[DP_STREAM1_PM]; + link_power = &parser->mp[DP_LINK_PM]; + + rc = dp_parser_init_clk_data(parser); + if (rc) { + DP_ERR("failed to initialize power data\n"); + rc = -EINVAL; + goto exit; + } + + core_clk_count = core_power->num_clk; + link_clk_count = link_power->num_clk; + strm0_clk_count = strm0_power->num_clk; + strm1_clk_count = strm1_power->num_clk; + + num_clk = of_property_count_strings(dev->of_node, "clock-names"); + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(dev->of_node, "clock-names", + i, &clk_name); + + if (dp_parser_check_prefix(core_clk, clk_name) && + core_clk_index < core_clk_count) { + struct dss_clk *clk = + &core_power->clk_config[core_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + clk->type = DSS_CLK_AHB; + core_clk_index++; + } else if (dp_parser_check_prefix(link_clk, clk_name) && + link_clk_index < link_clk_count) { + struct dss_clk *clk = + &link_power->clk_config[link_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + link_clk_index++; + + if (!strcmp(clk_name, "link_clk")) + clk->type = DSS_CLK_PCLK; + else + clk->type = DSS_CLK_AHB; + } else if (dp_parser_check_prefix(strm0_clk, clk_name) && + strm0_clk_index < strm0_clk_count) { + struct dss_clk *clk = + &strm0_power->clk_config[strm0_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + strm0_clk_index++; + + clk->type = DSS_CLK_PCLK; + } else if (dp_parser_check_prefix(strm1_clk, clk_name) && + strm1_clk_index < strm1_clk_count) { + struct dss_clk *clk = + &strm1_power->clk_config[strm1_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + strm1_clk_index++; + + clk->type = DSS_CLK_PCLK; + } + } + + DP_DEBUG("clock parsing successful\n"); + +exit: + return rc; +} + +static int dp_parser_catalog(struct dp_parser *parser) +{ + int rc; + u32 version; + struct device *dev = &parser->pdev->dev; + + rc = of_property_read_u32(dev->of_node, "qcom,phy-version", &version); + + if (!rc) + parser->hw_cfg.phy_version = version; + + return 0; +} + +static int dp_parser_mst(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + int i; + + parser->has_mst = of_property_read_bool(dev->of_node, + "qcom,mst-enable"); + + parser->no_mst_encoder = of_property_read_bool(dev->of_node, + "qcom,no-mst-encoder"); + + parser->has_mst_sideband = parser->has_mst; + + DP_DEBUG("mst parsing successful. mst:%d\n", parser->has_mst); + + for (i = 0; i < MAX_DP_MST_STREAMS; i++) { + of_property_read_u32_index(dev->of_node, + "qcom,mst-fixed-topology-ports", i, + &parser->mst_fixed_port[i]); + } + + return 0; +} + +static void dp_parser_dsc(struct dp_parser *parser) +{ + int rc; + struct device *dev = &parser->pdev->dev; + + parser->dsc_feature_enable = of_property_read_bool(dev->of_node, + "qcom,dsc-feature-enable"); + + rc = of_property_read_u32(dev->of_node, + "qcom,max-dp-dsc-blks", &parser->max_dp_dsc_blks); + if (rc || !parser->max_dp_dsc_blks) + parser->dsc_feature_enable = false; + + rc = of_property_read_u32(dev->of_node, + "qcom,max-dp-dsc-input-width-pixs", + &parser->max_dp_dsc_input_width_pixs); + if (rc || !parser->max_dp_dsc_input_width_pixs) + parser->dsc_feature_enable = false; + + DP_DEBUG("dsc parsing successful. dsc:%d, blks:%d, width:%d\n", + parser->dsc_feature_enable, + parser->max_dp_dsc_blks, + parser->max_dp_dsc_input_width_pixs); +} + +static void dp_parser_fec(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + + parser->fec_feature_enable = of_property_read_bool(dev->of_node, + "qcom,fec-feature-enable"); + + DP_DEBUG("fec parsing successful. fec:%d\n", + parser->fec_feature_enable); +} + +static void dp_parser_widebus(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + + parser->has_widebus = of_property_read_bool(dev->of_node, + "qcom,widebus-enable"); + + DP_DEBUG("widebus parsing successful. widebus:%d\n", + parser->has_widebus); +} + +static int dp_parser_parse(struct dp_parser *parser) +{ + int rc = 0; + + if (!parser) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto err; + } + + rc = dp_parser_reg(parser); + if (rc) + goto err; + + rc = dp_parser_aux(parser); + if (rc) + goto err; + + rc = dp_parser_misc(parser); + if (rc) + goto err; + + rc = dp_parser_clock(parser); + if (rc) + goto err; + + rc = dp_parser_regulator(parser); + if (rc) + goto err; + + rc = dp_parser_gpio(parser); + if (rc) + goto err; + + rc = dp_parser_catalog(parser); + if (rc) + goto err; + + rc = dp_parser_pinctrl(parser); + if (rc) + goto err; + + rc = dp_parser_msm_hdcp_dev(parser); + if (rc) + goto err; + + rc = dp_parser_mst(parser); + if (rc) + goto err; + + dp_parser_dsc(parser); + dp_parser_fec(parser); + dp_parser_widebus(parser); +err: + return rc; +} + +static struct dp_io_data *dp_parser_get_io(struct dp_parser *dp_parser, + char *name) +{ + int i = 0; + struct dp_io *io; + + if (!dp_parser) { + DP_ERR("invalid input\n"); + goto err; + } + + io = &dp_parser->io; + + for (i = 0; i < io->len; i++) { + struct dp_io_data *data = &io->data[i]; + + if (!strcmp(data->name, name)) + return data; + } +err: + return NULL; +} + +static void dp_parser_get_io_buf(struct dp_parser *dp_parser, char *name) +{ + int i = 0; + struct dp_io *io; + + if (!dp_parser) { + DP_ERR("invalid input\n"); + return; + } + + io = &dp_parser->io; + + for (i = 0; i < io->len; i++) { + struct dp_io_data *data = &io->data[i]; + + if (!strcmp(data->name, name)) { + if (!data->buf) + data->buf = devm_kzalloc(&dp_parser->pdev->dev, + data->io.len, GFP_KERNEL); + } + } +} + +static void dp_parser_clear_io_buf(struct dp_parser *dp_parser) +{ + int i = 0; + struct dp_io *io; + + if (!dp_parser) { + DP_ERR("invalid input\n"); + return; + } + + io = &dp_parser->io; + + for (i = 0; i < io->len; i++) { + struct dp_io_data *data = &io->data[i]; + + if (data->buf) + devm_kfree(&dp_parser->pdev->dev, data->buf); + + data->buf = NULL; + } +} + +struct dp_parser *dp_parser_get(struct platform_device *pdev) +{ + struct dp_parser *parser; + + parser = devm_kzalloc(&pdev->dev, sizeof(*parser), GFP_KERNEL); + if (!parser) + return ERR_PTR(-ENOMEM); + + parser->parse = dp_parser_parse; + parser->get_io = dp_parser_get_io; + parser->get_io_buf = dp_parser_get_io_buf; + parser->clear_io_buf = dp_parser_clear_io_buf; + parser->pdev = pdev; + + return parser; +} + +void dp_parser_put(struct dp_parser *parser) +{ + int i = 0; + struct dss_module_power *power = NULL; + + if (!parser) { + DP_ERR("invalid parser module\n"); + return; + } + + power = parser->mp; + + for (i = 0; i < DP_MAX_PM; i++) { + dp_parser_put_clk_data(&parser->pdev->dev, &power[i]); + dp_parser_put_vreg_data(&parser->pdev->dev, &power[i]); + dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]); + } + + dp_parser_clear_io_buf(parser); + devm_kfree(&parser->pdev->dev, parser->io.data); + devm_kfree(&parser->pdev->dev, parser); +} diff --git a/techpack/display/msm/dp/dp_parser.h b/techpack/display/msm/dp/dp_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..0970dff71ed02c639c4fd7f53692f4bd86b639e4 --- /dev/null +++ b/techpack/display/msm/dp/dp_parser.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_PARSER_H_ +#define _DP_PARSER_H_ + +#include <linux/sde_io_util.h> + +#define DP_LABEL "MDSS DP DISPLAY" +#define AUX_CFG_LEN 10 +#define DP_MAX_PIXEL_CLK_KHZ 675000 +#define DP_MAX_LINK_CLK_KHZ 810000 +#define MAX_DP_MST_STREAMS 2 + +enum dp_pm_type { + DP_CORE_PM, + DP_CTRL_PM, + DP_PHY_PM, + DP_STREAM0_PM, + DP_STREAM1_PM, + DP_LINK_PM, + DP_MAX_PM +}; + +static inline const char *dp_parser_pm_name(enum dp_pm_type module) +{ + switch (module) { + case DP_CORE_PM: return "DP_CORE_PM"; + case DP_CTRL_PM: return "DP_CTRL_PM"; + case DP_PHY_PM: return "DP_PHY_PM"; + case DP_STREAM0_PM: return "DP_STREAM0_PM"; + case DP_STREAM1_PM: return "DP_STREAM1_PM"; + case DP_LINK_PM: return "DP_LINK_PM"; + default: return "???"; + } +} + +/** + * struct dp_display_data - display related device tree data. + * + * @ctrl_node: referece to controller device + * @phy_node: reference to phy device + * @is_active: is the controller currently active + * @name: name of the display + * @display_type: type of the display + */ +struct dp_display_data { + struct device_node *ctrl_node; + struct device_node *phy_node; + bool is_active; + const char *name; + const char *display_type; +}; + +/** + * struct dp_io_data - data structure to store DP IO related info + * @name: name of the IO + * @buf: buffer corresponding to IO for debugging + * @io: io data which give len and mapped address + */ +struct dp_io_data { + const char *name; + u8 *buf; + struct dss_io_data io; +}; + +/** + * struct dp_io - data struct to store array of DP IO info + * @len: total number of IOs + * @data: pointer to an array of DP IO data structures. + */ +struct dp_io { + u32 len; + struct dp_io_data *data; +}; + +/** + * struct dp_pinctrl - DP's pin control + * + * @pin: pin-controller's instance + * @state_active: active state pin control + * @state_hpd_active: hpd active state pin control + * @state_suspend: suspend state pin control + */ +struct dp_pinctrl { + struct pinctrl *pin; + struct pinctrl_state *state_active; + struct pinctrl_state *state_hpd_active; + struct pinctrl_state *state_hpd_tlmm; + struct pinctrl_state *state_hpd_ctrl; + struct pinctrl_state *state_suspend; +}; + +#define DP_ENUM_STR(x) #x +#define DP_AUX_CFG_MAX_VALUE_CNT 3 +/** + * struct dp_aux_cfg - DP's AUX configuration settings + * + * @cfg_cnt: count of the configurable settings for the AUX register + * @current_index: current index of the AUX config lut + * @offset: register offset of the AUX config register + * @lut: look up table for the AUX config values for this register + */ +struct dp_aux_cfg { + u32 cfg_cnt; + u32 current_index; + u32 offset; + u32 lut[DP_AUX_CFG_MAX_VALUE_CNT]; +}; + +/* PHY AUX config registers */ +enum dp_phy_aux_config_type { + PHY_AUX_CFG0, + PHY_AUX_CFG1, + PHY_AUX_CFG2, + PHY_AUX_CFG3, + PHY_AUX_CFG4, + PHY_AUX_CFG5, + PHY_AUX_CFG6, + PHY_AUX_CFG7, + PHY_AUX_CFG8, + PHY_AUX_CFG9, + PHY_AUX_CFG_MAX, +}; + +/** + * enum dp_phy_version - version of the dp phy + * @DP_PHY_VERSION_UNKNOWN: Unknown controller version + * @DP_PHY_VERSION_4_2_0: DP phy v4.2.0 controller + * @DP_PHY_VERSION_MAX: max version + */ +enum dp_phy_version { + DP_PHY_VERSION_UNKNOWN, + DP_PHY_VERSION_2_0_0 = 0x200, + DP_PHY_VERSION_4_2_0 = 0x420, + DP_PHY_VERSION_MAX +}; + +/** + * struct dp_hw_cfg - DP HW specific configuration + * + * @phy_version: DP PHY HW version + */ +struct dp_hw_cfg { + enum dp_phy_version phy_version; +}; + +static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) +{ + switch (cfg_type) { + case PHY_AUX_CFG0: + return DP_ENUM_STR(PHY_AUX_CFG0); + case PHY_AUX_CFG1: + return DP_ENUM_STR(PHY_AUX_CFG1); + case PHY_AUX_CFG2: + return DP_ENUM_STR(PHY_AUX_CFG2); + case PHY_AUX_CFG3: + return DP_ENUM_STR(PHY_AUX_CFG3); + case PHY_AUX_CFG4: + return DP_ENUM_STR(PHY_AUX_CFG4); + case PHY_AUX_CFG5: + return DP_ENUM_STR(PHY_AUX_CFG5); + case PHY_AUX_CFG6: + return DP_ENUM_STR(PHY_AUX_CFG6); + case PHY_AUX_CFG7: + return DP_ENUM_STR(PHY_AUX_CFG7); + case PHY_AUX_CFG8: + return DP_ENUM_STR(PHY_AUX_CFG8); + case PHY_AUX_CFG9: + return DP_ENUM_STR(PHY_AUX_CFG9); + default: + return "unknown"; + } +} + +/** + * struct dp_parser - DP parser's data exposed to clients + * + * @pdev: platform data of the client + * @msm_hdcp_dev: device pointer for the HDCP driver + * @mp: gpio, regulator and clock related data + * @pinctrl: pin-control related data + * @disp_data: controller's display related data + * @l_pnswap: P/N swap status on each lane + * @max_pclk_khz: maximum pixel clock supported for the platform + * @max_lclk_khz: maximum link clock supported for the platform + * @hw_cfg: DP HW specific settings + * @has_mst: MST feature enable status + * @has_mst_sideband: MST sideband feature enable status + * @no_aux_switch: presence AUX switch status + * @no_mst_encoder: only one dp interface available + * @gpio_aux_switch: presence GPIO AUX switch status + * @dsc_feature_enable: DSC feature enable status + * @fec_feature_enable: FEC feature enable status + * @max_dp_dsc_blks: maximum DSC blks for DP interface + * @max_dp_dsc_input_width_pixs: Maximum input width for DSC block + * @has_widebus: widebus (2PPC) feature eanble status + *@mst_fixed_port: mst port_num reserved for fixed topology + * @parse: function to be called by client to parse device tree. + * @get_io: function to be called by client to get io data. + * @get_io_buf: function to be called by client to get io buffers. + * @clear_io_buf: function to be called by client to clear io buffers. + */ +struct dp_parser { + struct platform_device *pdev; + struct device *msm_hdcp_dev; + struct dss_module_power mp[DP_MAX_PM]; + struct dp_pinctrl pinctrl; + struct dp_io io; + struct dp_display_data disp_data; + + u8 l_map[4]; + u8 l_pnswap; + struct dp_aux_cfg aux_cfg[AUX_CFG_LEN]; + u32 max_pclk_khz; + u32 max_lclk_khz; + struct dp_hw_cfg hw_cfg; + bool has_mst; + bool has_mst_sideband; + bool no_aux_switch; + bool no_mst_encoder; + bool dsc_feature_enable; + bool fec_feature_enable; + bool has_widebus; + bool gpio_aux_switch; + u32 max_dp_dsc_blks; + u32 max_dp_dsc_input_width_pixs; + bool lphw_hpd; + u32 mst_fixed_port[MAX_DP_MST_STREAMS]; + + int (*parse)(struct dp_parser *parser); + struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name); + void (*get_io_buf)(struct dp_parser *parser, char *name); + void (*clear_io_buf)(struct dp_parser *parser); +}; + +enum dp_phy_lane_num { + DP_PHY_LN0 = 0, + DP_PHY_LN1 = 1, + DP_PHY_LN2 = 2, + DP_PHY_LN3 = 3, + DP_MAX_PHY_LN = 4, +}; + +enum dp_mainlink_lane_num { + DP_ML0 = 0, + DP_ML1 = 1, + DP_ML2 = 2, + DP_ML3 = 3, +}; + +/** + * dp_parser_get() - get the DP's device tree parser module + * + * @pdev: platform data of the client + * return: pointer to dp_parser structure. + * + * This function provides client capability to parse the + * device tree and populate the data structures. The data + * related to clock, regulators, pin-control and other + * can be parsed using this module. + */ +struct dp_parser *dp_parser_get(struct platform_device *pdev); + +/** + * dp_parser_put() - cleans the dp_parser module + * + * @parser: pointer to the parser's data. + */ +void dp_parser_put(struct dp_parser *parser); +#endif diff --git a/techpack/display/msm/dp/dp_power.c b/techpack/display/msm/dp/dp_power.c new file mode 100644 index 0000000000000000000000000000000000000000..e14488f43fa0226bf834f5ce7e5fc317368f0b06 --- /dev/null +++ b/techpack/display/msm/dp/dp_power.c @@ -0,0 +1,702 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/pm_runtime.h> +#include <drm/drmP.h> +#include "dp_power.h" +#include "dp_catalog.h" +#include "dp_debug.h" + +#define DP_CLIENT_NAME_SIZE 20 + +struct dp_power_private { + struct dp_parser *parser; + struct platform_device *pdev; + struct clk *pixel_clk_rcg; + struct clk *pixel_parent; + struct clk *pixel1_clk_rcg; + struct clk *pixel1_parent; + + struct dp_power dp_power; + + bool core_clks_on; + bool link_clks_on; + bool strm0_clks_on; + bool strm1_clks_on; +}; + +static int dp_power_regulator_init(struct dp_power_private *power) +{ + int rc = 0, i = 0, j = 0; + struct platform_device *pdev; + struct dp_parser *parser; + + parser = power->parser; + pdev = power->pdev; + + for (i = DP_CORE_PM; !rc && (i < DP_MAX_PM); i++) { + rc = msm_dss_config_vreg(&pdev->dev, + parser->mp[i].vreg_config, + parser->mp[i].num_vreg, 1); + if (rc) { + DP_ERR("failed to init vregs for %s\n", + dp_parser_pm_name(i)); + for (j = i - 1; j >= DP_CORE_PM; j--) { + msm_dss_config_vreg(&pdev->dev, + parser->mp[j].vreg_config, + parser->mp[j].num_vreg, 0); + } + + goto error; + } + } +error: + return rc; +} + +static void dp_power_regulator_deinit(struct dp_power_private *power) +{ + int rc = 0, i = 0; + struct platform_device *pdev; + struct dp_parser *parser; + + parser = power->parser; + pdev = power->pdev; + + for (i = DP_CORE_PM; (i < DP_MAX_PM); i++) { + rc = msm_dss_config_vreg(&pdev->dev, + parser->mp[i].vreg_config, + parser->mp[i].num_vreg, 0); + if (rc) + DP_ERR("failed to deinit vregs for %s\n", + dp_parser_pm_name(i)); + } +} + +static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable) +{ + int rc = 0, i = 0, j = 0; + struct dp_parser *parser; + + parser = power->parser; + + for (i = DP_CORE_PM; i < DP_MAX_PM; i++) { + rc = msm_dss_enable_vreg( + parser->mp[i].vreg_config, + parser->mp[i].num_vreg, enable); + if (rc) { + DP_ERR("failed to '%s' vregs for %s\n", + enable ? "enable" : "disable", + dp_parser_pm_name(i)); + if (enable) { + for (j = i-1; j >= DP_CORE_PM; j--) { + msm_dss_enable_vreg( + parser->mp[j].vreg_config, + parser->mp[j].num_vreg, 0); + } + } + goto error; + } + } +error: + return rc; +} + +static int dp_power_pinctrl_set(struct dp_power_private *power, bool active) +{ + int rc = -EFAULT; + struct pinctrl_state *pin_state; + struct dp_parser *parser; + + parser = power->parser; + + if (IS_ERR_OR_NULL(parser->pinctrl.pin)) + return 0; + + if (parser->no_aux_switch && parser->lphw_hpd) { + pin_state = active ? parser->pinctrl.state_hpd_ctrl + : parser->pinctrl.state_hpd_tlmm; + if (!IS_ERR_OR_NULL(pin_state)) { + rc = pinctrl_select_state(parser->pinctrl.pin, + pin_state); + if (rc) { + DP_ERR("cannot direct hpd line to %s\n", + active ? "ctrl" : "tlmm"); + return rc; + } + } + } + + if (parser->no_aux_switch) + return 0; + + pin_state = active ? parser->pinctrl.state_active + : parser->pinctrl.state_suspend; + if (!IS_ERR_OR_NULL(pin_state)) { + rc = pinctrl_select_state(parser->pinctrl.pin, + pin_state); + if (rc) + DP_ERR("can not set %s pins\n", + active ? "dp_active" + : "dp_sleep"); + } else { + DP_ERR("invalid '%s' pinstate\n", + active ? "dp_active" + : "dp_sleep"); + } + + return rc; +} + +static int dp_power_clk_init(struct dp_power_private *power, bool enable) +{ + int rc = 0; + struct device *dev; + enum dp_pm_type module; + + dev = &power->pdev->dev; + + if (enable) { + for (module = DP_CORE_PM; module < DP_MAX_PM; module++) { + struct dss_module_power *pm = + &power->parser->mp[module]; + + if (!pm->num_clk) + continue; + + rc = msm_dss_get_clk(dev, pm->clk_config, pm->num_clk); + if (rc) { + DP_ERR("failed to get %s clk. err=%d\n", + dp_parser_pm_name(module), rc); + goto exit; + } + } + + power->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg"); + if (IS_ERR(power->pixel_clk_rcg)) { + DP_DEBUG("Unable to get DP pixel clk RCG\n"); + power->pixel_clk_rcg = NULL; + } + + power->pixel_parent = devm_clk_get(dev, "pixel_parent"); + if (IS_ERR(power->pixel_parent)) { + DP_DEBUG("Unable to get DP pixel RCG parent\n"); + power->pixel_parent = NULL; + } + + power->pixel1_clk_rcg = devm_clk_get(dev, "pixel1_clk_rcg"); + if (IS_ERR(power->pixel1_clk_rcg)) { + DP_DEBUG("Unable to get DP pixel1 clk RCG\n"); + power->pixel1_clk_rcg = NULL; + } + + power->pixel1_parent = devm_clk_get(dev, "pixel1_parent"); + if (IS_ERR(power->pixel1_parent)) { + DP_DEBUG("Unable to get DP pixel1 RCG parent\n"); + power->pixel1_parent = NULL; + } + } else { + if (power->pixel_parent) + devm_clk_put(dev, power->pixel_parent); + + if (power->pixel_clk_rcg) + devm_clk_put(dev, power->pixel_clk_rcg); + + if (power->pixel1_parent) + devm_clk_put(dev, power->pixel1_parent); + + if (power->pixel1_clk_rcg) + devm_clk_put(dev, power->pixel1_clk_rcg); + + for (module = DP_CORE_PM; module < DP_MAX_PM; module++) { + struct dss_module_power *pm = + &power->parser->mp[module]; + + if (!pm->num_clk) + continue; + + msm_dss_put_clk(pm->clk_config, pm->num_clk); + } + } +exit: + return rc; +} + +static int dp_power_clk_set_rate(struct dp_power_private *power, + enum dp_pm_type module, bool enable) +{ + int rc = 0; + struct dss_module_power *mp; + + if (!power) { + DP_ERR("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + mp = &power->parser->mp[module]; + + if (enable) { + rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); + if (rc) { + DP_ERR("failed to set clks rate.\n"); + goto exit; + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 1); + if (rc) { + DP_ERR("failed to enable clks\n"); + goto exit; + } + } else { + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 0); + if (rc) { + DP_ERR("failed to disable clks\n"); + goto exit; + } + } +exit: + return rc; +} + +static int dp_power_clk_enable(struct dp_power *dp_power, + enum dp_pm_type pm_type, bool enable) +{ + int rc = 0; + struct dss_module_power *mp; + struct dp_power_private *power; + + if (!dp_power) { + DP_ERR("invalid power data\n"); + rc = -EINVAL; + goto error; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + mp = &power->parser->mp[pm_type]; + + if (pm_type >= DP_MAX_PM) { + DP_ERR("unsupported power module: %s\n", + dp_parser_pm_name(pm_type)); + return -EINVAL; + } + + if (enable) { + if (pm_type == DP_CORE_PM && power->core_clks_on) { + DP_DEBUG("core clks already enabled\n"); + return 0; + } + + if ((pm_type == DP_STREAM0_PM) && (power->strm0_clks_on)) { + DP_DEBUG("strm0 clks already enabled\n"); + return 0; + } + + if ((pm_type == DP_STREAM1_PM) && (power->strm1_clks_on)) { + DP_DEBUG("strm1 clks already enabled\n"); + return 0; + } + + if ((pm_type == DP_CTRL_PM) && (!power->core_clks_on)) { + DP_DEBUG("Need to enable core clks before link clks\n"); + + rc = dp_power_clk_set_rate(power, pm_type, enable); + if (rc) { + DP_ERR("failed to enable clks: %s. err=%d\n", + dp_parser_pm_name(DP_CORE_PM), rc); + goto error; + } else { + power->core_clks_on = true; + } + } + + if (pm_type == DP_LINK_PM && power->link_clks_on) { + DP_DEBUG("links clks already enabled\n"); + return 0; + } + } + + rc = dp_power_clk_set_rate(power, pm_type, enable); + if (rc) { + DP_ERR("failed to '%s' clks for: %s. err=%d\n", + enable ? "enable" : "disable", + dp_parser_pm_name(pm_type), rc); + goto error; + } + + if (pm_type == DP_CORE_PM) + power->core_clks_on = enable; + else if (pm_type == DP_STREAM0_PM) + power->strm0_clks_on = enable; + else if (pm_type == DP_STREAM1_PM) + power->strm1_clks_on = enable; + else if (pm_type == DP_LINK_PM) + power->link_clks_on = enable; + + /* + * This log is printed only when user connects or disconnects + * a DP cable. As this is a user-action and not a frequent + * usecase, it is not going to flood the kernel logs. Also, + * helpful in debugging the NOC issues. + */ + DP_INFO("core:%s link:%s strm0:%s strm1:%s\n", + power->core_clks_on ? "on" : "off", + power->link_clks_on ? "on" : "off", + power->strm0_clks_on ? "on" : "off", + power->strm1_clks_on ? "on" : "off"); +error: + return rc; +} + +static int dp_power_request_gpios(struct dp_power_private *power) +{ + int rc = 0, i; + struct device *dev; + struct dss_module_power *mp; + static const char * const gpio_names[] = { + "aux_enable", "aux_sel", "usbplug_cc", + }; + + if (!power) { + DP_ERR("invalid power data\n"); + return -EINVAL; + } + + dev = &power->pdev->dev; + mp = &power->parser->mp[DP_CORE_PM]; + + for (i = 0; i < ARRAY_SIZE(gpio_names); i++) { + unsigned int gpio = mp->gpio_config[i].gpio; + + if (gpio_is_valid(gpio)) { + rc = devm_gpio_request(dev, gpio, gpio_names[i]); + if (rc) { + DP_ERR("request %s gpio failed, rc=%d\n", + gpio_names[i], rc); + goto error; + } + } + } + return 0; +error: + for (i = 0; i < ARRAY_SIZE(gpio_names); i++) { + unsigned int gpio = mp->gpio_config[i].gpio; + + if (gpio_is_valid(gpio)) + gpio_free(gpio); + } + return rc; +} + +static bool dp_power_find_gpio(const char *gpio1, const char *gpio2) +{ + return !!strnstr(gpio1, gpio2, strlen(gpio1)); +} + +static void dp_power_set_gpio(struct dp_power_private *power, bool flip) +{ + int i; + struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM]; + struct dss_gpio *config = mp->gpio_config; + + for (i = 0; i < mp->num_gpio; i++) { + if (dp_power_find_gpio(config->gpio_name, "aux-sel")) + config->value = flip; + + if (gpio_is_valid(config->gpio)) { + DP_DEBUG("gpio %s, value %d\n", config->gpio_name, + config->value); + + if (dp_power_find_gpio(config->gpio_name, "aux-en") || + dp_power_find_gpio(config->gpio_name, "aux-sel")) + gpio_direction_output(config->gpio, + config->value); + else + gpio_set_value(config->gpio, config->value); + + } + config++; + } +} + +static int dp_power_config_gpios(struct dp_power_private *power, bool flip, + bool enable) +{ + int rc = 0, i; + struct dss_module_power *mp; + struct dss_gpio *config; + + if (power->parser->no_aux_switch) + return 0; + + mp = &power->parser->mp[DP_CORE_PM]; + config = mp->gpio_config; + + if (enable) { + rc = dp_power_request_gpios(power); + if (rc) { + DP_ERR("gpio request failed\n"); + return rc; + } + + dp_power_set_gpio(power, flip); + } else { + for (i = 0; i < mp->num_gpio; i++) { + if (gpio_is_valid(config[i].gpio)) { + gpio_set_value(config[i].gpio, 0); + gpio_free(config[i].gpio); + } + } + } + + return 0; +} + +static int dp_power_client_init(struct dp_power *dp_power, + struct sde_power_handle *phandle, struct drm_device *drm_dev) +{ + int rc = 0; + struct dp_power_private *power; + + if (!drm_dev) { + DP_ERR("invalid drm_dev\n"); + return -EINVAL; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + rc = dp_power_regulator_init(power); + if (rc) { + DP_ERR("failed to init regulators\n"); + goto error_power; + } + + rc = dp_power_clk_init(power, true); + if (rc) { + DP_ERR("failed to init clocks\n"); + goto error_clk; + } + dp_power->phandle = phandle; + dp_power->drm_dev = drm_dev; + + return 0; + +error_clk: + dp_power_regulator_deinit(power); +error_power: + return rc; +} + +static void dp_power_client_deinit(struct dp_power *dp_power) +{ + struct dp_power_private *power; + + if (!dp_power) { + DP_ERR("invalid power data\n"); + return; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + dp_power_clk_init(power, false); + dp_power_regulator_deinit(power); +} + +static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power, u32 strm_id) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power || strm_id >= DP_STREAM_MAX) { + DP_ERR("invalid power data. stream %d\n", strm_id); + rc = -EINVAL; + goto exit; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + if (strm_id == DP_STREAM_0) { + if (power->pixel_clk_rcg && power->pixel_parent) + clk_set_parent(power->pixel_clk_rcg, + power->pixel_parent); + } else if (strm_id == DP_STREAM_1) { + if (power->pixel1_clk_rcg && power->pixel1_parent) + clk_set_parent(power->pixel1_clk_rcg, + power->pixel1_parent); + } +exit: + return rc; +} + +static u64 dp_power_clk_get_rate(struct dp_power *dp_power, char *clk_name) +{ + size_t i; + enum dp_pm_type j; + struct dss_module_power *mp; + struct dp_power_private *power; + bool clk_found = false; + u64 rate = 0; + + if (!clk_name) { + DP_ERR("invalid pointer for clk_name\n"); + return 0; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + mp = &dp_power->phandle->mp; + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clk_name)) { + rate = clk_get_rate(mp->clk_config[i].clk); + clk_found = true; + break; + } + } + + for (j = DP_CORE_PM; j < DP_MAX_PM && !clk_found; j++) { + mp = &power->parser->mp[j]; + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clk_name)) { + rate = clk_get_rate(mp->clk_config[i].clk); + clk_found = true; + break; + } + } + } + + return rate; +} + +static int dp_power_init(struct dp_power *dp_power, bool flip) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power) { + DP_ERR("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + rc = dp_power_regulator_ctrl(power, true); + if (rc) { + DP_ERR("failed to enable regulators\n"); + goto exit; + } + + rc = dp_power_pinctrl_set(power, true); + if (rc) { + DP_ERR("failed to set pinctrl state\n"); + goto err_pinctrl; + } + + rc = dp_power_config_gpios(power, flip, true); + if (rc) { + DP_ERR("failed to enable gpios\n"); + goto err_gpio; + } + + rc = pm_runtime_get_sync(dp_power->drm_dev->dev); + if (rc < 0) { + DP_ERR("Power resource enable failed\n"); + goto err_sde_power; + } + + rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); + if (rc) { + DP_ERR("failed to enable DP core clocks\n"); + goto err_clk; + } + + return 0; + +err_clk: + pm_runtime_put_sync(dp_power->drm_dev->dev); +err_sde_power: + dp_power_config_gpios(power, flip, false); +err_gpio: + dp_power_pinctrl_set(power, false); +err_pinctrl: + dp_power_regulator_ctrl(power, false); +exit: + return rc; +} + +static int dp_power_deinit(struct dp_power *dp_power) +{ + int rc = 0; + struct dp_power_private *power; + + if (!dp_power) { + DP_ERR("invalid power data\n"); + rc = -EINVAL; + goto exit; + } + + power = container_of(dp_power, struct dp_power_private, dp_power); + + if (power->link_clks_on) + dp_power_clk_enable(dp_power, DP_LINK_PM, false); + + dp_power_clk_enable(dp_power, DP_CORE_PM, false); + pm_runtime_put_sync(dp_power->drm_dev->dev); + + dp_power_config_gpios(power, false, false); + dp_power_pinctrl_set(power, false); + dp_power_regulator_ctrl(power, false); +exit: + return rc; +} + +struct dp_power *dp_power_get(struct dp_parser *parser) +{ + int rc = 0; + struct dp_power_private *power; + struct dp_power *dp_power; + + if (!parser) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL); + if (!power) { + rc = -ENOMEM; + goto error; + } + + power->parser = parser; + power->pdev = parser->pdev; + + dp_power = &power->dp_power; + + dp_power->init = dp_power_init; + dp_power->deinit = dp_power_deinit; + dp_power->clk_enable = dp_power_clk_enable; + dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent; + dp_power->clk_get_rate = dp_power_clk_get_rate; + dp_power->power_client_init = dp_power_client_init; + dp_power->power_client_deinit = dp_power_client_deinit; + + return dp_power; +error: + return ERR_PTR(rc); +} + +void dp_power_put(struct dp_power *dp_power) +{ + struct dp_power_private *power = NULL; + + if (!dp_power) + return; + + power = container_of(dp_power, struct dp_power_private, dp_power); + + devm_kfree(&power->pdev->dev, power); +} diff --git a/techpack/display/msm/dp/dp_power.h b/techpack/display/msm/dp/dp_power.h new file mode 100644 index 0000000000000000000000000000000000000000..a5e5f5d93e90288e7288e1e6f9216b9a8b99ded8 --- /dev/null +++ b/techpack/display/msm/dp/dp_power.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_POWER_H_ +#define _DP_POWER_H_ + +#include "dp_parser.h" +#include "sde_power_handle.h" + +/** + * sruct dp_power - DisplayPort's power related data + * + * @init: initializes the regulators/core clocks/GPIOs/pinctrl + * @deinit: turns off the regulators/core clocks/GPIOs/pinctrl + * @clk_enable: enable/disable the DP clocks + * @set_pixel_clk_parent: set the parent of DP pixel clock + * @clk_get_rate: get the current rate for provided clk_name + */ +struct dp_power { + struct drm_device *drm_dev; + struct sde_power_handle *phandle; + int (*init)(struct dp_power *power, bool flip); + int (*deinit)(struct dp_power *power); + int (*clk_enable)(struct dp_power *power, enum dp_pm_type pm_type, + bool enable); + int (*set_pixel_clk_parent)(struct dp_power *power, u32 stream_id); + u64 (*clk_get_rate)(struct dp_power *power, char *clk_name); + int (*power_client_init)(struct dp_power *power, + struct sde_power_handle *phandle, + struct drm_device *drm_dev); + void (*power_client_deinit)(struct dp_power *power); +}; + +/** + * dp_power_get() - configure and get the DisplayPort power module data + * + * @parser: instance of parser module + * return: pointer to allocated power module data + * + * This API will configure the DisplayPort's power module and provides + * methods to be called by the client to configure the power related + * modueles. + */ +struct dp_power *dp_power_get(struct dp_parser *parser); + +/** + * dp_power_put() - release the power related resources + * + * @power: pointer to the power module's data + */ +void dp_power_put(struct dp_power *power); +#endif /* _DP_POWER_H_ */ diff --git a/techpack/display/msm/dp/dp_reg.h b/techpack/display/msm/dp/dp_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..df6a8d3ce8c4e5301d4209b1fa575394cdec2d27 --- /dev/null +++ b/techpack/display/msm/dp/dp_reg.h @@ -0,0 +1,443 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_REG_H_ +#define _DP_REG_H_ + +/* DP_TX Registers */ +#define DP_HW_VERSION (0x00000000) +#define DP_SW_RESET (0x00000010) +#define DP_PHY_CTRL (0x00000014) +#define DP_CLK_CTRL (0x00000018) +#define DP_CLK_ACTIVE (0x0000001C) +#define DP_INTR_STATUS (0x00000020) +#define DP_INTR_STATUS2 (0x00000024) +#define DP_INTR_STATUS3 (0x00000028) +#define DP_INTR_STATUS5 (0x00000034) + +#define DP_DP_HPD_CTRL (0x00000000) +#define DP_DP_HPD_INT_STATUS (0x00000004) +#define DP_DP_HPD_INT_ACK (0x00000008) +#define DP_DP_HPD_INT_MASK (0x0000000C) +#define DP_DP_HPD_REFTIMER (0x00000018) +#define DP_DP_HPD_EVENT_TIME_0 (0x0000001C) +#define DP_DP_HPD_EVENT_TIME_1 (0x00000020) +#define DP_AUX_CTRL (0x00000030) +#define DP_AUX_DATA (0x00000034) +#define DP_AUX_TRANS_CTRL (0x00000038) +#define DP_TIMEOUT_COUNT (0x0000003C) +#define DP_AUX_LIMITS (0x00000040) +#define DP_AUX_STATUS (0x00000044) + +#define DP_DPCD_CP_IRQ (0x201) +#define DP_DPCD_RXSTATUS (0x69493) + +#define DP_INTERRUPT_TRANS_NUM (0x000000A0) + +#define DP_MAINLINK_CTRL (0x00000000) +#define DP_STATE_CTRL (0x00000004) +#define DP_CONFIGURATION_CTRL (0x00000008) +#define DP_SOFTWARE_MVID (0x00000010) +#define DP_SOFTWARE_NVID (0x00000018) +#define DP_TOTAL_HOR_VER (0x0000001C) +#define DP_START_HOR_VER_FROM_SYNC (0x00000020) +#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000024) +#define DP_ACTIVE_HOR_VER (0x00000028) +#define DP_MISC1_MISC0 (0x0000002C) +#define DP_VALID_BOUNDARY (0x00000030) +#define DP_VALID_BOUNDARY_2 (0x00000034) +#define DP_LOGICAL2PHYSICAL_LANE_MAPPING (0x00000038) + +#define DP1_CONFIGURATION_CTRL (0x00000400) +#define DP_DP0_TIMESLOT_1_32 (0x00000404) +#define DP_DP0_TIMESLOT_33_63 (0x00000408) +#define DP_DP1_TIMESLOT_1_32 (0x0000040C) +#define DP_DP1_TIMESLOT_33_63 (0x00000410) +#define DP1_SOFTWARE_MVID (0x00000414) +#define DP1_SOFTWARE_NVID (0x00000418) +#define DP1_TOTAL_HOR_VER (0x0000041C) +#define DP1_START_HOR_VER_FROM_SYNC (0x00000420) +#define DP1_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424) +#define DP1_ACTIVE_HOR_VER (0x00000428) +#define DP1_MISC1_MISC0 (0x0000042C) +#define DP_DP0_RG (0x000004F8) +#define DP_DP1_RG (0x000004FC) + +#define DP_MST_ACT (0x00000500) +#define DP_MST_MAINLINK_READY (0x00000504) + +#define DP_MAINLINK_READY (0x00000040) +#define DP_MAINLINK_LEVELS (0x00000044) +#define DP_TU (0x0000004C) + +#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000054) +#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000000C0) +#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000000C4) +#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000000C8) + +#define MMSS_DP_MISC1_MISC0 (0x0000002C) +#define MMSS_DP_AUDIO_TIMING_GEN (0x00000080) +#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000084) +#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000088) +#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000008C) +#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000090) +#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000094) +#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000098) + +#define MMSS_DP_PSR_CRC_RG (0x00000154) +#define MMSS_DP_PSR_CRC_B (0x00000158) + +#define DP_COMPRESSION_MODE_CTRL (0x00000180) +#define DP_PPS_HB_0_3 (0x00000184) +#define DP_PPS_PB_0_3 (0x00000188) +#define DP_PPS_PB_4_7 (0x0000018C) +#define DP_PPS_PB_8_11 (0x00000190) +#define DP_PPS_PB_12_15 (0x00000194) +#define DP_PPS_PB_16_19 (0x00000198) +#define DP_PPS_PB_20_23 (0x0000019C) +#define DP_PPS_PB_24_27 (0x000001A0) +#define DP_PPS_PB_28_31 (0x000001A4) +#define DP_PPS_PPS_0_3 (0x000001A8) +#define DP_PPS_PPS_4_7 (0x000001AC) +#define DP_PPS_PPS_8_11 (0x000001B0) +#define DP_PPS_PPS_12_15 (0x000001B4) +#define DP_PPS_PPS_16_19 (0x000001B8) +#define DP_PPS_PPS_20_23 (0x000001BC) +#define DP_PPS_PPS_24_27 (0x000001C0) +#define DP_PPS_PPS_28_31 (0x000001C4) +#define DP_PPS_PPS_32_35 (0x000001C8) +#define DP_PPS_PPS_36_39 (0x000001CC) +#define DP_PPS_PPS_40_43 (0x000001D0) +#define DP_PPS_PPS_44_47 (0x000001D4) +#define DP_PPS_PPS_48_51 (0x000001D8) +#define DP_PPS_PPS_52_55 (0x000001DC) +#define DP_PPS_PPS_56_59 (0x000001E0) +#define DP_PPS_PPS_60_63 (0x000001E4) +#define DP_PPS_PPS_64_67 (0x000001E8) +#define DP_PPS_PPS_68_71 (0x000001EC) +#define DP_PPS_PPS_72_75 (0x000001F0) +#define DP_PPS_PPS_76_79 (0x000001F4) +#define DP_PPS_PPS_80_83 (0x000001F8) +#define DP_PPS_PPS_84_87 (0x000001FC) + +#define MMSS_DP_AUDIO_CFG (0x00000200) +#define MMSS_DP_AUDIO_STATUS (0x00000204) +#define MMSS_DP_AUDIO_PKT_CTRL (0x00000208) +#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000020C) +#define MMSS_DP_AUDIO_ACR_CTRL (0x00000210) +#define MMSS_DP_AUDIO_CTRL_RESET (0x00000214) + +#define MMSS_DP_SDP_CFG (0x00000228) +#define MMSS_DP_SDP_CFG2 (0x0000022C) +#define MMSS_DP_SDP_CFG3 (0x0000024C) +#define MMSS_DP_SDP_CFG4 (0x000004EC) +#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000230) +#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000234) + +#define MMSS_DP_AUDIO_STREAM_0 (0x00000240) +#define MMSS_DP_AUDIO_STREAM_1 (0x00000244) + +#define MMSS_DP_EXTENSION_0 (0x00000250) +#define MMSS_DP_EXTENSION_1 (0x00000254) +#define MMSS_DP_EXTENSION_2 (0x00000258) +#define MMSS_DP_EXTENSION_3 (0x0000025C) +#define MMSS_DP_EXTENSION_4 (0x00000260) +#define MMSS_DP_EXTENSION_5 (0x00000264) +#define MMSS_DP_EXTENSION_6 (0x00000268) +#define MMSS_DP_EXTENSION_7 (0x0000026C) +#define MMSS_DP_EXTENSION_8 (0x00000270) +#define MMSS_DP_EXTENSION_9 (0x00000274) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000278) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000027C) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000280) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000284) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000288) +#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000028C) +#define MMSS_DP_AUDIO_ISRC_0 (0x00000290) +#define MMSS_DP_AUDIO_ISRC_1 (0x00000294) +#define MMSS_DP_AUDIO_ISRC_2 (0x00000298) +#define MMSS_DP_AUDIO_ISRC_3 (0x0000029C) +#define MMSS_DP_AUDIO_ISRC_4 (0x000002A0) +#define MMSS_DP_AUDIO_ISRC_5 (0x000002A4) +#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000002A8) +#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000002AC) +#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000002B0) + +#define MMSS_DP_FLUSH (0x000002F8) +#define MMSS_DP1_FLUSH (0x000002FC) + +#define MMSS_DP_GENERIC0_0 (0x00000300) +#define MMSS_DP_GENERIC0_1 (0x00000304) +#define MMSS_DP_GENERIC0_2 (0x00000308) +#define MMSS_DP_GENERIC0_3 (0x0000030C) +#define MMSS_DP_GENERIC0_4 (0x00000310) +#define MMSS_DP_GENERIC0_5 (0x00000314) +#define MMSS_DP_GENERIC0_6 (0x00000318) +#define MMSS_DP_GENERIC0_7 (0x0000031C) +#define MMSS_DP_GENERIC0_8 (0x00000320) +#define MMSS_DP_GENERIC0_9 (0x00000324) +#define MMSS_DP_GENERIC1_0 (0x00000328) +#define MMSS_DP_GENERIC1_1 (0x0000032C) +#define MMSS_DP_GENERIC1_2 (0x00000330) +#define MMSS_DP_GENERIC1_3 (0x00000334) +#define MMSS_DP_GENERIC1_4 (0x00000338) +#define MMSS_DP_GENERIC1_5 (0x0000033C) +#define MMSS_DP_GENERIC1_6 (0x00000340) +#define MMSS_DP_GENERIC1_7 (0x00000344) +#define MMSS_DP_GENERIC1_8 (0x00000348) +#define MMSS_DP_GENERIC1_9 (0x0000034C) + +#define MMSS_DP1_GENERIC0_0 (0x00000490) +#define MMSS_DP1_GENERIC0_1 (0x00000494) +#define MMSS_DP1_GENERIC0_2 (0x00000498) +#define MMSS_DP1_GENERIC0_3 (0x0000049C) +#define MMSS_DP1_GENERIC0_4 (0x000004A0) +#define MMSS_DP1_GENERIC0_5 (0x000004A4) +#define MMSS_DP1_GENERIC0_6 (0x000004A8) +#define MMSS_DP1_GENERIC0_7 (0x000004AC) +#define MMSS_DP1_GENERIC0_8 (0x000004B0) +#define MMSS_DP1_GENERIC0_9 (0x000004B4) +#define MMSS_DP1_GENERIC1_0 (0x000004B8) +#define MMSS_DP1_GENERIC1_1 (0x000004BC) +#define MMSS_DP1_GENERIC1_2 (0x000004C0) +#define MMSS_DP1_GENERIC1_3 (0x000004C4) +#define MMSS_DP1_GENERIC1_4 (0x000004C8) +#define MMSS_DP1_GENERIC1_5 (0x000004CC) +#define MMSS_DP1_GENERIC1_6 (0x000004D0) +#define MMSS_DP1_GENERIC1_7 (0x000004D4) +#define MMSS_DP1_GENERIC1_8 (0x000004D8) +#define MMSS_DP1_GENERIC1_9 (0x000004DC) + +#define MMSS_DP_GENERIC2_0 (0x000003d8) +#define MMSS_DP_GENERIC2_1 (0x000003dc) +#define MMSS_DP_GENERIC2_2 (0x000003e0) +#define MMSS_DP_GENERIC2_3 (0x000003e4) +#define MMSS_DP_GENERIC2_4 (0x000003e8) +#define MMSS_DP_GENERIC2_5 (0x000003ec) +#define MMSS_DP_GENERIC2_6 (0x000003f0) +#define MMSS_DP_GENERIC2_7 (0x000003f4) +#define MMSS_DP_GENERIC2_8 (0x000003f8) +#define MMSS_DP_GENERIC2_9 (0x000003fc) +#define MMSS_DP1_GENERIC2_0 (0x00000510) +#define MMSS_DP1_GENERIC2_1 (0x00000514) +#define MMSS_DP1_GENERIC2_2 (0x00000518) +#define MMSS_DP1_GENERIC2_3 (0x0000051c) +#define MMSS_DP1_GENERIC2_4 (0x00000520) +#define MMSS_DP1_GENERIC2_5 (0x00000524) +#define MMSS_DP1_GENERIC2_6 (0x00000528) +#define MMSS_DP1_GENERIC2_7 (0x0000052C) +#define MMSS_DP1_GENERIC2_8 (0x00000530) +#define MMSS_DP1_GENERIC2_9 (0x00000534) + +#define MMSS_DP1_SDP_CFG (0x000004E0) +#define MMSS_DP1_SDP_CFG2 (0x000004E4) +#define MMSS_DP1_SDP_CFG3 (0x000004E8) +#define MMSS_DP1_SDP_CFG4 (0x000004F0) + +#define DP1_COMPRESSION_MODE_CTRL (0x00000560) +#define DP1_PPS_HB_0_3 (0x00000564) +#define DP1_PPS_PB_0_3 (0x00000568) +#define DP1_PPS_PB_4_7 (0x0000056C) +#define DP1_PPS_PB_8_11 (0x00000570) +#define DP1_PPS_PB_12_15 (0x00000574) +#define DP1_PPS_PB_16_19 (0x00000578) +#define DP1_PPS_PB_20_23 (0x0000057C) +#define DP1_PPS_PB_24_27 (0x00000580) +#define DP1_PPS_PB_28_31 (0x00000584) +#define DP1_PPS_PPS_0_3 (0x00000588) +#define DP1_PPS_PPS_4_7 (0x0000058C) +#define DP1_PPS_PPS_8_11 (0x00000590) +#define DP1_PPS_PPS_12_15 (0x00000594) +#define DP1_PPS_PPS_16_19 (0x00000598) +#define DP1_PPS_PPS_20_23 (0x0000059C) +#define DP1_PPS_PPS_24_27 (0x000005A0) +#define DP1_PPS_PPS_28_31 (0x000005A4) +#define DP1_PPS_PPS_32_35 (0x000005A8) +#define DP1_PPS_PPS_36_39 (0x000005AC) +#define DP1_PPS_PPS_40_43 (0x000005B0) +#define DP1_PPS_PPS_44_47 (0x000005B4) +#define DP1_PPS_PPS_48_51 (0x000005B8) +#define DP1_PPS_PPS_52_55 (0x000005BC) +#define DP1_PPS_PPS_56_59 (0x000005C0) +#define DP1_PPS_PPS_60_63 (0x000005C4) +#define DP1_PPS_PPS_64_67 (0x000005C8) +#define DP1_PPS_PPS_68_71 (0x000005CC) +#define DP1_PPS_PPS_72_75 (0x000005D0) +#define DP1_PPS_PPS_76_79 (0x000005D4) +#define DP1_PPS_PPS_80_83 (0x000005D8) +#define DP1_PPS_PPS_84_87 (0x000005DC) + +#define MMSS_DP_VSCEXT_0 (0x000002D0) +#define MMSS_DP_VSCEXT_1 (0x000002D4) +#define MMSS_DP_VSCEXT_2 (0x000002D8) +#define MMSS_DP_VSCEXT_3 (0x000002DC) +#define MMSS_DP_VSCEXT_4 (0x000002E0) +#define MMSS_DP_VSCEXT_5 (0x000002E4) +#define MMSS_DP_VSCEXT_6 (0x000002E8) +#define MMSS_DP_VSCEXT_7 (0x000002EC) +#define MMSS_DP_VSCEXT_8 (0x000002F0) +#define MMSS_DP_VSCEXT_9 (0x000002F4) + +#define MMSS_DP1_VSCEXT_0 (0x00000468) +#define MMSS_DP1_VSCEXT_1 (0x0000046c) +#define MMSS_DP1_VSCEXT_2 (0x00000470) +#define MMSS_DP1_VSCEXT_3 (0x00000474) +#define MMSS_DP1_VSCEXT_4 (0x00000478) +#define MMSS_DP1_VSCEXT_5 (0x0000047c) +#define MMSS_DP1_VSCEXT_6 (0x00000480) +#define MMSS_DP1_VSCEXT_7 (0x00000484) +#define MMSS_DP1_VSCEXT_8 (0x00000488) +#define MMSS_DP1_VSCEXT_9 (0x0000048c) + +#define MMSS_DP_BIST_ENABLE (0x00000000) +#define MMSS_DP_TIMING_ENGINE_EN (0x00000010) +#define MMSS_DP_INTF_CONFIG (0x00000014) +#define MMSS_DP_INTF_HSYNC_CTL (0x00000018) +#define MMSS_DP_INTF_VSYNC_PERIOD_F0 (0x0000001C) +#define MMSS_DP_INTF_VSYNC_PERIOD_F1 (0x00000020) +#define MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0 (0x00000024) +#define MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1 (0x00000028) +#define MMSS_INTF_DISPLAY_V_START_F0 (0x0000002C) +#define MMSS_INTF_DISPLAY_V_START_F1 (0x00000030) +#define MMSS_DP_INTF_DISPLAY_V_END_F0 (0x00000034) +#define MMSS_DP_INTF_DISPLAY_V_END_F1 (0x00000038) +#define MMSS_DP_INTF_ACTIVE_V_START_F0 (0x0000003C) +#define MMSS_DP_INTF_ACTIVE_V_START_F1 (0x00000040) +#define MMSS_DP_INTF_ACTIVE_V_END_F0 (0x00000044) +#define MMSS_DP_INTF_ACTIVE_V_END_F1 (0x00000048) +#define MMSS_DP_INTF_DISPLAY_HCTL (0x0000004C) +#define MMSS_DP_INTF_ACTIVE_HCTL (0x00000050) +#define MMSS_DP_INTF_POLARITY_CTL (0x00000058) +#define MMSS_DP_TPG_MAIN_CONTROL (0x00000060) +#define MMSS_DP_TPG_VIDEO_CONFIG (0x00000064) +#define MMSS_DP_DSC_DTO (0x0000007C) +#define MMSS_DP_DSC_DTO_COUNT (0x00000084) +#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000088) + +#define MMSS_DP1_BIST_ENABLE (0x00000000) +#define MMSS_DP1_TIMING_ENGINE_EN (0x00000010) +#define MMSS_DP1_INTF_CONFIG (0x00000014) +#define MMSS_DP1_INTF_HSYNC_CTL (0x00000018) +#define MMSS_DP1_INTF_VSYNC_PERIOD_F0 (0x0000001C) +#define MMSS_DP1_INTF_VSYNC_PERIOD_F1 (0x00000020) +#define MMSS_DP1_INTF_VSYNC_PULSE_WIDTH_F0 (0x00000024) +#define MMSS_DP1_INTF_VSYNC_PULSE_WIDTH_F1 (0x00000028) +#define MMSS_DP1_INTF_DISPLAY_V_START_F0 (0x0000002C) +#define MMSS_DP1_INTF_DISPLAY_V_START_F1 (0x00000030) +#define MMSS_DP1_INTF_DISPLAY_V_END_F0 (0x00000034) +#define MMSS_DP1_INTF_DISPLAY_V_END_F1 (0x00000038) +#define MMSS_DP1_INTF_ACTIVE_V_START_F0 (0x0000003C) +#define MMSS_DP1_INTF_ACTIVE_V_START_F1 (0x00000040) +#define MMSS_DP1_INTF_ACTIVE_V_END_F0 (0x00000044) +#define MMSS_DP1_INTF_ACTIVE_V_END_F1 (0x00000048) +#define MMSS_DP1_INTF_DISPLAY_HCTL (0x0000004C) +#define MMSS_DP1_INTF_ACTIVE_HCTL (0x00000050) +#define MMSS_DP1_INTF_POLARITY_CTL (0x00000058) +#define MMSS_DP1_TPG_MAIN_CONTROL (0x00000060) +#define MMSS_DP1_TPG_VIDEO_CONFIG (0x00000064) +#define MMSS_DP1_DSC_DTO (0x0000007C) +#define MMSS_DP1_DSC_DTO_COUNT (0x00000084) +#define MMSS_DP1_ASYNC_FIFO_CONFIG (0x00000088) + +/*DP PHY Register offsets */ +#define DP_PHY_REVISION_ID0 (0x00000000) +#define DP_PHY_REVISION_ID1 (0x00000004) +#define DP_PHY_REVISION_ID2 (0x00000008) +#define DP_PHY_REVISION_ID3 (0x0000000C) + +#define DP_PHY_CFG (0x00000010) +#define DP_PHY_PD_CTL (0x00000018) +#define DP_PHY_MODE (0x0000001C) + +#define DP_PHY_AUX_CFG0 (0x00000020) +#define DP_PHY_AUX_CFG1 (0x00000024) +#define DP_PHY_AUX_CFG2 (0x00000028) +#define DP_PHY_AUX_CFG3 (0x0000002C) +#define DP_PHY_AUX_CFG4 (0x00000030) +#define DP_PHY_AUX_CFG5 (0x00000034) +#define DP_PHY_AUX_CFG6 (0x00000038) +#define DP_PHY_AUX_CFG7 (0x0000003C) +#define DP_PHY_AUX_CFG8 (0x00000040) +#define DP_PHY_AUX_CFG9 (0x00000044) +#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048) +#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C) +#define DP_PHY_AUX_INTERRUPT_STATUS (0x000000BC) +#define DP_PHY_AUX_INTERRUPT_MASK_V200 (0x00000048) +#define DP_PHY_AUX_INTERRUPT_CLEAR_V200 (0x0000004C) +#define DP_PHY_AUX_INTERRUPT_STATUS_V200 (0x000000BC) + +#define DP_PHY_SPARE0 (0x00AC) + +#define TXn_TX_EMP_POST1_LVL (0x000C) +#define TXn_TX_DRV_LVL (0x001C) +#define TXn_TX_POL_INV (0x0064) + +#define TXn_TRANSCEIVER_BIAS_EN (0x005C) +#define TXn_HIGHZ_DRVR_EN (0x0060) + +#define DP_PHY_STATUS_V420 (0x00DC) +#define DP_PHY_AUX_INTERRUPT_MASK_V420 (0x0054) +#define DP_PHY_AUX_INTERRUPT_CLEAR_V420 (0x0058) +#define DP_PHY_AUX_INTERRUPT_STATUS_V420 (0x00D8) +#define DP_PHY_SPARE0_V420 (0x00C8) +#define TXn_TX_DRV_LVL_V420 (0x0014) +#define TXn_TRANSCEIVER_BIAS_EN_V420 (0x0054) +#define TXn_HIGHZ_DRVR_EN_V420 (0x0058) +#define TXn_TX_POL_INV_V420 (0x005C) + +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004) + +/* DP MMSS_CC registers */ +#define MMSS_DP_LINK_CMD_RCGR (0x0138) +#define MMSS_DP_LINK_CFG_RCGR (0x013C) +#define MMSS_DP_PIXEL_M (0x0134) +#define MMSS_DP_PIXEL_N (0x0138) +#define MMSS_DP_PIXEL1_M (0x01CC) +#define MMSS_DP_PIXEL1_N (0x01D0) +#define MMSS_DP_PIXEL_M_V200 (0x0130) +#define MMSS_DP_PIXEL_N_V200 (0x0134) +#define MMSS_DP_PIXEL1_M_V200 (0x0148) +#define MMSS_DP_PIXEL1_N_V200 (0x014C) +#define MMSS_DP_PIXEL_M_V420 (0x01B4) +#define MMSS_DP_PIXEL_N_V420 (0x01B8) +#define MMSS_DP_PIXEL1_M_V420 (0x01CC) +#define MMSS_DP_PIXEL1_N_V420 (0x01D0) + +/* DP HDCP 1.3 registers */ +#define DP_HDCP_CTRL (0x0A0) +#define DP_HDCP_STATUS (0x0A4) +#define DP_HDCP_SW_UPPER_AKSV (0x098) +#define DP_HDCP_SW_LOWER_AKSV (0x09C) +#define DP_HDCP_ENTROPY_CTRL0 (0x350) +#define DP_HDCP_ENTROPY_CTRL1 (0x35C) +#define DP_HDCP_SHA_STATUS (0x0C8) +#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0) +#define DP_HDCP_RCVPORT_DATA3 (0x0A4) +#define DP_HDCP_RCVPORT_DATA4 (0x0A8) +#define DP_HDCP_RCVPORT_DATA5 (0x0C0) +#define DP_HDCP_RCVPORT_DATA6 (0x0C4) + +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020) + +/* USB3 DP COM registers */ +#define USB3_DP_COM_RESET_OVRD_CTRL (0x1C) +#define USB3_DP_COM_PHY_MODE_CTRL (0x00) +#define USB3_DP_COM_SW_RESET (0x04) +#define USB3_DP_COM_TYPEC_CTRL (0x10) +#define USB3_DP_COM_SWI_CTRL (0x0c) +#define USB3_DP_COM_POWER_DOWN_CTRL (0x08) + + + +#endif /* _DP_REG_H_ */ diff --git a/techpack/display/msm/dp/dp_usbpd.c b/techpack/display/msm/dp/dp_usbpd.c new file mode 100644 index 0000000000000000000000000000000000000000..44cfb710af49ac6e53e35c595dce5059f8fad64b --- /dev/null +++ b/techpack/display/msm/dp/dp_usbpd.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/usb/usbpd.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/delay.h> + +#include "dp_usbpd.h" +#include "dp_debug.h" + +/* DP specific VDM commands */ +#define DP_USBPD_VDM_STATUS 0x10 +#define DP_USBPD_VDM_CONFIGURE 0x11 + +/* USBPD-TypeC specific Macros */ +#define VDM_VERSION 0x0 +#define USB_C_DP_SID 0xFF01 + +enum dp_usbpd_pin_assignment { + DP_USBPD_PIN_A, + DP_USBPD_PIN_B, + DP_USBPD_PIN_C, + DP_USBPD_PIN_D, + DP_USBPD_PIN_E, + DP_USBPD_PIN_F, + DP_USBPD_PIN_MAX, +}; + +enum dp_usbpd_events { + DP_USBPD_EVT_DISCOVER, + DP_USBPD_EVT_ENTER, + DP_USBPD_EVT_STATUS, + DP_USBPD_EVT_CONFIGURE, + DP_USBPD_EVT_CC_PIN_POLARITY, + DP_USBPD_EVT_EXIT, + DP_USBPD_EVT_ATTENTION, +}; + +enum dp_usbpd_alt_mode { + DP_USBPD_ALT_MODE_NONE = 0, + DP_USBPD_ALT_MODE_INIT = BIT(0), + DP_USBPD_ALT_MODE_DISCOVER = BIT(1), + DP_USBPD_ALT_MODE_ENTER = BIT(2), + DP_USBPD_ALT_MODE_STATUS = BIT(3), + DP_USBPD_ALT_MODE_CONFIGURE = BIT(4), +}; + +struct dp_usbpd_capabilities { + enum dp_usbpd_port port; + bool receptacle_state; + u8 ulink_pin_config; + u8 dlink_pin_config; +}; + +struct dp_usbpd_private { + bool forced_disconnect; + u32 vdo; + struct device *dev; + struct usbpd *pd; + struct usbpd_svid_handler svid_handler; + struct dp_hpd_cb *dp_cb; + struct dp_usbpd_capabilities cap; + struct dp_usbpd dp_usbpd; + enum dp_usbpd_alt_mode alt_mode; + u32 dp_usbpd_config; +}; + +static const char *dp_usbpd_pin_name(u8 pin) +{ + switch (pin) { + case DP_USBPD_PIN_A: return "DP_USBPD_PIN_ASSIGNMENT_A"; + case DP_USBPD_PIN_B: return "DP_USBPD_PIN_ASSIGNMENT_B"; + case DP_USBPD_PIN_C: return "DP_USBPD_PIN_ASSIGNMENT_C"; + case DP_USBPD_PIN_D: return "DP_USBPD_PIN_ASSIGNMENT_D"; + case DP_USBPD_PIN_E: return "DP_USBPD_PIN_ASSIGNMENT_E"; + case DP_USBPD_PIN_F: return "DP_USBPD_PIN_ASSIGNMENT_F"; + default: return "UNKNOWN"; + } +} + +static const char *dp_usbpd_port_name(enum dp_usbpd_port port) +{ + switch (port) { + case DP_USBPD_PORT_NONE: return "DP_USBPD_PORT_NONE"; + case DP_USBPD_PORT_UFP_D: return "DP_USBPD_PORT_UFP_D"; + case DP_USBPD_PORT_DFP_D: return "DP_USBPD_PORT_DFP_D"; + case DP_USBPD_PORT_D_UFP_D: return "DP_USBPD_PORT_D_UFP_D"; + default: return "DP_USBPD_PORT_NONE"; + } +} + +static const char *dp_usbpd_cmd_name(u8 cmd) +{ + switch (cmd) { + case USBPD_SVDM_DISCOVER_MODES: return "USBPD_SVDM_DISCOVER_MODES"; + case USBPD_SVDM_ENTER_MODE: return "USBPD_SVDM_ENTER_MODE"; + case USBPD_SVDM_ATTENTION: return "USBPD_SVDM_ATTENTION"; + case DP_USBPD_VDM_STATUS: return "DP_USBPD_VDM_STATUS"; + case DP_USBPD_VDM_CONFIGURE: return "DP_USBPD_VDM_CONFIGURE"; + default: return "DP_USBPD_VDM_ERROR"; + } +} + +static void dp_usbpd_init_port(enum dp_usbpd_port *port, u32 in_port) +{ + switch (in_port) { + case 0: + *port = DP_USBPD_PORT_NONE; + break; + case 1: + *port = DP_USBPD_PORT_UFP_D; + break; + case 2: + *port = DP_USBPD_PORT_DFP_D; + break; + case 3: + *port = DP_USBPD_PORT_D_UFP_D; + break; + default: + *port = DP_USBPD_PORT_NONE; + } + DP_DEBUG("port:%s\n", dp_usbpd_port_name(*port)); +} + +static void dp_usbpd_get_capabilities(struct dp_usbpd_private *pd) +{ + struct dp_usbpd_capabilities *cap = &pd->cap; + u32 buf = pd->vdo; + int port = buf & 0x3; + + cap->receptacle_state = (buf & BIT(6)) ? true : false; + cap->dlink_pin_config = (buf >> 8) & 0xff; + cap->ulink_pin_config = (buf >> 16) & 0xff; + + dp_usbpd_init_port(&cap->port, port); +} + +static void dp_usbpd_get_status(struct dp_usbpd_private *pd) +{ + struct dp_usbpd *status = &pd->dp_usbpd; + u32 buf = pd->vdo; + int port = buf & 0x3; + + status->low_pow_st = (buf & BIT(2)) ? true : false; + status->adaptor_dp_en = (buf & BIT(3)) ? true : false; + status->base.multi_func = (buf & BIT(4)) ? true : false; + status->usb_config_req = (buf & BIT(5)) ? true : false; + status->exit_dp_mode = (buf & BIT(6)) ? true : false; + status->base.hpd_high = (buf & BIT(7)) ? true : false; + status->base.hpd_irq = (buf & BIT(8)) ? true : false; + + DP_DEBUG("low_pow_st = %d, adaptor_dp_en = %d, multi_func = %d\n", + status->low_pow_st, status->adaptor_dp_en, + status->base.multi_func); + DP_DEBUG("usb_config_req = %d, exit_dp_mode = %d, hpd_high =%d\n", + status->usb_config_req, + status->exit_dp_mode, status->base.hpd_high); + DP_DEBUG("hpd_irq = %d\n", status->base.hpd_irq); + + dp_usbpd_init_port(&status->port, port); +} + +static u32 dp_usbpd_gen_config_pkt(struct dp_usbpd_private *pd) +{ + u8 pin_cfg, pin; + u32 config = 0; + const u32 ufp_d_config = 0x2, dp_ver = 0x1; + + if (pd->cap.receptacle_state) + pin_cfg = pd->cap.ulink_pin_config; + else + pin_cfg = pd->cap.dlink_pin_config; + + for (pin = DP_USBPD_PIN_A; pin < DP_USBPD_PIN_MAX; pin++) { + if (pin_cfg & BIT(pin)) { + if (pd->dp_usbpd.base.multi_func) { + if (pin == DP_USBPD_PIN_D) + break; + } else { + break; + } + } + } + + if (pin == DP_USBPD_PIN_MAX) + pin = DP_USBPD_PIN_C; + + DP_DEBUG("pin assignment: %s\n", dp_usbpd_pin_name(pin)); + + config |= BIT(pin) << 8; + + config |= (dp_ver << 2); + config |= ufp_d_config; + + DP_DEBUG("config = 0x%x\n", config); + return config; +} + +static void dp_usbpd_send_event(struct dp_usbpd_private *pd, + enum dp_usbpd_events event) +{ + u32 config; + + switch (event) { + case DP_USBPD_EVT_DISCOVER: + usbpd_send_svdm(pd->pd, USB_C_DP_SID, + USBPD_SVDM_DISCOVER_MODES, + SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0); + break; + case DP_USBPD_EVT_ENTER: + usbpd_send_svdm(pd->pd, USB_C_DP_SID, + USBPD_SVDM_ENTER_MODE, + SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); + break; + case DP_USBPD_EVT_EXIT: + usbpd_send_svdm(pd->pd, USB_C_DP_SID, + USBPD_SVDM_EXIT_MODE, + SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); + break; + case DP_USBPD_EVT_STATUS: + config = 0x1; /* DFP_D connected */ + usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_STATUS, + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); + break; + case DP_USBPD_EVT_CONFIGURE: + config = dp_usbpd_gen_config_pkt(pd); + usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_CONFIGURE, + SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); + break; + default: + DP_ERR("unknown event:%d\n", event); + } +} + +static void dp_usbpd_connect_cb(struct usbpd_svid_handler *hdlr, + bool peer_usb_comm) +{ + struct dp_usbpd_private *pd; + + pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); + if (!pd) { + DP_ERR("get_usbpd phandle failed\n"); + return; + } + + DP_DEBUG("peer_usb_comm: %d\n", peer_usb_comm); + pd->dp_usbpd.base.peer_usb_comm = peer_usb_comm; + dp_usbpd_send_event(pd, DP_USBPD_EVT_DISCOVER); +} + +static void dp_usbpd_disconnect_cb(struct usbpd_svid_handler *hdlr) +{ + struct dp_usbpd_private *pd; + + pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); + if (!pd) { + DP_ERR("get_usbpd phandle failed\n"); + return; + } + + pd->alt_mode = DP_USBPD_ALT_MODE_NONE; + pd->dp_usbpd.base.alt_mode_cfg_done = false; + DP_DEBUG("\n"); + + if (pd->dp_cb && pd->dp_cb->disconnect) + pd->dp_cb->disconnect(pd->dev); +} + +static int dp_usbpd_validate_callback(u8 cmd, + enum usbpd_svdm_cmd_type cmd_type, int num_vdos) +{ + int ret = 0; + + if (cmd_type == SVDM_CMD_TYPE_RESP_NAK) { + DP_ERR("error: NACK\n"); + ret = -EINVAL; + goto end; + } + + if (cmd_type == SVDM_CMD_TYPE_RESP_BUSY) { + DP_ERR("error: BUSY\n"); + ret = -EBUSY; + goto end; + } + + if (cmd == USBPD_SVDM_ATTENTION) { + if (cmd_type != SVDM_CMD_TYPE_INITIATOR) { + DP_ERR("error: invalid cmd type for attention\n"); + ret = -EINVAL; + goto end; + } + + if (!num_vdos) { + DP_ERR("error: no vdo provided\n"); + ret = -EINVAL; + goto end; + } + } else { + if (cmd_type != SVDM_CMD_TYPE_RESP_ACK) { + DP_ERR("error: invalid cmd type\n"); + ret = -EINVAL; + } + } +end: + return ret; +} + + +static int dp_usbpd_get_ss_lanes(struct dp_usbpd_private *pd) +{ + int rc = 0; + int timeout = 250; + + /* + * By default, USB reserves two lanes for Super Speed. + * Which means DP has remaining two lanes to operate on. + * If multi-function is not supported, request USB to + * release the Super Speed lanes so that DP can use + * all four lanes in case DPCD indicates support for + * four lanes. + */ + if (!pd->dp_usbpd.base.multi_func) { + while (timeout) { + rc = pd->svid_handler.request_usb_ss_lane( + pd->pd, &pd->svid_handler); + if (rc != -EBUSY) + break; + + DP_WARN("USB busy, retry\n"); + + /* wait for hw recommended delay for usb */ + msleep(20); + timeout--; + } + } + + return rc; +} + +static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd, + enum usbpd_svdm_cmd_type cmd_type, + const u32 *vdos, int num_vdos) +{ + struct dp_usbpd_private *pd; + int rc = 0; + + pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); + + DP_DEBUG("callback -> cmd: %s, *vdos = 0x%x, num_vdos = %d\n", + dp_usbpd_cmd_name(cmd), *vdos, num_vdos); + + if (dp_usbpd_validate_callback(cmd, cmd_type, num_vdos)) { + DP_DEBUG("invalid callback received\n"); + return; + } + + switch (cmd) { + case USBPD_SVDM_DISCOVER_MODES: + pd->vdo = *vdos; + dp_usbpd_get_capabilities(pd); + + pd->alt_mode |= DP_USBPD_ALT_MODE_DISCOVER; + + if (pd->cap.port & BIT(0)) + dp_usbpd_send_event(pd, DP_USBPD_EVT_ENTER); + break; + case USBPD_SVDM_ENTER_MODE: + pd->alt_mode |= DP_USBPD_ALT_MODE_ENTER; + + dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS); + break; + case USBPD_SVDM_ATTENTION: + if (pd->forced_disconnect) + break; + + pd->vdo = *vdos; + dp_usbpd_get_status(pd); + + if (!pd->dp_usbpd.base.alt_mode_cfg_done) { + if (pd->dp_usbpd.port & BIT(1)) + dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE); + break; + } + + if (pd->dp_cb && pd->dp_cb->attention) + pd->dp_cb->attention(pd->dev); + + break; + case DP_USBPD_VDM_STATUS: + pd->vdo = *vdos; + dp_usbpd_get_status(pd); + + if (!(pd->alt_mode & DP_USBPD_ALT_MODE_CONFIGURE)) { + pd->alt_mode |= DP_USBPD_ALT_MODE_STATUS; + + if (pd->dp_usbpd.port & BIT(1)) + dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE); + } + break; + case DP_USBPD_VDM_CONFIGURE: + pd->alt_mode |= DP_USBPD_ALT_MODE_CONFIGURE; + pd->dp_usbpd.base.alt_mode_cfg_done = true; + dp_usbpd_get_status(pd); + + pd->dp_usbpd.base.orientation = + usbpd_get_plug_orientation(pd->pd); + + rc = dp_usbpd_get_ss_lanes(pd); + if (rc) { + DP_ERR("failed to get SuperSpeed lanes\n"); + break; + } + + if (pd->dp_cb && pd->dp_cb->configure) + pd->dp_cb->configure(pd->dev); + break; + default: + DP_ERR("unknown cmd: %d\n", cmd); + break; + } +} + +static int dp_usbpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd) +{ + int rc = 0; + struct dp_usbpd *dp_usbpd; + struct dp_usbpd_private *pd; + + if (!dp_hpd) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base); + pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + dp_usbpd->base.hpd_high = hpd; + pd->forced_disconnect = !hpd; + pd->dp_usbpd.base.alt_mode_cfg_done = hpd; + + DP_DEBUG("hpd_high=%d, forced_disconnect=%d, orientation=%d\n", + dp_usbpd->base.hpd_high, pd->forced_disconnect, + pd->dp_usbpd.base.orientation); + if (hpd) + pd->dp_cb->configure(pd->dev); + else + pd->dp_cb->disconnect(pd->dev); + +error: + return rc; +} + +static int dp_usbpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo) +{ + int rc = 0; + struct dp_usbpd *dp_usbpd; + struct dp_usbpd_private *pd; + + dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base); + if (!dp_usbpd) { + DP_ERR("invalid input\n"); + rc = -EINVAL; + goto error; + } + + pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + pd->vdo = vdo; + dp_usbpd_get_status(pd); + + if (pd->dp_cb && pd->dp_cb->attention) + pd->dp_cb->attention(pd->dev); +error: + return rc; +} + +int dp_usbpd_register(struct dp_hpd *dp_hpd) +{ + struct dp_usbpd *dp_usbpd; + struct dp_usbpd_private *usbpd; + int rc = 0; + + if (!dp_hpd) + return -EINVAL; + + dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base); + + usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + rc = usbpd_register_svid(usbpd->pd, &usbpd->svid_handler); + if (rc) + DP_ERR("pd registration failed\n"); + + return rc; +} + +static void dp_usbpd_wakeup_phy(struct dp_hpd *dp_hpd, bool wakeup) +{ + struct dp_usbpd *dp_usbpd; + struct dp_usbpd_private *usbpd; + + dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base); + usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + if (!usbpd->pd) { + DP_ERR("usbpd pointer invalid"); + return; + } + + usbpd_vdm_in_suspend(usbpd->pd, wakeup); +} + +struct dp_hpd *dp_usbpd_get(struct device *dev, struct dp_hpd_cb *cb) +{ + int rc = 0; + const char *pd_phandle = "qcom,dp-usbpd-detection"; + struct usbpd *pd = NULL; + struct dp_usbpd_private *usbpd; + struct dp_usbpd *dp_usbpd; + struct usbpd_svid_handler svid_handler = { + .svid = USB_C_DP_SID, + .vdm_received = NULL, + .connect = &dp_usbpd_connect_cb, + .svdm_received = &dp_usbpd_response_cb, + .disconnect = &dp_usbpd_disconnect_cb, + }; + + if (!cb) { + DP_ERR("invalid cb data\n"); + rc = -EINVAL; + goto error; + } + + pd = devm_usbpd_get_by_phandle(dev, pd_phandle); + if (IS_ERR(pd)) { + DP_ERR("usbpd phandle failed (%ld)\n", PTR_ERR(pd)); + rc = PTR_ERR(pd); + goto error; + } + + usbpd = devm_kzalloc(dev, sizeof(*usbpd), GFP_KERNEL); + if (!usbpd) { + rc = -ENOMEM; + goto error; + } + + usbpd->dev = dev; + usbpd->pd = pd; + usbpd->svid_handler = svid_handler; + usbpd->dp_cb = cb; + + dp_usbpd = &usbpd->dp_usbpd; + dp_usbpd->base.simulate_connect = dp_usbpd_simulate_connect; + dp_usbpd->base.simulate_attention = dp_usbpd_simulate_attention; + dp_usbpd->base.register_hpd = dp_usbpd_register; + dp_usbpd->base.wakeup_phy = dp_usbpd_wakeup_phy; + + return &dp_usbpd->base; +error: + return ERR_PTR(rc); +} + +void dp_usbpd_put(struct dp_hpd *dp_hpd) +{ + struct dp_usbpd *dp_usbpd; + struct dp_usbpd_private *usbpd; + + dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base); + if (!dp_usbpd) + return; + + usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); + + usbpd_unregister_svid(usbpd->pd, &usbpd->svid_handler); + + devm_kfree(usbpd->dev, usbpd); +} diff --git a/techpack/display/msm/dp/dp_usbpd.h b/techpack/display/msm/dp/dp_usbpd.h new file mode 100644 index 0000000000000000000000000000000000000000..899ac4c5960ccf0ef94fd0c23d3f6a9b94ac63aa --- /dev/null +++ b/techpack/display/msm/dp/dp_usbpd.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DP_USBPD_H_ +#define _DP_USBPD_H_ + +#include <linux/types.h> +#include "dp_hpd.h" + +struct device; + +/** + * enum dp_usbpd_port - usb/dp port type + * @DP_USBPD_PORT_NONE: port not configured + * @DP_USBPD_PORT_UFP_D: Upstream Facing Port - DisplayPort + * @DP_USBPD_PORT_DFP_D: Downstream Facing Port - DisplayPort + * @DP_USBPD_PORT_D_UFP_D: Both UFP & DFP - DisplayPort + */ + +enum dp_usbpd_port { + DP_USBPD_PORT_NONE, + DP_USBPD_PORT_UFP_D, + DP_USBPD_PORT_DFP_D, + DP_USBPD_PORT_D_UFP_D, +}; + +/** + * struct dp_usbpd - DisplayPort status + * + * @port: port configured + * @low_pow_st: low power state + * @adaptor_dp_en: adaptor functionality enabled + * @usb_config_req: request to switch to usb + * @exit_dp_mode: request exit from displayport mode + * @debug_en: bool to specify debug mode + */ +struct dp_usbpd { + struct dp_hpd base; + enum dp_usbpd_port port; + bool low_pow_st; + bool adaptor_dp_en; + bool usb_config_req; + bool exit_dp_mode; + bool debug_en; +}; + +/** + * dp_usbpd_get() - setup usbpd module + * + * @dev: device instance of the caller + * @cb: struct containing callback function pointers. + * + * This function allows the client to initialize the usbpd + * module. The module will communicate with usb driver and + * handles the power delivery (PD) communication with the + * sink/usb device. This module will notify the client using + * the callback functions about the connection and status. + */ +struct dp_hpd *dp_usbpd_get(struct device *dev, struct dp_hpd_cb *cb); + +void dp_usbpd_put(struct dp_hpd *pd); +#endif /* _DP_USBPD_H_ */ diff --git a/techpack/display/msm/dsi/dsi_catalog.c b/techpack/display/msm/dsi/dsi_catalog.c new file mode 100644 index 0000000000000000000000000000000000000000..f26c72964e5abcaeef75ce9d26d140bb4b8d6cfa --- /dev/null +++ b/techpack/display/msm/dsi/dsi_catalog.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/errno.h> + +#include "dsi_catalog.h" + +/** + * dsi_catalog_cmn_init() - catalog init for dsi controller v1.4 + */ +static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, + enum dsi_ctrl_version version) +{ + /* common functions */ + ctrl->ops.host_setup = dsi_ctrl_hw_cmn_host_setup; + ctrl->ops.video_engine_en = dsi_ctrl_hw_cmn_video_engine_en; + ctrl->ops.video_engine_setup = dsi_ctrl_hw_cmn_video_engine_setup; + ctrl->ops.set_video_timing = dsi_ctrl_hw_cmn_set_video_timing; + ctrl->ops.set_timing_db = dsi_ctrl_hw_cmn_set_timing_db; + ctrl->ops.cmd_engine_setup = dsi_ctrl_hw_cmn_cmd_engine_setup; + ctrl->ops.setup_cmd_stream = dsi_ctrl_hw_cmn_setup_cmd_stream; + ctrl->ops.ctrl_en = dsi_ctrl_hw_cmn_ctrl_en; + ctrl->ops.cmd_engine_en = dsi_ctrl_hw_cmn_cmd_engine_en; + ctrl->ops.phy_sw_reset = dsi_ctrl_hw_cmn_phy_sw_reset; + ctrl->ops.soft_reset = dsi_ctrl_hw_cmn_soft_reset; + ctrl->ops.kickoff_command = dsi_ctrl_hw_cmn_kickoff_command; + ctrl->ops.kickoff_fifo_command = dsi_ctrl_hw_cmn_kickoff_fifo_command; + ctrl->ops.reset_cmd_fifo = dsi_ctrl_hw_cmn_reset_cmd_fifo; + ctrl->ops.trigger_command_dma = dsi_ctrl_hw_cmn_trigger_command_dma; + ctrl->ops.get_interrupt_status = dsi_ctrl_hw_cmn_get_interrupt_status; + ctrl->ops.get_error_status = dsi_ctrl_hw_cmn_get_error_status; + ctrl->ops.clear_error_status = dsi_ctrl_hw_cmn_clear_error_status; + ctrl->ops.clear_interrupt_status = + dsi_ctrl_hw_cmn_clear_interrupt_status; + ctrl->ops.enable_status_interrupts = + dsi_ctrl_hw_cmn_enable_status_interrupts; + ctrl->ops.enable_error_interrupts = + dsi_ctrl_hw_cmn_enable_error_interrupts; + ctrl->ops.video_test_pattern_setup = + dsi_ctrl_hw_cmn_video_test_pattern_setup; + ctrl->ops.cmd_test_pattern_setup = + dsi_ctrl_hw_cmn_cmd_test_pattern_setup; + ctrl->ops.test_pattern_enable = dsi_ctrl_hw_cmn_test_pattern_enable; + ctrl->ops.trigger_cmd_test_pattern = + dsi_ctrl_hw_cmn_trigger_cmd_test_pattern; + ctrl->ops.clear_phy0_ln_err = dsi_ctrl_hw_dln0_phy_err; + ctrl->ops.phy_reset_config = dsi_ctrl_hw_cmn_phy_reset_config; + ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr; + ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr; + ctrl->ops.debug_bus = dsi_ctrl_hw_cmn_debug_bus; + ctrl->ops.get_cmd_read_data = dsi_ctrl_hw_cmn_get_cmd_read_data; + ctrl->ops.clear_rdbk_register = dsi_ctrl_hw_cmn_clear_rdbk_reg; + ctrl->ops.ctrl_reset = dsi_ctrl_hw_cmn_ctrl_reset; + ctrl->ops.mask_error_intr = dsi_ctrl_hw_cmn_mask_error_intr; + ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl; + ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask; + ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version; + ctrl->ops.wait_for_cmd_mode_mdp_idle = + dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle; + ctrl->ops.setup_avr = dsi_ctrl_hw_cmn_setup_avr; + ctrl->ops.set_continuous_clk = dsi_ctrl_hw_cmn_set_continuous_clk; + ctrl->ops.wait4dynamic_refresh_done = + dsi_ctrl_hw_cmn_wait4dynamic_refresh_done; + ctrl->ops.hs_req_sel = dsi_ctrl_hw_cmn_hs_req_sel; + + switch (version) { + case DSI_CTRL_VERSION_1_4: + ctrl->ops.setup_lane_map = dsi_ctrl_hw_14_setup_lane_map; + ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_cmn_ulps_request; + ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_cmn_ulps_exit; + ctrl->ops.wait_for_lane_idle = + dsi_ctrl_hw_14_wait_for_lane_idle; + ctrl->ops.ulps_ops.get_lanes_in_ulps = + dsi_ctrl_hw_cmn_get_lanes_in_ulps; + ctrl->ops.clamp_enable = dsi_ctrl_hw_14_clamp_enable; + ctrl->ops.clamp_disable = dsi_ctrl_hw_14_clamp_disable; + ctrl->ops.reg_dump_to_buffer = + dsi_ctrl_hw_14_reg_dump_to_buffer; + ctrl->ops.schedule_dma_cmd = NULL; + ctrl->ops.kickoff_command_non_embedded_mode = NULL; + ctrl->ops.config_clk_gating = NULL; + break; + case DSI_CTRL_VERSION_2_0: + ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map; + ctrl->ops.wait_for_lane_idle = + dsi_ctrl_hw_20_wait_for_lane_idle; + ctrl->ops.reg_dump_to_buffer = + dsi_ctrl_hw_20_reg_dump_to_buffer; + ctrl->ops.ulps_ops.ulps_request = NULL; + ctrl->ops.ulps_ops.ulps_exit = NULL; + ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL; + ctrl->ops.clamp_enable = NULL; + ctrl->ops.clamp_disable = NULL; + ctrl->ops.schedule_dma_cmd = NULL; + ctrl->ops.kickoff_command_non_embedded_mode = NULL; + ctrl->ops.config_clk_gating = NULL; + break; + case DSI_CTRL_VERSION_2_2: + case DSI_CTRL_VERSION_2_3: + case DSI_CTRL_VERSION_2_4: + ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config; + ctrl->ops.config_clk_gating = dsi_ctrl_hw_22_config_clk_gating; + ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map; + ctrl->ops.wait_for_lane_idle = + dsi_ctrl_hw_20_wait_for_lane_idle; + ctrl->ops.reg_dump_to_buffer = + dsi_ctrl_hw_20_reg_dump_to_buffer; + ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_cmn_ulps_request; + ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_cmn_ulps_exit; + ctrl->ops.ulps_ops.get_lanes_in_ulps = + dsi_ctrl_hw_cmn_get_lanes_in_ulps; + ctrl->ops.clamp_enable = NULL; + ctrl->ops.clamp_disable = NULL; + ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd; + ctrl->ops.kickoff_command_non_embedded_mode = + dsi_ctrl_hw_kickoff_non_embedded_mode; + break; + default: + break; + } +} + +/** + * dsi_catalog_ctrl_setup() - return catalog info for dsi controller + * @ctrl: Pointer to DSI controller hw object. + * @version: DSI controller version. + * @index: DSI controller instance ID. + * @phy_isolation_enabled: DSI controller works isolated from phy. + * @null_insertion_enabled: DSI controller inserts null packet. + * + * This function setups the catalog information in the dsi_ctrl_hw object. + * + * return: error code for failure and 0 for success. + */ +int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, + enum dsi_ctrl_version version, u32 index, + bool phy_isolation_enabled, bool null_insertion_enabled) +{ + int rc = 0; + + if (version == DSI_CTRL_VERSION_UNKNOWN || + version >= DSI_CTRL_VERSION_MAX) { + DSI_ERR("Unsupported version: %d\n", version); + return -ENOTSUPP; + } + + ctrl->index = index; + ctrl->null_insertion_enabled = null_insertion_enabled; + set_bit(DSI_CTRL_VIDEO_TPG, ctrl->feature_map); + set_bit(DSI_CTRL_CMD_TPG, ctrl->feature_map); + set_bit(DSI_CTRL_VARIABLE_REFRESH_RATE, ctrl->feature_map); + set_bit(DSI_CTRL_DYNAMIC_REFRESH, ctrl->feature_map); + set_bit(DSI_CTRL_DESKEW_CALIB, ctrl->feature_map); + set_bit(DSI_CTRL_DPHY, ctrl->feature_map); + + switch (version) { + case DSI_CTRL_VERSION_1_4: + dsi_catalog_cmn_init(ctrl, version); + break; + case DSI_CTRL_VERSION_2_0: + case DSI_CTRL_VERSION_2_2: + case DSI_CTRL_VERSION_2_3: + case DSI_CTRL_VERSION_2_4: + ctrl->phy_isolation_enabled = phy_isolation_enabled; + dsi_catalog_cmn_init(ctrl, version); + break; + default: + return -ENOTSUPP; + } + + return rc; +} + +/** + * dsi_catalog_phy_2_0_init() - catalog init for DSI PHY 14nm + */ +static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy) +{ + phy->ops.regulator_enable = dsi_phy_hw_v2_0_regulator_enable; + phy->ops.regulator_disable = dsi_phy_hw_v2_0_regulator_disable; + phy->ops.enable = dsi_phy_hw_v2_0_enable; + phy->ops.disable = dsi_phy_hw_v2_0_disable; + phy->ops.calculate_timing_params = + dsi_phy_hw_calculate_timing_params; + phy->ops.phy_idle_on = dsi_phy_hw_v2_0_idle_on; + phy->ops.phy_idle_off = dsi_phy_hw_v2_0_idle_off; + phy->ops.calculate_timing_params = + dsi_phy_hw_calculate_timing_params; + phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0; + phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl; + phy->ops.dyn_refresh_ops.dyn_refresh_config = + dsi_phy_hw_v2_0_dyn_refresh_config; + phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay = + dsi_phy_hw_v2_0_dyn_refresh_pipe_delay; + phy->ops.dyn_refresh_ops.dyn_refresh_helper = + dsi_phy_hw_v2_0_dyn_refresh_helper; + phy->ops.dyn_refresh_ops.cache_phy_timings = + dsi_phy_hw_v2_0_cache_phy_timings; +} + +/** + * dsi_catalog_phy_3_0_init() - catalog init for DSI PHY 10nm + */ +static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy) +{ + phy->ops.regulator_enable = dsi_phy_hw_v3_0_regulator_enable; + phy->ops.regulator_disable = dsi_phy_hw_v3_0_regulator_disable; + phy->ops.enable = dsi_phy_hw_v3_0_enable; + phy->ops.disable = dsi_phy_hw_v3_0_disable; + phy->ops.calculate_timing_params = + dsi_phy_hw_calculate_timing_params; + phy->ops.ulps_ops.wait_for_lane_idle = + dsi_phy_hw_v3_0_wait_for_lane_idle; + phy->ops.ulps_ops.ulps_request = + dsi_phy_hw_v3_0_ulps_request; + phy->ops.ulps_ops.ulps_exit = + dsi_phy_hw_v3_0_ulps_exit; + phy->ops.ulps_ops.get_lanes_in_ulps = + dsi_phy_hw_v3_0_get_lanes_in_ulps; + phy->ops.ulps_ops.is_lanes_in_ulps = + dsi_phy_hw_v3_0_is_lanes_in_ulps; + phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0; + phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl; + phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset; + phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo; + phy->ops.dyn_refresh_ops.dyn_refresh_config = + dsi_phy_hw_v3_0_dyn_refresh_config; + phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay = + dsi_phy_hw_v3_0_dyn_refresh_pipe_delay; + phy->ops.dyn_refresh_ops.dyn_refresh_helper = + dsi_phy_hw_v3_0_dyn_refresh_helper; + phy->ops.dyn_refresh_ops.cache_phy_timings = + dsi_phy_hw_v3_0_cache_phy_timings; +} + +/** + * dsi_catalog_phy_4_0_init() - catalog init for DSI PHY 7nm + */ +static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy) +{ + phy->ops.regulator_enable = NULL; + phy->ops.regulator_disable = NULL; + phy->ops.enable = dsi_phy_hw_v4_0_enable; + phy->ops.disable = dsi_phy_hw_v4_0_disable; + phy->ops.calculate_timing_params = + dsi_phy_hw_calculate_timing_params; + phy->ops.ulps_ops.wait_for_lane_idle = + dsi_phy_hw_v4_0_wait_for_lane_idle; + phy->ops.ulps_ops.ulps_request = + dsi_phy_hw_v4_0_ulps_request; + phy->ops.ulps_ops.ulps_exit = + dsi_phy_hw_v4_0_ulps_exit; + phy->ops.ulps_ops.get_lanes_in_ulps = + dsi_phy_hw_v4_0_get_lanes_in_ulps; + phy->ops.ulps_ops.is_lanes_in_ulps = + dsi_phy_hw_v4_0_is_lanes_in_ulps; + phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v4_0; + phy->ops.phy_lane_reset = dsi_phy_hw_v4_0_lane_reset; + phy->ops.toggle_resync_fifo = dsi_phy_hw_v4_0_toggle_resync_fifo; + phy->ops.reset_clk_en_sel = dsi_phy_hw_v4_0_reset_clk_en_sel; + + phy->ops.dyn_refresh_ops.dyn_refresh_config = + dsi_phy_hw_v4_0_dyn_refresh_config; + phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay = + dsi_phy_hw_v4_0_dyn_refresh_pipe_delay; + phy->ops.dyn_refresh_ops.dyn_refresh_helper = + dsi_phy_hw_v4_0_dyn_refresh_helper; + phy->ops.dyn_refresh_ops.cache_phy_timings = + dsi_phy_hw_v4_0_cache_phy_timings; + phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk; + phy->ops.commit_phy_timing = dsi_phy_hw_v4_0_commit_phy_timing; +} + +/** + * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware + * @ctrl: Pointer to DSI PHY hw object. + * @version: DSI PHY version. + * @index: DSI PHY instance ID. + * + * This function setups the catalog information in the dsi_phy_hw object. + * + * return: error code for failure and 0 for success. + */ +int dsi_catalog_phy_setup(struct dsi_phy_hw *phy, + enum dsi_phy_version version, + u32 index) +{ + int rc = 0; + + if (version == DSI_PHY_VERSION_UNKNOWN || + version >= DSI_PHY_VERSION_MAX) { + DSI_ERR("Unsupported version: %d\n", version); + return -ENOTSUPP; + } + + phy->index = index; + phy->version = version; + set_bit(DSI_PHY_DPHY, phy->feature_map); + + dsi_phy_timing_calc_init(phy, version); + + switch (version) { + case DSI_PHY_VERSION_2_0: + dsi_catalog_phy_2_0_init(phy); + break; + case DSI_PHY_VERSION_3_0: + dsi_catalog_phy_3_0_init(phy); + break; + case DSI_PHY_VERSION_4_0: + case DSI_PHY_VERSION_4_1: + dsi_catalog_phy_4_0_init(phy); + break; + case DSI_PHY_VERSION_0_0_HPM: + case DSI_PHY_VERSION_0_0_LPM: + case DSI_PHY_VERSION_1_0: + default: + return -ENOTSUPP; + } + + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_catalog.h b/techpack/display/msm/dsi/dsi_catalog.h new file mode 100644 index 0000000000000000000000000000000000000000..ed047e9ef86d5735456b39d4de1f204881888044 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_catalog.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_CATALOG_H_ +#define _DSI_CATALOG_H_ + +#include "dsi_ctrl_hw.h" +#include "dsi_phy_hw.h" + +/** + * dsi_catalog_ctrl_setup() - return catalog info for dsi controller + * @ctrl: Pointer to DSI controller hw object. + * @version: DSI controller version. + * @index: DSI controller instance ID. + * @phy_isolation_enabled: DSI controller works isolated from phy. + * @null_insertion_enabled: DSI controller inserts null packet. + * + * This function setups the catalog information in the dsi_ctrl_hw object. + * + * return: error code for failure and 0 for success. + */ +int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl, + enum dsi_ctrl_version version, u32 index, + bool phy_isolation_enabled, bool null_insertion_enabled); + +/** + * dsi_catalog_phy_setup() - return catalog info for dsi phy hardware + * @phy: Pointer to DSI PHY hw object. + * @version: DSI PHY version. + * @index: DSI PHY instance ID. + * + * This function setups the catalog information in the dsi_phy_hw object. + * + * return: error code for failure and 0 for success. + */ +int dsi_catalog_phy_setup(struct dsi_phy_hw *phy, + enum dsi_phy_version version, + u32 index); + +/** + * dsi_phy_timing_calc_init() - initialize info for DSI PHY timing calculations + * @phy: Pointer to DSI PHY hw object. + * @version: DSI PHY version. + * + * This function setups the catalog information in the dsi_phy_hw object. + * + * return: error code for failure and 0 for success. + */ +int dsi_phy_timing_calc_init(struct dsi_phy_hw *phy, + enum dsi_phy_version version); + +/** + * dsi_phy_hw_calculate_timing_params() - DSI PHY timing parameter calculations + * @phy: Pointer to DSI PHY hw object. + * @mode: DSI mode information. + * @host: DSI host configuration. + * @timing: DSI phy lane configurations. + * @use_mode_bit_clk: Boolean to indicate whether to recalculate bit clk. + * + * This function setups the catalog information in the dsi_phy_hw object. + * + * return: error code for failure and 0 for success. + */ +int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy, + struct dsi_mode_info *mode, + struct dsi_host_common_cfg *host, + struct dsi_phy_per_lane_cfgs *timing, + bool use_mode_bit_clk); + +/* Definitions for 14nm PHY hardware driver */ +void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *cfg); +void dsi_phy_hw_v2_0_regulator_disable(struct dsi_phy_hw *phy); +void dsi_phy_hw_v2_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +void dsi_phy_hw_v2_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +void dsi_phy_hw_v2_0_idle_on(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy); +int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg, + u32 *timing_val, u32 size); +void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable); +void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset); +void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master); +void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay); +int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size); + +/* Definitions for 10nm PHY hardware driver */ +void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *cfg); +void dsi_phy_hw_v3_0_regulator_disable(struct dsi_phy_hw *phy); +void dsi_phy_hw_v3_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +void dsi_phy_hw_v3_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +int dsi_phy_hw_v3_0_wait_for_lane_idle(struct dsi_phy_hw *phy, u32 lanes); +void dsi_phy_hw_v3_0_ulps_request(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes); +void dsi_phy_hw_v3_0_ulps_exit(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes); +u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy); +bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes); +int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg, + u32 *timing_val, u32 size); +void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable); +int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy); +void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy); + +/* Definitions for 7nm PHY hardware driver */ +void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +void dsi_phy_hw_v4_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); +int dsi_phy_hw_v4_0_wait_for_lane_idle(struct dsi_phy_hw *phy, u32 lanes); +void dsi_phy_hw_v4_0_ulps_request(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes); +void dsi_phy_hw_v4_0_ulps_exit(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes); +u32 dsi_phy_hw_v4_0_get_lanes_in_ulps(struct dsi_phy_hw *phy); +bool dsi_phy_hw_v4_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes); +int dsi_phy_hw_timing_val_v4_0(struct dsi_phy_per_lane_cfgs *timing_cfg, + u32 *timing_val, u32 size); +int dsi_phy_hw_v4_0_lane_reset(struct dsi_phy_hw *phy); +void dsi_phy_hw_v4_0_toggle_resync_fifo(struct dsi_phy_hw *phy); +void dsi_phy_hw_v4_0_reset_clk_en_sel(struct dsi_phy_hw *phy); +void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable); +void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *timing); + +/* DSI controller common ops */ +u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl, u32 *entries, + u32 size); +void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints); +void dsi_ctrl_hw_cmn_enable_status_interrupts(struct dsi_ctrl_hw *ctrl, + u32 ints); + +u64 dsi_ctrl_hw_cmn_get_error_status(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors); +void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl, + u64 errors); + +void dsi_ctrl_hw_cmn_video_test_pattern_setup(struct dsi_ctrl_hw *ctrl, + enum dsi_test_pattern type, + u32 init_val); +void dsi_ctrl_hw_cmn_cmd_test_pattern_setup(struct dsi_ctrl_hw *ctrl, + enum dsi_test_pattern type, + u32 init_val, + u32 stream_id); +void dsi_ctrl_hw_cmn_test_pattern_enable(struct dsi_ctrl_hw *ctrl, bool enable); +void dsi_ctrl_hw_cmn_trigger_cmd_test_pattern(struct dsi_ctrl_hw *ctrl, + u32 stream_id); + +void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *config); +void dsi_ctrl_hw_cmn_video_engine_en(struct dsi_ctrl_hw *ctrl, bool on); +void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *common_cfg, + struct dsi_video_engine_cfg *cfg); + +void dsi_ctrl_hw_cmn_setup_avr(struct dsi_ctrl_hw *ctrl, bool enable); + +void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, + struct dsi_mode_info *mode); +void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl, + bool enable); +void dsi_ctrl_hw_cmn_cmd_engine_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *common_cfg, + struct dsi_cmd_engine_cfg *cfg); + +void dsi_ctrl_hw_cmn_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on); +void dsi_ctrl_hw_cmn_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on); + +void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, + struct dsi_mode_info *mode, + u32 h_stride, + u32 vc_id, + struct dsi_rect *roi); +void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl); + +void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode, + bool enable, u32 frame_count); +u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode); + +void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags); + +void dsi_ctrl_hw_cmn_kickoff_fifo_command(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_fifo_info *cmd, + u32 flags); +void dsi_ctrl_hw_cmn_reset_cmd_fifo(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_dln0_phy_err(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl, + bool enable); +void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl, + bool enable); +u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, + u8 *rd_buf, + u32 read_offset, + u32 rx_byte, + u32 pkt_size, u32 *hw_read_cnt); +void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl); +void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_on); +int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl, + int mask); +void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, + bool en); +void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en); +u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl); +u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl); +int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl); + +/* Definitions specific to 1.4 DSI controller hardware */ +int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); +void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl, + struct dsi_lane_map *lane_map); +void dsi_ctrl_hw_cmn_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes); +void dsi_ctrl_hw_cmn_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes); +u32 dsi_ctrl_hw_cmn_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl); + +void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl, + u32 lanes, + bool enable_ulps); + +void dsi_ctrl_hw_14_clamp_disable(struct dsi_ctrl_hw *ctrl, + u32 lanes, + bool disable_ulps); +ssize_t dsi_ctrl_hw_14_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, + char *buf, + u32 size); + +/* Definitions specific to 2.0 DSI controller hardware */ +void dsi_ctrl_hw_20_setup_lane_map(struct dsi_ctrl_hw *ctrl, + struct dsi_lane_map *lane_map); +int dsi_ctrl_hw_20_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); +ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, + char *buf, + u32 size); +void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags); + +/* Definitions specific to 2.2 DSI controller hardware */ +void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable, + enum dsi_clk_gate_type clk_selection); + +void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable); +void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy); + +/* dynamic refresh specific functions */ +void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset); +void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master); +void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay); + +int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl); +int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size); + +void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset); +void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master); +void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay); + +int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size); +#endif /* _DSI_CATALOG_H_ */ diff --git a/techpack/display/msm/dsi/dsi_clk.h b/techpack/display/msm/dsi/dsi_clk.h new file mode 100644 index 0000000000000000000000000000000000000000..fcd352d19b7b9fe9cfad26cf828d32634684706b --- /dev/null +++ b/techpack/display/msm/dsi/dsi_clk.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_CLK_H_ +#define _DSI_CLK_H_ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <drm/drmP.h> + +#define MAX_STRING_LEN 32 +#define MAX_DSI_CTRL 2 + +enum dsi_clk_state { + DSI_CLK_OFF, + DSI_CLK_ON, + DSI_CLK_EARLY_GATE, +}; + +enum clk_req_client { + DSI_CLK_REQ_MDP_CLIENT = 0, + DSI_CLK_REQ_DSI_CLIENT, +}; + +enum dsi_link_clk_type { + DSI_LINK_ESC_CLK, + DSI_LINK_BYTE_CLK, + DSI_LINK_PIX_CLK, + DSI_LINK_BYTE_INTF_CLK, + DSI_LINK_CLK_MAX, +}; + +enum dsi_link_clk_op_type { + DSI_LINK_CLK_SET_RATE = BIT(0), + DSI_LINK_CLK_PREPARE = BIT(1), + DSI_LINK_CLK_ENABLE = BIT(2), + DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2), +}; + +enum dsi_clk_type { + DSI_CORE_CLK = BIT(0), + DSI_LINK_CLK = BIT(1), + DSI_ALL_CLKS = (BIT(0) | BIT(1)), + DSI_CLKS_MAX = BIT(2), +}; + +enum dsi_lclk_type { + DSI_LINK_NONE = 0, + DSI_LINK_LP_CLK = BIT(0), + DSI_LINK_HS_CLK = BIT(1), +}; + +struct dsi_clk_ctrl_info { + enum dsi_clk_type clk_type; + enum dsi_clk_state clk_state; + enum clk_req_client client; +}; + +struct clk_ctrl_cb { + void *priv; + int (*dsi_clk_cb)(void *priv, struct dsi_clk_ctrl_info clk_ctrl_info); +}; + +/** + * struct dsi_core_clk_info - Core clock information for DSI hardware + * @mdp_core_clk: Handle to MDP core clock. + * @iface_clk: Handle to MDP interface clock. + * @core_mmss_clk: Handle to MMSS core clock. + * @bus_clk: Handle to bus clock. + * @mnoc_clk: Handle to MMSS NOC clock. + * @drm: Pointer to drm device node + */ +struct dsi_core_clk_info { + struct clk *mdp_core_clk; + struct clk *iface_clk; + struct clk *core_mmss_clk; + struct clk *bus_clk; + struct clk *mnoc_clk; + struct drm_device *drm; +}; + +/** + * struct dsi_link_hs_clk_info - Set of high speed link clocks for DSI HW + * @byte_clk: Handle to DSI byte_clk. + * @pixel_clk: Handle to DSI pixel_clk. + * @byte_intf_clk: Handle to DSI byte intf. clock. + */ +struct dsi_link_hs_clk_info { + struct clk *byte_clk; + struct clk *pixel_clk; + struct clk *byte_intf_clk; +}; + +/** + * struct dsi_link_lp_clk_info - Set of low power link clocks for DSI HW. + * @esc_clk: Handle to DSI escape clock. + */ +struct dsi_link_lp_clk_info { + struct clk *esc_clk; +}; + +/** + * struct link_clk_freq - Clock frequency information for Link clocks + * @byte_clk_rate: Frequency of DSI byte_clk in Hz. + * @byte_intf_clk_rate: Frequency of DSI byte_intf_clk in Hz. + * @pixel_clk_rate: Frequency of DSI pixel_clk in Hz. + * @esc_clk_rate: Frequency of DSI escape clock in Hz. + */ +struct link_clk_freq { + u32 byte_clk_rate; + u32 byte_intf_clk_rate; + u32 pix_clk_rate; + u32 esc_clk_rate; +}; + +/** + * typedef *pre_clockoff_cb() - Callback before clock is turned off + * @priv: private data pointer. + * @clk_type: clock which is being turned off. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @new_state: next state for the clock. + * + * @return: error code. + */ +typedef int (*pre_clockoff_cb)(void *priv, + enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state); + +/** + * typedef *post_clockoff_cb() - Callback after clock is turned off + * @priv: private data pointer. + * @clk_type: clock which was turned off. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @curr_state: current state for the clock. + * + * @return: error code. + */ +typedef int (*post_clockoff_cb)(void *priv, + enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state); + +/** + * typedef *post_clockon_cb() - Callback after clock is turned on + * @priv: private data pointer. + * @clk_type: clock which was turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @curr_state: current state for the clock. + * + * @return: error code. + */ +typedef int (*post_clockon_cb)(void *priv, + enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state); + +/** + * typedef *pre_clockon_cb() - Callback before clock is turned on + * @priv: private data pointer. + * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type.Valid only for link clocks. + * @new_state: next state for the clock. + * + * @return: error code. + */ +typedef int (*pre_clockon_cb)(void *priv, + enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state); + + +/** + * struct dsi_clk_info - clock information for DSI hardware. + * @name: client name. + * @c_clks[MAX_DSI_CTRL] array of core clock configurations + * @l_lp_clks[MAX_DSI_CTRL] array of low power(esc) clock configurations + * @l_hs_clks[MAX_DSI_CTRL] array of high speed clock configurations + * @bus_handle[MAX_DSI_CTRL] array of bus handles + * @ctrl_index[MAX_DSI_CTRL] array of DSI controller indexes mapped + * to core and link clock configurations + * @pre_clkoff_cb callback before clock is turned off + * @post_clkoff_cb callback after clock is turned off + * @post_clkon_cb callback after clock is turned on + * @pre_clkon_cb callback before clock is turned on + * @priv_data pointer to private data + * @master_ndx master DSI controller index + * @dsi_ctrl_count number of DSI controllers + */ +struct dsi_clk_info { + char name[MAX_STRING_LEN]; + struct dsi_core_clk_info c_clks[MAX_DSI_CTRL]; + struct dsi_link_lp_clk_info l_lp_clks[MAX_DSI_CTRL]; + struct dsi_link_hs_clk_info l_hs_clks[MAX_DSI_CTRL]; + u32 bus_handle[MAX_DSI_CTRL]; + u32 ctrl_index[MAX_DSI_CTRL]; + pre_clockoff_cb pre_clkoff_cb; + post_clockoff_cb post_clkoff_cb; + post_clockon_cb post_clkon_cb; + pre_clockon_cb pre_clkon_cb; + void *priv_data; + u32 master_ndx; + u32 dsi_ctrl_count; +}; + +/** + * struct dsi_clk_link_set - Pair of clock handles to describe link clocks + * @byte_clk: Handle to DSi byte_clk. + * @pixel_clk: Handle to DSI pixel_clk. + */ +struct dsi_clk_link_set { + struct clk *byte_clk; + struct clk *pixel_clk; +}; + +/** + * dsi_display_clk_mngr_update_splash_status() - Update splash stattus + * @clk_mngr: Structure containing DSI clock information + * @status: Splash status + */ +void dsi_display_clk_mngr_update_splash_status(void *clk_mgr, bool status); + +/** + * dsi_display_clk_mgr_register() - Register DSI clock manager + * @info: Structure containing DSI clock information + */ +void *dsi_display_clk_mngr_register(struct dsi_clk_info *info); + +/** + * dsi_display_clk_mngr_deregister() - Deregister DSI clock manager + * @clk_mngr: DSI clock manager pointer + */ +int dsi_display_clk_mngr_deregister(void *clk_mngr); + +/** + * dsi_register_clk_handle() - Register clock handle with DSI clock manager + * @clk_mngr: DSI clock manager pointer + * @client: DSI clock client pointer. + */ +void *dsi_register_clk_handle(void *clk_mngr, char *client); + +/** + * dsi_deregister_clk_handle() - Deregister clock handle from DSI clock manager + * @client: DSI clock client pointer. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_deregister_clk_handle(void *client); + +/** + * dsi_display_link_clk_force_update_ctrl() - force to set link clks + * @handle: Handle of desired DSI clock client. + * + * return: error code in case of failure or 0 for success. + */ + +int dsi_display_link_clk_force_update_ctrl(void *handle); + +/** + * dsi_display_clk_ctrl() - set frequencies for link clks + * @handle: Handle of desired DSI clock client. + * @clk_type: Clock which is being controlled. + * @clk_state: Desired state of clock + * + * return: error code in case of failure or 0 for success. + */ +int dsi_display_clk_ctrl(void *handle, + enum dsi_clk_type clk_type, enum dsi_clk_state clk_state); + +/** + * dsi_clk_set_link_frequencies() - set frequencies for link clks + * @client: DSI clock client pointer. + * @freq: Structure containing link clock frequencies. + * @index: Index of the DSI controller. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq, + u32 index); + + +/** + * dsi_clk_set_pixel_clk_rate() - set frequency for pixel_clk + * @client: DSI clock client pointer. + * @pixel_clk: Pixel_clk rate in Hz. + * @index: Index of the DSI controller. + * return: error code in case of failure or 0 for success. + */ +int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index); + + +/** + * dsi_clk_set_byte_clk_rate() - set frequency for byte clock + * @client: DSI clock client pointer. + * @byte_clk: Pixel clock rate in Hz. + * @byte_intf_clk: Byte interface clock rate in Hz. + * @index: Index of the DSI controller. + * return: error code in case of failure or 0 for success. + */ +int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, + u64 byte_intf_clk, u32 index); + +/** + * dsi_clk_update_parent() - update parent clocks for specified clock + * @parent: link clock pair which are set as parent. + * @child: link clock pair whose parent has to be set. + */ +int dsi_clk_update_parent(struct dsi_clk_link_set *parent, + struct dsi_clk_link_set *child); + +/** + * dsi_clk_prepare_enable() - prepare and enable dsi src clocks + * @clk: list of src clocks. + * + * @return: Zero on success and err no on failure + */ +int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk); + +/** + * dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks + * @clk: list of src clocks. + */ +void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk); +#endif /* _DSI_CLK_H_ */ diff --git a/techpack/display/msm/dsi/dsi_clk_manager.c b/techpack/display/msm/dsi/dsi_clk_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..ec2df96605a93ebacbd2f376b0cdf309add195c1 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_clk_manager.c @@ -0,0 +1,1481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/msm-bus.h> +#include <linux/pm_runtime.h> +#include "dsi_clk.h" +#include "dsi_defs.h" + +struct dsi_core_clks { + struct dsi_core_clk_info clks; + u32 bus_handle; +}; + +struct dsi_link_clks { + struct dsi_link_hs_clk_info hs_clks; + struct dsi_link_lp_clk_info lp_clks; + struct link_clk_freq freq; +}; + +struct dsi_clk_mngr { + char name[MAX_STRING_LEN]; + struct mutex clk_mutex; + struct list_head client_list; + + u32 dsi_ctrl_count; + u32 master_ndx; + struct dsi_core_clks core_clks[MAX_DSI_CTRL]; + struct dsi_link_clks link_clks[MAX_DSI_CTRL]; + u32 ctrl_index[MAX_DSI_CTRL]; + u32 core_clk_state; + u32 link_clk_state; + + pre_clockoff_cb pre_clkoff_cb; + post_clockoff_cb post_clkoff_cb; + post_clockon_cb post_clkon_cb; + pre_clockon_cb pre_clkon_cb; + + bool is_cont_splash_enabled; + void *priv_data; +}; + +struct dsi_clk_client_info { + char name[MAX_STRING_LEN]; + u32 core_refcount; + u32 link_refcount; + u32 core_clk_state; + u32 link_clk_state; + struct list_head list; + struct dsi_clk_mngr *mngr; +}; + +static int _get_clk_mngr_index(struct dsi_clk_mngr *mngr, + u32 dsi_ctrl_index, + u32 *clk_mngr_index) +{ + int i; + + for (i = 0; i < mngr->dsi_ctrl_count; i++) { + if (mngr->ctrl_index[i] == dsi_ctrl_index) { + *clk_mngr_index = i; + return 0; + } + } + + return -EINVAL; +} + +/** + * dsi_clk_set_link_frequencies() - set frequencies for link clks + * @clks: Link clock information + * @pixel_clk: pixel clock frequency in KHz. + * @byte_clk: Byte clock frequency in KHz. + * @esc_clk: Escape clock frequency in KHz. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq, + u32 index) +{ + int rc = 0, clk_mngr_index = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + + if (!client) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mngr = c->mngr; + rc = _get_clk_mngr_index(mngr, index, &clk_mngr_index); + if (rc) { + DSI_ERR("failed to map control index %d\n", index); + return -EINVAL; + } + + memcpy(&mngr->link_clks[clk_mngr_index].freq, &freq, + sizeof(struct link_clk_freq)); + + return rc; +} + +/** + * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock + * @clks: DSI link clock information. + * @pixel_clk: Pixel clock rate in KHz. + * @index: Index of the DSI controller. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index) +{ + int rc = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + + mngr = c->mngr; + rc = clk_set_rate(mngr->link_clks[index].hs_clks.pixel_clk, pixel_clk); + if (rc) + DSI_ERR("failed to set clk rate for pixel clk, rc=%d\n", rc); + else + mngr->link_clks[index].freq.pix_clk_rate = pixel_clk; + + return rc; +} + +/** + * dsi_clk_set_byte_clk_rate() - set frequency for byte clock + * @client: DSI clock client pointer. + * @byte_clk: Byte clock rate in Hz. + * @byte_intf_clk: Byte interface clock rate in Hz. + * @index: Index of the DSI controller. + * return: error code in case of failure or 0 for success. + */ +int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, + u64 byte_intf_clk, u32 index) +{ + int rc = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + + mngr = c->mngr; + rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk); + if (rc) + DSI_ERR("failed to set clk rate for byte clk, rc=%d\n", rc); + else + mngr->link_clks[index].freq.byte_clk_rate = byte_clk; + + if (mngr->link_clks[index].hs_clks.byte_intf_clk) { + rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_intf_clk, + byte_intf_clk); + if (rc) + DSI_ERR("failed to set clk rate for byte intf clk=%d\n", + rc); + else + mngr->link_clks[index].freq.byte_intf_clk_rate = + byte_intf_clk; + } + + return rc; +} + +/** + * dsi_clk_update_parent() - update parent clocks for specified clock + * @parent: link clock pair which are set as parent. + * @child: link clock pair whose parent has to be set. + */ +int dsi_clk_update_parent(struct dsi_clk_link_set *parent, + struct dsi_clk_link_set *child) +{ + int rc = 0; + + rc = clk_set_parent(child->byte_clk, parent->byte_clk); + if (rc) { + DSI_ERR("failed to set byte clk parent\n"); + goto error; + } + + rc = clk_set_parent(child->pixel_clk, parent->pixel_clk); + if (rc) { + DSI_ERR("failed to set pixel clk parent\n"); + goto error; + } +error: + return rc; +} + +/** + * dsi_clk_prepare_enable() - prepare and enable dsi src clocks + * @clk: list of src clocks. + * + * @return: Zero on success and err no on failure. + */ +int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk) +{ + int rc; + + rc = clk_prepare_enable(clk->byte_clk); + if (rc) { + DSI_ERR("failed to enable byte src clk %d\n", rc); + return rc; + } + + rc = clk_prepare_enable(clk->pixel_clk); + if (rc) { + DSI_ERR("failed to enable pixel src clk %d\n", rc); + return rc; + } + + return 0; +} + +/** + * dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks + * @clk: list of src clocks. + */ +void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk) +{ + clk_disable_unprepare(clk->pixel_clk); + clk_disable_unprepare(clk->byte_clk); +} + +int dsi_core_clk_start(struct dsi_core_clks *c_clks) +{ + int rc = 0; + + if (c_clks->clks.mdp_core_clk) { + rc = clk_prepare_enable(c_clks->clks.mdp_core_clk); + if (rc) { + DSI_ERR("failed to enable mdp_core_clk, rc=%d\n", rc); + goto error; + } + } + + if (c_clks->clks.mnoc_clk) { + rc = clk_prepare_enable(c_clks->clks.mnoc_clk); + if (rc) { + DSI_ERR("failed to enable mnoc_clk, rc=%d\n", rc); + goto error_disable_core_clk; + } + } + + if (c_clks->clks.iface_clk) { + rc = clk_prepare_enable(c_clks->clks.iface_clk); + if (rc) { + DSI_ERR("failed to enable iface_clk, rc=%d\n", rc); + goto error_disable_mnoc_clk; + } + } + + if (c_clks->clks.bus_clk) { + rc = clk_prepare_enable(c_clks->clks.bus_clk); + if (rc) { + DSI_ERR("failed to enable bus_clk, rc=%d\n", rc); + goto error_disable_iface_clk; + } + } + + if (c_clks->clks.core_mmss_clk) { + rc = clk_prepare_enable(c_clks->clks.core_mmss_clk); + if (rc) { + DSI_ERR("failed to enable core_mmss_clk, rc=%d\n", rc); + goto error_disable_bus_clk; + } + } + + if (c_clks->bus_handle) { + rc = msm_bus_scale_client_update_request(c_clks->bus_handle, 1); + if (rc) { + DSI_ERR("bus scale client enable failed, rc=%d\n", rc); + goto error_disable_mmss_clk; + } + } + + return rc; + +error_disable_mmss_clk: + if (c_clks->clks.core_mmss_clk) + clk_disable_unprepare(c_clks->clks.core_mmss_clk); +error_disable_bus_clk: + if (c_clks->clks.bus_clk) + clk_disable_unprepare(c_clks->clks.bus_clk); +error_disable_iface_clk: + if (c_clks->clks.iface_clk) + clk_disable_unprepare(c_clks->clks.iface_clk); +error_disable_mnoc_clk: + if (c_clks->clks.mnoc_clk) + clk_disable_unprepare(c_clks->clks.mnoc_clk); +error_disable_core_clk: + if (c_clks->clks.mdp_core_clk) + clk_disable_unprepare(c_clks->clks.mdp_core_clk); +error: + return rc; +} + +int dsi_core_clk_stop(struct dsi_core_clks *c_clks) +{ + int rc = 0; + + if (c_clks->bus_handle) { + rc = msm_bus_scale_client_update_request(c_clks->bus_handle, 0); + if (rc) { + DSI_ERR("bus scale client disable failed, rc=%d\n", rc); + return rc; + } + } + + if (c_clks->clks.core_mmss_clk) + clk_disable_unprepare(c_clks->clks.core_mmss_clk); + + if (c_clks->clks.bus_clk) + clk_disable_unprepare(c_clks->clks.bus_clk); + + if (c_clks->clks.iface_clk) + clk_disable_unprepare(c_clks->clks.iface_clk); + + if (c_clks->clks.mnoc_clk) + clk_disable_unprepare(c_clks->clks.mnoc_clk); + + if (c_clks->clks.mdp_core_clk) + clk_disable_unprepare(c_clks->clks.mdp_core_clk); + + return rc; +} + +static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks, + int index) +{ + int rc = 0; + struct dsi_clk_mngr *mngr; + struct dsi_link_clks *l_clks; + + if (index >= MAX_DSI_CTRL) { + DSI_ERR("Invalid DSI ctrl index\n"); + return -EINVAL; + } + + l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); + mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]); + + /* + * In an ideal world, cont_splash_enabled should not be required inside + * the clock manager. But, in the current driver cont_splash_enabled + * flag is set inside mdp driver and there is no interface event + * associated with this flag setting. + */ + if (mngr->is_cont_splash_enabled) + return 0; + + rc = clk_set_rate(link_hs_clks->byte_clk, + l_clks->freq.byte_clk_rate); + if (rc) { + DSI_ERR("clk_set_rate failed for byte_clk rc = %d\n", rc); + goto error; + } + + rc = clk_set_rate(link_hs_clks->pixel_clk, + l_clks->freq.pix_clk_rate); + if (rc) { + DSI_ERR("clk_set_rate failed for pixel_clk rc = %d\n", rc); + goto error; + } + + /* + * If byte_intf_clk is present, set rate for that too. + */ + if (link_hs_clks->byte_intf_clk) { + rc = clk_set_rate(link_hs_clks->byte_intf_clk, + l_clks->freq.byte_intf_clk_rate); + if (rc) { + DSI_ERR("set_rate failed for byte_intf_clk rc = %d\n", + rc); + goto error; + } + } +error: + return rc; +} + +static int dsi_link_hs_clk_prepare(struct dsi_link_hs_clk_info *link_hs_clks) +{ + int rc = 0; + + rc = clk_prepare(link_hs_clks->byte_clk); + if (rc) { + DSI_ERR("Failed to prepare dsi byte clk, rc=%d\n", rc); + goto byte_clk_err; + } + + rc = clk_prepare(link_hs_clks->pixel_clk); + if (rc) { + DSI_ERR("Failed to prepare dsi pixel clk, rc=%d\n", rc); + goto pixel_clk_err; + } + + if (link_hs_clks->byte_intf_clk) { + rc = clk_prepare(link_hs_clks->byte_intf_clk); + if (rc) { + DSI_ERR("Failed to prepare dsi byte intf clk, rc=%d\n", + rc); + goto byte_intf_clk_err; + } + } + + return rc; + +byte_intf_clk_err: + clk_unprepare(link_hs_clks->pixel_clk); +pixel_clk_err: + clk_unprepare(link_hs_clks->byte_clk); +byte_clk_err: + return rc; +} + +static void dsi_link_hs_clk_unprepare(struct dsi_link_hs_clk_info *link_hs_clks) +{ + if (link_hs_clks->byte_intf_clk) + clk_unprepare(link_hs_clks->byte_intf_clk); + clk_unprepare(link_hs_clks->pixel_clk); + clk_unprepare(link_hs_clks->byte_clk); +} + +static int dsi_link_hs_clk_enable(struct dsi_link_hs_clk_info *link_hs_clks) +{ + int rc = 0; + + rc = clk_enable(link_hs_clks->byte_clk); + if (rc) { + DSI_ERR("Failed to enable dsi byte clk, rc=%d\n", rc); + goto byte_clk_err; + } + + rc = clk_enable(link_hs_clks->pixel_clk); + if (rc) { + DSI_ERR("Failed to enable dsi pixel clk, rc=%d\n", rc); + goto pixel_clk_err; + } + + if (link_hs_clks->byte_intf_clk) { + rc = clk_enable(link_hs_clks->byte_intf_clk); + if (rc) { + DSI_ERR("Failed to enable dsi byte intf clk, rc=%d\n", + rc); + goto byte_intf_clk_err; + } + } + + return rc; + +byte_intf_clk_err: + clk_disable(link_hs_clks->pixel_clk); +pixel_clk_err: + clk_disable(link_hs_clks->byte_clk); +byte_clk_err: + return rc; +} + +static void dsi_link_hs_clk_disable(struct dsi_link_hs_clk_info *link_hs_clks) +{ + if (link_hs_clks->byte_intf_clk) + clk_disable(link_hs_clks->byte_intf_clk); + clk_disable(link_hs_clks->pixel_clk); + clk_disable(link_hs_clks->byte_clk); +} + +/** + * dsi_link_clk_start() - enable dsi link clocks + */ +static int dsi_link_hs_clk_start(struct dsi_link_hs_clk_info *link_hs_clks, + enum dsi_link_clk_op_type op_type, int index) +{ + int rc = 0; + + if (index >= MAX_DSI_CTRL) { + DSI_ERR("Invalid DSI ctrl index\n"); + return -EINVAL; + } + + if (op_type & DSI_LINK_CLK_SET_RATE) { + rc = dsi_link_hs_clk_set_rate(link_hs_clks, index); + if (rc) { + DSI_ERR("failed to set HS clk rates, rc = %d\n", rc); + goto error; + } + } + + if (op_type & DSI_LINK_CLK_PREPARE) { + rc = dsi_link_hs_clk_prepare(link_hs_clks); + if (rc) { + DSI_ERR("failed to prepare link HS clks, rc = %d\n", + rc); + goto error; + } + } + + if (op_type & DSI_LINK_CLK_ENABLE) { + rc = dsi_link_hs_clk_enable(link_hs_clks); + if (rc) { + DSI_ERR("failed to enable link HS clks, rc = %d\n", rc); + goto error_unprepare; + } + } + + DSI_DEBUG("HS Link clocks are enabled\n"); + return rc; +error_unprepare: + dsi_link_hs_clk_unprepare(link_hs_clks); +error: + return rc; +} + +/** + * dsi_link_clk_stop() - Stop DSI link clocks. + */ +static int dsi_link_hs_clk_stop(struct dsi_link_hs_clk_info *link_hs_clks) +{ + struct dsi_link_clks *l_clks; + + l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); + + dsi_link_hs_clk_disable(link_hs_clks); + dsi_link_hs_clk_unprepare(link_hs_clks); + + DSI_DEBUG("HS Link clocks disabled\n"); + + return 0; +} + +static int dsi_link_lp_clk_start(struct dsi_link_lp_clk_info *link_lp_clks, + int index) +{ + int rc = 0; + struct dsi_clk_mngr *mngr; + struct dsi_link_clks *l_clks; + + if (index >= MAX_DSI_CTRL) { + DSI_ERR("Invalid DSI ctrl index\n"); + return -EINVAL; + } + + l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); + + mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]); + if (!mngr) + return -EINVAL; + + /* + * In an ideal world, cont_splash_enabled should not be required inside + * the clock manager. But, in the current driver cont_splash_enabled + * flag is set inside mdp driver and there is no interface event + * associated with this flag setting. Also, set rate for clock need not + * be called for every enable call. It should be done only once when + * coming out of suspend. + */ + if (mngr->is_cont_splash_enabled) + goto prepare; + + rc = clk_set_rate(link_lp_clks->esc_clk, l_clks->freq.esc_clk_rate); + if (rc) { + DSI_ERR("clk_set_rate failed for esc_clk rc = %d\n", rc); + goto error; + } + +prepare: + rc = clk_prepare_enable(link_lp_clks->esc_clk); + if (rc) { + DSI_ERR("Failed to enable dsi esc clk\n"); + clk_unprepare(l_clks->lp_clks.esc_clk); + } +error: + DSI_DEBUG("LP Link clocks are enabled\n"); + return rc; +} + +static int dsi_link_lp_clk_stop( + struct dsi_link_lp_clk_info *link_lp_clks) +{ + struct dsi_link_clks *l_clks; + + l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); + + clk_disable_unprepare(l_clks->lp_clks.esc_clk); + + DSI_DEBUG("LP Link clocks are disabled\n"); + return 0; +} + +static int dsi_display_core_clk_enable(struct dsi_core_clks *clks, + u32 ctrl_count, u32 master_ndx) +{ + int rc = 0; + int i; + struct dsi_core_clks *clk, *m_clks; + + /* + * In case of split DSI usecases, the clock for master controller should + * be enabled before the other controller. Master controller in the + * clock context refers to the controller that sources the clock. + */ + + m_clks = &clks[master_ndx]; + + rc = dsi_core_clk_start(m_clks); + if (rc) { + DSI_ERR("failed to turn on master clocks, rc=%d\n", rc); + goto error; + } + + /* Turn on rest of the core clocks */ + for (i = 0; i < ctrl_count; i++) { + clk = &clks[i]; + if (!clk || (clk == m_clks)) + continue; + + rc = dsi_core_clk_start(clk); + if (rc) { + DSI_ERR("failed to turn on clocks, rc=%d\n", rc); + goto error_disable_master; + } + } + return rc; +error_disable_master: + (void)dsi_core_clk_stop(m_clks); + +error: + return rc; +} + +static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, + enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx) +{ + int rc = 0; + int i; + struct dsi_link_clks *clk, *m_clks; + + /* + * In case of split DSI usecases, the clock for master controller should + * be enabled before the other controller. Master controller in the + * clock context refers to the controller that sources the clock. + */ + + m_clks = &clks[master_ndx]; + + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_start(&m_clks->lp_clks, master_ndx); + if (rc) { + DSI_ERR("failed to turn on master lp link clocks, rc=%d\n", + rc); + goto error; + } + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_start(&m_clks->hs_clks, + DSI_LINK_CLK_START, master_ndx); + if (rc) { + DSI_ERR("failed to turn on master hs link clocks, rc=%d\n", + rc); + goto error; + } + } + + for (i = 0; i < ctrl_count; i++) { + clk = &clks[i]; + if (!clk || (clk == m_clks)) + continue; + + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_start(&clk->lp_clks, i); + if (rc) { + DSI_ERR("failed to turn on lp link clocks, rc=%d\n", + rc); + goto error_disable_master; + } + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_start(&clk->hs_clks, + DSI_LINK_CLK_START, i); + if (rc) { + DSI_ERR("failed to turn on hs link clocks, rc=%d\n", + rc); + goto error_disable_master; + } + } + } + return rc; + +error_disable_master: + if (l_type == DSI_LINK_LP_CLK) + (void)dsi_link_lp_clk_stop(&m_clks->lp_clks); + else if (l_type == DSI_LINK_HS_CLK) + (void)dsi_link_hs_clk_stop(&m_clks->hs_clks); +error: + return rc; +} + +static int dsi_display_core_clk_disable(struct dsi_core_clks *clks, + u32 ctrl_count, u32 master_ndx) +{ + int rc = 0; + int i; + struct dsi_core_clks *clk, *m_clks; + + /* + * In case of split DSI usecases, clock for slave DSI controllers should + * be disabled first before disabling clock for master controller. Slave + * controllers in the clock context refer to controller which source + * clock from another controller. + */ + + m_clks = &clks[master_ndx]; + + /* Turn off non-master core clocks */ + for (i = 0; i < ctrl_count; i++) { + clk = &clks[i]; + if (!clk || (clk == m_clks)) + continue; + + rc = dsi_core_clk_stop(clk); + if (rc) { + DSI_DEBUG("failed to turn off clocks, rc=%d\n", rc); + goto error; + } + } + + rc = dsi_core_clk_stop(m_clks); + if (rc) { + DSI_ERR("failed to turn off master clocks, rc=%d\n", rc); + goto error; + } + +error: + return rc; +} + +static int dsi_display_link_clk_disable(struct dsi_link_clks *clks, + enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx) +{ + int rc = 0; + int i; + struct dsi_link_clks *clk, *m_clks; + + /* + * In case of split DSI usecases, clock for slave DSI controllers should + * be disabled first before disabling clock for master controller. Slave + * controllers in the clock context refer to controller which source + * clock from another controller. + */ + + m_clks = &clks[master_ndx]; + + /* Turn off non-master link clocks */ + for (i = 0; i < ctrl_count; i++) { + clk = &clks[i]; + if (!clk || (clk == m_clks)) + continue; + + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_stop(&clk->lp_clks); + if (rc) + DSI_ERR("failed to turn off lp link clocks, rc=%d\n", + rc); + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_stop(&clk->hs_clks); + if (rc) + DSI_ERR("failed to turn off hs link clocks, rc=%d\n", + rc); + } + } + + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_stop(&m_clks->lp_clks); + if (rc) + DSI_ERR("failed to turn off master lp link clocks, rc=%d\n", + rc); + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_stop(&m_clks->hs_clks); + if (rc) + DSI_ERR("failed to turn off master hs link clocks, rc=%d\n", + rc); + } + + return rc; +} + +static int dsi_clk_update_link_clk_state(struct dsi_clk_mngr *mngr, + struct dsi_link_clks *l_clks, enum dsi_lclk_type l_type, u32 l_state, + bool enable) +{ + int rc = 0; + + if (!mngr) + return -EINVAL; + + if (enable) { + if (mngr->pre_clkon_cb) { + rc = mngr->pre_clkon_cb(mngr->priv_data, DSI_LINK_CLK, + l_type, l_state); + if (rc) { + DSI_ERR("pre link clk on cb failed for type %d\n", + l_type); + goto error; + } + } + rc = dsi_display_link_clk_enable(l_clks, l_type, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + DSI_ERR("failed to start link clk type %d rc=%d\n", + l_type, rc); + goto error; + } + + if (mngr->post_clkon_cb) { + rc = mngr->post_clkon_cb(mngr->priv_data, DSI_LINK_CLK, + l_type, l_state); + if (rc) { + DSI_ERR("post link clk on cb failed for type %d\n", + l_type); + goto error; + } + } + } else { + if (mngr->pre_clkoff_cb) { + rc = mngr->pre_clkoff_cb(mngr->priv_data, + DSI_LINK_CLK, l_type, l_state); + if (rc) + DSI_ERR("pre link clk off cb failed\n"); + } + + rc = dsi_display_link_clk_disable(l_clks, l_type, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + DSI_ERR("failed to stop link clk type %d, rc = %d\n", + l_type, rc); + goto error; + } + + if (mngr->post_clkoff_cb) { + rc = mngr->post_clkoff_cb(mngr->priv_data, + DSI_LINK_CLK, l_type, l_state); + if (rc) + DSI_ERR("post link clk off cb failed\n"); + } + } + +error: + return rc; +} + +static int dsi_update_core_clks(struct dsi_clk_mngr *mngr, + struct dsi_core_clks *c_clks) +{ + int rc = 0; + + if (mngr->core_clk_state == DSI_CLK_OFF) { + rc = mngr->pre_clkon_cb(mngr->priv_data, + DSI_CORE_CLK, + DSI_LINK_NONE, + DSI_CLK_ON); + if (rc) { + DSI_ERR("failed to turn on MDP FS rc= %d\n", rc); + goto error; + } + } + rc = dsi_display_core_clk_enable(c_clks, mngr->dsi_ctrl_count, + mngr->master_ndx); + if (rc) { + DSI_ERR("failed to turn on core clks rc = %d\n", rc); + goto error; + } + + if (mngr->post_clkon_cb) { + rc = mngr->post_clkon_cb(mngr->priv_data, + DSI_CORE_CLK, + DSI_LINK_NONE, + DSI_CLK_ON); + if (rc) + DSI_ERR("post clk on cb failed, rc = %d\n", rc); + } + mngr->core_clk_state = DSI_CLK_ON; +error: + return rc; +} + +static int dsi_update_clk_state(struct dsi_clk_mngr *mngr, + struct dsi_core_clks *c_clks, u32 c_state, + struct dsi_link_clks *l_clks, u32 l_state) +{ + int rc = 0; + bool l_c_on = false; + + if (!mngr) + return -EINVAL; + + DSI_DEBUG("c_state = %d, l_state = %d\n", + c_clks ? c_state : -1, l_clks ? l_state : -1); + /* + * Below is the sequence to toggle DSI clocks: + * 1. For ON sequence, Core clocks before link clocks + * 2. For OFF sequence, Link clocks before core clocks. + */ + if (c_clks && (c_state == DSI_CLK_ON)) + rc = dsi_update_core_clks(mngr, c_clks); + + if (rc) + goto error; + + if (l_clks) { + if (l_state == DSI_CLK_ON) { + rc = dsi_clk_update_link_clk_state(mngr, l_clks, + DSI_LINK_LP_CLK, l_state, true); + if (rc) + goto error; + + rc = dsi_clk_update_link_clk_state(mngr, l_clks, + DSI_LINK_HS_CLK, l_state, true); + if (rc) + goto error; + } else { + /* + * Two conditions that need to be checked for Link + * clocks: + * 1. Link clocks need core clocks to be on when + * transitioning from EARLY_GATE to OFF state. + * 2. ULPS mode might have to be enabled in case of OFF + * state. For ULPS, Link clocks should be turned ON + * first before they are turned off again. + * + * If Link is going from EARLY_GATE to OFF state AND + * Core clock is already in EARLY_GATE or OFF state, + * turn on Core clocks and link clocks. + * + * ULPS state is managed as part of the pre_clkoff_cb. + */ + if ((l_state == DSI_CLK_OFF) && + (mngr->link_clk_state == + DSI_CLK_EARLY_GATE) && + (mngr->core_clk_state != + DSI_CLK_ON)) { + rc = dsi_display_core_clk_enable( + mngr->core_clks, mngr->dsi_ctrl_count, + mngr->master_ndx); + if (rc) { + DSI_ERR("core clks did not start\n"); + goto error; + } + + rc = dsi_display_link_clk_enable(l_clks, + (DSI_LINK_LP_CLK & DSI_LINK_HS_CLK), + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + DSI_ERR("LP Link clks did not start\n"); + goto error; + } + l_c_on = true; + DSI_DEBUG("ECG: core and Link_on\n"); + } + + rc = dsi_clk_update_link_clk_state(mngr, l_clks, + DSI_LINK_HS_CLK, l_state, false); + if (rc) + goto error; + + rc = dsi_clk_update_link_clk_state(mngr, l_clks, + DSI_LINK_LP_CLK, l_state, false); + if (rc) + goto error; + + /* + * This check is to save unnecessary clock state + * change when going from EARLY_GATE to OFF. In the + * case where the request happens for both Core and Link + * clocks in the same call, core clocks need to be + * turned on first before OFF state can be entered. + * + * Core clocks are turned on here for Link clocks to go + * to OFF state. If core clock request is also present, + * then core clocks can be turned off Core clocks are + * transitioned to OFF state. + */ + if (l_c_on && (!(c_clks && (c_state == DSI_CLK_OFF) + && (mngr->core_clk_state == + DSI_CLK_EARLY_GATE)))) { + rc = dsi_display_core_clk_disable( + mngr->core_clks, mngr->dsi_ctrl_count, + mngr->master_ndx); + if (rc) { + DSI_ERR("core clks did not stop\n"); + goto error; + } + + l_c_on = false; + DSI_DEBUG("ECG: core off\n"); + } else + DSI_DEBUG("ECG: core off skip\n"); + } + + mngr->link_clk_state = l_state; + } + + if (c_clks && (c_state != DSI_CLK_ON)) { + /* + * When going to OFF state from EARLY GATE state, Core clocks + * should be turned on first so that the IOs can be clamped. + * l_c_on flag is set, then the core clocks were turned before + * to the Link clocks go to OFF state. So Core clocks are + * already ON and this step can be skipped. + * + * IOs are clamped in pre_clkoff_cb callback. + */ + if ((c_state == DSI_CLK_OFF) && + (mngr->core_clk_state == + DSI_CLK_EARLY_GATE) && !l_c_on) { + rc = dsi_display_core_clk_enable(mngr->core_clks, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + DSI_ERR("core clks did not start\n"); + goto error; + } + DSI_DEBUG("ECG: core on\n"); + } else + DSI_DEBUG("ECG: core on skip\n"); + + if (mngr->pre_clkoff_cb) { + rc = mngr->pre_clkoff_cb(mngr->priv_data, + DSI_CORE_CLK, + DSI_LINK_NONE, + c_state); + if (rc) + DSI_ERR("pre core clk off cb failed\n"); + } + + rc = dsi_display_core_clk_disable(c_clks, mngr->dsi_ctrl_count, + mngr->master_ndx); + if (rc) { + DSI_ERR("failed to turn off core clks rc = %d\n", rc); + goto error; + } + + if (c_state == DSI_CLK_OFF) { + if (mngr->post_clkoff_cb) { + rc = mngr->post_clkoff_cb(mngr->priv_data, + DSI_CORE_CLK, + DSI_LINK_NONE, + DSI_CLK_OFF); + if (rc) + DSI_ERR("post clkoff cb fail, rc = %d\n", + rc); + } + } + mngr->core_clk_state = c_state; + } + +error: + return rc; +} + +static int dsi_recheck_clk_state(struct dsi_clk_mngr *mngr) +{ + int rc = 0; + struct list_head *pos = NULL; + struct dsi_clk_client_info *c; + u32 new_core_clk_state = DSI_CLK_OFF; + u32 new_link_clk_state = DSI_CLK_OFF; + u32 old_c_clk_state = DSI_CLK_OFF; + u32 old_l_clk_state = DSI_CLK_OFF; + struct dsi_core_clks *c_clks = NULL; + struct dsi_link_clks *l_clks = NULL; + + /* + * Conditions to maintain DSI manager clock state based on + * clock states of various clients: + * 1. If any client has clock in ON state, DSI manager clock state + * should be ON. + * 2. If any client is in ECG state with rest of them turned OFF, + * go to Early gate state. + * 3. If all clients have clocks as OFF, then go to OFF state. + */ + list_for_each(pos, &mngr->client_list) { + c = list_entry(pos, struct dsi_clk_client_info, list); + if (c->core_clk_state == DSI_CLK_ON) { + new_core_clk_state = DSI_CLK_ON; + break; + } else if (c->core_clk_state == DSI_CLK_EARLY_GATE) { + new_core_clk_state = DSI_CLK_EARLY_GATE; + } + } + + list_for_each(pos, &mngr->client_list) { + c = list_entry(pos, struct dsi_clk_client_info, list); + if (c->link_clk_state == DSI_CLK_ON) { + new_link_clk_state = DSI_CLK_ON; + break; + } else if (c->link_clk_state == DSI_CLK_EARLY_GATE) { + new_link_clk_state = DSI_CLK_EARLY_GATE; + } + } + + if (new_core_clk_state != mngr->core_clk_state) + c_clks = mngr->core_clks; + + if (new_link_clk_state != mngr->link_clk_state) + l_clks = mngr->link_clks; + + old_c_clk_state = mngr->core_clk_state; + old_l_clk_state = mngr->link_clk_state; + + DSI_DEBUG("c_clk_state (%d -> %d)\n", old_c_clk_state, + new_core_clk_state); + DSI_DEBUG("l_clk_state (%d -> %d)\n", old_l_clk_state, + new_link_clk_state); + + if (c_clks || l_clks) { + rc = dsi_update_clk_state(mngr, c_clks, new_core_clk_state, + l_clks, new_link_clk_state); + if (rc) { + DSI_ERR("failed to update clock state, rc = %d\n", rc); + goto error; + } + } + +error: + return rc; +} + +int dsi_clk_req_state(void *client, enum dsi_clk_type clk, + enum dsi_clk_state state) +{ + int rc = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + bool changed = false; + + if (!client || !clk || clk > (DSI_CORE_CLK | DSI_LINK_CLK) || + state > DSI_CLK_EARLY_GATE) { + DSI_ERR("Invalid params, client = %pK, clk = 0x%x, state = %d\n", + client, clk, state); + return -EINVAL; + } + + mngr = c->mngr; + mutex_lock(&mngr->clk_mutex); + + DSI_DEBUG("[%s]%s: CLK=%d, new_state=%d, core=%d, linkl=%d\n", + mngr->name, c->name, clk, state, c->core_clk_state, + c->link_clk_state); + + /* + * Clock refcount handling as below: + * i. Increment refcount whenever ON is called. + * ii. Decrement refcount when transitioning from ON state to + * either OFF or EARLY_GATE. + * iii. Do not decrement refcount when changing from + * EARLY_GATE to OFF. + */ + if (state == DSI_CLK_ON) { + if (clk & DSI_CORE_CLK) { + c->core_refcount++; + if (c->core_clk_state != DSI_CLK_ON) { + c->core_clk_state = DSI_CLK_ON; + changed = true; + } + } + if (clk & DSI_LINK_CLK) { + c->link_refcount++; + if (c->link_clk_state != DSI_CLK_ON) { + c->link_clk_state = DSI_CLK_ON; + changed = true; + } + } + } else if ((state == DSI_CLK_EARLY_GATE) || + (state == DSI_CLK_OFF)) { + if (clk & DSI_CORE_CLK) { + if (c->core_refcount == 0) { + if ((c->core_clk_state == + DSI_CLK_EARLY_GATE) && + (state == DSI_CLK_OFF)) { + changed = true; + c->core_clk_state = DSI_CLK_OFF; + } else { + DSI_WARN("Core refcount is zero for %s\n", + c->name); + } + } else { + c->core_refcount--; + if (c->core_refcount == 0) { + c->core_clk_state = state; + changed = true; + } + } + } + if (clk & DSI_LINK_CLK) { + if (c->link_refcount == 0) { + if ((c->link_clk_state == + DSI_CLK_EARLY_GATE) && + (state == DSI_CLK_OFF)) { + changed = true; + c->link_clk_state = DSI_CLK_OFF; + } else { + DSI_WARN("Link refcount is zero for %s\n", + c->name); + } + } else { + c->link_refcount--; + if (c->link_refcount == 0) { + c->link_clk_state = state; + changed = true; + } + } + } + } + DSI_DEBUG("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n", + mngr->name, c->name, changed, c->core_refcount, + c->core_clk_state, c->link_refcount, c->link_clk_state); + + if (changed) { + rc = dsi_recheck_clk_state(mngr); + if (rc) + DSI_ERR("Failed to adjust clock state rc = %d\n", rc); + } + + mutex_unlock(&mngr->clk_mutex); + return rc; +} + +DEFINE_MUTEX(dsi_mngr_clk_mutex); + +static int dsi_display_link_clk_force_update(void *client) +{ + int rc = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + struct dsi_link_clks *l_clks; + + mngr = c->mngr; + mutex_lock(&mngr->clk_mutex); + + l_clks = mngr->link_clks; + + /* + * When link_clk_state is DSI_CLK_OFF, don't change DSI clock rate + * since it is possible to be overwritten, and return -EAGAIN to + * dynamic DSI writing interface to defer the reenabling to the next + * drm commit. + */ + if (mngr->link_clk_state == DSI_CLK_OFF) { + rc = -EAGAIN; + goto error; + } + + rc = dsi_clk_update_link_clk_state(mngr, l_clks, (DSI_LINK_LP_CLK | + DSI_LINK_HS_CLK), DSI_CLK_OFF, false); + if (rc) + goto error; + + rc = dsi_clk_update_link_clk_state(mngr, l_clks, (DSI_LINK_LP_CLK | + DSI_LINK_HS_CLK), DSI_CLK_ON, true); + if (rc) + goto error; + +error: + mutex_unlock(&mngr->clk_mutex); + return rc; + +} + +int dsi_display_link_clk_force_update_ctrl(void *handle) +{ + int rc = 0; + + if (!handle) { + DSI_ERR("Invalid arg\n"); + return -EINVAL; + } + + mutex_lock(&dsi_mngr_clk_mutex); + + rc = dsi_display_link_clk_force_update(handle); + + mutex_unlock(&dsi_mngr_clk_mutex); + + return rc; +} + +int dsi_display_clk_ctrl(void *handle, + enum dsi_clk_type clk_type, enum dsi_clk_state clk_state) +{ + int rc = 0; + + if (!handle) { + DSI_ERR("Invalid arg\n"); + return -EINVAL; + } + + mutex_lock(&dsi_mngr_clk_mutex); + rc = dsi_clk_req_state(handle, clk_type, clk_state); + if (rc) + DSI_ERR("failed set clk state, rc = %d\n", rc); + mutex_unlock(&dsi_mngr_clk_mutex); + + return rc; +} + +void *dsi_register_clk_handle(void *clk_mngr, char *client) +{ + void *handle = NULL; + struct dsi_clk_mngr *mngr = clk_mngr; + struct dsi_clk_client_info *c; + + if (!mngr) { + DSI_ERR("bad params\n"); + return ERR_PTR(-EINVAL); + } + + mutex_lock(&mngr->clk_mutex); + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) { + handle = ERR_PTR(-ENOMEM); + goto error; + } + + strlcpy(c->name, client, MAX_STRING_LEN); + c->mngr = mngr; + + list_add(&c->list, &mngr->client_list); + + DSI_DEBUG("[%s]: Added new client (%s)\n", mngr->name, c->name); + handle = c; +error: + mutex_unlock(&mngr->clk_mutex); + return handle; +} + +int dsi_deregister_clk_handle(void *client) +{ + int rc = 0; + struct dsi_clk_client_info *c = client; + struct dsi_clk_mngr *mngr; + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + struct dsi_clk_client_info *node = NULL; + + if (!client) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mngr = c->mngr; + DSI_DEBUG("%s: ENTER\n", mngr->name); + mutex_lock(&mngr->clk_mutex); + c->core_clk_state = DSI_CLK_OFF; + c->link_clk_state = DSI_CLK_OFF; + + rc = dsi_recheck_clk_state(mngr); + if (rc) { + DSI_ERR("clock state recheck failed rc = %d\n", rc); + goto error; + } + + list_for_each_safe(pos, tmp, &mngr->client_list) { + node = list_entry(pos, struct dsi_clk_client_info, + list); + if (node == c) { + list_del(&node->list); + DSI_DEBUG("Removed device (%s)\n", node->name); + kfree(node); + break; + } + } + +error: + mutex_unlock(&mngr->clk_mutex); + DSI_DEBUG("%s: EXIT, rc = %d\n", mngr->name, rc); + return rc; +} + +void dsi_display_clk_mngr_update_splash_status(void *clk_mgr, bool status) +{ + struct dsi_clk_mngr *mngr; + + if (!clk_mgr) { + DSI_ERR("Invalid params\n"); + return; + } + + mngr = (struct dsi_clk_mngr *)clk_mgr; + mngr->is_cont_splash_enabled = status; +} + +void *dsi_display_clk_mngr_register(struct dsi_clk_info *info) +{ + struct dsi_clk_mngr *mngr; + int i = 0; + + if (!info) { + DSI_ERR("Invalid params\n"); + return ERR_PTR(-EINVAL); + } + + mngr = kzalloc(sizeof(*mngr), GFP_KERNEL); + if (!mngr) { + mngr = ERR_PTR(-ENOMEM); + goto error; + } + + mutex_init(&mngr->clk_mutex); + mngr->dsi_ctrl_count = info->dsi_ctrl_count; + mngr->master_ndx = info->master_ndx; + + if (mngr->dsi_ctrl_count > MAX_DSI_CTRL) { + kfree(mngr); + return ERR_PTR(-EINVAL); + } + + for (i = 0; i < mngr->dsi_ctrl_count; i++) { + memcpy(&mngr->core_clks[i].clks, &info->c_clks[i], + sizeof(struct dsi_core_clk_info)); + memcpy(&mngr->link_clks[i].hs_clks, &info->l_hs_clks[i], + sizeof(struct dsi_link_hs_clk_info)); + memcpy(&mngr->link_clks[i].lp_clks, &info->l_lp_clks[i], + sizeof(struct dsi_link_lp_clk_info)); + mngr->core_clks[i].bus_handle = info->bus_handle[i]; + mngr->ctrl_index[i] = info->ctrl_index[i]; + } + + INIT_LIST_HEAD(&mngr->client_list); + mngr->pre_clkon_cb = info->pre_clkon_cb; + mngr->post_clkon_cb = info->post_clkon_cb; + mngr->pre_clkoff_cb = info->pre_clkoff_cb; + mngr->post_clkoff_cb = info->post_clkoff_cb; + mngr->priv_data = info->priv_data; + memcpy(mngr->name, info->name, MAX_STRING_LEN); + +error: + DSI_DEBUG("EXIT, rc = %ld\n", PTR_ERR(mngr)); + return mngr; +} + +int dsi_display_clk_mngr_deregister(void *clk_mngr) +{ + int rc = 0; + struct dsi_clk_mngr *mngr = clk_mngr; + struct list_head *position = NULL; + struct list_head *tmp = NULL; + struct dsi_clk_client_info *node = NULL; + + if (!mngr) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + DSI_DEBUG("%s: ENTER\n", mngr->name); + mutex_lock(&mngr->clk_mutex); + + list_for_each_safe(position, tmp, &mngr->client_list) { + node = list_entry(position, struct dsi_clk_client_info, + list); + list_del(&node->list); + DSI_DEBUG("Removed device (%s)\n", node->name); + kfree(node); + } + + rc = dsi_recheck_clk_state(mngr); + if (rc) + DSI_ERR("failed to disable all clocks\n"); + + mutex_unlock(&mngr->clk_mutex); + DSI_DEBUG("%s: EXIT, rc = %d\n", mngr->name, rc); + kfree(mngr); + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_ctrl.c b/techpack/display/msm/dsi/dsi_ctrl.c new file mode 100644 index 0000000000000000000000000000000000000000..87b0062c353468cd57d8c0328d42f47e804bb9e5 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl.c @@ -0,0 +1,3948 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/of_device.h> +#include <linux/err.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#include <linux/msm-bus.h> +#include <linux/of_irq.h> +#include <video/mipi_display.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "msm_mmu.h" +#include "dsi_ctrl.h" +#include "dsi_ctrl_hw.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "dsi_catalog.h" +#include "dsi_panel.h" + +#include "sde_dbg.h" + +#define DSI_CTRL_DEFAULT_LABEL "MDSS DSI CTRL" + +#define DSI_CTRL_TX_TO_MS 200 + +#define TO_ON_OFF(x) ((x) ? "ON" : "OFF") + +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) + +#define TICKS_IN_MICRO_SECOND 1000000 + +#define DSI_CTRL_DEBUG(c, fmt, ...) DRM_DEV_DEBUG(NULL, "[msm-dsi-debug]: %s: "\ + fmt, c ? c->name : "inv", ##__VA_ARGS__) +#define DSI_CTRL_ERR(c, fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: %s: "\ + fmt, c ? c->name : "inv", ##__VA_ARGS__) +#define DSI_CTRL_INFO(c, fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: %s: "\ + fmt, c->name, ##__VA_ARGS__) +#define DSI_CTRL_WARN(c, fmt, ...) DRM_WARN("[msm-dsi-warn]: %s: " fmt,\ + c ? c->name : "inv", ##__VA_ARGS__) + +struct dsi_ctrl_list_item { + struct dsi_ctrl *ctrl; + struct list_head list; +}; + +static LIST_HEAD(dsi_ctrl_list); +static DEFINE_MUTEX(dsi_ctrl_list_lock); + +static const enum dsi_ctrl_version dsi_ctrl_v1_4 = DSI_CTRL_VERSION_1_4; +static const enum dsi_ctrl_version dsi_ctrl_v2_0 = DSI_CTRL_VERSION_2_0; +static const enum dsi_ctrl_version dsi_ctrl_v2_2 = DSI_CTRL_VERSION_2_2; +static const enum dsi_ctrl_version dsi_ctrl_v2_3 = DSI_CTRL_VERSION_2_3; +static const enum dsi_ctrl_version dsi_ctrl_v2_4 = DSI_CTRL_VERSION_2_4; + +static const struct of_device_id msm_dsi_of_match[] = { + { + .compatible = "qcom,dsi-ctrl-hw-v1.4", + .data = &dsi_ctrl_v1_4, + }, + { + .compatible = "qcom,dsi-ctrl-hw-v2.0", + .data = &dsi_ctrl_v2_0, + }, + { + .compatible = "qcom,dsi-ctrl-hw-v2.2", + .data = &dsi_ctrl_v2_2, + }, + { + .compatible = "qcom,dsi-ctrl-hw-v2.3", + .data = &dsi_ctrl_v2_3, + }, + { + .compatible = "qcom,dsi-ctrl-hw-v2.4", + .data = &dsi_ctrl_v2_4, + }, + {} +}; + +#ifdef CONFIG_DEBUG_FS +static ssize_t debugfs_state_info_read(struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + struct dsi_ctrl *dsi_ctrl = file->private_data; + char *buf; + u32 len = 0; + + if (!dsi_ctrl) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* Dump current state */ + len += snprintf((buf + len), (SZ_4K - len), "Current State:\n"); + len += snprintf((buf + len), (SZ_4K - len), + "\tCTRL_ENGINE = %s\n", + TO_ON_OFF(dsi_ctrl->current_state.controller_state)); + len += snprintf((buf + len), (SZ_4K - len), + "\tVIDEO_ENGINE = %s\n\tCOMMAND_ENGINE = %s\n", + TO_ON_OFF(dsi_ctrl->current_state.vid_engine_state), + TO_ON_OFF(dsi_ctrl->current_state.cmd_engine_state)); + + /* Dump clock information */ + len += snprintf((buf + len), (SZ_4K - len), "\nClock Info:\n"); + len += snprintf((buf + len), (SZ_4K - len), + "\tBYTE_CLK = %u, PIXEL_CLK = %u, ESC_CLK = %u\n", + dsi_ctrl->clk_freq.byte_clk_rate, + dsi_ctrl->clk_freq.pix_clk_rate, + dsi_ctrl->clk_freq.esc_clk_rate); + + if (len > count) + len = count; + + len = min_t(size_t, len, SZ_4K); + if (copy_to_user(buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static ssize_t debugfs_reg_dump_read(struct file *file, + char __user *buff, + size_t count, + loff_t *ppos) +{ + struct dsi_ctrl *dsi_ctrl = file->private_data; + char *buf; + u32 len = 0; + struct dsi_clk_ctrl_info clk_info; + int rc = 0; + + if (!dsi_ctrl) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + clk_info.client = DSI_CLK_REQ_DSI_CLIENT; + clk_info.clk_type = DSI_CORE_CLK; + clk_info.clk_state = DSI_CLK_ON; + + rc = dsi_ctrl->clk_cb.dsi_clk_cb(dsi_ctrl->clk_cb.priv, clk_info); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to enable DSI core clocks\n"); + kfree(buf); + return rc; + } + + if (dsi_ctrl->hw.ops.reg_dump_to_buffer) + len = dsi_ctrl->hw.ops.reg_dump_to_buffer(&dsi_ctrl->hw, + buf, SZ_4K); + + clk_info.clk_state = DSI_CLK_OFF; + rc = dsi_ctrl->clk_cb.dsi_clk_cb(dsi_ctrl->clk_cb.priv, clk_info); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to disable DSI core clocks\n"); + kfree(buf); + return rc; + } + + if (len > count) + len = count; + + len = min_t(size_t, len, SZ_4K); + if (copy_to_user(buff, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + kfree(buf); + return len; +} + +static const struct file_operations state_info_fops = { + .open = simple_open, + .read = debugfs_state_info_read, +}; + +static const struct file_operations reg_dump_fops = { + .open = simple_open, + .read = debugfs_reg_dump_read, +}; + +static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, + struct dentry *parent) +{ + int rc = 0; + struct dentry *dir, *state_file, *reg_dump; + char dbg_name[DSI_DEBUG_NAME_LEN]; + + if (!dsi_ctrl || !parent) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + dir = debugfs_create_dir(dsi_ctrl->name, parent); + if (IS_ERR_OR_NULL(dir)) { + rc = PTR_ERR(dir); + DSI_CTRL_ERR(dsi_ctrl, "debugfs create dir failed, rc=%d\n", + rc); + goto error; + } + + state_file = debugfs_create_file("state_info", + 0444, + dir, + dsi_ctrl, + &state_info_fops); + if (IS_ERR_OR_NULL(state_file)) { + rc = PTR_ERR(state_file); + DSI_CTRL_ERR(dsi_ctrl, "state file failed, rc=%d\n", rc); + goto error_remove_dir; + } + + reg_dump = debugfs_create_file("reg_dump", + 0444, + dir, + dsi_ctrl, + ®_dump_fops); + if (IS_ERR_OR_NULL(reg_dump)) { + rc = PTR_ERR(reg_dump); + DSI_CTRL_ERR(dsi_ctrl, "reg dump file failed, rc=%d\n", rc); + goto error_remove_dir; + } + + dsi_ctrl->debugfs_root = dir; + + snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl", + dsi_ctrl->cell_index); + sde_dbg_reg_register_base(dbg_name, dsi_ctrl->hw.base, + msm_iomap_size(dsi_ctrl->pdev, "dsi_ctrl")); +error_remove_dir: + debugfs_remove(dir); +error: + return rc; +} + +static int dsi_ctrl_debugfs_deinit(struct dsi_ctrl *dsi_ctrl) +{ + debugfs_remove(dsi_ctrl->debugfs_root); + return 0; +} +#else +static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl, + struct dentry *parent) +{ + return 0; +} +static int dsi_ctrl_debugfs_deinit(struct dsi_ctrl *dsi_ctrl) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static inline struct msm_gem_address_space* +dsi_ctrl_get_aspace(struct dsi_ctrl *dsi_ctrl, + int domain) +{ + if (!dsi_ctrl || !dsi_ctrl->drm_dev) + return NULL; + + return msm_gem_smmu_address_space_get(dsi_ctrl->drm_dev, domain); +} + +static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl) +{ + /* + * If a command is triggered right after another command, + * check if the previous command transfer is completed. If + * transfer is done, cancel any work that has been + * queued. Otherwise wait till the work is scheduled and + * completed before triggering the next command by + * flushing the workqueue. + */ + if (atomic_read(&dsi_ctrl->dma_irq_trig)) { + cancel_work_sync(&dsi_ctrl->dma_cmd_wait); + } else { + flush_workqueue(dsi_ctrl->dma_cmd_workq); + SDE_EVT32(SDE_EVTLOG_FUNC_CASE2); + } +} + +static void dsi_ctrl_dma_cmd_wait_for_done(struct work_struct *work) +{ + int ret = 0; + struct dsi_ctrl *dsi_ctrl = NULL; + u32 status; + u32 mask = DSI_CMD_MODE_DMA_DONE; + struct dsi_ctrl_hw_ops dsi_hw_ops; + + dsi_ctrl = container_of(work, struct dsi_ctrl, dma_cmd_wait); + dsi_hw_ops = dsi_ctrl->hw.ops; + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY); + + /* + * This atomic state will be set if ISR has been triggered, + * so the wait is not needed. + */ + if (atomic_read(&dsi_ctrl->dma_irq_trig)) + goto done; + + ret = wait_for_completion_timeout( + &dsi_ctrl->irq_info.cmd_dma_done, + msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); + if (ret == 0 && !atomic_read(&dsi_ctrl->dma_irq_trig)) { + status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw); + if (status & mask) { + status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE); + dsi_hw_ops.clear_interrupt_status(&dsi_ctrl->hw, + status); + DSI_CTRL_WARN(dsi_ctrl, + "dma_tx done but irq not triggered\n"); + } else { + DSI_CTRL_ERR(dsi_ctrl, + "Command transfer failed\n"); + } + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + } + +done: + dsi_ctrl->dma_wait_queued = false; +} + +static int dsi_ctrl_check_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_ctrl_driver_ops op, + u32 op_state) +{ + int rc = 0; + struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state; + + SDE_EVT32(dsi_ctrl->cell_index, op, op_state); + + switch (op) { + case DSI_CTRL_OP_POWER_STATE_CHANGE: + if (state->power_state == op_state) { + DSI_CTRL_ERR(dsi_ctrl, "No change in state, pwr_state=%d\n", + op_state); + rc = -EINVAL; + } else if (state->power_state == DSI_CTRL_POWER_VREG_ON) { + if (state->vid_engine_state == DSI_CTRL_ENGINE_ON) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d\n", + op_state, + state->vid_engine_state); + rc = -EINVAL; + } + } + break; + case DSI_CTRL_OP_CMD_ENGINE: + if (state->cmd_engine_state == op_state) { + DSI_CTRL_ERR(dsi_ctrl, "No change in state, cmd_state=%d\n", + op_state); + rc = -EINVAL; + } else if ((state->power_state != DSI_CTRL_POWER_VREG_ON) || + (state->controller_state != DSI_CTRL_ENGINE_ON)) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d, %d\n", + op, + state->power_state, + state->controller_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_VID_ENGINE: + if (state->vid_engine_state == op_state) { + DSI_CTRL_ERR(dsi_ctrl, "No change in state, cmd_state=%d\n", + op_state); + rc = -EINVAL; + } else if ((state->power_state != DSI_CTRL_POWER_VREG_ON) || + (state->controller_state != DSI_CTRL_ENGINE_ON)) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d, %d\n", + op, + state->power_state, + state->controller_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_HOST_ENGINE: + if (state->controller_state == op_state) { + DSI_CTRL_ERR(dsi_ctrl, "No change in state, ctrl_state=%d\n", + op_state); + rc = -EINVAL; + } else if (state->power_state != DSI_CTRL_POWER_VREG_ON) { + DSI_CTRL_ERR(dsi_ctrl, "State error (link is off): op=%d:, %d\n", + op_state, + state->power_state); + rc = -EINVAL; + } else if ((op_state == DSI_CTRL_ENGINE_OFF) && + ((state->cmd_engine_state != DSI_CTRL_ENGINE_OFF) || + (state->vid_engine_state != DSI_CTRL_ENGINE_OFF))) { + DSI_CTRL_ERR(dsi_ctrl, "State error (eng on): op=%d: %d, %d\n", + op_state, + state->cmd_engine_state, + state->vid_engine_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_CMD_TX: + if ((state->power_state != DSI_CTRL_POWER_VREG_ON) || + (!state->host_initialized) || + (state->cmd_engine_state != DSI_CTRL_ENGINE_ON)) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d, %d, %d\n", + op, + state->power_state, + state->host_initialized, + state->cmd_engine_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_HOST_INIT: + if (state->host_initialized == op_state) { + DSI_CTRL_ERR(dsi_ctrl, "No change in state, host_init=%d\n", + op_state); + rc = -EINVAL; + } else if (state->power_state != DSI_CTRL_POWER_VREG_ON) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d\n", + op, state->power_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_TPG: + if (state->tpg_enabled == op_state) { + DSI_CTRL_ERR(dsi_ctrl, "No change in state, tpg_enabled=%d\n", + op_state); + rc = -EINVAL; + } else if ((state->power_state != DSI_CTRL_POWER_VREG_ON) || + (state->controller_state != DSI_CTRL_ENGINE_ON)) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d, %d\n", + op, + state->power_state, + state->controller_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_PHY_SW_RESET: + if (state->power_state != DSI_CTRL_POWER_VREG_ON) { + DSI_CTRL_ERR(dsi_ctrl, "State error: op=%d: %d\n", + op, state->power_state); + rc = -EINVAL; + } + break; + case DSI_CTRL_OP_ASYNC_TIMING: + if (state->vid_engine_state != op_state) { + DSI_CTRL_ERR(dsi_ctrl, "Unexpected engine state vid_state=%d\n", + op_state); + rc = -EINVAL; + } + break; + default: + rc = -ENOTSUPP; + break; + } + + return rc; +} + +bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl) +{ + struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state; + + if (!state) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid host state for DSI controller\n"); + return -EINVAL; + } + + if (!state->host_initialized) + return false; + + return true; +} + +static void dsi_ctrl_update_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_ctrl_driver_ops op, + u32 op_state) +{ + struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state; + + switch (op) { + case DSI_CTRL_OP_POWER_STATE_CHANGE: + state->power_state = op_state; + break; + case DSI_CTRL_OP_CMD_ENGINE: + state->cmd_engine_state = op_state; + break; + case DSI_CTRL_OP_VID_ENGINE: + state->vid_engine_state = op_state; + break; + case DSI_CTRL_OP_HOST_ENGINE: + state->controller_state = op_state; + break; + case DSI_CTRL_OP_HOST_INIT: + state->host_initialized = (op_state == 1) ? true : false; + break; + case DSI_CTRL_OP_TPG: + state->tpg_enabled = (op_state == 1) ? true : false; + break; + case DSI_CTRL_OP_CMD_TX: + case DSI_CTRL_OP_PHY_SW_RESET: + default: + break; + } +} + +static int dsi_ctrl_init_regmap(struct platform_device *pdev, + struct dsi_ctrl *ctrl) +{ + int rc = 0; + void __iomem *ptr; + + ptr = msm_ioremap(pdev, "dsi_ctrl", ctrl->name); + if (IS_ERR(ptr)) { + rc = PTR_ERR(ptr); + return rc; + } + + ctrl->hw.base = ptr; + DSI_CTRL_DEBUG(ctrl, "map dsi_ctrl registers to %pK\n", ctrl->hw.base); + + switch (ctrl->version) { + case DSI_CTRL_VERSION_1_4: + case DSI_CTRL_VERSION_2_0: + ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name); + if (IS_ERR(ptr)) { + DSI_CTRL_ERR(ctrl, "mmss_misc base address not found\n"); + rc = PTR_ERR(ptr); + return rc; + } + ctrl->hw.mmss_misc_base = ptr; + ctrl->hw.disp_cc_base = NULL; + break; + case DSI_CTRL_VERSION_2_2: + case DSI_CTRL_VERSION_2_3: + case DSI_CTRL_VERSION_2_4: + ptr = msm_ioremap(pdev, "disp_cc_base", ctrl->name); + if (IS_ERR(ptr)) { + DSI_CTRL_ERR(ctrl, "disp_cc base address not found for\n"); + rc = PTR_ERR(ptr); + return rc; + } + ctrl->hw.disp_cc_base = ptr; + ctrl->hw.mmss_misc_base = NULL; + break; + default: + break; + } + + return rc; +} + +static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl) +{ + struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks; + struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks; + struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks; + struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks; + + if (core->mdp_core_clk) + devm_clk_put(&ctrl->pdev->dev, core->mdp_core_clk); + if (core->iface_clk) + devm_clk_put(&ctrl->pdev->dev, core->iface_clk); + if (core->core_mmss_clk) + devm_clk_put(&ctrl->pdev->dev, core->core_mmss_clk); + if (core->bus_clk) + devm_clk_put(&ctrl->pdev->dev, core->bus_clk); + if (core->mnoc_clk) + devm_clk_put(&ctrl->pdev->dev, core->mnoc_clk); + + memset(core, 0x0, sizeof(*core)); + + if (hs_link->byte_clk) + devm_clk_put(&ctrl->pdev->dev, hs_link->byte_clk); + if (hs_link->pixel_clk) + devm_clk_put(&ctrl->pdev->dev, hs_link->pixel_clk); + if (lp_link->esc_clk) + devm_clk_put(&ctrl->pdev->dev, lp_link->esc_clk); + if (hs_link->byte_intf_clk) + devm_clk_put(&ctrl->pdev->dev, hs_link->byte_intf_clk); + + memset(hs_link, 0x0, sizeof(*hs_link)); + memset(lp_link, 0x0, sizeof(*lp_link)); + + if (rcg->byte_clk) + devm_clk_put(&ctrl->pdev->dev, rcg->byte_clk); + if (rcg->pixel_clk) + devm_clk_put(&ctrl->pdev->dev, rcg->pixel_clk); + + memset(rcg, 0x0, sizeof(*rcg)); + + return 0; +} + +static int dsi_ctrl_clocks_init(struct platform_device *pdev, + struct dsi_ctrl *ctrl) +{ + int rc = 0; + struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks; + struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks; + struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks; + struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks; + + core->mdp_core_clk = devm_clk_get(&pdev->dev, "mdp_core_clk"); + if (IS_ERR(core->mdp_core_clk)) { + core->mdp_core_clk = NULL; + DSI_CTRL_DEBUG(ctrl, "failed to get mdp_core_clk, rc=%d\n", rc); + } + + core->iface_clk = devm_clk_get(&pdev->dev, "iface_clk"); + if (IS_ERR(core->iface_clk)) { + core->iface_clk = NULL; + DSI_CTRL_DEBUG(ctrl, "failed to get iface_clk, rc=%d\n", rc); + } + + core->core_mmss_clk = devm_clk_get(&pdev->dev, "core_mmss_clk"); + if (IS_ERR(core->core_mmss_clk)) { + core->core_mmss_clk = NULL; + DSI_CTRL_DEBUG(ctrl, "failed to get core_mmss_clk, rc=%d\n", + rc); + } + + core->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); + if (IS_ERR(core->bus_clk)) { + core->bus_clk = NULL; + DSI_CTRL_DEBUG(ctrl, "failed to get bus_clk, rc=%d\n", rc); + } + + core->mnoc_clk = devm_clk_get(&pdev->dev, "mnoc_clk"); + if (IS_ERR(core->mnoc_clk)) { + core->mnoc_clk = NULL; + DSI_CTRL_DEBUG(ctrl, "can't get mnoc clock, rc=%d\n", rc); + } + + hs_link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk"); + if (IS_ERR(hs_link->byte_clk)) { + rc = PTR_ERR(hs_link->byte_clk); + DSI_CTRL_ERR(ctrl, "failed to get byte_clk, rc=%d\n", rc); + goto fail; + } + + hs_link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk"); + if (IS_ERR(hs_link->pixel_clk)) { + rc = PTR_ERR(hs_link->pixel_clk); + DSI_CTRL_ERR(ctrl, "failed to get pixel_clk, rc=%d\n", rc); + goto fail; + } + + lp_link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk"); + if (IS_ERR(lp_link->esc_clk)) { + rc = PTR_ERR(lp_link->esc_clk); + DSI_CTRL_ERR(ctrl, "failed to get esc_clk, rc=%d\n", rc); + goto fail; + } + + hs_link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk"); + if (IS_ERR(hs_link->byte_intf_clk)) { + hs_link->byte_intf_clk = NULL; + DSI_CTRL_DEBUG(ctrl, "can't find byte intf clk, rc=%d\n", rc); + } + + rcg->byte_clk = devm_clk_get(&pdev->dev, "byte_clk_rcg"); + if (IS_ERR(rcg->byte_clk)) { + rc = PTR_ERR(rcg->byte_clk); + DSI_CTRL_ERR(ctrl, "failed to get byte_clk_rcg, rc=%d\n", rc); + goto fail; + } + + rcg->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk_rcg"); + if (IS_ERR(rcg->pixel_clk)) { + rc = PTR_ERR(rcg->pixel_clk); + DSI_CTRL_ERR(ctrl, "failed to get pixel_clk_rcg, rc=%d\n", rc); + goto fail; + } + + return 0; +fail: + dsi_ctrl_clocks_deinit(ctrl); + return rc; +} + +static int dsi_ctrl_supplies_deinit(struct dsi_ctrl *ctrl) +{ + int i = 0; + int rc = 0; + struct dsi_regulator_info *regs; + + regs = &ctrl->pwr_info.digital; + for (i = 0; i < regs->count; i++) { + if (!regs->vregs[i].vreg) + DSI_CTRL_ERR(ctrl, + "vreg is NULL, should not reach here\n"); + else + devm_regulator_put(regs->vregs[i].vreg); + } + + regs = &ctrl->pwr_info.host_pwr; + for (i = 0; i < regs->count; i++) { + if (!regs->vregs[i].vreg) + DSI_CTRL_ERR(ctrl, + "vreg is NULL, should not reach here\n"); + else + devm_regulator_put(regs->vregs[i].vreg); + } + + if (!ctrl->pwr_info.host_pwr.vregs) { + devm_kfree(&ctrl->pdev->dev, ctrl->pwr_info.host_pwr.vregs); + ctrl->pwr_info.host_pwr.vregs = NULL; + ctrl->pwr_info.host_pwr.count = 0; + } + + if (!ctrl->pwr_info.digital.vregs) { + devm_kfree(&ctrl->pdev->dev, ctrl->pwr_info.digital.vregs); + ctrl->pwr_info.digital.vregs = NULL; + ctrl->pwr_info.digital.count = 0; + } + + return rc; +} + +static int dsi_ctrl_supplies_init(struct platform_device *pdev, + struct dsi_ctrl *ctrl) +{ + int rc = 0; + int i = 0; + struct dsi_regulator_info *regs; + struct regulator *vreg = NULL; + + rc = dsi_pwr_get_dt_vreg_data(&pdev->dev, + &ctrl->pwr_info.digital, + "qcom,core-supply-entries"); + if (rc) + DSI_CTRL_DEBUG(ctrl, + "failed to get digital supply, rc = %d\n", rc); + + rc = dsi_pwr_get_dt_vreg_data(&pdev->dev, + &ctrl->pwr_info.host_pwr, + "qcom,ctrl-supply-entries"); + if (rc) { + DSI_CTRL_ERR(ctrl, + "failed to get host power supplies, rc = %d\n", rc); + goto error_digital; + } + + regs = &ctrl->pwr_info.digital; + for (i = 0; i < regs->count; i++) { + vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name); + if (IS_ERR(vreg)) { + DSI_CTRL_ERR(ctrl, "failed to get %s regulator\n", + regs->vregs[i].vreg_name); + rc = PTR_ERR(vreg); + goto error_host_pwr; + } + regs->vregs[i].vreg = vreg; + } + + regs = &ctrl->pwr_info.host_pwr; + for (i = 0; i < regs->count; i++) { + vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name); + if (IS_ERR(vreg)) { + DSI_CTRL_ERR(ctrl, "failed to get %s regulator\n", + regs->vregs[i].vreg_name); + for (--i; i >= 0; i--) + devm_regulator_put(regs->vregs[i].vreg); + rc = PTR_ERR(vreg); + goto error_digital_put; + } + regs->vregs[i].vreg = vreg; + } + + return rc; + +error_digital_put: + regs = &ctrl->pwr_info.digital; + for (i = 0; i < regs->count; i++) + devm_regulator_put(regs->vregs[i].vreg); +error_host_pwr: + devm_kfree(&pdev->dev, ctrl->pwr_info.host_pwr.vregs); + ctrl->pwr_info.host_pwr.vregs = NULL; + ctrl->pwr_info.host_pwr.count = 0; +error_digital: + if (ctrl->pwr_info.digital.vregs) + devm_kfree(&pdev->dev, ctrl->pwr_info.digital.vregs); + ctrl->pwr_info.digital.vregs = NULL; + ctrl->pwr_info.digital.count = 0; + return rc; +} + +static int dsi_ctrl_axi_bus_client_init(struct platform_device *pdev, + struct dsi_ctrl *ctrl) +{ + int rc = 0; + struct dsi_ctrl_bus_scale_info *bus = &ctrl->axi_bus_info; + + bus->bus_scale_table = msm_bus_cl_get_pdata(pdev); + if (IS_ERR_OR_NULL(bus->bus_scale_table)) { + rc = PTR_ERR(bus->bus_scale_table); + DSI_CTRL_DEBUG(ctrl, "msm_bus_cl_get_pdata() failed, rc = %d\n", + rc); + bus->bus_scale_table = NULL; + return rc; + } + + bus->bus_handle = msm_bus_scale_register_client(bus->bus_scale_table); + if (!bus->bus_handle) { + rc = -EINVAL; + DSI_CTRL_ERR(ctrl, "failed to register axi bus client\n"); + } + + return rc; +} + +static int dsi_ctrl_axi_bus_client_deinit(struct dsi_ctrl *ctrl) +{ + struct dsi_ctrl_bus_scale_info *bus = &ctrl->axi_bus_info; + + if (bus->bus_handle) { + msm_bus_scale_unregister_client(bus->bus_handle); + + bus->bus_handle = 0; + } + + return 0; +} + +static int dsi_ctrl_validate_panel_info(struct dsi_ctrl *dsi_ctrl, + struct dsi_host_config *config) +{ + int rc = 0; + struct dsi_host_common_cfg *host_cfg = &config->common_config; + + if (config->panel_mode >= DSI_OP_MODE_MAX) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid dsi operation mode (%d)\n", + config->panel_mode); + rc = -EINVAL; + goto err; + } + + if ((host_cfg->data_lanes & (DSI_CLOCK_LANE - 1)) == 0) { + DSI_CTRL_ERR(dsi_ctrl, "No data lanes are enabled\n"); + rc = -EINVAL; + goto err; + } +err: + return rc; +} + +/* Function returns number of bits per pxl */ +int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format) +{ + u32 bpp = 0; + + switch (dst_format) { + case DSI_PIXEL_FORMAT_RGB111: + bpp = 3; + break; + case DSI_PIXEL_FORMAT_RGB332: + bpp = 8; + break; + case DSI_PIXEL_FORMAT_RGB444: + bpp = 12; + break; + case DSI_PIXEL_FORMAT_RGB565: + bpp = 16; + break; + case DSI_PIXEL_FORMAT_RGB666: + case DSI_PIXEL_FORMAT_RGB666_LOOSE: + bpp = 18; + break; + case DSI_PIXEL_FORMAT_RGB888: + bpp = 24; + break; + default: + bpp = 24; + break; + } + return bpp; +} + +static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl, + struct dsi_host_config *config, void *clk_handle, + struct dsi_display_mode *mode) +{ + int rc = 0; + u32 num_of_lanes = 0; + u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */ + u32 bpp, frame_time_us, byte_intf_clk_div; + u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, + byte_clk_rate, byte_intf_clk_rate; + struct dsi_host_common_cfg *host_cfg = &config->common_config; + struct dsi_split_link_config *split_link = &host_cfg->split_link; + struct dsi_mode_info *timing = &config->video_timing; + u64 dsi_transfer_time_us = mode->priv_info->dsi_transfer_time_us; + u64 min_dsi_clk_hz = mode->priv_info->min_dsi_clk_hz; + + /* Get bits per pxl in destination format */ + bpp = dsi_ctrl_pixel_format_to_bpp(host_cfg->dst_format); + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); + + if (host_cfg->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + if (split_link->split_link_enabled) + num_of_lanes = split_link->lanes_per_sublink; + + config->common_config.num_data_lanes = num_of_lanes; + config->common_config.bpp = bpp; + + if (config->bit_clk_rate_hz_override != 0) { + bit_rate = config->bit_clk_rate_hz_override * num_of_lanes; + if (host_cfg->phy_type == DSI_PHY_TYPE_CPHY) { + bit_rate *= bits_per_symbol; + do_div(bit_rate, num_of_symbols); + } + } else if (config->panel_mode == DSI_OP_CMD_MODE) { + /* Calculate the bit rate needed to match dsi transfer time */ + bit_rate = min_dsi_clk_hz * frame_time_us; + do_div(bit_rate, dsi_transfer_time_us); + bit_rate = bit_rate * num_of_lanes; + } else { + h_period = DSI_H_TOTAL_DSC(timing); + v_period = DSI_V_TOTAL(timing); + bit_rate = h_period * v_period * timing->refresh_rate * bpp; + } + + + pclk_rate = bit_rate; + do_div(pclk_rate, bpp); + if (host_cfg->phy_type == DSI_PHY_TYPE_DPHY) { + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 8); + byte_intf_clk_rate = byte_clk_rate; + byte_intf_clk_div = host_cfg->byte_intf_clk_div; + do_div(byte_intf_clk_rate, byte_intf_clk_div); + config->bit_clk_rate_hz = byte_clk_rate * 8; + } else { + do_div(bit_rate, bits_per_symbol); + bit_rate *= num_of_symbols; + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 7); + /* For CPHY, byte_intf_clk is same as byte_clk */ + byte_intf_clk_rate = byte_clk_rate; + config->bit_clk_rate_hz = byte_clk_rate * 7; + } + DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", + bit_rate, bit_rate_per_lane); + DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, byte_intf_clk = %llu\n", + byte_clk_rate, byte_intf_clk_rate); + DSI_CTRL_DEBUG(dsi_ctrl, "pclk_rate = %llu\n", pclk_rate); + SDE_EVT32(dsi_ctrl->cell_index, bit_rate, byte_clk_rate, pclk_rate); + + dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate; + dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate; + dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate; + dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz; + + rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq, + dsi_ctrl->cell_index); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, "Failed to update link frequencies\n"); + + return rc; +} + +static int dsi_ctrl_enable_supplies(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + int rc = 0; + + if (enable) { + rc = pm_runtime_get_sync(dsi_ctrl->drm_dev->dev); + if (rc < 0) { + DSI_CTRL_ERR(dsi_ctrl, + "Power resource enable failed, rc=%d\n", rc); + goto error; + } + + if (!dsi_ctrl->current_state.host_initialized) { + rc = dsi_pwr_enable_regulator( + &dsi_ctrl->pwr_info.host_pwr, true); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to enable host power regs\n"); + goto error_get_sync; + } + } + + rc = dsi_pwr_enable_regulator(&dsi_ctrl->pwr_info.digital, + true); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to enable gdsc, rc=%d\n", + rc); + (void)dsi_pwr_enable_regulator( + &dsi_ctrl->pwr_info.host_pwr, + false + ); + goto error_get_sync; + } + return rc; + } else { + rc = dsi_pwr_enable_regulator(&dsi_ctrl->pwr_info.digital, + false); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to disable gdsc, rc=%d\n", + rc); + goto error; + } + + if (!dsi_ctrl->current_state.host_initialized) { + rc = dsi_pwr_enable_regulator( + &dsi_ctrl->pwr_info.host_pwr, false); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to disable host power regs\n"); + goto error; + } + } + pm_runtime_put_sync(dsi_ctrl->drm_dev->dev); + return rc; + } +error_get_sync: + pm_runtime_put_sync(dsi_ctrl->drm_dev->dev); +error: + return rc; +} + +static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_packet *packet, + u8 **buffer, + u32 *size) +{ + int rc = 0; + u8 *buf = NULL; + u32 len, i; + u8 cmd_type = 0; + + len = packet->size; + len += 0x3; len &= ~0x03; /* Align to 32 bits */ + + buf = devm_kzalloc(&dsi_ctrl->pdev->dev, len * sizeof(u8), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (i = 0; i < len; i++) { + if (i >= packet->size) + buf[i] = 0xFF; + else if (i < sizeof(packet->header)) + buf[i] = packet->header[i]; + else + buf[i] = packet->payload[i - sizeof(packet->header)]; + } + + if (packet->payload_length > 0) + buf[3] |= BIT(6); + + + /* send embedded BTA for read commands */ + cmd_type = buf[2] & 0x3f; + if ((cmd_type == MIPI_DSI_DCS_READ) || + (cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM) || + (cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM) || + (cmd_type == MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM)) + buf[3] |= BIT(5); + + *buffer = buf; + *size = len; + + return rc; +} + +int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + if (dsi_ctrl->host_config.panel_mode != DSI_OP_CMD_MODE) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl->hw.ops.wait_for_cmd_mode_mdp_idle(&dsi_ctrl->hw); + + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl) +{ + u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret; + struct dsi_mode_info *timing; + + /** + * No need to wait if the panel is not video mode or + * if DSI controller supports command DMA scheduling or + * if we are sending init commands. + */ + if ((dsi_ctrl->host_config.panel_mode != DSI_OP_VIDEO_MODE) || + (dsi_ctrl->version >= DSI_CTRL_VERSION_2_2) || + (dsi_ctrl->current_state.vid_engine_state != + DSI_CTRL_ENGINE_ON)) + return; + + dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, + DSI_VIDEO_MODE_FRAME_DONE); + + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_VIDEO_MODE_FRAME_DONE, NULL); + reinit_completion(&dsi_ctrl->irq_info.vid_frame_done); + ret = wait_for_completion_timeout( + &dsi_ctrl->irq_info.vid_frame_done, + msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); + if (ret <= 0) + DSI_CTRL_DEBUG(dsi_ctrl, "wait for video done failed\n"); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_VIDEO_MODE_FRAME_DONE); + + timing = &(dsi_ctrl->host_config.video_timing); + v_total = timing->v_sync_width + timing->v_back_porch + + timing->v_front_porch + timing->v_active; + v_blank = timing->v_sync_width + timing->v_back_porch; + fps = timing->refresh_rate; + + sleep_ms = CEIL((v_blank * 1000), (v_total * fps)) + 1; + udelay(sleep_ms * 1000); +} + +void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, + u32 cmd_len, + u32 *flags) +{ + /** + * Setup the mode of transmission + * override cmd fetch mode during secure session + */ + if (dsi_ctrl->secure_mode) { + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1); + *flags &= ~DSI_CTRL_CMD_FETCH_MEMORY; + *flags |= DSI_CTRL_CMD_FIFO_STORE; + DSI_CTRL_DEBUG(dsi_ctrl, + "override to TPG during secure session\n"); + return; + } + + /* Check to see if cmd len plus header is greater than fifo size */ + if ((cmd_len + 4) > DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES) { + *flags |= DSI_CTRL_CMD_NON_EMBEDDED_MODE; + DSI_CTRL_DEBUG(dsi_ctrl, "override to non-embedded mode,cmd len =%d\n", + cmd_len); + return; + } +} + +int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, + u32 cmd_len, + u32 *flags) +{ + int rc = 0; + + if (*flags & DSI_CTRL_CMD_FIFO_STORE) { + /* if command size plus header is greater than fifo size */ + if ((cmd_len + 4) > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE) { + DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer Cmd in FIFO config\n"); + return -ENOTSUPP; + } + if (!dsi_ctrl->hw.ops.kickoff_fifo_command) { + DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer command,ops not defined\n"); + return -ENOTSUPP; + } + } + + if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + if (*flags & DSI_CTRL_CMD_BROADCAST) { + DSI_CTRL_ERR(dsi_ctrl, "Non embedded not supported with broadcast\n"); + return -ENOTSUPP; + } + if (!dsi_ctrl->hw.ops.kickoff_command_non_embedded_mode) { + DSI_CTRL_ERR(dsi_ctrl, " Cannot transfer command,ops not defined\n"); + return -ENOTSUPP; + } + if ((cmd_len + 4) > SZ_4K) { + DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer,size is greater than 4096\n"); + return -ENOTSUPP; + } + } + + if (*flags & DSI_CTRL_CMD_FETCH_MEMORY) { + if ((dsi_ctrl->cmd_len + cmd_len + 4) > SZ_4K) { + DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer,size is greater than 4096\n"); + return -ENOTSUPP; + } + } + + return rc; +} + +static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, + struct dsi_ctrl_cmd_dma_fifo_info *cmd, + struct dsi_ctrl_cmd_dma_info *cmd_mem, + u32 flags) +{ + u32 hw_flags = 0; + u32 line_no = 0x1; + struct dsi_mode_info *timing; + struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops; + + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags, + msg->flags); + /* check if custom dma scheduling line needed */ + if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && + (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) + line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; + + timing = &(dsi_ctrl->host_config.video_timing); + if (timing) + line_no += timing->v_back_porch + timing->v_sync_width + + timing->v_active; + if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && + dsi_hw_ops.schedule_dma_cmd && + (dsi_ctrl->current_state.vid_engine_state == + DSI_CTRL_ENGINE_ON)) + dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, + line_no); + + hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ? + DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0; + + if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) + hw_flags |= DSI_CTRL_CMD_LAST_COMMAND; + + if (flags & DSI_CTRL_CMD_DEFER_TRIGGER) { + if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + dsi_hw_ops.kickoff_command_non_embedded_mode( + &dsi_ctrl->hw, + cmd_mem, + hw_flags); + } else { + dsi_hw_ops.kickoff_command( + &dsi_ctrl->hw, + cmd_mem, + hw_flags); + } + } else if (flags & DSI_CTRL_CMD_FIFO_STORE) { + dsi_hw_ops.kickoff_fifo_command(&dsi_ctrl->hw, + cmd, + hw_flags); + } + } + + if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER)) { + dsi_ctrl_wait_for_video_done(dsi_ctrl); + dsi_ctrl_mask_overflow(dsi_ctrl, true); + + atomic_set(&dsi_ctrl->dma_irq_trig, 0); + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE, NULL); + reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); + + if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + dsi_hw_ops.kickoff_command_non_embedded_mode( + &dsi_ctrl->hw, + cmd_mem, + hw_flags); + } else { + dsi_hw_ops.kickoff_command( + &dsi_ctrl->hw, + cmd_mem, + hw_flags); + } + } else if (flags & DSI_CTRL_CMD_FIFO_STORE) { + dsi_hw_ops.kickoff_fifo_command(&dsi_ctrl->hw, + cmd, + hw_flags); + } + if (flags & DSI_CTRL_CMD_ASYNC_WAIT) { + dsi_ctrl->dma_wait_queued = true; + queue_work(dsi_ctrl->dma_cmd_workq, + &dsi_ctrl->dma_cmd_wait); + } else { + dsi_ctrl->dma_wait_queued = false; + dsi_ctrl_dma_cmd_wait_for_done(&dsi_ctrl->dma_cmd_wait); + } + + dsi_ctrl_mask_overflow(dsi_ctrl, false); + + dsi_hw_ops.reset_cmd_fifo(&dsi_ctrl->hw); + + /* + * DSI 2.2 needs a soft reset whenever we send non-embedded + * mode command followed by embedded mode. Otherwise it will + * result in smmu write faults with DSI as client. + */ + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4) + dsi_hw_ops.soft_reset(&dsi_ctrl->hw); + dsi_ctrl->cmd_len = 0; + } + } +} +static void print_cmd_desc(struct dsi_ctrl *dsi_ctrl, const struct mipi_dsi_msg *msg) +{ + char buf[1024]; + int len = 0; + size_t i; + char *tx_buf = (char*)msg->tx_buf; + + /* Packet Info */ + len += snprintf(buf, sizeof(buf) - len, "%02X ", msg->type); + /* Last bit */ + len += snprintf(buf + len, sizeof(buf) - len, "%02X ", (msg->flags & MIPI_DSI_MSG_LASTCOMMAND) ? 1 : 0); + len += snprintf(buf + len, sizeof(buf) - len, "%02X ", msg->channel); + len += snprintf(buf + len, sizeof(buf) - len, "%02X ", (unsigned int)msg->flags); + /* Delay */ + len += snprintf(buf + len, sizeof(buf) - len, "%02X ", msg->wait_ms); + len += snprintf(buf + len, sizeof(buf) - len, "%02X %02X ", msg->tx_len >> 8, msg->tx_len & 0x00FF); + + /* Packet Payload */ + for (i = 0 ; i < msg->tx_len ; i++) { + len += snprintf(buf + len, sizeof(buf) - len, "%02X ", tx_buf[i]); + /* Break to prevent show too long command */ + if (i > 250) + break; + } + + DSI_CTRL_ERR(dsi_ctrl, "%s\n", buf); +} + +extern int dsi_cmd_log_enable; + +static void dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, + u32 *flags) +{ + /* + * ASYNC command wait mode is not supported for + * - commands sent using DSI FIFO memory + * - DSI read commands + * - DCS commands sent in non-embedded mode + * - whenever an explicit wait time is specificed for the command + * since the wait time cannot be guaranteed in async mode + * - video mode panels + * If async override is set, skip async flag reset + */ + if (((*flags & DSI_CTRL_CMD_FIFO_STORE) || + *flags & DSI_CTRL_CMD_READ || + *flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE || + msg->wait_ms || + (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) && + !(msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE)) + *flags &= ~DSI_CTRL_CMD_ASYNC_WAIT; +} + +static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, + u32 *flags) +{ + int rc = 0; + struct mipi_dsi_packet packet; + struct dsi_ctrl_cmd_dma_fifo_info cmd; + struct dsi_ctrl_cmd_dma_info cmd_mem; + u32 length = 0; + u8 *buffer = NULL; + u32 cnt = 0; + u8 *cmdbuf; + + if (dsi_cmd_log_enable) + print_cmd_desc(dsi_ctrl, msg); + + /* Select the tx mode to transfer the command */ + dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, flags); + + /* Validate the mode before sending the command */ + rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, flags); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, + "Cmd tx validation failed, cannot transfer cmd\n"); + rc = -ENOTSUPP; + goto error; + } + + dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags); + + if (dsi_ctrl->dma_wait_queued) + dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl); + + if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; + cmd_mem.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ? + true : false; + cmd_mem.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + true : false; + cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? + true : false; + cmd_mem.datatype = msg->type; + cmd_mem.length = msg->tx_len; + + dsi_ctrl->cmd_len = msg->tx_len; + memcpy(dsi_ctrl->vaddr, msg->tx_buf, msg->tx_len); + DSI_CTRL_DEBUG(dsi_ctrl, + "non-embedded mode , size of command =%zd\n", + msg->tx_len); + + goto kickoff; + } + + rc = mipi_dsi_create_packet(&packet, msg); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to create message packet, rc=%d\n", + rc); + goto error; + } + + rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl, + &packet, + &buffer, + &length); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to copy message, rc=%d\n", rc); + goto error; + } + + if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) + buffer[3] |= BIT(7);//set the last cmd bit in header. + + if (*flags & DSI_CTRL_CMD_FETCH_MEMORY) { + /* Embedded mode config is selected */ + cmd_mem.offset = dsi_ctrl->cmd_buffer_iova; + cmd_mem.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ? + true : false; + cmd_mem.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + true : false; + cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? + true : false; + + cmdbuf = (u8 *)(dsi_ctrl->vaddr); + + msm_gem_sync(dsi_ctrl->tx_cmd_buf); + for (cnt = 0; cnt < length; cnt++) + cmdbuf[dsi_ctrl->cmd_len + cnt] = buffer[cnt]; + + dsi_ctrl->cmd_len += length; + + if (!(msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) { + goto error; + } else { + cmd_mem.length = dsi_ctrl->cmd_len; + dsi_ctrl->cmd_len = 0; + } + + } else if (*flags & DSI_CTRL_CMD_FIFO_STORE) { + cmd.command = (u32 *)buffer; + cmd.size = length; + cmd.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ? + true : false; + cmd.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ? + true : false; + cmd.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ? + true : false; + } + +kickoff: + dsi_kickoff_msg_tx(dsi_ctrl, msg, &cmd, &cmd_mem, *flags); +error: + if (buffer) + devm_kfree(&dsi_ctrl->pdev->dev, buffer); + return rc; +} + +static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *rx_msg, + u32 size) +{ + int rc = 0; + u8 tx[2] = { (u8)(size & 0xFF), (u8)(size >> 8) }; + u32 flags = DSI_CTRL_CMD_FETCH_MEMORY; + u16 dflags = rx_msg->flags; + + struct mipi_dsi_msg msg = { + .channel = rx_msg->channel, + .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, + .tx_len = 2, + .tx_buf = tx, + .flags = rx_msg->flags, + }; + + /* remove last message flag to batch max packet cmd to read command */ + dflags &= ~BIT(3); + msg.flags = dflags; + + rc = dsi_message_tx(dsi_ctrl, &msg, &flags); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, "failed to send max return size packet, rc=%d\n", + rc); + + return rc; +} + +/* Helper functions to support DCS read operation */ +static int dsi_parse_short_read1_resp(const struct mipi_dsi_msg *msg, + unsigned char *buff) +{ + u8 *data = msg->rx_buf; + int read_len = 1; + + if (!data) + return 0; + + /* remove dcs type */ + if (msg->rx_len >= 1) + data[0] = buff[1]; + else + read_len = 0; + + return read_len; +} + +static int dsi_parse_short_read2_resp(const struct mipi_dsi_msg *msg, + unsigned char *buff) +{ + u8 *data = msg->rx_buf; + int read_len = 2; + + if (!data) + return 0; + + /* remove dcs type */ + if (msg->rx_len >= 2) { + data[0] = buff[1]; + data[1] = buff[2]; + } else { + read_len = 0; + } + + return read_len; +} + +static int dsi_parse_long_read_resp(const struct mipi_dsi_msg *msg, + unsigned char *buff) +{ + if (!msg->rx_buf) + return 0; + + /* remove dcs type */ + if (msg->rx_buf && msg->rx_len) + memcpy(msg->rx_buf, buff + 4, msg->rx_len); + + return msg->rx_len; +} + +static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, + u32 *flags) +{ + int rc = 0; + u32 rd_pkt_size, total_read_len, hw_read_cnt; + u32 current_read_len = 0, total_bytes_read = 0; + bool short_resp = false; + bool read_done = false; + u32 dlen, diff, rlen; + unsigned char *buff; + char cmd; + + if (!msg) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid msg\n"); + rc = -EINVAL; + goto error; + } + + rlen = msg->rx_len; + if (msg->rx_len <= 2) { + short_resp = true; + rd_pkt_size = msg->rx_len; + total_read_len = 4; + } else { + short_resp = false; + current_read_len = 10; + if (msg->rx_len < current_read_len) + rd_pkt_size = msg->rx_len; + else + rd_pkt_size = current_read_len; + + total_read_len = current_read_len + 6; + } + buff = msg->rx_buf; + + while (!read_done) { + rc = dsi_set_max_return_size(dsi_ctrl, msg, rd_pkt_size); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to set max return packet size, rc=%d\n", + rc); + goto error; + } + + /* clear RDBK_DATA registers before proceeding */ + dsi_ctrl->hw.ops.clear_rdbk_register(&dsi_ctrl->hw); + + rc = dsi_message_tx(dsi_ctrl, msg, flags); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Message transmission failed, rc=%d\n", + rc); + goto error; + } + /* + * wait before reading rdbk_data register, if any delay is + * required after sending the read command. + */ + if (msg->wait_ms) + usleep_range(msg->wait_ms * 1000, + ((msg->wait_ms * 1000) + 10)); + + dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw, + buff, total_bytes_read, + total_read_len, rd_pkt_size, + &hw_read_cnt); + if (!dlen) + goto error; + + if (short_resp) + break; + + if (rlen <= current_read_len) { + diff = current_read_len - rlen; + read_done = true; + } else { + diff = 0; + rlen -= current_read_len; + } + + dlen -= 2; /* 2 bytes of CRC */ + dlen -= diff; + buff += dlen; + total_bytes_read += dlen; + if (!read_done) { + current_read_len = 14; /* Not first read */ + if (rlen < current_read_len) + rd_pkt_size += rlen; + else + rd_pkt_size += current_read_len; + } + } + + if (hw_read_cnt < 16 && !short_resp) + buff = msg->rx_buf + (16 - hw_read_cnt); + else + buff = msg->rx_buf; + + /* parse the data read from panel */ + cmd = buff[0]; + switch (cmd) { + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: + DSI_CTRL_ERR(dsi_ctrl, "Rx ACK_ERROR 0x%x\n", cmd); + rc = 0; + break; + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: + rc = dsi_parse_short_read1_resp(msg, buff); + break; + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: + rc = dsi_parse_short_read2_resp(msg, buff); + break; + case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE: + case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE: + rc = dsi_parse_long_read_resp(msg, buff); + break; + default: + DSI_CTRL_WARN(dsi_ctrl, "Invalid response: 0x%x\n", cmd); + rc = 0; + } + +error: + return rc; +} + +static int dsi_enable_ulps(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + u32 lanes = 0; + u32 ulps_lanes; + + lanes = dsi_ctrl->host_config.common_config.data_lanes; + + rc = dsi_ctrl->hw.ops.wait_for_lane_idle(&dsi_ctrl->hw, lanes); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "lanes not entering idle, skip ULPS\n"); + return rc; + } + + if (!dsi_ctrl->hw.ops.ulps_ops.ulps_request || + !dsi_ctrl->hw.ops.ulps_ops.ulps_exit) { + DSI_CTRL_DEBUG(dsi_ctrl, "DSI controller ULPS ops not present\n"); + return 0; + } + + lanes |= DSI_CLOCK_LANE; + dsi_ctrl->hw.ops.ulps_ops.ulps_request(&dsi_ctrl->hw, lanes); + + ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw); + + if ((lanes & ulps_lanes) != lanes) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to enter ULPS, request=0x%x, actual=0x%x\n", + lanes, ulps_lanes); + rc = -EIO; + } + + return rc; +} + +static int dsi_disable_ulps(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + u32 ulps_lanes, lanes = 0; + + dsi_ctrl->hw.ops.clear_phy0_ln_err(&dsi_ctrl->hw); + + if (!dsi_ctrl->hw.ops.ulps_ops.ulps_request || + !dsi_ctrl->hw.ops.ulps_ops.ulps_exit) { + DSI_CTRL_DEBUG(dsi_ctrl, "DSI controller ULPS ops not present\n"); + return 0; + } + + lanes = dsi_ctrl->host_config.common_config.data_lanes; + lanes |= DSI_CLOCK_LANE; + + ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw); + + if ((lanes & ulps_lanes) != lanes) + DSI_CTRL_ERR(dsi_ctrl, "Mismatch between lanes in ULPS\n"); + + lanes &= ulps_lanes; + + dsi_ctrl->hw.ops.ulps_ops.ulps_exit(&dsi_ctrl->hw, lanes); + + ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw); + if (ulps_lanes & lanes) { + DSI_CTRL_ERR(dsi_ctrl, "Lanes (0x%x) stuck in ULPS\n", + ulps_lanes); + rc = -EIO; + } + + return rc; +} + +static void dsi_ctrl_enable_error_interrupts(struct dsi_ctrl *dsi_ctrl) +{ + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && + !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && + !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, + 0xFF00A0); + else + dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, + 0xFF00E0); +} + +static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + bool splash_enabled = false; + struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state; + + if (!splash_enabled) { + state->power_state = DSI_CTRL_POWER_VREG_OFF; + state->cmd_engine_state = DSI_CTRL_ENGINE_OFF; + state->vid_engine_state = DSI_CTRL_ENGINE_OFF; + } + + return rc; +} + +static int dsi_ctrl_buffer_deinit(struct dsi_ctrl *dsi_ctrl) +{ + struct msm_gem_address_space *aspace = NULL; + + if (dsi_ctrl->tx_cmd_buf) { + aspace = dsi_ctrl_get_aspace(dsi_ctrl, + MSM_SMMU_DOMAIN_UNSECURE); + if (!aspace) { + DSI_CTRL_ERR(dsi_ctrl, "failed to get address space\n"); + return -ENOMEM; + } + + msm_gem_put_iova(dsi_ctrl->tx_cmd_buf, aspace); + + mutex_lock(&dsi_ctrl->drm_dev->struct_mutex); + msm_gem_free_object(dsi_ctrl->tx_cmd_buf); + mutex_unlock(&dsi_ctrl->drm_dev->struct_mutex); + dsi_ctrl->tx_cmd_buf = NULL; + } + + return 0; +} + +int dsi_ctrl_buffer_init(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + u64 iova = 0; + struct msm_gem_address_space *aspace = NULL; + + aspace = dsi_ctrl_get_aspace(dsi_ctrl, MSM_SMMU_DOMAIN_UNSECURE); + if (!aspace) { + DSI_CTRL_ERR(dsi_ctrl, "failed to get address space\n"); + return -ENOMEM; + } + + dsi_ctrl->tx_cmd_buf = msm_gem_new(dsi_ctrl->drm_dev, + SZ_4K, + MSM_BO_UNCACHED); + + if (IS_ERR(dsi_ctrl->tx_cmd_buf)) { + rc = PTR_ERR(dsi_ctrl->tx_cmd_buf); + DSI_CTRL_ERR(dsi_ctrl, "failed to allocate gem, rc=%d\n", rc); + dsi_ctrl->tx_cmd_buf = NULL; + goto error; + } + + dsi_ctrl->cmd_buffer_size = SZ_4K; + + rc = msm_gem_get_iova(dsi_ctrl->tx_cmd_buf, aspace, &iova); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to get iova, rc=%d\n", rc); + (void)dsi_ctrl_buffer_deinit(dsi_ctrl); + goto error; + } + + if (iova & 0x07) { + DSI_CTRL_ERR(dsi_ctrl, "Tx command buffer is not 8 byte aligned\n"); + rc = -ENOTSUPP; + (void)dsi_ctrl_buffer_deinit(dsi_ctrl); + goto error; + } +error: + return rc; +} + +static int dsi_enable_io_clamp(struct dsi_ctrl *dsi_ctrl, + bool enable, bool ulps_enabled) +{ + u32 lanes = 0; + + if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) + lanes = dsi_ctrl->host_config.common_config.data_lanes; + + lanes |= DSI_CLOCK_LANE; + + if (enable) + dsi_ctrl->hw.ops.clamp_enable(&dsi_ctrl->hw, + lanes, ulps_enabled); + else + dsi_ctrl->hw.ops.clamp_disable(&dsi_ctrl->hw, + lanes, ulps_enabled); + + return 0; +} + +static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl, + struct device_node *of_node) +{ + u32 index = 0, frame_threshold_time_us = 0; + int rc = 0; + + if (!dsi_ctrl || !of_node) { + DSI_CTRL_ERR(dsi_ctrl, "invalid dsi_ctrl:%d or of_node:%d\n", + dsi_ctrl != NULL, of_node != NULL); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, "cell-index", &index); + if (rc) { + DSI_CTRL_DEBUG(dsi_ctrl, "cell index not set, default to 0\n"); + index = 0; + } + + dsi_ctrl->cell_index = index; + dsi_ctrl->name = of_get_property(of_node, "label", NULL); + if (!dsi_ctrl->name) + dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL; + + dsi_ctrl->phy_isolation_enabled = of_property_read_bool(of_node, + "qcom,dsi-phy-isolation-enabled"); + + dsi_ctrl->null_insertion_enabled = of_property_read_bool(of_node, + "qcom,null-insertion-enabled"); + + dsi_ctrl->split_link_supported = of_property_read_bool(of_node, + "qcom,split-link-supported"); + + rc = of_property_read_u32(of_node, "frame-threshold-time-us", + &frame_threshold_time_us); + if (rc) { + DSI_CTRL_DEBUG(dsi_ctrl, + "frame-threshold-time not specified, defaulting\n"); + frame_threshold_time_us = 2666; + } + + dsi_ctrl->frame_threshold_time_us = frame_threshold_time_us; + + return 0; +} + +static int dsi_ctrl_dev_probe(struct platform_device *pdev) +{ + struct dsi_ctrl *dsi_ctrl; + struct dsi_ctrl_list_item *item; + const struct of_device_id *id; + enum dsi_ctrl_version version; + int rc = 0; + + id = of_match_node(msm_dsi_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + + version = *(enum dsi_ctrl_version *)id->data; + + item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL); + if (!item) + return -ENOMEM; + + dsi_ctrl = devm_kzalloc(&pdev->dev, sizeof(*dsi_ctrl), GFP_KERNEL); + if (!dsi_ctrl) + return -ENOMEM; + + dsi_ctrl->version = version; + dsi_ctrl->irq_info.irq_num = -1; + dsi_ctrl->irq_info.irq_stat_mask = 0x0; + + INIT_WORK(&dsi_ctrl->dma_cmd_wait, dsi_ctrl_dma_cmd_wait_for_done); + atomic_set(&dsi_ctrl->dma_irq_trig, 0); + + spin_lock_init(&dsi_ctrl->irq_info.irq_lock); + + rc = dsi_ctrl_dts_parse(dsi_ctrl, pdev->dev.of_node); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "dts parse failed, rc = %d\n", rc); + goto fail; + } + + rc = dsi_ctrl_init_regmap(pdev, dsi_ctrl); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to parse register information, rc = %d\n", + rc); + goto fail; + } + + rc = dsi_ctrl_clocks_init(pdev, dsi_ctrl); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to parse clock information, rc = %d\n", + rc); + goto fail; + } + + rc = dsi_ctrl_supplies_init(pdev, dsi_ctrl); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to parse voltage supplies, rc = %d\n", + rc); + goto fail_clks; + } + + rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version, + dsi_ctrl->cell_index, dsi_ctrl->phy_isolation_enabled, + dsi_ctrl->null_insertion_enabled); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Catalog does not support version (%d)\n", + dsi_ctrl->version); + goto fail_supplies; + } + + rc = dsi_ctrl_axi_bus_client_init(pdev, dsi_ctrl); + if (rc) + DSI_CTRL_DEBUG(dsi_ctrl, "failed to init axi bus client, rc = %d\n", + rc); + + item->ctrl = dsi_ctrl; + + mutex_lock(&dsi_ctrl_list_lock); + list_add(&item->list, &dsi_ctrl_list); + mutex_unlock(&dsi_ctrl_list_lock); + + mutex_init(&dsi_ctrl->ctrl_lock); + dsi_ctrl->secure_mode = false; + + dsi_ctrl->pdev = pdev; + platform_set_drvdata(pdev, dsi_ctrl); + DSI_CTRL_INFO(dsi_ctrl, "Probe successful\n"); + + return 0; + +fail_supplies: + (void)dsi_ctrl_supplies_deinit(dsi_ctrl); +fail_clks: + (void)dsi_ctrl_clocks_deinit(dsi_ctrl); +fail: + return rc; +} + +static int dsi_ctrl_dev_remove(struct platform_device *pdev) +{ + int rc = 0; + struct dsi_ctrl *dsi_ctrl; + struct list_head *pos, *tmp; + + dsi_ctrl = platform_get_drvdata(pdev); + + mutex_lock(&dsi_ctrl_list_lock); + list_for_each_safe(pos, tmp, &dsi_ctrl_list) { + struct dsi_ctrl_list_item *n = list_entry(pos, + struct dsi_ctrl_list_item, + list); + if (n->ctrl == dsi_ctrl) { + list_del(&n->list); + break; + } + } + mutex_unlock(&dsi_ctrl_list_lock); + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl_axi_bus_client_deinit(dsi_ctrl); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, "failed to deinitialize axi bus client, rc = %d\n", + rc); + + rc = dsi_ctrl_supplies_deinit(dsi_ctrl); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, + "failed to deinitialize voltage supplies, rc=%d\n", + rc); + + rc = dsi_ctrl_clocks_deinit(dsi_ctrl); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, + "failed to deinitialize clocks, rc=%d\n", rc); + + atomic_set(&dsi_ctrl->dma_irq_trig, 0); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + mutex_destroy(&dsi_ctrl->ctrl_lock); + devm_kfree(&pdev->dev, dsi_ctrl); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver dsi_ctrl_driver = { + .probe = dsi_ctrl_dev_probe, + .remove = dsi_ctrl_dev_remove, + .driver = { + .name = "drm_dsi_ctrl", + .of_match_table = msm_dsi_of_match, + .suppress_bind_attrs = true, + }, +}; + +#if defined(CONFIG_DEBUG_FS) + +void dsi_ctrl_debug_dump(u32 *entries, u32 size) +{ + struct list_head *pos, *tmp; + struct dsi_ctrl *ctrl = NULL; + + if (!entries || !size) + return; + + mutex_lock(&dsi_ctrl_list_lock); + list_for_each_safe(pos, tmp, &dsi_ctrl_list) { + struct dsi_ctrl_list_item *n; + + n = list_entry(pos, struct dsi_ctrl_list_item, list); + ctrl = n->ctrl; + DSI_ERR("dsi ctrl:%d\n", ctrl->cell_index); + ctrl->hw.ops.debug_bus(&ctrl->hw, entries, size); + } + mutex_unlock(&dsi_ctrl_list_lock); +} + +#endif +/** + * dsi_ctrl_get() - get a dsi_ctrl handle from an of_node + * @of_node: of_node of the DSI controller. + * + * Gets the DSI controller handle for the corresponding of_node. The ref count + * is incremented to one and all subsequent gets will fail until the original + * clients calls a put. + * + * Return: DSI Controller handle. + */ +struct dsi_ctrl *dsi_ctrl_get(struct device_node *of_node) +{ + struct list_head *pos, *tmp; + struct dsi_ctrl *ctrl = NULL; + + mutex_lock(&dsi_ctrl_list_lock); + list_for_each_safe(pos, tmp, &dsi_ctrl_list) { + struct dsi_ctrl_list_item *n; + + n = list_entry(pos, struct dsi_ctrl_list_item, list); + if (n->ctrl->pdev->dev.of_node == of_node) { + ctrl = n->ctrl; + break; + } + } + mutex_unlock(&dsi_ctrl_list_lock); + + if (!ctrl) { + DSI_CTRL_ERR(ctrl, "Device with of node not found\n"); + ctrl = ERR_PTR(-EPROBE_DEFER); + return ctrl; + } + + mutex_lock(&ctrl->ctrl_lock); + if (ctrl->refcount == 1) { + DSI_CTRL_ERR(ctrl, "Device in use\n"); + mutex_unlock(&ctrl->ctrl_lock); + ctrl = ERR_PTR(-EBUSY); + return ctrl; + } + + ctrl->refcount++; + mutex_unlock(&ctrl->ctrl_lock); + return ctrl; +} + +/** + * dsi_ctrl_put() - releases a dsi controller handle. + * @dsi_ctrl: DSI controller handle. + * + * Releases the DSI controller. Driver will clean up all resources and puts back + * the DSI controller into reset state. + */ +void dsi_ctrl_put(struct dsi_ctrl *dsi_ctrl) +{ + mutex_lock(&dsi_ctrl->ctrl_lock); + + if (dsi_ctrl->refcount == 0) + DSI_CTRL_ERR(dsi_ctrl, "Unbalanced %s call\n", __func__); + else + dsi_ctrl->refcount--; + + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + +/** + * dsi_ctrl_drv_init() - initialize dsi controller driver. + * @dsi_ctrl: DSI controller handle. + * @parent: Parent directory for debug fs. + * + * Initializes DSI controller driver. Driver should be initialized after + * dsi_ctrl_get() succeeds. + * + * Return: error code. + */ +int dsi_ctrl_drv_init(struct dsi_ctrl *dsi_ctrl, struct dentry *parent) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl_drv_state_init(dsi_ctrl); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to initialize driver state, rc=%d\n", + rc); + goto error; + } + + rc = dsi_ctrl_debugfs_init(dsi_ctrl, parent); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to init debug fs, rc=%d\n", rc); + goto error; + } + +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_drv_deinit() - de-initializes dsi controller driver + * @dsi_ctrl: DSI controller handle. + * + * Releases all resources acquired by dsi_ctrl_drv_init(). + * + * Return: error code. + */ +int dsi_ctrl_drv_deinit(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_debugfs_deinit(dsi_ctrl); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, "failed to release debugfs root, rc=%d\n", + rc); + + rc = dsi_ctrl_buffer_deinit(dsi_ctrl); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, "Failed to free cmd buffers, rc=%d\n", + rc); + + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +int dsi_ctrl_clk_cb_register(struct dsi_ctrl *dsi_ctrl, + struct clk_ctrl_cb *clk_cb) +{ + if (!dsi_ctrl || !clk_cb) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + dsi_ctrl->clk_cb.priv = clk_cb->priv; + dsi_ctrl->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb; + return 0; +} + +/** + * dsi_ctrl_phy_sw_reset() - perform a PHY software reset + * @dsi_ctrl: DSI controller handle. + * + * Performs a PHY software reset on the DSI controller. Reset should be done + * when the controller power state is DSI_CTRL_POWER_CORE_CLK_ON and the PHY is + * not enabled. + * + * This function will fail if driver is in any other state. + * + * Return: error code. + */ +int dsi_ctrl_phy_sw_reset(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_PHY_SW_RESET, 0x0); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + dsi_ctrl->hw.ops.phy_sw_reset(&dsi_ctrl->hw); + + DSI_CTRL_DEBUG(dsi_ctrl, "PHY soft reset done\n"); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_PHY_SW_RESET, 0x0); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_seamless_timing_update() - update only controller timing + * @dsi_ctrl: DSI controller handle. + * @timing: New DSI timing info + * + * Updates host timing values to conduct a seamless transition to new timing + * For example, to update the porch values in a dynamic fps switch. + * + * Return: error code. + */ +int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl, + struct dsi_mode_info *timing) +{ + struct dsi_mode_info *host_mode; + int rc = 0; + + if (!dsi_ctrl || !timing) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_ASYNC_TIMING, + DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto exit; + } + + host_mode = &dsi_ctrl->host_config.video_timing; + memcpy(host_mode, timing, sizeof(*host_mode)); + dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, true); + dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, host_mode); + +exit: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_timing_db_update() - update only controller Timing DB + * @dsi_ctrl: DSI controller handle. + * @enable: Enable/disable Timing DB register + * + * Update timing db register value during dfps usecases + * + * Return: error code. + */ +int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl, + bool enable) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid dsi_ctrl\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_ASYNC_TIMING, + DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto exit; + } + + /* + * Add HW recommended delay for dfps feature. + * When prefetch is enabled, MDSS HW works on 2 vsync + * boundaries i.e. mdp_vsync and panel_vsync. + * In the current implementation we are only waiting + * for mdp_vsync. We need to make sure that interface + * flush is after panel_vsync. So, added the recommended + * delays after dfps update. + */ + usleep_range(2000, 2010); + + dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, enable); + +exit: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +int dsi_ctrl_timing_setup(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) { + dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config, + &dsi_ctrl->host_config.u.cmd_engine); + + dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, + &dsi_ctrl->host_config.video_timing, + dsi_ctrl->host_config.video_timing.h_active * 3, + 0x0, + &dsi_ctrl->roi); + dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true); + } else { + dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config, + &dsi_ctrl->host_config.u.video_engine); + dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, + &dsi_ctrl->host_config.video_timing); + dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, true); + } + + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + rc = dsi_ctrl_timing_setup(dsi_ctrl); + if (rc) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + + dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw, + &dsi_ctrl->host_config.lane_map); + + dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config); + + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); + dsi_ctrl_enable_error_interrupts(dsi_ctrl); + + dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); + + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, + bool *changed) +{ + int rc = 0; + + if (!dsi_ctrl || !roi || !changed) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + if ((!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) || + dsi_ctrl->modeupdated) { + *changed = true; + memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi)); + dsi_ctrl->modeupdated = false; + } else + *changed = false; + + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_config_clk_gating() - Enable/disable DSI PHY clk gating. + * @dsi_ctrl: DSI controller handle. + * @enable: Enable/disable DSI PHY clk gating + * @clk_selection: clock to enable/disable clock gating + * + * Return: error code. + */ +int dsi_ctrl_config_clk_gating(struct dsi_ctrl *dsi_ctrl, bool enable, + enum dsi_clk_gate_type clk_selection) +{ + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + if (dsi_ctrl->hw.ops.config_clk_gating) + dsi_ctrl->hw.ops.config_clk_gating(&dsi_ctrl->hw, enable, + clk_selection); + + return 0; +} + +/** + * dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal + * to DSI PHY hardware. + * @dsi_ctrl: DSI controller handle. + * @enable: Mask/unmask the PHY reset signal. + * + * Return: error code. + */ +int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + if (dsi_ctrl->hw.ops.phy_reset_config) + dsi_ctrl->hw.ops.phy_reset_config(&dsi_ctrl->hw, enable); + + return 0; +} + +static bool dsi_ctrl_check_for_spurious_error_interrupts( + struct dsi_ctrl *dsi_ctrl) +{ + const unsigned long intr_check_interval = msecs_to_jiffies(1000); + const unsigned int interrupt_threshold = 15; + unsigned long jiffies_now = jiffies; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid DSI controller structure\n"); + return false; + } + + if (dsi_ctrl->jiffies_start == 0) + dsi_ctrl->jiffies_start = jiffies; + + dsi_ctrl->error_interrupt_count++; + + if ((jiffies_now - dsi_ctrl->jiffies_start) < intr_check_interval) { + if (dsi_ctrl->error_interrupt_count > interrupt_threshold) { + DSI_CTRL_WARN(dsi_ctrl, "Detected spurious interrupts on dsi ctrl\n"); + SDE_EVT32_IRQ(dsi_ctrl->error_interrupt_count); + return true; + } + } else { + dsi_ctrl->jiffies_start = jiffies; + dsi_ctrl->error_interrupt_count = 1; + } + return false; +} + +static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl, + unsigned long error) +{ + struct dsi_event_cb_info cb_info; + + cb_info = dsi_ctrl->irq_info.irq_err_cb; + + /* disable error interrupts */ + if (dsi_ctrl->hw.ops.error_intr_ctrl) + dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false); + + /* clear error interrupts first */ + if (dsi_ctrl->hw.ops.clear_error_status) + dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, + error); + + /* DTLN PHY error */ + if (error & 0x3000E00) + DSI_CTRL_ERR(dsi_ctrl, "dsi PHY contention error: 0x%lx\n", + error); + + /* ignore TX timeout if blpp_lp11 is disabled */ + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE && + !dsi_ctrl->host_config.u.video_engine.bllp_lp11_en && + !dsi_ctrl->host_config.u.video_engine.eof_bllp_lp11_en) + error &= ~DSI_HS_TX_TIMEOUT; + + /* TX timeout error */ + if (error & 0xE0) { + if (error & 0xA0) { + if (cb_info.event_cb) { + cb_info.event_idx = DSI_LP_Rx_TIMEOUT; + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + 0, 0, 0, 0); + } + } + DSI_CTRL_ERR(dsi_ctrl, "tx timeout error: 0x%lx\n", error); + } + + /* DSI FIFO OVERFLOW error */ + if (error & 0xF0000) { + u32 mask = 0; + + if (dsi_ctrl->hw.ops.get_error_mask) + mask = dsi_ctrl->hw.ops.get_error_mask(&dsi_ctrl->hw); + /* no need to report FIFO overflow if already masked */ + if (cb_info.event_cb && !(mask & 0xf0000)) { + cb_info.event_idx = DSI_FIFO_OVERFLOW; + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + 0, 0, 0, 0); + DSI_CTRL_ERR(dsi_ctrl, "dsi FIFO OVERFLOW error: 0x%lx\n", + error); + } + } + + /* DSI FIFO UNDERFLOW error */ + if (error & 0xF00000) { + if (cb_info.event_cb) { + cb_info.event_idx = DSI_FIFO_UNDERFLOW; + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + 0, 0, 0, 0); + } + DSI_CTRL_ERR(dsi_ctrl, "dsi FIFO UNDERFLOW error: 0x%lx\n", + error); + } + + /* DSI PLL UNLOCK error */ + if (error & BIT(8)) + DSI_CTRL_ERR(dsi_ctrl, "dsi PLL unlock error: 0x%lx\n", error); + + /* ACK error */ + if (error & 0xF) + DSI_CTRL_ERR(dsi_ctrl, "ack error: 0x%lx\n", error); + + /* + * DSI Phy can go into bad state during ESD influence. This can + * manifest as various types of spurious error interrupts on + * DSI controller. This check will allow us to handle afore mentioned + * case and prevent us from re enabling interrupts until a full ESD + * recovery is completed. + */ + if (dsi_ctrl_check_for_spurious_error_interrupts(dsi_ctrl) && + dsi_ctrl->esd_check_underway) { + dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw); + return; + } + + /* enable back DSI interrupts */ + if (dsi_ctrl->hw.ops.error_intr_ctrl) + dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, true); +} + +/** + * dsi_ctrl_isr - interrupt service routine for DSI CTRL component + * @irq: Incoming IRQ number + * @ptr: Pointer to user data structure (struct dsi_ctrl) + * Returns: IRQ_HANDLED if no further action required + */ +static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) +{ + struct dsi_ctrl *dsi_ctrl; + struct dsi_event_cb_info cb_info; + unsigned long flags; + uint32_t status = 0x0, i; + uint64_t errors = 0x0; + + if (!ptr) + return IRQ_NONE; + dsi_ctrl = ptr; + + /* check status interrupts */ + if (dsi_ctrl->hw.ops.get_interrupt_status) + status = dsi_ctrl->hw.ops.get_interrupt_status(&dsi_ctrl->hw); + + /* check error interrupts */ + if (dsi_ctrl->hw.ops.get_error_status) + errors = dsi_ctrl->hw.ops.get_error_status(&dsi_ctrl->hw); + + /* clear interrupts */ + if (dsi_ctrl->hw.ops.clear_interrupt_status) + dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, 0x0); + + SDE_EVT32_IRQ(dsi_ctrl->cell_index, status, errors); + + /* handle DSI error recovery */ + if (status & DSI_ERROR) + dsi_ctrl_handle_error_status(dsi_ctrl, errors); + + if (status & DSI_CMD_MODE_DMA_DONE) { + atomic_set(&dsi_ctrl->dma_irq_trig, 1); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE); + complete_all(&dsi_ctrl->irq_info.cmd_dma_done); + } + + if (status & DSI_CMD_FRAME_DONE) { + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_FRAME_DONE); + complete_all(&dsi_ctrl->irq_info.cmd_frame_done); + } + + if (status & DSI_VIDEO_MODE_FRAME_DONE) { + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_VIDEO_MODE_FRAME_DONE); + complete_all(&dsi_ctrl->irq_info.vid_frame_done); + } + + if (status & DSI_BTA_DONE) { + u32 fifo_overflow_mask = (DSI_DLN0_HS_FIFO_OVERFLOW | + DSI_DLN1_HS_FIFO_OVERFLOW | + DSI_DLN2_HS_FIFO_OVERFLOW | + DSI_DLN3_HS_FIFO_OVERFLOW); + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_BTA_DONE); + complete_all(&dsi_ctrl->irq_info.bta_done); + if (dsi_ctrl->hw.ops.clear_error_status) + dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, + fifo_overflow_mask); + } + + for (i = 0; status && i < DSI_STATUS_INTERRUPT_COUNT; ++i) { + if (status & 0x1) { + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); + cb_info = dsi_ctrl->irq_info.irq_stat_cb[i]; + spin_unlock_irqrestore( + &dsi_ctrl->irq_info.irq_lock, flags); + + if (cb_info.event_cb) + (void)cb_info.event_cb(cb_info.event_usr_ptr, + cb_info.event_idx, + dsi_ctrl->cell_index, + irq, 0, 0, 0); + } + status >>= 1; + } + + return IRQ_HANDLED; +} + +/** + * _dsi_ctrl_setup_isr - register ISR handler + * @dsi_ctrl: Pointer to associated dsi_ctrl structure + * Returns: Zero on success + */ +static int _dsi_ctrl_setup_isr(struct dsi_ctrl *dsi_ctrl) +{ + int irq_num, rc; + + if (!dsi_ctrl) + return -EINVAL; + if (dsi_ctrl->irq_info.irq_num != -1) + return 0; + + init_completion(&dsi_ctrl->irq_info.cmd_dma_done); + init_completion(&dsi_ctrl->irq_info.vid_frame_done); + init_completion(&dsi_ctrl->irq_info.cmd_frame_done); + init_completion(&dsi_ctrl->irq_info.bta_done); + + irq_num = platform_get_irq(dsi_ctrl->pdev, 0); + if (irq_num < 0) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to get IRQ number, %d\n", + irq_num); + rc = irq_num; + } else { + rc = devm_request_threaded_irq(&dsi_ctrl->pdev->dev, irq_num, + dsi_ctrl_isr, NULL, 0, "dsi_ctrl", dsi_ctrl); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to request IRQ, %d\n", + rc); + } else { + dsi_ctrl->irq_info.irq_num = irq_num; + disable_irq_nosync(irq_num); + + DSI_CTRL_INFO(dsi_ctrl, "IRQ %d registered\n", irq_num); + } + } + return rc; +} + +/** + * _dsi_ctrl_destroy_isr - unregister ISR handler + * @dsi_ctrl: Pointer to associated dsi_ctrl structure + */ +static void _dsi_ctrl_destroy_isr(struct dsi_ctrl *dsi_ctrl) +{ + if (!dsi_ctrl || !dsi_ctrl->pdev || dsi_ctrl->irq_info.irq_num < 0) + return; + + if (dsi_ctrl->irq_info.irq_num != -1) { + devm_free_irq(&dsi_ctrl->pdev->dev, + dsi_ctrl->irq_info.irq_num, dsi_ctrl); + dsi_ctrl->irq_info.irq_num = -1; + } +} + +void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl, + uint32_t intr_idx, struct dsi_event_cb_info *event_info) +{ + unsigned long flags; + + if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 || + intr_idx >= DSI_STATUS_INTERRUPT_COUNT) + return; + + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, intr_idx); + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); + + if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx] == 0) { + /* enable irq on first request */ + if (dsi_ctrl->irq_info.irq_stat_mask == 0) + enable_irq(dsi_ctrl->irq_info.irq_num); + + /* update hardware mask */ + dsi_ctrl->irq_info.irq_stat_mask |= BIT(intr_idx); + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, + dsi_ctrl->irq_info.irq_stat_mask); + } + + if (intr_idx == DSI_SINT_CMD_MODE_DMA_DONE) + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, + dsi_ctrl->irq_info.irq_stat_mask); + ++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]); + + if (event_info) + dsi_ctrl->irq_info.irq_stat_cb[intr_idx] = *event_info; + + spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags); +} + +void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl, + uint32_t intr_idx) +{ + unsigned long flags; + + if (!dsi_ctrl || intr_idx >= DSI_STATUS_INTERRUPT_COUNT) + return; + + SDE_EVT32_IRQ(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, intr_idx); + spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); + + if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) + if (--(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) == 0) { + dsi_ctrl->irq_info.irq_stat_mask &= ~BIT(intr_idx); + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, + dsi_ctrl->irq_info.irq_stat_mask); + + /* don't need irq if no lines are enabled */ + if (dsi_ctrl->irq_info.irq_stat_mask == 0 && + dsi_ctrl->irq_info.irq_num != -1) + disable_irq_nosync(dsi_ctrl->irq_info.irq_num); + } + + spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags); +} + +int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl) +{ + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + if (dsi_ctrl->hw.ops.host_setup) + dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config); + + if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) { + if (dsi_ctrl->hw.ops.cmd_engine_setup) + dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config, + &dsi_ctrl->host_config.u.cmd_engine); + + if (dsi_ctrl->hw.ops.setup_cmd_stream) + dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, + &dsi_ctrl->host_config.video_timing, + dsi_ctrl->host_config.video_timing.h_active * 3, + 0x0, NULL); + } else { + DSI_CTRL_ERR(dsi_ctrl, "invalid panel mode for resolution switch\n"); + return -EINVAL; + } + + return 0; +} + +/** + * dsi_ctrl_update_host_state() - Update the host initialization state. + * @dsi_ctrl: DSI controller handle. + * @op: ctrl driver ops + * @enable: boolean signifying host state. + * + * Update the host status only while exiting from ulps during suspend state. + * + * Return: error code. + */ +int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_ctrl_driver_ops op, bool enable) +{ + int rc = 0; + u32 state = enable ? 0x1 : 0x0; + + if (!dsi_ctrl) + return rc; + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl_check_state(dsi_ctrl, op, state); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; + } + + dsi_ctrl_update_state(dsi_ctrl, op, state); + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_host_init() - Initialize DSI host hardware. + * @dsi_ctrl: DSI controller handle. + * @is_splash_enabled: boolean signifying splash status. + * + * Initializes DSI controller hardware with host configuration provided by + * dsi_ctrl_update_host_config(). Initialization can be performed only during + * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been + * performed. + * + * Return: error code. + */ +int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + /* For Splash usecases we omit hw operations as bootloader + * already takes care of them + */ + if (!is_splash_enabled) { + dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw, + &dsi_ctrl->host_config.lane_map); + + dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config); + + if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) { + dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config, + &dsi_ctrl->host_config.u.cmd_engine); + + dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw, + &dsi_ctrl->host_config.video_timing, + dsi_ctrl->host_config.video_timing.h_active * 3, + 0x0, + NULL); + } else { + dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw, + &dsi_ctrl->host_config.common_config, + &dsi_ctrl->host_config.u.video_engine); + dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, + &dsi_ctrl->host_config.video_timing); + } + } + + dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); + dsi_ctrl_enable_error_interrupts(dsi_ctrl); + + DSI_CTRL_DEBUG(dsi_ctrl, "Host initialization complete, continuous splash status:%d\n", + is_splash_enabled); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_isr_configure() - API to register/deregister dsi isr + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control register/deregister isr + */ +void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + if (enable) + _dsi_ctrl_setup_isr(dsi_ctrl); + else + _dsi_ctrl_destroy_isr(dsi_ctrl); + + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + +void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.hs_req_sel(&dsi_ctrl->hw, sel_phy); + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + +void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.set_continuous_clk(&dsi_ctrl->hw, enable); + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + +int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl) +{ + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + DSI_CTRL_DEBUG(dsi_ctrl, "Soft reset complete\n"); + return 0; +} + +int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask) +{ + int rc = 0; + + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl->hw.ops.ctrl_reset(&dsi_ctrl->hw, mask); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + rc = dsi_ctrl->hw.ops.get_hw_version(&dsi_ctrl->hw); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on) +{ + int rc = 0; + + if (!dsi_ctrl) + return -EINVAL; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, on); + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +int dsi_ctrl_setup_avr(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) + return -EINVAL; + + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) { + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->hw.ops.setup_avr(&dsi_ctrl->hw, enable); + mutex_unlock(&dsi_ctrl->ctrl_lock); + } + + return 0; +} + +/** + * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware. + * @dsi_ctrl: DSI controller handle. + * + * De-initializes DSI controller hardware. It can be performed only during + * DSI_CTRL_POWER_CORE_CLK_ON state after LINK clocks have been turned off. + * + * Return: error code. + */ +int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x0); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + DSI_CTRL_ERR(dsi_ctrl, "driver state check failed, rc=%d\n", + rc); + goto error; + } + + DSI_CTRL_DEBUG(dsi_ctrl, "Host deinitization complete\n"); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x0); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_update_host_config() - update dsi host configuration + * @dsi_ctrl: DSI controller handle. + * @config: DSI host configuration. + * @flags: dsi_mode_flags modifying the behavior + * + * Updates driver with new Host configuration to use for host initialization. + * This function call will only update the software context. The stored + * configuration information will be used when the host is initialized. + * + * Return: error code. + */ +int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl, + struct dsi_host_config *config, + struct dsi_display_mode *mode, int flags, + void *clk_handle) +{ + int rc = 0; + + if (!ctrl || !config) { + DSI_CTRL_ERR(ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&ctrl->ctrl_lock); + + rc = dsi_ctrl_validate_panel_info(ctrl, config); + if (rc) { + DSI_CTRL_ERR(ctrl, "panel validation failed, rc=%d\n", rc); + goto error; + } + + if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR | + DSI_MODE_FLAG_DYN_CLK))) { + /* + * for dynamic clk switch case link frequence would + * be updated dsi_display_dynamic_clk_switch(). + */ + rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle, + mode); + if (rc) { + DSI_CTRL_ERR(ctrl, "failed to update link frequency, rc=%d\n", + rc); + goto error; + } + } + + DSI_CTRL_DEBUG(ctrl, "Host config updated\n"); + memcpy(&ctrl->host_config, config, sizeof(ctrl->host_config)); + ctrl->mode_bounds.x = ctrl->host_config.video_timing.h_active * + ctrl->horiz_index; + ctrl->mode_bounds.y = 0; + ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active; + ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active; + memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds)); + ctrl->modeupdated = true; + ctrl->roi.x = 0; +error: + mutex_unlock(&ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_validate_timing() - validate a video timing configuration + * @dsi_ctrl: DSI controller handle. + * @timing: Pointer to timing data. + * + * Driver will validate if the timing configuration is supported on the + * controller hardware. + * + * Return: error code if timing is not supported. + */ +int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, + struct dsi_mode_info *mode) +{ + int rc = 0; + + if (!dsi_ctrl || !mode) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + return rc; +} + +/** + * dsi_ctrl_cmd_transfer() - Transfer commands on DSI link + * @dsi_ctrl: DSI controller handle. + * @msg: Message to transfer on DSI link. + * @flags: Modifiers for message transfer. + * + * Command transfer can be done only when command engine is enabled. The + * transfer API will block until either the command transfer finishes or + * the timeout value is reached. If the trigger is deferred, it will return + * without triggering the transfer. Command parameters are programmed to + * hardware. + * + * Return: error code. + */ +int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, + u32 *flags) +{ + int rc = 0; + + if (!dsi_ctrl || !msg) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_CMD_TX, 0x0); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + if (*flags & DSI_CTRL_CMD_READ) { + rc = dsi_message_rx(dsi_ctrl, msg, flags); + if (rc <= 0) + DSI_CTRL_ERR(dsi_ctrl, "read message failed read length, rc=%d\n", + rc); + } else { + rc = dsi_message_tx(dsi_ctrl, msg, flags); + if (rc) + DSI_CTRL_ERR(dsi_ctrl, "command msg transfer failed, rc = %d\n", + rc); + } + + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_TX, 0x0); + +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_mask_overflow() - API to mask/unmask overflow error. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control masking/unmasking. + */ +void dsi_ctrl_mask_overflow(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + struct dsi_ctrl_hw_ops dsi_hw_ops; + + dsi_hw_ops = dsi_ctrl->hw.ops; + + if (enable) { + if (dsi_hw_ops.mask_error_intr) + dsi_hw_ops.mask_error_intr(&dsi_ctrl->hw, + BIT(DSI_FIFO_OVERFLOW), true); + } else { + if (dsi_hw_ops.mask_error_intr && !dsi_ctrl->esd_check_underway) + dsi_hw_ops.mask_error_intr(&dsi_ctrl->hw, + BIT(DSI_FIFO_OVERFLOW), false); + } +} + +/** + * dsi_ctrl_clear_slave_dma_status - API to clear slave DMA status + * @dsi_ctrl: DSI controller handle. + * @flags: Modifiers + */ +int dsi_ctrl_clear_slave_dma_status(struct dsi_ctrl *dsi_ctrl, u32 flags) +{ + struct dsi_ctrl_hw_ops dsi_hw_ops; + u32 status; + u32 mask = DSI_CMD_MODE_DMA_DONE; + int rc = 0, wait_for_done = 5; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + /* Return if this is not the last command */ + if (!(flags & DSI_CTRL_CMD_LAST_COMMAND)) + return rc; + + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY); + + mutex_lock(&dsi_ctrl->ctrl_lock); + + dsi_hw_ops = dsi_ctrl->hw.ops; + + while (wait_for_done > 0) { + status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw); + if (status & mask) { + status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE); + dsi_hw_ops.clear_interrupt_status(&dsi_ctrl->hw, + status); + SDE_EVT32(dsi_ctrl->cell_index, status); + wait_for_done = 1; + break; + } + udelay(10); + wait_for_done--; + } + + if (wait_for_done == 0) + DSI_CTRL_ERR(dsi_ctrl, + "DSI1 CMD_MODE_DMA_DONE failed\n"); + + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return rc; +} + +/** + * dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command. + * @dsi_ctrl: DSI controller handle. + * @flags: Modifiers. + * + * Return: error code. + */ +int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) +{ + int rc = 0; + struct dsi_ctrl_hw_ops dsi_hw_ops; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + dsi_hw_ops = dsi_ctrl->hw.ops; + + SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags); + /* Dont trigger the command if this is not the last ocmmand */ + if (!(flags & DSI_CTRL_CMD_LAST_COMMAND)) + return rc; + + mutex_lock(&dsi_ctrl->ctrl_lock); + + if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER)) + dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); + + if ((flags & DSI_CTRL_CMD_BROADCAST) && + (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) { + dsi_ctrl_wait_for_video_done(dsi_ctrl); + atomic_set(&dsi_ctrl->dma_irq_trig, 0); + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_CMD_MODE_DMA_DONE, NULL); + reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); + + /* trigger command */ + dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw); + if (flags & DSI_CTRL_CMD_ASYNC_WAIT) { + dsi_ctrl->dma_wait_queued = true; + queue_work(dsi_ctrl->dma_cmd_workq, + &dsi_ctrl->dma_cmd_wait); + } else { + dsi_ctrl->dma_wait_queued = false; + dsi_ctrl_dma_cmd_wait_for_done(&dsi_ctrl->dma_cmd_wait); + } + + if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { + if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4) + dsi_hw_ops.soft_reset(&dsi_ctrl->hw); + dsi_ctrl->cmd_len = 0; + } + } + + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_cache_misr - Cache frame MISR value + * @dsi_ctrl: Pointer to associated dsi_ctrl structure + */ +void dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl) +{ + u32 misr; + + if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr) + return; + + misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw, + dsi_ctrl->host_config.panel_mode); + + if (misr) + dsi_ctrl->misr_cache = misr; + + DSI_CTRL_DEBUG(dsi_ctrl, "misr_cache = %x\n", dsi_ctrl->misr_cache); +} + +/** + * dsi_ctrl_get_host_engine_init_state() - Return host init state + * @dsi_ctrl: DSI controller handle. + * @state: Controller initialization state + * + * Return: error code. + */ +int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, + bool *state) +{ + if (!dsi_ctrl || !state) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid Params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + *state = dsi_ctrl->current_state.host_initialized; + mutex_unlock(&dsi_ctrl->ctrl_lock); + + return 0; +} + +/** + * dsi_ctrl_update_host_engine_state_for_cont_splash() - + * set engine state for dsi controller during continuous splash + * @dsi_ctrl: DSI controller handle. + * @state: Engine state. + * + * Set host engine state for DSI controller during continuous splash. + * + * Return: error code. + */ +int dsi_ctrl_update_host_engine_state_for_cont_splash(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state) +{ + int rc = 0; + + if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + DSI_CTRL_DEBUG(dsi_ctrl, "Set host engine state = %d\n", state); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_power_state() - set power state for dsi controller + * @dsi_ctrl: DSI controller handle. + * @state: Power state. + * + * Set power state for DSI controller. Power state can be changed only when + * Controller, Video and Command engines are turned off. + * + * Return: error code. + */ +int dsi_ctrl_set_power_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_power_state state) +{ + int rc = 0; + + if (!dsi_ctrl || (state >= DSI_CTRL_POWER_MAX)) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid Params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_POWER_STATE_CHANGE, + state); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + if (state == DSI_CTRL_POWER_VREG_ON) { + rc = dsi_ctrl_enable_supplies(dsi_ctrl, true); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to enable voltage supplies, rc=%d\n", + rc); + goto error; + } + } else if (state == DSI_CTRL_POWER_VREG_OFF) { + rc = dsi_ctrl_enable_supplies(dsi_ctrl, false); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "failed to disable vreg supplies, rc=%d\n", + rc); + goto error; + } + } + + DSI_CTRL_DEBUG(dsi_ctrl, "Power state updated to %d\n", state); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_POWER_STATE_CHANGE, state); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller + * @dsi_ctrl: DSI controller handle. + * @on: enable/disable test pattern. + * + * Test pattern can be enabled only after Video engine (for video mode panels) + * or command engine (for cmd mode panels) is enabled. + * + * Return: error code. + */ +int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_TPG, on); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + if (on) { + if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) { + dsi_ctrl->hw.ops.video_test_pattern_setup(&dsi_ctrl->hw, + DSI_TEST_PATTERN_INC, + 0xFFFF); + } else { + dsi_ctrl->hw.ops.cmd_test_pattern_setup( + &dsi_ctrl->hw, + DSI_TEST_PATTERN_INC, + 0xFFFF, + 0x0); + } + } + dsi_ctrl->hw.ops.test_pattern_enable(&dsi_ctrl->hw, on); + + DSI_CTRL_DEBUG(dsi_ctrl, "Set test pattern state=%d\n", on); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_TPG, on); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_host_engine_state() - set host engine state + * @dsi_ctrl: DSI Controller handle. + * @state: Engine state. + * + * Host engine state can be modified only when DSI controller power state is + * set to DSI_CTRL_POWER_LINK_CLK_ON and cmd, video engines are disabled. + * + * Return: error code. + */ +int dsi_ctrl_set_host_engine_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state) +{ + int rc = 0; + + if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + if (state == DSI_CTRL_ENGINE_ON) + dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); + else + dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, false); + + SDE_EVT32(dsi_ctrl->cell_index, state); + DSI_CTRL_DEBUG(dsi_ctrl, "Set host engine state = %d\n", state); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_cmd_engine_state() - set command engine state + * @dsi_ctrl: DSI Controller handle. + * @state: Engine state. + * + * Command engine state can be modified only when DSI controller power state is + * set to DSI_CTRL_POWER_LINK_CLK_ON. + * + * Return: error code. + */ +int dsi_ctrl_set_cmd_engine_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state) +{ + int rc = 0; + + if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_CMD_ENGINE, state); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + if (state == DSI_CTRL_ENGINE_ON) + dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true); + else + dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, false); + + SDE_EVT32(dsi_ctrl->cell_index, state); + DSI_CTRL_DEBUG(dsi_ctrl, "Set cmd engine state = %d\n", state); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_ENGINE, state); +error: + return rc; +} + +/** + * dsi_ctrl_set_vid_engine_state() - set video engine state + * @dsi_ctrl: DSI Controller handle. + * @state: Engine state. + * + * Video engine state can be modified only when DSI controller power state is + * set to DSI_CTRL_POWER_LINK_CLK_ON. + * + * Return: error code. + */ +int dsi_ctrl_set_vid_engine_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state) +{ + int rc = 0; + bool on; + + if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_VID_ENGINE, state); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n", + rc); + goto error; + } + + on = (state == DSI_CTRL_ENGINE_ON) ? true : false; + dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, on); + + /* perform a reset when turning off video engine */ + if (!on && dsi_ctrl->version < DSI_CTRL_VERSION_1_3) + dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw); + + SDE_EVT32(dsi_ctrl->cell_index, state); + DSI_CTRL_DEBUG(dsi_ctrl, "Set video engine state = %d\n", state); + dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_VID_ENGINE, state); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable ULPS. + * + * ULPS can be enabled/disabled after DSI host engine is turned on. + * + * Return: error code. + */ +int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + if (enable) + rc = dsi_enable_ulps(dsi_ctrl); + else + rc = dsi_disable_ulps(dsi_ctrl); + + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Ulps state change(%d) failed, rc=%d\n", + enable, rc); + goto error; + } + DSI_CTRL_DEBUG(dsi_ctrl, "ULPS state = %d\n", enable); + +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_clamp_state() - set clamp state for DSI phy + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable clamping. + * + * Clamps can be enabled/disabled while DSI controller is still turned on. + * + * Return: error code. + */ +int dsi_ctrl_set_clamp_state(struct dsi_ctrl *dsi_ctrl, + bool enable, bool ulps_enabled) +{ + int rc = 0; + + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + if (!dsi_ctrl->hw.ops.clamp_enable || + !dsi_ctrl->hw.ops.clamp_disable) { + DSI_CTRL_DEBUG(dsi_ctrl, "No clamp control for DSI controller\n"); + return 0; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_enable_io_clamp(dsi_ctrl, enable, ulps_enabled); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to enable IO clamp\n"); + goto error; + } + + DSI_CTRL_DEBUG(dsi_ctrl, "Clamp state = %d\n", enable); +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_set_clock_source() - set clock source fpr dsi link clocks + * @dsi_ctrl: DSI controller handle. + * @source_clks: Source clocks for DSI link clocks. + * + * Clock source should be changed while link clocks are disabled. + * + * Return: error code. + */ +int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl, + struct dsi_clk_link_set *source_clks) +{ + int rc = 0; + + if (!dsi_ctrl || !source_clks) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_ctrl->ctrl_lock); + + rc = dsi_clk_update_parent(source_clks, &dsi_ctrl->clk_info.rcg_clks); + if (rc) { + DSI_CTRL_ERR(dsi_ctrl, "Failed to update link clk parent, rc=%d\n", + rc); + (void)dsi_clk_update_parent(&dsi_ctrl->clk_info.pll_op_clks, + &dsi_ctrl->clk_info.rcg_clks); + goto error; + } + + dsi_ctrl->clk_info.pll_op_clks.byte_clk = source_clks->byte_clk; + dsi_ctrl->clk_info.pll_op_clks.pixel_clk = source_clks->pixel_clk; + + DSI_CTRL_DEBUG(dsi_ctrl, "Source clocks are updated\n"); + +error: + mutex_unlock(&dsi_ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_setup_misr() - Setup frame MISR + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + * + * Return: error code. + */ +int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl, + bool enable, + u32 frame_count) +{ + if (!dsi_ctrl) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return -EINVAL; + } + + if (!dsi_ctrl->hw.ops.setup_misr) + return 0; + + mutex_lock(&dsi_ctrl->ctrl_lock); + dsi_ctrl->misr_enable = enable; + dsi_ctrl->hw.ops.setup_misr(&dsi_ctrl->hw, + dsi_ctrl->host_config.panel_mode, + enable, frame_count); + mutex_unlock(&dsi_ctrl->ctrl_lock); + return 0; +} + +/** + * dsi_ctrl_collect_misr() - Read frame MISR + * @dsi_ctrl: DSI controller handle. + * + * Return: MISR value. + */ +u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl) +{ + u32 misr; + + if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr) + return 0; + + misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw, + dsi_ctrl->host_config.panel_mode); + if (!misr) + misr = dsi_ctrl->misr_cache; + + DSI_CTRL_DEBUG(dsi_ctrl, "cached misr = %x, final = %x\n", + dsi_ctrl->misr_cache, misr); + + return misr; +} + +void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl, u32 idx, + bool mask_enable) +{ + if (!dsi_ctrl || !dsi_ctrl->hw.ops.error_intr_ctrl + || !dsi_ctrl->hw.ops.clear_error_status) { + DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n"); + return; + } + + /* + * Mask DSI error status interrupts and clear error status + * register + */ + mutex_lock(&dsi_ctrl->ctrl_lock); + if (idx & BIT(DSI_ERR_INTR_ALL)) { + /* + * The behavior of mask_enable is different in ctrl register + * and mask register and hence mask_enable is manipulated for + * selective error interrupt masking vs total error interrupt + * masking. + */ + + dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, !mask_enable); + dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, + DSI_ERROR_INTERRUPT_COUNT); + } else { + dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, idx, + mask_enable); + dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, + DSI_ERROR_INTERRUPT_COUNT); + } + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + +/** + * dsi_ctrl_irq_update() - Put a irq vote to process DSI error + * interrupts at any time. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to enable/disable irq + */ +void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable) +{ + if (!dsi_ctrl) + return; + + mutex_lock(&dsi_ctrl->ctrl_lock); + if (enable) + dsi_ctrl_enable_status_interrupt(dsi_ctrl, + DSI_SINT_ERROR, NULL); + else + dsi_ctrl_disable_status_interrupt(dsi_ctrl, + DSI_SINT_ERROR); + + mutex_unlock(&dsi_ctrl->ctrl_lock); +} + +/** + * dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamci refresh + * done interrupt. + * @dsi_ctrl: DSI controller handle. + */ +int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl) +{ + int rc = 0; + + if (!ctrl) + return 0; + + mutex_lock(&ctrl->ctrl_lock); + + if (ctrl->hw.ops.wait4dynamic_refresh_done) + rc = ctrl->hw.ops.wait4dynamic_refresh_done(&ctrl->hw); + + mutex_unlock(&ctrl->ctrl_lock); + return rc; +} + +/** + * dsi_ctrl_drv_register() - register platform driver for dsi controller + */ +void dsi_ctrl_drv_register(void) +{ + platform_driver_register(&dsi_ctrl_driver); +} + +/** + * dsi_ctrl_drv_unregister() - unregister platform driver + */ +void dsi_ctrl_drv_unregister(void) +{ + platform_driver_unregister(&dsi_ctrl_driver); +} diff --git a/techpack/display/msm/dsi/dsi_ctrl.h b/techpack/display/msm/dsi/dsi_ctrl.h new file mode 100644 index 0000000000000000000000000000000000000000..c0348092e9eb639ab0be2c9ec616a30a59b91b9f --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl.h @@ -0,0 +1,878 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_CTRL_H_ +#define _DSI_CTRL_H_ + +#include <linux/debugfs.h> + +#include "dsi_defs.h" +#include "dsi_ctrl_hw.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "drm_mipi_dsi.h" + +/* + * DSI Command transfer modifiers + * @DSI_CTRL_CMD_READ: The current transfer involves reading data. + * @DSI_CTRL_CMD_BROADCAST: The current transfer needs to be done in + * broadcast mode to multiple slaves. + * @DSI_CTRL_CMD_BROADCAST_MASTER: This controller is the master and the slaves + * sync to this trigger. + * @DSI_CTRL_CMD_DEFER_TRIGGER: Defer the command trigger to later. + * @DSI_CTRL_CMD_FIFO_STORE: Use FIFO for command transfer in place of + * reading data from memory. + * @DSI_CTRL_CMD_FETCH_MEMORY: Fetch command from memory through AXI bus + * and transfer it. + * @DSI_CTRL_CMD_LAST_COMMAND: Trigger the DMA cmd transfer if this is last + * command in the batch. + * @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Transfer cmd packets in non embedded mode. + * @DSI_CTRL_CMD_CUSTOM_DMA_SCHED: Use the dma scheduling line number defined in + * display panel dtsi file instead of default. + * @DSI_CTRL_CMD_ASYNC_WAIT: Command flag to indicate that the wait for done + * for this command is asynchronous and must be queued. + */ +#define DSI_CTRL_CMD_READ 0x1 +#define DSI_CTRL_CMD_BROADCAST 0x2 +#define DSI_CTRL_CMD_BROADCAST_MASTER 0x4 +#define DSI_CTRL_CMD_DEFER_TRIGGER 0x8 +#define DSI_CTRL_CMD_FIFO_STORE 0x10 +#define DSI_CTRL_CMD_FETCH_MEMORY 0x20 +#define DSI_CTRL_CMD_LAST_COMMAND 0x40 +#define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80 +#define DSI_CTRL_CMD_CUSTOM_DMA_SCHED 0x100 +#define DSI_CTRL_CMD_ASYNC_WAIT 0x200 + +/* DSI embedded mode fifo size + * If the command is greater than 256 bytes it is sent in non-embedded mode. + */ +#define DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES 256 + +/* max size supported for dsi cmd transfer using TPG */ +#define DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE 64 + +/** + * enum dsi_power_state - defines power states for dsi controller. + * @DSI_CTRL_POWER_VREG_OFF: Digital and analog supplies for DSI controller + turned off + * @DSI_CTRL_POWER_VREG_ON: Digital and analog supplies for DSI controller + * @DSI_CTRL_POWER_MAX: Maximum value. + */ +enum dsi_power_state { + DSI_CTRL_POWER_VREG_OFF = 0, + DSI_CTRL_POWER_VREG_ON, + DSI_CTRL_POWER_MAX, +}; + +/** + * enum dsi_engine_state - define engine status for dsi controller. + * @DSI_CTRL_ENGINE_OFF: Engine is turned off. + * @DSI_CTRL_ENGINE_ON: Engine is turned on. + * @DSI_CTRL_ENGINE_MAX: Maximum value. + */ +enum dsi_engine_state { + DSI_CTRL_ENGINE_OFF = 0, + DSI_CTRL_ENGINE_ON, + DSI_CTRL_ENGINE_MAX, +}; + +/** + * enum dsi_ctrl_driver_ops - controller driver ops + */ +enum dsi_ctrl_driver_ops { + DSI_CTRL_OP_POWER_STATE_CHANGE, + DSI_CTRL_OP_CMD_ENGINE, + DSI_CTRL_OP_VID_ENGINE, + DSI_CTRL_OP_HOST_ENGINE, + DSI_CTRL_OP_CMD_TX, + DSI_CTRL_OP_HOST_INIT, + DSI_CTRL_OP_TPG, + DSI_CTRL_OP_PHY_SW_RESET, + DSI_CTRL_OP_ASYNC_TIMING, + DSI_CTRL_OP_MAX +}; + +/** + * struct dsi_ctrl_power_info - digital and analog power supplies for dsi host + * @digital: Digital power supply required to turn on DSI controller hardware. + * @host_pwr: Analog power supplies required to turn on DSI controller hardware. + * Even though DSI controller it self does not require an analog + * power supply, supplies required for PLL can be defined here to + * allow proper control over these supplies. + */ +struct dsi_ctrl_power_info { + struct dsi_regulator_info digital; + struct dsi_regulator_info host_pwr; +}; + +/** + * struct dsi_ctrl_clk_info - clock information for DSI controller + * @core_clks: Core clocks needed to access DSI controller registers. + * @hs_link_clks: Clocks required to transmit high speed data over DSI + * @lp_link_clks: Clocks required to perform low power ops over DSI + * @rcg_clks: Root clock generation clocks generated in MMSS_CC. The + * output of the PLL is set as parent for these root + * clocks. These clocks are specific to controller + * instance. + * @mux_clks: Mux clocks used for Dynamic refresh feature. + * @ext_clks: External byte/pixel clocks from the MMSS block. These + * clocks are set as parent to rcg clocks. + * @pll_op_clks: TODO: + * @shadow_clks: TODO: + */ +struct dsi_ctrl_clk_info { + /* Clocks parsed from DT */ + struct dsi_core_clk_info core_clks; + struct dsi_link_hs_clk_info hs_link_clks; + struct dsi_link_lp_clk_info lp_link_clks; + struct dsi_clk_link_set rcg_clks; + + /* Clocks set by DSI Manager */ + struct dsi_clk_link_set mux_clks; + struct dsi_clk_link_set ext_clks; + struct dsi_clk_link_set pll_op_clks; + struct dsi_clk_link_set shadow_clks; +}; + +/** + * struct dsi_ctrl_bus_scale_info - Bus scale info for msm-bus bandwidth voting + * @bus_scale_table: Bus scale voting usecases. + * @bus_handle: Handle used for voting bandwidth. + */ +struct dsi_ctrl_bus_scale_info { + struct msm_bus_scale_pdata *bus_scale_table; + u32 bus_handle; +}; + +/** + * struct dsi_ctrl_state_info - current driver state information + * @power_state: Status of power states on DSI controller. + * @cmd_engine_state: Status of DSI command engine. + * @vid_engine_state: Status of DSI video engine. + * @controller_state: Status of DSI Controller engine. + * @host_initialized: Boolean to indicate status of DSi host Initialization + * @tpg_enabled: Boolean to indicate whether tpg is enabled. + */ +struct dsi_ctrl_state_info { + enum dsi_power_state power_state; + enum dsi_engine_state cmd_engine_state; + enum dsi_engine_state vid_engine_state; + enum dsi_engine_state controller_state; + bool host_initialized; + bool tpg_enabled; +}; + +/** + * struct dsi_ctrl_interrupts - define interrupt information + * @irq_lock: Spinlock for ISR handler. + * @irq_num: Linux interrupt number associated with device. + * @irq_stat_mask: Hardware mask of currently enabled interrupts. + * @irq_stat_refcount: Number of times each interrupt has been requested. + * @irq_stat_cb: Status IRQ callback definitions. + * @irq_err_cb: IRQ callback definition to handle DSI ERRORs. + * @cmd_dma_done: Completion signal for DSI_CMD_MODE_DMA_DONE interrupt + * @vid_frame_done: Completion signal for DSI_VIDEO_MODE_FRAME_DONE int. + * @cmd_frame_done: Completion signal for DSI_CMD_FRAME_DONE interrupt. + */ +struct dsi_ctrl_interrupts { + spinlock_t irq_lock; + int irq_num; + uint32_t irq_stat_mask; + int irq_stat_refcount[DSI_STATUS_INTERRUPT_COUNT]; + struct dsi_event_cb_info irq_stat_cb[DSI_STATUS_INTERRUPT_COUNT]; + struct dsi_event_cb_info irq_err_cb; + + struct completion cmd_dma_done; + struct completion vid_frame_done; + struct completion cmd_frame_done; + struct completion bta_done; +}; + +/** + * struct dsi_ctrl - DSI controller object + * @pdev: Pointer to platform device. + * @cell_index: Instance cell id. + * @horiz_index: Index in physical horizontal CTRL layout, 0 = leftmost + * @name: Name of the controller instance. + * @refcount: ref counter. + * @ctrl_lock: Mutex for hardware and object access. + * @drm_dev: Pointer to DRM device. + * @version: DSI controller version. + * @hw: DSI controller hardware object. + * @current_state: Current driver and hardware state. + * @clk_cb: Callback for DSI clock control. + * @irq_info: Interrupt information. + * @recovery_cb: Recovery call back to SDE. + * @clk_info: Clock information. + * @clk_freq: DSi Link clock frequency information. + * @pwr_info: Power information. + * @axi_bus_info: AXI bus information. + * @host_config: Current host configuration. + * @mode_bounds: Boundaries of the default mode ROI. + * Origin is at top left of all CTRLs. + * @roi: Partial update region of interest. + * Origin is top left of this CTRL. + * @tx_cmd_buf: Tx command buffer. + * @cmd_buffer_iova: cmd buffer mapped address. + * @cmd_buffer_size: Size of command buffer. + * @vaddr: CPU virtual address of cmd buffer. + * @secure_mode: Indicates if secure-session is in progress + * @esd_check_underway: Indicates if esd status check is in progress + * @dma_cmd_wait: Work object waiting on DMA command transfer done. + * @dma_cmd_workq: Pointer to the workqueue of DMA command transfer done + * wait sequence. + * @dma_wait_queued: Indicates if any DMA command transfer wait work + * is queued. + * @dma_irq_trig: Atomic state to indicate DMA done IRQ + * triggered. + * @debugfs_root: Root for debugfs entries. + * @misr_enable: Frame MISR enable/disable + * @misr_cache: Cached Frame MISR value + * @frame_threshold_time_us: Frame threshold time in microseconds, where + * dsi data lane will be idle i.e from pingpong done to + * next TE for command mode. + * @phy_isolation_enabled: A boolean property allows to isolate the phy from + * dsi controller and run only dsi controller. + * @null_insertion_enabled: A boolean property to allow dsi controller to + * insert null packet. + * @modeupdated: Boolean to send new roi if mode is updated. + * @split_link_supported: Boolean to check if hw supports split link. + */ +struct dsi_ctrl { + struct platform_device *pdev; + u32 cell_index; + u32 horiz_index; + const char *name; + u32 refcount; + struct mutex ctrl_lock; + struct drm_device *drm_dev; + + enum dsi_ctrl_version version; + struct dsi_ctrl_hw hw; + + /* Current state */ + struct dsi_ctrl_state_info current_state; + struct clk_ctrl_cb clk_cb; + + struct dsi_ctrl_interrupts irq_info; + struct dsi_event_cb_info recovery_cb; + + /* Clock and power states */ + struct dsi_ctrl_clk_info clk_info; + struct link_clk_freq clk_freq; + struct dsi_ctrl_power_info pwr_info; + struct dsi_ctrl_bus_scale_info axi_bus_info; + + struct dsi_host_config host_config; + struct dsi_rect mode_bounds; + struct dsi_rect roi; + + /* Command tx and rx */ + struct drm_gem_object *tx_cmd_buf; + u32 cmd_buffer_size; + u32 cmd_buffer_iova; + u32 cmd_len; + void *vaddr; + bool secure_mode; + bool esd_check_underway; + struct work_struct dma_cmd_wait; + struct workqueue_struct *dma_cmd_workq; + bool dma_wait_queued; + atomic_t dma_irq_trig; + + /* Debug Information */ + struct dentry *debugfs_root; + + /* MISR */ + bool misr_enable; + u32 misr_cache; + + u32 frame_threshold_time_us; + + /* Check for spurious interrupts */ + unsigned long jiffies_start; + unsigned int error_interrupt_count; + + bool phy_isolation_enabled; + bool null_insertion_enabled; + bool modeupdated; + bool split_link_supported; +}; + +/** + * dsi_ctrl_get() - get a dsi_ctrl handle from an of_node + * @of_node: of_node of the DSI controller. + * + * Gets the DSI controller handle for the corresponding of_node. The ref count + * is incremented to one and all subsequent gets will fail until the original + * clients calls a put. + * + * Return: DSI Controller handle. + */ +struct dsi_ctrl *dsi_ctrl_get(struct device_node *of_node); + +/** + * dsi_ctrl_put() - releases a dsi controller handle. + * @dsi_ctrl: DSI controller handle. + * + * Releases the DSI controller. Driver will clean up all resources and puts back + * the DSI controller into reset state. + */ +void dsi_ctrl_put(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_drv_init() - initialize dsi controller driver. + * @dsi_ctrl: DSI controller handle. + * @parent: Parent directory for debug fs. + * + * Initializes DSI controller driver. Driver should be initialized after + * dsi_ctrl_get() succeeds. + * + * Return: error code. + */ +int dsi_ctrl_drv_init(struct dsi_ctrl *dsi_ctrl, struct dentry *parent); + +/** + * dsi_ctrl_drv_deinit() - de-initializes dsi controller driver + * @dsi_ctrl: DSI controller handle. + * + * Releases all resources acquired by dsi_ctrl_drv_init(). + * + * Return: error code. + */ +int dsi_ctrl_drv_deinit(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_validate_timing() - validate a video timing configuration + * @dsi_ctrl: DSI controller handle. + * @timing: Pointer to timing data. + * + * Driver will validate if the timing configuration is supported on the + * controller hardware. + * + * Return: error code if timing is not supported. + */ +int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl, + struct dsi_mode_info *timing); + +/** + * dsi_ctrl_update_host_config() - update dsi host configuration + * @dsi_ctrl: DSI controller handle. + * @config: DSI host configuration. + * @mode: DSI host mode selected. + * @flags: dsi_mode_flags modifying the behavior + * @clk_handle: Clock handle for DSI clocks + * + * Updates driver with new Host configuration to use for host initialization. + * This function call will only update the software context. The stored + * configuration information will be used when the host is initialized. + * + * Return: error code. + */ +int dsi_ctrl_update_host_config(struct dsi_ctrl *dsi_ctrl, + struct dsi_host_config *config, + struct dsi_display_mode *mode, int flags, + void *clk_handle); + +/** + * dsi_ctrl_timing_db_update() - update only controller Timing DB + * @dsi_ctrl: DSI controller handle. + * @enable: Enable/disable Timing DB register + * + * Update timing db register value during dfps usecases + * + * Return: error code. + */ +int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl, + bool enable); + +/** + * dsi_ctrl_async_timing_update() - update only controller timing + * @dsi_ctrl: DSI controller handle. + * @timing: New DSI timing info + * + * Updates host timing values to asynchronously transition to new timing + * For example, to update the porch values in a seamless/dynamic fps switch. + * + * Return: error code. + */ +int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl, + struct dsi_mode_info *timing); + +/** + * dsi_ctrl_phy_sw_reset() - perform a PHY software reset + * @dsi_ctrl: DSI controller handle. + * + * Performs a PHY software reset on the DSI controller. Reset should be done + * when the controller power state is DSI_CTRL_POWER_CORE_CLK_ON and the PHY is + * not enabled. + * + * This function will fail if driver is in any other state. + * + * Return: error code. + */ +int dsi_ctrl_phy_sw_reset(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal + * to DSI PHY hardware. + * @dsi_ctrl: DSI controller handle. + * @enable: Mask/unmask the PHY reset signal. + * + * Return: error code. + */ +int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_config_clk_gating() - Enable/Disable DSI PHY clk gating + * @dsi_ctrl: DSI controller handle. + * @enable: Enable/disable DSI PHY clk gating + * @clk_selection: clock selection for gating + * + * Return: error code. + */ +int dsi_ctrl_config_clk_gating(struct dsi_ctrl *dsi_ctrl, bool enable, + enum dsi_clk_gate_type clk_selection); + +/** + * dsi_ctrl_soft_reset() - perform a soft reset on DSI controller + * @dsi_ctrl: DSI controller handle. + * + * The video, command and controller engines will be disabled before the + * reset is triggered. After, the engines will be re-enabled to the same state + * as before the reset. + * + * If the reset is done while MDP timing engine is turned on, the video + * engine should be re-enabled only during the vertical blanking time. + * + * Return: error code + */ +int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_host_timing_update - reinitialize host with new timing values + * @dsi_ctrl: DSI controller handle. + * + * Reinitialize DSI controller hardware with new display timing values + * when resolution is switched dynamically. + * + * Return: error code + */ +int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_host_init() - Initialize DSI host hardware. + * @dsi_ctrl: DSI controller handle. + * @is_splash_enabled: boolean signifying splash status. + * + * Initializes DSI controller hardware with host configuration provided by + * dsi_ctrl_update_host_config(). Initialization can be performed only during + * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been + * performed. + * + * Return: error code. + */ +int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled); + +/** + * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware. + * @dsi_ctrl: DSI controller handle. + * + * De-initializes DSI controller hardware. It can be performed only during + * DSI_CTRL_POWER_CORE_CLK_ON state after LINK clocks have been turned off. + * + * Return: error code. + */ +int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable ULPS. + * + * ULPS can be enabled/disabled after DSI host engine is turned on. + * + * Return: error code. + */ +int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_timing_setup() - Setup DSI host config + * @dsi_ctrl: DSI controller handle. + * + * Initializes DSI controller hardware with host configuration provided by + * dsi_ctrl_update_host_config(). This is called while setting up DSI host + * through dsi_ctrl_setup() and after any ROI change. + * + * Also used to program the video mode timing values. + * + * Return: error code. + */ +int dsi_ctrl_timing_setup(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_setup() - Setup DSI host hardware while coming out of idle screen. + * @dsi_ctrl: DSI controller handle. + * + * Initialization of DSI controller hardware with host configuration and + * enabling required interrupts. Initialization can be performed only during + * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been + * performed. + * + * Return: error code. + */ +int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_set_roi() - Set DSI controller's region of interest + * @dsi_ctrl: DSI controller handle. + * @roi: Region of interest rectangle, must be less than mode bounds + * @changed: Output parameter, set to true of the controller's ROI was + * dirtied by setting the new ROI, and DCS cmd update needed + * + * Return: error code. + */ +int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi, + bool *changed); + +/** + * dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller + * @dsi_ctrl: DSI controller handle. + * @on: enable/disable test pattern. + * + * Test pattern can be enabled only after Video engine (for video mode panels) + * or command engine (for cmd mode panels) is enabled. + * + * Return: error code. + */ +int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on); + +/** + * dsi_ctrl_cmd_transfer() - Transfer commands on DSI link + * @dsi_ctrl: DSI controller handle. + * @msg: Message to transfer on DSI link. + * @flags: Modifiers for message transfer. + * + * Command transfer can be done only when command engine is enabled. The + * transfer API will until either the command transfer finishes or the timeout + * value is reached. If the trigger is deferred, it will return without + * triggering the transfer. Command parameters are programmed to hardware. + * + * Return: error code. + */ +int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, + const struct mipi_dsi_msg *msg, + u32 *flags); + +/** + * dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command. + * @dsi_ctrl: DSI controller handle. + * @flags: Modifiers. + * + * Return: error code. + */ +int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags); + +/** + * dsi_ctrl_update_host_engine_state_for_cont_splash() - update engine + * states for cont splash usecase + * @dsi_ctrl: DSI controller handle. + * @state: DSI engine state + * + * Return: error code. + */ +int dsi_ctrl_update_host_engine_state_for_cont_splash(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state); + +/** + * dsi_ctrl_set_power_state() - set power state for dsi controller + * @dsi_ctrl: DSI controller handle. + * @state: Power state. + * + * Set power state for DSI controller. Power state can be changed only when + * Controller, Video and Command engines are turned off. + * + * Return: error code. + */ +int dsi_ctrl_set_power_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_power_state state); + +/** + * dsi_ctrl_set_cmd_engine_state() - set command engine state + * @dsi_ctrl: DSI Controller handle. + * @state: Engine state. + * + * Command engine state can be modified only when DSI controller power state is + * set to DSI_CTRL_POWER_LINK_CLK_ON. + * + * Return: error code. + */ +int dsi_ctrl_set_cmd_engine_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state); + +/** + * dsi_ctrl_validate_host_state() - validate DSI ctrl host state + * @dsi_ctrl: DSI Controller handle. + * + * Validate DSI cotroller host state + * + * Return: boolean indicating whether host is not initialized. + */ +bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_set_vid_engine_state() - set video engine state + * @dsi_ctrl: DSI Controller handle. + * @state: Engine state. + * + * Video engine state can be modified only when DSI controller power state is + * set to DSI_CTRL_POWER_LINK_CLK_ON. + * + * Return: error code. + */ +int dsi_ctrl_set_vid_engine_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state); + +/** + * dsi_ctrl_set_host_engine_state() - set host engine state + * @dsi_ctrl: DSI Controller handle. + * @state: Engine state. + * + * Host engine state can be modified only when DSI controller power state is + * set to DSI_CTRL_POWER_LINK_CLK_ON and cmd, video engines are disabled. + * + * Return: error code. + */ +int dsi_ctrl_set_host_engine_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_engine_state state); + +/** + * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes. + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable ULPS. + * + * ULPS can be enabled/disabled after DSI host engine is turned on. + * + * Return: error code. + */ +int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_clk_cb_register() - Register DSI controller clk control callback + * @dsi_ctrl: DSI controller handle. + * @clk__cb: Structure containing callback for clock control. + * + * Register call for DSI clock control + * + * Return: error code. + */ +int dsi_ctrl_clk_cb_register(struct dsi_ctrl *dsi_ctrl, + struct clk_ctrl_cb *clk_cb); + +/** + * dsi_ctrl_set_clamp_state() - set clamp state for DSI phy + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable clamping. + * @ulps_enabled: ulps state. + * + * Clamps can be enabled/disabled while DSI controller is still turned on. + * + * Return: error code. + */ +int dsi_ctrl_set_clamp_state(struct dsi_ctrl *dsi_Ctrl, + bool enable, bool ulps_enabled); + +/** + * dsi_ctrl_set_clock_source() - set clock source fpr dsi link clocks + * @dsi_ctrl: DSI controller handle. + * @source_clks: Source clocks for DSI link clocks. + * + * Clock source should be changed while link clocks are disabled. + * + * Return: error code. + */ +int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl, + struct dsi_clk_link_set *source_clks); + +/** + * dsi_ctrl_enable_status_interrupt() - enable status interrupts + * @dsi_ctrl: DSI controller handle. + * @intr_idx: Index interrupt to disable. + * @event_info: Pointer to event callback definition + */ +void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl, + uint32_t intr_idx, struct dsi_event_cb_info *event_info); + +/** + * dsi_ctrl_disable_status_interrupt() - disable status interrupts + * @dsi_ctrl: DSI controller handle. + * @intr_idx: Index interrupt to disable. + */ +void dsi_ctrl_disable_status_interrupt( + struct dsi_ctrl *dsi_ctrl, uint32_t intr_idx); + +/** + * dsi_ctrl_setup_misr() - Setup frame MISR + * @dsi_ctrl: DSI controller handle. + * @enable: enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + * + * Return: error code. + */ +int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl, + bool enable, + u32 frame_count); + +/** + * dsi_ctrl_collect_misr() - Read frame MISR + * @dsi_ctrl: DSI controller handle. + * + * Return: MISR value. + */ +u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_cache_misr - Cache frame MISR value + * @dsi_ctrl: DSI controller handle. + */ +void dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_drv_register() - register platform driver for dsi controller + */ +void dsi_ctrl_drv_register(void); + +/** + * dsi_ctrl_drv_unregister() - unregister platform driver + */ +void dsi_ctrl_drv_unregister(void); + +/** + * dsi_ctrl_reset() - Reset DSI PHY CLK/DATA lane + * @dsi_ctrl: DSI controller handle. + * @mask: Mask to indicate if CLK and/or DATA lane needs reset. + */ +int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask); + +/** + * dsi_ctrl_get_hw_version() - read dsi controller hw revision + * @dsi_ctrl: DSI controller handle. + */ +int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl); + +/** + * dsi_ctrl_vid_engine_en() - Control DSI video engine HW state + * @dsi_ctrl: DSI controller handle. + * @on: variable to control video engine ON/OFF. + */ +int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on); + +/** + * dsi_ctrl_setup_avr() - Set/Clear the AVR_SUPPORT_ENABLE bit + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control AVR support ON/OFF. + */ +int dsi_ctrl_setup_avr(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * @dsi_ctrl: DSI controller handle. + * cmd_len: Length of command. + * flags: Config mode flags. + */ +void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len, + u32 *flags); + +/** + * @dsi_ctrl: DSI controller handle. + * cmd_len: Length of command. + * flags: Config mode flags. + */ +int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len, + u32 *flags); + +/** + * dsi_ctrl_isr_configure() - API to register/deregister dsi isr + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control register/deregister isr + */ +void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_mask_error_status_interrupts() - API to mask dsi ctrl error status + * interrupts + * @dsi_ctrl: DSI controller handle. + * @idx: id indicating which interrupts to enable/disable. + * @mask_enable: boolean to enable/disable masking. + */ +void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl, u32 idx, + bool mask_enable); + +/** + * dsi_ctrl_irq_update() - Put a irq vote to process DSI error + * interrupts at any time. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control enable/disable irq line + */ +void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_get_host_engine_init_state() - Return host init state + */ +int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, + bool *state); + +/** + * dsi_ctrl_wait_for_cmd_mode_mdp_idle() - Wait for command mode engine not to + * be busy sending data from display engine. + * @dsi_ctrl: DSI controller handle. + */ +int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl); +/** + * dsi_ctrl_update_host_state() - Set the host state + */ +int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl, + enum dsi_ctrl_driver_ops op, bool en); + +/** + * dsi_ctrl_pixel_format_to_bpp() - returns number of bits per pxl + */ +int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format); + +/** + * dsi_ctrl_hs_req_sel() - API to enable continuous clk support through phy + * @dsi_ctrl: DSI controller handle. + * @sel_phy: Boolean to control whether to select phy or + * controller + */ +void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy); + +/** + * dsi_ctrl_set_continuous_clk() - API to set/unset force clock lane HS request. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control continuous clock. + */ +void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamic refresh done + * interrupt. + * @dsi_ctrl: DSI controller handle. + */ +int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl); + +/** + * dsi_ctrl_mask_overflow() - API to mask/unmask overflow errors. + * @dsi_ctrl: DSI controller handle. + * @enable: variable to control masking/unmasking. + */ +void dsi_ctrl_mask_overflow(struct dsi_ctrl *dsi_ctrl, bool enable); + +/** + * dsi_ctrl_clear_slave_dma_status - API to clear slave DMA status + * @dsi_ctrl: DSI controller handle. + * @flags: Modifiers + */ +int dsi_ctrl_clear_slave_dma_status(struct dsi_ctrl *dsi_ctrl, u32 flags); +#endif /* _DSI_CTRL_H_ */ diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw.h b/techpack/display/msm/dsi/dsi_ctrl_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..9411e98c0fb6e152245d86cd3164dd85eab67b3e --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl_hw.h @@ -0,0 +1,883 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_CTRL_HW_H_ +#define _DSI_CTRL_HW_H_ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/bitmap.h> + +#include "dsi_defs.h" + +#define DSI_CTRL_HW_DBG(c, fmt, ...) DRM_DEV_DEBUG(NULL, "[msm-dsi-debug]: DSI_%d: "\ + fmt, c ? c->index : -1, ##__VA_ARGS__) +#define DSI_CTRL_HW_ERR(c, fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: DSI_%d: "\ + fmt, c ? c->index : -1, ##__VA_ARGS__) +#define DSI_CTRL_HW_INFO(c, fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: DSI_%d: "\ + fmt, c ? c->index : -1, ##__VA_ARGS__) + +/** + * Modifier flag for command transmission. If this flag is set, command + * information is programmed to hardware and transmission is not triggered. + * Caller should call the trigger_command_dma() to start the transmission. This + * flag is valed for kickoff_command() and kickoff_fifo_command() operations. + */ +#define DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER 0x1 + +/** + * enum dsi_ctrl_version - version of the dsi host controller + * @DSI_CTRL_VERSION_UNKNOWN: Unknown controller version + * @DSI_CTRL_VERSION_1_3: DSI host v1.3 controller + * @DSI_CTRL_VERSION_1_4: DSI host v1.4 controller + * @DSI_CTRL_VERSION_2_0: DSI host v2.0 controller + * @DSI_CTRL_VERSION_2_2: DSI host v2.2 controller + * @DSI_CTRL_VERSION_2_3: DSI host v2.3 controller + * @DSI_CTRL_VERSION_2_4: DSI host v2.4 controller + * @DSI_CTRL_VERSION_MAX: max version + */ +enum dsi_ctrl_version { + DSI_CTRL_VERSION_UNKNOWN, + DSI_CTRL_VERSION_1_3, + DSI_CTRL_VERSION_1_4, + DSI_CTRL_VERSION_2_0, + DSI_CTRL_VERSION_2_2, + DSI_CTRL_VERSION_2_3, + DSI_CTRL_VERSION_2_4, + DSI_CTRL_VERSION_MAX +}; + +/** + * enum dsi_ctrl_hw_features - features supported by dsi host controller + * @DSI_CTRL_VIDEO_TPG: Test pattern support for video mode. + * @DSI_CTRL_CMD_TPG: Test pattern support for command mode. + * @DSI_CTRL_VARIABLE_REFRESH_RATE: variable panel timing + * @DSI_CTRL_DYNAMIC_REFRESH: variable pixel clock rate + * @DSI_CTRL_NULL_PACKET_INSERTION: NULL packet insertion + * @DSI_CTRL_DESKEW_CALIB: Deskew calibration support + * @DSI_CTRL_DPHY: Controller support for DPHY + * @DSI_CTRL_CPHY: Controller support for CPHY + * @DSI_CTRL_MAX_FEATURES: + */ +enum dsi_ctrl_hw_features { + DSI_CTRL_VIDEO_TPG, + DSI_CTRL_CMD_TPG, + DSI_CTRL_VARIABLE_REFRESH_RATE, + DSI_CTRL_DYNAMIC_REFRESH, + DSI_CTRL_NULL_PACKET_INSERTION, + DSI_CTRL_DESKEW_CALIB, + DSI_CTRL_DPHY, + DSI_CTRL_CPHY, + DSI_CTRL_MAX_FEATURES +}; + +/** + * enum dsi_test_pattern - test pattern type + * @DSI_TEST_PATTERN_FIXED: Test pattern is fixed, based on init value. + * @DSI_TEST_PATTERN_INC: Incremental test pattern, base on init value. + * @DSI_TEST_PATTERN_POLY: Pattern generated from polynomial and init val. + * @DSI_TEST_PATTERN_MAX: + */ +enum dsi_test_pattern { + DSI_TEST_PATTERN_FIXED = 0, + DSI_TEST_PATTERN_INC, + DSI_TEST_PATTERN_POLY, + DSI_TEST_PATTERN_MAX +}; + +/** + * enum dsi_status_int_index - index of interrupts generated by DSI controller + * @DSI_SINT_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out. + * @DSI_SINT_CMD_STREAM0_FRAME_DONE: A frame of cmd mode stream0 is sent out. + * @DSI_SINT_CMD_STREAM1_FRAME_DONE: A frame of cmd mode stream1 is sent out. + * @DSI_SINT_CMD_STREAM2_FRAME_DONE: A frame of cmd mode stream2 is sent out. + * @DSI_SINT_VIDEO_MODE_FRAME_DONE: A frame of video mode stream is sent out. + * @DSI_SINT_BTA_DONE: A BTA is completed. + * @DSI_SINT_CMD_FRAME_DONE: A frame of selected cmd mode stream is + * sent out by MDP. + * @DSI_SINT_DYN_REFRESH_DONE: The dynamic refresh operation completed. + * @DSI_SINT_DESKEW_DONE: The deskew calibration operation done. + * @DSI_SINT_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has + * completed. + * @DSI_SINT_ERROR: DSI error has happened. + */ +enum dsi_status_int_index { + DSI_SINT_CMD_MODE_DMA_DONE = 0, + DSI_SINT_CMD_STREAM0_FRAME_DONE = 1, + DSI_SINT_CMD_STREAM1_FRAME_DONE = 2, + DSI_SINT_CMD_STREAM2_FRAME_DONE = 3, + DSI_SINT_VIDEO_MODE_FRAME_DONE = 4, + DSI_SINT_BTA_DONE = 5, + DSI_SINT_CMD_FRAME_DONE = 6, + DSI_SINT_DYN_REFRESH_DONE = 7, + DSI_SINT_DESKEW_DONE = 8, + DSI_SINT_DYN_BLANK_DMA_DONE = 9, + DSI_SINT_ERROR = 10, + + DSI_STATUS_INTERRUPT_COUNT +}; + +/** + * enum dsi_status_int_type - status interrupts generated by DSI controller + * @DSI_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out. + * @DSI_CMD_STREAM0_FRAME_DONE: A frame of command mode stream0 is sent out. + * @DSI_CMD_STREAM1_FRAME_DONE: A frame of command mode stream1 is sent out. + * @DSI_CMD_STREAM2_FRAME_DONE: A frame of command mode stream2 is sent out. + * @DSI_VIDEO_MODE_FRAME_DONE: A frame of video mode stream is sent out. + * @DSI_BTA_DONE: A BTA is completed. + * @DSI_CMD_FRAME_DONE: A frame of selected command mode stream is + * sent out by MDP. + * @DSI_DYN_REFRESH_DONE: The dynamic refresh operation has completed. + * @DSI_DESKEW_DONE: The deskew calibration operation has completed + * @DSI_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has + * completed. + * @DSI_ERROR: DSI error has happened. + */ +enum dsi_status_int_type { + DSI_CMD_MODE_DMA_DONE = BIT(DSI_SINT_CMD_MODE_DMA_DONE), + DSI_CMD_STREAM0_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM0_FRAME_DONE), + DSI_CMD_STREAM1_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM1_FRAME_DONE), + DSI_CMD_STREAM2_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM2_FRAME_DONE), + DSI_VIDEO_MODE_FRAME_DONE = BIT(DSI_SINT_VIDEO_MODE_FRAME_DONE), + DSI_BTA_DONE = BIT(DSI_SINT_BTA_DONE), + DSI_CMD_FRAME_DONE = BIT(DSI_SINT_CMD_FRAME_DONE), + DSI_DYN_REFRESH_DONE = BIT(DSI_SINT_DYN_REFRESH_DONE), + DSI_DESKEW_DONE = BIT(DSI_SINT_DESKEW_DONE), + DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE), + DSI_ERROR = BIT(DSI_SINT_ERROR) +}; + +/** + * enum dsi_error_int_index - index of error interrupts from DSI controller + * @DSI_EINT_RDBK_SINGLE_ECC_ERR: Single bit ECC error in read packet. + * @DSI_EINT_RDBK_MULTI_ECC_ERR: Multi bit ECC error in read packet. + * @DSI_EINT_RDBK_CRC_ERR: CRC error in read packet. + * @DSI_EINT_RDBK_INCOMPLETE_PKT: Incomplete read packet. + * @DSI_EINT_PERIPH_ERROR_PKT: Error packet returned from peripheral, + * @DSI_EINT_LP_RX_TIMEOUT: Low power reverse transmission timeout. + * @DSI_EINT_HS_TX_TIMEOUT: High speed fwd transmission timeout. + * @DSI_EINT_BTA_TIMEOUT: BTA timeout. + * @DSI_EINT_PLL_UNLOCK: PLL has unlocked. + * @DSI_EINT_DLN0_ESC_ENTRY_ERR: Incorrect LP Rx escape entry. + * @DSI_EINT_DLN0_ESC_SYNC_ERR: LP Rx data is not byte aligned. + * @DSI_EINT_DLN0_LP_CONTROL_ERR: Incorrect LP Rx state sequence. + * @DSI_EINT_PANEL_SPECIFIC_ERR: DSI Protocol violation error. + * @DSI_EINT_INTERLEAVE_OP_CONTENTION: Interleave operation contention. + * @DSI_EINT_CMD_DMA_FIFO_UNDERFLOW: Command mode DMA FIFO underflow. + * @DSI_EINT_CMD_MDP_FIFO_UNDERFLOW: Command MDP FIFO underflow (failed to + * receive one complete line from MDP). + * @DSI_EINT_DLN0_HS_FIFO_OVERFLOW: High speed FIFO data lane 0 overflows. + * @DSI_EINT_DLN1_HS_FIFO_OVERFLOW: High speed FIFO data lane 1 overflows. + * @DSI_EINT_DLN2_HS_FIFO_OVERFLOW: High speed FIFO data lane 2 overflows. + * @DSI_EINT_DLN3_HS_FIFO_OVERFLOW: High speed FIFO data lane 3 overflows. + * @DSI_EINT_DLN0_HS_FIFO_UNDERFLOW: High speed FIFO data lane 0 underflows. + * @DSI_EINT_DLN1_HS_FIFO_UNDERFLOW: High speed FIFO data lane 1 underflows. + * @DSI_EINT_DLN2_HS_FIFO_UNDERFLOW: High speed FIFO data lane 2 underflows. + * @DSI_EINT_DLN3_HS_FIFO_UNDERFLOW: High speed FIFO data lane 3 undeflows. + * @DSI_EINT_DLN0_LP0_CONTENTION: PHY level contention while lane 0 low. + * @DSI_EINT_DLN1_LP0_CONTENTION: PHY level contention while lane 1 low. + * @DSI_EINT_DLN2_LP0_CONTENTION: PHY level contention while lane 2 low. + * @DSI_EINT_DLN3_LP0_CONTENTION: PHY level contention while lane 3 low. + * @DSI_EINT_DLN0_LP1_CONTENTION: PHY level contention while lane 0 high. + * @DSI_EINT_DLN1_LP1_CONTENTION: PHY level contention while lane 1 high. + * @DSI_EINT_DLN2_LP1_CONTENTION: PHY level contention while lane 2 high. + * @DSI_EINT_DLN3_LP1_CONTENTION: PHY level contention while lane 3 high. + */ +enum dsi_error_int_index { + DSI_EINT_RDBK_SINGLE_ECC_ERR = 0, + DSI_EINT_RDBK_MULTI_ECC_ERR = 1, + DSI_EINT_RDBK_CRC_ERR = 2, + DSI_EINT_RDBK_INCOMPLETE_PKT = 3, + DSI_EINT_PERIPH_ERROR_PKT = 4, + DSI_EINT_LP_RX_TIMEOUT = 5, + DSI_EINT_HS_TX_TIMEOUT = 6, + DSI_EINT_BTA_TIMEOUT = 7, + DSI_EINT_PLL_UNLOCK = 8, + DSI_EINT_DLN0_ESC_ENTRY_ERR = 9, + DSI_EINT_DLN0_ESC_SYNC_ERR = 10, + DSI_EINT_DLN0_LP_CONTROL_ERR = 11, + DSI_EINT_PANEL_SPECIFIC_ERR = 12, + DSI_EINT_INTERLEAVE_OP_CONTENTION = 13, + DSI_EINT_CMD_DMA_FIFO_UNDERFLOW = 14, + DSI_EINT_CMD_MDP_FIFO_UNDERFLOW = 15, + DSI_EINT_DLN0_HS_FIFO_OVERFLOW = 16, + DSI_EINT_DLN1_HS_FIFO_OVERFLOW = 17, + DSI_EINT_DLN2_HS_FIFO_OVERFLOW = 18, + DSI_EINT_DLN3_HS_FIFO_OVERFLOW = 19, + DSI_EINT_DLN0_HS_FIFO_UNDERFLOW = 20, + DSI_EINT_DLN1_HS_FIFO_UNDERFLOW = 21, + DSI_EINT_DLN2_HS_FIFO_UNDERFLOW = 22, + DSI_EINT_DLN3_HS_FIFO_UNDERFLOW = 23, + DSI_EINT_DLN0_LP0_CONTENTION = 24, + DSI_EINT_DLN1_LP0_CONTENTION = 25, + DSI_EINT_DLN2_LP0_CONTENTION = 26, + DSI_EINT_DLN3_LP0_CONTENTION = 27, + DSI_EINT_DLN0_LP1_CONTENTION = 28, + DSI_EINT_DLN1_LP1_CONTENTION = 29, + DSI_EINT_DLN2_LP1_CONTENTION = 30, + DSI_EINT_DLN3_LP1_CONTENTION = 31, + + DSI_ERROR_INTERRUPT_COUNT +}; + +/** + * enum dsi_error_int_type - error interrupts generated by DSI controller + * @DSI_RDBK_SINGLE_ECC_ERR: Single bit ECC error in read packet. + * @DSI_RDBK_MULTI_ECC_ERR: Multi bit ECC error in read packet. + * @DSI_RDBK_CRC_ERR: CRC error in read packet. + * @DSI_RDBK_INCOMPLETE_PKT: Incomplete read packet. + * @DSI_PERIPH_ERROR_PKT: Error packet returned from peripheral, + * @DSI_LP_RX_TIMEOUT: Low power reverse transmission timeout. + * @DSI_HS_TX_TIMEOUT: High speed forward transmission timeout. + * @DSI_BTA_TIMEOUT: BTA timeout. + * @DSI_PLL_UNLOCK: PLL has unlocked. + * @DSI_DLN0_ESC_ENTRY_ERR: Incorrect LP Rx escape entry. + * @DSI_DLN0_ESC_SYNC_ERR: LP Rx data is not byte aligned. + * @DSI_DLN0_LP_CONTROL_ERR: Incorrect LP Rx state sequence. + * @DSI_PANEL_SPECIFIC_ERR: DSI Protocol violation. + * @DSI_INTERLEAVE_OP_CONTENTION: Interleave operation contention. + * @DSI_CMD_DMA_FIFO_UNDERFLOW: Command mode DMA FIFO underflow. + * @DSI_CMD_MDP_FIFO_UNDERFLOW: Command MDP FIFO underflow (failed to + * receive one complete line from MDP). + * @DSI_DLN0_HS_FIFO_OVERFLOW: High speed FIFO for data lane 0 overflows. + * @DSI_DLN1_HS_FIFO_OVERFLOW: High speed FIFO for data lane 1 overflows. + * @DSI_DLN2_HS_FIFO_OVERFLOW: High speed FIFO for data lane 2 overflows. + * @DSI_DLN3_HS_FIFO_OVERFLOW: High speed FIFO for data lane 3 overflows. + * @DSI_DLN0_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 0 underflows. + * @DSI_DLN1_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 1 underflows. + * @DSI_DLN2_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 2 underflows. + * @DSI_DLN3_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 3 undeflows. + * @DSI_DLN0_LP0_CONTENTION: PHY level contention while lane 0 is low. + * @DSI_DLN1_LP0_CONTENTION: PHY level contention while lane 1 is low. + * @DSI_DLN2_LP0_CONTENTION: PHY level contention while lane 2 is low. + * @DSI_DLN3_LP0_CONTENTION: PHY level contention while lane 3 is low. + * @DSI_DLN0_LP1_CONTENTION: PHY level contention while lane 0 is high. + * @DSI_DLN1_LP1_CONTENTION: PHY level contention while lane 1 is high. + * @DSI_DLN2_LP1_CONTENTION: PHY level contention while lane 2 is high. + * @DSI_DLN3_LP1_CONTENTION: PHY level contention while lane 3 is high. + */ +enum dsi_error_int_type { + DSI_RDBK_SINGLE_ECC_ERR = BIT(DSI_EINT_RDBK_SINGLE_ECC_ERR), + DSI_RDBK_MULTI_ECC_ERR = BIT(DSI_EINT_RDBK_MULTI_ECC_ERR), + DSI_RDBK_CRC_ERR = BIT(DSI_EINT_RDBK_CRC_ERR), + DSI_RDBK_INCOMPLETE_PKT = BIT(DSI_EINT_RDBK_INCOMPLETE_PKT), + DSI_PERIPH_ERROR_PKT = BIT(DSI_EINT_PERIPH_ERROR_PKT), + DSI_LP_RX_TIMEOUT = BIT(DSI_EINT_LP_RX_TIMEOUT), + DSI_HS_TX_TIMEOUT = BIT(DSI_EINT_HS_TX_TIMEOUT), + DSI_BTA_TIMEOUT = BIT(DSI_EINT_BTA_TIMEOUT), + DSI_PLL_UNLOCK = BIT(DSI_EINT_PLL_UNLOCK), + DSI_DLN0_ESC_ENTRY_ERR = BIT(DSI_EINT_DLN0_ESC_ENTRY_ERR), + DSI_DLN0_ESC_SYNC_ERR = BIT(DSI_EINT_DLN0_ESC_SYNC_ERR), + DSI_DLN0_LP_CONTROL_ERR = BIT(DSI_EINT_DLN0_LP_CONTROL_ERR), + DSI_PANEL_SPECIFIC_ERR = BIT(DSI_EINT_PANEL_SPECIFIC_ERR), + DSI_INTERLEAVE_OP_CONTENTION = BIT(DSI_EINT_INTERLEAVE_OP_CONTENTION), + DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_DMA_FIFO_UNDERFLOW), + DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_MDP_FIFO_UNDERFLOW), + DSI_DLN0_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_OVERFLOW), + DSI_DLN1_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_OVERFLOW), + DSI_DLN2_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_OVERFLOW), + DSI_DLN3_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_OVERFLOW), + DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_UNDERFLOW), + DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_UNDERFLOW), + DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_UNDERFLOW), + DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_UNDERFLOW), + DSI_DLN0_LP0_CONTENTION = BIT(DSI_EINT_DLN0_LP0_CONTENTION), + DSI_DLN1_LP0_CONTENTION = BIT(DSI_EINT_DLN1_LP0_CONTENTION), + DSI_DLN2_LP0_CONTENTION = BIT(DSI_EINT_DLN2_LP0_CONTENTION), + DSI_DLN3_LP0_CONTENTION = BIT(DSI_EINT_DLN3_LP0_CONTENTION), + DSI_DLN0_LP1_CONTENTION = BIT(DSI_EINT_DLN0_LP1_CONTENTION), + DSI_DLN1_LP1_CONTENTION = BIT(DSI_EINT_DLN1_LP1_CONTENTION), + DSI_DLN2_LP1_CONTENTION = BIT(DSI_EINT_DLN2_LP1_CONTENTION), + DSI_DLN3_LP1_CONTENTION = BIT(DSI_EINT_DLN3_LP1_CONTENTION), +}; + +/** + * struct dsi_ctrl_cmd_dma_info - command buffer information + * @offset: IOMMU VA for command buffer address. + * @length: Length of the command buffer. + * @datatype: Datatype of cmd. + * @en_broadcast: Enable broadcast mode if set to true. + * @is_master: Is master in broadcast mode. + * @use_lpm: Use low power mode for command transmission. + */ +struct dsi_ctrl_cmd_dma_info { + u32 offset; + u32 length; + u8 datatype; + bool en_broadcast; + bool is_master; + bool use_lpm; +}; + +/** + * struct dsi_ctrl_cmd_dma_fifo_info - command payload tp be sent using FIFO + * @command: VA for command buffer. + * @size: Size of the command buffer. + * @en_broadcast: Enable broadcast mode if set to true. + * @is_master: Is master in broadcast mode. + * @use_lpm: Use low power mode for command transmission. + */ +struct dsi_ctrl_cmd_dma_fifo_info { + u32 *command; + u32 size; + bool en_broadcast; + bool is_master; + bool use_lpm; +}; + +struct dsi_ctrl_hw; + +struct ctrl_ulps_config_ops { + /** + * ulps_request() - request ulps entry for specified lanes + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to enter ULPS. + * + * Caller should check if lanes are in ULPS mode by calling + * get_lanes_in_ulps() operation. + */ + void (*ulps_request)(struct dsi_ctrl_hw *ctrl, u32 lanes); + + /** + * ulps_exit() - exit ULPS on specified lanes + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to exit ULPS. + * + * Caller should check if lanes are in active mode by calling + * get_lanes_in_ulps() operation. + */ + void (*ulps_exit)(struct dsi_ctrl_hw *ctrl, u32 lanes); + + /** + * get_lanes_in_ulps() - returns the list of lanes in ULPS mode + * @ctrl: Pointer to the controller host hardware. + * + * Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS + * state. If 0 is returned, all the lanes are active. + * + * Return: List of lanes in ULPS state. + */ + u32 (*get_lanes_in_ulps)(struct dsi_ctrl_hw *ctrl); +}; + +/** + * struct dsi_ctrl_hw_ops - operations supported by dsi host hardware + */ +struct dsi_ctrl_hw_ops { + + /** + * host_setup() - Setup DSI host configuration + * @ctrl: Pointer to controller host hardware. + * @config: Configuration for DSI host controller + */ + void (*host_setup)(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *config); + + /** + * video_engine_en() - enable DSI video engine + * @ctrl: Pointer to controller host hardware. + * @on: Enable/disabel video engine. + */ + void (*video_engine_en)(struct dsi_ctrl_hw *ctrl, bool on); + + /** + * setup_avr() - set the AVR_SUPPORT_ENABLE bit in DSI_VIDEO_MODE_CTRL + * @ctrl: Pointer to controller host hardware. + * @enable: Controls whether this bit is set or cleared + */ + void (*setup_avr)(struct dsi_ctrl_hw *ctrl, bool enable); + + /** + * video_engine_setup() - Setup dsi host controller for video mode + * @ctrl: Pointer to controller host hardware. + * @common_cfg: Common configuration parameters. + * @cfg: Video mode configuration. + * + * Set up DSI video engine with a specific configuration. Controller and + * video engine are not enabled as part of this function. + */ + void (*video_engine_setup)(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *common_cfg, + struct dsi_video_engine_cfg *cfg); + + /** + * set_video_timing() - set up the timing for video frame + * @ctrl: Pointer to controller host hardware. + * @mode: Video mode information. + * + * Set up the video timing parameters for the DSI video mode operation. + */ + void (*set_video_timing)(struct dsi_ctrl_hw *ctrl, + struct dsi_mode_info *mode); + + /** + * cmd_engine_setup() - setup dsi host controller for command mode + * @ctrl: Pointer to the controller host hardware. + * @common_cfg: Common configuration parameters. + * @cfg: Command mode configuration. + * + * Setup DSI CMD engine with a specific configuration. Controller and + * command engine are not enabled as part of this function. + */ + void (*cmd_engine_setup)(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *common_cfg, + struct dsi_cmd_engine_cfg *cfg); + + /** + * setup_cmd_stream() - set up parameters for command pixel streams + * @ctrl: Pointer to controller host hardware. + * @mode: Pointer to mode information. + * @h_stride: Horizontal stride in bytes. + * @vc_id: stream_id. + * + * Setup parameters for command mode pixel stream size. + */ + void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl, + struct dsi_mode_info *mode, + u32 h_stride, + u32 vc_id, + struct dsi_rect *roi); + + /** + * ctrl_en() - enable DSI controller engine + * @ctrl: Pointer to the controller host hardware. + * @on: turn on/off the DSI controller engine. + */ + void (*ctrl_en)(struct dsi_ctrl_hw *ctrl, bool on); + + /** + * cmd_engine_en() - enable DSI controller command engine + * @ctrl: Pointer to the controller host hardware. + * @on: Turn on/off the DSI command engine. + */ + void (*cmd_engine_en)(struct dsi_ctrl_hw *ctrl, bool on); + + /** + * phy_sw_reset() - perform a soft reset on the PHY. + * @ctrl: Pointer to the controller host hardware. + */ + void (*phy_sw_reset)(struct dsi_ctrl_hw *ctrl); + + /** + * config_clk_gating() - enable/disable DSI PHY clk gating + * @ctrl: Pointer to the controller host hardware. + * @enable: enable/disable DSI PHY clock gating. + * @clk_selection: clock to enable/disable clock gating. + */ + void (*config_clk_gating)(struct dsi_ctrl_hw *ctrl, bool enable, + enum dsi_clk_gate_type clk_selection); + + /** + * debug_bus() - get dsi debug bus status. + * @ctrl: Pointer to the controller host hardware. + * @entries: Array of dsi debug bus control values. + * @size: Size of dsi debug bus control array. + */ + void (*debug_bus)(struct dsi_ctrl_hw *ctrl, u32 *entries, u32 size); + + /** + * soft_reset() - perform a soft reset on DSI controller + * @ctrl: Pointer to the controller host hardware. + * + * The video, command and controller engines will be disabled before the + * reset is triggered. After, the engines will be re-enabled to the same + * state as before the reset. + * + * If the reset is done while MDP timing engine is turned on, the video + * engine should be re-enabled only during the vertical blanking time. + */ + void (*soft_reset)(struct dsi_ctrl_hw *ctrl); + + /** + * setup_lane_map() - setup mapping between logical and physical lanes + * @ctrl: Pointer to the controller host hardware. + * @lane_map: Structure defining the mapping between DSI logical + * lanes and physical lanes. + */ + void (*setup_lane_map)(struct dsi_ctrl_hw *ctrl, + struct dsi_lane_map *lane_map); + + /** + * kickoff_command() - transmits commands stored in memory + * @ctrl: Pointer to the controller host hardware. + * @cmd: Command information. + * @flags: Modifiers for command transmission. + * + * The controller hardware is programmed with address and size of the + * command buffer. The transmission is kicked off if + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is + * set, caller should make a separate call to trigger_command_dma() to + * transmit the command. + */ + void (*kickoff_command)(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags); + + /** + * kickoff_command_non_embedded_mode() - cmd in non embedded mode + * @ctrl: Pointer to the controller host hardware. + * @cmd: Command information. + * @flags: Modifiers for command transmission. + * + * If command length is greater than DMA FIFO size of 256 bytes we use + * this non- embedded mode. + * The controller hardware is programmed with address and size of the + * command buffer. The transmission is kicked off if + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is + * set, caller should make a separate call to trigger_command_dma() to + * transmit the command. + */ + + void (*kickoff_command_non_embedded_mode)(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags); + + /** + * kickoff_fifo_command() - transmits a command using FIFO in dsi + * hardware. + * @ctrl: Pointer to the controller host hardware. + * @cmd: Command information. + * @flags: Modifiers for command transmission. + * + * The controller hardware FIFO is programmed with command header and + * payload. The transmission is kicked off if + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is + * set, caller should make a separate call to trigger_command_dma() to + * transmit the command. + */ + void (*kickoff_fifo_command)(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_fifo_info *cmd, + u32 flags); + + void (*reset_cmd_fifo)(struct dsi_ctrl_hw *ctrl); + /** + * trigger_command_dma() - trigger transmission of command buffer. + * @ctrl: Pointer to the controller host hardware. + * + * This trigger can be only used if there was a prior call to + * kickoff_command() of kickoff_fifo_command() with + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag. + */ + void (*trigger_command_dma)(struct dsi_ctrl_hw *ctrl); + + /** + * get_cmd_read_data() - get data read from the peripheral + * @ctrl: Pointer to the controller host hardware. + * @rd_buf: Buffer where data will be read into. + * @read_offset: Offset from where to read. + * @rx_byte: Number of bytes to be read. + * @pkt_size: Size of response expected. + * @hw_read_cnt: Actual number of bytes read by HW. + */ + u32 (*get_cmd_read_data)(struct dsi_ctrl_hw *ctrl, + u8 *rd_buf, + u32 read_offset, + u32 rx_byte, + u32 pkt_size, + u32 *hw_read_cnt); + + /** + * wait_for_lane_idle() - wait for DSI lanes to go to idle state + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to be checked to be in idle state. + */ + int (*wait_for_lane_idle)(struct dsi_ctrl_hw *ctrl, u32 lanes); + + struct ctrl_ulps_config_ops ulps_ops; + + /** + * clamp_enable() - enable DSI clamps + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes which need to have clamps released. + * @enable_ulps: ulps state. + */ + + /** + * clamp_enable() - enable DSI clamps to keep PHY driving a stable link + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes which need to have clamps released. + * @enable_ulps: TODO:?? + */ + void (*clamp_enable)(struct dsi_ctrl_hw *ctrl, + u32 lanes, + bool enable_ulps); + + /** + * clamp_disable() - disable DSI clamps + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes which need to have clamps released. + * @disable_ulps: ulps state. + */ + void (*clamp_disable)(struct dsi_ctrl_hw *ctrl, + u32 lanes, + bool disable_ulps); + + /** + * phy_reset_config() - Disable/enable propagation of reset signal + * from ahb domain to DSI PHY + * @ctrl: Pointer to the controller host hardware. + * @enable: True to mask the reset signal, false to unmask + */ + void (*phy_reset_config)(struct dsi_ctrl_hw *ctrl, + bool enable); + + /** + * get_interrupt_status() - returns the interrupt status + * @ctrl: Pointer to the controller host hardware. + * + * Returns the ORed list of interrupts(enum dsi_status_int_type) that + * are active. This list does not include any error interrupts. Caller + * should call get_error_status for error interrupts. + * + * Return: List of active interrupts. + */ + u32 (*get_interrupt_status)(struct dsi_ctrl_hw *ctrl); + + /** + * clear_interrupt_status() - clears the specified interrupts + * @ctrl: Pointer to the controller host hardware. + * @ints: List of interrupts to be cleared. + */ + void (*clear_interrupt_status)(struct dsi_ctrl_hw *ctrl, u32 ints); + + /** + * enable_status_interrupts() - enable the specified interrupts + * @ctrl: Pointer to the controller host hardware. + * @ints: List of interrupts to be enabled. + * + * Enables the specified interrupts. This list will override the + * previous interrupts enabled through this function. Caller has to + * maintain the state of the interrupts enabled. To disable all + * interrupts, set ints to 0. + */ + void (*enable_status_interrupts)(struct dsi_ctrl_hw *ctrl, u32 ints); + + /** + * get_error_status() - returns the error status + * @ctrl: Pointer to the controller host hardware. + * + * Returns the ORed list of errors(enum dsi_error_int_type) that are + * active. This list does not include any status interrupts. Caller + * should call get_interrupt_status for status interrupts. + * + * Return: List of active error interrupts. + */ + u64 (*get_error_status)(struct dsi_ctrl_hw *ctrl); + + /** + * clear_error_status() - clears the specified errors + * @ctrl: Pointer to the controller host hardware. + * @errors: List of errors to be cleared. + */ + void (*clear_error_status)(struct dsi_ctrl_hw *ctrl, u64 errors); + + /** + * enable_error_interrupts() - enable the specified interrupts + * @ctrl: Pointer to the controller host hardware. + * @errors: List of errors to be enabled. + * + * Enables the specified interrupts. This list will override the + * previous interrupts enabled through this function. Caller has to + * maintain the state of the interrupts enabled. To disable all + * interrupts, set errors to 0. + */ + void (*enable_error_interrupts)(struct dsi_ctrl_hw *ctrl, u64 errors); + + /** + * video_test_pattern_setup() - setup test pattern engine for video mode + * @ctrl: Pointer to the controller host hardware. + * @type: Type of test pattern. + * @init_val: Initial value to use for generating test pattern. + */ + void (*video_test_pattern_setup)(struct dsi_ctrl_hw *ctrl, + enum dsi_test_pattern type, + u32 init_val); + + /** + * cmd_test_pattern_setup() - setup test patttern engine for cmd mode + * @ctrl: Pointer to the controller host hardware. + * @type: Type of test pattern. + * @init_val: Initial value to use for generating test pattern. + * @stream_id: Stream Id on which packets are generated. + */ + void (*cmd_test_pattern_setup)(struct dsi_ctrl_hw *ctrl, + enum dsi_test_pattern type, + u32 init_val, + u32 stream_id); + + /** + * test_pattern_enable() - enable test pattern engine + * @ctrl: Pointer to the controller host hardware. + * @enable: Enable/Disable test pattern engine. + */ + void (*test_pattern_enable)(struct dsi_ctrl_hw *ctrl, bool enable); + + /** + * clear_phy0_ln_err() - clear DSI PHY lane-0 errors + * @ctrl: Pointer to the controller host hardware. + */ + void (*clear_phy0_ln_err)(struct dsi_ctrl_hw *ctrl); + + /** + * trigger_cmd_test_pattern() - trigger a command mode frame update with + * test pattern + * @ctrl: Pointer to the controller host hardware. + * @stream_id: Stream on which frame update is sent. + */ + void (*trigger_cmd_test_pattern)(struct dsi_ctrl_hw *ctrl, + u32 stream_id); + + ssize_t (*reg_dump_to_buffer)(struct dsi_ctrl_hw *ctrl, + char *buf, + u32 size); + + /** + * setup_misr() - Setup frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + * @enable: Enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + */ + void (*setup_misr)(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode, + bool enable, u32 frame_count); + + /** + * collect_misr() - Read frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + */ + u32 (*collect_misr)(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode); + + /** + * set_timing_db() - enable/disable Timing DB register + * @ctrl: Pointer to controller host hardware. + * @enable: Enable/Disable flag. + * + * Enable or Disabe the Timing DB register. + */ + void (*set_timing_db)(struct dsi_ctrl_hw *ctrl, + bool enable); + /** + * clear_rdbk_register() - Clear and reset read back register + * @ctrl: Pointer to the controller host hardware. + */ + void (*clear_rdbk_register)(struct dsi_ctrl_hw *ctrl); + + /** schedule_dma_cmd() - Schdeule DMA command transfer on a + * particular blanking line. + * @ctrl: Pointer to the controller host hardware. + * @line_no: Blanking line number on whihch DMA command + * needs to be sent. + */ + void (*schedule_dma_cmd)(struct dsi_ctrl_hw *ctrl, int line_no); + + /** + * ctrl_reset() - Reset DSI lanes to recover from DSI errors + * @ctrl: Pointer to the controller host hardware. + * @mask: Indicates the error type. + */ + int (*ctrl_reset)(struct dsi_ctrl_hw *ctrl, int mask); + + /** + * mask_error_int() - Mask/Unmask particular DSI error interrupts + * @ctrl: Pointer to the controller host hardware. + * @idx: Indicates the errors to be masked. + * @en: Bool for mask or unmask of the error + */ + void (*mask_error_intr)(struct dsi_ctrl_hw *ctrl, u32 idx, bool en); + + /** + * error_intr_ctrl() - Mask/Unmask master DSI error interrupt + * @ctrl: Pointer to the controller host hardware. + * @en: Bool for mask or unmask of DSI error + */ + void (*error_intr_ctrl)(struct dsi_ctrl_hw *ctrl, bool en); + + /** + * get_error_mask() - get DSI error interrupt mask status + * @ctrl: Pointer to the controller host hardware. + */ + u32 (*get_error_mask)(struct dsi_ctrl_hw *ctrl); + + /** + * get_hw_version() - get DSI controller hw version + * @ctrl: Pointer to the controller host hardware. + */ + u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl); + + /** + * wait_for_cmd_mode_mdp_idle() - wait for command mode engine not to + * be busy sending data from display engine + * @ctrl: Pointer to the controller host hardware. + */ + int (*wait_for_cmd_mode_mdp_idle)(struct dsi_ctrl_hw *ctrl); + + /** + * hw.ops.set_continuous_clk() - Set continuous clock + * @ctrl: Pointer to the controller host hardware. + * @enable: Bool to control continuous clock request. + */ + void (*set_continuous_clk)(struct dsi_ctrl_hw *ctrl, bool enable); + + /** + * hw.ops.wait4dynamic_refresh_done() - Wait for dynamic refresh done + * @ctrl: Pointer to the controller host hardware. + */ + int (*wait4dynamic_refresh_done)(struct dsi_ctrl_hw *ctrl); + /** + * hw.ops.hs_req_sel() - enable continuous clk support through phy + * @ctrl: Pointer to the controller host hardware. + * @sel_phy: Bool to control whether to select phy or controller + */ + void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy); +}; + +/* + * struct dsi_ctrl_hw - DSI controller hardware object specific to an instance + * @base: VA for the DSI controller base address. + * @length: Length of the DSI controller register map. + * @mmss_misc_base: Base address of mmss_misc register map. + * @mmss_misc_length: Length of mmss_misc register map. + * @disp_cc_base: Base address of disp_cc register map. + * @disp_cc_length: Length of disp_cc register map. + * @index: Instance ID of the controller. + * @feature_map: Features supported by the DSI controller. + * @ops: Function pointers to the operations supported by the + * controller. + * @supported_interrupts: Number of supported interrupts. + * @supported_errors: Number of supported errors. + * @phy_isolation_enabled: A boolean property allows to isolate the phy from + * dsi controller and run only dsi controller. + * @null_insertion_enabled: A boolean property to allow dsi controller to + * insert null packet. + */ +struct dsi_ctrl_hw { + void __iomem *base; + u32 length; + void __iomem *mmss_misc_base; + u32 mmss_misc_length; + void __iomem *disp_cc_base; + u32 disp_cc_length; + u32 index; + + /* features */ + DECLARE_BITMAP(feature_map, DSI_CTRL_MAX_FEATURES); + struct dsi_ctrl_hw_ops ops; + + /* capabilities */ + u32 supported_interrupts; + u64 supported_errors; + + bool phy_isolation_enabled; + bool null_insertion_enabled; +}; + +#endif /* _DSI_CTRL_HW_H_ */ diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw_1_4.c b/techpack/display/msm/dsi/dsi_ctrl_hw_1_4.c new file mode 100644 index 0000000000000000000000000000000000000000..1fa0b51207aa59000bbf0c82e91b8054cbf2f2a7 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl_hw_1_4.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include "dsi_ctrl_hw.h" +#include "dsi_ctrl_reg.h" +#include "dsi_hw.h" + +#define MMSS_MISC_CLAMP_REG_OFF 0x0014 + +/** + * dsi_ctrl_hw_14_setup_lane_map() - setup mapping between + * logical and physical lanes + * @ctrl: Pointer to the controller host hardware. + * @lane_map: Structure defining the mapping between DSI logical + * lanes and physical lanes. + */ +void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl, + struct dsi_lane_map *lane_map) +{ + DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, lane_map->lane_map_v1); + + DSI_CTRL_HW_DBG(ctrl, "Lane swap setup complete\n"); +} + +/** + * dsi_ctrl_hw_14_wait_for_lane_idle() + * This function waits for all the active DSI lanes to be idle by polling all + * the FIFO_EMPTY bits and polling he lane status to ensure that all the lanes + * are in stop state. This function assumes that the bus clocks required to + * access the registers are already turned on. + * + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to be stopped. + * + * return: Error code. + */ +int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes) +{ + int rc = 0, val = 0; + u32 stop_state_mask = 0, fifo_empty_mask = 0; + u32 const sleep_us = 10; + u32 const timeout_us = 100; + + if (lanes & DSI_DATA_LANE_0) { + stop_state_mask |= BIT(0); + fifo_empty_mask |= (BIT(12) | BIT(16)); + } + if (lanes & DSI_DATA_LANE_1) { + stop_state_mask |= BIT(1); + fifo_empty_mask |= BIT(20); + } + if (lanes & DSI_DATA_LANE_2) { + stop_state_mask |= BIT(2); + fifo_empty_mask |= BIT(24); + } + if (lanes & DSI_DATA_LANE_3) { + stop_state_mask |= BIT(3); + fifo_empty_mask |= BIT(28); + } + + DSI_CTRL_HW_DBG(ctrl, "polling for fifo empty, mask=0x%08x\n", + fifo_empty_mask); + rc = readl_poll_timeout(ctrl->base + DSI_FIFO_STATUS, val, + (val & fifo_empty_mask), sleep_us, timeout_us); + if (rc) { + DSI_CTRL_HW_ERR(ctrl, "fifo not empty, FIFO_STATUS=0x%08x\n", + val); + goto error; + } + + DSI_CTRL_HW_DBG(ctrl, "polling for lanes to be in stop state, mask=0x%08x\n", + stop_state_mask); + rc = readl_poll_timeout(ctrl->base + DSI_LANE_STATUS, val, + (val & stop_state_mask), sleep_us, timeout_us); + if (rc) { + DSI_CTRL_HW_ERR(ctrl, "lanes not in stop state, LANE_STATUS=0x%08x\n", + val); + goto error; + } + +error: + return rc; + +} + +/** + * ulps_request() - request ulps entry for specified lanes + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to enter ULPS. + * + * Caller should check if lanes are in ULPS mode by calling + * get_lanes_in_ulps() operation. + */ +void dsi_ctrl_hw_cmn_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_LANE_CTRL); + + if (lanes & DSI_CLOCK_LANE) + reg |= BIT(4); + if (lanes & DSI_DATA_LANE_0) + reg |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + reg |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + reg |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + reg |= BIT(3); + + /* + * ULPS entry request. Wait for short time to make sure + * that the lanes enter ULPS. Recommended as per HPG. + */ + DSI_W32(ctrl, DSI_LANE_CTRL, reg); + usleep_range(100, 110); + + DSI_CTRL_HW_DBG(ctrl, "ULPS requested for lanes 0x%x\n", lanes); +} + +/** + * ulps_exit() - exit ULPS on specified lanes + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to exit ULPS. + * + * Caller should check if lanes are in active mode by calling + * get_lanes_in_ulps() operation. + */ +void dsi_ctrl_hw_cmn_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes) +{ + u32 reg = 0; + u32 prev_reg = 0; + + prev_reg = DSI_R32(ctrl, DSI_LANE_CTRL); + prev_reg &= BIT(24); + + if (lanes & DSI_CLOCK_LANE) + reg |= BIT(12); + if (lanes & DSI_DATA_LANE_0) + reg |= BIT(8); + if (lanes & DSI_DATA_LANE_1) + reg |= BIT(9); + if (lanes & DSI_DATA_LANE_2) + reg |= BIT(10); + if (lanes & DSI_DATA_LANE_3) + reg |= BIT(11); + + /* + * ULPS Exit Request + * Hardware requirement is to wait for at least 1ms + */ + DSI_W32(ctrl, DSI_LANE_CTRL, reg | prev_reg); + usleep_range(1000, 1010); + /* + * Sometimes when exiting ULPS, it is possible that some DSI + * lanes are not in the stop state which could lead to DSI + * commands not going through. To avoid this, force the lanes + * to be in stop state. + */ + DSI_W32(ctrl, DSI_LANE_CTRL, (reg << 8) | prev_reg); + wmb(); /* ensure lanes are put to stop state */ + DSI_W32(ctrl, DSI_LANE_CTRL, 0x0 | prev_reg); + wmb(); /* ensure lanes are put to stop state */ + + DSI_CTRL_HW_DBG(ctrl, "ULPS exit request for lanes=0x%x\n", lanes); +} + +/** + * get_lanes_in_ulps() - returns the list of lanes in ULPS mode + * @ctrl: Pointer to the controller host hardware. + * + * Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS + * state. If 0 is returned, all the lanes are active. + * + * Return: List of lanes in ULPS state. + */ +u32 dsi_ctrl_hw_cmn_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + u32 lanes = 0; + + reg = DSI_R32(ctrl, DSI_LANE_STATUS); + if (!(reg & BIT(8))) + lanes |= DSI_DATA_LANE_0; + if (!(reg & BIT(9))) + lanes |= DSI_DATA_LANE_1; + if (!(reg & BIT(10))) + lanes |= DSI_DATA_LANE_2; + if (!(reg & BIT(11))) + lanes |= DSI_DATA_LANE_3; + if (!(reg & BIT(12))) + lanes |= DSI_CLOCK_LANE; + + DSI_CTRL_HW_DBG(ctrl, "lanes in ulps = 0x%x\n", lanes); + return lanes; +} + +/** + * clamp_enable() - enable DSI clamps to keep PHY driving a stable link + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes which need to be clamped. + * @enable_ulps: Boolean to specify if ULPS is enabled in DSI controller + */ +void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl, + u32 lanes, + bool enable_ulps) +{ + u32 clamp_reg = 0; + u32 bit_shift = 0; + u32 reg = 0; + + if (ctrl->index == 1) + bit_shift = 16; + + if (lanes & DSI_CLOCK_LANE) { + clamp_reg |= BIT(9); + if (enable_ulps) + clamp_reg |= BIT(8); + } + + if (lanes & DSI_DATA_LANE_0) { + clamp_reg |= BIT(7); + if (enable_ulps) + clamp_reg |= BIT(6); + } + + if (lanes & DSI_DATA_LANE_1) { + clamp_reg |= BIT(5); + if (enable_ulps) + clamp_reg |= BIT(4); + } + + if (lanes & DSI_DATA_LANE_2) { + clamp_reg |= BIT(3); + if (enable_ulps) + clamp_reg |= BIT(2); + } + + if (lanes & DSI_DATA_LANE_3) { + clamp_reg |= BIT(1); + if (enable_ulps) + clamp_reg |= BIT(0); + } + + reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); + reg |= (clamp_reg << bit_shift); + DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); + + reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); + reg |= (BIT(15) << bit_shift); /* Enable clamp */ + DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); + + DSI_CTRL_HW_DBG(ctrl, "Clamps enabled for lanes=0x%x\n", lanes); +} + +/** + * clamp_disable() - disable DSI clamps + * @ctrl: Pointer to the controller host hardware. + * @lanes: ORed list of lanes which need to have clamps released. + * @disable_ulps: Boolean to specify if ULPS is enabled in DSI controller + */ +void dsi_ctrl_hw_14_clamp_disable(struct dsi_ctrl_hw *ctrl, + u32 lanes, + bool disable_ulps) +{ + u32 clamp_reg = 0; + u32 bit_shift = 0; + u32 reg = 0; + + if (ctrl->index == 1) + bit_shift = 16; + + if (lanes & DSI_CLOCK_LANE) { + clamp_reg |= BIT(9); + if (disable_ulps) + clamp_reg |= BIT(8); + } + + if (lanes & DSI_DATA_LANE_0) { + clamp_reg |= BIT(7); + if (disable_ulps) + clamp_reg |= BIT(6); + } + + if (lanes & DSI_DATA_LANE_1) { + clamp_reg |= BIT(5); + if (disable_ulps) + clamp_reg |= BIT(4); + } + + if (lanes & DSI_DATA_LANE_2) { + clamp_reg |= BIT(3); + if (disable_ulps) + clamp_reg |= BIT(2); + } + + if (lanes & DSI_DATA_LANE_3) { + clamp_reg |= BIT(1); + if (disable_ulps) + clamp_reg |= BIT(0); + } + + clamp_reg |= BIT(15); /* Enable clamp */ + clamp_reg <<= bit_shift; + + reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); + reg &= ~(clamp_reg); + DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); + + DSI_CTRL_HW_DBG(ctrl, "Disable clamps for lanes=%d\n", lanes); +} + +#define DUMP_REG_VALUE(off) "\t%-30s: 0x%08x\n", #off, DSI_R32(ctrl, off) +ssize_t dsi_ctrl_hw_14_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, + char *buf, + u32 size) +{ + u32 len = 0; + + len += snprintf((buf + len), (size - len), "CONFIGURATION REGS:\n"); + + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_HW_VERSION)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_FIFO_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_SYNC_DATATYPE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_PIXEL_DATATYPE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_BLANKING_DATATYPE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_DATA_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_H)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_V)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_HSYNC)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC_VPOS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_DMA_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_CMD_OFFSET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_CMD_LENGTH)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_FIFO_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_NULL_PACKET_DATA)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_ACK_ERR_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA0)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA1)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA2)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA3)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATATYPE0)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATATYPE1)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TRIG_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EXT_MUX)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EXT_MUX_TE_PULSE_DETECT_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CMD_MODE_DMA_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CMD_MODE_MDP_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CMD_MODE_BTA_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LANE_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LANE_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LANE_SWAP_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DLN0_PHY_ERR)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LP_TIMER_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_HS_TIMER_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TIMEOUT_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CLKOUT_TIMING_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EOT_PACKET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EOT_PACKET_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_GENERIC_ESC_TX_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_ERR_INT_MASK0)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_INT_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_SOFT_RESET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CLK_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CLK_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_PHY_SW_RESET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_AXI2AHB_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VBIF_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_AES_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_WRITE_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DSI_TIMING_FLUSH)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DSI_TIMING_DB_MODE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_RESET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VERSION)); + + DSI_CTRL_HW_ERR(ctrl, "LLENGTH = %d\n", len); + return len; +} diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw_2_0.c b/techpack/display/msm/dsi/dsi_ctrl_hw_2_0.c new file mode 100644 index 0000000000000000000000000000000000000000..3af3225d77bda4d31a6aa5a08e8cd40a63a2758b --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl_hw_2_0.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include "dsi_ctrl_hw.h" +#include "dsi_ctrl_reg.h" +#include "dsi_hw.h" + +void dsi_ctrl_hw_20_setup_lane_map(struct dsi_ctrl_hw *ctrl, + struct dsi_lane_map *lane_map) +{ + u32 reg_value = lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4) | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] << 8) | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 12); + + DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, reg_value); + + DSI_CTRL_HW_DBG(ctrl, "Lane swap setup complete\n"); +} + +int dsi_ctrl_hw_20_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, + u32 lanes) +{ + int rc = 0, val = 0; + u32 fifo_empty_mask = 0; + u32 const sleep_us = 10; + u32 const timeout_us = 100; + + if (lanes & DSI_DATA_LANE_0) + fifo_empty_mask |= (BIT(12) | BIT(16)); + + if (lanes & DSI_DATA_LANE_1) + fifo_empty_mask |= BIT(20); + + if (lanes & DSI_DATA_LANE_2) + fifo_empty_mask |= BIT(24); + + if (lanes & DSI_DATA_LANE_3) + fifo_empty_mask |= BIT(28); + + DSI_CTRL_HW_DBG(ctrl, "polling for fifo empty, mask=0x%08x\n", + fifo_empty_mask); + rc = readl_poll_timeout(ctrl->base + DSI_FIFO_STATUS, val, + (val & fifo_empty_mask), sleep_us, timeout_us); + if (rc) { + DSI_CTRL_HW_ERR(ctrl, "fifo not empty, FIFO_STATUS=0x%08x\n", + val); + goto error; + } + +error: + return rc; +} + +#define DUMP_REG_VALUE(off) "\t%-30s: 0x%08x\n", #off, DSI_R32(ctrl, off) +ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl, + char *buf, + u32 size) +{ + u32 len = 0; + + len += snprintf((buf + len), (size - len), "CONFIGURATION REGS:\n"); + + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_HW_VERSION)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_FIFO_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_SYNC_DATATYPE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_PIXEL_DATATYPE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_BLANKING_DATATYPE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_DATA_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_H)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_V)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_HSYNC)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC_VPOS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_DMA_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_CMD_OFFSET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_CMD_LENGTH)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_FIFO_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DMA_NULL_PACKET_DATA)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_ACK_ERR_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA0)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA1)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA2)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA3)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATATYPE0)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATATYPE1)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TRIG_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EXT_MUX)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EXT_MUX_TE_PULSE_DETECT_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CMD_MODE_DMA_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CMD_MODE_MDP_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CMD_MODE_BTA_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_CMD_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_VIDEO_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LANE_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LANE_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LANE_SWAP_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DLN0_PHY_ERR)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_LP_TIMER_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_HS_TIMER_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TIMEOUT_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CLKOUT_TIMING_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EOT_PACKET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_EOT_PACKET_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_GENERIC_ESC_TX_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_ERR_INT_MASK0)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_INT_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_SOFT_RESET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CLK_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_CLK_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_PHY_SW_RESET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_AXI2AHB_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_CMD_MDP0_32BIT)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_CMD_MDP1_32BIT)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_MISR_VIDEO_32BIT)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_TOTAL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VBIF_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_AES_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_RDBK_DATA_CTRL)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_STATUS)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_WRITE_TRIGGER)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DSI_TIMING_FLUSH)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_DSI_TIMING_DB_MODE)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_RESET)); + len += snprintf((buf + len), (size - len), + DUMP_REG_VALUE(DSI_VERSION)); + + DSI_CTRL_HW_ERR(ctrl, "LLENGTH = %d\n", len); + return len; +} diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c b/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c new file mode 100644 index 0000000000000000000000000000000000000000..0c6d3404a268fcdb469a76b8b43c901af9b1c896 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "dsi_ctrl_hw.h" +#include "dsi_ctrl_reg.h" +#include "dsi_hw.h" +#include "dsi_catalog.h" + +#define DISP_CC_MISC_CMD_REG_OFF 0x00 + +/* register to configure DMA scheduling */ +#define DSI_DMA_SCHEDULE_CTRL 0x100 + +/** + * dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps + * @ctrl: Pointer to the controller host hardware. + * @enable: boolean to specify enable/disable. + */ +void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl, + bool enable) +{ + u32 reg = 0; + + reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF); + + /* Mask/unmask disable PHY reset bit */ + if (enable) + reg &= ~BIT(ctrl->index); + else + reg |= BIT(ctrl->index); + DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg); +} + +/** + * dsi_ctrl_hw_22_schedule_dma_cmd() - to schedule DMA command transfer + * @ctrl: Pointer to the controller host hardware. + * @line_no: Line number at which command needs to be sent. + */ +void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_no) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_DMA_SCHEDULE_CTRL); + reg |= BIT(28); + reg |= (line_no & 0xffff); + + DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, reg); +} + +/* + * dsi_ctrl_hw_kickoff_non_embedded_mode()-Kickoff cmd in non-embedded mode + * @ctrl: - Pointer to the controller host hardware. + * @dsi_ctrl_cmd_dma_info: - command buffer information. + * @flags: - DSI CTRL Flags. + */ +void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL); + + reg &= ~BIT(31);/* disable broadcast */ + reg &= ~BIT(30); + + if (cmd->use_lpm) + reg |= BIT(26); + else + reg &= ~BIT(26); + + /* Select non EMBEDDED_MODE, pick the packet header from register */ + reg &= ~BIT(28); + reg |= BIT(24);/* long packet */ + reg |= BIT(29);/* wc_sel = 1 */ + reg |= (((cmd->datatype) & 0x03f) << 16);/* data type */ + DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); + + /* Enable WRITE_WATERMARK_DISABLE and READ_WATERMARK_DISABLE bits */ + reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL); + reg |= BIT(20); + reg |= BIT(16); + reg |= 0x33;/* Set READ and WRITE watermark levels to maximum */ + DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg); + + DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset); + DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, ((cmd->length) & 0xFFFFFF)); + + /* wait for writes to complete before kick off */ + wmb(); + + if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) + DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); +} + +/* + * dsi_ctrl_hw_22_config_clk_gating() - enable/disable clk gating on DSI PHY + * @ctrl: Pointer to the controller host hardware. + * @enable: bool to notify enable/disable. + * @clk_selection: clock to enable/disable clock gating. + * + */ +void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable, + enum dsi_clk_gate_type clk_selection) +{ + u32 reg = 0; + u32 enable_select = 0; + + reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF); + + if (clk_selection & PIXEL_CLK) + enable_select |= ctrl->index ? BIT(6) : BIT(5); + + if (clk_selection & BYTE_CLK) + enable_select |= ctrl->index ? BIT(8) : BIT(7); + + if (clk_selection & DSI_PHY) + enable_select |= ctrl->index ? BIT(10) : BIT(9); + + if (enable) + reg |= enable_select; + else + reg &= ~enable_select; + + DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg); +} diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c b/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c new file mode 100644 index 0000000000000000000000000000000000000000..caa1f86591c58cc07487ff1a2b7af651e9e7356e --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c @@ -0,0 +1,1622 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include "dsi_catalog.h" +#include "dsi_ctrl_hw.h" +#include "dsi_ctrl_reg.h" +#include "dsi_hw.h" +#include "dsi_panel.h" +#include "dsi_catalog.h" +#include "sde_dbg.h" + +#define MMSS_MISC_CLAMP_REG_OFF 0x0014 +#define DSI_CTRL_DYNAMIC_FORCE_ON (0x23F|BIT(8)|BIT(9)|BIT(11)|BIT(21)) +#define DSI_CTRL_CMD_MISR_ENABLE BIT(28) +#define DSI_CTRL_VIDEO_MISR_ENABLE BIT(16) +#define DSI_CTRL_DMA_LINK_SEL (BIT(12)|BIT(13)) +#define DSI_CTRL_MDP0_LINK_SEL (BIT(20)|BIT(22)) + +/* Unsupported formats default to RGB888 */ +static const u8 cmd_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { + 0x6, 0x7, 0x8, 0x8, 0x0, 0x3, 0x4 }; +static const u8 video_mode_format_map[DSI_PIXEL_FORMAT_MAX] = { + 0x0, 0x1, 0x2, 0x3, 0x3, 0x3, 0x3 }; + +/** + * dsi_split_link_setup() - setup dsi split link configurations + * @ctrl: Pointer to the controller host hardware. + * @cfg: DSI host configuration that is common to both video and + * command modes. + */ +static void dsi_split_link_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg) +{ + u32 reg; + + if (!cfg->split_link.split_link_enabled) + return; + + reg = DSI_R32(ctrl, DSI_SPLIT_LINK); + + /* DMA_LINK_SEL */ + reg &= ~(0x7 << 12); + reg |= DSI_CTRL_DMA_LINK_SEL; + + /* MDP0_LINK_SEL */ + reg &= ~(0x7 << 20); + reg |= DSI_CTRL_MDP0_LINK_SEL; + + /* EN */ + reg |= 0x1; + + /* DSI_SPLIT_LINK */ + DSI_W32(ctrl, DSI_SPLIT_LINK, reg); + wmb(); /* make sure split link is asserted */ +} + +/** + * dsi_setup_trigger_controls() - setup dsi trigger configurations + * @ctrl: Pointer to the controller host hardware. + * @cfg: DSI host configuration that is common to both video and + * command modes. + */ +static void dsi_setup_trigger_controls(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg) +{ + u32 reg = 0; + const u8 trigger_map[DSI_TRIGGER_MAX] = { + 0x0, 0x2, 0x1, 0x4, 0x5, 0x6 }; + + reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0; + reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7); + reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4; + DSI_W32(ctrl, DSI_TRIG_CTRL, reg); +} + +/** + * dsi_ctrl_hw_cmn_host_setup() - setup dsi host configuration + * @ctrl: Pointer to the controller host hardware. + * @cfg: DSI host configuration that is common to both video and + * command modes. + */ +void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *cfg) +{ + u32 reg_value = 0; + + dsi_setup_trigger_controls(ctrl, cfg); + dsi_split_link_setup(ctrl, cfg); + + /* Setup T_CLK_PRE extend register */ + reg_value = DSI_R32(ctrl, DSI_TEST_PATTERN_GEN_VIDEO_ENABLE); + if (cfg->t_clk_pre_extend) + reg_value |= BIT(0); + else + reg_value &= ~BIT(0); + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_VIDEO_ENABLE, reg_value); + + /* Setup clocking timing controls */ + reg_value = ((cfg->t_clk_post & 0x3F) << 8); + reg_value |= (cfg->t_clk_pre & 0x3F); + DSI_W32(ctrl, DSI_CLKOUT_TIMING_CTRL, reg_value); + + /* EOT packet control */ + reg_value = cfg->append_tx_eot ? 1 : 0; + reg_value |= (cfg->ignore_rx_eot ? (1 << 4) : 0); + DSI_W32(ctrl, DSI_EOT_PACKET_CTRL, reg_value); + + /* Turn on dsi clocks */ + DSI_W32(ctrl, DSI_CLK_CTRL, 0x23F); + + /* Setup DSI control register */ + reg_value = DSI_R32(ctrl, DSI_CTRL); + reg_value |= (cfg->en_crc_check ? BIT(24) : 0); + reg_value |= (cfg->en_ecc_check ? BIT(20) : 0); + reg_value |= BIT(8); /* Clock lane */ + reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_3) ? BIT(7) : 0); + reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_2) ? BIT(6) : 0); + reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_1) ? BIT(5) : 0); + reg_value |= ((cfg->data_lanes & DSI_DATA_LANE_0) ? BIT(4) : 0); + + DSI_W32(ctrl, DSI_CTRL, reg_value); + + if (cfg->phy_type == DSI_PHY_TYPE_CPHY) + DSI_W32(ctrl, DSI_CPHY_MODE_CTRL, BIT(0)); + + if (ctrl->phy_isolation_enabled) + DSI_W32(ctrl, DSI_DEBUG_CTRL, BIT(28)); + DSI_CTRL_HW_DBG(ctrl, "Host configuration complete\n"); +} + +/** + * phy_sw_reset() - perform a soft reset on the PHY. + * @ctrl: Pointer to the controller host hardware. + */ +void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl) +{ + DSI_W32(ctrl, DSI_PHY_SW_RESET, BIT(24)|BIT(0)); + wmb(); /* make sure reset is asserted */ + udelay(1000); + DSI_W32(ctrl, DSI_PHY_SW_RESET, 0x0); + wmb(); /* ensure reset is cleared before waiting */ + udelay(100); + + DSI_CTRL_HW_DBG(ctrl, "phy sw reset done\n"); +} + +/** + * soft_reset() - perform a soft reset on DSI controller + * @ctrl: Pointer to the controller host hardware. + * + * The video, command and controller engines will be disabled before the + * reset is triggered and re-enabled after the reset is complete. + * + * If the reset is done while MDP timing engine is turned on, the video + * enigne should be re-enabled only during the vertical blanking time. + */ +void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + u32 reg_ctrl = 0; + + /* Clear DSI_EN, VIDEO_MODE_EN, CMD_MODE_EN */ + reg_ctrl = DSI_R32(ctrl, DSI_CTRL); + DSI_W32(ctrl, DSI_CTRL, reg_ctrl & ~0x7); + wmb(); /* wait controller to be disabled before reset */ + + /* Force enable PCLK, BYTECLK, AHBM_HCLK */ + reg = DSI_R32(ctrl, DSI_CLK_CTRL); + DSI_W32(ctrl, DSI_CLK_CTRL, reg | DSI_CTRL_DYNAMIC_FORCE_ON); + wmb(); /* wait for clocks to be enabled */ + + /* Trigger soft reset */ + DSI_W32(ctrl, DSI_SOFT_RESET, 0x1); + wmb(); /* wait for reset to assert before waiting */ + udelay(1); + DSI_W32(ctrl, DSI_SOFT_RESET, 0x0); + wmb(); /* ensure reset is cleared */ + + /* Disable force clock on */ + DSI_W32(ctrl, DSI_CLK_CTRL, reg); + wmb(); /* make sure clocks are restored */ + + /* Re-enable DSI controller */ + DSI_W32(ctrl, DSI_CTRL, reg_ctrl); + wmb(); /* make sure DSI controller is enabled again */ + DSI_CTRL_HW_DBG(ctrl, "ctrl soft reset done\n"); + SDE_EVT32(ctrl->index); +} + +/** + * setup_misr() - Setup frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + * @enable: Enable/disable MISR. + * @frame_count: Number of frames to accumulate MISR. + */ +void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode, + bool enable, + u32 frame_count) +{ + u32 addr; + u32 config = 0; + + if (panel_mode == DSI_OP_CMD_MODE) { + addr = DSI_MISR_CMD_CTRL; + if (enable) + config = DSI_CTRL_CMD_MISR_ENABLE; + } else { + addr = DSI_MISR_VIDEO_CTRL; + if (enable) + config = DSI_CTRL_VIDEO_MISR_ENABLE; + if (frame_count > 255) + frame_count = 255; + config |= frame_count << 8; + } + + DSI_CTRL_HW_DBG(ctrl, "MISR ctrl: 0x%x\n", config); + DSI_W32(ctrl, addr, config); + wmb(); /* make sure MISR is configured */ +} + +/** + * collect_misr() - Read frame MISR + * @ctrl: Pointer to the controller host hardware. + * @panel_mode: CMD or VIDEO mode indicator + */ +u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl, + enum dsi_op_mode panel_mode) +{ + u32 addr; + u32 enabled; + u32 misr = 0; + + if (panel_mode == DSI_OP_CMD_MODE) { + addr = DSI_MISR_CMD_MDP0_32BIT; + enabled = DSI_R32(ctrl, DSI_MISR_CMD_CTRL) & + DSI_CTRL_CMD_MISR_ENABLE; + } else { + addr = DSI_MISR_VIDEO_32BIT; + enabled = DSI_R32(ctrl, DSI_MISR_VIDEO_CTRL) & + DSI_CTRL_VIDEO_MISR_ENABLE; + } + + if (enabled) + misr = DSI_R32(ctrl, addr); + + DSI_CTRL_HW_DBG(ctrl, "MISR enabled %x value: 0x%x\n", enabled, misr); + return misr; +} + +/** + * set_timing_db() - enable/disable Timing DB register + * @ctrl: Pointer to controller host hardware. + * @enable: Enable/Disable flag. + * + * Enable or Disabe the Timing DB register. + */ +void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl, + bool enable) +{ + if (enable) + DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x1); + else + DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x0); + + wmb(); /* make sure timing db registers are set */ + DSI_CTRL_HW_DBG(ctrl, "ctrl timing DB set:%d\n", enable); + SDE_EVT32(ctrl->index, enable); +} + +/** + * set_video_timing() - set up the timing for video frame + * @ctrl: Pointer to controller host hardware. + * @mode: Video mode information. + * + * Set up the video timing parameters for the DSI video mode operation. + */ +void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl, + struct dsi_mode_info *mode) +{ + u32 reg = 0; + u32 hs_start = 0; + u32 hs_end, active_h_start, active_h_end, h_total, width = 0; + u32 vs_start = 0, vs_end = 0; + u32 vpos_start = 0, vpos_end, active_v_start, active_v_end, v_total; + + if (mode->dsc_enabled && mode->dsc) { + width = mode->dsc->pclk_per_line; + reg = mode->dsc->bytes_per_pkt << 16; + reg |= (0x0b << 8); /* dtype of compressed image */ + /* + * pkt_per_line: + * 0 == 1 pkt + * 1 == 2 pkt + * 2 == 4 pkt + * 3 pkt is not support + */ + if (mode->dsc->pkt_per_line == 4) + reg |= (mode->dsc->pkt_per_line - 2) << 6; + else + reg |= (mode->dsc->pkt_per_line - 1) << 6; + reg |= mode->dsc->eol_byte_num << 4; + reg |= 1; + DSI_W32(ctrl, DSI_VIDEO_COMPRESSION_MODE_CTRL, reg); + } else { + width = mode->h_active; + } + + hs_end = mode->h_sync_width; + active_h_start = mode->h_sync_width + mode->h_back_porch; + active_h_end = active_h_start + width; + h_total = (mode->h_sync_width + mode->h_back_porch + width + + mode->h_front_porch) - 1; + + vpos_end = mode->v_sync_width; + active_v_start = mode->v_sync_width + mode->v_back_porch; + active_v_end = active_v_start + mode->v_active; + v_total = (mode->v_sync_width + mode->v_back_porch + mode->v_active + + mode->v_front_porch) - 1; + + reg = ((active_h_end & 0xFFFF) << 16) | (active_h_start & 0xFFFF); + DSI_W32(ctrl, DSI_VIDEO_MODE_ACTIVE_H, reg); + + reg = ((active_v_end & 0xFFFF) << 16) | (active_v_start & 0xFFFF); + DSI_W32(ctrl, DSI_VIDEO_MODE_ACTIVE_V, reg); + + reg = ((v_total & 0xFFFF) << 16) | (h_total & 0xFFFF); + DSI_W32(ctrl, DSI_VIDEO_MODE_TOTAL, reg); + + reg = ((hs_end & 0xFFFF) << 16) | (hs_start & 0xFFFF); + DSI_W32(ctrl, DSI_VIDEO_MODE_HSYNC, reg); + + reg = ((vs_end & 0xFFFF) << 16) | (vs_start & 0xFFFF); + DSI_W32(ctrl, DSI_VIDEO_MODE_VSYNC, reg); + + reg = ((vpos_end & 0xFFFF) << 16) | (vpos_start & 0xFFFF); + DSI_W32(ctrl, DSI_VIDEO_MODE_VSYNC_VPOS, reg); + + /* TODO: HS TIMER value? */ + DSI_W32(ctrl, DSI_HS_TIMER_CTRL, 0x3FD08); + DSI_W32(ctrl, DSI_MISR_VIDEO_CTRL, 0x10100); + DSI_W32(ctrl, DSI_DSI_TIMING_FLUSH, 0x1); + DSI_CTRL_HW_DBG(ctrl, "ctrl video parameters updated\n"); + SDE_EVT32(v_total, h_total); +} + +/** + * setup_cmd_stream() - set up parameters for command pixel streams + * @ctrl: Pointer to controller host hardware. + * @mode: Pointer to mode information. + * @h_stride: Horizontal stride in bytes. + * @vc_id: stream_id + * + * Setup parameters for command mode pixel stream size. + */ +void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl, + struct dsi_mode_info *mode, + u32 h_stride, + u32 vc_id, + struct dsi_rect *roi) +{ + u32 width_final, stride_final; + u32 height_final; + u32 stream_total = 0, stream_ctrl = 0; + u32 reg_ctrl = 0, reg_ctrl2 = 0, data = 0; + + if (roi && (!roi->w || !roi->h)) + return; + + if (mode->dsc_enabled && mode->dsc) { + u32 reg = 0; + u32 offset = 0; + int pic_width, this_frame_slices, intf_ip_w; + struct msm_display_dsc_info dsc; + + memcpy(&dsc, mode->dsc, sizeof(dsc)); + pic_width = roi ? roi->w : mode->h_active; + this_frame_slices = pic_width / dsc.slice_width; + intf_ip_w = this_frame_slices * dsc.slice_width; + dsi_dsc_pclk_param_calc(&dsc, intf_ip_w); + + if (vc_id != 0) + offset = 16; + reg_ctrl = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL); + reg_ctrl2 = DSI_R32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2); + width_final = dsc.pclk_per_line; + stride_final = dsc.bytes_per_pkt; + height_final = roi ? roi->h : mode->v_active; + + reg = 0x39 << 8; + /* + * pkt_per_line: + * 0 == 1 pkt + * 1 == 2 pkt + * 2 == 4 pkt + * 3 pkt is not support + */ + if (dsc.pkt_per_line == 4) + reg |= (dsc.pkt_per_line - 2) << 6; + else + reg |= (dsc.pkt_per_line - 1) << 6; + reg |= dsc.eol_byte_num << 4; + reg |= 1; + + reg_ctrl &= ~(0xFFFF << offset); + reg_ctrl |= (reg << offset); + reg_ctrl2 &= ~(0xFFFF << offset); + reg_ctrl2 |= (dsc.bytes_in_slice << offset); + + DSI_CTRL_HW_DBG(ctrl, "reg_ctrl 0x%x reg_ctrl2 0x%x\n", + reg_ctrl, reg_ctrl2); + } else if (roi) { + width_final = roi->w; + stride_final = roi->w * 3; + height_final = roi->h; + } else { + width_final = mode->h_active; + stride_final = h_stride; + height_final = mode->v_active; + } + + /* HS Timer value */ + DSI_W32(ctrl, DSI_HS_TIMER_CTRL, 0x3FD08); + + stream_ctrl = (stride_final + 1) << 16; + stream_ctrl |= (vc_id & 0x3) << 8; + stream_ctrl |= 0x39; /* packet data type */ + + DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL, reg_ctrl); + DSI_W32(ctrl, DSI_COMMAND_COMPRESSION_MODE_CTRL2, reg_ctrl2); + + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_CTRL, stream_ctrl); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_CTRL, stream_ctrl); + + stream_total = (height_final << 16) | width_final; + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM0_TOTAL, stream_total); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_STREAM1_TOTAL, stream_total); + + if (ctrl->null_insertion_enabled) { + /* enable null packet insertion */ + data = (vc_id << 1); + data |= 0 << 16; + data |= 0x1; + DSI_W32(ctrl, DSI_COMMAND_MODE_NULL_INSERTION_CTRL, data); + } + + DSI_CTRL_HW_DBG(ctrl, "stream_ctrl 0x%x stream_total 0x%x\n", + stream_ctrl, stream_total); +} + +/** + * setup_avr() - set the AVR_SUPPORT_ENABLE bit in DSI_VIDEO_MODE_CTRL + * @ctrl: Pointer to controller host hardware. + * @enable: Controls whether this bit is set or cleared + * + * Set or clear the AVR_SUPPORT_ENABLE bit in DSI_VIDEO_MODE_CTRL. + */ +void dsi_ctrl_hw_cmn_setup_avr(struct dsi_ctrl_hw *ctrl, bool enable) +{ + u32 reg = DSI_R32(ctrl, DSI_VIDEO_MODE_CTRL); + + if (enable) + reg |= BIT(29); + else + reg &= ~BIT(29); + + DSI_W32(ctrl, DSI_VIDEO_MODE_CTRL, reg); + DSI_CTRL_HW_DBG(ctrl, "AVR %s\n", enable ? "enabled" : "disabled"); +} + +/** + * video_engine_setup() - Setup dsi host controller for video mode + * @ctrl: Pointer to controller host hardware. + * @common_cfg: Common configuration parameters. + * @cfg: Video mode configuration. + * + * Set up DSI video engine with a specific configuration. Controller and + * video engine are not enabled as part of this function. + */ +void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *common_cfg, + struct dsi_video_engine_cfg *cfg) +{ + u32 reg = 0; + + reg |= (cfg->last_line_interleave_en ? BIT(31) : 0); + reg |= (cfg->pulse_mode_hsa_he ? BIT(28) : 0); + reg |= (cfg->hfp_lp11_en ? BIT(24) : 0); + reg |= (cfg->hbp_lp11_en ? BIT(20) : 0); + reg |= (cfg->hsa_lp11_en ? BIT(16) : 0); + reg |= (cfg->eof_bllp_lp11_en ? BIT(15) : 0); + reg |= (cfg->bllp_lp11_en ? BIT(12) : 0); + reg |= (cfg->traffic_mode & 0x3) << 8; + reg |= (cfg->vc_id & 0x3); + reg |= (video_mode_format_map[common_cfg->dst_format] & 0x3) << 4; + DSI_W32(ctrl, DSI_VIDEO_MODE_CTRL, reg); + + reg = (common_cfg->swap_mode & 0x7) << 12; + reg |= (common_cfg->bit_swap_red ? BIT(0) : 0); + reg |= (common_cfg->bit_swap_green ? BIT(4) : 0); + reg |= (common_cfg->bit_swap_blue ? BIT(8) : 0); + DSI_W32(ctrl, DSI_VIDEO_MODE_DATA_CTRL, reg); + /* Disable Timing double buffering */ + DSI_W32(ctrl, DSI_DSI_TIMING_DB_MODE, 0x0); + + DSI_CTRL_HW_DBG(ctrl, "Video engine setup done\n"); +} + +void dsi_ctrl_hw_cmn_debug_bus(struct dsi_ctrl_hw *ctrl, u32 *entries, u32 size) +{ + u32 reg = 0, i = 0; + + for (i = 0; i < size; i++) { + DSI_W32(ctrl, DSI_DEBUG_BUS_CTL, entries[i]); + /* make sure that debug test point is enabled */ + wmb(); + reg = DSI_R32(ctrl, DSI_DEBUG_BUS_STATUS); + DSI_CTRL_HW_INFO(ctrl, "debug bus ctrl: 0x%x status:0x%x\n", + entries[i], reg); + } +} + +/** + * cmd_engine_setup() - setup dsi host controller for command mode + * @ctrl: Pointer to the controller host hardware. + * @common_cfg: Common configuration parameters. + * @cfg: Command mode configuration. + * + * Setup DSI CMD engine with a specific configuration. Controller and + * command engine are not enabled as part of this function. + */ +void dsi_ctrl_hw_cmn_cmd_engine_setup(struct dsi_ctrl_hw *ctrl, + struct dsi_host_common_cfg *common_cfg, + struct dsi_cmd_engine_cfg *cfg) +{ + u32 reg = 0; + + reg = (cfg->max_cmd_packets_interleave & 0xF) << 20; + reg |= (common_cfg->bit_swap_red ? BIT(4) : 0); + reg |= (common_cfg->bit_swap_green ? BIT(8) : 0); + reg |= (common_cfg->bit_swap_blue ? BIT(12) : 0); + reg |= cmd_mode_format_map[common_cfg->dst_format]; + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL, reg); + + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2); + reg |= BIT(16); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_CTRL2, reg); + + reg = cfg->wr_mem_start & 0xFF; + reg |= (cfg->wr_mem_continue & 0xFF) << 8; + reg |= (cfg->insert_dcs_command ? BIT(16) : 0); + DSI_W32(ctrl, DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "Cmd engine setup done\n"); +} + +/** + * video_engine_en() - enable DSI video engine + * @ctrl: Pointer to controller host hardware. + * @on: Enable/disabel video engine. + */ +void dsi_ctrl_hw_cmn_video_engine_en(struct dsi_ctrl_hw *ctrl, bool on) +{ + u32 reg = 0; + + /* Set/Clear VIDEO_MODE_EN bit */ + reg = DSI_R32(ctrl, DSI_CTRL); + if (on) + reg |= BIT(1); + else + reg &= ~BIT(1); + + DSI_W32(ctrl, DSI_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "Video engine = %d\n", on); +} + +/** + * ctrl_en() - enable DSI controller engine + * @ctrl: Pointer to the controller host hardware. + * @on: turn on/off the DSI controller engine. + */ +void dsi_ctrl_hw_cmn_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on) +{ + u32 reg = 0; + u32 clk_ctrl; + + clk_ctrl = DSI_R32(ctrl, DSI_CLK_CTRL); + DSI_W32(ctrl, DSI_CLK_CTRL, clk_ctrl | DSI_CTRL_DYNAMIC_FORCE_ON); + wmb(); /* wait for clocks to enable */ + + /* Set/Clear DSI_EN bit */ + reg = DSI_R32(ctrl, DSI_CTRL); + if (on) + reg |= BIT(0); + else + reg &= ~BIT(0); + + DSI_W32(ctrl, DSI_CTRL, reg); + wmb(); /* wait for DSI_EN update before disabling clocks */ + + DSI_W32(ctrl, DSI_CLK_CTRL, clk_ctrl); + wmb(); /* make sure clocks are restored */ + + DSI_CTRL_HW_DBG(ctrl, "Controller engine = %d\n", on); +} + +/** + * cmd_engine_en() - enable DSI controller command engine + * @ctrl: Pointer to the controller host hardware. + * @on: Turn on/off the DSI command engine. + */ +void dsi_ctrl_hw_cmn_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on) +{ + u32 reg = 0; + + /* Set/Clear CMD_MODE_EN bit */ + reg = DSI_R32(ctrl, DSI_CTRL); + if (on) + reg |= BIT(2); + else + reg &= ~BIT(2); + + DSI_W32(ctrl, DSI_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "command engine = %d\n", on); +} + +/** + * kickoff_command() - transmits commands stored in memory + * @ctrl: Pointer to the controller host hardware. + * @cmd: Command information. + * @flags: Modifiers for command transmission. + * + * The controller hardware is programmed with address and size of the + * command buffer. The transmission is kicked off if + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is + * set, caller should make a separate call to trigger_command_dma() to + * transmit the command. + */ +void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_info *cmd, + u32 flags) +{ + u32 reg = 0; + + /*Set BROADCAST_EN and EMBEDDED_MODE */ + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL); + if (cmd->en_broadcast) + reg |= BIT(31); + else + reg &= ~BIT(31); + + if (cmd->is_master) + reg |= BIT(30); + else + reg &= ~BIT(30); + + if (cmd->use_lpm) + reg |= BIT(26); + else + reg &= ~BIT(26); + + reg |= BIT(28);/* Select embedded mode */ + reg &= ~BIT(24);/* packet type */ + reg &= ~BIT(29);/* WC_SEL to 0 */ + DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); + + reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL); + reg |= BIT(20);/* Disable write watermark*/ + reg |= BIT(16);/* Disable read watermark */ + + DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg); + DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset); + DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->length & 0xFFFFFF)); + + /* wait for writes to complete before kick off */ + wmb(); + + if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) + DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); +} + +/** + * kickoff_fifo_command() - transmits a command using FIFO in dsi + * hardware. + * @ctrl: Pointer to the controller host hardware. + * @cmd: Command information. + * @flags: Modifiers for command transmission. + * + * The controller hardware FIFO is programmed with command header and + * payload. The transmission is kicked off if + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is + * set, caller should make a separate call to trigger_command_dma() to + * transmit the command. + */ +void dsi_ctrl_hw_cmn_kickoff_fifo_command(struct dsi_ctrl_hw *ctrl, + struct dsi_ctrl_cmd_dma_fifo_info *cmd, + u32 flags) +{ + u32 reg = 0, i = 0; + u32 *ptr = cmd->command; + /* + * Set CMD_DMA_TPG_EN, TPG_DMA_FIFO_MODE and + * CMD_DMA_PATTERN_SEL = custom pattern stored in TPG DMA FIFO + */ + reg = (BIT(1) | BIT(2) | (0x3 << 16)); + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); + + /* + * Program the FIFO with command buffer. Hardware requires an extra + * DWORD (set to zero) if the length of command buffer is odd DWORDS. + */ + for (i = 0; i < cmd->size; i += 4) { + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL, *ptr); + ptr++; + } + + if ((cmd->size / 4) & 0x1) + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL, 0); + + /*Set BROADCAST_EN and EMBEDDED_MODE */ + reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL); + if (cmd->en_broadcast) + reg |= BIT(31); + else + reg &= ~BIT(31); + + if (cmd->is_master) + reg |= BIT(30); + else + reg &= ~BIT(30); + + if (cmd->use_lpm) + reg |= BIT(26); + else + reg &= ~BIT(26); + + reg |= BIT(28); + + DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg); + + DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, (cmd->size & 0xFFFFFFFF)); + /* Finish writes before command trigger */ + wmb(); + + if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER)) + DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); + + DSI_CTRL_HW_DBG(ctrl, "size=%d, trigger = %d\n", cmd->size, + (flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER) ? false : true); +} + +void dsi_ctrl_hw_cmn_reset_cmd_fifo(struct dsi_ctrl_hw *ctrl) +{ + /* disable cmd dma tpg */ + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, 0x0); + + DSI_W32(ctrl, DSI_TPG_DMA_FIFO_RESET, 0x1); + udelay(1); + DSI_W32(ctrl, DSI_TPG_DMA_FIFO_RESET, 0x0); +} + +/** + * trigger_command_dma() - trigger transmission of command buffer. + * @ctrl: Pointer to the controller host hardware. + * + * This trigger can be only used if there was a prior call to + * kickoff_command() of kickoff_fifo_command() with + * DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag. + */ +void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl) +{ + DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1); + DSI_CTRL_HW_DBG(ctrl, "CMD DMA triggered\n"); +} + +/** + * clear_rdbk_reg() - clear previously read panel data. + * @ctrl: Pointer to the controller host hardware. + * + * This function is called before sending DSI Rx command to + * panel in order to clear if any stale data remaining from + * previous read operation. + */ +void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl) +{ + DSI_W32(ctrl, DSI_RDBK_DATA_CTRL, 0x1); + wmb(); /* ensure read back register is reset */ + DSI_W32(ctrl, DSI_RDBK_DATA_CTRL, 0x0); + wmb(); /* ensure read back register is cleared */ +} + +/** + * get_cmd_read_data() - get data read from the peripheral + * @ctrl: Pointer to the controller host hardware. + * @rd_buf: Buffer where data will be read into. + * @total_read_len: Number of bytes to read. + * + * return: number of bytes read. + */ +u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, + u8 *rd_buf, + u32 read_offset, + u32 rx_byte, + u32 pkt_size, + u32 *hw_read_cnt) +{ + u32 *lp, *temp, data; + int i, j = 0, cnt, off; + u32 read_cnt; + u32 repeated_bytes = 0; + u8 reg[16] = {0}; + bool ack_err = false; + + lp = (u32 *)rd_buf; + temp = (u32 *)reg; + cnt = (rx_byte + 3) >> 2; + + if (cnt > 4) + cnt = 4; + + read_cnt = (DSI_R32(ctrl, DSI_RDBK_DATA_CTRL) >> 16); + ack_err = (rx_byte == 4) ? (read_cnt == 8) : + ((read_cnt - 4) == (pkt_size + 6)); + + if (ack_err) + read_cnt -= 4; + if (!read_cnt) { + DSI_CTRL_HW_ERR(ctrl, "Panel detected error, no data read\n"); + return 0; + } + + if (read_cnt > 16) { + int bytes_shifted, data_lost = 0, rem_header = 0; + + bytes_shifted = read_cnt - rx_byte; + if (bytes_shifted >= 4) + data_lost = bytes_shifted - 4; /* remove DCS header */ + else + rem_header = 4 - bytes_shifted; /* remaining header */ + + repeated_bytes = (read_offset - 4) - data_lost + rem_header; + } + + off = DSI_RDBK_DATA0; + off += ((cnt - 1) * 4); + + for (i = 0; i < cnt; i++) { + data = DSI_R32(ctrl, off); + if (!repeated_bytes) + *lp++ = ntohl(data); + else + *temp++ = ntohl(data); + off -= 4; + } + + if (repeated_bytes) { + for (i = repeated_bytes; i < 16; i++) + rd_buf[j++] = reg[i]; + } + + *hw_read_cnt = read_cnt; + DSI_CTRL_HW_DBG(ctrl, "Read %d bytes\n", rx_byte); + return rx_byte; +} + +/** + * get_interrupt_status() - returns the interrupt status + * @ctrl: Pointer to the controller host hardware. + * + * Returns the ORed list of interrupts(enum dsi_status_int_type) that + * are active. This list does not include any error interrupts. Caller + * should call get_error_status for error interrupts. + * + * Return: List of active interrupts. + */ +u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + u32 ints = 0; + + reg = DSI_R32(ctrl, DSI_INT_CTRL); + + if (reg & BIT(0)) + ints |= DSI_CMD_MODE_DMA_DONE; + if (reg & BIT(8)) + ints |= DSI_CMD_FRAME_DONE; + if (reg & BIT(10)) + ints |= DSI_CMD_STREAM0_FRAME_DONE; + if (reg & BIT(12)) + ints |= DSI_CMD_STREAM1_FRAME_DONE; + if (reg & BIT(14)) + ints |= DSI_CMD_STREAM2_FRAME_DONE; + if (reg & BIT(16)) + ints |= DSI_VIDEO_MODE_FRAME_DONE; + if (reg & BIT(20)) + ints |= DSI_BTA_DONE; + if (reg & BIT(28)) + ints |= DSI_DYN_REFRESH_DONE; + if (reg & BIT(30)) + ints |= DSI_DESKEW_DONE; + if (reg & BIT(24)) + ints |= DSI_ERROR; + + DSI_CTRL_HW_DBG(ctrl, "Interrupt status = 0x%x, INT_CTRL=0x%x\n", + ints, reg); + return ints; +} + +/** + * clear_interrupt_status() - clears the specified interrupts + * @ctrl: Pointer to the controller host hardware. + * @ints: List of interrupts to be cleared. + */ +void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_INT_CTRL); + + if (ints & DSI_CMD_MODE_DMA_DONE) + reg |= BIT(0); + if (ints & DSI_CMD_FRAME_DONE) + reg |= BIT(8); + if (ints & DSI_CMD_STREAM0_FRAME_DONE) + reg |= BIT(10); + if (ints & DSI_CMD_STREAM1_FRAME_DONE) + reg |= BIT(12); + if (ints & DSI_CMD_STREAM2_FRAME_DONE) + reg |= BIT(14); + if (ints & DSI_VIDEO_MODE_FRAME_DONE) + reg |= BIT(16); + if (ints & DSI_BTA_DONE) + reg |= BIT(20); + if (ints & DSI_DYN_REFRESH_DONE) + reg |= BIT(28); + if (ints & DSI_DESKEW_DONE) + reg |= BIT(30); + + /* + * Do not clear error status. + * It will be cleared as part of + * error handler function. + */ + reg &= ~BIT(24); + DSI_W32(ctrl, DSI_INT_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "Clear interrupts, ints = 0x%x, INT_CTRL=0x%x\n", + ints, reg); +} + +/** + * enable_status_interrupts() - enable the specified interrupts + * @ctrl: Pointer to the controller host hardware. + * @ints: List of interrupts to be enabled. + * + * Enables the specified interrupts. This list will override the + * previous interrupts enabled through this function. Caller has to + * maintain the state of the interrupts enabled. To disable all + * interrupts, set ints to 0. + */ +void dsi_ctrl_hw_cmn_enable_status_interrupts( + struct dsi_ctrl_hw *ctrl, u32 ints) +{ + u32 reg = 0; + + /* Do not change value of DSI_ERROR_MASK bit */ + reg |= (DSI_R32(ctrl, DSI_INT_CTRL) & BIT(25)); + if (ints & DSI_CMD_MODE_DMA_DONE) + reg |= BIT(1); + if (ints & DSI_CMD_FRAME_DONE) + reg |= BIT(9); + if (ints & DSI_CMD_STREAM0_FRAME_DONE) + reg |= BIT(11); + if (ints & DSI_CMD_STREAM1_FRAME_DONE) + reg |= BIT(13); + if (ints & DSI_CMD_STREAM2_FRAME_DONE) + reg |= BIT(15); + if (ints & DSI_VIDEO_MODE_FRAME_DONE) + reg |= BIT(17); + if (ints & DSI_BTA_DONE) + reg |= BIT(21); + if (ints & DSI_DYN_REFRESH_DONE) + reg |= BIT(29); + if (ints & DSI_DESKEW_DONE) + reg |= BIT(31); + + DSI_W32(ctrl, DSI_INT_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "Enable interrupts 0x%x, INT_CTRL=0x%x\n", ints, + reg); +} + +/** + * get_error_status() - returns the error status + * @ctrl: Pointer to the controller host hardware. + * + * Returns the ORed list of errors(enum dsi_error_int_type) that are + * active. This list does not include any status interrupts. Caller + * should call get_interrupt_status for status interrupts. + * + * Return: List of active error interrupts. + */ +u64 dsi_ctrl_hw_cmn_get_error_status(struct dsi_ctrl_hw *ctrl) +{ + u32 dln0_phy_err; + u32 fifo_status; + u32 ack_error; + u32 timeout_errors; + u32 clk_error; + u32 dsi_status; + u64 errors = 0, shift = 0x1; + + dln0_phy_err = DSI_R32(ctrl, DSI_DLN0_PHY_ERR); + if (dln0_phy_err & BIT(0)) + errors |= DSI_DLN0_ESC_ENTRY_ERR; + if (dln0_phy_err & BIT(4)) + errors |= DSI_DLN0_ESC_SYNC_ERR; + if (dln0_phy_err & BIT(8)) + errors |= DSI_DLN0_LP_CONTROL_ERR; + if (dln0_phy_err & BIT(12)) + errors |= DSI_DLN0_LP0_CONTENTION; + if (dln0_phy_err & BIT(16)) + errors |= DSI_DLN0_LP1_CONTENTION; + + fifo_status = DSI_R32(ctrl, DSI_FIFO_STATUS); + if (fifo_status & BIT(7)) + errors |= DSI_CMD_MDP_FIFO_UNDERFLOW; + if (fifo_status & BIT(10)) + errors |= DSI_CMD_DMA_FIFO_UNDERFLOW; + if (fifo_status & BIT(18)) + errors |= DSI_DLN0_HS_FIFO_OVERFLOW; + if (fifo_status & BIT(19)) + errors |= DSI_DLN0_HS_FIFO_UNDERFLOW; + if (fifo_status & BIT(22)) + errors |= DSI_DLN1_HS_FIFO_OVERFLOW; + if (fifo_status & BIT(23)) + errors |= DSI_DLN1_HS_FIFO_UNDERFLOW; + if (fifo_status & BIT(26)) + errors |= DSI_DLN2_HS_FIFO_OVERFLOW; + if (fifo_status & BIT(27)) + errors |= DSI_DLN2_HS_FIFO_UNDERFLOW; + if (fifo_status & BIT(30)) + errors |= DSI_DLN3_HS_FIFO_OVERFLOW; + if (fifo_status & BIT(31)) + errors |= DSI_DLN3_HS_FIFO_UNDERFLOW; + + ack_error = DSI_R32(ctrl, DSI_ACK_ERR_STATUS); + if (ack_error & BIT(16)) + errors |= DSI_RDBK_SINGLE_ECC_ERR; + if (ack_error & BIT(17)) + errors |= DSI_RDBK_MULTI_ECC_ERR; + if (ack_error & BIT(20)) + errors |= DSI_RDBK_CRC_ERR; + if (ack_error & BIT(23)) + errors |= DSI_RDBK_INCOMPLETE_PKT; + if (ack_error & BIT(24)) + errors |= DSI_PERIPH_ERROR_PKT; + if (ack_error & BIT(15)) + errors |= (shift << DSI_EINT_PANEL_SPECIFIC_ERR); + + timeout_errors = DSI_R32(ctrl, DSI_TIMEOUT_STATUS); + if (timeout_errors & BIT(0)) + errors |= DSI_HS_TX_TIMEOUT; + if (timeout_errors & BIT(4)) + errors |= DSI_LP_RX_TIMEOUT; + if (timeout_errors & BIT(8)) + errors |= DSI_BTA_TIMEOUT; + + clk_error = DSI_R32(ctrl, DSI_CLK_STATUS); + if (clk_error & BIT(16)) + errors |= DSI_PLL_UNLOCK; + + dsi_status = DSI_R32(ctrl, DSI_STATUS); + if (dsi_status & BIT(31)) + errors |= DSI_INTERLEAVE_OP_CONTENTION; + + DSI_CTRL_HW_DBG(ctrl, "Error status = 0x%llx, phy=0x%x, fifo=0x%x\n", + errors, dln0_phy_err, fifo_status); + DSI_CTRL_HW_DBG(ctrl, "ack=0x%x, timeout=0x%x, clk=0x%x, dsi=0x%x\n", + ack_error, timeout_errors, clk_error, dsi_status); + return errors; +} + +/** + * clear_error_status() - clears the specified errors + * @ctrl: Pointer to the controller host hardware. + * @errors: List of errors to be cleared. + */ +void dsi_ctrl_hw_cmn_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors) +{ + u32 dln0_phy_err = 0; + u32 fifo_status = 0; + u32 ack_error = 0; + u32 timeout_error = 0; + u32 clk_error = 0; + u32 dsi_status = 0; + + if (errors & DSI_RDBK_SINGLE_ECC_ERR) + ack_error |= BIT(16); + if (errors & DSI_RDBK_MULTI_ECC_ERR) + ack_error |= BIT(17); + if (errors & DSI_RDBK_CRC_ERR) + ack_error |= BIT(20); + if (errors & DSI_RDBK_INCOMPLETE_PKT) + ack_error |= BIT(23); + if (errors & DSI_PERIPH_ERROR_PKT) + ack_error |= BIT(24); + if (errors & DSI_PANEL_SPECIFIC_ERR) + ack_error |= BIT(15); + + if (errors & DSI_LP_RX_TIMEOUT) + timeout_error |= BIT(4); + if (errors & DSI_HS_TX_TIMEOUT) + timeout_error |= BIT(0); + if (errors & DSI_BTA_TIMEOUT) + timeout_error |= BIT(8); + + if (errors & DSI_PLL_UNLOCK) + clk_error |= BIT(16); + + if (errors & DSI_DLN0_LP0_CONTENTION) + dln0_phy_err |= BIT(12); + if (errors & DSI_DLN0_LP1_CONTENTION) + dln0_phy_err |= BIT(16); + if (errors & DSI_DLN0_ESC_ENTRY_ERR) + dln0_phy_err |= BIT(0); + if (errors & DSI_DLN0_ESC_SYNC_ERR) + dln0_phy_err |= BIT(4); + if (errors & DSI_DLN0_LP_CONTROL_ERR) + dln0_phy_err |= BIT(8); + + if (errors & DSI_CMD_DMA_FIFO_UNDERFLOW) + fifo_status |= BIT(10); + if (errors & DSI_CMD_MDP_FIFO_UNDERFLOW) + fifo_status |= BIT(7); + if (errors & DSI_DLN0_HS_FIFO_OVERFLOW) + fifo_status |= BIT(18); + if (errors & DSI_DLN1_HS_FIFO_OVERFLOW) + fifo_status |= BIT(22); + if (errors & DSI_DLN2_HS_FIFO_OVERFLOW) + fifo_status |= BIT(26); + if (errors & DSI_DLN3_HS_FIFO_OVERFLOW) + fifo_status |= BIT(30); + if (errors & DSI_DLN0_HS_FIFO_UNDERFLOW) + fifo_status |= BIT(19); + if (errors & DSI_DLN1_HS_FIFO_UNDERFLOW) + fifo_status |= BIT(23); + if (errors & DSI_DLN2_HS_FIFO_UNDERFLOW) + fifo_status |= BIT(27); + if (errors & DSI_DLN3_HS_FIFO_UNDERFLOW) + fifo_status |= BIT(31); + + if (errors & DSI_INTERLEAVE_OP_CONTENTION) + dsi_status |= BIT(31); + + DSI_W32(ctrl, DSI_DLN0_PHY_ERR, dln0_phy_err); + DSI_W32(ctrl, DSI_FIFO_STATUS, fifo_status); + /* Writing of an extra 0 is needed to clear ack error bits */ + DSI_W32(ctrl, DSI_ACK_ERR_STATUS, ack_error); + wmb(); /* make sure register is committed */ + DSI_W32(ctrl, DSI_ACK_ERR_STATUS, 0x0); + DSI_W32(ctrl, DSI_TIMEOUT_STATUS, timeout_error); + DSI_W32(ctrl, DSI_CLK_STATUS, clk_error); + DSI_W32(ctrl, DSI_STATUS, dsi_status); + + DSI_CTRL_HW_DBG(ctrl, "clear errors = 0x%llx, phy=0x%x, fifo=0x%x\n", + errors, dln0_phy_err, fifo_status); + DSI_CTRL_HW_DBG(ctrl, "ack=0x%x, timeout=0x%x, clk=0x%x, dsi=0x%x\n", + ack_error, timeout_error, clk_error, dsi_status); +} + +/** + * enable_error_interrupts() - enable the specified interrupts + * @ctrl: Pointer to the controller host hardware. + * @errors: List of errors to be enabled. + * + * Enables the specified interrupts. This list will override the + * previous interrupts enabled through this function. Caller has to + * maintain the state of the interrupts enabled. To disable all + * interrupts, set errors to 0. + */ +void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl, + u64 errors) +{ + u32 int_ctrl = 0; + u32 int_mask0 = 0x7FFF3BFF; + + int_ctrl = DSI_R32(ctrl, DSI_INT_CTRL); + if (errors) + int_ctrl |= BIT(25); + else + int_ctrl &= ~BIT(25); + + if (errors & DSI_RDBK_SINGLE_ECC_ERR) + int_mask0 &= ~BIT(0); + if (errors & DSI_RDBK_MULTI_ECC_ERR) + int_mask0 &= ~BIT(1); + if (errors & DSI_RDBK_CRC_ERR) + int_mask0 &= ~BIT(2); + if (errors & DSI_RDBK_INCOMPLETE_PKT) + int_mask0 &= ~BIT(3); + if (errors & DSI_PERIPH_ERROR_PKT) + int_mask0 &= ~BIT(4); + + if (errors & DSI_LP_RX_TIMEOUT) + int_mask0 &= ~BIT(5); + if (errors & DSI_HS_TX_TIMEOUT) + int_mask0 &= ~BIT(6); + if (errors & DSI_BTA_TIMEOUT) + int_mask0 &= ~BIT(7); + + if (errors & DSI_PLL_UNLOCK) + int_mask0 &= ~BIT(28); + + if (errors & DSI_DLN0_LP0_CONTENTION) + int_mask0 &= ~BIT(24); + if (errors & DSI_DLN0_LP1_CONTENTION) + int_mask0 &= ~BIT(25); + if (errors & DSI_DLN0_ESC_ENTRY_ERR) + int_mask0 &= ~BIT(21); + if (errors & DSI_DLN0_ESC_SYNC_ERR) + int_mask0 &= ~BIT(22); + if (errors & DSI_DLN0_LP_CONTROL_ERR) + int_mask0 &= ~BIT(23); + + if (errors & DSI_CMD_DMA_FIFO_UNDERFLOW) + int_mask0 &= ~BIT(9); + if (errors & DSI_CMD_MDP_FIFO_UNDERFLOW) + int_mask0 &= ~BIT(11); + if (errors & DSI_DLN0_HS_FIFO_OVERFLOW) + int_mask0 &= ~BIT(16); + if (errors & DSI_DLN1_HS_FIFO_OVERFLOW) + int_mask0 &= ~BIT(17); + if (errors & DSI_DLN2_HS_FIFO_OVERFLOW) + int_mask0 &= ~BIT(18); + if (errors & DSI_DLN3_HS_FIFO_OVERFLOW) + int_mask0 &= ~BIT(19); + if (errors & DSI_DLN0_HS_FIFO_UNDERFLOW) + int_mask0 &= ~BIT(26); + if (errors & DSI_DLN1_HS_FIFO_UNDERFLOW) + int_mask0 &= ~BIT(27); + if (errors & DSI_DLN2_HS_FIFO_UNDERFLOW) + int_mask0 &= ~BIT(29); + if (errors & DSI_DLN3_HS_FIFO_UNDERFLOW) + int_mask0 &= ~BIT(30); + + if (errors & DSI_INTERLEAVE_OP_CONTENTION) + int_mask0 &= ~BIT(8); + + DSI_W32(ctrl, DSI_INT_CTRL, int_ctrl); + DSI_W32(ctrl, DSI_ERR_INT_MASK0, int_mask0); + + DSI_CTRL_HW_DBG(ctrl, "[DSI_%d] enable errors = 0x%llx, int_mask0=0x%x\n", + errors, int_mask0); +} + +/** + * video_test_pattern_setup() - setup test pattern engine for video mode + * @ctrl: Pointer to the controller host hardware. + * @type: Type of test pattern. + * @init_val: Initial value to use for generating test pattern. + */ +void dsi_ctrl_hw_cmn_video_test_pattern_setup(struct dsi_ctrl_hw *ctrl, + enum dsi_test_pattern type, + u32 init_val) +{ + u32 reg = 0; + + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_VIDEO_INIT_VAL, init_val); + + switch (type) { + case DSI_TEST_PATTERN_FIXED: + reg |= (0x2 << 4); + break; + case DSI_TEST_PATTERN_INC: + reg |= (0x1 << 4); + break; + case DSI_TEST_PATTERN_POLY: + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_VIDEO_POLY, 0xF0F0F); + break; + default: + break; + } + + DSI_W32(ctrl, DSI_TPG_MAIN_CONTROL, 0x100); + DSI_W32(ctrl, DSI_TPG_VIDEO_CONFIG, 0x5); + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "Video test pattern setup done\n"); +} + +/** + * cmd_test_pattern_setup() - setup test patttern engine for cmd mode + * @ctrl: Pointer to the controller host hardware. + * @type: Type of test pattern. + * @init_val: Initial value to use for generating test pattern. + * @stream_id: Stream Id on which packets are generated. + */ +void dsi_ctrl_hw_cmn_cmd_test_pattern_setup(struct dsi_ctrl_hw *ctrl, + enum dsi_test_pattern type, + u32 init_val, + u32 stream_id) +{ + u32 reg = 0; + u32 init_offset; + u32 poly_offset; + u32 pattern_sel_shift; + + switch (stream_id) { + case 0: + init_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL0; + poly_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM0_POLY; + pattern_sel_shift = 8; + break; + case 1: + init_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL1; + poly_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM1_POLY; + pattern_sel_shift = 12; + break; + case 2: + init_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL2; + poly_offset = DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY; + pattern_sel_shift = 20; + break; + default: + return; + } + + DSI_W32(ctrl, init_offset, init_val); + + switch (type) { + case DSI_TEST_PATTERN_FIXED: + reg |= (0x2 << pattern_sel_shift); + break; + case DSI_TEST_PATTERN_INC: + reg |= (0x1 << pattern_sel_shift); + break; + case DSI_TEST_PATTERN_POLY: + DSI_W32(ctrl, poly_offset, 0xF0F0F); + break; + default: + break; + } + + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); + DSI_CTRL_HW_DBG(ctrl, "Cmd test pattern setup done\n"); +} + +/** + * test_pattern_enable() - enable test pattern engine + * @ctrl: Pointer to the controller host hardware. + * @enable: Enable/Disable test pattern engine. + */ +void dsi_ctrl_hw_cmn_test_pattern_enable(struct dsi_ctrl_hw *ctrl, + bool enable) +{ + u32 reg = DSI_R32(ctrl, DSI_TEST_PATTERN_GEN_CTRL); + + if (enable) + reg |= BIT(0); + else + reg &= ~BIT(0); + + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CTRL, reg); + + DSI_CTRL_HW_DBG(ctrl, "Test pattern enable=%d\n", enable); +} + +/** + * trigger_cmd_test_pattern() - trigger a command mode frame update with + * test pattern + * @ctrl: Pointer to the controller host hardware. + * @stream_id: Stream on which frame update is sent. + */ +void dsi_ctrl_hw_cmn_trigger_cmd_test_pattern(struct dsi_ctrl_hw *ctrl, + u32 stream_id) +{ + switch (stream_id) { + case 0: + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER, 0x1); + break; + case 1: + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_STREAM1_TRIGGER, 0x1); + break; + case 2: + DSI_W32(ctrl, DSI_TEST_PATTERN_GEN_CMD_STREAM2_TRIGGER, 0x1); + break; + default: + break; + } + + DSI_CTRL_HW_DBG(ctrl, "Cmd Test pattern trigger\n"); +} + +void dsi_ctrl_hw_dln0_phy_err(struct dsi_ctrl_hw *ctrl) +{ + u32 status = 0; + /* + * Clear out any phy errors prior to exiting ULPS + * This fixes certain instances where phy does not exit + * ULPS cleanly. Also, do not print error during such cases. + */ + status = DSI_R32(ctrl, DSI_DLN0_PHY_ERR); + if (status & 0x011111) { + DSI_W32(ctrl, DSI_DLN0_PHY_ERR, status); + DSI_CTRL_HW_ERR(ctrl, "phy_err_status = %x\n", status); + } +} + +void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl, + bool enable) +{ + u32 reg = 0; + + reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF); + + /* Mask/unmask disable PHY reset bit */ + if (enable) + reg |= BIT(30); + else + reg &= ~BIT(30); + + DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg); +} + +int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl, + int mask) +{ + int rc = 0; + u32 data; + + DSI_CTRL_HW_DBG(ctrl, "DSI CTRL and PHY reset, mask=%d\n", mask); + + data = DSI_R32(ctrl, 0x0004); + /* Disable DSI video mode */ + DSI_W32(ctrl, 0x004, (data & ~BIT(1))); + wmb(); /* ensure register committed */ + /* Disable DSI controller */ + DSI_W32(ctrl, 0x004, (data & ~(BIT(0) | BIT(1)))); + wmb(); /* ensure register committed */ + /* "Force On" all dynamic clocks */ + DSI_W32(ctrl, 0x11c, 0x100a00); + + /* DSI_SW_RESET */ + DSI_W32(ctrl, 0x118, 0x1); + wmb(); /* ensure register is committed */ + DSI_W32(ctrl, 0x118, 0x0); + wmb(); /* ensure register is committed */ + + /* Remove "Force On" all dynamic clocks */ + DSI_W32(ctrl, 0x11c, 0x00); + /* Enable DSI controller */ + DSI_W32(ctrl, 0x004, (data & ~BIT(1))); + wmb(); /* ensure register committed */ + + return rc; +} + +void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, bool en) +{ + u32 reg = 0; + u32 fifo_status = 0, timeout_status = 0; + u32 overflow_clear = BIT(10) | BIT(18) | BIT(22) | BIT(26) | BIT(30); + u32 underflow_clear = BIT(19) | BIT(23) | BIT(27) | BIT(31); + u32 lp_rx_clear = BIT(4); + + reg = DSI_R32(ctrl, 0x10c); + + /* + * Before unmasking we should clear the corresponding error status bits + * that might have been set while we masked these errors. Since these + * are sticky bits, these errors will trigger the moment we unmask + * the error bits. + */ + if (idx & BIT(DSI_FIFO_OVERFLOW)) { + if (en) { + reg |= (0x1f << 16); + reg |= BIT(9); + } else { + reg &= ~(0x1f << 16); + reg &= ~BIT(9); + fifo_status = DSI_R32(ctrl, 0x00c); + DSI_W32(ctrl, 0x00c, fifo_status | overflow_clear); + } + } + + if (idx & BIT(DSI_FIFO_UNDERFLOW)) { + if (en) + reg |= (0x1b << 26); + else { + reg &= ~(0x1b << 26); + fifo_status = DSI_R32(ctrl, 0x00c); + DSI_W32(ctrl, 0x00c, fifo_status | underflow_clear); + } + } + + if (idx & BIT(DSI_LP_Rx_TIMEOUT)) { + if (en) + reg |= (0x7 << 23); + else { + reg &= ~(0x7 << 23); + timeout_status = DSI_R32(ctrl, 0x0c0); + DSI_W32(ctrl, 0x0c0, timeout_status | lp_rx_clear); + } + } + + if (idx & BIT(DSI_PLL_UNLOCK_ERR)) { + if (en) + reg |= BIT(28); + else + reg &= ~BIT(28); + } + + DSI_W32(ctrl, 0x10c, reg); + wmb(); /* ensure error is masked */ +} + +void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en) +{ + u32 reg = 0; + u32 dsi_total_mask = 0x2222AA02; + + reg = DSI_R32(ctrl, 0x110); + reg &= dsi_total_mask; + + if (en) + reg |= (BIT(24) | BIT(25)); + else + reg &= ~BIT(25); + + DSI_W32(ctrl, 0x110, reg); + wmb(); /* ensure error is masked */ +} + +u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, 0x10c); + + return reg; +} + +u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, 0x0); + + return reg; +} + +int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl) +{ + int rc = 0, val = 0; + u32 cmd_mode_mdp_busy_mask = BIT(2); + u32 const sleep_us = 2 * 1000; + u32 const timeout_us = 200 * 1000; + + rc = readl_poll_timeout(ctrl->base + DSI_STATUS, val, + !(val & cmd_mode_mdp_busy_mask), sleep_us, timeout_us); + if (rc) + DSI_CTRL_HW_ERR(ctrl, "timed out waiting for idle\n"); + + return rc; +} + +void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_LANE_CTRL); + if (sel_phy) + reg &= ~BIT(24); + else + reg |= BIT(24); + DSI_W32(ctrl, DSI_LANE_CTRL, reg); + wmb(); /* make sure request is set */ +} + +void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable) +{ + u32 reg = 0; + + reg = DSI_R32(ctrl, DSI_LANE_CTRL); + if (enable) + reg |= BIT(28); + else + reg &= ~BIT(28); + DSI_W32(ctrl, DSI_LANE_CTRL, reg); + wmb(); /* make sure request is set */ +} + +int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl) +{ + int rc; + u32 const sleep_us = 1000; + u32 const timeout_us = 84000; /* approximately 5 vsyncs */ + u32 reg = 0, dyn_refresh_done = BIT(28); + + rc = readl_poll_timeout(ctrl->base + DSI_INT_CTRL, reg, + (reg & dyn_refresh_done), sleep_us, timeout_us); + if (rc) { + DSI_CTRL_HW_ERR(ctrl, "wait4dynamic refresh timedout %d\n", rc); + return rc; + } + + /* ack dynamic refresh done status */ + reg = DSI_R32(ctrl, DSI_INT_CTRL); + reg |= dyn_refresh_done; + DSI_W32(ctrl, DSI_INT_CTRL, reg); + + return 0; +} diff --git a/techpack/display/msm/dsi/dsi_ctrl_reg.h b/techpack/display/msm/dsi/dsi_ctrl_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..43a11530555ac7976166dfc42ef03fec691883bf --- /dev/null +++ b/techpack/display/msm/dsi/dsi_ctrl_reg.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_CTRL_REG_H_ +#define _DSI_CTRL_REG_H_ + +#define DSI_HW_VERSION (0x0000) +#define DSI_CTRL (0x0004) +#define DSI_STATUS (0x0008) +#define DSI_FIFO_STATUS (0x000C) +#define DSI_VIDEO_MODE_CTRL (0x0010) +#define DSI_VIDEO_MODE_SYNC_DATATYPE (0x0014) +#define DSI_VIDEO_MODE_PIXEL_DATATYPE (0x0018) +#define DSI_VIDEO_MODE_BLANKING_DATATYPE (0x001C) +#define DSI_VIDEO_MODE_DATA_CTRL (0x0020) +#define DSI_VIDEO_MODE_ACTIVE_H (0x0024) +#define DSI_VIDEO_MODE_ACTIVE_V (0x0028) +#define DSI_VIDEO_MODE_TOTAL (0x002C) +#define DSI_VIDEO_MODE_HSYNC (0x0030) +#define DSI_VIDEO_MODE_VSYNC (0x0034) +#define DSI_VIDEO_MODE_VSYNC_VPOS (0x0038) +#define DSI_COMMAND_MODE_DMA_CTRL (0x003C) +#define DSI_COMMAND_MODE_MDP_CTRL (0x0040) +#define DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL (0x0044) +#define DSI_DMA_CMD_OFFSET (0x0048) +#define DSI_DMA_CMD_LENGTH (0x004C) +#define DSI_DMA_FIFO_CTRL (0x0050) +#define DSI_DMA_NULL_PACKET_DATA (0x0054) +#define DSI_COMMAND_MODE_MDP_STREAM0_CTRL (0x0058) +#define DSI_COMMAND_MODE_MDP_STREAM0_TOTAL (0x005C) +#define DSI_COMMAND_MODE_MDP_STREAM1_CTRL (0x0060) +#define DSI_COMMAND_MODE_MDP_STREAM1_TOTAL (0x0064) +#define DSI_ACK_ERR_STATUS (0x0068) +#define DSI_RDBK_DATA0 (0x006C) +#define DSI_RDBK_DATA1 (0x0070) +#define DSI_RDBK_DATA2 (0x0074) +#define DSI_RDBK_DATA3 (0x0078) +#define DSI_RDBK_DATATYPE0 (0x007C) +#define DSI_RDBK_DATATYPE1 (0x0080) +#define DSI_TRIG_CTRL (0x0084) +#define DSI_EXT_MUX (0x0088) +#define DSI_EXT_MUX_TE_PULSE_DETECT_CTRL (0x008C) +#define DSI_CMD_MODE_DMA_SW_TRIGGER (0x0090) +#define DSI_CMD_MODE_MDP_SW_TRIGGER (0x0094) +#define DSI_CMD_MODE_BTA_SW_TRIGGER (0x0098) +#define DSI_RESET_SW_TRIGGER (0x009C) +#define DSI_MISR_CMD_CTRL (0x00A0) +#define DSI_MISR_VIDEO_CTRL (0x00A4) +#define DSI_LANE_STATUS (0x00A8) +#define DSI_LANE_CTRL (0x00AC) +#define DSI_LANE_SWAP_CTRL (0x00B0) +#define DSI_DLN0_PHY_ERR (0x00B4) +#define DSI_LP_TIMER_CTRL (0x00B8) +#define DSI_HS_TIMER_CTRL (0x00BC) +#define DSI_TIMEOUT_STATUS (0x00C0) +#define DSI_CLKOUT_TIMING_CTRL (0x00C4) +#define DSI_EOT_PACKET (0x00C8) +#define DSI_EOT_PACKET_CTRL (0x00CC) +#define DSI_GENERIC_ESC_TX_TRIGGER (0x00D0) +#define DSI_CAM_BIST_CTRL (0x00D4) +#define DSI_CAM_BIST_FRAME_SIZE (0x00D8) +#define DSI_CAM_BIST_BLOCK_SIZE (0x00DC) +#define DSI_CAM_BIST_FRAME_CONFIG (0x00E0) +#define DSI_CAM_BIST_LSFR_CTRL (0x00E4) +#define DSI_CAM_BIST_LSFR_INIT (0x00E8) +#define DSI_CAM_BIST_START (0x00EC) +#define DSI_CAM_BIST_STATUS (0x00F0) +#define DSI_ERR_INT_MASK0 (0x010C) +#define DSI_INT_CTRL (0x0110) +#define DSI_IOBIST_CTRL (0x0114) +#define DSI_SOFT_RESET (0x0118) +#define DSI_CLK_CTRL (0x011C) +#define DSI_CLK_STATUS (0x0120) +#define DSI_DEBUG_BUS_CTL (0x0124) +#define DSI_DEBUG_BUS_STATUS (0x0128) +#define DSI_PHY_SW_RESET (0x012C) +#define DSI_AXI2AHB_CTRL (0x0130) +#define DSI_MISR_CMD_MDP0_32BIT (0x0134) +#define DSI_MISR_CMD_MDP1_32BIT (0x0138) +#define DSI_MISR_CMD_DMA_32BIT (0x013C) +#define DSI_MISR_VIDEO_32BIT (0x0140) +#define DSI_LANE_MISR_CTRL (0x0144) +#define DSI_LANE0_MISR (0x0148) +#define DSI_LANE1_MISR (0x014C) +#define DSI_LANE2_MISR (0x0150) +#define DSI_LANE3_MISR (0x0154) +#define DSI_TEST_PATTERN_GEN_CTRL (0x015C) +#define DSI_TEST_PATTERN_GEN_VIDEO_POLY (0x0160) +#define DSI_TEST_PATTERN_GEN_VIDEO_INIT_VAL (0x0164) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM0_POLY (0x0168) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL0 (0x016C) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM1_POLY (0x0170) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL1 (0x0174) +#define DSI_TEST_PATTERN_GEN_CMD_DMA_POLY (0x0178) +#define DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL (0x017C) +#define DSI_TEST_PATTERN_GEN_VIDEO_ENABLE (0x0180) +#define DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER (0x0184) +#define DSI_TEST_PATTERN_GEN_CMD_STREAM1_TRIGGER (0x0188) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL2 (0x018C) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY (0x0190) +#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY (0x0190) +#define DSI_COMMAND_MODE_MDP_IDLE_CTRL (0x0194) +#define DSI_TEST_PATTERN_GEN_CMD_STREAM2_TRIGGER (0x0198) +#define DSI_TPG_MAIN_CONTROL (0x019C) +#define DSI_TPG_MAIN_CONTROL2 (0x01A0) +#define DSI_TPG_VIDEO_CONFIG (0x01A4) +#define DSI_TPG_COMPONENT_LIMITS (0x01A8) +#define DSI_TPG_RECTANGLE (0x01AC) +#define DSI_TPG_BLACK_WHITE_PATTERN_FRAMES (0x01B0) +#define DSI_TPG_RGB_MAPPING (0x01B4) +#define DSI_COMMAND_MODE_MDP_CTRL2 (0x01B8) +#define DSI_COMMAND_MODE_MDP_STREAM2_CTRL (0x01BC) +#define DSI_COMMAND_MODE_MDP_STREAM2_TOTAL (0x01C0) +#define DSI_MISR_CMD_MDP2_8BIT (0x01C4) +#define DSI_MISR_CMD_MDP2_32BIT (0x01C8) +#define DSI_VBIF_CTRL (0x01CC) +#define DSI_AES_CTRL (0x01D0) +#define DSI_RDBK_DATA_CTRL (0x01D4) +#define DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2 (0x01D8) +#define DSI_TPG_DMA_FIFO_STATUS (0x01DC) +#define DSI_TPG_DMA_FIFO_WRITE_TRIGGER (0x01E0) +#define DSI_DSI_TIMING_FLUSH (0x01E4) +#define DSI_DSI_TIMING_DB_MODE (0x01E8) +#define DSI_TPG_DMA_FIFO_RESET (0x01EC) +#define DSI_SCRATCH_REGISTER_0 (0x01F0) +#define DSI_VERSION (0x01F4) +#define DSI_SCRATCH_REGISTER_1 (0x01F8) +#define DSI_SCRATCH_REGISTER_2 (0x01FC) +#define DSI_DYNAMIC_REFRESH_CTRL (0x0200) +#define DSI_DYNAMIC_REFRESH_STATUS (0x0210) +#define DSI_VIDEO_COMPRESSION_MODE_CTRL (0x02A0) +#define DSI_VIDEO_COMPRESSION_MODE_CTRL2 (0x02A4) +#define DSI_COMMAND_COMPRESSION_MODE_CTRL (0x02A8) +#define DSI_COMMAND_COMPRESSION_MODE_CTRL2 (0x02AC) +#define DSI_COMMAND_COMPRESSION_MODE_CTRL3 (0x02B0) +#define DSI_COMMAND_MODE_NULL_INSERTION_CTRL (0x02B4) +#define DSI_READ_BACK_DISABLE_STATUS (0x02B8) +#define DSI_DESKEW_CTRL (0x02BC) +#define DSI_DESKEW_DELAY_CTRL (0x02C0) +#define DSI_DESKEW_SW_TRIGGER (0x02C4) +#define DSI_DEBUG_CTRL (0x02C8) +#define DSI_SECURE_DISPLAY_STATUS (0x02CC) +#define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0) +#define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4) +#define DSI_CPHY_MODE_CTRL (0x02D8) +#define DSI_LOGICAL_LANE_SWAP_CTRL (0x0310) +#define DSI_SPLIT_LINK (0x0330) + + +#endif /* _DSI_CTRL_REG_H_ */ diff --git a/techpack/display/msm/dsi/dsi_defs.h b/techpack/display/msm/dsi/dsi_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..c2de6d1b97fde7e0739fd556343844716f70479d --- /dev/null +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -0,0 +1,834 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_DEFS_H_ +#define _DSI_DEFS_H_ + +#include <linux/types.h> +#include <drm/drm_mipi_dsi.h> +#include "msm_drv.h" + +#define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \ + ((t)->h_sync_width) + ((t)->h_front_porch)) + +#define DSI_V_TOTAL(t) (((t)->v_active) + ((t)->v_back_porch) + \ + ((t)->v_sync_width) + ((t)->v_front_porch)) + +#define DSI_H_TOTAL_DSC(t) \ + ({\ + u64 value;\ + if ((t)->dsc_enabled && (t)->dsc)\ + value = (t)->dsc->pclk_per_line;\ + else\ + value = (t)->h_active;\ + value = value + (t)->h_back_porch + (t)->h_sync_width +\ + (t)->h_front_porch;\ + value;\ + }) + +#define DSI_H_ACTIVE_DSC(t) \ + ({\ + u64 value;\ + if ((t)->dsc_enabled && (t)->dsc)\ + value = (t)->dsc->pclk_per_line;\ + else\ + value = (t)->h_active;\ + value;\ + }) + + +#define DSI_DEBUG_NAME_LEN 32 +#define display_for_each_ctrl(index, display) \ + for (index = 0; (index < (display)->ctrl_count) &&\ + (index < MAX_DSI_CTRLS_PER_DISPLAY); index++) + +#define DSI_WARN(fmt, ...) DRM_WARN("[msm-dsi-warn]: "fmt, ##__VA_ARGS__) +#define DSI_ERR(fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: " fmt, \ + ##__VA_ARGS__) +#define DSI_INFO(fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: "fmt, \ + ##__VA_ARGS__) +#define DSI_DEBUG(fmt, ...) DRM_DEV_DEBUG(NULL, "[msm-dsi-debug]: "fmt, \ + ##__VA_ARGS__) +/** + * enum dsi_pixel_format - DSI pixel formats + * @DSI_PIXEL_FORMAT_RGB565: + * @DSI_PIXEL_FORMAT_RGB666: + * @DSI_PIXEL_FORMAT_RGB666_LOOSE: + * @DSI_PIXEL_FORMAT_RGB888: + * @DSI_PIXEL_FORMAT_RGB111: + * @DSI_PIXEL_FORMAT_RGB332: + * @DSI_PIXEL_FORMAT_RGB444: + * @DSI_PIXEL_FORMAT_MAX: + */ +enum dsi_pixel_format { + DSI_PIXEL_FORMAT_RGB565 = 0, + DSI_PIXEL_FORMAT_RGB666, + DSI_PIXEL_FORMAT_RGB666_LOOSE, + DSI_PIXEL_FORMAT_RGB888, + DSI_PIXEL_FORMAT_RGB111, + DSI_PIXEL_FORMAT_RGB332, + DSI_PIXEL_FORMAT_RGB444, + DSI_PIXEL_FORMAT_MAX +}; + +/** + * enum dsi_op_mode - dsi operation mode + * @DSI_OP_VIDEO_MODE: DSI video mode operation + * @DSI_OP_CMD_MODE: DSI Command mode operation + * @DSI_OP_MODE_MAX: + */ +enum dsi_op_mode { + DSI_OP_VIDEO_MODE = 0, + DSI_OP_CMD_MODE, + DSI_OP_MODE_MAX +}; + +/** + * enum dsi_mode_flags - flags to signal other drm components via private flags + * @DSI_MODE_FLAG_SEAMLESS: Seamless transition requested by user + * @DSI_MODE_FLAG_DFPS: Seamless transition is DynamicFPS + * @DSI_MODE_FLAG_VBLANK_PRE_MODESET: Transition needs VBLANK before Modeset + * @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch + * @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS. + * New timing values are sent from DAL. + * @DSI_MODE_FLAG_POMS: + * Seamless transition is dynamic panel operating mode switch + * @DSI_MODE_FLAG_DYN_CLK: Seamless transition is dynamic clock change + * @DSI_MODE_FLAG_DMS_FPS: Seamless fps only transition in Dynamic Mode Switch + */ +enum dsi_mode_flags { + DSI_MODE_FLAG_SEAMLESS = BIT(0), + DSI_MODE_FLAG_DFPS = BIT(1), + DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2), + DSI_MODE_FLAG_DMS = BIT(3), + DSI_MODE_FLAG_VRR = BIT(4), + DSI_MODE_FLAG_POMS = BIT(5), + DSI_MODE_FLAG_DYN_CLK = BIT(6), + DSI_MODE_FLAG_DMS_FPS = BIT(7), +}; + +/** + * enum dsi_logical_lane - dsi logical lanes + * @DSI_LOGICAL_LANE_0: Logical lane 0 + * @DSI_LOGICAL_LANE_1: Logical lane 1 + * @DSI_LOGICAL_LANE_2: Logical lane 2 + * @DSI_LOGICAL_LANE_3: Logical lane 3 + * @DSI_LOGICAL_CLOCK_LANE: Clock lane + * @DSI_LANE_MAX: Maximum lanes supported + */ +enum dsi_logical_lane { + DSI_LOGICAL_LANE_0 = 0, + DSI_LOGICAL_LANE_1, + DSI_LOGICAL_LANE_2, + DSI_LOGICAL_LANE_3, + DSI_LOGICAL_CLOCK_LANE, + DSI_LANE_MAX +}; + +/** + * enum dsi_data_lanes - BIT map for DSI data lanes + * This is used to identify the active DSI data lanes for + * various operations like DSI data lane enable/ULPS/clamp + * configurations. + * @DSI_DATA_LANE_0: BIT(DSI_LOGICAL_LANE_0) + * @DSI_DATA_LANE_1: BIT(DSI_LOGICAL_LANE_1) + * @DSI_DATA_LANE_2: BIT(DSI_LOGICAL_LANE_2) + * @DSI_DATA_LANE_3: BIT(DSI_LOGICAL_LANE_3) + * @DSI_CLOCK_LANE: BIT(DSI_LOGICAL_CLOCK_LANE) + */ +enum dsi_data_lanes { + DSI_DATA_LANE_0 = BIT(DSI_LOGICAL_LANE_0), + DSI_DATA_LANE_1 = BIT(DSI_LOGICAL_LANE_1), + DSI_DATA_LANE_2 = BIT(DSI_LOGICAL_LANE_2), + DSI_DATA_LANE_3 = BIT(DSI_LOGICAL_LANE_3), + DSI_CLOCK_LANE = BIT(DSI_LOGICAL_CLOCK_LANE) +}; + +/** + * enum dsi_phy_data_lanes - dsi physical lanes + * used for DSI logical to physical lane mapping + * @DSI_PHYSICAL_LANE_INVALID: Physical lane valid/invalid + * @DSI_PHYSICAL_LANE_0: Physical lane 0 + * @DSI_PHYSICAL_LANE_1: Physical lane 1 + * @DSI_PHYSICAL_LANE_2: Physical lane 2 + * @DSI_PHYSICAL_LANE_3: Physical lane 3 + */ +enum dsi_phy_data_lanes { + DSI_PHYSICAL_LANE_INVALID = 0, + DSI_PHYSICAL_LANE_0 = BIT(0), + DSI_PHYSICAL_LANE_1 = BIT(1), + DSI_PHYSICAL_LANE_2 = BIT(2), + DSI_PHYSICAL_LANE_3 = BIT(3) +}; + +enum dsi_lane_map_type_v1 { + DSI_LANE_MAP_0123, + DSI_LANE_MAP_3012, + DSI_LANE_MAP_2301, + DSI_LANE_MAP_1230, + DSI_LANE_MAP_0321, + DSI_LANE_MAP_1032, + DSI_LANE_MAP_2103, + DSI_LANE_MAP_3210, +}; + +/** + * lane_map: DSI logical <-> physical lane mapping + * lane_map_v1: Lane mapping for DSI controllers < v2.0 + * lane_map_v2: Lane mapping for DSI controllers >= 2.0 + */ +struct dsi_lane_map { + enum dsi_lane_map_type_v1 lane_map_v1; + u8 lane_map_v2[DSI_LANE_MAX - 1]; +}; + +/** + * enum dsi_trigger_type - dsi trigger type + * @DSI_TRIGGER_NONE: No trigger. + * @DSI_TRIGGER_TE: TE trigger. + * @DSI_TRIGGER_SEOF: Start or End of frame. + * @DSI_TRIGGER_SW: Software trigger. + * @DSI_TRIGGER_SW_SEOF: Software trigger and start/end of frame. + * @DSI_TRIGGER_SW_TE: Software and TE triggers. + * @DSI_TRIGGER_MAX: Max trigger values. + */ +enum dsi_trigger_type { + DSI_TRIGGER_NONE = 0, + DSI_TRIGGER_TE, + DSI_TRIGGER_SEOF, + DSI_TRIGGER_SW, + DSI_TRIGGER_SW_SEOF, + DSI_TRIGGER_SW_TE, + DSI_TRIGGER_MAX +}; + +/** + * enum dsi_color_swap_mode - color swap mode + * @DSI_COLOR_SWAP_RGB: + * @DSI_COLOR_SWAP_RBG: + * @DSI_COLOR_SWAP_BGR: + * @DSI_COLOR_SWAP_BRG: + * @DSI_COLOR_SWAP_GRB: + * @DSI_COLOR_SWAP_GBR: + */ +enum dsi_color_swap_mode { + DSI_COLOR_SWAP_RGB = 0, + DSI_COLOR_SWAP_RBG, + DSI_COLOR_SWAP_BGR, + DSI_COLOR_SWAP_BRG, + DSI_COLOR_SWAP_GRB, + DSI_COLOR_SWAP_GBR +}; + +/** + * enum dsi_dfps_type - Dynamic FPS support type + * @DSI_DFPS_NONE: Dynamic FPS is not supported. + * @DSI_DFPS_SUSPEND_RESUME: + * @DSI_DFPS_IMMEDIATE_CLK: + * @DSI_DFPS_IMMEDIATE_HFP: + * @DSI_DFPS_IMMEDIATE_VFP: + * @DSI_DPFS_MAX: + */ +enum dsi_dfps_type { + DSI_DFPS_NONE = 0, + DSI_DFPS_SUSPEND_RESUME, + DSI_DFPS_IMMEDIATE_CLK, + DSI_DFPS_IMMEDIATE_HFP, + DSI_DFPS_IMMEDIATE_VFP, + DSI_DFPS_MAX +}; + +/** + * enum dsi_dyn_clk_feature_type - Dynamic clock feature support type + * @DSI_DYN_CLK_TYPE_LEGACY: Constant FPS is not supported + * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: Constant FPS supported with + * change in hfp + * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: Constant FPS supported with + * change in vfp + * @DSI_DYN_CLK_TYPE_MAX: + */ +enum dsi_dyn_clk_feature_type { + DSI_DYN_CLK_TYPE_LEGACY = 0, + DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP, + DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP, + DSI_DYN_CLK_TYPE_MAX +}; + +/** + * enum dsi_cmd_set_type - DSI command set type + * @DSI_CMD_SET_PRE_ON: Panel pre on + * @DSI_CMD_SET_ON: Panel on + * @DSI_CMD_SET_POST_ON: Panel post on + * @DSI_CMD_SET_PRE_OFF: Panel pre off + * @DSI_CMD_SET_OFF: Panel off + * @DSI_CMD_SET_POST_OFF: Panel post off + * @DSI_CMD_SET_PRE_RES_SWITCH: Pre resolution switch + * @DSI_CMD_SET_RES_SWITCH: Resolution switch + * @DSI_CMD_SET_POST_RES_SWITCH: Post resolution switch + * @DSI_CMD_SET_CMD_TO_VID_SWITCH: Cmd to video mode switch + * @DSI_CMD_SET_POST_CMD_TO_VID_SWITCH: Post cmd to vid switch + * @DSI_CMD_SET_VID_TO_CMD_SWITCH: Video to cmd mode switch + * @DSI_CMD_SET_POST_VID_TO_CMD_SWITCH: Post vid to cmd switch + * @DSI_CMD_SET_PANEL_STATUS: Panel status + * @DSI_CMD_SET_LP1: Low power mode 1 + * @DSI_CMD_SET_LP2: Low power mode 2 + * @DSI_CMD_SET_NOLP: Low power mode disable + * @DSI_CMD_SET_PPS: DSC PPS command + * @DSI_CMD_SET_ROI: Panel ROI update + * @DSI_CMD_SET_TIMING_SWITCH: Timing switch + * @DSI_CMD_SET_POST_TIMING_SWITCH: Post timing switch + * @DSI_CMD_SET_QSYNC_ON Enable qsync mode + * @DSI_CMD_SET_QSYNC_OFF Disable qsync mode + * @DSI_CMD_SET_MAX + */ +enum dsi_cmd_set_type { + DSI_CMD_SET_PRE_ON = 0, + DSI_CMD_SET_ON, + DSI_CMD_SET_SP_ON, + DSI_CMD_SET_SP_OFF, + DSI_CMD_SET_POST_ON, + DSI_CMD_SET_PRE_OFF, + DSI_CMD_SET_OFF, + DSI_CMD_SET_POST_OFF, + DSI_CMD_SET_PRE_RES_SWITCH, + DSI_CMD_SET_RES_SWITCH, + DSI_CMD_SET_POST_RES_SWITCH, + DSI_CMD_SET_CMD_TO_VID_SWITCH, + DSI_CMD_SET_POST_CMD_TO_VID_SWITCH, + DSI_CMD_SET_VID_TO_CMD_SWITCH, + DSI_CMD_SET_POST_VID_TO_CMD_SWITCH, + DSI_CMD_SET_PANEL_STATUS, + DSI_CMD_SET_LP1, + DSI_CMD_SET_LP2, + DSI_CMD_SET_NOLP, + DSI_CMD_SET_PPS, + DSI_CMD_SET_ROI, + DSI_CMD_SET_TIMING_SWITCH, + DSI_CMD_SET_POST_TIMING_SWITCH, + DSI_CMD_SET_QSYNC_ON, + DSI_CMD_SET_QSYNC_OFF, + DSI_CMD_SET_HBM_BRIGHTNESS_ON, + DSI_CMD_SET_HBM_BRIGHTNESS_OFF, + DSI_CMD_SET_SEED_LP_ON_0, + DSI_CMD_SET_SEED_LP_ON_1, + DSI_CMD_SET_SEED_LP_ON_2, + DSI_CMD_SET_SEED_LP_OFF, + DSI_CMD_SET_HBM_ON_1, + DSI_CMD_SET_HBM_ON_2, + DSI_CMD_SET_HBM_ON_3, + DSI_CMD_SET_HBM_ON_4, + DSI_CMD_SET_HBM_ON_5, + DSI_CMD_SET_HBM_OFF, + DSI_CMD_SET_PANEL_SERIAL_NUMBER, + DSI_CMD_SET_AOD_ON_1, + DSI_CMD_SET_AOD_ON_2, + DSI_CMD_SET_AOD_ON_3, + DSI_CMD_SET_AOD_ON_4, + DSI_CMD_SET_AOD_ON_5, + DSI_CMD_SET_AOD_OFF, + DSI_CMD_AOD_OFF_HBM_ON_SETTING, + DSI_CMD_SET_AOD_OFF_NEW, + DSI_CMD_HBM_OFF_AOD_ON_SETTING, + DSI_CMD_REAL_AOD_OFF_HBM_ON_SETTING, + DSI_CMD_SET_AOD_OFF_SAMSUNG, +// DSI_CMD_SET_SRGB_ON, +// DSI_CMD_SET_SRGB_OFF, + DSI_CMD_SET_DCI_P3_ON, + DSI_CMD_SET_DCI_P3_OFF, + DSI_CMD_SET_NIGHT_ON, + DSI_CMD_SET_NIGHT_OFF, + DSI_CMD_SET_PANEL_ID, + DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ON, + DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ED_ON, + DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_SP_ON, + DSI_CMD_SET_PANEL_ID1, + DSI_CMD_SET_PANEL_ID2, + DSI_CMD_SET_PANEL_ID3, + DSI_CMD_SET_PANEL_ID4, + DSI_CMD_SET_PANEL_ID5, + DSI_CMD_SET_PANEL_ID6, + DSI_CMD_SET_PANEL_ID7, + DSI_CMD_SET_DDIC_CHECK_INFO, + DSI_CMD_SET_PANEL_SP_LEVEL, + DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF, + DSI_CMD_SET_ACL_MODE, + DSI_CMD_READ_SAMSUNG_PANEL_IC_V_REGISTER_ON, + DSI_CMD_SET_PANEL_IC_V, + DSI_CMD_READ_SAMSUNG_PANEL_IC_V_REGISTER_OFF, + DSI_CMD_SET_LCDINFO_PRE, + DSI_CMD_SET_LCDINFO_POST, + DSI_CMD_SET_CODE_INFO, + DSI_CMD_SET_STAGE_INFO, + DSI_CMD_SET_PRODUCTION_INFO, + DSI_CMD_SET_ESD_LOGREAD_PREREAD, + DSI_CMD_SET_GAMMA_FLASH_PRE_READ_1, + DSI_CMD_SET_GAMMA_FLASH_PRE_READ_2, + DSI_CMD_SET_GAMMA_FLASH_READ_FB, + DSI_CMD_SET_LEVEL2_KEY_ENABLE, + DSI_CMD_SET_GAMMA_OTP_READ_C8_SMRPS, + DSI_CMD_SET_GAMMA_OTP_READ_C8, + DSI_CMD_SET_GAMMA_OTP_READ_C9_SMRPS, + DSI_CMD_SET_GAMMA_OTP_READ_C9, + DSI_CMD_SET_GAMMA_OTP_READ_B3_SMRPS, + DSI_CMD_SET_GAMMA_OTP_READ_B3, + DSI_CMD_SET_LEVEL2_KEY_DISABLE, + DSI_CMD_SET_NATIVE_DISPLAY_P3_ON, + DSI_CMD_SET_NATIVE_DISPLAY_P3_OFF, + DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_ON, + DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_OFF, + DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_ON, + DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_OFF, + DSI_CMD_SET_113MHZ_OSC_ON, + DSI_CMD_POST_ON_BACKLIGHT, + DSI_CMD_LOADING_EFFECT_ON, + DSI_CMD_LOADING_EFFECT_OFF, + DSI_CMD_LOADING_CUSTOMER_RGB_ON, + DSI_CMD_LOADING_CUSTOMER_RGB_OFF, + DSI_CMD_LOADING_CUSTOMER_P3_ON, + DSI_CMD_LOADING_CUSTOMER_P3_OFF, + DSI_CMD_SET_PANEL_COMMAND, + DSI_CMD_SET_SEED_COMMAND, + DSI_CMD_SET_NATIVE_DISPLAY_P3_LOW_BACKLIGHT_ON, + DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_LOW_BACKLIGHT_ON, + DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_LOW_BACKLIGHT_ON, + DSI_CMD_LOADING_CUSTOMER_RGB_LOW_BACKLIGHT_ON, + DSI_CMD_LOADING_CUSTOMER_P3_LOW_BACKLIGHT_ON, + + DSI_CMD_SET_MAX +}; + +/** + * enum dsi_cmd_set_state - command set state + * @DSI_CMD_SET_STATE_LP: dsi low power mode + * @DSI_CMD_SET_STATE_HS: dsi high speed mode + * @DSI_CMD_SET_STATE_MAX + */ +enum dsi_cmd_set_state { + DSI_CMD_SET_STATE_LP = 0, + DSI_CMD_SET_STATE_HS, + DSI_CMD_SET_STATE_MAX +}; + +/** + * enum dsi_clk_gate_type - Type of clock to be gated. + * @PIXEL_CLK: DSI pixel clock. + * @BYTE_CLK: DSI byte clock. + * @DSI_PHY: DSI PHY. + * @DSI_CLK_ALL: All available DSI clocks + * @DSI_CLK_NONE: None of the clocks should be gated + */ +enum dsi_clk_gate_type { + PIXEL_CLK = 1, + BYTE_CLK = 2, + DSI_PHY = 4, + DSI_CLK_ALL = (PIXEL_CLK | BYTE_CLK | DSI_PHY), + DSI_CLK_NONE = 8, +}; + +/** + * enum dsi_phy_type - DSI phy types + * @DSI_PHY_TYPE_DPHY: + * @DSI_PHY_TYPE_CPHY: + */ +enum dsi_phy_type { + DSI_PHY_TYPE_DPHY, + DSI_PHY_TYPE_CPHY +}; + +/** + * enum dsi_te_mode - dsi te source + * @DSI_TE_ON_DATA_LINK: TE read from DSI link + * @DSI_TE_ON_EXT_PIN: TE signal on an external GPIO + */ +enum dsi_te_mode { + DSI_TE_ON_DATA_LINK = 0, + DSI_TE_ON_EXT_PIN, +}; + +/** + * enum dsi_video_traffic_mode - video mode pixel transmission type + * @DSI_VIDEO_TRAFFIC_SYNC_PULSES: Non-burst mode with sync pulses. + * @DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS: Non-burst mode with sync start events. + * @DSI_VIDEO_TRAFFIC_BURST_MODE: Burst mode using sync start events. + */ +enum dsi_video_traffic_mode { + DSI_VIDEO_TRAFFIC_SYNC_PULSES = 0, + DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS, + DSI_VIDEO_TRAFFIC_BURST_MODE, +}; + +/** + * struct dsi_cmd_desc - description of a dsi command + * @msg: dsi mipi msg packet + * @last_command: indicates whether the cmd is the last one to send + * @post_wait_ms: post wait duration + */ +struct dsi_cmd_desc { + struct mipi_dsi_msg msg; + bool last_command; + u32 post_wait_ms; +}; + +/** + * struct dsi_panel_cmd_set - command set of the panel + * @type: type of the command + * @state: state of the command + * @count: number of cmds + * @ctrl_idx: index of the dsi control + * @cmds: arry of cmds + */ +struct dsi_panel_cmd_set { + enum dsi_cmd_set_type type; + enum dsi_cmd_set_state state; + u32 count; + u32 ctrl_idx; + struct dsi_cmd_desc *cmds; +}; + +/** + * struct dsi_mode_info - video mode information dsi frame + * @h_active: Active width of one frame in pixels. + * @h_back_porch: Horizontal back porch in pixels. + * @h_sync_width: HSYNC width in pixels. + * @h_front_porch: Horizontal fron porch in pixels. + * @h_skew: + * @h_sync_polarity: Polarity of HSYNC (false is active low). + * @v_active: Active height of one frame in lines. + * @v_back_porch: Vertical back porch in lines. + * @v_sync_width: VSYNC width in lines. + * @v_front_porch: Vertical front porch in lines. + * @v_sync_polarity: Polarity of VSYNC (false is active low). + * @refresh_rate: Refresh rate in Hz. + * @clk_rate_hz: DSI bit clock rate per lane in Hz. + * @min_dsi_clk_hz: Min DSI bit clock to transfer in vsync time. + * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode + * panels in microseconds. + * @dsi_transfer_time_us: Specifies dsi transfer time for command mode. + * @dsc_enabled: DSC compression enabled. + * @dsc: DSC compression configuration. + * @roi_caps: Panel ROI capabilities. + */ +struct dsi_mode_info { + u32 h_active; + u32 h_back_porch; + u32 h_sync_width; + u32 h_front_porch; + u32 h_skew; + bool h_sync_polarity; + + u32 v_active; + u32 v_back_porch; + u32 v_sync_width; + u32 v_front_porch; + bool v_sync_polarity; + + u32 refresh_rate; + u64 clk_rate_hz; + u64 min_dsi_clk_hz; + u32 mdp_transfer_time_us; + u32 dsi_transfer_time_us; + bool dsc_enabled; + struct msm_display_dsc_info *dsc; + struct msm_roi_caps roi_caps; +}; + +/** + * struct dsi_split_link_config - Split Link Configuration + * @split_link_enabled: Split Link Enabled. + * @num_sublinks: Number of sublinks. + * @lanes_per_sublink: Number of lanes per sublink. + */ +struct dsi_split_link_config { + bool split_link_enabled; + u32 num_sublinks; + u32 lanes_per_sublink; +}; + +/** + * struct dsi_host_common_cfg - Host configuration common to video and cmd mode + * @dst_format: Destination pixel format. + * @data_lanes: Physical data lanes to be enabled. + * @num_data_lanes: Number of physical data lanes. + * @bpp: Number of bits per pixel. + * @en_crc_check: Enable CRC checks. + * @en_ecc_check: Enable ECC checks. + * @te_mode: Source for TE signalling. + * @mdp_cmd_trigger: MDP frame update trigger for command mode. + * @dma_cmd_trigger: Command DMA trigger. + * @cmd_trigger_stream: Command mode stream to trigger. + * @swap_mode: DSI color swap mode. + * @bit_swap_read: Is red color bit swapped. + * @bit_swap_green: Is green color bit swapped. + * @bit_swap_blue: Is blue color bit swapped. + * @t_clk_post: Number of byte clock cycles that the transmitter shall + * continue sending after last data lane has transitioned + * to LP mode. + * @t_clk_pre: Number of byte clock cycles that the high spped clock + * shall be driven prior to data lane transitions from LP + * to HS mode. + * @t_clk_pre_extend: Increment t_clk_pre counter by 2 byteclk if set to + * true, otherwise increment by 1 byteclk. + * @ignore_rx_eot: Ignore Rx EOT packets if set to true. + * @append_tx_eot: Append EOT packets for forward transmissions if set to + * true. + * @ext_bridge_mode: External bridge is connected. + * @force_hs_clk_lane: Send continuous clock to the panel. + * @phy_type: DPHY/CPHY is enabled for this panel. + * @dsi_split_link_config: Split Link Configuration. + * @byte_intf_clk_div: Determines the factor for calculating byte intf clock. + */ +struct dsi_host_common_cfg { + enum dsi_pixel_format dst_format; + enum dsi_data_lanes data_lanes; + u8 num_data_lanes; + u8 bpp; + bool en_crc_check; + bool en_ecc_check; + enum dsi_te_mode te_mode; + enum dsi_trigger_type mdp_cmd_trigger; + enum dsi_trigger_type dma_cmd_trigger; + u32 cmd_trigger_stream; + enum dsi_color_swap_mode swap_mode; + bool bit_swap_red; + bool bit_swap_green; + bool bit_swap_blue; + u32 t_clk_post; + u32 t_clk_pre; + bool t_clk_pre_extend; + bool ignore_rx_eot; + bool append_tx_eot; + bool ext_bridge_mode; + bool force_hs_clk_lane; + enum dsi_phy_type phy_type; + struct dsi_split_link_config split_link; + u32 byte_intf_clk_div; +}; + +/** + * struct dsi_video_engine_cfg - DSI video engine configuration + * @last_line_interleave_en: Allow command mode op interleaved on last line of + * video stream. + * @pulse_mode_hsa_he: Send HSA and HE following VS/VE packet if set to + * true. + * @hfp_lp11_en: Enter low power stop mode (LP-11) during HFP. + * @hbp_lp11_en: Enter low power stop mode (LP-11) during HBP. + * @hsa_lp11_en: Enter low power stop mode (LP-11) during HSA. + * @eof_bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP of + * last line of a frame. + * @bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP. + * @traffic_mode: Traffic mode for video stream. + * @vc_id: Virtual channel identifier. + * @dma_sched_line: Line number, after vactive end, at which command dma + * needs to be triggered. + */ +struct dsi_video_engine_cfg { + bool last_line_interleave_en; + bool pulse_mode_hsa_he; + bool hfp_lp11_en; + bool hbp_lp11_en; + bool hsa_lp11_en; + bool eof_bllp_lp11_en; + bool bllp_lp11_en; + enum dsi_video_traffic_mode traffic_mode; + u32 vc_id; + u32 dma_sched_line; +}; + +/** + * struct dsi_cmd_engine_cfg - DSI command engine configuration + * @max_cmd_packets_interleave Maximum number of command mode RGB packets to + * send with in one horizontal blanking period + * of the video mode frame. + * @wr_mem_start: DCS command for write_memory_start. + * @wr_mem_continue: DCS command for write_memory_continue. + * @insert_dcs_command: Insert DCS command as first byte of payload + * of the pixel data. + */ +struct dsi_cmd_engine_cfg { + u32 max_cmd_packets_interleave; + u32 wr_mem_start; + u32 wr_mem_continue; + bool insert_dcs_command; +}; + +/** + * struct dsi_host_config - DSI host configuration parameters. + * @panel_mode: Operation mode for panel (video or cmd mode). + * @common_config: Host configuration common to both Video and Cmd mode. + * @video_engine: Video engine configuration if panel is in video mode. + * @cmd_engine: Cmd engine configuration if panel is in cmd mode. + * @esc_clk_rate_hz: Esc clock frequency in Hz. + * @bit_clk_rate_hz: Bit clock frequency in Hz. + * @bit_clk_rate_hz_override: DSI bit clk rate override from dt/sysfs. + * @video_timing: Video timing information of a frame. + * @lane_map: Mapping between logical and physical lanes. + */ +struct dsi_host_config { + enum dsi_op_mode panel_mode; + struct dsi_host_common_cfg common_config; + union { + struct dsi_video_engine_cfg video_engine; + struct dsi_cmd_engine_cfg cmd_engine; + } u; + u64 esc_clk_rate_hz; + u64 bit_clk_rate_hz; + u64 bit_clk_rate_hz_override; + struct dsi_mode_info video_timing; + struct dsi_lane_map lane_map; +}; + +/** + * struct dsi_display_mode_priv_info - private mode info that will be attached + * with each drm mode + * @cmd_sets: Command sets of the mode + * @phy_timing_val: Phy timing values + * @phy_timing_len: Phy timing array length + * @panel_jitter: Panel jitter for RSC backoff + * @panel_prefill_lines: Panel prefill lines for RSC + * @mdp_transfer_time_us: Specifies the mdp transfer time for command mode + * panels in microseconds. + * @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels. + * @clk_rate_hz: DSI bit clock per lane in hz. + * @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time. + * @topology: Topology selected for the panel + * @dsc: DSC compression info + * @dsc_enabled: DSC compression enabled + * @roi_caps: Panel ROI capabilities + */ +struct dsi_display_mode_priv_info { + struct dsi_panel_cmd_set cmd_sets[DSI_CMD_SET_MAX]; + + u32 *phy_timing_val; + u32 phy_timing_len; + + u32 panel_jitter_numer; + u32 panel_jitter_denom; + u32 panel_prefill_lines; + u32 mdp_transfer_time_us; + u32 dsi_transfer_time_us; + u64 clk_rate_hz; + u64 min_dsi_clk_hz; + + struct msm_display_topology topology; + struct msm_display_dsc_info dsc; + bool dsc_enabled; + struct msm_roi_caps roi_caps; +}; + +/** + * struct dsi_display_mode - specifies mode for dsi display + * @timing: Timing parameters for the panel. + * @pixel_clk_khz: Pixel clock in Khz. + * @dsi_mode_flags: Flags to signal other drm components via private flags + * @panel_mode: Panel mode + * @is_preferred: Is mode preferred + * @priv_info: Mode private info + */ +struct dsi_display_mode { + struct dsi_mode_info timing; + u32 pixel_clk_khz; + u32 dsi_mode_flags; + enum dsi_op_mode panel_mode; + bool is_preferred; + struct dsi_display_mode_priv_info *priv_info; +}; + +/** + * struct dsi_rect - dsi rectangle representation + * Note: sde_rect is also using u16, this must be maintained for memcpy + */ +struct dsi_rect { + u16 x; + u16 y; + u16 w; + u16 h; +}; + +/** + * dsi_rect_intersect - intersect two rectangles + * @r1: first rectangle + * @r2: scissor rectangle + * @result: result rectangle, all 0's on no intersection found + */ +void dsi_rect_intersect(const struct dsi_rect *r1, + const struct dsi_rect *r2, + struct dsi_rect *result); + +/** + * dsi_rect_is_equal - compares two rects + * @r1: rect value to compare + * @r2: rect value to compare + * + * Returns true if the rects are same + */ +static inline bool dsi_rect_is_equal(struct dsi_rect *r1, + struct dsi_rect *r2) +{ + return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && + r1->h == r2->h; +} + +struct dsi_event_cb_info { + uint32_t event_idx; + void *event_usr_ptr; + + int (*event_cb)(void *event_usr_ptr, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); +}; + +/** + * enum dsi_error_status - various dsi errors + * @DSI_FIFO_OVERFLOW: DSI FIFO Overflow error + * @DSI_FIFO_UNDERFLOW: DSI FIFO Underflow error + * @DSI_LP_Rx_TIMEOUT: DSI LP/RX Timeout error + * @DSI_PLL_UNLOCK_ERR: DSI PLL unlock error + */ +enum dsi_error_status { + DSI_FIFO_OVERFLOW = 1, + DSI_FIFO_UNDERFLOW, + DSI_LP_Rx_TIMEOUT, + DSI_PLL_UNLOCK_ERR, + DSI_ERR_INTR_ALL, +}; + +/* structure containing the delays required for dynamic clk */ +struct dsi_dyn_clk_delay { + u32 pipe_delay; + u32 pipe_delay2; + u32 pll_delay; +}; + +/* dynamic refresh control bits */ +enum dsi_dyn_clk_control_bits { + DYN_REFRESH_INTF_SEL = 1, + DYN_REFRESH_SYNC_MODE, + DYN_REFRESH_SW_TRIGGER, + DYN_REFRESH_SWI_CTRL, +}; + +/* convert dsi pixel format into bits per pixel */ +static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt) +{ + switch (fmt) { + case DSI_PIXEL_FORMAT_RGB888: + case DSI_PIXEL_FORMAT_MAX: + return 24; + case DSI_PIXEL_FORMAT_RGB666: + case DSI_PIXEL_FORMAT_RGB666_LOOSE: + return 18; + case DSI_PIXEL_FORMAT_RGB565: + return 16; + case DSI_PIXEL_FORMAT_RGB111: + return 3; + case DSI_PIXEL_FORMAT_RGB332: + return 8; + case DSI_PIXEL_FORMAT_RGB444: + return 12; + } + return 24; +} +#endif /* _DSI_DEFS_H_ */ diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c new file mode 100644 index 0000000000000000000000000000000000000000..151d9d121ba4d4e48b6e6c395854a9dc25d235f2 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_display.c @@ -0,0 +1,11941 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/list.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/err.h> + +#include "msm_drv.h" +#include "sde_connector.h" +#include "msm_mmu.h" +#include "dsi_display.h" +#include "dsi_panel.h" +#include "dsi_ctrl.h" +#include "dsi_ctrl_hw.h" +#include "dsi_drm.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "sde_dbg.h" +#include "dsi_parser.h" +#include <drm/drm_panel.h> +#include <linux/notifier.h> +#include <linux/sched.h> +#include <linux/pm_qos.h> +#include <linux/cpufreq.h> +#include <linux/pm_wakeup.h> +#include <linux/input.h> +#include <linux/proc_fs.h> +#include "../sde/sde_trace.h" +#include "dsi_parser.h" +#include <linux/oem/boot_mode.h> +#define to_dsi_display(x) container_of(x, struct dsi_display, host) +#define INT_BASE_10 10 +#define NO_OVERRIDE -1 + +#define MISR_BUFF_SIZE 256 +#define ESD_MODE_STRING_MAX_LEN 256 +#define ESD_TRIGGER_STRING_MAX_LEN 10 + +#define MAX_NAME_SIZE 64 +#define INVALID_BL_VALUE 20190909 + +#define DSI_CLOCK_BITRATE_RADIX 10 +#define MAX_TE_SOURCE_ID 2 + +#define WU_SEED_REGISTER 0x67 +#define UG_SEED_REGISTER 0xB1 +#define SP_READ_LEVEL_INTERVAL_COUNT 3600 +static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; +static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN]; +static char SERIAL_NUMBER_flag = 0; +static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY] = { + {.boot_param = dsi_display_primary}, + {.boot_param = dsi_display_secondary}, +}; + +static const struct of_device_id dsi_display_dt_match[] = { + {.compatible = "qcom,dsi-display"}, + {} +}; +static int esd_black_count; +static int esd_greenish_count; +static struct dsi_display *primary_display; +static char reg_read_value[128] = {0}; +/* jack.jiao@MM 20200612 add for distinguish seed value for normal light and low light*/ +static seed_low_backlight = 40; + +int reg_read_len = 1; +EXPORT_SYMBOL(reg_read_len); + +#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) +char buf_Lotid[6]; + +typedef enum { + ToolB = 0, + ToolA = 1, + ToolA_HVS30 = 2, + Tool_Green = 10, +} eTool; + +typedef struct { + char LotID[6]; + int wafer_Start; + int wafer_End; + int HVS30; +} LotDBItem; + +LotDBItem ANA6705_ToolA_DB[109] = { + {"K2T7N", 0, 0, 0}, + {"K2T7P", 0, 0, 0}, + {"K2TK4", 0, 0, 0}, + {"K4ART", 1, 12, 1}, + {"K4C07", 0, 0, 1}, + {"K4C0A", 1, 12, 1}, + {"K4C7S", 0, 0, 1}, + {"K4C7T", 0, 0, 1}, + {"K4CCH", 0, 0, 1}, + {"K4CCN", 0, 0, 1}, + {"K4CCP", 0, 0, 1}, + {"K4CJL", 0, 0, 1}, + {"K4CNS", 0, 0, 1}, + {"K4C06", 0, 0, 1}, + {"K4CNW", 0, 0, 1}, + {"K4JGT", 0, 0, 1}, + {"K4F8J", 0, 0, 1}, + {"K4FFA", 0, 0, 1}, + {"K4F4G", 0, 0, 1}, + {"K4C82", 0, 0, 1}, + {"K4CJM", 0, 0, 1}, + {"K4CNT", 0, 0, 1}, + {"K4F0T", 0, 0, 1}, + {"K4F4K", 0, 0, 1}, + {"K4F4N", 0, 0, 1}, + {"K4JA8", 0, 0, 1}, + {"K4JA8", 0, 0, 1}, + {"K4J54", 0, 0, 1}, + {"K4F4P", 0, 0, 1}, + {"K4M9N", 0, 0, 1}, + {"K4J6F", 0, 0, 1}, + {"K4FFC", 0, 0, 1}, + {"K4JQP", 0, 0, 1}, + {"K4K5A", 0, 0, 1}, + {"K4K19", 0, 0, 1}, + {"K4K7L", 0, 0, 1}, + {"K4JW4", 0, 0, 1}, + {"K4MGK", 0, 0, 1}, + {"K4KTR", 0, 0, 1}, + {"K4L07", 0, 0, 1}, + {"K4L07", 0, 0, 1}, + {"K4MGJ", 0, 0, 1}, + {"K4JLA", 0, 0, 1}, + {"K4KTS", 0, 0, 1}, + {"K4MGL", 0, 0, 1}, + {"K4JJS", 0, 0, 1}, + {"K4PYR", 0, 0, 1}, + {"K4PS4", 0, 0, 1}, + {"K4QC2", 0, 0, 1}, + {"K4Q7K", 0, 0, 1}, + {"K4PS5", 0, 0, 1}, + {"K4Q3Q", 0, 0, 1}, + {"K4Q3R", 0, 0, 1}, + {"K4QC0", 0, 0, 1}, + {"K4QHT", 0, 0, 1}, + {"K4QC1", 0, 0, 1}, + {"K4QHW", 0, 0, 1}, + {"K4QMP", 0, 0, 1}, + {"K4QMQ", 0, 0, 1}, + {"K4QMR", 0, 0, 1}, + {"K4Q7L", 0, 0, 1}, + {"K4QRL", 0, 0, 1}, + {"K4QYM", 0, 0, 1}, + {"K4PYQ", 0, 0, 1}, + {"K4QYN", 0, 0, 1}, + {"K4R7A", 0, 0, 1}, + {"K4QRM", 0, 0, 1}, + {"K4R7F", 0, 0, 1}, + {"K4R3L", 0, 0, 1}, + {"K4QYP", 0, 0, 1}, + {"K4R3K", 0, 0, 1}, + {"K4RJ7", 0, 0, 1}, + {"K4R7C", 0, 0, 1}, + {"K4RC8", 0, 0, 1}, + {"K4RNW", 0, 0, 1}, + {"K4RS4", 0, 0, 1}, + {"K4RC9", 0, 0, 1}, + {"K4RJ8", 0, 0, 1}, + {"K4RNS", 0, 0, 1}, + {"K4RNT", 0, 0, 1}, + {"K4RS5", 0, 0, 1}, + {"K4RYL", 0, 0, 1}, + {"K4RYM", 0, 0, 1}, + {"K4S1S", 0, 0, 1}, + {"K4S78", 0, 0, 1}, + {"K4SAY", 0, 0, 1}, + {"K4SHS", 0, 0, 1}, + {"K4SHT", 0, 0, 1}, + {"K4S1T", 0, 0, 1}, + {"K4S77", 0, 0, 1}, + {"K4SC1", 0, 0, 1}, + {"K4SMM", 0, 0, 1}, + {"K4SC0", 0, 0, 1}, + {"K4SRA", 0, 0, 1}, + {"K4TAM", 0, 0, 1}, + {"K4TAN", 0, 0, 1}, + {"K5G14", 0, 0, 1}, + {"K5G16", 0, 0, 1}, + {"K5G15", 0, 0, 1}, + {"K5G4W", 0, 0, 1}, + {"K5G4Y", 0, 0, 1}, + {"K5G8W", 0, 0, 1}, + {"K5G8Y", 0, 0, 1}, + {"K5GFS", 0, 0, 1}, + {"K5GFT", 0, 0, 1}, + {"K5GFW", 0, 0, 1}, + {"K5GL5", 0, 0, 1}, + {"K5GL6", 0, 0, 1}, + {"K5GNY", 0, 0, 1} +}; + +LotDBItem ANA6705_ToolB_DB[164] = { + {"K2T30", 0, 0, 0}, + {"K2T2Y", 0, 0, 0}, + {"K2T35", 0, 0, 0}, + {"K2WJ7", 0, 0, 0}, + {"K2WJ7", 0, 0, 0}, + {"K2TPW", 0, 0, 0}, + {"K2W76", 0, 0, 0}, + {"K2TW7", 0, 0, 0}, + {"K2WJ6", 0, 0, 0}, + {"K2WJ6", 0, 0, 0}, + {"K2T7N", 0, 0, 0}, + {"K2T7P", 0, 0, 0}, + {"K2TK3", 0, 0, 0}, + {"K2TK4", 0, 0, 0}, + {"K2TPY", 0, 0, 0}, + {"K2TQ0", 0, 0, 0}, + {"K2TQ1", 0, 0, 0}, + {"K2TW8", 0, 0, 0}, + {"K2TW9", 0, 0, 0}, + {"K2TWA", 0, 0, 0}, + {"K2W2K", 0, 0, 0}, + {"K2W2L", 0, 0, 0}, + {"K2W2M", 0, 0, 0}, + {"K2W2N", 0, 0, 0}, + {"K2W75", 0, 0, 0}, + {"K2W77", 0, 0, 0}, + {"K2W78", 0, 0, 0}, + {"K2WCF", 0, 0, 0}, + {"K2WCG", 0, 0, 0}, + {"K2WCH", 0, 0, 0}, + {"K2WCJ", 0, 0, 0}, + {"K2WJ8", 0, 0, 0}, + {"K2WJ9", 0, 0, 0}, + {"K2WN8", 0, 0, 0}, + {"K2WN9", 0, 0, 0}, + {"K2WNC", 0, 0, 0}, + {"K2WNF", 0, 0, 0}, + {"K2WNH", 0, 0, 0}, + {"K2WSF", 0, 0, 0}, + {"K2WSG", 0, 0, 0}, + {"K2WSH", 0, 0, 0}, + {"K2WSJ", 0, 0, 0}, + {"K2WSK", 0, 0, 0}, + {"K2WSL", 0, 0, 0}, + {"K2Y14", 0, 0, 0}, + {"K2Y15", 0, 0, 0}, + {"K2Y16", 0, 0, 0}, + {"K2Y17", 0, 0, 0}, + {"K2Y18", 0, 0, 0}, + {"K2Y19", 0, 0, 0}, + {"K3C74", 0, 0, 0}, + {"K3FK0", 0, 0, 0}, + {"K2TF5", 0, 0, 0}, + {"K2TF7", 0, 0, 0}, + {"K2TK1", 0, 0, 0}, + {"K2TK2", 0, 0, 0}, + {"K2WNA", 0, 0, 0}, + {"K2Y13", 0, 0, 0}, + {"K4A0F", 0, 0, 0}, + {"K4A3C", 0, 0, 0}, + {"K3YSJ", 0, 0, 0}, + {"K4A6L", 0, 0, 0}, + {"K4A6M", 0, 0, 0}, + {"K4A83", 0, 0, 0}, + {"K4A83", 0, 0, 0}, + {"K4A83", 0, 0, 0}, + {"K4A80", 0, 0, 0}, + {"K3WYS", 0, 0, 0}, + {"K4AMP", 0, 0, 0}, + {"K3J0A", 0, 0, 0}, + {"K3TQY", 0, 0, 0}, + {"K4A6N", 0, 0, 0}, + {"K4A81", 0, 0, 0}, + {"K4A82", 0, 0, 0}, + {"K4AF1", 0, 0, 0}, + {"K4ALM", 0, 0, 0}, + {"K4ALN", 0, 0, 0}, + {"K4ALS", 0, 0, 0}, + {"K4ALT", 0, 0, 0}, + {"K4ALT", 0, 0, 0}, + {"K4ALW", 0, 0, 0}, + {"K4AMQ", 0, 0, 0}, + {"K4AMY", 0, 0, 0}, + {"K4AS0", 0, 0, 0}, + {"K3T2T", 0, 0, 0}, + {"K4ALR", 0, 0, 0}, + {"K4ART", 13, 25, 0}, + {"K4ARW", 0, 0, 0}, + {"K4AS2", 0, 0, 0}, + {"K4C4A", 0, 0, 0}, + {"K2T36", 0, 0, 0}, + {"K2T37", 0, 0, 0}, + {"K2T7M", 0, 0, 0}, + {"K3HT4", 0, 0, 0}, + {"K3PRW", 0, 0, 0}, + {"K4A84", 0, 0, 0}, + {"K4AF2", 0, 0, 0}, + {"K4ALQ", 0, 0, 0}, + {"K4AMT", 0, 0, 0}, + {"K4AS1", 0, 0, 0}, + {"K4AS3", 0, 0, 0}, + {"K4C04", 0, 0, 0}, + {"K4C05", 0, 0, 0}, + {"K4C08", 0, 0, 0}, + {"K4C0A", 13, 25, 0}, + {"K4C46", 0, 0, 0}, + {"K4C7R", 0, 0, 0}, + {"K4CJJ", 0, 0, 0}, + {"K4CSW", 0, 0, 0}, + {"K4FQW", 0, 0, 0}, + {"K4ARY", 0, 0, 0}, + {"K4ARY", 0, 0, 0}, + {"K4AMR", 0, 0, 0}, + {"K4CJH", 0, 0, 0}, + {"K4CP2", 0, 0, 0}, + {"K4CSS", 0, 0, 0}, + {"K4CT2", 0, 0, 0}, + {"K4CT3", 0, 0, 0}, + {"K4F0P", 0, 0, 0}, + {"K4F0Q", 0, 0, 0}, + {"K4F0R", 0, 0, 0}, + {"K4F0S", 0, 0, 0}, + {"K4F0W", 0, 0, 0}, + {"K4F0Y", 0, 0, 0}, + {"K4F10", 0, 0, 0}, + {"K4F4H", 0, 0, 0}, + {"K4F4J", 0, 0, 0}, + {"K4F4L", 0, 0, 0}, + {"K4F8G", 0, 0, 0}, + {"K4F8H", 0, 0, 0}, + {"K4F8L", 0, 0, 0}, + {"K4FQT", 0, 0, 0}, + {"K4GLQ", 0, 0, 0}, + {"K4GLR", 0, 0, 0}, + {"K4FFF", 0, 0, 0}, + {"K4FFG", 0, 0, 0}, + {"K2WNG", 0, 0, 0}, + {"K2WSC", 9, 25, 0}, + {"K4C44", 0, 0, 0}, + {"K4CCJ", 0, 0, 0}, + {"K4CT0", 0, 0, 0}, + {"K4CT1", 0, 0, 0}, + {"K4CP1", 0, 0, 0}, + {"K4CSY", 0, 0, 0}, + {"K4F8F", 0, 0, 0}, + {"K4C09", 0, 0, 0}, + {"K4C06", 13, 25, 0}, + {"K4C47", 0, 0, 0}, + {"K4C48", 0, 0, 0}, + {"K4C49", 0, 0, 0}, + {"K4C7W", 0, 0, 0}, + {"K4C80", 0, 0, 0}, + {"K4C81", 0, 0, 0}, + {"K4CCK", 0, 0, 0}, + {"K4CCL", 0, 0, 0}, + {"K4CCM", 0, 0, 0}, + {"K4CCQ", 0, 0, 0}, + {"K4CJC", 0, 0, 0}, + {"K4CJF", 0, 0, 0}, + {"K4CJG", 0, 0, 0}, + {"K4CJK", 0, 0, 0}, + {"K4CNY", 0, 0, 0}, + {"K4CP0", 0, 0, 0}, + {"K4CP3", 0, 0, 0} +}; + +LotDBItem ANA6706_ToolA_DB[121] = { + {"K4AN0", 1, 12, 0}, + {"K4AJG", 1, 12, 0}, + {"K4AS4", 1, 12, 0}, + {"K4H99", 0, 0, 0}, + {"K4C4C", 0, 0, 1}, + {"K4H9A", 0, 0, 1}, + {"K4HAC", 0, 0, 1}, + {"K4J55", 0, 0, 1}, + {"K4HAC", 0, 0, 1}, + {"K4HM2", 0, 0, 1}, + {"K4HPW", 0, 0, 1}, + {"K4HYW", 0, 0, 1}, + {"K4J56", 0, 0, 1}, + {"K4J6G", 0, 0, 1}, + {"K4J6H", 0, 0, 1}, + {"K4J6J", 0, 0, 1}, + {"K4JA9", 0, 0, 1}, + {"K4JAA", 0, 0, 1}, + {"K4JLH", 0, 0, 1}, + {"K4JQR", 0, 0, 1}, + {"K4JLG", 0, 0, 1}, + {"K4HJ0", 0, 0, 1}, + {"K4JAF", 0, 0, 1}, + {"K4JGW", 0, 0, 1}, + {"K4JGY", 0, 0, 1}, + {"K4JLF", 0, 0, 1}, + {"K4J29", 0, 0, 1}, + {"K4JAC", 0, 0, 1}, + {"K4JH0", 0, 0, 1}, + {"K4JW7", 0, 0, 1}, + {"K4HS4", 0, 0, 1}, + {"K4HYY", 0, 0, 1}, + {"K4K5G", 0, 0, 1}, + {"K4JLC", 0, 0, 1}, + {"K4KL8", 0, 0, 1}, + {"K4K1G", 0, 0, 1}, + {"K4K5C", 0, 0, 1}, + {"K4JQQ", 0, 0, 1}, + {"K4KG8", 0, 0, 1}, + {"K4KQL", 0, 0, 1}, + {"K4KTT", 0, 0, 1}, + {"K4KG9", 0, 0, 1}, + {"K4L5G", 0, 0, 1}, + {"K4K1C", 0, 0, 1}, + {"K4K5F", 0, 0, 1}, + {"K4K9L", 0, 0, 1}, + {"K4KG6", 0, 0, 1}, + {"K4KQK", 0, 0, 1}, + {"K4KG9", 0, 0, 1}, + {"K4JQS", 0, 0, 1}, + {"K4JW5", 0, 0, 1}, + {"K4KG7", 0, 0, 1}, + {"K4KL9", 0, 0, 1}, + {"K4K9H", 0, 0, 1}, + {"K4L9G", 0, 0, 1}, + {"K4K5H", 0, 0, 1}, + {"K4K9J", 0, 0, 1}, + {"K4K9K", 0, 0, 1}, + {"K4KLA", 0, 0, 1}, + {"K4L1J", 0, 0, 1}, + {"K4L1K", 0, 0, 1}, + {"K4L1L", 0, 0, 1}, + {"K4L5H", 0, 0, 1}, + {"K4L5J", 0, 0, 1}, + {"K4L9H", 0, 0, 1}, + {"K4L9J", 0, 0, 1}, + {"K4LGA", 0, 0, 1}, + {"K4LGC", 0, 0, 1}, + {"K4LKY", 0, 0, 1}, + {"K4LL0", 0, 0, 1}, + {"K4LL1", 0, 0, 1}, + {"K4LPQ", 0, 0, 1}, + {"K4LPR", 0, 0, 1}, + {"K4LPS", 0, 0, 1}, + {"K4LTP", 0, 0, 1}, + {"K4LTQ", 0, 0, 1}, + {"K4LTR", 0, 0, 1}, + {"K4M1F", 0, 0, 1}, + {"K4M1G", 0, 0, 1}, + {"K4M5M", 0, 0, 1}, + {"K4M5N", 0, 0, 1}, + {"K4M5P", 0, 0, 1}, + {"K4M9P", 0, 0, 1}, + {"K4M9Q", 0, 0, 1}, + {"K4MLL", 0, 0, 1}, + {"K4MLM", 0, 0, 1}, + {"K4MLN", 0, 0, 1}, + {"K4MQY", 0, 0, 1}, + {"K4MR0", 0, 0, 1}, + {"K4MWS", 0, 0, 1}, + {"K4MWT", 0, 0, 1}, + {"K4MWW", 0, 0, 1}, + {"K4N2K", 0, 0, 1}, + {"K4N2L", 0, 0, 1}, + {"K4N66", 0, 0, 1}, + {"K4N67", 0, 0, 1}, + {"K4N68", 0, 0, 1}, + {"K4NPW", 0, 0, 1}, + {"K4NPY", 0, 0, 1}, + {"K4NQ0", 0, 0, 1}, + {"K4NTS", 0, 0, 1}, + {"K4NTT", 0, 0, 1}, + {"K4NTW", 0, 0, 1}, + {"K4P1F", 0, 0, 1}, + {"K4P1G", 0, 0, 1}, + {"K4P1H", 0, 0, 1}, + {"K4P51", 0, 0, 1}, + {"K4P52", 0, 0, 1}, + {"K4P53", 0, 0, 1}, + {"K4P8M", 0, 0, 1}, + {"K4P8N", 0, 0, 1}, + {"K4SMN", 0, 0, 1}, + {"K4SMP", 0, 0, 1}, + {"K4SRC", 0, 0, 1}, + {"K4SRF", 0, 0, 1}, + {"K4SY4", 0, 0, 1}, + {"K4SY5", 0, 0, 1}, + {"K4T6T", 0, 0, 1}, + {"K4T6W", 0, 0, 1}, + {"K4TAP", 0, 0, 1}, + {"K4TAQ", 0, 0, 1} +}; + +LotDBItem ANA6706_ToolB_DB[8] = { + {"K4A6P", 0, 0, 0}, + {"K4C0C", 0, 0, 0}, + {"K4A85", 0, 0, 0}, + {"K4AF3", 0, 0, 0}, + {"K4AN0", 13, 25, 0}, + {"K4AJG", 13, 25, 0}, + {"K4AS4", 13, 24, 0}, + {"K4HAR", 0, 0, 0}, +}; + +LotDBItem ANA6706_Green[18] = { + {"K4C4C", 0, 0 ,0}, + {"K4H9A", 0, 0 ,0}, + {"K4HAR", 0, 0 ,0}, + {"K4HJ0", 0, 0 ,0}, + {"K4HM2", 0, 0 ,0}, + {"K4HM3", 0, 0 ,0}, + {"K4HPW", 0, 0 ,0}, + {"K4HS4", 0, 0 ,0}, + {"K4HYW", 0, 0 ,0}, + {"K4HYY", 0, 0 ,0}, + {"K4J29", 0, 0 ,0}, + {"K4J55", 0, 0 ,0}, + {"K4J6H", 0, 0 ,0}, + {"K4J6J", 0, 0 ,0}, + {"K4JAA", 0, 0 ,0}, + {"K4JAC", 0, 0 ,0}, + {"K4JH0", 0, 0 ,0}, + {"K4JW8", 0, 0 ,0}, +}; + +void extractLotID(unsigned char* chipID, char *szLotID) +{ + int i; + unsigned long lotValue = (chipID[0] << 14) + (chipID[1] << 6) + (chipID[2] >> 2); + + szLotID[0] = 'K'; + szLotID[1] = ((long)(lotValue / (36 * 36 * 36)) % 36) + 'A'; + + szLotID[2] = ((long)(lotValue / (36 * 36)) % 36) + 'A'; + szLotID[3] = ((long)(lotValue / 36) % 36) + 'A'; + szLotID[4] = (lotValue % 36) + 'A'; + + for (i = 1; i < 5; i++) { + if (szLotID[i] > 90) + szLotID[i] = (szLotID[i] - 91) + '0'; + } +} + + +int extractWaferNumber(unsigned char* chipID) +{ + int noWafer; + noWafer = ((chipID[2] & 0x03) << 3) + (chipID[3] >> 5); + return noWafer; +} + +eTool discrimination_ANA6705_ToolsType(char* szLotID, int WaferNumber) +{ + int i; + int count = sizeof(ANA6705_ToolA_DB) / sizeof(LotDBItem); + bool bFound = false; + eTool toolType; + for (i = 0; i < count; i++) { + if (strncmp(szLotID, ANA6705_ToolA_DB[i].LotID, 5) == 0) { + if (ANA6705_ToolA_DB[i].wafer_Start > 0) { + if (WaferNumber >= ANA6705_ToolA_DB[i].wafer_Start && WaferNumber <= ANA6705_ToolA_DB[i].wafer_End) { + bFound = true; + if (ANA6705_ToolA_DB[i].HVS30) + toolType = ToolA_HVS30; + else + toolType = ToolA; + } + break; + } + else { + bFound = true; + if (ANA6705_ToolA_DB[i].HVS30) + toolType = ToolA_HVS30; + else + toolType = ToolA; + + break; + } + } + } + + if (bFound == false) + toolType = ToolB; + + return toolType; +} + + +eTool discrimination_ANA6706_ToolsType(char* szLotID, int WaferNumber) +{ + int i; + int count = sizeof(ANA6706_ToolA_DB) / sizeof(LotDBItem); + bool bFound = false; + eTool toolType; + for (i = 0; i < count; i++) { + if (strncmp(szLotID, ANA6706_ToolA_DB[i].LotID, 5) == 0) { + if (ANA6706_ToolA_DB[i].wafer_Start > 0) { + if (WaferNumber >= ANA6706_ToolA_DB[i].wafer_Start && WaferNumber <= ANA6706_ToolA_DB[i].wafer_End) { + bFound = true; + if (ANA6706_ToolA_DB[i].HVS30) + toolType = ToolA_HVS30; + else + toolType = ToolA; + } + break; + } + else { + bFound = true; + if (ANA6706_ToolA_DB[i].HVS30) + toolType = ToolA_HVS30; + else + toolType = ToolA; + + break; + } + } + } + + if (bFound == false) + toolType = ToolB; + + return toolType; +} + +static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display, + u32 mask, bool enable) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + dsi_ctrl_mask_error_status_interrupts(ctrl->ctrl, mask, enable); + } +} + +static int dsi_display_config_clk_gating(struct dsi_display *display, + bool enable) +{ + int rc = 0, i = 0; + struct dsi_display_ctrl *mctrl, *ctrl; + enum dsi_clk_gate_type clk_selection; + enum dsi_clk_gate_type const default_clk_select = PIXEL_CLK | DSI_PHY; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (display->panel->host_config.force_hs_clk_lane) { + DSI_DEBUG("no dsi clock gating for continuous clock mode\n"); + return 0; + } + + mctrl = &display->ctrl[display->clk_master_idx]; + if (!mctrl) { + DSI_ERR("Invalid controller\n"); + return -EINVAL; + } + + clk_selection = display->clk_gating_config; + + if (!enable) { + /* for disable path, make sure to disable all clk gating */ + clk_selection = DSI_CLK_ALL; + } else if (!clk_selection || clk_selection > DSI_CLK_NONE) { + /* Default selection, no overrides */ + clk_selection = default_clk_select; + } else if (clk_selection == DSI_CLK_NONE) { + clk_selection = 0; + } + + DSI_DEBUG("%s clock gating Byte:%s Pixel:%s PHY:%s\n", + enable ? "Enabling" : "Disabling", + clk_selection & BYTE_CLK ? "yes" : "no", + clk_selection & PIXEL_CLK ? "yes" : "no", + clk_selection & DSI_PHY ? "yes" : "no"); + rc = dsi_ctrl_config_clk_gating(mctrl->ctrl, enable, clk_selection); + if (rc) { + DSI_ERR("[%s] failed to %s clk gating for clocks %d, rc=%d\n", + display->name, enable ? "enable" : "disable", + clk_selection, rc); + return rc; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == mctrl)) + continue; + /** + * In Split DSI usecase we should not enable clock gating on + * DSI PHY1 to ensure no display atrifacts are seen. + */ + clk_selection &= ~DSI_PHY; + rc = dsi_ctrl_config_clk_gating(ctrl->ctrl, enable, + clk_selection); + if (rc) { + DSI_ERR("[%s] failed to %s clk gating for clocks %d, rc=%d\n", + display->name, enable ? "enable" : "disable", + clk_selection, rc); + return rc; + } + } + + return 0; +} + +static void dsi_display_set_ctrl_esd_check_flag(struct dsi_display *display, + bool enable) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + ctrl->ctrl->esd_check_underway = enable; + } +} + +static void dsi_display_ctrl_irq_update(struct dsi_display *display, bool en) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + dsi_ctrl_irq_update(ctrl->ctrl, en); + } +} + +void dsi_rect_intersect(const struct dsi_rect *r1, + const struct dsi_rect *r2, + struct dsi_rect *result) +{ + int l, t, r, b; + + if (!r1 || !r2 || !result) + return; + + l = max(r1->x, r2->x); + t = max(r1->y, r2->y); + r = min((r1->x + r1->w), (r2->x + r2->w)); + b = min((r1->y + r1->h), (r2->y + r2->h)); + + if (r <= l || b <= t) { + memset(result, 0, sizeof(*result)); + } else { + result->x = l; + result->y = t; + result->w = r - l; + result->h = b - t; + } +} + +extern int aod_layer_hide; +int dsi_display_set_backlight(struct drm_connector *connector, + void *display, u32 bl_lvl) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + u32 bl_scale, bl_scale_sv; + u64 bl_temp; + int rc = 0; + static int gamma_read_flag; + static int sp_read_count; + int old_backlight; + + if (dsi_display == NULL || dsi_display->panel == NULL) + return -EINVAL; + + panel = dsi_display->panel; + old_backlight = panel->bl_config.bl_level; + mutex_lock(&panel->panel_lock); + if (!dsi_panel_initialized(panel)) { + if (bl_lvl != INVALID_BL_VALUE) { + panel->hbm_backlight = bl_lvl; + panel->bl_config.bl_level = bl_lvl; + } + DSI_ERR("hbm_backlight = %d\n", panel->hbm_backlight); + rc = -EINVAL; + goto error; + } + if (bl_lvl != INVALID_BL_VALUE) + panel->bl_config.bl_level = bl_lvl; + else + bl_lvl = panel->bl_config.bl_level; + if (strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) { + if (bl_lvl != 0 && bl_lvl != INVALID_BL_VALUE + && panel->bl_config.bl_level == 0) { + if (panel->naive_display_p3_mode) { + msleep(20); + dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_P3_ON); + DSI_ERR("Send DSI_CMD_SET_NATIVE_DISPLAY_P3_ON cmds\n"); + } + if (panel->naive_display_wide_color_mode) { + msleep(20); + dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_ON); + DSI_ERR("Send DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_ON cmds\n"); + } + if (panel->naive_display_srgb_color_mode) { + msleep(20); + dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_ON); + DSI_ERR("Send DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_ON cmds\n"); + } + if (panel->naive_display_customer_srgb_mode) { + dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_ON); + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_RGB_ON cmds\n"); + } else { + dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_OFF); + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_RGB_OFF cmds\n"); + } + if (panel->naive_display_customer_p3_mode) { + dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_ON); + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_P3_ON cmds\n"); + } else { + dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_OFF); + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_P3_OFF cmds\n"); + } + } + } + + /* scale backlight */ + bl_scale = panel->bl_config.bl_scale; + bl_temp = bl_lvl * bl_scale / MAX_BL_SCALE_LEVEL; + + bl_scale_sv = panel->bl_config.bl_scale_sv; + bl_temp = (u32)bl_temp * bl_scale_sv / MAX_SV_BL_SCALE_LEVEL; + + DSI_DEBUG("bl_scale = %u, bl_scale_sv = %u, bl_lvl = %u\n", + bl_scale, bl_scale_sv, (u32)bl_temp); + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_backlight(panel, (u32)bl_temp); + if (rc) + DSI_ERR("unable to set backlight\n"); + + if((old_backlight >= seed_low_backlight && bl_lvl < seed_low_backlight) + || (old_backlight < seed_low_backlight && bl_lvl >= seed_low_backlight)) { + if (panel->naive_display_p3_mode) { + if (bl_lvl >= seed_low_backlight) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_P3_ON); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_P3_LOW_BACKLIGHT_ON); + } + DSI_ERR("Send DSI_CMD_SET_NATIVE_DISPLAY_P3_ON cmds. the backlight is %d.\n", bl_lvl); + } + if (panel->naive_display_wide_color_mode) { + if (bl_lvl >= seed_low_backlight) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_ON); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_LOW_BACKLIGHT_ON); + } + DSI_ERR("Send DSI_CMD_SET_NATIVE_DISPLAY_WIDE_ON cmds. the backlight is %d.\n", bl_lvl); + } + if (panel->naive_display_srgb_color_mode) { + if (bl_lvl >= seed_low_backlight) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_ON); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_LOW_BACKLIGHT_ON); + } + DSI_ERR("Send DSI_CMD_SET_NATIVE_DISPLAY_SRGB_ON cmds. the backlight is %d.\n", bl_lvl); + } + if (panel->naive_display_customer_srgb_mode) { + if (bl_lvl >= seed_low_backlight) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_ON); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_LOW_BACKLIGHT_ON); + } + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_RGB_ON cmds. the backlight is %d.\n", bl_lvl); + } + if (panel->naive_display_customer_p3_mode) { + if (bl_lvl >= seed_low_backlight) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_ON); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_LOW_BACKLIGHT_ON); + } + DSI_ERR("Send DSI_CMD_LOADING_CUSTOMER_RGB_ON cmds. the backlight is %d.\n", bl_lvl); + } + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&panel->panel_lock); + if(((strcmp(dsi_display->panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0 ) || + (strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0 )) && (0 == SERIAL_NUMBER_flag)) { + dsi_display_get_serial_number_AT(connector); + } + if ((gamma_read_flag < 2) && ((strcmp(dsi_display->panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0))) { + if (gamma_read_flag < 1) { + gamma_read_flag++; + } + else { + schedule_delayed_work(&dsi_display->panel->gamma_read_work, 0); + gamma_read_flag++; + } + } + + if ((sp_read_count < 2) && ((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) + || (strcmp(dsi_display->panel->name, "samsung ana6706 dsc cmd mode panel") == 0))) { + if (sp_read_count < 1) { + sp_read_count++; + } + else { + dsi_display_sp_read(dsi_display); + sp_read_count++; + } + } + return rc; +} + +int dsi_display_sp_read(struct dsi_display *dsi_display) +{ + int rc = 0; + struct dsi_panel *panel = NULL; + + DSI_ERR("%s start\n", __func__); + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", dsi_display->name, rc); + goto error; + } + + dsi_display_get_sp_level(dsi_display, panel); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI clocks, rc=%d\n", dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&dsi_display->display_lock); + DSI_ERR("%s end\n", __func__); + return rc; +} + +int dsi_display_get_sp_level(struct dsi_display *dsi_display, struct dsi_panel *panel) +{ + int rc = 0; + u32 flags = 0; + u32 count = 0; + u8 sp_register[1] = {0}; + + struct dsi_cmd_desc *cmds; + struct dsi_display_ctrl *m_ctrl; + struct dsi_display_mode *mode; + + DSI_ERR("%s start\n", __func__); + + m_ctrl = &dsi_display->ctrl[dsi_display->cmd_master_idx]; + + if (!panel || !m_ctrl) + return -EINVAL; + + rc = dsi_display_cmd_engine_enable(dsi_display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EPERM; + } + + dsi_panel_acquire_panel_lock(panel); + mode = dsi_display->panel->cur_mode; + + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_SP_ON].count; + if (!count) { + DSI_ERR("This panel does not support sp register reading\n"); + goto exit; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_SP_ON); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_SP_ON commands\n"); + goto exit; + } + } + + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_SP_LEVEL].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto exit; + cmds->msg.rx_buf = sp_register; + cmds->msg.rx_len = 1; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) { + DSI_ERR("Failed to read DSI_CMD_SET_PANEL_SP_LEVEL rc=%d\n", rc); + goto exit; + } + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF].count; + if (!count) { + DSI_ERR("This panel does not support sp register reading\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF commands\n"); + goto exit; + } + } + + if (sp_register[0] > 2) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SP_ON].count; + if (!count) { + DSI_ERR("This panel does not support sp on\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SP_ON); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_SP_ON commands\n"); + goto exit; + } + sp_read_flag = SP_READ_SUCCESS; + } + DSI_ERR("sp level is %02x, sp on\n", sp_register[0]); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SP_OFF].count; + if (!count) { + DSI_ERR("This panel does not support sp off\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SP_OFF); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_SP_OFF commands\n"); + goto exit; + } + sp_read_flag = SP_READ_ERROR; + } + DSI_ERR("sp level is %02x, sp off\n", sp_register[0]); + } + +exit: + dsi_panel_release_panel_lock(panel); + dsi_display_cmd_engine_disable(dsi_display); + DSI_ERR("%s end\n", __func__); + return rc; +} + +int dsi_display_cmd_engine_enable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + mutex_lock(&m_ctrl->ctrl->ctrl_lock); + + if (display->cmd_engine_refcount > 0) { + display->cmd_engine_refcount++; + goto done; + } + + rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_ERR("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto done; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_ERR("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto error_disable_master; + } + } + + display->cmd_engine_refcount++; + goto done; +error_disable_master: + (void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); +done: + mutex_unlock(&m_ctrl->ctrl->ctrl_lock); + return rc; +} + +int dsi_display_cmd_engine_disable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + mutex_lock(&m_ctrl->ctrl->ctrl_lock); + + if (display->cmd_engine_refcount == 0) { + DSI_ERR("[%s] Invalid refcount\n", display->name); + goto done; + } else if (display->cmd_engine_refcount > 1) { + display->cmd_engine_refcount--; + goto done; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_OFF); + if (rc) + DSI_ERR("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + } + + rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); + if (rc) { + DSI_ERR("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto error; + } + +error: + display->cmd_engine_refcount = 0; +done: + mutex_unlock(&m_ctrl->ctrl->ctrl_lock); + return rc; +} + +static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach) +{ + struct dsi_display *display; + struct dsi_display_ctrl *display_ctrl; + int rc, cnt; + + if (!cb_data) { + DSI_ERR("aspace cb called with invalid cb_data\n"); + return; + } + display = (struct dsi_display *)cb_data; + + /* + * acquire panel_lock to make sure no commands are in-progress + * while detaching the non-secure context banks + */ + dsi_panel_acquire_panel_lock(display->panel); + + if (is_detach) { + /* invalidate the stored iova */ + display->cmd_buffer_iova = 0; + + /* return the virtual address mapping */ + msm_gem_put_vaddr(display->tx_cmd_buf); + msm_gem_vunmap(display->tx_cmd_buf, OBJ_LOCK_NORMAL); + + } else { + rc = msm_gem_get_iova(display->tx_cmd_buf, + display->aspace, &(display->cmd_buffer_iova)); + if (rc) { + DSI_ERR("failed to get the iova rc %d\n", rc); + goto end; + } + + display->vaddr = + (void *) msm_gem_get_vaddr(display->tx_cmd_buf); + + if (IS_ERR_OR_NULL(display->vaddr)) { + DSI_ERR("failed to get va rc %d\n", rc); + goto end; + } + } + + display_for_each_ctrl(cnt, display) { + display_ctrl = &display->ctrl[cnt]; + display_ctrl->ctrl->cmd_buffer_size = display->cmd_buffer_size; + display_ctrl->ctrl->cmd_buffer_iova = display->cmd_buffer_iova; + display_ctrl->ctrl->vaddr = display->vaddr; + display_ctrl->ctrl->secure_mode = is_detach; + } + +end: + /* release panel_lock */ + dsi_panel_release_panel_lock(display->panel); +} + +static irqreturn_t dsi_display_panel_te_irq_handler(int irq, void *data) +{ + struct dsi_display *display = (struct dsi_display *)data; + + /* + * This irq handler is used for sole purpose of identifying + * ESD attacks on panel and we can safely assume IRQ_HANDLED + * in case of display not being initialized yet + */ + if (!display) + return IRQ_HANDLED; + + SDE_EVT32(SDE_EVTLOG_FUNC_CASE1); + complete_all(&display->esd_te_gate); + return IRQ_HANDLED; +} + +static void dsi_display_change_te_irq_status(struct dsi_display *display, + bool enable) +{ + if (!display) { + DSI_ERR("Invalid params\n"); + return; + } + + /* Handle unbalanced irq enable/disable calls */ + if (enable && !display->is_te_irq_enabled) { + enable_irq(gpio_to_irq(display->disp_te_gpio)); + display->is_te_irq_enabled = true; + } else if (!enable && display->is_te_irq_enabled) { + disable_irq(gpio_to_irq(display->disp_te_gpio)); + display->is_te_irq_enabled = false; + } +} + +static void dsi_display_register_te_irq(struct dsi_display *display) +{ + int rc = 0; + struct platform_device *pdev; + struct device *dev; + unsigned int te_irq; + + pdev = display->pdev; + if (!pdev) { + DSI_ERR("invalid platform device\n"); + return; + } + + dev = &pdev->dev; + if (!dev) { + DSI_ERR("invalid device\n"); + return; + } + + if (!gpio_is_valid(display->disp_te_gpio)) { + rc = -EINVAL; + goto error; + } + + init_completion(&display->esd_te_gate); + te_irq = gpio_to_irq(display->disp_te_gpio); + + /* Avoid deferred spurious irqs with disable_irq() */ + irq_set_status_flags(te_irq, IRQ_DISABLE_UNLAZY); + + rc = devm_request_irq(dev, te_irq, dsi_display_panel_te_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "TE_GPIO", display); + if (rc) { + DSI_ERR("TE request_irq failed for ESD rc:%d\n", rc); + irq_clear_status_flags(te_irq, IRQ_DISABLE_UNLAZY); + goto error; + } + + disable_irq(te_irq); + display->is_te_irq_enabled = false; + + return; + +error: + /* disable the TE based ESD check */ + DSI_WARN("Unable to register for TE IRQ\n"); + if (display->panel->esd_config.status_mode == ESD_MODE_PANEL_TE) + display->panel->esd_config.esd_enabled = false; +} + +/* Allocate memory for cmd dma tx buffer */ +static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display) +{ + int rc = 0, cnt = 0; + struct dsi_display_ctrl *display_ctrl; + + display->tx_cmd_buf = msm_gem_new(display->drm_dev, + SZ_4K, + MSM_BO_UNCACHED); + + if ((display->tx_cmd_buf) == NULL) { + DSI_ERR("Failed to allocate cmd tx buf memory\n"); + rc = -ENOMEM; + goto error; + } + + display->cmd_buffer_size = SZ_4K; + + display->aspace = msm_gem_smmu_address_space_get( + display->drm_dev, MSM_SMMU_DOMAIN_UNSECURE); + if (!display->aspace) { + DSI_ERR("failed to get aspace\n"); + rc = -EINVAL; + goto free_gem; + } + /* register to aspace */ + rc = msm_gem_address_space_register_cb(display->aspace, + dsi_display_aspace_cb_locked, (void *)display); + if (rc) { + DSI_ERR("failed to register callback %d\n", rc); + goto free_gem; + } + + rc = msm_gem_get_iova(display->tx_cmd_buf, display->aspace, + &(display->cmd_buffer_iova)); + if (rc) { + DSI_ERR("failed to get the iova rc %d\n", rc); + goto free_aspace_cb; + } + + display->vaddr = + (void *) msm_gem_get_vaddr(display->tx_cmd_buf); + if (IS_ERR_OR_NULL(display->vaddr)) { + DSI_ERR("failed to get va rc %d\n", rc); + rc = -EINVAL; + goto put_iova; + } + + display_for_each_ctrl(cnt, display) { + display_ctrl = &display->ctrl[cnt]; + display_ctrl->ctrl->cmd_buffer_size = SZ_4K; + display_ctrl->ctrl->cmd_buffer_iova = + display->cmd_buffer_iova; + display_ctrl->ctrl->vaddr = display->vaddr; + display_ctrl->ctrl->tx_cmd_buf = display->tx_cmd_buf; + } + + return rc; + +put_iova: + msm_gem_put_iova(display->tx_cmd_buf, display->aspace); +free_aspace_cb: + msm_gem_address_space_unregister_cb(display->aspace, + dsi_display_aspace_cb_locked, display); +free_gem: + mutex_lock(&display->drm_dev->struct_mutex); + msm_gem_free_object(display->tx_cmd_buf); + mutex_unlock(&display->drm_dev->struct_mutex); +error: + return rc; +} + +static bool dsi_display_validate_reg_read(struct dsi_panel *panel) +{ + int i, j = 0; + int len = 0, *lenp; + int group = 0, count = 0; + struct drm_panel_esd_config *config; + + if (!panel) + return false; + + config = &(panel->esd_config); + + lenp = config->status_valid_params ?: config->status_cmds_rlen; + count = config->status_cmd.count; + + for (i = 0; i < count; i++) + len += lenp[i]; + + for (i = 0; i < len; i++) + j += len; + + for (j = 0; j < config->groups; ++j) { + for (i = 0; i < len; ++i) { + if (config->return_buf[i] != + config->status_value[group + i]) { + DRM_ERROR("mismatch: 0x%x\n", + config->return_buf[i]); + break; + } + } + + if (i == len) + return true; + group += len; + } + + return false; +} + +static void dsi_display_parse_te_data(struct dsi_display *display) +{ + struct platform_device *pdev; + struct device *dev; + int rc = 0; + u32 val = 0; + + pdev = display->pdev; + if (!pdev) { + DSI_ERR("Invalid platform device\n"); + return; + } + + dev = &pdev->dev; + if (!dev) { + DSI_ERR("Invalid platform device\n"); + return; + } + + display->disp_te_gpio = of_get_named_gpio(dev->of_node, + "qcom,platform-te-gpio", 0); + + if (display->fw) + rc = dsi_parser_read_u32(display->parser_node, + "qcom,panel-te-source", &val); + else + rc = of_property_read_u32(dev->of_node, + "qcom,panel-te-source", &val); + + if (rc || (val > MAX_TE_SOURCE_ID)) { + DSI_ERR("invalid vsync source selection\n"); + val = 0; + } + + display->te_source = val; +} + +static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel) +{ + int i, rc = 0, count = 0, start = 0, *lenp; + struct drm_panel_esd_config *config; + struct dsi_cmd_desc *cmds; + u32 flags = 0; + + if (!panel || !ctrl || !ctrl->ctrl) + return -EINVAL; + + /* + * When DSI controller is not in initialized state, we do not want to + * report a false ESD failure and hence we defer until next read + * happen. + */ + if (!dsi_ctrl_validate_host_state(ctrl->ctrl)) + return 1; + + config = &(panel->esd_config); + lenp = config->status_valid_params ?: config->status_cmds_rlen; + count = config->status_cmd.count; + cmds = config->status_cmd.cmds; + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ | + DSI_CTRL_CMD_CUSTOM_DMA_SCHED); + + for (i = 0; i < count; ++i) { + memset(config->status_buf, 0x0, SZ_4K); + if (cmds[i].last_command) { + cmds[i].msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + if (config->status_cmd.state == DSI_CMD_SET_STATE_LP) + cmds[i].msg.flags |= MIPI_DSI_MSG_USE_LPM; + cmds[i].msg.rx_buf = config->status_buf; + cmds[i].msg.rx_len = config->status_cmds_rlen[i]; + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, &flags); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + return rc; + } + + memcpy(config->return_buf + start, + config->status_buf, lenp[i]); + start += lenp[i]; + } + + return rc; +} + +static int dsi_display_validate_status(struct dsi_display_ctrl *ctrl, + struct dsi_panel *panel) +{ + int rc = 0; + + rc = dsi_display_read_status(ctrl, panel); + if (rc <= 0) { + goto exit; + } else { + /* + * panel status read successfully. + * check for validity of the data read back. + */ + rc = dsi_display_validate_reg_read(panel); + if (!rc) { + rc = -EINVAL; + goto exit; + } + } + +exit: + return rc; +} + +static int dsi_panel_tx_cmd_set_op(struct dsi_panel *panel, + enum dsi_cmd_set_type type) +{ + int rc = 0, i = 0; + ssize_t len; + struct dsi_cmd_desc *cmds; + u32 count; + enum dsi_cmd_set_state state; + struct dsi_display_mode *mode; + const struct mipi_dsi_host_ops *ops = panel->host->ops; + if (!panel || !panel->cur_mode) + return -EINVAL; + + + mode = panel->cur_mode; + + cmds = mode->priv_info->cmd_sets[type].cmds; + count = mode->priv_info->cmd_sets[type].count; + state = mode->priv_info->cmd_sets[type].state; + + if (count == 0) { + DSI_DEBUG("[%s] No commands to be sent for state(%d)\n", + panel->name, type); + goto error; + } + for (i = 0; i < count; i++) { + if (state == DSI_CMD_SET_STATE_LP) + cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM; + + if (cmds->last_command) + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + + len = ops->transfer(panel->host, &cmds->msg); + if (len < 0) { + rc = len; + DSI_ERR("failed to set cmds(%d), rc=%d\n", type, rc); + goto error; + } + if (cmds->post_wait_ms) + usleep_range(cmds->post_wait_ms*1000, + ((cmds->post_wait_ms*1000)+10)); + cmds++; + } +error: + return rc; +} + +static int dsi_display_status_reg_read(struct dsi_display *display) +{ + int rc = 0, i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + struct dsi_display_mode *mode; + u32 flags = 0; + u32 count = 0; + int retry_times = 0; + struct dsi_panel *panel = NULL; + struct dsi_cmd_desc *cmds1; + struct dsi_cmd_desc *cmds2; + struct dsi_cmd_desc *cmds3; + struct dsi_cmd_desc *cmds4; + u8 register_0a[10] = {0}; + u8 register_ee[10] = {0}; + u8 register_e5[10] = {0}; + u8 register_ed[10] = {0}; + u8 buf[48]; + memset(buf, 0, sizeof(buf)); + + DSI_DEBUG(" ++\n"); + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + if (display->tx_cmd_buf == NULL) { + rc = dsi_host_alloc_cmd_tx_buffer(display); + if (rc) { + DSI_ERR("failed to allocate cmd tx buffer memory\n"); + goto done; + } + } + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EPERM; + } + mode = display->panel->cur_mode; + panel = display->panel; + + if (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) { + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ON].count; + if (!count) { + DSI_ERR("This panel does not support esd register reading\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ON); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ON command\n"); + rc = -1; + goto exit; + } + } + + flags = 0; + retry_times = 0; + cmds1 = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_ID1].cmds; + if (cmds1->last_command) { + cmds1->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds1->msg.rx_buf = register_0a; + cmds1->msg.rx_len = 1; + do { + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds1->msg, &flags); + retry_times++; + } while ((rc <= 0) && (retry_times < 3)); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + goto exit; + } + + flags = 0; + retry_times = 0; + cmds2 = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_ID2].cmds; + if (cmds2->last_command) { + cmds2->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds2->msg.rx_buf = register_ee; + cmds2->msg.rx_len = 1; + do { + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds2->msg, &flags); + retry_times++; + } while ((rc <= 0) && (retry_times < 3)); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + goto exit; + } + + flags = 0; + retry_times = 0; + cmds3 = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_ID3].cmds; + if (cmds3->last_command) { + cmds3->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds3->msg.rx_buf = register_e5; + cmds3->msg.rx_len = 1; + do { + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds3->msg, &flags); + retry_times++; + } while ((rc <= 0) && (retry_times < 3)); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + goto exit; + } + + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ED_ON].count; + if (!count) { + DSI_ERR("This panel does not support esd register reading\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ED_ON); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ED_ON command\n"); + rc = -1; + goto exit; + } + } + flags = 0; + retry_times = 0; + cmds4 = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_ID4].cmds; + if (cmds4->last_command) { + cmds4->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds4->msg.rx_buf = register_ed; + cmds4->msg.rx_len = 1; + do { + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds4->msg, &flags); + retry_times++; + } while ((rc <= 0) && (retry_times < 3)); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + goto exit; + } + + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF].count; + if (!count) { + DSI_ERR("This panel does not support esd register reading\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF command\n"); + rc = -1; + goto exit; + } + } + //DSI_ERR("ESD check Leaving %d , %d , %d , %d \n",register_0a[0],register_ee[0],register_e5[0],register_ed[0]); + + if ((register_0a[0] != 0x9c) || ((register_ee[0] != 0x00) && (register_ee[0] != 0x80)) + || ((register_e5[0] != 0x13) && (register_e5[0] != 0x12)) || (register_ed[0] != 0x97)) { + DSI_ERR("0x0A = %02x, 0xEE = %02x, 0xE5 = %02x, 0xED = %02x\n", register_0a[0], register_ee[0], register_e5[0], register_ed[0]); + if (register_0a[0] != 0x9c) + esd_black_count++; + if ((register_ee[0] != 0x00) || (register_e5[0] != 0x13) || (register_ed[0] != 0x97)) + esd_greenish_count++; + DSI_ERR("%s:black_count=%d, greenish_count=%d, total=%d\n", + __func__, esd_black_count, esd_greenish_count, + esd_black_count + esd_greenish_count); + rc = -1; + } + else { + rc = 1; + } + } else { + rc = dsi_display_validate_status(m_ctrl, display->panel); + } + if (rc <= 0) { + DSI_ERR("[%s] read status failed on master,rc=%d\n", + display->name, rc); + goto exit; + } + + if (!display->panel->sync_broadcast_en) + goto exit; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (ctrl == m_ctrl) + continue; + + rc = dsi_display_validate_status(ctrl, display->panel); + if (rc <= 0) { + DSI_ERR("[%s] read status failed on slave,rc=%d\n", + display->name, rc); + goto exit; + } + } +exit: + dsi_display_cmd_engine_disable(display); +done: + return rc; +} + +static int dsi_display_status_bta_request(struct dsi_display *display) +{ + int rc = 0; + + DSI_DEBUG(" ++\n"); + /* TODO: trigger SW BTA and wait for acknowledgment */ + + return rc; +} + +static int dsi_display_status_check_te(struct dsi_display *display) +{ + int rc = 1; + int const esd_te_timeout = msecs_to_jiffies(3*20); + + dsi_display_change_te_irq_status(display, true); + + reinit_completion(&display->esd_te_gate); + if (!wait_for_completion_timeout(&display->esd_te_gate, + esd_te_timeout)) { + DSI_ERR("TE check failed\n"); + rc = -EINVAL; + } + + dsi_display_change_te_irq_status(display, false); + + return rc; +} + +int dsi_display_check_status(struct drm_connector *connector, void *display, + bool te_check_override) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + static int sp_read_wait_count; + u32 status_mode; + int rc = 0x1, ret; + u32 mask; + + if (!dsi_display || !dsi_display->panel) + return -EINVAL; + + panel = dsi_display->panel; + + dsi_panel_acquire_panel_lock(panel); + + if (!panel->panel_initialized) { + DSI_DEBUG("Panel not initialized\n"); + goto release_panel_lock; + } + + /* Prevent another ESD check,when ESD recovery is underway */ + if (atomic_read(&panel->esd_recovery_pending)) + goto release_panel_lock; + + status_mode = panel->esd_config.status_mode; + + if (status_mode == ESD_MODE_SW_SIM_SUCCESS) + goto release_panel_lock; + + if (status_mode == ESD_MODE_SW_SIM_FAILURE) { + rc = -EINVAL; + goto release_panel_lock; + } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY, status_mode, te_check_override); + + if (te_check_override && gpio_is_valid(dsi_display->disp_te_gpio)) + status_mode = ESD_MODE_PANEL_TE; + + if (status_mode == ESD_MODE_PANEL_TE) { + rc = dsi_display_status_check_te(dsi_display); + goto exit; + } + + if (dsi_display->panel->err_flag_status == true) { + esd_black_count++; + DSI_ERR("%s:black_count=%d, greenish_count=%d, total=%d\n", + __func__, esd_black_count, esd_greenish_count, + esd_black_count + esd_greenish_count); + rc = -1; + goto exit; + } + + if ((dsi_display->panel->panel_switch_status == true) + && (strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) { + DSI_ERR("panel_switch_status = true, skip ESD reading\n"); + goto release_panel_lock; + } + + ret = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (ret) + goto release_panel_lock; + + /* Mask error interrupts before attempting ESD read */ + mask = BIT(DSI_FIFO_OVERFLOW) | BIT(DSI_FIFO_UNDERFLOW); + dsi_display_set_ctrl_esd_check_flag(dsi_display, true); + dsi_display_mask_ctrl_error_interrupts(dsi_display, mask, true); + + if (status_mode == ESD_MODE_REG_READ) { + rc = dsi_display_status_reg_read(dsi_display); + } else if (status_mode == ESD_MODE_SW_BTA) { + rc = dsi_display_status_bta_request(dsi_display); + } else if (status_mode == ESD_MODE_PANEL_TE) { + rc = dsi_display_status_check_te(dsi_display); + } else { + DSI_WARN("Unsupported check status mode: %d\n", status_mode); + panel->esd_config.esd_enabled = false; + } + + /* Unmask error interrupts if check passed*/ + if (rc > 0) { + dsi_display_set_ctrl_esd_check_flag(dsi_display, false); + dsi_display_mask_ctrl_error_interrupts(dsi_display, mask, + false); + } + + dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + +exit: + /* Handle Panel failures during display disable sequence */ + if (rc <=0) + atomic_set(&panel->esd_recovery_pending, 1); + +release_panel_lock: + dsi_panel_release_panel_lock(panel); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT, rc); + if (rc > 0) { + if ((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) { + sp_read_wait_count++; + if ((sp_read_wait_count == SP_READ_LEVEL_INTERVAL_COUNT) + && (sp_read_flag == SP_READ_ERROR)) { + dsi_display_sp_read(dsi_display); + DSI_ERR("dsi_display_sp_read\n"); + sp_read_wait_count = 0; + } + } + } + return rc; +} + +static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, + struct dsi_cmd_desc *cmd, u8 *payload, u32 payload_len) +{ + int i; + + memset(cmd, 0x00, sizeof(*cmd)); + cmd->msg.type = cmd_buf[0]; + cmd->last_command = (cmd_buf[1] == 1); + cmd->msg.channel = cmd_buf[2]; + cmd->msg.flags = cmd_buf[3]; + cmd->msg.ctrl = 0; + cmd->post_wait_ms = cmd->msg.wait_ms = cmd_buf[4]; + cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6])); + + if (cmd->msg.tx_len > payload_len) { + DSI_ERR("Incorrect payload length tx_len %zu, payload_len %d\n", + cmd->msg.tx_len, payload_len); + return -EINVAL; + } + + if (cmd->last_command) + cmd->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + + for (i = 0; i < cmd->msg.tx_len; i++) + payload[i] = cmd_buf[7 + i]; + + cmd->msg.tx_buf = payload; + return 0; +} + +static int dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, + bool *state) +{ + struct dsi_display_ctrl *ctrl; + int i, rc = -EINVAL; + + display_for_each_ctrl(i, dsi_display) { + ctrl = &dsi_display->ctrl[i]; + rc = dsi_ctrl_get_host_engine_init_state(ctrl->ctrl, state); + if (rc) + break; + } + return rc; +} + +int dsi_display_cmd_transfer(struct drm_connector *connector, + void *display, const char *cmd_buf, + u32 cmd_buf_len) +{ + struct dsi_display *dsi_display = display; + struct dsi_cmd_desc cmd; + u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE]; + int rc = 0; + bool state = false; + + if (!dsi_display || !cmd_buf) { + DSI_ERR("[DSI] invalid params\n"); + return -EINVAL; + } + + DSI_DEBUG("[DSI] Display command transfer\n"); + + rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len, + &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE); + if (rc) { + DSI_ERR("[DSI] command prepare failed. rc %d\n", rc); + return rc; + } + + mutex_lock(&dsi_display->display_lock); + rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); + + /** + * Handle scenario where a command transfer is initiated through + * sysfs interface when device is in suepnd state. + */ + if (!rc && !state) { + pr_warn_ratelimited("Command xfer attempted while device is in suspend state\n" + ); + rc = -EPERM; + goto end; + } + if (rc || !state) { + DSI_ERR("[DSI] Invalid host state %d rc %d\n", + state, rc); + rc = -EPERM; + goto end; + } + + rc = dsi_display->host.ops->transfer(&dsi_display->host, + &cmd.msg); +end: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +static void _dsi_display_continuous_clk_ctrl(struct dsi_display *display, + bool enable) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display || !display->panel->host_config.force_hs_clk_lane) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + + /* + * For phy ver 4.0 chipsets, configure DSI controller and + * DSI PHY to force clk lane to HS mode always whereas + * for other phy ver chipsets, configure DSI controller only. + */ + if (ctrl->phy->hw.ops.set_continuous_clk) { + dsi_ctrl_hs_req_sel(ctrl->ctrl, true); + dsi_ctrl_set_continuous_clk(ctrl->ctrl, enable); + dsi_phy_set_continuous_clk(ctrl->phy, enable); + } else { + dsi_ctrl_set_continuous_clk(ctrl->ctrl, enable); + } + } +} + +int dsi_display_soft_reset(void *display) +{ + struct dsi_display *dsi_display; + struct dsi_display_ctrl *ctrl; + int rc = 0; + int i; + + if (!display) + return -EINVAL; + + dsi_display = display; + + display_for_each_ctrl(i, dsi_display) { + ctrl = &dsi_display->ctrl[i]; + rc = dsi_ctrl_soft_reset(ctrl->ctrl); + if (rc) { + DSI_ERR("[%s] failed to soft reset host_%d, rc=%d\n", + dsi_display->name, i, rc); + break; + } + } + + return rc; +} + +enum dsi_pixel_format dsi_display_get_dst_format( + struct drm_connector *connector, + void *display) +{ + enum dsi_pixel_format format = DSI_PIXEL_FORMAT_MAX; + struct dsi_display *dsi_display = (struct dsi_display *)display; + + if (!dsi_display || !dsi_display->panel) { + DSI_ERR("Invalid params(s) dsi_display %pK, panel %pK\n", + dsi_display, + ((dsi_display) ? dsi_display->panel : NULL)); + return format; + } + + format = dsi_display->panel->host_config.dst_format; + return format; +} + +static void _dsi_display_setup_misr(struct dsi_display *display) +{ + int i; + + display_for_each_ctrl(i, display) { + dsi_ctrl_setup_misr(display->ctrl[i].ctrl, + display->misr_enable, + display->misr_frame_count); + } +} + +extern int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level); + +int dsi_display_set_power(struct drm_connector *connector, + int power_mode, void *disp) +{ + struct dsi_display *display = disp; + int rc = 0; + struct drm_panel_notifier notifier_data; + int blank; + +#ifdef CONFIG_F2FS_OF2FS + struct drm_panel_notifier notifier_data_f2fs; + int blank_f2fs; +#endif + + if (!display || !display->panel) { + DSI_ERR("invalid display/panel\n"); + return -EINVAL; + } + + switch (power_mode) { + case SDE_MODE_DPMS_LP1: + DSI_ERR("SDE_MODE_DPMS_LP1\n"); + rc = dsi_panel_set_lp1(display->panel); + if (display->panel->aod_mode && display->panel->aod_mode != 2) { + display->panel->aod_status = 0; + rc = dsi_panel_set_aod_mode(display->panel, 5); + DSI_ERR("Send dsi_panel_set_aod_mode 5 cmds\n"); + if (rc) { + DSI_ERR("[%s] failed to send dsi_panel_set_aod_mode cmds, rc=%d\n", + display->panel->name, rc); + } + } + break; + case SDE_MODE_DPMS_LP2: + DSI_ERR("SDE_MODE_DPMS_LP2\n"); + rc = dsi_panel_set_lp2(display->panel); + break; + case SDE_MODE_DPMS_ON: + DSI_ERR("SDE_MODE_DPMS_ON\n"); + if (display->panel->power_mode == SDE_MODE_DPMS_LP1 || + display->panel->power_mode == SDE_MODE_DPMS_LP2) + rc = dsi_panel_set_nolp(display->panel); + /*send screen on cmd for tp */ + blank = DRM_PANEL_BLANK_UNBLANK_CUST; + notifier_data.data = ␣ + DSI_ERR("DRM_PANEL_BLANK_UNBLANK_CUST\n"); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); +#ifdef CONFIG_F2FS_OF2FS + blank_f2fs = DRM_PANEL_BLANK_UNBLANK_CUST; + notifier_data_f2fs.data = &blank_f2fs; + f2fs_panel_notifier_call_chain(DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data_f2fs); +#endif + /* send screen on cmd for tp end */ + break; + case SDE_MODE_DPMS_OFF: + /*send screen off cmd for tp start */ + blank = DRM_PANEL_BLANK_POWERDOWN_CUST; + notifier_data.data = ␣ + DSI_ERR("DRM_PANEL_BLANK_POWERDOWN_CUST\n"); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); +#ifdef CONFIG_F2FS_OF2FS + blank_f2fs = DRM_PANEL_BLANK_POWERDOWN_CUST; + notifier_data_f2fs.data = &blank_f2fs; + f2fs_panel_notifier_call_chain(DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data_f2fs); +#endif + break; + default: + return rc; + } + + SDE_EVT32(display->panel->power_mode, power_mode, rc); + DSI_DEBUG("Power mode transition from %d to %d %s", + display->panel->power_mode, power_mode, + rc ? "failed" : "successful"); + if (!rc) + display->panel->power_mode = power_mode; + + return rc; + +} + +#ifdef CONFIG_DEBUG_FS +static bool dsi_display_is_te_based_esd(struct dsi_display *display) +{ + u32 status_mode = 0; + + if (!display->panel) { + DSI_ERR("Invalid panel data\n"); + return false; + } + + status_mode = display->panel->esd_config.status_mode; + + if (status_mode == ESD_MODE_PANEL_TE && + gpio_is_valid(display->disp_te_gpio)) + return true; + return false; +} + +static ssize_t debugfs_dump_info_read(struct file *file, + char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char *buf; + u32 len = 0; + int i; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += snprintf(buf + len, (SZ_4K - len), "name = %s\n", display->name); + len += snprintf(buf + len, (SZ_4K - len), + "\tResolution = %dx%d\n", + display->config.video_timing.h_active, + display->config.video_timing.v_active); + + display_for_each_ctrl(i, display) { + len += snprintf(buf + len, (SZ_4K - len), + "\tCTRL_%d:\n\t\tctrl = %s\n\t\tphy = %s\n", + i, display->ctrl[i].ctrl->name, + display->ctrl[i].phy->name); + } + + len += snprintf(buf + len, (SZ_4K - len), + "\tPanel = %s\n", display->panel->name); + + len += snprintf(buf + len, (SZ_4K - len), + "\tClock master = %s\n", + display->ctrl[display->clk_master_idx].ctrl->name); + + if (len > user_len) + len = user_len; + + if (copy_to_user(user_buf, buf, len)) { + kfree(buf); + return -EFAULT; + } + + *ppos += len; + + kfree(buf); + return len; +} + +static ssize_t debugfs_misr_setup(struct file *file, + const char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char *buf; + int rc = 0; + size_t len; + u32 enable, frame_count; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(MISR_BUFF_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* leave room for termination char */ + len = min_t(size_t, user_len, MISR_BUFF_SIZE - 1); + if (copy_from_user(buf, user_buf, len)) { + rc = -EINVAL; + goto error; + } + + buf[len] = '\0'; /* terminate the string */ + + if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) { + rc = -EINVAL; + goto error; + } + + display->misr_enable = enable; + display->misr_frame_count = frame_count; + + mutex_lock(&display->display_lock); + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto unlock; + } + + _dsi_display_setup_misr(display); + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + display->name, rc); + goto unlock; + } + + rc = user_len; +unlock: + mutex_unlock(&display->display_lock); +error: + kfree(buf); + return rc; +} + +static ssize_t debugfs_misr_read(struct file *file, + char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char *buf; + u32 len = 0; + int rc = 0; + struct dsi_ctrl *dsi_ctrl; + int i; + u32 misr; + size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE); + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(max_len, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + mutex_lock(&display->display_lock); + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + dsi_ctrl = display->ctrl[i].ctrl; + misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl); + + len += snprintf((buf + len), max_len - len, + "DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr); + + if (len >= max_len) + break; + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + display->name, rc); + goto error; + } + + if (copy_to_user(user_buf, buf, max_len)) { + rc = -EFAULT; + goto error; + } + + *ppos += len; + +error: + mutex_unlock(&display->display_lock); + kfree(buf); + return len; +} + +static ssize_t debugfs_esd_trigger_check(struct file *file, + const char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + char *buf; + int rc = 0; + struct drm_panel_esd_config *esd_config = &display->panel->esd_config; + u32 esd_trigger; + size_t len; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + if (user_len > sizeof(u32)) + return -EINVAL; + + if (!user_len || !user_buf) + return -EINVAL; + + if (!display->panel || + atomic_read(&display->panel->esd_recovery_pending)) + return user_len; + + if (!esd_config->esd_enabled) { + DSI_ERR("ESD feature is not enabled\n"); + return -EINVAL; + } + + buf = kzalloc(ESD_TRIGGER_STRING_MAX_LEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len = min_t(size_t, user_len, ESD_TRIGGER_STRING_MAX_LEN - 1); + if (copy_from_user(buf, user_buf, len)) { + rc = -EINVAL; + goto error; + } + + buf[len] = '\0'; /* terminate the string */ + + if (kstrtouint(buf, 10, &esd_trigger)) { + rc = -EINVAL; + goto error; + } + + if (esd_trigger != 1) { + rc = -EINVAL; + goto error; + } + + display->esd_trigger = esd_trigger; + + if (display->esd_trigger) { + DSI_INFO("ESD attack triggered by user\n"); + rc = dsi_panel_trigger_esd_attack(display->panel); + if (rc) { + DSI_ERR("Failed to trigger ESD attack\n"); + goto error; + } + } + + rc = len; +error: + kfree(buf); + return rc; +} + +static ssize_t debugfs_alter_esd_check_mode(struct file *file, + const char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + struct drm_panel_esd_config *esd_config; + char *buf; + int rc = 0; + size_t len; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + buf = kzalloc(ESD_MODE_STRING_MAX_LEN, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN - 1); + if (copy_from_user(buf, user_buf, len)) { + rc = -EINVAL; + goto error; + } + + buf[len] = '\0'; /* terminate the string */ + if (!display->panel) { + rc = -EINVAL; + goto error; + } + + esd_config = &display->panel->esd_config; + if (!esd_config) { + DSI_ERR("Invalid panel esd config\n"); + rc = -EINVAL; + goto error; + } + + if (!esd_config->esd_enabled) + goto error; + + if (!strcmp(buf, "te_signal_check\n")) { + if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { + DSI_INFO("TE based ESD check for Video Mode panels is not allowed\n"); + goto error; + } + DSI_INFO("ESD check is switched to TE mode by user\n"); + esd_config->status_mode = ESD_MODE_PANEL_TE; + dsi_display_change_te_irq_status(display, true); + } + + if (!strcmp(buf, "reg_read\n")) { + DSI_INFO("ESD check is switched to reg read by user\n"); + rc = dsi_panel_parse_esd_reg_read_configs(display->panel); + if (rc) { + DSI_ERR("failed to alter esd check mode,rc=%d\n", + rc); + rc = user_len; + goto error; + } + esd_config->status_mode = ESD_MODE_REG_READ; + if (dsi_display_is_te_based_esd(display)) + dsi_display_change_te_irq_status(display, false); + } + + if (!strcmp(buf, "esd_sw_sim_success\n")) + esd_config->status_mode = ESD_MODE_SW_SIM_SUCCESS; + + if (!strcmp(buf, "esd_sw_sim_failure\n")) + esd_config->status_mode = ESD_MODE_SW_SIM_FAILURE; + + rc = len; +error: + kfree(buf); + return rc; +} + +static ssize_t debugfs_read_esd_check_mode(struct file *file, + char __user *user_buf, + size_t user_len, + loff_t *ppos) +{ + struct dsi_display *display = file->private_data; + struct drm_panel_esd_config *esd_config; + char *buf; + int rc = 0; + size_t len; + + if (!display) + return -ENODEV; + + if (*ppos) + return 0; + + if (!display->panel) { + DSI_ERR("invalid panel data\n"); + return -EINVAL; + } + + buf = kzalloc(ESD_MODE_STRING_MAX_LEN, GFP_KERNEL); + if (ZERO_OR_NULL_PTR(buf)) + return -ENOMEM; + + esd_config = &display->panel->esd_config; + if (!esd_config) { + DSI_ERR("Invalid panel esd config\n"); + rc = -EINVAL; + goto error; + } + + len = min_t(size_t, user_len, ESD_MODE_STRING_MAX_LEN - 1); + if (!esd_config->esd_enabled) { + rc = snprintf(buf, len, "ESD feature not enabled"); + goto output_mode; + } + + switch (esd_config->status_mode) { + case ESD_MODE_REG_READ: + rc = snprintf(buf, len, "reg_read"); + break; + case ESD_MODE_PANEL_TE: + rc = snprintf(buf, len, "te_signal_check"); + break; + case ESD_MODE_SW_SIM_FAILURE: + rc = snprintf(buf, len, "esd_sw_sim_failure"); + break; + case ESD_MODE_SW_SIM_SUCCESS: + rc = snprintf(buf, len, "esd_sw_sim_success"); + break; + default: + rc = snprintf(buf, len, "invalid"); + break; + } + +output_mode: + if (!rc) { + rc = -EINVAL; + goto error; + } + + if (copy_to_user(user_buf, buf, len)) { + rc = -EFAULT; + goto error; + } + + *ppos += len; + +error: + kfree(buf); + return len; +} + +static const struct file_operations dump_info_fops = { + .open = simple_open, + .read = debugfs_dump_info_read, +}; + +static const struct file_operations misr_data_fops = { + .open = simple_open, + .read = debugfs_misr_read, + .write = debugfs_misr_setup, +}; + +static const struct file_operations esd_trigger_fops = { + .open = simple_open, + .write = debugfs_esd_trigger_check, +}; + +static const struct file_operations esd_check_mode_fops = { + .open = simple_open, + .write = debugfs_alter_esd_check_mode, + .read = debugfs_read_esd_check_mode, +}; + +static int dsi_display_debugfs_init(struct dsi_display *display) +{ + int rc = 0; + struct dentry *dir, *dump_file, *misr_data; + char name[MAX_NAME_SIZE]; + int i; + + dir = debugfs_create_dir(display->name, NULL); + if (IS_ERR_OR_NULL(dir)) { + rc = PTR_ERR(dir); + DSI_ERR("[%s] debugfs create dir failed, rc = %d\n", + display->name, rc); + goto error; + } + + dump_file = debugfs_create_file("dump_info", + 0400, + dir, + display, + &dump_info_fops); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + DSI_ERR("[%s] debugfs create dump info file failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + + dump_file = debugfs_create_file("esd_trigger", + 0644, + dir, + display, + &esd_trigger_fops); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + DSI_ERR("[%s] debugfs for esd trigger file failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + + dump_file = debugfs_create_file("esd_check_mode", + 0644, + dir, + display, + &esd_check_mode_fops); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + DSI_ERR("[%s] debugfs for esd check mode failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + + misr_data = debugfs_create_file("misr_data", + 0600, + dir, + display, + &misr_data_fops); + if (IS_ERR_OR_NULL(misr_data)) { + rc = PTR_ERR(misr_data); + DSI_ERR("[%s] debugfs create misr datafile failed, rc=%d\n", + display->name, rc); + goto error_remove_dir; + } + + display_for_each_ctrl(i, display) { + struct msm_dsi_phy *phy = display->ctrl[i].phy; + + if (!phy || !phy->name) + continue; + + snprintf(name, ARRAY_SIZE(name), + "%s_allow_phy_power_off", phy->name); + dump_file = debugfs_create_bool(name, 0600, dir, + &phy->allow_phy_power_off); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + DSI_ERR("[%s] debugfs create %s failed, rc=%d\n", + display->name, name, rc); + goto error_remove_dir; + } + + snprintf(name, ARRAY_SIZE(name), + "%s_regulator_min_datarate_bps", phy->name); + dump_file = debugfs_create_u32(name, 0600, dir, + &phy->regulator_min_datarate_bps); + if (IS_ERR_OR_NULL(dump_file)) { + rc = PTR_ERR(dump_file); + DSI_ERR("[%s] debugfs create %s failed, rc=%d\n", + display->name, name, rc); + goto error_remove_dir; + } + } + + if (!debugfs_create_bool("ulps_feature_enable", 0600, dir, + &display->panel->ulps_feature_enabled)) { + DSI_ERR("[%s] debugfs create ulps feature enable file failed\n", + display->name); + goto error_remove_dir; + } + + if (!debugfs_create_bool("ulps_suspend_feature_enable", 0600, dir, + &display->panel->ulps_suspend_enabled)) { + DSI_ERR("[%s] debugfs create ulps-suspend feature enable file failed\n", + display->name); + goto error_remove_dir; + } + + if (!debugfs_create_bool("ulps_status", 0400, dir, + &display->ulps_enabled)) { + DSI_ERR("[%s] debugfs create ulps status file failed\n", + display->name); + goto error_remove_dir; + } + + if (!debugfs_create_u32("clk_gating_config", 0600, dir, + &display->clk_gating_config)) { + DSI_ERR("[%s] debugfs create clk gating config failed\n", + display->name); + goto error_remove_dir; + } + + display->root = dir; + dsi_parser_dbg_init(display->parser, dir); + + return rc; +error_remove_dir: + debugfs_remove(dir); +error: + return rc; +} + +static int dsi_display_debugfs_deinit(struct dsi_display *display) +{ + debugfs_remove_recursive(display->root); + + return 0; +} +#else +static int dsi_display_debugfs_init(struct dsi_display *display) +{ + return 0; +} +static int dsi_display_debugfs_deinit(struct dsi_display *display) +{ + return 0; +} +#endif /* CONFIG_DEBUG_FS */ + +static void adjust_timing_by_ctrl_count(const struct dsi_display *display, + struct dsi_display_mode *mode) +{ + struct dsi_host_common_cfg *host = &display->panel->host_config; + bool is_split_link = host->split_link.split_link_enabled; + u32 sublinks_count = host->split_link.num_sublinks; + + if (is_split_link && sublinks_count > 1) { + mode->timing.h_active /= sublinks_count; + mode->timing.h_front_porch /= sublinks_count; + mode->timing.h_sync_width /= sublinks_count; + mode->timing.h_back_porch /= sublinks_count; + mode->timing.h_skew /= sublinks_count; + mode->pixel_clk_khz /= sublinks_count; + } else { + mode->timing.h_active /= display->ctrl_count; + mode->timing.h_front_porch /= display->ctrl_count; + mode->timing.h_sync_width /= display->ctrl_count; + mode->timing.h_back_porch /= display->ctrl_count; + mode->timing.h_skew /= display->ctrl_count; + mode->pixel_clk_khz /= display->ctrl_count; + } +} + +static int dsi_display_is_ulps_req_valid(struct dsi_display *display, + bool enable) +{ + /* TODO: make checks based on cont. splash */ + + DSI_DEBUG("checking ulps req validity\n"); + + if (atomic_read(&display->panel->esd_recovery_pending)) { + DSI_DEBUG("%s: ESD recovery sequence underway\n", __func__); + return false; + } + + if (!dsi_panel_ulps_feature_enabled(display->panel) && + !display->panel->ulps_suspend_enabled) { + DSI_DEBUG("%s: ULPS feature is not enabled\n", __func__); + return false; + } + + if (!dsi_panel_initialized(display->panel) && + !display->panel->ulps_suspend_enabled) { + DSI_DEBUG("%s: panel not yet initialized\n", __func__); + return false; + } + + if (enable && display->ulps_enabled) { + DSI_DEBUG("ULPS already enabled\n"); + return false; + } else if (!enable && !display->ulps_enabled) { + DSI_DEBUG("ULPS already disabled\n"); + return false; + } + + /* + * No need to enter ULPS when transitioning from splash screen to + * boot animation since it is expected that the clocks would be turned + * right back on. + */ + if (enable && display->is_cont_splash_enabled) + return false; + + return true; +} + + +/** + * dsi_display_set_ulps() - set ULPS state for DSI lanes. + * @dsi_display: DSI display handle. + * @enable: enable/disable ULPS. + * + * ULPS can be enabled/disabled after DSI host engine is turned on. + * + * Return: error code. + */ +static int dsi_display_set_ulps(struct dsi_display *display, bool enable) +{ + int rc = 0; + int i = 0; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (!dsi_display_is_ulps_req_valid(display, enable)) { + DSI_DEBUG("%s: skipping ULPS config, enable=%d\n", + __func__, enable); + return 0; + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + /* + * ULPS entry-exit can be either through the DSI controller or + * the DSI PHY depending on hardware variation. For some chipsets, + * both controller version and phy version ulps entry-exit ops can + * be present. To handle such cases, send ulps request through PHY, + * if ulps request is handled in PHY, then no need to send request + * through controller. + */ + + rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable, + display->clamp_enabled); + + if (rc == DSI_PHY_ULPS_ERROR) { + DSI_ERR("Ulps PHY state change(%d) failed\n", enable); + return -EINVAL; + } + + else if (rc == DSI_PHY_ULPS_HANDLED) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_phy_set_ulps(ctrl->phy, &display->config, + enable, display->clamp_enabled); + if (rc == DSI_PHY_ULPS_ERROR) { + DSI_ERR("Ulps PHY state change(%d) failed\n", + enable); + return -EINVAL; + } + } + } + + else if (rc == DSI_PHY_ULPS_NOT_HANDLED) { + rc = dsi_ctrl_set_ulps(m_ctrl->ctrl, enable); + if (rc) { + DSI_ERR("Ulps controller state change(%d) failed\n", + enable); + return rc; + } + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_ulps(ctrl->ctrl, enable); + if (rc) { + DSI_ERR("Ulps controller state change(%d) failed\n", + enable); + return rc; + } + } + } + + display->ulps_enabled = enable; + return 0; +} + +/** + * dsi_display_set_clamp() - set clamp state for DSI IO. + * @dsi_display: DSI display handle. + * @enable: enable/disable clamping. + * + * Return: error code. + */ +static int dsi_display_set_clamp(struct dsi_display *display, bool enable) +{ + int rc = 0; + int i = 0; + struct dsi_display_ctrl *m_ctrl, *ctrl; + bool ulps_enabled = false; + + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + ulps_enabled = display->ulps_enabled; + + /* + * Clamp control can be either through the DSI controller or + * the DSI PHY depending on hardware variation + */ + rc = dsi_ctrl_set_clamp_state(m_ctrl->ctrl, enable, ulps_enabled); + if (rc) { + DSI_ERR("DSI ctrl clamp state change(%d) failed\n", enable); + return rc; + } + + rc = dsi_phy_set_clamp_state(m_ctrl->phy, enable); + if (rc) { + DSI_ERR("DSI phy clamp state change(%d) failed\n", enable); + return rc; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_clamp_state(ctrl->ctrl, enable, ulps_enabled); + if (rc) { + DSI_ERR("DSI Clamp state change(%d) failed\n", enable); + return rc; + } + + rc = dsi_phy_set_clamp_state(ctrl->phy, enable); + if (rc) { + DSI_ERR("DSI phy clamp state change(%d) failed\n", + enable); + return rc; + } + + DSI_DEBUG("Clamps %s for ctrl%d\n", + enable ? "enabled" : "disabled", i); + } + + display->clamp_enabled = enable; + return 0; +} + +/** + * dsi_display_setup_ctrl() - setup DSI controller. + * @dsi_display: DSI display handle. + * + * Return: error code. + */ +static int dsi_display_ctrl_setup(struct dsi_display *display) +{ + int rc = 0; + int i = 0; + struct dsi_display_ctrl *ctrl, *m_ctrl; + + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + rc = dsi_ctrl_setup(m_ctrl->ctrl); + if (rc) { + DSI_ERR("DSI controller setup failed\n"); + return rc; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_setup(ctrl->ctrl); + if (rc) { + DSI_ERR("DSI controller setup failed\n"); + return rc; + } + } + return 0; +} + +static int dsi_display_phy_enable(struct dsi_display *display); + +/** + * dsi_display_phy_idle_on() - enable DSI PHY while coming out of idle screen. + * @dsi_display: DSI display handle. + * @mmss_clamp: True if clamp is enabled. + * + * Return: error code. + */ +static int dsi_display_phy_idle_on(struct dsi_display *display, + bool mmss_clamp) +{ + int rc = 0; + int i = 0; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (mmss_clamp && !display->phy_idle_power_off) { + dsi_display_phy_enable(display); + return 0; + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + rc = dsi_phy_idle_ctrl(m_ctrl->phy, true); + if (rc) { + DSI_ERR("DSI controller setup failed\n"); + return rc; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_phy_idle_ctrl(ctrl->phy, true); + if (rc) { + DSI_ERR("DSI controller setup failed\n"); + return rc; + } + } + display->phy_idle_power_off = false; + return 0; +} + +/** + * dsi_display_phy_idle_off() - disable DSI PHY while going to idle screen. + * @dsi_display: DSI display handle. + * + * Return: error code. + */ +static int dsi_display_phy_idle_off(struct dsi_display *display) +{ + int rc = 0; + int i = 0; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + display_for_each_ctrl(i, display) { + struct msm_dsi_phy *phy = display->ctrl[i].phy; + + if (!phy) + continue; + + if (!phy->allow_phy_power_off) { + DSI_DEBUG("phy doesn't support this feature\n"); + return 0; + } + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + rc = dsi_phy_idle_ctrl(m_ctrl->phy, false); + if (rc) { + DSI_ERR("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + return rc; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_phy_idle_ctrl(ctrl->phy, false); + if (rc) { + DSI_ERR("DSI controller setup failed\n"); + return rc; + } + } + display->phy_idle_power_off = true; + return 0; +} + +void dsi_display_enable_event(struct drm_connector *connector, + struct dsi_display *display, + uint32_t event_idx, struct dsi_event_cb_info *event_info, + bool enable) +{ + uint32_t irq_status_idx = DSI_STATUS_INTERRUPT_COUNT; + int i; + + if (!display) { + DSI_ERR("invalid display\n"); + return; + } + + if (event_info) + event_info->event_idx = event_idx; + + switch (event_idx) { + case SDE_CONN_EVENT_VID_DONE: + irq_status_idx = DSI_SINT_VIDEO_MODE_FRAME_DONE; + break; + case SDE_CONN_EVENT_CMD_DONE: + irq_status_idx = DSI_SINT_CMD_FRAME_DONE; + break; + case SDE_CONN_EVENT_VID_FIFO_OVERFLOW: + case SDE_CONN_EVENT_CMD_FIFO_UNDERFLOW: + if (event_info) { + display_for_each_ctrl(i, display) + display->ctrl[i].ctrl->recovery_cb = + *event_info; + } + break; + default: + /* nothing to do */ + DSI_DEBUG("[%s] unhandled event %d\n", display->name, event_idx); + return; + } + + if (enable) { + display_for_each_ctrl(i, display) + dsi_ctrl_enable_status_interrupt( + display->ctrl[i].ctrl, irq_status_idx, + event_info); + } else { + display_for_each_ctrl(i, display) + dsi_ctrl_disable_status_interrupt( + display->ctrl[i].ctrl, irq_status_idx); + } +} + +/** + * dsi_config_host_engine_state_for_cont_splash()- update host engine state + * during continuous splash. + * @display: Handle to dsi display + * + */ +static void dsi_config_host_engine_state_for_cont_splash + (struct dsi_display *display) +{ + int i; + struct dsi_display_ctrl *ctrl; + enum dsi_engine_state host_state = DSI_CTRL_ENGINE_ON; + + /* Sequence does not matter for split dsi usecases */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + dsi_ctrl_update_host_engine_state_for_cont_splash(ctrl->ctrl, + host_state); + } +} + +static int dsi_display_ctrl_power_on(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + /* Sequence does not matter for split dsi usecases */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + rc = dsi_ctrl_set_power_state(ctrl->ctrl, + DSI_CTRL_POWER_VREG_ON); + if (rc) { + DSI_ERR("[%s] Failed to set power state, rc=%d\n", + ctrl->ctrl->name, rc); + goto error; + } + } + + return rc; +error: + for (i = i - 1; i >= 0; i--) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + (void)dsi_ctrl_set_power_state(ctrl->ctrl, + DSI_CTRL_POWER_VREG_OFF); + } + return rc; +} + +static int dsi_display_ctrl_power_off(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + /* Sequence does not matter for split dsi usecases */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + rc = dsi_ctrl_set_power_state(ctrl->ctrl, + DSI_CTRL_POWER_VREG_OFF); + if (rc) { + DSI_ERR("[%s] Failed to power off, rc=%d\n", + ctrl->ctrl->name, rc); + goto error; + } + } +error: + return rc; +} + +static void dsi_display_parse_cmdline_topology(struct dsi_display *display, + unsigned int display_type) +{ + char *boot_str = NULL; + char *str = NULL; + char *sw_te = NULL; + unsigned long cmdline_topology = NO_OVERRIDE; + unsigned long cmdline_timing = NO_OVERRIDE; + + if (display_type >= MAX_DSI_ACTIVE_DISPLAY) { + DSI_ERR("display_type=%d not supported\n", display_type); + goto end; + } + + if (display_type == DSI_PRIMARY) + boot_str = dsi_display_primary; + else + boot_str = dsi_display_secondary; + + sw_te = strnstr(boot_str, ":swte", strlen(boot_str)); + if (sw_te) + display->sw_te_using_wd = true; + + str = strnstr(boot_str, ":config", strlen(boot_str)); + if (str) { + if (sscanf(str, ":config%lu", &cmdline_topology) != 1) { + DSI_ERR("invalid config index override: %s\n", + boot_str); + goto end; + } + } + + str = strnstr(boot_str, ":timing", strlen(boot_str)); + if (str) { + if (sscanf(str, ":timing%lu", &cmdline_timing) != 1) { + DSI_ERR("invalid timing index override: %s\n", + boot_str); + cmdline_topology = NO_OVERRIDE; + goto end; + } + } + DSI_DEBUG("successfully parsed command line topology and timing\n"); +end: + display->cmdline_topology = cmdline_topology; + display->cmdline_timing = cmdline_timing; +} + +/** + * dsi_display_parse_boot_display_selection()- Parse DSI boot display name + * + * Return: returns error status + */ +static int dsi_display_parse_boot_display_selection(void) +{ + char *pos = NULL; + char disp_buf[MAX_CMDLINE_PARAM_LEN] = {'\0'}; + int i, j; + + for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) { + strlcpy(disp_buf, boot_displays[i].boot_param, + MAX_CMDLINE_PARAM_LEN); + + pos = strnstr(disp_buf, ":", MAX_CMDLINE_PARAM_LEN); + + /* Use ':' as a delimiter to retrieve the display name */ + if (!pos) { + DSI_DEBUG("display name[%s]is not valid\n", disp_buf); + continue; + } + + for (j = 0; (disp_buf + j) < pos; j++) + boot_displays[i].name[j] = *(disp_buf + j); + + boot_displays[i].name[j] = '\0'; + + boot_displays[i].boot_disp_en = true; + } + + return 0; +} + +static int dsi_display_phy_power_on(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + /* Sequence does not matter for split dsi usecases */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + + rc = dsi_phy_set_power_state(ctrl->phy, true); + if (rc) { + DSI_ERR("[%s] Failed to set power state, rc=%d\n", + ctrl->phy->name, rc); + goto error; + } + } + + return rc; +error: + for (i = i - 1; i >= 0; i--) { + ctrl = &display->ctrl[i]; + if (!ctrl->phy) + continue; + (void)dsi_phy_set_power_state(ctrl->phy, false); + } + return rc; +} + +static int dsi_display_phy_power_off(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + /* Sequence does not matter for split dsi usecases */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->phy) + continue; + + rc = dsi_phy_set_power_state(ctrl->phy, false); + if (rc) { + DSI_ERR("[%s] Failed to power off, rc=%d\n", + ctrl->ctrl->name, rc); + goto error; + } + } +error: + return rc; +} + +static int dsi_display_set_clk_src(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + /* + * For CPHY mode, the parent of mux_clks need to be set + * to Cphy_clks to have correct dividers for byte and + * pixel clocks. + */ + if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) { + rc = dsi_clk_update_parent(&display->clock_info.cphy_clks, + &display->clock_info.mux_clks); + if (rc) { + DSI_ERR("failed update mux parent to shadow\n"); + return rc; + } + } + + /* + * In case of split DSI usecases, the clock for master controller should + * be enabled before the other controller. Master controller in the + * clock context refers to the controller that sources the clock. + */ + m_ctrl = &display->ctrl[display->clk_master_idx]; + + rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl, + &display->clock_info.mux_clks); + if (rc) { + DSI_ERR("[%s] failed to set source clocks for master, rc=%d\n", + display->name, rc); + return rc; + } + + /* Turn on rest of the controllers */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_clock_source(ctrl->ctrl, + &display->clock_info.mux_clks); + if (rc) { + DSI_ERR("[%s] failed to set source clocks, rc=%d\n", + display->name, rc); + return rc; + } + } + return 0; +} + +static int dsi_display_phy_reset_config(struct dsi_display *display, + bool enable) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_phy_reset_config(ctrl->ctrl, enable); + if (rc) { + DSI_ERR("[%s] failed to %s phy reset, rc=%d\n", + display->name, enable ? "mask" : "unmask", rc); + return rc; + } + } + return 0; +} + +static void dsi_display_toggle_resync_fifo(struct dsi_display *display) +{ + struct dsi_display_ctrl *ctrl; + int i; + + if (!display) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_phy_toggle_resync_fifo(ctrl->phy); + } + + /* + * After retime buffer synchronization we need to turn of clk_en_sel + * bit on each phy. Avoid this for Cphy. + */ + + if (display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_phy_reset_clk_en_sel(ctrl->phy); + } + +} + +static int dsi_display_ctrl_update(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_host_timing_update(ctrl->ctrl); + if (rc) { + DSI_ERR("[%s] failed to update host_%d, rc=%d\n", + display->name, i, rc); + goto error_host_deinit; + } + } + + return 0; +error_host_deinit: + for (i = i - 1; i >= 0; i--) { + ctrl = &display->ctrl[i]; + (void)dsi_ctrl_host_deinit(ctrl->ctrl); + } + + return rc; +} + +static int dsi_display_ctrl_init(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + /* when ULPS suspend feature is enabled, we will keep the lanes in + * ULPS during suspend state and clamp DSI phy. Hence while resuming + * we will programe DSI controller as part of core clock enable. + * After that we should not re-configure DSI controller again here for + * usecases where we are resuming from ulps suspend as it might put + * the HW in bad state. + */ + if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_host_init(ctrl->ctrl, + display->is_cont_splash_enabled); + if (rc) { + DSI_ERR("[%s] failed to init host_%d, rc=%d\n", + display->name, i, rc); + goto error_host_deinit; + } + } + } else { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_update_host_state(ctrl->ctrl, + DSI_CTRL_OP_HOST_INIT, + true); + if (rc) + DSI_DEBUG("host init update failed rc=%d\n", + rc); + } + } + + return rc; +error_host_deinit: + for (i = i - 1; i >= 0; i--) { + ctrl = &display->ctrl[i]; + (void)dsi_ctrl_host_deinit(ctrl->ctrl); + } + return rc; +} + +static int dsi_display_ctrl_deinit(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_host_deinit(ctrl->ctrl); + if (rc) { + DSI_ERR("[%s] failed to deinit host_%d, rc=%d\n", + display->name, i, rc); + } + } + + return rc; +} + +static int dsi_display_ctrl_host_enable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + /* Host engine states are already taken care for + * continuous splash case + */ + if (display->is_cont_splash_enabled) { + DSI_DEBUG("cont splash enabled, host enable not required\n"); + return 0; + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_ERR("[%s] failed to enable host engine, rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_ERR("[%s] failed to enable sl host engine, rc=%d\n", + display->name, rc); + goto error_disable_master; + } + } + + return rc; +error_disable_master: + (void)dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); +error: + return rc; +} + +static int dsi_display_ctrl_host_disable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + /* + * For platforms where ULPS is controlled by DSI controller block, + * do not disable dsi controller block if lanes are to be + * kept in ULPS during suspend. So just update the SW state + * and return early. + */ + if (display->panel->ulps_suspend_enabled && + !m_ctrl->phy->hw.ops.ulps_ops.ulps_request) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_update_host_state(ctrl->ctrl, + DSI_CTRL_OP_HOST_ENGINE, + false); + if (rc) + DSI_DEBUG("host state update failed %d\n", rc); + } + return rc; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_OFF); + if (rc) + DSI_ERR("[%s] failed to disable host engine, rc=%d\n", + display->name, rc); + } + + rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable host engine, rc=%d\n", + display->name, rc); + goto error; + } + +error: + return rc; +} + +static int dsi_display_vid_engine_enable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->video_master_idx]; + + rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_ERR("[%s] failed to enable vid engine, rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_ON); + if (rc) { + DSI_ERR("[%s] failed to enable vid engine, rc=%d\n", + display->name, rc); + goto error_disable_master; + } + } + + return rc; +error_disable_master: + (void)dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); +error: + return rc; +} + +static int dsi_display_vid_engine_disable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->video_master_idx]; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl, + DSI_CTRL_ENGINE_OFF); + if (rc) + DSI_ERR("[%s] failed to disable vid engine, rc=%d\n", + display->name, rc); + } + + rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF); + if (rc) + DSI_ERR("[%s] failed to disable mvid engine, rc=%d\n", + display->name, rc); + + return rc; +} + +static int dsi_display_phy_enable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + enum dsi_phy_pll_source m_src = DSI_PLL_SOURCE_STANDALONE; + + m_ctrl = &display->ctrl[display->clk_master_idx]; + if (display->ctrl_count > 1) + m_src = DSI_PLL_SOURCE_NATIVE; + + rc = dsi_phy_enable(m_ctrl->phy, + &display->config, + m_src, + true, + display->is_cont_splash_enabled); + if (rc) { + DSI_ERR("[%s] failed to enable DSI PHY, rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_phy_enable(ctrl->phy, + &display->config, + DSI_PLL_SOURCE_NON_NATIVE, + true, + display->is_cont_splash_enabled); + if (rc) { + DSI_ERR("[%s] failed to enable DSI PHY, rc=%d\n", + display->name, rc); + goto error_disable_master; + } + } + + return rc; + +error_disable_master: + (void)dsi_phy_disable(m_ctrl->phy); +error: + return rc; +} + +static int dsi_display_phy_disable(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + m_ctrl = &display->ctrl[display->clk_master_idx]; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_phy_disable(ctrl->phy); + if (rc) + DSI_ERR("[%s] failed to disable DSI PHY, rc=%d\n", + display->name, rc); + } + + rc = dsi_phy_disable(m_ctrl->phy); + if (rc) + DSI_ERR("[%s] failed to disable DSI PHY, rc=%d\n", + display->name, rc); + + return rc; +} + +static int dsi_display_wake_up(struct dsi_display *display) +{ + return 0; +} + +static void dsi_display_mask_overflow(struct dsi_display *display, u32 flags, + bool enable) +{ + struct dsi_display_ctrl *ctrl; + int i; + + if (!(flags & DSI_CTRL_CMD_LAST_COMMAND)) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + dsi_ctrl_mask_overflow(ctrl->ctrl, enable); + } +} + +static int dsi_display_broadcast_cmd(struct dsi_display *display, + const struct mipi_dsi_msg *msg) +{ + int rc = 0; + u32 flags, m_flags; + struct dsi_display_ctrl *ctrl, *m_ctrl; + int i; + + m_flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_BROADCAST_MASTER | + DSI_CTRL_CMD_DEFER_TRIGGER | DSI_CTRL_CMD_FETCH_MEMORY); + flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_DEFER_TRIGGER | + DSI_CTRL_CMD_FETCH_MEMORY); + + if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) { + flags |= DSI_CTRL_CMD_LAST_COMMAND; + m_flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + + if (display->queue_cmd_waits || + msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) { + flags |= DSI_CTRL_CMD_ASYNC_WAIT; + m_flags |= DSI_CTRL_CMD_ASYNC_WAIT; + } + + /* + * 1. Setup commands in FIFO + * 2. Trigger commands + */ + m_ctrl = &display->ctrl[display->cmd_master_idx]; + dsi_display_mask_overflow(display, m_flags, true); + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, &m_flags); + if (rc) { + DSI_ERR("[%s] cmd transfer failed on master,rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (ctrl == m_ctrl) + continue; + + rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, &flags); + if (rc) { + DSI_ERR("[%s] cmd transfer failed, rc=%d\n", + display->name, rc); + goto error; + } + + rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl, flags); + if (rc) { + DSI_ERR("[%s] cmd trigger failed, rc=%d\n", + display->name, rc); + goto error; + } + } + + rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl, m_flags); + if (rc) { + DSI_ERR("[%s] cmd trigger failed for master, rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (ctrl == m_ctrl) + continue; + + rc = dsi_ctrl_clear_slave_dma_status(ctrl->ctrl, flags); + if (rc) { + DSI_ERR("[%s] clear interrupt status failed, rc=%d\n", + display->name, rc); + goto error; + } + } + +error: + dsi_display_mask_overflow(display, m_flags, false); + return rc; +} + +static int dsi_display_phy_sw_reset(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + + /* For continuous splash use case ctrl states are updated + * separately and hence we do an early return + */ + if (display->is_cont_splash_enabled) { + DSI_DEBUG("cont splash enabled, phy sw reset not required\n"); + return 0; + } + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + + rc = dsi_ctrl_phy_sw_reset(m_ctrl->ctrl); + if (rc) { + DSI_ERR("[%s] failed to reset phy, rc=%d\n", display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_phy_sw_reset(ctrl->ctrl); + if (rc) { + DSI_ERR("[%s] failed to reset phy, rc=%d\n", + display->name, rc); + goto error; + } + } + +error: + return rc; +} + +static int dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi) +{ + return 0; +} + +static int dsi_host_detach(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi) +{ + return 0; +} + +static ssize_t dsi_host_transfer(struct mipi_dsi_host *host, + const struct mipi_dsi_msg *msg) +{ + struct dsi_display *display; + int rc = 0, ret = 0; + + if (!host || !msg) { + DSI_ERR("Invalid params\n"); + return 0; + } + + display = to_dsi_display(host); + + /* Avoid sending DCS commands when ESD recovery is pending */ + if (atomic_read(&display->panel->esd_recovery_pending)) { + DSI_DEBUG("ESD recovery pending\n"); + return 0; + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable all DSI clocks, rc=%d\n", + display->name, rc); + goto error; + } + + rc = dsi_display_wake_up(display); + if (rc) { + DSI_ERR("[%s] failed to wake up display, rc=%d\n", + display->name, rc); + goto error_disable_clks; + } + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("[%s] failed to enable cmd engine, rc=%d\n", + display->name, rc); + goto error_disable_clks; + } + + if (display->tx_cmd_buf == NULL) { + rc = dsi_host_alloc_cmd_tx_buffer(display); + if (rc) { + DSI_ERR("failed to allocate cmd tx buffer memory\n"); + goto error_disable_cmd_engine; + } + } + + if (display->ctrl_count > 1 && !(msg->flags & MIPI_DSI_MSG_UNICAST)) { + rc = dsi_display_broadcast_cmd(display, msg); + if (rc) { + DSI_ERR("[%s] cmd broadcast failed, rc=%d\n", + display->name, rc); + goto error_disable_cmd_engine; + } + } else { + int ctrl_idx = (msg->flags & MIPI_DSI_MSG_UNICAST) ? + msg->ctrl : 0; + u32 cmd_flags = DSI_CTRL_CMD_FETCH_MEMORY; + + if (display->queue_cmd_waits || + msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) + cmd_flags |= DSI_CTRL_CMD_ASYNC_WAIT; + + rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg, + &cmd_flags); + if (rc) { + DSI_ERR("[%s] cmd transfer failed, rc=%d\n", + display->name, rc); + goto error_disable_cmd_engine; + } + } + +error_disable_cmd_engine: + ret = dsi_display_cmd_engine_disable(display); + if (ret) { + DSI_ERR("[%s]failed to disable DSI cmd engine, rc=%d\n", + display->name, ret); + } +error_disable_clks: + ret = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (ret) { + DSI_ERR("[%s] failed to disable all DSI clocks, rc=%d\n", + display->name, ret); + } +error: + return rc; +} + + +static struct mipi_dsi_host_ops dsi_host_ops = { + .attach = dsi_host_attach, + .detach = dsi_host_detach, + .transfer = dsi_host_transfer, +}; + +static int dsi_display_mipi_host_init(struct dsi_display *display) +{ + int rc = 0; + struct mipi_dsi_host *host = &display->host; + + host->dev = &display->pdev->dev; + host->ops = &dsi_host_ops; + + rc = mipi_dsi_host_register(host); + if (rc) { + DSI_ERR("[%s] failed to register mipi dsi host, rc=%d\n", + display->name, rc); + goto error; + } + +error: + return rc; +} +static int dsi_display_mipi_host_deinit(struct dsi_display *display) +{ + int rc = 0; + struct mipi_dsi_host *host = &display->host; + + mipi_dsi_host_unregister(host); + + host->dev = NULL; + host->ops = NULL; + + return rc; +} + +static int dsi_display_clocks_deinit(struct dsi_display *display) +{ + int rc = 0; + struct dsi_clk_link_set *src = &display->clock_info.src_clks; + struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; + struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; + + if (src->byte_clk) { + devm_clk_put(&display->pdev->dev, src->byte_clk); + src->byte_clk = NULL; + } + + if (src->pixel_clk) { + devm_clk_put(&display->pdev->dev, src->pixel_clk); + src->pixel_clk = NULL; + } + + if (mux->byte_clk) { + devm_clk_put(&display->pdev->dev, mux->byte_clk); + mux->byte_clk = NULL; + } + + if (mux->pixel_clk) { + devm_clk_put(&display->pdev->dev, mux->pixel_clk); + mux->pixel_clk = NULL; + } + + if (shadow->byte_clk) { + devm_clk_put(&display->pdev->dev, shadow->byte_clk); + shadow->byte_clk = NULL; + } + + if (shadow->pixel_clk) { + devm_clk_put(&display->pdev->dev, shadow->pixel_clk); + shadow->pixel_clk = NULL; + } + + return rc; +} + +static bool dsi_display_check_prefix(const char *clk_prefix, + const char *clk_name) +{ + return !!strnstr(clk_name, clk_prefix, strlen(clk_name)); +} + +static int dsi_display_get_clocks_count(struct dsi_display *display, + char *dsi_clk_name) +{ + if (display->fw) + return dsi_parser_count_strings(display->parser_node, + dsi_clk_name); + else + return of_property_count_strings(display->panel_node, + dsi_clk_name); +} + +static void dsi_display_get_clock_name(struct dsi_display *display, + char *dsi_clk_name, int index, + const char **clk_name) +{ + if (display->fw) + dsi_parser_read_string_index(display->parser_node, + dsi_clk_name, index, clk_name); + else + of_property_read_string_index(display->panel_node, + dsi_clk_name, index, clk_name); +} + +static int dsi_display_clocks_init(struct dsi_display *display) +{ + int i, rc = 0, num_clk = 0; + const char *clk_name; + const char *src_byte = "src_byte", *src_pixel = "src_pixel"; + const char *mux_byte = "mux_byte", *mux_pixel = "mux_pixel"; + const char *cphy_byte = "cphy_byte", *cphy_pixel = "cphy_pixel"; + const char *shadow_byte = "shadow_byte", *shadow_pixel = "shadow_pixel"; + const char *shadow_cphybyte = "shadow_cphybyte", + *shadow_cphypixel = "shadow_cphypixel"; + struct clk *dsi_clk; + struct dsi_clk_link_set *src = &display->clock_info.src_clks; + struct dsi_clk_link_set *mux = &display->clock_info.mux_clks; + struct dsi_clk_link_set *cphy = &display->clock_info.cphy_clks; + struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks; + struct dsi_clk_link_set *shadow_cphy = + &display->clock_info.shadow_cphy_clks; + struct dsi_dyn_clk_caps *dyn_clk_caps = &(display->panel->dyn_clk_caps); + char *dsi_clock_name; + + if (!strcmp(display->display_type, "primary")) + dsi_clock_name = "qcom,dsi-select-clocks"; + else + dsi_clock_name = "qcom,dsi-select-sec-clocks"; + + num_clk = dsi_display_get_clocks_count(display, dsi_clock_name); + + DSI_DEBUG("clk count=%d\n", num_clk); + + for (i = 0; i < num_clk; i++) { + dsi_display_get_clock_name(display, dsi_clock_name, i, + &clk_name); + + DSI_DEBUG("clock name:%s\n", clk_name); + + dsi_clk = devm_clk_get(&display->pdev->dev, clk_name); + if (IS_ERR_OR_NULL(dsi_clk)) { + rc = PTR_ERR(dsi_clk); + + DSI_ERR("failed to get %s, rc=%d\n", clk_name, rc); + + if (dsi_display_check_prefix(mux_byte, clk_name)) { + mux->byte_clk = NULL; + goto error; + } + if (dsi_display_check_prefix(mux_pixel, clk_name)) { + mux->pixel_clk = NULL; + goto error; + } + + if (dsi_display_check_prefix(cphy_byte, clk_name)) { + cphy->byte_clk = NULL; + goto error; + } + if (dsi_display_check_prefix(cphy_pixel, clk_name)) { + cphy->pixel_clk = NULL; + goto error; + } + + if (dyn_clk_caps->dyn_clk_support && + (display->panel->panel_mode == + DSI_OP_VIDEO_MODE)) { + + if (dsi_display_check_prefix(src_byte, + clk_name)) + src->byte_clk = NULL; + if (dsi_display_check_prefix(src_pixel, + clk_name)) + src->pixel_clk = NULL; + if (dsi_display_check_prefix(shadow_byte, + clk_name)) + shadow->byte_clk = NULL; + if (dsi_display_check_prefix(shadow_pixel, + clk_name)) + shadow->pixel_clk = NULL; + if (dsi_display_check_prefix(shadow_cphybyte, + clk_name)) + shadow_cphy->byte_clk = NULL; + if (dsi_display_check_prefix(shadow_cphypixel, + clk_name)) + shadow_cphy->pixel_clk = NULL; + + dyn_clk_caps->dyn_clk_support = false; + } + } + + if (dsi_display_check_prefix(src_byte, clk_name)) { + src->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(src_pixel, clk_name)) { + src->pixel_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(cphy_byte, clk_name)) { + cphy->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(cphy_pixel, clk_name)) { + cphy->pixel_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(mux_byte, clk_name)) { + mux->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(mux_pixel, clk_name)) { + mux->pixel_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(shadow_byte, clk_name)) { + shadow->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(shadow_pixel, clk_name)) { + shadow->pixel_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(shadow_cphybyte, clk_name)) { + shadow_cphy->byte_clk = dsi_clk; + continue; + } + + if (dsi_display_check_prefix(shadow_cphypixel, clk_name)) { + shadow_cphy->pixel_clk = dsi_clk; + continue; + } + } + + return 0; +error: + (void)dsi_display_clocks_deinit(display); + return rc; +} + +static int dsi_display_clk_ctrl_cb(void *priv, + struct dsi_clk_ctrl_info clk_state_info) +{ + int rc = 0; + struct dsi_display *display = NULL; + void *clk_handle = NULL; + + if (!priv) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + display = priv; + + if (clk_state_info.client == DSI_CLK_REQ_MDP_CLIENT) { + clk_handle = display->mdp_clk_handle; + } else if (clk_state_info.client == DSI_CLK_REQ_DSI_CLIENT) { + clk_handle = display->dsi_clk_handle; + } else { + DSI_ERR("invalid clk handle, return error\n"); + return -EINVAL; + } + + /* + * TODO: Wait for CMD_MDP_DONE interrupt if MDP client tries + * to turn off DSI clocks. + */ + rc = dsi_display_clk_ctrl(clk_handle, + clk_state_info.clk_type, clk_state_info.clk_state); + if (rc) { + DSI_ERR("[%s] failed to %d DSI %d clocks, rc=%d\n", + display->name, clk_state_info.clk_state, + clk_state_info.clk_type, rc); + return rc; + } + return 0; +} + +static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en) +{ + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl) + continue; + dsi_ctrl_isr_configure(ctrl->ctrl, en); + } +} + +int dsi_pre_clkoff_cb(void *priv, + enum dsi_clk_type clk, + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state) +{ + int rc = 0, i; + struct dsi_display *display = priv; + struct dsi_display_ctrl *ctrl; + + + /* + * If Idle Power Collapse occurs immediately after a CMD + * transfer with an asynchronous wait for DMA done, ensure + * that the work queued is scheduled and completed before turning + * off the clocks and disabling interrupts to validate the command + * transfer. + */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || !ctrl->ctrl->dma_wait_queued) + continue; + flush_workqueue(display->dma_cmd_workq); + cancel_work_sync(&ctrl->ctrl->dma_cmd_wait); + ctrl->ctrl->dma_wait_queued = false; + } + if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && + (l_type & DSI_LINK_LP_CLK)) { + /* + * If continuous clock is enabled then disable it + * before entering into ULPS Mode. + */ + if (display->panel->host_config.force_hs_clk_lane) + _dsi_display_continuous_clk_ctrl(display, false); + /* + * If ULPS feature is enabled, enter ULPS first. + * However, when blanking the panel, we should enter ULPS + * only if ULPS during suspend feature is enabled. + */ + if (!dsi_panel_initialized(display->panel)) { + if (display->panel->ulps_suspend_enabled) + rc = dsi_display_set_ulps(display, true); + } else if (dsi_panel_ulps_feature_enabled(display->panel)) { + rc = dsi_display_set_ulps(display, true); + } + if (rc) + DSI_ERR("%s: failed enable ulps, rc = %d\n", + __func__, rc); + } + + if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && + (l_type & DSI_LINK_HS_CLK)) { + /* + * PHY clock gating should be disabled before the PLL and the + * branch clocks are turned off. Otherwise, it is possible that + * the clock RCGs may not be turned off correctly resulting + * in clock warnings. + */ + rc = dsi_display_config_clk_gating(display, false); + if (rc) + DSI_ERR("[%s] failed to disable clk gating, rc=%d\n", + display->name, rc); + } + + if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) { + /* + * Enable DSI clamps only if entering idle power collapse or + * when ULPS during suspend is enabled.. + */ + if (dsi_panel_initialized(display->panel) || + display->panel->ulps_suspend_enabled) { + dsi_display_phy_idle_off(display); + rc = dsi_display_set_clamp(display, true); + if (rc) + DSI_ERR("%s: Failed to enable dsi clamps. rc=%d\n", + __func__, rc); + + rc = dsi_display_phy_reset_config(display, false); + if (rc) + DSI_ERR("%s: Failed to reset phy, rc=%d\n", + __func__, rc); + } else { + /* Make sure that controller is not in ULPS state when + * the DSI link is not active. + */ + rc = dsi_display_set_ulps(display, false); + if (rc) + DSI_ERR("%s: failed to disable ulps. rc=%d\n", + __func__, rc); + } + /* dsi will not be able to serve irqs from here on */ + dsi_display_ctrl_irq_update(display, false); + + /* cache the MISR values */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + dsi_ctrl_cache_misr(ctrl->ctrl); + } + + } + + return rc; +} + +int dsi_post_clkon_cb(void *priv, + enum dsi_clk_type clk, + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state) +{ + int rc = 0; + struct dsi_display *display = priv; + bool mmss_clamp = false; + + if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_LP_CLK)) { + mmss_clamp = display->clamp_enabled; + /* + * controller setup is needed if coming out of idle + * power collapse with clamps enabled. + */ + if (mmss_clamp) + dsi_display_ctrl_setup(display); + + /* + * Phy setup is needed if coming out of idle + * power collapse with clamps enabled. + */ + if (display->phy_idle_power_off || mmss_clamp) + dsi_display_phy_idle_on(display, mmss_clamp); + + if (display->ulps_enabled && mmss_clamp) { + /* + * ULPS Entry Request. This is needed if the lanes were + * in ULPS prior to power collapse, since after + * power collapse and reset, the DSI controller resets + * back to idle state and not ULPS. This ulps entry + * request will transition the state of the DSI + * controller to ULPS which will match the state of the + * DSI phy. This needs to be done prior to disabling + * the DSI clamps. + * + * Also, reset the ulps flag so that ulps_config + * function would reconfigure the controller state to + * ULPS. + */ + display->ulps_enabled = false; + rc = dsi_display_set_ulps(display, true); + if (rc) { + DSI_ERR("%s: Failed to enter ULPS. rc=%d\n", + __func__, rc); + goto error; + } + } + + rc = dsi_display_phy_reset_config(display, true); + if (rc) { + DSI_ERR("%s: Failed to reset phy, rc=%d\n", + __func__, rc); + goto error; + } + + rc = dsi_display_set_clamp(display, false); + if (rc) { + DSI_ERR("%s: Failed to disable dsi clamps. rc=%d\n", + __func__, rc); + goto error; + } + } + + if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_HS_CLK)) { + /* + * Toggle the resync FIFO everytime clock changes, except + * when cont-splash screen transition is going on. + * Toggling resync FIFO during cont splash transition + * can lead to blinks on the display. + */ + if (!display->is_cont_splash_enabled) + dsi_display_toggle_resync_fifo(display); + + if (display->ulps_enabled) { + rc = dsi_display_set_ulps(display, false); + if (rc) { + DSI_ERR("%s: failed to disable ulps, rc= %d\n", + __func__, rc); + goto error; + } + } + + if (display->panel->host_config.force_hs_clk_lane) + _dsi_display_continuous_clk_ctrl(display, true); + + rc = dsi_display_config_clk_gating(display, true); + if (rc) { + DSI_ERR("[%s] failed to enable clk gating %d\n", + display->name, rc); + goto error; + } + } + + /* enable dsi to serve irqs */ + if (clk & DSI_CORE_CLK) + dsi_display_ctrl_irq_update(display, true); + +error: + return rc; +} + +int dsi_post_clkoff_cb(void *priv, + enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state) +{ + int rc = 0; + struct dsi_display *display = priv; + + if (!display) { + DSI_ERR("%s: Invalid arg\n", __func__); + return -EINVAL; + } + + if ((clk_type & DSI_CORE_CLK) && + (curr_state == DSI_CLK_OFF)) { + rc = dsi_display_phy_power_off(display); + if (rc) + DSI_ERR("[%s] failed to power off PHY, rc=%d\n", + display->name, rc); + + rc = dsi_display_ctrl_power_off(display); + if (rc) + DSI_ERR("[%s] failed to power DSI vregs, rc=%d\n", + display->name, rc); + } + return rc; +} + +int dsi_pre_clkon_cb(void *priv, + enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state) +{ + int rc = 0; + struct dsi_display *display = priv; + + if (!display) { + DSI_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + if ((clk_type & DSI_CORE_CLK) && (new_state == DSI_CLK_ON)) { + /* + * Enable DSI core power + * 1.> PANEL_PM are controlled as part of + * panel_power_ctrl. Needed not be handled here. + * 2.> CTRL_PM need to be enabled/disabled + * only during unblank/blank. Their state should + * not be changed during static screen. + */ + + DSI_DEBUG("updating power states for ctrl and phy\n"); + rc = dsi_display_ctrl_power_on(display); + if (rc) { + DSI_ERR("[%s] failed to power on dsi controllers, rc=%d\n", + display->name, rc); + return rc; + } + + rc = dsi_display_phy_power_on(display); + if (rc) { + DSI_ERR("[%s] failed to power on dsi phy, rc = %d\n", + display->name, rc); + return rc; + } + + DSI_DEBUG("%s: Enable DSI core power\n", __func__); + } + + return rc; +} + +static void __set_lane_map_v2(u8 *lane_map_v2, + enum dsi_phy_data_lanes lane0, + enum dsi_phy_data_lanes lane1, + enum dsi_phy_data_lanes lane2, + enum dsi_phy_data_lanes lane3) +{ + lane_map_v2[DSI_LOGICAL_LANE_0] = lane0; + lane_map_v2[DSI_LOGICAL_LANE_1] = lane1; + lane_map_v2[DSI_LOGICAL_LANE_2] = lane2; + lane_map_v2[DSI_LOGICAL_LANE_3] = lane3; +} + +static int dsi_display_parse_lane_map(struct dsi_display *display) +{ + int rc = 0, i = 0; + const char *data; + u8 temp[DSI_LANE_MAX - 1]; + + if (!display) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + /* lane-map-v2 supersedes lane-map-v1 setting */ + rc = of_property_read_u8_array(display->pdev->dev.of_node, + "qcom,lane-map-v2", temp, (DSI_LANE_MAX - 1)); + if (!rc) { + for (i = DSI_LOGICAL_LANE_0; i < (DSI_LANE_MAX - 1); i++) + display->lane_map.lane_map_v2[i] = BIT(temp[i]); + return 0; + } else if (rc != EINVAL) { + DSI_DEBUG("Incorrect mapping, configure default\n"); + goto set_default; + } + + /* lane-map older version, for DSI controller version < 2.0 */ + data = of_get_property(display->pdev->dev.of_node, + "qcom,lane-map", NULL); + if (!data) + goto set_default; + + if (!strcmp(data, "lane_map_3012")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_3012; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_1, + DSI_PHYSICAL_LANE_2, + DSI_PHYSICAL_LANE_3, + DSI_PHYSICAL_LANE_0); + } else if (!strcmp(data, "lane_map_2301")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_2301; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_2, + DSI_PHYSICAL_LANE_3, + DSI_PHYSICAL_LANE_0, + DSI_PHYSICAL_LANE_1); + } else if (!strcmp(data, "lane_map_1230")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_1230; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_3, + DSI_PHYSICAL_LANE_0, + DSI_PHYSICAL_LANE_1, + DSI_PHYSICAL_LANE_2); + } else if (!strcmp(data, "lane_map_0321")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_0321; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_0, + DSI_PHYSICAL_LANE_3, + DSI_PHYSICAL_LANE_2, + DSI_PHYSICAL_LANE_1); + } else if (!strcmp(data, "lane_map_1032")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_1032; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_1, + DSI_PHYSICAL_LANE_0, + DSI_PHYSICAL_LANE_3, + DSI_PHYSICAL_LANE_2); + } else if (!strcmp(data, "lane_map_2103")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_2103; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_2, + DSI_PHYSICAL_LANE_1, + DSI_PHYSICAL_LANE_0, + DSI_PHYSICAL_LANE_3); + } else if (!strcmp(data, "lane_map_3210")) { + display->lane_map.lane_map_v1 = DSI_LANE_MAP_3210; + __set_lane_map_v2(display->lane_map.lane_map_v2, + DSI_PHYSICAL_LANE_3, + DSI_PHYSICAL_LANE_2, + DSI_PHYSICAL_LANE_1, + DSI_PHYSICAL_LANE_0); + } else { + DSI_WARN("%s: invalid lane map %s specified. defaulting to lane_map0123\n", + __func__, data); + goto set_default; + } + return 0; + +set_default: + /* default lane mapping */ + __set_lane_map_v2(display->lane_map.lane_map_v2, DSI_PHYSICAL_LANE_0, + DSI_PHYSICAL_LANE_1, DSI_PHYSICAL_LANE_2, DSI_PHYSICAL_LANE_3); + display->lane_map.lane_map_v1 = DSI_LANE_MAP_0123; + return 0; +} + +static int dsi_display_get_phandle_index( + struct dsi_display *display, + const char *propname, int count, int index) +{ + struct device_node *disp_node = display->panel_node; + u32 *val = NULL; + int rc = 0; + + val = kcalloc(count, sizeof(*val), GFP_KERNEL); + if (ZERO_OR_NULL_PTR(val)) { + rc = -ENOMEM; + goto end; + } + + if (index >= count) + goto end; + + if (display->fw) + rc = dsi_parser_read_u32_array(display->parser_node, + propname, val, count); + else + rc = of_property_read_u32_array(disp_node, propname, + val, count); + if (rc) + goto end; + + rc = val[index]; + + DSI_DEBUG("%s index=%d\n", propname, rc); +end: + kfree(val); + return rc; +} + +static int dsi_display_get_phandle_count(struct dsi_display *display, + const char *propname) +{ + if (display->fw) + return dsi_parser_count_u32_elems(display->parser_node, + propname); + else + return of_property_count_u32_elems(display->panel_node, + propname); +} + +static int dsi_display_parse_dt(struct dsi_display *display) +{ + int i, rc = 0; + u32 phy_count = 0; + struct device_node *of_node = display->pdev->dev.of_node; + char *dsi_ctrl_name, *dsi_phy_name; + + if (!strcmp(display->display_type, "primary")) { + dsi_ctrl_name = "qcom,dsi-ctrl-num"; + dsi_phy_name = "qcom,dsi-phy-num"; + } else { + dsi_ctrl_name = "qcom,dsi-sec-ctrl-num"; + dsi_phy_name = "qcom,dsi-sec-phy-num"; + } + + display->ctrl_count = dsi_display_get_phandle_count(display, + dsi_ctrl_name); + phy_count = dsi_display_get_phandle_count(display, dsi_phy_name); + + DSI_DEBUG("ctrl count=%d, phy count=%d\n", + display->ctrl_count, phy_count); + + if (!phy_count || !display->ctrl_count) { + DSI_ERR("no ctrl/phys found\n"); + rc = -ENODEV; + goto error; + } + + if (phy_count != display->ctrl_count) { + DSI_ERR("different ctrl and phy counts\n"); + rc = -ENODEV; + goto error; + } + + display_for_each_ctrl(i, display) { + struct dsi_display_ctrl *ctrl = &display->ctrl[i]; + int index; + index = dsi_display_get_phandle_index(display, dsi_ctrl_name, + display->ctrl_count, i); + ctrl->ctrl_of_node = of_parse_phandle(of_node, + "qcom,dsi-ctrl", index); + of_node_put(ctrl->ctrl_of_node); + + index = dsi_display_get_phandle_index(display, dsi_phy_name, + display->ctrl_count, i); + ctrl->phy_of_node = of_parse_phandle(of_node, + "qcom,dsi-phy", index); + of_node_put(ctrl->phy_of_node); + } + + /* Parse TE data */ + dsi_display_parse_te_data(display); + + /* Parse all external bridges from port 0 */ + display_for_each_ctrl(i, display) { + display->ext_bridge[i].node_of = + of_graph_get_remote_node(of_node, 0, i); + if (display->ext_bridge[i].node_of) + display->ext_bridge_cnt++; + else + break; + } + + DSI_DEBUG("success\n"); +error: + return rc; +} + +static int dsi_display_res_init(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + ctrl->ctrl = dsi_ctrl_get(ctrl->ctrl_of_node); + if (IS_ERR_OR_NULL(ctrl->ctrl)) { + rc = PTR_ERR(ctrl->ctrl); + DSI_ERR("failed to get dsi controller, rc=%d\n", rc); + ctrl->ctrl = NULL; + goto error_ctrl_put; + } + + ctrl->phy = dsi_phy_get(ctrl->phy_of_node); + if (IS_ERR_OR_NULL(ctrl->phy)) { + rc = PTR_ERR(ctrl->phy); + DSI_ERR("failed to get phy controller, rc=%d\n", rc); + dsi_ctrl_put(ctrl->ctrl); + ctrl->phy = NULL; + goto error_ctrl_put; + } + } + + display->panel = dsi_panel_get(&display->pdev->dev, + display->panel_node, + display->parser_node, + display->display_type, + display->cmdline_topology); + if (IS_ERR_OR_NULL(display->panel)) { + rc = PTR_ERR(display->panel); + DSI_ERR("failed to get panel, rc=%d\n", rc); + display->panel = NULL; + goto error_ctrl_put; + } + + display_for_each_ctrl(i, display) { + struct msm_dsi_phy *phy = display->ctrl[i].phy; + + phy->cfg.force_clk_lane_hs = + display->panel->host_config.force_hs_clk_lane; + phy->cfg.phy_type = + display->panel->host_config.phy_type; + } + + rc = dsi_display_parse_lane_map(display); + if (rc) { + DSI_ERR("Lane map not found, rc=%d\n", rc); + goto error_ctrl_put; + } + + rc = dsi_display_clocks_init(display); + if (rc) { + DSI_ERR("Failed to parse clock data, rc=%d\n", rc); + goto error_ctrl_put; + } + + INIT_DELAYED_WORK(&display->panel->gamma_read_work, dsi_display_gamma_read_work); + DSI_ERR("INIT_DELAYED_WORK: dsi_display_gamma_read_work\n"); + return 0; +error_ctrl_put: + for (i = i - 1; i >= 0; i--) { + ctrl = &display->ctrl[i]; + dsi_ctrl_put(ctrl->ctrl); + dsi_phy_put(ctrl->phy); + } + return rc; +} + +static int dsi_display_res_deinit(struct dsi_display *display) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + rc = dsi_display_clocks_deinit(display); + if (rc) + DSI_ERR("clocks deinit failed, rc=%d\n", rc); + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_phy_put(ctrl->phy); + dsi_ctrl_put(ctrl->ctrl); + } + + if (display->panel) + dsi_panel_put(display->panel); + + return rc; +} + +static int dsi_display_validate_mode_set(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + /* + * To set a mode: + * 1. Controllers should be turned off. + * 2. Link clocks should be off. + * 3. Phy should be disabled. + */ + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if ((ctrl->power_state > DSI_CTRL_POWER_VREG_ON) || + (ctrl->phy_enabled)) { + rc = -EINVAL; + goto error; + } + } + +error: + return rc; +} + +static bool dsi_display_is_seamless_dfps_possible( + const struct dsi_display *display, + const struct dsi_display_mode *tgt, + const enum dsi_dfps_type dfps_type) +{ + struct dsi_display_mode *cur; + + if (!display || !tgt || !display->panel) { + DSI_ERR("Invalid params\n"); + return false; + } + + cur = display->panel->cur_mode; + + if (cur->timing.h_active != tgt->timing.h_active) { + DSI_DEBUG("timing.h_active differs %d %d\n", + cur->timing.h_active, tgt->timing.h_active); + return false; + } + + if (cur->timing.h_back_porch != tgt->timing.h_back_porch) { + DSI_DEBUG("timing.h_back_porch differs %d %d\n", + cur->timing.h_back_porch, + tgt->timing.h_back_porch); + return false; + } + + if (cur->timing.h_sync_width != tgt->timing.h_sync_width) { + DSI_DEBUG("timing.h_sync_width differs %d %d\n", + cur->timing.h_sync_width, + tgt->timing.h_sync_width); + return false; + } + + if (cur->timing.h_front_porch != tgt->timing.h_front_porch) { + DSI_DEBUG("timing.h_front_porch differs %d %d\n", + cur->timing.h_front_porch, + tgt->timing.h_front_porch); + if (dfps_type != DSI_DFPS_IMMEDIATE_HFP) + return false; + } + + if (cur->timing.h_skew != tgt->timing.h_skew) { + DSI_DEBUG("timing.h_skew differs %d %d\n", + cur->timing.h_skew, + tgt->timing.h_skew); + return false; + } + + /* skip polarity comparison */ + + if (cur->timing.v_active != tgt->timing.v_active) { + DSI_DEBUG("timing.v_active differs %d %d\n", + cur->timing.v_active, + tgt->timing.v_active); + return false; + } + + if (cur->timing.v_back_porch != tgt->timing.v_back_porch) { + DSI_DEBUG("timing.v_back_porch differs %d %d\n", + cur->timing.v_back_porch, + tgt->timing.v_back_porch); + return false; + } + + if (cur->timing.v_sync_width != tgt->timing.v_sync_width) { + DSI_DEBUG("timing.v_sync_width differs %d %d\n", + cur->timing.v_sync_width, + tgt->timing.v_sync_width); + return false; + } + + if (cur->timing.v_front_porch != tgt->timing.v_front_porch) { + DSI_DEBUG("timing.v_front_porch differs %d %d\n", + cur->timing.v_front_porch, + tgt->timing.v_front_porch); + if (dfps_type != DSI_DFPS_IMMEDIATE_VFP) + return false; + } + + /* skip polarity comparison */ + + if (cur->timing.refresh_rate == tgt->timing.refresh_rate) + DSI_DEBUG("timing.refresh_rate identical %d %d\n", + cur->timing.refresh_rate, + tgt->timing.refresh_rate); + + if (cur->pixel_clk_khz != tgt->pixel_clk_khz) + DSI_DEBUG("pixel_clk_khz differs %d %d\n", + cur->pixel_clk_khz, tgt->pixel_clk_khz); + + if (cur->dsi_mode_flags != tgt->dsi_mode_flags) + DSI_DEBUG("flags differs %d %d\n", + cur->dsi_mode_flags, tgt->dsi_mode_flags); + + return true; +} + +void dsi_display_update_byte_intf_div(struct dsi_display *display) +{ + struct dsi_host_common_cfg *config; + struct dsi_display_ctrl *m_ctrl; + int phy_ver; + + m_ctrl = &display->ctrl[display->cmd_master_idx]; + config = &display->panel->host_config; + + phy_ver = dsi_phy_get_version(m_ctrl->phy); + if (phy_ver <= DSI_PHY_VERSION_2_0) + config->byte_intf_clk_div = 1; + else + config->byte_intf_clk_div = 2; +} + +static int dsi_display_update_dsi_bitrate(struct dsi_display *display, + u32 bit_clk_rate) +{ + int rc = 0; + int i; + + DSI_DEBUG("%s:bit rate:%d\n", __func__, bit_clk_rate); + if (!display->panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (bit_clk_rate == 0) { + DSI_ERR("Invalid bit clock rate\n"); + return -EINVAL; + } + + display->config.bit_clk_rate_hz = bit_clk_rate; + + display_for_each_ctrl(i, display) { + struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i]; + struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl; + u32 num_of_lanes = 0, bpp, byte_intf_clk_div; + u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate, + byte_intf_clk_rate; + u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */ + struct dsi_host_common_cfg *host_cfg; + + mutex_lock(&ctrl->ctrl_lock); + + host_cfg = &display->panel->host_config; + if (host_cfg->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host_cfg->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + if (num_of_lanes == 0) { + DSI_ERR("Invalid lane count\n"); + rc = -EINVAL; + goto error; + } + + bpp = dsi_pixel_format_to_bpp(host_cfg->dst_format); + + bit_rate = display->config.bit_clk_rate_hz * num_of_lanes; + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + pclk_rate = bit_rate; + do_div(pclk_rate, bpp); + if (host_cfg->phy_type == DSI_PHY_TYPE_DPHY) { + bit_rate_per_lane = bit_rate; + do_div(bit_rate_per_lane, num_of_lanes); + byte_clk_rate = bit_rate_per_lane; + do_div(byte_clk_rate, 8); + byte_intf_clk_rate = byte_clk_rate; + byte_intf_clk_div = host_cfg->byte_intf_clk_div; + do_div(byte_intf_clk_rate, byte_intf_clk_div); + } else { + bit_rate_per_lane = bit_clk_rate; + pclk_rate *= bits_per_symbol; + do_div(pclk_rate, num_of_symbols); + byte_clk_rate = bit_clk_rate; + do_div(byte_clk_rate, num_of_symbols); + + /* For CPHY, byte_intf_clk is same as byte_clk */ + byte_intf_clk_rate = byte_clk_rate; + } + + DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", + bit_rate, bit_rate_per_lane); + DSI_DEBUG("byte_clk_rate = %llu, byte_intf_clk_rate = %llu\n", + byte_clk_rate, byte_intf_clk_rate); + DSI_DEBUG("pclk_rate = %llu\n", pclk_rate); + SDE_EVT32(i, bit_rate, byte_clk_rate, pclk_rate); + + ctrl->clk_freq.byte_clk_rate = byte_clk_rate; + ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate; + ctrl->clk_freq.pix_clk_rate = pclk_rate; + rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle, + ctrl->clk_freq, ctrl->cell_index); + if (rc) { + DSI_ERR("Failed to update link frequencies\n"); + goto error; + } + + ctrl->host_config.bit_clk_rate_hz = bit_clk_rate; +error: + mutex_unlock(&ctrl->ctrl_lock); + + /* TODO: recover ctrl->clk_freq in case of failure */ + if (rc) + return rc; + } + + return 0; +} + +static void _dsi_display_calc_pipe_delay(struct dsi_display *display, + struct dsi_dyn_clk_delay *delay, + struct dsi_display_mode *mode) +{ + u32 esc_clk_rate_hz; + u32 pclk_to_esc_ratio, byte_to_esc_ratio, hr_bit_to_esc_ratio; + u32 hsync_period = 0; + struct dsi_display_ctrl *m_ctrl; + struct dsi_ctrl *dsi_ctrl; + struct dsi_phy_cfg *cfg; + int phy_ver; + + m_ctrl = &display->ctrl[display->clk_master_idx]; + dsi_ctrl = m_ctrl->ctrl; + + cfg = &(m_ctrl->phy->cfg); + + esc_clk_rate_hz = dsi_ctrl->clk_freq.esc_clk_rate; + pclk_to_esc_ratio = (dsi_ctrl->clk_freq.pix_clk_rate / + esc_clk_rate_hz); + byte_to_esc_ratio = (dsi_ctrl->clk_freq.byte_clk_rate / + esc_clk_rate_hz); + hr_bit_to_esc_ratio = ((dsi_ctrl->clk_freq.byte_clk_rate * 4) / + esc_clk_rate_hz); + + hsync_period = DSI_H_TOTAL_DSC(&mode->timing); + delay->pipe_delay = (hsync_period + 1) / pclk_to_esc_ratio; + if (!display->panel->video_config.eof_bllp_lp11_en) + delay->pipe_delay += (17 / pclk_to_esc_ratio) + + ((21 + (display->config.common_config.t_clk_pre + 1) + + (display->config.common_config.t_clk_post + 1)) / + byte_to_esc_ratio) + + ((((cfg->timing.lane_v3[8] >> 1) + 1) + + ((cfg->timing.lane_v3[6] >> 1) + 1) + + ((cfg->timing.lane_v3[3] * 4) + + (cfg->timing.lane_v3[5] >> 1) + 1) + + ((cfg->timing.lane_v3[7] >> 1) + 1) + + ((cfg->timing.lane_v3[1] >> 1) + 1) + + ((cfg->timing.lane_v3[4] >> 1) + 1)) / + hr_bit_to_esc_ratio); + + delay->pipe_delay2 = 0; + if (display->panel->host_config.force_hs_clk_lane) + delay->pipe_delay2 = (6 / byte_to_esc_ratio) + + ((((cfg->timing.lane_v3[1] >> 1) + 1) + + ((cfg->timing.lane_v3[4] >> 1) + 1)) / + hr_bit_to_esc_ratio); + + /* + * 100us pll delay recommended for phy ver 2.0 and 3.0 + * 25us pll delay recommended for phy ver 4.0 + */ + phy_ver = dsi_phy_get_version(m_ctrl->phy); + if (phy_ver <= DSI_PHY_VERSION_3_0) + delay->pll_delay = 100; + else + delay->pll_delay = 25; + + delay->pll_delay = ((delay->pll_delay * esc_clk_rate_hz) / 1000000); +} + +/* + * dsi_display_is_type_cphy - check if panel type is cphy + * @display: Pointer to private display structure + * Returns: True if panel type is cphy + */ +static inline bool dsi_display_is_type_cphy(struct dsi_display *display) +{ + return (display->panel->host_config.phy_type == + DSI_PHY_TYPE_CPHY) ? true : false; +} + +static int _dsi_display_dyn_update_clks(struct dsi_display *display, + struct link_clk_freq *bkp_freq) +{ + int rc = 0, i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + struct dsi_clk_link_set *parent_clk, *enable_clk; + + m_ctrl = &display->ctrl[display->clk_master_idx]; + + if (dsi_display_is_type_cphy(display)) { + enable_clk = &display->clock_info.cphy_clks; + parent_clk = &display->clock_info.shadow_cphy_clks; + } else { + enable_clk = &display->clock_info.src_clks; + parent_clk = &display->clock_info.shadow_clks; + } + + dsi_clk_prepare_enable(enable_clk); + + rc = dsi_clk_update_parent(parent_clk, + &display->clock_info.mux_clks); + if (rc) { + DSI_ERR("failed to update mux parent\n"); + goto exit; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle, + ctrl->ctrl->clk_freq.byte_clk_rate, + ctrl->ctrl->clk_freq.byte_intf_clk_rate, i); + if (rc) { + DSI_ERR("failed to set byte rate for index:%d\n", i); + goto recover_byte_clk; + } + rc = dsi_clk_set_pixel_clk_rate(display->dsi_clk_handle, + ctrl->ctrl->clk_freq.pix_clk_rate, i); + if (rc) { + DSI_ERR("failed to set pix rate for index:%d\n", i); + goto recover_pix_clk; + } + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (ctrl == m_ctrl) + continue; + dsi_phy_dynamic_refresh_trigger(ctrl->phy, false); + } + dsi_phy_dynamic_refresh_trigger(m_ctrl->phy, true); + + /* wait for dynamic refresh done */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_wait4dynamic_refresh_done(ctrl->ctrl); + if (rc) { + DSI_ERR("wait4dynamic refresh failed for dsi:%d\n", i); + goto recover_pix_clk; + } else { + DSI_INFO("dynamic refresh done on dsi: %s\n", + i ? "slave" : "master"); + } + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_phy_dynamic_refresh_clear(ctrl->phy); + } + + rc = dsi_clk_update_parent(enable_clk, + &display->clock_info.mux_clks); + + if (rc) + DSI_ERR("could not switch back to src clks %d\n", rc); + + dsi_clk_disable_unprepare(enable_clk); + + return rc; + +recover_pix_clk: + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + dsi_clk_set_pixel_clk_rate(display->dsi_clk_handle, + bkp_freq->pix_clk_rate, i); + } + +recover_byte_clk: + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + dsi_clk_set_byte_clk_rate(display->dsi_clk_handle, + bkp_freq->byte_clk_rate, + bkp_freq->byte_intf_clk_rate, i); + } + +exit: + dsi_clk_disable_unprepare(&display->clock_info.src_clks); + + return rc; +} + +static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display, + struct dsi_display_mode *mode) +{ + int rc = 0, mask, i; + struct dsi_display_ctrl *m_ctrl, *ctrl; + struct dsi_dyn_clk_delay delay; + struct link_clk_freq bkp_freq; + + dsi_panel_acquire_panel_lock(display->panel); + + m_ctrl = &display->ctrl[display->clk_master_idx]; + + dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + + /* mask PLL unlock, FIFO overflow and underflow errors */ + mask = BIT(DSI_PLL_UNLOCK_ERR) | BIT(DSI_FIFO_UNDERFLOW) | + BIT(DSI_FIFO_OVERFLOW); + dsi_display_mask_ctrl_error_interrupts(display, mask, true); + + /* update the phy timings based on new mode */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_phy_update_phy_timings(ctrl->phy, &display->config); + } + + /* back up existing rates to handle failure case */ + bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate; + bkp_freq.byte_intf_clk_rate = m_ctrl->ctrl->clk_freq.byte_intf_clk_rate; + bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate; + bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate; + + rc = dsi_display_update_dsi_bitrate(display, mode->timing.clk_rate_hz); + if (rc) { + DSI_ERR("failed set link frequencies %d\n", rc); + goto exit; + } + + /* calculate pipe delays */ + _dsi_display_calc_pipe_delay(display, &delay, mode); + + /* configure dynamic refresh ctrl registers */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->phy) + continue; + if (ctrl == m_ctrl) + dsi_phy_config_dynamic_refresh(ctrl->phy, &delay, true); + else + dsi_phy_config_dynamic_refresh(ctrl->phy, &delay, + false); + } + + rc = _dsi_display_dyn_update_clks(display, &bkp_freq); + +exit: + dsi_display_mask_ctrl_error_interrupts(display, mask, false); + + dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_ALL_CLKS, + DSI_CLK_OFF); + + /* store newly calculated phy timings in mode private info */ + dsi_phy_dyn_refresh_cache_phy_timings(m_ctrl->phy, + mode->priv_info->phy_timing_val, + mode->priv_info->phy_timing_len); + + dsi_panel_release_panel_lock(display->panel); + + return rc; +} + +static int dsi_display_dynamic_clk_configure_cmd(struct dsi_display *display, + int clk_rate) +{ + int rc = 0; + + if (clk_rate <= 0) { + DSI_ERR("%s: bitrate should be greater than 0\n", __func__); + return -EINVAL; + } + + if (clk_rate == display->cached_clk_rate) { + DSI_INFO("%s: ignore duplicated DSI clk setting\n", __func__); + return rc; + } + + display->cached_clk_rate = clk_rate; + + rc = dsi_display_update_dsi_bitrate(display, clk_rate); + if (!rc) { + DSI_INFO("%s: bit clk is ready to be configured to '%d'\n", + __func__, clk_rate); + atomic_set(&display->clkrate_change_pending, 1); + } else { + DSI_ERR("%s: Failed to prepare to configure '%d'. rc = %d\n", + __func__, clk_rate, rc); + /* Caching clock failed, so don't go on doing so. */ + atomic_set(&display->clkrate_change_pending, 0); + display->cached_clk_rate = 0; + } + + return rc; +} + +static int dsi_display_dfps_update(struct dsi_display *display, + struct dsi_display_mode *dsi_mode) +{ + struct dsi_mode_info *timing; + struct dsi_display_ctrl *m_ctrl, *ctrl; + struct dsi_display_mode *panel_mode; + struct dsi_dfps_capabilities dfps_caps; + int rc = 0; + int i = 0; + struct dsi_dyn_clk_caps *dyn_clk_caps; + + if (!display || !dsi_mode || !display->panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + timing = &dsi_mode->timing; + + dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + dyn_clk_caps = &(display->panel->dyn_clk_caps); + if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) { + DSI_ERR("dfps or constant fps not supported\n"); + return -ENOTSUPP; + } + + if (dfps_caps.type == DSI_DFPS_IMMEDIATE_CLK) { + DSI_ERR("dfps clock method not supported\n"); + return -ENOTSUPP; + } + + /* For split DSI, update the clock master first */ + + DSI_DEBUG("configuring seamless dynamic fps\n\n"); + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + + m_ctrl = &display->ctrl[display->clk_master_idx]; + rc = dsi_ctrl_async_timing_update(m_ctrl->ctrl, timing); + if (rc) { + DSI_ERR("[%s] failed to dfps update host_%d, rc=%d\n", + display->name, i, rc); + goto error; + } + + /* Update the rest of the controllers */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_async_timing_update(ctrl->ctrl, timing); + if (rc) { + DSI_ERR("[%s] failed to dfps update host_%d, rc=%d\n", + display->name, i, rc); + goto error; + } + } + + panel_mode = display->panel->cur_mode; + memcpy(panel_mode, dsi_mode, sizeof(*panel_mode)); + /* + * dsi_mode_flags flags are used to communicate with other drm driver + * components, and are transient. They aren't inherently part of the + * display panel's mode and shouldn't be saved into the cached currently + * active mode. + */ + panel_mode->dsi_mode_flags = 0; + +error: + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); + return rc; +} + +static int dsi_display_dfps_calc_front_porch( + u32 old_fps, + u32 new_fps, + u32 a_total, + u32 b_total, + u32 b_fp, + u32 *b_fp_out) +{ + s32 b_fp_new; + int add_porches, diff; + + if (!b_fp_out) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (!a_total || !new_fps) { + DSI_ERR("Invalid pixel total or new fps in mode request\n"); + return -EINVAL; + } + + /* + * Keep clock, other porches constant, use new fps, calc front porch + * new_vtotal = old_vtotal * (old_fps / new_fps ) + * new_vfp - old_vfp = new_vtotal - old_vtotal + * new_vfp = old_vfp + old_vtotal * ((old_fps - new_fps)/ new_fps) + */ + diff = abs(old_fps - new_fps); + add_porches = mult_frac(b_total, diff, new_fps); + + if (old_fps > new_fps) + b_fp_new = b_fp + add_porches; + else + b_fp_new = b_fp - add_porches; + + DSI_DEBUG("fps %u a %u b %u b_fp %u new_fp %d\n", + new_fps, a_total, b_total, b_fp, b_fp_new); + + if (b_fp_new < 0) { + DSI_ERR("Invalid new_hfp calcluated%d\n", b_fp_new); + return -EINVAL; + } + + /** + * TODO: To differentiate from clock method when communicating to the + * other components, perhaps we should set clk here to original value + */ + *b_fp_out = b_fp_new; + + return 0; +} + +/** + * dsi_display_get_dfps_timing() - Get the new dfps values. + * @display: DSI display handle. + * @adj_mode: Mode value structure to be changed. + * It contains old timing values and latest fps value. + * New timing values are updated based on new fps. + * @curr_refresh_rate: Current fps rate. + * If zero , current fps rate is taken from + * display->panel->cur_mode. + * Return: error code. + */ +static int dsi_display_get_dfps_timing(struct dsi_display *display, + struct dsi_display_mode *adj_mode, + u32 curr_refresh_rate) +{ + struct dsi_dfps_capabilities dfps_caps; + struct dsi_display_mode per_ctrl_mode; + struct dsi_mode_info *timing; + struct dsi_ctrl *m_ctrl; + + int rc = 0; + + if (!display || !adj_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + m_ctrl = display->ctrl[display->clk_master_idx].ctrl; + + dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + if (!dfps_caps.dfps_support) { + DSI_ERR("dfps not supported by panel\n"); + return -EINVAL; + } + + per_ctrl_mode = *adj_mode; + adjust_timing_by_ctrl_count(display, &per_ctrl_mode); + + if (!curr_refresh_rate) { + if (!dsi_display_is_seamless_dfps_possible(display, + &per_ctrl_mode, dfps_caps.type)) { + DSI_ERR("seamless dynamic fps not supported for mode\n"); + return -EINVAL; + } + if (display->panel->cur_mode) { + curr_refresh_rate = + display->panel->cur_mode->timing.refresh_rate; + } else { + DSI_ERR("cur_mode is not initialized\n"); + return -EINVAL; + } + } + /* TODO: Remove this direct reference to the dsi_ctrl */ + timing = &per_ctrl_mode.timing; + + switch (dfps_caps.type) { + case DSI_DFPS_IMMEDIATE_VFP: + rc = dsi_display_dfps_calc_front_porch( + curr_refresh_rate, + timing->refresh_rate, + DSI_H_TOTAL_DSC(timing), + DSI_V_TOTAL(timing), + timing->v_front_porch, + &adj_mode->timing.v_front_porch); + SDE_EVT32(SDE_EVTLOG_FUNC_CASE1, DSI_DFPS_IMMEDIATE_VFP, + curr_refresh_rate, timing->refresh_rate, + timing->v_front_porch, adj_mode->timing.v_front_porch); + break; + + case DSI_DFPS_IMMEDIATE_HFP: + rc = dsi_display_dfps_calc_front_porch( + curr_refresh_rate, + timing->refresh_rate, + DSI_V_TOTAL(timing), + DSI_H_TOTAL_DSC(timing), + timing->h_front_porch, + &adj_mode->timing.h_front_porch); + SDE_EVT32(SDE_EVTLOG_FUNC_CASE2, DSI_DFPS_IMMEDIATE_HFP, + curr_refresh_rate, timing->refresh_rate, + timing->h_front_porch, adj_mode->timing.h_front_porch); + if (!rc) + adj_mode->timing.h_front_porch *= display->ctrl_count; + break; + + default: + DSI_ERR("Unsupported DFPS mode %d\n", dfps_caps.type); + rc = -ENOTSUPP; + } + + return rc; +} + +static bool dsi_display_validate_mode_seamless(struct dsi_display *display, + struct dsi_display_mode *adj_mode) +{ + int rc = 0; + + if (!display || !adj_mode) { + DSI_ERR("Invalid params\n"); + return false; + } + + /* Currently the only seamless transition is dynamic fps */ + rc = dsi_display_get_dfps_timing(display, adj_mode, 0); + if (rc) { + DSI_DEBUG("Dynamic FPS not supported for seamless\n"); + } else { + DSI_DEBUG("Mode switch is seamless Dynamic FPS\n"); + adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS | + DSI_MODE_FLAG_VBLANK_PRE_MODESET; + } + + return rc; +} + +static void dsi_display_validate_dms_fps(struct dsi_display_mode *cur_mode, + struct dsi_display_mode *to_mode) +{ + u32 cur_fps, to_fps; + u32 cur_h_active, to_h_active; + u32 cur_v_active, to_v_active; + + cur_fps = cur_mode->timing.refresh_rate; + to_fps = to_mode->timing.refresh_rate; + cur_h_active = cur_mode->timing.h_active; + cur_v_active = cur_mode->timing.v_active; + to_h_active = to_mode->timing.h_active; + to_v_active = to_mode->timing.v_active; + + if ((cur_h_active == to_h_active) && (cur_v_active == to_v_active) && + (cur_fps != to_fps)) { + to_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS_FPS; + DSI_DEBUG("DMS Modeset with FPS change\n"); + } else { + to_mode->dsi_mode_flags &= ~DSI_MODE_FLAG_DMS_FPS; + } +} + + +static int dsi_display_set_mode_sub(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags) +{ + int rc = 0, clk_rate = 0; + int i; + struct dsi_display_ctrl *ctrl; + struct dsi_display_mode_priv_info *priv_info; + bool commit_phy_timing = false; + + priv_info = mode->priv_info; + if (!priv_info) { + DSI_ERR("[%s] failed to get private info of the display mode\n", + display->name); + return -EINVAL; + } + + SDE_EVT32(mode->dsi_mode_flags, mode->panel_mode); + if (mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) { + display->config.panel_mode = mode->panel_mode; + display->panel->panel_mode = mode->panel_mode; + } + rc = dsi_panel_get_host_cfg_for_mode(display->panel, + mode, + &display->config); + if (rc) { + DSI_ERR("[%s] failed to get host config for mode, rc=%d\n", + display->name, rc); + goto error; + } + + memcpy(&display->config.lane_map, &display->lane_map, + sizeof(display->lane_map)); + + if (mode->dsi_mode_flags & + (DSI_MODE_FLAG_DFPS | DSI_MODE_FLAG_VRR)) { + rc = dsi_display_dfps_update(display, mode); + if (rc) { + DSI_ERR("[%s]DSI dfps update failed, rc=%d\n", + display->name, rc); + goto error; + } + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_update_host_config(ctrl->ctrl, + &display->config, mode, mode->dsi_mode_flags, + display->dsi_clk_handle); + if (rc) { + DSI_ERR("failed to update ctrl config\n"); + goto error; + } + } + if (priv_info->phy_timing_len) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_phy_set_timing_params(ctrl->phy, + priv_info->phy_timing_val, + priv_info->phy_timing_len, + commit_phy_timing); + if (rc) + DSI_ERR("Fail to add timing params\n"); + } + } + if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) + return rc; + } + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { + if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { + rc = dsi_display_dynamic_clk_switch_vid(display, mode); + if (rc) + DSI_ERR("dynamic clk change failed %d\n", rc); + /* + * skip rest of the opearations since + * dsi_display_dynamic_clk_switch_vid() already takes + * care of them. + */ + return rc; + } else if (display->panel->panel_mode == DSI_OP_CMD_MODE) { + clk_rate = mode->timing.clk_rate_hz; + rc = dsi_display_dynamic_clk_configure_cmd(display, + clk_rate); + if (rc) { + DSI_ERR("Failed to configure dynamic clk\n"); + return rc; + } + } + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config, + mode, mode->dsi_mode_flags, + display->dsi_clk_handle); + if (rc) { + DSI_ERR("[%s] failed to update ctrl config, rc=%d\n", + display->name, rc); + goto error; + } + } + + if ((mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) && + (display->panel->panel_mode == DSI_OP_CMD_MODE)) { + u64 cur_bitclk = display->panel->cur_mode->timing.clk_rate_hz; + u64 to_bitclk = mode->timing.clk_rate_hz; + commit_phy_timing = true; + + /* No need to set clkrate pending flag if clocks are same */ + if ((!cur_bitclk && !to_bitclk) || (cur_bitclk != to_bitclk)) + atomic_set(&display->clkrate_change_pending, 1); + + dsi_display_validate_dms_fps(display->panel->cur_mode, mode); + } + + if (priv_info->phy_timing_len) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_phy_set_timing_params(ctrl->phy, + priv_info->phy_timing_val, + priv_info->phy_timing_len, + commit_phy_timing); + if (rc) + DSI_ERR("failed to add DSI PHY timing params\n"); + } + } +error: + return rc; +} + +/** + * _dsi_display_dev_init - initializes the display device + * Initialization will acquire references to the resources required for the + * display hardware to function. + * @display: Handle to the display + * Returns: Zero on success + */ +static int _dsi_display_dev_init(struct dsi_display *display) +{ + int rc = 0; + + if (!display) { + DSI_ERR("invalid display\n"); + return -EINVAL; + } + + if (!display->panel_node && !display->fw) + return 0; + + mutex_lock(&display->display_lock); + + display->parser = dsi_parser_get(&display->pdev->dev); + if (display->fw && display->parser) + display->parser_node = dsi_parser_get_head_node( + display->parser, display->fw->data, + display->fw->size); + + rc = dsi_display_parse_dt(display); + if (rc) { + DSI_ERR("[%s] failed to parse dt, rc=%d\n", display->name, rc); + goto error; + } + + rc = dsi_display_res_init(display); + if (rc) { + DSI_ERR("[%s] failed to initialize resources, rc=%d\n", + display->name, rc); + goto error; + } +error: + mutex_unlock(&display->display_lock); + return rc; +} + +/** + * _dsi_display_dev_deinit - deinitializes the display device + * All the resources acquired during device init will be released. + * @display: Handle to the display + * Returns: Zero on success + */ +static int _dsi_display_dev_deinit(struct dsi_display *display) +{ + int rc = 0; + + if (!display) { + DSI_ERR("invalid display\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + rc = dsi_display_res_deinit(display); + if (rc) + DSI_ERR("[%s] failed to deinitialize resource, rc=%d\n", + display->name, rc); + + mutex_unlock(&display->display_lock); + + return rc; +} + +/** + * dsi_display_cont_splash_config() - Initialize resources for continuous splash + * @dsi_display: Pointer to dsi display + * Returns: Zero on success + */ +int dsi_display_cont_splash_config(void *dsi_display) +{ + struct dsi_display *display = dsi_display; + int rc = 0; + + /* Vote for gdsc required to read register address space */ + if (!display) { + DSI_ERR("invalid input display param\n"); + return -EINVAL; + } + + rc = pm_runtime_get_sync(display->drm_dev->dev); + if (rc < 0) { + DSI_ERR("failed to vote gdsc for continuous splash, rc=%d\n", + rc); + return rc; + } + + mutex_lock(&display->display_lock); + + display->is_cont_splash_enabled = true; + + /* Update splash status for clock manager */ + dsi_display_clk_mngr_update_splash_status(display->clk_mngr, + display->is_cont_splash_enabled); + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY, display->is_cont_splash_enabled); + + /* Set up ctrl isr before enabling core clk */ + dsi_display_ctrl_isr_configure(display, true); + + /* Vote for Core clk and link clk. Votes on ctrl and phy + * regulator are inplicit from pre clk on callback + */ + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI link clocks, rc=%d\n", + display->name, rc); + goto clk_manager_update; + } + + /* Vote on panel regulator will be removed during suspend path */ + rc = dsi_pwr_enable_regulator(&display->panel->power_info, true); + if (rc) { + DSI_ERR("[%s] failed to enable vregs, rc=%d\n", + display->panel->name, rc); + goto clks_disabled; + } + + dsi_config_host_engine_state_for_cont_splash(display); + mutex_unlock(&display->display_lock); + + /* Set the current brightness level */ + dsi_panel_bl_handoff(display->panel); + + return rc; + +clks_disabled: + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + +clk_manager_update: + dsi_display_ctrl_isr_configure(display, false); + /* Update splash status for clock manager */ + dsi_display_clk_mngr_update_splash_status(display->clk_mngr, + false); + pm_runtime_put_sync(display->drm_dev->dev); + display->is_cont_splash_enabled = false; + mutex_unlock(&display->display_lock); + return rc; +} + +/** + * dsi_display_splash_res_cleanup() - cleanup for continuous splash + * @display: Pointer to dsi display + * Returns: Zero on success + */ +int dsi_display_splash_res_cleanup(struct dsi_display *display) +{ + int rc = 0; + + if (!display->is_cont_splash_enabled) + return 0; + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) + DSI_ERR("[%s] failed to disable DSI link clocks, rc=%d\n", + display->name, rc); + + pm_runtime_put_sync(display->drm_dev->dev); + + display->is_cont_splash_enabled = false; + /* Update splash status for clock manager */ + dsi_display_clk_mngr_update_splash_status(display->clk_mngr, + display->is_cont_splash_enabled); + + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT, display->is_cont_splash_enabled); + return rc; +} + +static int dsi_display_force_update_dsi_clk(struct dsi_display *display) +{ + int rc = 0; + + rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle); + + if (!rc) { + DSI_INFO("dsi bit clk has been configured to %d\n", + display->cached_clk_rate); + + atomic_set(&display->clkrate_change_pending, 0); + } else { + DSI_ERR("Failed to configure dsi bit clock '%d'. rc = %d\n", + display->cached_clk_rate, rc); + } + + return rc; +} + +static int dsi_display_validate_split_link(struct dsi_display *display) +{ + int i, rc = 0; + struct dsi_display_ctrl *ctrl; + struct dsi_host_common_cfg *host = &display->panel->host_config; + + if (!host->split_link.split_link_enabled) + return 0; + + if (display->panel->panel_mode == DSI_OP_CMD_MODE) { + DSI_ERR("[%s] split link is not supported in command mode\n", + display->name); + rc = -ENOTSUPP; + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl->split_link_supported) { + DSI_ERR("[%s] split link is not supported by hw\n", + display->name); + rc = -ENOTSUPP; + goto error; + } + + set_bit(DSI_PHY_SPLIT_LINK, ctrl->phy->hw.feature_map); + } + + DSI_DEBUG("Split link is enabled\n"); + return 0; + +error: + host->split_link.split_link_enabled = false; + return rc; +} + +/** + * dsi_display_bind - bind dsi device with controlling device + * @dev: Pointer to base of platform device + * @master: Pointer to container of drm device + * @data: Pointer to private data + * Returns: Zero on success + */ +static int dsi_display_bind(struct device *dev, + struct device *master, + void *data) +{ + struct dsi_display_ctrl *display_ctrl; + struct drm_device *drm; + struct dsi_display *display; + struct dsi_clk_info info; + struct clk_ctrl_cb clk_cb; + void *handle = NULL; + struct platform_device *pdev = to_platform_device(dev); + char *client1 = "dsi_clk_client"; + char *client2 = "mdp_event_client"; + int i, rc = 0; + + if (!dev || !pdev || !master) { + DSI_ERR("invalid param(s), dev %pK, pdev %pK, master %pK\n", + dev, pdev, master); + return -EINVAL; + } + + drm = dev_get_drvdata(master); + display = platform_get_drvdata(pdev); + if (!drm || !display) { + DSI_ERR("invalid param(s), drm %pK, display %pK\n", + drm, display); + return -EINVAL; + } + if (!display->panel_node && !display->fw) + return 0; + + if (!display->fw) + display->name = display->panel_node->name; + + /* defer bind if ext bridge driver is not loaded */ + if (display->panel && display->panel->host_config.ext_bridge_mode) { + for (i = 0; i < display->ext_bridge_cnt; i++) { + if (!of_drm_find_bridge( + display->ext_bridge[i].node_of)) { + DSI_DEBUG("defer for bridge[%d] %s\n", i, + display->ext_bridge[i].node_of->full_name); + return -EPROBE_DEFER; + } + } + } + + mutex_lock(&display->display_lock); + + rc = dsi_display_validate_split_link(display); + if (rc) { + DSI_ERR("[%s] split link validation failed, rc=%d\n", + display->name, rc); + goto error; + } + + rc = dsi_display_debugfs_init(display); + if (rc) { + DSI_ERR("[%s] debugfs init failed, rc=%d\n", display->name, rc); + goto error; + } + + atomic_set(&display->clkrate_change_pending, 0); + display->cached_clk_rate = 0; + + memset(&info, 0x0, sizeof(info)); + + display_for_each_ctrl(i, display) { + display_ctrl = &display->ctrl[i]; + rc = dsi_ctrl_drv_init(display_ctrl->ctrl, display->root); + if (rc) { + DSI_ERR("[%s] failed to initialize ctrl[%d], rc=%d\n", + display->name, i, rc); + goto error_ctrl_deinit; + } + display_ctrl->ctrl->horiz_index = i; + + rc = dsi_phy_drv_init(display_ctrl->phy); + if (rc) { + DSI_ERR("[%s] Failed to initialize phy[%d], rc=%d\n", + display->name, i, rc); + (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl); + goto error_ctrl_deinit; + } + + display_ctrl->ctrl->dma_cmd_workq = display->dma_cmd_workq; + memcpy(&info.c_clks[i], + (&display_ctrl->ctrl->clk_info.core_clks), + sizeof(struct dsi_core_clk_info)); + memcpy(&info.l_hs_clks[i], + (&display_ctrl->ctrl->clk_info.hs_link_clks), + sizeof(struct dsi_link_hs_clk_info)); + memcpy(&info.l_lp_clks[i], + (&display_ctrl->ctrl->clk_info.lp_link_clks), + sizeof(struct dsi_link_lp_clk_info)); + + info.c_clks[i].drm = drm; + info.bus_handle[i] = + display_ctrl->ctrl->axi_bus_info.bus_handle; + info.ctrl_index[i] = display_ctrl->ctrl->cell_index; + } + + info.pre_clkoff_cb = dsi_pre_clkoff_cb; + info.pre_clkon_cb = dsi_pre_clkon_cb; + info.post_clkoff_cb = dsi_post_clkoff_cb; + info.post_clkon_cb = dsi_post_clkon_cb; + info.priv_data = display; + info.master_ndx = display->clk_master_idx; + info.dsi_ctrl_count = display->ctrl_count; + snprintf(info.name, MAX_STRING_LEN, + "DSI_MNGR-%s", display->name); + + display->clk_mngr = dsi_display_clk_mngr_register(&info); + if (IS_ERR_OR_NULL(display->clk_mngr)) { + rc = PTR_ERR(display->clk_mngr); + display->clk_mngr = NULL; + DSI_ERR("dsi clock registration failed, rc = %d\n", rc); + goto error_ctrl_deinit; + } + + handle = dsi_register_clk_handle(display->clk_mngr, client1); + if (IS_ERR_OR_NULL(handle)) { + rc = PTR_ERR(handle); + DSI_ERR("failed to register %s client, rc = %d\n", + client1, rc); + goto error_clk_deinit; + } else { + display->dsi_clk_handle = handle; + } + + handle = dsi_register_clk_handle(display->clk_mngr, client2); + if (IS_ERR_OR_NULL(handle)) { + rc = PTR_ERR(handle); + DSI_ERR("failed to register %s client, rc = %d\n", + client2, rc); + goto error_clk_client_deinit; + } else { + display->mdp_clk_handle = handle; + } + + clk_cb.priv = display; + clk_cb.dsi_clk_cb = dsi_display_clk_ctrl_cb; + + display_for_each_ctrl(i, display) { + display_ctrl = &display->ctrl[i]; + + rc = dsi_ctrl_clk_cb_register(display_ctrl->ctrl, &clk_cb); + if (rc) { + DSI_ERR("[%s] failed to register ctrl clk_cb[%d], rc=%d\n", + display->name, i, rc); + goto error_ctrl_deinit; + } + + rc = dsi_phy_clk_cb_register(display_ctrl->phy, &clk_cb); + if (rc) { + DSI_ERR("[%s] failed to register phy clk_cb[%d], rc=%d\n", + display->name, i, rc); + goto error_ctrl_deinit; + } + } + + dsi_display_update_byte_intf_div(display); + rc = dsi_display_mipi_host_init(display); + if (rc) { + DSI_ERR("[%s] failed to initialize mipi host, rc=%d\n", + display->name, rc); + goto error_ctrl_deinit; + } + + rc = dsi_panel_drv_init(display->panel, &display->host); + if (rc) { + if (rc != -EPROBE_DEFER) + DSI_ERR("[%s] failed to initialize panel driver, rc=%d\n", + display->name, rc); + goto error_host_deinit; + } + + DSI_INFO("Successfully bind display panel '%s'\n", display->name); + display->drm_dev = drm; + + display_for_each_ctrl(i, display) { + display_ctrl = &display->ctrl[i]; + + if (!display_ctrl->phy || !display_ctrl->ctrl) + continue; + + display_ctrl->ctrl->drm_dev = drm; + + rc = dsi_phy_set_clk_freq(display_ctrl->phy, + &display_ctrl->ctrl->clk_freq); + if (rc) { + DSI_ERR("[%s] failed to set phy clk freq, rc=%d\n", + display->name, rc); + goto error; + } + } + + /* register te irq handler */ + dsi_display_register_te_irq(display); + + goto error; + +error_host_deinit: + (void)dsi_display_mipi_host_deinit(display); +error_clk_client_deinit: + (void)dsi_deregister_clk_handle(display->dsi_clk_handle); +error_clk_deinit: + (void)dsi_display_clk_mngr_deregister(display->clk_mngr); +error_ctrl_deinit: + for (i = i - 1; i >= 0; i--) { + display_ctrl = &display->ctrl[i]; + (void)dsi_phy_drv_deinit(display_ctrl->phy); + (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl); + } + (void)dsi_display_debugfs_deinit(display); +error: + mutex_unlock(&display->display_lock); + return rc; +} + +/** + * dsi_display_unbind - unbind dsi from controlling device + * @dev: Pointer to base of platform device + * @master: Pointer to container of drm device + * @data: Pointer to private data + */ +static void dsi_display_unbind(struct device *dev, + struct device *master, void *data) +{ + struct dsi_display_ctrl *display_ctrl; + struct dsi_display *display; + struct platform_device *pdev = to_platform_device(dev); + int i, rc = 0; + + if (!dev || !pdev) { + DSI_ERR("invalid param(s)\n"); + return; + } + + display = platform_get_drvdata(pdev); + if (!display) { + DSI_ERR("invalid display\n"); + return; + } + + mutex_lock(&display->display_lock); + + rc = dsi_panel_drv_deinit(display->panel); + if (rc) + DSI_ERR("[%s] failed to deinit panel driver, rc=%d\n", + display->name, rc); + + rc = dsi_display_mipi_host_deinit(display); + if (rc) + DSI_ERR("[%s] failed to deinit mipi hosts, rc=%d\n", + display->name, + rc); + + display_for_each_ctrl(i, display) { + display_ctrl = &display->ctrl[i]; + + rc = dsi_phy_drv_deinit(display_ctrl->phy); + if (rc) + DSI_ERR("[%s] failed to deinit phy%d driver, rc=%d\n", + display->name, i, rc); + + display->ctrl->ctrl->dma_cmd_workq = NULL; + rc = dsi_ctrl_drv_deinit(display_ctrl->ctrl); + if (rc) + DSI_ERR("[%s] failed to deinit ctrl%d driver, rc=%d\n", + display->name, i, rc); + } + + atomic_set(&display->clkrate_change_pending, 0); + (void)dsi_display_debugfs_deinit(display); + + mutex_unlock(&display->display_lock); +} + +static const struct component_ops dsi_display_comp_ops = { + .bind = dsi_display_bind, + .unbind = dsi_display_unbind, +}; + +static struct platform_driver dsi_display_driver = { + .probe = dsi_display_dev_probe, + .remove = dsi_display_dev_remove, + .driver = { + .name = "msm-dsi-display", + .of_match_table = dsi_display_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int dsi_display_init(struct dsi_display *display) +{ + int rc = 0; + struct platform_device *pdev = display->pdev; + + mutex_init(&display->display_lock); + + rc = _dsi_display_dev_init(display); + if (rc) { + DSI_ERR("device init failed, rc=%d\n", rc); + goto end; + } + + rc = component_add(&pdev->dev, &dsi_display_comp_ops); + if (rc) + DSI_ERR("component add failed, rc=%d\n", rc); + + DSI_DEBUG("component add success: %s\n", display->name); +end: + return rc; +} + +static void dsi_display_firmware_display(const struct firmware *fw, + void *context) +{ + struct dsi_display *display = context; + + if (fw) { + DSI_INFO("reading data from firmware, size=%zd\n", + fw->size); + + display->fw = fw; + + if (!strcmp(display->display_type, "primary")) + display->name = "dsi_firmware_display"; + + else if (!strcmp(display->display_type, "secondary")) + display->name = "dsi_firmware_display_secondary"; + + } else { + DSI_INFO("no firmware available, fallback to device node\n"); + } + + if (dsi_display_init(display)) + return; + + DSI_DEBUG("success\n"); +} + +int dsi_display_dev_probe(struct platform_device *pdev) +{ + struct dsi_display *display = NULL; + struct device_node *node = NULL, *panel_node = NULL, *mdp_node = NULL; + int rc = 0, index = DSI_PRIMARY; + bool firm_req = false; + struct dsi_display_boot_param *boot_disp; + + if (!pdev || !pdev->dev.of_node) { + DSI_ERR("pdev not found\n"); + rc = -ENODEV; + goto end; + } + + display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL); + if (!display) { + rc = -ENOMEM; + goto end; + } + + display->dma_cmd_workq = create_singlethread_workqueue( + "dsi_dma_cmd_workq"); + if (!display->dma_cmd_workq) { + DSI_ERR("failed to create work queue\n"); + rc = -EINVAL; + goto end; + } + + display->display_type = of_get_property(pdev->dev.of_node, + "label", NULL); + if (!display->display_type) + display->display_type = "primary"; + + if (!strcmp(display->display_type, "secondary")) + index = DSI_SECONDARY; + + boot_disp = &boot_displays[index]; + node = pdev->dev.of_node; + if (boot_disp->boot_disp_en) { + mdp_node = of_parse_phandle(node, "qcom,mdp", 0); + if (!mdp_node) { + DSI_ERR("mdp_node not found\n"); + rc = -ENODEV; + goto end; + } + + /* The panel name should be same as UEFI name index */ + panel_node = of_find_node_by_name(mdp_node, boot_disp->name); + if (!panel_node) + DSI_WARN("panel_node %s not found\n", boot_disp->name); + } else { + panel_node = of_parse_phandle(node, + "qcom,dsi-default-panel", 0); + if (!panel_node) + DSI_WARN("default panel not found\n"); + } + + boot_disp->node = pdev->dev.of_node; + boot_disp->disp = display; + + display->panel_node = panel_node; + display->pdev = pdev; + display->boot_disp = boot_disp; + + dsi_display_parse_cmdline_topology(display, index); + + platform_set_drvdata(pdev, display); + + /* initialize display in firmware callback */ + if (!boot_disp->boot_disp_en && IS_ENABLED(CONFIG_DSI_PARSER)) { + if (!strcmp(display->display_type, "primary")) + firm_req = !request_firmware_nowait( + THIS_MODULE, 1, "dsi_prop", + &pdev->dev, GFP_KERNEL, display, + dsi_display_firmware_display); + + else if (!strcmp(display->display_type, "secondary")) + firm_req = !request_firmware_nowait( + THIS_MODULE, 1, "dsi_prop_sec", + &pdev->dev, GFP_KERNEL, display, + dsi_display_firmware_display); + } + + if (!firm_req) { + rc = dsi_display_init(display); + if (rc) + goto end; + } + + return 0; +end: + if (display) + devm_kfree(&pdev->dev, display); + + return rc; +} + +int dsi_display_dev_remove(struct platform_device *pdev) +{ + int rc = 0i, i = 0; + struct dsi_display *display; + struct dsi_display_ctrl *ctrl; + + if (!pdev) { + DSI_ERR("Invalid device\n"); + return -EINVAL; + } + + display = platform_get_drvdata(pdev); + + /* decrement ref count */ + of_node_put(display->panel_node); + + if (display->dma_cmd_workq) { + flush_workqueue(display->dma_cmd_workq); + destroy_workqueue(display->dma_cmd_workq); + display->dma_cmd_workq = NULL; + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + ctrl->ctrl->dma_cmd_workq = NULL; + } + } + + (void)_dsi_display_dev_deinit(display); + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, display); + return rc; +} + +int dsi_display_get_num_of_displays(void) +{ + int i, count = 0; + + for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) { + struct dsi_display *display = boot_displays[i].disp; + + if ((display && display->panel_node) || + (display && display->fw)) + count++; + } + + return count; +} + +int dsi_display_get_active_displays(void **display_array, u32 max_display_count) +{ + int index = 0, count = 0; + + if (!display_array || !max_display_count) { + DSI_ERR("invalid params\n"); + return 0; + } + + for (index = 0; index < MAX_DSI_ACTIVE_DISPLAY; index++) { + struct dsi_display *display = boot_displays[index].disp; + + if ((display && display->panel_node) || + (display && display->fw)) + display_array[count++] = display; + } + + return count; +} + +int dsi_display_drm_bridge_init(struct dsi_display *display, + struct drm_encoder *enc) +{ + int rc = 0; + struct dsi_bridge *bridge; + struct msm_drm_private *priv = NULL; + + if (!display || !display->drm_dev || !enc) { + DSI_ERR("invalid param(s)\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + priv = display->drm_dev->dev_private; + + if (!priv) { + DSI_ERR("Private data is not present\n"); + rc = -EINVAL; + goto error; + } + + if (display->bridge) { + DSI_ERR("display is already initialize\n"); + goto error; + } + + bridge = dsi_drm_bridge_init(display, display->drm_dev, enc); + if (IS_ERR_OR_NULL(bridge)) { + rc = PTR_ERR(bridge); + DSI_ERR("[%s] brige init failed, %d\n", display->name, rc); + goto error; + } + + display->bridge = bridge; + priv->bridges[priv->num_bridges++] = &bridge->base; + +error: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_drm_bridge_deinit(struct dsi_display *display) +{ + int rc = 0; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + dsi_drm_bridge_cleanup(display->bridge); + display->bridge = NULL; + + mutex_unlock(&display->display_lock); + return rc; +} + +/* Hook functions to call external connector, pointer validation is + * done in dsi_display_drm_ext_bridge_init. + */ +static enum drm_connector_status dsi_display_drm_ext_detect( + struct drm_connector *connector, + bool force, + void *disp) +{ + struct dsi_display *display = disp; + + return display->ext_conn->funcs->detect(display->ext_conn, force); +} + +static int dsi_display_drm_ext_get_modes( + struct drm_connector *connector, void *disp, + const struct msm_resource_caps_info *avail_res) +{ + struct dsi_display *display = disp; + struct drm_display_mode *pmode, *pt; + int count; + + /* if there are modes defined in panel, ignore external modes */ + if (display->panel->num_timing_nodes) + return dsi_connector_get_modes(connector, disp, avail_res); + + count = display->ext_conn->helper_private->get_modes( + display->ext_conn); + + list_for_each_entry_safe(pmode, pt, + &display->ext_conn->probed_modes, head) { + list_move_tail(&pmode->head, &connector->probed_modes); + } + + connector->display_info = display->ext_conn->display_info; + + return count; +} + +static enum drm_mode_status dsi_display_drm_ext_mode_valid( + struct drm_connector *connector, + struct drm_display_mode *mode, + void *disp, const struct msm_resource_caps_info *avail_res) +{ + struct dsi_display *display = disp; + enum drm_mode_status status; + + /* always do internal mode_valid check */ + status = dsi_conn_mode_valid(connector, mode, disp, avail_res); + if (status != MODE_OK) + return status; + + return display->ext_conn->helper_private->mode_valid( + display->ext_conn, mode); +} + +static int dsi_display_drm_ext_atomic_check(struct drm_connector *connector, + void *disp, + struct drm_connector_state *c_state) +{ + struct dsi_display *display = disp; + + return display->ext_conn->helper_private->atomic_check( + display->ext_conn, c_state); +} + +static int dsi_display_ext_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *disp) +{ + struct dsi_display *display; + int i; + + if (!info || !disp) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + display = disp; + if (!display->panel) { + DSI_ERR("invalid display panel\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + memset(info, 0, sizeof(struct msm_display_info)); + + info->intf_type = DRM_MODE_CONNECTOR_DSI; + info->num_of_h_tiles = display->ctrl_count; + for (i = 0; i < info->num_of_h_tiles; i++) + info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index; + + info->is_connected = connector->status != connector_status_disconnected; + + if (!strcmp(display->display_type, "primary")) + info->display_type = SDE_CONNECTOR_PRIMARY; + else if (!strcmp(display->display_type, "secondary")) + info->display_type = SDE_CONNECTOR_SECONDARY; + + info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE | + MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG); + info->curr_panel_mode = MSM_DISPLAY_VIDEO_MODE; + + mutex_unlock(&display->display_lock); + return 0; +} + +static int dsi_display_ext_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res) +{ + struct msm_display_topology *topology; + + if (!drm_mode || !mode_info || + !avail_res || !avail_res->max_mixer_width) + return -EINVAL; + + memset(mode_info, 0, sizeof(*mode_info)); + mode_info->frame_rate = drm_mode->vrefresh; + mode_info->vtotal = drm_mode->vtotal; + + topology = &mode_info->topology; + topology->num_lm = (avail_res->max_mixer_width + <= drm_mode->hdisplay) ? 2 : 1; + topology->num_enc = 0; + topology->num_intf = topology->num_lm; + + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; + + return 0; +} + +static struct dsi_display_ext_bridge *dsi_display_ext_get_bridge( + struct drm_bridge *bridge) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct list_head *connector_list; + struct drm_connector *conn_iter; + struct sde_connector *sde_conn; + struct dsi_display *display; + int i; + + if (!bridge || !bridge->encoder) { + SDE_ERROR("invalid argument\n"); + return NULL; + } + + priv = bridge->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + connector_list = &sde_kms->dev->mode_config.connector_list; + + list_for_each_entry(conn_iter, connector_list, head) { + sde_conn = to_sde_connector(conn_iter); + if (sde_conn->encoder == bridge->encoder) { + display = sde_conn->display; + display_for_each_ctrl(i, display) { + if (display->ext_bridge[i].bridge == bridge) + return &display->ext_bridge[i]; + } + } + } + + return NULL; +} + +static void dsi_display_drm_ext_adjust_timing( + const struct dsi_display *display, + struct drm_display_mode *mode) +{ + mode->hdisplay /= display->ctrl_count; + mode->hsync_start /= display->ctrl_count; + mode->hsync_end /= display->ctrl_count; + mode->htotal /= display->ctrl_count; + mode->hskew /= display->ctrl_count; + mode->clock /= display->ctrl_count; +} + +static enum drm_mode_status dsi_display_drm_ext_bridge_mode_valid( + struct drm_bridge *bridge, + const struct drm_display_mode *mode) +{ + struct dsi_display_ext_bridge *ext_bridge; + struct drm_display_mode tmp; + + ext_bridge = dsi_display_ext_get_bridge(bridge); + if (!ext_bridge) + return MODE_ERROR; + + tmp = *mode; + dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); + return ext_bridge->orig_funcs->mode_valid(bridge, &tmp); +} + +static bool dsi_display_drm_ext_bridge_mode_fixup( + struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dsi_display_ext_bridge *ext_bridge; + struct drm_display_mode tmp; + + ext_bridge = dsi_display_ext_get_bridge(bridge); + if (!ext_bridge) + return false; + + tmp = *mode; + dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); + return ext_bridge->orig_funcs->mode_fixup(bridge, &tmp, &tmp); +} + +static void dsi_display_drm_ext_bridge_mode_set( + struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dsi_display_ext_bridge *ext_bridge; + struct drm_display_mode tmp; + + ext_bridge = dsi_display_ext_get_bridge(bridge); + if (!ext_bridge) + return; + + tmp = *mode; + dsi_display_drm_ext_adjust_timing(ext_bridge->display, &tmp); + ext_bridge->orig_funcs->mode_set(bridge, &tmp, &tmp); +} + +static int dsi_host_ext_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi) +{ + struct dsi_display *display = to_dsi_display(host); + struct dsi_panel *panel; + + if (!host || !dsi || !display->panel) { + DSI_ERR("Invalid param\n"); + return -EINVAL; + } + + DSI_DEBUG("DSI[%s]: channel=%d, lanes=%d, format=%d, mode_flags=%lx\n", + dsi->name, dsi->channel, dsi->lanes, + dsi->format, dsi->mode_flags); + + panel = display->panel; + panel->host_config.data_lanes = 0; + if (dsi->lanes > 0) + panel->host_config.data_lanes |= DSI_DATA_LANE_0; + if (dsi->lanes > 1) + panel->host_config.data_lanes |= DSI_DATA_LANE_1; + if (dsi->lanes > 2) + panel->host_config.data_lanes |= DSI_DATA_LANE_2; + if (dsi->lanes > 3) + panel->host_config.data_lanes |= DSI_DATA_LANE_3; + + switch (dsi->format) { + case MIPI_DSI_FMT_RGB888: + panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB888; + break; + case MIPI_DSI_FMT_RGB666: + panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666_LOOSE; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB666; + break; + case MIPI_DSI_FMT_RGB565: + default: + panel->host_config.dst_format = DSI_PIXEL_FORMAT_RGB565; + break; + } + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { + panel->panel_mode = DSI_OP_VIDEO_MODE; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + panel->video_config.traffic_mode = + DSI_VIDEO_TRAFFIC_BURST_MODE; + else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + panel->video_config.traffic_mode = + DSI_VIDEO_TRAFFIC_SYNC_PULSES; + else + panel->video_config.traffic_mode = + DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS; + + panel->video_config.hsa_lp11_en = + dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA; + panel->video_config.hbp_lp11_en = + dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP; + panel->video_config.hfp_lp11_en = + dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP; + panel->video_config.pulse_mode_hsa_he = + dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE; + panel->video_config.bllp_lp11_en = + dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BLLP; + panel->video_config.eof_bllp_lp11_en = + dsi->mode_flags & MIPI_DSI_MODE_VIDEO_EOF_BLLP; + } else { + panel->panel_mode = DSI_OP_CMD_MODE; + DSI_ERR("command mode not supported by ext bridge\n"); + return -ENOTSUPP; + } + + panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN; + + return 0; +} + +static struct mipi_dsi_host_ops dsi_host_ext_ops = { + .attach = dsi_host_ext_attach, + .detach = dsi_host_detach, + .transfer = dsi_host_transfer, +}; + +struct drm_panel *dsi_display_get_drm_panel(struct dsi_display * display) +{ + if (!display || !display->panel) { + pr_err("invalid param(s)\n"); + return NULL; + } + + return &display->panel->drm_panel; +} + +int dsi_display_drm_ext_bridge_init(struct dsi_display *display, + struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *drm; + struct drm_bridge *bridge; + struct drm_bridge *ext_bridge; + struct drm_connector *ext_conn; + struct sde_connector *sde_conn; + struct drm_bridge *prev_bridge; + int rc = 0, i; + + if (!display || !encoder || !connector) + return -EINVAL; + + drm = encoder->dev; + bridge = encoder->bridge; + sde_conn = to_sde_connector(connector); + prev_bridge = bridge; + + if (display->panel && !display->panel->host_config.ext_bridge_mode) + return 0; + + for (i = 0; i < display->ext_bridge_cnt; i++) { + struct dsi_display_ext_bridge *ext_bridge_info = + &display->ext_bridge[i]; + + /* return if ext bridge is already initialized */ + if (ext_bridge_info->bridge) + return 0; + + ext_bridge = of_drm_find_bridge(ext_bridge_info->node_of); + if (IS_ERR_OR_NULL(ext_bridge)) { + rc = PTR_ERR(ext_bridge); + DSI_ERR("failed to find ext bridge\n"); + goto error; + } + + /* override functions for mode adjustment */ + if (display->ext_bridge_cnt > 1) { + ext_bridge_info->bridge_funcs = *ext_bridge->funcs; + if (ext_bridge->funcs->mode_fixup) + ext_bridge_info->bridge_funcs.mode_fixup = + dsi_display_drm_ext_bridge_mode_fixup; + if (ext_bridge->funcs->mode_valid) + ext_bridge_info->bridge_funcs.mode_valid = + dsi_display_drm_ext_bridge_mode_valid; + if (ext_bridge->funcs->mode_set) + ext_bridge_info->bridge_funcs.mode_set = + dsi_display_drm_ext_bridge_mode_set; + ext_bridge_info->orig_funcs = ext_bridge->funcs; + ext_bridge->funcs = &ext_bridge_info->bridge_funcs; + } + + rc = drm_bridge_attach(encoder, ext_bridge, prev_bridge); + if (rc) { + DSI_ERR("[%s] ext brige attach failed, %d\n", + display->name, rc); + goto error; + } + + ext_bridge_info->display = display; + ext_bridge_info->bridge = ext_bridge; + prev_bridge = ext_bridge; + + /* ext bridge will init its own connector during attach, + * we need to extract it out of the connector list + */ + spin_lock_irq(&drm->mode_config.connector_list_lock); + ext_conn = list_last_entry(&drm->mode_config.connector_list, + struct drm_connector, head); + if (ext_conn && ext_conn != connector && + ext_conn->encoder_ids[0] == bridge->encoder->base.id) { + list_del_init(&ext_conn->head); + display->ext_conn = ext_conn; + } + spin_unlock_irq(&drm->mode_config.connector_list_lock); + + /* if there is no valid external connector created, or in split + * mode, default setting is used from panel defined in DT file. + */ + if (!display->ext_conn || + !display->ext_conn->funcs || + !display->ext_conn->helper_private || + display->ext_bridge_cnt > 1) { + display->ext_conn = NULL; + continue; + } + + /* otherwise, hook up the functions to use external connector */ + if (display->ext_conn->funcs->detect) + sde_conn->ops.detect = dsi_display_drm_ext_detect; + + if (display->ext_conn->helper_private->get_modes) + sde_conn->ops.get_modes = + dsi_display_drm_ext_get_modes; + + if (display->ext_conn->helper_private->mode_valid) + sde_conn->ops.mode_valid = + dsi_display_drm_ext_mode_valid; + + if (display->ext_conn->helper_private->atomic_check) + sde_conn->ops.atomic_check = + dsi_display_drm_ext_atomic_check; + + sde_conn->ops.get_info = + dsi_display_ext_get_info; + sde_conn->ops.get_mode_info = + dsi_display_ext_get_mode_info; + + /* add support to attach/detach */ + display->host.ops = &dsi_host_ext_ops; + } + + return 0; +error: + return rc; +} + +int dsi_display_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *disp) +{ + struct dsi_display *display; + struct dsi_panel_phy_props phy_props; + struct dsi_host_common_cfg *host; + int i, rc; + + if (!info || !disp) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + display = disp; + if (!display->panel) { + DSI_ERR("invalid display panel\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + rc = dsi_panel_get_phy_props(display->panel, &phy_props); + if (rc) { + DSI_ERR("[%s] failed to get panel phy props, rc=%d\n", + display->name, rc); + goto error; + } + + memset(info, 0, sizeof(struct msm_display_info)); + info->intf_type = DRM_MODE_CONNECTOR_DSI; + info->num_of_h_tiles = display->ctrl_count; + for (i = 0; i < info->num_of_h_tiles; i++) + info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index; + + info->is_connected = true; + + if (!strcmp(display->display_type, "primary")) + info->display_type = SDE_CONNECTOR_PRIMARY; + else if (!strcmp(display->display_type, "secondary")) + info->display_type = SDE_CONNECTOR_SECONDARY; + + info->width_mm = phy_props.panel_width_mm; + info->height_mm = phy_props.panel_height_mm; + info->max_width = 1920; + info->max_height = 1080; + info->qsync_min_fps = + display->panel->qsync_min_fps; + + switch (display->panel->panel_mode) { + case DSI_OP_VIDEO_MODE: + info->curr_panel_mode = MSM_DISPLAY_VIDEO_MODE; + info->capabilities |= MSM_DISPLAY_CAP_VID_MODE; + if (display->panel->panel_mode_switch_enabled) + info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE; + break; + case DSI_OP_CMD_MODE: + info->curr_panel_mode = MSM_DISPLAY_CMD_MODE; + info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE; + if (display->panel->panel_mode_switch_enabled) + info->capabilities |= MSM_DISPLAY_CAP_VID_MODE; + info->is_te_using_watchdog_timer = + display->panel->te_using_watchdog_timer | + display->sw_te_using_wd; + break; + default: + DSI_ERR("unknwown dsi panel mode %d\n", + display->panel->panel_mode); + break; + } + + if (display->panel->esd_config.esd_enabled) + info->capabilities |= MSM_DISPLAY_ESD_ENABLED; + + info->te_source = display->te_source; + + host = &display->panel->host_config; + if (host->split_link.split_link_enabled) + info->capabilities |= MSM_DISPLAY_SPLIT_LINK; +error: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_get_mode_count(struct dsi_display *display, + u32 *count) +{ + if (!display || !display->panel) { + DSI_ERR("invalid display:%d panel:%d\n", display != NULL, + display ? display->panel != NULL : 0); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + *count = display->panel->num_display_modes; + mutex_unlock(&display->display_lock); + + return 0; +} + +void dsi_display_adjust_mode_timing(struct dsi_display *display, + struct dsi_display_mode *dsi_mode, + int lanes, int bpp) +{ + u64 new_htotal, new_vtotal, htotal, vtotal, old_htotal, div; + struct dsi_dyn_clk_caps *dyn_clk_caps; + u32 bits_per_symbol = 16, num_of_symbols = 7; /* For Cphy */ + + dyn_clk_caps = &(display->panel->dyn_clk_caps); + + /* Constant FPS is not supported on command mode */ + if (dsi_mode->panel_mode == DSI_OP_CMD_MODE) + return; + + if (!dyn_clk_caps->maintain_const_fps) + return; + /* + * When there is a dynamic clock switch, there is small change + * in FPS. To compensate for this difference in FPS, hfp or vfp + * is adjusted. It has been assumed that the refined porch values + * are supported by the panel. This logic can be enhanced further + * in future by taking min/max porches supported by the panel. + */ + switch (dyn_clk_caps->type) { + case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: + vtotal = DSI_V_TOTAL(&dsi_mode->timing); + old_htotal = DSI_H_TOTAL_DSC(&dsi_mode->timing); + do_div(old_htotal, display->ctrl_count); + new_htotal = dsi_mode->timing.clk_rate_hz * lanes; + div = bpp * vtotal * dsi_mode->timing.refresh_rate; + if (dsi_display_is_type_cphy(display)) { + new_htotal = new_htotal * bits_per_symbol; + div = div * num_of_symbols; + } + do_div(new_htotal, div); + if (old_htotal > new_htotal) + dsi_mode->timing.h_front_porch -= + ((old_htotal - new_htotal) * display->ctrl_count); + else + dsi_mode->timing.h_front_porch += + ((new_htotal - old_htotal) * display->ctrl_count); + break; + + case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: + htotal = DSI_H_TOTAL_DSC(&dsi_mode->timing); + do_div(htotal, display->ctrl_count); + new_vtotal = dsi_mode->timing.clk_rate_hz * lanes; + div = bpp * htotal * dsi_mode->timing.refresh_rate; + if (dsi_display_is_type_cphy(display)) { + new_vtotal = new_vtotal * bits_per_symbol; + div = div * num_of_symbols; + } + do_div(new_vtotal, div); + dsi_mode->timing.v_front_porch = new_vtotal - + dsi_mode->timing.v_back_porch - + dsi_mode->timing.v_sync_width - + dsi_mode->timing.v_active; + break; + + default: + break; + } +} + +static void _dsi_display_populate_bit_clks(struct dsi_display *display, + int start, int end, u32 *mode_idx) +{ + struct dsi_dyn_clk_caps *dyn_clk_caps; + struct dsi_display_mode *src, *dst; + struct dsi_host_common_cfg *cfg; + int i, j, total_modes, bpp, lanes = 0; + + if (!display || !mode_idx) + return; + + dyn_clk_caps = &(display->panel->dyn_clk_caps); + if (!dyn_clk_caps->dyn_clk_support) + return; + + cfg = &(display->panel->host_config); + bpp = dsi_pixel_format_to_bpp(cfg->dst_format); + + if (cfg->data_lanes & DSI_DATA_LANE_0) + lanes++; + if (cfg->data_lanes & DSI_DATA_LANE_1) + lanes++; + if (cfg->data_lanes & DSI_DATA_LANE_2) + lanes++; + if (cfg->data_lanes & DSI_DATA_LANE_3) + lanes++; + + total_modes = display->panel->num_display_modes; + + for (i = start; i < end; i++) { + src = &display->modes[i]; + if (!src) + return; + /* + * TODO: currently setting the first bit rate in + * the list as preferred rate. But ideally should + * be based on user or device tree preferrence. + */ + src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0]; + + dsi_display_adjust_mode_timing(display, src, lanes, bpp); + + src->pixel_clk_khz = + div_u64(src->timing.clk_rate_hz * lanes, bpp); + src->pixel_clk_khz /= 1000; + src->pixel_clk_khz *= display->ctrl_count; + } + + for (i = 1; i < dyn_clk_caps->bit_clk_list_len; i++) { + if (*mode_idx >= total_modes) + return; + for (j = start; j < end; j++) { + src = &display->modes[j]; + dst = &display->modes[*mode_idx]; + + if (!src || !dst) { + DSI_ERR("invalid mode index\n"); + return; + } + memcpy(dst, src, sizeof(struct dsi_display_mode)); + dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i]; + + dsi_display_adjust_mode_timing(display, dst, lanes, + bpp); + + dst->pixel_clk_khz = + div_u64(dst->timing.clk_rate_hz * lanes, bpp); + dst->pixel_clk_khz /= 1000; + dst->pixel_clk_khz *= display->ctrl_count; + (*mode_idx)++; + } + } +} + +void dsi_display_put_mode(struct dsi_display *display, + struct dsi_display_mode *mode) +{ + dsi_panel_put_mode(mode); +} + +int dsi_display_get_modes(struct dsi_display *display, + struct dsi_display_mode **out_modes) +{ + struct dsi_dfps_capabilities dfps_caps; + struct dsi_display_ctrl *ctrl; + struct dsi_host_common_cfg *host = &display->panel->host_config; + bool is_split_link, is_cmd_mode; + u32 num_dfps_rates, timing_mode_count, display_mode_count; + u32 sublinks_count, mode_idx, array_idx = 0; + struct dsi_dyn_clk_caps *dyn_clk_caps; + int i, start, end, rc = -EINVAL; + + if (!display || !out_modes) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + *out_modes = NULL; + ctrl = &display->ctrl[0]; + + mutex_lock(&display->display_lock); + + if (display->modes) + goto exit; + + display_mode_count = display->panel->num_display_modes; + + display->modes = kcalloc(display_mode_count, sizeof(*display->modes), + GFP_KERNEL); + if (!display->modes) { + rc = -ENOMEM; + goto error; + } + + rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + if (rc) { + DSI_ERR("[%s] failed to get dfps caps from panel\n", + display->name); + goto error; + } + + dyn_clk_caps = &(display->panel->dyn_clk_caps); + + timing_mode_count = display->panel->num_timing_nodes; + + /* Validate command line timing */ + if ((display->cmdline_timing != NO_OVERRIDE) && + (display->cmdline_timing >= timing_mode_count)) + display->cmdline_timing = NO_OVERRIDE; + + for (mode_idx = 0; mode_idx < timing_mode_count; mode_idx++) { + struct dsi_display_mode display_mode; + int topology_override = NO_OVERRIDE; + bool is_preferred = false; + u32 frame_threshold_us = ctrl->ctrl->frame_threshold_time_us; + + if (display->cmdline_timing == mode_idx) { + topology_override = display->cmdline_topology; + is_preferred = true; + } + + memset(&display_mode, 0, sizeof(display_mode)); + + rc = dsi_panel_get_mode(display->panel, mode_idx, + &display_mode, + topology_override); + if (rc) { + DSI_ERR("[%s] failed to get mode idx %d from panel\n", + display->name, mode_idx); + goto error; + } + + is_cmd_mode = (display_mode.panel_mode == DSI_OP_CMD_MODE); + + num_dfps_rates = ((!dfps_caps.dfps_support || + is_cmd_mode) ? 1 : dfps_caps.dfps_list_len); + + /* Calculate dsi frame transfer time */ + if (is_cmd_mode) { + dsi_panel_calc_dsi_transfer_time( + &display->panel->host_config, + &display_mode, frame_threshold_us); + display_mode.priv_info->dsi_transfer_time_us = + display_mode.timing.dsi_transfer_time_us; + display_mode.priv_info->min_dsi_clk_hz = + display_mode.timing.min_dsi_clk_hz; + + display_mode.priv_info->mdp_transfer_time_us = + display_mode.timing.mdp_transfer_time_us; + } + + is_split_link = host->split_link.split_link_enabled; + sublinks_count = host->split_link.num_sublinks; + if (is_split_link && sublinks_count > 1) { + display_mode.timing.h_active *= sublinks_count; + display_mode.timing.h_front_porch *= sublinks_count; + display_mode.timing.h_sync_width *= sublinks_count; + display_mode.timing.h_back_porch *= sublinks_count; + display_mode.timing.h_skew *= sublinks_count; + display_mode.pixel_clk_khz *= sublinks_count; + } else { + display_mode.timing.h_active *= display->ctrl_count; + display_mode.timing.h_front_porch *= + display->ctrl_count; + display_mode.timing.h_sync_width *= + display->ctrl_count; + display_mode.timing.h_back_porch *= + display->ctrl_count; + display_mode.timing.h_skew *= display->ctrl_count; + display_mode.pixel_clk_khz *= display->ctrl_count; + } + + start = array_idx; + for (i = 0; i < num_dfps_rates; i++) { + struct dsi_display_mode *sub_mode = + &display->modes[array_idx]; + u32 curr_refresh_rate; + + if (!sub_mode) { + DSI_ERR("invalid mode data\n"); + rc = -EFAULT; + goto error; + } + + memcpy(sub_mode, &display_mode, sizeof(display_mode)); + array_idx++; + + if (!dfps_caps.dfps_support || is_cmd_mode) + continue; + + curr_refresh_rate = sub_mode->timing.refresh_rate; + sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i]; + + dsi_display_get_dfps_timing(display, sub_mode, + curr_refresh_rate); + } + end = array_idx; + /* + * if POMS is enabled and boot up mode is video mode, + * skip bit clk rates update for command mode, + * else if dynamic clk switch is supported then update all + * the bit clk rates. + */ + + if (is_cmd_mode && + (display->panel->panel_mode == DSI_OP_VIDEO_MODE)) + continue; + + _dsi_display_populate_bit_clks(display, start, end, &array_idx); + if (is_preferred) { + /* Set first timing sub mode as preferred mode */ + display->modes[start].is_preferred = true; + } + } + +exit: + *out_modes = display->modes; + primary_display = display; + rc = 0; + +error: + if (rc) + kfree(display->modes); + + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_get_panel_vfp(void *dsi_display, + int h_active, int v_active) +{ + int i, rc = 0; + u32 count, refresh_rate = 0; + struct dsi_dfps_capabilities dfps_caps; + struct dsi_display *display = (struct dsi_display *)dsi_display; + struct dsi_host_common_cfg *host; + + if (!display || !display->panel) + return -EINVAL; + + mutex_lock(&display->display_lock); + + count = display->panel->num_display_modes; + + if (display->panel->cur_mode) + refresh_rate = display->panel->cur_mode->timing.refresh_rate; + + dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + if (dfps_caps.dfps_support) + refresh_rate = dfps_caps.max_refresh_rate; + + if (!refresh_rate) { + mutex_unlock(&display->display_lock); + DSI_ERR("Null Refresh Rate\n"); + return -EINVAL; + } + + host = &display->panel->host_config; + if (host->split_link.split_link_enabled) + h_active *= host->split_link.num_sublinks; + else + h_active *= display->ctrl_count; + + for (i = 0; i < count; i++) { + struct dsi_display_mode *m = &display->modes[i]; + + if (m && v_active == m->timing.v_active && + h_active == m->timing.h_active && + refresh_rate == m->timing.refresh_rate) { + rc = m->timing.v_front_porch; + break; + } + } + mutex_unlock(&display->display_lock); + + return rc; +} + +int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm) +{ + struct dsi_display *display = (struct dsi_display *)dsi_display; + u32 count, i; + int rc = 0; + + *num_lm = 0; + + mutex_lock(&display->display_lock); + count = display->panel->num_display_modes; + mutex_unlock(&display->display_lock); + + if (!display->modes) { + struct dsi_display_mode *m; + + rc = dsi_display_get_modes(display, &m); + if (rc) + return rc; + } + + mutex_lock(&display->display_lock); + for (i = 0; i < count; i++) { + struct dsi_display_mode *m = &display->modes[i]; + + *num_lm = max(m->priv_info->topology.num_lm, *num_lm); + } + mutex_unlock(&display->display_lock); + + return rc; +} + +int dsi_display_find_mode(struct dsi_display *display, + const struct dsi_display_mode *cmp, + struct dsi_display_mode **out_mode) +{ + u32 count, i; + int rc; + + if (!display || !out_mode) + return -EINVAL; + + *out_mode = NULL; + + mutex_lock(&display->display_lock); + count = display->panel->num_display_modes; + mutex_unlock(&display->display_lock); + + if (!display->modes) { + struct dsi_display_mode *m; + + rc = dsi_display_get_modes(display, &m); + if (rc) + return rc; + } + + mutex_lock(&display->display_lock); + for (i = 0; i < count; i++) { + struct dsi_display_mode *m = &display->modes[i]; + + if (cmp->timing.v_active == m->timing.v_active && + cmp->timing.h_active == m->timing.h_active && + cmp->timing.refresh_rate == m->timing.refresh_rate && + cmp->panel_mode == m->panel_mode && + cmp->pixel_clk_khz == m->pixel_clk_khz) { + *out_mode = m; + rc = 0; + break; + } + } + mutex_unlock(&display->display_lock); + + if (!*out_mode) { + DSI_ERR("[%s] failed to find mode for v_active %u h_active %u fps %u pclk %u\n", + display->name, cmp->timing.v_active, + cmp->timing.h_active, cmp->timing.refresh_rate, + cmp->pixel_clk_khz); + rc = -ENOENT; + } + + return rc; +} + +static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur, + struct dsi_display_mode *adj) +{ + /* + * If there is a change in the hfp or vfp of the current and adjoining + * mode,then either it is a dfps mode switch or dynamic clk change with + * constant fps. + */ + if ((cur->timing.h_front_porch != adj->timing.h_front_porch) || + (cur->timing.v_front_porch != adj->timing.v_front_porch)) + return true; + else + return false; +} + +/** + * dsi_display_validate_mode_change() - Validate mode change case. + * @display: DSI display handle. + * @cur_mode: Current mode. + * @adj_mode: Mode to be set. + * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there + * is change in hfp or vfp but vactive and hactive are same. + * DSI_MODE_FLAG_DYN_CLK flag is set if there + * is change in clk but vactive and hactive are same. + * Return: error code. + */ +u32 mode_fps = 90; +EXPORT_SYMBOL(mode_fps); +int dsi_display_validate_mode_change(struct dsi_display *display, + struct dsi_display_mode *cur_mode, + struct dsi_display_mode *adj_mode) +{ + int rc = 0; + struct dsi_dfps_capabilities dfps_caps; + struct dsi_dyn_clk_caps *dyn_clk_caps; + struct drm_panel_notifier notifier_data; + int dynamic_fps; + + if (!display || !adj_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (!display->panel || !display->panel->cur_mode) { + DSI_DEBUG("Current panel mode not set\n"); + return rc; + } + + mutex_lock(&display->display_lock); + dyn_clk_caps = &(display->panel->dyn_clk_caps); + if ((cur_mode->timing.v_active == adj_mode->timing.v_active) && + (cur_mode->timing.h_active == adj_mode->timing.h_active) && + (cur_mode->panel_mode == adj_mode->panel_mode)) { + /* dfps and dynamic clock with const fps use case */ + if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) { + dsi_panel_get_dfps_caps(display->panel, &dfps_caps); + if (mode_fps != adj_mode->timing.refresh_rate) { + mode_fps = adj_mode->timing.refresh_rate; + dynamic_fps = mode_fps; + notifier_data.data = &dynamic_fps; + DSI_ERR("set fps: %d\n", dynamic_fps); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + } + if (dfps_caps.dfps_support || + dyn_clk_caps->maintain_const_fps) { + DSI_DEBUG("Mode switch is seamless variable refresh\n"); + adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; + SDE_EVT32(SDE_EVTLOG_FUNC_CASE1, + cur_mode->timing.refresh_rate, + adj_mode->timing.refresh_rate, + cur_mode->timing.h_front_porch, + adj_mode->timing.h_front_porch, + cur_mode->timing.v_front_porch, + adj_mode->timing.v_front_porch); + } + } + + /* dynamic clk change use case */ + if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) { + if (dyn_clk_caps->dyn_clk_support) { + DSI_DEBUG("dynamic clk change detected\n"); + if ((adj_mode->dsi_mode_flags & + DSI_MODE_FLAG_VRR) && + (!dyn_clk_caps->maintain_const_fps)) { + DSI_ERR("dfps and dyn clk not supported in same commit\n"); + rc = -ENOTSUPP; + goto error; + } + + adj_mode->dsi_mode_flags |= + DSI_MODE_FLAG_DYN_CLK; + SDE_EVT32(SDE_EVTLOG_FUNC_CASE2, + cur_mode->pixel_clk_khz, + adj_mode->pixel_clk_khz); + } + } + } + +error: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_validate_mode(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + struct dsi_display_mode adj_mode; + + if (!display || !mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + adj_mode = *mode; + adjust_timing_by_ctrl_count(display, &adj_mode); + + rc = dsi_panel_validate_mode(display->panel, &adj_mode); + if (rc) { + DSI_ERR("[%s] panel mode validation failed, rc=%d\n", + display->name, rc); + goto error; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_validate_timing(ctrl->ctrl, &adj_mode.timing); + if (rc) { + DSI_ERR("[%s] ctrl mode validation failed, rc=%d\n", + display->name, rc); + goto error; + } + + rc = dsi_phy_validate_mode(ctrl->phy, &adj_mode.timing); + if (rc) { + DSI_ERR("[%s] phy mode validation failed, rc=%d\n", + display->name, rc); + goto error; + } + } + + if ((flags & DSI_VALIDATE_FLAG_ALLOW_ADJUST) && + (mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS)) { + rc = dsi_display_validate_mode_seamless(display, mode); + if (rc) { + DSI_ERR("[%s] seamless not possible rc=%d\n", + display->name, rc); + goto error; + } + } + +error: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_set_mode(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags) +{ + int rc = 0; + struct dsi_display_mode adj_mode; + struct dsi_mode_info timing; + + if (!display || !mode || !display->panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + adj_mode = *mode; + timing = adj_mode.timing; + adjust_timing_by_ctrl_count(display, &adj_mode); + + if (!display->panel->cur_mode) { + display->panel->cur_mode = + kzalloc(sizeof(struct dsi_display_mode), GFP_KERNEL); + if (!display->panel->cur_mode) { + rc = -ENOMEM; + goto error; + } + } + + /*For dynamic DSI setting, use specified clock rate */ + if (display->cached_clk_rate > 0) + adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate; + + rc = dsi_display_validate_mode_set(display, &adj_mode, flags); + if (rc) { + DSI_ERR("[%s] mode cannot be set\n", display->name); + goto error; + } + + rc = dsi_display_set_mode_sub(display, &adj_mode, flags); + if (rc) { + DSI_ERR("[%s] failed to set mode\n", display->name); + goto error; + } + + DSI_INFO("mdp_transfer_time_us=%d us\n", + adj_mode.priv_info->mdp_transfer_time_us); + DSI_INFO("hactive= %d,vactive= %d,fps=%d\n", + timing.h_active, timing.v_active, + timing.refresh_rate); + + memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode)); + mode_fps = display->panel->cur_mode->timing.refresh_rate; +error: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_set_tpg_state(struct dsi_display *display, bool enable) +{ + int rc = 0; + int i; + struct dsi_display_ctrl *ctrl; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_set_tpg_state(ctrl->ctrl, enable); + if (rc) { + DSI_ERR("[%s] failed to set tpg state for host_%d\n", + display->name, i); + goto error; + } + } + + display->is_tpg_enabled = enable; +error: + return rc; +} + +static int dsi_display_pre_switch(struct dsi_display *display) +{ + int rc = 0; + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto error; + } + + rc = dsi_display_ctrl_update(display); + if (rc) { + DSI_ERR("[%s] failed to update DSI controller, rc=%d\n", + display->name, rc); + goto error_ctrl_clk_off; + } + + rc = dsi_display_set_clk_src(display); + if (rc) { + DSI_ERR("[%s] failed to set DSI link clock source, rc=%d\n", + display->name, rc); + goto error_ctrl_deinit; + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_LINK_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI link clocks, rc=%d\n", + display->name, rc); + goto error_ctrl_deinit; + } + + goto error; + +error_ctrl_deinit: + (void)dsi_display_ctrl_deinit(display); +error_ctrl_clk_off: + (void)dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); +error: + return rc; +} + +static bool _dsi_display_validate_host_state(struct dsi_display *display) +{ + int i; + struct dsi_display_ctrl *ctrl; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl) + continue; + if (!dsi_ctrl_validate_host_state(ctrl->ctrl)) + return false; + } + + return true; +} + +static void dsi_display_handle_fifo_underflow(struct work_struct *work) +{ + struct dsi_display *display = NULL; + + display = container_of(work, struct dsi_display, fifo_underflow_work); + if (!display || !display->panel || + atomic_read(&display->panel->esd_recovery_pending)) { + DSI_DEBUG("Invalid recovery use case\n"); + return; + } + + mutex_lock(&display->display_lock); + + if (!_dsi_display_validate_host_state(display)) { + mutex_unlock(&display->display_lock); + return; + } + + DSI_DEBUG("handle DSI FIFO underflow error\n"); + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + dsi_display_soft_reset(display); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + + mutex_unlock(&display->display_lock); +} + +static void dsi_display_handle_fifo_overflow(struct work_struct *work) +{ + struct dsi_display *display = NULL; + struct dsi_display_ctrl *ctrl; + int i, rc; + int mask = BIT(20); /* clock lane */ + int (*cb_func)(void *event_usr_ptr, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + void *data; + u32 version = 0; + + display = container_of(work, struct dsi_display, fifo_overflow_work); + if (!display || !display->panel || + (display->panel->panel_mode != DSI_OP_VIDEO_MODE) || + atomic_read(&display->panel->esd_recovery_pending)) { + DSI_DEBUG("Invalid recovery use case\n"); + return; + } + + mutex_lock(&display->display_lock); + + if (!_dsi_display_validate_host_state(display)) { + mutex_unlock(&display->display_lock); + return; + } + + DSI_DEBUG("handle DSI FIFO overflow error\n"); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + /* + * below recovery sequence is not applicable to + * hw version 2.0.0, 2.1.0 and 2.2.0, so return early. + */ + ctrl = &display->ctrl[display->clk_master_idx]; + version = dsi_ctrl_get_hw_version(ctrl->ctrl); + if (!version || (version < 0x20020001)) + goto end; + + /* reset ctrl and lanes */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_reset(ctrl->ctrl, mask); + rc = dsi_phy_lane_reset(ctrl->phy); + } + + /* wait for display line count to be in active area */ + ctrl = &display->ctrl[display->clk_master_idx]; + if (ctrl->ctrl->recovery_cb.event_cb) { + cb_func = ctrl->ctrl->recovery_cb.event_cb; + data = ctrl->ctrl->recovery_cb.event_usr_ptr; + rc = cb_func(data, SDE_CONN_EVENT_VID_FIFO_OVERFLOW, + display->clk_master_idx, 0, 0, 0, 0); + if (rc < 0) { + DSI_DEBUG("sde callback failed\n"); + goto end; + } + } + + /* Enable Video mode for DSI controller */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_ctrl_vid_engine_en(ctrl->ctrl, true); + } + /* + * Add sufficient delay to make sure + * pixel transmission has started + */ + udelay(200); +end: + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + mutex_unlock(&display->display_lock); +} + +static void dsi_display_handle_lp_rx_timeout(struct work_struct *work) +{ + struct dsi_display *display = NULL; + struct dsi_display_ctrl *ctrl; + int i, rc; + int mask = (BIT(20) | (0xF << 16)); /* clock lane and 4 data lane */ + int (*cb_func)(void *event_usr_ptr, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + void *data; + u32 version = 0; + + display = container_of(work, struct dsi_display, lp_rx_timeout_work); + if (!display || !display->panel || + (display->panel->panel_mode != DSI_OP_VIDEO_MODE) || + atomic_read(&display->panel->esd_recovery_pending)) { + DSI_DEBUG("Invalid recovery use case\n"); + return; + } + + mutex_lock(&display->display_lock); + + if (!_dsi_display_validate_host_state(display)) { + mutex_unlock(&display->display_lock); + return; + } + + DSI_DEBUG("handle DSI LP RX Timeout error\n"); + + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + + /* + * below recovery sequence is not applicable to + * hw version 2.0.0, 2.1.0 and 2.2.0, so return early. + */ + ctrl = &display->ctrl[display->clk_master_idx]; + version = dsi_ctrl_get_hw_version(ctrl->ctrl); + if (!version || (version < 0x20020001)) + goto end; + + /* reset ctrl and lanes */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + rc = dsi_ctrl_reset(ctrl->ctrl, mask); + rc = dsi_phy_lane_reset(ctrl->phy); + } + + ctrl = &display->ctrl[display->clk_master_idx]; + if (ctrl->ctrl->recovery_cb.event_cb) { + cb_func = ctrl->ctrl->recovery_cb.event_cb; + data = ctrl->ctrl->recovery_cb.event_usr_ptr; + rc = cb_func(data, SDE_CONN_EVENT_VID_FIFO_OVERFLOW, + display->clk_master_idx, 0, 0, 0, 0); + if (rc < 0) { + DSI_DEBUG("Target is in suspend/shutdown\n"); + goto end; + } + } + + /* Enable Video mode for DSI controller */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + dsi_ctrl_vid_engine_en(ctrl->ctrl, true); + } + + /* + * Add sufficient delay to make sure + * pixel transmission as started + */ + udelay(200); +end: + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + mutex_unlock(&display->display_lock); +} + +static int dsi_display_cb_error_handler(void *data, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3) +{ + struct dsi_display *display = data; + + if (!display || !(display->err_workq)) + return -EINVAL; + + switch (event_idx) { + case DSI_FIFO_UNDERFLOW: + queue_work(display->err_workq, &display->fifo_underflow_work); + break; + case DSI_FIFO_OVERFLOW: + queue_work(display->err_workq, &display->fifo_overflow_work); + break; + case DSI_LP_Rx_TIMEOUT: + queue_work(display->err_workq, &display->lp_rx_timeout_work); + break; + default: + DSI_WARN("unhandled error interrupt: %d\n", event_idx); + break; + } + + return 0; +} + +static void dsi_display_register_error_handler(struct dsi_display *display) +{ + int i = 0; + struct dsi_display_ctrl *ctrl; + struct dsi_event_cb_info event_info; + + if (!display) + return; + + display->err_workq = create_singlethread_workqueue("dsi_err_workq"); + if (!display->err_workq) { + DSI_ERR("failed to create dsi workq!\n"); + return; + } + + INIT_WORK(&display->fifo_underflow_work, + dsi_display_handle_fifo_underflow); + INIT_WORK(&display->fifo_overflow_work, + dsi_display_handle_fifo_overflow); + INIT_WORK(&display->lp_rx_timeout_work, + dsi_display_handle_lp_rx_timeout); + + memset(&event_info, 0, sizeof(event_info)); + + event_info.event_cb = dsi_display_cb_error_handler; + event_info.event_usr_ptr = display; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + ctrl->ctrl->irq_info.irq_err_cb = event_info; + } +} + +static void dsi_display_unregister_error_handler(struct dsi_display *display) +{ + int i = 0; + struct dsi_display_ctrl *ctrl; + + if (!display) + return; + + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + memset(&ctrl->ctrl->irq_info.irq_err_cb, + 0, sizeof(struct dsi_event_cb_info)); + } + + if (display->err_workq) { + destroy_workqueue(display->err_workq); + display->err_workq = NULL; + } +} + +int dsi_display_prepare(struct dsi_display *display) +{ + int rc = 0; + struct dsi_display_mode *mode; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (!display->panel->cur_mode) { + DSI_ERR("no valid mode set for the display\n"); + return -EINVAL; + } + + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + mutex_lock(&display->display_lock); + + mode = display->panel->cur_mode; + + dsi_display_set_ctrl_esd_check_flag(display, false); + + /* Set up ctrl isr before enabling core clk */ + dsi_display_ctrl_isr_configure(display, true); + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { + if (display->is_cont_splash_enabled && + display->config.panel_mode == DSI_OP_VIDEO_MODE) { + DSI_ERR("DMS not supported on first frame\n"); + rc = -EINVAL; + goto error; + } + + if (!display->is_cont_splash_enabled) { + /* update dsi ctrl for new mode */ + rc = dsi_display_pre_switch(display); + if (rc) + DSI_ERR("[%s] panel pre-switch failed, rc=%d\n", + display->name, rc); + goto error; + } + } + + if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) && + (!display->is_cont_splash_enabled)) { + /* + * For continuous splash usecase we skip panel + * pre prepare since the regulator vote is already + * taken care in splash resource init + */ + rc = dsi_panel_pre_prepare(display->panel); + if (rc) { + DSI_ERR("[%s] panel pre-prepare failed, rc=%d\n", + display->name, rc); + goto error; + } + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, rc); + goto error_panel_post_unprep; + } + + /* + * If ULPS during suspend feature is enabled, then DSI PHY was + * left on during suspend. In this case, we do not need to reset/init + * PHY. This would have already been done when the CORE clocks are + * turned on. However, if cont splash is disabled, the first time DSI + * is powered on, phy init needs to be done unconditionally. + */ + if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) { + rc = dsi_display_phy_sw_reset(display); + if (rc) { + DSI_ERR("[%s] failed to reset phy, rc=%d\n", + display->name, rc); + goto error_ctrl_clk_off; + } + + rc = dsi_display_phy_enable(display); + if (rc) { + DSI_ERR("[%s] failed to enable DSI PHY, rc=%d\n", + display->name, rc); + goto error_ctrl_clk_off; + } + } + + rc = dsi_display_set_clk_src(display); + if (rc) { + DSI_ERR("[%s] failed to set DSI link clock source, rc=%d\n", + display->name, rc); + goto error_phy_disable; + } + + rc = dsi_display_ctrl_init(display); + if (rc) { + DSI_ERR("[%s] failed to setup DSI controller, rc=%d\n", + display->name, rc); + goto error_phy_disable; + } + /* Set up DSI ERROR event callback */ + dsi_display_register_error_handler(display); + + rc = dsi_display_ctrl_host_enable(display); + if (rc) { + DSI_ERR("[%s] failed to enable DSI host, rc=%d\n", + display->name, rc); + goto error_ctrl_deinit; + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_LINK_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI link clocks, rc=%d\n", + display->name, rc); + goto error_host_engine_off; + } + + if (!display->is_cont_splash_enabled) { + /* + * For continuous splash usecase, skip panel prepare and + * ctl reset since the pnael and ctrl is already in active + * state and panel on commands are not needed + */ + rc = dsi_display_soft_reset(display); + if (rc) { + DSI_ERR("[%s] failed soft reset, rc=%d\n", + display->name, rc); + goto error_ctrl_link_off; + } + + if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS)) { + rc = dsi_panel_prepare(display->panel); + if (rc) { + DSI_ERR("[%s] panel prepare failed, rc=%d\n", + display->name, rc); + goto error_ctrl_link_off; + } + } + } + goto error; + +error_ctrl_link_off: + (void)dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_LINK_CLK, DSI_CLK_OFF); +error_host_engine_off: + (void)dsi_display_ctrl_host_disable(display); +error_ctrl_deinit: + (void)dsi_display_ctrl_deinit(display); +error_phy_disable: + (void)dsi_display_phy_disable(display); +error_ctrl_clk_off: + (void)dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); +error_panel_post_unprep: + (void)dsi_panel_post_unprepare(display->panel); +error: + mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); + return rc; +} + +static int dsi_display_calc_ctrl_roi(const struct dsi_display *display, + const struct dsi_display_ctrl *ctrl, + const struct msm_roi_list *req_rois, + struct dsi_rect *out_roi) +{ + const struct dsi_rect *bounds = &ctrl->ctrl->mode_bounds; + struct dsi_display_mode *cur_mode; + struct msm_roi_caps *roi_caps; + struct dsi_rect req_roi = { 0 }; + int rc = 0; + + cur_mode = display->panel->cur_mode; + if (!cur_mode) + return 0; + + roi_caps = &cur_mode->priv_info->roi_caps; + if (req_rois->num_rects > roi_caps->num_roi) { + DSI_ERR("request for %d rois greater than max %d\n", + req_rois->num_rects, + roi_caps->num_roi); + rc = -EINVAL; + goto exit; + } + + /** + * if no rois, user wants to reset back to full resolution + * note: h_active is already divided by ctrl_count + */ + if (!req_rois->num_rects) { + *out_roi = *bounds; + goto exit; + } + + /* intersect with the bounds */ + req_roi.x = req_rois->roi[0].x1; + req_roi.y = req_rois->roi[0].y1; + req_roi.w = req_rois->roi[0].x2 - req_rois->roi[0].x1; + req_roi.h = req_rois->roi[0].y2 - req_rois->roi[0].y1; + dsi_rect_intersect(&req_roi, bounds, out_roi); + +exit: + /* adjust the ctrl origin to be top left within the ctrl */ + out_roi->x = out_roi->x - bounds->x; + + DSI_DEBUG("ctrl%d:%d: req (%d,%d,%d,%d) bnd (%d,%d,%d,%d) out (%d,%d,%d,%d)\n", + ctrl->dsi_ctrl_idx, ctrl->ctrl->cell_index, + req_roi.x, req_roi.y, req_roi.w, req_roi.h, + bounds->x, bounds->y, bounds->w, bounds->h, + out_roi->x, out_roi->y, out_roi->w, out_roi->h); + + return rc; +} + +static int dsi_display_qsync(struct dsi_display *display, bool enable) +{ + int i; + int rc = 0; + + if (!display->panel->qsync_min_fps) { + DSI_ERR("%s:ERROR: qsync set, but no fps\n", __func__); + return 0; + } + + mutex_lock(&display->display_lock); + + display_for_each_ctrl(i, display) { + if (enable) { + /* send the commands to enable qsync */ + rc = dsi_panel_send_qsync_on_dcs(display->panel, i); + if (rc) { + DSI_ERR("fail qsync ON cmds rc:%d\n", rc); + goto exit; + } + } else { + /* send the commands to enable qsync */ + rc = dsi_panel_send_qsync_off_dcs(display->panel, i); + if (rc) { + DSI_ERR("fail qsync OFF cmds rc:%d\n", rc); + goto exit; + } + } + + dsi_ctrl_setup_avr(display->ctrl[i].ctrl, enable); + } + +exit: + SDE_EVT32(enable, display->panel->qsync_min_fps, rc); + mutex_unlock(&display->display_lock); + return rc; +} + +static int dsi_display_set_roi(struct dsi_display *display, + struct msm_roi_list *rois) +{ + struct dsi_display_mode *cur_mode; + struct msm_roi_caps *roi_caps; + int rc = 0; + int i; + + if (!display || !rois || !display->panel) + return -EINVAL; + + cur_mode = display->panel->cur_mode; + if (!cur_mode) + return 0; + + roi_caps = &cur_mode->priv_info->roi_caps; + if (!roi_caps->enabled) + return 0; + + display_for_each_ctrl(i, display) { + struct dsi_display_ctrl *ctrl = &display->ctrl[i]; + struct dsi_rect ctrl_roi; + bool changed = false; + + rc = dsi_display_calc_ctrl_roi(display, ctrl, rois, &ctrl_roi); + if (rc) { + DSI_ERR("dsi_display_calc_ctrl_roi failed rc %d\n", rc); + return rc; + } + + rc = dsi_ctrl_set_roi(ctrl->ctrl, &ctrl_roi, &changed); + if (rc) { + DSI_ERR("dsi_ctrl_set_roi failed rc %d\n", rc); + return rc; + } + + if (!changed) + continue; + + /* send the new roi to the panel via dcs commands */ + rc = dsi_panel_send_roi_dcs(display->panel, i, &ctrl_roi); + if (rc) { + DSI_ERR("dsi_panel_set_roi failed rc %d\n", rc); + return rc; + } + + /* re-program the ctrl with the timing based on the new roi */ + rc = dsi_ctrl_timing_setup(ctrl->ctrl); + if (rc) { + DSI_ERR("dsi_ctrl_setup failed rc %d\n", rc); + return rc; + } + } + + return rc; +} + +int dsi_display_pre_kickoff(struct drm_connector *connector, + struct dsi_display *display, + struct msm_display_kickoff_params *params) +{ + int rc = 0; + int i; + + /* check and setup MISR */ + if (display->misr_enable) + _dsi_display_setup_misr(display); + + rc = dsi_display_set_roi(display, params->rois); + + /* dynamic DSI clock setting */ + if (atomic_read(&display->clkrate_change_pending)) { + mutex_lock(&display->display_lock); + /* + * acquire panel_lock to make sure no commands are in progress + */ + dsi_panel_acquire_panel_lock(display->panel); + + /* + * Wait for DSI command engine not to be busy sending data + * from display engine. + * If waiting fails, return "rc" instead of below "ret" so as + * not to impact DRM commit. The clock updating would be + * deferred to the next DRM commit. + */ + display_for_each_ctrl(i, display) { + struct dsi_ctrl *ctrl = display->ctrl[i].ctrl; + int ret = 0; + + ret = dsi_ctrl_wait_for_cmd_mode_mdp_idle(ctrl); + if (ret) + goto wait_failure; + } + + /* + * Don't check the return value so as not to impact DRM commit + * when error occurs. + */ + (void)dsi_display_force_update_dsi_clk(display); +wait_failure: + /* release panel_lock */ + dsi_panel_release_panel_lock(display->panel); + mutex_unlock(&display->display_lock); + } + + return rc; +} + +int dsi_display_config_ctrl_for_cont_splash(struct dsi_display *display) +{ + int rc = 0; + + if (!display || !display->panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (!display->panel->cur_mode) { + DSI_ERR("no valid mode set for the display\n"); + return -EINVAL; + } + + if (!display->is_cont_splash_enabled) + return 0; + + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { + rc = dsi_display_vid_engine_enable(display); + if (rc) { + DSI_ERR("[%s]failed to enable DSI video engine, rc=%d\n", + display->name, rc); + goto error_out; + } + } else if (display->config.panel_mode == DSI_OP_CMD_MODE) { + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("[%s]failed to enable DSI cmd engine, rc=%d\n", + display->name, rc); + goto error_out; + } + } else { + DSI_ERR("[%s] Invalid configuration\n", display->name); + rc = -EINVAL; + } + +error_out: + return rc; +} + +int dsi_display_pre_commit(void *display, + struct msm_display_conn_params *params) +{ + bool enable = false; + int rc = 0; + + if (!display || !params) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + if (params->qsync_update) { + enable = (params->qsync_mode > 0) ? true : false; + rc = dsi_display_qsync(display, enable); + if (rc) + pr_err("%s failed to send qsync commands\n", + __func__); + SDE_EVT32(params->qsync_mode, rc); + } + + return rc; +} + +int dsi_display_enable(struct dsi_display *display) +{ + int rc = 0; + struct dsi_display_mode *mode; + + if (!display || !display->panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (!display->panel->cur_mode) { + DSI_ERR("no valid mode set for the display\n"); + return -EINVAL; + } + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + + /* Engine states and panel states are populated during splash + * resource init and hence we return early + */ + if (display->is_cont_splash_enabled) { + + dsi_display_config_ctrl_for_cont_splash(display); + + rc = dsi_display_splash_res_cleanup(display); + if (rc) { + DSI_ERR("Continuous splash res cleanup failed, rc=%d\n", + rc); + return -EINVAL; + } + + display->panel->panel_initialized = true; + DSI_DEBUG("cont splash enabled, display enable not required\n"); + return 0; + } + + mutex_lock(&display->display_lock); + + mode = display->panel->cur_mode; + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { + rc = dsi_panel_post_switch(display->panel); + if (rc) { + DSI_ERR("[%s] failed to switch DSI panel mode, rc=%d\n", + display->name, rc); + goto error; + } + } else if (!(display->panel->cur_mode->dsi_mode_flags & + DSI_MODE_FLAG_POMS)){ + rc = dsi_panel_enable(display->panel); + if (rc) { + DSI_ERR("[%s] failed to enable DSI panel, rc=%d\n", + display->name, rc); + goto error; + } + } + + /* Block sending pps command if modeset is due to fps difference */ + if ((mode->priv_info->dsc_enabled) && + !(mode->dsi_mode_flags & DSI_MODE_FLAG_DMS_FPS)) { + mode->priv_info->dsc.pic_width *= display->ctrl_count; + rc = dsi_panel_update_pps(display->panel); + if (rc) { + DSI_ERR("[%s] panel pps cmd update failed, rc=%d\n", + display->name, rc); + goto error; + } + } + + if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) { + rc = dsi_panel_switch(display->panel); + if (rc) + DSI_ERR("[%s] failed to switch DSI panel mode, rc=%d\n", + display->name, rc); + + goto error; + } + + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { + DSI_DEBUG("%s:enable video timing eng\n", __func__); + rc = dsi_display_vid_engine_enable(display); + if (rc) { + DSI_ERR("[%s]failed to enable DSI video engine, rc=%d\n", + display->name, rc); + goto error_disable_panel; + } + } else if (display->config.panel_mode == DSI_OP_CMD_MODE) { + DSI_DEBUG("%s:enable command timing eng\n", __func__); + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("[%s]failed to enable DSI cmd engine, rc=%d\n", + display->name, rc); + goto error_disable_panel; + } + } else { + DSI_ERR("[%s] Invalid configuration\n", display->name); + rc = -EINVAL; + goto error_disable_panel; + } + + goto error; + +error_disable_panel: + (void)dsi_panel_disable(display->panel); +error: + mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); + return rc; +} + +int dsi_display_post_enable(struct dsi_display *display) +{ + int rc = 0; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + if (display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) { + if (display->config.panel_mode == DSI_OP_CMD_MODE) + dsi_panel_mode_switch_to_cmd(display->panel); + + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) + dsi_panel_mode_switch_to_vid(display->panel); + } else { + rc = dsi_panel_post_enable(display->panel); + if (rc) + DSI_ERR("[%s] panel post-enable failed, rc=%d\n", + display->name, rc); + } + + /* remove the clk vote for CMD mode panels */ + if (display->config.panel_mode == DSI_OP_CMD_MODE) + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_pre_disable(struct dsi_display *display) +{ + int rc = 0; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&display->display_lock); + + /* enable the clk vote for CMD mode panels */ + if (display->config.panel_mode == DSI_OP_CMD_MODE) + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (display->poms_pending) { + if (display->config.panel_mode == DSI_OP_CMD_MODE) + dsi_panel_pre_mode_switch_to_video(display->panel); + + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { + /* + * Add unbalanced vote for clock & cmd engine to enable + * async trigger of pre video to cmd mode switch. + */ + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s]failed to enable all clocks,rc=%d", + display->name, rc); + goto exit; + } + + rc = dsi_display_cmd_engine_enable(display); + if (rc) { + DSI_ERR("[%s]failed to enable cmd engine,rc=%d", + display->name, rc); + goto error_disable_clks; + } + + dsi_panel_pre_mode_switch_to_cmd(display->panel); + } + } else { + rc = dsi_panel_pre_disable(display->panel); + if (rc) + DSI_ERR("[%s] panel pre-disable failed, rc=%d\n", + display->name, rc); + } + goto exit; + +error_disable_clks: + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) + DSI_ERR("[%s] failed to disable all DSI clocks, rc=%d\n", + display->name, rc); + +exit: + mutex_unlock(&display->display_lock); + return rc; +} + +int dsi_display_disable(struct dsi_display *display) +{ + int rc = 0; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + mutex_lock(&display->display_lock); + + rc = dsi_display_wake_up(display); + if (rc) + DSI_ERR("[%s] display wake up failed, rc=%d\n", + display->name, rc); + + if (display->config.panel_mode == DSI_OP_VIDEO_MODE) { + rc = dsi_display_vid_engine_disable(display); + if (rc) + DSI_ERR("[%s]failed to disable DSI vid engine, rc=%d\n", + display->name, rc); + } else if (display->config.panel_mode == DSI_OP_CMD_MODE) { + rc = dsi_display_cmd_engine_disable(display); + if (rc) + DSI_ERR("[%s]failed to disable DSI cmd engine, rc=%d\n", + display->name, rc); + } else { + DSI_ERR("[%s] Invalid configuration\n", display->name); + rc = -EINVAL; + } + + if (!display->poms_pending) { + rc = dsi_panel_disable(display->panel); + if (rc) + DSI_ERR("[%s] failed to disable DSI panel, rc=%d\n", + display->name, rc); + } + mutex_unlock(&display->display_lock); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); + return rc; +} + +int dsi_display_update_pps(char *pps_cmd, void *disp) +{ + struct dsi_display *display; + + if (pps_cmd == NULL || disp == NULL) { + DSI_ERR("Invalid parameter\n"); + return -EINVAL; + } + + display = disp; + mutex_lock(&display->display_lock); + memcpy(display->panel->dsc_pps_cmd, pps_cmd, DSI_CMD_PPS_SIZE); + mutex_unlock(&display->display_lock); + + return 0; +} +int dsi_display_set_acl_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->acl_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_acl_mode(panel, level); + if (rc) + DSI_ERR("unable to set acl mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_acl_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->acl_mode; +} +int dsi_display_unprepare(struct dsi_display *display) +{ + int rc = 0, i; + struct dsi_display_ctrl *ctrl; + + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + mutex_lock(&display->display_lock); + + rc = dsi_display_wake_up(display); + if (rc) + DSI_ERR("[%s] display wake up failed, rc=%d\n", + display->name, rc); + if (!display->poms_pending) { + rc = dsi_panel_unprepare(display->panel); + if (rc) + DSI_ERR("[%s] panel unprepare failed, rc=%d\n", + display->name, rc); + } + + /* Remove additional vote added for pre_mode_switch_to_cmd */ + if (display->poms_pending && + display->config.panel_mode == DSI_OP_VIDEO_MODE) { + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || !ctrl->ctrl->dma_wait_queued) + continue; + flush_workqueue(display->dma_cmd_workq); + cancel_work_sync(&ctrl->ctrl->dma_cmd_wait); + ctrl->ctrl->dma_wait_queued = false; + } + + dsi_display_cmd_engine_disable(display); + dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + } + + rc = dsi_display_ctrl_host_disable(display); + if (rc) + DSI_ERR("[%s] failed to disable DSI host, rc=%d\n", + display->name, rc); + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_LINK_CLK, DSI_CLK_OFF); + if (rc) + DSI_ERR("[%s] failed to disable Link clocks, rc=%d\n", + display->name, rc); + + rc = dsi_display_ctrl_deinit(display); + if (rc) + DSI_ERR("[%s] failed to deinit controller, rc=%d\n", + display->name, rc); + + if (!display->panel->ulps_suspend_enabled) { + rc = dsi_display_phy_disable(display); + if (rc) + DSI_ERR("[%s] failed to disable DSI PHY, rc=%d\n", + display->name, rc); + } + + rc = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) + DSI_ERR("[%s] failed to disable DSI clocks, rc=%d\n", + display->name, rc); + + /* destrory dsi isr set up */ + dsi_display_ctrl_isr_configure(display, false); + + if (!display->poms_pending) { + rc = dsi_panel_post_unprepare(display->panel); + if (rc) + DSI_ERR("[%s] panel post-unprepare failed, rc=%d\n", + display->name, rc); + } + + mutex_unlock(&display->display_lock); + + /* Free up DSI ERROR event callback */ + dsi_display_unregister_error_handler(display); + + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT); + return rc; +} +int dsi_display_get_gamma_para(struct dsi_display *dsi_display, struct dsi_panel *panel) +{ + int i = 0; + int j = 0; + int rc = 0; + int flags = 0; + char fb[13] = {0}; + //char c8[135] = {0}; + //char c9[180] = {0}; + char b3[47] = {0}; + char fb_temp[13] = {0}; + char c8_temp[135] = {0}; + char c9_temp[180] = {0}; + char b3_temp[47] = {0}; + char gamma_para_60hz[452] = {0}; + char gamma_para_backup[413] = {0}; + int check_sum_60hz = 0; + + struct dsi_cmd_desc *cmds; + struct dsi_display_mode *mode; + struct dsi_display_ctrl *m_ctrl; + + DSI_ERR("%s start\n", __func__); + + m_ctrl = &dsi_display->ctrl[dsi_display->cmd_master_idx]; + if (!panel || !m_ctrl) + return -EINVAL; + + rc = dsi_display_cmd_engine_enable(dsi_display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EINVAL; + } + + dsi_panel_acquire_panel_lock(panel); + mode = panel->cur_mode; + +/* Read 60hz gamma para */ + memcpy(gamma_para_backup, gamma_para[0], 413); + do { + check_sum_60hz = 0; + if (j > 0) { + DSI_ERR("Failed to read the 60hz gamma parameters %d!", j); + for (i = 0; i < 52; i++) { + if (i != 51) { + DSI_ERR("[60hz][%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X", + i*8, gamma_para[0][i*8], i*8+1, gamma_para[0][i*8+1], i*8+2, gamma_para[0][i*8+2], i*8+3, gamma_para[0][i*8+3], i*8+4, gamma_para[0][i*8+4], + i*8+5, gamma_para[0][i*8+5], i*8+6, gamma_para[0][i*8+6], i*8+7, gamma_para[0][i*8+7]); + } + else { + DSI_ERR("[60hz][%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X,[%d]0x%02X", + i*8, gamma_para[0][i*8], i*8+1, gamma_para[0][i*8+1], i*8+2, gamma_para[0][i*8+2], i*8+3, gamma_para[0][i*8+3], i*8+4, gamma_para[0][i*8+4]); + } + } + mdelay(1000); + } + for(i = 0; i < 452; i++) + { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_GAMMA_FLASH_PRE_READ_1); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_FLASH_PRE_READ_1 command\n"); + goto error; + } + + rc = dsi_panel_gamma_read_address_setting(panel, i); + if (rc) { + DSI_ERR("Failed to set gamma read address\n"); + goto error; + } + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_GAMMA_FLASH_PRE_READ_2); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_FLASH_PRE_READ_2 command\n"); + goto error; + } + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_GAMMA_FLASH_READ_FB].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + cmds->msg.rx_buf = fb_temp; + cmds->msg.rx_len = 13; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) { + DSI_ERR("Failed to read DSI_CMD_SET_GAMMA_FLASH_READ_FB\n"); + goto error; + } + memcpy(fb, cmds->msg.rx_buf, 13); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LEVEL2_KEY_DISABLE); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_LEVEL2_KEY_DISABLE command\n"); + goto error; + } + + if (i < 135) { + gamma_para[0][i+18] = fb[12]; + } + else if (i < 315) { + gamma_para[0][i+26] = fb[12]; + } + else if (i < 360) { + gamma_para[0][i+43] = fb[12]; + } + + gamma_para_60hz[i] = fb[12]; + if (i < 449) { + check_sum_60hz = gamma_para_60hz[i] + check_sum_60hz; + } + j++; + } + } + while ((check_sum_60hz != (gamma_para_60hz[450] << 8) + gamma_para_60hz[451]) && (j < 10)); + + if (check_sum_60hz == (gamma_para_60hz[450] << 8) + gamma_para_60hz[451]) { + DSI_ERR("Read 60hz gamma done\n"); + } + else { + DSI_ERR("Failed to read 60hz gamma, use default 60hz gamma.\n"); + memcpy(gamma_para[0], gamma_para_backup, 413); + gamma_read_flag = GAMMA_READ_ERROR; + } + +/* Read 90hz gamma para */ + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LEVEL2_KEY_ENABLE); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_LEVEL2_KEY_ENABLE command\n"); + goto error; + } + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_GAMMA_OTP_READ_C8_SMRPS); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_OTP_READ_C8_SMRPS command\n"); + goto error; + } + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_GAMMA_OTP_READ_C8].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds->msg.rx_buf = c8_temp; + cmds->msg.rx_len = 135; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) { + DSI_ERR("Failed to read DSI_CMD_SET_GAMMA_OTP_READ_C8\n"); + goto error; + } + memcpy(&gamma_para[1][18], cmds->msg.rx_buf, 135); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_GAMMA_OTP_READ_C9_SMRPS); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_OTP_READ_C9_SMRPS command\n"); + goto error; + } + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_GAMMA_OTP_READ_C9].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds->msg.rx_buf = c9_temp; + cmds->msg.rx_len = 180; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) { + DSI_ERR("Failed to read DSI_CMD_SET_GAMMA_OTP_READ_C9\n"); + goto error; + } + memcpy(&gamma_para[1][161], cmds->msg.rx_buf, 180); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_GAMMA_OTP_READ_B3_SMRPS); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_OTP_READ_C9_SMRPS command\n"); + goto error; + } + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_GAMMA_OTP_READ_B3].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds->msg.rx_buf = b3_temp; + cmds->msg.rx_len = 47; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) { + DSI_ERR("Failed to read DSI_CMD_SET_GAMMA_OTP_READ_B3\n"); + goto error; + } + memcpy(b3, cmds->msg.rx_buf, 47); + memcpy(&gamma_para[1][358], &b3[2], 45); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LEVEL2_KEY_DISABLE); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_GAMMA_OTP_READ_C9_SMRPS command\n"); + goto error; + } + DSI_ERR("Read 90hz gamma done\n"); + +error: + dsi_panel_release_panel_lock(panel); + dsi_display_cmd_engine_disable(dsi_display); + DSI_ERR("%s end\n", __func__); + return rc; +} + +int dsi_display_gamma_read(struct dsi_display *dsi_display) +{ + int rc = 0; + struct dsi_panel *panel = NULL; + + DSI_ERR("%s start\n", __func__); + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + mutex_lock(&dsi_display->display_lock); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", dsi_display->name, rc); + goto error; + } + + dsi_display_get_gamma_para(dsi_display, panel); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI clocks, rc=%d\n", dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&dsi_display->display_lock); + DSI_ERR("%s end\n", __func__); + return rc; +} + +void dsi_display_gamma_read_work(struct work_struct *work) +{ + struct dsi_display *dsi_display; + + dsi_display = get_main_display(); + + if (((dsi_display->panel->panel_production_info & 0x0F) == 0x0C) + || ((dsi_display->panel->panel_production_info & 0x0F) == 0x0E) + || ((dsi_display->panel->panel_production_info & 0x0F) == 0x0D)) + dsi_display_gamma_read(dsi_display); + + dsi_panel_parse_gamma_cmd_sets(); +} + +int dsi_display_update_gamma_para(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + rc = dsi_display_gamma_read(dsi_display); + if (rc) + DSI_ERR("Failed to read gamma para, rc=%d\n", rc); + + return rc; +} + + +int dsi_display_read_serial_number(struct dsi_display *dsi_display, + struct dsi_panel *panel, char *buf, int len) +{ + int rc = 0; + int flags = 0; + int code_info = 0; + int stage_info = 0; + int prodution_info = 0; + int panel_ic_v = 0; + int ddic_x = 0; + int ddic_y = 0; + u32 count = 0; + u8 register_d6[10] = {0}; + struct dsi_cmd_desc *cmds; + struct dsi_cmd_desc *cmds1; + struct dsi_display_mode *mode; + struct dsi_display_ctrl *m_ctrl; + + DSI_ERR("%s start\n", __func__); + + m_ctrl = &dsi_display->ctrl[dsi_display->cmd_master_idx]; + + if (!panel || !m_ctrl) + return -EINVAL; + + rc = dsi_display_cmd_engine_enable(dsi_display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EINVAL; + } + + dsi_panel_acquire_panel_lock(panel); + mode = panel->cur_mode; + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) { + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_IC_V_REGISTER_ON].count; + if (!count) { + DSI_ERR("This panel does not read register\n"); + } else { + rc = dsi_panel_tx_cmd_set_op(panel, DSI_CMD_READ_SAMSUNG_PANEL_IC_V_REGISTER_ON); + } + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_IC_V].count; + + if (!count){ + DSI_ERR("This panel does not read SET_PANEL_IC_V register\n"); + } else { + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_IC_V].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds->msg.rx_buf = &panel_ic_v; + cmds->msg.rx_len = 1; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + panel->panel_ic_v = panel_ic_v & 0x0f; + DSI_ERR("rx panel_ic_v = %d\n", panel->panel_ic_v); + rc = dsi_panel_tx_cmd_set_op(panel, DSI_CMD_READ_SAMSUNG_PANEL_IC_V_REGISTER_OFF); + flags = 0; + } + } + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) { + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ON].count; + if (!count) { + DSI_ERR("This panel does not read ddic_check register\n"); + } else { + + rc = dsi_panel_tx_cmd_set_op(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_ON); + } + + cmds1 = mode->priv_info->cmd_sets[DSI_CMD_SET_DDIC_CHECK_INFO].cmds; + count = mode->priv_info->cmd_sets[DSI_CMD_SET_DDIC_CHECK_INFO].count; + + if (!count) { + DSI_ERR("This panel does not read DDIC_CHECK register\n"); + } else { + if (cmds1->last_command) { + cmds1->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + cmds1->msg.rx_buf = register_d6; + cmds1->msg.rx_len = 10; + + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds1->msg, &flags); + } + + if (rc <= 0) + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + count = mode->priv_info->cmd_sets[DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF].count; + if (!count) { + DSI_ERR("This panel does not support ddic_check register reading\n"); + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_READ_SAMSUNG_PANEL_REGISTER_OFF); + } + memcpy(panel->buf_select, register_d6, 10); + panel->panel_tool = dsi_display_back_ToolsType_ANA6706(register_d6); + DSI_ERR("reg_D6: %02x %02x %02x %02x %02x %02x %02x\n" + ,register_d6[0],register_d6[1],register_d6[2],register_d6[3],register_d6[4],register_d6[5],register_d6[6]); + ddic_x = (((register_d6[3] & 0x1f) << 4) | ((register_d6[4] & 0xf0) >> 4)); + ddic_y = (register_d6[4] & 0x0f); + panel->ddic_x = ddic_x; + panel->ddic_y = ddic_y; + DSI_ERR("LCD X = %d, Y = %d D6[3] = %d D6[4] = %d \n", panel->ddic_x, panel->ddic_y, register_d6[3] , register_d6[4]); + flags = 0; + } + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) { + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LCDINFO_PRE); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_LCDINFO_PRE commands\n"); + goto error; + } + } + + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_SERIAL_NUMBER].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + cmds->msg.rx_buf = buf; + cmds->msg.rx_len = len; + + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) + DSI_ERR("Failed to get panel serial number, rc=%d\n", rc); + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) { + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_CODE_INFO].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + cmds->msg.rx_buf = &code_info; + cmds->msg.rx_len = 1; + + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) + DSI_ERR("Failed to get code info, rc=%d\n", rc); + + panel->panel_code_info = code_info & 0xff; + DSI_ERR("Code info is 0x%X\n", panel->panel_code_info); + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_STAGE_INFO].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + cmds->msg.rx_buf = &stage_info; + cmds->msg.rx_len = 1; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) + DSI_ERR("Failed to get stage info, rc=%d\n", rc); + + panel->panel_stage_info = stage_info & 0xff; + DSI_ERR("Stage info is 0x%X\n", panel->panel_stage_info); + + flags = 0; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PRODUCTION_INFO].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + cmds->msg.rx_buf = &prodution_info; + cmds->msg.rx_len = 1; + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + if (rc <= 0) + DSI_ERR("Failed to get production info, rc=%d\n", rc); + + panel->panel_production_info = prodution_info & 0xff; + DSI_ERR("Production info is 0x%X\n", panel->panel_production_info); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LCDINFO_POST); + if (rc) { + DSI_ERR("Failed to send DSI_CMD_SET_LCDINFO_POST commands\n"); + goto error; + } + } + + error: + dsi_panel_release_panel_lock(panel); + dsi_display_cmd_engine_disable(dsi_display); + DSI_ERR("%s end\n", __func__); + + return rc; +} + +int dsi_display_get_serial_number(struct drm_connector *connector) +{ + struct dsi_display_mode *mode; + struct dsi_panel *panel = NULL; + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + char buf[32]; + int panel_year = 0; + int panel_mon = 0; + int panel_day = 0; + int panel_hour = 0; + int panel_min = 0; + int panel_sec = 0; + int panel_msec = 0; + int panel_msec_int = 0; + int panel_msec_rem = 0; + int len = 0; + int count; + int rc = 0; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + mutex_lock(&dsi_display->display_lock); + + if (!dsi_panel_initialized(panel) || !panel->cur_mode) + goto error; + + mode = panel->cur_mode; + count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_SERIAL_NUMBER].count; + if (count) { + len = panel->panel_min_index; + if (len > sizeof(buf)) { + DSI_ERR("len is large than buf size!!!\n"); + goto error; + } + + if ((panel->panel_year_index > len) || (panel->panel_mon_index > len) + || (panel->panel_day_index > len) || (panel->panel_hour_index > len) + || (panel->panel_min_index > len)) { + DSI_ERR("Panel serial number index not corrected.\n"); + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + memset(buf, 0, sizeof(buf)); + dsi_display_read_serial_number(dsi_display, panel, buf, len); + memcpy(panel->buf_id, buf, 32); + panel_year = 2011 + ((buf[panel->panel_year_index - 1] >> 4) & 0x0f); + if (panel_year == 2011) + panel_year = 0; + panel_mon = buf[panel->panel_mon_index - 1] & 0x0f; + if ((panel_mon > 12) || (panel_mon < 1)) { + DSI_ERR("Panel Mon not corrected.\n"); + panel_mon = 0; + } + panel_day = buf[panel->panel_day_index - 1] & 0x3f; + if ((panel_day > 31) || (panel_day < 1)) { + DSI_ERR("Panel Day not corrected.\n"); + panel_day = 0; + } + panel_hour = buf[panel->panel_hour_index - 1] & 0x3f; + if ((panel_hour > 23) || (panel_hour < 0)) { + DSI_ERR("Panel Hour not corrected.\n"); + panel_hour = 0; + } + panel_min = buf[panel->panel_min_index - 1] & 0x3f; + if ((panel_min > 59) || (panel_min < 0)) { + DSI_ERR("Panel Min not corrected.\n"); + panel_min = 0; + } + panel_sec = buf[panel->panel_sec_index - 1] & 0x3f; + if ((panel_sec > 59) || (panel_sec < 0)) { + DSI_ERR("Panel sec not corrected.\n"); + panel_sec = 0; + } + panel_msec = ((buf[panel->panel_msec_high_index - 1]<<8) | buf[panel->panel_msec_low_index - 1]); + if ((panel_msec > 9999) || (panel_msec < 0)) { + DSI_ERR("Panel msec not corrected.\n"); + panel_sec = 0; + } + panel_msec_int = panel_msec/10; + panel_msec_rem = panel_msec%10; + DSI_ERR("panel_msec is %d , panel_msec_int is %d , panel_msec_rem is %d.\n", panel_msec, panel_msec_int, panel_msec_rem); + + panel->panel_year = panel_year; + panel->panel_mon = panel_mon; + panel->panel_day = panel_day; + panel->panel_hour = panel_hour; + panel->panel_min = panel_min; + panel->panel_sec = panel_sec; + panel->panel_msec = panel_msec; + panel->panel_msec_int = panel_msec_int; + panel->panel_msec_rem = panel_msec_rem; + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + } else { + DSI_ERR("This panel not support serial number.\n"); + } + +error: + mutex_unlock(&dsi_display->display_lock); + DSI_DEBUG("%s end\n", __func__); + return 0; +} +char* dsi_display_get_ic_reg_buf(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->buf_select; +} +int dsi_display_back_ToolsType_ANA6706(u8 *buff) +{ + int i; + int WaferNumber; + eTool typeTool; + char szLotID[6] = { 0 }; + unsigned char chipID1[6] = { 0 }; + + for(i = 1;i <= 5; i++) + chipID1[i-1] = buff[i-1]; + + // [6706] Chip IDLot IDWafer Number + extractLotID(chipID1, szLotID); + memcpy(buf_Lotid, szLotID, 6); + WaferNumber = extractWaferNumber(chipID1); + // LotID Wafer Number Tool Type + typeTool = discrimination_ANA6706_ToolsType(szLotID, WaferNumber); + + if (typeTool == ToolB) + DSI_ERR("Result: 6706 LotID: %s \tWaferNo: %d, Tool: Tool-B (%d)\n", szLotID, WaferNumber, typeTool); + else if (typeTool == ToolA) + DSI_ERR("Result: 6706 LotID: %s \tWaferNo: %d, Tool: Tool-A (%d)\n", szLotID, WaferNumber, typeTool); + else if (typeTool == ToolA_HVS30) + DSI_ERR("Result: 6706 LotID: %s \tWaferNo: %d, Tool: Tool-A HVS 3.0 (%d)\n", szLotID, WaferNumber, typeTool); + + for (i = 0; i < 18; i++) { + if((strcmp(szLotID, ANA6706_Green[i].LotID) == 0)){ + typeTool = Tool_Green; + DSI_ERR("Result: typeTool = %d \n",typeTool); + break; + } + + } + return typeTool; +} + +int dsi_display_get_ToolsType_ANA6706(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_tool; +} +int dsi_display_get_ddic_coords_X(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + DSI_DEBUG("%s start\n", __func__); + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + DSI_DEBUG("%s end\n", __func__); + return dsi_display->panel->ddic_x; +} +int dsi_display_get_ddic_coords_Y(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + DSI_DEBUG("%s start\n", __func__); + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + DSI_DEBUG("%s end\n", __func__); + return dsi_display->panel->ddic_y; +} +int dsi_display_get_ddic_check_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + int ddic_x = 0; + int panel_tool = 0; + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + ddic_x = dsi_display->panel->ddic_x; + panel_tool = dsi_display->panel->panel_tool; + + switch (dsi_display->panel->ddic_y) { + case 2: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 115) && (ddic_x < 186)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 3: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 56) && (ddic_x < 245)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 4: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 40) && (ddic_x < 261)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 5: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 33) && (ddic_x < 268)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 6: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 41) && (ddic_x < 261)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 7: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 57) && (ddic_x < 245)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + case 8: + if((strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) && + (ddic_x > 119) && (ddic_x < 183)) { + dsi_display->panel->ddic_check_info = 1; + } else + dsi_display->panel->ddic_check_info = 0; + break; + + default: + dsi_display->panel->ddic_check_info = 0; + break; + } + DSI_DEBUG("%s end\n", __func__); + if(panel_tool == 10) + dsi_display->panel->ddic_check_info = 0; + + return dsi_display->panel->ddic_check_info; +} + + +int dsi_display_get_serial_number_year(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_year; +} + +int dsi_display_get_serial_number_mon(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_mon; +} + +int dsi_display_get_serial_number_day(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_day; +} + +int dsi_display_get_serial_number_hour(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_hour; +} + +int dsi_display_get_serial_number_min(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_min; +} + +int dsi_display_get_serial_number_sec(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_sec; +} + +int dsi_display_get_serial_number_msec_int(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_msec_int; +} + +int dsi_display_get_serial_number_msec_rem(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_msec_rem; +} + +int dsi_display_get_code_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_code_info; +} + +int dsi_display_get_panel_ic_v_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_ic_v; +} + +int dsi_display_get_stage_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_stage_info; +} + +int dsi_display_get_production_info(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + DSI_DEBUG("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + DSI_DEBUG("%s end\n", __func__); + + return dsi_display->panel->panel_production_info; +} + +int dsi_display_get_serial_number_AT(struct drm_connector *connector) +{ + struct dsi_display_mode *mode; + struct dsi_panel *panel = NULL; + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + char buf[32]; + int panel_year = 0; + int panel_mon = 0; + int panel_day = 0; + int panel_hour = 0; + int panel_min = 0; + int panel_sec = 0; + int len = 0; + u32 count; + int rc = 0; + uint64_t serial_number; + DSI_ERR("%s start\n", __func__); + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + mutex_lock(&dsi_display->display_lock); + + if (!dsi_panel_initialized(panel) || !panel->cur_mode) { + goto error; + } + mode = panel->cur_mode; + count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_SERIAL_NUMBER].count; + + if (count) { + + len = panel->panel_min_index; + if (len > sizeof(buf)) { + DSI_ERR("len is large than buf size!!!\n" ); + goto error; + } + + if ((panel->panel_year_index > len) || (panel->panel_mon_index > len) + || (panel->panel_day_index > len) || (panel->panel_hour_index > len) + || (panel->panel_min_index > len)) { + DSI_ERR("Panel serial number index not corrected.\n"); + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + memset(buf, 0, sizeof(buf)); + dsi_display_read_serial_number(dsi_display, panel, buf, len); + memcpy(panel->buf_id, buf, 32); + + panel_year = 2011 + ((buf[panel->panel_year_index-1] >> 4) & 0x0f); + if (panel_year == 2011){ + panel_year = 0; + } + panel_mon = buf[panel->panel_mon_index-1] & 0x0f; + if ((panel_mon > 12) || (panel_mon < 1)){ + DSI_ERR("Panel Mon not corrected.\n"); + panel_mon = 0; + } + panel_day = buf[panel->panel_day_index-1] & 0x3f; + if ((panel_day > 31) || (panel_day < 1)){ + DSI_ERR("Panel Day not corrected.\n"); + panel_day = 0; + } + panel_hour = buf[panel->panel_hour_index-1] & 0x3f; + if ((panel_hour > 23) || (panel_hour < 0)){ + DSI_ERR("Panel Hour not corrected.\n"); + panel_hour = 0; + } + panel_min = buf[panel->panel_min_index-1] & 0x3f; + if ((panel_min > 59) || (panel_min < 0)){ + DSI_ERR("Panel Min not corrected.\n"); + panel_min = 0; + } + panel_sec = buf[panel->panel_sec_index-1] & 0x3f; + if ((panel_sec > 59) || (panel_sec < 0)){ + DSI_ERR("Panel sec not corrected.\n"); + panel_sec = 0; + } +/* + serial_number = ((uint64_t)panel_year << 56) + + ((uint64_t)panel_mon << 48) + + ((uint64_t)panel_day << 40) + + ((uint64_t)panel_hour << 32) + + ((uint64_t)panel_min << 24) + + ((uint64_t)panel_sec << 16) + + ((uint64_t)0 << 8) + + ((uint64_t)0); +*/ + serial_number = (uint64_t)panel_year * 10000000000 + (uint64_t)panel_mon * 100000000 + (uint64_t)panel_day * 1000000 + + (uint64_t)panel_hour * 10000 + (uint64_t)panel_min * 100 + (uint64_t)panel_sec; + + dsi_display_get_serial_number_id(serial_number); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + } else{ + DSI_ERR("This panel not support serial number.\n"); + } +error: + mutex_unlock(&dsi_display->display_lock); + DSI_ERR("%s END\n", __func__); + return 0; +} + +uint64_t dsi_display_get_serial_number_id(uint64_t serial_number) +{ + + static uint64_t serial_number_at; + + DSI_ERR("%s start\n",__func__); + if(0 == SERIAL_NUMBER_flag) + { + serial_number_at = serial_number; + if(0 == serial_number_at) + SERIAL_NUMBER_flag = 0; + else + SERIAL_NUMBER_flag = 1; + } + + return serial_number_at; +} +int dsi_display_set_seed_lp_mode(struct drm_connector *connector, int seed_lp_level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + panel->seed_lp_mode = seed_lp_level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + mutex_lock(&dsi_display->display_lock); + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_seed_lp_mode(panel, seed_lp_level); + if (rc) + DSI_ERR("unable to set seed lp mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} +int dsi_display_get_seed_lp_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->seed_lp_mode; +} +int dsi_display_set_hbm_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->hbm_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_hbm_mode(panel, level); + if (rc) + DSI_ERR("unable to set hbm mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_hbm_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->hbm_mode; +} + +int dsi_display_set_hbm_brightness(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + + + + mutex_lock(&dsi_display->display_lock); + + panel->hbm_brightness = level; + + if (!dsi_panel_initialized(panel)) + goto error; + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_hbm_brightness(panel, level); + if (rc) + DSI_ERR("Failed to set hbm brightness mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_hbm_brightness(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->hbm_brightness; +} + +extern int oneplus_force_screenfp; + +int dsi_display_set_fp_hbm_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->op_force_screenfp = level; + oneplus_force_screenfp=panel->op_force_screenfp; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_op_set_hbm_mode(panel, level); + if (rc) + DSI_ERR("unable to set hbm mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + + +int dsi_display_get_fp_hbm_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->op_force_screenfp; +} + +int dsi_display_set_dci_p3_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->dci_p3_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_dci_p3_mode(panel, level); + if (rc) + DSI_ERR("unable to set dci_p3 mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_dci_p3_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->dci_p3_mode; +} + +int dsi_display_set_night_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->night_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_night_mode(panel, level); + if (rc) + DSI_ERR("unable to set night mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_night_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->night_mode; +} +int dsi_display_set_native_display_p3_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->naive_display_p3_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_native_display_p3_mode(panel, level); + if (rc) + DSI_ERR("unable to set native display p3 mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_native_display_p3_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->naive_display_p3_mode; +} + +int dsi_display_set_native_display_wide_color_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->naive_display_wide_color_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_native_display_wide_color_mode(panel, level); + if (rc) + DSI_ERR("unable to set native display p3 mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_set_native_loading_effect_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->naive_display_loading_effect_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_native_loading_effect_mode(panel, level); + if (rc) + DSI_ERR("unable to set loading effect mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} +int dsi_display_set_customer_srgb_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->naive_display_customer_srgb_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_customer_srgb_mode(panel, level); + if (rc) + DSI_ERR("unable to set customer srgb mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_set_customer_p3_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->naive_display_customer_p3_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_customer_p3_mode(panel, level); + if (rc) + DSI_ERR("unable to set customer srgb mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} +int dsi_display_set_native_display_srgb_color_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + panel->naive_display_srgb_color_mode = level; + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_set_native_display_srgb_color_mode(panel, level); + if (rc) + DSI_ERR("unable to set native display p3 mode\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_native_display_srgb_color_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->naive_display_srgb_color_mode; +} + +int dsi_display_get_native_display_wide_color_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->naive_display_wide_color_mode; +} + +int dsi_display_get_native_display_loading_effect_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->naive_display_loading_effect_mode; +} +int dsi_display_get_customer_srgb_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->naive_display_customer_srgb_mode; +} +int dsi_display_get_customer_p3_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->naive_display_customer_p3_mode; +} + +int dsi_display_set_aod_mode(struct drm_connector *connector, int level) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + panel->aod_mode = level; + + mutex_lock(&dsi_display->display_lock); + if (!dsi_panel_initialized(panel)) { + goto error; + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + if ((dsi_display->panel->aod_mode != 5) && (dsi_display->panel->aod_mode != 4)) { + rc = dsi_panel_set_aod_mode(panel, level); + if (rc) + DSI_ERR("unable to set aod mode\n"); + } + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } +error: + mutex_unlock(&dsi_display->display_lock); + + return rc; +} + +int dsi_display_get_aod_mode(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->aod_mode; +} + +int dsi_display_set_aod_disable(struct drm_connector *connector, int disable) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + mutex_lock(&dsi_display->display_lock); + panel->aod_disable = disable; + mutex_unlock(&dsi_display->display_lock); + + return rc; +} + +int dsi_display_get_aod_disable(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->aod_disable; +} +int dsi_display_read_panel_id(struct dsi_display *dsi_display, + struct dsi_panel *panel, char* buf, int len) +{ + int rc = 0; + u32 flags = 0; + struct dsi_cmd_desc *cmds; + struct dsi_display_mode *mode; + struct dsi_display_ctrl *m_ctrl; + int retry_times; + + m_ctrl = &dsi_display->ctrl[dsi_display->cmd_master_idx]; + + if (!panel || !m_ctrl) + return -EINVAL; + + rc = dsi_display_cmd_engine_enable(dsi_display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EINVAL; + } + + dsi_panel_acquire_panel_lock(panel); + + mode = panel->cur_mode; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_ID].cmds;; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + + cmds->msg.rx_buf = buf; + cmds->msg.rx_len = len; + retry_times = 0; + do { + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + retry_times++; + } while ((rc <= 0) && (retry_times < 3)); + + if (rc <= 0) + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + + error: + dsi_panel_release_panel_lock(panel); + + dsi_display_cmd_engine_disable(dsi_display); + + return rc; +} + +char dsi_display_ascii_to_int(char ascii, int *ascii_err) +{ + char int_value; + + if ((ascii >= 48) && (ascii <= 57)){ + int_value = ascii - 48; + } + else if ((ascii >= 65) && (ascii <= 70)) { + int_value = ascii - 65 + 10; + } + else if ((ascii >= 97) && (ascii <= 102)) { + int_value = ascii - 97 + 10; + } + else { + int_value = 0; + *ascii_err = 1; + DSI_ERR("Bad para: %d , please enter the right value!", ascii); + } + + return int_value; +} + +int dsi_display_update_dsi_on_command(struct drm_connector *connector, const char *buf, size_t count) +{ + int i = 0; + int j = 0; + int ascii_err = 0; + unsigned int length; + char *data; + struct dsi_panel_cmd_set *set; + + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + mutex_lock(&dsi_display->display_lock); + + length = count / 3; + data = kzalloc(length + 1, GFP_KERNEL); + + for (i = 0; (buf[i+2] != 10) && (j < length); i = i+3) { + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + j++; + } + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + if (ascii_err == 1) { + DSI_ERR("Bad Para, ignore this command\n"); + goto error; + } + + set = &panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_ON]; + + rc = dsi_panel_update_cmd_sets_sub(set, DSI_CMD_SET_ON, data, length); + if (rc) + DSI_ERR("Failed to update_cmd_sets_sub, rc=%d\n", rc); + +error: + kfree(data); + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +static int dsi_display_get_mipi_dsi_msg(const struct mipi_dsi_msg *msg, char* buf) +{ + int len = 0; + size_t i; + char *tx_buf = (char*)msg->tx_buf; + /* Packet Info */ + len += snprintf(buf + len, PAGE_SIZE - len, "%02X ", msg->type); + /* Last bit */ + len += snprintf(buf + len, PAGE_SIZE - len, "%02X ", (msg->flags & MIPI_DSI_MSG_LASTCOMMAND) ? 1 : 0); + len += snprintf(buf + len, PAGE_SIZE - len, "%02X ", msg->channel); + len += snprintf(buf + len, PAGE_SIZE - len, "%02X ", (unsigned int)msg->flags); + /* Delay */ + len += snprintf(buf + len, PAGE_SIZE - len, "%02X ", msg->wait_ms); + len += snprintf(buf + len, PAGE_SIZE - len, "%02X %02X ", msg->tx_len >> 8, msg->tx_len & 0x00FF); + + /* Packet Payload */ + for (i = 0 ; i < msg->tx_len ; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, "%02X ", tx_buf[i]); + } + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + + return len; +} + +int dsi_display_get_dsi_on_command(struct drm_connector *connector, char *buf) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + struct dsi_panel_cmd_set *cmd; + int i = 0; + int count = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + cmd = &dsi_display->panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_ON]; + + for (i = 0; i < cmd->count; i++) { + count += dsi_display_get_mipi_dsi_msg(&cmd->cmds[i].msg, &buf[count]); + } + + return count; +} + +int dsi_display_update_dsi_panel_command(struct drm_connector *connector, const char *buf, size_t count) +{ + int i = 0; + int j = 0; + int ascii_err = 0; + unsigned int length; + char *data; + struct dsi_panel_cmd_set *set; + + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") != 0)) { + return 0; + } + + mutex_lock(&dsi_display->display_lock); + + if (!dsi_panel_initialized(panel)) + goto error; + + length = count / 3; + data = kzalloc(length + 1, GFP_KERNEL); + + for (i = 0; (buf[i+2] != 10) && (j < length); i = i+3) { + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + j++; + } + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + if (ascii_err == 1) { + DSI_ERR("Bad Para, ignore this command\n"); + kfree(data); + goto error; + } + + set = &panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND]; + + rc = dsi_panel_update_cmd_sets_sub(set, DSI_CMD_SET_PANEL_COMMAND, data, length); + if (rc) + DSI_ERR("Failed to update_cmd_sets_sub, rc=%d\n", rc); + kfree(data); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_send_dsi_panel_command(panel); + if (rc) + DSI_ERR("Failed to send dsi panel command\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_dsi_panel_command(struct drm_connector *connector, char *buf) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + struct dsi_panel_cmd_set *cmd; + int i = 0; + int count = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + cmd = &dsi_display->panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND]; + + for (i = 0; i < cmd->count; i++) + count += dsi_display_get_mipi_dsi_msg(&cmd->cmds[i].msg, &buf[count]); + + return count; +} + +int dsi_display_update_dsi_seed_command(struct drm_connector *connector, const char *buf, size_t count) +{ + int i = 0; + int j = 0; + int ascii_err = 0; + unsigned int length; + char *data; + struct dsi_panel_cmd_set *set; + + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") != 0)) { + + return 0; + } + + mutex_lock(&panel->panel_lock); + + if (!dsi_panel_initialized(panel)) + goto error; + + length = count / 3; + if (length != 0x16) { + DSI_ERR("Insufficient parameters!\n"); + goto error; + } + data = kzalloc(length + 1, GFP_KERNEL); + + for (i = 0; (buf[i+2] != 10) && (j < length); i = i+3) { + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + j++; + } + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + if (ascii_err == 1) { + DSI_ERR("Bad Para, ignore this command\n"); + kfree(data); + goto error; + } + + set = &panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_COMMAND]; + + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) || + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0)) + data[0] = UG_SEED_REGISTER; + + rc = dsi_panel_update_dsi_seed_command(set->cmds, DSI_CMD_SET_SEED_COMMAND, data); + if (rc) + DSI_ERR("Failed to dsi_panel_update_dsi_seed_command, rc=%d\n", rc); + kfree(data); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_panel_send_dsi_seed_command(panel); + if (rc) + DSI_ERR("Failed to send dsi seed command\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_display_get_dsi_seed_command(struct drm_connector *connector, char *buf) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + struct dsi_panel_cmd_set *cmd; + int i = 0; + int count = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + if ((strcmp(dsi_display->panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(dsi_display->panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") != 0)) { + + return 0; + } + + cmd = &dsi_display->panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_COMMAND]; + + for (i = 0; i < cmd->count; i++) { + count += dsi_display_get_mipi_dsi_msg(&cmd->cmds[i].msg, &buf[count]); + } + + return count; +} + +int dsi_display_get_reg_value(struct dsi_display *dsi_display, struct dsi_panel *panel) +{ + int rc = 0; + int flags = 0; + int i = 0; + int retry_times = 0; + int count = 0; + struct dsi_cmd_desc *cmds; + struct dsi_display_mode *mode; + struct dsi_display_ctrl *m_ctrl; + + DSI_ERR("start\n"); + + m_ctrl = &dsi_display->ctrl[dsi_display->cmd_master_idx]; + if (!panel || !m_ctrl) + return -EINVAL; + + rc = dsi_display_cmd_engine_enable(dsi_display); + if (rc) { + DSI_ERR("cmd engine enable failed\n"); + return -EINVAL; + } + + dsi_panel_acquire_panel_lock(panel); + mode = panel->cur_mode; + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_LEVEL2_KEY_ENABLE].count; + if (!count) { + DSI_ERR("This panel does not support level2 key enable command\n"); + } else { + dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LEVEL2_KEY_ENABLE); + } + + + { + + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND].cmds; + if (cmds->last_command) { + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + flags |= DSI_CTRL_CMD_LAST_COMMAND; + } + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + if (!m_ctrl->ctrl->vaddr) + goto error; + cmds->msg.rx_buf = reg_read_value; + cmds->msg.rx_len = reg_read_len; + do { + rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmds->msg, &flags); + retry_times++; + } while ((rc <= 0) && (retry_times < 3)); + if (rc <= 0) { + DSI_ERR("rx cmd transfer failed rc=%d\n", rc); + goto error; + } + } + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_LEVEL2_KEY_DISABLE].count; + if (!count) { + DSI_ERR("This panel does not support level2 key disable command\n"); + } else { + dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LEVEL2_KEY_DISABLE); + } + + for (i = 0; i < reg_read_len; i++) + DSI_ERR("reg_read_value[%d] = %d\n", i, reg_read_value[i]); + +error: + dsi_panel_release_panel_lock(panel); + dsi_display_cmd_engine_disable(dsi_display); + DSI_ERR("end\n", __func__); + return rc; +} + +int dsi_display_reg_read(struct drm_connector *connector, const char *buf, size_t count) +{ + int i = 0; + int j = 0; + int ascii_err = 0; + unsigned int length; + char *data; + struct dsi_panel_cmd_set *set; + + struct dsi_display *dsi_display = NULL; + struct dsi_panel *panel = NULL; + struct dsi_bridge *c_bridge; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return -EINVAL; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + + if ((strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") != 0) && + (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") != 0)) { + + return 0; + } + + mutex_lock(&dsi_display->display_lock); + + if (!dsi_panel_initialized(panel)) + goto error; + + length = count / 3; + data = kzalloc(length + 1, GFP_KERNEL); + + for (i = 0; (buf[i+2] != 10) && (j < length); i = i+3) { + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + j++; + } + data[j] = dsi_display_ascii_to_int(buf[i], &ascii_err) << 4; + data[j] += dsi_display_ascii_to_int(buf[i+1], &ascii_err); + if (ascii_err == 1) { + DSI_ERR("Bad Para, ignore this command\n"); + kfree(data); + goto error; + } + + set = &panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND]; + + rc = dsi_panel_update_cmd_sets_sub(set, DSI_CMD_SET_PANEL_COMMAND, data, length); + if (rc) + DSI_ERR("Failed to update_cmd_sets_sub, rc=%d\n", rc); + kfree(data); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + rc = dsi_display_get_reg_value(dsi_display, panel); + if (rc <= 0) + DSI_ERR("Failed to get reg value\n"); + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to disable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + +error: + mutex_unlock(&dsi_display->display_lock); + return rc; +} + +int dsi_display_get_reg_read_command_and_value(struct drm_connector *connector, char *buf) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + struct dsi_panel_cmd_set *cmd; + int i = 0; + int count = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + cmd = &dsi_display->panel->cur_mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND]; + + for (i = 0; i < cmd->count; i++) + count += dsi_display_get_mipi_dsi_msg(&cmd->cmds[i].msg, &buf[count]); + + count += snprintf(&buf[count], PAGE_SIZE - count, "Reg value:"); + for (i = 0; i < reg_read_len; i++) + count += snprintf(&buf[count], PAGE_SIZE - count, "%02X ", reg_read_value[i]); + count += snprintf(&buf[count], PAGE_SIZE - count, "\n"); + + return count; +} + +int dsi_display_panel_mismatch_check(struct drm_connector *connector) +{ + struct dsi_display_mode *mode; + struct dsi_panel *panel = NULL; + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + char buf[32]; + int panel_id; + u32 count; + int rc = 0; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + + panel = dsi_display->panel; + mutex_lock(&dsi_display->display_lock); + + if (!dsi_panel_initialized(panel) || !panel->cur_mode) { + panel->panel_mismatch = 0; + goto error; + } + + if (!panel->panel_mismatch_check) { + panel->panel_mismatch = 0; + DSI_ERR("This hw not support panel mismatch check(dvt-mp)\n"); + goto error; + } + + mode = panel->cur_mode; + count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_ID].count; + if (count) { + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_ON); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + + memset(buf, 0, sizeof(buf)); + dsi_display_read_panel_id(dsi_display, panel, buf, 1); + + panel_id = buf[0]; + panel->panel_mismatch = (panel_id == 0x03)? 1 : 0; + + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, + DSI_ALL_CLKS, DSI_CLK_OFF); + if (rc) { + DSI_ERR("[%s] failed to enable DSI clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + } else{ + panel->panel_mismatch = 0; + DSI_ERR("This panel not support panel mismatch check.\n"); + } +error: + mutex_unlock(&dsi_display->display_lock); + return 0; +} + +int dsi_display_panel_mismatch(struct drm_connector *connector) +{ + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return 0; + + return dsi_display->panel->panel_mismatch; +} +//*vikas.kala add for support aod,hbm,seed*/ +struct dsi_display *get_main_display(void) { + return primary_display; +} +EXPORT_SYMBOL(get_main_display); + +static int __init dsi_display_register(void) +{ + dsi_phy_drv_register(); + dsi_ctrl_drv_register(); + + dsi_display_parse_boot_display_selection(); + + return platform_driver_register(&dsi_display_driver); +} + +static void __exit dsi_display_unregister(void) +{ + platform_driver_unregister(&dsi_display_driver); + dsi_ctrl_drv_unregister(); + dsi_phy_drv_unregister(); +} +module_param_string(dsi_display0, dsi_display_primary, MAX_CMDLINE_PARAM_LEN, + 0600); +MODULE_PARM_DESC(dsi_display0, + "msm_drm.dsi_display0=<display node>:<configX> where <display node> is 'primary dsi display node name' and <configX> where x represents index in the topology list"); +module_param_string(dsi_display1, dsi_display_secondary, MAX_CMDLINE_PARAM_LEN, + 0600); +MODULE_PARM_DESC(dsi_display1, + "msm_drm.dsi_display1=<display node>:<configX> where <display node> is 'secondary dsi display node name' and <configX> where x represents index in the topology list"); +module_init(dsi_display_register); +module_exit(dsi_display_unregister); diff --git a/techpack/display/msm/dsi/dsi_display.h b/techpack/display/msm/dsi/dsi_display.h new file mode 100644 index 0000000000000000000000000000000000000000..bf5e05181b8e4dc1f0c32ff0b4ee9dc1750ee4aa --- /dev/null +++ b/techpack/display/msm/dsi/dsi_display.h @@ -0,0 +1,745 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_DISPLAY_H_ +#define _DSI_DISPLAY_H_ + +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/debugfs.h> +#include <linux/of_device.h> +#include <linux/firmware.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> + +#include "msm_drv.h" +#include "dsi_defs.h" +#include "dsi_ctrl.h" +#include "dsi_phy.h" +#include "dsi_panel.h" + +#define MAX_DSI_CTRLS_PER_DISPLAY 2 +#define DSI_CLIENT_NAME_SIZE 20 +#define MAX_CMDLINE_PARAM_LEN 512 +#define MAX_CMD_PAYLOAD_SIZE 256 +/* + * DSI Validate Mode modifiers + * @DSI_VALIDATE_FLAG_ALLOW_ADJUST: Allow mode validation to also do fixup + */ +#define DSI_VALIDATE_FLAG_ALLOW_ADJUST 0x1 + +/** + * enum dsi_display_selection_type - enumerates DSI display selection types + * @DSI_PRIMARY: primary DSI display selected from module parameter + * @DSI_SECONDARY: Secondary DSI display selected from module parameter + * @MAX_DSI_ACTIVE_DISPLAY: Maximum acive displays that can be selected + */ +enum dsi_display_selection_type { + DSI_PRIMARY = 0, + DSI_SECONDARY, + MAX_DSI_ACTIVE_DISPLAY, +}; + +/** + * enum dsi_display_type - enumerates DSI display types + * @DSI_DISPLAY_SINGLE: A panel connected on a single DSI interface. + * @DSI_DISPLAY_EXT_BRIDGE: A bridge is connected between panel and DSI host. + * It utilizes a single DSI interface. + * @DSI_DISPLAY_SPLIT: A panel that utilizes more than one DSI + * interfaces. + * @DSI_DISPLAY_SPLIT_EXT_BRIDGE: A bridge is present between panel and DSI + * host. It utilizes more than one DSI interface. + */ +enum dsi_display_type { + DSI_DISPLAY_SINGLE = 0, + DSI_DISPLAY_EXT_BRIDGE, + DSI_DISPLAY_SPLIT, + DSI_DISPLAY_SPLIT_EXT_BRIDGE, + DSI_DISPLAY_MAX, +}; + +/** + * struct dsi_display_ctrl - dsi ctrl/phy information for the display + * @ctrl: Handle to the DSI controller device. + * @ctrl_of_node: pHandle to the DSI controller device. + * @dsi_ctrl_idx: DSI controller instance id. + * @power_state: Current power state of the DSI controller. + * @phy: Handle to the DSI PHY device. + * @phy_of_node: pHandle to the DSI PHY device. + * @phy_enabled: PHY power status. + */ +struct dsi_display_ctrl { + /* controller info */ + struct dsi_ctrl *ctrl; + struct device_node *ctrl_of_node; + u32 dsi_ctrl_idx; + + enum dsi_power_state power_state; + + /* phy info */ + struct msm_dsi_phy *phy; + struct device_node *phy_of_node; + + bool phy_enabled; +}; +/** + * struct dsi_display_boot_param - defines DSI boot display selection + * @name:Name of DSI display selected as a boot param. + * @boot_disp_en:bool to indicate dtsi availability of display node + * @is_primary:bool to indicate whether current display is primary display + * @length:length of DSI display. + * @cmdline_topology: Display topology shared from kernel command line. + */ +struct dsi_display_boot_param { + char name[MAX_CMDLINE_PARAM_LEN]; + char *boot_param; + bool boot_disp_en; + int length; + struct device_node *node; + int cmdline_topology; + void *disp; +}; + +/** + * struct dsi_display_clk_info - dsi display clock source information + * @src_clks: Source clocks for DSI display. + * @mux_clks: Mux clocks used for DFPS. + * @shadow_clks: Used for D-phy clock switch. + * @shadow_cphy_clks: Used for C-phy clock switch. + */ +struct dsi_display_clk_info { + struct dsi_clk_link_set src_clks; + struct dsi_clk_link_set mux_clks; + struct dsi_clk_link_set cphy_clks; + struct dsi_clk_link_set shadow_clks; + struct dsi_clk_link_set shadow_cphy_clks; +}; + +/** + * struct dsi_display_ext_bridge - dsi display external bridge information + * @display: Pointer of DSI display. + * @node_of: Bridge node created from bridge driver. + * @bridge: Bridge created from bridge driver + * @orig_funcs: Bridge function from bridge driver (split mode only) + * @bridge_funcs: Overridden function from bridge driver (split mode only) + */ +struct dsi_display_ext_bridge { + void *display; + struct device_node *node_of; + struct drm_bridge *bridge; + const struct drm_bridge_funcs *orig_funcs; + struct drm_bridge_funcs bridge_funcs; +}; + +/** + * struct dsi_display - dsi display information + * @pdev: Pointer to platform device. + * @drm_dev: DRM device associated with the display. + * @drm_conn: Pointer to DRM connector associated with the display + * @ext_conn: Pointer to external connector attached to DSI connector + * @name: Name of the display. + * @display_type: Display type as defined in device tree. + * @list: List pointer. + * @is_active: Is display active. + * @is_cont_splash_enabled: Is continuous splash enabled + * @sw_te_using_wd: Is software te enabled + * @display_lock: Mutex for dsi_display interface. + * @disp_te_gpio: GPIO for panel TE interrupt. + * @is_te_irq_enabled:bool to specify whether TE interrupt is enabled. + * @esd_te_gate: completion gate to signal TE interrupt. + * @ctrl_count: Number of DSI interfaces required by panel. + * @ctrl: Controller information for DSI display. + * @panel: Handle to DSI panel. + * @panel_node: pHandle to DSI panel actually in use. + * @ext_bridge: External bridge information for DSI display. + * @ext_bridge_cnt: Number of external bridges + * @modes: Array of probed DSI modes + * @type: DSI display type. + * @clk_master_idx: The master controller for controlling clocks. This is an + * index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array. + * @cmd_master_idx: The master controller for sending DSI commands to panel. + * @video_master_idx: The master controller for enabling video engine. + * @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs. + * @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling. + * @clock_info: Clock sourcing for DSI display. + * @config: DSI host configuration information. + * @lane_map: Lane mapping between DSI host and Panel. + * @cmdline_topology: Display topology shared from kernel command line. + * @cmdline_timing: Display timing shared from kernel command line. + * @is_tpg_enabled: TPG state. + * @poms_pending; Flag indicating the pending panel operating mode switch. + * @ulps_enabled: ulps state. + * @clamp_enabled: clamp state. + * @phy_idle_power_off: PHY power state. + * @host: DRM MIPI DSI Host. + * @bridge: Pointer to DRM bridge object. + * @cmd_engine_refcount: Reference count enforcing single instance of cmd eng + * @clk_mngr: DSI clock manager. + * @dsi_clk_handle: DSI clock handle. + * @mdp_clk_handle: MDP clock handle. + * @root: Debugfs root directory + * @misr_enable Frame MISR enable/disable + * @misr_frame_count Number of frames to accumulate the MISR value + * @esd_trigger field indicating ESD trigger through debugfs + * @te_source vsync source pin information + * @clk_gating_config Clocks for which clock gating needs to be enabled + * @queue_cmd_waits Indicates if wait for dma commands done has to be queued. + * @dma_cmd_workq: Pointer to the workqueue of DMA command transfer done + * wait sequence. + */ +struct dsi_display { + struct platform_device *pdev; + struct drm_device *drm_dev; + struct drm_connector *drm_conn; + struct drm_connector *ext_conn; + + const char *name; + const char *display_type; + struct list_head list; + bool is_cont_splash_enabled; + bool sw_te_using_wd; + struct mutex display_lock; + int disp_te_gpio; + bool is_te_irq_enabled; + struct completion esd_te_gate; + + u32 ctrl_count; + struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY]; + + /* panel info */ + struct dsi_panel *panel; + struct device_node *panel_node; + struct device_node *parser_node; + + /* external bridge */ + struct dsi_display_ext_bridge ext_bridge[MAX_DSI_CTRLS_PER_DISPLAY]; + u32 ext_bridge_cnt; + + struct dsi_display_mode *modes; + + enum dsi_display_type type; + u32 clk_master_idx; + u32 cmd_master_idx; + u32 video_master_idx; + + /* dynamic DSI clock info*/ + u32 cached_clk_rate; + atomic_t clkrate_change_pending; + + struct dsi_display_clk_info clock_info; + struct dsi_host_config config; + struct dsi_lane_map lane_map; + int cmdline_topology; + int cmdline_timing; + bool is_tpg_enabled; + bool poms_pending; + bool ulps_enabled; + bool clamp_enabled; + bool phy_idle_power_off; + struct drm_gem_object *tx_cmd_buf; + u32 cmd_buffer_size; + u64 cmd_buffer_iova; + void *vaddr; + struct msm_gem_address_space *aspace; + + struct mipi_dsi_host host; + struct dsi_bridge *bridge; + u32 cmd_engine_refcount; + + void *clk_mngr; + void *dsi_clk_handle; + void *mdp_clk_handle; + + /* DEBUG FS */ + struct dentry *root; + + bool misr_enable; + u32 misr_frame_count; + u32 esd_trigger; + /* multiple dsi error handlers */ + struct workqueue_struct *err_workq; + struct work_struct fifo_underflow_work; + struct work_struct fifo_overflow_work; + struct work_struct lp_rx_timeout_work; + + /* firmware panel data */ + const struct firmware *fw; + void *parser; + + struct dsi_display_boot_param *boot_disp; + + u32 te_source; + u32 clk_gating_config; + bool queue_cmd_waits; + struct workqueue_struct *dma_cmd_workq; +}; + +int dsi_display_dev_probe(struct platform_device *pdev); +int dsi_display_dev_remove(struct platform_device *pdev); + +/** + * dsi_display_get_num_of_displays() - returns number of display devices + * supported. + * + * Return: number of displays. + */ +int dsi_display_get_num_of_displays(void); + +/** + * dsi_display_get_active_displays - returns pointers for active display devices + * @display_array: Pointer to display array to be filled + * @max_display_count: Size of display_array + * @Returns: Number of display entries filled + */ +int dsi_display_get_active_displays(void **display_array, + u32 max_display_count); + +/** + * dsi_display_get_display_by_name()- finds display by name + * @name: name of the display. + * + * Return: handle to the display or error code. + */ +struct dsi_display *dsi_display_get_display_by_name(const char *name); + +/** + * dsi_display_set_active_state() - sets the state of the display + * @display: Handle to display. + * @is_active: state + */ +void dsi_display_set_active_state(struct dsi_display *display, bool is_active); + +/** + * dsi_display_drm_bridge_init() - initializes DRM bridge object for DSI + * @display: Handle to the display. + * @encoder: Pointer to the encoder object which is connected to the + * display. + * + * Return: error code. + */ +int dsi_display_drm_bridge_init(struct dsi_display *display, + struct drm_encoder *enc); + +/** + * dsi_display_drm_bridge_deinit() - destroys DRM bridge for the display + * @display: Handle to the display. + * + * Return: error code. + */ +int dsi_display_drm_bridge_deinit(struct dsi_display *display); + +/** + * dsi_display_drm_ext_bridge_init() - initializes DRM bridge for ext bridge + * @display: Handle to the display. + * @enc: Pointer to the encoder object which is connected to the + * display. + * @connector: Pointer to the connector object which is connected to + * the display. + * + * Return: error code. + */ +int dsi_display_drm_ext_bridge_init(struct dsi_display *display, + struct drm_encoder *enc, struct drm_connector *connector); + +/** + * dsi_display_get_info() - returns the display properties + * @connector: Pointer to drm connector structure + * @info: Pointer to the structure where info is stored. + * @disp: Handle to the display. + * + * Return: error code. + */ +int dsi_display_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *disp); + +/** + * dsi_display_get_mode_count() - get number of modes supported by the display + * @display: Handle to display. + * @count: Number of modes supported + * + * Return: error code. + */ +int dsi_display_get_mode_count(struct dsi_display *display, u32 *count); + +/** + * dsi_display_get_modes() - get modes supported by display + * @display: Handle to display. + * @modes; Output param, list of DSI modes. Number of modes matches + * count got from display->panel->num_display_modes; + * + * Return: error code. + */ +int dsi_display_get_modes(struct dsi_display *display, + struct dsi_display_mode **modes); + +/** + * dsi_display_put_mode() - free up mode created for the display + * @display: Handle to display. + * @mode: Display mode to be freed up + * + * Return: error code. + */ +void dsi_display_put_mode(struct dsi_display *display, + struct dsi_display_mode *mode); + +/** + * dsi_display_get_default_lms() - retrieve max number of lms used + * for dsi display by traversing through all topologies + * @display: Handle to display. + * @num_lm: Number of LMs used + * + * Return: error code. + */ +int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm); + +/** + * dsi_display_find_mode() - retrieve cached DSI mode given relevant params + * @display: Handle to display. + * @cmp: Mode to use as comparison to find original + * @out_mode: Output parameter, pointer to retrieved mode + * + * Return: error code. + */ +int dsi_display_find_mode(struct dsi_display *display, + const struct dsi_display_mode *cmp, + struct dsi_display_mode **out_mode); +/** + * dsi_display_validate_mode() - validates if mode is supported by display + * @display: Handle to display. + * @mode: Mode to be validated. + * @flags: Modifier flags. + * + * Return: 0 if supported or error code. + */ +int dsi_display_validate_mode(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags); + +/** + * dsi_display_validate_mode_change() - validates mode if variable refresh case + * or dynamic clk change case + * @display: Handle to display. + * @mode: Mode to be validated.. + * + * Return: 0 if error code. + */ +int dsi_display_validate_mode_change(struct dsi_display *display, + struct dsi_display_mode *cur_dsi_mode, + struct dsi_display_mode *mode); + +/** + * dsi_display_set_mode() - Set mode on the display. + * @display: Handle to display. + * @mode: mode to be set. + * @flags: Modifier flags. + * + * Return: error code. + */ +int dsi_display_set_mode(struct dsi_display *display, + struct dsi_display_mode *mode, + u32 flags); + +/** + * dsi_display_prepare() - prepare display + * @display: Handle to display. + * + * Prepare will perform power up sequences for the host and panel hardware. + * Power and clock resources might be turned on (depending on the panel mode). + * The video engine is not enabled. + * + * Return: error code. + */ +int dsi_display_prepare(struct dsi_display *display); + +/** + * dsi_display_splash_res_cleanup() - cleanup for continuous splash + * @display: Pointer to dsi display + * Returns: Zero on success + */ +int dsi_display_splash_res_cleanup(struct dsi_display *display); + +/** + * dsi_display_config_ctrl_for_cont_splash()- Enable engine modes for DSI + * controller during continuous splash + * @display: Handle to DSI display + * + * Return: returns error code + */ +int dsi_display_config_ctrl_for_cont_splash(struct dsi_display *display); + +/** + * dsi_display_enable() - enable display + * @display: Handle to display. + * + * Enable will turn on the host engine and the panel. At the end of the enable + * function, Host and panel hardware are ready to accept pixel data from + * upstream. + * + * Return: error code. + */ +int dsi_display_enable(struct dsi_display *display); + +/** + * dsi_display_post_enable() - perform post enable operations. + * @display: Handle to display. + * + * Some panels might require some commands to be sent after pixel data + * transmission has started. Such commands are sent as part of the post_enable + * function. + * + * Return: error code. + */ +int dsi_display_post_enable(struct dsi_display *display); + +/** + * dsi_display_pre_disable() - perform pre disable operations. + * @display: Handle to display. + * + * If a panel requires commands to be sent before pixel data transmission is + * stopped, those can be sent as part of pre_disable. + * + * Return: error code. + */ +int dsi_display_pre_disable(struct dsi_display *display); + +/** + * dsi_display_disable() - disable panel and host hardware. + * @display: Handle to display. + * + * Disable host and panel hardware and pixel data transmission can not continue. + * + * Return: error code. + */ +int dsi_display_disable(struct dsi_display *display); + +/** + * dsi_pre_clkoff_cb() - Callback before clock is turned off + * @priv: private data pointer. + * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @new_state: next state for the clock. + * + * @return: error code. + */ +int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state); + +/** + * dsi_display_update_pps() - update PPS buffer. + * @pps_cmd: PPS buffer. + * @display: Handle to display. + * + * Copies new PPS buffer into display structure. + * + * Return: error code. + */ +int dsi_display_update_pps(char *pps_cmd, void *display); + +/** + * dsi_post_clkoff_cb() - Callback after clock is turned off + * @priv: private data pointer. + * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @curr_state: current state for the clock. + * + * @return: error code. + */ +int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state); + +/** + * dsi_post_clkon_cb() - Callback after clock is turned on + * @priv: private data pointer. + * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @curr_state: current state for the clock. + * + * @return: error code. + */ +int dsi_post_clkon_cb(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state); + +/** + * dsi_pre_clkon_cb() - Callback before clock is turned on + * @priv: private data pointer. + * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. + * @new_state: next state for the clock. + * + * @return: error code. + */ +int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state); + +/** + * dsi_display_unprepare() - power off display hardware. + * @display: Handle to display. + * + * Host and panel hardware is turned off. Panel will be in reset state at the + * end of the function. + * + * Return: error code. + */ +int dsi_display_unprepare(struct dsi_display *display); + +int dsi_display_set_tpg_state(struct dsi_display *display, bool enable); + +int dsi_display_clock_gate(struct dsi_display *display, bool enable); +int dsi_dispaly_static_frame(struct dsi_display *display, bool enable); +uint64_t dsi_display_get_serial_number_id(uint64_t serial_number); +int dsi_display_get_serial_number_AT(struct drm_connector *connector); + +/** + * dsi_display_get_drm_panel() - get drm_panel from display. + * @display: Handle to display. + * Get drm_panel which was inclued in dsi_display's dsi_panel. + * + * Return: drm_panel/NULL. + */ +struct drm_panel *dsi_display_get_drm_panel(struct dsi_display *display); + +/** + * dsi_display_enable_event() - enable interrupt based connector event + * @connector: Pointer to drm connector structure + * @display: Handle to display. + * @event_idx: Event index. + * @event_info: Event callback definition. + * @enable: Whether to enable/disable the event interrupt. + */ +void dsi_display_enable_event(struct drm_connector *connector, + struct dsi_display *display, + uint32_t event_idx, struct dsi_event_cb_info *event_info, + bool enable); + +/** + * dsi_display_set_backlight() - set backlight + * @connector: Pointer to drm connector structure + * @display: Handle to display. + * @bl_lvl: Backlight level. + * @event_info: Event callback definition. + * @enable: Whether to enable/disable the event interrupt. + */ +int dsi_display_set_backlight(struct drm_connector *connector, + void *display, u32 bl_lvl); + +/** + * dsi_display_check_status() - check if panel is dead or alive + * @connector: Pointer to drm connector structure + * @display: Handle to display. + * @te_check_override: Whether check for TE from panel or default check + */ +int dsi_display_check_status(struct drm_connector *connector, void *display, + bool te_check_override); + +/** + * dsi_display_cmd_transfer() - transfer command to the panel + * @connector: Pointer to drm connector structure + * @display: Handle to display. + * @cmd_buf: Command buffer + * @cmd_buf_len: Command buffer length in bytes + */ +int dsi_display_cmd_transfer(struct drm_connector *connector, + void *display, const char *cmd_buffer, + u32 cmd_buf_len); + +/** + * dsi_display_soft_reset() - perform a soft reset on DSI controller + * @display: Handle to display + * + * The video, command and controller engines will be disabled before the + * reset is triggered. After, the engines will be re-enabled to the same state + * as before the reset. + * + * If the reset is done while MDP timing engine is turned on, the video + * engine should be re-enabled only during the vertical blanking time. + * + * Return: error code + */ +int dsi_display_soft_reset(void *display); + +/** + * dsi_display_set_power - update power/dpms setting + * @connector: Pointer to drm connector structure + * @power_mode: One of the following, + * SDE_MODE_DPMS_ON + * SDE_MODE_DPMS_LP1 + * SDE_MODE_DPMS_LP2 + * SDE_MODE_DPMS_STANDBY + * SDE_MODE_DPMS_SUSPEND + * SDE_MODE_DPMS_OFF + * @display: Pointer to private display structure + * Returns: Zero on success + */ +int dsi_display_set_power(struct drm_connector *connector, + int power_mode, void *display); + +/* + * dsi_display_pre_kickoff - program kickoff-time features + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + * @params: Parameters for kickoff-time programming + * Returns: Zero on success + */ +int dsi_display_pre_kickoff(struct drm_connector *connector, + struct dsi_display *display, + struct msm_display_kickoff_params *params); + +/* + * dsi_display_pre_commit - program pre commit features + * @display: Pointer to private display structure + * @params: Parameters for pre commit time programming + * Returns: Zero on success + */ +int dsi_display_pre_commit(void *display, + struct msm_display_conn_params *params); + +/** + * dsi_display_get_dst_format() - get dst_format from DSI display + * @connector: Pointer to drm connector structure + * @display: Handle to display + * + * Return: enum dsi_pixel_format type + */ +enum dsi_pixel_format dsi_display_get_dst_format( + struct drm_connector *connector, + void *display); + +/** + * dsi_display_cont_splash_config() - initialize splash resources + * @display: Handle to display + * + * Return: Zero on Success + */ +int dsi_display_cont_splash_config(void *display); +/* + * dsi_display_get_panel_vfp - get panel vsync + * @display: Pointer to private display structure + * @h_active: width + * @v_active: height + * Returns: v_front_porch on success error code on failure + */ +int dsi_display_get_panel_vfp(void *display, + int h_active, int v_active); +extern struct drm_panel *lcd_active_panel; +extern int drm_panel_notifier_call_chain(struct drm_panel *panel, +unsigned long val, void *v); +#ifdef CONFIG_F2FS_OF2FS +extern int f2fs_panel_notifier_call_chain(unsigned long val, void *v); +#endif +int dsi_display_cmd_engine_enable(struct dsi_display *display); +int dsi_display_cmd_engine_disable(struct dsi_display *display); + +struct dsi_display *get_main_display(void); +extern char gamma_para[2][413]; +int dsi_display_get_sp_level(struct dsi_display *dsi_display, + struct dsi_panel *panel); +int dsi_display_sp_read(struct dsi_display *dsi_display); +void dsi_display_gamma_read_work(struct work_struct *work); +int dsi_display_back_ToolsType_ANA6706(u8 *buff); +#endif /* _DSI_DISPLAY_H_ */ diff --git a/techpack/display/msm/dsi/dsi_display_test.c b/techpack/display/msm/dsi/dsi_display_test.c new file mode 100644 index 0000000000000000000000000000000000000000..60f83958c89251057408ea1d51772d9137db86b6 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_display_test.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/slab.h> + +#include "dsi_display_test.h" + +static void dsi_display_test_dump_modes(struct dsi_display_mode *mode, u32 + count) +{ +} + +static void dsi_display_test_work(struct work_struct *work) +{ + struct dsi_display_test *test; + struct dsi_display *display; + struct dsi_display_mode *modes; + u32 count = 0; + int rc = 0; + + test = container_of(work, struct dsi_display_test, test_work); + + display = test->display; + rc = dsi_display_get_mode_count(display, &count); + if (rc) { + DSI_ERR("failed to get modes count, rc=%d\n", rc); + goto test_fail; + } + + rc = dsi_display_get_modes(display, &modes); + if (rc) { + DSI_ERR("failed to get modes, rc=%d\n", rc); + goto test_fail_free_modes; + } + + dsi_display_test_dump_modes(modes, count); + + rc = dsi_display_set_mode(display, &modes[0], 0x0); + if (rc) { + DSI_ERR("failed to set mode, rc=%d\n", rc); + goto test_fail_free_modes; + } + + rc = dsi_display_prepare(display); + if (rc) { + DSI_ERR("failed to prepare display, rc=%d\n", rc); + goto test_fail_free_modes; + } + + rc = dsi_display_enable(display); + if (rc) { + DSI_ERR("failed to enable display, rc=%d\n", rc); + goto test_fail_unprep_disp; + } + return; + +test_fail_unprep_disp: + if (rc) { + DSI_ERR("failed to unprep display, rc=%d\n", rc); + goto test_fail_free_modes; + } + +test_fail_free_modes: + kfree(modes); +test_fail: + return; +} + +int dsi_display_test_init(struct dsi_display *display) +{ + static int done; + int rc = 0; + struct dsi_display_test *test; + + if (done) + return rc; + + done = 1; + if (!display) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + test = kzalloc(sizeof(*test), GFP_KERNEL); + if (!test) + return -ENOMEM; + + test->display = display; + INIT_WORK(&test->test_work, dsi_display_test_work); + + dsi_display_test_work(&test->test_work); + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_display_test.h b/techpack/display/msm/dsi/dsi_display_test.h new file mode 100644 index 0000000000000000000000000000000000000000..b05270a27af13ac0d2574749b674a575af62f6a2 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_display_test.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_DISPLAY_TEST_H_ +#define _DSI_DISPLAY_TEST_H_ + +#include "dsi_display.h" +#include "dsi_ctrl_hw.h" +#include "dsi_ctrl.h" + +struct dsi_display_test { + struct dsi_display *display; + + struct work_struct test_work; +}; + +int dsi_display_test_init(struct dsi_display *display); + + +#endif /* _DSI_DISPLAY_TEST_H_ */ diff --git a/techpack/display/msm/dsi/dsi_drm.c b/techpack/display/msm/dsi/dsi_drm.c new file mode 100644 index 0000000000000000000000000000000000000000..c7002f58c410a0939d4e173761fbd4a1ef1b97be --- /dev/null +++ b/techpack/display/msm/dsi/dsi_drm.c @@ -0,0 +1,1070 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + + +#include <drm/drm_atomic_helper.h> +#include <drm/drm_atomic.h> + +#include "msm_kms.h" +#include "sde_connector.h" +#include "dsi_drm.h" +#include "sde_trace.h" +#include "sde_dbg.h" + +#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) +#define to_dsi_state(x) container_of((x), struct dsi_connector_state, base) + +#define DEFAULT_PANEL_JITTER_NUMERATOR 2 +#define DEFAULT_PANEL_JITTER_DENOMINATOR 1 +#define DEFAULT_PANEL_JITTER_ARRAY_SIZE 2 +#define DEFAULT_PANEL_PREFILL_LINES 25 + +static struct dsi_display_mode_priv_info default_priv_info = { + .panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR, + .panel_jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR, + .panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES, + .dsc_enabled = false, +}; + +static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, + struct dsi_display_mode *dsi_mode) +{ + memset(dsi_mode, 0, sizeof(*dsi_mode)); + + dsi_mode->timing.h_active = drm_mode->hdisplay; + dsi_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; + dsi_mode->timing.h_sync_width = drm_mode->htotal - + (drm_mode->hsync_start + dsi_mode->timing.h_back_porch); + dsi_mode->timing.h_front_porch = drm_mode->hsync_start - + drm_mode->hdisplay; + dsi_mode->timing.h_skew = drm_mode->hskew; + + dsi_mode->timing.v_active = drm_mode->vdisplay; + dsi_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; + dsi_mode->timing.v_sync_width = drm_mode->vtotal - + (drm_mode->vsync_start + dsi_mode->timing.v_back_porch); + + dsi_mode->timing.v_front_porch = drm_mode->vsync_start - + drm_mode->vdisplay; + + dsi_mode->timing.refresh_rate = drm_mode->vrefresh; + + dsi_mode->pixel_clk_khz = drm_mode->clock; + + dsi_mode->priv_info = + (struct dsi_display_mode_priv_info *)drm_mode->private; + + if (dsi_mode->priv_info) { + dsi_mode->timing.dsc_enabled = dsi_mode->priv_info->dsc_enabled; + dsi_mode->timing.dsc = &dsi_mode->priv_info->dsc; + } + + if (msm_is_mode_seamless(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS; + if (msm_is_mode_dynamic_fps(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS; + if (msm_needs_vblank_pre_modeset(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET; + if (msm_is_mode_seamless_dms(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS; + if (msm_is_mode_seamless_vrr(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; + if (msm_is_mode_seamless_poms(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS; + if (msm_is_mode_seamless_dyn_clk(drm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK; + + dsi_mode->timing.h_sync_polarity = + !!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC); + dsi_mode->timing.v_sync_polarity = + !!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC); + + if (drm_mode->flags & DRM_MODE_FLAG_VID_MODE_PANEL) + dsi_mode->panel_mode = DSI_OP_VIDEO_MODE; + if (drm_mode->flags & DRM_MODE_FLAG_CMD_MODE_PANEL) + dsi_mode->panel_mode = DSI_OP_CMD_MODE; +} + +void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, + struct drm_display_mode *drm_mode) +{ + bool video_mode = (dsi_mode->panel_mode == DSI_OP_VIDEO_MODE); + + memset(drm_mode, 0, sizeof(*drm_mode)); + + drm_mode->hdisplay = dsi_mode->timing.h_active; + drm_mode->hsync_start = drm_mode->hdisplay + + dsi_mode->timing.h_front_porch; + drm_mode->hsync_end = drm_mode->hsync_start + + dsi_mode->timing.h_sync_width; + drm_mode->htotal = drm_mode->hsync_end + dsi_mode->timing.h_back_porch; + drm_mode->hskew = dsi_mode->timing.h_skew; + + drm_mode->vdisplay = dsi_mode->timing.v_active; + drm_mode->vsync_start = drm_mode->vdisplay + + dsi_mode->timing.v_front_porch; + drm_mode->vsync_end = drm_mode->vsync_start + + dsi_mode->timing.v_sync_width; + drm_mode->vtotal = drm_mode->vsync_end + dsi_mode->timing.v_back_porch; + + drm_mode->vrefresh = dsi_mode->timing.refresh_rate; + drm_mode->clock = dsi_mode->pixel_clk_khz; + + drm_mode->private = (int *)dsi_mode->priv_info; + + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) + drm_mode->flags |= DRM_MODE_FLAG_SEAMLESS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VBLANK_PRE_MODESET) + drm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) + drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK; + + if (dsi_mode->timing.h_sync_polarity) + drm_mode->flags |= DRM_MODE_FLAG_PHSYNC; + if (dsi_mode->timing.v_sync_polarity) + drm_mode->flags |= DRM_MODE_FLAG_PVSYNC; + + if (dsi_mode->panel_mode == DSI_OP_VIDEO_MODE) + drm_mode->flags |= DRM_MODE_FLAG_VID_MODE_PANEL; + if (dsi_mode->panel_mode == DSI_OP_CMD_MODE) + drm_mode->flags |= DRM_MODE_FLAG_CMD_MODE_PANEL; + + /* set mode name */ + snprintf(drm_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%dx%dx%d%s", + drm_mode->hdisplay, drm_mode->vdisplay, + drm_mode->vrefresh, drm_mode->clock, + video_mode ? "vid" : "cmd"); +} + +static int dsi_bridge_attach(struct drm_bridge *bridge) +{ + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + + if (!bridge) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + DSI_DEBUG("[%d] attached\n", c_bridge->id); + + return 0; + +} + +static void dsi_bridge_pre_enable(struct drm_bridge *bridge) +{ + int rc = 0; + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + + if (!bridge) { + DSI_ERR("Invalid params\n"); + return; + } + + if (!c_bridge || !c_bridge->display || !c_bridge->display->panel) { + DSI_ERR("Incorrect bridge details\n"); + return; + } + + atomic_set(&c_bridge->display->panel->esd_recovery_pending, 0); + + /* By this point mode should have been validated through mode_fixup */ + rc = dsi_display_set_mode(c_bridge->display, + &(c_bridge->dsi_mode), 0x0); + if (rc) { + DSI_ERR("[%d] failed to perform a mode set, rc=%d\n", + c_bridge->id, rc); + return; + } + + if (c_bridge->dsi_mode.dsi_mode_flags & + (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR | + DSI_MODE_FLAG_DYN_CLK)) { + DSI_DEBUG("[%d] seamless pre-enable\n", c_bridge->id); + return; + } + + SDE_ATRACE_BEGIN("dsi_display_prepare"); + rc = dsi_display_prepare(c_bridge->display); + if (rc) { + DSI_ERR("[%d] DSI display prepare failed, rc=%d\n", + c_bridge->id, rc); + SDE_ATRACE_END("dsi_display_prepare"); + return; + } + SDE_ATRACE_END("dsi_display_prepare"); + + SDE_ATRACE_BEGIN("dsi_display_enable"); + rc = dsi_display_enable(c_bridge->display); + if (rc) { + DSI_ERR("[%d] DSI display enable failed, rc=%d\n", + c_bridge->id, rc); + (void)dsi_display_unprepare(c_bridge->display); + } + SDE_ATRACE_END("dsi_display_enable"); + + rc = dsi_display_splash_res_cleanup(c_bridge->display); + if (rc) + DSI_ERR("Continuous splash pipeline cleanup failed, rc=%d\n", + rc); +} + +static void dsi_bridge_enable(struct drm_bridge *bridge) +{ + int rc = 0; + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + struct dsi_display *display; + + if (!bridge) { + DSI_ERR("Invalid params\n"); + return; + } + + if (c_bridge->dsi_mode.dsi_mode_flags & + (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR | + DSI_MODE_FLAG_DYN_CLK)) { + DSI_DEBUG("[%d] seamless enable\n", c_bridge->id); + return; + } + display = c_bridge->display; + + rc = dsi_display_post_enable(display); + if (rc) + DSI_ERR("[%d] DSI display post enabled failed, rc=%d\n", + c_bridge->id, rc); + + if (display && display->drm_conn) { + sde_connector_helper_bridge_enable(display->drm_conn); + if (c_bridge->dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS) + sde_connector_schedule_status_work(display->drm_conn, + true); + } +} + +static void dsi_bridge_disable(struct drm_bridge *bridge) +{ + int rc = 0; + int private_flags; + struct dsi_display *display; + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + + if (!bridge) { + DSI_ERR("Invalid params\n"); + return; + } + display = c_bridge->display; + private_flags = + bridge->encoder->crtc->state->adjusted_mode.private_flags; + + if (display && display->drm_conn) { + display->poms_pending = + private_flags & MSM_MODE_FLAG_SEAMLESS_POMS; + + sde_connector_helper_bridge_disable(display->drm_conn); + } + + rc = dsi_display_pre_disable(c_bridge->display); + if (rc) { + DSI_ERR("[%d] DSI display pre disable failed, rc=%d\n", + c_bridge->id, rc); + } +} + +static void dsi_bridge_post_disable(struct drm_bridge *bridge) +{ + int rc = 0; + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + + if (!bridge) { + DSI_ERR("Invalid params\n"); + return; + } + + SDE_ATRACE_BEGIN("dsi_bridge_post_disable"); + SDE_ATRACE_BEGIN("dsi_display_disable"); + rc = dsi_display_disable(c_bridge->display); + if (rc) { + DSI_ERR("[%d] DSI display disable failed, rc=%d\n", + c_bridge->id, rc); + SDE_ATRACE_END("dsi_display_disable"); + return; + } + SDE_ATRACE_END("dsi_display_disable"); + + rc = dsi_display_unprepare(c_bridge->display); + if (rc) { + DSI_ERR("[%d] DSI display unprepare failed, rc=%d\n", + c_bridge->id, rc); + SDE_ATRACE_END("dsi_bridge_post_disable"); + return; + } + SDE_ATRACE_END("dsi_bridge_post_disable"); +} + +static void dsi_bridge_mode_set(struct drm_bridge *bridge, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + + if (!bridge || !mode || !adjusted_mode) { + DSI_ERR("Invalid params\n"); + return; + } + + memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode)); + convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode)); + + /* restore bit_clk_rate also for dynamic clk use cases */ + c_bridge->dsi_mode.timing.clk_rate_hz = + dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode); + + DSI_DEBUG("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz); +} + +static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + int rc = 0; + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + struct dsi_display *display; + struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode; + struct drm_crtc_state *crtc_state; + + crtc_state = container_of(mode, struct drm_crtc_state, mode); + + if (!bridge || !mode || !adjusted_mode) { + DSI_ERR("Invalid params\n"); + return false; + } + + display = c_bridge->display; + if (!display) { + DSI_ERR("Invalid params\n"); + return false; + } + + /* + * if no timing defined in panel, it must be external mode + * and we'll use empty priv info to populate the mode + */ + if (display->panel && !display->panel->num_timing_nodes) { + *adjusted_mode = *mode; + adjusted_mode->private = (int *)&default_priv_info; + adjusted_mode->private_flags = 0; + return true; + } + + convert_to_dsi_mode(mode, &dsi_mode); + + /* + * retrieve dsi mode from dsi driver's cache since not safe to take + * the drm mode config mutex in all paths + */ + rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode); + if (rc) + return rc; + + /* propagate the private info to the adjusted_mode derived dsi mode */ + dsi_mode.priv_info = panel_dsi_mode->priv_info; + dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags; + dsi_mode.timing.dsc_enabled = dsi_mode.priv_info->dsc_enabled; + dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc; + + rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode, + DSI_VALIDATE_FLAG_ALLOW_ADJUST); + if (rc) { + DSI_ERR("[%d] mode is not valid, rc=%d\n", c_bridge->id, rc); + return false; + } + + if (bridge->encoder && bridge->encoder->crtc && + crtc_state->crtc) { + const struct drm_display_mode *cur_mode = + &crtc_state->crtc->state->mode; + convert_to_dsi_mode(cur_mode, &cur_dsi_mode); + cur_dsi_mode.timing.dsc_enabled = + dsi_mode.priv_info->dsc_enabled; + cur_dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc; + rc = dsi_display_validate_mode_change(c_bridge->display, + &cur_dsi_mode, &dsi_mode); + if (rc) { + DSI_ERR("[%s] seamless mode mismatch failure rc=%d\n", + c_bridge->display->name, rc); + return false; + } + + /* No panel mode switch when drm pipeline is changing */ + if ((dsi_mode.panel_mode != cur_dsi_mode.panel_mode) && + (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) && + (crtc_state->enable == + crtc_state->crtc->state->enable)) { + dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_POMS; + + SDE_EVT32(SDE_EVTLOG_FUNC_CASE1, + dsi_mode.timing.h_active, + dsi_mode.timing.v_active, + dsi_mode.timing.refresh_rate, + dsi_mode.pixel_clk_khz, + dsi_mode.panel_mode); + } + /* No DMS/VRR when drm pipeline is changing */ + if (!drm_mode_equal(cur_mode, adjusted_mode) && + (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) && + (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS)) && + (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) && + (!crtc_state->active_changed || + display->is_cont_splash_enabled)) { + dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS; + + SDE_EVT32(SDE_EVTLOG_FUNC_CASE2, + dsi_mode.timing.h_active, + dsi_mode.timing.v_active, + dsi_mode.timing.refresh_rate, + dsi_mode.pixel_clk_khz, + dsi_mode.panel_mode); + } + } + + /* Reject seamless transition when active changed */ + if (crtc_state->active_changed && + ((dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) || + (dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS) || + (dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))) { + DSI_ERR("seamless upon active changed 0x%x %d\n", + dsi_mode.dsi_mode_flags, crtc_state->active_changed); + return false; + } + + /* convert back to drm mode, propagating the private info & flags */ + dsi_convert_to_drm_mode(&dsi_mode, adjusted_mode); + + return true; +} + +u64 dsi_drm_find_bit_clk_rate(void *display, + const struct drm_display_mode *drm_mode) +{ + int i = 0, count = 0; + struct dsi_display *dsi_display = display; + struct dsi_display_mode *dsi_mode; + u64 bit_clk_rate = 0; + + if (!dsi_display || !drm_mode) + return 0; + + dsi_display_get_mode_count(dsi_display, &count); + + for (i = 0; i < count; i++) { + dsi_mode = &dsi_display->modes[i]; + if ((dsi_mode->timing.v_active == drm_mode->vdisplay) && + (dsi_mode->timing.h_active == drm_mode->hdisplay) && + (dsi_mode->pixel_clk_khz == drm_mode->clock) && + (dsi_mode->timing.refresh_rate == drm_mode->vrefresh)) { + bit_clk_rate = dsi_mode->timing.clk_rate_hz; + break; + } + } + + return bit_clk_rate; +} + +int dsi_conn_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res) +{ + struct dsi_display_mode dsi_mode; + struct dsi_mode_info *timing; + + if (!drm_mode || !mode_info) + return -EINVAL; + + convert_to_dsi_mode(drm_mode, &dsi_mode); + + if (!dsi_mode.priv_info) + return -EINVAL; + + memset(mode_info, 0, sizeof(*mode_info)); + + timing = &dsi_mode.timing; + mode_info->frame_rate = dsi_mode.timing.refresh_rate; + mode_info->vtotal = DSI_V_TOTAL(timing); + mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines; + mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer; + mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom; + mode_info->clk_rate = dsi_drm_find_bit_clk_rate(display, drm_mode); + mode_info->mdp_transfer_time_us = + dsi_mode.priv_info->mdp_transfer_time_us; + + memcpy(&mode_info->topology, &dsi_mode.priv_info->topology, + sizeof(struct msm_display_topology)); + + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; + if (dsi_mode.priv_info->dsc_enabled) { + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; + memcpy(&mode_info->comp_info.dsc_info, &dsi_mode.priv_info->dsc, + sizeof(dsi_mode.priv_info->dsc)); + mode_info->comp_info.comp_ratio = + MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1; + } + + if (dsi_mode.priv_info->roi_caps.enabled) { + memcpy(&mode_info->roi_caps, &dsi_mode.priv_info->roi_caps, + sizeof(dsi_mode.priv_info->roi_caps)); + } + + return 0; +} + +static const struct drm_bridge_funcs dsi_bridge_ops = { + .attach = dsi_bridge_attach, + .mode_fixup = dsi_bridge_mode_fixup, + .pre_enable = dsi_bridge_pre_enable, + .enable = dsi_bridge_enable, + .disable = dsi_bridge_disable, + .post_disable = dsi_bridge_post_disable, + .mode_set = dsi_bridge_mode_set, +}; + +int dsi_conn_set_info_blob(struct drm_connector *connector, + void *info, void *display, struct msm_mode_info *mode_info) +{ + struct dsi_display *dsi_display = display; + struct dsi_panel *panel; + enum dsi_pixel_format fmt; + u32 bpp; + + if (!info || !dsi_display) + return -EINVAL; + + dsi_display->drm_conn = connector; + + sde_kms_info_add_keystr(info, + "display type", dsi_display->display_type); + + switch (dsi_display->type) { + case DSI_DISPLAY_SINGLE: + sde_kms_info_add_keystr(info, "display config", + "single display"); + break; + case DSI_DISPLAY_EXT_BRIDGE: + sde_kms_info_add_keystr(info, "display config", "ext bridge"); + break; + case DSI_DISPLAY_SPLIT: + sde_kms_info_add_keystr(info, "display config", + "split display"); + break; + case DSI_DISPLAY_SPLIT_EXT_BRIDGE: + sde_kms_info_add_keystr(info, "display config", + "split ext bridge"); + break; + default: + DSI_DEBUG("invalid display type:%d\n", dsi_display->type); + break; + } + + if (!dsi_display->panel) { + DSI_DEBUG("invalid panel data\n"); + goto end; + } + + panel = dsi_display->panel; + sde_kms_info_add_keystr(info, "panel name", panel->name); + + switch (panel->panel_mode) { + case DSI_OP_VIDEO_MODE: + sde_kms_info_add_keystr(info, "panel mode", "video"); + sde_kms_info_add_keystr(info, "qsync support", + panel->qsync_min_fps ? "true" : "false"); + break; + case DSI_OP_CMD_MODE: + sde_kms_info_add_keystr(info, "panel mode", "command"); + sde_kms_info_add_keyint(info, "mdp_transfer_time_us", + mode_info->mdp_transfer_time_us); + sde_kms_info_add_keystr(info, "qsync support", + panel->qsync_min_fps ? "true" : "false"); + break; + default: + DSI_DEBUG("invalid panel type:%d\n", panel->panel_mode); + break; + } + sde_kms_info_add_keystr(info, "dfps support", + panel->dfps_caps.dfps_support ? "true" : "false"); + + if (panel->dfps_caps.dfps_support) { + sde_kms_info_add_keyint(info, "min_fps", + panel->dfps_caps.min_refresh_rate); + sde_kms_info_add_keyint(info, "max_fps", + panel->dfps_caps.max_refresh_rate); + } + + sde_kms_info_add_keystr(info, "dyn bitclk support", + panel->dyn_clk_caps.dyn_clk_support ? "true" : "false"); + + switch (panel->phy_props.rotation) { + case DSI_PANEL_ROTATE_NONE: + sde_kms_info_add_keystr(info, "panel orientation", "none"); + break; + case DSI_PANEL_ROTATE_H_FLIP: + sde_kms_info_add_keystr(info, "panel orientation", "horz flip"); + break; + case DSI_PANEL_ROTATE_V_FLIP: + sde_kms_info_add_keystr(info, "panel orientation", "vert flip"); + break; + case DSI_PANEL_ROTATE_HV_FLIP: + sde_kms_info_add_keystr(info, "panel orientation", + "horz & vert flip"); + break; + default: + DSI_DEBUG("invalid panel rotation:%d\n", + panel->phy_props.rotation); + break; + } + + switch (panel->bl_config.type) { + case DSI_BACKLIGHT_PWM: + sde_kms_info_add_keystr(info, "backlight type", "pwm"); + break; + case DSI_BACKLIGHT_WLED: + sde_kms_info_add_keystr(info, "backlight type", "wled"); + break; + case DSI_BACKLIGHT_DCS: + sde_kms_info_add_keystr(info, "backlight type", "dcs"); + break; + default: + DSI_DEBUG("invalid panel backlight type:%d\n", + panel->bl_config.type); + break; + } + + if (mode_info && mode_info->roi_caps.enabled) { + sde_kms_info_add_keyint(info, "partial_update_num_roi", + mode_info->roi_caps.num_roi); + sde_kms_info_add_keyint(info, "partial_update_xstart", + mode_info->roi_caps.align.xstart_pix_align); + sde_kms_info_add_keyint(info, "partial_update_walign", + mode_info->roi_caps.align.width_pix_align); + sde_kms_info_add_keyint(info, "partial_update_wmin", + mode_info->roi_caps.align.min_width); + sde_kms_info_add_keyint(info, "partial_update_ystart", + mode_info->roi_caps.align.ystart_pix_align); + sde_kms_info_add_keyint(info, "partial_update_halign", + mode_info->roi_caps.align.height_pix_align); + sde_kms_info_add_keyint(info, "partial_update_hmin", + mode_info->roi_caps.align.min_height); + sde_kms_info_add_keyint(info, "partial_update_roimerge", + mode_info->roi_caps.merge_rois); + } + + fmt = dsi_display->config.common_config.dst_format; + bpp = dsi_ctrl_pixel_format_to_bpp(fmt); + + sde_kms_info_add_keyint(info, "bit_depth", bpp); + +end: + return 0; +} + +enum drm_connector_status dsi_conn_detect(struct drm_connector *conn, + bool force, + void *display) +{ + enum drm_connector_status status = connector_status_unknown; + struct msm_display_info info; + int rc; + + if (!conn || !display) + return status; + + /* get display dsi_info */ + memset(&info, 0x0, sizeof(info)); + rc = dsi_display_get_info(conn, &info, display); + if (rc) { + DSI_ERR("failed to get display info, rc=%d\n", rc); + return connector_status_disconnected; + } + + if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) + status = (info.is_connected ? connector_status_connected : + connector_status_disconnected); + else + status = connector_status_connected; + + conn->display_info.width_mm = info.width_mm; + conn->display_info.height_mm = info.height_mm; + + return status; +} + +void dsi_connector_put_modes(struct drm_connector *connector, + void *display) +{ + struct drm_display_mode *drm_mode; + struct dsi_display_mode dsi_mode; + struct dsi_display *dsi_display; + + if (!connector || !display) + return; + + list_for_each_entry(drm_mode, &connector->modes, head) { + convert_to_dsi_mode(drm_mode, &dsi_mode); + dsi_display_put_mode(display, &dsi_mode); + } + + /* free the display structure modes also */ + dsi_display = display; + kfree(dsi_display->modes); + dsi_display->modes = NULL; +} + + +static int dsi_drm_update_edid_name(struct edid *edid, const char *name) +{ + u8 *dtd = (u8 *)&edid->detailed_timings[3]; + u8 standard_header[] = {0x00, 0x00, 0x00, 0xFE, 0x00}; + u32 dtd_size = 18; + u32 header_size = sizeof(standard_header); + + if (!name) + return -EINVAL; + + /* Fill standard header */ + memcpy(dtd, standard_header, header_size); + + dtd_size -= header_size; + dtd_size = min_t(u32, dtd_size, strlen(name)); + + memcpy(dtd + header_size, name, dtd_size); + + return 0; +} + +static void dsi_drm_update_dtd(struct edid *edid, + struct dsi_display_mode *modes, u32 modes_count) +{ + u32 i; + u32 count = min_t(u32, modes_count, 3); + + for (i = 0; i < count; i++) { + struct detailed_timing *dtd = &edid->detailed_timings[i]; + struct dsi_display_mode *mode = &modes[i]; + struct dsi_mode_info *timing = &mode->timing; + struct detailed_pixel_timing *pd = &dtd->data.pixel_data; + u32 h_blank = timing->h_front_porch + timing->h_sync_width + + timing->h_back_porch; + u32 v_blank = timing->v_front_porch + timing->v_sync_width + + timing->v_back_porch; + u32 h_img = 0, v_img = 0; + + dtd->pixel_clock = mode->pixel_clk_khz / 10; + + pd->hactive_lo = timing->h_active & 0xFF; + pd->hblank_lo = h_blank & 0xFF; + pd->hactive_hblank_hi = ((h_blank >> 8) & 0xF) | + ((timing->h_active >> 8) & 0xF) << 4; + + pd->vactive_lo = timing->v_active & 0xFF; + pd->vblank_lo = v_blank & 0xFF; + pd->vactive_vblank_hi = ((v_blank >> 8) & 0xF) | + ((timing->v_active >> 8) & 0xF) << 4; + + pd->hsync_offset_lo = timing->h_front_porch & 0xFF; + pd->hsync_pulse_width_lo = timing->h_sync_width & 0xFF; + pd->vsync_offset_pulse_width_lo = + ((timing->v_front_porch & 0xF) << 4) | + (timing->v_sync_width & 0xF); + + pd->hsync_vsync_offset_pulse_width_hi = + (((timing->h_front_porch >> 8) & 0x3) << 6) | + (((timing->h_sync_width >> 8) & 0x3) << 4) | + (((timing->v_front_porch >> 4) & 0x3) << 2) | + (((timing->v_sync_width >> 4) & 0x3) << 0); + + pd->width_mm_lo = h_img & 0xFF; + pd->height_mm_lo = v_img & 0xFF; + pd->width_height_mm_hi = (((h_img >> 8) & 0xF) << 4) | + ((v_img >> 8) & 0xF); + + pd->hborder = 0; + pd->vborder = 0; + pd->misc = 0; + } +} + +static void dsi_drm_update_checksum(struct edid *edid) +{ + u8 *data = (u8 *)edid; + u32 i, sum = 0; + + for (i = 0; i < EDID_LENGTH - 1; i++) + sum += data[i]; + + edid->checksum = 0x100 - (sum & 0xFF); +} + +int dsi_connector_get_modes(struct drm_connector *connector, void *data, + const struct msm_resource_caps_info *avail_res) +{ + int rc, i; + u32 count = 0, edid_size; + struct dsi_display_mode *modes = NULL; + struct drm_display_mode drm_mode; + struct dsi_display *display = data; + struct edid edid; + unsigned int width_mm = connector->display_info.width_mm; + unsigned int height_mm = connector->display_info.height_mm; + const u8 edid_buf[EDID_LENGTH] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x44, 0x6D, + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1B, 0x10, 0x01, 0x03, + 0x80, 0x00, 0x00, 0x78, 0x0A, 0x0D, 0xC9, 0xA0, 0x57, 0x47, + 0x98, 0x27, 0x12, 0x48, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + }; + + edid_size = min_t(u32, sizeof(edid), EDID_LENGTH); + + memcpy(&edid, edid_buf, edid_size); + + rc = dsi_display_get_mode_count(display, &count); + if (rc) { + DSI_ERR("failed to get num of modes, rc=%d\n", rc); + goto end; + } + + rc = dsi_display_get_modes(display, &modes); + if (rc) { + DSI_ERR("failed to get modes, rc=%d\n", rc); + count = 0; + goto end; + } + + for (i = 0; i < count; i++) { + struct drm_display_mode *m; + + memset(&drm_mode, 0x0, sizeof(drm_mode)); + dsi_convert_to_drm_mode(&modes[i], &drm_mode); + m = drm_mode_duplicate(connector->dev, &drm_mode); + if (!m) { + DSI_ERR("failed to add mode %ux%u\n", + drm_mode.hdisplay, + drm_mode.vdisplay); + count = -ENOMEM; + goto end; + } + m->width_mm = connector->display_info.width_mm; + m->height_mm = connector->display_info.height_mm; + + if (display->cmdline_timing != NO_OVERRIDE) { + /* get the preferred mode from dsi display mode */ + if (modes[i].is_preferred) + m->type |= DRM_MODE_TYPE_PREFERRED; + } else if (i == 0) { + /* set the first mode in list as preferred */ + m->type |= DRM_MODE_TYPE_PREFERRED; + } + drm_mode_probed_add(connector, m); + } + + rc = dsi_drm_update_edid_name(&edid, display->panel->name); + if (rc) { + count = 0; + goto end; + } + + edid.width_cm = (connector->display_info.width_mm) / 10; + edid.height_cm = (connector->display_info.height_mm) / 10; + + dsi_drm_update_dtd(&edid, modes, count); + dsi_drm_update_checksum(&edid); + rc = drm_connector_update_edid_property(connector, &edid); + if (rc) + count = 0; + /* + * DRM EDID structure maintains panel physical dimensions in + * centimeters, we will be losing the precision anything below cm. + * Changing DRM framework will effect other clients at this + * moment, overriding the values back to millimeter. + */ + connector->display_info.width_mm = width_mm; + connector->display_info.height_mm = height_mm; +end: + DSI_DEBUG("MODE COUNT =%d\n\n", count); + return count; +} + +enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display, const struct msm_resource_caps_info *avail_res) +{ + struct dsi_display_mode dsi_mode; + int rc; + + if (!connector || !mode) { + DSI_ERR("Invalid params\n"); + return MODE_ERROR; + } + + convert_to_dsi_mode(mode, &dsi_mode); + + rc = dsi_display_validate_mode(display, &dsi_mode, + DSI_VALIDATE_FLAG_ALLOW_ADJUST); + if (rc) { + DSI_ERR("mode not supported, rc=%d\n", rc); + return MODE_BAD; + } + + return MODE_OK; +} + +int dsi_conn_pre_kickoff(struct drm_connector *connector, + void *display, + struct msm_display_kickoff_params *params) +{ + if (!connector || !display || !params) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + return dsi_display_pre_kickoff(connector, display, params); +} + +int dsi_conn_prepare_commit(void *display, + struct msm_display_conn_params *params) +{ + if (!display || !params) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + return dsi_display_pre_commit(display, params); +} + +void dsi_conn_enable_event(struct drm_connector *connector, + uint32_t event_idx, bool enable, void *display) +{ + struct dsi_event_cb_info event_info; + + memset(&event_info, 0, sizeof(event_info)); + + event_info.event_cb = sde_connector_trigger_event; + event_info.event_usr_ptr = connector; + + dsi_display_enable_event(connector, display, + event_idx, &event_info, enable); +} + +int dsi_conn_post_kickoff(struct drm_connector *connector, + struct msm_display_conn_params *params) +{ + struct drm_encoder *encoder; + struct dsi_bridge *c_bridge; + struct dsi_display_mode adj_mode; + struct dsi_display *display; + struct dsi_display_ctrl *m_ctrl, *ctrl; + int i, rc = 0; + bool enable; + + if (!connector || !connector->state) { + DSI_ERR("invalid connector or connector state\n"); + return -EINVAL; + } + + encoder = connector->state->best_encoder; + if (!encoder) { + DSI_DEBUG("best encoder is not available\n"); + return 0; + } + + c_bridge = to_dsi_bridge(encoder->bridge); + adj_mode = c_bridge->dsi_mode; + display = c_bridge->display; + + if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) { + m_ctrl = &display->ctrl[display->clk_master_idx]; + rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false); + if (rc) { + DSI_ERR("[%s] failed to dfps update rc=%d\n", + display->name, rc); + return -EINVAL; + } + + /* Update the rest of the controllers */ + display_for_each_ctrl(i, display) { + ctrl = &display->ctrl[i]; + if (!ctrl->ctrl || (ctrl == m_ctrl)) + continue; + + rc = dsi_ctrl_timing_db_update(ctrl->ctrl, false); + if (rc) { + DSI_ERR("[%s] failed to dfps update rc=%d\n", + display->name, rc); + return -EINVAL; + } + } + + c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR; + } + + /* ensure dynamic clk switch flag is reset */ + c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_DYN_CLK; + + if (params->qsync_update) { + enable = (params->qsync_mode > 0) ? true : false; + display_for_each_ctrl(i, display) + dsi_ctrl_setup_avr(display->ctrl[i].ctrl, enable); + } + + return 0; +} + +struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display, + struct drm_device *dev, + struct drm_encoder *encoder) +{ + int rc = 0; + struct dsi_bridge *bridge; + + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + if (!bridge) { + rc = -ENOMEM; + goto error; + } + + bridge->display = display; + bridge->base.funcs = &dsi_bridge_ops; + bridge->base.encoder = encoder; + + rc = drm_bridge_attach(encoder, &bridge->base, NULL); + if (rc) { + DSI_ERR("failed to attach bridge, rc=%d\n", rc); + goto error_free_bridge; + } + + encoder->bridge = &bridge->base; + return bridge; +error_free_bridge: + kfree(bridge); +error: + return ERR_PTR(rc); +} + +void dsi_drm_bridge_cleanup(struct dsi_bridge *bridge) +{ + if (bridge && bridge->base.encoder) + bridge->base.encoder->bridge = NULL; + + kfree(bridge); +} diff --git a/techpack/display/msm/dsi/dsi_drm.h b/techpack/display/msm/dsi/dsi_drm.h new file mode 100644 index 0000000000000000000000000000000000000000..ec012c2cb5296c564f503e3bfe962005eed8a247 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_drm.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_DRM_H_ +#define _DSI_DRM_H_ + +#include <linux/types.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> + +#include "msm_drv.h" + +#include "dsi_display.h" + +#define NO_OVERRIDE -1 + +struct dsi_bridge { + struct drm_bridge base; + u32 id; + + struct dsi_display *display; + struct dsi_display_mode dsi_mode; +}; + +/** + * dsi_conn_set_info_blob - callback to perform info blob initialization + * @connector: Pointer to drm connector structure + * @info: Pointer to sde connector info structure + * @display: Pointer to private display handle + * @mode_info: Pointer to mode info structure + * Returns: Zero on success + */ +int dsi_conn_set_info_blob(struct drm_connector *connector, + void *info, + void *display, + struct msm_mode_info *mode_info); + +/** + * dsi_conn_detect - callback to determine if connector is connected + * @connector: Pointer to drm connector structure + * @force: Force detect setting from drm framework + * @display: Pointer to private display handle + * Returns: Connector 'is connected' status + */ +enum drm_connector_status dsi_conn_detect(struct drm_connector *conn, + bool force, + void *display); + +/** + * dsi_connector_get_modes - callback to add drm modes via drm_mode_probed_add() + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @avail_res: Pointer with curr available resources + * Returns: Number of modes added + */ +int dsi_connector_get_modes(struct drm_connector *connector, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * dsi_connector_put_modes - callback to free up drm modes of the connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + */ +void dsi_connector_put_modes(struct drm_connector *connector, + void *display); + +/** + * dsi_conn_get_mode_info - retrieve information on the mode selected + * @drm_mode: Display mode set for the display + * @mode_info: Out parameter. information of the mode. + * @display: Pointer to private display structure + * @avail_res: Pointer with curr available resources + * Returns: Zero on success + */ +int dsi_conn_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * dsi_conn_mode_valid - callback to determine if specified mode is valid + * @connector: Pointer to drm connector structure + * @mode: Pointer to drm mode structure + * @display: Pointer to private display handle + * @avail_res: Pointer with curr available resources + * Returns: Validity status for specified mode + */ +enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * dsi_conn_enable_event - callback to notify DSI driver of event registration + * @connector: Pointer to drm connector structure + * @event_idx: Connector event index + * @enable: Whether or not the event is enabled + * @display: Pointer to private display handle + */ +void dsi_conn_enable_event(struct drm_connector *connector, + uint32_t event_idx, bool enable, void *display); + +struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display, + struct drm_device *dev, + struct drm_encoder *encoder); + +void dsi_drm_bridge_cleanup(struct dsi_bridge *bridge); + +/** + * dsi_display_pre_kickoff - program kickoff-time features + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + * @params: Parameters for kickoff-time programming + * Returns: Zero on success + */ +int dsi_conn_pre_kickoff(struct drm_connector *connector, + void *display, + struct msm_display_kickoff_params *params); + +/** + * dsi_display_post_kickoff - program post kickoff-time features + * @connector: Pointer to drm connector structure + * @params: Parameters for post kickoff programming + * Returns: Zero on success + */ +int dsi_conn_post_kickoff(struct drm_connector *connector, + struct msm_display_conn_params *params); + +/** + * dsi_convert_to_drm_mode - Update drm mode with dsi mode information + * @dsi_mode: input parameter. structure having dsi mode information. + * @drm_mode: output parameter. DRM mode set for the display + */ +void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, + struct drm_display_mode *drm_mode); + +u64 dsi_drm_find_bit_clk_rate(void *display, + const struct drm_display_mode *drm_mode); + +/** + * dsi_conn_prepare_commit - program pre commit time features + * @display: Pointer to private display structure + * @params: Parameters for pre commit programming + * Returns: Zero on success + */ +int dsi_conn_prepare_commit(void *display, + struct msm_display_conn_params *params); + +#endif /* _DSI_DRM_H_ */ diff --git a/techpack/display/msm/dsi/dsi_hw.h b/techpack/display/msm/dsi/dsi_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..cf849a4ae78b175fa84043c629edc00b5839edfa --- /dev/null +++ b/techpack/display/msm/dsi/dsi_hw.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_HW_H_ +#define _DSI_HW_H_ +#include <linux/io.h> + +#define DSI_R32(dsi_hw, off) readl_relaxed((dsi_hw)->base + (off)) +#define DSI_W32(dsi_hw, off, val) \ + do {\ + pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ + (dsi_hw)->index, #off, (uint32_t)(val)); \ + writel_relaxed((val), (dsi_hw)->base + (off)); \ + } while (0) + +#define DSI_MMSS_MISC_R32(dsi_hw, off) \ + readl_relaxed((dsi_hw)->mmss_misc_base + (off)) +#define DSI_MMSS_MISC_W32(dsi_hw, off, val) \ + do {\ + pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ + (dsi_hw)->index, #off, val); \ + writel_relaxed((val), (dsi_hw)->mmss_misc_base + (off)); \ + } while (0) + +#define DSI_MISC_R32(dsi_hw, off) \ + readl_relaxed((dsi_hw)->phy_clamp_base + (off)) +#define DSI_MISC_W32(dsi_hw, off, val) \ + do {\ + pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ + (dsi_hw)->index, #off, val); \ + writel_relaxed((val), (dsi_hw)->phy_clamp_base + (off)); \ + } while (0) +#define DSI_DISP_CC_R32(dsi_hw, off) \ + readl_relaxed((dsi_hw)->disp_cc_base + (off)) +#define DSI_DISP_CC_W32(dsi_hw, off, val) \ + do {\ + pr_debug("[DSI_%d][%s] - [0x%08x]\n", \ + (dsi_hw)->index, #off, val); \ + writel_relaxed((val), (dsi_hw)->disp_cc_base + (off)); \ + } while (0) + +#define DSI_R64(dsi_hw, off) readq_relaxed((dsi_hw)->base + (off)) +#define DSI_W64(dsi_hw, off, val) writeq_relaxed((val), (dsi_hw)->base + (off)) + +#define PLL_CALC_DATA(addr0, addr1, data0, data1) \ + (((data1) << 24) | ((((addr1)/4) & 0xFF) << 16) | \ + ((data0) << 8) | (((addr0)/4) & 0xFF)) + +#define DSI_DYN_REF_REG_W(base, offset, addr0, addr1, data0, data1) \ + writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \ + (base) + (offset)) + +#define DSI_GEN_R32(base, offset) readl_relaxed(base + (offset)) +#define DSI_GEN_W32(base, offset, val) writel_relaxed((val), base + (offset)) +#endif /* _DSI_HW_H_ */ diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c new file mode 100644 index 0000000000000000000000000000000000000000..1a3a7ed36fe1db98c39086be30476a2c45a6679e --- /dev/null +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -0,0 +1,6048 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/pwm.h> +#include <video/mipi_display.h> +#include <linux/oem/boot_mode.h> + +#include "dsi_panel.h" +#include "dsi_ctrl_hw.h" +#include "dsi_parser.h" +#include <linux/pm_wakeup.h> +#include <linux/oem/project_info.h> +#include <linux/msm_drm_notify.h> +#include <linux/notifier.h> +#include <linux/string.h> +#include <linux/input.h> +#include <linux/proc_fs.h> +#include "dsi_drm.h" +#include "dsi_display.h" +#include "sde_crtc.h" +#include "sde_rm.h" +#include "sde_trace.h" +#include <linux/pm_wakeup.h> +#include "sde_dbg.h" + +/** + * topology is currently defined by a set of following 3 values: + * 1. num of layer mixers + * 2. num of compression encoders + * 3. num of interfaces + */ +#define TOPOLOGY_SET_LEN 3 +#define MAX_TOPOLOGY 5 + +#define DSI_PANEL_SAMSUNG_ANA6705 0 +#define DSI_PANEL_SAMSUNG_AMSS644_VK04 1 +#define DSI_PANEL_SAMSUNG_SOFEF00_M 2 +#define DSI_PANEL_DEFAULT_LABEL "Default dsi panel" + +#define DEFAULT_PANEL_JITTER_NUMERATOR 2 +#define DEFAULT_PANEL_JITTER_DENOMINATOR 1 +#define DEFAULT_PANEL_JITTER_ARRAY_SIZE 2 +#define MAX_PANEL_JITTER 10 +#define DEFAULT_PANEL_PREFILL_LINES 25 +#define MIN_PREFILL_LINES 35 + +enum dsi_dsc_ratio_type { + DSC_8BPC_8BPP, + DSC_10BPC_8BPP, + DSC_12BPC_8BPP, + DSC_10BPC_10BPP, + DSC_RATIO_TYPE_MAX +}; + +static u32 dsi_dsc_rc_buf_thresh[] = {0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, + 0x62, 0x69, 0x70, 0x77, 0x79, 0x7b, 0x7d, 0x7e}; + +/* + * DSC 1.1 + * Rate control - Min QP values for each ratio type in dsi_dsc_ratio_type + */ +static char dsi_dsc_rc_range_min_qp_1_1[][15] = { + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 7, 12}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 17}, + {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 15, 21}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + }; + +/* + * DSC 1.1 SCR + * Rate control - Min QP values for each ratio type in dsi_dsc_ratio_type + */ +static char dsi_dsc_rc_range_min_qp_1_1_scr1[][15] = { + {0, 0, 1, 1, 3, 3, 3, 3, 3, 3, 5, 5, 5, 9, 12}, + {0, 4, 5, 5, 7, 7, 7, 7, 7, 7, 9, 9, 9, 13, 16}, + {0, 4, 9, 9, 11, 11, 11, 11, 11, 11, 13, 13, 13, 17, 20}, + {0, 4, 5, 6, 7, 7, 7, 7, 7, 7, 9, 9, 9, 11, 15}, + }; + +/* + * DSC 1.1 + * Rate control - Max QP values for each ratio type in dsi_dsc_ratio_type + */ +static char dsi_dsc_rc_range_max_qp_1_1[][15] = { + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 11, 12, 13, 13, 15}, + {4, 8, 9, 10, 11, 11, 11, 12, 13, 14, 15, 16, 17, 17, 19}, + {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 19, 20, 21, 21, 23}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + }; + +/* + * DSC 1.1 SCR + * Rate control - Max QP values for each ratio type in dsi_dsc_ratio_type + */ +static char dsi_dsc_rc_range_max_qp_1_1_scr1[][15] = { + {4, 4, 5, 6, 7, 7, 7, 8, 9, 10, 10, 11, 11, 12, 13}, + {8, 8, 9, 10, 11, 11, 11, 12, 13, 14, 14, 15, 15, 16, 17}, + {12, 12, 13, 14, 15, 15, 15, 16, 17, 18, 18, 19, 19, 20, 23}, + {7, 8, 9, 10, 11, 11, 11, 12, 13, 13, 14, 14, 15, 15, 16}, + }; + +/* + * DSC 1.1 and DSC 1.1 SCR + * Rate control - bpg offset values + */ +static char dsi_dsc_rc_range_bpg_offset[] = {2, 0, 0, -2, -4, -6, -8, -8, + -8, -10, -10, -12, -12, -12, -12}; +static bool hbm_finger_print = false; +static int hbm_brightness_flag = 0; +static int cur_backlight = -1; +static int cur_fps = 60; +static int cur_h = 1400; +static struct dsi_panel_cmd_set gamma_cmd_set[2]; +static seed_low_backlight = 40; +int sp_read_flag = SP_READ_SUCCESS; +char gamma_para[2][413] = { +{ +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0x5A,0x5A, +0x39,0x01,0x00,0x00,0x00,0x00,0x88,0xC8, +0xAA,0xA9,0x95,0x97,0x44,0xD8,0x52,0x08, +0x91,0x09,0xC7,0x44,0xA2,0x6B,0xDB,0x55, +0x10,0x40,0x55,0x25,0x89,0x28,0xFC,0x59, +0xFD,0xD7,0x29,0xBC,0xA0,0xDF,0x00,0x00, +0x00,0x9C,0x8F,0xB6,0x71,0x79,0x86,0x37, +0x37,0x37,0x00,0x00,0x00,0xAA,0xA9,0x95, +0x52,0x08,0x90,0x52,0x08,0x90,0x12,0xCF, +0x4F,0xAA,0x72,0xE4,0x55,0x54,0x40,0x5B, +0x29,0x8F,0x2E,0x01,0x5D,0x04,0xDD,0x30, +0xC8,0xAF,0xEF,0x00,0x00,0x00,0xAF,0x96, +0xC4,0x9F,0x85,0xA9,0x37,0x37,0x37,0x00, +0x00,0x00,0xAA,0xA9,0x95,0x52,0x08,0x90, +0x52,0x08,0x90,0x14,0xD0,0x51,0xAB,0x73, +0xE5,0x55,0x54,0x40,0x5E,0x2E,0x92,0x32, +0x04,0x5F,0x09,0xE3,0x35,0xD5,0xB9,0xFA, +0x00,0x00,0x00,0xC9,0xA9,0xDD,0xB6,0x9F, +0xBC,0x37,0x37,0x37,0x00,0x00,0x00, +0x39,0x01,0x00,0x00,0x00,0x00,0xB5,0xC9, +0xAA,0xA9,0x95,0x52,0x08,0x90,0x52,0x08, +0x90,0x15,0xD2,0x53,0xAD,0x74,0xE8,0x55, +0x54,0x41,0x63,0x35,0x9B,0x3F,0x14,0x71, +0x18,0xF1,0x46,0xE0,0xC6,0x06,0x00,0x00, +0x00,0xCE,0xC1,0xF0,0xBE,0xB5,0xBF,0x37, +0x37,0x37,0x00,0x00,0x00,0xAA,0xA9,0x95, +0x52,0x08,0x90,0x52,0x08,0x90,0x18,0xD4, +0x56,0xB1,0x78,0xEC,0x55,0x54,0x41,0x66, +0x38,0x9E,0x42,0x17,0x75,0x1A,0xF5,0x4D, +0xEE,0xD3,0x1C,0x04,0x00,0x00,0xDF,0xD7, +0x03,0xC8,0xC3,0xCF,0x37,0x37,0x37,0x00, +0x00,0x00,0xAA,0xA9,0x95,0x52,0x08,0x90, +0x52,0x08,0x90,0x0D,0xCB,0x4B,0xA8,0x73, +0xE4,0x55,0x55,0x51,0x61,0x35,0x97,0x3B, +0x17,0x70,0x20,0x00,0x53,0x01,0xE6,0x2F, +0x04,0x00,0x00,0xDD,0xE1,0x10,0xD2,0xCE, +0xF0,0x37,0x37,0x37,0x00,0x00,0x00,0xAA, +0xA9,0x95,0x52,0x08,0x90,0x52,0x08,0x90, +0x0A,0xCB,0x49,0xAE,0x7A,0xEA,0x55,0x55, +0x45,0x70,0x45,0xA4,0x4C,0x2D,0x82,0x30, +0x13,0x64,0xFF,0x04,0x3B,0x04,0x10,0x00, +0xFF,0xFD,0x36,0xF4,0xC5,0x1A,0x37,0x37, +0x37,0x00,0x00,0x00, +0x15,0x01,0x00,0x00,0x00,0x00,0x02,0xB0,0x02, +0x39,0x01,0x00,0x00,0x00,0x00,0x2E,0xB3, +0xAE,0xA9,0x95,0xC7,0x68,0x08,0x77,0x28, +0xB6,0x27,0xE1,0x63,0xB6,0x7D,0xF1,0x55, +0x54,0x40,0x64,0x31,0x98,0x34,0x07,0x67, +0x06,0xDF,0x33,0xC7,0xA3,0xE5,0x00,0x00, +0x00,0xA3,0x93,0xC6,0x0A,0x01,0x01,0x37, +0x37,0x37,0x00,0x00,0x00, +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0xA5,0xA5 +}, +{ +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0x5A,0x5A, +0x39,0x01,0x00,0x00,0x00,0x00,0x88,0xC8, +0xAA,0xA9,0x95,0x97,0x44,0xD8,0x52,0x08, +0x90,0x09,0xC7,0x45,0xA2,0x6B,0xDB,0x55, +0x10,0x40,0x55,0x26,0x89,0x29,0xFF,0x59, +0xFE,0xDA,0x29,0xC6,0xAF,0xE5,0x00,0x00, +0x00,0xA6,0x97,0xBC,0x84,0x85,0x94,0x37, +0x37,0x37,0x00,0x00,0x00,0xAA,0xA9,0x95, +0x5A,0x21,0x9B,0x5A,0x21,0x9B,0x17,0xD3, +0x54,0xAB,0x73,0xE4,0x55,0x54,0x40,0x5F, +0x30,0x94,0x32,0x08,0x63,0x09,0xE6,0x35, +0xD9,0xC4,0xFD,0x00,0x00,0x00,0xCD,0xB9, +0xE7,0xAE,0x9F,0xB2,0x37,0x37,0x37,0x00, +0x00,0x00,0xAA,0xA9,0x95,0x5A,0x21,0x9B, +0x5A,0x21,0x9B,0x18,0xD4,0x55,0xAE,0x76, +0xE7,0x55,0x54,0x41,0x63,0x35,0x98,0x39, +0x11,0x68,0x16,0xF3,0x3E,0xF4,0xDD,0x1A, +0x04,0x00,0x00,0xEF,0xCF,0x06,0xD6,0xC4, +0xE5,0x37,0x37,0x37,0x00,0x00,0x00, +0x39,0x01,0x00,0x00,0x00,0x00,0xB5,0xC9, +0xAA,0xA9,0x95,0x5A,0x21,0x9B,0x5A,0x21, +0x9B,0x18,0xD3,0x54,0xB0,0x78,0xE9,0x55, +0x55,0x51,0x67,0x3A,0x9C,0x43,0x1A,0x6F, +0x24,0x00,0x4D,0x0A,0xEB,0x31,0x44,0x10, +0x00,0x07,0xE0,0x23,0xF1,0xD5,0x05,0x37, +0x37,0x37,0x00,0x00,0x00,0xAA,0xA9,0x95, +0x5A,0x21,0x9B,0x5A,0x21,0x9B,0x18,0xD4, +0x55,0xB3,0x7B,0xEB,0x55,0x55,0x51,0x6E, +0x42,0x9F,0x47,0x23,0x75,0x30,0x0E,0x55, +0x1B,0xFA,0x3C,0x44,0x10,0x00,0x0E,0xEF, +0x2D,0xF8,0xD8,0x0C,0x37,0x37,0x37,0x00, +0x00,0x00,0xAA,0xA9,0x95,0x5A,0x21,0x9B, +0x5A,0x21,0x9B,0x0D,0xCB,0x49,0xAF,0x7B, +0xE8,0x55,0x55,0x55,0x72,0x48,0xA2,0x51, +0x2C,0x79,0x3C,0x1A,0x5E,0x2C,0x08,0x46, +0x45,0x10,0x00,0x15,0xF4,0x40,0x05,0xDE, +0x24,0x37,0x37,0x37,0x00,0x00,0x00,0xAA, +0xA9,0x95,0x5A,0x21,0x9B,0x5A,0x21,0x9B, +0x09,0xCC,0x44,0xB7,0x89,0xED,0x55,0x55, +0x55,0x87,0x5F,0xAE,0x6F,0x4C,0x8D,0x63, +0x3F,0x7D,0x56,0x30,0x6C,0x55,0x50,0x00, +0x3B,0x1B,0x62,0x2B,0x03,0x45,0x37,0x37, +0x37,0x00,0x00,0x00, +/*0xB0 0x02*/ +0x15,0x01,0x00,0x00,0x00,0x00,0x02,0xB0,0x02, +/* 45 parameter read value (90Hz) */ +0x39,0x01,0x00,0x00,0x00,0x00,0x2E,0xB3, +0xAE,0xA9,0x95,0xC7,0x68,0x08,0x74,0x26, +0xB3,0x22,0xDC,0x5F,0xB5,0x7C,0xF0,0x55, +0x54,0x40,0x62,0x31,0x98,0x34,0x07,0x66, +0x06,0xDF,0x32,0xC9,0xA9,0xE9,0x00,0x00, +0x00,0xAD,0x9D,0xCE,0x0D,0x01,0x01,0x37, +0x37,0x37,0x00,0x00,0x00, +/* level2_key Disable */ +0x39,0x01,0x00,0x00,0x00,0x00,0x03,0xF0,0xA5,0xA5 +} + +}; +EXPORT_SYMBOL(gamma_para); + +const char *gamma_cmd_set_map[DSI_GAMMA_CMD_SET_MAX] = { + "dsi-gamma-cmd-set-switch-60hz", + "dsi-gamma-cmd-set-switch-90hz", +}; +int gamma_read_flag = GAMMA_READ_SUCCESS; + +char dsi_panel_name = DSI_PANEL_SAMSUNG_ANA6705; +EXPORT_SYMBOL(dsi_panel_name); + +int dsi_dsc_create_pps_buf_cmd(struct msm_display_dsc_info *dsc, char *buf, + int pps_id) +{ + char *bp; + char data; + int i, bpp; + char *dbgbp; + + dbgbp = buf; + bp = buf; + /* First 7 bytes are cmd header */ + *bp++ = 0x0A; + *bp++ = 1; + *bp++ = 0; + *bp++ = 0; + *bp++ = dsc->pps_delay_ms; + *bp++ = 0; + *bp++ = 128; + + *bp++ = (dsc->version & 0xff); /* pps0 */ + *bp++ = (pps_id & 0xff); /* pps1 */ + bp++; /* pps2, reserved */ + + data = dsc->line_buf_depth & 0x0f; + data |= ((dsc->bpc & 0xf) << 4); + *bp++ = data; /* pps3 */ + + bpp = dsc->bpp; + bpp <<= 4; /* 4 fraction bits */ + data = (bpp >> 8); + data &= 0x03; /* upper two bits */ + data |= ((dsc->block_pred_enable & 0x1) << 5); + data |= ((dsc->convert_rgb & 0x1) << 4); + data |= ((dsc->enable_422 & 0x1) << 3); + data |= ((dsc->vbr_enable & 0x1) << 2); + *bp++ = data; /* pps4 */ + *bp++ = (bpp & 0xff); /* pps5 */ + + *bp++ = ((dsc->pic_height >> 8) & 0xff); /* pps6 */ + *bp++ = (dsc->pic_height & 0x0ff); /* pps7 */ + *bp++ = ((dsc->pic_width >> 8) & 0xff); /* pps8 */ + *bp++ = (dsc->pic_width & 0x0ff); /* pps9 */ + + *bp++ = ((dsc->slice_height >> 8) & 0xff);/* pps10 */ + *bp++ = (dsc->slice_height & 0x0ff); /* pps11 */ + *bp++ = ((dsc->slice_width >> 8) & 0xff); /* pps12 */ + *bp++ = (dsc->slice_width & 0x0ff); /* pps13 */ + + *bp++ = ((dsc->chunk_size >> 8) & 0xff);/* pps14 */ + *bp++ = (dsc->chunk_size & 0x0ff); /* pps15 */ + + *bp++ = (dsc->initial_xmit_delay >> 8) & 0x3; /* pps16, bit 0, 1 */ + *bp++ = (dsc->initial_xmit_delay & 0xff);/* pps17 */ + + *bp++ = ((dsc->initial_dec_delay >> 8) & 0xff); /* pps18 */ + *bp++ = (dsc->initial_dec_delay & 0xff);/* pps19 */ + + bp++; /* pps20, reserved */ + + *bp++ = (dsc->initial_scale_value & 0x3f); /* pps21 */ + + *bp++ = ((dsc->scale_increment_interval >> 8) & 0xff); /* pps22 */ + *bp++ = (dsc->scale_increment_interval & 0xff); /* pps23 */ + + *bp++ = ((dsc->scale_decrement_interval >> 8) & 0xf); /* pps24 */ + *bp++ = (dsc->scale_decrement_interval & 0x0ff);/* pps25 */ + + bp++; /* pps26, reserved */ + + *bp++ = (dsc->first_line_bpg_offset & 0x1f);/* pps27 */ + + *bp++ = ((dsc->nfl_bpg_offset >> 8) & 0xff);/* pps28 */ + *bp++ = (dsc->nfl_bpg_offset & 0x0ff); /* pps29 */ + *bp++ = ((dsc->slice_bpg_offset >> 8) & 0xff);/* pps30 */ + *bp++ = (dsc->slice_bpg_offset & 0x0ff);/* pps31 */ + + *bp++ = ((dsc->initial_offset >> 8) & 0xff);/* pps32 */ + *bp++ = (dsc->initial_offset & 0x0ff); /* pps33 */ + + *bp++ = ((dsc->final_offset >> 8) & 0xff);/* pps34 */ + *bp++ = (dsc->final_offset & 0x0ff); /* pps35 */ + + *bp++ = (dsc->min_qp_flatness & 0x1f); /* pps36 */ + *bp++ = (dsc->max_qp_flatness & 0x1f); /* pps37 */ + + *bp++ = ((dsc->rc_model_size >> 8) & 0xff);/* pps38 */ + *bp++ = (dsc->rc_model_size & 0x0ff); /* pps39 */ + + *bp++ = (dsc->edge_factor & 0x0f); /* pps40 */ + + *bp++ = (dsc->quant_incr_limit0 & 0x1f); /* pps41 */ + *bp++ = (dsc->quant_incr_limit1 & 0x1f); /* pps42 */ + + data = ((dsc->tgt_offset_hi & 0xf) << 4); + data |= (dsc->tgt_offset_lo & 0x0f); + *bp++ = data; /* pps43 */ + + for (i = 0; i < 14; i++) + *bp++ = (dsc->buf_thresh[i] & 0xff); /* pps44 - pps57 */ + + for (i = 0; i < 15; i++) { /* pps58 - pps87 */ + data = (dsc->range_min_qp[i] & 0x1f); + data <<= 3; + data |= ((dsc->range_max_qp[i] >> 2) & 0x07); + *bp++ = data; + data = (dsc->range_max_qp[i] & 0x03); + data <<= 6; + data |= (dsc->range_bpg_offset[i] & 0x3f); + *bp++ = data; + } + + return 128; +} + +static int dsi_panel_vreg_get(struct dsi_panel *panel) +{ + int rc = 0; + int i; + struct regulator *vreg = NULL; + + for (i = 0; i < panel->power_info.count; i++) { + vreg = devm_regulator_get(panel->parent, + panel->power_info.vregs[i].vreg_name); + rc = PTR_RET(vreg); + if (rc) { + DSI_ERR("failed to get %s regulator\n", + panel->power_info.vregs[i].vreg_name); + goto error_put; + } + panel->power_info.vregs[i].vreg = vreg; + } + + return rc; +error_put: + for (i = i - 1; i >= 0; i--) { + devm_regulator_put(panel->power_info.vregs[i].vreg); + panel->power_info.vregs[i].vreg = NULL; + } + return rc; +} + +static int dsi_panel_vreg_put(struct dsi_panel *panel) +{ + int rc = 0; + int i; + + for (i = panel->power_info.count - 1; i >= 0; i--) + devm_regulator_put(panel->power_info.vregs[i].vreg); + + return rc; +} + +static int dsi_panel_gpio_request(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_panel_reset_config *r_config = &panel->reset_config; + + if (gpio_is_valid(r_config->reset_gpio)) { + rc = gpio_request(r_config->reset_gpio, "reset_gpio"); + if (rc) { + DSI_ERR("request for reset_gpio failed, rc=%d\n", rc); + goto error; + } + } + + if (gpio_is_valid(r_config->disp_en_gpio)) { + rc = gpio_request(r_config->disp_en_gpio, "disp_en_gpio"); + if (rc) { + DSI_ERR("request for disp_en_gpio failed, rc=%d\n", rc); + goto error_release_reset; + } + } + + if (gpio_is_valid(panel->bl_config.en_gpio)) { + rc = gpio_request(panel->bl_config.en_gpio, "bklt_en_gpio"); + if (rc) { + DSI_ERR("request for bklt_en_gpio failed, rc=%d\n", rc); + goto error_release_disp_en; + } + } + + if (gpio_is_valid(r_config->lcd_mode_sel_gpio)) { + rc = gpio_request(r_config->lcd_mode_sel_gpio, "mode_gpio"); + if (rc) { + DSI_ERR("request for mode_gpio failed, rc=%d\n", rc); + goto error_release_mode_sel; + } + } + + if (gpio_is_valid(panel->panel_test_gpio)) { + rc = gpio_request(panel->panel_test_gpio, "panel_test_gpio"); + if (rc) { + DSI_WARN("request for panel_test_gpio failed, rc=%d\n", + rc); + panel->panel_test_gpio = -1; + rc = 0; + } + } + + goto error; +error_release_mode_sel: + if (gpio_is_valid(panel->bl_config.en_gpio)) + gpio_free(panel->bl_config.en_gpio); +error_release_disp_en: + if (gpio_is_valid(r_config->disp_en_gpio)) + gpio_free(r_config->disp_en_gpio); +error_release_reset: + if (gpio_is_valid(r_config->reset_gpio)) + gpio_free(r_config->reset_gpio); +error: + return rc; +} + +static int dsi_panel_gpio_release(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_panel_reset_config *r_config = &panel->reset_config; + + if (gpio_is_valid(r_config->reset_gpio)) + gpio_free(r_config->reset_gpio); + + if (gpio_is_valid(r_config->disp_en_gpio)) + gpio_free(r_config->disp_en_gpio); + + if (gpio_is_valid(panel->bl_config.en_gpio)) + gpio_free(panel->bl_config.en_gpio); + + if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) + gpio_free(panel->reset_config.lcd_mode_sel_gpio); + + if (gpio_is_valid(panel->panel_test_gpio)) + gpio_free(panel->panel_test_gpio); + + return rc; +} + +int dsi_panel_trigger_esd_attack(struct dsi_panel *panel) +{ + struct dsi_panel_reset_config *r_config; + + if (!panel) { + DSI_ERR("Invalid panel param\n"); + return -EINVAL; + } + + r_config = &panel->reset_config; + if (!r_config) { + DSI_ERR("Invalid panel reset configuration\n"); + return -EINVAL; + } + + if (gpio_is_valid(r_config->reset_gpio)) { + gpio_set_value(r_config->reset_gpio, 0); + SDE_EVT32(SDE_EVTLOG_FUNC_CASE1); + DSI_INFO("GPIO pulled low to simulate ESD\n"); + return 0; + } + DSI_ERR("failed to pull down gpio\n"); + return -EINVAL; +} + +static int dsi_panel_reset(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_panel_reset_config *r_config = &panel->reset_config; + int i; + + if (gpio_is_valid(panel->reset_config.disp_en_gpio)) { + rc = gpio_direction_output(panel->reset_config.disp_en_gpio, 1); + if (rc) { + DSI_ERR("unable to set dir for disp gpio rc=%d\n", rc); + goto exit; + } + } + + if (r_config->count) { + rc = gpio_direction_output(r_config->reset_gpio, + r_config->sequence[0].level); + if (rc) { + DSI_ERR("unable to set dir for rst gpio rc=%d\n", rc); + goto exit; + } + } + + for (i = 0; i < r_config->count; i++) { + gpio_set_value(r_config->reset_gpio, + r_config->sequence[i].level); + + + if (r_config->sequence[i].sleep_ms) + usleep_range(r_config->sequence[i].sleep_ms * 1000, + (r_config->sequence[i].sleep_ms * 1000) + 100); + } + + if (gpio_is_valid(panel->bl_config.en_gpio)) { + rc = gpio_direction_output(panel->bl_config.en_gpio, 1); + if (rc) + DSI_ERR("unable to set dir for bklt gpio rc=%d\n", rc); + } + + if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) { + bool out = true; + + if ((panel->reset_config.mode_sel_state == MODE_SEL_DUAL_PORT) + || (panel->reset_config.mode_sel_state + == MODE_GPIO_LOW)) + out = false; + else if ((panel->reset_config.mode_sel_state + == MODE_SEL_SINGLE_PORT) || + (panel->reset_config.mode_sel_state + == MODE_GPIO_HIGH)) + out = true; + + rc = gpio_direction_output( + panel->reset_config.lcd_mode_sel_gpio, out); + if (rc) + DSI_ERR("unable to set dir for mode gpio rc=%d\n", rc); + } + + if (gpio_is_valid(panel->panel_test_gpio)) { + rc = gpio_direction_input(panel->panel_test_gpio); + if (rc) + DSI_WARN("unable to set dir for panel test gpio rc=%d\n", + rc); + } + +exit: + return rc; +} + +static int dsi_panel_set_pinctrl_state(struct dsi_panel *panel, bool enable) +{ + int rc = 0; + struct pinctrl_state *state; + + if (panel->host_config.ext_bridge_mode) + return 0; + + if (enable) + state = panel->pinctrl.active; + else + state = panel->pinctrl.suspend; + + rc = pinctrl_select_state(panel->pinctrl.pinctrl, state); + if (rc) + DSI_ERR("[%s] failed to set pin state, rc=%d\n", + panel->name, rc); + + return rc; +} + + +static int dsi_panel_power_on(struct dsi_panel *panel) +{ + int rc = 0; + + rc = dsi_pwr_enable_regulator(&panel->power_info, true); + if (rc) { + DSI_ERR("[%s] failed to enable vregs, rc=%d\n", + panel->name, rc); + goto exit; + } + + rc = dsi_panel_set_pinctrl_state(panel, true); + if (rc) { + DSI_ERR("[%s] failed to set pinctrl, rc=%d\n", panel->name, rc); + goto error_disable_vregs; + } + +/*Vikas@.MULTIMEDIA Display.LCD.,2020-2-18 Change reset enable sequence for LCD power on spec.*/ + if (!strcmp(panel->name,"samsung ams644vk04 fhd cmd mode dsc dsi panel") || !strcmp(panel->name,"samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel")) { + usleep_range(10, 11); + } else { + rc = dsi_panel_reset(panel); + } + if (rc) { + DSI_ERR("[%s] failed to reset panel, rc=%d\n", panel->name, rc); + goto error_disable_gpio; + } + + goto exit; + +error_disable_gpio: + if (gpio_is_valid(panel->reset_config.disp_en_gpio)) + gpio_set_value(panel->reset_config.disp_en_gpio, 0); + + if (gpio_is_valid(panel->bl_config.en_gpio)) + gpio_set_value(panel->bl_config.en_gpio, 0); + + (void)dsi_panel_set_pinctrl_state(panel, false); + +error_disable_vregs: + (void)dsi_pwr_enable_regulator(&panel->power_info, false); + +exit: + return rc; +} + +static int dsi_panel_power_off(struct dsi_panel *panel) +{ + int rc = 0; + + if (gpio_is_valid(panel->reset_config.disp_en_gpio)) + gpio_set_value(panel->reset_config.disp_en_gpio, 0); + + if (gpio_is_valid(panel->reset_config.reset_gpio) && + !panel->reset_gpio_always_on) + gpio_set_value(panel->reset_config.reset_gpio, 0); + + if (gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) + gpio_set_value(panel->reset_config.lcd_mode_sel_gpio, 0); + + if (gpio_is_valid(panel->panel_test_gpio)) { + rc = gpio_direction_input(panel->panel_test_gpio); + if (rc) + DSI_WARN("set dir for panel test gpio failed rc=%d\n", + rc); + } + + rc = dsi_panel_set_pinctrl_state(panel, false); + if (rc) { + DSI_ERR("[%s] failed set pinctrl state, rc=%d\n", panel->name, + rc); + } + + if (!strcmp(panel->name,"samsung ams644vk04 fhd cmd mode dsc dsi panel") || !strcmp(panel->name,"samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel")) { + usleep_range(4000, 5000); + if (gpio_is_valid(panel->reset_config.reset_gpio)) + gpio_set_value(panel->reset_config.reset_gpio, 0); + usleep_range(10000, 12000); + } + rc = dsi_pwr_enable_regulator(&panel->power_info, false); + if (rc) + DSI_ERR("[%s] failed to enable vregs, rc=%d\n", + panel->name, rc); + + return rc; +} +int dsi_panel_tx_cmd_set(struct dsi_panel *panel, + enum dsi_cmd_set_type type) +{ + int rc = 0, i = 0; + ssize_t len; + struct dsi_cmd_desc *cmds; + u32 count; + enum dsi_cmd_set_state state; + struct dsi_display_mode *mode; + const struct mipi_dsi_host_ops *ops = panel->host->ops; + + if (!panel || !panel->cur_mode) + return -EINVAL; + + mode = panel->cur_mode; + + cmds = mode->priv_info->cmd_sets[type].cmds; + count = mode->priv_info->cmd_sets[type].count; + state = mode->priv_info->cmd_sets[type].state; + SDE_EVT32(type, state, count); + + if (count == 0) { + DSI_DEBUG("[%s] No commands to be sent for state(%d)\n", + panel->name, type); + goto error; + } + + for (i = 0; i < count; i++) { + if (state == DSI_CMD_SET_STATE_LP) + cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM; + + if (cmds->last_command) + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + + if (type == DSI_CMD_SET_VID_TO_CMD_SWITCH) + cmds->msg.flags |= MIPI_DSI_MSG_ASYNC_OVERRIDE; + + len = ops->transfer(panel->host, &cmds->msg); + if (len < 0) { + rc = len; + DSI_ERR("failed to set cmds(%d), rc=%d\n", type, rc); + goto error; + } + if (cmds->post_wait_ms) + usleep_range(cmds->post_wait_ms*1000, + ((cmds->post_wait_ms*1000)+10)); + cmds++; + } +error: + return rc; +} + +static int dsi_panel_pinctrl_deinit(struct dsi_panel *panel) +{ + int rc = 0; + + if (panel->host_config.ext_bridge_mode) + return 0; + + devm_pinctrl_put(panel->pinctrl.pinctrl); + + return rc; +} + +static int dsi_panel_pinctrl_init(struct dsi_panel *panel) +{ + int rc = 0; + + if (panel->host_config.ext_bridge_mode) + return 0; + + /* TODO: pinctrl is defined in dsi dt node */ + panel->pinctrl.pinctrl = devm_pinctrl_get(panel->parent); + if (IS_ERR_OR_NULL(panel->pinctrl.pinctrl)) { + rc = PTR_ERR(panel->pinctrl.pinctrl); + DSI_ERR("failed to get pinctrl, rc=%d\n", rc); + goto error; + } + + panel->pinctrl.active = pinctrl_lookup_state(panel->pinctrl.pinctrl, + "panel_active"); + if (IS_ERR_OR_NULL(panel->pinctrl.active)) { + rc = PTR_ERR(panel->pinctrl.active); + DSI_ERR("failed to get pinctrl active state, rc=%d\n", rc); + goto error; + } + + panel->pinctrl.suspend = + pinctrl_lookup_state(panel->pinctrl.pinctrl, "panel_suspend"); + + if (IS_ERR_OR_NULL(panel->pinctrl.suspend)) { + rc = PTR_ERR(panel->pinctrl.suspend); + DSI_ERR("failed to get pinctrl suspend state, rc=%d\n", rc); + goto error; + } + +error: + return rc; +} + +static int dsi_panel_wled_register(struct dsi_panel *panel, + struct dsi_backlight_config *bl) +{ + struct backlight_device *bd; + + bd = backlight_device_get_by_type(BACKLIGHT_RAW); + if (!bd) { + DSI_ERR("[%s] fail raw backlight register\n", panel->name); + return -EPROBE_DEFER; + } + + bl->raw_bd = bd; + return 0; +} +bool HBM_flag =false; + +int dsi_panel_gamma_read_address_setting(struct dsi_panel *panel, u16 read_number) +{ + int rc = 0; + struct mipi_dsi_device *dsi; + + if (!panel || (read_number > 0xffff)) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + dsi = &panel->mipi_device; + + rc = mipi_dsi_dcs_write_c1(dsi, read_number); + + return rc; +} + +extern int op_dimlayer_bl_alpha; +extern int op_dimlayer_bl_enabled; +extern int op_dimlayer_bl_enable_real; + +static int saved_backlight = -1; + +int dsi_panel_backlight_get(void) +{ + return saved_backlight; +} +static int dsi_panel_update_backlight(struct dsi_panel *panel, + u32 bl_lvl) +{ + int rc = 0; + u32 count; + struct mipi_dsi_device *dsi= &panel->mipi_device; + + struct dsi_display_mode *mode; + + + if (!panel || (bl_lvl > 0xffff) || !panel->cur_mode) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + dsi = &panel->mipi_device; + mode = panel->cur_mode; + + saved_backlight = bl_lvl; + + + if (panel->is_hbm_enabled) { + hbm_finger_print = true; + DSI_ERR("HBM is enabled\n"); + return 0; + } + + if (op_dimlayer_bl_enabled != op_dimlayer_bl_enable_real) { + op_dimlayer_bl_enable_real = op_dimlayer_bl_enabled; + if (op_dimlayer_bl_enable_real && (bl_lvl != 0) && (bl_lvl < op_dimlayer_bl_alpha)) + bl_lvl = op_dimlayer_bl_alpha; + DSI_ERR("dc light %d %d\n", op_dimlayer_bl_enable_real, bl_lvl); + } + if (op_dimlayer_bl_enable_real && (bl_lvl != 0) && (bl_lvl < op_dimlayer_bl_alpha)) + bl_lvl = op_dimlayer_bl_alpha; + + if (panel->bl_config.bl_high2bit) { + if (HBM_flag == true) + return 0; + + if (cur_backlight == bl_lvl && (mode_fps != cur_fps || + cur_h != panel->cur_mode->timing.h_active) && !hbm_finger_print) { + cur_fps = mode_fps; + cur_h = panel->cur_mode->timing.h_active; + return 0; + } + + if (hbm_brightness_flag == 1) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_BRIGHTNESS_OFF].count; + if (!count) { + DSI_ERR("This panel does not support HBM brightness off mode.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_BRIGHTNESS_OFF); + DSI_ERR("Send DSI_CMD_SET_HBM_BRIGHTNESS_OFF cmds.\n"); + hbm_brightness_flag = 0; + } + } + + + + rc = mipi_dsi_dcs_set_display_brightness_samsung(dsi, bl_lvl); + + DSI_ERR("backlight = %d\n", bl_lvl); + cur_backlight = bl_lvl; + cur_fps = mode_fps; + cur_h = panel->cur_mode->timing.h_active; + hbm_finger_print = false; + } else { + if (panel->bl_config.bl_inverted_dbv) + bl_lvl = (((bl_lvl & 0xff) << 8) | (bl_lvl >> 8)); + + rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl); + } + if (rc < 0) + DSI_ERR("failed to update dcs backlight:%d\n", bl_lvl); +error: + return rc; + +} +int dsi_panel_op_set_hbm_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + mode = panel->cur_mode; + switch (level) { + case 0: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_OFF].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode off.\n"); + goto error; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_OFF); + printk(KERN_ERR"When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n",panel->hbm_backlight,panel->bl_config.bl_level); + rc= dsi_panel_update_backlight(panel,panel->hbm_backlight); + } + break; + + case 1: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_5].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode.\n"); + goto error; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON_5); + } + break; + default: + break; + + } + DSI_ERR("Set HBM Mode = %d\n", level); + if(level==5) + { + DSI_ERR("HBM == 5 for fingerprint\n"); + } + +error: + mutex_unlock(&panel->panel_lock); + + return rc; +} + +static int dsi_panel_update_pwm_backlight(struct dsi_panel *panel, + u32 bl_lvl) +{ + int rc = 0; + u32 duty = 0; + u32 period_ns = 0; + struct dsi_backlight_config *bl; + + if (!panel) { + DSI_ERR("Invalid Params\n"); + return -EINVAL; + } + + bl = &panel->bl_config; + if (!bl->pwm_bl) { + DSI_ERR("pwm device not found\n"); + return -EINVAL; + } + + period_ns = bl->pwm_period_usecs * NSEC_PER_USEC; + duty = bl_lvl * period_ns; + duty /= bl->bl_max_level; + + rc = pwm_config(bl->pwm_bl, duty, period_ns); + if (rc) { + DSI_ERR("[%s] failed to change pwm config, rc=\n", panel->name, + rc); + goto error; + } + + if (bl_lvl == 0 && bl->pwm_enabled) { + pwm_disable(bl->pwm_bl); + bl->pwm_enabled = false; + return 0; + } + + if (!bl->pwm_enabled) { + rc = pwm_enable(bl->pwm_bl); + if (rc) { + DSI_ERR("[%s] failed to enable pwm, rc=\n", panel->name, + rc); + goto error; + } + + bl->pwm_enabled = true; + } + +error: + return rc; +} + +int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl) +{ + int rc = 0; + struct dsi_backlight_config *bl = &panel->bl_config; + + if (panel->host_config.ext_bridge_mode) + return 0; + + DSI_DEBUG("backlight type:%d lvl:%d\n", bl->type, bl_lvl); + switch (bl->type) { + case DSI_BACKLIGHT_WLED: + rc = backlight_device_set_brightness(bl->raw_bd, bl_lvl); + break; + case DSI_BACKLIGHT_DCS: + panel->hbm_backlight = bl_lvl; + rc = dsi_panel_update_backlight(panel, bl_lvl); + break; + case DSI_BACKLIGHT_EXTERNAL: + break; + case DSI_BACKLIGHT_PWM: + rc = dsi_panel_update_pwm_backlight(panel, bl_lvl); + break; + default: + DSI_ERR("Backlight type(%d) not supported\n", bl->type); + rc = -ENOTSUPP; + } + + return rc; +} + +static u32 dsi_panel_get_brightness(struct dsi_backlight_config *bl) +{ + u32 cur_bl_level; + struct backlight_device *bd = bl->raw_bd; + + /* default the brightness level to 50% */ + cur_bl_level = bl->bl_max_level >> 1; + + switch (bl->type) { + case DSI_BACKLIGHT_WLED: + /* Try to query the backlight level from the backlight device */ + if (bd->ops && bd->ops->get_brightness) + cur_bl_level = bd->ops->get_brightness(bd); + break; + case DSI_BACKLIGHT_DCS: + case DSI_BACKLIGHT_EXTERNAL: + case DSI_BACKLIGHT_PWM: + default: + /* + * Ideally, we should read the backlight level from the + * panel. For now, just set it default value. + */ + break; + } + + DSI_DEBUG("cur_bl_level=%d\n", cur_bl_level); + return cur_bl_level; +} + +void dsi_panel_bl_handoff(struct dsi_panel *panel) +{ + struct dsi_backlight_config *bl = &panel->bl_config; + + bl->bl_level = dsi_panel_get_brightness(bl); +} + +static int dsi_panel_pwm_register(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_backlight_config *bl = &panel->bl_config; + + bl->pwm_bl = devm_of_pwm_get(panel->parent, panel->panel_of_node, NULL); + if (IS_ERR_OR_NULL(bl->pwm_bl)) { + rc = PTR_ERR(bl->pwm_bl); + DSI_ERR("[%s] failed to request pwm, rc=%d\n", panel->name, + rc); + return rc; + } + + return 0; +} + +static int dsi_panel_bl_register(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_backlight_config *bl = &panel->bl_config; + + if (panel->host_config.ext_bridge_mode) + return 0; + + switch (bl->type) { + case DSI_BACKLIGHT_WLED: + rc = dsi_panel_wled_register(panel, bl); + break; + case DSI_BACKLIGHT_DCS: + break; + case DSI_BACKLIGHT_EXTERNAL: + break; + case DSI_BACKLIGHT_PWM: + rc = dsi_panel_pwm_register(panel); + break; + default: + DSI_ERR("Backlight type(%d) not supported\n", bl->type); + rc = -ENOTSUPP; + goto error; + } + +error: + return rc; +} + +static void dsi_panel_pwm_unregister(struct dsi_panel *panel) +{ + struct dsi_backlight_config *bl = &panel->bl_config; + + devm_pwm_put(panel->parent, bl->pwm_bl); +} + +static int dsi_panel_bl_unregister(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_backlight_config *bl = &panel->bl_config; + + if (panel->host_config.ext_bridge_mode) + return 0; + + switch (bl->type) { + case DSI_BACKLIGHT_WLED: + break; + case DSI_BACKLIGHT_DCS: + break; + case DSI_BACKLIGHT_EXTERNAL: + break; + case DSI_BACKLIGHT_PWM: + dsi_panel_pwm_unregister(panel); + break; + default: + DSI_ERR("Backlight type(%d) not supported\n", bl->type); + rc = -ENOTSUPP; + goto error; + } + +error: + return rc; +} + +static int dsi_panel_parse_timing(struct dsi_mode_info *mode, + struct dsi_parser_utils *utils) +{ + int rc = 0; + u64 tmp64 = 0; + struct dsi_display_mode *display_mode; + struct dsi_display_mode_priv_info *priv_info; + + display_mode = container_of(mode, struct dsi_display_mode, timing); + + priv_info = display_mode->priv_info; + + rc = utils->read_u64(utils->data, + "qcom,mdss-dsi-panel-clockrate", &tmp64); + if (rc == -EOVERFLOW) { + tmp64 = 0; + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-panel-clockrate", (u32 *)&tmp64); + } + + mode->clk_rate_hz = !rc ? tmp64 : 0; + display_mode->priv_info->clk_rate_hz = mode->clk_rate_hz; + + rc = utils->read_u32(utils->data, "qcom,mdss-mdp-transfer-time-us", + &mode->mdp_transfer_time_us); + if (!rc) + display_mode->priv_info->mdp_transfer_time_us = + mode->mdp_transfer_time_us; + else + display_mode->priv_info->mdp_transfer_time_us = 0; + + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-panel-framerate", + &mode->refresh_rate); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-panel-framerate, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-width", + &mode->h_active); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-panel-width, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-h-front-porch", + &mode->h_front_porch); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-h-front-porch, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-h-back-porch", + &mode->h_back_porch); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-h-back-porch, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-h-pulse-width", + &mode->h_sync_width); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-h-pulse-width, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-h-sync-skew", + &mode->h_skew); + if (rc) + DSI_ERR("qcom,mdss-dsi-h-sync-skew is not defined, rc=%d\n", + rc); + + DSI_DEBUG("panel horz active:%d front_portch:%d back_porch:%d sync_skew:%d\n", + mode->h_active, mode->h_front_porch, mode->h_back_porch, + mode->h_sync_width); + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-height", + &mode->v_active); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-panel-height, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-v-back-porch", + &mode->v_back_porch); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-v-front-porch", + &mode->v_front_porch); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-v-back-porch, rc=%d\n", + rc); + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-v-pulse-width", + &mode->v_sync_width); + if (rc) { + DSI_ERR("failed to read qcom,mdss-dsi-v-pulse-width, rc=%d\n", + rc); + goto error; + } + DSI_DEBUG("panel vert active:%d front_portch:%d back_porch:%d pulse_width:%d\n", + mode->v_active, mode->v_front_porch, mode->v_back_porch, + mode->v_sync_width); + +error: + return rc; +} + +static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + int rc = 0; + u32 bpp = 0; + enum dsi_pixel_format fmt; + const char *packing; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bpp", &bpp); + if (rc) { + DSI_ERR("[%s] failed to read qcom,mdss-dsi-bpp, rc=%d\n", + name, rc); + return rc; + } + + host->bpp = bpp; + + switch (bpp) { + case 3: + fmt = DSI_PIXEL_FORMAT_RGB111; + break; + case 8: + fmt = DSI_PIXEL_FORMAT_RGB332; + break; + case 12: + fmt = DSI_PIXEL_FORMAT_RGB444; + break; + case 16: + fmt = DSI_PIXEL_FORMAT_RGB565; + break; + case 18: + fmt = DSI_PIXEL_FORMAT_RGB666; + break; + case 24: + default: + fmt = DSI_PIXEL_FORMAT_RGB888; + break; + } + + if (fmt == DSI_PIXEL_FORMAT_RGB666) { + packing = utils->get_property(utils->data, + "qcom,mdss-dsi-pixel-packing", + NULL); + if (packing && !strcmp(packing, "loose")) + fmt = DSI_PIXEL_FORMAT_RGB666_LOOSE; + } + + host->dst_format = fmt; + return rc; +} + +static int dsi_panel_parse_lane_states(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + int rc = 0; + bool lane_enabled; + u32 num_of_lanes = 0; + + lane_enabled = utils->read_bool(utils->data, + "qcom,mdss-dsi-lane-0-state"); + host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_0 : 0); + + lane_enabled = utils->read_bool(utils->data, + "qcom,mdss-dsi-lane-1-state"); + host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_1 : 0); + + lane_enabled = utils->read_bool(utils->data, + "qcom,mdss-dsi-lane-2-state"); + host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_2 : 0); + + lane_enabled = utils->read_bool(utils->data, + "qcom,mdss-dsi-lane-3-state"); + host->data_lanes |= (lane_enabled ? DSI_DATA_LANE_3 : 0); + + if (host->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + host->num_data_lanes = num_of_lanes; + + if (host->data_lanes == 0) { + DSI_ERR("[%s] No data lanes are enabled, rc=%d\n", name, rc); + rc = -EINVAL; + } + + return rc; +} + +static int dsi_panel_parse_color_swap(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + int rc = 0; + const char *swap_mode; + + swap_mode = utils->get_property(utils->data, + "qcom,mdss-dsi-color-order", NULL); + if (swap_mode) { + if (!strcmp(swap_mode, "rgb_swap_rgb")) { + host->swap_mode = DSI_COLOR_SWAP_RGB; + } else if (!strcmp(swap_mode, "rgb_swap_rbg")) { + host->swap_mode = DSI_COLOR_SWAP_RBG; + } else if (!strcmp(swap_mode, "rgb_swap_brg")) { + host->swap_mode = DSI_COLOR_SWAP_BRG; + } else if (!strcmp(swap_mode, "rgb_swap_grb")) { + host->swap_mode = DSI_COLOR_SWAP_GRB; + } else if (!strcmp(swap_mode, "rgb_swap_gbr")) { + host->swap_mode = DSI_COLOR_SWAP_GBR; + } else { + DSI_ERR("[%s] Unrecognized color order-%s\n", + name, swap_mode); + rc = -EINVAL; + } + } else { + DSI_DEBUG("[%s] Falling back to default color order\n", name); + host->swap_mode = DSI_COLOR_SWAP_RGB; + } + + /* bit swap on color channel is not defined in dt */ + host->bit_swap_red = false; + host->bit_swap_green = false; + host->bit_swap_blue = false; + return rc; +} + +static int dsi_panel_parse_triggers(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + const char *trig; + int rc = 0; + + trig = utils->get_property(utils->data, + "qcom,mdss-dsi-mdp-trigger", NULL); + if (trig) { + if (!strcmp(trig, "none")) { + host->mdp_cmd_trigger = DSI_TRIGGER_NONE; + } else if (!strcmp(trig, "trigger_te")) { + host->mdp_cmd_trigger = DSI_TRIGGER_TE; + } else if (!strcmp(trig, "trigger_sw")) { + host->mdp_cmd_trigger = DSI_TRIGGER_SW; + } else if (!strcmp(trig, "trigger_sw_te")) { + host->mdp_cmd_trigger = DSI_TRIGGER_SW_TE; + } else { + DSI_ERR("[%s] Unrecognized mdp trigger type (%s)\n", + name, trig); + rc = -EINVAL; + } + + } else { + DSI_DEBUG("[%s] Falling back to default MDP trigger\n", + name); + host->mdp_cmd_trigger = DSI_TRIGGER_SW; + } + + trig = utils->get_property(utils->data, + "qcom,mdss-dsi-dma-trigger", NULL); + if (trig) { + if (!strcmp(trig, "none")) { + host->dma_cmd_trigger = DSI_TRIGGER_NONE; + } else if (!strcmp(trig, "trigger_te")) { + host->dma_cmd_trigger = DSI_TRIGGER_TE; + } else if (!strcmp(trig, "trigger_sw")) { + host->dma_cmd_trigger = DSI_TRIGGER_SW; + } else if (!strcmp(trig, "trigger_sw_seof")) { + host->dma_cmd_trigger = DSI_TRIGGER_SW_SEOF; + } else if (!strcmp(trig, "trigger_sw_te")) { + host->dma_cmd_trigger = DSI_TRIGGER_SW_TE; + } else { + DSI_ERR("[%s] Unrecognized mdp trigger type (%s)\n", + name, trig); + rc = -EINVAL; + } + + } else { + DSI_DEBUG("[%s] Falling back to default MDP trigger\n", name); + host->dma_cmd_trigger = DSI_TRIGGER_SW; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-te-pin-select", + &host->te_mode); + if (rc) { + DSI_WARN("[%s] fallback to default te-pin-select\n", name); + host->te_mode = 1; + rc = 0; + } + + return rc; +} + +static int dsi_panel_parse_misc_host_config(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + u32 val = 0; + int rc = 0; + bool panel_cphy_mode = false; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-post", &val); + if (!rc) { + host->t_clk_post = val; + DSI_DEBUG("[%s] t_clk_post = %d\n", name, val); + } + + val = 0; + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-t-clk-pre", &val); + if (!rc) { + host->t_clk_pre = val; + DSI_DEBUG("[%s] t_clk_pre = %d\n", name, val); + } + + host->t_clk_pre_extend = utils->read_bool(utils->data, + "qcom,mdss-dsi-t-clk-pre-extend"); + + host->ignore_rx_eot = utils->read_bool(utils->data, + "qcom,mdss-dsi-rx-eot-ignore"); + + host->append_tx_eot = utils->read_bool(utils->data, + "qcom,mdss-dsi-tx-eot-append"); + + host->ext_bridge_mode = utils->read_bool(utils->data, + "qcom,mdss-dsi-ext-bridge-mode"); + + host->force_hs_clk_lane = utils->read_bool(utils->data, + "qcom,mdss-dsi-force-clock-lane-hs"); + panel_cphy_mode = utils->read_bool(utils->data, + "qcom,panel-cphy-mode"); + host->phy_type = panel_cphy_mode ? DSI_PHY_TYPE_CPHY + : DSI_PHY_TYPE_DPHY; + + return 0; +} + +static void dsi_panel_parse_split_link_config(struct dsi_host_common_cfg *host, + struct dsi_parser_utils *utils, + const char *name) +{ + int rc = 0; + u32 val = 0; + bool supported = false; + struct dsi_split_link_config *split_link = &host->split_link; + + supported = utils->read_bool(utils->data, "qcom,split-link-enabled"); + + if (!supported) { + DSI_DEBUG("[%s] Split link is not supported\n", name); + split_link->split_link_enabled = false; + return; + } + + rc = utils->read_u32(utils->data, "qcom,sublinks-count", &val); + if (rc || val < 1) { + DSI_DEBUG("[%s] Using default sublinks count\n", name); + split_link->num_sublinks = 2; + } else { + split_link->num_sublinks = val; + } + + rc = utils->read_u32(utils->data, "qcom,lanes-per-sublink", &val); + if (rc || val < 1) { + DSI_DEBUG("[%s] Using default lanes per sublink\n", name); + split_link->lanes_per_sublink = 2; + } else { + split_link->lanes_per_sublink = val; + } + + DSI_DEBUG("[%s] Split link is supported %d-%d\n", name, + split_link->num_sublinks, split_link->lanes_per_sublink); + split_link->split_link_enabled = true; +} + +static int dsi_panel_parse_host_config(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_parser_utils *utils = &panel->utils; + + rc = dsi_panel_parse_pixel_format(&panel->host_config, utils, + panel->name); + if (rc) { + DSI_ERR("[%s] failed to get pixel format, rc=%d\n", + panel->name, rc); + goto error; + } + + rc = dsi_panel_parse_lane_states(&panel->host_config, utils, + panel->name); + if (rc) { + DSI_ERR("[%s] failed to parse lane states, rc=%d\n", + panel->name, rc); + goto error; + } + + rc = dsi_panel_parse_color_swap(&panel->host_config, utils, + panel->name); + if (rc) { + DSI_ERR("[%s] failed to parse color swap config, rc=%d\n", + panel->name, rc); + goto error; + } + + rc = dsi_panel_parse_triggers(&panel->host_config, utils, + panel->name); + if (rc) { + DSI_ERR("[%s] failed to parse triggers, rc=%d\n", + panel->name, rc); + goto error; + } + + rc = dsi_panel_parse_misc_host_config(&panel->host_config, utils, + panel->name); + if (rc) { + DSI_ERR("[%s] failed to parse misc host config, rc=%d\n", + panel->name, rc); + goto error; + } + + dsi_panel_parse_split_link_config(&panel->host_config, utils, + panel->name); + +error: + return rc; +} + +static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel, + struct device_node *of_node) +{ + int rc = 0; + u32 val = 0; + + rc = of_property_read_u32(of_node, + "qcom,mdss-dsi-qsync-min-refresh-rate", + &val); + if (rc) + DSI_DEBUG("[%s] qsync min fps not defined rc:%d\n", + panel->name, rc); + + panel->qsync_min_fps = val; + + return rc; +} + +static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel) +{ + int rc = 0; + bool supported = false; + struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps; + struct dsi_parser_utils *utils = &panel->utils; + const char *name = panel->name; + const char *type; + + supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable"); + + if (!supported) { + dyn_clk_caps->dyn_clk_support = false; + return rc; + } + + dyn_clk_caps->bit_clk_list_len = utils->count_u32_elems(utils->data, + "qcom,dsi-dyn-clk-list"); + + if (dyn_clk_caps->bit_clk_list_len < 1) { + DSI_ERR("[%s] failed to get supported bit clk list\n", name); + return -EINVAL; + } + + dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len, + sizeof(u32), GFP_KERNEL); + if (!dyn_clk_caps->bit_clk_list) + return -ENOMEM; + + rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list", + dyn_clk_caps->bit_clk_list, + dyn_clk_caps->bit_clk_list_len); + + if (rc) { + DSI_ERR("[%s] failed to parse supported bit clk list\n", name); + return -EINVAL; + } + + dyn_clk_caps->dyn_clk_support = true; + + type = utils->get_property(utils->data, + "qcom,dsi-dyn-clk-type", NULL); + if (!type) { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; + dyn_clk_caps->maintain_const_fps = false; + return 0; + } + if (!strcmp(type, "constant-fps-adjust-hfp")) { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP; + dyn_clk_caps->maintain_const_fps = true; + } else if (!strcmp(type, "constant-fps-adjust-vfp")) { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP; + dyn_clk_caps->maintain_const_fps = true; + } else { + dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY; + dyn_clk_caps->maintain_const_fps = false; + } + DSI_DEBUG("Dynamic clock type is [%s]\n", type); + return 0; +} + +static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel) +{ + int rc = 0; + bool supported = false; + struct dsi_dfps_capabilities *dfps_caps = &panel->dfps_caps; + struct dsi_parser_utils *utils = &panel->utils; + const char *name = panel->name; + const char *type; + u32 i; + + supported = utils->read_bool(utils->data, + "qcom,mdss-dsi-pan-enable-dynamic-fps"); + + if (!supported) { + DSI_DEBUG("[%s] DFPS is not supported\n", name); + dfps_caps->dfps_support = false; + return rc; + } + + type = utils->get_property(utils->data, + "qcom,mdss-dsi-pan-fps-update", NULL); + if (!type) { + DSI_ERR("[%s] dfps type not defined\n", name); + rc = -EINVAL; + goto error; + } else if (!strcmp(type, "dfps_suspend_resume_mode")) { + dfps_caps->type = DSI_DFPS_SUSPEND_RESUME; + } else if (!strcmp(type, "dfps_immediate_clk_mode")) { + dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK; + } else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) { + dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP; + } else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) { + dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP; + } else { + DSI_ERR("[%s] dfps type is not recognized\n", name); + rc = -EINVAL; + goto error; + } + + dfps_caps->dfps_list_len = utils->count_u32_elems(utils->data, + "qcom,dsi-supported-dfps-list"); + if (dfps_caps->dfps_list_len < 1) { + DSI_ERR("[%s] dfps refresh list not present\n", name); + rc = -EINVAL; + goto error; + } + + dfps_caps->dfps_list = kcalloc(dfps_caps->dfps_list_len, sizeof(u32), + GFP_KERNEL); + if (!dfps_caps->dfps_list) { + rc = -ENOMEM; + goto error; + } + + rc = utils->read_u32_array(utils->data, + "qcom,dsi-supported-dfps-list", + dfps_caps->dfps_list, + dfps_caps->dfps_list_len); + if (rc) { + DSI_ERR("[%s] dfps refresh rate list parse failed\n", name); + rc = -EINVAL; + goto error; + } + dfps_caps->dfps_support = true; + + /* calculate max and min fps */ + dfps_caps->max_refresh_rate = dfps_caps->dfps_list[0]; + dfps_caps->min_refresh_rate = dfps_caps->dfps_list[0]; + + for (i = 1; i < dfps_caps->dfps_list_len; i++) { + if (dfps_caps->dfps_list[i] < dfps_caps->min_refresh_rate) + dfps_caps->min_refresh_rate = dfps_caps->dfps_list[i]; + else if (dfps_caps->dfps_list[i] > dfps_caps->max_refresh_rate) + dfps_caps->max_refresh_rate = dfps_caps->dfps_list[i]; + } + +error: + return rc; +} + +static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, + struct dsi_parser_utils *utils, + const char *name) +{ + int rc = 0; + const char *traffic_mode; + u32 vc_id = 0; + u32 val = 0; + u32 line_no = 0; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-h-sync-pulse", &val); + if (rc) { + DSI_DEBUG("[%s] fallback to default h-sync-pulse\n", name); + cfg->pulse_mode_hsa_he = false; + } else if (val == 1) { + cfg->pulse_mode_hsa_he = true; + } else if (val == 0) { + cfg->pulse_mode_hsa_he = false; + } else { + DSI_ERR("[%s] Unrecognized value for mdss-dsi-h-sync-pulse\n", + name); + rc = -EINVAL; + goto error; + } + + cfg->hfp_lp11_en = utils->read_bool(utils->data, + "qcom,mdss-dsi-hfp-power-mode"); + + cfg->hbp_lp11_en = utils->read_bool(utils->data, + "qcom,mdss-dsi-hbp-power-mode"); + + cfg->hsa_lp11_en = utils->read_bool(utils->data, + "qcom,mdss-dsi-hsa-power-mode"); + + cfg->last_line_interleave_en = utils->read_bool(utils->data, + "qcom,mdss-dsi-last-line-interleave"); + + cfg->eof_bllp_lp11_en = utils->read_bool(utils->data, + "qcom,mdss-dsi-bllp-eof-power-mode"); + + cfg->bllp_lp11_en = utils->read_bool(utils->data, + "qcom,mdss-dsi-bllp-power-mode"); + + traffic_mode = utils->get_property(utils->data, + "qcom,mdss-dsi-traffic-mode", + NULL); + if (!traffic_mode) { + DSI_DEBUG("[%s] Falling back to default traffic mode\n", name); + cfg->traffic_mode = DSI_VIDEO_TRAFFIC_SYNC_PULSES; + } else if (!strcmp(traffic_mode, "non_burst_sync_pulse")) { + cfg->traffic_mode = DSI_VIDEO_TRAFFIC_SYNC_PULSES; + } else if (!strcmp(traffic_mode, "non_burst_sync_event")) { + cfg->traffic_mode = DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS; + } else if (!strcmp(traffic_mode, "burst_mode")) { + cfg->traffic_mode = DSI_VIDEO_TRAFFIC_BURST_MODE; + } else { + DSI_ERR("[%s] Unrecognized traffic mode-%s\n", name, + traffic_mode); + rc = -EINVAL; + goto error; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-virtual-channel-id", + &vc_id); + if (rc) { + DSI_DEBUG("[%s] Fallback to default vc id\n", name); + cfg->vc_id = 0; + } else { + cfg->vc_id = vc_id; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-dma-schedule-line", + &line_no); + if (rc) { + DSI_DEBUG("[%s] set default dma scheduling line no\n", name); + cfg->dma_sched_line = 0x1; + /* do not fail since we have default value */ + rc = 0; + } else { + cfg->dma_sched_line = line_no; + } + +error: + return rc; +} + +static int dsi_panel_parse_cmd_host_config(struct dsi_cmd_engine_cfg *cfg, + struct dsi_parser_utils *utils, + const char *name) +{ + u32 val = 0; + int rc = 0; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-wr-mem-start", &val); + if (rc) { + DSI_DEBUG("[%s] Fallback to default wr-mem-start\n", name); + cfg->wr_mem_start = 0x2C; + } else { + cfg->wr_mem_start = val; + } + + val = 0; + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-wr-mem-continue", + &val); + if (rc) { + DSI_DEBUG("[%s] Fallback to default wr-mem-continue\n", name); + cfg->wr_mem_continue = 0x3C; + } else { + cfg->wr_mem_continue = val; + } + + /* TODO: fix following */ + cfg->max_cmd_packets_interleave = 0; + + val = 0; + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-te-dcs-command", + &val); + if (rc) { + DSI_DEBUG("[%s] fallback to default te-dcs-cmd\n", name); + cfg->insert_dcs_command = true; + } else if (val == 1) { + cfg->insert_dcs_command = true; + } else if (val == 0) { + cfg->insert_dcs_command = false; + } else { + DSI_ERR("[%s] Unrecognized value for mdss-dsi-te-dcs-command\n", + name); + rc = -EINVAL; + goto error; + } + +error: + return rc; +} + +static int dsi_panel_parse_panel_mode(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_parser_utils *utils = &panel->utils; + bool panel_mode_switch_enabled; + enum dsi_op_mode panel_mode; + const char *mode; + + mode = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-type", NULL); + if (!mode) { + DSI_DEBUG("[%s] Fallback to default panel mode\n", panel->name); + panel_mode = DSI_OP_VIDEO_MODE; + } else if (!strcmp(mode, "dsi_video_mode")) { + panel_mode = DSI_OP_VIDEO_MODE; + } else if (!strcmp(mode, "dsi_cmd_mode")) { + panel_mode = DSI_OP_CMD_MODE; + } else { + DSI_ERR("[%s] Unrecognized panel type-%s\n", panel->name, mode); + rc = -EINVAL; + goto error; + } + + panel_mode_switch_enabled = utils->read_bool(utils->data, + "qcom,mdss-dsi-panel-mode-switch"); + + DSI_DEBUG("%s: panel operating mode switch feature %s\n", __func__, + (panel_mode_switch_enabled ? "enabled" : "disabled")); + + if (panel_mode == DSI_OP_VIDEO_MODE || panel_mode_switch_enabled) { + rc = dsi_panel_parse_video_host_config(&panel->video_config, + utils, + panel->name); + if (rc) { + DSI_ERR("[%s] Failed to parse video host cfg, rc=%d\n", + panel->name, rc); + goto error; + } + } + + if (panel_mode == DSI_OP_CMD_MODE || panel_mode_switch_enabled) { + rc = dsi_panel_parse_cmd_host_config(&panel->cmd_config, + utils, + panel->name); + if (rc) { + DSI_ERR("[%s] Failed to parse cmd host config, rc=%d\n", + panel->name, rc); + goto error; + } + } + + panel->panel_mode = panel_mode; + panel->panel_mode_switch_enabled = panel_mode_switch_enabled; +error: + return rc; +} + +static int dsi_panel_parse_phy_props(struct dsi_panel *panel) +{ + int rc = 0; + u32 val = 0; + const char *str; + struct dsi_panel_phy_props *props = &panel->phy_props; + struct dsi_parser_utils *utils = &panel->utils; + const char *name = panel->name; + + rc = utils->read_u32(utils->data, + "qcom,mdss-pan-physical-width-dimension", &val); + if (rc) { + DSI_DEBUG("[%s] Physical panel width is not defined\n", name); + props->panel_width_mm = 0; + rc = 0; + } else { + props->panel_width_mm = val; + } + + rc = utils->read_u32(utils->data, + "qcom,mdss-pan-physical-height-dimension", + &val); + if (rc) { + DSI_DEBUG("[%s] Physical panel height is not defined\n", name); + props->panel_height_mm = 0; + rc = 0; + } else { + props->panel_height_mm = val; + } + + str = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-orientation", NULL); + if (!str) { + props->rotation = DSI_PANEL_ROTATE_NONE; + } else if (!strcmp(str, "180")) { + props->rotation = DSI_PANEL_ROTATE_HV_FLIP; + } else if (!strcmp(str, "hflip")) { + props->rotation = DSI_PANEL_ROTATE_H_FLIP; + } else if (!strcmp(str, "vflip")) { + props->rotation = DSI_PANEL_ROTATE_V_FLIP; + } else { + DSI_ERR("[%s] Unrecognized panel rotation-%s\n", name, str); + rc = -EINVAL; + goto error; + } +error: + return rc; +} +const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { + "qcom,mdss-dsi-pre-on-command", + "qcom,mdss-dsi-on-command", + "qcom,mdss-dsi-sp-on-command", + "qcom,mdss-dsi-sp-off-command", + "qcom,mdss-dsi-post-panel-on-command", + "qcom,mdss-dsi-pre-off-command", + "qcom,mdss-dsi-off-command", + "qcom,mdss-dsi-post-off-command", + "qcom,mdss-dsi-pre-res-switch", + "qcom,mdss-dsi-res-switch", + "qcom,mdss-dsi-post-res-switch", + "qcom,cmd-to-video-mode-switch-commands", + "qcom,cmd-to-video-mode-post-switch-commands", + "qcom,video-to-cmd-mode-switch-commands", + "qcom,video-to-cmd-mode-post-switch-commands", + "qcom,mdss-dsi-panel-status-command", + "qcom,mdss-dsi-lp1-command", + "qcom,mdss-dsi-lp2-command", + "qcom,mdss-dsi-nolp-command", + "PPS not parsed from DTSI, generated dynamically", + "ROI not parsed from DTSI, generated dynamically", + "qcom,mdss-dsi-timing-switch-command", + "qcom,mdss-dsi-post-mode-switch-on-command", + "qcom,mdss-dsi-qsync-on-commands", + "qcom,mdss-dsi-qsync-off-commands", + "qcom,mdss-dsi-panel-hbm-brightness-on-command", + "qcom,mdss-dsi-panel-hbm-brightness-off-command", + "qcom,mdss-dsi-panel-seed-lp-on-command-0", + "qcom,mdss-dsi-panel-seed-lp-on-command-1", + "qcom,mdss-dsi-panel-seed-lp-on-command-2", + "qcom,mdss-dsi-panel-seed-lp-off-command", + "qcom,mdss-dsi-panel-hbm-on-command-1", + "qcom,mdss-dsi-panel-hbm-on-command-2", + "qcom,mdss-dsi-panel-hbm-on-command-3", + "qcom,mdss-dsi-panel-hbm-on-command-4", + "qcom,mdss-dsi-panel-hbm-on-command-5", + "qcom,mdss-dsi-panel-hbm-off-command", + "qcom,mdss-dsi-panel-serial-num-command", + "qcom,mdss-dsi-panel-aod-on-command-1", + "qcom,mdss-dsi-panel-aod-on-command-2", + "qcom,mdss-dsi-panel-aod-on-command-3", + "qcom,mdss-dsi-panel-aod-on-command-4", + "qcom,mdss-dsi-panel-aod-on-command-5", + "qcom,mdss-dsi-panel-aod-off-command", + "qcom,mdss-dsi-panel-aod-off-hbm-on-command", + "qcom,mdss-dsi-panel-aod-off-new-command", + "qcom,mdss-dsi-panel-hbm-off-aod-on-command", + "qcom,mdss-dsi-panel-real-aod-off-hbm-on-command", + "qcom,mdss-dsi-panel-aod-off-samsung-command", + "qcom,mdss-dsi-panel-dci-p3-on-command", + "qcom,mdss-dsi-panel-dci-p3-off-command", + "qcom,mdss-dsi-panel-night-mode-on-command", + "qcom,mdss-dsi-panel-night-mode-off-command", + "qcom,mdss-dsi-panel-id-command", + "qcom,mdss-dsi-panel-read-register-open-command", + "qcom,mdss-dsi-panel-read-register-ed-command", + "qcom,mdss-dsi-panel-read-register-sp-on-command", + "qcom,mdss-dsi-panel-id1-command", + "qcom,mdss-dsi-panel-id2-command", + "qcom,mdss-dsi-panel-id3-command", + "qcom,mdss-dsi-panel-id4-command", + "qcom,mdss-dsi-panel-id5-command", + "qcom,mdss-dsi-panel-id6-command", + "qcom,mdss-dsi-panel-id7-command", + "qcom,mdss-dsi-panel-check-info-command", + "qcom,mdss-dsi-panel-get-sp-level-command", + "qcom,mdss-dsi-panel-read-register-close-command", + "qcom,mdss-dsi-acl-command", + "qcom,mdss-dsi-panel-read-ic_v-register-open-command", + "qcom,mdss-dsi-panel-ic_v-command", + "qcom,mdss-dsi-panel-read-ic_v-register-close-command", + "qcom,mdss-dsi-panel-serial-num-pre-command", + "qcom,mdss-dsi-panel-serial-num-post-command", + "qcom,mdss-dsi-panel-code-info-command", + "qcom,mdss-dsi-panel-stage-info-command", + "qcom,mdss-dsi-panel-production-info-command", + "qcom,mdss-dsi-panel-read-esd-registed-longread-command", + "qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command", + "qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command", + "qcom,mdss-dsi-panel-gamma-flash-read-fb-command", + "qcom,mdss-dsi-panel-level2-key-enable-command", + "qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command", + "qcom,mdss-dsi-panel-gamma-otp-read-c8-command", + "qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command", + "qcom,mdss-dsi-panel-gamma-otp-read-c9-command", + "qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command", + "qcom,mdss-dsi-panel-gamma-otp-read-b3-command", + "qcom,mdss-dsi-panel-level2-key-disable-command", + "qcom,mdss-dsi-panel-display-p3-mode-on-command", + "qcom,mdss-dsi-panel-display-p3-mode-off-command", + "qcom,mdss-dsi-panel-display-wide-color-mode-on-command", + "qcom,mdss-dsi-panel-display-wide-color-mode-off-command", + "qcom,mdss-dsi-panel-display-srgb-color-mode-on-command", + "qcom,mdss-dsi-panel-display-srgb-color-mode-off-command", + "qcom,mdss-113mhz-osc-dsi-on-command", + "qcom,mdss-dsi-post-on-backlight", + "qcom,mdss-dsi-loading-effect-enable-command", + "qcom,mdss-dsi-loading-effect-disable-command", + "qcom,mdss-dsi-customer-srgb-enable-command", + "qcom,mdss-dsi-customer-srgb-disable-command", + "qcom,mdss-dsi-customer-p3-enable-command", + "qcom,mdss-dsi-customer-p3-disable-command", + "qcom,mdss-dsi-panel-command", + "qcom,mdss-dsi-seed-command", + "qcom,mdss-dsi-panel-display-p3-mode-low-backlight-on-command", + "qcom,mdss-dsi-panel-display-wide-color-mode-low-backlight-on-command", + "qcom,mdss-dsi-panel-display-srgb-color-mode-low-backlight-on-command", + "qcom,mdss-dsi-customer-srgb-low-backlight-enable-command", + "qcom,mdss-dsi-customer-p3-low-backlight-enable-command", +}; + +const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { + "qcom,mdss-dsi-pre-on-command-state", + "qcom,mdss-dsi-on-command-state", + "qcom,mdss-dsi-sp-on-command-state", + "qcom,mdss-dsi-sp-off-command-state", + "qcom,mdss-dsi-post-on-command-state", + "qcom,mdss-dsi-pre-off-command-state", + "qcom,mdss-dsi-off-command-state", + "qcom,mdss-dsi-post-off-command-state", + "qcom,mdss-dsi-pre-res-switch-state", + "qcom,mdss-dsi-res-switch-state", + "qcom,mdss-dsi-post-res-switch-state", + "qcom,cmd-to-video-mode-switch-commands-state", + "qcom,cmd-to-video-mode-post-switch-commands-state", + "qcom,video-to-cmd-mode-switch-commands-state", + "qcom,video-to-cmd-mode-post-switch-commands-state", + "qcom,mdss-dsi-panel-status-command-state", + "qcom,mdss-dsi-lp1-command-state", + "qcom,mdss-dsi-lp2-command-state", + "qcom,mdss-dsi-nolp-command-state", + "PPS not parsed from DTSI, generated dynamically", + "ROI not parsed from DTSI, generated dynamically", + "qcom,mdss-dsi-timing-switch-command-state", + "qcom,mdss-dsi-post-mode-switch-on-command-state", + "qcom,mdss-dsi-qsync-on-commands-state", + "qcom,mdss-dsi-qsync-off-commands-state", + "qcom,mdss-dsi-panel-hbm-brightness-on-command-state", + "qcom,mdss-dsi-panel-hbm-brightness-off-command-state", + "qcom,mdss-dsi-panel-seed-lp-on-command-0-state", + "qcom,mdss-dsi-panel-seed-lp-on-command-1-state", + "qcom,mdss-dsi-panel-seed-lp-on-command-2-state", + "qcom,mdss-dsi-panel-seed-lp-off-command-state", + "qcom,mdss-dsi-panel-hbm-on-command-1-state", + "qcom,mdss-dsi-panel-hbm-on-command-2-state", + "qcom,mdss-dsi-panel-hbm-on-command-3-state", + "qcom,mdss-dsi-panel-hbm-on-command-4-state", + "qcom,mdss-dsi-panel-hbm-on-command-5-state", + "qcom,mdss-dsi-panel-hbm-off-command-state", + "qcom,mdss-dsi-panel-serial-num-command-state", + "qcom,mdss-dsi-panel-aod-on-command-1-state", + "qcom,mdss-dsi-panel-aod-on-command-2-state", + "qcom,mdss-dsi-panel-aod-on-command-3-state", + "qcom,mdss-dsi-panel-aod-on-command-4-state", + "qcom,mdss-dsi-panel-aod-on-command-5-state", + "qcom,mdss-dsi-panel-aod-off-command-state", + "qcom,mdss-dsi-panel-aod-off-hbm-on-command-state", + "qcom,mdss-dsi-panel-aod-off-new-command-state", + "qcom,mdss-dsi-panel-hbm-off-aod-on-command-state", + "qcom,mdss-dsi-panel-real-aod-off-hbm-on-command-state", + "qcom,mdss-dsi-panel-aod-off-samsung-command-state", + "qcom,mdss-dsi-panel-dci-p3-on-command-state", + "qcom,mdss-dsi-panel-dci-p3-off-command-state", + "qcom,mdss-dsi-panel-night-mode-on-command-state", + "qcom,mdss-dsi-panel-night-mode-off-command-state", + "qcom,mdss-dsi-panel-id-command-state", + "qcom,mdss-dsi-panel-read-register-open-command-state", + "qcom,mdss-dsi-panel-read-register-ed-command-state", + "qcom,mdss-dsi-panel-read-register-sp-on-command-state", + "qcom,mdss-dsi-panel-id1-command-state", + "qcom,mdss-dsi-panel-id2-command-state", + "qcom,mdss-dsi-panel-id3-command-state", + "qcom,mdss-dsi-panel-id4-command-state", + "qcom,mdss-dsi-panel-id5-command-state", + "qcom,mdss-dsi-panel-id6-command-state", + "qcom,mdss-dsi-panel-id7-command-state", + "qcom,mdss-dsi-panel-check-info-command-state", + "qcom,mdss-dsi-panel-get-sp-level-command-state", + "qcom,mdss-dsi-panel-read-register-close-command-state", + "qcom,mdss-dsi-acl-command-state", + "qcom,mdss-dsi-panel-read-ic_v-register-open-command-state", + "qcom,mdss-dsi-panel-ic_v-command-state", + "qcom,mdss-dsi-panel-read-ic_v-register-close-command-state", + "qcom,mdss-dsi-panel-serial-num-pre-command-state", + "qcom,mdss-dsi-panel-serial-num-post-command-state", + "qcom,mdss-dsi-panel-code-info-command-state", + "qcom,mdss-dsi-panel-stage-info-command-state", + "qcom,mdss-dsi-panel-production-info-command-state", + "qcom,mdss-dsi-panel-read-esd-registed-longread-command-state", + "qcom,mdss-dsi-panel-gamma-flash-pre-read-1-command-state", + "qcom,mdss-dsi-panel-gamma-flash-pre-read-2-command-state", + "qcom,mdss-dsi-panel-gamma-flash-read-fb-command-state", + "qcom,mdss-dsi-panel-level2-key-enable-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-c8-smrps-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-c8-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-c9-smrps-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-c9-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-b3-smrps-command-state", + "qcom,mdss-dsi-panel-gamma-otp-read-b3-command-state", + "qcom,mdss-dsi-panel-level2-key-disable-command-state", + "qcom,mdss-dsi-panel-display-p3-mode-on-command-state", + "qcom,mdss-dsi-panel-display-p3-mode-off-command-state", + "qcom,mdss-dsi-panel-display-wide-color-mode-on-command-state", + "qcom,mdss-dsi-panel-display-wide-color-mode-off-command-state", + "qcom,mdss-dsi-panel-display-srgb-color-mode-on-command-state", + "qcom,mdss-dsi-panel-display-srgb-color-mode-off-command-state", + "qcom,mdss-113mhz-osc-dsi-on-command-state", + "qcom,mdss-dsi-post-on-backlight-state", + "qcom,mdss-dsi-loading-effect-enable-command-state", + "qcom,mdss-dsi-loading-effect-disable-command-state", + "qcom,mdss-dsi-customer-srgb-enable-command-state", + "qcom,mdss-dsi-customer-srgb-disable-command-state", + "qcom,mdss-dsi-customer-p3-enable-command-state", + "qcom,mdss-dsi-customer-p3-disable-command-state", + "qcom,mdss-dsi-panel-command-state", + "qcom,mdss-dsi-seed-command-state", + "qcom,mdss-dsi-panel-display-p3-mode-low-backlight_on-command-state", + "qcom,mdss-dsi-panel-display-wide-color-mode-low-backlight-on-command-state", + "qcom,mdss-dsi-panel-display-srgb-color-mode-low-backlight-on-command-state", + "qcom,mdss-dsi-customer-srgb-low-backlight-enable-command-state", + "qcom,mdss-dsi-customer-p3-low-backlight-enable-command-state", +}; + +static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt) +{ + const u32 cmd_set_min_size = 7; + u32 count = 0; + u32 packet_length; + u32 tmp; + + while (length >= cmd_set_min_size) { + packet_length = cmd_set_min_size; + tmp = ((data[5] << 8) | (data[6])); + packet_length += tmp; + if (packet_length > length) { + DSI_ERR("format error\n"); + return -EINVAL; + } + length -= packet_length; + data += packet_length; + count++; + } + + *cnt = count; + return 0; +} + +static int dsi_panel_create_cmd_packets(const char *data, + u32 length, + u32 count, + struct dsi_cmd_desc *cmd) +{ + int rc = 0; + int i, j; + u8 *payload; + + for (i = 0; i < count; i++) { + u32 size; + + cmd[i].msg.type = data[0]; + cmd[i].last_command = (data[1] == 1); + cmd[i].msg.channel = data[2]; + cmd[i].msg.flags |= (data[3] == 1 ? MIPI_DSI_MSG_REQ_ACK : 0); + cmd[i].msg.ctrl = 0; + cmd[i].post_wait_ms = cmd[i].msg.wait_ms = data[4]; + cmd[i].msg.tx_len = ((data[5] << 8) | (data[6])); + + size = cmd[i].msg.tx_len * sizeof(u8); + + payload = kzalloc(size, GFP_KERNEL); + if (!payload) { + rc = -ENOMEM; + goto error_free_payloads; + } + + for (j = 0; j < cmd[i].msg.tx_len; j++) + payload[j] = data[7 + j]; + + cmd[i].msg.tx_buf = payload; + data += (7 + cmd[i].msg.tx_len); + } + + return rc; +error_free_payloads: + for (i = i - 1; i >= 0; i--) { + cmd--; + kfree(cmd->msg.tx_buf); + } + + return rc; +} + +static void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) +{ + u32 i = 0; + struct dsi_cmd_desc *cmd; + + for (i = 0; i < set->count; i++) { + cmd = &set->cmds[i]; + kfree(cmd->msg.tx_buf); + } +} + +static void dsi_panel_dealloc_cmd_packets(struct dsi_panel_cmd_set *set) +{ + kfree(set->cmds); +} + +static int dsi_panel_alloc_cmd_packets(struct dsi_panel_cmd_set *cmd, + u32 packet_count) +{ + u32 size; + + size = packet_count * sizeof(*cmd->cmds); + cmd->cmds = kzalloc(size, GFP_KERNEL); + if (!cmd->cmds) + return -ENOMEM; + + cmd->count = packet_count; + return 0; +} + +static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, + enum dsi_cmd_set_type type, + struct dsi_parser_utils *utils) +{ + int rc = 0; + u32 length = 0; + const char *data; + const char *state; + u32 packet_count = 0; + + data = utils->get_property(utils->data, cmd_set_prop_map[type], + &length); + if (!data) { + DSI_DEBUG("%s commands not defined\n", cmd_set_prop_map[type]); + rc = -ENOTSUPP; + goto error; + } + + DSI_DEBUG("type=%d, name=%s, length=%d\n", type, + cmd_set_prop_map[type], length); + + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 8, 1, data, length, false); + + rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count); + if (rc) { + DSI_ERR("commands failed, rc=%d\n", rc); + goto error; + } + DSI_DEBUG("[%s] packet-count=%d, %d\n", cmd_set_prop_map[type], + packet_count, length); + + rc = dsi_panel_alloc_cmd_packets(cmd, packet_count); + if (rc) { + DSI_ERR("failed to allocate cmd packets, rc=%d\n", rc); + goto error; + } + + rc = dsi_panel_create_cmd_packets(data, length, packet_count, + cmd->cmds); + if (rc) { + DSI_ERR("failed to create cmd packets, rc=%d\n", rc); + goto error_free_mem; + } + + state = utils->get_property(utils->data, cmd_set_state_map[type], NULL); + if (!state || !strcmp(state, "dsi_lp_mode")) { + cmd->state = DSI_CMD_SET_STATE_LP; + } else if (!strcmp(state, "dsi_hs_mode")) { + cmd->state = DSI_CMD_SET_STATE_HS; + } else { + DSI_ERR("[%s] command state unrecognized-%s\n", + cmd_set_state_map[type], state); + goto error_free_mem; + } + + return rc; +error_free_mem: + kfree(cmd->cmds); + cmd->cmds = NULL; +error: + return rc; + +} + +static int dsi_panel_parse_cmd_sets( + struct dsi_display_mode_priv_info *priv_info, + struct dsi_parser_utils *utils) +{ + int rc = 0; + struct dsi_panel_cmd_set *set; + u32 i; + + if (!priv_info) { + DSI_ERR("invalid mode priv info\n"); + return -EINVAL; + } + + for (i = DSI_CMD_SET_PRE_ON; i < DSI_CMD_SET_MAX; i++) { + set = &priv_info->cmd_sets[i]; + set->type = i; + set->count = 0; + + if (i == DSI_CMD_SET_PPS) { + rc = dsi_panel_alloc_cmd_packets(set, 1); + if (rc) + DSI_ERR("failed to allocate cmd set %d, rc = %d\n", + i, rc); + set->state = DSI_CMD_SET_STATE_LP; + } else { + rc = dsi_panel_parse_cmd_sets_sub(set, i, utils); + if (rc) + DSI_DEBUG("failed to parse set %d\n", i); + } + } + + rc = 0; + return rc; +} + +static int dsi_panel_parse_reset_sequence(struct dsi_panel *panel) +{ + int rc = 0; + int i; + u32 length = 0; + u32 count = 0; + u32 size = 0; + u32 *arr_32 = NULL; + const u32 *arr; + struct dsi_parser_utils *utils = &panel->utils; + struct dsi_reset_seq *seq; + + if (panel->host_config.ext_bridge_mode) + return 0; + + arr = utils->get_property(utils->data, + "qcom,mdss-dsi-reset-sequence", &length); + if (!arr) { + DSI_ERR("[%s] dsi-reset-sequence not found\n", panel->name); + rc = -EINVAL; + goto error; + } + if (length & 0x1) { + DSI_ERR("[%s] syntax error for dsi-reset-sequence\n", + panel->name); + rc = -EINVAL; + goto error; + } + + DSI_DEBUG("RESET SEQ LENGTH = %d\n", length); + length = length / sizeof(u32); + + size = length * sizeof(u32); + + arr_32 = kzalloc(size, GFP_KERNEL); + if (!arr_32) { + rc = -ENOMEM; + goto error; + } + + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-reset-sequence", + arr_32, length); + if (rc) { + DSI_ERR("[%s] cannot read dso-reset-seqience\n", panel->name); + goto error_free_arr_32; + } + + count = length / 2; + size = count * sizeof(*seq); + seq = kzalloc(size, GFP_KERNEL); + if (!seq) { + rc = -ENOMEM; + goto error_free_arr_32; + } + + panel->reset_config.sequence = seq; + panel->reset_config.count = count; + + for (i = 0; i < length; i += 2) { + seq->level = arr_32[i]; + seq->sleep_ms = arr_32[i + 1]; + seq++; + } + + +error_free_arr_32: + kfree(arr_32); +error: + return rc; +} + +static int dsi_panel_parse_misc_features(struct dsi_panel *panel) +{ + struct dsi_parser_utils *utils = &panel->utils; + + panel->ulps_feature_enabled = + utils->read_bool(utils->data, "qcom,ulps-enabled"); + + DSI_DEBUG("%s: ulps feature %s\n", __func__, + (panel->ulps_feature_enabled ? "enabled" : "disabled")); + + panel->ulps_suspend_enabled = + utils->read_bool(utils->data, "qcom,suspend-ulps-enabled"); + + DSI_DEBUG("%s: ulps during suspend feature %s\n", __func__, + (panel->ulps_suspend_enabled ? "enabled" : "disabled")); + + panel->te_using_watchdog_timer = utils->read_bool(utils->data, + "qcom,mdss-dsi-te-using-wd"); + + panel->sync_broadcast_en = utils->read_bool(utils->data, + "qcom,cmd-sync-wait-broadcast"); + + panel->lp11_init = utils->read_bool(utils->data, + "qcom,mdss-dsi-lp11-init"); + + panel->reset_gpio_always_on = utils->read_bool(utils->data, + "qcom,platform-reset-gpio-always-on"); + + return 0; +} + +static int dsi_panel_parse_jitter_config( + struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + int rc; + struct dsi_display_mode_priv_info *priv_info; + u32 jitter[DEFAULT_PANEL_JITTER_ARRAY_SIZE] = {0, 0}; + u64 jitter_val = 0; + + priv_info = mode->priv_info; + + rc = utils->read_u32_array(utils->data, "qcom,mdss-dsi-panel-jitter", + jitter, DEFAULT_PANEL_JITTER_ARRAY_SIZE); + if (rc) { + DSI_DEBUG("panel jitter not defined rc=%d\n", rc); + } else { + jitter_val = jitter[0]; + jitter_val = div_u64(jitter_val, jitter[1]); + } + + if (rc || !jitter_val || (jitter_val > MAX_PANEL_JITTER)) { + priv_info->panel_jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; + priv_info->panel_jitter_denom = + DEFAULT_PANEL_JITTER_DENOMINATOR; + } else { + priv_info->panel_jitter_numer = jitter[0]; + priv_info->panel_jitter_denom = jitter[1]; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-panel-prefill-lines", + &priv_info->panel_prefill_lines); + if (rc) { + DSI_DEBUG("panel prefill lines are not defined rc=%d\n", rc); + priv_info->panel_prefill_lines = mode->timing.v_back_porch + + mode->timing.v_sync_width + mode->timing.v_front_porch; + } else if (priv_info->panel_prefill_lines >= + DSI_V_TOTAL(&mode->timing)) { + DSI_DEBUG("invalid prefill lines config=%d setting to:%d\n", + priv_info->panel_prefill_lines, DEFAULT_PANEL_PREFILL_LINES); + + priv_info->panel_prefill_lines = DEFAULT_PANEL_PREFILL_LINES; + } + + return 0; +} + +static int dsi_panel_parse_power_cfg(struct dsi_panel *panel) +{ + int rc = 0; + char *supply_name; + + if (panel->host_config.ext_bridge_mode) + return 0; + + if (!strcmp(panel->type, "primary")) + supply_name = "qcom,panel-supply-entries"; + else + supply_name = "qcom,panel-sec-supply-entries"; + + rc = dsi_pwr_of_get_vreg_data(&panel->utils, + &panel->power_info, supply_name); + if (rc) { + DSI_ERR("[%s] failed to parse vregs\n", panel->name); + goto error; + } + +error: + return rc; +} + +static int dsi_panel_parse_gpios(struct dsi_panel *panel) +{ + int rc = 0; + const char *data; + struct dsi_parser_utils *utils = &panel->utils; + char *reset_gpio_name, *mode_set_gpio_name; + + if (!strcmp(panel->type, "primary")) { + reset_gpio_name = "qcom,platform-reset-gpio"; + mode_set_gpio_name = "qcom,panel-mode-gpio"; + } else { + reset_gpio_name = "qcom,platform-sec-reset-gpio"; + mode_set_gpio_name = "qcom,panel-sec-mode-gpio"; + } + + panel->reset_config.reset_gpio = utils->get_named_gpio(utils->data, + reset_gpio_name, 0); + if (!gpio_is_valid(panel->reset_config.reset_gpio) && + !panel->host_config.ext_bridge_mode) { + rc = panel->reset_config.reset_gpio; + DSI_ERR("[%s] failed get reset gpio, rc=%d\n", panel->name, rc); + goto error; + } + + panel->reset_config.disp_en_gpio = utils->get_named_gpio(utils->data, + "qcom,5v-boost-gpio", + 0); + if (!gpio_is_valid(panel->reset_config.disp_en_gpio)) { + DSI_DEBUG("[%s] 5v-boot-gpio is not set, rc=%d\n", + panel->name, rc); + panel->reset_config.disp_en_gpio = + utils->get_named_gpio(utils->data, + "qcom,platform-en-gpio", 0); + if (!gpio_is_valid(panel->reset_config.disp_en_gpio)) { + DSI_DEBUG("[%s] platform-en-gpio is not set, rc=%d\n", + panel->name, rc); + } + } + + panel->reset_config.lcd_mode_sel_gpio = utils->get_named_gpio( + utils->data, mode_set_gpio_name, 0); + if (!gpio_is_valid(panel->reset_config.lcd_mode_sel_gpio)) + DSI_DEBUG("mode gpio not specified\n"); + + DSI_DEBUG("mode gpio=%d\n", panel->reset_config.lcd_mode_sel_gpio); + + data = utils->get_property(utils->data, + "qcom,mdss-dsi-mode-sel-gpio-state", NULL); + if (data) { + if (!strcmp(data, "single_port")) + panel->reset_config.mode_sel_state = + MODE_SEL_SINGLE_PORT; + else if (!strcmp(data, "dual_port")) + panel->reset_config.mode_sel_state = + MODE_SEL_DUAL_PORT; + else if (!strcmp(data, "high")) + panel->reset_config.mode_sel_state = + MODE_GPIO_HIGH; + else if (!strcmp(data, "low")) + panel->reset_config.mode_sel_state = + MODE_GPIO_LOW; + } else { + /* Set default mode as SPLIT mode */ + panel->reset_config.mode_sel_state = MODE_SEL_DUAL_PORT; + } + + /* TODO: release memory */ + rc = dsi_panel_parse_reset_sequence(panel); + if (rc) { + DSI_ERR("[%s] failed to parse reset sequence, rc=%d\n", + panel->name, rc); + goto error; + } + + panel->panel_test_gpio = utils->get_named_gpio(utils->data, + "qcom,mdss-dsi-panel-test-pin", + 0); + if (!gpio_is_valid(panel->panel_test_gpio)) + DSI_DEBUG("%s:%d panel test gpio not specified\n", __func__, + __LINE__); + +error: + return rc; +} + +static int dsi_panel_parse_bl_pwm_config(struct dsi_panel *panel) +{ + int rc = 0; + u32 val; + struct dsi_backlight_config *config = &panel->bl_config; + struct dsi_parser_utils *utils = &panel->utils; + + rc = utils->read_u32(utils->data, "qcom,bl-pmic-pwm-period-usecs", + &val); + if (rc) { + DSI_ERR("bl-pmic-pwm-period-usecs is not defined, rc=%d\n", rc); + goto error; + } + config->pwm_period_usecs = val; + +error: + return rc; +} + +static int dsi_panel_parse_bl_config(struct dsi_panel *panel) +{ + int rc = 0; + u32 val = 0; + const char *bl_type; + const char *data; + struct dsi_parser_utils *utils = &panel->utils; + char *bl_name; + + if (!strcmp(panel->type, "primary")) + bl_name = "qcom,mdss-dsi-bl-pmic-control-type"; + else + bl_name = "qcom,mdss-dsi-sec-bl-pmic-control-type"; + + bl_type = utils->get_property(utils->data, bl_name, NULL); + if (!bl_type) { + panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN; + } else if (!strcmp(bl_type, "bl_ctrl_pwm")) { + panel->bl_config.type = DSI_BACKLIGHT_PWM; + } else if (!strcmp(bl_type, "bl_ctrl_wled")) { + panel->bl_config.type = DSI_BACKLIGHT_WLED; + } else if (!strcmp(bl_type, "bl_ctrl_dcs")) { + panel->bl_config.type = DSI_BACKLIGHT_DCS; + } else if (!strcmp(bl_type, "bl_ctrl_external")) { + panel->bl_config.type = DSI_BACKLIGHT_EXTERNAL; + } else { + DSI_DEBUG("[%s] bl-pmic-control-type unknown-%s\n", + panel->name, bl_type); + panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN; + } + + data = utils->get_property(utils->data, "qcom,bl-update-flag", NULL); + if (!data) { + panel->bl_config.bl_update = BL_UPDATE_NONE; + } else if (!strcmp(data, "delay_until_first_frame")) { + panel->bl_config.bl_update = BL_UPDATE_DELAY_UNTIL_FIRST_FRAME; + } else { + DSI_DEBUG("[%s] No valid bl-update-flag: %s\n", + panel->name, data); + panel->bl_config.bl_update = BL_UPDATE_NONE; + } + + panel->bl_config.bl_scale = MAX_BL_SCALE_LEVEL; + panel->bl_config.bl_scale_sv = MAX_SV_BL_SCALE_LEVEL; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bl-min-level", &val); + if (rc) { + DSI_DEBUG("[%s] bl-min-level unspecified, defaulting to zero\n", + panel->name); + panel->bl_config.bl_min_level = 0; + } else { + panel->bl_config.bl_min_level = val; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bl-max-level", &val); + if (rc) { + DSI_DEBUG("[%s] bl-max-level unspecified, defaulting to max level\n", + panel->name); + panel->bl_config.bl_max_level = MAX_BL_LEVEL; + } else { + panel->bl_config.bl_max_level = val; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-brightness-default-val", &val); + if (rc) { + DSI_DEBUG("[%s] brightness-default-val unspecified, defaulting to val\n", + panel->name); + panel->bl_config.bl_def_val = 200; + } else { + panel->bl_config.bl_def_val = val; + } + DSI_ERR("default backlight bl_def_val= %d\n",panel->bl_config.bl_def_val); + rc = utils->read_u32(utils->data, "qcom,mdss-brightness-max-level", + &val); + if (rc) { + DSI_DEBUG("[%s] brigheness-max-level unspecified, defaulting to 255\n", + panel->name); + panel->bl_config.brightness_max_level = 255; + } else { + panel->bl_config.brightness_max_level = val; + } + + panel->bl_config.bl_inverted_dbv = utils->read_bool(utils->data, + "qcom,mdss-dsi-bl-inverted-dbv"); + + if (panel->bl_config.type == DSI_BACKLIGHT_PWM) { + rc = dsi_panel_parse_bl_pwm_config(panel); + if (rc) { + DSI_ERR("[%s] failed to parse pwm config, rc=%d\n", + panel->name, rc); + goto error; + } + } + + panel->bl_config.en_gpio = utils->get_named_gpio(utils->data, + "qcom,platform-bklight-en-gpio", + 0); + if (!gpio_is_valid(panel->bl_config.en_gpio)) { + if (panel->bl_config.en_gpio == -EPROBE_DEFER) { + DSI_DEBUG("[%s] failed to get bklt gpio, rc=%d\n", + panel->name, rc); + rc = -EPROBE_DEFER; + goto error; + } else { + DSI_DEBUG("[%s] failed to get bklt gpio, rc=%d\n", + panel->name, rc); + rc = 0; + goto error; + } + } + +error: + return rc; +} + +void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width) +{ + int slice_per_pkt, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + + if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || + (intf_width < dsc->slice_width)) { + DSI_ERR("invalid input, intf_width=%d slice_width=%d\n", + intf_width, dsc ? dsc->slice_width : -1); + return; + } + + slice_per_pkt = dsc->slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); + + /* + * If slice_per_pkt is greater than slice_per_intf then default to 1. + * This can happen during partial update. + */ + if (slice_per_pkt > slice_per_intf) + slice_per_pkt = 1; + + bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + dsc->eol_byte_num = total_bytes_per_intf % 3; + dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc->bytes_in_slice = bytes_in_slice; + dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; + dsc->pkt_per_line = slice_per_intf / slice_per_pkt; +} + + +int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc) +{ + int bpp, bpc; + int mux_words_size; + int groups_per_line, groups_total; + int min_rate_buffer_size; + int hrd_delay; + int pre_num_extra_mux_bits, num_extra_mux_bits; + int slice_bits; + int data; + int final_value, final_scale; + int ratio_index, mod_offset; + + dsc->rc_model_size = 8192; + + if (dsc->version == 0x11 && dsc->scr_rev == 0x1) + dsc->first_line_bpg_offset = 15; + else + dsc->first_line_bpg_offset = 12; + + dsc->edge_factor = 6; + dsc->tgt_offset_hi = 3; + dsc->tgt_offset_lo = 3; + dsc->enable_422 = 0; + dsc->convert_rgb = 1; + dsc->vbr_enable = 0; + + dsc->buf_thresh = dsi_dsc_rc_buf_thresh; + + bpp = dsc->bpp; + bpc = dsc->bpc; + + if ((bpc == 12) && (bpp == 8)) + ratio_index = DSC_12BPC_8BPP; + else if ((bpc == 10) && (bpp == 8)) + ratio_index = DSC_10BPC_8BPP; + else if ((bpc == 10) && (bpp == 10)) + ratio_index = DSC_10BPC_10BPP; + else + ratio_index = DSC_8BPC_8BPP; + + if (dsc->version == 0x11 && dsc->scr_rev == 0x1) { + dsc->range_min_qp = + dsi_dsc_rc_range_min_qp_1_1_scr1[ratio_index]; + dsc->range_max_qp = + dsi_dsc_rc_range_max_qp_1_1_scr1[ratio_index]; + } else { + dsc->range_min_qp = dsi_dsc_rc_range_min_qp_1_1[ratio_index]; + dsc->range_max_qp = dsi_dsc_rc_range_max_qp_1_1[ratio_index]; + } + dsc->range_bpg_offset = dsi_dsc_rc_range_bpg_offset; + + if (bpp == 8) { + dsc->initial_offset = 6144; + dsc->initial_xmit_delay = 512; + } else if (bpp == 10) { + dsc->initial_offset = 5632; + dsc->initial_xmit_delay = 410; + } else { + dsc->initial_offset = 2048; + dsc->initial_xmit_delay = 341; + } + + dsc->line_buf_depth = bpc + 1; + + if (bpc == 8) { + dsc->input_10_bits = 0; + dsc->min_qp_flatness = 3; + dsc->max_qp_flatness = 12; + dsc->quant_incr_limit0 = 11; + dsc->quant_incr_limit1 = 11; + mux_words_size = 48; + } else if (bpc == 10) { /* 10bpc */ + dsc->input_10_bits = 1; + dsc->min_qp_flatness = 7; + dsc->max_qp_flatness = 16; + dsc->quant_incr_limit0 = 15; + dsc->quant_incr_limit1 = 15; + mux_words_size = 48; + } else { /* 12 bpc */ + dsc->input_10_bits = 0; + dsc->min_qp_flatness = 11; + dsc->max_qp_flatness = 20; + dsc->quant_incr_limit0 = 19; + dsc->quant_incr_limit1 = 19; + mux_words_size = 64; + } + + mod_offset = dsc->slice_width % 3; + switch (mod_offset) { + case 0: + dsc->slice_last_group_size = 2; + break; + case 1: + dsc->slice_last_group_size = 0; + break; + case 2: + dsc->slice_last_group_size = 1; + break; + default: + break; + } + + dsc->det_thresh_flatness = 2 << (bpc - 8); + + groups_per_line = DIV_ROUND_UP(dsc->slice_width, 3); + + dsc->chunk_size = dsc->slice_width * bpp / 8; + if ((dsc->slice_width * bpp) % 8) + dsc->chunk_size++; + + /* rbs-min */ + min_rate_buffer_size = dsc->rc_model_size - dsc->initial_offset + + dsc->initial_xmit_delay * bpp + + groups_per_line * dsc->first_line_bpg_offset; + + hrd_delay = DIV_ROUND_UP(min_rate_buffer_size, bpp); + + dsc->initial_dec_delay = hrd_delay - dsc->initial_xmit_delay; + + dsc->initial_scale_value = 8 * dsc->rc_model_size / + (dsc->rc_model_size - dsc->initial_offset); + + slice_bits = 8 * dsc->chunk_size * dsc->slice_height; + + groups_total = groups_per_line * dsc->slice_height; + + data = dsc->first_line_bpg_offset * 2048; + + dsc->nfl_bpg_offset = DIV_ROUND_UP(data, (dsc->slice_height - 1)); + + pre_num_extra_mux_bits = 3 * (mux_words_size + (4 * bpc + 4) - 2); + + num_extra_mux_bits = pre_num_extra_mux_bits - (mux_words_size - + ((slice_bits - pre_num_extra_mux_bits) % mux_words_size)); + + data = 2048 * (dsc->rc_model_size - dsc->initial_offset + + num_extra_mux_bits); + dsc->slice_bpg_offset = DIV_ROUND_UP(data, groups_total); + + data = dsc->initial_xmit_delay * bpp; + final_value = dsc->rc_model_size - data + num_extra_mux_bits; + + final_scale = 8 * dsc->rc_model_size / + (dsc->rc_model_size - final_value); + + dsc->final_offset = final_value; + + data = (final_scale - 9) * (dsc->nfl_bpg_offset + + dsc->slice_bpg_offset); + dsc->scale_increment_interval = (2048 * dsc->final_offset) / data; + + dsc->scale_decrement_interval = groups_per_line / + (dsc->initial_scale_value - 8); + + return 0; +} + + +static int dsi_panel_parse_phy_timing(struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + const char *data; + u32 len, i; + int rc = 0; + struct dsi_display_mode_priv_info *priv_info; + u64 pixel_clk_khz; + + if (!mode || !mode->priv_info) + return -EINVAL; + + priv_info = mode->priv_info; + + data = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-phy-timings", &len); + if (!data) { + DSI_DEBUG("Unable to read Phy timing settings\n"); + } else { + priv_info->phy_timing_val = + kzalloc((sizeof(u32) * len), GFP_KERNEL); + if (!priv_info->phy_timing_val) + return -EINVAL; + + for (i = 0; i < len; i++) + priv_info->phy_timing_val[i] = data[i]; + + priv_info->phy_timing_len = len; + } + + if (mode->panel_mode == DSI_OP_VIDEO_MODE) { + /* + * For command mode we update the pclk as part of + * function dsi_panel_calc_dsi_transfer_time( ) + * as we set it based on dsi clock or mdp transfer time. + */ + pixel_clk_khz = (DSI_H_TOTAL_DSC(&mode->timing) * + DSI_V_TOTAL(&mode->timing) * + mode->timing.refresh_rate); + do_div(pixel_clk_khz, 1000); + mode->pixel_clk_khz = pixel_clk_khz; + } + + return rc; +} + +static int dsi_panel_parse_dsc_params(struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + u32 data; + int rc = -EINVAL; + int intf_width; + const char *compression; + struct dsi_display_mode_priv_info *priv_info; + + if (!mode || !mode->priv_info) + return -EINVAL; + + priv_info = mode->priv_info; + + priv_info->dsc_enabled = false; + compression = utils->get_property(utils->data, + "qcom,compression-mode", NULL); + if (compression && !strcmp(compression, "dsc")) + priv_info->dsc_enabled = true; + + if (!priv_info->dsc_enabled) { + DSI_DEBUG("dsc compression is not enabled for the mode\n"); + return 0; + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-version", &data); + if (rc) { + priv_info->dsc.version = 0x11; + rc = 0; + } else { + priv_info->dsc.version = data & 0xff; + /* only support DSC 1.1 rev */ + if (priv_info->dsc.version != 0x11) { + DSI_ERR("%s: DSC version:%d not supported\n", __func__, + priv_info->dsc.version); + rc = -EINVAL; + goto error; + } + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-scr-version", &data); + if (rc) { + priv_info->dsc.scr_rev = 0x0; + rc = 0; + } else { + priv_info->dsc.scr_rev = data & 0xff; + /* only one scr rev supported */ + if (priv_info->dsc.scr_rev > 0x1) { + DSI_ERR("%s: DSC scr version:%d not supported\n", + __func__, priv_info->dsc.scr_rev); + rc = -EINVAL; + goto error; + } + } + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-height", &data); + if (rc) { + DSI_ERR("failed to parse qcom,mdss-dsc-slice-height\n"); + goto error; + } + priv_info->dsc.slice_height = data; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-width", &data); + if (rc) { + DSI_ERR("failed to parse qcom,mdss-dsc-slice-width\n"); + goto error; + } + priv_info->dsc.slice_width = data; + + intf_width = mode->timing.h_active; + if (intf_width % priv_info->dsc.slice_width) { + DSI_ERR("invalid slice width for the intf width:%d slice width:%d\n", + intf_width, priv_info->dsc.slice_width); + rc = -EINVAL; + goto error; + } + + priv_info->dsc.pic_width = mode->timing.h_active; + priv_info->dsc.pic_height = mode->timing.v_active; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-slice-per-pkt", &data); + if (rc) { + DSI_ERR("failed to parse qcom,mdss-dsc-slice-per-pkt\n"); + goto error; + } else if (!data || (data > 2)) { + DSI_ERR("invalid dsc slice-per-pkt:%d\n", data); + goto error; + } + priv_info->dsc.slice_per_pkt = data; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-bit-per-component", + &data); + if (rc) { + DSI_ERR("failed to parse qcom,mdss-dsc-bit-per-component\n"); + goto error; + } + priv_info->dsc.bpc = data; + + rc = utils->read_u32(utils->data, "qcom,mdss-pps-delay-ms", &data); + if (rc) { + DSI_DEBUG("pps-delay-ms not specified, defaulting to 0\n"); + data = 0; + } + priv_info->dsc.pps_delay_ms = data; + + rc = utils->read_u32(utils->data, "qcom,mdss-dsc-bit-per-pixel", + &data); + if (rc) { + DSI_ERR("failed to parse qcom,mdss-dsc-bit-per-pixel\n"); + goto error; + } + priv_info->dsc.bpp = data; + + priv_info->dsc.block_pred_enable = utils->read_bool(utils->data, + "qcom,mdss-dsc-block-prediction-enable"); + + priv_info->dsc.full_frame_slices = DIV_ROUND_UP(intf_width, + priv_info->dsc.slice_width); + + dsi_dsc_populate_static_param(&priv_info->dsc); + dsi_dsc_pclk_param_calc(&priv_info->dsc, intf_width); + + mode->timing.dsc_enabled = true; + mode->timing.dsc = &priv_info->dsc; + +error: + return rc; +} + +static int dsi_panel_parse_hdr_config(struct dsi_panel *panel) +{ + int rc = 0; + struct drm_panel_hdr_properties *hdr_prop; + struct dsi_parser_utils *utils = &panel->utils; + + hdr_prop = &panel->hdr_props; + hdr_prop->hdr_enabled = utils->read_bool(utils->data, + "qcom,mdss-dsi-panel-hdr-enabled"); + + if (hdr_prop->hdr_enabled) { + rc = utils->read_u32_array(utils->data, + "qcom,mdss-dsi-panel-hdr-color-primaries", + hdr_prop->display_primaries, + DISPLAY_PRIMARIES_MAX); + if (rc) { + DSI_ERR("%s:%d, Unable to read color primaries,rc:%u\n", + __func__, __LINE__, rc); + hdr_prop->hdr_enabled = false; + return rc; + } + + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-panel-peak-brightness", + &(hdr_prop->peak_brightness)); + if (rc) { + DSI_ERR("%s:%d, Unable to read hdr brightness, rc:%u\n", + __func__, __LINE__, rc); + hdr_prop->hdr_enabled = false; + return rc; + } + + rc = utils->read_u32(utils->data, + "qcom,mdss-dsi-panel-blackness-level", + &(hdr_prop->blackness_level)); + if (rc) { + DSI_ERR("%s:%d, Unable to read hdr brightness, rc:%u\n", + __func__, __LINE__, rc); + hdr_prop->hdr_enabled = false; + return rc; + } + } + return 0; +} + +static int dsi_panel_parse_topology( + struct dsi_display_mode_priv_info *priv_info, + struct dsi_parser_utils *utils, + int topology_override) +{ + struct msm_display_topology *topology; + u32 top_count, top_sel, *array = NULL; + int i, len = 0; + int rc = -EINVAL; + + len = utils->count_u32_elems(utils->data, "qcom,display-topology"); + if (len <= 0 || len % TOPOLOGY_SET_LEN || + len > (TOPOLOGY_SET_LEN * MAX_TOPOLOGY)) { + DSI_ERR("invalid topology list for the panel, rc = %d\n", rc); + return rc; + } + + top_count = len / TOPOLOGY_SET_LEN; + + array = kcalloc(len, sizeof(u32), GFP_KERNEL); + if (!array) + return -ENOMEM; + + rc = utils->read_u32_array(utils->data, + "qcom,display-topology", array, len); + if (rc) { + DSI_ERR("unable to read the display topologies, rc = %d\n", rc); + goto read_fail; + } + + topology = kcalloc(top_count, sizeof(*topology), GFP_KERNEL); + if (!topology) { + rc = -ENOMEM; + goto read_fail; + } + + for (i = 0; i < top_count; i++) { + struct msm_display_topology *top = &topology[i]; + + top->num_lm = array[i * TOPOLOGY_SET_LEN]; + top->num_enc = array[i * TOPOLOGY_SET_LEN + 1]; + top->num_intf = array[i * TOPOLOGY_SET_LEN + 2]; + } + + if (topology_override >= 0 && topology_override < top_count) { + DSI_INFO("override topology: cfg:%d lm:%d comp_enc:%d intf:%d\n", + topology_override, + topology[topology_override].num_lm, + topology[topology_override].num_enc, + topology[topology_override].num_intf); + top_sel = topology_override; + goto parse_done; + } + + rc = utils->read_u32(utils->data, + "qcom,default-topology-index", &top_sel); + if (rc) { + DSI_ERR("no default topology selected, rc = %d\n", rc); + goto parse_fail; + } + + if (top_sel >= top_count) { + rc = -EINVAL; + DSI_ERR("default topology is specified is not valid, rc = %d\n", + rc); + goto parse_fail; + } + + DSI_INFO("default topology: lm: %d comp_enc:%d intf: %d\n", + topology[top_sel].num_lm, + topology[top_sel].num_enc, + topology[top_sel].num_intf); + +parse_done: + memcpy(&priv_info->topology, &topology[top_sel], + sizeof(struct msm_display_topology)); +parse_fail: + kfree(topology); +read_fail: + kfree(array); + + return rc; +} + +static int dsi_panel_parse_roi_alignment(struct dsi_parser_utils *utils, + struct msm_roi_alignment *align) +{ + int len = 0, rc = 0; + u32 value[6]; + struct property *data; + + if (!align) + return -EINVAL; + + memset(align, 0, sizeof(*align)); + + data = utils->find_property(utils->data, + "qcom,panel-roi-alignment", &len); + len /= sizeof(u32); + if (!data) { + DSI_ERR("panel roi alignment not found\n"); + rc = -EINVAL; + } else if (len != 6) { + DSI_ERR("incorrect roi alignment len %d\n", len); + rc = -EINVAL; + } else { + rc = utils->read_u32_array(utils->data, + "qcom,panel-roi-alignment", value, len); + if (rc) + DSI_DEBUG("error reading panel roi alignment values\n"); + else { + align->xstart_pix_align = value[0]; + align->ystart_pix_align = value[1]; + align->width_pix_align = value[2]; + align->height_pix_align = value[3]; + align->min_width = value[4]; + align->min_height = value[5]; + } + + DSI_INFO("roi alignment: [%d, %d, %d, %d, %d, %d]\n", + align->xstart_pix_align, + align->width_pix_align, + align->ystart_pix_align, + align->height_pix_align, + align->min_width, + align->min_height); + } + + return rc; +} + +static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + struct msm_roi_caps *roi_caps = NULL; + const char *data; + int rc = 0; + + if (!mode || !mode->priv_info) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + roi_caps = &mode->priv_info->roi_caps; + + memset(roi_caps, 0, sizeof(*roi_caps)); + + data = utils->get_property(utils->data, + "qcom,partial-update-enabled", NULL); + if (data) { + if (!strcmp(data, "dual_roi")) + roi_caps->num_roi = 2; + else if (!strcmp(data, "single_roi")) + roi_caps->num_roi = 1; + else { + DSI_INFO( + "invalid value for qcom,partial-update-enabled: %s\n", + data); + return 0; + } + } else { + DSI_DEBUG("partial update disabled as the property is not set\n"); + return 0; + } + + roi_caps->merge_rois = utils->read_bool(utils->data, + "qcom,partial-update-roi-merge"); + + roi_caps->enabled = roi_caps->num_roi > 0; + + DSI_DEBUG("partial update num_rois=%d enabled=%d\n", roi_caps->num_roi, + roi_caps->enabled); + + if (roi_caps->enabled) + rc = dsi_panel_parse_roi_alignment(utils, + &roi_caps->align); + + if (rc) + memset(roi_caps, 0, sizeof(*roi_caps)); + + return rc; +} + +static int dsi_panel_parse_panel_mode_caps(struct dsi_display_mode *mode, + struct dsi_parser_utils *utils) +{ + bool vid_mode_support, cmd_mode_support; + + if (!mode || !mode->priv_info) { + DSI_ERR("invalid arguments\n"); + return -EINVAL; + } + + vid_mode_support = utils->read_bool(utils->data, + "qcom,mdss-dsi-video-mode"); + + cmd_mode_support = utils->read_bool(utils->data, + "qcom,mdss-dsi-cmd-mode"); + + if (cmd_mode_support) + mode->panel_mode = DSI_OP_CMD_MODE; + else if (vid_mode_support) + mode->panel_mode = DSI_OP_VIDEO_MODE; + else + return -EINVAL; + + return 0; +}; + + +static int dsi_panel_parse_dms_info(struct dsi_panel *panel) +{ + int dms_enabled; + const char *data; + struct dsi_parser_utils *utils = &panel->utils; + + panel->dms_mode = DSI_DMS_MODE_DISABLED; + dms_enabled = utils->read_bool(utils->data, + "qcom,dynamic-mode-switch-enabled"); + if (!dms_enabled) + return 0; + + data = utils->get_property(utils->data, + "qcom,dynamic-mode-switch-type", NULL); + if (data && !strcmp(data, "dynamic-resolution-switch-immediate")) { + panel->dms_mode = DSI_DMS_MODE_RES_SWITCH_IMMEDIATE; + } else { + DSI_ERR("[%s] unsupported dynamic switch mode: %s\n", + panel->name, data); + return -EINVAL; + } + + return 0; +}; +static int dsi_panel_parse_oem_config(struct dsi_panel *panel, + struct device_node *of_node) +{ + u32 tmp = 0; + int rc; + static const char *panel_manufacture; + static const char *panel_version; + static const char *backlight_manufacture; + static const char *backlight_version; + + DSI_DEBUG("%s start\n", __func__); + + panel_manufacture = of_get_property(of_node, + "qcom,mdss-dsi-panel-manufacture", NULL); + if (!panel_manufacture) + DSI_ERR("%s:%d, panel manufacture not specified\n", + __func__, __LINE__); + panel_version = of_get_property(of_node, + "qcom,mdss-dsi-panel-version", NULL); + if (!panel_version) + DSI_ERR("%s:%d, panel version not specified\n", + __func__, __LINE__); + push_component_info(LCD, (char *)panel_version,(char *)panel_manufacture); + + backlight_manufacture = of_get_property(of_node, + "qcom,mdss-dsi-backlight-manufacture", NULL); + if (!backlight_manufacture) + DSI_ERR("%s:%d, backlight manufacture not specified\n", + __func__, __LINE__); + backlight_version = of_get_property(of_node, + "qcom,mdss-dsi-backlight-version", NULL); + if (!backlight_version) + DSI_ERR("%s:%d, backlight version not specified\n", + __func__, __LINE__); + + push_component_info(BACKLIGHT, (char *)backlight_version, (char *)backlight_manufacture); + + panel->lp11_init = + of_property_read_bool(of_node, "qcom,mdss-dsi-lp11-init"); + if (panel->lp11_init) + DSI_DEBUG("lp11_init:%d\n", panel->lp11_init); + + panel->bl_config.bl_high2bit = + of_property_read_bool(of_node, "qcom,mdss-bl-high2bit"); + if (panel->bl_config.bl_high2bit) { + DSI_DEBUG("bl_high2bit:%d\n", panel->bl_config.bl_high2bit); + } + + panel->naive_display_loading_effect_mode = + of_property_read_bool(of_node, "qcom,mdss-loading-effect"); + if (panel->naive_display_loading_effect_mode) + DSI_INFO("naive_display_loading_effect_mode:%d\n", panel->naive_display_loading_effect_mode); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-acl-cmd-index", &tmp); + panel->acl_cmd_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-acl-mode-index", &tmp); + panel->acl_mode_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-year-index", &tmp); + panel->panel_year_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-mon-index", &tmp); + panel->panel_mon_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-day-index", &tmp); + panel->panel_day_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-hour-index", &tmp); + panel->panel_hour_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-min-index", &tmp); + panel->panel_min_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-sec-index", &tmp); + panel->panel_sec_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-msec-high-index", &tmp); + panel->panel_msec_high_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-seria-num-msec-low-index", &tmp); + panel->panel_msec_low_index = (!rc ? tmp : 0); + + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-panel-status-value-2", &tmp); + panel->status_value = (!rc ? tmp : 0); + + panel->panel_mismatch_check = + of_property_read_bool(of_node, "qcom,mdss-panel-mismatch-check"); + + DSI_DEBUG("%s end\n", __func__); + return 0; +} + +/* + * The length of all the valid values to be checked should not be greater + * than the length of returned data from read command. + */ +static bool +dsi_panel_parse_esd_check_valid_params(struct dsi_panel *panel, u32 count) +{ + int i; + struct drm_panel_esd_config *config = &panel->esd_config; + + for (i = 0; i < count; ++i) { + if (config->status_valid_params[i] > + config->status_cmds_rlen[i]) { + DSI_DEBUG("ignore valid params\n"); + return false; + } + } + + return true; +} + +static bool dsi_panel_parse_esd_status_len(struct dsi_parser_utils *utils, + char *prop_key, u32 **target, u32 cmd_cnt) +{ + int tmp; + + if (!utils->find_property(utils->data, prop_key, &tmp)) + return false; + + tmp /= sizeof(u32); + if (tmp != cmd_cnt) { + DSI_ERR("request property(%d) do not match cmd count(%d)\n", + tmp, cmd_cnt); + return false; + } + + *target = kcalloc(tmp, sizeof(u32), GFP_KERNEL); + if (IS_ERR_OR_NULL(*target)) { + DSI_ERR("Error allocating memory for property\n"); + return false; + } + + if (utils->read_u32_array(utils->data, prop_key, *target, tmp)) { + DSI_ERR("cannot get values from dts\n"); + kfree(*target); + *target = NULL; + return false; + } + + return true; +} + +static void dsi_panel_esd_config_deinit(struct drm_panel_esd_config *esd_config) +{ + kfree(esd_config->status_buf); + kfree(esd_config->return_buf); + kfree(esd_config->status_value); + kfree(esd_config->status_valid_params); + kfree(esd_config->status_cmds_rlen); + kfree(esd_config->status_cmd.cmds); +} + +int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel) +{ + struct drm_panel_esd_config *esd_config; + int rc = 0; + u32 tmp; + u32 i, status_len, *lenp; + struct property *data; + struct dsi_parser_utils *utils = &panel->utils; + + if (!panel) { + DSI_ERR("Invalid Params\n"); + return -EINVAL; + } + + esd_config = &panel->esd_config; + if (!esd_config) + return -EINVAL; + + dsi_panel_parse_cmd_sets_sub(&esd_config->status_cmd, + DSI_CMD_SET_PANEL_STATUS, utils); + if (!esd_config->status_cmd.count) { + DSI_ERR("panel status command parsing failed\n"); + rc = -EINVAL; + goto error; + } + + if (!dsi_panel_parse_esd_status_len(utils, + "qcom,mdss-dsi-panel-status-read-length", + &panel->esd_config.status_cmds_rlen, + esd_config->status_cmd.count)) { + DSI_ERR("Invalid status read length\n"); + rc = -EINVAL; + goto error1; + } + + if (dsi_panel_parse_esd_status_len(utils, + "qcom,mdss-dsi-panel-status-valid-params", + &panel->esd_config.status_valid_params, + esd_config->status_cmd.count)) { + if (!dsi_panel_parse_esd_check_valid_params(panel, + esd_config->status_cmd.count)) { + rc = -EINVAL; + goto error2; + } + } + + status_len = 0; + lenp = esd_config->status_valid_params ?: esd_config->status_cmds_rlen; + for (i = 0; i < esd_config->status_cmd.count; ++i) + status_len += lenp[i]; + + if (!status_len) { + rc = -EINVAL; + goto error2; + } + + /* + * Some panel may need multiple read commands to properly + * check panel status. Do a sanity check for proper status + * value which will be compared with the value read by dsi + * controller during ESD check. Also check if multiple read + * commands are there then, there should be corresponding + * status check values for each read command. + */ + data = utils->find_property(utils->data, + "qcom,mdss-dsi-panel-status-value", &tmp); + tmp /= sizeof(u32); + if (!IS_ERR_OR_NULL(data) && tmp != 0 && (tmp % status_len) == 0) { + esd_config->groups = tmp / status_len; + } else { + DSI_ERR("error parse panel-status-value\n"); + rc = -EINVAL; + goto error2; + } + + esd_config->status_value = + kzalloc(sizeof(u32) * status_len * esd_config->groups, + GFP_KERNEL); + if (!esd_config->status_value) { + rc = -ENOMEM; + goto error2; + } + + esd_config->return_buf = kcalloc(status_len * esd_config->groups, + sizeof(unsigned char), GFP_KERNEL); + if (!esd_config->return_buf) { + rc = -ENOMEM; + goto error3; + } + + esd_config->status_buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!esd_config->status_buf) { + rc = -ENOMEM; + goto error4; + } + + rc = utils->read_u32_array(utils->data, + "qcom,mdss-dsi-panel-status-value", + esd_config->status_value, esd_config->groups * status_len); + if (rc) { + DSI_DEBUG("error reading panel status values\n"); + memset(esd_config->status_value, 0, + esd_config->groups * status_len); + } + + return 0; + +error4: + kfree(esd_config->return_buf); +error3: + kfree(esd_config->status_value); +error2: + kfree(esd_config->status_valid_params); + kfree(esd_config->status_cmds_rlen); +error1: + kfree(esd_config->status_cmd.cmds); +error: + return rc; +} + +static int dsi_panel_parse_esd_config(struct dsi_panel *panel) +{ + int rc = 0; + const char *string; + struct drm_panel_esd_config *esd_config; + struct dsi_parser_utils *utils = &panel->utils; + u8 *esd_mode = NULL; + + esd_config = &panel->esd_config; + esd_config->status_mode = ESD_MODE_MAX; + esd_config->esd_enabled = utils->read_bool(utils->data, + "qcom,esd-check-enabled"); + + if (!esd_config->esd_enabled) + return 0; + + rc = utils->read_string(utils->data, + "qcom,mdss-dsi-panel-status-check-mode", &string); + if (!rc) { + if (!strcmp(string, "bta_check")) { + esd_config->status_mode = ESD_MODE_SW_BTA; + } else if (!strcmp(string, "reg_read")) { + esd_config->status_mode = ESD_MODE_REG_READ; + } else if (!strcmp(string, "te_signal_check")) { + if (panel->panel_mode == DSI_OP_CMD_MODE) { + esd_config->status_mode = ESD_MODE_PANEL_TE; + } else { + DSI_ERR("TE-ESD not valid for video mode\n"); + rc = -EINVAL; + goto error; + } + } else { + DSI_ERR("No valid panel-status-check-mode string\n"); + rc = -EINVAL; + goto error; + } + } else { + DSI_DEBUG("status check method not defined!\n"); + rc = -EINVAL; + goto error; + } + + if (panel->esd_config.status_mode == ESD_MODE_REG_READ) { + rc = dsi_panel_parse_esd_reg_read_configs(panel); + if (rc) { + DSI_ERR("failed to parse esd reg read mode params, rc=%d\n", + rc); + goto error; + } + esd_mode = "register_read"; + } else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA) { + esd_mode = "bta_trigger"; + } else if (panel->esd_config.status_mode == ESD_MODE_PANEL_TE) { + esd_mode = "te_check"; + } + + DSI_DEBUG("ESD enabled with mode: %s\n", esd_mode); + + return 0; + +error: + panel->esd_config.esd_enabled = false; + return rc; +} + +static void dsi_panel_update_util(struct dsi_panel *panel, + struct device_node *parser_node) +{ + struct dsi_parser_utils *utils = &panel->utils; + + if (parser_node) { + *utils = *dsi_parser_get_parser_utils(); + utils->data = parser_node; + + DSI_DEBUG("switching to parser APIs\n"); + + goto end; + } + + *utils = *dsi_parser_get_of_utils(); + utils->data = panel->panel_of_node; +end: + utils->node = panel->panel_of_node; +} + +struct dsi_panel *dsi_panel_get(struct device *parent, + struct device_node *of_node, + struct device_node *parser_node, + const char *type, + int topology_override) +{ + struct dsi_panel *panel; + struct dsi_parser_utils *utils; + const char *panel_physical_type; + int rc = 0; + + panel = kzalloc(sizeof(*panel), GFP_KERNEL); + if (!panel) + return ERR_PTR(-ENOMEM); + + panel->panel_of_node = of_node; + panel->parent = parent; + panel->type = type; + + dsi_panel_update_util(panel, parser_node); + utils = &panel->utils; + + panel->name = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-name", NULL); + if (strcmp(panel->name, "samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_ANA6705; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_ANA6705"); + } + else if (strcmp(panel->name, "samsung ams644vk04 fhd cmd mode dsc dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_AMSS644_VK04; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_AMSS644_VK04"); + } + else if (strcmp(panel->name, "samsung sofef00_m video mode dsi panel") == 0) { + dsi_panel_name = DSI_PANEL_SAMSUNG_SOFEF00_M; + DSI_ERR("Dsi panel name is DSI_PANEL_SAMSUNG_SOFEF00_M"); + } + else if (!panel->name) + panel->name = DSI_PANEL_DEFAULT_LABEL; + + /* + * Set panel type to LCD as default. + */ + panel->panel_type = DSI_DISPLAY_PANEL_TYPE_LCD; + panel_physical_type = utils->get_property(utils->data, + "qcom,mdss-dsi-panel-physical-type", NULL); + if (panel_physical_type && !strcmp(panel_physical_type, "oled")) + panel->panel_type = DSI_DISPLAY_PANEL_TYPE_OLED; + rc = dsi_panel_parse_host_config(panel); + if (rc) { + DSI_ERR("failed to parse host configuration, rc=%d\n", + rc); + goto error; + } + + rc = dsi_panel_parse_panel_mode(panel); + if (rc) { + DSI_ERR("failed to parse panel mode configuration, rc=%d\n", + rc); + goto error; + } + + rc = dsi_panel_parse_dfps_caps(panel); + if (rc) + DSI_ERR("failed to parse dfps configuration, rc=%d\n", rc); + + rc = dsi_panel_parse_qsync_caps(panel, of_node); + if (rc) + DSI_DEBUG("failed to parse qsync features, rc=%d\n", rc); + + /* allow qsync support only if DFPS is with VFP approach */ + if ((panel->dfps_caps.dfps_support) && + !(panel->dfps_caps.type == DSI_DFPS_IMMEDIATE_VFP)) + panel->qsync_min_fps = 0; + + rc = dsi_panel_parse_dyn_clk_caps(panel); + if (rc) + DSI_ERR("failed to parse dynamic clk config, rc=%d\n", rc); + + rc = dsi_panel_parse_phy_props(panel); + if (rc) { + DSI_ERR("failed to parse panel physical dimension, rc=%d\n", + rc); + goto error; + } + + rc = dsi_panel_parse_gpios(panel); + if (rc) { + DSI_ERR("failed to parse panel gpios, rc=%d\n", rc); + goto error; + } + + rc = dsi_panel_parse_power_cfg(panel); + if (rc) + DSI_ERR("failed to parse power config, rc=%d\n", rc); + + rc = dsi_panel_parse_bl_config(panel); + if (rc) { + DSI_ERR("failed to parse backlight config, rc=%d\n", rc); + if (rc == -EPROBE_DEFER) + goto error; + } + + rc = dsi_panel_parse_misc_features(panel); + if (rc) + DSI_ERR("failed to parse misc features, rc=%d\n", rc); + + rc = dsi_panel_parse_hdr_config(panel); + if (rc) + DSI_ERR("failed to parse hdr config, rc=%d\n", rc); + rc = dsi_panel_parse_oem_config(panel, of_node); + if (rc) + DSI_DEBUG("failed to get oem config, rc=%d\n", rc); + + rc = dsi_panel_get_mode_count(panel); + if (rc) { + DSI_ERR("failed to get mode count, rc=%d\n", rc); + goto error; + } + + rc = dsi_panel_parse_dms_info(panel); + if (rc) + DSI_DEBUG("failed to get dms info, rc=%d\n", rc); + + rc = dsi_panel_parse_esd_config(panel); + if (rc) + DSI_DEBUG("failed to parse esd config, rc=%d\n", rc); + + panel->power_mode = SDE_MODE_DPMS_OFF; + drm_panel_init(&panel->drm_panel); + panel->drm_panel.dev = &panel->mipi_device.dev; + panel->mipi_device.dev.of_node = of_node; + printk("enter drm_panel_add, name is %s\n", of_node->name); + + rc = drm_panel_add(&panel->drm_panel); + if (rc) + goto error; + + mutex_init(&panel->panel_lock); + + return panel; +error: + kfree(panel); + return ERR_PTR(rc); +} + +void dsi_panel_put(struct dsi_panel *panel) +{ + drm_panel_remove(&panel->drm_panel); + + /* free resources allocated for ESD check */ + dsi_panel_esd_config_deinit(&panel->esd_config); + + kfree(panel); +} + +int dsi_panel_drv_init(struct dsi_panel *panel, + struct mipi_dsi_host *host) +{ + int rc = 0; + struct mipi_dsi_device *dev; + + if (!panel || !host) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + dev = &panel->mipi_device; + + dev->host = host; + /* + * We dont have device structure since panel is not a device node. + * When using drm panel framework, the device is probed when the host is + * create. + */ + dev->channel = 0; + dev->lanes = 4; + + panel->host = host; + rc = dsi_panel_vreg_get(panel); + if (rc) { + DSI_ERR("[%s] failed to get panel regulators, rc=%d\n", + panel->name, rc); + goto exit; + } + + rc = dsi_panel_pinctrl_init(panel); + if (rc) { + DSI_ERR("[%s] failed to init pinctrl, rc=%d\n", + panel->name, rc); + goto error_vreg_put; + } + + rc = dsi_panel_gpio_request(panel); + if (rc) { + DSI_ERR("[%s] failed to request gpios, rc=%d\n", panel->name, + rc); + goto error_pinctrl_deinit; + } + + rc = dsi_panel_bl_register(panel); + if (rc) { + if (rc != -EPROBE_DEFER) + DSI_ERR("[%s] failed to register backlight, rc=%d\n", + panel->name, rc); + goto error_gpio_release; + } + + goto exit; + +error_gpio_release: + (void)dsi_panel_gpio_release(panel); +error_pinctrl_deinit: + (void)dsi_panel_pinctrl_deinit(panel); +error_vreg_put: + (void)dsi_panel_vreg_put(panel); +exit: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_drv_deinit(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_bl_unregister(panel); + if (rc) + DSI_ERR("[%s] failed to unregister backlight, rc=%d\n", + panel->name, rc); + + rc = dsi_panel_gpio_release(panel); + if (rc) + DSI_ERR("[%s] failed to release gpios, rc=%d\n", panel->name, + rc); + + rc = dsi_panel_pinctrl_deinit(panel); + if (rc) + DSI_ERR("[%s] failed to deinit gpios, rc=%d\n", panel->name, + rc); + + rc = dsi_panel_vreg_put(panel); + if (rc) + DSI_ERR("[%s] failed to put regs, rc=%d\n", panel->name, rc); + + panel->host = NULL; + memset(&panel->mipi_device, 0x0, sizeof(panel->mipi_device)); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_validate_mode(struct dsi_panel *panel, + struct dsi_display_mode *mode) +{ + return 0; +} + +int dsi_panel_get_mode_count(struct dsi_panel *panel) +{ + const u32 SINGLE_MODE_SUPPORT = 1; + struct dsi_parser_utils *utils; + struct device_node *timings_np, *child_np; + int num_dfps_rates, num_bit_clks; + int num_video_modes = 0, num_cmd_modes = 0; + int count, rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + utils = &panel->utils; + + panel->num_timing_nodes = 0; + + timings_np = utils->get_child_by_name(utils->data, + "qcom,mdss-dsi-display-timings"); + if (!timings_np && !panel->host_config.ext_bridge_mode) { + DSI_ERR("no display timing nodes defined\n"); + rc = -EINVAL; + goto error; + } + + count = utils->get_child_count(timings_np); + if ((!count && !panel->host_config.ext_bridge_mode) || + count > DSI_MODE_MAX) { + DSI_ERR("invalid count of timing nodes: %d\n", count); + rc = -EINVAL; + goto error; + } + + /* No multiresolution support is available for video mode panels. + * Multi-mode is supported for video mode during POMS is enabled. + */ + if (panel->panel_mode != DSI_OP_CMD_MODE && + !panel->host_config.ext_bridge_mode && + !panel->panel_mode_switch_enabled) + count = SINGLE_MODE_SUPPORT; + + panel->num_timing_nodes = count; + dsi_for_each_child_node(timings_np, child_np) { + if (utils->read_bool(child_np, "qcom,mdss-dsi-video-mode")) + num_video_modes++; + else if (utils->read_bool(child_np, + "qcom,mdss-dsi-cmd-mode")) + num_cmd_modes++; + else if (panel->panel_mode == DSI_OP_VIDEO_MODE) + num_video_modes++; + else if (panel->panel_mode == DSI_OP_CMD_MODE) + num_cmd_modes++; + } + + num_dfps_rates = !panel->dfps_caps.dfps_support ? 1 : + panel->dfps_caps.dfps_list_len; + + num_bit_clks = !panel->dyn_clk_caps.dyn_clk_support ? 1 : + panel->dyn_clk_caps.bit_clk_list_len; + + /* + * Inflate num_of_modes by fps and bit clks in dfps. + * Single command mode for video mode panels supporting + * panel operating mode switch. + */ + num_video_modes = num_video_modes * num_bit_clks * num_dfps_rates; + + if ((panel->panel_mode == DSI_OP_VIDEO_MODE) && + (panel->panel_mode_switch_enabled)) + num_cmd_modes = 1; + else + num_cmd_modes = num_cmd_modes * num_bit_clks; + + panel->num_display_modes = num_video_modes + num_cmd_modes; + +error: + return rc; +} + +int dsi_panel_get_phy_props(struct dsi_panel *panel, + struct dsi_panel_phy_props *phy_props) +{ + int rc = 0; + + if (!panel || !phy_props) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + memcpy(phy_props, &panel->phy_props, sizeof(*phy_props)); + return rc; +} + +int dsi_panel_get_dfps_caps(struct dsi_panel *panel, + struct dsi_dfps_capabilities *dfps_caps) +{ + int rc = 0; + + if (!panel || !dfps_caps) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + memcpy(dfps_caps, &panel->dfps_caps, sizeof(*dfps_caps)); + return rc; +} + +void dsi_panel_put_mode(struct dsi_display_mode *mode) +{ + int i; + + if (!mode->priv_info) + return; + + for (i = 0; i < DSI_CMD_SET_MAX; i++) { + dsi_panel_destroy_cmd_packets(&mode->priv_info->cmd_sets[i]); + dsi_panel_dealloc_cmd_packets(&mode->priv_info->cmd_sets[i]); + } + + kfree(mode->priv_info); +} + +void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, + struct dsi_display_mode *mode, u32 frame_threshold_us) +{ + u32 frame_time_us,nslices; + u64 min_bitclk_hz, total_active_pixels, bits_per_line, pclk_rate_hz, + dsi_transfer_time_us, pixel_clk_khz; + struct msm_display_dsc_info *dsc = mode->timing.dsc; + struct dsi_mode_info *timing = &mode->timing; + struct dsi_display_mode *display_mode; + u32 jitter_numer, jitter_denom, prefill_lines; + u32 min_threshold_us, prefill_time_us; + + /* Packet overlead in bits,2 bytes header + 2 bytes checksum + * + 1 byte dcs data command. + */ + const u32 packet_overhead = 56; + + display_mode = container_of(timing, struct dsi_display_mode, timing); + + jitter_numer = display_mode->priv_info->panel_jitter_numer; + jitter_denom = display_mode->priv_info->panel_jitter_denom; + + frame_time_us = mult_frac(1000, 1000, (timing->refresh_rate)); + + if (timing->dsc_enabled) { + nslices = (timing->h_active)/(dsc->slice_width); + /* (slice width x bit-per-pixel + packet overhead) x + * number of slices x height x fps / lane + */ + bits_per_line = ((dsc->slice_width * dsc->bpp) + + packet_overhead) * nslices; + bits_per_line = bits_per_line / (config->num_data_lanes); + + min_bitclk_hz = (bits_per_line * timing->v_active * + timing->refresh_rate); + } else { + total_active_pixels = ((DSI_H_ACTIVE_DSC(timing) + * timing->v_active)); + /* calculate the actual bitclk needed to transfer the frame */ + min_bitclk_hz = (total_active_pixels * (timing->refresh_rate) * + (config->bpp)); + do_div(min_bitclk_hz, config->num_data_lanes); + } + + timing->min_dsi_clk_hz = min_bitclk_hz; + + if (timing->clk_rate_hz) { + /* adjust the transfer time proportionately for bit clk*/ + dsi_transfer_time_us = frame_time_us * min_bitclk_hz; + do_div(dsi_transfer_time_us, timing->clk_rate_hz); + timing->dsi_transfer_time_us = dsi_transfer_time_us; + + } else if (mode->priv_info->mdp_transfer_time_us) { + timing->dsi_transfer_time_us = + mode->priv_info->mdp_transfer_time_us; + } else { + + min_threshold_us = mult_frac(frame_time_us, + jitter_numer, (jitter_denom * 100)); + /* + * Increase the prefill_lines proportionately as recommended + * 35lines for 60fps, 52 for 90fps, 70lines for 120fps. + */ + prefill_lines = mult_frac(MIN_PREFILL_LINES, + timing->refresh_rate, 60); + + prefill_time_us = mult_frac(frame_time_us, prefill_lines, + (timing->v_active)); + + /* + * Threshold is sum of panel jitter time, prefill line time + * plus 100usec buffer time. + */ + min_threshold_us = min_threshold_us + 100 + prefill_time_us; + + DSI_DEBUG("min threshold time=%d\n", min_threshold_us); + + if (min_threshold_us > frame_threshold_us) + frame_threshold_us = min_threshold_us; + + timing->dsi_transfer_time_us = frame_time_us - + frame_threshold_us; + } + + timing->mdp_transfer_time_us = timing->dsi_transfer_time_us; + + /* Force update mdp xfer time to hal,if clk and mdp xfer time is set */ + if (mode->priv_info->mdp_transfer_time_us && timing->clk_rate_hz) { + timing->mdp_transfer_time_us = + mode->priv_info->mdp_transfer_time_us; + } + + /* Calculate pclk_khz to update modeinfo */ + pclk_rate_hz = min_bitclk_hz * frame_time_us; + do_div(pclk_rate_hz, timing->dsi_transfer_time_us); + + pixel_clk_khz = pclk_rate_hz * config->num_data_lanes; + do_div(pixel_clk_khz, config->bpp); + display_mode->pixel_clk_khz = pixel_clk_khz; + + display_mode->pixel_clk_khz = display_mode->pixel_clk_khz / 1000; +} + + +int dsi_panel_get_mode(struct dsi_panel *panel, + u32 index, struct dsi_display_mode *mode, + int topology_override) +{ + struct device_node *timings_np, *child_np; + struct dsi_parser_utils *utils; + struct dsi_display_mode_priv_info *prv_info; + u32 child_idx = 0; + int rc = 0, num_timings; + void *utils_data = NULL; + + if (!panel || !mode) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + utils = &panel->utils; + + mode->priv_info = kzalloc(sizeof(*mode->priv_info), GFP_KERNEL); + if (!mode->priv_info) { + rc = -ENOMEM; + goto done; + } + + prv_info = mode->priv_info; + + timings_np = utils->get_child_by_name(utils->data, + "qcom,mdss-dsi-display-timings"); + if (!timings_np) { + DSI_ERR("no display timing nodes defined\n"); + rc = -EINVAL; + goto parse_fail; + } + + num_timings = utils->get_child_count(timings_np); + if (!num_timings || num_timings > DSI_MODE_MAX) { + DSI_ERR("invalid count of timing nodes: %d\n", num_timings); + rc = -EINVAL; + goto parse_fail; + } + + utils_data = utils->data; + + dsi_for_each_child_node(timings_np, child_np) { + if (index != child_idx++) + continue; + + utils->data = child_np; + + rc = dsi_panel_parse_timing(&mode->timing, utils); + if (rc) { + DSI_ERR("failed to parse panel timing, rc=%d\n", rc); + goto parse_fail; + } + + rc = dsi_panel_parse_dsc_params(mode, utils); + if (rc) { + DSI_ERR("failed to parse dsc params, rc=%d\n", rc); + goto parse_fail; + } + + rc = dsi_panel_parse_topology(prv_info, utils, + topology_override); + if (rc) { + DSI_ERR("failed to parse panel topology, rc=%d\n", rc); + goto parse_fail; + } + + rc = dsi_panel_parse_cmd_sets(prv_info, utils); + if (rc) { + DSI_ERR("failed to parse command sets, rc=%d\n", rc); + goto parse_fail; + } + + rc = dsi_panel_parse_jitter_config(mode, utils); + if (rc) + DSI_ERR( + "failed to parse panel jitter config, rc=%d\n", rc); + + rc = dsi_panel_parse_phy_timing(mode, utils); + if (rc) { + DSI_ERR( + "failed to parse panel phy timings, rc=%d\n", rc); + goto parse_fail; + } + + rc = dsi_panel_parse_partial_update_caps(mode, utils); + if (rc) + DSI_ERR("failed to partial update caps, rc=%d\n", rc); + + if (panel->panel_mode_switch_enabled) { + rc = dsi_panel_parse_panel_mode_caps(mode, utils); + if (rc) { + rc = 0; + mode->panel_mode = panel->panel_mode; + DSI_INFO( + "POMS: panel mode isn't specified in timing[%d]\n", + child_idx); + } + } else { + mode->panel_mode = panel->panel_mode; + } + } + goto done; + +parse_fail: + kfree(mode->priv_info); + mode->priv_info = NULL; +done: + utils->data = utils_data; + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel, + struct dsi_display_mode *mode, + struct dsi_host_config *config) +{ + int rc = 0; + struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps; + + if (!panel || !mode || !config) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + config->panel_mode = panel->panel_mode; + memcpy(&config->common_config, &panel->host_config, + sizeof(config->common_config)); + + if (panel->panel_mode == DSI_OP_VIDEO_MODE) { + memcpy(&config->u.video_engine, &panel->video_config, + sizeof(config->u.video_engine)); + } else { + memcpy(&config->u.cmd_engine, &panel->cmd_config, + sizeof(config->u.cmd_engine)); + } + + memcpy(&config->video_timing, &mode->timing, + sizeof(config->video_timing)); + config->video_timing.mdp_transfer_time_us = + mode->priv_info->mdp_transfer_time_us; + config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled; + config->video_timing.dsc = &mode->priv_info->dsc; + + if (dyn_clk_caps->dyn_clk_support) + config->bit_clk_rate_hz_override = mode->timing.clk_rate_hz; + else + config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz; + + config->esc_clk_rate_hz = 19200000; + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_pre_prepare(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + /* If LP11_INIT is set, panel will be powered up during prepare() */ + if (panel->lp11_init) + goto error; + + rc = dsi_panel_power_on(panel); + if (rc) { + DSI_ERR("[%s] panel power on failed, rc=%d\n", panel->name, rc); + goto error; + } + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_update_pps(struct dsi_panel *panel) +{ + int rc = 0; + struct dsi_panel_cmd_set *set = NULL; + struct dsi_display_mode_priv_info *priv_info = NULL; + + if (!panel || !panel->cur_mode) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + priv_info = panel->cur_mode->priv_info; + + set = &priv_info->cmd_sets[DSI_CMD_SET_PPS]; + + dsi_dsc_create_pps_buf_cmd(&priv_info->dsc, panel->dsc_pps_cmd, 0); + rc = dsi_panel_create_cmd_packets(panel->dsc_pps_cmd, + DSI_CMD_PPS_SIZE, 1, set->cmds); + if (rc) { + DSI_ERR("failed to create cmd packets, rc=%d\n", rc); + goto error; + } + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PPS); + if (rc) { + DSI_ERR("[%s] failed to send DSI_CMD_SET_PPS cmds, rc=%d\n", + panel->name, rc); + } + + dsi_panel_destroy_cmd_packets(set); +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_lp1(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + if (!panel->panel_initialized) + goto exit; + + /* + * Consider LP1->LP2->LP1. + * If the panel is already in LP mode, do not need to + * set the regulator. + * IBB and AB power mode would be set at the same time + * in PMIC driver, so we only call ibb setting that is enough. + */ + if (dsi_panel_is_type_oled(panel) && + panel->power_mode != SDE_MODE_DPMS_LP2) + dsi_pwr_panel_regulator_mode_set(&panel->power_info, + "ibb", REGULATOR_MODE_IDLE); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP1); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n", + panel->name, rc); +exit: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_lp2(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + if (!panel->panel_initialized) + goto exit; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_LP2); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n", + panel->name, rc); +exit: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_nolp(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + if (!panel->panel_initialized) + goto exit; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP); + /* + * Consider about LP1->LP2->NOLP. + */ + if (dsi_panel_is_type_oled(panel) && + (panel->power_mode == SDE_MODE_DPMS_LP1 || + panel->power_mode == SDE_MODE_DPMS_LP2)) + dsi_pwr_panel_regulator_mode_set(&panel->power_info, + "ibb", REGULATOR_MODE_NORMAL); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n", + panel->name, rc); +exit: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_prepare(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + if (!strcmp(panel->name,"samsung ams644vk04 fhd cmd mode dsc dsi panel") || !strcmp(panel->name,"samsung ams644vk04 ana6705 fhd cmd mode dsc dsi panel")) { + + usleep_range(6000, 6100); + dsi_panel_reset(panel); + } + if (panel->lp11_init) { + rc = dsi_panel_power_on(panel); + if (rc) { + DSI_ERR("[%s] panel power on failed, rc=%d\n", + panel->name, rc); + goto error; + } + } + else { + usleep_range(2000, 2100); + } + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_ON); + if (rc) { + DSI_ERR("[%s] failed to send DSI_CMD_SET_PRE_ON cmds, rc=%d\n", + panel->name, rc); + goto error; + } + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +static int dsi_panel_roi_prepare_dcs_cmds(struct dsi_panel_cmd_set *set, + struct dsi_rect *roi, int ctrl_idx, int unicast) +{ + static const int ROI_CMD_LEN = 5; + + int rc = 0; + + /* DTYPE_DCS_LWRITE */ + char *caset, *paset; + + set->cmds = NULL; + + caset = kzalloc(ROI_CMD_LEN, GFP_KERNEL); + if (!caset) { + rc = -ENOMEM; + goto exit; + } + caset[0] = 0x2a; + caset[1] = (roi->x & 0xFF00) >> 8; + caset[2] = roi->x & 0xFF; + caset[3] = ((roi->x - 1 + roi->w) & 0xFF00) >> 8; + caset[4] = (roi->x - 1 + roi->w) & 0xFF; + + paset = kzalloc(ROI_CMD_LEN, GFP_KERNEL); + if (!paset) { + rc = -ENOMEM; + goto error_free_mem; + } + paset[0] = 0x2b; + paset[1] = (roi->y & 0xFF00) >> 8; + paset[2] = roi->y & 0xFF; + paset[3] = ((roi->y - 1 + roi->h) & 0xFF00) >> 8; + paset[4] = (roi->y - 1 + roi->h) & 0xFF; + + set->type = DSI_CMD_SET_ROI; + set->state = DSI_CMD_SET_STATE_LP; + set->count = 2; /* send caset + paset together */ + set->cmds = kcalloc(set->count, sizeof(*set->cmds), GFP_KERNEL); + if (!set->cmds) { + rc = -ENOMEM; + goto error_free_mem; + } + set->cmds[0].msg.channel = 0; + set->cmds[0].msg.type = MIPI_DSI_DCS_LONG_WRITE; + set->cmds[0].msg.flags = unicast ? MIPI_DSI_MSG_UNICAST : 0; + set->cmds[0].msg.ctrl = unicast ? ctrl_idx : 0; + set->cmds[0].msg.tx_len = ROI_CMD_LEN; + set->cmds[0].msg.tx_buf = caset; + set->cmds[0].msg.rx_len = 0; + set->cmds[0].msg.rx_buf = 0; + set->cmds[0].msg.wait_ms = 0; + set->cmds[0].last_command = 0; + set->cmds[0].post_wait_ms = 0; + + set->cmds[1].msg.channel = 0; + set->cmds[1].msg.type = MIPI_DSI_DCS_LONG_WRITE; + set->cmds[1].msg.flags = unicast ? MIPI_DSI_MSG_UNICAST : 0; + set->cmds[1].msg.ctrl = unicast ? ctrl_idx : 0; + set->cmds[1].msg.tx_len = ROI_CMD_LEN; + set->cmds[1].msg.tx_buf = paset; + set->cmds[1].msg.rx_len = 0; + set->cmds[1].msg.rx_buf = 0; + set->cmds[1].msg.wait_ms = 0; + set->cmds[1].last_command = 1; + set->cmds[1].post_wait_ms = 0; + + goto exit; + +error_free_mem: + kfree(caset); + kfree(paset); + kfree(set->cmds); + +exit: + return rc; +} + +int dsi_panel_send_qsync_on_dcs(struct dsi_panel *panel, + int ctrl_idx) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + DSI_DEBUG("ctrl:%d qsync on\n", ctrl_idx); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_QSYNC_ON); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_QSYNC_ON cmds rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_send_qsync_off_dcs(struct dsi_panel *panel, + int ctrl_idx) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + DSI_DEBUG("ctrl:%d qsync off\n", ctrl_idx); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_QSYNC_OFF); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_QSYNC_OFF cmds rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx, + struct dsi_rect *roi) +{ + int rc = 0; + struct dsi_panel_cmd_set *set; + struct dsi_display_mode_priv_info *priv_info; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + priv_info = panel->cur_mode->priv_info; + set = &priv_info->cmd_sets[DSI_CMD_SET_ROI]; + + rc = dsi_panel_roi_prepare_dcs_cmds(set, roi, ctrl_idx, true); + if (rc) { + DSI_ERR("[%s] failed to prepare DSI_CMD_SET_ROI cmds, rc=%d\n", + panel->name, rc); + return rc; + } + DSI_DEBUG("[%s] send roi x %d y %d w %d h %d\n", panel->name, + roi->x, roi->y, roi->w, roi->h); + SDE_EVT32(roi->x, roi->y, roi->w, roi->h); + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ROI); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_ROI cmds, rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + + dsi_panel_destroy_cmd_packets(set); + dsi_panel_dealloc_cmd_packets(set); + + return rc; +} + +int dsi_panel_pre_mode_switch_to_video(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_CMD_TO_VID_SWITCH); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_pre_mode_switch_to_cmd(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_VID_TO_CMD_SWITCH); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_mode_switch_to_cmd(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_VID_TO_CMD_SWITCH); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_mode_switch_to_vid(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_CMD_TO_VID_SWITCH); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_switch(struct dsi_panel *panel) +{ + int rc = 0; + static int cur_h_active = 0; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (cur_h_active != panel->cur_mode->timing.h_active) { + udelay(2000); //Add delay for resolution switch garbage issue + cur_h_active = panel->cur_mode->timing.h_active; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_TIMING_SWITCH cmds, rc=%d\n", + panel->name, rc); + + DSI_ERR("panel->cur_mode->timing->h_active = %d\n", panel->cur_mode->timing.h_active); + mutex_unlock(&panel->panel_lock); + panel->panel_switch_status = false; + return rc; +} + +int dsi_panel_post_switch(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + panel->panel_switch_status = true; + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_TIMING_SWITCH); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_POST_TIMING_SWITCH cmds, rc=%d\n", + panel->name, rc); + + mutex_unlock(&panel->panel_lock); + return rc; +} + +bool aod_fod_flag = false; +bool aod_complete = false; +bool real_aod_mode = false; +int dsi_panel_enable(struct dsi_panel *panel) +{ + int rc = 0; + int blank; + struct drm_panel_notifier notifier_data; + + if (!panel) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + + mutex_lock(&panel->panel_lock); + + if (panel->aod_mode == 2) { + DSI_ERR("Send dsi_panel_set_aod_mode 2 cmds\n"); + rc = dsi_panel_set_aod_mode(panel, 2); + panel->aod_status = 1; + } + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ON); + if (rc) + DSI_ERR("[%s] failed to send DSI_CMD_SET_ON cmds, rc=%d\n", + panel->name, rc); + else + panel->panel_initialized = true; + + panel->need_power_on_backlight = true; + blank = DRM_PANEL_BLANK_UNBLANK_CHARGE; + notifier_data.data = ␣ + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + if (panel->aod_mode == 0) { + DSI_ERR("Send dsi_panel_set_aod_mode 0 cmds\n"); + panel->aod_status = 0; + aod_complete = false; + } + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_post_enable(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_ON); + if (rc) { + DSI_ERR("[%s] failed to send DSI_CMD_SET_POST_ON cmds, rc=%d\n", + panel->name, rc); + goto error; + } +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_pre_disable(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_OFF); + if (rc) { + DSI_ERR("[%s] failed to send DSI_CMD_SET_PRE_OFF cmds, rc=%d\n", + panel->name, rc); + goto error; + } + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_disable(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + /* Avoid sending panel off commands when ESD recovery is underway */ + if (!atomic_read(&panel->esd_recovery_pending)) { + HBM_flag = false; + /* + * Need to set IBB/AB regulator mode to STANDBY, + * if panel is going off from AOD mode. + */ + if (dsi_panel_is_type_oled(panel) && + (panel->power_mode == SDE_MODE_DPMS_LP1 || + panel->power_mode == SDE_MODE_DPMS_LP2)) + dsi_pwr_panel_regulator_mode_set(&panel->power_info, + "ibb", REGULATOR_MODE_STANDBY); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF); + if (rc) { + /* + * Sending panel off commands may fail when DSI + * controller is in a bad state. These failures can be + * ignored since controller will go for full reset on + * subsequent display enable anyway. + */ + pr_warn_ratelimited("[%s] failed to send DSI_CMD_SET_OFF cmds, rc=%d\n", + panel->name, rc); + rc = 0; + } + DSI_ERR("aod_mode = %d\n", panel->aod_mode); + if (panel->aod_mode == 2) + panel->aod_status = 1; + if (panel->aod_mode == 0) + panel->aod_status = 0; + } + panel->panel_initialized = false; + panel->power_mode = SDE_MODE_DPMS_OFF; + + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_unprepare(struct dsi_panel *panel) +{ + int rc = 0; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_OFF); + if (rc) { + DSI_ERR("[%s] failed to send DSI_CMD_SET_POST_OFF cmds, rc=%d\n", + panel->name, rc); + goto error; + } + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_post_unprepare(struct dsi_panel *panel) +{ + int rc = 0; + int blank; + struct drm_panel_notifier notifier_data; + + if (!panel) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + + rc = dsi_panel_power_off(panel); + if (rc) { + DSI_ERR("[%s] panel power_Off failed, rc=%d\n", + panel->name, rc); + goto error; + } +error: + blank = DRM_PANEL_BLANK_POWERDOWN_CHARGE; + notifier_data.data = ␣ + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + mutex_unlock(&panel->panel_lock); + return rc; +} +int dsi_panel_set_seed_lp_mode(struct dsi_panel *panel, int seed_lp_level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + mode = panel->cur_mode; + + switch (seed_lp_level) { + case 0: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_LP_ON_0].count; + if (!count) { + DSI_ERR("This panel does not support seed lp mode0 on.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SEED_LP_ON_0); + if(!rc){ + DSI_ERR("This panel does not support seed lp mode0.\n"); + goto error; + } + DSI_ERR("Send DSI_CMD_SET_SEED_LP_ON_0 cmds.\n"); + } + break; + + case 1: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_LP_ON_1].count; + if (!count) { + DSI_ERR("This panel does not support seed lp mode1.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SEED_LP_ON_1); + if(!rc){ + DSI_ERR("This panel does not support seed lp mode1.\n"); + goto error; + } + DSI_ERR("Send DSI_CMD_SET_SEED_LP_ON_1 cmds.\n"); + } + break; + + case 2: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_LP_ON_2].count; + if (!count) { + DSI_ERR("This panel does not support seed lp mode2.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SEED_LP_ON_2); + if(!rc){ + DSI_ERR("This panel does not support seed lp mode2.\n"); + goto error; + } + DSI_ERR("Send DSI_CMD_SET_SEED_LP_ON_2 cmds.\n"); + } + break; + + case 4: //default off + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_LP_OFF].count; + if (!count) { + DSI_ERR("This panel does not support seed lp off.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SEED_LP_OFF); + if(!rc){ + DSI_ERR("This panel does not support seed lp off.\n"); + goto error; + } + DSI_ERR("Send DSI_CMD_SET_SEED_LP_OFF cmds.\n"); + } + break; + + default: + break; + } + + error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_hbm_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&panel->panel_lock); + mode = panel->cur_mode; + + switch (level) { + case 0: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_OFF].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode off.\n"); + goto error; + } + else { + HBM_flag = false; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_OFF); + DSI_ERR("Send DSI_CMD_SET_HBM_OFF cmds.\n"); + DSI_ERR("hbm_backight = %d, panel->bl_config.bl_level = %d\n",panel->hbm_backlight, panel->bl_config.bl_level); + rc= dsi_panel_update_backlight(panel,panel->hbm_backlight); + } + break; + + case 1: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_1].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode 1.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON_1); + DSI_ERR("Send DSI_CMD_SET_HBM_ON_1 cmds.\n"); + } + break; + + case 2: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_2].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode 2.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON_2); + DSI_ERR("Send DSI_CMD_SET_HBM_ON_2 cmds.\n"); + } + break; + + case 3: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_3].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode 3.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON_3); + DSI_ERR("Send DSI_CMD_SET_HBM_ON_3 cmds.\n"); + } + break; + + case 4: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_4].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode 4.\n"); + goto error; + } + else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON_4); + DSI_ERR("Send DSI_CMD_SET_HBM_ON_4 cmds.\n"); + } + break; + + case 5: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_5].count; + if (!count) { + DSI_ERR("This panel does not support HBM mode 5.\n"); + goto error; + } + else { + HBM_flag = true; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON_5); + DSI_ERR("Send DSI_CMD_SET_HBM_ON_5 cmds.\n"); + } + break; + + default: + break; + } + + DSI_ERR("Set HBM Mode = %d\n", level); + if(level == 5){ + DSI_ERR("HBM == 5 for fingerprint\n"); + } + + error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_hbm_brightness(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct mipi_dsi_device *dsi; + struct dsi_display_mode *mode; + + if (!panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + dsi = &panel->mipi_device; + mode = panel->cur_mode; + + if (panel->is_hbm_enabled) { + hbm_finger_print = true; + DSI_ERR("HBM is enabled\n"); + return 0; + } + + mutex_lock(&panel->panel_lock); + if (hbm_brightness_flag == 0) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_BRIGHTNESS_ON].count; + if (!count) { + DSI_ERR("This panel does not support HBM brightness on mode.\n"); + goto error; + } + else { + DSI_ERR("Send DSI_CMD_SET_HBM_BRIGHTNESS_ON cmds.\n"); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_BRIGHTNESS_ON); + hbm_brightness_flag = 1; + } + } + + + if ((panel->panel_stage_info == 0x02) || (panel->panel_stage_info == 0x03) + || (panel->panel_stage_info == 0x04)) { + level = level + 2048 + (380 * 2); + if (level > 4095) + level = 4095; + } + else + level = level + 2048; + rc = mipi_dsi_dcs_set_display_brightness_samsung(dsi, level); + + DSI_ERR("hbm backlight = %d\n", level); + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_acl_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_cmd_desc *cmds; + struct dsi_display_mode *mode; + u8 *tx = NULL; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mutex_lock(&panel->panel_lock); + + mode = panel->cur_mode; + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_ACL_MODE].count; + cmds = mode->priv_info->cmd_sets[DSI_CMD_SET_ACL_MODE].cmds; + + if (count == 0) { + DSI_ERR("This panel does not support acl mode\n"); + goto error; + } + + tx = (u8 *)cmds[panel->acl_cmd_index].msg.tx_buf; + if (tx != NULL) { + tx[panel->acl_mode_index] = level; + } + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_ACL_MODE); + + DSI_ERR("Set ACL Mode = %d\n", level); + +error: + mutex_unlock(&panel->panel_lock); + + return rc; +} + +int dsi_panel_set_dci_p3_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + if(aod_fod_flag==true) + return rc; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + if (level) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_DCI_P3_ON].count; + + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DCI_P3_ON); + DSI_ERR("DCI-P3 Mode On.\n"); + } else { + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DCI_P3_OFF); + DSI_ERR("DCI-P3 Mode Off.\n"); + } + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_set_night_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + if (level) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NIGHT_ON].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NIGHT_ON); + DSI_ERR("night Mode On.\n"); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NIGHT_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NIGHT_OFF); + DSI_ERR("night Mode Off.\n"); + } + mutex_unlock(&panel->panel_lock); + return rc; +} +int dsi_panel_set_native_display_p3_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + if (level) { + /* jack.jiao@MM 20200612 modify for distinguish seed value for normal light and low light*/ + if (panel->bl_config.bl_level >= seed_low_backlight) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_P3_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_P3_ON); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_P3_LOW_BACKLIGHT_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_P3_LOW_BACKLIGHT_ON); + } + DSI_ERR("Native Display p3 Mode On, the back light lever is %d.\n", panel->bl_config.bl_level); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_P3_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_P3_OFF); + DSI_ERR("Native Display p3 Mode Off.\n"); + } + mutex_unlock(&panel->panel_lock); +return rc; +} + +int dsi_panel_set_native_display_wide_color_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + if (level) { + /* jack.jiao@MM 20200612 modify for distinguish seed value for normal light and low light*/ + if (panel->bl_config.bl_level >= seed_low_backlight) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_ON); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_LOW_BACKLIGHT_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_LOW_BACKLIGHT_ON); + } + DSI_ERR("Native wide color Mode On, the backlight lever is %d.\n", panel->bl_config.bl_level); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_WIDE_COLOR_OFF); + DSI_ERR("Native wide color Mode Off.\n"); + } + mutex_unlock(&panel->panel_lock); +return rc; +} + +int dsi_panel_set_native_display_srgb_color_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + if (level) { + /* jack.jiao@MM 20200612 modify for distinguish seed value for normal light and low light*/ + if (panel->bl_config.bl_level >= seed_low_backlight) { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_ON); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_LOW_BACKLIGHT_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_LOW_BACKLIGHT_ON); + } + DSI_ERR("Native srgb color Mode On, the backlight lever is %d.\n", panel->bl_config.bl_level); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NATIVE_DISPLAY_SRGB_COLOR_OFF); + DSI_ERR("Native srgb color Mode Off.\n"); + } + mutex_unlock(&panel->panel_lock); +return rc; +} + + +int dsi_panel_set_native_loading_effect_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + if (level) { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_EFFECT_ON].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_EFFECT_ON); + DSI_ERR("turn on loading effect\n"); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_EFFECT_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_EFFECT_OFF); + DSI_ERR("turn off loading effect.\n"); + } + mutex_unlock(&panel->panel_lock); +return rc; +} + +int dsi_panel_set_customer_srgb_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + if (level) { + /* jack.jiao@MM 20200612 modify for distinguish seed value for normal light and low light*/ + if (panel->bl_config.bl_level >= seed_low_backlight) { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_CUSTOMER_RGB_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_ON); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_CUSTOMER_RGB_LOW_BACKLIGHT_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_LOW_BACKLIGHT_ON); + } + DSI_ERR("turn on customer srgb, the backlight lever is %d.\n", panel->bl_config.bl_level); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_CUSTOMER_RGB_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_RGB_OFF); + DSI_ERR("turn off customer srgb\n"); + } + mutex_unlock(&panel->panel_lock); +return rc; +} + +int dsi_panel_set_customer_p3_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + u32 count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + if (level) { + /* jack.jiao@MM 20200612 modify for distinguish seed value for normal light and low light*/ + if (panel->bl_config.bl_level >= seed_low_backlight) { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_CUSTOMER_P3_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_ON); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_CUSTOMER_P3_LOW_BACKLIGHT_ON].count; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_LOW_BACKLIGHT_ON); + } + DSI_ERR("turn on customer p3, the backlight lever is %d.\n", panel->bl_config.bl_level); + } else { + count = mode->priv_info->cmd_sets[DSI_CMD_LOADING_CUSTOMER_P3_OFF].count; + + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_LOADING_CUSTOMER_P3_OFF); + DSI_ERR("turn off customer P3\n"); + } + mutex_unlock(&panel->panel_lock); +return rc; +} + +int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + struct dsi_display_mode *mode; + struct drm_panel_notifier notifier_data; + int tp_aod_flag; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (panel->aod_disable) + return 0; + + mode = panel->cur_mode; + DSI_ERR("aod_status == %d\n", panel->aod_status); + + if (level == 1) { + mutex_lock(&panel->panel_lock); + panel->aod_status = 1; + real_aod_mode = true; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_ON_1); + aod_complete = true; + DSI_ERR("Send DSI_CMD_SET_AOD_ON_1 cmds\n"); + + tp_aod_flag = 100; + notifier_data.data = &tp_aod_flag; + DSI_ERR("set aod state TP flag: %d\n", tp_aod_flag); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + + aod_fod_flag = false; + mutex_unlock(&panel->panel_lock); + } else if (level == 2) { + if (panel->aod_status == 0) { + panel->aod_status = 1; + real_aod_mode = false; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_ON_2); + DSI_ERR("Send DSI_CMD_SET_AOD_ON_2 cmds\n"); + + tp_aod_flag = 100; + notifier_data.data = &tp_aod_flag; + DSI_ERR("set aod state TP flag: %d\n", tp_aod_flag); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + + aod_fod_flag = false; + } + } else if (level == 3) { + mutex_lock(&panel->panel_lock); + panel->aod_status = 1; + real_aod_mode = true; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_ON_3); + aod_complete = true; + DSI_ERR("Send DSI_CMD_SET_AOD_ON_3 cmds\n"); + + tp_aod_flag = 100; + notifier_data.data = &tp_aod_flag; + DSI_ERR("set aod state TP flag: %d\n", tp_aod_flag); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + + aod_fod_flag = false; + mutex_unlock(&panel->panel_lock); + } else if (level == 4 || level == 5) { + mutex_lock(&panel->panel_lock); + panel->aod_status = 1; + real_aod_mode = true; + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_ON_5); + aod_complete = true; + DSI_ERR("Send DSI_CMD_SET_AOD_ON_5 cmds\n"); + + tp_aod_flag = 100; + notifier_data.data = &tp_aod_flag; + DSI_ERR("set aod state TP flag: %d\n", tp_aod_flag); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + + aod_fod_flag = false; + mutex_unlock(&panel->panel_lock); + } else { + if (panel->aod_status) { + panel->aod_status = 0; + if (aod_fod_flag == true) { + if (real_aod_mode) { + mutex_lock(&panel->panel_lock); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_OFF); + mutex_unlock(&panel->panel_lock); + DSI_ERR("Real aod mode send DSI_CMD_SET_AOD_OFF cmds\n"); + } else { + DSI_ERR("real_aod_mode is %d, aod_fod_flag is %d\n", real_aod_mode, aod_fod_flag); + } + } + if (aod_fod_flag == false) { + if (real_aod_mode) { + mutex_lock(&panel->panel_lock); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_OFF_NEW); + mutex_unlock(&panel->panel_lock); + DSI_ERR("Real aod mode send DSI_CMD_SET_AOD_OFF_NEW cmds\n"); + } else { + DSI_ERR("real_aod_mode is %d, aod_fod_flag is %d\n", real_aod_mode, aod_fod_flag); + } + + if (level == 0) { + tp_aod_flag = 200; + notifier_data.data = &tp_aod_flag; + DSI_ERR("set aod state TP flag: %d\n", tp_aod_flag); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_EARLY_EVENT_BLANK, ¬ifier_data); + } + } + aod_complete = false; + } + } + + panel->aod_curr_mode = level; + DSI_ERR("AOD mode = %d\n", level); + + return rc; +} + +int dsi_panel_send_dsi_panel_command(struct dsi_panel *panel) +{ + int rc = 0; + int count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + mutex_lock(&panel->panel_lock); + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_COMMAND].count; + if (!count) { + DSI_ERR("This panel does not support DSI_CMD_SET_PANEL_COMMAND\n"); + goto error; + } + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PANEL_COMMAND); + if (rc) + DSI_ERR("Failed to send dsi panel command\n"); + DSI_ERR("Send DSI_CMD_SET_PANEL_COMMAND cmds.\n"); + +error: + mutex_unlock(&panel->panel_lock); + return rc; +} + +int dsi_panel_send_dsi_seed_command(struct dsi_panel *panel) +{ + int rc = 0; + int count; + struct dsi_display_mode *mode; + + if (!panel || !panel->cur_mode) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + mode = panel->cur_mode; + + count = mode->priv_info->cmd_sets[DSI_CMD_SET_SEED_COMMAND].count; + if (!count) { + DSI_ERR("This panel does not support DSI_CMD_SET_SEED_COMMAND\n"); + goto error; + } + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_SEED_COMMAND); + if (rc) + DSI_ERR("Failed to send dsi seed command\n"); +// DSI_ERR("Send DSI_CMD_SET_SEED_COMMAND cmds.\n"); + +error: + return rc; +} + +static int dsi_panel_parse_gamma_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, const char *data, unsigned int length, enum dsi_cmd_set_state state, enum dsi_gamma_cmd_set_type type) +{ + int rc = 0; + u32 packet_count = 0; + + if (!data) { + DSI_DEBUG("[%s] data not found\n", gamma_cmd_set_map[type]); + rc = -ENOTSUPP; + goto error; + } + + DSI_DEBUG("type=%d, name=%s, length=%d\n", type, + gamma_cmd_set_map[type], length); + + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 8, 1, data, length, false); + + rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count); + if (rc) { + DSI_ERR("commands failed, rc=%d\n", rc); + goto error; + } + DSI_DEBUG("[%s] packet-count=%d, %d\n", gamma_cmd_set_map[type], + packet_count, length); + + rc = dsi_panel_alloc_cmd_packets(cmd, packet_count); + if (rc) { + DSI_ERR("failed to allocate cmd packets, rc=%d\n", rc); + goto error; + } + + rc = dsi_panel_create_cmd_packets(data, length, packet_count, + cmd->cmds); + if (rc) { + DSI_ERR("failed to create cmd packets, rc=%d\n", rc); + goto error_free_mem; + } + + cmd->state = state; + + return rc; + +error_free_mem: + kfree(cmd->cmds); + cmd->cmds = NULL; + +error: + return rc; + +} + +int dsi_panel_parse_gamma_cmd_sets(void) +{ + int rc = 0; + int i = 0; + + memset(gamma_cmd_set, 0, 2*sizeof(struct dsi_panel_cmd_set)); + + for (i = 0; i < 2; i++) { + rc = dsi_panel_parse_gamma_cmd_sets_sub(&gamma_cmd_set[i], (char *)&gamma_para[i], sizeof(gamma_para)/2, DSI_CMD_SET_STATE_HS, i); + if (rc) { + DSI_ERR("Failed to parse gamma cmd sets %d, rc=%d\n", i, rc); + } + } + + return rc; +} + +int dsi_panel_tx_gamma_cmd_set(struct dsi_panel *panel, + enum dsi_gamma_cmd_set_type type) +{ + int rc = 0, i = 0; + ssize_t len; + struct dsi_cmd_desc *cmds; + u32 count; + enum dsi_cmd_set_state state; + const struct mipi_dsi_host_ops *ops = panel->host->ops; + + if (!panel) + return -EINVAL; + + cmds = gamma_cmd_set[type].cmds; + count = gamma_cmd_set[type].count; + state = gamma_cmd_set[type].state; + + if (count == 0) { + DSI_DEBUG("[%s] No commands to be sent for gamma state(%d)\n", + panel->name, type); + goto error; + } + + for (i = 0; i < count; i++) { + if (state == DSI_CMD_SET_STATE_LP) + cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM; + + if (cmds->last_command) + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + + len = ops->transfer(panel->host, &cmds->msg); + if (len < 0) { + rc = len; + DSI_ERR("failed to set cmds(%d), rc=%d\n", type, rc); + goto error; + } + if (cmds->post_wait_ms) + usleep_range(cmds->post_wait_ms*1000, + ((cmds->post_wait_ms*1000)+10)); + cmds++; + } +error: + return rc; +} + +int dsi_panel_update_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, + enum dsi_cmd_set_type type, const char *data, unsigned int length) +{ + int i = 0; + int rc = 0; + u32 packet_count = 0; + + if (!data) { + DSI_ERR("%s commands not defined\n", cmd_set_prop_map[type]); + rc = -ENOTSUPP; + goto error; + } + + DSI_ERR("type=%d, name=%s, length=%d\n", type, + cmd_set_prop_map[type], length); + + print_hex_dump_debug("", DUMP_PREFIX_NONE, + 8, 1, data, length, false); + + for (i = 0; i < length; i++) { + DSI_ERR("data[%d]=%02X", i, data[i]); + } + rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count); + if (rc) { + DSI_ERR("commands failed, rc=%d\n", rc); + goto error; + } + DSI_ERR("[%s] packet-count=%d, %d\n", cmd_set_prop_map[type], + packet_count, length); + + for (i = 0; i < cmd->count; i++) { + kfree(cmd->cmds[i].msg.tx_buf); + } + kfree(cmd->cmds); + cmd->cmds = NULL; + DSI_ERR("Free tx_buf and dsi_cmd_desc struct pointers done."); + + rc = dsi_panel_alloc_cmd_packets(cmd, packet_count); + if (rc) { + DSI_ERR("failed to allocate cmd packets, rc=%d\n", rc); + goto error; + } + + rc = dsi_panel_create_cmd_packets(data, length, packet_count, + cmd->cmds); + if (rc) { + DSI_ERR("failed to create cmd packets, rc=%d\n", rc); + goto error_free_mem; + } + + return rc; + +error_free_mem: + kfree(cmd->cmds); + cmd->cmds = NULL; + +error: + return rc; + +} + +int dsi_panel_update_dsi_seed_command(struct dsi_cmd_desc *cmds, + enum dsi_cmd_set_type type, const char *data) +{ + int i = 0; + int rc = 0; + u8 *payload; + + if (!data) { + DSI_ERR("%s commands not defined\n", cmd_set_prop_map[type]); + rc = -ENOTSUPP; + goto error; + } + + payload = (u8 *)cmds[3].msg.tx_buf; + for (i = 0; i < 0x16; i++) + payload[i] = data[i]; + +error: + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h new file mode 100644 index 0000000000000000000000000000000000000000..e6a6ab0d3487c66dd6827a01b275bd0881c2098e --- /dev/null +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -0,0 +1,442 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_PANEL_H_ +#define _DSI_PANEL_H_ + +#include <linux/of_device.h> +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/backlight.h> +#include <drm/drm_panel.h> +#include <drm/msm_drm.h> + +#include "dsi_defs.h" +#include "dsi_ctrl_hw.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "dsi_parser.h" +#include "msm_drv.h" + +#define MAX_BL_LEVEL 4096 +#define MAX_BL_SCALE_LEVEL 1024 +#define MAX_SV_BL_SCALE_LEVEL 65535 +#define DSI_CMD_PPS_SIZE 135 + +#define DSI_MODE_MAX 32 + +#define GAMMA_READ_SUCCESS 1 +#define GAMMA_READ_ERROR 0 +#define SP_READ_SUCCESS 1 +#define SP_READ_ERROR 0 +extern u32 mode_fps; +extern int gamma_read_flag; +extern int sp_read_flag; +enum dsi_gamma_cmd_set_type { + DSI_GAMMA_CMD_SET_SWITCH_60HZ = 0, + DSI_GAMMA_CMD_SET_SWITCH_90HZ, + DSI_GAMMA_CMD_SET_MAX +}; +/* + * Defining custom dsi msg flag, + * continued from drm_mipi_dsi.h + * Override to use async transfer + */ +#define MIPI_DSI_MSG_ASYNC_OVERRIDE BIT(4) + +enum dsi_panel_rotation { + DSI_PANEL_ROTATE_NONE = 0, + DSI_PANEL_ROTATE_HV_FLIP, + DSI_PANEL_ROTATE_H_FLIP, + DSI_PANEL_ROTATE_V_FLIP +}; + +enum dsi_backlight_type { + DSI_BACKLIGHT_PWM = 0, + DSI_BACKLIGHT_WLED, + DSI_BACKLIGHT_DCS, + DSI_BACKLIGHT_EXTERNAL, + DSI_BACKLIGHT_UNKNOWN, + DSI_BACKLIGHT_MAX, +}; + +enum bl_update_flag { + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME, + BL_UPDATE_NONE, +}; + +enum { + MODE_GPIO_NOT_VALID = 0, + MODE_SEL_DUAL_PORT, + MODE_SEL_SINGLE_PORT, + MODE_GPIO_HIGH, + MODE_GPIO_LOW, +}; + +enum dsi_dms_mode { + DSI_DMS_MODE_DISABLED = 0, + DSI_DMS_MODE_RES_SWITCH_IMMEDIATE, +}; + +enum dsi_panel_physical_type { + DSI_DISPLAY_PANEL_TYPE_LCD = 0, + DSI_DISPLAY_PANEL_TYPE_OLED, + DSI_DISPLAY_PANEL_TYPE_MAX, +}; + +struct dsi_dfps_capabilities { + enum dsi_dfps_type type; + u32 min_refresh_rate; + u32 max_refresh_rate; + u32 *dfps_list; + u32 dfps_list_len; + bool dfps_support; +}; + +struct dsi_dyn_clk_caps { + bool dyn_clk_support; + u32 *bit_clk_list; + u32 bit_clk_list_len; + enum dsi_dyn_clk_feature_type type; + bool maintain_const_fps; +}; + +struct dsi_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *active; + struct pinctrl_state *suspend; +}; + +struct dsi_panel_phy_props { + u32 panel_width_mm; + u32 panel_height_mm; + enum dsi_panel_rotation rotation; +}; + +struct dsi_backlight_config { + enum dsi_backlight_type type; + enum bl_update_flag bl_update; + + u32 bl_min_level; + u32 bl_max_level; + u32 brightness_max_level; + u32 bl_level; + u32 bl_scale; + u32 bl_scale_sv; + bool bl_inverted_dbv; + + int en_gpio; + /* PWM params */ + struct pwm_device *pwm_bl; + bool pwm_enabled; + u32 pwm_period_usecs; + bool bl_high2bit; + u32 bl_def_val; + + /* WLED params */ + struct led_trigger *wled; + struct backlight_device *raw_bd; +}; + +struct dsi_reset_seq { + u32 level; + u32 sleep_ms; +}; + +struct dsi_panel_reset_config { + struct dsi_reset_seq *sequence; + u32 count; + + int reset_gpio; + int disp_en_gpio; + int lcd_mode_sel_gpio; + u32 mode_sel_state; +}; + +enum esd_check_status_mode { + ESD_MODE_REG_READ, + ESD_MODE_SW_BTA, + ESD_MODE_PANEL_TE, + ESD_MODE_SW_SIM_SUCCESS, + ESD_MODE_SW_SIM_FAILURE, + ESD_MODE_MAX +}; + +struct drm_panel_esd_config { + bool esd_enabled; + + enum esd_check_status_mode status_mode; + struct dsi_panel_cmd_set status_cmd; + u32 *status_cmds_rlen; + u32 *status_valid_params; + u32 *status_value; + u8 *return_buf; + u8 *status_buf; + u32 groups; +}; + +struct dsi_panel { + const char *name; + const char *type; + struct device_node *panel_of_node; + struct mipi_dsi_device mipi_device; + + struct mutex panel_lock; + struct drm_panel drm_panel; + struct mipi_dsi_host *host; + struct device *parent; + + struct dsi_host_common_cfg host_config; + struct dsi_video_engine_cfg video_config; + struct dsi_cmd_engine_cfg cmd_config; + enum dsi_op_mode panel_mode; + bool panel_mode_switch_enabled; + + struct dsi_dfps_capabilities dfps_caps; + struct dsi_dyn_clk_caps dyn_clk_caps; + struct dsi_panel_phy_props phy_props; + + struct dsi_display_mode *cur_mode; + u32 num_timing_nodes; + u32 num_display_modes; + + struct dsi_regulator_info power_info; + struct dsi_backlight_config bl_config; + struct dsi_panel_reset_config reset_config; + struct dsi_pinctrl_info pinctrl; + struct drm_panel_hdr_properties hdr_props; + struct drm_panel_esd_config esd_config; + + struct dsi_parser_utils utils; + char buf_id[32]; + char buf_select[10]; + int panel_ic_v; + int panel_year; + int panel_mon; + int panel_day; + int panel_hour; + int panel_min; + int panel_sec; + int panel_msec; + int panel_msec_int; + int panel_msec_rem; + int panel_year_index; + int panel_mon_index; + int panel_day_index; + int panel_hour_index; + int panel_min_index; + int panel_sec_index; + int panel_msec_high_index; + int panel_msec_low_index; + int panel_code_info; + int panel_stage_info; + int panel_production_info; + int ddic_check_info; + int ddic_x; + int ddic_y; + int acl_mode; + int acl_cmd_index; + int acl_mode_index; + int hbm_mode; + int hbm_brightness; + int aod_mode; + int aod_status; + int aod_curr_mode; + int aod_disable; + int srgb_mode; + int dci_p3_mode; + int night_mode; + int oneplus_mode; + int adaption_mode; + int status_value; + int panel_mismatch_check; + int panel_mismatch; + int hbm_backlight; + int naive_display_p3_mode; + int naive_display_wide_color_mode; + int naive_display_srgb_color_mode; + int naive_display_loading_effect_mode; + int naive_display_customer_srgb_mode; + int naive_display_customer_p3_mode; + bool need_power_on_backlight; + struct delayed_work gamma_read_work; + int tp1v8_gpio; + int vddr_gpio; + int err_flag_gpio; + bool is_err_flag_irq_enabled; + bool err_flag_status; + bool panel_switch_status; + bool is_hbm_enabled; + int op_force_screenfp; + bool dim_status; + int seed_lp_mode; + int poc; + int panel_tool; + bool lp11_init; + bool ulps_feature_enabled; + bool ulps_suspend_enabled; + bool allow_phy_power_off; + bool reset_gpio_always_on; + atomic_t esd_recovery_pending; + + bool panel_initialized; + bool te_using_watchdog_timer; + u32 qsync_min_fps; + + char dsc_pps_cmd[DSI_CMD_PPS_SIZE]; + enum dsi_dms_mode dms_mode; + + bool sync_broadcast_en; + + int panel_test_gpio; + int power_mode; + enum dsi_panel_physical_type panel_type; +}; + +static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel) +{ + return panel->ulps_feature_enabled; +} + +static inline bool dsi_panel_initialized(struct dsi_panel *panel) +{ + return panel->panel_initialized; +} + +static inline void dsi_panel_acquire_panel_lock(struct dsi_panel *panel) +{ + mutex_lock(&panel->panel_lock); +} + +static inline void dsi_panel_release_panel_lock(struct dsi_panel *panel) +{ + mutex_unlock(&panel->panel_lock); +} + +static inline bool dsi_panel_is_type_oled(struct dsi_panel *panel) +{ + return (panel->panel_type == DSI_DISPLAY_PANEL_TYPE_OLED); +} + +struct dsi_panel *dsi_panel_get(struct device *parent, + struct device_node *of_node, + struct device_node *parser_node, + const char *type, + int topology_override); + +int dsi_panel_trigger_esd_attack(struct dsi_panel *panel); + +void dsi_panel_put(struct dsi_panel *panel); + +int dsi_panel_drv_init(struct dsi_panel *panel, struct mipi_dsi_host *host); + +int dsi_panel_drv_deinit(struct dsi_panel *panel); + +int dsi_panel_get_mode_count(struct dsi_panel *panel); + +void dsi_panel_put_mode(struct dsi_display_mode *mode); + +int dsi_panel_get_mode(struct dsi_panel *panel, + u32 index, + struct dsi_display_mode *mode, + int topology_override); + +int dsi_panel_validate_mode(struct dsi_panel *panel, + struct dsi_display_mode *mode); + +int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel, + struct dsi_display_mode *mode, + struct dsi_host_config *config); + +int dsi_panel_get_phy_props(struct dsi_panel *panel, + struct dsi_panel_phy_props *phy_props); +int dsi_panel_get_dfps_caps(struct dsi_panel *panel, + struct dsi_dfps_capabilities *dfps_caps); + +int dsi_panel_pre_prepare(struct dsi_panel *panel); + +int dsi_panel_set_lp1(struct dsi_panel *panel); + +int dsi_panel_set_lp2(struct dsi_panel *panel); + +int dsi_panel_set_nolp(struct dsi_panel *panel); + +int dsi_panel_prepare(struct dsi_panel *panel); + +int dsi_panel_enable(struct dsi_panel *panel); + +int dsi_panel_post_enable(struct dsi_panel *panel); + +int dsi_panel_pre_disable(struct dsi_panel *panel); + +int dsi_panel_disable(struct dsi_panel *panel); + +int dsi_panel_unprepare(struct dsi_panel *panel); + +int dsi_panel_post_unprepare(struct dsi_panel *panel); + +int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl); + +int dsi_panel_update_pps(struct dsi_panel *panel); + +int dsi_panel_send_qsync_on_dcs(struct dsi_panel *panel, + int ctrl_idx); +int dsi_panel_send_qsync_off_dcs(struct dsi_panel *panel, + int ctrl_idx); + +int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx, + struct dsi_rect *roi); + +int dsi_panel_pre_mode_switch_to_video(struct dsi_panel *panel); +int dsi_panel_pre_mode_switch_to_cmd(struct dsi_panel *panel); +int dsi_panel_mode_switch_to_cmd(struct dsi_panel *panel); +int dsi_panel_mode_switch_to_vid(struct dsi_panel *panel); + +int dsi_panel_switch(struct dsi_panel *panel); + +int dsi_panel_post_switch(struct dsi_panel *panel); + +void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width); + +void dsi_panel_bl_handoff(struct dsi_panel *panel); + +struct dsi_panel *dsi_panel_ext_bridge_get(struct device *parent, + struct device_node *of_node, + int topology_override); + +int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel); + +void dsi_panel_ext_bridge_put(struct dsi_panel *panel); +int dsi_panel_set_hbm_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_acl_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_hbm_brightness(struct dsi_panel *panel, int level); +int dsi_panel_op_set_hbm_mode(struct dsi_panel *panel, int level); +void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, + struct dsi_display_mode *mode, u32 frame_threshold_us); +extern int drm_panel_notifier_call_chain(struct drm_panel *panel, + unsigned long val, void *v); +int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_dci_p3_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_night_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_native_display_p3_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_native_display_wide_color_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_native_display_srgb_color_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_native_loading_effect_mode(struct dsi_panel *panel, int level); +int dsi_panel_gamma_read_address_setting(struct dsi_panel *panel, u16 read_number); +int dsi_panel_tx_cmd_set(struct dsi_panel *panel, enum dsi_cmd_set_type type); +int dsi_panel_parse_gamma_cmd_sets(void); +int dsi_panel_tx_gamma_cmd_set(struct dsi_panel *panel, enum dsi_gamma_cmd_set_type type); +extern int mipi_dsi_dcs_write_c1(struct mipi_dsi_device *dsi, u16 read_number); +int dsi_panel_update_cmd_sets_sub(struct dsi_panel_cmd_set *cmd, + enum dsi_cmd_set_type type, const char *data, unsigned int length); +int dsi_panel_send_dsi_panel_command(struct dsi_panel *panel); +int dsi_panel_update_dsi_seed_command(struct dsi_cmd_desc *cmds, + enum dsi_cmd_set_type type, const char *data); +int dsi_panel_send_dsi_seed_command(struct dsi_panel *panel); +int dsi_panel_set_customer_srgb_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_customer_p3_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_seed_lp_mode(struct dsi_panel *panel, int seed_lp_level); +#endif /* _DSI_PANEL_H_ */ diff --git a/techpack/display/msm/dsi/dsi_parser.c b/techpack/display/msm/dsi/dsi_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..cef5fe70cf5d55dcd0ffd8d85b6adda5a266b572 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_parser.c @@ -0,0 +1,1250 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/firmware.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/device.h> + +#include "dsi_parser.h" +#include "dsi_defs.h" + +#define DSI_PARSER_MAX_NODES 20 + +enum dsi_parser_prop_type { + DSI_PROP_TYPE_STR, + DSI_PROP_TYPE_STR_ARRAY, + DSI_PROP_TYPE_INT_SET, + DSI_PROP_TYPE_INT_SET_ARRAY, + DSI_PROP_TYPE_INT_ARRAY, +}; + +struct dsi_parser_prop { + char *name; + char *raw; + char *value; + char **items; + enum dsi_parser_prop_type type; + int len; +}; + +struct dsi_parser_node { + char *name; + char *data; + + struct dsi_parser_prop *prop; + int prop_count; + + struct dsi_parser_node *child[DSI_PARSER_MAX_NODES]; + int children_count; +}; + +struct dsi_parser { + const struct firmware *fw; + struct dsi_parser_node *head_node; + struct dsi_parser_node *current_node; + struct device *dev; + char *buf; + char file_name[SZ_32]; +}; + +static int dsi_parser_count(char *buf, int item) +{ + int count = 0; + + do { + buf = strnchr(buf, strlen(buf), item); + if (buf) + count++; + } while (buf++); + + return count; +} + +static char *dsi_parser_clear_tail(char *buf) +{ + int size = strlen(buf); + char *end; + + if (!size) + goto exit; + + end = buf + size - 1; + while (end >= buf && *end == '*') + end--; + + *(end + 1) = '\0'; +exit: + return buf; +} + +static char *dsi_parser_strim(char *buf) +{ + strreplace(buf, '*', ' '); + + return strim(buf); +} + +static char *dsi_parser_get_data(char *start, char *end, char *str) +{ + strsep(&str, start); + if (str) + return dsi_parser_clear_tail(strsep(&str, end)); + + return NULL; +} + +static bool dsi_parser_get_tuples_data( + struct dsi_parser_prop *prop, char *str) +{ + bool middle_of_tx = false; + + if (!str) { + DSI_ERR("Invalid input\n"); + return middle_of_tx; + } + + while (str) { + char *out = strsep(&str, " "); + + if (str || middle_of_tx) { + middle_of_tx = true; + + prop->items[prop->len++] = dsi_parser_strim(out); + } + } + + return middle_of_tx; +} + +static bool dsi_parser_get_strings(struct device *dev, + struct dsi_parser_prop *prop, char *str) +{ + bool middle_of_tx = false; + int i = 0; + int count = 0; + + if (!str) { + DSI_ERR("Invalid input\n"); + goto end; + } + + if (!dsi_parser_count(str, '"')) + goto end; + + count = dsi_parser_count(str, ','); + DSI_DEBUG("count=%d\n", count); + + if (!count) { + prop->value = dsi_parser_get_data("\"", "\"", str); + prop->type = DSI_PROP_TYPE_STR; + middle_of_tx = prop->value ? true : false; + + goto end; + } + + /* number of items are 1 more than separator */ + count++; + prop->items = devm_kzalloc(dev, count, GFP_KERNEL); + if (!prop->items) + goto end; + + prop->type = DSI_PROP_TYPE_STR_ARRAY; + + while (str) { + char *out = strsep(&str, ","); + + if ((str || middle_of_tx) && (i < count)) { + prop->items[i++] = + dsi_parser_get_data("\"", "\"", out); + prop->len++; + + middle_of_tx = true; + } + } +end: + return middle_of_tx; +} + +static bool dsi_parser_get_tuples(struct device *dev, + struct dsi_parser_prop *prop, char *str) +{ + bool middle_of_tx = false; + char *data = NULL; + + if (!str) { + DSI_ERR("Invalid input\n"); + return middle_of_tx; + } + + while (str) { + char *out = strsep(&str, ","); + + if (str || middle_of_tx) { + data = dsi_parser_get_data("<", ">", out); + middle_of_tx = true; + + dsi_parser_get_tuples_data(prop, data); + } + } + + return middle_of_tx; +} + +static void dsi_parser_get_int_value(struct dsi_parser_prop *prop, + int forced_base) +{ + int i; + + for (i = 0; i < prop->len; i++) { + int base, val; + char *to_int, *tmp; + char item[SZ_128]; + + strlcpy(item, prop->items[i], SZ_128); + + tmp = item; + + if (forced_base) { + base = forced_base; + } else { + to_int = strsep(&tmp, "x"); + + if (!tmp) { + tmp = to_int; + base = 10; + } else { + base = 16; + } + } + + if (kstrtoint(tmp, base, &val)) { + DSI_ERR("error converting %s at %d\n", + tmp, i); + + continue; + } + + prop->value[i] = val & 0xFF; + } +} + +static bool dsi_parser_parse_prop(struct device *dev, + struct dsi_parser_prop *prop, char *buf) +{ + bool found = false; + char *out = strsep(&buf, "="); + size_t buf_len; + + if (!out || !buf) + goto end; + + buf_len = strlen(buf); + + prop->raw = devm_kzalloc(dev, buf_len + 1, GFP_KERNEL); + if (!prop->raw) + goto end; + + strlcpy(prop->raw, buf, buf_len + 1); + + found = true; + + prop->name = dsi_parser_strim(out); + DSI_DEBUG("RAW: %s: %s\n", prop->name, prop->raw); + + prop->len = 0; + + if (dsi_parser_get_strings(dev, prop, buf)) + goto end; + + prop->items = devm_kzalloc(dev, strlen(buf) * 2, GFP_KERNEL); + if (!prop->items) + goto end; + + if (dsi_parser_get_tuples(dev, prop, buf)) { + prop->value = devm_kzalloc(dev, prop->len, GFP_KERNEL); + if (prop->value) { + prop->type = DSI_PROP_TYPE_INT_SET_ARRAY; + dsi_parser_get_int_value(prop, 0); + } + goto end; + } + + prop->value = dsi_parser_get_data("<", ">", buf); + if (prop->value) { + if (dsi_parser_get_tuples_data(prop, prop->value)) { + prop->value = devm_kzalloc(dev, prop->len, GFP_KERNEL); + if (prop->value) { + prop->type = DSI_PROP_TYPE_INT_SET; + dsi_parser_get_int_value(prop, 0); + } + goto end; + } else { + prop->items[prop->len++] = prop->value; + } + + goto end; + } + + prop->value = dsi_parser_get_data("[", "]", buf); + if (prop->value) { + char *out5; + + if (!prop->items) + goto end; + + out5 = prop->value; + while (out5 && strlen(out5)) { + char *out6 = strsep(&out5, " "); + + out6 = dsi_parser_strim(out6); + if (out6 && strlen(out6)) + prop->items[prop->len++] = out6; + } + + prop->value = devm_kzalloc(dev, prop->len, GFP_KERNEL); + if (prop->value) { + prop->type = DSI_PROP_TYPE_INT_ARRAY; + + dsi_parser_get_int_value(prop, 16); + } + } else { + found = false; + } +end: + return found; +} + +static char *dsi_parser_clean_name(char *name) +{ + char *clean_name = name; + + if (!name) { + DSI_ERR("Invalid input\n"); + return NULL; + } + + while (name) + clean_name = strsep(&name, ";"); + + return dsi_parser_strim(clean_name); +} + +static char *dsi_parser_get_blob(char **buf, bool *has_child) +{ + char *data = NULL; + char *start = *buf; + + data = strpbrk(*buf, "{}"); + if (!data) + goto end; + + if (*data == '{') + *has_child = true; + + if (*has_child) { + while (data != *buf) { + data--; + if (*data == ';') { + data++; + *data = '\0'; + *buf = data + 1; + break; + } + } + } else { + *data = '\0'; + *buf = data + 1; + } +end: + return start; +} + +static struct dsi_parser_node *dsi_parser_find_nodes(struct device *dev, + char **buf) +{ + struct dsi_parser_node *node = NULL, *cnode = NULL; + char *name, *data; + bool has_child = false; + + if (!buf || !*buf) + goto end; + + data = strpbrk(*buf, "{}"); + if (!data) { + DSI_DEBUG("{} not found\n"); + goto end; + } + + if (*data == '}') { + *buf = data + 1; + goto end; + } + + name = strsep(buf, "{"); + + if (*buf && name) { + node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); + if (!node) + goto end; + + node->name = dsi_parser_clean_name(name); + node->data = dsi_parser_get_blob(buf, &has_child); + + if (!has_child) + goto end; + + do { + cnode = dsi_parser_find_nodes(dev, buf); + if (cnode && + (node->children_count < DSI_PARSER_MAX_NODES)) + node->child[node->children_count++] = cnode; + } while (cnode); + } +end: + return node; +} + +static void dsi_parser_count_properties(struct dsi_parser_node *node) +{ + int count; + + if (node && strlen(node->data)) { + node->prop_count = dsi_parser_count(node->data, ';'); + + for (count = 0; count < node->children_count; count++) + dsi_parser_count_properties(node->child[count]); + } +} + +static void dsi_parser_get_properties(struct device *dev, + struct dsi_parser_node *node) +{ + int count; + + if (!node) + return; + + if (node->prop_count) { + int i = 0; + char *buf = node->data; + + node->prop = devm_kcalloc(dev, node->prop_count, + sizeof(struct dsi_parser_prop), + GFP_KERNEL); + if (!node->prop) + return; + + for (i = 0; i < node->prop_count; i++) { + char *out = strsep(&buf, ";"); + struct dsi_parser_prop *prop = &node->prop[i]; + + if (!out || !prop) + continue; + + if (!dsi_parser_parse_prop(dev, prop, out)) { + char *out1 = strsep(&out, "}"); + + if (!out1) + continue; + + out1 = dsi_parser_strim(out1); + + if (!out && strlen(out1)) { + prop->name = out1; + prop->value = "1"; + } + } + } + } + + for (count = 0; count < node->children_count; count++) + dsi_parser_get_properties(dev, node->child[count]); +} + +static struct dsi_parser_prop *dsi_parser_search_property( + struct dsi_parser_node *node, + const char *name) +{ + int i = 0; + struct dsi_parser_prop *prop = node->prop; + + for (i = 0; i < node->prop_count; i++) { + if (prop[i].name && !strcmp(prop[i].name, name)) + return &prop[i]; + } + + return NULL; +} + +/* APIs for the clients */ +struct property *dsi_parser_find_property(const struct device_node *np, + const char *name, + int *lenp) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop = NULL; + + if (!node || !name || !lenp) + goto end; + + prop = dsi_parser_search_property(node, name); + if (!prop) { + DSI_DEBUG("%s not found\n", name); + goto end; + } + + if (lenp) { + if (prop->type == DSI_PROP_TYPE_INT_ARRAY) + *lenp = prop->len; + else if (prop->type == DSI_PROP_TYPE_INT_SET_ARRAY || + prop->type == DSI_PROP_TYPE_INT_SET) + *lenp = prop->len * sizeof(u32); + else + *lenp = strlen(prop->raw) + 1; + + DSI_DEBUG("%s len=%d\n", name, *lenp); + } +end: + return (struct property *)prop; +} + +bool dsi_parser_read_bool(const struct device_node *np, + const char *propname) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + bool prop_set; + + prop_set = dsi_parser_search_property(node, propname) ? true : false; + + DSI_DEBUG("%s=%s\n", propname, prop_set ? "set" : "not set"); + + return prop_set; +} + +int dsi_parser_read_string(const struct device_node *np, + const char *propname, const char **out_string) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + char *property = NULL; + int rc = 0; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + DSI_DEBUG("%s not found\n", propname); + rc = -EINVAL; + } else { + property = prop->value; + } + + *out_string = property; + + DSI_DEBUG("%s=%s\n", propname, *out_string); + return rc; +} + +int dsi_parser_read_u64(const struct device_node *np, const char *propname, + u64 *out_value) +{ + return -EINVAL; +} + +int dsi_parser_read_u32(const struct device_node *np, + const char *propname, u32 *out_value) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + char *property, *to_int, item[SZ_128]; + int rc = 0, base; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + DSI_DEBUG("%s not found\n", propname); + rc = -EINVAL; + goto end; + } + + if (!prop->value) + goto end; + + strlcpy(item, prop->value, SZ_128); + property = item; + to_int = strsep(&property, "x"); + + if (!property) { + property = to_int; + base = 10; + } else { + base = 16; + } + + rc = kstrtoint(property, base, out_value); + if (rc) { + DSI_ERR("prop=%s error(%d) converting %s, base=%d\n", + propname, rc, property, base); + goto end; + } + + DSI_DEBUG("%s=%d\n", propname, *out_value); +end: + return rc; +} + +int dsi_parser_read_u32_array(const struct device_node *np, + const char *propname, + u32 *out_values, size_t sz) +{ + int i, rc = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + DSI_DEBUG("%s not found\n", propname); + rc = -EINVAL; + goto end; + } + + for (i = 0; i < prop->len; i++) { + int base, val; + char item[SZ_128]; + char *to_int, *tmp; + + strlcpy(item, prop->items[i], SZ_128); + + tmp = item; + + to_int = strsep(&tmp, "x"); + + if (!tmp) { + tmp = to_int; + base = 10; + } else { + base = 16; + } + + rc = kstrtoint(tmp, base, &val); + if (rc) { + DSI_ERR("prop=%s error(%d) converting %s(%d), base=%d\n", + propname, rc, tmp, i, base); + continue; + } + + *out_values++ = val; + + DSI_DEBUG("%s: [%d]=%d\n", propname, i, *(out_values - 1)); + } +end: + return rc; +} + +const void *dsi_parser_get_property(const struct device_node *np, + const char *name, int *lenp) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + char *property = NULL; + + prop = dsi_parser_search_property(node, name); + if (!prop) { + DSI_DEBUG("%s not found\n", name); + goto end; + } + + property = prop->value; + + if (prop->type == DSI_PROP_TYPE_STR) + DSI_DEBUG("%s=%s\n", name, property); + + if (lenp) { + if (prop->type == DSI_PROP_TYPE_INT_ARRAY) + *lenp = prop->len; + else if (prop->type == DSI_PROP_TYPE_INT_SET_ARRAY || + prop->type == DSI_PROP_TYPE_INT_SET) + *lenp = prop->len * sizeof(u32); + else + *lenp = strlen(prop->raw) + 1; + + DSI_DEBUG("%s len=%d\n", name, *lenp); + } +end: + return property; +} + +struct device_node *dsi_parser_get_child_by_name(const struct device_node *np, + const char *name) +{ + int index = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_node *matched_node = NULL; + + if (!node || !node->children_count) + goto end; + + do { + struct dsi_parser_node *child_node = node->child[index++]; + + if (!child_node) + goto end; + + if (!strcmp(child_node->name, name)) { + matched_node = child_node; + break; + } + } while (index < node->children_count); +end: + DSI_DEBUG("%s: %s\n", name, matched_node ? "found" : "not found"); + + return (struct device_node *)matched_node; +} + +struct dsi_parser_node *dsi_parser_get_node_by_name( + struct dsi_parser_node *node, + char *name) +{ + int count = 0; + struct dsi_parser_node *matched_node = NULL; + + if (!node) { + DSI_ERR("node is null\n"); + goto end; + } + + if (!strcmp(node->name, name)) { + matched_node = node; + goto end; + } + + for (count = 0; count < node->children_count; count++) { + matched_node = dsi_parser_get_node_by_name( + node->child[count], name); + if (matched_node) + break; + } +end: + DSI_DEBUG("%s: %s\n", name, matched_node ? "found" : "not found"); + + return matched_node; +} + +int dsi_parser_get_child_count(const struct device_node *np) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + int count = 0; + + if (node) { + count = node->children_count; + DSI_DEBUG("node %s child count=%d\n", node->name, count); + } + + return count; +} + +struct device_node *dsi_parser_get_next_child(const struct device_node *np, + struct device_node *prev) +{ + int index = 0; + struct dsi_parser_node *parent = (struct dsi_parser_node *)np; + struct dsi_parser_node *prev_child = (struct dsi_parser_node *)prev; + struct dsi_parser_node *matched_node = NULL; + + if (!parent || !parent->children_count) + goto end; + + do { + struct dsi_parser_node *child_node = parent->child[index++]; + + if (!child_node) + goto end; + + if (!prev) { + matched_node = child_node; + goto end; + } + + if (!strcmp(child_node->name, prev_child->name)) { + if (index < parent->children_count) + matched_node = parent->child[index]; + break; + } + } while (index < parent->children_count); +end: + if (matched_node) + DSI_DEBUG("next child: %s\n", matched_node->name); + + return (struct device_node *)matched_node; +} + +int dsi_parser_count_u32_elems(const struct device_node *np, + const char *propname) +{ + int count = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + DSI_DEBUG("%s not found\n", propname); + goto end; + } + + count = prop->len; + + DSI_DEBUG("prop %s has %d items\n", prop->name, count); +end: + return count; +} + +int dsi_parser_count_strings(const struct device_node *np, + const char *propname) +{ + int count = 0; + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + DSI_DEBUG("%s not found\n", propname); + goto end; + } + + if (prop->type == DSI_PROP_TYPE_STR_ARRAY) + count = prop->len; + else if (prop->type == DSI_PROP_TYPE_STR) + count = 1; + + DSI_DEBUG("prop %s has %d items\n", prop->name, count); +end: + return count; +} + +int dsi_parser_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output) +{ + struct dsi_parser_node *node = (struct dsi_parser_node *)np; + struct dsi_parser_prop *prop; + + prop = dsi_parser_search_property(node, propname); + if (!prop) { + DSI_DEBUG("%s not found\n", propname); + goto end; + } + + if (prop->type != DSI_PROP_TYPE_STR_ARRAY) { + DSI_ERR("not a string array property\n"); + goto end; + } + + if (index >= prop->len) { + DSI_ERR("out of bond index %d\n", index); + goto end; + } + + *output = prop->items[index]; + + return 0; +end: + return -EINVAL; +} + +int dsi_parser_get_named_gpio(struct device_node *np, + const char *propname, int index) +{ + int gpio = -EINVAL; + + dsi_parser_read_u32(np, propname, &gpio); + + return gpio; +} + +void *dsi_parser_get_head_node(void *in, + const u8 *data, u32 size) +{ + struct dsi_parser *parser = in; + char *buf; + + if (!parser || !data || !size) { + DSI_ERR("invalid input\n"); + goto err; + } + + parser->buf = devm_kzalloc(parser->dev, size, GFP_KERNEL); + if (!parser->buf) + goto err; + + buf = parser->buf; + + memcpy(buf, data, size); + + strreplace(buf, '\n', ' '); + strreplace(buf, '\t', '*'); + + parser->head_node = dsi_parser_find_nodes(parser->dev, &buf); + if (!parser->head_node) { + DSI_ERR("could not get head node\n"); + devm_kfree(parser->dev, parser->buf); + goto err; + } + + dsi_parser_count_properties(parser->head_node); + dsi_parser_get_properties(parser->dev, parser->head_node); + + parser->current_node = parser->head_node; + + return parser->head_node; +err: + return NULL; +} + +static int dsi_parser_read_file(struct dsi_parser *parser, + const u8 **buf, u32 *size) +{ + int rc = 0; + + release_firmware(parser->fw); + + rc = request_firmware(&parser->fw, parser->file_name, parser->dev); + if (rc || !parser->fw) { + DSI_ERR("couldn't read firmware\n"); + goto end; + } + + *buf = parser->fw->data; + *size = parser->fw->size; + + DSI_DEBUG("file %s: size %zd\n", + parser->file_name, parser->fw->size); +end: + return rc; +} + +static void dsi_parser_free_mem(struct device *dev, + struct dsi_parser_node *node) +{ + int i = 0; + + if (!node) + return; + + DSI_DEBUG("node=%s, prop_count=%d\n", node->name, node->prop_count); + + for (i = 0; i < node->prop_count; i++) { + struct dsi_parser_prop *prop = &node->prop[i]; + + if (!prop) + continue; + + DSI_DEBUG("deleting prop=%s\n", prop->name); + + if (prop->items) + devm_kfree(dev, prop->items); + + if (prop->raw) + devm_kfree(dev, prop->raw); + + if ((prop->type == DSI_PROP_TYPE_INT_SET_ARRAY || + prop->type == DSI_PROP_TYPE_INT_SET || + prop->type == DSI_PROP_TYPE_INT_ARRAY) && prop->value) + devm_kfree(dev, prop->value); + } + + if (node->prop) + devm_kfree(dev, node->prop); + + for (i = 0; i < node->children_count; i++) + dsi_parser_free_mem(dev, node->child[i]); + + devm_kfree(dev, node); +} + +static ssize_t dsi_parser_write_init(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dsi_parser *parser = file->private_data; + const u8 *data = NULL; + u32 size = 0; + char buf[SZ_32]; + size_t len = 0; + + if (!parser) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_32 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + if (sscanf(buf, "%31s", parser->file_name) != 1) { + DSI_ERR("failed to get val\n"); + goto end; + } + + if (dsi_parser_read_file(parser, &data, &size)) { + DSI_ERR("failed to read file\n"); + goto end; + } + + dsi_parser_free_mem(parser->dev, parser->head_node); + + if (parser->buf) { + devm_kfree(parser->dev, parser->buf); + parser->buf = NULL; + } + + parser->head_node = dsi_parser_get_head_node(parser, data, size); + if (!parser->head_node) { + DSI_ERR("failed to parse data\n"); + goto end; + } +end: + return len; +} + +static ssize_t dsi_parser_read_node(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + char *buf = NULL; + int i, j, len = 0, max_size = SZ_4K; + struct dsi_parser *parser = file->private_data; + struct dsi_parser_node *node; + struct dsi_parser_prop *prop; + + if (!parser) + return -ENODEV; + + if (*ppos) + return len; + + buf = kzalloc(SZ_4K, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + node = parser->current_node; + if (!node) { + len = -EINVAL; + goto error; + } + + prop = node->prop; + + len += scnprintf(buf + len, max_size - len, "node name=%s\n", + node->name); + if (len == max_size) + goto buffer_overflow; + + len += scnprintf(buf + len, max_size - len, "children count=%d\n", + node->children_count); + if (len == max_size) + goto buffer_overflow; + + for (i = 0; i < node->children_count; i++) { + len += scnprintf(buf + len, max_size - len, "child[%d]=%s\n", + i, node->child[i]->name); + if (len == max_size) + goto buffer_overflow; + } + + for (i = 0; i < node->prop_count; i++) { + if (!prop[i].name) + continue; + + len += scnprintf(buf + len, max_size - len, + "property=%s\n", prop[i].name); + if (len == max_size) + goto buffer_overflow; + + if (prop[i].value) { + if (prop[i].type == DSI_PROP_TYPE_STR) { + len += scnprintf(buf + len, max_size - len, + "value=%s\n", prop[i].value); + if (len == max_size) + goto buffer_overflow; + } else { + for (j = 0; j < prop[i].len; j++) { + len += scnprintf(buf + len, + max_size - len, + "%x", prop[i].value[j]); + if (len == max_size) + goto buffer_overflow; + } + + len += scnprintf(buf + len, max_size - len, + "\n"); + if (len == max_size) + goto buffer_overflow; + + } + } + + if (prop[i].len) { + len += scnprintf(buf + len, max_size - len, "items:\n"); + if (len == max_size) + goto buffer_overflow; + } + + for (j = 0; j < prop[i].len; j++) { + char delim; + + if (j && !(j % 10)) + delim = '\n'; + else + delim = ' '; + + len += scnprintf(buf + len, max_size - len, "%s%c", + prop[i].items[j], delim); + if (len == max_size) + goto buffer_overflow; + } + + len += scnprintf(buf + len, max_size - len, "\n\n"); + if (len == max_size) + goto buffer_overflow; + } +buffer_overflow: + if (simple_read_from_buffer(user_buff, count, ppos, buf, len)) { + len = -EFAULT; + goto error; + } +error: + kfree(buf); + + return len; +} + +static ssize_t dsi_parser_write_node(struct file *file, + const char __user *user_buff, size_t count, loff_t *ppos) +{ + struct dsi_parser *parser = file->private_data; + char buf[SZ_512]; + size_t len = 0; + + if (!parser) + return -ENODEV; + + if (*ppos) + return 0; + + /* Leave room for termination char */ + len = min_t(size_t, count, SZ_512 - 1); + if (copy_from_user(buf, user_buff, len)) + goto end; + + buf[len] = '\0'; + + strreplace(buf, '\n', ' '); + + if (!strcmp(strim(buf), "head_node")) + parser->current_node = parser->head_node; + else + parser->current_node = dsi_parser_get_node_by_name( + parser->head_node, strim(buf)); +end: + return len; +} + +static const struct file_operations dsi_parser_init_fops = { + .open = simple_open, + .write = dsi_parser_write_init, +}; + +static const struct file_operations dsi_parser_node_fops = { + .open = simple_open, + .read = dsi_parser_read_node, + .write = dsi_parser_write_node, +}; + +int dsi_parser_dbg_init(void *parser, struct dentry *parent_dir) +{ + int rc = 0; + struct dentry *dir, *file; + + if (!parser || !parent_dir) { + DSI_ERR("invalid input\n"); + goto end; + } + + dir = debugfs_create_dir("parser", parent_dir); + if (IS_ERR_OR_NULL(dir)) { + rc = PTR_ERR(dir); + + DSI_ERR("failed to create parser debugfs\n"); + goto end; + } + + file = debugfs_create_file("init", 0644, dir, + parser, &dsi_parser_init_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + + DSI_ERR("failed to create init debugfs\n"); + goto dbg; + } + + file = debugfs_create_file("node", 0644, dir, + parser, &dsi_parser_node_fops); + if (IS_ERR_OR_NULL(file)) { + rc = PTR_ERR(file); + + DSI_ERR("failed to create init debugfs\n"); + goto dbg; + } + + DSI_DEBUG("success\n"); + return 0; +dbg: + debugfs_remove_recursive(dir); +end: + return rc; +} + +void *dsi_parser_get(struct device *dev) +{ + int rc = 0; + struct dsi_parser *parser = NULL; + + if (!dev) { + DSI_ERR("invalid data\n"); + rc = -EINVAL; + goto end; + } + + parser = devm_kzalloc(dev, sizeof(*parser), GFP_KERNEL); + if (!parser) { + rc = -ENOMEM; + goto end; + } + + parser->dev = dev; + + strlcpy(parser->file_name, "dsi_prop", sizeof(parser->file_name)); + + return parser; +end: + return ERR_PTR(rc); +} + +void dsi_parser_put(void *data) +{ + struct dsi_parser *parser = data; + + if (!parser) + return; + + dsi_parser_free_mem(parser->dev, parser->head_node); + + devm_kfree(parser->dev, parser->buf); + devm_kfree(parser->dev, parser); +} + diff --git a/techpack/display/msm/dsi/dsi_parser.h b/techpack/display/msm/dsi/dsi_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..949de1b4b02efb26f21beb672f9eadf78407e784 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_parser.h @@ -0,0 +1,235 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_PARSER_H_ +#define _DSI_PARSER_H_ + +#include <linux/of.h> +#include <linux/of_gpio.h> + +#ifdef CONFIG_DSI_PARSER +void *dsi_parser_get(struct device *dev); +void dsi_parser_put(void *data); +int dsi_parser_dbg_init(void *parser, struct dentry *dir); +void *dsi_parser_get_head_node(void *parser, + const u8 *data, u32 size); + +const void *dsi_parser_get_property(const struct device_node *np, + const char *name, int *lenp); +bool dsi_parser_read_bool(const struct device_node *np, + const char *propname); +int dsi_parser_read_u64(const struct device_node *np, const char *propname, + u64 *out_value); +int dsi_parser_read_u32(const struct device_node *np, + const char *propname, u32 *out_value); +int dsi_parser_read_u32_array(const struct device_node *np, + const char *propname, + u32 *out_values, size_t sz); +int dsi_parser_read_string(const struct device_node *np, + const char *propname, const char **out_string); +struct device_node *dsi_parser_get_child_by_name(const struct device_node *node, + const char *name); +int dsi_parser_get_child_count(const struct device_node *np); +struct property *dsi_parser_find_property(const struct device_node *np, + const char *name, int *lenp); +struct device_node *dsi_parser_get_next_child(const struct device_node *np, + struct device_node *prev); +int dsi_parser_count_u32_elems(const struct device_node *np, + const char *propname); +int dsi_parser_count_strings(const struct device_node *np, + const char *propname); +int dsi_parser_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output); +int dsi_parser_get_named_gpio(struct device_node *np, + const char *propname, int index); +#else /* CONFIG_DSI_PARSER */ +static inline void *dsi_parser_get(struct device *dev) +{ + return NULL; +} + +static inline void dsi_parser_put(void *data) +{ +} + +static inline int dsi_parser_dbg_init(void *parser, struct dentry *dir) +{ + return -ENODEV; +} + +static inline void *dsi_parser_get_head_node(void *parser, + const u8 *data, u32 size) +{ + return NULL; +} + +static inline const void *dsi_parser_get_property(const struct device_node *np, + const char *name, int *lenp) +{ + return NULL; +} + +static inline bool dsi_parser_read_bool(const struct device_node *np, + const char *propname) +{ + return false; +} + +static inline int dsi_parser_read_u64(const struct device_node *np, + const char *propname, u64 *out_value) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_u32(const struct device_node *np, + const char *propname, u32 *out_value) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_u32_array(const struct device_node *np, + const char *propname, u32 *out_values, size_t sz) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_string(const struct device_node *np, + const char *propname, const char **out_string) +{ + return -ENODEV; +} + +static inline struct device_node *dsi_parser_get_child_by_name( + const struct device_node *node, + const char *name) +{ + return NULL; +} + +static inline int dsi_parser_get_child_count(const struct device_node *np) +{ + return -ENODEV; +} + +static inline struct property *dsi_parser_find_property( + const struct device_node *np, + const char *name, int *lenp) +{ + return NULL; +} + +static inline struct device_node *dsi_parser_get_next_child( + const struct device_node *np, + struct device_node *prev) +{ + return NULL; +} + +static inline int dsi_parser_count_u32_elems(const struct device_node *np, + const char *propname) +{ + return -ENODEV; +} + +static inline int dsi_parser_count_strings(const struct device_node *np, + const char *propname) +{ + return -ENODEV; +} + +static inline int dsi_parser_read_string_index(const struct device_node *np, + const char *propname, + int index, const char **output) +{ + return -ENODEV; +} + +static inline int dsi_parser_get_named_gpio(struct device_node *np, + const char *propname, int index) +{ + return -ENODEV; +} + +#endif /* CONFIG_DSI_PARSER */ + +#define dsi_for_each_child_node(parent, child) \ + for (child = utils->get_next_child(parent, NULL); \ + child != NULL; \ + child = utils->get_next_child(parent, child)) + +struct dsi_parser_utils { + void *data; + struct device_node *node; + + const void *(*get_property)(const struct device_node *np, + const char *name, int *lenp); + int (*read_u64)(const struct device_node *np, + const char *propname, u64 *out_value); + int (*read_u32)(const struct device_node *np, + const char *propname, u32 *out_value); + bool (*read_bool)(const struct device_node *np, + const char *propname); + int (*read_u32_array)(const struct device_node *np, + const char *propname, u32 *out_values, size_t sz); + int (*read_string)(const struct device_node *np, const char *propname, + const char **out_string); + struct device_node *(*get_child_by_name)( + const struct device_node *node, + const char *name); + int (*get_child_count)(const struct device_node *np); + struct property *(*find_property)(const struct device_node *np, + const char *name, int *lenp); + struct device_node *(*get_next_child)(const struct device_node *np, + struct device_node *prev); + int (*count_u32_elems)(const struct device_node *np, + const char *propname); + int (*get_named_gpio)(struct device_node *np, + const char *propname, int index); + int (*get_available_child_count)(const struct device_node *np); +}; + +static inline struct dsi_parser_utils *dsi_parser_get_of_utils(void) +{ + static struct dsi_parser_utils of_utils = { + .get_property = of_get_property, + .read_bool = of_property_read_bool, + .read_u64 = of_property_read_u64, + .read_u32 = of_property_read_u32, + .read_u32_array = of_property_read_u32_array, + .read_string = of_property_read_string, + .get_child_by_name = of_get_child_by_name, + .get_child_count = of_get_child_count, + .get_available_child_count = of_get_available_child_count, + .find_property = of_find_property, + .get_next_child = of_get_next_child, + .count_u32_elems = of_property_count_u32_elems, + .get_named_gpio = of_get_named_gpio, + }; + + return &of_utils; +} + +static inline struct dsi_parser_utils *dsi_parser_get_parser_utils(void) +{ + static struct dsi_parser_utils parser_utils = { + .get_property = dsi_parser_get_property, + .read_bool = dsi_parser_read_bool, + .read_u64 = dsi_parser_read_u64, + .read_u32 = dsi_parser_read_u32, + .read_u32_array = dsi_parser_read_u32_array, + .read_string = dsi_parser_read_string, + .get_child_by_name = dsi_parser_get_child_by_name, + .get_child_count = dsi_parser_get_child_count, + .get_available_child_count = dsi_parser_get_child_count, + .find_property = dsi_parser_find_property, + .get_next_child = dsi_parser_get_next_child, + .count_u32_elems = dsi_parser_count_u32_elems, + .get_named_gpio = dsi_parser_get_named_gpio, + }; + + return &parser_utils; +} +#endif diff --git a/techpack/display/msm/dsi/dsi_phy.c b/techpack/display/msm/dsi/dsi_phy.c new file mode 100644 index 0000000000000000000000000000000000000000..4115138bb32a0a619d10d6c5a3c37557f26249cf --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy.c @@ -0,0 +1,1281 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/of_device.h> +#include <linux/err.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#include <linux/msm-bus.h> +#include <linux/list.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "dsi_phy.h" +#include "dsi_phy_hw.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "dsi_catalog.h" + +#include "sde_dbg.h" + +#define DSI_PHY_DEFAULT_LABEL "MDSS PHY CTRL" + +#define BITS_PER_BYTE 8 + +struct dsi_phy_list_item { + struct msm_dsi_phy *phy; + struct list_head list; +}; + +static LIST_HEAD(dsi_phy_list); +static DEFINE_MUTEX(dsi_phy_list_lock); + +static const struct dsi_ver_spec_info dsi_phy_v0_0_hpm = { + .version = DSI_PHY_VERSION_0_0_HPM, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 1, + .timing_cfg_count = 8, +}; +static const struct dsi_ver_spec_info dsi_phy_v0_0_lpm = { + .version = DSI_PHY_VERSION_0_0_LPM, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 1, + .timing_cfg_count = 8, +}; +static const struct dsi_ver_spec_info dsi_phy_v1_0 = { + .version = DSI_PHY_VERSION_1_0, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 1, + .timing_cfg_count = 8, +}; +static const struct dsi_ver_spec_info dsi_phy_v2_0 = { + .version = DSI_PHY_VERSION_2_0, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 1, + .timing_cfg_count = 8, +}; +static const struct dsi_ver_spec_info dsi_phy_v3_0 = { + .version = DSI_PHY_VERSION_3_0, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 0, + .timing_cfg_count = 12, +}; + +static const struct dsi_ver_spec_info dsi_phy_v4_0 = { + .version = DSI_PHY_VERSION_4_0, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 0, + .timing_cfg_count = 14, +}; + +static const struct dsi_ver_spec_info dsi_phy_v4_1 = { + .version = DSI_PHY_VERSION_4_1, + .lane_cfg_count = 4, + .strength_cfg_count = 2, + .regulator_cfg_count = 0, + .timing_cfg_count = 14, +}; + +static const struct of_device_id msm_dsi_phy_of_match[] = { + { .compatible = "qcom,dsi-phy-v0.0-hpm", + .data = &dsi_phy_v0_0_hpm,}, + { .compatible = "qcom,dsi-phy-v0.0-lpm", + .data = &dsi_phy_v0_0_lpm,}, + { .compatible = "qcom,dsi-phy-v1.0", + .data = &dsi_phy_v1_0,}, + { .compatible = "qcom,dsi-phy-v2.0", + .data = &dsi_phy_v2_0,}, + { .compatible = "qcom,dsi-phy-v3.0", + .data = &dsi_phy_v3_0,}, + { .compatible = "qcom,dsi-phy-v4.0", + .data = &dsi_phy_v4_0,}, + { .compatible = "qcom,dsi-phy-v4.1", + .data = &dsi_phy_v4_1,}, + {} +}; + +int dsi_phy_get_version(struct msm_dsi_phy *phy) +{ + return phy->ver_info->version; +} + +static int dsi_phy_regmap_init(struct platform_device *pdev, + struct msm_dsi_phy *phy) +{ + int rc = 0; + void __iomem *ptr; + + ptr = msm_ioremap(pdev, "dsi_phy", phy->name); + if (IS_ERR(ptr)) { + rc = PTR_ERR(ptr); + return rc; + } + + phy->hw.base = ptr; + + ptr = msm_ioremap(pdev, "dyn_refresh_base", phy->name); + phy->hw.dyn_pll_base = ptr; + + DSI_PHY_DBG(phy, "map dsi_phy registers to %pK\n", phy->hw.base); + + switch (phy->ver_info->version) { + case DSI_PHY_VERSION_2_0: + ptr = msm_ioremap(pdev, "phy_clamp_base", phy->name); + if (IS_ERR(ptr)) + phy->hw.phy_clamp_base = NULL; + else + phy->hw.phy_clamp_base = ptr; + break; + default: + break; + } + + return rc; +} + +static int dsi_phy_regmap_deinit(struct msm_dsi_phy *phy) +{ + DSI_PHY_DBG(phy, "unmap registers\n"); + return 0; +} + +static int dsi_phy_supplies_init(struct platform_device *pdev, + struct msm_dsi_phy *phy) +{ + int rc = 0; + int i = 0; + struct dsi_regulator_info *regs; + struct regulator *vreg = NULL; + + regs = &phy->pwr_info.digital; + regs->vregs = devm_kzalloc(&pdev->dev, sizeof(struct dsi_vreg), + GFP_KERNEL); + if (!regs->vregs) + goto error; + + regs->count = 1; + snprintf(regs->vregs->vreg_name, + ARRAY_SIZE(regs->vregs[i].vreg_name), + "%s", "gdsc"); + + rc = dsi_pwr_get_dt_vreg_data(&pdev->dev, + &phy->pwr_info.phy_pwr, + "qcom,phy-supply-entries"); + if (rc) { + DSI_PHY_ERR(phy, "failed to get host power supplies, rc = %d\n", + rc); + goto error_digital; + } + + regs = &phy->pwr_info.digital; + for (i = 0; i < regs->count; i++) { + vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name); + rc = PTR_RET(vreg); + if (rc) { + DSI_PHY_ERR(phy, "failed to get %s regulator\n", + regs->vregs[i].vreg_name); + goto error_host_pwr; + } + regs->vregs[i].vreg = vreg; + } + + regs = &phy->pwr_info.phy_pwr; + for (i = 0; i < regs->count; i++) { + vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name); + rc = PTR_RET(vreg); + if (rc) { + DSI_PHY_ERR(phy, "failed to get %s regulator\n", + regs->vregs[i].vreg_name); + for (--i; i >= 0; i--) + devm_regulator_put(regs->vregs[i].vreg); + goto error_digital_put; + } + regs->vregs[i].vreg = vreg; + } + + return rc; + +error_digital_put: + regs = &phy->pwr_info.digital; + for (i = 0; i < regs->count; i++) + devm_regulator_put(regs->vregs[i].vreg); +error_host_pwr: + devm_kfree(&pdev->dev, phy->pwr_info.phy_pwr.vregs); + phy->pwr_info.phy_pwr.vregs = NULL; + phy->pwr_info.phy_pwr.count = 0; +error_digital: + devm_kfree(&pdev->dev, phy->pwr_info.digital.vregs); + phy->pwr_info.digital.vregs = NULL; + phy->pwr_info.digital.count = 0; +error: + return rc; +} + +static int dsi_phy_supplies_deinit(struct msm_dsi_phy *phy) +{ + int i = 0; + int rc = 0; + struct dsi_regulator_info *regs; + + regs = &phy->pwr_info.digital; + for (i = 0; i < regs->count; i++) { + if (!regs->vregs[i].vreg) + DSI_PHY_ERR(phy, "vreg is NULL, should not reach here\n"); + else + devm_regulator_put(regs->vregs[i].vreg); + } + + regs = &phy->pwr_info.phy_pwr; + for (i = 0; i < regs->count; i++) { + if (!regs->vregs[i].vreg) + DSI_PHY_ERR(phy, "vreg is NULL, should not reach here\n"); + else + devm_regulator_put(regs->vregs[i].vreg); + } + + if (phy->pwr_info.phy_pwr.vregs) { + devm_kfree(&phy->pdev->dev, phy->pwr_info.phy_pwr.vregs); + phy->pwr_info.phy_pwr.vregs = NULL; + phy->pwr_info.phy_pwr.count = 0; + } + if (phy->pwr_info.digital.vregs) { + devm_kfree(&phy->pdev->dev, phy->pwr_info.digital.vregs); + phy->pwr_info.digital.vregs = NULL; + phy->pwr_info.digital.count = 0; + } + + return rc; +} + +static int dsi_phy_parse_dt_per_lane_cfgs(struct platform_device *pdev, + struct dsi_phy_per_lane_cfgs *cfg, + char *property) +{ + int rc = 0, i = 0, j = 0; + const u8 *data; + u32 len = 0; + + data = of_get_property(pdev->dev.of_node, property, &len); + if (!data) { + DSI_ERR("Unable to read Phy %s settings\n", property); + return -EINVAL; + } + + if (len != DSI_LANE_MAX * cfg->count_per_lane) { + DSI_ERR("incorrect phy %s settings, exp=%d, act=%d\n", + property, (DSI_LANE_MAX * cfg->count_per_lane), len); + return -EINVAL; + } + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + for (j = 0; j < cfg->count_per_lane; j++) { + cfg->lane[i][j] = *data; + data++; + } + } + + return rc; +} + +static int dsi_phy_settings_init(struct platform_device *pdev, + struct msm_dsi_phy *phy) +{ + int rc = 0; + struct dsi_phy_per_lane_cfgs *lane = &phy->cfg.lanecfg; + struct dsi_phy_per_lane_cfgs *strength = &phy->cfg.strength; + struct dsi_phy_per_lane_cfgs *timing = &phy->cfg.timing; + struct dsi_phy_per_lane_cfgs *regs = &phy->cfg.regulators; + + lane->count_per_lane = phy->ver_info->lane_cfg_count; + rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, lane, + "qcom,platform-lane-config"); + if (rc) { + DSI_PHY_ERR(phy, "failed to parse lane cfgs, rc=%d\n", rc); + goto err; + } + + strength->count_per_lane = phy->ver_info->strength_cfg_count; + rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, strength, + "qcom,platform-strength-ctrl"); + if (rc) { + DSI_PHY_ERR(phy, "failed to parse lane cfgs, rc=%d\n", rc); + goto err; + } + + regs->count_per_lane = phy->ver_info->regulator_cfg_count; + if (regs->count_per_lane > 0) { + rc = dsi_phy_parse_dt_per_lane_cfgs(pdev, regs, + "qcom,platform-regulator-settings"); + if (rc) { + DSI_PHY_ERR(phy, "failed to parse lane cfgs, rc=%d\n", + rc); + goto err; + } + } + + /* Actual timing values are dependent on panel */ + timing->count_per_lane = phy->ver_info->timing_cfg_count; + + phy->allow_phy_power_off = of_property_read_bool(pdev->dev.of_node, + "qcom,panel-allow-phy-poweroff"); + + of_property_read_u32(pdev->dev.of_node, + "qcom,dsi-phy-regulator-min-datarate-bps", + &phy->regulator_min_datarate_bps); + + return 0; +err: + lane->count_per_lane = 0; + strength->count_per_lane = 0; + regs->count_per_lane = 0; + timing->count_per_lane = 0; + return rc; +} + +static int dsi_phy_settings_deinit(struct msm_dsi_phy *phy) +{ + memset(&phy->cfg.lanecfg, 0x0, sizeof(phy->cfg.lanecfg)); + memset(&phy->cfg.strength, 0x0, sizeof(phy->cfg.strength)); + memset(&phy->cfg.timing, 0x0, sizeof(phy->cfg.timing)); + memset(&phy->cfg.regulators, 0x0, sizeof(phy->cfg.regulators)); + return 0; +} + +static int dsi_phy_driver_probe(struct platform_device *pdev) +{ + struct msm_dsi_phy *dsi_phy; + struct dsi_phy_list_item *item; + const struct of_device_id *id; + const struct dsi_ver_spec_info *ver_info; + int rc = 0; + u32 index = 0; + + if (!pdev || !pdev->dev.of_node) { + DSI_ERR("pdev not found\n"); + return -ENODEV; + } + + id = of_match_node(msm_dsi_phy_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + + ver_info = id->data; + + item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL); + if (!item) + return -ENOMEM; + + + dsi_phy = devm_kzalloc(&pdev->dev, sizeof(*dsi_phy), GFP_KERNEL); + if (!dsi_phy) { + devm_kfree(&pdev->dev, item); + return -ENOMEM; + } + + rc = of_property_read_u32(pdev->dev.of_node, "cell-index", &index); + if (rc) { + DSI_PHY_DBG(dsi_phy, "cell index not set, default to 0\n"); + index = 0; + } + + dsi_phy->index = index; + + dsi_phy->name = of_get_property(pdev->dev.of_node, "label", NULL); + if (!dsi_phy->name) + dsi_phy->name = DSI_PHY_DEFAULT_LABEL; + + DSI_PHY_DBG(dsi_phy, "Probing device\n"); + + dsi_phy->ver_info = ver_info; + + rc = dsi_phy_regmap_init(pdev, dsi_phy); + if (rc) { + DSI_PHY_ERR(dsi_phy, "Failed to parse register information, rc=%d\n", + rc); + goto fail; + } + + rc = dsi_phy_supplies_init(pdev, dsi_phy); + if (rc) { + DSI_PHY_ERR(dsi_phy, "failed to parse voltage supplies, rc = %d\n", + rc); + goto fail_regmap; + } + + rc = dsi_catalog_phy_setup(&dsi_phy->hw, ver_info->version, + dsi_phy->index); + if (rc) { + DSI_PHY_ERR(dsi_phy, "Catalog does not support version (%d)\n", + ver_info->version); + goto fail_supplies; + } + + rc = dsi_phy_settings_init(pdev, dsi_phy); + if (rc) { + DSI_PHY_ERR(dsi_phy, "Failed to parse phy setting, rc=%d\n", + rc); + goto fail_supplies; + } + + item->phy = dsi_phy; + + mutex_lock(&dsi_phy_list_lock); + list_add(&item->list, &dsi_phy_list); + mutex_unlock(&dsi_phy_list_lock); + + mutex_init(&dsi_phy->phy_lock); + /** TODO: initialize debugfs */ + dsi_phy->pdev = pdev; + platform_set_drvdata(pdev, dsi_phy); + DSI_PHY_INFO(dsi_phy, "Probe successful\n"); + return 0; + +fail_supplies: + (void)dsi_phy_supplies_deinit(dsi_phy); +fail_regmap: + (void)dsi_phy_regmap_deinit(dsi_phy); +fail: + devm_kfree(&pdev->dev, dsi_phy); + devm_kfree(&pdev->dev, item); + return rc; +} + +static int dsi_phy_driver_remove(struct platform_device *pdev) +{ + int rc = 0; + struct msm_dsi_phy *phy = platform_get_drvdata(pdev); + struct list_head *pos, *tmp; + + if (!pdev || !phy) { + DSI_PHY_ERR(phy, "Invalid device\n"); + return -EINVAL; + } + + mutex_lock(&dsi_phy_list_lock); + list_for_each_safe(pos, tmp, &dsi_phy_list) { + struct dsi_phy_list_item *n; + + n = list_entry(pos, struct dsi_phy_list_item, list); + if (n->phy == phy) { + list_del(&n->list); + devm_kfree(&pdev->dev, n); + break; + } + } + mutex_unlock(&dsi_phy_list_lock); + + mutex_lock(&phy->phy_lock); + rc = dsi_phy_settings_deinit(phy); + if (rc) + DSI_PHY_ERR(phy, "failed to deinitialize phy settings, rc=%d\n", + rc); + + rc = dsi_phy_supplies_deinit(phy); + if (rc) + DSI_PHY_ERR(phy, "failed to deinitialize voltage supplies, rc=%d\n", + rc); + + rc = dsi_phy_regmap_deinit(phy); + if (rc) + DSI_PHY_ERR(phy, "failed to deinitialize regmap, rc=%d\n", rc); + mutex_unlock(&phy->phy_lock); + + mutex_destroy(&phy->phy_lock); + devm_kfree(&pdev->dev, phy); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver dsi_phy_platform_driver = { + .probe = dsi_phy_driver_probe, + .remove = dsi_phy_driver_remove, + .driver = { + .name = "dsi_phy", + .of_match_table = msm_dsi_phy_of_match, + }, +}; + +static void dsi_phy_enable_hw(struct msm_dsi_phy *phy) +{ + if (phy->hw.ops.regulator_enable) + phy->hw.ops.regulator_enable(&phy->hw, &phy->cfg.regulators); + + if (phy->hw.ops.enable) + phy->hw.ops.enable(&phy->hw, &phy->cfg); +} + +static void dsi_phy_disable_hw(struct msm_dsi_phy *phy) +{ + if (phy->hw.ops.disable) + phy->hw.ops.disable(&phy->hw, &phy->cfg); + + if (phy->hw.ops.regulator_disable) + phy->hw.ops.regulator_disable(&phy->hw); +} + +/** + * dsi_phy_get() - get a dsi phy handle from device node + * @of_node: device node for dsi phy controller + * + * Gets the DSI PHY handle for the corresponding of_node. The ref count is + * incremented to one all subsequents get will fail until the original client + * calls a put. + * + * Return: DSI PHY handle or an error code. + */ +struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node) +{ + struct list_head *pos, *tmp; + struct msm_dsi_phy *phy = NULL; + + mutex_lock(&dsi_phy_list_lock); + list_for_each_safe(pos, tmp, &dsi_phy_list) { + struct dsi_phy_list_item *n; + + n = list_entry(pos, struct dsi_phy_list_item, list); + if (n->phy->pdev->dev.of_node == of_node) { + phy = n->phy; + break; + } + } + mutex_unlock(&dsi_phy_list_lock); + + if (!phy) { + DSI_PHY_ERR(phy, "Device with of node not found\n"); + phy = ERR_PTR(-EPROBE_DEFER); + return phy; + } + + mutex_lock(&phy->phy_lock); + if (phy->refcount > 0) { + DSI_PHY_ERR(phy, "Device under use\n"); + phy = ERR_PTR(-EINVAL); + } else { + phy->refcount++; + } + mutex_unlock(&phy->phy_lock); + return phy; +} + +/** + * dsi_phy_put() - release dsi phy handle + * @dsi_phy: DSI PHY handle. + * + * Release the DSI PHY hardware. Driver will clean up all resources and puts + * back the DSI PHY into reset state. + */ +void dsi_phy_put(struct msm_dsi_phy *dsi_phy) +{ + mutex_lock(&dsi_phy->phy_lock); + + if (dsi_phy->refcount == 0) + DSI_PHY_ERR(dsi_phy, "Unbalanced %s call\n", __func__); + else + dsi_phy->refcount--; + + mutex_unlock(&dsi_phy->phy_lock); +} + +/** + * dsi_phy_drv_init() - initialize dsi phy driver + * @dsi_phy: DSI PHY handle. + * + * Initializes DSI PHY driver. Should be called after dsi_phy_get(). + * + * Return: error code. + */ +int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy) +{ + char dbg_name[DSI_DEBUG_NAME_LEN]; + + snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_phy", dsi_phy->index); + sde_dbg_reg_register_base(dbg_name, dsi_phy->hw.base, + msm_iomap_size(dsi_phy->pdev, "dsi_phy")); + return 0; +} + +/** + * dsi_phy_drv_deinit() - de-initialize dsi phy driver + * @dsi_phy: DSI PHY handle. + * + * Release all resources acquired by dsi_phy_drv_init(). + * + * Return: error code. + */ +int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy) +{ + return 0; +} + +int dsi_phy_clk_cb_register(struct msm_dsi_phy *dsi_phy, + struct clk_ctrl_cb *clk_cb) +{ + if (!dsi_phy || !clk_cb) { + DSI_PHY_ERR(dsi_phy, "Invalid params\n"); + return -EINVAL; + } + + dsi_phy->clk_cb.priv = clk_cb->priv; + dsi_phy->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb; + return 0; +} + +/** + * dsi_phy_validate_mode() - validate a display mode + * @dsi_phy: DSI PHY handle. + * @mode: Mode information. + * + * Validation will fail if the mode cannot be supported by the PHY driver or + * hardware. + * + * Return: error code. + */ +int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy, + struct dsi_mode_info *mode) +{ + int rc = 0; + + if (!dsi_phy || !mode) { + DSI_PHY_ERR(dsi_phy, "Invalid params\n"); + return -EINVAL; + } + + DSI_PHY_DBG(dsi_phy, "Skipping validation\n"); + + return rc; +} + +/** + * dsi_phy_set_power_state() - enable/disable dsi phy power supplies + * @dsi_phy: DSI PHY handle. + * @enable: Boolean flag to enable/disable. + * + * Return: error code. + */ +int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable) +{ + int rc = 0; + + if (!dsi_phy) { + DSI_PHY_ERR(dsi_phy, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&dsi_phy->phy_lock); + + if (enable == dsi_phy->power_state) { + DSI_PHY_ERR(dsi_phy, "No state change\n"); + goto error; + } + + if (enable) { + rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, true); + if (rc) { + DSI_PHY_ERR(dsi_phy, "failed to enable digital regulator\n"); + goto error; + } + + if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF && + dsi_phy->regulator_required) { + rc = dsi_pwr_enable_regulator( + &dsi_phy->pwr_info.phy_pwr, true); + if (rc) { + DSI_PHY_ERR(dsi_phy, "failed to enable phy power\n"); + (void)dsi_pwr_enable_regulator( + &dsi_phy->pwr_info.digital, false); + goto error; + } + } + } else { + if (dsi_phy->dsi_phy_state == DSI_PHY_ENGINE_OFF && + dsi_phy->regulator_required) { + rc = dsi_pwr_enable_regulator( + &dsi_phy->pwr_info.phy_pwr, false); + if (rc) { + DSI_PHY_ERR(dsi_phy, "failed to enable digital regulator\n"); + goto error; + } + } + + rc = dsi_pwr_enable_regulator(&dsi_phy->pwr_info.digital, + false); + if (rc) { + DSI_PHY_ERR(dsi_phy, "failed to enable phy power\n"); + goto error; + } + } + + dsi_phy->power_state = enable; +error: + mutex_unlock(&dsi_phy->phy_lock); + return rc; +} + +static int dsi_phy_enable_ulps(struct msm_dsi_phy *phy, + struct dsi_host_config *config, bool clamp_enabled) +{ + int rc = 0; + u32 lanes = 0; + u32 ulps_lanes; + + lanes = config->common_config.data_lanes; + lanes |= DSI_CLOCK_LANE; + + /* + * If DSI clamps are enabled, it means that the DSI lanes are + * already in idle state. Checking for lanes to be in idle state + * should be skipped during ULPS entry programming while coming + * out of idle screen. + */ + if (!clamp_enabled) { + rc = phy->hw.ops.ulps_ops.wait_for_lane_idle(&phy->hw, lanes); + if (rc) { + DSI_PHY_ERR(phy, "lanes not entering idle, skip ULPS\n"); + return rc; + } + } + + phy->hw.ops.ulps_ops.ulps_request(&phy->hw, &phy->cfg, lanes); + + ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw); + + if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) { + DSI_PHY_ERR(phy, "Failed to enter ULPS, request=0x%x, actual=0x%x\n", + lanes, ulps_lanes); + rc = -EIO; + } + + return rc; +} + +static int dsi_phy_disable_ulps(struct msm_dsi_phy *phy, + struct dsi_host_config *config) +{ + u32 ulps_lanes, lanes = 0; + + lanes = config->common_config.data_lanes; + lanes |= DSI_CLOCK_LANE; + + ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw); + + if (!phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) { + DSI_PHY_ERR(phy, "Mismatch in ULPS: lanes:%d, ulps_lanes:%d\n", + lanes, ulps_lanes); + return -EIO; + } + + phy->hw.ops.ulps_ops.ulps_exit(&phy->hw, &phy->cfg, lanes); + + ulps_lanes = phy->hw.ops.ulps_ops.get_lanes_in_ulps(&phy->hw); + + if (phy->hw.ops.ulps_ops.is_lanes_in_ulps(lanes, ulps_lanes)) { + DSI_PHY_ERR(phy, "Lanes (0x%x) stuck in ULPS\n", ulps_lanes); + return -EIO; + } + + return 0; +} + +void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy) +{ + if (!phy) + return; + + if (!phy->hw.ops.toggle_resync_fifo) + return; + + phy->hw.ops.toggle_resync_fifo(&phy->hw); +} + + +void dsi_phy_reset_clk_en_sel(struct msm_dsi_phy *phy) +{ + if (!phy) + return; + + if (!phy->hw.ops.reset_clk_en_sel) + return; + + phy->hw.ops.reset_clk_en_sel(&phy->hw); +} + +int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config, + bool enable, bool clamp_enabled) +{ + int rc = 0; + + if (!phy) { + DSI_PHY_ERR(phy, "Invalid params\n"); + return DSI_PHY_ULPS_ERROR; + } + + if (!phy->hw.ops.ulps_ops.ulps_request || + !phy->hw.ops.ulps_ops.ulps_exit || + !phy->hw.ops.ulps_ops.get_lanes_in_ulps || + !phy->hw.ops.ulps_ops.is_lanes_in_ulps || + !phy->hw.ops.ulps_ops.wait_for_lane_idle) { + DSI_PHY_DBG(phy, "DSI PHY ULPS ops not present\n"); + return DSI_PHY_ULPS_NOT_HANDLED; + } + + mutex_lock(&phy->phy_lock); + + if (enable) + rc = dsi_phy_enable_ulps(phy, config, clamp_enabled); + else + rc = dsi_phy_disable_ulps(phy, config); + + if (rc) { + DSI_PHY_ERR(phy, "Ulps state change(%d) failed, rc=%d\n", + enable, rc); + rc = DSI_PHY_ULPS_ERROR; + goto error; + } + DSI_PHY_DBG(phy, "ULPS state = %d\n", enable); + +error: + mutex_unlock(&phy->phy_lock); + return rc; +} + +/** + * dsi_phy_enable() - enable DSI PHY hardware + * @dsi_phy: DSI PHY handle. + * @config: DSI host configuration. + * @pll_source: Source PLL for PHY clock. + * @skip_validation: Validation will not be performed on parameters. + * @is_cont_splash_enabled: check whether continuous splash enabled. + * + * Validates and enables DSI PHY. + * + * Return: error code. + */ +int dsi_phy_enable(struct msm_dsi_phy *phy, + struct dsi_host_config *config, + enum dsi_phy_pll_source pll_source, + bool skip_validation, + bool is_cont_splash_enabled) +{ + int rc = 0; + + if (!phy || !config) { + DSI_PHY_ERR(phy, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&phy->phy_lock); + + if (!skip_validation) + DSI_PHY_DBG(phy, "TODO: perform validation\n"); + + memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode)); + memcpy(&phy->cfg.lane_map, &config->lane_map, sizeof(config->lane_map)); + phy->data_lanes = config->common_config.data_lanes; + phy->dst_format = config->common_config.dst_format; + phy->cfg.pll_source = pll_source; + phy->cfg.bit_clk_rate_hz = config->bit_clk_rate_hz; + + /** + * If PHY timing parameters are not present in panel dtsi file, + * then calculate them in the driver + */ + if (!phy->cfg.is_phy_timing_present) + rc = phy->hw.ops.calculate_timing_params(&phy->hw, + &phy->mode, + &config->common_config, + &phy->cfg.timing, false); + if (rc) { + DSI_PHY_ERR(phy, "failed to set timing, rc=%d\n", rc); + goto error; + } + + if (!is_cont_splash_enabled) { + dsi_phy_enable_hw(phy); + DSI_PHY_DBG(phy, "cont splash not enabled, phy enable required\n"); + } + phy->dsi_phy_state = DSI_PHY_ENGINE_ON; + +error: + mutex_unlock(&phy->phy_lock); + + return rc; +} + +/* update dsi phy timings for dynamic clk switch use case */ +int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy, + struct dsi_host_config *config) +{ + int rc = 0; + + if (!phy || !config) { + DSI_PHY_ERR(phy, "invalid argument\n"); + return -EINVAL; + } + + memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode)); + rc = phy->hw.ops.calculate_timing_params(&phy->hw, &phy->mode, + &config->common_config, + &phy->cfg.timing, true); + if (rc) + DSI_PHY_ERR(phy, "failed to calculate phy timings %d\n", rc); + + return rc; +} + +int dsi_phy_lane_reset(struct msm_dsi_phy *phy) +{ + int ret = 0; + + if (!phy) + return ret; + + mutex_lock(&phy->phy_lock); + if (phy->hw.ops.phy_lane_reset) + ret = phy->hw.ops.phy_lane_reset(&phy->hw); + mutex_unlock(&phy->phy_lock); + + return ret; +} + +/** + * dsi_phy_disable() - disable DSI PHY hardware. + * @phy: DSI PHY handle. + * + * Return: error code. + */ +int dsi_phy_disable(struct msm_dsi_phy *phy) +{ + int rc = 0; + + if (!phy) { + DSI_PHY_ERR(phy, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&phy->phy_lock); + dsi_phy_disable_hw(phy); + phy->dsi_phy_state = DSI_PHY_ENGINE_OFF; + mutex_unlock(&phy->phy_lock); + + return rc; +} + +/** + * dsi_phy_set_clamp_state() - configure clamps for DSI lanes + * @phy: DSI PHY handle. + * @enable: boolean to specify clamp enable/disable. + * + * Return: error code. + */ +int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable) +{ + if (!phy) + return -EINVAL; + + DSI_PHY_DBG(phy, "enable=%d\n", enable); + + if (phy->hw.ops.clamp_ctrl) + phy->hw.ops.clamp_ctrl(&phy->hw, enable); + + return 0; +} + +/** + * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen + * @phy: DSI PHY handle + * @enable: boolean to specify PHY enable/disable. + * + * Return: error code. + */ + +int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable) +{ + if (!phy) { + DSI_PHY_ERR(phy, "Invalid params\n"); + return -EINVAL; + } + + DSI_PHY_DBG(phy, "enable=%d\n", enable); + + mutex_lock(&phy->phy_lock); + if (enable) { + if (phy->hw.ops.phy_idle_on) + phy->hw.ops.phy_idle_on(&phy->hw, &phy->cfg); + + if (phy->hw.ops.regulator_enable) + phy->hw.ops.regulator_enable(&phy->hw, + &phy->cfg.regulators); + + if (phy->hw.ops.enable) + phy->hw.ops.enable(&phy->hw, &phy->cfg); + + phy->dsi_phy_state = DSI_PHY_ENGINE_ON; + } else { + phy->dsi_phy_state = DSI_PHY_ENGINE_OFF; + + if (phy->hw.ops.disable) + phy->hw.ops.disable(&phy->hw, &phy->cfg); + + if (phy->hw.ops.phy_idle_off) + phy->hw.ops.phy_idle_off(&phy->hw); + } + mutex_unlock(&phy->phy_lock); + + return 0; +} + +/** + * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting + * @phy: DSI PHY handle + * @clk_freq: link clock frequency + * + * Return: error code. + */ +int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy, + struct link_clk_freq *clk_freq) +{ + if (!phy || !clk_freq) { + DSI_PHY_ERR(phy, "Invalid params\n"); + return -EINVAL; + } + + phy->regulator_required = clk_freq->byte_clk_rate > + (phy->regulator_min_datarate_bps / BITS_PER_BYTE); + + /* + * DSI PLL needs 0p9 LDO1A for Powering DSI PLL block. + * PLL driver can vote for this regulator in PLL driver file, but for + * the usecase where we come out of idle(static screen), if PLL and + * PHY vote for regulator ,there will be performance delays as both + * votes go through RPM to enable regulators. + */ + phy->regulator_required = true; + DSI_PHY_DBG(phy, "lane_datarate=%u min_datarate=%u required=%d\n", + clk_freq->byte_clk_rate * BITS_PER_BYTE, + phy->regulator_min_datarate_bps, + phy->regulator_required); + + return 0; +} + +/** + * dsi_phy_set_timing_params() - timing parameters for the panel + * @phy: DSI PHY handle + * @timing: array holding timing params. + * @size: size of the array. + * @commit: boolean to indicate if programming PHY HW registers is + * required + * + * When PHY timing calculator is not implemented, this array will be used to + * pass PHY timing information. + * + * Return: error code. + */ +int dsi_phy_set_timing_params(struct msm_dsi_phy *phy, + u32 *timing, u32 size, bool commit) +{ + int rc = 0; + + if (!phy || !timing || !size) { + DSI_PHY_ERR(phy, "Invalid params\n"); + return -EINVAL; + } + + mutex_lock(&phy->phy_lock); + + if (phy->hw.ops.phy_timing_val) + rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size); + + if (!rc) + phy->cfg.is_phy_timing_present = true; + + if (phy->hw.ops.commit_phy_timing && commit) + phy->hw.ops.commit_phy_timing(&phy->hw, &phy->cfg.timing); + + mutex_unlock(&phy->phy_lock); + return rc; +} + +/** + * dsi_phy_conv_phy_to_logical_lane() - Convert physical to logical lane + * @lane_map: logical lane + * @phy_lane: physical lane + * + * Return: Error code on failure. Lane number on success. + */ +int dsi_phy_conv_phy_to_logical_lane( + struct dsi_lane_map *lane_map, enum dsi_phy_data_lanes phy_lane) +{ + int i = 0; + + if (phy_lane > DSI_PHYSICAL_LANE_3) + return -EINVAL; + + for (i = DSI_LOGICAL_LANE_0; i < (DSI_LANE_MAX - 1); i++) { + if (lane_map->lane_map_v2[i] == phy_lane) + break; + } + return i; +} + +/** + * dsi_phy_conv_logical_to_phy_lane() - Convert logical to physical lane + * @lane_map: physical lane + * @lane: logical lane + * + * Return: Error code on failure. Lane number on success. + */ +int dsi_phy_conv_logical_to_phy_lane( + struct dsi_lane_map *lane_map, enum dsi_logical_lane lane) +{ + int i = 0; + + if (lane > (DSI_LANE_MAX - 1)) + return -EINVAL; + + for (i = DSI_LOGICAL_LANE_0; i < (DSI_LANE_MAX - 1); i++) { + if (BIT(i) == lane_map->lane_map_v2[lane]) + break; + } + return i; +} + +/** + * dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers + * @phy: DSI PHY handle + * @delay: pipe delays for dynamic refresh + * @is_master: Boolean to indicate if for master or slave. + */ +void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy, + struct dsi_dyn_clk_delay *delay, + bool is_master) +{ + struct dsi_phy_cfg *cfg; + + if (!phy) + return; + + mutex_lock(&phy->phy_lock); + + cfg = &phy->cfg; + if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_config) + phy->hw.ops.dyn_refresh_ops.dyn_refresh_config(&phy->hw, cfg, + is_master); + if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay) + phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay( + &phy->hw, delay); + + mutex_unlock(&phy->phy_lock); +} + +/** + * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh + * @phy: DSI PHY handle + * @is_master: Boolean to indicate if for master or slave. + */ +void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master) +{ + u32 off; + + if (!phy) + return; + + mutex_lock(&phy->phy_lock); + /* + * program PLL_SWI_INTF_SEL and SW_TRIGGER bit only for + * master and program SYNC_MODE bit only for slave. + */ + if (is_master) + off = BIT(DYN_REFRESH_INTF_SEL) | BIT(DYN_REFRESH_SWI_CTRL) | + BIT(DYN_REFRESH_SW_TRIGGER); + else + off = BIT(DYN_REFRESH_SYNC_MODE) | BIT(DYN_REFRESH_SWI_CTRL); + + if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper) + phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, off); + + mutex_unlock(&phy->phy_lock); +} + +/** + * dsi_phy_cache_phy_timings - cache the phy timings calculated as part of + * dynamic refresh. + * @phy: DSI PHY Handle. + * @dst: Pointer to cache location. + * @size: Number of phy lane settings. + */ +int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, u32 *dst, + u32 size) +{ + int rc = 0; + + if (!phy || !dst || !size) + return -EINVAL; + + if (phy->hw.ops.dyn_refresh_ops.cache_phy_timings) + rc = phy->hw.ops.dyn_refresh_ops.cache_phy_timings( + &phy->cfg.timing, dst, size); + + if (rc) + DSI_PHY_ERR(phy, "failed to cache phy timings %d\n", rc); + + return rc; +} + +/** + * dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config + * @phy: DSI PHY handle + */ +void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy) +{ + if (!phy) + return; + + mutex_lock(&phy->phy_lock); + + if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper) + phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, 0); + + mutex_unlock(&phy->phy_lock); +} + +/** + * dsi_phy_set_continuous_clk() - set/unset force clock lane HS request + * @phy: DSI PHY handle + * @enable: variable to control continuous clock + */ +void dsi_phy_set_continuous_clk(struct msm_dsi_phy *phy, bool enable) +{ + if (!phy) + return; + + mutex_lock(&phy->phy_lock); + + if (phy->hw.ops.set_continuous_clk) + phy->hw.ops.set_continuous_clk(&phy->hw, enable); + else + DSI_PHY_WARN(phy, "set_continuous_clk ops not present\n"); + + mutex_unlock(&phy->phy_lock); + +} + +void dsi_phy_drv_register(void) +{ + platform_driver_register(&dsi_phy_platform_driver); +} + +void dsi_phy_drv_unregister(void) +{ + platform_driver_unregister(&dsi_phy_platform_driver); +} diff --git a/techpack/display/msm/dsi/dsi_phy.h b/techpack/display/msm/dsi/dsi_phy.h new file mode 100644 index 0000000000000000000000000000000000000000..6643a940c1989b21b409cab0c93cb916448fc44b --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy.h @@ -0,0 +1,352 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_PHY_H_ +#define _DSI_PHY_H_ + +#include "dsi_defs.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "dsi_phy_hw.h" + +struct dsi_ver_spec_info { + enum dsi_phy_version version; + u32 lane_cfg_count; + u32 strength_cfg_count; + u32 regulator_cfg_count; + u32 timing_cfg_count; +}; + +/** + * struct dsi_phy_power_info - digital and analog power supplies for DSI PHY + * @digital: Digital power supply for DSI PHY. + * @phy_pwr: Analog power supplies for DSI PHY to work. + */ +struct dsi_phy_power_info { + struct dsi_regulator_info digital; + struct dsi_regulator_info phy_pwr; +}; + +/** + * enum phy_engine_state - define engine status for dsi phy. + * @DSI_PHY_ENGINE_OFF: Engine is turned off. + * @DSI_PHY_ENGINE_ON: Engine is turned on. + * @DSI_PHY_ENGINE_MAX: Maximum value. + */ +enum phy_engine_state { + DSI_PHY_ENGINE_OFF = 0, + DSI_PHY_ENGINE_ON, + DSI_PHY_ENGINE_MAX, +}; + +/** + * enum phy_ulps_return_type - define set_ulps return type for dsi phy. + * @DSI_PHY_ULPS_HANDLED: ulps is handled in phy. + * @DSI_PHY_ULPS_NOT_HANDLED: ulps is not handled in phy. + * @DSI_PHY_ULPS_ERROR: ulps request failed in phy. + */ +enum phy_ulps_return_type { + DSI_PHY_ULPS_HANDLED = 0, + DSI_PHY_ULPS_NOT_HANDLED, + DSI_PHY_ULPS_ERROR, +}; + +/** + * struct msm_dsi_phy - DSI PHY object + * @pdev: Pointer to platform device. + * @index: Instance id. + * @name: Name of the PHY instance. + * @refcount: Reference count. + * @phy_lock: Mutex for hardware and object access. + * @ver_info: Version specific phy parameters. + * @hw: DSI PHY hardware object. + * @pwr_info: Power information. + * @cfg: DSI phy configuration. + * @clk_cb: structure containing call backs for clock control + * @power_state: True if PHY is powered on. + * @dsi_phy_state: PHY state information. + * @mode: Current mode. + * @data_lanes: Number of data lanes used. + * @dst_format: Destination format. + * @allow_phy_power_off: True if PHY is allowed to power off when idle + * @regulator_min_datarate_bps: Minimum per lane data rate to turn on regulator + * @regulator_required: True if phy regulator is required + */ +struct msm_dsi_phy { + struct platform_device *pdev; + int index; + const char *name; + u32 refcount; + struct mutex phy_lock; + + const struct dsi_ver_spec_info *ver_info; + struct dsi_phy_hw hw; + + struct dsi_phy_power_info pwr_info; + + struct dsi_phy_cfg cfg; + struct clk_ctrl_cb clk_cb; + + enum phy_engine_state dsi_phy_state; + bool power_state; + struct dsi_mode_info mode; + enum dsi_data_lanes data_lanes; + enum dsi_pixel_format dst_format; + + bool allow_phy_power_off; + u32 regulator_min_datarate_bps; + bool regulator_required; +}; + +/** + * dsi_phy_get() - get a dsi phy handle from device node + * @of_node: device node for dsi phy controller + * + * Gets the DSI PHY handle for the corresponding of_node. The ref count is + * incremented to one all subsequents get will fail until the original client + * calls a put. + * + * Return: DSI PHY handle or an error code. + */ +struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node); + +/** + * dsi_phy_put() - release dsi phy handle + * @dsi_phy: DSI PHY handle. + * + * Release the DSI PHY hardware. Driver will clean up all resources and puts + * back the DSI PHY into reset state. + */ +void dsi_phy_put(struct msm_dsi_phy *dsi_phy); + +/** + * dsi_phy_get_version() - returns dsi phy version + * @dsi_phy: DSI PHY handle. + * + * Return: phy version + */ +int dsi_phy_get_version(struct msm_dsi_phy *phy); + +/** + * dsi_phy_drv_init() - initialize dsi phy driver + * @dsi_phy: DSI PHY handle. + * + * Initializes DSI PHY driver. Should be called after dsi_phy_get(). + * + * Return: error code. + */ +int dsi_phy_drv_init(struct msm_dsi_phy *dsi_phy); + +/** + * dsi_phy_drv_deinit() - de-initialize dsi phy driver + * @dsi_phy: DSI PHY handle. + * + * Release all resources acquired by dsi_phy_drv_init(). + * + * Return: error code. + */ +int dsi_phy_drv_deinit(struct msm_dsi_phy *dsi_phy); + +/** + * dsi_phy_validate_mode() - validate a display mode + * @dsi_phy: DSI PHY handle. + * @mode: Mode information. + * + * Validation will fail if the mode cannot be supported by the PHY driver or + * hardware. + * + * Return: error code. + */ +int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy, + struct dsi_mode_info *mode); + +/** + * dsi_phy_set_power_state() - enable/disable dsi phy power supplies + * @dsi_phy: DSI PHY handle. + * @enable: Boolean flag to enable/disable. + * + * Return: error code. + */ +int dsi_phy_set_power_state(struct msm_dsi_phy *dsi_phy, bool enable); + +/** + * dsi_phy_enable() - enable DSI PHY hardware + * @dsi_phy: DSI PHY handle. + * @config: DSI host configuration. + * @pll_source: Source PLL for PHY clock. + * @skip_validation: Validation will not be performed on parameters. + * @is_cont_splash_enabled: check whether continuous splash enabled. + * + * Validates and enables DSI PHY. + * + * Return: error code. + */ +int dsi_phy_enable(struct msm_dsi_phy *dsi_phy, + struct dsi_host_config *config, + enum dsi_phy_pll_source pll_source, + bool skip_validation, + bool is_cont_splash_enabled); + +/** + * dsi_phy_disable() - disable DSI PHY hardware. + * @phy: DSI PHY handle. + * + * Return: error code. + */ +int dsi_phy_disable(struct msm_dsi_phy *phy); + +/** + * dsi_phy_set_ulps() - set ulps state for DSI pHY + * @phy: DSI PHY handle + * @config: DSi host configuration information. + * @enable: Enable/Disable + * @clamp_enabled: mmss_clamp enabled/disabled + * + * Return: error code. + */ +int dsi_phy_set_ulps(struct msm_dsi_phy *phy, struct dsi_host_config *config, + bool enable, bool clamp_enabled); + +/** + * dsi_phy_clk_cb_register() - Register PHY clock control callback + * @phy: DSI PHY handle + * @clk_cb: Structure containing call back for clock control + * + * Return: error code. + */ +int dsi_phy_clk_cb_register(struct msm_dsi_phy *phy, + struct clk_ctrl_cb *clk_cb); + +/** + * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen + * @phy: DSI PHY handle + * @enable: boolean to specify PHY enable/disable. + * + * Return: error code. + */ +int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable); + +/** + * dsi_phy_set_clamp_state() - configure clamps for DSI lanes + * @phy: DSI PHY handle. + * @enable: boolean to specify clamp enable/disable. + * + * Return: error code. + */ +int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable); + +/** + * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting + * @phy: DSI PHY handle + * @clk_freq: link clock frequency + * + * Return: error code. + */ +int dsi_phy_set_clk_freq(struct msm_dsi_phy *phy, + struct link_clk_freq *clk_freq); + +/** + * dsi_phy_set_timing_params() - timing parameters for the panel + * @phy: DSI PHY handle + * @timing: array holding timing params. + * @size: size of the array. + * @commit: boolean to indicate if programming PHY HW registers is + * required + * + * When PHY timing calculator is not implemented, this array will be used to + * pass PHY timing information. + * + * Return: error code. + */ +int dsi_phy_set_timing_params(struct msm_dsi_phy *phy, + u32 *timing, u32 size, bool commit); + +/** + * dsi_phy_lane_reset() - Reset DSI PHY lanes in case of error + * @phy: DSI PHY handle + * + * Return: error code. + */ +int dsi_phy_lane_reset(struct msm_dsi_phy *phy); + +/** + * dsi_phy_toggle_resync_fifo() - toggle resync retime FIFO + * @phy: DSI PHY handle + * + * Toggle the resync retime FIFO to synchronize the data paths. + * This should be done everytime there is a change in the link clock + * rate + */ +void dsi_phy_toggle_resync_fifo(struct msm_dsi_phy *phy); + +/** + * dsi_phy_reset_clk_en_sel() - reset clk_en_select on cmn_clk_cfg1 register + * @phy: DSI PHY handle + * + * After toggling resync fifo regiater, clk_en_sel bit on cmn_clk_cfg1 + * register has to be reset + */ +void dsi_phy_reset_clk_en_sel(struct msm_dsi_phy *phy); + +/** + * dsi_phy_drv_register() - register platform driver for dsi phy + */ +void dsi_phy_drv_register(void); + +/** + * dsi_phy_drv_unregister() - unregister platform driver + */ +void dsi_phy_drv_unregister(void); + +/** + * dsi_phy_update_phy_timings() - Update dsi phy timings + * @phy: DSI PHY handle + * @config: DSI Host config parameters + * + * Return: error code. + */ +int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy, + struct dsi_host_config *config); + +/** + * dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers + * @phy: DSI PHY handle + * @delay: pipe delays for dynamic refresh + * @is_master: Boolean to indicate if for master or slave + */ +void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy, + struct dsi_dyn_clk_delay *delay, + bool is_master); +/** + * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh + * @phy: DSI PHY handle + * @is_master: Boolean to indicate if for master or slave. + */ +void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master); + +/** + * dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config + * @phy: DSI PHY handle + */ +void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy); + +/** + * dsi_phy_dyn_refresh_cache_phy_timings - cache the phy timings calculated + * as part of dynamic refresh. + * @phy: DSI PHY Handle. + * @dst: Pointer to cache location. + * @size: Number of phy lane settings. + */ +int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, + + u32 *dst, u32 size); +/** + * dsi_phy_set_continuous_clk() - API to set/unset force clock lane HS request. + * @phy: DSI PHY Handle. + * @enable: variable to control continuous clock. + */ +void dsi_phy_set_continuous_clk(struct msm_dsi_phy *phy, bool enable); + +#endif /* _DSI_PHY_H_ */ diff --git a/techpack/display/msm/dsi/dsi_phy_hw.h b/techpack/display/msm/dsi/dsi_phy_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..b550ee720cadc66386de2716e136f711a4acc5d6 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_hw.h @@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_PHY_HW_H_ +#define _DSI_PHY_HW_H_ + +#include "dsi_defs.h" + +#define DSI_MAX_SETTINGS 8 +#define DSI_PHY_TIMING_V3_SIZE 12 +#define DSI_PHY_TIMING_V4_SIZE 14 + +#define DSI_PHY_DBG(p, fmt, ...) DRM_DEV_DEBUG(NULL, "[msm-dsi-debug]: DSI_%d: "\ + fmt, p ? p->index : -1, ##__VA_ARGS__) +#define DSI_PHY_ERR(p, fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: DSI_%d: "\ + fmt, p ? p->index : -1, ##__VA_ARGS__) +#define DSI_PHY_INFO(p, fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: DSI_%d: "\ + fmt, p ? p->index : -1, ##__VA_ARGS__) +#define DSI_PHY_WARN(p, fmt, ...) DRM_WARN("[msm-dsi-warn]: DSI_%d: " fmt,\ + p ? p->index : -1, ##__VA_ARGS__) + +/** + * enum dsi_phy_version - DSI PHY version enumeration + * @DSI_PHY_VERSION_UNKNOWN: Unknown version. + * @DSI_PHY_VERSION_0_0_HPM: 28nm-HPM. + * @DSI_PHY_VERSION_0_0_LPM: 28nm-HPM. + * @DSI_PHY_VERSION_1_0: 20nm + * @DSI_PHY_VERSION_2_0: 14nm + * @DSI_PHY_VERSION_3_0: 10nm + * @DSI_PHY_VERSION_4_0: 7nm + * @DSI_PHY_VERSION_4_1: 7nm + * @DSI_PHY_VERSION_MAX: + */ +enum dsi_phy_version { + DSI_PHY_VERSION_UNKNOWN, + DSI_PHY_VERSION_0_0_HPM, /* 28nm-HPM */ + DSI_PHY_VERSION_0_0_LPM, /* 28nm-LPM */ + DSI_PHY_VERSION_1_0, /* 20nm */ + DSI_PHY_VERSION_2_0, /* 14nm */ + DSI_PHY_VERSION_3_0, /* 10nm */ + DSI_PHY_VERSION_4_0, /* 7nm */ + DSI_PHY_VERSION_4_1, /* 7nm */ + DSI_PHY_VERSION_MAX +}; + +/** + * enum dsi_phy_hw_features - features supported by DSI PHY hardware + * @DSI_PHY_DPHY: Supports DPHY + * @DSI_PHY_CPHY: Supports CPHY + * @DSI_PHY_SPLIT_LINK: Supports Split Link + * @DSI_PHY_MAX_FEATURES: + */ +enum dsi_phy_hw_features { + DSI_PHY_DPHY, + DSI_PHY_CPHY, + DSI_PHY_SPLIT_LINK, + DSI_PHY_MAX_FEATURES +}; + +/** + * enum dsi_phy_pll_source - pll clock source for PHY. + * @DSI_PLL_SOURCE_STANDALONE: Clock is sourced from native PLL and is not + * shared by other PHYs. + * @DSI_PLL_SOURCE_NATIVE: Clock is sourced from native PLL and is + * shared by other PHYs. + * @DSI_PLL_SOURCE_NON_NATIVE: Clock is sourced from other PHYs. + * @DSI_PLL_SOURCE_MAX: + */ +enum dsi_phy_pll_source { + DSI_PLL_SOURCE_STANDALONE = 0, + DSI_PLL_SOURCE_NATIVE, + DSI_PLL_SOURCE_NON_NATIVE, + DSI_PLL_SOURCE_MAX +}; + +/** + * struct dsi_phy_per_lane_cfgs - Holds register values for PHY parameters + * @lane: A set of maximum 8 values for each lane. + * @lane_v3: A set of maximum 12 values for each lane. + * @count_per_lane: Number of values per each lane. + */ +struct dsi_phy_per_lane_cfgs { + u8 lane[DSI_LANE_MAX][DSI_MAX_SETTINGS]; + u8 lane_v3[DSI_PHY_TIMING_V3_SIZE]; + u8 lane_v4[DSI_PHY_TIMING_V4_SIZE]; + u32 count_per_lane; +}; + +/** + * struct dsi_phy_cfg - DSI PHY configuration + * @lanecfg: Lane configuration settings. + * @strength: Strength settings for lanes. + * @timing: Timing parameters for lanes. + * @is_phy_timing_present: Boolean whether phy timings are defined. + * @regulators: Regulator settings for lanes. + * @pll_source: PLL source. + * @lane_map: DSI logical to PHY lane mapping. + * @force_clk_lane_hs:Boolean whether to force clock lane in HS mode. + * @phy_type: Phy-type (Dphy/Cphy). + * @bit_clk_rate_hz: DSI bit clk rate in HZ. + */ +struct dsi_phy_cfg { + struct dsi_phy_per_lane_cfgs lanecfg; + struct dsi_phy_per_lane_cfgs strength; + struct dsi_phy_per_lane_cfgs timing; + bool is_phy_timing_present; + struct dsi_phy_per_lane_cfgs regulators; + enum dsi_phy_pll_source pll_source; + struct dsi_lane_map lane_map; + bool force_clk_lane_hs; + enum dsi_phy_type phy_type; + unsigned long bit_clk_rate_hz; +}; + +struct dsi_phy_hw; + +struct phy_ulps_config_ops { + /** + * wait_for_lane_idle() - wait for DSI lanes to go to idle state + * @phy: Pointer to DSI PHY hardware instance. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to be checked to be in idle state. + */ + int (*wait_for_lane_idle)(struct dsi_phy_hw *phy, u32 lanes); + + /** + * ulps_request() - request ulps entry for specified lanes + * @phy: Pointer to DSI PHY hardware instance. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to enter ULPS. + * + * Caller should check if lanes are in ULPS mode by calling + * get_lanes_in_ulps() operation. + */ + void (*ulps_request)(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes); + + /** + * ulps_exit() - exit ULPS on specified lanes + * @phy: Pointer to DSI PHY hardware instance. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + * @lanes: ORed list of lanes (enum dsi_data_lanes) which need + * to exit ULPS. + * + * Caller should check if lanes are in active mode by calling + * get_lanes_in_ulps() operation. + */ + void (*ulps_exit)(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes); + + /** + * get_lanes_in_ulps() - returns the list of lanes in ULPS mode + * @phy: Pointer to DSI PHY hardware instance. + * + * Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS + * state. + * + * Return: List of lanes in ULPS state. + */ + u32 (*get_lanes_in_ulps)(struct dsi_phy_hw *phy); + + /** + * is_lanes_in_ulps() - checks if the given lanes are in ulps + * @lanes: lanes to be checked. + * @ulps_lanes: lanes in ulps currenly. + * + * Return: true if all the given lanes are in ulps; false otherwise. + */ + bool (*is_lanes_in_ulps)(u32 ulps, u32 ulps_lanes); +}; + +struct phy_dyn_refresh_ops { + /** + * dyn_refresh_helper - helper function to config particular registers + * @phy: Pointer to DSI PHY hardware instance. + * @offset: register offset to program. + */ + void (*dyn_refresh_helper)(struct dsi_phy_hw *phy, u32 offset); + + /** + * dyn_refresh_config - configure dynamic refresh ctrl registers + * @phy: Pointer to DSI PHY hardware instance. + * @cfg: Pointer to DSI PHY timings. + * @is_master: Boolean to indicate whether for master or slave. + */ + void (*dyn_refresh_config)(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master); + + /** + * dyn_refresh_pipe_delay - configure pipe delay registers for dynamic + * refresh. + * @phy: Pointer to DSI PHY hardware instance. + * @delay: structure containing all the delays to be programed. + */ + void (*dyn_refresh_pipe_delay)(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay); + + /** + * cache_phy_timings - cache the phy timings calculated as part of + * dynamic refresh. + * @timings: Pointer to calculated phy timing parameters. + * @dst: Pointer to cache location. + * @size: Number of phy lane settings. + */ + int (*cache_phy_timings)(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size); +}; + +/** + * struct dsi_phy_hw_ops - Operations for DSI PHY hardware. + * @regulator_enable: Enable PHY regulators. + * @regulator_disable: Disable PHY regulators. + * @enable: Enable PHY. + * @disable: Disable PHY. + * @calculate_timing_params: Calculate PHY timing params from mode information + */ +struct dsi_phy_hw_ops { + /** + * regulator_enable() - enable regulators for DSI PHY + * @phy: Pointer to DSI PHY hardware object. + * @reg_cfg: Regulator configuration for all DSI lanes. + */ + void (*regulator_enable)(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *reg_cfg); + + /** + * regulator_disable() - disable regulators + * @phy: Pointer to DSI PHY hardware object. + */ + void (*regulator_disable)(struct dsi_phy_hw *phy); + + /** + * enable() - Enable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ + void (*enable)(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); + + /** + * disable() - Disable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ + void (*disable)(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); + + /** + * phy_idle_on() - Enable PHY hardware when entering idle screen + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ + void (*phy_idle_on)(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg); + + /** + * phy_idle_off() - Disable PHY hardware when exiting idle screen + * @phy: Pointer to DSI PHY hardware object. + */ + void (*phy_idle_off)(struct dsi_phy_hw *phy); + + /** + * calculate_timing_params() - calculates timing parameters. + * @phy: Pointer to DSI PHY hardware object. + * @mode: Mode information for which timing has to be calculated. + * @config: DSI host configuration for this mode. + * @timing: Timing parameters for each lane which will be returned. + * @use_mode_bit_clk: Boolean to indicate whether reacalculate dsi + * bitclk or use the existing bitclk(for dynamic clk case). + */ + int (*calculate_timing_params)(struct dsi_phy_hw *phy, + struct dsi_mode_info *mode, + struct dsi_host_common_cfg *config, + struct dsi_phy_per_lane_cfgs *timing, + bool use_mode_bit_clk); + + /** + * phy_timing_val() - Gets PHY timing values. + * @timing_val: Timing parameters for each lane which will be returned. + * @timing: Array containing PHY timing values + * @size: Size of the array + */ + int (*phy_timing_val)(struct dsi_phy_per_lane_cfgs *timing_val, + u32 *timing, u32 size); + + /** + * clamp_ctrl() - configure clamps for DSI lanes + * @phy: DSI PHY handle. + * @enable: boolean to specify clamp enable/disable. + * Return: error code. + */ + void (*clamp_ctrl)(struct dsi_phy_hw *phy, bool enable); + + /** + * phy_lane_reset() - Reset dsi phy lanes in case of error. + * @phy: Pointer to DSI PHY hardware object. + * Return: error code. + */ + int (*phy_lane_reset)(struct dsi_phy_hw *phy); + + /** + * toggle_resync_fifo() - toggle resync retime FIFO to sync data paths + * @phy: Pointer to DSI PHY hardware object. + * Return: error code. + */ + void (*toggle_resync_fifo)(struct dsi_phy_hw *phy); + + /** + * reset_clk_en_sel() - reset clk_en_sel on phy cmn_clk_cfg1 register + * @phy: Pointer to DSI PHY hardware object. + */ + void (*reset_clk_en_sel)(struct dsi_phy_hw *phy); + + /** + * set_continuous_clk() - Set continuous clock + * @phy: Pointer to DSI PHY hardware object + * @enable: Bool to control continuous clock request. + */ + void (*set_continuous_clk)(struct dsi_phy_hw *phy, bool enable); + + /** + * commit_phy_timing() - Commit PHY timing + * @phy: Pointer to DSI PHY hardware object. + * @timing: Pointer to PHY timing array + */ + void (*commit_phy_timing)(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *timing); + + void *timing_ops; + struct phy_ulps_config_ops ulps_ops; + struct phy_dyn_refresh_ops dyn_refresh_ops; +}; + +/** + * struct dsi_phy_hw - DSI phy hardware object specific to an instance + * @base: VA for the DSI PHY base address. + * @length: Length of the DSI PHY register base map. + * @dyn_pll_base: VA for the DSI dynamic refresh base address. + * @length: Length of the DSI dynamic refresh register base map. + * @index: Instance ID of the controller. + * @version: DSI PHY version. + * @phy_clamp_base: Base address of phy clamp register map. + * @feature_map: Features supported by DSI PHY. + * @ops: Function pointer to PHY operations. + */ +struct dsi_phy_hw { + void __iomem *base; + u32 length; + void __iomem *dyn_pll_base; + u32 dyn_refresh_len; + u32 index; + + enum dsi_phy_version version; + void __iomem *phy_clamp_base; + + DECLARE_BITMAP(feature_map, DSI_PHY_MAX_FEATURES); + struct dsi_phy_hw_ops ops; +}; + +/** + * dsi_phy_conv_phy_to_logical_lane() - Convert physical to logical lane + * @lane_map: logical lane + * @phy_lane: physical lane + * + * Return: Error code on failure. Lane number on success. + */ +int dsi_phy_conv_phy_to_logical_lane( + struct dsi_lane_map *lane_map, enum dsi_phy_data_lanes phy_lane); + +/** + * dsi_phy_conv_logical_to_phy_lane() - Convert logical to physical lane + * @lane_map: physical lane + * @lane: logical lane + * + * Return: Error code on failure. Lane number on success. + */ +int dsi_phy_conv_logical_to_phy_lane( + struct dsi_lane_map *lane_map, enum dsi_logical_lane lane); + +#endif /* _DSI_PHY_HW_H_ */ diff --git a/techpack/display/msm/dsi/dsi_phy_hw_v2_0.c b/techpack/display/msm/dsi/dsi_phy_hw_v2_0.c new file mode 100644 index 0000000000000000000000000000000000000000..5ee1de16c62a06eccfe9b12e692d6c0a5e406d9d --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_hw_v2_0.c @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/math64.h> +#include <linux/delay.h> +#include "dsi_hw.h" +#include "dsi_phy_hw.h" + +#define DSIPHY_CMN_REVISION_ID0 0x0000 +#define DSIPHY_CMN_REVISION_ID1 0x0004 +#define DSIPHY_CMN_REVISION_ID2 0x0008 +#define DSIPHY_CMN_REVISION_ID3 0x000C +#define DSIPHY_CMN_CLK_CFG0 0x0010 +#define DSIPHY_CMN_CLK_CFG1 0x0014 +#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018 +#define DSIPHY_CMN_CTRL_0 0x001C +#define DSIPHY_CMN_CTRL_1 0x0020 +#define DSIPHY_CMN_CAL_HW_TRIGGER 0x0024 +#define DSIPHY_CMN_CAL_SW_CFG0 0x0028 +#define DSIPHY_CMN_CAL_SW_CFG1 0x002C +#define DSIPHY_CMN_CAL_SW_CFG2 0x0030 +#define DSIPHY_CMN_CAL_HW_CFG0 0x0034 +#define DSIPHY_CMN_CAL_HW_CFG1 0x0038 +#define DSIPHY_CMN_CAL_HW_CFG2 0x003C +#define DSIPHY_CMN_CAL_HW_CFG3 0x0040 +#define DSIPHY_CMN_CAL_HW_CFG4 0x0044 +#define DSIPHY_CMN_PLL_CNTRL 0x0048 +#define DSIPHY_CMN_LDO_CNTRL 0x004C + +#define DSIPHY_CMN_REGULATOR_CAL_STATUS0 0x0064 +#define DSIPHY_CMN_REGULATOR_CAL_STATUS1 0x0068 +#define DSI_MDP_ULPS_CLAMP_ENABLE_OFF 0x0054 + +/* n = 0..3 for data lanes and n = 4 for clock lane + * t for count per lane + */ +#define DSIPHY_DLNX_CFG(n, t) \ + (0x100 + ((t) * 0x04) + ((n) * 0x80)) +#define DSIPHY_DLNX_TIMING_CTRL(n, t) \ + (0x118 + ((t) * 0x04) + ((n) * 0x80)) +#define DSIPHY_DLNX_STRENGTH_CTRL(n, t) \ + (0x138 + ((t) * 0x04) + ((n) * 0x80)) +#define DSIPHY_DLNX_TEST_DATAPATH(n) (0x110 + ((n) * 0x80)) +#define DSIPHY_DLNX_TEST_STR(n) (0x114 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_POLY(n) (0x140 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_SEED0(n) (0x144 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_SEED1(n) (0x148 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_HEAD(n) (0x14C + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_SOT(n) (0x150 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_CTRL0(n) (0x154 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_CTRL1(n) (0x158 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_CTRL2(n) (0x15C + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_CTRL3(n) (0x160 + ((n) * 0x80)) +#define DSIPHY_DLNX_VREG_CNTRL(n) (0x164 + ((n) * 0x80)) +#define DSIPHY_DLNX_HSTX_STR_STATUS(n) (0x168 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_STATUS0(n) (0x16C + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_STATUS1(n) (0x170 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_STATUS2(n) (0x174 + ((n) * 0x80)) +#define DSIPHY_DLNX_BIST_STATUS3(n) (0x178 + ((n) * 0x80)) +#define DSIPHY_DLNX_MISR_STATUS(n) (0x17C + ((n) * 0x80)) + +#define DSIPHY_PLL_CLKBUFLR_EN 0x041C +#define DSIPHY_PLL_PLL_BANDGAP 0x0508 + +/* dynamic refresh control registers */ +#define DSI_DYN_REFRESH_CTRL 0x000 +#define DSI_DYN_REFRESH_PIPE_DELAY 0x004 +#define DSI_DYN_REFRESH_PIPE_DELAY2 0x008 +#define DSI_DYN_REFRESH_PLL_DELAY 0x00C +#define DSI_DYN_REFRESH_STATUS 0x010 +#define DSI_DYN_REFRESH_PLL_CTRL0 0x014 +#define DSI_DYN_REFRESH_PLL_CTRL1 0x018 +#define DSI_DYN_REFRESH_PLL_CTRL2 0x01C +#define DSI_DYN_REFRESH_PLL_CTRL3 0x020 +#define DSI_DYN_REFRESH_PLL_CTRL4 0x024 +#define DSI_DYN_REFRESH_PLL_CTRL5 0x028 +#define DSI_DYN_REFRESH_PLL_CTRL6 0x02C +#define DSI_DYN_REFRESH_PLL_CTRL7 0x030 +#define DSI_DYN_REFRESH_PLL_CTRL8 0x034 +#define DSI_DYN_REFRESH_PLL_CTRL9 0x038 +#define DSI_DYN_REFRESH_PLL_CTRL10 0x03C +#define DSI_DYN_REFRESH_PLL_CTRL11 0x040 +#define DSI_DYN_REFRESH_PLL_CTRL12 0x044 +#define DSI_DYN_REFRESH_PLL_CTRL13 0x048 +#define DSI_DYN_REFRESH_PLL_CTRL14 0x04C +#define DSI_DYN_REFRESH_PLL_CTRL15 0x050 +#define DSI_DYN_REFRESH_PLL_CTRL16 0x054 +#define DSI_DYN_REFRESH_PLL_CTRL17 0x058 +#define DSI_DYN_REFRESH_PLL_CTRL18 0x05C +#define DSI_DYN_REFRESH_PLL_CTRL19 0x060 +#define DSI_DYN_REFRESH_PLL_CTRL20 0x064 +#define DSI_DYN_REFRESH_PLL_CTRL21 0x068 +#define DSI_DYN_REFRESH_PLL_CTRL22 0x06C +#define DSI_DYN_REFRESH_PLL_CTRL23 0x070 +#define DSI_DYN_REFRESH_PLL_CTRL24 0x074 +#define DSI_DYN_REFRESH_PLL_CTRL25 0x078 +#define DSI_DYN_REFRESH_PLL_CTRL26 0x07C +#define DSI_DYN_REFRESH_PLL_CTRL27 0x080 +#define DSI_DYN_REFRESH_PLL_CTRL28 0x084 +#define DSI_DYN_REFRESH_PLL_CTRL29 0x088 +#define DSI_DYN_REFRESH_PLL_CTRL30 0x08C +#define DSI_DYN_REFRESH_PLL_CTRL31 0x090 +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR 0x094 +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2 0x098 + +#define DSIPHY_DLN0_CFG1 0x0104 +#define DSIPHY_DLN0_TIMING_CTRL_4 0x0118 +#define DSIPHY_DLN0_TIMING_CTRL_5 0x011C +#define DSIPHY_DLN0_TIMING_CTRL_6 0x0120 +#define DSIPHY_DLN0_TIMING_CTRL_7 0x0124 +#define DSIPHY_DLN0_TIMING_CTRL_8 0x0128 + +#define DSIPHY_DLN1_CFG1 0x0184 +#define DSIPHY_DLN1_TIMING_CTRL_4 0x0198 +#define DSIPHY_DLN1_TIMING_CTRL_5 0x019C +#define DSIPHY_DLN1_TIMING_CTRL_6 0x01A0 +#define DSIPHY_DLN1_TIMING_CTRL_7 0x01A4 +#define DSIPHY_DLN1_TIMING_CTRL_8 0x01A8 + +#define DSIPHY_DLN2_CFG1 0x0204 +#define DSIPHY_DLN2_TIMING_CTRL_4 0x0218 +#define DSIPHY_DLN2_TIMING_CTRL_5 0x021C +#define DSIPHY_DLN2_TIMING_CTRL_6 0x0220 +#define DSIPHY_DLN2_TIMING_CTRL_7 0x0224 +#define DSIPHY_DLN2_TIMING_CTRL_8 0x0228 + +#define DSIPHY_DLN3_CFG1 0x0284 +#define DSIPHY_DLN3_TIMING_CTRL_4 0x0298 +#define DSIPHY_DLN3_TIMING_CTRL_5 0x029C +#define DSIPHY_DLN3_TIMING_CTRL_6 0x02A0 +#define DSIPHY_DLN3_TIMING_CTRL_7 0x02A4 +#define DSIPHY_DLN3_TIMING_CTRL_8 0x02A8 + +#define DSIPHY_CKLN_CFG1 0x0304 +#define DSIPHY_CKLN_TIMING_CTRL_4 0x0318 +#define DSIPHY_CKLN_TIMING_CTRL_5 0x031C +#define DSIPHY_CKLN_TIMING_CTRL_6 0x0320 +#define DSIPHY_CKLN_TIMING_CTRL_7 0x0324 +#define DSIPHY_CKLN_TIMING_CTRL_8 0x0328 + +#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c +/** + * regulator_enable() - enable regulators for DSI PHY + * @phy: Pointer to DSI PHY hardware object. + * @reg_cfg: Regulator configuration for all DSI lanes. + */ +void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *reg_cfg) +{ + int i; + bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map); + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) + DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(i), reg_cfg->lane[i][0]); + + if (is_split_link) + DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(DSI_LOGICAL_CLOCK_LANE+1), + reg_cfg->lane[DSI_LOGICAL_CLOCK_LANE][0]); + + /* make sure all values are written to hardware */ + wmb(); + + DSI_PHY_DBG(phy, "Phy regulators enabled\n"); +} + +/** + * regulator_disable() - disable regulators + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v2_0_regulator_disable(struct dsi_phy_hw *phy) +{ + DSI_PHY_DBG(phy, "Phy regulators disabled\n"); +} + +/** + * enable() - Enable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +void dsi_phy_hw_v2_0_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + int i, j; + struct dsi_phy_per_lane_cfgs *lanecfg = &cfg->lanecfg; + struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; + struct dsi_phy_per_lane_cfgs *strength = &cfg->strength; + u32 data; + bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map); + + DSI_W32(phy, DSIPHY_CMN_LDO_CNTRL, 0x1C); + + DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, 0x1); + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + for (j = 0; j < lanecfg->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_CFG(i, j), + lanecfg->lane[i][j]); + + DSI_W32(phy, DSIPHY_DLNX_TEST_STR(i), 0x88); + + for (j = 0; j < timing->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL(i, j), + timing->lane[i][j]); + + for (j = 0; j < strength->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i, j), + strength->lane[i][j]); + } + + if (is_split_link) { + i = DSI_LOGICAL_CLOCK_LANE; + + for (j = 0; j < lanecfg->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_CFG(i+1, j), + lanecfg->lane[i][j]); + + DSI_W32(phy, DSIPHY_DLNX_TEST_STR(i+1), 0x0); + DSI_W32(phy, DSIPHY_DLNX_TEST_DATAPATH(i+1), 0x88); + + for (j = 0; j < timing->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_TIMING_CTRL(i+1, j), + timing->lane[i][j]); + + for (j = 0; j < strength->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i+1, j), + strength->lane[i][j]); + + /* enable split link for cmn clk cfg1 */ + data = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1); + data |= BIT(1); + DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, data); + + } + + /* make sure all values are written to hardware before enabling phy */ + wmb(); + + DSI_W32(phy, DSIPHY_CMN_CTRL_1, 0x80); + udelay(100); + DSI_W32(phy, DSIPHY_CMN_CTRL_1, 0x00); + + data = DSI_R32(phy, DSIPHY_CMN_GLBL_TEST_CTRL); + + switch (cfg->pll_source) { + case DSI_PLL_SOURCE_STANDALONE: + DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0x01); + data &= ~BIT(2); + break; + case DSI_PLL_SOURCE_NATIVE: + DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0x03); + data &= ~BIT(2); + break; + case DSI_PLL_SOURCE_NON_NATIVE: + DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0x00); + data |= BIT(2); + break; + default: + break; + } + + DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, data); + + /* Enable bias current for pll1 during split display case */ + if (cfg->pll_source == DSI_PLL_SOURCE_NON_NATIVE) + DSI_W32(phy, DSIPHY_PLL_PLL_BANDGAP, 0x3); + + DSI_PHY_DBG(phy, "Phy enabled\n"); +} + +/** + * disable() - Disable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v2_0_disable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + DSI_W32(phy, DSIPHY_PLL_CLKBUFLR_EN, 0); + DSI_W32(phy, DSIPHY_CMN_GLBL_TEST_CTRL, 0); + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0); + DSI_PHY_DBG(phy, "Phy disabled\n"); +} + +/** + * dsi_phy_hw_v2_0_idle_on() - Enable DSI PHY hardware during idle screen + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v2_0_idle_on(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg) +{ + int i = 0, j; + struct dsi_phy_per_lane_cfgs *strength = &cfg->strength; + bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map); + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + for (j = 0; j < strength->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i, j), + strength->lane[i][j]); + } + if (is_split_link) { + i = DSI_LOGICAL_CLOCK_LANE; + for (j = 0; j < strength->count_per_lane; j++) + DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i+1, j), + strength->lane[i][j]); + } + wmb(); /* make sure write happens */ + DSI_PHY_DBG(phy, "Phy enabled out of idle screen\n"); +} + + +/** + * dsi_phy_hw_v2_0_idle_off() - Disable DSI PHY hardware during idle screen + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy) +{ + int i = 0; + bool is_split_link = test_bit(DSI_PHY_SPLIT_LINK, phy->feature_map); + + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f); + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) + DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(i), 0x1c); + if (is_split_link) + DSI_W32(phy, DSIPHY_DLNX_VREG_CNTRL(DSI_LOGICAL_CLOCK_LANE+1), + 0x1c); + + DSI_W32(phy, DSIPHY_CMN_LDO_CNTRL, 0x1C); + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) + DSI_W32(phy, DSIPHY_DLNX_STRENGTH_CTRL(i, 1), 0x0); + if (is_split_link) + DSI_W32(phy, + DSIPHY_DLNX_STRENGTH_CTRL(DSI_LOGICAL_CLOCK_LANE+1, 1), 0x0); + + wmb(); /* make sure write happens */ + DSI_PHY_DBG(phy, "Phy disabled during idle screen\n"); +} + +int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg, + u32 *timing_val, u32 size) +{ + int i = 0, j = 0; + + if (size != (DSI_LANE_MAX * DSI_MAX_SETTINGS)) { + DSI_ERR("Unexpected timing array size %d\n", size); + return -EINVAL; + } + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + for (j = 0; j < DSI_MAX_SETTINGS; j++) { + timing_cfg->lane[i][j] = *timing_val; + timing_val++; + } + } + return 0; +} + +void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable) +{ + u32 clamp_reg = 0; + + if (!phy->phy_clamp_base) { + DSI_PHY_DBG(phy, "phy_clamp_base NULL\n"); + return; + } + + if (enable) { + clamp_reg |= BIT(0); + DSI_MISC_W32(phy, DSI_MDP_ULPS_CLAMP_ENABLE_OFF, + clamp_reg); + DSI_PHY_DBG(phy, "clamp enabled\n"); + } else { + clamp_reg &= ~BIT(0); + DSI_MISC_W32(phy, DSI_MDP_ULPS_CLAMP_ENABLE_OFF, + clamp_reg); + DSI_PHY_DBG(phy, "clamp disabled\n"); + } +} + +void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master) +{ + u32 glbl_tst_cntrl; + + if (is_master) { + glbl_tst_cntrl = DSI_R32(phy, DSIPHY_CMN_GLBL_TEST_CTRL); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0, + DSIPHY_CMN_GLBL_TEST_CTRL, + DSIPHY_PLL_PLL_BANDGAP, + glbl_tst_cntrl | BIT(1), 0x1); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1, + DSIPHY_PLL_RESETSM_CNTRL5, + DSIPHY_PLL_PLL_BANDGAP, 0x0D, 0x03); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2, + DSIPHY_PLL_RESETSM_CNTRL5, + DSIPHY_CMN_PLL_CNTRL, 0x1D, 0x00); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3, + DSIPHY_CMN_CTRL_1, DSIPHY_DLN0_CFG1, 0x20, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4, + DSIPHY_DLN1_CFG1, DSIPHY_DLN2_CFG1, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5, + DSIPHY_DLN3_CFG1, DSIPHY_CKLN_CFG1, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6, + DSIPHY_DLN0_TIMING_CTRL_4, + DSIPHY_DLN1_TIMING_CTRL_4, + cfg->timing.lane[0][0], cfg->timing.lane[1][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7, + DSIPHY_DLN2_TIMING_CTRL_4, + DSIPHY_DLN3_TIMING_CTRL_4, + cfg->timing.lane[2][0], cfg->timing.lane[3][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8, + DSIPHY_CKLN_TIMING_CTRL_4, + DSIPHY_DLN0_TIMING_CTRL_5, + cfg->timing.lane[4][0], cfg->timing.lane[0][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_DLN1_TIMING_CTRL_5, + DSIPHY_DLN2_TIMING_CTRL_5, + cfg->timing.lane[1][1], cfg->timing.lane[2][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10, + DSIPHY_DLN3_TIMING_CTRL_5, + DSIPHY_CKLN_TIMING_CTRL_5, + cfg->timing.lane[3][1], cfg->timing.lane[4][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11, + DSIPHY_DLN0_TIMING_CTRL_6, + DSIPHY_DLN1_TIMING_CTRL_6, + cfg->timing.lane[0][2], cfg->timing.lane[1][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12, + DSIPHY_DLN2_TIMING_CTRL_6, + DSIPHY_DLN3_TIMING_CTRL_6, + cfg->timing.lane[2][2], cfg->timing.lane[3][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13, + DSIPHY_CKLN_TIMING_CTRL_6, + DSIPHY_DLN0_TIMING_CTRL_7, + cfg->timing.lane[4][2], cfg->timing.lane[0][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14, + DSIPHY_DLN1_TIMING_CTRL_7, + DSIPHY_DLN2_TIMING_CTRL_7, + cfg->timing.lane[1][3], cfg->timing.lane[2][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15, + DSIPHY_DLN3_TIMING_CTRL_7, + DSIPHY_CKLN_TIMING_CTRL_7, + cfg->timing.lane[3][3], cfg->timing.lane[4][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, + DSI_DYN_REFRESH_PLL_CTRL16, + DSIPHY_DLN0_TIMING_CTRL_8, + DSIPHY_DLN1_TIMING_CTRL_8, + cfg->timing.lane[0][4], cfg->timing.lane[1][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17, + DSIPHY_DLN2_TIMING_CTRL_8, + DSIPHY_DLN3_TIMING_CTRL_8, + cfg->timing.lane[2][4], cfg->timing.lane[3][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18, + DSIPHY_CKLN_TIMING_CTRL_8, DSIPHY_CMN_CTRL_1, + cfg->timing.lane[4][4], 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30, + DSIPHY_CMN_GLBL_TEST_CTRL, + DSIPHY_CMN_GLBL_TEST_CTRL, + ((glbl_tst_cntrl) & (~BIT(2))), + ((glbl_tst_cntrl) & (~BIT(2)))); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31, + DSIPHY_CMN_GLBL_TEST_CTRL, + DSIPHY_CMN_GLBL_TEST_CTRL, + ((glbl_tst_cntrl) & (~BIT(2))), + ((glbl_tst_cntrl) & (~BIT(2)))); + } else { + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0, + DSIPHY_DLN0_CFG1, DSIPHY_DLN1_CFG1, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1, + DSIPHY_DLN2_CFG1, DSIPHY_DLN3_CFG1, 0x0, 0x0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2, + DSIPHY_CKLN_CFG1, DSIPHY_DLN0_TIMING_CTRL_4, + 0x0, cfg->timing.lane[0][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3, + DSIPHY_DLN1_TIMING_CTRL_4, + DSIPHY_DLN2_TIMING_CTRL_4, + cfg->timing.lane[1][0], cfg->timing.lane[2][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4, + DSIPHY_DLN3_TIMING_CTRL_4, + DSIPHY_CKLN_TIMING_CTRL_4, + cfg->timing.lane[3][0], cfg->timing.lane[4][0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5, + DSIPHY_DLN0_TIMING_CTRL_5, + DSIPHY_DLN1_TIMING_CTRL_5, + cfg->timing.lane[0][1], cfg->timing.lane[1][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6, + DSIPHY_DLN2_TIMING_CTRL_5, + DSIPHY_DLN3_TIMING_CTRL_5, + cfg->timing.lane[2][1], cfg->timing.lane[3][1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7, + DSIPHY_CKLN_TIMING_CTRL_5, + DSIPHY_DLN0_TIMING_CTRL_6, + cfg->timing.lane[4][1], cfg->timing.lane[0][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8, + DSIPHY_DLN1_TIMING_CTRL_6, + DSIPHY_DLN2_TIMING_CTRL_6, + cfg->timing.lane[1][2], cfg->timing.lane[2][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_DLN3_TIMING_CTRL_6, + DSIPHY_CKLN_TIMING_CTRL_6, + cfg->timing.lane[3][2], cfg->timing.lane[4][2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10, + DSIPHY_DLN0_TIMING_CTRL_7, + DSIPHY_DLN1_TIMING_CTRL_7, + cfg->timing.lane[0][3], cfg->timing.lane[1][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11, + DSIPHY_DLN2_TIMING_CTRL_7, + DSIPHY_DLN3_TIMING_CTRL_7, + cfg->timing.lane[2][3], cfg->timing.lane[3][3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12, + DSIPHY_CKLN_TIMING_CTRL_7, + DSIPHY_DLN0_TIMING_CTRL_8, + cfg->timing.lane[4][3], cfg->timing.lane[0][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13, + DSIPHY_DLN1_TIMING_CTRL_8, + DSIPHY_DLN2_TIMING_CTRL_8, + cfg->timing.lane[1][4], cfg->timing.lane[2][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14, + DSIPHY_DLN3_TIMING_CTRL_8, + DSIPHY_CKLN_TIMING_CTRL_8, + cfg->timing.lane[3][4], cfg->timing.lane[4][4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL27, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL28, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL29, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30, + 0x0110, 0x0110, 0, 0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31, + 0x0110, 0x0110, 0, 0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR, + 0x0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR2, + 0x0); + } + + wmb(); /* make sure phy timings are updated*/ +} + +void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay) +{ + if (!delay) + return; + + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY, + delay->pipe_delay); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2, + delay->pipe_delay2); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY, + delay->pll_delay); +} + +void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset) +{ + u32 reg; + + /* + * if no offset is mentioned then this means we want to clear + * the dynamic refresh ctrl register which is the last step + * of dynamic refresh sequence. + */ + if (!offset) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg &= ~(BIT(0) | BIT(8)); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is cleared */ + return; + } + + if (offset & BIT(DYN_REFRESH_INTF_SEL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(13); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SWI_CTRL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(8); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is triggered */ + } +} + +int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size) +{ + int i, j, count = 0; + + if (!timings || !dst || !size) + return -EINVAL; + + if (size != (DSI_LANE_MAX * DSI_MAX_SETTINGS)) { + pr_err("size mis-match\n"); + return -EINVAL; + } + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + for (j = 0; j < DSI_MAX_SETTINGS; j++) { + dst[count] = timings->lane[i][j]; + count++; + } + } + + return 0; +} diff --git a/techpack/display/msm/dsi/dsi_phy_hw_v3_0.c b/techpack/display/msm/dsi/dsi_phy_hw_v3_0.c new file mode 100644 index 0000000000000000000000000000000000000000..a863827050ad1078f35b157686b72e4b3a2d3467 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_hw_v3_0.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/math64.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include "dsi_hw.h" +#include "dsi_phy_hw.h" +#include "dsi_catalog.h" + +#define DSIPHY_CMN_CLK_CFG0 0x010 +#define DSIPHY_CMN_CLK_CFG1 0x014 +#define DSIPHY_CMN_GLBL_CTRL 0x018 +#define DSIPHY_CMN_RBUF_CTRL 0x01C +#define DSIPHY_CMN_VREG_CTRL 0x020 +#define DSIPHY_CMN_CTRL_0 0x024 +#define DSIPHY_CMN_CTRL_1 0x028 +#define DSIPHY_CMN_CTRL_2 0x02C +#define DSIPHY_CMN_LANE_CFG0 0x030 +#define DSIPHY_CMN_LANE_CFG1 0x034 +#define DSIPHY_CMN_PLL_CNTRL 0x038 +#define DSIPHY_CMN_LANE_CTRL0 0x098 +#define DSIPHY_CMN_LANE_CTRL1 0x09C +#define DSIPHY_CMN_LANE_CTRL2 0x0A0 +#define DSIPHY_CMN_LANE_CTRL3 0x0A4 +#define DSIPHY_CMN_LANE_CTRL4 0x0A8 +#define DSIPHY_CMN_TIMING_CTRL_0 0x0AC +#define DSIPHY_CMN_TIMING_CTRL_1 0x0B0 +#define DSIPHY_CMN_TIMING_CTRL_2 0x0B4 +#define DSIPHY_CMN_TIMING_CTRL_3 0x0B8 +#define DSIPHY_CMN_TIMING_CTRL_4 0x0BC +#define DSIPHY_CMN_TIMING_CTRL_5 0x0C0 +#define DSIPHY_CMN_TIMING_CTRL_6 0x0C4 +#define DSIPHY_CMN_TIMING_CTRL_7 0x0C8 +#define DSIPHY_CMN_TIMING_CTRL_8 0x0CC +#define DSIPHY_CMN_TIMING_CTRL_9 0x0D0 +#define DSIPHY_CMN_TIMING_CTRL_10 0x0D4 +#define DSIPHY_CMN_TIMING_CTRL_11 0x0D8 +#define DSIPHY_CMN_PHY_STATUS 0x0EC +#define DSIPHY_CMN_LANE_STATUS0 0x0F4 +#define DSIPHY_CMN_LANE_STATUS1 0x0F8 + + +/* n = 0..3 for data lanes and n = 4 for clock lane */ +#define DSIPHY_LNX_CFG0(n) (0x200 + (0x80 * (n))) +#define DSIPHY_LNX_CFG1(n) (0x204 + (0x80 * (n))) +#define DSIPHY_LNX_CFG2(n) (0x208 + (0x80 * (n))) +#define DSIPHY_LNX_CFG3(n) (0x20C + (0x80 * (n))) +#define DSIPHY_LNX_TEST_DATAPATH(n) (0x210 + (0x80 * (n))) +#define DSIPHY_LNX_PIN_SWAP(n) (0x214 + (0x80 * (n))) +#define DSIPHY_LNX_HSTX_STR_CTRL(n) (0x218 + (0x80 * (n))) +#define DSIPHY_LNX_OFFSET_TOP_CTRL(n) (0x21C + (0x80 * (n))) +#define DSIPHY_LNX_OFFSET_BOT_CTRL(n) (0x220 + (0x80 * (n))) +#define DSIPHY_LNX_LPTX_STR_CTRL(n) (0x224 + (0x80 * (n))) +#define DSIPHY_LNX_LPRX_CTRL(n) (0x228 + (0x80 * (n))) +#define DSIPHY_LNX_TX_DCTRL(n) (0x22C + (0x80 * (n))) + +/* dynamic refresh control registers */ +#define DSI_DYN_REFRESH_CTRL (0x000) +#define DSI_DYN_REFRESH_PIPE_DELAY (0x004) +#define DSI_DYN_REFRESH_PIPE_DELAY2 (0x008) +#define DSI_DYN_REFRESH_PLL_DELAY (0x00C) +#define DSI_DYN_REFRESH_STATUS (0x010) +#define DSI_DYN_REFRESH_PLL_CTRL0 (0x014) +#define DSI_DYN_REFRESH_PLL_CTRL1 (0x018) +#define DSI_DYN_REFRESH_PLL_CTRL2 (0x01C) +#define DSI_DYN_REFRESH_PLL_CTRL3 (0x020) +#define DSI_DYN_REFRESH_PLL_CTRL4 (0x024) +#define DSI_DYN_REFRESH_PLL_CTRL5 (0x028) +#define DSI_DYN_REFRESH_PLL_CTRL6 (0x02C) +#define DSI_DYN_REFRESH_PLL_CTRL7 (0x030) +#define DSI_DYN_REFRESH_PLL_CTRL8 (0x034) +#define DSI_DYN_REFRESH_PLL_CTRL9 (0x038) +#define DSI_DYN_REFRESH_PLL_CTRL10 (0x03C) +#define DSI_DYN_REFRESH_PLL_CTRL11 (0x040) +#define DSI_DYN_REFRESH_PLL_CTRL12 (0x044) +#define DSI_DYN_REFRESH_PLL_CTRL13 (0x048) +#define DSI_DYN_REFRESH_PLL_CTRL14 (0x04C) +#define DSI_DYN_REFRESH_PLL_CTRL15 (0x050) +#define DSI_DYN_REFRESH_PLL_CTRL16 (0x054) +#define DSI_DYN_REFRESH_PLL_CTRL17 (0x058) +#define DSI_DYN_REFRESH_PLL_CTRL18 (0x05C) +#define DSI_DYN_REFRESH_PLL_CTRL19 (0x060) +#define DSI_DYN_REFRESH_PLL_CTRL20 (0x064) +#define DSI_DYN_REFRESH_PLL_CTRL21 (0x068) +#define DSI_DYN_REFRESH_PLL_CTRL22 (0x06C) +#define DSI_DYN_REFRESH_PLL_CTRL23 (0x070) +#define DSI_DYN_REFRESH_PLL_CTRL24 (0x074) +#define DSI_DYN_REFRESH_PLL_CTRL25 (0x078) +#define DSI_DYN_REFRESH_PLL_CTRL26 (0x07C) +#define DSI_DYN_REFRESH_PLL_CTRL27 (0x080) +#define DSI_DYN_REFRESH_PLL_CTRL28 (0x084) +#define DSI_DYN_REFRESH_PLL_CTRL29 (0x088) +#define DSI_DYN_REFRESH_PLL_CTRL30 (0x08C) +#define DSI_DYN_REFRESH_PLL_CTRL31 (0x090) +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR (0x094) +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2 (0x098) + +/** + * regulator_enable() - enable regulators for DSI PHY + * @phy: Pointer to DSI PHY hardware object. + * @reg_cfg: Regulator configuration for all DSI lanes. + */ +void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *reg_cfg) +{ + DSI_PHY_DBG(phy, "Phy regulators enabled\n"); + /* Nothing to be done for DSI PHY regulator enable */ +} + +/** + * regulator_disable() - disable regulators + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v3_0_regulator_disable(struct dsi_phy_hw *phy) +{ + DSI_PHY_DBG(phy, "Phy regulators disabled\n"); + /* Nothing to be done for DSI PHY regulator disable */ +} + +void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy) +{ + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00); + /* ensure that the FIFO is off */ + wmb(); + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x1); + /* ensure that the FIFO is toggled back on */ + wmb(); +} + +static int dsi_phy_hw_v3_0_is_pll_on(struct dsi_phy_hw *phy) +{ + u32 data = 0; + + data = DSI_R32(phy, DSIPHY_CMN_PLL_CNTRL); + mb(); /*make sure read happened */ + return (data & BIT(0)); +} + +static void dsi_phy_hw_v3_0_config_lpcdrx(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool enable) +{ + int phy_lane_0 = dsi_phy_conv_logical_to_phy_lane(&cfg->lane_map, + DSI_LOGICAL_LANE_0); + /* + * LPRX and CDRX need to enabled only for physical data lane + * corresponding to the logical data lane 0 + */ + + if (enable) + DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(phy_lane_0), + cfg->strength.lane[phy_lane_0][1]); + else + DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(phy_lane_0), 0); +} + +static void dsi_phy_hw_v3_0_lane_swap_config(struct dsi_phy_hw *phy, + struct dsi_lane_map *lane_map) +{ + DSI_W32(phy, DSIPHY_CMN_LANE_CFG0, + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4))); + DSI_W32(phy, DSIPHY_CMN_LANE_CFG1, + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 4))); +} + +static void dsi_phy_hw_v3_0_lane_settings(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + int i; + u8 tx_dctrl[] = {0x00, 0x00, 0x00, 0x04, 0x01}; + + /* Strength ctrl settings */ + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + DSI_W32(phy, DSIPHY_LNX_LPTX_STR_CTRL(i), + cfg->strength.lane[i][0]); + /* + * Disable LPRX and CDRX for all lanes. And later on, it will + * be only enabled for the physical data lane corresponding + * to the logical data lane 0 + */ + DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(i), 0); + DSI_W32(phy, DSIPHY_LNX_PIN_SWAP(i), 0x0); + DSI_W32(phy, DSIPHY_LNX_HSTX_STR_CTRL(i), 0x88); + } + dsi_phy_hw_v3_0_config_lpcdrx(phy, cfg, true); + + /* other settings */ + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + DSI_W32(phy, DSIPHY_LNX_CFG0(i), cfg->lanecfg.lane[i][0]); + DSI_W32(phy, DSIPHY_LNX_CFG1(i), cfg->lanecfg.lane[i][1]); + DSI_W32(phy, DSIPHY_LNX_CFG2(i), cfg->lanecfg.lane[i][2]); + DSI_W32(phy, DSIPHY_LNX_CFG3(i), cfg->lanecfg.lane[i][3]); + DSI_W32(phy, DSIPHY_LNX_OFFSET_TOP_CTRL(i), 0x0); + DSI_W32(phy, DSIPHY_LNX_OFFSET_BOT_CTRL(i), 0x0); + DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]); + } +} + +void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable) +{ + u32 reg; + + DSI_PHY_DBG(phy, "enable=%s\n", enable ? "true" : "false"); + + /* + * DSI PHY lane clamps, also referred to as PHY FreezeIO is + * enalbed by default as part of the initialization sequnce. + * This would get triggered anytime the chip FreezeIO is asserted. + */ + if (enable) + return; + + /* + * Toggle BIT 0 to exlplictly release PHY freeze I/0 to disable + * the clamps. + */ + reg = DSI_R32(phy, DSIPHY_LNX_TX_DCTRL(3)); + DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg | BIT(0)); + wmb(); /* Ensure that the freezeio bit is toggled */ + DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg & ~BIT(0)); + wmb(); /* Ensure that the freezeio bit is toggled */ +} + +/** + * enable() - Enable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +void dsi_phy_hw_v3_0_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + int rc = 0; + u32 status; + u32 const delay_us = 5; + u32 const timeout_us = 1000; + struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; + u32 data; + + if (dsi_phy_hw_v3_0_is_pll_on(phy)) + DSI_PHY_WARN(phy, "PLL turned on before configuring PHY\n"); + + /* wait for REFGEN READY */ + rc = readl_poll_timeout_atomic(phy->base + DSIPHY_CMN_PHY_STATUS, + status, (status & BIT(0)), delay_us, timeout_us); + if (rc) { + DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n"); + return; + } + + /* de-assert digital and pll power down */ + data = BIT(6) | BIT(5); + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + + /* Assert PLL core reset */ + DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00); + + /* turn off resync FIFO */ + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00); + + /* Select MS1 byte-clk */ + DSI_W32(phy, DSIPHY_CMN_GLBL_CTRL, 0x10); + + /* Enable LDO */ + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL, 0x59); + + /* Configure PHY lane swap */ + dsi_phy_hw_v3_0_lane_swap_config(phy, &cfg->lane_map); + + /* DSI PHY timings */ + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v3[0]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_1, timing->lane_v3[1]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_2, timing->lane_v3[2]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_3, timing->lane_v3[3]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v3[4]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v3[5]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v3[6]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v3[7]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v3[8]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v3[9]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v3[10]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v3[11]); + + /* Remove power down from all blocks */ + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f); + + /*power up lanes */ + data = DSI_R32(phy, DSIPHY_CMN_CTRL_0); + /* TODO: only power up lanes that are used */ + data |= 0x1F; + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x1F); + + /* Select full-rate mode */ + DSI_W32(phy, DSIPHY_CMN_CTRL_2, 0x40); + + switch (cfg->pll_source) { + case DSI_PLL_SOURCE_STANDALONE: + case DSI_PLL_SOURCE_NATIVE: + data = 0x0; /* internal PLL */ + break; + case DSI_PLL_SOURCE_NON_NATIVE: + data = 0x1; /* external PLL */ + break; + default: + break; + } + DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */ + + /* DSI lane settings */ + dsi_phy_hw_v3_0_lane_settings(phy, cfg); + + DSI_PHY_DBG(phy, "Phy enabled\n"); +} + +/** + * disable() - Disable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v3_0_disable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + u32 data = 0; + + if (dsi_phy_hw_v3_0_is_pll_on(phy)) + DSI_PHY_WARN(phy, "Turning OFF PHY while PLL is on\n"); + + dsi_phy_hw_v3_0_config_lpcdrx(phy, cfg, false); + + data = DSI_R32(phy, DSIPHY_CMN_CTRL_0); + /* disable all lanes */ + data &= ~0x1F; + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0); + + /* Turn off all PHY blocks */ + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x00); + /* make sure phy is turned off */ + wmb(); + DSI_PHY_DBG(phy, "Phy disabled\n"); +} + +int dsi_phy_hw_v3_0_wait_for_lane_idle( + struct dsi_phy_hw *phy, u32 lanes) +{ + int rc = 0, val = 0; + u32 stop_state_mask = 0; + u32 const sleep_us = 10; + u32 const timeout_us = 100; + + stop_state_mask = BIT(4); /* clock lane */ + if (lanes & DSI_DATA_LANE_0) + stop_state_mask |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + stop_state_mask |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + stop_state_mask |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + stop_state_mask |= BIT(3); + + DSI_PHY_DBG(phy, "polling for lanes to be in stop state, mask=0x%08x\n", + stop_state_mask); + rc = readl_poll_timeout(phy->base + DSIPHY_CMN_LANE_STATUS1, val, + ((val & stop_state_mask) == stop_state_mask), + sleep_us, timeout_us); + if (rc) { + DSI_PHY_ERR(phy, "lanes not in stop state, LANE_STATUS=0x%08x\n", + val); + return rc; + } + + return 0; +} + +void dsi_phy_hw_v3_0_ulps_request(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes) +{ + u32 reg = 0; + + if (lanes & DSI_CLOCK_LANE) + reg = BIT(4); + if (lanes & DSI_DATA_LANE_0) + reg |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + reg |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + reg |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + reg |= BIT(3); + + /* + * ULPS entry request. Wait for short time to make sure + * that the lanes enter ULPS. Recommended as per HPG. + */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg); + usleep_range(100, 110); + + /* disable LPRX and CDRX */ + dsi_phy_hw_v3_0_config_lpcdrx(phy, cfg, false); + /* disable lane LDOs */ + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL, 0x19); + DSI_PHY_DBG(phy, "ULPS requested for lanes 0x%x\n", lanes); +} + +int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy) +{ + int ret = 0, loop = 10, u_dly = 200; + u32 ln_status = 0; + + while ((ln_status != 0x1f) && loop) { + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0x1f); + wmb(); /* ensure register is committed */ + loop--; + udelay(u_dly); + ln_status = DSI_R32(phy, DSIPHY_CMN_LANE_STATUS1); + DSI_PHY_DBG(phy, "trial no: %d\n", loop); + } + + if (!loop) + DSI_PHY_DBG(phy, "could not reset phy lanes\n"); + + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0x0); + wmb(); /* ensure register is committed */ + + return ret; +} + +void dsi_phy_hw_v3_0_ulps_exit(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes) +{ + u32 reg = 0; + + if (lanes & DSI_CLOCK_LANE) + reg = BIT(4); + if (lanes & DSI_DATA_LANE_0) + reg |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + reg |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + reg |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + reg |= BIT(3); + + /* enable lane LDOs */ + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL, 0x59); + /* enable LPRX and CDRX */ + dsi_phy_hw_v3_0_config_lpcdrx(phy, cfg, true); + + /* ULPS exit request */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL2, reg); + usleep_range(1000, 1010); + + /* Clear ULPS request flags on all lanes */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, 0); + /* Clear ULPS exit flags on all lanes */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL2, 0); + + /* + * Sometimes when exiting ULPS, it is possible that some DSI + * lanes are not in the stop state which could lead to DSI + * commands not going through. To avoid this, force the lanes + * to be in stop state. + */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, reg); + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0); + usleep_range(100, 110); +} + +u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy) +{ + u32 lanes = 0; + + lanes = DSI_R32(phy, DSIPHY_CMN_LANE_STATUS0); + DSI_PHY_DBG(phy, "lanes in ulps = 0x%x\n", lanes); + return lanes; +} + +bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes) +{ + if (lanes & ulps_lanes) + return false; + + return true; +} + +int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg, + u32 *timing_val, u32 size) +{ + int i = 0; + + if (size != DSI_PHY_TIMING_V3_SIZE) { + DSI_ERR("Unexpected timing array size %d\n", size); + return -EINVAL; + } + + for (i = 0; i < size; i++) + timing_cfg->lane_v3[i] = timing_val[i]; + return 0; +} + +void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master) +{ + u32 reg; + + if (is_master) { + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_CMN_GLBL_CTRL, DSIPHY_CMN_VREG_CTRL, + 0x10, 0x59); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10, + DSIPHY_CMN_TIMING_CTRL_0, DSIPHY_CMN_TIMING_CTRL_1, + cfg->timing.lane_v3[0], cfg->timing.lane_v3[1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11, + DSIPHY_CMN_TIMING_CTRL_2, DSIPHY_CMN_TIMING_CTRL_3, + cfg->timing.lane_v3[2], cfg->timing.lane_v3[3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12, + DSIPHY_CMN_TIMING_CTRL_4, DSIPHY_CMN_TIMING_CTRL_5, + cfg->timing.lane_v3[4], cfg->timing.lane_v3[5]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13, + DSIPHY_CMN_TIMING_CTRL_6, DSIPHY_CMN_TIMING_CTRL_7, + cfg->timing.lane_v3[6], cfg->timing.lane_v3[7]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14, + DSIPHY_CMN_TIMING_CTRL_8, DSIPHY_CMN_TIMING_CTRL_9, + cfg->timing.lane_v3[8], cfg->timing.lane_v3[9]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15, + DSIPHY_CMN_TIMING_CTRL_10, DSIPHY_CMN_TIMING_CTRL_11, + cfg->timing.lane_v3[10], cfg->timing.lane_v3[11]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16, + DSIPHY_CMN_CTRL_0, DSIPHY_CMN_LANE_CTRL0, + 0x7f, 0x1f); + } else { + reg = DSI_R32(phy, DSIPHY_CMN_CLK_CFG0); + reg &= ~BIT(5); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0, + DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_PLL_CNTRL, + reg, 0x0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1, + DSIPHY_CMN_RBUF_CTRL, DSIPHY_CMN_GLBL_CTRL, + 0x0, 0x10); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2, + DSIPHY_CMN_VREG_CTRL, DSIPHY_CMN_TIMING_CTRL_0, + 0x59, cfg->timing.lane_v3[0]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3, + DSIPHY_CMN_TIMING_CTRL_1, DSIPHY_CMN_TIMING_CTRL_2, + cfg->timing.lane_v3[1], cfg->timing.lane_v3[2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4, + DSIPHY_CMN_TIMING_CTRL_3, DSIPHY_CMN_TIMING_CTRL_4, + cfg->timing.lane_v3[3], cfg->timing.lane_v3[4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5, + DSIPHY_CMN_TIMING_CTRL_5, DSIPHY_CMN_TIMING_CTRL_6, + cfg->timing.lane_v3[5], cfg->timing.lane_v3[6]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6, + DSIPHY_CMN_TIMING_CTRL_7, DSIPHY_CMN_TIMING_CTRL_8, + cfg->timing.lane_v3[7], cfg->timing.lane_v3[8]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7, + DSIPHY_CMN_TIMING_CTRL_9, DSIPHY_CMN_TIMING_CTRL_10, + cfg->timing.lane_v3[9], cfg->timing.lane_v3[10]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8, + DSIPHY_CMN_TIMING_CTRL_11, DSIPHY_CMN_CTRL_0, + cfg->timing.lane_v3[11], 0x7f); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_2, + 0x1f, 0x40); + /* + * fill with dummy register writes since controller will blindly + * send these values to DSI PHY. + */ + reg = DSI_DYN_REFRESH_PLL_CTRL11; + while (reg <= DSI_DYN_REFRESH_PLL_CTRL29) { + DSI_DYN_REF_REG_W(phy->dyn_pll_base, reg, + DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_0, + 0x1f, 0x7f); + reg += 0x4; + } + + DSI_GEN_W32(phy->dyn_pll_base, + DSI_DYN_REFRESH_PLL_UPPER_ADDR, 0); + DSI_GEN_W32(phy->dyn_pll_base, + DSI_DYN_REFRESH_PLL_UPPER_ADDR2, 0); + } + + wmb(); /* make sure all registers are updated */ +} + +void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay) +{ + if (!delay) + return; + + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY, + delay->pipe_delay); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2, + delay->pipe_delay2); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY, + delay->pll_delay); +} + +void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset) +{ + u32 reg; + + /* + * if no offset is mentioned then this means we want to clear + * the dynamic refresh ctrl register which is the last step + * of dynamic refresh sequence. + */ + if (!offset) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg &= ~(BIT(0) | BIT(8)); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is cleared */ + return; + } + + if (offset & BIT(DYN_REFRESH_INTF_SEL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(13); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SYNC_MODE)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(16); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SWI_CTRL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(8); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is triggered */ + } +} + +int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size) +{ + int i; + + if (!timings || !dst || !size) + return -EINVAL; + + if (size != DSI_PHY_TIMING_V3_SIZE) { + DSI_ERR("size mis-match\n"); + return -EINVAL; + } + + for (i = 0; i < size; i++) + dst[i] = timings->lane_v3[i]; + + return 0; +} diff --git a/techpack/display/msm/dsi/dsi_phy_hw_v4_0.c b/techpack/display/msm/dsi/dsi_phy_hw_v4_0.c new file mode 100644 index 0000000000000000000000000000000000000000..220e9de5e3c4fe9a4da60b24bcdfcc152ebedef9 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_hw_v4_0.c @@ -0,0 +1,828 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/math64.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include "dsi_hw.h" +#include "dsi_phy_hw.h" +#include "dsi_catalog.h" + +#define DSIPHY_CMN_REVISION_ID0 0x000 +#define DSIPHY_CMN_REVISION_ID1 0x004 +#define DSIPHY_CMN_REVISION_ID2 0x008 +#define DSIPHY_CMN_REVISION_ID3 0x00C +#define DSIPHY_CMN_CLK_CFG0 0x010 +#define DSIPHY_CMN_CLK_CFG1 0x014 +#define DSIPHY_CMN_GLBL_CTRL 0x018 +#define DSIPHY_CMN_RBUF_CTRL 0x01C +#define DSIPHY_CMN_VREG_CTRL_0 0x020 +#define DSIPHY_CMN_CTRL_0 0x024 +#define DSIPHY_CMN_CTRL_1 0x028 +#define DSIPHY_CMN_CTRL_2 0x02C +#define DSIPHY_CMN_CTRL_3 0x030 +#define DSIPHY_CMN_LANE_CFG0 0x034 +#define DSIPHY_CMN_LANE_CFG1 0x038 +#define DSIPHY_CMN_PLL_CNTRL 0x03C +#define DSIPHY_CMN_DPHY_SOT 0x040 +#define DSIPHY_CMN_LANE_CTRL0 0x0A0 +#define DSIPHY_CMN_LANE_CTRL1 0x0A4 +#define DSIPHY_CMN_LANE_CTRL2 0x0A8 +#define DSIPHY_CMN_LANE_CTRL3 0x0AC +#define DSIPHY_CMN_LANE_CTRL4 0x0B0 +#define DSIPHY_CMN_TIMING_CTRL_0 0x0B4 +#define DSIPHY_CMN_TIMING_CTRL_1 0x0B8 +#define DSIPHY_CMN_TIMING_CTRL_2 0x0Bc +#define DSIPHY_CMN_TIMING_CTRL_3 0x0C0 +#define DSIPHY_CMN_TIMING_CTRL_4 0x0C4 +#define DSIPHY_CMN_TIMING_CTRL_5 0x0C8 +#define DSIPHY_CMN_TIMING_CTRL_6 0x0CC +#define DSIPHY_CMN_TIMING_CTRL_7 0x0D0 +#define DSIPHY_CMN_TIMING_CTRL_8 0x0D4 +#define DSIPHY_CMN_TIMING_CTRL_9 0x0D8 +#define DSIPHY_CMN_TIMING_CTRL_10 0x0DC +#define DSIPHY_CMN_TIMING_CTRL_11 0x0E0 +#define DSIPHY_CMN_TIMING_CTRL_12 0x0E4 +#define DSIPHY_CMN_TIMING_CTRL_13 0x0E8 +#define DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0 0x0EC +#define DSIPHY_CMN_GLBL_HSTX_STR_CTRL_1 0x0F0 +#define DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL 0x0F4 +#define DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL 0x0F8 +#define DSIPHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL 0x0FC +#define DSIPHY_CMN_GLBL_LPTX_STR_CTRL 0x100 +#define DSIPHY_CMN_GLBL_PEMPH_CTRL_0 0x104 +#define DSIPHY_CMN_GLBL_PEMPH_CTRL_1 0x108 +#define DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL 0x10C +#define DSIPHY_CMN_VREG_CTRL_1 0x110 +#define DSIPHY_CMN_CTRL_4 0x114 +#define DSIPHY_CMN_PHY_STATUS 0x140 +#define DSIPHY_CMN_LANE_STATUS0 0x148 +#define DSIPHY_CMN_LANE_STATUS1 0x14C + +/* n = 0..3 for data lanes and n = 4 for clock lane */ +#define DSIPHY_LNX_CFG0(n) (0x200 + (0x80 * (n))) +#define DSIPHY_LNX_CFG1(n) (0x204 + (0x80 * (n))) +#define DSIPHY_LNX_CFG2(n) (0x208 + (0x80 * (n))) +#define DSIPHY_LNX_TEST_DATAPATH(n) (0x20C + (0x80 * (n))) +#define DSIPHY_LNX_PIN_SWAP(n) (0x210 + (0x80 * (n))) +#define DSIPHY_LNX_LPRX_CTRL(n) (0x214 + (0x80 * (n))) +#define DSIPHY_LNX_TX_DCTRL(n) (0x218 + (0x80 * (n))) + +/* dynamic refresh control registers */ +#define DSI_DYN_REFRESH_CTRL (0x000) +#define DSI_DYN_REFRESH_PIPE_DELAY (0x004) +#define DSI_DYN_REFRESH_PIPE_DELAY2 (0x008) +#define DSI_DYN_REFRESH_PLL_DELAY (0x00C) +#define DSI_DYN_REFRESH_STATUS (0x010) +#define DSI_DYN_REFRESH_PLL_CTRL0 (0x014) +#define DSI_DYN_REFRESH_PLL_CTRL1 (0x018) +#define DSI_DYN_REFRESH_PLL_CTRL2 (0x01C) +#define DSI_DYN_REFRESH_PLL_CTRL3 (0x020) +#define DSI_DYN_REFRESH_PLL_CTRL4 (0x024) +#define DSI_DYN_REFRESH_PLL_CTRL5 (0x028) +#define DSI_DYN_REFRESH_PLL_CTRL6 (0x02C) +#define DSI_DYN_REFRESH_PLL_CTRL7 (0x030) +#define DSI_DYN_REFRESH_PLL_CTRL8 (0x034) +#define DSI_DYN_REFRESH_PLL_CTRL9 (0x038) +#define DSI_DYN_REFRESH_PLL_CTRL10 (0x03C) +#define DSI_DYN_REFRESH_PLL_CTRL11 (0x040) +#define DSI_DYN_REFRESH_PLL_CTRL12 (0x044) +#define DSI_DYN_REFRESH_PLL_CTRL13 (0x048) +#define DSI_DYN_REFRESH_PLL_CTRL14 (0x04C) +#define DSI_DYN_REFRESH_PLL_CTRL15 (0x050) +#define DSI_DYN_REFRESH_PLL_CTRL16 (0x054) +#define DSI_DYN_REFRESH_PLL_CTRL17 (0x058) +#define DSI_DYN_REFRESH_PLL_CTRL18 (0x05C) +#define DSI_DYN_REFRESH_PLL_CTRL19 (0x060) +#define DSI_DYN_REFRESH_PLL_CTRL20 (0x064) +#define DSI_DYN_REFRESH_PLL_CTRL21 (0x068) +#define DSI_DYN_REFRESH_PLL_CTRL22 (0x06C) +#define DSI_DYN_REFRESH_PLL_CTRL23 (0x070) +#define DSI_DYN_REFRESH_PLL_CTRL24 (0x074) +#define DSI_DYN_REFRESH_PLL_CTRL25 (0x078) +#define DSI_DYN_REFRESH_PLL_CTRL26 (0x07C) +#define DSI_DYN_REFRESH_PLL_CTRL27 (0x080) +#define DSI_DYN_REFRESH_PLL_CTRL28 (0x084) +#define DSI_DYN_REFRESH_PLL_CTRL29 (0x088) +#define DSI_DYN_REFRESH_PLL_CTRL30 (0x08C) +#define DSI_DYN_REFRESH_PLL_CTRL31 (0x090) +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR (0x094) +#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2 (0x098) + +static int dsi_phy_hw_v4_0_is_pll_on(struct dsi_phy_hw *phy) +{ + u32 data = 0; + + data = DSI_R32(phy, DSIPHY_CMN_PLL_CNTRL); + mb(); /*make sure read happened */ + return (data & BIT(0)); +} + +static void dsi_phy_hw_v4_0_config_lpcdrx(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool enable) +{ + int phy_lane_0 = dsi_phy_conv_logical_to_phy_lane(&cfg->lane_map, + DSI_LOGICAL_LANE_0); + /* + * LPRX and CDRX need to enabled only for physical data lane + * corresponding to the logical data lane 0 + */ + + if (enable) + DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(phy_lane_0), + cfg->strength.lane[phy_lane_0][1]); + else + DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(phy_lane_0), 0); +} + +static void dsi_phy_hw_v4_0_lane_swap_config(struct dsi_phy_hw *phy, + struct dsi_lane_map *lane_map) +{ + DSI_W32(phy, DSIPHY_CMN_LANE_CFG0, + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4))); + DSI_W32(phy, DSIPHY_CMN_LANE_CFG1, + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] | + (lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 4))); +} + +static void dsi_phy_hw_v4_0_lane_settings(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + int i; + u8 tx_dctrl_v4[] = {0x00, 0x00, 0x00, 0x04, 0x01}; + u8 tx_dctrl_v4_1[] = {0x40, 0x40, 0x40, 0x46, 0x41}; + u8 *tx_dctrl; + + if (phy->version == DSI_PHY_VERSION_4_1) + tx_dctrl = &tx_dctrl_v4_1[0]; + else + tx_dctrl = &tx_dctrl_v4[0]; + + /* Strength ctrl settings */ + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + /* + * Disable LPRX and CDRX for all lanes. And later on, it will + * be only enabled for the physical data lane corresponding + * to the logical data lane 0 + */ + DSI_W32(phy, DSIPHY_LNX_LPRX_CTRL(i), 0); + DSI_W32(phy, DSIPHY_LNX_PIN_SWAP(i), 0x0); + } + dsi_phy_hw_v4_0_config_lpcdrx(phy, cfg, true); + + /* other settings */ + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + DSI_W32(phy, DSIPHY_LNX_CFG0(i), cfg->lanecfg.lane[i][0]); + DSI_W32(phy, DSIPHY_LNX_CFG1(i), cfg->lanecfg.lane[i][1]); + DSI_W32(phy, DSIPHY_LNX_CFG2(i), cfg->lanecfg.lane[i][2]); + DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]); + } +} + +void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy, + struct dsi_phy_per_lane_cfgs *timing) +{ + /* Commit DSI PHY timings */ + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v4[0]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_1, timing->lane_v4[1]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_2, timing->lane_v4[2]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_3, timing->lane_v4[3]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v4[4]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v4[5]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v4[6]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v4[7]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v4[8]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v4[9]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v4[10]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v4[11]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_12, timing->lane_v4[12]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_13, timing->lane_v4[13]); +} + +/** + * cphy_enable() - Enable CPHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +static void dsi_phy_hw_cphy_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; + u32 data; + u32 minor_ver = 0; + /* For C-PHY, no low power settings for lower clk rate */ + u32 vreg_ctrl_0 = 0x51; + u32 glbl_str_swi_cal_sel_ctrl = 0; + u32 glbl_hstx_str_ctrl_0 = 0; + u32 glbl_rescode_top_ctrl = 0; + u32 glbl_rescode_bot_ctrl = 0; + + if (phy->version == DSI_PHY_VERSION_4_1) { + glbl_rescode_top_ctrl = 0x00; + glbl_rescode_bot_ctrl = 0x3C; + glbl_str_swi_cal_sel_ctrl = 0x00; + glbl_hstx_str_ctrl_0 = 0x88; + } else { + glbl_str_swi_cal_sel_ctrl = 0x03; + glbl_hstx_str_ctrl_0 = 0x66; + glbl_rescode_top_ctrl = 0x03; + glbl_rescode_bot_ctrl = 0x3c; + } + + /* de-assert digital and pll power down */ + data = BIT(6) | BIT(5); + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + + /* Assert PLL core reset */ + DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00); + + /* turn off resync FIFO */ + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00); + + /* program CMN_CTRL_4 for minor_ver 2 chipsets*/ + minor_ver = DSI_R32(phy, DSIPHY_CMN_REVISION_ID0); + minor_ver = minor_ver & (0xf0); + if (minor_ver == 0x20) + DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x04); + + /* Configure PHY lane swap */ + dsi_phy_hw_v4_0_lane_swap_config(phy, &cfg->lane_map); + + DSI_W32(phy, DSIPHY_CMN_GLBL_CTRL, BIT(6)); + + /* Enable LDO */ + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0); + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x55); + DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, + glbl_str_swi_cal_sel_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0); + DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x11); + DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_1, 0x01); + DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, + glbl_rescode_top_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, + glbl_rescode_bot_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55); + + /* Remove power down from all blocks */ + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f); + + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x17); + + switch (cfg->pll_source) { + case DSI_PLL_SOURCE_STANDALONE: + case DSI_PLL_SOURCE_NATIVE: + data = 0x0; /* internal PLL */ + break; + case DSI_PLL_SOURCE_NON_NATIVE: + data = 0x1; /* external PLL */ + break; + default: + break; + } + DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */ + + /* DSI PHY timings */ + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_0, timing->lane_v4[0]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_4, timing->lane_v4[4]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_5, timing->lane_v4[5]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_6, timing->lane_v4[6]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_7, timing->lane_v4[7]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_8, timing->lane_v4[8]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_9, timing->lane_v4[9]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_10, timing->lane_v4[10]); + DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_11, timing->lane_v4[11]); + + /* DSI lane settings */ + dsi_phy_hw_v4_0_lane_settings(phy, cfg); + + DSI_PHY_DBG(phy, "C-Phy enabled\n"); +} + +/** + * dphy_enable() - Enable DPHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + struct dsi_phy_per_lane_cfgs *timing = &cfg->timing; + u32 data; + u32 minor_ver = 0; + bool less_than_1500_mhz = false; + u32 vreg_ctrl_0 = 0; + u32 glbl_str_swi_cal_sel_ctrl = 0; + u32 glbl_hstx_str_ctrl_0 = 0; + u32 glbl_rescode_top_ctrl = 0; + u32 glbl_rescode_bot_ctrl = 0; + + /* Alter PHY configurations if data rate less than 1.5GHZ*/ + if (cfg->bit_clk_rate_hz <= 1500000000) + less_than_1500_mhz = true; + + if (phy->version == DSI_PHY_VERSION_4_1) { + vreg_ctrl_0 = less_than_1500_mhz ? 0x53 : 0x52; + glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x00; + glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x39 : 0x3c; + glbl_str_swi_cal_sel_ctrl = 0x00; + glbl_hstx_str_ctrl_0 = 0x88; + } else { + vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59; + glbl_str_swi_cal_sel_ctrl = less_than_1500_mhz ? 0x03 : 0x00; + glbl_hstx_str_ctrl_0 = less_than_1500_mhz ? 0x66 : 0x88; + glbl_rescode_top_ctrl = 0x03; + glbl_rescode_bot_ctrl = 0x3c; + } + + /* de-assert digital and pll power down */ + data = BIT(6) | BIT(5); + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + + /* Assert PLL core reset */ + DSI_W32(phy, DSIPHY_CMN_PLL_CNTRL, 0x00); + + /* turn off resync FIFO */ + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00); + + /* program CMN_CTRL_4 for minor_ver 2 chipsets*/ + minor_ver = DSI_R32(phy, DSIPHY_CMN_REVISION_ID0); + minor_ver = minor_ver & (0xf0); + if (minor_ver == 0x20) + DSI_W32(phy, DSIPHY_CMN_CTRL_4, 0x04); + + /* Configure PHY lane swap */ + dsi_phy_hw_v4_0_lane_swap_config(phy, &cfg->lane_map); + + /* Enable LDO */ + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0); + DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x5c); + + DSI_W32(phy, DSIPHY_CMN_CTRL_3, 0x00); + DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, + glbl_str_swi_cal_sel_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, glbl_hstx_str_ctrl_0); + DSI_W32(phy, DSIPHY_CMN_GLBL_PEMPH_CTRL_0, 0x00); + DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, + glbl_rescode_top_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, + glbl_rescode_bot_ctrl); + DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55); + + /* Remove power down from all blocks */ + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f); + + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0x1F); + + /* Select full-rate mode */ + DSI_W32(phy, DSIPHY_CMN_CTRL_2, 0x40); + + switch (cfg->pll_source) { + case DSI_PLL_SOURCE_STANDALONE: + case DSI_PLL_SOURCE_NATIVE: + data = 0x0; /* internal PLL */ + break; + case DSI_PLL_SOURCE_NON_NATIVE: + data = 0x1; /* external PLL */ + break; + default: + break; + } + DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, (data << 2)); /* set PLL src */ + + /* DSI PHY timings */ + dsi_phy_hw_v4_0_commit_phy_timing(phy, timing); + + /* DSI lane settings */ + dsi_phy_hw_v4_0_lane_settings(phy, cfg); + + DSI_PHY_DBG(phy, "D-Phy enabled\n"); +} + +/** + * enable() - Enable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + * @cfg: Per lane configurations for timing, strength and lane + * configurations. + */ +void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + int rc = 0; + u32 status; + u32 const delay_us = 5; + u32 const timeout_us = 1000; + + if (dsi_phy_hw_v4_0_is_pll_on(phy)) + pr_warn("PLL turned on before configuring PHY\n"); + + /* wait for REFGEN READY */ + rc = readl_poll_timeout_atomic(phy->base + DSIPHY_CMN_PHY_STATUS, + status, (status & BIT(0)), delay_us, timeout_us); + if (rc) { + DSI_PHY_ERR(phy, "Ref gen not ready. Aborting\n"); + return; + } + + if (cfg->phy_type == DSI_PHY_TYPE_CPHY) + dsi_phy_hw_cphy_enable(phy, cfg); + else /* Default PHY type is DPHY */ + dsi_phy_hw_dphy_enable(phy, cfg); + +} + +/** + * disable() - Disable PHY hardware + * @phy: Pointer to DSI PHY hardware object. + */ +void dsi_phy_hw_v4_0_disable(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg) +{ + u32 data = 0; + + if (dsi_phy_hw_v4_0_is_pll_on(phy)) + DSI_PHY_WARN(phy, "Turning OFF PHY while PLL is on\n"); + + dsi_phy_hw_v4_0_config_lpcdrx(phy, cfg, false); + + data = DSI_R32(phy, DSIPHY_CMN_CTRL_0); + /* disable all lanes */ + data &= ~0x1F; + DSI_W32(phy, DSIPHY_CMN_CTRL_0, data); + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, 0); + + /* Turn off all PHY blocks */ + DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x00); + /* make sure phy is turned off */ + wmb(); + DSI_PHY_DBG(phy, "Phy disabled\n"); +} + +void dsi_phy_hw_v4_0_toggle_resync_fifo(struct dsi_phy_hw *phy) +{ + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x00); + /* ensure that the FIFO is off */ + wmb(); + DSI_W32(phy, DSIPHY_CMN_RBUF_CTRL, 0x1); + /* ensure that the FIFO is toggled back on */ + wmb(); +} + +void dsi_phy_hw_v4_0_reset_clk_en_sel(struct dsi_phy_hw *phy) +{ + u32 data = 0; + + /*Turning off CLK_EN_SEL after retime buffer sync */ + data = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1); + data &= ~BIT(4); + DSI_W32(phy, DSIPHY_CMN_CLK_CFG1, data); + /* ensure that clk_en_sel bit is turned off */ + wmb(); +} + +int dsi_phy_hw_v4_0_wait_for_lane_idle( + struct dsi_phy_hw *phy, u32 lanes) +{ + int rc = 0, val = 0; + u32 stop_state_mask = 0; + u32 const sleep_us = 10; + u32 const timeout_us = 100; + + stop_state_mask = BIT(4); /* clock lane */ + if (lanes & DSI_DATA_LANE_0) + stop_state_mask |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + stop_state_mask |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + stop_state_mask |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + stop_state_mask |= BIT(3); + + DSI_PHY_DBG(phy, "polling for lanes to be in stop state, mask=0x%08x\n", + stop_state_mask); + rc = readl_poll_timeout(phy->base + DSIPHY_CMN_LANE_STATUS1, val, + ((val & stop_state_mask) == stop_state_mask), + sleep_us, timeout_us); + if (rc) { + DSI_PHY_ERR(phy, "lanes not in stop state, LANE_STATUS=0x%08x\n", + val); + return rc; + } + + return 0; +} + +void dsi_phy_hw_v4_0_ulps_request(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes) +{ + u32 reg = 0; + + if (lanes & DSI_CLOCK_LANE) + reg = BIT(4); + if (lanes & DSI_DATA_LANE_0) + reg |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + reg |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + reg |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + reg |= BIT(3); + + if (cfg->force_clk_lane_hs) + reg |= BIT(5) | BIT(6); + + /* + * ULPS entry request. Wait for short time to make sure + * that the lanes enter ULPS. Recommended as per HPG. + */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg); + usleep_range(100, 110); + + /* disable LPRX and CDRX */ + dsi_phy_hw_v4_0_config_lpcdrx(phy, cfg, false); + + DSI_PHY_DBG(phy, "ULPS requested for lanes 0x%x\n", lanes); +} + +int dsi_phy_hw_v4_0_lane_reset(struct dsi_phy_hw *phy) +{ + int ret = 0, loop = 10, u_dly = 200; + u32 ln_status = 0; + + while ((ln_status != 0x1f) && loop) { + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0x1f); + wmb(); /* ensure register is committed */ + loop--; + udelay(u_dly); + ln_status = DSI_R32(phy, DSIPHY_CMN_LANE_STATUS1); + DSI_PHY_DBG(phy, "trial no: %d\n", loop); + } + + if (!loop) + DSI_PHY_DBG(phy, "could not reset phy lanes\n"); + + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0x0); + wmb(); /* ensure register is committed */ + + return ret; +} + +void dsi_phy_hw_v4_0_ulps_exit(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, u32 lanes) +{ + u32 reg = 0; + + if (lanes & DSI_CLOCK_LANE) + reg = BIT(4); + if (lanes & DSI_DATA_LANE_0) + reg |= BIT(0); + if (lanes & DSI_DATA_LANE_1) + reg |= BIT(1); + if (lanes & DSI_DATA_LANE_2) + reg |= BIT(2); + if (lanes & DSI_DATA_LANE_3) + reg |= BIT(3); + + /* enable LPRX and CDRX */ + dsi_phy_hw_v4_0_config_lpcdrx(phy, cfg, true); + + /* ULPS exit request */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL2, reg); + usleep_range(1000, 1010); + + /* Clear ULPS request flags on all lanes */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, 0); + /* Clear ULPS exit flags on all lanes */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL2, 0); + + /* + * Sometimes when exiting ULPS, it is possible that some DSI + * lanes are not in the stop state which could lead to DSI + * commands not going through. To avoid this, force the lanes + * to be in stop state. + */ + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, reg); + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL3, 0); + usleep_range(100, 110); + + if (cfg->force_clk_lane_hs) { + reg = BIT(5) | BIT(6); + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg); + } +} + +u32 dsi_phy_hw_v4_0_get_lanes_in_ulps(struct dsi_phy_hw *phy) +{ + u32 lanes = 0; + + lanes = DSI_R32(phy, DSIPHY_CMN_LANE_STATUS0); + DSI_PHY_DBG(phy, "lanes in ulps = 0x%x\n", lanes); + return lanes; +} + +bool dsi_phy_hw_v4_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes) +{ + if (lanes & ulps_lanes) + return false; + + return true; +} + +int dsi_phy_hw_timing_val_v4_0(struct dsi_phy_per_lane_cfgs *timing_cfg, + u32 *timing_val, u32 size) +{ + int i = 0; + + if (size != DSI_PHY_TIMING_V4_SIZE) { + DSI_ERR("Unexpected timing array size %d\n", size); + return -EINVAL; + } + + for (i = 0; i < size; i++) + timing_cfg->lane_v4[i] = timing_val[i]; + return 0; +} + +void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy, + struct dsi_phy_cfg *cfg, bool is_master) +{ + u32 reg; + bool is_cphy = (cfg->phy_type == DSI_PHY_TYPE_CPHY) ? + true : false; + + if (is_master) { + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19, + DSIPHY_CMN_TIMING_CTRL_0, DSIPHY_CMN_TIMING_CTRL_1, + cfg->timing.lane_v4[0], cfg->timing.lane_v4[1]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20, + DSIPHY_CMN_TIMING_CTRL_2, DSIPHY_CMN_TIMING_CTRL_3, + cfg->timing.lane_v4[2], cfg->timing.lane_v4[3]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21, + DSIPHY_CMN_TIMING_CTRL_4, DSIPHY_CMN_TIMING_CTRL_5, + cfg->timing.lane_v4[4], cfg->timing.lane_v4[5]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22, + DSIPHY_CMN_TIMING_CTRL_6, DSIPHY_CMN_TIMING_CTRL_7, + cfg->timing.lane_v4[6], cfg->timing.lane_v4[7]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23, + DSIPHY_CMN_TIMING_CTRL_8, DSIPHY_CMN_TIMING_CTRL_9, + cfg->timing.lane_v4[8], cfg->timing.lane_v4[9]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24, + DSIPHY_CMN_TIMING_CTRL_10, DSIPHY_CMN_TIMING_CTRL_11, + cfg->timing.lane_v4[10], cfg->timing.lane_v4[11]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25, + DSIPHY_CMN_TIMING_CTRL_12, DSIPHY_CMN_TIMING_CTRL_13, + cfg->timing.lane_v4[12], cfg->timing.lane_v4[13]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26, + DSIPHY_CMN_CTRL_0, DSIPHY_CMN_LANE_CTRL0, + 0x7f, is_cphy ? 0x17 : 0x1f); + + } else { + reg = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1); + reg &= ~BIT(5); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0, + DSIPHY_CMN_CLK_CFG1, DSIPHY_CMN_PLL_CNTRL, + reg, 0x0); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1, + DSIPHY_CMN_RBUF_CTRL, DSIPHY_CMN_TIMING_CTRL_0, + 0x0, cfg->timing.lane_v4[0]); + + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2, + DSIPHY_CMN_TIMING_CTRL_1, DSIPHY_CMN_TIMING_CTRL_2, + cfg->timing.lane_v4[1], cfg->timing.lane_v4[2]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3, + DSIPHY_CMN_TIMING_CTRL_3, DSIPHY_CMN_TIMING_CTRL_4, + cfg->timing.lane_v4[3], cfg->timing.lane_v4[4]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4, + DSIPHY_CMN_TIMING_CTRL_5, DSIPHY_CMN_TIMING_CTRL_6, + cfg->timing.lane_v4[5], cfg->timing.lane_v4[6]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5, + DSIPHY_CMN_TIMING_CTRL_7, DSIPHY_CMN_TIMING_CTRL_8, + cfg->timing.lane_v4[7], cfg->timing.lane_v4[8]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6, + DSIPHY_CMN_TIMING_CTRL_9, DSIPHY_CMN_TIMING_CTRL_10, + cfg->timing.lane_v4[9], cfg->timing.lane_v4[10]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7, + DSIPHY_CMN_TIMING_CTRL_11, DSIPHY_CMN_TIMING_CTRL_12, + cfg->timing.lane_v4[11], cfg->timing.lane_v4[12]); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8, + DSIPHY_CMN_TIMING_CTRL_13, DSIPHY_CMN_CTRL_0, + cfg->timing.lane_v4[13], 0x7f); + DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9, + DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_2, + is_cphy ? 0x17 : 0x1f, 0x40); + /* + * fill with dummy register writes since controller will blindly + * send these values to DSI PHY. + */ + reg = DSI_DYN_REFRESH_PLL_CTRL11; + while (reg <= DSI_DYN_REFRESH_PLL_CTRL29) { + DSI_DYN_REF_REG_W(phy->dyn_pll_base, reg, + DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_0, + is_cphy ? 0x17 : 0x1f, 0x7f); + reg += 0x4; + } + + DSI_GEN_W32(phy->dyn_pll_base, + DSI_DYN_REFRESH_PLL_UPPER_ADDR, 0); + DSI_GEN_W32(phy->dyn_pll_base, + DSI_DYN_REFRESH_PLL_UPPER_ADDR2, 0); + } + + wmb(); /* make sure all registers are updated */ +} + +void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy, + struct dsi_dyn_clk_delay *delay) +{ + if (!delay) + return; + + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY, + delay->pipe_delay); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2, + delay->pipe_delay2); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY, + delay->pll_delay); +} + +void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset) +{ + u32 reg; + + /* + * if no offset is mentioned then this means we want to clear + * the dynamic refresh ctrl register which is the last step + * of dynamic refresh sequence. + */ + if (!offset) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg &= ~(BIT(0) | BIT(8)); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is cleared */ + return; + } + + if (offset & BIT(DYN_REFRESH_INTF_SEL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(13); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SYNC_MODE)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(16); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SWI_CTRL)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(0); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + } + + if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) { + reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); + reg |= BIT(8); + DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); + wmb(); /* ensure dynamic fps is triggered */ + } +} + +int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, + u32 *dst, u32 size) +{ + int i; + + if (!timings || !dst || !size) + return -EINVAL; + + if (size != DSI_PHY_TIMING_V4_SIZE) { + DSI_ERR("size mis-match\n"); + return -EINVAL; + } + + for (i = 0; i < size; i++) + dst[i] = timings->lane_v4[i]; + + return 0; +} + +void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable) +{ + u32 reg = 0; + + reg = DSI_R32(phy, DSIPHY_CMN_LANE_CTRL1); + + if (enable) + reg |= BIT(5) | BIT(6); + else + reg &= ~(BIT(5) | BIT(6)); + + DSI_W32(phy, DSIPHY_CMN_LANE_CTRL1, reg); + wmb(); /* make sure request is set */ +} diff --git a/techpack/display/msm/dsi/dsi_phy_timing_calc.c b/techpack/display/msm/dsi/dsi_phy_timing_calc.c new file mode 100644 index 0000000000000000000000000000000000000000..655b81780594dbdbefa3f0494dffda6ee571a905 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_timing_calc.c @@ -0,0 +1,1036 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include "dsi_phy_timing_calc.h" + +static const u32 bits_per_pixel[DSI_PIXEL_FORMAT_MAX] = { + 16, 18, 18, 24, 3, 8, 12 }; + +static int dsi_phy_cmn_validate_and_set(struct timing_entry *t, + char const *t_name) +{ + if (t->rec & 0xffffff00) { + /* Output value can only be 8 bits */ + DSI_ERR("Incorrect %s rec value - %d\n", t_name, t->rec); + return -EINVAL; + } + t->reg_value = t->rec; + return 0; +} + +/** + * calc_clk_prepare - calculates prepare timing params for clk lane. + */ +static int calc_clk_prepare(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc, + s32 *actual_frac, + s64 *actual_intermediate) +{ + u64 multiplier = BIT(20); + struct timing_entry *t = &desc->clk_prepare; + int rc = 0; + u64 dividend, temp, temp_multiple; + s32 frac = 0; + s64 intermediate; + s64 clk_prep_actual; + + t->rec_min = DIV_ROUND_UP((t->mipi_min * clk_params->bitclk_mbps), + (8 * clk_params->tlpx_numer_ns)); + t->rec_max = rounddown( + mult_frac((t->mipi_max * clk_params->bitclk_mbps), + 1, (8 * clk_params->tlpx_numer_ns)), 1); + + dividend = ((t->rec_max - t->rec_min) * + clk_params->clk_prep_buf * multiplier); + temp = roundup(div_s64(dividend, 100), multiplier); + temp += (t->rec_min * multiplier); + t->rec = div_s64(temp, multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_prepare"); + if (rc) + goto error; + + /* calculate theoretical value */ + temp_multiple = 8 * t->reg_value * clk_params->tlpx_numer_ns + * multiplier; + intermediate = div_s64(temp_multiple, clk_params->bitclk_mbps); + div_s64_rem(temp_multiple, clk_params->bitclk_mbps, &frac); + clk_prep_actual = div_s64((intermediate + frac), multiplier); + + DSI_PHY_DBG(phy, "CLK_PREPARE:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max); + DSI_PHY_DBG(phy, " reg_value=%d, actual=%lld\n", t->reg_value, + clk_prep_actual); + + *actual_frac = frac; + *actual_intermediate = intermediate; + +error: + return rc; +} + +/** + * calc_clk_zero - calculates zero timing params for clk lane. + */ +static int calc_clk_zero(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc, + s32 actual_frac, s64 actual_intermediate) +{ + u64 const multiplier = BIT(20); + int rc = 0; + struct timing_entry *t = &desc->clk_zero; + s64 mipi_min, rec_temp1; + struct phy_timing_ops *ops = phy->ops.timing_ops; + + mipi_min = ((300 * multiplier) - (actual_intermediate + actual_frac)); + t->mipi_min = div_s64(mipi_min, multiplier); + + rec_temp1 = div_s64((mipi_min * clk_params->bitclk_mbps), + clk_params->tlpx_numer_ns); + + if (ops->calc_clk_zero) { + t->rec_min = ops->calc_clk_zero(rec_temp1, multiplier); + } else { + rc = -EINVAL; + goto error; + } + t->rec_max = ((t->rec_min > 255) ? 511 : 255); + + t->rec = DIV_ROUND_UP((((t->rec_max - t->rec_min) * + clk_params->clk_zero_buf) + (t->rec_min * 100)), 100); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_zero"); + if (rc) + goto error; + + + DSI_PHY_DBG(phy, "CLK_ZERO:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); +error: + return rc; +} + +/** + * calc_clk_trail - calculates prepare trail params for clk lane. + */ +static int calc_clk_trail(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc, + s64 *teot_clk_lane) +{ + u64 const multiplier = BIT(20); + int rc = 0; + struct timing_entry *t = &desc->clk_trail; + u64 temp_multiple; + s32 frac; + s64 mipi_max_tr, rec_temp1, mipi_max; + s64 teot_clk_lane1; + struct phy_timing_ops *ops = phy->ops.timing_ops; + + temp_multiple = div_s64( + (12 * multiplier * clk_params->tlpx_numer_ns), + clk_params->bitclk_mbps); + div_s64_rem(temp_multiple, multiplier, &frac); + + mipi_max_tr = ((105 * multiplier) + + (temp_multiple + frac)); + teot_clk_lane1 = div_s64(mipi_max_tr, multiplier); + + mipi_max = (mipi_max_tr - (clk_params->treot_ns * multiplier)); + t->mipi_max = div_s64(mipi_max, multiplier); + + temp_multiple = div_s64( + (t->mipi_min * multiplier * clk_params->bitclk_mbps), + clk_params->tlpx_numer_ns); + + div_s64_rem(temp_multiple, multiplier, &frac); + if (ops->calc_clk_trail_rec_min) { + t->rec_min = ops->calc_clk_trail_rec_min(temp_multiple, + frac, multiplier); + } else { + rc = -EINVAL; + goto error; + } + + /* recommended max */ + rec_temp1 = div_s64((mipi_max * clk_params->bitclk_mbps), + clk_params->tlpx_numer_ns); + if (ops->calc_clk_trail_rec_max) { + t->rec_max = ops->calc_clk_trail_rec_max(rec_temp1, multiplier); + } else { + rc = -EINVAL; + goto error; + } + + t->rec = DIV_ROUND_UP( + (((t->rec_max - t->rec_min) * clk_params->clk_trail_buf) + + (t->rec_min * 100)), 100); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_trail"); + if (rc) + goto error; + + *teot_clk_lane = teot_clk_lane1; + DSI_PHY_DBG(phy, "CLK_TRAIL:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); + +error: + return rc; + +} + +/** + * calc_hs_prepare - calculates prepare timing params for data lanes in HS. + */ +static int calc_hs_prepare(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc, + u64 *temp_mul) +{ + u64 multiplier = BIT(20); + int rc = 0; + struct timing_entry *t = &desc->hs_prepare; + u64 temp_multiple, dividend, temp; + s32 frac; + s64 rec_temp1, rec_temp2, mipi_max, mipi_min; + u32 low_clk_multiplier = 0; + + if (clk_params->bitclk_mbps <= 120) + low_clk_multiplier = 2; + /* mipi min */ + temp_multiple = div_s64((4 * multiplier * clk_params->tlpx_numer_ns), + clk_params->bitclk_mbps); + div_s64_rem(temp_multiple, multiplier, &frac); + mipi_min = (40 * multiplier) + (temp_multiple + frac); + t->mipi_min = div_s64(mipi_min, multiplier); + + /* mipi_max */ + temp_multiple = div_s64( + (6 * multiplier * clk_params->tlpx_numer_ns), + clk_params->bitclk_mbps); + div_s64_rem(temp_multiple, multiplier, &frac); + mipi_max = (85 * multiplier) + temp_multiple; + t->mipi_max = div_s64(mipi_max, multiplier); + + /* recommended min */ + temp_multiple = div_s64((mipi_min * clk_params->bitclk_mbps), + clk_params->tlpx_numer_ns); + temp_multiple -= (low_clk_multiplier * multiplier); + div_s64_rem(temp_multiple, multiplier, &frac); + rec_temp1 = roundup(((temp_multiple + frac) / 8), multiplier); + t->rec_min = div_s64(rec_temp1, multiplier); + + /* recommended max */ + temp_multiple = div_s64((mipi_max * clk_params->bitclk_mbps), + clk_params->tlpx_numer_ns); + temp_multiple -= (low_clk_multiplier * multiplier); + div_s64_rem(temp_multiple, multiplier, &frac); + rec_temp2 = rounddown((temp_multiple / 8), multiplier); + t->rec_max = div_s64(rec_temp2, multiplier); + + /* register value */ + dividend = ((rec_temp2 - rec_temp1) * clk_params->hs_prep_buf); + temp = roundup(div_u64(dividend, 100), multiplier); + t->rec = div_s64((temp + rec_temp1), multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "hs_prepare"); + if (rc) + goto error; + + temp_multiple = div_s64( + (8 * (temp + rec_temp1) * clk_params->tlpx_numer_ns), + clk_params->bitclk_mbps); + + *temp_mul = temp_multiple; + DSI_PHY_DBG(phy, "HS_PREP:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); +error: + return rc; +} + +/** + * calc_hs_zero - calculates zero timing params for data lanes in HS. + */ +static int calc_hs_zero(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc, + u64 temp_multiple) +{ + u64 const multiplier = BIT(20); + int rc = 0; + struct timing_entry *t = &desc->hs_zero; + s64 rec_temp1, mipi_min; + struct phy_timing_ops *ops = phy->ops.timing_ops; + + mipi_min = div_s64((10 * clk_params->tlpx_numer_ns * multiplier), + clk_params->bitclk_mbps); + rec_temp1 = (145 * multiplier) + mipi_min - temp_multiple; + t->mipi_min = div_s64(rec_temp1, multiplier); + + /* recommended min */ + rec_temp1 = div_s64((rec_temp1 * clk_params->bitclk_mbps), + clk_params->tlpx_numer_ns); + + if (ops->calc_hs_zero) { + t->rec_min = ops->calc_hs_zero(rec_temp1, multiplier); + } else { + rc = -EINVAL; + goto error; + } + + t->rec_max = ((t->rec_min > 255) ? 511 : 255); + t->rec = DIV_ROUND_UP( + (((t->rec_max - t->rec_min) * clk_params->hs_zero_buf) + + (t->rec_min * 100)), + 100); + + rc = dsi_phy_cmn_validate_and_set(t, "hs_zero"); + if (rc) + goto error; + + DSI_PHY_DBG(phy, "HS_ZERO:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); + +error: + return rc; +} + +/** + * calc_hs_trail - calculates trail timing params for data lanes in HS. + */ +static int calc_hs_trail(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc, + u64 teot_clk_lane) +{ + int rc = 0; + struct timing_entry *t = &desc->hs_trail; + s64 rec_temp1; + struct phy_timing_ops *ops = phy->ops.timing_ops; + + t->mipi_min = 60 + + mult_frac(clk_params->tlpx_numer_ns, 4, + clk_params->bitclk_mbps); + + t->mipi_max = teot_clk_lane - clk_params->treot_ns; + + if (ops->calc_hs_trail) { + ops->calc_hs_trail(clk_params, desc); + } else { + rc = -EINVAL; + goto error; + } + + rec_temp1 = DIV_ROUND_UP( + ((t->rec_max - t->rec_min) * clk_params->hs_trail_buf), + 100); + t->rec = rec_temp1 + t->rec_min; + + rc = dsi_phy_cmn_validate_and_set(t, "hs_trail"); + if (rc) + goto error; + + DSI_PHY_DBG(phy, "HS_TRAIL:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); + +error: + return rc; +} + +/** + * calc_hs_rqst - calculates rqst timing params for data lanes in HS. + */ +static int calc_hs_rqst(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + int rc = 0; + struct timing_entry *t = &desc->hs_rqst; + + t->rec = DIV_ROUND_UP( + ((t->mipi_min * clk_params->bitclk_mbps) - + (8 * clk_params->tlpx_numer_ns)), + (8 * clk_params->tlpx_numer_ns)); + + rc = dsi_phy_cmn_validate_and_set(t, "hs_rqst"); + if (rc) + goto error; + + DSI_PHY_DBG(phy, "HS_RQST:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); + +error: + return rc; +} + +/** + * calc_hs_exit - calculates exit timing params for data lanes in HS. + */ +static int calc_hs_exit(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + int rc = 0; + struct timing_entry *t = &desc->hs_exit; + + t->rec_min = (DIV_ROUND_UP( + (t->mipi_min * clk_params->bitclk_mbps), + (8 * clk_params->tlpx_numer_ns)) - 1); + + t->rec = DIV_ROUND_UP( + (((t->rec_max - t->rec_min) * clk_params->hs_exit_buf) + + (t->rec_min * 100)), 100); + + rc = dsi_phy_cmn_validate_and_set(t, "hs_exit"); + if (rc) + goto error; + + + DSI_PHY_DBG(phy, "HS_EXIT:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); + +error: + return rc; +} + +/** + * calc_hs_rqst_clk - calculates rqst timing params for clock lane.. + */ +static int calc_hs_rqst_clk(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + int rc = 0; + struct timing_entry *t = &desc->hs_rqst_clk; + + t->rec = DIV_ROUND_UP( + ((t->mipi_min * clk_params->bitclk_mbps) - + (8 * clk_params->tlpx_numer_ns)), + (8 * clk_params->tlpx_numer_ns)); + + rc = dsi_phy_cmn_validate_and_set(t, "hs_rqst_clk"); + if (rc) + goto error; + + DSI_PHY_DBG(phy, "HS_RQST_CLK:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); + +error: + return rc; +} + +/** + * cal_clk_pulse_time - calculates clk pulse time in nsec + */ +static s64 cal_clk_pulse_time(u32 inp1, u32 inp2, u32 bitclk_mbps) +{ + u64 const multiplier = BIT(20); + u64 clk_multiple; + s32 frac; + s64 temp, result; + + clk_multiple = div_s64((inp1 * multiplier * 1000), bitclk_mbps); + div_s64_rem(clk_multiple, multiplier, &frac); + temp = (inp2 * multiplier) + (clk_multiple + frac); + result = div_s64(temp, multiplier); + + return result; +} + +/** + * calc_clk_post - calculates clk_post timing params for data lanes in HS. + */ +static int calc_clk_post(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + int rc = 0; + struct timing_entry *t = &desc->clk_post; + s64 rec_cal1, rec_cal2; + u32 input1; + + /* mipi min */ + t->mipi_min = cal_clk_pulse_time(52, 60, clk_params->bitclk_mbps); + + /* recommended min + * = roundup((mipi_min_ns + t_hs_trail_ns)/(16*bit_clk_ns), 0) - 1 + */ + rec_cal1 = cal_clk_pulse_time(16, 0, clk_params->bitclk_mbps); + + input1 = (desc->hs_trail.reg_value + 1) * 8; + rec_cal2 = cal_clk_pulse_time(input1, 0, clk_params->bitclk_mbps); + rec_cal2 += t->mipi_min; + + t->rec_min = div_s64(rec_cal2, rec_cal1) - 1; + + /* recommended max */ + t->rec_max = 255; + + /* register value */ + t->rec = DIV_ROUND_UP((((t->rec_max - t->rec_min) * + clk_params->clk_post_buf) + (t->rec_min * 100)), 100); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_post"); + if (rc) + goto error; + + DSI_PHY_DBG(phy, "CLK_POST:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); +error: + return rc; +} + +/** + * calc_clk_pre - calculates clk_pre timing params for data lanes in HS. + */ +static int calc_clk_pre(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + int rc = 0; + struct timing_entry *t = &desc->clk_pre; + s64 rec_temp1; + s64 clk_prepare, clk_zero, clk_16; + u32 input1; + + /* mipi min */ + t->mipi_min = cal_clk_pulse_time(8, 0, clk_params->bitclk_mbps); + + /* recommended min + * val1 = (tlpx_ns + clk_prepare_ns + clk_zero_ns + hs_rqst_ns) + * val2 = (16 * bit_clk_ns) + * final = roundup(val1/val2, 0) - 1 + */ + input1 = desc->clk_prepare.reg_value * 8; + clk_prepare = cal_clk_pulse_time(input1, 0, clk_params->bitclk_mbps); + + input1 = (desc->clk_zero.reg_value + 1) * 8; + clk_zero = cal_clk_pulse_time(input1, 0, clk_params->bitclk_mbps); + + clk_16 = cal_clk_pulse_time(16, 0, clk_params->bitclk_mbps); + + rec_temp1 = 52 + clk_prepare + clk_zero + 54; + t->rec_min = div_s64(rec_temp1, clk_16) - 1; + + /* recommended max */ + t->rec_max = 255; + + /* register value */ + t->rec =DIV_ROUND_UP((((t->rec_max - t->rec_min) * + 125) + (t->rec_min * 100 * 100)), 100 * 100); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_pre"); + if (rc) + goto error; + + DSI_PHY_DBG(phy, "CLK_PRE:mipi_min=%d, mipi_max=%d, rec_min=%d, rec_max=%d, reg_val=%d\n", + t->mipi_min, t->mipi_max, t->rec_min, t->rec_max, + t->reg_value); +error: + return rc; +} + +/** + * dsi_phy_calc_timing_params - calculates timing paramets for a given bit clock + */ +static int dsi_phy_cmn_calc_timing_params(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, struct phy_timing_desc *desc) +{ + int rc = 0; + s32 actual_frac = 0; + s64 actual_intermediate = 0; + u64 temp_multiple; + s64 teot_clk_lane; + + rc = calc_clk_prepare(phy, clk_params, desc, &actual_frac, + &actual_intermediate); + if (rc) { + DSI_PHY_ERR(phy, "clk_prepare calculations failed, rc=%d\n", + rc); + goto error; + } + + rc = calc_clk_zero(phy, clk_params, desc, + actual_frac, actual_intermediate); + if (rc) { + DSI_PHY_ERR(phy, "clk_zero calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_clk_trail(phy, clk_params, desc, &teot_clk_lane); + if (rc) { + DSI_PHY_ERR(phy, "clk_trail calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_hs_prepare(phy, clk_params, desc, &temp_multiple); + if (rc) { + DSI_PHY_ERR(phy, "hs_prepare calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_hs_zero(phy, clk_params, desc, temp_multiple); + if (rc) { + DSI_PHY_ERR(phy, "hs_zero calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_hs_trail(phy, clk_params, desc, teot_clk_lane); + if (rc) { + DSI_PHY_ERR(phy, "hs_trail calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_hs_rqst(phy, clk_params, desc); + if (rc) { + DSI_PHY_ERR(phy, "hs_rqst calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_hs_exit(phy, clk_params, desc); + if (rc) { + DSI_PHY_ERR(phy, "hs_exit calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_hs_rqst_clk(phy, clk_params, desc); + if (rc) { + DSI_PHY_ERR(phy, "hs_rqst_clk calculations failed, rc=%d\n", + rc); + goto error; + } + + rc = calc_clk_post(phy, clk_params, desc); + if (rc) { + DSI_PHY_ERR(phy, "clk_post calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_clk_pre(phy, clk_params, desc); + if (rc) { + DSI_PHY_ERR(phy, "clk_pre calculations failed, rc=%d\n", rc); + goto error; + } +error: + return rc; +} + +/** + * calc_cphy_clk_prepare - calculates cphy_clk_prepare parameter for cphy. + */ +static int calc_cphy_clk_prepare(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + u64 multiplier = BIT(20); + struct timing_entry *t = &desc->clk_prepare; + int rc = 0; + u64 dividend, temp; + + t->rec_min = DIV_ROUND_UP((t->mipi_min * clk_params->bitclk_mbps), + (7 * clk_params->tlpx_numer_ns)); + t->rec_max = rounddown( + mult_frac((t->mipi_max * clk_params->bitclk_mbps), + 1, (7 * clk_params->tlpx_numer_ns)), 1); + + dividend = ((t->rec_max - t->rec_min) * + clk_params->clk_prep_buf * multiplier); + temp = roundup(div_s64(dividend, 100), multiplier); + temp += (t->rec_min * multiplier); + t->rec = div_s64(temp, multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "cphy_clk_prepare"); + + DSI_DEBUG("CPHY_CLK_PREPARE: rec_min=%d, rec_max=%d, reg_val=%d\n", + t->rec_min, t->rec_max, t->reg_value); + + return rc; +} + +/** + * calc_cphy_clk_pre - calculates cphy_clk_pre parameter for cphy. + */ +static int calc_cphy_clk_pre(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + u64 multiplier = BIT(20); + struct timing_entry *t = &desc->clk_pre; + int rc = 0; + u64 dividend, temp; + + t->mipi_min = min(300 - 38 - mult_frac(7, clk_params->tlpx_numer_ns, + clk_params->bitclk_mbps), + mult_frac(448, clk_params->tlpx_numer_ns, + clk_params->bitclk_mbps)); + t->mipi_max = mult_frac(448, clk_params->tlpx_numer_ns, + clk_params->bitclk_mbps); + + t->rec_min = DIV_ROUND_UP((t->mipi_min * clk_params->bitclk_mbps), + (7 * clk_params->tlpx_numer_ns)); + t->rec_max = rounddown( + mult_frac((t->mipi_max * clk_params->bitclk_mbps), + 1, (7 * clk_params->tlpx_numer_ns)), 1); + + dividend = ((t->rec_max - t->rec_min) * clk_params->clk_pre_buf + * multiplier); + temp = roundup(div_s64(dividend, 100), multiplier); + temp += (t->rec_min * multiplier); + t->rec = div_s64(temp, multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "cphy_clk_pre"); + + DSI_DEBUG("CPHY_CLK_PRE: rec_min=%d, rec_max=%d, reg_val=%d\n", + t->rec_min, t->rec_max, t->reg_value); + + return rc; +} + +/** + * calc_cphy_clk_post - calculates cphy_clk_post parameter for cphy. + */ +static int calc_cphy_clk_post(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + u64 multiplier = BIT(20); + struct timing_entry *t = &desc->clk_post; + int rc = 0; + u64 dividend, temp; + + t->mipi_min = mult_frac(7, clk_params->tlpx_numer_ns, + clk_params->bitclk_mbps); + t->mipi_max = mult_frac(224, clk_params->tlpx_numer_ns, + clk_params->bitclk_mbps); + + t->rec_min = DIV_ROUND_UP((t->mipi_min * clk_params->bitclk_mbps), + (7 * clk_params->tlpx_numer_ns)); + t->rec_max = rounddown( + mult_frac((t->mipi_max * clk_params->bitclk_mbps), + 1, (7 * clk_params->tlpx_numer_ns)), 1); + + dividend = ((t->rec_max - t->rec_min) * clk_params->clk_post_buf + * multiplier); + temp = roundup(div_s64(dividend, 100), multiplier); + temp += (t->rec_min * multiplier); + t->rec = div_s64(temp, multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "cphy_clk_post"); + + DSI_DEBUG("CPHY_CLK_POST: rec_min=%d, rec_max=%d, reg_val=%d\n", + t->rec_min, t->rec_max, t->reg_value); + + return rc; +} + +/** + * calc_cphy_hs_rqst - calculates cphy_hs_rqst parameter for cphy. + */ +static int calc_cphy_hs_rqst(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + u64 multiplier = BIT(20); + struct timing_entry *t = &desc->hs_rqst; + int rc = 0; + u64 dividend, temp; + + t->rec_min = DIV_ROUND_UP( + ((t->mipi_min * clk_params->bitclk_mbps) - + (7 * clk_params->tlpx_numer_ns)), + (7 * clk_params->tlpx_numer_ns)); + + dividend = ((t->rec_max - t->rec_min) * + clk_params->hs_rqst_buf * multiplier); + temp = roundup(div_s64(dividend, 100), multiplier); + temp += t->rec_min * multiplier; + t->rec = div_s64(temp, multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "cphy_hs_rqst"); + + DSI_DEBUG("CPHY_HS_RQST: rec_min=%d, rec_max=%d, reg_val=%d\n", + t->rec_min, t->rec_max, t->reg_value); + + return rc; +} + +/** + * calc_cphy_hs_exit - calculates cphy_hs_exit parameter for cphy. + */ +static int calc_cphy_hs_exit(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + int rc = 0; + u64 multiplier = BIT(20); + u64 dividend, temp; + struct timing_entry *t = &desc->hs_exit; + + t->rec_min = (DIV_ROUND_UP( + (t->mipi_min * clk_params->bitclk_mbps), + (7 * clk_params->tlpx_numer_ns)) - 1); + + dividend = ((t->rec_max - t->rec_min) * + clk_params->hs_exit_buf * multiplier); + temp = roundup(div_s64(dividend, 100), multiplier); + temp += t->rec_min * multiplier; + t->rec = div_s64(temp, multiplier); + + rc = dsi_phy_cmn_validate_and_set(t, "cphy_hs_exit"); + + DSI_DEBUG("CPHY_HS_EXIT: rec_min=%d, rec_max=%d, reg_val=%d\n", + t->rec_min, t->rec_max, t->reg_value); + + return rc; +} + +/** + * dsi_phy_calc_cphy_timing_params - calculates cphy timing parameters + * for a given bit clock + */ +static int dsi_phy_cmn_calc_cphy_timing_params(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, struct phy_timing_desc *desc) +{ + int rc = 0; + + rc = calc_cphy_clk_prepare(phy, clk_params, desc); + if (rc) { + DSI_ERR("clk_prepare calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_cphy_clk_pre(phy, clk_params, desc); + if (rc) { + DSI_ERR("clk_pre calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_cphy_clk_post(phy, clk_params, desc); + if (rc) { + DSI_ERR("clk_zero calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_cphy_hs_rqst(phy, clk_params, desc); + if (rc) { + DSI_ERR("hs_rqst calculations failed, rc=%d\n", rc); + goto error; + } + + rc = calc_cphy_hs_exit(phy, clk_params, desc); + if (rc) { + DSI_ERR("hs_exit calculations failed, rc=%d\n", rc); + goto error; + } + +error: + return rc; +} + +/** + * calculate_timing_params() - calculates timing parameters. + * @phy: Pointer to DSI PHY hardware object. + * @mode: Mode information for which timing has to be calculated. + * @config: DSI host configuration for this mode. + * @timing: Timing parameters for each lane which will be returned. + * @use_mode_bit_clk: Boolean to indicate whether reacalculate dsi + * bit clk or use the existing bit clk(for dynamic clk case). + */ +int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy, + struct dsi_mode_info *mode, + struct dsi_host_common_cfg *host, + struct dsi_phy_per_lane_cfgs *timing, + bool use_mode_bit_clk) +{ + /* constants */ + u32 const esc_clk_mhz = 192; /* TODO: esc clock is hardcoded */ + u32 const esc_clk_mmss_cc_prediv = 10; + u32 const tlpx_numer = 1000; + u32 const tr_eot = 20; + u32 const clk_prepare_spec_min = 38; + u32 const clk_prepare_spec_max = 95; + u32 const clk_trail_spec_min = 60; + u32 const hs_exit_spec_min = 100; + u32 const hs_exit_reco_max = 255; + u32 const hs_rqst_spec_min = 50; + u32 const hs_rqst_reco_max = 255; + + /* local vars */ + int rc = 0; + u32 h_total, v_total; + u32 inter_num; + u32 num_of_lanes = 0; + u32 bpp; + u64 x, y; + struct phy_timing_desc desc; + struct phy_clk_params clk_params = {0}; + struct phy_timing_ops *ops = phy->ops.timing_ops; + + u32 phy_type = host->phy_type; + + memset(&desc, 0x0, sizeof(desc)); + h_total = DSI_H_TOTAL_DSC(mode); + v_total = DSI_V_TOTAL(mode); + + bpp = bits_per_pixel[host->dst_format]; + + inter_num = bpp * mode->refresh_rate; + + if (host->data_lanes & DSI_DATA_LANE_0) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_1) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_2) + num_of_lanes++; + if (host->data_lanes & DSI_DATA_LANE_3) + num_of_lanes++; + + + if (use_mode_bit_clk) + x = mode->clk_rate_hz; + else { + x = mult_frac(v_total * h_total, inter_num, num_of_lanes); + if (phy_type == DSI_PHY_TYPE_CPHY) + x = mult_frac(x, 7, 16); + } + y = rounddown(x, 1); + + clk_params.bitclk_mbps = rounddown(DIV_ROUND_UP_ULL(y, 1000000), 1); + clk_params.escclk_numer = esc_clk_mhz; + clk_params.escclk_denom = esc_clk_mmss_cc_prediv; + clk_params.tlpx_numer_ns = tlpx_numer; + clk_params.treot_ns = tr_eot; + + + /* Setup default parameters */ + desc.clk_prepare.mipi_min = clk_prepare_spec_min; + desc.clk_prepare.mipi_max = clk_prepare_spec_max; + desc.clk_trail.mipi_min = clk_trail_spec_min; + desc.hs_exit.mipi_min = hs_exit_spec_min; + desc.hs_exit.rec_max = hs_exit_reco_max; + desc.hs_rqst.mipi_min = hs_rqst_spec_min; + desc.hs_rqst_clk.mipi_min = hs_rqst_spec_min; + desc.hs_rqst.rec_max = hs_rqst_reco_max; + + if (ops->get_default_phy_params) { + ops->get_default_phy_params(&clk_params, phy_type); + } else { + rc = -EINVAL; + goto error; + } + + DSI_PHY_DBG(phy, "BIT CLOCK = %d, tlpx_numer_ns=%d, treot_ns=%d\n", + clk_params.bitclk_mbps, clk_params.tlpx_numer_ns, + clk_params.treot_ns); + + if (phy_type == DSI_PHY_TYPE_CPHY) + rc = dsi_phy_cmn_calc_cphy_timing_params(phy, &clk_params, + &desc); + else + rc = dsi_phy_cmn_calc_timing_params(phy, &clk_params, &desc); + if (rc) { + DSI_PHY_ERR(phy, "Timing calc failed, rc=%d\n", rc); + goto error; + } + + if (ops->update_timing_params) { + ops->update_timing_params(timing, &desc, phy_type); + } else { + rc = -EINVAL; + goto error; + } + +error: + return rc; +} + +int dsi_phy_timing_calc_init(struct dsi_phy_hw *phy, + enum dsi_phy_version version) +{ + struct phy_timing_ops *ops = NULL; + + if (version == DSI_PHY_VERSION_UNKNOWN || + version >= DSI_PHY_VERSION_MAX || !phy) { + DSI_PHY_ERR(phy, "Unsupported version: %d\n", version); + return -ENOTSUPP; + } + + ops = kzalloc(sizeof(struct phy_timing_ops), GFP_KERNEL); + if (!ops) + return -EINVAL; + phy->ops.timing_ops = ops; + + switch (version) { + case DSI_PHY_VERSION_2_0: + ops->get_default_phy_params = + dsi_phy_hw_v2_0_get_default_phy_params; + ops->calc_clk_zero = + dsi_phy_hw_v2_0_calc_clk_zero; + ops->calc_clk_trail_rec_min = + dsi_phy_hw_v2_0_calc_clk_trail_rec_min; + ops->calc_clk_trail_rec_max = + dsi_phy_hw_v2_0_calc_clk_trail_rec_max; + ops->calc_hs_zero = + dsi_phy_hw_v2_0_calc_hs_zero; + ops->calc_hs_trail = + dsi_phy_hw_v2_0_calc_hs_trail; + ops->update_timing_params = + dsi_phy_hw_v2_0_update_timing_params; + break; + case DSI_PHY_VERSION_3_0: + ops->get_default_phy_params = + dsi_phy_hw_v3_0_get_default_phy_params; + ops->calc_clk_zero = + dsi_phy_hw_v3_0_calc_clk_zero; + ops->calc_clk_trail_rec_min = + dsi_phy_hw_v3_0_calc_clk_trail_rec_min; + ops->calc_clk_trail_rec_max = + dsi_phy_hw_v3_0_calc_clk_trail_rec_max; + ops->calc_hs_zero = + dsi_phy_hw_v3_0_calc_hs_zero; + ops->calc_hs_trail = + dsi_phy_hw_v3_0_calc_hs_trail; + ops->update_timing_params = + dsi_phy_hw_v3_0_update_timing_params; + break; + case DSI_PHY_VERSION_4_0: + case DSI_PHY_VERSION_4_1: + ops->get_default_phy_params = + dsi_phy_hw_v4_0_get_default_phy_params; + ops->calc_clk_zero = + dsi_phy_hw_v4_0_calc_clk_zero; + ops->calc_clk_trail_rec_min = + dsi_phy_hw_v4_0_calc_clk_trail_rec_min; + ops->calc_clk_trail_rec_max = + dsi_phy_hw_v4_0_calc_clk_trail_rec_max; + ops->calc_hs_zero = + dsi_phy_hw_v4_0_calc_hs_zero; + ops->calc_hs_trail = + dsi_phy_hw_v4_0_calc_hs_trail; + ops->update_timing_params = + dsi_phy_hw_v4_0_update_timing_params; + break; + case DSI_PHY_VERSION_0_0_HPM: + case DSI_PHY_VERSION_0_0_LPM: + case DSI_PHY_VERSION_1_0: + default: + kfree(ops); + return -ENOTSUPP; + } + + return 0; +} + diff --git a/techpack/display/msm/dsi/dsi_phy_timing_calc.h b/techpack/display/msm/dsi/dsi_phy_timing_calc.h new file mode 100644 index 0000000000000000000000000000000000000000..536e7670a129e375f77578c2f6ae32cc06d57f70 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_timing_calc.h @@ -0,0 +1,163 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_PHY_TIMING_CALC_H_ +#define _DSI_PHY_TIMING_CALC_H_ + +#include <linux/math64.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/bitops.h> +#include <linux/bitmap.h> +#include <linux/errno.h> + +#include "dsi_defs.h" +#include "dsi_phy_hw.h" +#include "dsi_catalog.h" + +/** + * struct timing_entry - Calculated values for each timing parameter. + * @mipi_min: + * @mipi_max: + * @rec_min: + * @rec_max: + * @rec: + * @reg_value: Value to be programmed in register. + */ +struct timing_entry { + s32 mipi_min; + s32 mipi_max; + s32 rec_min; + s32 rec_max; + s32 rec; + u8 reg_value; +}; + +/** + * struct phy_timing_desc - Timing parameters for DSI PHY. + */ +struct phy_timing_desc { + struct timing_entry clk_prepare; + struct timing_entry clk_zero; + struct timing_entry clk_trail; + struct timing_entry hs_prepare; + struct timing_entry hs_zero; + struct timing_entry hs_trail; + struct timing_entry hs_rqst; + struct timing_entry hs_rqst_clk; + struct timing_entry hs_exit; + struct timing_entry ta_go; + struct timing_entry ta_sure; + struct timing_entry ta_set; + struct timing_entry clk_post; + struct timing_entry clk_pre; +}; + +/** + * struct phy_clk_params - Clock parameters for PHY timing calculations. + */ +struct phy_clk_params { + u32 bitclk_mbps; + u32 escclk_numer; + u32 escclk_denom; + u32 tlpx_numer_ns; + u32 treot_ns; + u32 clk_prep_buf; + u32 clk_zero_buf; + u32 clk_trail_buf; + u32 hs_prep_buf; + u32 hs_zero_buf; + u32 hs_trail_buf; + u32 hs_rqst_buf; + u32 hs_exit_buf; + u32 clk_pre_buf; + u32 clk_post_buf; +}; + +/** + * Various Ops needed for auto-calculation of DSI PHY timing parameters. + */ +struct phy_timing_ops { + void (*get_default_phy_params)(struct phy_clk_params *params, + u32 phy_type); + + int32_t (*calc_clk_zero)(s64 rec_temp1, s64 mult); + + int32_t (*calc_clk_trail_rec_min)(s64 temp_mul, + s64 frac, s64 mult); + + int32_t (*calc_clk_trail_rec_max)(s64 temp1, s64 mult); + + int32_t (*calc_hs_zero)(s64 temp1, s64 mult); + + void (*calc_hs_trail)(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc); + + void (*update_timing_params)(struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type); +}; + +#define roundup64(x, y) \ + ({ u64 _tmp = (x)+(y)-1; do_div(_tmp, y); _tmp * y; }) + +/* DSI PHY timing functions for 14nm */ +void dsi_phy_hw_v2_0_get_default_phy_params(struct phy_clk_params *params, + u32 phy_type); + +int32_t dsi_phy_hw_v2_0_calc_clk_zero(s64 rec_temp1, s64 mult); + +int32_t dsi_phy_hw_v2_0_calc_clk_trail_rec_min(s64 temp_mul, + s64 frac, s64 mult); + +int32_t dsi_phy_hw_v2_0_calc_clk_trail_rec_max(s64 temp1, s64 mult); + +int32_t dsi_phy_hw_v2_0_calc_hs_zero(s64 temp1, s64 mult); + +void dsi_phy_hw_v2_0_calc_hs_trail(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc); + +void dsi_phy_hw_v2_0_update_timing_params(struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type); + +/* DSI PHY timing functions for 10nm */ +void dsi_phy_hw_v3_0_get_default_phy_params(struct phy_clk_params *params, + u32 phy_type); + +int32_t dsi_phy_hw_v3_0_calc_clk_zero(s64 rec_temp1, s64 mult); + +int32_t dsi_phy_hw_v3_0_calc_clk_trail_rec_min(s64 temp_mul, + s64 frac, s64 mult); + +int32_t dsi_phy_hw_v3_0_calc_clk_trail_rec_max(s64 temp1, s64 mult); + +int32_t dsi_phy_hw_v3_0_calc_hs_zero(s64 temp1, s64 mult); + +void dsi_phy_hw_v3_0_calc_hs_trail(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc); + +void dsi_phy_hw_v3_0_update_timing_params(struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type); + +/* DSI PHY timing functions for 7nm */ +void dsi_phy_hw_v4_0_get_default_phy_params(struct phy_clk_params *params, + u32 phy_type); + +int32_t dsi_phy_hw_v4_0_calc_clk_zero(s64 rec_temp1, s64 mult); + +int32_t dsi_phy_hw_v4_0_calc_clk_trail_rec_min(s64 temp_mul, + s64 frac, s64 mult); + +int32_t dsi_phy_hw_v4_0_calc_clk_trail_rec_max(s64 temp1, s64 mult); + +int32_t dsi_phy_hw_v4_0_calc_hs_zero(s64 temp1, s64 mult); + +void dsi_phy_hw_v4_0_calc_hs_trail(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc); + +void dsi_phy_hw_v4_0_update_timing_params(struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type); + +#endif /* _DSI_PHY_TIMING_CALC_H_ */ diff --git a/techpack/display/msm/dsi/dsi_phy_timing_v2_0.c b/techpack/display/msm/dsi/dsi_phy_timing_v2_0.c new file mode 100644 index 0000000000000000000000000000000000000000..383999395bcded4783bb97aa39c10ee3a50a80ef --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_timing_v2_0.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include "dsi_phy_timing_calc.h" + +void dsi_phy_hw_v2_0_get_default_phy_params(struct phy_clk_params *params, + u32 phy_type) +{ + params->clk_prep_buf = 50; + params->clk_zero_buf = 2; + params->clk_trail_buf = 30; + params->hs_prep_buf = 50; + params->hs_zero_buf = 10; + params->hs_trail_buf = 30; + params->hs_rqst_buf = 0; + params->hs_exit_buf = 10; +} + +int32_t dsi_phy_hw_v2_0_calc_clk_zero(s64 rec_temp1, s64 mult) +{ + s64 rec_temp2, rec_temp3; + + rec_temp2 = (rec_temp1 - (11 * mult)); + rec_temp3 = roundup64(div_s64(rec_temp2, 8), mult); + return (div_s64(rec_temp3, mult) - 3); +} + +int32_t dsi_phy_hw_v2_0_calc_clk_trail_rec_min(s64 temp_mul, + s64 frac, s64 mult) +{ + s64 rec_temp1, rec_temp2, rec_temp3; + + rec_temp1 = temp_mul + frac + (3 * mult); + rec_temp2 = div_s64(rec_temp1, 8); + rec_temp3 = roundup64(rec_temp2, mult); + + return div_s64(rec_temp3, mult); +} + +int32_t dsi_phy_hw_v2_0_calc_clk_trail_rec_max(s64 temp1, s64 mult) +{ + s64 rec_temp2, rec_temp3; + + rec_temp2 = temp1 + (3 * mult); + rec_temp3 = rec_temp2 / 8; + return div_s64(rec_temp3, mult); + +} + +int32_t dsi_phy_hw_v2_0_calc_hs_zero(s64 temp1, s64 mult) +{ + s64 rec_temp2, rec_temp3, rec_min; + + rec_temp2 = temp1 - (11 * mult); + rec_temp3 = roundup64((rec_temp2 / 8), mult); + rec_min = rec_temp3 - (3 * mult); + return div_s64(rec_min, mult); +} + +void dsi_phy_hw_v2_0_calc_hs_trail(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + s64 rec_temp1; + struct timing_entry *t = &desc->hs_trail; + + t->rec_min = DIV_ROUND_UP( + ((t->mipi_min * clk_params->bitclk_mbps) + + (3 * clk_params->tlpx_numer_ns)), + (8 * clk_params->tlpx_numer_ns)); + + rec_temp1 = ((t->mipi_max * clk_params->bitclk_mbps) + + (3 * clk_params->tlpx_numer_ns)); + t->rec_max = DIV_ROUND_UP_ULL(rec_temp1, + (8 * clk_params->tlpx_numer_ns)); +} + +void dsi_phy_hw_v2_0_update_timing_params( + struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type) +{ + int i = 0; + + for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) { + timing->lane[i][0] = desc->hs_exit.reg_value; + + if (i == DSI_LOGICAL_CLOCK_LANE) + timing->lane[i][1] = desc->clk_zero.reg_value; + else + timing->lane[i][1] = desc->hs_zero.reg_value; + + if (i == DSI_LOGICAL_CLOCK_LANE) + timing->lane[i][2] = desc->clk_prepare.reg_value; + else + timing->lane[i][2] = desc->hs_prepare.reg_value; + + if (i == DSI_LOGICAL_CLOCK_LANE) + timing->lane[i][3] = desc->clk_trail.reg_value; + else + timing->lane[i][3] = desc->hs_trail.reg_value; + + if (i == DSI_LOGICAL_CLOCK_LANE) + timing->lane[i][4] = desc->hs_rqst_clk.reg_value; + else + timing->lane[i][4] = desc->hs_rqst.reg_value; + + timing->lane[i][5] = 0x2; + timing->lane[i][6] = 0x4; + timing->lane[i][7] = 0xA0; + DSI_DEBUG("[%d][%d %d %d %d %d]\n", i, timing->lane[i][0], + timing->lane[i][1], + timing->lane[i][2], + timing->lane[i][3], + timing->lane[i][4]); + } + timing->count_per_lane = 8; +} diff --git a/techpack/display/msm/dsi/dsi_phy_timing_v3_0.c b/techpack/display/msm/dsi/dsi_phy_timing_v3_0.c new file mode 100644 index 0000000000000000000000000000000000000000..c57b6b5ff28d1e27a340a5bd10c4119ba7984f15 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_timing_v3_0.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include "dsi_phy_timing_calc.h" + +void dsi_phy_hw_v3_0_get_default_phy_params( + struct phy_clk_params *params, u32 phy_type) +{ + params->clk_prep_buf = 0; + params->clk_zero_buf = 0; + params->clk_trail_buf = 0; + params->hs_prep_buf = 0; + params->hs_zero_buf = 0; + params->hs_trail_buf = 0; + params->hs_rqst_buf = 0; + params->hs_exit_buf = 0; +} + +int32_t dsi_phy_hw_v3_0_calc_clk_zero(s64 rec_temp1, s64 mult) +{ + s64 rec_temp2, rec_temp3; + + rec_temp2 = (rec_temp1 - mult); + rec_temp3 = roundup64(div_s64(rec_temp2, 8), mult); + return (div_s64(rec_temp3, mult) - 1); +} + +int32_t dsi_phy_hw_v3_0_calc_clk_trail_rec_min(s64 temp_mul, + s64 frac, s64 mult) +{ + s64 rec_temp1, rec_temp2, rec_temp3; + + rec_temp1 = temp_mul + frac; + rec_temp2 = div_s64(rec_temp1, 8); + rec_temp3 = roundup64(rec_temp2, mult); + return (div_s64(rec_temp3, mult) - 1); +} + +int32_t dsi_phy_hw_v3_0_calc_clk_trail_rec_max(s64 temp1, s64 mult) +{ + s64 rec_temp2; + + rec_temp2 = temp1 / 8; + return (div_s64(rec_temp2, mult) - 1); +} + +int32_t dsi_phy_hw_v3_0_calc_hs_zero(s64 temp1, s64 mult) +{ + s64 rec_temp2, rec_min; + + rec_temp2 = roundup64((temp1 / 8), mult); + rec_min = rec_temp2 - (1 * mult); + return div_s64(rec_min, mult); +} + +void dsi_phy_hw_v3_0_calc_hs_trail(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + s64 rec_temp1; + struct timing_entry *t = &desc->hs_trail; + + t->rec_min = DIV_ROUND_UP( + (t->mipi_min * clk_params->bitclk_mbps), + (8 * clk_params->tlpx_numer_ns)) - 1; + + rec_temp1 = (t->mipi_max * clk_params->bitclk_mbps); + t->rec_max = + (div_s64(rec_temp1, (8 * clk_params->tlpx_numer_ns))) - 1; +} + +void dsi_phy_hw_v3_0_update_timing_params( + struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type) +{ + timing->lane_v3[0] = 0x00; + timing->lane_v3[1] = desc->clk_zero.reg_value; + timing->lane_v3[2] = desc->clk_prepare.reg_value; + timing->lane_v3[3] = desc->clk_trail.reg_value; + timing->lane_v3[4] = desc->hs_exit.reg_value; + timing->lane_v3[5] = desc->hs_zero.reg_value; + timing->lane_v3[6] = desc->hs_prepare.reg_value; + timing->lane_v3[7] = desc->hs_trail.reg_value; + timing->lane_v3[8] = desc->hs_rqst.reg_value; + timing->lane_v3[9] = 0x02; + timing->lane_v3[10] = 0x04; + timing->lane_v3[11] = 0x00; + + DSI_DEBUG("[%d %d %d %d]\n", timing->lane_v3[0], + timing->lane_v3[1], timing->lane_v3[2], timing->lane_v3[3]); + DSI_DEBUG("[%d %d %d %d]\n", timing->lane_v3[4], + timing->lane_v3[5], timing->lane_v3[6], timing->lane_v3[7]); + DSI_DEBUG("[%d %d %d %d]\n", timing->lane_v3[8], + timing->lane_v3[9], timing->lane_v3[10], timing->lane_v3[11]); + timing->count_per_lane = 12; +} diff --git a/techpack/display/msm/dsi/dsi_phy_timing_v4_0.c b/techpack/display/msm/dsi/dsi_phy_timing_v4_0.c new file mode 100644 index 0000000000000000000000000000000000000000..112762896a60d904ace9048d80b62b4889749722 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_phy_timing_v4_0.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#include "dsi_phy_timing_calc.h" + +void dsi_phy_hw_v4_0_get_default_phy_params( + struct phy_clk_params *params, u32 phy_type) +{ + if (phy_type == DSI_PHY_TYPE_CPHY) { + params->clk_prep_buf = 50; + params->clk_pre_buf = 20; + params->clk_post_buf = 80; + params->hs_rqst_buf = 1; + params->hs_exit_buf = 10; + } else { + params->clk_prep_buf = 50; + params->clk_zero_buf = 2; + params->clk_trail_buf = 30; + params->hs_prep_buf = 50; + params->hs_zero_buf = 10; + params->hs_trail_buf = 30; + params->hs_rqst_buf = 0; + params->hs_exit_buf = 10; + /* 1.25 is used in code for precision */ + params->clk_pre_buf = 1; + params->clk_post_buf = 5; + } +} + +int32_t dsi_phy_hw_v4_0_calc_clk_zero(s64 rec_temp1, s64 mult) +{ + s64 rec_temp2, rec_temp3; + + rec_temp2 = rec_temp1; + rec_temp3 = roundup64(div_s64(rec_temp2, 8), mult); + return (div_s64(rec_temp3, mult) - 1); +} + +int32_t dsi_phy_hw_v4_0_calc_clk_trail_rec_min(s64 temp_mul, + s64 frac, s64 mult) +{ + s64 rec_temp1, rec_temp2, rec_temp3; + + rec_temp1 = temp_mul; + rec_temp2 = div_s64(rec_temp1, 8); + rec_temp3 = roundup64(rec_temp2, mult); + return (div_s64(rec_temp3, mult) - 1); +} + +int32_t dsi_phy_hw_v4_0_calc_clk_trail_rec_max(s64 temp1, s64 mult) +{ + s64 rec_temp2; + + rec_temp2 = temp1 / 8; + return (div_s64(rec_temp2, mult) - 1); +} + +int32_t dsi_phy_hw_v4_0_calc_hs_zero(s64 temp1, s64 mult) +{ + s64 rec_temp2, rec_min; + + rec_temp2 = roundup64((temp1 / 8), mult); + rec_min = rec_temp2 - (1 * mult); + return div_s64(rec_min, mult); +} + +void dsi_phy_hw_v4_0_calc_hs_trail(struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + s64 rec_temp1; + struct timing_entry *t = &desc->hs_trail; + + t->rec_min = DIV_ROUND_UP( + (t->mipi_min * clk_params->bitclk_mbps), + (8 * clk_params->tlpx_numer_ns)) - 1; + + rec_temp1 = (t->mipi_max * clk_params->bitclk_mbps); + t->rec_max = + (div_s64(rec_temp1, (8 * clk_params->tlpx_numer_ns))) - 1; +} + +void dsi_phy_hw_v4_0_update_timing_params( + struct dsi_phy_per_lane_cfgs *timing, + struct phy_timing_desc *desc, u32 phy_type) +{ + if (phy_type == DSI_PHY_TYPE_CPHY) { + timing->lane_v4[0] = 0x00; + timing->lane_v4[1] = 0x00; + timing->lane_v4[2] = 0x00; + timing->lane_v4[3] = 0x00; + timing->lane_v4[4] = desc->hs_exit.reg_value; + timing->lane_v4[5] = desc->clk_pre.reg_value; + timing->lane_v4[6] = desc->clk_prepare.reg_value; + timing->lane_v4[7] = desc->clk_post.reg_value; + timing->lane_v4[8] = desc->hs_rqst.reg_value; + timing->lane_v4[9] = 0x02; + timing->lane_v4[10] = 0x04; + timing->lane_v4[11] = 0x00; + } else { + timing->lane_v4[0] = 0x00; + timing->lane_v4[1] = desc->clk_zero.reg_value; + timing->lane_v4[2] = desc->clk_prepare.reg_value; + timing->lane_v4[3] = desc->clk_trail.reg_value; + timing->lane_v4[4] = desc->hs_exit.reg_value; + timing->lane_v4[5] = desc->hs_zero.reg_value; + timing->lane_v4[6] = desc->hs_prepare.reg_value; + timing->lane_v4[7] = desc->hs_trail.reg_value; + timing->lane_v4[8] = desc->hs_rqst.reg_value; + timing->lane_v4[9] = 0x02; + timing->lane_v4[10] = 0x04; + timing->lane_v4[11] = 0x00; + timing->lane_v4[12] = desc->clk_pre.reg_value; + timing->lane_v4[13] = desc->clk_post.reg_value; + } + + DSI_DEBUG("[%d %d %d %d]\n", timing->lane_v4[0], + timing->lane_v4[1], timing->lane_v4[2], timing->lane_v4[3]); + DSI_DEBUG("[%d %d %d %d]\n", timing->lane_v4[4], + timing->lane_v4[5], timing->lane_v4[6], timing->lane_v4[7]); + DSI_DEBUG("[%d %d %d %d]\n", timing->lane_v4[8], + timing->lane_v4[9], timing->lane_v4[10], timing->lane_v4[11]); + DSI_DEBUG("[%d %d]\n", timing->lane_v4[12], timing->lane_v4[13]); + timing->count_per_lane = 14; +} diff --git a/techpack/display/msm/dsi/dsi_pwr.c b/techpack/display/msm/dsi/dsi_pwr.c new file mode 100644 index 0000000000000000000000000000000000000000..bcaefaf98acf8fab54d211f7526cecad031d26fe --- /dev/null +++ b/techpack/display/msm/dsi/dsi_pwr.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/of.h> +#include <linux/delay.h> +#include <linux/slab.h> + +#include "dsi_pwr.h" +#include "dsi_parser.h" +#include "dsi_defs.h" + +/* + * dsi_pwr_parse_supply_node() - parse power supply node from root device node + */ +static int dsi_pwr_parse_supply_node(struct dsi_parser_utils *utils, + struct device_node *root, + struct dsi_regulator_info *regs) +{ + int rc = 0; + int i = 0; + u32 tmp = 0; + struct device_node *node = NULL; + + dsi_for_each_child_node(root, node) { + const char *st = NULL; + + rc = utils->read_string(node, "qcom,supply-name", &st); + if (rc) { + DSI_ERR("failed to read name, rc = %d\n", rc); + goto error; + } + + snprintf(regs->vregs[i].vreg_name, + ARRAY_SIZE(regs->vregs[i].vreg_name), + "%s", st); + + rc = utils->read_u32(node, "qcom,supply-min-voltage", &tmp); + if (rc) { + DSI_ERR("failed to read min voltage, rc = %d\n", rc); + goto error; + } + regs->vregs[i].min_voltage = tmp; + + rc = utils->read_u32(node, "qcom,supply-max-voltage", &tmp); + if (rc) { + DSI_ERR("failed to read max voltage, rc = %d\n", rc); + goto error; + } + regs->vregs[i].max_voltage = tmp; + + rc = utils->read_u32(node, "qcom,supply-enable-load", &tmp); + if (rc) { + DSI_ERR("failed to read enable load, rc = %d\n", rc); + goto error; + } + regs->vregs[i].enable_load = tmp; + + rc = utils->read_u32(node, "qcom,supply-disable-load", &tmp); + if (rc) { + DSI_ERR("failed to read disable load, rc = %d\n", rc); + goto error; + } + regs->vregs[i].disable_load = tmp; + + /* Optional values */ + rc = utils->read_u32(node, "qcom,supply-off-min-voltage", &tmp); + if (rc) { + DSI_DEBUG("off-min-voltage not specified\n"); + rc = 0; + } else { + regs->vregs[i].off_min_voltage = tmp; + } + + rc = utils->read_u32(node, "qcom,supply-pre-on-sleep", &tmp); + if (rc) { + DSI_DEBUG("pre-on-sleep not specified\n"); + rc = 0; + } else { + regs->vregs[i].pre_on_sleep = tmp; + } + + rc = utils->read_u32(node, "qcom,supply-pre-off-sleep", &tmp); + if (rc) { + DSI_DEBUG("pre-off-sleep not specified\n"); + rc = 0; + } else { + regs->vregs[i].pre_off_sleep = tmp; + } + + rc = utils->read_u32(node, "qcom,supply-post-on-sleep", &tmp); + if (rc) { + DSI_DEBUG("post-on-sleep not specified\n"); + rc = 0; + } else { + regs->vregs[i].post_on_sleep = tmp; + } + + rc = utils->read_u32(node, "qcom,supply-post-off-sleep", &tmp); + if (rc) { + DSI_DEBUG("post-off-sleep not specified\n"); + rc = 0; + } else { + regs->vregs[i].post_off_sleep = tmp; + } + + DSI_DEBUG("[%s] minv=%d maxv=%d, en_load=%d, dis_load=%d\n", + regs->vregs[i].vreg_name, + regs->vregs[i].min_voltage, + regs->vregs[i].max_voltage, + regs->vregs[i].enable_load, + regs->vregs[i].disable_load); + ++i; + } + +error: + return rc; +} + +/** + * dsi_pwr_enable_vregs() - enable/disable regulators + */ +static int dsi_pwr_enable_vregs(struct dsi_regulator_info *regs, bool enable) +{ + int rc = 0, i = 0; + struct dsi_vreg *vreg; + int num_of_v = 0; + u32 pre_on_ms, post_on_ms; + u32 pre_off_ms, post_off_ms; + + if (enable) { + for (i = 0; i < regs->count; i++) { + vreg = ®s->vregs[i]; + pre_on_ms = vreg->pre_on_sleep; + post_on_ms = vreg->post_on_sleep; + + if (vreg->pre_on_sleep) + usleep_range((pre_on_ms * 1000), + (pre_on_ms * 1000) + 10); + + rc = regulator_set_load(vreg->vreg, + vreg->enable_load); + if (rc < 0) { + DSI_ERR("Setting optimum mode failed for %s\n", + vreg->vreg_name); + goto error; + } + num_of_v = regulator_count_voltages(vreg->vreg); + if (num_of_v > 0) { + rc = regulator_set_voltage(vreg->vreg, + vreg->min_voltage, + vreg->max_voltage); + if (rc) { + DSI_ERR("Set voltage(%s) fail, rc=%d\n", + vreg->vreg_name, rc); + goto error_disable_opt_mode; + } + } + + rc = regulator_enable(vreg->vreg); + if (rc) { + DSI_ERR("enable failed for %s, rc=%d\n", + vreg->vreg_name, rc); + goto error_disable_voltage; + } + + if (vreg->post_on_sleep) + usleep_range((post_on_ms * 1000), + (post_on_ms * 1000) + 10); + } + } else { + for (i = (regs->count - 1); i >= 0; i--) { + vreg = ®s->vregs[i]; + pre_off_ms = vreg->pre_off_sleep; + post_off_ms = vreg->post_off_sleep; + + if (pre_off_ms) + usleep_range((pre_off_ms * 1000), + (pre_off_ms * 1000) + 10); + + if (regs->vregs[i].off_min_voltage) + (void)regulator_set_voltage(regs->vregs[i].vreg, + regs->vregs[i].off_min_voltage, + regs->vregs[i].max_voltage); + + (void)regulator_set_load(regs->vregs[i].vreg, + regs->vregs[i].disable_load); + (void)regulator_disable(regs->vregs[i].vreg); + + if (post_off_ms) + usleep_range((post_off_ms * 1000), + (post_off_ms * 1000) + 10); + } + } + + return 0; +error_disable_opt_mode: + (void)regulator_set_load(regs->vregs[i].vreg, + regs->vregs[i].disable_load); + +error_disable_voltage: + if (num_of_v > 0) + (void)regulator_set_voltage(regs->vregs[i].vreg, + 0, regs->vregs[i].max_voltage); +error: + for (i--; i >= 0; i--) { + vreg = ®s->vregs[i]; + pre_off_ms = vreg->pre_off_sleep; + post_off_ms = vreg->post_off_sleep; + + if (pre_off_ms) + usleep_range((pre_off_ms * 1000), + (pre_off_ms * 1000) + 10); + + (void)regulator_set_load(regs->vregs[i].vreg, + regs->vregs[i].disable_load); + + num_of_v = regulator_count_voltages(regs->vregs[i].vreg); + if (num_of_v > 0) + (void)regulator_set_voltage(regs->vregs[i].vreg, + 0, regs->vregs[i].max_voltage); + + (void)regulator_disable(regs->vregs[i].vreg); + + if (post_off_ms) + usleep_range((post_off_ms * 1000), + (post_off_ms * 1000) + 10); + } + + return rc; +} + +/** + * dsi_pwr_of_get_vreg_data - Parse regulator supply information + * @of_node: Device of node to parse for supply information. + * @regs: Pointer where regulator information will be copied to. + * @supply_name: Name of the supply node. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_of_get_vreg_data(struct dsi_parser_utils *utils, + struct dsi_regulator_info *regs, + char *supply_name) +{ + int rc = 0; + struct device_node *supply_root_node = NULL; + + if (!utils || !regs) { + DSI_ERR("Bad params\n"); + return -EINVAL; + } + + regs->count = 0; + supply_root_node = utils->get_child_by_name(utils->data, supply_name); + if (!supply_root_node) { + supply_root_node = of_parse_phandle(utils->node, + supply_name, 0); + if (!supply_root_node) { + DSI_DEBUG("No supply entry present for %s\n", + supply_name); + return -EINVAL; + } + } + + regs->count = utils->get_available_child_count(supply_root_node); + if (regs->count == 0) { + DSI_ERR("No vregs defined for %s\n", supply_name); + return -EINVAL; + } + + regs->vregs = kcalloc(regs->count, sizeof(*regs->vregs), GFP_KERNEL); + if (!regs->vregs) { + regs->count = 0; + return -ENOMEM; + } + + rc = dsi_pwr_parse_supply_node(utils, supply_root_node, regs); + if (rc) { + DSI_ERR("failed to parse supply node for %s, rc = %d\n", + supply_name, rc); + + kfree(regs->vregs); + regs->vregs = NULL; + regs->count = 0; + } + + return rc; +} + +/** + * dsi_pwr_get_dt_vreg_data - parse regulator supply information + * @dev: Device whose of_node needs to be parsed. + * @regs: Pointer where regulator information will be copied to. + * @supply_name: Name of the supply node. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_get_dt_vreg_data(struct device *dev, + struct dsi_regulator_info *regs, + char *supply_name) +{ + int rc = 0; + struct device_node *of_node = NULL; + struct device_node *supply_node = NULL; + struct device_node *supply_root_node = NULL; + struct dsi_parser_utils utils = *dsi_parser_get_of_utils(); + + if (!dev || !regs) { + DSI_ERR("Bad params\n"); + return -EINVAL; + } + + of_node = dev->of_node; + regs->count = 0; + supply_root_node = of_get_child_by_name(of_node, supply_name); + if (!supply_root_node) { + supply_root_node = of_parse_phandle(of_node, supply_name, 0); + if (!supply_root_node) { + DSI_DEBUG("No supply entry present for %s\n", + supply_name); + return -EINVAL; + } + } + + for_each_child_of_node(supply_root_node, supply_node) + regs->count++; + + if (regs->count == 0) { + DSI_ERR("No vregs defined for %s\n", supply_name); + return -EINVAL; + } + + regs->vregs = devm_kcalloc(dev, regs->count, sizeof(*regs->vregs), + GFP_KERNEL); + if (!regs->vregs) { + regs->count = 0; + return -ENOMEM; + } + + utils.data = of_node; + utils.node = of_node; + + rc = dsi_pwr_parse_supply_node(&utils, supply_root_node, regs); + if (rc) { + DSI_ERR("failed to parse supply node for %s, rc = %d\n", + supply_name, rc); + devm_kfree(dev, regs->vregs); + regs->vregs = NULL; + regs->count = 0; + } + + return rc; +} + +/** + * dsi_pwr_enable_regulator() - enable a set of regulators + * @regs: Pointer to set of regulators to enable or disable. + * @enable: Enable/Disable regulators. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable) +{ + int rc = 0; + + if (regs->count == 0) { + DSI_DEBUG("No valid regulators to enable\n"); + return 0; + } + + if (!regs->vregs) { + DSI_ERR("Invalid params\n"); + return -EINVAL; + } + + if (enable) { + if (regs->refcount == 0) { + rc = dsi_pwr_enable_vregs(regs, true); + if (rc) + DSI_ERR("failed to enable regulators\n"); + } + regs->refcount++; + } else { + if (regs->refcount == 0) { + DSI_ERR("Unbalanced regulator off:%s\n", + regs->vregs->vreg_name); + } else { + regs->refcount--; + if (regs->refcount == 0) { + rc = dsi_pwr_enable_vregs(regs, false); + if (rc) + DSI_ERR("failed to disable vregs\n"); + } + } + } + + return rc; +} + +/* + * dsi_pwr_panel_regulator_mode_set() + * set the AB/IBB regulator mode for OLED panel + * AOD mode entry and exit + * @regs: Pointer to set of regulators to enable or disable. + * @reg_name: Name of panel power we want to set. + * @retulator_mode: Regulator mode values, like: + * REGULATOR_MODE_INVALID + * REGULATOR_MODE_FAST + * REGULATOR_MODE_NORMAL + * REGULATOR_MODE_IDLE + * REGULATOR_MODE_STANDBY + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_panel_regulator_mode_set(struct dsi_regulator_info *regs, + const char *reg_name, + int regulator_mode) +{ + int i = 0, rc = 0; + struct dsi_vreg *vreg; + + if (regs->count == 0) + return -EINVAL; + + if (!regs->vregs) + return -EINVAL; + + for (i = 0; i < regs->count; i++) { + vreg = ®s->vregs[i]; + if (!strcmp(vreg->vreg_name, reg_name)) { + rc = regulator_set_mode(vreg->vreg, + regulator_mode); + if (rc) + DSI_ERR("Regulator %s set mode %d failed\n", + vreg->vreg_name, rc); + break; + } + } + + if (i >= regs->count) { + DSI_ERR("Regulator %s was not found\n", reg_name); + return -EINVAL; + } + + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_pwr.h b/techpack/display/msm/dsi/dsi_pwr.h new file mode 100644 index 0000000000000000000000000000000000000000..fd9ef2c18d8bdcdcc6529c7d2ae57f7b17b56452 --- /dev/null +++ b/techpack/display/msm/dsi/dsi_pwr.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _DSI_PWR_H_ +#define _DSI_PWR_H_ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/regulator/consumer.h> + +struct dsi_parser_utils; + +/** + * struct dsi_vreg - regulator information for DSI regulators + * @vreg: Handle to the regulator. + * @vreg_name: Regulator name. + * @min_voltage: Minimum voltage in uV. + * @max_voltage: Maximum voltage in uV. + * @enable_load: Load, in uA, when enabled. + * @disable_load: Load, in uA, when disabled. + * @off_min_voltage: Minimum voltage in uV when regulator is disabled. + * @pre_on_sleep: Sleep, in ms, before enabling the regulator. + * @post_on_sleep: Sleep, in ms, after enabling the regulator. + * @pre_off_sleep: Sleep, in ms, before disabling the regulator. + * @post_off_sleep: Sleep, in ms, after disabling the regulator. + */ +struct dsi_vreg { + struct regulator *vreg; + char vreg_name[32]; + u32 min_voltage; + u32 max_voltage; + u32 enable_load; + u32 disable_load; + u32 off_min_voltage; + u32 pre_on_sleep; + u32 post_on_sleep; + u32 pre_off_sleep; + u32 post_off_sleep; +}; + +/** + * struct dsi_regulator_info - set of vregs that are turned on/off together. + * @vregs: Array of dsi_vreg structures. + * @count: Number of vregs. + * @refcount: Reference counting for enabling. + */ +struct dsi_regulator_info { + struct dsi_vreg *vregs; + u32 count; + u32 refcount; +}; + +/** + * dsi_pwr_of_get_vreg_data - parse regulator supply information + * @of_node: Device of node to parse for supply information. + * @regs: Pointer where regulator information will be copied to. + * @supply_name: Name of the supply node. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_of_get_vreg_data(struct dsi_parser_utils *utils, + struct dsi_regulator_info *regs, + char *supply_name); + +/** + * dsi_pwr_get_dt_vreg_data - parse regulator supply information + * @dev: Device whose of_node needs to be parsed. + * @regs: Pointer where regulator information will be copied to. + * @supply_name: Name of the supply node. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_get_dt_vreg_data(struct device *dev, + struct dsi_regulator_info *regs, + char *supply_name); + +/** + * dsi_pwr_enable_regulator() - enable a set of regulators + * @regs: Pointer to set of regulators to enable or disable. + * @enable: Enable/Disable regulators. + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable); + +/** + * dsi_pwr_panel_regulator_mode_set() + * set regulator mode for OLED panel + * @regs: Pointer to set of regulators to enable or disable. + * @reg_name: Panel regulator name + * @regulator_mode: Regulator mode values, like: + * REGULATOR_MODE_INVALID + * REGULATOR_MODE_FAST + * REGULATOR_MODE_NORMAL + * REGULATOR_MODE_IDLE + * REGULATOR_MODE_STANDBY + * + * return: error code in case of failure or 0 for success. + */ +int dsi_pwr_panel_regulator_mode_set(struct dsi_regulator_info *regs, + const char *reg_name, + int regulator_mode); +#endif /* _DSI_PWR_H_ */ diff --git a/techpack/display/msm/msm_atomic.c b/techpack/display/msm/msm_atomic.c new file mode 100644 index 0000000000000000000000000000000000000000..6f27ed8527d44910189c41207ca46457815f2583 --- /dev/null +++ b/techpack/display/msm/msm_atomic.c @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2014 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <drm/drm_panel.h> + +#include "msm_drv.h" +#include "msm_gem.h" +#include "msm_kms.h" +#include "sde_trace.h" + +#define MULTIPLE_CONN_DETECTED(x) (x > 1) + +struct msm_commit { + struct drm_device *dev; + struct drm_atomic_state *state; + uint32_t crtc_mask; + uint32_t plane_mask; + bool nonblock; + struct kthread_work commit_work; +}; + +static inline bool _msm_seamless_for_crtc(struct drm_device *dev, + struct drm_atomic_state *state, + struct drm_crtc_state *crtc_state, bool enable) +{ + struct drm_connector *connector = NULL; + struct drm_connector_state *conn_state = NULL; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + int i = 0; + int conn_cnt = 0; + bool splash_en = false; + + if (msm_is_mode_seamless(&crtc_state->mode) || + msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode) || + msm_is_mode_seamless_poms(&crtc_state->adjusted_mode) || + msm_is_mode_seamless_dyn_clk(&crtc_state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable) + return true; + + if (!crtc_state->mode_changed && crtc_state->connectors_changed) { + for_each_old_connector_in_state(state, connector, + conn_state, i) { + if ((conn_state->crtc == crtc_state->crtc) || + (connector->state->crtc == + crtc_state->crtc)) + conn_cnt++; + + if (kms && kms->funcs && kms->funcs->check_for_splash) + splash_en = kms->funcs->check_for_splash(kms, + crtc_state->crtc); + + if (MULTIPLE_CONN_DETECTED(conn_cnt) && !splash_en) + return true; + } + } + + return false; +} + +static inline bool _msm_seamless_for_conn(struct drm_connector *connector, + struct drm_connector_state *old_conn_state, bool enable) +{ + if (!old_conn_state || !old_conn_state->crtc) + return false; + + if (!old_conn_state->crtc->state->mode_changed && + !old_conn_state->crtc->state->active_changed && + old_conn_state->crtc->state->connectors_changed) { + if (old_conn_state->crtc == connector->state->crtc) + return true; + } + + if (enable) + return false; + + if (!connector->state->crtc && + old_conn_state->crtc->state->connectors_changed) + return false; + + if (msm_is_mode_seamless(&connector->encoder->crtc->state->mode)) + return true; + + if (msm_is_mode_seamless_vrr( + &connector->encoder->crtc->state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dyn_clk( + &connector->encoder->crtc->state->adjusted_mode)) + return true; + + if (msm_is_mode_seamless_dms( + &connector->encoder->crtc->state->adjusted_mode)) + return true; + + return false; +} + +/* clear specified crtcs (no longer pending update) */ +static void commit_destroy(struct msm_commit *c) +{ + struct msm_drm_private *priv = c->dev->dev_private; + uint32_t crtc_mask = c->crtc_mask; + uint32_t plane_mask = c->plane_mask; + + /* End_atomic */ + spin_lock(&priv->pending_crtcs_event.lock); + DBG("end: %08x", crtc_mask); + priv->pending_crtcs &= ~crtc_mask; + priv->pending_planes &= ~plane_mask; + wake_up_all_locked(&priv->pending_crtcs_event); + spin_unlock(&priv->pending_crtcs_event.lock); + + if (c->nonblock) + kfree(c); +} + +static void msm_atomic_wait_for_commit_done( + struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *new_crtc_state; + struct msm_drm_private *priv = old_state->dev->dev_private; + struct msm_kms *kms = priv->kms; + int i; + + for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) { + if (!new_crtc_state->active) + continue; + + kms->funcs->wait_for_crtc_commit_done(kms, crtc); + } +} + +static void +msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) +{ + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + int i; + + SDE_ATRACE_BEGIN("msm_disable"); + for_each_old_connector_in_state(old_state, connector, + old_conn_state, i) { + const struct drm_encoder_helper_funcs *funcs; + struct drm_encoder *encoder; + struct drm_crtc_state *old_crtc_state; + + /* + * Shut down everything that's in the changeset and currently + * still on. So need to check the old, saved state. + */ + if (!old_conn_state->crtc) + continue; + + old_crtc_state = drm_atomic_get_old_crtc_state(old_state, + old_conn_state->crtc); + + if (!old_crtc_state->active || + !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state)) + continue; + + encoder = old_conn_state->best_encoder; + + /* We shouldn't get this far if we didn't previously have + * an encoder.. but WARN_ON() rather than explode. + */ + if (WARN_ON(!encoder)) + continue; + + if (_msm_seamless_for_conn(connector, old_conn_state, false)) + continue; + + funcs = encoder->helper_private; + + DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + /* + * Each encoder has at most one connector (since we always steal + * it away), so we won't call disable hooks twice. + */ + drm_bridge_disable(encoder->bridge); + + /* Right function depends upon target state. */ + if (connector->state->crtc && funcs->prepare) + funcs->prepare(encoder); + else if (funcs->disable) + funcs->disable(encoder); + else + funcs->dpms(encoder, DRM_MODE_DPMS_OFF); + + drm_bridge_post_disable(encoder->bridge); + } + + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { + const struct drm_crtc_helper_funcs *funcs; + + /* Shut down everything that needs a full modeset. */ + if (!drm_atomic_crtc_needs_modeset(crtc->state)) + continue; + + if (!old_crtc_state->active) + continue; + + if (_msm_seamless_for_crtc(dev, old_state, crtc->state, false)) + continue; + + funcs = crtc->helper_private; + + DRM_DEBUG_ATOMIC("disabling [CRTC:%d]\n", + crtc->base.id); + + /* Right function depends upon target state. */ + if (crtc->state->enable && funcs->prepare) + funcs->prepare(crtc); + else if (funcs->disable) + funcs->disable(crtc); + else + funcs->dpms(crtc, DRM_MODE_DPMS_OFF); + } + SDE_ATRACE_END("msm_disable"); +} + +static void +msm_crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + int i; + + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { + const struct drm_crtc_helper_funcs *funcs; + + if (!crtc->state->mode_changed) + continue; + + funcs = crtc->helper_private; + + if (crtc->state->enable && funcs->mode_set_nofb) { + DRM_DEBUG_ATOMIC("modeset on [CRTC:%d]\n", + crtc->base.id); + + funcs->mode_set_nofb(crtc); + } + } + + for_each_old_connector_in_state(old_state, connector, + old_conn_state, i) { + const struct drm_encoder_helper_funcs *funcs; + struct drm_crtc_state *new_crtc_state; + struct drm_encoder *encoder; + struct drm_display_mode *mode, *adjusted_mode; + + if (!connector->state->best_encoder) + continue; + + encoder = connector->state->best_encoder; + funcs = encoder->helper_private; + new_crtc_state = connector->state->crtc->state; + mode = &new_crtc_state->mode; + adjusted_mode = &new_crtc_state->adjusted_mode; + + if (!new_crtc_state->mode_changed && + new_crtc_state->connectors_changed) { + if (_msm_seamless_for_conn(connector, + old_conn_state, false)) + continue; + } else if (!new_crtc_state->mode_changed) { + continue; + } + + DRM_DEBUG_ATOMIC("modeset on [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + SDE_ATRACE_BEGIN("msm_set_mode"); + /* + * Each encoder has at most one connector (since we always steal + * it away), so we won't call mode_set hooks twice. + */ + if (funcs->mode_set) + funcs->mode_set(encoder, mode, adjusted_mode); + + drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode); + SDE_ATRACE_END("msm_set_mode"); + } +} + +/** + * msm_atomic_helper_commit_modeset_disables - modeset commit to disable outputs + * @dev: DRM device + * @old_state: atomic state object with old state structures + * + * This function shuts down all the outputs that need to be shut down and + * prepares them (if required) with the new mode. + * + * For compatibility with legacy crtc helpers this should be called before + * drm_atomic_helper_commit_planes(), which is what the default commit function + * does. But drivers with different needs can group the modeset commits together + * and do the plane commits at the end. This is useful for drivers doing runtime + * PM since planes updates then only happen when the CRTC is actually enabled. + */ +void msm_atomic_helper_commit_modeset_disables(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + msm_disable_outputs(dev, old_state); + + drm_atomic_helper_update_legacy_modeset_state(dev, old_state); + + msm_crtc_set_mode(dev, old_state); +} + +/** + * msm_atomic_helper_commit_modeset_enables - modeset commit to enable outputs + * @dev: DRM device + * @old_state: atomic state object with old state structures + * + * This function enables all the outputs with the new configuration which had to + * be turned off for the update. + * + * For compatibility with legacy crtc helpers this should be called after + * drm_atomic_helper_commit_planes(), which is what the default commit function + * does. But drivers with different needs can group the modeset commits together + * and do the plane commits at the end. This is useful for drivers doing runtime + * PM since planes updates then only happen when the CRTC is actually enabled. + */ +static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_crtc_state *new_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *new_conn_state; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + int bridge_enable_count = 0; + int i; + + SDE_ATRACE_BEGIN("msm_enable"); + for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, + new_crtc_state, i) { + const struct drm_crtc_helper_funcs *funcs; + + /* Need to filter out CRTCs where only planes change. */ + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + continue; + + if (!new_crtc_state->active) + continue; + + if (_msm_seamless_for_crtc(dev, old_state, crtc->state, true)) + continue; + + funcs = crtc->helper_private; + + if (crtc->state->enable) { + DRM_DEBUG_ATOMIC("enabling [CRTC:%d]\n", + crtc->base.id); + + if (funcs->atomic_enable) + funcs->atomic_enable(crtc, old_crtc_state); + else + funcs->commit(crtc); + } + + if (msm_needs_vblank_pre_modeset( + &new_crtc_state->adjusted_mode)) + drm_crtc_wait_one_vblank(crtc); + + } + + for_each_new_connector_in_state(old_state, connector, + new_conn_state, i) { + const struct drm_encoder_helper_funcs *funcs; + struct drm_encoder *encoder; + struct drm_connector_state *old_conn_state; + + if (!new_conn_state->best_encoder) + continue; + + if (!new_conn_state->crtc->state->active || + !drm_atomic_crtc_needs_modeset( + new_conn_state->crtc->state)) + continue; + + old_conn_state = drm_atomic_get_old_connector_state( + old_state, connector); + if (_msm_seamless_for_conn(connector, old_conn_state, true)) + continue; + + encoder = connector->state->best_encoder; + funcs = encoder->helper_private; + + DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + /* + * Each encoder has at most one connector (since we always steal + * it away), so we won't call enable hooks twice. + */ + drm_bridge_pre_enable(encoder->bridge); + ++bridge_enable_count; + + if (funcs->enable) + funcs->enable(encoder); + else + funcs->commit(encoder); + } + + if (kms && kms->funcs && kms->funcs->commit) { + DRM_DEBUG_ATOMIC("triggering commit\n"); + kms->funcs->commit(kms, old_state); + } + + /* If no bridges were pre_enabled, skip iterating over them again */ + if (bridge_enable_count == 0) { + SDE_ATRACE_END("msm_enable"); + return; + } + + for_each_new_connector_in_state(old_state, connector, + new_conn_state, i) { + struct drm_encoder *encoder; + struct drm_connector_state *old_conn_state; + + if (!new_conn_state->best_encoder) + continue; + + if (!new_conn_state->crtc->state->active || + !drm_atomic_crtc_needs_modeset( + new_conn_state->crtc->state)) + continue; + + old_conn_state = drm_atomic_get_old_connector_state( + old_state, connector); + if (_msm_seamless_for_conn(connector, old_conn_state, true)) + continue; + + encoder = connector->state->best_encoder; + + DRM_DEBUG_ATOMIC("bridge enable enabling [ENCODER:%d:%s]\n", + encoder->base.id, encoder->name); + + drm_bridge_enable(encoder->bridge); + } + SDE_ATRACE_END("msm_enable"); +} + +int msm_atomic_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct msm_drm_private *priv = plane->dev->dev_private; + struct msm_kms *kms = priv->kms; + struct drm_gem_object *obj; + struct msm_gem_object *msm_obj; + struct dma_fence *fence; + + if (!new_state->fb) + return 0; + + obj = msm_framebuffer_bo(new_state->fb, 0); + msm_obj = to_msm_bo(obj); + fence = reservation_object_get_excl_rcu(msm_obj->resv); + + drm_atomic_set_fence_for_plane(new_state, fence); + + return msm_framebuffer_prepare(new_state->fb, kms->aspace); +} + +/* The (potentially) asynchronous part of the commit. At this point + * nothing can fail short of armageddon. + */ +static void complete_commit(struct msm_commit *c) +{ + struct drm_atomic_state *state = c->state; + struct drm_device *dev = state->dev; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + drm_atomic_helper_wait_for_fences(dev, state, false); + + kms->funcs->prepare_commit(kms, state); + + msm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_planes(dev, state, + DRM_PLANE_COMMIT_ACTIVE_ONLY); + + msm_atomic_helper_commit_modeset_enables(dev, state); + + /* NOTE: _wait_for_vblanks() only waits for vblank on + * enabled CRTCs. So we end up faulting when disabling + * due to (potentially) unref'ing the outgoing fb's + * before the vblank when the disable has latched. + * + * But if it did wait on disabled (or newly disabled) + * CRTCs, that would be racy (ie. we could have missed + * the irq. We need some way to poll for pipe shut + * down. Or just live with occasionally hitting the + * timeout in the CRTC disable path (which really should + * not be critical path) + */ + + msm_atomic_wait_for_commit_done(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + kms->funcs->complete_commit(kms, state); + + drm_atomic_state_put(state); + + priv->commit_end_time = ktime_get(); //commit end time + commit_destroy(c); +} + +static void _msm_drm_commit_work_cb(struct kthread_work *work) +{ + struct msm_commit *commit = NULL; + + if (!work) { + DRM_ERROR("%s: Invalid commit work data!\n", __func__); + return; + } + + commit = container_of(work, struct msm_commit, commit_work); + + SDE_ATRACE_BEGIN("complete_commit"); + complete_commit(commit); + SDE_ATRACE_END("complete_commit"); +} + +static struct msm_commit *commit_init(struct drm_atomic_state *state, + bool nonblock) +{ + struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL); + + if (!c) + return NULL; + + c->dev = state->dev; + c->state = state; + c->nonblock = nonblock; + + kthread_init_work(&c->commit_work, _msm_drm_commit_work_cb); + + return c; +} + +/* Start display thread function */ +static void msm_atomic_commit_dispatch(struct drm_device *dev, + struct drm_atomic_state *state, struct msm_commit *commit) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_crtc *crtc = NULL; + struct drm_crtc_state *crtc_state = NULL; + int ret = -ECANCELED, i = 0, j = 0; + bool nonblock; + + /* cache since work will kfree commit in non-blocking case */ + nonblock = commit->nonblock; + + for_each_old_crtc_in_state(state, crtc, crtc_state, i) { + for (j = 0; j < priv->num_crtcs; j++) { + if (priv->disp_thread[j].crtc_id == + crtc->base.id) { + if (priv->disp_thread[j].thread) { + kthread_queue_work( + &priv->disp_thread[j].worker, + &commit->commit_work); + /* only return zero if work is + * queued successfully. + */ + ret = 0; + } else { + DRM_ERROR(" Error for crtc_id: %d\n", + priv->disp_thread[j].crtc_id); + ret = -EINVAL; + } + break; + } + } + /* + * TODO: handle cases where there will be more than + * one crtc per commit cycle. Remove this check then. + * Current assumption is there will be only one crtc + * per commit cycle. + */ + if (j < priv->num_crtcs) + break; + } + + if (ret) { + if (ret == -EINVAL) + DRM_ERROR("failed to dispatch commit to any CRTC\n"); + else + DRM_DEBUG_DRIVER_RATELIMITED("empty crtc state\n"); + + /** + * this is not expected to happen, but at this point the state + * has been swapped, but we couldn't dispatch to a crtc thread. + * fallback now to a synchronous complete_commit to try and + * ensure that SW and HW state don't get out of sync. + */ + complete_commit(commit); + } else if (!nonblock) { + kthread_flush_work(&commit->commit_work); + } + + /* free nonblocking commits in this context, after processing */ + if (!nonblock) + kfree(commit); +} + +/** + * drm_atomic_helper_commit - commit validated state object + * @dev: DRM device + * @state: the driver state object + * @nonblock: nonblocking commit + * + * This function commits a with drm_atomic_helper_check() pre-validated state + * object. This can still fail when e.g. the framebuffer reservation fails. + * + * RETURNS + * Zero for success or -errno. + */ +int msm_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, bool nonblock) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_commit *c; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_plane *plane; + struct drm_plane_state *old_plane_state, *new_plane_state; + int i, ret; + + if (!priv || priv->shutdown_in_progress) { + DRM_ERROR("priv is null or shutdwon is in-progress\n"); + return -EINVAL; + } + + SDE_ATRACE_BEGIN("atomic_commit"); + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) { + SDE_ATRACE_END("atomic_commit"); + return ret; + } + + c = commit_init(state, nonblock); + if (!c) { + ret = -ENOMEM; + goto error; + } + + /* + * Figure out what crtcs we have: + */ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) + c->crtc_mask |= drm_crtc_mask(crtc); + + /* + * Figure out what fence to wait for: + */ + for_each_oldnew_plane_in_state(state, plane, old_plane_state, + new_plane_state, i) { + if ((new_plane_state->fb != old_plane_state->fb) + && new_plane_state->fb) { + struct drm_gem_object *obj = + msm_framebuffer_bo(new_plane_state->fb, 0); + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct dma_fence *fence = + reservation_object_get_excl_rcu(msm_obj->resv); + + drm_atomic_set_fence_for_plane(new_plane_state, fence); + } + c->plane_mask |= (1 << drm_plane_index(plane)); + } + + /* Protection for prepare_fence callback */ +retry: + ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, + state->acquire_ctx); + + if (ret == -EDEADLK) { + drm_modeset_backoff(state->acquire_ctx); + goto retry; + } + + /* + * Wait for pending updates on any of the same crtc's and then + * mark our set of crtc's as busy: + */ + + /* Start Atomic */ + spin_lock(&priv->pending_crtcs_event.lock); + ret = wait_event_interruptible_locked(priv->pending_crtcs_event, + !(priv->pending_crtcs & c->crtc_mask) && + !(priv->pending_planes & c->plane_mask)); + if (ret == 0) { + DBG("start: %08x", c->crtc_mask); + priv->pending_crtcs |= c->crtc_mask; + priv->pending_planes |= c->plane_mask; + } + spin_unlock(&priv->pending_crtcs_event.lock); + + if (ret) + goto err_free; + + WARN_ON(drm_atomic_helper_swap_state(state, false) < 0); + + /* + * Provide the driver a chance to prepare for output fences. This is + * done after the point of no return, but before asynchronous commits + * are dispatched to work queues, so that the fence preparation is + * finished before the .atomic_commit returns. + */ + if (priv && priv->kms && priv->kms->funcs && + priv->kms->funcs->prepare_fence) + priv->kms->funcs->prepare_fence(priv->kms, state); + + /* + * Everything below can be run asynchronously without the need to grab + * any modeset locks at all under one conditions: It must be guaranteed + * that the asynchronous work has either been cancelled (if the driver + * supports it, which at least requires that the framebuffers get + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed + * before the new state gets committed on the software side with + * drm_atomic_helper_swap_state(). + * + * This scheme allows new atomic state updates to be prepared and + * checked in parallel to the asynchronous completion of the previous + * update. Which is important since compositors need to figure out the + * composition of the next frame right after having submitted the + * current layout + */ + + drm_atomic_state_get(state); + msm_atomic_commit_dispatch(dev, state, c); + + SDE_ATRACE_END("atomic_commit"); + + return 0; +err_free: + kfree(c); +error: + drm_atomic_helper_cleanup_planes(dev, state); + SDE_ATRACE_END("atomic_commit"); + return ret; +} + +struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev) +{ + struct msm_kms_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state || drm_atomic_state_init(dev, &state->base) < 0) { + kfree(state); + return NULL; + } + + return &state->base; +} + +void msm_atomic_state_clear(struct drm_atomic_state *s) +{ + struct msm_kms_state *state = to_kms_state(s); + + drm_atomic_state_default_clear(&state->base); + kfree(state->state); + state->state = NULL; +} + +void msm_atomic_state_free(struct drm_atomic_state *state) +{ + kfree(to_kms_state(state)->state); + drm_atomic_state_default_release(state); + kfree(state); +} + +void msm_atomic_commit_tail(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + kms->funcs->prepare_commit(kms, state); + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_planes(dev, state, 0); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + msm_atomic_wait_for_commit_done(dev, state); + + kms->funcs->complete_commit(kms, state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_commit_hw_done(state); + + drm_atomic_helper_cleanup_planes(dev, state); +} diff --git a/techpack/display/msm/msm_drv.c b/techpack/display/msm/msm_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..09124218e245693b951b0d1c69c283c3fd1a85dd --- /dev/null +++ b/techpack/display/msm/msm_drv.c @@ -0,0 +1,2089 @@ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ +/* + * Copyright (c) 2016 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include <linux/of_address.h> +#include <linux/kthread.h> +#include <uapi/linux/sched/types.h> +#include <drm/drm_of.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "msm_mmu.h" +#include "sde_wb.h" +#include "sde_dbg.h" + +/* + * MSM driver version: + * - 1.0.0 - initial interface + * - 1.1.0 - adds madvise, and support for submits with > 4 cmd buffers + * - 1.2.0 - adds explicit fence support for submit ioctl + * - 1.3.0 - adds GMEM_BASE + NR_RINGS params, SUBMITQUEUE_NEW + + * SUBMITQUEUE_CLOSE ioctls, and MSM_INFO_IOVA flag for + * MSM_GEM_INFO ioctl. + */ +#define MSM_VERSION_MAJOR 1 +#define MSM_VERSION_MINOR 3 +#define MSM_VERSION_PATCHLEVEL 0 + +static void msm_fb_output_poll_changed(struct drm_device *dev) +{ + struct msm_drm_private *priv = NULL; + + if (!dev) { + DRM_ERROR("output_poll_changed failed, invalid input\n"); + return; + } + + priv = dev->dev_private; + + if (priv->fbdev) + drm_fb_helper_hotplug_event(priv->fbdev); +} + +/** + * msm_atomic_helper_check - validate state object + * @dev: DRM device + * @state: the driver state object + * + * This is a wrapper for the drm_atomic_helper_check to check the modeset + * and state checking for planes. Additionally it checks if any secure + * transition(moving CRTC and planes between secure and non-secure states and + * vice versa) is allowed or not. When going to secure state, planes + * with fb_mode as dir translated only can be staged on the CRTC, and only one + * CRTC should be active. + * Also mixing of secure and non-secure is not allowed. + * + * RETURNS + * Zero for success or -errorno. + */ +int msm_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct msm_drm_private *priv; + + priv = dev->dev_private; + if (priv && priv->kms && priv->kms->funcs && + priv->kms->funcs->atomic_check) + return priv->kms->funcs->atomic_check(priv->kms, state); + + return drm_atomic_helper_check(dev, state); +} + +static const struct drm_mode_config_funcs mode_config_funcs = { + .fb_create = msm_framebuffer_create, + .output_poll_changed = msm_fb_output_poll_changed, + .atomic_check = msm_atomic_check, + .atomic_commit = msm_atomic_commit, + .atomic_state_alloc = msm_atomic_state_alloc, + .atomic_state_clear = msm_atomic_state_clear, + .atomic_state_free = msm_atomic_state_free, +}; + +static const struct drm_mode_config_helper_funcs mode_config_helper_funcs = { + .atomic_commit_tail = msm_atomic_commit_tail, +}; + +#ifdef CONFIG_DRM_MSM_REGISTER_LOGGING +static bool reglog = false; +MODULE_PARM_DESC(reglog, "Enable register read/write logging"); +module_param(reglog, bool, 0600); +#else +#define reglog 0 +#endif + +#ifdef CONFIG_DRM_FBDEV_EMULATION +static bool fbdev = true; +MODULE_PARM_DESC(fbdev, "Enable fbdev compat layer"); +module_param(fbdev, bool, 0600); +#endif + +static char *vram = "16m"; +MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU)"); +module_param(vram, charp, 0); + +bool dumpstate = false; +MODULE_PARM_DESC(dumpstate, "Dump KMS state on errors"); +module_param(dumpstate, bool, 0600); + +static bool modeset = true; +MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (1=on (default), 0=disable)"); +module_param(modeset, bool, 0600); + +/* + * Util/helpers: + */ + +int msm_clk_bulk_get(struct device *dev, struct clk_bulk_data **bulk) +{ + struct property *prop; + const char *name; + struct clk_bulk_data *local; + int i = 0, ret, count; + + count = of_property_count_strings(dev->of_node, "clock-names"); + if (count < 1) + return 0; + + local = devm_kcalloc(dev, sizeof(struct clk_bulk_data *), + count, GFP_KERNEL); + if (!local) + return -ENOMEM; + + of_property_for_each_string(dev->of_node, "clock-names", prop, name) { + local[i].id = devm_kstrdup(dev, name, GFP_KERNEL); + if (!local[i].id) { + devm_kfree(dev, local); + return -ENOMEM; + } + + i++; + } + + ret = devm_clk_bulk_get(dev, count, local); + + if (ret) { + for (i = 0; i < count; i++) + devm_kfree(dev, (void *) local[i].id); + devm_kfree(dev, local); + + return ret; + } + + *bulk = local; + return count; +} + +struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count, + const char *name) +{ + int i; + char n[32]; + + snprintf(n, sizeof(n), "%s_clk", name); + + for (i = 0; bulk && i < count; i++) { + if (!strcmp(bulk[i].id, name) || !strcmp(bulk[i].id, n)) + return bulk[i].clk; + } + + + return NULL; +} + +struct clk *msm_clk_get(struct platform_device *pdev, const char *name) +{ + struct clk *clk; + char name2[32]; + + clk = devm_clk_get(&pdev->dev, name); + if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER) + return clk; + + snprintf(name2, sizeof(name2), "%s_clk", name); + + clk = devm_clk_get(&pdev->dev, name2); + if (!IS_ERR(clk)) + dev_warn(&pdev->dev, "Using legacy clk name binding. Use " + "\"%s\" instead of \"%s\"\n", name, name2); + + return clk; +} + +void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, + const char *dbgname) +{ + struct resource *res; + unsigned long size; + void __iomem *ptr; + + if (name) + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + else + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_dbg(&pdev->dev, "failed to get memory resource: %s\n", + name); + return ERR_PTR(-EINVAL); + } + + size = resource_size(res); + + ptr = devm_ioremap_nocache(&pdev->dev, res->start, size); + if (!ptr) { + dev_err(&pdev->dev, "failed to ioremap: %s\n", name); + return ERR_PTR(-ENOMEM); + } + + if (reglog) + dev_dbg(&pdev->dev, "IO:region %s %pK %08lx\n", + dbgname, ptr, size); + + return ptr; +} + +unsigned long msm_iomap_size(struct platform_device *pdev, const char *name) +{ + struct resource *res; + + if (name) + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); + else + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_dbg(&pdev->dev, "failed to get memory resource: %s\n", + name); + return 0; + } + + return resource_size(res); +} + +void msm_iounmap(struct platform_device *pdev, void __iomem *addr) +{ + devm_iounmap(&pdev->dev, addr); +} + +void msm_writel(u32 data, void __iomem *addr) +{ + if (reglog) + pr_debug("IO:W %pK %08x\n", addr, data); + writel(data, addr); +} + +u32 msm_readl(const void __iomem *addr) +{ + u32 val = readl(addr); + + if (reglog) + pr_err("IO:R %pK %08x\n", addr, val); + return val; +} + +struct vblank_work { + struct kthread_work work; + int crtc_id; + bool enable; + struct msm_drm_private *priv; +}; + +static void vblank_ctrl_worker(struct kthread_work *work) +{ + struct vblank_work *cur_work = container_of(work, + struct vblank_work, work); + struct msm_drm_private *priv = cur_work->priv; + struct msm_kms *kms = priv->kms; + + if (cur_work->enable) + kms->funcs->enable_vblank(kms, priv->crtcs[cur_work->crtc_id]); + else + kms->funcs->disable_vblank(kms, priv->crtcs[cur_work->crtc_id]); + + kfree(cur_work); +} + +static int vblank_ctrl_queue_work(struct msm_drm_private *priv, + int crtc_id, bool enable) +{ + struct vblank_work *cur_work; + struct drm_crtc *crtc; + struct kthread_worker *worker; + + if (!priv || crtc_id >= priv->num_crtcs) + return -EINVAL; + + cur_work = kzalloc(sizeof(*cur_work), GFP_ATOMIC); + if (!cur_work) + return -ENOMEM; + + crtc = priv->crtcs[crtc_id]; + + kthread_init_work(&cur_work->work, vblank_ctrl_worker); + cur_work->crtc_id = crtc_id; + cur_work->enable = enable; + cur_work->priv = priv; + worker = &priv->event_thread[crtc_id].worker; + + kthread_queue_work(worker, &cur_work->work); + return 0; +} + +static int msm_drm_uninit(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = ddev->dev_private; + struct msm_kms *kms = priv->kms; + int i; + + /* clean up display commit/event worker threads */ + for (i = 0; i < priv->num_crtcs; i++) { + if (priv->disp_thread[i].thread) { + kthread_flush_worker(&priv->disp_thread[i].worker); + kthread_stop(priv->disp_thread[i].thread); + priv->disp_thread[i].thread = NULL; + } + + if (priv->event_thread[i].thread) { + kthread_flush_worker(&priv->event_thread[i].worker); + kthread_stop(priv->event_thread[i].thread); + priv->event_thread[i].thread = NULL; + } + } + + drm_kms_helper_poll_fini(ddev); + + drm_mode_config_cleanup(ddev); + + if (priv->registered) { + drm_dev_unregister(ddev); + priv->registered = false; + } + +#ifdef CONFIG_DRM_FBDEV_EMULATION + if (fbdev && priv->fbdev) + msm_fbdev_free(ddev); +#endif + drm_mode_config_cleanup(ddev); + + pm_runtime_get_sync(dev); + drm_irq_uninstall(ddev); + pm_runtime_put_sync(dev); + + flush_workqueue(priv->wq); + destroy_workqueue(priv->wq); + + if (kms && kms->funcs) + kms->funcs->destroy(kms); + + if (priv->vram.paddr) { + unsigned long attrs = DMA_ATTR_NO_KERNEL_MAPPING; + drm_mm_takedown(&priv->vram.mm); + dma_free_attrs(dev, priv->vram.size, NULL, + priv->vram.paddr, attrs); + } + + component_unbind_all(dev, ddev); + + sde_dbg_destroy(); + debugfs_remove_recursive(priv->debug_root); + + sde_power_resource_deinit(pdev, &priv->phandle); + + msm_mdss_destroy(ddev); + + ddev->dev_private = NULL; + kfree(priv); + + drm_dev_put(ddev); + + return 0; +} + +#define KMS_MDP4 4 +#define KMS_MDP5 5 +#define KMS_SDE 3 + +static int get_mdp_ver(struct platform_device *pdev) +{ +#ifdef CONFIG_OF + static const struct of_device_id match_types[] = { { + .compatible = "qcom,mdss_mdp", + .data = (void *)KMS_MDP5, + }, + { + .compatible = "qcom,sde-kms", + .data = (void *)KMS_SDE, + }, + {}, + }; + struct device *dev = &pdev->dev; + const struct of_device_id *match; + + match = of_match_node(match_types, dev->of_node); + if (match) + return (int)(unsigned long)match->data; +#endif + return KMS_MDP4; +} + +static int msm_init_vram(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct device_node *node; + unsigned long size = 0; + int ret = 0; + + /* In the device-tree world, we could have a 'memory-region' + * phandle, which gives us a link to our "vram". Allocating + * is all nicely abstracted behind the dma api, but we need + * to know the entire size to allocate it all in one go. There + * are two cases: + * 1) device with no IOMMU, in which case we need exclusive + * access to a VRAM carveout big enough for all gpu + * buffers + * 2) device with IOMMU, but where the bootloader puts up + * a splash screen. In this case, the VRAM carveout + * need only be large enough for fbdev fb. But we need + * exclusive access to the buffer to avoid the kernel + * using those pages for other purposes (which appears + * as corruption on screen before we have a chance to + * load and do initial modeset) + */ + + node = of_parse_phandle(dev->dev->of_node, "memory-region", 0); + if (node) { + struct resource r; + ret = of_address_to_resource(node, 0, &r); + of_node_put(node); + if (ret) + return ret; + size = r.end - r.start; + DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start); + + /* if we have no IOMMU, then we need to use carveout allocator. + * Grab the entire CMA chunk carved out in early startup in + * mach-msm: + */ + } else if (!iommu_present(&platform_bus_type)) { + DRM_INFO("using %s VRAM carveout\n", vram); + size = memparse(vram, NULL); + } + + if (size) { + unsigned long attrs = 0; + void *p; + + priv->vram.size = size; + + drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1); + spin_lock_init(&priv->vram.lock); + + attrs |= DMA_ATTR_NO_KERNEL_MAPPING; + attrs |= DMA_ATTR_WRITE_COMBINE; + + /* note that for no-kernel-mapping, the vaddr returned + * is bogus, but non-null if allocation succeeded: + */ + p = dma_alloc_attrs(dev->dev, size, + &priv->vram.paddr, GFP_KERNEL, attrs); + if (!p) { + dev_err(dev->dev, "failed to allocate VRAM\n"); + priv->vram.paddr = 0; + return -ENOMEM; + } + + dev_info(dev->dev, "VRAM: %08x->%08x\n", + (uint32_t)priv->vram.paddr, + (uint32_t)(priv->vram.paddr + size)); + } + + return ret; +} + +#ifdef CONFIG_OF +static int msm_component_bind_all(struct device *dev, + struct drm_device *drm_dev) +{ + int ret; + + ret = component_bind_all(dev, drm_dev); + if (ret) + DRM_ERROR("component_bind_all failed: %d\n", ret); + + return ret; +} +#else +static int msm_component_bind_all(struct device *dev, + struct drm_device *drm_dev) +{ + return 0; +} +#endif + +static int msm_drm_display_thread_create(struct sched_param param, + struct msm_drm_private *priv, struct drm_device *ddev, + struct device *dev) +{ + int i, ret = 0; + + /** + * this priority was found during empiric testing to have appropriate + * realtime scheduling to process display updates and interact with + * other real time and normal priority task + */ + param.sched_priority = 16; + for (i = 0; i < priv->num_crtcs; i++) { + + /* initialize display thread */ + priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id; + kthread_init_worker(&priv->disp_thread[i].worker); + priv->disp_thread[i].dev = ddev; + priv->disp_thread[i].thread = + kthread_run(kthread_worker_fn, + &priv->disp_thread[i].worker, + "crtc_commit:%d", priv->disp_thread[i].crtc_id); + ret = sched_setscheduler(priv->disp_thread[i].thread, + SCHED_FIFO, ¶m); + if (ret) + pr_warn("display thread priority update failed: %d\n", + ret); + + if (IS_ERR(priv->disp_thread[i].thread)) { + dev_err(dev, "failed to create crtc_commit kthread\n"); + priv->disp_thread[i].thread = NULL; + } + + /* initialize event thread */ + priv->event_thread[i].crtc_id = priv->crtcs[i]->base.id; + kthread_init_worker(&priv->event_thread[i].worker); + priv->event_thread[i].dev = ddev; + priv->event_thread[i].thread = + kthread_run(kthread_worker_fn, + &priv->event_thread[i].worker, + "crtc_event:%d", priv->event_thread[i].crtc_id); + /** + * event thread should also run at same priority as disp_thread + * because it is handling frame_done events. A lower priority + * event thread and higher priority disp_thread can causes + * frame_pending counters beyond 2. This can lead to commit + * failure at crtc commit level. + */ + ret = sched_setscheduler(priv->event_thread[i].thread, + SCHED_FIFO, ¶m); + if (ret) + pr_warn("display event thread priority update failed: %d\n", + ret); + + if (IS_ERR(priv->event_thread[i].thread)) { + dev_err(dev, "failed to create crtc_event kthread\n"); + priv->event_thread[i].thread = NULL; + } + + if ((!priv->disp_thread[i].thread) || + !priv->event_thread[i].thread) { + /* clean up previously created threads if any */ + for ( ; i >= 0; i--) { + if (priv->disp_thread[i].thread) { + kthread_stop( + priv->disp_thread[i].thread); + priv->disp_thread[i].thread = NULL; + } + + if (priv->event_thread[i].thread) { + kthread_stop( + priv->event_thread[i].thread); + priv->event_thread[i].thread = NULL; + } + } + return -EINVAL; + } + } + + /** + * Since pp interrupt is heavy weight, try to queue the work + * into a dedicated worker thread, so that they dont interrupt + * other important events. + */ + kthread_init_worker(&priv->pp_event_worker); + priv->pp_event_thread = kthread_run(kthread_worker_fn, + &priv->pp_event_worker, "pp_event"); + + ret = sched_setscheduler(priv->pp_event_thread, + SCHED_FIFO, ¶m); + if (ret) + pr_warn("pp_event thread priority update failed: %d\n", + ret); + + if (IS_ERR(priv->pp_event_thread)) { + dev_err(dev, "failed to create pp_event kthread\n"); + ret = PTR_ERR(priv->pp_event_thread); + priv->pp_event_thread = NULL; + return ret; + } + + return 0; + +} +static struct msm_kms *_msm_drm_init_helper(struct msm_drm_private *priv, + struct drm_device *ddev, struct device *dev, + struct platform_device *pdev) +{ + int ret; + struct msm_kms *kms; + + switch (get_mdp_ver(pdev)) { + case KMS_MDP4: + kms = mdp4_kms_init(ddev); + break; + case KMS_MDP5: + kms = mdp5_kms_init(ddev); + break; + case KMS_SDE: + kms = sde_kms_init(ddev); + break; + default: + kms = ERR_PTR(-ENODEV); + break; + } + + if (IS_ERR_OR_NULL(kms)) { + /* + * NOTE: once we have GPU support, having no kms should not + * be considered fatal.. ideally we would still support gpu + * and (for example) use dmabuf/prime to share buffers with + * imx drm driver on iMX5 + */ + dev_err(dev, "failed to load kms\n"); + return kms; + } + priv->kms = kms; + pm_runtime_enable(dev); + + /** + * Since kms->funcs->hw_init(kms) might call + * drm_object_property_set_value to initialize some custom + * properties we need to make sure mode_config.funcs are populated + * beforehand to avoid dereferencing an unset value during the + * drm_drv_uses_atomic_modeset check. + */ + ddev->mode_config.funcs = &mode_config_funcs; + + ret = (kms)->funcs->hw_init(kms); + if (ret) { + dev_err(dev, "kms hw init failed: %d\n", ret); + return ERR_PTR(ret); + } + + return kms; +} + +static int msm_drm_init(struct device *dev, struct drm_driver *drv) +{ + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev; + struct msm_drm_private *priv; + struct msm_kms *kms = NULL; + int ret; + struct sched_param param = { 0 }; + struct drm_crtc *crtc; + + ddev = drm_dev_alloc(drv, dev); + if (!ddev) { + dev_err(dev, "failed to allocate drm_device\n"); + return -ENOMEM; + } + + drm_mode_config_init(ddev); + platform_set_drvdata(pdev, ddev); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto priv_alloc_fail; + } + + ddev->dev_private = priv; + priv->dev = ddev; + + ret = msm_mdss_init(ddev); + if (ret) + goto mdss_init_fail; + + priv->wq = alloc_ordered_workqueue("msm_drm", 0); + init_waitqueue_head(&priv->pending_crtcs_event); + + INIT_LIST_HEAD(&priv->client_event_list); + INIT_LIST_HEAD(&priv->inactive_list); + + ret = sde_power_resource_init(pdev, &priv->phandle); + if (ret) { + pr_err("sde power resource init failed\n"); + goto power_init_fail; + } + + ret = sde_dbg_init(&pdev->dev); + if (ret) { + dev_err(dev, "failed to init sde dbg: %d\n", ret); + goto dbg_init_fail; + } + + /* Bind all our sub-components: */ + ret = msm_component_bind_all(dev, ddev); + if (ret) + goto bind_fail; + + ret = msm_init_vram(ddev); + if (ret) + goto fail; + + ddev->mode_config.funcs = &mode_config_funcs; + ddev->mode_config.helper_private = &mode_config_helper_funcs; + + kms = _msm_drm_init_helper(priv, ddev, dev, pdev); + if (IS_ERR_OR_NULL(kms)) { + dev_err(dev, "msm_drm_init_helper failed\n"); + goto fail; + } + + ret = msm_drm_display_thread_create(param, priv, ddev, dev); + if (ret) { + dev_err(dev, "msm_drm_display_thread_create failed\n"); + goto fail; + } + + ret = drm_vblank_init(ddev, priv->num_crtcs); + if (ret < 0) { + dev_err(dev, "failed to initialize vblank\n"); + goto fail; + } + + drm_for_each_crtc(crtc, ddev) + drm_crtc_vblank_reset(crtc); + + if (kms) { + pm_runtime_get_sync(dev); + ret = drm_irq_install(ddev, platform_get_irq(pdev, 0)); + pm_runtime_put_sync(dev); + if (ret < 0) { + dev_err(dev, "failed to install IRQ handler\n"); + goto fail; + } + } + + ret = drm_dev_register(ddev, 0); + if (ret) + goto fail; + priv->registered = true; + + drm_mode_config_reset(ddev); + + if (kms && kms->funcs && kms->funcs->cont_splash_config) { + ret = kms->funcs->cont_splash_config(kms); + if (ret) { + dev_err(dev, "kms cont_splash config failed.\n"); + goto fail; + } + } + +#ifdef CONFIG_DRM_FBDEV_EMULATION + if (fbdev) + priv->fbdev = msm_fbdev_init(ddev); +#endif + + ret = sde_dbg_debugfs_register(dev); + if (ret) { + dev_err(dev, "failed to reg sde dbg debugfs: %d\n", ret); + goto fail; + } + + /* perform subdriver post initialization */ + if (kms && kms->funcs && kms->funcs->postinit) { + ret = kms->funcs->postinit(kms); + if (ret) { + pr_err("kms post init failed: %d\n", ret); + goto fail; + } + } + + drm_kms_helper_poll_init(ddev); + + return 0; + +fail: + msm_drm_uninit(dev); + return ret; +bind_fail: + sde_dbg_destroy(); +dbg_init_fail: + sde_power_resource_deinit(pdev, &priv->phandle); +power_init_fail: + msm_mdss_destroy(ddev); +mdss_init_fail: + kfree(priv); +priv_alloc_fail: + drm_dev_put(ddev); + return ret; +} + +/* + * DRM operations: + */ + +static int context_init(struct drm_device *dev, struct drm_file *file) +{ + struct msm_file_private *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mutex_init(&ctx->power_lock); + + file->driver_priv = ctx; + + if (dev && dev->dev_private) { + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms; + + kms = priv->kms; + if (kms && kms->funcs && kms->funcs->postopen) + kms->funcs->postopen(kms, file); + } + + return 0; +} + +static int msm_open(struct drm_device *dev, struct drm_file *file) +{ + return context_init(dev, file); +} + +static void context_close(struct msm_file_private *ctx) +{ + kfree(ctx); +} + +static void msm_preclose(struct drm_device *dev, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->preclose) + kms->funcs->preclose(kms, file); +} + +static void msm_postclose(struct drm_device *dev, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_file_private *ctx = file->driver_priv; + struct msm_kms *kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->postclose) + kms->funcs->postclose(kms, file); + + mutex_lock(&dev->struct_mutex); + if (ctx == priv->lastctx) + priv->lastctx = NULL; + mutex_unlock(&dev->struct_mutex); + + mutex_lock(&ctx->power_lock); + if (ctx->enable_refcnt) { + SDE_EVT32(ctx->enable_refcnt); + pm_runtime_put_sync(dev->dev); + } + mutex_unlock(&ctx->power_lock); + + context_close(ctx); +} + +static int msm_disable_all_modes_commit( + struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct drm_plane *plane; + struct drm_crtc *crtc; + unsigned int plane_mask; + int ret; + + plane_mask = 0; + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } + + plane_state->rotation = 0; + + plane->old_fb = plane->fb; + plane_mask |= 1 << drm_plane_index(plane); + + /* disable non-primary: */ + if (plane->type == DRM_PLANE_TYPE_PRIMARY) + continue; + + DRM_DEBUG("disabling plane %d\n", plane->base.id); + + ret = __drm_atomic_helper_disable_plane(plane, plane_state); + if (ret != 0) + DRM_ERROR("error %d disabling plane %d\n", ret, + plane->base.id); + } + + drm_for_each_crtc(crtc, dev) { + struct drm_mode_set mode_set; + + memset(&mode_set, 0, sizeof(struct drm_mode_set)); + mode_set.crtc = crtc; + + DRM_DEBUG("disabling crtc %d\n", crtc->base.id); + + ret = __drm_atomic_helper_set_config(&mode_set, state); + if (ret != 0) + DRM_ERROR("error %d disabling crtc %d\n", ret, + crtc->base.id); + } + + DRM_DEBUG("committing disables\n"); + ret = drm_atomic_commit(state); + +fail: + DRM_DEBUG("disables result %d\n", ret); + return ret; +} + +/** + * msm_clear_all_modes - disables all planes and crtcs via an atomic commit + * based on restore_fbdev_mode_atomic in drm_fb_helper.c + * @dev: device pointer + * @Return: 0 on success, otherwise -error + */ +static int msm_disable_all_modes( + struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + int ret, i; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = ctx; + + for (i = 0; i < TEARDOWN_DEADLOCK_RETRY_MAX; i++) { + ret = msm_disable_all_modes_commit(dev, state); + if (ret != -EDEADLK || ret != -ERESTARTSYS) + break; + drm_atomic_state_clear(state); + drm_modeset_backoff(ctx); + } + + drm_atomic_state_put(state); + + return ret; +} + +static void msm_lastclose(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + struct drm_modeset_acquire_ctx ctx; + int i, rc; + + /* check for splash status before triggering cleanup + * if we end up here with splash status ON i.e before first + * commit then ignore the last close call. Also, ignore + * if kms module is not yet initialized. + */ + if (!kms || (kms && kms->funcs && kms->funcs->check_for_splash + && kms->funcs->check_for_splash(kms, NULL))) + return; + + /* + * clean up vblank disable immediately as this is the last close. + */ + for (i = 0; i < dev->num_crtcs; i++) { + struct drm_vblank_crtc *vblank = &dev->vblank[i]; + struct timer_list *disable_timer = &vblank->disable_timer; + + if (del_timer_sync(disable_timer)) + disable_timer->function(disable_timer); + } + + /* wait for pending vblank requests to be executed by worker thread */ + flush_workqueue(priv->wq); + + if (priv->fbdev) { + drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev); + return; + } + + drm_modeset_acquire_init(&ctx, 0); +retry: + rc = drm_modeset_lock_all_ctx(dev, &ctx); + if (rc) + goto fail; + + rc = msm_disable_all_modes(dev, &ctx); + if (rc) + goto fail; + + if (kms && kms->funcs && kms->funcs->lastclose) + kms->funcs->lastclose(kms, &ctx); + +fail: + if (rc == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (rc) { + pr_err("last close failed: %d\n", rc); + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +static irqreturn_t msm_irq(int irq, void *arg) +{ + struct drm_device *dev = arg; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + BUG_ON(!kms); + return kms->funcs->irq(kms); +} + +static void msm_irq_preinstall(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + BUG_ON(!kms); + kms->funcs->irq_preinstall(kms); +} + +static int msm_irq_postinstall(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + BUG_ON(!kms); + return kms->funcs->irq_postinstall(kms); +} + +static void msm_irq_uninstall(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + BUG_ON(!kms); + kms->funcs->irq_uninstall(kms); +} + +static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + if (!kms) + return -ENXIO; + DBG("dev=%pK, crtc=%u", dev, pipe); + return vblank_ctrl_queue_work(priv, pipe, true); +} + +static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + if (!kms) + return; + DBG("dev=%pK, crtc=%u", dev, pipe); + vblank_ctrl_queue_work(priv, pipe, false); +} + +/* + * DRM ioctls: + */ + +static int msm_ioctl_gem_new(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_msm_gem_new *args = data; + + if (args->flags & ~MSM_BO_FLAGS) { + DRM_ERROR("invalid flags: %08x\n", args->flags); + return -EINVAL; + } + + return msm_gem_new_handle(dev, file, args->size, + args->flags, &args->handle); +} + +static inline ktime_t to_ktime(struct drm_msm_timespec timeout) +{ + return ktime_set(timeout.tv_sec, timeout.tv_nsec); +} + +static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_msm_gem_cpu_prep *args = data; + struct drm_gem_object *obj; + ktime_t timeout = to_ktime(args->timeout); + int ret; + + if (args->op & ~MSM_PREP_FLAGS) { + DRM_ERROR("invalid op: %08x\n", args->op); + return -EINVAL; + } + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + ret = msm_gem_cpu_prep(obj, args->op, &timeout); + + drm_gem_object_put_unlocked(obj); + + return ret; +} + +static int msm_ioctl_gem_cpu_fini(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_msm_gem_cpu_fini *args = data; + struct drm_gem_object *obj; + int ret; + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + ret = msm_gem_cpu_fini(obj); + + drm_gem_object_put_unlocked(obj); + + return ret; +} + +static int msm_ioctl_gem_madvise(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct drm_msm_gem_madvise *args = data; + struct drm_gem_object *obj; + int ret; + + switch (args->madv) { + case MSM_MADV_DONTNEED: + case MSM_MADV_WILLNEED: + break; + default: + return -EINVAL; + } + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) { + ret = -ENOENT; + goto unlock; + } + + ret = msm_gem_madvise(obj, args->madv); + if (ret >= 0) { + args->retained = ret; + ret = 0; + } + + drm_gem_object_put(obj); + +unlock: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +static int msm_drm_object_supports_event(struct drm_device *dev, + struct drm_msm_event_req *req) +{ + int ret = -EINVAL; + struct drm_mode_object *arg_obj; + + arg_obj = drm_mode_object_find(dev, NULL, req->object_id, + req->object_type); + if (!arg_obj) + return -ENOENT; + + switch (arg_obj->type) { + case DRM_MODE_OBJECT_CRTC: + case DRM_MODE_OBJECT_CONNECTOR: + ret = 0; + break; + default: + ret = -EOPNOTSUPP; + break; + } + + drm_mode_object_put(arg_obj); + + return ret; +} + +static int msm_register_event(struct drm_device *dev, + struct drm_msm_event_req *req, struct drm_file *file, bool en) +{ + int ret = -EINVAL; + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + struct drm_mode_object *arg_obj; + + arg_obj = drm_mode_object_find(dev, file, req->object_id, + req->object_type); + if (!arg_obj) + return -ENOENT; + + ret = kms->funcs->register_events(kms, arg_obj, req->event, en); + + drm_mode_object_put(arg_obj); + + return ret; +} + +static int msm_event_client_count(struct drm_device *dev, + struct drm_msm_event_req *req_event, bool locked) +{ + struct msm_drm_private *priv = dev->dev_private; + unsigned long flag = 0; + struct msm_drm_event *node; + int count = 0; + + if (!locked) + spin_lock_irqsave(&dev->event_lock, flag); + list_for_each_entry(node, &priv->client_event_list, base.link) { + if (node->event.base.type == req_event->event && + node->event.info.object_id == req_event->object_id) + count++; + } + if (!locked) + spin_unlock_irqrestore(&dev->event_lock, flag); + + return count; +} + +static int msm_ioctl_register_event(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_msm_event_req *req_event = data; + struct msm_drm_event *client, *node; + unsigned long flag = 0; + bool dup_request = false; + int ret = 0, count = 0; + + ret = msm_drm_object_supports_event(dev, req_event); + if (ret) { + DRM_ERROR("unsupported event %x object %x object id %d\n", + req_event->event, req_event->object_type, + req_event->object_id); + return ret; + } + + spin_lock_irqsave(&dev->event_lock, flag); + list_for_each_entry(node, &priv->client_event_list, base.link) { + if (node->base.file_priv != file) + continue; + if (node->event.base.type == req_event->event && + node->event.info.object_id == req_event->object_id) { + DRM_DEBUG("duplicate request for event %x obj id %d\n", + node->event.base.type, + node->event.info.object_id); + dup_request = true; + break; + } + } + spin_unlock_irqrestore(&dev->event_lock, flag); + + if (dup_request) + return -EALREADY; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->base.file_priv = file; + client->base.event = &client->event.base; + client->event.base.type = req_event->event; + memcpy(&client->event.info, req_event, sizeof(client->event.info)); + + /* Get the count of clients that have registered for event. + * Event should be enabled for first client, for subsequent enable + * calls add to client list and return. + */ + count = msm_event_client_count(dev, req_event, false); + /* Add current client to list */ + spin_lock_irqsave(&dev->event_lock, flag); + list_add_tail(&client->base.link, &priv->client_event_list); + spin_unlock_irqrestore(&dev->event_lock, flag); + + if (count) + return 0; + + ret = msm_register_event(dev, req_event, file, true); + if (ret) { + DRM_ERROR("failed to enable event %x object %x object id %d\n", + req_event->event, req_event->object_type, + req_event->object_id); + spin_lock_irqsave(&dev->event_lock, flag); + list_del(&client->base.link); + spin_unlock_irqrestore(&dev->event_lock, flag); + kfree(client); + } + return ret; +} + +static int msm_ioctl_deregister_event(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_msm_event_req *req_event = data; + struct msm_drm_event *client = NULL, *node, *temp; + unsigned long flag = 0; + int count = 0; + bool found = false; + int ret = 0; + + ret = msm_drm_object_supports_event(dev, req_event); + if (ret) { + DRM_ERROR("unsupported event %x object %x object id %d\n", + req_event->event, req_event->object_type, + req_event->object_id); + return ret; + } + + spin_lock_irqsave(&dev->event_lock, flag); + list_for_each_entry_safe(node, temp, &priv->client_event_list, + base.link) { + if (node->event.base.type == req_event->event && + node->event.info.object_id == req_event->object_id && + node->base.file_priv == file) { + client = node; + list_del(&client->base.link); + found = true; + kfree(client); + break; + } + } + spin_unlock_irqrestore(&dev->event_lock, flag); + + if (!found) + return -ENOENT; + + count = msm_event_client_count(dev, req_event, false); + if (!count) + ret = msm_register_event(dev, req_event, file, false); + + return ret; +} + +void msm_mode_object_event_notify(struct drm_mode_object *obj, + struct drm_device *dev, struct drm_event *event, u8 *payload) +{ + struct msm_drm_private *priv = NULL; + unsigned long flags; + struct msm_drm_event *notify, *node; + int len = 0, ret; + + if (!obj || !event || !event->length || !payload) { + DRM_ERROR("err param obj %pK event %pK len %d payload %pK\n", + obj, event, ((event) ? (event->length) : -1), + payload); + return; + } + priv = (dev) ? dev->dev_private : NULL; + if (!dev || !priv) { + DRM_ERROR("invalid dev %pK priv %pK\n", dev, priv); + return; + } + + spin_lock_irqsave(&dev->event_lock, flags); + list_for_each_entry(node, &priv->client_event_list, base.link) { + if (node->event.base.type != event->type || + obj->id != node->event.info.object_id) + continue; + len = event->length + sizeof(struct msm_drm_event); + if (node->base.file_priv->event_space < len) { + DRM_ERROR("Insufficient space %d for event %x len %d\n", + node->base.file_priv->event_space, event->type, + len); + continue; + } + notify = kzalloc(len, GFP_ATOMIC); + if (!notify) + continue; + notify->base.file_priv = node->base.file_priv; + notify->base.event = ¬ify->event.base; + notify->event.base.type = node->event.base.type; + notify->event.base.length = event->length + + sizeof(struct drm_msm_event_resp); + memcpy(¬ify->event.info, &node->event.info, + sizeof(notify->event.info)); + memcpy(notify->event.data, payload, event->length); + ret = drm_event_reserve_init_locked(dev, node->base.file_priv, + ¬ify->base, ¬ify->event.base); + if (ret) { + kfree(notify); + continue; + } + drm_send_event_locked(dev, ¬ify->base); + } + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +static int msm_release(struct inode *inode, struct file *filp) +{ + struct drm_file *file_priv = filp->private_data; + struct drm_minor *minor = file_priv->minor; + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_event *node, *temp, *tmp_node; + u32 count; + unsigned long flags; + LIST_HEAD(tmp_head); + + spin_lock_irqsave(&dev->event_lock, flags); + list_for_each_entry_safe(node, temp, &priv->client_event_list, + base.link) { + if (node->base.file_priv != file_priv) + continue; + list_del(&node->base.link); + list_add_tail(&node->base.link, &tmp_head); + } + spin_unlock_irqrestore(&dev->event_lock, flags); + + list_for_each_entry_safe(node, temp, &tmp_head, + base.link) { + list_del(&node->base.link); + count = msm_event_client_count(dev, &node->event.info, false); + + list_for_each_entry(tmp_node, &tmp_head, base.link) { + if (tmp_node->event.base.type == + node->event.info.event && + tmp_node->event.info.object_id == + node->event.info.object_id) + count++; + } + if (!count) + msm_register_event(dev, &node->event.info, file_priv, + false); + kfree(node); + } + + return drm_release(inode, filp); +} + +/** + * msm_ioctl_rmfb2 - remove an FB from the configuration + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + * Remove the FB specified by the user. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int msm_ioctl_rmfb2(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_framebuffer *fb = NULL; + struct drm_framebuffer *fbl = NULL; + uint32_t *id = data; + int found = 0; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, file_priv, *id); + if (!fb) + return -ENOENT; + + /* drop extra ref from traversing drm_framebuffer_lookup */ + drm_framebuffer_put(fb); + + mutex_lock(&file_priv->fbs_lock); + list_for_each_entry(fbl, &file_priv->fbs, filp_head) + if (fb == fbl) + found = 1; + if (!found) { + mutex_unlock(&file_priv->fbs_lock); + return -ENOENT; + } + + list_del_init(&fb->filp_head); + mutex_unlock(&file_priv->fbs_lock); + + drm_framebuffer_put(fb); + + return 0; +} +EXPORT_SYMBOL(msm_ioctl_rmfb2); + +/** + * msm_ioctl_power_ctrl - enable/disable power vote on MDSS Hw + * @dev: drm device for the ioctl + * @data: data pointer for the ioctl + * @file_priv: drm file for the ioctl call + * + */ +int msm_ioctl_power_ctrl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct msm_file_private *ctx = file_priv->driver_priv; + struct msm_drm_private *priv; + struct drm_msm_power_ctrl *power_ctrl = data; + bool vote_req = false; + int old_cnt; + int rc = 0; + + if (unlikely(!power_ctrl)) { + DRM_ERROR("invalid ioctl data\n"); + return -EINVAL; + } + + priv = dev->dev_private; + + mutex_lock(&ctx->power_lock); + + old_cnt = ctx->enable_refcnt; + if (power_ctrl->enable) { + if (!ctx->enable_refcnt) + vote_req = true; + ctx->enable_refcnt++; + } else if (ctx->enable_refcnt) { + ctx->enable_refcnt--; + if (!ctx->enable_refcnt) + vote_req = true; + } else { + pr_err("ignoring, unbalanced disable\n"); + } + + mutex_lock(&priv->phandle.ext_client_lock); + + if (vote_req) { + if (power_ctrl->enable) { + rc = pm_runtime_get_sync(dev->dev); + priv->phandle.is_ext_vote_en = true; + } else { + pm_runtime_put_sync(dev->dev); + priv->phandle.is_ext_vote_en = false; + } + + if (rc < 0) + ctx->enable_refcnt = old_cnt; + else + rc = 0; + } + + mutex_unlock(&priv->phandle.ext_client_lock); + + pr_debug("pid %d enable %d, refcnt %d, vote_req %d\n", + current->pid, power_ctrl->enable, ctx->enable_refcnt, + vote_req); + SDE_EVT32(current->pid, power_ctrl->enable, ctx->enable_refcnt, + vote_req); + mutex_unlock(&ctx->power_lock); + return rc; +} + +static const struct drm_ioctl_desc msm_ioctls[] = { + DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(MSM_GEM_MADVISE, msm_ioctl_gem_madvise, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(SDE_WB_CONFIG, sde_wb_config, DRM_UNLOCKED|DRM_AUTH), + DRM_IOCTL_DEF_DRV(MSM_REGISTER_EVENT, msm_ioctl_register_event, + DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(MSM_DEREGISTER_EVENT, msm_ioctl_deregister_event, + DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(MSM_RMFB2, msm_ioctl_rmfb2, DRM_UNLOCKED), + DRM_IOCTL_DEF_DRV(MSM_POWER_CTRL, msm_ioctl_power_ctrl, + DRM_RENDER_ALLOW), +}; + +static const struct vm_operations_struct vm_ops = { + .fault = msm_gem_fault, + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = msm_release, + .unlocked_ioctl = drm_ioctl, + .compat_ioctl = drm_compat_ioctl, + .poll = drm_poll, + .read = drm_read, + .llseek = no_llseek, + .mmap = msm_gem_mmap, +}; + +static struct drm_driver msm_driver = { + .driver_features = DRIVER_HAVE_IRQ | + DRIVER_GEM | + DRIVER_PRIME | + DRIVER_RENDER | + DRIVER_ATOMIC | + DRIVER_MODESET, + .open = msm_open, + .preclose = msm_preclose, + .postclose = msm_postclose, + .lastclose = msm_lastclose, + .irq_handler = msm_irq, + .irq_preinstall = msm_irq_preinstall, + .irq_postinstall = msm_irq_postinstall, + .irq_uninstall = msm_irq_uninstall, + .enable_vblank = msm_enable_vblank, + .disable_vblank = msm_disable_vblank, + .gem_free_object = msm_gem_free_object, + .gem_vm_ops = &vm_ops, + .dumb_create = msm_gem_dumb_create, + .dumb_map_offset = msm_gem_dumb_map_offset, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_import = msm_gem_prime_import, + .gem_prime_res_obj = msm_gem_prime_res_obj, + .gem_prime_pin = msm_gem_prime_pin, + .gem_prime_unpin = msm_gem_prime_unpin, + .gem_prime_get_sg_table = msm_gem_prime_get_sg_table, + .gem_prime_import_sg_table = msm_gem_prime_import_sg_table, + .gem_prime_vmap = msm_gem_prime_vmap, + .gem_prime_vunmap = msm_gem_prime_vunmap, + .gem_prime_mmap = msm_gem_prime_mmap, + .ioctls = msm_ioctls, + .num_ioctls = ARRAY_SIZE(msm_ioctls), + .fops = &fops, + .name = "msm_drm", + .desc = "MSM Snapdragon DRM", + .date = "20130625", + .major = MSM_VERSION_MAJOR, + .minor = MSM_VERSION_MINOR, + .patchlevel = MSM_VERSION_PATCHLEVEL, +}; + +#ifdef CONFIG_PM_SLEEP +static int msm_pm_suspend(struct device *dev) +{ + struct drm_device *ddev; + struct msm_drm_private *priv; + struct msm_kms *kms; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev->dev_private) + return -EINVAL; + + priv = ddev->dev_private; + kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->pm_suspend) + return kms->funcs->pm_suspend(dev); + + /* disable hot-plug polling */ + drm_kms_helper_poll_disable(ddev); + + return 0; +} + +static int msm_pm_resume(struct device *dev) +{ + struct drm_device *ddev; + struct msm_drm_private *priv; + struct msm_kms *kms; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev->dev_private) + return -EINVAL; + + priv = ddev->dev_private; + kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->pm_resume) + return kms->funcs->pm_resume(dev); + + /* enable hot-plug polling */ + drm_kms_helper_poll_enable(ddev); + + return 0; +} +#endif + +#ifdef CONFIG_PM +static int msm_runtime_suspend(struct device *dev) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev->dev_private; + + DBG(""); + + if (priv->mdss) + msm_mdss_disable(priv->mdss); + else + sde_power_resource_enable(&priv->phandle, false); + + return 0; +} + +static int msm_runtime_resume(struct device *dev) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct msm_drm_private *priv = ddev->dev_private; + int ret; + + DBG(""); + + if (priv->mdss) + ret = msm_mdss_enable(priv->mdss); + else + ret = sde_power_resource_enable(&priv->phandle, true); + + return ret; +} +#endif + +static const struct dev_pm_ops msm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume) + SET_RUNTIME_PM_OPS(msm_runtime_suspend, msm_runtime_resume, NULL) +}; + +/* + * Componentized driver support: + */ + +/* + * NOTE: duplication of the same code as exynos or imx (or probably any other). + * so probably some room for some helpers + */ +static int compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/* + * Identify what components need to be added by parsing what remote-endpoints + * our MDP output ports are connected to. In the case of LVDS on MDP4, there + * is no external component that we need to add since LVDS is within MDP4 + * itself. + */ +static int add_components_mdp(struct device *mdp_dev, + struct component_match **matchptr) +{ + struct device_node *np = mdp_dev->of_node; + struct device_node *ep_node; + struct device *master_dev; + + /* + * on MDP4 based platforms, the MDP platform device is the component + * master that adds other display interface components to itself. + * + * on MDP5 based platforms, the MDSS platform device is the component + * master that adds MDP5 and other display interface components to + * itself. + */ + if (of_device_is_compatible(np, "qcom,mdp4")) + master_dev = mdp_dev; + else + master_dev = mdp_dev->parent; + + for_each_endpoint_of_node(np, ep_node) { + struct device_node *intf; + struct of_endpoint ep; + int ret; + + ret = of_graph_parse_endpoint(ep_node, &ep); + if (ret) { + dev_err(mdp_dev, "unable to parse port endpoint\n"); + of_node_put(ep_node); + return ret; + } + + /* + * The LCDC/LVDS port on MDP4 is a speacial case where the + * remote-endpoint isn't a component that we need to add + */ + if (of_device_is_compatible(np, "qcom,mdp4") && + ep.port == 0) + continue; + + /* + * It's okay if some of the ports don't have a remote endpoint + * specified. It just means that the port isn't connected to + * any external interface. + */ + intf = of_graph_get_remote_port_parent(ep_node); + if (!intf) + continue; + + if (of_device_is_available(intf)) + drm_of_component_match_add(master_dev, matchptr, + compare_of, intf); + of_node_put(intf); + } + + return 0; +} + +static int compare_name_mdp(struct device *dev, void *data) +{ + return (strnstr(dev_name(dev), "mdp", strlen("mdp")) != NULL); +} + +static int add_display_components(struct device *dev, + struct component_match **matchptr) +{ + struct device *mdp_dev = NULL; + struct device_node *node; + int ret; + + if (of_device_is_compatible(dev->of_node, "qcom,sde-kms")) { + struct device_node *np = dev->of_node; + unsigned int i; + + for (i = 0; ; i++) { + node = of_parse_phandle(np, "connectors", i); + if (!node) + break; + + component_match_add(dev, matchptr, compare_of, node); + } + + return 0; + } + + /* + * MDP5 based devices don't have a flat hierarchy. There is a top level + * parent: MDSS, and children: MDP5, DSI, HDMI, eDP etc. Populate the + * children devices, find the MDP5 node, and then add the interfaces + * to our components list. + */ + if (of_device_is_compatible(dev->of_node, "qcom,mdss")) { + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) { + dev_err(dev, "failed to populate children devices\n"); + return ret; + } + + mdp_dev = device_find_child(dev, NULL, compare_name_mdp); + if (!mdp_dev) { + dev_err(dev, "failed to find MDSS MDP node\n"); + of_platform_depopulate(dev); + return -ENODEV; + } + + put_device(mdp_dev); + + /* add the MDP component itself */ + component_match_add(dev, matchptr, compare_of, + mdp_dev->of_node); + } else { + /* MDP4 */ + mdp_dev = dev; + } + + ret = add_components_mdp(mdp_dev, matchptr); + if (ret) + of_platform_depopulate(dev); + + return ret; +} + +struct msm_gem_address_space * +msm_gem_smmu_address_space_get(struct drm_device *dev, + unsigned int domain) +{ + struct msm_drm_private *priv = NULL; + struct msm_kms *kms; + const struct msm_kms_funcs *funcs; + + if ((!dev) || (!dev->dev_private)) + return NULL; + + priv = dev->dev_private; + kms = priv->kms; + if (!kms) + return NULL; + + funcs = kms->funcs; + + if ((!funcs) || (!funcs->get_address_space)) + return NULL; + + return funcs->get_address_space(priv->kms, domain); +} + +int msm_get_mixer_count(struct msm_drm_private *priv, + const struct drm_display_mode *mode, + const struct msm_resource_caps_info *res, u32 *num_lm) +{ + struct msm_kms *kms; + const struct msm_kms_funcs *funcs; + + if (!priv) { + DRM_ERROR("invalid drm private struct\n"); + return -EINVAL; + } + + kms = priv->kms; + if (!kms) { + DRM_ERROR("invalid msm kms struct\n"); + return -EINVAL; + } + + funcs = kms->funcs; + if (!funcs || !funcs->get_mixer_count) { + DRM_ERROR("invalid function pointers\n"); + return -EINVAL; + } + + return funcs->get_mixer_count(priv->kms, mode, res, num_lm); +} + +static int msm_drm_bind(struct device *dev) +{ + return msm_drm_init(dev, &msm_driver); +} + +static void msm_drm_unbind(struct device *dev) +{ + msm_drm_uninit(dev); +} + +static const struct component_master_ops msm_drm_ops = { + .bind = msm_drm_bind, + .unbind = msm_drm_unbind, +}; + +/* + * Platform driver: + */ + +static int msm_pdev_probe(struct platform_device *pdev) +{ + int ret; + struct component_match *match = NULL; + + ret = add_display_components(&pdev->dev, &match); + if (ret) + return ret; + if (!match) + return -ENODEV; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match); +} + +static int msm_pdev_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &msm_drm_ops); + of_platform_depopulate(&pdev->dev); + + msm_drm_unbind(&pdev->dev); + component_master_del(&pdev->dev, &msm_drm_ops); + return 0; +} + +static void msm_pdev_shutdown(struct platform_device *pdev) +{ + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = NULL; + + if (!ddev) { + DRM_ERROR("invalid drm device node\n"); + return; + } + + priv = ddev->dev_private; + if (!priv) { + DRM_ERROR("invalid msm drm private node\n"); + return; + } + + msm_lastclose(ddev); + + /* set this after lastclose to allow kickoff from lastclose */ + priv->shutdown_in_progress = true; +} + +static const struct of_device_id dt_match[] = { + { .compatible = "qcom,mdp4", .data = (void *)KMS_MDP4 }, + { .compatible = "qcom,mdss", .data = (void *)KMS_MDP5 }, + { .compatible = "qcom,sde-kms", .data = (void *)KMS_SDE }, + {}, +}; +MODULE_DEVICE_TABLE(of, dt_match); + +static struct platform_driver msm_platform_driver = { + .probe = msm_pdev_probe, + .remove = msm_pdev_remove, + .shutdown = msm_pdev_shutdown, + .driver = { + .name = "msm_drm", + .of_match_table = dt_match, + .pm = &msm_pm_ops, + .suppress_bind_attrs = true, + }, +}; + +static int __init msm_drm_register(void) +{ + if (!modeset) + return -EINVAL; + + DBG("init"); + msm_smmu_driver_init(); + msm_dsi_register(); + msm_edp_register(); + msm_hdmi_register(); + return platform_driver_register(&msm_platform_driver); +} + +static void __exit msm_drm_unregister(void) +{ + DBG("fini"); + platform_driver_unregister(&msm_platform_driver); + msm_hdmi_unregister(); + msm_edp_unregister(); + msm_dsi_unregister(); + msm_smmu_driver_cleanup(); +} + +module_init(msm_drm_register); +module_exit(msm_drm_unregister); + +MODULE_AUTHOR("Rob Clark <robdclark@gmail.com"); +MODULE_DESCRIPTION("MSM DRM Driver"); +MODULE_LICENSE("GPL"); diff --git a/techpack/display/msm/msm_drv.h b/techpack/display/msm/msm_drv.h new file mode 100644 index 0000000000000000000000000000000000000000..facce9f923790991e4ea54f6866ac630a91eced1 --- /dev/null +++ b/techpack/display/msm/msm_drv.h @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_DRV_H__ +#define __MSM_DRV_H__ + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/module.h> +#include <linux/component.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/iommu.h> +#include <linux/types.h> +#include <linux/of_graph.h> +#include <linux/of_device.h> +#include <linux/sde_io_util.h> +#include <asm/sizes.h> +#include <linux/kthread.h> + +#include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_plane_helper.h> +#include <drm/drm_fb_helper.h> +#include <drm/msm_drm.h> +#include <drm/drm_gem.h> + +#include "sde_power_handle.h" + +#define GET_MAJOR_REV(rev) ((rev) >> 28) +#define GET_MINOR_REV(rev) (((rev) >> 16) & 0xFFF) +#define GET_STEP_REV(rev) ((rev) & 0xFFFF) + +struct msm_kms; +struct msm_gpu; +struct msm_mmu; +struct msm_mdss; +struct msm_rd_state; +struct msm_perf_state; +struct msm_gem_submit; +struct msm_fence_context; +struct msm_fence_cb; +struct msm_gem_address_space; +struct msm_gem_vma; + +#define NUM_DOMAINS 4 /* one for KMS, then one per gpu core (?) */ +#define MAX_CRTCS 16 +#define MAX_PLANES 20 +#define MAX_ENCODERS 16 +#define MAX_BRIDGES 16 +#define MAX_CONNECTORS 16 + +#define TEARDOWN_DEADLOCK_RETRY_MAX 5 + +struct msm_file_private { + rwlock_t queuelock; + struct list_head submitqueues; + + int queueid; + + /* update the refcount when user driver calls power_ctrl IOCTL */ + unsigned short enable_refcnt; + + /* protects enable_refcnt */ + struct mutex power_lock; +}; + +enum msm_mdp_plane_property { + /* blob properties, always put these first */ + PLANE_PROP_CSC_V1, + PLANE_PROP_CSC_DMA_V1, + PLANE_PROP_INFO, + PLANE_PROP_SCALER_LUT_ED, + PLANE_PROP_SCALER_LUT_CIR, + PLANE_PROP_SCALER_LUT_SEP, + PLANE_PROP_SKIN_COLOR, + PLANE_PROP_SKY_COLOR, + PLANE_PROP_FOLIAGE_COLOR, + PLANE_PROP_VIG_GAMUT, + PLANE_PROP_VIG_IGC, + PLANE_PROP_DMA_IGC, + PLANE_PROP_DMA_GC, + + /* # of blob properties */ + PLANE_PROP_BLOBCOUNT, + + /* range properties */ + PLANE_PROP_ZPOS = PLANE_PROP_BLOBCOUNT, +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint + PLANE_PROP_CUSTOM, + PLANE_PROP_ALPHA, + PLANE_PROP_COLOR_FILL, + PLANE_PROP_H_DECIMATE, + PLANE_PROP_V_DECIMATE, + PLANE_PROP_INPUT_FENCE, + PLANE_PROP_HUE_ADJUST, + PLANE_PROP_SATURATION_ADJUST, + PLANE_PROP_VALUE_ADJUST, + PLANE_PROP_CONTRAST_ADJUST, + PLANE_PROP_EXCL_RECT_V1, + PLANE_PROP_PREFILL_SIZE, + PLANE_PROP_PREFILL_TIME, + PLANE_PROP_SCALER_V1, + PLANE_PROP_SCALER_V2, + PLANE_PROP_INVERSE_PMA, + + /* enum/bitmask properties */ + PLANE_PROP_BLEND_OP, + PLANE_PROP_SRC_CONFIG, + PLANE_PROP_FB_TRANSLATION_MODE, + PLANE_PROP_MULTIRECT_MODE, + + /* total # of properties */ + PLANE_PROP_COUNT +}; + +enum msm_mdp_crtc_property { + CRTC_PROP_INFO, + CRTC_PROP_DEST_SCALER_LUT_ED, + CRTC_PROP_DEST_SCALER_LUT_CIR, + CRTC_PROP_DEST_SCALER_LUT_SEP, + + /* # of blob properties */ + CRTC_PROP_BLOBCOUNT, + + /* range properties */ + CRTC_PROP_INPUT_FENCE_TIMEOUT = CRTC_PROP_BLOBCOUNT, + CRTC_PROP_OUTPUT_FENCE, + CRTC_PROP_OUTPUT_FENCE_OFFSET, + CRTC_PROP_DIM_LAYER_V1, + CRTC_PROP_CORE_CLK, + CRTC_PROP_CORE_AB, + CRTC_PROP_CORE_IB, + CRTC_PROP_LLCC_AB, + CRTC_PROP_LLCC_IB, + CRTC_PROP_DRAM_AB, + CRTC_PROP_DRAM_IB, + CRTC_PROP_ROT_PREFILL_BW, + CRTC_PROP_ROT_CLK, + CRTC_PROP_ROI_V1, + CRTC_PROP_SECURITY_LEVEL, + CRTC_PROP_IDLE_TIMEOUT, + CRTC_PROP_DEST_SCALER, + CRTC_PROP_CAPTURE_OUTPUT, + + CRTC_PROP_IDLE_PC_STATE, + + /* total # of properties */ + CRTC_PROP_CUSTOM, + CRTC_PROP_COUNT +}; + +enum msm_mdp_conn_property { + /* blob properties, always put these first */ + CONNECTOR_PROP_SDE_INFO, + CONNECTOR_PROP_MODE_INFO, + CONNECTOR_PROP_HDR_INFO, + CONNECTOR_PROP_EXT_HDR_INFO, + CONNECTOR_PROP_PP_DITHER, + CONNECTOR_PROP_HDR_METADATA, + + /* # of blob properties */ + CONNECTOR_PROP_BLOBCOUNT, + + /* range properties */ + CONNECTOR_PROP_OUT_FB = CONNECTOR_PROP_BLOBCOUNT, + CONNECTOR_PROP_RETIRE_FENCE, + CONNECTOR_PROP_DST_X, + CONNECTOR_PROP_DST_Y, + CONNECTOR_PROP_DST_W, + CONNECTOR_PROP_DST_H, + CONNECTOR_PROP_ROI_V1, + CONNECTOR_PROP_BL_SCALE, + CONNECTOR_PROP_SV_BL_SCALE, + CONNECTOR_PROP_SUPPORTED_COLORSPACES, + + /* enum/bitmask properties */ + CONNECTOR_PROP_TOPOLOGY_NAME, + CONNECTOR_PROP_TOPOLOGY_CONTROL, + CONNECTOR_PROP_AUTOREFRESH, + CONNECTOR_PROP_LP, + CONNECTOR_PROP_FB_TRANSLATION_MODE, + CONNECTOR_PROP_QSYNC_MODE, + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE, + CONNECTOR_PROP_CUSTOM, + /* total # of properties */ + CONNECTOR_PROP_COUNT +}; + +#define MSM_GPU_MAX_RINGS 4 +#define MAX_H_TILES_PER_DISPLAY 2 + +/** + * enum msm_display_compression_type - compression method used for pixel stream + * @MSM_DISPLAY_COMPRESSION_NONE: Pixel data is not compressed + * @MSM_DISPLAY_COMPRESSION_DSC: DSC compresison is used + */ +enum msm_display_compression_type { + MSM_DISPLAY_COMPRESSION_NONE, + MSM_DISPLAY_COMPRESSION_DSC, +}; + +/** + * enum msm_display_compression_ratio - compression ratio + * @MSM_DISPLAY_COMPRESSION_NONE: no compression + * @MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1: 2 to 1 compression + * @MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1: 3 to 1 compression + */ +enum msm_display_compression_ratio { + MSM_DISPLAY_COMPRESSION_RATIO_NONE, + MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1, + MSM_DISPLAY_COMPRESSION_RATIO_3_TO_1, + MSM_DISPLAY_COMPRESSION_RATIO_MAX, +}; + +/** + * enum msm_display_caps - features/capabilities supported by displays + * @MSM_DISPLAY_CAP_VID_MODE: Video or "active" mode supported + * @MSM_DISPLAY_CAP_CMD_MODE: Command mode supported + * @MSM_DISPLAY_CAP_HOT_PLUG: Hot plug detection supported + * @MSM_DISPLAY_CAP_EDID: EDID supported + * @MSM_DISPLAY_ESD_ENABLED: ESD feature enabled + * @MSM_DISPLAY_CAP_MST_MODE: Display with MST support + * @MSM_DISPLAY_SPLIT_LINK: Split Link enabled + */ +enum msm_display_caps { + MSM_DISPLAY_CAP_VID_MODE = BIT(0), + MSM_DISPLAY_CAP_CMD_MODE = BIT(1), + MSM_DISPLAY_CAP_HOT_PLUG = BIT(2), + MSM_DISPLAY_CAP_EDID = BIT(3), + MSM_DISPLAY_ESD_ENABLED = BIT(4), + MSM_DISPLAY_CAP_MST_MODE = BIT(5), + MSM_DISPLAY_SPLIT_LINK = BIT(6), +}; + +/** + * enum panel_mode - panel operation mode + * @MSM_DISPLAY_VIDEO_MODE: video mode panel + * @MSM_DISPLAY_CMD_MODE: Command mode panel + * @MODE_MAX: + */ +enum panel_op_mode { + MSM_DISPLAY_VIDEO_MODE = 0, + MSM_DISPLAY_CMD_MODE, + MSM_DISPLAY_MODE_MAX, +}; + +/** + * enum msm_event_wait - type of HW events to wait for + * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW + * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel + * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters) + * @MSM_ENC_ACTIVE_REGION - wait for the TG to be in active pixel region + */ +enum msm_event_wait { + MSM_ENC_COMMIT_DONE = 0, + MSM_ENC_TX_COMPLETE, + MSM_ENC_VBLANK, + MSM_ENC_ACTIVE_REGION, +}; + +/** + * struct msm_roi_alignment - region of interest alignment restrictions + * @xstart_pix_align: left x offset alignment restriction + * @width_pix_align: width alignment restriction + * @ystart_pix_align: top y offset alignment restriction + * @height_pix_align: height alignment restriction + * @min_width: minimum width restriction + * @min_height: minimum height restriction + */ +struct msm_roi_alignment { + uint32_t xstart_pix_align; + uint32_t width_pix_align; + uint32_t ystart_pix_align; + uint32_t height_pix_align; + uint32_t min_width; + uint32_t min_height; +}; + +/** + * struct msm_roi_caps - display's region of interest capabilities + * @enabled: true if some region of interest is supported + * @merge_rois: merge rois before sending to display + * @num_roi: maximum number of rois supported + * @align: roi alignment restrictions + */ +struct msm_roi_caps { + bool enabled; + bool merge_rois; + uint32_t num_roi; + struct msm_roi_alignment align; +}; + +/** + * struct msm_display_dsc_info - defines dsc configuration + * @version: DSC version. + * @scr_rev: DSC revision. + * @pic_height: Picture height in pixels. + * @pic_width: Picture width in pixels. + * @initial_lines: Number of initial lines stored in encoder. + * @pkt_per_line: Number of packets per line. + * @bytes_in_slice: Number of bytes in slice. + * @eol_byte_num: Valid bytes at the end of line. + * @pclk_per_line: Compressed width. + * @full_frame_slices: Number of slice per interface. + * @slice_height: Slice height in pixels. + * @slice_width: Slice width in pixels. + * @chunk_size: Chunk size in bytes for slice multiplexing. + * @slice_last_group_size: Size of last group in pixels. + * @bpp: Target bits per pixel. + * @bpc: Number of bits per component. + * @line_buf_depth: Line buffer bit depth. + * @block_pred_enable: Block prediction enabled/disabled. + * @vbr_enable: VBR mode. + * @enable_422: Indicates if input uses 4:2:2 sampling. + * @convert_rgb: DSC color space conversion. + * @input_10_bits: 10 bit per component input. + * @slice_per_pkt: Number of slices per packet. + * @initial_dec_delay: Initial decoding delay. + * @initial_xmit_delay: Initial transmission delay. + * @initial_scale_value: Scale factor value at the beginning of a slice. + * @scale_decrement_interval: Scale set up at the beginning of a slice. + * @scale_increment_interval: Scale set up at the end of a slice. + * @first_line_bpg_offset: Extra bits allocated on the first line of a slice. + * @nfl_bpg_offset: Slice specific settings. + * @slice_bpg_offset: Slice specific settings. + * @initial_offset: Initial offset at the start of a slice. + * @final_offset: Maximum end-of-slice value. + * @rc_model_size: Number of bits in RC model. + * @det_thresh_flatness: Flatness threshold. + * @max_qp_flatness: Maximum QP for flatness adjustment. + * @min_qp_flatness: Minimum QP for flatness adjustment. + * @edge_factor: Ratio to detect presence of edge. + * @quant_incr_limit0: QP threshold. + * @quant_incr_limit1: QP threshold. + * @tgt_offset_hi: Upper end of variability range. + * @tgt_offset_lo: Lower end of variability range. + * @buf_thresh: Thresholds in RC model + * @range_min_qp: Min QP allowed. + * @range_max_qp: Max QP allowed. + * @range_bpg_offset: Bits per group adjustment. + * @extra_width: Extra width required in timing calculations. + * @pps_delay_ms: Post PPS command delay in milliseconds. + */ +struct msm_display_dsc_info { + u8 version; + u8 scr_rev; + + int pic_height; + int pic_width; + int slice_height; + int slice_width; + + int initial_lines; + int pkt_per_line; + int bytes_in_slice; + int bytes_per_pkt; + int eol_byte_num; + int pclk_per_line; + int full_frame_slices; + int slice_last_group_size; + int bpp; + int bpc; + int line_buf_depth; + + int slice_per_pkt; + int chunk_size; + bool block_pred_enable; + int vbr_enable; + int enable_422; + int convert_rgb; + int input_10_bits; + + int initial_dec_delay; + int initial_xmit_delay; + int initial_scale_value; + int scale_decrement_interval; + int scale_increment_interval; + int first_line_bpg_offset; + int nfl_bpg_offset; + int slice_bpg_offset; + int initial_offset; + int final_offset; + + int rc_model_size; + int det_thresh_flatness; + int max_qp_flatness; + int min_qp_flatness; + int edge_factor; + int quant_incr_limit0; + int quant_incr_limit1; + int tgt_offset_hi; + int tgt_offset_lo; + + u32 *buf_thresh; + char *range_min_qp; + char *range_max_qp; + char *range_bpg_offset; + + u32 extra_width; + u32 pps_delay_ms; +}; + +/** + * struct msm_compression_info - defined panel compression + * @comp_type: type of compression supported + * @comp_ratio: compression ratio + * @dsc_info: dsc configuration if the compression + * supported is DSC + */ +struct msm_compression_info { + enum msm_display_compression_type comp_type; + enum msm_display_compression_ratio comp_ratio; + + union{ + struct msm_display_dsc_info dsc_info; + }; +}; + +/** + * struct msm_display_topology - defines a display topology pipeline + * @num_lm: number of layer mixers used + * @num_enc: number of compression encoder blocks used + * @num_intf: number of interfaces the panel is mounted on + */ +struct msm_display_topology { + u32 num_lm; + u32 num_enc; + u32 num_intf; +}; + +/** + * struct msm_mode_info - defines all msm custom mode info + * @frame_rate: frame_rate of the mode + * @vtotal: vtotal calculated for the mode + * @prefill_lines: prefill lines based on porches. + * @jitter_numer: display panel jitter numerator configuration + * @jitter_denom: display panel jitter denominator configuration + * @clk_rate: DSI bit clock per lane in HZ. + * @topology: supported topology for the mode + * @comp_info: compression info supported + * @roi_caps: panel roi capabilities + * @wide_bus_en: wide-bus mode cfg for interface module + * @mdp_transfer_time_us Specifies the mdp transfer time for command mode + * panels in microseconds. + */ +struct msm_mode_info { + uint32_t frame_rate; + uint32_t vtotal; + uint32_t prefill_lines; + uint32_t jitter_numer; + uint32_t jitter_denom; + uint64_t clk_rate; + struct msm_display_topology topology; + struct msm_compression_info comp_info; + struct msm_roi_caps roi_caps; + bool wide_bus_en; + u32 mdp_transfer_time_us; +}; + +/** + * struct msm_resource_caps_info - defines hw resources + * @num_lm number of layer mixers available + * @num_dsc number of dsc available + * @num_ctl number of ctl available + * @num_3dmux number of 3d mux available + * @max_mixer_width: max width supported by layer mixer + */ +struct msm_resource_caps_info { + uint32_t num_lm; + uint32_t num_dsc; + uint32_t num_ctl; + uint32_t num_3dmux; + uint32_t max_mixer_width; +}; + +/** + * struct msm_display_info - defines display properties + * @intf_type: DRM_MODE_CONNECTOR_ display type + * @capabilities: Bitmask of display flags + * @num_of_h_tiles: Number of horizontal tiles in case of split interface + * @h_tile_instance: Controller instance used per tile. Number of elements is + * based on num_of_h_tiles + * @is_connected: Set to true if display is connected + * @width_mm: Physical width + * @height_mm: Physical height + * @max_width: Max width of display. In case of hot pluggable display + * this is max width supported by controller + * @max_height: Max height of display. In case of hot pluggable display + * this is max height supported by controller + * @clk_rate: DSI bit clock per lane in HZ. + * @display_type: Enum for type of display + * @is_te_using_watchdog_timer: Boolean to indicate watchdog TE is + * used instead of panel TE in cmd mode panels + * @roi_caps: Region of interest capability info + * @qsync_min_fps Minimum fps supported by Qsync feature + * @te_source vsync source pin information + */ +struct msm_display_info { + int intf_type; + uint32_t capabilities; + enum panel_op_mode curr_panel_mode; + uint32_t num_of_h_tiles; + uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY]; + + bool is_connected; + + unsigned int width_mm; + unsigned int height_mm; + + uint32_t max_width; + uint32_t max_height; + uint64_t clk_rate; + + uint32_t display_type; + bool is_te_using_watchdog_timer; + struct msm_roi_caps roi_caps; + + uint32_t qsync_min_fps; + uint32_t te_source; +}; + +#define MSM_MAX_ROI 4 + +/** + * struct msm_roi_list - list of regions of interest for a drm object + * @num_rects: number of valid rectangles in the roi array + * @roi: list of roi rectangles + */ +struct msm_roi_list { + uint32_t num_rects; + struct drm_clip_rect roi[MSM_MAX_ROI]; +}; + +/** + * struct - msm_display_kickoff_params - info for display features at kickoff + * @rois: Regions of interest structure for mapping CRTC to Connector output + */ +struct msm_display_kickoff_params { + struct msm_roi_list *rois; + struct drm_msm_ext_hdr_metadata *hdr_meta; +}; + +/** + * struct - msm_display_conn_params - info of dpu display features + * @qsync_mode: Qsync mode, where 0: disabled 1: continuous mode 2: oneshot + * @qsync_update: Qsync settings were changed/updated + */ +struct msm_display_conn_params { + uint32_t qsync_mode; + bool qsync_update; +}; + +/** + * struct msm_drm_event - defines custom event notification struct + * @base: base object required for event notification by DRM framework. + * @event: event object required for event notification by DRM framework. + */ +struct msm_drm_event { + struct drm_pending_event base; + struct drm_msm_event_resp event; +}; + +/* Commit/Event thread specific structure */ +struct msm_drm_thread { + struct drm_device *dev; + struct task_struct *thread; + unsigned int crtc_id; + struct kthread_worker worker; +}; + +struct msm_drm_private { + + struct drm_device *dev; + + struct msm_kms *kms; + + struct sde_power_handle phandle; + + /* subordinate devices, if present: */ + struct platform_device *gpu_pdev; + + /* top level MDSS wrapper device (for MDP5 only) */ + struct msm_mdss *mdss; + + /* possibly this should be in the kms component, but it is + * shared by both mdp4 and mdp5.. + */ + struct hdmi *hdmi; + + /* eDP is for mdp5 only, but kms has not been created + * when edp_bind() and edp_init() are called. Here is the only + * place to keep the edp instance. + */ + struct msm_edp *edp; + + /* DSI is shared by mdp4 and mdp5 */ + struct msm_dsi *dsi[2]; + + /* when we have more than one 'msm_gpu' these need to be an array: */ + struct msm_gpu *gpu; + struct msm_file_private *lastctx; + + struct drm_fb_helper *fbdev; + + struct msm_rd_state *rd; /* debugfs to dump all submits */ + struct msm_rd_state *hangrd; /* debugfs to dump hanging submits */ + struct msm_perf_state *perf; + + /* list of GEM objects: */ + struct list_head inactive_list; + + struct workqueue_struct *wq; + + /* crtcs pending async atomic updates: */ + uint32_t pending_crtcs; + uint32_t pending_planes; + wait_queue_head_t pending_crtcs_event; + + unsigned int num_planes; + struct drm_plane *planes[MAX_PLANES]; + + unsigned int num_crtcs; + struct drm_crtc *crtcs[MAX_CRTCS]; + + struct msm_drm_thread disp_thread[MAX_CRTCS]; + struct msm_drm_thread event_thread[MAX_CRTCS]; + + struct task_struct *pp_event_thread; + struct kthread_worker pp_event_worker; + + unsigned int num_encoders; + struct drm_encoder *encoders[MAX_ENCODERS]; + + unsigned int num_bridges; + struct drm_bridge *bridges[MAX_BRIDGES]; + + unsigned int num_connectors; + struct drm_connector *connectors[MAX_CONNECTORS]; + + /* Properties */ + struct drm_property *plane_property[PLANE_PROP_COUNT]; + struct drm_property *crtc_property[CRTC_PROP_COUNT]; + struct drm_property *conn_property[CONNECTOR_PROP_COUNT]; + + /* Color processing properties for the crtc */ + struct drm_property **cp_property; + + /* VRAM carveout, used when no IOMMU: */ + struct { + unsigned long size; + dma_addr_t paddr; + /* NOTE: mm managed at the page level, size is in # of pages + * and position mm_node->start is in # of pages: + */ + struct drm_mm mm; + spinlock_t lock; /* Protects drm_mm node allocation/removal */ + } vram; + + struct notifier_block vmap_notifier; + struct shrinker shrinker; + + struct drm_atomic_state *pm_state; + + /* task holding struct_mutex.. currently only used in submit path + * to detect and reject faults from copy_from_user() for submit + * ioctl. + */ + struct task_struct *struct_mutex_task; + + /* list of clients waiting for events */ + struct list_head client_event_list; + + /* whether registered and drm_dev_unregister should be called */ + bool registered; + + /* msm drv debug root node */ + struct dentry *debug_root; + + /* update the flag when msm driver receives shutdown notification */ + bool shutdown_in_progress; + ktime_t commit_end_time; +}; + +/* get struct msm_kms * from drm_device * */ +#define ddev_to_msm_kms(D) ((D) && (D)->dev_private ? \ + ((struct msm_drm_private *)((D)->dev_private))->kms : NULL) + +struct msm_format { + uint32_t pixel_format; +}; + +int msm_atomic_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state); +void msm_atomic_commit_tail(struct drm_atomic_state *state); +int msm_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, bool nonblock); + +/* callback from wq once fence has passed: */ +struct msm_fence_cb { + struct work_struct work; + uint32_t fence; + void (*func)(struct msm_fence_cb *cb); +}; + +void __msm_fence_worker(struct work_struct *work); + +#define INIT_FENCE_CB(_cb, _func) do { \ + INIT_WORK(&(_cb)->work, __msm_fence_worker); \ + (_cb)->func = _func; \ + } while (0) + +struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev); +void msm_atomic_state_clear(struct drm_atomic_state *state); +void msm_atomic_state_free(struct drm_atomic_state *state); + +void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + unsigned int flags); +int msm_gem_map_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, int npages, + unsigned int flags); + +struct device *msm_gem_get_aspace_device(struct msm_gem_address_space *aspace); + +void msm_gem_address_space_put(struct msm_gem_address_space *aspace); + +struct msm_gem_address_space * +msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, + const char *name); + +/* For SDE display */ +struct msm_gem_address_space * +msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu, + const char *name); + +/** + * msm_gem_add_obj_to_aspace_active_list: adds obj to active obj list in aspace + */ +void msm_gem_add_obj_to_aspace_active_list( + struct msm_gem_address_space *aspace, + struct drm_gem_object *obj); + +/** + * msm_gem_remove_obj_from_aspace_active_list: removes obj from active obj + * list in aspace + */ +void msm_gem_remove_obj_from_aspace_active_list( + struct msm_gem_address_space *aspace, + struct drm_gem_object *obj); + +/** + * msm_gem_smmu_address_space_get: returns the aspace pointer for the requested + * domain + */ +struct msm_gem_address_space * +msm_gem_smmu_address_space_get(struct drm_device *dev, + unsigned int domain); +int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); +void msm_unregister_mmu(struct drm_device *dev, struct msm_mmu *mmu); + +/** + * msm_gem_aspace_domain_attach_detach: function to inform the attach/detach + * of the domain for this aspace + */ +void msm_gem_aspace_domain_attach_detach_update( + struct msm_gem_address_space *aspace, + bool is_detach); + +/** + * msm_gem_address_space_register_cb: function to register callback for attach + * and detach of the domain + */ +int msm_gem_address_space_register_cb( + struct msm_gem_address_space *aspace, + void (*cb)(void *, bool), + void *cb_data); + +/** + * msm_gem_address_space_register_cb: function to unregister callback + */ +int msm_gem_address_space_unregister_cb( + struct msm_gem_address_space *aspace, + void (*cb)(void *, bool), + void *cb_data); + +void msm_gem_submit_free(struct msm_gem_submit *submit); +int msm_ioctl_gem_submit(struct drm_device *dev, void *data, + struct drm_file *file); + +void msm_gem_shrinker_init(struct drm_device *dev); +void msm_gem_shrinker_cleanup(struct drm_device *dev); + +void msm_gem_sync(struct drm_gem_object *obj); +int msm_gem_mmap_obj(struct drm_gem_object *obj, + struct vm_area_struct *vma); +int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma); +vm_fault_t msm_gem_fault(struct vm_fault *vmf); +uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); +int msm_gem_get_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace, uint64_t *iova); +uint64_t msm_gem_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace); +struct page **msm_gem_get_pages(struct drm_gem_object *obj); +void msm_gem_put_pages(struct drm_gem_object *obj); +void msm_gem_put_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace); +dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj); +int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); +int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset); +struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj); +void *msm_gem_prime_vmap(struct drm_gem_object *obj); +void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr); +int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); +struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj); +struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, struct sg_table *sg); +int msm_gem_prime_pin(struct drm_gem_object *obj); +void msm_gem_prime_unpin(struct drm_gem_object *obj); +struct drm_gem_object *msm_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); +void *msm_gem_get_vaddr(struct drm_gem_object *obj); +void *msm_gem_get_vaddr_active(struct drm_gem_object *obj); +void msm_gem_put_vaddr(struct drm_gem_object *obj); +int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv); +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); +int msm_gem_cpu_fini(struct drm_gem_object *obj); +void msm_gem_free_object(struct drm_gem_object *obj); +int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, + uint32_t size, uint32_t flags, uint32_t *handle); +struct drm_gem_object *msm_gem_new(struct drm_device *dev, + uint32_t size, uint32_t flags); +struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev, + uint32_t size, uint32_t flags); +void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size, + uint32_t flags, struct msm_gem_address_space *aspace, + struct drm_gem_object **bo, uint64_t *iova); +void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size, + uint32_t flags, struct msm_gem_address_space *aspace, + struct drm_gem_object **bo, uint64_t *iova); +struct drm_gem_object *msm_gem_import(struct drm_device *dev, + struct dma_buf *dmabuf, struct sg_table *sgt); +int msm_gem_delayed_import(struct drm_gem_object *obj); + +void msm_framebuffer_set_kmap(struct drm_framebuffer *fb, bool enable); +void msm_framebuffer_set_keepattrs(struct drm_framebuffer *fb, bool enable); +int msm_framebuffer_prepare(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace); +void msm_framebuffer_cleanup(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace); +uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace, int plane); +uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb, int plane); +struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane); +const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb); +struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object **bos); +struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); +struct drm_framebuffer * msm_alloc_stolen_fb(struct drm_device *dev, + int w, int h, int p, uint32_t format); + +struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); +void msm_fbdev_free(struct drm_device *dev); + +struct hdmi; +#ifdef CONFIG_DRM_MSM_HDMI +int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev, + struct drm_encoder *encoder); +void __init msm_hdmi_register(void); +void __exit msm_hdmi_unregister(void); +#else +static inline void __init msm_hdmi_register(void) +{ +} +static inline void __exit msm_hdmi_unregister(void) +{ +} +#endif + +struct msm_edp; +#ifdef CONFIG_DRM_MSM_EDP +void __init msm_edp_register(void); +void __exit msm_edp_unregister(void); +int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev, + struct drm_encoder *encoder); +#else +static inline void __init msm_edp_register(void) +{ +} +static inline void __exit msm_edp_unregister(void) +{ +} + +static inline int msm_edp_modeset_init(struct msm_edp *edp, + struct drm_device *dev, struct drm_encoder *encoder) +{ + return -EINVAL; +} +#endif + +struct msm_dsi; + +/* * + * msm_mode_object_event_notify - notify user-space clients of drm object + * events. + * @obj: mode object (crtc/connector) that is generating the event. + * @event: event that needs to be notified. + * @payload: payload for the event. + */ +void msm_mode_object_event_notify(struct drm_mode_object *obj, + struct drm_device *dev, struct drm_event *event, u8 *payload); +#ifndef CONFIG_DRM_MSM_DSI +void __init msm_dsi_register(void); +void __exit msm_dsi_unregister(void); +int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev, + struct drm_encoder *encoder); +#else +static inline void __init msm_dsi_register(void) +{ +} +static inline void __exit msm_dsi_unregister(void) +{ +} +static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, + struct drm_device *dev, + struct drm_encoder *encoder) +{ + return -EINVAL; +} +#endif + +#ifdef CONFIG_DRM_MSM_MDP5 +void __init msm_mdp_register(void); +void __exit msm_mdp_unregister(void); +#else +static inline void __init msm_mdp_register(void) +{ +} +static inline void __exit msm_mdp_unregister(void) +{ +} +#endif + +#ifdef CONFIG_DEBUG_FS +void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m); +void msm_gem_describe_objects(struct list_head *list, struct seq_file *m); +void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m); +int msm_debugfs_late_init(struct drm_device *dev); +int msm_rd_debugfs_init(struct drm_minor *minor); +void msm_rd_debugfs_cleanup(struct msm_drm_private *priv); +void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, + const char *fmt, ...); +int msm_perf_debugfs_init(struct drm_minor *minor); +void msm_perf_debugfs_cleanup(struct msm_drm_private *priv); +#else +static inline int msm_debugfs_late_init(struct drm_device *dev) { return 0; } +static inline void msm_rd_dump_submit(struct msm_rd_state *rd, struct msm_gem_submit *submit, + const char *fmt, ...) {} +static inline void msm_rd_debugfs_cleanup(struct msm_drm_private *priv) {} +static inline void msm_perf_debugfs_cleanup(struct msm_drm_private *priv) {} +#endif + +struct clk *msm_clk_get(struct platform_device *pdev, const char *name); +int msm_clk_bulk_get(struct device *dev, struct clk_bulk_data **bulk); + +struct clk *msm_clk_bulk_get_clock(struct clk_bulk_data *bulk, int count, + const char *name); +void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, + const char *dbgname); +unsigned long msm_iomap_size(struct platform_device *pdev, const char *name); +void msm_iounmap(struct platform_device *dev, void __iomem *addr); +void msm_writel(u32 data, void __iomem *addr); +u32 msm_readl(const void __iomem *addr); + +#define DBG(fmt, ...) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__) +#define VERB(fmt, ...) if (0) DRM_DEBUG_DRIVER(fmt"\n", ##__VA_ARGS__) + +static inline int align_pitch(int width, int bpp) +{ + int bytespp = (bpp + 7) / 8; + /* adreno needs pitch aligned to 32 pixels: */ + return bytespp * ALIGN(width, 32); +} + +/* for the generated headers: */ +#define INVALID_IDX(idx) ({BUG(); 0;}) +#define fui(x) ({BUG(); 0;}) +#define util_float_to_half(x) ({BUG(); 0;}) + + +#define FIELD(val, name) (((val) & name ## __MASK) >> name ## __SHIFT) + +/* for conditionally setting boolean flag(s): */ +#define COND(bool, val) ((bool) ? (val) : 0) + +static inline unsigned long timeout_to_jiffies(const ktime_t *timeout) +{ + ktime_t now = ktime_get(); + unsigned long remaining_jiffies; + + if (ktime_compare(*timeout, now) < 0) { + remaining_jiffies = 0; + } else { + ktime_t rem = ktime_sub(*timeout, now); + struct timespec ts = ktime_to_timespec(rem); + remaining_jiffies = timespec_to_jiffies(&ts); + } + + return remaining_jiffies; +} + +int msm_get_mixer_count(struct msm_drm_private *priv, + const struct drm_display_mode *mode, + const struct msm_resource_caps_info *res, u32 *num_lm); + +#endif /* __MSM_DRV_H__ */ diff --git a/techpack/display/msm/msm_fb.c b/techpack/display/msm/msm_fb.c new file mode 100644 index 0000000000000000000000000000000000000000..f5ddd139e57c01b6862566c512f4fccdbdac2981 --- /dev/null +++ b/techpack/display/msm/msm_fb.c @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/dma-mapping.h> +#include <linux/dma-buf.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_framebuffer_helper.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "msm_gem.h" + +#define MSM_FRAMEBUFFER_FLAG_KMAP BIT(0) + +struct msm_framebuffer { + struct drm_framebuffer base; + const struct msm_format *format; + void *vaddr[MAX_PLANE]; + atomic_t kmap_count; + u32 flags; +}; +#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base) + +int msm_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned int flags, + unsigned int color, struct drm_clip_rect *clips, + unsigned int num_clips) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; + struct drm_plane *plane; + int ret = 0; + + if (!num_clips || !clips) + return 0; + + drm_modeset_acquire_init(&ctx, + file_priv ? DRM_MODESET_ACQUIRE_INTERRUPTIBLE : 0); + + state = drm_atomic_state_alloc(fb->dev); + if (!state) { + ret = -ENOMEM; + goto out_drop_locks; + } + state->acquire_ctx = &ctx; + +retry: + drm_for_each_plane(plane, fb->dev) { + struct drm_plane_state *plane_state; + + ret = drm_modeset_lock(&plane->mutex, state->acquire_ctx); + if (ret) + goto out; + + if (plane->state->fb != fb) { + drm_modeset_unlock(&plane->mutex); + continue; + } + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto out; + } + + plane_state->visible = true; + } + + ret = drm_atomic_commit(state); + +out: + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + ret = drm_modeset_backoff(&ctx); + if (!ret) + goto retry; + } + + drm_atomic_state_put(state); + +out_drop_locks: + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + +static const struct drm_framebuffer_funcs msm_framebuffer_funcs = { + .create_handle = drm_gem_fb_create_handle, + .destroy = drm_gem_fb_destroy, + .dirty = msm_framebuffer_dirty, +}; + +#ifdef CONFIG_DEBUG_FS +void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) +{ + struct msm_framebuffer *msm_fb; + int i, n; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return; + } + + msm_fb = to_msm_framebuffer(fb); + n = fb->format->num_planes; + seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n", + fb->width, fb->height, (char *)&fb->format->format, + drm_framebuffer_read_refcount(fb), fb->base.id); + + for (i = 0; i < n; i++) { + seq_printf(m, " %d: offset=%d pitch=%d, obj: ", + i, fb->offsets[i], fb->pitches[i]); + msm_gem_describe(fb->obj[i], m); + } +} +#endif + +void msm_framebuffer_set_keepattrs(struct drm_framebuffer *fb, bool enable) +{ + struct msm_framebuffer *msm_fb; + int i, n; + struct drm_gem_object *bo; + struct msm_gem_object *msm_obj; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return; + } + + if (!fb->format) { + DRM_ERROR("from:%pS null fb->format\n", + __builtin_return_address(0)); + return; + } + + msm_fb = to_msm_framebuffer(fb); + n = fb->format->num_planes; + for (i = 0; i < n; i++) { + bo = msm_framebuffer_bo(fb, i); + if (bo) { + msm_obj = to_msm_bo(bo); + if (enable) + msm_obj->flags |= MSM_BO_KEEPATTRS; + else + msm_obj->flags &= ~MSM_BO_KEEPATTRS; + } + } +} + +void msm_framebuffer_set_kmap(struct drm_framebuffer *fb, bool enable) +{ + struct msm_framebuffer *msm_fb; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return; + } + + msm_fb = to_msm_framebuffer(fb); + if (enable) + msm_fb->flags |= MSM_FRAMEBUFFER_FLAG_KMAP; + else + msm_fb->flags &= ~MSM_FRAMEBUFFER_FLAG_KMAP; +} + +static int msm_framebuffer_kmap(struct drm_framebuffer *fb) +{ + struct msm_framebuffer *msm_fb; + int i, n; + struct drm_gem_object *bo; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return -EINVAL; + } + + msm_fb = to_msm_framebuffer(fb); + n = fb->format->num_planes; + if (atomic_inc_return(&msm_fb->kmap_count) > 1) + return 0; + + for (i = 0; i < n; i++) { + bo = msm_framebuffer_bo(fb, i); + if (!bo || !bo->dma_buf) { + msm_fb->vaddr[i] = NULL; + continue; + } + dma_buf_begin_cpu_access(bo->dma_buf, DMA_BIDIRECTIONAL); + msm_fb->vaddr[i] = dma_buf_kmap(bo->dma_buf, 0); + DRM_INFO("FB[%u]: vaddr[%d]:%ux%u:0x%llx\n", fb->base.id, i, + fb->width, fb->height, (u64) msm_fb->vaddr[i]); + } + + return 0; +} + +static void msm_framebuffer_kunmap(struct drm_framebuffer *fb) +{ + struct msm_framebuffer *msm_fb; + int i, n; + struct drm_gem_object *bo; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return; + } + + msm_fb = to_msm_framebuffer(fb); + n = fb->format->num_planes; + if (atomic_dec_return(&msm_fb->kmap_count) > 0) + return; + + for (i = 0; i < n; i++) { + bo = msm_framebuffer_bo(fb, i); + if (!bo || !msm_fb->vaddr[i]) + continue; + if (bo->dma_buf) { + dma_buf_kunmap(bo->dma_buf, 0, msm_fb->vaddr[i]); + dma_buf_end_cpu_access(bo->dma_buf, DMA_BIDIRECTIONAL); + } + msm_fb->vaddr[i] = NULL; + } +} + +/* prepare/pin all the fb's bo's for scanout. Note that it is not valid + * to prepare an fb more multiple different initiator 'id's. But that + * should be fine, since only the scanout (mdpN) side of things needs + * this, the gpu doesn't care about fb's. + */ +int msm_framebuffer_prepare(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace) +{ + struct msm_framebuffer *msm_fb; + int ret, i, n; + uint64_t iova; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return -EINVAL; + } + + msm_fb = to_msm_framebuffer(fb); + n = fb->format->num_planes; + for (i = 0; i < n; i++) { + ret = msm_gem_get_iova(fb->obj[i], aspace, &iova); + DBG("FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret); + if (ret) + return ret; + } + + if (msm_fb->flags & MSM_FRAMEBUFFER_FLAG_KMAP) + msm_framebuffer_kmap(fb); + + return 0; +} + +void msm_framebuffer_cleanup(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace) +{ + struct msm_framebuffer *msm_fb; + int i, n; + + if (fb == NULL) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return; + } + + msm_fb = to_msm_framebuffer(fb); + n = fb->format->num_planes; + + if (msm_fb->flags & MSM_FRAMEBUFFER_FLAG_KMAP) + msm_framebuffer_kunmap(fb); + + for (i = 0; i < n; i++) + msm_gem_put_iova(fb->obj[i], aspace); +} + +uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, + struct msm_gem_address_space *aspace, int plane) +{ + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return -EINVAL; + } + + if (!fb->obj[plane]) + return 0; + + return msm_gem_iova(fb->obj[plane], aspace) + fb->offsets[plane]; +} + +uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb, + int plane) +{ + struct msm_framebuffer *msm_fb; + dma_addr_t phys_addr; + + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return -EINVAL; + } + + msm_fb = to_msm_framebuffer(fb); + + if (!msm_fb->base.obj[plane]) + return 0; + + phys_addr = msm_gem_get_dma_addr(msm_fb->base.obj[plane]); + if (!phys_addr) + return 0; + + return phys_addr + fb->offsets[plane]; +} + +struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) +{ + if (!fb) { + DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0)); + return ERR_PTR(-EINVAL); + } + + return drm_gem_fb_get_obj(fb, plane); +} + +const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) +{ + return fb ? (to_msm_framebuffer(fb))->format : NULL; +} + +struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_gem_object *bos[4] = {0}; + struct drm_framebuffer *fb; + int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); + + for (i = 0; i < n; i++) { + bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]); + if (!bos[i]) { + ret = -ENXIO; + goto out_unref; + } + } + + fb = msm_framebuffer_init(dev, mode_cmd, bos); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); + goto out_unref; + } + + return fb; + +out_unref: + for (i = 0; i < n; i++) + drm_gem_object_put_unlocked(bos[i]); + return ERR_PTR(ret); +} + +struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + struct msm_framebuffer *msm_fb = NULL; + struct drm_framebuffer *fb; + const struct msm_format *format; + int ret, i, num_planes; + unsigned int hsub, vsub; + bool is_modified = false; + + DBG("create framebuffer: dev=%pK, mode_cmd=%pK (%dx%d@%4.4s)", + dev, mode_cmd, mode_cmd->width, mode_cmd->height, + (char *)&mode_cmd->pixel_format); + + num_planes = drm_format_num_planes(mode_cmd->pixel_format); + hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); + vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); + + format = kms->funcs->get_format(kms, mode_cmd->pixel_format, + mode_cmd->modifier[0]); + if (!format) { + dev_err(dev->dev, "unsupported pixel format: %4.4s\n", + (char *)&mode_cmd->pixel_format); + ret = -EINVAL; + goto fail; + } + + msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL); + if (!msm_fb) { + ret = -ENOMEM; + goto fail; + } + + fb = &msm_fb->base; + + msm_fb->format = format; + atomic_set(&msm_fb->kmap_count, 0); + + if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) { + for (i = 0; i < ARRAY_SIZE(mode_cmd->modifier); i++) { + if (mode_cmd->modifier[i]) { + is_modified = true; + break; + } + } + } + + if (num_planes > ARRAY_SIZE(fb->obj)) { + ret = -EINVAL; + goto fail; + } + + if (is_modified) { + if (!kms->funcs->check_modified_format) { + dev_err(dev->dev, "can't check modified fb format\n"); + ret = -EINVAL; + goto fail; + } else { + ret = kms->funcs->check_modified_format( + kms, msm_fb->format, mode_cmd, bos); + if (ret) + goto fail; + } + } else { + const struct drm_format_info *info; + + info = drm_format_info(mode_cmd->pixel_format); + if (!info || num_planes > ARRAY_SIZE(info->cpp)) { + ret = -EINVAL; + goto fail; + } + + for (i = 0; i < num_planes; i++) { + unsigned int width = mode_cmd->width / (i ? hsub : 1); + unsigned int height = mode_cmd->height / (i ? vsub : 1); + unsigned int min_size; + unsigned int cpp = 0; + + cpp = drm_format_plane_cpp(mode_cmd->pixel_format, i); + + min_size = (height - 1) * mode_cmd->pitches[i] + + width * cpp + + mode_cmd->offsets[i]; + + if (!bos[i] || bos[i]->size < min_size) { + ret = -EINVAL; + goto fail; + } + } + } + + for (i = 0; i < num_planes; i++) + msm_fb->base.obj[i] = bos[i]; + + drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); + + ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs); + if (ret) { + dev_err(dev->dev, "framebuffer init failed: %d\n", ret); + goto fail; + } + + DBG("create: FB ID: %d (%pK)", fb->base.id, fb); + + return fb; + +fail: + kfree(msm_fb); + + return ERR_PTR(ret); +} + +struct drm_framebuffer * +msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format) +{ + struct drm_mode_fb_cmd2 mode_cmd = { + .pixel_format = format, + .width = w, + .height = h, + .pitches = { p }, + }; + struct drm_gem_object *bo; + struct drm_framebuffer *fb; + int size; + + /* allocate backing bo */ + size = mode_cmd.pitches[0] * mode_cmd.height; + DBG("allocating %d bytes for fb %d", size, dev->primary->index); + bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN); + if (IS_ERR(bo)) { + dev_warn(dev->dev, "could not allocate stolen bo\n"); + /* try regular bo: */ + bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC); + } + if (IS_ERR(bo)) { + dev_err(dev->dev, "failed to allocate buffer object\n"); + return ERR_CAST(bo); + } + + fb = msm_framebuffer_init(dev, &mode_cmd, &bo); + if (IS_ERR(fb)) { + dev_err(dev->dev, "failed to allocate fb\n"); + /* note: if fb creation failed, we can't rely on fb destroy + * to unref the bo: + */ + drm_gem_object_put_unlocked(bo); + return ERR_CAST(fb); + } + + return fb; +} diff --git a/techpack/display/msm/msm_fbdev.c b/techpack/display/msm/msm_fbdev.c new file mode 100644 index 0000000000000000000000000000000000000000..78f804c12ef276b83938bb61aafe2718bc333dfc --- /dev/null +++ b/techpack/display/msm/msm_fbdev.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <drm/drm_crtc.h> +#include <drm/drm_fb_helper.h> + +#include "msm_drv.h" +#include "msm_kms.h" + +extern int msm_gem_mmap_obj(struct drm_gem_object *obj, + struct vm_area_struct *vma); +static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma); + +/* + * fbdev funcs, to implement legacy fbdev interface on top of drm driver + */ + +#define to_msm_fbdev(x) container_of(x, struct msm_fbdev, base) + +struct msm_fbdev { + struct drm_fb_helper base; + struct drm_framebuffer *fb; +}; + +static struct fb_ops msm_fb_ops = { + .owner = THIS_MODULE, + DRM_FB_HELPER_DEFAULT_OPS, + + /* Note: to properly handle manual update displays, we wrap the + * basic fbdev ops which write to the framebuffer + */ + .fb_read = drm_fb_helper_sys_read, + .fb_write = drm_fb_helper_sys_write, + .fb_fillrect = drm_fb_helper_sys_fillrect, + .fb_copyarea = drm_fb_helper_sys_copyarea, + .fb_imageblit = drm_fb_helper_sys_imageblit, + .fb_mmap = msm_fbdev_mmap, +}; + +static int msm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *helper = (struct drm_fb_helper *)info->par; + struct msm_fbdev *fbdev = to_msm_fbdev(helper); + struct drm_gem_object *bo = msm_framebuffer_bo(fbdev->fb, 0); + int ret = 0; + + ret = drm_gem_mmap_obj(bo, bo->size, vma); + if (ret) { + pr_err("%s:drm_gem_mmap_obj fail\n", __func__); + return ret; + } + + return msm_gem_mmap_obj(bo, vma); +} + +static int msm_fbdev_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct msm_fbdev *fbdev = to_msm_fbdev(helper); + struct drm_device *dev = helper->dev; + struct msm_drm_private *priv = dev->dev_private; + struct drm_framebuffer *fb = NULL; + struct drm_gem_object *bo; + struct fb_info *fbi = NULL; + uint64_t paddr; + uint32_t format; + int ret, pitch; + + format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, + sizes->surface_height, sizes->surface_bpp, + sizes->fb_width, sizes->fb_height); + + pitch = align_pitch(sizes->surface_width, sizes->surface_bpp); + /* double buffer */ + fb = msm_alloc_stolen_fb(dev, sizes->surface_width, + sizes->surface_height * 2, pitch, format); + + if (IS_ERR(fb)) { + dev_err(dev->dev, "failed to allocate fb\n"); + return PTR_ERR(fb); + } + + bo = msm_framebuffer_bo(fb, 0); + + mutex_lock(&dev->struct_mutex); + + /* + * NOTE: if we can be guaranteed to be able to map buffer + * in panic (ie. lock-safe, etc) we could avoid pinning the + * buffer now: + */ + ret = msm_gem_get_iova(bo, priv->kms->aspace, &paddr); + if (ret) { + dev_err(dev->dev, "failed to get buffer obj iova: %d\n", ret); + goto fail_unlock; + } + + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { + dev_err(dev->dev, "failed to allocate fb info\n"); + ret = PTR_ERR(fbi); + goto fail_unlock; + } + + DBG("fbi=%p, dev=%p", fbi, dev); + + fbdev->fb = fb; + helper->fb = fb; + + fbi->par = helper; + fbi->fbops = &msm_fb_ops; + + strlcpy(fbi->fix.id, "msm", sizeof(fbi->fix.id)); + + drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth); + drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); + + dev->mode_config.fb_base = paddr; + + fbi->screen_base = msm_gem_get_vaddr(bo); + if (IS_ERR(fbi->screen_base)) { + ret = PTR_ERR(fbi->screen_base); + goto fail_unlock; + } + fbi->screen_size = bo->size; + fbi->fix.smem_start = paddr; + fbi->fix.smem_len = bo->size; + + DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); + DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); + + mutex_unlock(&dev->struct_mutex); + + return 0; + +fail_unlock: + mutex_unlock(&dev->struct_mutex); + drm_framebuffer_remove(fb); + return ret; +} + +static const struct drm_fb_helper_funcs msm_fb_helper_funcs = { + .fb_probe = msm_fbdev_create, +}; + +/* initialize fbdev helper */ +struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_fbdev *fbdev = NULL; + struct drm_fb_helper *helper; + int ret; + + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); + if (!fbdev) + goto fail; + + helper = &fbdev->base; + + drm_fb_helper_prepare(dev, helper, &msm_fb_helper_funcs); + + ret = drm_fb_helper_init(dev, helper, priv->num_connectors); + if (ret) { + dev_err(dev->dev, "could not init fbdev: ret=%d\n", ret); + goto fail; + } + + ret = drm_fb_helper_single_add_all_connectors(helper); + if (ret) + goto fini; + + ret = drm_fb_helper_initial_config(helper, 32); + if (ret) + goto fini; + + priv->fbdev = helper; + + return helper; + +fini: + drm_fb_helper_fini(helper); +fail: + kfree(fbdev); + return NULL; +} + +void msm_fbdev_free(struct drm_device *dev) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_fb_helper *helper = priv->fbdev; + struct msm_fbdev *fbdev; + + DBG(); + + drm_fb_helper_unregister_fbi(helper); + + drm_fb_helper_fini(helper); + + fbdev = to_msm_fbdev(priv->fbdev); + + /* this will free the backing object */ + if (fbdev->fb) { + struct drm_gem_object *bo = + msm_framebuffer_bo(fbdev->fb, 0); + msm_gem_put_vaddr(bo); + drm_framebuffer_remove(fbdev->fb); + } + + kfree(fbdev); + + priv->fbdev = NULL; +} diff --git a/techpack/display/msm/msm_gem.c b/techpack/display/msm/msm_gem.c new file mode 100644 index 0000000000000000000000000000000000000000..a38ccc204f6636b27fab519b97a9bfc7f5f047ab --- /dev/null +++ b/techpack/display/msm/msm_gem.c @@ -0,0 +1,1258 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/spinlock.h> +#include <linux/shmem_fs.h> +#include <linux/dma-buf.h> +#include <linux/pfn_t.h> +#include <linux/ion.h> + +#include "msm_drv.h" +#include "msm_gem.h" +#include "msm_mmu.h" +#include "sde_dbg.h" + +static void msm_gem_vunmap_locked(struct drm_gem_object *obj); + + +static dma_addr_t physaddr(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_drm_private *priv = obj->dev->dev_private; + return (((dma_addr_t)msm_obj->vram_node->start) << PAGE_SHIFT) + + priv->vram.paddr; +} + +static bool use_pages(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + return !msm_obj->vram_node; +} + +/* allocate pages from VRAM carveout, used when no IOMMU: */ +static struct page **get_pages_vram(struct drm_gem_object *obj, int npages) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_drm_private *priv = obj->dev->dev_private; + dma_addr_t paddr; + struct page **p; + int ret, i; + + p = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + spin_lock(&priv->vram.lock); + ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node, npages); + spin_unlock(&priv->vram.lock); + if (ret) { + kvfree(p); + return ERR_PTR(ret); + } + + paddr = physaddr(obj); + for (i = 0; i < npages; i++) { + p[i] = phys_to_page(paddr); + paddr += PAGE_SIZE; + } + + return p; +} + +static struct page **get_pages(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct device *aspace_dev; + + if (obj->import_attach) + return msm_obj->pages; + + if (!msm_obj->pages) { + struct drm_device *dev = obj->dev; + struct page **p; + int npages = obj->size >> PAGE_SHIFT; + + if (use_pages(obj)) + p = drm_gem_get_pages(obj); + else + p = get_pages_vram(obj, npages); + + if (IS_ERR(p)) { + dev_err(dev->dev, "could not get pages: %ld\n", + PTR_ERR(p)); + return p; + } + + msm_obj->pages = p; + + msm_obj->sgt = drm_prime_pages_to_sg(p, npages); + if (IS_ERR(msm_obj->sgt)) { + void *ptr = ERR_CAST(msm_obj->sgt); + + dev_err(dev->dev, "failed to allocate sgt\n"); + msm_obj->sgt = NULL; + return ptr; + } + + /* + * Make sure to flush the CPU cache for newly allocated memory + * so we don't get ourselves into trouble with a dirty cache + */ + if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) { + aspace_dev = msm_gem_get_aspace_device(msm_obj->aspace); + dma_sync_sg_for_device(aspace_dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, DMA_BIDIRECTIONAL); + } + } + + return msm_obj->pages; +} + +static void put_pages_vram(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_drm_private *priv = obj->dev->dev_private; + + spin_lock(&priv->vram.lock); + drm_mm_remove_node(msm_obj->vram_node); + spin_unlock(&priv->vram.lock); + + kvfree(msm_obj->pages); +} + +static void put_pages(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + if (msm_obj->pages) { + if (msm_obj->sgt) { + sg_free_table(msm_obj->sgt); + kfree(msm_obj->sgt); + } + + if (use_pages(obj)) + drm_gem_put_pages(obj, msm_obj->pages, true, false); + else + put_pages_vram(obj); + + msm_obj->pages = NULL; + } +} + +struct page **msm_gem_get_pages(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct page **p; + + mutex_lock(&msm_obj->lock); + + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { + mutex_unlock(&msm_obj->lock); + return ERR_PTR(-EBUSY); + } + + p = get_pages(obj); + mutex_unlock(&msm_obj->lock); + return p; +} + +void msm_gem_put_pages(struct drm_gem_object *obj) +{ + /* when we start tracking the pin count, then do something here */ +} + +void msm_gem_sync(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj; + struct device *aspace_dev; + + if (!obj) + return; + + msm_obj = to_msm_bo(obj); + + /* + * dma_sync_sg_for_device synchronises a single contiguous or + * scatter/gather mapping for the CPU and device. + */ + aspace_dev = msm_gem_get_aspace_device(msm_obj->aspace); + dma_sync_sg_for_device(aspace_dev, msm_obj->sgt->sgl, + msm_obj->sgt->nents, DMA_BIDIRECTIONAL); +} + + +int msm_gem_mmap_obj(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + vma->vm_flags &= ~VM_PFNMAP; + vma->vm_flags |= VM_MIXEDMAP; + + if (msm_obj->flags & MSM_BO_WC) { + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + } else if (msm_obj->flags & MSM_BO_UNCACHED) { + vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags)); + } else { + /* + * Shunt off cached objs to shmem file so they have their own + * address_space (so unmap_mapping_range does what we want, + * in particular in the case of mmap'd dmabufs) + */ + fput(vma->vm_file); + get_file(obj->filp); + vma->vm_pgoff = 0; + vma->vm_file = obj->filp; + + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + } + + return 0; +} + +int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) { + DBG("mmap failed: %d", ret); + return ret; + } + + return msm_gem_mmap_obj(vma->vm_private_data, vma); +} + +vm_fault_t msm_gem_fault(struct vm_fault *vmf) +{ + struct vm_area_struct *vma = vmf->vma; + struct drm_gem_object *obj = vma->vm_private_data; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct page **pages; + unsigned long pfn; + pgoff_t pgoff; + int err; + vm_fault_t ret; + + /* + * vm_ops.open/drm_gem_mmap_obj and close get and put + * a reference on obj. So, we dont need to hold one here. + */ + err = mutex_lock_interruptible(&msm_obj->lock); + if (err) { + ret = VM_FAULT_NOPAGE; + goto out; + } + + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { + mutex_unlock(&msm_obj->lock); + return VM_FAULT_SIGBUS; + } + + msm_obj->aspace = msm_gem_smmu_address_space_get(obj->dev, + MSM_SMMU_DOMAIN_UNSECURE); + /* make sure we have pages attached now */ + pages = get_pages(obj); + if (IS_ERR(pages)) { + ret = vmf_error(PTR_ERR(pages)); + goto out_unlock; + } + + /* We don't use vmf->pgoff since that has the fake offset: */ + pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; + + pfn = page_to_pfn(pages[pgoff]); + + VERB("Inserting %pK pfn %lx, pa %lx", (void *)vmf->address, + pfn, pfn << PAGE_SHIFT); + + ret = vmf_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); +out_unlock: + mutex_unlock(&msm_obj->lock); +out: + return ret; +} + +/** get mmap offset */ +static uint64_t mmap_offset(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + int ret; + + WARN_ON(!mutex_is_locked(&msm_obj->lock)); + + /* Make it mmapable */ + ret = drm_gem_create_mmap_offset(obj); + + if (ret) { + dev_err(dev->dev, "could not allocate mmap offset\n"); + return 0; + } + + return drm_vma_node_offset_addr(&obj->vma_node); +} + +uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) +{ + uint64_t offset; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + mutex_lock(&msm_obj->lock); + offset = mmap_offset(obj); + mutex_unlock(&msm_obj->lock); + return offset; +} + +dma_addr_t msm_gem_get_dma_addr(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct sg_table *sgt; + + if (!msm_obj->sgt) { + sgt = dma_buf_map_attachment(obj->import_attach, + DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(sgt)) { + DRM_ERROR("dma_buf_map_attachment failure, err=%ld\n", + PTR_ERR(sgt)); + return 0; + } + msm_obj->sgt = sgt; + } + + return sg_phys(msm_obj->sgt->sgl); +} + +static struct msm_gem_vma *add_vma(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *vma; + + WARN_ON(!mutex_is_locked(&msm_obj->lock)); + + vma = kzalloc(sizeof(*vma), GFP_KERNEL); + if (!vma) + return ERR_PTR(-ENOMEM); + + vma->aspace = aspace; + msm_obj->aspace = aspace; + + list_add_tail(&vma->list, &msm_obj->vmas); + + return vma; +} + +static struct msm_gem_vma *lookup_vma(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *vma; + + WARN_ON(!mutex_is_locked(&msm_obj->lock)); + + list_for_each_entry(vma, &msm_obj->vmas, list) { + if (vma->aspace == aspace) + return vma; + } + + return NULL; +} + +static void del_vma(struct msm_gem_vma *vma) +{ + if (!vma) + return; + + list_del(&vma->list); + kfree(vma); +} + +/* Called with msm_obj->lock locked */ +static void +put_iova(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *vma, *tmp; + + WARN_ON(!mutex_is_locked(&msm_obj->lock)); + + list_for_each_entry_safe(vma, tmp, &msm_obj->vmas, list) { + msm_gem_unmap_vma(vma->aspace, vma, msm_obj->sgt, + msm_obj->flags); + /* + * put_iova removes the domain connected to the obj which makes + * the aspace inaccessible. Store the aspace, as it is used to + * update the active_list during gem_free_obj and gem_purge. + */ + msm_obj->aspace = vma->aspace; + del_vma(vma); + } +} + +/* get iova, taking a reference. Should have a matching put */ +int msm_gem_get_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace, uint64_t *iova) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *vma; + int ret = 0; + + mutex_lock(&msm_obj->lock); + + if (WARN_ON(msm_obj->madv != MSM_MADV_WILLNEED)) { + mutex_unlock(&msm_obj->lock); + return -EBUSY; + } + + vma = lookup_vma(obj, aspace); + + if (!vma) { + struct page **pages; + struct device *dev; + struct dma_buf *dmabuf; + bool reattach = false; + + dev = msm_gem_get_aspace_device(aspace); + if ((dev && obj->import_attach) && + ((dev != obj->import_attach->dev) || + msm_obj->obj_dirty)) { + dmabuf = obj->import_attach->dmabuf; + + DRM_DEBUG("detach nsec-dev:%pK attach sec-dev:%pK\n", + obj->import_attach->dev, dev); + SDE_EVT32(obj->import_attach->dev, dev, msm_obj->sgt); + + if (msm_obj->sgt) + dma_buf_unmap_attachment(obj->import_attach, + msm_obj->sgt, DMA_BIDIRECTIONAL); + dma_buf_detach(dmabuf, obj->import_attach); + + obj->import_attach = dma_buf_attach(dmabuf, dev); + if (IS_ERR(obj->import_attach)) { + DRM_ERROR("dma_buf_attach failure, err=%ld\n", + PTR_ERR(obj->import_attach)); + goto unlock; + } + msm_obj->obj_dirty = false; + reattach = true; + } + + /* perform delayed import for buffers without existing sgt */ + if (((msm_obj->flags & MSM_BO_EXTBUF) && !(msm_obj->sgt)) + || reattach) { + ret = msm_gem_delayed_import(obj); + if (ret) { + DRM_ERROR("delayed dma-buf import failed %d\n", + ret); + goto unlock; + } + } + + vma = add_vma(obj, aspace); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto unlock; + } + + pages = get_pages(obj); + if (IS_ERR(pages)) { + ret = PTR_ERR(pages); + goto fail; + } + + ret = msm_gem_map_vma(aspace, vma, msm_obj->sgt, + obj->size >> PAGE_SHIFT, + msm_obj->flags); + if (ret) + goto fail; + } + + *iova = vma->iova; + + if (aspace && !msm_obj->in_active_list) { + mutex_lock(&aspace->list_lock); + msm_gem_add_obj_to_aspace_active_list(aspace, obj); + mutex_unlock(&aspace->list_lock); + } + + mutex_unlock(&msm_obj->lock); + return 0; + +fail: + del_vma(vma); +unlock: + mutex_unlock(&msm_obj->lock); + return ret; +} + +/* get iova without taking a reference, used in places where you have + * already done a 'msm_gem_get_iova()'. + */ +uint64_t msm_gem_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_gem_vma *vma; + + mutex_lock(&msm_obj->lock); + vma = lookup_vma(obj, aspace); + mutex_unlock(&msm_obj->lock); + WARN_ON(!vma); + + return vma ? vma->iova : 0; +} + +void msm_gem_put_iova(struct drm_gem_object *obj, + struct msm_gem_address_space *aspace) +{ + // XXX TODO .. + // NOTE: probably don't need a _locked() version.. we wouldn't + // normally unmap here, but instead just mark that it could be + // unmapped (if the iova refcnt drops to zero), but then later + // if another _get_iova_locked() fails we can start unmapping + // things that are no longer needed.. +} + +void msm_gem_aspace_domain_attach_detach_update( + struct msm_gem_address_space *aspace, + bool is_detach) +{ + struct msm_gem_object *msm_obj; + struct drm_gem_object *obj; + struct aspace_client *aclient; + int ret; + uint64_t iova; + + if (!aspace) + return; + + mutex_lock(&aspace->list_lock); + if (is_detach) { + /* Indicate to clients domain is getting detached */ + list_for_each_entry(aclient, &aspace->clients, list) { + if (aclient->cb) + aclient->cb(aclient->cb_data, + is_detach); + } + + /** + * Unmap active buffers, + * typically clients should do this when the callback is called, + * but this needs to be done for the buffers which are not + * attached to any planes. + */ + list_for_each_entry(msm_obj, &aspace->active_list, iova_list) { + obj = &msm_obj->base; + if (obj->import_attach) { + mutex_lock(&msm_obj->lock); + put_iova(obj); + msm_obj->obj_dirty = true; + mutex_unlock(&msm_obj->lock); + } + } + } else { + /* map active buffers */ + list_for_each_entry(msm_obj, &aspace->active_list, iova_list) { + obj = &msm_obj->base; + ret = msm_gem_get_iova(obj, aspace, &iova); + if (ret) { + mutex_unlock(&aspace->list_lock); + return; + } + } + + /* Indicate to clients domain is attached */ + list_for_each_entry(aclient, &aspace->clients, list) { + if (aclient->cb) + aclient->cb(aclient->cb_data, + is_detach); + } + } + mutex_unlock(&aspace->list_lock); +} + +int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + args->pitch = align_pitch(args->width, args->bpp); + args->size = PAGE_ALIGN(args->pitch * args->height); + return msm_gem_new_handle(dev, file, args->size, + MSM_BO_SCANOUT | MSM_BO_WC, &args->handle); +} + +int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *obj; + int ret = 0; + + /* GEM does all our handle to object mapping */ + obj = drm_gem_object_lookup(file, handle); + if (obj == NULL) { + ret = -ENOENT; + goto fail; + } + + *offset = msm_gem_mmap_offset(obj); + + drm_gem_object_put_unlocked(obj); + +fail: + return ret; +} + +static void *get_vaddr(struct drm_gem_object *obj, unsigned madv) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + int ret = 0; + + mutex_lock(&msm_obj->lock); + + if (WARN_ON(msm_obj->madv > madv)) { + dev_err(obj->dev->dev, "Invalid madv state: %u vs %u\n", + msm_obj->madv, madv); + mutex_unlock(&msm_obj->lock); + return ERR_PTR(-EBUSY); + } + + /* increment vmap_count *before* vmap() call, so shrinker can + * check vmap_count (is_vunmapable()) outside of msm_obj->lock. + * This guarantees that we won't try to msm_gem_vunmap() this + * same object from within the vmap() call (while we already + * hold msm_obj->lock) + */ + msm_obj->vmap_count++; + + if (!msm_obj->vaddr) { + struct page **pages = get_pages(obj); + if (IS_ERR(pages)) { + ret = PTR_ERR(pages); + goto fail; + } + + if (obj->import_attach) { + ret = dma_buf_begin_cpu_access( + obj->import_attach->dmabuf, DMA_BIDIRECTIONAL); + if (ret) + goto fail; + + msm_obj->vaddr = + dma_buf_vmap(obj->import_attach->dmabuf); + } else { + msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, + VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + } + + if (msm_obj->vaddr == NULL) { + ret = -ENOMEM; + goto fail; + } + } + + mutex_unlock(&msm_obj->lock); + return msm_obj->vaddr; + +fail: + msm_obj->vmap_count--; + mutex_unlock(&msm_obj->lock); + return ERR_PTR(ret); +} + +void *msm_gem_get_vaddr(struct drm_gem_object *obj) +{ + return get_vaddr(obj, MSM_MADV_WILLNEED); +} + +/* + * Don't use this! It is for the very special case of dumping + * submits from GPU hangs or faults, were the bo may already + * be MSM_MADV_DONTNEED, but we know the buffer is still on the + * active list. + */ +void *msm_gem_get_vaddr_active(struct drm_gem_object *obj) +{ + return get_vaddr(obj, __MSM_MADV_PURGED); +} + +void msm_gem_put_vaddr(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + mutex_lock(&msm_obj->lock); + WARN_ON(msm_obj->vmap_count < 1); + msm_obj->vmap_count--; + mutex_unlock(&msm_obj->lock); +} + +/* Update madvise status, returns true if not purged, else + * false or -errno. + */ +int msm_gem_madvise(struct drm_gem_object *obj, unsigned madv) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + mutex_lock(&msm_obj->lock); + + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + + if (msm_obj->madv != __MSM_MADV_PURGED) + msm_obj->madv = madv; + + madv = msm_obj->madv; + + mutex_unlock(&msm_obj->lock); + + return (madv != __MSM_MADV_PURGED); +} + +void msm_gem_purge(struct drm_gem_object *obj, enum msm_gem_lock subclass) +{ + struct drm_device *dev = obj->dev; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + WARN_ON(!is_purgeable(msm_obj)); + WARN_ON(obj->import_attach); + + mutex_lock_nested(&msm_obj->lock, subclass); + + put_iova(obj); + if (msm_obj->aspace) { + mutex_lock(&msm_obj->aspace->list_lock); + msm_gem_remove_obj_from_aspace_active_list(msm_obj->aspace, + obj); + mutex_unlock(&msm_obj->aspace->list_lock); + } + + msm_gem_vunmap_locked(obj); + + put_pages(obj); + + msm_obj->madv = __MSM_MADV_PURGED; + + drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping); + drm_gem_free_mmap_offset(obj); + + /* Our goal here is to return as much of the memory as + * is possible back to the system as we are called from OOM. + * To do this we must instruct the shmfs to drop all of its + * backing pages, *now*. + */ + shmem_truncate_range(file_inode(obj->filp), 0, (loff_t)-1); + + invalidate_mapping_pages(file_inode(obj->filp)->i_mapping, + 0, (loff_t)-1); + + mutex_unlock(&msm_obj->lock); +} + +static void msm_gem_vunmap_locked(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + WARN_ON(!mutex_is_locked(&msm_obj->lock)); + + if (!msm_obj->vaddr || WARN_ON(!is_vunmapable(msm_obj))) + return; + + if (obj->import_attach) { + dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr); + dma_buf_end_cpu_access(obj->import_attach->dmabuf, + DMA_BIDIRECTIONAL); + } else { + vunmap(msm_obj->vaddr); + } + + msm_obj->vaddr = NULL; +} + +void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + mutex_lock_nested(&msm_obj->lock, subclass); + msm_gem_vunmap_locked(obj); + mutex_unlock(&msm_obj->lock); +} + +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + bool write = !!(op & MSM_PREP_WRITE); + unsigned long remain = + op & MSM_PREP_NOSYNC ? 0 : timeout_to_jiffies(timeout); + long ret; + + ret = reservation_object_wait_timeout_rcu(msm_obj->resv, write, + true, remain); + if (ret == 0) + return remain == 0 ? -EBUSY : -ETIMEDOUT; + else if (ret < 0) + return ret; + + /* TODO cache maintenance */ + + return 0; +} + +int msm_gem_cpu_fini(struct drm_gem_object *obj) +{ + /* TODO cache maintenance */ + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void describe_fence(struct dma_fence *fence, const char *type, + struct seq_file *m) +{ + if (!dma_fence_is_signaled(fence)) + seq_printf(m, "\t%9s: %s %s seq %u\n", type, + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno); +} + +void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct reservation_object *robj = msm_obj->resv; + struct reservation_object_list *fobj; + struct dma_fence *fence; + struct msm_gem_vma *vma; + uint64_t off = drm_vma_node_start(&obj->vma_node); + const char *madv; + + mutex_lock(&msm_obj->lock); + + switch (msm_obj->madv) { + case __MSM_MADV_PURGED: + madv = " purged"; + break; + case MSM_MADV_DONTNEED: + madv = " purgeable"; + break; + case MSM_MADV_WILLNEED: + default: + madv = ""; + break; + } + + seq_printf(m, "%08x: %c %2d (%2d) %08llx %pK\t", + msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', + obj->name, kref_read(&obj->refcount), + off, msm_obj->vaddr); + + /* FIXME: we need to print the address space here too */ + list_for_each_entry(vma, &msm_obj->vmas, list) + seq_printf(m, " %08llx", vma->iova); + + seq_printf(m, " %zu%s\n", obj->size, madv); + + rcu_read_lock(); + fobj = rcu_dereference(robj->fence); + if (fobj) { + unsigned int i, shared_count = fobj->shared_count; + + for (i = 0; i < shared_count; i++) { + fence = rcu_dereference(fobj->shared[i]); + describe_fence(fence, "Shared", m); + } + } + + fence = rcu_dereference(robj->fence_excl); + if (fence) + describe_fence(fence, "Exclusive", m); + rcu_read_unlock(); + + mutex_unlock(&msm_obj->lock); +} + +void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) +{ + struct msm_gem_object *msm_obj; + int count = 0; + size_t size = 0; + + list_for_each_entry(msm_obj, list, mm_list) { + struct drm_gem_object *obj = &msm_obj->base; + seq_printf(m, " "); + msm_gem_describe(obj, m); + count++; + size += obj->size; + } + + seq_printf(m, "Total %d objects, %zu bytes\n", count, size); +} +#endif + +/* don't call directly! Use drm_gem_object_put() and friends */ +void msm_gem_free_object(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + /* object should not be on active list: */ + WARN_ON(is_active(msm_obj)); + + list_del(&msm_obj->mm_list); + + mutex_lock(&msm_obj->lock); + + put_iova(obj); + if (msm_obj->aspace) { + mutex_lock(&msm_obj->aspace->list_lock); + msm_gem_remove_obj_from_aspace_active_list(msm_obj->aspace, + obj); + mutex_unlock(&msm_obj->aspace->list_lock); + } + + if (obj->import_attach) { + if (msm_obj->vaddr) + dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr); + + /* Don't drop the pages for imported dmabuf, as they are not + * ours, just free the array we allocated: + */ + if (msm_obj->pages) + kvfree(msm_obj->pages); + + drm_prime_gem_destroy(obj, msm_obj->sgt); + } else { + msm_gem_vunmap_locked(obj); + put_pages(obj); + } + + if (msm_obj->resv == &msm_obj->_resv) + reservation_object_fini(msm_obj->resv); + + drm_gem_object_release(obj); + + mutex_unlock(&msm_obj->lock); + kfree(msm_obj); +} + +/* convenience method to construct a GEM buffer object, and userspace handle */ +int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, + uint32_t size, uint32_t flags, uint32_t *handle) +{ + struct drm_gem_object *obj; + int ret; + + obj = msm_gem_new(dev, size, flags); + + if (IS_ERR(obj)) + return PTR_ERR(obj); + + ret = drm_gem_handle_create(file, obj, handle); + + /* drop reference from allocate - handle holds it now */ + drm_gem_object_put_unlocked(obj); + + return ret; +} + +static int msm_gem_new_impl(struct drm_device *dev, + uint32_t size, uint32_t flags, + struct reservation_object *resv, + struct drm_gem_object **obj, + bool struct_mutex_locked) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_gem_object *msm_obj; + + switch (flags & MSM_BO_CACHE_MASK) { + case MSM_BO_UNCACHED: + case MSM_BO_CACHED: + case MSM_BO_WC: + break; + default: + dev_err(dev->dev, "invalid cache flag: %x\n", + (flags & MSM_BO_CACHE_MASK)); + return -EINVAL; + } + + msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL); + if (!msm_obj) + return -ENOMEM; + + mutex_init(&msm_obj->lock); + + msm_obj->flags = flags; + msm_obj->madv = MSM_MADV_WILLNEED; + + if (resv) { + msm_obj->resv = resv; + } else { + msm_obj->resv = &msm_obj->_resv; + reservation_object_init(msm_obj->resv); + } + + INIT_LIST_HEAD(&msm_obj->submit_entry); + INIT_LIST_HEAD(&msm_obj->vmas); + INIT_LIST_HEAD(&msm_obj->iova_list); + msm_obj->aspace = NULL; + msm_obj->in_active_list = false; + msm_obj->obj_dirty = false; + + if (struct_mutex_locked) { + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); + } else { + mutex_lock(&dev->struct_mutex); + list_add_tail(&msm_obj->mm_list, &priv->inactive_list); + mutex_unlock(&dev->struct_mutex); + } + + *obj = &msm_obj->base; + + return 0; +} + +static struct drm_gem_object *_msm_gem_new(struct drm_device *dev, + uint32_t size, uint32_t flags, bool struct_mutex_locked) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_gem_object *obj = NULL; + bool use_vram = false; + int ret; + + size = PAGE_ALIGN(size); + + if (!iommu_present(&platform_bus_type)) + use_vram = true; + else if ((flags & MSM_BO_STOLEN) && priv->vram.size) + use_vram = true; + + if (WARN_ON(use_vram && !priv->vram.size)) + return ERR_PTR(-EINVAL); + + /* Disallow zero sized objects as they make the underlying + * infrastructure grumpy + */ + if (size == 0) + return ERR_PTR(-EINVAL); + + ret = msm_gem_new_impl(dev, size, flags, NULL, &obj, struct_mutex_locked); + if (ret) + goto fail; + + if (use_vram) { + struct msm_gem_vma *vma; + struct page **pages; + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + mutex_lock(&msm_obj->lock); + + vma = add_vma(obj, NULL); + mutex_unlock(&msm_obj->lock); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto fail; + } + + to_msm_bo(obj)->vram_node = &vma->node; + + drm_gem_private_object_init(dev, obj, size); + + pages = get_pages(obj); + if (IS_ERR(pages)) { + ret = PTR_ERR(pages); + goto fail; + } + + vma->iova = physaddr(obj); + } else { + ret = drm_gem_object_init(dev, obj, size); + if (ret) + goto fail; + } + + return obj; + +fail: + drm_gem_object_put_unlocked(obj); + return ERR_PTR(ret); +} + +struct drm_gem_object *msm_gem_new_locked(struct drm_device *dev, + uint32_t size, uint32_t flags) +{ + return _msm_gem_new(dev, size, flags, true); +} + +struct drm_gem_object *msm_gem_new(struct drm_device *dev, + uint32_t size, uint32_t flags) +{ + return _msm_gem_new(dev, size, flags, false); +} + +int msm_gem_delayed_import(struct drm_gem_object *obj) +{ + struct dma_buf_attachment *attach; + struct sg_table *sgt; + struct msm_gem_object *msm_obj; + int ret = 0; + + if (!obj) { + DRM_ERROR("NULL drm gem object\n"); + return -EINVAL; + } + + msm_obj = to_msm_bo(obj); + + if (!obj->import_attach) { + DRM_ERROR("NULL dma_buf_attachment in drm gem object\n"); + return -EINVAL; + } + + attach = obj->import_attach; + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + + if (msm_obj->flags & MSM_BO_SKIPSYNC) + attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + + if (msm_obj->flags & MSM_BO_KEEPATTRS) + attach->dma_map_attrs |= + DMA_ATTR_IOMMU_USE_UPSTREAM_HINT; + + /* + * dma_buf_map_attachment will call dma_map_sg for ion buffer + * mapping, and iova will get mapped when the function returns. + */ + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + DRM_ERROR("dma_buf_map_attachment failure, err=%d\n", + ret); + goto fail_import; + } + msm_obj->sgt = sgt; + msm_obj->pages = NULL; + +fail_import: + return ret; +} + +struct drm_gem_object *msm_gem_import(struct drm_device *dev, + struct dma_buf *dmabuf, struct sg_table *sgt) +{ + struct msm_gem_object *msm_obj; + struct drm_gem_object *obj = NULL; + uint32_t size; + int ret; + unsigned long flags = 0; + + /* if we don't have IOMMU, don't bother pretending we can import: */ + if (!iommu_present(&platform_bus_type)) { + dev_err(dev->dev, "cannot import without IOMMU\n"); + return ERR_PTR(-EINVAL); + } + + size = PAGE_ALIGN(dmabuf->size); + + ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj, + false); + if (ret) + goto fail; + + drm_gem_private_object_init(dev, obj, size); + + msm_obj = to_msm_bo(obj); + mutex_lock(&msm_obj->lock); + msm_obj->sgt = sgt; + msm_obj->pages = NULL; + /* + * 1) If sg table is NULL, user should call msm_gem_delayed_import + * to add back the sg table to the drm gem object. + * + * 2) Add buffer flag unconditionally for all import cases. + * # Cached buffer will be attached immediately hence sgt will + * be available upon gem obj creation. + * # Un-cached buffer will follow delayed attach hence sgt + * will be NULL upon gem obj creation. + */ + msm_obj->flags |= MSM_BO_EXTBUF; + + /* + * For all uncached buffers, there is no need to perform cache + * maintenance on dma map/unmap time. + */ + ret = dma_buf_get_flags(dmabuf, &flags); + if (ret) { + DRM_ERROR("dma_buf_get_flags failure, err=%d\n", ret); + } else if ((flags & ION_FLAG_CACHED) == 0) { + DRM_DEBUG("Buffer is uncached type\n"); + msm_obj->flags |= MSM_BO_SKIPSYNC; + } + + mutex_unlock(&msm_obj->lock); + return obj; + +fail: + drm_gem_object_put_unlocked(obj); + return ERR_PTR(ret); +} + +static void *_msm_gem_kernel_new(struct drm_device *dev, uint32_t size, + uint32_t flags, struct msm_gem_address_space *aspace, + struct drm_gem_object **bo, uint64_t *iova, bool locked) +{ + void *vaddr; + struct drm_gem_object *obj = _msm_gem_new(dev, size, flags, locked); + int ret; + + if (IS_ERR(obj)) + return ERR_CAST(obj); + + if (iova) { + ret = msm_gem_get_iova(obj, aspace, iova); + if (ret) { + drm_gem_object_put(obj); + return ERR_PTR(ret); + } + } + + vaddr = msm_gem_get_vaddr(obj); + if (IS_ERR(vaddr)) { + msm_gem_put_iova(obj, aspace); + drm_gem_object_put(obj); + return ERR_CAST(vaddr); + } + + if (bo) + *bo = obj; + + return vaddr; +} + +void *msm_gem_kernel_new(struct drm_device *dev, uint32_t size, + uint32_t flags, struct msm_gem_address_space *aspace, + struct drm_gem_object **bo, uint64_t *iova) +{ + return _msm_gem_kernel_new(dev, size, flags, aspace, bo, iova, false); +} + +void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size, + uint32_t flags, struct msm_gem_address_space *aspace, + struct drm_gem_object **bo, uint64_t *iova) +{ + return _msm_gem_kernel_new(dev, size, flags, aspace, bo, iova, true); +} diff --git a/techpack/display/msm/msm_gem.h b/techpack/display/msm/msm_gem.h new file mode 100644 index 0000000000000000000000000000000000000000..9b9290e03b62c930000a49ef37bbe25933103f0a --- /dev/null +++ b/techpack/display/msm/msm_gem.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_GEM_H__ +#define __MSM_GEM_H__ + +#include <linux/kref.h> +#include <linux/reservation.h> +#include "msm_drv.h" + +/* Additional internal-use only BO flags: */ +#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ +#define MSM_BO_KEEPATTRS 0x20000000 /* keep h/w bus attributes */ +#define MSM_BO_SKIPSYNC 0x40000000 /* skip dmabuf cpu sync */ +#define MSM_BO_EXTBUF 0x80000000 /* indicate BO is an import buffer */ + +struct msm_gem_object; + +struct msm_gem_aspace_ops { + int (*map)(struct msm_gem_address_space *space, struct msm_gem_vma *vma, + struct sg_table *sgt, int npages, unsigned int flags); + + void (*unmap)(struct msm_gem_address_space *space, + struct msm_gem_vma *vma, struct sg_table *sgt, + unsigned int flags); + + void (*destroy)(struct msm_gem_address_space *space); + void (*add_to_active)(struct msm_gem_address_space *space, + struct msm_gem_object *obj); + void (*remove_from_active)(struct msm_gem_address_space *space, + struct msm_gem_object *obj); + int (*register_cb)(struct msm_gem_address_space *space, + void (*cb)(void *cb, bool data), + void *cb_data); + int (*unregister_cb)(struct msm_gem_address_space *space, + void (*cb)(void *cb, bool data), + void *cb_data); +}; + +struct aspace_client { + void (*cb)(void *cb, bool data); + void *cb_data; + struct list_head list; +}; + + +struct msm_gem_address_space { + const char *name; + /* NOTE: mm managed at the page level, size is in # of pages + * and position mm_node->start is in # of pages: + */ + struct drm_mm mm; + spinlock_t lock; /* Protects drm_mm node allocation/removal */ + struct msm_mmu *mmu; + struct kref kref; + bool domain_attached; + const struct msm_gem_aspace_ops *ops; + struct drm_device *dev; + /* list of mapped objects */ + struct list_head active_list; + /* list of clients */ + struct list_head clients; + struct mutex list_lock; /* Protects active_list & clients */ +}; + +struct msm_gem_vma { + struct drm_mm_node node; + uint64_t iova; + struct msm_gem_address_space *aspace; + struct list_head list; /* node in msm_gem_object::vmas */ +}; + +struct msm_gem_object { + struct drm_gem_object base; + + uint32_t flags; + + /** + * Advice: are the backing pages purgeable? + */ + uint8_t madv; + + /** + * count of active vmap'ing + */ + uint8_t vmap_count; + + /* And object is either: + * inactive - on priv->inactive_list + * active - on one one of the gpu's active_list.. well, at + * least for now we don't have (I don't think) hw sync between + * 2d and 3d one devices which have both, meaning we need to + * block on submit if a bo is already on other ring + * + */ + struct list_head mm_list; + struct msm_gpu *gpu; /* non-null if active */ + + /* Transiently in the process of submit ioctl, objects associated + * with the submit are on submit->bo_list.. this only lasts for + * the duration of the ioctl, so one bo can never be on multiple + * submit lists. + */ + struct list_head submit_entry; + + struct page **pages; + struct sg_table *sgt; + void *vaddr; + + struct list_head vmas; /* list of msm_gem_vma */ + + /* normally (resv == &_resv) except for imported bo's */ + struct reservation_object *resv; + struct reservation_object _resv; + + /* For physically contiguous buffers. Used when we don't have + * an IOMMU. Also used for stolen/splashscreen buffer. + */ + struct drm_mm_node *vram_node; + struct mutex lock; /* Protects resources associated with bo */ + struct list_head iova_list; + + struct msm_gem_address_space *aspace; + bool in_active_list; + + /* Indicates whether object needs to request for + * new pagetables due to cb switch + */ + bool obj_dirty; +}; +#define to_msm_bo(x) container_of(x, struct msm_gem_object, base) + +static inline bool is_active(struct msm_gem_object *msm_obj) +{ + return msm_obj->gpu != NULL; +} + +static inline bool is_purgeable(struct msm_gem_object *msm_obj) +{ + WARN_ON(!mutex_is_locked(&msm_obj->base.dev->struct_mutex)); + return (msm_obj->madv == MSM_MADV_DONTNEED) && msm_obj->sgt && + !msm_obj->base.dma_buf && !msm_obj->base.import_attach; +} + +static inline bool is_vunmapable(struct msm_gem_object *msm_obj) +{ + return (msm_obj->vmap_count == 0) && msm_obj->vaddr; +} + +/* The shrinker can be triggered while we hold objA->lock, and need + * to grab objB->lock to purge it. Lockdep just sees these as a single + * class of lock, so we use subclasses to teach it the difference. + * + * OBJ_LOCK_NORMAL is implicit (ie. normal mutex_lock() call), and + * OBJ_LOCK_SHRINKER is used by shrinker. + * + * It is *essential* that we never go down paths that could trigger the + * shrinker for a purgable object. This is ensured by checking that + * msm_obj->madv == MSM_MADV_WILLNEED. + */ +enum msm_gem_lock { + OBJ_LOCK_NORMAL, + OBJ_LOCK_SHRINKER, +}; + +void msm_gem_purge(struct drm_gem_object *obj, enum msm_gem_lock subclass); +void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass); + +/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, + * associated with the cmdstream submission for synchronization (and + * make it easier to unwind when things go wrong, etc). This only + * lasts for the duration of the submit-ioctl. + */ +struct msm_gem_submit { + struct drm_device *dev; + struct msm_gpu *gpu; + struct list_head node; /* node in ring submit list */ + struct list_head bo_list; + struct ww_acquire_ctx ticket; + uint32_t seqno; /* Sequence number of the submit on the ring */ + struct dma_fence *fence; + struct msm_gpu_submitqueue *queue; + struct pid *pid; /* submitting process */ + bool valid; /* true if no cmdstream patching needed */ + bool in_rb; /* "sudo" mode, copy cmds into RB */ + struct msm_ringbuffer *ring; + unsigned int nr_cmds; + unsigned int nr_bos; + struct { + uint32_t type; + uint32_t size; /* in dwords */ + uint64_t iova; + uint32_t idx; /* cmdstream buffer idx in bos[] */ + } *cmd; /* array of size nr_cmds */ + struct { + uint32_t flags; + struct msm_gem_object *obj; + uint64_t iova; + } bos[0]; +}; + +#endif /* __MSM_GEM_H__ */ diff --git a/techpack/display/msm/msm_gem_prime.c b/techpack/display/msm/msm_gem_prime.c new file mode 100644 index 0000000000000000000000000000000000000000..d40f0fd502d19a4bcaa2a8abcac671dc6e02b8f1 --- /dev/null +++ b/techpack/display/msm/msm_gem_prime.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_gem.h" +#include "msm_mmu.h" +#include "msm_kms.h" + +#include <linux/dma-buf.h> +#include <linux/ion.h> +#include <linux/msm_ion.h> + +struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + int npages = obj->size >> PAGE_SHIFT; + + if (WARN_ON(!msm_obj->pages)) /* should have already pinned! */ + return NULL; + + return drm_prime_pages_to_sg(msm_obj->pages, npages); +} + +void *msm_gem_prime_vmap(struct drm_gem_object *obj) +{ + return msm_gem_get_vaddr(obj); +} + +void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) +{ + msm_gem_put_vaddr(obj); +} + +int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +{ + int ret; + + ret = drm_gem_mmap_obj(obj, obj->size, vma); + if (ret < 0) + return ret; + + return msm_gem_mmap_obj(vma->vm_private_data, vma); +} + +struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, struct sg_table *sg) +{ + return msm_gem_import(dev, attach->dmabuf, sg); +} + +int msm_gem_prime_pin(struct drm_gem_object *obj) +{ + if (!obj->import_attach) + msm_gem_get_pages(obj); + return 0; +} + +void msm_gem_prime_unpin(struct drm_gem_object *obj) +{ + if (!obj->import_attach) + msm_gem_put_pages(obj); +} + +struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + return msm_obj->resv; +} + + +struct drm_gem_object *msm_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf) +{ + struct dma_buf_attachment *attach; + struct sg_table *sgt = NULL; + struct drm_gem_object *obj; + struct device *attach_dev = NULL; + unsigned long flags = 0; + struct msm_drm_private *priv; + struct msm_kms *kms; + int ret; + + if (!dma_buf || !dev->dev_private) + return ERR_PTR(-EINVAL); + + priv = dev->dev_private; + kms = priv->kms; + + if (dma_buf->priv && !dma_buf->ops->begin_cpu_access) { + obj = dma_buf->priv; + if (obj->dev == dev) { + /* + * Importing dmabuf exported from out own gem increases + * refcount on gem itself instead of f_count of dmabuf. + */ + drm_gem_object_get(obj); + return obj; + } + } + + if (!dev->driver->gem_prime_import_sg_table) { + DRM_ERROR("NULL gem_prime_import_sg_table\n"); + return ERR_PTR(-EINVAL); + } + + get_dma_buf(dma_buf); + + ret = dma_buf_get_flags(dma_buf, &flags); + if (ret) { + DRM_ERROR("dma_buf_get_flags failure, err=%d\n", ret); + goto fail_put; + } + + if (!kms || !kms->funcs->get_address_space_device) { + DRM_ERROR("invalid kms ops\n"); + goto fail_put; + } + + if (flags & ION_FLAG_SECURE) { + if (flags & ION_FLAG_CP_PIXEL) { + attach_dev = kms->funcs->get_address_space_device(kms, + MSM_SMMU_DOMAIN_SECURE); + /* + * While transitioning from secure use-cases, the + * secure-cb might still not be attached back, while + * the prime_fd_to_handle call is made for the next + * frame. Attach those buffers to default drm device + * and reattaching with the correct context-bank + * will be handled in msm_gem_delayed_import + */ + if (!attach_dev) + attach_dev = dev->dev; + + } else if ((flags & ION_FLAG_CP_SEC_DISPLAY) + || (flags & ION_FLAG_CP_CAMERA_PREVIEW)) { + attach_dev = dev->dev; + } else { + DRM_ERROR("invalid ion secure flag: 0x%lx\n", flags); + } + } else { + attach_dev = kms->funcs->get_address_space_device(kms, + MSM_SMMU_DOMAIN_UNSECURE); + } + + if (!attach_dev) { + DRM_ERROR("aspace device not found for domain\n"); + ret = -EINVAL; + goto fail_put; + } + + attach = dma_buf_attach(dma_buf, attach_dev); + if (IS_ERR(attach)) { + DRM_ERROR("dma_buf_attach failure, err=%ld\n", PTR_ERR(attach)); + return ERR_CAST(attach); + } + + /* + * For cached buffers where CPU access is required, dma_map_attachment + * must be called now to allow user-space to perform cpu sync begin/end + * otherwise do delayed mapping during the commit. + */ + if (flags & ION_FLAG_CACHED) { + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + sgt = dma_buf_map_attachment( + attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + DRM_ERROR( + "dma_buf_map_attachment failure, err=%d\n", + ret); + goto fail_detach; + } + } + + /* + * If importing a NULL sg table (i.e. for uncached buffers), + * create a drm gem object with only the dma buf attachment. + */ + obj = dev->driver->gem_prime_import_sg_table(dev, attach, sgt); + if (IS_ERR(obj)) { + ret = PTR_ERR(obj); + DRM_ERROR("gem_prime_import_sg_table failure, err=%d\n", ret); + goto fail_unmap; + } + + obj->import_attach = attach; + + return obj; + +fail_unmap: + if (sgt) + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); +fail_detach: + dma_buf_detach(dma_buf, attach); +fail_put: + dma_buf_put(dma_buf); + + return ERR_PTR(ret); +} diff --git a/techpack/display/msm/msm_gem_vma.c b/techpack/display/msm/msm_gem_vma.c new file mode 100644 index 0000000000000000000000000000000000000000..2240f774dde6416ff991aa7d5465c29cd10c310d --- /dev/null +++ b/techpack/display/msm/msm_gem_vma.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2016 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_gem.h" +#include "msm_mmu.h" + +/* SDE address space operations */ +static void smmu_aspace_unmap_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + unsigned int flags) +{ + if (!vma->iova) + return; + + if (aspace) { + aspace->mmu->funcs->unmap_dma_buf(aspace->mmu, sgt, + DMA_BIDIRECTIONAL, flags); + } + + vma->iova = 0; + msm_gem_address_space_put(aspace); +} + +static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + int npages, unsigned int flags) +{ + int ret = -EINVAL; + + if (!aspace || !aspace->domain_attached) + return ret; + + ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, + DMA_BIDIRECTIONAL, flags); + if (!ret) + vma->iova = sg_dma_address(sgt->sgl); + + /* Get a reference to the aspace to keep it around */ + kref_get(&aspace->kref); + + return ret; +} + +static void smmu_aspace_destroy(struct msm_gem_address_space *aspace) +{ + if (aspace->mmu) + aspace->mmu->funcs->destroy(aspace->mmu); +} + +static void smmu_aspace_add_to_active( + struct msm_gem_address_space *aspace, + struct msm_gem_object *msm_obj) +{ + WARN_ON(!mutex_is_locked(&aspace->list_lock)); + list_move_tail(&msm_obj->iova_list, &aspace->active_list); + msm_obj->in_active_list = true; +} + +static void smmu_aspace_remove_from_active( + struct msm_gem_address_space *aspace, + struct msm_gem_object *obj) +{ + struct msm_gem_object *msm_obj, *next; + + WARN_ON(!mutex_is_locked(&aspace->list_lock)); + + list_for_each_entry_safe(msm_obj, next, &aspace->active_list, + iova_list) { + if (msm_obj == obj) { + msm_obj->in_active_list = false; + list_del(&msm_obj->iova_list); + break; + } + } +} + +static int smmu_aspace_register_cb( + struct msm_gem_address_space *aspace, + void (*cb)(void *, bool), + void *cb_data) +{ + struct aspace_client *aclient = NULL; + struct aspace_client *temp; + + if (!aspace) + return -EINVAL; + + if (!aspace->domain_attached) + return -EACCES; + + aclient = kzalloc(sizeof(*aclient), GFP_KERNEL); + if (!aclient) + return -ENOMEM; + + aclient->cb = cb; + aclient->cb_data = cb_data; + INIT_LIST_HEAD(&aclient->list); + + /* check if callback is already registered */ + mutex_lock(&aspace->list_lock); + list_for_each_entry(temp, &aspace->clients, list) { + if ((temp->cb == aclient->cb) && + (temp->cb_data == aclient->cb_data)) { + kfree(aclient); + mutex_unlock(&aspace->list_lock); + return -EEXIST; + } + } + + list_move_tail(&aclient->list, &aspace->clients); + mutex_unlock(&aspace->list_lock); + + return 0; +} + +static int smmu_aspace_unregister_cb( + struct msm_gem_address_space *aspace, + void (*cb)(void *, bool), + void *cb_data) +{ + struct aspace_client *aclient = NULL; + int rc = -ENOENT; + + if (!aspace || !cb) + return -EINVAL; + + mutex_lock(&aspace->list_lock); + list_for_each_entry(aclient, &aspace->clients, list) { + if ((aclient->cb == cb) && + (aclient->cb_data == cb_data)) { + list_del(&aclient->list); + kfree(aclient); + rc = 0; + break; + } + } + mutex_unlock(&aspace->list_lock); + + return rc; +} + +static const struct msm_gem_aspace_ops smmu_aspace_ops = { + .map = smmu_aspace_map_vma, + .unmap = smmu_aspace_unmap_vma, + .destroy = smmu_aspace_destroy, + .add_to_active = smmu_aspace_add_to_active, + .remove_from_active = smmu_aspace_remove_from_active, + .register_cb = smmu_aspace_register_cb, + .unregister_cb = smmu_aspace_unregister_cb, +}; + +struct msm_gem_address_space * +msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu, + const char *name) +{ + struct msm_gem_address_space *aspace; + + if (!mmu) + return ERR_PTR(-EINVAL); + + aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); + if (!aspace) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&aspace->lock); + aspace->dev = dev; + aspace->name = name; + aspace->mmu = mmu; + aspace->ops = &smmu_aspace_ops; + INIT_LIST_HEAD(&aspace->active_list); + INIT_LIST_HEAD(&aspace->clients); + kref_init(&aspace->kref); + mutex_init(&aspace->list_lock); + + return aspace; +} + +static void +msm_gem_address_space_destroy(struct kref *kref) +{ + struct msm_gem_address_space *aspace = container_of(kref, + struct msm_gem_address_space, kref); + + if (aspace && aspace->ops->destroy) + aspace->ops->destroy(aspace); + + kfree(aspace); +} + + +void msm_gem_address_space_put(struct msm_gem_address_space *aspace) +{ + if (aspace) + kref_put(&aspace->kref, msm_gem_address_space_destroy); +} + +/* GPU address space operations */ +static void iommu_aspace_unmap_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + unsigned int flags) +{ + if (!aspace || !vma->iova) + return; + + if (aspace->mmu) { + unsigned size = vma->node.size << PAGE_SHIFT; + aspace->mmu->funcs->unmap(aspace->mmu, vma->iova, sgt, size); + } + + spin_lock(&aspace->lock); + drm_mm_remove_node(&vma->node); + spin_unlock(&aspace->lock); + + vma->iova = 0; + + msm_gem_address_space_put(aspace); +} + +void +msm_gem_unmap_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + unsigned int flags) +{ + if (aspace && aspace->ops->unmap) + aspace->ops->unmap(aspace, vma, sgt, flags); +} + + +static int iommu_aspace_map_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, + int npages, unsigned int flags) +{ + int ret; + + spin_lock(&aspace->lock); + if (WARN_ON(drm_mm_node_allocated(&vma->node))) { + spin_unlock(&aspace->lock); + return 0; + } + + ret = drm_mm_insert_node(&aspace->mm, &vma->node, npages); + spin_unlock(&aspace->lock); + + if (ret) + return ret; + + vma->iova = vma->node.start << PAGE_SHIFT; + + if (aspace->mmu) { + unsigned size = npages << PAGE_SHIFT; + ret = aspace->mmu->funcs->map(aspace->mmu, vma->iova, sgt, + size, IOMMU_READ | IOMMU_WRITE); + } + + /* Get a reference to the aspace to keep it around */ + kref_get(&aspace->kref); + + return ret; +} + +static void iommu_aspace_destroy(struct msm_gem_address_space *aspace) +{ + drm_mm_takedown(&aspace->mm); + if (aspace->mmu) + aspace->mmu->funcs->destroy(aspace->mmu); +} + +static const struct msm_gem_aspace_ops msm_iommu_aspace_ops = { + .map = iommu_aspace_map_vma, + .unmap = iommu_aspace_unmap_vma, + .destroy = iommu_aspace_destroy, +}; + +struct msm_gem_address_space * +msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, + const char *name) +{ + struct msm_gem_address_space *aspace; + u64 size = domain->geometry.aperture_end - + domain->geometry.aperture_start; + + aspace = kzalloc(sizeof(*aspace), GFP_KERNEL); + if (!aspace) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&aspace->lock); + aspace->name = name; + aspace->mmu = msm_iommu_new(dev, domain); + aspace->ops = &msm_iommu_aspace_ops; + + drm_mm_init(&aspace->mm, (domain->geometry.aperture_start >> PAGE_SHIFT), + size >> PAGE_SHIFT); + + kref_init(&aspace->kref); + + return aspace; +} + +int +msm_gem_map_vma(struct msm_gem_address_space *aspace, + struct msm_gem_vma *vma, struct sg_table *sgt, int npages, + unsigned int flags) +{ + if (aspace && aspace->ops->map) + return aspace->ops->map(aspace, vma, sgt, npages, flags); + + return -EINVAL; +} + +struct device *msm_gem_get_aspace_device(struct msm_gem_address_space *aspace) +{ + struct device *client_dev = NULL; + + if (aspace && aspace->mmu && aspace->mmu->funcs->get_dev) + client_dev = aspace->mmu->funcs->get_dev(aspace->mmu); + + return client_dev; +} + +void msm_gem_add_obj_to_aspace_active_list( + struct msm_gem_address_space *aspace, + struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + if (aspace && aspace->ops && aspace->ops->add_to_active) + aspace->ops->add_to_active(aspace, msm_obj); +} + +void msm_gem_remove_obj_from_aspace_active_list( + struct msm_gem_address_space *aspace, + struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + if (aspace && aspace->ops && aspace->ops->remove_from_active) + aspace->ops->remove_from_active(aspace, msm_obj); +} + +int msm_gem_address_space_register_cb(struct msm_gem_address_space *aspace, + void (*cb)(void *, bool), + void *cb_data) +{ + if (aspace && aspace->ops && aspace->ops->register_cb) + return aspace->ops->register_cb(aspace, cb, cb_data); + + return -EINVAL; +} + +int msm_gem_address_space_unregister_cb(struct msm_gem_address_space *aspace, + void (*cb)(void *, bool), + void *cb_data) +{ + if (aspace && aspace->ops && aspace->ops->unregister_cb) + return aspace->ops->unregister_cb(aspace, cb, cb_data); + + return -EINVAL; +} + diff --git a/techpack/display/msm/msm_iommu.c b/techpack/display/msm/msm_iommu.c new file mode 100644 index 0000000000000000000000000000000000000000..2a90aa4caec081b2349ce115d77f4225d22ab3a4 --- /dev/null +++ b/techpack/display/msm/msm_iommu.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "msm_drv.h" +#include "msm_mmu.h" + +struct msm_iommu { + struct msm_mmu base; + struct iommu_domain *domain; +}; +#define to_msm_iommu(x) container_of(x, struct msm_iommu, base) + +static int msm_fault_handler(struct iommu_domain *domain, struct device *dev, + unsigned long iova, int flags, void *arg) +{ + struct msm_iommu *iommu = arg; + if (iommu->base.handler) + return iommu->base.handler(iommu->base.arg, iova, flags); + pr_warn_ratelimited("*** fault: iova=%08lx, flags=%d\n", iova, flags); + return 0; +} + +static int msm_iommu_attach(struct msm_mmu *mmu, const char * const *names, + int cnt) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + int ret; + + pm_runtime_get_sync(mmu->dev); + ret = iommu_attach_device(iommu->domain, mmu->dev); + pm_runtime_put_sync(mmu->dev); + + return ret; +} + +static void msm_iommu_detach(struct msm_mmu *mmu, const char * const *names, + int cnt) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + + pm_runtime_get_sync(mmu->dev); + iommu_detach_device(iommu->domain, mmu->dev); + pm_runtime_put_sync(mmu->dev); +} + +static int msm_iommu_map(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, unsigned len, int prot) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + size_t ret; + +// pm_runtime_get_sync(mmu->dev); + ret = iommu_map_sg(iommu->domain, iova, sgt->sgl, sgt->nents, prot); +// pm_runtime_put_sync(mmu->dev); + WARN_ON(!ret); + + return (ret == len) ? 0 : -EINVAL; +} + +static int msm_iommu_unmap(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, unsigned len) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + + pm_runtime_get_sync(mmu->dev); + iommu_unmap(iommu->domain, iova, len); + pm_runtime_put_sync(mmu->dev); + + return 0; +} + +static void msm_iommu_destroy(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + iommu_domain_free(iommu->domain); + kfree(iommu); +} + +static const struct msm_mmu_funcs funcs = { + .attach = msm_iommu_attach, + .detach = msm_iommu_detach, + .map = msm_iommu_map, + .unmap = msm_iommu_unmap, + .destroy = msm_iommu_destroy, +}; + +struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain) +{ + struct msm_iommu *iommu; + + iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); + if (!iommu) + return ERR_PTR(-ENOMEM); + + iommu->domain = domain; + msm_mmu_init(&iommu->base, dev, &funcs); + iommu_set_fault_handler(domain, msm_fault_handler, iommu); + + return &iommu->base; +} diff --git a/techpack/display/msm/msm_kms.h b/techpack/display/msm/msm_kms.h new file mode 100644 index 0000000000000000000000000000000000000000..d6ff517afb8ff97723a205c7651761d9cb092fb7 --- /dev/null +++ b/techpack/display/msm/msm_kms.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_KMS_H__ +#define __MSM_KMS_H__ + +#include <linux/clk.h> +#include <linux/regulator/consumer.h> + +#include "msm_drv.h" + +#define MAX_PLANE 4 + +/** + * Device Private DRM Mode Flags + * drm_mode->private_flags + */ +/* Connector has interpreted seamless transition request as dynamic fps */ +#define MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS (1<<0) +/* Transition to new mode requires a wait-for-vblank before the modeset */ +#define MSM_MODE_FLAG_VBLANK_PRE_MODESET (1<<1) +/* Request to switch the connector mode */ +#define MSM_MODE_FLAG_SEAMLESS_DMS (1<<2) +/* Request to switch the fps */ +#define MSM_MODE_FLAG_SEAMLESS_VRR (1<<3) +/* Request to switch the panel mode */ +#define MSM_MODE_FLAG_SEAMLESS_POMS (1<<4) +/* Request to switch the bit clk */ +#define MSM_MODE_FLAG_SEAMLESS_DYN_CLK (1<<5) + +/* As there are different display controller blocks depending on the + * snapdragon version, the kms support is split out and the appropriate + * implementation is loaded at runtime. The kms module is responsible + * for constructing the appropriate planes/crtcs/encoders/connectors. + */ +struct msm_kms_funcs { + /* hw initialization: */ + int (*hw_init)(struct msm_kms *kms); + int (*postinit)(struct msm_kms *kms); + /* irq handling: */ + void (*irq_preinstall)(struct msm_kms *kms); + int (*irq_postinstall)(struct msm_kms *kms); + void (*irq_uninstall)(struct msm_kms *kms); + irqreturn_t (*irq)(struct msm_kms *kms); + int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); + void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); + /* modeset, bracketing atomic_commit(): */ + void (*prepare_fence)(struct msm_kms *kms, + struct drm_atomic_state *state); + void (*prepare_commit)(struct msm_kms *kms, + struct drm_atomic_state *state); + void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state); + void (*complete_commit)(struct msm_kms *kms, + struct drm_atomic_state *state); + /* functions to wait for atomic commit completed on each CRTC */ + void (*wait_for_crtc_commit_done)(struct msm_kms *kms, + struct drm_crtc *crtc); + /* function pointer to wait for pixel transfer to panel to complete*/ + void (*wait_for_tx_complete)(struct msm_kms *kms, + struct drm_crtc *crtc); + /* get msm_format w/ optional format modifiers from drm_mode_fb_cmd2 */ + const struct msm_format *(*get_format)(struct msm_kms *kms, + const uint32_t format, + const uint64_t modifier); + /* do format checking on format modified through fb_cmd2 modifiers */ + int (*check_modified_format)(const struct msm_kms *kms, + const struct msm_format *msm_fmt, + const struct drm_mode_fb_cmd2 *cmd, + struct drm_gem_object **bos); + /* perform complete atomic check of given atomic state */ + int (*atomic_check)(struct msm_kms *kms, + struct drm_atomic_state *state); + /* misc: */ + long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, + struct drm_encoder *encoder); + int (*set_split_display)(struct msm_kms *kms, + struct drm_encoder *encoder, + struct drm_encoder *slave_encoder, + bool is_cmd_mode); + void (*postopen)(struct msm_kms *kms, struct drm_file *file); + void (*preclose)(struct msm_kms *kms, struct drm_file *file); + void (*postclose)(struct msm_kms *kms, struct drm_file *file); + void (*lastclose)(struct msm_kms *kms, + struct drm_modeset_acquire_ctx *ctx); + int (*register_events)(struct msm_kms *kms, + struct drm_mode_object *obj, u32 event, bool en); + void (*set_encoder_mode)(struct msm_kms *kms, + struct drm_encoder *encoder, + bool cmd_mode); + /* pm suspend/resume hooks */ + int (*pm_suspend)(struct device *dev); + int (*pm_resume)(struct device *dev); + /* cleanup: */ + void (*destroy)(struct msm_kms *kms); + /* get address space */ + struct msm_gem_address_space *(*get_address_space)( + struct msm_kms *kms, + unsigned int domain); + struct device *(*get_address_space_device)( + struct msm_kms *kms, + unsigned int domain); +#ifdef CONFIG_DEBUG_FS + /* debugfs: */ + int (*debugfs_init)(struct msm_kms *kms, struct drm_minor *minor); +#endif + /* handle continuous splash */ + int (*cont_splash_config)(struct msm_kms *kms); + /* check for continuous splash status */ + bool (*check_for_splash)(struct msm_kms *kms, struct drm_crtc *crtc); + /* topology information */ + int (*get_mixer_count)(const struct msm_kms *kms, + const struct drm_display_mode *mode, + const struct msm_resource_caps_info *res, u32 *num_lm); +}; + +struct msm_kms { + const struct msm_kms_funcs *funcs; + + /* irq number to be passed on to drm_irq_install */ + int irq; + + /* mapper-id used to request GEM buffer mapped for scanout: */ + struct msm_gem_address_space *aspace; +}; + +/** + * Subclass of drm_atomic_state, to allow kms backend to have driver + * private global state. The kms backend can do whatever it wants + * with the ->state ptr. On ->atomic_state_clear() the ->state ptr + * is kfree'd and set back to NULL. + */ +struct msm_kms_state { + struct drm_atomic_state base; + void *state; +}; +#define to_kms_state(x) container_of(x, struct msm_kms_state, base) + +static inline void msm_kms_init(struct msm_kms *kms, + const struct msm_kms_funcs *funcs) +{ + kms->funcs = funcs; +} + +#ifdef CONFIG_DRM_MSM_MDP4 +struct msm_kms *mdp4_kms_init(struct drm_device *dev); +#else +static inline +struct msm_kms *mdp4_kms_init(struct drm_device *dev) { return NULL; }; +#endif +#ifdef CONFIG_DRM_MSM_MDP5 +struct msm_kms *mdp5_kms_init(struct drm_device *dev); +int msm_mdss_init(struct drm_device *dev); +void msm_mdss_destroy(struct drm_device *dev); +struct msm_kms *mdp5_kms_init(struct drm_device *dev); +int msm_mdss_enable(struct msm_mdss *mdss); +int msm_mdss_disable(struct msm_mdss *mdss); +#else +static inline int msm_mdss_init(struct drm_device *dev) +{ + return 0; +} +static inline void msm_mdss_destroy(struct drm_device *dev) +{ +} +static inline struct msm_kms *mdp5_kms_init(struct drm_device *dev) +{ + return NULL; +} +static inline int msm_mdss_enable(struct msm_mdss *mdss) +{ + return 0; +} +static inline int msm_mdss_disable(struct msm_mdss *mdss) +{ + return 0; +} +#endif + +struct msm_kms *sde_kms_init(struct drm_device *dev); + + +/** + * Mode Set Utility Functions + */ +static inline bool msm_is_mode_seamless(const struct drm_display_mode *mode) +{ + return (mode->flags & DRM_MODE_FLAG_SEAMLESS); +} + +static inline bool msm_is_mode_seamless_dms(const struct drm_display_mode *mode) +{ + return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DMS) + : false; +} + +static inline bool msm_is_mode_dynamic_fps(const struct drm_display_mode *mode) +{ + return ((mode->flags & DRM_MODE_FLAG_SEAMLESS) && + (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS)); +} + +static inline bool msm_is_mode_seamless_vrr(const struct drm_display_mode *mode) +{ + return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_VRR) + : false; +} + +static inline bool msm_is_mode_seamless_poms( + const struct drm_display_mode *mode) +{ + return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS) + : false; +} + +static inline bool msm_is_mode_seamless_dyn_clk( + const struct drm_display_mode *mode) +{ + return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYN_CLK) + : false; +} + +static inline bool msm_needs_vblank_pre_modeset( + const struct drm_display_mode *mode) +{ + return (mode->private_flags & MSM_MODE_FLAG_VBLANK_PRE_MODESET); +} +#endif /* __MSM_KMS_H__ */ diff --git a/techpack/display/msm/msm_mmu.h b/techpack/display/msm/msm_mmu.h new file mode 100644 index 0000000000000000000000000000000000000000..ee6cbcd580794c477adeb61766b13ac4914f90f0 --- /dev/null +++ b/techpack/display/msm/msm_mmu.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __MSM_MMU_H__ +#define __MSM_MMU_H__ + +#include <linux/iommu.h> + +struct msm_mmu; + +enum msm_mmu_domain_type { + MSM_SMMU_DOMAIN_UNSECURE, + MSM_SMMU_DOMAIN_NRT_UNSECURE, + MSM_SMMU_DOMAIN_SECURE, + MSM_SMMU_DOMAIN_NRT_SECURE, + MSM_SMMU_DOMAIN_MAX, +}; + +struct msm_mmu_funcs { + int (*attach)(struct msm_mmu *mmu, const char * const *names, int cnt); + void (*detach)(struct msm_mmu *mmu, const char * const *names, int cnt); + int (*map)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, + unsigned int len, int prot); + int (*unmap)(struct msm_mmu *mmu, uint64_t iova, struct sg_table *sgt, + unsigned int len); + int (*map_sg)(struct msm_mmu *mmu, struct sg_table *sgt, + enum dma_data_direction dir); + void (*unmap_sg)(struct msm_mmu *mmu, struct sg_table *sgt, + enum dma_data_direction dir); + int (*map_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, + int dir, u32 flags); + void (*unmap_dma_buf)(struct msm_mmu *mmu, struct sg_table *sgt, + int dir, u32 flags); + void (*destroy)(struct msm_mmu *mmu); + bool (*is_domain_secure)(struct msm_mmu *mmu); + int (*set_attribute)(struct msm_mmu *mmu, + enum iommu_attr attr, void *data); + int (*one_to_one_map)(struct msm_mmu *mmu, uint32_t iova, + uint32_t dest_address, uint32_t size, int prot); + int (*one_to_one_unmap)(struct msm_mmu *mmu, uint32_t dest_address, + uint32_t size); + struct device *(*get_dev)(struct msm_mmu *mmu); +}; + +struct msm_mmu { + const struct msm_mmu_funcs *funcs; + struct device *dev; + int (*handler)(void *arg, unsigned long iova, int flags); + void *arg; +}; + +static inline void msm_mmu_init(struct msm_mmu *mmu, struct device *dev, + const struct msm_mmu_funcs *funcs) +{ + mmu->dev = dev; + mmu->funcs = funcs; +} + +struct msm_mmu *msm_iommu_new(struct device *dev, struct iommu_domain *domain); +struct msm_mmu *msm_smmu_new(struct device *dev, + enum msm_mmu_domain_type domain); + +static inline void msm_mmu_set_fault_handler(struct msm_mmu *mmu, void *arg, + int (*handler)(void *arg, unsigned long iova, int flags)) +{ + mmu->arg = arg; + mmu->handler = handler; +} + +/* SDE smmu driver initialize and cleanup functions */ +int __init msm_smmu_driver_init(void); +void __exit msm_smmu_driver_cleanup(void); + +#endif /* __MSM_MMU_H__ */ diff --git a/techpack/display/msm/msm_notifier.c b/techpack/display/msm/msm_notifier.c new file mode 100644 index 0000000000000000000000000000000000000000..f6cb9c56d0c6afac86bdbbcd6264b3c02723a2e8 --- /dev/null +++ b/techpack/display/msm/msm_notifier.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/of_platform.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/sched.h> + +#include <drm/drm_panel.h> +#include "sde_dbg.h" + +struct msm_display_fps_info { + uint32_t id; + enum fps fps; + struct list_head list; + struct drm_panel *panel; +}; + +static int msm_notifier_fps_chg_callback(struct notifier_block *nb, + unsigned long val, void *data); + +static struct notifier_block msm_notifier_block = { + .notifier_call = msm_notifier_fps_chg_callback, +}; + +struct notifier_info { + struct notifier_block notifier; +}; + +struct display_list { + struct list_head list; + enum fps max_fps; +}; + +static struct display_list *active_displays; + +static int msm_notifier_fps_chg_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + int fps; + enum fps sched_fps, max_fps; + struct drm_panel_notifier *notifier_data = + (struct drm_panel_notifier *) data; + struct msm_display_fps_info *display; + bool display_id_match = false; + + /* + * Get ceiling of fps from notifier data to pass to scheduler. + * Default will be FPS60 and sent to scheduler during suspend. + * Currently scheduler expects FPS120 for any fps over 90. + */ + fps = notifier_data->refresh_rate; + if (fps > FPS90) + sched_fps = FPS120; + else if (fps > FPS60) + sched_fps = FPS90; + else if (fps > FPS48) + sched_fps = FPS60; + else if (fps > FPS30) + sched_fps = FPS48; + else if (fps > FPS0) + sched_fps = FPS30; + else + sched_fps = FPS60; + + max_fps = sched_fps; + + /* + * Iterate displays and set id and fps if uninitialized. + * Update display's current fps if id match is found. + * Find max refresh rate to pass to scheduler. + */ + list_for_each_entry(display, &active_displays->list, list) { + if (!display->fps && !display_id_match) { + display->id = notifier_data->id; + display->fps = sched_fps; + } + + if (display->id == notifier_data->id) { + display_id_match = true; + display->fps = sched_fps; + } + + if (display->fps > max_fps) + max_fps = display->fps; + } + + if (max_fps != active_displays->max_fps) { + SDE_EVT32(notifier_data->id, + notifier_data->refresh_rate, max_fps); + + active_displays->max_fps = max_fps; + sched_set_refresh_rate(max_fps); + } + + return 0; +} + +static int msm_notifier_remove(struct platform_device *pdev) +{ + struct msm_display_fps_info *display; + struct notifier_info *info = platform_get_drvdata(pdev); + + list_for_each_entry(display, &active_displays->list, list) + drm_panel_notifier_unregister(display->panel, &info->notifier); + + return 0; +} + +static int msm_notifier_probe(struct platform_device *pdev) +{ + int i, count, ret = 0; + struct device_node *node; + struct drm_panel *panel; + struct notifier_info *info = NULL; + struct msm_display_fps_info *display; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->notifier = msm_notifier_block; + + platform_set_drvdata(pdev, info); + + active_displays = devm_kzalloc(&pdev->dev, + sizeof(*active_displays), GFP_KERNEL); + if (!active_displays) { + ret = -ENOMEM; + goto end; + } + + INIT_LIST_HEAD(&active_displays->list); + + /* Set default max fps to 0 */ + active_displays->max_fps = 0; + + count = of_count_phandle_with_args(pdev->dev.of_node, "panel", NULL); + + for (i = 0; i < count; i++) { + node = of_parse_phandle(pdev->dev.of_node, "panel", i); + panel = of_drm_find_panel(node); + of_node_put(node); + if (!IS_ERR(panel)) { + /* + * Add new msm_display_fps_info to linked list + * of active displays. Initialize fps as + * 0 to mark unassigned node. Assign when + * you get the first callback for that display + */ + struct msm_display_fps_info *display_fps_info = + devm_kzalloc(&pdev->dev, + sizeof(*display_fps_info), GFP_KERNEL); + if (!display_fps_info) { + ret = -ENOMEM; + goto fail; + } + + display_fps_info->panel = panel; + + list_add(&display_fps_info->list, + &active_displays->list); + + drm_panel_notifier_register(panel, &info->notifier); + } + } + + pr_info("msm notifier probed successfully\n"); + + return ret; +fail: + list_for_each_entry(display, &active_displays->list, list) + drm_panel_notifier_unregister(display->panel, &info->notifier); + + devm_kfree(&pdev->dev, active_displays); +end: + devm_kfree(&pdev->dev, info); + return ret; +} + +static const struct of_device_id dt_match[] = { + { .compatible = "qcom,msm-notifier"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, dt_match); + +static struct platform_driver msm_notifier_platform_driver = { + .probe = msm_notifier_probe, + .remove = msm_notifier_remove, + .driver = { + .name = "msm_notifier", + .of_match_table = dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init msm_notifier_register(void) +{ + return platform_driver_register(&msm_notifier_platform_driver); +} + +static void __exit msm_notifier_unregister(void) +{ + platform_driver_unregister(&msm_notifier_platform_driver); +} + +late_initcall(msm_notifier_register); +module_exit(msm_notifier_unregister); diff --git a/techpack/display/msm/msm_prop.c b/techpack/display/msm/msm_prop.c new file mode 100644 index 0000000000000000000000000000000000000000..d7c9eb0f847505370627548a97f3f0ec540c0fe2 --- /dev/null +++ b/techpack/display/msm/msm_prop.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include "msm_prop.h" + +void msm_property_init(struct msm_property_info *info, + struct drm_mode_object *base, + struct drm_device *dev, + struct drm_property **property_array, + struct msm_property_data *property_data, + uint32_t property_count, + uint32_t blob_count, + uint32_t state_size) +{ + /* prevent access if any of these are NULL */ + if (!base || !dev || !property_array || !property_data) { + property_count = 0; + blob_count = 0; + + DRM_ERROR("invalid arguments, forcing zero properties\n"); + return; + } + + /* can't have more blob properties than total properties */ + if (blob_count > property_count) { + blob_count = property_count; + + DBG("Capping number of blob properties to %d", blob_count); + } + + if (!info) { + DRM_ERROR("info pointer is NULL\n"); + } else { + info->base = base; + info->dev = dev; + info->property_array = property_array; + info->property_data = property_data; + info->property_count = property_count; + info->blob_count = blob_count; + info->install_request = 0; + info->install_count = 0; + info->recent_idx = 0; + info->is_active = false; + info->state_size = state_size; + info->state_cache_size = 0; + mutex_init(&info->property_lock); + + memset(property_data, + 0, + sizeof(struct msm_property_data) * + property_count); + } +} + +void msm_property_destroy(struct msm_property_info *info) +{ + if (!info) + return; + + /* free state cache */ + while (info->state_cache_size > 0) + kfree(info->state_cache[--(info->state_cache_size)]); + + mutex_destroy(&info->property_lock); +} + +int msm_property_pop_dirty(struct msm_property_info *info, + struct msm_property_state *property_state) +{ + struct list_head *item; + int rc = 0; + + if (!info || !property_state || !property_state->values) { + DRM_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + + WARN_ON(!mutex_is_locked(&info->property_lock)); + + if (list_empty(&property_state->dirty_list)) { + rc = -EAGAIN; + } else { + item = property_state->dirty_list.next; + list_del_init(item); + rc = container_of(item, struct msm_property_value, dirty_node) + - property_state->values; + DRM_DEBUG_KMS("property %d dirty\n", rc); + } + + return rc; +} + +/** + * _msm_property_set_dirty_no_lock - flag given property as being dirty + * This function doesn't mutex protect the + * dirty linked list. + * @info: Pointer to property info container struct + * @property_state: Pointer to property state container struct + * @property_idx: Property index + */ +static void _msm_property_set_dirty_no_lock( + struct msm_property_info *info, + struct msm_property_state *property_state, + uint32_t property_idx) +{ + if (!info || !property_state || !property_state->values || + property_idx >= info->property_count) { + DRM_ERROR("invalid argument(s), idx %u\n", property_idx); + return; + } + + /* avoid re-inserting if already dirty */ + if (!list_empty(&property_state->values[property_idx].dirty_node)) { + DRM_DEBUG_KMS("property %u already dirty\n", property_idx); + return; + } + + list_add_tail(&property_state->values[property_idx].dirty_node, + &property_state->dirty_list); +} + +bool msm_property_is_dirty( + struct msm_property_info *info, + struct msm_property_state *property_state, + uint32_t property_idx) +{ + if (!info || !property_state || !property_state->values || + property_idx >= info->property_count) { + DRM_ERROR("invalid argument(s), idx %u\n", property_idx); + return false; + } + + return !list_empty(&property_state->values[property_idx].dirty_node); +} + +/** + * _msm_property_install_integer - install standard drm range property + * @info: Pointer to property info container struct + * @name: Property name + * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE + * @min: Min property value + * @max: Max property value + * @init: Default Property value + * @property_idx: Property index + * @force_dirty: Whether or not to filter 'dirty' status on unchanged values + */ +static void _msm_property_install_integer(struct msm_property_info *info, + const char *name, int flags, uint64_t min, uint64_t max, + uint64_t init, uint32_t property_idx, bool force_dirty) +{ + struct drm_property **prop; + + if (!info) + return; + + ++info->install_request; + + if (!name || (property_idx >= info->property_count)) { + DRM_ERROR("invalid argument(s), %s\n", name ? name : "null"); + } else { + prop = &info->property_array[property_idx]; + /* + * Properties need to be attached to each drm object that + * uses them, but only need to be created once + */ + if (!*prop) { + *prop = drm_property_create_range(info->dev, + flags, name, min, max); + if (!*prop) + DRM_ERROR("create %s property failed\n", name); + } + + /* save init value for later */ + info->property_data[property_idx].default_value = init; + info->property_data[property_idx].force_dirty = force_dirty; + + /* always attach property, if created */ + if (*prop) { + drm_object_attach_property(info->base, *prop, init); + ++info->install_count; + } + } +} + +void msm_property_install_range(struct msm_property_info *info, + const char *name, int flags, uint64_t min, uint64_t max, + uint64_t init, uint32_t property_idx) +{ + _msm_property_install_integer(info, name, flags, + min, max, init, property_idx, false); +} + +void msm_property_install_volatile_range(struct msm_property_info *info, + const char *name, int flags, uint64_t min, uint64_t max, + uint64_t init, uint32_t property_idx) +{ + _msm_property_install_integer(info, name, flags, + min, max, init, property_idx, true); +} + +void msm_property_install_enum(struct msm_property_info *info, + const char *name, int flags, int is_bitmask, + const struct drm_prop_enum_list *values, int num_values, + uint32_t property_idx) +{ + struct drm_property **prop; + + if (!info) + return; + + ++info->install_request; + + if (!name || !values || !num_values || + (property_idx >= info->property_count)) { + DRM_ERROR("invalid argument(s), %s\n", name ? name : "null"); + } else { + prop = &info->property_array[property_idx]; + /* + * Properties need to be attached to each drm object that + * uses them, but only need to be created once + */ + if (!*prop) { + /* 'bitmask' is a special type of 'enum' */ + if (is_bitmask) + *prop = drm_property_create_bitmask(info->dev, + DRM_MODE_PROP_BITMASK | flags, + name, values, num_values, -1); + else + *prop = drm_property_create_enum(info->dev, + DRM_MODE_PROP_ENUM | flags, + name, values, num_values); + if (!*prop) + DRM_ERROR("create %s property failed\n", name); + } + + /* save init value for later */ + info->property_data[property_idx].default_value = 0; + info->property_data[property_idx].force_dirty = false; + + /* select first defined value for enums */ + if (!is_bitmask) + info->property_data[property_idx].default_value = + values->type; + + /* always attach property, if created */ + if (*prop) { + drm_object_attach_property(info->base, *prop, + info->property_data + [property_idx].default_value); + ++info->install_count; + } + } +} + +void msm_property_install_blob(struct msm_property_info *info, + const char *name, int flags, uint32_t property_idx) +{ + struct drm_property **prop; + + if (!info) + return; + + ++info->install_request; + + if (!name || (property_idx >= info->blob_count)) { + DRM_ERROR("invalid argument(s), %s\n", name ? name : "null"); + } else { + prop = &info->property_array[property_idx]; + /* + * Properties need to be attached to each drm object that + * uses them, but only need to be created once + */ + if (!*prop) { + /* use 'create' for blob property place holder */ + *prop = drm_property_create(info->dev, + DRM_MODE_PROP_BLOB | flags, name, 0); + if (!*prop) + DRM_ERROR("create %s property failed\n", name); + } + + /* save init value for later */ + info->property_data[property_idx].default_value = 0; + info->property_data[property_idx].force_dirty = true; + + /* always attach property, if created */ + if (*prop) { + drm_object_attach_property(info->base, *prop, -1); + ++info->install_count; + } + } +} + +int msm_property_install_get_status(struct msm_property_info *info) +{ + int rc = -ENOMEM; + + if (info && (info->install_request == info->install_count)) + rc = 0; + + return rc; +} + +int msm_property_index(struct msm_property_info *info, + struct drm_property *property) +{ + uint32_t count; + int32_t idx; + int rc = -EINVAL; + + if (!info || !property) { + DRM_ERROR("invalid argument(s)\n"); + } else { + /* + * Linear search, but start from last found index. This will + * help if any single property is accessed multiple times in a + * row. Ideally, we could keep a list of properties sorted in + * the order of most recent access, but that may be overkill + * for now. + */ + mutex_lock(&info->property_lock); + idx = info->recent_idx; + count = info->property_count; + while (count) { + --count; + + /* stop searching on match */ + if (info->property_array[idx] == property) { + info->recent_idx = idx; + rc = idx; + break; + } + + /* move to next valid index */ + if (--idx < 0) + idx = info->property_count - 1; + } + mutex_unlock(&info->property_lock); + } + + return rc; +} + +int msm_property_set_dirty(struct msm_property_info *info, + struct msm_property_state *property_state, + int property_idx) +{ + if (!info || !property_state || !property_state->values) { + DRM_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + mutex_lock(&info->property_lock); + _msm_property_set_dirty_no_lock(info, property_state, property_idx); + mutex_unlock(&info->property_lock); + return 0; +} + +int msm_property_atomic_set(struct msm_property_info *info, + struct msm_property_state *property_state, + struct drm_property *property, uint64_t val) +{ + struct drm_property_blob *blob; + int property_idx, rc = -EINVAL; + + if (!info || !property_state) { + DRM_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + + property_idx = msm_property_index(info, property); + if ((property_idx == -EINVAL) || !property_state->values) { + DRM_ERROR("invalid argument(s)\n"); + } else { + /* extra handling for incoming properties */ + mutex_lock(&info->property_lock); + if ((property->flags & DRM_MODE_PROP_BLOB) && + (property_idx < info->blob_count)) { + + /* need to clear previous ref */ + if (property_state->values[property_idx].blob) + drm_property_blob_put( + property_state->values[ + property_idx].blob); + + /* DRM lookup also takes a reference */ + blob = drm_property_lookup_blob(info->dev, + (uint32_t)val); + if (val && !blob) { + DRM_ERROR("prop %d blob id 0x%llx not found\n", + property_idx, val); + val = 0; + } else { + if (blob) { + DBG("Blob %u saved", blob->base.id); + val = blob->base.id; + } + + /* save the new blob */ + property_state->values[property_idx].blob = + blob; + } + } + + /* update value and flag as dirty */ + if (property_state->values[property_idx].value != val || + info->property_data[property_idx].force_dirty) { + property_state->values[property_idx].value = val; + _msm_property_set_dirty_no_lock(info, property_state, + property_idx); + + DBG("%s - %lld", property->name, val); + } + mutex_unlock(&info->property_lock); + rc = 0; + } + + return rc; +} + +int msm_property_atomic_get(struct msm_property_info *info, + struct msm_property_state *property_state, + struct drm_property *property, uint64_t *val) +{ + int property_idx, rc = -EINVAL; + + property_idx = msm_property_index(info, property); + if (!info || (property_idx == -EINVAL) || + !property_state->values || !val) { + DRM_DEBUG("Invalid argument(s)\n"); + } else { + mutex_lock(&info->property_lock); + *val = property_state->values[property_idx].value; + mutex_unlock(&info->property_lock); + rc = 0; + } + + return rc; +} + +void *msm_property_alloc_state(struct msm_property_info *info) +{ + void *state = NULL; + + if (!info) { + DRM_ERROR("invalid property info\n"); + return NULL; + } + + mutex_lock(&info->property_lock); + if (info->state_cache_size) + state = info->state_cache[--(info->state_cache_size)]; + mutex_unlock(&info->property_lock); + + if (!state && info->state_size) + state = kmalloc(info->state_size, GFP_KERNEL); + + if (!state) + DRM_ERROR("failed to allocate state\n"); + + return state; +} + +/** + * _msm_property_free_state - helper function for freeing local state objects + * @info: Pointer to property info container struct + * @st: Pointer to state object + */ +static void _msm_property_free_state(struct msm_property_info *info, void *st) +{ + if (!info || !st) + return; + + mutex_lock(&info->property_lock); + if (info->state_cache_size < MSM_PROP_STATE_CACHE_SIZE) + info->state_cache[(info->state_cache_size)++] = st; + else + kfree(st); + mutex_unlock(&info->property_lock); +} + +void msm_property_reset_state(struct msm_property_info *info, void *state, + struct msm_property_state *property_state, + struct msm_property_value *property_values) +{ + uint32_t i; + + if (!info) { + DRM_ERROR("invalid property info\n"); + return; + } + + if (state) + memset(state, 0, info->state_size); + + if (property_state) { + property_state->property_count = info->property_count; + property_state->values = property_values; + INIT_LIST_HEAD(&property_state->dirty_list); + } + + /* + * Assign default property values. This helper is mostly used + * to initialize newly created state objects. + */ + if (property_values) + for (i = 0; i < info->property_count; ++i) { + property_values[i].value = + info->property_data[i].default_value; + property_values[i].blob = NULL; + INIT_LIST_HEAD(&property_values[i].dirty_node); + } +} + +void msm_property_duplicate_state(struct msm_property_info *info, + void *old_state, void *state, + struct msm_property_state *property_state, + struct msm_property_value *property_values) +{ + uint32_t i; + + if (!info || !old_state || !state) { + DRM_ERROR("invalid argument(s)\n"); + return; + } + + memcpy(state, old_state, info->state_size); + + if (!property_state) + return; + + INIT_LIST_HEAD(&property_state->dirty_list); + property_state->values = property_values; + + if (property_state->values) + /* add ref count for blobs and initialize dirty nodes */ + for (i = 0; i < info->property_count; ++i) { + if (property_state->values[i].blob) + drm_property_blob_get( + property_state->values[i].blob); + INIT_LIST_HEAD(&property_state->values[i].dirty_node); + } +} + +void msm_property_destroy_state(struct msm_property_info *info, void *state, + struct msm_property_state *property_state) +{ + uint32_t i; + + if (!info || !state) { + DRM_ERROR("invalid argument(s)\n"); + return; + } + if (property_state && property_state->values) { + /* remove ref count for blobs */ + for (i = 0; i < info->property_count; ++i) + if (property_state->values[i].blob) { + drm_property_blob_put( + property_state->values[i].blob); + property_state->values[i].blob = NULL; + } + } + + _msm_property_free_state(info, state); +} + +void *msm_property_get_blob(struct msm_property_info *info, + struct msm_property_state *property_state, + size_t *byte_len, + uint32_t property_idx) +{ + struct drm_property_blob *blob; + size_t len = 0; + void *rc = 0; + + if (!info || !property_state || !property_state->values || + (property_idx >= info->blob_count)) { + DRM_ERROR("invalid argument(s)\n"); + } else { + blob = property_state->values[property_idx].blob; + if (blob) { + len = blob->length; + rc = blob->data; + } + } + + if (byte_len) + *byte_len = len; + + return rc; +} + +int msm_property_set_blob(struct msm_property_info *info, + struct drm_property_blob **blob_reference, + void *blob_data, + size_t byte_len, + uint32_t property_idx) +{ + struct drm_property_blob *blob = NULL; + int rc = -EINVAL; + + if (!info || !blob_reference || (property_idx >= info->blob_count)) { + DRM_ERROR("invalid argument(s)\n"); + } else { + /* create blob */ + if (blob_data && byte_len) { + blob = drm_property_create_blob(info->dev, + byte_len, + blob_data); + if (IS_ERR_OR_NULL(blob)) { + rc = PTR_ERR(blob); + DRM_ERROR("failed to create blob, %d\n", rc); + goto exit; + } + } + + /* update drm object */ + rc = drm_object_property_set_value(info->base, + info->property_array[property_idx], + blob ? blob->base.id : 0); + if (rc) { + DRM_ERROR("failed to set blob to property\n"); + if (blob) + drm_property_blob_put(blob); + goto exit; + } + + /* update local reference */ + if (*blob_reference) + drm_property_blob_put(*blob_reference); + *blob_reference = blob; + } + +exit: + return rc; +} + +int msm_property_set_property(struct msm_property_info *info, + struct msm_property_state *property_state, + uint32_t property_idx, + uint64_t val) +{ + int rc = -EINVAL; + + if (!info || (property_idx >= info->property_count) || + property_idx < info->blob_count || + !property_state || !property_state->values) { + DRM_ERROR("invalid argument(s)\n"); + } else { + struct drm_property *drm_prop; + + mutex_lock(&info->property_lock); + + /* update cached value */ + property_state->values[property_idx].value = val; + + /* update the new default value for immutables */ + drm_prop = info->property_array[property_idx]; + if (drm_prop->flags & DRM_MODE_PROP_IMMUTABLE) + info->property_data[property_idx].default_value = val; + + mutex_unlock(&info->property_lock); + + /* update drm object */ + rc = drm_object_property_set_value(info->base, drm_prop, val); + if (rc) + DRM_ERROR("failed set property value, idx %d rc %d\n", + property_idx, rc); + + } + + return rc; +} + diff --git a/techpack/display/msm/msm_prop.h b/techpack/display/msm/msm_prop.h new file mode 100644 index 0000000000000000000000000000000000000000..6069aaaa500397dd27198bb9085cb1055df4c3ef --- /dev/null +++ b/techpack/display/msm/msm_prop.h @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_PROP_H_ +#define _MSM_PROP_H_ + +#include <linux/list.h> +#include "msm_drv.h" + +#define MSM_PROP_STATE_CACHE_SIZE 2 + +/** + * struct msm_property_data - opaque structure for tracking per + * drm-object per property stuff + * @default_value: Default property value for this drm object + * @force_dirty: Always dirty property on incoming sets, rather than checking + * for modified values + */ +struct msm_property_data { + uint64_t default_value; + bool force_dirty; +}; + +/** + * struct msm_property_value - opaque structure for tracking per + * drm-object per property stuff + * @value: Current property value for this drm object + * @blob: Pointer to associated blob data, if available + * @dirty_node: Linked list node to track if property is dirty or not + */ +struct msm_property_value { + uint64_t value; + struct drm_property_blob *blob; + struct list_head dirty_node; +}; + +/** + * struct msm_property_info: Structure for property/state helper functions + * @base: Pointer to base drm object (plane/crtc/etc.) + * @dev: Pointer to drm device object + * @property_array: Pointer to array for storing created property objects + * @property_data: Pointer to array for storing private property data + * @property_count: Total number of properties + * @blob_count: Total number of blob properties, should be <= count + * @install_request: Total number of property 'install' requests + * @install_count: Total number of successful 'install' requests + * @recent_idx: Index of property most recently accessed by set/get + * @is_active: Whether or not drm component properties are 'active' + * @state_cache: Cache of local states, to prevent alloc/free thrashing + * @state_size: Size of local state structures + * @state_cache_size: Number of state structures currently stored in state_cache + * @property_lock: Mutex to protect local variables + */ +struct msm_property_info { + struct drm_mode_object *base; + struct drm_device *dev; + + struct drm_property **property_array; + struct msm_property_data *property_data; + uint32_t property_count; + uint32_t blob_count; + uint32_t install_request; + uint32_t install_count; + + int32_t recent_idx; + + bool is_active; + + void *state_cache[MSM_PROP_STATE_CACHE_SIZE]; + uint32_t state_size; + int32_t state_cache_size; + struct mutex property_lock; +}; + +/** + * struct msm_property_state - Structure for local property state information + * @property_count: Total number of properties + * @values: Pointer to array of msm_property_value objects + * @dirty_list: List of all properties that have been 'atomic_set' but not + * yet cleared with 'msm_property_pop_dirty' + */ +struct msm_property_state { + uint32_t property_count; + struct msm_property_value *values; + struct list_head dirty_list; +}; + +/** + * msm_property_index_to_drm_property - get drm property struct from prop index + * @info: Pointer to property info container struct + * @property_idx: Property index + * Returns: drm_property pointer associated with property index + */ +static inline +struct drm_property *msm_property_index_to_drm_property( + struct msm_property_info *info, uint32_t property_idx) +{ + if (!info || property_idx >= info->property_count) + return NULL; + + return info->property_array[property_idx]; +} + +/** + * msm_property_get_default - query default value of a property + * @info: Pointer to property info container struct + * @property_idx: Property index + * Returns: Default value for specified property + */ +static inline +uint64_t msm_property_get_default(struct msm_property_info *info, + uint32_t property_idx) +{ + uint64_t rc = 0; + + if (!info) + return 0; + + mutex_lock(&info->property_lock); + if (property_idx < info->property_count) + rc = info->property_data[property_idx].default_value; + mutex_unlock(&info->property_lock); + + return rc; +} + +/** + * msm_property_set_is_active - set overall 'active' status for all properties + * @info: Pointer to property info container struct + * @is_active: New 'is active' status + */ +static inline +void msm_property_set_is_active(struct msm_property_info *info, bool is_active) +{ + if (info) { + mutex_lock(&info->property_lock); + info->is_active = is_active; + mutex_unlock(&info->property_lock); + } +} + +/** + * msm_property_get_is_active - query property 'is active' status + * @info: Pointer to property info container struct + * Returns: Current 'is active's status + */ +static inline +bool msm_property_get_is_active(struct msm_property_info *info) +{ + bool rc = false; + + if (info) { + mutex_lock(&info->property_lock); + rc = info->is_active; + mutex_unlock(&info->property_lock); + } + + return rc; +} + +/** + * msm_property_pop_dirty - determine next dirty property and clear + * its dirty flag. Caller needs to acquire property + * lock before calling this function and release + * the lock when finished. + * @info: Pointer to property info container struct + * @property_state: Pointer to property state container struct + * Returns: Valid msm property index on success, + * -EAGAIN if no dirty properties are available + * Property indicies returned from this function are similar + * to those returned by the msm_property_index function. + */ +int msm_property_pop_dirty(struct msm_property_info *info, + struct msm_property_state *property_state); + +/** + * msm_property_init - initialize property info structure + * @info: Pointer to property info container struct + * @base: Pointer to base drm object (plane/crtc/etc.) + * @dev: Pointer to drm device object + * @property_array: Pointer to array for storing created property objects + * @property_data: Pointer to array for storing private property data + * @property_count: Total number of properties + * @blob_count: Total number of blob properties, should be <= count + * @state_size: Size of local state object + */ +void msm_property_init(struct msm_property_info *info, + struct drm_mode_object *base, + struct drm_device *dev, + struct drm_property **property_array, + struct msm_property_data *property_data, + uint32_t property_count, + uint32_t blob_count, + uint32_t state_size); + +/** + * msm_property_destroy - destroy helper info structure + * + * @info: Pointer to property info container struct + */ +void msm_property_destroy(struct msm_property_info *info); + +/** + * msm_property_install_range - install standard drm range property + * @info: Pointer to property info container struct + * @name: Property name + * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE + * @min: Min property value + * @max: Max property value + * @init: Default Property value + * @property_idx: Property index + */ +void msm_property_install_range(struct msm_property_info *info, + const char *name, + int flags, + uint64_t min, + uint64_t max, + uint64_t init, + uint32_t property_idx); + +/** + * msm_property_install_volatile_range - install drm range property + * This function is similar to msm_property_install_range, but assumes + * that the property is meant for holding user pointers or descriptors + * that may reference volatile data without having an updated value. + * @info: Pointer to property info container struct + * @name: Property name + * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE + * @min: Min property value + * @max: Max property value + * @init: Default Property value + * @property_idx: Property index + */ +void msm_property_install_volatile_range(struct msm_property_info *info, + const char *name, + int flags, + uint64_t min, + uint64_t max, + uint64_t init, + uint32_t property_idx); + +/** + * msm_property_install_enum - install standard drm enum/bitmask property + * @info: Pointer to property info container struct + * @name: Property name + * @flags: Other property type flags, e.g. DRM_MODE_PROP_IMMUTABLE + * @is_bitmask: Set to non-zero to create a bitmask property, rather than an + * enumeration one + * @values: Array of allowable enumeration/bitmask values + * @num_values: Size of values array + * @property_idx: Property index + */ +void msm_property_install_enum(struct msm_property_info *info, + const char *name, + int flags, + int is_bitmask, + const struct drm_prop_enum_list *values, + int num_values, + uint32_t property_idx); + +/** + * msm_property_install_blob - install standard drm blob property + * @info: Pointer to property info container struct + * @name: Property name + * @flags: Extra flags for property creation + * @property_idx: Property index + */ +void msm_property_install_blob(struct msm_property_info *info, + const char *name, + int flags, + uint32_t property_idx); + +/** + * msm_property_install_get_status - query overal status of property additions + * @info: Pointer to property info container struct + * Returns: Zero if previous property install calls were all successful + */ +int msm_property_install_get_status(struct msm_property_info *info); + +/** + * msm_property_index - determine property index from drm_property ptr + * @info: Pointer to property info container struct + * @property: Incoming property pointer + * Returns: Valid property index, or -EINVAL on error + */ +int msm_property_index(struct msm_property_info *info, + struct drm_property *property); + +/** + * msm_property_set_dirty - forcibly flag a property as dirty + * @info: Pointer to property info container struct + * @property_state: Pointer to property state container struct + * @property_idx: Property index + * Returns: Zero on success + */ +int msm_property_set_dirty(struct msm_property_info *info, + struct msm_property_state *property_state, + int property_idx); + +/** + * msm_property_is_dirty - check whether a property is dirty + * Note: Intended for use during atomic_check before pop_dirty usage + * @info: Pointer to property info container struct + * @property_state: Pointer to property state container struct + * @property_idx: Property index + * Returns: true if dirty, false otherwise + */ +bool msm_property_is_dirty( + struct msm_property_info *info, + struct msm_property_state *property_state, + uint32_t property_idx); + +/** + * msm_property_atomic_set - helper function for atomic property set callback + * @info: Pointer to property info container struct + * @property_state: Pointer to local state structure + * @property: Incoming property pointer + * @val: Incoming property value + * Returns: Zero on success + */ +int msm_property_atomic_set(struct msm_property_info *info, + struct msm_property_state *property_state, + struct drm_property *property, + uint64_t val); + +/** + * msm_property_atomic_get - helper function for atomic property get callback + * @info: Pointer to property info container struct + * @property_state: Pointer to local state structure + * @property: Incoming property pointer + * @val: Pointer to variable for receiving property value + * Returns: Zero on success + */ +int msm_property_atomic_get(struct msm_property_info *info, + struct msm_property_state *property_state, + struct drm_property *property, + uint64_t *val); + +/** + * msm_property_alloc_state - helper function for allocating local state objects + * @info: Pointer to property info container struct + */ +void *msm_property_alloc_state(struct msm_property_info *info); + +/** + * msm_property_reset_state - helper function for state reset callback + * @info: Pointer to property info container struct + * @state: Pointer to local state structure + * @property_state: Pointer to property state container struct + * @property_values: Pointer to property values cache array + */ +void msm_property_reset_state(struct msm_property_info *info, void *state, + struct msm_property_state *property_state, + struct msm_property_value *property_values); + +/** + * msm_property_duplicate_state - helper function for duplicate state cb + * @info: Pointer to property info container struct + * @old_state: Pointer to original state structure + * @state: Pointer to newly created state structure + * @property_state: Pointer to destination property state container struct + * @property_values: Pointer to property values cache array + */ +void msm_property_duplicate_state(struct msm_property_info *info, + void *old_state, + void *state, + struct msm_property_state *property_state, + struct msm_property_value *property_values); + +/** + * msm_property_destroy_state - helper function for destroy state cb + * @info: Pointer to property info container struct + * @state: Pointer to local state structure + * @property_state: Pointer to property state container struct + */ +void msm_property_destroy_state(struct msm_property_info *info, + void *state, + struct msm_property_state *property_state); + +/** + * msm_property_get_blob - obtain cached data pointer for drm blob property + * @info: Pointer to property info container struct + * @property_state: Pointer to property state container struct + * @byte_len: Optional pointer to variable for accepting blob size + * @property_idx: Property index + * Returns: Pointer to blob data + */ +void *msm_property_get_blob(struct msm_property_info *info, + struct msm_property_state *property_state, + size_t *byte_len, + uint32_t property_idx); + +/** + * msm_property_set_blob - update blob property on a drm object + * This function updates the blob property value of the given drm object. Its + * intended use is to update blob properties that have been created with the + * DRM_MODE_PROP_IMMUTABLE flag set. + * @info: Pointer to property info container struct + * @blob_reference: Reference to a pointer that holds the created data blob + * @blob_data: Pointer to blob data + * @byte_len: Length of blob data, in bytes + * @property_idx: Property index + * Returns: Zero on success + */ +int msm_property_set_blob(struct msm_property_info *info, + struct drm_property_blob **blob_reference, + void *blob_data, + size_t byte_len, + uint32_t property_idx); + +/** + * msm_property_set_property - update property on a drm object + * This function updates the property value of the given drm object. Its + * intended use is to update properties that have been created with the + * DRM_MODE_PROP_IMMUTABLE flag set. + * Note: This function cannot be called on a blob. + * @info: Pointer to property info container struct + * @property_state: Pointer to property state container struct + * @property_idx: Property index + * @val: value of the property to set + * Returns: Zero on success + */ +int msm_property_set_property(struct msm_property_info *info, + struct msm_property_state *property_state, + uint32_t property_idx, + uint64_t val); + +#endif /* _MSM_PROP_H_ */ + diff --git a/techpack/display/msm/msm_smmu.c b/techpack/display/msm/msm_smmu.c new file mode 100644 index 0000000000000000000000000000000000000000..824103055b19086008b49c003d59e2aadaa959e6 --- /dev/null +++ b/techpack/display/msm/msm_smmu.c @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> +#include <linux/msm_dma_iommu_mapping.h> +#include <linux/dma-mapping.h> + +#include <asm/dma-iommu.h> +#include <soc/qcom/secure_buffer.h> + +#include "msm_drv.h" +#include "msm_gem.h" +#include "msm_mmu.h" +#include "sde_dbg.h" + +struct msm_smmu_client { + struct device *dev; + struct iommu_domain *domain; + const struct dma_map_ops *dma_ops; + bool domain_attached; + bool secure; +}; + +struct msm_smmu { + struct msm_mmu base; + struct device *client_dev; + struct msm_smmu_client *client; +}; + +struct msm_smmu_domain { + const char *label; + bool secure; +}; + +#define to_msm_smmu(x) container_of(x, struct msm_smmu, base) +#define msm_smmu_to_client(smmu) (smmu->client) + +static int msm_smmu_attach(struct msm_mmu *mmu, const char * const *names, + int cnt) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + int rc = 0; + + if (!client) { + pr_err("undefined smmu client\n"); + return -EINVAL; + } + + /* domain attach only once */ + if (client->domain_attached) + return 0; + + if (client->dma_ops) { + set_dma_ops(client->dev, client->dma_ops); + client->dma_ops = NULL; + dev_dbg(client->dev, "iommu domain ops restored\n"); + } + + rc = iommu_attach_device(client->domain, client->dev); + if (rc) { + dev_err(client->dev, "iommu attach dev failed (%d)\n", rc); + return rc; + } + + client->domain_attached = true; + + dev_dbg(client->dev, "iommu domain attached\n"); + + return 0; +} + +static void msm_smmu_detach(struct msm_mmu *mmu, const char * const *names, + int cnt) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + + if (!client) { + pr_err("undefined smmu client\n"); + return; + } + + if (!client->domain_attached) + return; + + pm_runtime_get_sync(mmu->dev); + msm_dma_unmap_all_for_dev(client->dev); + iommu_detach_device(client->domain, client->dev); + + client->dma_ops = get_dma_ops(client->dev); + if (client->dma_ops) { + set_dma_ops(client->dev, NULL); + dev_dbg(client->dev, "iommu domain ops removed\n"); + } + + pm_runtime_put_sync(mmu->dev); + + client->domain_attached = false; + dev_dbg(client->dev, "iommu domain detached\n"); +} + +static int msm_smmu_set_attribute(struct msm_mmu *mmu, + enum iommu_attr attr, void *data) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + int ret = 0; + + if (!client || !client->domain) + return -ENODEV; + + ret = iommu_domain_set_attr(client->domain, attr, data); + if (ret) + DRM_ERROR("set domain attribute failed:%d\n", ret); + + return ret; +} + +static int msm_smmu_one_to_one_unmap(struct msm_mmu *mmu, + uint32_t dest_address, uint32_t size) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + int ret = 0; + + if (!client || !client->domain) + return -ENODEV; + + ret = iommu_unmap(client->domain, dest_address, size); + if (ret != size) + pr_err("smmu unmap failed\n"); + + return 0; +} + +static int msm_smmu_one_to_one_map(struct msm_mmu *mmu, uint32_t iova, + uint32_t dest_address, uint32_t size, int prot) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + int ret = 0; + + if (!client || !client->domain) + return -ENODEV; + + ret = iommu_map(client->domain, dest_address, dest_address, + size, prot); + if (ret) + pr_err("smmu map failed\n"); + + return ret; +} + +static int msm_smmu_map(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, unsigned int len, int prot) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + size_t ret = 0; + + if (sgt && sgt->sgl) { + ret = iommu_map_sg(client->domain, iova, sgt->sgl, + sgt->nents, prot); + WARN_ON((int)ret < 0); + DRM_DEBUG("%pad/0x%x/0x%x/\n", &sgt->sgl->dma_address, + sgt->sgl->dma_length, prot); + SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, prot); + } + return (ret == len) ? 0 : -EINVAL; +} + +static int msm_smmu_unmap(struct msm_mmu *mmu, uint64_t iova, + struct sg_table *sgt, unsigned int len) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + + pm_runtime_get_sync(mmu->dev); + iommu_unmap(client->domain, iova, len); + pm_runtime_put_sync(mmu->dev); + + return 0; +} + +static void msm_smmu_destroy(struct msm_mmu *mmu) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct platform_device *pdev = to_platform_device(smmu->client_dev); + + if (smmu->client_dev) + platform_device_unregister(pdev); + kfree(smmu); +} + +struct device *msm_smmu_get_dev(struct msm_mmu *mmu) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + + return smmu->client_dev; +} + +static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, + int dir, u32 flags) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + unsigned long attrs = 0x0; + int ret; + + if (!sgt || !client) { + DRM_ERROR("sg table is invalid\n"); + return -ENOMEM; + } + + /* + * For import buffer type, dma_map_sg_attrs is called during + * dma_buf_map_attachment and is not required to call again + */ + if (!(flags & MSM_BO_EXTBUF)) { + ret = dma_map_sg_attrs(client->dev, sgt->sgl, sgt->nents, dir, + attrs); + if (!ret) { + DRM_ERROR("dma map sg failed\n"); + return -ENOMEM; + } + } + + if (sgt && sgt->sgl) { + DRM_DEBUG("%pad/0x%x/0x%x/0x%lx\n", + &sgt->sgl->dma_address, sgt->sgl->dma_length, + dir, attrs); + SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, + dir, attrs, client->secure); + } + + return 0; +} + + +static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt, + int dir, u32 flags) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + + if (!sgt || !client) { + DRM_ERROR("sg table is invalid\n"); + return; + } + + if (sgt->sgl) { + DRM_DEBUG("%pad/0x%x/0x%x\n", + &sgt->sgl->dma_address, sgt->sgl->dma_length, + dir); + SDE_EVT32(sgt->sgl->dma_address, sgt->sgl->dma_length, + dir, client->secure); + } + + if (!(flags & MSM_BO_EXTBUF)) + dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir); +} + +static bool msm_smmu_is_domain_secure(struct msm_mmu *mmu) +{ + struct msm_smmu *smmu = to_msm_smmu(mmu); + struct msm_smmu_client *client = msm_smmu_to_client(smmu); + + return client->secure; +} + +static const struct msm_mmu_funcs funcs = { + .attach = msm_smmu_attach, + .detach = msm_smmu_detach, + .map = msm_smmu_map, + .unmap = msm_smmu_unmap, + .map_dma_buf = msm_smmu_map_dma_buf, + .unmap_dma_buf = msm_smmu_unmap_dma_buf, + .destroy = msm_smmu_destroy, + .is_domain_secure = msm_smmu_is_domain_secure, + .set_attribute = msm_smmu_set_attribute, + .one_to_one_map = msm_smmu_one_to_one_map, + .one_to_one_unmap = msm_smmu_one_to_one_unmap, + .get_dev = msm_smmu_get_dev, +}; + +static struct msm_smmu_domain msm_smmu_domains[MSM_SMMU_DOMAIN_MAX] = { + [MSM_SMMU_DOMAIN_UNSECURE] = { + .label = "mdp_ns", + .secure = false, + }, + [MSM_SMMU_DOMAIN_SECURE] = { + .label = "mdp_s", + .secure = true, + }, + [MSM_SMMU_DOMAIN_NRT_UNSECURE] = { + .label = "rot_ns", + .secure = false, + }, + [MSM_SMMU_DOMAIN_NRT_SECURE] = { + .label = "rot_s", + .secure = true, + }, +}; + +static const struct of_device_id msm_smmu_dt_match[] = { + { .compatible = "qcom,smmu_sde_unsec", + .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_UNSECURE] }, + { .compatible = "qcom,smmu_sde_sec", + .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_SECURE] }, + { .compatible = "qcom,smmu_sde_nrt_unsec", + .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_NRT_UNSECURE] }, + { .compatible = "qcom,smmu_sde_nrt_sec", + .data = &msm_smmu_domains[MSM_SMMU_DOMAIN_NRT_SECURE] }, + {} +}; +MODULE_DEVICE_TABLE(of, msm_smmu_dt_match); + +static struct device *msm_smmu_device_create(struct device *dev, + enum msm_mmu_domain_type domain, + struct msm_smmu *smmu) +{ + struct device_node *child; + struct platform_device *pdev; + int i; + const char *compat = NULL; + + for (i = 0; i < ARRAY_SIZE(msm_smmu_dt_match); i++) { + if (msm_smmu_dt_match[i].data == &msm_smmu_domains[domain]) { + compat = msm_smmu_dt_match[i].compatible; + break; + } + } + + if (!compat) { + DRM_DEBUG("unable to find matching domain for %d\n", domain); + return ERR_PTR(-ENOENT); + } + DRM_DEBUG("found domain %d compat: %s\n", domain, compat); + + child = of_find_compatible_node(dev->of_node, NULL, compat); + if (!child) { + DRM_DEBUG("unable to find compatible node for %s\n", compat); + return ERR_PTR(-ENODEV); + } + + pdev = of_platform_device_create(child, NULL, dev); + if (!pdev) { + DRM_ERROR("unable to create smmu platform dev for domain %d\n", + domain); + return ERR_PTR(-ENODEV); + } + + smmu->client = platform_get_drvdata(pdev); + + return &pdev->dev; +} + +struct msm_mmu *msm_smmu_new(struct device *dev, + enum msm_mmu_domain_type domain) +{ + struct msm_smmu *smmu; + struct device *client_dev; + + smmu = kzalloc(sizeof(*smmu), GFP_KERNEL); + if (!smmu) + return ERR_PTR(-ENOMEM); + + client_dev = msm_smmu_device_create(dev, domain, smmu); + if (IS_ERR(client_dev)) { + kfree(smmu); + return (void *)client_dev ? : ERR_PTR(-ENODEV); + } + + smmu->client_dev = client_dev; + msm_mmu_init(&smmu->base, dev, &funcs); + + return &smmu->base; +} + +static int msm_smmu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, + int flags, void *token) +{ + struct msm_smmu_client *client; + int rc = -EINVAL; + + if (!token) { + DRM_ERROR("Error: token is NULL\n"); + return -EINVAL; + } + + client = (struct msm_smmu_client *)token; + + /* see iommu.h for fault flags definition */ + SDE_EVT32(iova, flags); + DRM_ERROR("trigger dump, iova=0x%08lx, flags=0x%x\n", iova, flags); + DRM_ERROR("SMMU device:%s", client->dev ? client->dev->kobj.name : ""); + + /* + * return -ENOSYS to allow smmu driver to dump out useful + * debug info. + */ + return rc; +} + +/** + * msm_smmu_probe() + * @pdev: platform device + * + * Each smmu context acts as a separate device and the context banks are + * configured with a VA range. + * Registers the clks as each context bank has its own clks, for which voting + * has to be done everytime before using that context bank. + */ +static int msm_smmu_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct msm_smmu_client *client; + const struct msm_smmu_domain *domain; + + match = of_match_device(msm_smmu_dt_match, &pdev->dev); + if (!match || !match->data) { + dev_err(&pdev->dev, "probe failed as match data is invalid\n"); + return -EINVAL; + } + + domain = match->data; + if (!domain) { + dev_err(&pdev->dev, "no matching device found\n"); + return -EINVAL; + } + + DRM_INFO("probing device %s\n", match->compatible); + + client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->dev = &pdev->dev; + client->domain = iommu_get_domain_for_dev(client->dev); + if (!client->domain) { + dev_err(&pdev->dev, "iommu get domain for dev failed\n"); + return -EINVAL; + } + client->secure = domain->secure; + client->domain_attached = true; + + if (!client->dev->dma_parms) + client->dev->dma_parms = devm_kzalloc(client->dev, + sizeof(*client->dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(client->dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(client->dev, (unsigned long)DMA_BIT_MASK(64)); + + iommu_set_fault_handler(client->domain, + msm_smmu_fault_handler, (void *)client); + + DRM_INFO("Created domain %s, secure=%d\n", + domain->label, domain->secure); + + platform_set_drvdata(pdev, client); + + return 0; +} + +static int msm_smmu_remove(struct platform_device *pdev) +{ + struct msm_smmu_client *client; + + client = platform_get_drvdata(pdev); + client->domain_attached = false; + + return 0; +} + +static struct platform_driver msm_smmu_driver = { + .probe = msm_smmu_probe, + .remove = msm_smmu_remove, + .driver = { + .name = "msmdrm_smmu", + .of_match_table = msm_smmu_dt_match, + .suppress_bind_attrs = true, + }, +}; + +int __init msm_smmu_driver_init(void) +{ + int ret; + + ret = platform_driver_register(&msm_smmu_driver); + if (ret) + pr_err("mdss_smmu_register_driver() failed!\n"); + + return ret; +} + +void __exit msm_smmu_driver_cleanup(void) +{ + platform_driver_unregister(&msm_smmu_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MSM SMMU driver"); diff --git a/techpack/display/msm/sde/sde_ad4.h b/techpack/display/msm/sde/sde_ad4.h new file mode 100644 index 0000000000000000000000000000000000000000..7d99d4faeaba5c0d01682eb23e29f9507bf0ee12 --- /dev/null +++ b/techpack/display/msm/sde/sde_ad4.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _SDE_AD4_H_ +#define _SDE_AD4_H_ + +#include <drm/drm_mode.h> +#include <drm/drm_property.h> +#include "sde_hw_dspp.h" + +/** + * enum ad4_modes - ad4 modes supported by driver + */ +enum ad4_modes { + AD4_OFF, + AD4_AUTO_STRENGTH, + AD4_CALIBRATION, + AD4_MANUAL, +}; + +/** + * struct drm_prop_enum_list - drm structure for creating enum property and + * enumerating values + */ +static const struct drm_prop_enum_list ad4_modes[] = { + {AD4_OFF, "off"}, + {AD4_AUTO_STRENGTH, "auto_strength_mode"}, + {AD4_CALIBRATION, "calibration_mode"}, + {AD4_MANUAL, "manual_mode"}, +}; + +/** + * enum ad_property - properties that can be set for ad + */ +enum ad_property { + AD_MODE, + AD_INIT, + AD_CFG, + AD_INPUT, + AD_SUSPEND, + AD_ASSERTIVE, + AD_BACKLIGHT, + AD_STRENGTH, + AD_ROI, + AD_IPC_SUSPEND, + AD_IPC_RESUME, + AD_IPC_RESET, + AD_PROPMAX, +}; + +/** + * enum ad_intr_resp_property - ad4 interrupt response enum + */ +enum ad_intr_resp_property { + AD4_IN_OUT_BACKLIGHT, + AD4_RESPMAX, +}; + +/** + * struct sde_ad_hw_cfg - structure for setting the ad properties + * @prop: enum of ad property + * @hw_cfg: payload for the prop being set. + */ +struct sde_ad_hw_cfg { + enum ad_property prop; + struct sde_hw_cp_cfg *hw_cfg; +}; + +/** + * sde_validate_dspp_ad4() - api to validate if ad property is allowed for + * the display with allocated dspp/mixers. + * @dspp: pointer to dspp info structure. + * @prop: pointer to u32 pointing to ad property + */ +int sde_validate_dspp_ad4(struct sde_hw_dspp *dspp, u32 *prop); + +/** + * sde_setup_dspp_ad4 - api to apply the ad property, sde_validate_dspp_ad4 + * should be called before call this function + * @dspp: pointer to dspp info structure. + * @cfg: pointer to struct sde_ad_hw_cfg + */ +void sde_setup_dspp_ad4(struct sde_hw_dspp *dspp, void *cfg); + +/** + * sde_read_intr_resp_ad4 - api to get ad4 interrupt status for event + * @dspp: pointer to dspp object + * @event: event for which response is needed + * @resp_in: read ad4 input value of event requested + * @resp_out: read ad4 output value of event requested + */ +void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event, + u32 *resp_in, u32 *resp_out); + +#endif /* _SDE_AD4_H_ */ diff --git a/techpack/display/msm/sde/sde_color_processing.c b/techpack/display/msm/sde/sde_color_processing.c new file mode 100644 index 0000000000000000000000000000000000000000..6777d0e4c31b933767cc1c2b1b56ecdf9c732d25 --- /dev/null +++ b/techpack/display/msm/sde/sde_color_processing.c @@ -0,0 +1,3375 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/dma-buf.h> +#include <drm/msm_drm_pp.h> +#include "sde_color_processing.h" +#include "sde_kms.h" +#include "sde_crtc.h" +#include "sde_hw_dspp.h" +#include "sde_hw_lm.h" +#include "sde_ad4.h" +#include "sde_hw_interrupts.h" +#include "sde_core_irq.h" +#include "dsi_panel.h" +#include "sde_hw_color_proc_common_v4.h" + +struct sde_cp_node { + u32 property_id; + u32 prop_flags; + u32 feature; + void *blob_ptr; + uint64_t prop_val; + const struct sde_pp_blk *pp_blk; + struct list_head feature_list; + struct list_head active_list; + struct list_head dirty_list; + bool is_dspp_feature; + u32 prop_blob_sz; + struct sde_irq_callback *irq; +}; + +struct sde_cp_prop_attach { + struct drm_crtc *crtc; + struct drm_property *prop; + struct sde_cp_node *prop_node; + u32 feature; + uint64_t val; +}; + +#define ALIGNED_OFFSET (U32_MAX & ~(LTM_GUARD_BYTES)) + +static void dspp_pcc_install_property(struct drm_crtc *crtc); + +static void dspp_hsic_install_property(struct drm_crtc *crtc); + +static void dspp_memcolor_install_property(struct drm_crtc *crtc); + +static void dspp_sixzone_install_property(struct drm_crtc *crtc); + +static void dspp_ad_install_property(struct drm_crtc *crtc); + +static void dspp_ltm_install_property(struct drm_crtc *crtc); + +static void dspp_vlut_install_property(struct drm_crtc *crtc); + +static void dspp_gamut_install_property(struct drm_crtc *crtc); + +static void dspp_gc_install_property(struct drm_crtc *crtc); + +static void dspp_igc_install_property(struct drm_crtc *crtc); + +static void dspp_hist_install_property(struct drm_crtc *crtc); + +static void dspp_dither_install_property(struct drm_crtc *crtc); + +typedef void (*dspp_prop_install_func_t)(struct drm_crtc *crtc); + +static dspp_prop_install_func_t dspp_prop_install_func[SDE_DSPP_MAX]; + +static void sde_cp_update_list(struct sde_cp_node *prop_node, + struct sde_crtc *crtc, bool dirty_list); + +static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node, + struct sde_crtc *crtc); + +static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg); + +static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc, + enum ad_property ad_prop); + +static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg); + +static void _sde_cp_crtc_set_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg); +static void _sde_cp_crtc_free_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg); +static void _sde_cp_crtc_queue_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg); +static int _sde_cp_crtc_get_ltm_buffer(struct sde_crtc *sde_crtc, u64 *addr); +static void _sde_cp_crtc_enable_ltm_hist(struct sde_crtc *sde_crtc, + struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg); +static void _sde_cp_crtc_disable_ltm_hist(struct sde_crtc *sde_crtc, + struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg); +static void sde_cp_notify_ltm_hist(struct drm_crtc *crtc_drm, void *arg); +static void sde_cp_notify_ltm_wb_pb(struct drm_crtc *crtc_drm, void *arg); +static void _sde_cp_crtc_update_ltm_roi(struct sde_crtc *sde_crtc, + struct sde_hw_cp_cfg *hw_cfg); + +#define setup_dspp_prop_install_funcs(func) \ +do { \ + func[SDE_DSPP_PCC] = dspp_pcc_install_property; \ + func[SDE_DSPP_HSIC] = dspp_hsic_install_property; \ + func[SDE_DSPP_MEMCOLOR] = dspp_memcolor_install_property; \ + func[SDE_DSPP_SIXZONE] = dspp_sixzone_install_property; \ + func[SDE_DSPP_AD] = dspp_ad_install_property; \ + func[SDE_DSPP_LTM] = dspp_ltm_install_property; \ + func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \ + func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \ + func[SDE_DSPP_GC] = dspp_gc_install_property; \ + func[SDE_DSPP_IGC] = dspp_igc_install_property; \ + func[SDE_DSPP_HIST] = dspp_hist_install_property; \ + func[SDE_DSPP_DITHER] = dspp_dither_install_property; \ +} while (0) + +typedef void (*lm_prop_install_func_t)(struct drm_crtc *crtc); + +static lm_prop_install_func_t lm_prop_install_func[SDE_MIXER_MAX]; + +static void lm_gc_install_property(struct drm_crtc *crtc); + +#define setup_lm_prop_install_funcs(func) \ + (func[SDE_MIXER_GC] = lm_gc_install_property) + +enum { + /* Append new DSPP features before SDE_CP_CRTC_DSPP_MAX */ + /* DSPP Features start */ + SDE_CP_CRTC_DSPP_IGC, + SDE_CP_CRTC_DSPP_PCC, + SDE_CP_CRTC_DSPP_GC, + SDE_CP_CRTC_DSPP_HSIC, + SDE_CP_CRTC_DSPP_MEMCOL_SKIN, + SDE_CP_CRTC_DSPP_MEMCOL_SKY, + SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE, + SDE_CP_CRTC_DSPP_MEMCOL_PROT, + SDE_CP_CRTC_DSPP_SIXZONE, + SDE_CP_CRTC_DSPP_GAMUT, + SDE_CP_CRTC_DSPP_DITHER, + SDE_CP_CRTC_DSPP_HIST_CTRL, + SDE_CP_CRTC_DSPP_HIST_IRQ, + SDE_CP_CRTC_DSPP_AD, + SDE_CP_CRTC_DSPP_VLUT, + SDE_CP_CRTC_DSPP_AD_MODE, + SDE_CP_CRTC_DSPP_AD_INIT, + SDE_CP_CRTC_DSPP_AD_CFG, + SDE_CP_CRTC_DSPP_AD_INPUT, + SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, + SDE_CP_CRTC_DSPP_AD_BACKLIGHT, + SDE_CP_CRTC_DSPP_AD_STRENGTH, + SDE_CP_CRTC_DSPP_AD_ROI, + SDE_CP_CRTC_DSPP_LTM, + SDE_CP_CRTC_DSPP_LTM_INIT, + SDE_CP_CRTC_DSPP_LTM_ROI, + SDE_CP_CRTC_DSPP_LTM_HIST_CTL, + SDE_CP_CRTC_DSPP_LTM_HIST_THRESH, + SDE_CP_CRTC_DSPP_LTM_SET_BUF, + SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF, + SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2, + SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3, + SDE_CP_CRTC_DSPP_LTM_VLUT, + SDE_CP_CRTC_DSPP_MAX, + /* DSPP features end */ + + /* Append new LM features before SDE_CP_CRTC_MAX_FEATURES */ + /* LM feature start*/ + SDE_CP_CRTC_LM_GC, + /* LM feature end*/ + + SDE_CP_CRTC_MAX_FEATURES, +}; + +static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc); + +typedef int (*set_feature_wrapper)(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc); + +static int set_dspp_vlut_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_vlut) + ret = -EINVAL; + else + hw_dspp->ops.setup_vlut(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_pcc_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pcc) + ret = -EINVAL; + else + hw_dspp->ops.setup_pcc(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_igc_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_igc) + ret = -EINVAL; + else + hw_dspp->ops.setup_igc(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_gc_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_gc) + ret = -EINVAL; + else + hw_dspp->ops.setup_gc(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_hsic_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pa_hsic) + ret = -EINVAL; + else + hw_dspp->ops.setup_pa_hsic(hw_dspp, hw_cfg); + + return ret; +} + + +static int set_dspp_memcol_skin_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_skin) + ret = -EINVAL; + else + hw_dspp->ops.setup_pa_memcol_skin(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_memcol_sky_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_sky) + ret = -EINVAL; + else + hw_dspp->ops.setup_pa_memcol_sky(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_memcol_foliage_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_foliage) + ret = -EINVAL; + else + hw_dspp->ops.setup_pa_memcol_foliage(hw_dspp, hw_cfg); + return ret; +} + + +static int set_dspp_memcol_prot_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pa_memcol_prot) + ret = -EINVAL; + else + hw_dspp->ops.setup_pa_memcol_prot(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_sixzone_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_sixzone) + ret = -EINVAL; + else + hw_dspp->ops.setup_sixzone(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_gamut_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_gamut) + ret = -EINVAL; + else + hw_dspp->ops.setup_gamut(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_dither_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_pa_dither) + ret = -EINVAL; + else + hw_dspp->ops.setup_pa_dither(hw_dspp, hw_cfg); + return ret; +} + +static int set_dspp_hist_ctrl_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + bool feature_enabled; + + if (!hw_dspp || !hw_dspp->ops.setup_histogram) { + ret = -EINVAL; + } else { + feature_enabled = hw_cfg->payload && + *((u64 *)hw_cfg->payload) != 0; + hw_dspp->ops.setup_histogram(hw_dspp, &feature_enabled); + } + return ret; +} + +static int set_dspp_hist_irq_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + struct sde_hw_mixer *hw_lm = hw_cfg->mixer_info; + + if (!hw_dspp) + ret = -EINVAL; + else if (!hw_lm->cfg.right_mixer) + _sde_cp_crtc_enable_hist_irq(hw_crtc); + return ret; +} + + +static int set_dspp_ad_mode_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_MODE; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_init_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_INIT; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_cfg_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_CFG; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_input_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_INPUT; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_assertive_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_ASSERTIVE; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_backlight_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_BACKLIGHT; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_strength_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_STRENGTH; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_dspp_ad_roi_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + } else { + struct sde_ad_hw_cfg ad_cfg; + + ad_cfg.prop = AD_ROI; + ad_cfg.hw_cfg = hw_cfg; + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } + return ret; +} + +static int set_lm_gc_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + struct sde_hw_mixer *hw_lm = (struct sde_hw_mixer *)hw_cfg->mixer_info; + + if (!hw_lm->ops.setup_gc) + ret = -EINVAL; + else + hw_lm->ops.setup_gc(hw_lm, hw_cfg); + return ret; +} + +static int set_ltm_init_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ltm_init) + ret = -EINVAL; + else + hw_dspp->ops.setup_ltm_init(hw_dspp, hw_cfg); + + return ret; +} + +static int set_ltm_roi_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ltm_roi) { + ret = -EINVAL; + } else { + hw_dspp->ops.setup_ltm_roi(hw_dspp, hw_cfg); + _sde_cp_crtc_update_ltm_roi(hw_crtc, hw_cfg); + } + + return ret; +} + +static int set_ltm_vlut_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *hw_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ltm_vlut) + ret = -EINVAL; + else + hw_dspp->ops.setup_ltm_vlut(hw_dspp, hw_cfg); + + return ret; +} + +static int set_ltm_thresh_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *sde_crtc) +{ + int ret = 0; + + if (!hw_dspp || !hw_dspp->ops.setup_ltm_thresh) + ret = -EINVAL; + else + hw_dspp->ops.setup_ltm_thresh(hw_dspp, hw_cfg); + + return ret; +} + +static int set_ltm_buffers_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *sde_crtc) +{ + int ret = 0; + struct sde_hw_mixer *hw_lm; + struct drm_msm_ltm_buffers_ctrl *payload; + + if (!sde_crtc || !hw_dspp) { + ret = -EINVAL; + } else { + hw_lm = hw_cfg->mixer_info; + /* in merge mode, both LTM cores use the same buffer */ + if (!hw_lm->cfg.right_mixer) { + payload = hw_cfg->payload; + mutex_lock(&sde_crtc->ltm_buffer_lock); + if (payload) + _sde_cp_crtc_set_ltm_buffer(sde_crtc, hw_cfg); + else + _sde_cp_crtc_free_ltm_buffer(sde_crtc, hw_cfg); + mutex_unlock(&sde_crtc->ltm_buffer_lock); + } + } + + return ret; +} + +static int set_ltm_queue_buf_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *sde_crtc) +{ + int ret = 0; + struct sde_hw_mixer *hw_lm; + + if (!sde_crtc || !hw_dspp) { + ret = -EINVAL; + } else { + hw_lm = hw_cfg->mixer_info; + /* in merge mode, both LTM cores use the same buffer */ + if (!hw_lm->cfg.right_mixer) { + mutex_lock(&sde_crtc->ltm_buffer_lock); + _sde_cp_crtc_queue_ltm_buffer(sde_crtc, hw_cfg); + mutex_unlock(&sde_crtc->ltm_buffer_lock); + } + } + + return ret; +} + +static int set_ltm_hist_crtl_feature(struct sde_hw_dspp *hw_dspp, + struct sde_hw_cp_cfg *hw_cfg, + struct sde_crtc *sde_crtc) +{ + int ret = 0; + bool feature_enabled = false; + + if (!sde_crtc || !hw_dspp || !hw_dspp->ops.setup_ltm_hist_ctrl) { + ret = -EINVAL; + } else { + mutex_lock(&sde_crtc->ltm_buffer_lock); + feature_enabled = hw_cfg->payload && + (*((u64 *)hw_cfg->payload) != 0); + if (feature_enabled) + _sde_cp_crtc_enable_ltm_hist(sde_crtc, hw_dspp, hw_cfg); + else + _sde_cp_crtc_disable_ltm_hist(sde_crtc, hw_dspp, + hw_cfg); + mutex_unlock(&sde_crtc->ltm_buffer_lock); + } + + return ret; +} + +set_feature_wrapper crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES]; + +#define setup_crtc_feature_wrappers(wrappers) \ +do { \ + memset(wrappers, 0, sizeof(wrappers)); \ + wrappers[SDE_CP_CRTC_DSPP_VLUT] = set_dspp_vlut_feature; \ + wrappers[SDE_CP_CRTC_DSPP_PCC] = set_dspp_pcc_feature; \ + wrappers[SDE_CP_CRTC_DSPP_IGC] = set_dspp_igc_feature; \ + wrappers[SDE_CP_CRTC_DSPP_GC] = set_dspp_gc_feature; \ + wrappers[SDE_CP_CRTC_DSPP_HSIC] =\ + set_dspp_hsic_feature; \ + wrappers[SDE_CP_CRTC_DSPP_MEMCOL_SKIN] = set_dspp_memcol_skin_feature; \ + wrappers[SDE_CP_CRTC_DSPP_MEMCOL_SKY] =\ + set_dspp_memcol_sky_feature; \ + wrappers[SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE] =\ + set_dspp_memcol_foliage_feature; \ + wrappers[SDE_CP_CRTC_DSPP_MEMCOL_PROT] = set_dspp_memcol_prot_feature; \ + wrappers[SDE_CP_CRTC_DSPP_SIXZONE] = set_dspp_sixzone_feature; \ + wrappers[SDE_CP_CRTC_DSPP_GAMUT] = set_dspp_gamut_feature; \ + wrappers[SDE_CP_CRTC_DSPP_DITHER] = set_dspp_dither_feature; \ + wrappers[SDE_CP_CRTC_DSPP_HIST_CTRL] = set_dspp_hist_ctrl_feature; \ + wrappers[SDE_CP_CRTC_DSPP_HIST_IRQ] = set_dspp_hist_irq_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_MODE] = set_dspp_ad_mode_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_INIT] = set_dspp_ad_init_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_CFG] = set_dspp_ad_cfg_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_INPUT] = set_dspp_ad_input_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS] =\ + set_dspp_ad_assertive_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_BACKLIGHT] =\ + set_dspp_ad_backlight_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_STRENGTH] = set_dspp_ad_strength_feature; \ + wrappers[SDE_CP_CRTC_DSPP_AD_ROI] = set_dspp_ad_roi_feature; \ + wrappers[SDE_CP_CRTC_LM_GC] = set_lm_gc_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_INIT] = set_ltm_init_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_ROI] = set_ltm_roi_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_VLUT] = set_ltm_vlut_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_THRESH] = set_ltm_thresh_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_SET_BUF] = set_ltm_buffers_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF] = set_ltm_queue_buf_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2] = set_ltm_queue_buf_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = set_ltm_queue_buf_feature; \ + wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \ +} while (0) + +#define INIT_PROP_ATTACH(p, crtc, prop, node, feature, val) \ + do { \ + (p)->crtc = crtc; \ + (p)->prop = prop; \ + (p)->prop_node = node; \ + (p)->feature = feature; \ + (p)->val = val; \ + } while (0) + +static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node, + struct sde_hw_cp_cfg *hw_cfg, + bool *feature_enabled) +{ + struct drm_property_blob *blob = NULL; + memset(hw_cfg, 0, sizeof(*hw_cfg)); + *feature_enabled = false; + + blob = prop_node->blob_ptr; + if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) { + if (blob) { + hw_cfg->len = blob->length; + hw_cfg->payload = blob->data; + *feature_enabled = true; + } + } else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) { + /* Check if local blob is Set */ + if (!blob) { + if (prop_node->prop_val) { + hw_cfg->len = sizeof(prop_node->prop_val); + hw_cfg->payload = &prop_node->prop_val; + } + } else { + hw_cfg->len = (prop_node->prop_val) ? blob->length : + 0; + hw_cfg->payload = (prop_node->prop_val) ? blob->data + : NULL; + } + if (prop_node->prop_val) + *feature_enabled = true; + } else if (prop_node->prop_flags & DRM_MODE_PROP_ENUM) { + *feature_enabled = (prop_node->prop_val != 0); + hw_cfg->len = sizeof(prop_node->prop_val); + hw_cfg->payload = &prop_node->prop_val; + } else { + DRM_ERROR("property type is not supported\n"); + } +} + +static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node) +{ + struct drm_property_blob *blob = prop_node->blob_ptr; + + if (!blob) + return 0; + drm_property_blob_put(blob); + prop_node->blob_ptr = NULL; + return 0; +} + +static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len) +{ + int ret = -EINVAL; + bool found = false; + struct sde_cp_node *prop_node = NULL; + struct drm_property_blob *blob_ptr; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) { + if (prop_node->feature == feature) { + found = true; + break; + } + } + + if (!found || !(prop_node->prop_flags & DRM_MODE_PROP_RANGE)) { + DRM_ERROR("local blob create failed prop found %d flags %d\n", + found, prop_node->prop_flags); + return ret; + } + + blob_ptr = drm_property_create_blob(crtc->dev, len, NULL); + ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0; + if (!ret) + prop_node->blob_ptr = blob_ptr; + + return ret; +} + +static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node) +{ + if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) && + prop_node->blob_ptr) + drm_property_blob_put(prop_node->blob_ptr); +} + +static int sde_cp_handle_range_property(struct sde_cp_node *prop_node, + uint64_t val) +{ + int ret = 0; + struct drm_property_blob *blob_ptr = prop_node->blob_ptr; + + if (!blob_ptr) { + prop_node->prop_val = val; + return 0; + } + + if (!val) { + prop_node->prop_val = 0; + return 0; + } + + ret = copy_from_user(blob_ptr->data, u64_to_user_ptr(val), + blob_ptr->length); + if (ret) { + DRM_ERROR("failed to get the property info ret %d", ret); + ret = -EFAULT; + } else { + prop_node->prop_val = val; + } + + return ret; +} + +static int sde_cp_disable_crtc_property(struct drm_crtc *crtc, + struct drm_property *property, + struct sde_cp_node *prop_node) +{ + int ret = -EINVAL; + + if (property->flags & DRM_MODE_PROP_BLOB) { + ret = sde_cp_disable_crtc_blob_property(prop_node); + } else if (property->flags & DRM_MODE_PROP_RANGE) { + ret = sde_cp_handle_range_property(prop_node, 0); + } else if (property->flags & DRM_MODE_PROP_ENUM) { + ret = 0; + prop_node->prop_val = 0; + } + return ret; +} + +static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc, + struct sde_cp_node *prop_node, + uint64_t val) +{ + struct drm_property_blob *blob = NULL; + + /** + * For non-blob based properties add support to create a blob + * using the val and store the blob_ptr in prop_node. + */ + blob = drm_property_lookup_blob(crtc->dev, val); + if (!blob) { + DRM_ERROR("invalid blob id %lld\n", val); + return -EINVAL; + } + if (blob->length != prop_node->prop_blob_sz) { + DRM_ERROR("invalid blob len %zd exp %d feature %d\n", + blob->length, prop_node->prop_blob_sz, prop_node->feature); + drm_property_blob_put(blob); + return -EINVAL; + } + /* Release refernce to existing payload of the property */ + if (prop_node->blob_ptr) + drm_property_blob_put(prop_node->blob_ptr); + + prop_node->blob_ptr = blob; + return 0; +} + +static int sde_cp_enable_crtc_property(struct drm_crtc *crtc, + struct drm_property *property, + struct sde_cp_node *prop_node, + uint64_t val) +{ + int ret = -EINVAL; + + if (property->flags & DRM_MODE_PROP_BLOB) { + ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val); + } else if (property->flags & DRM_MODE_PROP_RANGE) { + ret = sde_cp_handle_range_property(prop_node, val); + } else if (property->flags & DRM_MODE_PROP_ENUM) { + ret = 0; + prop_node->prop_val = val; + } + return ret; +} + +static struct sde_kms *get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv = crtc->dev->dev_private; + + return to_sde_kms(priv->kms); +} + +static void sde_cp_crtc_prop_attach(struct sde_cp_prop_attach *prop_attach) +{ + + struct sde_crtc *sde_crtc = to_sde_crtc(prop_attach->crtc); + + drm_object_attach_property(&prop_attach->crtc->base, + prop_attach->prop, prop_attach->val); + + INIT_LIST_HEAD(&prop_attach->prop_node->active_list); + INIT_LIST_HEAD(&prop_attach->prop_node->dirty_list); + + prop_attach->prop_node->property_id = prop_attach->prop->base.id; + prop_attach->prop_node->prop_flags = prop_attach->prop->flags; + prop_attach->prop_node->feature = prop_attach->feature; + + if (prop_attach->feature < SDE_CP_CRTC_DSPP_MAX) + prop_attach->prop_node->is_dspp_feature = true; + else + prop_attach->prop_node->is_dspp_feature = false; + + list_add(&prop_attach->prop_node->feature_list, + &sde_crtc->feature_list); +} + +void sde_cp_crtc_init(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = NULL; + + if (!crtc) { + DRM_ERROR("invalid crtc %pK\n", crtc); + return; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + /* create blob to store histogram data */ + sde_crtc->hist_blob = drm_property_create_blob(crtc->dev, + sizeof(struct drm_msm_hist), NULL); + if (IS_ERR(sde_crtc->hist_blob)) + sde_crtc->hist_blob = NULL; + + mutex_init(&sde_crtc->crtc_cp_lock); + INIT_LIST_HEAD(&sde_crtc->active_list); + INIT_LIST_HEAD(&sde_crtc->dirty_list); + INIT_LIST_HEAD(&sde_crtc->feature_list); + INIT_LIST_HEAD(&sde_crtc->ad_dirty); + INIT_LIST_HEAD(&sde_crtc->ad_active); + mutex_init(&sde_crtc->ltm_buffer_lock); + spin_lock_init(&sde_crtc->ltm_lock); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); +} + +static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc, + char *name, + u32 feature) +{ + struct drm_property *prop; + struct sde_cp_node *prop_node = NULL; + struct msm_drm_private *priv; + struct sde_cp_prop_attach prop_attach; + uint64_t val = 0; + + if (feature >= SDE_CP_CRTC_MAX_FEATURES) { + DRM_ERROR("invalid feature %d max %d\n", feature, + SDE_CP_CRTC_MAX_FEATURES); + return; + } + + prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL); + if (!prop_node) + return; + + priv = crtc->dev->dev_private; + prop = priv->cp_property[feature]; + + if (!prop) { + prop = drm_property_create_range(crtc->dev, + DRM_MODE_PROP_IMMUTABLE, name, 0, 1); + if (!prop) { + DRM_ERROR("property create failed: %s\n", name); + kfree(prop_node); + return; + } + priv->cp_property[feature] = prop; + } + + INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, + feature, val); + sde_cp_crtc_prop_attach(&prop_attach); +} + +static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc, + char *name, + u32 feature, + uint64_t min, uint64_t max, + uint64_t val) +{ + struct drm_property *prop; + struct sde_cp_node *prop_node = NULL; + struct msm_drm_private *priv; + struct sde_cp_prop_attach prop_attach; + + if (feature >= SDE_CP_CRTC_MAX_FEATURES) { + DRM_ERROR("invalid feature %d max %d\n", feature, + SDE_CP_CRTC_MAX_FEATURES); + return; + } + + prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL); + if (!prop_node) + return; + + priv = crtc->dev->dev_private; + prop = priv->cp_property[feature]; + + if (!prop) { + prop = drm_property_create_range(crtc->dev, 0, name, min, max); + if (!prop) { + DRM_ERROR("property create failed: %s\n", name); + kfree(prop_node); + return; + } + priv->cp_property[feature] = prop; + } + + INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, + feature, val); + + sde_cp_crtc_prop_attach(&prop_attach); +} + +static void sde_cp_crtc_install_blob_property(struct drm_crtc *crtc, char *name, + u32 feature, u32 blob_sz) +{ + struct drm_property *prop; + struct sde_cp_node *prop_node = NULL; + struct msm_drm_private *priv; + uint64_t val = 0; + struct sde_cp_prop_attach prop_attach; + + if (feature >= SDE_CP_CRTC_MAX_FEATURES) { + DRM_ERROR("invalid feature %d max %d\n", feature, + SDE_CP_CRTC_MAX_FEATURES); + return; + } + + prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL); + if (!prop_node) + return; + + priv = crtc->dev->dev_private; + prop = priv->cp_property[feature]; + + if (!prop) { + prop = drm_property_create(crtc->dev, + DRM_MODE_PROP_BLOB, name, 0); + if (!prop) { + DRM_ERROR("property create failed: %s\n", name); + kfree(prop_node); + return; + } + priv->cp_property[feature] = prop; + } + + INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, + feature, val); + prop_node->prop_blob_sz = blob_sz; + + sde_cp_crtc_prop_attach(&prop_attach); +} + +static void sde_cp_crtc_install_enum_property(struct drm_crtc *crtc, + u32 feature, const struct drm_prop_enum_list *list, u32 enum_sz, + char *name) +{ + struct drm_property *prop; + struct sde_cp_node *prop_node = NULL; + struct msm_drm_private *priv; + uint64_t val = 0; + struct sde_cp_prop_attach prop_attach; + + if (feature >= SDE_CP_CRTC_MAX_FEATURES) { + DRM_ERROR("invalid feature %d max %d\n", feature, + SDE_CP_CRTC_MAX_FEATURES); + return; + } + + prop_node = kzalloc(sizeof(*prop_node), GFP_KERNEL); + if (!prop_node) + return; + + priv = crtc->dev->dev_private; + prop = priv->cp_property[feature]; + + if (!prop) { + prop = drm_property_create_enum(crtc->dev, 0, name, + list, enum_sz); + if (!prop) { + DRM_ERROR("property create failed: %s\n", name); + kfree(prop_node); + return; + } + priv->cp_property[feature] = prop; + } + + INIT_PROP_ATTACH(&prop_attach, crtc, prop, prop_node, + feature, val); + + sde_cp_crtc_prop_attach(&prop_attach); +} + +static struct sde_crtc_irq_info *_sde_cp_get_intr_node(u32 event, + struct sde_crtc *sde_crtc) +{ + bool found = false; + struct sde_crtc_irq_info *node = NULL; + + list_for_each_entry(node, &sde_crtc->user_event_list, list) { + if (node->event == event) { + found = true; + break; + } + } + + if (!found) + node = NULL; + + return node; +} + +static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc) +{ + struct drm_crtc *crtc_drm = &sde_crtc->base; + struct sde_kms *kms = NULL; + struct sde_hw_mixer *hw_lm; + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_crtc_irq_info *node = NULL; + int i, irq_idx, ret = 0; + unsigned long flags; + + if (!crtc_drm) { + DRM_ERROR("invalid crtc %pK\n", crtc_drm); + return; + } + + kms = get_kms(crtc_drm); + + for (i = 0; i < sde_crtc->num_mixers; i++) { + hw_lm = sde_crtc->mixers[i].hw_lm; + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_lm->cfg.right_mixer) + break; + } + + if (!hw_dspp) { + DRM_ERROR("invalid dspp\n"); + return; + } + + irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE, + hw_dspp->idx); + if (irq_idx < 0) { + DRM_ERROR("failed to get irq idx\n"); + return; + } + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, sde_crtc); + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + if (!node) + return; + + spin_lock_irqsave(&node->state_lock, flags); + if (node->state == IRQ_DISABLED) { + ret = sde_core_irq_enable(kms, &irq_idx, 1); + if (ret) + DRM_ERROR("failed to enable irq %d\n", irq_idx); + else + node->state = IRQ_ENABLED; + } + spin_unlock_irqrestore(&node->state_lock, flags); +} + +static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, + struct sde_crtc *sde_crtc) +{ + struct sde_hw_cp_cfg hw_cfg; + struct sde_hw_mixer *hw_lm; + struct sde_hw_dspp *hw_dspp; + u32 num_mixers = sde_crtc->num_mixers; + int i = 0, ret = 0; + bool feature_enabled = false; + struct sde_mdss_cfg *catalog = NULL; + + memset(&hw_cfg, 0, sizeof(hw_cfg)); + sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled); + hw_cfg.num_of_mixers = sde_crtc->num_mixers; + hw_cfg.last_feature = 0; + + for (i = 0; i < num_mixers; i++) { + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_dspp || i >= DSPP_MAX) + continue; + hw_cfg.dspp[i] = hw_dspp; + } + + if ((prop_node->feature >= SDE_CP_CRTC_MAX_FEATURES) || + crtc_feature_wrappers[prop_node->feature] == NULL) { + ret = -EINVAL; + } else { + set_feature_wrapper set_feature = + crtc_feature_wrappers[prop_node->feature]; + catalog = get_kms(&sde_crtc->base)->catalog; + hw_cfg.broadcast_disabled = catalog->dma_cfg.broadcast_disabled; + + for (i = 0; i < num_mixers && !ret; i++) { + hw_lm = sde_crtc->mixers[i].hw_lm; + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_lm) { + ret = -EINVAL; + continue; + } + hw_cfg.ctl = sde_crtc->mixers[i].hw_ctl; + hw_cfg.mixer_info = hw_lm; + hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width; + hw_cfg.displayv = hw_lm->cfg.out_height; + + ret = set_feature(hw_dspp, &hw_cfg, sde_crtc); + if (ret) + break; + } + + if (ret) { + DRM_ERROR("failed to %s feature %d\n", + ((feature_enabled) ? "enable" : "disable"), + prop_node->feature); + return; + } + } + + if (feature_enabled) { + DRM_DEBUG_DRIVER("Add feature to active list %d\n", + prop_node->property_id); + sde_cp_update_list(prop_node, sde_crtc, false); + } else { + DRM_DEBUG_DRIVER("remove feature from active list %d\n", + prop_node->property_id); + list_del_init(&prop_node->active_list); + } + /* Programming of feature done remove from dirty list */ + list_del_init(&prop_node->dirty_list); +} + +void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = NULL; + bool set_dspp_flush = false, set_lm_flush = false; + struct sde_cp_node *prop_node = NULL, *n = NULL; + struct sde_hw_ctl *ctl; + u32 num_mixers = 0, i = 0; + + if (!crtc || !crtc->dev) { + DRM_ERROR("invalid crtc %pK dev %pK\n", crtc, + (crtc ? crtc->dev : NULL)); + return; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + num_mixers = sde_crtc->num_mixers; + if (!num_mixers) { + DRM_DEBUG_DRIVER("no mixers for this crtc\n"); + return; + } + + mutex_lock(&sde_crtc->crtc_cp_lock); + + /* Check if dirty lists are empty and ad features are disabled for + * early return. If ad properties are active then we need to issue + * dspp flush. + **/ + if (list_empty(&sde_crtc->dirty_list) && + list_empty(&sde_crtc->ad_dirty)) { + if (list_empty(&sde_crtc->ad_active)) { + DRM_DEBUG_DRIVER("Dirty list is empty\n"); + goto exit; + } + set_dspp_flush = true; + } + + if (!list_empty(&sde_crtc->ad_active)) + sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET); + + list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list, + dirty_list) { + sde_cp_crtc_setfeature(prop_node, sde_crtc); + /* Set the flush flag to true */ + if (prop_node->is_dspp_feature) + set_dspp_flush = true; + else + set_lm_flush = true; + } + + list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_dirty, + dirty_list) { + set_dspp_flush = true; + sde_cp_crtc_setfeature(prop_node, sde_crtc); + } + + for (i = 0; i < num_mixers; i++) { + ctl = sde_crtc->mixers[i].hw_ctl; + if (!ctl) + continue; + if (set_dspp_flush && ctl->ops.update_bitmask_dspp + && sde_crtc->mixers[i].hw_dspp) { + ctl->ops.update_bitmask_dspp(ctl, + sde_crtc->mixers[i].hw_dspp->idx, 1); + } + if (set_lm_flush && ctl->ops.update_bitmask_mixer + && sde_crtc->mixers[i].hw_lm) { + ctl->ops.update_bitmask_mixer(ctl, + sde_crtc->mixers[i].hw_lm->idx, 1); + } + } +exit: + mutex_unlock(&sde_crtc->crtc_cp_lock); +} + +void sde_cp_crtc_install_properties(struct drm_crtc *crtc) +{ + struct sde_kms *kms = NULL; + struct sde_crtc *sde_crtc = NULL; + struct sde_mdss_cfg *catalog = NULL; + unsigned long features = 0; + int i = 0; + struct msm_drm_private *priv; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + DRM_ERROR("invalid crtc %pK dev %pK\n", + crtc, ((crtc) ? crtc->dev : NULL)); + return; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("sde_crtc %pK\n", sde_crtc); + return; + } + + kms = get_kms(crtc); + if (!kms || !kms->catalog) { + DRM_ERROR("invalid sde kms %pK catalog %pK sde_crtc %pK\n", + kms, ((kms) ? kms->catalog : NULL), sde_crtc); + return; + } + + mutex_lock(&sde_crtc->crtc_cp_lock); + + /** + * Function can be called during the atomic_check with test_only flag + * and actual commit. Allocate properties only if feature list is + * empty during the atomic_check with test_only flag. + */ + if (!list_empty(&sde_crtc->feature_list)) + goto exit; + + catalog = kms->catalog; + priv = crtc->dev->dev_private; + /** + * DSPP/LM properties are global to all the CRTCS. + * Properties are created for first CRTC and re-used for later + * crtcs. + */ + if (!priv->cp_property) { + priv->cp_property = kzalloc((sizeof(priv->cp_property) * + SDE_CP_CRTC_MAX_FEATURES), GFP_KERNEL); + setup_dspp_prop_install_funcs(dspp_prop_install_func); + setup_lm_prop_install_funcs(lm_prop_install_func); + setup_crtc_feature_wrappers(crtc_feature_wrappers); + } + if (!priv->cp_property) + goto exit; + + if (!catalog->dspp_count) + goto lm_property; + + /* Check for all the DSPP properties and attach it to CRTC */ + features = catalog->dspp[0].features; + for (i = 0; i < SDE_DSPP_MAX; i++) { + if (!test_bit(i, &features)) + continue; + if (dspp_prop_install_func[i]) + dspp_prop_install_func[i](crtc); + } + +lm_property: + if (!catalog->mixer_count) + goto exit; + + /* Check for all the LM properties and attach it to CRTC */ + features = catalog->mixer[0].features; + for (i = 0; i < SDE_MIXER_MAX; i++) { + if (!test_bit(i, &features)) + continue; + if (lm_prop_install_func[i]) + lm_prop_install_func[i](crtc); + } +exit: + mutex_unlock(&sde_crtc->crtc_cp_lock); + +} + +int sde_cp_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, + uint64_t val) +{ + struct sde_cp_node *prop_node = NULL; + struct sde_crtc *sde_crtc = NULL; + int ret = 0, i = 0, dspp_cnt, lm_cnt; + u8 found = 0; + + if (!crtc || !property) { + DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return -EINVAL; + } + + mutex_lock(&sde_crtc->crtc_cp_lock); + list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) { + if (property->base.id == prop_node->property_id) { + found = 1; + break; + } + } + + if (!found) { + ret = -ENOENT; + goto exit; + } + + /** + * sde_crtc is virtual ensure that hardware has been attached to the + * crtc. Check LM and dspp counts based on whether feature is a + * dspp/lm feature. + */ + if (sde_crtc->num_mixers > ARRAY_SIZE(sde_crtc->mixers)) { + DRM_INFO("Invalid mixer config act cnt %d max cnt %ld\n", + sde_crtc->num_mixers, + (long)ARRAY_SIZE(sde_crtc->mixers)); + ret = -EPERM; + goto exit; + } + + dspp_cnt = 0; + lm_cnt = 0; + for (i = 0; i < sde_crtc->num_mixers; i++) { + if (sde_crtc->mixers[i].hw_dspp) + dspp_cnt++; + if (sde_crtc->mixers[i].hw_lm) + lm_cnt++; + } + + if (prop_node->is_dspp_feature && dspp_cnt < sde_crtc->num_mixers) { + DRM_ERROR("invalid dspp cnt %d mixer cnt %d\n", dspp_cnt, + sde_crtc->num_mixers); + ret = -EINVAL; + goto exit; + } else if (lm_cnt < sde_crtc->num_mixers) { + DRM_ERROR("invalid lm cnt %d mixer cnt %d\n", lm_cnt, + sde_crtc->num_mixers); + ret = -EINVAL; + goto exit; + } + + ret = sde_cp_ad_validate_prop(prop_node, sde_crtc); + if (ret) { + DRM_ERROR("ad property validation failed ret %d\n", ret); + goto exit; + } + + /* remove the property from dirty list */ + list_del_init(&prop_node->dirty_list); + + if (!val) + ret = sde_cp_disable_crtc_property(crtc, property, prop_node); + else + ret = sde_cp_enable_crtc_property(crtc, property, + prop_node, val); + + if (!ret) { + /* remove the property from active list */ + list_del_init(&prop_node->active_list); + /* Mark the feature as dirty */ + sde_cp_update_list(prop_node, sde_crtc, true); + } +exit: + mutex_unlock(&sde_crtc->crtc_cp_lock); + return ret; +} + +int sde_cp_crtc_get_property(struct drm_crtc *crtc, + struct drm_property *property, uint64_t *val) +{ + struct sde_cp_node *prop_node = NULL; + struct sde_crtc *sde_crtc = NULL; + + if (!crtc || !property || !val) { + DRM_ERROR("invalid crtc %pK property %pK val %pK\n", + crtc, property, val); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return -EINVAL; + } + /* Return 0 if property is not supported */ + *val = 0; + mutex_lock(&sde_crtc->crtc_cp_lock); + list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) { + if (property->base.id == prop_node->property_id) { + *val = prop_node->prop_val; + break; + } + } + mutex_unlock(&sde_crtc->crtc_cp_lock); + return 0; +} + +void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = NULL; + struct sde_cp_node *prop_node = NULL, *n = NULL; + u32 i = 0; + + if (!crtc) { + DRM_ERROR("invalid crtc %pK\n", crtc); + return; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + list_for_each_entry_safe(prop_node, n, &sde_crtc->feature_list, + feature_list) { + if (prop_node->prop_flags & DRM_MODE_PROP_BLOB + && prop_node->blob_ptr) + drm_property_blob_put(prop_node->blob_ptr); + + list_del_init(&prop_node->active_list); + list_del_init(&prop_node->dirty_list); + list_del_init(&prop_node->feature_list); + sde_cp_destroy_local_blob(prop_node); + kfree(prop_node); + } + + if (sde_crtc->hist_blob) + drm_property_blob_put(sde_crtc->hist_blob); + + for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++) { + if (sde_crtc->ltm_buffers[i]) { + msm_gem_put_vaddr(sde_crtc->ltm_buffers[i]->gem); + drm_framebuffer_put(sde_crtc->ltm_buffers[i]->fb); + msm_gem_put_iova(sde_crtc->ltm_buffers[i]->gem, + sde_crtc->ltm_buffers[i]->aspace); + kfree(sde_crtc->ltm_buffers[i]); + sde_crtc->ltm_buffers[i] = NULL; + } + } + sde_crtc->ltm_buffer_cnt = 0; + sde_crtc->ltm_hist_en = false; + + mutex_destroy(&sde_crtc->crtc_cp_lock); + INIT_LIST_HEAD(&sde_crtc->active_list); + INIT_LIST_HEAD(&sde_crtc->dirty_list); + INIT_LIST_HEAD(&sde_crtc->ad_dirty); + INIT_LIST_HEAD(&sde_crtc->ad_active); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); +} + +void sde_cp_crtc_suspend(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = NULL; + struct sde_cp_node *prop_node = NULL, *n = NULL; + bool ad_suspend = false; + unsigned long irq_flags; + + if (!crtc) { + DRM_ERROR("crtc %pK\n", crtc); + return; + } + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("sde_crtc %pK\n", sde_crtc); + return; + } + + mutex_lock(&sde_crtc->crtc_cp_lock); + list_for_each_entry_safe(prop_node, n, &sde_crtc->active_list, + active_list) { + sde_cp_update_list(prop_node, sde_crtc, true); + list_del_init(&prop_node->active_list); + } + + list_for_each_entry_safe(prop_node, n, &sde_crtc->ad_active, + active_list) { + sde_cp_update_list(prop_node, sde_crtc, true); + list_del_init(&prop_node->active_list); + ad_suspend = true; + } + mutex_unlock(&sde_crtc->crtc_cp_lock); + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + sde_crtc->ltm_hist_en = false; + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + + if (ad_suspend) + sde_cp_ad_set_prop(sde_crtc, AD_SUSPEND); +} + +void sde_cp_crtc_resume(struct drm_crtc *crtc) +{ + /* placeholder for operations needed during resume */ +} + +void sde_cp_crtc_clear(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = NULL; + unsigned long flags; + u32 i = 0; + + if (!crtc) { + DRM_ERROR("crtc %pK\n", crtc); + return; + } + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("sde_crtc %pK\n", sde_crtc); + return; + } + + mutex_lock(&sde_crtc->crtc_cp_lock); + list_del_init(&sde_crtc->active_list); + list_del_init(&sde_crtc->dirty_list); + list_del_init(&sde_crtc->ad_active); + list_del_init(&sde_crtc->ad_dirty); + mutex_unlock(&sde_crtc->crtc_cp_lock); + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + list_del_init(&sde_crtc->user_event_list); + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++) { + if (sde_crtc->ltm_buffers[i]) { + msm_gem_put_vaddr(sde_crtc->ltm_buffers[i]->gem); + drm_framebuffer_put(sde_crtc->ltm_buffers[i]->fb); + msm_gem_put_iova(sde_crtc->ltm_buffers[i]->gem, + sde_crtc->ltm_buffers[i]->aspace); + kfree(sde_crtc->ltm_buffers[i]); + sde_crtc->ltm_buffers[i] = NULL; + } + } + sde_crtc->ltm_buffer_cnt = 0; + sde_crtc->ltm_hist_en = false; + INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); +} + +static void dspp_pcc_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + + version = catalog->dspp[0].sblk->pcc.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PCC_V", version); + switch (version) { + case 1: + case 4: + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_PCC, sizeof(struct drm_msm_pcc)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_hsic_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->dspp[0].sblk->hsic.version >> 16; + switch (version) { + case 1: + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_HSIC_V", version); + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_HSIC, sizeof(struct drm_msm_pa_hsic)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_memcolor_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->dspp[0].sblk->memcolor.version >> 16; + switch (version) { + case 1: + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_MEMCOL_SKIN_V", version); + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_MEMCOL_SKIN, + sizeof(struct drm_msm_memcol)); + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_MEMCOL_SKY_V", version); + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_MEMCOL_SKY, + sizeof(struct drm_msm_memcol)); + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_MEMCOL_FOLIAGE_V", version); + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_MEMCOL_FOLIAGE, + sizeof(struct drm_msm_memcol)); + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_MEMCOL_PROT_V", version); + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_MEMCOL_PROT, + sizeof(struct drm_msm_memcol)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_sixzone_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->dspp[0].sblk->sixzone.version >> 16; + switch (version) { + case 1: + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_SIXZONE_V", version); + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_SIXZONE, + sizeof(struct drm_msm_sixzone)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_vlut_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->dspp[0].sblk->vlut.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_VLUT_V", version); + switch (version) { + case 1: + sde_cp_crtc_install_range_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_VLUT, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, + SDE_CP_CRTC_DSPP_VLUT, + sizeof(struct drm_msm_pa_vlut)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_ad_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->dspp[0].sblk->ad.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_AD_V", version); + switch (version) { + case 3: + sde_cp_crtc_install_immutable_property(crtc, + feature_name, SDE_CP_CRTC_DSPP_AD); + break; + case 4: + sde_cp_crtc_install_immutable_property(crtc, + feature_name, SDE_CP_CRTC_DSPP_AD); + + sde_cp_crtc_install_enum_property(crtc, + SDE_CP_CRTC_DSPP_AD_MODE, ad4_modes, + ARRAY_SIZE(ad4_modes), "SDE_DSPP_AD_V4_MODE"); + + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INIT", + SDE_CP_CRTC_DSPP_AD_INIT, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_INIT, + sizeof(struct drm_msm_ad4_init)); + + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_CFG", + SDE_CP_CRTC_DSPP_AD_CFG, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_CFG, + sizeof(struct drm_msm_ad4_cfg)); + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_AD_V4_ASSERTIVENESS", + SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0); + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_AD_V4_STRENGTH", + SDE_CP_CRTC_DSPP_AD_STRENGTH, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_STRENGTH, + sizeof(struct drm_msm_ad4_manual_str_cfg)); + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT", + SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0); + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_AD_V4_BACKLIGHT", + SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1), + 0); + + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_ROI", + SDE_CP_CRTC_DSPP_AD_ROI, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_AD_ROI, + sizeof(struct drm_msm_ad4_roi_cfg)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_ltm_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->dspp[0].sblk->ltm.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_LTM_V", version); + switch (version) { + case 1: + sde_cp_crtc_install_immutable_property(crtc, + feature_name, SDE_CP_CRTC_DSPP_LTM); + + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_LTM_INIT_V1", + SDE_CP_CRTC_DSPP_LTM_INIT, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_LTM_INIT, + sizeof(struct drm_msm_ltm_init_param)); + + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_LTM_ROI_V1", + SDE_CP_CRTC_DSPP_LTM_ROI, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_LTM_ROI, + sizeof(struct drm_msm_ltm_cfg_param)); + + sde_cp_crtc_install_enum_property(crtc, + SDE_CP_CRTC_DSPP_LTM_HIST_CTL, sde_ltm_hist_modes, + ARRAY_SIZE(sde_ltm_hist_modes), + "SDE_DSPP_LTM_HIST_CTRL_V1"); + + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_LTM_HIST_THRESH_V1", + SDE_CP_CRTC_DSPP_LTM_HIST_THRESH, 0, (BIT(10) - 1), 0); + + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_LTM_SET_BUF_V1", + SDE_CP_CRTC_DSPP_LTM_SET_BUF, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_LTM_SET_BUF, + sizeof(struct drm_msm_ltm_buffers_ctrl)); + + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_LTM_QUEUE_BUF_V1", + SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF, 0, U64_MAX, 0); + + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_LTM_QUEUE_BUF2_V1", + SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2, 0, U64_MAX, 0); + + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_LTM_QUEUE_BUF3_V1", + SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3, 0, U64_MAX, 0); + + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_LTM_VLUT_V1", + SDE_CP_CRTC_DSPP_LTM_VLUT, 0, U64_MAX, 0); + sde_cp_create_local_blob(crtc, SDE_CP_CRTC_DSPP_LTM_VLUT, + sizeof(struct drm_msm_ltm_data)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void lm_gc_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + version = catalog->mixer[0].sblk->gc.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_LM_GC_V", version); + switch (version) { + case 1: + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_LM_GC, sizeof(struct drm_msm_pgc_lut)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_gamut_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + + version = catalog->dspp[0].sblk->gamut.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_GAMUT_V", version); + switch (version) { + case 4: + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_GAMUT, + sizeof(struct drm_msm_3d_gamut)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_gc_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + + version = catalog->dspp[0].sblk->gc.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_GC_V", version); + switch (version) { + case 1: + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_GC, sizeof(struct drm_msm_pgc_lut)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_igc_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + + version = catalog->dspp[0].sblk->igc.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_IGC_V", version); + switch (version) { + case 3: + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_IGC, sizeof(struct drm_msm_igc_lut)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_hist_install_property(struct drm_crtc *crtc) +{ + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + + version = catalog->dspp[0].sblk->hist.version >> 16; + switch (version) { + case 1: + sde_cp_crtc_install_enum_property(crtc, + SDE_CP_CRTC_DSPP_HIST_CTRL, sde_hist_modes, + ARRAY_SIZE(sde_hist_modes), "SDE_DSPP_HIST_CTRL_V1"); + sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_HIST_IRQ_V1", + SDE_CP_CRTC_DSPP_HIST_IRQ, 0, U16_MAX, 0); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void dspp_dither_install_property(struct drm_crtc *crtc) +{ + char feature_name[256]; + struct sde_kms *kms = NULL; + struct sde_mdss_cfg *catalog = NULL; + u32 version; + + kms = get_kms(crtc); + catalog = kms->catalog; + + version = catalog->dspp[0].sblk->dither.version >> 16; + snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d", + "SDE_DSPP_PA_DITHER_V", version); + switch (version) { + case 1: + sde_cp_crtc_install_blob_property(crtc, feature_name, + SDE_CP_CRTC_DSPP_DITHER, + sizeof(struct drm_msm_pa_dither)); + break; + default: + DRM_ERROR("version %d not supported\n", version); + break; + } +} + +static void sde_cp_update_list(struct sde_cp_node *prop_node, + struct sde_crtc *crtc, bool dirty_list) +{ + switch (prop_node->feature) { + case SDE_CP_CRTC_DSPP_AD_MODE: + case SDE_CP_CRTC_DSPP_AD_INIT: + case SDE_CP_CRTC_DSPP_AD_CFG: + case SDE_CP_CRTC_DSPP_AD_INPUT: + case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS: + case SDE_CP_CRTC_DSPP_AD_BACKLIGHT: + case SDE_CP_CRTC_DSPP_AD_STRENGTH: + case SDE_CP_CRTC_DSPP_AD_ROI: + if (dirty_list) + list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty); + else + list_add_tail(&prop_node->active_list, + &crtc->ad_active); + break; + case SDE_CP_CRTC_DSPP_LTM_SET_BUF: + case SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF: + case SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF2: + case SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3: + if (dirty_list) + list_add_tail(&prop_node->dirty_list, + &crtc->dirty_list); + break; + default: + /* color processing properties handle here */ + if (dirty_list) + list_add_tail(&prop_node->dirty_list, + &crtc->dirty_list); + else + list_add_tail(&prop_node->active_list, + &crtc->active_list); + break; + } +} + +static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node, + struct sde_crtc *crtc) +{ + int i = 0, ret = 0; + u32 ad_prop; + + for (i = 0; i < crtc->num_mixers && !ret; i++) { + if (!crtc->mixers[i].hw_dspp) { + ret = -EINVAL; + continue; + } + switch (prop_node->feature) { + case SDE_CP_CRTC_DSPP_AD_MODE: + ad_prop = AD_MODE; + break; + case SDE_CP_CRTC_DSPP_AD_INIT: + ad_prop = AD_INIT; + break; + case SDE_CP_CRTC_DSPP_AD_CFG: + ad_prop = AD_CFG; + break; + case SDE_CP_CRTC_DSPP_AD_INPUT: + ad_prop = AD_INPUT; + break; + case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS: + ad_prop = AD_ASSERTIVE; + break; + case SDE_CP_CRTC_DSPP_AD_BACKLIGHT: + ad_prop = AD_BACKLIGHT; + break; + case SDE_CP_CRTC_DSPP_AD_STRENGTH: + ad_prop = AD_STRENGTH; + break; + case SDE_CP_CRTC_DSPP_AD_ROI: + ad_prop = AD_ROI; + break; + default: + /* Not an AD property */ + return 0; + } + if (!crtc->mixers[i].hw_dspp->ops.validate_ad) + ret = -EINVAL; + else + ret = crtc->mixers[i].hw_dspp->ops.validate_ad( + crtc->mixers[i].hw_dspp, &ad_prop); + } + return ret; +} + +static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx) +{ + struct sde_crtc *crtc = arg; + + sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, + NULL, true); +} + +static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg) +{ + uint32_t input_bl = 0, output_bl = 0; + uint32_t scale = MAX_SV_BL_SCALE_LEVEL; + struct sde_hw_mixer *hw_lm = NULL; + struct sde_hw_dspp *hw_dspp = NULL; + u32 num_mixers; + struct sde_crtc *crtc; + struct drm_event event; + int i; + struct msm_drm_private *priv; + struct sde_kms *kms; + int ret; + + crtc = to_sde_crtc(crtc_drm); + num_mixers = crtc->num_mixers; + if (!num_mixers) + return; + + for (i = 0; i < num_mixers; i++) { + hw_lm = crtc->mixers[i].hw_lm; + hw_dspp = crtc->mixers[i].hw_dspp; + if (!hw_lm->cfg.right_mixer) + break; + } + + if (!hw_dspp) + return; + + kms = get_kms(crtc_drm); + if (!kms || !kms->dev) { + SDE_ERROR("invalid arg(s)\n"); + return; + } + + priv = kms->dev->dev_private; + ret = pm_runtime_get_sync(kms->dev->dev); + if (ret < 0) { + SDE_ERROR("failed to enable power resource %d\n", ret); + SDE_EVT32(ret, SDE_EVTLOG_ERROR); + return; + } + + hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_IN_OUT_BACKLIGHT, + &input_bl, &output_bl); + + pm_runtime_put_sync(kms->dev->dev); + if (!input_bl || input_bl < output_bl) + return; + + scale = (output_bl * MAX_SV_BL_SCALE_LEVEL) / input_bl; + event.length = sizeof(u32); + event.type = DRM_EVENT_AD_BACKLIGHT; + msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev, + &event, (u8 *)&scale); +} + +int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *ad_irq) +{ + struct sde_kms *kms = NULL; + u32 num_mixers; + struct sde_hw_mixer *hw_lm; + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_crtc *crtc; + int i; + int irq_idx, ret; + unsigned long flags; + struct sde_cp_node prop_node; + struct sde_crtc_irq_info *node = NULL; + + if (!crtc_drm || !ad_irq) { + DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, ad_irq); + return -EINVAL; + } + + crtc = to_sde_crtc(crtc_drm); + if (!crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", crtc); + return -EINVAL; + } + + kms = get_kms(crtc_drm); + num_mixers = crtc->num_mixers; + + memset(&prop_node, 0, sizeof(prop_node)); + prop_node.feature = SDE_CP_CRTC_DSPP_AD_BACKLIGHT; + ret = sde_cp_ad_validate_prop(&prop_node, crtc); + if (ret) { + DRM_ERROR("Ad not supported ret %d\n", ret); + goto exit; + } + + for (i = 0; i < num_mixers; i++) { + hw_lm = crtc->mixers[i].hw_lm; + hw_dspp = crtc->mixers[i].hw_dspp; + if (!hw_lm->cfg.right_mixer) + break; + } + + if (!hw_dspp) { + DRM_ERROR("invalid dspp\n"); + ret = -EINVAL; + goto exit; + } + + irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_AD4_BL_DONE, + hw_dspp->idx); + if (irq_idx < 0) { + DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx); + ret = irq_idx; + goto exit; + } + + node = container_of(ad_irq, struct sde_crtc_irq_info, irq); + + if (!en) { + spin_lock_irqsave(&node->state_lock, flags); + if (node->state == IRQ_ENABLED) { + ret = sde_core_irq_disable(kms, &irq_idx, 1); + if (ret) + DRM_ERROR("disable irq %d error %d\n", + irq_idx, ret); + else + node->state = IRQ_NOINIT; + } else { + node->state = IRQ_NOINIT; + } + spin_unlock_irqrestore(&node->state_lock, flags); + sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); + ret = 0; + goto exit; + } + + ad_irq->arg = crtc; + ad_irq->func = sde_cp_ad_interrupt_cb; + ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq); + if (ret) { + DRM_ERROR("failed to register the callback ret %d\n", ret); + goto exit; + } + + spin_lock_irqsave(&node->state_lock, flags); + if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) { + ret = sde_core_irq_enable(kms, &irq_idx, 1); + if (ret) { + DRM_ERROR("enable irq %d error %d\n", irq_idx, ret); + sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); + } else { + node->state = IRQ_ENABLED; + } + } + spin_unlock_irqrestore(&node->state_lock, flags); + +exit: + return ret; +} + +static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc, + enum ad_property ad_prop) +{ + struct sde_ad_hw_cfg ad_cfg; + struct sde_hw_cp_cfg hw_cfg; + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_hw_mixer *hw_lm = NULL; + u32 num_mixers = sde_crtc->num_mixers; + int i = 0, ret = 0; + + hw_cfg.num_of_mixers = sde_crtc->num_mixers; + + for (i = 0; i < num_mixers && !ret; i++) { + hw_lm = sde_crtc->mixers[i].hw_lm; + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_lm || !hw_dspp || !hw_dspp->ops.validate_ad || + !hw_dspp->ops.setup_ad) { + ret = -EINVAL; + continue; + } + + hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width; + hw_cfg.displayv = hw_lm->cfg.out_height; + hw_cfg.mixer_info = hw_lm; + ad_cfg.prop = ad_prop; + ad_cfg.hw_cfg = &hw_cfg; + ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop); + if (!ret) + hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + } +} + +void sde_cp_crtc_pre_ipc(struct drm_crtc *drm_crtc) +{ + struct sde_crtc *sde_crtc; + + sde_crtc = to_sde_crtc(drm_crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + sde_cp_ad_set_prop(sde_crtc, AD_IPC_SUSPEND); +} + +void sde_cp_crtc_post_ipc(struct drm_crtc *drm_crtc) +{ + struct sde_crtc *sde_crtc; + + sde_crtc = to_sde_crtc(drm_crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESUME); +} + +static void sde_cp_hist_interrupt_cb(void *arg, int irq_idx) +{ + struct sde_crtc *crtc = arg; + struct drm_crtc *crtc_drm = &crtc->base; + struct sde_hw_dspp *hw_dspp; + struct sde_kms *kms; + struct sde_crtc_irq_info *node = NULL; + u32 i; + int ret = 0; + unsigned long flags; + + /* disable histogram irq */ + kms = get_kms(crtc_drm); + spin_lock_irqsave(&crtc->spin_lock, flags); + node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc); + spin_unlock_irqrestore(&crtc->spin_lock, flags); + + if (!node) { + DRM_DEBUG_DRIVER("cannot find histogram event node in crtc\n"); + return; + } + + spin_lock_irqsave(&node->state_lock, flags); + if (node->state == IRQ_ENABLED) { + if (sde_core_irq_disable_nolock(kms, irq_idx)) { + DRM_ERROR("failed to disable irq %d, ret %d\n", + irq_idx, ret); + spin_unlock_irqrestore(&node->state_lock, flags); + return; + } + node->state = IRQ_DISABLED; + } + spin_unlock_irqrestore(&node->state_lock, flags); + + /* lock histogram buffer */ + for (i = 0; i < crtc->num_mixers; i++) { + hw_dspp = crtc->mixers[i].hw_dspp; + if (hw_dspp && hw_dspp->ops.lock_histogram) + hw_dspp->ops.lock_histogram(hw_dspp, NULL); + } + + /* notify histogram event */ + sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event, + NULL, true); +} + +static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg) +{ + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_crtc *crtc; + struct drm_event event; + struct drm_msm_hist *hist_data; + struct sde_kms *kms; + int ret; + u32 i; + + if (!crtc_drm) { + DRM_ERROR("invalid crtc %pK\n", crtc_drm); + return; + } + + crtc = to_sde_crtc(crtc_drm); + if (!crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", crtc); + return; + } + + if (!crtc->hist_blob) + return; + + kms = get_kms(crtc_drm); + if (!kms || !kms->dev) { + SDE_ERROR("invalid arg(s)\n"); + return; + } + + ret = pm_runtime_get_sync(kms->dev->dev); + if (ret < 0) { + SDE_ERROR("failed to enable power resource %d\n", ret); + SDE_EVT32(ret, SDE_EVTLOG_ERROR); + return; + } + + /* read histogram data into blob */ + hist_data = (struct drm_msm_hist *)crtc->hist_blob->data; + memset(hist_data->data, 0, sizeof(hist_data->data)); + for (i = 0; i < crtc->num_mixers; i++) { + hw_dspp = crtc->mixers[i].hw_dspp; + if (!hw_dspp || !hw_dspp->ops.read_histogram) { + DRM_ERROR("invalid dspp %pK or read_histogram func\n", + hw_dspp); + pm_runtime_put_sync(kms->dev->dev); + return; + } + hw_dspp->ops.read_histogram(hw_dspp, hist_data); + } + + pm_runtime_put_sync(kms->dev->dev); + /* send histogram event with blob id */ + event.length = sizeof(u32); + event.type = DRM_EVENT_HISTOGRAM; + msm_mode_object_event_notify(&crtc_drm->base, crtc_drm->dev, + &event, (u8 *)(&crtc->hist_blob->base.id)); +} + +int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *hist_irq) +{ + struct sde_kms *kms = NULL; + u32 num_mixers; + struct sde_hw_mixer *hw_lm; + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_crtc *crtc; + struct sde_crtc_irq_info *node = NULL; + int i, irq_idx, ret = 0; + unsigned long flags; + + if (!crtc_drm || !hist_irq) { + DRM_ERROR("invalid crtc %pK irq %pK\n", crtc_drm, hist_irq); + return -EINVAL; + } + + crtc = to_sde_crtc(crtc_drm); + if (!crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", crtc); + return -EINVAL; + } + + kms = get_kms(crtc_drm); + num_mixers = crtc->num_mixers; + + for (i = 0; i < num_mixers; i++) { + hw_lm = crtc->mixers[i].hw_lm; + hw_dspp = crtc->mixers[i].hw_dspp; + if (!hw_lm->cfg.right_mixer) + break; + } + + if (!hw_dspp) { + DRM_ERROR("invalid dspp\n"); + ret = -EPERM; + goto exit; + } + + irq_idx = sde_core_irq_idx_lookup(kms, SDE_IRQ_TYPE_HIST_DSPP_DONE, + hw_dspp->idx); + if (irq_idx < 0) { + DRM_ERROR("failed to get the irq idx ret %d\n", irq_idx); + ret = irq_idx; + goto exit; + } + + node = container_of(hist_irq, struct sde_crtc_irq_info, irq); + + /* deregister histogram irq */ + if (!en) { + spin_lock_irqsave(&node->state_lock, flags); + if (node->state == IRQ_ENABLED) { + node->state = IRQ_DISABLING; + spin_unlock_irqrestore(&node->state_lock, flags); + ret = sde_core_irq_disable(kms, &irq_idx, 1); + spin_lock_irqsave(&node->state_lock, flags); + if (ret) { + DRM_ERROR("disable irq %d error %d\n", + irq_idx, ret); + node->state = IRQ_ENABLED; + } else { + node->state = IRQ_NOINIT; + } + spin_unlock_irqrestore(&node->state_lock, flags); + } else if (node->state == IRQ_DISABLED) { + node->state = IRQ_NOINIT; + spin_unlock_irqrestore(&node->state_lock, flags); + } else { + spin_unlock_irqrestore(&node->state_lock, flags); + } + + sde_core_irq_unregister_callback(kms, irq_idx, hist_irq); + goto exit; + } + + /* register histogram irq */ + hist_irq->arg = crtc; + hist_irq->func = sde_cp_hist_interrupt_cb; + ret = sde_core_irq_register_callback(kms, irq_idx, hist_irq); + if (ret) { + DRM_ERROR("failed to register the callback ret %d\n", ret); + goto exit; + } + + spin_lock_irqsave(&node->state_lock, flags); + if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) { + ret = sde_core_irq_enable(kms, &irq_idx, 1); + if (ret) { + DRM_ERROR("enable irq %d error %d\n", irq_idx, ret); + sde_core_irq_unregister_callback(kms, + irq_idx, hist_irq); + } else { + node->state = IRQ_ENABLED; + } + } + spin_unlock_irqrestore(&node->state_lock, flags); + +exit: + return ret; +} + +/* needs to be called within ltm_buffer_lock mutex */ +static void _sde_cp_crtc_free_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg) +{ + u32 i = 0, buffer_count = 0; + unsigned long irq_flags; + + if (!sde_crtc) { + DRM_ERROR("invalid parameters sde_crtc %pK\n", sde_crtc); + return; + } + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + if (sde_crtc->ltm_hist_en) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("cannot free LTM buffers when hist is enabled\n"); + return; + } + if (!sde_crtc->ltm_buffer_cnt) { + /* ltm_buffers are already freed */ + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + return; + } + if (!list_empty(&sde_crtc->ltm_buf_busy)) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("ltm_buf_busy is not empty\n"); + return; + } + + buffer_count = sde_crtc->ltm_buffer_cnt; + sde_crtc->ltm_buffer_cnt = 0; + INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + + for (i = 0; i < buffer_count && sde_crtc->ltm_buffers[i]; i++) { + msm_gem_put_vaddr(sde_crtc->ltm_buffers[i]->gem); + drm_framebuffer_put(sde_crtc->ltm_buffers[i]->fb); + msm_gem_put_iova(sde_crtc->ltm_buffers[i]->gem, + sde_crtc->ltm_buffers[i]->aspace); + kfree(sde_crtc->ltm_buffers[i]); + sde_crtc->ltm_buffers[i] = NULL; + } +} + +/* needs to be called within ltm_buffer_lock mutex */ +static void _sde_cp_crtc_set_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_ltm_buffers_ctrl *buf_cfg; + struct drm_framebuffer *fb; + struct drm_crtc *crtc; + u32 size = 0, expected_size = 0; + u32 i = 0, j = 0, num = 0, iova_aligned; + int ret = 0; + unsigned long irq_flags; + + if (!sde_crtc || !cfg) { + DRM_ERROR("invalid parameters sde_crtc %pK cfg %pK\n", sde_crtc, + cfg); + return; + } + + crtc = &sde_crtc->base; + if (!crtc) { + DRM_ERROR("invalid parameters drm_crtc %pK\n", crtc); + return; + } + + buf_cfg = hw_cfg->payload; + num = buf_cfg->num_of_buffers; + if (num == 0 || num > LTM_BUFFER_SIZE) { + DRM_ERROR("invalid buffer size %d\n", num); + return; + } + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + if (sde_crtc->ltm_buffer_cnt) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_DEBUG("%d ltm_buffers already allocated\n", + sde_crtc->ltm_buffer_cnt); + return; + } + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + + expected_size = sizeof(struct drm_msm_ltm_stats_data) + LTM_GUARD_BYTES; + for (i = 0; i < num; i++) { + sde_crtc->ltm_buffers[i] = kzalloc( + sizeof(struct sde_ltm_buffer), GFP_KERNEL); + if (IS_ERR_OR_NULL(sde_crtc->ltm_buffers[i])) + goto exit; + + sde_crtc->ltm_buffers[i]->drm_fb_id = buf_cfg->fds[i]; + fb = drm_framebuffer_lookup(crtc->dev, NULL, buf_cfg->fds[i]); + if (!fb) { + DRM_ERROR("unknown framebuffer ID %d\n", + buf_cfg->fds[i]); + goto exit; + } + + sde_crtc->ltm_buffers[i]->fb = fb; + sde_crtc->ltm_buffers[i]->gem = msm_framebuffer_bo(fb, 0); + if (!sde_crtc->ltm_buffers[i]->gem) { + DRM_ERROR("failed to get gem object\n"); + goto exit; + } + + size = PAGE_ALIGN(sde_crtc->ltm_buffers[i]->gem->size); + if (size < expected_size) { + DRM_ERROR("Invalid buffer size\n"); + goto exit; + } + + sde_crtc->ltm_buffers[i]->aspace = + msm_gem_smmu_address_space_get(crtc->dev, + MSM_SMMU_DOMAIN_UNSECURE); + if (!sde_crtc->ltm_buffers[i]->aspace) { + DRM_ERROR("failed to get aspace\n"); + goto exit; + } + ret = msm_gem_get_iova(sde_crtc->ltm_buffers[i]->gem, + sde_crtc->ltm_buffers[i]->aspace, + &sde_crtc->ltm_buffers[i]->iova); + if (ret) { + DRM_ERROR("failed to get the iova ret %d\n", ret); + goto exit; + } + + sde_crtc->ltm_buffers[i]->kva = msm_gem_get_vaddr( + sde_crtc->ltm_buffers[i]->gem); + if (IS_ERR_OR_NULL(sde_crtc->ltm_buffers[i]->kva)) { + DRM_ERROR("failed to get kva\n"); + goto exit; + } + iova_aligned = (sde_crtc->ltm_buffers[i]->iova + + LTM_GUARD_BYTES) & ALIGNED_OFFSET; + sde_crtc->ltm_buffers[i]->offset = iova_aligned - + sde_crtc->ltm_buffers[i]->iova; + } + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + /* Add buffers to ltm_buf_free list */ + for (i = 0; i < num; i++) + list_add(&sde_crtc->ltm_buffers[i]->node, + &sde_crtc->ltm_buf_free); + sde_crtc->ltm_buffer_cnt = num; + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + + return; +exit: + for (j = 0; j < i; j++) { + if (sde_crtc->ltm_buffers[i]->aspace) + msm_gem_put_iova(sde_crtc->ltm_buffers[i]->gem, + sde_crtc->ltm_buffers[i]->aspace); + if (sde_crtc->ltm_buffers[i]->gem) + msm_gem_put_vaddr(sde_crtc->ltm_buffers[i]->gem); + if (sde_crtc->ltm_buffers[i]->fb) + drm_framebuffer_put(sde_crtc->ltm_buffers[i]->fb); + kfree(sde_crtc->ltm_buffers[i]); + sde_crtc->ltm_buffers[i] = NULL; + } +} + +/* needs to be called within ltm_buffer_lock mutex */ +static void _sde_cp_crtc_queue_ltm_buffer(struct sde_crtc *sde_crtc, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_ltm_buffer *buf; + struct drm_msm_ltm_stats_data *ltm_data = NULL; + struct sde_ltm_buffer *free_buf; + u32 i; + bool found = false, already = false; + unsigned long irq_flags; + struct sde_ltm_buffer *buffer = NULL, *n = NULL; + u64 addr = 0; + bool submit_buf = false; + uint32_t num_mixers = 0; + struct sde_hw_dspp *hw_dspp = NULL; + + if (!sde_crtc || !cfg) { + DRM_ERROR("invalid parameters sde_crtc %pK cfg %pK\n", sde_crtc, + cfg); + return; + } + + buf = hw_cfg->payload; + if (!buf) { + DRM_ERROR("invalid parameters payload %pK\n", buf); + return; + } + num_mixers = sde_crtc->num_mixers; + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + if (!sde_crtc->ltm_buffer_cnt) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("LTM buffers are not allocated\n"); + return; + } + + if (list_empty(&sde_crtc->ltm_buf_free)) + submit_buf = true; + for (i = 0; i < LTM_BUFFER_SIZE; i++) { + if (sde_crtc->ltm_buffers[i] && buf->fd == + sde_crtc->ltm_buffers[i]->drm_fb_id) { + /* clear the status flag */ + ltm_data = (struct drm_msm_ltm_stats_data *) + ((u8 *)sde_crtc->ltm_buffers[i]->kva + + sde_crtc->ltm_buffers[i]->offset); + ltm_data->status_flag = 0; + + list_for_each_entry_safe(buffer, n, + &sde_crtc->ltm_buf_free, node) { + if (buffer->drm_fb_id == buf->fd) + already = true; + } + if (!already) + list_add_tail(&sde_crtc->ltm_buffers[i]->node, + &sde_crtc->ltm_buf_free); + found = true; + } + } + if (submit_buf && found) { + free_buf = list_first_entry(&sde_crtc->ltm_buf_free, + struct sde_ltm_buffer, node); + addr = free_buf->iova + free_buf->offset; + + for (i = 0; i < num_mixers; i++) { + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_dspp) { + DRM_ERROR("invalid dspp for mixer %d\n", i); + break; + } + hw_dspp->ops.setup_ltm_hist_buffer(hw_dspp, addr); + } + } + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + + if (!found) + DRM_ERROR("failed to found a matching buffer fd %d", buf->fd); +} + +/* this func needs to be called within the ltm_buffer_lock and ltm_lock */ +static int _sde_cp_crtc_get_ltm_buffer(struct sde_crtc *sde_crtc, u64 *addr) +{ + struct sde_ltm_buffer *buf; + + if (!sde_crtc || !addr) { + DRM_ERROR("invalid parameters sde_crtc %pK cfg %pK\n", + sde_crtc, addr); + return -EINVAL; + } + + /** + * for LTM merge mode, both LTM blocks will use the same buffer for + * hist collection. The first LTM will acquire a buffer from buf_free + * list and move that buffer to buf_busy list; the second LTM block + * will get the same buffer from busy list for HW programming + */ + if (!list_empty(&sde_crtc->ltm_buf_busy)) { + buf = list_first_entry(&sde_crtc->ltm_buf_busy, + struct sde_ltm_buffer, node); + *addr = buf->iova + buf->offset; + DRM_DEBUG_DRIVER("ltm_buf_busy list already has a buffer\n"); + return 0; + } + + buf = list_first_entry(&sde_crtc->ltm_buf_free, struct sde_ltm_buffer, + node); + + *addr = buf->iova + buf->offset; + list_del_init(&buf->node); + list_add_tail(&buf->node, &sde_crtc->ltm_buf_busy); + + return 0; +} + +/* this func needs to be called within the ltm_buffer_lock mutex */ +static void _sde_cp_crtc_enable_ltm_hist(struct sde_crtc *sde_crtc, + struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg) +{ + int ret = 0; + u64 addr = 0; + unsigned long irq_flags; + struct sde_hw_mixer *hw_lm = hw_cfg->mixer_info; + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + if (!sde_crtc->ltm_buffer_cnt) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("LTM buffers are not allocated\n"); + return; + } + + if (!hw_lm->cfg.right_mixer && sde_crtc->ltm_hist_en) { + /* histogram is already enabled */ + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + return; + } + + ret = _sde_cp_crtc_get_ltm_buffer(sde_crtc, &addr); + if (!ret) { + if (!hw_lm->cfg.right_mixer) + sde_crtc->ltm_hist_en = true; + hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, hw_cfg, + true, addr); + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + } + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); +} + +/* this func needs to be called within the ltm_buffer_lock mutex */ +static void _sde_cp_crtc_disable_ltm_hist(struct sde_crtc *sde_crtc, + struct sde_hw_dspp *hw_dspp, struct sde_hw_cp_cfg *hw_cfg) +{ + unsigned long irq_flags; + u32 i = 0; + bool notify = false; + u8 hist_off = 1; + struct drm_event event; + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + notify = sde_crtc->ltm_hist_en; + sde_crtc->ltm_hist_en = false; + INIT_LIST_HEAD(&sde_crtc->ltm_buf_free); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); + for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++) + list_add(&sde_crtc->ltm_buffers[i]->node, + &sde_crtc->ltm_buf_free); + hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, NULL, + false, 0); + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + event.type = DRM_EVENT_LTM_OFF; + event.length = sizeof(hist_off); + if (notify) { + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); + msm_mode_object_event_notify(&sde_crtc->base.base, + sde_crtc->base.dev, &event, + (u8 *)&hist_off); + } + +} + +static void sde_cp_ltm_hist_interrupt_cb(void *arg, int irq_idx) +{ + struct sde_crtc *sde_crtc = arg; + struct sde_ltm_buffer *busy_buf, *free_buf; + struct sde_hw_dspp *hw_dspp = NULL; + struct drm_msm_ltm_stats_data *ltm_data = NULL; + u32 num_mixers = 0, i = 0, status = 0, ltm_hist_status = 0; + u64 addr = 0; + int idx = -1; + unsigned long irq_flags; + struct sde_ltm_phase_info phase; + struct sde_hw_cp_cfg hw_cfg; + struct sde_hw_mixer *hw_lm; + + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + memset(&phase, 0, sizeof(phase)); + + /* read intr_status register value */ + num_mixers = sde_crtc->num_mixers; + if (!num_mixers) + return; + + for (i = 0; i < num_mixers; i++) { + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_dspp) { + DRM_ERROR("invalid dspp for mixer %d\n", i); + return; + } + hw_dspp->ops.ltm_read_intr_status(hw_dspp, &status); + if (status & LTM_STATS_SAT) + ltm_hist_status |= LTM_STATS_SAT; + if (status & LTM_STATS_MERGE_SAT) + ltm_hist_status |= LTM_STATS_MERGE_SAT; + } + + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + if (!sde_crtc->ltm_buffer_cnt) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + /* all LTM buffers are freed, no further action is needed */ + return; + } + + if (!sde_crtc->ltm_hist_en) { + /* histogram is disabled, no need to notify user space */ + for (i = 0; i < sde_crtc->num_mixers; i++) { + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_dspp || i >= DSPP_MAX) + continue; + hw_dspp->ops.setup_ltm_hist_ctrl(hw_dspp, NULL, false, + 0); + } + + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_DEBUG_DRIVER("LTM histogram is disabled\n"); + return; + } + + /* if no free buffer available, the same buffer is used by HW */ + if (list_empty(&sde_crtc->ltm_buf_free)) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_DEBUG_DRIVER("no free buffer available\n"); + return; + } + + busy_buf = list_first_entry(&sde_crtc->ltm_buf_busy, + struct sde_ltm_buffer, node); + free_buf = list_first_entry(&sde_crtc->ltm_buf_free, + struct sde_ltm_buffer, node); + + /* find the index of buffer in the ltm_buffers */ + for (i = 0; i < sde_crtc->ltm_buffer_cnt; i++) { + if (busy_buf->drm_fb_id == sde_crtc->ltm_buffers[i]->drm_fb_id) + idx = i; + } + if (idx < 0) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("failed to found the buffer in the list fb_id %d\n", + busy_buf->drm_fb_id); + return; + } + + addr = free_buf->iova + free_buf->offset; + for (i = 0; i < num_mixers; i++) { + hw_dspp = sde_crtc->mixers[i].hw_dspp; + if (!hw_dspp) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("invalid dspp for mixer %d\n", i); + return; + } + hw_dspp->ops.setup_ltm_hist_buffer(hw_dspp, addr); + } + + list_del_init(&busy_buf->node); + list_del_init(&free_buf->node); + INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy); + list_add_tail(&free_buf->node, &sde_crtc->ltm_buf_busy); + + ltm_data = (struct drm_msm_ltm_stats_data *) + ((u8 *)sde_crtc->ltm_buffers[idx]->kva + + sde_crtc->ltm_buffers[idx]->offset); + ltm_data->status_flag = ltm_hist_status; + + hw_lm = sde_crtc->mixers[0].hw_lm; + if (!hw_lm) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + DRM_ERROR("invalid layer mixer\n"); + return; + } + hw_cfg.num_of_mixers = num_mixers; + hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width; + hw_cfg.displayv = hw_lm->cfg.out_height; + + sde_ltm_get_phase_info(&hw_cfg, &phase); + ltm_data->display_h = hw_cfg.displayh; + ltm_data->display_v = hw_cfg.displayv; + ltm_data->init_h[0] = phase.init_h[LTM_0]; + ltm_data->init_h[1] = phase.init_h[LTM_1]; + ltm_data->init_v = phase.init_v; + ltm_data->inc_v = phase.inc_v; + ltm_data->inc_h = phase.inc_h; + ltm_data->portrait_en = phase.portrait_en; + ltm_data->merge_en = phase.merge_en; + ltm_data->cfg_param_01 = sde_crtc->ltm_cfg.cfg_param_01; + ltm_data->cfg_param_02 = sde_crtc->ltm_cfg.cfg_param_02; + ltm_data->cfg_param_03 = sde_crtc->ltm_cfg.cfg_param_03; + ltm_data->cfg_param_04 = sde_crtc->ltm_cfg.cfg_param_04; + sde_crtc_event_queue(&sde_crtc->base, sde_cp_notify_ltm_hist, + sde_crtc->ltm_buffers[idx], true); + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); +} + +static void sde_cp_ltm_wb_pb_interrupt_cb(void *arg, int irq_idx) +{ + struct sde_crtc *sde_crtc = arg; + + sde_crtc_event_queue(&sde_crtc->base, sde_cp_notify_ltm_wb_pb, NULL, + true); +} + +static void sde_cp_notify_ltm_hist(struct drm_crtc *crtc, void *arg) +{ + struct drm_event event; + struct drm_msm_ltm_buffer payload = {}; + struct sde_ltm_buffer *buf; + struct sde_crtc *sde_crtc; + unsigned long irq_flags; + + if (!crtc || !arg) { + DRM_ERROR("invalid drm_crtc %pK or arg %pK\n", crtc, arg); + return; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + mutex_lock(&sde_crtc->ltm_buffer_lock); + spin_lock_irqsave(&sde_crtc->ltm_lock, irq_flags); + if (!sde_crtc->ltm_buffer_cnt) { + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + mutex_unlock(&sde_crtc->ltm_buffer_lock); + /* all LTM buffers are freed, no further action is needed */ + return; + } + + if (!sde_crtc->ltm_hist_en) { + /* histogram is disabled, no need to notify user space */ + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + mutex_unlock(&sde_crtc->ltm_buffer_lock); + DRM_DEBUG_DRIVER("ltm histogram is disabled\n"); + return; + } + + buf = (struct sde_ltm_buffer *)arg; + payload.fd = buf->drm_fb_id; + payload.offset = buf->offset; + event.length = sizeof(struct drm_msm_ltm_buffer); + event.type = DRM_EVENT_LTM_HIST; + DRM_DEBUG_DRIVER("notify with LTM hist event drm_fb_id %d\n", + buf->drm_fb_id); + msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, + (u8 *)&payload); + spin_unlock_irqrestore(&sde_crtc->ltm_lock, irq_flags); + mutex_unlock(&sde_crtc->ltm_buffer_lock); +} + +static void sde_cp_notify_ltm_wb_pb(struct drm_crtc *crtc, void *arg) +{ + struct drm_event event; + struct drm_msm_ltm_buffer payload = {}; + + if (!crtc) { + DRM_ERROR("invalid drm_crtc %pK\n", crtc); + return; + } + + payload.fd = 0; + payload.offset = 0; + event.length = sizeof(struct drm_msm_ltm_buffer); + event.type = DRM_EVENT_LTM_WB_PB; + msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, + (u8 *)&payload); +} + +static int sde_cp_ltm_register_irq(struct sde_kms *kms, + struct sde_crtc *sde_crtc, struct sde_hw_dspp *hw_dspp, + struct sde_irq_callback *ltm_irq, enum sde_intr_type irq) +{ + int irq_idx, ret = 0; + + if (irq == SDE_IRQ_TYPE_LTM_STATS_DONE) { + ltm_irq->func = sde_cp_ltm_hist_interrupt_cb; + } else if (irq == SDE_IRQ_TYPE_LTM_STATS_WB_PB) { + ltm_irq->func = sde_cp_ltm_wb_pb_interrupt_cb; + } else { + DRM_ERROR("invalid irq type %d\n", irq); + return -EINVAL; + } + + irq_idx = sde_core_irq_idx_lookup(kms, irq, hw_dspp->idx); + if (irq_idx < 0) { + DRM_ERROR("failed to get the irq idx %d\n", irq_idx); + return irq_idx; + } + + ltm_irq->arg = sde_crtc; + ret = sde_core_irq_register_callback(kms, irq_idx, ltm_irq); + if (ret) { + DRM_ERROR("failed to register the callback ret %d\n", ret); + return ret; + } + + ret = sde_core_irq_enable(kms, &irq_idx, 1); + if (ret) { + DRM_ERROR("enable irq %d error %d\n", irq_idx, ret); + sde_core_irq_unregister_callback(kms, irq_idx, ltm_irq); + } + + return ret; +} + +static int sde_cp_ltm_unregister_irq(struct sde_kms *kms, + struct sde_crtc *sde_crtc, struct sde_hw_dspp *hw_dspp, + struct sde_irq_callback *ltm_irq, enum sde_intr_type irq) +{ + int irq_idx, ret = 0; + + if (!(irq == SDE_IRQ_TYPE_LTM_STATS_DONE || + irq == SDE_IRQ_TYPE_LTM_STATS_WB_PB)) { + DRM_ERROR("invalid irq type %d\n", irq); + return -EINVAL; + } + + irq_idx = sde_core_irq_idx_lookup(kms, irq, hw_dspp->idx); + if (irq_idx < 0) { + DRM_ERROR("failed to get the irq idx %d\n", irq_idx); + return irq_idx; + } + + ret = sde_core_irq_disable(kms, &irq_idx, 1); + if (ret) + DRM_ERROR("disable irq %d error %d\n", irq_idx, ret); + + sde_core_irq_unregister_callback(kms, irq_idx, ltm_irq); + return ret; +} + +int sde_cp_ltm_hist_interrupt(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *ltm_irq) +{ + struct sde_kms *kms = NULL; + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_crtc *sde_crtc; + int ret = 0; + + if (!crtc || !ltm_irq) { + DRM_ERROR("invalid params: crtc %pK irq %pK\n", crtc, ltm_irq); + return -EINVAL; + } + + kms = get_kms(crtc); + sde_crtc = to_sde_crtc(crtc); + if (!kms || !sde_crtc) { + DRM_ERROR("invalid params: kms %pK sde_crtc %pK\n", kms, + sde_crtc); + return -EINVAL; + } + + /* enable interrupt on master LTM block */ + hw_dspp = sde_crtc->mixers[0].hw_dspp; + if (!hw_dspp) { + DRM_ERROR("invalid dspp\n"); + return -ENODEV; + } + + if (en) { + ret = sde_cp_ltm_register_irq(kms, sde_crtc, hw_dspp, + ltm_irq, SDE_IRQ_TYPE_LTM_STATS_DONE); + if (ret) + DRM_ERROR("failed to register stats_done irq\n"); + } else { + ret = sde_cp_ltm_unregister_irq(kms, sde_crtc, hw_dspp, + ltm_irq, SDE_IRQ_TYPE_LTM_STATS_DONE); + if (ret) + DRM_ERROR("failed to unregister stats_done irq\n"); + } + return ret; +} + +int sde_cp_ltm_wb_pb_interrupt(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *ltm_irq) +{ + struct sde_kms *kms = NULL; + struct sde_hw_dspp *hw_dspp = NULL; + struct sde_crtc *sde_crtc; + int ret = 0; + + if (!crtc || !ltm_irq) { + DRM_ERROR("invalid params: crtc %pK irq %pK\n", crtc, ltm_irq); + return -EINVAL; + } + + kms = get_kms(crtc); + sde_crtc = to_sde_crtc(crtc); + if (!kms || !sde_crtc) { + DRM_ERROR("invalid params: kms %pK sde_crtc %pK\n", kms, + sde_crtc); + return -EINVAL; + } + + /* enable interrupt on master LTM block */ + hw_dspp = sde_crtc->mixers[0].hw_dspp; + if (!hw_dspp) { + DRM_ERROR("invalid dspp\n"); + return -EINVAL; + } + + if (en) { + ret = sde_cp_ltm_register_irq(kms, sde_crtc, hw_dspp, + ltm_irq, SDE_IRQ_TYPE_LTM_STATS_WB_PB); + if (ret) + DRM_ERROR("failed to register WB_PB irq\n"); + } else { + ret = sde_cp_ltm_unregister_irq(kms, sde_crtc, hw_dspp, + ltm_irq, SDE_IRQ_TYPE_LTM_STATS_WB_PB); + if (ret) + DRM_ERROR("failed to unregister WB_PB irq\n"); + } + return ret; +} + +static void _sde_cp_crtc_update_ltm_roi(struct sde_crtc *sde_crtc, + struct sde_hw_cp_cfg *hw_cfg) +{ + struct drm_msm_ltm_cfg_param *cfg_param = NULL; + + /* disable case */ + if (!hw_cfg->payload) { + memset(&sde_crtc->ltm_cfg, 0, + sizeof(struct drm_msm_ltm_cfg_param)); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_ltm_cfg_param)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_ltm_cfg_param)); + return; + } + + cfg_param = hw_cfg->payload; + /* input param exceeds the display width */ + if (cfg_param->cfg_param_01 + cfg_param->cfg_param_03 > + hw_cfg->displayh) { + DRM_DEBUG_DRIVER("invalid input = [%u,%u], displayh = %u\n", + cfg_param->cfg_param_01, cfg_param->cfg_param_03, + hw_cfg->displayh); + /* set the roi width to max register value */ + cfg_param->cfg_param_03 = 0xFFFF; + } + + /* input param exceeds the display height */ + if (cfg_param->cfg_param_02 + cfg_param->cfg_param_04 > + hw_cfg->displayv) { + DRM_DEBUG_DRIVER("invalid input = [%u,%u], displayv = %u\n", + cfg_param->cfg_param_02, cfg_param->cfg_param_04, + hw_cfg->displayv); + /* set the roi height to max register value */ + cfg_param->cfg_param_04 = 0xFFFF; + } + + sde_crtc->ltm_cfg = *cfg_param; +} + +int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *hist_irq) +{ + return 0; +} + +void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm) +{ + struct sde_cp_node *prop_node = NULL, *n = NULL; + struct sde_crtc *crtc; + + if (!crtc_drm) { + DRM_ERROR("invalid crtc handle"); + return; + } + crtc = to_sde_crtc(crtc_drm); + mutex_lock(&crtc->crtc_cp_lock); + list_for_each_entry_safe(prop_node, n, &crtc->active_list, + active_list) { + if (prop_node->feature == SDE_CP_CRTC_DSPP_LTM_INIT || + prop_node->feature == SDE_CP_CRTC_DSPP_LTM_VLUT) { + list_del_init(&prop_node->active_list); + list_add_tail(&prop_node->dirty_list, + &crtc->dirty_list); + } + } + mutex_unlock(&crtc->crtc_cp_lock); +} diff --git a/techpack/display/msm/sde/sde_color_processing.h b/techpack/display/msm/sde/sde_color_processing.h new file mode 100644 index 0000000000000000000000000000000000000000..0b831977d7400567fc16abef6f553dcba721b7fb --- /dev/null +++ b/techpack/display/msm/sde/sde_color_processing.h @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_COLOR_PROCESSING_H +#define _SDE_COLOR_PROCESSING_H +#include <drm/drm_crtc.h> + +struct sde_irq_callback; + +/* + * PA MEMORY COLOR types + * @MEMCOLOR_SKIN Skin memory color type + * @MEMCOLOR_SKY Sky memory color type + * @MEMCOLOR_FOLIAGE Foliage memory color type + */ +enum sde_memcolor_type { + MEMCOLOR_SKIN = 0, + MEMCOLOR_SKY, + MEMCOLOR_FOLIAGE, + MEMCOLOR_MAX +}; + +/* + * PA HISTOGRAM modes + * @HIST_DISABLED Histogram disabled + * @HIST_ENABLED Histogram enabled + */ +enum sde_hist_modes { + HIST_DISABLED, + HIST_ENABLED +}; + +/** + * struct drm_prop_enum_list - drm structure for creating enum property and + * enumerating values + */ +static const struct drm_prop_enum_list sde_hist_modes[] = { + {HIST_DISABLED, "hist_off"}, + {HIST_ENABLED, "hist_on"}, +}; + +/* + * LTM HISTOGRAM modes + * @LTM_HIST_DISABLED Histogram disabled + * @LTM_HIST_ENABLED Histogram enabled + */ +enum ltm_hist_modes { + LTM_HIST_DISABLED, + LTM_HIST_ENABLED +}; + +/** + * struct drm_prop_enum_list - drm structure for creating enum property and + * enumerating values + */ +static const struct drm_prop_enum_list sde_ltm_hist_modes[] = { + {LTM_HIST_DISABLED, "ltm_hist_off"}, + {LTM_HIST_ENABLED, "ltm_hist_on"}, +}; + +/** + * sde_cp_crtc_init(): Initialize color processing lists for a crtc. + * Should be called during crtc initialization. + * @crtc: Pointer to sde_crtc. + */ +void sde_cp_crtc_init(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_install_properties(): Installs the color processing + * properties for a crtc. + * Should be called during crtc initialization. + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_install_properties(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_destroy_properties: Destroys color processing + * properties for a crtc. + * should be called during crtc de-initialization. + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_set_property: Set a color processing property + * for a crtc. + * Should be during atomic set property. + * @crtc: Pointer to crtc. + * @property: Property that needs to enabled/disabled. + * @val: Value of property. + */ +int sde_cp_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, uint64_t val); + +/** + * sde_cp_crtc_apply_properties: Enable/disable properties + * for a crtc. + * Should be called during atomic commit call. + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_apply_properties(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_get_property: Get value of color processing property + * for a crtc. + * Should be during atomic get property. + * @crtc: Pointer to crtc. + * @property: Property that needs to enabled/disabled. + * @val: Value of property. + * + */ +int sde_cp_crtc_get_property(struct drm_crtc *crtc, + struct drm_property *property, uint64_t *val); + +/** + * sde_cp_crtc_suspend: Suspend the crtc features + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_suspend(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_resume: Resume the crtc features + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_resume(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_clear: Clear the active list and dirty list of crtc features + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_clear(struct drm_crtc *crtc); + +/** + * sde_cp_ad_interrupt: Api to enable/disable ad interrupt + * @crtc: Pointer to crtc. + * @en: Variable to enable/disable interrupt. + * @irq: Pointer to irq callback + */ +int sde_cp_ad_interrupt(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *irq); + +/** + * sde_cp_crtc_pre_ipc: Handle color processing features + * before entering IPC + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_pre_ipc(struct drm_crtc *crtc); + +/** + * sde_cp_crtc_post_ipc: Handle color processing features + * after exiting IPC + * @crtc: Pointer to crtc. + */ +void sde_cp_crtc_post_ipc(struct drm_crtc *crtc); + +/** + * sde_cp_hist_interrupt: Api to enable/disable histogram interrupt + * @crtc: Pointer to crtc. + * @en: Variable to enable/disable interrupt. + * @irq: Pointer to irq callback + */ +int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *hist_irq); + +/** + * sde_cp_ltm_hist_interrupt: API to enable/disable LTM hist interrupt + * @crtc: Pointer to crtc. + * @en: Variable to enable/disable interrupt. + * @irq: Pointer to irq callback + */ +int sde_cp_ltm_hist_interrupt(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *hist_irq); + +/** + * sde_cp_ltm_wb_pb_interrupt: API to enable/disable LTM wb_pb interrupt + * @crtc: Pointer to crtc. + * @en: Variable to enable/disable interrupt. + * @irq: Pointer to irq callback + */ +int sde_cp_ltm_wb_pb_interrupt(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *hist_irq); + +/** + * sde_cp_ltm_off_event_handler: API to enable/disable LTM off notification + * @crtc: Pointer to crtc. + * @en: Variable to enable/disable notification. + * @irq: Pointer to irq callback + */ +int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en, + struct sde_irq_callback *hist_irq); + +/** + * sde_cp_mode_switch_prop_dirty: API marks mode dependent features as dirty + * @crtc_drm: Pointer to crtc. + */ +void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm); +#endif /*_SDE_COLOR_PROCESSING_H */ diff --git a/techpack/display/msm/sde/sde_connector.c b/techpack/display/msm/sde/sde_connector.c new file mode 100644 index 0000000000000000000000000000000000000000..59dd523a2841b42c7290299e3fceab4dcae98437 --- /dev/null +++ b/techpack/display/msm/sde/sde_connector.c @@ -0,0 +1,3067 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include "msm_drv.h" +#include "sde_dbg.h" + +#include "sde_kms.h" +#include "sde_connector.h" +#include "sde_encoder.h" +#include <linux/backlight.h> +#include <linux/string.h> +#include "dsi_drm.h" +#include "dsi_display.h" +#include "sde_crtc.h" +#include "sde_rm.h" +#include "sde_trace.h" + +#define BL_NODE_NAME_SIZE 32 +#define HDR10_PLUS_VSIF_TYPE_CODE 0x81 + +/* Autorefresh will occur after FRAME_CNT frames. Large values are unlikely */ +#define AUTOREFRESH_MAX_FRAME_CNT 6 + +#define SDE_DEBUG_CONN(c, fmt, ...) SDE_DEBUG("conn%d " fmt,\ + (c) ? (c)->base.base.id : -1, ##__VA_ARGS__) + +#define SDE_ERROR_CONN(c, fmt, ...) SDE_ERROR("conn%d " fmt,\ + (c) ? (c)->base.base.id : -1, ##__VA_ARGS__) +static u32 dither_matrix[DITHER_MATRIX_SZ] = { + 15, 7, 13, 5, 3, 11, 1, 9, 12, 4, 14, 6, 0, 8, 2, 10 +}; + +static const struct drm_prop_enum_list e_topology_name[] = { + {SDE_RM_TOPOLOGY_NONE, "sde_none"}, + {SDE_RM_TOPOLOGY_SINGLEPIPE, "sde_singlepipe"}, + {SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, "sde_singlepipe_dsc"}, + {SDE_RM_TOPOLOGY_DUALPIPE, "sde_dualpipe"}, + {SDE_RM_TOPOLOGY_DUALPIPE_DSC, "sde_dualpipe_dsc"}, + {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, "sde_dualpipemerge"}, + {SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, "sde_dualpipemerge_dsc"}, + {SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, "sde_dualpipe_dscmerge"}, + {SDE_RM_TOPOLOGY_PPSPLIT, "sde_ppsplit"}, +}; +static const struct drm_prop_enum_list e_topology_control[] = { + {SDE_RM_TOPCTL_RESERVE_LOCK, "reserve_lock"}, + {SDE_RM_TOPCTL_RESERVE_CLEAR, "reserve_clear"}, + {SDE_RM_TOPCTL_DSPP, "dspp"}, + {SDE_RM_TOPCTL_DS, "ds"}, +}; +static const struct drm_prop_enum_list e_power_mode[] = { + {SDE_MODE_DPMS_ON, "ON"}, + {SDE_MODE_DPMS_LP1, "LP1"}, + {SDE_MODE_DPMS_LP2, "LP2"}, + {SDE_MODE_DPMS_OFF, "OFF"}, +}; +static const struct drm_prop_enum_list e_qsync_mode[] = { + {SDE_RM_QSYNC_DISABLED, "none"}, + {SDE_RM_QSYNC_CONTINUOUS_MODE, "continuous"}, + {SDE_RM_QSYNC_ONE_SHOT_MODE, "one_shot"}, +}; +static const struct drm_prop_enum_list e_frame_trigger_mode[] = { + {FRAME_DONE_WAIT_DEFAULT, "default"}, + {FRAME_DONE_WAIT_SERIALIZE, "serialize_frame_trigger"}, + {FRAME_DONE_WAIT_POSTED_START, "posted_start"}, +}; + +static int sde_backlight_device_update_status(struct backlight_device *bd) +{ + int brightness; + struct dsi_display *display; + struct sde_connector *c_conn; + int bl_lvl; + struct drm_event event; + int rc = 0; + + brightness = bd->props.brightness; + + if ((bd->props.power != FB_BLANK_UNBLANK) || + (bd->props.state & BL_CORE_FBBLANK) || + (bd->props.state & BL_CORE_SUSPENDED)) + brightness = 0; + + c_conn = bl_get_data(bd); + display = (struct dsi_display *) c_conn->display; + if (brightness > display->panel->bl_config.bl_max_level) + brightness = display->panel->bl_config.bl_max_level; + + /* map UI brightness into driver backlight level with rounding */ + bl_lvl = mult_frac(brightness, display->panel->bl_config.bl_max_level, + display->panel->bl_config.brightness_max_level); + + if (!bl_lvl && brightness) + bl_lvl = 1; + + if (!c_conn->allow_bl_update) { + c_conn->unset_bl_level = bl_lvl; + return 0; + } + + if (c_conn->ops.set_backlight) { + /* skip notifying user space if bl is 0 */ + if (brightness != 0) { + event.type = DRM_EVENT_SYS_BACKLIGHT; + event.length = sizeof(u32); + msm_mode_object_event_notify(&c_conn->base.base, + c_conn->base.dev, &event, (u8 *)&brightness); + } + rc = c_conn->ops.set_backlight(&c_conn->base, + c_conn->display, bl_lvl); + c_conn->unset_bl_level = 0; + } + + return rc; +} + +static int sde_backlight_device_get_brightness(struct backlight_device *bd) +{ + return 0; +} + +static const struct backlight_ops sde_backlight_device_ops = { + .update_status = sde_backlight_device_update_status, + .get_brightness = sde_backlight_device_get_brightness, +}; + +static int sde_backlight_setup(struct sde_connector *c_conn, + struct drm_device *dev) +{ + struct backlight_properties props; + struct dsi_display *display; + struct dsi_backlight_config *bl_config; + static int display_count; + char bl_node_name[BL_NODE_NAME_SIZE]; + + if (!c_conn || !dev || !dev->dev) { + SDE_ERROR("invalid param\n"); + return -EINVAL; + } else if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) { + return 0; + } + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.power = FB_BLANK_UNBLANK; + + display = (struct dsi_display *) c_conn->display; + bl_config = &display->panel->bl_config; + props.max_brightness = bl_config->brightness_max_level; + props.brightness = bl_config->bl_def_val; + SDE_ERROR("props.brightness = %d\n",props.brightness); + snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight", + display_count); + c_conn->bl_device = backlight_device_register(bl_node_name, dev->dev, + c_conn, &sde_backlight_device_ops, &props); + if (IS_ERR_OR_NULL(c_conn->bl_device)) { + SDE_ERROR("Failed to register backlight: %ld\n", + PTR_ERR(c_conn->bl_device)); + c_conn->bl_device = NULL; + return -ENODEV; + } + display_count++; + + return 0; +} + +int sde_connector_trigger_event(void *drm_connector, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3) +{ + struct sde_connector *c_conn; + unsigned long irq_flags; + int (*cb_func)(uint32_t event_idx, + uint32_t instance_idx, void *usr, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + void *usr; + int rc = 0; + + /* + * This function may potentially be called from an ISR context, so + * avoid excessive logging/etc. + */ + if (!drm_connector) + return -EINVAL; + else if (event_idx >= SDE_CONN_EVENT_COUNT) + return -EINVAL; + c_conn = to_sde_connector(drm_connector); + + spin_lock_irqsave(&c_conn->event_lock, irq_flags); + cb_func = c_conn->event_table[event_idx].cb_func; + usr = c_conn->event_table[event_idx].usr; + spin_unlock_irqrestore(&c_conn->event_lock, irq_flags); + + if (cb_func) + rc = cb_func(event_idx, instance_idx, usr, + data0, data1, data2, data3); + else + rc = -EAGAIN; + + return rc; +} + +int sde_connector_register_event(struct drm_connector *connector, + uint32_t event_idx, + int (*cb_func)(uint32_t event_idx, + uint32_t instance_idx, void *usr, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3), + void *usr) +{ + struct sde_connector *c_conn; + unsigned long irq_flags; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return -EINVAL; + } else if (event_idx >= SDE_CONN_EVENT_COUNT) { + SDE_ERROR("conn%d, invalid event %d\n", + connector->base.id, event_idx); + return -EINVAL; + } + c_conn = to_sde_connector(connector); + + spin_lock_irqsave(&c_conn->event_lock, irq_flags); + c_conn->event_table[event_idx].cb_func = cb_func; + c_conn->event_table[event_idx].usr = usr; + spin_unlock_irqrestore(&c_conn->event_lock, irq_flags); + + /* optionally notify display of event registration */ + if (c_conn->ops.enable_event && c_conn->display) + c_conn->ops.enable_event(connector, event_idx, + cb_func != NULL, c_conn->display); + return 0; +} + +void sde_connector_unregister_event(struct drm_connector *connector, + uint32_t event_idx) +{ + (void)sde_connector_register_event(connector, event_idx, 0, 0); +} + +static int _sde_connector_get_default_dither_cfg_v1( + struct sde_connector *c_conn, void *cfg) +{ + struct drm_msm_dither *dither_cfg = (struct drm_msm_dither *)cfg; + enum dsi_pixel_format dst_format = DSI_PIXEL_FORMAT_MAX; + + if (!c_conn || !cfg) { + SDE_ERROR("invalid argument(s), c_conn %pK, cfg %pK\n", + c_conn, cfg); + return -EINVAL; + } + + if (!c_conn->ops.get_dst_format) { + SDE_DEBUG("get_dst_format is unavailable\n"); + return 0; + } + + dst_format = c_conn->ops.get_dst_format(&c_conn->base, c_conn->display); + switch (dst_format) { + case DSI_PIXEL_FORMAT_RGB888: + dither_cfg->c0_bitdepth = 8; + dither_cfg->c1_bitdepth = 8; + dither_cfg->c2_bitdepth = 8; + dither_cfg->c3_bitdepth = 8; + break; + case DSI_PIXEL_FORMAT_RGB666: + case DSI_PIXEL_FORMAT_RGB666_LOOSE: + dither_cfg->c0_bitdepth = 6; + dither_cfg->c1_bitdepth = 6; + dither_cfg->c2_bitdepth = 6; + dither_cfg->c3_bitdepth = 6; + break; + default: + SDE_DEBUG("no default dither config for dst_format %d\n", + dst_format); + return -ENODATA; + } + + memcpy(&dither_cfg->matrix, dither_matrix, + sizeof(u32) * DITHER_MATRIX_SZ); + dither_cfg->temporal_en = 0; + return 0; +} + +static void _sde_connector_install_dither_property(struct drm_device *dev, + struct sde_kms *sde_kms, struct sde_connector *c_conn) +{ + char prop_name[DRM_PROP_NAME_LEN]; + struct sde_mdss_cfg *catalog = NULL; + struct drm_property_blob *blob_ptr; + void *cfg; + int ret = 0; + u32 version = 0, len = 0; + bool defalut_dither_needed = false; + + if (!dev || !sde_kms || !c_conn) { + SDE_ERROR("invld args (s), dev %pK, sde_kms %pK, c_conn %pK\n", + dev, sde_kms, c_conn); + return; + } + + catalog = sde_kms->catalog; + version = SDE_COLOR_PROCESS_MAJOR( + catalog->pingpong[0].sblk->dither.version); + snprintf(prop_name, ARRAY_SIZE(prop_name), "%s%d", + "SDE_PP_DITHER_V", version); + switch (version) { + case 1: + msm_property_install_blob(&c_conn->property_info, prop_name, + DRM_MODE_PROP_BLOB, + CONNECTOR_PROP_PP_DITHER); + len = sizeof(struct drm_msm_dither); + cfg = kzalloc(len, GFP_KERNEL); + if (!cfg) + return; + + ret = _sde_connector_get_default_dither_cfg_v1(c_conn, cfg); + if (!ret) + defalut_dither_needed = true; + break; + default: + SDE_ERROR("unsupported dither version %d\n", version); + return; + } + + if (defalut_dither_needed) { + blob_ptr = drm_property_create_blob(dev, len, cfg); + if (IS_ERR_OR_NULL(blob_ptr)) + goto exit; + c_conn->blob_dither = blob_ptr; + } +exit: + kfree(cfg); +} + +int sde_connector_get_dither_cfg(struct drm_connector *conn, + struct drm_connector_state *state, void **cfg, + size_t *len) +{ + struct sde_connector *c_conn = NULL; + struct sde_connector_state *c_state = NULL; + size_t dither_sz = 0; + u32 *p = (u32 *)cfg; + + if (!conn || !state || !p) + return -EINVAL; + + c_conn = to_sde_connector(conn); + c_state = to_sde_connector_state(state); + + /* try to get user config data first */ + *cfg = msm_property_get_blob(&c_conn->property_info, + &c_state->property_state, + &dither_sz, + CONNECTOR_PROP_PP_DITHER); + /* if user config data doesn't exist, use default dither blob */ + if (*cfg == NULL && c_conn->blob_dither) { + *cfg = c_conn->blob_dither->data; + dither_sz = c_conn->blob_dither->length; + } + *len = dither_sz; + return 0; +} + +static void sde_connector_get_avail_res_info(struct drm_connector *conn, + struct msm_resource_caps_info *avail_res) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct drm_encoder *drm_enc = NULL; + struct msm_display_info display_info; + + if (!conn || !conn->dev || !conn->dev->dev_private) + return; + + priv = conn->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + if (!sde_kms) + return; + + memset(&display_info, 0, sizeof(display_info)); + + if (conn->state && conn->state->best_encoder) + drm_enc = conn->state->best_encoder; + else + drm_enc = conn->encoder; + + sde_connector_get_info(conn, &display_info); + + sde_rm_get_resource_info(&sde_kms->rm, drm_enc, avail_res, + display_info.display_type); + + avail_res->max_mixer_width = sde_kms->catalog->max_mixer_width; +} + +int sde_connector_get_mode_info(struct drm_connector *conn, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info) +{ + struct sde_connector *sde_conn; + struct msm_resource_caps_info avail_res; + + memset(&avail_res, 0, sizeof(avail_res)); + + sde_conn = to_sde_connector(conn); + + if (!sde_conn) + return -EINVAL; + + sde_connector_get_avail_res_info(conn, &avail_res); + + return sde_conn->ops.get_mode_info(conn, drm_mode, + mode_info, sde_conn->display, &avail_res); +} + +int sde_connector_state_get_mode_info(struct drm_connector_state *conn_state, + struct msm_mode_info *mode_info) +{ + struct sde_connector_state *sde_conn_state = NULL; + + if (!conn_state || !mode_info) { + SDE_ERROR("Invalid arguments\n"); + return -EINVAL; + } + + sde_conn_state = to_sde_connector_state(conn_state); + memcpy(mode_info, &sde_conn_state->mode_info, + sizeof(sde_conn_state->mode_info)); + + return 0; +} + +static int sde_connector_handle_disp_recovery(uint32_t event_idx, + uint32_t instance_idx, void *usr, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3) +{ + struct sde_connector *c_conn = usr; + int rc = 0; + + if (!c_conn) + return -EINVAL; + + rc = sde_kms_handle_recovery(c_conn->encoder); + + return rc; +} + +int sde_connector_get_info(struct drm_connector *connector, + struct msm_display_info *info) +{ + struct sde_connector *c_conn; + + if (!connector || !info) { + SDE_ERROR("invalid argument(s), conn %pK, info %pK\n", + connector, info); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + + if (!c_conn->display || !c_conn->ops.get_info) { + SDE_ERROR("display info not supported for %pK\n", + c_conn->display); + return -EINVAL; + } + + return c_conn->ops.get_info(&c_conn->base, info, c_conn->display); +} + +void sde_connector_schedule_status_work(struct drm_connector *connector, + bool en) +{ + struct sde_connector *c_conn; + struct msm_display_info info; + + c_conn = to_sde_connector(connector); + if (!c_conn) + return; + + /* Return if there is no change in ESD status check condition */ + if (en == c_conn->esd_status_check) + return; + + sde_connector_get_info(connector, &info); + if (c_conn->ops.check_status && + (info.capabilities & MSM_DISPLAY_ESD_ENABLED)) { + if (en) { + u32 interval; + + /* + * If debugfs property is not set then take + * default value + */ + interval = c_conn->esd_status_interval ? + c_conn->esd_status_interval : + STATUS_CHECK_INTERVAL_MS; + /* Schedule ESD status check */ + schedule_delayed_work(&c_conn->status_work, + msecs_to_jiffies(interval)); + c_conn->esd_status_check = true; + } else { + /* Cancel any pending ESD status check */ + cancel_delayed_work_sync(&c_conn->status_work); + c_conn->esd_status_check = false; + } + } +} + +static int _sde_connector_update_power_locked(struct sde_connector *c_conn) +{ + struct drm_connector *connector; + void *display; + int (*set_power)(struct drm_connector *conn, int status, void *disp); + int mode, rc = 0; + + if (!c_conn) + return -EINVAL; + connector = &c_conn->base; + + switch (c_conn->dpms_mode) { + case DRM_MODE_DPMS_ON: + mode = c_conn->lp_mode; + break; + case DRM_MODE_DPMS_STANDBY: + mode = SDE_MODE_DPMS_STANDBY; + break; + case DRM_MODE_DPMS_SUSPEND: + mode = SDE_MODE_DPMS_SUSPEND; + break; + case DRM_MODE_DPMS_OFF: + mode = SDE_MODE_DPMS_OFF; + break; + default: + mode = c_conn->lp_mode; + SDE_ERROR("conn %d dpms set to unrecognized mode %d\n", + connector->base.id, mode); + break; + } + + SDE_EVT32(connector->base.id, c_conn->dpms_mode, c_conn->lp_mode, mode); + SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id, + c_conn->dpms_mode, c_conn->lp_mode, mode); + + if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) { + display = c_conn->display; + set_power = c_conn->ops.set_power; + + mutex_unlock(&c_conn->lock); + rc = set_power(connector, mode, display); + mutex_lock(&c_conn->lock); + } + c_conn->last_panel_power_mode = mode; + + mutex_unlock(&c_conn->lock); + if (mode != SDE_MODE_DPMS_ON) + sde_connector_schedule_status_work(connector, false); + else + sde_connector_schedule_status_work(connector, true); + mutex_lock(&c_conn->lock); + + return rc; +} + +static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) +{ + struct dsi_display *dsi_display; + struct dsi_backlight_config *bl_config; + int rc = 0; + + if (!c_conn) { + SDE_ERROR("Invalid params sde_connector null\n"); + return -EINVAL; + } + + dsi_display = c_conn->display; + if (!dsi_display || !dsi_display->panel) { + SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n", + dsi_display, + ((dsi_display) ? dsi_display->panel : NULL)); + return -EINVAL; + } + + bl_config = &dsi_display->panel->bl_config; + + if (!c_conn->allow_bl_update) { + c_conn->unset_bl_level = bl_config->bl_level; + return 0; + } + + if (c_conn->unset_bl_level) + bl_config->bl_level = c_conn->unset_bl_level; + + bl_config->bl_scale = c_conn->bl_scale > MAX_BL_SCALE_LEVEL ? + MAX_BL_SCALE_LEVEL : c_conn->bl_scale; + bl_config->bl_scale_sv = c_conn->bl_scale_sv > MAX_SV_BL_SCALE_LEVEL ? + MAX_SV_BL_SCALE_LEVEL : c_conn->bl_scale_sv; + + SDE_DEBUG("bl_scale = %u, bl_scale_sv = %u, bl_level = %u\n", + bl_config->bl_scale, bl_config->bl_scale_sv, + bl_config->bl_level); + rc = c_conn->ops.set_backlight(&c_conn->base, + dsi_display, bl_config->bl_level); + c_conn->unset_bl_level = 0; + + return rc; +} + +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint +extern bool sde_crtc_get_fingerprint_mode(struct drm_crtc_state *crtc_state); +extern bool sde_crtc_get_fingerprint_pressed(struct drm_crtc_state *crtc_state); +extern int dsi_display_set_hbm_mode(struct drm_connector *connector, int level); +/* +static int dsi_panel_tx_cmd_set_op(struct dsi_panel *panel, + enum dsi_cmd_set_type type) +{ + int rc = 0, i = 0; + ssize_t len; + struct dsi_cmd_desc *cmds; + u32 count; + enum dsi_cmd_set_state state; + struct dsi_display_mode *mode; + const struct mipi_dsi_host_ops *ops = panel->host->ops; + + if (!panel || !panel->cur_mode) + return -EINVAL; + +// if (panel->type == EXT_BRIDGE) +// return 0; + + mode = panel->cur_mode; + + cmds = mode->priv_info->cmd_sets[type].cmds; + count = mode->priv_info->cmd_sets[type].count; + state = mode->priv_info->cmd_sets[type].state; + + if (count == 0) { + pr_debug("[%s] No commands to be sent for state(%d)\n", + panel->name, type); + goto error; + } + + for (i = 0; i < count; i++) { + if (state == DSI_CMD_SET_STATE_LP) + cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM; + + if (cmds->last_command) + cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND; + + len = ops->transfer(panel->host, &cmds->msg); + if (len < 0) { + rc = len; + pr_err("failed to set cmds(%d), rc=%d\n", type, rc); + goto error; + } + if (cmds->post_wait_ms) + usleep_range(cmds->post_wait_ms*1000, + ((cmds->post_wait_ms*1000)+10)); + cmds++; + } +error: + return rc; +} +*/ +int aod_layer_hide = 0; +extern bool HBM_flag ; +extern int oneplus_dim_status; +extern int oneplus_onscreenfp_status; +extern bool aod_fod_flag; +extern bool real_aod_mode; +extern bool aod_complete; +extern bool finger_type; + +extern int op_dimlayer_bl; +extern int op_dimlayer_bl_enabled; + +int sde_connector_update_backlight(struct drm_connector *connector) +{ + if (op_dimlayer_bl != op_dimlayer_bl_enabled) { + struct sde_connector *c_conn = to_sde_connector(connector); + if (!c_conn) { + SDE_ERROR("Invalid params sde_connector null\n"); + return -EINVAL; + } + op_dimlayer_bl_enabled = op_dimlayer_bl; + _sde_connector_update_bl_scale(c_conn); + } + + return 0; +} +extern int dsi_panel_tx_cmd_set(struct dsi_panel *panel, + enum dsi_cmd_set_type type); +static int _sde_connector_update_hbm(struct sde_connector *c_conn) +{ + struct drm_connector *connector = &c_conn->base; + struct dsi_display *dsi_display; + struct sde_connector_state *c_state; + int rc = 0; + int fingerprint_mode; + + if (!c_conn) { + SDE_ERROR("Invalid params sde_connector null\n"); + return -EINVAL; + } + + if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) + return 0; + + c_state = to_sde_connector_state(connector->state); + + dsi_display = c_conn->display; + if (!dsi_display || !dsi_display->panel) { + SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n", + dsi_display, + ((dsi_display) ? dsi_display->panel : NULL)); + return -EINVAL; + } + + if (!c_conn->encoder || !c_conn->encoder->crtc || + !c_conn->encoder->crtc->state) { + return 0; + } + if (!finger_type) { + if (dsi_display->panel->aod_status==1) { + if (real_aod_mode && !aod_complete) { + pr_err("aod not complete\n"); + return 0; + } + if (!(sde_crtc_get_fingerprint_mode(c_conn->encoder->crtc->state))) + fingerprint_mode = false; + else { + fingerprint_mode = sde_crtc_get_fingerprint_mode(c_conn->encoder->crtc->state); + } + } else { + if (!(sde_crtc_get_fingerprint_mode(c_conn->encoder->crtc->state))) + fingerprint_mode = false; + else if (oneplus_dim_status == 1) + fingerprint_mode = !!oneplus_dim_status; + else + fingerprint_mode = sde_crtc_get_fingerprint_mode(c_conn->encoder->crtc->state); + } + } else { + if (dsi_display->panel->aod_status==1) { + if (oneplus_dim_status==5) + fingerprint_mode = false; + else if (oneplus_dim_status==2) + fingerprint_mode = !!oneplus_dim_status; + } else { + return 0; + } + } + + if (fingerprint_mode != dsi_display->panel->is_hbm_enabled) { + //struct drm_encoder *drm_enc = c_conn->encoder; + dsi_display->panel->is_hbm_enabled = fingerprint_mode; + if (fingerprint_mode) { + SDE_ATRACE_BEGIN("set_hbm_on"); + HBM_flag=true; + mutex_lock(&dsi_display->panel->panel_lock); + + if (dsi_display->panel->aod_status==1 && !finger_type) { + if (dsi_display->panel->aod_mode == 2) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_AOD_OFF_HBM_ON_SETTING); + pr_err("Send DSI_CMD_AOD_OFF_HBM_ON_SETTING cmds\n"); + } else { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_REAL_AOD_OFF_HBM_ON_SETTING); + pr_err("Send DSI_CMD_REAL_AOD_OFF_HBM_ON_SETTING cmds\n"); + } + aod_fod_flag = true; + } + else if (dsi_display->panel->aod_status == 1 && finger_type) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_AOD_OFF_NEW); + pr_err("qdt aod off\n"); + } + else { + //sde_encoder_poll_line_counts(drm_enc); + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_HBM_ON_5); + pr_err("Send DSI_CMD_SET_HBM_ON_5 cmds\n"); + } + SDE_ATRACE_END("set_hbm_on"); + mutex_unlock(&dsi_display->panel->panel_lock); + if (rc) { + pr_err("failed to send DSI_GAMMA_CMD_SET_HBM_ON cmds, rc=%d\n", rc); + return rc; + } + } + else { + SDE_ATRACE_BEGIN("set_hbm_off"); + HBM_flag = false; + //_sde_connector_update_bl_scale(c_conn); + mutex_lock(&dsi_display->panel->panel_lock); + if (dsi_display->panel->aod_status == 1 && !finger_type) { + if(oneplus_dim_status == 5){ + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_HBM_OFF); + pr_err("Send DSI_CMD_SET_HBM_OFF cmds\n"); + aod_fod_flag = true; + dsi_display->panel->aod_status = 0; + oneplus_dim_status = 0; + aod_layer_hide = 1; + } + else { + if (oneplus_onscreenfp_status == 4) { + if (dsi_display->panel->aod_mode == 5 || dsi_display->panel->aod_mode == 4) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_AOD_ON_5); + pr_err("Send DSI_CMD_SET_AOD_ON_5 cmds\n"); + } else if (dsi_display->panel->aod_mode == 1) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_AOD_ON_1); + pr_err("Send DSI_CMD_SET_AOD_ON_1 cmds\n"); + } else if (dsi_display->panel->aod_mode == 3) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_AOD_ON_3); + pr_err("Send DSI_CMD_SET_AOD_ON_3 cmds\n"); + } + } else if (oneplus_onscreenfp_status == 0) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_HBM_OFF_AOD_ON_SETTING ); + aod_layer_hide = 1; + pr_err("Send DSI_CMD_HBM_OFF_AOD_ON_SETTING cmds\n"); + } + } + } + else if (dsi_display->panel->aod_status == 1 && finger_type) { + if(oneplus_dim_status == 5) { + pr_err("qdt aod off dim 5\n"); + } else { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_AOD_ON_2); + pr_err("qdt aod on dim 0\n"); + } + } + else { + HBM_flag = false; + //sde_encoder_poll_line_counts(drm_enc); + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_HBM_OFF); + pr_err("Send DSI_CMD_SET_HBM_OFF cmds\n"); + } + SDE_ATRACE_END("set_hbm_off"); + mutex_unlock(&dsi_display->panel->panel_lock); + _sde_connector_update_bl_scale(c_conn); + if (rc) { + pr_err("failed to send DSI_CMD_HBM_OFF cmds, rc=%d\n", rc); + return rc; + } + } + } + return 0; +} + +void sde_connector_set_colorspace(struct sde_connector *c_conn) +{ + int rc = 0; + + if (c_conn->ops.set_colorspace) + rc = c_conn->ops.set_colorspace(&c_conn->base, + c_conn->display); + + if (rc) + SDE_ERROR_CONN(c_conn, "cannot apply new colorspace %d\n", rc); + +} + +void sde_connector_set_qsync_params(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + u32 qsync_propval = 0; + bool prop_dirty; + + if (!connector) + return; + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + c_conn->qsync_updated = false; + + prop_dirty = msm_property_is_dirty(&c_conn->property_info, + &c_state->property_state, + CONNECTOR_PROP_QSYNC_MODE); + if (prop_dirty) { + qsync_propval = sde_connector_get_property(c_conn->base.state, + CONNECTOR_PROP_QSYNC_MODE); + if (qsync_propval != c_conn->qsync_mode) { + SDE_DEBUG("updated qsync mode %d -> %d\n", + c_conn->qsync_mode, qsync_propval); + c_conn->qsync_updated = true; + c_conn->qsync_mode = qsync_propval; + } + } +} + +void sde_connector_complete_qsync_commit(struct drm_connector *conn, + struct msm_display_conn_params *params) +{ + struct sde_connector *c_conn; + + if (!conn || !params) { + SDE_ERROR("invalid params\n"); + return; + } + + c_conn = to_sde_connector(conn); + + if (c_conn && c_conn->qsync_updated && + (c_conn->qsync_mode == SDE_RM_QSYNC_ONE_SHOT_MODE)) { + /* Reset qsync states if mode is one shot */ + params->qsync_mode = c_conn->qsync_mode = 0; + params->qsync_update = true; + SDE_EVT32(conn->base.id, c_conn->qsync_mode); + } +} + +static int _sde_connector_update_hdr_metadata(struct sde_connector *c_conn, + struct sde_connector_state *c_state) +{ + int rc = 0; + + if (c_conn->ops.config_hdr) + rc = c_conn->ops.config_hdr(&c_conn->base, c_conn->display, + c_state); + + if (rc) + SDE_ERROR_CONN(c_conn, "cannot apply hdr metadata %d\n", rc); + + SDE_DEBUG_CONN(c_conn, "updated hdr metadata: %d\n", rc); + return rc; +} + +static int _sde_connector_update_dirty_properties( + struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + int idx; + + if (!connector) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + + mutex_lock(&c_conn->property_info.property_lock); + while ((idx = msm_property_pop_dirty(&c_conn->property_info, + &c_state->property_state)) >= 0) { + switch (idx) { + case CONNECTOR_PROP_LP: + mutex_lock(&c_conn->lock); + c_conn->lp_mode = sde_connector_get_property( + connector->state, CONNECTOR_PROP_LP); + _sde_connector_update_power_locked(c_conn); + mutex_unlock(&c_conn->lock); + break; + case CONNECTOR_PROP_BL_SCALE: + case CONNECTOR_PROP_SV_BL_SCALE: + // _sde_connector_update_bl_scale(c_conn); + break; + case CONNECTOR_PROP_HDR_METADATA: + _sde_connector_update_hdr_metadata(c_conn, c_state); + break; + default: + /* nothing to do for most properties */ + break; + } + } + mutex_unlock(&c_conn->property_info.property_lock); + + /* if colorspace needs to be updated do it first */ + if (c_conn->colorspace_updated) { + c_conn->colorspace_updated = false; + sde_connector_set_colorspace(c_conn); + } + + /* + * Special handling for postproc properties and + * for updating backlight if any unset backlight level is present + */ + if (c_conn->bl_scale_dirty || c_conn->unset_bl_level) { + _sde_connector_update_bl_scale(c_conn); + c_conn->bl_scale_dirty = false; + } + + return 0; +} + +struct sde_connector_dyn_hdr_metadata *sde_connector_get_dyn_hdr_meta( + struct drm_connector *connector) +{ + struct sde_connector_state *c_state; + + if (!connector) + return NULL; + + c_state = to_sde_connector_state(connector->state); + return &c_state->dyn_hdr_meta; +} + +int sde_connector_pre_kickoff(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct msm_display_kickoff_params params; + struct dsi_display *display; + int rc; + + if (!connector) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + if (!c_conn->display) { + SDE_ERROR("invalid connector display\n"); + return -EINVAL; + } + + /* + * During pre kickoff DCS commands have to have an + * asynchronous wait to avoid an unnecessary stall + * in pre-kickoff. This flag must be reset at the + * end of display pre-kickoff. + */ + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) { + display = (struct dsi_display *)c_conn->display; + display->queue_cmd_waits = true; + } + + rc = _sde_connector_update_dirty_properties(connector); +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint + rc = _sde_connector_update_hbm(c_conn); + if (rc) { + SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR); + goto end; + } + + if (!c_conn->ops.pre_kickoff) + return 0; + + params.rois = &c_state->rois; + params.hdr_meta = &c_state->hdr_meta; + + SDE_EVT32_VERBOSE(connector->base.id); + + rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms); + + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) + display->queue_cmd_waits = false; +end: + return rc; +} + +int sde_connector_prepare_commit(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct msm_display_conn_params params; + int rc; + + if (!connector) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector->state); + if (!c_conn->display) { + SDE_ERROR("invalid connector display\n"); + return -EINVAL; + } + + if (!c_conn->ops.prepare_commit) + return 0; + + memset(¶ms, 0, sizeof(params)); + + if (c_conn->qsync_updated) { + params.qsync_mode = c_conn->qsync_mode; + params.qsync_update = true; + } + + rc = c_conn->ops.prepare_commit(c_conn->display, ¶ms); + + SDE_EVT32(connector->base.id, params.qsync_mode, + params.qsync_update, rc); + + return rc; +} + +void sde_connector_helper_bridge_disable(struct drm_connector *connector) +{ + int rc; + struct sde_connector *c_conn = NULL; + struct dsi_display *display; + bool poms_pending = false; + + if (!connector) + return; + + c_conn = to_sde_connector(connector); + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) { + display = (struct dsi_display *) c_conn->display; + poms_pending = display->poms_pending; + } + + if (!poms_pending) { + rc = _sde_connector_update_dirty_properties(connector); + if (rc) { + SDE_ERROR("conn %d final pre kickoff failed %d\n", + connector->base.id, rc); + SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR); + } + } + /* Disable ESD thread */ + sde_connector_schedule_status_work(connector, false); + + if (c_conn->bl_device) { + c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; + c_conn->bl_device->props.state |= BL_CORE_FBBLANK; + backlight_update_status(c_conn->bl_device); + } + + c_conn->allow_bl_update = false; +} + +void sde_connector_helper_bridge_enable(struct drm_connector *connector) +{ + struct sde_connector *c_conn = NULL; + struct dsi_display *display; + + if (!connector) + return; + + c_conn = to_sde_connector(connector); + display = (struct dsi_display *) c_conn->display; + + /* + * Special handling for some panels which need atleast + * one frame to be transferred to GRAM before enabling backlight. + * So delay backlight update to these panels until the + * first frame commit is received from the HW. + */ + if (display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME) + sde_encoder_wait_for_event(c_conn->encoder, + MSM_ENC_TX_COMPLETE); + c_conn->allow_bl_update = true; + + if (c_conn->bl_device) { + c_conn->bl_device->props.power = FB_BLANK_UNBLANK; + c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK; + backlight_update_status(c_conn->bl_device); + } + c_conn->panel_dead = false; +} + +int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable) +{ + struct sde_connector *c_conn; + struct dsi_display *display; + u32 state = enable ? DSI_CLK_ON : DSI_CLK_OFF; + int rc = 0; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + display = (struct dsi_display *) c_conn->display; + + if (display && c_conn->ops.clk_ctrl) + rc = c_conn->ops.clk_ctrl(display->mdp_clk_handle, + DSI_ALL_CLKS, state); + + return rc; +} + +void sde_connector_destroy(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return; + } + + c_conn = to_sde_connector(connector); + + /* cancel if any pending esd work */ + sde_connector_schedule_status_work(connector, false); + + if (c_conn->ops.pre_destroy) + c_conn->ops.pre_destroy(connector, c_conn->display); + + if (c_conn->blob_caps) + drm_property_blob_put(c_conn->blob_caps); + if (c_conn->blob_hdr) + drm_property_blob_put(c_conn->blob_hdr); + if (c_conn->blob_dither) + drm_property_blob_put(c_conn->blob_dither); + if (c_conn->blob_mode_info) + drm_property_blob_put(c_conn->blob_mode_info); + if (c_conn->blob_ext_hdr) + drm_property_blob_put(c_conn->blob_ext_hdr); + + if (c_conn->bl_device) + backlight_device_unregister(c_conn->bl_device); + drm_connector_unregister(connector); + mutex_destroy(&c_conn->lock); + sde_fence_deinit(c_conn->retire_fence); + drm_connector_cleanup(connector); + msm_property_destroy(&c_conn->property_info); + kfree(c_conn); +} + +/** + * _sde_connector_destroy_fb - clean up connector state's out_fb buffer + * @c_conn: Pointer to sde connector structure + * @c_state: Pointer to sde connector state structure + */ +static void _sde_connector_destroy_fb(struct sde_connector *c_conn, + struct sde_connector_state *c_state) +{ + if (!c_state || !c_state->out_fb) { + SDE_ERROR("invalid state %pK\n", c_state); + return; + } + + drm_framebuffer_put(c_state->out_fb); + c_state->out_fb = NULL; + + if (c_conn) + c_state->property_values[CONNECTOR_PROP_OUT_FB].value = + msm_property_get_default(&c_conn->property_info, + CONNECTOR_PROP_OUT_FB); + else + c_state->property_values[CONNECTOR_PROP_OUT_FB].value = ~0; +} + +static void sde_connector_atomic_destroy_state(struct drm_connector *connector, + struct drm_connector_state *state) +{ + struct sde_connector *c_conn = NULL; + struct sde_connector_state *c_state = NULL; + + if (!state) { + SDE_ERROR("invalid state\n"); + return; + } + + /* + * The base DRM framework currently always passes in a NULL + * connector pointer. This is not correct, but attempt to + * handle that case as much as possible. + */ + if (connector) + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(state); + + if (c_state->out_fb) + _sde_connector_destroy_fb(c_conn, c_state); + + __drm_atomic_helper_connector_destroy_state(&c_state->base); + + if (!c_conn) { + kfree(c_state); + } else { + /* destroy value helper */ + msm_property_destroy_state(&c_conn->property_info, c_state, + &c_state->property_state); + } +} + +static void sde_connector_atomic_reset(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return; + } + + c_conn = to_sde_connector(connector); + + if (connector->state && + !sde_crtc_is_reset_required(connector->state->crtc)) { + SDE_DEBUG_CONN(c_conn, "avoid reset for connector\n"); + return; + } + + if (connector->state) { + sde_connector_atomic_destroy_state(connector, connector->state); + connector->state = 0; + } + + c_state = msm_property_alloc_state(&c_conn->property_info); + if (!c_state) { + SDE_ERROR("state alloc failed\n"); + return; + } + + /* reset value helper, zero out state structure and reset properties */ + msm_property_reset_state(&c_conn->property_info, c_state, + &c_state->property_state, + c_state->property_values); + + __drm_atomic_helper_connector_reset(connector, &c_state->base); +} + +static struct drm_connector_state * +sde_connector_atomic_duplicate_state(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state, *c_oldstate; + + if (!connector || !connector->state) { + SDE_ERROR("invalid connector %pK\n", connector); + return NULL; + } + + c_conn = to_sde_connector(connector); + c_oldstate = to_sde_connector_state(connector->state); + c_state = msm_property_alloc_state(&c_conn->property_info); + if (!c_state) { + SDE_ERROR("state alloc failed\n"); + return NULL; + } + + /* duplicate value helper */ + msm_property_duplicate_state(&c_conn->property_info, + c_oldstate, c_state, + &c_state->property_state, c_state->property_values); + + __drm_atomic_helper_connector_duplicate_state(connector, + &c_state->base); + + /* additional handling for drm framebuffer objects */ + if (c_state->out_fb) + drm_framebuffer_get(c_state->out_fb); + + /* clear dynamic HDR metadata from prev state */ + if (c_state->dyn_hdr_meta.dynamic_hdr_update) { + c_state->dyn_hdr_meta.dynamic_hdr_update = false; + c_state->dyn_hdr_meta.dynamic_hdr_payload_size = 0; + } + + return &c_state->base; +} + +int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state) +{ + const struct msm_roi_alignment *align = NULL; + struct sde_connector *c_conn = NULL; + struct msm_mode_info mode_info; + struct sde_connector_state *c_state; + int i, w, h; + + if (!conn_state) + return -EINVAL; + + memset(&mode_info, 0, sizeof(mode_info)); + + c_state = to_sde_connector_state(conn_state); + c_conn = to_sde_connector(conn_state->connector); + + memcpy(&mode_info, &c_state->mode_info, sizeof(c_state->mode_info)); + + if (!mode_info.roi_caps.enabled) + return 0; + + if (c_state->rois.num_rects > mode_info.roi_caps.num_roi) { + SDE_ERROR_CONN(c_conn, "too many rects specified: %d > %d\n", + c_state->rois.num_rects, + mode_info.roi_caps.num_roi); + return -E2BIG; + } + + align = &mode_info.roi_caps.align; + for (i = 0; i < c_state->rois.num_rects; ++i) { + struct drm_clip_rect *roi_conn; + + roi_conn = &c_state->rois.roi[i]; + w = roi_conn->x2 - roi_conn->x1; + h = roi_conn->y2 - roi_conn->y1; + + SDE_EVT32_VERBOSE(DRMID(&c_conn->base), + roi_conn->x1, roi_conn->y1, + roi_conn->x2, roi_conn->y2); + + if (w <= 0 || h <= 0) { + SDE_ERROR_CONN(c_conn, "invalid conn roi w %d h %d\n", + w, h); + return -EINVAL; + } + + if (w < align->min_width || w % align->width_pix_align) { + SDE_ERROR_CONN(c_conn, + "invalid conn roi width %d min %d align %d\n", + w, align->min_width, + align->width_pix_align); + return -EINVAL; + } + + if (h < align->min_height || h % align->height_pix_align) { + SDE_ERROR_CONN(c_conn, + "invalid conn roi height %d min %d align %d\n", + h, align->min_height, + align->height_pix_align); + return -EINVAL; + } + + if (roi_conn->x1 % align->xstart_pix_align) { + SDE_ERROR_CONN(c_conn, + "invalid conn roi x1 %d align %d\n", + roi_conn->x1, align->xstart_pix_align); + return -EINVAL; + } + + if (roi_conn->y1 % align->ystart_pix_align) { + SDE_ERROR_CONN(c_conn, + "invalid conn roi y1 %d align %d\n", + roi_conn->y1, align->ystart_pix_align); + return -EINVAL; + } + } + + return 0; +} + +static int _sde_connector_set_roi_v1( + struct sde_connector *c_conn, + struct sde_connector_state *c_state, + void __user *usr_ptr) +{ + struct sde_drm_roi_v1 roi_v1; + int i; + + if (!c_conn || !c_state) { + SDE_ERROR("invalid args\n"); + return -EINVAL; + } + + memset(&c_state->rois, 0, sizeof(c_state->rois)); + + if (!usr_ptr) { + SDE_DEBUG_CONN(c_conn, "rois cleared\n"); + return 0; + } + + if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) { + SDE_ERROR_CONN(c_conn, "failed to copy roi_v1 data\n"); + return -EINVAL; + } + + SDE_DEBUG_CONN(c_conn, "num_rects %d\n", roi_v1.num_rects); + + if (roi_v1.num_rects == 0) { + SDE_DEBUG_CONN(c_conn, "rois cleared\n"); + return 0; + } + + if (roi_v1.num_rects > SDE_MAX_ROI_V1) { + SDE_ERROR_CONN(c_conn, "num roi rects more than supported: %d", + roi_v1.num_rects); + return -EINVAL; + } + + c_state->rois.num_rects = roi_v1.num_rects; + for (i = 0; i < roi_v1.num_rects; ++i) { + c_state->rois.roi[i] = roi_v1.roi[i]; + SDE_DEBUG_CONN(c_conn, "roi%d: roi (%d,%d) (%d,%d)\n", i, + c_state->rois.roi[i].x1, + c_state->rois.roi[i].y1, + c_state->rois.roi[i].x2, + c_state->rois.roi[i].y2); + } + + return 0; +} + +static int _sde_connector_set_ext_hdr_info( + struct sde_connector *c_conn, + struct sde_connector_state *c_state, + void __user *usr_ptr) +{ + int rc = 0; + struct drm_connector *connector; + struct drm_msm_ext_hdr_metadata *hdr_meta; + size_t payload_size = 0; + u8 *payload = NULL; + int i; + + if (!c_conn || !c_state) { + SDE_ERROR_CONN(c_conn, "invalid args\n"); + rc = -EINVAL; + goto end; + } + + connector = &c_conn->base; + + memset(&c_state->hdr_meta, 0, sizeof(c_state->hdr_meta)); + + if (!usr_ptr) { + SDE_DEBUG_CONN(c_conn, "hdr metadata cleared\n"); + goto end; + } + + if (!connector->hdr_supported) { + SDE_ERROR_CONN(c_conn, "sink doesn't support HDR\n"); + rc = -ENOTSUPP; + goto end; + } + + if (copy_from_user(&c_state->hdr_meta, + (void __user *)usr_ptr, + sizeof(*hdr_meta))) { + SDE_ERROR_CONN(c_conn, "failed to copy hdr metadata\n"); + rc = -EFAULT; + goto end; + } + + hdr_meta = &c_state->hdr_meta; + + /* dynamic metadata support */ + if (!hdr_meta->hdr_plus_payload_size || !hdr_meta->hdr_plus_payload) + goto skip_dhdr; + + if (!connector->hdr_plus_app_ver) { + SDE_ERROR_CONN(c_conn, "sink doesn't support dynamic HDR\n"); + rc = -ENOTSUPP; + goto end; + } + + payload_size = hdr_meta->hdr_plus_payload_size; + if (payload_size > sizeof(c_state->dyn_hdr_meta.dynamic_hdr_payload)) { + SDE_ERROR_CONN(c_conn, "payload size exceeds limit\n"); + rc = -EINVAL; + goto end; + } + + payload = c_state->dyn_hdr_meta.dynamic_hdr_payload; + if (copy_from_user(payload, + (void __user *)c_state->hdr_meta.hdr_plus_payload, + payload_size)) { + SDE_ERROR_CONN(c_conn, "failed to copy dhdr metadata\n"); + rc = -EFAULT; + goto end; + } + + /* verify 1st header byte, programmed in DP Infoframe SDP header */ + if (payload_size < 1 || (payload[0] != HDR10_PLUS_VSIF_TYPE_CODE)) { + SDE_ERROR_CONN(c_conn, "invalid payload detected, size: %zd\n", + payload_size); + rc = -EINVAL; + goto end; + } + + c_state->dyn_hdr_meta.dynamic_hdr_update = true; + +skip_dhdr: + c_state->dyn_hdr_meta.dynamic_hdr_payload_size = payload_size; + + SDE_DEBUG_CONN(c_conn, "hdr_state %d\n", hdr_meta->hdr_state); + SDE_DEBUG_CONN(c_conn, "hdr_supported %d\n", hdr_meta->hdr_supported); + SDE_DEBUG_CONN(c_conn, "eotf %d\n", hdr_meta->eotf); + SDE_DEBUG_CONN(c_conn, "white_point_x %d\n", hdr_meta->white_point_x); + SDE_DEBUG_CONN(c_conn, "white_point_y %d\n", hdr_meta->white_point_y); + SDE_DEBUG_CONN(c_conn, "max_luminance %d\n", hdr_meta->max_luminance); + SDE_DEBUG_CONN(c_conn, "max_content_light_level %d\n", + hdr_meta->max_content_light_level); + SDE_DEBUG_CONN(c_conn, "max_average_light_level %d\n", + hdr_meta->max_average_light_level); + + for (i = 0; i < HDR_PRIMARIES_COUNT; i++) { + SDE_DEBUG_CONN(c_conn, "display_primaries_x [%d]\n", + hdr_meta->display_primaries_x[i]); + SDE_DEBUG_CONN(c_conn, "display_primaries_y [%d]\n", + hdr_meta->display_primaries_y[i]); + } + SDE_DEBUG_CONN(c_conn, "hdr_plus payload%s updated, size %d\n", + c_state->dyn_hdr_meta.dynamic_hdr_update ? "" : " NOT", + c_state->dyn_hdr_meta.dynamic_hdr_payload_size); + +end: + return rc; +} + +static int sde_connector_atomic_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + int idx, rc; + uint64_t fence_user_fd; + uint64_t __user prev_user_fd; + + if (!connector || !state || !property) { + SDE_ERROR("invalid argument(s), conn %pK, state %pK, prp %pK\n", + connector, state, property); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(state); + + /* generic property handling */ + rc = msm_property_atomic_set(&c_conn->property_info, + &c_state->property_state, property, val); + if (rc) + goto end; + + /* connector-specific property handling */ + idx = msm_property_index(&c_conn->property_info, property); + switch (idx) { + case CONNECTOR_PROP_OUT_FB: + /* clear old fb, if present */ + if (c_state->out_fb) + _sde_connector_destroy_fb(c_conn, c_state); + + /* convert fb val to drm framebuffer and prepare it */ + c_state->out_fb = + drm_framebuffer_lookup(connector->dev, NULL, val); + if (!c_state->out_fb && val) { + SDE_ERROR("failed to look up fb %lld\n", val); + rc = -EFAULT; + } else if (!c_state->out_fb && !val) { + SDE_DEBUG("cleared fb_id\n"); + rc = 0; + } else { + msm_framebuffer_set_kmap(c_state->out_fb, + c_conn->fb_kmap); + } + break; + case CONNECTOR_PROP_RETIRE_FENCE: + if (!val) + goto end; + + rc = copy_from_user(&prev_user_fd, (void __user *)val, + sizeof(uint64_t)); + if (rc) { + SDE_ERROR("copy from user failed rc:%d\n", rc); + rc = -EFAULT; + goto end; + } + + /* + * client is expected to reset the property to -1 before + * requesting for the retire fence + */ + if (prev_user_fd == -1) { + /* + * update the offset to a timeline for + * commit completion + */ + rc = sde_fence_create(c_conn->retire_fence, + &fence_user_fd, 1); + if (rc) { + SDE_ERROR("fence create failed rc:%d\n", rc); + goto end; + } + + rc = copy_to_user((uint64_t __user *)(uintptr_t)val, + &fence_user_fd, sizeof(uint64_t)); + if (rc) { + SDE_ERROR("copy to user failed rc:%d\n", rc); + /* + * fence will be released with timeline + * update + */ + put_unused_fd(fence_user_fd); + rc = -EFAULT; + goto end; + } + } + break; + case CONNECTOR_PROP_ROI_V1: + rc = _sde_connector_set_roi_v1(c_conn, c_state, + (void *)(uintptr_t)val); + if (rc) + SDE_ERROR_CONN(c_conn, "invalid roi_v1, rc: %d\n", rc); + break; + /* CONNECTOR_PROP_BL_SCALE and CONNECTOR_PROP_SV_BL_SCALE are + * color-processing properties. These two properties require + * special handling since they don't quite fit the current standard + * atomic set property framework. + */ + case CONNECTOR_PROP_BL_SCALE: + // c_conn->bl_scale = val; + // c_conn->bl_scale_dirty = true; + break; + case CONNECTOR_PROP_SV_BL_SCALE: + // c_conn->bl_scale_sv = val; + // c_conn->bl_scale_dirty = true; + break; + case CONNECTOR_PROP_HDR_METADATA: + rc = _sde_connector_set_ext_hdr_info(c_conn, + c_state, (void *)(uintptr_t)val); + if (rc) + SDE_ERROR_CONN(c_conn, "cannot set hdr info %d\n", rc); + break; + case CONNECTOR_PROP_QSYNC_MODE: + msm_property_set_dirty(&c_conn->property_info, + &c_state->property_state, idx); + break; + default: + break; + } + + /* check for custom property handling */ + if (!rc && c_conn->ops.set_property) { + rc = c_conn->ops.set_property(connector, + state, + idx, + val, + c_conn->display); + + /* potentially clean up out_fb if rc != 0 */ + if ((idx == CONNECTOR_PROP_OUT_FB) && rc) + _sde_connector_destroy_fb(c_conn, c_state); + } +end: + return rc; +} + +static int sde_connector_atomic_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + int idx, rc = -EINVAL; + + if (!connector || !state) { + SDE_ERROR("invalid argument(s), conn %pK, state %pK\n", + connector, state); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(state); + + idx = msm_property_index(&c_conn->property_info, property); + if (idx == CONNECTOR_PROP_RETIRE_FENCE) { + *val = ~0; + rc = 0; + } else { + /* get cached property value */ + rc = msm_property_atomic_get(&c_conn->property_info, + &c_state->property_state, property, val); + } + + /* allow for custom override */ + if (c_conn->ops.get_property) + rc = c_conn->ops.get_property(connector, + (struct drm_connector_state *)state, + idx, + val, + c_conn->display); + return rc; +} + +void sde_conn_timeline_status(struct drm_connector *conn) +{ + struct sde_connector *c_conn; + + if (!conn) { + SDE_ERROR("invalid connector\n"); + return; + } + + c_conn = to_sde_connector(conn); + sde_fence_timeline_status(c_conn->retire_fence, &conn->base); +} + +void sde_connector_prepare_fence(struct drm_connector *connector) +{ + if (!connector) { + SDE_ERROR("invalid connector\n"); + return; + } + + sde_fence_prepare(to_sde_connector(connector)->retire_fence); +} + +void sde_connector_complete_commit(struct drm_connector *connector, + ktime_t ts, enum sde_fence_event fence_event) +{ + if (!connector) { + SDE_ERROR("invalid connector\n"); + return; + } + + /* signal connector's retire fence */ + sde_fence_signal(to_sde_connector(connector)->retire_fence, + ts, fence_event); +} + +void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) +{ + if (!connector) { + SDE_ERROR("invalid connector\n"); + return; + } + + /* signal connector's retire fence */ + sde_fence_signal(to_sde_connector(connector)->retire_fence, + ts, SDE_FENCE_RESET_TIMELINE); +} + +static void sde_connector_update_hdr_props(struct drm_connector *connector) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + struct drm_msm_ext_hdr_properties hdr = {0}; + + hdr.hdr_metadata_type_one = connector->hdr_metadata_type_one ? 1 : 0; + hdr.hdr_supported = connector->hdr_supported ? 1 : 0; + hdr.hdr_eotf = connector->hdr_eotf; + hdr.hdr_max_luminance = connector->hdr_max_luminance; + hdr.hdr_avg_luminance = connector->hdr_avg_luminance; + hdr.hdr_min_luminance = connector->hdr_min_luminance; + hdr.hdr_plus_supported = connector->hdr_plus_app_ver; + + msm_property_set_blob(&c_conn->property_info, &c_conn->blob_ext_hdr, + &hdr, sizeof(hdr), CONNECTOR_PROP_EXT_HDR_INFO); +} + +static void sde_connector_update_colorspace(struct drm_connector *connector) +{ + int ret; + + ret = msm_property_set_property( + sde_connector_get_propinfo(connector), + sde_connector_get_property_state(connector->state), + CONNECTOR_PROP_SUPPORTED_COLORSPACES, + connector->color_enc_fmt); + + if (ret) + SDE_ERROR("failed to set colorspace property for connector\n"); +} + +static enum drm_connector_status +sde_connector_detect(struct drm_connector *connector, bool force) +{ + enum drm_connector_status status = connector_status_unknown; + struct sde_connector *c_conn; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return status; + } + + c_conn = to_sde_connector(connector); + + if (c_conn->ops.detect) + status = c_conn->ops.detect(connector, + force, + c_conn->display); + + return status; +} + +int sde_connector_get_dpms(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + int rc; + + if (!connector) { + SDE_DEBUG("invalid connector\n"); + return DRM_MODE_DPMS_OFF; + } + + c_conn = to_sde_connector(connector); + + mutex_lock(&c_conn->lock); + rc = c_conn->dpms_mode; + mutex_unlock(&c_conn->lock); + + return rc; +} + +int sde_connector_set_property_for_commit(struct drm_connector *connector, + struct drm_atomic_state *atomic_state, + uint32_t property_idx, uint64_t value) +{ + struct drm_connector_state *state; + struct drm_property *property; + struct sde_connector *c_conn; + + if (!connector || !atomic_state) { + SDE_ERROR("invalid argument(s), conn %d, state %d\n", + connector != NULL, atomic_state != NULL); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + property = msm_property_index_to_drm_property( + &c_conn->property_info, property_idx); + if (!property) { + SDE_ERROR("invalid property index %d\n", property_idx); + return -EINVAL; + } + + state = drm_atomic_get_connector_state(atomic_state, connector); + if (IS_ERR_OR_NULL(state)) { + SDE_ERROR("failed to get conn %d state\n", + connector->base.id); + return -EINVAL; + } + + return sde_connector_atomic_set_property( + connector, state, property, value); +} + +int sde_connector_helper_reset_custom_properties( + struct drm_connector *connector, + struct drm_connector_state *connector_state) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + struct drm_property *drm_prop; + enum msm_mdp_conn_property prop_idx; + + if (!connector || !connector_state) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(connector_state); + + for (prop_idx = 0; prop_idx < CONNECTOR_PROP_COUNT; prop_idx++) { + uint64_t val = c_state->property_values[prop_idx].value; + uint64_t def; + int ret; + + drm_prop = msm_property_index_to_drm_property( + &c_conn->property_info, prop_idx); + if (!drm_prop) { + /* not all props will be installed, based on caps */ + SDE_DEBUG_CONN(c_conn, "invalid property index %d\n", + prop_idx); + continue; + } + + def = msm_property_get_default(&c_conn->property_info, + prop_idx); + if (val == def) + continue; + + SDE_DEBUG_CONN(c_conn, "set prop %s idx %d from %llu to %llu\n", + drm_prop->name, prop_idx, val, def); + + ret = sde_connector_atomic_set_property(connector, + connector_state, drm_prop, def); + if (ret) { + SDE_ERROR_CONN(c_conn, + "set property failed, idx %d ret %d\n", + prop_idx, ret); + continue; + } + } + + return 0; +} + +static int _sde_connector_lm_preference(struct sde_connector *sde_conn, + struct sde_kms *sde_kms, uint32_t disp_type) +{ + int ret = 0; + u32 num_lm = 0; + + if (!sde_conn || !sde_kms || !sde_conn->ops.get_default_lms) { + SDE_DEBUG("invalid input params"); + return -EINVAL; + } + + if (!disp_type || disp_type >= SDE_CONNECTOR_MAX) { + SDE_DEBUG("invalid display_type"); + return -EINVAL; + } + + ret = sde_conn->ops.get_default_lms(sde_conn->display, &num_lm); + if (ret || !num_lm) { + SDE_DEBUG("failed to get default lm count"); + return ret; + } + + if (num_lm > sde_kms->catalog->mixer_count) { + SDE_DEBUG( + "topology requesting more lms [%d] than hw exists [%d]", + num_lm, sde_kms->catalog->mixer_count); + return -EINVAL; + } + + sde_hw_mixer_set_preference(sde_kms->catalog, num_lm, disp_type); + + return ret; +} + +int sde_connector_get_panel_vfp(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct sde_connector *c_conn; + int vfp = -EINVAL; + + if (!connector || !mode) { + SDE_ERROR("invalid connector\n"); + return vfp; + } + c_conn = to_sde_connector(connector); + if (!c_conn->ops.get_panel_vfp) + return vfp; + + vfp = c_conn->ops.get_panel_vfp(c_conn->display, + mode->hdisplay, mode->vdisplay); + if (vfp <= 0) + SDE_ERROR("Failed get_panel_vfp %d\n", vfp); + + return vfp; +} + +static int _sde_debugfs_conn_cmd_tx_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->private_data = inode->i_private; + return nonseekable_open(inode, file); +} + +static ssize_t _sde_debugfs_conn_cmd_tx_sts_read(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct drm_connector *connector = file->private_data; + struct sde_connector *c_conn; + char buffer[MAX_CMD_PAYLOAD_SIZE]; + int blen = 0; + + if (*ppos) + return 0; + + if (!connector) { + SDE_ERROR("invalid argument, conn is NULL\n"); + return 0; + } + + c_conn = to_sde_connector(connector); + + mutex_lock(&c_conn->lock); + blen = snprintf(buffer, MAX_CMD_PAYLOAD_SIZE, + "last_cmd_tx_sts:0x%x", + c_conn->last_cmd_tx_sts); + mutex_unlock(&c_conn->lock); + + SDE_DEBUG("output: %s\n", buffer); + if (blen <= 0) { + SDE_ERROR("snprintf failed, blen %d\n", blen); + return 0; + } + + if (blen > count) + blen = count; + + blen = min_t(size_t, blen, MAX_CMD_PAYLOAD_SIZE); + if (copy_to_user(buf, buffer, blen)) { + SDE_ERROR("copy to user buffer failed\n"); + return -EFAULT; + } + + *ppos += blen; + return blen; +} + +static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file, + const char __user *p, size_t count, loff_t *ppos) +{ + struct drm_connector *connector = file->private_data; + struct sde_connector *c_conn; + char *input, *token, *input_copy, *input_dup = NULL; + const char *delim = " "; + u32 buf_size = 0; + char buffer[MAX_CMD_PAYLOAD_SIZE]; + int rc = 0, strtoint; + + if (*ppos || !connector) { + SDE_ERROR("invalid argument(s), conn %d\n", connector != NULL); + return 0; + } + + c_conn = to_sde_connector(connector); + + if (!c_conn->ops.cmd_transfer) { + SDE_ERROR("no cmd transfer support for connector name %s\n", + c_conn->name); + return 0; + } + + input = kmalloc(count + 1, GFP_KERNEL); + if (!input) + return -ENOMEM; + + if (copy_from_user(input, p, count)) { + SDE_ERROR("copy from user failed\n"); + rc = -EFAULT; + goto end; + } + input[count] = '\0'; + + SDE_INFO("Command requested for trasnfer to panel: %s\n", input); + + input_copy = kstrdup(input, GFP_KERNEL); + if (!input_copy) { + rc = -ENOMEM; + goto end; + } + + input_dup = input_copy; + token = strsep(&input_copy, delim); + while (token) { + rc = kstrtoint(token, 0, &strtoint); + if (rc) { + SDE_ERROR("input buffer conversion failed\n"); + goto end; + } + + if (buf_size >= MAX_CMD_PAYLOAD_SIZE) { + SDE_ERROR("buffer size exceeding the limit %d\n", + MAX_CMD_PAYLOAD_SIZE); + goto end; + } + buffer[buf_size++] = (strtoint & 0xff); + token = strsep(&input_copy, delim); + } + SDE_DEBUG("command packet size in bytes: %u\n", buf_size); + if (!buf_size) + goto end; + + mutex_lock(&c_conn->lock); + rc = c_conn->ops.cmd_transfer(&c_conn->base, c_conn->display, buffer, + buf_size); + c_conn->last_cmd_tx_sts = !rc ? true : false; + mutex_unlock(&c_conn->lock); + + rc = count; +end: + kfree(input_dup); + kfree(input); + return rc; +} + +static const struct file_operations conn_cmd_tx_fops = { + .open = _sde_debugfs_conn_cmd_tx_open, + .read = _sde_debugfs_conn_cmd_tx_sts_read, + .write = _sde_debugfs_conn_cmd_tx_write, +}; + +#ifdef CONFIG_DEBUG_FS +/** + * sde_connector_init_debugfs - initialize connector debugfs + * @connector: Pointer to drm connector + */ +static int sde_connector_init_debugfs(struct drm_connector *connector) +{ + struct sde_connector *sde_connector; + struct msm_display_info info; + + if (!connector || !connector->debugfs_entry) { + SDE_ERROR("invalid connector\n"); + return -EINVAL; + } + + sde_connector = to_sde_connector(connector); + + sde_connector_get_info(connector, &info); + if (sde_connector->ops.check_status && + (info.capabilities & MSM_DISPLAY_ESD_ENABLED)) { + debugfs_create_u32("esd_status_interval", 0600, + connector->debugfs_entry, + &sde_connector->esd_status_interval); + } + + if (!debugfs_create_bool("fb_kmap", 0600, connector->debugfs_entry, + &sde_connector->fb_kmap)) { + SDE_ERROR("failed to create connector fb_kmap\n"); + return -ENOMEM; + } + + if (sde_connector->ops.cmd_transfer) { + if (!debugfs_create_file("tx_cmd", 0600, + connector->debugfs_entry, + connector, &conn_cmd_tx_fops)) { + SDE_ERROR("failed to create connector cmd_tx\n"); + return -ENOMEM; + } + } + + return 0; +} +#else +static int sde_connector_init_debugfs(struct drm_connector *connector) +{ + return 0; +} +#endif + +static int sde_connector_late_register(struct drm_connector *connector) +{ + return sde_connector_init_debugfs(connector); +} + +static void sde_connector_early_unregister(struct drm_connector *connector) +{ + /* debugfs under connector->debugfs are deleted by drm_debugfs */ +} + +static int sde_connector_fill_modes(struct drm_connector *connector, + uint32_t max_width, uint32_t max_height) +{ + int rc, mode_count = 0; + struct sde_connector *sde_conn = NULL; + + sde_conn = to_sde_connector(connector); + if (!sde_conn) { + SDE_ERROR("invalid arguments\n"); + return 0; + } + + mode_count = drm_helper_probe_single_connector_modes(connector, + max_width, max_height); + + rc = sde_connector_set_blob_data(connector, + connector->state, + CONNECTOR_PROP_MODE_INFO); + if (rc) { + SDE_ERROR_CONN(sde_conn, + "failed to setup mode info prop, rc = %d\n", rc); + return 0; + } + + return mode_count; +} + +static const struct drm_connector_funcs sde_connector_ops = { + .reset = sde_connector_atomic_reset, + .detect = sde_connector_detect, + .destroy = sde_connector_destroy, + .fill_modes = sde_connector_fill_modes, + .atomic_duplicate_state = sde_connector_atomic_duplicate_state, + .atomic_destroy_state = sde_connector_atomic_destroy_state, + .atomic_set_property = sde_connector_atomic_set_property, + .atomic_get_property = sde_connector_atomic_get_property, + .late_register = sde_connector_late_register, + .early_unregister = sde_connector_early_unregister, +}; + +static int sde_connector_get_modes(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + struct msm_resource_caps_info avail_res; + int mode_count = 0; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return 0; + } + + c_conn = to_sde_connector(connector); + if (!c_conn->ops.get_modes) { + SDE_DEBUG("missing get_modes callback\n"); + return 0; + } + + memset(&avail_res, 0, sizeof(avail_res)); + sde_connector_get_avail_res_info(connector, &avail_res); + + mode_count = c_conn->ops.get_modes(connector, c_conn->display, + &avail_res); + if (!mode_count) { + SDE_ERROR_CONN(c_conn, "failed to get modes\n"); + return 0; + } + + if (c_conn->hdr_capable) + sde_connector_update_hdr_props(connector); + + if (c_conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) + sde_connector_update_colorspace(connector); + + return mode_count; +} + +static enum drm_mode_status +sde_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct sde_connector *c_conn; + struct msm_resource_caps_info avail_res; + + if (!connector || !mode) { + SDE_ERROR("invalid argument(s), conn %pK, mode %pK\n", + connector, mode); + return MODE_ERROR; + } + + c_conn = to_sde_connector(connector); + + memset(&avail_res, 0, sizeof(avail_res)); + sde_connector_get_avail_res_info(connector, &avail_res); + + if (c_conn->ops.mode_valid) + return c_conn->ops.mode_valid(connector, mode, c_conn->display, + &avail_res); + + /* assume all modes okay by default */ + return MODE_OK; +} + +static struct drm_encoder * +sde_connector_best_encoder(struct drm_connector *connector) +{ + struct sde_connector *c_conn = to_sde_connector(connector); + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return NULL; + } + + /* + * This is true for now, revisit this code when multiple encoders are + * supported. + */ + return c_conn->encoder; +} + +static struct drm_encoder * +sde_connector_atomic_best_encoder(struct drm_connector *connector, + struct drm_connector_state *connector_state) +{ + struct sde_connector *c_conn; + struct drm_encoder *encoder = NULL; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return NULL; + } + + c_conn = to_sde_connector(connector); + + if (c_conn->ops.atomic_best_encoder) + encoder = c_conn->ops.atomic_best_encoder(connector, + c_conn->display, connector_state); + + c_conn->encoder = encoder; + + return encoder; +} + +static int sde_connector_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) +{ + struct sde_connector *c_conn; + struct sde_connector_state *c_state; + bool qsync_dirty = false, has_modeset = false; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return -EINVAL; + } + + if (!new_conn_state) { + SDE_ERROR("invalid connector state\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + c_state = to_sde_connector_state(new_conn_state); + + has_modeset = sde_crtc_atomic_check_has_modeset(new_conn_state->state, + new_conn_state->crtc); + qsync_dirty = msm_property_is_dirty(&c_conn->property_info, + &c_state->property_state, + CONNECTOR_PROP_QSYNC_MODE); + + SDE_DEBUG("has_modeset %d qsync_dirty %d\n", has_modeset, qsync_dirty); + if (has_modeset && qsync_dirty) { + SDE_ERROR("invalid qsync update during modeset\n"); + return -EINVAL; + } + + if (c_conn->ops.atomic_check) + return c_conn->ops.atomic_check(connector, + c_conn->display, new_conn_state); + + return 0; +} + +static void _sde_connector_report_panel_dead(struct sde_connector *conn, + bool skip_pre_kickoff) +{ + struct drm_event event; + + if (!conn) + return; + + /* Panel dead notification can come: + * 1) ESD thread + * 2) Commit thread (if TE stops coming) + * So such case, avoid failure notification twice. + */ + if (conn->panel_dead) + return; + + conn->panel_dead = true; + event.type = DRM_EVENT_PANEL_DEAD; + event.length = sizeof(bool); + msm_mode_object_event_notify(&conn->base.base, + conn->base.dev, &event, (u8 *)&conn->panel_dead); + sde_encoder_display_failure_notification(conn->encoder, + skip_pre_kickoff); + SDE_EVT32(SDE_EVTLOG_ERROR); + SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n", + conn->base.base.id, conn->encoder->base.id); +} + +int sde_connector_esd_status(struct drm_connector *conn) +{ + struct sde_connector *sde_conn = NULL; + struct dsi_display *display; + int ret = 0; + + if (!conn) + return ret; + + sde_conn = to_sde_connector(conn); + if (!sde_conn || !sde_conn->ops.check_status) + return ret; + + display = sde_conn->display; + + /* protect this call with ESD status check call */ + mutex_lock(&sde_conn->lock); + if (atomic_read(&(display->panel->esd_recovery_pending))) { + SDE_ERROR("ESD recovery already pending\n"); + mutex_unlock(&sde_conn->lock); + return -ETIMEDOUT; + } + ret = sde_conn->ops.check_status(&sde_conn->base, + sde_conn->display, true); + mutex_unlock(&sde_conn->lock); + + if (ret <= 0) { + /* cancel if any pending esd work */ + sde_connector_schedule_status_work(conn, false); + _sde_connector_report_panel_dead(sde_conn, true); + ret = -ETIMEDOUT; + } else { + SDE_DEBUG("Successfully received TE from panel\n"); + ret = 0; + } + SDE_EVT32(ret); + + return ret; +} + +static void sde_connector_check_status_work(struct work_struct *work) +{ + struct sde_connector *conn; + int rc = 0; + struct device *dev; + + conn = container_of(to_delayed_work(work), + struct sde_connector, status_work); + if (!conn) { + SDE_ERROR("not able to get connector object\n"); + return; + } + + mutex_lock(&conn->lock); + dev = conn->base.dev->dev; + + if (!conn->ops.check_status || dev->power.is_suspended || + (conn->dpms_mode != DRM_MODE_DPMS_ON)) { + SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode); + mutex_unlock(&conn->lock); + return; + } + + rc = conn->ops.check_status(&conn->base, conn->display, false); + mutex_unlock(&conn->lock); + + if (rc > 0) { + u32 interval; + + SDE_DEBUG("esd check status success conn_id: %d enc_id: %d\n", + conn->base.base.id, conn->encoder->base.id); + + /* If debugfs property is not set then take default value */ + interval = conn->esd_status_interval ? + conn->esd_status_interval : STATUS_CHECK_INTERVAL_MS; + schedule_delayed_work(&conn->status_work, + msecs_to_jiffies(interval)); + return; + } + + _sde_connector_report_panel_dead(conn, false); +} + +static const struct drm_connector_helper_funcs sde_connector_helper_ops = { + .get_modes = sde_connector_get_modes, + .mode_valid = sde_connector_mode_valid, + .best_encoder = sde_connector_best_encoder, + .atomic_check = sde_connector_atomic_check, +}; + +static const struct drm_connector_helper_funcs sde_connector_helper_ops_v2 = { + .get_modes = sde_connector_get_modes, + .mode_valid = sde_connector_mode_valid, + .best_encoder = sde_connector_best_encoder, + .atomic_best_encoder = sde_connector_atomic_best_encoder, + .atomic_check = sde_connector_atomic_check, +}; + +static int sde_connector_populate_mode_info(struct drm_connector *conn, + struct sde_kms_info *info) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct sde_connector *c_conn = NULL; + struct drm_display_mode *mode; + struct msm_mode_info mode_info; + int rc = 0; + + if (!conn || !conn->dev || !conn->dev->dev_private) { + SDE_ERROR("invalid arguments\n"); + return -EINVAL; + } + + priv = conn->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + c_conn = to_sde_connector(conn); + if (!c_conn->ops.get_mode_info) { + SDE_ERROR_CONN(c_conn, "get_mode_info not defined\n"); + return -EINVAL; + } + + list_for_each_entry(mode, &conn->modes, head) { + int topology_idx = 0; + + memset(&mode_info, 0, sizeof(mode_info)); + + rc = sde_connector_get_mode_info(&c_conn->base, mode, + &mode_info); + if (rc) { + SDE_ERROR_CONN(c_conn, + "failed to get mode info for mode %s\n", + mode->name); + continue; + } + + sde_kms_info_add_keystr(info, "mode_name", mode->name); + + sde_kms_info_add_keyint(info, "bit_clk_rate", + mode_info.clk_rate); + + topology_idx = (int)sde_rm_get_topology_name( + mode_info.topology); + if (topology_idx < SDE_RM_TOPOLOGY_MAX) { + sde_kms_info_add_keystr(info, "topology", + e_topology_name[topology_idx].name); + } else { + SDE_ERROR_CONN(c_conn, "invalid topology\n"); + continue; + } + + sde_kms_info_add_keyint(info, "mdp_transfer_time_us", + mode_info.mdp_transfer_time_us); + + if (!mode_info.roi_caps.num_roi) + continue; + + sde_kms_info_add_keyint(info, "partial_update_num_roi", + mode_info.roi_caps.num_roi); + sde_kms_info_add_keyint(info, "partial_update_xstart", + mode_info.roi_caps.align.xstart_pix_align); + sde_kms_info_add_keyint(info, "partial_update_walign", + mode_info.roi_caps.align.width_pix_align); + sde_kms_info_add_keyint(info, "partial_update_wmin", + mode_info.roi_caps.align.min_width); + sde_kms_info_add_keyint(info, "partial_update_ystart", + mode_info.roi_caps.align.ystart_pix_align); + sde_kms_info_add_keyint(info, "partial_update_halign", + mode_info.roi_caps.align.height_pix_align); + sde_kms_info_add_keyint(info, "partial_update_hmin", + mode_info.roi_caps.align.min_height); + sde_kms_info_add_keyint(info, "partial_update_roimerge", + mode_info.roi_caps.merge_rois); + } + + return rc; +} + +int sde_connector_set_blob_data(struct drm_connector *conn, + struct drm_connector_state *state, + enum msm_mdp_conn_property prop_id) +{ + struct sde_kms_info *info; + struct sde_connector *c_conn = NULL; + struct sde_connector_state *sde_conn_state = NULL; + struct msm_mode_info mode_info; + struct drm_property_blob **blob = NULL; + int rc = 0; + + c_conn = to_sde_connector(conn); + if (!c_conn) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + sde_kms_info_reset(info); + + switch (prop_id) { + case CONNECTOR_PROP_SDE_INFO: + memset(&mode_info, 0, sizeof(mode_info)); + + if (state) { + sde_conn_state = to_sde_connector_state(state); + memcpy(&mode_info, &sde_conn_state->mode_info, + sizeof(sde_conn_state->mode_info)); + } else { + /** + * connector state is assigned only on first + * atomic_commit. But this function is allowed to be + * invoked during probe/init sequence. So not throwing + * an error. + */ + SDE_DEBUG_CONN(c_conn, "invalid connector state\n"); + } + + if (c_conn->ops.set_info_blob) { + rc = c_conn->ops.set_info_blob(conn, info, + c_conn->display, &mode_info); + if (rc) { + SDE_ERROR_CONN(c_conn, + "set_info_blob failed, %d\n", + rc); + goto exit; + } + } + + blob = &c_conn->blob_caps; + break; + case CONNECTOR_PROP_MODE_INFO: + rc = sde_connector_populate_mode_info(conn, info); + if (rc) { + SDE_ERROR_CONN(c_conn, + "mode info population failed, %d\n", + rc); + goto exit; + } + blob = &c_conn->blob_mode_info; + break; + default: + SDE_ERROR_CONN(c_conn, "invalid prop_id: %d\n", prop_id); + goto exit; + } + + msm_property_set_blob(&c_conn->property_info, + blob, + SDE_KMS_INFO_DATA(info), + SDE_KMS_INFO_DATALEN(info), + prop_id); +exit: + kfree(info); + + return rc; +} + +static int _sde_connector_install_properties(struct drm_device *dev, + struct sde_kms *sde_kms, struct sde_connector *c_conn, + int connector_type, void *display, + struct msm_display_info *display_info) +{ + struct dsi_display *dsi_display; + int rc; + struct drm_connector *connector; + + msm_property_install_blob(&c_conn->property_info, "capabilities", + DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); + + rc = sde_connector_set_blob_data(&c_conn->base, + NULL, CONNECTOR_PROP_SDE_INFO); + if (rc) { + SDE_ERROR_CONN(c_conn, + "failed to setup connector info, rc = %d\n", rc); + return rc; + } + + connector = &c_conn->base; + + msm_property_install_blob(&c_conn->property_info, "mode_properties", + DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_MODE_INFO); + + if (connector_type == DRM_MODE_CONNECTOR_DSI) { + dsi_display = (struct dsi_display *)(display); + if (dsi_display && dsi_display->panel && + dsi_display->panel->hdr_props.hdr_enabled == true) { + msm_property_install_blob(&c_conn->property_info, + "hdr_properties", + DRM_MODE_PROP_IMMUTABLE, + CONNECTOR_PROP_HDR_INFO); + + msm_property_set_blob(&c_conn->property_info, + &c_conn->blob_hdr, + &dsi_display->panel->hdr_props, + sizeof(dsi_display->panel->hdr_props), + CONNECTOR_PROP_HDR_INFO); + } + } + + msm_property_install_volatile_range( + &c_conn->property_info, "sde_drm_roi_v1", 0x0, + 0, ~0, 0, CONNECTOR_PROP_ROI_V1); + + /* install PP_DITHER properties */ + _sde_connector_install_dither_property(dev, sde_kms, c_conn); + + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + struct drm_msm_ext_hdr_properties hdr = {0}; + + c_conn->hdr_capable = true; + + msm_property_install_blob(&c_conn->property_info, + "ext_hdr_properties", + DRM_MODE_PROP_IMMUTABLE, + CONNECTOR_PROP_EXT_HDR_INFO); + + /* set default values to avoid reading uninitialized data */ + msm_property_set_blob(&c_conn->property_info, + &c_conn->blob_ext_hdr, + &hdr, + sizeof(hdr), + CONNECTOR_PROP_EXT_HDR_INFO); + + /* create and attach colorspace property for DP */ + if (!drm_mode_create_colorspace_property(connector)) + drm_object_attach_property(&connector->base, + connector->colorspace_property, 0); + } + + msm_property_install_volatile_range(&c_conn->property_info, + "hdr_metadata", 0x0, 0, ~0, 0, CONNECTOR_PROP_HDR_METADATA); + + msm_property_install_volatile_range(&c_conn->property_info, + "RETIRE_FENCE", 0x0, 0, ~0, 0, CONNECTOR_PROP_RETIRE_FENCE); + + msm_property_install_range(&c_conn->property_info, "autorefresh", + 0x0, 0, AUTOREFRESH_MAX_FRAME_CNT, 0, + CONNECTOR_PROP_AUTOREFRESH); + + if (connector_type == DRM_MODE_CONNECTOR_DSI) { + if (sde_kms->catalog->has_qsync && display_info->qsync_min_fps) + msm_property_install_enum(&c_conn->property_info, + "qsync_mode", 0, 0, e_qsync_mode, + ARRAY_SIZE(e_qsync_mode), + CONNECTOR_PROP_QSYNC_MODE); + + if (display_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + msm_property_install_enum(&c_conn->property_info, + "frame_trigger_mode", 0, 0, + e_frame_trigger_mode, + ARRAY_SIZE(e_frame_trigger_mode), + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE); + } + + msm_property_install_range(&c_conn->property_info, "bl_scale", + 0x0, 0, MAX_BL_SCALE_LEVEL, MAX_BL_SCALE_LEVEL, + CONNECTOR_PROP_BL_SCALE); + + msm_property_install_range(&c_conn->property_info, "sv_bl_scale", + 0x0, 0, MAX_SV_BL_SCALE_LEVEL, MAX_SV_BL_SCALE_LEVEL, + CONNECTOR_PROP_SV_BL_SCALE); + + c_conn->bl_scale_dirty = false; + c_conn->bl_scale = MAX_BL_SCALE_LEVEL; + c_conn->bl_scale_sv = MAX_SV_BL_SCALE_LEVEL; + +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint + msm_property_install_range(&c_conn->property_info,"CONNECTOR_CUST", + 0x0, 0, INT_MAX, 0, CONNECTOR_PROP_CUSTOM); + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort) + msm_property_install_range(&c_conn->property_info, + "supported_colorspaces", + DRM_MODE_PROP_IMMUTABLE, 0, 0xffff, 0, + CONNECTOR_PROP_SUPPORTED_COLORSPACES); + + /* enum/bitmask properties */ + msm_property_install_enum(&c_conn->property_info, "topology_name", + DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, + ARRAY_SIZE(e_topology_name), + CONNECTOR_PROP_TOPOLOGY_NAME); + msm_property_install_enum(&c_conn->property_info, "topology_control", + 0, 1, e_topology_control, + ARRAY_SIZE(e_topology_control), + CONNECTOR_PROP_TOPOLOGY_CONTROL); + msm_property_install_enum(&c_conn->property_info, "LP", + 0, 0, e_power_mode, + ARRAY_SIZE(e_power_mode), + CONNECTOR_PROP_LP); + + return 0; +} + +struct drm_connector *sde_connector_init(struct drm_device *dev, + struct drm_encoder *encoder, + struct drm_panel *panel, + void *display, + const struct sde_connector_ops *ops, + int connector_poll, + int connector_type) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct sde_connector *c_conn = NULL; + struct msm_display_info display_info; + int rc; + + if (!dev || !dev->dev_private || !encoder) { + SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n", + dev, encoder); + return ERR_PTR(-EINVAL); + } + + priv = dev->dev_private; + if (!priv->kms) { + SDE_ERROR("invalid kms reference\n"); + return ERR_PTR(-EINVAL); + } + + c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL); + if (!c_conn) { + SDE_ERROR("failed to alloc sde connector\n"); + return ERR_PTR(-ENOMEM); + } + + memset(&display_info, 0, sizeof(display_info)); + + rc = drm_connector_init(dev, + &c_conn->base, + &sde_connector_ops, + connector_type); + if (rc) + goto error_free_conn; + + spin_lock_init(&c_conn->event_lock); + + c_conn->base.panel = panel; + c_conn->connector_type = connector_type; + c_conn->encoder = encoder; + c_conn->display = display; + + c_conn->dpms_mode = DRM_MODE_DPMS_ON; + c_conn->lp_mode = 0; + c_conn->last_panel_power_mode = SDE_MODE_DPMS_ON; + + sde_kms = to_sde_kms(priv->kms); + if (sde_kms->vbif[VBIF_NRT]) { + c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE]; + c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE]; + } else { + c_conn->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE]; + c_conn->aspace[SDE_IOMMU_DOMAIN_SECURE] = + sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE]; + } + + if (ops) + c_conn->ops = *ops; + + if (ops && ops->atomic_best_encoder && ops->atomic_check) + c_conn->base.helper_private = &sde_connector_helper_ops_v2; + else + c_conn->base.helper_private = &sde_connector_helper_ops; + + c_conn->base.polled = connector_poll; + c_conn->base.interlace_allowed = 0; + c_conn->base.doublescan_allowed = 0; + + snprintf(c_conn->name, + SDE_CONNECTOR_NAME_SIZE, + "conn%u", + c_conn->base.base.id); + + c_conn->retire_fence = sde_fence_init(c_conn->name, + c_conn->base.base.id); + if (IS_ERR(c_conn->retire_fence)) { + rc = PTR_ERR(c_conn->retire_fence); + SDE_ERROR("failed to init fence, %d\n", rc); + goto error_cleanup_conn; + } + + mutex_init(&c_conn->lock); + + rc = drm_connector_attach_encoder(&c_conn->base, encoder); + if (rc) { + SDE_ERROR("failed to attach encoder to connector, %d\n", rc); + goto error_cleanup_fence; + } + + rc = sde_backlight_setup(c_conn, dev); + if (rc) { + SDE_ERROR("failed to setup backlight, rc=%d\n", rc); + goto error_cleanup_fence; + } + + /* create properties */ + msm_property_init(&c_conn->property_info, &c_conn->base.base, dev, + priv->conn_property, c_conn->property_data, + CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT, + sizeof(struct sde_connector_state)); + + if (c_conn->ops.post_init) { + rc = c_conn->ops.post_init(&c_conn->base, display); + if (rc) { + SDE_ERROR("post-init failed, %d\n", rc); + goto error_cleanup_fence; + } + } + + rc = sde_connector_get_info(&c_conn->base, &display_info); + if (!rc && (connector_type == DRM_MODE_CONNECTOR_DSI) && + (display_info.capabilities & MSM_DISPLAY_CAP_VID_MODE)) + sde_connector_register_event(&c_conn->base, + SDE_CONN_EVENT_VID_FIFO_OVERFLOW, + sde_connector_handle_disp_recovery, + c_conn); + + rc = _sde_connector_install_properties(dev, sde_kms, c_conn, + connector_type, display, &display_info); + if (rc) + goto error_cleanup_fence; + + rc = msm_property_install_get_status(&c_conn->property_info); + if (rc) { + SDE_ERROR("failed to create one or more properties\n"); + goto error_destroy_property; + } + + _sde_connector_lm_preference(c_conn, sde_kms, + display_info.display_type); + + SDE_DEBUG("connector %d attach encoder %d\n", + c_conn->base.base.id, encoder->base.id); + + INIT_DELAYED_WORK(&c_conn->status_work, + sde_connector_check_status_work); + + return &c_conn->base; + +error_destroy_property: + if (c_conn->blob_caps) + drm_property_blob_put(c_conn->blob_caps); + if (c_conn->blob_hdr) + drm_property_blob_put(c_conn->blob_hdr); + if (c_conn->blob_dither) + drm_property_blob_put(c_conn->blob_dither); + if (c_conn->blob_mode_info) + drm_property_blob_put(c_conn->blob_mode_info); + if (c_conn->blob_ext_hdr) + drm_property_blob_put(c_conn->blob_ext_hdr); + + msm_property_destroy(&c_conn->property_info); +error_cleanup_fence: + mutex_destroy(&c_conn->lock); + sde_fence_deinit(c_conn->retire_fence); +error_cleanup_conn: + drm_connector_cleanup(&c_conn->base); +error_free_conn: + kfree(c_conn); + + return ERR_PTR(rc); +} + +static int _sde_conn_hw_recovery_handler( + struct drm_connector *connector, bool val) +{ + struct sde_connector *c_conn; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return -EINVAL; + } + c_conn = to_sde_connector(connector); + + if (c_conn->encoder) + sde_encoder_recovery_events_handler(c_conn->encoder, val); + + return 0; +} + +int sde_connector_register_custom_event(struct sde_kms *kms, + struct drm_connector *conn_drm, u32 event, bool val) +{ + int ret = -EINVAL; + + switch (event) { + case DRM_EVENT_SYS_BACKLIGHT: + ret = 0; + break; + case DRM_EVENT_PANEL_DEAD: + ret = 0; + break; + case DRM_EVENT_SDE_HW_RECOVERY: + ret = _sde_conn_hw_recovery_handler(conn_drm, val); + break; + default: + break; + } + return ret; +} + +int sde_connector_event_notify(struct drm_connector *connector, uint32_t type, + uint32_t len, uint32_t val) +{ + struct drm_event event; + int ret; + + if (!connector) { + SDE_ERROR("invalid connector\n"); + return -EINVAL; + } + + switch (type) { + case DRM_EVENT_SYS_BACKLIGHT: + case DRM_EVENT_PANEL_DEAD: + case DRM_EVENT_SDE_HW_RECOVERY: + ret = 0; + break; + default: + SDE_ERROR("connector %d, Unsupported event %d\n", + connector->base.id, type); + return -EINVAL; + } + + event.type = type; + event.length = len; + msm_mode_object_event_notify(&connector->base, connector->dev, &event, + (u8 *)&val); + + SDE_EVT32(connector->base.id, type, len, val); + SDE_DEBUG("connector:%d hw recovery event(%d) value (%d) notified\n", + connector->base.id, type, val); + + return ret; +} diff --git a/techpack/display/msm/sde/sde_connector.h b/techpack/display/msm/sde/sde_connector.h new file mode 100644 index 0000000000000000000000000000000000000000..9389f135109ee093ba4c443b120608e140bdc335 --- /dev/null +++ b/techpack/display/msm/sde/sde_connector.h @@ -0,0 +1,966 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_CONNECTOR_H_ +#define _SDE_CONNECTOR_H_ + +#include <uapi/drm/msm_drm_pp.h> +#include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_panel.h> + +#include "msm_drv.h" +#include "msm_prop.h" +#include "sde_kms.h" +#include "sde_fence.h" + +#define SDE_CONNECTOR_NAME_SIZE 16 +#define SDE_CONNECTOR_DHDR_MEMPOOL_MAX_SIZE SZ_32 + +struct sde_connector; +struct sde_connector_state; + +/** + * struct sde_connector_ops - callback functions for generic sde connector + * Individual callbacks documented below. + */ +struct sde_connector_ops { + /** + * post_init - perform additional initialization steps + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success + */ + int (*post_init)(struct drm_connector *connector, + void *display); + + /** + * set_info_blob - initialize given info blob + * @connector: Pointer to drm connector structure + * @info: Pointer to sde connector info structure + * @display: Pointer to private display handle + * @mode_info: Pointer to mode info structure + * Returns: Zero on success + */ + int (*set_info_blob)(struct drm_connector *connector, + void *info, + void *display, + struct msm_mode_info *mode_info); + + /** + * detect - determine if connector is connected + * @connector: Pointer to drm connector structure + * @force: Force detect setting from drm framework + * @display: Pointer to private display handle + * Returns: Connector 'is connected' status + */ + enum drm_connector_status (*detect)(struct drm_connector *connector, + bool force, + void *display); + + /** + * get_modes - add drm modes via drm_mode_probed_add() + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @avail_res: Pointer with current available resources + * Returns: Number of modes added + */ + int (*get_modes)(struct drm_connector *connector, + void *display, + const struct msm_resource_caps_info *avail_res); + + /** + * update_pps - update pps command for the display panel + * @connector: Pointer to drm connector structure + * @pps_cmd: Pointer to pps command + * @display: Pointer to private display handle + * Returns: Zero on success + */ + int (*update_pps)(struct drm_connector *connector, + char *pps_cmd, void *display); + + /** + * mode_valid - determine if specified mode is valid + * @connector: Pointer to drm connector structure + * @mode: Pointer to drm mode structure + * @display: Pointer to private display handle + * @avail_res: Pointer with curr available resources + * Returns: Validity status for specified mode + */ + enum drm_mode_status (*mode_valid)(struct drm_connector *connector, + struct drm_display_mode *mode, + void *display, + const struct msm_resource_caps_info *avail_res); + + /** + * set_property - set property value + * @connector: Pointer to drm connector structure + * @state: Pointer to drm connector state structure + * @property_index: DRM property index + * @value: Incoming property value + * @display: Pointer to private display structure + * Returns: Zero on success + */ + int (*set_property)(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t value, + void *display); + + /** + * get_property - get property value + * @connector: Pointer to drm connector structure + * @state: Pointer to drm connector state structure + * @property_index: DRM property index + * @value: Pointer to variable for accepting property value + * @display: Pointer to private display structure + * Returns: Zero on success + */ + int (*get_property)(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t *value, + void *display); + + /** + * get_info - get display information + * @connector: Pointer to drm connector structure + * @info: Pointer to msm display info structure + * @display: Pointer to private display structure + * Returns: Zero on success + */ + int (*get_info)(struct drm_connector *connector, + struct msm_display_info *info, void *display); + + /** + * get_mode_info - retrieve mode information + * @connector: Pointer to drm connector structure + * @drm_mode: Display mode set for the display + * @mode_info: Out parameter. information of the display mode + * @display: Pointer to private display structure + * @avail_res: Pointer with curr available resources + * Returns: Zero on success + */ + int (*get_mode_info)(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, + const struct msm_resource_caps_info *avail_res); + + /** + * enable_event - notify display of event registration/unregistration + * @connector: Pointer to drm connector structure + * @event_idx: SDE connector event index + * @enable: Whether the event is being enabled/disabled + * @display: Pointer to private display structure + */ + void (*enable_event)(struct drm_connector *connector, + uint32_t event_idx, bool enable, void *display); + + /** + * set_backlight - set backlight level + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + * @bl_lvel: Backlight level + */ + int (*set_backlight)(struct drm_connector *connector, + void *display, u32 bl_lvl); + + /** + * set_colorspace - set colorspace for connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + */ + int (*set_colorspace)(struct drm_connector *connector, + void *display); + + /** + * soft_reset - perform a soft reset on the connector + * @display: Pointer to private display structure + * Return: Zero on success, -ERROR otherwise + */ + int (*soft_reset)(void *display); + + /** + * pre_kickoff - trigger display to program kickoff-time features + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + * @params: Parameter bundle of connector-stored information for + * kickoff-time programming into the display + * Returns: Zero on success + */ + int (*pre_kickoff)(struct drm_connector *connector, + void *display, + struct msm_display_kickoff_params *params); + + /** + * clk_ctrl - perform clk enable/disable on the connector + * @handle: Pointer to clk handle + * @type: Type of clks + * @enable: State of clks + */ + int (*clk_ctrl)(void *handle, u32 type, u32 state); + + /** + * set_power - update dpms setting + * @connector: Pointer to drm connector structure + * @power_mode: One of the following, + * SDE_MODE_DPMS_ON + * SDE_MODE_DPMS_LP1 + * SDE_MODE_DPMS_LP2 + * SDE_MODE_DPMS_OFF + * @display: Pointer to private display structure + * Returns: Zero on success + */ + int (*set_power)(struct drm_connector *connector, + int power_mode, void *display); + + /** + * get_dst_format - get dst_format from display + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: dst_format of display + */ + enum dsi_pixel_format (*get_dst_format)(struct drm_connector *connector, + void *display); + + /** + * post_kickoff - display to program post kickoff-time features + * @connector: Pointer to drm connector structure + * @params: Parameter bundle of connector-stored information for + * post kickoff programming into the display + * Returns: Zero on success + */ + int (*post_kickoff)(struct drm_connector *connector, + struct msm_display_conn_params *params); + + /** + * post_open - calls connector to process post open functionalities + * @display: Pointer to private display structure + */ + void (*post_open)(struct drm_connector *connector, void *display); + + /** + * check_status - check status of connected display panel + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @te_check_override: Whether check TE from panel or default check + * Returns: positive value for success, negetive or zero for failure + */ + int (*check_status)(struct drm_connector *connector, void *display, + bool te_check_override); + + /** + * cmd_transfer - Transfer command to the connected display panel + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @cmd_buf: Command buffer + * @cmd_buf_len: Command buffer length in bytes + * Returns: Zero for success, negetive for failure + */ + int (*cmd_transfer)(struct drm_connector *connector, + void *display, const char *cmd_buf, + u32 cmd_buf_len); + + /** + * config_hdr - configure HDR + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @c_state: Pointer to connector state + * Returns: Zero on success, negative error code for failures + */ + int (*config_hdr)(struct drm_connector *connector, void *display, + struct sde_connector_state *c_state); + + /** + * atomic_best_encoder - atomic best encoder selection for connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @c_state: Pointer to connector state + * Returns: valid drm_encoder for success + */ + struct drm_encoder *(*atomic_best_encoder)( + struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state); + + /** + * atomic_check - atomic check handling for connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * @c_state: Pointer to connector state + * Returns: valid drm_encoder for success + */ + int (*atomic_check)(struct drm_connector *connector, + void *display, + struct drm_connector_state *c_state); + + /** + * pre_destroy - handle pre destroy operations for the connector + * @connector: Pointer to drm connector structure + * @display: Pointer to private display handle + * Returns: Zero on success, negative error code for failures + */ + void (*pre_destroy)(struct drm_connector *connector, void *display); + + /** + * cont_splash_config - initialize splash resources + * @display: Pointer to private display handle + * Returns: zero for success, negetive for failure + */ + int (*cont_splash_config)(void *display); + + /** + * get_panel_vfp - returns original panel vfp + * @display: Pointer to private display handle + * @h_active: width + * @v_active: height + * Returns: v_front_porch on success error-code on failure + */ + int (*get_panel_vfp)(void *display, int h_active, int v_active); + + /** + * get_default_lm - returns default number of lm + * @display: Pointer to private display handle + * @num_lm: Pointer to number of lms to be populated + * Returns: zero for success, negetive for failure + */ + int (*get_default_lms)(void *display, u32 *num_lm); + + /** + * prepare_commit - trigger display to program pre-commit time features + * @display: Pointer to private display structure + * @params: Parameter bundle of connector-stored information for + * pre commit time programming into the display + * Returns: Zero on success + */ + int (*prepare_commit)(void *display, + struct msm_display_conn_params *params); +}; + +/** + * enum sde_connector_display_type - list of display types + */ +enum sde_connector_display { + SDE_CONNECTOR_UNDEFINED, + SDE_CONNECTOR_PRIMARY, + SDE_CONNECTOR_SECONDARY, + SDE_CONNECTOR_MAX +}; + +/** + * enum sde_connector_events - list of recognized connector events + */ +enum sde_connector_events { + SDE_CONN_EVENT_VID_DONE, /* video mode frame done */ + SDE_CONN_EVENT_CMD_DONE, /* command mode frame done */ + SDE_CONN_EVENT_VID_FIFO_OVERFLOW, /* dsi fifo overflow error */ + SDE_CONN_EVENT_CMD_FIFO_UNDERFLOW, /* dsi fifo underflow error */ + SDE_CONN_EVENT_COUNT, +}; + +/** + * struct sde_connector_evt - local event registration entry structure + * @cb_func: Pointer to desired callback function + * @usr: User pointer to pass to callback on event trigger + * Returns: Zero success, negetive for failure + */ +struct sde_connector_evt { + int (*cb_func)(uint32_t event_idx, + uint32_t instance_idx, void *usr, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + void *usr; +}; + +struct sde_connector_dyn_hdr_metadata { + u8 dynamic_hdr_payload[SDE_CONNECTOR_DHDR_MEMPOOL_MAX_SIZE]; + int dynamic_hdr_payload_size; + bool dynamic_hdr_update; +}; + +/** + * struct sde_connector - local sde connector structure + * @base: Base drm connector structure + * @connector_type: Set to one of DRM_MODE_CONNECTOR_ types + * @encoder: Pointer to preferred drm encoder + * @panel: Pointer to drm panel, if present + * @display: Pointer to private display data structure + * @drv_panel: Pointer to interface driver's panel module, if present + * @mst_port: Pointer to mst port, if present + * @mmu_secure: MMU id for secure buffers + * @mmu_unsecure: MMU id for unsecure buffers + * @name: ASCII name of connector + * @lock: Mutex lock object for this structure + * @retire_fence: Retire fence context reference + * @ops: Local callback function pointer table + * @dpms_mode: DPMS property setting from user space + * @lp_mode: LP property setting from user space + * @last_panel_power_mode: Last consolidated dpms/lp mode setting + * @property_info: Private structure for generic property handling + * @property_data: Array of private data for generic property handling + * @blob_caps: Pointer to blob structure for 'capabilities' property + * @blob_hdr: Pointer to blob structure for 'hdr_properties' property + * @blob_ext_hdr: Pointer to blob structure for 'ext_hdr_properties' property + * @blob_dither: Pointer to blob structure for default dither config + * @blob_mode_info: Pointer to blob structure for mode info + * @fb_kmap: true if kernel mapping of framebuffer is requested + * @event_table: Array of registered events + * @event_lock: Lock object for event_table + * @bl_device: backlight device node + * @status_work: work object to perform status checks + * @esd_status_interval: variable to change ESD check interval in millisec + * @panel_dead: Flag to indicate if panel has gone bad + * @esd_status_check: Flag to indicate if ESD thread is scheduled or not + * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed + * @bl_scale: BL scale value for ABA feature + * @bl_scale_sv: BL scale value for sunlight visibility feature + * @unset_bl_level: BL level that needs to be set later + * @allow_bl_update: Flag to indicate if BL update is allowed currently or not + * @qsync_mode: Cached Qsync mode, 0=disabled, 1=continuous mode + * @qsync_updated: Qsync settings were updated + * @colorspace_updated: Colorspace property was updated + * last_cmd_tx_sts: status of the last command transfer + * @hdr_capable: external hdr support present + * @core_clk_rate: MDP core clk rate used for dynamic HDR packet calculation + */ +struct sde_connector { + struct drm_connector base; + + int connector_type; + + struct drm_encoder *encoder; + void *display; + void *drv_panel; + void *mst_port; + + struct msm_gem_address_space *aspace[SDE_IOMMU_DOMAIN_MAX]; + + char name[SDE_CONNECTOR_NAME_SIZE]; + + struct mutex lock; + struct sde_fence_context *retire_fence; + struct sde_connector_ops ops; + int dpms_mode; + int lp_mode; + int last_panel_power_mode; + + struct msm_property_info property_info; + struct msm_property_data property_data[CONNECTOR_PROP_COUNT]; + struct drm_property_blob *blob_caps; + struct drm_property_blob *blob_hdr; + struct drm_property_blob *blob_ext_hdr; + struct drm_property_blob *blob_dither; + struct drm_property_blob *blob_mode_info; + + bool fb_kmap; + struct sde_connector_evt event_table[SDE_CONN_EVENT_COUNT]; + spinlock_t event_lock; + + struct backlight_device *bl_device; + struct delayed_work status_work; + u32 esd_status_interval; + bool panel_dead; + bool esd_status_check; + + bool bl_scale_dirty; + u32 bl_scale; + u32 bl_scale_sv; + u32 unset_bl_level; + bool allow_bl_update; + + u32 qsync_mode; + bool qsync_updated; + + bool colorspace_updated; + + bool last_cmd_tx_sts; + bool hdr_capable; +}; + +/** + * to_sde_connector - convert drm_connector pointer to sde connector pointer + * @X: Pointer to drm_connector structure + * Returns: Pointer to sde_connector structure + */ +#define to_sde_connector(x) container_of((x), struct sde_connector, base) + +/** + * sde_connector_get_display - get sde connector's private display pointer + * @C: Pointer to drm connector structure + * Returns: Pointer to associated private display structure + */ +#define sde_connector_get_display(C) \ + ((C) ? to_sde_connector((C))->display : NULL) + +/** + * sde_connector_get_encoder - get sde connector's private encoder pointer + * @C: Pointer to drm connector structure + * Returns: Pointer to associated private encoder structure + */ +#define sde_connector_get_encoder(C) \ + ((C) ? to_sde_connector((C))->encoder : NULL) + +/** + * sde_connector_qsync_updated - indicates if connector updated qsync + * @C: Pointer to drm connector structure + * Returns: True if qsync is updated; false otherwise + */ +#define sde_connector_is_qsync_updated(C) \ + ((C) ? to_sde_connector((C))->qsync_updated : 0) + +/** + * sde_connector_get_qsync_mode - get sde connector's qsync_mode + * @C: Pointer to drm connector structure + * Returns: Current cached qsync_mode for given connector + */ +#define sde_connector_get_qsync_mode(C) \ + ((C) ? to_sde_connector((C))->qsync_mode : 0) + +/** + * sde_connector_get_propinfo - get sde connector's property info pointer + * @C: Pointer to drm connector structure + * Returns: Pointer to associated private property info structure + */ +#define sde_connector_get_propinfo(C) \ + ((C) ? &to_sde_connector((C))->property_info : NULL) + +/** + * struct sde_connector_state - private connector status structure + * @base: Base drm connector structure + * @out_fb: Pointer to output frame buffer, if applicable + * @property_state: Local storage for msm_prop properties + * @property_values: Local cache of current connector property values + * @rois: Regions of interest structure for mapping CRTC to Connector output + * @property_blobs: blob properties + * @mode_info: local copy of msm_mode_info struct + * @hdr_meta: HDR metadata info passed from userspace + * @dyn_hdr_meta: Dynamic HDR metadata payload and state tracking + * @old_topology_name: topology of previous atomic state. remove this in later + * kernel versions which provide drm_atomic_state old_state pointers + */ +struct sde_connector_state { + struct drm_connector_state base; + struct drm_framebuffer *out_fb; + struct msm_property_state property_state; + struct msm_property_value property_values[CONNECTOR_PROP_COUNT]; + + struct msm_roi_list rois; + struct drm_property_blob *property_blobs[CONNECTOR_PROP_BLOBCOUNT]; + struct msm_mode_info mode_info; + struct drm_msm_ext_hdr_metadata hdr_meta; + struct sde_connector_dyn_hdr_metadata dyn_hdr_meta; + enum sde_rm_topology_name old_topology_name; +}; + +/** + * to_sde_connector_state - convert drm_connector_state pointer to + * sde connector state pointer + * @X: Pointer to drm_connector_state structure + * Returns: Pointer to sde_connector_state structure + */ +#define to_sde_connector_state(x) \ + container_of((x), struct sde_connector_state, base) + +/** + * sde_connector_get_property - query integer value of connector property + * @S: Pointer to drm connector state + * @X: Property index, from enum msm_mdp_connector_property + * Returns: Integer value of requested property + */ +#define sde_connector_get_property(S, X) \ + ((S) && ((X) < CONNECTOR_PROP_COUNT) ? \ + (to_sde_connector_state((S))->property_values[(X)].value) : 0) + +/** + * sde_connector_get_property_state - retrieve property state cache + * @S: Pointer to drm connector state + * Returns: Pointer to local property state structure + */ +#define sde_connector_get_property_state(S) \ + ((S) ? (&to_sde_connector_state((S))->property_state) : NULL) + +/** + * sde_connector_get_out_fb - query out_fb value from sde connector state + * @S: Pointer to drm connector state + * Returns: Output fb associated with specified connector state + */ +#define sde_connector_get_out_fb(S) \ + ((S) ? to_sde_connector_state((S))->out_fb : 0) + +/** + * sde_connector_get_topology_name - helper accessor to retrieve topology_name + * @connector: pointer to drm connector + * Returns: value of the CONNECTOR_PROP_TOPOLOGY_NAME property or 0 + */ +static inline uint64_t sde_connector_get_topology_name( + struct drm_connector *connector) +{ + if (!connector || !connector->state) + return 0; + return sde_connector_get_property(connector->state, + CONNECTOR_PROP_TOPOLOGY_NAME); +} + +/** + * sde_connector_get_old_topology_name - helper accessor to retrieve + * topology_name for the previous mode + * @connector: pointer to drm connector state + * Returns: cached value of the previous topology, or SDE_RM_TOPOLOGY_NONE + */ +static inline enum sde_rm_topology_name sde_connector_get_old_topology_name( + struct drm_connector_state *state) +{ + struct sde_connector_state *c_state = to_sde_connector_state(state); + + if (!state) + return SDE_RM_TOPOLOGY_NONE; + + return c_state->old_topology_name; +} + +/** + * sde_connector_set_old_topology_name - helper to cache value of previous + * mode's topology + * @connector: pointer to drm connector state + * Returns: 0 on success, negative errno on failure + */ +static inline int sde_connector_set_old_topology_name( + struct drm_connector_state *state, + enum sde_rm_topology_name top) +{ + struct sde_connector_state *c_state = to_sde_connector_state(state); + + if (!state) + return -EINVAL; + + c_state->old_topology_name = top; + + return 0; +} + +/** + * sde_connector_get_lp - helper accessor to retrieve LP state + * @connector: pointer to drm connector + * Returns: value of the CONNECTOR_PROP_LP property or 0 + */ +static inline uint64_t sde_connector_get_lp( + struct drm_connector *connector) +{ + if (!connector || !connector->state) + return 0; + return sde_connector_get_property(connector->state, + CONNECTOR_PROP_LP); +} + +/** + * sde_connector_set_property_for_commit - add property set to atomic state + * Add a connector state property update for the specified property index + * to the atomic state in preparation for a drm_atomic_commit. + * @connector: Pointer to drm connector + * @atomic_state: Pointer to DRM atomic state structure for commit + * @property_idx: Connector property index + * @value: Updated property value + * Returns: Zero on success + */ +int sde_connector_set_property_for_commit(struct drm_connector *connector, + struct drm_atomic_state *atomic_state, + uint32_t property_idx, uint64_t value); + +/** + * sde_connector_init - create drm connector object for a given display + * @dev: Pointer to drm device struct + * @encoder: Pointer to associated encoder + * @panel: Pointer to associated panel, can be NULL + * @display: Pointer to associated display object + * @ops: Pointer to callback operations function table + * @connector_poll: Set to appropriate DRM_CONNECTOR_POLL_ setting + * @connector_type: Set to appropriate DRM_MODE_CONNECTOR_ type + * Returns: Pointer to newly created drm connector struct + */ +struct drm_connector *sde_connector_init(struct drm_device *dev, + struct drm_encoder *encoder, + struct drm_panel *panel, + void *display, + const struct sde_connector_ops *ops, + int connector_poll, + int connector_type); + +/** + * sde_connector_prepare_fence - prepare fence support for current commit + * @connector: Pointer to drm connector object + */ +void sde_connector_prepare_fence(struct drm_connector *connector); + +/** + * sde_connector_complete_commit - signal completion of current commit + * @connector: Pointer to drm connector object + * @ts: timestamp to be updated in the fence signalling + * @fence_event: enum value to indicate nature of fence event + */ +void sde_connector_complete_commit(struct drm_connector *connector, + ktime_t ts, enum sde_fence_event fence_event); + +/** + * sde_connector_commit_reset - reset the completion signal + * @connector: Pointer to drm connector object + * @ts: timestamp to be updated in the fence signalling + */ +void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts); + +/** + * sde_connector_get_info - query display specific information + * @connector: Pointer to drm connector object + * @info: Pointer to msm display information structure + * Returns: Zero on success + */ +int sde_connector_get_info(struct drm_connector *connector, + struct msm_display_info *info); + +/** + * sde_connector_clk_ctrl - enables/disables the connector clks + * @connector: Pointer to drm connector object + * @enable: true/false to enable/disable + * Returns: Zero on success + */ +int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable); + +/** + * sde_connector_get_dpms - query dpms setting + * @connector: Pointer to drm connector structure + * Returns: Current DPMS setting for connector + */ +int sde_connector_get_dpms(struct drm_connector *connector); + +/** + * sde_connector_set_qsync_params - set status of qsync_updated for current + * frame and update the cached qsync_mode + * @connector: pointer to drm connector + * + * This must be called after the connector set_property values are applied, + * and before sde_connector's qsync_updated or qsync_mode fields are accessed. + * It must only be called once per frame update for the given connector. + */ +void sde_connector_set_qsync_params(struct drm_connector *connector); + +/** + * sde_connector_complete_qsync_commit - callback signalling completion + * of qsync, if modified for the current commit + * @conn - Pointer to drm connector object + * @params - Parameter bundle of connector-stored information for + * post kickoff programming into the display + */ +void sde_connector_complete_qsync_commit(struct drm_connector *conn, + struct msm_display_conn_params *params); + +/** +* sde_connector_get_dyn_hdr_meta - returns pointer to connector state's dynamic +* HDR metadata info +* @connector: pointer to drm connector +*/ + +struct sde_connector_dyn_hdr_metadata *sde_connector_get_dyn_hdr_meta( + struct drm_connector *connector); + +/** + * sde_connector_trigger_event - indicate that an event has occurred + * Any callbacks that have been registered against this event will + * be called from the same thread context. + * @connector: Pointer to drm connector structure + * @event_idx: Index of event to trigger + * @instance_idx: Event-specific "instance index" to pass to callback + * @data0: Event-specific "data" to pass to callback + * @data1: Event-specific "data" to pass to callback + * @data2: Event-specific "data" to pass to callback + * @data3: Event-specific "data" to pass to callback + * Returns: Zero on success + */ +int sde_connector_trigger_event(void *drm_connector, + uint32_t event_idx, uint32_t instance_idx, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3); + +/** + * sde_connector_register_event - register a callback function for an event + * @connector: Pointer to drm connector structure + * @event_idx: Index of event to register + * @cb_func: Pointer to desired callback function + * @usr: User pointer to pass to callback on event trigger + * Returns: Zero on success + */ +int sde_connector_register_event(struct drm_connector *connector, + uint32_t event_idx, + int (*cb_func)(uint32_t event_idx, + uint32_t instance_idx, void *usr, + uint32_t data0, uint32_t data1, + uint32_t data2, uint32_t data3), + void *usr); + +/** + * sde_connector_unregister_event - unregister all callbacks for an event + * @connector: Pointer to drm connector structure + * @event_idx: Index of event to register + */ +void sde_connector_unregister_event(struct drm_connector *connector, + uint32_t event_idx); + +/** + * sde_connector_register_custom_event - register for async events + * @kms: Pointer to sde_kms + * @conn_drm: Pointer to drm connector object + * @event: Event for which request is being sent + * @en: Flag to enable/disable the event + * Returns: Zero on success + */ +int sde_connector_register_custom_event(struct sde_kms *kms, + struct drm_connector *conn_drm, u32 event, bool en); + +/** + * sde_connector_pre_kickoff - trigger kickoff time feature programming + * @connector: Pointer to drm connector object + * Returns: Zero on success + */ +int sde_connector_pre_kickoff(struct drm_connector *connector); + +/** + * sde_connector_prepare_commit - trigger commit time feature programming + * @connector: Pointer to drm connector object + * Returns: Zero on success + */ +int sde_connector_prepare_commit(struct drm_connector *connector); + +/** + * sde_connector_needs_offset - adjust the output fence offset based on + * display type + * @connector: Pointer to drm connector object + * Returns: true if offset is required, false for all other cases. + */ +static inline bool sde_connector_needs_offset(struct drm_connector *connector) +{ + struct sde_connector *c_conn; + + if (!connector) + return false; + + c_conn = to_sde_connector(connector); + return (c_conn->connector_type != DRM_MODE_CONNECTOR_VIRTUAL); +} + +/** + * sde_connector_get_dither_cfg - get dither property data + * @conn: Pointer to drm_connector struct + * @state: Pointer to drm_connector_state struct + * @cfg: Pointer to pointer to dither cfg + * @len: length of the dither data + * Returns: Zero on success + */ +int sde_connector_get_dither_cfg(struct drm_connector *conn, + struct drm_connector_state *state, void **cfg, size_t *len); + +/** + * sde_connector_set_blob_data - set connector blob property data + * @conn: Pointer to drm_connector struct + * @state: Pointer to the drm_connector_state struct + * @prop_id: property id to be populated + * Returns: Zero on success + */ +int sde_connector_set_blob_data(struct drm_connector *conn, + struct drm_connector_state *state, + enum msm_mdp_conn_property prop_id); + +/** + * sde_connector_roi_v1_check_roi - validate connector ROI + * @conn_state: Pointer to drm_connector_state struct + * Returns: Zero on success + */ +int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state); + +/** + * sde_connector_schedule_status_work - manage ESD thread + * conn: Pointer to drm_connector struct + * @en: flag to start/stop ESD thread + */ +void sde_connector_schedule_status_work(struct drm_connector *conn, bool en); + +/** + * sde_connector_helper_reset_properties - reset properties to default values in + * the given DRM connector state object + * @connector: Pointer to DRM connector object + * @connector_state: Pointer to DRM connector state object + * Returns: 0 on success, negative errno on failure + */ +int sde_connector_helper_reset_custom_properties( + struct drm_connector *connector, + struct drm_connector_state *connector_state); + +/** + * sde_connector_state_get_mode_info - get information of the current mode + * in the given connector state. + * conn_state: Pointer to the DRM connector state object + * mode_info: Pointer to the mode info structure + */ +int sde_connector_state_get_mode_info(struct drm_connector_state *conn_state, + struct msm_mode_info *mode_info); + +/** +* sde_connector_get_mode_info - retrieve mode info for given mode +* @connector: Pointer to drm connector structure +* @drm_mode: Display mode set for the display +* @mode_info: Out parameter. information of the display mode +* Returns: Zero on success +*/ +int sde_connector_get_mode_info(struct drm_connector *conn, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info); + +/** + * sde_conn_timeline_status - current buffer timeline status + * conn: Pointer to drm_connector struct + */ +void sde_conn_timeline_status(struct drm_connector *conn); + +/** + * sde_connector_helper_bridge_disable - helper function for drm bridge disable + * @connector: Pointer to DRM connector object + */ +void sde_connector_helper_bridge_disable(struct drm_connector *connector); + +/** + * sde_connector_destroy - destroy drm connector object + * @connector: Pointer to DRM connector object + */ +void sde_connector_destroy(struct drm_connector *connector); + +/** + * sde_connector_event_notify - signal hw recovery event to client + * @connector: pointer to connector + * @type: event type + * @len: length of the value of the event + * @val: value + */ +int sde_connector_event_notify(struct drm_connector *connector, uint32_t type, + uint32_t len, uint32_t val); +/** + * sde_connector_helper_bridge_enable - helper function for drm bridge enable + * @connector: Pointer to DRM connector object + */ +void sde_connector_helper_bridge_enable(struct drm_connector *connector); + +/** + * sde_connector_get_panel_vfp - helper to get panel vfp + * @connector: pointer to drm connector + * @h_active: panel width + * @v_active: panel heigth + * Returns: v_front_porch on success error-code on failure + */ +int sde_connector_get_panel_vfp(struct drm_connector *connector, + struct drm_display_mode *mode); +/** + * sde_connector_esd_status - helper function to check te status + * @connector: Pointer to DRM connector object + */ +int sde_connector_esd_status(struct drm_connector *connector); + +#endif /* _SDE_CONNECTOR_H_ */ diff --git a/techpack/display/msm/sde/sde_core_irq.c b/techpack/display/msm/sde/sde_core_irq.c new file mode 100644 index 0000000000000000000000000000000000000000..5ee1865be6322884ea8d14569b46f1c9c9f2769c --- /dev/null +++ b/techpack/display/msm/sde/sde_core_irq.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> +#include <linux/irqdomain.h> +#include <linux/irq.h> +#include <linux/kthread.h> + +#include "sde_core_irq.h" +#include "sde_power_handle.h" + +/** + * sde_core_irq_callback_handler - dispatch core interrupts + * @arg: private data of callback handler + * @irq_idx: interrupt index + */ +static void sde_core_irq_callback_handler(void *arg, int irq_idx) +{ + struct sde_kms *sde_kms = arg; + struct sde_irq *irq_obj = &sde_kms->irq_obj; + struct sde_irq_callback *cb; + unsigned long irq_flags; + bool cb_tbl_error = false; + int enable_counts = 0; + + pr_debug("irq_idx=%d\n", irq_idx); + + spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); + if (list_empty(&irq_obj->irq_cb_tbl[irq_idx])) { + /* print error outside lock */ + cb_tbl_error = true; + enable_counts = atomic_read( + &sde_kms->irq_obj.enable_counts[irq_idx]); + } + + atomic_inc(&irq_obj->irq_counts[irq_idx]); + + /* + * Perform registered function callback + */ + list_for_each_entry(cb, &irq_obj->irq_cb_tbl[irq_idx], list) + if (cb->func) + cb->func(cb->arg, irq_idx); + spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); + + if (cb_tbl_error) { + /* + * If enable count is zero and callback list is empty, then it's + * not a fatal issue. Log this case as debug. If the enable + * count is nonzero and callback list is empty, then its a real + * issue. Log this case as error to ensure we don't have silent + * IRQs running. + */ + if (!enable_counts) { + SDE_DEBUG("irq has no callback, idx %d enables %d\n", + irq_idx, enable_counts); + SDE_EVT32_IRQ(irq_idx, enable_counts); + } else { + SDE_ERROR("irq has no callback, idx %d enables %d\n", + irq_idx, enable_counts); + SDE_EVT32_IRQ(irq_idx, enable_counts, SDE_EVTLOG_ERROR); + } + } + + /* + * Clear pending interrupt status in HW. + * NOTE: sde_core_irq_callback_handler is protected by top-level + * spinlock, so it is safe to clear any interrupt status here. + */ + sde_kms->hw_intr->ops.clear_intr_status_nolock( + sde_kms->hw_intr, + irq_idx); +} + +int sde_core_irq_idx_lookup(struct sde_kms *sde_kms, + enum sde_intr_type intr_type, u32 instance_idx) +{ + if (!sde_kms || !sde_kms->hw_intr || + !sde_kms->hw_intr->ops.irq_idx_lookup) + return -EINVAL; + + return sde_kms->hw_intr->ops.irq_idx_lookup( + sde_kms->hw_intr, intr_type, + instance_idx); +} + +/** + * _sde_core_irq_enable - enable core interrupt given by the index + * @sde_kms: Pointer to sde kms context + * @irq_idx: interrupt index + */ +static int _sde_core_irq_enable(struct sde_kms *sde_kms, int irq_idx) +{ + unsigned long irq_flags; + int ret = 0; + + if (!sde_kms || !sde_kms->hw_intr || + !sde_kms->irq_obj.enable_counts || + !sde_kms->irq_obj.irq_counts) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->sde_irq_map_size) { + SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx, + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])); + + SDE_EVT32(irq_idx, + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])); + + if (atomic_inc_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 1) { + spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); + /* empty callback list but interrupt is being enabled */ + if (list_empty(&sde_kms->irq_obj.irq_cb_tbl[irq_idx])) + SDE_ERROR("enabling irq_idx=%d with no callback\n", + irq_idx); + spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); + + spin_lock_irqsave(&sde_kms->hw_intr->irq_lock, irq_flags); + ret = sde_kms->hw_intr->ops.enable_irq_nolock( + sde_kms->hw_intr, irq_idx); + spin_unlock_irqrestore(&sde_kms->hw_intr->irq_lock, irq_flags); + } + + if (ret) + SDE_ERROR("Fail to enable IRQ for irq_idx:%d\n", irq_idx); + + SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret); + + return ret; +} + +int sde_core_irq_enable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count) +{ + int i, ret = 0; + + if (!sde_kms || !irq_idxs || !irq_count) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + for (i = 0; (i < irq_count) && !ret; i++) + ret = _sde_core_irq_enable(sde_kms, irq_idxs[i]); + + return ret; +} + +/** + * _sde_core_irq_disable - disable core interrupt given by the index + * @sde_kms: Pointer to sde kms context + * @irq_idx: interrupt index + */ +static int _sde_core_irq_disable(struct sde_kms *sde_kms, int irq_idx) +{ + int ret = 0; + unsigned long irq_flags; + + if (!sde_kms || !sde_kms->hw_intr || !sde_kms->irq_obj.enable_counts) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->sde_irq_map_size) { + SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx, + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])); + + SDE_EVT32(irq_idx, + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])); + + spin_lock_irqsave(&sde_kms->hw_intr->irq_lock, irq_flags); + if (atomic_add_unless(&sde_kms->irq_obj.enable_counts[irq_idx], -1, 0) + && atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx]) == 0) + ret = sde_kms->hw_intr->ops.disable_irq_nolock( + sde_kms->hw_intr, irq_idx); + spin_unlock_irqrestore(&sde_kms->hw_intr->irq_lock, irq_flags); + + if (ret) + SDE_ERROR("Fail to disable IRQ for irq_idx:%d\n", irq_idx); + SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret); + + return ret; +} + +int sde_core_irq_disable(struct sde_kms *sde_kms, int *irq_idxs, u32 irq_count) +{ + int i, ret = 0; + + if (!sde_kms || !irq_idxs || !irq_count) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + for (i = 0; (i < irq_count) && !ret; i++) + ret = _sde_core_irq_disable(sde_kms, irq_idxs[i]); + + return ret; +} + +/** + * sde_core_irq_disable_nolock - disable core interrupt given by the index + * without lock + * @sde_kms: Pointer to sde kms context + * @irq_idx: interrupt index + */ +int sde_core_irq_disable_nolock(struct sde_kms *sde_kms, int irq_idx) +{ + int ret = 0; + + if (!sde_kms || !sde_kms->hw_intr || !sde_kms->irq_obj.enable_counts) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->sde_irq_map_size) { + SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + SDE_DEBUG("irq_idx=%d enable_count=%d\n", irq_idx, + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])); + + SDE_EVT32(irq_idx, + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])); + if (atomic_dec_return(&sde_kms->irq_obj.enable_counts[irq_idx]) == 0) { + ret = sde_kms->hw_intr->ops.disable_irq_nolock( + sde_kms->hw_intr, + irq_idx); + if (ret) + SDE_ERROR("Fail to disable IRQ for irq_idx:%d\n", + irq_idx); + SDE_DEBUG("irq_idx=%d ret=%d\n", irq_idx, ret); + } + + return ret; +} + +u32 sde_core_irq_read_nolock(struct sde_kms *sde_kms, int irq_idx, bool clear) +{ + if (!sde_kms || !sde_kms->hw_intr || + !sde_kms->hw_intr->ops.get_interrupt_status) + return 0; + + if (irq_idx < 0) { + SDE_ERROR("[%pS] invalid irq_idx=%d\n", + __builtin_return_address(0), irq_idx); + return 0; + } + + return sde_kms->hw_intr->ops.get_intr_status_nolock(sde_kms->hw_intr, + irq_idx, clear); +} + +u32 sde_core_irq_read(struct sde_kms *sde_kms, int irq_idx, bool clear) +{ + if (!sde_kms || !sde_kms->hw_intr || + !sde_kms->hw_intr->ops.get_interrupt_status) + return 0; + + if (irq_idx < 0) { + SDE_ERROR("[%pS] invalid irq_idx=%d\n", + __builtin_return_address(0), irq_idx); + return 0; + } + + return sde_kms->hw_intr->ops.get_interrupt_status(sde_kms->hw_intr, + irq_idx, clear); +} + +int sde_core_irq_register_callback(struct sde_kms *sde_kms, int irq_idx, + struct sde_irq_callback *register_irq_cb) +{ + unsigned long irq_flags; + + if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + if (!register_irq_cb || !register_irq_cb->func) { + SDE_ERROR("invalid irq_cb:%d func:%d\n", + register_irq_cb != NULL, + register_irq_cb ? + register_irq_cb->func != NULL : -1); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->sde_irq_map_size) { + SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + SDE_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); + + spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); + SDE_EVT32(irq_idx, register_irq_cb); + list_del_init(®ister_irq_cb->list); + list_add_tail(®ister_irq_cb->list, + &sde_kms->irq_obj.irq_cb_tbl[irq_idx]); + spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); + + return 0; +} + +int sde_core_irq_unregister_callback(struct sde_kms *sde_kms, int irq_idx, + struct sde_irq_callback *register_irq_cb) +{ + unsigned long irq_flags; + + if (!sde_kms || !sde_kms->irq_obj.irq_cb_tbl) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + if (!register_irq_cb || !register_irq_cb->func) { + SDE_ERROR("invalid irq_cb:%d func:%d\n", + register_irq_cb != NULL, + register_irq_cb ? + register_irq_cb->func != NULL : -1); + return -EINVAL; + } + + if (irq_idx < 0 || irq_idx >= sde_kms->hw_intr->sde_irq_map_size) { + SDE_ERROR("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + SDE_DEBUG("[%pS] irq_idx=%d\n", __builtin_return_address(0), irq_idx); + + spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); + SDE_EVT32(irq_idx, register_irq_cb); + list_del_init(®ister_irq_cb->list); + /* empty callback list but interrupt is still enabled */ + if (list_empty(&sde_kms->irq_obj.irq_cb_tbl[irq_idx]) && + atomic_read(&sde_kms->irq_obj.enable_counts[irq_idx])) + SDE_ERROR("irq_idx=%d enabled with no callback\n", irq_idx); + spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); + + return 0; +} + +static void sde_clear_all_irqs(struct sde_kms *sde_kms) +{ + if (!sde_kms || !sde_kms->hw_intr || + !sde_kms->hw_intr->ops.clear_all_irqs) + return; + + sde_kms->hw_intr->ops.clear_all_irqs(sde_kms->hw_intr); +} + +static void sde_disable_all_irqs(struct sde_kms *sde_kms) +{ + if (!sde_kms || !sde_kms->hw_intr || + !sde_kms->hw_intr->ops.disable_all_irqs) + return; + + sde_kms->hw_intr->ops.disable_all_irqs(sde_kms->hw_intr); +} + +#ifdef CONFIG_DEBUG_FS +#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix) \ +static int __prefix ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __prefix ## _show, inode->i_private); \ +} \ +static const struct file_operations __prefix ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __prefix ## _open, \ + .release = single_release, \ + .read = seq_read, \ + .llseek = seq_lseek, \ +} + +static int sde_debugfs_core_irq_show(struct seq_file *s, void *v) +{ + struct sde_irq *irq_obj = s->private; + struct sde_irq_callback *cb; + unsigned long irq_flags; + int i, irq_count, enable_count, cb_count; + + if (!irq_obj || !irq_obj->enable_counts || !irq_obj->irq_cb_tbl) { + SDE_ERROR("invalid parameters\n"); + return 0; + } + + for (i = 0; i < irq_obj->total_irqs; i++) { + spin_lock_irqsave(&irq_obj->cb_lock, irq_flags); + cb_count = 0; + irq_count = atomic_read(&irq_obj->irq_counts[i]); + enable_count = atomic_read(&irq_obj->enable_counts[i]); + list_for_each_entry(cb, &irq_obj->irq_cb_tbl[i], list) + cb_count++; + spin_unlock_irqrestore(&irq_obj->cb_lock, irq_flags); + + if (irq_count || enable_count || cb_count) + seq_printf(s, "idx:%d irq:%d enable:%d cb:%d\n", + i, irq_count, enable_count, cb_count); + } + + return 0; +} + +DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_debugfs_core_irq); + +int sde_debugfs_core_irq_init(struct sde_kms *sde_kms, + struct dentry *parent) +{ + sde_kms->irq_obj.debugfs_file = debugfs_create_file("core_irq", 0400, + parent, &sde_kms->irq_obj, + &sde_debugfs_core_irq_fops); + + return 0; +} + +void sde_debugfs_core_irq_destroy(struct sde_kms *sde_kms) +{ + debugfs_remove(sde_kms->irq_obj.debugfs_file); + sde_kms->irq_obj.debugfs_file = NULL; +} + +#else +int sde_debugfs_core_irq_init(struct sde_kms *sde_kms, + struct dentry *parent) +{ + return 0; +} + +void sde_debugfs_core_irq_destroy(struct sde_kms *sde_kms) +{ +} +#endif + +void sde_core_irq_preinstall(struct sde_kms *sde_kms) +{ + int i; + int rc; + + if (!sde_kms || !sde_kms->dev) { + SDE_ERROR("invalid sde_kms or dev\n"); + return; + } + + rc = pm_runtime_get_sync(sde_kms->dev->dev); + if (rc < 0) { + SDE_ERROR("failed to enable power resource %d\n", rc); + SDE_EVT32(rc, SDE_EVTLOG_ERROR); + return; + } + + sde_clear_all_irqs(sde_kms); + sde_disable_all_irqs(sde_kms); + pm_runtime_put_sync(sde_kms->dev->dev); + + spin_lock_init(&sde_kms->irq_obj.cb_lock); + + /* Create irq callbacks for all possible irq_idx */ + sde_kms->irq_obj.total_irqs = sde_kms->hw_intr->sde_irq_map_size; + sde_kms->irq_obj.irq_cb_tbl = kcalloc(sde_kms->irq_obj.total_irqs, + sizeof(struct list_head), GFP_KERNEL); + sde_kms->irq_obj.enable_counts = kcalloc(sde_kms->irq_obj.total_irqs, + sizeof(atomic_t), GFP_KERNEL); + sde_kms->irq_obj.irq_counts = kcalloc(sde_kms->irq_obj.total_irqs, + sizeof(atomic_t), GFP_KERNEL); + if (!sde_kms->irq_obj.irq_cb_tbl || !sde_kms->irq_obj.enable_counts + || !sde_kms->irq_obj.irq_counts) + return; + + for (i = 0; i < sde_kms->irq_obj.total_irqs; i++) { + if (sde_kms->irq_obj.irq_cb_tbl) + INIT_LIST_HEAD(&sde_kms->irq_obj.irq_cb_tbl[i]); + if (sde_kms->irq_obj.enable_counts) + atomic_set(&sde_kms->irq_obj.enable_counts[i], 0); + if (sde_kms->irq_obj.irq_counts) + atomic_set(&sde_kms->irq_obj.irq_counts[i], 0); + } +} + +int sde_core_irq_postinstall(struct sde_kms *sde_kms) +{ + return 0; +} + +void sde_core_irq_uninstall(struct sde_kms *sde_kms) +{ + int i; + int rc; + unsigned long irq_flags; + + if (!sde_kms || !sde_kms->dev) { + SDE_ERROR("invalid sde_kms or dev\n"); + return; + } + + rc = pm_runtime_get_sync(sde_kms->dev->dev); + if (rc < 0) { + SDE_ERROR("failed to enable power resource %d\n", rc); + SDE_EVT32(rc, SDE_EVTLOG_ERROR); + return; + } + + for (i = 0; i < sde_kms->irq_obj.total_irqs; i++) + if (atomic_read(&sde_kms->irq_obj.enable_counts[i]) || + !list_empty(&sde_kms->irq_obj.irq_cb_tbl[i])) + SDE_ERROR("irq_idx=%d still enabled/registered\n", i); + + sde_clear_all_irqs(sde_kms); + sde_disable_all_irqs(sde_kms); + pm_runtime_put_sync(sde_kms->dev->dev); + + spin_lock_irqsave(&sde_kms->irq_obj.cb_lock, irq_flags); + kfree(sde_kms->irq_obj.irq_cb_tbl); + kfree(sde_kms->irq_obj.enable_counts); + kfree(sde_kms->irq_obj.irq_counts); + sde_kms->irq_obj.irq_cb_tbl = NULL; + sde_kms->irq_obj.enable_counts = NULL; + sde_kms->irq_obj.irq_counts = NULL; + sde_kms->irq_obj.total_irqs = 0; + spin_unlock_irqrestore(&sde_kms->irq_obj.cb_lock, irq_flags); +} + +static void sde_core_irq_mask(struct irq_data *irqd) +{ + struct sde_kms *sde_kms; + + if (!irqd || !irq_data_get_irq_chip_data(irqd)) { + SDE_ERROR("invalid parameters irqd %d\n", irqd != NULL); + return; + } + sde_kms = irq_data_get_irq_chip_data(irqd); + + /* memory barrier */ + smp_mb__before_atomic(); + clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); + /* memory barrier */ + smp_mb__after_atomic(); +} + +static void sde_core_irq_unmask(struct irq_data *irqd) +{ + struct sde_kms *sde_kms; + + if (!irqd || !irq_data_get_irq_chip_data(irqd)) { + SDE_ERROR("invalid parameters irqd %d\n", irqd != NULL); + return; + } + sde_kms = irq_data_get_irq_chip_data(irqd); + + /* memory barrier */ + smp_mb__before_atomic(); + set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask); + /* memory barrier */ + smp_mb__after_atomic(); +} + +static struct irq_chip sde_core_irq_chip = { + .name = "sde", + .irq_mask = sde_core_irq_mask, + .irq_unmask = sde_core_irq_unmask, +}; + +static int sde_core_irqdomain_map(struct irq_domain *domain, + unsigned int irq, irq_hw_number_t hwirq) +{ + struct sde_kms *sde_kms; + int rc; + + if (!domain || !domain->host_data) { + SDE_ERROR("invalid parameters domain %d\n", domain != NULL); + return -EINVAL; + } + sde_kms = domain->host_data; + + irq_set_chip_and_handler(irq, &sde_core_irq_chip, handle_level_irq); + rc = irq_set_chip_data(irq, sde_kms); + + return rc; +} + +static const struct irq_domain_ops sde_core_irqdomain_ops = { + .map = sde_core_irqdomain_map, + .xlate = irq_domain_xlate_onecell, +}; + +int sde_core_irq_domain_add(struct sde_kms *sde_kms) +{ + struct device *dev; + struct irq_domain *domain; + + if (!sde_kms->dev || !sde_kms->dev->dev) { + pr_err("invalid device handles\n"); + return -EINVAL; + } + + dev = sde_kms->dev->dev; + + domain = irq_domain_add_linear(dev->of_node, 32, + &sde_core_irqdomain_ops, sde_kms); + if (!domain) { + pr_err("failed to add irq_domain\n"); + return -EINVAL; + } + + sde_kms->irq_controller.enabled_mask = 0; + sde_kms->irq_controller.domain = domain; + + return 0; +} + +int sde_core_irq_domain_fini(struct sde_kms *sde_kms) +{ + if (sde_kms->irq_controller.domain) { + irq_domain_remove(sde_kms->irq_controller.domain); + sde_kms->irq_controller.domain = NULL; + } + return 0; +} + +irqreturn_t sde_core_irq(struct sde_kms *sde_kms) +{ + /* + * Read interrupt status from all sources. Interrupt status are + * stored within hw_intr. + * Function will also clear the interrupt status after reading. + * Individual interrupt status bit will only get stored if it + * is enabled. + */ + sde_kms->hw_intr->ops.get_interrupt_statuses(sde_kms->hw_intr); + + /* + * Dispatch to HW driver to handle interrupt lookup that is being + * fired. When matching interrupt is located, HW driver will call to + * sde_core_irq_callback_handler with the irq_idx from the lookup table. + * sde_core_irq_callback_handler will perform the registered function + * callback, and do the interrupt status clearing once the registered + * callback is finished. + */ + sde_kms->hw_intr->ops.dispatch_irqs( + sde_kms->hw_intr, + sde_core_irq_callback_handler, + sde_kms); + + return IRQ_HANDLED; +} diff --git a/techpack/display/msm/sde/sde_core_irq.h b/techpack/display/msm/sde/sde_core_irq.h new file mode 100644 index 0000000000000000000000000000000000000000..ce27b20ee6c138777d08f1190dc0d266f1bfca53 --- /dev/null +++ b/techpack/display/msm/sde/sde_core_irq.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_CORE_IRQ_H__ +#define __SDE_CORE_IRQ_H__ + +#include "sde_kms.h" +#include "sde_hw_interrupts.h" + +/** + * sde_core_irq_preinstall - perform pre-installation of core IRQ handler + * @sde_kms: SDE handle + * @return: none + */ +void sde_core_irq_preinstall(struct sde_kms *sde_kms); + +/** + * sde_core_irq_postinstall - perform post-installation of core IRQ handler + * @sde_kms: SDE handle + * @return: 0 if success; error code otherwise + */ +int sde_core_irq_postinstall(struct sde_kms *sde_kms); + +/** + * sde_core_irq_uninstall - uninstall core IRQ handler + * @sde_kms: SDE handle + * @return: none + */ +void sde_core_irq_uninstall(struct sde_kms *sde_kms); + +/** + * sde_core_irq_domain_add - Add core IRQ domain for SDE + * @sde_kms: SDE handle + * @return: none + */ +int sde_core_irq_domain_add(struct sde_kms *sde_kms); + +/** + * sde_core_irq_domain_fini - uninstall core IRQ domain + * @sde_kms: SDE handle + * @return: 0 if success; error code otherwise + */ +int sde_core_irq_domain_fini(struct sde_kms *sde_kms); + +/** + * sde_core_irq - core IRQ handler + * @sde_kms: SDE handle + * @return: interrupt handling status + */ +irqreturn_t sde_core_irq(struct sde_kms *sde_kms); + +/** + * sde_core_irq_idx_lookup - IRQ helper function for lookup irq_idx from HW + * interrupt mapping table. + * @sde_kms: SDE handle + * @intr_type: SDE HW interrupt type for lookup + * @instance_idx: SDE HW block instance defined in sde_hw_mdss.h + * @return: irq_idx or -EINVAL when fail to lookup + */ +int sde_core_irq_idx_lookup( + struct sde_kms *sde_kms, + enum sde_intr_type intr_type, + uint32_t instance_idx); + +/** + * sde_core_irq_enable - IRQ helper function for enabling one or more IRQs + * @sde_kms: SDE handle + * @irq_idxs: Array of irq index + * @irq_count: Number of irq_idx provided in the array + * @return: 0 for success enabling IRQ, otherwise failure + * + * This function increments count on each enable and decrements on each + * disable. Interrupts is enabled if count is 0 before increment. + */ +int sde_core_irq_enable( + struct sde_kms *sde_kms, + int *irq_idxs, + uint32_t irq_count); + +/** + * sde_core_irq_disable - IRQ helper function for disabling one of more IRQs + * @sde_kms: SDE handle + * @irq_idxs: Array of irq index + * @irq_count: Number of irq_idx provided in the array + * @return: 0 for success disabling IRQ, otherwise failure + * + * This function increments count on each enable and decrements on each + * disable. Interrupts is disabled if count is 0 after decrement. + */ +int sde_core_irq_disable( + struct sde_kms *sde_kms, + int *irq_idxs, + uint32_t irq_count); + +/** + * sde_core_irq_disable_nolock - no lock version of sde_core_irq_disable + * @sde_kms: SDE handle + * @irq_idx: Irq index + * @return: 0 for success disabling IRQ, otherwise failure + * + * This function increments count on each enable and decrements on each + * disable. Interrupts is disabled if count is 0 after decrement. + */ +int sde_core_irq_disable_nolock( + struct sde_kms *sde_kms, + int irq_idx); + +/** + * sde_core_irq_read - IRQ helper function for reading IRQ status + * @sde_kms: SDE handle + * @irq_idx: irq index + * @clear: True to clear the irq after read + * @return: non-zero if irq detected; otherwise no irq detected + */ +u32 sde_core_irq_read( + struct sde_kms *sde_kms, + int irq_idx, + bool clear); + +/** + * sde_core_irq_read - no lock version of sde_core_irq_read + * @sde_kms: SDE handle + * @irq_idx: irq index + * @clear: True to clear the irq after read + * @return: non-zero if irq detected; otherwise no irq detected + */ +u32 sde_core_irq_read_nolock( + struct sde_kms *sde_kms, + int irq_idx, + bool clear); + +/** + * sde_core_irq_register_callback - For registering callback function on IRQ + * interrupt + * @sde_kms: SDE handle + * @irq_idx: irq index + * @irq_cb: IRQ callback structure, containing callback function + * and argument. Passing NULL for irq_cb will unregister + * the callback for the given irq_idx + * This must exist until un-registration. + * @return: 0 for success registering callback, otherwise failure + * + * This function supports registration of multiple callbacks for each interrupt. + */ +int sde_core_irq_register_callback( + struct sde_kms *sde_kms, + int irq_idx, + struct sde_irq_callback *irq_cb); + +/** + * sde_core_irq_unregister_callback - For unregistering callback function on IRQ + * interrupt + * @sde_kms: SDE handle + * @irq_idx: irq index + * @irq_cb: IRQ callback structure, containing callback function + * and argument. Passing NULL for irq_cb will unregister + * the callback for the given irq_idx + * This must match with registration. + * @return: 0 for success registering callback, otherwise failure + * + * This function supports registration of multiple callbacks for each interrupt. + */ +int sde_core_irq_unregister_callback( + struct sde_kms *sde_kms, + int irq_idx, + struct sde_irq_callback *irq_cb); + +/** + * sde_debugfs_core_irq_init - register core irq debugfs + * @sde_kms: pointer to kms + * @parent: debugfs directory root + * @Return: 0 on success + */ +int sde_debugfs_core_irq_init(struct sde_kms *sde_kms, + struct dentry *parent); + +/** + * sde_debugfs_core_irq_destroy - deregister core irq debugfs + * @sde_kms: pointer to kms + */ +void sde_debugfs_core_irq_destroy(struct sde_kms *sde_kms); + +#endif /* __SDE_CORE_IRQ_H__ */ diff --git a/techpack/display/msm/sde/sde_core_perf.c b/techpack/display/msm/sde/sde_core_perf.c new file mode 100644 index 0000000000000000000000000000000000000000..3add93d9a61e3a109945b36ac39966ff999717f5 --- /dev/null +++ b/techpack/display/msm/sde/sde_core_perf.c @@ -0,0 +1,1320 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/sort.h> +#include <linux/clk.h> +#include <linux/bitmap.h> +#include <linux/sde_rsc.h> +#include <linux/platform_device.h> +#include <linux/soc/qcom/llcc-qcom.h> + +#include "msm_prop.h" + +#include "sde_kms.h" +#include "sde_trace.h" +#include "sde_crtc.h" +#include "sde_encoder.h" +#include "sde_core_perf.h" + +#define SDE_PERF_MODE_STRING_SIZE 128 +#define SDE_PERF_THRESHOLD_HIGH_MIN 12800000 + +#define GET_H32(val) (val >> 32) +#define GET_L32(val) (val & 0xffffffff) + +static DEFINE_MUTEX(sde_core_perf_lock); + +/** + * enum sde_perf_mode - performance tuning mode + * @SDE_PERF_MODE_NORMAL: performance controlled by user mode client + * @SDE_PERF_MODE_MINIMUM: performance bounded by minimum setting + * @SDE_PERF_MODE_FIXED: performance bounded by fixed setting + */ +enum sde_perf_mode { + SDE_PERF_MODE_NORMAL, + SDE_PERF_MODE_MINIMUM, + SDE_PERF_MODE_FIXED, + SDE_PERF_MODE_MAX +}; + +/** + * enum sde_perf_vote_mode: perf vote mode. + * @APPS_RSC_MODE: It combines the vote for all displays and votes it + * through APPS rsc. This is default mode when display + * rsc is not available. + * @DISP_RSC_MODE: It combines the vote for all displays and votes it + * through display rsc. This is default configuration + * when display rsc is available. + * @DISP_RSC_PRIMARY_MODE: The primary display votes through display rsc + * while all other displays votes through apps rsc. + */ +enum sde_perf_vote_mode { + APPS_RSC_MODE, + DISP_RSC_MODE, + DISP_RSC_PRIMARY_MODE, +}; + +static struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + + if (!crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid device\n"); + return NULL; + } + + priv = crtc->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid kms\n"); + return NULL; + } + + return to_sde_kms(priv->kms); +} + +static bool _sde_core_perf_crtc_is_power_on(struct drm_crtc *crtc) +{ + return sde_crtc_is_enabled(crtc); +} + +static void _sde_core_perf_calc_doze_suspend(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct sde_core_perf_params *perf) +{ + struct sde_crtc_state *new_cstate, *old_cstate; + struct sde_core_perf_params *old_perf; + struct drm_connector *conn = NULL; + struct sde_connector *c_conn = NULL; + bool is_doze_suspend = false; + int i; + + if (!crtc || !crtc->state || !state) + return; + + old_cstate = to_sde_crtc_state(crtc->state); + new_cstate = to_sde_crtc_state(state); + old_perf = &old_cstate->new_perf; + + if (!old_perf) + return; + + if (!perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC] && + !perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC] && + state->plane_mask) { + + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC] = + old_perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC]; + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC] = + old_perf->max_per_pipe_ib + [SDE_POWER_HANDLE_DBUS_ID_MNOC]; + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC] = + old_perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC]; + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC] = + old_perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC]; + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI] = + old_perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI]; + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI] = + old_perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI]; + + if (!old_perf->core_clk_rate) + perf->core_clk_rate = old_perf->core_clk_rate; + + for (i = 0; i < new_cstate->num_connectors; i++) { + conn = new_cstate->connectors[i]; + if (!conn) + continue; + c_conn = to_sde_connector(conn); + if ((c_conn->dpms_mode == DRM_MODE_DPMS_ON) && + (sde_connector_get_lp(conn) == SDE_MODE_DPMS_LP2)) + is_doze_suspend = true; + } + + if (!is_doze_suspend && conn && c_conn) + SDE_ERROR("No BW, planes:%x dpms_mode:%d lpmode:%d\n", + state->plane_mask, c_conn->dpms_mode, + sde_connector_get_lp(conn)); + if (conn && c_conn) + SDE_EVT32(state->plane_mask, c_conn->dpms_mode, + sde_connector_get_lp(conn), is_doze_suspend, + SDE_EVTLOG_ERROR); + } +} + +static void _sde_core_perf_calc_crtc(struct sde_kms *kms, + struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct sde_core_perf_params *perf) +{ + struct sde_crtc_state *sde_cstate; + int i; + + if (!kms || !kms->catalog || !crtc || !state || !perf) { + SDE_ERROR("invalid parameters\n"); + return; + } + + sde_cstate = to_sde_crtc_state(state); + memset(perf, 0, sizeof(struct sde_core_perf_params)); + + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB); + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_IB); + + if (sde_cstate->bw_split_vote) { + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_LLCC_AB); + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_LLCC_IB); + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_DRAM_AB); + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_DRAM_IB); + } else { + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB); + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_IB); + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_AB); + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI] = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_IB); + } + + perf->core_clk_rate = + sde_crtc_get_property(sde_cstate, CRTC_PROP_CORE_CLK); + + _sde_core_perf_calc_doze_suspend(crtc, state, perf); + + if (!sde_cstate->bw_control) { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + perf->bw_ctl[i] = kms->catalog->perf.max_bw_high * + 1000ULL; + perf->max_per_pipe_ib[i] = perf->bw_ctl[i]; + } + perf->core_clk_rate = kms->perf.max_core_clk_rate; + } else if (kms->perf.perf_tune.mode == SDE_PERF_MODE_MINIMUM) { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + perf->bw_ctl[i] = 0; + perf->max_per_pipe_ib[i] = 0; + } + perf->core_clk_rate = 0; + } else if (kms->perf.perf_tune.mode == SDE_PERF_MODE_FIXED) { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + perf->bw_ctl[i] = max(kms->perf.fix_core_ab_vote, + perf->bw_ctl[i]); + perf->max_per_pipe_ib[i] = max( + kms->perf.fix_core_ib_vote, + perf->max_per_pipe_ib[i]); + } + perf->core_clk_rate = max(kms->perf.fix_core_clk_rate, + perf->core_clk_rate); + } + + SDE_EVT32(DRMID(crtc), perf->core_clk_rate, + GET_H32(perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC]), + GET_L32(perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC]), + GET_H32(perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC]), + GET_L32(perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC]), + GET_H32(perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI]), + GET_L32(perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI])); + SDE_EVT32(DRMID(crtc), + GET_H32(perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC]), + GET_L32(perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC]), + GET_H32(perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC]), + GET_L32(perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC]), + GET_H32(perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI]), + GET_L32(perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI])); + trace_sde_perf_calc_crtc(crtc->base.id, + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC], + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC], + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI], + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC], + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC], + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI], + perf->core_clk_rate); + + SDE_DEBUG( + "crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n", + crtc->base.id, perf->core_clk_rate, + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC], + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC], + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC], + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC], + perf->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI], + perf->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI]); +} + +int sde_core_perf_crtc_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + u32 bw, threshold; + u64 bw_sum_of_intfs = 0; + enum sde_crtc_client_type curr_client_type; + struct sde_crtc_state *sde_cstate; + struct drm_crtc *tmp_crtc; + struct sde_kms *kms; + int i; + + if (!crtc || !state) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid parameters\n"); + return 0; + } + + sde_cstate = to_sde_crtc_state(state); + + /* obtain new values */ + _sde_core_perf_calc_crtc(kms, crtc, state, &sde_cstate->new_perf); + + for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC; + i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + bw_sum_of_intfs = sde_cstate->new_perf.bw_ctl[i]; + curr_client_type = sde_crtc_get_client_type(crtc); + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_sde_core_perf_crtc_is_power_on(tmp_crtc) && + (sde_crtc_get_client_type(tmp_crtc) == + curr_client_type) && + (tmp_crtc != crtc)) { + struct sde_crtc_state *tmp_cstate = + to_sde_crtc_state(tmp_crtc->state); + + SDE_DEBUG("crtc:%d bw:%llu ctrl:%d\n", + tmp_crtc->base.id, + tmp_cstate->new_perf.bw_ctl[i], + tmp_cstate->bw_control); + /* + * For bw check only use the bw if the + * atomic property has been already set + */ + if (tmp_cstate->bw_control) + bw_sum_of_intfs += + tmp_cstate->new_perf.bw_ctl[i]; + } + } + + /* convert bandwidth to kb */ + bw = DIV_ROUND_UP_ULL(bw_sum_of_intfs, 1000); + SDE_DEBUG("calculated bandwidth=%uk\n", bw); + + threshold = kms->catalog->perf.max_bw_high; + + SDE_DEBUG("final threshold bw limit = %d\n", threshold); + + if (!sde_cstate->bw_control) { + SDE_DEBUG("bypass bandwidth check\n"); + } else if (!threshold) { + SDE_ERROR("no bandwidth limits specified\n"); + return -E2BIG; + } else if (bw > threshold) { + SDE_ERROR("exceeds bandwidth: %ukb > %ukb\n", bw, + threshold); + return -E2BIG; + } + } + + return 0; +} + +static inline bool _is_crtc_client_type_matches(struct drm_crtc *tmp_crtc, + enum sde_crtc_client_type curr_client_type, + struct sde_core_perf *perf) +{ + if (!tmp_crtc) + return false; + else if (perf->bw_vote_mode == DISP_RSC_PRIMARY_MODE && + perf->sde_rsc_available) + return curr_client_type == sde_crtc_get_client_type(tmp_crtc); + else + return true; +} + +static inline enum sde_crtc_client_type _get_sde_client_type( + enum sde_crtc_client_type curr_client_type, + struct sde_core_perf *perf) +{ + if (perf->bw_vote_mode == DISP_RSC_PRIMARY_MODE && + perf->sde_rsc_available) + return curr_client_type; + else if (perf->bw_vote_mode != APPS_RSC_MODE && perf->sde_rsc_available) + return RT_RSC_CLIENT; + else + return RT_CLIENT; +} + +/** + * @_sde_core_perf_activate_llcc() - Activates/deactivates the system llcc + * @kms - pointer to the kms + * @uid - ID for which the llcc would be activated + * @activate - boolean to indicate if activate/deactivate the LLCC + * + * Function assumes that caller has already acquired the "sde_core_perf_lock", + * which would protect from any race condition between CRTC's + */ +static int _sde_core_perf_activate_llcc(struct sde_kms *kms, + u32 uid, bool activate) +{ + struct llcc_slice_desc *slice; + struct drm_device *drm_dev; + struct device *dev; + struct platform_device *pdev; + int rc = 0; + + if (!kms || !kms->dev || !kms->dev->dev) { + SDE_ERROR("wrong params won't activate llcc\n"); + rc = -EINVAL; + goto exit; + } + + drm_dev = kms->dev; + dev = drm_dev->dev; + pdev = to_platform_device(dev); + + /* If LLCC is already in the requested state, skip */ + SDE_EVT32(activate, kms->perf.llcc_active); + if ((activate && kms->perf.llcc_active) || + (!activate && !kms->perf.llcc_active)) { + SDE_DEBUG("skip llcc request:%d state:%d\n", + activate, kms->perf.llcc_active); + goto exit; + } + + SDE_DEBUG("activate/deactivate the llcc request:%d state:%d\n", + activate, kms->perf.llcc_active); + + slice = llcc_slice_getd(uid); + if (IS_ERR_OR_NULL(slice)) { + SDE_ERROR("failed to get llcc slice for uid:%d\n", uid); + rc = -EINVAL; + goto exit; + } + + if (activate) { + llcc_slice_activate(slice); + kms->perf.llcc_active = true; + } else { + llcc_slice_deactivate(slice); + kms->perf.llcc_active = false; + } + +exit: + if (rc) + SDE_ERROR("error activating llcc:%d rc:%d\n", + activate, rc); + return rc; + +} + +static void _sde_core_perf_crtc_update_llcc(struct sde_kms *kms, + struct drm_crtc *crtc) +{ + struct drm_crtc *tmp_crtc; + struct sde_crtc *sde_crtc; + enum sde_crtc_client_type curr_client_type + = sde_crtc_get_client_type(crtc); + u32 total_llcc_active = 0; + + if (!kms->perf.catalog->sc_cfg.has_sys_cache) { + SDE_DEBUG("System Cache is not enabled!. Won't use\n"); + return; + } + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_sde_core_perf_crtc_is_power_on(tmp_crtc) && + _is_crtc_client_type_matches(tmp_crtc, curr_client_type, + &kms->perf)) { + + /* use current perf, which are the values voted */ + sde_crtc = to_sde_crtc(tmp_crtc); + total_llcc_active |= + sde_crtc->cur_perf.llcc_active; + + SDE_DEBUG("crtc=%d llcc:%u active:0x%x\n", + tmp_crtc->base.id, + sde_crtc->cur_perf.llcc_active, + total_llcc_active); + + if (total_llcc_active) + break; + } + } + + _sde_core_perf_activate_llcc(kms, LLCC_ROTATOR, + total_llcc_active ? true : false); +} + +static void _sde_core_uidle_setup_wd(struct sde_kms *kms, + bool enable) +{ + struct sde_uidle_wd_cfg wd; + struct sde_hw_uidle *uidle; + + uidle = kms->hw_uidle; + wd.enable = enable; + wd.clear = false; + wd.granularity = SDE_UIDLE_WD_GRANULARITY; + wd.heart_beat = SDE_UIDLE_WD_HEART_BEAT; + wd.load_value = SDE_UIDLE_WD_LOAD_VAL; + + if (uidle->ops.setup_wd_timer) + uidle->ops.setup_wd_timer(uidle, &wd); +} + +static void _sde_core_uidle_setup_cfg(struct sde_kms *kms, + bool enable) +{ + struct sde_uidle_ctl_cfg cfg; + struct sde_hw_uidle *uidle; + + uidle = kms->hw_uidle; + cfg.uidle_enable = enable; + cfg.fal10_danger = + kms->catalog->uidle_cfg.fal10_danger; + cfg.fal10_exit_cnt = + kms->catalog->uidle_cfg.fal10_exit_cnt; + cfg.fal10_exit_danger = + kms->catalog->uidle_cfg.fal10_exit_danger; + + SDE_DEBUG("fal10_danger:%d fal10_exit_cnt:%d fal10_exit_danger:%d\n", + cfg.fal10_danger, cfg.fal10_exit_cnt, cfg.fal10_exit_danger); + SDE_EVT32(enable, cfg.fal10_danger, cfg.fal10_exit_cnt, + cfg.fal10_exit_danger); + + if (uidle->ops.set_uidle_ctl) + uidle->ops.set_uidle_ctl(uidle, &cfg); +} + +static void _sde_core_uidle_setup_ctl(struct drm_crtc *crtc, + bool enable) +{ + struct drm_encoder *drm_enc; + + /* Disable uidle in the CTL */ + drm_for_each_encoder(drm_enc, crtc->dev) { + if (drm_enc->crtc != crtc) + continue; + + sde_encoder_uidle_enable(drm_enc, enable); + } +} + +static int _sde_core_perf_enable_uidle(struct sde_kms *kms, + struct drm_crtc *crtc, bool enable) +{ + int rc = 0; + + if (!kms->dev || !kms->dev->dev || !kms->hw_uidle) { + SDE_ERROR("wrong params won't enable uidlen"); + rc = -EINVAL; + goto exit; + } + + SDE_EVT32(enable); + _sde_core_uidle_setup_wd(kms, enable); + _sde_core_uidle_setup_cfg(kms, enable); + _sde_core_uidle_setup_ctl(crtc, enable); + + kms->perf.uidle_enabled = enable; + +exit: + return rc; +} + +static inline bool _sde_core_perf_is_wb(struct drm_crtc *crtc) +{ + enum sde_intf_mode if_mode = INTF_MODE_NONE; + + if_mode = sde_crtc_get_intf_mode(crtc, crtc->state); + if (if_mode == INTF_MODE_WB_BLOCK || + if_mode == INTF_MODE_WB_LINE) + return true; + + return false; +} + +static bool _sde_core_perf_is_cwb(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + + /* if any other encoder is connected to same crtc in clone mode */ + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc == crtc && + sde_encoder_in_clone_mode(encoder)) { + return true; + } + } + + return false; +} + +static void _sde_core_perf_uidle_setup_cntr(struct sde_kms *sde_kms, + bool enable) +{ + struct sde_hw_uidle *uidle; + + uidle = sde_kms->hw_uidle; + + SDE_EVT32(enable); + if (uidle->ops.uidle_setup_cntr) { + uidle->ops.uidle_setup_cntr(uidle, enable); + sde_kms->catalog->uidle_cfg.perf_cntr_en = enable; + } +} + +void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, + bool enable) +{ + struct drm_crtc *tmp_crtc; + struct sde_kms *kms; + bool disable_uidle = false; + u32 fps; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return; + } + + mutex_lock(&sde_core_perf_lock); + + if (!kms->perf.catalog->uidle_cfg.uidle_rev || + (enable && !kms->perf.catalog->uidle_cfg.debugfs_ctrl)) { + SDE_DEBUG("uidle is not enabled %d %d\n", + kms->perf.catalog->uidle_cfg.uidle_rev, + kms->perf.catalog->uidle_cfg.debugfs_ctrl); + goto exit; + } + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) { + + fps = sde_crtc_get_fps_mode(tmp_crtc); + + SDE_DEBUG("crtc=%d fps:%d wb:%d cwb:%d dis:%d en:%d\n", + tmp_crtc->base.id, fps, + _sde_core_perf_is_wb(tmp_crtc), + _sde_core_perf_is_cwb(tmp_crtc), + disable_uidle, enable); + + if (_sde_core_perf_is_wb(tmp_crtc) || + _sde_core_perf_is_cwb(tmp_crtc) || (!fps || + fps > kms->perf.catalog->uidle_cfg.max_fps)) { + disable_uidle = true; + break; + } + } + } + + _sde_core_perf_enable_uidle(kms, crtc, + (enable && !disable_uidle) ? true : false); + + /* If perf counters enabled, set them up now */ + if (kms->catalog->uidle_cfg.debugfs_perf) + _sde_core_perf_uidle_setup_cntr(kms, enable); + +exit: + mutex_unlock(&sde_core_perf_lock); +} + +static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms, + struct drm_crtc *crtc, u32 bus_id) +{ + u64 bw_sum_of_intfs = 0, bus_ab_quota, bus_ib_quota; + struct sde_core_perf_params perf = { { 0 } }; + enum sde_crtc_client_type client_vote, curr_client_type + = sde_crtc_get_client_type(crtc); + struct drm_crtc *tmp_crtc; + struct sde_crtc_state *sde_cstate; + struct msm_drm_private *priv = kms->dev->dev_private; + struct sde_crtc *sde_crtc; + + u64 tmp_max_per_pipe_ib; + u64 tmp_bw_ctl; + + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_sde_core_perf_crtc_is_power_on(tmp_crtc) && + _is_crtc_client_type_matches(tmp_crtc, curr_client_type, + &kms->perf)) { + + /* use current perf, which are the values voted */ + sde_crtc = to_sde_crtc(tmp_crtc); + tmp_max_per_pipe_ib = + sde_crtc->cur_perf.max_per_pipe_ib[bus_id]; + tmp_bw_ctl = + sde_crtc->cur_perf.bw_ctl[bus_id]; + + perf.max_per_pipe_ib[bus_id] = + max(perf.max_per_pipe_ib[bus_id], + tmp_max_per_pipe_ib); + + bw_sum_of_intfs += tmp_bw_ctl; + + SDE_DEBUG("crtc=%d bus_id=%d bw=%llu perf_pipe:%llu\n", + tmp_crtc->base.id, bus_id, + tmp_bw_ctl, tmp_max_per_pipe_ib); + } + } + + bus_ab_quota = max(bw_sum_of_intfs, kms->perf.perf_tune.min_bus_vote); + bus_ib_quota = perf.max_per_pipe_ib[bus_id]; + + if (kms->perf.perf_tune.mode == SDE_PERF_MODE_FIXED) { + bus_ab_quota = max(kms->perf.fix_core_ab_vote, + bus_ab_quota); + bus_ib_quota = max(kms->perf.fix_core_ib_vote, + bus_ib_quota); + } + + client_vote = _get_sde_client_type(curr_client_type, &kms->perf); + switch (client_vote) { + case RT_CLIENT: + sde_power_data_bus_set_quota(&priv->phandle, + bus_id, bus_ab_quota, bus_ib_quota); + SDE_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "rt", + bus_id, bus_ab_quota, bus_ib_quota); + break; + + case RT_RSC_CLIENT: + sde_cstate = to_sde_crtc_state(crtc->state); + sde_rsc_client_vote(sde_cstate->rsc_client, + bus_id, bus_ab_quota, bus_ib_quota); + SDE_DEBUG("client:%s bus_id=%d ab=%llu ib=%llu\n", "rt_rsc", + bus_id, bus_ab_quota, bus_ib_quota); + break; + + default: + SDE_ERROR("invalid client type:%d\n", curr_client_type); + break; + } + + if (kms->perf.bw_vote_mode_updated) { + switch (kms->perf.bw_vote_mode) { + case DISP_RSC_MODE: + sde_power_data_bus_set_quota(&priv->phandle, + bus_id, 0, 0); + kms->perf.bw_vote_mode_updated = false; + break; + + case APPS_RSC_MODE: + sde_cstate = to_sde_crtc_state(crtc->state); + if (sde_cstate->rsc_client) { + sde_rsc_client_vote(sde_cstate->rsc_client, + bus_id, 0, 0); + kms->perf.bw_vote_mode_updated = false; + } + break; + + default: + break; + } + } +} + +/** + * @sde_core_perf_crtc_release_bw() - request zero bandwidth + * @crtc - pointer to a crtc + * + * Function checks a state variable for the crtc, if all pending commit + * requests are done, meaning no more bandwidth is needed, release + * bandwidth request. + */ +void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc) +{ + struct drm_crtc *tmp_crtc; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_cstate; + struct sde_kms *kms; + int i; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + sde_cstate = to_sde_crtc_state(crtc->state); + + /* only do this for command mode rt client (non-rsc client) */ + if ((sde_crtc_get_intf_mode(crtc, crtc->state) != INTF_MODE_CMD) && + (sde_crtc_get_client_type(crtc) != RT_RSC_CLIENT)) + return; + + /* + * If video interface present, cmd panel bandwidth cannot be + * released. + */ + if (sde_crtc_get_intf_mode(crtc, crtc->state) == INTF_MODE_CMD) + drm_for_each_crtc(tmp_crtc, crtc->dev) { + if (_sde_core_perf_crtc_is_power_on(tmp_crtc) && + sde_crtc_get_intf_mode(tmp_crtc, + tmp_crtc->state) == INTF_MODE_VIDEO) + return; + } + + /* Release the bandwidth */ + if (kms->perf.enable_bw_release) { + trace_sde_cmd_release_bw(crtc->base.id); + SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id); + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + sde_crtc->cur_perf.bw_ctl[i] = 0; + _sde_core_perf_crtc_update_bus(kms, crtc, i); + } + } +} + +static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms) +{ + u64 clk_rate = kms->perf.perf_tune.min_core_clk; + struct drm_crtc *tmp_crtc; + struct sde_crtc *sde_crtc; + u64 tmp_rate; + + drm_for_each_crtc(tmp_crtc, kms->dev) { + if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) { + + /* use current perf, which are the values voted */ + sde_crtc = to_sde_crtc(tmp_crtc); + tmp_rate = sde_crtc->cur_perf.core_clk_rate; + + clk_rate = max(tmp_rate, clk_rate); + + clk_rate = clk_round_rate(kms->perf.core_clk, clk_rate); + } + } + + if (kms->perf.perf_tune.mode == SDE_PERF_MODE_FIXED) + clk_rate = max(kms->perf.fix_core_clk_rate, clk_rate); + + SDE_DEBUG("clk:%llu\n", clk_rate); + + return clk_rate; +} + +static void _sde_core_perf_crtc_update_check(struct drm_crtc *crtc, + int params_changed, + int *update_bus, int *update_clk, int *update_llcc) +{ + struct sde_kms *kms = _sde_crtc_get_kms(crtc); + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_core_perf_params *old = &sde_crtc->cur_perf; + struct sde_core_perf_params *new = &sde_crtc->new_perf; + int i; + + if (!kms) + return; + + /* + * cases for the llcc update. + * 1. llcc is transitioning: 'inactive->active' during kickoff, + * for current request. + * 2. llcc is transitioning: 'active->inactive'at the end of the + * commit or during stop + */ + + if ((params_changed && + new->llcc_active && !old->llcc_active) || + (!params_changed && + !new->llcc_active && old->llcc_active)) { + + SDE_DEBUG("crtc=%d p=%d new_llcc=%d, old_llcc=%d\n", + crtc->base.id, params_changed, + new->llcc_active, old->llcc_active); + + old->llcc_active = new->llcc_active; + *update_llcc = 1; + } + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + /* + * cases for bus bandwidth update. + * 1. new bandwidth vote - "ab or ib vote" is higher + * than current vote for update request. + * 2. new bandwidth vote - "ab or ib vote" is lower + * than current vote at end of commit or stop. + */ + + if ((params_changed && + (new->bw_ctl[i] > old->bw_ctl[i])) || + (!params_changed && + (new->bw_ctl[i] < old->bw_ctl[i]))) { + + SDE_DEBUG( + "crtc=%d p=%d new_bw=%llu,old_bw=%llu\n", + crtc->base.id, params_changed, + new->bw_ctl[i], old->bw_ctl[i]); + old->bw_ctl[i] = new->bw_ctl[i]; + *update_bus |= BIT(i); + } + + if ((params_changed && + (new->max_per_pipe_ib[i] > + old->max_per_pipe_ib[i])) || + (!params_changed && + (new->max_per_pipe_ib[i] < + old->max_per_pipe_ib[i]))) { + + SDE_DEBUG( + "crtc=%d p=%d new_ib=%llu,old_ib=%llu\n", + crtc->base.id, params_changed, + new->max_per_pipe_ib[i], + old->max_per_pipe_ib[i]); + old->max_per_pipe_ib[i] = + new->max_per_pipe_ib[i]; + *update_bus |= BIT(i); + } + + /* display rsc override during solver mode */ + if (kms->perf.bw_vote_mode == DISP_RSC_MODE && + get_sde_rsc_current_state(SDE_RSC_INDEX) != + SDE_RSC_CLK_STATE) { + /* update new bandwidth in all cases */ + if (params_changed && ((new->bw_ctl[i] != + old->bw_ctl[i]) || + (new->max_per_pipe_ib[i] != + old->max_per_pipe_ib[i]))) { + old->bw_ctl[i] = new->bw_ctl[i]; + old->max_per_pipe_ib[i] = + new->max_per_pipe_ib[i]; + *update_bus |= BIT(i); + /* + * reduce bw vote is not required in solver + * mode + */ + } else if (!params_changed) { + *update_bus &= ~BIT(i); + } + } + } + + if (kms->perf.perf_tune.mode_changed && + kms->perf.perf_tune.min_core_clk) + new->core_clk_rate = kms->perf.perf_tune.min_core_clk; + + if ((params_changed && + (new->core_clk_rate > old->core_clk_rate)) || + (!params_changed && new->core_clk_rate && + (new->core_clk_rate < old->core_clk_rate)) || + kms->perf.perf_tune.mode_changed) { + old->core_clk_rate = new->core_clk_rate; + *update_clk = 1; + kms->perf.perf_tune.mode_changed = false; + } +} + +void sde_core_perf_crtc_update(struct drm_crtc *crtc, + int params_changed, bool stop_req) +{ + struct sde_core_perf_params *new, *old; + int update_bus = 0, update_clk = 0, update_llcc = 0; + u64 clk_rate = 0; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_cstate; + int ret, i; + struct msm_drm_private *priv; + struct sde_kms *kms; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return; + } + priv = kms->dev->dev_private; + sde_crtc = to_sde_crtc(crtc); + sde_cstate = to_sde_crtc_state(crtc->state); + + SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n", + crtc->base.id, stop_req, kms->perf.core_clk_rate); + + mutex_lock(&sde_core_perf_lock); + + /* + * cache the performance numbers in the crtc prior to the + * crtc kickoff, so the same numbers are used during the + * perf update that happens post kickoff. + */ + if (params_changed) + memcpy(&sde_crtc->new_perf, &sde_cstate->new_perf, + sizeof(struct sde_core_perf_params)); + + old = &sde_crtc->cur_perf; + new = &sde_crtc->new_perf; + + if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) { + _sde_core_perf_crtc_update_check(crtc, params_changed, + &update_bus, &update_clk, &update_llcc); + } else { + SDE_DEBUG("crtc=%d disable\n", crtc->base.id); + memset(old, 0, sizeof(*old)); + memset(new, 0, sizeof(*new)); + update_bus = ~0; + update_clk = 1; + update_llcc = 1; + } + trace_sde_perf_crtc_update(crtc->base.id, + new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MNOC], + new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MNOC], + new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_LLCC], + new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_LLCC], + new->bw_ctl[SDE_POWER_HANDLE_DBUS_ID_EBI], + new->max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_EBI], + new->core_clk_rate, stop_req, + update_bus, update_clk, params_changed); + + if (update_llcc) + _sde_core_perf_crtc_update_llcc(kms, crtc); + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + if (update_bus & BIT(i)) + _sde_core_perf_crtc_update_bus(kms, crtc, i); + } + + if (kms->perf.bw_vote_mode == DISP_RSC_MODE && + ((get_sde_rsc_current_state(SDE_RSC_INDEX) != SDE_RSC_CLK_STATE + && params_changed) || + (get_sde_rsc_current_state(SDE_RSC_INDEX) == SDE_RSC_CLK_STATE + && update_bus))) + sde_rsc_client_trigger_vote(sde_cstate->rsc_client, + update_bus ? true : false); + + /* + * Update the clock after bandwidth vote to ensure + * bandwidth is available before clock rate is increased. + */ + if (update_clk) { + clk_rate = _sde_core_perf_get_core_clk_rate(kms); + + SDE_EVT32(kms->dev, stop_req, clk_rate, params_changed, + old->core_clk_rate, new->core_clk_rate); + ret = sde_power_clk_set_rate(&priv->phandle, + kms->perf.clk_name, clk_rate); + if (ret) { + SDE_ERROR("failed to set %s clock rate %llu\n", + kms->perf.clk_name, clk_rate); + mutex_unlock(&sde_core_perf_lock); + return; + } + + kms->perf.core_clk_rate = clk_rate; + SDE_DEBUG("update clk rate = %lld HZ\n", clk_rate); + } + mutex_unlock(&sde_core_perf_lock); + +} + +#ifdef CONFIG_DEBUG_FS + +static ssize_t _sde_core_perf_threshold_high_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_core_perf *perf = file->private_data; + u32 threshold_high = 0; + char buf[10]; + + if (!perf) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtouint(buf, 0, &threshold_high)) + return -EFAULT; + + if (threshold_high < SDE_PERF_THRESHOLD_HIGH_MIN) + threshold_high = SDE_PERF_THRESHOLD_HIGH_MIN; + + perf->catalog->perf.max_bw_high = threshold_high; + + return count; +} + +static ssize_t _sde_core_perf_threshold_high_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct sde_core_perf *perf = file->private_data; + int len = 0; + char buf[20] = {'\0'}; + + if (!perf) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), + "%d\n", perf->catalog->perf.max_bw_high); + + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static ssize_t _sde_core_perf_mode_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_core_perf *perf = file->private_data; + struct sde_perf_cfg *cfg = &perf->catalog->perf; + u32 perf_mode = 0; + char buf[10]; + int ret = 0; + + if (!perf) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtouint(buf, 0, &perf_mode)) + return -EFAULT; + + if (perf_mode >= SDE_PERF_MODE_MAX) + return -EFAULT; + + if (perf_mode == SDE_PERF_MODE_FIXED) { + DRM_INFO("fix performance mode\n"); + } else if (perf_mode == SDE_PERF_MODE_MINIMUM) { + /* run the driver with max clk and BW vote */ + perf->perf_tune.min_core_clk = perf->max_core_clk_rate; + perf->perf_tune.min_bus_vote = + (u64) cfg->max_bw_high * 1000; + + ret = sde_power_clk_set_rate(perf->phandle, + perf->clk_name, perf->max_core_clk_rate); + if (ret) { + SDE_ERROR("failed to set %s clock rate %llu\n", + perf->clk_name, + perf->max_core_clk_rate); + + perf->perf_tune.min_core_clk = 0; + perf->perf_tune.min_bus_vote = 0; + perf_mode = SDE_PERF_MODE_NORMAL; + } else { + DRM_INFO("minimum performance mode\n"); + } + SDE_EVT32(perf->max_core_clk_rate, ret); + } else if (perf_mode == SDE_PERF_MODE_NORMAL) { + /* reset the perf tune params to 0 */ + perf->perf_tune.min_core_clk = 0; + perf->perf_tune.min_bus_vote = 0; + DRM_INFO("normal performance mode\n"); + } + perf->perf_tune.mode = perf_mode; + perf->perf_tune.mode_changed = true; + + return count; +} + +static ssize_t _sde_core_perf_mode_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct sde_core_perf *perf = file->private_data; + int len = 0; + char buf[SDE_PERF_MODE_STRING_SIZE] = {'\0'}; + + if (!perf) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), + "mode %d min_mdp_clk %llu min_bus_vote %llu\n", + perf->perf_tune.mode, + perf->perf_tune.min_core_clk, + perf->perf_tune.min_bus_vote); + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static const struct file_operations sde_core_perf_threshold_high_fops = { + .open = simple_open, + .read = _sde_core_perf_threshold_high_read, + .write = _sde_core_perf_threshold_high_write, +}; + +static const struct file_operations sde_core_perf_mode_fops = { + .open = simple_open, + .read = _sde_core_perf_mode_read, + .write = _sde_core_perf_mode_write, +}; + +static void sde_core_perf_debugfs_destroy(struct sde_core_perf *perf) +{ + debugfs_remove_recursive(perf->debugfs_root); + perf->debugfs_root = NULL; +} + +int sde_core_perf_debugfs_init(struct sde_core_perf *perf, + struct dentry *parent) +{ + struct sde_mdss_cfg *catalog = perf->catalog; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + priv = perf->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(priv->kms); + + perf->debugfs_root = debugfs_create_dir("core_perf", parent); + if (!perf->debugfs_root) { + SDE_ERROR("failed to create core perf debugfs\n"); + return -EINVAL; + } + + debugfs_create_u64("max_core_clk_rate", 0600, perf->debugfs_root, + &perf->max_core_clk_rate); + debugfs_create_u64("core_clk_rate", 0600, perf->debugfs_root, + &perf->core_clk_rate); + debugfs_create_u32("threshold_low", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.max_bw_low); + debugfs_create_file("threshold_high", 0600, perf->debugfs_root, + (u32 *)perf, &sde_core_perf_threshold_high_fops); + debugfs_create_u32("min_core_ib", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.min_core_ib); + debugfs_create_u32("min_llcc_ib", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.min_llcc_ib); + debugfs_create_u32("min_dram_ib", 0600, perf->debugfs_root, + (u32 *)&catalog->perf.min_dram_ib); + debugfs_create_file("perf_mode", 0600, perf->debugfs_root, + (u32 *)perf, &sde_core_perf_mode_fops); + debugfs_create_u32("bw_vote_mode", 0600, perf->debugfs_root, + &perf->bw_vote_mode); + debugfs_create_bool("bw_vote_mode_updated", 0600, perf->debugfs_root, + &perf->bw_vote_mode_updated); + debugfs_create_u64("fix_core_clk_rate", 0600, perf->debugfs_root, + &perf->fix_core_clk_rate); + debugfs_create_u64("fix_core_ib_vote", 0600, perf->debugfs_root, + &perf->fix_core_ib_vote); + debugfs_create_u64("fix_core_ab_vote", 0600, perf->debugfs_root, + &perf->fix_core_ab_vote); + + debugfs_create_u32("uidle_perf_cnt", 0600, perf->debugfs_root, + &sde_kms->catalog->uidle_cfg.debugfs_perf); + debugfs_create_bool("uidle_enable", 0600, perf->debugfs_root, + &sde_kms->catalog->uidle_cfg.debugfs_ctrl); + + return 0; +} +#else +static void sde_core_perf_debugfs_destroy(struct sde_core_perf *perf) +{ +} + +int sde_core_perf_debugfs_init(struct sde_core_perf *perf, + struct dentry *parent) +{ + return 0; +} +#endif + +void sde_core_perf_destroy(struct sde_core_perf *perf) +{ + if (!perf) { + SDE_ERROR("invalid parameters\n"); + return; + } + + sde_core_perf_debugfs_destroy(perf); + perf->max_core_clk_rate = 0; + perf->core_clk = NULL; + perf->clk_name = NULL; + perf->phandle = NULL; + perf->catalog = NULL; + perf->dev = NULL; +} + +int sde_core_perf_init(struct sde_core_perf *perf, + struct drm_device *dev, + struct sde_mdss_cfg *catalog, + struct sde_power_handle *phandle, + char *clk_name) +{ + if (!perf || !dev || !catalog || !phandle || !clk_name) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + perf->dev = dev; + perf->catalog = catalog; + perf->phandle = phandle; + perf->clk_name = clk_name; + perf->sde_rsc_available = is_sde_rsc_available(SDE_RSC_INDEX); + /* set default mode */ + if (perf->sde_rsc_available) + perf->bw_vote_mode = DISP_RSC_MODE; + else + perf->bw_vote_mode = APPS_RSC_MODE; + + perf->core_clk = sde_power_clk_get_clk(phandle, clk_name); + if (!perf->core_clk) { + SDE_ERROR("invalid core clk\n"); + goto err; + } + + perf->max_core_clk_rate = sde_power_clk_get_max_rate(phandle, clk_name); + if (!perf->max_core_clk_rate) { + SDE_DEBUG("optional max core clk rate, use default\n"); + perf->max_core_clk_rate = SDE_PERF_DEFAULT_MAX_CORE_CLK_RATE; + } + + return 0; + +err: + sde_core_perf_destroy(perf); + return -ENODEV; +} diff --git a/techpack/display/msm/sde/sde_core_perf.h b/techpack/display/msm/sde/sde_core_perf.h new file mode 100644 index 0000000000000000000000000000000000000000..6f644b8592225fadc18526ed29a076a0b5779f14 --- /dev/null +++ b/techpack/display/msm/sde/sde_core_perf.h @@ -0,0 +1,160 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_CORE_PERF_H_ +#define _SDE_CORE_PERF_H_ + +#include <linux/types.h> +#include <linux/dcache.h> +#include <linux/mutex.h> +#include <drm/drm_crtc.h> + +#include "sde_hw_catalog.h" +#include "sde_power_handle.h" + +#define SDE_PERF_DEFAULT_MAX_CORE_CLK_RATE 320000000 + +/** + * uidle performance counters mode + * @SDE_PERF_UIDLE_DISABLE: Disable logging (default) + * @SDE_PERF_UIDLE_CNT: Enable logging of uidle performance counters + * @SDE_PERF_UIDLE_STATUS: Enable logging of uidle status + * @SDE_PERF_UIDLE_MAX: Max available mode + */ +#define SDE_PERF_UIDLE_DISABLE 0x0 +#define SDE_PERF_UIDLE_CNT BIT(0) +#define SDE_PERF_UIDLE_STATUS BIT(1) +#define SDE_PERF_UIDLE_MAX BIT(2) + +/** + * struct sde_core_perf_params - definition of performance parameters + * @max_per_pipe_ib: maximum instantaneous bandwidth request + * @bw_ctl: arbitrated bandwidth request + * @core_clk_rate: core clock rate request + * @llcc_active: request to activate/deactivate the llcc + */ +struct sde_core_perf_params { + u64 max_per_pipe_ib[SDE_POWER_HANDLE_DBUS_ID_MAX]; + u64 bw_ctl[SDE_POWER_HANDLE_DBUS_ID_MAX]; + u64 core_clk_rate; + bool llcc_active; +}; + +/** + * struct sde_core_perf_tune - definition of performance tuning control + * @mode: performance mode + * @min_core_clk: minimum core clock + * @min_bus_vote: minimum bus vote + * @mode_changed: indicate if clock tuning strategy changed + */ +struct sde_core_perf_tune { + u32 mode; + u64 min_core_clk; + u64 min_bus_vote; + bool mode_changed; +}; + +/** + * struct sde_core_perf - definition of core performance context + * @dev: Pointer to drm device + * @debugfs_root: top level debug folder + * @catalog: Pointer to catalog configuration + * @phandle: Pointer to power handler + * @clk_name: core clock name + * @core_clk: Pointer to core clock structure + * @core_clk_rate: current core clock rate + * @max_core_clk_rate: maximum allowable core clock rate + * @perf_tune: debug control for performance tuning + * @enable_bw_release: debug control for bandwidth release + * @fix_core_clk_rate: fixed core clock request in Hz used in mode 2 + * @fix_core_ib_vote: fixed core ib vote in bps used in mode 2 + * @fix_core_ab_vote: fixed core ab vote in bps used in mode 2 + * @bw_vote_mode: apps rsc vs display rsc bandwidth vote mode + * @sde_rsc_available: is display rsc available + * @bw_vote_mode_updated: bandwidth vote mode update + * @llcc_active: status of the llcc, true if active. + * @uidle_enabled: indicates if uidle is already enabled + */ +struct sde_core_perf { + struct drm_device *dev; + struct dentry *debugfs_root; + struct sde_mdss_cfg *catalog; + struct sde_power_handle *phandle; + char *clk_name; + struct clk *core_clk; + u64 core_clk_rate; + u64 max_core_clk_rate; + struct sde_core_perf_tune perf_tune; + u32 enable_bw_release; + u64 fix_core_clk_rate; + u64 fix_core_ib_vote; + u64 fix_core_ab_vote; + u32 bw_vote_mode; + bool sde_rsc_available; + bool bw_vote_mode_updated; + bool llcc_active; + bool uidle_enabled; +}; + +/** + * sde_core_perf_crtc_check - validate performance of the given crtc state + * @crtc: Pointer to crtc + * @state: Pointer to new crtc state + * return: zero if success, or error code otherwise + */ +int sde_core_perf_crtc_check(struct drm_crtc *crtc, + struct drm_crtc_state *state); + +/** + * sde_core_perf_crtc_update - update performance of the given crtc + * @crtc: Pointer to crtc + * @params_changed: true if crtc parameters are modified + * @stop_req: true if this is a stop request + */ +void sde_core_perf_crtc_update(struct drm_crtc *crtc, + int params_changed, bool stop_req); + +/** + * sde_core_perf_crtc_release_bw - release bandwidth of the given crtc + * @crtc: Pointer to crtc + */ +void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc); + +/** + * sde_core_perf_crtc_update_uidle - attempts to enable uidle of the given crtc + * @crtc: Pointer to crtc + * @enable: enable/disable uidle + */ +void sde_core_perf_crtc_update_uidle(struct drm_crtc *crtc, bool enable); + +/** + * sde_core_perf_destroy - destroy the given core performance context + * @perf: Pointer to core performance context + */ +void sde_core_perf_destroy(struct sde_core_perf *perf); + +/** + * sde_core_perf_init - initialize the given core performance context + * @perf: Pointer to core performance context + * @dev: Pointer to drm device + * @catalog: Pointer to catalog + * @phandle: Pointer to power handle + * @clk_name: core clock name + */ +int sde_core_perf_init(struct sde_core_perf *perf, + struct drm_device *dev, + struct sde_mdss_cfg *catalog, + struct sde_power_handle *phandle, + char *clk_name); + +/** + * sde_core_perf_debugfs_init - initialize debugfs for core performance context + * @perf: Pointer to core performance context + * @debugfs_parent: Pointer to parent debugfs + */ +int sde_core_perf_debugfs_init(struct sde_core_perf *perf, + struct dentry *parent); + +#endif /* _SDE_CORE_PERF_H_ */ diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c new file mode 100644 index 0000000000000000000000000000000000000000..4ce0661edd67879bebdf0aeb351a13ecc44dda4a --- /dev/null +++ b/techpack/display/msm/sde/sde_crtc.c @@ -0,0 +1,7190 @@ +/* + * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/sort.h> +#include <linux/debugfs.h> +#include <linux/ktime.h> +#include <uapi/drm/sde_drm.h> +#include <drm/drm_mode.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_flip_work.h> +#include <linux/clk/qcom.h> + +#include "sde_kms.h" +#include "sde_hw_lm.h" +#include "sde_hw_ctl.h" +#include "sde_crtc.h" +#include "sde_plane.h" +#include "sde_hw_util.h" +#include "sde_hw_catalog.h" +#include "sde_color_processing.h" +#include "sde_encoder.h" +#include "sde_connector.h" +#include "sde_vbif.h" +#include "sde_power_handle.h" +#include "sde_core_perf.h" +#include "sde_trace.h" +#include <linux/msm_drm_notify.h> +#include <linux/notifier.h> +#include <linux/err.h> +#include <linux/list.h> +#include <linux/of.h> +#include <linux/err.h> +#include "msm_drv.h" +#include "sde_connector.h" +#include "msm_mmu.h" +#include "dsi_display.h" +#include "dsi_panel.h" +#include "dsi_ctrl.h" +#include "dsi_ctrl_hw.h" +#include "dsi_drm.h" +#include "dsi_clk.h" +#include "dsi_pwr.h" +#include "sde_dbg.h" +#include <linux/kobject.h> +#include <linux/string.h> +#include <linux/sysfs.h> +#include <linux/module.h> +#include <linux/init.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_sysfs.h> +#include <drm/drmP.h> +#define to_drm_connector(d) dev_get_drvdata(d) +#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) +extern int msm_drm_notifier_call_chain(unsigned long val, void *v); + +#define SDE_PSTATES_MAX (SDE_STAGE_MAX * 4) +#define SDE_MULTIRECT_PLANE_MAX (SDE_STAGE_MAX * 2) + +struct sde_crtc_custom_events { + u32 event; + int (*func)(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *irq); +}; + +static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, + bool en, struct sde_irq_callback *ad_irq); +static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, + bool en, struct sde_irq_callback *idle_irq); +static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *noirq); + +static struct sde_crtc_custom_events custom_events[] = { + {DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt}, + {DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler}, + {DRM_EVENT_IDLE_NOTIFY, sde_crtc_idle_interrupt_handler}, + {DRM_EVENT_HISTOGRAM, sde_cp_hist_interrupt}, + {DRM_EVENT_SDE_POWER, sde_crtc_pm_event_handler}, + {DRM_EVENT_LTM_HIST, sde_cp_ltm_hist_interrupt}, + {DRM_EVENT_LTM_WB_PB, sde_cp_ltm_wb_pb_interrupt}, + {DRM_EVENT_LTM_OFF, sde_cp_ltm_off_event_handler}, +}; + +/* default input fence timeout, in ms */ +#define SDE_CRTC_INPUT_FENCE_TIMEOUT 10000 + +/* + * The default input fence timeout is 2 seconds while max allowed + * range is 10 seconds. Any value above 10 seconds adds glitches beyond + * tolerance limit. + */ +#define SDE_CRTC_MAX_INPUT_FENCE_TIMEOUT 10000 + +/* layer mixer index on sde_crtc */ +#define LEFT_MIXER 0 +#define RIGHT_MIXER 1 + +#define MISR_BUFF_SIZE 256 + +/* + * Time period for fps calculation in micro seconds. + * Default value is set to 1 sec. + */ +#define DEFAULT_FPS_PERIOD_1_SEC 1000000 +#define MAX_FPS_PERIOD_5_SECONDS 5000000 +#define MAX_FRAME_COUNT 1000 +#define MILI_TO_MICRO 1000 + +static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return NULL; + } + priv = crtc->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid kms\n"); + return NULL; + } + + return to_sde_kms(priv->kms); +} + +/** + * sde_crtc_calc_fps() - Calculates fps value. + * @sde_crtc : CRTC structure + * + * This function is called at frame done. It counts the number + * of frames done for every 1 sec. Stores the value in measured_fps. + * measured_fps value is 10 times the calculated fps value. + * For example, measured_fps= 594 for calculated fps of 59.4 + */ +static void sde_crtc_calc_fps(struct sde_crtc *sde_crtc) +{ + ktime_t current_time_us; + u64 fps, diff_us; + + current_time_us = ktime_get(); + diff_us = (u64)ktime_us_delta(current_time_us, + sde_crtc->fps_info.last_sampled_time_us); + sde_crtc->fps_info.frame_count++; + + if (diff_us >= DEFAULT_FPS_PERIOD_1_SEC) { + + /* Multiplying with 10 to get fps in floating point */ + fps = ((u64)sde_crtc->fps_info.frame_count) + * DEFAULT_FPS_PERIOD_1_SEC * 10; + do_div(fps, diff_us); + sde_crtc->fps_info.measured_fps = (unsigned int)fps; + SDE_DEBUG(" FPS for crtc%d is %d.%d\n", + sde_crtc->base.base.id, (unsigned int)fps/10, + (unsigned int)fps%10); + sde_crtc->fps_info.last_sampled_time_us = current_time_us; + sde_crtc->fps_info.frame_count = 0; + } + + if (!sde_crtc->fps_info.time_buf) + return; + + /** + * Array indexing is based on sliding window algorithm. + * sde_crtc->time_buf has a maximum capacity of MAX_FRAME_COUNT + * time slots. As the count increases to MAX_FRAME_COUNT + 1, the + * counter loops around and comes back to the first index to store + * the next ktime. + */ + sde_crtc->fps_info.time_buf[sde_crtc->fps_info.next_time_index++] = + ktime_get(); + sde_crtc->fps_info.next_time_index %= MAX_FRAME_COUNT; +} + +static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) +{ + if (!sde_crtc) + return; +} + +#ifdef CONFIG_DEBUG_FS +static int _sde_debugfs_fps_status_show(struct seq_file *s, void *data) +{ + struct sde_crtc *sde_crtc; + u64 fps_int, fps_float; + ktime_t current_time_us; + u64 fps, diff_us; + + if (!s || !s->private) { + SDE_ERROR("invalid input param(s)\n"); + return -EAGAIN; + } + + sde_crtc = s->private; + + current_time_us = ktime_get(); + diff_us = (u64)ktime_us_delta(current_time_us, + sde_crtc->fps_info.last_sampled_time_us); + + if (diff_us >= DEFAULT_FPS_PERIOD_1_SEC) { + + /* Multiplying with 10 to get fps in floating point */ + fps = ((u64)sde_crtc->fps_info.frame_count) + * DEFAULT_FPS_PERIOD_1_SEC * 10; + do_div(fps, diff_us); + sde_crtc->fps_info.measured_fps = (unsigned int)fps; + sde_crtc->fps_info.last_sampled_time_us = current_time_us; + sde_crtc->fps_info.frame_count = 0; + SDE_DEBUG("Measured FPS for crtc%d is %d.%d\n", + sde_crtc->base.base.id, (unsigned int)fps/10, + (unsigned int)fps%10); + } + + fps_int = (unsigned int) sde_crtc->fps_info.measured_fps; + fps_float = do_div(fps_int, 10); + + seq_printf(s, "fps: %llu.%llu\n", fps_int, fps_float); + + return 0; +} + + +static int _sde_debugfs_fps_status(struct inode *inode, struct file *file) +{ + return single_open(file, _sde_debugfs_fps_status_show, + inode->i_private); +} +#endif + +static ssize_t fps_periodicity_ms_store(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + int res; + + /* Base of the input */ + int cnt = 10; + + if (!device || !buf) { + SDE_ERROR("invalid input param(s)\n"); + return -EAGAIN; + } + + crtc = dev_get_drvdata(device); + if (!crtc) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + + res = kstrtou32(buf, cnt, &sde_crtc->fps_info.fps_periodic_duration); + if (res < 0) + return res; + + if (sde_crtc->fps_info.fps_periodic_duration <= 0) + sde_crtc->fps_info.fps_periodic_duration = + DEFAULT_FPS_PERIOD_1_SEC; + else if ((sde_crtc->fps_info.fps_periodic_duration) * MILI_TO_MICRO > + MAX_FPS_PERIOD_5_SECONDS) + sde_crtc->fps_info.fps_periodic_duration = + MAX_FPS_PERIOD_5_SECONDS; + else + sde_crtc->fps_info.fps_periodic_duration *= MILI_TO_MICRO; + + return count; +} + +static ssize_t fps_periodicity_ms_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + + if (!device || !buf) { + SDE_ERROR("invalid input param(s)\n"); + return -EAGAIN; + } + + crtc = dev_get_drvdata(device); + if (!crtc) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + + return scnprintf(buf, PAGE_SIZE, "%d\n", + (sde_crtc->fps_info.fps_periodic_duration)/MILI_TO_MICRO); +} + +static ssize_t measured_fps_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + uint64_t fps_int, fps_decimal; + u64 fps = 0, frame_count = 0; + ktime_t current_time; + int i = 0, current_time_index; + u64 diff_us; + + if (!device || !buf) { + SDE_ERROR("invalid input param(s)\n"); + return -EAGAIN; + } + + crtc = dev_get_drvdata(device); + if (!crtc) { + scnprintf(buf, PAGE_SIZE, "fps information not available"); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + + if (!sde_crtc->fps_info.time_buf) { + scnprintf(buf, PAGE_SIZE, + "timebuf null - fps information not available"); + return -EINVAL; + } + + /** + * Whenever the time_index counter comes to zero upon decrementing, + * it is set to the last index since it is the next index that we + * should check for calculating the buftime. + */ + current_time_index = (sde_crtc->fps_info.next_time_index == 0) ? + MAX_FRAME_COUNT - 1 : (sde_crtc->fps_info.next_time_index - 1); + + current_time = ktime_get(); + + for (i = 0; i < MAX_FRAME_COUNT; i++) { + u64 ptime = (u64)ktime_to_us(current_time); + u64 buftime = (u64)ktime_to_us( + sde_crtc->fps_info.time_buf[current_time_index]); + diff_us = (u64)ktime_us_delta(current_time, + sde_crtc->fps_info.time_buf[current_time_index]); + if (ptime > buftime && diff_us >= (u64) + sde_crtc->fps_info.fps_periodic_duration) { + + /* Multiplying with 10 to get fps in floating point */ + fps = frame_count * DEFAULT_FPS_PERIOD_1_SEC * 10; + do_div(fps, diff_us); + sde_crtc->fps_info.measured_fps = (unsigned int)fps; + SDE_DEBUG("measured fps: %d\n", + sde_crtc->fps_info.measured_fps); + break; + } + + current_time_index = (current_time_index == 0) ? + (MAX_FRAME_COUNT - 1) : (current_time_index - 1); + SDE_DEBUG("current time index: %d\n", current_time_index); + + frame_count++; + } + + if (i == MAX_FRAME_COUNT) { + + current_time_index = (sde_crtc->fps_info.next_time_index == 0) ? + MAX_FRAME_COUNT - 1 : (sde_crtc->fps_info.next_time_index - 1); + + diff_us = (u64)ktime_us_delta(current_time, + sde_crtc->fps_info.time_buf[current_time_index]); + + if (diff_us >= sde_crtc->fps_info.fps_periodic_duration) { + + /* Multiplying with 10 to get fps in floating point */ + fps = (frame_count) * DEFAULT_FPS_PERIOD_1_SEC * 10; + do_div(fps, diff_us); + sde_crtc->fps_info.measured_fps = (unsigned int)fps; + } + } + + fps_int = (uint64_t) sde_crtc->fps_info.measured_fps; + fps_decimal = do_div(fps_int, 10); + return scnprintf(buf, PAGE_SIZE, + "fps: %d.%d duration:%d frame_count:%lld\n", fps_int, fps_decimal, + sde_crtc->fps_info.fps_periodic_duration, frame_count); +} + +static ssize_t vsync_event_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + + if (!device || !buf) { + SDE_ERROR("invalid input param(s)\n"); + return -EAGAIN; + } + + crtc = dev_get_drvdata(device); + sde_crtc = to_sde_crtc(crtc); + return scnprintf(buf, PAGE_SIZE, "VSYNC=%llu\n", + ktime_to_ns(sde_crtc->vblank_last_cb_time)); +} + +static DEVICE_ATTR_RO(vsync_event); +static DEVICE_ATTR_RO(measured_fps); +static DEVICE_ATTR_RW(fps_periodicity_ms); + +static struct attribute *sde_crtc_dev_attrs[] = { + &dev_attr_vsync_event.attr, + &dev_attr_measured_fps.attr, + &dev_attr_fps_periodicity_ms.attr, + NULL +}; + +static const struct attribute_group sde_crtc_attr_group = { + .attrs = sde_crtc_dev_attrs, +}; + +static const struct attribute_group *sde_crtc_attr_groups[] = { + &sde_crtc_attr_group, + NULL, +}; + +static void sde_crtc_destroy(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + SDE_DEBUG("\n"); + + if (!crtc) + return; + + if (sde_crtc->vsync_event_sf) + sysfs_put(sde_crtc->vsync_event_sf); + if (sde_crtc->sysfs_dev) + device_unregister(sde_crtc->sysfs_dev); + + if (sde_crtc->blob_info) + drm_property_blob_put(sde_crtc->blob_info); + msm_property_destroy(&sde_crtc->property_info); + sde_cp_crtc_destroy_properties(crtc); + + sde_fence_deinit(sde_crtc->output_fence); + _sde_crtc_deinit_events(sde_crtc); + + drm_crtc_cleanup(crtc); + mutex_destroy(&sde_crtc->crtc_lock); + kfree(sde_crtc); +} + +static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + SDE_DEBUG("\n"); + + sde_cp_mode_switch_prop_dirty(crtc); + if ((msm_is_mode_seamless(adjusted_mode) || + (msm_is_mode_seamless_vrr(adjusted_mode) || + msm_is_mode_seamless_dyn_clk(adjusted_mode))) && + (!crtc->enabled)) { + SDE_ERROR("crtc state prevents seamless transition\n"); + return false; + } + + return true; +} + +static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer, + struct sde_plane_state *pstate, struct sde_format *format) +{ + uint32_t blend_op, fg_alpha, bg_alpha; + uint32_t blend_type; + struct sde_hw_mixer *lm = mixer->hw_lm; + + /* default to opaque blending */ + fg_alpha = sde_plane_get_property(pstate, PLANE_PROP_ALPHA); + bg_alpha = 0xFF - fg_alpha; + blend_op = SDE_BLEND_FG_ALPHA_FG_CONST | SDE_BLEND_BG_ALPHA_BG_CONST; + blend_type = sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP); + + SDE_DEBUG("blend type:0x%x blend alpha:0x%x\n", blend_type, fg_alpha); + + switch (blend_type) { + + case SDE_DRM_BLEND_OP_OPAQUE: + blend_op = SDE_BLEND_FG_ALPHA_FG_CONST | + SDE_BLEND_BG_ALPHA_BG_CONST; + break; + + case SDE_DRM_BLEND_OP_PREMULTIPLIED: + if (format->alpha_enable) { + blend_op = SDE_BLEND_FG_ALPHA_FG_CONST | + SDE_BLEND_BG_ALPHA_FG_PIXEL; + if (fg_alpha != 0xff) { + bg_alpha = fg_alpha; + blend_op |= SDE_BLEND_BG_MOD_ALPHA | + SDE_BLEND_BG_INV_MOD_ALPHA; + } else { + blend_op |= SDE_BLEND_BG_INV_ALPHA; + } + } + break; + + case SDE_DRM_BLEND_OP_COVERAGE: + if (format->alpha_enable) { + blend_op = SDE_BLEND_FG_ALPHA_FG_PIXEL | + SDE_BLEND_BG_ALPHA_FG_PIXEL; + if (fg_alpha != 0xff) { + bg_alpha = fg_alpha; + blend_op |= SDE_BLEND_FG_MOD_ALPHA | + SDE_BLEND_BG_MOD_ALPHA | + SDE_BLEND_BG_INV_MOD_ALPHA; + } else { + blend_op |= SDE_BLEND_BG_INV_ALPHA; + } + } + break; + default: + /* do nothing */ + break; + } + + lm->ops.setup_blend_config(lm, pstate->stage, fg_alpha, + bg_alpha, blend_op); + SDE_DEBUG( + "format: %4.4s, alpha_enable %u fg alpha:0x%x bg alpha:0x%x blend_op:0x%x\n", + (char *) &format->base.pixel_format, + format->alpha_enable, fg_alpha, bg_alpha, blend_op); +} + +static void _sde_crtc_setup_dim_layer_cfg(struct drm_crtc *crtc, + struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer, + struct sde_hw_dim_layer *dim_layer) +{ + struct sde_crtc_state *cstate; + struct sde_hw_mixer *lm; + struct sde_hw_dim_layer split_dim_layer; + int i; + + if (!dim_layer->rect.w || !dim_layer->rect.h) { + SDE_DEBUG("empty dim_layer\n"); + return; + } + + cstate = to_sde_crtc_state(crtc->state); + + SDE_DEBUG("dim_layer - flags:%d, stage:%d\n", + dim_layer->flags, dim_layer->stage); + + split_dim_layer.stage = dim_layer->stage; + split_dim_layer.color_fill = dim_layer->color_fill; + + /* + * traverse through the layer mixers attached to crtc and find the + * intersecting dim layer rect in each LM and program accordingly. + */ + for (i = 0; i < sde_crtc->num_mixers; i++) { + split_dim_layer.flags = dim_layer->flags; + + sde_kms_rect_intersect(&cstate->lm_roi[i], &dim_layer->rect, + &split_dim_layer.rect); + if (sde_kms_rect_is_null(&split_dim_layer.rect)) { + /* + * no extra programming required for non-intersecting + * layer mixers with INCLUSIVE dim layer + */ + if (split_dim_layer.flags & SDE_DRM_DIM_LAYER_INCLUSIVE) + continue; + + /* + * program the other non-intersecting layer mixers with + * INCLUSIVE dim layer of full size for uniformity + * with EXCLUSIVE dim layer config. + */ + split_dim_layer.flags &= ~SDE_DRM_DIM_LAYER_EXCLUSIVE; + split_dim_layer.flags |= SDE_DRM_DIM_LAYER_INCLUSIVE; + memcpy(&split_dim_layer.rect, &cstate->lm_bounds[i], + sizeof(split_dim_layer.rect)); + + } else { + split_dim_layer.rect.x = + split_dim_layer.rect.x - + cstate->lm_roi[i].x; + split_dim_layer.rect.y = + split_dim_layer.rect.y - + cstate->lm_roi[i].y; + } + + SDE_EVT32(DRMID(crtc), dim_layer->stage, + cstate->lm_roi[i].x, + cstate->lm_roi[i].y, + cstate->lm_roi[i].w, + cstate->lm_roi[i].h, + dim_layer->rect.x, + dim_layer->rect.y, + dim_layer->rect.w, + dim_layer->rect.h, + split_dim_layer.rect.x, + split_dim_layer.rect.y, + split_dim_layer.rect.w, + split_dim_layer.rect.h); + + SDE_DEBUG("split_dim_layer - LM:%d, rect:{%d,%d,%d,%d}}\n", + i, split_dim_layer.rect.x, split_dim_layer.rect.y, + split_dim_layer.rect.w, split_dim_layer.rect.h); + + lm = mixer[i].hw_lm; + mixer[i].mixer_op_mode |= 1 << split_dim_layer.stage; + lm->ops.setup_dim_layer(lm, &split_dim_layer); + } +} + +void sde_crtc_get_crtc_roi(struct drm_crtc_state *state, + const struct sde_rect **crtc_roi) +{ + struct sde_crtc_state *crtc_state; + + if (!state || !crtc_roi) + return; + + crtc_state = to_sde_crtc_state(state); + *crtc_roi = &crtc_state->crtc_roi; +} + +bool sde_crtc_is_crtc_roi_dirty(struct drm_crtc_state *state) +{ + struct sde_crtc_state *cstate; + struct sde_crtc *sde_crtc; + + if (!state || !state->crtc) + return false; + + sde_crtc = to_sde_crtc(state->crtc); + cstate = to_sde_crtc_state(state); + + return msm_property_is_dirty(&sde_crtc->property_info, + &cstate->property_state, CRTC_PROP_ROI_V1); +} + +static int _sde_crtc_set_roi_v1(struct drm_crtc_state *state, + void __user *usr_ptr) +{ + struct drm_crtc *crtc; + struct sde_crtc_state *cstate; + struct sde_drm_roi_v1 roi_v1; + int i; + + if (!state) { + SDE_ERROR("invalid args\n"); + return -EINVAL; + } + + cstate = to_sde_crtc_state(state); + crtc = cstate->base.crtc; + + memset(&cstate->user_roi_list, 0, sizeof(cstate->user_roi_list)); + + if (!usr_ptr) { + SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc)); + return 0; + } + + if (copy_from_user(&roi_v1, usr_ptr, sizeof(roi_v1))) { + SDE_ERROR("crtc%d: failed to copy roi_v1 data\n", DRMID(crtc)); + return -EINVAL; + } + + SDE_DEBUG("crtc%d: num_rects %d\n", DRMID(crtc), roi_v1.num_rects); + + if (roi_v1.num_rects == 0) { + SDE_DEBUG("crtc%d: rois cleared\n", DRMID(crtc)); + return 0; + } + + if (roi_v1.num_rects > SDE_MAX_ROI_V1) { + SDE_ERROR("crtc%d: too many rects specified: %d\n", DRMID(crtc), + roi_v1.num_rects); + return -EINVAL; + } + + cstate->user_roi_list.num_rects = roi_v1.num_rects; + for (i = 0; i < roi_v1.num_rects; ++i) { + cstate->user_roi_list.roi[i] = roi_v1.roi[i]; + SDE_DEBUG("crtc%d: roi%d: roi (%d,%d) (%d,%d)\n", + DRMID(crtc), i, + cstate->user_roi_list.roi[i].x1, + cstate->user_roi_list.roi[i].y1, + cstate->user_roi_list.roi[i].x2, + cstate->user_roi_list.roi[i].y2); + SDE_EVT32_VERBOSE(DRMID(crtc), + cstate->user_roi_list.roi[i].x1, + cstate->user_roi_list.roi[i].y1, + cstate->user_roi_list.roi[i].x2, + cstate->user_roi_list.roi[i].y2); + } + + return 0; +} + +static bool _sde_crtc_setup_is_3dmux_dsc(struct drm_crtc_state *state) +{ + int i; + struct sde_crtc_state *cstate; + bool is_3dmux_dsc = false; + + cstate = to_sde_crtc_state(state); + + for (i = 0; i < cstate->num_connectors; i++) { + struct drm_connector *conn = cstate->connectors[i]; + + if (sde_connector_get_topology_name(conn) == + SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC) + is_3dmux_dsc = true; + } + + return is_3dmux_dsc; +} + +static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct drm_connector *conn; + struct drm_connector_state *conn_state; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + struct sde_rect *crtc_roi; + struct msm_mode_info mode_info; + int i = 0; + int rc; + bool is_crtc_roi_dirty; + bool is_any_conn_roi_dirty; + + if (!crtc || !state) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(state); + crtc_roi = &crtc_state->crtc_roi; + + is_crtc_roi_dirty = sde_crtc_is_crtc_roi_dirty(state); + is_any_conn_roi_dirty = false; + + for_each_new_connector_in_state(state->state, conn, conn_state, i) { + struct sde_connector *sde_conn; + struct sde_connector_state *sde_conn_state; + struct sde_rect conn_roi; + + if (!conn_state || conn_state->crtc != crtc) + continue; + + rc = sde_connector_state_get_mode_info(conn_state, &mode_info); + if (rc) { + SDE_ERROR("failed to get mode info\n"); + return -EINVAL; + } + + sde_conn = to_sde_connector(conn_state->connector); + sde_conn_state = to_sde_connector_state(conn_state); + + is_any_conn_roi_dirty = is_any_conn_roi_dirty || + msm_property_is_dirty( + &sde_conn->property_info, + &sde_conn_state->property_state, + CONNECTOR_PROP_ROI_V1); + + if (!mode_info.roi_caps.enabled) + continue; + + /* + * current driver only supports same connector and crtc size, + * but if support for different sizes is added, driver needs + * to check the connector roi here to make sure is full screen + * for dsc 3d-mux topology that doesn't support partial update. + */ + if (memcmp(&sde_conn_state->rois, &crtc_state->user_roi_list, + sizeof(crtc_state->user_roi_list))) { + SDE_ERROR("%s: crtc -> conn roi scaling unsupported\n", + sde_crtc->name); + return -EINVAL; + } + + sde_kms_rect_merge_rectangles(&sde_conn_state->rois, &conn_roi); + SDE_EVT32_VERBOSE(DRMID(crtc), DRMID(conn), + conn_roi.x, conn_roi.y, + conn_roi.w, conn_roi.h); + } + + /* + * Check against CRTC ROI and Connector ROI not being updated together. + * This restriction should be relaxed when Connector ROI scaling is + * supported. + */ + if (is_any_conn_roi_dirty != is_crtc_roi_dirty) { + SDE_ERROR("connector/crtc rois not updated together\n"); + return -EINVAL; + } + + sde_kms_rect_merge_rectangles(&crtc_state->user_roi_list, crtc_roi); + + /* clear the ROI to null if it matches full screen anyways */ + if (crtc_roi->x == 0 && crtc_roi->y == 0 && + crtc_roi->w == state->adjusted_mode.hdisplay && + crtc_roi->h == state->adjusted_mode.vdisplay) + memset(crtc_roi, 0, sizeof(*crtc_roi)); + + SDE_DEBUG("%s: crtc roi (%d,%d,%d,%d)\n", sde_crtc->name, + crtc_roi->x, crtc_roi->y, crtc_roi->w, crtc_roi->h); + SDE_EVT32_VERBOSE(DRMID(crtc), crtc_roi->x, crtc_roi->y, crtc_roi->w, + crtc_roi->h); + + return 0; +} + +static int _sde_crtc_check_autorefresh(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + int i; + + if (!crtc || !state) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(state); + + if (sde_kms_rect_is_null(&crtc_state->crtc_roi)) + return 0; + + /* partial update active, check if autorefresh is also requested */ + for_each_new_connector_in_state(state->state, conn, conn_state, i) { + uint64_t autorefresh; + + if (!conn_state || conn_state->crtc != crtc) + continue; + + autorefresh = sde_connector_get_property(conn_state, + CONNECTOR_PROP_AUTOREFRESH); + if (autorefresh) { + SDE_ERROR( + "%s: autorefresh & partial crtc roi incompatible %llu\n", + sde_crtc->name, autorefresh); + return -EINVAL; + } + } + + return 0; +} + +static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc, + struct drm_crtc_state *state, int lm_idx) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + const struct sde_rect *crtc_roi; + const struct sde_rect *lm_bounds; + struct sde_rect *lm_roi; + + if (!crtc || !state || lm_idx >= ARRAY_SIZE(crtc_state->lm_bounds)) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(state); + crtc_roi = &crtc_state->crtc_roi; + lm_bounds = &crtc_state->lm_bounds[lm_idx]; + lm_roi = &crtc_state->lm_roi[lm_idx]; + + if (sde_kms_rect_is_null(crtc_roi)) + memcpy(lm_roi, lm_bounds, sizeof(*lm_roi)); + else + sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi); + + SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx, + lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h); + + /* + * partial update is not supported with 3dmux dsc or dest scaler. + * hence, crtc roi must match the mixer dimensions. + */ + if (crtc_state->num_ds_enabled || + _sde_crtc_setup_is_3dmux_dsc(state)) { + if (memcmp(lm_roi, lm_bounds, sizeof(struct sde_rect))) { + SDE_ERROR("Unsupported: Dest scaler/3d mux DSC + PU\n"); + return -EINVAL; + } + } + + /* if any dimension is zero, clear all dimensions for clarity */ + if (sde_kms_rect_is_null(lm_roi)) + memset(lm_roi, 0, sizeof(*lm_roi)); + + return 0; +} + +static u32 _sde_crtc_get_displays_affected(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + u32 disp_bitmask = 0; + int i; + + if (!crtc || !state) { + pr_err("Invalid crtc or state\n"); + return 0; + } + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(state); + + /* pingpong split: one ROI, one LM, two physical displays */ + if (crtc_state->is_ppsplit) { + u32 lm_split_width = crtc_state->lm_bounds[0].w / 2; + struct sde_rect *roi = &crtc_state->lm_roi[0]; + + if (sde_kms_rect_is_null(roi)) + disp_bitmask = 0; + else if ((u32)roi->x + (u32)roi->w <= lm_split_width) + disp_bitmask = BIT(0); /* left only */ + else if (roi->x >= lm_split_width) + disp_bitmask = BIT(1); /* right only */ + else + disp_bitmask = BIT(0) | BIT(1); /* left and right */ + } else { + for (i = 0; i < sde_crtc->num_mixers; i++) { + if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i])) + disp_bitmask |= BIT(i); + } + } + + SDE_DEBUG("affected displays 0x%x\n", disp_bitmask); + + return disp_bitmask; +} + +static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + const struct sde_rect *roi[CRTC_DUAL_MIXERS]; + + if (!crtc || !state) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(state); + + if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { + SDE_ERROR("%s: unsupported number of mixers: %d\n", + sde_crtc->name, sde_crtc->num_mixers); + return -EINVAL; + } + + /* + * If using pingpong split: one ROI, one LM, two physical displays + * then the ROI must be centered on the panel split boundary and + * be of equal width across the split. + */ + if (crtc_state->is_ppsplit) { + u16 panel_split_width; + u32 display_mask; + + roi[0] = &crtc_state->lm_roi[0]; + + if (sde_kms_rect_is_null(roi[0])) + return 0; + + display_mask = _sde_crtc_get_displays_affected(crtc, state); + if (display_mask != (BIT(0) | BIT(1))) + return 0; + + panel_split_width = crtc_state->lm_bounds[0].w / 2; + if (roi[0]->x + roi[0]->w / 2 != panel_split_width) { + SDE_ERROR("%s: roi x %d w %d split %d\n", + sde_crtc->name, roi[0]->x, roi[0]->w, + panel_split_width); + return -EINVAL; + } + + return 0; + } + + /* + * On certain HW, if using 2 LM, ROIs must be split evenly between the + * LMs and be of equal width. + */ + if (sde_crtc->num_mixers < 2) + return 0; + + roi[0] = &crtc_state->lm_roi[0]; + roi[1] = &crtc_state->lm_roi[1]; + + /* if one of the roi is null it's a left/right-only update */ + if (sde_kms_rect_is_null(roi[0]) || sde_kms_rect_is_null(roi[1])) + return 0; + + /* check lm rois are equal width & first roi ends at 2nd roi */ + if (roi[0]->x + roi[0]->w != roi[1]->x || roi[0]->w != roi[1]->w) { + SDE_ERROR( + "%s: rois not centered and symmetric: roi0 x %d w %d roi1 x %d w %d\n", + sde_crtc->name, roi[0]->x, roi[0]->w, + roi[1]->x, roi[1]->w); + return -EINVAL; + } + + return 0; +} + +static int _sde_crtc_check_planes_within_crtc_roi(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + const struct sde_rect *crtc_roi; + const struct drm_plane_state *pstate; + struct drm_plane *plane; + + if (!crtc || !state) + return -EINVAL; + + /* + * Reject commit if a Plane CRTC destination coordinates fall outside + * the partial CRTC ROI. LM output is determined via connector ROIs, + * if they are specified, not Plane CRTC ROIs. + */ + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(state); + crtc_roi = &crtc_state->crtc_roi; + + if (sde_kms_rect_is_null(crtc_roi)) + return 0; + + drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { + struct sde_rect plane_roi, intersection; + + if (IS_ERR_OR_NULL(pstate)) { + int rc = PTR_ERR(pstate); + + SDE_ERROR("%s: failed to get plane%d state, %d\n", + sde_crtc->name, plane->base.id, rc); + return rc; + } + + plane_roi.x = pstate->crtc_x; + plane_roi.y = pstate->crtc_y; + plane_roi.w = pstate->crtc_w; + plane_roi.h = pstate->crtc_h; + sde_kms_rect_intersect(crtc_roi, &plane_roi, &intersection); + if (!sde_kms_rect_is_equal(&plane_roi, &intersection)) { + SDE_ERROR( + "%s: plane%d crtc roi (%d,%d,%d,%d) outside crtc roi (%d,%d,%d,%d)\n", + sde_crtc->name, plane->base.id, + plane_roi.x, plane_roi.y, + plane_roi.w, plane_roi.h, + crtc_roi->x, crtc_roi->y, + crtc_roi->w, crtc_roi->h); + return -E2BIG; + } + } + + return 0; +} + +static int _sde_crtc_check_rois(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_crtc_state; + struct msm_mode_info mode_info; + int rc, lm_idx, i; + + if (!crtc || !state) + return -EINVAL; + + memset(&mode_info, 0, sizeof(mode_info)); + + sde_crtc = to_sde_crtc(crtc); + sde_crtc_state = to_sde_crtc_state(state); + + /* + * check connector array cached at modeset time since incoming atomic + * state may not include any connectors if they aren't modified + */ + for (i = 0; i < sde_crtc_state->num_connectors; i++) { + struct drm_connector *conn = sde_crtc_state->connectors[i]; + + if (!conn || !conn->state) + continue; + + rc = sde_connector_state_get_mode_info(conn->state, &mode_info); + if (rc) { + SDE_ERROR("failed to get mode info\n"); + return -EINVAL; + } + + if (!mode_info.roi_caps.enabled) + continue; + + if (sde_crtc_state->user_roi_list.num_rects > + mode_info.roi_caps.num_roi) { + SDE_ERROR("roi count is exceeding limit, %d > %d\n", + sde_crtc_state->user_roi_list.num_rects, + mode_info.roi_caps.num_roi); + return -E2BIG; + } + + rc = _sde_crtc_set_crtc_roi(crtc, state); + if (rc) + return rc; + + rc = _sde_crtc_check_autorefresh(crtc, state); + if (rc) + return rc; + + for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { + rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx); + if (rc) + return rc; + } + + rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state); + if (rc) + return rc; + + rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state); + if (rc) + return rc; + } + + return 0; +} + +static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *crtc_state; + const struct sde_rect *lm_roi; + struct sde_hw_mixer *hw_lm; + int lm_idx, lm_horiz_position; + + if (!crtc) + return; + + sde_crtc = to_sde_crtc(crtc); + crtc_state = to_sde_crtc_state(crtc->state); + + lm_horiz_position = 0; + for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { + struct sde_hw_mixer_cfg cfg; + + lm_roi = &crtc_state->lm_roi[lm_idx]; + hw_lm = sde_crtc->mixers[lm_idx].hw_lm; + + SDE_EVT32(DRMID(crtc_state->base.crtc), lm_idx, + lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h); + + if (sde_kms_rect_is_null(lm_roi)) + continue; + + hw_lm->cfg.out_width = lm_roi->w; + hw_lm->cfg.out_height = lm_roi->h; + hw_lm->cfg.right_mixer = lm_horiz_position; + + cfg.out_width = lm_roi->w; + cfg.out_height = lm_roi->h; + cfg.right_mixer = lm_horiz_position++; + cfg.flags = 0; + hw_lm->ops.setup_mixer_out(hw_lm, &cfg); + } +} + +struct plane_state { + struct sde_plane_state *sde_pstate; + const struct drm_plane_state *drm_pstate; + int stage; + u32 pipe_id; +}; + +static int pstate_cmp(const void *a, const void *b) +{ + struct plane_state *pa = (struct plane_state *)a; + struct plane_state *pb = (struct plane_state *)b; + int rc = 0; + int pa_zpos, pb_zpos; + + pa_zpos = sde_plane_get_property(pa->sde_pstate, PLANE_PROP_ZPOS); + pb_zpos = sde_plane_get_property(pb->sde_pstate, PLANE_PROP_ZPOS); + + if (pa_zpos != pb_zpos) + rc = pa_zpos - pb_zpos; + else + rc = pa->drm_pstate->crtc_x - pb->drm_pstate->crtc_x; + + return rc; +} + +/* + * validate and set source split: + * use pstates sorted by stage to check planes on same stage + * we assume that all pipes are in source split so its valid to compare + * without taking into account left/right mixer placement + */ +static int _sde_crtc_validate_src_split_order(struct drm_crtc *crtc, + struct plane_state *pstates, int cnt) +{ + struct plane_state *prv_pstate, *cur_pstate; + struct sde_rect left_rect, right_rect; + struct sde_kms *sde_kms; + int32_t left_pid, right_pid; + int32_t stage; + int i, rc = 0; + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms || !sde_kms->catalog) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + for (i = 1; i < cnt; i++) { + prv_pstate = &pstates[i - 1]; + cur_pstate = &pstates[i]; + + if (prv_pstate->stage != cur_pstate->stage) + continue; + + stage = cur_pstate->stage; + + left_pid = prv_pstate->sde_pstate->base.plane->base.id; + POPULATE_RECT(&left_rect, prv_pstate->drm_pstate->crtc_x, + prv_pstate->drm_pstate->crtc_y, + prv_pstate->drm_pstate->crtc_w, + prv_pstate->drm_pstate->crtc_h, false); + + right_pid = cur_pstate->sde_pstate->base.plane->base.id; + POPULATE_RECT(&right_rect, cur_pstate->drm_pstate->crtc_x, + cur_pstate->drm_pstate->crtc_y, + cur_pstate->drm_pstate->crtc_w, + cur_pstate->drm_pstate->crtc_h, false); + + if (right_rect.x < left_rect.x) { + swap(left_pid, right_pid); + swap(left_rect, right_rect); + swap(prv_pstate, cur_pstate); + } + + /* + * - planes are enumerated in pipe-priority order such that + * planes with lower drm_id must be left-most in a shared + * blend-stage when using source split. + * - planes in source split must be contiguous in width + * - planes in source split must have same dest yoff and height + */ + if ((right_pid < left_pid) && + !sde_kms->catalog->pipe_order_type) { + SDE_ERROR( + "invalid src split cfg, stage:%d left:%d right:%d\n", + stage, left_pid, right_pid); + return -EINVAL; + } else if (right_rect.x != (left_rect.x + left_rect.w)) { + SDE_ERROR( + "invalid coordinates, stage:%d l:%d-%d r:%d-%d\n", + stage, left_rect.x, left_rect.w, + right_rect.x, right_rect.w); + return -EINVAL; + } else if ((left_rect.y != right_rect.y) || + (left_rect.h != right_rect.h)) { + SDE_ERROR( + "stage:%d invalid yoff/ht: l_yxh:%dx%d r_yxh:%dx%d\n", + stage, left_rect.y, left_rect.h, + right_rect.y, right_rect.h); + return -EINVAL; + } + } + + return rc; +} + +static void _sde_crtc_set_src_split_order(struct drm_crtc *crtc, + struct plane_state *pstates, int cnt) +{ + struct plane_state *prv_pstate, *cur_pstate, *nxt_pstate; + struct sde_kms *sde_kms; + struct sde_rect left_rect, right_rect; + int32_t left_pid, right_pid; + int32_t stage; + int i; + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms || !sde_kms->catalog) { + SDE_ERROR("invalid parameters\n"); + return; + } + + if (!sde_kms->catalog->pipe_order_type) + return; + + for (i = 0; i < cnt; i++) { + prv_pstate = (i > 0) ? &pstates[i - 1] : NULL; + cur_pstate = &pstates[i]; + nxt_pstate = ((i + 1) < cnt) ? &pstates[i + 1] : NULL; + + if ((!prv_pstate) || (prv_pstate->stage != cur_pstate->stage)) { + /* + * reset if prv or nxt pipes are not in the same stage + * as the cur pipe + */ + if ((!nxt_pstate) + || (nxt_pstate->stage != cur_pstate->stage)) + cur_pstate->sde_pstate->pipe_order_flags = 0; + + continue; + } + + stage = cur_pstate->stage; + + left_pid = prv_pstate->sde_pstate->base.plane->base.id; + POPULATE_RECT(&left_rect, prv_pstate->drm_pstate->crtc_x, + prv_pstate->drm_pstate->crtc_y, + prv_pstate->drm_pstate->crtc_w, + prv_pstate->drm_pstate->crtc_h, false); + + right_pid = cur_pstate->sde_pstate->base.plane->base.id; + POPULATE_RECT(&right_rect, cur_pstate->drm_pstate->crtc_x, + cur_pstate->drm_pstate->crtc_y, + cur_pstate->drm_pstate->crtc_w, + cur_pstate->drm_pstate->crtc_h, false); + + if (right_rect.x < left_rect.x) { + swap(left_pid, right_pid); + swap(left_rect, right_rect); + swap(prv_pstate, cur_pstate); + } + + cur_pstate->sde_pstate->pipe_order_flags = SDE_SSPP_RIGHT; + prv_pstate->sde_pstate->pipe_order_flags = 0; + } + + for (i = 0; i < cnt; i++) { + cur_pstate = &pstates[i]; + sde_plane_setup_src_split_order( + cur_pstate->drm_pstate->plane, + cur_pstate->sde_pstate->multirect_index, + cur_pstate->sde_pstate->pipe_order_flags); + } +} +static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, + struct drm_crtc_state *old_state, struct sde_crtc *sde_crtc, + struct sde_crtc_mixer *mixer) +{ + struct drm_plane *plane; + struct drm_framebuffer *fb; + struct drm_plane_state *state; + struct sde_crtc_state *cstate; + struct sde_plane_state *pstate = NULL; + struct plane_state *pstates = NULL; + struct sde_format *format; + struct sde_hw_ctl *ctl; + struct sde_hw_mixer *lm; + struct sde_hw_stage_cfg *stage_cfg; + struct sde_rect plane_crtc_roi; + uint32_t stage_idx, lm_idx; + int zpos_cnt[SDE_STAGE_MAX + 1] = { 0 }; + int i, mode, cnt = 0; + bool bg_alpha_enable = false, is_secure = false; + + if (!sde_crtc || !crtc->state || !mixer) { + SDE_ERROR("invalid sde_crtc or mixer\n"); + return; + } + + ctl = mixer->hw_ctl; + lm = mixer->hw_lm; + stage_cfg = &sde_crtc->stage_cfg; + cstate = to_sde_crtc_state(crtc->state); + pstates = kcalloc(SDE_PSTATES_MAX, + sizeof(struct plane_state), GFP_KERNEL); + if (!pstates) + return; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + state = plane->state; + if (!state) + continue; + + plane_crtc_roi.x = state->crtc_x; + plane_crtc_roi.y = state->crtc_y; + plane_crtc_roi.w = state->crtc_w; + plane_crtc_roi.h = state->crtc_h; + + pstate = to_sde_plane_state(state); + fb = state->fb; + + mode = sde_plane_get_property(pstate, + PLANE_PROP_FB_TRANSLATION_MODE); + is_secure = ((mode == SDE_DRM_FB_SEC) || + (mode == SDE_DRM_FB_SEC_DIR_TRANS)) ? + true : false; + + sde_plane_ctl_flush(plane, ctl, true); + + SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n", + crtc->base.id, + pstate->stage, + plane->base.id, + sde_plane_pipe(plane) - SSPP_VIG0, + state->fb ? state->fb->base.id : -1); + + format = to_sde_format(msm_framebuffer_format(pstate->base.fb)); + if (!format) { + SDE_ERROR("invalid format\n"); + goto end; + } + + if (pstate->stage == SDE_STAGE_BASE && format->alpha_enable) + bg_alpha_enable = true; + + SDE_EVT32(DRMID(crtc), DRMID(plane), + state->fb ? state->fb->base.id : -1, + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + pstate->rotation, is_secure); + + stage_idx = zpos_cnt[pstate->stage]++; + stage_cfg->stage[pstate->stage][stage_idx] = + sde_plane_pipe(plane); + stage_cfg->multirect_index[pstate->stage][stage_idx] = + pstate->multirect_index; + + SDE_EVT32(DRMID(crtc), DRMID(plane), stage_idx, + sde_plane_pipe(plane) - SSPP_VIG0, pstate->stage, + pstate->multirect_index, pstate->multirect_mode, + format->base.pixel_format, fb ? fb->modifier : 0); + + /* blend config update */ + for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { + _sde_crtc_setup_blend_cfg(mixer + lm_idx, pstate, + format); + + if (bg_alpha_enable && !format->alpha_enable) + mixer[lm_idx].mixer_op_mode = 0; + else + mixer[lm_idx].mixer_op_mode |= + 1 << pstate->stage; + } + + if (cnt >= SDE_PSTATES_MAX) + continue; + + pstates[cnt].sde_pstate = pstate; + pstates[cnt].drm_pstate = state; + pstates[cnt].stage = sde_plane_get_property( + pstates[cnt].sde_pstate, PLANE_PROP_ZPOS); + pstates[cnt].pipe_id = sde_plane_pipe(plane); + + cnt++; + } + + sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); + _sde_crtc_set_src_split_order(crtc, pstates, cnt); + + if (lm && lm->ops.setup_dim_layer) { + cstate = to_sde_crtc_state(crtc->state); + for (i = 0; i < cstate->num_dim_layers; i++) + _sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc, + mixer, &cstate->dim_layer[i]); + if (cstate->fingerprint_dim_layer) + { + _sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc, + mixer, cstate->fingerprint_dim_layer); + } + } + + _sde_crtc_program_lm_output_roi(crtc); + +end: + kfree(pstates); +} + +static void _sde_crtc_swap_mixers_for_right_partial_update( + struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_encoder *drm_enc; + bool is_right_only; + bool encoder_in_dsc_merge = false; + + if (!crtc || !crtc->state) + return; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + + if (sde_crtc->num_mixers != CRTC_DUAL_MIXERS) + return; + + drm_for_each_encoder_mask(drm_enc, crtc->dev, + crtc->state->encoder_mask) { + if (sde_encoder_is_dsc_merge(drm_enc)) { + encoder_in_dsc_merge = true; + break; + } + } + + /** + * For right-only partial update with DSC merge, we swap LM0 & LM1. + * This is due to two reasons: + * - On 8996, there is a DSC HW requirement that in DSC Merge Mode, + * the left DSC must be used, right DSC cannot be used alone. + * For right-only partial update, this means swap layer mixers to map + * Left LM to Right INTF. On later HW this was relaxed. + * - In DSC Merge mode, the physical encoder has already registered + * PP0 as the master, to switch to right-only we would have to + * reprogram to be driven by PP1 instead. + * To support both cases, we prefer to support the mixer swap solution. + */ + if (!encoder_in_dsc_merge) + return; + + is_right_only = sde_kms_rect_is_null(&cstate->lm_roi[0]) && + !sde_kms_rect_is_null(&cstate->lm_roi[1]); + + if (is_right_only && !sde_crtc->mixers_swapped) { + /* right-only update swap mixers */ + swap(sde_crtc->mixers[0], sde_crtc->mixers[1]); + sde_crtc->mixers_swapped = true; + } else if (!is_right_only && sde_crtc->mixers_swapped) { + /* left-only or full update, swap back */ + swap(sde_crtc->mixers[0], sde_crtc->mixers[1]); + sde_crtc->mixers_swapped = false; + } + + SDE_DEBUG("%s: right_only %d swapped %d, mix0->lm%d, mix1->lm%d\n", + sde_crtc->name, is_right_only, sde_crtc->mixers_swapped, + sde_crtc->mixers[0].hw_lm->idx - LM_0, + sde_crtc->mixers[1].hw_lm->idx - LM_0); + SDE_EVT32(DRMID(crtc), is_right_only, sde_crtc->mixers_swapped, + sde_crtc->mixers[0].hw_lm->idx - LM_0, + sde_crtc->mixers[1].hw_lm->idx - LM_0); +} + +/** + * _sde_crtc_blend_setup - configure crtc mixers + * @crtc: Pointer to drm crtc structure + * @old_state: Pointer to old crtc state + * @add_planes: Whether or not to add planes to mixers + */ +static void _sde_crtc_blend_setup(struct drm_crtc *crtc, + struct drm_crtc_state *old_state, bool add_planes) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *sde_crtc_state; + struct sde_crtc_mixer *mixer; + struct sde_hw_ctl *ctl; + struct sde_hw_mixer *lm; + struct sde_ctl_flush_cfg cfg = {0,}; + + int i; + + if (!crtc) + return; + + sde_crtc = to_sde_crtc(crtc); + sde_crtc_state = to_sde_crtc_state(crtc->state); + mixer = sde_crtc->mixers; + + SDE_DEBUG("%s\n", sde_crtc->name); + + if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { + SDE_ERROR("invalid number mixers: %d\n", sde_crtc->num_mixers); + return; + } + + for (i = 0; i < sde_crtc->num_mixers; i++) { + if (!mixer[i].hw_lm || !mixer[i].hw_ctl) { + SDE_ERROR("invalid lm or ctl assigned to mixer\n"); + return; + } + mixer[i].mixer_op_mode = 0; + if (mixer[i].hw_ctl->ops.clear_all_blendstages) + mixer[i].hw_ctl->ops.clear_all_blendstages( + mixer[i].hw_ctl); + + /* clear dim_layer settings */ + lm = mixer[i].hw_lm; + if (lm->ops.clear_dim_layer) + lm->ops.clear_dim_layer(lm); + } + + _sde_crtc_swap_mixers_for_right_partial_update(crtc); + + /* initialize stage cfg */ + memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg)); + + if (add_planes) + _sde_crtc_blend_setup_mixer(crtc, old_state, sde_crtc, mixer); + + for (i = 0; i < sde_crtc->num_mixers; i++) { + const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i]; + + ctl = mixer[i].hw_ctl; + lm = mixer[i].hw_lm; + + if (sde_kms_rect_is_null(lm_roi)) { + SDE_DEBUG( + "%s: lm%d leave ctl%d mask 0 since null roi\n", + sde_crtc->name, lm->idx - LM_0, + ctl->idx - CTL_0); + continue; + } + + lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode); + + /* stage config flush mask */ + ctl->ops.update_bitmask_mixer(ctl, mixer[i].hw_lm->idx, 1); + ctl->ops.get_pending_flush(ctl, &cfg); + + SDE_DEBUG("lm %d, op_mode 0x%X, ctl %d, flush mask 0x%x\n", + mixer[i].hw_lm->idx - LM_0, + mixer[i].mixer_op_mode, + ctl->idx - CTL_0, + cfg.pending_flush_mask); + + ctl->ops.setup_blendstage(ctl, mixer[i].hw_lm->idx, + &sde_crtc->stage_cfg); + } + + _sde_crtc_program_lm_output_roi(crtc); +} + +int sde_crtc_find_plane_fb_modes(struct drm_crtc *crtc, + uint32_t *fb_ns, uint32_t *fb_sec, uint32_t *fb_sec_dir) +{ + struct drm_plane *plane; + struct sde_plane_state *sde_pstate; + uint32_t mode = 0; + int rc; + + if (!crtc) { + SDE_ERROR("invalid state\n"); + return -EINVAL; + } + + *fb_ns = 0; + *fb_sec = 0; + *fb_sec_dir = 0; + drm_atomic_crtc_for_each_plane(plane, crtc) { + if (IS_ERR_OR_NULL(plane) || IS_ERR_OR_NULL(plane->state)) { + rc = PTR_ERR(plane); + SDE_ERROR("crtc%d failed to get plane%d state%d\n", + DRMID(crtc), DRMID(plane), rc); + return rc; + } + sde_pstate = to_sde_plane_state(plane->state); + mode = sde_plane_get_property(sde_pstate, + PLANE_PROP_FB_TRANSLATION_MODE); + + switch (mode) { + case SDE_DRM_FB_NON_SEC: + (*fb_ns)++; + break; + case SDE_DRM_FB_SEC: + (*fb_sec)++; + break; + case SDE_DRM_FB_SEC_DIR_TRANS: + (*fb_sec_dir)++; + break; + default: + SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d", + DRMID(plane), mode); + return -EINVAL; + } + } + return 0; +} + +int sde_crtc_state_find_plane_fb_modes(struct drm_crtc_state *state, + uint32_t *fb_ns, uint32_t *fb_sec, uint32_t *fb_sec_dir) +{ + struct drm_plane *plane; + const struct drm_plane_state *pstate; + struct sde_plane_state *sde_pstate; + uint32_t mode = 0; + int rc; + + if (!state) { + SDE_ERROR("invalid state\n"); + return -EINVAL; + } + + *fb_ns = 0; + *fb_sec = 0; + *fb_sec_dir = 0; + drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { + if (IS_ERR_OR_NULL(pstate)) { + rc = PTR_ERR(pstate); + SDE_ERROR("crtc%d failed to get plane%d state%d\n", + DRMID(state->crtc), DRMID(plane), rc); + return rc; + } + sde_pstate = to_sde_plane_state(pstate); + mode = sde_plane_get_property(sde_pstate, + PLANE_PROP_FB_TRANSLATION_MODE); + + switch (mode) { + case SDE_DRM_FB_NON_SEC: + (*fb_ns)++; + break; + case SDE_DRM_FB_SEC: + (*fb_sec)++; + break; + case SDE_DRM_FB_SEC_DIR_TRANS: + (*fb_sec_dir)++; + break; + default: + SDE_ERROR("Error: Plane[%d], fb_trans_mode:%d", + DRMID(plane), mode); + return -EINVAL; + } + } + return 0; +} + +static void _sde_drm_fb_sec_dir_trans( + struct sde_kms_smmu_state_data *smmu_state, uint32_t secure_level, + struct sde_mdss_cfg *catalog, bool old_valid_fb, int *ops) +{ + /* secure display usecase */ + if ((smmu_state->state == ATTACHED) + && (secure_level == SDE_DRM_SEC_ONLY)) { + smmu_state->state = catalog->sui_ns_allowed ? + DETACH_SEC_REQ : DETACH_ALL_REQ; + smmu_state->secure_level = secure_level; + smmu_state->transition_type = PRE_COMMIT; + *ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE; + if (old_valid_fb) + *ops |= (SDE_KMS_OPS_WAIT_FOR_TX_DONE | + SDE_KMS_OPS_CLEANUP_PLANE_FB); + if (catalog->sui_misr_supported) + smmu_state->sui_misr_state = + SUI_MISR_ENABLE_REQ; + /* secure camera usecase */ + } else if (smmu_state->state == ATTACHED) { + smmu_state->state = DETACH_SEC_REQ; + smmu_state->secure_level = secure_level; + smmu_state->transition_type = PRE_COMMIT; + *ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE; + } +} + +static void _sde_drm_fb_transactions( + struct sde_kms_smmu_state_data *smmu_state, + struct sde_mdss_cfg *catalog, bool old_valid_fb, bool post_commit, + int *ops) +{ + if (((smmu_state->state == DETACHED) + || (smmu_state->state == DETACH_ALL_REQ)) + || ((smmu_state->secure_level == SDE_DRM_SEC_ONLY) + && ((smmu_state->state == DETACHED_SEC) + || (smmu_state->state == DETACH_SEC_REQ)))) { + smmu_state->state = catalog->sui_ns_allowed ? + ATTACH_SEC_REQ : ATTACH_ALL_REQ; + smmu_state->transition_type = post_commit ? + POST_COMMIT : PRE_COMMIT; + *ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE; + if (old_valid_fb) + *ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE; + if (catalog->sui_misr_supported) + smmu_state->sui_misr_state = + SUI_MISR_DISABLE_REQ; + } else if ((smmu_state->state == DETACHED_SEC) + || (smmu_state->state == DETACH_SEC_REQ)) { + smmu_state->state = ATTACH_SEC_REQ; + smmu_state->transition_type = post_commit ? + POST_COMMIT : PRE_COMMIT; + *ops |= SDE_KMS_OPS_SECURE_STATE_CHANGE; + if (old_valid_fb) + *ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE; + } +} + +/** + * sde_crtc_get_secure_transition_ops - determines the operations that + * need to be performed before transitioning to secure state + * This function should be called after swapping the new state + * @crtc: Pointer to drm crtc structure + * Returns the bitmask of operations need to be performed, -Error in + * case of error cases + */ +int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state, + bool old_valid_fb) +{ + struct drm_plane *plane; + struct drm_encoder *encoder; + struct sde_crtc *sde_crtc; + struct sde_kms *sde_kms; + struct sde_mdss_cfg *catalog; + struct sde_kms_smmu_state_data *smmu_state; + struct drm_device *dev; + uint32_t translation_mode = 0, secure_level; + int ops = 0; + bool post_commit = false; + bool clone_mode = false; + + if (!crtc || !crtc->state) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) + return -EINVAL; + + smmu_state = &sde_kms->smmu_state; + smmu_state->prev_state = smmu_state->state; + smmu_state->prev_secure_level = smmu_state->secure_level; + + sde_crtc = to_sde_crtc(crtc); + secure_level = sde_crtc_get_secure_level(crtc, crtc->state); + catalog = sde_kms->catalog; + dev = sde_kms->dev; + + /* + * Loop through encoder list to find out if clone mode is + * enabled on any of the encoders. If clone mode is enabled, + * wait for the cwb commit to be completed, before making + * the secure transition. + */ + list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head) + if (sde_encoder_in_clone_mode(encoder)) + clone_mode = true; + + /* + * SMMU operations need to be delayed in case of video mode panels + * when switching back to non_secure mode + */ + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + if (sde_encoder_is_dsi_display(encoder)) + post_commit |= sde_encoder_check_curr_mode(encoder, + MSM_DISPLAY_VIDEO_MODE); + } + + SDE_DEBUG("crtc%d: secure_level %d old_valid_fb %d post_commit %d\n", + DRMID(crtc), secure_level, old_valid_fb, post_commit); + SDE_EVT32_VERBOSE(DRMID(crtc), secure_level, smmu_state->state, + old_valid_fb, post_commit, SDE_EVTLOG_FUNC_ENTRY); + + drm_atomic_crtc_for_each_plane(plane, crtc) { + if (!plane->state) + continue; + + translation_mode = sde_plane_get_property( + to_sde_plane_state(plane->state), + PLANE_PROP_FB_TRANSLATION_MODE); + if (translation_mode > SDE_DRM_FB_SEC_DIR_TRANS) { + SDE_ERROR("crtc%d: invalid translation_mode %d\n", + DRMID(crtc), translation_mode); + return -EINVAL; + } + + /* we can break if we find sec_dir plane */ + if (translation_mode == SDE_DRM_FB_SEC_DIR_TRANS) + break; + } + + mutex_lock(&sde_kms->secure_transition_lock); + + switch (translation_mode) { + case SDE_DRM_FB_SEC_DIR_TRANS: + _sde_drm_fb_sec_dir_trans(smmu_state, secure_level, + catalog, old_valid_fb, &ops); + if (clone_mode && (ops & SDE_KMS_OPS_SECURE_STATE_CHANGE)) + ops |= SDE_KMS_OPS_WAIT_FOR_TX_DONE; + break; + + case SDE_DRM_FB_SEC: + case SDE_DRM_FB_NON_SEC: + _sde_drm_fb_transactions(smmu_state, catalog, + old_valid_fb, post_commit, &ops); + break; + + default: + SDE_ERROR("crtc%d: invalid plane fb_mode %d\n", + DRMID(crtc), translation_mode); + ops = -EINVAL; + } + + /* log only during actual transition times */ + if (ops) { + SDE_DEBUG("crtc%d: state%d sec%d sec_lvl%d type%d ops%x\n", + DRMID(crtc), smmu_state->state, + secure_level, smmu_state->secure_level, + smmu_state->transition_type, ops); + SDE_EVT32(DRMID(crtc), secure_level, translation_mode, + smmu_state->state, smmu_state->transition_type, + smmu_state->secure_level, old_valid_fb, + post_commit, ops, SDE_EVTLOG_FUNC_EXIT); + } + + mutex_unlock(&sde_kms->secure_transition_lock); + + return ops; +} + +/** + * _sde_crtc_setup_scaler3_lut - Set up scaler lut + * LUTs are configured only once during boot + * @sde_crtc: Pointer to sde crtc + * @cstate: Pointer to sde crtc state + */ +static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc, + struct sde_crtc_state *cstate, uint32_t lut_idx) +{ + struct sde_hw_scaler3_lut_cfg *cfg; + struct sde_kms *sde_kms; + u32 *lut_data = NULL; + size_t len = 0; + int ret = 0; + + if (!sde_crtc || !cstate) { + SDE_ERROR("invalid args\n"); + return -EINVAL; + } + + sde_kms = _sde_crtc_get_kms(&sde_crtc->base); + if (!sde_kms) + return -EINVAL; + + if (is_qseed3_rev_qseed3lite(sde_kms->catalog)) + return 0; + + lut_data = msm_property_get_blob(&sde_crtc->property_info, + &cstate->property_state, &len, lut_idx); + if (!lut_data || !len) { + SDE_DEBUG("%s: lut(%d): cleared: %pK, %zu\n", sde_crtc->name, + lut_idx, lut_data, len); + lut_data = NULL; + len = 0; + } + + cfg = &cstate->scl3_lut_cfg; + + switch (lut_idx) { + case CRTC_PROP_DEST_SCALER_LUT_ED: + cfg->dir_lut = lut_data; + cfg->dir_len = len; + break; + case CRTC_PROP_DEST_SCALER_LUT_CIR: + cfg->cir_lut = lut_data; + cfg->cir_len = len; + break; + case CRTC_PROP_DEST_SCALER_LUT_SEP: + cfg->sep_lut = lut_data; + cfg->sep_len = len; + break; + default: + ret = -EINVAL; + SDE_ERROR("%s:invalid LUT idx(%d)\n", sde_crtc->name, lut_idx); + SDE_EVT32(DRMID(&sde_crtc->base), lut_idx, SDE_EVTLOG_ERROR); + break; + } + + cfg->is_configured = cfg->dir_lut && cfg->cir_lut && cfg->sep_lut; + + SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), ret, lut_idx, len, + cfg->is_configured); + return ret; +} + +void sde_crtc_timeline_status(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + sde_fence_timeline_status(sde_crtc->output_fence, &crtc->base); +} + +static int _sde_validate_hw_resources(struct sde_crtc *sde_crtc) +{ + int i; + + /** + * Check if sufficient hw resources are + * available as per target caps & topology + */ + if (!sde_crtc) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + if (!sde_crtc->num_mixers || + sde_crtc->num_mixers > CRTC_DUAL_MIXERS) { + SDE_ERROR("%s: invalid number mixers: %d\n", + sde_crtc->name, sde_crtc->num_mixers); + SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers, + SDE_EVTLOG_ERROR); + return -EINVAL; + } + + for (i = 0; i < sde_crtc->num_mixers; i++) { + if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ctl + || !sde_crtc->mixers[i].hw_ds) { + SDE_ERROR("%s:insufficient resources for mixer(%d)\n", + sde_crtc->name, i); + SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers, + i, sde_crtc->mixers[i].hw_lm, + sde_crtc->mixers[i].hw_ctl, + sde_crtc->mixers[i].hw_ds, SDE_EVTLOG_ERROR); + return -EINVAL; + } + } + + return 0; +} + +/** + * _sde_crtc_dest_scaler_setup - Set up dest scaler block + * @crtc: Pointer to drm crtc + */ +static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct sde_hw_mixer *hw_lm; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_ds *hw_ds; + struct sde_hw_ds_cfg *cfg; + struct sde_kms *kms; + u32 op_mode = 0; + u32 lm_idx = 0, num_mixers = 0; + int i, count = 0; + bool ds_dirty = false; + + if (!crtc) + return; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + kms = _sde_crtc_get_kms(crtc); + num_mixers = sde_crtc->num_mixers; + count = cstate->num_ds; + + SDE_DEBUG("crtc%d\n", crtc->base.id); + SDE_EVT32(DRMID(crtc), num_mixers, count, cstate->ds_dirty, + sde_crtc->ds_reconfig, cstate->num_ds_enabled); + + /** + * destination scaler configuration will be done either + * or on set property or on power collapse (idle/suspend) + */ + ds_dirty = (cstate->ds_dirty || sde_crtc->ds_reconfig); + if (sde_crtc->ds_reconfig) { + SDE_DEBUG("reconfigure dest scaler block\n"); + sde_crtc->ds_reconfig = false; + } + + if (!ds_dirty) { + SDE_DEBUG("no change in settings, skip commit\n"); + } else if (!kms || !kms->catalog) { + SDE_ERROR("crtc%d:invalid parameters\n", crtc->base.id); + } else if (!kms->catalog->mdp[0].has_dest_scaler) { + SDE_DEBUG("dest scaler feature not supported\n"); + } else if (_sde_validate_hw_resources(sde_crtc)) { + //do nothing + } else if ((!cstate->scl3_lut_cfg.is_configured) && + (!is_qseed3_rev_qseed3lite(kms->catalog))) { + SDE_ERROR("crtc%d:no LUT data available\n", crtc->base.id); + } else { + for (i = 0; i < count; i++) { + cfg = &cstate->ds_cfg[i]; + + if (!cfg->flags) + continue; + + lm_idx = cfg->idx; + hw_lm = sde_crtc->mixers[lm_idx].hw_lm; + hw_ctl = sde_crtc->mixers[lm_idx].hw_ctl; + hw_ds = sde_crtc->mixers[lm_idx].hw_ds; + + /* Setup op mode - Dual/single */ + if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE) + op_mode |= BIT(hw_ds->idx - DS_0); + + if ((i == count-1) && hw_ds->ops.setup_opmode) { + op_mode |= (cstate->num_ds_enabled == + CRTC_DUAL_MIXERS) ? + SDE_DS_OP_MODE_DUAL : 0; + hw_ds->ops.setup_opmode(hw_ds, op_mode); + SDE_EVT32_VERBOSE(DRMID(crtc), op_mode); + } + + /* Setup scaler */ + if ((cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE) || + (cfg->flags & + SDE_DRM_DESTSCALER_ENHANCER_UPDATE)) { + if (hw_ds->ops.setup_scaler) + hw_ds->ops.setup_scaler(hw_ds, + &cfg->scl3_cfg, + &cstate->scl3_lut_cfg); + + } + + /* + * Dest scaler shares the flush bit of the LM in control + */ + if (hw_ctl && hw_ctl->ops.update_bitmask_mixer) + hw_ctl->ops.update_bitmask_mixer( + hw_ctl, hw_lm->idx, 1); + } + } +} + +static void sde_crtc_frame_event_cb(void *data, u32 event) +{ + struct drm_crtc *crtc = (struct drm_crtc *)data; + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv; + struct sde_crtc_frame_event *fevent; + struct sde_crtc_frame_event_cb_data *cb_data; + struct drm_plane *plane; + u32 ubwc_error; + unsigned long flags; + u32 crtc_id; + + cb_data = (struct sde_crtc_frame_event_cb_data *)data; + if (!data) { + SDE_ERROR("invalid parameters\n"); + return; + } + + crtc = cb_data->crtc; + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid parameters\n"); + return; + } + sde_crtc = to_sde_crtc(crtc); + priv = crtc->dev->dev_private; + crtc_id = drm_crtc_index(crtc); + + SDE_DEBUG("crtc%d\n", crtc->base.id); + SDE_EVT32_VERBOSE(DRMID(crtc), event); + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, + struct sde_crtc_frame_event, list); + if (fevent) + list_del_init(&fevent->list); + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + if (!fevent) { + SDE_ERROR("crtc%d event %d overflow\n", + crtc->base.id, event); + SDE_EVT32(DRMID(crtc), event); + return; + } + + /* log and clear plane ubwc errors if any */ + if (event & (SDE_ENCODER_FRAME_EVENT_ERROR + | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD + | SDE_ENCODER_FRAME_EVENT_DONE)) { + drm_for_each_plane_mask(plane, crtc->dev, + sde_crtc->plane_mask_old) { + ubwc_error = sde_plane_get_ubwc_error(plane); + if (ubwc_error) { + SDE_EVT32(DRMID(crtc), DRMID(plane), + ubwc_error, SDE_EVTLOG_ERROR); + SDE_DEBUG("crtc%d plane %d ubwc_error %d\n", + DRMID(crtc), DRMID(plane), + ubwc_error); + sde_plane_clear_ubwc_error(plane); + } + } + } + + fevent->event = event; + fevent->crtc = crtc; + fevent->connector = cb_data->connector; + fevent->ts = ktime_get(); + kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); +} + +void sde_crtc_prepare_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct drm_device *dev; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_connector *conn; + struct drm_encoder *encoder; + struct drm_connector_list_iter conn_iter; + + if (!crtc || !crtc->state) { + SDE_ERROR("invalid crtc\n"); + return; + } + + dev = crtc->dev; + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + SDE_EVT32_VERBOSE(DRMID(crtc)); + + SDE_ATRACE_BEGIN("sde_crtc_prepare_commit"); + + /* identify connectors attached to this crtc */ + cstate->num_connectors = 0; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) + if (conn->state && conn->state->crtc == crtc && + cstate->num_connectors < MAX_CONNECTORS) { + encoder = conn->state->best_encoder; + if (encoder) + sde_encoder_register_frame_event_callback( + encoder, + sde_crtc_frame_event_cb, + crtc); + + cstate->connectors[cstate->num_connectors++] = conn; + sde_connector_prepare_fence(conn); + } + drm_connector_list_iter_end(&conn_iter); + + /* prepare main output fence */ + sde_fence_prepare(sde_crtc->output_fence); + SDE_ATRACE_END("sde_crtc_prepare_commit"); +} + +/** + * sde_crtc_complete_flip - signal pending page_flip events + * Any pending vblank events are added to the vblank_event_list + * so that the next vblank interrupt shall signal them. + * However PAGE_FLIP events are not handled through the vblank_event_list. + * This API signals any pending PAGE_FLIP events requested through + * DRM_IOCTL_MODE_PAGE_FLIP and are cached in the sde_crtc->event. + * if file!=NULL, this is preclose potential cancel-flip path + * @crtc: Pointer to drm crtc structure + * @file: Pointer to drm file + */ +void sde_crtc_complete_flip(struct drm_crtc *crtc, + struct drm_file *file) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_pending_vblank_event *event; + unsigned long flags; + + spin_lock_irqsave(&dev->event_lock, flags); + event = sde_crtc->event; + if (!event) + goto end; + + /* + * if regular vblank case (!file) or if cancel-flip from + * preclose on file that requested flip, then send the + * event: + */ + if (!file || (event->base.file_priv == file)) { + sde_crtc->event = NULL; + DRM_DEBUG_VBL("%s: send event: %pK\n", + sde_crtc->name, event); + SDE_EVT32_VERBOSE(DRMID(crtc)); + drm_crtc_send_vblank_event(crtc, event); + } + +end: + spin_unlock_irqrestore(&dev->event_lock, flags); +} + +enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc, + struct drm_crtc_state *cstate) +{ + struct drm_encoder *encoder; + + if (!crtc || !crtc->dev || !cstate) { + SDE_ERROR("invalid crtc\n"); + return INTF_MODE_NONE; + } + + drm_for_each_encoder_mask(encoder, crtc->dev, + cstate->encoder_mask) { + /* continue if copy encoder is encountered */ + if (sde_encoder_in_clone_mode(encoder)) + continue; + + return sde_encoder_get_intf_mode(encoder); + } + + return INTF_MODE_NONE; +} + +u32 sde_crtc_get_fps_mode(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + + if (!crtc || !crtc->dev) { + SDE_ERROR("invalid crtc\n"); + return INTF_MODE_NONE; + } + + drm_for_each_encoder(encoder, crtc->dev) + if ((encoder->crtc == crtc) + && !sde_encoder_in_cont_splash(encoder)) + return sde_encoder_get_fps(encoder); + + return 0; +} + +static void sde_crtc_vblank_cb(void *data) +{ + struct drm_crtc *crtc = (struct drm_crtc *)data; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + /* keep statistics on vblank callback - with auto reset via debugfs */ + if (ktime_compare(sde_crtc->vblank_cb_time, ktime_set(0, 0)) == 0) + sde_crtc->vblank_cb_time = ktime_get(); + else + sde_crtc->vblank_cb_count++; + + sde_crtc->vblank_last_cb_time = ktime_get(); + sysfs_notify_dirent(sde_crtc->vsync_event_sf); + + drm_crtc_handle_vblank(crtc); + DRM_DEBUG_VBL("crtc%d\n", crtc->base.id); + SDE_EVT32_VERBOSE(DRMID(crtc)); +} + +static void _sde_crtc_retire_event(struct drm_connector *connector, + ktime_t ts, enum sde_fence_event fence_event) +{ + if (!connector) { + SDE_ERROR("invalid param\n"); + return; + } + + SDE_ATRACE_BEGIN("signal_retire_fence"); + sde_connector_complete_commit(connector, ts, fence_event); + SDE_ATRACE_END("signal_retire_fence"); +} + +static void sde_crtc_frame_event_work(struct kthread_work *work) +{ + struct msm_drm_private *priv; + struct sde_crtc_frame_event *fevent; + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + struct sde_kms *sde_kms; + unsigned long flags; + bool in_clone_mode = false; + + if (!work) { + SDE_ERROR("invalid work handle\n"); + return; + } + + fevent = container_of(work, struct sde_crtc_frame_event, work); + if (!fevent->crtc || !fevent->crtc->state) { + SDE_ERROR("invalid crtc\n"); + return; + } + + crtc = fevent->crtc; + sde_crtc = to_sde_crtc(crtc); + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) { + SDE_ERROR("invalid kms handle\n"); + return; + } + priv = sde_kms->dev->dev_private; + SDE_ATRACE_BEGIN("crtc_frame_event"); + + SDE_DEBUG("crtc%d event:%u ts:%lld\n", crtc->base.id, fevent->event, + ktime_to_ns(fevent->ts)); + + SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY); + + in_clone_mode = (fevent->event & SDE_ENCODER_FRAME_EVENT_CWB_DONE) ? + true : false; + + if (!in_clone_mode && (fevent->event & (SDE_ENCODER_FRAME_EVENT_ERROR + | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD + | SDE_ENCODER_FRAME_EVENT_DONE))) { + if (atomic_read(&sde_crtc->frame_pending) < 1) { + /* this should not happen */ + SDE_ERROR("crtc%d ts:%lld invalid frame_pending:%d\n", + crtc->base.id, + ktime_to_ns(fevent->ts), + atomic_read(&sde_crtc->frame_pending)); + SDE_EVT32(DRMID(crtc), fevent->event, + SDE_EVTLOG_FUNC_CASE1); + } else if (atomic_dec_return(&sde_crtc->frame_pending) == 0) { + /* release bandwidth and other resources */ + SDE_DEBUG("crtc%d ts:%lld last pending\n", + crtc->base.id, + ktime_to_ns(fevent->ts)); + SDE_EVT32(DRMID(crtc), fevent->event, + SDE_EVTLOG_FUNC_CASE2); + sde_core_perf_crtc_release_bw(crtc); + } else { + SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, + SDE_EVTLOG_FUNC_CASE3); + } + } + + if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) { + SDE_ATRACE_BEGIN("signal_release_fence"); + sde_fence_signal(sde_crtc->output_fence, fevent->ts, + (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) + ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); + SDE_ATRACE_END("signal_release_fence"); + } + + if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE) + /* this api should be called without spin_lock */ + _sde_crtc_retire_event(fevent->connector, fevent->ts, + (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) + ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); + + if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) + SDE_ERROR("crtc%d ts:%lld received panel dead event\n", + crtc->base.id, ktime_to_ns(fevent->ts)); + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + list_add_tail(&fevent->list, &sde_crtc->frame_event_list); + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + SDE_ATRACE_END("crtc_frame_event"); +} + +void sde_crtc_complete_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct sde_crtc *sde_crtc; + + if (!crtc || !crtc->state) { + SDE_ERROR("invalid crtc\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + SDE_EVT32_VERBOSE(DRMID(crtc)); + + sde_core_perf_crtc_update(crtc, 0, false); + //Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint + { + struct sde_crtc_state *old_cstate; + struct sde_crtc_state *cstate; + struct drm_panel_notifier notifier_data; + int blank; + + if (!old_state) { + SDE_ERROR("failed to find old cstate"); + return; + } + old_cstate = to_sde_crtc_state(old_state); + cstate = to_sde_crtc_state(crtc->state); + + if (old_cstate->fingerprint_pressed != cstate->fingerprint_pressed) { + blank = cstate->fingerprint_pressed; + notifier_data.data = ␣ + pr_err("fingerprint status: %s", + blank ? "pressed" : "up"); + SDE_ATRACE_BEGIN("press_event_notify"); + if (lcd_active_panel) + drm_panel_notifier_call_chain(lcd_active_panel, DRM_PANEL_ONSCREENFINGERPRINT_EVENT, ¬ifier_data); + SDE_ATRACE_END("press_event_notify"); + } + } + +} + +/** + * _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout + * @cstate: Pointer to sde crtc state + */ +static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate) +{ + if (!cstate) { + SDE_ERROR("invalid cstate\n"); + return; + } + cstate->input_fence_timeout_ns = + sde_crtc_get_property(cstate, CRTC_PROP_INPUT_FENCE_TIMEOUT); + cstate->input_fence_timeout_ns *= NSEC_PER_MSEC; +} + +/** + * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings + * @cstate: Pointer to sde crtc state + */ +static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate) +{ + u32 i; + + if (!cstate) + return; + + for (i = 0; i < cstate->num_dim_layers; i++) + memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i])); + + cstate->num_dim_layers = 0; +} + +/** + * _sde_crtc_set_dim_layer_v1 - copy dim layer settings from userspace + * @cstate: Pointer to sde crtc state + * @user_ptr: User ptr for sde_drm_dim_layer_v1 struct + */ +static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc, + struct sde_crtc_state *cstate, void __user *usr_ptr) +{ + struct sde_drm_dim_layer_v1 dim_layer_v1; + struct sde_drm_dim_layer_cfg *user_cfg; + struct sde_hw_dim_layer *dim_layer; + u32 count, i; + struct sde_kms *kms; + + if (!crtc || !cstate) { + SDE_ERROR("invalid crtc or cstate\n"); + return; + } + dim_layer = cstate->dim_layer; + + if (!usr_ptr) { + /* usr_ptr is null when setting the default property value */ + _sde_crtc_clear_dim_layers_v1(cstate); + SDE_DEBUG("dim_layer data removed\n"); + return; + } + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return; + } + + if (copy_from_user(&dim_layer_v1, usr_ptr, sizeof(dim_layer_v1))) { + SDE_ERROR("failed to copy dim_layer data\n"); + return; + } + + count = dim_layer_v1.num_layers; + if (count > SDE_MAX_DIM_LAYERS) { + SDE_ERROR("invalid number of dim_layers:%d", count); + return; + } + + /* populate from user space */ + cstate->num_dim_layers = count; + for (i = 0; i < count; i++) { + user_cfg = &dim_layer_v1.layer_cfg[i]; + + dim_layer[i].flags = user_cfg->flags; + dim_layer[i].stage = (kms->catalog->has_base_layer) ? + user_cfg->stage : user_cfg->stage + + SDE_STAGE_0; + + dim_layer[i].rect.x = user_cfg->rect.x1; + dim_layer[i].rect.y = user_cfg->rect.y1; + dim_layer[i].rect.w = user_cfg->rect.x2 - user_cfg->rect.x1; + dim_layer[i].rect.h = user_cfg->rect.y2 - user_cfg->rect.y1; + + dim_layer[i].color_fill = (struct sde_mdss_color) { + user_cfg->color_fill.color_0, + user_cfg->color_fill.color_1, + user_cfg->color_fill.color_2, + user_cfg->color_fill.color_3, + }; + + SDE_DEBUG("dim_layer[%d] - flags:%d, stage:%d\n", + i, dim_layer[i].flags, dim_layer[i].stage); + SDE_DEBUG(" rect:{%d,%d,%d,%d}, color:{%d,%d,%d,%d}\n", + dim_layer[i].rect.x, dim_layer[i].rect.y, + dim_layer[i].rect.w, dim_layer[i].rect.h, + dim_layer[i].color_fill.color_0, + dim_layer[i].color_fill.color_1, + dim_layer[i].color_fill.color_2, + dim_layer[i].color_fill.color_3); + } +} + +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint +bool sde_crtc_get_dimlayer_mode(struct drm_crtc_state *crtc_state) +{ + struct sde_crtc_state *cstate; + + if (!crtc_state) + return false; + + cstate = to_sde_crtc_state(crtc_state); + return !!cstate->fingerprint_dim_layer; +} + +bool sde_crtc_get_fingerprint_mode(struct drm_crtc_state *crtc_state) +{ + struct sde_crtc_state *cstate; + + if (!crtc_state) + return false; + + cstate = to_sde_crtc_state(crtc_state); + return !!cstate->fingerprint_mode; +} + +bool sde_crtc_get_fingerprint_pressed(struct drm_crtc_state *crtc_state) +{ + struct sde_crtc_state *cstate; + + if (!crtc_state) + return false; + + cstate = to_sde_crtc_state(crtc_state); + return cstate->fingerprint_pressed; +} + +/*******************************************************************/ + +extern int oneplus_force_screenfp; +extern int oneplus_panel_alpha; +struct ba { + u32 brightness; + u32 alpha; +}; +struct ba brightness_alpha_lut_1[] = { + {0, 0xff}, + {2, 0xf1}, + {4, 236}, + {6, 235}, + {8, 234}, + {12, 230}, + {20, 225}, + {40, 214}, + {60, 206}, + {90, 197}, + {140, 184}, + {200, 172}, + {300, 156}, + {454, 137}, + {600, 123}, + {800, 104}, + {1000, 87}, + {1200, 72}, + {1600, 46}, + {2047, 18}, + {2047, 18}, +}; + +struct ba brightness_alpha_lut_2[] = { + {0, 0xff}, + {2, 0xf1}, + {4, 237}, + {6, 236}, + {8, 234}, + {12, 230}, + {20, 223}, + {40, 213}, + {60, 208}, + {90, 197}, + {140, 183}, + {200, 173}, + {300, 164}, + {454, 141}, + {600, 126}, + {800, 104}, + {1000, 90}, + {1200, 75}, + {1600, 50}, + {2047, 25}, + {2047, 25}, +}; + +struct ba brightness_alpha_lut_dc[] = { + + {0, 0xff}, + {1, 0xE0}, + {2, 0xd5}, + {3, 0xd3}, + {4, 0xd0}, + {5, 0xce}, + {6, 0xcb}, + {8, 0xc8}, + {10, 0xc4}, + {15, 0xba}, + {20, 0xb0}, + {30, 0xa0}, + {45, 0x8b}, + {70, 0x72}, + {100, 0x5a}, + {150, 0x38}, + {227, 0xe}, + {260, 0x00} +}; + +struct ba brightness_alpha_lut[21] = {}; +static int interpolate(int x, int xa, int xb, int ya, int yb) +{ + int bf, factor, plus; + int sub = 0; + + bf = 2 * (yb - ya) * (x - xa) / (xb - xa); + factor = bf / 2; + plus = bf % 2; + if ((xa - xb) && (yb - ya)) + sub = 2 * (x - xa) * (x - xb) / (yb - ya) / (xa - xb); + + return ya + factor + plus + sub; +} + +int brightness_to_alpha(int brightness) +{ + int level = ARRAY_SIZE(brightness_alpha_lut); + int i = 0; + + for (i = 0; i < ARRAY_SIZE(brightness_alpha_lut); i++){ + if (brightness_alpha_lut[i].brightness >= brightness) + break; + } + + if (i == 0) + return brightness_alpha_lut[0].alpha; + else if (i == level) + return brightness_alpha_lut[level - 1].alpha; + + return interpolate(brightness, + brightness_alpha_lut[i-1].brightness, + brightness_alpha_lut[i].brightness, + brightness_alpha_lut[i-1].alpha, + brightness_alpha_lut[i].alpha); +} + +int bl_to_alpha_dc(int brightness) +{ + int level = ARRAY_SIZE(brightness_alpha_lut_dc); + int i = 0; + int alpha; + + for (i = 0; i < ARRAY_SIZE(brightness_alpha_lut_dc); i++) { + if (brightness_alpha_lut_dc[i].brightness >= brightness) + break; + } + + if (i == 0) + alpha = brightness_alpha_lut_dc[0].alpha; + else if (i == level) + alpha = brightness_alpha_lut_dc[level - 1].alpha; + else + alpha = interpolate(brightness, + brightness_alpha_lut_dc[i-1].brightness, + brightness_alpha_lut_dc[i].brightness, + brightness_alpha_lut_dc[i-1].alpha, + brightness_alpha_lut_dc[i].alpha); + return alpha; +} + +int oneplus_get_panel_brightness_to_alpha(void) +{ + struct dsi_display *display = get_main_display(); + + if (!display) + return 0; + if (oneplus_panel_alpha) + return oneplus_panel_alpha; + if (display->panel->dim_status) + return brightness_to_alpha(display->panel->hbm_backlight); + else + return bl_to_alpha_dc(display->panel->hbm_backlight); +} +int oneplus_onscreenaod_hid = 0; +int oneplus_aod_hid = 0; +ssize_t notify_aod_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int onscreenaod_hid = 0; + SDE_ATRACE_BEGIN("aod_hid_node"); + sscanf(buf, "%du", &onscreenaod_hid); + //oneplus_onscreenaod_hid = !!onscreenaod_hid; + if (onscreenaod_hid == oneplus_onscreenaod_hid) + { + SDE_ATRACE_END("notify_fppress_store"); + return count; + } + + pr_err("notify aod hid %d\n", onscreenaod_hid ); + oneplus_onscreenaod_hid = onscreenaod_hid; + SDE_ATRACE_END("aod_hid_node"); + return count; +} + +int oneplus_onscreenfp_status = 0; +ssize_t notify_fppress_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + struct drm_device *drm_dev; + struct drm_connector *dsi_connector; + struct drm_mode_config *mode_config; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + struct msm_drm_private *priv; + int err; + ktime_t now; + bool need_commit = false; + int onscreenfp_status = 0; + SDE_ATRACE_BEGIN("notify_fppress_store"); + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + drm_dev = dsi_display->drm_dev; + dsi_connector = dsi_display->drm_conn; + mode_config = &drm_dev->mode_config; + sscanf(buf, "%du", &onscreenfp_status); + //onscreenfp_status = !!onscreenfp_status; + if (onscreenfp_status == oneplus_onscreenfp_status) + { + SDE_ATRACE_END("notify_fppress_store"); + return count; + } + + pr_err("notify fingerpress %d\n", onscreenfp_status ); + oneplus_onscreenfp_status = onscreenfp_status; + + drm_modeset_lock_all(drm_dev); + state = drm_atomic_state_alloc(drm_dev); + state->acquire_ctx = mode_config->acquire_ctx; + crtc = dsi_connector->state->crtc; + crtc_state = drm_atomic_get_crtc_state(state, crtc); + priv = drm_dev->dev_private; + now = ktime_get(); + need_commit = (((now- priv->commit_end_time) > 20000000 ? true:false)&&dsi_display->panel->aod_status==0); + if(need_commit){ + err = drm_atomic_commit(state); + if (err < 0) + drm_atomic_state_clear(state); + } + drm_modeset_unlock_all(drm_dev); + SDE_ATRACE_END("notify_fppress_store"); + return count; +} + +extern int aod_layer_hide; +extern bool HBM_flag; +extern int dsi_panel_tx_cmd_set(struct dsi_panel *panel, + enum dsi_cmd_set_type type); +int oneplus_dim_status = 0; +int oneplus_aod_fod = 0; +int oneplus_aod_dc = 0; +ssize_t notify_dim_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct drm_connector *connector = to_drm_connector(dev); + struct dsi_display *dsi_display = NULL; + struct dsi_bridge *c_bridge; + struct drm_device *drm_dev; + struct drm_connector *dsi_connector; + struct drm_mode_config *mode_config; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int err = 0, rc = 0; + int dim_status = 0; + SDE_ATRACE_BEGIN("notify_dim_store"); + if ((connector == NULL) || (connector->encoder == NULL) + || (connector->encoder->bridge == NULL)) + return 0; + c_bridge = to_dsi_bridge(connector->encoder->bridge); + dsi_display = c_bridge->display; + + if ((dsi_display == NULL) || (dsi_display->panel == NULL)) + return -EINVAL; + drm_dev = dsi_display->drm_dev; + dsi_connector = dsi_display->drm_conn; + mode_config = &drm_dev->mode_config; + sscanf(buf, "%du", &dim_status); + + if(dsi_display->panel->aod_status==0 && (dim_status == 2)){ + pr_err("fp set it in normal status\n"); + if (dim_status == oneplus_dim_status) + return count; + oneplus_dim_status = dim_status; + SDE_ATRACE_END("notify_dim_store"); + return count; + }else if(dsi_display->panel->aod_status==1&& dim_status == 2){ + oneplus_onscreenfp_status = 1; + oneplus_aod_fod = 1; + } else if (dsi_display->panel->aod_status == 1 && dim_status == 0) { + oneplus_onscreenfp_status = 0; + } else if (dsi_display->panel->aod_status == 1 && dim_status == 5) { + oneplus_aod_dc = 1; + } + if (dim_status == 1) + dsi_display->panel->aod_status = 0; + if (dim_status == 0) + oneplus_onscreenfp_status = 0; + if (dim_status == oneplus_dim_status) + return count; + oneplus_dim_status = dim_status; + pr_err("notify dim %d,aod = %d press= %d aod_hide =%d\n", + oneplus_dim_status, dsi_display->panel->aod_status, oneplus_onscreenfp_status, aod_layer_hide); + if (oneplus_dim_status == 1 && HBM_flag) { + rc = dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_HBM_ON_5); + if (rc) { + pr_err("failed to send DSI_CMD_SET_HBM_ON_5 cmds, rc=%d\n", rc); + return rc; + } + pr_err("Notify dim not commit,send DSI_CMD_SET_HBM_ON_5 cmds\n"); + return count; + } + drm_modeset_lock_all(drm_dev); + + state = drm_atomic_state_alloc(drm_dev); + state->acquire_ctx = mode_config->acquire_ctx; + crtc = dsi_connector->state->crtc; + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if((oneplus_dim_status !=0) && (oneplus_dim_status != 5)){ + err = drm_atomic_commit(state); + if (err < 0) + drm_atomic_state_clear(state); + } + drm_modeset_unlock_all(drm_dev); + SDE_ATRACE_END("notify_dim_store"); + return count; +} +/***************************************************************************/ +static int sde_crtc_config_fingerprint_dim_layer(struct drm_crtc_state *crtc_state, int stage) +{ + struct sde_crtc_state *cstate; + struct drm_display_mode *mode = &crtc_state->adjusted_mode; + struct sde_hw_dim_layer *fingerprint_dim_layer; + int alpha = oneplus_get_panel_brightness_to_alpha(); + struct sde_kms *kms; + struct dsi_display *display = get_main_display(); + + if(display == NULL || display->panel == NULL){ + SDE_ERROR("display panel is null\n"); + return 0; + } + + //do not set alpha to avoid screen black when unlock in aod status + if (display->panel->aod_status==1 && (display->panel->aod_mode==5 || + display->panel->aod_mode==1 || display->panel->aod_mode==3)){ + if(oneplus_dim_status == 2){ + alpha = 255; + } + } else if (display->panel->aod_status==1 && display->panel->aod_mode==4){ + if(oneplus_dim_status == 2){ + alpha = 0; + } + } + + kms = _sde_crtc_get_kms(crtc_state->crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + SDE_ATRACE_BEGIN("set_dim_layer"); + + cstate = to_sde_crtc_state(crtc_state); + + if (cstate->num_dim_layers == SDE_MAX_DIM_LAYERS - 1) { + pr_err("failed to get available dim layer for custom\n"); + return -EINVAL; + } + + if (!alpha) { + cstate->fingerprint_dim_layer = NULL; + return 0; + } + + if ((stage + SDE_STAGE_0) >= kms->catalog->mixer[0].sblk->maxblendstages) { + return -EINVAL; + } + + fingerprint_dim_layer = &cstate->dim_layer[cstate->num_dim_layers]; + fingerprint_dim_layer->flags = SDE_DRM_DIM_LAYER_INCLUSIVE; + fingerprint_dim_layer->stage = stage + SDE_STAGE_0; + + fingerprint_dim_layer->rect.x = 0; + fingerprint_dim_layer->rect.y = 0; + fingerprint_dim_layer->rect.w = mode->hdisplay; + fingerprint_dim_layer->rect.h = mode->vdisplay; + fingerprint_dim_layer->color_fill = (struct sde_mdss_color) {0, 0, 0, alpha}; + cstate->fingerprint_dim_layer = fingerprint_dim_layer; + SDE_ATRACE_END("set_dim_layer"); + return 0; +} + +/** + * _sde_crtc_set_dest_scaler - copy dest scaler settings from userspace + * @sde_crtc : Pointer to sde crtc + * @cstate : Pointer to sde crtc state + * @usr_ptr: User ptr for sde_drm_dest_scaler_data struct + */ +static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc, + struct sde_crtc_state *cstate, + void __user *usr_ptr) +{ + struct sde_drm_dest_scaler_data ds_data; + struct sde_drm_dest_scaler_cfg *ds_cfg_usr; + struct sde_drm_scaler_v2 scaler_v2; + void __user *scaler_v2_usr; + int i, count; + + if (!sde_crtc || !cstate) { + SDE_ERROR("invalid sde_crtc/state\n"); + return -EINVAL; + } + + SDE_DEBUG("crtc %s\n", sde_crtc->name); + + if (!usr_ptr) { + SDE_DEBUG("ds data removed\n"); + return 0; + } + + if (copy_from_user(&ds_data, usr_ptr, sizeof(ds_data))) { + SDE_ERROR("%s:failed to copy dest scaler data from user\n", + sde_crtc->name); + return -EINVAL; + } + + count = ds_data.num_dest_scaler; + if (!count) { + SDE_DEBUG("no ds data available\n"); + return 0; + } + + if (count > SDE_MAX_DS_COUNT) { + SDE_ERROR("%s: invalid config: num_ds(%d) max(%d)\n", + sde_crtc->name, count, SDE_MAX_DS_COUNT); + SDE_EVT32(DRMID(&sde_crtc->base), count, SDE_EVTLOG_ERROR); + return -EINVAL; + } + + /* Populate from user space */ + for (i = 0; i < count; i++) { + ds_cfg_usr = &ds_data.ds_cfg[i]; + + cstate->ds_cfg[i].idx = ds_cfg_usr->index; + cstate->ds_cfg[i].flags = ds_cfg_usr->flags; + cstate->ds_cfg[i].lm_width = ds_cfg_usr->lm_width; + cstate->ds_cfg[i].lm_height = ds_cfg_usr->lm_height; + memset(&scaler_v2, 0, sizeof(scaler_v2)); + + if (ds_cfg_usr->scaler_cfg) { + scaler_v2_usr = + (void __user *)((uintptr_t)ds_cfg_usr->scaler_cfg); + + if (copy_from_user(&scaler_v2, scaler_v2_usr, + sizeof(scaler_v2))) { + SDE_ERROR("%s:scaler: copy from user failed\n", + sde_crtc->name); + return -EINVAL; + } + } + + sde_set_scaler_v2(&cstate->ds_cfg[i].scl3_cfg, &scaler_v2); + + SDE_DEBUG("en(%d)dir(%d)de(%d) src(%dx%d) dst(%dx%d)\n", + scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, + scaler_v2.src_width[0], scaler_v2.src_height[0], + scaler_v2.dst_width, scaler_v2.dst_height); + SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), + scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable, + scaler_v2.src_width[0], scaler_v2.src_height[0], + scaler_v2.dst_width, scaler_v2.dst_height); + + SDE_DEBUG("ds cfg[%d]-ndx(%d) flags(%d) lm(%dx%d)\n", + i, ds_cfg_usr->index, ds_cfg_usr->flags, + ds_cfg_usr->lm_width, ds_cfg_usr->lm_height); + SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), i, ds_cfg_usr->index, + ds_cfg_usr->flags, ds_cfg_usr->lm_width, + ds_cfg_usr->lm_height); + } + + cstate->num_ds = count; + cstate->ds_dirty = true; + SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), count, cstate->ds_dirty); + + return 0; +} + +static int _sde_crtc_check_dest_scaler_lm(struct drm_crtc *crtc, + struct drm_display_mode *mode, struct sde_hw_ds_cfg *cfg, u32 hdisplay, + u32 prev_lm_width, u32 prev_lm_height) +{ + if (cfg->lm_width > hdisplay || cfg->lm_height > mode->vdisplay + || !cfg->lm_width || !cfg->lm_height) { + SDE_ERROR("crtc%d: lm size[%d,%d] display [%d,%d]\n", + crtc->base.id, cfg->lm_width, cfg->lm_height, + hdisplay, mode->vdisplay); + SDE_EVT32(DRMID(crtc), cfg->lm_width, cfg->lm_height, + hdisplay, mode->vdisplay, SDE_EVTLOG_ERROR); + return -E2BIG; + } + + if (!prev_lm_width && !prev_lm_height) { + prev_lm_width = cfg->lm_width; + prev_lm_height = cfg->lm_height; + } else { + if (cfg->lm_width != prev_lm_width || + cfg->lm_height != prev_lm_height) { + SDE_ERROR("crtc%d:lm left[%d,%d]right[%d %d]\n", + crtc->base.id, cfg->lm_width, + cfg->lm_height, prev_lm_width, + prev_lm_height); + SDE_EVT32(DRMID(crtc), cfg->lm_width, + cfg->lm_height, prev_lm_width, + prev_lm_height, SDE_EVTLOG_ERROR); + return -EINVAL; + } + } + return 0; +} + +static int _sde_crtc_check_dest_scaler_cfg(struct drm_crtc *crtc, + struct sde_crtc *sde_crtc, struct drm_display_mode *mode, + struct sde_hw_ds *hw_ds, struct sde_hw_ds_cfg *cfg, u32 hdisplay, + u32 max_in_width, u32 max_out_width) +{ + if (cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE || + cfg->flags & SDE_DRM_DESTSCALER_ENHANCER_UPDATE) { + + /** + * Scaler src and dst width shouldn't exceed the maximum + * width limitation. Also, if there is no partial update + * dst width and height must match display resolution. + */ + if (cfg->scl3_cfg.src_width[0] > max_in_width || + cfg->scl3_cfg.dst_width > max_out_width || + !cfg->scl3_cfg.src_width[0] || + !cfg->scl3_cfg.dst_width || + (!(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE) + && (cfg->scl3_cfg.dst_width != hdisplay || + cfg->scl3_cfg.dst_height != mode->vdisplay))) { + SDE_ERROR("crtc%d: ", crtc->base.id); + SDE_ERROR("src_w(%d) dst(%dx%d) display(%dx%d)", + cfg->scl3_cfg.src_width[0], + cfg->scl3_cfg.dst_width, + cfg->scl3_cfg.dst_height, + hdisplay, mode->vdisplay); + SDE_ERROR("num_mixers(%d) flags(%d) ds-%d:\n", + sde_crtc->num_mixers, cfg->flags, + hw_ds->idx - DS_0); + SDE_ERROR("scale_en = %d, DE_en =%d\n", + cfg->scl3_cfg.enable, + cfg->scl3_cfg.de.enable); + + SDE_EVT32(DRMID(crtc), cfg->scl3_cfg.enable, + cfg->scl3_cfg.de.enable, cfg->flags, + max_in_width, max_out_width, + cfg->scl3_cfg.src_width[0], + cfg->scl3_cfg.dst_width, + cfg->scl3_cfg.dst_height, hdisplay, + mode->vdisplay, sde_crtc->num_mixers, + SDE_EVTLOG_ERROR); + + cfg->flags &= + ~SDE_DRM_DESTSCALER_SCALE_UPDATE; + cfg->flags &= + ~SDE_DRM_DESTSCALER_ENHANCER_UPDATE; + + return -EINVAL; + } + } + return 0; +} + +static int _sde_crtc_check_dest_scaler_validate_ds(struct drm_crtc *crtc, + struct sde_crtc *sde_crtc, struct sde_crtc_state *cstate, + struct drm_display_mode *mode, struct sde_hw_ds *hw_ds, + struct sde_hw_ds_cfg *cfg, u32 hdisplay, u32 *num_ds_enable, + u32 prev_lm_width, u32 prev_lm_height, u32 max_in_width, + u32 max_out_width) +{ + int i, ret; + u32 lm_idx; + + for (i = 0; i < cstate->num_ds; i++) { + cfg = &cstate->ds_cfg[i]; + lm_idx = cfg->idx; + + /** + * Validate against topology + * No of dest scalers should match the num of mixers + * unless it is partial update left only/right only use case + */ + if (lm_idx >= sde_crtc->num_mixers || (i != lm_idx && + !(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { + SDE_ERROR("crtc%d: ds_cfg id(%d):idx(%d), flags(%d)\n", + crtc->base.id, i, lm_idx, cfg->flags); + SDE_EVT32(DRMID(crtc), i, lm_idx, cfg->flags, + SDE_EVTLOG_ERROR); + return -EINVAL; + } + + hw_ds = sde_crtc->mixers[lm_idx].hw_ds; + + if (!max_in_width && !max_out_width) { + max_in_width = hw_ds->scl->top->maxinputwidth; + max_out_width = hw_ds->scl->top->maxoutputwidth; + + if (cstate->num_ds == CRTC_DUAL_MIXERS) + max_in_width -= SDE_DS_OVERFETCH_SIZE; + + SDE_DEBUG("max DS width [%d,%d] for num_ds = %d\n", + max_in_width, max_out_width, cstate->num_ds); + } + + /* Check LM width and height */ + ret = _sde_crtc_check_dest_scaler_lm(crtc, mode, cfg, hdisplay, + prev_lm_width, prev_lm_height); + if (ret) + return ret; + + /* Check scaler data */ + ret = _sde_crtc_check_dest_scaler_cfg(crtc, sde_crtc, mode, + hw_ds, cfg, hdisplay, + max_in_width, max_out_width); + if (ret) + return ret; + + if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE) + (*num_ds_enable)++; + + SDE_DEBUG("ds[%d]: flags[0x%X]\n", + hw_ds->idx - DS_0, cfg->flags); + SDE_EVT32_VERBOSE(DRMID(crtc), hw_ds->idx - DS_0, cfg->flags); + } + + return 0; +} + +static void _sde_crtc_check_dest_scaler_data_disable(struct drm_crtc *crtc, + struct sde_crtc_state *cstate, struct sde_hw_ds_cfg *cfg, + u32 num_ds_enable) +{ + int i; + + SDE_DEBUG("dest scaler status : %d -> %d\n", + cstate->num_ds_enabled, num_ds_enable); + SDE_EVT32_VERBOSE(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable, + cstate->num_ds, cstate->ds_dirty); + + if (cstate->num_ds_enabled != num_ds_enable) { + /* Disabling destination scaler */ + if (!num_ds_enable) { + for (i = 0; i < cstate->num_ds; i++) { + cfg = &cstate->ds_cfg[i]; + cfg->idx = i; + /* Update scaler settings in disable case */ + cfg->flags = SDE_DRM_DESTSCALER_SCALE_UPDATE; + cfg->scl3_cfg.enable = 0; + cfg->scl3_cfg.de.enable = 0; + } + } + cstate->num_ds_enabled = num_ds_enable; + cstate->ds_dirty = true; + } else { + if (!cstate->num_ds_enabled) + cstate->ds_dirty = false; + } +} + +/** + * _sde_crtc_check_dest_scaler_data - validate the dest scaler data + * @crtc : Pointer to drm crtc + * @state : Pointer to drm crtc state + */ +static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_display_mode *mode; + struct sde_kms *kms; + struct sde_hw_ds *hw_ds; + struct sde_hw_ds_cfg *cfg; + u32 ret = 0; + u32 num_ds_enable = 0, hdisplay = 0; + u32 max_in_width = 0, max_out_width = 0; + u32 prev_lm_width = 0, prev_lm_height = 0; + + if (!crtc || !state) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + kms = _sde_crtc_get_kms(crtc); + mode = &state->adjusted_mode; + + SDE_DEBUG("crtc%d\n", crtc->base.id); + + if (!cstate->ds_dirty) { + SDE_DEBUG("dest scaler property not set, skip validation\n"); + return 0; + } + + if (!kms || !kms->catalog) { + SDE_ERROR("crtc%d: invalid parameters\n", crtc->base.id); + return -EINVAL; + } + + if (!kms->catalog->mdp[0].has_dest_scaler) { + SDE_DEBUG("dest scaler feature not supported\n"); + return 0; + } + + if (!sde_crtc->num_mixers) { + SDE_DEBUG("mixers not allocated\n"); + return 0; + } + + ret = _sde_validate_hw_resources(sde_crtc); + if (ret) + goto err; + + /** + * No of dest scalers shouldn't exceed hw ds block count and + * also, match the num of mixers unless it is partial update + * left only/right only use case - currently PU + DS is not supported + */ + if (cstate->num_ds > kms->catalog->ds_count || + ((cstate->num_ds != sde_crtc->num_mixers) && + !(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) { + SDE_ERROR("crtc%d: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n", + crtc->base.id, cstate->num_ds, kms->catalog->ds_count, + cstate->ds_cfg[0].flags); + ret = -EINVAL; + goto err; + } + + /** + * Check if DS needs to be enabled or disabled + * In case of enable, validate the data + */ + if (!(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) { + SDE_DEBUG("disable dest scaler, num(%d) flags(%d)\n", + cstate->num_ds, cstate->ds_cfg[0].flags); + goto disable; + } + + /* Display resolution */ + hdisplay = mode->hdisplay/sde_crtc->num_mixers; + + /* Validate the DS data */ + ret = _sde_crtc_check_dest_scaler_validate_ds(crtc, sde_crtc, cstate, + mode, hw_ds, cfg, hdisplay, &num_ds_enable, + prev_lm_width, prev_lm_height, + max_in_width, max_out_width); + if (ret) + goto err; + +disable: + _sde_crtc_check_dest_scaler_data_disable(crtc, cstate, cfg, + num_ds_enable); + return 0; + +err: + cstate->ds_dirty = false; + return ret; +} + +/** + * _sde_crtc_wait_for_fences - wait for incoming framebuffer sync fences + * @crtc: Pointer to CRTC object + */ +static void _sde_crtc_wait_for_fences(struct drm_crtc *crtc) +{ + struct drm_plane *plane = NULL; + uint32_t wait_ms = 1; + ktime_t kt_end, kt_wait; + int rc = 0; + + SDE_DEBUG("\n"); + + if (!crtc || !crtc->state) { + SDE_ERROR("invalid crtc/state %pK\n", crtc); + return; + } + + /* use monotonic timer to limit total fence wait time */ + kt_end = ktime_add_ns(ktime_get(), + to_sde_crtc_state(crtc->state)->input_fence_timeout_ns); + + /* + * Wait for fences sequentially, as all of them need to be signalled + * before we can proceed. + * + * Limit total wait time to INPUT_FENCE_TIMEOUT, but still call + * sde_plane_wait_input_fence with wait_ms == 0 after the timeout so + * that each plane can check its fence status and react appropriately + * if its fence has timed out. Call input fence wait multiple times if + * fence wait is interrupted due to interrupt call. + */ + SDE_ATRACE_BEGIN("plane_wait_input_fence"); + drm_atomic_crtc_for_each_plane(plane, crtc) { + do { + kt_wait = ktime_sub(kt_end, ktime_get()); + if (ktime_compare(kt_wait, ktime_set(0, 0)) >= 0) + wait_ms = ktime_to_ms(kt_wait); + else + wait_ms = 0; + + rc = sde_plane_wait_input_fence(plane, wait_ms); + } while (wait_ms && rc == -ERESTARTSYS); + } + SDE_ATRACE_END("plane_wait_input_fence"); +} + +static void _sde_crtc_setup_mixer_for_encoder( + struct drm_crtc *crtc, + struct drm_encoder *enc) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_kms *sde_kms = _sde_crtc_get_kms(crtc); + struct sde_rm *rm = &sde_kms->rm; + struct sde_crtc_mixer *mixer; + struct sde_hw_ctl *last_valid_ctl = NULL; + int i; + struct sde_rm_hw_iter lm_iter, ctl_iter, dspp_iter, ds_iter; + + sde_rm_init_hw_iter(&lm_iter, enc->base.id, SDE_HW_BLK_LM); + sde_rm_init_hw_iter(&ctl_iter, enc->base.id, SDE_HW_BLK_CTL); + sde_rm_init_hw_iter(&dspp_iter, enc->base.id, SDE_HW_BLK_DSPP); + sde_rm_init_hw_iter(&ds_iter, enc->base.id, SDE_HW_BLK_DS); + + /* Set up all the mixers and ctls reserved by this encoder */ + for (i = sde_crtc->num_mixers; i < ARRAY_SIZE(sde_crtc->mixers); i++) { + mixer = &sde_crtc->mixers[i]; + + if (!sde_rm_get_hw(rm, &lm_iter)) + break; + mixer->hw_lm = (struct sde_hw_mixer *)lm_iter.hw; + + /* CTL may be <= LMs, if <, multiple LMs controlled by 1 CTL */ + if (!sde_rm_get_hw(rm, &ctl_iter)) { + SDE_DEBUG("no ctl assigned to lm %d, using previous\n", + mixer->hw_lm->idx - LM_0); + mixer->hw_ctl = last_valid_ctl; + } else { + mixer->hw_ctl = (struct sde_hw_ctl *)ctl_iter.hw; + last_valid_ctl = mixer->hw_ctl; + sde_crtc->num_ctls++; + } + + /* Shouldn't happen, mixers are always >= ctls */ + if (!mixer->hw_ctl) { + SDE_ERROR("no valid ctls found for lm %d\n", + mixer->hw_lm->idx - LM_0); + return; + } + + /* Dspp may be null */ + (void) sde_rm_get_hw(rm, &dspp_iter); + mixer->hw_dspp = (struct sde_hw_dspp *)dspp_iter.hw; + + /* DS may be null */ + (void) sde_rm_get_hw(rm, &ds_iter); + mixer->hw_ds = (struct sde_hw_ds *)ds_iter.hw; + + mixer->encoder = enc; + + sde_crtc->num_mixers++; + SDE_DEBUG("setup mixer %d: lm %d\n", + i, mixer->hw_lm->idx - LM_0); + SDE_DEBUG("setup mixer %d: ctl %d\n", + i, mixer->hw_ctl->idx - CTL_0); + if (mixer->hw_ds) + SDE_DEBUG("setup mixer %d: ds %d\n", + i, mixer->hw_ds->idx - DS_0); + } +} + +static void _sde_crtc_setup_mixers(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct drm_encoder *enc; + + sde_crtc->num_ctls = 0; + sde_crtc->num_mixers = 0; + sde_crtc->mixers_swapped = false; + memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers)); + + mutex_lock(&sde_crtc->crtc_lock); + /* Check for mixers on all encoders attached to this crtc */ + list_for_each_entry(enc, &crtc->dev->mode_config.encoder_list, head) { + if (enc->crtc != crtc) + continue; + + /* avoid overwriting mixers info from a copy encoder */ + if (sde_encoder_in_clone_mode(enc)) + continue; + + _sde_crtc_setup_mixer_for_encoder(crtc, enc); + } + + mutex_unlock(&sde_crtc->crtc_lock); + _sde_crtc_check_dest_scaler_data(crtc, crtc->state); +} + +static void _sde_crtc_setup_is_ppsplit(struct drm_crtc_state *state) +{ + int i; + struct sde_crtc_state *cstate; + + cstate = to_sde_crtc_state(state); + + cstate->is_ppsplit = false; + for (i = 0; i < cstate->num_connectors; i++) { + struct drm_connector *conn = cstate->connectors[i]; + + if (sde_connector_get_topology_name(conn) == + SDE_RM_TOPOLOGY_PPSPLIT) + cstate->is_ppsplit = true; + } +} + +static void _sde_crtc_setup_lm_bounds(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_display_mode *adj_mode; + u32 crtc_split_width; + int i; + + if (!crtc || !state) { + SDE_ERROR("invalid args\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + adj_mode = &state->adjusted_mode; + crtc_split_width = sde_crtc_get_mixer_width(sde_crtc, cstate, adj_mode); + + for (i = 0; i < sde_crtc->num_mixers; i++) { + cstate->lm_bounds[i].x = crtc_split_width * i; + cstate->lm_bounds[i].y = 0; + cstate->lm_bounds[i].w = crtc_split_width; + cstate->lm_bounds[i].h = + sde_crtc_get_mixer_height(sde_crtc, cstate, adj_mode); + memcpy(&cstate->lm_roi[i], &cstate->lm_bounds[i], + sizeof(cstate->lm_roi[i])); + SDE_EVT32_VERBOSE(DRMID(crtc), i, + cstate->lm_bounds[i].x, cstate->lm_bounds[i].y, + cstate->lm_bounds[i].w, cstate->lm_bounds[i].h); + SDE_DEBUG("%s: lm%d bnd&roi (%d,%d,%d,%d)\n", sde_crtc->name, i, + cstate->lm_roi[i].x, cstate->lm_roi[i].y, + cstate->lm_roi[i].w, cstate->lm_roi[i].h); + } + + drm_mode_debug_printmodeline(adj_mode); +} + +static void sde_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct sde_crtc *sde_crtc; + struct drm_encoder *encoder; + struct drm_device *dev; + struct sde_kms *sde_kms; + struct sde_splash_display *splash_display; + bool cont_splash_enabled = false; + size_t i; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + if (!crtc->state->enable) { + SDE_DEBUG("crtc%d -> enable %d, skip atomic_begin\n", + crtc->base.id, crtc->state->enable); + return; + } + + if (!sde_kms_power_resource_is_enabled(crtc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) + return; + + SDE_ATRACE_BEGIN("crtc_atomic_begin"); + SDE_DEBUG("crtc%d\n", crtc->base.id); + + sde_crtc = to_sde_crtc(crtc); + dev = crtc->dev; + + if (!sde_crtc->num_mixers) { + _sde_crtc_setup_mixers(crtc); + _sde_crtc_setup_is_ppsplit(crtc->state); + _sde_crtc_setup_lm_bounds(crtc, crtc->state); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + /* encoder will trigger pending mask now */ + sde_encoder_trigger_kickoff_pending(encoder); + } + + /* update performance setting */ + sde_core_perf_crtc_update(crtc, 1, false); + + /* + * If no mixers have been allocated in sde_crtc_atomic_check(), + * it means we are trying to flush a CRTC whose state is disabled: + * nothing else needs to be done. + */ + if (unlikely(!sde_crtc->num_mixers)) + goto end; + + _sde_crtc_blend_setup(crtc, old_state, true); + _sde_crtc_dest_scaler_setup(crtc); + + /* cancel the idle notify delayed work */ + if (sde_encoder_check_curr_mode(sde_crtc->mixers[0].encoder, + MSM_DISPLAY_VIDEO_MODE) && + kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work)) + SDE_DEBUG("idle notify work cancelled\n"); + + /* + * Since CP properties use AXI buffer to program the + * HW, check if context bank is in attached state, + * apply color processing properties only if + * smmu state is attached, + */ + for (i = 0; i < MAX_DSI_DISPLAYS; i++) { + splash_display = &sde_kms->splash_data.splash_display[i]; + if (splash_display->cont_splash_enabled && + splash_display->encoder && + crtc == splash_display->encoder->crtc) + cont_splash_enabled = true; + } + + if (sde_kms_is_cp_operation_allowed(sde_kms) && + (cont_splash_enabled || sde_crtc->enabled)) + sde_cp_crtc_apply_properties(crtc); + + /* + * PP_DONE irq is only used by command mode for now. + * It is better to request pending before FLUSH and START trigger + * to make sure no pp_done irq missed. + * This is safe because no pp_done will happen before SW trigger + * in command mode. + */ + +end: + SDE_ATRACE_END("crtc_atomic_begin"); +} + +static void sde_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct drm_encoder *encoder; + struct sde_crtc *sde_crtc; + struct drm_device *dev; + struct drm_plane *plane; + struct msm_drm_private *priv; + struct msm_drm_thread *event_thread; + struct sde_crtc_state *cstate; + struct sde_kms *sde_kms; + int idle_time = 0; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return; + } + + if (!crtc->state->enable) { + SDE_DEBUG("crtc%d -> enable %d, skip atomic_flush\n", + crtc->base.id, crtc->state->enable); + return; + } + + if (!sde_kms_power_resource_is_enabled(crtc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) { + SDE_ERROR("invalid kms\n"); + return; + } + + SDE_DEBUG("crtc%d\n", crtc->base.id); + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + dev = crtc->dev; + priv = dev->dev_private; + + if (crtc->index >= ARRAY_SIZE(priv->event_thread)) { + SDE_ERROR("invalid crtc index[%d]\n", crtc->index); + return; + } + + event_thread = &priv->event_thread[crtc->index]; + idle_time = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_TIMEOUT); + + /* + * If no mixers has been allocated in sde_crtc_atomic_check(), + * it means we are trying to flush a CRTC whose state is disabled: + * nothing else needs to be done. + */ + if (unlikely(!sde_crtc->num_mixers)) + return; + + SDE_ATRACE_BEGIN("sde_crtc_atomic_flush"); + + /* + * For planes without commit update, drm framework will not add + * those planes to current state since hardware update is not + * required. However, if those planes were power collapsed since + * last commit cycle, driver has to restore the hardware state + * of those planes explicitly here prior to plane flush. + * Also use this iteration to see if any plane requires cache, + * so during the perf update driver can activate/deactivate + * the cache accordingly. + */ + sde_crtc->new_perf.llcc_active = false; + drm_atomic_crtc_for_each_plane(plane, crtc) { + sde_plane_restore(plane); + + if (sde_plane_is_cache_required(plane)) + sde_crtc->new_perf.llcc_active = true; + } + + /* wait for acquire fences before anything else is done */ + _sde_crtc_wait_for_fences(crtc); + + /* schedule the idle notify delayed work */ + if (idle_time && sde_encoder_check_curr_mode( + sde_crtc->mixers[0].encoder, + MSM_DISPLAY_VIDEO_MODE)) { + kthread_queue_delayed_work(&event_thread->worker, + &sde_crtc->idle_notify_work, + msecs_to_jiffies(idle_time)); + SDE_DEBUG("schedule idle notify work in %dms\n", idle_time); + } + + if (!cstate->rsc_update) { + drm_for_each_encoder_mask(encoder, dev, + crtc->state->encoder_mask) { + cstate->rsc_client = + sde_encoder_get_rsc_client(encoder); + } + cstate->rsc_update = true; + } + + /* + * Final plane updates: Give each plane a chance to complete all + * required writes/flushing before crtc's "flush + * everything" call below. + */ + drm_atomic_crtc_for_each_plane(plane, crtc) { + if (sde_kms->smmu_state.transition_error) + sde_plane_set_error(plane, true); + sde_plane_flush(plane); + } + + /* Kickoff will be scheduled by outer layer */ + SDE_ATRACE_END("sde_crtc_atomic_flush"); +} + +/** + * sde_crtc_destroy_state - state destroy hook + * @crtc: drm CRTC + * @state: CRTC state object to release + */ +static void sde_crtc_destroy_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_encoder *enc; + struct sde_kms *sde_kms; + + if (!crtc || !state) { + SDE_ERROR("invalid argument(s)\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + sde_kms = _sde_crtc_get_kms(crtc); + + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return; + } + + SDE_DEBUG("crtc%d\n", crtc->base.id); + + drm_for_each_encoder_mask(enc, crtc->dev, state->encoder_mask) + sde_rm_release(&sde_kms->rm, enc, true); + + __drm_atomic_helper_crtc_destroy_state(state); + + /* destroy value helper */ + msm_property_destroy_state(&sde_crtc->property_info, cstate, + &cstate->property_state); +} + +static int _sde_crtc_flush_event_thread(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + int i; + + if (!crtc) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + sde_crtc = to_sde_crtc(crtc); + + if (!atomic_read(&sde_crtc->frame_pending)) { + SDE_DEBUG("no frames pending\n"); + return 0; + } + + SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_ENTRY); + + /* + * flush all the event thread work to make sure all the + * FRAME_EVENTS from encoder are propagated to crtc + */ + for (i = 0; i < ARRAY_SIZE(sde_crtc->frame_events); i++) { + if (list_empty(&sde_crtc->frame_events[i].list)) + kthread_flush_work(&sde_crtc->frame_events[i].work); + } + + SDE_EVT32_VERBOSE(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT); + + return 0; +} + +/** + * _sde_crtc_remove_pipe_flush - remove staged pipes from flush mask + * @crtc: Pointer to crtc structure + */ +static void _sde_crtc_remove_pipe_flush(struct drm_crtc *crtc) +{ + struct drm_plane *plane; + struct drm_plane_state *state; + struct sde_crtc *sde_crtc; + struct sde_crtc_mixer *mixer; + struct sde_hw_ctl *ctl; + + if (!crtc) + return; + + sde_crtc = to_sde_crtc(crtc); + mixer = sde_crtc->mixers; + if (!mixer) + return; + ctl = mixer->hw_ctl; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + state = plane->state; + if (!state) + continue; + + /* clear plane flush bitmask */ + sde_plane_ctl_flush(plane, ctl, false); + } +} + +/** + * sde_crtc_reset_hw - attempt hardware reset on errors + * @crtc: Pointer to DRM crtc instance + * @old_state: Pointer to crtc state for previous commit + * @recovery_events: Whether or not recovery events are enabled + * Returns: Zero if current commit should still be attempted + */ +int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, + bool recovery_events) +{ + struct drm_plane *plane_halt[MAX_PLANES]; + struct drm_plane *plane; + struct drm_encoder *encoder; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct sde_hw_ctl *ctl; + signed int i, plane_count; + int rc; + + if (!crtc || !crtc->dev || !old_state || !crtc->state) + return -EINVAL; + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + + SDE_EVT32(DRMID(crtc), recovery_events, SDE_EVTLOG_FUNC_ENTRY); + + /* optionally generate a panic instead of performing a h/w reset */ + SDE_DBG_CTRL("stop_ftrace", "reset_hw_panic"); + + for (i = 0; i < sde_crtc->num_ctls; ++i) { + ctl = sde_crtc->mixers[i].hw_ctl; + if (!ctl || !ctl->ops.reset) + continue; + + rc = ctl->ops.reset(ctl); + if (rc) { + SDE_DEBUG("crtc%d: ctl%d reset failure\n", + crtc->base.id, ctl->idx - CTL_0); + SDE_EVT32(DRMID(crtc), ctl->idx - CTL_0, + SDE_EVTLOG_ERROR); + break; + } + } + + /* Early out if simple ctl reset succeeded */ + if (i == sde_crtc->num_ctls) + return 0; + + SDE_DEBUG("crtc%d: issuing hard reset\n", DRMID(crtc)); + + /* force all components in the system into reset at the same time */ + for (i = 0; i < sde_crtc->num_ctls; ++i) { + ctl = sde_crtc->mixers[i].hw_ctl; + if (!ctl || !ctl->ops.hard_reset) + continue; + + SDE_EVT32(DRMID(crtc), ctl->idx - CTL_0); + ctl->ops.hard_reset(ctl, true); + } + + plane_count = 0; + drm_atomic_crtc_state_for_each_plane(plane, old_state) { + if (plane_count >= ARRAY_SIZE(plane_halt)) + break; + + plane_halt[plane_count++] = plane; + sde_plane_halt_requests(plane, true); + sde_plane_set_revalidate(plane, true); + } + + /* provide safe "border color only" commit configuration for later */ + _sde_crtc_remove_pipe_flush(crtc); + _sde_crtc_blend_setup(crtc, old_state, false); + + /* take h/w components out of reset */ + for (i = plane_count - 1; i >= 0; --i) + sde_plane_halt_requests(plane_halt[i], false); + + /* attempt to poll for start of frame cycle before reset release */ + list_for_each_entry(encoder, + &crtc->dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) + sde_encoder_poll_line_counts(encoder); + } + + for (i = 0; i < sde_crtc->num_ctls; ++i) { + ctl = sde_crtc->mixers[i].hw_ctl; + if (!ctl || !ctl->ops.hard_reset) + continue; + + ctl->ops.hard_reset(ctl, false); + } + + list_for_each_entry(encoder, + &crtc->dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO) + sde_encoder_kickoff(encoder, false); + } + + /* panic the device if VBIF is not in good state */ + return !recovery_events ? 0 : -EAGAIN; +} + +void sde_crtc_commit_kickoff(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + struct drm_encoder *encoder; + struct drm_device *dev; + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct sde_crtc_state *cstate; + bool is_error = false; + unsigned long flags; + enum sde_crtc_idle_pc_state idle_pc_state; + struct sde_encoder_kickoff_params params = { 0 }; + + if (!crtc) { + SDE_ERROR("invalid argument\n"); + return; + } + dev = crtc->dev; + sde_crtc = to_sde_crtc(crtc); + sde_kms = _sde_crtc_get_kms(crtc); + + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { + SDE_ERROR("invalid argument\n"); + return; + } + + priv = sde_kms->dev->dev_private; + cstate = to_sde_crtc_state(crtc->state); + + /* + * If no mixers has been allocated in sde_crtc_atomic_check(), + * it means we are trying to start a CRTC whose state is disabled: + * nothing else needs to be done. + */ + if (unlikely(!sde_crtc->num_mixers)) + return; + + SDE_ATRACE_BEGIN("crtc_commit"); + + idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE); + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + /* + * Encoder will flush/start now, unless it has a tx pending. + * If so, it may delay and flush at an irq event (e.g. ppdone) + */ + params.affected_displays = _sde_crtc_get_displays_affected(crtc, + crtc->state); + if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) + sde_crtc->needs_hw_reset = true; + + if (idle_pc_state != IDLE_PC_NONE) + sde_encoder_control_idle_pc(encoder, + (idle_pc_state == IDLE_PC_ENABLE) ? true : false); + } + + /* + * Optionally attempt h/w recovery if any errors were detected while + * preparing for the kickoff + */ + if (sde_crtc->needs_hw_reset) { + sde_crtc->frame_trigger_mode = params.frame_trigger_mode; + if (sde_crtc->frame_trigger_mode + != FRAME_DONE_WAIT_POSTED_START && + sde_crtc_reset_hw(crtc, old_state, + params.recovery_events_enabled)) + is_error = true; + sde_crtc->needs_hw_reset = false; + } + + sde_crtc_calc_fps(sde_crtc); + SDE_ATRACE_BEGIN("flush_event_thread"); + _sde_crtc_flush_event_thread(crtc); + SDE_ATRACE_END("flush_event_thread"); + sde_crtc->plane_mask_old = crtc->state->plane_mask; + + if (atomic_inc_return(&sde_crtc->frame_pending) == 1) { + /* acquire bandwidth and other resources */ + SDE_DEBUG("crtc%d first commit\n", crtc->base.id); + SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE1); + } else { + SDE_DEBUG("crtc%d commit\n", crtc->base.id); + SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_CASE2); + } + sde_crtc->play_count++; + + sde_vbif_clear_errors(sde_kms); + + if (is_error) { + _sde_crtc_remove_pipe_flush(crtc); + _sde_crtc_blend_setup(crtc, old_state, false); + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + sde_encoder_kickoff(encoder, false); + } + + /* store the event after frame trigger */ + if (sde_crtc->event) { + WARN_ON(sde_crtc->event); + } else { + spin_lock_irqsave(&dev->event_lock, flags); + sde_crtc->event = crtc->state->event; + spin_unlock_irqrestore(&dev->event_lock, flags); + } + + SDE_ATRACE_END("crtc_commit"); +} + +/** + * _sde_crtc_vblank_enable_no_lock - update power resource and vblank request + * @sde_crtc: Pointer to sde crtc structure + * @enable: Whether to enable/disable vblanks + * + * @Return: error code + */ +static int _sde_crtc_vblank_enable_no_lock( + struct sde_crtc *sde_crtc, bool enable) +{ + struct drm_crtc *crtc; + struct drm_encoder *enc; + + if (!sde_crtc) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + + crtc = &sde_crtc->base; + + if (enable) { + int ret; + + /* drop lock since power crtc cb may try to re-acquire lock */ + mutex_unlock(&sde_crtc->crtc_lock); + ret = pm_runtime_get_sync(crtc->dev->dev); + mutex_lock(&sde_crtc->crtc_lock); + if (ret < 0) + return ret; + + drm_for_each_encoder_mask(enc, crtc->dev, + crtc->state->encoder_mask) { + SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable, + sde_crtc->enabled); + + sde_encoder_register_vblank_callback(enc, + sde_crtc_vblank_cb, (void *)crtc); + } + } else { + drm_for_each_encoder_mask(enc, crtc->dev, + crtc->state->encoder_mask) { + SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable, + sde_crtc->enabled); + + sde_encoder_register_vblank_callback(enc, NULL, NULL); + } + + /* drop lock since power crtc cb may try to re-acquire lock */ + mutex_unlock(&sde_crtc->crtc_lock); + pm_runtime_put_sync(crtc->dev->dev); + mutex_lock(&sde_crtc->crtc_lock); + } + + return 0; +} + +/** + * sde_crtc_duplicate_state - state duplicate hook + * @crtc: Pointer to drm crtc structure + * @Returns: Pointer to new drm_crtc_state structure + */ +static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate, *old_cstate; + + if (!crtc || !crtc->state) { + SDE_ERROR("invalid argument(s)\n"); + return NULL; + } + + sde_crtc = to_sde_crtc(crtc); + old_cstate = to_sde_crtc_state(crtc->state); + cstate = msm_property_alloc_state(&sde_crtc->property_info); + if (!cstate) { + SDE_ERROR("failed to allocate state\n"); + return NULL; + } + + /* duplicate value helper */ + msm_property_duplicate_state(&sde_crtc->property_info, + old_cstate, cstate, + &cstate->property_state, cstate->property_values); + + /* clear destination scaler dirty bit */ + cstate->ds_dirty = false; + + /* duplicate base helper */ + __drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base); + + return &cstate->base; +} + +/** + * sde_crtc_reset - reset hook for CRTCs + * Resets the atomic state for @crtc by freeing the state pointer (which might + * be NULL, e.g. at driver load time) and allocating a new empty state object. + * @crtc: Pointer to drm crtc structure + */ +static void sde_crtc_reset(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + /* revert suspend actions, if necessary */ + if (!sde_crtc_is_reset_required(crtc)) { + SDE_DEBUG("avoiding reset for crtc:%d\n", crtc->base.id); + return; + } + + /* remove previous state, if present */ + if (crtc->state) { + sde_crtc_destroy_state(crtc, crtc->state); + crtc->state = 0; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = msm_property_alloc_state(&sde_crtc->property_info); + if (!cstate) { + SDE_ERROR("failed to allocate state\n"); + return; + } + + /* reset value helper */ + msm_property_reset_state(&sde_crtc->property_info, cstate, + &cstate->property_state, + cstate->property_values); + + _sde_crtc_set_input_fence_timeout(cstate); + + cstate->base.crtc = crtc; + crtc->state = &cstate->base; +} + +static void sde_crtc_handle_power_event(u32 event_type, void *arg) +{ + struct drm_crtc *crtc = arg; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_plane *plane; + struct drm_encoder *encoder; + u32 power_on; + unsigned long flags; + struct sde_crtc_irq_info *node = NULL; + int ret = 0; + struct drm_event event; + struct msm_drm_private *priv; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + priv = crtc->dev->dev_private; + + mutex_lock(&sde_crtc->crtc_lock); + + SDE_EVT32(DRMID(crtc), event_type); + + switch (event_type) { + case SDE_POWER_EVENT_POST_ENABLE: + /* disable mdp LUT memory retention */ + ret = sde_power_clk_set_flags(&priv->phandle, "lut_clk", + CLKFLAG_NORETAIN_MEM); + if (ret) + SDE_ERROR("disable LUT memory retention err %d\n", ret); + + /* restore encoder; crtc will be programmed during commit */ + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + sde_encoder_virt_restore(encoder); + } + + /* restore UIDLE */ + sde_core_perf_crtc_update_uidle(crtc, true); + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + list_for_each_entry(node, &sde_crtc->user_event_list, list) { + ret = 0; + if (node->func) + ret = node->func(crtc, true, &node->irq); + if (ret) + SDE_ERROR("%s failed to enable event %x\n", + sde_crtc->name, node->event); + } + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + sde_cp_crtc_post_ipc(crtc); + break; + case SDE_POWER_EVENT_PRE_DISABLE: + /* enable mdp LUT memory retention */ + ret = sde_power_clk_set_flags(&priv->phandle, "lut_clk", + CLKFLAG_RETAIN_MEM); + if (ret) + SDE_ERROR("enable LUT memory retention err %d\n", ret); + + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + /* + * disable the vsync source after updating the + * rsc state. rsc state update might have vsync wait + * and vsync source must be disabled after it. + * It will avoid generating any vsync from this point + * till mode-2 entry. It is SW workaround for HW + * limitation and should not be removed without + * checking the updated design. + */ + sde_encoder_control_te(encoder, false); + } + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + node = NULL; + list_for_each_entry(node, &sde_crtc->user_event_list, list) { + ret = 0; + if (node->func) + ret = node->func(crtc, false, &node->irq); + if (ret) + SDE_ERROR("%s failed to disable event %x\n", + sde_crtc->name, node->event); + } + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + sde_cp_crtc_pre_ipc(crtc); + break; + case SDE_POWER_EVENT_POST_DISABLE: + /* + * set revalidate flag in planes, so it will be re-programmed + * in the next frame update + */ + drm_atomic_crtc_for_each_plane(plane, crtc) + sde_plane_set_revalidate(plane, true); + + sde_cp_crtc_suspend(crtc); + + /** + * destination scaler if enabled should be reconfigured + * in the next frame update + */ + if (cstate->num_ds_enabled) + sde_crtc->ds_reconfig = true; + + event.type = DRM_EVENT_SDE_POWER; + event.length = sizeof(power_on); + power_on = 0; + msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, + (u8 *)&power_on); + break; + default: + SDE_DEBUG("event:%d not handled\n", event_type); + break; + } + + mutex_unlock(&sde_crtc->crtc_lock); +} + +static void sde_crtc_disable(struct drm_crtc *crtc) +{ + struct sde_kms *sde_kms; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_encoder *encoder; + struct msm_drm_private *priv; + unsigned long flags; + struct sde_crtc_irq_info *node = NULL; + struct drm_event event; + u32 power_on; + bool in_cont_splash = false; + int ret, i; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private || !crtc->state) { + SDE_ERROR("invalid crtc\n"); + return; + } + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) { + SDE_ERROR("invalid kms\n"); + return; + } + + if (!sde_kms_power_resource_is_enabled(crtc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc->state); + priv = crtc->dev->dev_private; + + SDE_DEBUG("crtc%d\n", crtc->base.id); + + drm_crtc_vblank_off(crtc); + + mutex_lock(&sde_crtc->crtc_lock); + SDE_EVT32_VERBOSE(DRMID(crtc)); + + /* update color processing on suspend */ + event.type = DRM_EVENT_CRTC_POWER; + event.length = sizeof(u32); + sde_cp_crtc_suspend(crtc); + power_on = 0; + msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, + (u8 *)&power_on); + + /* destination scaler if enabled should be reconfigured on resume */ + if (cstate->num_ds_enabled) + sde_crtc->ds_reconfig = true; + + _sde_crtc_flush_event_thread(crtc); + + SDE_EVT32(DRMID(crtc), sde_crtc->enabled, + crtc->state->active, crtc->state->enable); + sde_crtc->enabled = false; + + /* Try to disable uidle */ + sde_core_perf_crtc_update_uidle(crtc, false); + + if (atomic_read(&sde_crtc->frame_pending)) { + SDE_ERROR("crtc%d frame_pending%d\n", crtc->base.id, + atomic_read(&sde_crtc->frame_pending)); + SDE_EVT32(DRMID(crtc), atomic_read(&sde_crtc->frame_pending), + SDE_EVTLOG_FUNC_CASE2); + sde_core_perf_crtc_release_bw(crtc); + atomic_set(&sde_crtc->frame_pending, 0); + } + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + list_for_each_entry(node, &sde_crtc->user_event_list, list) { + ret = 0; + if (node->func) + ret = node->func(crtc, false, &node->irq); + if (ret) + SDE_ERROR("%s failed to disable event %x\n", + sde_crtc->name, node->event); + } + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + if (sde_encoder_in_cont_splash(encoder)) { + in_cont_splash = true; + break; + } + } + + /* avoid clk/bw downvote if cont-splash is enabled */ + if (!in_cont_splash) + sde_core_perf_crtc_update(crtc, 0, true); + + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + sde_encoder_register_frame_event_callback(encoder, NULL, NULL); + cstate->rsc_client = NULL; + cstate->rsc_update = false; + + /* + * reset idle power-collapse to original state during suspend; + * user-mode will change the state on resume, if required + */ + if (sde_kms->catalog->has_idle_pc) + sde_encoder_control_idle_pc(encoder, true); + } + + if (sde_crtc->power_event) + sde_power_handle_unregister_event(&priv->phandle, + sde_crtc->power_event); + + /** + * All callbacks are unregistered and frame done waits are complete + * at this point. No buffers are accessed by hardware. + * reset the fence timeline if crtc will not be enabled for this commit + */ + if (!crtc->state->active || !crtc->state->enable) { + sde_fence_signal(sde_crtc->output_fence, + ktime_get(), SDE_FENCE_RESET_TIMELINE); + for (i = 0; i < cstate->num_connectors; ++i) + sde_connector_commit_reset(cstate->connectors[i], + ktime_get()); + } + + memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers)); + sde_crtc->num_mixers = 0; + sde_crtc->mixers_swapped = false; + + /* disable clk & bw control until clk & bw properties are set */ + cstate->bw_control = false; + cstate->bw_split_vote = false; + + mutex_unlock(&sde_crtc->crtc_lock); +} + +static void sde_crtc_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) +{ + struct sde_crtc *sde_crtc; + struct drm_encoder *encoder; + struct msm_drm_private *priv; + unsigned long flags; + struct sde_crtc_irq_info *node = NULL; + struct drm_event event; + u32 power_on; + int ret, i; + struct sde_crtc_state *cstate; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return; + } + priv = crtc->dev->dev_private; + cstate = to_sde_crtc_state(crtc->state); + + if (!sde_kms_power_resource_is_enabled(crtc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + SDE_DEBUG("crtc%d\n", crtc->base.id); + SDE_EVT32_VERBOSE(DRMID(crtc)); + sde_crtc = to_sde_crtc(crtc); + + /* + * Avoid drm_crtc_vblank_on during seamless DMS case + * when CRTC is already in enabled state + */ + if (!sde_crtc->enabled) + drm_crtc_vblank_on(crtc); + + mutex_lock(&sde_crtc->crtc_lock); + SDE_EVT32(DRMID(crtc), sde_crtc->enabled); + + /* + * Try to enable uidle (if possible), we do this before the call + * to return early during seamless dms mode, so any fps + * change is also consider to enable/disable UIDLE + */ + sde_core_perf_crtc_update_uidle(crtc, true); + + /* return early if crtc is already enabled, do this after UIDLE check */ + if (sde_crtc->enabled) { + if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode) || + msm_is_mode_seamless_dyn_clk(&crtc->state->adjusted_mode)) + + SDE_DEBUG("%s extra crtc enable expected during DMS\n", + sde_crtc->name); + else + WARN(1, "%s unexpected crtc enable\n", sde_crtc->name); + + mutex_unlock(&sde_crtc->crtc_lock); + return; + } + + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + sde_encoder_register_frame_event_callback(encoder, + sde_crtc_frame_event_cb, crtc); + } + + sde_crtc->enabled = true; + + /* update color processing on resume */ + event.type = DRM_EVENT_CRTC_POWER; + event.length = sizeof(u32); + sde_cp_crtc_resume(crtc); + power_on = 1; + msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, + (u8 *)&power_on); + + mutex_unlock(&sde_crtc->crtc_lock); + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + list_for_each_entry(node, &sde_crtc->user_event_list, list) { + ret = 0; + if (node->func) + ret = node->func(crtc, true, &node->irq); + if (ret) + SDE_ERROR("%s failed to enable event %x\n", + sde_crtc->name, node->event); + } + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + sde_crtc->power_event = sde_power_handle_register_event( + &priv->phandle, + SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE | + SDE_POWER_EVENT_PRE_DISABLE, + sde_crtc_handle_power_event, crtc, sde_crtc->name); + + /* Enable ESD thread */ + for (i = 0; i < cstate->num_connectors; i++) + sde_connector_schedule_status_work(cstate->connectors[i], true); +} + +/* no input validation - caller API has all the checks */ +static int _sde_crtc_excl_dim_layer_check(struct drm_crtc_state *state, + struct plane_state pstates[], int cnt) +{ + struct sde_crtc_state *cstate = to_sde_crtc_state(state); + struct drm_display_mode *mode = &state->adjusted_mode; + const struct drm_plane_state *pstate; + struct sde_plane_state *sde_pstate; + int rc = 0, i; + + /* Check dim layer rect bounds and stage */ + for (i = 0; i < cstate->num_dim_layers; i++) { + if ((CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.y, + cstate->dim_layer[i].rect.h, mode->vdisplay)) || + (CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.x, + cstate->dim_layer[i].rect.w, mode->hdisplay)) || + (cstate->dim_layer[i].stage >= SDE_STAGE_MAX) || + (!cstate->dim_layer[i].rect.w) || + (!cstate->dim_layer[i].rect.h)) { + SDE_ERROR("invalid dim_layer:{%d,%d,%d,%d}, stage:%d\n", + cstate->dim_layer[i].rect.x, + cstate->dim_layer[i].rect.y, + cstate->dim_layer[i].rect.w, + cstate->dim_layer[i].rect.h, + cstate->dim_layer[i].stage); + SDE_ERROR("display: %dx%d\n", mode->hdisplay, + mode->vdisplay); + rc = -E2BIG; + goto end; + } + } + + /* log all src and excl_rect, useful for debugging */ + for (i = 0; i < cnt; i++) { + pstate = pstates[i].drm_pstate; + sde_pstate = to_sde_plane_state(pstate); + SDE_DEBUG("p %d z %d src{%d,%d,%d,%d} excl_rect{%d,%d,%d,%d}\n", + pstate->plane->base.id, pstates[i].stage, + pstate->crtc_x, pstate->crtc_y, + pstate->crtc_w, pstate->crtc_h, + sde_pstate->excl_rect.x, sde_pstate->excl_rect.y, + sde_pstate->excl_rect.w, sde_pstate->excl_rect.h); + } + +end: + return rc; +} + +static int _sde_crtc_check_secure_blend_config(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct plane_state pstates[], + struct sde_crtc_state *cstate, struct sde_kms *sde_kms, + int cnt, int secure, int fb_ns, int fb_sec, int fb_sec_dir) +{ + struct drm_plane *plane; + int i; + struct drm_crtc_state *old_state = crtc->state; + struct sde_crtc_state *old_cstate = to_sde_crtc_state(old_state); + + if (secure == SDE_DRM_SEC_ONLY) { + /* + * validate planes - only fb_sec_dir is allowed during sec_crtc + * - fb_sec_dir is for secure camera preview and + * secure display use case + * - fb_sec is for secure video playback + * - fb_ns is for normal non secure use cases + */ + if (fb_ns || fb_sec) { + SDE_ERROR( + "crtc%d: invalid fb_modes Sec:%d, NS:%d, Sec_Dir:%d\n", + DRMID(crtc), fb_sec, fb_ns, fb_sec_dir); + return -EINVAL; + } + + /* + * - only one blending stage is allowed in sec_crtc + * - validate if pipe is allowed for sec-ui updates + */ + for (i = 1; i < cnt; i++) { + if (!pstates[i].drm_pstate + || !pstates[i].drm_pstate->plane) { + SDE_ERROR("crtc%d: invalid pstate at i:%d\n", + DRMID(crtc), i); + return -EINVAL; + } + plane = pstates[i].drm_pstate->plane; + + if (!sde_plane_is_sec_ui_allowed(plane)) { + SDE_ERROR("crtc%d: sec-ui not allowed in p%d\n", + DRMID(crtc), plane->base.id); + return -EINVAL; + + } else if (pstates[i].stage != pstates[i-1].stage) { + SDE_ERROR( + "crtc%d: invalid blend stages %d:%d, %d:%d\n", + DRMID(crtc), i, pstates[i].stage, + i-1, pstates[i-1].stage); + return -EINVAL; + } + } + + /* check if all the dim_layers are in the same stage */ + for (i = 1; i < cstate->num_dim_layers; i++) { + if (cstate->dim_layer[i].stage != + cstate->dim_layer[i-1].stage) { + SDE_ERROR( + "crtc%d: invalid dimlayer stage %d:%d, %d:%d\n", + DRMID(crtc), + i, cstate->dim_layer[i].stage, + i-1, cstate->dim_layer[i-1].stage); + return -EINVAL; + } + } + + /* + * if secure-ui supported blendstage is specified, + * - fail empty commit + * - validate dim_layer or plane is staged in the supported + * blendstage + * - fail if previous commit has no planes staged and + * no dim layer at highest blendstage. + */ + if (sde_kms->catalog->sui_supported_blendstage) { + int sec_stage = cnt ? pstates[0].sde_pstate->stage : + cstate->dim_layer[0].stage; + + if (!sde_kms->catalog->has_base_layer) + sec_stage -= SDE_STAGE_0; + + if ((!cnt && !cstate->num_dim_layers) || + (sde_kms->catalog->sui_supported_blendstage + != sec_stage)) { + SDE_ERROR( + "crtc%d: empty cnt%d/dim%d or bad stage%d\n", + DRMID(crtc), cnt, + cstate->num_dim_layers, sec_stage); + return -EINVAL; + } + + if (!old_state->plane_mask && + !old_cstate->num_dim_layers) { + SDE_ERROR( + "crtc%d: no dim layer in nonsecure to secure transition\n", + DRMID(crtc)); + return -EINVAL; + } + } + } + + return 0; +} + +static int _sde_crtc_check_secure_single_encoder(struct drm_crtc *crtc, + struct drm_crtc_state *state, int fb_sec_dir) +{ + struct drm_encoder *encoder; + int encoder_cnt = 0; + + if (fb_sec_dir) { + drm_for_each_encoder_mask(encoder, crtc->dev, + state->encoder_mask) + encoder_cnt++; + + if (encoder_cnt > MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC) { + SDE_ERROR("crtc:%d invalid number of encoders:%d\n", + DRMID(crtc), encoder_cnt); + return -EINVAL; + } + } + return 0; +} + +static int _sde_crtc_check_secure_state_smmu_translation(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct sde_kms *sde_kms, int secure, + int fb_ns, int fb_sec, int fb_sec_dir) +{ + struct sde_kms_smmu_state_data *smmu_state = &sde_kms->smmu_state; + struct drm_encoder *encoder; + int is_video_mode = false; + + drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) { + if (sde_encoder_is_dsi_display(encoder)) + is_video_mode |= sde_encoder_check_curr_mode(encoder, + MSM_DISPLAY_VIDEO_MODE); + } + + /* + * Secure display to secure camera needs without direct + * transition is currently not allowed + */ + if (fb_sec_dir && secure == SDE_DRM_SEC_NON_SEC && + smmu_state->state != ATTACHED && + smmu_state->secure_level == SDE_DRM_SEC_ONLY) { + + SDE_EVT32(DRMID(crtc), fb_ns, fb_sec_dir, + smmu_state->state, smmu_state->secure_level, + secure); + goto sec_err; + } + + /* + * In video mode check for null commit before transition + * from secure to non secure and vice versa + */ + if (is_video_mode && smmu_state && + state->plane_mask && crtc->state->plane_mask && + ((fb_sec_dir && ((smmu_state->state == ATTACHED) && + (secure == SDE_DRM_SEC_ONLY))) || + (fb_ns && ((smmu_state->state == DETACHED) || + (smmu_state->state == DETACH_ALL_REQ))) || + (fb_ns && ((smmu_state->state == DETACHED_SEC) || + (smmu_state->state == DETACH_SEC_REQ)) && + (smmu_state->secure_level == SDE_DRM_SEC_ONLY)))) { + + SDE_EVT32(DRMID(crtc), fb_ns, fb_sec_dir, + smmu_state->state, smmu_state->secure_level, + secure, crtc->state->plane_mask, state->plane_mask); + goto sec_err; + } + + return 0; + +sec_err: + SDE_ERROR( + "crtc%d Invalid transition;sec%d state%d slvl%d ns%d sdir%d\n", + DRMID(crtc), secure, smmu_state->state, + smmu_state->secure_level, fb_ns, fb_sec_dir); + return -EINVAL; +} + +static int _sde_crtc_check_secure_conn(struct drm_crtc *crtc, + struct drm_crtc_state *state, uint32_t fb_sec) +{ + + bool conn_secure = false, is_wb = false; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + int i; + + for_each_new_connector_in_state(state->state, conn, conn_state, i) { + if (conn_state && conn_state->crtc == crtc) { + if (conn->connector_type == + DRM_MODE_CONNECTOR_VIRTUAL) + is_wb = true; + if (sde_connector_get_property(conn_state, + CONNECTOR_PROP_FB_TRANSLATION_MODE) == + SDE_DRM_FB_SEC) + conn_secure = true; + } + } + + /* + * If any input buffers are secure for wb, + * the output buffer must also be secure. + */ + if (is_wb && fb_sec && !conn_secure) { + SDE_ERROR("crtc%d: input fb sec %d, output fb secure %d\n", + DRMID(crtc), fb_sec, conn_secure); + return -EINVAL; + } + + return 0; +} + +static int _sde_crtc_check_secure_state(struct drm_crtc *crtc, + struct drm_crtc_state *state, struct plane_state pstates[], + int cnt) +{ + struct sde_crtc_state *cstate; + struct sde_kms *sde_kms; + uint32_t secure; + uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0; + int rc; + + if (!crtc || !state) { + SDE_ERROR("invalid arguments\n"); + return -EINVAL; + } + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms || !sde_kms->catalog) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + cstate = to_sde_crtc_state(state); + + secure = sde_crtc_get_property(cstate, CRTC_PROP_SECURITY_LEVEL); + + rc = sde_crtc_state_find_plane_fb_modes(state, &fb_ns, + &fb_sec, &fb_sec_dir); + if (rc) + return rc; + + rc = _sde_crtc_check_secure_blend_config(crtc, state, pstates, cstate, + sde_kms, cnt, secure, fb_ns, fb_sec, fb_sec_dir); + if (rc) + return rc; + + rc = _sde_crtc_check_secure_conn(crtc, state, fb_sec); + if (rc) + return rc; + + /* + * secure_crtc is not allowed in a shared toppolgy + * across different encoders. + */ + rc = _sde_crtc_check_secure_single_encoder(crtc, state, fb_sec_dir); + if (rc) + return rc; + + rc = _sde_crtc_check_secure_state_smmu_translation(crtc, state, sde_kms, + secure, fb_ns, fb_sec, fb_sec_dir); + if (rc) + return rc; + + SDE_DEBUG("crtc:%d Secure validation successful\n", DRMID(crtc)); + + return 0; +} + +int op_dimlayer_bl_alpha = 260; +int op_dimlayer_bl_enabled = 0; +int op_dimlayer_bl_enable_real = 0; +int op_dimlayer_bl = 0; +bool finger_type = false; +extern int aod_layer_hide; +extern int op_dimlayer_bl_enable; +extern int op_dp_enable; +extern int sde_plane_check_fingerprint_layer(const struct drm_plane_state *drm_state); +static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, + struct plane_state *pstates, int cnt) +{ + int fp_index = -1; + int fppressed_index = -1; + int aod_index = -1; + int fppressed_index_rt = -1; + int zpos = INT_MAX; + int mode; + int fp_mode = oneplus_onscreenfp_status; + int dim_mode = oneplus_dim_status; + int aod_mode = -1; + int i = 0; + int dim_backlight = 0; + struct dsi_display *display = get_main_display(); + static int dim_backlight_pre; + + if (display == NULL || + display->panel == NULL) { + SDE_ERROR("display panel is null\n"); + return 0; + } + + if (display->panel->aod_status == 1) { + if (oneplus_dim_status == 2 && oneplus_onscreenfp_status == 1) { + fp_mode = 1; + //dim_mode = 0; + } else if (oneplus_dim_status == 2 && oneplus_onscreenfp_status == 0) { + if (display->panel->aod_mode == 2) { + fp_mode = 0; + dim_mode = 0; + } else { + fp_mode = 0; + //dim_mode = 0; + } + } else if (oneplus_dim_status == 2 && oneplus_onscreenfp_status == 4) { + fp_mode = 0; + dim_mode = 0; + } + } else if (oneplus_onscreenfp_status == 0 || oneplus_onscreenfp_status == 4) { + fp_mode = 0; + //dim_mode = 0; //add for press hbm up + } + if ((display->panel->aod_mode && display->panel->aod_mode != 2 && display->panel->aod_mode != 4) && + (oneplus_dim_status == 5 || aod_layer_hide == 1)) { + SDE_ERROR("display oneplus_onscreenaod_hid is 1\n"); + oneplus_aod_hid = 1; + dim_mode = 0; + } + aod_mode = oneplus_aod_hid; + if (oneplus_dim_status == 5 && display->panel->aod_status == 0) + dim_mode = 0; + + for (i = 0; i < cnt; i++) { + mode = sde_plane_check_fingerprint_layer(pstates[i].drm_pstate); + if (mode == 1) + fp_index = i; + if (mode == 2) { + fppressed_index = i; + fppressed_index_rt = i; + } + if (mode ==3) + aod_index = i; + } + if(fp_index >=0 && dim_mode!=0) + display->panel->dim_status = true; + else + display->panel->dim_status = false; + + if(aod_index <0){ + oneplus_aod_hid = 0; + aod_layer_hide = 0; + } + + if (fppressed_index_rt < 0) { + oneplus_aod_fod = 0; + oneplus_aod_dc = 0; + } + + if (finger_type) { + if (aod_index >= 0 && + aod_mode == 1) { + SDE_ATRACE_BEGIN("aod_layer_qbt_hid"); + pstates[aod_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; + aod_index = -1; + SDE_ATRACE_END("aod_layer_qbt_hid"); + } + return 0; + } + + if ( + (fp_index >= 0 && dim_mode != 0) || + (display->panel->aod_status == 1 + && oneplus_aod_dc == 0) + ) { + op_dimlayer_bl = 0; + } else { + if (op_dimlayer_bl_enable && !op_dp_enable) { + //if (/*display->panel->bl_config.bl_level != 0 &&*/ + // display->panel->bl_config.bl_level < op_dimlayer_bl_alpha) { + // dim_backlight = 1; + // op_dimlayer_bl = 1; + + //} else { + op_dimlayer_bl = 0; + //} + } else { + op_dimlayer_bl = 0; + if (dim_backlight_pre) { + dim_backlight = 1; + + dim_backlight_pre = 0; + SDE_ERROR("show dl one more frame %d\n", dsi_panel_name); + } + } + } + + SDE_DEBUG("fp_index=%d,fppressed_index=%d,aod_index=%d\n", fp_index, fppressed_index, aod_index); + if (fp_index >= 0 || fppressed_index >= 0 || oneplus_force_screenfp || dim_backlight == 1) { + if (fp_index >= 0 && fppressed_index >= 0) { + if (pstates[fp_index].stage >= pstates[fppressed_index].stage) { + SDE_ERROR("Bug!!@@@@: fp layer top of fppressed layer\n"); + return -EINVAL; + } + } + if (fppressed_index >= 0) { + if (zpos > pstates[fppressed_index].stage) + zpos = pstates[fppressed_index].stage; + pstates[fppressed_index].stage++; + } + + if (fp_index >= 0) { + if (zpos > pstates[fp_index].stage) + zpos = pstates[fp_index].stage; + pstates[fp_index].stage++; + } + for (i = 0; i < cnt; i++) { + if (i == fp_index || i == fppressed_index) + { + continue; + } + if (pstates[i].stage >= zpos) { + // SDE_ERROR("Warn!!: the fp layer not on top"); + pstates[i].stage++; + } + } + if (zpos == INT_MAX) { + zpos = 0; + for (i = 0; i < cnt; i++) { + if (pstates[i].stage > zpos) + zpos = pstates[i].stage; + } + zpos++; + } + + if (fp_index >= 0) { + if (dim_mode == 0) { + //pstates[fp_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + fp_index = -1; + } + } + if (fppressed_index >= 0) { + if (fp_mode == 0) { + pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; + if(oneplus_aod_fod == 1 && aod_index < 0) { + SDE_DEBUG("set reset pstate\n"); + for (i = 0; i < cnt; i++) { + if(i!=fppressed_index ) { + if(pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value == 0){ + pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + } + } + } + } + fppressed_index = -1; + } else { + pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + } + } + + if (aod_index >= 0) { + if (aod_mode == 1) { + SDE_DEBUG("aod layer hid"); + SDE_ATRACE_BEGIN("aod_layer_hid"); + pstates[aod_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; + aod_index = -1; + SDE_ATRACE_END("aod_layer_hid"); + } + } + + if (fp_index >= 0) + cstate->fingerprint_mode = true; + else + cstate->fingerprint_mode = false; + + if ((fp_index >= 0 || dim_backlight > 0) && sde_crtc_config_fingerprint_dim_layer(&cstate->base, zpos)) { + SDE_ERROR("Failed to config dim layer\n"); + return -EINVAL; + } + if (fppressed_index >= 0) + cstate->fingerprint_pressed = true; + else { + cstate->fingerprint_pressed = false; + } + } else { + cstate->fingerprint_pressed = false; + cstate->fingerprint_mode = false; + for (i = 0; i < cnt; i++) { + if(pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value == 0){ + SDE_DEBUG("pstates PLANE_PROP_ALPHA value is 0\n"); + } + } + } + if (fp_index < 0 && !dim_backlight) { + cstate->fingerprint_dim_layer = NULL; + } + + return 0; +} +static int _sde_crtc_check_get_pstates(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_display_mode *mode, + struct plane_state *pstates, + struct drm_plane *plane, + struct sde_multirect_plane_states *multirect_plane, + int *cnt) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + const struct drm_plane_state *pstate; + const struct drm_plane_state *pipe_staged[SSPP_MAX]; + int rc = 0, multirect_count = 0, i, mixer_width, mixer_height; + int inc_sde_stage = 0; + struct sde_kms *kms; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + kms = _sde_crtc_get_kms(crtc); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + memset(pipe_staged, 0, sizeof(pipe_staged)); + + mixer_width = sde_crtc_get_mixer_width(sde_crtc, cstate, mode); + mixer_height = sde_crtc_get_mixer_height(sde_crtc, cstate, mode); + + if (cstate->num_ds_enabled) + mixer_width = mixer_width * cstate->num_ds_enabled; + + drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) { + if (IS_ERR_OR_NULL(pstate)) { + rc = PTR_ERR(pstate); + SDE_ERROR("%s: failed to get plane%d state, %d\n", + sde_crtc->name, plane->base.id, rc); + return rc; + } + + if (*cnt >= SDE_PSTATES_MAX) + continue; + + pstates[*cnt].sde_pstate = to_sde_plane_state(pstate); + pstates[*cnt].drm_pstate = pstate; + pstates[*cnt].stage = sde_plane_get_property( + pstates[*cnt].sde_pstate, PLANE_PROP_ZPOS); + pstates[*cnt].pipe_id = sde_plane_pipe(plane); + + if (!kms->catalog->has_base_layer) + inc_sde_stage = SDE_STAGE_0; + + /* check dim layer stage with every plane */ + for (i = 0; i < cstate->num_dim_layers; i++) { + if (cstate->dim_layer[i].stage == + (pstates[*cnt].stage + inc_sde_stage)) { + SDE_ERROR( + "plane:%d/dim_layer:%i-same stage:%d\n", + plane->base.id, i, + cstate->dim_layer[i].stage); + return -EINVAL; + } + } + + if (pipe_staged[pstates[*cnt].pipe_id]) { + multirect_plane[multirect_count].r0 = + pipe_staged[pstates[*cnt].pipe_id]; + multirect_plane[multirect_count].r1 = pstate; + multirect_count++; + + pipe_staged[pstates[*cnt].pipe_id] = NULL; + } else { + pipe_staged[pstates[*cnt].pipe_id] = pstate; + } + + (*cnt)++; + + if (CHECK_LAYER_BOUNDS(pstate->crtc_y, pstate->crtc_h, + mode->vdisplay) || + CHECK_LAYER_BOUNDS(pstate->crtc_x, pstate->crtc_w, + mode->hdisplay)) { + SDE_ERROR("invalid vertical/horizontal destination\n"); + SDE_ERROR("y:%d h:%d vdisp:%d x:%d w:%d hdisp:%d\n", + pstate->crtc_y, pstate->crtc_h, mode->vdisplay, + pstate->crtc_x, pstate->crtc_w, mode->hdisplay); + return -E2BIG; + } + + if (cstate->num_ds_enabled && + ((pstate->crtc_h > mixer_height) || + (pstate->crtc_w > mixer_width))) { + SDE_ERROR("plane w/h:%x*%x > mixer w/h:%x*%x\n", + pstate->crtc_w, pstate->crtc_h, + mixer_width, mixer_height); + return -E2BIG; + } + } + + for (i = 1; i < SSPP_MAX; i++) { + if (pipe_staged[i]) { + if (is_sde_plane_virtual(pipe_staged[i]->plane)) { + SDE_ERROR( + "r1 only virt plane:%d not supported\n", + pipe_staged[i]->plane->base.id); + return -EINVAL; + } + sde_plane_clear_multirect(pipe_staged[i]); + } + } + + for (i = 0; i < multirect_count; i++) { + if (sde_plane_validate_multirect_v2(&multirect_plane[i])) { + SDE_ERROR( + "multirect validation failed for planes (%d - %d)\n", + multirect_plane[i].r0->plane->base.id, + multirect_plane[i].r1->plane->base.id); + return -EINVAL; + } + } + return rc; +} + +static int _sde_crtc_check_zpos(struct drm_crtc_state *state, + struct sde_crtc *sde_crtc, + struct plane_state *pstates, + struct sde_crtc_state *cstate, + struct drm_display_mode *mode, + int cnt) +{ + int rc = 0, i, z_pos; + u32 zpos_cnt = 0; + struct drm_crtc *crtc; + struct sde_kms *kms; + + crtc = &sde_crtc->base; + kms = _sde_crtc_get_kms(crtc); + + if (!kms || !kms->catalog) { + SDE_ERROR("Invalid kms\n"); + return -EINVAL; + } + + sort(pstates, cnt, sizeof(pstates[0]), pstate_cmp, NULL); + + rc = _sde_crtc_excl_dim_layer_check(state, pstates, cnt); + if (rc) + return rc; + + if (!sde_is_custom_client()) { + int stage_old = pstates[0].stage; + + z_pos = 0; + for (i = 0; i < cnt; i++) { + if (stage_old != pstates[i].stage) + ++z_pos; + stage_old = pstates[i].stage; + pstates[i].stage = z_pos; + } + } + + z_pos = -1; + for (i = 0; i < cnt; i++) { + /* reset counts at every new blend stage */ + if (pstates[i].stage != z_pos) { + zpos_cnt = 0; + z_pos = pstates[i].stage; + } + + /* verify z_pos setting before using it */ + if (z_pos >= SDE_STAGE_MAX - SDE_STAGE_0) { + SDE_ERROR("> %d plane stages assigned\n", + SDE_STAGE_MAX - SDE_STAGE_0); + return -EINVAL; + } else if (zpos_cnt == 2) { + SDE_ERROR("> 2 planes @ stage %d\n", z_pos); + return -EINVAL; + } else { + zpos_cnt++; + } + + if (!kms->catalog->has_base_layer) + pstates[i].sde_pstate->stage = z_pos + SDE_STAGE_0; + else + pstates[i].sde_pstate->stage = z_pos; + + SDE_DEBUG("%s: zpos %d", sde_crtc->name, z_pos); + } + return rc; +} + +static int _sde_crtc_atomic_check_pstates(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct plane_state *pstates, + struct sde_multirect_plane_states *multirect_plane) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct sde_kms *kms; + struct drm_plane *plane; + struct drm_display_mode *mode; + int rc = 0, cnt = 0; + + kms = _sde_crtc_get_kms(crtc); + + if (!kms || !kms->catalog) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + mode = &state->adjusted_mode; + + /* get plane state for all drm planes associated with crtc state */ + rc = _sde_crtc_check_get_pstates(crtc, state, mode, pstates, + plane, multirect_plane, &cnt); + if (rc) + return rc; + + rc = sde_crtc_onscreenfinger_atomic_check(cstate, pstates, cnt); + if (rc) + return rc; + /* assign mixer stages based on sorted zpos property */ + rc = _sde_crtc_check_zpos(state, sde_crtc, pstates, cstate, mode, cnt); + if (rc) + return rc; + + rc = _sde_crtc_check_secure_state(crtc, state, pstates, cnt); + if (rc) + return rc; + + /* + * validate and set source split: + * use pstates sorted by stage to check planes on same stage + * we assume that all pipes are in source split so its valid to compare + * without taking into account left/right mixer placement + */ + rc = _sde_crtc_validate_src_split_order(crtc, pstates, cnt); + if (rc) + return rc; + + return 0; +} + +static int sde_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct drm_device *dev; + struct sde_crtc *sde_crtc; + struct plane_state *pstates = NULL; + struct sde_crtc_state *cstate; + struct drm_display_mode *mode; + int rc = 0; + struct sde_multirect_plane_states *multirect_plane = NULL; + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + + dev = crtc->dev; + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + if (!state->enable || !state->active) { + SDE_DEBUG("crtc%d -> enable %d, active %d, skip atomic_check\n", + crtc->base.id, state->enable, state->active); + goto end; + } + + pstates = kcalloc(SDE_PSTATES_MAX, + sizeof(struct plane_state), GFP_KERNEL); + + multirect_plane = kcalloc(SDE_MULTIRECT_PLANE_MAX, + sizeof(struct sde_multirect_plane_states), + GFP_KERNEL); + + if (!pstates || !multirect_plane) { + rc = -ENOMEM; + goto end; + } + + mode = &state->adjusted_mode; + SDE_DEBUG("%s: check", sde_crtc->name); + + /* force a full mode set if active state changed */ + if (state->active_changed) + state->mode_changed = true; + + rc = _sde_crtc_check_dest_scaler_data(crtc, state); + if (rc) { + SDE_ERROR("crtc%d failed dest scaler check %d\n", + crtc->base.id, rc); + goto end; + } + + /* identify connectors attached to this crtc */ + cstate->num_connectors = 0; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) + if (conn->state && conn->state->crtc == crtc && + cstate->num_connectors < MAX_CONNECTORS) { + cstate->connectors[cstate->num_connectors++] = conn; + } + drm_connector_list_iter_end(&conn_iter); + + _sde_crtc_setup_is_ppsplit(state); + _sde_crtc_setup_lm_bounds(crtc, state); + + rc = _sde_crtc_atomic_check_pstates(crtc, state, pstates, + multirect_plane); + if (rc) { + SDE_ERROR("crtc%d failed pstate check %d\n", crtc->base.id, rc); + goto end; + } + + rc = sde_core_perf_crtc_check(crtc, state); + if (rc) { + SDE_ERROR("crtc%d failed performance check %d\n", + crtc->base.id, rc); + goto end; + } + + rc = _sde_crtc_check_rois(crtc, state); + if (rc) { + SDE_ERROR("crtc%d failed roi check %d\n", crtc->base.id, rc); + goto end; + } + +end: + kfree(pstates); + kfree(multirect_plane); + return rc; +} + +/** + * sde_crtc_get_num_datapath - get the number of datapath active + * of primary connector + * @crtc: Pointer to DRM crtc object + * @connector: Pointer to DRM connector object of WB in CWB case + */ +int sde_crtc_get_num_datapath(struct drm_crtc *crtc, + struct drm_connector *connector) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_connector_state *sde_conn_state = NULL; + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + + if (!sde_crtc || !connector) { + SDE_DEBUG("Invalid argument\n"); + return 0; + } + + if (sde_crtc->num_mixers) + return sde_crtc->num_mixers; + + drm_connector_list_iter_begin(crtc->dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + if (conn->state && conn->state->crtc == crtc && + conn != connector) + sde_conn_state = to_sde_connector_state(conn->state); + } + + drm_connector_list_iter_end(&conn_iter); + + if (sde_conn_state) + return sde_conn_state->mode_info.topology.num_lm; + + return 0; +} + +int sde_crtc_vblank(struct drm_crtc *crtc, bool en) +{ + struct sde_crtc *sde_crtc; + int ret; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + sde_crtc = to_sde_crtc(crtc); + + mutex_lock(&sde_crtc->vblank_modeset_ctrl_lock); + mutex_lock(&sde_crtc->crtc_lock); + SDE_EVT32(DRMID(&sde_crtc->base), en, sde_crtc->enabled); + ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, en); + if (ret) + SDE_ERROR("%s vblank enable failed: %d\n", + sde_crtc->name, ret); + + mutex_unlock(&sde_crtc->crtc_lock); + mutex_unlock(&sde_crtc->vblank_modeset_ctrl_lock); + + return 0; +} + +static void sde_kms_add_ubwc_info(struct sde_kms_info *info, + struct sde_mdss_cfg *catalog) +{ + sde_kms_info_add_keyint(info, "UBWC version", + catalog->ubwc_version); + sde_kms_info_add_keyint(info, "UBWC macrotile_mode", + catalog->macrotile_mode); + sde_kms_info_add_keyint(info, "UBWC highest banking bit", + catalog->mdp[0].highest_bank_bit); + sde_kms_info_add_keyint(info, "UBWC swizzle", + catalog->mdp[0].ubwc_swizzle); + + if (of_fdt_get_ddrtype() == LP_DDR4_TYPE) + sde_kms_info_add_keystr(info, "DDR version", "DDR4"); + else + sde_kms_info_add_keystr(info, "DDR version", "DDR5"); +} + +/** + * sde_crtc_install_properties - install all drm properties for crtc + * @crtc: Pointer to drm crtc structure + */ +static void sde_crtc_install_properties(struct drm_crtc *crtc, + struct sde_mdss_cfg *catalog) +{ + struct sde_crtc *sde_crtc; + struct drm_device *dev; + struct sde_kms_info *info; + struct sde_kms *sde_kms; + int i, j; + + static const struct drm_prop_enum_list e_secure_level[] = { + {SDE_DRM_SEC_NON_SEC, "sec_and_non_sec"}, + {SDE_DRM_SEC_ONLY, "sec_only"}, + }; + + static const struct drm_prop_enum_list e_cwb_data_points[] = { + {CAPTURE_MIXER_OUT, "capture_mixer_out"}, + {CAPTURE_DSPP_OUT, "capture_pp_out"}, + }; + + static const struct drm_prop_enum_list e_idle_pc_state[] = { + {IDLE_PC_NONE, "idle_pc_none"}, + {IDLE_PC_ENABLE, "idle_pc_enable"}, + {IDLE_PC_DISABLE, "idle_pc_disable"}, + }; + + SDE_DEBUG("\n"); + + if (!crtc || !catalog) { + SDE_ERROR("invalid crtc or catalog\n"); + return; + } + + sde_crtc = to_sde_crtc(crtc); + dev = crtc->dev; + sde_kms = _sde_crtc_get_kms(crtc); + + if (!sde_kms) { + SDE_ERROR("invalid argument\n"); + return; + } + + info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL); + if (!info) { + SDE_ERROR("failed to allocate info memory\n"); + return; + } + + /* range properties */ + msm_property_install_range(&sde_crtc->property_info, + "input_fence_timeout", 0x0, 0, SDE_CRTC_MAX_INPUT_FENCE_TIMEOUT, + SDE_CRTC_INPUT_FENCE_TIMEOUT, CRTC_PROP_INPUT_FENCE_TIMEOUT); + + msm_property_install_volatile_range(&sde_crtc->property_info, + "output_fence", 0x0, 0, ~0, 0, CRTC_PROP_OUTPUT_FENCE); + + msm_property_install_range(&sde_crtc->property_info, + "output_fence_offset", 0x0, 0, 1, 0, + CRTC_PROP_OUTPUT_FENCE_OFFSET); + + msm_property_install_range(&sde_crtc->property_info, + "core_clk", 0x0, 0, U64_MAX, + sde_kms->perf.max_core_clk_rate, + CRTC_PROP_CORE_CLK); + msm_property_install_range(&sde_crtc->property_info, + "core_ab", 0x0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_CORE_AB); + msm_property_install_range(&sde_crtc->property_info, + "core_ib", 0x0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_CORE_IB); + msm_property_install_range(&sde_crtc->property_info, + "llcc_ab", 0x0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_LLCC_AB); + msm_property_install_range(&sde_crtc->property_info, + "llcc_ib", 0x0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_LLCC_IB); + msm_property_install_range(&sde_crtc->property_info, + "dram_ab", 0x0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_DRAM_AB); + msm_property_install_range(&sde_crtc->property_info, + "dram_ib", 0x0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_DRAM_IB); + msm_property_install_range(&sde_crtc->property_info, + "rot_prefill_bw", 0, 0, U64_MAX, + catalog->perf.max_bw_high * 1000ULL, + CRTC_PROP_ROT_PREFILL_BW); + msm_property_install_range(&sde_crtc->property_info, + "rot_clk", 0, 0, U64_MAX, + sde_kms->perf.max_core_clk_rate, + CRTC_PROP_ROT_CLK); + + msm_property_install_range(&sde_crtc->property_info, + "idle_time", 0, 0, U64_MAX, 0, + CRTC_PROP_IDLE_TIMEOUT); + + msm_property_install_range(&sde_crtc->property_info, + "CRTC_CUST",0x0, 0, INT_MAX, 0,CRTC_PROP_CUSTOM); + if (catalog->has_idle_pc) + msm_property_install_enum(&sde_crtc->property_info, + "idle_pc_state", 0x0, 0, e_idle_pc_state, + ARRAY_SIZE(e_idle_pc_state), + CRTC_PROP_IDLE_PC_STATE); + + if (catalog->has_cwb_support) + msm_property_install_enum(&sde_crtc->property_info, + "capture_mode", 0, 0, e_cwb_data_points, + ARRAY_SIZE(e_cwb_data_points), + CRTC_PROP_CAPTURE_OUTPUT); + + msm_property_install_blob(&sde_crtc->property_info, "capabilities", + DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); + + msm_property_install_volatile_range(&sde_crtc->property_info, + "sde_drm_roi_v1", 0x0, 0, ~0, 0, CRTC_PROP_ROI_V1); + + msm_property_install_enum(&sde_crtc->property_info, "security_level", + 0x0, 0, e_secure_level, + ARRAY_SIZE(e_secure_level), + CRTC_PROP_SECURITY_LEVEL); + + sde_kms_info_reset(info); + + if (catalog->has_dim_layer) { + msm_property_install_volatile_range(&sde_crtc->property_info, + "dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1); + sde_kms_info_add_keyint(info, "dim_layer_v1_max_layers", + SDE_MAX_DIM_LAYERS); + } + + sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion); + sde_kms_info_add_keyint(info, "max_linewidth", + catalog->max_mixer_width); + sde_kms_info_add_keyint(info, "max_blendstages", + catalog->max_mixer_blendstages); + if (catalog->qseed_type == SDE_SSPP_SCALER_QSEED2) + sde_kms_info_add_keystr(info, "qseed_type", "qseed2"); + if (catalog->qseed_type == SDE_SSPP_SCALER_QSEED3) + sde_kms_info_add_keystr(info, "qseed_type", "qseed3"); + if (catalog->qseed_type == SDE_SSPP_SCALER_QSEED3LITE) + sde_kms_info_add_keystr(info, "qseed_type", "qseed3lite"); + + if (catalog->ubwc_version) + sde_kms_add_ubwc_info(info, catalog); + + if (sde_is_custom_client()) { + /* No support for SMART_DMA_V1 yet */ + if (catalog->smart_dma_rev == SDE_SSPP_SMART_DMA_V2) + sde_kms_info_add_keystr(info, + "smart_dma_rev", "smart_dma_v2"); + else if (catalog->smart_dma_rev == SDE_SSPP_SMART_DMA_V2p5) + sde_kms_info_add_keystr(info, + "smart_dma_rev", "smart_dma_v2p5"); + } + + if (catalog->mdp[0].has_dest_scaler) { + sde_kms_info_add_keyint(info, "has_dest_scaler", + catalog->mdp[0].has_dest_scaler); + sde_kms_info_add_keyint(info, "dest_scaler_count", + catalog->ds_count); + + if (catalog->ds[0].top) { + sde_kms_info_add_keyint(info, + "max_dest_scaler_input_width", + catalog->ds[0].top->maxinputwidth); + sde_kms_info_add_keyint(info, + "max_dest_scaler_output_width", + catalog->ds[0].top->maxinputwidth); + sde_kms_info_add_keyint(info, "max_dest_scale_up", + catalog->ds[0].top->maxupscale); + } + + if (catalog->ds[0].features & BIT(SDE_SSPP_SCALER_QSEED3)) { + msm_property_install_volatile_range( + &sde_crtc->property_info, "dest_scaler", + 0x0, 0, ~0, 0, CRTC_PROP_DEST_SCALER); + msm_property_install_blob(&sde_crtc->property_info, + "ds_lut_ed", 0, + CRTC_PROP_DEST_SCALER_LUT_ED); + msm_property_install_blob(&sde_crtc->property_info, + "ds_lut_cir", 0, + CRTC_PROP_DEST_SCALER_LUT_CIR); + msm_property_install_blob(&sde_crtc->property_info, + "ds_lut_sep", 0, + CRTC_PROP_DEST_SCALER_LUT_SEP); + } else if (catalog->ds[0].features + & BIT(SDE_SSPP_SCALER_QSEED3LITE)) { + msm_property_install_volatile_range( + &sde_crtc->property_info, "dest_scaler", + 0x0, 0, ~0, 0, CRTC_PROP_DEST_SCALER); + } + } + + sde_kms_info_add_keyint(info, "has_src_split", catalog->has_src_split); + sde_kms_info_add_keyint(info, "has_hdr", catalog->has_hdr); + sde_kms_info_add_keyint(info, "has_hdr_plus", catalog->has_hdr_plus); + if (catalog->perf.max_bw_low) + sde_kms_info_add_keyint(info, "max_bandwidth_low", + catalog->perf.max_bw_low * 1000LL); + if (catalog->perf.max_bw_high) + sde_kms_info_add_keyint(info, "max_bandwidth_high", + catalog->perf.max_bw_high * 1000LL); + if (catalog->perf.min_core_ib) + sde_kms_info_add_keyint(info, "min_core_ib", + catalog->perf.min_core_ib * 1000LL); + if (catalog->perf.min_llcc_ib) + sde_kms_info_add_keyint(info, "min_llcc_ib", + catalog->perf.min_llcc_ib * 1000LL); + if (catalog->perf.min_dram_ib) + sde_kms_info_add_keyint(info, "min_dram_ib", + catalog->perf.min_dram_ib * 1000LL); + if (sde_kms->perf.max_core_clk_rate) + sde_kms_info_add_keyint(info, "max_mdp_clk", + sde_kms->perf.max_core_clk_rate); + + if (catalog->uidle_cfg.uidle_rev) + sde_kms_info_add_keyint(info, "has_uidle", + true); + + for (i = 0; i < catalog->limit_count; i++) { + sde_kms_info_add_keyint(info, + catalog->limit_cfg[i].name, + catalog->limit_cfg[i].lmt_case_cnt); + + for (j = 0; j < catalog->limit_cfg[i].lmt_case_cnt; j++) { + sde_kms_info_add_keyint(info, + catalog->limit_cfg[i].vector_cfg[j].usecase, + catalog->limit_cfg[i].vector_cfg[j].value); + } + + if (!strcmp(catalog->limit_cfg[i].name, + "sspp_linewidth_usecases")) + sde_kms_info_add_keyint(info, + "sspp_linewidth_values", + catalog->limit_cfg[i].lmt_vec_cnt); + else if (!strcmp(catalog->limit_cfg[i].name, + "sde_bwlimit_usecases")) + sde_kms_info_add_keyint(info, + "sde_bwlimit_values", + catalog->limit_cfg[i].lmt_vec_cnt); + + for (j = 0; j < catalog->limit_cfg[i].lmt_vec_cnt; j++) { + sde_kms_info_add_keyint(info, "limit_usecase", + catalog->limit_cfg[i].value_cfg[j].use_concur); + sde_kms_info_add_keyint(info, "limit_value", + catalog->limit_cfg[i].value_cfg[j].value); + } + } + + sde_kms_info_add_keystr(info, "core_ib_ff", + catalog->perf.core_ib_ff); + sde_kms_info_add_keystr(info, "core_clk_ff", + catalog->perf.core_clk_ff); + sde_kms_info_add_keystr(info, "comp_ratio_rt", + catalog->perf.comp_ratio_rt); + sde_kms_info_add_keystr(info, "comp_ratio_nrt", + catalog->perf.comp_ratio_nrt); + sde_kms_info_add_keyint(info, "dest_scale_prefill_lines", + catalog->perf.dest_scale_prefill_lines); + sde_kms_info_add_keyint(info, "undersized_prefill_lines", + catalog->perf.undersized_prefill_lines); + sde_kms_info_add_keyint(info, "macrotile_prefill_lines", + catalog->perf.macrotile_prefill_lines); + sde_kms_info_add_keyint(info, "yuv_nv12_prefill_lines", + catalog->perf.yuv_nv12_prefill_lines); + sde_kms_info_add_keyint(info, "linear_prefill_lines", + catalog->perf.linear_prefill_lines); + sde_kms_info_add_keyint(info, "downscaling_prefill_lines", + catalog->perf.downscaling_prefill_lines); + sde_kms_info_add_keyint(info, "xtra_prefill_lines", + catalog->perf.xtra_prefill_lines); + sde_kms_info_add_keyint(info, "amortizable_threshold", + catalog->perf.amortizable_threshold); + sde_kms_info_add_keyint(info, "min_prefill_lines", + catalog->perf.min_prefill_lines); + sde_kms_info_add_keyint(info, "num_mnoc_ports", + catalog->perf.num_mnoc_ports); + sde_kms_info_add_keyint(info, "axi_bus_width", + catalog->perf.axi_bus_width); + sde_kms_info_add_keyint(info, "sec_ui_blendstage", + catalog->sui_supported_blendstage); + + if (catalog->ubwc_bw_calc_version) + sde_kms_info_add_keyint(info, "ubwc_bw_calc_ver", + catalog->ubwc_bw_calc_version); + + sde_kms_info_add_keyint(info, "use_baselayer_for_stage", + catalog->has_base_layer); + + msm_property_set_blob(&sde_crtc->property_info, &sde_crtc->blob_info, + info->data, SDE_KMS_INFO_DATALEN(info), CRTC_PROP_INFO); + + kfree(info); +} + +static int _sde_crtc_get_output_fence(struct drm_crtc *crtc, + const struct drm_crtc_state *state, uint64_t *val) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + uint32_t offset; + bool is_vid = false; + struct drm_encoder *encoder; + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) { + if (sde_encoder_check_curr_mode(encoder, + MSM_DISPLAY_VIDEO_MODE)) + is_vid = true; + if (is_vid) + break; + } + + offset = sde_crtc_get_property(cstate, CRTC_PROP_OUTPUT_FENCE_OFFSET); + + /* + * Increment trigger offset for vidoe mode alone as its release fence + * can be triggered only after the next frame-update. For cmd mode & + * virtual displays the release fence for the current frame can be + * triggered right after PP_DONE/WB_DONE interrupt + */ + if (is_vid) + offset++; + + /* + * Hwcomposer now queries the fences using the commit list in atomic + * commit ioctl. The offset should be set to next timeline + * which will be incremented during the prepare commit phase + */ + offset++; + + return sde_fence_create(sde_crtc->output_fence, val, offset); +} + +/** + * sde_crtc_atomic_set_property - atomically set a crtc drm property + * @crtc: Pointer to drm crtc structure + * @state: Pointer to drm crtc state structure + * @property: Pointer to targeted drm property + * @val: Updated property value + * @Returns: Zero on success + */ +static int sde_crtc_atomic_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, + uint64_t val) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + int idx, ret; + uint64_t fence_user_fd; + uint64_t __user prev_user_fd; + + if (!crtc || !state || !property) { + SDE_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + SDE_ATRACE_BEGIN("sde_crtc_atomic_set_property"); + /* check with cp property system first */ + ret = sde_cp_crtc_set_property(crtc, property, val); + if (ret != -ENOENT) + goto exit; + + /* if not handled by cp, check msm_property system */ + ret = msm_property_atomic_set(&sde_crtc->property_info, + &cstate->property_state, property, val); + if (ret) + goto exit; + + idx = msm_property_index(&sde_crtc->property_info, property); + switch (idx) { + case CRTC_PROP_INPUT_FENCE_TIMEOUT: + _sde_crtc_set_input_fence_timeout(cstate); + break; + case CRTC_PROP_DIM_LAYER_V1: + _sde_crtc_set_dim_layer_v1(crtc, cstate, + (void __user *)(uintptr_t)val); + break; + case CRTC_PROP_ROI_V1: + ret = _sde_crtc_set_roi_v1(state, + (void __user *)(uintptr_t)val); + break; + case CRTC_PROP_DEST_SCALER: + ret = _sde_crtc_set_dest_scaler(sde_crtc, cstate, + (void __user *)(uintptr_t)val); + break; + case CRTC_PROP_DEST_SCALER_LUT_ED: + case CRTC_PROP_DEST_SCALER_LUT_CIR: + case CRTC_PROP_DEST_SCALER_LUT_SEP: + ret = _sde_crtc_set_dest_scaler_lut(sde_crtc, cstate, idx); + break; + case CRTC_PROP_CORE_CLK: + case CRTC_PROP_CORE_AB: + case CRTC_PROP_CORE_IB: + cstate->bw_control = true; + break; + case CRTC_PROP_LLCC_AB: + case CRTC_PROP_LLCC_IB: + case CRTC_PROP_DRAM_AB: + case CRTC_PROP_DRAM_IB: + cstate->bw_control = true; + cstate->bw_split_vote = true; + break; + case CRTC_PROP_OUTPUT_FENCE: + if (!val) + goto exit; + + ret = copy_from_user(&prev_user_fd, (void __user *)val, + sizeof(uint64_t)); + if (ret) { + SDE_ERROR("copy from user failed rc:%d\n", ret); + ret = -EFAULT; + goto exit; + } + + /* + * client is expected to reset the property to -1 before + * requesting for the release fence + */ + if (prev_user_fd == -1) { + ret = _sde_crtc_get_output_fence(crtc, state, + &fence_user_fd); + if (ret) { + SDE_ERROR("fence create failed rc:%d\n", ret); + goto exit; + } + + ret = copy_to_user((uint64_t __user *)(uintptr_t)val, + &fence_user_fd, sizeof(uint64_t)); + if (ret) { + SDE_ERROR("copy to user failed rc:%d\n", ret); + put_unused_fd(fence_user_fd); + ret = -EFAULT; + goto exit; + } + } + break; + default: + /* nothing to do */ + break; + } + +exit: + if (ret) { + if (ret != -EPERM) + SDE_ERROR("%s: failed to set property%d %s: %d\n", + crtc->name, DRMID(property), + property->name, ret); + else + SDE_DEBUG("%s: failed to set property%d %s: %d\n", + crtc->name, DRMID(property), + property->name, ret); + } else { + SDE_DEBUG("%s: %s[%d] <= 0x%llx\n", crtc->name, property->name, + property->base.id, val); + } + + SDE_ATRACE_END("sde_crtc_atomic_set_property"); + return ret; +} + +/** + * sde_crtc_atomic_get_property - retrieve a crtc drm property + * @crtc: Pointer to drm crtc structure + * @state: Pointer to drm crtc state structure + * @property: Pointer to targeted drm property + * @val: Pointer to variable for receiving property value + * @Returns: Zero on success + */ +static int sde_crtc_atomic_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + int ret = -EINVAL, i; + + if (!crtc || !state) { + SDE_ERROR("invalid argument(s)\n"); + goto end; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(state); + + i = msm_property_index(&sde_crtc->property_info, property); + if (i == CRTC_PROP_OUTPUT_FENCE) { + *val = ~0; + ret = 0; + } else { + ret = msm_property_atomic_get(&sde_crtc->property_info, + &cstate->property_state, property, val); + if (ret) + ret = sde_cp_crtc_get_property(crtc, property, val); + } + if (ret) + DRM_ERROR("get property failed\n"); + +end: + return ret; +} + +int sde_crtc_helper_reset_custom_properties(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct drm_property *drm_prop; + enum msm_mdp_crtc_property prop_idx; + + if (!crtc || !crtc_state) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + sde_crtc = to_sde_crtc(crtc); + cstate = to_sde_crtc_state(crtc_state); + + sde_cp_crtc_clear(crtc); + + for (prop_idx = 0; prop_idx < CRTC_PROP_COUNT; prop_idx++) { + uint64_t val = cstate->property_values[prop_idx].value; + uint64_t def; + int ret; + + drm_prop = msm_property_index_to_drm_property( + &sde_crtc->property_info, prop_idx); + if (!drm_prop) { + /* not all props will be installed, based on caps */ + SDE_DEBUG("%s: invalid property index %d\n", + sde_crtc->name, prop_idx); + continue; + } + + def = msm_property_get_default(&sde_crtc->property_info, + prop_idx); + if (val == def) + continue; + + SDE_DEBUG("%s: set prop %s idx %d from %llu to %llu\n", + sde_crtc->name, drm_prop->name, prop_idx, val, + def); + + ret = sde_crtc_atomic_set_property(crtc, crtc_state, drm_prop, + def); + if (ret) { + SDE_ERROR("%s: set property failed, idx %d ret %d\n", + sde_crtc->name, prop_idx, ret); + continue; + } + } + + return 0; +} + +void sde_crtc_misr_setup(struct drm_crtc *crtc, bool enable, u32 frame_count) +{ + struct sde_crtc *sde_crtc; + struct sde_crtc_mixer *m; + int i; + + if (!crtc) { + SDE_ERROR("invalid argument\n"); + return; + } + sde_crtc = to_sde_crtc(crtc); + + sde_crtc->misr_enable_sui = enable; + sde_crtc->misr_frame_count = frame_count; + for (i = 0; i < sde_crtc->num_mixers; ++i) { + m = &sde_crtc->mixers[i]; + if (!m->hw_lm || !m->hw_lm->ops.setup_misr) + continue; + + m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count); + } +} + +void sde_crtc_get_misr_info(struct drm_crtc *crtc, + struct sde_crtc_misr_info *crtc_misr_info) +{ + struct sde_crtc *sde_crtc; + struct sde_kms *sde_kms; + + if (!crtc_misr_info) { + SDE_ERROR("invalid misr info\n"); + return; + } + + crtc_misr_info->misr_enable = false; + crtc_misr_info->misr_frame_count = 0; + + if (!crtc) { + SDE_ERROR("invalid crtc\n"); + return; + } + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return; + } + + if (sde_kms_is_secure_session_inprogress(sde_kms)) + return; + + sde_crtc = to_sde_crtc(crtc); + crtc_misr_info->misr_enable = + sde_crtc->misr_enable_debugfs ? true : false; + crtc_misr_info->misr_frame_count = sde_crtc->misr_frame_count; +} + +#ifdef CONFIG_DEBUG_FS +static int _sde_debugfs_status_show(struct seq_file *s, void *data) +{ + struct sde_crtc *sde_crtc; + struct sde_plane_state *pstate = NULL; + struct sde_crtc_mixer *m; + + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_display_mode *mode; + struct drm_framebuffer *fb; + struct drm_plane_state *state; + struct sde_crtc_state *cstate; + + int i, out_width, out_height; + + if (!s || !s->private) + return -EINVAL; + + sde_crtc = s->private; + crtc = &sde_crtc->base; + cstate = to_sde_crtc_state(crtc->state); + + mutex_lock(&sde_crtc->crtc_lock); + mode = &crtc->state->adjusted_mode; + out_width = sde_crtc_get_mixer_width(sde_crtc, cstate, mode); + out_height = sde_crtc_get_mixer_height(sde_crtc, cstate, mode); + + seq_printf(s, "crtc:%d width:%d height:%d\n", crtc->base.id, + mode->hdisplay, mode->vdisplay); + + seq_puts(s, "\n"); + + for (i = 0; i < sde_crtc->num_mixers; ++i) { + m = &sde_crtc->mixers[i]; + if (!m->hw_lm) + seq_printf(s, "\tmixer[%d] has no lm\n", i); + else if (!m->hw_ctl) + seq_printf(s, "\tmixer[%d] has no ctl\n", i); + else + seq_printf(s, "\tmixer:%d ctl:%d width:%d height:%d\n", + m->hw_lm->idx - LM_0, m->hw_ctl->idx - CTL_0, + out_width, out_height); + } + + seq_puts(s, "\n"); + + for (i = 0; i < cstate->num_dim_layers; i++) { + struct sde_hw_dim_layer *dim_layer = &cstate->dim_layer[i]; + + seq_printf(s, "\tdim_layer:%d] stage:%d flags:%d\n", + i, dim_layer->stage, dim_layer->flags); + seq_printf(s, "\tdst_x:%d dst_y:%d dst_w:%d dst_h:%d\n", + dim_layer->rect.x, dim_layer->rect.y, + dim_layer->rect.w, dim_layer->rect.h); + seq_printf(s, + "\tcolor_0:%d color_1:%d color_2:%d color_3:%d\n", + dim_layer->color_fill.color_0, + dim_layer->color_fill.color_1, + dim_layer->color_fill.color_2, + dim_layer->color_fill.color_3); + seq_puts(s, "\n"); + } + + drm_atomic_crtc_for_each_plane(plane, crtc) { + pstate = to_sde_plane_state(plane->state); + state = plane->state; + + if (!pstate || !state) + continue; + + seq_printf(s, "\tplane:%u stage:%d rotation:%d\n", + plane->base.id, pstate->stage, pstate->rotation); + + if (plane->state->fb) { + fb = plane->state->fb; + + seq_printf(s, "\tfb:%d image format:%4.4s wxh:%ux%u ", + fb->base.id, (char *) &fb->format->format, + fb->width, fb->height); + for (i = 0; i < ARRAY_SIZE(fb->format->cpp); ++i) + seq_printf(s, "cpp[%d]:%u ", + i, fb->format->cpp[i]); + seq_puts(s, "\n\t"); + + seq_printf(s, "modifier:%8llu ", fb->modifier); + seq_puts(s, "\n"); + + seq_puts(s, "\t"); + for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) + seq_printf(s, "pitches[%d]:%8u ", i, + fb->pitches[i]); + seq_puts(s, "\n"); + + seq_puts(s, "\t"); + for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) + seq_printf(s, "offsets[%d]:%8u ", i, + fb->offsets[i]); + seq_puts(s, "\n"); + } + + seq_printf(s, "\tsrc_x:%4d src_y:%4d src_w:%4d src_h:%4d\n", + state->src_x >> 16, state->src_y >> 16, + state->src_w >> 16, state->src_h >> 16); + + seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n", + state->crtc_x, state->crtc_y, state->crtc_w, + state->crtc_h); + seq_printf(s, "\tmultirect: mode: %d index: %d\n", + pstate->multirect_mode, pstate->multirect_index); + + seq_printf(s, "\texcl_rect: x:%4d y:%4d w:%4d h:%4d\n", + pstate->excl_rect.x, pstate->excl_rect.y, + pstate->excl_rect.w, pstate->excl_rect.h); + + seq_puts(s, "\n"); + } + + if (sde_crtc->vblank_cb_count) { + ktime_t diff = ktime_sub(ktime_get(), sde_crtc->vblank_cb_time); + u32 diff_ms = ktime_to_ms(diff); + u64 fps = diff_ms ? DIV_ROUND_CLOSEST( + sde_crtc->vblank_cb_count * 1000, diff_ms) : 0; + + seq_printf(s, + "vblank fps:%lld count:%u total:%llums total_framecount:%llu\n", + fps, sde_crtc->vblank_cb_count, + ktime_to_ms(diff), sde_crtc->play_count); + + /* reset time & count for next measurement */ + sde_crtc->vblank_cb_count = 0; + sde_crtc->vblank_cb_time = ktime_set(0, 0); + } + + mutex_unlock(&sde_crtc->crtc_lock); + + return 0; +} + +static int _sde_debugfs_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, _sde_debugfs_status_show, inode->i_private); +} + +static ssize_t _sde_crtc_misr_setup(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + int rc; + char buf[MISR_BUFF_SIZE + 1]; + u32 frame_count, enable; + size_t buff_copy; + struct sde_kms *sde_kms; + + if (!file || !file->private_data) + return -EINVAL; + + sde_crtc = file->private_data; + crtc = &sde_crtc->base; + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return -EINVAL; + } + + buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); + if (copy_from_user(buf, user_buf, buff_copy)) { + SDE_ERROR("buffer copy failed\n"); + return -EINVAL; + } + + buf[buff_copy] = 0; /* end of string */ + + if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) + return -EINVAL; + + if (sde_kms_is_secure_session_inprogress(sde_kms)) { + SDE_DEBUG("crtc:%d misr enable/disable not allowed\n", + DRMID(crtc)); + return -EINVAL; + } + + rc = pm_runtime_get_sync(crtc->dev->dev); + if (rc < 0) + return rc; + + sde_crtc->misr_enable_debugfs = enable; + sde_crtc_misr_setup(crtc, enable, frame_count); + pm_runtime_put_sync(crtc->dev->dev); + + return count; +} + +static ssize_t _sde_crtc_misr_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct drm_crtc *crtc; + struct sde_crtc *sde_crtc; + struct sde_kms *sde_kms; + struct sde_crtc_mixer *m; + int i = 0, rc; + ssize_t len = 0; + char buf[MISR_BUFF_SIZE + 1] = {'\0'}; + + if (*ppos) + return 0; + + if (!file || !file->private_data) + return -EINVAL; + + sde_crtc = file->private_data; + crtc = &sde_crtc->base; + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) + return -EINVAL; + + rc = pm_runtime_get_sync(crtc->dev->dev); + if (rc < 0) + return rc; + + if (sde_kms_is_secure_session_inprogress(sde_kms)) { + SDE_DEBUG("crtc:%d misr read not allowed\n", DRMID(crtc)); + goto end; + } + + if (!sde_crtc->misr_enable_debugfs) { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "disabled\n"); + goto buff_check; + } + + for (i = 0; i < sde_crtc->num_mixers; ++i) { + u32 misr_value = 0; + + m = &sde_crtc->mixers[i]; + if (!m->hw_lm || !m->hw_lm->ops.collect_misr) { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "invalid\n"); + SDE_ERROR("crtc:%d invalid misr ops\n", DRMID(crtc)); + continue; + } + + rc = m->hw_lm->ops.collect_misr(m->hw_lm, false, &misr_value); + if (rc) { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "invalid\n"); + SDE_ERROR("crtc:%d failed to collect misr %d\n", + DRMID(crtc), rc); + continue; + } else { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "lm idx:%d\n", m->hw_lm->idx - LM_0); + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "0x%x\n", misr_value); + } + } + +buff_check: + if (count <= len) { + len = 0; + goto end; + } + + if (copy_to_user(user_buff, buf, len)) { + len = -EFAULT; + goto end; + } + + *ppos += len; /* increase offset */ + +end: + pm_runtime_put_sync(crtc->dev->dev); + return len; +} + +#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix) \ +static int __prefix ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __prefix ## _show, inode->i_private); \ +} \ +static const struct file_operations __prefix ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __prefix ## _open, \ + .release = single_release, \ + .read = seq_read, \ + .llseek = seq_lseek, \ +} + +static int sde_crtc_debugfs_state_show(struct seq_file *s, void *v) +{ + struct drm_crtc *crtc = (struct drm_crtc *) s->private; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state); + int i; + + seq_printf(s, "num_connectors: %d\n", cstate->num_connectors); + seq_printf(s, "client type: %d\n", sde_crtc_get_client_type(crtc)); + seq_printf(s, "intf_mode: %d\n", sde_crtc_get_intf_mode(crtc, + crtc->state)); + seq_printf(s, "core_clk_rate: %llu\n", + sde_crtc->cur_perf.core_clk_rate); + for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC; + i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + seq_printf(s, "bw_ctl[%s]: %llu\n", + sde_power_handle_get_dbus_name(i), + sde_crtc->cur_perf.bw_ctl[i]); + seq_printf(s, "max_per_pipe_ib[%s]: %llu\n", + sde_power_handle_get_dbus_name(i), + sde_crtc->cur_perf.max_per_pipe_ib[i]); + } + + return 0; +} +DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_crtc_debugfs_state); + +static int _sde_debugfs_fence_status_show(struct seq_file *s, void *data) +{ + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_connector *conn; + struct drm_mode_object *drm_obj; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct sde_fence_context *ctx; + struct drm_connector_list_iter conn_iter; + struct drm_device *dev; + + if (!s || !s->private) + return -EINVAL; + + sde_crtc = s->private; + crtc = &sde_crtc->base; + dev = crtc->dev; + cstate = to_sde_crtc_state(crtc->state); + + /* Dump input fence info */ + seq_puts(s, "===Input fence===\n"); + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct sde_plane_state *pstate; + struct dma_fence *fence; + + pstate = to_sde_plane_state(plane->state); + if (!pstate) + continue; + + seq_printf(s, "plane:%u stage:%d\n", plane->base.id, + pstate->stage); + + fence = pstate->input_fence; + if (fence) + sde_fence_list_dump(fence, &s); + } + + /* Dump release fence info */ + seq_puts(s, "\n"); + seq_puts(s, "===Release fence===\n"); + ctx = sde_crtc->output_fence; + drm_obj = &crtc->base; + sde_debugfs_timeline_dump(ctx, drm_obj, &s); + seq_puts(s, "\n"); + + /* Dump retire fence info */ + seq_puts(s, "===Retire fence===\n"); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) + if (conn->state && conn->state->crtc == crtc && + cstate->num_connectors < MAX_CONNECTORS) { + struct sde_connector *c_conn; + + c_conn = to_sde_connector(conn); + ctx = c_conn->retire_fence; + drm_obj = &conn->base; + sde_debugfs_timeline_dump(ctx, drm_obj, &s); + } + drm_connector_list_iter_end(&conn_iter); + seq_puts(s, "\n"); + + return 0; +} + +static int _sde_debugfs_fence_status(struct inode *inode, struct file *file) +{ + return single_open(file, _sde_debugfs_fence_status_show, + inode->i_private); +} + +static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + struct sde_kms *sde_kms; + + static const struct file_operations debugfs_status_fops = { + .open = _sde_debugfs_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; + static const struct file_operations debugfs_misr_fops = { + .open = simple_open, + .read = _sde_crtc_misr_read, + .write = _sde_crtc_misr_setup, + }; + static const struct file_operations debugfs_fps_fops = { + .open = _sde_debugfs_fps_status, + .read = seq_read, + }; + static const struct file_operations debugfs_fence_fops = { + .open = _sde_debugfs_fence_status, + .read = seq_read, + }; + + if (!crtc) + return -EINVAL; + sde_crtc = to_sde_crtc(crtc); + + sde_kms = _sde_crtc_get_kms(crtc); + if (!sde_kms) + return -EINVAL; + + sde_crtc->debugfs_root = debugfs_create_dir(sde_crtc->name, + crtc->dev->primary->debugfs_root); + if (!sde_crtc->debugfs_root) + return -ENOMEM; + + /* don't error check these */ + debugfs_create_file("status", 0400, + sde_crtc->debugfs_root, + sde_crtc, &debugfs_status_fops); + debugfs_create_file("state", 0400, + sde_crtc->debugfs_root, + &sde_crtc->base, + &sde_crtc_debugfs_state_fops); + debugfs_create_file("misr_data", 0600, sde_crtc->debugfs_root, + sde_crtc, &debugfs_misr_fops); + debugfs_create_file("fps", 0400, sde_crtc->debugfs_root, + sde_crtc, &debugfs_fps_fops); + debugfs_create_file("fence_status", 0400, sde_crtc->debugfs_root, + sde_crtc, &debugfs_fence_fops); + + return 0; +} + +static void _sde_crtc_destroy_debugfs(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) + return; + sde_crtc = to_sde_crtc(crtc); + debugfs_remove_recursive(sde_crtc->debugfs_root); +} +#else +static int _sde_crtc_init_debugfs(struct drm_crtc *crtc) +{ + return 0; +} + +static void _sde_crtc_destroy_debugfs(struct drm_crtc *crtc) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +static int sde_crtc_late_register(struct drm_crtc *crtc) +{ + return _sde_crtc_init_debugfs(crtc); +} + +static void sde_crtc_early_unregister(struct drm_crtc *crtc) +{ + _sde_crtc_destroy_debugfs(crtc); +} + +static const struct drm_crtc_funcs sde_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .destroy = sde_crtc_destroy, + .page_flip = drm_atomic_helper_page_flip, + .atomic_set_property = sde_crtc_atomic_set_property, + .atomic_get_property = sde_crtc_atomic_get_property, + .reset = sde_crtc_reset, + .atomic_duplicate_state = sde_crtc_duplicate_state, + .atomic_destroy_state = sde_crtc_destroy_state, + .late_register = sde_crtc_late_register, + .early_unregister = sde_crtc_early_unregister, +}; + +static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = { + .mode_fixup = sde_crtc_mode_fixup, + .disable = sde_crtc_disable, + .atomic_enable = sde_crtc_enable, + .atomic_check = sde_crtc_atomic_check, + .atomic_begin = sde_crtc_atomic_begin, + .atomic_flush = sde_crtc_atomic_flush, +}; + +static void _sde_crtc_event_cb(struct kthread_work *work) +{ + struct sde_crtc_event *event; + struct sde_crtc *sde_crtc; + unsigned long irq_flags; + + if (!work) { + SDE_ERROR("invalid work item\n"); + return; + } + + event = container_of(work, struct sde_crtc_event, kt_work); + + /* set sde_crtc to NULL for static work structures */ + sde_crtc = event->sde_crtc; + if (!sde_crtc) + return; + + if (event->cb_func) + event->cb_func(&sde_crtc->base, event->usr); + + spin_lock_irqsave(&sde_crtc->event_lock, irq_flags); + list_add_tail(&event->list, &sde_crtc->event_free_list); + spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags); +} + +int sde_crtc_event_queue(struct drm_crtc *crtc, + void (*func)(struct drm_crtc *crtc, void *usr), + void *usr, bool color_processing_event) +{ + unsigned long irq_flags; + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv; + struct sde_crtc_event *event = NULL; + u32 crtc_id; + + if (!crtc || !crtc->dev || !crtc->dev->dev_private || !func) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + sde_crtc = to_sde_crtc(crtc); + priv = crtc->dev->dev_private; + crtc_id = drm_crtc_index(crtc); + + /* + * Obtain an event struct from the private cache. This event + * queue may be called from ISR contexts, so use a private + * cache to avoid calling any memory allocation functions. + */ + spin_lock_irqsave(&sde_crtc->event_lock, irq_flags); + if (!list_empty(&sde_crtc->event_free_list)) { + event = list_first_entry(&sde_crtc->event_free_list, + struct sde_crtc_event, list); + list_del_init(&event->list); + } + spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags); + + if (!event) + return -ENOMEM; + + /* populate event node */ + event->sde_crtc = sde_crtc; + event->cb_func = func; + event->usr = usr; + + /* queue new event request */ + kthread_init_work(&event->kt_work, _sde_crtc_event_cb); + if (color_processing_event) + kthread_queue_work(&priv->pp_event_worker, + &event->kt_work); + else + kthread_queue_work(&priv->event_thread[crtc_id].worker, + &event->kt_work); + + return 0; +} + +static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) +{ + int i, rc = 0; + + if (!sde_crtc) { + SDE_ERROR("invalid crtc\n"); + return -EINVAL; + } + + spin_lock_init(&sde_crtc->event_lock); + + INIT_LIST_HEAD(&sde_crtc->event_free_list); + for (i = 0; i < SDE_CRTC_MAX_EVENT_COUNT; ++i) + list_add_tail(&sde_crtc->event_cache[i].list, + &sde_crtc->event_free_list); + + return rc; +} + +/* + * __sde_crtc_idle_notify_work - signal idle timeout to user space + */ +static void __sde_crtc_idle_notify_work(struct kthread_work *work) +{ + struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc, + idle_notify_work.work); + struct drm_crtc *crtc; + struct drm_event event; + int ret = 0; + + if (!sde_crtc) { + SDE_ERROR("invalid sde crtc\n"); + } else { + crtc = &sde_crtc->base; + event.type = DRM_EVENT_IDLE_NOTIFY; + event.length = sizeof(u32); + msm_mode_object_event_notify(&crtc->base, crtc->dev, + &event, (u8 *)&ret); + + SDE_DEBUG("crtc[%d]: idle timeout notified\n", crtc->base.id); + } +} + +/* initialize crtc */ +struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) +{ + struct drm_crtc *crtc = NULL; + struct sde_crtc *sde_crtc = NULL; + struct msm_drm_private *priv = NULL; + struct sde_kms *kms = NULL; + int i, rc; + + priv = dev->dev_private; + kms = to_sde_kms(priv->kms); + + sde_crtc = kzalloc(sizeof(*sde_crtc), GFP_KERNEL); + if (!sde_crtc) + return ERR_PTR(-ENOMEM); + + crtc = &sde_crtc->base; + crtc->dev = dev; + + mutex_init(&sde_crtc->crtc_lock); + spin_lock_init(&sde_crtc->spin_lock); + atomic_set(&sde_crtc->frame_pending, 0); + mutex_init(&sde_crtc->vblank_modeset_ctrl_lock); + + sde_crtc->enabled = false; + + /* Below parameters are for fps calculation for sysfs node */ + sde_crtc->fps_info.fps_periodic_duration = DEFAULT_FPS_PERIOD_1_SEC; + sde_crtc->fps_info.time_buf = kmalloc_array(MAX_FRAME_COUNT, + sizeof(ktime_t), GFP_KERNEL); + + if (!sde_crtc->fps_info.time_buf) + SDE_ERROR("invalid buffer\n"); + else + memset(sde_crtc->fps_info.time_buf, 0, + sizeof(*(sde_crtc->fps_info.time_buf))); + + INIT_LIST_HEAD(&sde_crtc->frame_event_list); + INIT_LIST_HEAD(&sde_crtc->user_event_list); + for (i = 0; i < ARRAY_SIZE(sde_crtc->frame_events); i++) { + INIT_LIST_HEAD(&sde_crtc->frame_events[i].list); + list_add(&sde_crtc->frame_events[i].list, + &sde_crtc->frame_event_list); + kthread_init_work(&sde_crtc->frame_events[i].work, + sde_crtc_frame_event_work); + } + + drm_crtc_init_with_planes(dev, crtc, plane, NULL, &sde_crtc_funcs, + NULL); + + drm_crtc_helper_add(crtc, &sde_crtc_helper_funcs); + + /* save user friendly CRTC name for later */ + snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); + + /* initialize event handling */ + rc = _sde_crtc_init_events(sde_crtc); + if (rc) { + drm_crtc_cleanup(crtc); + kfree(sde_crtc); + return ERR_PTR(rc); + } + + /* initialize output fence support */ + sde_crtc->output_fence = sde_fence_init(sde_crtc->name, crtc->base.id); + + if (IS_ERR(sde_crtc->output_fence)) { + rc = PTR_ERR(sde_crtc->output_fence); + SDE_ERROR("failed to init fence, %d\n", rc); + drm_crtc_cleanup(crtc); + kfree(sde_crtc); + return ERR_PTR(rc); + } + + /* create CRTC properties */ + msm_property_init(&sde_crtc->property_info, &crtc->base, dev, + priv->crtc_property, sde_crtc->property_data, + CRTC_PROP_COUNT, CRTC_PROP_BLOBCOUNT, + sizeof(struct sde_crtc_state)); + + sde_crtc_install_properties(crtc, kms->catalog); + + if (dsi_panel_name == DSI_PANEL_SAMSUNG_AMSS644_VK04 || dsi_panel_name == DSI_PANEL_SAMSUNG_ANA6705) { + for (i = 0; i < 21; i++) + brightness_alpha_lut[i] = brightness_alpha_lut_1[i]; + } else { + for (i = 0; i < 21; i++) + brightness_alpha_lut[i] = brightness_alpha_lut_1[i]; + } + /* Install color processing properties */ + sde_cp_crtc_init(crtc); + sde_cp_crtc_install_properties(crtc); + + sde_crtc->cur_perf.llcc_active = false; + sde_crtc->new_perf.llcc_active = false; + + kthread_init_delayed_work(&sde_crtc->idle_notify_work, + __sde_crtc_idle_notify_work); + + SDE_DEBUG("crtc=%d new_llcc=%d, old_llcc=%d\n", + crtc->base.id, + sde_crtc->new_perf.llcc_active, + sde_crtc->cur_perf.llcc_active); + + SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name); + return crtc; +} + +int sde_crtc_post_init(struct drm_device *dev, struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + int rc = 0; + + if (!dev || !dev->primary || !dev->primary->kdev || !crtc) { + SDE_ERROR("invalid input param(s)\n"); + rc = -EINVAL; + goto end; + } + + sde_crtc = to_sde_crtc(crtc); + sde_crtc->sysfs_dev = device_create_with_groups( + dev->primary->kdev->class, dev->primary->kdev, 0, crtc, + sde_crtc_attr_groups, "sde-crtc-%d", crtc->index); + if (IS_ERR_OR_NULL(sde_crtc->sysfs_dev)) { + SDE_ERROR("crtc:%d sysfs create failed rc:%ld\n", crtc->index, + PTR_ERR(sde_crtc->sysfs_dev)); + if (!sde_crtc->sysfs_dev) + rc = -EINVAL; + else + rc = PTR_ERR(sde_crtc->sysfs_dev); + goto end; + } + + sde_crtc->vsync_event_sf = sysfs_get_dirent( + sde_crtc->sysfs_dev->kobj.sd, "vsync_event"); + if (!sde_crtc->vsync_event_sf) + SDE_ERROR("crtc:%d vsync_event sysfs create failed\n", + crtc->base.id); + +end: + return rc; +} + +static int _sde_crtc_event_enable(struct sde_kms *kms, + struct drm_crtc *crtc_drm, u32 event) +{ + struct sde_crtc *crtc = NULL; + struct sde_crtc_irq_info *node; + unsigned long flags; + bool found = false; + int ret, i = 0; + bool add_event = false; + + crtc = to_sde_crtc(crtc_drm); + spin_lock_irqsave(&crtc->spin_lock, flags); + list_for_each_entry(node, &crtc->user_event_list, list) { + if (node->event == event) { + found = true; + break; + } + } + spin_unlock_irqrestore(&crtc->spin_lock, flags); + + /* event already enabled */ + if (found) + return 0; + + node = NULL; + for (i = 0; i < ARRAY_SIZE(custom_events); i++) { + if (custom_events[i].event == event && + custom_events[i].func) { + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; + INIT_LIST_HEAD(&node->list); + INIT_LIST_HEAD(&node->irq.list); + node->func = custom_events[i].func; + node->event = event; + node->state = IRQ_NOINIT; + spin_lock_init(&node->state_lock); + break; + } + } + + if (!node) { + SDE_ERROR("unsupported event %x\n", event); + return -EINVAL; + } + + ret = 0; + if (crtc_drm->enabled) { + ret = pm_runtime_get_sync(crtc_drm->dev->dev); + if (ret < 0) { + SDE_EVT32(ret, SDE_EVTLOG_ERROR); + kfree(node); + return ret; + } + + INIT_LIST_HEAD(&node->irq.list); + + mutex_lock(&crtc->crtc_lock); + ret = node->func(crtc_drm, true, &node->irq); + if (!ret) { + spin_lock_irqsave(&crtc->spin_lock, flags); + list_add_tail(&node->list, &crtc->user_event_list); + add_event = true; + spin_unlock_irqrestore(&crtc->spin_lock, flags); + } + mutex_unlock(&crtc->crtc_lock); + + pm_runtime_put_sync(crtc_drm->dev->dev); + } + + if (add_event) + return 0; + + if (!ret) { + spin_lock_irqsave(&crtc->spin_lock, flags); + list_add_tail(&node->list, &crtc->user_event_list); + spin_unlock_irqrestore(&crtc->spin_lock, flags); + } else { + kfree(node); + } + + return ret; +} + +static int _sde_crtc_event_disable(struct sde_kms *kms, + struct drm_crtc *crtc_drm, u32 event) +{ + struct sde_crtc *crtc = NULL; + struct sde_crtc_irq_info *node = NULL; + unsigned long flags; + bool found = false; + int ret; + + crtc = to_sde_crtc(crtc_drm); + spin_lock_irqsave(&crtc->spin_lock, flags); + list_for_each_entry(node, &crtc->user_event_list, list) { + if (node->event == event) { + list_del_init(&node->list); + found = true; + break; + } + } + spin_unlock_irqrestore(&crtc->spin_lock, flags); + + /* event already disabled */ + if (!found) + return 0; + + /** + * crtc is disabled interrupts are cleared remove from the list, + * no need to disable/de-register. + */ + if (!crtc_drm->enabled) { + kfree(node); + return 0; + } + ret = pm_runtime_get_sync(crtc_drm->dev->dev); + if (ret < 0) { + SDE_ERROR("failed to enable power resource %d\n", ret); + SDE_EVT32(ret, SDE_EVTLOG_ERROR); + kfree(node); + return ret; + } + + ret = node->func(crtc_drm, false, &node->irq); + if (ret) { + spin_lock_irqsave(&crtc->spin_lock, flags); + list_add_tail(&node->list, &crtc->user_event_list); + spin_unlock_irqrestore(&crtc->spin_lock, flags); + } else { + kfree(node); + } + + pm_runtime_put_sync(crtc_drm->dev->dev); + return ret; +} + +int sde_crtc_register_custom_event(struct sde_kms *kms, + struct drm_crtc *crtc_drm, u32 event, bool en) +{ + struct sde_crtc *crtc = NULL; + int ret; + + crtc = to_sde_crtc(crtc_drm); + if (!crtc || !kms || !kms->dev) { + DRM_ERROR("invalid sde_crtc %pK kms %pK dev %pK\n", crtc, + kms, ((kms) ? (kms->dev) : NULL)); + return -EINVAL; + } + + if (en) + ret = _sde_crtc_event_enable(kms, crtc_drm, event); + else + ret = _sde_crtc_event_disable(kms, crtc_drm, event); + + return ret; +} + +static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm, + bool en, struct sde_irq_callback *irq) +{ + return 0; +} + +static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *noirq) +{ + /* + * IRQ object noirq is not being used here since there is + * no crtc irq from pm event. + */ + return 0; +} + +static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm, + bool en, struct sde_irq_callback *irq) +{ + return 0; +} + +/** + * sde_crtc_update_cont_splash_settings - update mixer settings + * and initial clk during device bootup for cont_splash use case + * @crtc: Pointer to drm crtc structure + */ +void sde_crtc_update_cont_splash_settings(struct drm_crtc *crtc) +{ + struct sde_kms *kms = NULL; + struct msm_drm_private *priv; + struct sde_crtc *sde_crtc; + u64 rate; + + if (!crtc || !crtc->state || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid crtc\n"); + return; + } + + priv = crtc->dev->dev_private; + kms = to_sde_kms(priv->kms); + if (!kms || !kms->catalog) { + SDE_ERROR("invalid parameters\n"); + return; + } + + _sde_crtc_setup_mixers(crtc); + crtc->enabled = true; + + /* update core clk value for initial state with cont-splash */ + sde_crtc = to_sde_crtc(crtc); + rate = sde_power_clk_get_rate(&priv->phandle, kms->perf.clk_name); + sde_crtc->cur_perf.core_clk_rate = (rate > 0) ? + rate : kms->perf.max_core_clk_rate; + sde_crtc->cur_perf.core_clk_rate = kms->perf.max_core_clk_rate; +} diff --git a/techpack/display/msm/sde/sde_crtc.h b/techpack/display/msm/sde/sde_crtc.h new file mode 100644 index 0000000000000000000000000000000000000000..fcc1cb24239c8c4e1ab4b41f3f1abe2ecea53540 --- /dev/null +++ b/techpack/display/msm/sde/sde_crtc.h @@ -0,0 +1,876 @@ +/* + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _SDE_CRTC_H_ +#define _SDE_CRTC_H_ + +#include <linux/kthread.h> +#include <linux/of_fdt.h> +#include <drm/drm_crtc.h> +#include "msm_prop.h" +#include "sde_fence.h" +#include "sde_kms.h" +#include "sde_core_perf.h" +#include "sde_hw_ds.h" + +#define SDE_CRTC_NAME_SIZE 12 +#define RGB_NUM_COMPONENTS 3 + +/* define the maximum number of in-flight frame events */ +/* Expand it to 2x for handling atleast 2 connectors safely */ +#define SDE_CRTC_FRAME_EVENT_SIZE (4 * 2) + +#define DSI_PANEL_SAMSUNG_ANA6705 0 +#define DSI_PANEL_SAMSUNG_AMSS644_VK04 1 +#define DSI_PANEL_SAMSUNG_SOFEF00_M 2 +extern char dsi_panel_name; +/** + * enum sde_crtc_client_type: crtc client type + * @RT_CLIENT: RealTime client like video/cmd mode display + * voting through apps rsc + * @NRT_CLIENT: Non-RealTime client like WB display + * voting through apps rsc + * @RT_RSC_CLIENT: Realtime display RSC voting client + */ +enum sde_crtc_client_type { + RT_CLIENT, + NRT_CLIENT, + RT_RSC_CLIENT, +}; + +/** + * enum sde_crtc_output_capture_point + * @MIXER_OUT : capture mixer output + * @DSPP_OUT : capture output of dspp + */ +enum sde_crtc_output_capture_point { + CAPTURE_MIXER_OUT, + CAPTURE_DSPP_OUT +}; + +/** + * enum sde_crtc_idle_pc_state: states of idle power collapse + * @IDLE_PC_NONE: no-op + * @IDLE_PC_ENABLE: enable idle power-collapse + * @IDLE_PC_DISABLE: disable idle power-collapse + */ +enum sde_crtc_idle_pc_state { + IDLE_PC_NONE, + IDLE_PC_ENABLE, + IDLE_PC_DISABLE, +}; + +/** + * @connectors : Currently associated drm connectors for retire event + * @num_connectors: Number of associated drm connectors for retire event + * @list: event list + */ +struct sde_crtc_retire_event { + struct drm_connector *connectors[MAX_CONNECTORS]; + int num_connectors; + struct list_head list; +}; + +/** + * struct sde_crtc_mixer: stores the map for each virtual pipeline in the CRTC + * @hw_lm: LM HW Driver context + * @hw_ctl: CTL Path HW driver context + * @hw_dspp: DSPP HW driver context + * @hw_ds: DS HW driver context + * @encoder: Encoder attached to this lm & ctl + * @mixer_op_mode: mixer blending operation mode + */ +struct sde_crtc_mixer { + struct sde_hw_mixer *hw_lm; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_dspp *hw_dspp; + struct sde_hw_ds *hw_ds; + struct drm_encoder *encoder; + u32 mixer_op_mode; +}; + +/** + * struct sde_crtc_frame_event_cb_data : info of drm objects of a frame event + * @crtc: pointer to drm crtc object registered for frame event + * @connector: pointer to drm connector which is source of frame event + */ +struct sde_crtc_frame_event_cb_data { + struct drm_crtc *crtc; + struct drm_connector *connector; +}; + +/** + * struct sde_crtc_frame_event: stores crtc frame event for crtc processing + * @work: base work structure + * @crtc: Pointer to crtc handling this event + * @connector: pointer to drm connector which is source of frame event + * @list: event list + * @ts: timestamp at queue entry + * @event: event identifier + */ +struct sde_crtc_frame_event { + struct kthread_work work; + struct drm_crtc *crtc; + struct drm_connector *connector; + struct list_head list; + ktime_t ts; + u32 event; +}; + +/** + * struct sde_crtc_event - event callback tracking structure + * @list: Linked list tracking node + * @kt_work: Kthread worker structure + * @sde_crtc: Pointer to associated sde_crtc structure + * @cb_func: Pointer to callback function + * @usr: Pointer to user data to be provided to the callback + */ +struct sde_crtc_event { + struct list_head list; + struct kthread_work kt_work; + void *sde_crtc; + + void (*cb_func)(struct drm_crtc *crtc, void *usr); + void *usr; +}; +/** + * struct sde_crtc_fps_info - structure for measuring fps periodicity + * @frame_count : Total frames during configured periodic duration + * @last_sampled_time_us: Stores the last ktime in microsecs when fps + * was calculated + * @measured_fps : Last measured fps value + * @fps_periodic_duration : Duration in milliseconds to measure the fps. + * Default value is 1 second. + * @time_buf : Buffer for storing ktime of the commits + * @next_time_index : index into time_buf for storing ktime for next commit + */ +struct sde_crtc_fps_info { + u32 frame_count; + ktime_t last_sampled_time_us; + u32 measured_fps; + u32 fps_periodic_duration; + ktime_t *time_buf; + u32 next_time_index; +}; + +/** + * struct sde_ltm_buffer - defines LTM buffer structure. + * @fb: frm framebuffer for the buffer + * @gem: drm gem handle for the buffer + * @asapce : pointer to address space + * @drm_fb_id: framebuffer id associated with this buffer + * @offset: offset for alignment + * @iova: device address + * @kva: kernel virtual address + * @node: list node for LTM buffer list; + */ +struct sde_ltm_buffer { + struct drm_framebuffer *fb; + struct drm_gem_object *gem; + struct msm_gem_address_space *aspace; + u32 drm_fb_id; + u32 offset; + u64 iova; + void *kva; + struct list_head node; +}; + +/** + * struct sde_crtc_misr_info - structure for misr information + * @misr_enable : enable/disable flag + * @misr_frame_count : Number of frames for misr calculation. + */ +struct sde_crtc_misr_info { + bool misr_enable; + u32 misr_frame_count; +}; + +/* + * Maximum number of free event structures to cache + */ +#define SDE_CRTC_MAX_EVENT_COUNT 16 + +/** + * struct sde_crtc - virtualized CRTC data structure + * @base : Base drm crtc structure + * @name : ASCII description of this crtc + * @num_ctls : Number of ctl paths in use + * @num_mixers : Number of mixers in use + * @mixers_swapped: Whether the mixers have been swapped for left/right update + * especially in the case of DSC Merge. + * @mixers : List of active mixers + * @event : Pointer to last received drm vblank event. If there is a + * pending vblank event, this will be non-null. + * @vsync_count : Running count of received vsync events + * @drm_requested_vblank : Whether vblanks have been enabled in the encoder + * @property_info : Opaque structure for generic property support + * @property_defaults : Array of default values for generic property support + * @output_fence : output release fence context + * @stage_cfg : H/w mixer stage configuration + * @debugfs_root : Parent of debugfs node + * @priv_handle : Pointer to external private handle, if present + * @vblank_cb_count : count of vblank callback since last reset + * @play_count : frame count between crtc enable and disable + * @vblank_cb_time : ktime at vblank count reset + * @vblank_last_cb_time : ktime at last vblank notification + * @sysfs_dev : sysfs device node for crtc + * @vsync_event_sf : vsync event notifier sysfs device + * @enabled : whether the SDE CRTC is currently enabled. updated in the + * commit-thread, not state-swap time which is earlier, so + * safe to make decisions on during VBLANK on/off work + * @ds_reconfig : force reconfiguration of the destination scaler block + * @feature_list : list of color processing features supported on a crtc + * @active_list : list of color processing features are active + * @dirty_list : list of color processing features are dirty + * @ad_dirty : list containing ad properties that are dirty + * @ad_active : list containing ad properties that are active + * @crtc_lock : crtc lock around create, destroy and access. + * @vblank_modeset_ctrl_lock : lock used for controlling vblank + during modeset + * @frame_pending : Whether or not an update is pending + * @frame_events : static allocation of in-flight frame events + * @frame_event_list : available frame event list + * @spin_lock : spin lock for frame event, transaction status, etc... + * @event_thread : Pointer to event handler thread + * @event_worker : Event worker queue + * @event_cache : Local cache of event worker structures + * @event_free_list : List of available event structures + * @event_lock : Spinlock around event handling code + * @misr_enable_sui : boolean entry indicates misr enable/disable status + * for secure cases. + * @misr_enable_debugfs : boolean entry indicates misr enable/disable status + * from debugfs. + * @misr_frame_count : misr frame count provided by client + * @misr_data : store misr data before turning off the clocks. + * @idle_notify_work: delayed worker to notify idle timeout to user space + * @power_event : registered power event handle + * @cur_perf : current performance committed to clock/bandwidth driver + * @plane_mask_old: keeps track of the planes used in the previous commit + * @frame_trigger_mode: frame trigger mode + * @ltm_buffer_cnt : number of ltm buffers + * @ltm_buffers : struct stores ltm buffer related data + * @ltm_buf_free : list of LTM buffers that are available + * @ltm_buf_busy : list of LTM buffers that are been used by HW + * @ltm_hist_en : flag to indicate whether LTM hist is enabled or not + * @ltm_buffer_lock : muttx to protect ltm_buffers allcation and free + * @ltm_lock : Spinlock to protect ltm buffer_cnt, hist_en and ltm lists + * @needs_hw_reset : Initiate a hw ctl reset + * @comp_ratio : Compression ratio + */ +struct sde_crtc { + struct drm_crtc base; + char name[SDE_CRTC_NAME_SIZE]; + + /* HW Resources reserved for the crtc */ + u32 num_ctls; + u32 num_mixers; + bool mixers_swapped; + struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS]; + + struct drm_pending_vblank_event *event; + u32 vsync_count; + + struct msm_property_info property_info; + struct msm_property_data property_data[CRTC_PROP_COUNT]; + struct drm_property_blob *blob_info; + + /* output fence support */ + struct sde_fence_context *output_fence; + + struct sde_hw_stage_cfg stage_cfg; + struct dentry *debugfs_root; + void *priv_handle; + + u32 vblank_cb_count; + u64 play_count; + ktime_t vblank_cb_time; + ktime_t vblank_last_cb_time; + struct sde_crtc_fps_info fps_info; + struct device *sysfs_dev; + struct kernfs_node *vsync_event_sf; + bool enabled; + + bool ds_reconfig; + struct list_head feature_list; + struct list_head active_list; + struct list_head dirty_list; + struct list_head ad_dirty; + struct list_head ad_active; + struct list_head user_event_list; + + struct mutex crtc_lock; + struct mutex crtc_cp_lock; + struct mutex vblank_modeset_ctrl_lock; + + atomic_t frame_pending; + struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; + struct list_head frame_event_list; + spinlock_t spin_lock; + + /* for handling internal event thread */ + struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT]; + struct list_head event_free_list; + spinlock_t event_lock; + bool misr_enable_sui; + bool misr_enable_debugfs; + u32 misr_frame_count; + struct kthread_delayed_work idle_notify_work; + + struct sde_power_event *power_event; + + struct sde_core_perf_params cur_perf; + struct sde_core_perf_params new_perf; + + u32 plane_mask_old; + + /* blob for histogram data */ + struct drm_property_blob *hist_blob; + enum frame_trigger_mode_type frame_trigger_mode; + + u32 ltm_buffer_cnt; + struct sde_ltm_buffer *ltm_buffers[LTM_BUFFER_SIZE]; + struct list_head ltm_buf_free; + struct list_head ltm_buf_busy; + bool ltm_hist_en; + struct drm_msm_ltm_cfg_param ltm_cfg; + struct mutex ltm_buffer_lock; + spinlock_t ltm_lock; + bool needs_hw_reset; + + int comp_ratio; +}; + +#define to_sde_crtc(x) container_of(x, struct sde_crtc, base) + +/** + * struct sde_crtc_state - sde container for atomic crtc state + * @base: Base drm crtc state structure + * @connectors : Currently associated drm connectors + * @num_connectors: Number of associated drm connectors + * @rsc_client : sde rsc client when mode is valid + * @is_ppsplit : Whether current topology requires PPSplit special handling + * @bw_control : true if bw/clk controlled by core bw/clk properties + * @bw_split_vote : true if bw controlled by llcc/dram bw properties + * @crtc_roi : Current CRTC ROI. Possibly sub-rectangle of mode. + * Origin top left of CRTC. + * @lm_bounds : LM boundaries based on current mode full resolution, no ROI. + * Origin top left of CRTC. + * @lm_roi : Current LM ROI, possibly sub-rectangle of mode. + * Origin top left of CRTC. + * @user_roi_list : List of user's requested ROIs as from set property + * @property_state: Local storage for msm_prop properties + * @property_values: Current crtc property values + * @input_fence_timeout_ns : Cached input fence timeout, in ns + * @num_dim_layers: Number of dim layers + * @dim_layer: Dim layer configs + * @num_ds: Number of destination scalers to be configured + * @num_ds_enabled: Number of destination scalers enabled + * @ds_dirty: Boolean to indicate if dirty or not + * @ds_cfg: Destination scaler config + * @scl3_lut_cfg: QSEED3 lut config + * @new_perf: new performance state being requested + */ +struct sde_crtc_state { + struct drm_crtc_state base; + + struct drm_connector *connectors[MAX_CONNECTORS]; + int num_connectors; + struct sde_rsc_client *rsc_client; + bool rsc_update; + bool bw_control; + bool bw_split_vote; + + bool is_ppsplit; + struct sde_rect crtc_roi; + struct sde_rect lm_bounds[CRTC_DUAL_MIXERS]; + struct sde_rect lm_roi[CRTC_DUAL_MIXERS]; + struct msm_roi_list user_roi_list; + + struct msm_property_state property_state; + struct msm_property_value property_values[CRTC_PROP_COUNT]; + uint64_t input_fence_timeout_ns; + uint32_t num_dim_layers; + struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS]; + uint32_t num_ds; + uint32_t num_ds_enabled; + bool ds_dirty; + struct sde_hw_ds_cfg ds_cfg[SDE_MAX_DS_COUNT]; + struct sde_hw_scaler3_lut_cfg scl3_lut_cfg; + + struct sde_core_perf_params new_perf; + bool fingerprint_mode; + bool fingerprint_pressed; + struct sde_hw_dim_layer *fingerprint_dim_layer; +}; + +enum sde_crtc_irq_state { + IRQ_NOINIT, + IRQ_ENABLED, + IRQ_DISABLING, + IRQ_DISABLED, +}; + +/** + * sde_crtc_irq_info - crtc interrupt info + * @irq: interrupt callback + * @event: event type of the interrupt + * @func: function pointer to enable/disable the interrupt + * @list: list of user customized event in crtc + * @state: state of the interrupt + * @state_lock: spin lock for interrupt state + */ +struct sde_crtc_irq_info { + struct sde_irq_callback irq; + u32 event; + int (*func)(struct drm_crtc *crtc, bool en, + struct sde_irq_callback *irq); + struct list_head list; + enum sde_crtc_irq_state state; + spinlock_t state_lock; +}; + +#define to_sde_crtc_state(x) \ + container_of(x, struct sde_crtc_state, base) + +/** + * sde_crtc_get_property - query integer value of crtc property + * @S: Pointer to crtc state + * @X: Property index, from enum msm_mdp_crtc_property + * Returns: Integer value of requested property + */ +#define sde_crtc_get_property(S, X) \ + ((S) && ((X) < CRTC_PROP_COUNT) ? ((S)->property_values[(X)].value) : 0) + +/** + * sde_crtc_get_mixer_width - get the mixer width + * Mixer width will be same as panel width(/2 for split) + * unless destination scaler feature is enabled + */ +static inline int sde_crtc_get_mixer_width(struct sde_crtc *sde_crtc, + struct sde_crtc_state *cstate, struct drm_display_mode *mode) +{ + u32 mixer_width; + + if (!sde_crtc || !cstate || !mode) + return 0; + + if (cstate->num_ds_enabled) + mixer_width = cstate->ds_cfg[0].lm_width; + else + mixer_width = (sde_crtc->num_mixers == CRTC_DUAL_MIXERS ? + mode->hdisplay / CRTC_DUAL_MIXERS : mode->hdisplay); + + return mixer_width; +} + +/** + * sde_crtc_get_mixer_height - get the mixer height + * Mixer height will be same as panel height unless + * destination scaler feature is enabled + */ +static inline int sde_crtc_get_mixer_height(struct sde_crtc *sde_crtc, + struct sde_crtc_state *cstate, struct drm_display_mode *mode) +{ + if (!sde_crtc || !cstate || !mode) + return 0; + + return (cstate->num_ds_enabled ? + cstate->ds_cfg[0].lm_height : mode->vdisplay); +} + +/** + * sde_crtc_frame_pending - retun the number of pending frames + * @crtc: Pointer to drm crtc object + */ +static inline int sde_crtc_frame_pending(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) + return -EINVAL; + + sde_crtc = to_sde_crtc(crtc); + return atomic_read(&sde_crtc->frame_pending); +} + +/** + * sde_crtc_set_needs_hw_reset - set hw reset flag, to handle reset during + * commit kickoff + * @crtc: Pointer to DRM crtc instance + */ +static inline void sde_crtc_set_needs_hw_reset(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) + return; + + sde_crtc = to_sde_crtc(crtc); + sde_crtc->needs_hw_reset = true; +} + +/** + * sde_crtc_reset_hw - attempt hardware reset on errors + * @crtc: Pointer to DRM crtc instance + * @old_state: Pointer to crtc state for previous commit + * @recovery_events: Whether or not recovery events are enabled + * Returns: Zero if current commit should still be attempted + */ +int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state, + bool recovery_events); + +/** + * sde_crtc_request_frame_reset - requests for next frame reset + * @crtc: Pointer to drm crtc object + */ +static inline int sde_crtc_request_frame_reset(struct drm_crtc *crtc) +{ + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + if (sde_crtc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) + sde_crtc_reset_hw(crtc, crtc->state, false); + + return 0; +} + +/** + * sde_crtc_vblank - enable or disable vblanks for this crtc + * @crtc: Pointer to drm crtc object + * @en: true to enable vblanks, false to disable + */ +int sde_crtc_vblank(struct drm_crtc *crtc, bool en); + +/** + * sde_crtc_commit_kickoff - trigger kickoff of the commit for this crtc + * @crtc: Pointer to drm crtc object + * @old_state: Pointer to drm crtc old state object + */ +void sde_crtc_commit_kickoff(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); + +/** + * sde_crtc_prepare_commit - callback to prepare for output fences + * @crtc: Pointer to drm crtc object + * @old_state: Pointer to drm crtc old state object + */ +void sde_crtc_prepare_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); + +/** + * sde_crtc_complete_commit - callback signalling completion of current commit + * @crtc: Pointer to drm crtc object + * @old_state: Pointer to drm crtc old state object + */ +void sde_crtc_complete_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_state); + +/** + * sde_crtc_init - create a new crtc object + * @dev: sde device + * @plane: base plane + * @Return: new crtc object or error + */ +struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane); + +/** + * sde_crtc_post_init - update crtc object with post initialization. It + * can update the debugfs, sysfs, entires. + * @dev: sde device + * @crtc: Pointer to drm crtc structure + */ +int sde_crtc_post_init(struct drm_device *dev, struct drm_crtc *crtc); + +/** + * sde_crtc_complete_flip - complete flip for clients + * @crtc: Pointer to drm crtc object + * @file: client to cancel's file handle + */ +void sde_crtc_complete_flip(struct drm_crtc *crtc, struct drm_file *file); + +/** + * sde_crtc_register_custom_event - api for enabling/disabling crtc event + * @kms: Pointer to sde_kms + * @crtc_drm: Pointer to crtc object + * @event: Event that client is interested + * @en: Flag to enable/disable the event + */ +int sde_crtc_register_custom_event(struct sde_kms *kms, + struct drm_crtc *crtc_drm, u32 event, bool en); + +/** + * sde_crtc_get_intf_mode - get interface mode of the given crtc + * @crtc: Pointert to DRM crtc + * @crtc: Pointert to DRM crtc_state + */ +enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc, + struct drm_crtc_state *cstate); + +/** + * sde_crtc_get_fps_mode - get frame rate of the given crtc + * @crtc: Pointert to crtc + */ +u32 sde_crtc_get_fps_mode(struct drm_crtc *crtc); + +/** + * sde_crtc_get_client_type - check the crtc type- rt, rsc_rt, etc. + * @crtc: Pointer to crtc + */ +static inline enum sde_crtc_client_type sde_crtc_get_client_type( + struct drm_crtc *crtc) +{ + struct sde_crtc_state *cstate = + crtc ? to_sde_crtc_state(crtc->state) : NULL; + + if (!cstate) + return RT_CLIENT; + + return cstate->rsc_client ? RT_RSC_CLIENT : RT_CLIENT; +} + +/** + * sde_crtc_is_rt_client - check if real-time client or not + * @crtc: Pointer to DRM crtc + * @crtc_state: Pointer to DRM crtc_state + */ +static inline bool sde_crtc_is_rt_client(struct drm_crtc *crtc, + struct drm_crtc_state *cstate) +{ + if (!crtc || !cstate) + return true; + + return (sde_crtc_get_intf_mode(crtc, cstate) != INTF_MODE_WB_LINE); +} + +/** + * sde_crtc_is_enabled - check if sde crtc is enabled or not + * @crtc: Pointer to crtc + */ +static inline bool sde_crtc_is_enabled(struct drm_crtc *crtc) +{ + return crtc ? crtc->enabled : false; +} + +/** + * sde_crtc_is_reset_required - validate the reset request based on the + * pm_suspend and crtc's active status. crtc's are left active + * on pm_suspend during LP1/LP2 states, as the display is still + * left ON. Avoid reset for the subsequent pm_resume in such cases. + * @crtc: Pointer to crtc + * return: false if in suspend state and crtc active, true otherwise + */ +static inline bool sde_crtc_is_reset_required(struct drm_crtc *crtc) +{ + /* + * reset is required even when there is no crtc_state as it is required + * to create the initial state object + */ + if (!crtc || !crtc->state) + return true; + + /* reset not required if crtc is active during suspend state */ + if (sde_kms_is_suspend_state(crtc->dev) && crtc->state->active) + return false; + + return true; +} + +/** + * sde_crtc_event_queue - request event callback + * @crtc: Pointer to drm crtc structure + * @func: Pointer to callback function + * @usr: Pointer to user data to be passed to callback + * @color_processing_event: True if color processing event + * Returns: Zero on success + */ +int sde_crtc_event_queue(struct drm_crtc *crtc, + void (*func)(struct drm_crtc *crtc, void *usr), + void *usr, bool color_processing_event); + +/** + * sde_crtc_get_crtc_roi - retrieve the crtc_roi from the given state object + * used to allow the planes to adjust their final lm out_xy value in the + * case of partial update + * @crtc_state: Pointer to crtc state + * @crtc_roi: Output pointer to crtc roi in the given state + */ +void sde_crtc_get_crtc_roi(struct drm_crtc_state *state, + const struct sde_rect **crtc_roi); + +/** + * sde_crtc_is_crtc_roi_dirty - retrieve whether crtc_roi was updated this frame + * Note: Only use during atomic_check since dirty properties may be popped + * @crtc_state: Pointer to crtc state + * Return: true if roi is dirty, false otherwise + */ +bool sde_crtc_is_crtc_roi_dirty(struct drm_crtc_state *state); + +/** sde_crt_get_secure_level - retrieve the secure level from the give state + * object, this is used to determine the secure state of the crtc + * @crtc : Pointer to drm crtc structure + * @usr: Pointer to drm crtc state + * return: secure_level + */ +static inline int sde_crtc_get_secure_level(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + if (!crtc || !state) + return -EINVAL; + + return sde_crtc_get_property(to_sde_crtc_state(state), + CRTC_PROP_SECURITY_LEVEL); +} + +/** sde_crtc_atomic_check_has_modeset - checks if the new_crtc_state in the + * drm_atomic_state has a modeset + * @state : pointer to drm_atomic_state + * @crtc : Pointer to drm crtc structure + * Returns true if crtc has modeset + */ +static inline bool sde_crtc_atomic_check_has_modeset( + struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *crtc_state; + + if (!state || !crtc) + return false; + + crtc_state = drm_atomic_get_new_crtc_state(state, + crtc); + return (crtc_state && drm_atomic_crtc_needs_modeset(crtc_state)); +} + +/** + * sde_crtc_get_secure_transition - determines the operations to be + * performed before transitioning to secure state + * This function should be called after swapping the new state + * @crtc: Pointer to drm crtc structure + * @old_crtc_state: Poniter to previous CRTC state + * Returns the bitmask of operations need to be performed, -Error in + * case of error cases + */ +int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state, + bool old_valid_fb); + +/** + * sde_crtc_find_plane_fb_modes - finds the modes of all planes attached + * to crtc + * @crtc: Pointer to DRM crtc object + * @fb_ns: number of non secure planes + * @fb_sec: number of secure-playback planes + * @fb_sec_dir: number of secure-ui/secure-camera planes + */ +int sde_crtc_find_plane_fb_modes(struct drm_crtc *crtc, + uint32_t *fb_ns, uint32_t *fb_sec, uint32_t *fb_sec_dir); + +/** + * sde_crtc_state_find_plane_fb_modes - finds the modes of all planes attached + * to the crtc state + * @crtc_state: Pointer to DRM crtc state object + * @fb_ns: number of non secure planes + * @fb_sec: number of secure-playback planes + * @fb_sec_dir: number of secure-ui/secure-camera planes + */ +int sde_crtc_state_find_plane_fb_modes(struct drm_crtc_state *state, + uint32_t *fb_ns, uint32_t *fb_sec, uint32_t *fb_sec_dir); + +/** + * sde_crtc_secure_ctrl - Initiates the transition between secure and + * non-secure world + * @crtc: Pointer to crtc + * @post_commit: if this operation is triggered after commit + */ +int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit); + +/** + * sde_crtc_helper_reset_properties - reset properties to default values in the + * given DRM CRTC state object + * @crtc: Pointer to DRM crtc object + * @crtc_state: Pointer to DRM crtc state object + * Returns: 0 on success, negative errno on failure + */ +int sde_crtc_helper_reset_custom_properties(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state); + +/** + * sde_crtc_timeline_status - current buffer timeline status + * @crtc: Pointer to crtc + */ +void sde_crtc_timeline_status(struct drm_crtc *crtc); + +/** + * sde_crtc_update_cont_splash_settings - update mixer settings + * during device bootup for cont_splash use case + * @crtc: Pointer to drm crtc structure + */ +void sde_crtc_update_cont_splash_settings( + struct drm_crtc *crtc); + +/** + * sde_crtc_misr_setup - to configure and enable/disable MISR + * @crtc: Pointer to drm crtc structure + * @enable: boolean to indicate enable/disable misr + * @frame_count: frame_count to be configured + */ +void sde_crtc_misr_setup(struct drm_crtc *crtc, bool enable, u32 frame_count); + +/** + * sde_crtc_get_misr_info - to configure and enable/disable MISR + * @crtc: Pointer to drm crtc structure + * @crtc_misr_info: Pointer to crtc misr info structure + */ +void sde_crtc_get_misr_info(struct drm_crtc *crtc, + struct sde_crtc_misr_info *crtc_misr_info); + +/** + * sde_crtc_get_num_datapath - get the number of datapath active + * of primary connector + * @crtc: Pointer to DRM crtc object + * @connector: Pointer to DRM connector object of WB in CWB case + */ +int sde_crtc_get_num_datapath(struct drm_crtc *crtc, + struct drm_connector *connector); + +/* + * sde_crtc_set_compression_ratio - set compression ratio src_bpp/target_bpp + * @msm_mode_info: Mode info + * @crtc: Pointer to drm crtc structure + */ +static inline void sde_crtc_set_compression_ratio( + struct msm_mode_info mode_info, struct drm_crtc *crtc) +{ + int target_bpp, src_bpp; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + /** + * In cases where DSC compression type is not found, set + * compression value to default value of 1. + */ + if (mode_info.comp_info.comp_type != MSM_DISPLAY_COMPRESSION_DSC) { + sde_crtc->comp_ratio = 1; + goto end; + } + + target_bpp = mode_info.comp_info.dsc_info.bpp; + src_bpp = mode_info.comp_info.dsc_info.bpc * RGB_NUM_COMPONENTS; + sde_crtc->comp_ratio = mult_frac(1, src_bpp, target_bpp); +end: + SDE_DEBUG("sde_crtc comp ratio: %d\n", sde_crtc->comp_ratio); +} + +#endif /* _SDE_CRTC_H_ */ diff --git a/techpack/display/msm/sde/sde_encoder.c b/techpack/display/msm/sde/sde_encoder.c new file mode 100644 index 0000000000000000000000000000000000000000..fa8caad024f48f95a897e67788743783580ef4a6 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder.c @@ -0,0 +1,6217 @@ +/* + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/kthread.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/sde_rsc.h> + +#include "msm_drv.h" +#include "sde_kms.h" +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_intf.h" +#include "sde_hw_ctl.h" +#include "sde_formats.h" +#include "sde_encoder_phys.h" +#include "sde_power_handle.h" +#include "sde_hw_dsc.h" +#include "sde_crtc.h" +#include "sde_trace.h" +#include "sde_core_irq.h" +#include "sde_hw_top.h" +#include "sde_hw_qdss.h" + +#define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\ + (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) + +#define SDE_ERROR_ENC(e, fmt, ...) SDE_ERROR("enc%d " fmt,\ + (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) + +#define SDE_DEBUG_PHYS(p, fmt, ...) SDE_DEBUG("enc%d intf%d pp%d " fmt,\ + (p) ? (p)->parent->base.id : -1, \ + (p) ? (p)->intf_idx - INTF_0 : -1, \ + (p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \ + ##__VA_ARGS__) + +#define SDE_ERROR_PHYS(p, fmt, ...) SDE_ERROR("enc%d intf%d pp%d " fmt,\ + (p) ? (p)->parent->base.id : -1, \ + (p) ? (p)->intf_idx - INTF_0 : -1, \ + (p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \ + ##__VA_ARGS__) + +/* + * Two to anticipate panels that can do cmd/vid dynamic switching + * plan is to create all possible physical encoder types, and switch between + * them at runtime + */ +#define NUM_PHYS_ENCODER_TYPES 2 + +#define MAX_PHYS_ENCODERS_PER_VIRTUAL \ + (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES) + +#define MISR_BUFF_SIZE 256 + +#define IDLE_SHORT_TIMEOUT 1 + +#define EVT_TIME_OUT_SPLIT 2 + +/* Maximum number of VSYNC wait attempts for RSC state transition */ +#define MAX_RSC_WAIT 5 + +#define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \ + (((x) == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) || \ + ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE) || \ + ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)) + +#define REQ_SEAMLESS_MODESET_LOCK(adj_mode, is_cmd_mode) \ + (msm_is_mode_seamless_dms(adj_mode) || \ + (msm_is_mode_seamless_dyn_clk(adj_mode) && \ + is_cmd_mode) || msm_is_mode_seamless_poms(adj_mode)) + +/** + * enum sde_enc_rc_events - events for resource control state machine + * @SDE_ENC_RC_EVENT_KICKOFF: + * This event happens at NORMAL priority. + * Event that signals the start of the transfer. When this event is + * received, enable MDP/DSI core clocks and request RSC with CMD state. + * Regardless of the previous state, the resource should be in ON state + * at the end of this event. + * @SDE_ENC_RC_EVENT_FRAME_DONE: + * This event happens at INTERRUPT level. + * Event signals the end of the data transfer after the PP FRAME_DONE + * event. At the end of this event, a delayed work is scheduled to go to + * IDLE_PC state after IDLE_POWERCOLLAPSE_DURATION time. + * @SDE_ENC_RC_EVENT_PRE_STOP: + * This event happens at NORMAL priority. + * This event, when received during the ON state, set RSC to IDLE, and + * and leave the RC STATE in the PRE_OFF state. + * It should be followed by the STOP event as part of encoder disable. + * If received during IDLE or OFF states, it will do nothing. + * @SDE_ENC_RC_EVENT_STOP: + * This event happens at NORMAL priority. + * When this event is received, disable all the MDP/DSI core clocks, and + * disable IRQs. It should be called from the PRE_OFF or IDLE states. + * IDLE is expected when IDLE_PC has run, and PRE_OFF did nothing. + * PRE_OFF is expected when PRE_STOP was executed during the ON state. + * Resource state should be in OFF at the end of the event. + * @SDE_ENC_RC_EVENT_PRE_MODESET: + * This event happens at NORMAL priority from a work item. + * Event signals that there is a seamless mode switch is in prgoress. A + * client needs to turn of only irq - leave clocks ON to reduce the mode + * switch latency. + * @SDE_ENC_RC_EVENT_POST_MODESET: + * This event happens at NORMAL priority from a work item. + * Event signals that seamless mode switch is complete and resources are + * acquired. Clients wants to turn on the irq again and update the rsc + * with new vtotal. + * @SDE_ENC_RC_EVENT_ENTER_IDLE: + * This event happens at NORMAL priority from a work item. + * Event signals that there were no frame updates for + * IDLE_POWERCOLLAPSE_DURATION time. This would disable MDP/DSI core clocks + * and request RSC with IDLE state and change the resource state to IDLE. + * @SDE_ENC_RC_EVENT_EARLY_WAKEUP: + * This event is triggered from the input event thread when touch event is + * received from the input device. On receiving this event, + * - If the device is in SDE_ENC_RC_STATE_IDLE state, it turns ON the + clocks and enable RSC. + * - If the device is in SDE_ENC_RC_STATE_ON state, it resets the delayed + * off work since a new commit is imminent. + */ +enum sde_enc_rc_events { + SDE_ENC_RC_EVENT_KICKOFF = 1, + SDE_ENC_RC_EVENT_FRAME_DONE, + SDE_ENC_RC_EVENT_PRE_STOP, + SDE_ENC_RC_EVENT_STOP, + SDE_ENC_RC_EVENT_PRE_MODESET, + SDE_ENC_RC_EVENT_POST_MODESET, + SDE_ENC_RC_EVENT_ENTER_IDLE, + SDE_ENC_RC_EVENT_EARLY_WAKEUP, +}; + +/* + * enum sde_enc_rc_states - states that the resource control maintains + * @SDE_ENC_RC_STATE_OFF: Resource is in OFF state + * @SDE_ENC_RC_STATE_PRE_OFF: Resource is transitioning to OFF state + * @SDE_ENC_RC_STATE_ON: Resource is in ON state + * @SDE_ENC_RC_STATE_MODESET: Resource is in modeset state + * @SDE_ENC_RC_STATE_IDLE: Resource is in IDLE state + */ +enum sde_enc_rc_states { + SDE_ENC_RC_STATE_OFF, + SDE_ENC_RC_STATE_PRE_OFF, + SDE_ENC_RC_STATE_ON, + SDE_ENC_RC_STATE_MODESET, + SDE_ENC_RC_STATE_IDLE +}; + +/** + * struct sde_encoder_virt - virtual encoder. Container of one or more physical + * encoders. Virtual encoder manages one "logical" display. Physical + * encoders manage one intf block, tied to a specific panel/sub-panel. + * Virtual encoder defers as much as possible to the physical encoders. + * Virtual encoder registers itself with the DRM Framework as the encoder. + * @base: drm_encoder base class for registration with DRM + * @enc_spin_lock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @bus_scaling_client: Client handle to the bus scaling interface + * @te_source: vsync source pin information + * @ops: Encoder ops from init function + * @num_phys_encs: Actual number of physical encoders contained. + * @phys_encs: Container of physical encoders managed. + * @phys_vid_encs: Video physical encoders for panel mode switch. + * @phys_cmd_encs: Command physical encoders for panel mode switch. + * @cur_master: Pointer to the current master in this mode. Optimization + * Only valid after enable. Cleared as disable. + * @hw_pp Handle to the pingpong blocks used for the display. No. + * pingpong blocks can be different than num_phys_encs. + * @hw_dsc: Array of DSC block handles used for the display. + * @dirty_dsc_ids: Cached dsc indexes for dirty DSC blocks needing flush + * @intfs_swapped Whether or not the phys_enc interfaces have been swapped + * for partial update right-only cases, such as pingpong + * split where virtual pingpong does not generate IRQs + @qdss_status: indicate if qdss is modified since last update + * @crtc_vblank_cb: Callback into the upper layer / CRTC for + * notification of the VBLANK + * @crtc_vblank_cb_data: Data from upper layer for VBLANK notification + * @crtc_kickoff_cb: Callback into CRTC that will flush & start + * all CTL paths + * @crtc_kickoff_cb_data: Opaque user data given to crtc_kickoff_cb + * @debugfs_root: Debug file system root file node + * @enc_lock: Lock around physical encoder create/destroy and + access. + * @frame_done_cnt: Atomic counter for tracking which phys_enc is + * done with frame processing. + * @crtc_frame_event_cb: callback handler for frame event + * @crtc_frame_event_cb_data: callback handler private data + * @vsync_event_timer: vsync timer + * @rsc_client: rsc client pointer + * @rsc_state_init: boolean to indicate rsc config init + * @disp_info: local copy of msm_display_info struct + * @misr_enable: misr enable/disable status + * @misr_frame_count: misr frame count before start capturing the data + * @idle_pc_enabled: indicate if idle power collapse is enabled + * currently. This can be controlled by user-mode + * @rc_lock: resource control mutex lock to protect + * virt encoder over various state changes + * @rc_state: resource controller state + * @delayed_off_work: delayed worker to schedule disabling of + * clks and resources after IDLE_TIMEOUT time. + * @vsync_event_work: worker to handle vsync event for autorefresh + * @input_event_work: worker to handle input device touch events + * @esd_trigger_work: worker to handle esd trigger events + * @input_handler: handler for input device events + * @topology: topology of the display + * @vblank_enabled: boolean to track userspace vblank vote + * @idle_pc_restore: flag to indicate idle_pc_restore happened + * @frame_trigger_mode: frame trigger mode indication for command + * mode display + * @dynamic_hdr_updated: flag to indicate if mempool was programmed + * @rsc_config: rsc configuration for display vtotal, fps, etc. + * @cur_conn_roi: current connector roi + * @prv_conn_roi: previous connector roi to optimize if unchanged + * @crtc pointer to drm_crtc + * @recovery_events_enabled: status of hw recovery feature enable by client + * @elevated_ahb_vote: increase AHB bus speed for the first frame + * after power collapse + * @pm_qos_cpu_req: pm_qos request for cpu frequency + * @mode_info: stores the current mode and should be used + * only in commit phase + */ +struct sde_encoder_virt { + struct drm_encoder base; + spinlock_t enc_spinlock; + struct mutex vblank_ctl_lock; + uint32_t bus_scaling_client; + + uint32_t display_num_of_h_tiles; + uint32_t te_source; + + struct sde_encoder_ops ops; + + unsigned int num_phys_encs; + struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; + struct sde_encoder_phys *phys_vid_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; + struct sde_encoder_phys *phys_cmd_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL]; + struct sde_encoder_phys *cur_master; + struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; + struct sde_hw_pingpong *hw_dsc_pp[MAX_CHANNELS_PER_ENC]; + enum sde_dsc dirty_dsc_ids[MAX_CHANNELS_PER_ENC]; + + bool intfs_swapped; + bool qdss_status; + + void (*crtc_vblank_cb)(void *data); + void *crtc_vblank_cb_data; + + struct dentry *debugfs_root; + struct mutex enc_lock; + atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL]; + void (*crtc_frame_event_cb)(void *data, u32 event); + struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data; + + struct timer_list vsync_event_timer; + + struct sde_rsc_client *rsc_client; + bool rsc_state_init; + struct msm_display_info disp_info; + bool misr_enable; + u32 misr_frame_count; + + bool idle_pc_enabled; + struct mutex rc_lock; + enum sde_enc_rc_states rc_state; + struct kthread_delayed_work delayed_off_work; + struct kthread_work vsync_event_work; + struct kthread_work input_event_work; + struct kthread_work esd_trigger_work; + struct input_handler *input_handler; + struct msm_display_topology topology; + bool vblank_enabled; + bool idle_pc_restore; + enum frame_trigger_mode_type frame_trigger_mode; + bool dynamic_hdr_updated; + + struct sde_rsc_cmd_config rsc_config; + struct sde_rect cur_conn_roi; + struct sde_rect prv_conn_roi; + struct drm_crtc *crtc; + + bool recovery_events_enabled; + bool elevated_ahb_vote; + struct pm_qos_request pm_qos_cpu_req; + struct msm_mode_info mode_info; +}; + +#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) + +void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + int i; + + sde_enc = to_sde_encoder_virt(drm_enc); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->hw_ctl && phys->hw_ctl->ops.uidle_enable) { + SDE_EVT32(DRMID(drm_enc), enable); + phys->hw_ctl->ops.uidle_enable(phys->hw_ctl, enable); + } + } +} + +static void _sde_encoder_pm_qos_add_request(struct drm_encoder *drm_enc, + struct sde_kms *sde_kms) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + struct pm_qos_request *req; + u32 cpu_mask; + u32 cpu_dma_latency; + int cpu; + + if (!sde_kms->catalog || !sde_kms->catalog->perf.cpu_mask) + return; + + cpu_mask = sde_kms->catalog->perf.cpu_mask; + cpu_dma_latency = sde_kms->catalog->perf.cpu_dma_latency; + + req = &sde_enc->pm_qos_cpu_req; + req->type = PM_QOS_REQ_AFFINE_CORES; + cpumask_empty(&req->cpus_affine); + for_each_possible_cpu(cpu) { + if ((1 << cpu) & cpu_mask) + cpumask_set_cpu(cpu, &req->cpus_affine); + } + pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY, cpu_dma_latency); + + SDE_EVT32_VERBOSE(DRMID(drm_enc), cpu_mask, cpu_dma_latency); +} + +static void _sde_encoder_pm_qos_remove_request(struct drm_encoder *drm_enc, + struct sde_kms *sde_kms) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + if (!sde_kms->catalog || !sde_kms->catalog->perf.cpu_mask) + return; + + pm_qos_remove_request(&sde_enc->pm_qos_cpu_req); +} + +static bool _sde_encoder_is_autorefresh_enabled( + struct sde_encoder_virt *sde_enc) +{ + struct drm_connector *drm_conn; + + if (!sde_enc->cur_master || + !(sde_enc->disp_info.capabilities & MSM_DISPLAY_CAP_CMD_MODE)) + return false; + + drm_conn = sde_enc->cur_master->connector; + + if (!drm_conn || !drm_conn->state) + return false; + + return sde_connector_get_property(drm_conn->state, + CONNECTOR_PROP_AUTOREFRESH) ? true : false; +} + +static bool _sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct msm_compression_info *comp_info; + + if (!drm_enc) + return false; + + sde_enc = to_sde_encoder_virt(drm_enc); + comp_info = &sde_enc->mode_info.comp_info; + + return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC); +} + +static void sde_configure_qdss(struct sde_encoder_virt *sde_enc, + struct sde_hw_qdss *hw_qdss, + struct sde_encoder_phys *phys, bool enable) +{ + if (sde_enc->qdss_status == enable) + return; + + sde_enc->qdss_status = enable; + + phys->hw_mdptop->ops.set_mdp_hw_events(phys->hw_mdptop, + sde_enc->qdss_status); + hw_qdss->ops.enable_qdss_events(hw_qdss, sde_enc->qdss_status); +} + +static int _sde_encoder_wait_timeout(int32_t drm_id, int32_t hw_id, + s64 timeout_ms, struct sde_encoder_wait_info *info) +{ + int rc = 0; + s64 wait_time_jiffies = msecs_to_jiffies(timeout_ms); + ktime_t cur_ktime; + ktime_t exp_ktime = ktime_add_ms(ktime_get(), timeout_ms); + + do { + rc = wait_event_timeout(*(info->wq), + atomic_read(info->atomic_cnt) == info->count_check, + wait_time_jiffies); + cur_ktime = ktime_get(); + + SDE_EVT32(drm_id, hw_id, rc, ktime_to_ms(cur_ktime), + timeout_ms, atomic_read(info->atomic_cnt), + info->count_check); + /* If we timed out, counter is valid and time is less, wait again */ + } while ((atomic_read(info->atomic_cnt) != info->count_check) && + (rc == 0) && + (ktime_compare_safe(exp_ktime, cur_ktime) > 0)); + + return rc; +} + +bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc) +{ + enum sde_rm_topology_name topology; + struct sde_encoder_virt *sde_enc; + struct drm_connector *drm_conn; + + if (!drm_enc) + return false; + + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc->cur_master) + return false; + + drm_conn = sde_enc->cur_master->connector; + if (!drm_conn) + return false; + + topology = sde_connector_get_topology_name(drm_conn); + if (topology == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) + return true; + + return false; +} + +bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + return sde_enc && + (sde_enc->disp_info.display_type == + SDE_CONNECTOR_PRIMARY); +} + +bool sde_encoder_is_dsi_display(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + return sde_enc && + (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI); +} + +int sde_encoder_in_cont_splash(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + return sde_enc && sde_enc->cur_master && + sde_enc->cur_master->cont_splash_enabled; +} + +void sde_encoder_helper_report_irq_timeout(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx) +{ + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->intf_idx - INTF_0, + phys_enc->hw_pp->idx - PINGPONG_0, + intr_idx); + SDE_ERROR_PHYS(phys_enc, "irq %d timeout\n", intr_idx); + + if (phys_enc->parent_ops.handle_frame_done) + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_ERROR); +} + +int sde_encoder_helper_wait_for_irq(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx, + struct sde_encoder_wait_info *wait_info) +{ + struct sde_encoder_irq *irq; + u32 irq_status; + int ret, i; + + if (!phys_enc || !wait_info || intr_idx >= INTR_IDX_MAX) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + irq = &phys_enc->irq[intr_idx]; + + /* note: do master / slave checking outside */ + + /* return EWOULDBLOCK since we know the wait isn't necessary */ + if (phys_enc->enable_state == SDE_ENC_DISABLED) { + SDE_ERROR_PHYS(phys_enc, "encoder is disabled\n"); + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, intr_idx, SDE_EVTLOG_ERROR); + return -EWOULDBLOCK; + } + + if (irq->irq_idx < 0) { + SDE_DEBUG_PHYS(phys_enc, "irq %s hw %d disabled, skip wait\n", + irq->name, irq->hw_idx); + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx); + return 0; + } + + SDE_DEBUG_PHYS(phys_enc, "pending_cnt %d\n", + atomic_read(wait_info->atomic_cnt)); + SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt), SDE_EVTLOG_FUNC_ENTRY); + + /* + * Some module X may disable interrupt for longer duration + * and it may trigger all interrupts including timer interrupt + * when module X again enable the interrupt. + * That may cause interrupt wait timeout API in this API. + * It is handled by split the wait timer in two halves. + */ + + for (i = 0; i < EVT_TIME_OUT_SPLIT; i++) { + ret = _sde_encoder_wait_timeout(DRMID(phys_enc->parent), + irq->hw_idx, + (wait_info->timeout_ms/EVT_TIME_OUT_SPLIT), + wait_info); + if (ret) + break; + } + + if (ret <= 0) { + irq_status = sde_core_irq_read(phys_enc->sde_kms, + irq->irq_idx, true); + if (irq_status) { + unsigned long flags; + + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, + irq->hw_idx, irq->irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + SDE_DEBUG_PHYS(phys_enc, + "done but irq %d not triggered\n", + irq->irq_idx); + local_irq_save(flags); + irq->cb.func(phys_enc, irq->irq_idx); + local_irq_restore(flags); + ret = 0; + } else { + ret = -ETIMEDOUT; + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, + irq->hw_idx, irq->irq_idx, + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt), irq_status, + SDE_EVTLOG_ERROR); + } + } else { + ret = 0; + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt)); + } + + SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, ret, phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt), SDE_EVTLOG_FUNC_EXIT); + + return ret; +} + +int sde_encoder_helper_register_irq(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx) +{ + struct sde_encoder_irq *irq; + int ret = 0; + + if (!phys_enc || intr_idx >= INTR_IDX_MAX) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + irq = &phys_enc->irq[intr_idx]; + + if (irq->irq_idx >= 0) { + SDE_DEBUG_PHYS(phys_enc, + "skipping already registered irq %s type %d\n", + irq->name, irq->intr_type); + return 0; + } + + irq->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms, + irq->intr_type, irq->hw_idx); + if (irq->irq_idx < 0) { + SDE_ERROR_PHYS(phys_enc, + "failed to lookup IRQ index for %s type:%d\n", + irq->name, irq->intr_type); + return -EINVAL; + } + + ret = sde_core_irq_register_callback(phys_enc->sde_kms, irq->irq_idx, + &irq->cb); + if (ret) { + SDE_ERROR_PHYS(phys_enc, + "failed to register IRQ callback for %s\n", + irq->name); + irq->irq_idx = -EINVAL; + return ret; + } + + ret = sde_core_irq_enable(phys_enc->sde_kms, &irq->irq_idx, 1); + if (ret) { + SDE_ERROR_PHYS(phys_enc, + "enable IRQ for intr:%s failed, irq_idx %d\n", + irq->name, irq->irq_idx); + + sde_core_irq_unregister_callback(phys_enc->sde_kms, + irq->irq_idx, &irq->cb); + + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, SDE_EVTLOG_ERROR); + irq->irq_idx = -EINVAL; + return ret; + } + + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, irq->irq_idx); + SDE_DEBUG_PHYS(phys_enc, "registered irq %s idx: %d\n", + irq->name, irq->irq_idx); + + return ret; +} + +int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx) +{ + struct sde_encoder_irq *irq; + int ret; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + irq = &phys_enc->irq[intr_idx]; + + /* silently skip irqs that weren't registered */ + if (irq->irq_idx < 0) { + SDE_ERROR( + "extra unregister irq, enc%d intr_idx:0x%x hw_idx:0x%x irq_idx:0x%x\n", + DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx); + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, SDE_EVTLOG_ERROR); + return 0; + } + + ret = sde_core_irq_disable(phys_enc->sde_kms, &irq->irq_idx, 1); + if (ret) + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, ret, SDE_EVTLOG_ERROR); + + ret = sde_core_irq_unregister_callback(phys_enc->sde_kms, irq->irq_idx, + &irq->cb); + if (ret) + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, + irq->irq_idx, ret, SDE_EVTLOG_ERROR); + + SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, irq->irq_idx); + SDE_DEBUG_PHYS(phys_enc, "unregistered %d\n", irq->irq_idx); + + irq->irq_idx = -EINVAL; + + return 0; +} + +void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc, + struct sde_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct sde_encoder_virt *sde_enc = NULL; + struct msm_mode_info mode_info; + int i = 0; + + if (!hw_res || !drm_enc || !conn_state) { + SDE_ERROR("invalid argument(s), drm_enc %d, res %d, state %d\n", + !drm_enc, !hw_res, !conn_state); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "\n"); + + /* Query resources used by phys encs, expected to be without overlap */ + memset(hw_res, 0, sizeof(*hw_res)); + hw_res->display_num_of_h_tiles = sde_enc->display_num_of_h_tiles; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.get_hw_resources) + phys->ops.get_hw_resources(phys, hw_res, conn_state); + } + + /* + * NOTE: Do not use sde_encoder_get_mode_info here as this function is + * called from atomic_check phase. Use the below API to get mode + * information of the temporary conn_state passed + */ + sde_connector_state_get_mode_info(conn_state, &mode_info); + hw_res->topology = mode_info.topology; + hw_res->display_type = sde_enc->disp_info.display_type; +} + +void sde_encoder_destroy(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + int i = 0; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "\n"); + + mutex_lock(&sde_enc->enc_lock); + sde_rsc_client_destroy(sde_enc->rsc_client); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys; + + phys = sde_enc->phys_vid_encs[i]; + if (phys && phys->ops.destroy) { + phys->ops.destroy(phys); + --sde_enc->num_phys_encs; + sde_enc->phys_encs[i] = NULL; + } + + phys = sde_enc->phys_cmd_encs[i]; + if (phys && phys->ops.destroy) { + phys->ops.destroy(phys); + --sde_enc->num_phys_encs; + sde_enc->phys_encs[i] = NULL; + } + } + + if (sde_enc->num_phys_encs) + SDE_ERROR_ENC(sde_enc, "expected 0 num_phys_encs not %d\n", + sde_enc->num_phys_encs); + sde_enc->num_phys_encs = 0; + mutex_unlock(&sde_enc->enc_lock); + + drm_encoder_cleanup(drm_enc); + mutex_destroy(&sde_enc->enc_lock); + + kfree(sde_enc->input_handler); + sde_enc->input_handler = NULL; + + kfree(sde_enc); +} + +void sde_encoder_helper_update_intf_cfg( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_hw_intf_cfg_v1 *intf_cfg; + enum sde_3d_blend_mode mode_3d; + + if (!phys_enc || !phys_enc->hw_pp) { + SDE_ERROR("invalid args, encoder %d\n", !phys_enc); + return; + } + + sde_enc = to_sde_encoder_virt(phys_enc->parent); + intf_cfg = &sde_enc->cur_master->intf_cfg_v1; + + SDE_DEBUG_ENC(sde_enc, + "intf_cfg updated for %d at idx %d\n", + phys_enc->intf_idx, + intf_cfg->intf_count); + + + /* setup interface configuration */ + if (intf_cfg->intf_count >= MAX_INTF_PER_CTL_V1) { + pr_err("invalid inf_count %d\n", intf_cfg->intf_count); + return; + } + intf_cfg->intf[intf_cfg->intf_count++] = phys_enc->intf_idx; + if (phys_enc == sde_enc->cur_master) { + if (sde_enc->cur_master->intf_mode == INTF_MODE_CMD) + intf_cfg->intf_mode_sel = SDE_CTL_MODE_SEL_CMD; + else + intf_cfg->intf_mode_sel = SDE_CTL_MODE_SEL_VID; + } + + /* configure this interface as master for split display */ + if (phys_enc->split_role == ENC_ROLE_MASTER) + intf_cfg->intf_master = phys_enc->hw_intf->idx; + + /* setup which pp blk will connect to this intf */ + if (phys_enc->hw_intf->ops.bind_pingpong_blk) + phys_enc->hw_intf->ops.bind_pingpong_blk( + phys_enc->hw_intf, + true, + phys_enc->hw_pp->idx); + + + /*setup merge_3d configuration */ + mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc); + + if (mode_3d && phys_enc->hw_pp->merge_3d && + intf_cfg->merge_3d_count < MAX_MERGE_3D_PER_CTL_V1) + intf_cfg->merge_3d[intf_cfg->merge_3d_count++] = + phys_enc->hw_pp->merge_3d->idx; + + if (phys_enc->hw_pp->ops.setup_3d_mode) + phys_enc->hw_pp->ops.setup_3d_mode(phys_enc->hw_pp, + mode_3d); +} + +void sde_encoder_helper_split_config( + struct sde_encoder_phys *phys_enc, + enum sde_intf interface) +{ + struct sde_encoder_virt *sde_enc; + struct split_pipe_cfg *cfg; + struct sde_hw_mdp *hw_mdptop; + enum sde_rm_topology_name topology; + struct msm_display_info *disp_info; + + if (!phys_enc || !phys_enc->hw_mdptop || !phys_enc->parent) { + SDE_ERROR("invalid arg(s), encoder %d\n", !phys_enc); + return; + } + + sde_enc = to_sde_encoder_virt(phys_enc->parent); + hw_mdptop = phys_enc->hw_mdptop; + disp_info = &sde_enc->disp_info; + cfg = &phys_enc->hw_intf->cfg; + memset(cfg, 0, sizeof(*cfg)); + + if (disp_info->intf_type != DRM_MODE_CONNECTOR_DSI) + return; + + if (disp_info->capabilities & MSM_DISPLAY_SPLIT_LINK) + cfg->split_link_en = true; + + /** + * disable split modes since encoder will be operating in as the only + * encoder, either for the entire use case in the case of, for example, + * single DSI, or for this frame in the case of left/right only partial + * update. + */ + if (phys_enc->split_role == ENC_ROLE_SOLO) { + if (hw_mdptop->ops.setup_split_pipe) + hw_mdptop->ops.setup_split_pipe(hw_mdptop, cfg); + if (hw_mdptop->ops.setup_pp_split) + hw_mdptop->ops.setup_pp_split(hw_mdptop, cfg); + return; + } + + cfg->en = true; + cfg->mode = phys_enc->intf_mode; + cfg->intf = interface; + + if (cfg->en && phys_enc->ops.needs_single_flush && + phys_enc->ops.needs_single_flush(phys_enc)) + cfg->split_flush_en = true; + + topology = sde_connector_get_topology_name(phys_enc->connector); + if (topology == SDE_RM_TOPOLOGY_PPSPLIT) + cfg->pp_split_slave = cfg->intf; + else + cfg->pp_split_slave = INTF_MAX; + + if (phys_enc->split_role == ENC_ROLE_MASTER) { + SDE_DEBUG_ENC(sde_enc, "enable %d\n", cfg->en); + + if (hw_mdptop->ops.setup_split_pipe) + hw_mdptop->ops.setup_split_pipe(hw_mdptop, cfg); + } else if (sde_enc->hw_pp[0]) { + /* + * slave encoder + * - determine split index from master index, + * assume master is first pp + */ + cfg->pp_split_index = sde_enc->hw_pp[0]->idx - PINGPONG_0; + SDE_DEBUG_ENC(sde_enc, "master using pp%d\n", + cfg->pp_split_index); + + if (hw_mdptop->ops.setup_pp_split) + hw_mdptop->ops.setup_pp_split(hw_mdptop, cfg); + } +} + +bool sde_encoder_in_clone_mode(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + int i = 0; + + if (!drm_enc) + return false; + + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc) + return false; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->in_clone_mode) + return true; + } + + return false; +} + +static int _sde_encoder_atomic_check_phys_enc(struct sde_encoder_virt *sde_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + const struct drm_display_mode *mode; + struct drm_display_mode *adj_mode; + int i = 0; + int ret = 0; + + mode = &crtc_state->mode; + adj_mode = &crtc_state->adjusted_mode; + + /* perform atomic check on the first physical encoder (master) */ + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.atomic_check) + ret = phys->ops.atomic_check(phys, crtc_state, + conn_state); + else if (phys && phys->ops.mode_fixup) + if (!phys->ops.mode_fixup(phys, mode, adj_mode)) + ret = -EINVAL; + + if (ret) { + SDE_ERROR_ENC(sde_enc, + "mode unsupported, phys idx %d\n", i); + break; + } + } + + return ret; +} + +static int _sde_encoder_atomic_check_pu_roi(struct sde_encoder_virt *sde_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct sde_connector_state *sde_conn_state, + struct sde_crtc_state *sde_crtc_state) +{ + int ret = 0; + + if (crtc_state->mode_changed || crtc_state->active_changed) { + struct sde_rect mode_roi, roi; + + mode_roi.x = 0; + mode_roi.y = 0; + mode_roi.w = crtc_state->adjusted_mode.hdisplay; + mode_roi.h = crtc_state->adjusted_mode.vdisplay; + + if (sde_conn_state->rois.num_rects) { + sde_kms_rect_merge_rectangles( + &sde_conn_state->rois, &roi); + if (!sde_kms_rect_is_equal(&mode_roi, &roi)) { + SDE_ERROR_ENC(sde_enc, + "roi (%d,%d,%d,%d) on connector invalid during modeset\n", + roi.x, roi.y, roi.w, roi.h); + ret = -EINVAL; + } + } + + if (sde_crtc_state->user_roi_list.num_rects) { + sde_kms_rect_merge_rectangles( + &sde_crtc_state->user_roi_list, &roi); + if (!sde_kms_rect_is_equal(&mode_roi, &roi)) { + SDE_ERROR_ENC(sde_enc, + "roi (%d,%d,%d,%d) on crtc invalid during modeset\n", + roi.x, roi.y, roi.w, roi.h); + ret = -EINVAL; + } + } + } + + return ret; +} + +static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct sde_encoder_virt *sde_enc, struct sde_kms *sde_kms, + struct sde_connector *sde_conn, + struct sde_connector_state *sde_conn_state) +{ + int ret = 0; + struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode; + + if (sde_conn && drm_atomic_crtc_needs_modeset(crtc_state)) { + struct msm_display_topology *topology = NULL; + + ret = sde_connector_get_mode_info(&sde_conn->base, + adj_mode, &sde_conn_state->mode_info); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "failed to get mode info, rc = %d\n", ret); + return ret; + } + + if (sde_conn_state->mode_info.comp_info.comp_type && + sde_conn_state->mode_info.comp_info.comp_ratio >= + MSM_DISPLAY_COMPRESSION_RATIO_MAX) { + SDE_ERROR_ENC(sde_enc, + "invalid compression ratio: %d\n", + sde_conn_state->mode_info.comp_info.comp_ratio); + ret = -EINVAL; + return ret; + } + + /* Reserve dynamic resources, indicating atomic_check phase */ + ret = sde_rm_reserve(&sde_kms->rm, drm_enc, crtc_state, + conn_state, true); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "RM failed to reserve resources, rc = %d\n", + ret); + return ret; + } + + /** + * Update connector state with the topology selected for the + * resource set validated. Reset the topology if we are + * de-activating crtc. + */ + if (crtc_state->active) + topology = &sde_conn_state->mode_info.topology; + + ret = sde_rm_update_topology(conn_state, topology); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "RM failed to update topology, rc: %d\n", ret); + return ret; + } + + ret = sde_connector_set_blob_data(conn_state->connector, + conn_state, + CONNECTOR_PROP_SDE_INFO); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "connector failed to update info, rc: %d\n", + ret); + return ret; + } + } + + return ret; +} + +static int sde_encoder_virt_atomic_check( + struct drm_encoder *drm_enc, struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + const struct drm_display_mode *mode; + struct drm_display_mode *adj_mode; + struct sde_connector *sde_conn = NULL; + struct sde_connector_state *sde_conn_state = NULL; + struct sde_crtc_state *sde_crtc_state = NULL; + enum sde_rm_topology_name old_top; + int ret = 0; + + if (!drm_enc || !crtc_state || !conn_state) { + SDE_ERROR("invalid arg(s), drm_enc %d, crtc/conn state %d/%d\n", + !drm_enc, !crtc_state, !conn_state); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "\n"); + + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + mode = &crtc_state->mode; + adj_mode = &crtc_state->adjusted_mode; + sde_conn = to_sde_connector(conn_state->connector); + sde_conn_state = to_sde_connector_state(conn_state); + sde_crtc_state = to_sde_crtc_state(crtc_state); + + SDE_EVT32(DRMID(drm_enc), crtc_state->mode_changed, + crtc_state->active_changed, crtc_state->connectors_changed); + + ret = _sde_encoder_atomic_check_phys_enc(sde_enc, crtc_state, + conn_state); + if (ret) + return ret; + + ret = _sde_encoder_atomic_check_pu_roi(sde_enc, crtc_state, + conn_state, sde_conn_state, sde_crtc_state); + if (ret) + return ret; + + /** + * record topology in previous atomic state to be able to handle + * topology transitions correctly. + */ + old_top = sde_connector_get_property(conn_state, + CONNECTOR_PROP_TOPOLOGY_NAME); + ret = sde_connector_set_old_topology_name(conn_state, old_top); + if (ret) + return ret; + + ret = _sde_encoder_atomic_check_reserve(drm_enc, crtc_state, + conn_state, sde_enc, sde_kms, sde_conn, sde_conn_state); + if (ret) + return ret; + + ret = sde_connector_roi_v1_check_roi(conn_state); + if (ret) { + SDE_ERROR_ENC(sde_enc, "connector roi check failed, rc: %d", + ret); + return ret; + } + + drm_mode_set_crtcinfo(adj_mode, 0); + SDE_EVT32(DRMID(drm_enc), adj_mode->flags, adj_mode->private_flags); + + return ret; +} + +static int _sde_encoder_dsc_update_pic_dim(struct msm_display_dsc_info *dsc, + int pic_width, int pic_height) +{ + if (!dsc || !pic_width || !pic_height) { + SDE_ERROR("invalid input: pic_width=%d pic_height=%d\n", + pic_width, pic_height); + return -EINVAL; + } + + if ((pic_width % dsc->slice_width) || + (pic_height % dsc->slice_height)) { + SDE_ERROR("pic_dim=%dx%d has to be multiple of slice=%dx%d\n", + pic_width, pic_height, + dsc->slice_width, dsc->slice_height); + return -EINVAL; + } + + dsc->pic_width = pic_width; + dsc->pic_height = pic_height; + + return 0; +} + +static void _sde_encoder_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, + int intf_width) +{ + int slice_per_pkt, slice_per_intf; + int bytes_in_slice, total_bytes_per_intf; + + if (!dsc || !dsc->slice_width || !dsc->slice_per_pkt || + (intf_width < dsc->slice_width)) { + SDE_ERROR("invalid input: intf_width=%d slice_width=%d\n", + intf_width, dsc ? dsc->slice_width : -1); + return; + } + + slice_per_pkt = dsc->slice_per_pkt; + slice_per_intf = DIV_ROUND_UP(intf_width, dsc->slice_width); + + /* + * If slice_per_pkt is greater than slice_per_intf then default to 1. + * This can happen during partial update. + */ + if (slice_per_pkt > slice_per_intf) + slice_per_pkt = 1; + + bytes_in_slice = DIV_ROUND_UP(dsc->slice_width * dsc->bpp, 8); + total_bytes_per_intf = bytes_in_slice * slice_per_intf; + + dsc->eol_byte_num = total_bytes_per_intf % 3; + dsc->pclk_per_line = DIV_ROUND_UP(total_bytes_per_intf, 3); + dsc->bytes_in_slice = bytes_in_slice; + dsc->bytes_per_pkt = bytes_in_slice * slice_per_pkt; + dsc->pkt_per_line = slice_per_intf / slice_per_pkt; +} + +static int _sde_encoder_dsc_initial_line_calc(struct msm_display_dsc_info *dsc, + int enc_ip_width) +{ + int max_ssm_delay, max_se_size, obuf_latency; + int input_ssm_out_latency, base_hs_latency; + int multi_hs_extra_latency, mux_word_size; + + /* Hardent core config */ + int max_muxword_size = 48; + int output_rate = 64; + int rtl_max_bpc = 10; + int pipeline_latency = 28; + + max_se_size = 4 * (rtl_max_bpc + 1); + max_ssm_delay = max_se_size + max_muxword_size - 1; + mux_word_size = (dsc->bpc >= 12 ? 64 : 48); + input_ssm_out_latency = pipeline_latency + (3 * (max_ssm_delay + 2)); + obuf_latency = DIV_ROUND_UP((9 * output_rate + + mux_word_size), dsc->bpp) + 1; + base_hs_latency = dsc->initial_xmit_delay + input_ssm_out_latency + + obuf_latency; + multi_hs_extra_latency = DIV_ROUND_UP((8 * dsc->chunk_size), dsc->bpp); + dsc->initial_lines = DIV_ROUND_UP((base_hs_latency + + multi_hs_extra_latency), dsc->slice_width); + + return 0; +} + +static bool _sde_encoder_dsc_ich_reset_override_needed(bool pu_en, + struct msm_display_dsc_info *dsc) +{ + /* + * As per the DSC spec, ICH_RESET can be either end of the slice line + * or at the end of the slice. HW internally generates ich_reset at + * end of the slice line if DSC_MERGE is used or encoder has two + * soft slices. However, if encoder has only 1 soft slice and DSC_MERGE + * is not used then it will generate ich_reset at the end of slice. + * + * Now as per the spec, during one PPS session, position where + * ich_reset is generated should not change. Now if full-screen frame + * has more than 1 soft slice then HW will automatically generate + * ich_reset at the end of slice_line. But for the same panel, if + * partial frame is enabled and only 1 encoder is used with 1 slice, + * then HW will generate ich_reset at end of the slice. This is a + * mismatch. Prevent this by overriding HW's decision. + */ + return pu_en && dsc && (dsc->full_frame_slices > 1) && + (dsc->slice_width == dsc->pic_width); +} + +static void _sde_encoder_dsc_pipe_cfg(struct sde_hw_dsc *hw_dsc, + struct sde_hw_pingpong *hw_pp, struct msm_display_dsc_info *dsc, + u32 common_mode, bool ich_reset, bool enable, + struct sde_hw_pingpong *hw_dsc_pp, + bool half_panel_partial_update) +{ + if (!enable) { + /* + * avoid disabling dsc encoder in pp-block as it is + * not double-buffered and is not required to be disabled + * for half panel updates + */ + if (hw_dsc_pp && hw_dsc_pp->ops.disable_dsc + && !half_panel_partial_update) + hw_dsc_pp->ops.disable_dsc(hw_dsc_pp); + + if (hw_dsc && hw_dsc->ops.dsc_disable) + hw_dsc->ops.dsc_disable(hw_dsc); + + if (hw_dsc && hw_dsc->ops.bind_pingpong_blk) + hw_dsc->ops.bind_pingpong_blk(hw_dsc, false, + PINGPONG_MAX); + return; + } + + if (!dsc || !hw_dsc || !hw_pp || !hw_dsc_pp) { + SDE_ERROR("invalid params %d %d %d %d\n", !dsc, !hw_dsc, + !hw_pp, !hw_dsc_pp); + return; + } + + if (hw_dsc->ops.dsc_config) + hw_dsc->ops.dsc_config(hw_dsc, dsc, common_mode, ich_reset); + + if (hw_dsc->ops.dsc_config_thresh) + hw_dsc->ops.dsc_config_thresh(hw_dsc, dsc); + + if (hw_dsc_pp->ops.setup_dsc) + hw_dsc_pp->ops.setup_dsc(hw_dsc_pp); + + if (hw_dsc->ops.bind_pingpong_blk) + hw_dsc->ops.bind_pingpong_blk(hw_dsc, true, hw_pp->idx); + + if (hw_dsc_pp->ops.enable_dsc) + hw_dsc_pp->ops.enable_dsc(hw_dsc_pp); +} + +static void _sde_encoder_get_connector_roi( + struct sde_encoder_virt *sde_enc, + struct sde_rect *merged_conn_roi) +{ + struct drm_connector *drm_conn; + struct sde_connector_state *c_state; + + if (!sde_enc || !merged_conn_roi) + return; + + drm_conn = sde_enc->phys_encs[0]->connector; + + if (!drm_conn || !drm_conn->state) + return; + + c_state = to_sde_connector_state(drm_conn->state); + sde_kms_rect_merge_rectangles(&c_state->rois, merged_conn_roi); +} + +static int _sde_encoder_dsc_n_lm_1_enc_1_intf(struct sde_encoder_virt *sde_enc) +{ + int this_frame_slices; + int intf_ip_w, enc_ip_w; + int ich_res, dsc_common_mode = 0; + + struct sde_hw_pingpong *hw_pp = sde_enc->hw_pp[0]; + struct sde_hw_pingpong *hw_dsc_pp = sde_enc->hw_dsc_pp[0]; + struct sde_hw_dsc *hw_dsc = sde_enc->hw_dsc[0]; + struct sde_encoder_phys *enc_master = sde_enc->cur_master; + const struct sde_rect *roi = &sde_enc->cur_conn_roi; + struct msm_display_dsc_info *dsc = NULL; + struct sde_hw_ctl *hw_ctl; + struct sde_ctl_dsc_cfg cfg; + + if (hw_dsc == NULL || hw_pp == NULL || !enc_master) { + SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n"); + return -EINVAL; + } + + hw_ctl = enc_master->hw_ctl; + + memset(&cfg, 0, sizeof(cfg)); + dsc = &sde_enc->mode_info.comp_info.dsc_info; + _sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h); + + this_frame_slices = roi->w / dsc->slice_width; + intf_ip_w = this_frame_slices * dsc->slice_width; + _sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w); + + enc_ip_w = intf_ip_w; + _sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w); + + ich_res = _sde_encoder_dsc_ich_reset_override_needed(false, dsc); + + if (enc_master->intf_mode == INTF_MODE_VIDEO) + dsc_common_mode = DSC_MODE_VIDEO; + + SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n", + roi->w, roi->h, dsc_common_mode); + SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, dsc_common_mode); + + _sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, dsc, dsc_common_mode, + ich_res, true, hw_dsc_pp, false); + cfg.dsc[cfg.dsc_count++] = hw_dsc->idx; + + /* setup dsc active configuration in the control path */ + if (hw_ctl->ops.setup_dsc_cfg) { + hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg); + SDE_DEBUG_ENC(sde_enc, + "setup dsc_cfg hw_ctl[%d], count:%d,dsc[0]:%d, dsc[1]:%d\n", + hw_ctl->idx, + cfg.dsc_count, + cfg.dsc[0], + cfg.dsc[1]); + } + + if (hw_ctl->ops.update_bitmask_dsc) + hw_ctl->ops.update_bitmask_dsc(hw_ctl, hw_dsc->idx, 1); + + return 0; +} + +static int _sde_encoder_dsc_2_lm_2_enc_2_intf(struct sde_encoder_virt *sde_enc, + struct sde_encoder_kickoff_params *params) +{ + int this_frame_slices; + int intf_ip_w, enc_ip_w; + int ich_res, dsc_common_mode; + + struct sde_encoder_phys *enc_master = sde_enc->cur_master; + const struct sde_rect *roi = &sde_enc->cur_conn_roi; + struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; + struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct sde_hw_pingpong *hw_dsc_pp[MAX_CHANNELS_PER_ENC]; + struct msm_display_dsc_info dsc[MAX_CHANNELS_PER_ENC]; + bool half_panel_partial_update; + struct sde_hw_ctl *hw_ctl = NULL; + struct sde_ctl_dsc_cfg cfg; + int i; + + if (!enc_master) { + SDE_ERROR_ENC(sde_enc, "invalid encoder master for DSC\n"); + return -EINVAL; + } + + memset(&cfg, 0, sizeof(cfg)); + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + hw_pp[i] = sde_enc->hw_pp[i]; + hw_dsc[i] = sde_enc->hw_dsc[i]; + hw_dsc_pp[i] = sde_enc->hw_dsc_pp[i]; + + if (!hw_pp[i] || !hw_dsc[i] || !hw_dsc_pp[i]) { + SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n"); + return -EINVAL; + } + } + + hw_ctl = enc_master->hw_ctl; + + half_panel_partial_update = + hweight_long(params->affected_displays) == 1; + + dsc_common_mode = 0; + if (!half_panel_partial_update) + dsc_common_mode |= DSC_MODE_SPLIT_PANEL; + if (enc_master->intf_mode == INTF_MODE_VIDEO) + dsc_common_mode |= DSC_MODE_VIDEO; + + memcpy(&dsc[0], &sde_enc->mode_info.comp_info.dsc_info, sizeof(dsc[0])); + memcpy(&dsc[1], &sde_enc->mode_info.comp_info.dsc_info, sizeof(dsc[1])); + + /* + * Since both DSC use same pic dimension, set same pic dimension + * to both DSC structures. + */ + _sde_encoder_dsc_update_pic_dim(&dsc[0], roi->w, roi->h); + _sde_encoder_dsc_update_pic_dim(&dsc[1], roi->w, roi->h); + + this_frame_slices = roi->w / dsc[0].slice_width; + intf_ip_w = this_frame_slices * dsc[0].slice_width; + + if (!half_panel_partial_update) + intf_ip_w /= 2; + + /* + * In this topology when both interfaces are active, they have same + * load so intf_ip_w will be same. + */ + _sde_encoder_dsc_pclk_param_calc(&dsc[0], intf_ip_w); + _sde_encoder_dsc_pclk_param_calc(&dsc[1], intf_ip_w); + + /* + * In this topology, since there is no dsc_merge, uncompressed input + * to encoder and interface is same. + */ + enc_ip_w = intf_ip_w; + _sde_encoder_dsc_initial_line_calc(&dsc[0], enc_ip_w); + _sde_encoder_dsc_initial_line_calc(&dsc[1], enc_ip_w); + + /* + * __is_ich_reset_override_needed should be called only after + * updating pic dimension, mdss_panel_dsc_update_pic_dim. + */ + ich_res = _sde_encoder_dsc_ich_reset_override_needed( + half_panel_partial_update, &dsc[0]); + + SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n", + roi->w, roi->h, dsc_common_mode); + + for (i = 0; i < sde_enc->num_phys_encs && + i < MAX_CHANNELS_PER_ENC; i++) { + bool active = !!((1 << i) & params->affected_displays); + + SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, + dsc_common_mode, i, active); + _sde_encoder_dsc_pipe_cfg(hw_dsc[i], hw_pp[i], &dsc[i], + dsc_common_mode, ich_res, active, + hw_dsc_pp[i], false); + + if (active) { + if (cfg.dsc_count >= MAX_DSC_PER_CTL_V1) { + pr_err("Invalid dsc count:%d\n", + cfg.dsc_count); + return -EINVAL; + } + cfg.dsc[cfg.dsc_count++] = hw_dsc[i]->idx; + + if (hw_ctl->ops.update_bitmask_dsc) + hw_ctl->ops.update_bitmask_dsc(hw_ctl, + hw_dsc[i]->idx, 1); + } + } + + /* setup dsc active configuration in the control path */ + if (hw_ctl->ops.setup_dsc_cfg) { + hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg); + SDE_DEBUG_ENC(sde_enc, + "setup dsc_cfg hw_ctl[%d], count:%d,dsc[0]:%d, dsc[1]:%d\n", + hw_ctl->idx, + cfg.dsc_count, + cfg.dsc[0], + cfg.dsc[1]); + } + return 0; +} + +static int _sde_encoder_dsc_2_lm_2_enc_1_intf(struct sde_encoder_virt *sde_enc, + struct sde_encoder_kickoff_params *params) +{ + int this_frame_slices; + int intf_ip_w, enc_ip_w; + int ich_res, dsc_common_mode; + + struct sde_encoder_phys *enc_master = sde_enc->cur_master; + const struct sde_rect *roi = &sde_enc->cur_conn_roi; + struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC]; + struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC]; + struct sde_hw_pingpong *hw_dsc_pp[MAX_CHANNELS_PER_ENC]; + struct msm_display_dsc_info *dsc = NULL; + bool half_panel_partial_update; + struct sde_hw_ctl *hw_ctl = NULL; + struct sde_ctl_dsc_cfg cfg; + int i; + + if (!enc_master) { + SDE_ERROR_ENC(sde_enc, "invalid encoder master for DSC\n"); + return -EINVAL; + } + + memset(&cfg, 0, sizeof(cfg)); + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + hw_pp[i] = sde_enc->hw_pp[i]; + hw_dsc[i] = sde_enc->hw_dsc[i]; + hw_dsc_pp[i] = sde_enc->hw_dsc_pp[i]; + + if (!hw_pp[i] || !hw_dsc[i] || !hw_dsc_pp[i]) { + SDE_ERROR_ENC(sde_enc, "invalid params for DSC\n"); + return -EINVAL; + } + } + + hw_ctl = enc_master->hw_ctl; + + dsc = &sde_enc->mode_info.comp_info.dsc_info; + + half_panel_partial_update = + hweight_long(params->affected_displays) == 1; + + dsc_common_mode = 0; + if (!half_panel_partial_update) + dsc_common_mode |= DSC_MODE_SPLIT_PANEL | DSC_MODE_MULTIPLEX; + if (enc_master->intf_mode == INTF_MODE_VIDEO) + dsc_common_mode |= DSC_MODE_VIDEO; + + _sde_encoder_dsc_update_pic_dim(dsc, roi->w, roi->h); + + this_frame_slices = roi->w / dsc->slice_width; + intf_ip_w = this_frame_slices * dsc->slice_width; + _sde_encoder_dsc_pclk_param_calc(dsc, intf_ip_w); + + /* + * dsc merge case: when using 2 encoders for the same stream, + * no. of slices need to be same on both the encoders. + */ + enc_ip_w = intf_ip_w / 2; + _sde_encoder_dsc_initial_line_calc(dsc, enc_ip_w); + + ich_res = _sde_encoder_dsc_ich_reset_override_needed( + half_panel_partial_update, dsc); + + SDE_DEBUG_ENC(sde_enc, "pic_w: %d pic_h: %d mode:%d\n", + roi->w, roi->h, dsc_common_mode); + SDE_EVT32(DRMID(&sde_enc->base), roi->w, roi->h, + dsc_common_mode, i, params->affected_displays); + + _sde_encoder_dsc_pipe_cfg(hw_dsc[0], hw_pp[0], dsc, dsc_common_mode, + ich_res, true, hw_dsc_pp[0], false); + cfg.dsc[0] = hw_dsc[0]->idx; + cfg.dsc_count++; + if (hw_ctl->ops.update_bitmask_dsc) + hw_ctl->ops.update_bitmask_dsc(hw_ctl, hw_dsc[0]->idx, 1); + + + _sde_encoder_dsc_pipe_cfg(hw_dsc[1], hw_pp[1], dsc, dsc_common_mode, + ich_res, !half_panel_partial_update, hw_dsc_pp[1], + half_panel_partial_update); + if (!half_panel_partial_update) { + cfg.dsc[1] = hw_dsc[1]->idx; + cfg.dsc_count++; + if (hw_ctl->ops.update_bitmask_dsc) + hw_ctl->ops.update_bitmask_dsc(hw_ctl, hw_dsc[1]->idx, + 1); + } + /* setup dsc active configuration in the control path */ + if (hw_ctl->ops.setup_dsc_cfg) { + hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg); + SDE_DEBUG_ENC(sde_enc, + "setup_dsc_cfg hw_ctl[%d], count:%d,dsc[0]:%d, dsc[1]:%d\n", + hw_ctl->idx, + cfg.dsc_count, + cfg.dsc[0], + cfg.dsc[1]); + } + return 0; +} + +static int _sde_encoder_update_roi(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct drm_connector *drm_conn; + struct drm_display_mode *adj_mode; + struct sde_rect roi; + + if (!drm_enc) { + SDE_ERROR("invalid encoder parameter\n"); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc->crtc || !sde_enc->crtc->state) { + SDE_ERROR("invalid crtc parameter\n"); + return -EINVAL; + } + + if (!sde_enc->cur_master) { + SDE_ERROR("invalid cur_master parameter\n"); + return -EINVAL; + } + + adj_mode = &sde_enc->cur_master->cached_mode; + drm_conn = sde_enc->cur_master->connector; + + _sde_encoder_get_connector_roi(sde_enc, &roi); + if (sde_kms_rect_is_null(&roi)) { + roi.w = adj_mode->hdisplay; + roi.h = adj_mode->vdisplay; + } + + memcpy(&sde_enc->prv_conn_roi, &sde_enc->cur_conn_roi, + sizeof(sde_enc->prv_conn_roi)); + memcpy(&sde_enc->cur_conn_roi, &roi, sizeof(sde_enc->cur_conn_roi)); + + return 0; +} + +static int _sde_encoder_dsc_setup(struct sde_encoder_virt *sde_enc, + struct sde_encoder_kickoff_params *params) +{ + enum sde_rm_topology_name topology; + struct drm_connector *drm_conn; + int ret = 0; + + if (!sde_enc || !params || !sde_enc->phys_encs[0] || + !sde_enc->phys_encs[0]->connector) + return -EINVAL; + + drm_conn = sde_enc->phys_encs[0]->connector; + + topology = sde_connector_get_topology_name(drm_conn); + if (topology == SDE_RM_TOPOLOGY_NONE) { + SDE_ERROR_ENC(sde_enc, "topology not set yet\n"); + return -EINVAL; + } + + SDE_DEBUG_ENC(sde_enc, "topology:%d\n", topology); + SDE_EVT32(DRMID(&sde_enc->base), topology, + sde_enc->cur_conn_roi.x, + sde_enc->cur_conn_roi.y, + sde_enc->cur_conn_roi.w, + sde_enc->cur_conn_roi.h, + sde_enc->prv_conn_roi.x, + sde_enc->prv_conn_roi.y, + sde_enc->prv_conn_roi.w, + sde_enc->prv_conn_roi.h, + sde_enc->cur_master->cached_mode.hdisplay, + sde_enc->cur_master->cached_mode.vdisplay); + + if (sde_kms_rect_is_equal(&sde_enc->cur_conn_roi, + &sde_enc->prv_conn_roi)) + return ret; + + switch (topology) { + case SDE_RM_TOPOLOGY_SINGLEPIPE_DSC: + case SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC: + ret = _sde_encoder_dsc_n_lm_1_enc_1_intf(sde_enc); + break; + case SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE: + ret = _sde_encoder_dsc_2_lm_2_enc_1_intf(sde_enc, params); + break; + case SDE_RM_TOPOLOGY_DUALPIPE_DSC: + ret = _sde_encoder_dsc_2_lm_2_enc_2_intf(sde_enc, params); + break; + default: + SDE_ERROR_ENC(sde_enc, "No DSC support for topology %d", + topology); + return -EINVAL; + } + + return ret; +} + +void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, + u32 vsync_source, bool is_dummy) +{ + struct sde_vsync_source_cfg vsync_cfg = { 0 }; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct sde_hw_mdp *hw_mdptop; + struct drm_encoder *drm_enc; + struct sde_encoder_virt *sde_enc; + int i; + + sde_enc = to_sde_encoder_virt(phys_enc->parent); + + if (!sde_enc) { + SDE_ERROR("invalid param sde_enc:%d\n", sde_enc != NULL); + return; + } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { + SDE_ERROR("invalid num phys enc %d/%d\n", + sde_enc->num_phys_encs, + (int) ARRAY_SIZE(sde_enc->hw_pp)); + return; + } + + drm_enc = &sde_enc->base; + /* this pointers are checked in virt_enable_helper */ + priv = drm_enc->dev->dev_private; + + sde_kms = to_sde_kms(priv->kms); + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return; + } + + hw_mdptop = sde_kms->hw_mdp; + if (!hw_mdptop) { + SDE_ERROR("invalid mdptop\n"); + return; + } + + if (hw_mdptop->ops.setup_vsync_source) { + for (i = 0; i < sde_enc->num_phys_encs; i++) + vsync_cfg.ppnumber[i] = sde_enc->hw_pp[i]->idx; + + vsync_cfg.pp_count = sde_enc->num_phys_encs; + vsync_cfg.frame_rate = sde_enc->mode_info.frame_rate; + vsync_cfg.vsync_source = vsync_source; + vsync_cfg.is_dummy = is_dummy; + + hw_mdptop->ops.setup_vsync_source(hw_mdptop, &vsync_cfg); + } +} + +static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, + struct msm_display_info *disp_info, bool is_dummy) +{ + struct sde_encoder_phys *phys; + int i; + u32 vsync_source; + + if (!sde_enc || !disp_info) { + SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", + sde_enc != NULL, disp_info != NULL); + return; + } else if (sde_enc->num_phys_encs > ARRAY_SIZE(sde_enc->hw_pp)) { + SDE_ERROR("invalid num phys enc %d/%d\n", + sde_enc->num_phys_encs, + (int) ARRAY_SIZE(sde_enc->hw_pp)); + return; + } + + if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_CMD_MODE)) { + if (is_dummy) + vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0 - + sde_enc->te_source; + else if (disp_info->is_te_using_watchdog_timer) + vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_4; + else + vsync_source = sde_enc->te_source; + + SDE_EVT32(DRMID(&sde_enc->base), vsync_source, is_dummy, + disp_info->is_te_using_watchdog_timer); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.setup_vsync_source) + phys->ops.setup_vsync_source(phys, + vsync_source, is_dummy); + } + } +} + +static void _sde_encoder_dsc_disable(struct sde_encoder_virt *sde_enc) +{ + int i; + struct sde_hw_pingpong *hw_pp = NULL; + struct sde_hw_pingpong *hw_dsc_pp = NULL; + struct sde_hw_dsc *hw_dsc = NULL; + struct sde_hw_ctl *hw_ctl = NULL; + struct sde_ctl_dsc_cfg cfg; + + if (!_sde_encoder_is_dsc_enabled(&sde_enc->base)) + return; + + if (!sde_enc || !sde_enc->phys_encs[0]) { + SDE_ERROR("invalid params %d %d\n", + !sde_enc, sde_enc ? !sde_enc->phys_encs[0] : -1); + return; + } + + /* + * Connector can be null if the first virt modeset after suspend + * is called with dynamic clock or dms enabled. + */ + if (!sde_enc->phys_encs[0]->connector) + return; + + if (sde_enc->cur_master) + hw_ctl = sde_enc->cur_master->hw_ctl; + + /* Disable DSC for all the pp's present in this topology */ + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + hw_pp = sde_enc->hw_pp[i]; + hw_dsc = sde_enc->hw_dsc[i]; + hw_dsc_pp = sde_enc->hw_dsc_pp[i]; + + _sde_encoder_dsc_pipe_cfg(hw_dsc, hw_pp, NULL, + 0, 0, 0, hw_dsc_pp, false); + + if (hw_dsc) + sde_enc->dirty_dsc_ids[i] = hw_dsc->idx; + } + + /* Clear the DSC ACTIVE config for this CTL */ + if (hw_ctl && hw_ctl->ops.setup_dsc_cfg) { + memset(&cfg, 0, sizeof(cfg)); + hw_ctl->ops.setup_dsc_cfg(hw_ctl, &cfg); + } + + /** + * Since pending flushes from previous commit get cleared + * sometime after this point, setting DSC flush bits now + * will have no effect. Therefore dirty_dsc_ids track which + * DSC blocks must be flushed for the next trigger. + */ +} + +int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc, + bool watchdog_te) +{ + struct sde_encoder_virt *sde_enc; + struct msm_display_info disp_info; + + if (!drm_enc) { + pr_err("invalid drm encoder\n"); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + + sde_encoder_control_te(drm_enc, false); + + memcpy(&disp_info, &sde_enc->disp_info, sizeof(disp_info)); + disp_info.is_te_using_watchdog_timer = watchdog_te; + _sde_encoder_update_vsync_source(sde_enc, &disp_info, false); + + sde_encoder_control_te(drm_enc, true); + + return 0; +} + +static int _sde_encoder_rsc_client_update_vsync_wait( + struct drm_encoder *drm_enc, struct sde_encoder_virt *sde_enc, + int wait_vblank_crtc_id) +{ + int wait_refcount = 0, ret = 0; + int pipe = -1; + int wait_count = 0; + struct drm_crtc *primary_crtc; + struct drm_crtc *crtc; + + crtc = sde_enc->crtc; + + if (wait_vblank_crtc_id) + wait_refcount = + sde_rsc_client_get_vsync_refcount(sde_enc->rsc_client); + SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id, wait_refcount, + SDE_EVTLOG_FUNC_ENTRY); + + if (crtc->base.id != wait_vblank_crtc_id) { + primary_crtc = drm_crtc_find(drm_enc->dev, + NULL, wait_vblank_crtc_id); + if (!primary_crtc) { + SDE_ERROR_ENC(sde_enc, + "failed to find primary crtc id %d\n", + wait_vblank_crtc_id); + return -EINVAL; + } + pipe = drm_crtc_index(primary_crtc); + } + + /** + * note: VBLANK is expected to be enabled at this point in + * resource control state machine if on primary CRTC + */ + for (wait_count = 0; wait_count < MAX_RSC_WAIT; wait_count++) { + if (sde_rsc_client_is_state_update_complete( + sde_enc->rsc_client)) + break; + + if (crtc->base.id == wait_vblank_crtc_id) + ret = sde_encoder_wait_for_event(drm_enc, + MSM_ENC_VBLANK); + else + drm_wait_one_vblank(drm_enc->dev, pipe); + + if (ret) { + SDE_ERROR_ENC(sde_enc, + "wait for vblank failed ret:%d\n", ret); + /** + * rsc hardware may hang without vsync. avoid rsc hang + * by generating the vsync from watchdog timer. + */ + if (crtc->base.id == wait_vblank_crtc_id) + sde_encoder_helper_switch_vsync(drm_enc, true); + } + } + + if (wait_count >= MAX_RSC_WAIT) + SDE_EVT32(DRMID(drm_enc), wait_vblank_crtc_id, wait_count, + SDE_EVTLOG_ERROR); + + if (wait_refcount) + sde_rsc_client_reset_vsync_refcount(sde_enc->rsc_client); + SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id, wait_refcount, + SDE_EVTLOG_FUNC_EXIT); + + return ret; +} + +static int _sde_encoder_update_rsc_client( + struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + struct drm_crtc *crtc; + enum sde_rsc_state rsc_state = SDE_RSC_IDLE_STATE; + struct sde_rsc_cmd_config *rsc_config; + int ret; + struct msm_display_info *disp_info; + struct msm_mode_info *mode_info; + int wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID; + u32 qsync_mode = 0, v_front_porch; + struct drm_display_mode *mode; + bool is_vid_mode; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct drm_encoder *enc; + + if (!drm_enc || !drm_enc->dev) { + SDE_ERROR("invalid encoder arguments\n"); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + mode_info = &sde_enc->mode_info; + + crtc = sde_enc->crtc; + + if (!sde_enc->crtc) { + SDE_ERROR("invalid crtc parameter\n"); + return -EINVAL; + } + disp_info = &sde_enc->disp_info; + rsc_config = &sde_enc->rsc_config; + + if (!sde_enc->rsc_client) { + SDE_DEBUG_ENC(sde_enc, "rsc client not created\n"); + return 0; + } + + priv = drm_enc->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("Invalid kms\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(priv->kms); + + /** + * only primary command mode panel without Qsync can request CMD state. + * all other panels/displays can request for VID state including + * secondary command mode panel. + * Clone mode encoder can request CLK STATE only. + */ + if (sde_enc->cur_master) + qsync_mode = sde_connector_get_qsync_mode( + sde_enc->cur_master->connector); + + if (sde_encoder_in_clone_mode(drm_enc) || + (disp_info->display_type != SDE_CONNECTOR_PRIMARY) || + (disp_info->display_type && qsync_mode)) + rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE; + else if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) + rsc_state = enable ? SDE_RSC_CMD_STATE : SDE_RSC_IDLE_STATE; + else if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_VIDEO_MODE)) + rsc_state = enable ? SDE_RSC_VID_STATE : SDE_RSC_IDLE_STATE; + + drm_for_each_encoder(enc, drm_enc->dev) { + if (enc->base.id != drm_enc->base.id && + sde_encoder_in_cont_splash(enc)) + rsc_state = SDE_RSC_CLK_STATE; + } + + if (IS_SDE_MAJOR_SAME(sde_kms->core_rev, SDE_HW_VER_600) && + (rsc_state == SDE_RSC_VID_STATE)) + rsc_state = SDE_RSC_CLK_STATE; + + SDE_EVT32(rsc_state, qsync_mode); + + is_vid_mode = sde_encoder_check_curr_mode(&sde_enc->base, + MSM_DISPLAY_VIDEO_MODE); + mode = &sde_enc->crtc->state->mode; + v_front_porch = mode->vsync_start - mode->vdisplay; + + /* compare specific items and reconfigure the rsc */ + if ((rsc_config->fps != mode_info->frame_rate) || + (rsc_config->vtotal != mode_info->vtotal) || + (rsc_config->prefill_lines != mode_info->prefill_lines) || + (rsc_config->jitter_numer != mode_info->jitter_numer) || + (rsc_config->jitter_denom != mode_info->jitter_denom)) { + + rsc_config->fps = mode_info->frame_rate; + rsc_config->vtotal = mode_info->vtotal; + /* + * for video mode, prefill lines should not go beyond vertical + * front porch for RSCC configuration. This will ensure bw + * downvotes are not sent within the active region. Additional + * -1 is to give one line time for rscc mode min_threshold. + */ + if (is_vid_mode && (mode_info->prefill_lines >= v_front_porch)) + rsc_config->prefill_lines = v_front_porch - 1; + else + rsc_config->prefill_lines = mode_info->prefill_lines; + + rsc_config->jitter_numer = mode_info->jitter_numer; + rsc_config->jitter_denom = mode_info->jitter_denom; + sde_enc->rsc_state_init = false; + rsc_config->fps = mode_info->frame_rate; + } + + if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init + && (disp_info->display_type == SDE_CONNECTOR_PRIMARY)) { + /* update it only once */ + sde_enc->rsc_state_init = true; + + ret = sde_rsc_client_state_update(sde_enc->rsc_client, + rsc_state, rsc_config, crtc->base.id, + &wait_vblank_crtc_id); + } else { + ret = sde_rsc_client_state_update(sde_enc->rsc_client, + rsc_state, NULL, crtc->base.id, + &wait_vblank_crtc_id); + } + + /** + * if RSC performed a state change that requires a VBLANK wait, it will + * set wait_vblank_crtc_id to the CRTC whose VBLANK we must wait on. + * + * if we are the primary display, we will need to enable and wait + * locally since we hold the commit thread + * + * if we are an external display, we must send a signal to the primary + * to enable its VBLANK and wait one, since the RSC hardware is driven + * by the primary panel's VBLANK signals + */ + SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "sde rsc client update failed ret:%d\n", ret); + return ret; + } else if (wait_vblank_crtc_id == SDE_RSC_INVALID_CRTC_ID) { + return ret; + } + + ret = _sde_encoder_rsc_client_update_vsync_wait(drm_enc, + sde_enc, wait_vblank_crtc_id); + + return ret; +} + +static void _sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + int i; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + + SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.irq_control) + phys->ops.irq_control(phys, enable); + } + +} + +/* keep track of the userspace vblank during modeset */ +static void _sde_encoder_modeset_helper_locked(struct drm_encoder *drm_enc, + u32 sw_event) +{ + struct sde_encoder_virt *sde_enc; + bool enable; + int i; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, vblank_enabled:%d\n", + sw_event, sde_enc->vblank_enabled); + + /* nothing to do if vblank not enabled by userspace */ + if (!sde_enc->vblank_enabled) + return; + + /* disable vblank on pre_modeset */ + if (sw_event == SDE_ENC_RC_EVENT_PRE_MODESET) + enable = false; + /* enable vblank on post_modeset */ + else if (sw_event == SDE_ENC_RC_EVENT_POST_MODESET) + enable = true; + else + return; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.control_vblank_irq) + phys->ops.control_vblank_irq(phys, enable); + } +} + +struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) + return NULL; + sde_enc = to_sde_encoder_virt(drm_enc); + return sde_enc->rsc_client; +} + +static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, + bool enable) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct sde_encoder_virt *sde_enc; + int rc; + bool is_cmd_mode = false; + + sde_enc = to_sde_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) + is_cmd_mode = true; + + SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable); + SDE_EVT32(DRMID(drm_enc), enable); + + if (!sde_enc->cur_master) { + SDE_ERROR("encoder master not set\n"); + return -EINVAL; + } + + if (enable) { + /* enable SDE core clks */ + rc = pm_runtime_get_sync(drm_enc->dev->dev); + if (rc < 0) { + SDE_ERROR("failed to enable power resource %d\n", rc); + SDE_EVT32(rc, SDE_EVTLOG_ERROR); + return rc; + } + + sde_enc->elevated_ahb_vote = true; + /* enable DSI clks */ + rc = sde_connector_clk_ctrl(sde_enc->cur_master->connector, + true); + if (rc) { + SDE_ERROR("failed to enable clk control %d\n", rc); + pm_runtime_put_sync(drm_enc->dev->dev); + return rc; + } + + /* enable all the irq */ + _sde_encoder_irq_control(drm_enc, true); + + if (is_cmd_mode) + _sde_encoder_pm_qos_add_request(drm_enc, sde_kms); + + } else { + if (is_cmd_mode) + _sde_encoder_pm_qos_remove_request(drm_enc, sde_kms); + + /* disable all the irq */ + _sde_encoder_irq_control(drm_enc, false); + + /* disable DSI clks */ + sde_connector_clk_ctrl(sde_enc->cur_master->connector, false); + + /* disable SDE core clks */ + pm_runtime_put_sync(drm_enc->dev->dev); + } + + return 0; +} + +static void sde_encoder_misr_configure(struct drm_encoder *drm_enc, + bool enable, u32 frame_count) +{ + struct sde_encoder_virt *sde_enc; + int i; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys || !phys->ops.setup_misr) + continue; + + phys->ops.setup_misr(phys, enable, frame_count); + } +} + +static void sde_encoder_input_event_handler(struct input_handle *handle, + unsigned int type, unsigned int code, int value) +{ + struct drm_encoder *drm_enc = NULL; + struct sde_encoder_virt *sde_enc = NULL; + struct msm_drm_thread *disp_thread = NULL; + struct msm_drm_private *priv = NULL; + + if (!handle || !handle->handler || !handle->handler->private) { + SDE_ERROR("invalid encoder for the input event\n"); + return; + } + + drm_enc = (struct drm_encoder *)handle->handler->private; + if (!drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid parameters\n"); + return; + } + + priv = drm_enc->dev->dev_private; + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc->crtc || (sde_enc->crtc->index + >= ARRAY_SIZE(priv->disp_thread))) { + SDE_DEBUG_ENC(sde_enc, + "invalid cached CRTC: %d or crtc index: %d\n", + sde_enc->crtc == NULL, + sde_enc->crtc ? sde_enc->crtc->index : -EINVAL); + return; + } + + SDE_EVT32_VERBOSE(DRMID(drm_enc)); + + disp_thread = &priv->disp_thread[sde_enc->crtc->index]; + + kthread_queue_work(&disp_thread->worker, + &sde_enc->input_event_work); +} + +void sde_encoder_control_idle_pc(struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + + /* return early if there is no state change */ + if (sde_enc->idle_pc_enabled == enable) + return; + + sde_enc->idle_pc_enabled = enable; + + SDE_DEBUG("idle-pc state:%d\n", sde_enc->idle_pc_enabled); + SDE_EVT32(sde_enc->idle_pc_enabled); +} + +static void _sde_encoder_rc_cancel_delayed(struct sde_encoder_virt *sde_enc, + u32 sw_event) +{ + if (kthread_cancel_delayed_work_sync( + &sde_enc->delayed_off_work)) + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work cancelled\n", + sw_event); +} + +static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc, bool is_vid_mode) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + int ret = 0; + + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + /* cancel delayed off work, if any */ + _sde_encoder_rc_cancel_delayed(sde_enc, sw_event); + + mutex_lock(&sde_enc->rc_lock); + + /* return if the resource control is already in ON state */ + if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) { + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in ON state\n", + sw_event); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE1); + goto end; + } else if (sde_enc->rc_state != SDE_ENC_RC_STATE_OFF && + sde_enc->rc_state != SDE_ENC_RC_STATE_IDLE) { + SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc in state %d\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_ERROR); + goto end; + } + + if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { + _sde_encoder_irq_control(drm_enc, true); + sde_kms_update_pm_qos_irq_request(sde_kms, true, false); + } else { + /* enable all the clks and resources */ + ret = _sde_encoder_resource_control_helper(drm_enc, + true); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "sw_event:%d, rc in state %d\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, + sde_enc->rc_state, + SDE_EVTLOG_ERROR); + goto end; + } + _sde_encoder_update_rsc_client(drm_enc, true); + } + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE1); + sde_enc->rc_state = SDE_ENC_RC_STATE_ON; + +end: + mutex_unlock(&sde_enc->rc_lock); + return ret; +} + +static int _sde_encoder_rc_frame_done(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc, + struct msm_drm_private *priv) +{ + unsigned int lp, idle_pc_duration; + struct msm_drm_thread *disp_thread; + bool autorefresh_enabled = false; + + if (!sde_enc->crtc) { + SDE_ERROR("invalid crtc, sw_event:%u\n", sw_event); + return -EINVAL; + } + + if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { + SDE_ERROR("invalid crtc index :%u\n", + sde_enc->crtc->index); + return -EINVAL; + } + disp_thread = &priv->disp_thread[sde_enc->crtc->index]; + + /* + * mutex lock is not used as this event happens at interrupt + * context. And locking is not required as, the other events + * like KICKOFF and STOP does a wait-for-idle before executing + * the resource_control + */ + if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) { + SDE_ERROR_ENC(sde_enc, "sw_event:%d,rc:%d-unexpected\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_ERROR); + return -EINVAL; + } + + /* + * schedule off work item only when there are no + * frames pending + */ + if (sde_crtc_frame_pending(sde_enc->crtc) > 1) { + SDE_DEBUG_ENC(sde_enc, "skip schedule work"); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE2); + return 0; + } + + /* schedule delayed off work if autorefresh is disabled */ + if (sde_enc->cur_master && + sde_enc->cur_master->ops.is_autorefresh_enabled) + autorefresh_enabled = + sde_enc->cur_master->ops.is_autorefresh_enabled( + sde_enc->cur_master); + + /* set idle timeout based on master connector's lp value */ + if (sde_enc->cur_master) + lp = sde_connector_get_lp( + sde_enc->cur_master->connector); + else + lp = SDE_MODE_DPMS_ON; + + if (lp == SDE_MODE_DPMS_LP2) + idle_pc_duration = IDLE_SHORT_TIMEOUT; + else + idle_pc_duration = IDLE_POWERCOLLAPSE_DURATION; + + if (!autorefresh_enabled) + kthread_mod_delayed_work( + &disp_thread->worker, + &sde_enc->delayed_off_work, + msecs_to_jiffies(idle_pc_duration)); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + autorefresh_enabled, + idle_pc_duration, SDE_EVTLOG_FUNC_CASE2); + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, work scheduled\n", + sw_event); + return 0; +} + +static int _sde_encoder_rc_pre_stop(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc, bool is_vid_mode) +{ + /* cancel delayed off work, if any */ + _sde_encoder_rc_cancel_delayed(sde_enc, sw_event); + + mutex_lock(&sde_enc->rc_lock); + + if (is_vid_mode && + sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { + _sde_encoder_irq_control(drm_enc, true); + } + /* skip if is already OFF or IDLE, resources are off already */ + else if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF || + sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in %d state\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE3); + goto end; + } + + /** + * IRQs are still enabled currently, which allows wait for + * VBLANK which RSC may require to correctly transition to OFF + */ + _sde_encoder_update_rsc_client(drm_enc, false); + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_PRE_OFF, + SDE_EVTLOG_FUNC_CASE3); + + sde_enc->rc_state = SDE_ENC_RC_STATE_PRE_OFF; + +end: + mutex_unlock(&sde_enc->rc_lock); + return 0; +} + +static int _sde_encoder_rc_stop(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc) +{ + int ret = 0; + + /* cancel vsync event work and timer */ + kthread_cancel_work_sync(&sde_enc->vsync_event_work); + if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI) + del_timer_sync(&sde_enc->vsync_event_timer); + + mutex_lock(&sde_enc->rc_lock); + /* return if the resource control is already in OFF state */ + if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) { + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n", + sw_event); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE4); + goto end; + } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON || + sde_enc->rc_state == SDE_ENC_RC_STATE_MODESET) { + SDE_ERROR_ENC(sde_enc, "sw_event:%d, rc in state %d\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_ERROR); + ret = -EINVAL; + goto end; + } + + /** + * expect to arrive here only if in either idle state or pre-off + * and in IDLE state the resources are already disabled + */ + if (sde_enc->rc_state == SDE_ENC_RC_STATE_PRE_OFF) + _sde_encoder_resource_control_helper(drm_enc, false); + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_OFF, SDE_EVTLOG_FUNC_CASE4); + + sde_enc->rc_state = SDE_ENC_RC_STATE_OFF; + +end: + mutex_unlock(&sde_enc->rc_lock); + return ret; +} + +static int _sde_encoder_rc_pre_modeset(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc) +{ + int ret = 0; + + /* cancel delayed off work, if any */ + _sde_encoder_rc_cancel_delayed(sde_enc, sw_event); + + mutex_lock(&sde_enc->rc_lock); + + if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) { + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n", + sw_event); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE5); + goto end; + } else if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) { + /* enable all the clks and resources */ + ret = _sde_encoder_resource_control_helper(drm_enc, + true); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "sw_event:%d, rc in state %d\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, + sde_enc->rc_state, + SDE_EVTLOG_ERROR); + goto end; + } + + _sde_encoder_update_rsc_client(drm_enc, true); + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE5); + sde_enc->rc_state = SDE_ENC_RC_STATE_ON; + } + + ret = sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + if (ret && ret != -EWOULDBLOCK) { + SDE_ERROR_ENC(sde_enc, + "wait for commit done returned %d\n", + ret); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + ret, SDE_EVTLOG_ERROR); + ret = -EINVAL; + goto end; + } + + _sde_encoder_irq_control(drm_enc, false); + _sde_encoder_modeset_helper_locked(drm_enc, sw_event); + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_MODESET, SDE_EVTLOG_FUNC_CASE5); + + sde_enc->rc_state = SDE_ENC_RC_STATE_MODESET; + +end: + mutex_unlock(&sde_enc->rc_lock); + return ret; +} + +static int _sde_encoder_rc_post_modeset(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc) +{ + int ret = 0; + + mutex_lock(&sde_enc->rc_lock); + + if (sde_enc->rc_state == SDE_ENC_RC_STATE_OFF) { + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc in OFF state\n", + sw_event); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_FUNC_CASE5); + goto end; + } else if (sde_enc->rc_state != SDE_ENC_RC_STATE_MODESET) { + SDE_ERROR_ENC(sde_enc, + "sw_event:%d, rc:%d !MODESET state\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_ERROR); + ret = -EINVAL; + goto end; + } + + _sde_encoder_modeset_helper_locked(drm_enc, sw_event); + _sde_encoder_irq_control(drm_enc, true); + + _sde_encoder_update_rsc_client(drm_enc, true); + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE6); + + sde_enc->rc_state = SDE_ENC_RC_STATE_ON; + +end: + mutex_unlock(&sde_enc->rc_lock); + return ret; +} + +static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc, bool is_vid_mode) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct drm_crtc *crtc = drm_enc->crtc; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + mutex_lock(&sde_enc->rc_lock); + + if (sde_enc->rc_state != SDE_ENC_RC_STATE_ON) { + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, rc:%d !ON state\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_EVTLOG_ERROR); + goto end; + } else if (sde_crtc_frame_pending(sde_enc->crtc)) { + SDE_DEBUG_ENC(sde_enc, "skip idle entry"); + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + sde_crtc_frame_pending(sde_enc->crtc), + SDE_EVTLOG_ERROR); + goto end; + } + + if (is_vid_mode) { + _sde_encoder_irq_control(drm_enc, false); + sde_kms_update_pm_qos_irq_request(sde_kms, false, false); + } else { + /* disable all the clks and resources */ + _sde_encoder_update_rsc_client(drm_enc, false); + _sde_encoder_resource_control_helper(drm_enc, false); + + if (!sde_kms->perf.bw_vote_mode) + memset(&sde_crtc->cur_perf, 0, + sizeof(struct sde_core_perf_params)); + } + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_IDLE, SDE_EVTLOG_FUNC_CASE7); + sde_enc->rc_state = SDE_ENC_RC_STATE_IDLE; + +end: + mutex_unlock(&sde_enc->rc_lock); + return 0; +} + +static int _sde_encoder_rc_early_wakeup(struct drm_encoder *drm_enc, + u32 sw_event, struct sde_encoder_virt *sde_enc, + struct msm_drm_private *priv, bool is_vid_mode) +{ + bool autorefresh_enabled = false; + struct msm_drm_thread *disp_thread; + int ret = 0; + + if (!sde_enc->crtc || + sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) { + SDE_DEBUG_ENC(sde_enc, + "invalid crtc:%d or crtc index:%d , sw_event:%u\n", + sde_enc->crtc == NULL, + sde_enc->crtc ? sde_enc->crtc->index : -EINVAL, + sw_event); + return -EINVAL; + } + + disp_thread = &priv->disp_thread[sde_enc->crtc->index]; + + mutex_lock(&sde_enc->rc_lock); + + if (sde_enc->rc_state == SDE_ENC_RC_STATE_ON) { + if (sde_enc->cur_master && + sde_enc->cur_master->ops.is_autorefresh_enabled) + autorefresh_enabled = + sde_enc->cur_master->ops.is_autorefresh_enabled( + sde_enc->cur_master); + if (autorefresh_enabled) { + SDE_DEBUG_ENC(sde_enc, + "not handling early wakeup since auto refresh is enabled\n"); + goto end; + } + + if (!sde_crtc_frame_pending(sde_enc->crtc)) + kthread_mod_delayed_work(&disp_thread->worker, + &sde_enc->delayed_off_work, + msecs_to_jiffies( + IDLE_POWERCOLLAPSE_DURATION)); + } else if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { + /* enable all the clks and resources */ + ret = _sde_encoder_resource_control_helper(drm_enc, + true); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "sw_event:%d, rc in state %d\n", + sw_event, sde_enc->rc_state); + SDE_EVT32(DRMID(drm_enc), sw_event, + sde_enc->rc_state, + SDE_EVTLOG_ERROR); + goto end; + } + + _sde_encoder_update_rsc_client(drm_enc, true); + + /* + * In some cases, commit comes with slight delay + * (> 80 ms)after early wake up, prevent clock switch + * off to avoid jank in next update. So, increase the + * command mode idle timeout sufficiently to prevent + * such case. + */ + kthread_mod_delayed_work(&disp_thread->worker, + &sde_enc->delayed_off_work, + msecs_to_jiffies( + IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP)); + + sde_enc->rc_state = SDE_ENC_RC_STATE_ON; + } + + SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state, + SDE_ENC_RC_STATE_ON, SDE_EVTLOG_FUNC_CASE8); + +end: + mutex_unlock(&sde_enc->rc_lock); + return ret; +} + +static int sde_encoder_resource_control(struct drm_encoder *drm_enc, + u32 sw_event) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv; + int ret = 0; + bool is_vid_mode = false; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid encoder parameters, sw_event:%u\n", + sw_event); + return -EINVAL; + } + sde_enc = to_sde_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_VIDEO_MODE)) + is_vid_mode = true; + /* + * when idle_pc is not supported, process only KICKOFF, STOP and MODESET + * events and return early for other events (ie wb display). + */ + if (!sde_enc->idle_pc_enabled && + (sw_event != SDE_ENC_RC_EVENT_KICKOFF && + sw_event != SDE_ENC_RC_EVENT_PRE_MODESET && + sw_event != SDE_ENC_RC_EVENT_POST_MODESET && + sw_event != SDE_ENC_RC_EVENT_STOP && + sw_event != SDE_ENC_RC_EVENT_PRE_STOP)) + return 0; + + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc:%d\n", + sw_event, sde_enc->idle_pc_enabled); + SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_enabled, + sde_enc->rc_state, SDE_EVTLOG_FUNC_ENTRY); + + switch (sw_event) { + case SDE_ENC_RC_EVENT_KICKOFF: + ret = _sde_encoder_rc_kickoff(drm_enc, sw_event, sde_enc, + is_vid_mode); + break; + case SDE_ENC_RC_EVENT_FRAME_DONE: + ret = _sde_encoder_rc_frame_done(drm_enc, sw_event, sde_enc, + priv); + break; + case SDE_ENC_RC_EVENT_PRE_STOP: + ret = _sde_encoder_rc_pre_stop(drm_enc, sw_event, sde_enc, + is_vid_mode); + break; + case SDE_ENC_RC_EVENT_STOP: + ret = _sde_encoder_rc_stop(drm_enc, sw_event, sde_enc); + break; + case SDE_ENC_RC_EVENT_PRE_MODESET: + ret = _sde_encoder_rc_pre_modeset(drm_enc, sw_event, sde_enc); + break; + case SDE_ENC_RC_EVENT_POST_MODESET: + ret = _sde_encoder_rc_post_modeset(drm_enc, sw_event, sde_enc); + break; + case SDE_ENC_RC_EVENT_ENTER_IDLE: + ret = _sde_encoder_rc_idle(drm_enc, sw_event, sde_enc, + is_vid_mode); + break; + case SDE_ENC_RC_EVENT_EARLY_WAKEUP: + ret = _sde_encoder_rc_early_wakeup(drm_enc, sw_event, sde_enc, + priv, is_vid_mode); + break; + default: + SDE_EVT32(DRMID(drm_enc), sw_event, SDE_EVTLOG_ERROR); + SDE_ERROR("unexpected sw_event: %d\n", sw_event); + break; + } + + SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_enabled, + sde_enc->rc_state, SDE_EVTLOG_FUNC_EXIT); + return ret; +} + +static void sde_encoder_virt_mode_switch(struct drm_encoder *drm_enc, + enum sde_intf_mode intf_mode, struct drm_display_mode *adj_mode) +{ + int i = 0; + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + if (intf_mode == INTF_MODE_CMD) + sde_enc->disp_info.curr_panel_mode = MSM_DISPLAY_VIDEO_MODE; + else if (intf_mode == INTF_MODE_VIDEO) + sde_enc->disp_info.curr_panel_mode = MSM_DISPLAY_CMD_MODE; + + _sde_encoder_update_rsc_client(drm_enc, true); + + if (intf_mode == INTF_MODE_CMD) { + for (i = 0; i < sde_enc->num_phys_encs; i++) + sde_enc->phys_encs[i] = sde_enc->phys_vid_encs[i]; + SDE_DEBUG_ENC(sde_enc, "switch to video physical encoder\n"); + SDE_EVT32(DRMID(&sde_enc->base), intf_mode, + msm_is_mode_seamless_poms(adj_mode), + SDE_EVTLOG_FUNC_CASE1); + } else if (intf_mode == INTF_MODE_VIDEO) { + for (i = 0; i < sde_enc->num_phys_encs; i++) + sde_enc->phys_encs[i] = sde_enc->phys_cmd_encs[i]; + SDE_EVT32(DRMID(&sde_enc->base), intf_mode, + msm_is_mode_seamless_poms(adj_mode), + SDE_EVTLOG_FUNC_CASE2); + SDE_DEBUG_ENC(sde_enc, "switch to command physical encoder\n"); + } +} + +static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct list_head *connector_list; + struct drm_connector *conn = NULL, *conn_iter; + struct sde_rm_hw_iter dsc_iter, pp_iter, qdss_iter; + struct sde_rm_hw_request request_hw; + enum sde_intf_mode intf_mode; + bool is_cmd_mode = false; + int i = 0, ret; + struct sde_crtc *sde_crtc; + bool modeset_lock = false; + + if (!drm_enc || !drm_enc->crtc) { + SDE_ERROR("invalid params %d %d\n", + !drm_enc, drm_enc ? !drm_enc->crtc : -1); + return; + } + + if (!sde_kms_power_resource_is_enabled(drm_enc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "\n"); + + if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) + is_cmd_mode = true; + + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + connector_list = &sde_kms->dev->mode_config.connector_list; + + SDE_EVT32(DRMID(drm_enc)); + + sde_enc->crtc = drm_enc->crtc; + sde_crtc = to_sde_crtc(sde_enc->crtc); + + list_for_each_entry(conn_iter, connector_list, head) + if (conn_iter->encoder == drm_enc) + conn = conn_iter; + + if (!conn || !conn->state) { + SDE_ERROR_ENC(sde_enc, "invalid connector %d %d\n", + !conn, conn ? !conn->state : -1); + return; + } + + intf_mode = sde_encoder_get_intf_mode(drm_enc); + + /* store the mode_info */ + sde_connector_state_get_mode_info(conn->state, &sde_enc->mode_info); + + sde_crtc_set_compression_ratio(sde_enc->mode_info, sde_enc->crtc); + + modeset_lock = REQ_SEAMLESS_MODESET_LOCK(adj_mode, + is_cmd_mode); + if (modeset_lock) + mutex_lock(&sde_crtc->vblank_modeset_ctrl_lock); + /* release resources before seamless mode change */ + if (msm_is_mode_seamless_dms(adj_mode) || + (msm_is_mode_seamless_dyn_clk(adj_mode) && + is_cmd_mode)) { + /* restore resource state before releasing them */ + ret = sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_PRE_MODESET); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "sde resource control failed: %d\n", + ret); + goto exit; + } + + /* + * Disable dsc before switch the mode and after pre_modeset, + * to guarantee that previous kickoff finished. + */ + _sde_encoder_dsc_disable(sde_enc); + } else if (msm_is_mode_seamless_poms(adj_mode)) { + _sde_encoder_modeset_helper_locked(drm_enc, + SDE_ENC_RC_EVENT_PRE_MODESET); + sde_encoder_virt_mode_switch(drm_enc, intf_mode, adj_mode); + } + + /* Reserve dynamic resources now. Indicating non-AtomicTest phase */ + ret = sde_rm_reserve(&sde_kms->rm, drm_enc, drm_enc->crtc->state, + conn->state, false); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "failed to reserve hw resources, %d\n", ret); + goto exit; + } + + sde_rm_init_hw_iter(&pp_iter, drm_enc->base.id, SDE_HW_BLK_PINGPONG); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + sde_enc->hw_pp[i] = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &pp_iter)) + break; + sde_enc->hw_pp[i] = (struct sde_hw_pingpong *) pp_iter.hw; + } + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys) { + sde_rm_init_hw_iter(&qdss_iter, drm_enc->base.id, + SDE_HW_BLK_QDSS); + for (i = 0; i < QDSS_MAX; i++) { + if (sde_rm_get_hw(&sde_kms->rm, &qdss_iter)) { + phys->hw_qdss = + (struct sde_hw_qdss *)qdss_iter.hw; + break; + } + } + } + } + + sde_rm_init_hw_iter(&dsc_iter, drm_enc->base.id, SDE_HW_BLK_DSC); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + sde_enc->hw_dsc[i] = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &dsc_iter)) + break; + sde_enc->hw_dsc[i] = (struct sde_hw_dsc *) dsc_iter.hw; + } + + /* Get PP for DSC configuration */ + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + sde_enc->hw_dsc_pp[i] = NULL; + if (!sde_enc->hw_dsc[i]) + continue; + + request_hw.id = sde_enc->hw_dsc[i]->base.id; + request_hw.type = SDE_HW_BLK_PINGPONG; + if (!sde_rm_request_hw_blk(&sde_kms->rm, &request_hw)) + break; + sde_enc->hw_dsc_pp[i] = + (struct sde_hw_pingpong *) request_hw.hw; + } + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys) { + if (!sde_enc->hw_pp[i] && sde_enc->topology.num_intf) { + SDE_ERROR_ENC(sde_enc, + "invalid pingpong block for the encoder\n"); + goto exit; + } + phys->hw_pp = sde_enc->hw_pp[i]; + phys->connector = conn->state->connector; + if (phys->ops.mode_set) + phys->ops.mode_set(phys, mode, adj_mode); + } + } + + /* update resources after seamless mode change */ + if (msm_is_mode_seamless_dms(adj_mode) || + (msm_is_mode_seamless_dyn_clk(adj_mode) && + is_cmd_mode)) + sde_encoder_resource_control(&sde_enc->base, + SDE_ENC_RC_EVENT_POST_MODESET); + else if (msm_is_mode_seamless_poms(adj_mode)) + _sde_encoder_modeset_helper_locked(drm_enc, + SDE_ENC_RC_EVENT_POST_MODESET); +exit: + if (modeset_lock) + mutex_unlock(&sde_crtc->vblank_modeset_ctrl_lock); +} + +void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + int i; + + if (!drm_enc) { + SDE_ERROR("invalid parameters\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc) { + SDE_ERROR("invalid sde encoder\n"); + return; + } + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (phys && phys->ops.control_te) + phys->ops.control_te(phys, enable); + } +} + +static int _sde_encoder_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int rc = 0; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = handler->name; + + rc = input_register_handle(handle); + if (rc) { + pr_err("failed to register input handle\n"); + goto error; + } + + rc = input_open_device(handle); + if (rc) { + pr_err("failed to open input device\n"); + goto error_unregister; + } + + return 0; + +error_unregister: + input_unregister_handle(handle); + +error: + kfree(handle); + + return rc; +} + +static void _sde_encoder_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +/** + * Structure for specifying event parameters on which to receive callbacks. + * This structure will trigger a callback in case of a touch event (specified by + * EV_ABS) where there is a change in X and Y coordinates, + */ +static const struct input_device_id sde_input_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + { }, +}; + +static void _sde_encoder_input_handler_register( + struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + int rc; + + if (!sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) + return; + + if (sde_enc->input_handler && !sde_enc->input_handler->private) { + sde_enc->input_handler->private = sde_enc; + + /* register input handler if not already registered */ + rc = input_register_handler(sde_enc->input_handler); + if (rc) { + SDE_ERROR("input_handler_register failed, rc= %d\n", + rc); + kfree(sde_enc->input_handler); + } + } +} + +static void _sde_encoder_input_handler_unregister( + struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + if (!sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) + return; + + if (sde_enc->input_handler && sde_enc->input_handler->private) { + input_unregister_handler(sde_enc->input_handler); + sde_enc->input_handler->private = NULL; + } + +} + +static int _sde_encoder_input_handler( + struct sde_encoder_virt *sde_enc) +{ + struct input_handler *input_handler = NULL; + int rc = 0; + + if (sde_enc->input_handler) { + SDE_ERROR_ENC(sde_enc, + "input_handle is active. unexpected\n"); + return -EINVAL; + } + + input_handler = kzalloc(sizeof(*sde_enc->input_handler), GFP_KERNEL); + if (!input_handler) + return -ENOMEM; + + input_handler->event = sde_encoder_input_event_handler; + input_handler->connect = _sde_encoder_input_connect; + input_handler->disconnect = _sde_encoder_input_disconnect; + input_handler->name = "sde"; + input_handler->id_table = sde_input_ids; + + sde_enc->input_handler = input_handler; + + return rc; +} + +static void _sde_encoder_virt_enable_helper(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid parameters\n"); + return; + } + + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc || !sde_enc->cur_master) { + SDE_DEBUG("invalid sde encoder/master\n"); + return; + } + + if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DisplayPort && + sde_enc->cur_master->hw_mdptop && + sde_enc->cur_master->hw_mdptop->ops.intf_audio_select) + sde_enc->cur_master->hw_mdptop->ops.intf_audio_select( + sde_enc->cur_master->hw_mdptop); + + if (sde_enc->cur_master->hw_mdptop && + sde_enc->cur_master->hw_mdptop->ops.reset_ubwc) + sde_enc->cur_master->hw_mdptop->ops.reset_ubwc( + sde_enc->cur_master->hw_mdptop, + sde_kms->catalog); + + if (sde_enc->cur_master->hw_ctl && + sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1 && + !sde_enc->cur_master->cont_splash_enabled) + sde_enc->cur_master->hw_ctl->ops.setup_intf_cfg_v1( + sde_enc->cur_master->hw_ctl, + &sde_enc->cur_master->intf_cfg_v1); + + _sde_encoder_update_vsync_source(sde_enc, &sde_enc->disp_info, false); + sde_encoder_control_te(drm_enc, true); + + memset(&sde_enc->prv_conn_roi, 0, sizeof(sde_enc->prv_conn_roi)); + memset(&sde_enc->cur_conn_roi, 0, sizeof(sde_enc->cur_conn_roi)); +} + +void sde_encoder_virt_restore(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + int i; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + + if (!sde_enc->cur_master) { + SDE_DEBUG("virt encoder has no master\n"); + return; + } + + memset(&sde_enc->cur_master->intf_cfg_v1, 0, + sizeof(sde_enc->cur_master->intf_cfg_v1)); + sde_enc->idle_pc_restore = true; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys) + continue; + + if (phys->hw_ctl && phys->hw_ctl->ops.clear_pending_flush) + phys->hw_ctl->ops.clear_pending_flush(phys->hw_ctl); + + if ((phys != sde_enc->cur_master) && phys->ops.restore) + phys->ops.restore(phys); + } + + if (sde_enc->cur_master->ops.restore) + sde_enc->cur_master->ops.restore(sde_enc->cur_master); + + _sde_encoder_virt_enable_helper(drm_enc); +} + +static void sde_encoder_off_work(struct kthread_work *work) +{ + struct sde_encoder_virt *sde_enc = container_of(work, + struct sde_encoder_virt, delayed_off_work.work); + struct drm_encoder *drm_enc; + + if (!sde_enc) { + SDE_ERROR("invalid sde encoder\n"); + return; + } + drm_enc = &sde_enc->base; + + SDE_ATRACE_BEGIN("sde_encoder_off_work"); + sde_encoder_idle_request(drm_enc); + SDE_ATRACE_END("sde_encoder_off_work"); +} + +static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + int i, ret = 0; + struct msm_compression_info *comp_info = NULL; + struct drm_display_mode *cur_mode = NULL; + struct msm_display_info *disp_info; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + disp_info = &sde_enc->disp_info; + + if (!sde_kms_power_resource_is_enabled(drm_enc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + if (drm_enc->crtc && !sde_enc->crtc) + sde_enc->crtc = drm_enc->crtc; + + comp_info = &sde_enc->mode_info.comp_info; + cur_mode = &sde_enc->base.crtc->state->adjusted_mode; + + SDE_DEBUG_ENC(sde_enc, "\n"); + SDE_EVT32(DRMID(drm_enc), cur_mode->hdisplay, cur_mode->vdisplay); + + sde_enc->cur_master = NULL; + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.is_master && phys->ops.is_master(phys)) { + SDE_DEBUG_ENC(sde_enc, "master is now idx %d\n", i); + sde_enc->cur_master = phys; + break; + } + } + + if (!sde_enc->cur_master) { + SDE_ERROR("virt encoder has no master! num_phys %d\n", i); + return; + } + + _sde_encoder_input_handler_register(drm_enc); + + if ((drm_enc->crtc && drm_enc->crtc->state && + drm_enc->crtc->state->connectors_changed && + sde_encoder_in_clone_mode(drm_enc)) || + !(msm_is_mode_seamless_vrr(cur_mode) + || msm_is_mode_seamless_dms(cur_mode) + || msm_is_mode_seamless_dyn_clk(cur_mode))) + kthread_init_delayed_work(&sde_enc->delayed_off_work, + sde_encoder_off_work); + + ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF); + if (ret) { + SDE_ERROR_ENC(sde_enc, "sde resource control failed: %d\n", + ret); + return; + } + + memset(&sde_enc->cur_master->intf_cfg_v1, 0, + sizeof(sde_enc->cur_master->intf_cfg_v1)); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys) + continue; + + phys->comp_type = comp_info->comp_type; + phys->comp_ratio = comp_info->comp_ratio; + phys->wide_bus_en = sde_enc->mode_info.wide_bus_en; + phys->frame_trigger_mode = sde_enc->frame_trigger_mode; + if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) { + phys->dsc_extra_pclk_cycle_cnt = + comp_info->dsc_info.pclk_per_line; + phys->dsc_extra_disp_width = + comp_info->dsc_info.extra_width; + } + if (phys != sde_enc->cur_master) { + /** + * on DMS request, the encoder will be enabled + * already. Invoke restore to reconfigure the + * new mode. + */ + if ((msm_is_mode_seamless_dms(cur_mode) || + msm_is_mode_seamless_dyn_clk(cur_mode)) && + phys->ops.restore) + phys->ops.restore(phys); + else if (phys->ops.enable) + phys->ops.enable(phys); + } + + if (sde_enc->misr_enable && phys->ops.setup_misr && + (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_VIDEO_MODE))) + phys->ops.setup_misr(phys, true, + sde_enc->misr_frame_count); + } + + if ((msm_is_mode_seamless_dms(cur_mode) || + msm_is_mode_seamless_dyn_clk(cur_mode)) && + sde_enc->cur_master->ops.restore) + sde_enc->cur_master->ops.restore(sde_enc->cur_master); + else if (sde_enc->cur_master->ops.enable) + sde_enc->cur_master->ops.enable(sde_enc->cur_master); + + _sde_encoder_virt_enable_helper(drm_enc); +} + +static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + enum sde_intf_mode intf_mode; + int i = 0; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } else if (!drm_enc->dev) { + SDE_ERROR("invalid dev\n"); + return; + } else if (!drm_enc->dev->dev_private) { + SDE_ERROR("invalid dev_private\n"); + return; + } + + if (!sde_kms_power_resource_is_enabled(drm_enc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "\n"); + + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + intf_mode = sde_encoder_get_intf_mode(drm_enc); + + SDE_EVT32(DRMID(drm_enc)); + + /* wait for idle */ + sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); + + _sde_encoder_input_handler_unregister(drm_enc); + + /* + * For primary command mode and video mode encoders, execute the + * resource control pre-stop operations before the physical encoders + * are disabled, to allow the rsc to transition its states properly. + * + * For other encoder types, rsc should not be enabled until after + * they have been fully disabled, so delay the pre-stop operations + * until after the physical disable calls have returned. + */ + if (sde_enc->disp_info.display_type == SDE_CONNECTOR_PRIMARY && + (intf_mode == INTF_MODE_CMD || intf_mode == INTF_MODE_VIDEO)) { + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_PRE_STOP); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.disable) + phys->ops.disable(phys); + } + } else { + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.disable) + phys->ops.disable(phys); + } + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_PRE_STOP); + } + + /* + * disable dsc after the transfer is complete (for command mode) + * and after physical encoder is disabled, to make sure timing + * engine is already disabled (for video mode). + */ + _sde_encoder_dsc_disable(sde_enc); + + sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_STOP); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + if (sde_enc->phys_encs[i]) { + sde_enc->phys_encs[i]->cont_splash_enabled = false; + sde_enc->phys_encs[i]->connector = NULL; + } + atomic_set(&sde_enc->frame_done_cnt[i], 0); + } + + sde_enc->cur_master = NULL; + /* + * clear the cached crtc in sde_enc on use case finish, after all the + * outstanding events and timers have been completed + */ + sde_enc->crtc = NULL; + memset(&sde_enc->mode_info, 0, sizeof(sde_enc->mode_info)); + + SDE_DEBUG_ENC(sde_enc, "encoder disabled\n"); + + sde_rm_release(&sde_kms->rm, drm_enc, false); +} + +void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc, + struct sde_encoder_phys_wb *wb_enc) +{ + struct sde_encoder_virt *sde_enc; + + phys_enc->hw_ctl->ops.reset(phys_enc->hw_ctl); + sde_encoder_helper_reset_mixers(phys_enc, NULL); + + if (wb_enc) { + if (wb_enc->hw_wb->ops.bind_pingpong_blk) { + wb_enc->hw_wb->ops.bind_pingpong_blk(wb_enc->hw_wb, + false, phys_enc->hw_pp->idx); + + if (phys_enc->hw_ctl->ops.update_bitmask_wb) + phys_enc->hw_ctl->ops.update_bitmask_wb( + phys_enc->hw_ctl, + wb_enc->hw_wb->idx, true); + } + } else { + if (phys_enc->hw_intf->ops.bind_pingpong_blk) { + phys_enc->hw_intf->ops.bind_pingpong_blk( + phys_enc->hw_intf, false, + phys_enc->hw_pp->idx); + + if (phys_enc->hw_ctl->ops.update_bitmask_intf) + phys_enc->hw_ctl->ops.update_bitmask_intf( + phys_enc->hw_ctl, + phys_enc->hw_intf->idx, true); + } + } + + if (phys_enc->hw_pp && phys_enc->hw_pp->ops.reset_3d_mode) { + phys_enc->hw_pp->ops.reset_3d_mode(phys_enc->hw_pp); + + if (phys_enc->hw_ctl->ops.update_bitmask_merge3d && + phys_enc->hw_pp->merge_3d) + phys_enc->hw_ctl->ops.update_bitmask_merge3d( + phys_enc->hw_ctl, + phys_enc->hw_pp->merge_3d->idx, true); + } + + if (phys_enc->hw_cdm && phys_enc->hw_cdm->ops.bind_pingpong_blk && + phys_enc->hw_pp) { + phys_enc->hw_cdm->ops.bind_pingpong_blk(phys_enc->hw_cdm, + false, phys_enc->hw_pp->idx); + + if (phys_enc->hw_ctl->ops.update_bitmask_cdm) + phys_enc->hw_ctl->ops.update_bitmask_cdm( + phys_enc->hw_ctl, + phys_enc->hw_cdm->idx, true); + } + + sde_enc = to_sde_encoder_virt(phys_enc->parent); + + if (phys_enc == sde_enc->cur_master && phys_enc->hw_pp && + phys_enc->hw_ctl->ops.reset_post_disable) + phys_enc->hw_ctl->ops.reset_post_disable( + phys_enc->hw_ctl, &phys_enc->intf_cfg_v1, + phys_enc->hw_pp->merge_3d ? + phys_enc->hw_pp->merge_3d->idx : 0); + + phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl); + phys_enc->hw_ctl->ops.trigger_start(phys_enc->hw_ctl); +} + +static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog, + enum sde_intf_type type, u32 controller_id) +{ + int i = 0; + + for (i = 0; i < catalog->intf_count; i++) { + if (catalog->intf[i].type == type + && catalog->intf[i].controller_id == controller_id) { + return catalog->intf[i].id; + } + } + + return INTF_MAX; +} + +static enum sde_wb sde_encoder_get_wb(struct sde_mdss_cfg *catalog, + enum sde_intf_type type, u32 controller_id) +{ + if (controller_id < catalog->wb_count) + return catalog->wb[controller_id].id; + + return WB_MAX; +} + +void sde_encoder_perf_uidle_status(struct sde_kms *sde_kms, + struct drm_crtc *crtc) +{ + struct sde_hw_uidle *uidle; + struct sde_uidle_cntr cntr; + struct sde_uidle_status status; + + if (!sde_kms || !crtc || !sde_kms->hw_uidle) { + pr_err("invalid params %d %d\n", + !sde_kms, !crtc); + return; + } + + /* check if perf counters are enabled and setup */ + if (!sde_kms->catalog->uidle_cfg.perf_cntr_en) + return; + + uidle = sde_kms->hw_uidle; + if ((sde_kms->catalog->uidle_cfg.debugfs_perf & SDE_PERF_UIDLE_STATUS) + && uidle->ops.uidle_get_status) { + + uidle->ops.uidle_get_status(uidle, &status); + trace_sde_perf_uidle_status( + crtc->base.id, + status.uidle_danger_status_0, + status.uidle_danger_status_1, + status.uidle_safe_status_0, + status.uidle_safe_status_1, + status.uidle_idle_status_0, + status.uidle_idle_status_1, + status.uidle_fal_status_0, + status.uidle_fal_status_1, + status.uidle_status, + status.uidle_en_fal10); + } + + if ((sde_kms->catalog->uidle_cfg.debugfs_perf & SDE_PERF_UIDLE_CNT) + && uidle->ops.uidle_get_cntr) { + + uidle->ops.uidle_get_cntr(uidle, &cntr); + trace_sde_perf_uidle_cntr( + crtc->base.id, + cntr.fal1_gate_cntr, + cntr.fal10_gate_cntr, + cntr.fal_wait_gate_cntr, + cntr.fal1_num_transitions_cntr, + cntr.fal10_num_transitions_cntr, + cntr.min_gate_cntr, + cntr.max_gate_cntr); + } +} + +static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc, + struct sde_encoder_phys *phy_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + unsigned long lock_flags; + + if (!drm_enc || !phy_enc) + return; + + SDE_ATRACE_BEGIN("encoder_vblank_callback"); + sde_enc = to_sde_encoder_virt(drm_enc); + + spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags); + if (sde_enc->crtc_vblank_cb) + sde_enc->crtc_vblank_cb(sde_enc->crtc_vblank_cb_data); + spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); + + if (phy_enc->sde_kms && + phy_enc->sde_kms->catalog->uidle_cfg.debugfs_perf) + sde_encoder_perf_uidle_status(phy_enc->sde_kms, sde_enc->crtc); + + atomic_inc(&phy_enc->vsync_cnt); + SDE_ATRACE_END("encoder_vblank_callback"); +} + +static void sde_encoder_underrun_callback(struct drm_encoder *drm_enc, + struct sde_encoder_phys *phy_enc) +{ + if (!phy_enc) + return; + + SDE_ATRACE_BEGIN("encoder_underrun_callback"); + atomic_inc(&phy_enc->underrun_cnt); + SDE_EVT32(DRMID(drm_enc), atomic_read(&phy_enc->underrun_cnt)); + + trace_sde_encoder_underrun(DRMID(drm_enc), + atomic_read(&phy_enc->underrun_cnt)); + + SDE_DBG_CTRL("stop_ftrace"); + SDE_DBG_CTRL("panic_underrun"); + + SDE_ATRACE_END("encoder_underrun_callback"); +} + +void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc, + void (*vbl_cb)(void *), void *vbl_data) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + unsigned long lock_flags; + bool enable; + int i; + + enable = vbl_cb ? true : false; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + SDE_DEBUG_ENC(sde_enc, "\n"); + SDE_EVT32(DRMID(drm_enc), enable); + + if (sde_encoder_in_clone_mode(drm_enc)) { + SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_ERROR); + return; + } + + spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags); + sde_enc->crtc_vblank_cb = vbl_cb; + sde_enc->crtc_vblank_cb_data = vbl_data; + spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys && phys->ops.control_vblank_irq) + phys->ops.control_vblank_irq(phys, enable); + } + sde_enc->vblank_enabled = enable; +} + +void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc, + void (*frame_event_cb)(void *, u32 event), + struct drm_crtc *crtc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + unsigned long lock_flags; + bool enable; + + enable = frame_event_cb ? true : false; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + SDE_DEBUG_ENC(sde_enc, "\n"); + SDE_EVT32(DRMID(drm_enc), enable, 0); + + spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags); + sde_enc->crtc_frame_event_cb = frame_event_cb; + sde_enc->crtc_frame_event_cb_data.crtc = crtc; + spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); +} + +static void sde_encoder_frame_done_callback( + struct drm_encoder *drm_enc, + struct sde_encoder_phys *ready_phys, u32 event) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + unsigned int i; + bool trigger = true; + bool is_cmd_mode = false; + enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE; + + if (!drm_enc || !sde_enc->cur_master) { + SDE_ERROR("invalid param: drm_enc %pK, cur_master %pK\n", + drm_enc, drm_enc ? sde_enc->cur_master : 0); + return; + } + + sde_enc->crtc_frame_event_cb_data.connector = + sde_enc->cur_master->connector; + if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE)) + is_cmd_mode = true; + + if (event & (SDE_ENCODER_FRAME_EVENT_DONE + | SDE_ENCODER_FRAME_EVENT_ERROR + | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) && is_cmd_mode) { + + if (ready_phys->connector) + topology = sde_connector_get_topology_name( + ready_phys->connector); + + /* One of the physical encoders has become idle */ + for (i = 0; i < sde_enc->num_phys_encs; i++) { + if (sde_enc->phys_encs[i] == ready_phys) { + SDE_EVT32_VERBOSE(DRMID(drm_enc), i, + atomic_read(&sde_enc->frame_done_cnt[i])); + if (atomic_inc_return( + &sde_enc->frame_done_cnt[i]) > 1) + SDE_EVT32(DRMID(drm_enc), event, + ready_phys->intf_idx, + SDE_EVTLOG_ERROR); + } + + if (topology != SDE_RM_TOPOLOGY_PPSPLIT && + !atomic_read(&sde_enc->frame_done_cnt[i])) + trigger = false; + } + + if (trigger) { + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_FRAME_DONE); + + if (sde_enc->crtc_frame_event_cb) + sde_enc->crtc_frame_event_cb( + &sde_enc->crtc_frame_event_cb_data, + event); + for (i = 0; i < sde_enc->num_phys_encs; i++) + atomic_dec(&sde_enc->frame_done_cnt[i]); + } + } else if (sde_enc->crtc_frame_event_cb) { + if (!is_cmd_mode) + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_FRAME_DONE); + + sde_enc->crtc_frame_event_cb( + &sde_enc->crtc_frame_event_cb_data, event); + } +} + +static void sde_encoder_get_qsync_fps_callback( + struct drm_encoder *drm_enc, + u32 *qsync_fps) +{ + struct msm_display_info *disp_info; + struct sde_encoder_virt *sde_enc; + + if (!qsync_fps) + return; + + *qsync_fps = 0; + if (!drm_enc) { + SDE_ERROR("invalid drm encoder\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + disp_info = &sde_enc->disp_info; + *qsync_fps = disp_info->qsync_min_fps; +} + +int sde_encoder_idle_request(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) { + SDE_ERROR("invalid drm encoder\n"); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + sde_encoder_resource_control(&sde_enc->base, + SDE_ENC_RC_EVENT_ENTER_IDLE); + + return 0; +} + +/** + * _sde_encoder_trigger_flush - trigger flush for a physical encoder + * drm_enc: Pointer to drm encoder structure + * phys: Pointer to physical encoder structure + * extra_flush: Additional bit mask to include in flush trigger + */ +static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc, + struct sde_encoder_phys *phys, + struct sde_ctl_flush_cfg *extra_flush) +{ + struct sde_hw_ctl *ctl; + unsigned long lock_flags; + struct sde_encoder_virt *sde_enc; + int pend_ret_fence_cnt; + struct sde_connector *c_conn; + + if (!drm_enc || !phys) { + SDE_ERROR("invalid argument(s), drm_enc %d, phys_enc %d\n", + !drm_enc, !phys); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + c_conn = to_sde_connector(phys->connector); + + if (!phys->hw_pp) { + SDE_ERROR("invalid pingpong hw\n"); + return; + } + + ctl = phys->hw_ctl; + if (!ctl || !phys->ops.trigger_flush) { + SDE_ERROR("missing ctl/trigger cb\n"); + return; + } + + if (phys->split_role == ENC_ROLE_SKIP) { + SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent), + "skip flush pp%d ctl%d\n", + phys->hw_pp->idx - PINGPONG_0, + ctl->idx - CTL_0); + return; + } + + /* update pending counts and trigger kickoff ctl flush atomically */ + spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags); + + if (phys->ops.is_master && phys->ops.is_master(phys)) + atomic_inc(&phys->pending_retire_fence_cnt); + + pend_ret_fence_cnt = atomic_read(&phys->pending_retire_fence_cnt); + + if (phys->hw_intf && phys->hw_intf->cap->type == INTF_DP && + ctl->ops.update_bitmask_periph) { + /* perform peripheral flush on every frame update for dp dsc */ + if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC && + phys->comp_ratio && c_conn->ops.update_pps) { + c_conn->ops.update_pps(phys->connector, NULL, + c_conn->display); + ctl->ops.update_bitmask_periph(ctl, + phys->hw_intf->idx, 1); + } + + if (sde_enc->dynamic_hdr_updated) + ctl->ops.update_bitmask_periph(ctl, + phys->hw_intf->idx, 1); + } + + if ((extra_flush && extra_flush->pending_flush_mask) + && ctl->ops.update_pending_flush) + ctl->ops.update_pending_flush(ctl, extra_flush); + + phys->ops.trigger_flush(phys); + + spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); + + if (ctl->ops.get_pending_flush) { + struct sde_ctl_flush_cfg pending_flush = {0,}; + + ctl->ops.get_pending_flush(ctl, &pending_flush); + SDE_EVT32(DRMID(drm_enc), phys->intf_idx - INTF_0, + ctl->idx - CTL_0, + pending_flush.pending_flush_mask, + pend_ret_fence_cnt); + } else { + SDE_EVT32(DRMID(drm_enc), phys->intf_idx - INTF_0, + ctl->idx - CTL_0, + pend_ret_fence_cnt); + } +} + +/** + * _sde_encoder_trigger_start - trigger start for a physical encoder + * phys: Pointer to physical encoder structure + */ +static inline void _sde_encoder_trigger_start(struct sde_encoder_phys *phys) +{ + struct sde_hw_ctl *ctl; + struct sde_encoder_virt *sde_enc; + + if (!phys) { + SDE_ERROR("invalid argument(s)\n"); + return; + } + + if (!phys->hw_pp) { + SDE_ERROR("invalid pingpong hw\n"); + return; + } + + if (!phys->parent) { + SDE_ERROR("invalid parent\n"); + return; + } + /* avoid ctrl start for encoder in clone mode */ + if (phys->in_clone_mode) + return; + + ctl = phys->hw_ctl; + sde_enc = to_sde_encoder_virt(phys->parent); + + if (phys->split_role == ENC_ROLE_SKIP) { + SDE_DEBUG_ENC(sde_enc, + "skip start pp%d ctl%d\n", + phys->hw_pp->idx - PINGPONG_0, + ctl->idx - CTL_0); + return; + } + + if (phys->ops.trigger_start && phys->enable_state != SDE_ENC_DISABLED) + phys->ops.trigger_start(phys); +} + +void sde_encoder_helper_trigger_flush(struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_ctl *ctl; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + ctl = phys_enc->hw_ctl; + if (ctl && ctl->ops.trigger_flush) + ctl->ops.trigger_flush(ctl); +} + +void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_ctl *ctl; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + ctl = phys_enc->hw_ctl; + if (ctl && ctl->ops.trigger_start) { + ctl->ops.trigger_start(ctl); + SDE_EVT32(DRMID(phys_enc->parent), ctl->idx - CTL_0); + } +} + +void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_connector *sde_con; + void *sde_con_disp; + struct sde_hw_ctl *ctl; + int rc; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(phys_enc->parent); + ctl = phys_enc->hw_ctl; + + if (!ctl || !ctl->ops.reset) + return; + + SDE_DEBUG_ENC(sde_enc, "ctl %d reset\n", ctl->idx); + SDE_EVT32(DRMID(phys_enc->parent), ctl->idx); + + if (phys_enc->ops.is_master && phys_enc->ops.is_master(phys_enc) && + phys_enc->connector) { + sde_con = to_sde_connector(phys_enc->connector); + sde_con_disp = sde_connector_get_display(phys_enc->connector); + + if (sde_con->ops.soft_reset) { + rc = sde_con->ops.soft_reset(sde_con_disp); + if (rc) { + SDE_ERROR_ENC(sde_enc, + "connector soft reset failure\n"); + SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", + "panic"); + } + } + } + + phys_enc->enable_state = SDE_ENC_ENABLED; +} + +/** + * _sde_encoder_kickoff_phys - handle physical encoder kickoff + * Iterate through the physical encoders and perform consolidated flush + * and/or control start triggering as needed. This is done in the virtual + * encoder rather than the individual physical ones in order to handle + * use cases that require visibility into multiple physical encoders at + * a time. + * sde_enc: Pointer to virtual encoder structure + */ +static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) +{ + struct sde_hw_ctl *ctl; + uint32_t i; + struct sde_ctl_flush_cfg pending_flush = {0,}; + u32 pending_kickoff_cnt; + struct msm_drm_private *priv = NULL; + struct sde_kms *sde_kms = NULL; + struct sde_crtc_misr_info crtc_misr_info = {false, 0}; + bool is_regdma_blocking = false, is_vid_mode = false; + + if (!sde_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_VIDEO_MODE)) + is_vid_mode = true; + + is_regdma_blocking = (is_vid_mode || + _sde_encoder_is_autorefresh_enabled(sde_enc)); + + /* don't perform flush/start operations for slave encoders */ + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE; + + if (!phys || phys->enable_state == SDE_ENC_DISABLED) + continue; + + ctl = phys->hw_ctl; + if (!ctl) + continue; + + if (phys->connector) + topology = sde_connector_get_topology_name( + phys->connector); + + if (!phys->ops.needs_single_flush || + !phys->ops.needs_single_flush(phys)) { + if (ctl->ops.reg_dma_flush) + ctl->ops.reg_dma_flush(ctl, is_regdma_blocking); + _sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0); + } else if (ctl->ops.get_pending_flush) { + ctl->ops.get_pending_flush(ctl, &pending_flush); + } + } + + /* for split flush, combine pending flush masks and send to master */ + if (pending_flush.pending_flush_mask && sde_enc->cur_master) { + ctl = sde_enc->cur_master->hw_ctl; + if (ctl->ops.reg_dma_flush) + ctl->ops.reg_dma_flush(ctl, is_regdma_blocking); + _sde_encoder_trigger_flush(&sde_enc->base, sde_enc->cur_master, + &pending_flush); + } + + /* update pending_kickoff_cnt AFTER flush but before trigger start */ + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys || phys->enable_state == SDE_ENC_DISABLED) + continue; + + if (!phys->ops.needs_single_flush || + !phys->ops.needs_single_flush(phys)) { + pending_kickoff_cnt = + sde_encoder_phys_inc_pending(phys); + SDE_EVT32(pending_kickoff_cnt, SDE_EVTLOG_FUNC_CASE1); + } else { + pending_kickoff_cnt = + sde_encoder_phys_inc_pending(phys); + SDE_EVT32(pending_kickoff_cnt, + pending_flush.pending_flush_mask, + SDE_EVTLOG_FUNC_CASE2); + } + } + + if (sde_enc->misr_enable) + sde_encoder_misr_configure(&sde_enc->base, true, + sde_enc->misr_frame_count); + + sde_crtc_get_misr_info(sde_enc->crtc, &crtc_misr_info); + if (crtc_misr_info.misr_enable) + sde_crtc_misr_setup(sde_enc->crtc, true, + crtc_misr_info.misr_frame_count); + + _sde_encoder_trigger_start(sde_enc->cur_master); + + if (sde_enc->elevated_ahb_vote) { + priv = sde_enc->base.dev->dev_private; + if (priv != NULL) { + sde_kms = to_sde_kms(priv->kms); + if (sde_kms != NULL) { + sde_power_scale_reg_bus(&priv->phandle, + VOTE_INDEX_LOW, + false); + } + } + sde_enc->elevated_ahb_vote = false; + } + +} + +static void _sde_encoder_ppsplit_swap_intf_for_right_only_update( + struct drm_encoder *drm_enc, + unsigned long *affected_displays, + int num_active_phys) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *master; + enum sde_rm_topology_name topology; + bool is_right_only; + + if (!drm_enc || !affected_displays) + return; + + sde_enc = to_sde_encoder_virt(drm_enc); + master = sde_enc->cur_master; + if (!master || !master->connector) + return; + + topology = sde_connector_get_topology_name(master->connector); + if (topology != SDE_RM_TOPOLOGY_PPSPLIT) + return; + + /* + * For pingpong split, the slave pingpong won't generate IRQs. For + * right-only updates, we can't swap pingpongs, or simply swap the + * master/slave assignment, we actually have to swap the interfaces + * so that the master physical encoder will use a pingpong/interface + * that generates irqs on which to wait. + */ + is_right_only = !test_bit(0, affected_displays) && + test_bit(1, affected_displays); + + if (is_right_only && !sde_enc->intfs_swapped) { + /* right-only update swap interfaces */ + swap(sde_enc->phys_encs[0]->intf_idx, + sde_enc->phys_encs[1]->intf_idx); + sde_enc->intfs_swapped = true; + } else if (!is_right_only && sde_enc->intfs_swapped) { + /* left-only or full update, swap back */ + swap(sde_enc->phys_encs[0]->intf_idx, + sde_enc->phys_encs[1]->intf_idx); + sde_enc->intfs_swapped = false; + } + + SDE_DEBUG_ENC(sde_enc, + "right_only %d swapped %d phys0->intf%d, phys1->intf%d\n", + is_right_only, sde_enc->intfs_swapped, + sde_enc->phys_encs[0]->intf_idx - INTF_0, + sde_enc->phys_encs[1]->intf_idx - INTF_0); + SDE_EVT32(DRMID(drm_enc), is_right_only, sde_enc->intfs_swapped, + sde_enc->phys_encs[0]->intf_idx - INTF_0, + sde_enc->phys_encs[1]->intf_idx - INTF_0, + *affected_displays); + + /* ppsplit always uses master since ppslave invalid for irqs*/ + if (num_active_phys == 1) + *affected_displays = BIT(0); +} + +static void _sde_encoder_update_master(struct drm_encoder *drm_enc, + struct sde_encoder_kickoff_params *params) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + int i, num_active_phys; + bool master_assigned = false; + + if (!drm_enc || !params) + return; + + sde_enc = to_sde_encoder_virt(drm_enc); + + if (sde_enc->num_phys_encs <= 1) + return; + + /* count bits set */ + num_active_phys = hweight_long(params->affected_displays); + + SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n", + params->affected_displays, num_active_phys); + SDE_EVT32_VERBOSE(DRMID(drm_enc), params->affected_displays, + num_active_phys); + + /* for left/right only update, ppsplit master switches interface */ + _sde_encoder_ppsplit_swap_intf_for_right_only_update(drm_enc, + ¶ms->affected_displays, num_active_phys); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + enum sde_enc_split_role prv_role, new_role; + bool active = false; + + phys = sde_enc->phys_encs[i]; + if (!phys || !phys->ops.update_split_role || !phys->hw_pp) + continue; + + active = test_bit(i, ¶ms->affected_displays); + prv_role = phys->split_role; + + if (active && num_active_phys == 1) + new_role = ENC_ROLE_SOLO; + else if (active && !master_assigned) + new_role = ENC_ROLE_MASTER; + else if (active) + new_role = ENC_ROLE_SLAVE; + else + new_role = ENC_ROLE_SKIP; + + phys->ops.update_split_role(phys, new_role); + if (new_role == ENC_ROLE_SOLO || new_role == ENC_ROLE_MASTER) { + sde_enc->cur_master = phys; + master_assigned = true; + } + + SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n", + phys->hw_pp->idx - PINGPONG_0, prv_role, + phys->split_role, active); + SDE_EVT32(DRMID(drm_enc), params->affected_displays, + phys->hw_pp->idx - PINGPONG_0, prv_role, + phys->split_role, active, num_active_phys); + } +} + +bool sde_encoder_check_curr_mode(struct drm_encoder *drm_enc, u32 mode) +{ + struct sde_encoder_virt *sde_enc; + struct msm_display_info *disp_info; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return false; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + disp_info = &sde_enc->disp_info; + + return (disp_info->curr_panel_mode == mode); +} + +void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + unsigned int i; + struct sde_hw_ctl *ctl; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + + if (phys && phys->hw_ctl && (phys == sde_enc->cur_master) && + sde_encoder_check_curr_mode(drm_enc, + MSM_DISPLAY_CMD_MODE)) { + ctl = phys->hw_ctl; + if (ctl->ops.trigger_pending) + /* update only for command mode primary ctl */ + ctl->ops.trigger_pending(ctl); + } + } + sde_enc->idle_pc_restore = false; +} + +//Vikas@OnePlus.MultiMediaService,2020/03/13, force enable dither on Fingerprint scene +extern bool sde_crtc_get_fingerprint_mode(struct drm_crtc_state *crtc_state); +static bool +_sde_encoder_setup_dither_for_onscreenfingerprint(struct sde_encoder_phys *phys,struct sde_hw_pingpong *hw_pp, + void *dither_cfg, int len) +{ + struct drm_encoder *drm_enc = phys->parent; + struct drm_msm_dither dither; + + if (!drm_enc || !drm_enc->crtc) + return -EFAULT; + + if (!sde_crtc_get_fingerprint_mode(drm_enc->crtc->state)) + return -EINVAL; + + if (len != sizeof(dither)) + return -EINVAL; + + memcpy(&dither, dither_cfg, len); + dither.c0_bitdepth = 8; + dither.c1_bitdepth = 8; + dither.c2_bitdepth = 8; + dither.c3_bitdepth = 8; + dither.temporal_en = 1; + + phys->hw_pp->ops.setup_dither(hw_pp, &dither, len); + + return 0; +} +static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) +{ + void *dither_cfg; + int ret = 0, i = 0; + size_t len = 0; + enum sde_rm_topology_name topology; + struct drm_encoder *drm_enc; + struct msm_display_dsc_info *dsc = NULL; + struct sde_encoder_virt *sde_enc; + struct sde_hw_pingpong *hw_pp; + + if (!phys || !phys->connector || !phys->hw_pp || + !phys->hw_pp->ops.setup_dither || !phys->parent) + return; + + topology = sde_connector_get_topology_name(phys->connector); + if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) && + (phys->split_role == ENC_ROLE_SLAVE)) + return; + + drm_enc = phys->parent; + sde_enc = to_sde_encoder_virt(drm_enc); + dsc = &sde_enc->mode_info.comp_info.dsc_info; + /* disable dither for 10 bpp or 10bpc dsc config */ + if (dsc->bpp == 10 || dsc->bpc == 10) { + phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0); + return; + } + + ret = sde_connector_get_dither_cfg(phys->connector, + phys->connector->state, &dither_cfg, &len); + if (ret) + return; + + if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) { + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + hw_pp = sde_enc->hw_pp[i]; + if (hw_pp) { + if (_sde_encoder_setup_dither_for_onscreenfingerprint(phys,hw_pp, dither_cfg, len)) + phys->hw_pp->ops.setup_dither(hw_pp, dither_cfg, + len); + } + } + } else { + phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len); + } +} + +static int _sde_encoder_wakeup_time(struct drm_encoder *drm_enc, + ktime_t *wakeup_time) +{ + struct drm_display_mode *mode; + struct sde_encoder_virt *sde_enc; + u32 cur_line, lines_left; + u32 line_time, mdp_transfer_time_us; + u32 vtotal, time_to_vsync_us, threshold_time_us = 0; + ktime_t cur_time; + + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc || !sde_enc->cur_master) { + SDE_ERROR("invalid sde encoder/master\n"); + return -EINVAL; + } + + mode = &sde_enc->cur_master->cached_mode; + mdp_transfer_time_us = sde_enc->mode_info.mdp_transfer_time_us; + + vtotal = mode->vtotal; + if (!mdp_transfer_time_us) { + /* mdp_transfer_time set to 0 for video mode */ + line_time = (1000000 / sde_enc->mode_info.frame_rate) / vtotal; + } else { + line_time = mdp_transfer_time_us / vtotal; + threshold_time_us = ((1000000 / sde_enc->mode_info.frame_rate) + - mdp_transfer_time_us); + } + + if (!sde_enc->cur_master->ops.get_line_count) { + SDE_DEBUG_ENC(sde_enc, "can't get master line count\n"); + return -EINVAL; + } + + cur_line = sde_enc->cur_master->ops.get_line_count(sde_enc->cur_master); + + lines_left = (cur_line >= vtotal) ? vtotal : (vtotal - cur_line); + + time_to_vsync_us = line_time * lines_left; + + if (!time_to_vsync_us) { + SDE_ERROR("time to vsync should not be zero, vtotal=%d\n", + vtotal); + return -EINVAL; + } + + cur_time = ktime_get(); + *wakeup_time = ktime_add_us(cur_time, time_to_vsync_us); + if (threshold_time_us) + *wakeup_time = ktime_add_us(*wakeup_time, threshold_time_us); + + SDE_DEBUG_ENC(sde_enc, + "cur_line=%u vtotal=%u time_to_vsync=%u, cur_time=%lld, wakeup_time=%lld\n", + cur_line, vtotal, time_to_vsync_us, + ktime_to_ms(cur_time), + ktime_to_ms(*wakeup_time)); + return 0; +} + +static void sde_encoder_vsync_event_handler(struct timer_list *t) +{ + struct drm_encoder *drm_enc; + struct sde_encoder_virt *sde_enc = + from_timer(sde_enc, t, vsync_event_timer); + struct msm_drm_private *priv; + struct msm_drm_thread *event_thread; + + if (!sde_enc || !sde_enc->crtc) { + SDE_ERROR("invalid encoder parameters %d\n", !sde_enc); + return; + } + + drm_enc = &sde_enc->base; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid encoder parameters\n"); + return; + } + + priv = drm_enc->dev->dev_private; + + if (sde_enc->crtc->index >= ARRAY_SIZE(priv->event_thread)) { + SDE_ERROR("invalid crtc index:%u\n", + sde_enc->crtc->index); + return; + } + event_thread = &priv->event_thread[sde_enc->crtc->index]; + if (!event_thread) { + SDE_ERROR("event_thread not found for crtc:%d\n", + sde_enc->crtc->index); + return; + } + + kthread_queue_work(&event_thread->worker, + &sde_enc->vsync_event_work); +} + +static void sde_encoder_esd_trigger_work_handler(struct kthread_work *work) +{ + struct sde_encoder_virt *sde_enc = container_of(work, + struct sde_encoder_virt, esd_trigger_work); + + if (!sde_enc) { + SDE_ERROR("invalid sde encoder\n"); + return; + } + + sde_encoder_resource_control(&sde_enc->base, + SDE_ENC_RC_EVENT_KICKOFF); +} + +static void sde_encoder_input_event_work_handler(struct kthread_work *work) +{ + struct sde_encoder_virt *sde_enc = container_of(work, + struct sde_encoder_virt, input_event_work); + + if (!sde_enc) { + SDE_ERROR("invalid sde encoder\n"); + return; + } + + sde_encoder_resource_control(&sde_enc->base, + SDE_ENC_RC_EVENT_EARLY_WAKEUP); +} + +static void sde_encoder_vsync_event_work_handler(struct kthread_work *work) +{ + struct sde_encoder_virt *sde_enc = container_of(work, + struct sde_encoder_virt, vsync_event_work); + bool autorefresh_enabled = false; + int rc = 0; + ktime_t wakeup_time; + struct drm_encoder *drm_enc; + + if (!sde_enc) { + SDE_ERROR("invalid sde encoder\n"); + return; + } + + drm_enc = &sde_enc->base; + rc = pm_runtime_get_sync(drm_enc->dev->dev); + if (rc < 0) { + SDE_ERROR_ENC(sde_enc, "sde enc power enabled failed:%d\n", rc); + return; + } + + if (sde_enc->cur_master && + sde_enc->cur_master->ops.is_autorefresh_enabled) + autorefresh_enabled = + sde_enc->cur_master->ops.is_autorefresh_enabled( + sde_enc->cur_master); + + /* Update timer if autorefresh is enabled else return */ + if (!autorefresh_enabled) + goto exit; + + rc = _sde_encoder_wakeup_time(&sde_enc->base, &wakeup_time); + if (rc) + goto exit; + + SDE_EVT32_VERBOSE(ktime_to_ms(wakeup_time)); + mod_timer(&sde_enc->vsync_event_timer, + nsecs_to_jiffies(ktime_to_ns(wakeup_time))); + +exit: + pm_runtime_put_sync(drm_enc->dev->dev); +} + +int sde_encoder_poll_line_counts(struct drm_encoder *drm_enc) +{ + static const uint64_t timeout_us = 50000; + static const uint64_t sleep_us = 20; + struct sde_encoder_virt *sde_enc; + ktime_t cur_ktime, exp_ktime; + uint32_t line_count, tmp, i; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc->cur_master || + !sde_enc->cur_master->ops.get_line_count) { + SDE_DEBUG_ENC(sde_enc, "can't get master line count\n"); + SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_ERROR); + return -EINVAL; + } + + exp_ktime = ktime_add_ms(ktime_get(), timeout_us / 1000); + + line_count = sde_enc->cur_master->ops.get_line_count( + sde_enc->cur_master); + + for (i = 0; i < (timeout_us * 2 / sleep_us); ++i) { + tmp = line_count; + line_count = sde_enc->cur_master->ops.get_line_count( + sde_enc->cur_master); + if (line_count < tmp) { + SDE_EVT32(DRMID(drm_enc), line_count); + return 0; + } + + cur_ktime = ktime_get(); + if (ktime_compare_safe(exp_ktime, cur_ktime) <= 0) + break; + + usleep_range(sleep_us / 2, sleep_us); + } + + SDE_EVT32(DRMID(drm_enc), line_count, SDE_EVTLOG_ERROR); + return -ETIMEDOUT; +} + +static int _helper_flush_qsync(struct sde_encoder_phys *phys_enc) +{ + struct drm_encoder *drm_enc; + struct sde_rm_hw_iter rm_iter; + bool lm_valid = false; + bool intf_valid = false; + + if (!phys_enc || !phys_enc->parent) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + drm_enc = phys_enc->parent; + + /* Flush the interfaces for AVR update or Qsync with INTF TE */ + if (phys_enc->intf_mode == INTF_MODE_VIDEO || + (phys_enc->intf_mode == INTF_MODE_CMD && + phys_enc->has_intf_te)) { + sde_rm_init_hw_iter(&rm_iter, drm_enc->base.id, + SDE_HW_BLK_INTF); + while (sde_rm_get_hw(&phys_enc->sde_kms->rm, &rm_iter)) { + struct sde_hw_intf *hw_intf = + (struct sde_hw_intf *)rm_iter.hw; + + if (!hw_intf) + continue; + + if (phys_enc->hw_ctl->ops.update_bitmask_intf) + phys_enc->hw_ctl->ops.update_bitmask_intf( + phys_enc->hw_ctl, + hw_intf->idx, 1); + + intf_valid = true; + } + + if (!intf_valid) { + SDE_ERROR_ENC(to_sde_encoder_virt(drm_enc), + "intf not found to flush\n"); + return -EFAULT; + } + } else { + sde_rm_init_hw_iter(&rm_iter, drm_enc->base.id, SDE_HW_BLK_LM); + while (sde_rm_get_hw(&phys_enc->sde_kms->rm, &rm_iter)) { + struct sde_hw_mixer *hw_lm = + (struct sde_hw_mixer *)rm_iter.hw; + + if (!hw_lm) + continue; + + /* update LM flush for HW without INTF TE */ + if (phys_enc->hw_ctl->ops.update_bitmask_mixer) + phys_enc->hw_ctl->ops.update_bitmask_mixer( + phys_enc->hw_ctl, + hw_lm->idx, 1); + + lm_valid = true; + } + + if (!lm_valid) { + SDE_ERROR_ENC(to_sde_encoder_virt(drm_enc), + "lm not found to flush\n"); + return -EFAULT; + } + } + + return 0; +} + +static bool _sde_encoder_dsc_is_dirty(struct sde_encoder_virt *sde_enc) +{ + int i; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + /** + * This dirty_dsc_hw field is set during DSC disable to + * indicate which DSC blocks need to be flushed + */ + if (sde_enc->dirty_dsc_ids[i]) + return true; + } + + return false; +} + +static void _helper_flush_dsc(struct sde_encoder_virt *sde_enc) +{ + int i; + struct sde_hw_ctl *hw_ctl = NULL; + enum sde_dsc dsc_idx; + + if (sde_enc->cur_master) + hw_ctl = sde_enc->cur_master->hw_ctl; + + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + dsc_idx = sde_enc->dirty_dsc_ids[i]; + if (dsc_idx && hw_ctl && hw_ctl->ops.update_bitmask_dsc) + hw_ctl->ops.update_bitmask_dsc(hw_ctl, dsc_idx, 1); + + sde_enc->dirty_dsc_ids[i] = DSC_NONE; + } +} +static void _sde_encoder_helper_hdr_plus_mempool_update( + struct sde_encoder_virt *sde_enc) +{ + struct sde_connector_dyn_hdr_metadata *dhdr_meta = NULL; + struct sde_hw_mdp *mdptop = NULL; + + sde_enc->dynamic_hdr_updated = false; + if (sde_enc->cur_master) { + mdptop = sde_enc->cur_master->hw_mdptop; + dhdr_meta = sde_connector_get_dyn_hdr_meta( + sde_enc->cur_master->connector); + } + + if (!mdptop || !dhdr_meta || !dhdr_meta->dynamic_hdr_update) + return; + + if (mdptop->ops.set_hdr_plus_metadata) { + sde_enc->dynamic_hdr_updated = true; + mdptop->ops.set_hdr_plus_metadata( + mdptop, dhdr_meta->dynamic_hdr_payload, + dhdr_meta->dynamic_hdr_payload_size, + sde_enc->cur_master->intf_idx == INTF_0 ? + 0 : 1); + } +} + +void sde_encoder_needs_hw_reset(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + struct sde_encoder_phys *phys; + int i; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (phys && phys->ops.hw_reset) + phys->ops.hw_reset(phys); + } +} + +extern int sde_connector_update_backlight(struct drm_connector *conn); +int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, + struct sde_encoder_kickoff_params *params) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + struct sde_kms *sde_kms = NULL; + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv = NULL; + bool needs_hw_reset = false, is_cmd_mode; + int i, rc, ret = 0; + struct msm_display_info *disp_info; + + if (!drm_enc || !params || !drm_enc->dev || + !drm_enc->dev->dev_private) { + SDE_ERROR("invalid args\n"); + return -EINVAL; + } + sde_enc = to_sde_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + disp_info = &sde_enc->disp_info; + sde_crtc = to_sde_crtc(sde_enc->crtc); + + SDE_DEBUG_ENC(sde_enc, "\n"); + SDE_EVT32(DRMID(drm_enc)); + //Vikas@OnePlus.MultiMediaService,2020/03/13, add for DC backlight + if (sde_enc->cur_master && (!strcmp(sde_enc->cur_master->connector->name, "DSI-1"))) + sde_connector_update_backlight(sde_enc->cur_master->connector); + + is_cmd_mode = sde_encoder_check_curr_mode(drm_enc, + MSM_DISPLAY_CMD_MODE); + if (sde_enc->cur_master && sde_enc->cur_master->connector + && is_cmd_mode) + sde_enc->frame_trigger_mode = sde_connector_get_property( + sde_enc->cur_master->connector->state, + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE); + + _sde_encoder_helper_hdr_plus_mempool_update(sde_enc); + + /* prepare for next kickoff, may include waiting on previous kickoff */ + SDE_ATRACE_BEGIN("sde_encoder_prepare_for_kickoff"); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + params->frame_trigger_mode = sde_enc->frame_trigger_mode; + params->recovery_events_enabled = + sde_enc->recovery_events_enabled; + if (phys) { + if (phys->ops.prepare_for_kickoff) { + rc = phys->ops.prepare_for_kickoff( + phys, params); + if (rc) + ret = rc; + } + if (phys->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) + needs_hw_reset = true; + _sde_encoder_setup_dither(phys); + + if (sde_enc->cur_master && + sde_connector_is_qsync_updated( + sde_enc->cur_master->connector)) { + _helper_flush_qsync(phys); + } + } + } + + rc = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF); + if (rc) { + SDE_ERROR_ENC(sde_enc, "resource kickoff failed rc %d\n", rc); + ret = rc; + goto end; + } + + /* if any phys needs reset, reset all phys, in-order */ + if (needs_hw_reset) + sde_encoder_needs_hw_reset(drm_enc); + + _sde_encoder_update_master(drm_enc, params); + + _sde_encoder_update_roi(drm_enc); + + if (sde_enc->cur_master && sde_enc->cur_master->connector) { + rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); + if (rc) { + SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n", + sde_enc->cur_master->connector->base.id, + rc); + ret = rc; + } + } + + if (_sde_encoder_is_dsc_enabled(drm_enc) && sde_enc->cur_master && + ((is_cmd_mode && sde_enc->cur_master->cont_splash_enabled) || + !sde_enc->cur_master->cont_splash_enabled)) { + rc = _sde_encoder_dsc_setup(sde_enc, params); + if (rc) { + SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc); + ret = rc; + } + } + + if (_sde_encoder_dsc_is_dirty(sde_enc)) + _helper_flush_dsc(sde_enc); + + if (sde_enc->cur_master && !sde_enc->cur_master->cont_splash_enabled) + sde_configure_qdss(sde_enc, sde_enc->cur_master->hw_qdss, + sde_enc->cur_master, sde_kms->qdss_enabled); + +end: + SDE_ATRACE_END("sde_encoder_prepare_for_kickoff"); + return ret; +} + +/** + * _sde_encoder_reset_ctl_hw - reset h/w configuration for all ctl's associated + * with the specified encoder, and unstage all pipes from it + * @encoder: encoder pointer + * Returns: 0 on success + */ +static int _sde_encoder_reset_ctl_hw(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + unsigned int i; + int rc = 0; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + + SDE_ATRACE_BEGIN("encoder_release_lm"); + SDE_DEBUG_ENC(sde_enc, "\n"); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (!phys) + continue; + + SDE_EVT32(DRMID(drm_enc), phys->intf_idx - INTF_0); + + rc = sde_encoder_helper_reset_mixers(phys, NULL); + if (rc) + SDE_EVT32(DRMID(drm_enc), rc, SDE_EVTLOG_ERROR); + } + + SDE_ATRACE_END("encoder_release_lm"); + return rc; +} + +void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + ktime_t wakeup_time; + unsigned int i; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + SDE_ATRACE_BEGIN("encoder_kickoff"); + sde_enc = to_sde_encoder_virt(drm_enc); + + SDE_DEBUG_ENC(sde_enc, "\n"); + + /* create a 'no pipes' commit to release buffers on errors */ + if (is_error) + _sde_encoder_reset_ctl_hw(drm_enc); + + /* All phys encs are ready to go, trigger the kickoff */ + _sde_encoder_kickoff_phys(sde_enc); + + /* allow phys encs to handle any post-kickoff business */ + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (phys && phys->ops.handle_post_kickoff) + phys->ops.handle_post_kickoff(phys); + } + + if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI && + !_sde_encoder_wakeup_time(drm_enc, &wakeup_time)) { + SDE_EVT32_VERBOSE(ktime_to_ms(wakeup_time)); + mod_timer(&sde_enc->vsync_event_timer, + nsecs_to_jiffies(ktime_to_ns(wakeup_time))); + } + + SDE_ATRACE_END("encoder_kickoff"); +} + +void sde_encoder_helper_get_pp_line_count(struct drm_encoder *drm_enc, + struct sde_hw_pp_vsync_info *info) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + int i, ret; + + if (!drm_enc || !info) + return; + + sde_enc = to_sde_encoder_virt(drm_enc); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (phys && phys->hw_intf && phys->hw_pp + && phys->hw_intf->ops.get_vsync_info) { + ret = phys->hw_intf->ops.get_vsync_info( + phys->hw_intf, &info[i]); + if (!ret) { + info[i].pp_idx = phys->hw_pp->idx - PINGPONG_0; + info[i].intf_idx = phys->hw_intf->idx - INTF_0; + } + } + } +} + +int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb) +{ + struct drm_encoder *drm_enc; + struct sde_hw_mixer_cfg mixer; + struct sde_rm_hw_iter lm_iter; + bool lm_valid = false; + + if (!phys_enc || !phys_enc->parent) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + drm_enc = phys_enc->parent; + memset(&mixer, 0, sizeof(mixer)); + + /* reset associated CTL/LMs */ + if (phys_enc->hw_ctl->ops.clear_all_blendstages) + phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl); + + sde_rm_init_hw_iter(&lm_iter, drm_enc->base.id, SDE_HW_BLK_LM); + while (sde_rm_get_hw(&phys_enc->sde_kms->rm, &lm_iter)) { + struct sde_hw_mixer *hw_lm = (struct sde_hw_mixer *)lm_iter.hw; + + if (!hw_lm) + continue; + + /* need to flush LM to remove it */ + if (phys_enc->hw_ctl->ops.update_bitmask_mixer) + phys_enc->hw_ctl->ops.update_bitmask_mixer( + phys_enc->hw_ctl, + hw_lm->idx, 1); + + if (fb) { + /* assume a single LM if targeting a frame buffer */ + if (lm_valid) + continue; + + mixer.out_height = fb->height; + mixer.out_width = fb->width; + + if (hw_lm->ops.setup_mixer_out) + hw_lm->ops.setup_mixer_out(hw_lm, &mixer); + } + + lm_valid = true; + + /* only enable border color on LM */ + if (phys_enc->hw_ctl->ops.setup_blendstage) + phys_enc->hw_ctl->ops.setup_blendstage( + phys_enc->hw_ctl, hw_lm->idx, NULL); + } + + if (!lm_valid) { + SDE_ERROR_ENC(to_sde_encoder_virt(drm_enc), "lm not found\n"); + return -EFAULT; + } + return 0; +} + +int sde_encoder_prepare_commit(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys; + int i, rc = 0, ret = 0; + struct sde_hw_ctl *ctl; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + sde_enc = to_sde_encoder_virt(drm_enc); + + /* update the qsync parameters for the current frame */ + if (sde_enc->cur_master) + sde_connector_set_qsync_params( + sde_enc->cur_master->connector); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (phys && phys->ops.prepare_commit) + phys->ops.prepare_commit(phys); + + if (phys && phys->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) + ret = -ETIMEDOUT; + + if (phys && phys->hw_ctl) { + ctl = phys->hw_ctl; + /* + * avoid clearing the pending flush during the first + * frame update after idle power collpase as the + * restore path would have updated the pending flush + */ + if (!sde_enc->idle_pc_restore && + ctl->ops.clear_pending_flush) + ctl->ops.clear_pending_flush(ctl); + } + } + + if (sde_enc->cur_master && sde_enc->cur_master->connector) { + rc = sde_connector_prepare_commit( + sde_enc->cur_master->connector); + if (rc) + SDE_ERROR_ENC(sde_enc, + "prepare commit failed conn %d rc %d\n", + sde_enc->cur_master->connector->base.id, + rc); + } + + return ret; +} + +void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc, + bool enable, u32 frame_count) +{ + if (!phys_enc) + return; + + if (phys_enc->hw_intf && phys_enc->hw_intf->ops.setup_misr) + phys_enc->hw_intf->ops.setup_misr(phys_enc->hw_intf, + enable, frame_count); +} + +int sde_encoder_helper_collect_misr(struct sde_encoder_phys *phys_enc, + bool nonblock, u32 *misr_value) +{ + if (!phys_enc) + return -EINVAL; + + return phys_enc->hw_intf && phys_enc->hw_intf->ops.collect_misr ? + phys_enc->hw_intf->ops.collect_misr(phys_enc->hw_intf, + nonblock, misr_value) : -ENOTSUPP; +} + +#ifdef CONFIG_DEBUG_FS +static int _sde_encoder_status_show(struct seq_file *s, void *data) +{ + struct sde_encoder_virt *sde_enc; + int i; + + if (!s || !s->private) + return -EINVAL; + + sde_enc = s->private; + + mutex_lock(&sde_enc->enc_lock); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys) + continue; + + seq_printf(s, "intf:%d vsync:%8d underrun:%8d ", + phys->intf_idx - INTF_0, + atomic_read(&phys->vsync_cnt), + atomic_read(&phys->underrun_cnt)); + + switch (phys->intf_mode) { + case INTF_MODE_VIDEO: + seq_puts(s, "mode: video\n"); + break; + case INTF_MODE_CMD: + seq_puts(s, "mode: command\n"); + break; + case INTF_MODE_WB_BLOCK: + seq_puts(s, "mode: wb block\n"); + break; + case INTF_MODE_WB_LINE: + seq_puts(s, "mode: wb line\n"); + break; + default: + seq_puts(s, "mode: ???\n"); + break; + } + } + mutex_unlock(&sde_enc->enc_lock); + + return 0; +} + +static int _sde_encoder_debugfs_status_open(struct inode *inode, + struct file *file) +{ + return single_open(file, _sde_encoder_status_show, inode->i_private); +} + +static ssize_t _sde_encoder_misr_setup(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_encoder_virt *sde_enc; + int rc; + char buf[MISR_BUFF_SIZE + 1]; + size_t buff_copy; + u32 frame_count, enable; + struct msm_drm_private *priv = NULL; + struct sde_kms *sde_kms = NULL; + struct drm_encoder *drm_enc; + + if (!file || !file->private_data) + return -EINVAL; + + sde_enc = file->private_data; + priv = sde_enc->base.dev->dev_private; + if (!sde_enc || !priv || !priv->kms) + return -EINVAL; + + sde_kms = to_sde_kms(priv->kms); + drm_enc = &sde_enc->base; + + if (sde_kms_is_secure_session_inprogress(sde_kms)) { + SDE_DEBUG_ENC(sde_enc, "misr enable/disable not allowed\n"); + return -ENOTSUPP; + } + + buff_copy = min_t(size_t, count, MISR_BUFF_SIZE); + if (copy_from_user(buf, user_buf, buff_copy)) + return -EINVAL; + + buf[buff_copy] = 0; /* end of string */ + + if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) + return -EINVAL; + + rc = pm_runtime_get_sync(drm_enc->dev->dev); + if (rc < 0) + return rc; + + sde_enc->misr_enable = enable; + sde_enc->misr_frame_count = frame_count; + sde_encoder_misr_configure(&sde_enc->base, enable, frame_count); + pm_runtime_put_sync(drm_enc->dev->dev); + return count; +} + +static ssize_t _sde_encoder_misr_read(struct file *file, + char __user *user_buff, size_t count, loff_t *ppos) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv = NULL; + struct sde_kms *sde_kms = NULL; + struct drm_encoder *drm_enc; + int i = 0, len = 0; + char buf[MISR_BUFF_SIZE + 1] = {'\0'}; + int rc; + + if (*ppos) + return 0; + + if (!file || !file->private_data) + return -EINVAL; + + sde_enc = file->private_data; + priv = sde_enc->base.dev->dev_private; + if (priv != NULL) + sde_kms = to_sde_kms(priv->kms); + + if (sde_kms_is_secure_session_inprogress(sde_kms)) { + SDE_DEBUG_ENC(sde_enc, "misr read not allowed\n"); + return -ENOTSUPP; + } + drm_enc = &sde_enc->base; + + rc = pm_runtime_get_sync(drm_enc->dev->dev); + if (rc < 0) + return rc; + + if (!sde_enc->misr_enable) { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "disabled\n"); + goto buff_check; + } + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + u32 misr_value = 0; + + if (!phys || !phys->ops.collect_misr) { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "invalid\n"); + SDE_ERROR_ENC(sde_enc, "invalid misr ops\n"); + continue; + } + + rc = phys->ops.collect_misr(phys, false, &misr_value); + if (rc) { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "invalid\n"); + SDE_ERROR_ENC(sde_enc, "failed to collect misr %d\n", + rc); + continue; + } else { + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "Intf idx:%d\n", + phys->intf_idx - INTF_0); + len += scnprintf(buf + len, MISR_BUFF_SIZE - len, + "0x%x\n", misr_value); + } + } + +buff_check: + if (count <= len) { + len = 0; + goto end; + } + + if (copy_to_user(user_buff, buf, len)) { + len = -EFAULT; + goto end; + } + + *ppos += len; /* increase offset */ + +end: + pm_runtime_put_sync(drm_enc->dev->dev); + return len; +} + +static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + int i; + + static const struct file_operations debugfs_status_fops = { + .open = _sde_encoder_debugfs_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; + + static const struct file_operations debugfs_misr_fops = { + .open = simple_open, + .read = _sde_encoder_misr_read, + .write = _sde_encoder_misr_setup, + }; + + char name[SDE_NAME_SIZE]; + + if (!drm_enc || !drm_enc->dev || !drm_enc->dev->dev_private) { + SDE_ERROR("invalid encoder or kms\n"); + return -EINVAL; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + priv = drm_enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + + snprintf(name, SDE_NAME_SIZE, "encoder%u", drm_enc->base.id); + + /* create overall sub-directory for the encoder */ + sde_enc->debugfs_root = debugfs_create_dir(name, + drm_enc->dev->primary->debugfs_root); + if (!sde_enc->debugfs_root) + return -ENOMEM; + + /* don't error check these */ + debugfs_create_file("status", 0400, + sde_enc->debugfs_root, sde_enc, &debugfs_status_fops); + + debugfs_create_file("misr_data", 0600, + sde_enc->debugfs_root, sde_enc, &debugfs_misr_fops); + + debugfs_create_bool("idle_power_collapse", 0600, sde_enc->debugfs_root, + &sde_enc->idle_pc_enabled); + + debugfs_create_u32("frame_trigger_mode", 0400, sde_enc->debugfs_root, + &sde_enc->frame_trigger_mode); + + for (i = 0; i < sde_enc->num_phys_encs; i++) + if (sde_enc->phys_encs[i] && + sde_enc->phys_encs[i]->ops.late_register) + sde_enc->phys_encs[i]->ops.late_register( + sde_enc->phys_encs[i], + sde_enc->debugfs_root); + + return 0; +} + +static void _sde_encoder_destroy_debugfs(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) + return; + + sde_enc = to_sde_encoder_virt(drm_enc); + debugfs_remove_recursive(sde_enc->debugfs_root); +} +#else +static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc) +{ + return 0; +} + +static void _sde_encoder_destroy_debugfs(struct drm_encoder *drm_enc) +{ +} +#endif + +static int sde_encoder_late_register(struct drm_encoder *encoder) +{ + return _sde_encoder_init_debugfs(encoder); +} + +static void sde_encoder_early_unregister(struct drm_encoder *encoder) +{ + _sde_encoder_destroy_debugfs(encoder); +} + +static int sde_encoder_virt_add_phys_encs( + struct msm_display_info *disp_info, + struct sde_encoder_virt *sde_enc, + struct sde_enc_phys_init_params *params) +{ + struct sde_encoder_phys *enc = NULL; + u32 display_caps = disp_info->capabilities; + + SDE_DEBUG_ENC(sde_enc, "\n"); + + /* + * We may create up to NUM_PHYS_ENCODER_TYPES physical encoder types + * in this function, check up-front. + */ + if (sde_enc->num_phys_encs + NUM_PHYS_ENCODER_TYPES >= + ARRAY_SIZE(sde_enc->phys_encs)) { + SDE_ERROR_ENC(sde_enc, "too many physical encoders %d\n", + sde_enc->num_phys_encs); + return -EINVAL; + } + + if (display_caps & MSM_DISPLAY_CAP_VID_MODE) { + enc = sde_encoder_phys_vid_init(params); + + if (IS_ERR_OR_NULL(enc)) { + SDE_ERROR_ENC(sde_enc, "failed to init vid enc: %ld\n", + PTR_ERR(enc)); + return !enc ? -EINVAL : PTR_ERR(enc); + } + + sde_enc->phys_vid_encs[sde_enc->num_phys_encs] = enc; + } + + if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) { + enc = sde_encoder_phys_cmd_init(params); + + if (IS_ERR_OR_NULL(enc)) { + SDE_ERROR_ENC(sde_enc, "failed to init cmd enc: %ld\n", + PTR_ERR(enc)); + return !enc ? -EINVAL : PTR_ERR(enc); + } + sde_enc->phys_cmd_encs[sde_enc->num_phys_encs] = enc; + } + + if (disp_info->curr_panel_mode == MSM_DISPLAY_VIDEO_MODE) + sde_enc->phys_encs[sde_enc->num_phys_encs] = + sde_enc->phys_vid_encs[sde_enc->num_phys_encs]; + else + sde_enc->phys_encs[sde_enc->num_phys_encs] = + sde_enc->phys_cmd_encs[sde_enc->num_phys_encs]; + + ++sde_enc->num_phys_encs; + + return 0; +} + +static int sde_encoder_virt_add_phys_enc_wb(struct sde_encoder_virt *sde_enc, + struct sde_enc_phys_init_params *params) +{ + struct sde_encoder_phys *enc = NULL; + + if (!sde_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + SDE_DEBUG_ENC(sde_enc, "\n"); + + if (sde_enc->num_phys_encs + 1 >= ARRAY_SIZE(sde_enc->phys_encs)) { + SDE_ERROR_ENC(sde_enc, "too many physical encoders %d\n", + sde_enc->num_phys_encs); + return -EINVAL; + } + + enc = sde_encoder_phys_wb_init(params); + + if (IS_ERR_OR_NULL(enc)) { + SDE_ERROR_ENC(sde_enc, "failed to init wb enc: %ld\n", + PTR_ERR(enc)); + return !enc ? -EINVAL : PTR_ERR(enc); + } + + sde_enc->phys_encs[sde_enc->num_phys_encs] = enc; + ++sde_enc->num_phys_encs; + + return 0; +} + +static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, + struct sde_kms *sde_kms, + struct msm_display_info *disp_info, + int *drm_enc_mode) +{ + int ret = 0; + int i = 0; + enum sde_intf_type intf_type; + struct sde_encoder_virt_ops parent_ops = { + sde_encoder_vblank_callback, + sde_encoder_underrun_callback, + sde_encoder_frame_done_callback, + sde_encoder_get_qsync_fps_callback, + }; + struct sde_enc_phys_init_params phys_params; + + if (!sde_enc || !sde_kms) { + SDE_ERROR("invalid arg(s), enc %d kms %d\n", + !sde_enc, !sde_kms); + return -EINVAL; + } + + memset(&phys_params, 0, sizeof(phys_params)); + phys_params.sde_kms = sde_kms; + phys_params.parent = &sde_enc->base; + phys_params.parent_ops = parent_ops; + phys_params.enc_spinlock = &sde_enc->enc_spinlock; + phys_params.vblank_ctl_lock = &sde_enc->vblank_ctl_lock; + + SDE_DEBUG("\n"); + + if (disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) { + *drm_enc_mode = DRM_MODE_ENCODER_DSI; + intf_type = INTF_DSI; + } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_HDMIA) { + *drm_enc_mode = DRM_MODE_ENCODER_TMDS; + intf_type = INTF_HDMI; + } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_DisplayPort) { + if (disp_info->capabilities & MSM_DISPLAY_CAP_MST_MODE) + *drm_enc_mode = DRM_MODE_ENCODER_DPMST; + else + *drm_enc_mode = DRM_MODE_ENCODER_TMDS; + intf_type = INTF_DP; + } else if (disp_info->intf_type == DRM_MODE_CONNECTOR_VIRTUAL) { + *drm_enc_mode = DRM_MODE_ENCODER_VIRTUAL; + intf_type = INTF_WB; + } else { + SDE_ERROR_ENC(sde_enc, "unsupported display interface type\n"); + return -EINVAL; + } + + WARN_ON(disp_info->num_of_h_tiles < 1); + + sde_enc->display_num_of_h_tiles = disp_info->num_of_h_tiles; + sde_enc->te_source = disp_info->te_source; + + SDE_DEBUG("dsi_info->num_of_h_tiles %d\n", disp_info->num_of_h_tiles); + + if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) || + (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) + sde_enc->idle_pc_enabled = sde_kms->catalog->has_idle_pc; + + mutex_lock(&sde_enc->enc_lock); + for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { + /* + * Left-most tile is at index 0, content is controller id + * h_tile_instance_ids[2] = {0, 1}; DSI0 = left, DSI1 = right + * h_tile_instance_ids[2] = {1, 0}; DSI1 = left, DSI0 = right + */ + u32 controller_id = disp_info->h_tile_instance[i]; + + if (disp_info->num_of_h_tiles > 1) { + if (i == 0) + phys_params.split_role = ENC_ROLE_MASTER; + else + phys_params.split_role = ENC_ROLE_SLAVE; + } else { + phys_params.split_role = ENC_ROLE_SOLO; + } + + SDE_DEBUG("h_tile_instance %d = %d, split_role %d\n", + i, controller_id, phys_params.split_role); + + if (sde_enc->ops.phys_init) { + struct sde_encoder_phys *enc; + + enc = sde_enc->ops.phys_init(intf_type, + controller_id, + &phys_params); + if (enc) { + sde_enc->phys_encs[sde_enc->num_phys_encs] = + enc; + ++sde_enc->num_phys_encs; + } else + SDE_ERROR_ENC(sde_enc, + "failed to add phys encs\n"); + + continue; + } + + if (intf_type == INTF_WB) { + phys_params.intf_idx = INTF_MAX; + phys_params.wb_idx = sde_encoder_get_wb( + sde_kms->catalog, + intf_type, controller_id); + if (phys_params.wb_idx == WB_MAX) { + SDE_ERROR_ENC(sde_enc, + "could not get wb: type %d, id %d\n", + intf_type, controller_id); + ret = -EINVAL; + } + } else { + phys_params.wb_idx = WB_MAX; + phys_params.intf_idx = sde_encoder_get_intf( + sde_kms->catalog, intf_type, + controller_id); + if (phys_params.intf_idx == INTF_MAX) { + SDE_ERROR_ENC(sde_enc, + "could not get wb: type %d, id %d\n", + intf_type, controller_id); + ret = -EINVAL; + } + } + + if (!ret) { + if (intf_type == INTF_WB) + ret = sde_encoder_virt_add_phys_enc_wb(sde_enc, + &phys_params); + else + ret = sde_encoder_virt_add_phys_encs( + disp_info, + sde_enc, + &phys_params); + if (ret) + SDE_ERROR_ENC(sde_enc, + "failed to add phys encs\n"); + } + } + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *vid_phys = sde_enc->phys_vid_encs[i]; + struct sde_encoder_phys *cmd_phys = sde_enc->phys_cmd_encs[i]; + + if (vid_phys) { + atomic_set(&vid_phys->vsync_cnt, 0); + atomic_set(&vid_phys->underrun_cnt, 0); + } + + if (cmd_phys) { + atomic_set(&cmd_phys->vsync_cnt, 0); + atomic_set(&cmd_phys->underrun_cnt, 0); + } + + } + mutex_unlock(&sde_enc->enc_lock); + + return ret; +} + +static const struct drm_encoder_helper_funcs sde_encoder_helper_funcs = { + .mode_set = sde_encoder_virt_mode_set, + .disable = sde_encoder_virt_disable, + .enable = sde_encoder_virt_enable, + .atomic_check = sde_encoder_virt_atomic_check, +}; + +static const struct drm_encoder_funcs sde_encoder_funcs = { + .destroy = sde_encoder_destroy, + .late_register = sde_encoder_late_register, + .early_unregister = sde_encoder_early_unregister, +}; + +struct drm_encoder *sde_encoder_init_with_ops( + struct drm_device *dev, + struct msm_display_info *disp_info, + const struct sde_encoder_ops *ops) +{ + struct msm_drm_private *priv = dev->dev_private; + struct sde_kms *sde_kms = to_sde_kms(priv->kms); + struct drm_encoder *drm_enc = NULL; + struct sde_encoder_virt *sde_enc = NULL; + int drm_enc_mode = DRM_MODE_ENCODER_NONE; + char name[SDE_NAME_SIZE]; + int ret = 0, i, intf_index = INTF_MAX; + struct sde_encoder_phys *phys = NULL; + + sde_enc = kzalloc(sizeof(*sde_enc), GFP_KERNEL); + if (!sde_enc) { + ret = -ENOMEM; + goto fail; + } + + if (ops) + sde_enc->ops = *ops; + + mutex_init(&sde_enc->enc_lock); + ret = sde_encoder_setup_display(sde_enc, sde_kms, disp_info, + &drm_enc_mode); + if (ret) + goto fail; + + sde_enc->cur_master = NULL; + spin_lock_init(&sde_enc->enc_spinlock); + mutex_init(&sde_enc->vblank_ctl_lock); + for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) + atomic_set(&sde_enc->frame_done_cnt[i], 0); + drm_enc = &sde_enc->base; + drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL); + drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); + + if (disp_info->intf_type == DRM_MODE_CONNECTOR_DSI) + timer_setup(&sde_enc->vsync_event_timer, + sde_encoder_vsync_event_handler, 0); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + if (!phys) + continue; + if (phys->ops.is_master && phys->ops.is_master(phys)) + intf_index = phys->intf_idx - INTF_0; + } + snprintf(name, SDE_NAME_SIZE, "rsc_enc%u", drm_enc->base.id); + sde_enc->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, name, + (disp_info->display_type == SDE_CONNECTOR_PRIMARY) ? + SDE_RSC_PRIMARY_DISP_CLIENT : + SDE_RSC_EXTERNAL_DISP_CLIENT, intf_index + 1); + if (IS_ERR_OR_NULL(sde_enc->rsc_client)) { + SDE_DEBUG("sde rsc client create failed :%ld\n", + PTR_ERR(sde_enc->rsc_client)); + sde_enc->rsc_client = NULL; + } + + if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) { + ret = _sde_encoder_input_handler(sde_enc); + if (ret) + SDE_ERROR( + "input handler registration failed, rc = %d\n", ret); + } + + mutex_init(&sde_enc->rc_lock); + kthread_init_delayed_work(&sde_enc->delayed_off_work, + sde_encoder_off_work); + sde_enc->vblank_enabled = false; + sde_enc->qdss_status = false; + + kthread_init_work(&sde_enc->vsync_event_work, + sde_encoder_vsync_event_work_handler); + + kthread_init_work(&sde_enc->input_event_work, + sde_encoder_input_event_work_handler); + + kthread_init_work(&sde_enc->esd_trigger_work, + sde_encoder_esd_trigger_work_handler); + + memcpy(&sde_enc->disp_info, disp_info, sizeof(*disp_info)); + + SDE_DEBUG_ENC(sde_enc, "created\n"); + + return drm_enc; + +fail: + SDE_ERROR("failed to create encoder\n"); + if (drm_enc) + sde_encoder_destroy(drm_enc); + + return ERR_PTR(ret); +} + +struct drm_encoder *sde_encoder_init( + struct drm_device *dev, + struct msm_display_info *disp_info) +{ + return sde_encoder_init_with_ops(dev, disp_info, NULL); +} + +int sde_encoder_wait_for_event(struct drm_encoder *drm_enc, + enum msm_event_wait event) +{ + int (*fn_wait)(struct sde_encoder_phys *phys_enc) = NULL; + struct sde_encoder_virt *sde_enc = NULL; + int i, ret = 0; + char atrace_buf[32]; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + sde_enc = to_sde_encoder_virt(drm_enc); + SDE_DEBUG_ENC(sde_enc, "\n"); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + switch (event) { + case MSM_ENC_COMMIT_DONE: + fn_wait = phys->ops.wait_for_commit_done; + break; + case MSM_ENC_TX_COMPLETE: + fn_wait = phys->ops.wait_for_tx_complete; + break; + case MSM_ENC_VBLANK: + fn_wait = phys->ops.wait_for_vblank; + break; + case MSM_ENC_ACTIVE_REGION: + fn_wait = phys->ops.wait_for_active; + break; + default: + SDE_ERROR_ENC(sde_enc, "unknown wait event %d\n", + event); + return -EINVAL; + } + + if (phys && fn_wait) { + snprintf(atrace_buf, sizeof(atrace_buf), + "wait_completion_event_%d", event); + SDE_ATRACE_BEGIN(atrace_buf); + ret = fn_wait(phys); + SDE_ATRACE_END(atrace_buf); + if (ret) + return ret; + } + } + + return ret; +} + +void sde_encoder_helper_get_jitter_bounds_ns(struct drm_encoder *drm_enc, + u64 *l_bound, u64 *u_bound) +{ + struct sde_encoder_virt *sde_enc; + u64 jitter_ns, frametime_ns; + struct msm_mode_info *info; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + info = &sde_enc->mode_info; + + frametime_ns = (1 * 1000000000) / info->frame_rate; + jitter_ns = info->jitter_numer * frametime_ns; + do_div(jitter_ns, info->jitter_denom * 100); + + *l_bound = frametime_ns - jitter_ns; + *u_bound = frametime_ns + jitter_ns; +} + +u32 sde_encoder_get_fps(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return 0; + } + + sde_enc = to_sde_encoder_virt(drm_enc); + + return sde_enc->mode_info.frame_rate; +} + +enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder) +{ + struct sde_encoder_virt *sde_enc = NULL; + int i; + + if (!encoder) { + SDE_ERROR("invalid encoder\n"); + return INTF_MODE_NONE; + } + sde_enc = to_sde_encoder_virt(encoder); + + if (sde_enc->cur_master) + return sde_enc->cur_master->intf_mode; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (phys) + return phys->intf_mode; + } + + return INTF_MODE_NONE; +} + +static void _sde_encoder_cache_hw_res_cont_splash( + struct drm_encoder *encoder, + struct sde_kms *sde_kms) +{ + int i, idx; + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys_enc; + struct sde_rm_hw_iter dsc_iter, pp_iter, ctl_iter, intf_iter; + + sde_enc = to_sde_encoder_virt(encoder); + + sde_rm_init_hw_iter(&pp_iter, encoder->base.id, SDE_HW_BLK_PINGPONG); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + sde_enc->hw_pp[i] = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &pp_iter)) + break; + sde_enc->hw_pp[i] = (struct sde_hw_pingpong *) pp_iter.hw; + } + + sde_rm_init_hw_iter(&dsc_iter, encoder->base.id, SDE_HW_BLK_DSC); + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + sde_enc->hw_dsc[i] = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &dsc_iter)) + break; + sde_enc->hw_dsc[i] = (struct sde_hw_dsc *) dsc_iter.hw; + } + + /* + * If we have multiple phys encoders with one controller, make + * sure to populate the controller pointer in both phys encoders. + */ + for (idx = 0; idx < sde_enc->num_phys_encs; idx++) { + phys_enc = sde_enc->phys_encs[idx]; + phys_enc->hw_ctl = NULL; + + sde_rm_init_hw_iter(&ctl_iter, encoder->base.id, + SDE_HW_BLK_CTL); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + if (sde_rm_get_hw(&sde_kms->rm, &ctl_iter)) { + phys_enc->hw_ctl = + (struct sde_hw_ctl *) ctl_iter.hw; + pr_debug("HW CTL intf_idx:%d hw_ctl:[0x%pK]\n", + phys_enc->intf_idx, phys_enc->hw_ctl); + } + } + } + + sde_rm_init_hw_iter(&intf_iter, encoder->base.id, SDE_HW_BLK_INTF); + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + phys->hw_intf = NULL; + if (!sde_rm_get_hw(&sde_kms->rm, &intf_iter)) + break; + phys->hw_intf = (struct sde_hw_intf *) intf_iter.hw; + } +} + +/** + * sde_encoder_update_caps_for_cont_splash - update encoder settings during + * device bootup when cont_splash is enabled + * @drm_enc: Pointer to drm encoder structure + * @splash_display: Pointer to sde_splash_display corresponding to this encoder + * @enable: boolean indicates enable or displae state of splash + * @Return: true if successful in updating the encoder structure + */ +int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder, + struct sde_splash_display *splash_display, bool enable) +{ + struct sde_encoder_virt *sde_enc; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct drm_connector *conn = NULL; + struct sde_connector *sde_conn = NULL; + struct sde_connector_state *sde_conn_state = NULL; + struct drm_display_mode *drm_mode = NULL; + struct sde_encoder_phys *phys_enc; + int ret = 0, i; + + if (!encoder) { + SDE_ERROR("invalid drm enc\n"); + return -EINVAL; + } + + if (!encoder->dev || !encoder->dev->dev_private) { + SDE_ERROR("drm device invalid\n"); + return -EINVAL; + } + + priv = encoder->dev->dev_private; + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(priv->kms); + sde_enc = to_sde_encoder_virt(encoder); + if (!priv->num_connectors) { + SDE_ERROR_ENC(sde_enc, "No connectors registered\n"); + return -EINVAL; + } + SDE_DEBUG_ENC(sde_enc, + "num of connectors: %d\n", priv->num_connectors); + + SDE_DEBUG_ENC(sde_enc, "enable: %d\n", enable); + if (!enable) { + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys_enc = sde_enc->phys_encs[i]; + if (phys_enc) + phys_enc->cont_splash_enabled = false; + } + return ret; + } + + if (!splash_display) { + SDE_ERROR_ENC(sde_enc, "invalid splash data\n"); + return -EINVAL; + } + + for (i = 0; i < priv->num_connectors; i++) { + SDE_DEBUG_ENC(sde_enc, "connector id: %d\n", + priv->connectors[i]->base.id); + sde_conn = to_sde_connector(priv->connectors[i]); + if (!sde_conn->encoder) { + SDE_DEBUG_ENC(sde_enc, + "encoder not attached to connector\n"); + continue; + } + if (sde_conn->encoder->base.id + == encoder->base.id) { + conn = (priv->connectors[i]); + break; + } + } + + if (!conn || !conn->state) { + SDE_ERROR_ENC(sde_enc, "connector not found\n"); + return -EINVAL; + } + + sde_conn_state = to_sde_connector_state(conn->state); + + if (!sde_conn->ops.get_mode_info) { + SDE_ERROR_ENC(sde_enc, "conn: get_mode_info ops not found\n"); + return -EINVAL; + } + + ret = sde_connector_get_mode_info(&sde_conn->base, + &encoder->crtc->state->adjusted_mode, + &sde_conn_state->mode_info); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "conn: ->get_mode_info failed. ret=%d\n", ret); + return ret; + } + + if (sde_conn->encoder) { + conn->state->best_encoder = sde_conn->encoder; + SDE_DEBUG_ENC(sde_enc, + "configured cstate->best_encoder to ID = %d\n", + conn->state->best_encoder->base.id); + } else { + SDE_ERROR_ENC(sde_enc, "No encoder mapped to connector=%d\n", + conn->base.id); + } + + ret = sde_rm_reserve(&sde_kms->rm, encoder, encoder->crtc->state, + conn->state, false); + if (ret) { + SDE_ERROR_ENC(sde_enc, + "failed to reserve hw resources, %d\n", ret); + return ret; + } + + SDE_DEBUG_ENC(sde_enc, "connector topology = %llu\n", + sde_connector_get_topology_name(conn)); + drm_mode = &encoder->crtc->state->adjusted_mode; + SDE_DEBUG_ENC(sde_enc, "hdisplay = %d, vdisplay = %d\n", + drm_mode->hdisplay, drm_mode->vdisplay); + drm_set_preferred_mode(conn, drm_mode->hdisplay, drm_mode->vdisplay); + + if (encoder->bridge) { + SDE_DEBUG_ENC(sde_enc, "Bridge mapped to encoder\n"); + /* + * For cont-splash use case, we update the mode + * configurations manually. This will skip the + * usually mode set call when actual frame is + * pushed from framework. The bridge needs to + * be updated with the current drm mode by + * calling the bridge mode set ops. + */ + if (encoder->bridge->funcs) { + SDE_DEBUG_ENC(sde_enc, "calling mode_set\n"); + encoder->bridge->funcs->mode_set(encoder->bridge, + drm_mode, drm_mode); + } + } else { + SDE_ERROR_ENC(sde_enc, "No bridge attached to encoder\n"); + } + + _sde_encoder_cache_hw_res_cont_splash(encoder, sde_kms); + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + struct sde_encoder_phys *phys = sde_enc->phys_encs[i]; + + if (!phys) { + SDE_ERROR_ENC(sde_enc, + "phys encoders not initialized\n"); + return -EINVAL; + } + + /* update connector for master and slave phys encoders */ + phys->connector = conn; + phys->cont_splash_enabled = true; + + phys->hw_pp = sde_enc->hw_pp[i]; + if (phys->ops.cont_splash_mode_set) + phys->ops.cont_splash_mode_set(phys, drm_mode); + + if (phys->ops.is_master && phys->ops.is_master(phys)) + sde_enc->cur_master = phys; + } + + return ret; +} + +static void sde_encoder_wait_for_ctl_idle(struct sde_encoder_virt *sde_enc) +{ + int i = 0, rc = 0; + struct sde_encoder_phys *phys; + struct sde_hw_ctl *ctl; + + for (i = 0; i < sde_enc->num_phys_encs; i++) { + phys = sde_enc->phys_encs[i]; + + if (!phys || !phys->hw_ctl) + return; + + ctl = phys->hw_ctl; + if (ctl && ctl->ops.get_scheduler_status) { + rc = wait_event_timeout(phys->pending_kickoff_wq, + (ctl->ops.get_scheduler_status(ctl) & BIT(0)), + msecs_to_jiffies(KICKOFF_TIMEOUT_MS)); + if (!rc) { + SDE_ERROR("wait for ctl idle failed\n"); + SDE_EVT32(SDE_EVTLOG_ERROR); + return; + } + + SDE_EVT32(ctl->ops.get_scheduler_status(ctl)); + } + } +} + +int sde_encoder_display_failure_notification(struct drm_encoder *enc, + bool skip_pre_kickoff) +{ + struct msm_drm_thread *event_thread = NULL; + struct msm_drm_private *priv = NULL; + struct sde_encoder_virt *sde_enc = NULL; + bool posted_start_en = false; + + if (!enc || !enc->dev || !enc->dev->dev_private) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + priv = enc->dev->dev_private; + sde_enc = to_sde_encoder_virt(enc); + if (!sde_enc->crtc || (sde_enc->crtc->index + >= ARRAY_SIZE(priv->event_thread))) { + SDE_DEBUG_ENC(sde_enc, + "invalid cached CRTC: %d or crtc index: %d\n", + sde_enc->crtc == NULL, + sde_enc->crtc ? sde_enc->crtc->index : -EINVAL); + return -EINVAL; + } + + event_thread = &priv->event_thread[sde_enc->crtc->index]; + + if (sde_enc->cur_master && sde_enc->cur_master->connector) + posted_start_en = (sde_connector_get_property( + sde_enc->cur_master->connector->state, + CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE) == + FRAME_DONE_WAIT_POSTED_START) ? true : false; + + SDE_EVT32_VERBOSE(DRMID(enc), posted_start_en); + + if (!skip_pre_kickoff) { + kthread_queue_work(&event_thread->worker, + &sde_enc->esd_trigger_work); + kthread_flush_work(&sde_enc->esd_trigger_work); + } + + /* + * panel may stop generating te signal (vsync) during esd failure. rsc + * hardware may hang without vsync. Avoid rsc hang by generating the + * vsync from watchdog timer instead of panel. + */ + sde_encoder_helper_switch_vsync(enc, true); + + if (skip_pre_kickoff) + return 0; + else if (posted_start_en) + /* + * Make sure that the frame transfer is completed after + * switching to watchdog vsync. The timeout will be + * handled in the commit context for posted start usecases. + */ + sde_encoder_wait_for_ctl_idle(sde_enc); + else + sde_encoder_wait_for_event(enc, MSM_ENC_TX_COMPLETE); + + return 0; +} + +bool sde_encoder_recovery_events_enabled(struct drm_encoder *encoder) +{ + struct sde_encoder_virt *sde_enc; + + if (!encoder) { + SDE_ERROR("invalid drm enc\n"); + return false; + } + + sde_enc = to_sde_encoder_virt(encoder); + + return sde_enc->recovery_events_enabled; +} + +void sde_encoder_recovery_events_handler(struct drm_encoder *encoder, + bool enabled) +{ + struct sde_encoder_virt *sde_enc; + + if (!encoder) { + SDE_ERROR("invalid drm enc\n"); + return; + } + + sde_enc = to_sde_encoder_virt(encoder); + sde_enc->recovery_events_enabled = enabled; +} diff --git a/techpack/display/msm/sde/sde_encoder.h b/techpack/display/msm/sde/sde_encoder.h new file mode 100644 index 0000000000000000000000000000000000000000..ddfe05b97bffb0f70e3115a2fe21de9934216ee0 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SDE_ENCODER_H__ +#define __SDE_ENCODER_H__ + +#include <drm/drm_crtc.h> + +#include "msm_prop.h" +#include "sde_hw_mdss.h" +#include "sde_kms.h" +#include "sde_connector.h" + +#define MAX_CHANNELS_PER_ENC 2 + +#define SDE_ENCODER_FRAME_EVENT_DONE BIT(0) +#define SDE_ENCODER_FRAME_EVENT_ERROR BIT(1) +#define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD BIT(2) +#define SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE BIT(3) +#define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE BIT(4) +#define SDE_ENCODER_FRAME_EVENT_CWB_DONE BIT(5) + +#define IDLE_POWERCOLLAPSE_DURATION (66 - 16/2) +#define IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP (200 - 16/2) + +/** + * Encoder functions and data types + * @intfs: Interfaces this encoder is using, INTF_MODE_NONE if unused + * @wbs: Writebacks this encoder is using, INTF_MODE_NONE if unused + * @needs_cdm: Encoder requests a CDM based on pixel format conversion needs + * @display_num_of_h_tiles: Number of horizontal tiles in case of split + * interface + * @display_type: Type of the display + * @topology: Topology of the display + */ +struct sde_encoder_hw_resources { + enum sde_intf_mode intfs[INTF_MAX]; + enum sde_intf_mode wbs[WB_MAX]; + bool needs_cdm; + u32 display_num_of_h_tiles; + enum sde_connector_display display_type; + struct msm_display_topology topology; +}; + +/** + * sde_encoder_kickoff_params - info encoder requires at kickoff + * @affected_displays: bitmask, bit set means the ROI of the commit lies within + * the bounds of the physical display at the bit index + * @recovery_events_enabled: indicates status of client for recoovery events + * @frame_trigger_mode: indicates frame trigger mode + */ +struct sde_encoder_kickoff_params { + unsigned long affected_displays; + bool recovery_events_enabled; + enum frame_trigger_mode_type frame_trigger_mode; +}; + +/** + * struct sde_encoder_ops - callback functions for generic sde encoder + * Individual callbacks documented below. + */ +struct sde_encoder_ops { + /** + * phys_init - phys initialization function + * @type: controller type + * @controller_id: controller id + * @phys_init_params: Pointer of structure sde_enc_phys_init_params + * Returns: Pointer of sde_encoder_phys, NULL if failed + */ + void *(*phys_init)(enum sde_intf_type type, + u32 controller_id, void *phys_init_params); +}; + +/** + * sde_encoder_get_hw_resources - Populate table of required hardware resources + * @encoder: encoder pointer + * @hw_res: resource table to populate with encoder required resources + * @conn_state: report hw reqs based on this proposed connector state + */ +void sde_encoder_get_hw_resources(struct drm_encoder *encoder, + struct sde_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state); + +/** + * sde_encoder_register_vblank_callback - provide callback to encoder that + * will be called on the next vblank. + * @encoder: encoder pointer + * @cb: callback pointer, provide NULL to deregister and disable IRQs + * @data: user data provided to callback + */ +void sde_encoder_register_vblank_callback(struct drm_encoder *encoder, + void (*cb)(void *), void *data); + +/** + * sde_encoder_register_frame_event_callback - provide callback to encoder that + * will be called after the request is complete, or other events. + * @encoder: encoder pointer + * @cb: callback pointer, provide NULL to deregister + * @crtc: pointer to drm_crtc object interested in frame events + */ +void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder, + void (*cb)(void *, u32), struct drm_crtc *crtc); + +/** + * sde_encoder_get_rsc_client - gets the rsc client state for primary + * for primary display. + * @encoder: encoder pointer + */ +struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *encoder); + +/** + * sde_encoder_poll_line_counts - poll encoder line counts for start of frame + * @encoder: encoder pointer + * @Returns: zero on success + */ +int sde_encoder_poll_line_counts(struct drm_encoder *encoder); + +/** + * sde_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl + * path (i.e. ctl flush and start) at next appropriate time. + * Immediately: if no previous commit is outstanding. + * Delayed: Block until next trigger can be issued. + * @encoder: encoder pointer + * @params: kickoff time parameters + * @Returns: Zero on success, last detected error otherwise + */ +int sde_encoder_prepare_for_kickoff(struct drm_encoder *encoder, + struct sde_encoder_kickoff_params *params); + +/** + * sde_encoder_trigger_kickoff_pending - Clear the flush bits from previous + * kickoff and trigger the ctl prepare progress for command mode display. + * @encoder: encoder pointer + */ +void sde_encoder_trigger_kickoff_pending(struct drm_encoder *encoder); + +/** + * sde_encoder_kickoff - trigger a double buffer flip of the ctl path + * (i.e. ctl flush and start) immediately. + * @encoder: encoder pointer + * @is_error: whether the current commit needs to be aborted and replaced + * with a 'safe' commit + */ +void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error); + +/** + * sde_encoder_wait_for_event - Waits for encoder events + * @encoder: encoder pointer + * @event: event to wait for + * MSM_ENC_COMMIT_DONE - Wait for hardware to have flushed the current pending + * frames to hardware at a vblank or wr_ptr_start + * Encoders will map this differently depending on the + * panel type. + * vid mode -> vsync_irq + * cmd mode -> wr_ptr_start_irq + * MSM_ENC_TX_COMPLETE - Wait for the hardware to transfer all the pixels to + * the panel. Encoders will map this differently + * depending on the panel type. + * vid mode -> vsync_irq + * cmd mode -> pp_done + * Returns: 0 on success, -EWOULDBLOCK if already signaled, error otherwise + */ +int sde_encoder_wait_for_event(struct drm_encoder *drm_encoder, + enum msm_event_wait event); + +/** + * sde_encoder_idle_request - request for idle request to avoid 4 vsync cycle + * to turn off the clocks. + * @encoder: encoder pointer + * Returns: 0 on success, errorcode otherwise + */ +int sde_encoder_idle_request(struct drm_encoder *drm_enc); + +/* + * sde_encoder_get_fps - get interface frame rate of the given encoder + * @encoder: Pointer to drm encoder object + */ +u32 sde_encoder_get_fps(struct drm_encoder *encoder); + +/* + * sde_encoder_get_intf_mode - get interface mode of the given encoder + * @encoder: Pointer to drm encoder object + */ +enum sde_intf_mode sde_encoder_get_intf_mode(struct drm_encoder *encoder); + +/** + * sde_encoder_control_te - control enabling/disabling VSYNC_IN_EN + * @encoder: encoder pointer + * @enable: boolean to indicate enable/disable + */ +void sde_encoder_control_te(struct drm_encoder *encoder, bool enable); + +/** + * sde_encoder_virt_restore - restore the encoder configs + * @encoder: encoder pointer + */ +void sde_encoder_virt_restore(struct drm_encoder *encoder); + +/** + * sde_encoder_is_dsc_merge - check if encoder is in DSC merge mode + * @drm_enc: Pointer to drm encoder object + * @Return: true if encoder is in DSC merge mode + */ +bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc); + +/** + * sde_encoder_check_curr_mode - check if given mode is supported or not + * @drm_enc: Pointer to drm encoder object + * @mode: Mode to be checked + * @Return: true if it is cmd mode + */ +bool sde_encoder_check_curr_mode(struct drm_encoder *drm_enc, u32 mode); + +/** + * sde_encoder_init - initialize virtual encoder object + * @dev: Pointer to drm device structure + * @disp_info: Pointer to display information structure + * Returns: Pointer to newly created drm encoder + */ +struct drm_encoder *sde_encoder_init( + struct drm_device *dev, + struct msm_display_info *disp_info); + +/** + * sde_encoder_init_with_ops - initialize virtual encoder object with init ops + * @dev: Pointer to drm device structure + * @disp_info: Pointer to display information structure + * @ops: Pointer to encoder ops structure + * Returns: Pointer to newly created drm encoder + */ +struct drm_encoder *sde_encoder_init_with_ops( + struct drm_device *dev, + struct msm_display_info *disp_info, + const struct sde_encoder_ops *ops); + +/** + * sde_encoder_destroy - destroy previously initialized virtual encoder + * @drm_enc: Pointer to previously created drm encoder structure + */ +void sde_encoder_destroy(struct drm_encoder *drm_enc); + +/** + * sde_encoder_prepare_commit - prepare encoder at the very beginning of an + * atomic commit, before any registers are written + * @drm_enc: Pointer to previously created drm encoder structure + */ +int sde_encoder_prepare_commit(struct drm_encoder *drm_enc); + +/** + * sde_encoder_update_caps_for_cont_splash - update encoder settings during + * device bootup when cont_splash is enabled + * @drm_enc: Pointer to drm encoder structure + * @splash_display: Pointer to sde_splash_display corresponding to this encoder + * @enable: boolean indicates enable or displae state of splash + * @Return: true if successful in updating the encoder structure + */ +int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder, + struct sde_splash_display *splash_display, bool enable); + +/** + * sde_encoder_display_failure_notification - update sde encoder state for + * esd timeout or other display failure notification. This event flows from + * dsi, sde_connector to sde_encoder. + * + * This api must not be called from crtc_commit (display) thread because it + * requests the flush work on same thread. It is called from esd check thread + * based on current design. + * + * TODO: manage the event at sde_kms level for forward processing. + * @drm_enc: Pointer to drm encoder structure + * @skip_pre_kickoff: Caller can avoid pre_kickoff if it is triggering this + * event only to switch the panel TE to watchdog mode. + * @Return: true if successful in updating the encoder structure + */ +int sde_encoder_display_failure_notification(struct drm_encoder *enc, + bool skip_pre_kickoff); + +/** + * sde_encoder_recovery_events_enabled - checks if client has enabled + * sw recovery mechanism for this connector + * @drm_enc: Pointer to drm encoder structure + * @Return: true if enabled + */ +bool sde_encoder_recovery_events_enabled(struct drm_encoder *encoder); + +/** + * sde_encoder_recovery_events_handler - handler to enable/disable the + * sw recovery for this connector + * @drm_enc: Pointer to drm encoder structure + */ +void sde_encoder_recovery_events_handler(struct drm_encoder *encoder, + bool val); +/** + * sde_encoder_in_clone_mode - checks if underlying phys encoder is in clone + * mode or independent display mode. ref@ WB in Concurrent writeback mode. + * @drm_enc: Pointer to drm encoder structure + * @Return: true if successful in updating the encoder structure + */ +bool sde_encoder_in_clone_mode(struct drm_encoder *enc); + +/** + * sde_encoder_is_primary_display - checks if underlying display is primary + * display or not. + * @drm_enc: Pointer to drm encoder structure + * @Return: true if it is primary display. false if secondary display + */ +bool sde_encoder_is_primary_display(struct drm_encoder *enc); + +/** + * sde_encoder_is_dsi_display - checks if underlying display is DSI + * display or not. + * @drm_enc: Pointer to drm encoder structure + * @Return: true if it is primary display. false if secondary display + */ +bool sde_encoder_is_dsi_display(struct drm_encoder *enc); + +/** + * sde_encoder_control_idle_pc - control enable/disable of idle power collapse + * @drm_enc: Pointer to drm encoder structure + * @enable: enable/disable flag + */ +void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable); + +/** + * sde_encoder_in_cont_splash - checks if display is in continuous splash + * @drm_enc: Pointer to drm encoder structure + * @Return: true if display in continuous splash + */ +int sde_encoder_in_cont_splash(struct drm_encoder *enc); + +/** + * sde_encoder_helper_hw_reset - hw reset helper function + * @drm_enc: Pointer to drm encoder structure + */ +void sde_encoder_needs_hw_reset(struct drm_encoder *enc); + +/** + * sde_encoder_uidle_enable - control enable/disable of uidle + * @drm_enc: Pointer to drm encoder structure + * @enable: enable/disable flag + */ +void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable); + +#endif /* __SDE_ENCODER_H__ */ diff --git a/techpack/display/msm/sde/sde_encoder_phys.h b/techpack/display/msm/sde/sde_encoder_phys.h new file mode 100644 index 0000000000000000000000000000000000000000..8f35a8fa54eaf0f86a3703c1d990844bcb0e00ea --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder_phys.h @@ -0,0 +1,764 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ENCODER_PHYS_H__ +#define __SDE_ENCODER_PHYS_H__ + +#include <linux/jiffies.h> +#include <linux/sde_rsc.h> + +#include "sde_kms.h" +#include "sde_hw_intf.h" +#include "sde_hw_pingpong.h" +#include "sde_hw_ctl.h" +#include "sde_hw_top.h" +#include "sde_hw_wb.h" +#include "sde_hw_cdm.h" +#include "sde_encoder.h" +#include "sde_connector.h" + +#define SDE_ENCODER_NAME_MAX 16 + +/* wait for at most 2 vsync for lowest refresh rate (24hz) */ +#define KICKOFF_TIMEOUT_MS 84 +#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS) + +#define MAX_TE_PROFILE_COUNT 5 +/** + * enum sde_enc_split_role - Role this physical encoder will play in a + * split-panel configuration, where one panel is master, and others slaves. + * Masters have extra responsibilities, like managing the VBLANK IRQ. + * @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master. + * @ENC_ROLE_MASTER: This encoder is the master of a split panel config. + * @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config. + * @ENC_ROLE_SKIP: This encoder is not participating in kickoffs + */ +enum sde_enc_split_role { + ENC_ROLE_SOLO, + ENC_ROLE_MASTER, + ENC_ROLE_SLAVE, + ENC_ROLE_SKIP +}; + +/** + * enum sde_enc_enable_state - current enabled state of the physical encoder + * @SDE_ENC_DISABLING: Encoder transitioning to disable state + * Events bounding transition are encoder type specific + * @SDE_ENC_DISABLED: Encoder is disabled + * @SDE_ENC_ENABLING: Encoder transitioning to enabled + * Events bounding transition are encoder type specific + * @SDE_ENC_ENABLED: Encoder is enabled + * @SDE_ENC_ERR_NEEDS_HW_RESET: Encoder is enabled, but requires a hw_reset + * to recover from a previous error + */ +enum sde_enc_enable_state { + SDE_ENC_DISABLING, + SDE_ENC_DISABLED, + SDE_ENC_ENABLING, + SDE_ENC_ENABLED, + SDE_ENC_ERR_NEEDS_HW_RESET +}; + +struct sde_encoder_phys; + +/** + * struct sde_encoder_virt_ops - Interface the containing virtual encoder + * provides for the physical encoders to use to callback. + * @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception + * Note: This is called from IRQ handler context. + * @handle_underrun_virt: Notify virtual encoder of underrun IRQ reception + * Note: This is called from IRQ handler context. + * @handle_frame_done: Notify virtual encoder that this phys encoder + * completes last request frame. + * @get_qsync_fps: Returns the min fps for the qsync feature. + */ +struct sde_encoder_virt_ops { + void (*handle_vblank_virt)(struct drm_encoder *parent, + struct sde_encoder_phys *phys); + void (*handle_underrun_virt)(struct drm_encoder *parent, + struct sde_encoder_phys *phys); + void (*handle_frame_done)(struct drm_encoder *parent, + struct sde_encoder_phys *phys, u32 event); + void (*get_qsync_fps)(struct drm_encoder *parent, + u32 *qsync_fps); +}; + +/** + * struct sde_encoder_phys_ops - Interface the physical encoders provide to + * the containing virtual encoder. + * @late_register: DRM Call. Add Userspace interfaces, debugfs. + * @prepare_commit: MSM Atomic Call, start of atomic commit sequence + * @is_master: Whether this phys_enc is the current master + * encoder. Can be switched at enable time. Based + * on split_role and current mode (CMD/VID). + * @mode_fixup: DRM Call. Fixup a DRM mode. + * @cont_splash_mode_set: mode set with specific HW resources during + * cont splash enabled state. + * @mode_set: DRM Call. Set a DRM mode. + * This likely caches the mode, for use at enable. + * @enable: DRM Call. Enable a DRM mode. + * @disable: DRM Call. Disable mode. + * @atomic_check: DRM Call. Atomic check new DRM state. + * @destroy: DRM Call. Destroy and release resources. + * @get_hw_resources: Populate the structure with the hardware + * resources that this phys_enc is using. + * Expect no overlap between phys_encs. + * @control_vblank_irq Register/Deregister for VBLANK IRQ + * @wait_for_commit_done: Wait for hardware to have flushed the + * current pending frames to hardware + * @wait_for_tx_complete: Wait for hardware to transfer the pixels + * to the panel + * @wait_for_vblank: Wait for VBLANK, for sub-driver internal use + * @prepare_for_kickoff: Do any work necessary prior to a kickoff + * For CMD encoder, may wait for previous tx done + * @handle_post_kickoff: Do any work necessary post-kickoff work + * @trigger_flush: Process flush event on physical encoder + * @trigger_start: Process start event on physical encoder + * @needs_single_flush: Whether encoder slaves need to be flushed + * @setup_misr: Sets up MISR, enable and disables based on sysfs + * @collect_misr: Collects MISR data on frame update + * @hw_reset: Issue HW recovery such as CTL reset and clear + * SDE_ENC_ERR_NEEDS_HW_RESET state + * @irq_control: Handler to enable/disable all the encoder IRQs + * @update_split_role: Update the split role of the phys enc + * @control_te: Interface to control the vsync_enable status + * @restore: Restore all the encoder configs. + * @is_autorefresh_enabled: provides the autorefresh current + * enable/disable state. + * @get_line_count: Obtain current internal vertical line count + * @get_wr_line_count: Obtain current output vertical line count + * @wait_dma_trigger: Returns true if lut dma has to trigger and wait + * unitl transaction is complete. + * @wait_for_active: Wait for display scan line to be in active area + * @setup_vsync_source: Configure vsync source selection for cmd mode. + */ + +struct sde_encoder_phys_ops { + int (*late_register)(struct sde_encoder_phys *encoder, + struct dentry *debugfs_root); + void (*prepare_commit)(struct sde_encoder_phys *encoder); + bool (*is_master)(struct sde_encoder_phys *encoder); + bool (*mode_fixup)(struct sde_encoder_phys *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*mode_set)(struct sde_encoder_phys *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*cont_splash_mode_set)(struct sde_encoder_phys *encoder, + struct drm_display_mode *adjusted_mode); + void (*enable)(struct sde_encoder_phys *encoder); + void (*disable)(struct sde_encoder_phys *encoder); + int (*atomic_check)(struct sde_encoder_phys *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); + void (*destroy)(struct sde_encoder_phys *encoder); + void (*get_hw_resources)(struct sde_encoder_phys *encoder, + struct sde_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state); + int (*control_vblank_irq)(struct sde_encoder_phys *enc, bool enable); + int (*wait_for_commit_done)(struct sde_encoder_phys *phys_enc); + int (*wait_for_tx_complete)(struct sde_encoder_phys *phys_enc); + int (*wait_for_vblank)(struct sde_encoder_phys *phys_enc); + int (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc, + struct sde_encoder_kickoff_params *params); + void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc); + void (*trigger_flush)(struct sde_encoder_phys *phys_enc); + void (*trigger_start)(struct sde_encoder_phys *phys_enc); + bool (*needs_single_flush)(struct sde_encoder_phys *phys_enc); + + void (*setup_misr)(struct sde_encoder_phys *phys_encs, + bool enable, u32 frame_count); + int (*collect_misr)(struct sde_encoder_phys *phys_enc, bool nonblock, + u32 *misr_value); + void (*hw_reset)(struct sde_encoder_phys *phys_enc); + void (*irq_control)(struct sde_encoder_phys *phys, bool enable); + void (*update_split_role)(struct sde_encoder_phys *phys_enc, + enum sde_enc_split_role role); + void (*control_te)(struct sde_encoder_phys *phys_enc, bool enable); + void (*restore)(struct sde_encoder_phys *phys); + bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys); + int (*get_line_count)(struct sde_encoder_phys *phys); + int (*get_wr_line_count)(struct sde_encoder_phys *phys); + bool (*wait_dma_trigger)(struct sde_encoder_phys *phys); + int (*wait_for_active)(struct sde_encoder_phys *phys); + void (*setup_vsync_source)(struct sde_encoder_phys *phys, + u32 vsync_source, bool is_dummy); +}; + +/** + * enum sde_intr_idx - sde encoder interrupt index + * @INTR_IDX_VSYNC: Vsync interrupt for video mode panel + * @INTR_IDX_PINGPONG: Pingpong done interrupt for cmd mode panel + * @INTR_IDX_UNDERRUN: Underrun interrupt for video and cmd mode panel + * @INTR_IDX_RDPTR: Readpointer done interrupt for cmd mode panel + * @INTR_IDX_WB_DONE: Writeback done interrupt for WB + * @INTR_IDX_PP1_OVFL: Pingpong overflow interrupt on PP1 for Concurrent WB + * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB + * @INTR_IDX_PP3_OVFL: Pingpong overflow interrupt on PP3 for Concurrent WB + * @INTR_IDX_PP4_OVFL: Pingpong overflow interrupt on PP4 for Concurrent WB + * @INTR_IDX_PP5_OVFL: Pingpong overflow interrupt on PP5 for Concurrent WB + * @INTR_IDX_AUTOREFRESH_DONE: Autorefresh done for cmd mode panel meaning + * autorefresh has triggered a double buffer flip + * @INTR_IDX_WRPTR: Writepointer start interrupt for cmd mode panel + */ +enum sde_intr_idx { + INTR_IDX_VSYNC, + INTR_IDX_PINGPONG, + INTR_IDX_UNDERRUN, + INTR_IDX_CTL_START, + INTR_IDX_RDPTR, + INTR_IDX_AUTOREFRESH_DONE, + INTR_IDX_WB_DONE, + INTR_IDX_PP1_OVFL, + INTR_IDX_PP2_OVFL, + INTR_IDX_PP3_OVFL, + INTR_IDX_PP4_OVFL, + INTR_IDX_PP5_OVFL, + INTR_IDX_WRPTR, + INTR_IDX_MAX, +}; + +/** + * sde_encoder_irq - tracking structure for interrupts + * @name: string name of interrupt + * @intr_type: Encoder interrupt type + * @intr_idx: Encoder interrupt enumeration + * @hw_idx: HW Block ID + * @irq_idx: IRQ interface lookup index from SDE IRQ framework + * will be -EINVAL if IRQ is not registered + * @irq_cb: interrupt callback + */ +struct sde_encoder_irq { + const char *name; + enum sde_intr_type intr_type; + enum sde_intr_idx intr_idx; + int hw_idx; + int irq_idx; + struct sde_irq_callback cb; +}; + +/** + * struct sde_encoder_phys - physical encoder that drives a single INTF block + * tied to a specific panel / sub-panel. Abstract type, sub-classed by + * phys_vid or phys_cmd for video mode or command mode encs respectively. + * @parent: Pointer to the containing virtual encoder + * @connector: If a mode is set, cached pointer to the active connector + * @ops: Operations exposed to the virtual encoder + * @parent_ops: Callbacks exposed by the parent to the phys_enc + * @hw_mdptop: Hardware interface to the top registers + * @hw_ctl: Hardware interface to the ctl registers + * @hw_intf: Hardware interface to INTF registers + * @hw_cdm: Hardware interface to the cdm registers + * @hw_qdss: Hardware interface to the qdss registers + * @cdm_cfg: Chroma-down hardware configuration + * @hw_pp: Hardware interface to the ping pong registers + * @sde_kms: Pointer to the sde_kms top level + * @cached_mode: DRM mode cached at mode_set time, acted on in enable + * @enabled: Whether the encoder has enabled and running a mode + * @split_role: Role to play in a split-panel configuration + * @intf_mode: Interface mode + * @intf_idx: Interface index on sde hardware + * @intf_cfg: Interface hardware configuration + * @intf_cfg_v1: Interface hardware configuration to be used if control + * path supports SDE_CTL_ACTIVE_CFG + * @comp_type: Type of compression supported + * @comp_ratio: Compression ratio + * @dsc_extra_pclk_cycle_cnt: Extra pclk cycle count for DSC over DP + * @dsc_extra_disp_width: Additional display width for DSC over DP + * @wide_bus_en: Wide-bus configuraiton + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + * @enable_state: Enable state tracking + * @vblank_refcount: Reference count of vblank request + * @wbirq_refcount: Reference count of wb irq request + * @vsync_cnt: Vsync count for the physical encoder + * @underrun_cnt: Underrun count for the physical encoder + * @pending_kickoff_cnt: Atomic counter tracking the number of kickoffs + * vs. the number of done/vblank irqs. Should hover + * between 0-2 Incremented when a new kickoff is + * scheduled. Decremented in irq handler + * @pending_retire_fence_cnt: Atomic counter tracking the pending retire + * fences that have to be signalled. + * @pending_kickoff_wq: Wait queue for blocking until kickoff completes + * @irq: IRQ tracking structures + * @has_intf_te: Interface TE configuration support + * @cont_splash_enabled: Variable to store continuous splash settings. + * @in_clone_mode Indicates if encoder is in clone mode ref@CWB + * @vfp_cached: cached vertical front porch to be used for + * programming ROT and MDP fetch start + * @frame_trigger_mode: frame trigger mode indication for command + * mode display + */ +struct sde_encoder_phys { + struct drm_encoder *parent; + struct drm_connector *connector; + struct sde_encoder_phys_ops ops; + struct sde_encoder_virt_ops parent_ops; + struct sde_hw_mdp *hw_mdptop; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_intf *hw_intf; + struct sde_hw_cdm *hw_cdm; + struct sde_hw_qdss *hw_qdss; + struct sde_hw_cdm_cfg cdm_cfg; + struct sde_hw_pingpong *hw_pp; + struct sde_kms *sde_kms; + struct drm_display_mode cached_mode; + enum sde_enc_split_role split_role; + enum sde_intf_mode intf_mode; + enum sde_intf intf_idx; + struct sde_hw_intf_cfg intf_cfg; + struct sde_hw_intf_cfg_v1 intf_cfg_v1; + enum msm_display_compression_type comp_type; + enum msm_display_compression_ratio comp_ratio; + u32 dsc_extra_pclk_cycle_cnt; + u32 dsc_extra_disp_width; + bool wide_bus_en; + spinlock_t *enc_spinlock; + enum sde_enc_enable_state enable_state; + struct mutex *vblank_ctl_lock; + atomic_t vblank_refcount; + atomic_t wbirq_refcount; + atomic_t vsync_cnt; + atomic_t underrun_cnt; + atomic_t pending_kickoff_cnt; + atomic_t pending_retire_fence_cnt; + wait_queue_head_t pending_kickoff_wq; + struct sde_encoder_irq irq[INTR_IDX_MAX]; + bool has_intf_te; + bool cont_splash_enabled; + bool in_clone_mode; + int vfp_cached; + enum frame_trigger_mode_type frame_trigger_mode; +}; + +static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys) +{ + return atomic_inc_return(&phys->pending_kickoff_cnt); +} + +/** + * struct sde_encoder_phys_vid - sub-class of sde_encoder_phys to handle video + * mode specific operations + * @base: Baseclass physical encoder structure + * @timing_params: Current timing parameter + * @error_count: Number of consecutive kickoffs that experienced an error + */ +struct sde_encoder_phys_vid { + struct sde_encoder_phys base; + struct intf_timing_params timing_params; + int error_count; +}; + +/** + * struct sde_encoder_phys_cmd_autorefresh - autorefresh state tracking + * @cfg: current active autorefresh configuration + * @kickoff_cnt: atomic count tracking autorefresh done irq kickoffs pending + * @kickoff_wq: wait queue for waiting on autorefresh done irq + */ +struct sde_encoder_phys_cmd_autorefresh { + struct sde_hw_autorefresh cfg; + atomic_t kickoff_cnt; + wait_queue_head_t kickoff_wq; +}; + +/** + * struct sde_encoder_phys_cmd_te_timestamp - list node to keep track of + * rd_ptr/TE timestamp + * @list: list node + * @timestamp: TE timestamp + */ +struct sde_encoder_phys_cmd_te_timestamp { + struct list_head list; + ktime_t timestamp; +}; + +/** + * struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command + * mode specific operations + * @base: Baseclass physical encoder structure + * @stream_sel: Stream selection for multi-stream interfaces + * @pp_timeout_report_cnt: number of pingpong done irq timeout errors + * @autorefresh: autorefresh feature state + * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK + * @pending_vblank_wq: Wait queue for blocking until VBLANK received + * @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger + * @te_timestamp_list: List head for the TE timestamp list + * @te_timestamp: Array of size MAX_TE_PROFILE_COUNT te_timestamp_list elements + */ +struct sde_encoder_phys_cmd { + struct sde_encoder_phys base; + int stream_sel; + int pp_timeout_report_cnt; + struct sde_encoder_phys_cmd_autorefresh autorefresh; + atomic_t pending_vblank_cnt; + wait_queue_head_t pending_vblank_wq; + bool wr_ptr_wait_success; + struct list_head te_timestamp_list; + struct sde_encoder_phys_cmd_te_timestamp + te_timestamp[MAX_TE_PROFILE_COUNT]; +}; + +/** + * struct sde_encoder_phys_wb - sub-class of sde_encoder_phys to handle + * writeback specific operations + * @base: Baseclass physical encoder structure + * @hw_wb: Hardware interface to the wb registers + * @wbdone_timeout: Timeout value for writeback done in msec + * @bypass_irqreg: Bypass irq register/unregister if non-zero + * @wb_cfg: Writeback hardware configuration + * @cdp_cfg: Writeback CDP configuration + * @wb_roi: Writeback region-of-interest + * @wb_fmt: Writeback pixel format + * @wb_fb: Pointer to current writeback framebuffer + * @wb_aspace: Pointer to current writeback address space + * @cwb_old_fb: Pointer to old writeback framebuffer + * @cwb_old_aspace: Pointer to old writeback address space + * @frame_count: Counter of completed writeback operations + * @kickoff_count: Counter of issued writeback operations + * @aspace: address space identifier for non-secure/secure domain + * @wb_dev: Pointer to writeback device + * @start_time: Start time of writeback latest request + * @end_time: End time of writeback latest request + * @bo_disable: Buffer object(s) to use during the disabling state + * @fb_disable: Frame buffer to use during the disabling state + * @crtc Pointer to drm_crtc + */ +struct sde_encoder_phys_wb { + struct sde_encoder_phys base; + struct sde_hw_wb *hw_wb; + u32 wbdone_timeout; + u32 bypass_irqreg; + struct sde_hw_wb_cfg wb_cfg; + struct sde_hw_wb_cdp_cfg cdp_cfg; + struct sde_rect wb_roi; + const struct sde_format *wb_fmt; + struct drm_framebuffer *wb_fb; + struct msm_gem_address_space *wb_aspace; + struct drm_framebuffer *cwb_old_fb; + struct msm_gem_address_space *cwb_old_aspace; + u32 frame_count; + u32 kickoff_count; + struct msm_gem_address_space *aspace[SDE_IOMMU_DOMAIN_MAX]; + struct sde_wb_device *wb_dev; + ktime_t start_time; + ktime_t end_time; + struct drm_gem_object *bo_disable[SDE_MAX_PLANES]; + struct drm_framebuffer *fb_disable; + struct drm_crtc *crtc; +}; + +/** + * struct sde_enc_phys_init_params - initialization parameters for phys encs + * @sde_kms: Pointer to the sde_kms top level + * @parent: Pointer to the containing virtual encoder + * @parent_ops: Callbacks exposed by the parent to the phys_enc + * @split_role: Role to play in a split-panel configuration + * @intf_idx: Interface index this phys_enc will control + * @wb_idx: Writeback index this phys_enc will control + * @comp_type: Type of compression supported + * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes + */ +struct sde_enc_phys_init_params { + struct sde_kms *sde_kms; + struct drm_encoder *parent; + struct sde_encoder_virt_ops parent_ops; + enum sde_enc_split_role split_role; + enum sde_intf intf_idx; + enum sde_wb wb_idx; + enum msm_display_compression_type comp_type; + spinlock_t *enc_spinlock; + struct mutex *vblank_ctl_lock; +}; + +/** + * sde_encoder_wait_info - container for passing arguments to irq wait functions + * @wq: wait queue structure + * @atomic_cnt: wait until atomic_cnt equals zero + * @count_check: wait for specific atomic_cnt instead of zero. + * @timeout_ms: timeout value in milliseconds + */ +struct sde_encoder_wait_info { + wait_queue_head_t *wq; + atomic_t *atomic_cnt; + u32 count_check; + s64 timeout_ms; +}; + +/** + * sde_encoder_phys_vid_init - Construct a new video mode physical encoder + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +struct sde_encoder_phys *sde_encoder_phys_vid_init( + struct sde_enc_phys_init_params *p); + +/** + * sde_encoder_phys_cmd_init - Construct a new command mode physical encoder + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +struct sde_encoder_phys *sde_encoder_phys_cmd_init( + struct sde_enc_phys_init_params *p); + +/** + * sde_encoder_phys_wb_init - Construct a new writeback physical encoder + * @p: Pointer to init params structure + * Return: Error code or newly allocated encoder + */ +#ifdef CONFIG_DRM_SDE_WB +struct sde_encoder_phys *sde_encoder_phys_wb_init( + struct sde_enc_phys_init_params *p); +#else +static inline +struct sde_encoder_phys *sde_encoder_phys_wb_init( + struct sde_enc_phys_init_params *p) +{ + return NULL; +} +#endif + +void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb, const struct sde_format *format, + struct sde_rect *wb_roi); + +/** + * sde_encoder_helper_get_pp_line_count - pingpong linecount helper function + * @drm_enc: Pointer to drm encoder structure + * @info: structure used to populate the pp line count information + */ +void sde_encoder_helper_get_pp_line_count(struct drm_encoder *drm_enc, + struct sde_hw_pp_vsync_info *info); + +/** + * sde_encoder_helper_trigger_flush - control flush helper function + * This helper function may be optionally specified by physical + * encoders if they require ctl_flush triggering. + * @phys_enc: Pointer to physical encoder structure + */ +void sde_encoder_helper_trigger_flush(struct sde_encoder_phys *phys_enc); + +/** + * sde_encoder_helper_trigger_start - control start helper function + * This helper function may be optionally specified by physical + * encoders if they require ctl_start triggering. + * @phys_enc: Pointer to physical encoder structure + */ +void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc); + +/** + * sde_encoder_helper_vsync_config - configure vsync source for cmd mode + * @phys_enc: Pointer to physical encoder structure + * @vsync_source: vsync source selection + * @is_dummy: used only for RSC + */ +void sde_encoder_helper_vsync_config(struct sde_encoder_phys *phys_enc, + u32 vsync_source, bool is_dummy); + +/** + * sde_encoder_helper_wait_event_timeout - wait for event with timeout + * taking into account that jiffies may jump between reads leading to + * incorrectly detected timeouts. Prevent failure in this scenario by + * making sure that elapsed time during wait is valid. + * @drm_id: drm object id for logging + * @hw_id: hw instance id for logging + * @info: wait info structure + */ +int sde_encoder_helper_wait_event_timeout( + int32_t drm_id, + int32_t hw_id, + struct sde_encoder_wait_info *info); + +/* + * sde_encoder_get_fps - get the allowed panel jitter in nanoseconds + * @encoder: Pointer to drm encoder object + */ +void sde_encoder_helper_get_jitter_bounds_ns(struct drm_encoder *encoder, + u64 *l_bound, u64 *u_bound); + +/** + * sde_encoder_helper_switch_vsync - switch vsync source to WD or default + * @drm_enc: Pointer to drm encoder structure + * @watchdog_te: switch vsync source to watchdog TE + */ +int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc, + bool watchdog_te); + +/** + * sde_encoder_helper_hw_reset - issue ctl hw reset + * This helper function may be optionally specified by physical + * encoders if they require ctl hw reset. If state is currently + * SDE_ENC_ERR_NEEDS_HW_RESET, it is set back to SDE_ENC_ENABLED. + * @phys_enc: Pointer to physical encoder structure + */ +void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc); + +static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode( + struct sde_encoder_phys *phys_enc) +{ + enum sde_rm_topology_name topology; + + if (!phys_enc || phys_enc->enable_state == SDE_ENC_DISABLING) + return BLEND_3D_NONE; + + topology = sde_connector_get_topology_name(phys_enc->connector); + if (phys_enc->split_role == ENC_ROLE_SOLO && + (topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE || + topology == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)) + return BLEND_3D_H_ROW_INT; + + return BLEND_3D_NONE; +} + +/** + * sde_encoder_helper_split_config - split display configuration helper function + * This helper function may be used by physical encoders to configure + * the split display related registers. + * @phys_enc: Pointer to physical encoder structure + * @interface: enum sde_intf setting + */ +void sde_encoder_helper_split_config( + struct sde_encoder_phys *phys_enc, + enum sde_intf interface); + +/** + * sde_encoder_helper_reset_mixers - reset mixers associated with phys enc + * @phys_enc: Pointer to physical encoder structure + * @fb: Optional fb for specifying new mixer output resolution, may be NULL + * Return: Zero on success + */ +int sde_encoder_helper_reset_mixers(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb); + +/** + * sde_encoder_helper_report_irq_timeout - utility to report error that irq has + * timed out, including reporting frame error event to crtc and debug dump + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: Failing interrupt index + */ +void sde_encoder_helper_report_irq_timeout(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx); + +/** + * sde_encoder_helper_wait_for_irq - utility to wait on an irq. + * note: will call sde_encoder_helper_wait_for_irq on timeout + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: encoder interrupt index + * @wait_info: wait info struct + * @Return: 0 or -ERROR + */ +int sde_encoder_helper_wait_for_irq(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx, + struct sde_encoder_wait_info *wait_info); + +/** + * sde_encoder_helper_register_irq - register and enable an irq + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: encoder interrupt index + * @Return: 0 or -ERROR + */ +int sde_encoder_helper_register_irq(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx); + +/** + * sde_encoder_helper_unregister_irq - unregister and disable an irq + * @phys_enc: Pointer to physical encoder structure + * @intr_idx: encoder interrupt index + * @Return: 0 or -ERROR + */ +int sde_encoder_helper_unregister_irq(struct sde_encoder_phys *phys_enc, + enum sde_intr_idx intr_idx); + +/** + * sde_encoder_helper_update_intf_cfg - update interface configuration for + * single control path. + * @phys_enc: Pointer to physical encoder structure + */ +void sde_encoder_helper_update_intf_cfg( + struct sde_encoder_phys *phys_enc); + +/** + * _sde_encoder_phys_is_dual_ctl - check if encoder needs dual ctl path. + * @phys_enc: Pointer to physical encoder structure + * @Return: true if dual ctl paths else false + */ +static inline bool _sde_encoder_phys_is_dual_ctl( + struct sde_encoder_phys *phys_enc) +{ + struct sde_kms *sde_kms; + enum sde_rm_topology_name topology; + + if (!phys_enc) { + pr_err("invalid phys_enc\n"); + return false; + } + + sde_kms = phys_enc->sde_kms; + if (!sde_kms) { + pr_err("invalid kms\n"); + return false; + } + + topology = sde_connector_get_topology_name(phys_enc->connector); + + return sde_rm_topology_is_dual_ctl(&sde_kms->rm, topology); +} + +/** + * _sde_encoder_phys_is_ppsplit - check if pp_split is enabled + * @phys_enc: Pointer to physical encoder structure + * @Return: true or false + */ +static inline bool _sde_encoder_phys_is_ppsplit( + struct sde_encoder_phys *phys_enc) +{ + enum sde_rm_topology_name topology; + + if (!phys_enc) { + pr_err("invalid phys_enc\n"); + return false; + } + + topology = sde_connector_get_topology_name(phys_enc->connector); + if (topology == SDE_RM_TOPOLOGY_PPSPLIT) + return true; + + return false; +} + +static inline bool sde_encoder_phys_needs_single_flush( + struct sde_encoder_phys *phys_enc) +{ + if (!phys_enc) + return false; + + return (_sde_encoder_phys_is_ppsplit(phys_enc) || + !_sde_encoder_phys_is_dual_ctl(phys_enc)); +} + +/** + * sde_encoder_helper_phys_disable - helper function to disable virt encoder + * @phys_enc: Pointer to physical encoder structure + * @wb_enc: Pointer to writeback encoder structure + */ +void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc, + struct sde_encoder_phys_wb *wb_enc); + +/** + * sde_encoder_helper_setup_misr - helper function to setup misr + * @enable: enable/disable flag + * @frame_count: frame count for misr + */ +void sde_encoder_helper_setup_misr(struct sde_encoder_phys *phys_enc, + bool enable, u32 frame_count); + +/** + * sde_encoder_helper_collect_misr - helper function to collect misr + * @nonblock: blocking/non-blocking flag + * @misr_value: pointer to misr value + * @Return: zero on success + */ +int sde_encoder_helper_collect_misr(struct sde_encoder_phys *phys_enc, + bool nonblock, u32 *misr_value); + +#endif /* __sde_encoder_phys_H__ */ diff --git a/techpack/display/msm/sde/sde_encoder_phys_cmd.c b/techpack/display/msm/sde/sde_encoder_phys_cmd.c new file mode 100644 index 0000000000000000000000000000000000000000..4f99a496bcfab9b0d856365780a6a1c54457b40f --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder_phys_cmd.c @@ -0,0 +1,2068 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include "sde_encoder_phys.h" +#include "sde_hw_interrupts.h" +#include "sde_core_irq.h" +#include "sde_formats.h" +#include "sde_trace.h" + +#define SDE_DEBUG_CMDENC(e, fmt, ...) SDE_DEBUG("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) ? (e)->base.intf_idx - INTF_0 : -1, ##__VA_ARGS__) + +#define SDE_ERROR_CMDENC(e, fmt, ...) SDE_ERROR("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) ? (e)->base.intf_idx - INTF_0 : -1, ##__VA_ARGS__) + +#define to_sde_encoder_phys_cmd(x) \ + container_of(x, struct sde_encoder_phys_cmd, base) + +#define PP_TIMEOUT_MAX_TRIALS 4 + +/* + * Tearcheck sync start and continue thresholds are empirically found + * based on common panels In the future, may want to allow panels to override + * these default values + */ +#define DEFAULT_TEARCHECK_SYNC_THRESH_START 4 +#define DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE 4 + +#define SDE_ENC_WR_PTR_START_TIMEOUT_US 20000 +#define AUTOREFRESH_SEQ1_POLL_TIME 2000 +#define AUTOREFRESH_SEQ2_POLL_TIME 25000 +#define AUTOREFRESH_SEQ2_POLL_TIMEOUT 1000000 + +static inline int _sde_encoder_phys_cmd_get_idle_timeout( + struct sde_encoder_phys_cmd *cmd_enc) +{ + return cmd_enc->autorefresh.cfg.frame_count ? + cmd_enc->autorefresh.cfg.frame_count * + KICKOFF_TIMEOUT_MS : KICKOFF_TIMEOUT_MS; +} + +static inline bool sde_encoder_phys_cmd_is_master( + struct sde_encoder_phys *phys_enc) +{ + return (phys_enc->split_role != ENC_ROLE_SLAVE) ? true : false; +} + +static bool sde_encoder_phys_cmd_mode_fixup( + struct sde_encoder_phys *phys_enc, + const struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + if (phys_enc) + SDE_DEBUG_CMDENC(to_sde_encoder_phys_cmd(phys_enc), "\n"); + return true; +} + +static uint64_t _sde_encoder_phys_cmd_get_autorefresh_property( + struct sde_encoder_phys *phys_enc) +{ + struct drm_connector *conn = phys_enc->connector; + + if (!conn || !conn->state) + return 0; + + return sde_connector_get_property(conn->state, + CONNECTOR_PROP_AUTOREFRESH); +} + +static void _sde_encoder_phys_cmd_config_autorefresh( + struct sde_encoder_phys *phys_enc, + u32 new_frame_count) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; + struct sde_hw_intf *hw_intf = phys_enc->hw_intf; + struct drm_connector *conn = phys_enc->connector; + struct sde_hw_autorefresh *cfg_cur, cfg_nxt; + + if (!conn || !conn->state || !hw_pp || !hw_intf) + return; + + cfg_cur = &cmd_enc->autorefresh.cfg; + + /* autorefresh property value should be validated already */ + memset(&cfg_nxt, 0, sizeof(cfg_nxt)); + cfg_nxt.frame_count = new_frame_count; + cfg_nxt.enable = (cfg_nxt.frame_count != 0); + + SDE_DEBUG_CMDENC(cmd_enc, "autorefresh state %d->%d framecount %d\n", + cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); + SDE_EVT32(DRMID(phys_enc->parent), hw_pp->idx, hw_intf->idx, + cfg_cur->enable, cfg_nxt.enable, cfg_nxt.frame_count); + + /* only proceed on state changes */ + if (cfg_nxt.enable == cfg_cur->enable) + return; + + memcpy(cfg_cur, &cfg_nxt, sizeof(*cfg_cur)); + + if (phys_enc->has_intf_te && hw_intf->ops.setup_autorefresh) + hw_intf->ops.setup_autorefresh(hw_intf, cfg_cur); + else if (hw_pp->ops.setup_autorefresh) + hw_pp->ops.setup_autorefresh(hw_pp, cfg_cur); +} + +static void _sde_encoder_phys_cmd_update_flush_mask( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc; + struct sde_hw_ctl *ctl; + + if (!phys_enc || !phys_enc->hw_intf || !phys_enc->hw_pp) + return; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + ctl = phys_enc->hw_ctl; + + if (!ctl) + return; + + if (!ctl->ops.update_bitmask_intf || + (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) && + !ctl->ops.update_bitmask_merge3d)) { + SDE_ERROR("invalid hw_ctl ops %d\n", ctl->idx); + return; + } + + ctl->ops.update_bitmask_intf(ctl, phys_enc->intf_idx, 1); + + if (ctl->ops.update_bitmask_merge3d && phys_enc->hw_pp->merge_3d) + ctl->ops.update_bitmask_merge3d(ctl, + phys_enc->hw_pp->merge_3d->idx, 1); + + SDE_DEBUG_CMDENC(cmd_enc, "update pending flush ctl %d intf_idx %x\n", + ctl->idx - CTL_0, phys_enc->intf_idx); +} + +static void _sde_encoder_phys_cmd_update_intf_cfg( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_hw_ctl *ctl; + + if (!phys_enc) + return; + + ctl = phys_enc->hw_ctl; + if (!ctl) + return; + + if (ctl->ops.setup_intf_cfg) { + struct sde_hw_intf_cfg intf_cfg = { 0 }; + + intf_cfg.intf = phys_enc->intf_idx; + intf_cfg.intf_mode_sel = SDE_CTL_MODE_SEL_CMD; + intf_cfg.stream_sel = cmd_enc->stream_sel; + intf_cfg.mode_3d = + sde_encoder_helper_get_3d_blend_mode(phys_enc); + ctl->ops.setup_intf_cfg(ctl, &intf_cfg); + } else if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features)) { + sde_encoder_helper_update_intf_cfg(phys_enc); + } +} + +static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + u32 event = 0; + + if (!phys_enc || !phys_enc->hw_pp) + return; + + SDE_ATRACE_BEGIN("pp_done_irq"); + + /* notify all synchronous clients first, then asynchronous clients */ + if (phys_enc->parent_ops.handle_frame_done && + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) { + event = SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + spin_lock(phys_enc->enc_spinlock); + phys_enc->parent_ops.handle_frame_done(phys_enc->parent, + phys_enc, event); + spin_unlock(phys_enc->enc_spinlock); + } + + SDE_EVT32_IRQ(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, event); + + /* Signal any waiting atomic commit thread */ + wake_up_all(&phys_enc->pending_kickoff_wq); + SDE_ATRACE_END("pp_done_irq"); +} + +static void sde_encoder_phys_cmd_autorefresh_done_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + unsigned long lock_flags; + int new_cnt; + + if (!cmd_enc) + return; + + phys_enc = &cmd_enc->base; + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + new_cnt = atomic_add_unless(&cmd_enc->autorefresh.kickoff_cnt, -1, 0); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + SDE_EVT32_IRQ(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + new_cnt); + + /* Signal any waiting atomic commit thread */ + wake_up_all(&cmd_enc->autorefresh.kickoff_wq); +} + +static void sde_encoder_phys_cmd_te_rd_ptr_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + struct sde_encoder_phys_cmd *cmd_enc; + u32 scheduler_status = INVALID_CTL_STATUS; + struct sde_hw_ctl *ctl; + struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}}; + struct sde_encoder_phys_cmd_te_timestamp *te_timestamp; + unsigned long lock_flags; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) + return; + + SDE_ATRACE_BEGIN("rd_ptr_irq"); + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + ctl = phys_enc->hw_ctl; + + if (ctl && ctl->ops.get_scheduler_status) + scheduler_status = ctl->ops.get_scheduler_status(ctl); + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + te_timestamp = list_first_entry_or_null(&cmd_enc->te_timestamp_list, + struct sde_encoder_phys_cmd_te_timestamp, list); + if (te_timestamp) { + list_del_init(&te_timestamp->list); + te_timestamp->timestamp = ktime_get(); + list_add_tail(&te_timestamp->list, &cmd_enc->te_timestamp_list); + } + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + sde_encoder_helper_get_pp_line_count(phys_enc->parent, info); + SDE_EVT32_IRQ(DRMID(phys_enc->parent), + info[0].pp_idx, info[0].intf_idx, + info[0].wr_ptr_line_count, info[0].intf_frame_count, + info[1].pp_idx, info[1].intf_idx, + info[1].wr_ptr_line_count, info[1].intf_frame_count, + scheduler_status); + + if (phys_enc->parent_ops.handle_vblank_virt) + phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, + phys_enc); + + atomic_add_unless(&cmd_enc->pending_vblank_cnt, -1, 0); + wake_up_all(&cmd_enc->pending_vblank_wq); + SDE_ATRACE_END("rd_ptr_irq"); +} + +static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + struct sde_hw_ctl *ctl; + u32 event = 0; + struct sde_hw_pp_vsync_info info[MAX_CHANNELS_PER_ENC] = {{0}}; + + if (!phys_enc || !phys_enc->hw_ctl) + return; + + SDE_ATRACE_BEGIN("wr_ptr_irq"); + ctl = phys_enc->hw_ctl; + + if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) { + event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; + if (phys_enc->parent_ops.handle_frame_done) { + spin_lock(phys_enc->enc_spinlock); + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, event); + spin_unlock(phys_enc->enc_spinlock); + } + } + + sde_encoder_helper_get_pp_line_count(phys_enc->parent, info); + SDE_EVT32_IRQ(DRMID(phys_enc->parent), + ctl->idx - CTL_0, event, + info[0].pp_idx, info[0].intf_idx, info[0].wr_ptr_line_count, + info[1].pp_idx, info[1].intf_idx, info[1].wr_ptr_line_count); + + /* Signal any waiting wr_ptr start interrupt */ + wake_up_all(&phys_enc->pending_kickoff_wq); + SDE_ATRACE_END("wr_ptr_irq"); +} + +static void sde_encoder_phys_cmd_underrun_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + + if (!phys_enc) + return; + + if (phys_enc->parent_ops.handle_underrun_virt) + phys_enc->parent_ops.handle_underrun_virt(phys_enc->parent, + phys_enc); +} + +static void _sde_encoder_phys_cmd_setup_irq_hw_idx( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_irq *irq; + struct sde_kms *sde_kms; + int ret = 0; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) { + SDE_ERROR("invalid args %d %d\n", !phys_enc, + phys_enc ? !phys_enc->hw_pp : 0); + return; + } + + if (phys_enc->has_intf_te && !phys_enc->hw_intf) { + SDE_ERROR("invalid intf configuration\n"); + return; + } + + sde_kms = phys_enc->sde_kms; + mutex_lock(&sde_kms->vblank_ctl_global_lock); + + if (atomic_read(&phys_enc->vblank_refcount)) { + SDE_ERROR( + "vblank_refcount mismatch detected, try to reset %d\n", + atomic_read(&phys_enc->vblank_refcount)); + ret = sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_RDPTR); + if (ret) + SDE_ERROR( + "control vblank irq registration error %d\n", + ret); + } + atomic_set(&phys_enc->vblank_refcount, 0); + + irq = &phys_enc->irq[INTR_IDX_CTL_START]; + irq->hw_idx = phys_enc->hw_ctl->idx; + irq->irq_idx = -EINVAL; + + irq = &phys_enc->irq[INTR_IDX_PINGPONG]; + irq->hw_idx = phys_enc->hw_pp->idx; + irq->irq_idx = -EINVAL; + + irq = &phys_enc->irq[INTR_IDX_RDPTR]; + irq->irq_idx = -EINVAL; + if (phys_enc->has_intf_te) + irq->hw_idx = phys_enc->hw_intf->idx; + else + irq->hw_idx = phys_enc->hw_pp->idx; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + irq->hw_idx = phys_enc->intf_idx; + irq->irq_idx = -EINVAL; + + irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; + irq->irq_idx = -EINVAL; + if (phys_enc->has_intf_te) + irq->hw_idx = phys_enc->hw_intf->idx; + else + irq->hw_idx = phys_enc->hw_pp->idx; + + irq = &phys_enc->irq[INTR_IDX_WRPTR]; + irq->irq_idx = -EINVAL; + if (phys_enc->has_intf_te) + irq->hw_idx = phys_enc->hw_intf->idx; + else + irq->hw_idx = phys_enc->hw_pp->idx; + + mutex_unlock(&sde_kms->vblank_ctl_global_lock); + +} + +static void sde_encoder_phys_cmd_cont_splash_mode_set( + struct sde_encoder_phys *phys_enc, + struct drm_display_mode *adj_mode) +{ + struct sde_hw_intf *hw_intf; + struct sde_hw_pingpong *hw_pp; + struct sde_encoder_phys_cmd *cmd_enc; + + if (!phys_enc || !adj_mode) { + SDE_ERROR("invalid args\n"); + return; + } + + phys_enc->cached_mode = *adj_mode; + phys_enc->enable_state = SDE_ENC_ENABLED; + + if (!phys_enc->hw_ctl || !phys_enc->hw_pp) { + SDE_DEBUG("invalid ctl:%d pp:%d\n", + (phys_enc->hw_ctl == NULL), + (phys_enc->hw_pp == NULL)); + return; + } + + if (sde_encoder_phys_cmd_is_master(phys_enc)) { + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + hw_pp = phys_enc->hw_pp; + hw_intf = phys_enc->hw_intf; + + if (phys_enc->has_intf_te && hw_intf && + hw_intf->ops.get_autorefresh) { + hw_intf->ops.get_autorefresh(hw_intf, + &cmd_enc->autorefresh.cfg); + } else if (hw_pp && hw_pp->ops.get_autorefresh) { + hw_pp->ops.get_autorefresh(hw_pp, + &cmd_enc->autorefresh.cfg); + } + } + + _sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc); +} + +static void sde_encoder_phys_cmd_mode_set( + struct sde_encoder_phys *phys_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_rm *rm = &phys_enc->sde_kms->rm; + struct sde_rm_hw_iter iter; + int i, instance; + + if (!phys_enc || !mode || !adj_mode) { + SDE_ERROR("invalid args\n"); + return; + } + phys_enc->cached_mode = *adj_mode; + SDE_DEBUG_CMDENC(cmd_enc, "caching mode:\n"); + drm_mode_debug_printmodeline(adj_mode); + + instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0; + + /* Retrieve previously allocated HW Resources. Shouldn't fail */ + sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL); + for (i = 0; i <= instance; i++) { + if (sde_rm_get_hw(rm, &iter)) + phys_enc->hw_ctl = (struct sde_hw_ctl *)iter.hw; + } + + if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) { + SDE_ERROR_CMDENC(cmd_enc, "failed to init ctl: %ld\n", + PTR_ERR(phys_enc->hw_ctl)); + phys_enc->hw_ctl = NULL; + return; + } + + sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_INTF); + for (i = 0; i <= instance; i++) { + if (sde_rm_get_hw(rm, &iter)) + phys_enc->hw_intf = (struct sde_hw_intf *)iter.hw; + } + + if (IS_ERR_OR_NULL(phys_enc->hw_intf)) { + SDE_ERROR_CMDENC(cmd_enc, "failed to init intf: %ld\n", + PTR_ERR(phys_enc->hw_intf)); + phys_enc->hw_intf = NULL; + return; + } + + _sde_encoder_phys_cmd_setup_irq_hw_idx(phys_enc); +} + +static int _sde_encoder_phys_cmd_handle_ppdone_timeout( + struct sde_encoder_phys *phys_enc, + bool recovery_events) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + u32 frame_event = SDE_ENCODER_FRAME_EVENT_ERROR + | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + struct drm_connector *conn; + int event; + u32 pending_kickoff_cnt; + unsigned long lock_flags; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) + return -EINVAL; + + conn = phys_enc->connector; + + /* decrement the kickoff_cnt before checking for ESD status */ + if (!atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) + return 0; + + cmd_enc->pp_timeout_report_cnt++; + pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt) + 1; + + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, + cmd_enc->pp_timeout_report_cnt, + pending_kickoff_cnt, + frame_event); + + /* check if panel is still sending TE signal or not */ + if (sde_connector_esd_status(phys_enc->connector)) + goto exit; + + /* to avoid flooding, only log first time, and "dead" time */ + if (cmd_enc->pp_timeout_report_cnt == 1) { + SDE_ERROR_CMDENC(cmd_enc, + "pp:%d kickoff timed out ctl %d koff_cnt %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_ctl->idx - CTL_0, + pending_kickoff_cnt); + + SDE_EVT32(DRMID(phys_enc->parent), SDE_EVTLOG_FATAL); + sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR); + if (sde_kms_is_secure_session_inprogress(phys_enc->sde_kms)) + SDE_DBG_DUMP("secure", "all", "dbg_bus"); + else + SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus"); + sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR); + } + + /* + * if the recovery event is registered by user, don't panic + * trigger panic on first timeout if no listener registered + */ + if (recovery_events) { + event = cmd_enc->pp_timeout_report_cnt > PP_TIMEOUT_MAX_TRIALS ? + SDE_RECOVERY_HARD_RESET : SDE_RECOVERY_CAPTURE; + sde_connector_event_notify(conn, DRM_EVENT_SDE_HW_RECOVERY, + sizeof(uint8_t), event); + } else if (cmd_enc->pp_timeout_report_cnt) { + SDE_DBG_DUMP("dsi_dbg_bus", "panic"); + } + + /* request a ctl reset before the next kickoff */ + phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET; + +exit: + if (phys_enc->parent_ops.handle_frame_done) { + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, frame_event); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + } + + return -ETIMEDOUT; +} + +static bool _sde_encoder_phys_is_ppsplit_slave( + struct sde_encoder_phys *phys_enc) +{ + if (!phys_enc) + return false; + + return _sde_encoder_phys_is_ppsplit(phys_enc) && + phys_enc->split_role == ENC_ROLE_SLAVE; +} + +static bool _sde_encoder_phys_is_disabling_ppsplit_slave( + struct sde_encoder_phys *phys_enc) +{ + enum sde_rm_topology_name old_top; + + if (!phys_enc || !phys_enc->connector || + phys_enc->split_role != ENC_ROLE_SLAVE) + return false; + + old_top = sde_connector_get_old_topology_name( + phys_enc->connector->state); + + return old_top == SDE_RM_TOPOLOGY_PPSPLIT; +} + +static int _sde_encoder_phys_cmd_poll_write_pointer_started( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; + struct sde_hw_intf *hw_intf = phys_enc->hw_intf; + struct sde_hw_pp_vsync_info info; + u32 timeout_us = SDE_ENC_WR_PTR_START_TIMEOUT_US; + int ret = 0; + + if (!hw_pp || !hw_intf) + return 0; + + if (phys_enc->has_intf_te) { + if (!hw_intf->ops.get_vsync_info || + !hw_intf->ops.poll_timeout_wr_ptr) + goto end; + } else { + if (!hw_pp->ops.get_vsync_info || + !hw_pp->ops.poll_timeout_wr_ptr) + goto end; + } + + if (phys_enc->has_intf_te) + ret = hw_intf->ops.get_vsync_info(hw_intf, &info); + else + ret = hw_pp->ops.get_vsync_info(hw_pp, &info); + + if (ret) + return ret; + + SDE_DEBUG_CMDENC(cmd_enc, + "pp:%d intf:%d rd_ptr %d wr_ptr %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + info.rd_ptr_line_count, + info.wr_ptr_line_count); + SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + info.wr_ptr_line_count); + + if (phys_enc->has_intf_te) + ret = hw_intf->ops.poll_timeout_wr_ptr(hw_intf, timeout_us); + else + ret = hw_pp->ops.poll_timeout_wr_ptr(hw_pp, timeout_us); + + if (ret) { + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + timeout_us, + ret); + SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic"); + } + +end: + return ret; +} + +static bool _sde_encoder_phys_cmd_is_ongoing_pptx( + struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_pingpong *hw_pp; + struct sde_hw_pp_vsync_info info; + struct sde_hw_intf *hw_intf; + + if (!phys_enc) + return false; + + if (phys_enc->has_intf_te) { + hw_intf = phys_enc->hw_intf; + if (!hw_intf || !hw_intf->ops.get_vsync_info) + return false; + + hw_intf->ops.get_vsync_info(hw_intf, &info); + } else { + hw_pp = phys_enc->hw_pp; + if (!hw_pp || !hw_pp->ops.get_vsync_info) + return false; + + hw_pp->ops.get_vsync_info(hw_pp, &info); + } + + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + atomic_read(&phys_enc->pending_kickoff_cnt), + info.wr_ptr_line_count, + phys_enc->cached_mode.vdisplay); + + if (info.wr_ptr_line_count > 0 && info.wr_ptr_line_count < + phys_enc->cached_mode.vdisplay) + return true; + + return false; +} + +static bool _sde_encoder_phys_cmd_is_scheduler_idle( + struct sde_encoder_phys *phys_enc) +{ + bool wr_ptr_wait_success = true; + unsigned long lock_flags; + bool ret = false; + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_hw_ctl *ctl = phys_enc->hw_ctl; + + if (sde_encoder_phys_cmd_is_master(phys_enc)) + wr_ptr_wait_success = cmd_enc->wr_ptr_wait_success; + + /* + * Handle cases where a pp-done interrupt is missed + * due to irq latency with POSTED start + */ + if (wr_ptr_wait_success && + (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) && + ctl->ops.get_scheduler_status && + (ctl->ops.get_scheduler_status(ctl) & BIT(0)) && + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) && + phys_enc->parent_ops.handle_frame_done) { + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + atomic_read(&phys_enc->pending_kickoff_cnt)); + + ret = true; + } + + return ret; +} + +static int _sde_encoder_phys_cmd_wait_for_idle( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_encoder_wait_info wait_info = {0}; + bool recovery_events; + int ret; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + if (atomic_read(&phys_enc->pending_kickoff_cnt) > 1) + wait_info.count_check = 1; + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + recovery_events = sde_encoder_recovery_events_enabled( + phys_enc->parent); + + /* slave encoder doesn't enable for ppsplit */ + if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) + return 0; + + if (_sde_encoder_phys_cmd_is_scheduler_idle(phys_enc)) + return 0; + + ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, + &wait_info); + if (ret == -ETIMEDOUT) { + if (_sde_encoder_phys_cmd_is_scheduler_idle(phys_enc)) + return 0; + + _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc, + recovery_events); + } else if (!ret) { + if (cmd_enc->pp_timeout_report_cnt && recovery_events) { + struct drm_connector *conn = phys_enc->connector; + + sde_connector_event_notify(conn, + DRM_EVENT_SDE_HW_RECOVERY, + sizeof(uint8_t), + SDE_RECOVERY_SUCCESS); + } + cmd_enc->pp_timeout_report_cnt = 0; + } + + return ret; +} + +static int _sde_encoder_phys_cmd_wait_for_autorefresh_done( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_encoder_wait_info wait_info = {0}; + int ret = 0; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + /* only master deals with autorefresh */ + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + return 0; + + wait_info.wq = &cmd_enc->autorefresh.kickoff_wq; + wait_info.atomic_cnt = &cmd_enc->autorefresh.kickoff_cnt; + wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc); + + /* wait for autorefresh kickoff to start */ + ret = sde_encoder_helper_wait_for_irq(phys_enc, + INTR_IDX_AUTOREFRESH_DONE, &wait_info); + + /* double check that kickoff has started by reading write ptr reg */ + if (!ret) + ret = _sde_encoder_phys_cmd_poll_write_pointer_started( + phys_enc); + else + sde_encoder_helper_report_irq_timeout(phys_enc, + INTR_IDX_AUTOREFRESH_DONE); + + return ret; +} + +static int sde_encoder_phys_cmd_control_vblank_irq( + struct sde_encoder_phys *phys_enc, + bool enable) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + int ret = 0; + int refcount; + struct sde_kms *sde_kms; + + if (!phys_enc || !phys_enc->hw_pp) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + sde_kms = phys_enc->sde_kms; + + mutex_lock(&sde_kms->vblank_ctl_global_lock); + refcount = atomic_read(&phys_enc->vblank_refcount); + + /* Slave encoders don't report vblank */ + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + goto end; + + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; + goto end; + } + + SDE_DEBUG_CMDENC(cmd_enc, "[%pS] enable=%d/%d\n", + __builtin_return_address(0), enable, refcount); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, + enable, refcount); + + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) { + ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR); + if (ret) + atomic_dec_return(&phys_enc->vblank_refcount); + } else if (!enable && + atomic_dec_return(&phys_enc->vblank_refcount) == 0) { + ret = sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_RDPTR); + if (ret) + atomic_inc_return(&phys_enc->vblank_refcount); + } + +end: + if (ret) { + SDE_ERROR_CMDENC(cmd_enc, + "control vblank irq error %d, enable %d, refcount %d\n", + ret, enable, refcount); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + enable, refcount, SDE_EVTLOG_ERROR); + } + + mutex_unlock(&sde_kms->vblank_ctl_global_lock); + return ret; +} + +void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, + bool enable) +{ + struct sde_encoder_phys_cmd *cmd_enc; + + if (!phys_enc) + return; + + /** + * pingpong split slaves do not register for IRQs + * check old and new topologies + */ + if (_sde_encoder_phys_is_ppsplit_slave(phys_enc) || + _sde_encoder_phys_is_disabling_ppsplit_slave(phys_enc)) + return; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, + enable, atomic_read(&phys_enc->vblank_refcount)); + + if (enable) { + sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG); + sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true); + + if (sde_encoder_phys_cmd_is_master(phys_enc)) { + sde_encoder_helper_register_irq(phys_enc, + INTR_IDX_WRPTR); + sde_encoder_helper_register_irq(phys_enc, + INTR_IDX_AUTOREFRESH_DONE); + } + + } else { + if (sde_encoder_phys_cmd_is_master(phys_enc)) { + sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_WRPTR); + sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_AUTOREFRESH_DONE); + } + + sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false); + sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG); + } +} + +static int _get_tearcheck_threshold(struct sde_encoder_phys *phys_enc, + u32 *extra_frame_trigger_time) +{ + struct drm_connector *conn = phys_enc->connector; + u32 qsync_mode; + struct drm_display_mode *mode; + u32 threshold_lines = 0; + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + *extra_frame_trigger_time = 0; + if (!conn || !conn->state) + return 0; + + mode = &phys_enc->cached_mode; + qsync_mode = sde_connector_get_qsync_mode(conn); + + if (mode && (qsync_mode == SDE_RM_QSYNC_CONTINUOUS_MODE)) { + u32 qsync_min_fps = 0; + u32 default_fps = mode->vrefresh; + u32 yres = mode->vtotal; + u32 slow_time_ns; + u32 default_time_ns; + u32 extra_time_ns; + u32 total_extra_lines; + u32 default_line_time_ns; + + if (phys_enc->parent_ops.get_qsync_fps) + phys_enc->parent_ops.get_qsync_fps( + phys_enc->parent, &qsync_min_fps); + + if (!qsync_min_fps || !default_fps || !yres) { + SDE_ERROR_CMDENC(cmd_enc, + "wrong qsync params %d %d %d\n", + qsync_min_fps, default_fps, yres); + goto exit; + } + + if (qsync_min_fps >= default_fps) { + SDE_ERROR_CMDENC(cmd_enc, + "qsync fps:%d must be less than default:%d\n", + qsync_min_fps, default_fps); + goto exit; + } + + /* Calculate the number of extra lines*/ + slow_time_ns = (1 * 1000000000) / qsync_min_fps; + default_time_ns = (1 * 1000000000) / default_fps; + extra_time_ns = slow_time_ns - default_time_ns; + default_line_time_ns = (1 * 1000000000) / (default_fps * yres); + + total_extra_lines = extra_time_ns / default_line_time_ns; + threshold_lines += total_extra_lines; + + SDE_DEBUG_CMDENC(cmd_enc, "slow:%d default:%d extra:%d(ns)\n", + slow_time_ns, default_time_ns, extra_time_ns); + SDE_DEBUG_CMDENC(cmd_enc, "extra_lines:%d threshold:%d\n", + total_extra_lines, threshold_lines); + SDE_DEBUG_CMDENC(cmd_enc, "min_fps:%d fps:%d yres:%d\n", + qsync_min_fps, default_fps, yres); + + SDE_EVT32(qsync_mode, qsync_min_fps, extra_time_ns, default_fps, + yres, threshold_lines); + + *extra_frame_trigger_time = extra_time_ns; + } + +exit: + threshold_lines += DEFAULT_TEARCHECK_SYNC_THRESH_START; + + return threshold_lines; +} + +static void sde_encoder_phys_cmd_tearcheck_config( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_hw_tear_check tc_cfg = { 0 }; + struct drm_display_mode *mode; + bool tc_enable = true; + u32 vsync_hz, extra_frame_trigger_time; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) { + SDE_ERROR("invalid encoder\n"); + return; + } + mode = &phys_enc->cached_mode; + + SDE_DEBUG_CMDENC(cmd_enc, "pp %d, intf %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0); + + if (phys_enc->has_intf_te) { + if (!phys_enc->hw_intf->ops.setup_tearcheck || + !phys_enc->hw_intf->ops.enable_tearcheck) { + SDE_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); + return; + } + } else { + if (!phys_enc->hw_pp->ops.setup_tearcheck || + !phys_enc->hw_pp->ops.enable_tearcheck) { + SDE_DEBUG_CMDENC(cmd_enc, "tearcheck not supported\n"); + return; + } + } + + sde_kms = phys_enc->sde_kms; + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) { + SDE_ERROR("invalid device\n"); + return; + } + priv = sde_kms->dev->dev_private; + + /* + * TE default: dsi byte clock calculated base on 70 fps; + * around 14 ms to complete a kickoff cycle if te disabled; + * vclk_line base on 60 fps; write is faster than read; + * init == start == rdptr; + * + * vsync_count is ratio of MDP VSYNC clock frequency to LCD panel + * frequency divided by the no. of rows (lines) in the LCDpanel. + */ + vsync_hz = sde_power_clk_get_rate(&priv->phandle, "vsync_clk"); + if (!vsync_hz || !mode->vtotal || !mode->vrefresh) { + SDE_DEBUG_CMDENC(cmd_enc, + "invalid params - vsync_hz %u vtot %u vrefresh %u\n", + vsync_hz, mode->vtotal, mode->vrefresh); + return; + } + + tc_cfg.vsync_count = vsync_hz / (mode->vtotal * mode->vrefresh); + + /* enable external TE after kickoff to avoid premature autorefresh */ + tc_cfg.hw_vsync_mode = 0; + + /* + * By setting sync_cfg_height to near max register value, we essentially + * disable sde hw generated TE signal, since hw TE will arrive first. + * Only caveat is if due to error, we hit wrap-around. + */ + tc_cfg.sync_cfg_height = 0xFFF0; + tc_cfg.vsync_init_val = mode->vdisplay; + tc_cfg.sync_threshold_start = _get_tearcheck_threshold(phys_enc, + &extra_frame_trigger_time); + tc_cfg.sync_threshold_continue = DEFAULT_TEARCHECK_SYNC_THRESH_CONTINUE; + tc_cfg.start_pos = mode->vdisplay; + tc_cfg.rd_ptr_irq = mode->vdisplay + 1; + tc_cfg.wr_ptr_irq = 1; + + SDE_DEBUG_CMDENC(cmd_enc, + "tc %d intf %d vsync_clk_speed_hz %u vtotal %u vrefresh %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + vsync_hz, mode->vtotal, mode->vrefresh); + SDE_DEBUG_CMDENC(cmd_enc, + "tc %d intf %d enable %u start_pos %u rd_ptr_irq %u wr_ptr_irq %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + tc_enable, tc_cfg.start_pos, tc_cfg.rd_ptr_irq, + tc_cfg.wr_ptr_irq); + SDE_DEBUG_CMDENC(cmd_enc, + "tc %d intf %d hw_vsync_mode %u vsync_count %u vsync_init_val %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + tc_cfg.hw_vsync_mode, tc_cfg.vsync_count, + tc_cfg.vsync_init_val); + SDE_DEBUG_CMDENC(cmd_enc, + "tc %d intf %d cfgheight %u thresh_start %u thresh_cont %u\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + tc_cfg.sync_cfg_height, + tc_cfg.sync_threshold_start, tc_cfg.sync_threshold_continue); + + if (phys_enc->has_intf_te) { + phys_enc->hw_intf->ops.setup_tearcheck(phys_enc->hw_intf, + &tc_cfg); + phys_enc->hw_intf->ops.enable_tearcheck(phys_enc->hw_intf, + tc_enable); + } else { + phys_enc->hw_pp->ops.setup_tearcheck(phys_enc->hw_pp, &tc_cfg); + phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, + tc_enable); + } +} + +static void _sde_encoder_phys_cmd_pingpong_config( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) { + SDE_ERROR("invalid arg(s), enc %d\n", !phys_enc); + return; + } + + SDE_DEBUG_CMDENC(cmd_enc, "pp %d, enabling mode:\n", + phys_enc->hw_pp->idx - PINGPONG_0); + drm_mode_debug_printmodeline(&phys_enc->cached_mode); + + if (!_sde_encoder_phys_is_ppsplit_slave(phys_enc)) + _sde_encoder_phys_cmd_update_intf_cfg(phys_enc); + sde_encoder_phys_cmd_tearcheck_config(phys_enc); +} + +static void sde_encoder_phys_cmd_enable_helper( + struct sde_encoder_phys *phys_enc) +{ + if (!phys_enc || !phys_enc->hw_ctl || !phys_enc->hw_pp) { + SDE_ERROR("invalid arg(s), encoder %d\n", !phys_enc); + return; + } + + sde_encoder_helper_split_config(phys_enc, phys_enc->intf_idx); + + _sde_encoder_phys_cmd_pingpong_config(phys_enc); + + /* + * For pp-split, skip setting the flush bit for the slave intf, since + * both intfs use same ctl and HW will only flush the master. + */ + if (_sde_encoder_phys_is_ppsplit(phys_enc) && + !sde_encoder_phys_cmd_is_master(phys_enc)) + goto skip_flush; + + _sde_encoder_phys_cmd_update_flush_mask(phys_enc); + +skip_flush: + return; +} + +static void sde_encoder_phys_cmd_enable(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + if (!phys_enc || !phys_enc->hw_pp) { + SDE_ERROR("invalid phys encoder\n"); + return; + } + + SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); + + if (phys_enc->enable_state == SDE_ENC_ENABLED) { + if (!phys_enc->cont_splash_enabled) + SDE_ERROR("already enabled\n"); + return; + } + + sde_encoder_phys_cmd_enable_helper(phys_enc); + phys_enc->enable_state = SDE_ENC_ENABLED; +} + +static bool sde_encoder_phys_cmd_is_autorefresh_enabled( + struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_pingpong *hw_pp; + struct sde_hw_intf *hw_intf; + struct sde_hw_autorefresh cfg; + int ret; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) + return false; + + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + return false; + + if (phys_enc->has_intf_te) { + hw_intf = phys_enc->hw_intf; + if (!hw_intf->ops.get_autorefresh) + return false; + + ret = hw_intf->ops.get_autorefresh(hw_intf, &cfg); + } else { + hw_pp = phys_enc->hw_pp; + if (!hw_pp->ops.get_autorefresh) + return false; + + ret = hw_pp->ops.get_autorefresh(hw_pp, &cfg); + } + + if (ret) + return false; + + return cfg.enable; +} + +static void sde_encoder_phys_cmd_connect_te( + struct sde_encoder_phys *phys_enc, bool enable) +{ + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) + return; + + if (phys_enc->has_intf_te && + phys_enc->hw_intf->ops.connect_external_te) + phys_enc->hw_intf->ops.connect_external_te(phys_enc->hw_intf, + enable); + else if (phys_enc->hw_pp->ops.connect_external_te) + phys_enc->hw_pp->ops.connect_external_te(phys_enc->hw_pp, + enable); + else + return; + + SDE_EVT32(DRMID(phys_enc->parent), enable); +} + +static int sde_encoder_phys_cmd_te_get_line_count( + struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_pingpong *hw_pp; + struct sde_hw_intf *hw_intf; + u32 line_count; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) + return -EINVAL; + + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + return -EINVAL; + + if (phys_enc->has_intf_te) { + hw_intf = phys_enc->hw_intf; + if (!hw_intf->ops.get_line_count) + return -EINVAL; + + line_count = hw_intf->ops.get_line_count(hw_intf); + } else { + hw_pp = phys_enc->hw_pp; + if (!hw_pp->ops.get_line_count) + return -EINVAL; + + line_count = hw_pp->ops.get_line_count(hw_pp); + } + + return line_count; +} + +static int sde_encoder_phys_cmd_get_write_line_count( + struct sde_encoder_phys *phys_enc) +{ + struct sde_hw_pingpong *hw_pp; + struct sde_hw_intf *hw_intf; + struct sde_hw_pp_vsync_info info; + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) + return -EINVAL; + + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + return -EINVAL; + + if (phys_enc->has_intf_te) { + hw_intf = phys_enc->hw_intf; + if (!hw_intf->ops.get_vsync_info) + return -EINVAL; + + if (hw_intf->ops.get_vsync_info(hw_intf, &info)) + return -EINVAL; + } else { + hw_pp = phys_enc->hw_pp; + if (!hw_pp->ops.get_vsync_info) + return -EINVAL; + + if (hw_pp->ops.get_vsync_info(hw_pp, &info)) + return -EINVAL; + } + + return (int)info.wr_ptr_line_count; +} + +static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_intf) { + SDE_ERROR("invalid encoder\n"); + return; + } + SDE_DEBUG_CMDENC(cmd_enc, "pp %d intf %d state %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + phys_enc->enable_state); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->hw_intf->idx - INTF_0, + phys_enc->enable_state); + + if (phys_enc->enable_state == SDE_ENC_DISABLED) { + SDE_ERROR_CMDENC(cmd_enc, "already disabled\n"); + return; + } + + if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.enable_tearcheck) + phys_enc->hw_intf->ops.enable_tearcheck( + phys_enc->hw_intf, + false); + else if (phys_enc->hw_pp->ops.enable_tearcheck) + phys_enc->hw_pp->ops.enable_tearcheck(phys_enc->hw_pp, + false); + + phys_enc->enable_state = SDE_ENC_DISABLED; +} + +static void sde_encoder_phys_cmd_destroy(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + kfree(cmd_enc); +} + +static void sde_encoder_phys_cmd_get_hw_resources( + struct sde_encoder_phys *phys_enc, + struct sde_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + if ((phys_enc->intf_idx - INTF_0) >= INTF_MAX) { + SDE_ERROR("invalid intf idx:%d\n", phys_enc->intf_idx); + return; + } + + SDE_DEBUG_CMDENC(cmd_enc, "\n"); + hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_CMD; +} + +static int sde_encoder_phys_cmd_prepare_for_kickoff( + struct sde_encoder_phys *phys_enc, + struct sde_encoder_kickoff_params *params) +{ + struct sde_hw_tear_check tc_cfg = {0}; + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + int ret = 0; + u32 extra_frame_trigger_time; + + if (!phys_enc || !phys_enc->hw_pp) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0); + + phys_enc->frame_trigger_mode = params->frame_trigger_mode; + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(&phys_enc->pending_kickoff_cnt), + atomic_read(&cmd_enc->autorefresh.kickoff_cnt), + phys_enc->frame_trigger_mode); + + if (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_DEFAULT) { + /* + * Mark kickoff request as outstanding. If there are more + * than one outstanding frame, then we have to wait for the + * previous frame to complete + */ + ret = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + if (ret) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0); + SDE_ERROR("failed wait_for_idle: %d\n", ret); + } + } + + if (sde_connector_is_qsync_updated(phys_enc->connector)) { + tc_cfg.sync_threshold_start = + _get_tearcheck_threshold(phys_enc, + &extra_frame_trigger_time); + if (phys_enc->has_intf_te && + phys_enc->hw_intf->ops.update_tearcheck) + phys_enc->hw_intf->ops.update_tearcheck( + phys_enc->hw_intf, &tc_cfg); + else if (phys_enc->hw_pp->ops.update_tearcheck) + phys_enc->hw_pp->ops.update_tearcheck( + phys_enc->hw_pp, &tc_cfg); + SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start); + } + + SDE_DEBUG_CMDENC(cmd_enc, "pp:%d pending_cnt %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(&phys_enc->pending_kickoff_cnt)); + return ret; +} + +static bool _sde_encoder_phys_cmd_needs_vsync_change( + struct sde_encoder_phys *phys_enc, ktime_t profile_timestamp) +{ + struct sde_encoder_phys_cmd *cmd_enc; + struct sde_encoder_phys_cmd_te_timestamp *cur; + struct sde_encoder_phys_cmd_te_timestamp *prev = NULL; + ktime_t time_diff; + u64 l_bound = 0, u_bound = 0; + bool ret = false; + unsigned long lock_flags; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + sde_encoder_helper_get_jitter_bounds_ns(phys_enc->parent, + &l_bound, &u_bound); + if (!l_bound || !u_bound) { + SDE_ERROR_CMDENC(cmd_enc, "invalid vsync jitter bounds\n"); + return false; + } + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + list_for_each_entry_reverse(cur, &cmd_enc->te_timestamp_list, list) { + if (prev && ktime_after(cur->timestamp, profile_timestamp)) { + time_diff = ktime_sub(prev->timestamp, cur->timestamp); + if ((time_diff < l_bound) || (time_diff > u_bound)) { + ret = true; + break; + } + } + prev = cur; + } + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + if (ret) { + SDE_DEBUG_CMDENC(cmd_enc, + "time_diff:%llu, prev:%llu, cur:%llu, jitter:%llu/%llu\n", + time_diff, prev->timestamp, cur->timestamp, + l_bound, u_bound); + time_diff = div_s64(time_diff, 1000); + + SDE_EVT32(DRMID(phys_enc->parent), + (u32) (do_div(l_bound, 1000)), + (u32) (do_div(u_bound, 1000)), + (u32) (time_diff), SDE_EVTLOG_ERROR); + } + + return ret; +} + +static int _sde_encoder_phys_cmd_wait_for_wr_ptr( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct sde_encoder_wait_info wait_info = {0}; + int ret; + bool frame_pending = true; + struct sde_hw_ctl *ctl; + unsigned long lock_flags; + + if (!phys_enc || !phys_enc->hw_ctl) { + SDE_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + ctl = phys_enc->hw_ctl; + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + + /* slave encoder doesn't enable for ppsplit */ + if (_sde_encoder_phys_is_ppsplit_slave(phys_enc)) + return 0; + + ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WRPTR, + &wait_info); + if (ret == -ETIMEDOUT) { + struct sde_hw_ctl *ctl = phys_enc->hw_ctl; + + if (ctl && ctl->ops.get_start_state) + frame_pending = ctl->ops.get_start_state(ctl); + + ret = frame_pending ? ret : 0; + + /* + * There can be few cases of ESD where CTL_START is cleared but + * wr_ptr irq doesn't come. Signaling retire fence in these + * cases to avoid freeze and dangling pending_retire_fence_cnt + */ + if (!ret) { + SDE_EVT32(DRMID(phys_enc->parent), + SDE_EVTLOG_FUNC_CASE1); + + if (sde_encoder_phys_cmd_is_master(phys_enc) && + atomic_add_unless( + &phys_enc->pending_retire_fence_cnt, -1, 0)) { + spin_lock_irqsave(phys_enc->enc_spinlock, + lock_flags); + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); + spin_unlock_irqrestore(phys_enc->enc_spinlock, + lock_flags); + } + } + } + + cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false; + return ret; +} + +static int sde_encoder_phys_cmd_wait_for_tx_complete( + struct sde_encoder_phys *phys_enc) +{ + int rc; + struct sde_encoder_phys_cmd *cmd_enc; + + if (!phys_enc) + return -EINVAL; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + + if (!atomic_read(&phys_enc->pending_kickoff_cnt)) { + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->intf_idx - INTF_0, + phys_enc->enable_state); + return 0; + } + + rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc); + if (rc) { + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->intf_idx - INTF_0); + SDE_ERROR("failed wait_for_idle: %d\n", rc); + } + + return rc; +} + +static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout( + struct sde_encoder_phys *phys_enc, + ktime_t profile_timestamp) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + bool switch_te; + int ret = -ETIMEDOUT; + unsigned long lock_flags; + + switch_te = _sde_encoder_phys_cmd_needs_vsync_change( + phys_enc, profile_timestamp); + + SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_FUNC_ENTRY); + + if (switch_te) { + SDE_DEBUG_CMDENC(cmd_enc, + "wr_ptr_irq wait failed, retry with WD TE\n"); + + /* switch to watchdog TE and wait again */ + sde_encoder_helper_switch_vsync(phys_enc->parent, true); + + ret = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc); + + /* switch back to default TE */ + sde_encoder_helper_switch_vsync(phys_enc->parent, false); + } + + /* + * Signaling the retire fence at wr_ptr timeout + * to allow the next commit and avoid device freeze. + */ + if (ret == -ETIMEDOUT) { + SDE_ERROR_CMDENC(cmd_enc, + "wr_ptr_irq wait failed, switch_te:%d\n", switch_te); + SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_ERROR); + + if (sde_encoder_phys_cmd_is_master(phys_enc) && + atomic_add_unless( + &phys_enc->pending_retire_fence_cnt, -1, 0)) { + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE); + spin_unlock_irqrestore(phys_enc->enc_spinlock, + lock_flags); + } + } + + cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false; + + return ret; +} + +static int sde_encoder_phys_cmd_wait_for_commit_done( + struct sde_encoder_phys *phys_enc) +{ + int rc = 0, i, pending_cnt; + struct sde_encoder_phys_cmd *cmd_enc; + ktime_t profile_timestamp = ktime_get(); + u32 scheduler_status = INVALID_CTL_STATUS; + struct sde_hw_ctl *ctl; + + if (!phys_enc) + return -EINVAL; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + + /* only required for master controller */ + if (sde_encoder_phys_cmd_is_master(phys_enc)) { + rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc); + if (rc == -ETIMEDOUT) { + /* + * Profile all the TE received after profile_timestamp + * and if the jitter is more, switch to watchdog TE + * and wait for wr_ptr again. Finally move back to + * default TE. + */ + rc = _sde_encoder_phys_cmd_handle_wr_ptr_timeout( + phys_enc, profile_timestamp); + if (rc == -ETIMEDOUT) + goto wait_for_idle; + } + + if (cmd_enc->autorefresh.cfg.enable) + rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done( + phys_enc); + + ctl = phys_enc->hw_ctl; + if (ctl && ctl->ops.get_scheduler_status) + scheduler_status = ctl->ops.get_scheduler_status(ctl); + } + + /* wait for posted start or serialize trigger */ + pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + if ((pending_cnt > 1) || + (pending_cnt && (scheduler_status & BIT(0))) || + (!rc && phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_SERIALIZE)) + goto wait_for_idle; + + return rc; + +wait_for_idle: + pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + for (i = 0; i < pending_cnt; i++) + rc |= sde_encoder_wait_for_event(phys_enc->parent, + MSM_ENC_TX_COMPLETE); + if (rc) { + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_pp->idx - PINGPONG_0, + phys_enc->frame_trigger_mode, + atomic_read(&phys_enc->pending_kickoff_cnt), + phys_enc->enable_state, + cmd_enc->wr_ptr_wait_success, scheduler_status, rc); + SDE_ERROR("pp:%d failed wait_for_idle: %d\n", + phys_enc->hw_pp->idx - PINGPONG_0, rc); + if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET) + sde_encoder_needs_hw_reset(phys_enc->parent); + } + + return rc; +} + +static int sde_encoder_phys_cmd_wait_for_vblank( + struct sde_encoder_phys *phys_enc) +{ + int rc = 0; + struct sde_encoder_phys_cmd *cmd_enc; + struct sde_encoder_wait_info wait_info = {0}; + + if (!phys_enc) + return -EINVAL; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + + /* only required for master controller */ + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + return rc; + + wait_info.wq = &cmd_enc->pending_vblank_wq; + wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; + wait_info.timeout_ms = _sde_encoder_phys_cmd_get_idle_timeout(cmd_enc); + + atomic_inc(&cmd_enc->pending_vblank_cnt); + + rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_RDPTR, + &wait_info); + + return rc; +} + +static void sde_encoder_phys_cmd_update_split_role( + struct sde_encoder_phys *phys_enc, + enum sde_enc_split_role role) +{ + struct sde_encoder_phys_cmd *cmd_enc; + enum sde_enc_split_role old_role; + bool is_ppsplit; + + if (!phys_enc) + return; + + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + old_role = phys_enc->split_role; + is_ppsplit = _sde_encoder_phys_is_ppsplit(phys_enc); + + phys_enc->split_role = role; + + SDE_DEBUG_CMDENC(cmd_enc, "old role %d new role %d\n", + old_role, role); + + /* + * ppsplit solo needs to reprogram because intf may have swapped without + * role changing on left-only, right-only back-to-back commits + */ + if (!(is_ppsplit && role == ENC_ROLE_SOLO) && + (role == old_role || role == ENC_ROLE_SKIP)) + return; + + sde_encoder_helper_split_config(phys_enc, phys_enc->intf_idx); + _sde_encoder_phys_cmd_pingpong_config(phys_enc); + _sde_encoder_phys_cmd_update_flush_mask(phys_enc); +} + +static void _sde_encoder_autorefresh_disable_seq1( + struct sde_encoder_phys *phys_enc) +{ + int trial = 0; + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + /* + * If autorefresh is enabled, disable it and make sure it is safe to + * proceed with current frame commit/push. Sequence fallowed is, + * 1. Disable TE - caller will take care of it + * 2. Disable autorefresh config + * 4. Poll for frame transfer ongoing to be false + * 5. Enable TE back - caller will take care of it + */ + _sde_encoder_phys_cmd_config_autorefresh(phys_enc, 0); + + do { + udelay(AUTOREFRESH_SEQ1_POLL_TIME); + if ((trial * AUTOREFRESH_SEQ1_POLL_TIME) + > (KICKOFF_TIMEOUT_MS * USEC_PER_MSEC)) { + SDE_ERROR_CMDENC(cmd_enc, + "disable autorefresh failed\n"); + + phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET; + break; + } + + trial++; + } while (_sde_encoder_phys_cmd_is_ongoing_pptx(phys_enc)); +} + +static void _sde_encoder_autorefresh_disable_seq2( + struct sde_encoder_phys *phys_enc) +{ + int trial = 0; + struct sde_hw_mdp *hw_mdp = phys_enc->hw_mdptop; + u32 autorefresh_status = 0; + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + struct intf_tear_status tear_status; + struct sde_hw_intf *hw_intf = phys_enc->hw_intf; + + if (!hw_mdp->ops.get_autorefresh_status || + !hw_intf->ops.check_and_reset_tearcheck) { + SDE_DEBUG_CMDENC(cmd_enc, + "autofresh disable seq2 not supported\n"); + return; + } + + /* + * If autorefresh is still enabled after sequence-1, proceed with + * below sequence-2. + * 1. Disable autorefresh config + * 2. Run in loop: + * 2.1 Poll for autorefresh to be disabled + * 2.2 Log read and write count status + * 2.3 Replace te write count with start_pos to meet trigger window + */ + autorefresh_status = hw_mdp->ops.get_autorefresh_status(hw_mdp, + phys_enc->intf_idx); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0, + autorefresh_status, SDE_EVTLOG_FUNC_CASE1); + + if (!(autorefresh_status & BIT(7))) { + usleep_range(AUTOREFRESH_SEQ2_POLL_TIME, + AUTOREFRESH_SEQ2_POLL_TIME + 1); + + autorefresh_status = hw_mdp->ops.get_autorefresh_status(hw_mdp, + phys_enc->intf_idx); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0, + autorefresh_status, SDE_EVTLOG_FUNC_CASE2); + } + + while (autorefresh_status & BIT(7)) { + if (!trial) { + SDE_ERROR_CMDENC(cmd_enc, + "autofresh status:0x%x intf:%d\n", autorefresh_status, + phys_enc->intf_idx - INTF_0); + + _sde_encoder_phys_cmd_config_autorefresh(phys_enc, 0); + } + + usleep_range(AUTOREFRESH_SEQ2_POLL_TIME, + AUTOREFRESH_SEQ2_POLL_TIME + 1); + if ((trial * AUTOREFRESH_SEQ2_POLL_TIME) + > AUTOREFRESH_SEQ2_POLL_TIMEOUT) { + SDE_ERROR_CMDENC(cmd_enc, + "disable autorefresh failed\n"); + SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus", "panic"); + break; + } + + trial++; + autorefresh_status = hw_mdp->ops.get_autorefresh_status(hw_mdp, + phys_enc->intf_idx); + hw_intf->ops.check_and_reset_tearcheck(hw_intf, &tear_status); + SDE_ERROR_CMDENC(cmd_enc, + "autofresh status:0x%x intf:%d tear_read:0x%x tear_write:0x%x\n", + autorefresh_status, phys_enc->intf_idx - INTF_0, + tear_status.read_count, tear_status.write_count); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0, + autorefresh_status, tear_status.read_count, + tear_status.write_count); + } +} + +static void sde_encoder_phys_cmd_prepare_commit( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + + if (!phys_enc) + return; + + if (!sde_encoder_phys_cmd_is_master(phys_enc)) + return; + + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0, + cmd_enc->autorefresh.cfg.enable); + + if (!sde_encoder_phys_cmd_is_autorefresh_enabled(phys_enc)) + return; + + sde_encoder_phys_cmd_connect_te(phys_enc, false); + _sde_encoder_autorefresh_disable_seq1(phys_enc); + _sde_encoder_autorefresh_disable_seq2(phys_enc); + sde_encoder_phys_cmd_connect_te(phys_enc, true); + + SDE_DEBUG_CMDENC(cmd_enc, "autorefresh disabled successfully\n"); +} + +static void sde_encoder_phys_cmd_trigger_start( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc = + to_sde_encoder_phys_cmd(phys_enc); + u32 frame_cnt; + + if (!phys_enc) + return; + + /* we don't issue CTL_START when using autorefresh */ + frame_cnt = _sde_encoder_phys_cmd_get_autorefresh_property(phys_enc); + if (frame_cnt) { + _sde_encoder_phys_cmd_config_autorefresh(phys_enc, frame_cnt); + atomic_inc(&cmd_enc->autorefresh.kickoff_cnt); + } else { + sde_encoder_helper_trigger_start(phys_enc); + } + + /* wr_ptr_wait_success is set true when wr_ptr arrives */ + cmd_enc->wr_ptr_wait_success = false; +} + +static void sde_encoder_phys_cmd_setup_vsync_source( + struct sde_encoder_phys *phys_enc, + u32 vsync_source, bool is_dummy) +{ + if (!phys_enc || !phys_enc->hw_intf) + return; + + sde_encoder_helper_vsync_config(phys_enc, vsync_source, is_dummy); + + if (phys_enc->has_intf_te && phys_enc->hw_intf->ops.vsync_sel) + phys_enc->hw_intf->ops.vsync_sel(phys_enc->hw_intf, + vsync_source); +} + +static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops) +{ + ops->prepare_commit = sde_encoder_phys_cmd_prepare_commit; + ops->is_master = sde_encoder_phys_cmd_is_master; + ops->mode_set = sde_encoder_phys_cmd_mode_set; + ops->cont_splash_mode_set = sde_encoder_phys_cmd_cont_splash_mode_set; + ops->mode_fixup = sde_encoder_phys_cmd_mode_fixup; + ops->enable = sde_encoder_phys_cmd_enable; + ops->disable = sde_encoder_phys_cmd_disable; + ops->destroy = sde_encoder_phys_cmd_destroy; + ops->get_hw_resources = sde_encoder_phys_cmd_get_hw_resources; + ops->control_vblank_irq = sde_encoder_phys_cmd_control_vblank_irq; + ops->wait_for_commit_done = sde_encoder_phys_cmd_wait_for_commit_done; + ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff; + ops->wait_for_tx_complete = sde_encoder_phys_cmd_wait_for_tx_complete; + ops->wait_for_vblank = sde_encoder_phys_cmd_wait_for_vblank; + ops->trigger_flush = sde_encoder_helper_trigger_flush; + ops->trigger_start = sde_encoder_phys_cmd_trigger_start; + ops->needs_single_flush = sde_encoder_phys_needs_single_flush; + ops->hw_reset = sde_encoder_helper_hw_reset; + ops->irq_control = sde_encoder_phys_cmd_irq_control; + ops->update_split_role = sde_encoder_phys_cmd_update_split_role; + ops->restore = sde_encoder_phys_cmd_enable_helper; + ops->control_te = sde_encoder_phys_cmd_connect_te; + ops->is_autorefresh_enabled = + sde_encoder_phys_cmd_is_autorefresh_enabled; + ops->get_line_count = sde_encoder_phys_cmd_te_get_line_count; + ops->get_wr_line_count = sde_encoder_phys_cmd_get_write_line_count; + ops->wait_for_active = NULL; + ops->setup_vsync_source = sde_encoder_phys_cmd_setup_vsync_source; + ops->setup_misr = sde_encoder_helper_setup_misr; + ops->collect_misr = sde_encoder_helper_collect_misr; +} + +struct sde_encoder_phys *sde_encoder_phys_cmd_init( + struct sde_enc_phys_init_params *p) +{ + struct sde_encoder_phys *phys_enc = NULL; + struct sde_encoder_phys_cmd *cmd_enc = NULL; + struct sde_hw_mdp *hw_mdp; + struct sde_encoder_irq *irq; + int i, ret = 0; + + SDE_DEBUG("intf %d\n", p->intf_idx - INTF_0); + + cmd_enc = kzalloc(sizeof(*cmd_enc), GFP_KERNEL); + if (!cmd_enc) { + ret = -ENOMEM; + SDE_ERROR("failed to allocate\n"); + goto fail; + } + phys_enc = &cmd_enc->base; + + hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm); + if (IS_ERR_OR_NULL(hw_mdp)) { + ret = PTR_ERR(hw_mdp); + SDE_ERROR("failed to get mdptop\n"); + goto fail_mdp_init; + } + phys_enc->hw_mdptop = hw_mdp; + phys_enc->intf_idx = p->intf_idx; + + phys_enc->parent = p->parent; + phys_enc->parent_ops = p->parent_ops; + phys_enc->sde_kms = p->sde_kms; + phys_enc->split_role = p->split_role; + phys_enc->intf_mode = INTF_MODE_CMD; + phys_enc->enc_spinlock = p->enc_spinlock; + phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; + cmd_enc->stream_sel = 0; + phys_enc->enable_state = SDE_ENC_DISABLED; + sde_encoder_phys_cmd_init_ops(&phys_enc->ops); + phys_enc->comp_type = p->comp_type; + + if (sde_hw_intf_te_supported(phys_enc->sde_kms->catalog)) + phys_enc->has_intf_te = true; + else + phys_enc->has_intf_te = false; + + for (i = 0; i < INTR_IDX_MAX; i++) { + irq = &phys_enc->irq[i]; + INIT_LIST_HEAD(&irq->cb.list); + irq->irq_idx = -EINVAL; + irq->hw_idx = -EINVAL; + irq->cb.arg = phys_enc; + } + + irq = &phys_enc->irq[INTR_IDX_CTL_START]; + irq->name = "ctl_start"; + irq->intr_type = SDE_IRQ_TYPE_CTL_START; + irq->intr_idx = INTR_IDX_CTL_START; + irq->cb.func = NULL; + + irq = &phys_enc->irq[INTR_IDX_PINGPONG]; + irq->name = "pp_done"; + irq->intr_type = SDE_IRQ_TYPE_PING_PONG_COMP; + irq->intr_idx = INTR_IDX_PINGPONG; + irq->cb.func = sde_encoder_phys_cmd_pp_tx_done_irq; + + irq = &phys_enc->irq[INTR_IDX_RDPTR]; + irq->intr_idx = INTR_IDX_RDPTR; + irq->name = "te_rd_ptr"; + + if (phys_enc->has_intf_te) + irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_RD_PTR; + else + irq->intr_type = SDE_IRQ_TYPE_PING_PONG_RD_PTR; + + irq->cb.func = sde_encoder_phys_cmd_te_rd_ptr_irq; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + irq->name = "underrun"; + irq->intr_type = SDE_IRQ_TYPE_INTF_UNDER_RUN; + irq->intr_idx = INTR_IDX_UNDERRUN; + irq->cb.func = sde_encoder_phys_cmd_underrun_irq; + + irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; + irq->name = "autorefresh_done"; + + if (phys_enc->has_intf_te) + irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF; + else + irq->intr_type = SDE_IRQ_TYPE_PING_PONG_AUTO_REF; + + irq->intr_idx = INTR_IDX_AUTOREFRESH_DONE; + irq->cb.func = sde_encoder_phys_cmd_autorefresh_done_irq; + + irq = &phys_enc->irq[INTR_IDX_WRPTR]; + irq->intr_idx = INTR_IDX_WRPTR; + irq->name = "wr_ptr"; + + if (phys_enc->has_intf_te) + irq->intr_type = SDE_IRQ_TYPE_INTF_TEAR_WR_PTR; + else + irq->intr_type = SDE_IRQ_TYPE_PING_PONG_WR_PTR; + irq->cb.func = sde_encoder_phys_cmd_wr_ptr_irq; + + atomic_set(&phys_enc->vblank_refcount, 0); + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + atomic_set(&phys_enc->pending_retire_fence_cnt, 0); + atomic_set(&cmd_enc->pending_vblank_cnt, 0); + init_waitqueue_head(&phys_enc->pending_kickoff_wq); + init_waitqueue_head(&cmd_enc->pending_vblank_wq); + atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0); + init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq); + INIT_LIST_HEAD(&cmd_enc->te_timestamp_list); + for (i = 0; i < MAX_TE_PROFILE_COUNT; i++) + list_add(&cmd_enc->te_timestamp[i].list, + &cmd_enc->te_timestamp_list); + + SDE_DEBUG_CMDENC(cmd_enc, "created\n"); + + return phys_enc; + +fail_mdp_init: + kfree(cmd_enc); +fail: + return ERR_PTR(ret); +} diff --git a/techpack/display/msm/sde/sde_encoder_phys_vid.c b/techpack/display/msm/sde/sde_encoder_phys_vid.c new file mode 100644 index 0000000000000000000000000000000000000000..54faa7cb5cb642f7b77432b0b7be463c14c8ab83 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder_phys_vid.c @@ -0,0 +1,1354 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include "sde_encoder_phys.h" +#include "sde_hw_interrupts.h" +#include "sde_core_irq.h" +#include "sde_formats.h" +#include "dsi_display.h" +#include "sde_trace.h" + +#define SDE_DEBUG_VIDENC(e, fmt, ...) SDE_DEBUG("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) && (e)->base.hw_intf ? \ + (e)->base.hw_intf->idx - INTF_0 : -1, ##__VA_ARGS__) + +#define SDE_ERROR_VIDENC(e, fmt, ...) SDE_ERROR("enc%d intf%d " fmt, \ + (e) && (e)->base.parent ? \ + (e)->base.parent->base.id : -1, \ + (e) && (e)->base.hw_intf ? \ + (e)->base.hw_intf->idx - INTF_0 : -1, ##__VA_ARGS__) + +#define to_sde_encoder_phys_vid(x) \ + container_of(x, struct sde_encoder_phys_vid, base) + +/* maximum number of consecutive kickoff errors */ +#define KICKOFF_MAX_ERRORS 2 + +/* Poll time to do recovery during active region */ +#define POLL_TIME_USEC_FOR_LN_CNT 500 +#define MAX_POLL_CNT 10 + +static bool sde_encoder_phys_vid_is_master( + struct sde_encoder_phys *phys_enc) +{ + bool ret = false; + + if (phys_enc->split_role != ENC_ROLE_SLAVE) + ret = true; + + return ret; +} + +static void drm_mode_to_intf_timing_params( + const struct sde_encoder_phys_vid *vid_enc, + const struct drm_display_mode *mode, + struct intf_timing_params *timing) +{ + const struct sde_encoder_phys *phys_enc = &vid_enc->base; + enum msm_display_compression_ratio comp_ratio = + MSM_DISPLAY_COMPRESSION_RATIO_NONE; + + memset(timing, 0, sizeof(*timing)); + + if ((mode->htotal < mode->hsync_end) + || (mode->hsync_start < mode->hdisplay) + || (mode->vtotal < mode->vsync_end) + || (mode->vsync_start < mode->vdisplay) + || (mode->hsync_end < mode->hsync_start) + || (mode->vsync_end < mode->vsync_start)) { + SDE_ERROR( + "invalid params - hstart:%d,hend:%d,htot:%d,hdisplay:%d\n", + mode->hsync_start, mode->hsync_end, + mode->htotal, mode->hdisplay); + SDE_ERROR("vstart:%d,vend:%d,vtot:%d,vdisplay:%d\n", + mode->vsync_start, mode->vsync_end, + mode->vtotal, mode->vdisplay); + return; + } + + /* + * https://www.kernel.org/doc/htmldocs/drm/ch02s05.html + * Active Region Front Porch Sync Back Porch + * <-----------------><------------><-----><-----------> + * <- [hv]display ---> + * <--------- [hv]sync_start ------> + * <----------------- [hv]sync_end -------> + * <---------------------------- [hv]total -------------> + */ + timing->width = mode->hdisplay; /* active width */ + + if (phys_enc->hw_intf->cap->type != INTF_DP && + vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_DSC) { + comp_ratio = vid_enc->base.comp_ratio; + if (comp_ratio == MSM_DISPLAY_COMPRESSION_RATIO_2_TO_1) + timing->width = DIV_ROUND_UP(timing->width, 2); + else + timing->width = DIV_ROUND_UP(timing->width, 3); + } + + timing->height = mode->vdisplay; /* active height */ + timing->xres = timing->width; + timing->yres = timing->height; + timing->h_back_porch = mode->htotal - mode->hsync_end; + timing->h_front_porch = mode->hsync_start - mode->hdisplay; + timing->v_back_porch = mode->vtotal - mode->vsync_end; + timing->v_front_porch = mode->vsync_start - mode->vdisplay; + timing->hsync_pulse_width = mode->hsync_end - mode->hsync_start; + timing->vsync_pulse_width = mode->vsync_end - mode->vsync_start; + timing->hsync_polarity = (mode->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0; + timing->vsync_polarity = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0; + timing->border_clr = 0; + timing->underflow_clr = 0xff; + timing->hsync_skew = mode->hskew; + timing->v_front_porch_fixed = vid_enc->base.vfp_cached; + timing->compression_en = false; + + /* DSI controller cannot handle active-low sync signals. */ + if (phys_enc->hw_intf->cap->type == INTF_DSI) { + timing->hsync_polarity = 0; + timing->vsync_polarity = 0; + } + + /* for DP/EDP, Shift timings to align it to bottom right */ + if ((phys_enc->hw_intf->cap->type == INTF_DP) || + (phys_enc->hw_intf->cap->type == INTF_EDP)) { + timing->h_back_porch += timing->h_front_porch; + timing->h_front_porch = 0; + timing->v_back_porch += timing->v_front_porch; + timing->v_front_porch = 0; + } + + timing->wide_bus_en = vid_enc->base.wide_bus_en; + + /* + * for DP, divide the horizonal parameters by 2 when + * widebus or compression is enabled, irrespective of + * compression ratio + */ + if (phys_enc->hw_intf->cap->type == INTF_DP && + (timing->wide_bus_en || vid_enc->base.comp_ratio)) { + timing->width = timing->width >> 1; + timing->xres = timing->xres >> 1; + timing->h_back_porch = timing->h_back_porch >> 1; + timing->h_front_porch = timing->h_front_porch >> 1; + timing->hsync_pulse_width = timing->hsync_pulse_width >> 1; + + if (vid_enc->base.comp_type == MSM_DISPLAY_COMPRESSION_DSC && + vid_enc->base.comp_ratio) { + timing->compression_en = true; + timing->extra_dto_cycles = + vid_enc->base.dsc_extra_pclk_cycle_cnt; + timing->width += vid_enc->base.dsc_extra_disp_width; + timing->h_back_porch += + vid_enc->base.dsc_extra_disp_width; + } + } + + /* + * For edp only: + * DISPLAY_V_START = (VBP * HCYCLE) + HBP + * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP + */ + /* + * if (vid_enc->hw->cap->type == INTF_EDP) { + * display_v_start += mode->htotal - mode->hsync_start; + * display_v_end -= mode->hsync_start - mode->hdisplay; + * } + */ +} + +static inline u32 get_horizontal_total(const struct intf_timing_params *timing) +{ + u32 active = timing->xres; + u32 inactive = + timing->h_back_porch + timing->h_front_porch + + timing->hsync_pulse_width; + return active + inactive; +} + +static inline u32 get_vertical_total(const struct intf_timing_params *timing, + bool use_fixed_vfp) +{ + u32 inactive; + u32 active = timing->yres; + u32 v_front_porch = use_fixed_vfp ? + timing->v_front_porch_fixed : timing->v_front_porch; + + inactive = timing->v_back_porch + v_front_porch + + timing->vsync_pulse_width; + return active + inactive; +} + +/* + * programmable_fetch_get_num_lines: + * Number of fetch lines in vertical front porch + * @timing: Pointer to the intf timing information for the requested mode + * + * Returns the number of fetch lines in vertical front porch at which mdp + * can start fetching the next frame. + * + * Number of needed prefetch lines is anything that cannot be absorbed in the + * start of frame time (back porch + vsync pulse width). + * + * Some panels have very large VFP, however we only need a total number of + * lines based on the chip worst case latencies. + */ +static u32 programmable_fetch_get_num_lines( + struct sde_encoder_phys_vid *vid_enc, + const struct intf_timing_params *timing, + bool use_fixed_vfp) +{ + struct sde_encoder_phys *phys_enc = &vid_enc->base; + u32 worst_case_needed_lines = + phys_enc->hw_intf->cap->prog_fetch_lines_worst_case; + u32 start_of_frame_lines = + timing->v_back_porch + timing->vsync_pulse_width; + u32 needed_vfp_lines = worst_case_needed_lines - start_of_frame_lines; + u32 actual_vfp_lines = 0; + u32 v_front_porch = use_fixed_vfp ? + timing->v_front_porch_fixed : timing->v_front_porch; + + /* Fetch must be outside active lines, otherwise undefined. */ + if (start_of_frame_lines >= worst_case_needed_lines) { + SDE_DEBUG_VIDENC(vid_enc, + "prog fetch is not needed, large vbp+vsw\n"); + actual_vfp_lines = 0; + } else if (v_front_porch < needed_vfp_lines) { + /* Warn fetch needed, but not enough porch in panel config */ + pr_warn_once + ("low vbp+vfp may lead to perf issues in some cases\n"); + SDE_DEBUG_VIDENC(vid_enc, + "less vfp than fetch req, using entire vfp\n"); + actual_vfp_lines = v_front_porch; + } else { + SDE_DEBUG_VIDENC(vid_enc, "room in vfp for needed prefetch\n"); + actual_vfp_lines = needed_vfp_lines; + } + + SDE_DEBUG_VIDENC(vid_enc, + "v_front_porch %u v_back_porch %u vsync_pulse_width %u\n", + v_front_porch, timing->v_back_porch, + timing->vsync_pulse_width); + SDE_DEBUG_VIDENC(vid_enc, + "wc_lines %u needed_vfp_lines %u actual_vfp_lines %u\n", + worst_case_needed_lines, needed_vfp_lines, actual_vfp_lines); + + return actual_vfp_lines; +} + +/* + * programmable_fetch_config: Programs HW to prefetch lines by offsetting + * the start of fetch into the vertical front porch for cases where the + * vsync pulse width and vertical back porch time is insufficient + * + * Gets # of lines to pre-fetch, then calculate VSYNC counter value. + * HW layer requires VSYNC counter of first pixel of tgt VFP line. + * + * @timing: Pointer to the intf timing information for the requested mode + */ +static void programmable_fetch_config(struct sde_encoder_phys *phys_enc, + const struct intf_timing_params *timing) +{ + struct sde_encoder_phys_vid *vid_enc = + to_sde_encoder_phys_vid(phys_enc); + struct intf_prog_fetch f = { 0 }; + u32 vfp_fetch_lines = 0; + u32 horiz_total = 0; + u32 vert_total = 0; + u32 vfp_fetch_start_vsync_counter = 0; + unsigned long lock_flags; + struct sde_mdss_cfg *m; + + if (WARN_ON_ONCE(!phys_enc->hw_intf->ops.setup_prg_fetch)) + return; + + m = phys_enc->sde_kms->catalog; + + vfp_fetch_lines = programmable_fetch_get_num_lines(vid_enc, + timing, false); + if (vfp_fetch_lines) { + vert_total = get_vertical_total(timing, false); + horiz_total = get_horizontal_total(timing); + vfp_fetch_start_vsync_counter = + (vert_total - vfp_fetch_lines) * horiz_total + 1; + + /** + * Check if we need to throttle the fetch to start + * from second line after the active region. + */ + if (m->delay_prg_fetch_start) + vfp_fetch_start_vsync_counter += horiz_total; + + f.enable = 1; + f.fetch_start = vfp_fetch_start_vsync_counter; + } + + SDE_DEBUG_VIDENC(vid_enc, + "vfp_fetch_lines %u vfp_fetch_start_vsync_counter %u\n", + vfp_fetch_lines, vfp_fetch_start_vsync_counter); + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->hw_intf->ops.setup_prg_fetch(phys_enc->hw_intf, &f); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); +} + +static bool sde_encoder_phys_vid_mode_fixup( + struct sde_encoder_phys *phys_enc, + const struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + if (phys_enc) + SDE_DEBUG_VIDENC(to_sde_encoder_phys_vid(phys_enc), "\n"); + + /* + * Modifying mode has consequences when the mode comes back to us + */ + return true; +} + +/* vid_enc timing_params must be configured before calling this function */ +static void _sde_encoder_phys_vid_setup_avr( + struct sde_encoder_phys *phys_enc, u32 qsync_min_fps) +{ + struct sde_encoder_phys_vid *vid_enc; + struct drm_display_mode mode; + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + mode = phys_enc->cached_mode; + if (vid_enc->base.hw_intf->ops.avr_setup) { + struct intf_avr_params avr_params = {0}; + u32 default_fps = mode.vrefresh; + int ret; + + if (!default_fps) { + SDE_ERROR_VIDENC(vid_enc, + "invalid default fps %d\n", + default_fps); + return; + } + + if (qsync_min_fps > default_fps) { + SDE_ERROR_VIDENC(vid_enc, + "qsync fps %d must be less than default %d\n", + qsync_min_fps, default_fps); + return; + } + + avr_params.default_fps = default_fps; + avr_params.min_fps = qsync_min_fps; + + ret = vid_enc->base.hw_intf->ops.avr_setup( + vid_enc->base.hw_intf, + &vid_enc->timing_params, &avr_params); + if (ret) + SDE_ERROR_VIDENC(vid_enc, + "bad settings, can't configure AVR\n"); + + SDE_EVT32(DRMID(phys_enc->parent), default_fps, + qsync_min_fps, ret); + } +} + +static void _sde_encoder_phys_vid_avr_ctrl(struct sde_encoder_phys *phys_enc) +{ + struct intf_avr_params avr_params; + struct sde_encoder_phys_vid *vid_enc = + to_sde_encoder_phys_vid(phys_enc); + + avr_params.avr_mode = sde_connector_get_qsync_mode( + phys_enc->connector); + + if (vid_enc->base.hw_intf->ops.avr_ctrl) { + vid_enc->base.hw_intf->ops.avr_ctrl( + vid_enc->base.hw_intf, + &avr_params); + } + + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_intf->idx - INTF_0, + avr_params.avr_mode); +} + +static void sde_encoder_phys_vid_setup_timing_engine( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_vid *vid_enc; + struct drm_display_mode mode; + struct intf_timing_params timing_params = { 0 }; + const struct sde_format *fmt = NULL; + u32 fmt_fourcc = DRM_FORMAT_RGB888; + u32 qsync_min_fps = 0; + unsigned long lock_flags; + struct sde_hw_intf_cfg intf_cfg = { 0 }; + bool is_split_link = false; + + if (!phys_enc || !phys_enc->sde_kms || !phys_enc->hw_ctl || + !phys_enc->hw_intf) { + SDE_ERROR("invalid encoder %d\n", !phys_enc); + return; + } + + mode = phys_enc->cached_mode; + vid_enc = to_sde_encoder_phys_vid(phys_enc); + if (!phys_enc->hw_intf->ops.setup_timing_gen) { + SDE_ERROR("timing engine setup is not supported\n"); + return; + } + + SDE_DEBUG_VIDENC(vid_enc, "enabling mode:\n"); + drm_mode_debug_printmodeline(&mode); + + is_split_link = phys_enc->hw_intf->cfg.split_link_en; + if (phys_enc->split_role != ENC_ROLE_SOLO || is_split_link) { + mode.hdisplay >>= 1; + mode.htotal >>= 1; + mode.hsync_start >>= 1; + mode.hsync_end >>= 1; + + SDE_DEBUG_VIDENC(vid_enc, + "split_role %d, halve horizontal %d %d %d %d\n", + phys_enc->split_role, + mode.hdisplay, mode.htotal, + mode.hsync_start, mode.hsync_end); + } + + if (!phys_enc->vfp_cached) { + phys_enc->vfp_cached = + sde_connector_get_panel_vfp(phys_enc->connector, &mode); + if (phys_enc->vfp_cached <= 0) + phys_enc->vfp_cached = mode.vsync_start - mode.vdisplay; + } + + drm_mode_to_intf_timing_params(vid_enc, &mode, &timing_params); + + vid_enc->timing_params = timing_params; + + if (phys_enc->cont_splash_enabled) { + SDE_DEBUG_VIDENC(vid_enc, + "skipping intf programming since cont splash is enabled\n"); + goto exit; + } + + fmt = sde_get_sde_format(fmt_fourcc); + SDE_DEBUG_VIDENC(vid_enc, "fmt_fourcc 0x%X\n", fmt_fourcc); + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, + &timing_params, fmt); + + if (test_bit(SDE_CTL_ACTIVE_CFG, + &phys_enc->hw_ctl->caps->features)) { + sde_encoder_helper_update_intf_cfg(phys_enc); + } else if (phys_enc->hw_ctl->ops.setup_intf_cfg) { + intf_cfg.intf = phys_enc->hw_intf->idx; + intf_cfg.intf_mode_sel = SDE_CTL_MODE_SEL_VID; + intf_cfg.stream_sel = 0; /* Don't care value for video mode */ + intf_cfg.mode_3d = + sde_encoder_helper_get_3d_blend_mode(phys_enc); + + phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, + &intf_cfg); + } + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + if (phys_enc->hw_intf->cap->type == INTF_DSI) + programmable_fetch_config(phys_enc, &timing_params); + +exit: + if (phys_enc->parent_ops.get_qsync_fps) + phys_enc->parent_ops.get_qsync_fps( + phys_enc->parent, &qsync_min_fps); + + /* only panels which support qsync will have a non-zero min fps */ + if (qsync_min_fps) { + _sde_encoder_phys_vid_setup_avr(phys_enc, qsync_min_fps); + _sde_encoder_phys_vid_avr_ctrl(phys_enc); + } +} + +static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + struct sde_hw_ctl *hw_ctl; + struct intf_status intf_status = {0}; + unsigned long lock_flags; + u32 flush_register = ~0; + u32 reset_status = 0; + int new_cnt = -1, old_cnt = -1; + u32 event = 0; + int pend_ret_fence_cnt = 0; + + if (!phys_enc) + return; + + hw_ctl = phys_enc->hw_ctl; + if (!hw_ctl) + return; + + SDE_ATRACE_BEGIN("vblank_irq"); + + /* + * only decrement the pending flush count if we've actually flushed + * hardware. due to sw irq latency, vblank may have already happened + * so we need to double-check with hw that it accepted the flush bits + */ + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + + old_cnt = atomic_read(&phys_enc->pending_kickoff_cnt); + + if (hw_ctl && hw_ctl->ops.get_flush_register) + flush_register = hw_ctl->ops.get_flush_register(hw_ctl); + + if (flush_register) + goto not_flushed; + + new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); + pend_ret_fence_cnt = atomic_read(&phys_enc->pending_retire_fence_cnt); + + /* signal only for master, where there is a pending kickoff */ + if (sde_encoder_phys_vid_is_master(phys_enc) && + atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) { + event = SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + } + +not_flushed: + if (hw_ctl && hw_ctl->ops.get_reset) + reset_status = hw_ctl->ops.get_reset(hw_ctl); + + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + if (event && phys_enc->parent_ops.handle_frame_done) + phys_enc->parent_ops.handle_frame_done(phys_enc->parent, + phys_enc, event); + + if (phys_enc->parent_ops.handle_vblank_virt) + phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, + phys_enc); + + if (phys_enc->hw_intf->ops.get_status) + phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, + &intf_status); + + SDE_EVT32_IRQ(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, + old_cnt, atomic_read(&phys_enc->pending_kickoff_cnt), + reset_status ? SDE_EVTLOG_ERROR : 0, + flush_register, event, + atomic_read(&phys_enc->pending_retire_fence_cnt), + intf_status.frame_count); + + /* Signal any waiting atomic commit thread */ + wake_up_all(&phys_enc->pending_kickoff_wq); + SDE_ATRACE_END("vblank_irq"); +} + +static void sde_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + + if (!phys_enc) + return; + + if (phys_enc->parent_ops.handle_underrun_virt) + phys_enc->parent_ops.handle_underrun_virt(phys_enc->parent, + phys_enc); +} + +static void _sde_encoder_phys_vid_setup_irq_hw_idx( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_irq *irq; + + /* + * Initialize irq->hw_idx only when irq is not registered. + * Prevent invalidating irq->irq_idx as modeset may be + * called many times during dfps. + */ + + irq = &phys_enc->irq[INTR_IDX_VSYNC]; + if (irq->irq_idx < 0) + irq->hw_idx = phys_enc->intf_idx; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + if (irq->irq_idx < 0) + irq->hw_idx = phys_enc->intf_idx; +} + +static void sde_encoder_phys_vid_cont_splash_mode_set( + struct sde_encoder_phys *phys_enc, + struct drm_display_mode *adj_mode) +{ + if (!phys_enc || !adj_mode) { + SDE_ERROR("invalid args\n"); + return; + } + + phys_enc->cached_mode = *adj_mode; + phys_enc->enable_state = SDE_ENC_ENABLED; + + _sde_encoder_phys_vid_setup_irq_hw_idx(phys_enc); +} + +static void sde_encoder_phys_vid_mode_set( + struct sde_encoder_phys *phys_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct sde_rm *rm; + struct sde_rm_hw_iter iter; + int i, instance; + struct sde_encoder_phys_vid *vid_enc; + + if (!phys_enc || !phys_enc->sde_kms) { + SDE_ERROR("invalid encoder/kms\n"); + return; + } + + rm = &phys_enc->sde_kms->rm; + vid_enc = to_sde_encoder_phys_vid(phys_enc); + + if (adj_mode) { + phys_enc->cached_mode = *adj_mode; + drm_mode_debug_printmodeline(adj_mode); + SDE_DEBUG_VIDENC(vid_enc, "caching mode:\n"); + } + + instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0; + + /* Retrieve previously allocated HW Resources. Shouldn't fail */ + sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL); + for (i = 0; i <= instance; i++) { + if (sde_rm_get_hw(rm, &iter)) + phys_enc->hw_ctl = (struct sde_hw_ctl *)iter.hw; + } + if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) { + SDE_ERROR_VIDENC(vid_enc, "failed to init ctl, %ld\n", + PTR_ERR(phys_enc->hw_ctl)); + phys_enc->hw_ctl = NULL; + return; + } + + sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_INTF); + for (i = 0; i <= instance; i++) { + if (sde_rm_get_hw(rm, &iter)) + phys_enc->hw_intf = (struct sde_hw_intf *)iter.hw; + } + + if (IS_ERR_OR_NULL(phys_enc->hw_intf)) { + SDE_ERROR_VIDENC(vid_enc, "failed to init intf: %ld\n", + PTR_ERR(phys_enc->hw_intf)); + phys_enc->hw_intf = NULL; + return; + } + + _sde_encoder_phys_vid_setup_irq_hw_idx(phys_enc); +} + +static int sde_encoder_phys_vid_control_vblank_irq( + struct sde_encoder_phys *phys_enc, + bool enable) +{ + int ret = 0; + struct sde_encoder_phys_vid *vid_enc; + int refcount; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return -EINVAL; + } + + mutex_lock(phys_enc->vblank_ctl_lock); + refcount = atomic_read(&phys_enc->vblank_refcount); + vid_enc = to_sde_encoder_phys_vid(phys_enc); + + /* Slave encoders don't report vblank */ + if (!sde_encoder_phys_vid_is_master(phys_enc)) + goto end; + + /* protect against negative */ + if (!enable && refcount == 0) { + ret = -EINVAL; + goto end; + } + + SDE_DEBUG_VIDENC(vid_enc, "[%pS] enable=%d/%d\n", + __builtin_return_address(0), + enable, atomic_read(&phys_enc->vblank_refcount)); + + SDE_EVT32(DRMID(phys_enc->parent), enable, + atomic_read(&phys_enc->vblank_refcount)); + + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) { + ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_VSYNC); + if (ret) + atomic_dec_return(&phys_enc->vblank_refcount); + } else if (!enable && + atomic_dec_return(&phys_enc->vblank_refcount) == 0) { + ret = sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_VSYNC); + if (ret) + atomic_inc_return(&phys_enc->vblank_refcount); + } + +end: + if (ret) { + SDE_ERROR_VIDENC(vid_enc, + "control vblank irq error %d, enable %d\n", + ret, enable); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_intf->idx - INTF_0, + enable, refcount, SDE_EVTLOG_ERROR); + } + mutex_unlock(phys_enc->vblank_ctl_lock); + return ret; +} + +static bool sde_encoder_phys_vid_wait_dma_trigger( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_vid *vid_enc; + struct sde_hw_intf *intf; + struct sde_hw_ctl *ctl; + struct intf_status status; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return false; + } + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + intf = phys_enc->hw_intf; + ctl = phys_enc->hw_ctl; + if (!phys_enc->hw_intf || !phys_enc->hw_ctl) { + SDE_ERROR("invalid hw_intf %d hw_ctl %d\n", + phys_enc->hw_intf != NULL, phys_enc->hw_ctl != NULL); + return false; + } + + if (!intf->ops.get_status) + return false; + + intf->ops.get_status(intf, &status); + + /* if interface is not enabled, return true to wait for dma trigger */ + return status.is_en ? false : true; +} + +static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc) +{ + struct msm_drm_private *priv; + struct sde_encoder_phys_vid *vid_enc; + struct sde_hw_intf *intf; + struct sde_hw_ctl *ctl; + + if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev || + !phys_enc->parent->dev->dev_private || + !phys_enc->sde_kms) { + SDE_ERROR("invalid encoder/device\n"); + return; + } + priv = phys_enc->parent->dev->dev_private; + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + intf = phys_enc->hw_intf; + ctl = phys_enc->hw_ctl; + if (!phys_enc->hw_intf || !phys_enc->hw_ctl || !phys_enc->hw_pp) { + SDE_ERROR("invalid hw_intf %d hw_ctl %d hw_pp %d\n", + !phys_enc->hw_intf, !phys_enc->hw_ctl, + !phys_enc->hw_pp); + return; + } + if (!ctl->ops.update_bitmask_intf || + (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) && + !ctl->ops.update_bitmask_merge3d)) { + SDE_ERROR("invalid hw_ctl ops %d\n", ctl->idx); + return; + } + + SDE_DEBUG_VIDENC(vid_enc, "\n"); + + if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing)) + return; + + if (!phys_enc->cont_splash_enabled) + sde_encoder_helper_split_config(phys_enc, + phys_enc->hw_intf->idx); + + sde_encoder_phys_vid_setup_timing_engine(phys_enc); + + /* + * For cases where both the interfaces are connected to same ctl, + * set the flush bit for both master and slave. + * For single flush cases (dual-ctl or pp-split), skip setting the + * flush bit for the slave intf, since both intfs use same ctl + * and HW will only flush the master. + */ + if (!test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) && + sde_encoder_phys_needs_single_flush(phys_enc) && + !sde_encoder_phys_vid_is_master(phys_enc)) + goto skip_flush; + + /** + * skip flushing intf during cont. splash handoff since bootloader + * has already enabled the hardware and is single buffered. + */ + if (phys_enc->cont_splash_enabled) { + SDE_DEBUG_VIDENC(vid_enc, + "skipping intf flush bit set as cont. splash is enabled\n"); + goto skip_flush; + } + + ctl->ops.update_bitmask_intf(ctl, intf->idx, 1); + + if (ctl->ops.update_bitmask_merge3d && phys_enc->hw_pp->merge_3d) + ctl->ops.update_bitmask_merge3d(ctl, + phys_enc->hw_pp->merge_3d->idx, 1); + + if (phys_enc->hw_intf->cap->type == INTF_DP && + phys_enc->comp_type == MSM_DISPLAY_COMPRESSION_DSC && + phys_enc->comp_ratio && ctl->ops.update_bitmask_periph) + ctl->ops.update_bitmask_periph(ctl, intf->idx, 1); + +skip_flush: + SDE_DEBUG_VIDENC(vid_enc, "update pending flush ctl %d intf %d\n", + ctl->idx - CTL_0, intf->idx); + SDE_EVT32(DRMID(phys_enc->parent), + atomic_read(&phys_enc->pending_retire_fence_cnt)); + + /* ctl_flush & timing engine enable will be triggered by framework */ + if (phys_enc->enable_state == SDE_ENC_DISABLED) + phys_enc->enable_state = SDE_ENC_ENABLING; +} + +static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_vid *vid_enc; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + SDE_DEBUG_VIDENC(vid_enc, "\n"); + kfree(vid_enc); +} + +static void sde_encoder_phys_vid_get_hw_resources( + struct sde_encoder_phys *phys_enc, + struct sde_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct sde_encoder_phys_vid *vid_enc; + + if (!phys_enc || !hw_res) { + SDE_ERROR("invalid arg(s), enc %d hw_res %d conn_state %d\n", + !phys_enc, !hw_res, !conn_state); + return; + } + + if ((phys_enc->intf_idx - INTF_0) >= INTF_MAX) { + SDE_ERROR("invalid intf idx:%d\n", phys_enc->intf_idx); + return; + } + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + SDE_DEBUG_VIDENC(vid_enc, "\n"); + hw_res->intfs[phys_enc->intf_idx - INTF_0] = INTF_MODE_VIDEO; +} + +static int _sde_encoder_phys_vid_wait_for_vblank( + struct sde_encoder_phys *phys_enc, bool notify) +{ + struct sde_encoder_wait_info wait_info = {0}; + int ret = 0; + u32 event = SDE_ENCODER_FRAME_EVENT_ERROR | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; + + if (!phys_enc) { + pr_err("invalid encoder\n"); + return -EINVAL; + } + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt; + wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; + + /* Wait for kickoff to complete */ + ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, + &wait_info); + + if (notify && (ret == -ETIMEDOUT) && + atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0) && + phys_enc->parent_ops.handle_frame_done) + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, event); + + SDE_EVT32(DRMID(phys_enc->parent), event, notify, ret, + ret ? SDE_EVTLOG_FATAL : 0); + return ret; +} + +static int sde_encoder_phys_vid_wait_for_vblank( + struct sde_encoder_phys *phys_enc) +{ + return _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true); +} + +static int sde_encoder_phys_vid_wait_for_vblank_no_notify( + struct sde_encoder_phys *phys_enc) +{ + return _sde_encoder_phys_vid_wait_for_vblank(phys_enc, false); +} + +static int sde_encoder_phys_vid_prepare_for_kickoff( + struct sde_encoder_phys *phys_enc, + struct sde_encoder_kickoff_params *params) +{ + struct sde_encoder_phys_vid *vid_enc; + struct sde_hw_ctl *ctl; + bool recovery_events; + struct drm_connector *conn; + int event; + int rc; + + if (!phys_enc || !params || !phys_enc->hw_ctl) { + SDE_ERROR("invalid encoder/parameters\n"); + return -EINVAL; + } + vid_enc = to_sde_encoder_phys_vid(phys_enc); + + ctl = phys_enc->hw_ctl; + if (!ctl->ops.wait_reset_status) + return 0; + + conn = phys_enc->connector; + recovery_events = sde_encoder_recovery_events_enabled( + phys_enc->parent); + /* + * hw supports hardware initiated ctl reset, so before we kickoff a new + * frame, need to check and wait for hw initiated ctl reset completion + */ + rc = ctl->ops.wait_reset_status(ctl); + if (rc) { + SDE_ERROR_VIDENC(vid_enc, "ctl %d reset failure: %d\n", + ctl->idx, rc); + + ++vid_enc->error_count; + + /* to avoid flooding, only log first time, and "dead" time */ + if (vid_enc->error_count == 1) { + SDE_EVT32(DRMID(phys_enc->parent), SDE_EVTLOG_FATAL); + + sde_encoder_helper_unregister_irq( + phys_enc, INTR_IDX_VSYNC); + SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus"); + sde_encoder_helper_register_irq( + phys_enc, INTR_IDX_VSYNC); + } + + /* + * if the recovery event is registered by user, don't panic + * trigger panic on first timeout if no listener registered + */ + if (recovery_events) { + event = vid_enc->error_count > KICKOFF_MAX_ERRORS ? + SDE_RECOVERY_HARD_RESET : SDE_RECOVERY_CAPTURE; + sde_connector_event_notify(conn, + DRM_EVENT_SDE_HW_RECOVERY, + sizeof(uint8_t), event); + } else { + SDE_DBG_DUMP("panic"); + } + + /* request a ctl reset before the next flush */ + phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET; + } else { + if (recovery_events && vid_enc->error_count) + sde_connector_event_notify(conn, + DRM_EVENT_SDE_HW_RECOVERY, + sizeof(uint8_t), + SDE_RECOVERY_SUCCESS); + vid_enc->error_count = 0; + } + + return rc; +} + +static void sde_encoder_phys_vid_single_vblank_wait( + struct sde_encoder_phys *phys_enc) +{ + int ret; + struct sde_encoder_phys_vid *vid_enc + = to_sde_encoder_phys_vid(phys_enc); + + /* + * Wait for a vsync so we know the ENABLE=0 latched before + * the (connector) source of the vsync's gets disabled, + * otherwise we end up in a funny state if we re-enable + * before the disable latches, which results that some of + * the settings changes for the new modeset (like new + * scanout buffer) don't latch properly.. + */ + ret = sde_encoder_phys_vid_control_vblank_irq(phys_enc, true); + if (ret) { + SDE_ERROR_VIDENC(vid_enc, + "failed to enable vblank irq: %d\n", + ret); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_intf->idx - INTF_0, ret, + SDE_EVTLOG_FUNC_CASE1, + SDE_EVTLOG_ERROR); + } else { + ret = _sde_encoder_phys_vid_wait_for_vblank(phys_enc, false); + if (ret) { + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + SDE_ERROR_VIDENC(vid_enc, + "failure waiting for disable: %d\n", + ret); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_intf->idx - INTF_0, ret, + SDE_EVTLOG_FUNC_CASE2, + SDE_EVTLOG_ERROR); + } + sde_encoder_phys_vid_control_vblank_irq(phys_enc, false); + } +} + +static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc) +{ + struct msm_drm_private *priv; + struct sde_encoder_phys_vid *vid_enc; + unsigned long lock_flags; + struct intf_status intf_status = {0}; + + if (!phys_enc || !phys_enc->parent || !phys_enc->parent->dev || + !phys_enc->parent->dev->dev_private) { + SDE_ERROR("invalid encoder/device\n"); + return; + } + priv = phys_enc->parent->dev->dev_private; + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + if (!phys_enc->hw_intf || !phys_enc->hw_ctl) { + SDE_ERROR("invalid hw_intf %d hw_ctl %d\n", + !phys_enc->hw_intf, !phys_enc->hw_ctl); + return; + } + + SDE_DEBUG_VIDENC(vid_enc, "\n"); + + if (WARN_ON(!phys_enc->hw_intf->ops.enable_timing)) + return; + else if (!sde_encoder_phys_vid_is_master(phys_enc)) + goto exit; + + if (phys_enc->enable_state == SDE_ENC_DISABLED) { + SDE_ERROR("already disabled\n"); + return; + } + + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 0); + sde_encoder_phys_inc_pending(phys_enc); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + sde_encoder_phys_vid_single_vblank_wait(phys_enc); + if (phys_enc->hw_intf->ops.get_status) + phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, + &intf_status); + + if (intf_status.is_en) { + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + sde_encoder_phys_inc_pending(phys_enc); + spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); + + sde_encoder_phys_vid_single_vblank_wait(phys_enc); + } + + sde_encoder_helper_phys_disable(phys_enc, NULL); +exit: + SDE_EVT32(DRMID(phys_enc->parent), + atomic_read(&phys_enc->pending_retire_fence_cnt)); + phys_enc->vfp_cached = 0; + phys_enc->enable_state = SDE_ENC_DISABLED; +} + +static void sde_encoder_phys_vid_handle_post_kickoff( + struct sde_encoder_phys *phys_enc) +{ + unsigned long lock_flags; + struct sde_encoder_phys_vid *vid_enc; + u32 avr_mode; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + SDE_DEBUG_VIDENC(vid_enc, "enable_state %d\n", phys_enc->enable_state); + + /* + * Video mode must flush CTL before enabling timing engine + * Video encoders need to turn on their interfaces now + */ + if (phys_enc->enable_state == SDE_ENC_ENABLING) { + if (sde_encoder_phys_vid_is_master(phys_enc)) { + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_intf->idx - INTF_0); + spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); + phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, + 1); + spin_unlock_irqrestore(phys_enc->enc_spinlock, + lock_flags); + } + phys_enc->enable_state = SDE_ENC_ENABLED; + } + + avr_mode = sde_connector_get_qsync_mode(phys_enc->connector); + + if (avr_mode && vid_enc->base.hw_intf->ops.avr_trigger) { + vid_enc->base.hw_intf->ops.avr_trigger(vid_enc->base.hw_intf); + SDE_EVT32(DRMID(phys_enc->parent), + phys_enc->hw_intf->idx - INTF_0, + SDE_EVTLOG_FUNC_CASE9); + } +} + +static void sde_encoder_phys_vid_prepare_for_commit( + struct sde_encoder_phys *phys_enc) +{ + + if (!phys_enc) { + SDE_ERROR("invalid encoder parameters\n"); + return; + } + + if (sde_connector_is_qsync_updated(phys_enc->connector)) + _sde_encoder_phys_vid_avr_ctrl(phys_enc); + +} + +static void sde_encoder_phys_vid_irq_control(struct sde_encoder_phys *phys_enc, + bool enable) +{ + struct sde_encoder_phys_vid *vid_enc; + int ret; + + if (!phys_enc) + return; + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, + enable, atomic_read(&phys_enc->vblank_refcount)); + + if (enable) { + ret = sde_encoder_phys_vid_control_vblank_irq(phys_enc, true); + if (ret) + return; + + sde_encoder_helper_register_irq(phys_enc, INTR_IDX_UNDERRUN); + } else { + sde_encoder_phys_vid_control_vblank_irq(phys_enc, false); + sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_UNDERRUN); + } +} + +static int sde_encoder_phys_vid_get_line_count( + struct sde_encoder_phys *phys_enc) +{ + if (!phys_enc) + return -EINVAL; + + if (!sde_encoder_phys_vid_is_master(phys_enc)) + return -EINVAL; + + if (!phys_enc->hw_intf || !phys_enc->hw_intf->ops.get_line_count) + return -EINVAL; + + return phys_enc->hw_intf->ops.get_line_count(phys_enc->hw_intf); +} + +static int sde_encoder_phys_vid_wait_for_active( + struct sde_encoder_phys *phys_enc) +{ + struct drm_display_mode mode; + struct sde_encoder_phys_vid *vid_enc; + u32 ln_cnt, min_ln_cnt, active_lns_cnt; + u32 clk_period, time_of_line; + u32 delay, retry = MAX_POLL_CNT; + + vid_enc = to_sde_encoder_phys_vid(phys_enc); + + if (!phys_enc->hw_intf || !phys_enc->hw_intf->ops.get_line_count) { + SDE_ERROR_VIDENC(vid_enc, "invalid vid_enc params\n"); + return -EINVAL; + } + + mode = phys_enc->cached_mode; + + /* + * calculate clk_period as pico second to maintain good + * accuracy with high pclk rate and this number is in 17 bit + * range. + */ + clk_period = DIV_ROUND_UP_ULL(1000000000, mode.clock); + if (!clk_period) { + SDE_ERROR_VIDENC(vid_enc, "Unable to calculate clock period\n"); + return -EINVAL; + } + + min_ln_cnt = (mode.vtotal - mode.vsync_start) + + (mode.vsync_end - mode.vsync_start); + active_lns_cnt = mode.vdisplay; + time_of_line = mode.htotal * clk_period; + + /* delay in micro seconds */ + delay = (time_of_line * (min_ln_cnt + + (mode.vsync_start - mode.vdisplay))) / 1000000; + + /* + * Wait for max delay before + * polling to check active region + */ + if (delay > POLL_TIME_USEC_FOR_LN_CNT) + delay = POLL_TIME_USEC_FOR_LN_CNT; + + while (retry) { + ln_cnt = phys_enc->hw_intf->ops.get_line_count( + phys_enc->hw_intf); + + if ((ln_cnt >= min_ln_cnt) && + (ln_cnt < (active_lns_cnt + min_ln_cnt))) { + SDE_DEBUG_VIDENC(vid_enc, + "Needed lines left line_cnt=%d\n", + ln_cnt); + return 0; + } + + SDE_ERROR_VIDENC(vid_enc, "line count is less. line_cnt = %d\n", + ln_cnt); + /* Add delay so that line count is in active region */ + udelay(delay); + retry--; + } + + return -EINVAL; +} + +static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) +{ + ops->is_master = sde_encoder_phys_vid_is_master; + ops->mode_set = sde_encoder_phys_vid_mode_set; + ops->cont_splash_mode_set = sde_encoder_phys_vid_cont_splash_mode_set; + ops->mode_fixup = sde_encoder_phys_vid_mode_fixup; + ops->enable = sde_encoder_phys_vid_enable; + ops->disable = sde_encoder_phys_vid_disable; + ops->destroy = sde_encoder_phys_vid_destroy; + ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources; + ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq; + ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_vblank; + ops->wait_for_vblank = sde_encoder_phys_vid_wait_for_vblank_no_notify; + ops->wait_for_tx_complete = sde_encoder_phys_vid_wait_for_vblank; + ops->irq_control = sde_encoder_phys_vid_irq_control; + ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff; + ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff; + ops->needs_single_flush = sde_encoder_phys_needs_single_flush; + ops->setup_misr = sde_encoder_helper_setup_misr; + ops->collect_misr = sde_encoder_helper_collect_misr; + ops->trigger_flush = sde_encoder_helper_trigger_flush; + ops->hw_reset = sde_encoder_helper_hw_reset; + ops->get_line_count = sde_encoder_phys_vid_get_line_count; + ops->get_wr_line_count = sde_encoder_phys_vid_get_line_count; + ops->wait_dma_trigger = sde_encoder_phys_vid_wait_dma_trigger; + ops->wait_for_active = sde_encoder_phys_vid_wait_for_active; + ops->prepare_commit = sde_encoder_phys_vid_prepare_for_commit; +} + +struct sde_encoder_phys *sde_encoder_phys_vid_init( + struct sde_enc_phys_init_params *p) +{ + struct sde_encoder_phys *phys_enc = NULL; + struct sde_encoder_phys_vid *vid_enc = NULL; + struct sde_hw_mdp *hw_mdp; + struct sde_encoder_irq *irq; + int i, ret = 0; + + if (!p) { + ret = -EINVAL; + goto fail; + } + + vid_enc = kzalloc(sizeof(*vid_enc), GFP_KERNEL); + if (!vid_enc) { + ret = -ENOMEM; + goto fail; + } + + phys_enc = &vid_enc->base; + + hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm); + if (IS_ERR_OR_NULL(hw_mdp)) { + ret = PTR_ERR(hw_mdp); + SDE_ERROR("failed to get mdptop\n"); + goto fail; + } + phys_enc->hw_mdptop = hw_mdp; + phys_enc->intf_idx = p->intf_idx; + + SDE_DEBUG_VIDENC(vid_enc, "\n"); + + sde_encoder_phys_vid_init_ops(&phys_enc->ops); + phys_enc->parent = p->parent; + phys_enc->parent_ops = p->parent_ops; + phys_enc->sde_kms = p->sde_kms; + phys_enc->split_role = p->split_role; + phys_enc->intf_mode = INTF_MODE_VIDEO; + phys_enc->enc_spinlock = p->enc_spinlock; + phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; + phys_enc->comp_type = p->comp_type; + for (i = 0; i < INTR_IDX_MAX; i++) { + irq = &phys_enc->irq[i]; + INIT_LIST_HEAD(&irq->cb.list); + irq->irq_idx = -EINVAL; + irq->hw_idx = -EINVAL; + irq->cb.arg = phys_enc; + } + + irq = &phys_enc->irq[INTR_IDX_VSYNC]; + irq->name = "vsync_irq"; + irq->intr_type = SDE_IRQ_TYPE_INTF_VSYNC; + irq->intr_idx = INTR_IDX_VSYNC; + irq->cb.func = sde_encoder_phys_vid_vblank_irq; + + irq = &phys_enc->irq[INTR_IDX_UNDERRUN]; + irq->name = "underrun"; + irq->intr_type = SDE_IRQ_TYPE_INTF_UNDER_RUN; + irq->intr_idx = INTR_IDX_UNDERRUN; + irq->cb.func = sde_encoder_phys_vid_underrun_irq; + + atomic_set(&phys_enc->vblank_refcount, 0); + atomic_set(&phys_enc->pending_kickoff_cnt, 0); + atomic_set(&phys_enc->pending_retire_fence_cnt, 0); + init_waitqueue_head(&phys_enc->pending_kickoff_wq); + phys_enc->enable_state = SDE_ENC_DISABLED; + + SDE_DEBUG_VIDENC(vid_enc, "created intf idx:%d\n", p->intf_idx); + + return phys_enc; + +fail: + SDE_ERROR("failed to create encoder\n"); + if (vid_enc) + sde_encoder_phys_vid_destroy(phys_enc); + + return ERR_PTR(ret); +} diff --git a/techpack/display/msm/sde/sde_encoder_phys_wb.c b/techpack/display/msm/sde/sde_encoder_phys_wb.c new file mode 100644 index 0000000000000000000000000000000000000000..1530f0c91e44ddd0ab3b85e38373b26bea7e2498 --- /dev/null +++ b/techpack/display/msm/sde/sde_encoder_phys_wb.c @@ -0,0 +1,1937 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/debugfs.h> +#include <uapi/drm/sde_drm.h> + +#include "sde_encoder_phys.h" +#include "sde_formats.h" +#include "sde_hw_top.h" +#include "sde_hw_interrupts.h" +#include "sde_core_irq.h" +#include "sde_wb.h" +#include "sde_vbif.h" +#include "sde_crtc.h" + +#define to_sde_encoder_phys_wb(x) \ + container_of(x, struct sde_encoder_phys_wb, base) + +#define WBID(wb_enc) \ + ((wb_enc && wb_enc->wb_dev) ? wb_enc->wb_dev->wb_idx - WB_0 : -1) + +#define TO_S15D16(_x_) ((_x_) << 7) + +static const u32 cwb_irq_tbl[PINGPONG_MAX] = {SDE_NONE, INTR_IDX_PP1_OVFL, + INTR_IDX_PP2_OVFL, INTR_IDX_PP3_OVFL, INTR_IDX_PP4_OVFL, + INTR_IDX_PP5_OVFL, SDE_NONE, SDE_NONE}; + +/** + * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix + * + */ +static struct sde_csc_cfg sde_encoder_phys_wb_rgb2yuv_601l = { + { + TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032), + TO_S15D16(0x1fb5), TO_S15D16(0x1f6c), TO_S15D16(0x00e1), + TO_S15D16(0x00e1), TO_S15D16(0x1f45), TO_S15D16(0x1fdc) + }, + { 0x00, 0x00, 0x00 }, + { 0x0040, 0x0200, 0x0200 }, + { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, + { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, +}; + +/** + * sde_encoder_phys_wb_is_master - report wb always as master encoder + */ +static bool sde_encoder_phys_wb_is_master(struct sde_encoder_phys *phys_enc) +{ + return true; +} + +/** + * sde_encoder_phys_wb_get_intr_type - get interrupt type based on block mode + * @hw_wb: Pointer to h/w writeback driver + */ +static enum sde_intr_type sde_encoder_phys_wb_get_intr_type( + struct sde_hw_wb *hw_wb) +{ + return (hw_wb->caps->features & BIT(SDE_WB_BLOCK_MODE)) ? + SDE_IRQ_TYPE_WB_ROT_COMP : SDE_IRQ_TYPE_WB_WFD_COMP; +} + +/** + * sde_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_set_ot_limit( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct sde_vbif_set_ot_params ot_params; + + memset(&ot_params, 0, sizeof(ot_params)); + ot_params.xin_id = hw_wb->caps->xin_id; + ot_params.num = hw_wb->idx - WB_0; + ot_params.width = wb_enc->wb_roi.w; + ot_params.height = wb_enc->wb_roi.h; + ot_params.is_wfd = true; + ot_params.frame_rate = phys_enc->cached_mode.vrefresh; + ot_params.vbif_idx = hw_wb->caps->vbif_idx; + ot_params.clk_ctrl = hw_wb->caps->clk_ctrl; + ot_params.rd = false; + + sde_vbif_set_ot_limit(phys_enc->sde_kms, &ot_params); +} + +/** + * sde_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_set_qos_remap( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct drm_crtc *crtc; + struct sde_vbif_set_qos_params qos_params; + + if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) { + SDE_ERROR("invalid arguments\n"); + return; + } + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + if (!wb_enc->crtc) { + SDE_ERROR("invalid crtc"); + return; + } + + crtc = wb_enc->crtc; + + if (!wb_enc->hw_wb || !wb_enc->hw_wb->caps) { + SDE_ERROR("invalid writeback hardware\n"); + return; + } + + hw_wb = wb_enc->hw_wb; + + memset(&qos_params, 0, sizeof(qos_params)); + qos_params.vbif_idx = hw_wb->caps->vbif_idx; + qos_params.xin_id = hw_wb->caps->xin_id; + qos_params.clk_ctrl = hw_wb->caps->clk_ctrl; + qos_params.num = hw_wb->idx - WB_0; + qos_params.client_type = phys_enc->in_clone_mode ? + VBIF_CWB_CLIENT : VBIF_NRT_CLIENT; + + SDE_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d clone:%d\n", + qos_params.num, + qos_params.vbif_idx, + qos_params.xin_id, qos_params.client_type); + + sde_vbif_set_qos_remap(phys_enc->sde_kms, &qos_params); +} + +/** + * sde_encoder_phys_wb_set_qos - set QoS/danger/safe LUTs for writeback + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_set_qos(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct sde_hw_wb_qos_cfg qos_cfg = {0}; + struct sde_perf_cfg *perf; + u32 fps_index = 0, lut_index, index, frame_rate, qos_count; + + if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog) { + SDE_ERROR("invalid parameter(s)\n"); + return; + } + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + if (!wb_enc->hw_wb) { + SDE_ERROR("invalid writeback hardware\n"); + return; + } + + perf = &phys_enc->sde_kms->catalog->perf; + frame_rate = phys_enc->cached_mode.vrefresh; + + hw_wb = wb_enc->hw_wb; + qos_count = perf->qos_refresh_count; + while (qos_count && perf->qos_refresh_rate) { + if (frame_rate >= perf->qos_refresh_rate[qos_count - 1]) { + fps_index = qos_count - 1; + break; + } + qos_count--; + } + + qos_cfg.danger_safe_en = true; + + if (phys_enc->in_clone_mode) + lut_index = SDE_QOS_LUT_USAGE_CWB; + else + lut_index = SDE_QOS_LUT_USAGE_NRT; + index = (fps_index * SDE_QOS_LUT_USAGE_MAX) + lut_index; + + qos_cfg.danger_lut = perf->danger_lut[index]; + qos_cfg.safe_lut = (u32) perf->safe_lut[index]; + qos_cfg.creq_lut = perf->creq_lut[index]; + + SDE_DEBUG("wb_enc:%d hw idx:%d fps:%d mode:%d luts[0x%x,0x%x 0x%llx]\n", + DRMID(phys_enc->parent), hw_wb->idx - WB_0, + frame_rate, phys_enc->in_clone_mode, + qos_cfg.danger_lut, qos_cfg.safe_lut, qos_cfg.creq_lut); + + if (hw_wb->ops.setup_qos_lut) + hw_wb->ops.setup_qos_lut(hw_wb, &qos_cfg); +} + +/** + * sde_encoder_phys_setup_cdm - setup chroma down block + * @phys_enc: Pointer to physical encoder + * @fb: Pointer to output framebuffer + * @format: Output format + */ +void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb, const struct sde_format *format, + struct sde_rect *wb_roi) +{ + struct sde_hw_cdm *hw_cdm; + struct sde_hw_cdm_cfg *cdm_cfg; + struct sde_hw_pingpong *hw_pp; + int ret; + + if (!phys_enc || !format) + return; + + cdm_cfg = &phys_enc->cdm_cfg; + hw_pp = phys_enc->hw_pp; + hw_cdm = phys_enc->hw_cdm; + if (!hw_cdm) + return; + + if (!SDE_FORMAT_IS_YUV(format)) { + SDE_DEBUG("[cdm_disable fmt:%x]\n", + format->base.pixel_format); + + if (hw_cdm && hw_cdm->ops.disable) + hw_cdm->ops.disable(hw_cdm); + + return; + } + + memset(cdm_cfg, 0, sizeof(struct sde_hw_cdm_cfg)); + + if (!wb_roi) + return; + + cdm_cfg->output_width = wb_roi->w; + cdm_cfg->output_height = wb_roi->h; + cdm_cfg->output_fmt = format; + cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB; + cdm_cfg->output_bit_depth = SDE_FORMAT_IS_DX(format) ? + CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT; + + /* enable 10 bit logic */ + switch (cdm_cfg->output_fmt->chroma_sample) { + case SDE_CHROMA_RGB: + cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + case SDE_CHROMA_H2V1: + cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + case SDE_CHROMA_420: + cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; + cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE; + break; + case SDE_CHROMA_H1V2: + default: + SDE_ERROR("unsupported chroma sampling type\n"); + cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + } + + SDE_DEBUG("[cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n", + cdm_cfg->output_width, + cdm_cfg->output_height, + cdm_cfg->output_fmt->base.pixel_format, + cdm_cfg->output_type, + cdm_cfg->output_bit_depth, + cdm_cfg->h_cdwn_type, + cdm_cfg->v_cdwn_type); + + if (hw_cdm && hw_cdm->ops.setup_csc_data) { + ret = hw_cdm->ops.setup_csc_data(hw_cdm, + &sde_encoder_phys_wb_rgb2yuv_601l); + if (ret < 0) { + SDE_ERROR("failed to setup CSC %d\n", ret); + return; + } + } + + if (hw_cdm && hw_cdm->ops.setup_cdwn) { + ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg); + if (ret < 0) { + SDE_ERROR("failed to setup CDM %d\n", ret); + return; + } + } + + if (hw_cdm && hw_pp && hw_cdm->ops.enable) { + cdm_cfg->pp_id = hw_pp->idx; + ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg); + if (ret < 0) { + SDE_ERROR("failed to enable CDM %d\n", ret); + return; + } + } +} + +/** + * sde_encoder_phys_wb_setup_fb - setup output framebuffer + * @phys_enc: Pointer to physical encoder + * @fb: Pointer to output framebuffer + * @wb_roi: Pointer to output region of interest + */ +static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, + struct drm_framebuffer *fb, struct sde_rect *wb_roi) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb; + struct sde_hw_wb_cfg *wb_cfg; + struct sde_hw_wb_cdp_cfg *cdp_cfg; + const struct msm_format *format; + int ret; + struct msm_gem_address_space *aspace; + u32 fb_mode; + + if (!phys_enc || !phys_enc->sde_kms || !phys_enc->sde_kms->catalog || + !phys_enc->connector) { + SDE_ERROR("invalid encoder\n"); + return; + } + + hw_wb = wb_enc->hw_wb; + wb_cfg = &wb_enc->wb_cfg; + cdp_cfg = &wb_enc->cdp_cfg; + memset(wb_cfg, 0, sizeof(struct sde_hw_wb_cfg)); + + wb_cfg->intf_mode = phys_enc->intf_mode; + + fb_mode = sde_connector_get_property(phys_enc->connector->state, + CONNECTOR_PROP_FB_TRANSLATION_MODE); + if (phys_enc->enable_state == SDE_ENC_DISABLING) + wb_cfg->is_secure = false; + else if (fb_mode == SDE_DRM_FB_SEC) + wb_cfg->is_secure = true; + else + wb_cfg->is_secure = false; + + aspace = (wb_cfg->is_secure) ? + wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] : + wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE]; + + SDE_DEBUG("[fb_secure:%d]\n", wb_cfg->is_secure); + + ret = msm_framebuffer_prepare(fb, aspace); + if (ret) { + SDE_ERROR("prep fb failed, %d\n", ret); + return; + } + + /* cache framebuffer for cleanup in writeback done */ + wb_enc->wb_fb = fb; + wb_enc->wb_aspace = aspace; + drm_framebuffer_get(fb); + + format = msm_framebuffer_format(fb); + if (!format) { + SDE_DEBUG("invalid format for fb\n"); + return; + } + + wb_cfg->dest.format = sde_get_sde_format_ext( + format->pixel_format, + fb->modifier); + if (!wb_cfg->dest.format) { + /* this error should be detected during atomic_check */ + SDE_ERROR("failed to get format %x\n", format->pixel_format); + return; + } + wb_cfg->roi = *wb_roi; + + if (hw_wb->caps->features & BIT(SDE_WB_XY_ROI_OFFSET)) { + ret = sde_format_populate_layout(aspace, fb, &wb_cfg->dest); + if (ret) { + SDE_DEBUG("failed to populate layout %d\n", ret); + return; + } + wb_cfg->dest.width = fb->width; + wb_cfg->dest.height = fb->height; + wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes; + } else { + ret = sde_format_populate_layout_with_roi(aspace, fb, wb_roi, + &wb_cfg->dest); + if (ret) { + /* this error should be detected during atomic_check */ + SDE_DEBUG("failed to populate layout %d\n", ret); + return; + } + } + + if ((wb_cfg->dest.format->fetch_planes == SDE_PLANE_PLANAR) && + (wb_cfg->dest.format->element[0] == C1_B_Cb)) + swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]); + + SDE_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n", + wb_cfg->dest.plane_addr[0], + wb_cfg->dest.plane_addr[1], + wb_cfg->dest.plane_addr[2], + wb_cfg->dest.plane_addr[3]); + SDE_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n", + wb_cfg->dest.plane_pitch[0], + wb_cfg->dest.plane_pitch[1], + wb_cfg->dest.plane_pitch[2], + wb_cfg->dest.plane_pitch[3]); + + if (hw_wb->ops.setup_roi) + hw_wb->ops.setup_roi(hw_wb, wb_cfg); + + if (hw_wb->ops.setup_outformat) + hw_wb->ops.setup_outformat(hw_wb, wb_cfg); + + if (hw_wb->ops.setup_cdp) { + memset(cdp_cfg, 0, sizeof(struct sde_hw_wb_cdp_cfg)); + + cdp_cfg->enable = phys_enc->sde_kms->catalog->perf.cdp_cfg + [SDE_PERF_CDP_USAGE_NRT].wr_enable; + cdp_cfg->ubwc_meta_enable = + SDE_FORMAT_IS_UBWC(wb_cfg->dest.format); + cdp_cfg->tile_amortize_enable = + SDE_FORMAT_IS_UBWC(wb_cfg->dest.format) || + SDE_FORMAT_IS_TILE(wb_cfg->dest.format); + cdp_cfg->preload_ahead = SDE_WB_CDP_PRELOAD_AHEAD_64; + + hw_wb->ops.setup_cdp(hw_wb, cdp_cfg); + } + + if (hw_wb->ops.setup_outaddress) { + SDE_EVT32(hw_wb->idx, + wb_cfg->dest.width, + wb_cfg->dest.height, + wb_cfg->dest.plane_addr[0], + wb_cfg->dest.plane_size[0], + wb_cfg->dest.plane_addr[1], + wb_cfg->dest.plane_size[1], + wb_cfg->dest.plane_addr[2], + wb_cfg->dest.plane_size[2], + wb_cfg->dest.plane_addr[3], + wb_cfg->dest.plane_size[3]); + hw_wb->ops.setup_outaddress(hw_wb, wb_cfg); + } +} + +static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc, + bool enable) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl; + struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc); + struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; + bool need_merge = (crtc->num_mixers > 1); + int i = 0; + + if (!phys_enc->in_clone_mode) { + SDE_DEBUG("not in CWB mode. early return\n"); + return; + } + + if (!hw_pp || !hw_ctl || !hw_wb || hw_pp->idx >= PINGPONG_MAX) { + SDE_ERROR("invalid hw resources - return\n"); + return; + } + + hw_ctl = crtc->mixers[0].hw_ctl; + if (hw_ctl && hw_ctl->ops.setup_intf_cfg_v1 && + test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) { + struct sde_hw_intf_cfg_v1 intf_cfg = { 0, }; + + for (i = 0; i < crtc->num_mixers; i++) + intf_cfg.cwb[intf_cfg.cwb_count++] = + (enum sde_cwb)(hw_pp->idx + i); + + if (enable && hw_pp->merge_3d && (intf_cfg.merge_3d_count < + MAX_MERGE_3D_PER_CTL_V1) && need_merge) + intf_cfg.merge_3d[intf_cfg.merge_3d_count++] = + hw_pp->merge_3d->idx; + + if (hw_pp->ops.setup_3d_mode) + hw_pp->ops.setup_3d_mode(hw_pp, (enable && need_merge) ? + BLEND_3D_H_ROW_INT : 0); + + if (hw_wb->ops.bind_pingpong_blk) + hw_wb->ops.bind_pingpong_blk(hw_wb, enable, hw_pp->idx); + + if (hw_ctl->ops.update_cwb_cfg) { + hw_ctl->ops.update_cwb_cfg(hw_ctl, &intf_cfg, enable); + SDE_DEBUG("in CWB mode on CTL_%d PP-%d merge3d:%d\n", + hw_ctl->idx - CTL_0, + hw_pp->idx - PINGPONG_0, + hw_pp->merge_3d ? + hw_pp->merge_3d->idx - MERGE_3D_0 : -1); + } + } else { + struct sde_hw_intf_cfg *intf_cfg = &phys_enc->intf_cfg; + + memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg)); + intf_cfg->intf = SDE_NONE; + intf_cfg->wb = hw_wb->idx; + + if (hw_ctl && hw_ctl->ops.update_wb_cfg) { + hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable); + SDE_DEBUG("in CWB mode adding WB for CTL_%d\n", + hw_ctl->idx - CTL_0); + } + } +} + +/** + * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc, + const struct sde_format *format) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct sde_hw_cdm *hw_cdm; + struct sde_hw_ctl *ctl; + const int num_wb = 1; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + if (phys_enc->in_clone_mode) { + SDE_DEBUG("in CWB mode. early return\n"); + return; + } + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + hw_wb = wb_enc->hw_wb; + hw_cdm = phys_enc->hw_cdm; + ctl = phys_enc->hw_ctl; + + if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) && + (phys_enc->hw_ctl && + phys_enc->hw_ctl->ops.setup_intf_cfg_v1)) { + struct sde_hw_intf_cfg_v1 *intf_cfg_v1 = &phys_enc->intf_cfg_v1; + struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp; + enum sde_3d_blend_mode mode_3d; + + memset(intf_cfg_v1, 0, sizeof(struct sde_hw_intf_cfg_v1)); + + mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc); + intf_cfg_v1->intf_count = SDE_NONE; + intf_cfg_v1->wb_count = num_wb; + intf_cfg_v1->wb[0] = hw_wb->idx; + if (SDE_FORMAT_IS_YUV(format)) { + if (!phys_enc->hw_cdm) { + SDE_ERROR("Format:YUV but no cdm allocated\n"); + SDE_EVT32(DRMID(phys_enc->parent), + SDE_EVTLOG_ERROR); + return; + } + + intf_cfg_v1->cdm_count = num_wb; + intf_cfg_v1->cdm[0] = hw_cdm->idx; + } + + if (mode_3d && hw_pp && hw_pp->merge_3d && + intf_cfg_v1->merge_3d_count < MAX_MERGE_3D_PER_CTL_V1) + intf_cfg_v1->merge_3d[intf_cfg_v1->merge_3d_count++] = + hw_pp->merge_3d->idx; + + if (hw_pp && hw_pp->ops.setup_3d_mode) + hw_pp->ops.setup_3d_mode(hw_pp, mode_3d); + + /* setup which pp blk will connect to this wb */ + if (hw_pp && hw_wb->ops.bind_pingpong_blk) + hw_wb->ops.bind_pingpong_blk(hw_wb, true, + hw_pp->idx); + + phys_enc->hw_ctl->ops.setup_intf_cfg_v1(phys_enc->hw_ctl, + intf_cfg_v1); + } else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) { + struct sde_hw_intf_cfg *intf_cfg = &phys_enc->intf_cfg; + + memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg)); + + intf_cfg->intf = SDE_NONE; + intf_cfg->wb = hw_wb->idx; + intf_cfg->mode_3d = + sde_encoder_helper_get_3d_blend_mode(phys_enc); + phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, + intf_cfg); + } + +} + +static bool _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, + struct drm_crtc_state *crtc_state) +{ + struct drm_encoder *encoder; + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + const struct sde_wb_cfg *wb_cfg = wb_enc->hw_wb->caps; + + /* Check if WB has CWB support */ + if (!(wb_cfg->features & BIT(SDE_WB_HAS_CWB))) + return false; + + /* if any other encoder is connected to same crtc enable clone mode*/ + drm_for_each_encoder(encoder, crtc_state->crtc->dev) { + if (encoder->crtc != crtc_state->crtc) + continue; + + if (phys_enc->parent != encoder) { + return true; + } + } + + return false; +} + +static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); + struct sde_rect wb_roi = {0,}; + struct sde_rect pu_roi = {0,}; + int data_pt; + int ds_outw = 0; + int ds_outh = 0; + int ds_in_use = false; + int i = 0; + int ret = 0; + + if (!phys_enc->in_clone_mode) { + SDE_DEBUG("not in CWB mode. early return\n"); + goto exit; + } + + ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); + if (ret) { + SDE_ERROR("failed to get roi %d\n", ret); + goto exit; + } + + data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT); + + /* compute cumulative ds output dimensions if in use */ + for (i = 0; i < cstate->num_ds; i++) + if (cstate->ds_cfg[i].scl3_cfg.enable) { + ds_in_use = true; + ds_outw += cstate->ds_cfg[i].scl3_cfg.dst_width; + ds_outh = cstate->ds_cfg[i].scl3_cfg.dst_height; + } + + /* if ds in use check wb roi against ds output dimensions */ + if ((data_pt == CAPTURE_DSPP_OUT) && ds_in_use && + ((wb_roi.w != ds_outw) || (wb_roi.h != ds_outh))) { + SDE_ERROR("invalid wb roi with dest scalar [%dx%d vs %dx%d]\n", + wb_roi.w, wb_roi.h, ds_outw, ds_outh); + ret = -EINVAL; + goto exit; + } + + /* validate conn roi against pu rect */ + if (cstate->user_roi_list.num_rects) { + sde_kms_rect_merge_rectangles(&cstate->user_roi_list, &pu_roi); + if (wb_roi.w != pu_roi.w || wb_roi.h != pu_roi.h) { + SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n", + wb_roi.w, wb_roi.h, pu_roi.w, pu_roi.h); + ret = -EINVAL; + goto exit; + } + } +exit: + return ret; +} + +/** + * sde_encoder_phys_wb_atomic_check - verify and fixup given atomic states + * @phys_enc: Pointer to physical encoder + * @crtc_state: Pointer to CRTC atomic state + * @conn_state: Pointer to connector atomic state + */ +static int sde_encoder_phys_wb_atomic_check( + struct sde_encoder_phys *phys_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + const struct sde_wb_cfg *wb_cfg = hw_wb->caps; + struct drm_framebuffer *fb; + const struct sde_format *fmt; + struct sde_rect wb_roi; + const struct drm_display_mode *mode = &crtc_state->mode; + int rc; + bool clone_mode_curr = false; + + SDE_DEBUG("[atomic_check:%d,%d,\"%s\",%d,%d]\n", + hw_wb->idx - WB_0, mode->base.id, mode->name, + mode->hdisplay, mode->vdisplay); + + if (!conn_state || !conn_state->connector) { + SDE_ERROR("invalid connector state\n"); + return -EINVAL; + } else if (conn_state->connector->status != + connector_status_connected) { + SDE_ERROR("connector not connected %d\n", + conn_state->connector->status); + return -EINVAL; + } + + clone_mode_curr = _sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state); + + /** + * Fail the WB commit when there is a CWB session enabled in HW. + * CWB session needs to be disabled since WB and CWB share the same + * writeback hardware block. + */ + if (phys_enc->in_clone_mode && !clone_mode_curr) { + SDE_ERROR("WB commit before CWB disable\n"); + return -EINVAL; + } + + SDE_DEBUG("detect CWB - status:%d\n", clone_mode_curr); + phys_enc->in_clone_mode = clone_mode_curr; + memset(&wb_roi, 0, sizeof(struct sde_rect)); + + rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); + if (rc) { + SDE_ERROR("failed to get roi %d\n", rc); + return rc; + } + + SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi.x, wb_roi.y, + wb_roi.w, wb_roi.h); + + fb = sde_wb_connector_state_get_output_fb(conn_state); + if (!fb) { + SDE_ERROR("no output framebuffer\n"); + return -EINVAL; + } + + SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id, + fb->width, fb->height); + + fmt = sde_get_sde_format_ext(fb->format->format, fb->modifier); + if (!fmt) { + SDE_ERROR("unsupported output pixel format:%x\n", + fb->format->format); + return -EINVAL; + } + + SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->format->format, + fb->modifier); + + if (SDE_FORMAT_IS_YUV(fmt) && + !(wb_cfg->features & BIT(SDE_WB_YUV_CONFIG))) { + SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format); + return -EINVAL; + } + + if (SDE_FORMAT_IS_UBWC(fmt) && + !(wb_cfg->features & BIT(SDE_WB_UBWC))) { + SDE_ERROR("invalid output format %x\n", fmt->base.pixel_format); + return -EINVAL; + } + + if (SDE_FORMAT_IS_YUV(fmt) != !!phys_enc->hw_cdm) + crtc_state->mode_changed = true; + + if (wb_roi.w && wb_roi.h) { + if (wb_roi.w != mode->hdisplay) { + SDE_ERROR("invalid roi w=%d, mode w=%d\n", wb_roi.w, + mode->hdisplay); + return -EINVAL; + } else if (wb_roi.h != mode->vdisplay) { + SDE_ERROR("invalid roi h=%d, mode h=%d\n", wb_roi.h, + mode->vdisplay); + return -EINVAL; + } else if (wb_roi.x + wb_roi.w > fb->width) { + SDE_ERROR("invalid roi x=%d, w=%d, fb w=%d\n", + wb_roi.x, wb_roi.w, fb->width); + return -EINVAL; + } else if (wb_roi.y + wb_roi.h > fb->height) { + SDE_ERROR("invalid roi y=%d, h=%d, fb h=%d\n", + wb_roi.y, wb_roi.h, fb->height); + return -EINVAL; + } else if (wb_roi.w > wb_cfg->sblk->maxlinewidth) { + SDE_ERROR("invalid roi w=%d, maxlinewidth=%u\n", + wb_roi.w, wb_cfg->sblk->maxlinewidth); + return -EINVAL; + } + } else { + if (wb_roi.x || wb_roi.y) { + SDE_ERROR("invalid roi x=%d, y=%d\n", + wb_roi.x, wb_roi.y); + return -EINVAL; + } else if (fb->width != mode->hdisplay) { + SDE_ERROR("invalid fb w=%d, mode w=%d\n", fb->width, + mode->hdisplay); + return -EINVAL; + } else if (fb->height != mode->vdisplay) { + SDE_ERROR("invalid fb h=%d, mode h=%d\n", fb->height, + mode->vdisplay); + return -EINVAL; + } else if (fb->width > wb_cfg->sblk->maxlinewidth) { + SDE_ERROR("invalid fb w=%d, maxlinewidth=%u\n", + fb->width, wb_cfg->sblk->maxlinewidth); + return -EINVAL; + } + } + + rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, conn_state); + if (rc) { + SDE_ERROR("failed in cwb validation %d\n", rc); + return rc; + } + + return rc; +} + +static void _sde_encoder_phys_wb_update_cwb_flush( + struct sde_encoder_phys *phys_enc, bool enable) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_cdm *hw_cdm; + struct sde_hw_pingpong *hw_pp; + struct sde_crtc *crtc; + struct sde_crtc_state *crtc_state; + int i = 0; + int cwb_capture_mode = 0; + enum sde_cwb cwb_idx = 0; + enum sde_cwb src_pp_idx = 0; + bool dspp_out = false; + bool need_merge = false; + + if (!phys_enc->in_clone_mode) { + SDE_DEBUG("not in CWB mode. early return\n"); + return; + } + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + crtc = to_sde_crtc(wb_enc->crtc); + crtc_state = to_sde_crtc_state(wb_enc->crtc->state); + cwb_capture_mode = sde_crtc_get_property(crtc_state, + CRTC_PROP_CAPTURE_OUTPUT); + + hw_pp = phys_enc->hw_pp; + hw_wb = wb_enc->hw_wb; + hw_cdm = phys_enc->hw_cdm; + + /* In CWB mode, program actual source master sde_hw_ctl from crtc */ + hw_ctl = crtc->mixers[0].hw_ctl; + if (!hw_ctl || !hw_wb || !hw_pp) { + SDE_ERROR("[wb] HW resource not available for CWB\n"); + return; + } + + /* treating LM idx of primary display ctl path as source ping-pong idx*/ + src_pp_idx = (enum sde_cwb)crtc->mixers[0].hw_lm->idx; + cwb_idx = (enum sde_cwb)hw_pp->idx; + dspp_out = (cwb_capture_mode == CAPTURE_DSPP_OUT); + need_merge = (crtc->num_mixers > 1) ? true : false; + + if (src_pp_idx > CWB_0 || ((cwb_idx + crtc->num_mixers) > CWB_MAX)) { + SDE_ERROR("invalid hw config for CWB\n"); + return; + } + + if (hw_ctl->ops.update_bitmask_wb) + hw_ctl->ops.update_bitmask_wb(hw_ctl, hw_wb->idx, 1); + + if (hw_ctl->ops.update_bitmask_cdm && hw_cdm) + hw_ctl->ops.update_bitmask_cdm(hw_ctl, hw_cdm->idx, 1); + + if (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features)) { + for (i = 0; i < crtc->num_mixers; i++) { + cwb_idx = (enum sde_cwb) (hw_pp->idx + i); + src_pp_idx = (enum sde_cwb) (src_pp_idx + i); + + if (hw_wb->ops.program_cwb_ctrl) + hw_wb->ops.program_cwb_ctrl(hw_wb, cwb_idx, + src_pp_idx, dspp_out, enable); + + if (hw_ctl->ops.update_bitmask_cwb) + hw_ctl->ops.update_bitmask_cwb(hw_ctl, + cwb_idx, 1); + } + + if (need_merge && hw_ctl->ops.update_bitmask_merge3d + && hw_pp && hw_pp->merge_3d) + hw_ctl->ops.update_bitmask_merge3d(hw_ctl, + hw_pp->merge_3d->idx, 1); + } else { + phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop, + need_merge, dspp_out); + } +} + +/** + * _sde_encoder_phys_wb_update_flush - flush hardware update + * @phys_enc: Pointer to physical encoder + */ +static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_cdm *hw_cdm; + struct sde_hw_pingpong *hw_pp; + struct sde_ctl_flush_cfg pending_flush = {0,}; + + if (!phys_enc) + return; + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + hw_wb = wb_enc->hw_wb; + hw_cdm = phys_enc->hw_cdm; + hw_pp = phys_enc->hw_pp; + hw_ctl = phys_enc->hw_ctl; + + SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); + + if (phys_enc->in_clone_mode) { + SDE_DEBUG("in CWB mode. early return\n"); + return; + } + + if (!hw_ctl) { + SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0); + return; + } + + if (hw_ctl->ops.update_bitmask_wb) + hw_ctl->ops.update_bitmask_wb(hw_ctl, hw_wb->idx, 1); + + if (hw_ctl->ops.update_bitmask_cdm && hw_cdm) + hw_ctl->ops.update_bitmask_cdm(hw_ctl, hw_cdm->idx, 1); + + if (hw_ctl->ops.update_bitmask_merge3d && hw_pp && hw_pp->merge_3d) + hw_ctl->ops.update_bitmask_merge3d(hw_ctl, + hw_pp->merge_3d->idx, 1); + + if (hw_ctl->ops.get_pending_flush) + hw_ctl->ops.get_pending_flush(hw_ctl, + &pending_flush); + + SDE_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n", + hw_ctl->idx - CTL_0, pending_flush.pending_flush_mask, + hw_wb->idx - WB_0); +} + +/** + * sde_encoder_phys_wb_setup - setup writeback encoder + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_setup( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct drm_display_mode mode = phys_enc->cached_mode; + struct drm_framebuffer *fb; + struct sde_rect *wb_roi = &wb_enc->wb_roi; + + SDE_DEBUG("[mode_set:%d,%d,\"%s\",%d,%d]\n", + hw_wb->idx - WB_0, mode.base.id, mode.name, + mode.hdisplay, mode.vdisplay); + + memset(wb_roi, 0, sizeof(struct sde_rect)); + + /* clear writeback framebuffer - will be updated in setup_fb */ + wb_enc->wb_fb = NULL; + wb_enc->wb_aspace = NULL; + + if (phys_enc->enable_state == SDE_ENC_DISABLING) { + fb = wb_enc->fb_disable; + wb_roi->w = 0; + wb_roi->h = 0; + } else { + fb = sde_wb_get_output_fb(wb_enc->wb_dev); + sde_wb_get_output_roi(wb_enc->wb_dev, wb_roi); + } + + if (!fb) { + SDE_DEBUG("no output framebuffer\n"); + return; + } + + SDE_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id, + fb->width, fb->height); + + if (wb_roi->w == 0 || wb_roi->h == 0) { + wb_roi->x = 0; + wb_roi->y = 0; + wb_roi->w = fb->width; + wb_roi->h = fb->height; + } + + SDE_DEBUG("[roi:%u,%u,%u,%u]\n", wb_roi->x, wb_roi->y, + wb_roi->w, wb_roi->h); + + wb_enc->wb_fmt = sde_get_sde_format_ext(fb->format->format, + fb->modifier); + if (!wb_enc->wb_fmt) { + SDE_ERROR("unsupported output pixel format: %d\n", + fb->format->format); + return; + } + + SDE_DEBUG("[fb_fmt:%x,%llx]\n", fb->format->format, + fb->modifier); + + sde_encoder_phys_wb_set_ot_limit(phys_enc); + + sde_encoder_phys_wb_set_qos_remap(phys_enc); + + sde_encoder_phys_wb_set_qos(phys_enc); + + sde_encoder_phys_setup_cdm(phys_enc, fb, wb_enc->wb_fmt, wb_roi); + + sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi); + + sde_encoder_phys_wb_setup_cdp(phys_enc, wb_enc->wb_fmt); + + _sde_encoder_phys_wb_setup_cwb(phys_enc, true); +} + +static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error) +{ + struct sde_encoder_phys_wb *wb_enc = arg; + struct sde_encoder_phys *phys_enc = &wb_enc->base; + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + u32 event = frame_error ? SDE_ENCODER_FRAME_EVENT_ERROR : 0; + + SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count); + + /* don't notify upper layer for internal commit */ + if (phys_enc->enable_state == SDE_ENC_DISABLING) + goto complete; + + if (phys_enc->parent_ops.handle_frame_done && + atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) { + event |= SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; + + if (phys_enc->in_clone_mode) + event |= SDE_ENCODER_FRAME_EVENT_CWB_DONE; + else + event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + + phys_enc->parent_ops.handle_frame_done(phys_enc->parent, + phys_enc, event); + } + + if (!phys_enc->in_clone_mode && phys_enc->parent_ops.handle_vblank_virt) + phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, + phys_enc); + + SDE_EVT32_IRQ(DRMID(phys_enc->parent), hw_wb->idx - WB_0, event, + frame_error); + +complete: + wake_up_all(&phys_enc->pending_kickoff_wq); +} + +/** + * sde_encoder_phys_wb_done_irq - Pingpong overflow interrupt handler for CWB + * @arg: Pointer to writeback encoder + * @irq_idx: interrupt index + */ +static void sde_encoder_phys_cwb_ovflow(void *arg, int irq_idx) +{ + _sde_encoder_phys_wb_frame_done_helper(arg, true); +} + +/** + * sde_encoder_phys_wb_done_irq - writeback interrupt handler + * @arg: Pointer to writeback encoder + * @irq_idx: interrupt index + */ +static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) +{ + _sde_encoder_phys_wb_frame_done_helper(arg, false); +} + +/** + * sde_encoder_phys_wb_irq_ctrl - irq control of WB + * @phys: Pointer to physical encoder + * @enable: indicates enable or disable interrupts + */ +static void sde_encoder_phys_wb_irq_ctrl( + struct sde_encoder_phys *phys, bool enable) +{ + + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys); + int index = 0, refcount; + int ret = 0, pp = 0; + + if (!wb_enc) + return; + + if (wb_enc->bypass_irqreg) + return; + + pp = phys->hw_pp->idx - PINGPONG_0; + if ((pp + CRTC_DUAL_MIXERS) >= PINGPONG_MAX) { + SDE_ERROR("invalid pingpong index for WB or CWB\n"); + return; + } + + refcount = atomic_read(&phys->wbirq_refcount); + + if (enable && atomic_inc_return(&phys->wbirq_refcount) == 1) { + sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE); + if (ret) + atomic_dec_return(&phys->wbirq_refcount); + + for (index = 0; index < CRTC_DUAL_MIXERS; index++) + if (cwb_irq_tbl[index + pp] != SDE_NONE) + sde_encoder_helper_register_irq(phys, + cwb_irq_tbl[index + pp]); + } else if (!enable && + atomic_dec_return(&phys->wbirq_refcount) == 0) { + sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE); + if (ret) + atomic_inc_return(&phys->wbirq_refcount); + + for (index = 0; index < CRTC_DUAL_MIXERS; index++) + if (cwb_irq_tbl[index + pp] != SDE_NONE) + sde_encoder_helper_unregister_irq(phys, + cwb_irq_tbl[index + pp]); + } +} + +/** + * sde_encoder_phys_wb_mode_set - set display mode + * @phys_enc: Pointer to physical encoder + * @mode: Pointer to requested display mode + * @adj_mode: Pointer to adjusted display mode + */ +static void sde_encoder_phys_wb_mode_set( + struct sde_encoder_phys *phys_enc, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_rm *rm = &phys_enc->sde_kms->rm; + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct sde_rm_hw_iter iter; + int i, instance; + + phys_enc->cached_mode = *adj_mode; + instance = phys_enc->split_role == ENC_ROLE_SLAVE ? 1 : 0; + + SDE_DEBUG("[mode_set_cache:%d,%d,\"%s\",%d,%d]\n", + hw_wb->idx - WB_0, mode->base.id, + mode->name, mode->hdisplay, mode->vdisplay); + + phys_enc->hw_ctl = NULL; + phys_enc->hw_cdm = NULL; + + /* Retrieve previously allocated HW Resources. CTL shouldn't fail */ + sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL); + for (i = 0; i <= instance; i++) { + sde_rm_get_hw(rm, &iter); + if (i == instance) + phys_enc->hw_ctl = (struct sde_hw_ctl *) iter.hw; + } + + if (IS_ERR_OR_NULL(phys_enc->hw_ctl)) { + SDE_ERROR("failed init ctl: %ld\n", + (!phys_enc->hw_ctl) ? + -EINVAL : PTR_ERR(phys_enc->hw_ctl)); + phys_enc->hw_ctl = NULL; + return; + } + + /* CDM is optional */ + sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CDM); + for (i = 0; i <= instance; i++) { + sde_rm_get_hw(rm, &iter); + if (i == instance) + phys_enc->hw_cdm = (struct sde_hw_cdm *) iter.hw; + } + + if (IS_ERR(phys_enc->hw_cdm)) { + SDE_ERROR("CDM required but not allocated: %ld\n", + PTR_ERR(phys_enc->hw_cdm)); + phys_enc->hw_cdm = NULL; + } +} + +static int sde_encoder_phys_wb_frame_timeout(struct sde_encoder_phys *phys_enc) +{ + u32 event = 0; + + while (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0) && + phys_enc->parent_ops.handle_frame_done) { + + event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE + | SDE_ENCODER_FRAME_EVENT_ERROR; + + if (phys_enc->in_clone_mode) + event |= SDE_ENCODER_FRAME_EVENT_CWB_DONE; + else + event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; + + phys_enc->parent_ops.handle_frame_done( + phys_enc->parent, phys_enc, event); + + SDE_EVT32(DRMID(phys_enc->parent), event, + atomic_read(&phys_enc->pending_retire_fence_cnt)); + } + + return event; +} + +static int _sde_encoder_phys_wb_wait_for_commit_done( + struct sde_encoder_phys *phys_enc, bool is_disable) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + u32 event = 0; + u64 wb_time = 0; + int rc = 0; + struct sde_encoder_wait_info wait_info = {0}; + + /* Return EWOULDBLOCK since we know the wait isn't necessary */ + if (phys_enc->enable_state == SDE_ENC_DISABLED) { + SDE_ERROR("encoder already disabled\n"); + return -EWOULDBLOCK; + } + + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count, + wb_enc->kickoff_count, !!wb_enc->wb_fb, is_disable, + phys_enc->in_clone_mode); + + if (!is_disable && phys_enc->in_clone_mode && + (atomic_read(&phys_enc->pending_retire_fence_cnt) <= 1)) + goto skip_wait; + + /* signal completion if commit with no framebuffer */ + if (!wb_enc->wb_fb) { + SDE_DEBUG("no output framebuffer\n"); + _sde_encoder_phys_wb_frame_done_helper(wb_enc, false); + } + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; + wait_info.timeout_ms = max_t(u32, wb_enc->wbdone_timeout, + KICKOFF_TIMEOUT_MS); + rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE, + &wait_info); + if (rc == -ETIMEDOUT) { + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), + wb_enc->frame_count, SDE_EVTLOG_ERROR); + SDE_ERROR("wb:%d kickoff timed out\n", WBID(wb_enc)); + + event = sde_encoder_phys_wb_frame_timeout(phys_enc); + } + + /* cleanup writeback framebuffer */ + if (wb_enc->wb_fb && wb_enc->wb_aspace) { + msm_framebuffer_cleanup(wb_enc->wb_fb, wb_enc->wb_aspace); + drm_framebuffer_put(wb_enc->wb_fb); + wb_enc->wb_fb = NULL; + wb_enc->wb_aspace = NULL; + } + +skip_wait: + /* remove vote for iommu/clk/bus */ + wb_enc->frame_count++; + + if (!rc) { + wb_enc->end_time = ktime_get(); + wb_time = (u64)ktime_to_us(wb_enc->end_time) - + (u64)ktime_to_us(wb_enc->start_time); + SDE_DEBUG("wb:%d took %llu us\n", WBID(wb_enc), wb_time); + } + + /* cleanup previous buffer if pending */ + if (wb_enc->cwb_old_fb && wb_enc->cwb_old_aspace) { + msm_framebuffer_cleanup(wb_enc->cwb_old_fb, wb_enc->cwb_old_aspace); + drm_framebuffer_put(wb_enc->cwb_old_fb); + wb_enc->cwb_old_fb = NULL; + wb_enc->cwb_old_aspace = NULL; + } + + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count, + wb_time, event, rc); + + return rc; +} + +/** + * sde_encoder_phys_wb_wait_for_commit_done - wait until request is committed + * @phys_enc: Pointer to physical encoder + */ +static int sde_encoder_phys_wb_wait_for_commit_done( + struct sde_encoder_phys *phys_enc) +{ + return _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, false); +} + +static int sde_encoder_phys_wb_wait_for_cwb_done( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_encoder_wait_info wait_info = {0}; + int rc = 0; + + if (!phys_enc->in_clone_mode) + return 0; + + SDE_EVT32(atomic_read(&phys_enc->pending_retire_fence_cnt)); + + wait_info.wq = &phys_enc->pending_kickoff_wq; + wait_info.atomic_cnt = &phys_enc->pending_retire_fence_cnt; + wait_info.timeout_ms = max_t(u32, wb_enc->wbdone_timeout, + KICKOFF_TIMEOUT_MS); + + rc = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE, + &wait_info); + + if (rc == -ETIMEDOUT) + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), + wb_enc->frame_count, SDE_EVTLOG_ERROR); + + return rc; +} + +/** + * sde_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing + * @phys_enc: Pointer to physical encoder + * @params: kickoff parameters + * Returns: Zero on success + */ +static int sde_encoder_phys_wb_prepare_for_kickoff( + struct sde_encoder_phys *phys_enc, + struct sde_encoder_kickoff_params *params) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + + SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0, + wb_enc->kickoff_count); + + if (phys_enc->in_clone_mode) { + wb_enc->cwb_old_fb = wb_enc->wb_fb; + wb_enc->cwb_old_aspace = wb_enc->wb_aspace; + } + + wb_enc->kickoff_count++; + + /* set OT limit & enable traffic shaper */ + sde_encoder_phys_wb_setup(phys_enc); + + _sde_encoder_phys_wb_update_flush(phys_enc); + + _sde_encoder_phys_wb_update_cwb_flush(phys_enc, true); + + /* vote for iommu/clk/bus */ + wb_enc->start_time = ktime_get(); + + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), + wb_enc->kickoff_count, wb_enc->frame_count, + phys_enc->in_clone_mode); + return 0; +} + +/** + * sde_encoder_phys_wb_trigger_flush - trigger flush processing + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_trigger_flush(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + + if (!phys_enc || !wb_enc->hw_wb) { + SDE_ERROR("invalid encoder\n"); + return; + } + + /* + * Bail out iff in CWB mode. In case of CWB, primary control-path + * which is actually driving would trigger the flush + */ + if (phys_enc->in_clone_mode) { + SDE_DEBUG("in CWB mode. early return\n"); + return; + } + + SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0); + + /* clear pending flush if commit with no framebuffer */ + if (!wb_enc->wb_fb) { + SDE_DEBUG("no output framebuffer\n"); + return; + } + + sde_encoder_helper_trigger_flush(phys_enc); +} + +/** + * sde_encoder_phys_wb_handle_post_kickoff - post-kickoff processing + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_handle_post_kickoff( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + + SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0); + + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc)); +} + +/** + * _sde_encoder_phys_wb_init_internal_fb - create fb for internal commit + * @wb_enc: Pointer to writeback encoder + * @pixel_format: DRM pixel format + * @width: Desired fb width + * @height: Desired fb height + * @pitch: Desired fb pitch + */ +static int _sde_encoder_phys_wb_init_internal_fb( + struct sde_encoder_phys_wb *wb_enc, + uint32_t pixel_format, uint32_t width, + uint32_t height, uint32_t pitch) +{ + struct drm_device *dev; + struct drm_framebuffer *fb; + struct drm_mode_fb_cmd2 mode_cmd; + uint32_t size; + int nplanes, i, ret; + struct msm_gem_address_space *aspace; + + if (!wb_enc || !wb_enc->base.parent || !wb_enc->base.sde_kms) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + aspace = wb_enc->base.sde_kms->aspace[SDE_IOMMU_DOMAIN_UNSECURE]; + if (!aspace) { + SDE_ERROR("invalid address space\n"); + return -EINVAL; + } + + dev = wb_enc->base.sde_kms->dev; + if (!dev) { + SDE_ERROR("invalid dev\n"); + return -EINVAL; + } + + memset(&mode_cmd, 0, sizeof(mode_cmd)); + mode_cmd.pixel_format = pixel_format; + mode_cmd.width = width; + mode_cmd.height = height; + mode_cmd.pitches[0] = pitch; + + size = sde_format_get_framebuffer_size(pixel_format, + mode_cmd.width, mode_cmd.height, + mode_cmd.pitches, 0); + if (!size) { + SDE_DEBUG("not creating zero size buffer\n"); + return -EINVAL; + } + + /* allocate gem tracking object */ + nplanes = drm_format_num_planes(pixel_format); + if (nplanes >= SDE_MAX_PLANES) { + SDE_ERROR("requested format has too many planes\n"); + return -EINVAL; + } + + wb_enc->bo_disable[0] = msm_gem_new(dev, size, + MSM_BO_SCANOUT | MSM_BO_WC); + if (IS_ERR_OR_NULL(wb_enc->bo_disable[0])) { + ret = PTR_ERR(wb_enc->bo_disable[0]); + wb_enc->bo_disable[0] = NULL; + + SDE_ERROR("failed to create bo, %d\n", ret); + return ret; + } + + for (i = 0; i < nplanes; ++i) { + wb_enc->bo_disable[i] = wb_enc->bo_disable[0]; + mode_cmd.pitches[i] = width * + drm_format_plane_cpp(pixel_format, i); + } + + fb = msm_framebuffer_init(dev, &mode_cmd, wb_enc->bo_disable); + if (IS_ERR_OR_NULL(fb)) { + ret = PTR_ERR(fb); + drm_gem_object_put(wb_enc->bo_disable[0]); + wb_enc->bo_disable[0] = NULL; + + SDE_ERROR("failed to init fb, %d\n", ret); + return ret; + } + + /* prepare the backing buffer now so that it's available later */ + ret = msm_framebuffer_prepare(fb, aspace); + if (!ret) + wb_enc->fb_disable = fb; + return ret; +} + +/** + * _sde_encoder_phys_wb_destroy_internal_fb - deconstruct internal fb + * @wb_enc: Pointer to writeback encoder + */ +static void _sde_encoder_phys_wb_destroy_internal_fb( + struct sde_encoder_phys_wb *wb_enc) +{ + if (!wb_enc) + return; + + if (wb_enc->fb_disable) { + drm_framebuffer_unregister_private(wb_enc->fb_disable); + drm_framebuffer_remove(wb_enc->fb_disable); + wb_enc->fb_disable = NULL; + } + + if (wb_enc->bo_disable[0]) { + drm_gem_object_put(wb_enc->bo_disable[0]); + wb_enc->bo_disable[0] = NULL; + } +} + +/** + * sde_encoder_phys_wb_enable - enable writeback encoder + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_enable(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct drm_device *dev; + struct drm_connector *connector; + + SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); + + if (!wb_enc->base.parent || !wb_enc->base.parent->dev) { + SDE_ERROR("invalid drm device\n"); + return; + } + dev = wb_enc->base.parent->dev; + + /* find associated writeback connector */ + connector = phys_enc->connector; + + if (!connector || connector->encoder != phys_enc->parent) { + SDE_ERROR("failed to find writeback connector\n"); + return; + } + wb_enc->wb_dev = sde_wb_connector_get_wb(connector); + + phys_enc->enable_state = SDE_ENC_ENABLED; + + /* + * cache the crtc in wb_enc on enable for duration of use case + * for correctly servicing asynchronous irq events and timers + */ + wb_enc->crtc = phys_enc->parent->crtc; +} + +/** + * sde_encoder_phys_wb_disable - disable writeback encoder + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + + SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); + + if (phys_enc->enable_state == SDE_ENC_DISABLED) { + SDE_ERROR("encoder is already disabled\n"); + return; + } + + SDE_DEBUG("[wait_for_done: wb:%d, frame:%u, kickoff:%u]\n", + hw_wb->idx - WB_0, wb_enc->frame_count, + wb_enc->kickoff_count); + _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true); + + if (!phys_enc->hw_ctl || !phys_enc->parent || + !phys_enc->sde_kms || !wb_enc->fb_disable) { + SDE_DEBUG("invalid enc, skipping extra commit\n"); + goto exit; + } + + /* avoid reset frame for CWB */ + if (phys_enc->in_clone_mode) { + _sde_encoder_phys_wb_setup_cwb(phys_enc, false); + _sde_encoder_phys_wb_update_cwb_flush(phys_enc, false); + phys_enc->in_clone_mode = false; + goto exit; + } + + /* reset h/w before final flush */ + if (phys_enc->hw_ctl->ops.clear_pending_flush) + phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); + + /* + * New CTL reset sequence from 5.0 MDP onwards. + * If has_3d_merge_reset is not set, legacy reset + * sequence is executed. + */ + if (hw_wb->catalog->has_3d_merge_reset) { + sde_encoder_helper_phys_disable(phys_enc, wb_enc); + goto exit; + } + + if (sde_encoder_helper_reset_mixers(phys_enc, NULL)) + goto exit; + + phys_enc->enable_state = SDE_ENC_DISABLING; + + sde_encoder_phys_wb_prepare_for_kickoff(phys_enc, NULL); + sde_encoder_phys_wb_irq_ctrl(phys_enc, true); + if (phys_enc->hw_ctl->ops.trigger_flush) + phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl); + + sde_encoder_helper_trigger_start(phys_enc); + _sde_encoder_phys_wb_wait_for_commit_done(phys_enc, true); + sde_encoder_phys_wb_irq_ctrl(phys_enc, false); + +exit: + /* + * frame count and kickoff count are only used for debug purpose. Frame + * count can be more than kickoff count at the end of disable call due + * to extra frame_done wait. It does not cause any issue because + * frame_done wait is based on retire_fence count. Leaving these + * counters for debugging purpose. + */ + if (wb_enc->frame_count != wb_enc->kickoff_count) { + SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), + wb_enc->kickoff_count, wb_enc->frame_count, + phys_enc->in_clone_mode); + wb_enc->frame_count = wb_enc->kickoff_count; + } + + phys_enc->enable_state = SDE_ENC_DISABLED; + wb_enc->crtc = NULL; + phys_enc->hw_cdm = NULL; + phys_enc->hw_ctl = NULL; +} + +/** + * sde_encoder_phys_wb_get_hw_resources - get hardware resources + * @phys_enc: Pointer to physical encoder + * @hw_res: Pointer to encoder resources + */ +static void sde_encoder_phys_wb_get_hw_resources( + struct sde_encoder_phys *phys_enc, + struct sde_encoder_hw_resources *hw_res, + struct drm_connector_state *conn_state) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb; + struct drm_framebuffer *fb; + const struct sde_format *fmt = NULL; + + if (!phys_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + + fb = sde_wb_connector_state_get_output_fb(conn_state); + if (fb) { + fmt = sde_get_sde_format_ext(fb->format->format, fb->modifier); + if (!fmt) { + SDE_ERROR("unsupported output pixel format:%d\n", + fb->format->format); + return; + } + } + + hw_wb = wb_enc->hw_wb; + hw_res->wbs[hw_wb->idx - WB_0] = phys_enc->intf_mode; + hw_res->needs_cdm = fmt ? SDE_FORMAT_IS_YUV(fmt) : false; + SDE_DEBUG("[wb:%d] intf_mode=%d needs_cdm=%d\n", hw_wb->idx - WB_0, + hw_res->wbs[hw_wb->idx - WB_0], + hw_res->needs_cdm); +} + +#ifdef CONFIG_DEBUG_FS +/** + * sde_encoder_phys_wb_init_debugfs - initialize writeback encoder debugfs + * @phys_enc: Pointer to physical encoder + * @debugfs_root: Pointer to virtual encoder's debugfs_root dir + */ +static int sde_encoder_phys_wb_init_debugfs( + struct sde_encoder_phys *phys_enc, struct dentry *debugfs_root) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + + if (!phys_enc || !wb_enc->hw_wb || !debugfs_root) + return -EINVAL; + + if (!debugfs_create_u32("wbdone_timeout", 0600, + debugfs_root, &wb_enc->wbdone_timeout)) { + SDE_ERROR("failed to create debugfs/wbdone_timeout\n"); + return -ENOMEM; + } + + return 0; +} +#else +static int sde_encoder_phys_wb_init_debugfs( + struct sde_encoder_phys *phys_enc, struct dentry *debugfs_root) +{ + return 0; +} +#endif + +static int sde_encoder_phys_wb_late_register(struct sde_encoder_phys *phys_enc, + struct dentry *debugfs_root) +{ + return sde_encoder_phys_wb_init_debugfs(phys_enc, debugfs_root); +} + +/** + * sde_encoder_phys_wb_destroy - destroy writeback encoder + * @phys_enc: Pointer to physical encoder + */ +static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + + SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); + + if (!phys_enc) + return; + + _sde_encoder_phys_wb_destroy_internal_fb(wb_enc); + + kfree(wb_enc); +} + +/** + * sde_encoder_phys_wb_init_ops - initialize writeback operations + * @ops: Pointer to encoder operation table + */ +static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops) +{ + ops->late_register = sde_encoder_phys_wb_late_register; + ops->is_master = sde_encoder_phys_wb_is_master; + ops->mode_set = sde_encoder_phys_wb_mode_set; + ops->enable = sde_encoder_phys_wb_enable; + ops->disable = sde_encoder_phys_wb_disable; + ops->destroy = sde_encoder_phys_wb_destroy; + ops->atomic_check = sde_encoder_phys_wb_atomic_check; + ops->get_hw_resources = sde_encoder_phys_wb_get_hw_resources; + ops->wait_for_commit_done = sde_encoder_phys_wb_wait_for_commit_done; + ops->prepare_for_kickoff = sde_encoder_phys_wb_prepare_for_kickoff; + ops->handle_post_kickoff = sde_encoder_phys_wb_handle_post_kickoff; + ops->trigger_flush = sde_encoder_phys_wb_trigger_flush; + ops->trigger_start = sde_encoder_helper_trigger_start; + ops->hw_reset = sde_encoder_helper_hw_reset; + ops->irq_control = sde_encoder_phys_wb_irq_ctrl; + ops->wait_for_tx_complete = sde_encoder_phys_wb_wait_for_cwb_done; +} + +/** + * sde_encoder_phys_wb_init - initialize writeback encoder + * @init: Pointer to init info structure with initialization params + */ +struct sde_encoder_phys *sde_encoder_phys_wb_init( + struct sde_enc_phys_init_params *p) +{ + struct sde_encoder_phys *phys_enc; + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_mdp *hw_mdp; + struct sde_encoder_irq *irq; + int ret = 0; + + SDE_DEBUG("\n"); + + if (!p || !p->parent) { + SDE_ERROR("invalid params\n"); + ret = -EINVAL; + goto fail_alloc; + } + + wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL); + if (!wb_enc) { + SDE_ERROR("failed to allocate wb enc\n"); + ret = -ENOMEM; + goto fail_alloc; + } + wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS; + + phys_enc = &wb_enc->base; + + if (p->sde_kms->vbif[VBIF_NRT]) { + wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_UNSECURE]; + wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_NRT_SECURE]; + } else { + wb_enc->aspace[SDE_IOMMU_DOMAIN_UNSECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_UNSECURE]; + wb_enc->aspace[SDE_IOMMU_DOMAIN_SECURE] = + p->sde_kms->aspace[MSM_SMMU_DOMAIN_SECURE]; + } + + hw_mdp = sde_rm_get_mdp(&p->sde_kms->rm); + if (IS_ERR_OR_NULL(hw_mdp)) { + ret = PTR_ERR(hw_mdp); + SDE_ERROR("failed to init hw_top: %d\n", ret); + goto fail_mdp_init; + } + phys_enc->hw_mdptop = hw_mdp; + + /** + * hw_wb resource permanently assigned to this encoder + * Other resources allocated at atomic commit time by use case + */ + if (p->wb_idx != SDE_NONE) { + struct sde_rm_hw_iter iter; + + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_WB); + while (sde_rm_get_hw(&p->sde_kms->rm, &iter)) { + struct sde_hw_wb *hw_wb = (struct sde_hw_wb *)iter.hw; + + if (hw_wb->idx == p->wb_idx) { + wb_enc->hw_wb = hw_wb; + break; + } + } + + if (!wb_enc->hw_wb) { + ret = -EINVAL; + SDE_ERROR("failed to init hw_wb%d\n", p->wb_idx - WB_0); + goto fail_wb_init; + } + } else { + ret = -EINVAL; + SDE_ERROR("invalid wb_idx\n"); + goto fail_wb_check; + } + + sde_encoder_phys_wb_init_ops(&phys_enc->ops); + phys_enc->parent = p->parent; + phys_enc->parent_ops = p->parent_ops; + phys_enc->sde_kms = p->sde_kms; + phys_enc->split_role = p->split_role; + phys_enc->intf_mode = INTF_MODE_WB_LINE; + phys_enc->intf_idx = p->intf_idx; + phys_enc->enc_spinlock = p->enc_spinlock; + phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; + atomic_set(&phys_enc->pending_retire_fence_cnt, 0); + atomic_set(&phys_enc->wbirq_refcount, 0); + init_waitqueue_head(&phys_enc->pending_kickoff_wq); + + irq = &phys_enc->irq[INTR_IDX_WB_DONE]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "wb_done"; + irq->hw_idx = wb_enc->hw_wb->idx; + irq->irq_idx = -1; + irq->intr_type = sde_encoder_phys_wb_get_intr_type(wb_enc->hw_wb); + irq->intr_idx = INTR_IDX_WB_DONE; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_wb_done_irq; + + irq = &phys_enc->irq[INTR_IDX_PP1_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp1_overflow"; + irq->hw_idx = CWB_1; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP1_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; + + irq = &phys_enc->irq[INTR_IDX_PP2_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp2_overflow"; + irq->hw_idx = CWB_2; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP2_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; + + irq = &phys_enc->irq[INTR_IDX_PP3_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp3_overflow"; + irq->hw_idx = CWB_3; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP3_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; + + irq = &phys_enc->irq[INTR_IDX_PP4_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp4_overflow"; + irq->hw_idx = CWB_4; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP4_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; + + irq = &phys_enc->irq[INTR_IDX_PP5_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp5_overflow"; + irq->hw_idx = CWB_5; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP5_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; + + /* create internal buffer for disable logic */ + if (_sde_encoder_phys_wb_init_internal_fb(wb_enc, + DRM_FORMAT_RGB888, 2, 1, 6)) { + SDE_ERROR("failed to init internal fb\n"); + goto fail_wb_init; + } + + SDE_DEBUG("Created sde_encoder_phys_wb for wb %d\n", + wb_enc->hw_wb->idx - WB_0); + + return phys_enc; + +fail_wb_init: +fail_wb_check: +fail_mdp_init: + kfree(wb_enc); +fail_alloc: + return ERR_PTR(ret); +} diff --git a/techpack/display/msm/sde/sde_fence.c b/techpack/display/msm/sde/sde_fence.c new file mode 100644 index 0000000000000000000000000000000000000000..eb9b8fb51dec2dbfbf542cf9bbce90e69c2a5ff3 --- /dev/null +++ b/techpack/display/msm/sde/sde_fence.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/sync_file.h> +#include <linux/dma-fence.h> +#include "msm_drv.h" +#include "sde_kms.h" +#include "sde_fence.h" + +#define TIMELINE_VAL_LENGTH 128 + +void *sde_sync_get(uint64_t fd) +{ + /* force signed compare, fdget accepts an int argument */ + return (signed int)fd >= 0 ? sync_file_get_fence(fd) : NULL; +} + +void sde_sync_put(void *fence) +{ + if (fence) + dma_fence_put(fence); +} + +signed long sde_sync_wait(void *fnc, long timeout_ms) +{ + struct dma_fence *fence = fnc; + int rc; + char timeline_str[TIMELINE_VAL_LENGTH]; + + if (!fence) + return -EINVAL; + else if (dma_fence_is_signaled(fence)) + return timeout_ms ? msecs_to_jiffies(timeout_ms) : 1; + + rc = dma_fence_wait_timeout(fence, true, + msecs_to_jiffies(timeout_ms)); + if (!rc || (rc == -EINVAL)) { + if (fence->ops->timeline_value_str) + fence->ops->timeline_value_str(fence, + timeline_str, TIMELINE_VAL_LENGTH); + + SDE_ERROR( + "fence driver name:%s timeline name:%s seqno:0x%x timeline:%s signaled:0x%x\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno, timeline_str, + fence->ops->signaled ? + fence->ops->signaled(fence) : 0xffffffff); + } + + return rc; +} + +uint32_t sde_sync_get_name_prefix(void *fence) +{ + const char *name; + uint32_t i, prefix; + struct dma_fence *f = fence; + + if (!fence) + return 0; + + name = f->ops->get_driver_name(f); + if (!name) + return 0; + + prefix = 0x0; + for (i = 0; i < sizeof(uint32_t) && name[i]; ++i) + prefix = (prefix << CHAR_BIT) | name[i]; + + return prefix; +} + +/** + * struct sde_fence - release/retire fence structure + * @fence: base fence structure + * @name: name of each fence- it is fence timeline + commit_count + * @fence_list: list to associated this fence on timeline/context + * @fd: fd attached to this fence - debugging purpose. + */ +struct sde_fence { + struct dma_fence base; + struct sde_fence_context *ctx; + char name[SDE_FENCE_NAME_SIZE]; + struct list_head fence_list; + int fd; +}; + +static void sde_fence_destroy(struct kref *kref) +{ + struct sde_fence_context *ctx; + + if (!kref) { + SDE_ERROR("received invalid kref\n"); + return; + } + + ctx = container_of(kref, struct sde_fence_context, kref); + kfree(ctx); +} + +static inline struct sde_fence *to_sde_fence(struct dma_fence *fence) +{ + return container_of(fence, struct sde_fence, base); +} + +static const char *sde_fence_get_driver_name(struct dma_fence *fence) +{ + struct sde_fence *f = to_sde_fence(fence); + + return f->name; +} + +static const char *sde_fence_get_timeline_name(struct dma_fence *fence) +{ + struct sde_fence *f = to_sde_fence(fence); + + return f->ctx->name; +} + +static bool sde_fence_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static bool sde_fence_signaled(struct dma_fence *fence) +{ + struct sde_fence *f = to_sde_fence(fence); + bool status; + + status = (int)((fence->seqno - f->ctx->done_count) <= 0); + SDE_DEBUG("status:%d fence seq:%d and timeline:%d\n", + status, fence->seqno, f->ctx->done_count); + return status; +} + +static void sde_fence_release(struct dma_fence *fence) +{ + struct sde_fence *f; + + if (fence) { + f = to_sde_fence(fence); + kref_put(&f->ctx->kref, sde_fence_destroy); + kfree(f); + } +} + +static void sde_fence_value_str(struct dma_fence *fence, char *str, int size) +{ + if (!fence || !str) + return; + + snprintf(str, size, "%d", fence->seqno); +} + +static void sde_fence_timeline_value_str(struct dma_fence *fence, char *str, + int size) +{ + struct sde_fence *f = to_sde_fence(fence); + + if (!fence || !f->ctx || !str) + return; + + snprintf(str, size, "%d", f->ctx->done_count); +} + +static struct dma_fence_ops sde_fence_ops = { + .get_driver_name = sde_fence_get_driver_name, + .get_timeline_name = sde_fence_get_timeline_name, + .enable_signaling = sde_fence_enable_signaling, + .signaled = sde_fence_signaled, + .wait = dma_fence_default_wait, + .release = sde_fence_release, + .fence_value_str = sde_fence_value_str, + .timeline_value_str = sde_fence_timeline_value_str, +}; + +/** + * _sde_fence_create_fd - create fence object and return an fd for it + * This function is NOT thread-safe. + * @timeline: Timeline to associate with fence + * @val: Timeline value at which to signal the fence + * Return: File descriptor on success, or error code on error + */ +static int _sde_fence_create_fd(void *fence_ctx, uint32_t val) +{ + struct sde_fence *sde_fence; + struct sync_file *sync_file; + signed int fd = -EINVAL; + struct sde_fence_context *ctx = fence_ctx; + + if (!ctx) { + SDE_ERROR("invalid context\n"); + goto exit; + } + + sde_fence = kzalloc(sizeof(*sde_fence), GFP_KERNEL); + if (!sde_fence) + return -ENOMEM; + + sde_fence->ctx = fence_ctx; + snprintf(sde_fence->name, SDE_FENCE_NAME_SIZE, "sde_fence:%s:%u", + sde_fence->ctx->name, val); + dma_fence_init(&sde_fence->base, &sde_fence_ops, &ctx->lock, + ctx->context, val); + kref_get(&ctx->kref); + + /* create fd */ + fd = get_unused_fd_flags(0); + if (fd < 0) { + SDE_ERROR("failed to get_unused_fd_flags(), %s\n", + sde_fence->name); + dma_fence_put(&sde_fence->base); + goto exit; + } + + /* create fence */ + sync_file = sync_file_create(&sde_fence->base); + if (sync_file == NULL) { + put_unused_fd(fd); + fd = -EINVAL; + SDE_ERROR("couldn't create fence, %s\n", sde_fence->name); + dma_fence_put(&sde_fence->base); + goto exit; + } + + fd_install(fd, sync_file->file); + sde_fence->fd = fd; + + spin_lock(&ctx->list_lock); + list_add_tail(&sde_fence->fence_list, &ctx->fence_list_head); + spin_unlock(&ctx->list_lock); + +exit: + return fd; +} + +struct sde_fence_context *sde_fence_init(const char *name, uint32_t drm_id) +{ + struct sde_fence_context *ctx; + + if (!name) { + SDE_ERROR("invalid argument(s)\n"); + return ERR_PTR(-EINVAL); + } + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + + if (!ctx) { + SDE_ERROR("failed to alloc fence ctx\n"); + return ERR_PTR(-ENOMEM); + } + + strlcpy(ctx->name, name, ARRAY_SIZE(ctx->name)); + ctx->drm_id = drm_id; + kref_init(&ctx->kref); + ctx->context = dma_fence_context_alloc(1); + + spin_lock_init(&ctx->lock); + spin_lock_init(&ctx->list_lock); + INIT_LIST_HEAD(&ctx->fence_list_head); + + return ctx; +} + +void sde_fence_deinit(struct sde_fence_context *ctx) +{ + if (!ctx) { + SDE_ERROR("invalid fence\n"); + return; + } + + kref_put(&ctx->kref, sde_fence_destroy); +} + +void sde_fence_prepare(struct sde_fence_context *ctx) +{ + unsigned long flags; + + if (!ctx) { + SDE_ERROR("invalid argument(s), fence %pK\n", ctx); + } else { + spin_lock_irqsave(&ctx->lock, flags); + ++ctx->commit_count; + spin_unlock_irqrestore(&ctx->lock, flags); + } +} + +static void _sde_fence_trigger(struct sde_fence_context *ctx, + ktime_t ts, bool error) +{ + unsigned long flags; + struct sde_fence *fc, *next; + bool is_signaled = false; + + kref_get(&ctx->kref); + + spin_lock(&ctx->list_lock); + if (list_empty(&ctx->fence_list_head)) { + SDE_DEBUG("nothing to trigger!\n"); + goto end; + } + + list_for_each_entry_safe(fc, next, &ctx->fence_list_head, fence_list) { + spin_lock_irqsave(&ctx->lock, flags); + fc->base.error = error ? -EBUSY : 0; + fc->base.timestamp = ts; + is_signaled = dma_fence_is_signaled_locked(&fc->base); + spin_unlock_irqrestore(&ctx->lock, flags); + + if (is_signaled) { + list_del_init(&fc->fence_list); + dma_fence_put(&fc->base); + } + } +end: + spin_unlock(&ctx->list_lock); + kref_put(&ctx->kref, sde_fence_destroy); +} + +int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val, + uint32_t offset) +{ + uint32_t trigger_value; + int fd, rc = -EINVAL; + unsigned long flags; + + if (!ctx || !val) { + SDE_ERROR("invalid argument(s), fence %d, pval %d\n", + ctx != NULL, val != NULL); + return rc; + } + + /* + * Allow created fences to have a constant offset with respect + * to the timeline. This allows us to delay the fence signalling + * w.r.t. the commit completion (e.g., an offset of +1 would + * cause fences returned during a particular commit to signal + * after an additional delay of one commit, rather than at the + * end of the current one. + */ + spin_lock_irqsave(&ctx->lock, flags); + trigger_value = ctx->commit_count + offset; + spin_unlock_irqrestore(&ctx->lock, flags); + + fd = _sde_fence_create_fd(ctx, trigger_value); + *val = fd; + SDE_DEBUG("fd:%d trigger:%d commit:%d offset:%d\n", + fd, trigger_value, ctx->commit_count, offset); + + SDE_EVT32(ctx->drm_id, trigger_value, fd); + rc = (fd >= 0) ? 0 : fd; + + return rc; +} + +void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, + enum sde_fence_event fence_event) +{ + unsigned long flags; + + if (!ctx) { + SDE_ERROR("invalid ctx, %pK\n", ctx); + return; + } + + spin_lock_irqsave(&ctx->lock, flags); + if (fence_event == SDE_FENCE_RESET_TIMELINE) { + if ((int)(ctx->done_count - ctx->commit_count) < 0) { + SDE_DEBUG( + "timeline reset attempt! done count:%d commit:%d\n", + ctx->done_count, ctx->commit_count); + ctx->done_count = ctx->commit_count; + SDE_EVT32(ctx->drm_id, ctx->done_count, + ctx->commit_count, ktime_to_us(ts), + fence_event, SDE_EVTLOG_FUNC_CASE1); + } else { + spin_unlock_irqrestore(&ctx->lock, flags); + return; + } + } else if ((int)(ctx->done_count - ctx->commit_count) < 0) { + ++ctx->done_count; + SDE_DEBUG("fence_signal:done count:%d commit count:%d\n", + ctx->done_count, ctx->commit_count); + } else { + SDE_ERROR("extra signal attempt! done count:%d commit:%d\n", + ctx->done_count, ctx->commit_count); + SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count, + ktime_to_us(ts), fence_event, SDE_EVTLOG_FATAL); + spin_unlock_irqrestore(&ctx->lock, flags); + return; + } + spin_unlock_irqrestore(&ctx->lock, flags); + + SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count, + ktime_to_us(ts)); + + _sde_fence_trigger(ctx, ts, (fence_event == SDE_FENCE_SIGNAL_ERROR)); +} + +void sde_fence_timeline_status(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj) +{ + char *obj_name; + + if (!ctx || !drm_obj) { + SDE_ERROR("invalid input params\n"); + return; + } + + switch (drm_obj->type) { + case DRM_MODE_OBJECT_CRTC: + obj_name = "crtc"; + break; + case DRM_MODE_OBJECT_CONNECTOR: + obj_name = "connector"; + break; + default: + obj_name = "unknown"; + break; + } + + SDE_ERROR("drm obj:%s id:%d type:0x%x done_count:%d commit_count:%d\n", + obj_name, drm_obj->id, drm_obj->type, ctx->done_count, + ctx->commit_count); +} + +void sde_fence_list_dump(struct dma_fence *fence, struct seq_file **s) +{ + char timeline_str[TIMELINE_VAL_LENGTH]; + + if (fence->ops->timeline_value_str) + fence->ops->timeline_value_str(fence, + timeline_str, TIMELINE_VAL_LENGTH); + + seq_printf(*s, "fence name:%s timeline name:%s seqno:0x%x timeline:%s signaled:0x%x\n", + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno, timeline_str, + fence->ops->signaled ? + fence->ops->signaled(fence) : 0xffffffff); +} + +void sde_debugfs_timeline_dump(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj, struct seq_file **s) +{ + char *obj_name; + struct sde_fence *fc, *next; + struct dma_fence *fence; + + if (!ctx || !drm_obj) { + SDE_ERROR("invalid input params\n"); + return; + } + + switch (drm_obj->type) { + case DRM_MODE_OBJECT_CRTC: + obj_name = "crtc"; + break; + case DRM_MODE_OBJECT_CONNECTOR: + obj_name = "connector"; + break; + default: + obj_name = "unknown"; + break; + } + + seq_printf(*s, "drm obj:%s id:%d type:0x%x done_count:%d commit_count:%d\n", + obj_name, drm_obj->id, drm_obj->type, ctx->done_count, + ctx->commit_count); + + spin_lock(&ctx->list_lock); + list_for_each_entry_safe(fc, next, &ctx->fence_list_head, fence_list) { + fence = &fc->base; + sde_fence_list_dump(fence, s); + } + spin_unlock(&ctx->list_lock); +} diff --git a/techpack/display/msm/sde/sde_fence.h b/techpack/display/msm/sde/sde_fence.h new file mode 100644 index 0000000000000000000000000000000000000000..10177eecbb623e1940c1894eff30a5db34076655 --- /dev/null +++ b/techpack/display/msm/sde/sde_fence.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_FENCE_H_ +#define _SDE_FENCE_H_ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/mutex.h> + +#ifndef CHAR_BIT +#define CHAR_BIT 8 /* define this if limits.h not available */ +#endif + +#define SDE_FENCE_NAME_SIZE 24 + +/** + * struct sde_fence_context - release/retire fence context/timeline structure + * @commit_count: Number of detected commits since bootup + * @done_count: Number of completed commits since bootup + * @drm_id: ID number of owning DRM Object + * @ref: kref counter on timeline + * @lock: spinlock for fence counter protection + * @list_lock: spinlock for timeline protection + * @context: fence context + * @list_head: fence list to hold all the fence created on this context + * @name: name of fence context/timeline + */ +struct sde_fence_context { + unsigned int commit_count; + unsigned int done_count; + uint32_t drm_id; + struct kref kref; + spinlock_t lock; + spinlock_t list_lock; + u64 context; + struct list_head fence_list_head; + char name[SDE_FENCE_NAME_SIZE]; +}; + +/** + * enum sde_fence_event - sde fence event as hint fence operation + * @SDE_FENCE_SIGNAL: Signal the fence cleanly with current timeline + * @SDE_FENCE_RESET_TIMELINE: Reset timeline of the fence context + * @SDE_FENCE_SIGNAL: Signal the fence but indicate error throughfence status + */ +enum sde_fence_event { + SDE_FENCE_SIGNAL, + SDE_FENCE_RESET_TIMELINE, + SDE_FENCE_SIGNAL_ERROR +}; + +#if IS_ENABLED(CONFIG_SYNC_FILE) +/** + * sde_sync_get - Query sync fence object from a file handle + * + * On success, this function also increments the refcount of the sync fence + * + * @fd: Integer sync fence handle + * + * Return: Pointer to sync fence object, or NULL + */ +void *sde_sync_get(uint64_t fd); + +/** + * sde_sync_put - Releases a sync fence object acquired by @sde_sync_get + * + * This function decrements the sync fence's reference count; the object will + * be released if the reference count goes to zero. + * + * @fence: Pointer to sync fence + */ +void sde_sync_put(void *fence); + +/** + * sde_sync_wait - Query sync fence object from a file handle + * + * @fence: Pointer to sync fence + * @timeout_ms: Time to wait, in milliseconds. Waits forever if timeout_ms < 0 + * + * Return: + * Zero if timed out + * -ERESTARTSYS if wait interrupted + * remaining jiffies in all other success cases. + */ +signed long sde_sync_wait(void *fence, long timeout_ms); + +/** + * sde_sync_get_name_prefix - get integer representation of fence name prefix + * @fence: Pointer to opaque fence structure + * + * Return: 32-bit integer containing first 4 characters of fence name, + * big-endian notation + */ +uint32_t sde_sync_get_name_prefix(void *fence); + +/** + * sde_fence_init - initialize fence object + * @drm_id: ID number of owning DRM Object + * @name: Timeline name + * Returns: fence context object on success + */ +struct sde_fence_context *sde_fence_init(const char *name, + uint32_t drm_id); + +/** + * sde_fence_deinit - deinit fence container + * @fence: Pointer fence container + */ +void sde_fence_deinit(struct sde_fence_context *fence); + +/** + * sde_fence_prepare - prepare to return fences for current commit + * @fence: Pointer fence container + * Returns: Zero on success + */ +void sde_fence_prepare(struct sde_fence_context *fence); +/** + * sde_fence_create - create output fence object + * @fence: Pointer fence container + * @val: Pointer to output value variable, fence fd will be placed here + * @offset: Fence signal commit offset, e.g., +1 to signal on next commit + * Returns: Zero on success + */ +int sde_fence_create(struct sde_fence_context *fence, uint64_t *val, + uint32_t offset); + +/** + * sde_fence_signal - advance fence timeline to signal outstanding fences + * @fence: Pointer fence container + * @ts: fence timestamp + * @fence_event: fence event to indicate nature of fence signal. + */ +void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts, + enum sde_fence_event fence_event); + +/** + * sde_fence_timeline_status - prints fence timeline status + * @fence: Pointer fence container + * @drm_obj Pointer to drm object associated with fence timeline + */ +void sde_fence_timeline_status(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj); + +/** + * sde_fence_timeline_dump - utility to dump fence list info in debugfs node + * @fence: Pointer fence container + * @drm_obj: Pointer to drm object associated with fence timeline + * @s: used to writing on debugfs node + */ +void sde_debugfs_timeline_dump(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj, struct seq_file **s); + +/** + * sde_fence_timeline_status - dumps fence timeline in debugfs node + * @fence: Pointer fence container + * @s: used to writing on debugfs node + */ +void sde_fence_list_dump(struct dma_fence *fence, struct seq_file **s); + +#else +static inline void *sde_sync_get(uint64_t fd) +{ + return NULL; +} + +static inline void sde_sync_put(void *fence) +{ +} + +static inline signed long sde_sync_wait(void *fence, long timeout_ms) +{ + return 0; +} + +static inline uint32_t sde_sync_get_name_prefix(void *fence) +{ + return 0x0; +} + +static inline struct sde_fence_context *sde_fence_init(const char *name, + uint32_t drm_id) +{ + /* do nothing */ + return NULL; +} + +static inline void sde_fence_deinit(struct sde_fence_context *fence) +{ + /* do nothing */ +} + +static inline int sde_fence_get(struct sde_fence_context *fence, uint64_t *val) +{ + return -EINVAL; +} + +static inline void sde_fence_signal(struct sde_fence_context *fence, + ktime_t ts, bool reset_timeline) +{ + /* do nothing */ +} + +static inline void sde_fence_prepare(struct sde_fence_context *fence) +{ + /* do nothing */ +} + +static inline int sde_fence_create(struct sde_fence_context *fence, + uint64_t *val, uint32_t offset) +{ + return 0; +} + +static inline void sde_fence_timeline_status(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj); +{ + /* do nothing */ +} + +void sde_debugfs_timeline_dump(struct sde_fence_context *ctx, + struct drm_mode_object *drm_obj, struct seq_file **s) +{ + /* do nothing */ +} + +void sde_fence_list_dump(struct dma_fence *fence, struct seq_file **s) +{ + /* do nothing */ +} + +#endif /* IS_ENABLED(CONFIG_SW_SYNC) */ + +#endif /* _SDE_FENCE_H_ */ diff --git a/techpack/display/msm/sde/sde_formats.c b/techpack/display/msm/sde/sde_formats.c new file mode 100644 index 0000000000000000000000000000000000000000..19206f4a227af4d0b9d88d65208e65b3571c7308 --- /dev/null +++ b/techpack/display/msm/sde/sde_formats.c @@ -0,0 +1,1382 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <uapi/drm/drm_fourcc.h> +#include <uapi/media/msm_media_info.h> + +#include "sde_kms.h" +#include "sde_formats.h" + +#define SDE_UBWC_META_MACRO_W_H 16 +#define SDE_UBWC_META_BLOCK_SIZE 256 +#define SDE_UBWC_PLANE_SIZE_ALIGNMENT 4096 + +#define SDE_TILE_HEIGHT_DEFAULT 1 +#define SDE_TILE_HEIGHT_TILED 4 +#define SDE_TILE_HEIGHT_UBWC 4 +#define SDE_TILE_HEIGHT_NV12 8 + +#define SDE_MAX_IMG_WIDTH 0x3FFF +#define SDE_MAX_IMG_HEIGHT 0x3FFF + +/** + * SDE supported format packing, bpp, and other format + * information. + * SDE currently only supports interleaved RGB formats + * UBWC support for a pixel format is indicated by the flag, + * there is additional meta data plane for such formats + */ + +#define INTERLEAVED_RGB_FMT(fmt, a, r, g, b, e0, e1, e2, e3, uc, alpha, \ +bp, flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_INTERLEAVED, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = SDE_CHROMA_RGB, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = uc, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = SDE_TILE_HEIGHT_DEFAULT \ +} + +#define INTERLEAVED_RGB_FMT_TILED(fmt, a, r, g, b, e0, e1, e2, e3, uc, \ +alpha, bp, flg, fm, np, th) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_INTERLEAVED, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = SDE_CHROMA_RGB, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = uc, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = th \ +} + + +#define INTERLEAVED_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, e3, \ +alpha, chroma, count, bp, flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_INTERLEAVED, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), (e3)}, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = count, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = SDE_TILE_HEIGHT_DEFAULT \ +} + +#define PSEUDO_YUV_FMT(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = SDE_TILE_HEIGHT_DEFAULT \ +} + +#define PSEUDO_YUV_FMT_TILED(fmt, a, r, g, b, e0, e1, chroma, \ +flg, fm, np, th) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = th \ +} + +#define PSEUDO_YUV_FMT_LOOSE(fmt, a, r, g, b, e0, e1, chroma, flg, fm, np)\ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 1, \ + .unpack_tight = 0, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = SDE_TILE_HEIGHT_DEFAULT \ +} + +#define PSEUDO_YUV_FMT_LOOSE_TILED(fmt, a, r, g, b, e0, e1, chroma, \ +flg, fm, np, th) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_PSEUDO_PLANAR, \ + .alpha_enable = false, \ + .element = { (e0), (e1), 0, 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 1, \ + .unpack_tight = 0, \ + .unpack_count = 2, \ + .bpp = 2, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = th \ +} + + +#define PLANAR_YUV_FMT(fmt, a, r, g, b, e0, e1, e2, alpha, chroma, bp, \ +flg, fm, np) \ +{ \ + .base.pixel_format = DRM_FORMAT_ ## fmt, \ + .fetch_planes = SDE_PLANE_PLANAR, \ + .alpha_enable = alpha, \ + .element = { (e0), (e1), (e2), 0 }, \ + .bits = { g, b, r, a }, \ + .chroma_sample = chroma, \ + .unpack_align_msb = 0, \ + .unpack_tight = 1, \ + .unpack_count = 1, \ + .bpp = bp, \ + .fetch_mode = fm, \ + .flag = {(flg)}, \ + .num_planes = np, \ + .tile_height = SDE_TILE_HEIGHT_DEFAULT \ +} + +/* + * struct sde_media_color_map - maps drm format to media format + * @format: DRM base pixel format + * @color: Media API color related to DRM format + */ +struct sde_media_color_map { + uint32_t format; + uint32_t color; +}; + +static const struct sde_format sde_format_map[] = { + INTERLEAVED_RGB_FMT(ARGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 4, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGB888, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, + false, 3, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGR888, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 3, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGB565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGR565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ARGB1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR1555, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX5551, + COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ARGB4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX4444, + COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 2, 0, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRA1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBA1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ABGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(ARGB2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XRGB2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(BGRX1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(XBGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + INTERLEAVED_RGB_FMT(RGBX1010102, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + false, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_LINEAR, 1), + + PSEUDO_YUV_FMT(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + PSEUDO_YUV_FMT(NV21, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + PSEUDO_YUV_FMT(NV16, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + PSEUDO_YUV_FMT(NV61, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + SDE_CHROMA_H2V1, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(VYUY, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y, + false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(UYVY, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C0_G_Y, + false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(YUYV, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C0_G_Y, C1_B_Cb, C0_G_Y, C2_R_Cr, + false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + INTERLEAVED_YUV_FMT(YVYU, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C0_G_Y, C2_R_Cr, C0_G_Y, C1_B_Cb, + false, SDE_CHROMA_H2V1, 4, 2, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 2), + + PLANAR_YUV_FMT(YUV420, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, C0_G_Y, + false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 3), + + PLANAR_YUV_FMT(YVU420, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, C0_G_Y, + false, SDE_CHROMA_420, 1, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_LINEAR, 3), +}; + +/* + * A5x tile formats tables: + * These tables hold the A5x tile formats supported. + */ +static const struct sde_format sde_format_map_tile[] = { + INTERLEAVED_RGB_FMT_TILED(BGR565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 2, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(ARGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + true, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4, + true, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(XBGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(RGBA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(BGRA8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + true, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(BGRX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4, + false, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(XRGB8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4, + false, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(RGBX8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, 0, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(ABGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + INTERLEAVED_RGB_FMT_TILED(XBGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_DX, + SDE_FETCH_UBWC, 1, SDE_TILE_HEIGHT_TILED), + + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12), + + PSEUDO_YUV_FMT_TILED(NV21, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C1_B_Cb, + SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12), +}; + +static const struct sde_format sde_format_map_p010_tile[] = { + PSEUDO_YUV_FMT_LOOSE_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX), + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12), +}; + +static const struct sde_format sde_format_map_tp10_tile[] = { + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX), + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_NV12), +}; + +/* + * UBWC formats table: + * This table holds the UBWC formats supported. + * If a compression ratio needs to be used for this or any other format, + * the data will be passed by user-space. + */ +static const struct sde_format sde_format_map_ubwc[] = { + INTERLEAVED_RGB_FMT_TILED(BGR565, + 0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3, + false, 2, SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(ABGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(XBGR8888, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + false, 4, SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(ABGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + + INTERLEAVED_RGB_FMT_TILED(XBGR2101010, + COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4, + true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 2, SDE_TILE_HEIGHT_UBWC), + + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, SDE_FORMAT_FLAG_YUV | + SDE_FORMAT_FLAG_COMPRESSED, + SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12), +}; + +static const struct sde_format sde_format_map_p010[] = { + PSEUDO_YUV_FMT_LOOSE(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX), + SDE_FETCH_LINEAR, 2), +}; + +static const struct sde_format sde_format_map_p010_ubwc[] = { + PSEUDO_YUV_FMT_LOOSE_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX | + SDE_FORMAT_FLAG_COMPRESSED), + SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12), +}; + +static const struct sde_format sde_format_map_tp10_ubwc[] = { + PSEUDO_YUV_FMT_TILED(NV12, + 0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, + C1_B_Cb, C2_R_Cr, + SDE_CHROMA_420, (SDE_FORMAT_FLAG_YUV | SDE_FORMAT_FLAG_DX | + SDE_FORMAT_FLAG_COMPRESSED), + SDE_FETCH_UBWC, 4, SDE_TILE_HEIGHT_NV12), +}; + +bool sde_format_is_tp10_ubwc(const struct sde_format *fmt) +{ + if (SDE_FORMAT_IS_YUV(fmt) && SDE_FORMAT_IS_DX(fmt) && + SDE_FORMAT_IS_UBWC(fmt) && + (fmt->num_planes == 4) && fmt->unpack_tight) + return true; + else + return false; +} + +/* _sde_get_v_h_subsample_rate - Get subsample rates for all formats we support + * Note: Not using the drm_format_*_subsampling since we have formats + */ +static void _sde_get_v_h_subsample_rate( + enum sde_chroma_samp_type chroma_sample, + uint32_t *v_sample, + uint32_t *h_sample) +{ + if (!v_sample || !h_sample) + return; + + switch (chroma_sample) { + case SDE_CHROMA_H2V1: + *v_sample = 1; + *h_sample = 2; + break; + case SDE_CHROMA_H1V2: + *v_sample = 2; + *h_sample = 1; + break; + case SDE_CHROMA_420: + *v_sample = 2; + *h_sample = 2; + break; + default: + *v_sample = 1; + *h_sample = 1; + break; + } +} + +static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt) +{ + static const struct sde_media_color_map sde_media_ubwc_map[] = { + {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC}, + {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC}, + {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC}, + }; + int color_fmt = -1; + int i; + + if (fmt->base.pixel_format == DRM_FORMAT_NV12) { + if (SDE_FORMAT_IS_DX(fmt)) { + if (fmt->unpack_tight) + color_fmt = COLOR_FMT_NV12_BPP10_UBWC; + else + color_fmt = COLOR_FMT_P010_UBWC; + } else + color_fmt = COLOR_FMT_NV12_UBWC; + return color_fmt; + } + + for (i = 0; i < ARRAY_SIZE(sde_media_ubwc_map); ++i) + if (fmt->base.pixel_format == sde_media_ubwc_map[i].format) { + color_fmt = sde_media_ubwc_map[i].color; + break; + } + return color_fmt; +} + +static int _sde_format_get_plane_sizes_ubwc( + const struct sde_format *fmt, + const uint32_t width, + const uint32_t height, + struct sde_hw_fmt_layout *layout) +{ + int i; + int color; + bool meta = SDE_FORMAT_IS_UBWC(fmt); + + memset(layout, 0, sizeof(struct sde_hw_fmt_layout)); + layout->format = fmt; + layout->width = width; + layout->height = height; + layout->num_planes = fmt->num_planes; + + color = _sde_format_get_media_color_ubwc(fmt); + if (color < 0) { + DRM_ERROR("UBWC format not supported for fmt: %4.4s\n", + (char *)&fmt->base.pixel_format); + return -EINVAL; + } + + if (SDE_FORMAT_IS_YUV(layout->format)) { + uint32_t y_sclines, uv_sclines; + uint32_t y_meta_scanlines = 0; + uint32_t uv_meta_scanlines = 0; + + layout->num_planes = 2; + layout->plane_pitch[0] = VENUS_Y_STRIDE(color, width); + y_sclines = VENUS_Y_SCANLINES(color, height); + layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + y_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[1] = VENUS_UV_STRIDE(color, width); + uv_sclines = VENUS_UV_SCANLINES(color, height); + layout->plane_size[1] = MSM_MEDIA_ALIGN(layout->plane_pitch[1] * + uv_sclines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + if (!meta) + goto done; + + layout->num_planes += 2; + layout->plane_pitch[2] = VENUS_Y_META_STRIDE(color, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color, height); + layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + y_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + layout->plane_pitch[3] = VENUS_UV_META_STRIDE(color, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color, height); + layout->plane_size[3] = MSM_MEDIA_ALIGN(layout->plane_pitch[3] * + uv_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + } else { + uint32_t rgb_scanlines, rgb_meta_scanlines; + + layout->num_planes = 1; + + layout->plane_pitch[0] = VENUS_RGB_STRIDE(color, width); + rgb_scanlines = VENUS_RGB_SCANLINES(color, height); + layout->plane_size[0] = MSM_MEDIA_ALIGN(layout->plane_pitch[0] * + rgb_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + + if (!meta) + goto done; + layout->num_planes += 2; + layout->plane_pitch[2] = VENUS_RGB_META_STRIDE(color, width); + rgb_meta_scanlines = VENUS_RGB_META_SCANLINES(color, height); + layout->plane_size[2] = MSM_MEDIA_ALIGN(layout->plane_pitch[2] * + rgb_meta_scanlines, SDE_UBWC_PLANE_SIZE_ALIGNMENT); + } + +done: + for (i = 0; i < SDE_MAX_PLANES; i++) + layout->total_size += layout->plane_size[i]; + + return 0; +} + +static int _sde_format_get_plane_sizes_linear( + const struct sde_format *fmt, + const uint32_t width, + const uint32_t height, + struct sde_hw_fmt_layout *layout, + const uint32_t *pitches) +{ + int i; + + memset(layout, 0, sizeof(struct sde_hw_fmt_layout)); + layout->format = fmt; + layout->width = width; + layout->height = height; + layout->num_planes = fmt->num_planes; + + /* Due to memset above, only need to set planes of interest */ + if (fmt->fetch_planes == SDE_PLANE_INTERLEAVED) { + layout->num_planes = 1; + layout->plane_size[0] = width * height * layout->format->bpp; + layout->plane_pitch[0] = width * layout->format->bpp; + } else { + uint32_t v_subsample, h_subsample; + uint32_t chroma_samp; + uint32_t bpp = 1; + + chroma_samp = fmt->chroma_sample; + _sde_get_v_h_subsample_rate(chroma_samp, &v_subsample, + &h_subsample); + + if (width % h_subsample || height % v_subsample) { + DRM_ERROR("mismatch in subsample vs dimensions\n"); + return -EINVAL; + } + + if ((fmt->base.pixel_format == DRM_FORMAT_NV12) && + (SDE_FORMAT_IS_DX(fmt))) + bpp = 2; + layout->plane_pitch[0] = width * bpp; + layout->plane_pitch[1] = layout->plane_pitch[0] / h_subsample; + layout->plane_size[0] = layout->plane_pitch[0] * height; + layout->plane_size[1] = layout->plane_pitch[1] * + (height / v_subsample); + + if (fmt->fetch_planes == SDE_PLANE_PSEUDO_PLANAR) { + layout->num_planes = 2; + layout->plane_size[1] *= 2; + layout->plane_pitch[1] *= 2; + } else { + /* planar */ + layout->num_planes = 3; + layout->plane_size[2] = layout->plane_size[1]; + layout->plane_pitch[2] = layout->plane_pitch[1]; + } + } + + /* + * linear format: allow user allocated pitches if they are greater than + * the requirement. + * ubwc format: pitch values are computed uniformly across + * all the components based on ubwc specifications. + */ + for (i = 0; i < layout->num_planes && i < SDE_MAX_PLANES; ++i) { + if (pitches && layout->plane_pitch[i] < pitches[i]) + layout->plane_pitch[i] = pitches[i]; + } + + for (i = 0; i < SDE_MAX_PLANES; i++) + layout->total_size += layout->plane_size[i]; + + return 0; +} + +int sde_format_get_plane_sizes( + const struct sde_format *fmt, + const uint32_t w, + const uint32_t h, + struct sde_hw_fmt_layout *layout, + const uint32_t *pitches) +{ + if (!layout || !fmt) { + DRM_ERROR("invalid pointer\n"); + return -EINVAL; + } + + if ((w > SDE_MAX_IMG_WIDTH) || (h > SDE_MAX_IMG_HEIGHT)) { + DRM_ERROR("image dimensions outside max range\n"); + return -ERANGE; + } + + if (SDE_FORMAT_IS_UBWC(fmt) || SDE_FORMAT_IS_TILE(fmt)) + return _sde_format_get_plane_sizes_ubwc(fmt, w, h, layout); + + return _sde_format_get_plane_sizes_linear(fmt, w, h, layout, pitches); +} + +int sde_format_get_block_size(const struct sde_format *fmt, + uint32_t *w, uint32_t *h) +{ + if (!fmt || !w || !h) { + DRM_ERROR("invalid pointer\n"); + return -EINVAL; + } + + /* TP10 is 96x96 and all others are 128x128 */ + if (SDE_FORMAT_IS_YUV(fmt) && SDE_FORMAT_IS_DX(fmt) && + (fmt->num_planes == 2) && fmt->unpack_tight) + *w = *h = 96; + else + *w = *h = 128; + + return 0; +} + +uint32_t sde_format_get_framebuffer_size( + const uint32_t format, + const uint32_t width, + const uint32_t height, + const uint32_t *pitches, + const uint64_t modifier) +{ + const struct sde_format *fmt; + struct sde_hw_fmt_layout layout; + + fmt = sde_get_sde_format_ext(format, modifier); + if (!fmt) + return 0; + + if (!pitches) + return -EINVAL; + + if (sde_format_get_plane_sizes(fmt, width, height, &layout, pitches)) + layout.total_size = 0; + + return layout.total_size; +} + +static int _sde_format_populate_addrs_ubwc( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct sde_hw_fmt_layout *layout) +{ + uint32_t base_addr; + bool meta; + + if (!fb || !layout) { + DRM_ERROR("invalid pointers\n"); + return -EINVAL; + } + + if (aspace) + base_addr = msm_framebuffer_iova(fb, aspace, 0); + else + base_addr = msm_framebuffer_phys(fb, 0); + if (!base_addr) { + DRM_ERROR("failed to retrieve base addr\n"); + return -EFAULT; + } + + meta = SDE_FORMAT_IS_UBWC(layout->format); + + /* Per-format logic for verifying active planes */ + if (SDE_FORMAT_IS_YUV(layout->format)) { + /************************************************/ + /* UBWC ** */ + /* buffer ** SDE PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | Y meta | ** | Y bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Y bitstream | ** | CbCr bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Cbcr metadata | ** | Y meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | CbCr bitstream | ** | CbCr meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /************************************************/ + + /* configure Y bitstream plane */ + layout->plane_addr[0] = base_addr + layout->plane_size[2]; + + /* configure CbCr bitstream plane */ + layout->plane_addr[1] = base_addr + layout->plane_size[0] + + layout->plane_size[2] + layout->plane_size[3]; + + if (!meta) + goto done; + + /* configure Y metadata plane */ + layout->plane_addr[2] = base_addr; + + /* configure CbCr metadata plane */ + layout->plane_addr[3] = base_addr + layout->plane_size[0] + + layout->plane_size[2]; + + } else { + /************************************************/ + /* UBWC ** */ + /* buffer ** SDE PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | RGB meta | ** | RGB bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | RGB bitstream | ** | NONE | */ + /* | data | ** | | */ + /* ------------------- ** -------------------- */ + /* ** | RGB meta | */ + /* ** | plane | */ + /* ** -------------------- */ + /************************************************/ + + layout->plane_addr[0] = base_addr + layout->plane_size[2]; + layout->plane_addr[1] = 0; + + if (!meta) + goto done; + + layout->plane_addr[2] = base_addr; + layout->plane_addr[3] = 0; + } +done: + return 0; +} + +static int _sde_format_populate_addrs_linear( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct sde_hw_fmt_layout *layout) +{ + unsigned int i; + + /* Can now check the pitches given vs pitches expected */ + for (i = 0; i < layout->num_planes; ++i) { + if (layout->plane_pitch[i] > fb->pitches[i]) { + DRM_ERROR("plane %u expected pitch %u, fb %u\n", + i, layout->plane_pitch[i], fb->pitches[i]); + return -EINVAL; + } + } + + /* Populate addresses for simple formats here */ + for (i = 0; i < layout->num_planes; ++i) { + if (aspace) + layout->plane_addr[i] = + msm_framebuffer_iova(fb, aspace, i); + else + layout->plane_addr[i] = msm_framebuffer_phys(fb, i); + if (!layout->plane_addr[i]) { + DRM_ERROR("failed to retrieve base addr\n"); + return -EFAULT; + } + } + + return 0; +} + +int sde_format_populate_layout( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct sde_hw_fmt_layout *layout) +{ + uint32_t plane_addr[SDE_MAX_PLANES]; + int i, ret; + + if (!fb || !layout) { + DRM_ERROR("invalid arguments\n"); + return -EINVAL; + } + + if ((fb->width > SDE_MAX_IMG_WIDTH) || + (fb->height > SDE_MAX_IMG_HEIGHT)) { + DRM_ERROR("image dimensions outside max range\n"); + return -ERANGE; + } + + layout->format = to_sde_format(msm_framebuffer_format(fb)); + + /* Populate the plane sizes etc via get_format */ + ret = sde_format_get_plane_sizes(layout->format, fb->width, fb->height, + layout, fb->pitches); + if (ret) + return ret; + + for (i = 0; i < SDE_MAX_PLANES; ++i) + plane_addr[i] = layout->plane_addr[i]; + + /* Populate the addresses given the fb */ + if (SDE_FORMAT_IS_UBWC(layout->format) || + SDE_FORMAT_IS_TILE(layout->format)) + ret = _sde_format_populate_addrs_ubwc(aspace, fb, layout); + else + ret = _sde_format_populate_addrs_linear(aspace, fb, layout); + + /* check if anything changed */ + if (!ret && !memcmp(plane_addr, layout->plane_addr, sizeof(plane_addr))) + ret = -EAGAIN; + + return ret; +} + +static void _sde_format_calc_offset_linear(struct sde_hw_fmt_layout *source, + u32 x, u32 y) +{ + if ((x == 0) && (y == 0)) + return; + + source->plane_addr[0] += y * source->plane_pitch[0]; + + if (source->num_planes == 1) { + source->plane_addr[0] += x * source->format->bpp; + } else { + uint32_t xoff, yoff; + uint32_t v_subsample = 1; + uint32_t h_subsample = 1; + + _sde_get_v_h_subsample_rate(source->format->chroma_sample, + &v_subsample, &h_subsample); + + xoff = x / h_subsample; + yoff = y / v_subsample; + + source->plane_addr[0] += x; + source->plane_addr[1] += xoff + + (yoff * source->plane_pitch[1]); + if (source->num_planes == 2) /* pseudo planar */ + source->plane_addr[1] += xoff; + else /* planar */ + source->plane_addr[2] += xoff + + (yoff * source->plane_pitch[2]); + } +} + +int sde_format_populate_layout_with_roi( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct sde_rect *roi, + struct sde_hw_fmt_layout *layout) +{ + int ret; + + ret = sde_format_populate_layout(aspace, fb, layout); + if (ret || !roi) + return ret; + + if (!roi->w || !roi->h || (roi->x + roi->w > fb->width) || + (roi->y + roi->h > fb->height)) { + DRM_ERROR("invalid roi=[%d,%d,%d,%d], fb=[%u,%u]\n", + roi->x, roi->y, roi->w, roi->h, + fb->width, fb->height); + ret = -EINVAL; + } else if (SDE_FORMAT_IS_LINEAR(layout->format)) { + _sde_format_calc_offset_linear(layout, roi->x, roi->y); + layout->width = roi->w; + layout->height = roi->h; + } else if (roi->x || roi->y || (roi->w != fb->width) || + (roi->h != fb->height)) { + DRM_ERROR("non-linear layout with roi not supported\n"); + ret = -EINVAL; + } + + return ret; +} + +int sde_format_check_modified_format( + const struct msm_kms *kms, + const struct msm_format *msm_fmt, + const struct drm_mode_fb_cmd2 *cmd, + struct drm_gem_object **bos) +{ + int ret, i, num_base_fmt_planes; + const struct sde_format *fmt; + struct sde_hw_fmt_layout layout; + uint32_t bos_total_size = 0; + + if (!msm_fmt || !cmd || !bos) { + DRM_ERROR("invalid arguments\n"); + return -EINVAL; + } + + fmt = to_sde_format(msm_fmt); + num_base_fmt_planes = drm_format_num_planes(fmt->base.pixel_format); + + ret = sde_format_get_plane_sizes(fmt, cmd->width, cmd->height, + &layout, cmd->pitches); + if (ret) + return ret; + + for (i = 0; i < num_base_fmt_planes; i++) { + if (!bos[i]) { + DRM_ERROR("invalid handle for plane %d\n", i); + return -EINVAL; + } + if ((i == 0) || (bos[i] != bos[0])) + bos_total_size += bos[i]->size; + } + + if (bos_total_size < layout.total_size) { + DRM_ERROR("buffers total size too small %u expected %u\n", + bos_total_size, layout.total_size); + return -EINVAL; + } + + return 0; +} + +const struct sde_format *sde_get_sde_format_ext( + const uint32_t format, + const uint64_t modifier) +{ + uint32_t i = 0; + const struct sde_format *fmt = NULL; + const struct sde_format *map = NULL; + ssize_t map_size = 0; + + /* + * Currently only support exactly zero or one modifier. + * All planes use the same modifier. + */ + SDE_DEBUG("plane format modifier 0x%llX\n", modifier); + + switch (modifier) { + case 0: + map = sde_format_map; + map_size = ARRAY_SIZE(sde_format_map); + break; + case DRM_FORMAT_MOD_QCOM_COMPRESSED: + case DRM_FORMAT_MOD_QCOM_COMPRESSED | DRM_FORMAT_MOD_QCOM_TILE: + map = sde_format_map_ubwc; + map_size = ARRAY_SIZE(sde_format_map_ubwc); + SDE_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED\n", + (char *)&format); + break; + case DRM_FORMAT_MOD_QCOM_DX: + map = sde_format_map_p010; + map_size = ARRAY_SIZE(sde_format_map_p010); + SDE_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_DX\n", + (char *)&format); + break; + case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED): + case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_TILE): + map = sde_format_map_p010_ubwc; + map_size = ARRAY_SIZE(sde_format_map_p010_ubwc); + SDE_DEBUG( + "found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED/DX\n", + (char *)&format); + break; + case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_TIGHT): + case (DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_COMPRESSED | + DRM_FORMAT_MOD_QCOM_TIGHT | DRM_FORMAT_MOD_QCOM_TILE): + map = sde_format_map_tp10_ubwc; + map_size = ARRAY_SIZE(sde_format_map_tp10_ubwc); + SDE_DEBUG( + "found fmt: %4.4s DRM_FORMAT_MOD_QCOM_COMPRESSED/DX/TIGHT\n", + (char *)&format); + break; + case DRM_FORMAT_MOD_QCOM_TILE: + map = sde_format_map_tile; + map_size = ARRAY_SIZE(sde_format_map_tile); + SDE_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_TILE\n", + (char *)&format); + break; + case (DRM_FORMAT_MOD_QCOM_TILE | DRM_FORMAT_MOD_QCOM_DX): + map = sde_format_map_p010_tile; + map_size = ARRAY_SIZE(sde_format_map_p010_tile); + SDE_DEBUG("found fmt: %4.4s DRM_FORMAT_MOD_QCOM_TILE/DX\n", + (char *)&format); + break; + case (DRM_FORMAT_MOD_QCOM_TILE | DRM_FORMAT_MOD_QCOM_DX | + DRM_FORMAT_MOD_QCOM_TIGHT): + map = sde_format_map_tp10_tile; + map_size = ARRAY_SIZE(sde_format_map_tp10_tile); + SDE_DEBUG( + "found fmt: %4.4s DRM_FORMAT_MOD_QCOM_TILE/DX/TIGHT\n", + (char *)&format); + break; + default: + SDE_ERROR("unsupported format modifier %llX\n", modifier); + return NULL; + } + + for (i = 0; i < map_size; i++) { + if (format == map[i].base.pixel_format) { + fmt = &map[i]; + break; + } + } + + if (fmt == NULL) + SDE_ERROR("unsupported fmt: %4.4s modifier 0x%llX\n", + (char *)&format, modifier); + else + SDE_DEBUG("fmt %4.4s mod 0x%llX ubwc %d yuv %d\n", + (char *)&format, modifier, + SDE_FORMAT_IS_UBWC(fmt), + SDE_FORMAT_IS_YUV(fmt)); + + return fmt; +} + +const struct msm_format *sde_get_msm_format( + struct msm_kms *kms, + const uint32_t format, + const uint64_t modifier) +{ + const struct sde_format *fmt = sde_get_sde_format_ext(format, + modifier); + if (fmt) + return &fmt->base; + return NULL; +} + +uint32_t sde_populate_formats( + const struct sde_format_extended *format_list, + uint32_t *pixel_formats, + uint64_t *pixel_modifiers, + uint32_t pixel_formats_max) +{ + uint32_t i, fourcc_format; + + if (!format_list || !pixel_formats) + return 0; + + for (i = 0, fourcc_format = 0; + format_list->fourcc_format && i < pixel_formats_max; + ++format_list) { + /* verify if listed format is in sde_format_map? */ + + /* optionally return modified formats */ + if (pixel_modifiers) { + /* assume same modifier for all fb planes */ + pixel_formats[i] = format_list->fourcc_format; + pixel_modifiers[i++] = format_list->modifier; + } else { + /* assume base formats grouped together */ + if (fourcc_format != format_list->fourcc_format) { + fourcc_format = format_list->fourcc_format; + pixel_formats[i++] = fourcc_format; + } + } + } + + return i; +} + +int sde_format_validate_fmt(struct msm_kms *kms, + const struct sde_format *sde_fmt, + const struct sde_format_extended *fmt_list) +{ + const struct sde_format *fmt_tmp; + bool valid_format = false; + int ret = 0; + + if (!sde_fmt || !fmt_list) { + SDE_ERROR("invalid fmt:%d list:%d\n", + !sde_fmt, !fmt_list); + ret = -EINVAL; + goto exit; + } + + while (fmt_list->fourcc_format) { + fmt_tmp = sde_get_sde_format_ext(fmt_list->fourcc_format, + fmt_list->modifier); + if (fmt_tmp + && (fmt_tmp->base.pixel_format == sde_fmt->base.pixel_format) + && (fmt_tmp->fetch_mode == sde_fmt->fetch_mode)) { + valid_format = true; + break; + } + ++fmt_list; + } + + if (!valid_format) { + SDE_ERROR("fmt:%d mode:%d not found within the list!\n", + sde_fmt->base.pixel_format, sde_fmt->fetch_mode); + ret = -EINVAL; + } +exit: + return ret; +} diff --git a/techpack/display/msm/sde/sde_formats.h b/techpack/display/msm/sde/sde_formats.h new file mode 100644 index 0000000000000000000000000000000000000000..3c47172b87657266b5b8b8ba3c020dc533d894a6 --- /dev/null +++ b/techpack/display/msm/sde/sde_formats.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_FORMATS_H +#define _SDE_FORMATS_H + +#include <drm/drm_fourcc.h> +#include "msm_gem.h" +#include "sde_hw_mdss.h" + +/** + * sde_get_sde_format_ext() - Returns sde format structure pointer. + * @format: DRM FourCC Code + * @modifier: format modifier from client + */ +const struct sde_format *sde_get_sde_format_ext( + const uint32_t format, + const uint64_t modifier); + +#define sde_get_sde_format(f) sde_get_sde_format_ext(f, 0) + +/** + * sde_get_msm_format - get an sde_format by its msm_format base + * callback function registers with the msm_kms layer + * @kms: kms driver + * @format: DRM FourCC Code + * @modifier: data layout modifier + */ +const struct msm_format *sde_get_msm_format( + struct msm_kms *kms, + const uint32_t format, + const uint64_t modifier); + +/** + * sde_populate_formats - populate the given array with fourcc codes supported + * @format_list: pointer to list of possible formats + * @pixel_formats: array to populate with fourcc codes + * @pixel_modifiers: array to populate with drm modifiers, can be NULL + * @pixel_formats_max: length of pixel formats array + * Return: number of elements populated + */ +uint32_t sde_populate_formats( + const struct sde_format_extended *format_list, + uint32_t *pixel_formats, + uint64_t *pixel_modifiers, + uint32_t pixel_formats_max); + +/** + * sde_format_get_plane_sizes - calculate size and layout of given buffer format + * @fmt: pointer to sde_format + * @w: width of the buffer + * @h: height of the buffer + * @layout: layout of the buffer + * @pitches: array of size [SDE_MAX_PLANES] to populate + * pitch for each plane + * + * Return: size of the buffer + */ +int sde_format_get_plane_sizes( + const struct sde_format *fmt, + const uint32_t w, + const uint32_t h, + struct sde_hw_fmt_layout *layout, + const uint32_t *pitches); + +/** + * sde_format_get_block_size - get block size of given format when + * operating in block mode + * @fmt: pointer to sde_format + * @w: pointer to width of the block + * @h: pointer to height of the block + * + * Return: 0 if success; error oode otherwise + */ +int sde_format_get_block_size(const struct sde_format *fmt, + uint32_t *w, uint32_t *h); + +/** + * sde_format_check_modified_format - validate format and buffers for + * sde non-standard, i.e. modified format + * @kms: kms driver + * @msm_fmt: pointer to the msm_fmt base pointer of an sde_format + * @cmd: fb_cmd2 structure user request + * @bos: gem buffer object list + * + * Return: error code on failure, 0 on success + */ +int sde_format_check_modified_format( + const struct msm_kms *kms, + const struct msm_format *msm_fmt, + const struct drm_mode_fb_cmd2 *cmd, + struct drm_gem_object **bos); + +/** + * sde_format_populate_layout - populate the given format layout based on + * mmu, fb, and format found in the fb + * @aspace: address space pointer + * @fb: framebuffer pointer + * @fmtl: format layout structure to populate + * + * Return: error code on failure, -EAGAIN if success but the addresses + * are the same as before or 0 if new addresses were populated + */ +int sde_format_populate_layout( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct sde_hw_fmt_layout *fmtl); + +/** + * sde_format_populate_layout_with_roi - populate the given format layout + * based on mmu, fb, roi, and format found in the fb + * @aspace: address space pointer + * @fb: framebuffer pointer + * @roi: region of interest (optional) + * @fmtl: format layout structure to populate + * + * Return: error code on failure, 0 on success + */ +int sde_format_populate_layout_with_roi( + struct msm_gem_address_space *aspace, + struct drm_framebuffer *fb, + struct sde_rect *roi, + struct sde_hw_fmt_layout *fmtl); + +/** + * sde_format_get_framebuffer_size - get framebuffer memory size + * @format: DRM pixel format + * @width: pixel width + * @height: pixel height + * @pitches: array of size [SDE_MAX_PLANES] to populate + * pitch for each plane + * @modifier: drm modifier + * + * Return: memory size required for frame buffer + */ +uint32_t sde_format_get_framebuffer_size( + const uint32_t format, + const uint32_t width, + const uint32_t height, + const uint32_t *pitches, + const uint64_t modifier); + +/** + * sde_format_is_tp10_ubwc - check if the format is tp10 ubwc + * @format: DRM pixel format + * + * Return: returns true if the format is tp10 ubwc, otherwise false. + */ +bool sde_format_is_tp10_ubwc(const struct sde_format *fmt); + +/** + * sde_format_validate_fmt - validates if the format "sde_fmt" is within + * the list "fmt_list" + * @kms: pointer to the kms object + * @sde_fmt: pointer to the format to look within the list + * @fmt_list: list where driver will loop to look for the 'sde_fmt' format. + * @result: returns 0 if the format is found, otherwise will return an + * error code. + */ +int sde_format_validate_fmt(struct msm_kms *kms, + const struct sde_format *sde_fmt, + const struct sde_format_extended *fmt_list); + +#endif /*_SDE_FORMATS_H */ diff --git a/techpack/display/msm/sde/sde_hw_ad4.c b/techpack/display/msm/sde/sde_hw_ad4.c new file mode 100644 index 0000000000000000000000000000000000000000..4a2b73f1ee10745aa211a0bbd801b9ad7e3b87de --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_ad4.c @@ -0,0 +1,1771 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#include <drm/msm_drm_pp.h> +#include "sde_hw_catalog.h" +#include "sde_hw_util.h" +#include "sde_hw_mdss.h" +#include "sde_hw_lm.h" +#include "sde_ad4.h" + +#define AD_STATE_READY(x) \ + (((x) & ad4_init) && \ + ((x) & ad4_cfg) && \ + ((x) & ad4_mode) && \ + (((x) & ad4_input) | ((x) & ad4_strength))) + +#define MERGE_WIDTH_RIGHT 6 +#define MERGE_WIDTH_LEFT 5 +#define AD_IPC_FRAME_COUNT 2 + +enum ad4_ops_bitmask { + ad4_init = BIT(AD_INIT), + ad4_cfg = BIT(AD_CFG), + ad4_mode = BIT(AD_MODE), + ad4_input = BIT(AD_INPUT), + ad4_strength = BIT(AD_STRENGTH), + ad4_ops_max = BIT(31), +}; + +enum ad4_state { + ad4_state_idle, + ad4_state_startup, + ad4_state_run, + /* idle power collapse suspend state */ + ad4_state_ipcs, + /* idle power collapse resume state */ + ad4_state_ipcr, + /* manual mode state */ + ad4_state_manual, + ad4_state_max, +}; + +struct ad4_roi_info { + u32 h_start; + u32 h_end; + u32 v_start; + u32 v_end; + u32 f_in; + u32 f_out; +}; + +typedef int (*ad4_prop_setup)(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *ad); + +static int ad4_params_check(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); + +static int ad4_no_op_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); +static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); +static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode); +static int ad4_mode_setup_common(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); +static int ad4_init_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_init_setup_run(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_init_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); +static int ad4_cfg_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_cfg_setup_run(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_cfg_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_input_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_roi_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); +static int ad4_roi_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_roi_coordinate_offset(struct sde_hw_cp_cfg *hw_cfg, + struct ad4_roi_info *output); +static int ad4_input_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_input_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_suspend_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_assertive_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_assertive_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_backlight_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_backlight_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_strength_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); + +static int ad4_ipc_suspend_setup_run(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_ipc_suspend_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_ipc_resume_setup_ipcs(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_ipc_reset_setup_startup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_ipc_reset_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); +static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); + +static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { + [ad4_state_idle][AD_MODE] = ad4_mode_setup_common, + [ad4_state_idle][AD_INIT] = ad4_init_setup_idle, + [ad4_state_idle][AD_CFG] = ad4_cfg_setup_idle, + [ad4_state_idle][AD_INPUT] = ad4_input_setup_idle, + [ad4_state_idle][AD_SUSPEND] = ad4_suspend_setup, + [ad4_state_idle][AD_ASSERTIVE] = ad4_assertive_setup, + [ad4_state_idle][AD_BACKLIGHT] = ad4_backlight_setup, + [ad4_state_idle][AD_STRENGTH] = ad4_strength_setup_idle, + [ad4_state_idle][AD_ROI] = ad4_roi_setup, + [ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup, + [ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup, + [ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup, + + [ad4_state_startup][AD_MODE] = ad4_mode_setup_common, + [ad4_state_startup][AD_INIT] = ad4_init_setup, + [ad4_state_startup][AD_CFG] = ad4_cfg_setup, + [ad4_state_startup][AD_INPUT] = ad4_input_setup, + [ad4_state_startup][AD_SUSPEND] = ad4_suspend_setup, + [ad4_state_startup][AD_ASSERTIVE] = ad4_assertive_setup, + [ad4_state_startup][AD_BACKLIGHT] = ad4_backlight_setup, + [ad4_state_startup][AD_IPC_SUSPEND] = ad4_no_op_setup, + [ad4_state_startup][AD_STRENGTH] = ad4_no_op_setup, + [ad4_state_startup][AD_ROI] = ad4_roi_setup, + [ad4_state_startup][AD_IPC_RESUME] = ad4_no_op_setup, + [ad4_state_startup][AD_IPC_RESET] = ad4_ipc_reset_setup_startup, + + [ad4_state_run][AD_MODE] = ad4_mode_setup_common, + [ad4_state_run][AD_INIT] = ad4_init_setup_run, + [ad4_state_run][AD_CFG] = ad4_cfg_setup_run, + [ad4_state_run][AD_INPUT] = ad4_input_setup, + [ad4_state_run][AD_SUSPEND] = ad4_suspend_setup, + [ad4_state_run][AD_ASSERTIVE] = ad4_assertive_setup, + [ad4_state_run][AD_BACKLIGHT] = ad4_backlight_setup, + [ad4_state_run][AD_STRENGTH] = ad4_no_op_setup, + [ad4_state_run][AD_ROI] = ad4_roi_setup, + [ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run, + [ad4_state_run][AD_IPC_RESUME] = ad4_no_op_setup, + [ad4_state_run][AD_IPC_RESET] = ad4_setup_debug, + + [ad4_state_ipcs][AD_MODE] = ad4_no_op_setup, + [ad4_state_ipcs][AD_INIT] = ad4_no_op_setup, + [ad4_state_ipcs][AD_CFG] = ad4_no_op_setup, + [ad4_state_ipcs][AD_INPUT] = ad4_no_op_setup, + [ad4_state_ipcs][AD_SUSPEND] = ad4_no_op_setup, + [ad4_state_ipcs][AD_ASSERTIVE] = ad4_no_op_setup, + [ad4_state_ipcs][AD_BACKLIGHT] = ad4_no_op_setup, + [ad4_state_ipcs][AD_STRENGTH] = ad4_no_op_setup, + [ad4_state_ipcs][AD_ROI] = ad4_no_op_setup, + [ad4_state_ipcs][AD_IPC_SUSPEND] = ad4_no_op_setup, + [ad4_state_ipcs][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcs, + [ad4_state_ipcs][AD_IPC_RESET] = ad4_no_op_setup, + + [ad4_state_ipcr][AD_MODE] = ad4_mode_setup_common, + [ad4_state_ipcr][AD_INIT] = ad4_init_setup_ipcr, + [ad4_state_ipcr][AD_CFG] = ad4_cfg_setup_ipcr, + [ad4_state_ipcr][AD_INPUT] = ad4_input_setup_ipcr, + [ad4_state_ipcr][AD_SUSPEND] = ad4_suspend_setup, + [ad4_state_ipcr][AD_ASSERTIVE] = ad4_assertive_setup_ipcr, + [ad4_state_ipcr][AD_BACKLIGHT] = ad4_backlight_setup_ipcr, + [ad4_state_ipcr][AD_STRENGTH] = ad4_no_op_setup, + [ad4_state_ipcr][AD_ROI] = ad4_roi_setup_ipcr, + [ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_ipcr, + [ad4_state_ipcr][AD_IPC_RESUME] = ad4_no_op_setup, + [ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr, + + [ad4_state_manual][AD_MODE] = ad4_mode_setup_common, + [ad4_state_manual][AD_INIT] = ad4_init_setup, + [ad4_state_manual][AD_CFG] = ad4_cfg_setup, + [ad4_state_manual][AD_INPUT] = ad4_no_op_setup, + [ad4_state_manual][AD_SUSPEND] = ad4_no_op_setup, + [ad4_state_manual][AD_ASSERTIVE] = ad4_no_op_setup, + [ad4_state_manual][AD_BACKLIGHT] = ad4_no_op_setup, + [ad4_state_manual][AD_STRENGTH] = ad4_strength_setup, + [ad4_state_manual][AD_ROI] = ad4_roi_setup, + [ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup, + [ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup, + [ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual, +}; + +struct ad4_info { + enum ad4_state state; + u32 completed_ops_mask; + bool ad4_support; + enum ad4_modes mode; + bool is_master; + u32 last_assertive; + u32 cached_assertive; + u32 last_str_inroi; + u32 last_str_outroi; + u64 last_als; + u64 cached_als; + u64 last_bl; + u64 cached_bl; + u32 frame_count; + u32 frmt_mode; + u32 irdx_control_0; + u32 tf_ctrl; + u32 vc_control_0; + struct ad4_roi_info last_roi_cfg; + struct ad4_roi_info cached_roi_cfg; +}; + +static struct ad4_info info[DSPP_MAX] = { + [DSPP_0] = {ad4_state_idle, 0, true, AD4_OFF, false, 0x80, 0x80}, + [DSPP_1] = {ad4_state_idle, 0, true, AD4_OFF, false, 0x80, 0x80}, + [DSPP_2] = {ad4_state_max, 0, false, AD4_OFF, false, 0x80, 0x80}, + [DSPP_3] = {ad4_state_max, 0, false, AD4_OFF, false, 0x80, 0x80}, +}; + +void sde_setup_dspp_ad4(struct sde_hw_dspp *dspp, void *ad_cfg) +{ + int ret = 0; + struct sde_ad_hw_cfg *cfg = ad_cfg; + + ret = ad4_params_check(dspp, ad_cfg); + if (ret) + return; + + ret = prop_set_func[info[dspp->idx].state][cfg->prop](dspp, ad_cfg); + if (ret) + DRM_ERROR("op failed %d ret %d\n", cfg->prop, ret); +} + +int sde_validate_dspp_ad4(struct sde_hw_dspp *dspp, u32 *prop) +{ + + if (!dspp || !prop) { + DRM_ERROR("invalid params dspp %pK prop %pK\n", dspp, prop); + return -EINVAL; + } + + if (*prop >= AD_PROPMAX) { + DRM_ERROR("invalid prop set %d\n", *prop); + return -EINVAL; + } + + if (dspp->idx >= DSPP_MAX || !info[dspp->idx].ad4_support) { + DRM_ERROR("ad4 not supported for dspp idx %d\n", dspp->idx); + return -EINVAL; + } + + return 0; +} + +static int ad4_params_check(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + struct sde_hw_mixer *hw_lm; + + if (!dspp || !cfg || !cfg->hw_cfg) { + DRM_ERROR("invalid dspp %pK cfg %pK hw_cfg %pK\n", + dspp, cfg, ((cfg) ? (cfg->hw_cfg) : NULL)); + return -EINVAL; + } + + if (!cfg->hw_cfg->mixer_info) { + DRM_ERROR("invalid mixed info\n"); + return -EINVAL; + } + + if (dspp->idx >= DSPP_MAX || !info[dspp->idx].ad4_support) { + DRM_ERROR("ad4 not supported for dspp idx %d\n", dspp->idx); + return -EINVAL; + } + + if (cfg->prop >= AD_PROPMAX) { + DRM_ERROR("invalid prop set %d\n", cfg->prop); + return -EINVAL; + } + + if (info[dspp->idx].state >= ad4_state_max) { + DRM_ERROR("in max state for dspp idx %d\n", dspp->idx); + return -EINVAL; + } + + if (!prop_set_func[info[dspp->idx].state][cfg->prop]) { + DRM_ERROR("prop set not implemented for state %d prop %d\n", + info[dspp->idx].state, cfg->prop); + return -EINVAL; + } + + if (!cfg->hw_cfg->num_of_mixers || + cfg->hw_cfg->num_of_mixers > CRTC_DUAL_MIXERS) { + DRM_ERROR("invalid mixer cnt %d\n", + cfg->hw_cfg->num_of_mixers); + return -EINVAL; + } + hw_lm = cfg->hw_cfg->mixer_info; + if (!hw_lm) { + DRM_ERROR("invalid mixer info\n"); + return -EINVAL; + } + + if (cfg->hw_cfg->num_of_mixers == 1 && + hw_lm->cfg.out_height != cfg->hw_cfg->displayv && + hw_lm->cfg.out_width != cfg->hw_cfg->displayh) { + DRM_ERROR("single_lm lmh %d lmw %d displayh %d displayw %d\n", + hw_lm->cfg.out_height, hw_lm->cfg.out_width, + cfg->hw_cfg->displayh, cfg->hw_cfg->displayv); + return -EINVAL; + } else if (hw_lm->cfg.out_height != cfg->hw_cfg->displayv && + hw_lm->cfg.out_width != (cfg->hw_cfg->displayh >> 1)) { + DRM_ERROR("dual_lm lmh %d lmw %d displayh %d displayw %d\n", + hw_lm->cfg.out_height, hw_lm->cfg.out_width, + cfg->hw_cfg->displayh, cfg->hw_cfg->displayv); + return -EINVAL; + } + + return 0; +} + +static int ad4_no_op_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) +{ + return 0; +} + +static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) +{ + u32 in_str = 0, out_str = 0; + struct sde_hw_mixer *hw_lm; + + hw_lm = cfg->hw_cfg->mixer_info; + if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) + /* this AD core is the salve core */ + return 0; + + in_str = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x4c); + out_str = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x50); + pr_debug("%s(): AD in strength %d, out strength %d\n", __func__, + in_str, out_str); + return 0; +} + +static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u32 in_str = 0, out_str = 0; + struct sde_hw_mixer *hw_lm; + + hw_lm = cfg->hw_cfg->mixer_info; + if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) + /* this AD core is the salve core */ + return 0; + + in_str = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x15c); + out_str = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x160); + pr_debug("%s(): AD in strength = %d, out strength = %d in manual mode\n", + __func__, in_str, out_str); + + return 0; +} + +static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode) +{ + u32 blk_offset; + + if (mode == AD4_OFF) { + blk_offset = 0x04; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + 0x101); + info[dspp->idx].state = ad4_state_idle; + pr_debug("%s(): AD state move to idle\n", __func__); + info[dspp->idx].completed_ops_mask = 0; + /* reset last values to register default */ + info[dspp->idx].last_assertive = 0x80; + info[dspp->idx].cached_assertive = U8_MAX; + info[dspp->idx].last_bl = 0xFFFF; + info[dspp->idx].cached_bl = U64_MAX; + info[dspp->idx].last_als = 0x0; + info[dspp->idx].cached_als = U64_MAX; + info[dspp->idx].last_roi_cfg.h_start = 0x0; + info[dspp->idx].last_roi_cfg.h_end = 0xffff; + info[dspp->idx].last_roi_cfg.v_start = 0x0; + info[dspp->idx].last_roi_cfg.v_end = 0xffff; + info[dspp->idx].last_roi_cfg.f_in = 0x400; + info[dspp->idx].last_roi_cfg.f_out = 0x400; + info[dspp->idx].cached_roi_cfg.h_start = U32_MAX; + info[dspp->idx].cached_roi_cfg.h_end = U32_MAX; + info[dspp->idx].cached_roi_cfg.v_start = U32_MAX; + info[dspp->idx].cached_roi_cfg.v_end = U32_MAX; + info[dspp->idx].cached_roi_cfg.f_in = U32_MAX; + info[dspp->idx].cached_roi_cfg.f_out = U32_MAX; + } else { + if (mode == AD4_MANUAL) { + /*vc_control_0 */ + blk_offset = 0x138; + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + blk_offset, 0); + /* irdx_control_0 */ + blk_offset = 0x13c; + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].irdx_control_0); + } + if (info[dspp->idx].state == ad4_state_idle) { + if (mode == AD4_MANUAL) { + info[dspp->idx].state = ad4_state_manual; + pr_debug("%s(): AD state move to manual\n", + __func__); + } else { + info[dspp->idx].frame_count = 0; + info[dspp->idx].state = ad4_state_startup; + pr_debug("%s(): AD state move to startup\n", + __func__); + } + } + blk_offset = 0x04; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + 0x100); + } + + return 0; +} + +static int ad4_init_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) +{ + u32 frame_start, frame_end, proc_start, proc_end; + struct sde_hw_mixer *hw_lm; + u32 blk_offset, tile_ctl, val, i; + u32 off1, off2, off3, off4, off5, off6; + struct drm_msm_ad4_init *init; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_init; + return 0; + } + + if (cfg->hw_cfg->len != sizeof(struct drm_msm_ad4_init)) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(struct drm_msm_ad4_init), cfg->hw_cfg->len, + cfg->hw_cfg->payload); + return -EINVAL; + } + + hw_lm = cfg->hw_cfg->mixer_info; + if (cfg->hw_cfg->num_of_mixers == 1) { + frame_start = 0; + frame_end = 0xffff; + proc_start = 0; + proc_end = 0xffff; + tile_ctl = 0; + info[dspp->idx].is_master = true; + } else { + tile_ctl = 0x5; + if (hw_lm->cfg.right_mixer) { + frame_start = (cfg->hw_cfg->displayh >> 1) - + MERGE_WIDTH_RIGHT; + frame_end = cfg->hw_cfg->displayh - 1; + proc_start = (cfg->hw_cfg->displayh >> 1); + proc_end = frame_end; + tile_ctl |= 0x10; + info[dspp->idx].is_master = false; + } else { + frame_start = 0; + frame_end = (cfg->hw_cfg->displayh >> 1) + + MERGE_WIDTH_LEFT; + proc_start = 0; + proc_end = (cfg->hw_cfg->displayh >> 1) - 1; + tile_ctl |= 0x10; + info[dspp->idx].is_master = true; + } + } + + init = cfg->hw_cfg->payload; + + info[dspp->idx].frmt_mode = (init->init_param_009 & (BIT(14) - 1)); + + blk_offset = 0xc; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + init->init_param_010); + + init->init_param_012 = cfg->hw_cfg->displayv & (BIT(17) - 1); + init->init_param_011 = cfg->hw_cfg->displayh & (BIT(17) - 1); + blk_offset = 0x10; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + ((init->init_param_011 << 16) | init->init_param_012)); + + blk_offset = 0x14; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + tile_ctl); + + blk_offset = 0x44; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + ((((init->init_param_013) & (BIT(17) - 1)) << 16) | + (init->init_param_014 & (BIT(17) - 1)))); + + blk_offset = 0x5c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_015 & (BIT(16) - 1))); + blk_offset = 0x60; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_016 & (BIT(8) - 1))); + blk_offset = 0x64; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_017 & (BIT(12) - 1))); + blk_offset = 0x68; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_018 & (BIT(12) - 1))); + blk_offset = 0x6c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_019 & (BIT(12) - 1))); + blk_offset = 0x70; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_020 & (BIT(16) - 1))); + blk_offset = 0x74; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_021 & (BIT(8) - 1))); + blk_offset = 0x78; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_022 & (BIT(8) - 1))); + blk_offset = 0x7c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_023 & (BIT(16) - 1))); + blk_offset = 0x80; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_024 & (BIT(16) - 1)) << 16) | + ((init->init_param_025 & (BIT(16) - 1))))); + blk_offset = 0x84; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_026 & (BIT(16) - 1)) << 16) | + ((init->init_param_027 & (BIT(16) - 1))))); + + blk_offset = 0x90; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_028 & (BIT(16) - 1))); + blk_offset = 0x94; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_029 & (BIT(16) - 1))); + + blk_offset = 0x98; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_035 & (BIT(16) - 1)) << 16) | + ((init->init_param_030 & (BIT(16) - 1))))); + + blk_offset = 0x9c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_032 & (BIT(16) - 1)) << 16) | + ((init->init_param_031 & (BIT(16) - 1))))); + blk_offset = 0xa0; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_034 & (BIT(16) - 1)) << 16) | + ((init->init_param_033 & (BIT(16) - 1))))); + + blk_offset = 0xb4; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_036 & (BIT(8) - 1))); + blk_offset = 0xcc; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_037 & (BIT(8) - 1))); + blk_offset = 0xc0; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_038 & (BIT(8) - 1))); + blk_offset = 0xd8; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_039 & (BIT(8) - 1))); + + blk_offset = 0xe8; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_040 & (BIT(16) - 1))); + + blk_offset = 0xf4; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_041 & (BIT(8) - 1))); + + blk_offset = 0x100; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_042 & (BIT(16) - 1))); + + blk_offset = 0x10c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_043 & (BIT(8) - 1))); + + blk_offset = 0x120; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_044 & (BIT(16) - 1))); + blk_offset = 0x124; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_045 & (BIT(16) - 1))); + + blk_offset = 0x128; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_046 & (BIT(1) - 1))); + blk_offset = 0x12c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_047 & (BIT(8) - 1))); + + info[dspp->idx].irdx_control_0 = (init->init_param_048 & (BIT(5) - 1)); + + blk_offset = 0x140; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_049 & (BIT(8) - 1))); + + blk_offset = 0x144; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_050 & (BIT(8) - 1))); + blk_offset = 0x148; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_051 & (BIT(8) - 1)) << 8) | + ((init->init_param_052 & (BIT(8) - 1))))); + + blk_offset = 0x14c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_053 & (BIT(10) - 1))); + blk_offset = 0x150; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_054 & (BIT(10) - 1))); + blk_offset = 0x154; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_055 & (BIT(8) - 1))); + + blk_offset = 0x158; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_056 & (BIT(8) - 1))); + blk_offset = 0x164; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_057 & (BIT(8) - 1))); + blk_offset = 0x168; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_058 & (BIT(4) - 1))); + + blk_offset = 0x17c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (frame_start & (BIT(16) - 1))); + blk_offset = 0x180; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (frame_end & (BIT(16) - 1))); + blk_offset = 0x184; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (proc_start & (BIT(16) - 1))); + blk_offset = 0x188; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (proc_end & (BIT(16) - 1))); + + blk_offset = 0x18c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_059 & (BIT(4) - 1))); + + blk_offset = 0x190; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (((init->init_param_061 & (BIT(8) - 1)) << 8) | + ((init->init_param_060 & (BIT(8) - 1))))); + + blk_offset = 0x194; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_062 & (BIT(10) - 1))); + + blk_offset = 0x1a0; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_063 & (BIT(10) - 1))); + blk_offset = 0x1a4; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_064 & (BIT(10) - 1))); + blk_offset = 0x1a8; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_065 & (BIT(10) - 1))); + blk_offset = 0x1ac; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_066 & (BIT(8) - 1))); + blk_offset = 0x1b0; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_067 & (BIT(8) - 1))); + blk_offset = 0x1b4; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_068 & (BIT(6) - 1))); + + blk_offset = 0x460; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_069 & (BIT(16) - 1))); + blk_offset = 0x464; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_070 & (BIT(10) - 1))); + blk_offset = 0x468; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_071 & (BIT(10) - 1))); + blk_offset = 0x46c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_072 & (BIT(10) - 1))); + blk_offset = 0x470; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_073 & (BIT(8) - 1))); + blk_offset = 0x474; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_074 & (BIT(10) - 1))); + blk_offset = 0x478; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (init->init_param_075 & (BIT(10) - 1))); + + off1 = 0x1c0; + off2 = 0x210; + off3 = 0x260; + off4 = 0x2b0; + off5 = 0x380; + off6 = 0x3d0; + for (i = 0; i < AD4_LUT_GRP0_SIZE - 1; i = i + 2) { + val = (init->init_param_001[i] & (BIT(16) - 1)); + val |= ((init->init_param_001[i + 1] & (BIT(16) - 1)) + << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off1, val); + off1 += 4; + + val = (init->init_param_002[i] & (BIT(16) - 1)); + val |= ((init->init_param_002[i + 1] & (BIT(16) - 1)) + << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off2, val); + off2 += 4; + + val = (init->init_param_003[i] & (BIT(16) - 1)); + val |= ((init->init_param_003[i + 1] & (BIT(16) - 1)) + << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off3, val); + off3 += 4; + + val = (init->init_param_004[i] & (BIT(16) - 1)); + val |= ((init->init_param_004[i + 1] & (BIT(16) - 1)) + << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off4, val); + off4 += 4; + + val = (init->init_param_007[i] & (BIT(16) - 1)); + val |= ((init->init_param_007[i + 1] & + (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off5, val); + off5 += 4; + + val = (init->init_param_008[i] & (BIT(12) - 1)); + val |= ((init->init_param_008[i + 1] & + (BIT(12) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off6, val); + off6 += 4; + } + /* write last index data */ + i = AD4_LUT_GRP0_SIZE - 1; + val = ((init->init_param_001[i] & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off1, val); + val = ((init->init_param_002[i] & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off2, val); + val = ((init->init_param_003[i] & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off3, val); + val = ((init->init_param_004[i] & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off4, val); + val = ((init->init_param_007[i] & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off5, val); + val = ((init->init_param_008[i] & (BIT(12) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off6, val); + + off1 = 0x300; + off2 = 0x340; + for (i = 0; i < AD4_LUT_GRP1_SIZE; i = i + 2) { + val = (init->init_param_005[i] & (BIT(16) - 1)); + val |= ((init->init_param_005[i + 1] & + (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off1, val); + off1 += 4; + + val = (init->init_param_006[i] & (BIT(16) - 1)); + val |= ((init->init_param_006[i + 1] & (BIT(16) - 1)) + << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + off2, val); + off2 += 4; + } + + return 0; +} + +static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) +{ + u32 blk_offset, val; + struct drm_msm_ad4_cfg *ad_cfg; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_cfg; + return 0; + } + + if (cfg->hw_cfg->len != sizeof(struct drm_msm_ad4_cfg)) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(struct drm_msm_ad4_cfg), cfg->hw_cfg->len, + cfg->hw_cfg->payload); + return -EINVAL; + } + ad_cfg = cfg->hw_cfg->payload; + + blk_offset = 0x20; + val = (ad_cfg->cfg_param_005 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset = 0x24; + val = (ad_cfg->cfg_param_006 & (BIT(7) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + info[dspp->idx].tf_ctrl = (ad_cfg->cfg_param_008 & (BIT(8) - 1)); + + blk_offset = 0x38; + val = (ad_cfg->cfg_param_009 & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0x3c; + val = (ad_cfg->cfg_param_010 & (BIT(12) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0x88; + val = (ad_cfg->cfg_param_013 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_014 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xa4; + val = (ad_cfg->cfg_param_015 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_016 & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_017 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_018 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xc4; + val = (ad_cfg->cfg_param_019 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_020 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xb8; + val = (ad_cfg->cfg_param_021 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_022 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xd0; + val = (ad_cfg->cfg_param_023 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_024 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xdc; + val = (ad_cfg->cfg_param_025 & (BIT(16) - 1)); + val |= ((ad_cfg->cfg_param_026 & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_027 & (BIT(16) - 1)); + val |= ((ad_cfg->cfg_param_028 & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_029 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xec; + val = (ad_cfg->cfg_param_030 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_031 & (BIT(12) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0xf8; + val = (ad_cfg->cfg_param_032 & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_033 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0x104; + val = (ad_cfg->cfg_param_034 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_035 & (BIT(12) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0x110; + val = (ad_cfg->cfg_param_036 & (BIT(12) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_037 & (BIT(12) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_038 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_039 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + blk_offset = 0x134; + val = (ad_cfg->cfg_param_040 & (BIT(12) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + info[dspp->idx].vc_control_0 = (ad_cfg->cfg_param_041 & (BIT(7) - 1)); + + blk_offset = 0x16c; + val = (ad_cfg->cfg_param_044 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_045 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (ad_cfg->cfg_param_046 & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + return 0; +} + +static int ad4_input_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 *val, als; + u32 blk_offset; + + if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + blk_offset = 0x28; + if (cfg->hw_cfg->payload) { + val = cfg->hw_cfg->payload; + } else { + als = 0; + val = &als; + } + info[dspp->idx].last_als = (*val & (BIT(16) - 1)); + info[dspp->idx].completed_ops_mask |= ad4_input; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_als); + return 0; +} + +static int ad4_roi_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret = 0; + u32 blk_offset = 0, val = 0; + struct ad4_roi_info roi_cfg = {}; + + ret = ad4_roi_coordinate_offset(cfg->hw_cfg, &roi_cfg); + if (ret) { + DRM_ERROR("params invalid\n"); + return -EINVAL; + } + info[dspp->idx].last_roi_cfg = roi_cfg; + + /*roi h start and end*/ + blk_offset = 0x18; + val = (info[dspp->idx].last_roi_cfg.h_end & (BIT(16) - 1)); + val |= ((info[dspp->idx].last_roi_cfg.h_start & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + /*roi v start and end*/ + blk_offset += 4; + val = (info[dspp->idx].last_roi_cfg.v_end & (BIT(16) - 1)); + val |= ((info[dspp->idx].last_roi_cfg.v_start & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + /*roi factor in and out*/ + blk_offset = 0x40; + val = ((info[dspp->idx].last_roi_cfg.f_in & (BIT(16) - 1)) << 16); + val |= (info[dspp->idx].last_roi_cfg.f_out & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + return ret; +} + +static int ad4_roi_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret = 0; + struct ad4_roi_info roi_cfg = {}; + + ret = ad4_roi_coordinate_offset(cfg->hw_cfg, &roi_cfg); + if (ret) { + DRM_ERROR("params invalid\n"); + return -EINVAL; + } + + info[dspp->idx].cached_roi_cfg = roi_cfg; + + return 0; +} + +static int ad4_roi_coordinate_offset(struct sde_hw_cp_cfg *hw_cfg, + struct ad4_roi_info *output) +{ + struct sde_hw_mixer *hw_lm = hw_cfg->mixer_info; + struct drm_msm_ad4_roi_cfg *roi = NULL; + + if (!hw_cfg->payload) { + output->h_start = 0x0; + output->h_end = hw_cfg->displayh; + output->v_start = 0x0; + output->v_end = hw_cfg->displayv; + output->f_in = 0x400; + output->f_out = 0x400; + return 0; + } + + if (hw_cfg->len != sizeof(struct drm_msm_ad4_roi_cfg)) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(struct drm_msm_ad4_roi_cfg), hw_cfg->len, + hw_cfg->payload); + return -EINVAL; + } + roi = (struct drm_msm_ad4_roi_cfg *)hw_cfg->payload; + + if (roi->h_x >= hw_cfg->displayh || roi->v_x >= hw_cfg->displayv) { + DRM_ERROR("invalid roi=[%u,%u,%u,%u], display=[%u,%u]\n", + roi->h_x, roi->h_y, roi->v_x, roi->v_y, + hw_cfg->displayh, hw_cfg->displayv); + return -EINVAL; + } + + if (roi->h_x >= roi->h_y || roi->v_x >= roi->v_y) { + DRM_ERROR("invalid roi=[%u,%u,%u,%u], display=[%u,%u]\n", + roi->h_x, roi->h_y, roi->v_x, roi->v_y, + hw_cfg->displayh, hw_cfg->displayv); + return -EINVAL; + } + + if (roi->h_y > hw_cfg->displayh) + roi->h_y = hw_cfg->displayh; + + if (roi->v_y > hw_cfg->displayv) + roi->v_y = hw_cfg->displayv; + + /* single dspp cfg */ + output->h_start = roi->h_x; + output->h_end = roi->h_y; + output->v_start = roi->v_x; + output->v_end = roi->v_y; + output->f_in = roi->factor_in; + output->f_out = roi->factor_out; + + /* check whether dual dspp */ + if (hw_cfg->num_of_mixers != 2) + return 0; + + if (roi->h_y <= hw_lm->cfg.out_width) { + if (hw_lm->cfg.right_mixer) { + /* the region on the left of screen, clear right info */ + output->h_start = 0; + output->h_end = 0; + output->v_start = 0; + output->v_end = 0; + } + } else if (roi->h_x < hw_lm->cfg.out_width) { + /* the region occupy both sides of screen: left and right */ + if (hw_lm->cfg.right_mixer) { + output->h_start = 0; + output->h_end -= (hw_lm->cfg.out_width - + MERGE_WIDTH_RIGHT); + } else { + output->h_end = hw_lm->cfg.out_width; + } + } else { + /* the region on the right of the screen*/ + if (hw_lm->cfg.right_mixer) { + output->h_start -= (hw_lm->cfg.out_width - + MERGE_WIDTH_RIGHT); + output->h_end -= (hw_lm->cfg.out_width - + MERGE_WIDTH_RIGHT); + } else { + output->h_start = 0; + output->h_end = 0; + output->v_start = 0; + output->v_end = 0; + } + } + return 0; +} + +static int ad4_suspend_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + info[dspp->idx].state = ad4_state_idle; + pr_debug("%s(): AD state move to idle\n", __func__); + info[dspp->idx].completed_ops_mask = 0; + return 0; +} + +static int ad4_mode_setup_common(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + + if (cfg->hw_cfg->len != sizeof(u64) || !cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + info[dspp->idx].mode = *((enum ad4_modes *) + (cfg->hw_cfg->payload)); + info[dspp->idx].completed_ops_mask |= ad4_mode; + + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask) || + info[dspp->idx].mode == AD4_OFF) + ad4_mode_setup(dspp, info[dspp->idx].mode); + + return 0; +} + +static int ad4_init_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 blk_offset; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_init; + return 0; + } + + ret = ad4_init_setup(dspp, cfg); + if (ret) + return ret; + + /* enable memory initialization*/ + /* frmt mode */ + blk_offset = 0x8; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (info[dspp->idx].frmt_mode & 0x1fff)); + /* memory init */ + blk_offset = 0x450; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0x1); + + /* enforce 0 initial strength when powering up AD config */ + /* irdx_control_0 */ + blk_offset = 0x13c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0x6); + + info[dspp->idx].completed_ops_mask |= ad4_init; + + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + + return 0; +} + +static int ad4_init_setup_run(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 blk_offset; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_init; + return 0; + } + + ret = ad4_init_setup(dspp, cfg); + if (ret) + return ret; + + /* disable memory initialization*/ + /* frmt mode */ + blk_offset = 0x8; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (info[dspp->idx].frmt_mode | 0x2000)); + /* no need to explicitly set memory initialization sequence, + * since AD hw were not powered off. + */ + + /* irdx_control_0 */ + blk_offset = 0x13c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].irdx_control_0); + + return 0; +} + +static int ad4_init_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 blk_offset; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_init; + return 0; + } + + ret = ad4_init_setup(dspp, cfg); + if (ret) + return ret; + /* no need to explicitly set memory initialization sequence, + * since register reset values are the correct configuration + */ + /* frmt mode */ + blk_offset = 0x8; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (info[dspp->idx].frmt_mode | 0x2000)); + /* irdx_control_0 */ + blk_offset = 0x13c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].irdx_control_0); + + info[dspp->idx].completed_ops_mask |= ad4_init; + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + + return 0; +} + +static int ad4_cfg_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 blk_offset; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_cfg; + return 0; + } + + ret = ad4_cfg_setup(dspp, cfg); + if (ret) + return ret; + + /* enforce 0 initial strength when powering up AD config */ + /* assertiveness */ + blk_offset = 0x30; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0x0); + /* tf control */ + blk_offset = 0x34; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0x55); + + /* vc_control_0 */ + blk_offset = 0x138; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].vc_control_0); + + info[dspp->idx].completed_ops_mask |= ad4_cfg; + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + return 0; +} + +static int ad4_cfg_setup_run(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 blk_offset; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_cfg; + return 0; + } + + ret = ad4_cfg_setup(dspp, cfg); + if (ret) + return ret; + + /* assertiveness */ + blk_offset = 0x30; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_assertive); + /* tf control */ + blk_offset = 0x34; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].tf_ctrl); + /* vc_control_0 */ + blk_offset = 0x138; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].vc_control_0); + + return 0; +} + +static int ad4_cfg_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 blk_offset; + + if (!cfg->hw_cfg->payload) { + info[dspp->idx].completed_ops_mask &= ~ad4_cfg; + return 0; + } + + ret = ad4_cfg_setup(dspp, cfg); + if (ret) + return ret; + + /* assertiveness */ + blk_offset = 0x30; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_assertive); + + info[dspp->idx].completed_ops_mask |= ad4_cfg; + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + return 0; +} + +static int ad4_input_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + + ret = ad4_input_setup(dspp, cfg); + if (ret) + return ret; + + info[dspp->idx].completed_ops_mask |= ad4_input; + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + + return 0; +} + +static int ad4_input_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 *val, als; + u32 blk_offset; + + if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + blk_offset = 0x28; + if (cfg->hw_cfg->payload) { + val = cfg->hw_cfg->payload; + } else { + als = 0; + val = &als; + } + info[dspp->idx].cached_als = *val & (BIT(16) - 1); + info[dspp->idx].completed_ops_mask |= ad4_input; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_als); + + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + + return 0; +} + +static int ad4_assertive_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 *val, assertive; + u32 blk_offset; + + if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + blk_offset = 0x30; + if (cfg->hw_cfg->payload) { + val = cfg->hw_cfg->payload; + } else { + assertive = 0; + val = &assertive; + } + + info[dspp->idx].last_assertive = *val & (BIT(8) - 1); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + (info[dspp->idx].last_assertive)); + return 0; +} + +static int ad4_assertive_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 *val, assertive; + u32 blk_offset; + + if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + blk_offset = 0x30; + if (cfg->hw_cfg->payload) { + val = cfg->hw_cfg->payload; + } else { + assertive = 0; + val = &assertive; + } + + info[dspp->idx].cached_assertive = *val & (BIT(8) - 1); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_assertive); + + return 0; +} + +static int ad4_backlight_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 *val, bl; + u32 blk_offset; + + if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + blk_offset = 0x2c; + if (cfg->hw_cfg->payload) { + val = cfg->hw_cfg->payload; + } else { + bl = 0; + val = &bl; + } + + info[dspp->idx].last_bl = *val & (BIT(16) - 1); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_bl); + return 0; +} + +static int ad4_backlight_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 *val, bl; + u32 blk_offset; + + if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + blk_offset = 0x2c; + if (cfg->hw_cfg->payload) { + val = cfg->hw_cfg->payload; + } else { + bl = 0; + val = &bl; + } + + info[dspp->idx].cached_bl = *val & (BIT(16) - 1); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_bl); + + return 0; +} + +void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event, + u32 *resp_in, u32 *resp_out) +{ + if (!dspp || !resp_in || !resp_out) { + DRM_ERROR("invalid params dspp %pK resp_in %pK resp_out %pK\n", + dspp, resp_in, resp_out); + return; + } + + switch (event) { + case AD4_IN_OUT_BACKLIGHT: + *resp_in = SDE_REG_READ(&dspp->hw, + dspp->cap->sblk->ad.base + 0x2c); + *resp_out = SDE_REG_READ(&dspp->hw, + dspp->cap->sblk->ad.base + 0x48); + pr_debug("%s(): AD4 input BL %u, output BL %u\n", __func__, + (*resp_in), (*resp_out)); + break; + default: + break; + } +} + +static int ad4_ipc_suspend_setup_run(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u32 in_str = 0, out_str = 0, i = 0; + struct sde_hw_mixer *hw_lm; + + hw_lm = cfg->hw_cfg->mixer_info; + if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) { + /* this AD core is the salve core */ + for (i = DSPP_0; i < DSPP_MAX; i++) { + if (info[i].is_master) { + in_str = info[i].last_str_inroi; + out_str = info[i].last_str_outroi; + break; + } + } + } else { + in_str = SDE_REG_READ(&dspp->hw, + dspp->cap->sblk->ad.base + 0x4c); + out_str = SDE_REG_READ(&dspp->hw, + dspp->cap->sblk->ad.base + 0x50); + pr_debug("%s(): AD in strength %d, out %d\n", __func__, + in_str, out_str); + } + info[dspp->idx].last_str_inroi = in_str; + info[dspp->idx].last_str_outroi = out_str; + info[dspp->idx].state = ad4_state_ipcs; + pr_debug("%s(): AD state move to ipcs\n", __func__); + + return 0; +} + +static int ad4_ipc_resume_setup_ipcs(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u32 blk_offset, val; + + info[dspp->idx].frame_count = 0; + info[dspp->idx].state = ad4_state_ipcr; + pr_debug("%s(): AD state move to ipcr\n", __func__); + + /* no need to rewrite frmt_mode bit 13 and mem_init, + * since the default register values are exactly what + * we wanted. + */ + + /* ipc resume with manual strength */ + /* tf control */ + blk_offset = 0x34; + val = (0x55 & (BIT(8) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + /* set roi config */ + blk_offset = 0x18; + val = (info[dspp->idx].last_roi_cfg.h_end & (BIT(16) - 1)); + val |= ((info[dspp->idx].last_roi_cfg.h_start & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (info[dspp->idx].last_roi_cfg.v_end & (BIT(16) - 1)); + val |= ((info[dspp->idx].last_roi_cfg.v_start & (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset = 0x40; + val = ((info[dspp->idx].last_roi_cfg.f_in & (BIT(16) - 1)) << 16); + val |= (info[dspp->idx].last_roi_cfg.f_out & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + /* set manual strength */ + blk_offset = 0x15c; + val = (info[dspp->idx].last_str_inroi & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset = 0x160; + val = (info[dspp->idx].last_str_outroi & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + /* enable manual mode */ + blk_offset = 0x138; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, 0); + + return 0; +} + +static int ad4_ipc_suspend_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + info[dspp->idx].state = ad4_state_ipcs; + pr_debug("%s(): AD state move to ipcs\n", __func__); + return 0; +} + +static int ad4_ipc_reset_setup_ipcr(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + u32 in_str = 0, out_str = 0, i = 0; + struct sde_hw_mixer *hw_lm; + + /* Read AD calculator strength output during the 2 frames of manual + * strength mode, and assign the strength output to last_str + * when frame count reaches AD_IPC_FRAME_COUNT to avoid flickers + * caused by strength was not converged before entering IPC mode + */ + hw_lm = cfg->hw_cfg->mixer_info; + if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) { + /* this AD core is the salve core */ + for (i = DSPP_0; i < DSPP_MAX; i++) { + if (info[i].is_master) { + in_str = info[i].last_str_inroi; + out_str = info[i].last_str_outroi; + break; + } + } + } else { + in_str = SDE_REG_READ(&dspp->hw, + dspp->cap->sblk->ad.base + 0x4c); + out_str = SDE_REG_READ(&dspp->hw, + dspp->cap->sblk->ad.base + 0x50); + pr_debug("%s(): AD in strength %d, out %d\n", __func__, + in_str, out_str); + } + + if (info[dspp->idx].frame_count == AD_IPC_FRAME_COUNT) { + info[dspp->idx].state = ad4_state_run; + pr_debug("%s(): AD state move to run\n", __func__); + info[dspp->idx].last_str_inroi = in_str; + info[dspp->idx].last_str_outroi = out_str; + ret = ad4_cfg_ipc_reset(dspp, cfg); + if (ret) + return ret; + } else { + info[dspp->idx].frame_count++; + } + + return 0; +} + +static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u32 blk_offset, val = 0; + + /* revert manual strength */ + /* tf control */ + blk_offset = 0x34; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].tf_ctrl); + /* vc_control_0 */ + blk_offset = 0x138; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].vc_control_0); + + /* reset cached ALS, backlight and assertiveness */ + if (info[dspp->idx].cached_als != U64_MAX) { + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + 0x28, + info[dspp->idx].cached_als); + info[dspp->idx].last_als = info[dspp->idx].cached_als; + info[dspp->idx].cached_als = U64_MAX; + } + if (info[dspp->idx].cached_bl != U64_MAX) { + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + 0x2c, + info[dspp->idx].cached_bl); + info[dspp->idx].last_bl = info[dspp->idx].cached_bl; + info[dspp->idx].cached_bl = U64_MAX; + } + if (info[dspp->idx].cached_assertive != U8_MAX) { + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + 0x30, + info[dspp->idx].cached_assertive); + info[dspp->idx].last_assertive = + info[dspp->idx].cached_assertive; + info[dspp->idx].cached_assertive = U8_MAX; + } + + /*reset cached roi config*/ + if (info[dspp->idx].cached_roi_cfg.h_start != U32_MAX) { + blk_offset = 0x18; + val = (info[dspp->idx].cached_roi_cfg.h_end & (BIT(16) - 1)); + val |= ((info[dspp->idx].cached_roi_cfg.h_start & + (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (info[dspp->idx].cached_roi_cfg.v_end & (BIT(16) - 1)); + val |= ((info[dspp->idx].cached_roi_cfg.v_start & + (BIT(16) - 1)) << 16); + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset = 0x40; + val = ((info[dspp->idx].cached_roi_cfg.f_in & + (BIT(16) - 1)) << 16); + val |= (info[dspp->idx].cached_roi_cfg.f_out & (BIT(16) - 1)); + SDE_REG_WRITE(&dspp->hw, + dspp->cap->sblk->ad.base + blk_offset, val); + + info[dspp->idx].last_roi_cfg = info[dspp->idx].cached_roi_cfg; + info[dspp->idx].cached_roi_cfg.h_start = U32_MAX; + info[dspp->idx].cached_roi_cfg.h_end = U32_MAX; + info[dspp->idx].cached_roi_cfg.v_start = U32_MAX; + info[dspp->idx].cached_roi_cfg.v_end = U32_MAX; + info[dspp->idx].cached_roi_cfg.f_in = U32_MAX; + info[dspp->idx].cached_roi_cfg.f_out = U32_MAX; + } + return 0; +} + +static int ad4_ipc_reset_setup_startup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u32 blk_offset; + + if (info[dspp->idx].frame_count == AD_IPC_FRAME_COUNT) { + info[dspp->idx].state = ad4_state_run; + pr_debug("%s(): AD state move to run\n", __func__); + + /* revert enforce 0 initial strength */ + /* irdx_control_0 */ + blk_offset = 0x13c; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].irdx_control_0); + /* assertiveness */ + blk_offset = 0x30; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].last_assertive); + /* tf control */ + blk_offset = 0x34; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, + info[dspp->idx].tf_ctrl); + } else { + info[dspp->idx].frame_count++; + } + + return 0; +} + +static int ad4_strength_setup(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u64 in_str = 0, out_str = 0, val; + u32 blk_offset = 0x15c; + struct drm_msm_ad4_manual_str_cfg *str_cfg = NULL; + + if (cfg->hw_cfg->payload && (cfg->hw_cfg->len != + sizeof(struct drm_msm_ad4_manual_str_cfg))) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(struct drm_msm_ad4_manual_str_cfg), + cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + if (cfg->hw_cfg->payload) { + str_cfg = (struct drm_msm_ad4_manual_str_cfg *) + cfg->hw_cfg->payload; + in_str = str_cfg->in_str; + out_str = str_cfg->out_str; + } + + /* set manual strength */ + info[dspp->idx].completed_ops_mask |= ad4_strength; + val = (in_str & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + blk_offset += 4; + val = (out_str & (BIT(10) - 1)); + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + + return 0; +} + +static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + int ret; + + ret = ad4_strength_setup(dspp, cfg); + if (ret) + return ret; + + if (AD_STATE_READY(info[dspp->idx].completed_ops_mask)) + ad4_mode_setup(dspp, info[dspp->idx].mode); + return 0; +} diff --git a/techpack/display/msm/sde/sde_hw_blk.c b/techpack/display/msm/sde/sde_hw_blk.c new file mode 100644 index 0000000000000000000000000000000000000000..26585a2dbe49ec6ba16af833d23f8703236d78be --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_blk.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/mutex.h> +#include <linux/errno.h> +#include <linux/slab.h> + +#include "sde_hw_mdss.h" +#include "sde_hw_blk.h" + +/* Serialization lock for sde_hw_blk_list */ +static DEFINE_MUTEX(sde_hw_blk_lock); + +/* List of all hw block objects */ +static LIST_HEAD(sde_hw_blk_list); + +/** + * sde_hw_blk_init - initialize hw block object + * @type: hw block type - enum sde_hw_blk_type + * @id: instance id of the hw block + * @ops: Pointer to block operations + * return: 0 if success; error code otherwise + */ +int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id, + struct sde_hw_blk_ops *ops) +{ + if (!hw_blk) { + pr_err("invalid parameters\n"); + return -EINVAL; + } + + INIT_LIST_HEAD(&hw_blk->list); + hw_blk->type = type; + hw_blk->id = id; + atomic_set(&hw_blk->refcount, 0); + + if (ops) + hw_blk->ops = *ops; + + mutex_lock(&sde_hw_blk_lock); + list_add(&hw_blk->list, &sde_hw_blk_list); + mutex_unlock(&sde_hw_blk_lock); + + return 0; +} + +/** + * sde_hw_blk_destroy - destroy hw block object. + * @hw_blk: pointer to hw block object + * return: none + */ +void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk) +{ + if (!hw_blk) { + pr_err("invalid parameters\n"); + return; + } + + if (atomic_read(&hw_blk->refcount)) + pr_err("hw_blk:%d.%d invalid refcount\n", hw_blk->type, + hw_blk->id); + + mutex_lock(&sde_hw_blk_lock); + list_del(&hw_blk->list); + mutex_unlock(&sde_hw_blk_lock); +} + +/** + * sde_hw_blk_get - get hw_blk from free pool + * @hw_blk: if specified, increment reference count only + * @type: if hw_blk is not specified, allocate the next available of this type + * @id: if specified (>= 0), allocate the given instance of the above type + * return: pointer to hw block object + */ +struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id) +{ + struct sde_hw_blk *curr; + int rc, refcount; + + if (!hw_blk) { + mutex_lock(&sde_hw_blk_lock); + list_for_each_entry(curr, &sde_hw_blk_list, list) { + if ((curr->type != type) || + (id >= 0 && curr->id != id) || + (id < 0 && + atomic_read(&curr->refcount))) + continue; + + hw_blk = curr; + break; + } + mutex_unlock(&sde_hw_blk_lock); + } + + if (!hw_blk) { + pr_debug("no hw_blk:%d\n", type); + return NULL; + } + + refcount = atomic_inc_return(&hw_blk->refcount); + + if (refcount == 1 && hw_blk->ops.start) { + rc = hw_blk->ops.start(hw_blk); + if (rc) { + pr_err("failed to start hw_blk:%d rc:%d\n", type, rc); + goto error_start; + } + } + + pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, + hw_blk->id, refcount); + return hw_blk; + +error_start: + sde_hw_blk_put(hw_blk); + return ERR_PTR(rc); +} + +/** + * sde_hw_blk_put - put hw_blk to free pool if decremented refcount is zero + * @hw_blk: hw block to be freed + * @free_blk: function to be called when reference count goes to zero + */ +void sde_hw_blk_put(struct sde_hw_blk *hw_blk) +{ + if (!hw_blk) { + pr_err("invalid parameters\n"); + return; + } + + pr_debug("hw_blk:%d.%d refcount:%d\n", hw_blk->type, hw_blk->id, + atomic_read(&hw_blk->refcount)); + + if (!atomic_read(&hw_blk->refcount)) { + pr_err("hw_blk:%d.%d invalid put\n", hw_blk->type, hw_blk->id); + return; + } + + if (atomic_dec_return(&hw_blk->refcount)) + return; + + if (hw_blk->ops.stop) + hw_blk->ops.stop(hw_blk); +} diff --git a/techpack/display/msm/sde/sde_hw_blk.h b/techpack/display/msm/sde/sde_hw_blk.h new file mode 100644 index 0000000000000000000000000000000000000000..fe7077f3b1f7b708a8bbd428aff8f02186738c49 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_blk.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_BLK_H +#define _SDE_HW_BLK_H + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/atomic.h> + +struct sde_hw_blk; + +/** + * struct sde_hw_blk_ops - common hardware block operations + * @start: start operation on first get + * @stop: stop operation on last put + */ +struct sde_hw_blk_ops { + int (*start)(struct sde_hw_blk *hw_blk); + void (*stop)(struct sde_hw_blk *hw_blk); +}; + +/** + * struct sde_hw_blk - definition of hardware block object + * @list: list of hardware blocks + * @type: hardware block type + * @id: instance id + * @refcount: reference/usage count + */ +struct sde_hw_blk { + struct list_head list; + u32 type; + int id; + atomic_t refcount; + struct sde_hw_blk_ops ops; +}; + +int sde_hw_blk_init(struct sde_hw_blk *hw_blk, u32 type, int id, + struct sde_hw_blk_ops *ops); +void sde_hw_blk_destroy(struct sde_hw_blk *hw_blk); + +struct sde_hw_blk *sde_hw_blk_get(struct sde_hw_blk *hw_blk, u32 type, int id); +void sde_hw_blk_put(struct sde_hw_blk *hw_blk); +#endif /*_SDE_HW_BLK_H */ diff --git a/techpack/display/msm/sde/sde_hw_catalog.c b/techpack/display/msm/sde/sde_hw_catalog.c new file mode 100644 index 0000000000000000000000000000000000000000..ad7aa05e1eb716396661de0607fa3daf52bc9543 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_catalog.c @@ -0,0 +1,4627 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include <linux/slab.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/soc/qcom/llcc-qcom.h> +#include <linux/pm_qos.h> + +#include "sde_hw_mdss.h" +#include "sde_hw_catalog.h" +#include "sde_hw_catalog_format.h" +#include "sde_kms.h" +#include "sde_hw_uidle.h" +#include "sde_connector.h" + +/************************************************************* + * MACRO DEFINITION + *************************************************************/ + +/** + * Max hardware block in certain hardware. For ex: sspp pipes + * can have QSEED, pcc, igc, pa, csc, qos entries, etc. This count is + * 64 based on software design. It should be increased if any of the + * hardware block has more subblocks. + */ +#define MAX_SDE_HW_BLK 64 + +/* each entry will have register address and bit offset in that register */ +#define MAX_BIT_OFFSET 2 + +/* default line width for sspp, mixer, ds (input), wb */ +#define DEFAULT_SDE_LINE_WIDTH 2048 + +/* default output line width for ds */ +#define DEFAULT_SDE_OUTPUT_LINE_WIDTH 2560 + +/* max mixer blend stages */ +#define DEFAULT_SDE_MIXER_BLENDSTAGES 7 + +/* max number of channel */ +#define MAX_NUM_CHANNELS 8 + +/* HBB Offset */ +#define UBWC_HBB_OFFSET 13 + +/* + * max bank bit for macro tile and ubwc format. + * this value is left shifted and written to register + */ +#define DEFAULT_SDE_HIGHEST_BANK_BIT 0x02 + +/* default ubwc version */ +#define DEFAULT_SDE_UBWC_VERSION SDE_HW_UBWC_VER_10 + +/* No UBWC */ +#define DEFAULT_SDE_UBWC_NONE 0x0 + +/* default ubwc static config register value */ +#define DEFAULT_SDE_UBWC_STATIC 0x0 + +/* default ubwc swizzle register value */ +#define DEFAULT_SDE_UBWC_SWIZZLE 0x0 + +/* default ubwc macrotile mode value */ +#define DEFAULT_SDE_UBWC_MACROTILE_MODE 0x0 + +/* default hardware block size if dtsi entry is not present */ +#define DEFAULT_SDE_HW_BLOCK_LEN 0x100 + +/* total number of intf - dp, dsi, hdmi */ +#define INTF_COUNT 3 + +#define MAX_UPSCALE_RATIO 20 +#define MAX_DOWNSCALE_RATIO 4 +#define SSPP_UNITY_SCALE 1 + +#define MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR 11 +#define MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR 5 +#define MAX_DOWNSCALE_RATIO_INROT_PD_RT_NUMERATOR 4 +#define MAX_DOWNSCALE_RATIO_INROT_PD_RT_DENOMINATOR 1 +#define MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT 4 + +#define MAX_PRE_ROT_HEIGHT_INLINE_ROT_DEFAULT 1088 + +#define MAX_HORZ_DECIMATION 4 +#define MAX_VERT_DECIMATION 4 + +#define MAX_SPLIT_DISPLAY_CTL 2 +#define MAX_PP_SPLIT_DISPLAY_CTL 1 + +#define MDSS_BASE_OFFSET 0x0 + +#define ROT_LM_OFFSET 3 +#define LINE_LM_OFFSET 5 +#define LINE_MODE_WB_OFFSET 2 + +/** + * these configurations are decided based on max mdp clock. It accounts + * for max and min display resolution based on virtual hardware resource + * support. + */ +#define MAX_DISPLAY_HEIGHT_WITH_DECIMATION 2160 +#define MAX_DISPLAY_HEIGHT 5760 +#define MIN_DISPLAY_HEIGHT 0 +#define MIN_DISPLAY_WIDTH 0 +#define MAX_LM_PER_DISPLAY 2 + +/* maximum XIN halt timeout in usec */ +#define VBIF_XIN_HALT_TIMEOUT 0x4000 + +#define DEFAULT_PIXEL_RAM_SIZE (50 * 1024) + +/* access property value based on prop_type and hardware index */ +#define PROP_VALUE_ACCESS(p, i, j) ((p + i)->value[j]) + +/* + * access element within PROP_TYPE_BIT_OFFSET_ARRAYs based on prop_type, + * hardware index and offset array index + */ +#define PROP_BITVALUE_ACCESS(p, i, j, k) ((p + i)->bit_value[j][k]) + +#define DEFAULT_SBUF_HEADROOM (20) +#define DEFAULT_SBUF_PREFILL (128) + +/* + * Default parameter values + */ +#define DEFAULT_MAX_BW_HIGH 7000000 +#define DEFAULT_MAX_BW_LOW 7000000 +#define DEFAULT_UNDERSIZED_PREFILL_LINES 2 +#define DEFAULT_XTRA_PREFILL_LINES 2 +#define DEFAULT_DEST_SCALE_PREFILL_LINES 3 +#define DEFAULT_MACROTILE_PREFILL_LINES 4 +#define DEFAULT_YUV_NV12_PREFILL_LINES 8 +#define DEFAULT_LINEAR_PREFILL_LINES 1 +#define DEFAULT_DOWNSCALING_PREFILL_LINES 1 +#define DEFAULT_CORE_IB_FF "6.0" +#define DEFAULT_CORE_CLK_FF "1.0" +#define DEFAULT_COMP_RATIO_RT \ + "NV12/5/1/1.23 AB24/5/1/1.23 XB24/5/1/1.23" +#define DEFAULT_COMP_RATIO_NRT \ + "NV12/5/1/1.25 AB24/5/1/1.25 XB24/5/1/1.25" +#define DEFAULT_MAX_PER_PIPE_BW 2400000 +#define DEFAULT_AMORTIZABLE_THRESHOLD 25 +#define DEFAULT_MNOC_PORTS 2 +#define DEFAULT_AXI_BUS_WIDTH 32 +#define DEFAULT_CPU_MASK 0 +#define DEFAULT_CPU_DMA_LATENCY PM_QOS_DEFAULT_VALUE + +/* Uidle values */ +#define SDE_UIDLE_FAL10_EXIT_CNT 128 +#define SDE_UIDLE_FAL10_EXIT_DANGER 4 +#define SDE_UIDLE_FAL10_DANGER 6 +#define SDE_UIDLE_FAL10_TARGET_IDLE 50 +#define SDE_UIDLE_FAL1_TARGET_IDLE 10 +#define SDE_UIDLE_FAL10_THRESHOLD 12 +#define SDE_UIDLE_MAX_DWNSCALE 1500 +#define SDE_UIDLE_MAX_FPS 60 + + +/************************************************************* + * DTSI PROPERTY INDEX + *************************************************************/ +enum { + HW_OFF, + HW_LEN, + HW_DISP, + HW_PROP_MAX, +}; + +enum sde_prop { + SDE_OFF, + SDE_LEN, + SSPP_LINEWIDTH, + VIG_SSPP_LINEWIDTH, + MIXER_LINEWIDTH, + MIXER_BLEND, + WB_LINEWIDTH, + BANK_BIT, + UBWC_VERSION, + UBWC_STATIC, + UBWC_SWIZZLE, + QSEED_TYPE, + CSC_TYPE, + PANIC_PER_PIPE, + SRC_SPLIT, + DIM_LAYER, + SMART_DMA_REV, + IDLE_PC, + DEST_SCALER, + SMART_PANEL_ALIGN_MODE, + MACROTILE_MODE, + UBWC_BW_CALC_VERSION, + PIPE_ORDER_VERSION, + SEC_SID_MASK, + SDE_LIMITS, + BASE_LAYER, + NUM_DRAM_CHANNELS, + SDE_PROP_MAX, +}; + +enum { + PERF_MAX_BW_LOW, + PERF_MAX_BW_HIGH, + PERF_MIN_CORE_IB, + PERF_MIN_LLCC_IB, + PERF_MIN_DRAM_IB, + PERF_CORE_IB_FF, + PERF_CORE_CLK_FF, + PERF_COMP_RATIO_RT, + PERF_COMP_RATIO_NRT, + PERF_UNDERSIZED_PREFILL_LINES, + PERF_DEST_SCALE_PREFILL_LINES, + PERF_MACROTILE_PREFILL_LINES, + PERF_YUV_NV12_PREFILL_LINES, + PERF_LINEAR_PREFILL_LINES, + PERF_DOWNSCALING_PREFILL_LINES, + PERF_XTRA_PREFILL_LINES, + PERF_AMORTIZABLE_THRESHOLD, + PERF_NUM_MNOC_PORTS, + PERF_AXI_BUS_WIDTH, + PERF_CDP_SETTING, + PERF_CPU_MASK, + PERF_CPU_DMA_LATENCY, + PERF_CPU_IRQ_LATENCY, + PERF_PROP_MAX, +}; + +enum { + QOS_REFRESH_RATES, + QOS_DANGER_LUT, + QOS_SAFE_LUT_LINEAR, + QOS_SAFE_LUT_MACROTILE, + QOS_SAFE_LUT_NRT, + QOS_SAFE_LUT_CWB, + QOS_SAFE_LUT_MACROTILE_QSEED, + QOS_CREQ_LUT_LINEAR, + QOS_CREQ_LUT_MACROTILE, + QOS_CREQ_LUT_NRT, + QOS_CREQ_LUT_CWB, + QOS_CREQ_LUT_MACROTILE_QSEED, + QOS_PROP_MAX, +}; + +enum { + SSPP_OFF, + SSPP_SIZE, + SSPP_TYPE, + SSPP_XIN, + SSPP_CLK_CTRL, + SSPP_CLK_STATUS, + SSPP_SCALE_SIZE, + SSPP_VIG_BLOCKS, + SSPP_RGB_BLOCKS, + SSPP_DMA_BLOCKS, + SSPP_EXCL_RECT, + SSPP_SMART_DMA, + SSPP_MAX_PER_PIPE_BW, + SSPP_MAX_PER_PIPE_BW_HIGH, + SSPP_PROP_MAX, +}; + +enum { + VIG_QSEED_OFF, + VIG_QSEED_LEN, + VIG_CSC_OFF, + VIG_HSIC_PROP, + VIG_MEMCOLOR_PROP, + VIG_PCC_PROP, + VIG_GAMUT_PROP, + VIG_IGC_PROP, + VIG_INVERSE_PMA, + VIG_PROP_MAX, +}; + +enum { + RGB_SCALER_OFF, + RGB_SCALER_LEN, + RGB_PCC_PROP, + RGB_PROP_MAX, +}; + +enum { + DMA_IGC_PROP, + DMA_GC_PROP, + DMA_DGM_INVERSE_PMA, + DMA_CSC_OFF, + DMA_PROP_MAX, +}; + +enum { + INTF_OFF, + INTF_LEN, + INTF_PREFETCH, + INTF_TYPE, + INTF_PROP_MAX, +}; + +enum { + LIMIT_NAME, + LIMIT_USECASE, + LIMIT_ID, + LIMIT_VALUE, + LIMIT_PROP_MAX, +}; + +enum { + PP_OFF, + PP_LEN, + TE_OFF, + TE_LEN, + TE2_OFF, + TE2_LEN, + PP_SLAVE, + DITHER_OFF, + DITHER_LEN, + DITHER_VER, + PP_MERGE_3D_ID, + PP_PROP_MAX, +}; + +enum { + DSC_OFF, + DSC_LEN, + DSC_PAIR_MASK, + DSC_PROP_MAX, +}; + +enum { + DS_TOP_OFF, + DS_TOP_LEN, + DS_TOP_INPUT_LINEWIDTH, + DS_TOP_OUTPUT_LINEWIDTH, + DS_TOP_PROP_MAX, +}; + +enum { + DS_OFF, + DS_LEN, + DS_PROP_MAX, +}; + +enum { + DSPP_TOP_OFF, + DSPP_TOP_SIZE, + DSPP_TOP_PROP_MAX, +}; + +enum { + DSPP_OFF, + DSPP_SIZE, + DSPP_BLOCKS, + DSPP_PROP_MAX, +}; + +enum { + DSPP_IGC_PROP, + DSPP_PCC_PROP, + DSPP_GC_PROP, + DSPP_HSIC_PROP, + DSPP_MEMCOLOR_PROP, + DSPP_SIXZONE_PROP, + DSPP_GAMUT_PROP, + DSPP_DITHER_PROP, + DSPP_HIST_PROP, + DSPP_VLUT_PROP, + DSPP_BLOCKS_PROP_MAX, +}; + +enum { + AD_OFF, + AD_VERSION, + AD_PROP_MAX, +}; + +enum { + LTM_OFF, + LTM_VERSION, + LTM_PROP_MAX, +}; + +enum { + MIXER_OFF, + MIXER_LEN, + MIXER_PAIR_MASK, + MIXER_BLOCKS, + MIXER_DISP, + MIXER_CWB, + MIXER_PROP_MAX, +}; + +enum { + MIXER_GC_PROP, + MIXER_BLOCKS_PROP_MAX, +}; + +enum { + MIXER_BLEND_OP_OFF, + MIXER_BLEND_PROP_MAX, +}; + +enum { + WB_OFF, + WB_LEN, + WB_ID, + WB_XIN_ID, + WB_CLK_CTRL, + WB_PROP_MAX, +}; + +enum { + VBIF_OFF, + VBIF_LEN, + VBIF_ID, + VBIF_DEFAULT_OT_RD_LIMIT, + VBIF_DEFAULT_OT_WR_LIMIT, + VBIF_DYNAMIC_OT_RD_LIMIT, + VBIF_DYNAMIC_OT_WR_LIMIT, + VBIF_MEMTYPE_0, + VBIF_MEMTYPE_1, + VBIF_QOS_RT_REMAP, + VBIF_QOS_NRT_REMAP, + VBIF_QOS_CWB_REMAP, + VBIF_QOS_LUTDMA_REMAP, + VBIF_PROP_MAX, +}; + +enum { + UIDLE_OFF, + UIDLE_LEN, + UIDLE_PROP_MAX, +}; + +enum { + REG_DMA_OFF, + REG_DMA_VERSION, + REG_DMA_TRIGGER_OFF, + REG_DMA_BROADCAST_DISABLED, + REG_DMA_XIN_ID, + REG_DMA_CLK_CTRL, + REG_DMA_PROP_MAX +}; + +/************************************************************* + * dts property definition + *************************************************************/ +enum prop_type { + PROP_TYPE_BOOL, + PROP_TYPE_U32, + PROP_TYPE_U32_ARRAY, + PROP_TYPE_STRING, + PROP_TYPE_STRING_ARRAY, + PROP_TYPE_BIT_OFFSET_ARRAY, + PROP_TYPE_NODE, +}; + +struct sde_prop_type { + /* use property index from enum property for readability purpose */ + u8 id; + /* it should be property name based on dtsi documentation */ + char *prop_name; + /** + * if property is marked mandatory then it will fail parsing + * when property is not present + */ + u32 is_mandatory; + /* property type based on "enum prop_type" */ + enum prop_type type; +}; + +struct sde_prop_value { + u32 value[MAX_SDE_HW_BLK]; + u32 bit_value[MAX_SDE_HW_BLK][MAX_BIT_OFFSET]; +}; + +/************************************************************* + * dts property list + *************************************************************/ +static struct sde_prop_type sde_prop[] = { + {SDE_OFF, "qcom,sde-off", true, PROP_TYPE_U32}, + {SDE_LEN, "qcom,sde-len", false, PROP_TYPE_U32}, + {SSPP_LINEWIDTH, "qcom,sde-sspp-linewidth", false, PROP_TYPE_U32}, + {VIG_SSPP_LINEWIDTH, "qcom,sde-vig-sspp-linewidth", false, PROP_TYPE_U32}, + {MIXER_LINEWIDTH, "qcom,sde-mixer-linewidth", false, PROP_TYPE_U32}, + {MIXER_BLEND, "qcom,sde-mixer-blendstages", false, PROP_TYPE_U32}, + {WB_LINEWIDTH, "qcom,sde-wb-linewidth", false, PROP_TYPE_U32}, + {BANK_BIT, "qcom,sde-highest-bank-bit", false, PROP_TYPE_U32}, + {UBWC_VERSION, "qcom,sde-ubwc-version", false, PROP_TYPE_U32}, + {UBWC_STATIC, "qcom,sde-ubwc-static", false, PROP_TYPE_U32}, + {UBWC_SWIZZLE, "qcom,sde-ubwc-swizzle", false, PROP_TYPE_U32}, + {QSEED_TYPE, "qcom,sde-qseed-type", false, PROP_TYPE_STRING}, + {CSC_TYPE, "qcom,sde-csc-type", false, PROP_TYPE_STRING}, + {PANIC_PER_PIPE, "qcom,sde-panic-per-pipe", false, PROP_TYPE_BOOL}, + {SRC_SPLIT, "qcom,sde-has-src-split", false, PROP_TYPE_BOOL}, + {DIM_LAYER, "qcom,sde-has-dim-layer", false, PROP_TYPE_BOOL}, + {SMART_DMA_REV, "qcom,sde-smart-dma-rev", false, PROP_TYPE_STRING}, + {IDLE_PC, "qcom,sde-has-idle-pc", false, PROP_TYPE_BOOL}, + {DEST_SCALER, "qcom,sde-has-dest-scaler", false, PROP_TYPE_BOOL}, + {SMART_PANEL_ALIGN_MODE, "qcom,sde-smart-panel-align-mode", + false, PROP_TYPE_U32}, + {MACROTILE_MODE, "qcom,sde-macrotile-mode", false, PROP_TYPE_U32}, + {UBWC_BW_CALC_VERSION, "qcom,sde-ubwc-bw-calc-version", false, + PROP_TYPE_U32}, + {PIPE_ORDER_VERSION, "qcom,sde-pipe-order-version", false, + PROP_TYPE_U32}, + {SEC_SID_MASK, "qcom,sde-secure-sid-mask", false, PROP_TYPE_U32_ARRAY}, + {SDE_LIMITS, "qcom,sde-limits", false, PROP_TYPE_NODE}, + {BASE_LAYER, "qcom,sde-mixer-stage-base-layer", false, PROP_TYPE_BOOL}, + {NUM_DRAM_CHANNELS, "qcom,sde-dram-channels", true, PROP_TYPE_U32}, +}; + +static struct sde_prop_type sde_perf_prop[] = { + {PERF_MAX_BW_LOW, "qcom,sde-max-bw-low-kbps", false, PROP_TYPE_U32}, + {PERF_MAX_BW_HIGH, "qcom,sde-max-bw-high-kbps", false, PROP_TYPE_U32}, + {PERF_MIN_CORE_IB, "qcom,sde-min-core-ib-kbps", false, PROP_TYPE_U32}, + {PERF_MIN_LLCC_IB, "qcom,sde-min-llcc-ib-kbps", false, PROP_TYPE_U32}, + {PERF_MIN_DRAM_IB, "qcom,sde-min-dram-ib-kbps", false, PROP_TYPE_U32}, + {PERF_CORE_IB_FF, "qcom,sde-core-ib-ff", false, PROP_TYPE_STRING}, + {PERF_CORE_CLK_FF, "qcom,sde-core-clk-ff", false, PROP_TYPE_STRING}, + {PERF_COMP_RATIO_RT, "qcom,sde-comp-ratio-rt", false, + PROP_TYPE_STRING}, + {PERF_COMP_RATIO_NRT, "qcom,sde-comp-ratio-nrt", false, + PROP_TYPE_STRING}, + {PERF_UNDERSIZED_PREFILL_LINES, "qcom,sde-undersizedprefill-lines", + false, PROP_TYPE_U32}, + {PERF_DEST_SCALE_PREFILL_LINES, "qcom,sde-dest-scaleprefill-lines", + false, PROP_TYPE_U32}, + {PERF_MACROTILE_PREFILL_LINES, "qcom,sde-macrotileprefill-lines", + false, PROP_TYPE_U32}, + {PERF_YUV_NV12_PREFILL_LINES, "qcom,sde-yuv-nv12prefill-lines", + false, PROP_TYPE_U32}, + {PERF_LINEAR_PREFILL_LINES, "qcom,sde-linearprefill-lines", + false, PROP_TYPE_U32}, + {PERF_DOWNSCALING_PREFILL_LINES, "qcom,sde-downscalingprefill-lines", + false, PROP_TYPE_U32}, + {PERF_XTRA_PREFILL_LINES, "qcom,sde-xtra-prefill-lines", + false, PROP_TYPE_U32}, + {PERF_AMORTIZABLE_THRESHOLD, "qcom,sde-amortizable-threshold", + false, PROP_TYPE_U32}, + {PERF_NUM_MNOC_PORTS, "qcom,sde-num-mnoc-ports", + false, PROP_TYPE_U32}, + {PERF_AXI_BUS_WIDTH, "qcom,sde-axi-bus-width", + false, PROP_TYPE_U32}, + {PERF_CDP_SETTING, "qcom,sde-cdp-setting", false, + PROP_TYPE_U32_ARRAY}, + {PERF_CPU_MASK, "qcom,sde-qos-cpu-mask", false, PROP_TYPE_U32}, + {PERF_CPU_DMA_LATENCY, "qcom,sde-qos-cpu-dma-latency", false, + PROP_TYPE_U32}, + {PERF_CPU_IRQ_LATENCY, "qcom,sde-qos-cpu-irq-latency", false, + PROP_TYPE_U32}, +}; + +static struct sde_prop_type sde_qos_prop[] = { + {QOS_REFRESH_RATES, "qcom,sde-qos-refresh-rates", + false, PROP_TYPE_U32_ARRAY}, + {QOS_DANGER_LUT, "qcom,sde-danger-lut", false, PROP_TYPE_U32_ARRAY}, + {QOS_SAFE_LUT_LINEAR, "qcom,sde-safe-lut-linear", false, + PROP_TYPE_U32_ARRAY}, + {QOS_SAFE_LUT_MACROTILE, "qcom,sde-safe-lut-macrotile", false, + PROP_TYPE_U32_ARRAY}, + {QOS_SAFE_LUT_NRT, "qcom,sde-safe-lut-nrt", false, + PROP_TYPE_U32_ARRAY}, + {QOS_SAFE_LUT_CWB, "qcom,sde-safe-lut-cwb", false, + PROP_TYPE_U32_ARRAY}, + {QOS_SAFE_LUT_MACROTILE_QSEED, "qcom,sde-safe-lut-macrotile-qseed", + false, PROP_TYPE_U32_ARRAY}, + {QOS_CREQ_LUT_LINEAR, "qcom,sde-qos-lut-linear", false, + PROP_TYPE_U32_ARRAY}, + {QOS_CREQ_LUT_MACROTILE, "qcom,sde-qos-lut-macrotile", false, + PROP_TYPE_U32_ARRAY}, + {QOS_CREQ_LUT_NRT, "qcom,sde-qos-lut-nrt", false, + PROP_TYPE_U32_ARRAY}, + {QOS_CREQ_LUT_CWB, "qcom,sde-qos-lut-cwb", false, + PROP_TYPE_U32_ARRAY}, + {QOS_CREQ_LUT_MACROTILE_QSEED, "qcom,sde-qos-lut-macrotile-qseed", + false, PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type sspp_prop[] = { + {SSPP_OFF, "qcom,sde-sspp-off", true, PROP_TYPE_U32_ARRAY}, + {SSPP_SIZE, "qcom,sde-sspp-src-size", false, PROP_TYPE_U32}, + {SSPP_TYPE, "qcom,sde-sspp-type", true, PROP_TYPE_STRING_ARRAY}, + {SSPP_XIN, "qcom,sde-sspp-xin-id", true, PROP_TYPE_U32_ARRAY}, + {SSPP_CLK_CTRL, "qcom,sde-sspp-clk-ctrl", false, + PROP_TYPE_BIT_OFFSET_ARRAY}, + {SSPP_CLK_STATUS, "qcom,sde-sspp-clk-status", false, + PROP_TYPE_BIT_OFFSET_ARRAY}, + {SSPP_SCALE_SIZE, "qcom,sde-sspp-scale-size", false, PROP_TYPE_U32}, + {SSPP_VIG_BLOCKS, "qcom,sde-sspp-vig-blocks", false, PROP_TYPE_NODE}, + {SSPP_RGB_BLOCKS, "qcom,sde-sspp-rgb-blocks", false, PROP_TYPE_NODE}, + {SSPP_DMA_BLOCKS, "qcom,sde-sspp-dma-blocks", false, PROP_TYPE_NODE}, + {SSPP_EXCL_RECT, "qcom,sde-sspp-excl-rect", false, PROP_TYPE_U32_ARRAY}, + {SSPP_SMART_DMA, "qcom,sde-sspp-smart-dma-priority", false, + PROP_TYPE_U32_ARRAY}, + {SSPP_MAX_PER_PIPE_BW, "qcom,sde-max-per-pipe-bw-kbps", false, + PROP_TYPE_U32_ARRAY}, + {SSPP_MAX_PER_PIPE_BW_HIGH, "qcom,sde-max-per-pipe-bw-high-kbps", false, + PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type vig_prop[] = { + {VIG_QSEED_OFF, "qcom,sde-vig-qseed-off", false, PROP_TYPE_U32}, + {VIG_QSEED_LEN, "qcom,sde-vig-qseed-size", false, PROP_TYPE_U32}, + {VIG_CSC_OFF, "qcom,sde-vig-csc-off", false, PROP_TYPE_U32}, + {VIG_HSIC_PROP, "qcom,sde-vig-hsic", false, PROP_TYPE_U32_ARRAY}, + {VIG_MEMCOLOR_PROP, "qcom,sde-vig-memcolor", false, + PROP_TYPE_U32_ARRAY}, + {VIG_PCC_PROP, "qcom,sde-vig-pcc", false, PROP_TYPE_U32_ARRAY}, + {VIG_GAMUT_PROP, "qcom,sde-vig-gamut", false, PROP_TYPE_U32_ARRAY}, + {VIG_IGC_PROP, "qcom,sde-vig-igc", false, PROP_TYPE_U32_ARRAY}, + {VIG_INVERSE_PMA, "qcom,sde-vig-inverse-pma", false, PROP_TYPE_BOOL}, +}; + +static struct sde_prop_type rgb_prop[] = { + {RGB_SCALER_OFF, "qcom,sde-rgb-scaler-off", false, PROP_TYPE_U32}, + {RGB_SCALER_LEN, "qcom,sde-rgb-scaler-size", false, PROP_TYPE_U32}, + {RGB_PCC_PROP, "qcom,sde-rgb-pcc", false, PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type dma_prop[] = { + {DMA_IGC_PROP, "qcom,sde-dma-igc", false, PROP_TYPE_U32_ARRAY}, + {DMA_GC_PROP, "qcom,sde-dma-gc", false, PROP_TYPE_U32_ARRAY}, + {DMA_DGM_INVERSE_PMA, "qcom,sde-dma-inverse-pma", false, + PROP_TYPE_BOOL}, + {DMA_CSC_OFF, "qcom,sde-dma-csc-off", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type ctl_prop[] = { + {HW_OFF, "qcom,sde-ctl-off", true, PROP_TYPE_U32_ARRAY}, + {HW_LEN, "qcom,sde-ctl-size", false, PROP_TYPE_U32}, + {HW_DISP, "qcom,sde-ctl-display-pref", false, PROP_TYPE_STRING_ARRAY}, +}; + +struct sde_prop_type mixer_blend_prop[] = { + {MIXER_BLEND_OP_OFF, "qcom,sde-mixer-blend-op-off", true, + PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type mixer_prop[] = { + {MIXER_OFF, "qcom,sde-mixer-off", true, PROP_TYPE_U32_ARRAY}, + {MIXER_LEN, "qcom,sde-mixer-size", false, PROP_TYPE_U32}, + {MIXER_PAIR_MASK, "qcom,sde-mixer-pair-mask", true, + PROP_TYPE_U32_ARRAY}, + {MIXER_BLOCKS, "qcom,sde-mixer-blocks", false, PROP_TYPE_NODE}, + {MIXER_DISP, "qcom,sde-mixer-display-pref", false, + PROP_TYPE_STRING_ARRAY}, + {MIXER_CWB, "qcom,sde-mixer-cwb-pref", false, + PROP_TYPE_STRING_ARRAY}, +}; + +static struct sde_prop_type mixer_blocks_prop[] = { + {MIXER_GC_PROP, "qcom,sde-mixer-gc", false, PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type dspp_top_prop[] = { + {DSPP_TOP_OFF, "qcom,sde-dspp-top-off", true, PROP_TYPE_U32}, + {DSPP_TOP_SIZE, "qcom,sde-dspp-top-size", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type dspp_prop[] = { + {DSPP_OFF, "qcom,sde-dspp-off", true, PROP_TYPE_U32_ARRAY}, + {DSPP_SIZE, "qcom,sde-dspp-size", false, PROP_TYPE_U32}, + {DSPP_BLOCKS, "qcom,sde-dspp-blocks", false, PROP_TYPE_NODE}, +}; + +static struct sde_prop_type dspp_blocks_prop[] = { + {DSPP_IGC_PROP, "qcom,sde-dspp-igc", false, PROP_TYPE_U32_ARRAY}, + {DSPP_PCC_PROP, "qcom,sde-dspp-pcc", false, PROP_TYPE_U32_ARRAY}, + {DSPP_GC_PROP, "qcom,sde-dspp-gc", false, PROP_TYPE_U32_ARRAY}, + {DSPP_HSIC_PROP, "qcom,sde-dspp-hsic", false, PROP_TYPE_U32_ARRAY}, + {DSPP_MEMCOLOR_PROP, "qcom,sde-dspp-memcolor", false, + PROP_TYPE_U32_ARRAY}, + {DSPP_SIXZONE_PROP, "qcom,sde-dspp-sixzone", false, + PROP_TYPE_U32_ARRAY}, + {DSPP_GAMUT_PROP, "qcom,sde-dspp-gamut", false, PROP_TYPE_U32_ARRAY}, + {DSPP_DITHER_PROP, "qcom,sde-dspp-dither", false, PROP_TYPE_U32_ARRAY}, + {DSPP_HIST_PROP, "qcom,sde-dspp-hist", false, PROP_TYPE_U32_ARRAY}, + {DSPP_VLUT_PROP, "qcom,sde-dspp-vlut", false, PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type ad_prop[] = { + {AD_OFF, "qcom,sde-dspp-ad-off", false, PROP_TYPE_U32_ARRAY}, + {AD_VERSION, "qcom,sde-dspp-ad-version", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type ltm_prop[] = { + {LTM_OFF, "qcom,sde-dspp-ltm-off", false, PROP_TYPE_U32_ARRAY}, + {LTM_VERSION, "qcom,sde-dspp-ltm-version", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type ds_top_prop[] = { + {DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32}, + {DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32}, + {DS_TOP_INPUT_LINEWIDTH, "qcom,sde-max-dest-scaler-input-linewidth", + false, PROP_TYPE_U32}, + {DS_TOP_OUTPUT_LINEWIDTH, "qcom,sde-max-dest-scaler-output-linewidth", + false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type ds_prop[] = { + {DS_OFF, "qcom,sde-dest-scaler-off", false, PROP_TYPE_U32_ARRAY}, + {DS_LEN, "qcom,sde-dest-scaler-size", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type pp_prop[] = { + {PP_OFF, "qcom,sde-pp-off", true, PROP_TYPE_U32_ARRAY}, + {PP_LEN, "qcom,sde-pp-size", false, PROP_TYPE_U32}, + {TE_OFF, "qcom,sde-te-off", false, PROP_TYPE_U32_ARRAY}, + {TE_LEN, "qcom,sde-te-size", false, PROP_TYPE_U32}, + {TE2_OFF, "qcom,sde-te2-off", false, PROP_TYPE_U32_ARRAY}, + {TE2_LEN, "qcom,sde-te2-size", false, PROP_TYPE_U32}, + {PP_SLAVE, "qcom,sde-pp-slave", false, PROP_TYPE_U32_ARRAY}, + {DITHER_OFF, "qcom,sde-dither-off", false, PROP_TYPE_U32_ARRAY}, + {DITHER_LEN, "qcom,sde-dither-size", false, PROP_TYPE_U32}, + {DITHER_VER, "qcom,sde-dither-version", false, PROP_TYPE_U32}, + {PP_MERGE_3D_ID, "qcom,sde-pp-merge-3d-id", false, PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type dsc_prop[] = { + {DSC_OFF, "qcom,sde-dsc-off", false, PROP_TYPE_U32_ARRAY}, + {DSC_LEN, "qcom,sde-dsc-size", false, PROP_TYPE_U32}, + {DSC_PAIR_MASK, "qcom,sde-dsc-pair-mask", false, PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type cdm_prop[] = { + {HW_OFF, "qcom,sde-cdm-off", false, PROP_TYPE_U32_ARRAY}, + {HW_LEN, "qcom,sde-cdm-size", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type intf_prop[] = { + {INTF_OFF, "qcom,sde-intf-off", true, PROP_TYPE_U32_ARRAY}, + {INTF_LEN, "qcom,sde-intf-size", false, PROP_TYPE_U32}, + {INTF_PREFETCH, "qcom,sde-intf-max-prefetch-lines", false, + PROP_TYPE_U32_ARRAY}, + {INTF_TYPE, "qcom,sde-intf-type", false, PROP_TYPE_STRING_ARRAY}, +}; + +static struct sde_prop_type wb_prop[] = { + {WB_OFF, "qcom,sde-wb-off", false, PROP_TYPE_U32_ARRAY}, + {WB_LEN, "qcom,sde-wb-size", false, PROP_TYPE_U32}, + {WB_ID, "qcom,sde-wb-id", false, PROP_TYPE_U32_ARRAY}, + {WB_XIN_ID, "qcom,sde-wb-xin-id", false, PROP_TYPE_U32_ARRAY}, + {WB_CLK_CTRL, "qcom,sde-wb-clk-ctrl", false, + PROP_TYPE_BIT_OFFSET_ARRAY}, +}; + +static struct sde_prop_type vbif_prop[] = { + {VBIF_OFF, "qcom,sde-vbif-off", true, PROP_TYPE_U32_ARRAY}, + {VBIF_LEN, "qcom,sde-vbif-size", false, PROP_TYPE_U32}, + {VBIF_ID, "qcom,sde-vbif-id", false, PROP_TYPE_U32_ARRAY}, + {VBIF_DEFAULT_OT_RD_LIMIT, "qcom,sde-vbif-default-ot-rd-limit", false, + PROP_TYPE_U32}, + {VBIF_DEFAULT_OT_WR_LIMIT, "qcom,sde-vbif-default-ot-wr-limit", false, + PROP_TYPE_U32}, + {VBIF_DYNAMIC_OT_RD_LIMIT, "qcom,sde-vbif-dynamic-ot-rd-limit", false, + PROP_TYPE_U32_ARRAY}, + {VBIF_DYNAMIC_OT_WR_LIMIT, "qcom,sde-vbif-dynamic-ot-wr-limit", false, + PROP_TYPE_U32_ARRAY}, + {VBIF_MEMTYPE_0, "qcom,sde-vbif-memtype-0", false, PROP_TYPE_U32_ARRAY}, + {VBIF_MEMTYPE_1, "qcom,sde-vbif-memtype-1", false, PROP_TYPE_U32_ARRAY}, + {VBIF_QOS_RT_REMAP, "qcom,sde-vbif-qos-rt-remap", false, + PROP_TYPE_U32_ARRAY}, + {VBIF_QOS_NRT_REMAP, "qcom,sde-vbif-qos-nrt-remap", false, + PROP_TYPE_U32_ARRAY}, + {VBIF_QOS_CWB_REMAP, "qcom,sde-vbif-qos-cwb-remap", false, + PROP_TYPE_U32_ARRAY}, + {VBIF_QOS_LUTDMA_REMAP, "qcom,sde-vbif-qos-lutdma-remap", false, + PROP_TYPE_U32_ARRAY}, +}; + +static struct sde_prop_type uidle_prop[] = { + {UIDLE_OFF, "qcom,sde-uidle-off", false, PROP_TYPE_U32}, + {UIDLE_LEN, "qcom,sde-uidle-size", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type reg_dma_prop[REG_DMA_PROP_MAX] = { + [REG_DMA_OFF] = {REG_DMA_OFF, "qcom,sde-reg-dma-off", false, + PROP_TYPE_U32}, + [REG_DMA_VERSION] = {REG_DMA_VERSION, "qcom,sde-reg-dma-version", + false, PROP_TYPE_U32}, + [REG_DMA_TRIGGER_OFF] = {REG_DMA_TRIGGER_OFF, + "qcom,sde-reg-dma-trigger-off", false, + PROP_TYPE_U32}, + [REG_DMA_BROADCAST_DISABLED] = {REG_DMA_BROADCAST_DISABLED, + "qcom,sde-reg-dma-broadcast-disabled", false, PROP_TYPE_BOOL}, + [REG_DMA_XIN_ID] = {REG_DMA_XIN_ID, + "qcom,sde-reg-dma-xin-id", false, PROP_TYPE_U32}, + [REG_DMA_CLK_CTRL] = {REG_DMA_XIN_ID, + "qcom,sde-reg-dma-clk-ctrl", false, PROP_TYPE_BIT_OFFSET_ARRAY}, +}; + +static struct sde_prop_type merge_3d_prop[] = { + {HW_OFF, "qcom,sde-merge-3d-off", false, PROP_TYPE_U32_ARRAY}, + {HW_LEN, "qcom,sde-merge-3d-size", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type qdss_prop[] = { + {HW_OFF, "qcom,sde-qdss-off", false, PROP_TYPE_U32_ARRAY}, + {HW_LEN, "qcom,sde-qdss-size", false, PROP_TYPE_U32}, +}; + +static struct sde_prop_type limit_usecase_prop[] = { + {LIMIT_NAME, "qcom,sde-limit-name", false, PROP_TYPE_STRING}, + {LIMIT_USECASE, "qcom,sde-limit-cases", false, PROP_TYPE_STRING_ARRAY}, + {LIMIT_ID, "qcom,sde-limit-ids", false, PROP_TYPE_U32_ARRAY}, + {LIMIT_VALUE, "qcom,sde-limit-values", false, + PROP_TYPE_BIT_OFFSET_ARRAY}, +}; + +/************************************************************* + * static API list + *************************************************************/ + +static int _parse_dt_u32_handler(struct device_node *np, + char *prop_name, u32 *offsets, int len, bool mandatory) +{ + int rc = -EINVAL; + + if (len > MAX_SDE_HW_BLK) { + SDE_ERROR( + "prop: %s tries out of bound access for u32 array read len: %d\n", + prop_name, len); + return -E2BIG; + } + + rc = of_property_read_u32_array(np, prop_name, offsets, len); + if (rc && mandatory) + SDE_ERROR("mandatory prop: %s u32 array read len:%d\n", + prop_name, len); + else if (rc) + SDE_DEBUG("optional prop: %s u32 array read len:%d\n", + prop_name, len); + + return rc; +} + +static int _parse_dt_bit_offset(struct device_node *np, + char *prop_name, struct sde_prop_value *prop_value, u32 prop_index, + u32 count, bool mandatory) +{ + int rc = 0, len, i, j; + const u32 *arr; + + arr = of_get_property(np, prop_name, &len); + if (arr) { + len /= sizeof(u32); + len &= ~0x1; + + if (len > (MAX_SDE_HW_BLK * MAX_BIT_OFFSET)) { + SDE_ERROR( + "prop: %s len: %d will lead to out of bound access\n", + prop_name, len / MAX_BIT_OFFSET); + return -E2BIG; + } + + for (i = 0, j = 0; i < len; j++) { + PROP_BITVALUE_ACCESS(prop_value, prop_index, j, 0) = + be32_to_cpu(arr[i]); + i++; + PROP_BITVALUE_ACCESS(prop_value, prop_index, j, 1) = + be32_to_cpu(arr[i]); + i++; + } + } else { + if (mandatory) { + SDE_ERROR("error mandatory property '%s' not found\n", + prop_name); + rc = -EINVAL; + } else { + SDE_DEBUG("error optional property '%s' not found\n", + prop_name); + } + } + + return rc; +} + +static int _validate_dt_entry(struct device_node *np, + struct sde_prop_type *sde_prop, u32 prop_size, int *prop_count, + int *off_count) +{ + int rc = 0, i, val; + struct device_node *snp = NULL; + + if (off_count) { + *off_count = of_property_count_u32_elems(np, + sde_prop[0].prop_name); + if ((*off_count > MAX_BLOCKS) || (*off_count < 0)) { + if (sde_prop[0].is_mandatory) { + SDE_ERROR( + "invalid hw offset prop name:%s count: %d\n", + sde_prop[0].prop_name, *off_count); + rc = -EINVAL; + } + *off_count = 0; + memset(prop_count, 0, sizeof(int) * prop_size); + return rc; + } + } + + for (i = 0; i < prop_size; i++) { + switch (sde_prop[i].type) { + case PROP_TYPE_U32: + rc = of_property_read_u32(np, sde_prop[i].prop_name, + &val); + break; + case PROP_TYPE_U32_ARRAY: + prop_count[i] = of_property_count_u32_elems(np, + sde_prop[i].prop_name); + if (prop_count[i] < 0) + rc = prop_count[i]; + break; + case PROP_TYPE_STRING_ARRAY: + prop_count[i] = of_property_count_strings(np, + sde_prop[i].prop_name); + if (prop_count[i] < 0) + rc = prop_count[i]; + break; + case PROP_TYPE_BIT_OFFSET_ARRAY: + of_get_property(np, sde_prop[i].prop_name, &val); + prop_count[i] = val / (MAX_BIT_OFFSET * sizeof(u32)); + break; + case PROP_TYPE_NODE: + snp = of_get_child_by_name(np, + sde_prop[i].prop_name); + if (!snp) + rc = -EINVAL; + break; + default: + SDE_DEBUG("invalid property type:%d\n", + sde_prop[i].type); + break; + } + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d prop_count:%d\n", + i, sde_prop[i].prop_name, + sde_prop[i].type, prop_count[i]); + + if (rc && sde_prop[i].is_mandatory && + ((sde_prop[i].type == PROP_TYPE_U32) || + (sde_prop[i].type == PROP_TYPE_NODE))) { + SDE_ERROR("prop:%s not present\n", + sde_prop[i].prop_name); + goto end; + } else if (sde_prop[i].type == PROP_TYPE_U32 || + sde_prop[i].type == PROP_TYPE_BOOL || + sde_prop[i].type == PROP_TYPE_NODE) { + rc = 0; + continue; + } + + if (off_count && (prop_count[i] != *off_count) && + sde_prop[i].is_mandatory) { + SDE_ERROR( + "prop:%s count:%d is different compared to offset array:%d\n", + sde_prop[i].prop_name, + prop_count[i], *off_count); + rc = -EINVAL; + goto end; + } else if (off_count && prop_count[i] != *off_count) { + SDE_DEBUG( + "prop:%s count:%d is different compared to offset array:%d\n", + sde_prop[i].prop_name, + prop_count[i], *off_count); + rc = 0; + prop_count[i] = 0; + } + if (prop_count[i] < 0) { + prop_count[i] = 0; + if (sde_prop[i].is_mandatory) { + SDE_ERROR("prop:%s count:%d is negative\n", + sde_prop[i].prop_name, prop_count[i]); + rc = -EINVAL; + } else { + rc = 0; + SDE_DEBUG("prop:%s count:%d is negative\n", + sde_prop[i].prop_name, prop_count[i]); + } + } + } + +end: + return rc; +} + +static int _read_dt_entry(struct device_node *np, + struct sde_prop_type *sde_prop, u32 prop_size, int *prop_count, + bool *prop_exists, + struct sde_prop_value *prop_value) +{ + int rc = 0, i, j; + + for (i = 0; i < prop_size; i++) { + prop_exists[i] = true; + switch (sde_prop[i].type) { + case PROP_TYPE_U32: + rc = of_property_read_u32(np, sde_prop[i].prop_name, + &PROP_VALUE_ACCESS(prop_value, i, 0)); + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d value:0x%x\n", + i, sde_prop[i].prop_name, + sde_prop[i].type, + PROP_VALUE_ACCESS(prop_value, i, 0)); + if (rc) + prop_exists[i] = false; + break; + case PROP_TYPE_BOOL: + PROP_VALUE_ACCESS(prop_value, i, 0) = + of_property_read_bool(np, + sde_prop[i].prop_name); + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d value:0x%x\n", + i, sde_prop[i].prop_name, + sde_prop[i].type, + PROP_VALUE_ACCESS(prop_value, i, 0)); + break; + case PROP_TYPE_U32_ARRAY: + rc = _parse_dt_u32_handler(np, sde_prop[i].prop_name, + &PROP_VALUE_ACCESS(prop_value, i, 0), + prop_count[i], sde_prop[i].is_mandatory); + if (rc && sde_prop[i].is_mandatory) { + SDE_ERROR( + "%s prop validation success but read failed\n", + sde_prop[i].prop_name); + prop_exists[i] = false; + goto end; + } else { + if (rc) + prop_exists[i] = false; + /* only for debug purpose */ + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d", + i, sde_prop[i].prop_name, + sde_prop[i].type); + for (j = 0; j < prop_count[i]; j++) + SDE_DEBUG(" value[%d]:0x%x ", j, + PROP_VALUE_ACCESS(prop_value, i, + j)); + SDE_DEBUG("\n"); + } + break; + case PROP_TYPE_BIT_OFFSET_ARRAY: + rc = _parse_dt_bit_offset(np, sde_prop[i].prop_name, + prop_value, i, prop_count[i], + sde_prop[i].is_mandatory); + if (rc && sde_prop[i].is_mandatory) { + SDE_ERROR( + "%s prop validation success but read failed\n", + sde_prop[i].prop_name); + prop_exists[i] = false; + goto end; + } else { + if (rc) + prop_exists[i] = false; + SDE_DEBUG( + "prop id:%d prop name:%s prop type:%d", + i, sde_prop[i].prop_name, + sde_prop[i].type); + for (j = 0; j < prop_count[i]; j++) + SDE_DEBUG( + "count[%d]: bit:0x%x off:0x%x\n", j, + PROP_BITVALUE_ACCESS(prop_value, + i, j, 0), + PROP_BITVALUE_ACCESS(prop_value, + i, j, 1)); + SDE_DEBUG("\n"); + } + break; + case PROP_TYPE_NODE: + /* Node will be parsed in calling function */ + rc = 0; + break; + default: + SDE_DEBUG("invalid property type:%d\n", + sde_prop[i].type); + break; + } + rc = 0; + } + +end: + return rc; +} + +static void _sde_sspp_setup_vig(struct sde_mdss_cfg *sde_cfg, + struct sde_sspp_cfg *sspp, struct sde_sspp_sub_blks *sblk, + bool *prop_exists, struct sde_prop_value *prop_value, u32 *vig_count) +{ + sblk->maxlinewidth = sde_cfg->vig_sspp_linewidth; + sblk->maxupscale = MAX_UPSCALE_RATIO; + sblk->maxdwnscale = MAX_DOWNSCALE_RATIO; + sspp->id = SSPP_VIG0 + *vig_count; + snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u", + sspp->id - SSPP_VIG0); + sspp->clk_ctrl = SDE_CLK_CTRL_VIG0 + *vig_count; + sspp->type = SSPP_TYPE_VIG; + set_bit(SDE_PERF_SSPP_QOS, &sspp->perf_features); + if (sde_cfg->vbif_qos_nlvl == 8) + set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features); + (*vig_count)++; + + sblk->format_list = sde_cfg->vig_formats; + sblk->virt_format_list = sde_cfg->virt_vig_formats; + + if (!prop_value) + return; + + if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED2) { + set_bit(SDE_SSPP_SCALER_QSEED2, &sspp->features); + sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED2; + sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_QSEED_OFF, 0); + sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value, + VIG_QSEED_LEN, 0); + snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_scaler%u", sspp->id - SSPP_VIG0); + } else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3) { + set_bit(SDE_SSPP_SCALER_QSEED3, &sspp->features); + sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED3; + sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_QSEED_OFF, 0); + sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value, + VIG_QSEED_LEN, 0); + snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_scaler%u", sspp->id - SSPP_VIG0); + } else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3LITE) { + set_bit(SDE_SSPP_SCALER_QSEED3LITE, &sspp->features); + sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED3LITE; + sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_QSEED_OFF, 0); + sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value, + VIG_QSEED_LEN, 0); + snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_scaler%u", sspp->id - SSPP_VIG0); + } + + sblk->csc_blk.id = SDE_SSPP_CSC; + snprintf(sblk->csc_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_csc%u", sspp->id - SSPP_VIG0); + if (sde_cfg->csc_type == SDE_SSPP_CSC) { + set_bit(SDE_SSPP_CSC, &sspp->features); + sblk->csc_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_CSC_OFF, 0); + } else if (sde_cfg->csc_type == SDE_SSPP_CSC_10BIT) { + set_bit(SDE_SSPP_CSC_10BIT, &sspp->features); + sblk->csc_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_CSC_OFF, 0); + } + + sblk->hsic_blk.id = SDE_SSPP_HSIC; + snprintf(sblk->hsic_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_hsic%u", sspp->id - SSPP_VIG0); + if (prop_exists[VIG_HSIC_PROP]) { + sblk->hsic_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_HSIC_PROP, 0); + sblk->hsic_blk.version = PROP_VALUE_ACCESS(prop_value, + VIG_HSIC_PROP, 1); + sblk->hsic_blk.len = 0; + set_bit(SDE_SSPP_HSIC, &sspp->features); + } + + sblk->memcolor_blk.id = SDE_SSPP_MEMCOLOR; + snprintf(sblk->memcolor_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_memcolor%u", sspp->id - SSPP_VIG0); + if (prop_exists[VIG_MEMCOLOR_PROP]) { + sblk->memcolor_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_MEMCOLOR_PROP, 0); + sblk->memcolor_blk.version = PROP_VALUE_ACCESS(prop_value, + VIG_MEMCOLOR_PROP, 1); + sblk->memcolor_blk.len = 0; + set_bit(SDE_SSPP_MEMCOLOR, &sspp->features); + } + + sblk->pcc_blk.id = SDE_SSPP_PCC; + snprintf(sblk->pcc_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_pcc%u", sspp->id - SSPP_VIG0); + if (prop_exists[VIG_PCC_PROP]) { + sblk->pcc_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_PCC_PROP, 0); + sblk->pcc_blk.version = PROP_VALUE_ACCESS(prop_value, + VIG_PCC_PROP, 1); + sblk->pcc_blk.len = 0; + set_bit(SDE_SSPP_PCC, &sspp->features); + } + + if (prop_exists[VIG_GAMUT_PROP]) { + sblk->gamut_blk.id = SDE_SSPP_VIG_GAMUT; + snprintf(sblk->gamut_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_vig_gamut%u", sspp->id - SSPP_VIG0); + sblk->gamut_blk.base = PROP_VALUE_ACCESS(prop_value, + VIG_GAMUT_PROP, 0); + sblk->gamut_blk.version = PROP_VALUE_ACCESS(prop_value, + VIG_GAMUT_PROP, 1); + sblk->gamut_blk.len = 0; + set_bit(SDE_SSPP_VIG_GAMUT, &sspp->features); + } + + if (prop_exists[VIG_IGC_PROP]) { + sblk->igc_blk[0].id = SDE_SSPP_VIG_IGC; + snprintf(sblk->igc_blk[0].name, SDE_HW_BLK_NAME_LEN, + "sspp_vig_igc%u", sspp->id - SSPP_VIG0); + sblk->igc_blk[0].base = PROP_VALUE_ACCESS(prop_value, + VIG_IGC_PROP, 0); + sblk->igc_blk[0].version = PROP_VALUE_ACCESS(prop_value, + VIG_IGC_PROP, 1); + sblk->igc_blk[0].len = 0; + set_bit(SDE_SSPP_VIG_IGC, &sspp->features); + } + + if (PROP_VALUE_ACCESS(prop_value, VIG_INVERSE_PMA, 0)) + set_bit(SDE_SSPP_INVERSE_PMA, &sspp->features); + + if (sde_cfg->true_inline_rot_rev > 0) { + set_bit(SDE_SSPP_TRUE_INLINE_ROT, &sspp->features); + sblk->in_rot_format_list = sde_cfg->inline_rot_formats; + sblk->in_rot_maxheight = sde_cfg->inline_linewidth ? + sde_cfg->inline_linewidth : + MAX_PRE_ROT_HEIGHT_INLINE_ROT_DEFAULT; + } + + if (IS_SDE_INLINE_ROT_REV_200(sde_cfg->true_inline_rot_rev)) { + set_bit(SDE_SSPP_PREDOWNSCALE, &sspp->features); + sblk->in_rot_maxdwnscale_rt_num = + MAX_DOWNSCALE_RATIO_INROT_PD_RT_NUMERATOR; + sblk->in_rot_maxdwnscale_rt_denom = + MAX_DOWNSCALE_RATIO_INROT_PD_RT_DENOMINATOR; + sblk->in_rot_maxdwnscale_nrt = + MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT; + sblk->in_rot_maxdwnscale_rt_nopd_num = + MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR; + sblk->in_rot_maxdwnscale_rt_nopd_denom = + MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR; + } else if (IS_SDE_INLINE_ROT_REV_100(sde_cfg->true_inline_rot_rev)) { + sblk->in_rot_maxdwnscale_rt_num = + MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_NUMERATOR; + sblk->in_rot_maxdwnscale_rt_denom = + MAX_DOWNSCALE_RATIO_INROT_NOPD_RT_DENOMINATOR; + sblk->in_rot_maxdwnscale_nrt = + MAX_DOWNSCALE_RATIO_INROT_NRT_DEFAULT; + } + + if (sde_cfg->sc_cfg.has_sys_cache) { + set_bit(SDE_PERF_SSPP_SYS_CACHE, &sspp->perf_features); + sblk->llcc_scid = sde_cfg->sc_cfg.llcc_scid; + sblk->llcc_slice_size = + sde_cfg->sc_cfg.llcc_slice_size; + } +} + +static void _sde_sspp_setup_rgb(struct sde_mdss_cfg *sde_cfg, + struct sde_sspp_cfg *sspp, struct sde_sspp_sub_blks *sblk, + bool *prop_exists, struct sde_prop_value *prop_value, u32 *rgb_count) +{ + sblk->maxupscale = MAX_UPSCALE_RATIO; + sblk->maxdwnscale = MAX_DOWNSCALE_RATIO; + sspp->id = SSPP_RGB0 + *rgb_count; + snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u", + sspp->id - SSPP_VIG0); + sspp->clk_ctrl = SDE_CLK_CTRL_RGB0 + *rgb_count; + sspp->type = SSPP_TYPE_RGB; + set_bit(SDE_PERF_SSPP_QOS, &sspp->perf_features); + if (sde_cfg->vbif_qos_nlvl == 8) + set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features); + (*rgb_count)++; + + if (!prop_value) + return; + + if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED2) { + set_bit(SDE_SSPP_SCALER_RGB, &sspp->features); + sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED2; + sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value, + RGB_SCALER_OFF, 0); + sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value, + RGB_SCALER_LEN, 0); + snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_scaler%u", sspp->id - SSPP_VIG0); + } else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3) { + set_bit(SDE_SSPP_SCALER_RGB, &sspp->features); + sblk->scaler_blk.id = SDE_SSPP_SCALER_QSEED3; + sblk->scaler_blk.base = PROP_VALUE_ACCESS(prop_value, + RGB_SCALER_LEN, 0); + sblk->scaler_blk.len = PROP_VALUE_ACCESS(prop_value, + SSPP_SCALE_SIZE, 0); + snprintf(sblk->scaler_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_scaler%u", sspp->id - SSPP_VIG0); + } + + sblk->pcc_blk.id = SDE_SSPP_PCC; + if (prop_exists[RGB_PCC_PROP]) { + sblk->pcc_blk.base = PROP_VALUE_ACCESS(prop_value, + RGB_PCC_PROP, 0); + sblk->pcc_blk.version = PROP_VALUE_ACCESS(prop_value, + RGB_PCC_PROP, 1); + sblk->pcc_blk.len = 0; + set_bit(SDE_SSPP_PCC, &sspp->features); + } + + sblk->format_list = sde_cfg->dma_formats; + sblk->virt_format_list = NULL; +} + +static void _sde_sspp_setup_cursor(struct sde_mdss_cfg *sde_cfg, + struct sde_sspp_cfg *sspp, struct sde_sspp_sub_blks *sblk, + struct sde_prop_value *prop_value, u32 *cursor_count) +{ + if (!IS_SDE_MAJOR_MINOR_SAME(sde_cfg->hwversion, SDE_HW_VER_300)) + SDE_ERROR("invalid sspp type %d, xin id %d\n", + sspp->type, sspp->xin_id); + set_bit(SDE_SSPP_CURSOR, &sspp->features); + sblk->maxupscale = SSPP_UNITY_SCALE; + sblk->maxdwnscale = SSPP_UNITY_SCALE; + sblk->format_list = sde_cfg->cursor_formats; + sblk->virt_format_list = NULL; + sspp->id = SSPP_CURSOR0 + *cursor_count; + snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u", + sspp->id - SSPP_VIG0); + sspp->clk_ctrl = SDE_CLK_CTRL_CURSOR0 + *cursor_count; + sspp->type = SSPP_TYPE_CURSOR; + (*cursor_count)++; +} + +static void _sde_sspp_setup_dma(struct sde_mdss_cfg *sde_cfg, + struct sde_sspp_cfg *sspp, struct sde_sspp_sub_blks *sblk, + bool prop_exists[][DMA_PROP_MAX], struct sde_prop_value *prop_value, + u32 *dma_count, u32 dgm_count) +{ + u32 i = 0; + + sblk->maxupscale = SSPP_UNITY_SCALE; + sblk->maxdwnscale = SSPP_UNITY_SCALE; + sblk->format_list = sde_cfg->dma_formats; + sblk->virt_format_list = sde_cfg->dma_formats; + sspp->id = SSPP_DMA0 + *dma_count; + sspp->clk_ctrl = SDE_CLK_CTRL_DMA0 + *dma_count; + snprintf(sspp->name, SDE_HW_BLK_NAME_LEN, "sspp_%u", + sspp->id - SSPP_VIG0); + sspp->type = SSPP_TYPE_DMA; + set_bit(SDE_PERF_SSPP_QOS, &sspp->perf_features); + if (sde_cfg->vbif_qos_nlvl == 8) + set_bit(SDE_PERF_SSPP_QOS_8LVL, &sspp->perf_features); + (*dma_count)++; + + if (!prop_value) + return; + + sblk->num_igc_blk = dgm_count; + sblk->num_gc_blk = dgm_count; + sblk->num_dgm_csc_blk = dgm_count; + for (i = 0; i < dgm_count; i++) { + if (prop_exists[i][DMA_IGC_PROP]) { + sblk->igc_blk[i].id = SDE_SSPP_DMA_IGC; + snprintf(sblk->igc_blk[i].name, SDE_HW_BLK_NAME_LEN, + "sspp_dma_igc%u", sspp->id - SSPP_DMA0); + sblk->igc_blk[i].base = PROP_VALUE_ACCESS( + &prop_value[i * DMA_PROP_MAX], DMA_IGC_PROP, 0); + sblk->igc_blk[i].version = PROP_VALUE_ACCESS( + &prop_value[i * DMA_PROP_MAX], DMA_IGC_PROP, 1); + sblk->igc_blk[i].len = 0; + set_bit(SDE_SSPP_DMA_IGC, &sspp->features); + } + + if (prop_exists[i][DMA_GC_PROP]) { + sblk->gc_blk[i].id = SDE_SSPP_DMA_GC; + snprintf(sblk->gc_blk[0].name, SDE_HW_BLK_NAME_LEN, + "sspp_dma_gc%u", sspp->id - SSPP_DMA0); + sblk->gc_blk[i].base = PROP_VALUE_ACCESS( + &prop_value[i * DMA_PROP_MAX], DMA_GC_PROP, 0); + sblk->gc_blk[i].version = PROP_VALUE_ACCESS( + &prop_value[i * DMA_PROP_MAX], DMA_GC_PROP, 1); + sblk->gc_blk[i].len = 0; + set_bit(SDE_SSPP_DMA_GC, &sspp->features); + } + + if (PROP_VALUE_ACCESS(&prop_value[i * DMA_PROP_MAX], + DMA_DGM_INVERSE_PMA, 0)) + set_bit(SDE_SSPP_DGM_INVERSE_PMA, &sspp->features); + + if (prop_exists[i][DMA_CSC_OFF]) { + sblk->dgm_csc_blk[i].id = SDE_SSPP_DGM_CSC; + snprintf(sblk->csc_blk.name, SDE_HW_BLK_NAME_LEN, + "sspp_dgm_csc%u", sspp->id - SSPP_DMA0); + set_bit(SDE_SSPP_DGM_CSC, &sspp->features); + sblk->dgm_csc_blk[i].base = PROP_VALUE_ACCESS( + &prop_value[i * DMA_PROP_MAX], DMA_CSC_OFF, 0); + } + } +} + +static int sde_dgm_parse_dt(struct device_node *np, u32 index, + struct sde_prop_value *prop_value, bool *prop_exists) +{ + int rc = 0; + u32 child_idx = 0; + int prop_count[DMA_PROP_MAX] = {0}; + struct device_node *dgm_snp = NULL; + + for_each_child_of_node(np, dgm_snp) { + if (index != child_idx++) + continue; + rc = _validate_dt_entry(dgm_snp, dma_prop, ARRAY_SIZE(dma_prop), + prop_count, NULL); + if (rc) + return rc; + rc = _read_dt_entry(dgm_snp, dma_prop, ARRAY_SIZE(dma_prop), + prop_count, prop_exists, + prop_value); + } + + return rc; +} + +static int sde_sspp_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[SSPP_PROP_MAX], off_count, i, j; + int vig_prop_count[VIG_PROP_MAX], rgb_prop_count[RGB_PROP_MAX]; + bool prop_exists[SSPP_PROP_MAX], vig_prop_exists[VIG_PROP_MAX]; + bool rgb_prop_exists[RGB_PROP_MAX]; + bool dgm_prop_exists[SSPP_SUBBLK_COUNT_MAX][DMA_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + struct sde_prop_value *vig_prop_value = NULL, *rgb_prop_value = NULL; + struct sde_prop_value *dgm_prop_value = NULL; + const char *type; + struct sde_sspp_cfg *sspp; + struct sde_sspp_sub_blks *sblk; + u32 vig_count = 0, dma_count = 0, rgb_count = 0, cursor_count = 0; + u32 dgm_count = 0; + struct device_node *snp = NULL; + + prop_value = kcalloc(SSPP_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, sspp_prop, ARRAY_SIZE(sspp_prop), + prop_count, &off_count); + if (rc) + goto end; + + rc = _read_dt_entry(np, sspp_prop, ARRAY_SIZE(sspp_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + sde_cfg->sspp_count = off_count; + + /* get vig feature dt properties if they exist */ + snp = of_get_child_by_name(np, sspp_prop[SSPP_VIG_BLOCKS].prop_name); + if (snp) { + vig_prop_value = kcalloc(VIG_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!vig_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(snp, vig_prop, ARRAY_SIZE(vig_prop), + vig_prop_count, NULL); + if (rc) + goto end; + rc = _read_dt_entry(snp, vig_prop, ARRAY_SIZE(vig_prop), + vig_prop_count, vig_prop_exists, + vig_prop_value); + } + + /* get rgb feature dt properties if they exist */ + snp = of_get_child_by_name(np, sspp_prop[SSPP_RGB_BLOCKS].prop_name); + if (snp) { + rgb_prop_value = kcalloc(RGB_PROP_MAX, + sizeof(struct sde_prop_value), + GFP_KERNEL); + if (!rgb_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(snp, rgb_prop, ARRAY_SIZE(rgb_prop), + rgb_prop_count, NULL); + if (rc) + goto end; + rc = _read_dt_entry(snp, rgb_prop, ARRAY_SIZE(rgb_prop), + rgb_prop_count, rgb_prop_exists, + rgb_prop_value); + } + + /* get dma feature dt properties if they exist */ + snp = of_get_child_by_name(np, sspp_prop[SSPP_DMA_BLOCKS].prop_name); + if (snp) { + dgm_count = of_get_child_count(snp); + if (dgm_count > 0 && dgm_count <= SSPP_SUBBLK_COUNT_MAX) { + dgm_prop_value = kzalloc(dgm_count * DMA_PROP_MAX * + sizeof(struct sde_prop_value), + GFP_KERNEL); + if (!dgm_prop_value) { + rc = -ENOMEM; + goto end; + } + for (i = 0; i < dgm_count; i++) + sde_dgm_parse_dt(snp, i, + &dgm_prop_value[i * DMA_PROP_MAX], + &dgm_prop_exists[i][0]); + } + } + + for (i = 0; i < off_count; i++) { + sspp = sde_cfg->sspp + i; + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); + if (!sblk) { + rc = -ENOMEM; + /* catalog deinit will release the allocated blocks */ + goto end; + } + sspp->sblk = sblk; + + sspp->base = PROP_VALUE_ACCESS(prop_value, SSPP_OFF, i); + sspp->len = PROP_VALUE_ACCESS(prop_value, SSPP_SIZE, 0); + sblk->maxlinewidth = sde_cfg->max_sspp_linewidth; + + set_bit(SDE_SSPP_SRC, &sspp->features); + + if (sde_cfg->has_cdp) + set_bit(SDE_PERF_SSPP_CDP, &sspp->perf_features); + + if (sde_cfg->ts_prefill_rev == 1) { + set_bit(SDE_PERF_SSPP_TS_PREFILL, &sspp->perf_features); + } else if (sde_cfg->ts_prefill_rev == 2) { + set_bit(SDE_PERF_SSPP_TS_PREFILL, &sspp->perf_features); + set_bit(SDE_PERF_SSPP_TS_PREFILL_REC1, + &sspp->perf_features); + } + + sblk->smart_dma_priority = + PROP_VALUE_ACCESS(prop_value, SSPP_SMART_DMA, i); + + if (sblk->smart_dma_priority && sde_cfg->smart_dma_rev) + set_bit(sde_cfg->smart_dma_rev, &sspp->features); + + sblk->src_blk.id = SDE_SSPP_SRC; + + of_property_read_string_index(np, + sspp_prop[SSPP_TYPE].prop_name, i, &type); + if (!strcmp(type, "vig")) { + _sde_sspp_setup_vig(sde_cfg, sspp, sblk, + vig_prop_exists, vig_prop_value, &vig_count); + } else if (!strcmp(type, "rgb")) { + _sde_sspp_setup_rgb(sde_cfg, sspp, sblk, + rgb_prop_exists, rgb_prop_value, &rgb_count); + } else if (!strcmp(type, "cursor")) { + /* No prop values for cursor pipes */ + _sde_sspp_setup_cursor(sde_cfg, sspp, sblk, NULL, + &cursor_count); + } else if (!strcmp(type, "dma")) { + _sde_sspp_setup_dma(sde_cfg, sspp, sblk, + dgm_prop_exists, dgm_prop_value, &dma_count, + dgm_count); + } else { + SDE_ERROR("invalid sspp type:%s\n", type); + rc = -EINVAL; + goto end; + } + + if (sde_cfg->uidle_cfg.uidle_rev) + set_bit(SDE_PERF_SSPP_UIDLE, &sspp->perf_features); + + snprintf(sblk->src_blk.name, SDE_HW_BLK_NAME_LEN, "sspp_src_%u", + sspp->id - SSPP_VIG0); + + if (sspp->clk_ctrl >= SDE_CLK_CTRL_MAX) { + SDE_ERROR("%s: invalid clk ctrl: %d\n", + sblk->src_blk.name, sspp->clk_ctrl); + rc = -EINVAL; + goto end; + } + + if (sde_cfg->has_decimation) { + sblk->maxhdeciexp = MAX_HORZ_DECIMATION; + sblk->maxvdeciexp = MAX_VERT_DECIMATION; + } else { + sblk->maxhdeciexp = 0; + sblk->maxvdeciexp = 0; + } + + sspp->xin_id = PROP_VALUE_ACCESS(prop_value, SSPP_XIN, i); + sblk->pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE; + sblk->src_blk.len = PROP_VALUE_ACCESS(prop_value, SSPP_SIZE, 0); + + if (PROP_VALUE_ACCESS(prop_value, SSPP_EXCL_RECT, i) == 1) + set_bit(SDE_SSPP_EXCL_RECT, &sspp->features); + + if (prop_exists[SSPP_MAX_PER_PIPE_BW]) + sblk->max_per_pipe_bw = PROP_VALUE_ACCESS(prop_value, + SSPP_MAX_PER_PIPE_BW, i); + else + sblk->max_per_pipe_bw = DEFAULT_MAX_PER_PIPE_BW; + + if (prop_exists[SSPP_MAX_PER_PIPE_BW_HIGH]) + sblk->max_per_pipe_bw_high = + PROP_VALUE_ACCESS(prop_value, + SSPP_MAX_PER_PIPE_BW_HIGH, i); + else + sblk->max_per_pipe_bw_high = sblk->max_per_pipe_bw; + + for (j = 0; j < sde_cfg->mdp_count; j++) { + sde_cfg->mdp[j].clk_ctrls[sspp->clk_ctrl].reg_off = + PROP_BITVALUE_ACCESS(prop_value, + SSPP_CLK_CTRL, i, 0); + sde_cfg->mdp[j].clk_ctrls[sspp->clk_ctrl].bit_off = + PROP_BITVALUE_ACCESS(prop_value, + SSPP_CLK_CTRL, i, 1); + } + + SDE_DEBUG( + "xin:%d ram:%d clk%d:%x/%d\n", + sspp->xin_id, + sblk->pixel_ram_size, + sspp->clk_ctrl, + sde_cfg->mdp[0].clk_ctrls[sspp->clk_ctrl].reg_off, + sde_cfg->mdp[0].clk_ctrls[sspp->clk_ctrl].bit_off); + } + +end: + kfree(prop_value); + kfree(vig_prop_value); + kfree(rgb_prop_value); + kfree(dgm_prop_value); + return rc; +} + +static int sde_ctl_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[HW_PROP_MAX], i; + bool prop_exists[HW_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + struct sde_ctl_cfg *ctl; + u32 off_count; + + if (!sde_cfg) { + SDE_ERROR("invalid argument input param\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(HW_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->ctl_count = off_count; + + rc = _read_dt_entry(np, ctl_prop, ARRAY_SIZE(ctl_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + const char *disp_pref = NULL; + + ctl = sde_cfg->ctl + i; + ctl->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i); + ctl->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0); + ctl->id = CTL_0 + i; + snprintf(ctl->name, SDE_HW_BLK_NAME_LEN, "ctl_%u", + ctl->id - CTL_0); + + of_property_read_string_index(np, + ctl_prop[HW_DISP].prop_name, i, &disp_pref); + if (disp_pref && !strcmp(disp_pref, "primary")) + set_bit(SDE_CTL_PRIMARY_PREF, &ctl->features); + if ((i < MAX_SPLIT_DISPLAY_CTL) && + !(IS_SDE_CTL_REV_100(sde_cfg->ctl_rev))) + set_bit(SDE_CTL_SPLIT_DISPLAY, &ctl->features); + if (i < MAX_PP_SPLIT_DISPLAY_CTL) + set_bit(SDE_CTL_PINGPONG_SPLIT, &ctl->features); + if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) + set_bit(SDE_CTL_ACTIVE_CFG, &ctl->features); + if (IS_SDE_UIDLE_REV_100(sde_cfg->uidle_cfg.uidle_rev)) + set_bit(SDE_CTL_UIDLE, &ctl->features); + } +end: + kfree(prop_value); + return rc; +} + +void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, + uint32_t disp_type) +{ + u32 i, cnt = 0, sec_cnt = 0; + + if (disp_type == SDE_CONNECTOR_PRIMARY) { + for (i = 0; i < sde_cfg->mixer_count; i++) { + /* Check if lm was previously set for secondary */ + /* Clear pref, primary has higher priority */ + if (sde_cfg->mixer[i].features & + BIT(SDE_DISP_SECONDARY_PREF)) { + clear_bit(SDE_DISP_SECONDARY_PREF, + &sde_cfg->mixer[i].features); + sec_cnt++; + } + clear_bit(SDE_DISP_PRIMARY_PREF, + &sde_cfg->mixer[i].features); + + /* Set lm for primary pref */ + if (cnt < num_lm) { + set_bit(SDE_DISP_PRIMARY_PREF, + &sde_cfg->mixer[i].features); + cnt++; + } + + /* + * When all primary prefs have been set, + * and if 2 lms are required for secondary + * preference must be set with an lm pair + */ + if (cnt == num_lm && sec_cnt > 1 && + !test_bit(sde_cfg->mixer[i+1].id, + &sde_cfg->mixer[i].lm_pair_mask)) + continue; + + /* After primary pref is set, now re apply secondary */ + if (cnt >= num_lm && cnt < (num_lm + sec_cnt)) { + set_bit(SDE_DISP_SECONDARY_PREF, + &sde_cfg->mixer[i].features); + cnt++; + } + } + } else if (disp_type == SDE_CONNECTOR_SECONDARY) { + for (i = 0; i < sde_cfg->mixer_count; i++) { + clear_bit(SDE_DISP_SECONDARY_PREF, + &sde_cfg->mixer[i].features); + + /* + * If 2 lms are required for secondary + * preference must be set with an lm pair + */ + if (cnt == 0 && num_lm > 1 && + !test_bit(sde_cfg->mixer[i+1].id, + &sde_cfg->mixer[i].lm_pair_mask)) + continue; + + if (cnt < num_lm && !(sde_cfg->mixer[i].features & + BIT(SDE_DISP_PRIMARY_PREF))) { + set_bit(SDE_DISP_SECONDARY_PREF, + &sde_cfg->mixer[i].features); + cnt++; + } + } + } +} + +static int sde_mixer_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[MIXER_PROP_MAX], i, j; + int blocks_prop_count[MIXER_BLOCKS_PROP_MAX]; + int blend_prop_count[MIXER_BLEND_PROP_MAX]; + bool prop_exists[MIXER_PROP_MAX]; + bool blocks_prop_exists[MIXER_BLOCKS_PROP_MAX]; + bool blend_prop_exists[MIXER_BLEND_PROP_MAX]; + struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL; + struct sde_prop_value *blend_prop_value = NULL; + u32 off_count, blend_off_count, max_blendstages, lm_pair_mask; + struct sde_lm_cfg *mixer; + struct sde_lm_sub_blks *sblk; + int pp_count, dspp_count, ds_count, mixer_count; + u32 pp_idx, dspp_idx, ds_idx; + u32 mixer_base; + struct device_node *snp = NULL; + + if (!sde_cfg) { + SDE_ERROR("invalid argument input param\n"); + rc = -EINVAL; + goto end; + } + max_blendstages = sde_cfg->max_mixer_blendstages; + + prop_value = kcalloc(MIXER_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), + prop_count, &off_count); + if (rc) + goto end; + + rc = _read_dt_entry(np, mixer_prop, ARRAY_SIZE(mixer_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + pp_count = sde_cfg->pingpong_count; + dspp_count = sde_cfg->dspp_count; + ds_count = sde_cfg->ds_count; + + /* get mixer feature dt properties if they exist */ + snp = of_get_child_by_name(np, mixer_prop[MIXER_BLOCKS].prop_name); + if (snp) { + blocks_prop_value = kzalloc(MIXER_BLOCKS_PROP_MAX * + MAX_SDE_HW_BLK * sizeof(struct sde_prop_value), + GFP_KERNEL); + if (!blocks_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(snp, mixer_blocks_prop, + ARRAY_SIZE(mixer_blocks_prop), blocks_prop_count, NULL); + if (rc) + goto end; + rc = _read_dt_entry(snp, mixer_blocks_prop, + ARRAY_SIZE(mixer_blocks_prop), + blocks_prop_count, blocks_prop_exists, + blocks_prop_value); + } + + /* get the blend_op register offsets */ + blend_prop_value = kzalloc(MIXER_BLEND_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!blend_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(np, mixer_blend_prop, + ARRAY_SIZE(mixer_blend_prop), blend_prop_count, + &blend_off_count); + if (rc) + goto end; + + rc = _read_dt_entry(np, mixer_blend_prop, ARRAY_SIZE(mixer_blend_prop), + blend_prop_count, blend_prop_exists, blend_prop_value); + if (rc) + goto end; + + for (i = 0, mixer_count = 0, pp_idx = 0, dspp_idx = 0, + ds_idx = 0; i < off_count; i++) { + const char *disp_pref = NULL; + const char *cwb_pref = NULL; + + mixer_base = PROP_VALUE_ACCESS(prop_value, MIXER_OFF, i); + if (!mixer_base) + continue; + + mixer = sde_cfg->mixer + mixer_count; + + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); + if (!sblk) { + rc = -ENOMEM; + /* catalog deinit will release the allocated blocks */ + goto end; + } + mixer->sblk = sblk; + + mixer->base = mixer_base; + mixer->len = PROP_VALUE_ACCESS(prop_value, MIXER_LEN, 0); + mixer->id = LM_0 + i; + snprintf(mixer->name, SDE_HW_BLK_NAME_LEN, "lm_%u", + mixer->id - LM_0); + + if (!prop_exists[MIXER_LEN]) + mixer->len = DEFAULT_SDE_HW_BLOCK_LEN; + + lm_pair_mask = PROP_VALUE_ACCESS(prop_value, + MIXER_PAIR_MASK, i); + if (lm_pair_mask) + mixer->lm_pair_mask = 1 << lm_pair_mask; + + sblk->maxblendstages = max_blendstages; + sblk->maxwidth = sde_cfg->max_mixer_width; + + for (j = 0; j < blend_off_count; j++) + sblk->blendstage_base[j] = + PROP_VALUE_ACCESS(blend_prop_value, + MIXER_BLEND_OP_OFF, j); + + if (sde_cfg->has_src_split) + set_bit(SDE_MIXER_SOURCESPLIT, &mixer->features); + if (sde_cfg->has_dim_layer) + set_bit(SDE_DIM_LAYER, &mixer->features); + + of_property_read_string_index(np, + mixer_prop[MIXER_DISP].prop_name, i, &disp_pref); + if (disp_pref && !strcmp(disp_pref, "primary")) + set_bit(SDE_DISP_PRIMARY_PREF, &mixer->features); + + of_property_read_string_index(np, + mixer_prop[MIXER_CWB].prop_name, i, &cwb_pref); + if (cwb_pref && !strcmp(cwb_pref, "cwb")) + set_bit(SDE_DISP_CWB_PREF, &mixer->features); + + mixer->pingpong = pp_count > 0 ? pp_idx + PINGPONG_0 + : PINGPONG_MAX; + mixer->dspp = dspp_count > 0 ? dspp_idx + DSPP_0 + : DSPP_MAX; + mixer->ds = ds_count > 0 ? ds_idx + DS_0 : DS_MAX; + pp_count--; + dspp_count--; + ds_count--; + pp_idx++; + dspp_idx++; + ds_idx++; + + mixer_count++; + + sblk->gc.id = SDE_MIXER_GC; + if (blocks_prop_value && blocks_prop_exists[MIXER_GC_PROP]) { + sblk->gc.base = PROP_VALUE_ACCESS(blocks_prop_value, + MIXER_GC_PROP, 0); + sblk->gc.version = PROP_VALUE_ACCESS(blocks_prop_value, + MIXER_GC_PROP, 1); + sblk->gc.len = 0; + set_bit(SDE_MIXER_GC, &mixer->features); + } + } + sde_cfg->mixer_count = mixer_count; + +end: + kfree(prop_value); + kfree(blocks_prop_value); + kfree(blend_prop_value); + return rc; +} + +static int sde_intf_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[INTF_PROP_MAX], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[INTF_PROP_MAX]; + u32 off_count; + u32 dsi_count = 0, none_count = 0, hdmi_count = 0, dp_count = 0; + const char *type; + struct sde_intf_cfg *intf; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(INTF_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, intf_prop, ARRAY_SIZE(intf_prop), + prop_count, &off_count); + if (rc) + goto end; + + sde_cfg->intf_count = off_count; + + rc = _read_dt_entry(np, intf_prop, ARRAY_SIZE(intf_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + intf = sde_cfg->intf + i; + intf->base = PROP_VALUE_ACCESS(prop_value, INTF_OFF, i); + intf->len = PROP_VALUE_ACCESS(prop_value, INTF_LEN, 0); + intf->id = INTF_0 + i; + snprintf(intf->name, SDE_HW_BLK_NAME_LEN, "intf_%u", + intf->id - INTF_0); + + if (!prop_exists[INTF_LEN]) + intf->len = DEFAULT_SDE_HW_BLOCK_LEN; + + intf->prog_fetch_lines_worst_case = + !prop_exists[INTF_PREFETCH] ? + sde_cfg->perf.min_prefill_lines : + PROP_VALUE_ACCESS(prop_value, INTF_PREFETCH, i); + + of_property_read_string_index(np, + intf_prop[INTF_TYPE].prop_name, i, &type); + if (!strcmp(type, "dsi")) { + intf->type = INTF_DSI; + intf->controller_id = dsi_count; + dsi_count++; + } else if (!strcmp(type, "hdmi")) { + intf->type = INTF_HDMI; + intf->controller_id = hdmi_count; + hdmi_count++; + } else if (!strcmp(type, "dp")) { + intf->type = INTF_DP; + intf->controller_id = dp_count; + dp_count++; + } else { + intf->type = INTF_NONE; + intf->controller_id = none_count; + none_count++; + } + if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) + set_bit(SDE_INTF_INPUT_CTRL, &intf->features); + + if (IS_SDE_MAJOR_SAME((sde_cfg->hwversion), + SDE_HW_VER_500) || + IS_SDE_MAJOR_SAME((sde_cfg->hwversion), + SDE_HW_VER_600)) + set_bit(SDE_INTF_TE, &intf->features); + } + +end: + kfree(prop_value); + return rc; +} + +static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[WB_PROP_MAX], i, j; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[WB_PROP_MAX]; + u32 off_count; + struct sde_wb_cfg *wb; + struct sde_wb_sub_blocks *sblk; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(WB_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, wb_prop, ARRAY_SIZE(wb_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->wb_count = off_count; + + rc = _read_dt_entry(np, wb_prop, ARRAY_SIZE(wb_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + wb = sde_cfg->wb + i; + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); + if (!sblk) { + rc = -ENOMEM; + /* catalog deinit will release the allocated blocks */ + goto end; + } + wb->sblk = sblk; + + wb->base = PROP_VALUE_ACCESS(prop_value, WB_OFF, i); + wb->id = WB_0 + PROP_VALUE_ACCESS(prop_value, WB_ID, i); + snprintf(wb->name, SDE_HW_BLK_NAME_LEN, "wb_%u", + wb->id - WB_0); + wb->clk_ctrl = SDE_CLK_CTRL_WB0 + + PROP_VALUE_ACCESS(prop_value, WB_ID, i); + wb->xin_id = PROP_VALUE_ACCESS(prop_value, WB_XIN_ID, i); + + if (wb->clk_ctrl >= SDE_CLK_CTRL_MAX) { + SDE_ERROR("%s: invalid clk ctrl: %d\n", + wb->name, wb->clk_ctrl); + rc = -EINVAL; + goto end; + } + + if (IS_SDE_MAJOR_MINOR_SAME((sde_cfg->hwversion), + SDE_HW_VER_170)) + wb->vbif_idx = VBIF_NRT; + else + wb->vbif_idx = VBIF_RT; + + wb->len = PROP_VALUE_ACCESS(prop_value, WB_LEN, 0); + if (!prop_exists[WB_LEN]) + wb->len = DEFAULT_SDE_HW_BLOCK_LEN; + sblk->maxlinewidth = sde_cfg->max_wb_linewidth; + + if (wb->id >= LINE_MODE_WB_OFFSET) + set_bit(SDE_WB_LINE_MODE, &wb->features); + else + set_bit(SDE_WB_BLOCK_MODE, &wb->features); + set_bit(SDE_WB_TRAFFIC_SHAPER, &wb->features); + set_bit(SDE_WB_YUV_CONFIG, &wb->features); + + if (sde_cfg->has_cdp) + set_bit(SDE_WB_CDP, &wb->features); + + set_bit(SDE_WB_QOS, &wb->features); + if (sde_cfg->vbif_qos_nlvl == 8) + set_bit(SDE_WB_QOS_8LVL, &wb->features); + + if (sde_cfg->has_wb_ubwc) + set_bit(SDE_WB_UBWC, &wb->features); + + set_bit(SDE_WB_XY_ROI_OFFSET, &wb->features); + + if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) + set_bit(SDE_WB_INPUT_CTRL, &wb->features); + + if (sde_cfg->has_cwb_support) { + set_bit(SDE_WB_HAS_CWB, &wb->features); + if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) + set_bit(SDE_WB_CWB_CTRL, &wb->features); + } + + for (j = 0; j < sde_cfg->mdp_count; j++) { + sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off = + PROP_BITVALUE_ACCESS(prop_value, + WB_CLK_CTRL, i, 0); + sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].bit_off = + PROP_BITVALUE_ACCESS(prop_value, + WB_CLK_CTRL, i, 1); + } + + wb->format_list = sde_cfg->wb_formats; + + SDE_DEBUG( + "wb:%d xin:%d vbif:%d clk%d:%x/%d\n", + wb->id - WB_0, + wb->xin_id, + wb->vbif_idx, + wb->clk_ctrl, + sde_cfg->mdp[0].clk_ctrls[wb->clk_ctrl].reg_off, + sde_cfg->mdp[0].clk_ctrls[wb->clk_ctrl].bit_off); + } + +end: + kfree(prop_value); + return rc; +} + +static void _sde_dspp_setup_blocks(struct sde_mdss_cfg *sde_cfg, + struct sde_dspp_cfg *dspp, struct sde_dspp_sub_blks *sblk, + bool *prop_exists, struct sde_prop_value *prop_value) +{ + sblk->igc.id = SDE_DSPP_IGC; + if (prop_exists[DSPP_IGC_PROP]) { + sblk->igc.base = PROP_VALUE_ACCESS(prop_value, + DSPP_IGC_PROP, 0); + sblk->igc.version = PROP_VALUE_ACCESS(prop_value, + DSPP_IGC_PROP, 1); + sblk->igc.len = 0; + set_bit(SDE_DSPP_IGC, &dspp->features); + } + + sblk->pcc.id = SDE_DSPP_PCC; + if (prop_exists[DSPP_PCC_PROP]) { + sblk->pcc.base = PROP_VALUE_ACCESS(prop_value, + DSPP_PCC_PROP, 0); + sblk->pcc.version = PROP_VALUE_ACCESS(prop_value, + DSPP_PCC_PROP, 1); + sblk->pcc.len = 0; + set_bit(SDE_DSPP_PCC, &dspp->features); + } + + sblk->gc.id = SDE_DSPP_GC; + if (prop_exists[DSPP_GC_PROP]) { + sblk->gc.base = PROP_VALUE_ACCESS(prop_value, DSPP_GC_PROP, 0); + sblk->gc.version = PROP_VALUE_ACCESS(prop_value, + DSPP_GC_PROP, 1); + sblk->gc.len = 0; + set_bit(SDE_DSPP_GC, &dspp->features); + } + + sblk->gamut.id = SDE_DSPP_GAMUT; + if (prop_exists[DSPP_GAMUT_PROP]) { + sblk->gamut.base = PROP_VALUE_ACCESS(prop_value, + DSPP_GAMUT_PROP, 0); + sblk->gamut.version = PROP_VALUE_ACCESS(prop_value, + DSPP_GAMUT_PROP, 1); + sblk->gamut.len = 0; + set_bit(SDE_DSPP_GAMUT, &dspp->features); + } + + sblk->dither.id = SDE_DSPP_DITHER; + if (prop_exists[DSPP_DITHER_PROP]) { + sblk->dither.base = PROP_VALUE_ACCESS(prop_value, + DSPP_DITHER_PROP, 0); + sblk->dither.version = PROP_VALUE_ACCESS(prop_value, + DSPP_DITHER_PROP, 1); + sblk->dither.len = 0; + set_bit(SDE_DSPP_DITHER, &dspp->features); + } + + sblk->hist.id = SDE_DSPP_HIST; + if (prop_exists[DSPP_HIST_PROP]) { + sblk->hist.base = PROP_VALUE_ACCESS(prop_value, + DSPP_HIST_PROP, 0); + sblk->hist.version = PROP_VALUE_ACCESS(prop_value, + DSPP_HIST_PROP, 1); + sblk->hist.len = 0; + set_bit(SDE_DSPP_HIST, &dspp->features); + } + + sblk->hsic.id = SDE_DSPP_HSIC; + if (prop_exists[DSPP_HSIC_PROP]) { + sblk->hsic.base = PROP_VALUE_ACCESS(prop_value, + DSPP_HSIC_PROP, 0); + sblk->hsic.version = PROP_VALUE_ACCESS(prop_value, + DSPP_HSIC_PROP, 1); + sblk->hsic.len = 0; + set_bit(SDE_DSPP_HSIC, &dspp->features); + } + + sblk->memcolor.id = SDE_DSPP_MEMCOLOR; + if (prop_exists[DSPP_MEMCOLOR_PROP]) { + sblk->memcolor.base = PROP_VALUE_ACCESS(prop_value, + DSPP_MEMCOLOR_PROP, 0); + sblk->memcolor.version = PROP_VALUE_ACCESS(prop_value, + DSPP_MEMCOLOR_PROP, 1); + sblk->memcolor.len = 0; + set_bit(SDE_DSPP_MEMCOLOR, &dspp->features); + } + + sblk->sixzone.id = SDE_DSPP_SIXZONE; + if (prop_exists[DSPP_SIXZONE_PROP]) { + sblk->sixzone.base = PROP_VALUE_ACCESS(prop_value, + DSPP_SIXZONE_PROP, 0); + sblk->sixzone.version = PROP_VALUE_ACCESS(prop_value, + DSPP_SIXZONE_PROP, 1); + sblk->sixzone.len = 0; + set_bit(SDE_DSPP_SIXZONE, &dspp->features); + } + + sblk->vlut.id = SDE_DSPP_VLUT; + if (prop_exists[DSPP_VLUT_PROP]) { + sblk->vlut.base = PROP_VALUE_ACCESS(prop_value, + DSPP_VLUT_PROP, 0); + sblk->vlut.version = PROP_VALUE_ACCESS(prop_value, + DSPP_VLUT_PROP, 1); + sblk->sixzone.len = 0; + set_bit(SDE_DSPP_VLUT, &dspp->features); + } +} + +static int sde_rot_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + struct platform_device *pdev; + struct of_phandle_args phargs; + struct llcc_slice_desc *slice; + int rc = 0; + + rc = of_parse_phandle_with_args(np, + "qcom,sde-inline-rotator", "#list-cells", + 0, &phargs); + + if (rc) { + /* + * This is not a fatal error, system cache can be disabled + * in device tree. + */ + SDE_DEBUG("sys cache will be disabled rc:%d\n", rc); + rc = 0; + goto exit; + } + + if (!phargs.np || !phargs.args_count) { + SDE_ERROR("wrong phandle args %d %d\n", + !phargs.np, !phargs.args_count); + rc = -EINVAL; + goto exit; + } + + pdev = of_find_device_by_node(phargs.np); + if (!pdev) { + SDE_ERROR("invalid sde rotator node\n"); + goto exit; + } + + slice = llcc_slice_getd(LLCC_ROTATOR); + if (IS_ERR_OR_NULL(slice)) { + SDE_ERROR("failed to get rotator slice!\n"); + rc = -EINVAL; + goto cleanup; + } + + sde_cfg->sc_cfg.llcc_scid = llcc_get_slice_id(slice); + sde_cfg->sc_cfg.llcc_slice_size = llcc_get_slice_size(slice); + llcc_slice_putd(slice); + + sde_cfg->sc_cfg.has_sys_cache = true; + + SDE_DEBUG("rotator llcc scid:%d slice_size:%zukb\n", + sde_cfg->sc_cfg.llcc_scid, sde_cfg->sc_cfg.llcc_slice_size); +cleanup: + of_node_put(phargs.np); +exit: + return rc; +} + +static int sde_dspp_top_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[DSPP_TOP_PROP_MAX]; + bool prop_exists[DSPP_TOP_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + u32 off_count; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(DSPP_TOP_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, dspp_top_prop, ARRAY_SIZE(dspp_top_prop), + prop_count, &off_count); + if (rc) + goto end; + + rc = _read_dt_entry(np, dspp_top_prop, ARRAY_SIZE(dspp_top_prop), + prop_count, prop_exists, prop_value); + if (rc) + goto end; + + if (off_count != 1) { + SDE_ERROR("invalid dspp_top off_count:%d\n", off_count); + rc = -EINVAL; + goto end; + } + + sde_cfg->dspp_top.base = + PROP_VALUE_ACCESS(prop_value, DSPP_TOP_OFF, 0); + sde_cfg->dspp_top.len = + PROP_VALUE_ACCESS(prop_value, DSPP_TOP_SIZE, 0); + snprintf(sde_cfg->dspp_top.name, SDE_HW_BLK_NAME_LEN, "dspp_top"); + +end: + kfree(prop_value); + return rc; +} + +static int sde_dspp_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[DSPP_PROP_MAX], i; + int ad_prop_count[AD_PROP_MAX]; + int ltm_prop_count[LTM_PROP_MAX]; + bool prop_exists[DSPP_PROP_MAX], ad_prop_exists[AD_PROP_MAX]; + bool ltm_prop_exists[LTM_PROP_MAX]; + bool blocks_prop_exists[DSPP_BLOCKS_PROP_MAX]; + struct sde_prop_value *ad_prop_value = NULL, *ltm_prop_value = NULL; + int blocks_prop_count[DSPP_BLOCKS_PROP_MAX]; + struct sde_prop_value *prop_value = NULL, *blocks_prop_value = NULL; + u32 off_count, ad_off_count, ltm_off_count; + struct sde_dspp_cfg *dspp; + struct sde_dspp_sub_blks *sblk; + struct device_node *snp = NULL; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(DSPP_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), + prop_count, &off_count); + if (rc) + goto end; + + sde_cfg->dspp_count = off_count; + + rc = _read_dt_entry(np, dspp_prop, ARRAY_SIZE(dspp_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + /* Parse AD dtsi entries */ + ad_prop_value = kcalloc(AD_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!ad_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), + ad_prop_count, &ad_off_count); + if (rc) + goto end; + rc = _read_dt_entry(np, ad_prop, ARRAY_SIZE(ad_prop), ad_prop_count, + ad_prop_exists, ad_prop_value); + if (rc) + goto end; + + /* Parse LTM dtsi entries */ + ltm_prop_value = kcalloc(LTM_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!ltm_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), + ltm_prop_count, <m_off_count); + if (rc) + goto end; + rc = _read_dt_entry(np, ltm_prop, ARRAY_SIZE(ltm_prop), ltm_prop_count, + ltm_prop_exists, ltm_prop_value); + if (rc) + goto end; + + /* get DSPP feature dt properties if they exist */ + snp = of_get_child_by_name(np, dspp_prop[DSPP_BLOCKS].prop_name); + if (snp) { + blocks_prop_value = kzalloc(DSPP_BLOCKS_PROP_MAX * + MAX_SDE_HW_BLK * sizeof(struct sde_prop_value), + GFP_KERNEL); + if (!blocks_prop_value) { + rc = -ENOMEM; + goto end; + } + rc = _validate_dt_entry(snp, dspp_blocks_prop, + ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, NULL); + if (rc) + goto end; + rc = _read_dt_entry(snp, dspp_blocks_prop, + ARRAY_SIZE(dspp_blocks_prop), blocks_prop_count, + blocks_prop_exists, blocks_prop_value); + if (rc) + goto end; + } + + for (i = 0; i < off_count; i++) { + dspp = sde_cfg->dspp + i; + dspp->base = PROP_VALUE_ACCESS(prop_value, DSPP_OFF, i); + dspp->len = PROP_VALUE_ACCESS(prop_value, DSPP_SIZE, 0); + dspp->id = DSPP_0 + i; + snprintf(dspp->name, SDE_HW_BLK_NAME_LEN, "dspp_%u", + dspp->id - DSPP_0); + + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); + if (!sblk) { + rc = -ENOMEM; + /* catalog deinit will release the allocated blocks */ + goto end; + } + dspp->sblk = sblk; + + if (blocks_prop_value) + _sde_dspp_setup_blocks(sde_cfg, dspp, sblk, + blocks_prop_exists, blocks_prop_value); + + sblk->ad.id = SDE_DSPP_AD; + sde_cfg->ad_count = ad_off_count; + if (ad_prop_value && (i < ad_off_count) && + ad_prop_exists[AD_OFF]) { + sblk->ad.base = PROP_VALUE_ACCESS(ad_prop_value, + AD_OFF, i); + sblk->ad.version = PROP_VALUE_ACCESS(ad_prop_value, + AD_VERSION, 0); + set_bit(SDE_DSPP_AD, &dspp->features); + } + + sblk->ltm.id = SDE_DSPP_LTM; + sde_cfg->ltm_count = ltm_off_count; + if (ltm_prop_value && (i < ltm_off_count) && + ltm_prop_exists[LTM_OFF]) { + sblk->ltm.base = PROP_VALUE_ACCESS(ltm_prop_value, + LTM_OFF, i); + sblk->ltm.version = PROP_VALUE_ACCESS(ltm_prop_value, + LTM_VERSION, 0); + set_bit(SDE_DSPP_LTM, &dspp->features); + } + + } + +end: + kfree(prop_value); + kfree(ad_prop_value); + kfree(ltm_prop_value); + kfree(blocks_prop_value); + return rc; +} + +static int sde_ds_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[DS_PROP_MAX], top_prop_count[DS_TOP_PROP_MAX], i; + struct sde_prop_value *prop_value = NULL, *top_prop_value = NULL; + bool prop_exists[DS_PROP_MAX], top_prop_exists[DS_TOP_PROP_MAX]; + u32 off_count = 0, top_off_count = 0; + struct sde_ds_cfg *ds; + struct sde_ds_top_cfg *ds_top = NULL; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + if (!sde_cfg->mdp[0].has_dest_scaler) { + SDE_DEBUG("dest scaler feature not supported\n"); + rc = 0; + goto end; + } + + /* Parse the dest scaler top register offset and capabilities */ + top_prop_value = kzalloc(DS_TOP_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!top_prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, ds_top_prop, + ARRAY_SIZE(ds_top_prop), + top_prop_count, &top_off_count); + if (rc) + goto end; + + rc = _read_dt_entry(np, ds_top_prop, + ARRAY_SIZE(ds_top_prop), top_prop_count, + top_prop_exists, top_prop_value); + if (rc) + goto end; + + /* Parse the offset of each dest scaler block */ + prop_value = kcalloc(DS_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, ds_prop, ARRAY_SIZE(ds_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->ds_count = off_count; + + rc = _read_dt_entry(np, ds_prop, ARRAY_SIZE(ds_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + if (!off_count) + goto end; + + ds_top = kzalloc(sizeof(struct sde_ds_top_cfg), GFP_KERNEL); + if (!ds_top) { + rc = -ENOMEM; + goto end; + } + + ds_top->id = DS_TOP; + snprintf(ds_top->name, SDE_HW_BLK_NAME_LEN, "ds_top_%u", + ds_top->id - DS_TOP); + ds_top->base = PROP_VALUE_ACCESS(top_prop_value, DS_TOP_OFF, 0); + ds_top->len = PROP_VALUE_ACCESS(top_prop_value, DS_TOP_LEN, 0); + ds_top->maxupscale = MAX_UPSCALE_RATIO; + + ds_top->maxinputwidth = PROP_VALUE_ACCESS(top_prop_value, + DS_TOP_INPUT_LINEWIDTH, 0); + if (!top_prop_exists[DS_TOP_INPUT_LINEWIDTH]) + ds_top->maxinputwidth = DEFAULT_SDE_LINE_WIDTH; + + ds_top->maxoutputwidth = PROP_VALUE_ACCESS(top_prop_value, + DS_TOP_OUTPUT_LINEWIDTH, 0); + if (!top_prop_exists[DS_TOP_OUTPUT_LINEWIDTH]) + ds_top->maxoutputwidth = DEFAULT_SDE_OUTPUT_LINE_WIDTH; + + for (i = 0; i < off_count; i++) { + ds = sde_cfg->ds + i; + ds->top = ds_top; + ds->base = PROP_VALUE_ACCESS(prop_value, DS_OFF, i); + ds->id = DS_0 + i; + ds->len = PROP_VALUE_ACCESS(prop_value, DS_LEN, 0); + snprintf(ds->name, SDE_HW_BLK_NAME_LEN, "ds_%u", + ds->id - DS_0); + + if (!prop_exists[DS_LEN]) + ds->len = DEFAULT_SDE_HW_BLOCK_LEN; + + if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3) + set_bit(SDE_SSPP_SCALER_QSEED3, &ds->features); + else if (sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3LITE) + set_bit(SDE_SSPP_SCALER_QSEED3LITE, &ds->features); + + } + +end: + kfree(top_prop_value); + kfree(prop_value); + return rc; +}; + +static int sde_dsc_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[MAX_BLOCKS], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[DSC_PROP_MAX]; + u32 off_count, dsc_pair_mask; + struct sde_dsc_cfg *dsc; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(DSC_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, dsc_prop, ARRAY_SIZE(dsc_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->dsc_count = off_count; + + rc = _read_dt_entry(np, dsc_prop, ARRAY_SIZE(dsc_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + dsc = sde_cfg->dsc + i; + dsc->base = PROP_VALUE_ACCESS(prop_value, DSC_OFF, i); + dsc->id = DSC_0 + i; + dsc->len = PROP_VALUE_ACCESS(prop_value, DSC_LEN, 0); + snprintf(dsc->name, SDE_HW_BLK_NAME_LEN, "dsc_%u", + dsc->id - DSC_0); + + if (!prop_exists[DSC_LEN]) + dsc->len = DEFAULT_SDE_HW_BLOCK_LEN; + + if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) + set_bit(SDE_DSC_OUTPUT_CTRL, &dsc->features); + + dsc_pair_mask = PROP_VALUE_ACCESS(prop_value, + DSC_PAIR_MASK, i); + if (dsc_pair_mask) + set_bit(dsc_pair_mask, dsc->dsc_pair_mask); + } + +end: + kfree(prop_value); + return rc; +}; + +static int sde_cdm_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[HW_PROP_MAX], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[HW_PROP_MAX]; + u32 off_count; + struct sde_cdm_cfg *cdm; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(HW_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, cdm_prop, ARRAY_SIZE(cdm_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->cdm_count = off_count; + + rc = _read_dt_entry(np, cdm_prop, ARRAY_SIZE(cdm_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + cdm = sde_cfg->cdm + i; + cdm->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i); + cdm->id = CDM_0 + i; + snprintf(cdm->name, SDE_HW_BLK_NAME_LEN, "cdm_%u", + cdm->id - CDM_0); + cdm->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0); + + /* intf3 and wb2 for cdm block */ + cdm->wb_connect = sde_cfg->wb_count ? BIT(WB_2) : BIT(31); + cdm->intf_connect = sde_cfg->intf_count ? BIT(INTF_3) : BIT(31); + + if (IS_SDE_CTL_REV_100(sde_cfg->ctl_rev)) + set_bit(SDE_CDM_INPUT_CTRL, &cdm->features); + } + +end: + kfree(prop_value); + return rc; +} + +static int sde_uidle_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc = 0, prop_count[UIDLE_PROP_MAX]; + bool prop_exists[UIDLE_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + u32 off_count; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + if (!sde_cfg->uidle_cfg.uidle_rev) + return 0; + + prop_value = kcalloc(UIDLE_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) + return -ENOMEM; + + rc = _validate_dt_entry(np, uidle_prop, ARRAY_SIZE(uidle_prop), + prop_count, &off_count); + if (rc) + goto end; + + rc = _read_dt_entry(np, uidle_prop, ARRAY_SIZE(uidle_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + if (!prop_exists[UIDLE_LEN] || !prop_exists[UIDLE_OFF]) { + SDE_DEBUG("offset/len missing, will disable uidle:%d,%d\n", + prop_exists[UIDLE_LEN], prop_exists[UIDLE_OFF]); + rc = -EINVAL; + goto end; + } + + sde_cfg->uidle_cfg.id = UIDLE; + sde_cfg->uidle_cfg.base = + PROP_VALUE_ACCESS(prop_value, UIDLE_OFF, 0); + sde_cfg->uidle_cfg.len = + PROP_VALUE_ACCESS(prop_value, UIDLE_LEN, 0); + + /* validate */ + if (!sde_cfg->uidle_cfg.base || !sde_cfg->uidle_cfg.len) { + SDE_ERROR("invalid reg/len [%d, %d], will disable uidle\n", + sde_cfg->uidle_cfg.base, sde_cfg->uidle_cfg.len); + rc = -EINVAL; + } + +end: + if (rc && sde_cfg->uidle_cfg.uidle_rev) { + SDE_DEBUG("wrong dt entries, will disable uidle\n"); + sde_cfg->uidle_cfg.uidle_rev = 0; + } + + kfree(prop_value); + /* optional feature, so always return success */ + return 0; +} + +static int _sde_vbif_populate_ot_parsing(struct sde_vbif_cfg *vbif, + struct sde_prop_value *prop_value, int *prop_count) +{ + int j, k; + + vbif->default_ot_rd_limit = PROP_VALUE_ACCESS(prop_value, + VBIF_DEFAULT_OT_RD_LIMIT, 0); + SDE_DEBUG("default_ot_rd_limit=%u\n", + vbif->default_ot_rd_limit); + + vbif->default_ot_wr_limit = PROP_VALUE_ACCESS(prop_value, + VBIF_DEFAULT_OT_WR_LIMIT, 0); + SDE_DEBUG("default_ot_wr_limit=%u\n", + vbif->default_ot_wr_limit); + + vbif->dynamic_ot_rd_tbl.count = + prop_count[VBIF_DYNAMIC_OT_RD_LIMIT] / 2; + SDE_DEBUG("dynamic_ot_rd_tbl.count=%u\n", + vbif->dynamic_ot_rd_tbl.count); + if (vbif->dynamic_ot_rd_tbl.count) { + vbif->dynamic_ot_rd_tbl.cfg = kcalloc( + vbif->dynamic_ot_rd_tbl.count, + sizeof(struct sde_vbif_dynamic_ot_cfg), + GFP_KERNEL); + if (!vbif->dynamic_ot_rd_tbl.cfg) + return -ENOMEM; + } + + for (j = 0, k = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) { + vbif->dynamic_ot_rd_tbl.cfg[j].pps = (u64) + PROP_VALUE_ACCESS(prop_value, + VBIF_DYNAMIC_OT_RD_LIMIT, k++); + vbif->dynamic_ot_rd_tbl.cfg[j].ot_limit = + PROP_VALUE_ACCESS(prop_value, + VBIF_DYNAMIC_OT_RD_LIMIT, k++); + SDE_DEBUG("dynamic_ot_rd_tbl[%d].cfg=<%llu %u>\n", j, + vbif->dynamic_ot_rd_tbl.cfg[j].pps, + vbif->dynamic_ot_rd_tbl.cfg[j].ot_limit); + } + + vbif->dynamic_ot_wr_tbl.count = + prop_count[VBIF_DYNAMIC_OT_WR_LIMIT] / 2; + SDE_DEBUG("dynamic_ot_wr_tbl.count=%u\n", + vbif->dynamic_ot_wr_tbl.count); + if (vbif->dynamic_ot_wr_tbl.count) { + vbif->dynamic_ot_wr_tbl.cfg = kcalloc( + vbif->dynamic_ot_wr_tbl.count, + sizeof(struct sde_vbif_dynamic_ot_cfg), + GFP_KERNEL); + if (!vbif->dynamic_ot_wr_tbl.cfg) + return -ENOMEM; + } + + for (j = 0, k = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) { + vbif->dynamic_ot_wr_tbl.cfg[j].pps = (u64) + PROP_VALUE_ACCESS(prop_value, + VBIF_DYNAMIC_OT_WR_LIMIT, k++); + vbif->dynamic_ot_wr_tbl.cfg[j].ot_limit = + PROP_VALUE_ACCESS(prop_value, + VBIF_DYNAMIC_OT_WR_LIMIT, k++); + SDE_DEBUG("dynamic_ot_wr_tbl[%d].cfg=<%llu %u>\n", j, + vbif->dynamic_ot_wr_tbl.cfg[j].pps, + vbif->dynamic_ot_wr_tbl.cfg[j].ot_limit); + } + + if (vbif->default_ot_rd_limit || vbif->default_ot_wr_limit || + vbif->dynamic_ot_rd_tbl.count || + vbif->dynamic_ot_wr_tbl.count) + set_bit(SDE_VBIF_QOS_OTLIM, &vbif->features); + + return 0; +} + +static int _sde_vbif_populate_qos_parsing(struct sde_mdss_cfg *sde_cfg, + struct sde_vbif_cfg *vbif, struct sde_prop_value *prop_value, + int *prop_count) +{ + int i, j; + int prop_index = VBIF_QOS_RT_REMAP; + + for (i = VBIF_RT_CLIENT; + ((i < VBIF_MAX_CLIENT) && (prop_index < VBIF_PROP_MAX)); + i++, prop_index++) { + vbif->qos_tbl[i].npriority_lvl = prop_count[prop_index]; + SDE_DEBUG("qos_tbl[%d].npriority_lvl=%u\n", + i, vbif->qos_tbl[i].npriority_lvl); + + if (vbif->qos_tbl[i].npriority_lvl == sde_cfg->vbif_qos_nlvl) { + vbif->qos_tbl[i].priority_lvl = kcalloc( + vbif->qos_tbl[i].npriority_lvl, + sizeof(u32), GFP_KERNEL); + if (!vbif->qos_tbl[i].priority_lvl) + return -ENOMEM; + } else if (vbif->qos_tbl[i].npriority_lvl) { + vbif->qos_tbl[i].npriority_lvl = 0; + vbif->qos_tbl[i].priority_lvl = NULL; + SDE_ERROR("invalid qos table for client:%d, prop:%d\n", + i, prop_index); + } + + for (j = 0; j < vbif->qos_tbl[i].npriority_lvl; j++) { + vbif->qos_tbl[i].priority_lvl[j] = + PROP_VALUE_ACCESS(prop_value, prop_index, j); + SDE_DEBUG("client:%d, prop:%d, lvl[%d]=%u\n", + i, prop_index, j, + vbif->qos_tbl[i].priority_lvl[j]); + } + + if (vbif->qos_tbl[i].npriority_lvl) + set_bit(SDE_VBIF_QOS_REMAP, &vbif->features); + } + + return 0; +} + +static int _sde_vbif_populate(struct sde_mdss_cfg *sde_cfg, + struct sde_vbif_cfg *vbif, struct sde_prop_value *prop_value, + int *prop_count, u32 vbif_len, int i) +{ + int j, k, rc; + + vbif = sde_cfg->vbif + i; + vbif->base = PROP_VALUE_ACCESS(prop_value, VBIF_OFF, i); + vbif->len = vbif_len; + vbif->id = VBIF_0 + PROP_VALUE_ACCESS(prop_value, VBIF_ID, i); + snprintf(vbif->name, SDE_HW_BLK_NAME_LEN, "vbif_%u", + vbif->id - VBIF_0); + + SDE_DEBUG("vbif:%d\n", vbif->id - VBIF_0); + + vbif->xin_halt_timeout = VBIF_XIN_HALT_TIMEOUT; + + rc = _sde_vbif_populate_ot_parsing(vbif, prop_value, prop_count); + if (rc) + return rc; + + rc = _sde_vbif_populate_qos_parsing(sde_cfg, vbif, prop_value, + prop_count); + if (rc) + return rc; + + vbif->memtype_count = prop_count[VBIF_MEMTYPE_0] + + prop_count[VBIF_MEMTYPE_1]; + if (vbif->memtype_count > MAX_XIN_COUNT) { + vbif->memtype_count = 0; + SDE_ERROR("too many memtype defs, ignoring entries\n"); + } + for (j = 0, k = 0; j < prop_count[VBIF_MEMTYPE_0]; j++) + vbif->memtype[k++] = PROP_VALUE_ACCESS( + prop_value, VBIF_MEMTYPE_0, j); + for (j = 0; j < prop_count[VBIF_MEMTYPE_1]; j++) + vbif->memtype[k++] = PROP_VALUE_ACCESS( + prop_value, VBIF_MEMTYPE_1, j); + + return 0; +} + +static int sde_vbif_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[VBIF_PROP_MAX], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[VBIF_PROP_MAX]; + u32 off_count, vbif_len; + struct sde_vbif_cfg *vbif; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(VBIF_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, vbif_prop, ARRAY_SIZE(vbif_prop), + prop_count, &off_count); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_DYNAMIC_OT_RD_LIMIT], 1, + &prop_count[VBIF_DYNAMIC_OT_RD_LIMIT], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_DYNAMIC_OT_WR_LIMIT], 1, + &prop_count[VBIF_DYNAMIC_OT_WR_LIMIT], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_MEMTYPE_0], 1, + &prop_count[VBIF_MEMTYPE_0], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_MEMTYPE_1], 1, + &prop_count[VBIF_MEMTYPE_1], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_RT_REMAP], 1, + &prop_count[VBIF_QOS_RT_REMAP], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_NRT_REMAP], 1, + &prop_count[VBIF_QOS_NRT_REMAP], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_CWB_REMAP], 1, + &prop_count[VBIF_QOS_CWB_REMAP], NULL); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &vbif_prop[VBIF_QOS_LUTDMA_REMAP], 1, + &prop_count[VBIF_QOS_LUTDMA_REMAP], NULL); + if (rc) + goto end; + + sde_cfg->vbif_count = off_count; + + rc = _read_dt_entry(np, vbif_prop, ARRAY_SIZE(vbif_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + vbif_len = PROP_VALUE_ACCESS(prop_value, VBIF_LEN, 0); + if (!prop_exists[VBIF_LEN]) + vbif_len = DEFAULT_SDE_HW_BLOCK_LEN; + + for (i = 0; i < off_count; i++) { + rc = _sde_vbif_populate(sde_cfg, vbif, prop_value, + prop_count, vbif_len, i); + if (rc) + goto end; + } + +end: + kfree(prop_value); + return rc; +} + +static int sde_pp_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[PP_PROP_MAX], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[PP_PROP_MAX]; + u32 off_count, major_version; + struct sde_pingpong_cfg *pp; + struct sde_pingpong_sub_blks *sblk; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(PP_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, pp_prop, ARRAY_SIZE(pp_prop), prop_count, + &off_count); + if (rc) + goto end; + + sde_cfg->pingpong_count = off_count; + + rc = _read_dt_entry(np, pp_prop, ARRAY_SIZE(pp_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + pp = sde_cfg->pingpong + i; + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); + if (!sblk) { + rc = -ENOMEM; + /* catalog deinit will release the allocated blocks */ + goto end; + } + pp->sblk = sblk; + + pp->base = PROP_VALUE_ACCESS(prop_value, PP_OFF, i); + pp->id = PINGPONG_0 + i; + snprintf(pp->name, SDE_HW_BLK_NAME_LEN, "pingpong_%u", + pp->id - PINGPONG_0); + pp->len = PROP_VALUE_ACCESS(prop_value, PP_LEN, 0); + + sblk->te.base = PROP_VALUE_ACCESS(prop_value, TE_OFF, i); + sblk->te.id = SDE_PINGPONG_TE; + snprintf(sblk->te.name, SDE_HW_BLK_NAME_LEN, "te_%u", + pp->id - PINGPONG_0); + + major_version = SDE_HW_MAJOR(sde_cfg->hwversion); + if (major_version < SDE_HW_MAJOR(SDE_HW_VER_500)) + set_bit(SDE_PINGPONG_TE, &pp->features); + + sblk->te2.base = PROP_VALUE_ACCESS(prop_value, TE2_OFF, i); + if (sblk->te2.base) { + sblk->te2.id = SDE_PINGPONG_TE2; + snprintf(sblk->te2.name, SDE_HW_BLK_NAME_LEN, "te2_%u", + pp->id - PINGPONG_0); + set_bit(SDE_PINGPONG_TE2, &pp->features); + set_bit(SDE_PINGPONG_SPLIT, &pp->features); + } + + if (PROP_VALUE_ACCESS(prop_value, PP_SLAVE, i)) + set_bit(SDE_PINGPONG_SLAVE, &pp->features); + + sblk->dsc.base = PROP_VALUE_ACCESS(prop_value, DSC_OFF, i); + if (sblk->dsc.base) { + sblk->dsc.id = SDE_PINGPONG_DSC; + snprintf(sblk->dsc.name, SDE_HW_BLK_NAME_LEN, "dsc_%u", + pp->id - PINGPONG_0); + set_bit(SDE_PINGPONG_DSC, &pp->features); + } + + sblk->dither.base = PROP_VALUE_ACCESS(prop_value, DITHER_OFF, + i); + if (sblk->dither.base) { + sblk->dither.id = SDE_PINGPONG_DITHER; + snprintf(sblk->dither.name, SDE_HW_BLK_NAME_LEN, + "dither_%u", pp->id); + set_bit(SDE_PINGPONG_DITHER, &pp->features); + } + sblk->dither.len = PROP_VALUE_ACCESS(prop_value, DITHER_LEN, 0); + sblk->dither.version = PROP_VALUE_ACCESS(prop_value, DITHER_VER, + 0); + + if (prop_exists[PP_MERGE_3D_ID]) { + set_bit(SDE_PINGPONG_MERGE_3D, &pp->features); + pp->merge_3d_id = PROP_VALUE_ACCESS(prop_value, + PP_MERGE_3D_ID, i) + 1; + } + } + +end: + kfree(prop_value); + return rc; +} + +static int _sde_get_ubwc_hbb(bool prop_exists[SDE_PROP_MAX], + struct sde_prop_value *prop_value) +{ + int num_dram_channels, i, j, hbb = -EINVAL; + int num_ranks_per_channel[MAX_NUM_CHANNELS]; + + num_dram_channels = PROP_VALUE_ACCESS(prop_value, + NUM_DRAM_CHANNELS, 0); + + if (num_dram_channels > MAX_NUM_CHANNELS) + return -EINVAL; + + for (i = 0; i < num_dram_channels; i++) + num_ranks_per_channel[i] = of_fdt_get_ddrrank(i); + + for (i = 0; i < num_dram_channels; i++) { + for (j = 0; j < num_ranks_per_channel[i]; j++) + hbb = max(hbb, of_fdt_get_ddrhbb(i, j)); + } + + if (hbb >= UBWC_HBB_OFFSET) + hbb -= UBWC_HBB_OFFSET; + else + hbb = -EINVAL; + + return hbb; +} + +static int _sde_parse_prop_check(struct sde_mdss_cfg *cfg, + bool prop_exists[SDE_PROP_MAX], struct sde_prop_value *prop_value) +{ + int ret; + + cfg->max_sspp_linewidth = PROP_VALUE_ACCESS(prop_value, + SSPP_LINEWIDTH, 0); + if (!prop_exists[SSPP_LINEWIDTH]) + cfg->max_sspp_linewidth = DEFAULT_SDE_LINE_WIDTH; + + cfg->vig_sspp_linewidth = PROP_VALUE_ACCESS(prop_value, + VIG_SSPP_LINEWIDTH, 0); + if (!prop_exists[VIG_SSPP_LINEWIDTH]) + cfg->vig_sspp_linewidth = cfg->max_sspp_linewidth; + + cfg->max_mixer_width = PROP_VALUE_ACCESS(prop_value, + MIXER_LINEWIDTH, 0); + if (!prop_exists[MIXER_LINEWIDTH]) + cfg->max_mixer_width = DEFAULT_SDE_LINE_WIDTH; + + cfg->max_mixer_blendstages = PROP_VALUE_ACCESS(prop_value, + MIXER_BLEND, 0); + if (!prop_exists[MIXER_BLEND]) + cfg->max_mixer_blendstages = DEFAULT_SDE_MIXER_BLENDSTAGES; + + cfg->max_wb_linewidth = PROP_VALUE_ACCESS(prop_value, WB_LINEWIDTH, 0); + if (!prop_exists[WB_LINEWIDTH]) + cfg->max_wb_linewidth = DEFAULT_SDE_LINE_WIDTH; + + cfg->ubwc_version = SDE_HW_UBWC_VER(PROP_VALUE_ACCESS(prop_value, + UBWC_VERSION, 0)); + if (!prop_exists[UBWC_VERSION]) + cfg->ubwc_version = DEFAULT_SDE_UBWC_NONE; + + cfg->mdp[0].highest_bank_bit = PROP_VALUE_ACCESS(prop_value, + BANK_BIT, 0); + if (!prop_exists[BANK_BIT]) + cfg->mdp[0].highest_bank_bit = DEFAULT_SDE_HIGHEST_BANK_BIT; + + if (cfg->ubwc_version == SDE_HW_UBWC_VER_40 && + of_fdt_get_ddrtype() == LP_DDR4_TYPE) + cfg->mdp[0].highest_bank_bit = 0x02; + + if (IS_SDE_MAJOR_MINOR_SAME(cfg->hwversion, SDE_HW_VER_630)) { + ret = _sde_get_ubwc_hbb(prop_exists, prop_value); + + if (ret >= 0) + cfg->mdp[0].highest_bank_bit = ret; + } + + cfg->macrotile_mode = PROP_VALUE_ACCESS(prop_value, MACROTILE_MODE, 0); + if (!prop_exists[MACROTILE_MODE]) + cfg->macrotile_mode = DEFAULT_SDE_UBWC_MACROTILE_MODE; + + cfg->ubwc_bw_calc_version = + PROP_VALUE_ACCESS(prop_value, UBWC_BW_CALC_VERSION, 0); + + cfg->mdp[0].ubwc_static = PROP_VALUE_ACCESS(prop_value, UBWC_STATIC, 0); + if (!prop_exists[UBWC_STATIC]) + cfg->mdp[0].ubwc_static = DEFAULT_SDE_UBWC_STATIC; + + cfg->mdp[0].ubwc_swizzle = PROP_VALUE_ACCESS(prop_value, + UBWC_SWIZZLE, 0); + if (!prop_exists[UBWC_SWIZZLE]) + cfg->mdp[0].ubwc_swizzle = DEFAULT_SDE_UBWC_SWIZZLE; + + cfg->mdp[0].has_dest_scaler = + PROP_VALUE_ACCESS(prop_value, DEST_SCALER, 0); + + cfg->mdp[0].smart_panel_align_mode = + PROP_VALUE_ACCESS(prop_value, SMART_PANEL_ALIGN_MODE, 0); + return 0; +} + +static int sde_read_limit_node(struct device_node *snp, + struct sde_prop_value *lmt_val, struct sde_mdss_cfg *cfg) +{ + int j, i = 0, rc = 0; + const char *type = NULL; + struct device_node *node = NULL; + u32 vig = 0, dma = 0, inline_rot = 0, scaling = 0; + u32 usecase = 0, val = 0; + + for_each_child_of_node(snp, node) { + cfg->limit_cfg[i].vector_cfg = + kcalloc(cfg->limit_cfg[i].lmt_case_cnt, + sizeof(struct limit_vector_cfg), GFP_KERNEL); + if (!cfg->limit_cfg[i].vector_cfg) { + rc = -ENOMEM; + goto error; + } + + for (j = 0; j < cfg->limit_cfg[i].lmt_case_cnt; j++) { + of_property_read_string_index(node, + limit_usecase_prop[LIMIT_USECASE].prop_name, + j, &type); + cfg->limit_cfg[i].vector_cfg[j].usecase = type; + cfg->limit_cfg[i].vector_cfg[j].value = + PROP_VALUE_ACCESS(&lmt_val[i * LIMIT_PROP_MAX], + LIMIT_ID, j); + if (!strcmp(type, "vig")) + vig = cfg->limit_cfg[i].vector_cfg[j].value; + else if (!strcmp(type, "dma")) + dma = cfg->limit_cfg[i].vector_cfg[j].value; + else if (!strcmp(type, "inline_rot")) + inline_rot = + cfg->limit_cfg[i].vector_cfg[j].value; + else if (!strcmp(type, "scale")) + scaling = + cfg->limit_cfg[i].vector_cfg[j].value; + } + + cfg->limit_cfg[i].value_cfg = + kcalloc(cfg->limit_cfg[i].lmt_vec_cnt, + sizeof(struct limit_value_cfg), GFP_KERNEL); + + if (!cfg->limit_cfg[i].value_cfg) { + rc = -ENOMEM; + goto error; + } + + for (j = 0; j < cfg->limit_cfg[i].lmt_vec_cnt; j++) { + cfg->limit_cfg[i].value_cfg[j].use_concur = + PROP_BITVALUE_ACCESS( + &lmt_val[i * LIMIT_PROP_MAX], + LIMIT_VALUE, j, 0); + cfg->limit_cfg[i].value_cfg[j].value = + PROP_BITVALUE_ACCESS( + &lmt_val[i * LIMIT_PROP_MAX], + LIMIT_VALUE, j, 1); + cfg->limit_cfg[i].max_value = + max(cfg->limit_cfg[i].max_value, + cfg->limit_cfg[i].value_cfg[j].value); + + usecase = cfg->limit_cfg[i].value_cfg[j].use_concur; + val = cfg->limit_cfg[i].value_cfg[j].value; + + if (!strcmp(cfg->limit_cfg[i].name, + "sspp_linewidth_usecases")) { + if (usecase == dma) + cfg->max_sspp_linewidth = val; + else if (usecase == vig) + cfg->vig_sspp_linewidth = val; + else if (usecase == (vig | inline_rot)) + cfg->inline_linewidth = val; + else if (usecase == (vig | scaling)) + cfg->scaling_linewidth = val; + } + } + i++; + } + + return 0; +error: + for (j = 0; j < cfg->limit_count; j++) { + kfree(cfg->limit_cfg[j].vector_cfg); + kfree(cfg->limit_cfg[j].value_cfg); + } + + cfg->limit_count = 0; + return rc; +} + +static int sde_validate_limit_node(struct device_node *snp, + struct sde_prop_value *sde_limit_value, struct sde_mdss_cfg *cfg) +{ + int i = 0, rc = 0; + struct device_node *node = NULL; + int limit_value_count[LIMIT_PROP_MAX]; + bool limit_value_exists[LIMIT_SUBBLK_COUNT_MAX][LIMIT_PROP_MAX]; + const char *type = NULL; + + for_each_child_of_node(snp, node) { + rc = _validate_dt_entry(node, limit_usecase_prop, + ARRAY_SIZE(limit_usecase_prop), + limit_value_count, NULL); + if (rc) + goto end; + + rc = _read_dt_entry(node, limit_usecase_prop, + ARRAY_SIZE(limit_usecase_prop), limit_value_count, + &limit_value_exists[i][0], + &sde_limit_value[i * LIMIT_PROP_MAX]); + if (rc) + goto end; + + cfg->limit_cfg[i].lmt_case_cnt = + limit_value_count[LIMIT_ID]; + + cfg->limit_cfg[i].lmt_vec_cnt = + limit_value_count[LIMIT_VALUE]; + of_property_read_string(node, + limit_usecase_prop[LIMIT_NAME].prop_name, &type); + cfg->limit_cfg[i].name = type; + + if (!limit_value_count[LIMIT_ID] || + !limit_value_count[LIMIT_VALUE]) { + rc = -EINVAL; + goto end; + } + i++; + } + return 0; +end: + cfg->limit_count = 0; + return rc; +} + +static int sde_limit_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) +{ + struct device_node *snp = NULL; + struct sde_prop_value *sde_limit_value = NULL; + int rc = 0; + + snp = of_get_child_by_name(np, sde_prop[SDE_LIMITS].prop_name); + if (!snp) + goto end; + + cfg->limit_count = of_get_child_count(snp); + if (cfg->limit_count < 0) { + rc = -EINVAL; + goto end; + } + + sde_limit_value = kzalloc(cfg->limit_count * LIMIT_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!sde_limit_value) { + rc = -ENOMEM; + goto end; + } + + rc = sde_validate_limit_node(snp, sde_limit_value, cfg); + if (rc) { + SDE_ERROR("validating limit node failed\n"); + goto end; + } + + rc = sde_read_limit_node(snp, sde_limit_value, cfg); + if (rc) + SDE_ERROR("reading limit node failed\n"); + +end: + kfree(sde_limit_value); + return rc; +} + +static int sde_top_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) +{ + int rc, i, dma_rc, len, prop_count[SDE_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[SDE_PROP_MAX]; + const char *type; + u32 major_version; + + if (!cfg) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + prop_value = kzalloc(SDE_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) + return -ENOMEM; + + rc = _validate_dt_entry(np, sde_prop, ARRAY_SIZE(sde_prop), prop_count, + &len); + if (rc) + goto end; + + rc = _validate_dt_entry(np, &sde_prop[SEC_SID_MASK], 1, + &prop_count[SEC_SID_MASK], NULL); + if (rc) + goto end; + + rc = _read_dt_entry(np, sde_prop, ARRAY_SIZE(sde_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + cfg->mdss_count = 1; + cfg->mdss[0].base = MDSS_BASE_OFFSET; + cfg->mdss[0].id = MDP_TOP; + snprintf(cfg->mdss[0].name, SDE_HW_BLK_NAME_LEN, "mdss_%u", + cfg->mdss[0].id - MDP_TOP); + + cfg->mdp_count = 1; + cfg->mdp[0].id = MDP_TOP; + snprintf(cfg->mdp[0].name, SDE_HW_BLK_NAME_LEN, "top_%u", + cfg->mdp[0].id - MDP_TOP); + cfg->mdp[0].base = PROP_VALUE_ACCESS(prop_value, SDE_OFF, 0); + cfg->mdp[0].len = PROP_VALUE_ACCESS(prop_value, SDE_LEN, 0); + if (!prop_exists[SDE_LEN]) + cfg->mdp[0].len = DEFAULT_SDE_HW_BLOCK_LEN; + + rc = _sde_parse_prop_check(cfg, prop_exists, prop_value); + if (rc) + SDE_ERROR("sde parse property check failed\n"); + + major_version = SDE_HW_MAJOR(cfg->hwversion); + if (major_version < SDE_HW_MAJOR(SDE_HW_VER_500)) + set_bit(SDE_MDP_VSYNC_SEL, &cfg->mdp[0].features); + + if (prop_exists[SEC_SID_MASK]) { + cfg->sec_sid_mask_count = prop_count[SEC_SID_MASK]; + for (i = 0; i < cfg->sec_sid_mask_count; i++) + cfg->sec_sid_mask[i] = + PROP_VALUE_ACCESS(prop_value, SEC_SID_MASK, i); + } + + rc = of_property_read_string(np, sde_prop[QSEED_TYPE].prop_name, &type); + if (!rc && !strcmp(type, "qseedv3")) { + cfg->qseed_type = SDE_SSPP_SCALER_QSEED3; + } else if (!rc && !strcmp(type, "qseedv3lite")) { + cfg->qseed_type = SDE_SSPP_SCALER_QSEED3LITE; + } else if (!rc && !strcmp(type, "qseedv2")) { + cfg->qseed_type = SDE_SSPP_SCALER_QSEED2; + } else if (rc) { + SDE_DEBUG("invalid QSEED configuration\n"); + rc = 0; + } + + rc = of_property_read_string(np, sde_prop[CSC_TYPE].prop_name, &type); + if (!rc && !strcmp(type, "csc")) { + cfg->csc_type = SDE_SSPP_CSC; + } else if (!rc && !strcmp(type, "csc-10bit")) { + cfg->csc_type = SDE_SSPP_CSC_10BIT; + } else if (rc) { + SDE_DEBUG("invalid csc configuration\n"); + rc = 0; + } + + /* + * Current SDE support only Smart DMA 2.0-2.5. + * No support for Smart DMA 1.0 yet. + */ + cfg->smart_dma_rev = 0; + dma_rc = of_property_read_string(np, sde_prop[SMART_DMA_REV].prop_name, + &type); + if (dma_rc) { + SDE_DEBUG("invalid SMART_DMA_REV node in device tree: %d\n", + dma_rc); + } else if (!strcmp(type, "smart_dma_v2p5")) { + cfg->smart_dma_rev = SDE_SSPP_SMART_DMA_V2p5; + } else if (!strcmp(type, "smart_dma_v2")) { + cfg->smart_dma_rev = SDE_SSPP_SMART_DMA_V2; + } else if (!strcmp(type, "smart_dma_v1")) { + SDE_ERROR("smart dma 1.0 is not supported in SDE\n"); + } else { + SDE_DEBUG("unknown smart dma version\n"); + } + + cfg->has_src_split = PROP_VALUE_ACCESS(prop_value, SRC_SPLIT, 0); + cfg->has_dim_layer = PROP_VALUE_ACCESS(prop_value, DIM_LAYER, 0); + cfg->has_idle_pc = PROP_VALUE_ACCESS(prop_value, IDLE_PC, 0); + cfg->pipe_order_type = PROP_VALUE_ACCESS(prop_value, + PIPE_ORDER_VERSION, 0); + cfg->has_base_layer = PROP_VALUE_ACCESS(prop_value, BASE_LAYER, 0); + cfg->scaling_linewidth = 0; + cfg->inline_linewidth = MAX_PRE_ROT_HEIGHT_INLINE_ROT_DEFAULT; + + rc = sde_limit_parse_dt(np, cfg); + if (rc) + SDE_DEBUG("parsing of sde limit failed\n"); +end: + kfree(prop_value); + return rc; +} + +static int sde_parse_reg_dma_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc = 0, i, prop_count[REG_DMA_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + u32 off_count; + bool prop_exists[REG_DMA_PROP_MAX]; + + prop_value = kcalloc(REG_DMA_PROP_MAX, + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, reg_dma_prop, ARRAY_SIZE(reg_dma_prop), + prop_count, &off_count); + if (rc || !off_count) + goto end; + + rc = _read_dt_entry(np, reg_dma_prop, ARRAY_SIZE(reg_dma_prop), + prop_count, prop_exists, prop_value); + if (rc) + goto end; + + sde_cfg->reg_dma_count = off_count; + sde_cfg->dma_cfg.base = PROP_VALUE_ACCESS(prop_value, REG_DMA_OFF, 0); + sde_cfg->dma_cfg.version = PROP_VALUE_ACCESS(prop_value, + REG_DMA_VERSION, 0); + sde_cfg->dma_cfg.trigger_sel_off = PROP_VALUE_ACCESS(prop_value, + REG_DMA_TRIGGER_OFF, 0); + sde_cfg->dma_cfg.broadcast_disabled = PROP_VALUE_ACCESS(prop_value, + REG_DMA_BROADCAST_DISABLED, 0); + sde_cfg->dma_cfg.xin_id = PROP_VALUE_ACCESS(prop_value, + REG_DMA_XIN_ID, 0); + sde_cfg->dma_cfg.clk_ctrl = SDE_CLK_CTRL_LUTDMA; + sde_cfg->dma_cfg.vbif_idx = VBIF_RT; + + for (i = 0; i < sde_cfg->mdp_count; i++) { + sde_cfg->mdp[i].clk_ctrls[sde_cfg->dma_cfg.clk_ctrl].reg_off = + PROP_BITVALUE_ACCESS(prop_value, + REG_DMA_CLK_CTRL, 0, 0); + sde_cfg->mdp[i].clk_ctrls[sde_cfg->dma_cfg.clk_ctrl].bit_off = + PROP_BITVALUE_ACCESS(prop_value, + REG_DMA_CLK_CTRL, 0, 1); + } + +end: + kfree(prop_value); + /* reg dma is optional feature hence return 0 */ + return 0; +} + +static int _sde_perf_parse_dt_validate(struct device_node *np, int *prop_count) +{ + int rc, len; + + rc = _validate_dt_entry(np, sde_perf_prop, ARRAY_SIZE(sde_perf_prop), + prop_count, &len); + if (rc) + return rc; + + rc = _validate_dt_entry(np, &sde_perf_prop[PERF_CDP_SETTING], 1, + &prop_count[PERF_CDP_SETTING], NULL); + if (rc) + return rc; + + return rc; +} + +static int _sde_qos_parse_dt_cfg(struct sde_mdss_cfg *cfg, int *prop_count, + struct sde_prop_value *prop_value, bool *prop_exists) +{ + int i, j; + u32 qos_count = 1, index; + + if (prop_exists[QOS_REFRESH_RATES]) { + qos_count = prop_count[QOS_REFRESH_RATES]; + cfg->perf.qos_refresh_rate = kcalloc(qos_count, + sizeof(u32), GFP_KERNEL); + if (!cfg->perf.qos_refresh_rate) + goto end; + + for (j = 0; j < qos_count; j++) { + cfg->perf.qos_refresh_rate[j] = + PROP_VALUE_ACCESS(prop_value, + QOS_REFRESH_RATES, j); + SDE_DEBUG("qos usage:%d refresh rate:0x%x\n", + j, cfg->perf.qos_refresh_rate[j]); + } + } + cfg->perf.qos_refresh_count = qos_count; + + cfg->perf.danger_lut = kcalloc(qos_count, + sizeof(u64) * SDE_QOS_LUT_USAGE_MAX, GFP_KERNEL); + cfg->perf.safe_lut = kcalloc(qos_count, + sizeof(u64) * SDE_QOS_LUT_USAGE_MAX, GFP_KERNEL); + cfg->perf.creq_lut = kcalloc(qos_count, + sizeof(u64) * SDE_QOS_LUT_USAGE_MAX, GFP_KERNEL); + if (!cfg->perf.creq_lut || !cfg->perf.safe_lut || !cfg->perf.danger_lut) + goto end; + + if (prop_exists[QOS_DANGER_LUT] && + prop_count[QOS_DANGER_LUT] >= (SDE_QOS_LUT_USAGE_MAX * qos_count)) { + for (i = 0; i < prop_count[QOS_DANGER_LUT]; i++) { + cfg->perf.danger_lut[i] = + PROP_VALUE_ACCESS(prop_value, + QOS_DANGER_LUT, i); + SDE_DEBUG("danger usage:%i lut:0x%x\n", + i, cfg->perf.danger_lut[i]); + } + } + + for (i = 0; i < SDE_QOS_LUT_USAGE_MAX; i++) { + static const u32 prop_creq_key[SDE_QOS_LUT_USAGE_MAX] = { + [SDE_QOS_LUT_USAGE_LINEAR] = + QOS_CREQ_LUT_LINEAR, + [SDE_QOS_LUT_USAGE_MACROTILE] = + QOS_CREQ_LUT_MACROTILE, + [SDE_QOS_LUT_USAGE_NRT] = + QOS_CREQ_LUT_NRT, + [SDE_QOS_LUT_USAGE_CWB] = + QOS_CREQ_LUT_CWB, + [SDE_QOS_LUT_USAGE_MACROTILE_QSEED] = + QOS_CREQ_LUT_MACROTILE_QSEED, + }; + static const u32 prop_safe_key[SDE_QOS_LUT_USAGE_MAX] = { + [SDE_QOS_LUT_USAGE_LINEAR] = + QOS_SAFE_LUT_LINEAR, + [SDE_QOS_LUT_USAGE_MACROTILE] = + QOS_SAFE_LUT_MACROTILE, + [SDE_QOS_LUT_USAGE_NRT] = + QOS_SAFE_LUT_NRT, + [SDE_QOS_LUT_USAGE_CWB] = + QOS_SAFE_LUT_CWB, + [SDE_QOS_LUT_USAGE_MACROTILE_QSEED] = + QOS_SAFE_LUT_MACROTILE_QSEED, + }; + int creq_key = prop_creq_key[i]; + int safe_key = prop_safe_key[i]; + u64 lut_hi, lut_lo; + + if (!prop_exists[creq_key] || !prop_exists[safe_key]) + continue; + + for (j = 0; j < qos_count; j++) { + lut_hi = PROP_VALUE_ACCESS(prop_value, creq_key, + (j * 3) + 1); + lut_lo = PROP_VALUE_ACCESS(prop_value, creq_key, + (j * 3) + 2); + index = (j * SDE_QOS_LUT_USAGE_MAX) + i; + + cfg->perf.creq_lut[index] = + (lut_hi << 32) | lut_lo; + cfg->perf.safe_lut[index] = + PROP_VALUE_ACCESS(prop_value, safe_key, + (j * 2) + 1); + SDE_DEBUG("usage:%d creq lut:0x%llx safe:0x%x\n", + index, cfg->perf.creq_lut[index], + cfg->perf.safe_lut[index]); + } + } + + return 0; + +end: + kfree(cfg->perf.qos_refresh_rate); + kfree(cfg->perf.creq_lut); + kfree(cfg->perf.danger_lut); + kfree(cfg->perf.safe_lut); + + return -ENOMEM; +} + +static void _sde_perf_parse_dt_cfg_populate(struct sde_mdss_cfg *cfg, + int *prop_count, + struct sde_prop_value *prop_value, + bool *prop_exists) +{ + cfg->perf.max_bw_low = + prop_exists[PERF_MAX_BW_LOW] ? + PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_LOW, 0) : + DEFAULT_MAX_BW_LOW; + cfg->perf.max_bw_high = + prop_exists[PERF_MAX_BW_HIGH] ? + PROP_VALUE_ACCESS(prop_value, PERF_MAX_BW_HIGH, 0) : + DEFAULT_MAX_BW_HIGH; + cfg->perf.min_core_ib = + prop_exists[PERF_MIN_CORE_IB] ? + PROP_VALUE_ACCESS(prop_value, PERF_MIN_CORE_IB, 0) : + DEFAULT_MAX_BW_LOW; + cfg->perf.min_llcc_ib = + prop_exists[PERF_MIN_LLCC_IB] ? + PROP_VALUE_ACCESS(prop_value, PERF_MIN_LLCC_IB, 0) : + DEFAULT_MAX_BW_LOW; + cfg->perf.min_dram_ib = + prop_exists[PERF_MIN_DRAM_IB] ? + PROP_VALUE_ACCESS(prop_value, PERF_MIN_DRAM_IB, 0) : + DEFAULT_MAX_BW_LOW; + + cfg->perf.undersized_prefill_lines = + prop_exists[PERF_UNDERSIZED_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_UNDERSIZED_PREFILL_LINES, 0) : + DEFAULT_UNDERSIZED_PREFILL_LINES; + cfg->perf.xtra_prefill_lines = + prop_exists[PERF_XTRA_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_XTRA_PREFILL_LINES, 0) : + DEFAULT_XTRA_PREFILL_LINES; + cfg->perf.dest_scale_prefill_lines = + prop_exists[PERF_DEST_SCALE_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_DEST_SCALE_PREFILL_LINES, 0) : + DEFAULT_DEST_SCALE_PREFILL_LINES; + cfg->perf.macrotile_prefill_lines = + prop_exists[PERF_MACROTILE_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_MACROTILE_PREFILL_LINES, 0) : + DEFAULT_MACROTILE_PREFILL_LINES; + cfg->perf.yuv_nv12_prefill_lines = + prop_exists[PERF_YUV_NV12_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_YUV_NV12_PREFILL_LINES, 0) : + DEFAULT_YUV_NV12_PREFILL_LINES; + cfg->perf.linear_prefill_lines = + prop_exists[PERF_LINEAR_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_LINEAR_PREFILL_LINES, 0) : + DEFAULT_LINEAR_PREFILL_LINES; + cfg->perf.downscaling_prefill_lines = + prop_exists[PERF_DOWNSCALING_PREFILL_LINES] ? + PROP_VALUE_ACCESS(prop_value, + PERF_DOWNSCALING_PREFILL_LINES, 0) : + DEFAULT_DOWNSCALING_PREFILL_LINES; + cfg->perf.amortizable_threshold = + prop_exists[PERF_AMORTIZABLE_THRESHOLD] ? + PROP_VALUE_ACCESS(prop_value, + PERF_AMORTIZABLE_THRESHOLD, 0) : + DEFAULT_AMORTIZABLE_THRESHOLD; + cfg->perf.num_mnoc_ports = + prop_exists[PERF_NUM_MNOC_PORTS] ? + PROP_VALUE_ACCESS(prop_value, + PERF_NUM_MNOC_PORTS, 0) : + DEFAULT_MNOC_PORTS; + cfg->perf.axi_bus_width = + prop_exists[PERF_AXI_BUS_WIDTH] ? + PROP_VALUE_ACCESS(prop_value, + PERF_AXI_BUS_WIDTH, 0) : + DEFAULT_AXI_BUS_WIDTH; +} + +static int _sde_perf_parse_dt_cfg(struct device_node *np, + struct sde_mdss_cfg *cfg, int *prop_count, + struct sde_prop_value *prop_value, bool *prop_exists) +{ + int rc, j; + const char *str = NULL; + + /* + * The following performance parameters (e.g. core_ib_ff) are + * mapped directly as device tree string constants. + */ + rc = of_property_read_string(np, + sde_perf_prop[PERF_CORE_IB_FF].prop_name, &str); + cfg->perf.core_ib_ff = rc ? DEFAULT_CORE_IB_FF : str; + rc = of_property_read_string(np, + sde_perf_prop[PERF_CORE_CLK_FF].prop_name, &str); + cfg->perf.core_clk_ff = rc ? DEFAULT_CORE_CLK_FF : str; + rc = of_property_read_string(np, + sde_perf_prop[PERF_COMP_RATIO_RT].prop_name, &str); + cfg->perf.comp_ratio_rt = rc ? DEFAULT_COMP_RATIO_RT : str; + rc = of_property_read_string(np, + sde_perf_prop[PERF_COMP_RATIO_NRT].prop_name, &str); + cfg->perf.comp_ratio_nrt = rc ? DEFAULT_COMP_RATIO_NRT : str; + rc = 0; + + _sde_perf_parse_dt_cfg_populate(cfg, prop_count, prop_value, + prop_exists); + + if (prop_exists[PERF_CDP_SETTING]) { + const u32 prop_size = 2; + u32 count = prop_count[PERF_CDP_SETTING] / prop_size; + + count = min_t(u32, count, SDE_PERF_CDP_USAGE_MAX); + + for (j = 0; j < count; j++) { + cfg->perf.cdp_cfg[j].rd_enable = + PROP_VALUE_ACCESS(prop_value, + PERF_CDP_SETTING, j * prop_size); + cfg->perf.cdp_cfg[j].wr_enable = + PROP_VALUE_ACCESS(prop_value, + PERF_CDP_SETTING, j * prop_size + 1); + SDE_DEBUG("cdp usage:%d rd:%d wr:%d\n", + j, cfg->perf.cdp_cfg[j].rd_enable, + cfg->perf.cdp_cfg[j].wr_enable); + } + + cfg->has_cdp = true; + } + + cfg->perf.cpu_mask = + prop_exists[PERF_CPU_MASK] ? + PROP_VALUE_ACCESS(prop_value, PERF_CPU_MASK, 0) : + DEFAULT_CPU_MASK; + cfg->perf.cpu_dma_latency = + prop_exists[PERF_CPU_DMA_LATENCY] ? + PROP_VALUE_ACCESS(prop_value, PERF_CPU_DMA_LATENCY, 0) : + DEFAULT_CPU_DMA_LATENCY; + cfg->perf.cpu_irq_latency = + prop_exists[PERF_CPU_IRQ_LATENCY] ? + PROP_VALUE_ACCESS(prop_value, PERF_CPU_IRQ_LATENCY, 0) : + PM_QOS_DEFAULT_VALUE; + + return 0; +} + +static int sde_perf_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) +{ + int rc, prop_count[PERF_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[PERF_PROP_MAX]; + + if (!cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(PERF_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _sde_perf_parse_dt_validate(np, prop_count); + if (rc) + goto freeprop; + + rc = _read_dt_entry(np, sde_perf_prop, ARRAY_SIZE(sde_perf_prop), + prop_count, prop_exists, prop_value); + if (rc) + goto freeprop; + + rc = _sde_perf_parse_dt_cfg(np, cfg, prop_count, prop_value, + prop_exists); + +freeprop: + kfree(prop_value); +end: + return rc; +} + +static int sde_qos_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg) +{ + int rc, prop_count[QOS_PROP_MAX]; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[QOS_PROP_MAX]; + + if (!cfg) { + SDE_ERROR("invalid argument\n"); + rc = -EINVAL; + goto end; + } + + prop_value = kzalloc(QOS_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) { + rc = -ENOMEM; + goto end; + } + + rc = _validate_dt_entry(np, sde_qos_prop, ARRAY_SIZE(sde_qos_prop), + prop_count, NULL); + if (rc) + goto freeprop; + + rc = _read_dt_entry(np, sde_qos_prop, ARRAY_SIZE(sde_qos_prop), + prop_count, prop_exists, prop_value); + if (rc) + goto freeprop; + + rc = _sde_qos_parse_dt_cfg(cfg, prop_count, prop_value, prop_exists); + +freeprop: + kfree(prop_value); +end: + return rc; +} + +static int sde_parse_merge_3d_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[HW_PROP_MAX], off_count, i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[HW_PROP_MAX]; + struct sde_merge_3d_cfg *merge_3d; + + prop_value = kcalloc(HW_PROP_MAX, sizeof(struct sde_prop_value), + GFP_KERNEL); + if (!prop_value) + return -ENOMEM; + + rc = _validate_dt_entry(np, merge_3d_prop, ARRAY_SIZE(merge_3d_prop), + prop_count, &off_count); + if (rc) + goto end; + + sde_cfg->merge_3d_count = off_count; + + rc = _read_dt_entry(np, merge_3d_prop, ARRAY_SIZE(merge_3d_prop), + prop_count, + prop_exists, prop_value); + if (rc) { + sde_cfg->merge_3d_count = 0; + goto end; + } + + for (i = 0; i < off_count; i++) { + merge_3d = sde_cfg->merge_3d + i; + merge_3d->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i); + merge_3d->id = MERGE_3D_0 + i; + snprintf(merge_3d->name, SDE_HW_BLK_NAME_LEN, "merge_3d_%u", + merge_3d->id - MERGE_3D_0); + merge_3d->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0); + } + +end: + kfree(prop_value); + return rc; +} + +static int sde_qdss_parse_dt(struct device_node *np, + struct sde_mdss_cfg *sde_cfg) +{ + int rc, prop_count[HW_PROP_MAX], i; + struct sde_prop_value *prop_value = NULL; + bool prop_exists[HW_PROP_MAX]; + u32 off_count; + struct sde_qdss_cfg *qdss; + + if (!sde_cfg) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + prop_value = kzalloc(HW_PROP_MAX * + sizeof(struct sde_prop_value), GFP_KERNEL); + if (!prop_value) + return -ENOMEM; + + rc = _validate_dt_entry(np, qdss_prop, ARRAY_SIZE(qdss_prop), + prop_count, &off_count); + if (rc) { + sde_cfg->qdss_count = 0; + goto end; + } + + sde_cfg->qdss_count = off_count; + + rc = _read_dt_entry(np, qdss_prop, ARRAY_SIZE(qdss_prop), prop_count, + prop_exists, prop_value); + if (rc) + goto end; + + for (i = 0; i < off_count; i++) { + qdss = sde_cfg->qdss + i; + qdss->base = PROP_VALUE_ACCESS(prop_value, HW_OFF, i); + qdss->id = QDSS_0 + i; + snprintf(qdss->name, SDE_HW_BLK_NAME_LEN, "qdss_%u", + qdss->id - QDSS_0); + qdss->len = PROP_VALUE_ACCESS(prop_value, HW_LEN, 0); + } + +end: + kfree(prop_value); + return rc; +} + +static int sde_hardware_format_caps(struct sde_mdss_cfg *sde_cfg, + uint32_t hw_rev) +{ + int rc = 0; + uint32_t dma_list_size, vig_list_size, wb2_list_size; + uint32_t virt_vig_list_size, in_rot_list_size = 0; + uint32_t cursor_list_size = 0; + uint32_t index = 0; + const struct sde_format_extended *inline_fmt_tbl; + + /* cursor input formats */ + if (sde_cfg->has_cursor) { + cursor_list_size = ARRAY_SIZE(cursor_formats); + sde_cfg->cursor_formats = kcalloc(cursor_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->cursor_formats) { + rc = -ENOMEM; + goto out; + } + index = sde_copy_formats(sde_cfg->cursor_formats, + cursor_list_size, 0, cursor_formats, + ARRAY_SIZE(cursor_formats)); + } + + /* DMA pipe input formats */ + dma_list_size = ARRAY_SIZE(plane_formats); + + sde_cfg->dma_formats = kcalloc(dma_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->dma_formats) { + rc = -ENOMEM; + goto free_cursor; + } + + index = sde_copy_formats(sde_cfg->dma_formats, dma_list_size, + 0, plane_formats, ARRAY_SIZE(plane_formats)); + + /* ViG pipe input formats */ + vig_list_size = ARRAY_SIZE(plane_formats_vig); + if (sde_cfg->has_vig_p010) + vig_list_size += ARRAY_SIZE(p010_ubwc_formats); + + sde_cfg->vig_formats = kcalloc(vig_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->vig_formats) { + rc = -ENOMEM; + goto free_dma; + } + + index = sde_copy_formats(sde_cfg->vig_formats, vig_list_size, + 0, plane_formats_vig, ARRAY_SIZE(plane_formats_vig)); + if (sde_cfg->has_vig_p010) + index += sde_copy_formats(sde_cfg->vig_formats, + vig_list_size, index, p010_ubwc_formats, + ARRAY_SIZE(p010_ubwc_formats)); + + /* Virtual ViG pipe input formats (all virt pipes use DMA formats) */ + virt_vig_list_size = ARRAY_SIZE(plane_formats); + sde_cfg->virt_vig_formats = kcalloc(virt_vig_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->virt_vig_formats) { + rc = -ENOMEM; + goto free_vig; + } + + index = sde_copy_formats(sde_cfg->virt_vig_formats, virt_vig_list_size, + 0, plane_formats, ARRAY_SIZE(plane_formats)); + + /* WB output formats */ + wb2_list_size = ARRAY_SIZE(wb2_formats); + sde_cfg->wb_formats = kcalloc(wb2_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->wb_formats) { + SDE_ERROR("failed to allocate wb format list\n"); + rc = -ENOMEM; + goto free_virt; + } + + index = sde_copy_formats(sde_cfg->wb_formats, wb2_list_size, + 0, wb2_formats, ARRAY_SIZE(wb2_formats)); + + /* Rotation enabled input formats */ + if (IS_SDE_INLINE_ROT_REV_100(sde_cfg->true_inline_rot_rev)) { + inline_fmt_tbl = true_inline_rot_v1_fmts; + in_rot_list_size = ARRAY_SIZE(true_inline_rot_v1_fmts); + } else if (IS_SDE_INLINE_ROT_REV_200(sde_cfg->true_inline_rot_rev)) { + inline_fmt_tbl = true_inline_rot_v2_fmts; + in_rot_list_size = ARRAY_SIZE(true_inline_rot_v2_fmts); + } + + if (in_rot_list_size) { + sde_cfg->inline_rot_formats = kcalloc(in_rot_list_size, + sizeof(struct sde_format_extended), GFP_KERNEL); + if (!sde_cfg->inline_rot_formats) { + SDE_ERROR("failed to alloc inline rot format list\n"); + rc = -ENOMEM; + goto free_wb; + } + + index = sde_copy_formats(sde_cfg->inline_rot_formats, + in_rot_list_size, 0, inline_fmt_tbl, in_rot_list_size); + } + + return 0; + +free_wb: + kfree(sde_cfg->wb_formats); +free_virt: + kfree(sde_cfg->virt_vig_formats); +free_vig: + kfree(sde_cfg->vig_formats); +free_dma: + kfree(sde_cfg->dma_formats); +free_cursor: + if (sde_cfg->has_cursor) + kfree(sde_cfg->cursor_formats); +out: + return rc; +} + +static void _sde_hw_setup_uidle(struct sde_uidle_cfg *uidle_cfg) +{ + if (!uidle_cfg->uidle_rev) + return; + + if (IS_SDE_UIDLE_REV_100(uidle_cfg->uidle_rev)) { + uidle_cfg->fal10_exit_cnt = SDE_UIDLE_FAL10_EXIT_CNT; + uidle_cfg->fal10_exit_danger = SDE_UIDLE_FAL10_EXIT_DANGER; + uidle_cfg->fal10_danger = SDE_UIDLE_FAL10_DANGER; + uidle_cfg->fal10_target_idle_time = SDE_UIDLE_FAL10_TARGET_IDLE; + uidle_cfg->fal1_target_idle_time = SDE_UIDLE_FAL1_TARGET_IDLE; + uidle_cfg->fal10_threshold = SDE_UIDLE_FAL10_THRESHOLD; + uidle_cfg->max_dwnscale = SDE_UIDLE_MAX_DWNSCALE; + uidle_cfg->max_fps = SDE_UIDLE_MAX_FPS; + uidle_cfg->debugfs_ctrl = true; + } else { + pr_err("invalid uidle rev:0x%x, disabling uidle\n", + uidle_cfg->uidle_rev); + uidle_cfg->uidle_rev = 0; + } +} + +static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) +{ + int i, rc = 0; + + if (!sde_cfg) + return -EINVAL; + + for (i = 0; i < MDSS_INTR_MAX; i++) + set_bit(i, sde_cfg->mdss_irqs); + + if (IS_MSM8996_TARGET(hw_rev)) { + sde_cfg->perf.min_prefill_lines = 21; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_decimation = true; + } else if (IS_MSM8998_TARGET(hw_rev)) { + sde_cfg->has_wb_ubwc = true; + sde_cfg->perf.min_prefill_lines = 25; + sde_cfg->vbif_qos_nlvl = 4; + sde_cfg->ts_prefill_rev = 1; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_decimation = true; + sde_cfg->has_cursor = true; + sde_cfg->has_hdr = true; + } else if (IS_SDM845_TARGET(hw_rev)) { + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_cwb_support = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x3F71; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_decimation = true; + sde_cfg->has_hdr = true; + sde_cfg->has_vig_p010 = true; + } else if (IS_SDM670_TARGET(hw_rev)) { + sde_cfg->has_wb_ubwc = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_decimation = true; + sde_cfg->has_hdr = true; + sde_cfg->has_vig_p010 = true; + } else if (IS_SM8150_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_qsync = true; + sde_cfg->has_hdr = true; + sde_cfg->has_hdr_plus = true; + set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features); + sde_cfg->has_vig_p010 = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x3F71; + sde_cfg->has_sui_blendstage = true; + sde_cfg->has_3d_merge_reset = true; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_decimation = true; + } else if (IS_SDMSHRIKE_TARGET(hw_rev)) { + sde_cfg->has_wb_ubwc = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_decimation = true; + sde_cfg->has_hdr = true; + sde_cfg->has_vig_p010 = true; + } else if (IS_SM6150_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->has_decimation = true; + sde_cfg->sui_block_xin_mask = 0x2EE1; + sde_cfg->has_sui_blendstage = true; + sde_cfg->has_3d_merge_reset = true; + clear_bit(MDSS_INTR_LTM_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_LTM_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_hdr = true; + sde_cfg->has_vig_p010 = true; + } else if (IS_SDMMAGPIE_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0xE71; + sde_cfg->has_sui_blendstage = true; + sde_cfg->has_3d_merge_reset = true; + } else if (IS_KONA_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 35; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x3F71; + sde_cfg->has_sui_blendstage = true; + sde_cfg->has_3d_merge_reset = true; + clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_hdr = true; + sde_cfg->has_hdr_plus = true; + set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features); + sde_cfg->has_vig_p010 = true; + sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0; + sde_cfg->uidle_cfg.uidle_rev = SDE_UIDLE_VERSION_1_0_0; + } else if (IS_SAIPAN_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_wb_ubwc = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 35; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0xE71; + sde_cfg->has_sui_blendstage = true; + sde_cfg->has_3d_merge_reset = true; + clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_hdr = true; + sde_cfg->has_hdr_plus = true; + set_bit(SDE_MDP_DHDR_MEMPOOL, &sde_cfg->mdp[0].features); + sde_cfg->has_vig_p010 = true; + sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_1_0_0; + sde_cfg->update_tcsr_disp_glitch = true; + } else if (IS_SDMTRINKET_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0xC61; + sde_cfg->has_hdr = false; + sde_cfg->has_sui_blendstage = true; + } else if (IS_BENGAL_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = false; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0xC01; + sde_cfg->has_hdr = false; + sde_cfg->has_sui_blendstage = true; + sde_cfg->allow_gdsc_toggle = true; + clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs); + } else if (IS_LAGOON_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = true; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 35; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x261; + sde_cfg->has_sui_blendstage = true; + clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs); + sde_cfg->has_hdr = true; + sde_cfg->has_vig_p010 = true; + sde_cfg->true_inline_rot_rev = SDE_INLINE_ROT_VERSION_2_0_0; + sde_cfg->has_3d_merge_reset = true; + } else if (IS_SCUBA_TARGET(hw_rev)) { + sde_cfg->has_cwb_support = false; + sde_cfg->has_qsync = true; + sde_cfg->perf.min_prefill_lines = 24; + sde_cfg->vbif_qos_nlvl = 8; + sde_cfg->ts_prefill_rev = 2; + sde_cfg->ctl_rev = SDE_CTL_CFG_VERSION_1_0_0; + sde_cfg->delay_prg_fetch_start = true; + sde_cfg->sui_ns_allowed = true; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x1; + sde_cfg->has_hdr = false; + sde_cfg->has_sui_blendstage = true; + sde_cfg->allow_gdsc_toggle = true; + clear_bit(MDSS_INTR_AD4_0_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTR_AD4_1_INTR, sde_cfg->mdss_irqs); + } else { + SDE_ERROR("unsupported chipset id:%X\n", hw_rev); + sde_cfg->perf.min_prefill_lines = 0xffff; + rc = -ENODEV; + } + + if (!rc) + rc = sde_hardware_format_caps(sde_cfg, hw_rev); + + _sde_hw_setup_uidle(&sde_cfg->uidle_cfg); + + return rc; +} + +static int _sde_hardware_post_caps(struct sde_mdss_cfg *sde_cfg, + uint32_t hw_rev) +{ + int rc = 0, i; + u32 max_horz_deci = 0, max_vert_deci = 0, max_linewidth = 0; + + if (!sde_cfg) + return -EINVAL; + + if (sde_cfg->has_sui_blendstage) + sde_cfg->sui_supported_blendstage = + sde_cfg->max_mixer_blendstages - SDE_STAGE_0; + + for (i = 0; i < sde_cfg->sspp_count; i++) { + if (sde_cfg->sspp[i].sblk) { + max_horz_deci = max(max_horz_deci, + sde_cfg->sspp[i].sblk->maxhdeciexp); + max_vert_deci = max(max_vert_deci, + sde_cfg->sspp[i].sblk->maxvdeciexp); + } + + /* + * set sec-ui blocked SSPP feature flag based on blocked + * xin-mask if sec-ui-misr feature is enabled; + */ + if (sde_cfg->sui_misr_supported + && (sde_cfg->sui_block_xin_mask + & BIT(sde_cfg->sspp[i].xin_id))) + set_bit(SDE_SSPP_BLOCK_SEC_UI, + &sde_cfg->sspp[i].features); + } + + /* this should be updated based on HW rev in future */ + sde_cfg->max_lm_per_display = MAX_LM_PER_DISPLAY; + + for (i = 0; i < sde_cfg->limit_count; i++) { + if (!strcmp(sde_cfg->limit_cfg[i].name, + "sspp_linewidth_usecases")) + max_linewidth = sde_cfg->limit_cfg[i].max_value; + else if (!strcmp(sde_cfg->limit_cfg[i].name, + "sde_bwlimit_usecases")) + sde_cfg->perf.max_bw_high = + sde_cfg->limit_cfg[i].max_value; + } + + if (max_horz_deci) + sde_cfg->max_display_width = (max_linewidth ? max_linewidth : + sde_cfg->max_sspp_linewidth) * max_horz_deci; + else + sde_cfg->max_display_width = sde_cfg->max_sspp_linewidth * + MAX_DOWNSCALE_RATIO; + + if (max_vert_deci) + sde_cfg->max_display_height = + MAX_DISPLAY_HEIGHT_WITH_DECIMATION * max_vert_deci; + else + sde_cfg->max_display_height = MAX_DISPLAY_HEIGHT_WITH_DECIMATION + * MAX_DOWNSCALE_RATIO; + + sde_cfg->min_display_height = MIN_DISPLAY_HEIGHT; + sde_cfg->min_display_width = MIN_DISPLAY_WIDTH; + + return rc; +} + +void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg) +{ + int i, j; + + if (!sde_cfg) + return; + + for (i = 0; i < sde_cfg->sspp_count; i++) + kfree(sde_cfg->sspp[i].sblk); + + for (i = 0; i < sde_cfg->mixer_count; i++) + kfree(sde_cfg->mixer[i].sblk); + + for (i = 0; i < sde_cfg->wb_count; i++) + kfree(sde_cfg->wb[i].sblk); + + for (i = 0; i < sde_cfg->dspp_count; i++) + kfree(sde_cfg->dspp[i].sblk); + + if (sde_cfg->ds_count) + kfree(sde_cfg->ds[0].top); + + for (i = 0; i < sde_cfg->pingpong_count; i++) + kfree(sde_cfg->pingpong[i].sblk); + + for (i = 0; i < sde_cfg->vbif_count; i++) { + kfree(sde_cfg->vbif[i].dynamic_ot_rd_tbl.cfg); + kfree(sde_cfg->vbif[i].dynamic_ot_wr_tbl.cfg); + + for (j = VBIF_RT_CLIENT; j < VBIF_MAX_CLIENT; j++) + kfree(sde_cfg->vbif[i].qos_tbl[j].priority_lvl); + } + + for (i = 0; i < sde_cfg->limit_count; i++) { + kfree(sde_cfg->limit_cfg[i].vector_cfg); + kfree(sde_cfg->limit_cfg[i].value_cfg); + } + + kfree(sde_cfg->perf.qos_refresh_rate); + kfree(sde_cfg->perf.danger_lut); + kfree(sde_cfg->perf.safe_lut); + kfree(sde_cfg->perf.creq_lut); + + kfree(sde_cfg->dma_formats); + kfree(sde_cfg->cursor_formats); + kfree(sde_cfg->vig_formats); + kfree(sde_cfg->wb_formats); + kfree(sde_cfg->virt_vig_formats); + kfree(sde_cfg->inline_rot_formats); + + kfree(sde_cfg); +} + +/************************************************************* + * hardware catalog init + *************************************************************/ +struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 hw_rev) +{ + int rc; + struct sde_mdss_cfg *sde_cfg; + struct device_node *np = dev->dev->of_node; + + sde_cfg = kzalloc(sizeof(*sde_cfg), GFP_KERNEL); + if (!sde_cfg) + return ERR_PTR(-ENOMEM); + + sde_cfg->hwversion = hw_rev; + + rc = _sde_hardware_pre_caps(sde_cfg, hw_rev); + if (rc) + goto end; + + rc = sde_top_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_perf_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_qos_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_rot_parse_dt(np, sde_cfg); + if (rc) + goto end; + + /* uidle must be done before sspp and ctl, + * so if something goes wrong, we won't + * enable it in ctl and sspp. + */ + rc = sde_uidle_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_ctl_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_sspp_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_dspp_top_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_dspp_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_ds_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_dsc_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_pp_parse_dt(np, sde_cfg); + if (rc) + goto end; + + /* mixer parsing should be done after dspp, + * ds and pp for mapping setup + */ + rc = sde_mixer_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_intf_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_wb_parse_dt(np, sde_cfg); + if (rc) + goto end; + + /* cdm parsing should be done after intf and wb for mapping setup */ + rc = sde_cdm_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_vbif_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_parse_reg_dma_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_parse_merge_3d_dt(np, sde_cfg); + if (rc) + goto end; + + rc = sde_qdss_parse_dt(np, sde_cfg); + if (rc) + goto end; + + rc = _sde_hardware_post_caps(sde_cfg, hw_rev); + if (rc) + goto end; + + return sde_cfg; + +end: + sde_hw_catalog_deinit(sde_cfg); + return NULL; +} diff --git a/techpack/display/msm/sde/sde_hw_catalog.h b/techpack/display/msm/sde/sde_hw_catalog.h new file mode 100644 index 0000000000000000000000000000000000000000..bed02d96fbde9e4a6c28fb5ec7e739412d52038b --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_catalog.h @@ -0,0 +1,1484 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_CATALOG_H +#define _SDE_HW_CATALOG_H + +#include <linux/kernel.h> +#include <linux/bug.h> +#include <linux/bitmap.h> +#include <linux/err.h> +#include <linux/msm-bus.h> +#include <linux/of_fdt.h> +#include <drm/drmP.h> +#include "sde_hw_mdss.h" + +/** + * Max hardware block count: For ex: max 12 SSPP pipes or + * 5 ctl paths. In all cases, it can have max 12 hardware blocks + * based on current design + */ +#define MAX_BLOCKS 12 + +#define SDE_HW_VER(MAJOR, MINOR, STEP) (((MAJOR & 0xF) << 28) |\ + ((MINOR & 0xFFF) << 16) |\ + (STEP & 0xFFFF)) + +#define SDE_HW_MAJOR(rev) ((rev) >> 28) +#define SDE_HW_MINOR(rev) (((rev) >> 16) & 0xFFF) +#define SDE_HW_STEP(rev) ((rev) & 0xFFFF) +#define SDE_HW_MAJOR_MINOR(rev) ((rev) >> 16) + +#define IS_SDE_MAJOR_SAME(rev1, rev2) \ + (SDE_HW_MAJOR((rev1)) == SDE_HW_MAJOR((rev2))) + +#define IS_SDE_MAJOR_MINOR_SAME(rev1, rev2) \ + (SDE_HW_MAJOR_MINOR((rev1)) == SDE_HW_MAJOR_MINOR((rev2))) + +#define SDE_HW_VER_170 SDE_HW_VER(1, 7, 0) /* 8996 v1.0 */ +#define SDE_HW_VER_171 SDE_HW_VER(1, 7, 1) /* 8996 v2.0 */ +#define SDE_HW_VER_172 SDE_HW_VER(1, 7, 2) /* 8996 v3.0 */ +#define SDE_HW_VER_300 SDE_HW_VER(3, 0, 0) /* 8998 v1.0 */ +#define SDE_HW_VER_301 SDE_HW_VER(3, 0, 1) /* 8998 v1.1 */ +#define SDE_HW_VER_400 SDE_HW_VER(4, 0, 0) /* sdm845 v1.0 */ +#define SDE_HW_VER_401 SDE_HW_VER(4, 0, 1) /* sdm845 v2.0 */ +#define SDE_HW_VER_410 SDE_HW_VER(4, 1, 0) /* sdm670 v1.0 */ +#define SDE_HW_VER_500 SDE_HW_VER(5, 0, 0) /* sm8150 v1.0 */ +#define SDE_HW_VER_501 SDE_HW_VER(5, 0, 1) /* sm8150 v2.0 */ +#define SDE_HW_VER_510 SDE_HW_VER(5, 1, 0) /* sdmshrike v1.0 */ +#define SDE_HW_VER_520 SDE_HW_VER(5, 2, 0) /* sdmmagpie v1.0 */ +#define SDE_HW_VER_530 SDE_HW_VER(5, 3, 0) /* sm6150 v1.0 */ +#define SDE_HW_VER_540 SDE_HW_VER(5, 4, 0) /* sdmtrinket v1.0 */ +#define SDE_HW_VER_600 SDE_HW_VER(6, 0, 0) /* kona */ +#define SDE_HW_VER_610 SDE_HW_VER(6, 1, 0) /* sm7250 */ +#define SDE_HW_VER_630 SDE_HW_VER(6, 3, 0) /* bengal */ +#define SDE_HW_VER_640 SDE_HW_VER(6, 4, 0) /* lagoon */ +#define SDE_HW_VER_650 SDE_HW_VER(6, 5, 0) /* scuba */ + +#define IS_MSM8996_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_170) +#define IS_MSM8998_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_300) +#define IS_SDM845_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_400) +#define IS_SDM670_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_410) +#define IS_SM8150_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_500) +#define IS_SDMSHRIKE_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_510) +#define IS_SDMMAGPIE_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_520) +#define IS_SM6150_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_530) +#define IS_SDMTRINKET_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_540) +#define IS_KONA_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_600) +#define IS_SAIPAN_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_610) +#define IS_BENGAL_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_630) +#define IS_LAGOON_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_640) +#define IS_SCUBA_TARGET(rev) IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_VER_650) + +#define SDE_HW_BLK_NAME_LEN 16 + +#define MAX_IMG_WIDTH 0x3fff +#define MAX_IMG_HEIGHT 0x3fff + +#define CRTC_DUAL_MIXERS 2 + +#define SDE_COLOR_PROCESS_VER(MAJOR, MINOR) \ + ((((MAJOR) & 0xFFFF) << 16) | (((MINOR) & 0xFFFF))) +#define SDE_COLOR_PROCESS_MAJOR(version) (((version) & 0xFFFF0000) >> 16) +#define SDE_COLOR_PROCESS_MINOR(version) ((version) & 0xFFFF) + +#define MAX_XIN_COUNT 16 +#define SSPP_SUBBLK_COUNT_MAX 2 +#define LIMIT_SUBBLK_COUNT_MAX 10 + +#define SDE_CTL_CFG_VERSION_1_0_0 0x100 +#define MAX_INTF_PER_CTL_V1 2 +#define MAX_DSC_PER_CTL_V1 2 +#define MAX_CWB_PER_CTL_V1 2 +#define MAX_MERGE_3D_PER_CTL_V1 2 +#define MAX_WB_PER_CTL_V1 1 +#define MAX_CDM_PER_CTL_V1 1 +#define IS_SDE_CTL_REV_100(rev) \ + ((rev) == SDE_CTL_CFG_VERSION_1_0_0) + +/** + * True inline rotation supported versions + */ +#define SDE_INLINE_ROT_VERSION_1_0_0 0x100 +#define SDE_INLINE_ROT_VERSION_2_0_0 0x200 + +#define IS_SDE_INLINE_ROT_REV_100(rev) \ + ((rev) == SDE_INLINE_ROT_VERSION_1_0_0) +#define IS_SDE_INLINE_ROT_REV_200(rev) \ + ((rev) == SDE_INLINE_ROT_VERSION_2_0_0) + +/* + * UIDLE supported versions + */ +#define SDE_UIDLE_VERSION_1_0_0 0x100 +#define IS_SDE_UIDLE_REV_100(rev) \ + ((rev) == SDE_UIDLE_VERSION_1_0_0) + +#define SDE_HW_UBWC_VER(rev) \ + SDE_HW_VER((((rev) >> 8) & 0xF), (((rev) >> 4) & 0xF), ((rev) & 0xF)) + +/** + * Supported UBWC feature versions + */ +enum { + SDE_HW_UBWC_VER_10 = SDE_HW_UBWC_VER(0x100), + SDE_HW_UBWC_VER_20 = SDE_HW_UBWC_VER(0x200), + SDE_HW_UBWC_VER_30 = SDE_HW_UBWC_VER(0x300), + SDE_HW_UBWC_VER_40 = SDE_HW_UBWC_VER(0x400), +}; +#define IS_UBWC_10_SUPPORTED(rev) \ + IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_UBWC_VER_10) +#define IS_UBWC_20_SUPPORTED(rev) \ + IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_UBWC_VER_20) +#define IS_UBWC_30_SUPPORTED(rev) \ + IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_UBWC_VER_30) +#define IS_UBWC_40_SUPPORTED(rev) \ + IS_SDE_MAJOR_MINOR_SAME((rev), SDE_HW_UBWC_VER_40) + +/** + * Supported SSPP system cache settings + */ +#define SSPP_SYS_CACHE_EN_FLAG BIT(0) +#define SSPP_SYS_CACHE_SCID BIT(1) +#define SSPP_SYS_CACHE_OP_MODE BIT(2) +#define SSPP_SYS_CACHE_OP_TYPE BIT(3) +#define SSPP_SYS_CACHE_NO_ALLOC BIT(4) + +/** + * SDE INTERRUPTS - maintains the possible hw irq's allowed by HW + * The order in this enum must match the order of the irqs defined + * by 'sde_irq_map' + */ +enum sde_intr_enum { + MDSS_INTR_SSPP_TOP0_INTR, + MDSS_INTR_SSPP_TOP0_INTR2, + MDSS_INTF_TEAR_1_INTR, + MDSS_INTF_TEAR_2_INTR, + MDSS_INTR_SSPP_TOP0_HIST_INTR, + MDSS_INTR_INTF_0_INTR, + MDSS_INTR_INTF_1_INTR, + MDSS_INTR_INTF_2_INTR, + MDSS_INTR_INTF_3_INTR, + MDSS_INTR_INTF_4_INTR, + MDSS_INTR_AD4_0_INTR, + MDSS_INTR_AD4_1_INTR, + MDSS_INTR_LTM_0_INTR, + MDSS_INTR_LTM_1_INTR, + MDSS_INTR_MAX +}; + +/** + * MDP TOP BLOCK features + * @SDE_MDP_PANIC_PER_PIPE Panic configuration needs to be be done per pipe + * @SDE_MDP_10BIT_SUPPORT, Chipset supports 10 bit pixel formats + * @SDE_MDP_BWC, MDSS HW supports Bandwidth compression. + * @SDE_MDP_UBWC_1_0, This chipsets supports Universal Bandwidth + * compression initial revision + * @SDE_MDP_UBWC_1_5, Universal Bandwidth compression version 1.5 + * @SDE_MDP_VSYNC_SEL Vsync selection for command mode panels + * @SDE_MDP_DHDR_MEMPOOL Dynamic HDR Metadata mempool present + * @SDE_MDP_MAX Maximum value + + */ +enum { + SDE_MDP_PANIC_PER_PIPE = 0x1, + SDE_MDP_10BIT_SUPPORT, + SDE_MDP_BWC, + SDE_MDP_UBWC_1_0, + SDE_MDP_UBWC_1_5, + SDE_MDP_VSYNC_SEL, + SDE_MDP_DHDR_MEMPOOL, + SDE_MDP_MAX +}; + +/** + * SSPP sub-blocks/features + * @SDE_SSPP_SRC Src and fetch part of the pipes, + * @SDE_SSPP_SCALER_QSEED2, QSEED2 algorithm support + * @SDE_SSPP_SCALER_QSEED3, QSEED3 alogorithm support + * @SDE_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes + * @SDE_SSPP_CSC, Support of Color space converion + * @SDE_SSPP_CSC_10BIT, Support of 10-bit Color space conversion + * @SDE_SSPP_HSIC, Global HSIC control + * @SDE_SSPP_MEMCOLOR Memory Color Support + * @SDE_SSPP_PCC, Color correction support + * @SDE_SSPP_CURSOR, SSPP can be used as a cursor layer + * @SDE_SSPP_EXCL_RECT, SSPP supports exclusion rect + * @SDE_SSPP_SMART_DMA_V1, SmartDMA 1.0 support + * @SDE_SSPP_SMART_DMA_V2, SmartDMA 2.0 support + * @SDE_SSPP_SMART_DMA_V2p5, SmartDMA 2.5 support + * @SDE_SSPP_VIG_IGC, VIG 1D LUT IGC + * @SDE_SSPP_VIG_GAMUT, VIG 3D LUT Gamut + * @SDE_SSPP_DMA_IGC, DMA 1D LUT IGC + * @SDE_SSPP_DMA_GC, DMA 1D LUT GC + * @SDE_SSPP_INVERSE_PMA Alpha unmultiply (PMA) support + * @SDE_SSPP_DGM_INVERSE_PMA Alpha unmultiply (PMA) support in DGM block + * @SDE_SSPP_DGM_CSC Support of color space conversion in DGM block + * @SDE_SSPP_SEC_UI_ALLOWED Allows secure-ui layers + * @SDE_SSPP_BLOCK_SEC_UI Blocks secure-ui layers + * @SDE_SSPP_SCALER_QSEED3LITE Qseed3lite algorithm support + * @SDE_SSPP_TRUE_INLINE_ROT, Support of SSPP true inline rotation v1 + * @SDE_SSPP_PREDOWNSCALE Support pre-downscale X-direction by 2 for inline + * @SDE_SSPP_PREDOWNSCALE_Y Support pre-downscale Y-direction for inline + * @SDE_SSPP_MAX maximum value + */ +enum { + SDE_SSPP_SRC = 0x1, + SDE_SSPP_SCALER_QSEED2, + SDE_SSPP_SCALER_QSEED3, + SDE_SSPP_SCALER_RGB, + SDE_SSPP_CSC, + SDE_SSPP_CSC_10BIT, + SDE_SSPP_HSIC, + SDE_SSPP_MEMCOLOR, + SDE_SSPP_PCC, + SDE_SSPP_CURSOR, + SDE_SSPP_EXCL_RECT, + SDE_SSPP_SMART_DMA_V1, + SDE_SSPP_SMART_DMA_V2, + SDE_SSPP_SMART_DMA_V2p5, + SDE_SSPP_VIG_IGC, + SDE_SSPP_VIG_GAMUT, + SDE_SSPP_DMA_IGC, + SDE_SSPP_DMA_GC, + SDE_SSPP_INVERSE_PMA, + SDE_SSPP_DGM_INVERSE_PMA, + SDE_SSPP_DGM_CSC, + SDE_SSPP_SEC_UI_ALLOWED, + SDE_SSPP_BLOCK_SEC_UI, + SDE_SSPP_SCALER_QSEED3LITE, + SDE_SSPP_TRUE_INLINE_ROT, + SDE_SSPP_PREDOWNSCALE, + SDE_SSPP_PREDOWNSCALE_Y, + SDE_SSPP_MAX +}; + +/** + * SDE performance features + * @SDE_PERF_SSPP_QOS, SSPP support QoS control, danger/safe/creq + * @SDE_PERF_SSPP_QOS_8LVL, SSPP support 8-level QoS control + * @SDE_PERF_SSPP_TS_PREFILL Supports prefill with traffic shaper + * @SDE_PERF_SSPP_TS_PREFILL_REC1 Supports prefill with traffic shaper multirec + * @SDE_PERF_SSPP_CDP Supports client driven prefetch + * @SDE_PERF_SSPP_SYS_CACHE, SSPP supports system cache + * @SDE_PERF_SSPP_UIDLE, sspp supports uidle + * @SDE_PERF_SSPP_MAX Maximum value + */ +enum { + SDE_PERF_SSPP_QOS = 0x1, + SDE_PERF_SSPP_QOS_8LVL, + SDE_PERF_SSPP_TS_PREFILL, + SDE_PERF_SSPP_TS_PREFILL_REC1, + SDE_PERF_SSPP_CDP, + SDE_PERF_SSPP_SYS_CACHE, + SDE_PERF_SSPP_UIDLE, + SDE_PERF_SSPP_MAX +}; + +/* + * MIXER sub-blocks/features + * @SDE_MIXER_LAYER Layer mixer layer blend configuration, + * @SDE_MIXER_SOURCESPLIT Layer mixer supports source-split configuration + * @SDE_MIXER_GC Gamma correction block + * @SDE_DIM_LAYER Layer mixer supports dim layer + * @SDE_DISP_CWB_PREF Layer mixer preferred for CWB + * @SDE_DISP_PRIMARY_PREF Layer mixer preferred for primary display + * @SDE_DISP_SECONDARY_PREF Layer mixer preferred for secondary display + * @SDE_MIXER_MAX maximum value + */ +enum { + SDE_MIXER_LAYER = 0x1, + SDE_MIXER_SOURCESPLIT, + SDE_MIXER_GC, + SDE_DIM_LAYER, + SDE_DISP_PRIMARY_PREF, + SDE_DISP_SECONDARY_PREF, + SDE_DISP_CWB_PREF, + SDE_MIXER_MAX +}; + +/** + * DSPP sub-blocks + * @SDE_DSPP_IGC DSPP Inverse gamma correction block + * @SDE_DSPP_PCC Panel color correction block + * @SDE_DSPP_GC Gamma correction block + * @SDE_DSPP_HSIC Global HSIC block + * @SDE_DSPP_MEMCOLOR Memory Color block + * @SDE_DSPP_SIXZONE Six zone block + * @SDE_DSPP_GAMUT Gamut bloc + * @SDE_DSPP_DITHER Dither block + * @SDE_DSPP_HIST Histogram block + * @SDE_DSPP_VLUT PA VLUT block + * @SDE_DSPP_AD AD block + * @SDE_DSPP_LTM LTM block + * @SDE_DSPP_MAX maximum value + */ +enum { + SDE_DSPP_IGC = 0x1, + SDE_DSPP_PCC, + SDE_DSPP_GC, + SDE_DSPP_HSIC, + SDE_DSPP_MEMCOLOR, + SDE_DSPP_SIXZONE, + SDE_DSPP_GAMUT, + SDE_DSPP_DITHER, + SDE_DSPP_HIST, + SDE_DSPP_VLUT, + SDE_DSPP_AD, + SDE_DSPP_LTM, + SDE_DSPP_MAX +}; + +/** + * LTM sub-features + * @SDE_LTM_INIT LTM INIT feature + * @SDE_LTM_ROI LTM ROI feature + * @SDE_LTM_VLUT LTM VLUT feature + * @SDE_LTM_MAX maximum value + */ +enum { + SDE_LTM_INIT = 0x1, + SDE_LTM_ROI, + SDE_LTM_VLUT, + SDE_LTM_MAX +}; + +/** + * PINGPONG sub-blocks + * @SDE_PINGPONG_TE Tear check block + * @SDE_PINGPONG_TE2 Additional tear check block for split pipes + * @SDE_PINGPONG_SPLIT PP block supports split fifo + * @SDE_PINGPONG_SLAVE PP block is a suitable slave for split fifo + * @SDE_PINGPONG_DSC, Display stream compression blocks + * @SDE_PINGPONG_DITHER, Dither blocks + * @SDE_PINGPONG_MERGE_3D, Separate MERGE_3D block exists + * @SDE_PINGPONG_MAX + */ +enum { + SDE_PINGPONG_TE = 0x1, + SDE_PINGPONG_TE2, + SDE_PINGPONG_SPLIT, + SDE_PINGPONG_SLAVE, + SDE_PINGPONG_DSC, + SDE_PINGPONG_DITHER, + SDE_PINGPONG_MERGE_3D, + SDE_PINGPONG_MAX +}; + +/** DSC sub-blocks + * @SDE_DSC_OUTPUT_CTRL Supports the control of the pp id which gets + * the pixel output from this DSC. + * @SDE_DSC_MAX + */ +enum { + SDE_DSC_OUTPUT_CTRL = 0x1, + SDE_DSC_MAX +}; + +/** + * CTL sub-blocks + * @SDE_CTL_SPLIT_DISPLAY CTL supports video mode split display + * @SDE_CTL_PINGPONG_SPLIT CTL supports pingpong split + * @SDE_CTL_PRIMARY_PREF CTL preferred for primary display + * @SDE_CTL_ACTIVE_CFG CTL configuration is specified using active + * blocks + * @SDE_CTL_UIDLE CTL supports uidle + * @SDE_CTL_MAX + */ +enum { + SDE_CTL_SPLIT_DISPLAY = 0x1, + SDE_CTL_PINGPONG_SPLIT, + SDE_CTL_PRIMARY_PREF, + SDE_CTL_ACTIVE_CFG, + SDE_CTL_UIDLE, + SDE_CTL_MAX +}; + +/** + * INTF sub-blocks + * @SDE_INTF_INPUT_CTRL Supports the setting of pp block from which + * pixel data arrives to this INTF + * @SDE_INTF_TE INTF block has TE configuration support + * @SDE_INTF_MAX + */ +enum { + SDE_INTF_INPUT_CTRL = 0x1, + SDE_INTF_TE, + SDE_INTF_MAX +}; + +/** + * WB sub-blocks and features + * @SDE_WB_LINE_MODE Writeback module supports line/linear mode + * @SDE_WB_BLOCK_MODE Writeback module supports block mode read + * @SDE_WB_ROTATE rotation support,this is available if writeback + * supports block mode read + * @SDE_WB_CSC Writeback color conversion block support + * @SDE_WB_CHROMA_DOWN, Writeback chroma down block, + * @SDE_WB_DOWNSCALE, Writeback integer downscaler, + * @SDE_WB_DITHER, Dither block + * @SDE_WB_TRAFFIC_SHAPER, Writeback traffic shaper bloc + * @SDE_WB_UBWC, Writeback Universal bandwidth compression + * @SDE_WB_YUV_CONFIG Writeback supports output of YUV colorspace + * @SDE_WB_PIPE_ALPHA Writeback supports pipe alpha + * @SDE_WB_XY_ROI_OFFSET Writeback supports x/y-offset of out ROI in + * the destination image + * @SDE_WB_QOS, Writeback supports QoS control, danger/safe/creq + * @SDE_WB_QOS_8LVL, Writeback supports 8-level QoS control + * @SDE_WB_CDP Writeback supports client driven prefetch + * @SDE_WB_INPUT_CTRL Writeback supports from which pp block input pixel + * data arrives. + * @SDE_WB_HAS_CWB Writeback block supports concurrent writeback + * @SDE_WB_CWB_CTRL Separate CWB control is available for configuring + * @SDE_WB_MAX maximum value + */ +enum { + SDE_WB_LINE_MODE = 0x1, + SDE_WB_BLOCK_MODE, + SDE_WB_ROTATE = SDE_WB_BLOCK_MODE, + SDE_WB_CSC, + SDE_WB_CHROMA_DOWN, + SDE_WB_DOWNSCALE, + SDE_WB_DITHER, + SDE_WB_TRAFFIC_SHAPER, + SDE_WB_UBWC, + SDE_WB_YUV_CONFIG, + SDE_WB_PIPE_ALPHA, + SDE_WB_XY_ROI_OFFSET, + SDE_WB_QOS, + SDE_WB_QOS_8LVL, + SDE_WB_CDP, + SDE_WB_INPUT_CTRL, + SDE_WB_HAS_CWB, + SDE_WB_CWB_CTRL, + SDE_WB_MAX +}; + +/* CDM features + * @SDE_CDM_INPUT_CTRL CDM supports from which pp block intput pixel data + * arrives + * @SDE_CDM_MAX maximum value + */ +enum { + SDE_CDM_INPUT_CTRL = 0x1, + SDE_CDM_MAX +}; + +/** + * VBIF sub-blocks and features + * @SDE_VBIF_QOS_OTLIM VBIF supports OT Limit + * @SDE_VBIF_QOS_REMAP VBIF supports QoS priority remap + * @SDE_VBIF_MAX maximum value + */ +enum { + SDE_VBIF_QOS_OTLIM = 0x1, + SDE_VBIF_QOS_REMAP, + SDE_VBIF_MAX +}; + +/** + * MACRO SDE_HW_BLK_INFO - information of HW blocks inside SDE + * @name: string name for debug purposes + * @id: enum identifying this block + * @base: register base offset to mdss + * @len: length of hardware block + * @features bit mask identifying sub-blocks/features + * @perf_features bit mask identifying performance sub-blocks/features + */ +#define SDE_HW_BLK_INFO \ + char name[SDE_HW_BLK_NAME_LEN]; \ + u32 id; \ + u32 base; \ + u32 len; \ + unsigned long features; \ + unsigned long perf_features + +/** + * MACRO SDE_HW_SUBBLK_INFO - information of HW sub-block inside SDE + * @name: string name for debug purposes + * @id: enum identifying this sub-block + * @base: offset of this sub-block relative to the block + * offset + * @len register block length of this sub-block + */ +#define SDE_HW_SUBBLK_INFO \ + char name[SDE_HW_BLK_NAME_LEN]; \ + u32 id; \ + u32 base; \ + u32 len + +/** + * struct sde_src_blk: SSPP part of the source pipes + * @info: HW register and features supported by this sub-blk + */ +struct sde_src_blk { + SDE_HW_SUBBLK_INFO; +}; + +/** + * struct sde_scaler_blk: Scaler information + * @info: HW register and features supported by this sub-blk + * @version: qseed block revision + * @h_preload: horizontal preload + * @v_preload: vertical preload + */ +struct sde_scaler_blk { + SDE_HW_SUBBLK_INFO; + u32 version; + u32 h_preload; + u32 v_preload; +}; + +struct sde_csc_blk { + SDE_HW_SUBBLK_INFO; +}; + +/** + * struct sde_pp_blk : Pixel processing sub-blk information + * @info: HW register and features supported by this sub-blk + * @version: HW Algorithm version + */ +struct sde_pp_blk { + SDE_HW_SUBBLK_INFO; + u32 version; +}; + +/** + * struct sde_format_extended - define sde specific pixel format+modifier + * @fourcc_format: Base FOURCC pixel format code + * @modifier: 64-bit drm format modifier, same modifier must be applied to all + * framebuffer planes + */ +struct sde_format_extended { + uint32_t fourcc_format; + uint64_t modifier; +}; + +/** + * enum sde_qos_lut_usage - define QoS LUT use cases + */ +enum sde_qos_lut_usage { + SDE_QOS_LUT_USAGE_LINEAR, + SDE_QOS_LUT_USAGE_MACROTILE, + SDE_QOS_LUT_USAGE_NRT, + SDE_QOS_LUT_USAGE_CWB, + SDE_QOS_LUT_USAGE_MACROTILE_QSEED, + SDE_QOS_LUT_USAGE_MAX, +}; + +/** + * struct sde_sspp_sub_blks : SSPP sub-blocks + * @maxdwnscale: max downscale ratio supported(without DECIMATION) + * @maxupscale: maxupscale ratio supported + * @maxwidth: max pixelwidth supported by this pipe + * @creq_vblank: creq priority during vertical blanking + * @danger_vblank: danger priority during vertical blanking + * @pixel_ram_size: size of latency hiding and de-tiling buffer in bytes + * @smart_dma_priority: hw priority of rect1 of multirect pipe + * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps + * @max_per_pipe_bw_high: maximum allowable bandwidth of this pipe in kBps + * in case of no VFE + * @src_blk: + * @scaler_blk: + * @csc_blk: + * @hsic: + * @memcolor: + * @pcc_blk: + * @gamut_blk: 3D LUT gamut block + * @num_igc_blk: number of IGC block + * @igc_blk: 1D LUT IGC block + * @num_gc_blk: number of GC block + * @gc_blk: 1D LUT GC block + * @num_dgm_csc_blk: number of DGM CSC blocks + * @dgm_csc_blk: DGM CSC blocks + * @format_list: Pointer to list of supported formats + * @virt_format_list: Pointer to list of supported formats for virtual planes + * @in_rot_format_list: Pointer to list of supported formats for inline rotation + * @in_rot_maxdwnscale_rt_num: max downscale ratio for inline rotation + * rt clients - numerator + * @in_rot_maxdwnscale_rt_denom: max downscale ratio for inline rotation + * rt clients - denominator + * @in_rot_maxdwnscale_nrt: max downscale ratio for inline rotation nrt clients + * @in_rot_maxdwnscale_rt_nopd_num: downscale threshold for when pre-downscale + * must be enabled on HW with this support. + * @in_rot_maxdwnscale_rt_nopd_denom: downscale threshold for when pre-downscale + * must be enabled on HW with this support. + * @in_rot_maxheight: max pre rotated height for inline rotation + * @llcc_scid: scid for the system cache + * @llcc_slice size: slice size of the system cache + */ +struct sde_sspp_sub_blks { + u32 maxlinewidth; + u32 creq_vblank; + u32 danger_vblank; + u32 pixel_ram_size; + u32 maxdwnscale; + u32 maxupscale; + u32 maxhdeciexp; /* max decimation is 2^value */ + u32 maxvdeciexp; /* max decimation is 2^value */ + u32 smart_dma_priority; + u32 max_per_pipe_bw; + u32 max_per_pipe_bw_high; + struct sde_src_blk src_blk; + struct sde_scaler_blk scaler_blk; + struct sde_pp_blk csc_blk; + struct sde_pp_blk hsic_blk; + struct sde_pp_blk memcolor_blk; + struct sde_pp_blk pcc_blk; + struct sde_pp_blk gamut_blk; + u32 num_igc_blk; + struct sde_pp_blk igc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_gc_blk; + struct sde_pp_blk gc_blk[SSPP_SUBBLK_COUNT_MAX]; + u32 num_dgm_csc_blk; + struct sde_pp_blk dgm_csc_blk[SSPP_SUBBLK_COUNT_MAX]; + + const struct sde_format_extended *format_list; + const struct sde_format_extended *virt_format_list; + const struct sde_format_extended *in_rot_format_list; + u32 in_rot_maxdwnscale_rt_num; + u32 in_rot_maxdwnscale_rt_denom; + u32 in_rot_maxdwnscale_nrt; + u32 in_rot_maxdwnscale_rt_nopd_num; + u32 in_rot_maxdwnscale_rt_nopd_denom; + u32 in_rot_maxheight; + int llcc_scid; + size_t llcc_slice_size; +}; + +/** + * struct sde_lm_sub_blks: information of mixer block + * @maxwidth: Max pixel width supported by this mixer + * @maxblendstages: Max number of blend-stages supported + * @blendstage_base: Blend-stage register base offset + * @gc: gamma correction block + */ +struct sde_lm_sub_blks { + u32 maxwidth; + u32 maxblendstages; + u32 blendstage_base[MAX_BLOCKS]; + struct sde_pp_blk gc; +}; + +struct sde_dspp_sub_blks { + struct sde_pp_blk igc; + struct sde_pp_blk pcc; + struct sde_pp_blk gc; + struct sde_pp_blk hsic; + struct sde_pp_blk memcolor; + struct sde_pp_blk sixzone; + struct sde_pp_blk gamut; + struct sde_pp_blk dither; + struct sde_pp_blk hist; + struct sde_pp_blk ad; + struct sde_pp_blk ltm; + struct sde_pp_blk vlut; +}; + +struct sde_pingpong_sub_blks { + struct sde_pp_blk te; + struct sde_pp_blk te2; + struct sde_pp_blk dsc; + struct sde_pp_blk dither; +}; + +struct sde_wb_sub_blocks { + u32 maxlinewidth; +}; + +struct sde_mdss_base_cfg { + SDE_HW_BLK_INFO; +}; + +/** + * sde_clk_ctrl_type - Defines top level clock control signals + */ +enum sde_clk_ctrl_type { + SDE_CLK_CTRL_NONE, + SDE_CLK_CTRL_VIG0, + SDE_CLK_CTRL_VIG1, + SDE_CLK_CTRL_VIG2, + SDE_CLK_CTRL_VIG3, + SDE_CLK_CTRL_VIG4, + SDE_CLK_CTRL_RGB0, + SDE_CLK_CTRL_RGB1, + SDE_CLK_CTRL_RGB2, + SDE_CLK_CTRL_RGB3, + SDE_CLK_CTRL_DMA0, + SDE_CLK_CTRL_DMA1, + SDE_CLK_CTRL_CURSOR0, + SDE_CLK_CTRL_CURSOR1, + SDE_CLK_CTRL_WB0, + SDE_CLK_CTRL_WB1, + SDE_CLK_CTRL_WB2, + SDE_CLK_CTRL_LUTDMA, + SDE_CLK_CTRL_MAX, +}; + +/* struct sde_clk_ctrl_reg : Clock control register + * @reg_off: register offset + * @bit_off: bit offset + */ +struct sde_clk_ctrl_reg { + u32 reg_off; + u32 bit_off; +}; + +/* struct sde_mdp_cfg : MDP TOP-BLK instance info + * @id: index identifying this block + * @base: register base offset to mdss + * @features bit mask identifying sub-blocks/features + * @highest_bank_bit: UBWC parameter + * @ubwc_static: ubwc static configuration + * @ubwc_swizzle: ubwc default swizzle setting + * @has_dest_scaler: indicates support of destination scaler + * @smart_panel_align_mode: split display smart panel align modes + * @clk_ctrls clock control register definition + */ +struct sde_mdp_cfg { + SDE_HW_BLK_INFO; + u32 highest_bank_bit; + u32 ubwc_static; + u32 ubwc_swizzle; + bool has_dest_scaler; + u32 smart_panel_align_mode; + struct sde_clk_ctrl_reg clk_ctrls[SDE_CLK_CTRL_MAX]; +}; + +/* struct sde_uidle_cfg : MDP TOP-BLK instance info + * @id: index identifying this block + * @base: register base offset to mdss + * @features: bit mask identifying sub-blocks/features + * @fal10_exit_cnt: fal10 exit counter + * @fal10_exit_danger: fal10 exit danger level + * @fal10_danger: fal10 danger level + * @fal10_target_idle_time: fal10 targeted time in uS + * @fal1_target_idle_time: fal1 targeted time in uS + * @fal10_threshold: fal10 threshold value + * @max_downscale: maximum downscaling ratio x1000. + * This ratio is multiplied x1000 to allow + * 3 decimal precision digits. + * @max_fps: maximum fps to allow micro idle + * @uidle_rev: uidle revision supported by the target, + * zero if no support + * @debugfs_perf: enable/disable performance counters and status + * logging + * @debugfs_ctrl: uidle is enabled/disabled through debugfs + * @perf_cntr_en: performance counters are enabled/disabled + */ +struct sde_uidle_cfg { + SDE_HW_BLK_INFO; + /* global settings */ + u32 fal10_exit_cnt; + u32 fal10_exit_danger; + u32 fal10_danger; + /* per-pipe settings */ + u32 fal10_target_idle_time; + u32 fal1_target_idle_time; + u32 fal10_threshold; + u32 max_dwnscale; + u32 max_fps; + u32 uidle_rev; + u32 debugfs_perf; + bool debugfs_ctrl; + bool perf_cntr_en; +}; + +/* struct sde_mdp_cfg : MDP TOP-BLK instance info + * @id: index identifying this block + * @base: register base offset to mdss + * @features bit mask identifying sub-blocks/features + */ +struct sde_ctl_cfg { + SDE_HW_BLK_INFO; +}; + +/** + * struct sde_sspp_cfg - information of source pipes + * @id: index identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk: SSPP sub-blocks information + * @xin_id: bus client identifier + * @clk_ctrl clock control identifier + * @type sspp type identifier + */ +struct sde_sspp_cfg { + SDE_HW_BLK_INFO; + struct sde_sspp_sub_blks *sblk; + u32 xin_id; + enum sde_clk_ctrl_type clk_ctrl; + u32 type; +}; + +/** + * struct sde_lm_cfg - information of layer mixer blocks + * @id: index identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk: LM Sub-blocks information + * @dspp: ID of connected DSPP, DSPP_MAX if unsupported + * @pingpong: ID of connected PingPong, PINGPONG_MAX if unsupported + * @ds: ID of connected DS, DS_MAX if unsupported + * @lm_pair_mask: Bitmask of LMs that can be controlled by same CTL + */ +struct sde_lm_cfg { + SDE_HW_BLK_INFO; + const struct sde_lm_sub_blks *sblk; + u32 dspp; + u32 pingpong; + u32 ds; + unsigned long lm_pair_mask; +}; + +/** + * struct sde_dspp_cfg - information of DSPP top block + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * supported by this block + */ +struct sde_dspp_top_cfg { + SDE_HW_BLK_INFO; +}; + +/** + * struct sde_dspp_cfg - information of DSPP blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * supported by this block + * @sblk sub-blocks information + */ +struct sde_dspp_cfg { + SDE_HW_BLK_INFO; + const struct sde_dspp_sub_blks *sblk; +}; + +/** + * struct sde_ds_top_cfg - information of dest scaler top + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying features + * @version hw version of dest scaler + * @maxinputwidth maximum input line width + * @maxoutputwidth maximum output line width + * @maxupscale maximum upscale ratio + */ +struct sde_ds_top_cfg { + SDE_HW_BLK_INFO; + u32 version; + u32 maxinputwidth; + u32 maxoutputwidth; + u32 maxupscale; +}; + +/** + * struct sde_ds_cfg - information of dest scaler blocks + * @id enum identifying this block + * @base register offset wrt DS top offset + * @features bit mask identifying features + * @version hw version of the qseed block + * @top DS top information + */ +struct sde_ds_cfg { + SDE_HW_BLK_INFO; + u32 version; + const struct sde_ds_top_cfg *top; +}; + +/** + * struct sde_pingpong_cfg - information of PING-PONG blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk sub-blocks information + * @merge_3d_id merge_3d block id + */ +struct sde_pingpong_cfg { + SDE_HW_BLK_INFO; + const struct sde_pingpong_sub_blks *sblk; + int merge_3d_id; +}; + +/** + * struct sde_dsc_cfg - information of DSC blocks + * @id enum identifying this block + * @base register offset of this block + * @len: length of hardware block + * @features bit mask identifying sub-blocks/features + * @dsc_pair_mask: Bitmask of DSCs that can be controlled by same CTL + */ +struct sde_dsc_cfg { + SDE_HW_BLK_INFO; + DECLARE_BITMAP(dsc_pair_mask, DSC_MAX); +}; + +/** + * struct sde_cdm_cfg - information of chroma down blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @intf_connect Bitmask of INTF IDs this CDM can connect to + * @wb_connect: Bitmask of Writeback IDs this CDM can connect to + */ +struct sde_cdm_cfg { + SDE_HW_BLK_INFO; + unsigned long intf_connect; + unsigned long wb_connect; +}; + +/** + * struct sde_intf_cfg - information of timing engine blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @type: Interface type(DSI, DP, HDMI) + * @controller_id: Controller Instance ID in case of multiple of intf type + * @prog_fetch_lines_worst_case Worst case latency num lines needed to prefetch + */ +struct sde_intf_cfg { + SDE_HW_BLK_INFO; + u32 type; /* interface type*/ + u32 controller_id; + u32 prog_fetch_lines_worst_case; +}; + +/** + * struct sde_wb_cfg - information of writeback blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @sblk sub-block information + * @format_list: Pointer to list of supported formats + * @vbif_idx vbif identifier + * @xin_id client interface identifier + * @clk_ctrl clock control identifier + */ +struct sde_wb_cfg { + SDE_HW_BLK_INFO; + const struct sde_wb_sub_blocks *sblk; + const struct sde_format_extended *format_list; + u32 vbif_idx; + u32 xin_id; + enum sde_clk_ctrl_type clk_ctrl; +}; + +/** + * struct sde_merge_3d_cfg - information of merge_3d blocks + * @id enum identifying this block + * @base register offset of this block + * @len: length of hardware block + * @features bit mask identifying sub-blocks/features + */ +struct sde_merge_3d_cfg { + SDE_HW_BLK_INFO; +}; + +/** + * struct sde_qdss_cfg - information of qdss blocks + * @id enum identifying this block + * @base register offset of this block + * @len: length of hardware block + * @features bit mask identifying sub-blocks/features + */ +struct sde_qdss_cfg { + SDE_HW_BLK_INFO; +}; + +/* + * struct sde_vbif_dynamic_ot_cfg - dynamic OT setting + * @pps pixel per seconds + * @ot_limit OT limit to use up to specified pixel per second + */ +struct sde_vbif_dynamic_ot_cfg { + u64 pps; + u32 ot_limit; +}; + +/** + * struct sde_vbif_dynamic_ot_tbl - dynamic OT setting table + * @count length of cfg + * @cfg pointer to array of configuration settings with + * ascending requirements + */ +struct sde_vbif_dynamic_ot_tbl { + u32 count; + struct sde_vbif_dynamic_ot_cfg *cfg; +}; + +/** + * struct sde_vbif_qos_tbl - QoS priority table + * @npriority_lvl num of priority level + * @priority_lvl pointer to array of priority level in ascending order + */ +struct sde_vbif_qos_tbl { + u32 npriority_lvl; + u32 *priority_lvl; +}; + +/** + * enum sde_vbif_client_type + * @VBIF_RT_CLIENT: real time client + * @VBIF_NRT_CLIENT: non-realtime clients like writeback + * @VBIF_CWB_CLIENT: concurrent writeback client + * @VBIF_LUTDMA_CLIENT: LUTDMA client + * @VBIF_MAX_CLIENT: max number of clients + */ +enum sde_vbif_client_type { + VBIF_RT_CLIENT, + VBIF_NRT_CLIENT, + VBIF_CWB_CLIENT, + VBIF_LUTDMA_CLIENT, + VBIF_MAX_CLIENT +}; + +/** + * struct sde_vbif_cfg - information of VBIF blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @ot_rd_limit default OT read limit + * @ot_wr_limit default OT write limit + * @xin_halt_timeout maximum time (in usec) for xin to halt + * @dynamic_ot_rd_tbl dynamic OT read configuration table + * @dynamic_ot_wr_tbl dynamic OT write configuration table + * @qos_tbl Array of QoS priority table + * @memtype_count number of defined memtypes + * @memtype array of xin memtype definitions + */ +struct sde_vbif_cfg { + SDE_HW_BLK_INFO; + u32 default_ot_rd_limit; + u32 default_ot_wr_limit; + u32 xin_halt_timeout; + struct sde_vbif_dynamic_ot_tbl dynamic_ot_rd_tbl; + struct sde_vbif_dynamic_ot_tbl dynamic_ot_wr_tbl; + struct sde_vbif_qos_tbl qos_tbl[VBIF_MAX_CLIENT]; + u32 memtype_count; + u32 memtype[MAX_XIN_COUNT]; +}; +/** + * struct sde_reg_dma_cfg - information of lut dma blocks + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + * @version version of lutdma hw block + * @trigger_sel_off offset to trigger select registers of lutdma + * @broadcast_disabled flag indicating if broadcast usage should be avoided + * @xin_id VBIF xin client-id for LUTDMA + * @vbif_idx VBIF id (RT/NRT) + * @clk_ctrl VBIF xin client clk-ctrl + */ +struct sde_reg_dma_cfg { + SDE_HW_BLK_INFO; + u32 version; + u32 trigger_sel_off; + u32 broadcast_disabled; + u32 xin_id; + u32 vbif_idx; + enum sde_clk_ctrl_type clk_ctrl; +}; + +/** + * Define CDP use cases + * @SDE_PERF_CDP_UDAGE_RT: real-time use cases + * @SDE_PERF_CDP_USAGE_NRT: non real-time use cases such as WFD + */ +enum { + SDE_PERF_CDP_USAGE_RT, + SDE_PERF_CDP_USAGE_NRT, + SDE_PERF_CDP_USAGE_MAX +}; + +/** + * struct sde_perf_cdp_cfg - define CDP use case configuration + * @rd_enable: true if read pipe CDP is enabled + * @wr_enable: true if write pipe CDP is enabled + */ +struct sde_perf_cdp_cfg { + bool rd_enable; + bool wr_enable; +}; + +/** + * struct sde_sc_cfg - define system cache configuration + * @has_sys_cache: true if system cache is enabled + * @llcc_scid: scid for the system cache + * @llcc_slice_size: slice size of the system cache + */ +struct sde_sc_cfg { + bool has_sys_cache; + int llcc_scid; + size_t llcc_slice_size; +}; + +/** + * struct sde_perf_cfg - performance control settings + * @max_bw_low low threshold of maximum bandwidth (kbps) + * @max_bw_high high threshold of maximum bandwidth (kbps) + * @min_core_ib minimum bandwidth for core (kbps) + * @min_core_ib minimum mnoc ib vote in kbps + * @min_llcc_ib minimum llcc ib vote in kbps + * @min_dram_ib minimum dram ib vote in kbps + * @core_ib_ff core instantaneous bandwidth fudge factor + * @core_clk_ff core clock fudge factor + * @comp_ratio_rt string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio> + * @comp_ratio_nrt string of 0 or more of <fourcc>/<ven>/<mod>/<comp ratio> + * @undersized_prefill_lines undersized prefill in lines + * @xtra_prefill_lines extra prefill latency in lines + * @dest_scale_prefill_lines destination scaler latency in lines + * @macrotile_perfill_lines macrotile latency in lines + * @yuv_nv12_prefill_lines yuv_nv12 latency in lines + * @linear_prefill_lines linear latency in lines + * @downscaling_prefill_lines downscaling latency in lines + * @amortizable_theshold minimum y position for traffic shaping prefill + * @min_prefill_lines minimum pipeline latency in lines + * @danger_lut: linear, macrotile, etc. danger luts + * @safe_lut: linear, macrotile, macrotile_qseed, etc. safe luts + * @creq_lut: linear, macrotile, non_realtime, cwb, etc. creq luts + * @qos_refresh_count: total refresh count for possible different luts + * @qos_refresh_rate: different refresh rates for luts + * @cdp_cfg cdp use case configurations + * @cpu_mask: pm_qos cpu mask value + * @cpu_dma_latency: pm_qos cpu dma latency value + * @cpu_irq_latency: pm_qos cpu irq latency value + * @axi_bus_width: axi bus width value in bytes + * @num_mnoc_ports: number of mnoc ports + */ +struct sde_perf_cfg { + u32 max_bw_low; + u32 max_bw_high; + u32 min_core_ib; + u32 min_llcc_ib; + u32 min_dram_ib; + const char *core_ib_ff; + const char *core_clk_ff; + const char *comp_ratio_rt; + const char *comp_ratio_nrt; + u32 undersized_prefill_lines; + u32 xtra_prefill_lines; + u32 dest_scale_prefill_lines; + u32 macrotile_prefill_lines; + u32 yuv_nv12_prefill_lines; + u32 linear_prefill_lines; + u32 downscaling_prefill_lines; + u32 amortizable_threshold; + u32 min_prefill_lines; + u64 *danger_lut; + u64 *safe_lut; + u64 *creq_lut; + u32 qos_refresh_count; + u32 *qos_refresh_rate; + struct sde_perf_cdp_cfg cdp_cfg[SDE_PERF_CDP_USAGE_MAX]; + u32 cpu_mask; + u32 cpu_dma_latency; + u32 cpu_irq_latency; + u32 axi_bus_width; + u32 num_mnoc_ports; +}; + +/** + * struct limit_vector_cfg - information on the usecase for each limit + * @usecase: usecase for each limit + * @value: id corresponding to each usecase + */ +struct limit_vector_cfg { + const char *usecase; + u32 value; +}; + +/** + * struct limit_value_cfg - information on the value of usecase + * @use_concur: usecase for each limit + * @value: value corresponding to usecase for each limit + */ +struct limit_value_cfg { + u32 use_concur; + u32 value; +}; + +/** + * struct sde_limit_cfg - information om different mdp limits + * @name: name of the limit property + * @lmt_vec_cnt: number of vector values for each limit + * @lmt_case_cnt: number of usecases for each limit + * @max_value: maximum possible value for this property + * @vector_cfg: pointer to the vector entries containing info on usecase + * @value_cfg: pointer to the value of each vector entry + */ +struct sde_limit_cfg { + const char *name; + u32 lmt_vec_cnt; + u32 lmt_case_cnt; + u32 max_value; + struct limit_vector_cfg *vector_cfg; + struct limit_value_cfg *value_cfg; +}; + +/** + * struct sde_mdss_cfg - information of MDSS HW + * This is the main catalog data structure representing + * this HW version. Contains number of instances, + * register offsets, capabilities of the all MDSS HW sub-blocks. + * + * @max_sspp_linewidth max source pipe line width support. + * @vig_sspp_linewidth max vig source pipe line width support. + * @scaling_linewidth max vig source pipe linewidth for scaling usecases + * @inline_linewidth max source pipe linewidth for inline rotation + * @max_mixer_width max layer mixer line width support. + * @max_mixer_blendstages max layer mixer blend stages or + * supported z order + * @max_wb_linewidth max writeback line width support. + * @max_display_width maximum display width support. + * @max_display_height maximum display height support. + * @max_lm_per_display maximum layer mixer per display + * @min_display_width minimum display width support. + * @min_display_height minimum display height support. + * @qseed_type qseed2 or qseed3 support. + * @csc_type csc or csc_10bit support. + * @smart_dma_rev Supported version of SmartDMA feature. + * @ctl_rev supported version of control path. + * @has_src_split source split feature status + * @has_cdp Client driven prefetch feature status + * @has_wb_ubwc UBWC feature supported on WB + * @has_cwb_support indicates if device supports primary capture through CWB + * @ubwc_version UBWC feature version (0x0 for not supported) + * @ubwc_bw_calc_version indicate how UBWC BW has to be calculated + * @has_idle_pc indicate if idle power collapse feature is supported + * @has_hdr HDR feature support + * @has_hdr_plus HDR10+ feature support + * @dma_formats Supported formats for dma pipe + * @cursor_formats Supported formats for cursor pipe + * @vig_formats Supported formats for vig pipe + * @wb_formats Supported formats for wb + * @virt_vig_formats Supported formats for virtual vig pipe + * @vbif_qos_nlvl number of vbif QoS priority level + * @ts_prefill_rev prefill traffic shaper feature revision + * @true_inline_rot_rev inline rotator feature revision + * @macrotile_mode UBWC parameter for macro tile channel distribution + * @pipe_order_type indicate if it is required to specify pipe order + * @delay_prg_fetch_start indicates if throttling the fetch start is required + * @has_qsync Supports qsync feature + * @has_3d_merge_reset Supports 3D merge reset + * @has_decimation Supports decimation + * @update_tcsr_disp_glitch flag to enable HW workaround to avoid spurious + * transactions during suspend + * @has_base_layer Supports staging layer as base layer + * @allow_gdsc_toggle Flag to check if gdsc toggle is needed after crtc is + * disabled when external vote is present + * @sc_cfg: system cache configuration + * @uidle_cfg Settings for uidle feature + * @sui_misr_supported indicate if secure-ui-misr is supported + * @sui_block_xin_mask mask of all the xin-clients to be blocked during + * secure-ui when secure-ui-misr feature is supported + * @sec_sid_mask_count number of SID masks + * @sec_sid_mask SID masks used during the scm_call for transition + * between secure/non-secure sessions + * @sui_ns_allowed flag to indicate non-secure context banks are allowed + * during secure-ui session + * @sui_supported_blendstage secure-ui supported blendstage + * @has_sui_blendstage flag to indicate secure-ui has a blendstage restriction + * @has_cursor indicates if hardware cursor is supported + * @has_vig_p010 indicates if vig pipe supports p010 format + * @inline_rot_formats formats supported by the inline rotator feature + * @mdss_irqs bitmap with the irqs supported by the target + */ +struct sde_mdss_cfg { + u32 hwversion; + + u32 max_sspp_linewidth; + u32 vig_sspp_linewidth; + u32 scaling_linewidth; + u32 inline_linewidth; + u32 max_mixer_width; + u32 max_mixer_blendstages; + u32 max_wb_linewidth; + + u32 max_display_width; + u32 max_display_height; + u32 min_display_width; + u32 min_display_height; + u32 max_lm_per_display; + + u32 qseed_type; + u32 csc_type; + u32 smart_dma_rev; + u32 ctl_rev; + bool has_src_split; + bool has_cdp; + bool has_dim_layer; + bool has_wb_ubwc; + bool has_cwb_support; + u32 ubwc_version; + u32 ubwc_bw_calc_version; + bool has_idle_pc; + u32 vbif_qos_nlvl; + u32 ts_prefill_rev; + u32 true_inline_rot_rev; + u32 macrotile_mode; + u32 pipe_order_type; + bool delay_prg_fetch_start; + bool has_qsync; + bool has_3d_merge_reset; + bool has_decimation; + bool update_tcsr_disp_glitch; + bool has_base_layer; + bool allow_gdsc_toggle; + + struct sde_sc_cfg sc_cfg; + + bool sui_misr_supported; + u32 sui_block_xin_mask; + + u32 sec_sid_mask_count; + u32 sec_sid_mask[MAX_BLOCKS]; + u32 sui_ns_allowed; + u32 sui_supported_blendstage; + bool has_sui_blendstage; + + bool has_hdr; + bool has_hdr_plus; + bool has_cursor; + bool has_vig_p010; + u32 mdss_count; + struct sde_mdss_base_cfg mdss[MAX_BLOCKS]; + + u32 mdp_count; + struct sde_mdp_cfg mdp[MAX_BLOCKS]; + + /* uidle is a singleton */ + struct sde_uidle_cfg uidle_cfg; + + u32 ctl_count; + struct sde_ctl_cfg ctl[MAX_BLOCKS]; + + u32 sspp_count; + struct sde_sspp_cfg sspp[MAX_BLOCKS]; + + u32 mixer_count; + struct sde_lm_cfg mixer[MAX_BLOCKS]; + + struct sde_dspp_top_cfg dspp_top; + + u32 dspp_count; + struct sde_dspp_cfg dspp[MAX_BLOCKS]; + + u32 ds_count; + struct sde_ds_cfg ds[MAX_BLOCKS]; + + u32 pingpong_count; + struct sde_pingpong_cfg pingpong[MAX_BLOCKS]; + + u32 dsc_count; + struct sde_dsc_cfg dsc[MAX_BLOCKS]; + + u32 cdm_count; + struct sde_cdm_cfg cdm[MAX_BLOCKS]; + + u32 intf_count; + struct sde_intf_cfg intf[MAX_BLOCKS]; + + u32 wb_count; + struct sde_wb_cfg wb[MAX_BLOCKS]; + + u32 vbif_count; + struct sde_vbif_cfg vbif[MAX_BLOCKS]; + + u32 reg_dma_count; + struct sde_reg_dma_cfg dma_cfg; + + u32 ad_count; + u32 ltm_count; + + u32 merge_3d_count; + struct sde_merge_3d_cfg merge_3d[MAX_BLOCKS]; + + u32 qdss_count; + struct sde_qdss_cfg qdss[MAX_BLOCKS]; + + u32 limit_count; + struct sde_limit_cfg limit_cfg[LIMIT_SUBBLK_COUNT_MAX]; + + /* Add additional block data structures here */ + + struct sde_perf_cfg perf; + struct sde_format_extended *dma_formats; + struct sde_format_extended *cursor_formats; + struct sde_format_extended *vig_formats; + struct sde_format_extended *wb_formats; + struct sde_format_extended *virt_vig_formats; + struct sde_format_extended *inline_rot_formats; + + DECLARE_BITMAP(mdss_irqs, MDSS_INTR_MAX); +}; + +struct sde_mdss_hw_cfg_handler { + u32 major; + u32 minor; + struct sde_mdss_cfg* (*cfg_init)(u32 data); +}; + +/* + * Access Macros + */ +#define BLK_MDP(s) ((s)->mdp) +#define BLK_CTL(s) ((s)->ctl) +#define BLK_VIG(s) ((s)->vig) +#define BLK_RGB(s) ((s)->rgb) +#define BLK_DMA(s) ((s)->dma) +#define BLK_CURSOR(s) ((s)->cursor) +#define BLK_MIXER(s) ((s)->mixer) +#define BLK_DSPP(s) ((s)->dspp) +#define BLK_DS(s) ((s)->ds) +#define BLK_PINGPONG(s) ((s)->pingpong) +#define BLK_CDM(s) ((s)->cdm) +#define BLK_INTF(s) ((s)->intf) +#define BLK_WB(s) ((s)->wb) +#define BLK_AD(s) ((s)->ad) +#define BLK_LTM(s) ((s)->ltm) + +/** + * sde_hw_set_preference: populate the individual hw lm preferences, + * overwrite if exists + * @sde_cfg: pointer to sspp cfg + * @num_lm: num lms to set preference + * @disp_type: is the given display primary/secondary + */ +void sde_hw_mixer_set_preference(struct sde_mdss_cfg *sde_cfg, u32 num_lm, + uint32_t disp_type); + +/** + * sde_hw_catalog_init - sde hardware catalog init API parses dtsi property + * and stores all parsed offset, hardware capabilities in config structure. + * @dev: drm device node. + * @hw_rev: caller needs provide the hardware revision before parsing. + * + * Return: parsed sde config structure + */ +struct sde_mdss_cfg *sde_hw_catalog_init(struct drm_device *dev, u32 hw_rev); + +/** + * sde_hw_catalog_deinit - sde hardware catalog cleanup + * @sde_cfg: pointer returned from init function + */ +void sde_hw_catalog_deinit(struct sde_mdss_cfg *sde_cfg); + +/** + * sde_hw_sspp_multirect_enabled - check multirect enabled for the sspp + * @cfg: pointer to sspp cfg + */ +static inline bool sde_hw_sspp_multirect_enabled(const struct sde_sspp_cfg *cfg) +{ + return test_bit(SDE_SSPP_SMART_DMA_V1, &cfg->features) || + test_bit(SDE_SSPP_SMART_DMA_V2, &cfg->features) || + test_bit(SDE_SSPP_SMART_DMA_V2p5, &cfg->features); +} + +static inline bool sde_hw_intf_te_supported(const struct sde_mdss_cfg *sde_cfg) +{ + return test_bit(SDE_INTF_TE, &(sde_cfg->intf[0].features)); +} +#endif /* _SDE_HW_CATALOG_H */ diff --git a/techpack/display/msm/sde/sde_hw_catalog_format.h b/techpack/display/msm/sde/sde_hw_catalog_format.h new file mode 100644 index 0000000000000000000000000000000000000000..fe5d8e40223b3797d77101b2976a81b8077e98a3 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_catalog_format.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_mdss.h" + +#define RGB_10BIT_FMTS {DRM_FORMAT_BGRA1010102, 0}, \ + {DRM_FORMAT_BGRX1010102, 0}, \ + {DRM_FORMAT_RGBA1010102, 0}, \ + {DRM_FORMAT_RGBX1010102, 0}, \ + {DRM_FORMAT_ABGR2101010, 0}, \ + {DRM_FORMAT_ABGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, \ + {DRM_FORMAT_XBGR2101010, 0}, \ + {DRM_FORMAT_XBGR2101010, DRM_FORMAT_MOD_QCOM_COMPRESSED}, \ + {DRM_FORMAT_ARGB2101010, 0}, \ + {DRM_FORMAT_XRGB2101010, 0} + +#define RGB_FMTS {DRM_FORMAT_ARGB8888, 0}, \ + {DRM_FORMAT_ABGR8888, 0}, \ + {DRM_FORMAT_RGBA8888, 0}, \ + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, \ + {DRM_FORMAT_BGRA8888, 0}, \ + {DRM_FORMAT_XRGB8888, 0}, \ + {DRM_FORMAT_RGBX8888, 0}, \ + {DRM_FORMAT_BGRX8888, 0}, \ + {DRM_FORMAT_XBGR8888, 0}, \ + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, \ + {DRM_FORMAT_RGB888, 0}, \ + {DRM_FORMAT_BGR888, 0}, \ + {DRM_FORMAT_RGB565, 0}, \ + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, \ + {DRM_FORMAT_BGR565, 0}, \ + {DRM_FORMAT_ARGB1555, 0}, \ + {DRM_FORMAT_ABGR1555, 0}, \ + {DRM_FORMAT_RGBA5551, 0}, \ + {DRM_FORMAT_BGRA5551, 0}, \ + {DRM_FORMAT_XRGB1555, 0}, \ + {DRM_FORMAT_XBGR1555, 0}, \ + {DRM_FORMAT_RGBX5551, 0}, \ + {DRM_FORMAT_BGRX5551, 0}, \ + {DRM_FORMAT_ARGB4444, 0}, \ + {DRM_FORMAT_ABGR4444, 0}, \ + {DRM_FORMAT_RGBA4444, 0}, \ + {DRM_FORMAT_BGRA4444, 0}, \ + {DRM_FORMAT_XRGB4444, 0}, \ + {DRM_FORMAT_XBGR4444, 0}, \ + {DRM_FORMAT_RGBX4444, 0}, \ + {DRM_FORMAT_BGRX4444, 0} + +#define TP10_UBWC_FMTS {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED | \ + DRM_FORMAT_MOD_QCOM_DX | DRM_FORMAT_MOD_QCOM_TIGHT} + +#define P010_FMTS {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_DX} + +#define P010_UBWC_FMTS {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_DX | \ + DRM_FORMAT_MOD_QCOM_COMPRESSED} + + +static const struct sde_format_extended plane_formats[] = { + RGB_FMTS, + RGB_10BIT_FMTS, + {0, 0}, +}; + +static const struct sde_format_extended plane_formats_vig[] = { + RGB_FMTS, + + {DRM_FORMAT_NV12, 0}, + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_NV21, 0}, + {DRM_FORMAT_NV16, 0}, + {DRM_FORMAT_NV61, 0}, + {DRM_FORMAT_VYUY, 0}, + {DRM_FORMAT_UYVY, 0}, + {DRM_FORMAT_YUYV, 0}, + {DRM_FORMAT_YVYU, 0}, + {DRM_FORMAT_YUV420, 0}, + {DRM_FORMAT_YVU420, 0}, + + RGB_10BIT_FMTS, + TP10_UBWC_FMTS, + P010_FMTS, + + {0, 0}, +}; + +static const struct sde_format_extended cursor_formats[] = { + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {0, 0}, +}; + +static const struct sde_format_extended wb2_formats[] = { + {DRM_FORMAT_RGB565, 0}, + {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_RGB888, 0}, + {DRM_FORMAT_ARGB8888, 0}, + {DRM_FORMAT_RGBA8888, 0}, + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_XRGB8888, 0}, + {DRM_FORMAT_RGBX8888, 0}, + {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_ARGB1555, 0}, + {DRM_FORMAT_RGBA5551, 0}, + {DRM_FORMAT_XRGB1555, 0}, + {DRM_FORMAT_RGBX5551, 0}, + {DRM_FORMAT_ARGB4444, 0}, + {DRM_FORMAT_RGBA4444, 0}, + {DRM_FORMAT_RGBX4444, 0}, + {DRM_FORMAT_XRGB4444, 0}, + + {DRM_FORMAT_BGR565, 0}, + {DRM_FORMAT_BGR888, 0}, + {DRM_FORMAT_ABGR8888, 0}, + {DRM_FORMAT_BGRA8888, 0}, + {DRM_FORMAT_BGRX8888, 0}, + {DRM_FORMAT_XBGR8888, 0}, + {DRM_FORMAT_ABGR1555, 0}, + {DRM_FORMAT_BGRA5551, 0}, + {DRM_FORMAT_XBGR1555, 0}, + {DRM_FORMAT_BGRX5551, 0}, + {DRM_FORMAT_ABGR4444, 0}, + {DRM_FORMAT_BGRA4444, 0}, + {DRM_FORMAT_BGRX4444, 0}, + {DRM_FORMAT_XBGR4444, 0}, + + {DRM_FORMAT_YUV420, 0}, + {DRM_FORMAT_NV12, 0}, + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_NV16, 0}, + {DRM_FORMAT_YUYV, 0}, + + RGB_10BIT_FMTS, + TP10_UBWC_FMTS, + + {0, 0}, +}; + +static const struct sde_format_extended p010_ubwc_formats[] = { + P010_UBWC_FMTS, +}; + +static const struct sde_format_extended true_inline_rot_v1_fmts[] = { + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + TP10_UBWC_FMTS, + {0, 0}, +}; + +static const struct sde_format_extended true_inline_rot_v2_fmts[] = { + {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + {DRM_FORMAT_NV12, DRM_FORMAT_MOD_QCOM_COMPRESSED}, + TP10_UBWC_FMTS, + P010_UBWC_FMTS, + {0, 0}, +}; diff --git a/techpack/display/msm/sde/sde_hw_cdm.c b/techpack/display/msm/sde/sde_hw_cdm.c new file mode 100644 index 0000000000000000000000000000000000000000..df25ce8df2e86ce600ff881bf0aa3b9d9d97525b --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_cdm.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_mdss.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_cdm.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define CDM_CSC_10_OPMODE 0x000 +#define CDM_CSC_10_BASE 0x004 + +#define CDM_CDWN2_OP_MODE 0x100 +#define CDM_CDWN2_CLAMP_OUT 0x104 +#define CDM_CDWN2_PARAMS_3D_0 0x108 +#define CDM_CDWN2_PARAMS_3D_1 0x10C +#define CDM_CDWN2_COEFF_COSITE_H_0 0x110 +#define CDM_CDWN2_COEFF_COSITE_H_1 0x114 +#define CDM_CDWN2_COEFF_COSITE_H_2 0x118 +#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C +#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 +#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 +#define CDM_CDWN2_COEFF_COSITE_V 0x128 +#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C +#define CDM_CDWN2_OUT_SIZE 0x130 + +#define CDM_HDMI_PACK_OP_MODE 0x200 +#define CDM_CSC_10_MATRIX_COEFF_0 0x004 + +#define CDM_MUX 0x224 + +/** + * Horizontal coefficients for cosite chroma downscale + * s13 representation of coefficients + */ +static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; + +/** + * Horizontal coefficients for offsite chroma downscale + */ +static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; + +/** + * Vertical coefficients for cosite chroma downscale + */ +static u32 cosite_v_coeff[] = {0x00080004}; +/** + * Vertical coefficients for offsite chroma downscale + */ +static u32 offsite_v_coeff[] = {0x00060002}; + +/* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */ +static struct sde_csc_cfg rgb2yuv_cfg = { + { + 0x0083, 0x0102, 0x0032, + 0x1fb5, 0x1f6c, 0x00e1, + 0x00e1, 0x1f45, 0x1fdc + }, + { 0x00, 0x00, 0x00 }, + { 0x0040, 0x0200, 0x0200 }, + { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, + { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, +}; + +static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->cdm_count; i++) { + if (cdm == m->cdm[i].id) { + b->base_off = addr; + b->blk_off = m->cdm[i].base; + b->length = m->cdm[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_CDM; + return &m->cdm[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static int sde_hw_cdm_setup_csc_10bit(struct sde_hw_cdm *ctx, + struct sde_csc_cfg *data) +{ + sde_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, data, true); + + return 0; +} + +static int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx, + struct sde_hw_cdm_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 opmode = 0; + u32 out_size = 0; + + if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT) + opmode &= ~BIT(7); + else + opmode |= BIT(7); + + /* ENABLE DWNS_H bit */ + opmode |= BIT(1); + + switch (cfg->h_cdwn_type) { + case CDM_CDWN_DISABLE: + /* CLEAR METHOD_H field */ + opmode &= ~(0x18); + /* CLEAR DWNS_H bit */ + opmode &= ~BIT(1); + break; + case CDM_CDWN_PIXEL_DROP: + /* Clear METHOD_H field (pixel drop is 0) */ + opmode &= ~(0x18); + break; + case CDM_CDWN_AVG: + /* Clear METHOD_H field (Average is 0x1) */ + opmode &= ~(0x18); + opmode |= (0x1 << 0x3); + break; + case CDM_CDWN_COSITE: + /* Clear METHOD_H field (Average is 0x2) */ + opmode &= ~(0x18); + opmode |= (0x2 << 0x3); + /* Co-site horizontal coefficients */ + SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, + cosite_h_coeff[0]); + SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, + cosite_h_coeff[1]); + SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, + cosite_h_coeff[2]); + break; + case CDM_CDWN_OFFSITE: + /* Clear METHOD_H field (Average is 0x3) */ + opmode &= ~(0x18); + opmode |= (0x3 << 0x3); + + /* Off-site horizontal coefficients */ + SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, + offsite_h_coeff[0]); + SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, + offsite_h_coeff[1]); + SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, + offsite_h_coeff[2]); + break; + default: + pr_err("%s invalid horz down sampling type\n", __func__); + return -EINVAL; + } + + /* ENABLE DWNS_V bit */ + opmode |= BIT(2); + + switch (cfg->v_cdwn_type) { + case CDM_CDWN_DISABLE: + /* CLEAR METHOD_V field */ + opmode &= ~(0x60); + /* CLEAR DWNS_V bit */ + opmode &= ~BIT(2); + break; + case CDM_CDWN_PIXEL_DROP: + /* Clear METHOD_V field (pixel drop is 0) */ + opmode &= ~(0x60); + break; + case CDM_CDWN_AVG: + /* Clear METHOD_V field (Average is 0x1) */ + opmode &= ~(0x60); + opmode |= (0x1 << 0x5); + break; + case CDM_CDWN_COSITE: + /* Clear METHOD_V field (Average is 0x2) */ + opmode &= ~(0x60); + opmode |= (0x2 << 0x5); + /* Co-site vertical coefficients */ + SDE_REG_WRITE(c, + CDM_CDWN2_COEFF_COSITE_V, + cosite_v_coeff[0]); + break; + case CDM_CDWN_OFFSITE: + /* Clear METHOD_V field (Average is 0x3) */ + opmode &= ~(0x60); + opmode |= (0x3 << 0x5); + + /* Off-site vertical coefficients */ + SDE_REG_WRITE(c, + CDM_CDWN2_COEFF_OFFSITE_V, + offsite_v_coeff[0]); + break; + default: + return -EINVAL; + } + + if (cfg->v_cdwn_type || cfg->h_cdwn_type) + opmode |= BIT(0); /* EN CDWN module */ + else + opmode &= ~BIT(0); + + out_size = (cfg->output_width & 0xFFFF) | + ((cfg->output_height & 0xFFFF) << 16); + SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); + SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); + SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, + ((0x3FF << 16) | 0x0)); + + return 0; +} + +int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, + struct sde_hw_cdm_cfg *cdm) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + const struct sde_format *fmt; + struct cdm_output_cfg cdm_cfg = { 0 }; + u32 opmode = 0; + u32 csc = 0; + + if (!ctx || !cdm) + return -EINVAL; + + fmt = cdm->output_fmt; + + if (!SDE_FORMAT_IS_YUV(fmt)) + return -EINVAL; + + if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { + if (fmt->chroma_sample != SDE_CHROMA_H1V2) + return -EINVAL; /*unsupported format */ + opmode = BIT(0); + opmode |= (fmt->chroma_sample << 1); + cdm_cfg.intf_en = true; + } else { + opmode = 0; + cdm_cfg.wb_en = true; + } + + csc |= BIT(2); + csc &= ~BIT(1); + csc |= BIT(0); + + if (ctx && ctx->ops.bind_pingpong_blk) + ctx->ops.bind_pingpong_blk(ctx, true, + cdm->pp_id); + else if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) + ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); + + SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); + SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); + return 0; +} + +void sde_hw_cdm_disable(struct sde_hw_cdm *ctx) +{ + struct cdm_output_cfg cdm_cfg = { 0 }; + + if (!ctx) + return; + + if (ctx && ctx->ops.bind_pingpong_blk) + ctx->ops.bind_pingpong_blk(ctx, false, 0); + else if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) + ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); +} + +static void sde_hw_cdm_bind_pingpong_blk( + struct sde_hw_cdm *ctx, + bool enable, + const enum sde_pingpong pp) +{ + struct sde_hw_blk_reg_map *c; + int mux_cfg = 0xF; + + if (!ctx || (enable && (pp < PINGPONG_0 || pp >= PINGPONG_MAX))) + return; + + c = &ctx->hw; + + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0x7; + + SDE_REG_WRITE(c, CDM_MUX, mux_cfg); +} + + +static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops, + unsigned long features) +{ + ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit; + ops->setup_cdwn = sde_hw_cdm_setup_cdwn; + ops->enable = sde_hw_cdm_enable; + ops->disable = sde_hw_cdm_disable; + if (features & BIT(SDE_CDM_INPUT_CTRL)) + ops->bind_pingpong_blk = sde_hw_cdm_bind_pingpong_blk; +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, + void __iomem *addr, + struct sde_mdss_cfg *m, + struct sde_hw_mdp *hw_mdp) +{ + struct sde_hw_cdm *c; + struct sde_cdm_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _cdm_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + _setup_cdm_ops(&c->ops, c->caps->features); + c->hw_mdp = hw_mdp; + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CDM, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + /* + * Perform any default initialization for the chroma down module + * @setup default csc coefficients + */ + sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg); + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm) +{ + if (cdm) + sde_hw_blk_destroy(&cdm->base); + kfree(cdm); +} diff --git a/techpack/display/msm/sde/sde_hw_cdm.h b/techpack/display/msm/sde/sde_hw_cdm.h new file mode 100644 index 0000000000000000000000000000000000000000..d49280baaa4c3e8f2f8224c4f580ea21ea04f768 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_cdm.h @@ -0,0 +1,145 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_CDM_H +#define _SDE_HW_CDM_H + +#include "sde_hw_mdss.h" +#include "sde_hw_top.h" +#include "sde_hw_blk.h" + +struct sde_hw_cdm; + +struct sde_hw_cdm_cfg { + u32 output_width; + u32 output_height; + u32 output_bit_depth; + u32 h_cdwn_type; + u32 v_cdwn_type; + const struct sde_format *output_fmt; + u32 output_type; + int flags; + int pp_id; +}; + +enum sde_hw_cdwn_type { + CDM_CDWN_DISABLE, + CDM_CDWN_PIXEL_DROP, + CDM_CDWN_AVG, + CDM_CDWN_COSITE, + CDM_CDWN_OFFSITE, +}; + +enum sde_hw_cdwn_output_type { + CDM_CDWN_OUTPUT_HDMI, + CDM_CDWN_OUTPUT_WB, +}; + +enum sde_hw_cdwn_output_bit_depth { + CDM_CDWN_OUTPUT_8BIT, + CDM_CDWN_OUTPUT_10BIT, +}; + +/** + * struct sde_hw_cdm_ops : Interface to the chroma down Hw driver functions + * Assumption is these functions will be called after + * clocks are enabled + * @setup_csc: Programs the csc matrix + * @setup_cdwn: Sets up the chroma down sub module + * @enable: Enables the output to interface and programs the + * output packer + * @disable: Puts the cdm in bypass mode + * @bind_pingpong_blk: enable/disable the connection with pingpong which + * will feed pixels to this cdm + */ +struct sde_hw_cdm_ops { + /** + * Programs the CSC matrix for conversion from RGB space to YUV space, + * it is optional to call this function as this matrix is automatically + * set during initialization, user should call this if it wants + * to program a different matrix than default matrix. + * @cdm: Pointer to the chroma down context structure + * @data Pointer to CSC configuration data + * return: 0 if success; error code otherwise + */ + int (*setup_csc_data)(struct sde_hw_cdm *cdm, + struct sde_csc_cfg *data); + + /** + * Programs the Chroma downsample part. + * @cdm Pointer to chroma down context + */ + int (*setup_cdwn)(struct sde_hw_cdm *cdm, + struct sde_hw_cdm_cfg *cfg); + + /** + * Enable the CDM module + * @cdm Pointer to chroma down context + */ + int (*enable)(struct sde_hw_cdm *cdm, + struct sde_hw_cdm_cfg *cfg); + + /** + * Disable the CDM module + * @cdm Pointer to chroma down context + */ + void (*disable)(struct sde_hw_cdm *cdm); + + /** + * Enable/disable the connection with pingpong + * @cdm Pointer to chroma down context + * @enable Enable/disable control + * @pp pingpong block id. + */ + void (*bind_pingpong_blk)(struct sde_hw_cdm *cdm, + bool enable, + const enum sde_pingpong pp); +}; + +struct sde_hw_cdm { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* chroma down */ + const struct sde_cdm_cfg *caps; + enum sde_cdm idx; + + /* mdp top hw driver */ + struct sde_hw_mdp *hw_mdp; + + /* ops */ + struct sde_hw_cdm_ops ops; +}; + +/** + * sde_hw_cdm - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_cdm *to_sde_hw_cdm(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_cdm, base); +} + +/** + * sde_hw_cdm_init - initializes the cdm hw driver object. + * should be called once before accessing every cdm. + * @idx: cdm index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + * @hw_mdp: pointer to mdp top hw driver object + */ +struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, + void __iomem *addr, + struct sde_mdss_cfg *m, + struct sde_hw_mdp *hw_mdp); + +/** + * sde_hw_cdm_destroy - destroys CDM driver context + * @cdm: pointer to CDM driver context + */ +void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm); + +#endif /*_SDE_HW_CDM_H */ diff --git a/techpack/display/msm/sde/sde_hw_color_proc_common_v4.h b/techpack/display/msm/sde/sde_hw_color_proc_common_v4.h new file mode 100644 index 0000000000000000000000000000000000000000..104aaf521b695911fe5a369bcf0b4d152358694e --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_color_proc_common_v4.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _SDE_HW_COLOR_PROC_COMMON_V4_H_ +#define _SDE_HW_COLOR_PROC_COMMON_V4_H_ + +#include "sde_hw_mdss.h" + +#define GAMUT_TABLE_SEL_OFF 0x4 +#define GAMUT_UPPER_COLOR_OFF 0x8 +#define GAMUT_LOWER_COLOR_OFF 0xc +#define GAMUT_SCALEA_OFFSET_OFF 0x10 +#define GAMUT_SCALEB_OFFSET_OFF 0xe0 +#define GAMUT_TABLE0_SEL BIT(12) +#define GAMUT_MAP_EN BIT(1) +#define GAMUT_EN BIT(0) +#define GAMUT_MODE_13B_OFF 640 +#define GAMUT_MODE_5_OFF 1248 + +enum { + gamut_mode_17 = 0, + gamut_mode_5, + gamut_mode_13a, + gamut_mode_13b, + gamut_mode_17b, +}; + +#define GC_C0_OFF 0x4 +#define GC_C0_INDEX_OFF 0x8 +#define GC_8B_ROUND_EN BIT(1) +#define GC_EN BIT(0) +#define GC_TBL_NUM 3 +#define GC_LUT_SWAP_OFF 0x1c + +#define IGC_TBL_NUM 3 +#define IGC_DITHER_OFF 0x7e0 +#define IGC_OPMODE_OFF 0x0 +#define IGC_C0_OFF 0x0 +#define IGC_DATA_MASK (BIT(12) - 1) +#define IGC_DSPP_SEL_MASK_MAX (BIT(4) - 1) +#define IGC_DSPP_SEL_MASK(n) \ + ((IGC_DSPP_SEL_MASK_MAX & ~(1 << (n))) << 28) +#define IGC_INDEX_UPDATE BIT(25) +#define IGC_EN BIT(0) +#define IGC_DIS 0 +#define IGC_DITHER_DATA_MASK (BIT(4) - 1) + +#define PCC_NUM_PLANES 3 +#define PCC_NUM_COEFF 11 +#define PCC_EN BIT(0) +#define PCC_DIS 0 +#define PCC_C_OFF 0x4 +#define PCC_R_OFF 0x10 +#define PCC_G_OFF 0x1c +#define PCC_B_OFF 0x28 +#define PCC_RG_OFF 0x34 +#define PCC_RB_OFF 0x40 +#define PCC_GB_OFF 0x4c +#define PCC_RGB_OFF 0x58 +#define PCC_RR_OFF 0x64 +#define PCC_GG_OFF 0x70 +#define PCC_BB_OFF 0x7c + +#define PA_EN BIT(20) +#define PA_HUE_EN BIT(25) +#define PA_SAT_EN BIT(26) +#define PA_VAL_EN BIT(27) +#define PA_CONT_EN BIT(28) + +#define PA_SIXZONE_HUE_EN BIT(29) +#define PA_SIXZONE_SAT_EN BIT(30) +#define PA_SIXZONE_VAL_EN BIT(31) + +#define PA_HIST_EN BIT(16) + +#define PA_SKIN_EN BIT(5) +#define PA_FOL_EN BIT(6) +#define PA_SKY_EN BIT(7) + +#define PA_HUE_MASK (BIT(12) - 1) +#define PA_SAT_MASK (BIT(16) - 1) +#define PA_VAL_MASK (BIT(8) - 1) +#define PA_CONT_MASK (BIT(8) - 1) + +#define PA_HUE_OFF 0x1c +#define PA_SAT_OFF 0x20 +#define PA_VAL_OFF 0x24 +#define PA_CONT_OFF 0x28 +#define PA_PWL_HOLD_OFF 0x40 + +#define PA_DISABLE_REQUIRED(x) \ + !((x) & (PA_SKIN_EN | PA_SKY_EN | \ + PA_FOL_EN | PA_HUE_EN | \ + PA_SAT_EN | PA_VAL_EN | \ + PA_CONT_EN | PA_HIST_EN | \ + PA_SIXZONE_HUE_EN | PA_SIXZONE_SAT_EN | \ + PA_SIXZONE_VAL_EN)) + +#define SIXZONE_ADJ_CURVE_P1_OFF 0x4 +#define SIXZONE_THRESHOLDS_OFF 0x8 + +#define MEMCOL_SIZE0 20 +#define MEMCOL_SIZE1 8 +#define MEMCOL_PWL0_OFF 0x0 +#define MEMCOL_PWL2_OFF 0x3C +#define MEMCOL_HOLD_SIZE 0x4 + +#define MEMCOL_PROT_VAL_EN BIT(24) +#define MEMCOL_PROT_SAT_EN BIT(23) +#define MEMCOL_PROT_HUE_EN BIT(22) +#define MEMCOL_PROT_CONT_EN BIT(18) +#define MEMCOL_PROT_SIXZONE_EN BIT(17) +#define MEMCOL_PROT_BLEND_EN BIT(3) + +#define MEMCOL_PROT_MASK \ + (MEMCOL_PROT_VAL_EN | MEMCOL_PROT_SAT_EN | \ + MEMCOL_PROT_HUE_EN | MEMCOL_PROT_CONT_EN | \ + MEMCOL_PROT_SIXZONE_EN | MEMCOL_PROT_BLEND_EN) + +#define SSPP 0 +#define DSPP 1 + +struct sde_ltm_phase_info { + u32 init_h[LTM_MAX]; + u32 init_v; + u32 inc_h; + u32 inc_v; + bool portrait_en; + bool merge_en; +}; + +static inline void sde_ltm_get_phase_info(struct sde_hw_cp_cfg *hw_cfg, + struct sde_ltm_phase_info *info) +{ + u32 count_v, count_h, num_mixers; + + if (hw_cfg->displayh < hw_cfg->displayv) { + count_h = 4; + count_v = 8; + info->portrait_en = true; + } else { + count_h = 8; + count_v = 4; + info->portrait_en = false; + } + + num_mixers = hw_cfg->num_of_mixers; + if (num_mixers == 1) + info->merge_en = false; + else + info->merge_en = true; + + info->init_h[LTM_0] = (1 << 23); + info->init_h[LTM_1] = (1 << 23); + info->init_v = (1 << 23); + info->inc_h = ((count_h - 1) << 24) / (hw_cfg->displayh - 1); + info->inc_v = ((count_v - 1) << 24) / (hw_cfg->displayv - 1); + if (info->merge_en) + info->init_h[LTM_1] = info->init_h[LTM_0] + + info->inc_h * (hw_cfg->displayh / 2); +} + +#endif /* _SDE_HW_COLOR_PROC_COMMON_V4_H_ */ diff --git a/techpack/display/msm/sde/sde_hw_color_proc_v4.c b/techpack/display/msm/sde/sde_hw_color_proc_v4.c new file mode 100644 index 0000000000000000000000000000000000000000..f266683a96ea2a03eb2eed6e75a7008dbc011968 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_color_proc_v4.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#include <drm/msm_drm_pp.h> +#include "sde_hw_color_proc_common_v4.h" +#include "sde_hw_color_proc_v4.h" + +static int sde_write_3d_gamut(struct sde_hw_blk_reg_map *hw, + struct drm_msm_3d_gamut *payload, u32 base, + u32 *opcode, u32 pipe, u32 scale_tbl_a_len, + u32 scale_tbl_b_len) +{ + u32 reg, tbl_len, tbl_off, scale_off, i, j; + u32 scale_tbl_len, scale_tbl_off; + u32 *scale_data; + + if (!payload || !opcode || !hw) { + DRM_ERROR("invalid payload %pK opcode %pK hw %pK\n", + payload, opcode, hw); + return -EINVAL; + } + + switch (payload->mode) { + case GAMUT_3D_MODE_17: + tbl_len = GAMUT_3D_MODE17_TBL_SZ; + tbl_off = 0; + if (pipe == DSPP) { + scale_off = GAMUT_SCALEA_OFFSET_OFF; + *opcode = gamut_mode_17; + } else { + *opcode = (*opcode & (BIT(5) - 1)) >> 2; + if (*opcode == gamut_mode_17b) + *opcode = gamut_mode_17; + else + *opcode = gamut_mode_17b; + scale_off = (*opcode == gamut_mode_17) ? + GAMUT_SCALEA_OFFSET_OFF : + GAMUT_SCALEB_OFFSET_OFF; + } + break; + case GAMUT_3D_MODE_13: + *opcode = (*opcode & (BIT(4) - 1)) >> 2; + if (*opcode == gamut_mode_13a) + *opcode = gamut_mode_13b; + else + *opcode = gamut_mode_13a; + tbl_len = GAMUT_3D_MODE13_TBL_SZ; + tbl_off = (*opcode == gamut_mode_13a) ? 0 : + GAMUT_MODE_13B_OFF; + scale_off = (*opcode == gamut_mode_13a) ? + GAMUT_SCALEA_OFFSET_OFF : GAMUT_SCALEB_OFFSET_OFF; + *opcode <<= 2; + break; + case GAMUT_3D_MODE_5: + *opcode = gamut_mode_5 << 2; + tbl_len = GAMUT_3D_MODE5_TBL_SZ; + tbl_off = GAMUT_MODE_5_OFF; + scale_off = GAMUT_SCALEB_OFFSET_OFF; + break; + default: + DRM_ERROR("invalid mode %d\n", payload->mode); + return -EINVAL; + } + + if (payload->flags & GAMUT_3D_MAP_EN) + *opcode |= GAMUT_MAP_EN; + *opcode |= GAMUT_EN; + + for (i = 0; i < GAMUT_3D_TBL_NUM; i++) { + reg = GAMUT_TABLE0_SEL << i; + reg |= ((tbl_off) & (BIT(11) - 1)); + SDE_REG_WRITE(hw, base + GAMUT_TABLE_SEL_OFF, reg); + for (j = 0; j < tbl_len; j++) { + SDE_REG_WRITE(hw, base + GAMUT_LOWER_COLOR_OFF, + payload->col[i][j].c2_c1); + SDE_REG_WRITE(hw, base + GAMUT_UPPER_COLOR_OFF, + payload->col[i][j].c0); + } + } + + if ((*opcode & GAMUT_MAP_EN)) { + if (scale_off == GAMUT_SCALEA_OFFSET_OFF) + scale_tbl_len = scale_tbl_a_len; + else + scale_tbl_len = scale_tbl_b_len; + for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) { + scale_tbl_off = base + scale_off + + i * scale_tbl_len * sizeof(u32); + scale_data = &payload->scale_off[i][0]; + for (j = 0; j < scale_tbl_len; j++) + SDE_REG_WRITE(hw, + scale_tbl_off + (j * sizeof(u32)), + scale_data[j]); + } + } + SDE_REG_WRITE(hw, base, *opcode); + return 0; +} + +void sde_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_3d_gamut *payload; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 op_mode; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + op_mode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->gamut.base); + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable gamut feature\n"); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gamut.base, 0); + return; + } + + payload = hw_cfg->payload; + sde_write_3d_gamut(&ctx->hw, payload, ctx->cap->sblk->gamut.base, + &op_mode, DSPP, GAMUT_3D_SCALE_OFF_SZ, GAMUT_3D_SCALEB_OFF_SZ); + +} + +void sde_setup_dspp_3d_gamutv41(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_3d_gamut *payload; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 op_mode; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + op_mode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->gamut.base); + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable gamut feature\n"); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gamut.base, 0); + return; + } + + payload = hw_cfg->payload; + sde_write_3d_gamut(&ctx->hw, payload, ctx->cap->sblk->gamut.base, + &op_mode, DSPP, GAMUT_3D_SCALE_OFF_SZ, GAMUT_3D_SCALE_OFF_SZ); +} + +void sde_setup_dspp_igcv3(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_igc_lut *lut_cfg; + struct sde_hw_cp_cfg *hw_cfg = cfg; + int i = 0, j = 0; + u32 *addr[IGC_TBL_NUM]; + u32 offset = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable igc feature\n"); + SDE_REG_WRITE(&ctx->hw, IGC_OPMODE_OFF, 0); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_igc_lut)); + return; + } + + lut_cfg = hw_cfg->payload; + + addr[0] = lut_cfg->c0; + addr[1] = lut_cfg->c1; + addr[2] = lut_cfg->c2; + + for (i = 0; i < IGC_TBL_NUM; i++) { + offset = IGC_C0_OFF + (i * sizeof(u32)); + + for (j = 0; j < IGC_TBL_LEN; j++) { + addr[i][j] &= IGC_DATA_MASK; + addr[i][j] |= IGC_DSPP_SEL_MASK(ctx->idx - 1); + if (j == 0) + addr[i][j] |= IGC_INDEX_UPDATE; + /* IGC lut registers are part of DSPP Top HW block */ + SDE_REG_WRITE(&ctx->hw_top, offset, addr[i][j]); + } + } + + if (lut_cfg->flags & IGC_DITHER_ENABLE) { + SDE_REG_WRITE(&ctx->hw, IGC_DITHER_OFF, + lut_cfg->strength & IGC_DITHER_DATA_MASK); + } + + SDE_REG_WRITE(&ctx->hw, IGC_OPMODE_OFF, IGC_EN); +} + +void sde_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_pcc *pcc_cfg; + struct drm_msm_pcc_coeff *coeffs = NULL; + int i = 0; + u32 base = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable pcc feature\n"); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, 0); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_pcc)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pcc)); + return; + } + + pcc_cfg = hw_cfg->payload; + + for (i = 0; i < PCC_NUM_PLANES; i++) { + base = ctx->cap->sblk->pcc.base + (i * sizeof(u32)); + switch (i) { + case 0: + coeffs = &pcc_cfg->r; + SDE_REG_WRITE(&ctx->hw, + base + PCC_RR_OFF, pcc_cfg->r_rr); + SDE_REG_WRITE(&ctx->hw, + base + PCC_GG_OFF, pcc_cfg->r_gg); + SDE_REG_WRITE(&ctx->hw, + base + PCC_BB_OFF, pcc_cfg->r_bb); + break; + case 1: + coeffs = &pcc_cfg->g; + SDE_REG_WRITE(&ctx->hw, + base + PCC_RR_OFF, pcc_cfg->g_rr); + SDE_REG_WRITE(&ctx->hw, + base + PCC_GG_OFF, pcc_cfg->g_gg); + SDE_REG_WRITE(&ctx->hw, + base + PCC_BB_OFF, pcc_cfg->g_bb); + break; + case 2: + coeffs = &pcc_cfg->b; + SDE_REG_WRITE(&ctx->hw, + base + PCC_RR_OFF, pcc_cfg->b_rr); + SDE_REG_WRITE(&ctx->hw, + base + PCC_GG_OFF, pcc_cfg->b_gg); + SDE_REG_WRITE(&ctx->hw, + base + PCC_BB_OFF, pcc_cfg->b_bb); + break; + default: + DRM_ERROR("invalid pcc plane: %d\n", i); + return; + } + + SDE_REG_WRITE(&ctx->hw, base + PCC_C_OFF, coeffs->c); + SDE_REG_WRITE(&ctx->hw, base + PCC_R_OFF, coeffs->r); + SDE_REG_WRITE(&ctx->hw, base + PCC_G_OFF, coeffs->g); + SDE_REG_WRITE(&ctx->hw, base + PCC_B_OFF, coeffs->b); + SDE_REG_WRITE(&ctx->hw, base + PCC_RG_OFF, coeffs->rg); + SDE_REG_WRITE(&ctx->hw, base + PCC_RB_OFF, coeffs->rb); + SDE_REG_WRITE(&ctx->hw, base + PCC_GB_OFF, coeffs->gb); + SDE_REG_WRITE(&ctx->hw, base + PCC_RGB_OFF, coeffs->rgb); + } + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, PCC_EN); +} + +void sde_setup_dspp_ltm_threshv1(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + u64 thresh = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid parameters ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + if (!hw_cfg->payload) { + DRM_ERROR("invalid payload parameters for ltm thresh param\n"); + return; + } + + thresh = *((u64 *)hw_cfg->payload); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x60, + (thresh & 0x3FF)); +} + +void sde_setup_dspp_ltm_hist_bufferv1(struct sde_hw_dspp *ctx, u64 addr) +{ + struct drm_msm_ltm_stats_data *hist = NULL; + u64 lh_addr, hs_addr; + + if (!ctx || !addr) { + DRM_ERROR("invalid parameter ctx %pK addr 0x%llx\n", ctx, addr); + return; + } + + hist = (struct drm_msm_ltm_stats_data *)addr; + lh_addr = (u64)(&hist->stats_02[0]); + hs_addr = (u64)(&hist->stats_03[0]); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x70, + (addr & 0xFFFFFF00)); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x74, + (lh_addr & 0xFFFFFF00)); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x78, + (hs_addr & 0xFFFFFF00)); +} + +void sde_setup_dspp_ltm_hist_ctrlv1(struct sde_hw_dspp *ctx, void *cfg, + bool enable, u64 addr) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_ltm_phase_info phase; + u32 op_mode, offset; + + if (!ctx) { + DRM_ERROR("invalid parameters ctx %pK\n", ctx); + return; + } + + if (enable && (!addr || !cfg)) { + DRM_ERROR("invalid addr 0x%llx cfg %pK\n", addr, cfg); + return; + } + + offset = ctx->cap->sblk->ltm.base + 0x4; + op_mode = SDE_REG_READ(&ctx->hw, offset); + + if (!enable) { + op_mode &= ~BIT(0); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x4, + (op_mode & 0x1FFFFFF)); + return; + } + + if (ctx->idx >= DSPP_MAX) { + DRM_ERROR("Invalid idx %d\n", ctx->idx); + return; + } + + memset(&phase, 0, sizeof(phase)); + sde_ltm_get_phase_info(hw_cfg, &phase); + + if (phase.portrait_en) + op_mode |= BIT(2); + else + op_mode &= ~BIT(2); + + if (phase.merge_en) + op_mode |= BIT(16); + else + op_mode &= ~(BIT(16) | BIT(17)); + + offset = ctx->cap->sblk->ltm.base + 0x8; + SDE_REG_WRITE(&ctx->hw, offset, (phase.init_h[ctx->idx] & 0x7FFFFFF)); + offset += 4; + SDE_REG_WRITE(&ctx->hw, offset, (phase.init_v & 0xFFFFFF)); + offset += 4; + SDE_REG_WRITE(&ctx->hw, offset, (phase.inc_h & 0xFFFFFF)); + offset += 4; + SDE_REG_WRITE(&ctx->hw, offset, (phase.inc_v & 0xFFFFFF)); + + op_mode |= BIT(0); + sde_setup_dspp_ltm_hist_bufferv1(ctx, addr); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x4, + (op_mode & 0x1FFFFFF)); +} + +void sde_ltm_read_intr_status(struct sde_hw_dspp *ctx, u32 *status) +{ + u32 clear; + + if (!ctx || !status) { + DRM_ERROR("invalid parameters ctx %pK status %pK\n", ctx, + status); + return; + } + + *status = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->ltm.base + 0x54); + pr_debug("%s(): LTM interrupt status 0x%x\n", __func__, *status); + /* clear the hist_sat and hist_merge_sat bits */ + clear = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->ltm.base + 0x58); + clear |= BIT(1) | BIT(2); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->ltm.base + 0x58, clear); +} diff --git a/techpack/display/msm/sde/sde_hw_color_proc_v4.h b/techpack/display/msm/sde/sde_hw_color_proc_v4.h new file mode 100644 index 0000000000000000000000000000000000000000..3df8f8bc6b9fbe881838d7663dc3b0735ee1fc20 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_color_proc_v4.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _SDE_HW_COLOR_PROC_V4_H_ +#define _SDE_HW_COLOR_PROC_V4_H_ + +#include "sde_hw_util.h" +#include "sde_hw_catalog.h" +#include "sde_hw_dspp.h" +/** + * sde_setup_dspp_3d_gamutv4 - Function for 3d gamut v4 version feature + * programming. + * @ctx: dspp ctx pointer + * @cfg: pointer to sde_hw_cp_cfg + */ +void sde_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_3d_gamutv41 - Function for 3d gamut v4_1 version feature + * programming. + * @ctx: dspp ctx pointer + * @cfg: pointer to sde_hw_cp_cfg + */ +void sde_setup_dspp_3d_gamutv41(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_igcv3 - Function for igc v3 version feature + * programming. + * @ctx: dspp ctx pointer + * @cfg: pointer to sde_hw_cp_cfg + */ +void sde_setup_dspp_igcv3(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_pccv4 - Function for pcc v4 version feature + * programming. + * @ctx: dspp ctx pointer + * @cfg: pointer to sde_hw_cp_cfg + */ +void sde_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_ltm_threshv1 - Function for ltm thresh v1 programming. + * @ctx: dspp ctx pointer + * @cfg: pointer to sde_hw_cp_cfg + */ +void sde_setup_dspp_ltm_threshv1(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_ltm_hist_ctrlv1 - Function for ltm hist_ctrl v1 programming. + * @ctx: dspp ctx pointer + * @cfg: pointer to sde_hw_cp_cfg + * @enable: feature enable/disable value + * @addr: aligned iova address + */ +void sde_setup_dspp_ltm_hist_ctrlv1(struct sde_hw_dspp *ctx, void *cfg, + bool enable, u64 addr); +/** + * sde_setup_dspp_ltm_hist_bufferv1 - Function for setting ltm hist buffer v1. + * @ctx: dspp ctx pointer + * @addr: aligned iova address + */ +void sde_setup_dspp_ltm_hist_bufferv1(struct sde_hw_dspp *ctx, u64 addr); + +/** + * sde_ltm_read_intr_status - api to get ltm interrupt status + * @dspp: pointer to dspp object + * @status: Pointer to u32 where ltm status value is dumped. + */ +void sde_ltm_read_intr_status(struct sde_hw_dspp *dspp, u32 *status); + +#endif /* _SDE_HW_COLOR_PROC_V4_H_ */ diff --git a/techpack/display/msm/sde/sde_hw_color_processing.h b/techpack/display/msm/sde/sde_hw_color_processing.h new file mode 100644 index 0000000000000000000000000000000000000000..47f405d36eb0421fd4989a9b3d0dcec822b46304 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_color_processing.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_COLOR_PROCESSING_H +#define _SDE_HW_COLOR_PROCESSING_H + +#include "sde_hw_color_processing_v1_7.h" +#include "sde_hw_reg_dma_v1_color_proc.h" +#include "sde_hw_color_proc_v4.h" + +#endif diff --git a/techpack/display/msm/sde/sde_hw_color_processing_v1_7.c b/techpack/display/msm/sde/sde_hw_color_processing_v1_7.c new file mode 100644 index 0000000000000000000000000000000000000000..e7920320fab2df25d0cc385c32ea89a28fcd5b5f --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_color_processing_v1_7.c @@ -0,0 +1,1007 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <drm/msm_drm_pp.h> +#include "sde_hw_color_processing_v1_7.h" +#include "sde_hw_ctl.h" + +#define REG_MASK_SHIFT(n, shift) ((REG_MASK(n)) << (shift)) + +#define PA_HUE_VIG_OFF 0x110 +#define PA_SAT_VIG_OFF 0x114 +#define PA_VAL_VIG_OFF 0x118 +#define PA_CONT_VIG_OFF 0x11C + +#define PA_HUE_DSPP_OFF 0x1c +#define PA_SAT_DSPP_OFF 0x20 +#define PA_VAL_DSPP_OFF 0x24 +#define PA_CONT_DSPP_OFF 0x28 + +#define PA_HIST_CTRL_DSPP_OFF 0x4 +#define PA_HIST_DATA_DSPP_OFF 0x400 + +#define PA_LUTV_DSPP_OFF 0x1400 +#define PA_LUT_SWAP_OFF 0x234 + +#define PA_LUTV_DSPP_CTRL_OFF 0x4c +#define PA_LUTV_DSPP_SWAP_OFF 0x18 + +#define PA_DITH_DSPP_MATRIX_OFF 0x4 + +#define PA_HUE_MASK 0xFFF +#define PA_SAT_MASK 0xFFFF +#define PA_VAL_MASK 0xFF +#define PA_CONT_MASK 0xFF + +#define MEMCOL_PWL0_OFF 0x88 +#define MEMCOL_PWL0_MASK 0xFFFF07FF +#define MEMCOL_PWL1_OFF 0x8C +#define MEMCOL_PWL1_MASK 0xFFFFFFFF +#define MEMCOL_HUE_REGION_OFF 0x90 +#define MEMCOL_HUE_REGION_MASK 0x7FF07FF +#define MEMCOL_SAT_REGION_OFF 0x94 +#define MEMCOL_SAT_REGION_MASK 0xFFFFFF +#define MEMCOL_VAL_REGION_OFF 0x98 +#define MEMCOL_VAL_REGION_MASK 0xFFFFFF +#define MEMCOL_P0_LEN 0x14 +#define MEMCOL_P1_LEN 0x8 +#define MEMCOL_PWL2_OFF 0x218 +#define MEMCOL_PWL2_MASK 0xFFFFFFFF +#define MEMCOL_BLEND_GAIN_OFF 0x21C +#define MEMCOL_PWL_HOLD_OFF 0x214 + +#define VIG_OP_PA_EN BIT(4) +#define VIG_OP_PA_SKIN_EN BIT(5) +#define VIG_OP_PA_FOL_EN BIT(6) +#define VIG_OP_PA_SKY_EN BIT(7) +#define VIG_OP_PA_HUE_EN BIT(25) +#define VIG_OP_PA_SAT_EN BIT(26) +#define VIG_OP_PA_VAL_EN BIT(27) +#define VIG_OP_PA_CONT_EN BIT(28) + +#define DSPP_OP_SZ_VAL_EN BIT(31) +#define DSPP_OP_SZ_SAT_EN BIT(30) +#define DSPP_OP_SZ_HUE_EN BIT(29) +#define DSPP_OP_PA_HUE_EN BIT(25) +#define DSPP_OP_PA_SAT_EN BIT(26) +#define DSPP_OP_PA_VAL_EN BIT(27) +#define DSPP_OP_PA_CONT_EN BIT(28) +#define DSPP_OP_PA_EN BIT(20) +#define DSPP_OP_PA_LUTV_EN BIT(19) +#define DSPP_OP_PA_HIST_EN BIT(16) +#define DSPP_OP_PA_SKIN_EN BIT(5) +#define DSPP_OP_PA_FOL_EN BIT(6) +#define DSPP_OP_PA_SKY_EN BIT(7) + +#define DSPP_SZ_ADJ_CURVE_P1_OFF 0x4 +#define DSPP_SZ_THRESHOLDS_OFF 0x8 +#define DSPP_PA_PWL_HOLD_OFF 0x40 + +#define DSPP_MEMCOL_SIZE0 0x14 +#define DSPP_MEMCOL_SIZE1 0x8 +#define DSPP_MEMCOL_PWL0_OFF 0x0 +#define DSPP_MEMCOL_PWL2_OFF 0x3C +#define DSPP_MEMCOL_HOLD_SIZE 0x4 + +#define DSPP_MEMCOL_PROT_VAL_EN BIT(24) +#define DSPP_MEMCOL_PROT_SAT_EN BIT(23) +#define DSPP_MEMCOL_PROT_HUE_EN BIT(22) +#define DSPP_MEMCOL_PROT_CONT_EN BIT(18) +#define DSPP_MEMCOL_PROT_SIXZONE_EN BIT(17) +#define DSPP_MEMCOL_PROT_BLEND_EN BIT(3) + +#define DSPP_MEMCOL_MASK \ + (DSPP_OP_PA_SKIN_EN | DSPP_OP_PA_SKY_EN | DSPP_OP_PA_FOL_EN) + +#define DSPP_MEMCOL_PROT_MASK \ + (DSPP_MEMCOL_PROT_HUE_EN | DSPP_MEMCOL_PROT_SAT_EN | \ + DSPP_MEMCOL_PROT_VAL_EN | DSPP_MEMCOL_PROT_CONT_EN | \ + DSPP_MEMCOL_PROT_SIXZONE_EN | DSPP_MEMCOL_PROT_BLEND_EN) + +#define PA_VIG_DISABLE_REQUIRED(x) \ + !((x) & (VIG_OP_PA_SKIN_EN | VIG_OP_PA_SKY_EN | \ + VIG_OP_PA_FOL_EN | VIG_OP_PA_HUE_EN | \ + VIG_OP_PA_SAT_EN | VIG_OP_PA_VAL_EN | \ + VIG_OP_PA_CONT_EN)) + +#define PA_DSPP_DISABLE_REQUIRED(x) \ + !((x) & (DSPP_OP_PA_SKIN_EN | DSPP_OP_PA_SKY_EN | \ + DSPP_OP_PA_FOL_EN | DSPP_OP_PA_HUE_EN | \ + DSPP_OP_PA_SAT_EN | DSPP_OP_PA_VAL_EN | \ + DSPP_OP_PA_CONT_EN | DSPP_OP_PA_HIST_EN | \ + DSPP_OP_SZ_HUE_EN | DSPP_OP_SZ_SAT_EN | \ + DSPP_OP_SZ_VAL_EN)) + +#define DSPP_OP_PCC_ENABLE BIT(0) +#define PCC_OP_MODE_OFF 0 +#define PCC_CONST_COEFF_OFF 4 +#define PCC_R_COEFF_OFF 0x10 +#define PCC_G_COEFF_OFF 0x1C +#define PCC_B_COEFF_OFF 0x28 +#define PCC_RG_COEFF_OFF 0x34 +#define PCC_RB_COEFF_OFF 0x40 +#define PCC_GB_COEFF_OFF 0x4C +#define PCC_RGB_COEFF_OFF 0x58 +#define PCC_CONST_COEFF_MASK 0xFFFF +#define PCC_COEFF_MASK 0x3FFFF + +#define SSPP 0 +#define DSPP 1 + +#define PGC_C0_OFF 0x4 +#define PGC_C0_INDEX_OFF 0x8 +#define PGC_8B_ROUND_EN BIT(1) +#define PGC_EN BIT(0) +#define PGC_TBL_NUM 3 +#define PGC_LUT_SWAP_OFF 0x1c + + +static void __setup_pa_hue(struct sde_hw_blk_reg_map *hw, + const struct sde_pp_blk *blk, u32 hue, int loc) +{ + u32 base = blk->base; + u32 offset = (loc == DSPP) ? PA_HUE_DSPP_OFF : PA_HUE_VIG_OFF; + u32 op_hue_en = (loc == DSPP) ? DSPP_OP_PA_HUE_EN : VIG_OP_PA_HUE_EN; + u32 op_pa_en = (loc == DSPP) ? DSPP_OP_PA_EN : VIG_OP_PA_EN; + u32 disable_req; + u32 opmode; + + opmode = SDE_REG_READ(hw, base); + SDE_REG_WRITE(hw, base + offset, hue & PA_HUE_MASK); + + if (!hue) { + opmode &= ~op_hue_en; + disable_req = (loc == DSPP) ? + PA_DSPP_DISABLE_REQUIRED(opmode) : + PA_VIG_DISABLE_REQUIRED(opmode); + if (disable_req) + opmode &= ~op_pa_en; + } else { + opmode |= (op_hue_en | op_pa_en); + } + + SDE_REG_WRITE(hw, base, opmode); +} + +void sde_setup_pipe_pa_hue_v1_7(struct sde_hw_pipe *ctx, void *cfg) +{ + uint32_t hue = *((uint32_t *)cfg); + + __setup_pa_hue(&ctx->hw, &ctx->cap->sblk->hsic_blk, hue, SSPP); +} + +static void __setup_pa_sat(struct sde_hw_blk_reg_map *hw, + const struct sde_pp_blk *blk, u32 sat, int loc) +{ + u32 base = blk->base; + u32 offset = (loc == DSPP) ? PA_SAT_DSPP_OFF : PA_SAT_VIG_OFF; + u32 op_sat_en = (loc == DSPP) ? DSPP_OP_PA_SAT_EN : VIG_OP_PA_SAT_EN; + u32 op_pa_en = (loc == DSPP) ? DSPP_OP_PA_EN : VIG_OP_PA_EN; + u32 disable_req; + u32 opmode; + + opmode = SDE_REG_READ(hw, base); + SDE_REG_WRITE(hw, base + offset, sat & PA_SAT_MASK); + + if (!sat) { + opmode &= ~op_sat_en; + disable_req = (loc == DSPP) ? + PA_DSPP_DISABLE_REQUIRED(opmode) : + PA_VIG_DISABLE_REQUIRED(opmode); + if (disable_req) + opmode &= ~op_pa_en; + } else { + opmode |= (op_sat_en | op_pa_en); + } + + SDE_REG_WRITE(hw, base, opmode); +} + +void sde_setup_pipe_pa_sat_v1_7(struct sde_hw_pipe *ctx, void *cfg) +{ + uint32_t sat = *((uint32_t *)cfg); + + __setup_pa_sat(&ctx->hw, &ctx->cap->sblk->hsic_blk, sat, SSPP); +} + +static void __setup_pa_val(struct sde_hw_blk_reg_map *hw, + const struct sde_pp_blk *blk, u32 value, int loc) +{ + u32 base = blk->base; + u32 offset = (loc == DSPP) ? PA_VAL_DSPP_OFF : PA_VAL_VIG_OFF; + u32 op_val_en = (loc == DSPP) ? DSPP_OP_PA_VAL_EN : VIG_OP_PA_VAL_EN; + u32 op_pa_en = (loc == DSPP) ? DSPP_OP_PA_EN : VIG_OP_PA_EN; + u32 disable_req; + u32 opmode; + + opmode = SDE_REG_READ(hw, base); + SDE_REG_WRITE(hw, base + offset, value & PA_VAL_MASK); + + if (!value) { + opmode &= ~op_val_en; + disable_req = (loc == DSPP) ? + PA_DSPP_DISABLE_REQUIRED(opmode) : + PA_VIG_DISABLE_REQUIRED(opmode); + if (disable_req) + opmode &= ~op_pa_en; + } else { + opmode |= (op_val_en | op_pa_en); + } + + SDE_REG_WRITE(hw, base, opmode); +} + +void sde_setup_pipe_pa_val_v1_7(struct sde_hw_pipe *ctx, void *cfg) +{ + uint32_t value = *((uint32_t *)cfg); + + __setup_pa_val(&ctx->hw, &ctx->cap->sblk->hsic_blk, value, SSPP); +} + +static void __setup_pa_cont(struct sde_hw_blk_reg_map *hw, + const struct sde_pp_blk *blk, u32 contrast, int loc) +{ + u32 base = blk->base; + u32 offset = (loc == DSPP) ? PA_CONT_DSPP_OFF : PA_CONT_VIG_OFF; + u32 op_cont_en = (loc == DSPP) ? + DSPP_OP_PA_CONT_EN : VIG_OP_PA_CONT_EN; + u32 op_pa_en = (loc == DSPP) ? DSPP_OP_PA_EN : VIG_OP_PA_EN; + u32 disable_req; + u32 opmode; + + opmode = SDE_REG_READ(hw, base); + SDE_REG_WRITE(hw, base + offset, contrast & PA_CONT_MASK); + + if (!contrast) { + opmode &= ~op_cont_en; + disable_req = (loc == DSPP) ? + PA_DSPP_DISABLE_REQUIRED(opmode) : + PA_VIG_DISABLE_REQUIRED(opmode); + if (disable_req) + opmode &= ~op_pa_en; + } else { + opmode |= (op_cont_en | op_pa_en); + } + + SDE_REG_WRITE(hw, base, opmode); +} + +void sde_setup_pipe_pa_cont_v1_7(struct sde_hw_pipe *ctx, void *cfg) +{ + uint32_t contrast = *((uint32_t *)cfg); + + __setup_pa_cont(&ctx->hw, &ctx->cap->sblk->hsic_blk, contrast, SSPP); +} + +void sde_setup_dspp_pa_hsic_v17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_pa_hsic *hsic_cfg; + u32 hue = 0; + u32 sat = 0; + u32 val = 0; + u32 cont = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + if (hw_cfg->payload && + (hw_cfg->len != sizeof(struct drm_msm_pa_hsic))) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pa_hsic)); + return; + } + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable pa hsic feature\n"); + } else { + hsic_cfg = hw_cfg->payload; + if (hsic_cfg->flags & PA_HSIC_HUE_ENABLE) + hue = hsic_cfg->hue; + if (hsic_cfg->flags & PA_HSIC_SAT_ENABLE) + sat = hsic_cfg->saturation; + if (hsic_cfg->flags & PA_HSIC_VAL_ENABLE) + val = hsic_cfg->value; + if (hsic_cfg->flags & PA_HSIC_CONT_ENABLE) + cont = hsic_cfg->contrast; + } + + __setup_pa_hue(&ctx->hw, &ctx->cap->sblk->hsic, hue, DSPP); + __setup_pa_sat(&ctx->hw, &ctx->cap->sblk->hsic, sat, DSPP); + __setup_pa_val(&ctx->hw, &ctx->cap->sblk->hsic, val, DSPP); + __setup_pa_cont(&ctx->hw, &ctx->cap->sblk->hsic, cont, DSPP); +} + +void sde_setup_dspp_sixzone_v17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_sixzone *sixzone; + u32 opcode = 0, local_opcode = 0; + u32 reg = 0, hold = 0, local_hold = 0; + u32 addr = 0; + int i = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable sixzone feature\n"); + opcode &= ~(DSPP_OP_SZ_HUE_EN | DSPP_OP_SZ_SAT_EN | + DSPP_OP_SZ_VAL_EN); + if (PA_DSPP_DISABLE_REQUIRED(opcode)) + opcode &= ~DSPP_OP_PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_sixzone)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_sixzone)); + return; + } + + sixzone = hw_cfg->payload; + + reg = BIT(26); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->sixzone.base, reg); + + addr = ctx->cap->sblk->sixzone.base + DSPP_SZ_ADJ_CURVE_P1_OFF; + for (i = 0; i < SIXZONE_LUT_SIZE; i++) { + SDE_REG_WRITE(&ctx->hw, addr, sixzone->curve[i].p1); + SDE_REG_WRITE(&ctx->hw, (addr - 4), sixzone->curve[i].p0); + } + + addr = ctx->cap->sblk->sixzone.base + DSPP_SZ_THRESHOLDS_OFF; + SDE_REG_WRITE(&ctx->hw, addr, sixzone->threshold); + SDE_REG_WRITE(&ctx->hw, (addr + 4), sixzone->adjust_p0); + SDE_REG_WRITE(&ctx->hw, (addr + 8), sixzone->adjust_p1); + + hold = SDE_REG_READ(&ctx->hw, + (ctx->cap->sblk->hsic.base + DSPP_PA_PWL_HOLD_OFF)); + local_hold = ((sixzone->sat_hold & REG_MASK(2)) << 12); + local_hold |= ((sixzone->val_hold & REG_MASK(2)) << 14); + hold &= ~REG_MASK_SHIFT(4, 12); + hold |= local_hold; + SDE_REG_WRITE(&ctx->hw, + (ctx->cap->sblk->hsic.base + DSPP_PA_PWL_HOLD_OFF), + hold); + + if (sixzone->flags & SIXZONE_HUE_ENABLE) + local_opcode |= DSPP_OP_SZ_HUE_EN; + if (sixzone->flags & SIXZONE_SAT_ENABLE) + local_opcode |= DSPP_OP_SZ_SAT_EN; + if (sixzone->flags & SIXZONE_VAL_ENABLE) + local_opcode |= DSPP_OP_SZ_VAL_EN; + + if (local_opcode) + local_opcode |= DSPP_OP_PA_EN; + + opcode &= ~REG_MASK_SHIFT(3, 29); + opcode |= local_opcode; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); +} + +void sde_setup_pipe_pa_memcol_v1_7(struct sde_hw_pipe *ctx, + enum sde_memcolor_type type, + void *cfg) +{ + struct drm_msm_memcol *mc = cfg; + u32 base = ctx->cap->sblk->memcolor_blk.base; + u32 off, op, mc_en, hold = 0; + u32 mc_i = 0; + + switch (type) { + case MEMCOLOR_SKIN: + mc_en = VIG_OP_PA_SKIN_EN; + mc_i = 0; + break; + case MEMCOLOR_SKY: + mc_en = VIG_OP_PA_SKY_EN; + mc_i = 1; + break; + case MEMCOLOR_FOLIAGE: + mc_en = VIG_OP_PA_FOL_EN; + mc_i = 2; + break; + default: + DRM_ERROR("Invalid memory color type %d\n", type); + return; + } + + op = SDE_REG_READ(&ctx->hw, base); + if (!mc) { + op &= ~mc_en; + if (PA_VIG_DISABLE_REQUIRED(op)) + op &= ~VIG_OP_PA_EN; + SDE_REG_WRITE(&ctx->hw, base, op); + return; + } + + off = base + (mc_i * MEMCOL_P0_LEN); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_PWL0_OFF), + mc->color_adjust_p0 & MEMCOL_PWL0_MASK); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_PWL1_OFF), + mc->color_adjust_p1 & MEMCOL_PWL1_MASK); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_HUE_REGION_OFF), + mc->hue_region & MEMCOL_HUE_REGION_MASK); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_SAT_REGION_OFF), + mc->sat_region & MEMCOL_SAT_REGION_MASK); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_VAL_REGION_OFF), + mc->val_region & MEMCOL_VAL_REGION_MASK); + + off = base + (mc_i * MEMCOL_P1_LEN); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_PWL2_OFF), + mc->color_adjust_p2 & MEMCOL_PWL2_MASK); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_BLEND_GAIN_OFF), mc->blend_gain); + + hold = SDE_REG_READ(&ctx->hw, off + MEMCOL_PWL_HOLD_OFF); + hold &= ~(0xF << (mc_i * 4)); + hold |= ((mc->sat_hold & 0x3) << (mc_i * 4)); + hold |= ((mc->val_hold & 0x3) << ((mc_i * 4) + 2)); + SDE_REG_WRITE(&ctx->hw, (off + MEMCOL_PWL_HOLD_OFF), hold); + + op |= VIG_OP_PA_EN | mc_en; + SDE_REG_WRITE(&ctx->hw, base, op); +} + +static void __setup_dspp_memcol(struct sde_hw_dspp *ctx, + enum sde_memcolor_type type, + struct drm_msm_memcol *memcolor) +{ + u32 addr = 0, offset = 0, idx = 0; + u32 hold = 0, local_hold = 0, hold_shift = 0; + + switch (type) { + case MEMCOLOR_SKIN: + idx = 0; + break; + case MEMCOLOR_SKY: + idx = 1; + break; + case MEMCOLOR_FOLIAGE: + idx = 2; + break; + default: + DRM_ERROR("Invalid memory color type %d\n", type); + return; + } + + offset = DSPP_MEMCOL_PWL0_OFF + (idx * DSPP_MEMCOL_SIZE0); + addr = ctx->cap->sblk->memcolor.base + offset; + hold_shift = idx * DSPP_MEMCOL_HOLD_SIZE; + + SDE_REG_WRITE(&ctx->hw, addr, memcolor->color_adjust_p0); + addr += 4; + SDE_REG_WRITE(&ctx->hw, addr, memcolor->color_adjust_p1); + addr += 4; + SDE_REG_WRITE(&ctx->hw, addr, memcolor->hue_region); + addr += 4; + SDE_REG_WRITE(&ctx->hw, addr, memcolor->sat_region); + addr += 4; + SDE_REG_WRITE(&ctx->hw, addr, memcolor->val_region); + + offset = DSPP_MEMCOL_PWL2_OFF + (idx * DSPP_MEMCOL_SIZE1); + addr = ctx->cap->sblk->memcolor.base + offset; + + SDE_REG_WRITE(&ctx->hw, addr, memcolor->color_adjust_p2); + addr += 4; + SDE_REG_WRITE(&ctx->hw, addr, memcolor->blend_gain); + + addr = ctx->cap->sblk->hsic.base + DSPP_PA_PWL_HOLD_OFF; + hold = SDE_REG_READ(&ctx->hw, addr); + local_hold = ((memcolor->sat_hold & REG_MASK(2)) << hold_shift); + local_hold |= + ((memcolor->val_hold & REG_MASK(2)) << (hold_shift + 2)); + hold &= ~REG_MASK_SHIFT(4, hold_shift); + hold |= local_hold; + SDE_REG_WRITE(&ctx->hw, addr, hold); +} + +void sde_setup_dspp_memcol_skin_v17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_memcol *memcolor; + u32 opcode = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor skin feature\n"); + opcode &= ~(DSPP_OP_PA_SKIN_EN); + if (PA_DSPP_DISABLE_REQUIRED(opcode)) + opcode &= ~DSPP_OP_PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + memcolor = hw_cfg->payload; + + __setup_dspp_memcol(ctx, MEMCOLOR_SKIN, memcolor); + + opcode |= (DSPP_OP_PA_SKIN_EN | DSPP_OP_PA_EN); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); +} + +void sde_setup_dspp_memcol_sky_v17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_memcol *memcolor; + u32 opcode = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor sky feature\n"); + opcode &= ~(DSPP_OP_PA_SKY_EN); + if (PA_DSPP_DISABLE_REQUIRED(opcode)) + opcode &= ~DSPP_OP_PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + memcolor = hw_cfg->payload; + + __setup_dspp_memcol(ctx, MEMCOLOR_SKY, memcolor); + + opcode |= (DSPP_OP_PA_SKY_EN | DSPP_OP_PA_EN); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); +} + +void sde_setup_dspp_memcol_foliage_v17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_memcol *memcolor; + u32 opcode = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor foliage feature\n"); + opcode &= ~(DSPP_OP_PA_FOL_EN); + if (PA_DSPP_DISABLE_REQUIRED(opcode)) + opcode &= ~DSPP_OP_PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + memcolor = hw_cfg->payload; + + __setup_dspp_memcol(ctx, MEMCOLOR_FOLIAGE, memcolor); + + opcode |= (DSPP_OP_PA_FOL_EN | DSPP_OP_PA_EN); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); +} + +void sde_setup_dspp_memcol_prot_v17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_memcol *memcolor; + u32 opcode = 0, local_opcode = 0; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor prot feature\n"); + opcode &= ~(DSPP_MEMCOL_PROT_MASK); + if (PA_DSPP_DISABLE_REQUIRED(opcode)) + opcode &= ~DSPP_OP_PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + memcolor = hw_cfg->payload; + + if (memcolor->prot_flags) { + if (memcolor->prot_flags & MEMCOL_PROT_HUE) + local_opcode |= DSPP_MEMCOL_PROT_HUE_EN; + if (memcolor->prot_flags & MEMCOL_PROT_SAT) + local_opcode |= DSPP_MEMCOL_PROT_SAT_EN; + if (memcolor->prot_flags & MEMCOL_PROT_VAL) + local_opcode |= DSPP_MEMCOL_PROT_VAL_EN; + if (memcolor->prot_flags & MEMCOL_PROT_CONT) + local_opcode |= DSPP_MEMCOL_PROT_CONT_EN; + if (memcolor->prot_flags & MEMCOL_PROT_SIXZONE) + local_opcode |= DSPP_MEMCOL_PROT_SIXZONE_EN; + if (memcolor->prot_flags & MEMCOL_PROT_BLEND) + local_opcode |= DSPP_MEMCOL_PROT_BLEND_EN; + } + + if (local_opcode) { + local_opcode |= DSPP_OP_PA_EN; + opcode &= ~(DSPP_MEMCOL_PROT_MASK); + opcode |= local_opcode; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + } +} + +void sde_setup_dspp_pcc_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_pcc *pcc; + void __iomem *base; + + if (!hw_cfg || (hw_cfg->len != sizeof(*pcc) && hw_cfg->payload)) { + DRM_ERROR( + "invalid params hw %pK payload %pK payloadsize %d exp size %zd\n", + hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL), + ((hw_cfg) ? hw_cfg->len : 0), sizeof(*pcc)); + return; + } + base = ctx->hw.base_off + ctx->cap->base; + + /* Turn off feature */ + if (!hw_cfg->payload) { + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, + PCC_OP_MODE_OFF); + return; + } + DRM_DEBUG_DRIVER("Enable PCC feature\n"); + pcc = hw_cfg->payload; + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF, + pcc->r.c & PCC_CONST_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, + ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF + 4, + pcc->g.c & PCC_CONST_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, + ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF + 8, + pcc->b.c & PCC_CONST_COEFF_MASK); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF, + pcc->r.r & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF + 4, + pcc->g.r & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_R_COEFF_OFF + 8, + pcc->b.r & PCC_COEFF_MASK); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF, + pcc->r.g & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF + 4, + pcc->g.g & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_G_COEFF_OFF + 8, + pcc->b.g & PCC_COEFF_MASK); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF, + pcc->r.b & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF + 4, + pcc->g.b & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_B_COEFF_OFF + 8, + pcc->b.b & PCC_COEFF_MASK); + + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF, + pcc->r.rg & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF + 4, + pcc->g.rg & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RG_COEFF_OFF + 8, + pcc->b.rg & PCC_COEFF_MASK); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF, + pcc->r.rb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF + 4, + pcc->g.rb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RB_COEFF_OFF + 8, + pcc->b.rb & PCC_COEFF_MASK); + + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF, + pcc->r.gb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF + 4, + pcc->g.gb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_GB_COEFF_OFF + 8, + pcc->b.gb & PCC_COEFF_MASK); + + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF, + pcc->r.rgb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, + ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF + 4, + pcc->g.rgb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, + ctx->cap->sblk->pcc.base + PCC_RGB_COEFF_OFF + 8, + pcc->b.rgb & PCC_COEFF_MASK); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base, DSPP_OP_PCC_ENABLE); +} + +void sde_setup_dspp_pa_vlut_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_pa_vlut *payload = NULL; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 base = ctx->cap->sblk->vlut.base; + u32 offset = base + PA_LUTV_DSPP_OFF; + u32 op_mode, tmp; + int i = 0, j = 0; + + if (!hw_cfg || (hw_cfg->payload && hw_cfg->len != + sizeof(struct drm_msm_pa_vlut))) { + DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n", + hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL), + ((hw_cfg) ? hw_cfg->len : 0), + sizeof(struct drm_msm_pa_vlut)); + return; + } + op_mode = SDE_REG_READ(&ctx->hw, base); + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable vlut feature\n"); + /** + * In the PA_VLUT disable case, remove PA_VLUT enable bit(19) + * first, then check whether any other PA sub-features are + * enabled or not. If none of the sub-features are enabled, + * remove the PA global enable bit(20). + */ + op_mode &= ~((u32)DSPP_OP_PA_LUTV_EN); + if (PA_DSPP_DISABLE_REQUIRED(op_mode)) + op_mode &= ~((u32)DSPP_OP_PA_EN); + SDE_REG_WRITE(&ctx->hw, base, op_mode); + return; + } + payload = hw_cfg->payload; + DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags); + for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) { + tmp = (payload->val[i] & REG_MASK(10)) | + ((payload->val[i + 1] & REG_MASK(10)) << 16); + SDE_REG_WRITE(&ctx->hw, (offset + j), + tmp); + } + SDE_REG_WRITE(&ctx->hw, (base + PA_LUT_SWAP_OFF), 1); + op_mode |= DSPP_OP_PA_EN | DSPP_OP_PA_LUTV_EN; + SDE_REG_WRITE(&ctx->hw, base, op_mode); +} + +void sde_setup_dspp_pa_vlut_v1_8(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_pa_vlut *payload = NULL; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_ctl *ctl = NULL; + u32 vlut_base, pa_hist_base; + u32 ctrl_off, swap_off; + u32 tmp = 0; + int i = 0, j = 0; + + if (!ctx) { + DRM_ERROR("invalid input parameter NULL ctx\n"); + return; + } + + if (!hw_cfg || (hw_cfg->payload && hw_cfg->len != + sizeof(struct drm_msm_pa_vlut))) { + DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n", + hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL), + ((hw_cfg) ? hw_cfg->len : 0), + sizeof(struct drm_msm_pa_vlut)); + return; + } + + ctl = hw_cfg->ctl; + vlut_base = ctx->cap->sblk->vlut.base; + pa_hist_base = ctx->cap->sblk->hist.base; + ctrl_off = pa_hist_base + PA_LUTV_DSPP_CTRL_OFF; + swap_off = pa_hist_base + PA_LUTV_DSPP_SWAP_OFF; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable vlut feature\n"); + SDE_REG_WRITE(&ctx->hw, ctrl_off, 0); + goto exit; + } + + payload = hw_cfg->payload; + DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags); + for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) { + tmp = (payload->val[i] & REG_MASK(10)) | + ((payload->val[i + 1] & REG_MASK(10)) << 16); + SDE_REG_WRITE(&ctx->hw, (vlut_base + j), tmp); + } + SDE_REG_WRITE(&ctx->hw, ctrl_off, 1); + SDE_REG_WRITE(&ctx->hw, swap_off, 1); + +exit: + /* update flush bit */ + if (ctl && ctl->ops.update_bitmask_dspp_pavlut) + ctl->ops.update_bitmask_dspp_pavlut(ctl, ctx->idx, 1); +} + +void sde_setup_dspp_gc_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_pgc_lut *payload = NULL; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 c0_off, c1_off, c2_off, i; + + if (!hw_cfg || (hw_cfg->payload && hw_cfg->len != + sizeof(struct drm_msm_pgc_lut))) { + DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n", + hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL), + ((hw_cfg) ? hw_cfg->len : 0), + sizeof(struct drm_msm_pgc_lut)); + return; + } + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable pgc feature\n"); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base, 0); + return; + } + payload = hw_cfg->payload; + + /* Initialize index offsets */ + c0_off = ctx->cap->sblk->gc.base + PGC_C0_INDEX_OFF; + c1_off = c0_off + (sizeof(u32) * 2); + c2_off = c1_off + (sizeof(u32) * 2); + SDE_REG_WRITE(&ctx->hw, c0_off, 0); + SDE_REG_WRITE(&ctx->hw, c1_off, 0); + SDE_REG_WRITE(&ctx->hw, c2_off, 0); + + /* Initialize table offsets */ + c0_off = ctx->cap->sblk->gc.base + PGC_C0_OFF; + c1_off = c0_off + (sizeof(u32) * 2); + c2_off = c1_off + (sizeof(u32) * 2); + + for (i = 0; i < PGC_TBL_LEN; i++) { + SDE_REG_WRITE(&ctx->hw, c0_off, payload->c0[i]); + SDE_REG_WRITE(&ctx->hw, c1_off, payload->c1[i]); + SDE_REG_WRITE(&ctx->hw, c2_off, payload->c2[i]); + } + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base + PGC_LUT_SWAP_OFF, + BIT(0)); + i = BIT(0) | ((payload->flags & PGC_8B_ROUND) ? BIT(1) : 0); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base, i); +} + +void sde_setup_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + u32 base, offset; + u32 op_mode; + bool feature_enabled; + + if (!ctx || !cfg) { + DRM_ERROR("invalid parameters ctx %pK cfg %pK", ctx, cfg); + return; + } + + feature_enabled = *(bool *)cfg; + base = ctx->cap->sblk->hist.base; + offset = base + PA_HIST_CTRL_DSPP_OFF; + + op_mode = SDE_REG_READ(&ctx->hw, base); + if (!feature_enabled) { + op_mode &= ~DSPP_OP_PA_HIST_EN; + if (PA_DSPP_DISABLE_REQUIRED(op_mode)) + op_mode &= ~DSPP_OP_PA_EN; + } else { + op_mode |= DSPP_OP_PA_HIST_EN | DSPP_OP_PA_EN; + } + + SDE_REG_WRITE(&ctx->hw, offset, 0); + SDE_REG_WRITE(&ctx->hw, base, op_mode); +} + +void sde_read_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_hist *hist_data; + u32 offset, offset_ctl; + u32 i; + + if (!ctx || !cfg) { + DRM_ERROR("invalid parameters ctx %pK cfg %pK", ctx, cfg); + return; + } + + hist_data = (struct drm_msm_hist *)cfg; + offset = ctx->cap->sblk->hist.base + PA_HIST_DATA_DSPP_OFF; + offset_ctl = ctx->cap->sblk->hist.base + PA_HIST_CTRL_DSPP_OFF; + + /* collect hist data for given DSPPs */ + for (i = 0; i < HIST_V_SIZE; i++) + hist_data->data[i] += SDE_REG_READ(&ctx->hw, offset + i * 4) & + REG_MASK(24); + + /* unlock hist buffer */ + SDE_REG_WRITE(&ctx->hw, offset_ctl, 0); +} + +void sde_lock_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + u32 offset_ctl; + + if (!ctx) { + DRM_ERROR("invalid parameters ctx %pK", ctx); + return; + } + + offset_ctl = ctx->cap->sblk->hist.base + PA_HIST_CTRL_DSPP_OFF; + + /* lock hist buffer */ + SDE_REG_WRITE(&ctx->hw, offset_ctl, 1); +} + +void sde_setup_dspp_dither_v1_7(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_pa_dither *dither; + u32 ctrl_off, matrix_off; + u32 opmode, data, i; + + if (!hw_cfg || (hw_cfg->len != sizeof(struct drm_msm_pa_dither) && + hw_cfg->payload)) { + DRM_ERROR("hw %pK payload %pK size %d expected sz %zd\n", + hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL), + ((hw_cfg) ? hw_cfg->len : 0), + sizeof(struct drm_msm_pa_dither)); + return; + } + + ctrl_off = ctx->cap->sblk->dither.base; + matrix_off = ctrl_off + PA_DITH_DSPP_MATRIX_OFF; + + /* Turn off feature */ + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable DSPP dither feature\n"); + SDE_REG_WRITE(&ctx->hw, ctrl_off, 0); + return; + } + DRM_DEBUG_DRIVER("Enable DSPP Dither feature\n"); + dither = hw_cfg->payload; + + for (i = 0; i < DITHER_MATRIX_SZ; i += 4) { + data = (dither->matrix[i] & REG_MASK(4)) | + ((dither->matrix[i + 1] & REG_MASK(4)) << 4) | + ((dither->matrix[i + 2] & REG_MASK(4)) << 8) | + ((dither->matrix[i + 3] & REG_MASK(4)) << 12); + SDE_REG_WRITE(&ctx->hw, matrix_off + i, data); + } + + opmode = BIT(0); + opmode |= (dither->offset_en) ? BIT(1) : 0; + opmode |= ((dither->strength) & REG_MASK(4)) << 4; + SDE_REG_WRITE(&ctx->hw, ctrl_off, opmode); +} diff --git a/techpack/display/msm/sde/sde_hw_color_processing_v1_7.h b/techpack/display/msm/sde/sde_hw_color_processing_v1_7.h new file mode 100644 index 0000000000000000000000000000000000000000..f65e3291c50d57d6f2d11245fd401d3e2282e52b --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_color_processing_v1_7.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_COLOR_PROCESSING_V1_7_H +#define _SDE_HW_COLOR_PROCESSING_V1_7_H + +#include "sde_hw_sspp.h" +#include "sde_hw_dspp.h" + +/** + * sde_setup_pipe_pa_hue_v1_7 - setup SSPP hue feature in v1.7 hardware + * @ctx: Pointer to pipe context + * @cfg: Pointer to hue data + */ +void sde_setup_pipe_pa_hue_v1_7(struct sde_hw_pipe *ctx, void *cfg); + +/** + * sde_setup_pipe_pa_sat_v1_7 - setup SSPP saturation feature in v1.7 hardware + * @ctx: Pointer to pipe context + * @cfg: Pointer to saturation data + */ +void sde_setup_pipe_pa_sat_v1_7(struct sde_hw_pipe *ctx, void *cfg); + +/** + * sde_setup_pipe_pa_val_v1_7 - setup SSPP value feature in v1.7 hardware + * @ctx: Pointer to pipe context + * @cfg: Pointer to value data + */ +void sde_setup_pipe_pa_val_v1_7(struct sde_hw_pipe *ctx, void *cfg); + +/** + * sde_setup_pipe_pa_cont_v1_7 - setup SSPP contrast feature in v1.7 hardware + * @ctx: Pointer to pipe context + * @cfg: Pointer to contrast data + */ +void sde_setup_pipe_pa_cont_v1_7(struct sde_hw_pipe *ctx, void *cfg); + +/** + * sde_setup_pipe_pa_memcol_v1_7 - setup SSPP memory color in v1.7 hardware + * @ctx: Pointer to pipe context + * @type: Memory color type (Skin, sky, or foliage) + * @cfg: Pointer to memory color config data + */ +void sde_setup_pipe_pa_memcol_v1_7(struct sde_hw_pipe *ctx, + enum sde_memcolor_type type, + void *cfg); + +/** + * sde_setup_dspp_pcc_v1_7 - setup DSPP PCC veature in v1.7 hardware + * @ctx: Pointer to dspp context + * @cfg: Pointer to PCC data + */ +void sde_setup_dspp_pcc_v1_7(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_pa_hsic_v17 - setup DSPP hsic feature in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to hsic data + */ +void sde_setup_dspp_pa_hsic_v17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_memcol_skin_v17 - setup DSPP memcol skin in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to memcolor config data + */ +void sde_setup_dspp_memcol_skin_v17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_memcol_sky_v17 - setup DSPP memcol sky in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to memcolor config data + */ +void sde_setup_dspp_memcol_sky_v17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_memcol_foliage_v17 - setup DSPP memcol fol in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to memcolor config data + */ +void sde_setup_dspp_memcol_foliage_v17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_memcol_prot_v17 - setup DSPP memcol prot in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to memcolor config data + */ +void sde_setup_dspp_memcol_prot_v17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_sixzone_v17 - setup DSPP sixzone feature in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to sixzone data + */ +void sde_setup_dspp_sixzone_v17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_pa_vlut_v1_7 - setup DSPP PA vLUT feature in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to vLUT data + */ +void sde_setup_dspp_pa_vlut_v1_7(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_pa_vlut_v1_8 - setup DSPP PA vLUT feature in v1.8 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to vLUT data + */ +void sde_setup_dspp_pa_vlut_v1_8(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_gc_v1_7 - setup DSPP gc feature in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to gc data + */ +void sde_setup_dspp_gc_v1_7(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_hist_v1_7 - setup DSPP histogram feature in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to histogram control data + */ +void sde_setup_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_read_dspp_hist_v1_7 - read DSPP histogram data in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to histogram data + */ +void sde_read_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_lock_dspp_hist_v1_7 - lock DSPP histogram buffer in v1.7 hardware + * @ctx: Pointer to DSPP context + */ +void sde_lock_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg); + +/** + * sde_setup_dspp_dither_v1_7 - setup DSPP dither feature in v1.7 hardware + * @ctx: Pointer to DSPP context + * @cfg: Pointer to dither data + */ +void sde_setup_dspp_dither_v1_7(struct sde_hw_dspp *ctx, void *cfg); +#endif diff --git a/techpack/display/msm/sde/sde_hw_ctl.c b/techpack/display/msm/sde/sde_hw_ctl.c new file mode 100644 index 0000000000000000000000000000000000000000..a06b52b24f17531391b0d513419948a73bd8cd04 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_ctl.c @@ -0,0 +1,1336 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> +#include "sde_hwio.h" +#include "sde_hw_ctl.h" +#include "sde_dbg.h" +#include "sde_kms.h" +#include "sde_reg_dma.h" + +#define CTL_LAYER(lm) \ + (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT(lm) \ + (0x40 + (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT2(lm) \ + (0x70 + (((lm) - LM_0) * 0x004)) +#define CTL_LAYER_EXT3(lm) \ + (0xA0 + (((lm) - LM_0) * 0x004)) +#define CTL_TOP 0x014 +#define CTL_FLUSH 0x018 +#define CTL_START 0x01C +#define CTL_PREPARE 0x0d0 +#define CTL_SW_RESET 0x030 +#define CTL_SW_RESET_OVERRIDE 0x060 +#define CTL_STATUS 0x064 +#define CTL_LAYER_EXTN_OFFSET 0x40 +#define CTL_ROT_TOP 0x0C0 +#define CTL_ROT_FLUSH 0x0C4 +#define CTL_ROT_START 0x0CC + +#define CTL_MERGE_3D_ACTIVE 0x0E4 +#define CTL_DSC_ACTIVE 0x0E8 +#define CTL_WB_ACTIVE 0x0EC +#define CTL_CWB_ACTIVE 0x0F0 +#define CTL_INTF_ACTIVE 0x0F4 +#define CTL_CDM_ACTIVE 0x0F8 + +#define CTL_MERGE_3D_FLUSH 0x100 +#define CTL_DSC_FLUSH 0x104 +#define CTL_WB_FLUSH 0x108 +#define CTL_CWB_FLUSH 0x10C +#define CTL_INTF_FLUSH 0x110 +#define CTL_CDM_FLUSH 0x114 +#define CTL_PERIPH_FLUSH 0x128 + +#define CTL_INTF_MASTER 0x134 +#define CTL_UIDLE_ACTIVE 0x138 + +#define CTL_MIXER_BORDER_OUT BIT(24) +#define CTL_FLUSH_MASK_ROT BIT(27) +#define CTL_FLUSH_MASK_CTL BIT(17) + +#define CTL_NUM_EXT 4 +#define CTL_SSPP_MAX_RECTS 2 + +#define SDE_REG_RESET_TIMEOUT_US 2000 +#define SDE_REG_WAIT_RESET_TIMEOUT_US 100000 + +#define UPDATE_MASK(m, idx, en) \ + ((m) = (en) ? ((m) | BIT((idx))) : ((m) & ~BIT((idx)))) + +/** + * List of SSPP bits in CTL_FLUSH + */ +static const u32 sspp_tbl[SSPP_MAX] = { SDE_NONE, 0, 1, 2, 18, 3, 4, 5, + 19, 11, 12, 24, 25, SDE_NONE, SDE_NONE}; + +/** + * List of layer mixer bits in CTL_FLUSH + */ +static const u32 mixer_tbl[LM_MAX] = {SDE_NONE, 6, 7, 8, 9, 10, 20, + SDE_NONE}; + +/** + * List of DSPP bits in CTL_FLUSH + */ +static const u32 dspp_tbl[DSPP_MAX] = {SDE_NONE, 13, 14, 15, 21}; + +/** + * List of DSPP PA LUT bits in CTL_FLUSH + */ +static const u32 dspp_pav_tbl[DSPP_MAX] = {SDE_NONE, 3, 4, 5, 19}; + +/** + * List of CDM LUT bits in CTL_FLUSH + */ +static const u32 cdm_tbl[CDM_MAX] = {SDE_NONE, 26}; + +/** + * List of WB bits in CTL_FLUSH + */ +static const u32 wb_tbl[WB_MAX] = {SDE_NONE, SDE_NONE, SDE_NONE, 16}; + +/** + * List of ROT bits in CTL_FLUSH + */ +static const u32 rot_tbl[ROT_MAX] = {SDE_NONE, 27}; + +/** + * List of INTF bits in CTL_FLUSH + */ +static const u32 intf_tbl[INTF_MAX] = {SDE_NONE, 31, 30, 29, 28}; + +/** + * Below definitions are for CTL supporting SDE_CTL_ACTIVE_CFG, + * certain blocks have the individual flush control as well, + * for such blocks flush is done by flushing individual control and + * top level control. + */ + +/** + * list of WB bits in CTL_WB_FLUSH + */ +static const u32 wb_flush_tbl[WB_MAX] = {SDE_NONE, SDE_NONE, SDE_NONE, 2}; + +/** + * list of INTF bits in CTL_INTF_FLUSH + */ +static const u32 intf_flush_tbl[INTF_MAX] = {SDE_NONE, 0, 1, 2, 3, 4, 5}; + +/** + * list of DSC bits in CTL_DSC_FLUSH + */ +static const u32 dsc_flush_tbl[DSC_MAX] = {SDE_NONE, 0, 1, 2, 3, 4, 5}; + +/** + * list of MERGE_3D bits in CTL_MERGE_3D_FLUSH + */ +static const u32 merge_3d_tbl[MERGE_3D_MAX] = {SDE_NONE, 0, 1, 2}; + +/** + * list of CDM bits in CTL_CDM_FLUSH + */ +static const u32 cdm_flush_tbl[CDM_MAX] = {SDE_NONE, 0}; + +/** + * list of CWB bits in CTL_CWB_FLUSH + */ +static const u32 cwb_flush_tbl[CWB_MAX] = {SDE_NONE, SDE_NONE, 1, 2, 3, + 4, 5}; + +/** + * struct ctl_sspp_stage_reg_map: Describes bit layout for a sspp stage cfg + * @ext: Index to indicate LAYER_x_EXT id for given sspp + * @start: Start position of blend stage bits for given sspp + * @bits: Number of bits from @start assigned for given sspp + * @sec_bit_mask: Bitmask to add to LAYER_x_EXT1 for missing bit of sspp + */ +struct ctl_sspp_stage_reg_map { + u32 ext; + u32 start; + u32 bits; + u32 sec_bit_mask; +}; + +/* list of ctl_sspp_stage_reg_map for all the sppp */ +static const struct ctl_sspp_stage_reg_map +sspp_reg_cfg_tbl[SSPP_MAX][CTL_SSPP_MAX_RECTS] = { + /* SSPP_NONE */{ {0, 0, 0, 0}, {0, 0, 0, 0} }, + /* SSPP_VIG0 */{ {0, 0, 3, BIT(0)}, {3, 0, 4, 0} }, + /* SSPP_VIG1 */{ {0, 3, 3, BIT(2)}, {3, 4, 4, 0} }, + /* SSPP_VIG2 */{ {0, 6, 3, BIT(4)}, {3, 8, 4, 0} }, + /* SSPP_VIG3 */{ {0, 26, 3, BIT(6)}, {3, 12, 4, 0} }, + /* SSPP_RGB0 */{ {0, 9, 3, BIT(8)}, {0, 0, 0, 0} }, + /* SSPP_RGB1 */{ {0, 12, 3, BIT(10)}, {0, 0, 0, 0} }, + /* SSPP_RGB2 */{ {0, 15, 3, BIT(12)}, {0, 0, 0, 0} }, + /* SSPP_RGB3 */{ {0, 29, 3, BIT(14)}, {0, 0, 0, 0} }, + /* SSPP_DMA0 */{ {0, 18, 3, BIT(16)}, {2, 8, 4, 0} }, + /* SSPP_DMA1 */{ {0, 21, 3, BIT(18)}, {2, 12, 4, 0} }, + /* SSPP_DMA2 */{ {2, 0, 4, 0}, {2, 16, 4, 0} }, + /* SSPP_DMA3 */{ {2, 4, 4, 0}, {2, 20, 4, 0} }, + /* SSPP_CURSOR0 */{ {1, 20, 4, 0}, {0, 0, 0, 0} }, + /* SSPP_CURSOR1 */{ {0, 26, 4, 0}, {0, 0, 0, 0} } +}; + +/** + * Individual flush bit in CTL_FLUSH + */ +#define WB_IDX 16 +#define DSC_IDX 22 +#define MERGE_3D_IDX 23 +#define CDM_IDX 26 +#define CWB_IDX 28 +#define PERIPH_IDX 30 +#define INTF_IDX 31 + +static struct sde_ctl_cfg *_ctl_offset(enum sde_ctl ctl, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->ctl_count; i++) { + if (ctl == m->ctl[i].id) { + b->base_off = addr; + b->blk_off = m->ctl[i].base; + b->length = m->ctl[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_CTL; + return &m->ctl[i]; + } + } + return ERR_PTR(-ENOMEM); +} + +static int _mixer_stages(const struct sde_lm_cfg *mixer, int count, + enum sde_lm lm) +{ + int i; + int stages = -EINVAL; + + for (i = 0; i < count; i++) { + if (lm == mixer[i].id) { + stages = mixer[i].sblk->maxblendstages; + break; + } + } + + return stages; +} + +static inline int sde_hw_ctl_trigger_start(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return -EINVAL; + + SDE_REG_WRITE(&ctx->hw, CTL_START, 0x1); + return 0; +} + +static inline int sde_hw_ctl_get_start_state(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return -EINVAL; + + return SDE_REG_READ(&ctx->hw, CTL_START); +} + +static inline int sde_hw_ctl_trigger_pending(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return -EINVAL; + + SDE_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1); + return 0; +} + +static inline int sde_hw_ctl_clear_pending_flush(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return -EINVAL; + + memset(&ctx->flush, 0, sizeof(ctx->flush)); + return 0; +} + +static inline int sde_hw_ctl_update_pending_flush(struct sde_hw_ctl *ctx, + struct sde_ctl_flush_cfg *cfg) +{ + if (!ctx || !cfg) + return -EINVAL; + + ctx->flush.pending_flush_mask |= cfg->pending_flush_mask; + return 0; +} + +static int sde_hw_ctl_get_pending_flush(struct sde_hw_ctl *ctx, + struct sde_ctl_flush_cfg *cfg) +{ + if (!ctx || !cfg) + return -EINVAL; + + memcpy(cfg, &ctx->flush, sizeof(*cfg)); + return 0; +} + +static inline int sde_hw_ctl_trigger_flush(struct sde_hw_ctl *ctx) +{ + + if (!ctx) + return -EINVAL; + + SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->flush.pending_flush_mask); + return 0; +} + +static inline u32 sde_hw_ctl_get_flush_register(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 rot_op_mode; + + if (!ctx) + return 0; + + c = &ctx->hw; + rot_op_mode = SDE_REG_READ(c, CTL_ROT_TOP) & 0x3; + + /* rotate flush bit is undefined if offline mode, so ignore it */ + if (rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE) + return SDE_REG_READ(c, CTL_FLUSH) & ~CTL_FLUSH_MASK_ROT; + + return SDE_REG_READ(c, CTL_FLUSH); +} + +static inline void sde_hw_ctl_uidle_enable(struct sde_hw_ctl *ctx, bool enable) +{ + u32 val; + + if (!ctx) + return; + + val = SDE_REG_READ(&ctx->hw, CTL_UIDLE_ACTIVE); + val = (val & ~BIT(0)) | (enable ? BIT(0) : 0); + + SDE_REG_WRITE(&ctx->hw, CTL_UIDLE_ACTIVE, val); +} + +static inline int sde_hw_ctl_update_bitmask_sspp(struct sde_hw_ctl *ctx, + enum sde_sspp sspp, + bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(sspp > SSPP_NONE) || !(sspp < SSPP_MAX)) { + SDE_ERROR("Unsupported pipe %d\n", sspp); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, sspp_tbl[sspp], enable); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_mixer(struct sde_hw_ctl *ctx, + enum sde_lm lm, + bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(lm > SDE_NONE) || !(lm < LM_MAX)) { + SDE_ERROR("Unsupported mixer %d\n", lm); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, mixer_tbl[lm], enable); + ctx->flush.pending_flush_mask |= CTL_FLUSH_MASK_CTL; + + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_dspp(struct sde_hw_ctl *ctx, + enum sde_dspp dspp, + bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(dspp > SDE_NONE) || !(dspp < DSPP_MAX)) { + SDE_ERROR("Unsupported dspp %d\n", dspp); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, dspp_tbl[dspp], enable); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_dspp_pavlut(struct sde_hw_ctl *ctx, + enum sde_dspp dspp, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(dspp > SDE_NONE) || !(dspp < DSPP_MAX)) { + SDE_ERROR("Unsupported dspp %d\n", dspp); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, dspp_pav_tbl[dspp], enable); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_cdm(struct sde_hw_ctl *ctx, + enum sde_cdm cdm, + bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(cdm > SDE_NONE) || !(cdm < CDM_MAX) || (cdm == CDM_1)) { + SDE_ERROR("Unsupported cdm %d\n", cdm); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, cdm_tbl[cdm], enable); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_wb(struct sde_hw_ctl *ctx, + enum sde_wb wb, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(wb > SDE_NONE) || !(wb < WB_MAX) || + (wb == WB_0) || (wb == WB_1)) { + SDE_ERROR("Unsupported wb %d\n", wb); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, wb_tbl[wb], enable); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_intf(struct sde_hw_ctl *ctx, + enum sde_intf intf, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(intf > SDE_NONE) || !(intf < INTF_MAX) || (intf > INTF_4)) { + SDE_ERROR("Unsupported intf %d\n", intf); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_flush_mask, intf_tbl[intf], enable); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_wb_v1(struct sde_hw_ctl *ctx, + enum sde_wb wb, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (wb != WB_2) { + SDE_ERROR("Unsupported wb %d\n", wb); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_wb_flush_mask, wb_flush_tbl[wb], enable); + if (ctx->flush.pending_wb_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, WB_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, WB_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_intf_v1(struct sde_hw_ctl *ctx, + enum sde_intf intf, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(intf > SDE_NONE) || !(intf < INTF_MAX)) { + SDE_ERROR("Unsupported intf %d\n", intf); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_intf_flush_mask, intf_flush_tbl[intf], + enable); + if (ctx->flush.pending_intf_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, INTF_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, INTF_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_periph_v1(struct sde_hw_ctl *ctx, + enum sde_intf intf, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(intf > SDE_NONE) || !(intf < INTF_MAX)) { + SDE_ERROR("Unsupported intf %d\n", intf); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_periph_flush_mask, intf_flush_tbl[intf], + enable); + if (ctx->flush.pending_periph_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, PERIPH_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, PERIPH_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_dsc_v1(struct sde_hw_ctl *ctx, + enum sde_dsc dsc, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(dsc > SDE_NONE) || !(dsc < DSC_MAX)) { + SDE_ERROR("Unsupported dsc %d\n", dsc); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_dsc_flush_mask, dsc_flush_tbl[dsc], + enable); + if (ctx->flush.pending_dsc_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, DSC_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, DSC_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_merge3d_v1(struct sde_hw_ctl *ctx, + enum sde_merge_3d merge_3d, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (!(merge_3d > SDE_NONE) || !(merge_3d < MERGE_3D_MAX)) { + SDE_ERROR("Unsupported merge_3d %d\n", merge_3d); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_merge_3d_flush_mask, + merge_3d_tbl[merge_3d], enable); + if (ctx->flush.pending_merge_3d_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, MERGE_3D_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, MERGE_3D_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_cdm_v1(struct sde_hw_ctl *ctx, + enum sde_cdm cdm, bool enable) +{ + if (!ctx) + return -EINVAL; + + if (cdm != CDM_0) { + SDE_ERROR("Unsupported cdm %d\n", cdm); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_cdm_flush_mask, cdm_flush_tbl[cdm], + enable); + if (ctx->flush.pending_cdm_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, CDM_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, CDM_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_bitmask_cwb_v1(struct sde_hw_ctl *ctx, + enum sde_cwb cwb, bool enable) +{ + if (!ctx) + return -EINVAL; + + if ((cwb < CWB_1) || (cwb >= CWB_MAX)) { + SDE_ERROR("Unsupported cwb %d\n", cwb); + return -EINVAL; + } + + UPDATE_MASK(ctx->flush.pending_cwb_flush_mask, cwb_flush_tbl[cwb], + enable); + if (ctx->flush.pending_cwb_flush_mask) + UPDATE_MASK(ctx->flush.pending_flush_mask, CWB_IDX, 1); + else + UPDATE_MASK(ctx->flush.pending_flush_mask, CWB_IDX, 0); + return 0; +} + +static inline int sde_hw_ctl_update_pending_flush_v1( + struct sde_hw_ctl *ctx, + struct sde_ctl_flush_cfg *cfg) +{ + if (!ctx || !cfg) + return -EINVAL; + + ctx->flush.pending_flush_mask |= cfg->pending_flush_mask; + ctx->flush.pending_intf_flush_mask |= cfg->pending_intf_flush_mask; + ctx->flush.pending_cdm_flush_mask |= cfg->pending_cdm_flush_mask; + ctx->flush.pending_wb_flush_mask |= cfg->pending_wb_flush_mask; + ctx->flush.pending_dsc_flush_mask |= cfg->pending_dsc_flush_mask; + ctx->flush.pending_merge_3d_flush_mask |= + cfg->pending_merge_3d_flush_mask; + ctx->flush.pending_cwb_flush_mask |= cfg->pending_cwb_flush_mask; + ctx->flush.pending_periph_flush_mask |= cfg->pending_periph_flush_mask; + return 0; +} + +static inline int sde_hw_ctl_trigger_flush_v1(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return -EINVAL; + + if (ctx->flush.pending_flush_mask & BIT(WB_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_WB_FLUSH, + ctx->flush.pending_wb_flush_mask); + if (ctx->flush.pending_flush_mask & BIT(DSC_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, + ctx->flush.pending_dsc_flush_mask); + if (ctx->flush.pending_flush_mask & BIT(MERGE_3D_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_MERGE_3D_FLUSH, + ctx->flush.pending_merge_3d_flush_mask); + if (ctx->flush.pending_flush_mask & BIT(CDM_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_CDM_FLUSH, + ctx->flush.pending_cdm_flush_mask); + if (ctx->flush.pending_flush_mask & BIT(CWB_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_CWB_FLUSH, + ctx->flush.pending_cwb_flush_mask); + if (ctx->flush.pending_flush_mask & BIT(INTF_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH, + ctx->flush.pending_intf_flush_mask); + if (ctx->flush.pending_flush_mask & BIT(PERIPH_IDX)) + SDE_REG_WRITE(&ctx->hw, CTL_PERIPH_FLUSH, + ctx->flush.pending_periph_flush_mask); + + SDE_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->flush.pending_flush_mask); + return 0; +} + +static inline u32 sde_hw_ctl_get_intf_v1(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 intf_active; + + if (!ctx) { + pr_err("Invalid input argument\n"); + return 0; + } + + c = &ctx->hw; + intf_active = SDE_REG_READ(c, CTL_INTF_ACTIVE); + + return intf_active; +} + +static inline u32 sde_hw_ctl_get_intf(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 ctl_top; + u32 intf_active = 0; + + if (!ctx) { + pr_err("Invalid input argument\n"); + return 0; + } + + c = &ctx->hw; + ctl_top = SDE_REG_READ(c, CTL_TOP); + + intf_active = (ctl_top > 0) ? + BIT(ctl_top - 1) : 0; + + return intf_active; +} + +static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 timeout_us) +{ + struct sde_hw_blk_reg_map *c; + ktime_t timeout; + u32 status; + + if (!ctx) + return 0; + + c = &ctx->hw; + timeout = ktime_add_us(ktime_get(), timeout_us); + + /* + * it takes around 30us to have mdp finish resetting its ctl path + * poll every 50us so that reset should be completed at 1st poll + */ + do { + status = SDE_REG_READ(c, CTL_SW_RESET); + status &= 0x1; + if (status) + usleep_range(20, 50); + } while (status && ktime_compare_safe(ktime_get(), timeout) < 0); + + return status; +} + +static u32 sde_hw_ctl_get_reset_status(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return 0; + return (u32)SDE_REG_READ(&ctx->hw, CTL_SW_RESET); +} + +static u32 sde_hw_ctl_get_scheduler_status(struct sde_hw_ctl *ctx) +{ + if (!ctx) + return INVALID_CTL_STATUS; + return (u32)SDE_REG_READ(&ctx->hw, CTL_STATUS); +} + +static int sde_hw_ctl_reset_control(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + + if (!ctx) + return 0; + + c = &ctx->hw; + pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx); + SDE_REG_WRITE(c, CTL_SW_RESET, 0x1); + if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_US)) + return -EINVAL; + + return 0; +} + +static void sde_hw_ctl_hard_reset(struct sde_hw_ctl *ctx, bool enable) +{ + struct sde_hw_blk_reg_map *c; + + if (!ctx) + return; + + c = &ctx->hw; + pr_debug("hw ctl hard reset for ctl:%d, %d\n", + ctx->idx - CTL_0, enable); + SDE_REG_WRITE(c, CTL_SW_RESET_OVERRIDE, enable); +} + +static int sde_hw_ctl_wait_reset_status(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 status; + + if (!ctx) + return 0; + + c = &ctx->hw; + status = SDE_REG_READ(c, CTL_SW_RESET); + status &= 0x01; + if (!status) + return 0; + + pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx); + if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_WAIT_RESET_TIMEOUT_US)) { + pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx); + return -EINVAL; + } + + return 0; +} + +static void sde_hw_ctl_clear_all_blendstages(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + int i; + + if (!ctx) + return; + + c = &ctx->hw; + for (i = 0; i < ctx->mixer_count; i++) { + int mixer_id = ctx->mixer_hw_caps[i].id; + + SDE_REG_WRITE(c, CTL_LAYER(mixer_id), 0); + SDE_REG_WRITE(c, CTL_LAYER_EXT(mixer_id), 0); + SDE_REG_WRITE(c, CTL_LAYER_EXT2(mixer_id), 0); + SDE_REG_WRITE(c, CTL_LAYER_EXT3(mixer_id), 0); + } +} + +static void sde_hw_ctl_setup_blendstage(struct sde_hw_ctl *ctx, + enum sde_lm lm, struct sde_hw_stage_cfg *stage_cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 mixercfg = 0, mixercfg_ext = 0, mix, ext; + u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0; + int i, j; + u8 stages; + int pipes_per_stage; + + if (!ctx) + return; + + c = &ctx->hw; + stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm); + if ((int)stages < 0) + return; + + if (test_bit(SDE_MIXER_SOURCESPLIT, + &ctx->mixer_hw_caps->features)) + pipes_per_stage = PIPES_PER_STAGE; + else + pipes_per_stage = 1; + + if (!stage_cfg) + goto exit; + + for (i = 0; i <= stages; i++) { + /* overflow to ext register if 'i + 1 > 7' */ + mix = (i + 1) & 0x7; + ext = i >= 7; + + for (j = 0 ; j < pipes_per_stage; j++) { + enum sde_sspp_multirect_index rect_index = + stage_cfg->multirect_index[i][j]; + + switch (stage_cfg->stage[i][j]) { + case SSPP_VIG0: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 0; + } else { + mixercfg |= mix << 0; + mixercfg_ext |= ext << 0; + } + break; + case SSPP_VIG1: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 4; + } else { + mixercfg |= mix << 3; + mixercfg_ext |= ext << 2; + } + break; + case SSPP_VIG2: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 8; + } else { + mixercfg |= mix << 6; + mixercfg_ext |= ext << 4; + } + break; + case SSPP_VIG3: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext3 |= ((i + 1) & 0xF) << 12; + } else { + mixercfg |= mix << 26; + mixercfg_ext |= ext << 6; + } + break; + case SSPP_RGB0: + mixercfg |= mix << 9; + mixercfg_ext |= ext << 8; + break; + case SSPP_RGB1: + mixercfg |= mix << 12; + mixercfg_ext |= ext << 10; + break; + case SSPP_RGB2: + mixercfg |= mix << 15; + mixercfg_ext |= ext << 12; + break; + case SSPP_RGB3: + mixercfg |= mix << 29; + mixercfg_ext |= ext << 14; + break; + case SSPP_DMA0: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 8; + } else { + mixercfg |= mix << 18; + mixercfg_ext |= ext << 16; + } + break; + case SSPP_DMA1: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 12; + } else { + mixercfg |= mix << 21; + mixercfg_ext |= ext << 18; + } + break; + case SSPP_DMA2: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 16; + } else { + mix |= (i + 1) & 0xF; + mixercfg_ext2 |= mix << 0; + } + break; + case SSPP_DMA3: + if (rect_index == SDE_SSPP_RECT_1) { + mixercfg_ext2 |= ((i + 1) & 0xF) << 20; + } else { + mix |= (i + 1) & 0xF; + mixercfg_ext2 |= mix << 4; + } + break; + case SSPP_CURSOR0: + mixercfg_ext |= ((i + 1) & 0xF) << 20; + break; + case SSPP_CURSOR1: + mixercfg_ext |= ((i + 1) & 0xF) << 26; + break; + default: + break; + } + } + } + +exit: + if ((!mixercfg && !mixercfg_ext && !mixercfg_ext2 && !mixercfg_ext3) || + (stage_cfg && !stage_cfg->stage[0][0])) + mixercfg |= CTL_MIXER_BORDER_OUT; + + SDE_REG_WRITE(c, CTL_LAYER(lm), mixercfg); + SDE_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); + SDE_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2); + SDE_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3); +} + +static u32 sde_hw_ctl_get_staged_sspp(struct sde_hw_ctl *ctx, enum sde_lm lm, + struct sde_sspp_index_info *info, u32 info_max_cnt) +{ + int i, j; + u32 count = 0; + u32 mask = 0; + bool staged; + u32 mixercfg[CTL_NUM_EXT]; + struct sde_hw_blk_reg_map *c; + const struct ctl_sspp_stage_reg_map *sspp_cfg; + + if (!ctx || (lm >= LM_MAX) || !info) + return count; + + c = &ctx->hw; + mixercfg[0] = SDE_REG_READ(c, CTL_LAYER(lm)); + mixercfg[1] = SDE_REG_READ(c, CTL_LAYER_EXT(lm)); + mixercfg[2] = SDE_REG_READ(c, CTL_LAYER_EXT2(lm)); + mixercfg[3] = SDE_REG_READ(c, CTL_LAYER_EXT3(lm)); + + for (i = SSPP_VIG0; i < SSPP_MAX; i++) { + for (j = 0; j < CTL_SSPP_MAX_RECTS; j++) { + if (count >= info_max_cnt) + goto end; + + sspp_cfg = &sspp_reg_cfg_tbl[i][j]; + if (!sspp_cfg->bits || sspp_cfg->ext >= CTL_NUM_EXT) + continue; + + mask = ((0x1 << sspp_cfg->bits) - 1) << sspp_cfg->start; + staged = mixercfg[sspp_cfg->ext] & mask; + if (!staged) + staged = mixercfg[1] & sspp_cfg->sec_bit_mask; + + if (staged) { + info[count].sspp = i; + info[count].is_virtual = j; + count++; + } + } + } + +end: + return count; +} + +static int sde_hw_ctl_intf_cfg_v1(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg_v1 *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 intf_active = 0; + u32 wb_active = 0; + u32 merge_3d_active = 0; + u32 cwb_active = 0; + u32 mode_sel = 0; + u32 cdm_active = 0; + u32 intf_master = 0; + u32 i; + + if (!ctx) + return -EINVAL; + + c = &ctx->hw; + for (i = 0; i < cfg->intf_count; i++) { + if (cfg->intf[i]) + intf_active |= BIT(cfg->intf[i] - INTF_0); + } + + if (cfg->intf_count > 1) + intf_master = BIT(cfg->intf_master - INTF_0); + + for (i = 0; i < cfg->wb_count; i++) { + if (cfg->wb[i]) + wb_active |= BIT(cfg->wb[i] - WB_0); + } + + for (i = 0; i < cfg->merge_3d_count; i++) { + if (cfg->merge_3d[i]) + merge_3d_active |= BIT(cfg->merge_3d[i] - MERGE_3D_0); + } + + for (i = 0; i < cfg->cwb_count; i++) { + if (cfg->cwb[i]) + cwb_active |= BIT(cfg->cwb[i] - CWB_0); + } + + for (i = 0; i < cfg->cdm_count; i++) { + if (cfg->cdm[i]) + cdm_active |= BIT(cfg->cdm[i] - CDM_0); + } + + if (cfg->intf_mode_sel == SDE_CTL_MODE_SEL_CMD) + mode_sel |= BIT(17); + + SDE_REG_WRITE(c, CTL_TOP, mode_sel); + SDE_REG_WRITE(c, CTL_WB_ACTIVE, wb_active); + SDE_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active); + SDE_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active); + SDE_REG_WRITE(c, CTL_CDM_ACTIVE, cdm_active); + SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active); + SDE_REG_WRITE(c, CTL_INTF_MASTER, intf_master); + return 0; +} + +static int sde_hw_ctl_reset_post_disable(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg_v1 *cfg, u32 merge_3d_idx) +{ + struct sde_hw_blk_reg_map *c; + u32 intf_active = 0, wb_active = 0, merge_3d_active = 0; + u32 intf_flush = 0, wb_flush = 0; + u32 i; + + if (!ctx || !cfg) { + SDE_ERROR("invalid hw_ctl or hw_intf blk\n"); + return -EINVAL; + } + + c = &ctx->hw; + for (i = 0; i < cfg->intf_count; i++) { + if (cfg->intf[i]) { + intf_active &= ~BIT(cfg->intf[i] - INTF_0); + intf_flush |= BIT(cfg->intf[i] - INTF_0); + } + } + + for (i = 0; i < cfg->wb_count; i++) { + if (cfg->wb[i]) { + wb_active &= ~BIT(cfg->wb[i] - WB_0); + wb_flush |= BIT(cfg->wb[i] - WB_0); + } + } + + if (merge_3d_idx) { + /* disable and flush merge3d_blk */ + ctx->flush.pending_merge_3d_flush_mask = + BIT(merge_3d_idx - MERGE_3D_0); + merge_3d_active &= ~BIT(merge_3d_idx - MERGE_3D_0); + UPDATE_MASK(ctx->flush.pending_flush_mask, MERGE_3D_IDX, 1); + SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active); + } + + sde_hw_ctl_clear_all_blendstages(ctx); + + if (cfg->intf_count) { + ctx->flush.pending_intf_flush_mask = intf_flush; + UPDATE_MASK(ctx->flush.pending_flush_mask, INTF_IDX, 1); + SDE_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active); + } + + if (cfg->wb_count) { + ctx->flush.pending_wb_flush_mask = wb_flush; + UPDATE_MASK(ctx->flush.pending_flush_mask, WB_IDX, 1); + SDE_REG_WRITE(c, CTL_WB_ACTIVE, wb_active); + } + return 0; +} + +static int sde_hw_ctl_update_cwb_cfg(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg_v1 *cfg, bool enable) +{ + int i; + u32 cwb_active = 0; + u32 merge_3d_active = 0; + u32 wb_active = 0; + struct sde_hw_blk_reg_map *c; + + if (!ctx) + return -EINVAL; + + c = &ctx->hw; + cwb_active = SDE_REG_READ(c, CTL_CWB_ACTIVE); + for (i = 0; i < cfg->cwb_count; i++) { + if (cfg->cwb[i]) + cwb_active |= BIT(cfg->cwb[i] - CWB_0); + } + + merge_3d_active = SDE_REG_READ(c, CTL_MERGE_3D_ACTIVE); + for (i = 0; i < cfg->merge_3d_count; i++) { + if (cfg->merge_3d[i]) + merge_3d_active |= BIT(cfg->merge_3d[i] - MERGE_3D_0); + } + + if (enable) { + wb_active = BIT(2); + SDE_REG_WRITE(c, CTL_WB_ACTIVE, wb_active); + SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, merge_3d_active); + SDE_REG_WRITE(c, CTL_CWB_ACTIVE, cwb_active); + } else { + SDE_REG_WRITE(c, CTL_WB_ACTIVE, 0x0); + SDE_REG_WRITE(c, CTL_MERGE_3D_ACTIVE, 0x0); + SDE_REG_WRITE(c, CTL_CWB_ACTIVE, 0x0); + } + return 0; +} + +static int sde_hw_ctl_dsc_cfg(struct sde_hw_ctl *ctx, + struct sde_ctl_dsc_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 dsc_active = 0; + int i; + + if (!ctx) + return -EINVAL; + + c = &ctx->hw; + for (i = 0; i < cfg->dsc_count; i++) + if (cfg->dsc[i]) + dsc_active |= BIT(cfg->dsc[i] - DSC_0); + + SDE_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active); + return 0; +} + +static int sde_hw_ctl_intf_cfg(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 intf_cfg = 0; + + if (!ctx) + return -EINVAL; + + c = &ctx->hw; + intf_cfg |= (cfg->intf & 0xF) << 4; + + if (cfg->wb) + intf_cfg |= (cfg->wb & 0x3) + 2; + + if (cfg->mode_3d) { + intf_cfg |= BIT(19); + intf_cfg |= (cfg->mode_3d - 0x1) << 20; + } + + switch (cfg->intf_mode_sel) { + case SDE_CTL_MODE_SEL_VID: + intf_cfg &= ~BIT(17); + intf_cfg &= ~(0x3 << 15); + break; + case SDE_CTL_MODE_SEL_CMD: + intf_cfg |= BIT(17); + intf_cfg |= ((cfg->stream_sel & 0x3) << 15); + break; + default: + pr_err("unknown interface type %d\n", cfg->intf_mode_sel); + return -EINVAL; + } + + SDE_REG_WRITE(c, CTL_TOP, intf_cfg); + return 0; +} + +static void sde_hw_ctl_update_wb_cfg(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg *cfg, bool enable) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 intf_cfg = 0; + + if (!cfg->wb) + return; + + intf_cfg = SDE_REG_READ(c, CTL_TOP); + if (enable) + intf_cfg |= (cfg->wb & 0x3) + 2; + else + intf_cfg &= ~((cfg->wb & 0x3) + 2); + + SDE_REG_WRITE(c, CTL_TOP, intf_cfg); +} + +static inline u32 sde_hw_ctl_read_ctl_top(struct sde_hw_ctl *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 ctl_top; + + if (!ctx) { + pr_err("Invalid input argument\n"); + return 0; + } + c = &ctx->hw; + ctl_top = SDE_REG_READ(c, CTL_TOP); + return ctl_top; +} + +static inline u32 sde_hw_ctl_read_ctl_layers(struct sde_hw_ctl *ctx, int index) +{ + struct sde_hw_blk_reg_map *c; + u32 ctl_top; + + if (!ctx) { + pr_err("Invalid input argument\n"); + return 0; + } + c = &ctx->hw; + ctl_top = SDE_REG_READ(c, CTL_LAYER(index)); + pr_debug("Ctl_layer value = 0x%x\n", ctl_top); + return ctl_top; +} + +static int sde_hw_reg_dma_flush(struct sde_hw_ctl *ctx, bool blocking) +{ + struct sde_hw_reg_dma_ops *ops = sde_reg_dma_get_ops(); + + if (!ctx) + return -EINVAL; + + if (ops && ops->last_command) + return ops->last_command(ctx, DMA_CTL_QUEUE0, + (blocking ? REG_DMA_WAIT4_COMP : REG_DMA_NOWAIT)); + + return 0; + +} + +static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, + unsigned long cap) +{ + if (cap & BIT(SDE_CTL_ACTIVE_CFG)) { + ops->update_pending_flush = + sde_hw_ctl_update_pending_flush_v1; + ops->trigger_flush = sde_hw_ctl_trigger_flush_v1; + + ops->setup_intf_cfg_v1 = sde_hw_ctl_intf_cfg_v1; + ops->update_cwb_cfg = sde_hw_ctl_update_cwb_cfg; + ops->setup_dsc_cfg = sde_hw_ctl_dsc_cfg; + + ops->update_bitmask_cdm = sde_hw_ctl_update_bitmask_cdm_v1; + ops->update_bitmask_wb = sde_hw_ctl_update_bitmask_wb_v1; + ops->update_bitmask_intf = sde_hw_ctl_update_bitmask_intf_v1; + ops->update_bitmask_dsc = sde_hw_ctl_update_bitmask_dsc_v1; + ops->update_bitmask_merge3d = + sde_hw_ctl_update_bitmask_merge3d_v1; + ops->update_bitmask_cwb = sde_hw_ctl_update_bitmask_cwb_v1; + ops->update_bitmask_periph = + sde_hw_ctl_update_bitmask_periph_v1; + ops->get_ctl_intf = sde_hw_ctl_get_intf_v1; + ops->reset_post_disable = sde_hw_ctl_reset_post_disable; + ops->get_scheduler_status = sde_hw_ctl_get_scheduler_status; + } else { + ops->update_pending_flush = sde_hw_ctl_update_pending_flush; + ops->trigger_flush = sde_hw_ctl_trigger_flush; + + ops->setup_intf_cfg = sde_hw_ctl_intf_cfg; + + ops->update_bitmask_cdm = sde_hw_ctl_update_bitmask_cdm; + ops->update_bitmask_wb = sde_hw_ctl_update_bitmask_wb; + ops->update_bitmask_intf = sde_hw_ctl_update_bitmask_intf; + ops->get_ctl_intf = sde_hw_ctl_get_intf; + } + ops->clear_pending_flush = sde_hw_ctl_clear_pending_flush; + ops->get_pending_flush = sde_hw_ctl_get_pending_flush; + ops->get_flush_register = sde_hw_ctl_get_flush_register; + ops->trigger_start = sde_hw_ctl_trigger_start; + ops->trigger_pending = sde_hw_ctl_trigger_pending; + ops->read_ctl_top = sde_hw_ctl_read_ctl_top; + ops->read_ctl_layers = sde_hw_ctl_read_ctl_layers; + ops->update_wb_cfg = sde_hw_ctl_update_wb_cfg; + ops->reset = sde_hw_ctl_reset_control; + ops->get_reset = sde_hw_ctl_get_reset_status; + ops->hard_reset = sde_hw_ctl_hard_reset; + ops->wait_reset_status = sde_hw_ctl_wait_reset_status; + ops->clear_all_blendstages = sde_hw_ctl_clear_all_blendstages; + ops->setup_blendstage = sde_hw_ctl_setup_blendstage; + ops->get_staged_sspp = sde_hw_ctl_get_staged_sspp; + ops->update_bitmask_sspp = sde_hw_ctl_update_bitmask_sspp; + ops->update_bitmask_mixer = sde_hw_ctl_update_bitmask_mixer; + ops->update_bitmask_dspp = sde_hw_ctl_update_bitmask_dspp; + ops->update_bitmask_dspp_pavlut = sde_hw_ctl_update_bitmask_dspp_pavlut; + ops->reg_dma_flush = sde_hw_reg_dma_flush; + ops->get_start_state = sde_hw_ctl_get_start_state; + + if (cap & BIT(SDE_CTL_UIDLE)) + ops->uidle_enable = sde_hw_ctl_uidle_enable; +}; + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_ctl *c; + struct sde_ctl_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _ctl_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + pr_err("failed to create sde_hw_ctl %d\n", idx); + return ERR_PTR(-EINVAL); + } + + c->caps = cfg; + _setup_ctl_ops(&c->ops, c->caps->features); + c->idx = idx; + c->mixer_count = m->mixer_count; + c->mixer_hw_caps = m->mixer; + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CTL, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx) +{ + if (ctx) + sde_hw_blk_destroy(&ctx->base); + kfree(ctx); +} diff --git a/techpack/display/msm/sde/sde_hw_ctl.h b/techpack/display/msm/sde/sde_hw_ctl.h new file mode 100644 index 0000000000000000000000000000000000000000..0c90f1156232b3f4804aaa2913364e2e85c1d080 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_ctl.h @@ -0,0 +1,534 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_CTL_H +#define _SDE_HW_CTL_H + +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_catalog.h" +#include "sde_hw_sspp.h" +#include "sde_hw_blk.h" + +#define INVALID_CTL_STATUS 0xfffff88e + +/** + * sde_ctl_mode_sel: Interface mode selection + * SDE_CTL_MODE_SEL_VID: Video mode interface + * SDE_CTL_MODE_SEL_CMD: Command mode interface + */ +enum sde_ctl_mode_sel { + SDE_CTL_MODE_SEL_VID = 0, + SDE_CTL_MODE_SEL_CMD +}; + +/** + * sde_ctl_rot_op_mode - inline rotation mode + * SDE_CTL_ROT_OP_MODE_OFFLINE: offline rotation + * SDE_CTL_ROT_OP_MODE_RESERVED: reserved + * SDE_CTL_ROT_OP_MODE_INLINE_SYNC: inline rotation synchronous mode + * SDE_CTL_ROT_OP_MODE_INLINE_ASYNC: inline rotation asynchronous mode + */ +enum sde_ctl_rot_op_mode { + SDE_CTL_ROT_OP_MODE_OFFLINE, + SDE_CTL_ROT_OP_MODE_RESERVED, + SDE_CTL_ROT_OP_MODE_INLINE_SYNC, + SDE_CTL_ROT_OP_MODE_INLINE_ASYNC, +}; + +struct sde_hw_ctl; +/** + * struct sde_hw_stage_cfg - blending stage cfg + * @stage : SSPP_ID at each stage + * @multirect_index: index of the rectangle of SSPP. + */ +struct sde_hw_stage_cfg { + enum sde_sspp stage[SDE_STAGE_MAX][PIPES_PER_STAGE]; + enum sde_sspp_multirect_index multirect_index + [SDE_STAGE_MAX][PIPES_PER_STAGE]; +}; + +/** + * struct sde_hw_intf_cfg :Describes how the SDE writes data to output interface + * @intf : Interface id + * @wb: Writeback id + * @mode_3d: 3d mux configuration + * @intf_mode_sel: Interface mode, cmd / vid + * @stream_sel: Stream selection for multi-stream interfaces + */ +struct sde_hw_intf_cfg { + enum sde_intf intf; + enum sde_wb wb; + enum sde_3d_blend_mode mode_3d; + enum sde_ctl_mode_sel intf_mode_sel; + int stream_sel; +}; + +/** + * struct sde_hw_intf_cfg_v1 :Describes the data strcuture to configure the + * output interfaces for a particular display on a + * platform which supports ctl path version 1. + * @intf_count: No. of active interfaces for this display + * @intf : Interface ids of active interfaces + * @intf_mode_sel: Interface mode, cmd / vid + * @intf_master: Master interface for split display + * @wb_count: No. of active writebacks + * @wb: Writeback ids of active writebacks + * @merge_3d_count No. of active merge_3d blocks + * @merge_3d: Id of the active merge 3d blocks + * @cwb_count: No. of active concurrent writebacks + * @cwb: Id of active cwb blocks + * @cdm_count: No. of active chroma down module + * @cdm: Id of active cdm blocks + */ +struct sde_hw_intf_cfg_v1 { + uint32_t intf_count; + enum sde_intf intf[MAX_INTF_PER_CTL_V1]; + enum sde_ctl_mode_sel intf_mode_sel; + enum sde_intf intf_master; + + uint32_t wb_count; + enum sde_wb wb[MAX_WB_PER_CTL_V1]; + + uint32_t merge_3d_count; + enum sde_merge_3d merge_3d[MAX_MERGE_3D_PER_CTL_V1]; + + uint32_t cwb_count; + enum sde_cwb cwb[MAX_CWB_PER_CTL_V1]; + + uint32_t cdm_count; + enum sde_cdm cdm[MAX_CDM_PER_CTL_V1]; +}; + +/** + * struct sde_hw_ctl_dsc_cfg :Describes the DSC blocks being used for this + * display on a platoform which supports ctl path + * version 1. + * @dsc_count: No. of active dsc blocks + * @dsc: Id of active dsc blocks + */ +struct sde_ctl_dsc_cfg { + uint32_t dsc_count; + enum sde_dsc dsc[MAX_DSC_PER_CTL_V1]; +}; + +/** + * struct sde_ctl_flush_cfg - struct describing flush configuration managed + * via set, trigger and clear ops. + * set ops corresponding to the hw_block is called, when the block's + * configuration is changed and needs to be committed on Hw. Flush mask caches + * the different bits for the ongoing commit. + * clear ops clears the bitmask and cancels the update to the corresponding + * hw block. + * trigger op will trigger the update on the hw for the blocks cached in the + * pending flush mask. + * + * @pending_flush_mask: pending ctl_flush + * CTL path version SDE_CTL_CFG_VERSION_1_0_0 has * two level flush mechanism + * for lower pipe controls. individual control should be flushed before + * exercising top level flush + * @pending_intf_flush_mask: pending INTF flush + * @pending_cdm_flush_mask: pending CDWN block flush + * @pending_wb_flush_mask: pending writeback flush + * @pending_dsc_flush_mask: pending dsc flush + * @pending_merge_3d_flush_mask: pending 3d merge block flush + * @pending_cwb_flush_mask: pending flush for concurrent writeback + * @pending_periph_flush_mask: pending flush for peripheral module + */ +struct sde_ctl_flush_cfg { + u32 pending_flush_mask; + u32 pending_intf_flush_mask; + u32 pending_cdm_flush_mask; + u32 pending_wb_flush_mask; + u32 pending_dsc_flush_mask; + u32 pending_merge_3d_flush_mask; + u32 pending_cwb_flush_mask; + u32 pending_periph_flush_mask; +}; + +/** + * struct sde_hw_ctl_ops - Interface to the wb Hw driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_ctl_ops { + /** + * kickoff hw operation for Sw controlled interfaces + * DSI cmd mode and WB interface are SW controlled + * @ctx : ctl path ctx pointer + * @Return: error code + */ + int (*trigger_start)(struct sde_hw_ctl *ctx); + + /** + * kickoff prepare is in progress hw operation for sw + * controlled interfaces: DSI cmd mode and WB interface + * are SW controlled + * @ctx : ctl path ctx pointer + * @Return: error code + */ + int (*trigger_pending)(struct sde_hw_ctl *ctx); + + /** + * kickoff rotator operation for Sw controlled interfaces + * DSI cmd mode and WB interface are SW controlled + * @ctx : ctl path ctx pointer + * @Return: error code + */ + int (*trigger_rot_start)(struct sde_hw_ctl *ctx); + + /** + * enable/disable UIDLE feature + * @ctx : ctl path ctx pointer + * @enable: true to enable the feature + */ + void (*uidle_enable)(struct sde_hw_ctl *ctx, bool enable); + + /** + * Clear the value of the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @Return: error code + */ + int (*clear_pending_flush)(struct sde_hw_ctl *ctx); + + /** + * Query the value of the cached pending_flush_mask + * No effect on hardware + * @ctx : ctl path ctx pointer + * @cfg : current flush configuration + * @Return: error code + */ + int (*get_pending_flush)(struct sde_hw_ctl *ctx, + struct sde_ctl_flush_cfg *cfg); + + /** + * OR in the given flushbits to the flush_cfg + * No effect on hardware + * @ctx : ctl path ctx pointer + * @cfg : flush configuration pointer + * @Return: error code + */ + int (*update_pending_flush)(struct sde_hw_ctl *ctx, + struct sde_ctl_flush_cfg *cfg); + + /** + * Write the value of the pending_flush_mask to hardware + * @ctx : ctl path ctx pointer + * @Return: error code + */ + int (*trigger_flush)(struct sde_hw_ctl *ctx); + + /** + * Read the value of the flush register + * @ctx : ctl path ctx pointer + * @Return: value of the ctl flush register. + */ + u32 (*get_flush_register)(struct sde_hw_ctl *ctx); + + /** + * Setup ctl_path interface config + * @ctx + * @cfg : interface config structure pointer + * @Return: error code + */ + int (*setup_intf_cfg)(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg *cfg); + + /** + * Reset ctl_path interface config + * @ctx : ctl path ctx pointer + * @cfg : interface config structure pointer + * @merge_3d_idx : index of merge3d blk + * @Return: error code + */ + int (*reset_post_disable)(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg_v1 *cfg, u32 merge_3d_idx); + + /** update cwb for ctl_path + * @ctx : ctl path ctx pointer + * @cfg : interface config structure pointer + * @enable : enable/disable the cwb hw block + * @Return: error code + */ + int (*update_cwb_cfg)(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg_v1 *cfg, bool enable); + + /** + * Setup ctl_path interface config for SDE_CTL_ACTIVE_CFG + * @ctx : ctl path ctx pointer + * @cfg : interface config structure pointer + * @Return: error code + */ + int (*setup_intf_cfg_v1)(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg_v1 *cfg); + + /** + * Setup ctl_path dsc config for SDE_CTL_ACTIVE_CFG + * @ctx : ctl path ctx pointer + * @cfg : dsc config structure pointer + * @Return: error code + */ + int (*setup_dsc_cfg)(struct sde_hw_ctl *ctx, + struct sde_ctl_dsc_cfg *cfg); + + /** Update the interface selection with input WB config + * @ctx : ctl path ctx pointer + * @cfg : pointer to input wb config + * @enable : set if true, clear otherwise + */ + void (*update_wb_cfg)(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg *cfg, bool enable); + + int (*reset)(struct sde_hw_ctl *c); + + /** + * get_reset - check ctl reset status bit + * @ctx : ctl path ctx pointer + * Returns: current value of ctl reset status + */ + u32 (*get_reset)(struct sde_hw_ctl *ctx); + + /** + * get_scheduler_reset - check ctl scheduler status bit + * @ctx : ctl path ctx pointer + * Returns: current value of ctl scheduler and idle status + */ + u32 (*get_scheduler_status)(struct sde_hw_ctl *ctx); + + /** + * hard_reset - force reset on ctl_path + * @ctx : ctl path ctx pointer + * @enable : whether to enable/disable hard reset + */ + void (*hard_reset)(struct sde_hw_ctl *c, bool enable); + + /* + * wait_reset_status - checks ctl reset status + * @ctx : ctl path ctx pointer + * + * This function checks the ctl reset status bit. + * If the reset bit is set, it keeps polling the status till the hw + * reset is complete. + * Returns: 0 on success or -error if reset incomplete within interval + */ + int (*wait_reset_status)(struct sde_hw_ctl *ctx); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_sspp)(struct sde_hw_ctl *ctx, + enum sde_sspp blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_mixer)(struct sde_hw_ctl *ctx, + enum sde_lm blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_dspp)(struct sde_hw_ctl *ctx, + enum sde_dspp blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_dspp_pavlut)(struct sde_hw_ctl *ctx, + enum sde_dspp blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_intf)(struct sde_hw_ctl *ctx, + enum sde_intf blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_cdm)(struct sde_hw_ctl *ctx, + enum sde_cdm blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_wb)(struct sde_hw_ctl *ctx, + enum sde_wb blk, bool enable); + + /** + * update_bitmask_sspp: updates mask corresponding to sspp + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_rot)(struct sde_hw_ctl *ctx, + enum sde_rot blk, bool enable); + + /** + * update_bitmask_dsc: updates mask corresponding to dsc + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_dsc)(struct sde_hw_ctl *ctx, + enum sde_dsc blk, bool enable); + + /** + * update_bitmask_merge3d: updates mask corresponding to merge_3d + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_merge3d)(struct sde_hw_ctl *ctx, + enum sde_merge_3d blk, bool enable); + + /** + * update_bitmask_cwb: updates mask corresponding to cwb + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_cwb)(struct sde_hw_ctl *ctx, + enum sde_cwb blk, bool enable); + + /** + * update_bitmask_periph: updates mask corresponding to peripheral + * @blk : blk id + * @enable : true to enable, 0 to disable + */ + int (*update_bitmask_periph)(struct sde_hw_ctl *ctx, + enum sde_intf blk, bool enable); + + /** + * read CTL_TOP register value and return + * the data. + * @ctx : ctl path ctx pointer + * @return : CTL top register value + */ + u32 (*read_ctl_top)(struct sde_hw_ctl *ctx); + + /** + * get interfaces for the active CTL . + * @ctx : ctl path ctx pointer + * @return : bit mask with the active interfaces for the CTL + */ + u32 (*get_ctl_intf)(struct sde_hw_ctl *ctx); + + /** + * read CTL layers register value and return + * the data. + * @ctx : ctl path ctx pointer + * @index : layer index for this ctl path + * @return : CTL layers register value + */ + u32 (*read_ctl_layers)(struct sde_hw_ctl *ctx, int index); + + /** + * Set all blend stages to disabled + * @ctx : ctl path ctx pointer + */ + void (*clear_all_blendstages)(struct sde_hw_ctl *ctx); + + /** + * Configure layer mixer to pipe configuration + * @ctx : ctl path ctx pointer + * @lm : layer mixer enumeration + * @cfg : blend stage configuration + */ + void (*setup_blendstage)(struct sde_hw_ctl *ctx, + enum sde_lm lm, struct sde_hw_stage_cfg *cfg); + + /** + * Get all the sspp staged on a layer mixer + * @ctx : ctl path ctx pointer + * @lm : layer mixer enumeration + * @info : array address to populate connected sspp index info + * @info_max_cnt : maximum sspp info elements based on array size + * @Return: count of sspps info elements populated + */ + u32 (*get_staged_sspp)(struct sde_hw_ctl *ctx, enum sde_lm lm, + struct sde_sspp_index_info *info, u32 info_max_cnt); + + /** + * Flush the reg dma by sending last command. + * @ctx : ctl path ctx pointer + * @blocking : if set to true api will block until flush is done + * @Return: error code + */ + int (*reg_dma_flush)(struct sde_hw_ctl *ctx, bool blocking); + + /** + * check if ctl start trigger state to confirm the frame pending + * status + * @ctx : ctl path ctx pointer + * @Return: error code + */ + int (*get_start_state)(struct sde_hw_ctl *ctx); +}; + +/** + * struct sde_hw_ctl : CTL PATH driver object + * @base: hardware block base structure + * @hw: block register map object + * @idx: control path index + * @caps: control path capabilities + * @mixer_count: number of mixers + * @mixer_hw_caps: mixer hardware capabilities + * @flush: storage for pending ctl_flush managed via ops + * @ops: operation list + */ +struct sde_hw_ctl { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* ctl path */ + int idx; + const struct sde_ctl_cfg *caps; + int mixer_count; + const struct sde_lm_cfg *mixer_hw_caps; + struct sde_ctl_flush_cfg flush; + + /* ops */ + struct sde_hw_ctl_ops ops; +}; + +/** + * sde_hw_ctl - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_ctl *to_sde_hw_ctl(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_ctl, base); +} + +/** + * sde_hw_ctl_init(): Initializes the ctl_path hw driver object. + * should be called before accessing every ctl path registers. + * @idx: ctl_path index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct sde_hw_ctl *sde_hw_ctl_init(enum sde_ctl idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_ctl_destroy(): Destroys ctl driver context + * should be called to free the context + */ +void sde_hw_ctl_destroy(struct sde_hw_ctl *ctx); + +#endif /*_SDE_HW_CTL_H */ diff --git a/techpack/display/msm/sde/sde_hw_ds.c b/techpack/display/msm/sde/sde_hw_ds.c new file mode 100644 index 0000000000000000000000000000000000000000..0dc1cbf8a3a654a20bccb746849856a67bc1df15 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_ds.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_ds.h" +#include "sde_formats.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +/* Destination scaler TOP registers */ +#define DEST_SCALER_OP_MODE 0x00 +#define DEST_SCALER_HW_VERSION 0x10 + +static void sde_hw_ds_setup_opmode(struct sde_hw_ds *hw_ds, + u32 op_mode) +{ + struct sde_hw_blk_reg_map *hw = &hw_ds->hw; + + SDE_REG_WRITE(hw, DEST_SCALER_OP_MODE, op_mode); +} + +static u32 _sde_hw_ds_get_scaler3_ver(struct sde_hw_ds *ctx) +{ + if (!ctx) + return 0; + + return sde_hw_get_scaler3_ver(&ctx->hw, ctx->scl->base); +} + +static void sde_hw_ds_setup_scaler3(struct sde_hw_ds *hw_ds, + void *scaler_cfg, void *scaler_lut_cfg) +{ + struct sde_hw_scaler3_cfg *scl3_cfg = scaler_cfg; + struct sde_hw_scaler3_lut_cfg *scl3_lut_cfg = scaler_lut_cfg; + + if (!hw_ds || !hw_ds->scl || !scl3_cfg || !scl3_lut_cfg) + return; + + /* + * copy LUT values to scaler structure + */ + if (scl3_lut_cfg->is_configured) { + scl3_cfg->dir_lut = scl3_lut_cfg->dir_lut; + scl3_cfg->dir_len = scl3_lut_cfg->dir_len; + scl3_cfg->cir_lut = scl3_lut_cfg->cir_lut; + scl3_cfg->cir_len = scl3_lut_cfg->cir_len; + scl3_cfg->sep_lut = scl3_lut_cfg->sep_lut; + scl3_cfg->sep_len = scl3_lut_cfg->sep_len; + } + + sde_hw_setup_scaler3(&hw_ds->hw, scl3_cfg, hw_ds->scl->version, + hw_ds->scl->base, + sde_get_sde_format(DRM_FORMAT_XBGR2101010)); +} + +static void _setup_ds_ops(struct sde_hw_ds_ops *ops, unsigned long features) +{ + ops->setup_opmode = sde_hw_ds_setup_opmode; + + if (test_bit(SDE_SSPP_SCALER_QSEED3, &features) || + test_bit(SDE_SSPP_SCALER_QSEED3LITE, &features)) { + ops->get_scaler_ver = _sde_hw_ds_get_scaler3_ver; + ops->setup_scaler = sde_hw_ds_setup_scaler3; + } +} + +static struct sde_ds_cfg *_ds_offset(enum sde_ds ds, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + if (!m || !addr || !b) + return ERR_PTR(-EINVAL); + + for (i = 0; i < m->ds_count; i++) { + if ((ds == m->ds[i].id) && + (m->ds[i].top)) { + b->base_off = addr; + b->blk_off = m->ds[i].top->base; + b->length = m->ds[i].top->len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_DS; + return &m->ds[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_ds *sde_hw_ds_init(enum sde_ds idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_ds *hw_ds; + struct sde_ds_cfg *cfg; + int rc; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + + hw_ds = kzalloc(sizeof(*hw_ds), GFP_KERNEL); + if (!hw_ds) + return ERR_PTR(-ENOMEM); + + cfg = _ds_offset(idx, m, addr, &hw_ds->hw); + if (IS_ERR_OR_NULL(cfg)) { + SDE_ERROR("failed to get ds cfg\n"); + kfree(hw_ds); + return ERR_PTR(-EINVAL); + } + + /* Assign ops */ + hw_ds->idx = idx; + hw_ds->scl = cfg; + _setup_ds_ops(&hw_ds->ops, hw_ds->scl->features); + + if (hw_ds->ops.get_scaler_ver) + hw_ds->scl->version = hw_ds->ops.get_scaler_ver(hw_ds); + + + rc = sde_hw_blk_init(&hw_ds->base, SDE_HW_BLK_DS, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + if (cfg->len) { + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, + hw_ds->hw.blk_off + cfg->base, + hw_ds->hw.blk_off + cfg->base + cfg->len, + hw_ds->hw.xin_id); + } + + return hw_ds; + +blk_init_error: + kzfree(hw_ds); + + return ERR_PTR(rc); + +} + +void sde_hw_ds_destroy(struct sde_hw_ds *hw_ds) +{ + if (hw_ds) + sde_hw_blk_destroy(&hw_ds->base); + kfree(hw_ds); +} diff --git a/techpack/display/msm/sde/sde_hw_ds.h b/techpack/display/msm/sde/sde_hw_ds.h new file mode 100644 index 0000000000000000000000000000000000000000..e5b0ab899703b18f46763ad7a1e087c9d9b8b65f --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_ds.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_DS_H +#define _SDE_HW_DS_H + +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_catalog.h" +#include "sde_hw_blk.h" + +struct sde_hw_ds; + +/* Destination Scaler DUAL mode overfetch pixel count */ +#define SDE_DS_OVERFETCH_SIZE 5 + +/* Destination scaler DUAL mode operation bit */ +#define SDE_DS_OP_MODE_DUAL BIT(16) + +/* struct sde_hw_ds_cfg - destination scaler config + * @idx : DS selection index + * @flags : Flag to switch between mode for DS + * @lm_width : Layer mixer width configuration + * @lm_heigh : Layer mixer height configuration + * @scl3_cfg : Configuration data for scaler + */ +struct sde_hw_ds_cfg { + u32 idx; + int flags; + u32 lm_width; + u32 lm_height; + struct sde_hw_scaler3_cfg scl3_cfg; +}; + +/** + * struct sde_hw_ds_ops - interface to the destination scaler + * hardware driver functions + * Caller must call the init function to get the ds context for each ds + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_ds_ops { + /** + * setup_opmode - destination scaler op mode setup + * @hw_ds : Pointer to ds context + * @op_mode : Op mode configuration + */ + void (*setup_opmode)(struct sde_hw_ds *hw_ds, + u32 op_mode); + + /** + * setup_scaler - destination scaler block setup + * @hw_ds : Pointer to ds context + * @scaler_cfg : Pointer to scaler data + * @scaler_lut_cfg : Pointer to scaler lut + */ + void (*setup_scaler)(struct sde_hw_ds *hw_ds, + void *scaler_cfg, + void *scaler_lut_cfg); + + /** + * get_scaler_ver - get scaler h/w version + * @ctx: Pointer to ds structure + */ + u32 (*get_scaler_ver)(struct sde_hw_ds *ctx); + +}; + +/** + * struct sde_hw_ds - destination scaler description + * @base : Hardware block base structure + * @hw : Block hardware details + * @idx : Destination scaler index + * @scl : Pointer to + * - scaler offset relative to top offset + * - capabilities + * @ops : Pointer to operations for this DS + */ +struct sde_hw_ds { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + enum sde_ds idx; + struct sde_ds_cfg *scl; + struct sde_hw_ds_ops ops; +}; + +/** + * sde_hw_ds_init - initializes the destination scaler + * hw driver object and should be called once before + * accessing every destination scaler + * @idx : DS index for which driver object is required + * @addr: Mapped register io address of MDP + * @m : MDSS catalog information + * @Return: pointer to structure or ERR_PTR + */ +struct sde_hw_ds *sde_hw_ds_init(enum sde_ds idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_ds_destroy - destroys destination scaler + * driver context + * @hw_ds: Pointer to DS context + */ +void sde_hw_ds_destroy(struct sde_hw_ds *hw_ds); + +#endif /*_SDE_HW_DS_H */ diff --git a/techpack/display/msm/sde/sde_hw_dsc.c b/techpack/display/msm/sde/sde_hw_dsc.c new file mode 100644 index 0000000000000000000000000000000000000000..1e07b470c19a18c1b11dc6ef126a06b49be69a35 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_dsc.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_mdss.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_dsc.h" +#include "sde_hw_pingpong.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define DSC_COMMON_MODE 0x000 +#define DSC_ENC 0X004 +#define DSC_PICTURE 0x008 +#define DSC_SLICE 0x00C +#define DSC_CHUNK_SIZE 0x010 +#define DSC_DELAY 0x014 +#define DSC_SCALE_INITIAL 0x018 +#define DSC_SCALE_DEC_INTERVAL 0x01C +#define DSC_SCALE_INC_INTERVAL 0x020 +#define DSC_FIRST_LINE_BPG_OFFSET 0x024 +#define DSC_BPG_OFFSET 0x028 +#define DSC_DSC_OFFSET 0x02C +#define DSC_FLATNESS 0x030 +#define DSC_RC_MODEL_SIZE 0x034 +#define DSC_RC 0x038 +#define DSC_RC_BUF_THRESH 0x03C +#define DSC_RANGE_MIN_QP 0x074 +#define DSC_RANGE_MAX_QP 0x0B0 +#define DSC_RANGE_BPG_OFFSET 0x0EC + +#define DSC_CTL_BLOCK_SIZE 0x300 +#define DSC_CTL(m) \ + (((m == DSC_NONE) || (m >= DSC_MAX)) ? 0 : (0x1800 - 0x3FC * (m - 1))) + +static void sde_hw_dsc_disable(struct sde_hw_dsc *dsc) +{ + struct sde_hw_blk_reg_map *dsc_c = &dsc->hw; + + SDE_REG_WRITE(dsc_c, DSC_COMMON_MODE, 0); +} + +static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc, + struct msm_display_dsc_info *dsc, u32 mode, + bool ich_reset_override) +{ + u32 data; + u32 initial_lines = dsc->initial_lines; + struct sde_hw_blk_reg_map *dsc_c = &hw_dsc->hw; + + SDE_REG_WRITE(dsc_c, DSC_COMMON_MODE, mode); + + data = 0; + if (ich_reset_override) + data = 3 << 28; + + data |= (initial_lines << 20); + data |= (dsc->slice_last_group_size << 18); + data |= (dsc->bpp << 12); + data |= (dsc->block_pred_enable << 7); + data |= (dsc->line_buf_depth << 3); + data |= (dsc->enable_422 << 2); + data |= (dsc->convert_rgb << 1); + data |= dsc->input_10_bits; + + SDE_REG_WRITE(dsc_c, DSC_ENC, data); + + data = dsc->pic_width << 16; + data |= dsc->pic_height; + SDE_REG_WRITE(dsc_c, DSC_PICTURE, data); + + data = dsc->slice_width << 16; + data |= dsc->slice_height; + SDE_REG_WRITE(dsc_c, DSC_SLICE, data); + + data = dsc->chunk_size << 16; + SDE_REG_WRITE(dsc_c, DSC_CHUNK_SIZE, data); + + data = dsc->initial_dec_delay << 16; + data |= dsc->initial_xmit_delay; + SDE_REG_WRITE(dsc_c, DSC_DELAY, data); + + data = dsc->initial_scale_value; + SDE_REG_WRITE(dsc_c, DSC_SCALE_INITIAL, data); + + data = dsc->scale_decrement_interval; + SDE_REG_WRITE(dsc_c, DSC_SCALE_DEC_INTERVAL, data); + + data = dsc->scale_increment_interval; + SDE_REG_WRITE(dsc_c, DSC_SCALE_INC_INTERVAL, data); + + data = dsc->first_line_bpg_offset; + SDE_REG_WRITE(dsc_c, DSC_FIRST_LINE_BPG_OFFSET, data); + + data = dsc->nfl_bpg_offset << 16; + data |= dsc->slice_bpg_offset; + SDE_REG_WRITE(dsc_c, DSC_BPG_OFFSET, data); + + data = dsc->initial_offset << 16; + data |= dsc->final_offset; + SDE_REG_WRITE(dsc_c, DSC_DSC_OFFSET, data); + + data = dsc->det_thresh_flatness << 10; + data |= dsc->max_qp_flatness << 5; + data |= dsc->min_qp_flatness; + SDE_REG_WRITE(dsc_c, DSC_FLATNESS, data); + + data = dsc->rc_model_size; + SDE_REG_WRITE(dsc_c, DSC_RC_MODEL_SIZE, data); + + data = dsc->tgt_offset_lo << 18; + data |= dsc->tgt_offset_hi << 14; + data |= dsc->quant_incr_limit1 << 9; + data |= dsc->quant_incr_limit0 << 4; + data |= dsc->edge_factor; + SDE_REG_WRITE(dsc_c, DSC_RC, data); +} + +static void sde_hw_dsc_config_thresh(struct sde_hw_dsc *hw_dsc, + struct msm_display_dsc_info *dsc) +{ + u32 *lp; + char *cp; + int i; + + struct sde_hw_blk_reg_map *dsc_c = &hw_dsc->hw; + u32 off = 0x0; + + lp = dsc->buf_thresh; + off = DSC_RC_BUF_THRESH; + for (i = 0; i < 14; i++) { + SDE_REG_WRITE(dsc_c, off, *lp++); + off += 4; + } + + cp = dsc->range_min_qp; + off = DSC_RANGE_MIN_QP; + for (i = 0; i < 15; i++) { + SDE_REG_WRITE(dsc_c, off, *cp++); + off += 4; + } + + cp = dsc->range_max_qp; + off = DSC_RANGE_MAX_QP; + for (i = 0; i < 15; i++) { + SDE_REG_WRITE(dsc_c, off, *cp++); + off += 4; + } + + cp = dsc->range_bpg_offset; + off = DSC_RANGE_BPG_OFFSET; + for (i = 0; i < 15; i++) { + SDE_REG_WRITE(dsc_c, off, *cp++); + off += 4; + } +} + +static void sde_hw_dsc_bind_pingpong_blk( + struct sde_hw_dsc *hw_dsc, + bool enable, + const enum sde_pingpong pp) +{ + struct sde_hw_blk_reg_map *c; + int mux_cfg = 0xF; + u32 dsc_ctl_offset; + + if (!hw_dsc) + return; + + c = &hw_dsc->hw; + dsc_ctl_offset = DSC_CTL(hw_dsc->idx); + + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0x7; + + if (dsc_ctl_offset) + SDE_REG_WRITE(c, dsc_ctl_offset, mux_cfg); +} + + +static struct sde_dsc_cfg *_dsc_offset(enum sde_dsc dsc, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->dsc_count; i++) { + if (dsc == m->dsc[i].id) { + b->base_off = addr; + b->blk_off = m->dsc[i].base; + b->length = m->dsc[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_DSC; + return &m->dsc[i]; + } + } + + return NULL; +} + +static void _setup_dsc_ops(struct sde_hw_dsc_ops *ops, + unsigned long features) +{ + ops->dsc_disable = sde_hw_dsc_disable; + ops->dsc_config = sde_hw_dsc_config; + ops->dsc_config_thresh = sde_hw_dsc_config_thresh; + if (test_bit(SDE_DSC_OUTPUT_CTRL, &features)) + ops->bind_pingpong_blk = sde_hw_dsc_bind_pingpong_blk; +}; + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_dsc *sde_hw_dsc_init(enum sde_dsc idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_dsc *c; + struct sde_dsc_cfg *cfg; + u32 dsc_ctl_offset; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _dsc_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + _setup_dsc_ops(&c->ops, c->caps->features); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_DSC, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + if ((c->idx == DSC_0) && + test_bit(SDE_DSC_OUTPUT_CTRL, &cfg->features)) { + dsc_ctl_offset = DSC_CTL(c->idx); + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "dsc_ctl", + c->hw.blk_off + dsc_ctl_offset, + c->hw.blk_off + dsc_ctl_offset + DSC_CTL_BLOCK_SIZE, + c->hw.xin_id); + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_dsc_destroy(struct sde_hw_dsc *dsc) +{ + if (dsc) + sde_hw_blk_destroy(&dsc->base); + kfree(dsc); +} diff --git a/techpack/display/msm/sde/sde_hw_dsc.h b/techpack/display/msm/sde/sde_hw_dsc.h new file mode 100644 index 0000000000000000000000000000000000000000..33987c146537b4f0a0818f80cd4b0f7607b73d96 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_dsc.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_DSC_H +#define _SDE_HW_DSC_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_blk.h" + +struct sde_hw_dsc; +struct msm_display_dsc_info; + +#define DSC_MODE_SPLIT_PANEL BIT(0) +#define DSC_MODE_MULTIPLEX BIT(1) +#define DSC_MODE_VIDEO BIT(2) + +/** + * struct sde_hw_dsc_ops - interface to the dsc hardware driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_dsc_ops { + /** + * dsc_disable - disable dsc + * @hw_dsc: Pointer to dsc context + */ + void (*dsc_disable)(struct sde_hw_dsc *hw_dsc); + + /** + * dsc_config - configures dsc encoder + * @hw_dsc: Pointer to dsc context + * @dsc: panel dsc parameters + * @mode: dsc topology mode to be set + * @ich_reset_override: option to reset ich + */ + void (*dsc_config)(struct sde_hw_dsc *hw_dsc, + struct msm_display_dsc_info *dsc, + u32 mode, bool ich_reset_override); + + /** + * dsc_config_thresh - programs panel thresholds + * @hw_dsc: Pointer to dsc context + * @dsc: panel dsc parameters + */ + void (*dsc_config_thresh)(struct sde_hw_dsc *hw_dsc, + struct msm_display_dsc_info *dsc); + + /** + * bind_pingpong_blk - enable/disable the connection with pp + * @hw_dsc: Pointer to dsc context + * @enable: enable/disable connection + * @pp: pingpong blk id + */ + void (*bind_pingpong_blk)(struct sde_hw_dsc *hw_dsc, + bool enable, + const enum sde_pingpong pp); +}; + +struct sde_hw_dsc { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* dsc */ + enum sde_dsc idx; + const struct sde_dsc_cfg *caps; + + /* ops */ + struct sde_hw_dsc_ops ops; +}; + +/** + * sde_hw_dsc - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_dsc *to_sde_hw_dsc(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_dsc, base); +} + +/** + * sde_hw_dsc_init - initializes the dsc block for the passed + * dsc idx. + * @idx: DSC index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + * Returns: Error code or allocated sde_hw_dsc context + */ +struct sde_hw_dsc *sde_hw_dsc_init(enum sde_dsc idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_dsc_destroy - destroys dsc driver context + * should be called to free the context + * @dsc: Pointer to dsc driver context returned by sde_hw_dsc_init + */ +void sde_hw_dsc_destroy(struct sde_hw_dsc *dsc); + +#endif /*_SDE_HW_DSC_H */ diff --git a/techpack/display/msm/sde/sde_hw_dspp.c b/techpack/display/msm/sde/sde_hw_dspp.c new file mode 100644 index 0000000000000000000000000000000000000000..5b66b83be806a36fc689822e6640eb268981104a --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_dspp.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ +#include <drm/msm_drm_pp.h> +#include "sde_hw_mdss.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_dspp.h" +#include "sde_hw_color_processing.h" +#include "sde_dbg.h" +#include "sde_ad4.h" +#include "sde_kms.h" + +static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + if (!m || !addr || !b) + return ERR_PTR(-EINVAL); + + for (i = 0; i < m->dspp_count; i++) { + if (dspp == m->dspp[i].id) { + b->base_off = addr; + b->blk_off = m->dspp[i].base; + b->length = m->dspp[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_DSPP; + return &m->dspp[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static void dspp_igc(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->igc.version == SDE_COLOR_PROCESS_VER(0x3, 0x1)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_IGC, c->idx); + if (!ret) + c->ops.setup_igc = reg_dmav1_setup_dspp_igcv31; + else + c->ops.setup_igc = sde_setup_dspp_igcv3; + } +} + +static void dspp_pcc(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->pcc.version == (SDE_COLOR_PROCESS_VER(0x1, 0x7))) + c->ops.setup_pcc = sde_setup_dspp_pcc_v1_7; + else if (c->cap->sblk->pcc.version == + (SDE_COLOR_PROCESS_VER(0x4, 0x0))) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_PCC, c->idx); + if (!ret) + c->ops.setup_pcc = reg_dmav1_setup_dspp_pccv4; + else + c->ops.setup_pcc = sde_setup_dspp_pccv4; + } +} + +static void dspp_gc(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->gc.version == SDE_COLOR_PROCESS_VER(0x1, 8)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_GC, c->idx); + if (!ret) + c->ops.setup_gc = reg_dmav1_setup_dspp_gcv18; + /** + * programming for v18 through ahb is same as v17, + * hence assign v17 function + */ + else + c->ops.setup_gc = sde_setup_dspp_gc_v1_7; + } +} + +static void dspp_hsic(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->hsic.version == SDE_COLOR_PROCESS_VER(0x1, 0x7)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_HSIC, c->idx); + if (!ret) + c->ops.setup_pa_hsic = reg_dmav1_setup_dspp_pa_hsicv17; + else + c->ops.setup_pa_hsic = sde_setup_dspp_pa_hsic_v17; + } +} + +static void dspp_memcolor(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->memcolor.version == SDE_COLOR_PROCESS_VER(0x1, 0x7)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_MEMCOLOR, c->idx); + if (!ret) { + c->ops.setup_pa_memcol_skin = + reg_dmav1_setup_dspp_memcol_skinv17; + c->ops.setup_pa_memcol_sky = + reg_dmav1_setup_dspp_memcol_skyv17; + c->ops.setup_pa_memcol_foliage = + reg_dmav1_setup_dspp_memcol_folv17; + c->ops.setup_pa_memcol_prot = + reg_dmav1_setup_dspp_memcol_protv17; + } else { + c->ops.setup_pa_memcol_skin = + sde_setup_dspp_memcol_skin_v17; + c->ops.setup_pa_memcol_sky = + sde_setup_dspp_memcol_sky_v17; + c->ops.setup_pa_memcol_foliage = + sde_setup_dspp_memcol_foliage_v17; + c->ops.setup_pa_memcol_prot = + sde_setup_dspp_memcol_prot_v17; + } + } +} + +static void dspp_sixzone(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->sixzone.version == SDE_COLOR_PROCESS_VER(0x1, 0x7)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_SIXZONE, c->idx); + if (!ret) + c->ops.setup_sixzone = reg_dmav1_setup_dspp_sixzonev17; + else + c->ops.setup_sixzone = sde_setup_dspp_sixzone_v17; + } +} + +static void dspp_gamut(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->gamut.version == SDE_COLOR_PROCESS_VER(0x4, 0)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_GAMUT, c->idx); + if (!ret) + c->ops.setup_gamut = reg_dmav1_setup_dspp_3d_gamutv4; + else + c->ops.setup_gamut = sde_setup_dspp_3d_gamutv4; + } else if (c->cap->sblk->gamut.version == + SDE_COLOR_PROCESS_VER(0x4, 1)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_GAMUT, c->idx); + if (!ret) + c->ops.setup_gamut = reg_dmav1_setup_dspp_3d_gamutv41; + else + c->ops.setup_gamut = sde_setup_dspp_3d_gamutv41; + } else if (c->cap->sblk->gamut.version == + SDE_COLOR_PROCESS_VER(0x4, 2)) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_GAMUT, c->idx); + c->ops.setup_gamut = NULL; + if (!ret) + c->ops.setup_gamut = reg_dmav1_setup_dspp_3d_gamutv42; + } +} + +static void dspp_dither(struct sde_hw_dspp *c) +{ + if (c->cap->sblk->dither.version == SDE_COLOR_PROCESS_VER(0x1, 0x7)) + c->ops.setup_pa_dither = sde_setup_dspp_dither_v1_7; +} + +static void dspp_hist(struct sde_hw_dspp *c) +{ + if (c->cap->sblk->hist.version == (SDE_COLOR_PROCESS_VER(0x1, 0x7))) { + c->ops.setup_histogram = sde_setup_dspp_hist_v1_7; + c->ops.read_histogram = sde_read_dspp_hist_v1_7; + c->ops.lock_histogram = sde_lock_dspp_hist_v1_7; + } +} + +static void dspp_vlut(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->vlut.version == (SDE_COLOR_PROCESS_VER(0x1, 0x7))) { + c->ops.setup_vlut = sde_setup_dspp_pa_vlut_v1_7; + } else if (c->cap->sblk->vlut.version == + (SDE_COLOR_PROCESS_VER(0x1, 0x8))) { + ret = reg_dmav1_init_dspp_op_v4(SDE_DSPP_VLUT, c->idx); + if (!ret) + c->ops.setup_vlut = reg_dmav1_setup_dspp_vlutv18; + else + c->ops.setup_vlut = sde_setup_dspp_pa_vlut_v1_8; + } +} + +static void dspp_ad(struct sde_hw_dspp *c) +{ + if (c->cap->sblk->ad.version == SDE_COLOR_PROCESS_VER(4, 0)) { + c->ops.setup_ad = sde_setup_dspp_ad4; + c->ops.ad_read_intr_resp = sde_read_intr_resp_ad4; + c->ops.validate_ad = sde_validate_dspp_ad4; + } +} + +static void dspp_ltm(struct sde_hw_dspp *c) +{ + int ret = 0; + + if (c->cap->sblk->ltm.version == SDE_COLOR_PROCESS_VER(0x1, 0x0)) { + ret = reg_dmav1_init_ltm_op_v6(SDE_LTM_INIT, c->idx); + if (!ret) + ret = reg_dmav1_init_ltm_op_v6(SDE_LTM_ROI, c->idx); + if (!ret) + ret = reg_dmav1_init_ltm_op_v6(SDE_LTM_VLUT, c->idx); + + if (!ret) { + c->ops.setup_ltm_init = reg_dmav1_setup_ltm_initv1; + c->ops.setup_ltm_roi = reg_dmav1_setup_ltm_roiv1; + c->ops.setup_ltm_vlut = reg_dmav1_setup_ltm_vlutv1; + } else { + c->ops.setup_ltm_init = NULL; + c->ops.setup_ltm_roi = NULL; + c->ops.setup_ltm_vlut = NULL; + } + c->ops.setup_ltm_thresh = sde_setup_dspp_ltm_threshv1; + c->ops.setup_ltm_hist_ctrl = sde_setup_dspp_ltm_hist_ctrlv1; + c->ops.setup_ltm_hist_buffer = sde_setup_dspp_ltm_hist_bufferv1; + c->ops.ltm_read_intr_status = sde_ltm_read_intr_status; + } +} + +static void (*dspp_blocks[SDE_DSPP_MAX])(struct sde_hw_dspp *c); + +static void _init_dspp_ops(void) +{ + dspp_blocks[SDE_DSPP_IGC] = dspp_igc; + dspp_blocks[SDE_DSPP_PCC] = dspp_pcc; + dspp_blocks[SDE_DSPP_GC] = dspp_gc; + dspp_blocks[SDE_DSPP_HSIC] = dspp_hsic; + dspp_blocks[SDE_DSPP_MEMCOLOR] = dspp_memcolor; + dspp_blocks[SDE_DSPP_SIXZONE] = dspp_sixzone; + dspp_blocks[SDE_DSPP_GAMUT] = dspp_gamut; + dspp_blocks[SDE_DSPP_DITHER] = dspp_dither; + dspp_blocks[SDE_DSPP_HIST] = dspp_hist; + dspp_blocks[SDE_DSPP_VLUT] = dspp_vlut; + dspp_blocks[SDE_DSPP_AD] = dspp_ad; + dspp_blocks[SDE_DSPP_LTM] = dspp_ltm; +} + +static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features) +{ + int i = 0; + + if (!c->cap->sblk) + return; + + for (i = 0; i < SDE_DSPP_MAX; i++) { + if (!test_bit(i, &features)) + continue; + if (dspp_blocks[i]) + dspp_blocks[i](c); + } +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_dspp *c; + struct sde_dspp_cfg *cfg; + int rc; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _dspp_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* Populate DSPP Top HW block */ + c->hw_top.base_off = addr; + c->hw_top.blk_off = m->dspp_top.base; + c->hw_top.length = m->dspp_top.len; + c->hw_top.hwversion = m->hwversion; + c->hw_top.log_mask = SDE_DBG_MASK_DSPP; + + /* Assign ops */ + c->idx = idx; + c->cap = cfg; + _init_dspp_ops(); + _setup_dspp_ops(c, c->cap->features); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_DSPP, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + if ((cfg->sblk->ltm.id == SDE_DSPP_LTM) && cfg->sblk->ltm.base) { + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "LTM", + c->hw.blk_off + cfg->sblk->ltm.base, + c->hw.blk_off + cfg->sblk->ltm.base + 0xC4, + c->hw.xin_id); + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_dspp_destroy(struct sde_hw_dspp *dspp) +{ + if (dspp) { + reg_dmav1_deinit_dspp_ops(dspp->idx); + reg_dmav1_deinit_ltm_ops(dspp->idx); + sde_hw_blk_destroy(&dspp->base); + } + kfree(dspp); +} diff --git a/techpack/display/msm/sde/sde_hw_dspp.h b/techpack/display/msm/sde/sde_hw_dspp.h new file mode 100644 index 0000000000000000000000000000000000000000..dfc2ff1e492785999503cbd725484c885fe2ba86 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_dspp.h @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_DSPP_H +#define _SDE_HW_DSPP_H + +#include "sde_hw_blk.h" + +struct sde_hw_dspp; + +/** + * struct sde_hw_dspp_ops - interface to the dspp hardware driver functions + * Caller must call the init function to get the dspp context for each dspp + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_dspp_ops { + /** + * setup_histogram - setup dspp histogram + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_histogram)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * read_histogram - read dspp histogram + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*read_histogram)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * lock_histogram - lock dspp histogram buffer + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*lock_histogram)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_igc - update dspp igc + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_igc)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_pa_hsic - setup dspp pa hsic + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pa_hsic)(struct sde_hw_dspp *dspp, void *cfg); + + /** + * setup_pcc - setup dspp pcc + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pcc)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_sharpening - setup dspp sharpening + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_sharpening)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_pa_memcol_skin - setup dspp memcolor skin + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pa_memcol_skin)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_pa_memcol_sky - setup dspp memcolor sky + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pa_memcol_sky)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_pa_memcol_foliage - setup dspp memcolor foliage + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pa_memcol_foliage)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_pa_memcol_prot - setup dspp memcolor protection + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pa_memcol_prot)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_sixzone - setup dspp six zone + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_sixzone)(struct sde_hw_dspp *dspp, void *cfg); + + /** + * setup_danger_safe - setup danger safe LUTS + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_danger_safe)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_pa_dither - setup dspp PA dither + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_pa_dither)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_vlut - setup dspp PA VLUT + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_vlut)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_gc - update dspp gc + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_gc)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_gamut - update dspp gamut + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_gamut)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * validate_ad - check if ad property can be set + * @ctx: Pointer to dspp context + * @prop: Pointer to ad property being validated + */ + int (*validate_ad)(struct sde_hw_dspp *ctx, u32 *prop); + + /** + * setup_ad - update the ad property + * @ctx: Pointer to dspp context + * @cfg: Pointer to ad configuration + */ + void (*setup_ad)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * ad_read_intr_resp - function to get interrupt response for ad + * @event: Event for which response needs to be read + * @resp_in: Pointer to u32 where resp ad4 input value is dumped. + * @resp_out: Pointer to u32 where resp ad4 output value is dumped. + */ + void (*ad_read_intr_resp)(struct sde_hw_dspp *ctx, u32 event, + u32 *resp_in, u32 *resp_out); + + /** + * setup_ltm_init - setup LTM INIT + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_ltm_init)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_ltm_roi - setup LTM ROI + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_ltm_roi)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_ltm_vlut - setup LTM VLUT + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_ltm_vlut)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * setup_ltm_hist_ctrl - setup LTM histogram control + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + * @enable: feature enable/disable value + * @iova: aligned hist buffer address + */ + void (*setup_ltm_hist_ctrl)(struct sde_hw_dspp *ctx, void *cfg, + bool enable, u64 iova); + + /** + * setup_ltm_hist_buffer - setup LTM histogram buffer + * @ctx: Pointer to dspp context + * @iova: aligned hist buffer address + */ + void (*setup_ltm_hist_buffer)(struct sde_hw_dspp *ctx, u64 iova); + + /** + * setup_ltm_thresh - setup LTM histogram thresh + * @ctx: Pointer to dspp context + * @cfg: Pointer to configuration + */ + void (*setup_ltm_thresh)(struct sde_hw_dspp *ctx, void *cfg); + + /** + * ltm_read_intr_status - function to read ltm interrupt status + * @ctx: Pointer to dspp context + * @status: Pointer to u32 where ltm status value is dumped. + */ + void (*ltm_read_intr_status)(struct sde_hw_dspp *ctx, u32 *status); +}; + +/** + * struct sde_hw_dspp - dspp description + * @base: Hardware block base structure + * @hw: Block hardware details + * @hw_top: Block hardware top details + * @idx: DSPP index + * @cap: Pointer to layer_cfg + * @ops: Pointer to operations possible for this DSPP + */ +struct sde_hw_dspp { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* dspp top */ + struct sde_hw_blk_reg_map hw_top; + + /* dspp */ + enum sde_dspp idx; + const struct sde_dspp_cfg *cap; + + /* Ops */ + struct sde_hw_dspp_ops ops; +}; + +/** + * sde_hw_dspp - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_dspp *to_sde_hw_dspp(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_dspp, base); +} + +/** + * sde_hw_dspp_init - initializes the dspp hw driver object. + * should be called once before accessing every dspp. + * @idx: DSPP index for which driver object is required + * @addr: Mapped register io address of MDP + * @Return: pointer to structure or ERR_PTR + */ +struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_dspp_destroy(): Destroys DSPP driver context + * @dspp: Pointer to DSPP driver context + */ +void sde_hw_dspp_destroy(struct sde_hw_dspp *dspp); + +#endif /*_SDE_HW_DSPP_H */ diff --git a/techpack/display/msm/sde/sde_hw_interrupts.c b/techpack/display/msm/sde/sde_hw_interrupts.c new file mode 100644 index 0000000000000000000000000000000000000000..5616d1f28631601a0590b7262f7a343987fb7d36 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_interrupts.c @@ -0,0 +1,1500 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/bitops.h> +#include <linux/slab.h> + +#include "sde_kms.h" +#include "sde_hw_interrupts.h" +#include "sde_hw_util.h" +#include "sde_hw_mdss.h" + +/** + * Register offsets in MDSS register file for the interrupt registers + * w.r.t. to the MDSS base + */ +#define HW_INTR_STATUS 0x0010 +#define MDP_SSPP_TOP0_OFF 0x1000 +#define MDP_INTF_0_OFF 0x6B000 +#define MDP_INTF_1_OFF 0x6B800 +#define MDP_INTF_2_OFF 0x6C000 +#define MDP_INTF_3_OFF 0x6C800 +#define MDP_INTF_4_OFF 0x6D000 +#define MDP_AD4_0_OFF 0x7D000 +#define MDP_AD4_1_OFF 0x7E000 +#define MDP_AD4_INTR_EN_OFF 0x41c +#define MDP_AD4_INTR_CLEAR_OFF 0x424 +#define MDP_AD4_INTR_STATUS_OFF 0x420 +#define MDP_INTF_TEAR_INTF_1_IRQ_OFF 0x6E800 +#define MDP_INTF_TEAR_INTF_2_IRQ_OFF 0x6E900 +#define MDP_INTF_TEAR_INTR_EN_OFF 0x0 +#define MDP_INTF_TEAR_INTR_STATUS_OFF 0x4 +#define MDP_INTF_TEAR_INTR_CLEAR_OFF 0x8 +#define MDP_LTM_0_OFF 0x7F000 +#define MDP_LTM_1_OFF 0x7F100 +#define MDP_LTM_INTR_EN_OFF 0x50 +#define MDP_LTM_INTR_STATUS_OFF 0x54 +#define MDP_LTM_INTR_CLEAR_OFF 0x58 + +/** + * WB interrupt status bit definitions + */ +#define SDE_INTR_WB_0_DONE BIT(0) +#define SDE_INTR_WB_1_DONE BIT(1) +#define SDE_INTR_WB_2_DONE BIT(4) + +/** + * WDOG timer interrupt status bit definitions + */ +#define SDE_INTR_WD_TIMER_0_DONE BIT(2) +#define SDE_INTR_WD_TIMER_1_DONE BIT(3) +#define SDE_INTR_WD_TIMER_2_DONE BIT(5) +#define SDE_INTR_WD_TIMER_3_DONE BIT(6) +#define SDE_INTR_WD_TIMER_4_DONE BIT(7) + +/** + * Pingpong interrupt status bit definitions + */ +#define SDE_INTR_PING_PONG_0_DONE BIT(8) +#define SDE_INTR_PING_PONG_1_DONE BIT(9) +#define SDE_INTR_PING_PONG_2_DONE BIT(10) +#define SDE_INTR_PING_PONG_3_DONE BIT(11) +#define SDE_INTR_PING_PONG_4_DONE BIT(30) +#define SDE_INTR_PING_PONG_5_DONE BIT(31) +#define SDE_INTR_PING_PONG_0_RD_PTR BIT(12) +#define SDE_INTR_PING_PONG_1_RD_PTR BIT(13) +#define SDE_INTR_PING_PONG_2_RD_PTR BIT(14) +#define SDE_INTR_PING_PONG_3_RD_PTR BIT(15) +#define SDE_INTR_PING_PONG_0_WR_PTR BIT(16) +#define SDE_INTR_PING_PONG_1_WR_PTR BIT(17) +#define SDE_INTR_PING_PONG_2_WR_PTR BIT(18) +#define SDE_INTR_PING_PONG_3_WR_PTR BIT(19) +#define SDE_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20) +#define SDE_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21) +#define SDE_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22) +#define SDE_INTR_PING_PONG_3_AUTOREFRESH_DONE BIT(23) + +/** + * Interface interrupt status bit definitions + */ +#define SDE_INTR_INTF_0_UNDERRUN BIT(24) +#define SDE_INTR_INTF_1_UNDERRUN BIT(26) +#define SDE_INTR_INTF_2_UNDERRUN BIT(28) +#define SDE_INTR_INTF_3_UNDERRUN BIT(30) +#define SDE_INTR_INTF_0_VSYNC BIT(25) +#define SDE_INTR_INTF_1_VSYNC BIT(27) +#define SDE_INTR_INTF_2_VSYNC BIT(29) +#define SDE_INTR_INTF_3_VSYNC BIT(31) + +/** + * Pingpong Secondary interrupt status bit definitions + */ +#define SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE BIT(0) +#define SDE_INTR_PING_PONG_S0_WR_PTR BIT(4) +#define SDE_INTR_PING_PONG_S0_RD_PTR BIT(8) +#define SDE_INTR_PING_PONG_S0_TEAR_DETECTED BIT(22) +#define SDE_INTR_PING_PONG_S0_TE_DETECTED BIT(28) + +/** + * Pingpong TEAR detection interrupt status bit definitions + */ +#define SDE_INTR_PING_PONG_0_TEAR_DETECTED BIT(16) +#define SDE_INTR_PING_PONG_1_TEAR_DETECTED BIT(17) +#define SDE_INTR_PING_PONG_2_TEAR_DETECTED BIT(18) +#define SDE_INTR_PING_PONG_3_TEAR_DETECTED BIT(19) + +/** + * Pingpong TE detection interrupt status bit definitions + */ +#define SDE_INTR_PING_PONG_0_TE_DETECTED BIT(24) +#define SDE_INTR_PING_PONG_1_TE_DETECTED BIT(25) +#define SDE_INTR_PING_PONG_2_TE_DETECTED BIT(26) +#define SDE_INTR_PING_PONG_3_TE_DETECTED BIT(27) + +/** + * Ctl start interrupt status bit definitions + */ +#define SDE_INTR_CTL_0_START BIT(9) +#define SDE_INTR_CTL_1_START BIT(10) +#define SDE_INTR_CTL_2_START BIT(11) +#define SDE_INTR_CTL_3_START BIT(12) +#define SDE_INTR_CTL_4_START BIT(13) +#define SDE_INTR_CTL_5_START BIT(23) + +/** + * Concurrent WB overflow interrupt status bit definitions + */ +#define SDE_INTR_CWB_1_OVERFLOW BIT(8) +#define SDE_INTR_CWB_2_OVERFLOW BIT(14) +#define SDE_INTR_CWB_3_OVERFLOW BIT(15) +#define SDE_INTR_CWB_4_OVERFLOW BIT(20) +#define SDE_INTR_CWB_5_OVERFLOW BIT(21) + +/** + * Histogram VIG done interrupt status bit definitions + */ +#define SDE_INTR_HIST_VIG_0_DONE BIT(0) +#define SDE_INTR_HIST_VIG_1_DONE BIT(4) +#define SDE_INTR_HIST_VIG_2_DONE BIT(8) +#define SDE_INTR_HIST_VIG_3_DONE BIT(10) + +/** + * Histogram VIG reset Sequence done interrupt status bit definitions + */ +#define SDE_INTR_HIST_VIG_0_RSTSEQ_DONE BIT(1) +#define SDE_INTR_HIST_VIG_1_RSTSEQ_DONE BIT(5) +#define SDE_INTR_HIST_VIG_2_RSTSEQ_DONE BIT(9) +#define SDE_INTR_HIST_VIG_3_RSTSEQ_DONE BIT(11) + +/** + * Histogram DSPP done interrupt status bit definitions + */ +#define SDE_INTR_HIST_DSPP_0_DONE BIT(12) +#define SDE_INTR_HIST_DSPP_1_DONE BIT(16) +#define SDE_INTR_HIST_DSPP_2_DONE BIT(20) +#define SDE_INTR_HIST_DSPP_3_DONE BIT(22) + +/** + * Histogram DSPP reset Sequence done interrupt status bit definitions + */ +#define SDE_INTR_HIST_DSPP_0_RSTSEQ_DONE BIT(13) +#define SDE_INTR_HIST_DSPP_1_RSTSEQ_DONE BIT(17) +#define SDE_INTR_HIST_DSPP_2_RSTSEQ_DONE BIT(21) +#define SDE_INTR_HIST_DSPP_3_RSTSEQ_DONE BIT(23) + +/** + * INTF interrupt status bit definitions + */ +#define SDE_INTR_VIDEO_INTO_STATIC BIT(0) +#define SDE_INTR_VIDEO_OUTOF_STATIC BIT(1) +#define SDE_INTR_DSICMD_0_INTO_STATIC BIT(2) +#define SDE_INTR_DSICMD_0_OUTOF_STATIC BIT(3) +#define SDE_INTR_DSICMD_1_INTO_STATIC BIT(4) +#define SDE_INTR_DSICMD_1_OUTOF_STATIC BIT(5) +#define SDE_INTR_DSICMD_2_INTO_STATIC BIT(6) +#define SDE_INTR_DSICMD_2_OUTOF_STATIC BIT(7) +#define SDE_INTR_PROG_LINE BIT(8) + +/** + * AD4 interrupt status bit definitions + */ +#define SDE_INTR_BRIGHTPR_UPDATED BIT(4) +#define SDE_INTR_DARKENH_UPDATED BIT(3) +#define SDE_INTR_STREN_OUTROI_UPDATED BIT(2) +#define SDE_INTR_STREN_INROI_UPDATED BIT(1) +#define SDE_INTR_BACKLIGHT_UPDATED BIT(0) + +/** + * INTF Tear IRQ register bit definitions + */ +#define SDE_INTR_INTF_TEAR_AUTOREFRESH_DONE BIT(0) +#define SDE_INTR_INTF_TEAR_WR_PTR BIT(1) +#define SDE_INTR_INTF_TEAR_RD_PTR BIT(2) +#define SDE_INTR_INTF_TEAR_TE_DETECTED BIT(3) +#define SDE_INTR_INTF_TEAR_TEAR_DETECTED BIT(4) + +/** + * LTM interrupt status bit definitions + */ +#define SDE_INTR_LTM_STATS_DONE BIT(0) +#define SDE_INTR_LTM_STATS_WB_PB BIT(5) + +/** + * struct sde_intr_reg - array of SDE register sets + * @clr_off: offset to CLEAR reg + * @en_off: offset to ENABLE reg + * @status_off: offset to STATUS reg + * @sde_irq_idx; global index in the 'sde_irq_map' table, + * to know which interrupt type, instance, mask, etc. to use + * @map_idx_start first offset in the sde_irq_map table + * @map_idx_end last offset in the sde_irq_map table + */ +struct sde_intr_reg { + u32 clr_off; + u32 en_off; + u32 status_off; + int sde_irq_idx; + u32 map_idx_start; + u32 map_idx_end; +}; + +/** + * struct sde_irq_type - maps each irq with i/f + * @intr_type: type of interrupt listed in sde_intr_type + * @instance_idx: instance index of the associated HW block in SDE + * @irq_mask: corresponding bit in the interrupt status reg + * @reg_idx: index in the 'sde_irq_tbl' table, to know which + * registers offsets to use. -1 = invalid offset + */ +struct sde_irq_type { + u32 intr_type; + u32 instance_idx; + u32 irq_mask; + int reg_idx; +}; + +/** + * IRQ mapping tables - use for lookup an irq_idx in this table that have + * a matching interface type and instance index. + * Each of these tables are copied to a dynamically allocated + * table, that will be used to service each of the irqs + */ +static struct sde_irq_type sde_irq_intr_map[] = { + + { SDE_IRQ_TYPE_WB_ROT_COMP, WB_0, SDE_INTR_WB_0_DONE, -1}, + { SDE_IRQ_TYPE_WB_ROT_COMP, WB_1, SDE_INTR_WB_1_DONE, 0}, + { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_0, SDE_INTR_WD_TIMER_0_DONE, -1}, + { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_1, SDE_INTR_WD_TIMER_1_DONE, -1}, + + { SDE_IRQ_TYPE_WB_WFD_COMP, WB_2, SDE_INTR_WB_2_DONE, -1}, + { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_2, SDE_INTR_WD_TIMER_2_DONE, -1}, + { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_3, SDE_INTR_WD_TIMER_3_DONE, -1}, + { SDE_IRQ_TYPE_WD_TIMER, WD_TIMER_4, SDE_INTR_WD_TIMER_4_DONE, -1}, + + { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_0, + SDE_INTR_PING_PONG_0_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_1, + SDE_INTR_PING_PONG_1_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_2, + SDE_INTR_PING_PONG_2_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_3, + SDE_INTR_PING_PONG_3_DONE, -1}, + + { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_0, + SDE_INTR_PING_PONG_0_RD_PTR, -1}, + { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_1, + SDE_INTR_PING_PONG_1_RD_PTR, -1}, + { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_2, + SDE_INTR_PING_PONG_2_RD_PTR, -1}, + { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_3, + SDE_INTR_PING_PONG_3_RD_PTR, -1}, + + { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_0, + SDE_INTR_PING_PONG_0_WR_PTR, -1}, + { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_1, + SDE_INTR_PING_PONG_1_WR_PTR, -1}, + { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_2, + SDE_INTR_PING_PONG_2_WR_PTR, -1}, + { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_3, + SDE_INTR_PING_PONG_3_WR_PTR, -1}, + + { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_0, + SDE_INTR_PING_PONG_0_AUTOREFRESH_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_1, + SDE_INTR_PING_PONG_1_AUTOREFRESH_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_2, + SDE_INTR_PING_PONG_2_AUTOREFRESH_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_3, + SDE_INTR_PING_PONG_3_AUTOREFRESH_DONE, -1}, + + { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_0, SDE_INTR_INTF_0_UNDERRUN, -1}, + { SDE_IRQ_TYPE_INTF_VSYNC, INTF_0, SDE_INTR_INTF_0_VSYNC, -1}, + { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_1, SDE_INTR_INTF_1_UNDERRUN, -1}, + { SDE_IRQ_TYPE_INTF_VSYNC, INTF_1, SDE_INTR_INTF_1_VSYNC, -1}, + + { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_2, SDE_INTR_INTF_2_UNDERRUN, -1}, + { SDE_IRQ_TYPE_INTF_VSYNC, INTF_2, SDE_INTR_INTF_2_VSYNC, -1}, + { SDE_IRQ_TYPE_INTF_UNDER_RUN, INTF_3, SDE_INTR_INTF_3_UNDERRUN, -1}, + { SDE_IRQ_TYPE_INTF_VSYNC, INTF_3, SDE_INTR_INTF_3_VSYNC, -1}, +}; + +static struct sde_irq_type sde_irq_intr2_map[] = { + + { SDE_IRQ_TYPE_PING_PONG_AUTO_REF, PINGPONG_S0, + SDE_INTR_PING_PONG_S0_AUTOREFRESH_DONE, -1}, + + { SDE_IRQ_TYPE_PING_PONG_WR_PTR, PINGPONG_S0, + SDE_INTR_PING_PONG_S0_WR_PTR, -1}, + + { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_1, SDE_INTR_CWB_1_OVERFLOW, -1}, + + { SDE_IRQ_TYPE_PING_PONG_RD_PTR, PINGPONG_S0, + SDE_INTR_PING_PONG_S0_RD_PTR, -1}, + + { SDE_IRQ_TYPE_CTL_START, CTL_0, + SDE_INTR_CTL_0_START, -1}, + { SDE_IRQ_TYPE_CTL_START, CTL_1, + SDE_INTR_CTL_1_START, -1}, + { SDE_IRQ_TYPE_CTL_START, CTL_2, + SDE_INTR_CTL_2_START, -1}, + { SDE_IRQ_TYPE_CTL_START, CTL_3, + SDE_INTR_CTL_3_START, -1}, + { SDE_IRQ_TYPE_CTL_START, CTL_4, + SDE_INTR_CTL_4_START, -1}, + { SDE_IRQ_TYPE_CTL_START, CTL_5, + SDE_INTR_CTL_5_START, -1}, + + { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_2, SDE_INTR_CWB_2_OVERFLOW, -1}, + { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_3, SDE_INTR_CWB_3_OVERFLOW, -1}, + + { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_0, + SDE_INTR_PING_PONG_0_TEAR_DETECTED, -1}, + { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_1, + SDE_INTR_PING_PONG_1_TEAR_DETECTED, -1}, + { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_2, + SDE_INTR_PING_PONG_2_TEAR_DETECTED, -1}, + { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_3, + SDE_INTR_PING_PONG_3_TEAR_DETECTED, -1}, + + { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_4, SDE_INTR_CWB_4_OVERFLOW, -1}, + { SDE_IRQ_TYPE_CWB_OVERFLOW, CWB_5, SDE_INTR_CWB_5_OVERFLOW, -1}, + + { SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, PINGPONG_S0, + SDE_INTR_PING_PONG_S0_TEAR_DETECTED, -1}, + + { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_0, + SDE_INTR_PING_PONG_0_TE_DETECTED, -1}, + { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_1, + SDE_INTR_PING_PONG_1_TE_DETECTED, -1}, + { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_2, + SDE_INTR_PING_PONG_2_TE_DETECTED, -1}, + { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_3, + SDE_INTR_PING_PONG_3_TE_DETECTED, -1}, + + { SDE_IRQ_TYPE_PING_PONG_TE_CHECK, PINGPONG_S0, + SDE_INTR_PING_PONG_S0_TE_DETECTED, -1}, + + { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_4, + SDE_INTR_PING_PONG_4_DONE, -1}, + { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_5, + SDE_INTR_PING_PONG_5_DONE, -1}, +}; + +static struct sde_irq_type sde_irq_hist_map[] = { + + { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG0, SDE_INTR_HIST_VIG_0_DONE, -1}, + { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG0, + SDE_INTR_HIST_VIG_0_RSTSEQ_DONE, -1}, + + { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG1, SDE_INTR_HIST_VIG_1_DONE, -1}, + { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG1, + SDE_INTR_HIST_VIG_1_RSTSEQ_DONE, -1}, + + { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG2, SDE_INTR_HIST_VIG_2_DONE, -1}, + { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG2, + SDE_INTR_HIST_VIG_2_RSTSEQ_DONE, -1}, + { SDE_IRQ_TYPE_HIST_VIG_DONE, SSPP_VIG3, SDE_INTR_HIST_VIG_3_DONE, -1}, + { SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, SSPP_VIG3, + SDE_INTR_HIST_VIG_3_RSTSEQ_DONE, -1}, + + { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_0, SDE_INTR_HIST_DSPP_0_DONE, -1}, + { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_0, + SDE_INTR_HIST_DSPP_0_RSTSEQ_DONE, -1}, + + { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_1, SDE_INTR_HIST_DSPP_1_DONE, -1}, + { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_1, + SDE_INTR_HIST_DSPP_1_RSTSEQ_DONE, -1}, + + { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_2, SDE_INTR_HIST_DSPP_2_DONE, -1}, + { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_2, + SDE_INTR_HIST_DSPP_2_RSTSEQ_DONE, -1}, + { SDE_IRQ_TYPE_HIST_DSPP_DONE, DSPP_3, SDE_INTR_HIST_DSPP_3_DONE, -1}, + { SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, DSPP_3, + SDE_INTR_HIST_DSPP_3_RSTSEQ_DONE, -1}, +}; + +static struct sde_irq_type sde_irq_intf0_map[] = { + + { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_0, + SDE_INTR_VIDEO_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_0, + SDE_INTR_VIDEO_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_0, + SDE_INTR_DSICMD_0_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_0, + SDE_INTR_DSICMD_0_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_0, + SDE_INTR_DSICMD_1_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_0, + SDE_INTR_DSICMD_1_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_0, + SDE_INTR_DSICMD_2_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_0, + SDE_INTR_DSICMD_2_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_PROG_LINE, INTF_0, SDE_INTR_PROG_LINE, -1}, +}; + +static struct sde_irq_type sde_irq_inf1_map[] = { + + { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_1, + SDE_INTR_VIDEO_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_1, + SDE_INTR_VIDEO_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_1, + SDE_INTR_DSICMD_0_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_1, + SDE_INTR_DSICMD_0_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_1, + SDE_INTR_DSICMD_1_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_1, + SDE_INTR_DSICMD_1_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_1, + SDE_INTR_DSICMD_2_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_1, + SDE_INTR_DSICMD_2_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_PROG_LINE, INTF_1, SDE_INTR_PROG_LINE, -1}, +}; + +static struct sde_irq_type sde_irq_intf2_map[] = { + + + { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_2, + SDE_INTR_VIDEO_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_2, + SDE_INTR_VIDEO_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_2, + SDE_INTR_DSICMD_0_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_2, + SDE_INTR_DSICMD_0_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_2, + SDE_INTR_DSICMD_1_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_2, + SDE_INTR_DSICMD_1_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_2, + SDE_INTR_DSICMD_2_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_2, + SDE_INTR_DSICMD_2_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_PROG_LINE, INTF_2, SDE_INTR_PROG_LINE, -1}, +}; + +static struct sde_irq_type sde_irq_intf3_map[] = { + + { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_3, + SDE_INTR_VIDEO_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_3, + SDE_INTR_VIDEO_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_3, + SDE_INTR_DSICMD_0_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_3, + SDE_INTR_DSICMD_0_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_3, + SDE_INTR_DSICMD_1_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_3, + SDE_INTR_DSICMD_1_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_3, + SDE_INTR_DSICMD_2_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_3, + SDE_INTR_DSICMD_2_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_PROG_LINE, INTF_3, SDE_INTR_PROG_LINE, -1}, +}; + +static struct sde_irq_type sde_irq_inf4_map[] = { + + { SDE_IRQ_TYPE_SFI_VIDEO_IN, INTF_4, + SDE_INTR_VIDEO_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_VIDEO_OUT, INTF_4, + SDE_INTR_VIDEO_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_IN, INTF_4, + SDE_INTR_DSICMD_0_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_0_OUT, INTF_4, + SDE_INTR_DSICMD_0_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_SFI_CMD_1_IN, INTF_4, + SDE_INTR_DSICMD_1_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_1_OUT, INTF_4, + SDE_INTR_DSICMD_1_OUTOF_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_IN, INTF_4, + SDE_INTR_DSICMD_2_INTO_STATIC, -1}, + { SDE_IRQ_TYPE_SFI_CMD_2_OUT, INTF_4, + SDE_INTR_DSICMD_2_OUTOF_STATIC, -1}, + + { SDE_IRQ_TYPE_PROG_LINE, INTF_4, SDE_INTR_PROG_LINE, -1}, +}; + +static struct sde_irq_type sde_irq_ad4_0_map[] = { + + { SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_0, SDE_INTR_BACKLIGHT_UPDATED, -1}, +}; + +static struct sde_irq_type sde_irq_ad4_1_map[] = { + + { SDE_IRQ_TYPE_AD4_BL_DONE, DSPP_1, SDE_INTR_BACKLIGHT_UPDATED, -1}, +}; + +static struct sde_irq_type sde_irq_intf1_te_map[] = { + + { SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF, INTF_1, + SDE_INTR_INTF_TEAR_AUTOREFRESH_DONE, -1}, + { SDE_IRQ_TYPE_INTF_TEAR_WR_PTR, INTF_1, + SDE_INTR_INTF_TEAR_WR_PTR, -1}, + { SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, INTF_1, + SDE_INTR_INTF_TEAR_RD_PTR, -1}, + { SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK, INTF_1, + SDE_INTR_INTF_TEAR_TEAR_DETECTED, -1}, +}; + +static struct sde_irq_type sde_irq_intf2_te_map[] = { + + { SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF, INTF_2, + SDE_INTR_INTF_TEAR_AUTOREFRESH_DONE, -1}, + { SDE_IRQ_TYPE_INTF_TEAR_WR_PTR, INTF_2, + SDE_INTR_INTF_TEAR_WR_PTR, -1}, + { SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, INTF_2, + SDE_INTR_INTF_TEAR_RD_PTR, -1}, + + { SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK, INTF_2, + SDE_INTR_INTF_TEAR_TEAR_DETECTED, -1}, +}; + +static struct sde_irq_type sde_irq_ltm_0_map[] = { + + { SDE_IRQ_TYPE_LTM_STATS_DONE, DSPP_0, SDE_INTR_LTM_STATS_DONE, -1}, + { SDE_IRQ_TYPE_LTM_STATS_WB_PB, DSPP_0, SDE_INTR_LTM_STATS_WB_PB, -1}, +}; + +static struct sde_irq_type sde_irq_ltm_1_map[] = { + + { SDE_IRQ_TYPE_LTM_STATS_DONE, DSPP_1, SDE_INTR_LTM_STATS_DONE, -1}, + { SDE_IRQ_TYPE_LTM_STATS_WB_PB, DSPP_1, SDE_INTR_LTM_STATS_WB_PB, -1}, +}; + +static int sde_hw_intr_irqidx_lookup(struct sde_hw_intr *intr, + enum sde_intr_type intr_type, u32 instance_idx) +{ + int i; + + for (i = 0; i < intr->sde_irq_map_size; i++) { + if (intr_type == intr->sde_irq_map[i].intr_type && + instance_idx == intr->sde_irq_map[i].instance_idx) + return i; + } + + pr_debug("IRQ lookup fail!! intr_type=%d, instance_idx=%d\n", + intr_type, instance_idx); + return -EINVAL; +} + +static void sde_hw_intr_set_mask(struct sde_hw_intr *intr, uint32_t reg_off, + uint32_t mask) +{ + if (!intr) + return; + + SDE_REG_WRITE(&intr->hw, reg_off, mask); + + /* ensure register writes go through */ + wmb(); +} + +static void sde_hw_intr_dispatch_irq(struct sde_hw_intr *intr, + void (*cbfunc)(void *, int), + void *arg) +{ + int reg_idx; + int irq_idx; + int start_idx; + int end_idx; + u32 irq_status; + unsigned long irq_flags; + int sde_irq_idx; + + if (!intr) + return; + + /* + * The dispatcher will save the IRQ status before calling here. + * Now need to go through each IRQ status and find matching + * irq lookup index. + */ + spin_lock_irqsave(&intr->irq_lock, irq_flags); + for (reg_idx = 0; reg_idx < intr->sde_irq_size; reg_idx++) { + irq_status = intr->save_irq_status[reg_idx]; + + /* get the global offset in 'sde_irq_map' */ + sde_irq_idx = intr->sde_irq_tbl[reg_idx].sde_irq_idx; + if (sde_irq_idx < 0) + continue; + + /* + * Each Interrupt register has dynamic range of indexes, + * initialized during hw_intr_init when sde_irq_tbl is created. + */ + start_idx = intr->sde_irq_tbl[reg_idx].map_idx_start; + end_idx = intr->sde_irq_tbl[reg_idx].map_idx_end; + + if (start_idx >= intr->sde_irq_map_size || + end_idx > intr->sde_irq_map_size) + continue; + + /* + * Search through matching intr status from irq map. + * start_idx and end_idx defined the search range in + * the sde_irq_map. + */ + for (irq_idx = start_idx; + (irq_idx < end_idx) && irq_status; + irq_idx++) + if ((irq_status & + intr->sde_irq_map[irq_idx].irq_mask) && + (intr->sde_irq_map[irq_idx].reg_idx == + reg_idx)) { + /* + * Once a match on irq mask, perform a callback + * to the given cbfunc. cbfunc will take care + * the interrupt status clearing. If cbfunc is + * not provided, then the interrupt clearing + * is here. + */ + if (cbfunc) + cbfunc(arg, irq_idx); + else + intr->ops.clear_intr_status_nolock( + intr, irq_idx); + + /* + * When callback finish, clear the irq_status + * with the matching mask. Once irq_status + * is all cleared, the search can be stopped. + */ + irq_status &= + ~intr->sde_irq_map[irq_idx].irq_mask; + } + } + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); +} + +static int sde_hw_intr_enable_irq_nolock(struct sde_hw_intr *intr, int irq_idx) +{ + int reg_idx; + const struct sde_intr_reg *reg; + const struct sde_irq_type *irq; + const char *dbgstr = NULL; + uint32_t cache_irq_mask; + + if (!intr) + return -EINVAL; + + if (irq_idx < 0 || irq_idx >= intr->sde_irq_map_size) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + irq = &intr->sde_irq_map[irq_idx]; + reg_idx = irq->reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return -EINVAL; + } + + reg = &intr->sde_irq_tbl[reg_idx]; + + cache_irq_mask = intr->cache_irq_mask[reg_idx]; + if (cache_irq_mask & irq->irq_mask) { + dbgstr = "SDE IRQ already set:"; + } else { + dbgstr = "SDE IRQ enabled:"; + + cache_irq_mask |= irq->irq_mask; + /* Cleaning any pending interrupt */ + SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); + /* Enabling interrupts with the new mask */ + SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); + + /* ensure register write goes through */ + wmb(); + + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + + pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, + irq->irq_mask, cache_irq_mask); + + return 0; +} + +static int sde_hw_intr_disable_irq_nolock(struct sde_hw_intr *intr, int irq_idx) +{ + int reg_idx; + const struct sde_intr_reg *reg; + const struct sde_irq_type *irq; + const char *dbgstr = NULL; + uint32_t cache_irq_mask; + + if (!intr) + return -EINVAL; + + if (irq_idx < 0 || irq_idx >= intr->sde_irq_map_size) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return -EINVAL; + } + + irq = &intr->sde_irq_map[irq_idx]; + reg_idx = irq->reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return -EINVAL; + } + + reg = &intr->sde_irq_tbl[reg_idx]; + + cache_irq_mask = intr->cache_irq_mask[reg_idx]; + if ((cache_irq_mask & irq->irq_mask) == 0) { + dbgstr = "SDE IRQ is already cleared:"; + } else { + dbgstr = "SDE IRQ mask disable:"; + + cache_irq_mask &= ~irq->irq_mask; + /* Disable interrupts based on the new mask */ + SDE_REG_WRITE(&intr->hw, reg->en_off, cache_irq_mask); + /* Cleaning any pending interrupt */ + SDE_REG_WRITE(&intr->hw, reg->clr_off, irq->irq_mask); + + /* ensure register write goes through */ + wmb(); + + intr->cache_irq_mask[reg_idx] = cache_irq_mask; + } + + pr_debug("%s MASK:0x%.8x, CACHE-MASK:0x%.8x\n", dbgstr, + irq->irq_mask, cache_irq_mask); + + return 0; +} + +static int sde_hw_intr_clear_irqs(struct sde_hw_intr *intr) +{ + int i; + + if (!intr) + return -EINVAL; + + for (i = 0; i < intr->sde_irq_size; i++) + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[i].clr_off, + 0xffffffff); + + /* ensure register writes go through */ + wmb(); + + return 0; +} + +static int sde_hw_intr_disable_irqs(struct sde_hw_intr *intr) +{ + int i; + + if (!intr) + return -EINVAL; + + for (i = 0; i < intr->sde_irq_size; i++) + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[i].en_off, + 0x00000000); + + /* ensure register writes go through */ + wmb(); + + return 0; +} + +static int sde_hw_intr_get_valid_interrupts(struct sde_hw_intr *intr, + uint32_t *mask) +{ + if (!intr || !mask) + return -EINVAL; + + *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1 + | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP; + + return 0; +} + +static int sde_hw_intr_get_interrupt_sources(struct sde_hw_intr *intr, + uint32_t *sources) +{ + if (!intr || !sources) + return -EINVAL; + + *sources = SDE_REG_READ(&intr->hw, HW_INTR_STATUS); + + return 0; +} + +static void sde_hw_intr_get_interrupt_statuses(struct sde_hw_intr *intr) +{ + int i; + u32 enable_mask; + unsigned long irq_flags; + + if (!intr) + return; + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + for (i = 0; i < intr->sde_irq_size; i++) { + /* Read interrupt status */ + intr->save_irq_status[i] = SDE_REG_READ(&intr->hw, + intr->sde_irq_tbl[i].status_off); + + /* Read enable mask */ + enable_mask = SDE_REG_READ(&intr->hw, + intr->sde_irq_tbl[i].en_off); + + /* and clear the interrupt */ + if (intr->save_irq_status[i]) + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[i].clr_off, + intr->save_irq_status[i]); + + /* Finally update IRQ status based on enable mask */ + intr->save_irq_status[i] &= enable_mask; + } + + /* ensure register writes go through */ + wmb(); + + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); +} + +static void sde_hw_intr_clear_intr_status_force_mask(struct sde_hw_intr *intr, + int irq_idx, u32 irq_mask) +{ + int reg_idx; + + if (!intr) + return; + + if (irq_idx >= intr->sde_irq_map_size || irq_idx < 0) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return; + } + + reg_idx = intr->sde_irq_map[irq_idx].reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return; + } + + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[reg_idx].clr_off, + irq_mask); + + /* ensure register writes go through */ + wmb(); +} + +static void sde_hw_intr_clear_intr_status_nolock(struct sde_hw_intr *intr, + int irq_idx) +{ + int reg_idx; + + if (!intr) + return; + + if (irq_idx >= intr->sde_irq_map_size || irq_idx < 0) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return; + } + + reg_idx = intr->sde_irq_map[irq_idx].reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return; + } + + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[reg_idx].clr_off, + intr->sde_irq_map[irq_idx].irq_mask); + + /* ensure register writes go through */ + wmb(); +} + +static void sde_hw_intr_clear_interrupt_status(struct sde_hw_intr *intr, + int irq_idx) +{ + unsigned long irq_flags; + + if (!intr) + return; + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + sde_hw_intr_clear_intr_status_nolock(intr, irq_idx); + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); +} + +static u32 sde_hw_intr_get_intr_status_nolock(struct sde_hw_intr *intr, + int irq_idx, bool clear) +{ + int reg_idx; + u32 intr_status; + + if (!intr) + return 0; + + if (irq_idx >= intr->sde_irq_map_size || irq_idx < 0) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return 0; + } + + reg_idx = intr->sde_irq_map[irq_idx].reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return 0; + } + + intr_status = SDE_REG_READ(&intr->hw, + intr->sde_irq_tbl[reg_idx].status_off) & + intr->sde_irq_map[irq_idx].irq_mask; + if (intr_status && clear) + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[reg_idx].clr_off, + intr_status); + + /* ensure register writes go through */ + wmb(); + + return intr_status; +} + +static u32 sde_hw_intr_get_interrupt_status(struct sde_hw_intr *intr, + int irq_idx, bool clear) +{ + int reg_idx; + unsigned long irq_flags; + u32 intr_status; + + if (!intr) + return 0; + + if (irq_idx >= intr->sde_irq_map_size || irq_idx < 0) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return 0; + } + + reg_idx = intr->sde_irq_map[irq_idx].reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return 0; + } + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + + intr_status = SDE_REG_READ(&intr->hw, + intr->sde_irq_tbl[reg_idx].status_off) & + intr->sde_irq_map[irq_idx].irq_mask; + if (intr_status && clear) + SDE_REG_WRITE(&intr->hw, intr->sde_irq_tbl[reg_idx].clr_off, + intr_status); + + /* ensure register writes go through */ + wmb(); + + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); + + return intr_status; +} + +static u32 sde_hw_intr_get_intr_status_nomask(struct sde_hw_intr *intr, + int irq_idx, bool clear) +{ + int reg_idx; + unsigned long irq_flags; + u32 intr_status = 0; + + if (!intr) + return 0; + + if (irq_idx >= intr->sde_irq_map_size || irq_idx < 0) { + pr_err("invalid IRQ index: [%d]\n", irq_idx); + return 0; + } + + reg_idx = intr->sde_irq_map[irq_idx].reg_idx; + if (reg_idx < 0 || reg_idx > intr->sde_irq_size) { + pr_err("invalid irq reg:%d irq:%d\n", reg_idx, irq_idx); + return 0; + } + + spin_lock_irqsave(&intr->irq_lock, irq_flags); + intr_status = SDE_REG_READ(&intr->hw, + intr->sde_irq_tbl[reg_idx].status_off); + spin_unlock_irqrestore(&intr->irq_lock, irq_flags); + + return intr_status; +} + +static void __setup_intr_ops(struct sde_hw_intr_ops *ops) +{ + ops->set_mask = sde_hw_intr_set_mask; + ops->irq_idx_lookup = sde_hw_intr_irqidx_lookup; + ops->enable_irq_nolock = sde_hw_intr_enable_irq_nolock; + ops->disable_irq_nolock = sde_hw_intr_disable_irq_nolock; + ops->dispatch_irqs = sde_hw_intr_dispatch_irq; + ops->clear_all_irqs = sde_hw_intr_clear_irqs; + ops->disable_all_irqs = sde_hw_intr_disable_irqs; + ops->get_valid_interrupts = sde_hw_intr_get_valid_interrupts; + ops->get_interrupt_sources = sde_hw_intr_get_interrupt_sources; + ops->get_interrupt_statuses = sde_hw_intr_get_interrupt_statuses; + ops->clear_interrupt_status = sde_hw_intr_clear_interrupt_status; + ops->clear_intr_status_nolock = sde_hw_intr_clear_intr_status_nolock; + ops->clear_intr_status_force_mask = + sde_hw_intr_clear_intr_status_force_mask; + ops->get_interrupt_status = sde_hw_intr_get_interrupt_status; + ops->get_intr_status_nolock = sde_hw_intr_get_intr_status_nolock; + ops->get_intr_status_nomask = sde_hw_intr_get_intr_status_nomask; +} + +static struct sde_mdss_base_cfg *__intr_offset(struct sde_mdss_cfg *m, + void __iomem *addr, struct sde_hw_blk_reg_map *hw) +{ + if (!m || !addr || !hw || m->mdp_count == 0) + return NULL; + + hw->base_off = addr; + hw->blk_off = m->mdss[0].base; + hw->hwversion = m->hwversion; + return &m->mdss[0]; +} + +static inline int _sde_hw_intr_init_sde_irq_tbl(u32 irq_tbl_size, + struct sde_intr_reg *sde_irq_tbl) +{ + int idx; + struct sde_intr_reg *sde_irq; + + for (idx = 0; idx < irq_tbl_size; idx++) { + sde_irq = &sde_irq_tbl[idx]; + + switch (sde_irq->sde_irq_idx) { + case MDSS_INTR_SSPP_TOP0_INTR: + sde_irq->clr_off = + MDP_SSPP_TOP0_OFF+INTR_CLEAR; + sde_irq->en_off = + MDP_SSPP_TOP0_OFF+INTR_EN; + sde_irq->status_off = + MDP_SSPP_TOP0_OFF+INTR_STATUS; + break; + case MDSS_INTR_SSPP_TOP0_INTR2: + sde_irq->clr_off = + MDP_SSPP_TOP0_OFF+INTR2_CLEAR; + sde_irq->en_off = + MDP_SSPP_TOP0_OFF+INTR2_EN; + sde_irq->status_off = + MDP_SSPP_TOP0_OFF+INTR2_STATUS; + break; + case MDSS_INTR_SSPP_TOP0_HIST_INTR: + sde_irq->clr_off = + MDP_SSPP_TOP0_OFF+HIST_INTR_CLEAR; + sde_irq->en_off = + MDP_SSPP_TOP0_OFF+HIST_INTR_EN; + sde_irq->status_off = + MDP_SSPP_TOP0_OFF+HIST_INTR_STATUS; + break; + case MDSS_INTR_INTF_0_INTR: + sde_irq->clr_off = + MDP_INTF_0_OFF+INTF_INTR_CLEAR; + sde_irq->en_off = + MDP_INTF_0_OFF+INTF_INTR_EN; + sde_irq->status_off = + MDP_INTF_0_OFF+INTF_INTR_STATUS; + break; + case MDSS_INTR_INTF_1_INTR: + sde_irq->clr_off = + MDP_INTF_1_OFF+INTF_INTR_CLEAR; + sde_irq->en_off = + MDP_INTF_1_OFF+INTF_INTR_EN; + sde_irq->status_off = + MDP_INTF_1_OFF+INTF_INTR_STATUS; + break; + case MDSS_INTR_INTF_2_INTR: + sde_irq->clr_off = + MDP_INTF_2_OFF+INTF_INTR_CLEAR; + sde_irq->en_off = + MDP_INTF_2_OFF+INTF_INTR_EN; + sde_irq->status_off = + MDP_INTF_2_OFF+INTF_INTR_STATUS; + break; + case MDSS_INTR_INTF_3_INTR: + sde_irq->clr_off = + MDP_INTF_3_OFF+INTF_INTR_CLEAR; + sde_irq->en_off = + MDP_INTF_3_OFF+INTF_INTR_EN; + sde_irq->status_off = + MDP_INTF_3_OFF+INTF_INTR_STATUS; + break; + case MDSS_INTR_INTF_4_INTR: + sde_irq->clr_off = + MDP_INTF_4_OFF+INTF_INTR_CLEAR; + sde_irq->en_off = + MDP_INTF_4_OFF+INTF_INTR_EN; + sde_irq->status_off = + MDP_INTF_4_OFF+INTF_INTR_STATUS; + break; + case MDSS_INTR_AD4_0_INTR: + sde_irq->clr_off = + MDP_AD4_0_OFF + MDP_AD4_INTR_CLEAR_OFF; + sde_irq->en_off = + MDP_AD4_0_OFF + MDP_AD4_INTR_EN_OFF; + sde_irq->status_off = + MDP_AD4_0_OFF + MDP_AD4_INTR_STATUS_OFF; + break; + case MDSS_INTR_AD4_1_INTR: + sde_irq->clr_off = + MDP_AD4_1_OFF + MDP_AD4_INTR_CLEAR_OFF; + sde_irq->en_off = + MDP_AD4_1_OFF + MDP_AD4_INTR_EN_OFF; + sde_irq->status_off = + MDP_AD4_1_OFF + MDP_AD4_INTR_STATUS_OFF; + break; + case MDSS_INTF_TEAR_1_INTR: + sde_irq->clr_off = MDP_INTF_TEAR_INTF_1_IRQ_OFF + + MDP_INTF_TEAR_INTR_CLEAR_OFF; + sde_irq->en_off = + MDP_INTF_TEAR_INTF_1_IRQ_OFF + + MDP_INTF_TEAR_INTR_EN_OFF; + sde_irq->status_off = MDP_INTF_TEAR_INTF_1_IRQ_OFF + + MDP_INTF_TEAR_INTR_STATUS_OFF; + break; + case MDSS_INTF_TEAR_2_INTR: + sde_irq->clr_off = MDP_INTF_TEAR_INTF_2_IRQ_OFF + + MDP_INTF_TEAR_INTR_CLEAR_OFF; + sde_irq->en_off = MDP_INTF_TEAR_INTF_2_IRQ_OFF + + MDP_INTF_TEAR_INTR_EN_OFF; + sde_irq->status_off = MDP_INTF_TEAR_INTF_2_IRQ_OFF + + MDP_INTF_TEAR_INTR_STATUS_OFF; + break; + case MDSS_INTR_LTM_0_INTR: + sde_irq->clr_off = + MDP_LTM_0_OFF + MDP_LTM_INTR_CLEAR_OFF; + sde_irq->en_off = + MDP_LTM_0_OFF + MDP_LTM_INTR_EN_OFF; + sde_irq->status_off = + MDP_LTM_0_OFF + MDP_LTM_INTR_STATUS_OFF; + break; + case MDSS_INTR_LTM_1_INTR: + sde_irq->clr_off = + MDP_LTM_1_OFF + MDP_LTM_INTR_CLEAR_OFF; + sde_irq->en_off = + MDP_LTM_1_OFF + MDP_LTM_INTR_EN_OFF; + sde_irq->status_off = + MDP_LTM_1_OFF + MDP_LTM_INTR_STATUS_OFF; + break; + default: + pr_err("wrong irq idx %d\n", + sde_irq->sde_irq_idx); + return -EINVAL; + } + + pr_debug("idx:%d irq_idx:%d clr:0x%x en:0x%x status:0x%x\n", + idx, sde_irq->sde_irq_idx, sde_irq->clr_off, + sde_irq->en_off, sde_irq->status_off); + } + + return 0; +} + +void sde_hw_intr_destroy(struct sde_hw_intr *intr) +{ + if (intr) { + kfree(intr->sde_irq_tbl); + kfree(intr->sde_irq_map); + kfree(intr->cache_irq_mask); + kfree(intr->save_irq_status); + kfree(intr); + } +} + +static inline u32 _get_irq_map_size(int idx) +{ + u32 ret = 0; + + switch (idx) { + case MDSS_INTR_SSPP_TOP0_INTR: + ret = ARRAY_SIZE(sde_irq_intr_map); + break; + case MDSS_INTR_SSPP_TOP0_INTR2: + ret = ARRAY_SIZE(sde_irq_intr2_map); + break; + case MDSS_INTR_SSPP_TOP0_HIST_INTR: + ret = ARRAY_SIZE(sde_irq_hist_map); + break; + case MDSS_INTR_INTF_0_INTR: + ret = ARRAY_SIZE(sde_irq_intf0_map); + break; + case MDSS_INTR_INTF_1_INTR: + ret = ARRAY_SIZE(sde_irq_inf1_map); + break; + case MDSS_INTR_INTF_2_INTR: + ret = ARRAY_SIZE(sde_irq_intf2_map); + break; + case MDSS_INTR_INTF_3_INTR: + ret = ARRAY_SIZE(sde_irq_intf3_map); + break; + case MDSS_INTR_INTF_4_INTR: + ret = ARRAY_SIZE(sde_irq_inf4_map); + break; + case MDSS_INTR_AD4_0_INTR: + ret = ARRAY_SIZE(sde_irq_ad4_0_map); + break; + case MDSS_INTR_AD4_1_INTR: + ret = ARRAY_SIZE(sde_irq_ad4_1_map); + break; + case MDSS_INTF_TEAR_1_INTR: + ret = ARRAY_SIZE(sde_irq_intf1_te_map); + break; + case MDSS_INTF_TEAR_2_INTR: + ret = ARRAY_SIZE(sde_irq_intf2_te_map); + break; + case MDSS_INTR_LTM_0_INTR: + ret = ARRAY_SIZE(sde_irq_ltm_0_map); + break; + case MDSS_INTR_LTM_1_INTR: + ret = ARRAY_SIZE(sde_irq_ltm_1_map); + break; + default: + pr_err("invalid idx:%d\n", idx); + } + + return ret; +} + +static inline struct sde_irq_type *_get_irq_map_addr(int idx) +{ + struct sde_irq_type *ret = NULL; + + switch (idx) { + case MDSS_INTR_SSPP_TOP0_INTR: + ret = sde_irq_intr_map; + break; + case MDSS_INTR_SSPP_TOP0_INTR2: + ret = sde_irq_intr2_map; + break; + case MDSS_INTR_SSPP_TOP0_HIST_INTR: + ret = sde_irq_hist_map; + break; + case MDSS_INTR_INTF_0_INTR: + ret = sde_irq_intf0_map; + break; + case MDSS_INTR_INTF_1_INTR: + ret = sde_irq_inf1_map; + break; + case MDSS_INTR_INTF_2_INTR: + ret = sde_irq_intf2_map; + break; + case MDSS_INTR_INTF_3_INTR: + ret = sde_irq_intf3_map; + break; + case MDSS_INTR_INTF_4_INTR: + ret = sde_irq_inf4_map; + break; + case MDSS_INTR_AD4_0_INTR: + ret = sde_irq_ad4_0_map; + break; + case MDSS_INTR_AD4_1_INTR: + ret = sde_irq_ad4_1_map; + break; + case MDSS_INTF_TEAR_1_INTR: + ret = sde_irq_intf1_te_map; + break; + case MDSS_INTF_TEAR_2_INTR: + ret = sde_irq_intf2_te_map; + break; + case MDSS_INTR_LTM_0_INTR: + ret = sde_irq_ltm_0_map; + break; + case MDSS_INTR_LTM_1_INTR: + ret = sde_irq_ltm_1_map; + break; + default: + pr_err("invalid idx:%d\n", idx); + } + + return ret; +} + +static int _sde_copy_regs(struct sde_irq_type *sde_irq_map, u32 size, + u32 irq_idx, u32 low_idx, u32 high_idx) +{ + int i, j = 0; + struct sde_irq_type *src = _get_irq_map_addr(irq_idx); + u32 src_size = _get_irq_map_size(irq_idx); + + if (!src) + return -EINVAL; + + if (low_idx >= size || high_idx > size || + (high_idx - low_idx > src_size)) { + pr_err("invalid size l:%d h:%d dst:%d src:%d\n", + low_idx, high_idx, size, src_size); + return -EINVAL; + } + + for (i = low_idx; i < high_idx; i++) + sde_irq_map[i] = src[j++]; + + return 0; +} + +static int _sde_hw_intr_init_irq_tables(struct sde_hw_intr *intr, + struct sde_mdss_cfg *m) +{ + int i, idx, sde_irq_tbl_idx = 0, ret = 0; + u32 low_idx, high_idx; + u32 sde_irq_map_idx = 0; + + /* Initialize the offset of the irq's in the sde_irq_map table */ + for (idx = 0; idx < MDSS_INTR_MAX; idx++) { + if (test_bit(idx, m->mdss_irqs)) { + low_idx = sde_irq_map_idx; + high_idx = low_idx + _get_irq_map_size(idx); + + pr_debug("init[%d]=%d low:%d high:%d\n", + sde_irq_tbl_idx, idx, low_idx, high_idx); + + if (sde_irq_tbl_idx >= intr->sde_irq_size || + sde_irq_tbl_idx < 0) { + ret = -EINVAL; + goto exit; + } + + /* init sde_irq_map with the global irq mapping table */ + if (_sde_copy_regs(intr->sde_irq_map, + intr->sde_irq_map_size, + idx, low_idx, high_idx)) { + ret = -EINVAL; + goto exit; + } + + /* init irq map with its reg idx within the irq tbl */ + for (i = low_idx; i < high_idx; i++) { + intr->sde_irq_map[i].reg_idx = sde_irq_tbl_idx; + pr_debug("sde_irq_map[%d].reg_idx=%d\n", + i, sde_irq_tbl_idx); + } + + /* track the idx of the mapping table for this irq in + * sde_irq_map, this to only access the indexes of this + * irq during the irq dispatch + */ + intr->sde_irq_tbl[sde_irq_tbl_idx].sde_irq_idx = idx; + intr->sde_irq_tbl[sde_irq_tbl_idx].map_idx_start = + low_idx; + intr->sde_irq_tbl[sde_irq_tbl_idx].map_idx_end = + high_idx; + + /* increment idx for both tables accordingly */ + sde_irq_tbl_idx++; + sde_irq_map_idx = high_idx; + } + } + + /* do this after 'sde_irq_idx is initialized in sde_irq_tbl */ + ret = _sde_hw_intr_init_sde_irq_tbl(intr->sde_irq_size, + intr->sde_irq_tbl); + +exit: + return ret; +} + +struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_intr *intr = NULL; + struct sde_mdss_base_cfg *cfg; + u32 irq_regs_count = 0; + u32 irq_map_count = 0; + u32 size; + int idx; + int ret = 0; + + if (!addr || !m) { + ret = -EINVAL; + goto exit; + } + + intr = kzalloc(sizeof(*intr), GFP_KERNEL); + if (!intr) { + ret = -ENOMEM; + goto exit; + } + + cfg = __intr_offset(m, addr, &intr->hw); + if (!cfg) { + ret = -EINVAL; + goto exit; + } + __setup_intr_ops(&intr->ops); + + if (MDSS_INTR_MAX >= UINT_MAX) { + pr_err("max intr exceeded:%d\n", MDSS_INTR_MAX); + ret = -EINVAL; + goto exit; + } + + /* check how many irq's this target supports */ + for (idx = 0; idx < MDSS_INTR_MAX; idx++) { + if (test_bit(idx, m->mdss_irqs)) { + irq_regs_count++; + + size = _get_irq_map_size(idx); + if (!size || irq_map_count >= UINT_MAX - size) { + pr_err("wrong map cnt idx:%d sz:%d cnt:%d\n", + idx, size, irq_map_count); + ret = -EINVAL; + goto exit; + } + + irq_map_count += size; + } + } + + if (irq_regs_count == 0 || irq_regs_count > MDSS_INTR_MAX || + irq_map_count == 0) { + pr_err("wrong mapping of supported irqs 0x%lx\n", + m->mdss_irqs[0]); + ret = -EINVAL; + goto exit; + } + + /* Allocate table for the irq registers */ + intr->sde_irq_size = irq_regs_count; + intr->sde_irq_tbl = kcalloc(irq_regs_count, sizeof(*intr->sde_irq_tbl), + GFP_KERNEL); + if (intr->sde_irq_tbl == NULL) { + ret = -ENOMEM; + goto exit; + } + + /* Allocate table with the valid interrupts bits */ + intr->sde_irq_map_size = irq_map_count; + intr->sde_irq_map = kcalloc(irq_map_count, sizeof(*intr->sde_irq_map), + GFP_KERNEL); + if (intr->sde_irq_map == NULL) { + ret = -ENOMEM; + goto exit; + } + + /* Initialize IRQs tables */ + ret = _sde_hw_intr_init_irq_tables(intr, m); + if (ret) + goto exit; + + intr->cache_irq_mask = kcalloc(intr->sde_irq_size, + sizeof(*intr->cache_irq_mask), GFP_KERNEL); + if (intr->cache_irq_mask == NULL) { + ret = -ENOMEM; + goto exit; + } + + intr->save_irq_status = kcalloc(intr->sde_irq_size, + sizeof(*intr->save_irq_status), GFP_KERNEL); + if (intr->save_irq_status == NULL) { + ret = -ENOMEM; + goto exit; + } + + spin_lock_init(&intr->irq_lock); + +exit: + if (ret) { + sde_hw_intr_destroy(intr); + return ERR_PTR(ret); + } + + return intr; +} + diff --git a/techpack/display/msm/sde/sde_hw_interrupts.h b/techpack/display/msm/sde/sde_hw_interrupts.h new file mode 100644 index 0000000000000000000000000000000000000000..2be78655cc04a7a0c98416144549973fe415be73 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_interrupts.h @@ -0,0 +1,317 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_INTERRUPTS_H +#define _SDE_HW_INTERRUPTS_H + +#include <linux/types.h> + +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_util.h" +#include "sde_hw_mdss.h" + +#define IRQ_SOURCE_MDP BIT(0) +#define IRQ_SOURCE_DSI0 BIT(4) +#define IRQ_SOURCE_DSI1 BIT(5) +#define IRQ_SOURCE_HDMI BIT(8) +#define IRQ_SOURCE_EDP BIT(12) +#define IRQ_SOURCE_MHL BIT(16) + +/** + * sde_intr_type - HW Interrupt Type + * @SDE_IRQ_TYPE_WB_ROT_COMP: WB rotator done + * @SDE_IRQ_TYPE_WB_WFD_COMP: WB WFD done + * @SDE_IRQ_TYPE_PING_PONG_COMP: PingPong done + * @SDE_IRQ_TYPE_PING_PONG_RD_PTR: PingPong read pointer + * @SDE_IRQ_TYPE_PING_PONG_WR_PTR: PingPong write pointer + * @SDE_IRQ_TYPE_PING_PONG_AUTO_REF: PingPong auto refresh + * @SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK: PingPong Tear check + * @SDE_IRQ_TYPE_PING_PONG_TE_CHECK: PingPong TE detection + * @SDE_IRQ_TYPE_INTF_UNDER_RUN: INTF underrun + * @SDE_IRQ_TYPE_INTF_VSYNC: INTF VSYNC + * @SDE_IRQ_TYPE_CWB_OVERFLOW: Concurrent WB overflow + * @SDE_IRQ_TYPE_HIST_VIG_DONE: VIG Histogram done + * @SDE_IRQ_TYPE_HIST_VIG_RSTSEQ: VIG Histogram reset + * @SDE_IRQ_TYPE_HIST_DSPP_DONE: DSPP Histogram done + * @SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ: DSPP Histogram reset + * @SDE_IRQ_TYPE_WD_TIMER: Watchdog timer + * @SDE_IRQ_TYPE_SFI_VIDEO_IN: Video static frame INTR into static + * @SDE_IRQ_TYPE_SFI_VIDEO_OUT: Video static frame INTR out-of static + * @SDE_IRQ_TYPE_SFI_CMD_0_IN: DSI CMD0 static frame INTR into static + * @SDE_IRQ_TYPE_SFI_CMD_0_OUT: DSI CMD0 static frame INTR out-of static + * @SDE_IRQ_TYPE_SFI_CMD_1_IN: DSI CMD1 static frame INTR into static + * @SDE_IRQ_TYPE_SFI_CMD_1_OUT: DSI CMD1 static frame INTR out-of static + * @SDE_IRQ_TYPE_SFI_CMD_2_IN: DSI CMD2 static frame INTR into static + * @SDE_IRQ_TYPE_SFI_CMD_2_OUT: DSI CMD2 static frame INTR out-of static + * @SDE_IRQ_TYPE_PROG_LINE: Programmable Line interrupt + * @SDE_IRQ_TYPE_AD4_BL_DONE: AD4 backlight + * @SDE_IRQ_TYPE_CTL_START: Control start + * @SDE_IRQ_TYPE_INTF_TEAR_RD_PTR: INTF Tear read pointer + * @SDE_IRQ_TYPE_INTF_TEAR_WR_PTR: INTF Tear write pointer + * @SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF: INTF Tear auto refresh + * @SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK: INTF Tear Tear check + * @SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK: INTF Tear TE detection + * @SDE_IRQ_TYPE_LTM_STATS_DONE: LTM stats done interrupt + * @SDE_IRQ_TYPE_LTM_STATS_WB_PB: LTM stats WB push back interrupt + * @SDE_IRQ_TYPE_RESERVED: Reserved for expansion + */ +enum sde_intr_type { + SDE_IRQ_TYPE_WB_ROT_COMP, + SDE_IRQ_TYPE_WB_WFD_COMP, + SDE_IRQ_TYPE_PING_PONG_COMP, + SDE_IRQ_TYPE_PING_PONG_RD_PTR, + SDE_IRQ_TYPE_PING_PONG_WR_PTR, + SDE_IRQ_TYPE_PING_PONG_AUTO_REF, + SDE_IRQ_TYPE_PING_PONG_TEAR_CHECK, + SDE_IRQ_TYPE_PING_PONG_TE_CHECK, + SDE_IRQ_TYPE_INTF_UNDER_RUN, + SDE_IRQ_TYPE_INTF_VSYNC, + SDE_IRQ_TYPE_CWB_OVERFLOW, + SDE_IRQ_TYPE_HIST_VIG_DONE, + SDE_IRQ_TYPE_HIST_VIG_RSTSEQ, + SDE_IRQ_TYPE_HIST_DSPP_DONE, + SDE_IRQ_TYPE_HIST_DSPP_RSTSEQ, + SDE_IRQ_TYPE_WD_TIMER, + SDE_IRQ_TYPE_SFI_VIDEO_IN, + SDE_IRQ_TYPE_SFI_VIDEO_OUT, + SDE_IRQ_TYPE_SFI_CMD_0_IN, + SDE_IRQ_TYPE_SFI_CMD_0_OUT, + SDE_IRQ_TYPE_SFI_CMD_1_IN, + SDE_IRQ_TYPE_SFI_CMD_1_OUT, + SDE_IRQ_TYPE_SFI_CMD_2_IN, + SDE_IRQ_TYPE_SFI_CMD_2_OUT, + SDE_IRQ_TYPE_PROG_LINE, + SDE_IRQ_TYPE_AD4_BL_DONE, + SDE_IRQ_TYPE_CTL_START, + SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, + SDE_IRQ_TYPE_INTF_TEAR_WR_PTR, + SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF, + SDE_IRQ_TYPE_INTF_TEAR_TEAR_CHECK, + SDE_IRQ_TYPE_INTF_TEAR_TE_CHECK, + SDE_IRQ_TYPE_LTM_STATS_DONE, + SDE_IRQ_TYPE_LTM_STATS_WB_PB, + SDE_IRQ_TYPE_RESERVED, +}; + +struct sde_hw_intr; + +/** + * Interrupt operations. + */ +struct sde_hw_intr_ops { + /** + * set_mask - Programs the given interrupt register with the + * given interrupt mask. Register value will get overwritten. + * @intr: HW interrupt handle + * @reg_off: MDSS HW register offset + * @irqmask: IRQ mask value + */ + void (*set_mask)( + struct sde_hw_intr *intr, + uint32_t reg, + uint32_t irqmask); + + /** + * irq_idx_lookup - Lookup IRQ index on the HW interrupt type + * Used for all irq related ops + * @intr: HW interrupt handle + * @intr_type: Interrupt type defined in sde_intr_type + * @instance_idx: HW interrupt block instance + * @return: irq_idx or -EINVAL for lookup fail + */ + int (*irq_idx_lookup)( + struct sde_hw_intr *intr, + enum sde_intr_type intr_type, + u32 instance_idx); + + /** + * enable_irq_nolock - Enable IRQ based on lookup IRQ index without lock + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @return: 0 for success, otherwise failure + */ + int (*enable_irq_nolock)( + struct sde_hw_intr *intr, + int irq_idx); + + /** + * disable_irq_nolock - Disable IRQ based on IRQ index without lock + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @return: 0 for success, otherwise failure + */ + int (*disable_irq_nolock)( + struct sde_hw_intr *intr, + int irq_idx); + + /** + * clear_all_irqs - Clears all the interrupts (i.e. acknowledges + * any asserted IRQs). Useful during reset. + * @intr: HW interrupt handle + * @return: 0 for success, otherwise failure + */ + int (*clear_all_irqs)( + struct sde_hw_intr *intr); + + /** + * disable_all_irqs - Disables all the interrupts. Useful during reset. + * @intr: HW interrupt handle + * @return: 0 for success, otherwise failure + */ + int (*disable_all_irqs)( + struct sde_hw_intr *intr); + + /** + * dispatch_irqs - IRQ dispatcher will call the given callback + * function when a matching interrupt status bit is + * found in the irq mapping table. + * @intr: HW interrupt handle + * @cbfunc: Callback function pointer + * @arg: Argument to pass back during callback + */ + void (*dispatch_irqs)( + struct sde_hw_intr *intr, + void (*cbfunc)(void *arg, int irq_idx), + void *arg); + + /** + * get_interrupt_statuses - Gets and store value from all interrupt + * status registers that are currently fired. + * @intr: HW interrupt handle + */ + void (*get_interrupt_statuses)( + struct sde_hw_intr *intr); + + /** + * clear_interrupt_status - Clears HW interrupt status based on given + * lookup IRQ index. + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + */ + void (*clear_interrupt_status)( + struct sde_hw_intr *intr, + int irq_idx); + + /** + * clear_intr_status_nolock() - clears the HW interrupts without lock + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + */ + void (*clear_intr_status_nolock)( + struct sde_hw_intr *intr, + int irq_idx); + + /** + * clear_intr_status_force_mask() - clear the HW interrupts + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @irq_mask: irq mask to clear + */ + void (*clear_intr_status_force_mask)( + struct sde_hw_intr *intr, + int irq_idx, + u32 irq_mask); + + /** + * get_interrupt_status - Gets HW interrupt status, and clear if set, + * based on given lookup IRQ index. + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @clear: True to clear irq after read + */ + u32 (*get_interrupt_status)( + struct sde_hw_intr *intr, + int irq_idx, + bool clear); + + /** + * get_intr_status_nolock - nolock version of get_interrupt_status + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @clear: True to clear irq after read + */ + u32 (*get_intr_status_nolock)( + struct sde_hw_intr *intr, + int irq_idx, + bool clear); + + /** + * get_intr_status_nomask - nolock version of get_interrupt_status + * @intr: HW interrupt handle + * @irq_idx: Lookup irq index return from irq_idx_lookup + * @clear: True to clear irq after read + */ + u32 (*get_intr_status_nomask)( + struct sde_hw_intr *intr, + int irq_idx, + bool clear); + + /** + * get_valid_interrupts - Gets a mask of all valid interrupt sources + * within SDE. These are actually status bits + * within interrupt registers that specify the + * source of the interrupt in IRQs. For example, + * valid interrupt sources can be MDP, DSI, + * HDMI etc. + * @intr: HW interrupt handle + * @mask: Returning the interrupt source MASK + * @return: 0 for success, otherwise failure + */ + int (*get_valid_interrupts)( + struct sde_hw_intr *intr, + uint32_t *mask); + + /** + * get_interrupt_sources - Gets the bitmask of the SDE interrupt + * source that are currently fired. + * @intr: HW interrupt handle + * @sources: Returning the SDE interrupt source status bit mask + * @return: 0 for success, otherwise failure + */ + int (*get_interrupt_sources)( + struct sde_hw_intr *intr, + uint32_t *sources); +}; + +/** + * struct sde_hw_intr: hw interrupts handling data structure + * @hw: virtual address mapping + * @ops: function pointer mapping for IRQ handling + * @cache_irq_mask: array of IRQ enable masks reg storage created during init + * @save_irq_status: array of IRQ status reg storage created during init + * @irq_lock: spinlock for accessing IRQ resources + * @sde_irq_size: total number of elements of the sde_irq_tbl + * @sde_irq_tbl: table with the registesrs offsets of the sde interrupts + * supported by the hw + * @sde_irq_map_size: total number of elements of the 'sde_irq_map' + * @sde_irq_map: total number of interrupt bits valid within the irq regs + */ +struct sde_hw_intr { + struct sde_hw_blk_reg_map hw; + struct sde_hw_intr_ops ops; + u32 *cache_irq_mask; + u32 *save_irq_status; + u32 sde_irq_size; + struct sde_intr_reg *sde_irq_tbl; + u32 sde_irq_map_size; + struct sde_irq_type *sde_irq_map; + spinlock_t irq_lock; +}; + +/** + * sde_hw_intr_init(): Initializes the interrupts hw object + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct sde_hw_intr *sde_hw_intr_init(void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_intr_destroy(): Cleanup interrutps hw object + * @intr: pointer to interrupts hw object + */ +void sde_hw_intr_destroy(struct sde_hw_intr *intr); +#endif diff --git a/techpack/display/msm/sde/sde_hw_intf.c b/techpack/display/msm/sde/sde_hw_intf.c new file mode 100644 index 0000000000000000000000000000000000000000..f6ac497016571552a763ba320ee11faaa985795b --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_intf.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ +#include <linux/iopoll.h> + +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_intf.h" +#include "sde_dbg.h" + +#define INTF_TIMING_ENGINE_EN 0x000 +#define INTF_CONFIG 0x004 +#define INTF_HSYNC_CTL 0x008 +#define INTF_VSYNC_PERIOD_F0 0x00C +#define INTF_VSYNC_PERIOD_F1 0x010 +#define INTF_VSYNC_PULSE_WIDTH_F0 0x014 +#define INTF_VSYNC_PULSE_WIDTH_F1 0x018 +#define INTF_DISPLAY_V_START_F0 0x01C +#define INTF_DISPLAY_V_START_F1 0x020 +#define INTF_DISPLAY_V_END_F0 0x024 +#define INTF_DISPLAY_V_END_F1 0x028 +#define INTF_ACTIVE_V_START_F0 0x02C +#define INTF_ACTIVE_V_START_F1 0x030 +#define INTF_ACTIVE_V_END_F0 0x034 +#define INTF_ACTIVE_V_END_F1 0x038 +#define INTF_DISPLAY_HCTL 0x03C +#define INTF_ACTIVE_HCTL 0x040 +#define INTF_BORDER_COLOR 0x044 +#define INTF_UNDERFLOW_COLOR 0x048 +#define INTF_HSYNC_SKEW 0x04C +#define INTF_POLARITY_CTL 0x050 +#define INTF_TEST_CTL 0x054 +#define INTF_TP_COLOR0 0x058 +#define INTF_TP_COLOR1 0x05C +#define INTF_CONFIG2 0x060 +#define INTF_DISPLAY_DATA_HCTL 0x064 +#define INTF_ACTIVE_DATA_HCTL 0x068 +#define INTF_FRAME_LINE_COUNT_EN 0x0A8 +#define INTF_FRAME_COUNT 0x0AC +#define INTF_LINE_COUNT 0x0B0 + +#define INTF_DEFLICKER_CONFIG 0x0F0 +#define INTF_DEFLICKER_STRNG_COEFF 0x0F4 +#define INTF_DEFLICKER_WEAK_COEFF 0x0F8 + +#define INTF_REG_SPLIT_LINK 0x080 +#define INTF_DSI_CMD_MODE_TRIGGER_EN 0x084 +#define INTF_PANEL_FORMAT 0x090 +#define INTF_TPG_ENABLE 0x100 +#define INTF_TPG_MAIN_CONTROL 0x104 +#define INTF_TPG_VIDEO_CONFIG 0x108 +#define INTF_TPG_COMPONENT_LIMITS 0x10C +#define INTF_TPG_RECTANGLE 0x110 +#define INTF_TPG_INITIAL_VALUE 0x114 +#define INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118 +#define INTF_TPG_RGB_MAPPING 0x11C +#define INTF_PROG_FETCH_START 0x170 +#define INTF_PROG_ROT_START 0x174 + +#define INTF_MISR_CTRL 0x180 +#define INTF_MISR_SIGNATURE 0x184 + +#define INTF_MUX 0x25C +#define INTF_STATUS 0x26C +#define INTF_AVR_CONTROL 0x270 +#define INTF_AVR_MODE 0x274 +#define INTF_AVR_TRIGGER 0x278 +#define INTF_AVR_VTOTAL 0x27C +#define INTF_TEAR_MDP_VSYNC_SEL 0x280 +#define INTF_TEAR_TEAR_CHECK_EN 0x284 +#define INTF_TEAR_SYNC_CONFIG_VSYNC 0x288 +#define INTF_TEAR_SYNC_CONFIG_HEIGHT 0x28C +#define INTF_TEAR_SYNC_WRCOUNT 0x290 +#define INTF_TEAR_VSYNC_INIT_VAL 0x294 +#define INTF_TEAR_INT_COUNT_VAL 0x298 +#define INTF_TEAR_SYNC_THRESH 0x29C +#define INTF_TEAR_START_POS 0x2A0 +#define INTF_TEAR_RD_PTR_IRQ 0x2A4 +#define INTF_TEAR_WR_PTR_IRQ 0x2A8 +#define INTF_TEAR_OUT_LINE_COUNT 0x2AC +#define INTF_TEAR_LINE_COUNT 0x2B0 +#define INTF_TEAR_AUTOREFRESH_CONFIG 0x2B4 +#define INTF_TEAR_TEAR_DETECT_CTRL 0x2B8 + +static struct sde_intf_cfg *_intf_offset(enum sde_intf intf, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->intf_count; i++) { + if ((intf == m->intf[i].id) && + (m->intf[i].type != INTF_NONE)) { + b->base_off = addr; + b->blk_off = m->intf[i].base; + b->length = m->intf[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_INTF; + return &m->intf[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static void sde_hw_intf_avr_trigger(struct sde_hw_intf *ctx) +{ + struct sde_hw_blk_reg_map *c; + + if (!ctx) + return; + + c = &ctx->hw; + SDE_REG_WRITE(c, INTF_AVR_TRIGGER, 0x1); + SDE_DEBUG("AVR Triggered\n"); +} + +static int sde_hw_intf_avr_setup(struct sde_hw_intf *ctx, + const struct intf_timing_params *params, + const struct intf_avr_params *avr_params) +{ + struct sde_hw_blk_reg_map *c; + u32 hsync_period, vsync_period; + u32 min_fps, default_fps, diff_fps; + u32 vsync_period_slow; + u32 avr_vtotal; + u32 add_porches = 0; + + if (!ctx || !params || !avr_params) { + SDE_ERROR("invalid input parameter(s)\n"); + return -EINVAL; + } + + c = &ctx->hw; + min_fps = avr_params->min_fps; + default_fps = avr_params->default_fps; + diff_fps = default_fps - min_fps; + hsync_period = params->hsync_pulse_width + + params->h_back_porch + params->width + + params->h_front_porch; + vsync_period = params->vsync_pulse_width + + params->v_back_porch + params->height + + params->v_front_porch; + + if (diff_fps) + add_porches = mult_frac(vsync_period, diff_fps, min_fps); + + vsync_period_slow = vsync_period + add_porches; + avr_vtotal = vsync_period_slow * hsync_period; + + SDE_REG_WRITE(c, INTF_AVR_VTOTAL, avr_vtotal); + + return 0; +} + +static void sde_hw_intf_avr_ctrl(struct sde_hw_intf *ctx, + const struct intf_avr_params *avr_params) +{ + struct sde_hw_blk_reg_map *c; + u32 avr_mode = 0; + u32 avr_ctrl = 0; + + if (!ctx || !avr_params) + return; + + c = &ctx->hw; + if (avr_params->avr_mode) { + avr_ctrl = BIT(0); + avr_mode = + (avr_params->avr_mode == SDE_RM_QSYNC_ONE_SHOT_MODE) ? + (BIT(0) | BIT(8)) : 0x0; + } + + SDE_REG_WRITE(c, INTF_AVR_CONTROL, avr_ctrl); + SDE_REG_WRITE(c, INTF_AVR_MODE, avr_mode); +} + + +static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, + const struct intf_timing_params *p, + const struct sde_format *fmt) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 hsync_period, vsync_period; + u32 display_v_start, display_v_end; + u32 hsync_start_x, hsync_end_x; + u32 active_h_start, active_h_end; + u32 active_v_start, active_v_end; + u32 active_hctl, display_hctl, hsync_ctl; + u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity; + u32 panel_format; + u32 intf_cfg, intf_cfg2; + u32 display_data_hctl = 0, active_data_hctl = 0; + bool dp_intf = false; + + /* read interface_cfg */ + intf_cfg = SDE_REG_READ(c, INTF_CONFIG); + hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width + + p->h_front_porch; + vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height + + p->v_front_porch; + + display_v_start = ((p->vsync_pulse_width + p->v_back_porch) * + hsync_period) + p->hsync_skew; + display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) + + p->hsync_skew - 1; + + hsync_start_x = p->h_back_porch + p->hsync_pulse_width; + hsync_end_x = hsync_period - p->h_front_porch - 1; + + if (ctx->cap->type == INTF_EDP || ctx->cap->type == INTF_DP) + dp_intf = true; + + if (p->width != p->xres) { + active_h_start = hsync_start_x; + active_h_end = active_h_start + p->xres - 1; + } else { + active_h_start = 0; + active_h_end = 0; + } + + if (p->height != p->yres) { + active_v_start = display_v_start; + active_v_end = active_v_start + (p->yres * hsync_period) - 1; + } else { + active_v_start = 0; + active_v_end = 0; + } + + if (active_h_end) { + active_hctl = (active_h_end << 16) | active_h_start; + intf_cfg |= BIT(29); /* ACTIVE_H_ENABLE */ + } else { + active_hctl = 0; + } + + if (active_v_end) + intf_cfg |= BIT(30); /* ACTIVE_V_ENABLE */ + + hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width; + display_hctl = (hsync_end_x << 16) | hsync_start_x; + + if (dp_intf) { + active_h_start = hsync_start_x; + active_h_end = active_h_start + p->xres - 1; + active_v_start = display_v_start; + active_v_end = active_v_start + (p->yres * hsync_period) - 1; + + display_v_start += p->hsync_pulse_width + p->h_back_porch; + + active_hctl = (active_h_end << 16) | active_h_start; + display_hctl = active_hctl; + } + + intf_cfg2 = 0; + + if (dp_intf && p->compression_en) { + active_data_hctl = (hsync_start_x + p->extra_dto_cycles) << 16; + active_data_hctl += hsync_start_x; + + display_data_hctl = active_data_hctl; + + intf_cfg2 |= BIT(4); + } + + den_polarity = 0; + if (ctx->cap->type == INTF_HDMI) { + hsync_polarity = p->yres >= 720 ? 0 : 1; + vsync_polarity = p->yres >= 720 ? 0 : 1; + } else if (ctx->cap->type == INTF_DP) { + hsync_polarity = p->hsync_polarity; + vsync_polarity = p->vsync_polarity; + } else { + hsync_polarity = 0; + vsync_polarity = 0; + } + polarity_ctl = (den_polarity << 2) | /* DEN Polarity */ + (vsync_polarity << 1) | /* VSYNC Polarity */ + (hsync_polarity << 0); /* HSYNC Polarity */ + + if (!SDE_FORMAT_IS_YUV(fmt)) + panel_format = (fmt->bits[C0_G_Y] | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C2_R_Cr] << 4) | + (0x21 << 8)); + else + /* Interface treats all the pixel data in RGB888 format */ + panel_format = (COLOR_8BIT | + (COLOR_8BIT << 2) | + (COLOR_8BIT << 4) | + (0x21 << 8)); + + if (p->wide_bus_en) + intf_cfg2 |= BIT(0); + + if (ctx->cfg.split_link_en) + SDE_REG_WRITE(c, INTF_REG_SPLIT_LINK, 0x3); + + SDE_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl); + SDE_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period); + SDE_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0, + p->vsync_pulse_width * hsync_period); + SDE_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl); + SDE_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start); + SDE_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end); + SDE_REG_WRITE(c, INTF_ACTIVE_HCTL, active_hctl); + SDE_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start); + SDE_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end); + SDE_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr); + SDE_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr); + SDE_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew); + SDE_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl); + SDE_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3); + SDE_REG_WRITE(c, INTF_CONFIG, intf_cfg); + SDE_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format); + SDE_REG_WRITE(c, INTF_CONFIG2, intf_cfg2); + SDE_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl); + SDE_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl); +} + +static void sde_hw_intf_enable_timing_engine( + struct sde_hw_intf *intf, + u8 enable) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + /* Note: Display interface select is handled in top block hw layer */ + SDE_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0); +} + +static void sde_hw_intf_setup_prg_fetch( + struct sde_hw_intf *intf, + const struct intf_prog_fetch *fetch) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + int fetch_enable; + + /* + * Fetch should always be outside the active lines. If the fetching + * is programmed within active region, hardware behavior is unknown. + */ + + fetch_enable = SDE_REG_READ(c, INTF_CONFIG); + if (fetch->enable) { + fetch_enable |= BIT(31); + SDE_REG_WRITE(c, INTF_PROG_FETCH_START, + fetch->fetch_start); + } else { + fetch_enable &= ~BIT(31); + } + + SDE_REG_WRITE(c, INTF_CONFIG, fetch_enable); +} + +static void sde_hw_intf_bind_pingpong_blk( + struct sde_hw_intf *intf, + bool enable, + const enum sde_pingpong pp) +{ + struct sde_hw_blk_reg_map *c; + u32 mux_cfg; + + if (!intf) + return; + + c = &intf->hw; + + mux_cfg = SDE_REG_READ(c, INTF_MUX); + mux_cfg &= ~0xf; + + if (enable) { + mux_cfg |= (pp - PINGPONG_0) & 0x7; + if (intf->cfg.split_link_en) + mux_cfg = 0x60000; + } else { + mux_cfg = 0xf000f; + } + + SDE_REG_WRITE(c, INTF_MUX, mux_cfg); +} + +static void sde_hw_intf_get_status( + struct sde_hw_intf *intf, + struct intf_status *s) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + + s->is_en = SDE_REG_READ(c, INTF_TIMING_ENGINE_EN); + if (s->is_en) { + s->frame_count = SDE_REG_READ(c, INTF_FRAME_COUNT); + s->line_count = SDE_REG_READ(c, INTF_LINE_COUNT); + } else { + s->line_count = 0; + s->frame_count = 0; + } +} + +static void sde_hw_intf_v1_get_status( + struct sde_hw_intf *intf, + struct intf_status *s) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + + s->is_en = SDE_REG_READ(c, INTF_STATUS) & BIT(0); + if (s->is_en) { + s->frame_count = SDE_REG_READ(c, INTF_FRAME_COUNT); + s->line_count = SDE_REG_READ(c, INTF_LINE_COUNT); + } else { + s->line_count = 0; + s->frame_count = 0; + } +} +static void sde_hw_intf_setup_misr(struct sde_hw_intf *intf, + bool enable, u32 frame_count) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + u32 config = 0; + + SDE_REG_WRITE(c, INTF_MISR_CTRL, MISR_CTRL_STATUS_CLEAR); + /* clear misr data */ + wmb(); + + if (enable) + config = (frame_count & MISR_FRAME_COUNT_MASK) | + MISR_CTRL_ENABLE | + INTF_MISR_CTRL_FREE_RUN_MASK | + INTF_MISR_CTRL_INPUT_SEL_DATA; + + SDE_REG_WRITE(c, INTF_MISR_CTRL, config); +} + +static int sde_hw_intf_collect_misr(struct sde_hw_intf *intf, bool nonblock, + u32 *misr_value) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + u32 ctrl = 0; + + if (!misr_value) + return -EINVAL; + + ctrl = SDE_REG_READ(c, INTF_MISR_CTRL); + if (!nonblock) { + if (ctrl & MISR_CTRL_ENABLE) { + int rc; + + rc = readl_poll_timeout(c->base_off + c->blk_off + + INTF_MISR_CTRL, ctrl, + (ctrl & MISR_CTRL_STATUS) > 0, 500, + 84000); + if (rc) + return rc; + } else { + return -EINVAL; + } + } + + *misr_value = SDE_REG_READ(c, INTF_MISR_SIGNATURE); + return 0; +} + +static u32 sde_hw_intf_get_line_count(struct sde_hw_intf *intf) +{ + struct sde_hw_blk_reg_map *c; + + if (!intf) + return 0; + + c = &intf->hw; + + return SDE_REG_READ(c, INTF_LINE_COUNT); +} + +static int sde_hw_intf_setup_te_config(struct sde_hw_intf *intf, + struct sde_hw_tear_check *te) +{ + struct sde_hw_blk_reg_map *c; + int cfg; + + if (!intf) + return -EINVAL; + + c = &intf->hw; + + cfg = BIT(19); /* VSYNC_COUNTER_EN */ + if (te->hw_vsync_mode) + cfg |= BIT(20); + + cfg |= te->vsync_count; + + SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); + SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); + SDE_REG_WRITE(c, INTF_TEAR_VSYNC_INIT_VAL, te->vsync_init_val); + SDE_REG_WRITE(c, INTF_TEAR_RD_PTR_IRQ, te->rd_ptr_irq); + SDE_REG_WRITE(c, INTF_TEAR_WR_PTR_IRQ, te->wr_ptr_irq); + SDE_REG_WRITE(c, INTF_TEAR_START_POS, te->start_pos); + SDE_REG_WRITE(c, INTF_TEAR_SYNC_THRESH, + ((te->sync_threshold_continue << 16) | + te->sync_threshold_start)); + SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, + (te->start_pos + te->sync_threshold_start + 1)); + + return 0; +} + +static int sde_hw_intf_setup_autorefresh_config(struct sde_hw_intf *intf, + struct sde_hw_autorefresh *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 refresh_cfg; + + if (!intf || !cfg) + return -EINVAL; + + c = &intf->hw; + + refresh_cfg = SDE_REG_READ(c, INTF_TEAR_AUTOREFRESH_CONFIG); + if (cfg->enable) + refresh_cfg = BIT(31) | cfg->frame_count; + else + refresh_cfg &= ~BIT(31); + + SDE_REG_WRITE(c, INTF_TEAR_AUTOREFRESH_CONFIG, refresh_cfg); + + return 0; +} + +static int sde_hw_intf_get_autorefresh_config(struct sde_hw_intf *intf, + struct sde_hw_autorefresh *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 val; + + if (!intf || !cfg) + return -EINVAL; + + c = &intf->hw; + val = SDE_REG_READ(c, INTF_TEAR_AUTOREFRESH_CONFIG); + cfg->enable = (val & BIT(31)) >> 31; + cfg->frame_count = val & 0xffff; + + return 0; +} + +static int sde_hw_intf_poll_timeout_wr_ptr(struct sde_hw_intf *intf, + u32 timeout_us) +{ + struct sde_hw_blk_reg_map *c; + u32 val; + int rc; + + if (!intf) + return -EINVAL; + + c = &intf->hw; + rc = readl_poll_timeout(c->base_off + c->blk_off + INTF_TEAR_LINE_COUNT, + val, (val & 0xffff) >= 1, 10, timeout_us); + + return rc; +} + +static int sde_hw_intf_enable_te(struct sde_hw_intf *intf, bool enable) +{ + struct sde_hw_blk_reg_map *c; + + if (!intf) + return -EINVAL; + + c = &intf->hw; + SDE_REG_WRITE(c, INTF_TEAR_TEAR_CHECK_EN, enable); + return 0; +} + +static void sde_hw_intf_update_te(struct sde_hw_intf *intf, + struct sde_hw_tear_check *te) +{ + struct sde_hw_blk_reg_map *c; + int cfg; + + if (!intf || !te) + return; + + c = &intf->hw; + cfg = SDE_REG_READ(c, INTF_TEAR_SYNC_THRESH); + cfg &= ~0xFFFF; + cfg |= te->sync_threshold_start; + SDE_REG_WRITE(c, INTF_TEAR_SYNC_THRESH, cfg); +} + +static int sde_hw_intf_connect_external_te(struct sde_hw_intf *intf, + bool enable_external_te) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + u32 cfg; + int orig; + + if (!intf) + return -EINVAL; + + c = &intf->hw; + cfg = SDE_REG_READ(c, INTF_TEAR_SYNC_CONFIG_VSYNC); + orig = (bool)(cfg & BIT(20)); + if (enable_external_te) + cfg |= BIT(20); + else + cfg &= ~BIT(20); + SDE_REG_WRITE(c, INTF_TEAR_SYNC_CONFIG_VSYNC, cfg); + + return orig; +} + +static int sde_hw_intf_get_vsync_info(struct sde_hw_intf *intf, + struct sde_hw_pp_vsync_info *info) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + u32 val; + + if (!intf || !info) + return -EINVAL; + + c = &intf->hw; + + val = SDE_REG_READ(c, INTF_TEAR_VSYNC_INIT_VAL); + info->rd_ptr_init_val = val & 0xffff; + + val = SDE_REG_READ(c, INTF_TEAR_INT_COUNT_VAL); + info->rd_ptr_frame_count = (val & 0xffff0000) >> 16; + info->rd_ptr_line_count = val & 0xffff; + + val = SDE_REG_READ(c, INTF_TEAR_LINE_COUNT); + info->wr_ptr_line_count = val & 0xffff; + + val = SDE_REG_READ(c, INTF_FRAME_COUNT); + info->intf_frame_count = val; + + return 0; +} + +static int sde_hw_intf_v1_check_and_reset_tearcheck(struct sde_hw_intf *intf, + struct intf_tear_status *status) +{ + struct sde_hw_blk_reg_map *c = &intf->hw; + u32 start_pos; + + if (!intf || !status) + return -EINVAL; + + c = &intf->hw; + + status->read_count = SDE_REG_READ(c, INTF_TEAR_INT_COUNT_VAL); + start_pos = SDE_REG_READ(c, INTF_TEAR_START_POS); + status->write_count = SDE_REG_READ(c, INTF_TEAR_SYNC_WRCOUNT); + status->write_count &= 0xffff0000; + status->write_count |= start_pos; + SDE_REG_WRITE(c, INTF_TEAR_SYNC_WRCOUNT, status->write_count); + + return 0; +} + +static void sde_hw_intf_vsync_sel(struct sde_hw_intf *intf, + u32 vsync_source) +{ + struct sde_hw_blk_reg_map *c; + + if (!intf) + return; + + c = &intf->hw; + + SDE_REG_WRITE(c, INTF_TEAR_MDP_VSYNC_SEL, (vsync_source & 0xf)); +} + +static void _setup_intf_ops(struct sde_hw_intf_ops *ops, + unsigned long cap) +{ + ops->setup_timing_gen = sde_hw_intf_setup_timing_engine; + ops->setup_prg_fetch = sde_hw_intf_setup_prg_fetch; + ops->get_status = sde_hw_intf_get_status; + ops->enable_timing = sde_hw_intf_enable_timing_engine; + ops->setup_misr = sde_hw_intf_setup_misr; + ops->collect_misr = sde_hw_intf_collect_misr; + ops->get_line_count = sde_hw_intf_get_line_count; + ops->avr_setup = sde_hw_intf_avr_setup; + ops->avr_trigger = sde_hw_intf_avr_trigger; + ops->avr_ctrl = sde_hw_intf_avr_ctrl; + + if (cap & BIT(SDE_INTF_INPUT_CTRL)) + ops->bind_pingpong_blk = sde_hw_intf_bind_pingpong_blk; + + if (cap & BIT(SDE_INTF_TE)) { + ops->setup_tearcheck = sde_hw_intf_setup_te_config; + ops->enable_tearcheck = sde_hw_intf_enable_te; + ops->update_tearcheck = sde_hw_intf_update_te; + ops->connect_external_te = sde_hw_intf_connect_external_te; + ops->get_vsync_info = sde_hw_intf_get_vsync_info; + ops->setup_autorefresh = sde_hw_intf_setup_autorefresh_config; + ops->get_autorefresh = sde_hw_intf_get_autorefresh_config; + ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr; + ops->vsync_sel = sde_hw_intf_vsync_sel; + ops->get_status = sde_hw_intf_v1_get_status; + ops->check_and_reset_tearcheck = + sde_hw_intf_v1_check_and_reset_tearcheck; + } +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_intf *c; + struct sde_intf_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _intf_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + pr_err("failed to create sde_hw_intf %d\n", idx); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + c->idx = idx; + c->cap = cfg; + c->mdss = m; + _setup_intf_ops(&c->ops, c->cap->features); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_INTF, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_intf_destroy(struct sde_hw_intf *intf) +{ + if (intf) + sde_hw_blk_destroy(&intf->base); + kfree(intf); +} + diff --git a/techpack/display/msm/sde/sde_hw_intf.h b/techpack/display/msm/sde/sde_hw_intf.h new file mode 100644 index 0000000000000000000000000000000000000000..403ac6b286b16d8742f9e1f8ba0cfcb50f1d161f --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_intf.h @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_INTF_H +#define _SDE_HW_INTF_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_blk.h" +#include "sde_kms.h" + +struct sde_hw_intf; + +/* intf timing settings */ +struct intf_timing_params { + u32 width; /* active width */ + u32 height; /* active height */ + u32 xres; /* Display panel width */ + u32 yres; /* Display panel height */ + + u32 h_back_porch; + u32 h_front_porch; + u32 v_back_porch; + u32 v_front_porch; + u32 hsync_pulse_width; + u32 vsync_pulse_width; + u32 hsync_polarity; + u32 vsync_polarity; + u32 border_clr; + u32 underflow_clr; + u32 hsync_skew; + u32 v_front_porch_fixed; + bool wide_bus_en; /* for DP only */ + bool compression_en; /* for DP only */ + u32 extra_dto_cycles; /* for DP only */ +}; + +struct intf_prog_fetch { + u8 enable; + /* vsync counter for the front porch pixel line */ + u32 fetch_start; +}; + +struct intf_status { + u8 is_en; /* interface timing engine is enabled or not */ + u32 frame_count; /* frame count since timing engine enabled */ + u32 line_count; /* current line count including blanking */ +}; + +struct intf_tear_status { + u32 read_count; /* frame & line count for tear init value */ + u32 write_count; /* frame & line count for tear write */ +}; + +struct intf_avr_params { + u32 default_fps; + u32 min_fps; + u32 avr_mode; /* 0 - disable, 1 - continuous, 2 - one-shot */ +}; + +/** + * struct sde_hw_intf_ops : Interface to the interface Hw driver functions + * Assumption is these functions will be called after clocks are enabled + * @ setup_timing_gen : programs the timing engine + * @ setup_prog_fetch : enables/disables the programmable fetch logic + * @ setup_rot_start : enables/disables the rotator start trigger + * @ enable_timing: enable/disable timing engine + * @ get_status: returns if timing engine is enabled or not + * @ setup_misr: enables/disables MISR in HW register + * @ collect_misr: reads and stores MISR data from HW register + * @ get_line_count: reads current vertical line counter + * @bind_pingpong_blk: enable/disable the connection with pingpong which will + * feed pixels to this interface + */ +struct sde_hw_intf_ops { + void (*setup_timing_gen)(struct sde_hw_intf *intf, + const struct intf_timing_params *p, + const struct sde_format *fmt); + + void (*setup_prg_fetch)(struct sde_hw_intf *intf, + const struct intf_prog_fetch *fetch); + + void (*setup_rot_start)(struct sde_hw_intf *intf, + const struct intf_prog_fetch *fetch); + + void (*enable_timing)(struct sde_hw_intf *intf, + u8 enable); + + void (*get_status)(struct sde_hw_intf *intf, + struct intf_status *status); + + void (*setup_misr)(struct sde_hw_intf *intf, + bool enable, u32 frame_count); + + int (*collect_misr)(struct sde_hw_intf *intf, + bool nonblock, u32 *misr_value); + + /** + * returns the current scan line count of the display + * video mode panels use get_line_count whereas get_vsync_info + * is used for command mode panels + */ + u32 (*get_line_count)(struct sde_hw_intf *intf); + + void (*bind_pingpong_blk)(struct sde_hw_intf *intf, + bool enable, + const enum sde_pingpong pp); + + /** + * enables vysnc generation and sets up init value of + * read pointer and programs the tear check cofiguration + */ + int (*setup_tearcheck)(struct sde_hw_intf *intf, + struct sde_hw_tear_check *cfg); + + /** + * enables tear check block + */ + int (*enable_tearcheck)(struct sde_hw_intf *intf, + bool enable); + + /** + * updates tearcheck configuration + */ + void (*update_tearcheck)(struct sde_hw_intf *intf, + struct sde_hw_tear_check *cfg); + + /** + * read, modify, write to either set or clear listening to external TE + * @Return: 1 if TE was originally connected, 0 if not, or -ERROR + */ + int (*connect_external_te)(struct sde_hw_intf *intf, + bool enable_external_te); + + /** + * provides the programmed and current + * line_count + */ + int (*get_vsync_info)(struct sde_hw_intf *intf, + struct sde_hw_pp_vsync_info *info); + + /** + * configure and enable the autorefresh config + */ + int (*setup_autorefresh)(struct sde_hw_intf *intf, + struct sde_hw_autorefresh *cfg); + + /** + * retrieve autorefresh config from hardware + */ + int (*get_autorefresh)(struct sde_hw_intf *intf, + struct sde_hw_autorefresh *cfg); + + /** + * poll until write pointer transmission starts + * @Return: 0 on success, -ETIMEDOUT on timeout + */ + int (*poll_timeout_wr_ptr)(struct sde_hw_intf *intf, u32 timeout_us); + + /** + * Select vsync signal for tear-effect configuration + */ + void (*vsync_sel)(struct sde_hw_intf *intf, u32 vsync_source); + + /** + * Program the AVR_TOTAL for min fps rate + */ + int (*avr_setup)(struct sde_hw_intf *intf, + const struct intf_timing_params *params, + const struct intf_avr_params *avr_params); + + /** + * Signal the trigger on each commit for AVR + */ + void (*avr_trigger)(struct sde_hw_intf *ctx); + + /** + * Enable AVR and select the mode + */ + void (*avr_ctrl)(struct sde_hw_intf *intf, + const struct intf_avr_params *avr_params); + + /** + * Check the intf tear check status and reset it to start_pos + */ + int (*check_and_reset_tearcheck)(struct sde_hw_intf *intf, + struct intf_tear_status *status); +}; + +struct sde_hw_intf { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* intf */ + enum sde_intf idx; + const struct sde_intf_cfg *cap; + const struct sde_mdss_cfg *mdss; + struct split_pipe_cfg cfg; + + /* ops */ + struct sde_hw_intf_ops ops; +}; + +/** + * to_sde_hw_intf - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_intf *to_sde_hw_intf(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_intf, base); +} + +/** + * sde_hw_intf_init(): Initializes the intf driver for the passed + * interface idx. + * @idx: interface index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct sde_hw_intf *sde_hw_intf_init(enum sde_intf idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_intf_destroy(): Destroys INTF driver context + * @intf: Pointer to INTF driver context + */ +void sde_hw_intf_destroy(struct sde_hw_intf *intf); + +#endif /*_SDE_HW_INTF_H */ diff --git a/techpack/display/msm/sde/sde_hw_lm.c b/techpack/display/msm/sde/sde_hw_lm.c new file mode 100644 index 0000000000000000000000000000000000000000..3be559bc101157278440b6b0e6b7c572791835a1 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_lm.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/iopoll.h> + +#include "sde_kms.h" +#include "sde_hw_catalog.h" +#include "sde_hwio.h" +#include "sde_hw_lm.h" +#include "sde_hw_mdss.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define LM_OP_MODE 0x00 +#define LM_OUT_SIZE 0x04 +#define LM_BORDER_COLOR_0 0x08 +#define LM_BORDER_COLOR_1 0x010 + +/* These register are offset to mixer base + stage base */ +#define LM_BLEND0_OP 0x00 +#define LM_BLEND0_CONST_ALPHA 0x04 +#define LM_FG_COLOR_FILL_COLOR_0 0x08 +#define LM_FG_COLOR_FILL_COLOR_1 0x0C +#define LM_FG_COLOR_FILL_SIZE 0x10 +#define LM_FG_COLOR_FILL_XY 0x14 + +#define LM_BLEND0_FG_ALPHA 0x04 +#define LM_BLEND0_BG_ALPHA 0x08 + +#define LM_MISR_CTRL 0x310 +#define LM_MISR_SIGNATURE 0x314 + +static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->mixer_count; i++) { + if (mixer == m->mixer[i].id) { + b->base_off = addr; + b->blk_off = m->mixer[i].base; + b->length = m->mixer[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_LM; + return &m->mixer[i]; + } + } + + return ERR_PTR(-ENOMEM); +} + +/** + * _stage_offset(): returns the relative offset of the blend registers + * for the stage to be setup + * @c: mixer ctx contains the mixer to be programmed + * @stage: stage index to setup + */ +static inline int _stage_offset(struct sde_hw_mixer *ctx, enum sde_stage stage) +{ + const struct sde_lm_sub_blks *sblk = ctx->cap->sblk; + int rc; + + if (stage == SDE_STAGE_BASE) + rc = -EINVAL; + else if (stage <= sblk->maxblendstages) + rc = sblk->blendstage_base[stage - SDE_STAGE_0]; + else + rc = -EINVAL; + + return rc; +} + +static void sde_hw_lm_setup_out(struct sde_hw_mixer *ctx, + struct sde_hw_mixer_cfg *mixer) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 outsize; + u32 op_mode; + + op_mode = SDE_REG_READ(c, LM_OP_MODE); + + outsize = mixer->out_height << 16 | mixer->out_width; + SDE_REG_WRITE(c, LM_OUT_SIZE, outsize); + + /* SPLIT_LEFT_RIGHT */ + if (mixer->right_mixer) + op_mode |= BIT(31); + else + op_mode &= ~BIT(31); + SDE_REG_WRITE(c, LM_OP_MODE, op_mode); +} + +static void sde_hw_lm_setup_border_color(struct sde_hw_mixer *ctx, + struct sde_mdss_color *color, + u8 border_en) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + + if (border_en) { + SDE_REG_WRITE(c, LM_BORDER_COLOR_0, + (color->color_0 & 0xFFF) | + ((color->color_1 & 0xFFF) << 0x10)); + SDE_REG_WRITE(c, LM_BORDER_COLOR_1, + (color->color_2 & 0xFFF) | + ((color->color_3 & 0xFFF) << 0x10)); + } +} + +static void sde_hw_lm_setup_blend_config_sdm845(struct sde_hw_mixer *ctx, + u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + int stage_off; + u32 const_alpha; + + if (stage == SDE_STAGE_BASE) + return; + + stage_off = _stage_offset(ctx, stage); + if (WARN_ON(stage_off < 0)) + return; + + const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16); + SDE_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha); + SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); +} + +static void sde_hw_lm_setup_blend_config(struct sde_hw_mixer *ctx, + u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + int stage_off; + + if (stage == SDE_STAGE_BASE) + return; + + stage_off = _stage_offset(ctx, stage); + if (WARN_ON(stage_off < 0)) + return; + + SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha); + SDE_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha); + SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op); +} + +static void sde_hw_lm_setup_color3(struct sde_hw_mixer *ctx, + uint32_t mixer_op_mode) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + int op_mode; + + /* read the existing op_mode configuration */ + op_mode = SDE_REG_READ(c, LM_OP_MODE); + + op_mode = (op_mode & (BIT(31) | BIT(30))) | mixer_op_mode; + + SDE_REG_WRITE(c, LM_OP_MODE, op_mode); +} + +static void sde_hw_lm_gc(struct sde_hw_mixer *mixer, + void *cfg) +{ +} + +static void sde_hw_lm_clear_dim_layer(struct sde_hw_mixer *ctx) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + const struct sde_lm_sub_blks *sblk = ctx->cap->sblk; + int stage_off, i; + u32 reset = BIT(16), val; + + reset = ~reset; + for (i = SDE_STAGE_0; i <= sblk->maxblendstages; i++) { + stage_off = _stage_offset(ctx, i); + if (WARN_ON(stage_off < 0)) + return; + + /* + * read the existing blendn_op register and clear only DIM layer + * bit (color_fill bit) + */ + val = SDE_REG_READ(c, LM_BLEND0_OP + stage_off); + val &= reset; + SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, val); + } +} + +static void sde_hw_lm_setup_dim_layer(struct sde_hw_mixer *ctx, + struct sde_hw_dim_layer *dim_layer) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + int stage_off; + u32 val = 0, alpha = 0; + + if (dim_layer->stage == SDE_STAGE_BASE) + return; + + stage_off = _stage_offset(ctx, dim_layer->stage); + if (stage_off < 0) { + SDE_ERROR("invalid stage_off:%d for dim layer\n", stage_off); + return; + } + + alpha = dim_layer->color_fill.color_3 & 0xFF; + val = ((dim_layer->color_fill.color_1 << 2) & 0xFFF) << 16 | + ((dim_layer->color_fill.color_0 << 2) & 0xFFF); + SDE_REG_WRITE(c, LM_FG_COLOR_FILL_COLOR_0 + stage_off, val); + + val = (alpha << 4) << 16 | + ((dim_layer->color_fill.color_2 << 2) & 0xFFF); + SDE_REG_WRITE(c, LM_FG_COLOR_FILL_COLOR_1 + stage_off, val); + + val = dim_layer->rect.h << 16 | dim_layer->rect.w; + SDE_REG_WRITE(c, LM_FG_COLOR_FILL_SIZE + stage_off, val); + + val = dim_layer->rect.y << 16 | dim_layer->rect.x; + SDE_REG_WRITE(c, LM_FG_COLOR_FILL_XY + stage_off, val); + + val = BIT(16); /* enable dim layer */ + val |= SDE_BLEND_FG_ALPHA_FG_CONST | SDE_BLEND_BG_ALPHA_BG_CONST; + if (dim_layer->flags & SDE_DRM_DIM_LAYER_EXCLUSIVE) + val |= BIT(17); + else + val &= ~BIT(17); + SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, val); + val = (alpha << 16) | (0xff - alpha); + SDE_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, val); +} + +static void sde_hw_lm_setup_misr(struct sde_hw_mixer *ctx, + bool enable, u32 frame_count) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 config = 0; + + SDE_REG_WRITE(c, LM_MISR_CTRL, MISR_CTRL_STATUS_CLEAR); + /* clear misr data */ + wmb(); + + if (enable) + config = (frame_count & MISR_FRAME_COUNT_MASK) | + MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK; + + SDE_REG_WRITE(c, LM_MISR_CTRL, config); +} + +static int sde_hw_lm_collect_misr(struct sde_hw_mixer *ctx, bool nonblock, + u32 *misr_value) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 ctrl = 0; + + if (!misr_value) + return -EINVAL; + + ctrl = SDE_REG_READ(c, LM_MISR_CTRL); + if (!nonblock) { + if (ctrl & MISR_CTRL_ENABLE) { + int rc; + + rc = readl_poll_timeout(c->base_off + c->blk_off + + LM_MISR_CTRL, ctrl, + (ctrl & MISR_CTRL_STATUS) > 0, 500, + 84000); + if (rc) + return rc; + } else { + return -EINVAL; + } + } + + *misr_value = SDE_REG_READ(c, LM_MISR_SIGNATURE); + + return 0; +} + +static void _setup_mixer_ops(struct sde_mdss_cfg *m, + struct sde_hw_lm_ops *ops, + unsigned long features) +{ + ops->setup_mixer_out = sde_hw_lm_setup_out; + if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion) || + IS_SDE_MAJOR_SAME(m->hwversion, SDE_HW_VER_500) || + IS_SDE_MAJOR_SAME(m->hwversion, SDE_HW_VER_600)) + ops->setup_blend_config = sde_hw_lm_setup_blend_config_sdm845; + else + ops->setup_blend_config = sde_hw_lm_setup_blend_config; + ops->setup_alpha_out = sde_hw_lm_setup_color3; + ops->setup_border_color = sde_hw_lm_setup_border_color; + ops->setup_gc = sde_hw_lm_gc; + ops->setup_misr = sde_hw_lm_setup_misr; + ops->collect_misr = sde_hw_lm_collect_misr; + + if (test_bit(SDE_DIM_LAYER, &features)) { + ops->setup_dim_layer = sde_hw_lm_setup_dim_layer; + ops->clear_dim_layer = sde_hw_lm_clear_dim_layer; + } +}; + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_mixer *c; + struct sde_lm_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _lm_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* Assign ops */ + c->idx = idx; + c->cap = cfg; + _setup_mixer_ops(m, &c->ops, c->cap->features); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_LM, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_lm_destroy(struct sde_hw_mixer *lm) +{ + if (lm) + sde_hw_blk_destroy(&lm->base); + kfree(lm); +} diff --git a/techpack/display/msm/sde/sde_hw_lm.h b/techpack/display/msm/sde/sde_hw_lm.h new file mode 100644 index 0000000000000000000000000000000000000000..07574d3f656d28e8a146e06fae563f2002cf9dd0 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_lm.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_LM_H +#define _SDE_HW_LM_H + +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_blk.h" + +struct sde_hw_mixer; + +struct sde_hw_mixer_cfg { + u32 out_width; + u32 out_height; + bool right_mixer; + int flags; +}; + +struct sde_hw_color3_cfg { + u8 keep_fg[SDE_STAGE_MAX]; +}; + +/** + * + * struct sde_hw_lm_ops : Interface to the mixer Hw driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_lm_ops { + /* + * Sets up mixer output width and height + * and border color if enabled + */ + void (*setup_mixer_out)(struct sde_hw_mixer *ctx, + struct sde_hw_mixer_cfg *cfg); + + /* + * Alpha blending configuration + * for the specified stage + */ + void (*setup_blend_config)(struct sde_hw_mixer *ctx, uint32_t stage, + uint32_t fg_alpha, uint32_t bg_alpha, uint32_t blend_op); + + /* + * Alpha color component selection from either fg or bg + */ + void (*setup_alpha_out)(struct sde_hw_mixer *ctx, uint32_t mixer_op); + + /** + * setup_border_color : enable/disable border color + */ + void (*setup_border_color)(struct sde_hw_mixer *ctx, + struct sde_mdss_color *color, + u8 border_en); + /** + * setup_gc : enable/disable gamma correction feature + */ + void (*setup_gc)(struct sde_hw_mixer *mixer, + void *cfg); + + /** + * setup_dim_layer: configure dim layer settings + * @ctx: Pointer to layer mixer context + * @dim_layer: dim layer configs + */ + void (*setup_dim_layer)(struct sde_hw_mixer *ctx, + struct sde_hw_dim_layer *dim_layer); + + /** + * clear_dim_layer: clear dim layer settings + * @ctx: Pointer to layer mixer context + */ + void (*clear_dim_layer)(struct sde_hw_mixer *ctx); + + /* setup_misr: enables/disables MISR in HW register */ + void (*setup_misr)(struct sde_hw_mixer *ctx, + bool enable, u32 frame_count); + + /* collect_misr: reads and stores MISR data from HW register */ + int (*collect_misr)(struct sde_hw_mixer *ctx, bool nonblock, + u32 *misr_value); +}; + +struct sde_hw_mixer { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* lm */ + enum sde_lm idx; + const struct sde_lm_cfg *cap; + const struct sde_mdp_cfg *mdp; + const struct sde_ctl_cfg *ctl; + + /* ops */ + struct sde_hw_lm_ops ops; + + /* store mixer info specific to display */ + struct sde_hw_mixer_cfg cfg; +}; + +/** + * to_sde_hw_mixer - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_mixer *to_sde_hw_mixer(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_mixer, base); +} + +/** + * sde_hw_lm_init(): Initializes the mixer hw driver object. + * should be called once before accessing every mixer. + * @idx: mixer index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + */ +struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_lm_destroy(): Destroys layer mixer driver context + * @lm: Pointer to LM driver context + */ +void sde_hw_lm_destroy(struct sde_hw_mixer *lm); + +#endif /*_SDE_HW_LM_H */ diff --git a/techpack/display/msm/sde/sde_hw_mdss.h b/techpack/display/msm/sde/sde_hw_mdss.h new file mode 100644 index 0000000000000000000000000000000000000000..a5384a5f981a743cebe58fbb81a6ec5018562863 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_mdss.h @@ -0,0 +1,702 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_MDSS_H +#define _SDE_HW_MDSS_H + +#include <linux/kernel.h> +#include <linux/err.h> + +#include "msm_drv.h" + +#define SDE_DBG_NAME "sde" + +#define SDE_NONE 0 + +#ifndef SDE_CSC_MATRIX_COEFF_SIZE +#define SDE_CSC_MATRIX_COEFF_SIZE 9 +#endif + +#ifndef SDE_CSC_CLAMP_SIZE +#define SDE_CSC_CLAMP_SIZE 6 +#endif + +#ifndef SDE_CSC_BIAS_SIZE +#define SDE_CSC_BIAS_SIZE 3 +#endif + +#ifndef SDE_MAX_PLANES +#define SDE_MAX_PLANES 4 +#endif + +#define PIPES_PER_STAGE 2 +#ifndef SDE_MAX_DE_CURVES +#define SDE_MAX_DE_CURVES 3 +#endif + +#define MAX_DSI_DISPLAYS 2 +#define MAX_DATA_PATH_PER_DSIPLAY 2 + +enum sde_format_flags { + SDE_FORMAT_FLAG_YUV_BIT, + SDE_FORMAT_FLAG_DX_BIT, + SDE_FORMAT_FLAG_COMPRESSED_BIT, + SDE_FORMAT_FLAG_BIT_MAX, +}; + +#define SDE_FORMAT_FLAG_YUV BIT(SDE_FORMAT_FLAG_YUV_BIT) +#define SDE_FORMAT_FLAG_DX BIT(SDE_FORMAT_FLAG_DX_BIT) +#define SDE_FORMAT_FLAG_COMPRESSED BIT(SDE_FORMAT_FLAG_COMPRESSED_BIT) +#define SDE_FORMAT_IS_YUV(X) \ + (test_bit(SDE_FORMAT_FLAG_YUV_BIT, (X)->flag)) +#define SDE_FORMAT_IS_DX(X) \ + (test_bit(SDE_FORMAT_FLAG_DX_BIT, (X)->flag)) +#define SDE_FORMAT_IS_LINEAR(X) ((X)->fetch_mode == SDE_FETCH_LINEAR) +#define SDE_FORMAT_IS_TILE(X) \ + (((X)->fetch_mode == SDE_FETCH_UBWC) && \ + !test_bit(SDE_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag)) +#define SDE_FORMAT_IS_UBWC(X) \ + (((X)->fetch_mode == SDE_FETCH_UBWC) && \ + test_bit(SDE_FORMAT_FLAG_COMPRESSED_BIT, (X)->flag)) + +#define SDE_BLEND_FG_ALPHA_FG_CONST (0 << 0) +#define SDE_BLEND_FG_ALPHA_BG_CONST (1 << 0) +#define SDE_BLEND_FG_ALPHA_FG_PIXEL (2 << 0) +#define SDE_BLEND_FG_ALPHA_BG_PIXEL (3 << 0) +#define SDE_BLEND_FG_INV_ALPHA (1 << 2) +#define SDE_BLEND_FG_MOD_ALPHA (1 << 3) +#define SDE_BLEND_FG_INV_MOD_ALPHA (1 << 4) +#define SDE_BLEND_FG_TRANSP_EN (1 << 5) +#define SDE_BLEND_BG_ALPHA_FG_CONST (0 << 8) +#define SDE_BLEND_BG_ALPHA_BG_CONST (1 << 8) +#define SDE_BLEND_BG_ALPHA_FG_PIXEL (2 << 8) +#define SDE_BLEND_BG_ALPHA_BG_PIXEL (3 << 8) +#define SDE_BLEND_BG_INV_ALPHA (1 << 10) +#define SDE_BLEND_BG_MOD_ALPHA (1 << 11) +#define SDE_BLEND_BG_INV_MOD_ALPHA (1 << 12) +#define SDE_BLEND_BG_TRANSP_EN (1 << 13) + +#define SDE_VSYNC0_SOURCE_GPIO 0 +#define SDE_VSYNC1_SOURCE_GPIO 1 +#define SDE_VSYNC2_SOURCE_GPIO 2 +#define SDE_VSYNC_SOURCE_INTF_0 3 +#define SDE_VSYNC_SOURCE_INTF_1 4 +#define SDE_VSYNC_SOURCE_INTF_2 5 +#define SDE_VSYNC_SOURCE_INTF_3 6 +#define SDE_VSYNC_SOURCE_WD_TIMER_4 11 +#define SDE_VSYNC_SOURCE_WD_TIMER_3 12 +#define SDE_VSYNC_SOURCE_WD_TIMER_2 13 +#define SDE_VSYNC_SOURCE_WD_TIMER_1 14 +#define SDE_VSYNC_SOURCE_WD_TIMER_0 15 + +enum sde_hw_blk_type { + SDE_HW_BLK_TOP = 0, + SDE_HW_BLK_SSPP, + SDE_HW_BLK_LM, + SDE_HW_BLK_DSPP, + SDE_HW_BLK_DS, + SDE_HW_BLK_CTL, + SDE_HW_BLK_CDM, + SDE_HW_BLK_PINGPONG, + SDE_HW_BLK_INTF, + SDE_HW_BLK_WB, + SDE_HW_BLK_DSC, + SDE_HW_BLK_MERGE_3D, + SDE_HW_BLK_QDSS, + SDE_HW_BLK_MAX, +}; + +enum sde_uidle { + UIDLE = 0x1, + UIDLE_MAX, +}; + +enum sde_mdp { + MDP_TOP = 0x1, + MDP_MAX, +}; + +enum sde_sspp { + SSPP_NONE, + SSPP_VIG0, + SSPP_VIG1, + SSPP_VIG2, + SSPP_VIG3, + SSPP_RGB0, + SSPP_RGB1, + SSPP_RGB2, + SSPP_RGB3, + SSPP_DMA0, + SSPP_DMA1, + SSPP_DMA2, + SSPP_DMA3, + SSPP_CURSOR0, + SSPP_CURSOR1, + SSPP_MAX +}; + +enum sde_sspp_type { + SSPP_TYPE_VIG, + SSPP_TYPE_RGB, + SSPP_TYPE_DMA, + SSPP_TYPE_CURSOR, + SSPP_TYPE_MAX +}; + +enum sde_lm { + LM_0 = 1, + LM_1, + LM_2, + LM_3, + LM_4, + LM_5, + LM_6, + LM_MAX +}; + +enum sde_stage { + SDE_STAGE_BASE = 0, + SDE_STAGE_0, + SDE_STAGE_1, + SDE_STAGE_2, + SDE_STAGE_3, + SDE_STAGE_4, + SDE_STAGE_5, + SDE_STAGE_6, + SDE_STAGE_7, + SDE_STAGE_8, + SDE_STAGE_9, + SDE_STAGE_10, + SDE_STAGE_MAX +}; +enum sde_dspp { + DSPP_0 = 1, + DSPP_1, + DSPP_2, + DSPP_3, + DSPP_MAX +}; + +enum sde_ltm { + LTM_0 = DSPP_0, + LTM_1, + LTM_MAX +}; + +enum sde_ds { + DS_TOP, + DS_0, + DS_1, + DS_MAX +}; + +enum sde_ctl { + CTL_0 = 1, + CTL_1, + CTL_2, + CTL_3, + CTL_4, + CTL_5, + CTL_MAX +}; + +enum sde_cdm { + CDM_0 = 1, + CDM_1, + CDM_MAX +}; + +enum sde_pingpong { + PINGPONG_0 = 1, + PINGPONG_1, + PINGPONG_2, + PINGPONG_3, + PINGPONG_4, + PINGPONG_5, + PINGPONG_S0, + PINGPONG_MAX +}; + +enum sde_dsc { + DSC_NONE = 0, + DSC_0, + DSC_1, + DSC_2, + DSC_3, + DSC_4, + DSC_5, + DSC_MAX +}; + +enum sde_intf { + INTF_0 = 1, + INTF_1, + INTF_2, + INTF_3, + INTF_4, + INTF_5, + INTF_6, + INTF_MAX +}; + +enum sde_intf_type { + INTF_NONE = 0x0, + INTF_DSI = 0x1, + INTF_HDMI = 0x3, + INTF_LCDC = 0x5, + INTF_EDP = 0x9, + INTF_DP = 0xa, + INTF_TYPE_MAX, + + /* virtual interfaces */ + INTF_WB = 0x100, +}; + +enum sde_intf_mode { + INTF_MODE_NONE = 0, + INTF_MODE_CMD, + INTF_MODE_VIDEO, + INTF_MODE_WB_BLOCK, + INTF_MODE_WB_LINE, + INTF_MODE_MAX +}; + +enum sde_wb { + WB_0 = 1, + WB_1, + WB_2, + WB_3, + WB_MAX +}; + +enum sde_ad { + AD_0 = 0x1, + AD_1, + AD_MAX +}; + +enum sde_cwb { + CWB_0 = 0x1, + CWB_1, + CWB_2, + CWB_3, + CWB_4, + CWB_5, + CWB_MAX +}; + +enum sde_wd_timer { + WD_TIMER_0 = 0x1, + WD_TIMER_1, + WD_TIMER_2, + WD_TIMER_3, + WD_TIMER_4, + WD_TIMER_5, + WD_TIMER_MAX +}; + +enum sde_vbif { + VBIF_0, + VBIF_1, + VBIF_MAX, + VBIF_RT = VBIF_0, + VBIF_NRT = VBIF_1 +}; + +enum sde_iommu_domain { + SDE_IOMMU_DOMAIN_UNSECURE, + SDE_IOMMU_DOMAIN_SECURE, + SDE_IOMMU_DOMAIN_MAX +}; + +enum sde_rot { + ROT_0 = 1, + ROT_MAX +}; + +enum sde_merge_3d { + MERGE_3D_0 = 1, + MERGE_3D_1, + MERGE_3D_2, + MERGE_3D_MAX +}; + +enum sde_qdss { + QDSS_0, + QDSS_MAX +}; + +/** + * SDE HW,Component order color map + */ +enum { + C0_G_Y = 0, + C1_B_Cb = 1, + C2_R_Cr = 2, + C3_ALPHA = 3 +}; + +/** + * enum sde_plane_type - defines how the color component pixel packing + * @SDE_PLANE_INTERLEAVED : Color components in single plane + * @SDE_PLANE_PLANAR : Color component in separate planes + * @SDE_PLANE_PSEUDO_PLANAR : Chroma components interleaved in separate plane + */ +enum sde_plane_type { + SDE_PLANE_INTERLEAVED, + SDE_PLANE_PLANAR, + SDE_PLANE_PSEUDO_PLANAR, +}; + +/** + * enum sde_chroma_samp_type - chroma sub-samplng type + * @SDE_CHROMA_RGB : No chroma subsampling + * @SDE_CHROMA_H2V1 : Chroma pixels are horizontally subsampled + * @SDE_CHROMA_H1V2 : Chroma pixels are vertically subsampled + * @SDE_CHROMA_420 : 420 subsampling + */ +enum sde_chroma_samp_type { + SDE_CHROMA_RGB, + SDE_CHROMA_H2V1, + SDE_CHROMA_H1V2, + SDE_CHROMA_420 +}; + +/** + * sde_fetch_type - Defines How SDE HW fetches data + * @SDE_FETCH_LINEAR : fetch is line by line + * @SDE_FETCH_TILE : fetches data in Z order from a tile + * @SDE_FETCH_UBWC : fetch and decompress data + */ +enum sde_fetch_type { + SDE_FETCH_LINEAR, + SDE_FETCH_TILE, + SDE_FETCH_UBWC +}; + +/** + * Value of enum chosen to fit the number of bits + * expected by the HW programming. + */ +enum { + COLOR_ALPHA_1BIT = 0, + COLOR_ALPHA_4BIT = 1, + COLOR_4BIT = 0, + COLOR_5BIT = 1, /* No 5-bit Alpha */ + COLOR_6BIT = 2, /* 6-Bit Alpha also = 2 */ + COLOR_8BIT = 3, /* 8-Bit Alpha also = 3 */ +}; + +/** + * enum sde_3d_blend_mode + * Desribes how the 3d data is blended + * @BLEND_3D_NONE : 3d blending not enabled + * @BLEND_3D_FRAME_INT : Frame interleaving + * @BLEND_3D_H_ROW_INT : Horizontal row interleaving + * @BLEND_3D_V_ROW_INT : vertical row interleaving + * @BLEND_3D_COL_INT : column interleaving + * @BLEND_3D_MAX : + */ +enum sde_3d_blend_mode { + BLEND_3D_NONE = 0, + BLEND_3D_FRAME_INT, + BLEND_3D_H_ROW_INT, + BLEND_3D_V_ROW_INT, + BLEND_3D_COL_INT, + BLEND_3D_MAX +}; + +/** struct sde_format - defines the format configuration which + * allows SDE HW to correctly fetch and decode the format + * @base: base msm_format struture containing fourcc code + * @fetch_planes: how the color components are packed in pixel format + * @element: element color ordering + * @bits: element bit widths + * @chroma_sample: chroma sub-samplng type + * @unpack_align_msb: unpack aligned, 0 to LSB, 1 to MSB + * @unpack_tight: 0 for loose, 1 for tight + * @unpack_count: 0 = 1 component, 1 = 2 component + * @bpp: bytes per pixel + * @alpha_enable: whether the format has an alpha channel + * @num_planes: number of planes (including meta data planes) + * @fetch_mode: linear, tiled, or ubwc hw fetch behavior + * @is_yuv: is format a yuv variant + * @flag: usage bit flags + * @tile_width: format tile width + * @tile_height: format tile height + */ +struct sde_format { + struct msm_format base; + enum sde_plane_type fetch_planes; + u8 element[SDE_MAX_PLANES]; + u8 bits[SDE_MAX_PLANES]; + enum sde_chroma_samp_type chroma_sample; + u8 unpack_align_msb; + u8 unpack_tight; + u8 unpack_count; + u8 bpp; + u8 alpha_enable; + u8 num_planes; + enum sde_fetch_type fetch_mode; + DECLARE_BITMAP(flag, SDE_FORMAT_FLAG_BIT_MAX); + u16 tile_width; + u16 tile_height; +}; +#define to_sde_format(x) container_of(x, struct sde_format, base) + +/** + * struct sde_hw_fmt_layout - format information of the source pixel data + * @format: pixel format parameters + * @num_planes: number of planes (including meta data planes) + * @width: image width + * @height: image height + * @total_size: total size in bytes + * @plane_addr: address of each plane + * @plane_size: length of each plane + * @plane_pitch: pitch of each plane + */ +struct sde_hw_fmt_layout { + const struct sde_format *format; + uint32_t num_planes; + uint32_t width; + uint32_t height; + uint32_t total_size; + uint32_t plane_addr[SDE_MAX_PLANES]; + uint32_t plane_size[SDE_MAX_PLANES]; + uint32_t plane_pitch[SDE_MAX_PLANES]; +}; + +struct sde_rect { + u16 x; + u16 y; + u16 w; + u16 h; +}; + +struct sde_csc_cfg { + /* matrix coefficients in S15.16 format */ + uint32_t csc_mv[SDE_CSC_MATRIX_COEFF_SIZE]; + uint32_t csc_pre_bv[SDE_CSC_BIAS_SIZE]; + uint32_t csc_post_bv[SDE_CSC_BIAS_SIZE]; + uint32_t csc_pre_lv[SDE_CSC_CLAMP_SIZE]; + uint32_t csc_post_lv[SDE_CSC_CLAMP_SIZE]; +}; + +/** + * struct sde_mdss_color - mdss color description + * color 0 : green + * color 1 : blue + * color 2 : red + * color 3 : alpha + */ +struct sde_mdss_color { + u32 color_0; + u32 color_1; + u32 color_2; + u32 color_3; +}; + +/* + * Define bit masks for h/w logging. + */ +#define SDE_DBG_MASK_NONE (1 << 0) +#define SDE_DBG_MASK_CDM (1 << 1) +#define SDE_DBG_MASK_DSPP (1 << 2) +#define SDE_DBG_MASK_INTF (1 << 3) +#define SDE_DBG_MASK_LM (1 << 4) +#define SDE_DBG_MASK_CTL (1 << 5) +#define SDE_DBG_MASK_PINGPONG (1 << 6) +#define SDE_DBG_MASK_SSPP (1 << 7) +#define SDE_DBG_MASK_WB (1 << 8) +#define SDE_DBG_MASK_TOP (1 << 9) +#define SDE_DBG_MASK_VBIF (1 << 10) +#define SDE_DBG_MASK_DSC (1 << 11) +#define SDE_DBG_MASK_ROT (1 << 12) +#define SDE_DBG_MASK_DS (1 << 13) +#define SDE_DBG_MASK_REGDMA (1 << 14) +#define SDE_DBG_MASK_UIDLE (1 << 15) +#define SDE_DBG_MASK_SID (1 << 15) +#define SDE_DBG_MASK_QDSS (1 << 16) + +/** + * struct sde_hw_cp_cfg: hardware dspp/lm feature payload. + * @payload: Feature specific payload. + * @len: Length of the payload. + * @ctl: control pointer associated with dspp/lm. + * @last_feature: last feature that will be set. + * @num_of_mixers: number of layer mixers for the display. + * @mixer_info: mixer info pointer associated with lm. + * @displayv: height of the display. + * @displayh: width of the display. + * @dspp[DSPP_MAX]: array of hw_dspp pointers associated with crtc. + * @broadcast_disabled: flag indicating if broadcast should be avoided when + * using LUTDMA + */ +struct sde_hw_cp_cfg { + void *payload; + u32 len; + void *ctl; + u32 last_feature; + u32 num_of_mixers; + void *mixer_info; + u32 displayv; + u32 displayh; + struct sde_hw_dspp *dspp[DSPP_MAX]; + bool broadcast_disabled; +}; + +/** + * struct sde_hw_dim_layer: dim layer configs + * @flags: Flag to represent INCLUSIVE/EXCLUSIVE + * @stage: Blending stage of dim layer + * @color_fill: Color fill to be used for the layer + * @rect: Dim layer coordinates + */ +struct sde_hw_dim_layer { + uint32_t flags; + uint32_t stage; + struct sde_mdss_color color_fill; + struct sde_rect rect; +}; + +/** + * struct sde_splash_mem - Struct contains splah memory info + * @splash_buf_size: Indicates the size of the memory region + * @splash_buf_base: Address of specific splash memory region + * @ramdump_size: Size of ramdump buffer region + * @ramdump_base: Address of ramdump region reserved by bootloader + * @ref_cnt: Tracks the map count to help in sharing splash memory + */ +struct sde_splash_mem { + u32 splash_buf_size; + unsigned long splash_buf_base; + u32 ramdump_size; + unsigned long ramdump_base; + u32 ref_cnt; +}; + +struct fingerprint_dim_layer { + uint32_t flags; + uint32_t stage; + struct sde_mdss_color color_fill; + struct sde_rect rect; +}; + +/** + * struct sde_sspp_index_info - Struct containing sspp identifier info + * @sspp: Enum value indicates sspp id + * @is_virtual: Boolean to identify if virtual or base + */ +struct sde_sspp_index_info { + enum sde_sspp sspp; + bool is_virtual; +}; + +/** + * struct sde_splash_data - Struct contains details of resources and hw blocks + * used in continuous splash on a specific display. + * @cont_splash_enabled: Stores the cont_splash status (enabled/disabled) + * @encoder: Pointer to the drm encoder object used for this display + * @splash: Pointer to struct sde_splash_mem used for this display + * @ctl_ids: Stores the valid MDSS ctl block ids for the current mode + * @lm_ids: Stores the valid MDSS layer mixer block ids for the current mode + * @dsc_ids: Stores the valid MDSS DSC block ids for the current mode + * @pipes: Array of sspp info detected on this display + * @ctl_cnt: Stores the active number of MDSS "top" blks of the current mode + * @lm_cnt: Stores the active number of MDSS "LM" blks for the current mode + * @dsc_cnt: Stores the active number of MDSS "dsc" blks for the current mode + * @pipe_cnt: Stores the active number of "sspp" blks connected + */ +struct sde_splash_display { + bool cont_splash_enabled; + struct drm_encoder *encoder; + struct sde_splash_mem *splash; + u8 ctl_ids[MAX_DATA_PATH_PER_DSIPLAY]; + u8 lm_ids[MAX_DATA_PATH_PER_DSIPLAY]; + u8 dsc_ids[MAX_DATA_PATH_PER_DSIPLAY]; + struct sde_sspp_index_info pipes[MAX_DATA_PATH_PER_DSIPLAY]; + u8 ctl_cnt; + u8 lm_cnt; + u8 dsc_cnt; + u8 pipe_cnt; +}; + +/** + * struct sde_splash_data - Struct contains details of continuous splash + * for all the displays connected by probe time + * @num_splash_regions: Indicates number of splash memory regions from dtsi + * @num_splash_displays: Indicates count of active displays in continuous splash + * @splash_mem: Array of all struct sde_splash_mem listed from dtsi + * @splash_display: Array of all struct sde_splash_display + */ +struct sde_splash_data { + u32 num_splash_regions; + u32 num_splash_displays; + struct sde_splash_mem splash_mem[MAX_DSI_DISPLAYS]; + struct sde_splash_display splash_display[MAX_DSI_DISPLAYS]; +}; + +/** + * struct sde_hw_tear_check - Struct contains parameters to configure + * tear-effect module. This structure is used to configure tear-check + * logic present either in ping-pong or in interface module. + * @vsync_count: Ratio of MDP VSYNC clk freq(Hz) to refresh rate divided + * by no of lines + * @sync_cfg_height: Total vertical lines (display height - 1) + * @vsync_init_val: Init value to which the read pointer gets loaded at + * vsync edge + * @sync_threshold_start: Read pointer threshold start ROI for write operation + * @sync_threshold_continue: The minimum number of lines the write pointer + * needs to be above the read pointer + * @start_pos: The position from which the start_threshold value is added + * @rd_ptr_irq: The read pointer line at which interrupt has to be generated + * @wr_ptr_irq: The write pointer line at which interrupt has to be generated + * @hw_vsync_mode: Sync with external frame sync input + */ +struct sde_hw_tear_check { + u32 vsync_count; + u32 sync_cfg_height; + u32 vsync_init_val; + u32 sync_threshold_start; + u32 sync_threshold_continue; + u32 start_pos; + u32 rd_ptr_irq; + u32 wr_ptr_irq; + u8 hw_vsync_mode; +}; + +/** + * struct sde_hw_autorefresh - Struct contains parameters to configure + * auto-refresh mode for command mode panels + * @enable: Enalbe or disable the auto-refresh mode + * @frame_count: Auto-refresh frame counter at which update occurs + */ +struct sde_hw_autorefresh { + bool enable; + u32 frame_count; +}; + +/** + * struct sde_hw_pp_vsync_info - Struct contains parameters to configure + * read and write pointers for command mode panels + * @pp_idx: Ping-pong block index + * @intf_idx: Interface block index + * @rd_ptr_init_val: Value of rd pointer at vsync edge + * @rd_ptr_frame_count: num frames sent since enabling interface + * @rd_ptr_line_count: current line on panel (rd ptr) + * @wr_ptr_line_count: current line within pp fifo (wr ptr) + * @intf_frame_count: num frames read from intf + */ +struct sde_hw_pp_vsync_info { + u32 pp_idx; + u32 intf_idx; + u32 rd_ptr_init_val; + u32 rd_ptr_frame_count; + u32 rd_ptr_line_count; + u32 wr_ptr_line_count; + u32 intf_frame_count; +}; + +#endif /* _SDE_HW_MDSS_H */ diff --git a/techpack/display/msm/sde/sde_hw_pingpong.c b/techpack/display/msm/sde/sde_hw_pingpong.c new file mode 100644 index 0000000000000000000000000000000000000000..0d44b21e2c3c1e79e552af398d4739d1398d97be --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_pingpong.c @@ -0,0 +1,566 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/iopoll.h> + +#include "sde_hw_mdss.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_pingpong.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define PP_TEAR_CHECK_EN 0x000 +#define PP_SYNC_CONFIG_VSYNC 0x004 +#define PP_SYNC_CONFIG_HEIGHT 0x008 +#define PP_SYNC_WRCOUNT 0x00C +#define PP_VSYNC_INIT_VAL 0x010 +#define PP_INT_COUNT_VAL 0x014 +#define PP_SYNC_THRESH 0x018 +#define PP_START_POS 0x01C +#define PP_RD_PTR_IRQ 0x020 +#define PP_WR_PTR_IRQ 0x024 +#define PP_OUT_LINE_COUNT 0x028 +#define PP_LINE_COUNT 0x02C +#define PP_AUTOREFRESH_CONFIG 0x030 + +#define PP_FBC_MODE 0x034 +#define PP_FBC_BUDGET_CTL 0x038 +#define PP_FBC_LOSSY_MODE 0x03C +#define PP_DSC_MODE 0x0a0 +#define PP_DCE_DATA_IN_SWAP 0x0ac +#define PP_DCE_DATA_OUT_SWAP 0x0c8 + +#define DITHER_DEPTH_MAP_INDEX 9 +static u32 dither_depth_map[DITHER_DEPTH_MAP_INDEX] = { + 0, 0, 0, 0, 0, 1, 2, 3, 3 +}; + +#define MERGE_3D_MODE 0x004 +#define MERGE_3D_MUX 0x000 + +static struct sde_merge_3d_cfg *_merge_3d_offset(enum sde_merge_3d idx, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->merge_3d_count; i++) { + if (idx == m->merge_3d[i].id) { + b->base_off = addr; + b->blk_off = m->merge_3d[i].base; + b->length = m->merge_3d[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_PINGPONG; + return &m->merge_3d[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static void _sde_hw_merge_3d_setup_blend_mode(struct sde_hw_merge_3d *ctx, + enum sde_3d_blend_mode cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 mode = 0; + + if (!ctx) + return; + + c = &ctx->hw; + if (cfg) { + mode = BIT(0); + mode |= (cfg - 0x1) << 1; + } + + SDE_REG_WRITE(c, MERGE_3D_MODE, mode); +} + +static void sde_hw_merge_3d_reset_blend_mode(struct sde_hw_merge_3d *ctx) +{ + struct sde_hw_blk_reg_map *c; + + if (!ctx) + return; + + c = &ctx->hw; + SDE_REG_WRITE(c, MERGE_3D_MODE, 0x0); + SDE_REG_WRITE(c, MERGE_3D_MUX, 0x0); +} + +static void _setup_merge_3d_ops(struct sde_hw_merge_3d_ops *ops, + const struct sde_merge_3d_cfg *hw_cap) +{ + ops->setup_blend_mode = _sde_hw_merge_3d_setup_blend_mode; + ops->reset_blend_mode = sde_hw_merge_3d_reset_blend_mode; +} + +static struct sde_hw_merge_3d *_sde_pp_merge_3d_init(enum sde_merge_3d idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_merge_3d *c; + struct sde_merge_3d_cfg *cfg; + static u32 merge3d_init_mask; + + if (idx < MERGE_3D_0) + return NULL; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _merge_3d_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + pr_err("invalid merge_3d cfg%d\n", idx); + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + _setup_merge_3d_ops(&c->ops, c->caps); + + if (!(merge3d_init_mask & BIT(idx))) { + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, + c->hw.blk_off, c->hw.blk_off + c->hw.length, + c->hw.xin_id); + merge3d_init_mask |= BIT(idx); + } + + return c; +} + +static struct sde_pingpong_cfg *_pingpong_offset(enum sde_pingpong pp, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->pingpong_count; i++) { + if (pp == m->pingpong[i].id) { + b->base_off = addr; + b->blk_off = m->pingpong[i].base; + b->length = m->pingpong[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_PINGPONG; + return &m->pingpong[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static int sde_hw_pp_setup_te_config(struct sde_hw_pingpong *pp, + struct sde_hw_tear_check *te) +{ + struct sde_hw_blk_reg_map *c; + int cfg; + + if (!pp || !te) + return -EINVAL; + c = &pp->hw; + + cfg = BIT(19); /*VSYNC_COUNTER_EN */ + if (te->hw_vsync_mode) + cfg |= BIT(20); + + cfg |= te->vsync_count; + + SDE_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg); + SDE_REG_WRITE(c, PP_SYNC_CONFIG_HEIGHT, te->sync_cfg_height); + SDE_REG_WRITE(c, PP_VSYNC_INIT_VAL, te->vsync_init_val); + SDE_REG_WRITE(c, PP_RD_PTR_IRQ, te->rd_ptr_irq); + SDE_REG_WRITE(c, PP_WR_PTR_IRQ, te->wr_ptr_irq); + SDE_REG_WRITE(c, PP_START_POS, te->start_pos); + SDE_REG_WRITE(c, PP_SYNC_THRESH, + ((te->sync_threshold_continue << 16) | + te->sync_threshold_start)); + SDE_REG_WRITE(c, PP_SYNC_WRCOUNT, + (te->start_pos + te->sync_threshold_start + 1)); + + return 0; +} + +static void sde_hw_pp_update_te(struct sde_hw_pingpong *pp, + struct sde_hw_tear_check *te) +{ + struct sde_hw_blk_reg_map *c; + int cfg; + + if (!pp || !te) + return; + c = &pp->hw; + + cfg = SDE_REG_READ(c, PP_SYNC_THRESH); + cfg &= ~0xFFFF; + cfg |= te->sync_threshold_start; + SDE_REG_WRITE(c, PP_SYNC_THRESH, cfg); +} + +static int sde_hw_pp_setup_autorefresh_config(struct sde_hw_pingpong *pp, + struct sde_hw_autorefresh *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 refresh_cfg; + + if (!pp || !cfg) + return -EINVAL; + c = &pp->hw; + + if (cfg->enable) + refresh_cfg = BIT(31) | cfg->frame_count; + else + refresh_cfg = 0; + + SDE_REG_WRITE(c, PP_AUTOREFRESH_CONFIG, refresh_cfg); + SDE_EVT32(pp->idx - PINGPONG_0, refresh_cfg); + + return 0; +} + +static int sde_hw_pp_get_autorefresh_config(struct sde_hw_pingpong *pp, + struct sde_hw_autorefresh *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 val; + + if (!pp || !cfg) + return -EINVAL; + + c = &pp->hw; + val = SDE_REG_READ(c, PP_AUTOREFRESH_CONFIG); + cfg->enable = (val & BIT(31)) >> 31; + cfg->frame_count = val & 0xffff; + + return 0; +} + +static int sde_hw_pp_poll_timeout_wr_ptr(struct sde_hw_pingpong *pp, + u32 timeout_us) +{ + struct sde_hw_blk_reg_map *c; + u32 val; + int rc; + + if (!pp) + return -EINVAL; + + c = &pp->hw; + rc = readl_poll_timeout(c->base_off + c->blk_off + PP_LINE_COUNT, + val, (val & 0xffff) >= 1, 10, timeout_us); + + return rc; +} + +static void sde_hw_pp_dsc_enable(struct sde_hw_pingpong *pp) +{ + struct sde_hw_blk_reg_map *c; + + if (!pp) + return; + c = &pp->hw; + + SDE_REG_WRITE(c, PP_DSC_MODE, 1); +} + +static u32 sde_hw_pp_get_dsc_status(struct sde_hw_pingpong *pp) +{ + struct sde_hw_blk_reg_map *c; + + if (!pp) + return 0; + + c = &pp->hw; + return SDE_REG_READ(c, PP_DSC_MODE); +} + +static void sde_hw_pp_dsc_disable(struct sde_hw_pingpong *pp) +{ + struct sde_hw_blk_reg_map *c; + u32 data; + + if (!pp) + return; + c = &pp->hw; + + data = SDE_REG_READ(c, PP_DCE_DATA_OUT_SWAP); + data &= ~BIT(18); /* disable endian flip */ + SDE_REG_WRITE(c, PP_DCE_DATA_OUT_SWAP, data); + + SDE_REG_WRITE(c, PP_DSC_MODE, 0); +} + +static int sde_hw_pp_setup_dsc(struct sde_hw_pingpong *pp) +{ + struct sde_hw_blk_reg_map *c; + int data; + + if (!pp) + return -EINVAL; + c = &pp->hw; + + data = SDE_REG_READ(c, PP_DCE_DATA_OUT_SWAP); + data |= BIT(18); /* endian flip */ + SDE_REG_WRITE(c, PP_DCE_DATA_OUT_SWAP, data); + return 0; +} + +static int sde_hw_pp_setup_dither_v1(struct sde_hw_pingpong *pp, + void *cfg, size_t len) +{ + struct sde_hw_blk_reg_map *c; + struct drm_msm_dither *dither = (struct drm_msm_dither *)cfg; + u32 base = 0, offset = 0, data = 0, i = 0; + + if (!pp) + return -EINVAL; + + c = &pp->hw; + base = pp->caps->sblk->dither.base; + if (!dither) { + /* dither property disable case */ + SDE_REG_WRITE(c, base, 0); + return 0; + } + + if (len != sizeof(struct drm_msm_dither)) { + DRM_ERROR("input len %zu, expected len %zu\n", len, + sizeof(struct drm_msm_dither)); + return -EINVAL; + } + + if (dither->c0_bitdepth >= DITHER_DEPTH_MAP_INDEX || + dither->c1_bitdepth >= DITHER_DEPTH_MAP_INDEX || + dither->c2_bitdepth >= DITHER_DEPTH_MAP_INDEX || + dither->c3_bitdepth >= DITHER_DEPTH_MAP_INDEX) + return -EINVAL; + + offset += 4; + data = dither_depth_map[dither->c0_bitdepth] & REG_MASK(2); + data |= (dither_depth_map[dither->c1_bitdepth] & REG_MASK(2)) << 2; + data |= (dither_depth_map[dither->c2_bitdepth] & REG_MASK(2)) << 4; + data |= (dither_depth_map[dither->c3_bitdepth] & REG_MASK(2)) << 6; + data |= (dither->temporal_en) ? (1 << 8) : 0; + SDE_REG_WRITE(c, base + offset, data); + + for (i = 0; i < DITHER_MATRIX_SZ - 3; i += 4) { + offset += 4; + data = (dither->matrix[i] & REG_MASK(4)) | + ((dither->matrix[i + 1] & REG_MASK(4)) << 4) | + ((dither->matrix[i + 2] & REG_MASK(4)) << 8) | + ((dither->matrix[i + 3] & REG_MASK(4)) << 12); + SDE_REG_WRITE(c, base + offset, data); + } + SDE_REG_WRITE(c, base, 1); + + return 0; +} + +static int sde_hw_pp_enable_te(struct sde_hw_pingpong *pp, bool enable) +{ + struct sde_hw_blk_reg_map *c; + + if (!pp) + return -EINVAL; + c = &pp->hw; + + SDE_REG_WRITE(c, PP_TEAR_CHECK_EN, enable); + return 0; +} + +static int sde_hw_pp_connect_external_te(struct sde_hw_pingpong *pp, + bool enable_external_te) +{ + struct sde_hw_blk_reg_map *c = &pp->hw; + u32 cfg; + int orig; + + if (!pp) + return -EINVAL; + + c = &pp->hw; + cfg = SDE_REG_READ(c, PP_SYNC_CONFIG_VSYNC); + orig = (bool)(cfg & BIT(20)); + if (enable_external_te) + cfg |= BIT(20); + else + cfg &= ~BIT(20); + SDE_REG_WRITE(c, PP_SYNC_CONFIG_VSYNC, cfg); + SDE_EVT32(pp->idx - PINGPONG_0, cfg); + + return orig; +} + +static int sde_hw_pp_get_vsync_info(struct sde_hw_pingpong *pp, + struct sde_hw_pp_vsync_info *info) +{ + struct sde_hw_blk_reg_map *c; + u32 val; + + if (!pp || !info) + return -EINVAL; + c = &pp->hw; + + val = SDE_REG_READ(c, PP_VSYNC_INIT_VAL); + info->rd_ptr_init_val = val & 0xffff; + + val = SDE_REG_READ(c, PP_INT_COUNT_VAL); + info->rd_ptr_frame_count = (val & 0xffff0000) >> 16; + info->rd_ptr_line_count = val & 0xffff; + + val = SDE_REG_READ(c, PP_LINE_COUNT); + info->wr_ptr_line_count = val & 0xffff; + + return 0; +} + +static u32 sde_hw_pp_get_line_count(struct sde_hw_pingpong *pp) +{ + struct sde_hw_blk_reg_map *c = &pp->hw; + u32 height, init; + u32 line = 0xFFFF; + + if (!pp) + return 0; + c = &pp->hw; + + init = SDE_REG_READ(c, PP_VSYNC_INIT_VAL) & 0xFFFF; + height = SDE_REG_READ(c, PP_SYNC_CONFIG_HEIGHT) & 0xFFFF; + + if (height < init) + goto line_count_exit; + + line = SDE_REG_READ(c, PP_INT_COUNT_VAL) & 0xFFFF; + + if (line < init) + line += (0xFFFF - init); + else + line -= init; + +line_count_exit: + return line; +} + +static void sde_hw_pp_setup_3d_merge_mode(struct sde_hw_pingpong *pp, + enum sde_3d_blend_mode cfg) +{ + if (pp->merge_3d && pp->merge_3d->ops.setup_blend_mode) + pp->merge_3d->ops.setup_blend_mode(pp->merge_3d, cfg); +} + +static void sde_hw_pp_reset_3d_merge_mode(struct sde_hw_pingpong *pp) +{ + if (pp->merge_3d && pp->merge_3d->ops.reset_blend_mode) + pp->merge_3d->ops.reset_blend_mode(pp->merge_3d); +} +static void _setup_pingpong_ops(struct sde_hw_pingpong_ops *ops, + const struct sde_pingpong_cfg *hw_cap) +{ + u32 version = 0; + + if (hw_cap->features & BIT(SDE_PINGPONG_TE)) { + ops->setup_tearcheck = sde_hw_pp_setup_te_config; + ops->enable_tearcheck = sde_hw_pp_enable_te; + ops->update_tearcheck = sde_hw_pp_update_te; + ops->connect_external_te = sde_hw_pp_connect_external_te; + ops->get_vsync_info = sde_hw_pp_get_vsync_info; + ops->setup_autorefresh = sde_hw_pp_setup_autorefresh_config; + ops->get_autorefresh = sde_hw_pp_get_autorefresh_config; + ops->poll_timeout_wr_ptr = sde_hw_pp_poll_timeout_wr_ptr; + ops->get_line_count = sde_hw_pp_get_line_count; + } + ops->setup_dsc = sde_hw_pp_setup_dsc; + ops->enable_dsc = sde_hw_pp_dsc_enable; + ops->disable_dsc = sde_hw_pp_dsc_disable; + ops->get_dsc_status = sde_hw_pp_get_dsc_status; + + version = SDE_COLOR_PROCESS_MAJOR(hw_cap->sblk->dither.version); + switch (version) { + case 1: + ops->setup_dither = sde_hw_pp_setup_dither_v1; + break; + default: + ops->setup_dither = NULL; + break; + } + if (test_bit(SDE_PINGPONG_MERGE_3D, &hw_cap->features)) { + ops->setup_3d_mode = sde_hw_pp_setup_3d_merge_mode; + ops->reset_3d_mode = sde_hw_pp_reset_3d_merge_mode; + } +}; + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_pingpong *c; + struct sde_pingpong_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _pingpong_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + if (test_bit(SDE_PINGPONG_MERGE_3D, &cfg->features)) { + c->merge_3d = _sde_pp_merge_3d_init(cfg->merge_3d_id, addr, m); + if (IS_ERR(c->merge_3d)) { + SDE_ERROR("invalid merge_3d block %d\n", idx); + return ERR_PTR(-ENOMEM); + } + } + + _setup_pingpong_ops(&c->ops, c->caps); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_PINGPONG, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + if (cfg->sblk->dither.base && cfg->sblk->dither.len) { + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, + cfg->sblk->dither.name, + c->hw.blk_off + cfg->sblk->dither.base, + c->hw.blk_off + cfg->sblk->dither.base + + cfg->sblk->dither.len, + c->hw.xin_id); + } + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_pingpong_destroy(struct sde_hw_pingpong *pp) +{ + if (pp) { + sde_hw_blk_destroy(&pp->base); + kfree(pp->merge_3d); + kfree(pp); + } +} diff --git a/techpack/display/msm/sde/sde_hw_pingpong.h b/techpack/display/msm/sde/sde_hw_pingpong.h new file mode 100644 index 0000000000000000000000000000000000000000..102cfc03afe8f06a34fc3bf57ef7cd154d822967 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_pingpong.h @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_PINGPONG_H +#define _SDE_HW_PINGPONG_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_blk.h" +#include <uapi/drm/msm_drm_pp.h> + +struct sde_hw_pingpong; +struct sde_hw_merge_3d; + +struct sde_hw_dsc_cfg { + u8 enable; +}; + +/** + * + * struct sde_hw_pingpong_ops : Interface to the pingpong Hw driver functions + * Assumption is these functions will be called after clocks are enabled + * @setup_tearcheck : program tear check values + * @enable_tearcheck : enables tear check + * @get_vsync_info : retries timing info of the panel + * @setup_autorefresh : program auto refresh + * @setup_dsc : program DSC block with encoding details + * @enable_dsc : enables DSC encoder + * @disable_dsc : disables DSC encoder + * @setup_dither : function to program the dither hw block + * @get_line_count: obtain current vertical line counter + */ +struct sde_hw_pingpong_ops { + /** + * enables vysnc generation and sets up init value of + * read pointer and programs the tear check cofiguration + */ + int (*setup_tearcheck)(struct sde_hw_pingpong *pp, + struct sde_hw_tear_check *cfg); + + /** + * enables tear check block + */ + int (*enable_tearcheck)(struct sde_hw_pingpong *pp, + bool enable); + + /** + * updates tearcheck configuration + */ + void (*update_tearcheck)(struct sde_hw_pingpong *pp, + struct sde_hw_tear_check *cfg); + + /** + * read, modify, write to either set or clear listening to external TE + * @Return: 1 if TE was originally connected, 0 if not, or -ERROR + */ + int (*connect_external_te)(struct sde_hw_pingpong *pp, + bool enable_external_te); + + /** + * provides the programmed and current + * line_count + */ + int (*get_vsync_info)(struct sde_hw_pingpong *pp, + struct sde_hw_pp_vsync_info *info); + + /** + * configure and enable the autorefresh config + */ + int (*setup_autorefresh)(struct sde_hw_pingpong *pp, + struct sde_hw_autorefresh *cfg); + + /** + * retrieve autorefresh config from hardware + */ + int (*get_autorefresh)(struct sde_hw_pingpong *pp, + struct sde_hw_autorefresh *cfg); + + /** + * poll until write pointer transmission starts + * @Return: 0 on success, -ETIMEDOUT on timeout + */ + int (*poll_timeout_wr_ptr)(struct sde_hw_pingpong *pp, u32 timeout_us); + + /** + * Program the dsc compression block + */ + int (*setup_dsc)(struct sde_hw_pingpong *pp); + + /** + * Enables DSC encoder + */ + void (*enable_dsc)(struct sde_hw_pingpong *pp); + + /** + * Disables DSC encoder + */ + void (*disable_dsc)(struct sde_hw_pingpong *pp); + + /** + * Get DSC status + * @Return: register value of DSC config + */ + u32 (*get_dsc_status)(struct sde_hw_pingpong *pp); + + /** + * Program the dither hw block + */ + int (*setup_dither)(struct sde_hw_pingpong *pp, void *cfg, size_t len); + + /** + * Obtain current vertical line counter + */ + u32 (*get_line_count)(struct sde_hw_pingpong *pp); + + /** + * Programs the 3d blend configuration + */ + void (*setup_3d_mode)(struct sde_hw_pingpong *pp, + enum sde_3d_blend_mode cfg); + + /** + * reset 3d blend configuration + */ + void (*reset_3d_mode)(struct sde_hw_pingpong *pp); +}; + +struct sde_hw_merge_3d_ops { + /** + * setup the 3d blend mode configuration + */ + void (*setup_blend_mode)(struct sde_hw_merge_3d *id, + enum sde_3d_blend_mode cfg); + + /** + * reset 3d blend mode configuration + */ + void (*reset_blend_mode)(struct sde_hw_merge_3d *id); +}; + +struct sde_hw_merge_3d { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* merge_3d */ + enum sde_merge_3d idx; + const struct sde_merge_3d_cfg *caps; + + /* ops */ + struct sde_hw_merge_3d_ops ops; +}; + +struct sde_hw_pingpong { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* pingpong */ + enum sde_pingpong idx; + const struct sde_pingpong_cfg *caps; + + /* associated 3d_merge */ + struct sde_hw_merge_3d *merge_3d; + + /* ops */ + struct sde_hw_pingpong_ops ops; +}; + +/** + * sde_hw_pingpong - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_pingpong *to_sde_hw_pingpong(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_pingpong, base); +} + +/** + * sde_hw_pingpong_init - initializes the pingpong driver for the passed + * pingpong idx. + * @idx: Pingpong index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + * Returns: Error code or allocated sde_hw_pingpong context + */ +struct sde_hw_pingpong *sde_hw_pingpong_init(enum sde_pingpong idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_pingpong_destroy - destroys pingpong driver context + * should be called to free the context + * @pp: Pointer to PP driver context returned by sde_hw_pingpong_init + */ +void sde_hw_pingpong_destroy(struct sde_hw_pingpong *pp); + +#endif /*_SDE_HW_PINGPONG_H */ diff --git a/techpack/display/msm/sde/sde_hw_qdss.c b/techpack/display/msm/sde/sde_hw_qdss.c new file mode 100644 index 0000000000000000000000000000000000000000..054ad76daf62a27e00785ce3424de5c514da4b3d --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_qdss.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/mutex.h> +#include <linux/platform_device.h> + +#include "sde_kms.h" +#include "sde_dbg.h" +#include "sde_hw_qdss.h" + +#define QDSS_CONFIG 0x0 + +static struct sde_qdss_cfg *_qdss_offset(enum sde_qdss qdss, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->qdss_count; i++) { + if (qdss == m->qdss[i].id) { + b->base_off = addr; + b->blk_off = m->qdss[i].base; + b->length = m->qdss[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_QDSS; + return &m->qdss[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static void sde_hw_qdss_enable_qdss_events(struct sde_hw_qdss *hw_qdss, + bool enable) +{ + struct sde_hw_blk_reg_map *c = &hw_qdss->hw; + u32 val; + + val = enable ? 0x100 : 0; + + if (c) + SDE_REG_WRITE(c, QDSS_CONFIG, val); +} + +static void _setup_qdss_ops(struct sde_hw_qdss_ops *ops) +{ + ops->enable_qdss_events = sde_hw_qdss_enable_qdss_events; +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_qdss *sde_hw_qdss_init(enum sde_qdss idx, + void __iomem *addr, + struct sde_mdss_cfg *m) +{ + struct sde_hw_qdss *c; + struct sde_qdss_cfg *cfg; + int rc; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _qdss_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + c->idx = idx; + c->caps = cfg; + _setup_qdss_ops(&c->ops); + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_QDSS, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + kzfree(c); + return ERR_PTR(rc); + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + return c; +} + +void sde_hw_qdss_destroy(struct sde_hw_qdss *qdss) +{ + if (qdss) + sde_hw_blk_destroy(&qdss->base); + kfree(qdss); +} diff --git a/techpack/display/msm/sde/sde_hw_qdss.h b/techpack/display/msm/sde/sde_hw_qdss.h new file mode 100644 index 0000000000000000000000000000000000000000..00549dcbb176a742c5c1fd3780179f54cf0c73d1 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_qdss.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_QDSS_H +#define _SDE_HW_QDSS_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_blk.h" +#include "sde_hw_util.h" + +struct sde_hw_qdss; + +/** + * struct sde_hw_qdss_ops - interface to the qdss hardware driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_qdss_ops { + /** + * enable_qdss_events - enable qdss events + * @hw_qdss: Pointer to qdss context + */ + void (*enable_qdss_events)(struct sde_hw_qdss *hw_qdss, bool enable); +}; + +struct sde_hw_qdss { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* qdss */ + enum sde_qdss idx; + const struct sde_qdss_cfg *caps; + + /* ops */ + struct sde_hw_qdss_ops ops; +}; + +/** + * to_sde_hw_qdss - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_qdss *to_sde_hw_qdss(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_qdss, base); +} + +/** + * sde_hw_qdss_init - initializes the qdss block for the passed qdss idx + * @idx: QDSS index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + * Returns: Error code or allocated sde_hw_qdss context + */ +struct sde_hw_qdss *sde_hw_qdss_init(enum sde_qdss idx, + void __iomem *addr, + struct sde_mdss_cfg *m); + +/** + * sde_hw_qdss_destroy - destroys qdss driver context + * should be called to free the context + * @qdss: Pointer to qdss driver context returned by sde_hw_qdss_init + */ +void sde_hw_qdss_destroy(struct sde_hw_qdss *qdss); + +#endif /*_SDE_HW_QDSS_H */ diff --git a/techpack/display/msm/sde/sde_hw_reg_dma_v1.c b/techpack/display/msm/sde/sde_hw_reg_dma_v1.c new file mode 100644 index 0000000000000000000000000000000000000000..e8911cf80661fe32baefc267bf87123b99d65b76 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_reg_dma_v1.c @@ -0,0 +1,1022 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#include <linux/iopoll.h> +#include "sde_hw_mdss.h" +#include "sde_hw_ctl.h" +#include "sde_hw_reg_dma_v1.h" +#include "msm_drv.h" +#include "msm_mmu.h" +#include "sde_dbg.h" + +#define GUARD_BYTES (BIT(8) - 1) +#define ALIGNED_OFFSET (U32_MAX & ~(GUARD_BYTES)) +#define ADDR_ALIGN BIT(8) +#define MAX_RELATIVE_OFF (BIT(20) - 1) + +#define DECODE_SEL_OP (BIT(HW_BLK_SELECT)) +#define REG_WRITE_OP ((BIT(REG_SINGLE_WRITE)) | (BIT(REG_BLK_WRITE_SINGLE)) | \ + (BIT(REG_BLK_WRITE_INC)) | (BIT(REG_BLK_WRITE_MULTIPLE)) | \ + (BIT(REG_SINGLE_MODIFY))) + +#define REG_DMA_OPS (DECODE_SEL_OP | REG_WRITE_OP) +#define IS_OP_ALLOWED(op, buf_op) (BIT(op) & buf_op) + +#define SET_UP_REG_DMA_REG(hw, reg_dma) \ + do { \ + (hw).base_off = (reg_dma)->addr; \ + (hw).blk_off = (reg_dma)->caps->base; \ + (hw).hwversion = (reg_dma)->caps->version; \ + (hw).log_mask = SDE_DBG_MASK_REGDMA; \ +} while (0) + +#define SIZE_DWORD(x) ((x) / (sizeof(u32))) +#define NOT_WORD_ALIGNED(x) ((x) & 0x3) + + +#define GRP_VIG_HW_BLK_SELECT (VIG0 | VIG1 | VIG2 | VIG3) +#define GRP_DMA_HW_BLK_SELECT (DMA0 | DMA1 | DMA2 | DMA3) +#define GRP_DSPP_HW_BLK_SELECT (DSPP0 | DSPP1 | DSPP2 | DSPP3) +#define GRP_LTM_HW_BLK_SELECT (LTM0 | LTM1) +#define BUFFER_SPACE_LEFT(cfg) ((cfg)->dma_buf->buffer_size - \ + (cfg)->dma_buf->index) + +#define REL_ADDR_OPCODE (BIT(27)) +#define SINGLE_REG_WRITE_OPCODE (BIT(28)) +#define SINGLE_REG_MODIFY_OPCODE (BIT(29)) +#define HW_INDEX_REG_WRITE_OPCODE (BIT(28) | BIT(29)) +#define AUTO_INC_REG_WRITE_OPCODE (BIT(30)) +#define BLK_REG_WRITE_OPCODE (BIT(30) | BIT(28)) + +#define WRAP_MIN_SIZE 2 +#define WRAP_MAX_SIZE (BIT(4) - 1) +#define MAX_DWORDS_SZ (BIT(14) - 1) +#define REG_DMA_HEADERS_BUFFER_SZ (sizeof(u32) * 128) + +static uint32_t reg_dma_register_count; +static uint32_t reg_dma_decode_sel; +static uint32_t reg_dma_opmode_offset; +static uint32_t reg_dma_ctl0_queue0_cmd0_offset; +static uint32_t reg_dma_intr_status_offset; +static uint32_t reg_dma_intr_4_status_offset; +static uint32_t reg_dma_intr_clear_offset; +static uint32_t reg_dma_ctl_trigger_offset; +static uint32_t reg_dma_ctl0_reset_offset; +static uint32_t reg_dma_error_clear_mask; + +typedef int (*reg_dma_internal_ops) (struct sde_reg_dma_setup_ops_cfg *cfg); + +static struct sde_hw_reg_dma *reg_dma; +static u32 ops_mem_size[REG_DMA_SETUP_OPS_MAX] = { + [REG_BLK_WRITE_SINGLE] = sizeof(u32) * 2, + [REG_BLK_WRITE_INC] = sizeof(u32) * 2, + [REG_BLK_WRITE_MULTIPLE] = sizeof(u32) * 2, + [HW_BLK_SELECT] = sizeof(u32) * 2, + [REG_SINGLE_WRITE] = sizeof(u32) * 2, + [REG_SINGLE_MODIFY] = sizeof(u32) * 3, +}; + +static u32 queue_sel[DMA_CTL_QUEUE_MAX] = { + [DMA_CTL_QUEUE0] = BIT(0), + [DMA_CTL_QUEUE1] = BIT(4), +}; + +static u32 reg_dma_ctl_queue_off[CTL_MAX]; +static u32 dspp_read_sel[DSPP_HIST_MAX] = { + [DSPP0_HIST] = 0, + [DSPP1_HIST] = 1, + [DSPP2_HIST] = 2, + [DSPP3_HIST] = 3, +}; + +static u32 v1_supported[REG_DMA_FEATURES_MAX] = { + [GAMUT] = GRP_VIG_HW_BLK_SELECT | GRP_DSPP_HW_BLK_SELECT, + [VLUT] = GRP_DSPP_HW_BLK_SELECT, + [GC] = GRP_DSPP_HW_BLK_SELECT, + [IGC] = DSPP_IGC | GRP_DSPP_HW_BLK_SELECT, + [PCC] = GRP_DSPP_HW_BLK_SELECT, +}; + +static u32 ctl_trigger_done_mask[CTL_MAX][DMA_CTL_QUEUE_MAX] = { + [CTL_0][0] = BIT(16), + [CTL_0][1] = BIT(21), + [CTL_1][0] = BIT(17), + [CTL_1][1] = BIT(22), + [CTL_2][0] = BIT(18), + [CTL_2][1] = BIT(23), + [CTL_3][0] = BIT(19), + [CTL_3][1] = BIT(24), + [CTL_4][0] = BIT(25), + [CTL_4][1] = BIT(27), + [CTL_5][0] = BIT(26), + [CTL_5][1] = BIT(28), +}; + +static int validate_dma_cfg(struct sde_reg_dma_setup_ops_cfg *cfg); +static int validate_write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg); +static int validate_write_reg(struct sde_reg_dma_setup_ops_cfg *cfg); +static int validate_write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg); +static int validate_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_single_reg(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_multi_reg_index(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_multi_reg_inc(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_single_modify(struct sde_reg_dma_setup_ops_cfg *cfg); +static int write_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg); +static int reset_reg_dma_buffer_v1(struct sde_reg_dma_buffer *lut_buf); +static int check_support_v1(enum sde_reg_dma_features feature, + enum sde_reg_dma_blk blk, bool *is_supported); +static int setup_payload_v1(struct sde_reg_dma_setup_ops_cfg *cfg); +static int kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg); +static int reset_v1(struct sde_hw_ctl *ctl); +static int last_cmd_v1(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q, + enum sde_reg_dma_last_cmd_mode mode); +static struct sde_reg_dma_buffer *alloc_reg_dma_buf_v1(u32 size); +static int dealloc_reg_dma_v1(struct sde_reg_dma_buffer *lut_buf); +static void dump_regs_v1(void); + +static reg_dma_internal_ops write_dma_op_params[REG_DMA_SETUP_OPS_MAX] = { + [HW_BLK_SELECT] = write_decode_sel, + [REG_SINGLE_WRITE] = write_single_reg, + [REG_BLK_WRITE_SINGLE] = write_multi_reg_inc, + [REG_BLK_WRITE_INC] = write_multi_reg_index, + [REG_BLK_WRITE_MULTIPLE] = write_multi_lut_reg, + [REG_SINGLE_MODIFY] = write_single_modify, +}; + +static reg_dma_internal_ops validate_dma_op_params[REG_DMA_SETUP_OPS_MAX] = { + [HW_BLK_SELECT] = validate_write_decode_sel, + [REG_SINGLE_WRITE] = validate_write_reg, + [REG_BLK_WRITE_SINGLE] = validate_write_reg, + [REG_BLK_WRITE_INC] = validate_write_reg, + [REG_BLK_WRITE_MULTIPLE] = validate_write_multi_lut_reg, + [REG_SINGLE_MODIFY] = validate_write_reg, +}; + +static struct sde_reg_dma_buffer *last_cmd_buf[CTL_MAX]; + +static void get_decode_sel(unsigned long blk, u32 *decode_sel) +{ + int i = 0; + + *decode_sel = 0; + for_each_set_bit(i, &blk, 31) { + switch (BIT(i)) { + case VIG0: + *decode_sel |= BIT(0); + break; + case VIG1: + *decode_sel |= BIT(1); + break; + case VIG2: + *decode_sel |= BIT(2); + break; + case VIG3: + *decode_sel |= BIT(3); + break; + case DMA0: + *decode_sel |= BIT(5); + break; + case DMA1: + *decode_sel |= BIT(6); + break; + case DMA2: + *decode_sel |= BIT(7); + break; + case DMA3: + *decode_sel |= BIT(8); + break; + case DSPP0: + *decode_sel |= BIT(17); + break; + case DSPP1: + *decode_sel |= BIT(18); + break; + case DSPP2: + *decode_sel |= BIT(19); + break; + case DSPP3: + *decode_sel |= BIT(20); + break; + case SSPP_IGC: + *decode_sel |= BIT(4); + break; + case DSPP_IGC: + *decode_sel |= BIT(21); + break; + case LTM0: + *decode_sel |= BIT(22); + break; + case LTM1: + *decode_sel |= BIT(23); + break; + default: + DRM_ERROR("block not supported %zx\n", (size_t)BIT(i)); + break; + } + } +} + +static int write_multi_reg(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u8 *loc = NULL; + + loc = (u8 *)cfg->dma_buf->vaddr + cfg->dma_buf->index; + memcpy(loc, cfg->data, cfg->data_size); + cfg->dma_buf->index += cfg->data_size; + cfg->dma_buf->next_op_allowed = REG_WRITE_OP | DECODE_SEL_OP; + cfg->dma_buf->ops_completed |= REG_WRITE_OP; + + return 0; +} + +int write_multi_reg_index(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = HW_INDEX_REG_WRITE_OPCODE; + loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + loc[1] = SIZE_DWORD(cfg->data_size); + cfg->dma_buf->index += ops_mem_size[cfg->ops]; + + return write_multi_reg(cfg); +} + +int write_multi_reg_inc(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = AUTO_INC_REG_WRITE_OPCODE; + loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + loc[1] = SIZE_DWORD(cfg->data_size); + cfg->dma_buf->index += ops_mem_size[cfg->ops]; + + return write_multi_reg(cfg); +} + +static int write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = BLK_REG_WRITE_OPCODE; + loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + loc[1] = (cfg->inc) ? 0 : BIT(31); + loc[1] |= (cfg->wrap_size & WRAP_MAX_SIZE) << 16; + loc[1] |= ((SIZE_DWORD(cfg->data_size)) & MAX_DWORDS_SZ); + cfg->dma_buf->next_op_allowed = REG_WRITE_OP; + cfg->dma_buf->index += ops_mem_size[cfg->ops]; + + return write_multi_reg(cfg); +} + +static int write_single_reg(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = SINGLE_REG_WRITE_OPCODE; + loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + loc[1] = *cfg->data; + cfg->dma_buf->index += ops_mem_size[cfg->ops]; + cfg->dma_buf->ops_completed |= REG_WRITE_OP; + cfg->dma_buf->next_op_allowed = REG_WRITE_OP | DECODE_SEL_OP; + + return 0; +} + +static int write_single_modify(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = SINGLE_REG_MODIFY_OPCODE; + loc[0] |= (cfg->blk_offset & MAX_RELATIVE_OFF); + loc[1] = cfg->mask; + loc[2] = *cfg->data; + cfg->dma_buf->index += ops_mem_size[cfg->ops]; + cfg->dma_buf->ops_completed |= REG_WRITE_OP; + cfg->dma_buf->next_op_allowed = REG_WRITE_OP | DECODE_SEL_OP; + + return 0; +} + +static int write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = reg_dma_decode_sel; + get_decode_sel(cfg->blk, &loc[1]); + cfg->dma_buf->index += ops_mem_size[cfg->ops]; + cfg->dma_buf->ops_completed |= DECODE_SEL_OP; + cfg->dma_buf->next_op_allowed = REG_WRITE_OP; + + return 0; +} + +static int validate_write_multi_lut_reg(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + int rc; + + rc = validate_write_reg(cfg); + if (rc) + return rc; + + if (cfg->wrap_size < WRAP_MIN_SIZE || cfg->wrap_size > WRAP_MAX_SIZE) { + DRM_ERROR("invalid wrap sz %d min %d max %zd\n", + cfg->wrap_size, WRAP_MIN_SIZE, (size_t)WRAP_MAX_SIZE); + rc = -EINVAL; + } + + return rc; +} + +static int validate_write_reg(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 remain_len, write_len; + + remain_len = BUFFER_SPACE_LEFT(cfg); + write_len = ops_mem_size[cfg->ops] + cfg->data_size; + if (remain_len < write_len) { + DRM_ERROR("buffer is full sz %d needs %d bytes\n", + remain_len, write_len); + return -EINVAL; + } + + if (!cfg->data) { + DRM_ERROR("invalid data %pK size %d exp sz %d\n", cfg->data, + cfg->data_size, write_len); + return -EINVAL; + } + if ((SIZE_DWORD(cfg->data_size)) > MAX_DWORDS_SZ || + NOT_WORD_ALIGNED(cfg->data_size)) { + DRM_ERROR("Invalid data size %d max %zd align %x\n", + cfg->data_size, (size_t)MAX_DWORDS_SZ, + NOT_WORD_ALIGNED(cfg->data_size)); + return -EINVAL; + } + + if (cfg->blk_offset > MAX_RELATIVE_OFF || + NOT_WORD_ALIGNED(cfg->blk_offset)) { + DRM_ERROR("invalid offset %d max %zd align %x\n", + cfg->blk_offset, (size_t)MAX_RELATIVE_OFF, + NOT_WORD_ALIGNED(cfg->blk_offset)); + return -EINVAL; + } + + return 0; +} + +static int validate_write_decode_sel(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 remain_len; + + remain_len = BUFFER_SPACE_LEFT(cfg); + if (remain_len < ops_mem_size[HW_BLK_SELECT]) { + DRM_ERROR("buffer is full needs %d bytes\n", + ops_mem_size[HW_BLK_SELECT]); + return -EINVAL; + } + + if (!cfg->blk) { + DRM_ERROR("blk set as 0\n"); + return -EINVAL; + } + /* VIG, DMA and DSPP can't be combined */ + if (((cfg->blk & GRP_VIG_HW_BLK_SELECT) && + (cfg->blk & GRP_DSPP_HW_BLK_SELECT)) || + ((cfg->blk & GRP_DMA_HW_BLK_SELECT) && + (cfg->blk & GRP_DSPP_HW_BLK_SELECT)) || + ((cfg->blk & GRP_VIG_HW_BLK_SELECT) && + (cfg->blk & GRP_DMA_HW_BLK_SELECT))) { + DRM_ERROR("invalid blk combination %x\n", + cfg->blk); + return -EINVAL; + } + + return 0; +} + +static int validate_dma_cfg(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + int rc = 0; + bool supported; + + if (!cfg || cfg->ops >= REG_DMA_SETUP_OPS_MAX || !cfg->dma_buf) { + DRM_ERROR("invalid param cfg %pK ops %d dma_buf %pK\n", + cfg, ((cfg) ? cfg->ops : REG_DMA_SETUP_OPS_MAX), + ((cfg) ? cfg->dma_buf : NULL)); + return -EINVAL; + } + + rc = check_support_v1(cfg->feature, cfg->blk, &supported); + if (rc || !supported) { + DRM_ERROR("check support failed rc %d supported %d\n", + rc, supported); + rc = -EINVAL; + return rc; + } + + if (cfg->dma_buf->index >= cfg->dma_buf->buffer_size || + NOT_WORD_ALIGNED(cfg->dma_buf->index)) { + DRM_ERROR("Buf Overflow index %d max size %d align %x\n", + cfg->dma_buf->index, cfg->dma_buf->buffer_size, + NOT_WORD_ALIGNED(cfg->dma_buf->index)); + return -EINVAL; + } + + if (cfg->dma_buf->iova & GUARD_BYTES || !cfg->dma_buf->vaddr) { + DRM_ERROR("iova not aligned to %zx iova %llx kva %pK", + (size_t)ADDR_ALIGN, cfg->dma_buf->iova, + cfg->dma_buf->vaddr); + return -EINVAL; + } + if (!IS_OP_ALLOWED(cfg->ops, cfg->dma_buf->next_op_allowed)) { + DRM_ERROR("invalid op %x allowed %x\n", cfg->ops, + cfg->dma_buf->next_op_allowed); + return -EINVAL; + } + + if (!validate_dma_op_params[cfg->ops] || + !write_dma_op_params[cfg->ops]) { + DRM_ERROR("invalid op %d validate %pK write %pK\n", cfg->ops, + validate_dma_op_params[cfg->ops], + write_dma_op_params[cfg->ops]); + return -EINVAL; + } + return rc; +} + +static int validate_kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg) +{ + + if (!cfg || !cfg->ctl || !cfg->dma_buf) { + DRM_ERROR("invalid cfg %pK ctl %pK dma_buf %pK\n", + cfg, ((!cfg) ? NULL : cfg->ctl), + ((!cfg) ? NULL : cfg->dma_buf)); + return -EINVAL; + } + + if (cfg->ctl->idx < CTL_0 && cfg->ctl->idx >= CTL_MAX) { + DRM_ERROR("invalid ctl idx %d\n", cfg->ctl->idx); + return -EINVAL; + } + + if (cfg->op >= REG_DMA_OP_MAX) { + DRM_ERROR("invalid op %d\n", cfg->op); + return -EINVAL; + } + + if ((cfg->op == REG_DMA_WRITE) && + (!(cfg->dma_buf->ops_completed & DECODE_SEL_OP) || + !(cfg->dma_buf->ops_completed & REG_WRITE_OP))) { + DRM_ERROR("incomplete write ops %x\n", + cfg->dma_buf->ops_completed); + return -EINVAL; + } + + if (cfg->op == REG_DMA_READ && cfg->block_select >= DSPP_HIST_MAX) { + DRM_ERROR("invalid block for read %d\n", cfg->block_select); + return -EINVAL; + } + + /* Only immediate triggers are supported now hence hardcode */ + cfg->trigger_mode = (cfg->op == REG_DMA_READ) ? (READ_TRIGGER) : + (WRITE_TRIGGER); + + if (cfg->dma_buf->iova & GUARD_BYTES) { + DRM_ERROR("Address is not aligned to %zx iova %llx", + (size_t)ADDR_ALIGN, cfg->dma_buf->iova); + return -EINVAL; + } + + if (cfg->queue_select >= DMA_CTL_QUEUE_MAX) { + DRM_ERROR("invalid queue selected %d\n", cfg->queue_select); + return -EINVAL; + } + + if (SIZE_DWORD(cfg->dma_buf->index) > MAX_DWORDS_SZ || + !cfg->dma_buf->index) { + DRM_ERROR("invalid dword size %zd max %zd\n", + (size_t)SIZE_DWORD(cfg->dma_buf->index), + (size_t)MAX_DWORDS_SZ); + return -EINVAL; + } + return 0; +} + +static int write_kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg) +{ + u32 cmd1, mask = 0, val = 0; + struct sde_hw_blk_reg_map hw; + + memset(&hw, 0, sizeof(hw)); + msm_gem_sync(cfg->dma_buf->buf); + cmd1 = (cfg->op == REG_DMA_READ) ? + (dspp_read_sel[cfg->block_select] << 30) : 0; + cmd1 |= (cfg->last_command) ? BIT(24) : 0; + cmd1 |= (cfg->op == REG_DMA_READ) ? (2 << 22) : 0; + cmd1 |= (cfg->op == REG_DMA_WRITE) ? (BIT(22)) : 0; + cmd1 |= (SIZE_DWORD(cfg->dma_buf->index) & MAX_DWORDS_SZ); + + SET_UP_REG_DMA_REG(hw, reg_dma); + SDE_REG_WRITE(&hw, reg_dma_opmode_offset, BIT(0)); + val = SDE_REG_READ(&hw, reg_dma_intr_4_status_offset); + if (val) { + DRM_DEBUG("LUT dma status %x\n", val); + mask = reg_dma_error_clear_mask; + SDE_REG_WRITE(&hw, reg_dma_intr_clear_offset + sizeof(u32) * 4, + mask); + SDE_EVT32(val); + } + + SDE_REG_WRITE(&hw, reg_dma_ctl_queue_off[cfg->ctl->idx], + cfg->dma_buf->iova); + SDE_REG_WRITE(&hw, reg_dma_ctl_queue_off[cfg->ctl->idx] + 0x4, + cmd1); + if (cfg->last_command) { + mask = ctl_trigger_done_mask[cfg->ctl->idx][cfg->queue_select]; + SDE_REG_WRITE(&hw, reg_dma_intr_clear_offset, mask); + SDE_REG_WRITE(&cfg->ctl->hw, reg_dma_ctl_trigger_offset, + queue_sel[cfg->queue_select]); + } + + return 0; +} + +int init_v1(struct sde_hw_reg_dma *cfg) +{ + int i = 0, rc = 0; + + if (!cfg) + return -EINVAL; + + reg_dma = cfg; + for (i = CTL_0; i < CTL_MAX; i++) { + if (!last_cmd_buf[i]) { + last_cmd_buf[i] = + alloc_reg_dma_buf_v1(REG_DMA_HEADERS_BUFFER_SZ); + if (IS_ERR_OR_NULL(last_cmd_buf[i])) { + /* + * This will allow reg dma to fall back to + * AHB domain + */ + pr_info("Failed to allocate reg dma, ret:%lu\n", + PTR_ERR(last_cmd_buf[i])); + return 0; + } + } + } + if (rc) { + for (i = 0; i < CTL_MAX; i++) { + if (!last_cmd_buf[i]) + continue; + dealloc_reg_dma_v1(last_cmd_buf[i]); + last_cmd_buf[i] = NULL; + } + return rc; + } + + reg_dma->ops.check_support = check_support_v1; + reg_dma->ops.setup_payload = setup_payload_v1; + reg_dma->ops.kick_off = kick_off_v1; + reg_dma->ops.reset = reset_v1; + reg_dma->ops.alloc_reg_dma_buf = alloc_reg_dma_buf_v1; + reg_dma->ops.dealloc_reg_dma = dealloc_reg_dma_v1; + reg_dma->ops.reset_reg_dma_buf = reset_reg_dma_buffer_v1; + reg_dma->ops.last_command = last_cmd_v1; + reg_dma->ops.dump_regs = dump_regs_v1; + + reg_dma_register_count = 60; + reg_dma_decode_sel = 0x180ac060; + reg_dma_opmode_offset = 0x4; + reg_dma_ctl0_queue0_cmd0_offset = 0x14; + reg_dma_intr_status_offset = 0x90; + reg_dma_intr_4_status_offset = 0xa0; + reg_dma_intr_clear_offset = 0xb0; + reg_dma_ctl_trigger_offset = 0xd4; + reg_dma_ctl0_reset_offset = 0xe4; + reg_dma_error_clear_mask = BIT(0) | BIT(1) | BIT(2) | BIT(16); + + reg_dma_ctl_queue_off[CTL_0] = reg_dma_ctl0_queue0_cmd0_offset; + for (i = CTL_1; i < ARRAY_SIZE(reg_dma_ctl_queue_off); i++) + reg_dma_ctl_queue_off[i] = reg_dma_ctl_queue_off[i - 1] + + (sizeof(u32) * 4); + + return 0; +} + +int init_v11(struct sde_hw_reg_dma *cfg) +{ + int ret = 0, i = 0; + + ret = init_v1(cfg); + if (ret) { + DRM_ERROR("failed to initialize v1: ret %d\n", ret); + return -EINVAL; + } + + /* initialize register offsets and v1_supported based on version */ + reg_dma_register_count = 133; + reg_dma_decode_sel = 0x180ac114; + reg_dma_opmode_offset = 0x4; + reg_dma_ctl0_queue0_cmd0_offset = 0x14; + reg_dma_intr_status_offset = 0x160; + reg_dma_intr_4_status_offset = 0x170; + reg_dma_intr_clear_offset = 0x1a0; + reg_dma_ctl_trigger_offset = 0xd4; + reg_dma_ctl0_reset_offset = 0x200; + reg_dma_error_clear_mask = BIT(0) | BIT(1) | BIT(2) | BIT(16) | + BIT(17) | BIT(18); + + reg_dma_ctl_queue_off[CTL_0] = reg_dma_ctl0_queue0_cmd0_offset; + for (i = CTL_1; i < ARRAY_SIZE(reg_dma_ctl_queue_off); i++) + reg_dma_ctl_queue_off[i] = reg_dma_ctl_queue_off[i - 1] + + (sizeof(u32) * 4); + + v1_supported[IGC] = DSPP_IGC | GRP_DSPP_HW_BLK_SELECT | + GRP_VIG_HW_BLK_SELECT | GRP_DMA_HW_BLK_SELECT; + v1_supported[GC] = GRP_DMA_HW_BLK_SELECT | GRP_DSPP_HW_BLK_SELECT; + v1_supported[HSIC] = GRP_DSPP_HW_BLK_SELECT; + v1_supported[SIX_ZONE] = GRP_DSPP_HW_BLK_SELECT; + v1_supported[MEMC_SKIN] = GRP_DSPP_HW_BLK_SELECT; + v1_supported[MEMC_SKY] = GRP_DSPP_HW_BLK_SELECT; + v1_supported[MEMC_FOLIAGE] = GRP_DSPP_HW_BLK_SELECT; + v1_supported[MEMC_PROT] = GRP_DSPP_HW_BLK_SELECT; + v1_supported[QSEED] = GRP_VIG_HW_BLK_SELECT; + + return 0; +} + +int init_v12(struct sde_hw_reg_dma *cfg) +{ + int ret = 0; + + ret = init_v11(cfg); + if (ret) { + DRM_ERROR("failed to initialize v11: ret %d\n", ret); + return ret; + } + + v1_supported[LTM_INIT] = GRP_LTM_HW_BLK_SELECT; + v1_supported[LTM_ROI] = GRP_LTM_HW_BLK_SELECT; + v1_supported[LTM_VLUT] = GRP_LTM_HW_BLK_SELECT; + + return 0; +} + +static int check_support_v1(enum sde_reg_dma_features feature, + enum sde_reg_dma_blk blk, + bool *is_supported) +{ + int ret = 0; + + if (!is_supported) + return -EINVAL; + + if (feature >= REG_DMA_FEATURES_MAX || blk >= MDSS) { + *is_supported = false; + return ret; + } + + *is_supported = (blk & v1_supported[feature]) ? true : false; + return ret; +} + +static int setup_payload_v1(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + int rc = 0; + + rc = validate_dma_cfg(cfg); + + if (!rc) + rc = validate_dma_op_params[cfg->ops](cfg); + + if (!rc) + rc = write_dma_op_params[cfg->ops](cfg); + + return rc; +} + + +static int kick_off_v1(struct sde_reg_dma_kickoff_cfg *cfg) +{ + int rc = 0; + + rc = validate_kick_off_v1(cfg); + if (rc) + return rc; + + rc = write_kick_off_v1(cfg); + return rc; +} + +int reset_v1(struct sde_hw_ctl *ctl) +{ + struct sde_hw_blk_reg_map hw; + u32 index, val, i = 0; + + if (!ctl || ctl->idx > CTL_MAX) { + DRM_ERROR("invalid ctl %pK ctl idx %d\n", + ctl, ((ctl) ? ctl->idx : 0)); + return -EINVAL; + } + + memset(&hw, 0, sizeof(hw)); + index = ctl->idx - CTL_0; + SET_UP_REG_DMA_REG(hw, reg_dma); + SDE_REG_WRITE(&hw, reg_dma_opmode_offset, BIT(0)); + SDE_REG_WRITE(&hw, (reg_dma_ctl0_reset_offset + index * sizeof(u32)), + BIT(0)); + + i = 0; + do { + udelay(1000); + i++; + val = SDE_REG_READ(&hw, + (reg_dma_ctl0_reset_offset + index * sizeof(u32))); + } while (i < 2 && val); + + return 0; +} + +static void sde_reg_dma_aspace_cb_locked(void *cb_data, bool is_detach) +{ + struct sde_reg_dma_buffer *dma_buf = NULL; + struct msm_gem_address_space *aspace = NULL; + u32 iova_aligned, offset; + int rc; + + if (!cb_data) { + DRM_ERROR("aspace cb called with invalid dma_buf\n"); + return; + } + + dma_buf = (struct sde_reg_dma_buffer *)cb_data; + aspace = dma_buf->aspace; + + if (is_detach) { + /* invalidate the stored iova */ + dma_buf->iova = 0; + + /* return the virtual address mapping */ + msm_gem_put_vaddr(dma_buf->buf); + msm_gem_vunmap(dma_buf->buf, OBJ_LOCK_NORMAL); + + } else { + rc = msm_gem_get_iova(dma_buf->buf, aspace, + &dma_buf->iova); + if (rc) { + DRM_ERROR("failed to get the iova rc %d\n", rc); + return; + } + + dma_buf->vaddr = msm_gem_get_vaddr(dma_buf->buf); + if (IS_ERR_OR_NULL(dma_buf->vaddr)) { + DRM_ERROR("failed to get va rc %d\n", rc); + return; + } + + iova_aligned = (dma_buf->iova + GUARD_BYTES) & ALIGNED_OFFSET; + offset = iova_aligned - dma_buf->iova; + dma_buf->iova = dma_buf->iova + offset; + dma_buf->vaddr = (void *)(((u8 *)dma_buf->vaddr) + offset); + dma_buf->next_op_allowed = DECODE_SEL_OP; + } +} + +static struct sde_reg_dma_buffer *alloc_reg_dma_buf_v1(u32 size) +{ + struct sde_reg_dma_buffer *dma_buf = NULL; + u32 iova_aligned, offset; + u32 rsize = size + GUARD_BYTES; + struct msm_gem_address_space *aspace = NULL; + int rc = 0; + + if (!size || SIZE_DWORD(size) > MAX_DWORDS_SZ) { + DRM_ERROR("invalid buffer size %d\n", size); + return ERR_PTR(-EINVAL); + } + + dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); + if (!dma_buf) + return ERR_PTR(-ENOMEM); + + dma_buf->buf = msm_gem_new(reg_dma->drm_dev, + rsize, MSM_BO_UNCACHED); + if (IS_ERR_OR_NULL(dma_buf->buf)) { + rc = -EINVAL; + goto fail; + } + + aspace = msm_gem_smmu_address_space_get(reg_dma->drm_dev, + MSM_SMMU_DOMAIN_UNSECURE); + if (!aspace) { + DRM_ERROR("failed to get aspace\n"); + rc = -EINVAL; + goto free_gem; + } + + /* register to aspace */ + rc = msm_gem_address_space_register_cb(aspace, + sde_reg_dma_aspace_cb_locked, + (void *)dma_buf); + if (rc) { + DRM_ERROR("failed to register callback %d", rc); + goto free_gem; + } + + dma_buf->aspace = aspace; + rc = msm_gem_get_iova(dma_buf->buf, aspace, &dma_buf->iova); + if (rc) { + DRM_ERROR("failed to get the iova rc %d\n", rc); + goto free_aspace_cb; + } + + dma_buf->vaddr = msm_gem_get_vaddr(dma_buf->buf); + if (IS_ERR_OR_NULL(dma_buf->vaddr)) { + DRM_ERROR("failed to get va rc %d\n", rc); + rc = -EINVAL; + goto put_iova; + } + + dma_buf->buffer_size = size; + iova_aligned = (dma_buf->iova + GUARD_BYTES) & ALIGNED_OFFSET; + offset = iova_aligned - dma_buf->iova; + dma_buf->iova = dma_buf->iova + offset; + dma_buf->vaddr = (void *)(((u8 *)dma_buf->vaddr) + offset); + dma_buf->next_op_allowed = DECODE_SEL_OP; + + return dma_buf; + +put_iova: + msm_gem_put_iova(dma_buf->buf, aspace); +free_aspace_cb: + msm_gem_address_space_unregister_cb(aspace, + sde_reg_dma_aspace_cb_locked, dma_buf); +free_gem: + mutex_lock(®_dma->drm_dev->struct_mutex); + msm_gem_free_object(dma_buf->buf); + mutex_unlock(®_dma->drm_dev->struct_mutex); +fail: + kfree(dma_buf); + return ERR_PTR(rc); +} + +static int dealloc_reg_dma_v1(struct sde_reg_dma_buffer *dma_buf) +{ + if (!dma_buf) { + DRM_ERROR("invalid param reg_buf %pK\n", dma_buf); + return -EINVAL; + } + + if (dma_buf->buf) { + msm_gem_put_iova(dma_buf->buf, 0); + msm_gem_address_space_unregister_cb(dma_buf->aspace, + sde_reg_dma_aspace_cb_locked, dma_buf); + mutex_lock(®_dma->drm_dev->struct_mutex); + msm_gem_free_object(dma_buf->buf); + mutex_unlock(®_dma->drm_dev->struct_mutex); + } + + kfree(dma_buf); + return 0; +} + +static int reset_reg_dma_buffer_v1(struct sde_reg_dma_buffer *lut_buf) +{ + if (!lut_buf) + return -EINVAL; + + lut_buf->index = 0; + lut_buf->ops_completed = 0; + lut_buf->next_op_allowed = DECODE_SEL_OP; + return 0; +} + +static int validate_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 remain_len, write_len; + + remain_len = BUFFER_SPACE_LEFT(cfg); + write_len = sizeof(u32); + if (remain_len < write_len) { + DRM_ERROR("buffer is full sz %d needs %d bytes\n", + remain_len, write_len); + return -EINVAL; + } + return 0; +} + +static int write_last_cmd(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + u32 *loc = NULL; + + loc = (u32 *)((u8 *)cfg->dma_buf->vaddr + + cfg->dma_buf->index); + loc[0] = reg_dma_decode_sel; + loc[1] = 0; + cfg->dma_buf->index = sizeof(u32) * 2; + cfg->dma_buf->ops_completed = REG_WRITE_OP | DECODE_SEL_OP; + cfg->dma_buf->next_op_allowed = REG_WRITE_OP; + + return 0; +} + +static int last_cmd_v1(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q, + enum sde_reg_dma_last_cmd_mode mode) +{ + struct sde_reg_dma_setup_ops_cfg cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_blk_reg_map hw; + u32 val; + int rc; + + if (!ctl || ctl->idx >= CTL_MAX || q >= DMA_CTL_QUEUE_MAX) { + DRM_ERROR("ctl %pK q %d index %d\n", ctl, q, + ((ctl) ? ctl->idx : -1)); + return -EINVAL; + } + + if (!last_cmd_buf[ctl->idx] || !last_cmd_buf[ctl->idx]->iova) { + DRM_DEBUG("invalid last cmd buf for idx %d\n", ctl->idx); + return 0; + } + + cfg.dma_buf = last_cmd_buf[ctl->idx]; + reset_reg_dma_buffer_v1(last_cmd_buf[ctl->idx]); + if (validate_last_cmd(&cfg)) { + DRM_ERROR("validate buf failed\n"); + return -EINVAL; + } + + if (write_last_cmd(&cfg)) { + DRM_ERROR("write buf failed\n"); + return -EINVAL; + } + + kick_off.ctl = ctl; + kick_off.queue_select = q; + kick_off.trigger_mode = WRITE_IMMEDIATE; + kick_off.last_command = 1; + kick_off.op = REG_DMA_WRITE; + kick_off.dma_buf = last_cmd_buf[ctl->idx]; + if (kick_off_v1(&kick_off)) { + DRM_ERROR("kick off last cmd failed\n"); + return -EINVAL; + } + + memset(&hw, 0, sizeof(hw)); + SET_UP_REG_DMA_REG(hw, reg_dma); + + SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY, mode); + if (mode == REG_DMA_WAIT4_COMP) { + rc = readl_poll_timeout(hw.base_off + hw.blk_off + + reg_dma_intr_status_offset, val, + (val & ctl_trigger_done_mask[ctl->idx][q]), + 10, 20000); + if (rc) + DRM_ERROR("poll wait failed %d val %x mask %x\n", + rc, val, ctl_trigger_done_mask[ctl->idx][q]); + SDE_EVT32(SDE_EVTLOG_FUNC_EXIT, mode); + } + + return 0; +} + +void deinit_v1(void) +{ + int i = 0; + + for (i = CTL_0; i < CTL_MAX; i++) { + if (last_cmd_buf[i]) + dealloc_reg_dma_v1(last_cmd_buf[i]); + last_cmd_buf[i] = NULL; + } +} + +static void dump_regs_v1(void) +{ + uint32_t i = 0; + u32 val; + struct sde_hw_blk_reg_map hw; + + memset(&hw, 0, sizeof(hw)); + SET_UP_REG_DMA_REG(hw, reg_dma); + + for (i = 0; i < reg_dma_register_count; i++) { + val = SDE_REG_READ(&hw, i * sizeof(u32)); + DRM_ERROR("offset %x val %x\n", (u32)(i * sizeof(u32)), val); + } +} diff --git a/techpack/display/msm/sde/sde_hw_reg_dma_v1.h b/techpack/display/msm/sde/sde_hw_reg_dma_v1.h new file mode 100644 index 0000000000000000000000000000000000000000..828f18634926a4bc26c7d71dbb6ed93db8f6f89e --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_reg_dma_v1.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _SDE_HW_REG_DMA_V1_H +#define _SDE_HW_REG_DMA_V1_H + +#include "sde_reg_dma.h" + +/** + * init_v1() - initialize the reg dma v1 driver by installing v1 ops + * @reg_dma - reg_dma hw info structure exposing capabilities. + */ +int init_v1(struct sde_hw_reg_dma *reg_dma); + +/** + * init_v11() - initialize the reg dma v11 driver by installing v11 ops + * @reg_dma - reg_dma hw info structure exposing capabilities. + */ +int init_v11(struct sde_hw_reg_dma *reg_dma); + +/** + * init_v12() - initialize the reg dma v12 driver by installing v12 ops + * @reg_dma - reg_dma hw info structure exposing capabilities. + */ +int init_v12(struct sde_hw_reg_dma *reg_dma); + +/** + * deinit_v1() - free up any resources allocated during the v1 reg dma init + */ +void deinit_v1(void); +#endif /* _SDE_HW_REG_DMA_V1_H */ diff --git a/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.c b/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.c new file mode 100644 index 0000000000000000000000000000000000000000..ae789c2ca783a6613e41ca29e11fc8bff1ee83c2 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.c @@ -0,0 +1,3767 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ +#include <drm/msm_drm_pp.h> +#include "sde_reg_dma.h" +#include "sde_hw_reg_dma_v1_color_proc.h" +#include "sde_hw_color_proc_common_v4.h" +#include "sde_hw_ctl.h" +#include "sde_hw_sspp.h" +#include "sde_hwio.h" +#include "sde_hw_lm.h" + +/* Reserve space of 128 words for LUT dma payload set-up */ +#define REG_DMA_HEADERS_BUFFER_SZ (sizeof(u32) * 128) +#define REG_DMA_VIG_SWI_DIFF 0x200 +#define REG_DMA_DMA_SWI_DIFF 0x200 + +#define VLUT_MEM_SIZE ((128 * sizeof(u32)) + REG_DMA_HEADERS_BUFFER_SZ) +#define VLUT_LEN (128 * sizeof(u32)) +#define PA_OP_MODE_OFF 0x800 +#define PA_LUTV_OPMODE_OFF 0x84c +#define REG_DMA_PA_MODE_HSIC_MASK 0xE1EFFFFF +#define REG_DMA_PA_MODE_SZONE_MASK 0x1FEFFFFF +#define REG_DMA_PA_PWL_HOLD_SZONE_MASK 0x0FFF +#define PA_LUTV_DSPP_CTRL_OFF 0x4c +#define PA_LUTV_DSPP_SWAP_OFF 0x18 +/** + * the diff between LTM_INIT_ENABLE/DISABLE masks are portrait_en and + * merge_mode bits. When disabling INIT property, we don't want to reset those + * bits since they are needed for both LTM histogram and VLUT. + */ +#define REG_DMA_LTM_INIT_ENABLE_OP_MASK 0xFFFC8CAB +#define REG_DMA_LTM_INIT_DISABLE_OP_MASK 0xFFFF8CAF +#define REG_DMA_LTM_ROI_OP_MASK 0xFEFFFFFF +/** + * the diff between LTM_VLUT_ENABLE/DISABLE masks are dither strength and + * unsharp_gain bits. When disabling VLUT property, we want to reset these + * bits since those are only valid if VLUT is enabled. + */ +#define REG_DMA_LTM_VLUT_ENABLE_OP_MASK 0xFEFFFFAD +#define REG_DMA_LTM_VLUT_DISABLE_OP_MASK 0xFEFF8CAD +#define REG_DMA_LTM_UPDATE_REQ_MASK 0xFFFFFFFE + +#define GAMUT_LUT_MEM_SIZE ((sizeof(struct drm_msm_3d_gamut)) + \ + REG_DMA_HEADERS_BUFFER_SZ) +#define GAMUT_SCALE_OFF_LEN (GAMUT_3D_SCALE_OFF_SZ * sizeof(u32)) +#define GAMUT_SCALE_OFF_LEN_12 (GAMUT_3D_SCALEB_OFF_SZ * sizeof(u32)) + +#define GC_LUT_MEM_SIZE ((sizeof(struct drm_msm_pgc_lut)) + \ + REG_DMA_HEADERS_BUFFER_SZ) + +#define IGC_LUT_MEM_SIZE ((sizeof(struct drm_msm_igc_lut)) + \ + REG_DMA_HEADERS_BUFFER_SZ) + +#define PCC_LUT_ENTRIES (PCC_NUM_PLANES * PCC_NUM_COEFF) +#define PCC_LEN (PCC_LUT_ENTRIES * sizeof(u32)) +#define PCC_MEM_SIZE (PCC_LEN + \ + REG_DMA_HEADERS_BUFFER_SZ) + +#define HSIC_MEM_SIZE ((sizeof(struct drm_msm_pa_hsic)) + \ + REG_DMA_HEADERS_BUFFER_SZ) +#define SIXZONE_MEM_SIZE ((sizeof(struct drm_msm_sixzone)) + \ + REG_DMA_HEADERS_BUFFER_SZ) +#define MEMCOLOR_MEM_SIZE ((sizeof(struct drm_msm_memcol)) + \ + REG_DMA_HEADERS_BUFFER_SZ) + +#define QSEED3_MEM_SIZE (sizeof(struct sde_hw_scaler3_cfg) + \ + (450 * sizeof(u32)) + \ + REG_DMA_HEADERS_BUFFER_SZ) +#define LTM_INIT_MEM_SIZE ((sizeof(struct drm_msm_ltm_init_param)) + \ + REG_DMA_HEADERS_BUFFER_SZ) +#define LTM_ROI_MEM_SIZE ((sizeof(struct drm_msm_ltm_cfg_param)) + \ + REG_DMA_HEADERS_BUFFER_SZ) +#define LTM_VLUT_MEM_SIZE ((sizeof(struct drm_msm_ltm_data)) + \ + REG_DMA_HEADERS_BUFFER_SZ) + +#define REG_MASK(n) ((BIT(n)) - 1) +#define REG_MASK_SHIFT(n, shift) ((REG_MASK(n)) << (shift)) +#define REG_DMA_VIG_GAMUT_OP_MASK 0x300 +#define REG_DMA_VIG_IGC_OP_MASK 0x1001F +#define DMA_DGM_0_OP_MODE_OFF 0x604 +#define DMA_DGM_1_OP_MODE_OFF 0x1604 +#define REG_DMA_DMA_IGC_OP_MASK 0x10005 +#define REG_DMA_DMA_GC_OP_MASK 0x10003 +#define DMA_1D_LUT_IGC_LEN 128 +#define DMA_1D_LUT_GC_LEN 128 +#define DMA_1D_LUT_IGC_DITHER_OFF 0x408 +#define VIG_1D_LUT_IGC_LEN 128 +#define VIG_IGC_DATA_MASK (BIT(10) - 1) +#define VIG_IGC_DATA_MASK_V6 (BIT(12) - 1) + +/* SDE_SCALER_QSEED3 */ +#define QSEED3_DE_OFFSET 0x24 +#define QSEED3_COEF_LUT_SWAP_BIT 0 +#define QSEED3_COEF_LUT_CTRL_OFF 0x4C + +/* SDE_SCALER_QSEED3LITE */ +#define QSEED3L_COEF_LUT_SWAP_BIT 0 +#define QSEED3L_COEF_LUT_Y_SEP_BIT 4 +#define QSEED3L_COEF_LUT_UV_SEP_BIT 5 +#define QSEED3L_COEF_LUT_CTRL_OFF 0x4c +#define Y_INDEX 0 +#define UV_INDEX 1 + +enum ltm_vlut_ops_bitmask { + ltm_unsharp = BIT(0), + ltm_dither = BIT(1), + ltm_roi = BIT(2), + ltm_vlut = BIT(3), + ltm_ops_max = BIT(31), +}; + +static u32 ltm_vlut_ops_mask[LTM_MAX]; + +static struct sde_reg_dma_buffer *dspp_buf[REG_DMA_FEATURES_MAX][DSPP_MAX]; +static struct sde_reg_dma_buffer + *sspp_buf[SDE_SSPP_RECT_MAX][REG_DMA_FEATURES_MAX][SSPP_MAX]; +static struct sde_reg_dma_buffer *ltm_buf[REG_DMA_FEATURES_MAX][LTM_MAX]; + +static u32 feature_map[SDE_DSPP_MAX] = { + [SDE_DSPP_VLUT] = VLUT, + [SDE_DSPP_GAMUT] = GAMUT, + [SDE_DSPP_IGC] = IGC, + [SDE_DSPP_PCC] = PCC, + [SDE_DSPP_GC] = GC, + [SDE_DSPP_HSIC] = HSIC, + /* MEMCOLOR can be mapped to any MEMC_SKIN/SKY/FOLIAGE/PROT*/ + [SDE_DSPP_MEMCOLOR] = MEMC_SKIN, + [SDE_DSPP_SIXZONE] = SIX_ZONE, + [SDE_DSPP_DITHER] = REG_DMA_FEATURES_MAX, + [SDE_DSPP_HIST] = REG_DMA_FEATURES_MAX, + [SDE_DSPP_AD] = REG_DMA_FEATURES_MAX, +}; + +static u32 sspp_feature_map[SDE_SSPP_MAX] = { + [SDE_SSPP_VIG_IGC] = IGC, + [SDE_SSPP_VIG_GAMUT] = GAMUT, + [SDE_SSPP_DMA_IGC] = IGC, + [SDE_SSPP_DMA_GC] = GC, + [SDE_SSPP_SCALER_QSEED3] = QSEED, + [SDE_SSPP_SCALER_QSEED3LITE] = QSEED, +}; + +static u32 ltm_feature_map[SDE_LTM_MAX] = { + [SDE_LTM_INIT] = LTM_INIT, + [SDE_LTM_ROI] = LTM_ROI, + [SDE_LTM_VLUT] = LTM_VLUT, +}; + +static u32 feature_reg_dma_sz[SDE_DSPP_MAX] = { + [SDE_DSPP_VLUT] = VLUT_MEM_SIZE, + [SDE_DSPP_GAMUT] = GAMUT_LUT_MEM_SIZE, + [SDE_DSPP_GC] = GC_LUT_MEM_SIZE, + [SDE_DSPP_IGC] = IGC_LUT_MEM_SIZE, + [SDE_DSPP_PCC] = PCC_MEM_SIZE, + [SDE_DSPP_HSIC] = HSIC_MEM_SIZE, + [SDE_DSPP_SIXZONE] = SIXZONE_MEM_SIZE, + [SDE_DSPP_MEMCOLOR] = MEMCOLOR_MEM_SIZE, +}; + +static u32 sspp_feature_reg_dma_sz[SDE_SSPP_MAX] = { + [SDE_SSPP_VIG_IGC] = IGC_LUT_MEM_SIZE, + [SDE_SSPP_VIG_GAMUT] = GAMUT_LUT_MEM_SIZE, + [SDE_SSPP_DMA_IGC] = IGC_LUT_MEM_SIZE, + [SDE_SSPP_DMA_GC] = GC_LUT_MEM_SIZE, + [SDE_SSPP_SCALER_QSEED3] = QSEED3_MEM_SIZE, + [SDE_SSPP_SCALER_QSEED3LITE] = QSEED3_MEM_SIZE, +}; + +static u32 ltm_feature_reg_dma_sz[SDE_LTM_MAX] = { + [SDE_LTM_INIT] = LTM_INIT_MEM_SIZE, + [SDE_LTM_ROI] = LTM_ROI_MEM_SIZE, + [SDE_LTM_VLUT] = LTM_VLUT_MEM_SIZE, +}; + +static u32 dspp_mapping[DSPP_MAX] = { + [DSPP_0] = DSPP0, + [DSPP_1] = DSPP1, + [DSPP_2] = DSPP2, + [DSPP_3] = DSPP3, +}; + +static u32 sspp_mapping[SSPP_MAX] = { + [SSPP_VIG0] = VIG0, + [SSPP_VIG1] = VIG1, + [SSPP_VIG2] = VIG2, + [SSPP_VIG3] = VIG3, + [SSPP_DMA0] = DMA0, + [SSPP_DMA1] = DMA1, + [SSPP_DMA2] = DMA2, + [SSPP_DMA3] = DMA3, +}; + +static u32 ltm_mapping[LTM_MAX] = { + [LTM_0] = LTM0, + [LTM_1] = LTM1, +}; + +#define REG_DMA_INIT_OPS(cfg, block, reg_dma_feature, feature_dma_buf) \ + do { \ + memset(&cfg, 0, sizeof(cfg)); \ + (cfg).blk = block; \ + (cfg).feature = reg_dma_feature; \ + (cfg).dma_buf = feature_dma_buf; \ + } while (0) + +#define REG_DMA_SETUP_OPS(cfg, block_off, data_ptr, data_len, op, \ + wrap_sz, wrap_inc, reg_mask) \ + do { \ + (cfg).ops = op; \ + (cfg).blk_offset = block_off; \ + (cfg).data_size = data_len; \ + (cfg).data = data_ptr; \ + (cfg).inc = wrap_inc; \ + (cfg).wrap_size = wrap_sz; \ + (cfg).mask = reg_mask; \ + } while (0) + +#define REG_DMA_SETUP_KICKOFF(cfg, hw_ctl, feature_dma_buf, ops, ctl_q, \ + mode) \ + do { \ + memset(&cfg, 0, sizeof(cfg)); \ + (cfg).ctl = hw_ctl; \ + (cfg).dma_buf = feature_dma_buf; \ + (cfg).op = ops; \ + (cfg).queue_select = ctl_q; \ + (cfg).trigger_mode = mode; \ + } while (0) + +static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 sz); +static int reg_dma_dspp_check(struct sde_hw_dspp *ctx, void *cfg, + enum sde_reg_dma_features feature); +static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, + enum sde_reg_dma_features feature, + enum sde_sspp_multirect_index idx); +static int reg_dma_ltm_check(struct sde_hw_dspp *ctx, void *cfg, + enum sde_reg_dma_features feature); + +static int reg_dma_buf_init(struct sde_reg_dma_buffer **buf, u32 size) +{ + struct sde_hw_reg_dma_ops *dma_ops; + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + if (!buf) { + DRM_ERROR("invalid buf\n"); + return -EINVAL; + } + + /* buffer already initialized */ + if (*buf) + return 0; + + *buf = dma_ops->alloc_reg_dma_buf(size); + if (IS_ERR_OR_NULL(*buf)) + return -EINVAL; + + return 0; +} + +static int reg_dma_dspp_check(struct sde_hw_dspp *ctx, void *cfg, + enum sde_reg_dma_features feature) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_hw_cp_cfg *hw_cfg = cfg; + + if (!cfg || !ctx) { + DRM_ERROR("invalid cfg %pK ctx %pK\n", cfg, ctx); + return -EINVAL; + } + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -EINVAL; + + if (!hw_cfg->ctl || ctx->idx >= DSPP_MAX || + feature >= REG_DMA_FEATURES_MAX) { + DRM_ERROR("invalid ctl %pK dspp idx %d feature %d\n", + hw_cfg->ctl, ctx->idx, feature); + return -EINVAL; + } + + if (!dspp_buf[feature][ctx->idx]) { + DRM_ERROR("invalid dma_buf\n"); + return -EINVAL; + } + + return 0; +} + +int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx) +{ + int rc = -ENOTSUPP; + struct sde_hw_reg_dma_ops *dma_ops; + bool is_supported = false; + u32 blk; + + if (feature >= SDE_DSPP_MAX || idx >= DSPP_MAX) { + DRM_ERROR("invalid feature %x max %x dspp idx %x max %xd\n", + feature, SDE_DSPP_MAX, idx, DSPP_MAX); + return rc; + } + + if (feature_map[feature] >= REG_DMA_FEATURES_MAX) { + DRM_ERROR("invalid feature map %d for feature %d\n", + feature_map[feature], feature); + return -ENOTSUPP; + } + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + blk = (feature_map[feature] == IGC) ? DSPP_IGC : dspp_mapping[idx]; + rc = dma_ops->check_support(feature_map[feature], blk, &is_supported); + if (!rc) + rc = (is_supported) ? 0 : -ENOTSUPP; + + if (!rc) { + if (feature == SDE_DSPP_MEMCOLOR) { + rc = reg_dma_buf_init( + &dspp_buf[MEMC_SKIN][idx], + feature_reg_dma_sz[feature]); + if (rc) + return rc; + rc = reg_dma_buf_init( + &dspp_buf[MEMC_SKY][idx], + feature_reg_dma_sz[feature]); + if (rc) + return rc; + rc = reg_dma_buf_init( + &dspp_buf[MEMC_FOLIAGE][idx], + feature_reg_dma_sz[feature]); + if (rc) + return rc; + rc = reg_dma_buf_init( + &dspp_buf[MEMC_PROT][idx], + feature_reg_dma_sz[feature]); + } else { + rc = reg_dma_buf_init( + &dspp_buf[feature_map[feature]][idx], + feature_reg_dma_sz[feature]); + } + + } + return rc; +} + +static int reg_dmav1_get_dspp_blk(struct sde_hw_cp_cfg *hw_cfg, + enum sde_dspp curr_dspp, u32 *blk, u32 *num_of_mixers) +{ + struct sde_hw_dspp *dspp; + int rc = 0; + + *num_of_mixers = 0; + + if (hw_cfg == NULL) { + DRM_ERROR("Invalid sde_hw_cp_cfg structure provided\n"); + return -EINVAL; + } + + if (hw_cfg->dspp == NULL) { + DRM_ERROR("Invalid sde_hw_dspp structure provided in hw_cfg\n"); + return -EINVAL; + } + + if (blk == NULL) { + DRM_ERROR("Invalid payload provided\n"); + return -EINVAL; + } + + if (curr_dspp >= DSPP_MAX) { + DRM_ERROR("Invalid current dspp idx %d", curr_dspp); + return -EINVAL; + } + + /* Treat first dspp as master to simplify setup */ + dspp = hw_cfg->dspp[0]; + if(!dspp) { + DRM_ERROR("Invalid dspp NULL"); + return -EINVAL; + } + + if (hw_cfg->broadcast_disabled) { + *blk = dspp_mapping[curr_dspp]; + (*num_of_mixers)++; + } else if (curr_dspp != dspp->idx) { + DRM_DEBUG_DRIVER("Slave DSPP instance %d\n", dspp->idx); + rc = -EALREADY; + } else { + u32 i; + + for (i = 0 ; i < hw_cfg->num_of_mixers; i++) { + dspp = hw_cfg->dspp[i]; + if (!dspp) { + DRM_ERROR("Invalid dspp NULL"); + rc = -EINVAL; + break; + } + if (dspp->idx >= DSPP_MAX) { + DRM_ERROR("Invalid dspp idx %d", dspp->idx); + rc = -EINVAL; + break; + } + *blk |= dspp_mapping[dspp->idx]; + (*num_of_mixers)++; + } + } + + if (!rc && !blk) { + rc = -EINVAL; + *num_of_mixers = 0; + } + + return rc; +} + +void reg_dmav1_setup_dspp_vlutv18(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_pa_vlut *payload = NULL; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_hw_ctl *ctl = NULL; + struct sde_hw_dspp *dspp_list[DSPP_MAX]; + u32 *data = NULL; + int i, j, rc = 0; + u32 index, num_of_mixers, blk = 0; + + rc = reg_dma_dspp_check(ctx, cfg, VLUT); + if (rc) + return; + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } else if (num_of_mixers > DSPP_MAX) { + DRM_ERROR("unable to process more than %d DSPP blocks\n", + DSPP_MAX); + return; + } else if (num_of_mixers > 1) { + memcpy(dspp_list, hw_cfg->dspp, + sizeof(struct sde_hw_dspp *) * num_of_mixers); + } else { + dspp_list[0] = ctx; + } + + ctl = hw_cfg->ctl; + if (!hw_cfg->payload) { + struct sde_hw_dspp *dspp; + + DRM_DEBUG_DRIVER("Disable vlut feature\n"); + for (index = 0; index < num_of_mixers; index++) { + dspp = hw_cfg->dspp[index]; + SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->hist.base + + PA_LUTV_DSPP_CTRL_OFF, 0); + } + goto exit; + } + + if (hw_cfg->len != sizeof(struct drm_msm_pa_vlut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pa_vlut)); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[VLUT][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, VLUT, dspp_buf[VLUT][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + data = kzalloc(VLUT_LEN, GFP_KERNEL); + if (!data) + return; + + payload = hw_cfg->payload; + DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags); + for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j++) + data[j] = (payload->val[i] & REG_MASK(10)) | + ((payload->val[i + 1] & REG_MASK(10)) << 16); + + + REG_DMA_SETUP_OPS(dma_write_cfg, ctx->cap->sblk->vlut.base, data, + VLUT_LEN, REG_BLK_WRITE_SINGLE, 0, 0, 0); + + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write pa vlut failed ret %d\n", rc); + goto exit; + } + + i = 1; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hist.base + PA_LUTV_DSPP_CTRL_OFF, &i, + sizeof(i), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write single reg failed ret %d\n", rc); + goto exit; + } + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hist.base + PA_LUTV_DSPP_SWAP_OFF, &i, + sizeof(i), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write single reg failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[VLUT][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + goto exit; + } + +exit: + kfree(data); + /* update flush bit */ + if (!rc && ctl && ctl->ops.update_bitmask_dspp_pavlut) { + int dspp_idx; + + for (index = 0; index < num_of_mixers; index++) { + dspp_idx = dspp_list[index]->idx; + ctl->ops.update_bitmask_dspp_pavlut(ctl, dspp_idx, + true); + } + } +} + +static int sde_gamut_get_mode_info(u32 pipe, struct drm_msm_3d_gamut *payload, + u32 *tbl_len, u32 *tbl_off, u32 *opcode, u32 *scale_off) +{ + int rc = 0; + + if (payload->mode > GAMUT_3D_MODE_13) { + DRM_ERROR("invalid mode %d", payload->mode); + return -EINVAL; + } + + switch (payload->mode) { + case GAMUT_3D_MODE_17: + *tbl_len = GAMUT_3D_MODE17_TBL_SZ * sizeof(u32) * 2; + *tbl_off = 0; + if (pipe == DSPP) { + *scale_off = GAMUT_SCALEA_OFFSET_OFF; + *opcode = gamut_mode_17; + } else { + *opcode = (*opcode & (BIT(5) - 1)) >> 2; + if (*opcode == gamut_mode_17b) + *opcode = gamut_mode_17; + else + *opcode = gamut_mode_17b; + *scale_off = (*opcode == gamut_mode_17) ? + GAMUT_SCALEA_OFFSET_OFF : + GAMUT_SCALEB_OFFSET_OFF; + } + *opcode <<= 2; + break; + case GAMUT_3D_MODE_5: + *tbl_len = GAMUT_3D_MODE5_TBL_SZ * sizeof(u32) * 2; + *tbl_off = GAMUT_MODE_5_OFF; + *scale_off = GAMUT_SCALEB_OFFSET_OFF; + *opcode = gamut_mode_5 << 2; + break; + case GAMUT_3D_MODE_13: + *tbl_len = GAMUT_3D_MODE13_TBL_SZ * sizeof(u32) * 2; + *opcode = (*opcode & (BIT(4) - 1)) >> 2; + if (*opcode == gamut_mode_13a) + *opcode = gamut_mode_13b; + else + *opcode = gamut_mode_13a; + *tbl_off = (*opcode == gamut_mode_13a) ? 0 : + GAMUT_MODE_13B_OFF; + *scale_off = (*opcode == gamut_mode_13a) ? + GAMUT_SCALEA_OFFSET_OFF : GAMUT_SCALEB_OFFSET_OFF; + *opcode <<= 2; + break; + default: + rc = -EINVAL; + break; + } + if (payload->flags & GAMUT_3D_MAP_EN) + *opcode |= GAMUT_MAP_EN; + *opcode |= GAMUT_EN; + + return rc; +} + +static void dspp_3d_gamutv4_off(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 op_mode = 0; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + int rc; + u32 num_of_mixers, blk = 0; + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[GAMUT][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, GAMUT, dspp_buf[GAMUT][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gamut.base, + &op_mode, sizeof(op_mode), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GAMUT][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +static void reg_dmav1_setup_dspp_3d_gamutv4_common(struct sde_hw_dspp *ctx, + void *cfg, u32 scale_tbl_a_len, u32 scale_tbl_b_len) +{ + struct drm_msm_3d_gamut *payload; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 op_mode, reg, tbl_len, tbl_off, scale_off, i; + u32 scale_tbl_len, scale_tbl_off; + u32 *scale_data; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_hw_reg_dma_ops *dma_ops; + int rc; + u32 num_of_mixers, blk = 0; + + rc = reg_dma_dspp_check(ctx, cfg, GAMUT); + if (rc) + return; + + op_mode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->gamut.base); + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable gamut feature\n"); + dspp_3d_gamutv4_off(ctx, cfg); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_3d_gamut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_3d_gamut)); + return; + } + payload = hw_cfg->payload; + rc = sde_gamut_get_mode_info(DSPP, payload, &tbl_len, &tbl_off, + &op_mode, &scale_off); + if (rc) { + DRM_ERROR("invalid mode info rc %d\n", rc); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[GAMUT][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, GAMUT, dspp_buf[GAMUT][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + for (i = 0; i < GAMUT_3D_TBL_NUM; i++) { + reg = GAMUT_TABLE0_SEL << i; + reg |= ((tbl_off) & (BIT(11) - 1)); + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gamut.base + GAMUT_TABLE_SEL_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write tbl sel reg failed ret %d\n", rc); + return; + } + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gamut.base + GAMUT_LOWER_COLOR_OFF, + &payload->col[i][0].c2_c1, tbl_len, + REG_BLK_WRITE_MULTIPLE, 2, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write color reg failed ret %d\n", rc); + return; + } + } + + if (op_mode & GAMUT_MAP_EN) { + if (scale_off == GAMUT_SCALEA_OFFSET_OFF) + scale_tbl_len = scale_tbl_a_len; + else + scale_tbl_len = scale_tbl_b_len; + + for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) { + scale_tbl_off = ctx->cap->sblk->gamut.base + scale_off + + (i * scale_tbl_len); + scale_data = &payload->scale_off[i][0]; + REG_DMA_SETUP_OPS(dma_write_cfg, scale_tbl_off, + scale_data, scale_tbl_len, + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write scale/off reg failed ret %d\n", + rc); + return; + } + } + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gamut.base, + &op_mode, sizeof(op_mode), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GAMUT][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg) +{ + reg_dmav1_setup_dspp_3d_gamutv4_common(ctx, cfg, GAMUT_SCALE_OFF_LEN, + GAMUT_SCALE_OFF_LEN_12); +} + +void reg_dmav1_setup_dspp_3d_gamutv41(struct sde_hw_dspp *ctx, void *cfg) +{ + reg_dmav1_setup_dspp_3d_gamutv4_common(ctx, cfg, GAMUT_SCALE_OFF_LEN, + GAMUT_SCALE_OFF_LEN); +} + +void reg_dmav1_setup_dspp_3d_gamutv42(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct drm_msm_3d_gamut *payload = NULL; + uint32_t i, j, tmp; + uint32_t scale_off[GAMUT_3D_SCALE_OFF_TBL_NUM][GAMUT_3D_SCALE_OFF_SZ]; + int rc; + + rc = reg_dma_dspp_check(ctx, cfg, GAMUT); + if (rc) + return; + if (hw_cfg->payload && hw_cfg->len != sizeof(struct drm_msm_3d_gamut)) { + DRM_ERROR("invalid payload len actual %d expected %zd", + hw_cfg->len, sizeof(struct drm_msm_3d_gamut)); + return; + } + + payload = hw_cfg->payload; + if (payload && (payload->flags & GAMUT_3D_MAP_EN)) { + for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) { + for (j = 0; j < GAMUT_3D_SCALE_OFF_SZ; j++) { + scale_off[i][j] = payload->scale_off[i][j]; + tmp = payload->scale_off[i][j] & 0x1ffff000; + payload->scale_off[i][j] &= 0xfff; + tmp = tmp << 3; + payload->scale_off[i][j] = + tmp | payload->scale_off[i][j]; + } + } + } + reg_dmav1_setup_dspp_3d_gamutv4_common(ctx, cfg, GAMUT_SCALE_OFF_LEN, + GAMUT_SCALE_OFF_LEN); + if (payload && (payload->flags & GAMUT_3D_MAP_EN)) { + for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) { + for (j = 0; j < GAMUT_3D_SCALE_OFF_SZ; j++) { + payload->scale_off[i][j] = scale_off[i][j]; + } + } + } +} + +void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_pgc_lut *lut_cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + int rc, i = 0; + u32 reg; + u32 *addr[GC_TBL_NUM]; + u32 num_of_mixers, blk = 0; + + rc = reg_dma_dspp_check(ctx, cfg, GC); + if (rc) + return; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable pgc feature\n"); + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->gc.base, 0); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_pgc_lut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pgc_lut)); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } + + lut_cfg = hw_cfg->payload; + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[GC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, GC, dspp_buf[GC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + addr[0] = lut_cfg->c0; + addr[1] = lut_cfg->c1; + addr[2] = lut_cfg->c2; + for (i = 0; i < GC_TBL_NUM; i++) { + reg = 0; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gc.base + GC_C0_INDEX_OFF + + (i * sizeof(u32) * 2), + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("index init failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gc.base + GC_C0_OFF + + (i * sizeof(u32) * 2), + addr[i], + PGC_TBL_LEN * sizeof(u32), + REG_BLK_WRITE_INC, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + } + + reg = BIT(0); + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gc.base + GC_LUT_SWAP_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting swap offset failed ret %d\n", rc); + return; + } + + reg = GC_EN | ((lut_cfg->flags & PGC_8B_ROUND) ? GC_8B_ROUND_EN : 0); + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->gc.base, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("enabling gamma correction failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[GC][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} + +static void _dspp_igcv31_off(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + int rc; + u32 reg; + u32 num_of_mixers, blk = 0; + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, IGC, dspp_buf[IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + reg = IGC_DIS; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->igc.base + IGC_OPMODE_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[IGC][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_igc_lut *lut_cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_hw_dspp *dspp_list[DSPP_MAX]; + int rc, i = 0, j = 0; + u32 *addr[IGC_TBL_NUM]; + u32 offset = 0; + u32 reg; + u32 index, num_of_mixers, dspp_sel, blk = 0; + + rc = reg_dma_dspp_check(ctx, cfg, IGC); + if (rc) + return; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable igc feature\n"); + _dspp_igcv31_off(ctx, cfg); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_igc_lut)); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } else if (num_of_mixers > DSPP_MAX) { + DRM_ERROR("unable to process more than %d DSPP blocks\n", + DSPP_MAX); + return; + } else if (num_of_mixers > 1) { + memcpy(dspp_list, hw_cfg->dspp, + sizeof(struct sde_hw_dspp *) * num_of_mixers); + } else { + dspp_list[0] = ctx; + } + + lut_cfg = hw_cfg->payload; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, DSPP_IGC, IGC, dspp_buf[IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + dspp_sel = -1; + for (index = 0; index < num_of_mixers; index++) + dspp_sel &= IGC_DSPP_SEL_MASK(dspp_list[index]->idx - 1); + + addr[0] = lut_cfg->c0; + addr[1] = lut_cfg->c1; + addr[2] = lut_cfg->c2; + for (i = 0; i < IGC_TBL_NUM; i++) { + offset = IGC_C0_OFF + (i * sizeof(u32)); + + for (j = 0; j < IGC_TBL_LEN; j++) { + addr[i][j] &= IGC_DATA_MASK; + addr[i][j] |= dspp_sel; + if (j == 0) + addr[i][j] |= IGC_INDEX_UPDATE; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, offset, addr[i], + IGC_TBL_LEN * sizeof(u32), + REG_BLK_WRITE_INC, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + } + + REG_DMA_INIT_OPS(dma_write_cfg, blk, IGC, dspp_buf[IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (lut_cfg->flags & IGC_DITHER_ENABLE) { + reg = lut_cfg->strength & IGC_DITHER_DATA_MASK; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->igc.base + IGC_DITHER_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("dither strength failed ret %d\n", rc); + return; + } + } + + reg = IGC_EN; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->igc.base + IGC_OPMODE_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[IGC][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +static void _dspp_pccv4_off(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + int rc; + u32 reg; + u32 num_of_mixers, blk = 0; + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[PCC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, PCC, dspp_buf[PCC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + reg = PCC_DIS; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->pcc.base, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[PCC][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct drm_msm_pcc *pcc_cfg; + struct drm_msm_pcc_coeff *coeffs = NULL; + u32 *data = NULL; + int rc, i = 0; + u32 reg = 0; + u32 num_of_mixers, blk = 0; + + rc = reg_dma_dspp_check(ctx, cfg, PCC); + if (rc) + return; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable pcc feature\n"); + _dspp_pccv4_off(ctx, cfg); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_pcc)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pcc)); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } + + pcc_cfg = hw_cfg->payload; + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[PCC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, PCC, dspp_buf[PCC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + data = kzalloc(PCC_LEN, GFP_KERNEL); + if (!data) + return; + + for (i = 0; i < PCC_NUM_PLANES; i++) { + switch (i) { + case 0: + coeffs = &pcc_cfg->r; + data[i + 24] = pcc_cfg->r_rr; + data[i + 27] = pcc_cfg->r_gg; + data[i + 30] = pcc_cfg->r_bb; + break; + case 1: + coeffs = &pcc_cfg->g; + data[i + 24] = pcc_cfg->g_rr; + data[i + 27] = pcc_cfg->g_gg; + data[i + 30] = pcc_cfg->g_bb; + break; + case 2: + coeffs = &pcc_cfg->b; + data[i + 24] = pcc_cfg->b_rr; + data[i + 27] = pcc_cfg->b_gg; + data[i + 30] = pcc_cfg->b_bb; + break; + default: + DRM_ERROR("invalid pcc plane: %d\n", i); + goto exit; + } + + data[i] = coeffs->c; + data[i + 3] = coeffs->r; + data[i + 6] = coeffs->g; + data[i + 9] = coeffs->b; + data[i + 12] = coeffs->rg; + data[i + 15] = coeffs->rb; + data[i + 18] = coeffs->gb; + data[i + 21] = coeffs->rgb; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->pcc.base + PCC_C_OFF, + data, PCC_LEN, + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write pcc lut failed ret %d\n", rc); + goto exit; + } + + reg = PCC_EN; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->pcc.base, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + goto exit; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[PCC][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); + +exit: + kfree(data); +} + +void reg_dmav1_setup_dspp_pa_hsicv17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct drm_msm_pa_hsic *hsic_cfg; + struct sde_hw_dspp *dspp_list[DSPP_MAX]; + u32 reg = 0, opcode = 0, local_opcode = 0; + int rc, i; + u32 num_of_mixers, blk = 0; + + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + rc = reg_dma_dspp_check(ctx, cfg, HSIC); + if (rc) + return; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable pa hsic feature\n"); + opcode &= ~(PA_HUE_EN | PA_SAT_EN | PA_VAL_EN | PA_CONT_EN); + if (PA_DISABLE_REQUIRED(opcode)) + opcode &= ~PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_pa_hsic)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pa_hsic)); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } else if (num_of_mixers > DSPP_MAX) { + DRM_ERROR("unable to process more than %d DSPP blocks\n", + DSPP_MAX); + return; + } else if (num_of_mixers > 1) { + memcpy(dspp_list, hw_cfg->dspp, + sizeof(struct sde_hw_dspp *) * num_of_mixers); + } else { + dspp_list[0] = ctx; + } + + hsic_cfg = hw_cfg->payload; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[HSIC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, HSIC, dspp_buf[HSIC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (hsic_cfg->flags & PA_HSIC_HUE_ENABLE) { + reg = hsic_cfg->hue & PA_HUE_MASK; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base + PA_HUE_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("hsic hue write failed ret %d\n", rc); + return; + } + local_opcode |= PA_HUE_EN; + } + + if (hsic_cfg->flags & PA_HSIC_SAT_ENABLE) { + reg = hsic_cfg->saturation & PA_SAT_MASK; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base + PA_SAT_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("hsic saturation write failed ret %d\n", rc); + return; + } + local_opcode |= PA_SAT_EN; + } + + if (hsic_cfg->flags & PA_HSIC_VAL_ENABLE) { + reg = hsic_cfg->value & PA_VAL_MASK; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base + PA_VAL_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("hsic value write failed ret %d\n", rc); + return; + } + local_opcode |= PA_VAL_EN; + } + + if (hsic_cfg->flags & PA_HSIC_CONT_ENABLE) { + reg = hsic_cfg->contrast & PA_CONT_MASK; + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base + PA_CONT_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("hsic contrast write failed ret %d\n", rc); + return; + } + local_opcode |= PA_CONT_EN; + } + + if (local_opcode) { + local_opcode |= PA_EN; + } else { + DRM_ERROR("Invalid hsic config 0x%x\n", local_opcode); + return; + } + + for (i = 0; i < num_of_mixers; i++) { + blk = dspp_mapping[dspp_list[i]->idx]; + REG_DMA_INIT_OPS(dma_write_cfg, blk, HSIC, + dspp_buf[HSIC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, + 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base, &local_opcode, + sizeof(local_opcode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_PA_MODE_HSIC_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, dspp_buf[HSIC][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dspp_sixzonev17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct drm_msm_sixzone *sixzone; + struct sde_hw_dspp *dspp_list[DSPP_MAX]; + u32 reg = 0, local_hold = 0; + u32 opcode = 0, local_opcode = 0; + u32 num_of_mixers, blk = 0; + int rc, i; + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + rc = reg_dma_dspp_check(ctx, cfg, SIX_ZONE); + if (rc) + return; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable sixzone feature\n"); + opcode &= ~(PA_SIXZONE_HUE_EN | PA_SIXZONE_SAT_EN | + PA_SIXZONE_VAL_EN); + if (PA_DISABLE_REQUIRED(opcode)) + opcode &= ~PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_sixzone)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_sixzone)); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } else if (num_of_mixers > DSPP_MAX) { + DRM_ERROR("unable to process more than %d DSPP blocks\n", + DSPP_MAX); + return; + } else if (num_of_mixers > 1) { + memcpy(dspp_list, hw_cfg->dspp, + sizeof(struct sde_hw_dspp *) * num_of_mixers); + } else { + dspp_list[0] = ctx; + } + + sixzone = hw_cfg->payload; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[SIX_ZONE][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, SIX_ZONE, + dspp_buf[SIX_ZONE][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + reg = BIT(26); + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting lut index failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + (ctx->cap->sblk->sixzone.base + SIXZONE_ADJ_CURVE_P1_OFF), + &sixzone->curve[0].p1, (SIXZONE_LUT_SIZE * sizeof(u32) * 2), + REG_BLK_WRITE_MULTIPLE, 2, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone lut failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->sixzone.base + SIXZONE_THRESHOLDS_OFF, + &sixzone->threshold, 3 * sizeof(u32), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write sixzone threshold failed ret %d\n", rc); + return; + } + + local_hold = ((sixzone->sat_hold & REG_MASK(2)) << 12); + local_hold |= ((sixzone->val_hold & REG_MASK(2)) << 14); + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base + PA_PWL_HOLD_OFF, &local_hold, + sizeof(local_hold), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_PA_PWL_HOLD_SZONE_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting local_hold failed ret %d\n", rc); + return; + } + + if (sixzone->flags & SIXZONE_HUE_ENABLE) + local_opcode |= PA_SIXZONE_HUE_EN; + if (sixzone->flags & SIXZONE_SAT_ENABLE) + local_opcode |= PA_SIXZONE_SAT_EN; + if (sixzone->flags & SIXZONE_VAL_ENABLE) + local_opcode |= PA_SIXZONE_VAL_EN; + + if (local_opcode) { + local_opcode |= PA_EN; + } else { + DRM_ERROR("Invalid six zone config 0x%x\n", local_opcode); + return; + } + + for (i = 0; i < num_of_mixers; i++) { + blk = dspp_mapping[dspp_list[i]->idx]; + REG_DMA_INIT_OPS(dma_write_cfg, blk, SIX_ZONE, + dspp_buf[SIX_ZONE][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, + 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base, &local_opcode, + sizeof(local_opcode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_PA_MODE_SZONE_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting local_opcode failed ret %d\n", rc); + return; + } + } + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + dspp_buf[SIX_ZONE][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +int reg_dmav1_deinit_dspp_ops(enum sde_dspp idx) +{ + int i; + struct sde_hw_reg_dma_ops *dma_ops; + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + if (idx >= DSPP_MAX) { + DRM_ERROR("invalid dspp idx %x max %xd\n", idx, DSPP_MAX); + return -EINVAL; + } + + for (i = 0; i < REG_DMA_FEATURES_MAX; i++) { + if (!dspp_buf[i][idx]) + continue; + dma_ops->dealloc_reg_dma(dspp_buf[i][idx]); + dspp_buf[i][idx] = NULL; + } + return 0; +} + +static void __setup_dspp_memcol(struct sde_hw_dspp *ctx, + enum sde_reg_dma_features type, + struct sde_hw_cp_cfg *hw_cfg) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct drm_msm_memcol *memcolor; + struct sde_hw_dspp *dspp_list[DSPP_MAX]; + int rc, i; + u32 addr = 0, idx = 0; + u32 hold = 0, hold_shift = 0, mask = 0xFFFF; + u32 opcode = 0, opcode_mask = 0xFFFFFFFF; + u32 num_of_mixers, blk = 0; + + switch (type) { + case MEMC_SKIN: + idx = 0; + opcode |= PA_SKIN_EN; + break; + case MEMC_SKY: + idx = 1; + opcode |= PA_SKY_EN; + break; + case MEMC_FOLIAGE: + idx = 2; + opcode |= PA_FOL_EN; + break; + default: + DRM_ERROR("Invalid memory color type %d\n", type); + return; + } + + rc = reg_dmav1_get_dspp_blk(hw_cfg, ctx->idx, &blk, + &num_of_mixers); + if (rc == -EINVAL) { + DRM_ERROR("unable to determine LUTDMA DSPP blocks\n"); + return; + } else if (rc == -EALREADY) { + return; + } else if (num_of_mixers > DSPP_MAX) { + DRM_ERROR("unable to process more than %d DSPP blocks\n", + DSPP_MAX); + return; + } else if (num_of_mixers > 1) { + memcpy(dspp_list, hw_cfg->dspp, + sizeof(struct sde_hw_dspp *) * num_of_mixers); + } else { + dspp_list[0] = ctx; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[type][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, type, dspp_buf[type][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + memcolor = hw_cfg->payload; + addr = ctx->cap->sblk->memcolor.base + MEMCOL_PWL0_OFF + + (idx * MEMCOL_SIZE0); + /* write color_adjust_p0 and color_adjust_p1 */ + REG_DMA_SETUP_OPS(dma_write_cfg, addr, &memcolor->color_adjust_p0, + sizeof(u32) * 2, REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting color_adjust_p0 failed ret %d\n", rc); + return; + } + + /* write hue/sat/val region */ + addr += 8; + REG_DMA_SETUP_OPS(dma_write_cfg, addr, &memcolor->hue_region, + sizeof(u32) * 3, REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting color_adjust_p0 failed ret %d\n", rc); + return; + } + + addr = ctx->cap->sblk->memcolor.base + MEMCOL_PWL2_OFF + + (idx * MEMCOL_SIZE1); + /* write color_adjust_p2 and blend_gain */ + REG_DMA_SETUP_OPS(dma_write_cfg, addr, &memcolor->color_adjust_p2, + sizeof(u32) * 2, REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting color_adjust_p0 failed ret %d\n", rc); + return; + } + + addr = ctx->cap->sblk->hsic.base + PA_PWL_HOLD_OFF; + hold_shift = idx * MEMCOL_HOLD_SIZE; + hold = ((memcolor->sat_hold & REG_MASK(2)) << hold_shift); + hold |= ((memcolor->val_hold & REG_MASK(2)) << (hold_shift + 2)); + mask &= ~REG_MASK_SHIFT(4, hold_shift); + opcode |= PA_EN; + opcode_mask &= ~(opcode); + + /* write sat_hold and val_hold in PA_PWL_HOLD */ + for (i = 0; i < num_of_mixers; i++) { + blk = dspp_mapping[dspp_list[i]->idx]; + REG_DMA_INIT_OPS(dma_write_cfg, blk, type, + dspp_buf[type][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, + 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, addr, &hold, sizeof(hold), + REG_SINGLE_MODIFY, 0, 0, mask); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting color_adjust_p0 failed ret %d\n", + rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base, &opcode, sizeof(opcode), + REG_SINGLE_MODIFY, 0, 0, opcode_mask); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + dspp_buf[type][ctx->idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dspp_memcol_skinv17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 opcode = 0; + int rc; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + rc = reg_dma_dspp_check(ctx, cfg, MEMC_SKIN); + if (rc) + return; + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor skin feature\n"); + opcode &= ~(PA_SKIN_EN); + if (PA_DISABLE_REQUIRED(opcode)) + opcode &= ~PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + __setup_dspp_memcol(ctx, MEMC_SKIN, hw_cfg); +} + +void reg_dmav1_setup_dspp_memcol_skyv17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 opcode = 0; + int rc; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + rc = reg_dma_dspp_check(ctx, cfg, MEMC_SKY); + if (rc) + return; + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor sky feature\n"); + opcode &= ~(PA_SKY_EN); + if (PA_DISABLE_REQUIRED(opcode)) + opcode &= ~PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + __setup_dspp_memcol(ctx, MEMC_SKY, hw_cfg); +} + +void reg_dmav1_setup_dspp_memcol_folv17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 opcode = 0; + int rc; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + rc = reg_dma_dspp_check(ctx, cfg, MEMC_FOLIAGE); + if (rc) + return; + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor foliage feature\n"); + opcode &= ~(PA_FOL_EN); + if (PA_DISABLE_REQUIRED(opcode)) + opcode &= ~PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + __setup_dspp_memcol(ctx, MEMC_FOLIAGE, hw_cfg); +} + +void reg_dmav1_setup_dspp_memcol_protv17(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct drm_msm_memcol *memcolor; + int rc; + u32 opcode = 0, opcode_mask = 0xFFFFFFFF; + + if (!ctx || !cfg) { + DRM_ERROR("invalid param ctx %pK cfg %pK\n", ctx, cfg); + return; + } + + rc = reg_dma_dspp_check(ctx, cfg, MEMC_PROT); + if (rc) + return; + + opcode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->hsic.base); + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable memcolor prot feature\n"); + opcode &= ~(MEMCOL_PROT_MASK); + if (PA_DISABLE_REQUIRED(opcode)) + opcode &= ~PA_EN; + SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->hsic.base, opcode); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_memcol)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_memcol)); + return; + } + + memcolor = hw_cfg->payload; + opcode = 0; + if (memcolor->prot_flags) { + if (memcolor->prot_flags & MEMCOL_PROT_HUE) + opcode |= MEMCOL_PROT_HUE_EN; + if (memcolor->prot_flags & MEMCOL_PROT_SAT) + opcode |= MEMCOL_PROT_SAT_EN; + if (memcolor->prot_flags & MEMCOL_PROT_VAL) + opcode |= MEMCOL_PROT_VAL_EN; + if (memcolor->prot_flags & MEMCOL_PROT_CONT) + opcode |= MEMCOL_PROT_CONT_EN; + if (memcolor->prot_flags & MEMCOL_PROT_SIXZONE) + opcode |= MEMCOL_PROT_SIXZONE_EN; + if (memcolor->prot_flags & MEMCOL_PROT_BLEND) + opcode |= MEMCOL_PROT_BLEND_EN; + } + + if (!opcode) { + DRM_ERROR("Invalid memcolor prot config 0x%x\n", opcode); + return; + } + opcode |= PA_EN; + opcode_mask &= ~(MEMCOL_PROT_MASK); + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(dspp_buf[MEMC_PROT][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, dspp_mapping[ctx->idx], + MEMC_PROT, dspp_buf[MEMC_PROT][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + ctx->cap->sblk->hsic.base, &opcode, sizeof(opcode), + REG_SINGLE_MODIFY, 0, 0, opcode_mask); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + dspp_buf[MEMC_PROT][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx) +{ + int rc = -ENOTSUPP; + struct sde_hw_reg_dma_ops *dma_ops; + bool is_supported = false; + u32 blk, i = 0; + + if (feature >= SDE_SSPP_MAX || idx >= SSPP_MAX) { + DRM_ERROR("invalid feature %x max %x sspp idx %x max %xd\n", + feature, SDE_SSPP_MAX, idx, SSPP_MAX); + return rc; + } + + if (sspp_feature_map[feature] >= REG_DMA_FEATURES_MAX) { + DRM_ERROR("invalid feature map %d for feature %d\n", + sspp_feature_map[feature], feature); + return -ENOTSUPP; + } + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + blk = sspp_mapping[idx]; + rc = dma_ops->check_support(sspp_feature_map[feature], blk, + &is_supported); + if (!rc) + rc = (is_supported) ? 0 : -ENOTSUPP; + + if (!rc) { + for (i = SDE_SSPP_RECT_SOLO; i < SDE_SSPP_RECT_MAX; i++) { + rc = reg_dma_buf_init( + &sspp_buf[i][sspp_feature_map[feature]][idx], + sspp_feature_reg_dma_sz[feature]); + if (rc) { + DRM_ERROR("rect %d buf init failed\n", i); + break; + } + } + + } + + return rc; +} + +static int reg_dma_sspp_check(struct sde_hw_pipe *ctx, void *cfg, + enum sde_reg_dma_features feature, + enum sde_sspp_multirect_index idx) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_hw_cp_cfg *hw_cfg = cfg; + + if (!cfg || !ctx) { + DRM_ERROR("invalid cfg %pK ctx %pK\n", cfg, ctx); + return -EINVAL; + } + + if (idx >= SDE_SSPP_RECT_MAX) { + DRM_ERROR("invalid multirect idx %d\n", idx); + return -EINVAL; + } + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -EINVAL; + + if (!hw_cfg->ctl || ctx->idx > SSPP_DMA3 || ctx->idx <= SSPP_NONE || + feature >= REG_DMA_FEATURES_MAX) { + DRM_ERROR("invalid ctl %pK sspp idx %d feature %d\n", + hw_cfg->ctl, ctx->idx, feature); + return -EINVAL; + } + + if (!sspp_buf[idx][feature][ctx->idx]) { + DRM_ERROR("invalid dma_buf for rect idx %d sspp idx %d\n", idx, + ctx->idx); + return -EINVAL; + } + + return 0; +} + +static void vig_gamutv5_off(struct sde_hw_pipe *ctx, void *cfg) +{ + int rc; + u32 op_mode = 0; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GAMUT][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GAMUT, + sspp_buf[idx][GAMUT][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, gamut_base, + &op_mode, sizeof(op_mode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_VIG_GAMUT_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode modify single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GAMUT][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg) +{ + int rc; + u32 i, op_mode, reg, tbl_len, tbl_off, scale_off, scale_tbl_off; + u32 *scale_data; + struct drm_msm_3d_gamut *payload; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 gamut_base = ctx->cap->sblk->gamut_blk.base - REG_DMA_VIG_SWI_DIFF; + bool use_2nd_memory = false; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; + + rc = reg_dma_sspp_check(ctx, cfg, GAMUT, idx); + if (rc) + return; + + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("disable gamut feature\n"); + /* v5 and v6 call the same off version */ + vig_gamutv5_off(ctx, cfg); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_3d_gamut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_3d_gamut)); + return; + } + op_mode = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->gamut_blk.base); + payload = hw_cfg->payload; + rc = sde_gamut_get_mode_info(SSPP, payload, &tbl_len, &tbl_off, + &op_mode, &scale_off); + if (rc) { + DRM_ERROR("invalid mode info rc %d\n", rc); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GAMUT][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GAMUT, + sspp_buf[idx][GAMUT][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + if ((op_mode & (BIT(5) - 1)) >> 2 == gamut_mode_17b) + use_2nd_memory = true; + for (i = 0; i < GAMUT_3D_TBL_NUM; i++) { + reg = GAMUT_TABLE0_SEL << i; + reg |= ((tbl_off) & (BIT(11) - 1)); + /* when bit 11 equals to 1, 2nd memory will be in use */ + if (use_2nd_memory) + reg |= BIT(11); + REG_DMA_SETUP_OPS(dma_write_cfg, + gamut_base + GAMUT_TABLE_SEL_OFF, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write tbl sel reg failed ret %d\n", rc); + return; + } + REG_DMA_SETUP_OPS(dma_write_cfg, + gamut_base + GAMUT_LOWER_COLOR_OFF, + &payload->col[i][0].c2_c1, tbl_len, + REG_BLK_WRITE_MULTIPLE, 2, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write color reg failed ret %d\n", rc); + return; + } + } + + if (op_mode & GAMUT_MAP_EN) { + for (i = 0; i < GAMUT_3D_SCALE_OFF_TBL_NUM; i++) { + scale_tbl_off = gamut_base + scale_off + + (i * GAMUT_SCALE_OFF_LEN); + scale_data = &payload->scale_off[i][0]; + REG_DMA_SETUP_OPS(dma_write_cfg, scale_tbl_off, + scale_data, GAMUT_SCALE_OFF_LEN, + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write scale/off reg failed ret %d\n", + rc); + return; + } + } + } + + REG_DMA_SETUP_OPS(dma_write_cfg, gamut_base, + &op_mode, sizeof(op_mode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_VIG_GAMUT_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GAMUT][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_vig_gamutv6(struct sde_hw_pipe *ctx, void *cfg) +{ + reg_dmav1_setup_vig_gamutv5(ctx, cfg); +} + +static void vig_igcv5_off(struct sde_hw_pipe *ctx, void *cfg) +{ + int rc; + u32 op_mode = 0; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, + sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, igc_base, &op_mode, sizeof(op_mode), + REG_SINGLE_MODIFY, 0, 0, REG_DMA_VIG_IGC_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode modify single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +static int reg_dmav1_setup_vig_igc_common(struct sde_hw_reg_dma_ops *dma_ops, + struct sde_reg_dma_setup_ops_cfg *dma_write_cfg, + struct sde_hw_pipe *ctx, + struct sde_hw_cp_cfg *hw_cfg, u32 mask, + struct drm_msm_igc_lut *igc_lut) +{ + int rc = 0; + u32 i = 0, j = 0, reg = 0, index = 0; + u32 offset = 0; + u32 lut_sel = 0, lut_enable = 0; + u32 *data = NULL, *data_ptr = NULL; + u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF; + u32 *addr[IGC_TBL_NUM]; + + if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_igc_lut)); + } + + data = kzalloc(VIG_1D_LUT_IGC_LEN * sizeof(u32), GFP_KERNEL); + if (!data) + return -ENOMEM; + + reg = SDE_REG_READ(&ctx->hw, ctx->cap->sblk->igc_blk[0].base); + lut_enable = (reg >> 8) & BIT(0); + lut_sel = (reg >> 9) & BIT(0); + /* select LUT table (0 or 1) when 1D LUT is in active mode */ + if (lut_enable) + lut_sel = (~lut_sel) && BIT(0); + + addr[0] = igc_lut->c0; + addr[1] = igc_lut->c1; + addr[2] = igc_lut->c2; + for (i = 0; i < IGC_TBL_NUM; i++) { + /* write 0 to the index register */ + index = 0; + REG_DMA_SETUP_OPS(*dma_write_cfg, igc_base + 0x1B0, + &index, sizeof(index), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(dma_write_cfg); + if (rc) { + DRM_ERROR("VIG IGC index write failed ret %d\n", rc); + goto exit; + } + + offset = igc_base + 0x1B4 + i * sizeof(u32); + data_ptr = addr[i]; + for (j = 0; j < VIG_1D_LUT_IGC_LEN; j++) + data[j] = (data_ptr[2 * j] & mask) | + (data_ptr[2 * j + 1] & mask) << 16; + + REG_DMA_SETUP_OPS(*dma_write_cfg, offset, data, + VIG_1D_LUT_IGC_LEN * sizeof(u32), + REG_BLK_WRITE_INC, 0, 0, 0); + rc = dma_ops->setup_payload(dma_write_cfg); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + goto exit; + } + } + + if (igc_lut->flags & IGC_DITHER_ENABLE) { + reg = igc_lut->strength & IGC_DITHER_DATA_MASK; + reg |= BIT(4); + } else { + reg = 0; + } + REG_DMA_SETUP_OPS(*dma_write_cfg, igc_base + 0x1C0, + ®, sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(dma_write_cfg); + if (rc) { + DRM_ERROR("dither strength failed ret %d\n", rc); + goto exit; + } + + reg = BIT(8) | (lut_sel << 9); + REG_DMA_SETUP_OPS(*dma_write_cfg, igc_base, ®, sizeof(reg), + REG_SINGLE_MODIFY, 0, 0, REG_DMA_VIG_IGC_OP_MASK); + rc = dma_ops->setup_payload(dma_write_cfg); + if (rc) + DRM_ERROR("setting opcode failed ret %d\n", rc); +exit: + kfree(data); + return rc; +} + +void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg) +{ + int rc; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct drm_msm_igc_lut *igc_lut; + struct sde_hw_cp_cfg *hw_cfg = cfg; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + + rc = reg_dma_sspp_check(ctx, hw_cfg, IGC, idx); + if (rc) + return; + + igc_lut = hw_cfg->payload; + if (!igc_lut) { + DRM_DEBUG_DRIVER("disable igc feature\n"); + vig_igcv5_off(ctx, hw_cfg); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, + sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + rc = reg_dmav1_setup_vig_igc_common(dma_ops, &dma_write_cfg, + ctx, cfg, VIG_IGC_DATA_MASK, igc_lut); + if (rc) { + DRM_ERROR("setup_vig_igc_common failed\n"); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_vig_igcv6(struct sde_hw_pipe *ctx, void *cfg) +{ + int rc; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg *hw_cfg = cfg; + u32 igc_base = ctx->cap->sblk->igc_blk[0].base - REG_DMA_VIG_SWI_DIFF; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; + struct drm_msm_igc_lut *igc_lut; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + + rc = reg_dma_sspp_check(ctx, hw_cfg, IGC, idx); + if (rc) + return; + + igc_lut = hw_cfg->payload; + if (!igc_lut) { + DRM_DEBUG_DRIVER("disable igc feature\n"); + /* Both v5 and v6 call same igcv5_off */ + vig_igcv5_off(ctx, hw_cfg); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, + sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + rc = reg_dmav1_setup_vig_igc_common(dma_ops, &dma_write_cfg, + ctx, cfg, VIG_IGC_DATA_MASK_V6, igc_lut); + if (rc) { + DRM_ERROR("setup_vig_igcv6 failed\n"); + return; + } + + /* Perform LAST_LUT required for v6*/ + REG_DMA_SETUP_OPS(dma_write_cfg, igc_base + 0x1C4, &igc_lut->c0_last, + sizeof(u32) * 3, REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("c_last failed ret %d", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +static void dma_igcv5_off(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx) +{ + int rc; + u32 op_mode = 0; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 igc_opmode_off; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, + sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) + igc_opmode_off = DMA_DGM_0_OP_MODE_OFF; + else + igc_opmode_off = DMA_DGM_1_OP_MODE_OFF; + + REG_DMA_SETUP_OPS(dma_write_cfg, igc_opmode_off, &op_mode, + sizeof(op_mode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_DMA_IGC_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode modify single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx) +{ + int rc; + u32 i = 0, reg = 0; + u32 *data = NULL; + struct drm_msm_igc_lut *igc_lut; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 igc_base, igc_dither_off, igc_opmode_off; + + rc = reg_dma_sspp_check(ctx, cfg, IGC, idx); + if (rc) + return; + + igc_lut = hw_cfg->payload; + if (!igc_lut) { + DRM_DEBUG_DRIVER("disable igc feature\n"); + dma_igcv5_off(ctx, cfg, idx); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_igc_lut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_igc_lut)); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], IGC, + sspp_buf[idx][IGC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + data = kzalloc(DMA_1D_LUT_IGC_LEN * sizeof(u32), GFP_KERNEL); + if (!data) { + DRM_ERROR("failed to allocate memory for igc\n"); + return; + } + + /* client packs the 1D LUT data in c2 instead of c0 */ + for (i = 0; i < DMA_1D_LUT_IGC_LEN; i++) + data[i] = (igc_lut->c2[2 * i] & IGC_DATA_MASK) | + ((igc_lut->c2[2 * i + 1] & IGC_DATA_MASK) << 16); + + if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) { + igc_base = ctx->cap->sblk->igc_blk[0].base - + REG_DMA_DMA_SWI_DIFF; + igc_dither_off = igc_base + DMA_1D_LUT_IGC_DITHER_OFF; + igc_opmode_off = DMA_DGM_0_OP_MODE_OFF; + } else { + igc_base = ctx->cap->sblk->igc_blk[1].base - + REG_DMA_DMA_SWI_DIFF; + igc_dither_off = igc_base + DMA_1D_LUT_IGC_DITHER_OFF; + igc_opmode_off = DMA_DGM_1_OP_MODE_OFF; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, igc_base, data, + DMA_1D_LUT_IGC_LEN * sizeof(u32), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + goto igc_exit; + } + if (igc_lut->flags & IGC_DITHER_ENABLE) { + reg = igc_lut->strength & IGC_DITHER_DATA_MASK; + reg |= BIT(4); + } else { + reg = 0; + } + REG_DMA_SETUP_OPS(dma_write_cfg, igc_dither_off, ®, + sizeof(reg), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("failed to set dither strength %d\n", rc); + goto igc_exit; + } + + reg = BIT(1); + REG_DMA_SETUP_OPS(dma_write_cfg, igc_opmode_off, ®, sizeof(reg), + REG_SINGLE_MODIFY, 0, 0, REG_DMA_DMA_IGC_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + goto igc_exit; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][IGC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +igc_exit: + kfree(data); +} + +static void dma_gcv5_off(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx) +{ + int rc; + u32 op_mode = 0; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 gc_opmode_off; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GC, + sspp_buf[idx][GC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) + gc_opmode_off = DMA_DGM_0_OP_MODE_OFF; + else + gc_opmode_off = DMA_DGM_1_OP_MODE_OFF; + + REG_DMA_SETUP_OPS(dma_write_cfg, gc_opmode_off, &op_mode, + sizeof(op_mode), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_DMA_GC_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode modify single reg failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx) +{ + int rc; + u32 reg = 0; + struct drm_msm_pgc_lut *gc_lut; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + u32 gc_base, gc_opmode_off; + + rc = reg_dma_sspp_check(ctx, cfg, GC, idx); + if (rc) + return; + + gc_lut = hw_cfg->payload; + if (!gc_lut) { + DRM_DEBUG_DRIVER("disable gc feature\n"); + dma_gcv5_off(ctx, cfg, idx); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_pgc_lut)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_pgc_lut)); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][GC][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], GC, + sspp_buf[idx][GC][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (idx == SDE_SSPP_RECT_SOLO || idx == SDE_SSPP_RECT_0) { + gc_base = ctx->cap->sblk->gc_blk[0].base - REG_DMA_DMA_SWI_DIFF; + gc_opmode_off = DMA_DGM_0_OP_MODE_OFF; + } else { + gc_base = ctx->cap->sblk->gc_blk[1].base - REG_DMA_DMA_SWI_DIFF; + gc_opmode_off = DMA_DGM_1_OP_MODE_OFF; + } + + /* client packs the 1D LUT data in c2 instead of c0, + * and even & odd values are already stacked in register foramt + */ + REG_DMA_SETUP_OPS(dma_write_cfg, gc_base, gc_lut->c2, + DMA_1D_LUT_GC_LEN * sizeof(u32), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + reg = BIT(2); + REG_DMA_SETUP_OPS(dma_write_cfg, gc_opmode_off, ®, + sizeof(reg), REG_SINGLE_MODIFY, 0, 0, + REG_DMA_DMA_GC_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opcode failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, + sspp_buf[idx][GC][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); +} + +int reg_dmav1_deinit_sspp_ops(enum sde_sspp idx) +{ + u32 i, j; + struct sde_hw_reg_dma_ops *dma_ops; + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + if (idx >= SSPP_MAX) { + DRM_ERROR("invalid sspp idx %x max %x\n", idx, SSPP_MAX); + return -EINVAL; + } + + for (i = SDE_SSPP_RECT_SOLO; i < SDE_SSPP_RECT_MAX; i++) { + for (j = 0; j < REG_DMA_FEATURES_MAX; j++) { + if (!sspp_buf[i][j][idx]) + continue; + dma_ops->dealloc_reg_dma(sspp_buf[i][j][idx]); + sspp_buf[i][j][idx] = NULL; + } + } + return 0; +} + +void reg_dmav1_setup_scaler3_lut(struct sde_reg_dma_setup_ops_cfg *buf, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset) +{ + int i, filter, rc; + int config_lut = 0x0; + unsigned long lut_flags; + u32 lut_addr, lut_offset, lut_len; + struct sde_hw_reg_dma_ops *dma_ops; + u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL}; + static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = { + {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} }, + {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} }, + {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} }, + {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} }, + {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} }, + }; + + dma_ops = sde_reg_dma_get_ops(); + lut_flags = (unsigned long) scaler3_cfg->lut_flag; + if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) && + (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) { + lut[0] = scaler3_cfg->dir_lut; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && + (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { + lut[1] = scaler3_cfg->cir_lut + + scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) && + (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && + (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { + lut[2] = scaler3_cfg->cir_lut + + scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { + lut[3] = scaler3_cfg->sep_lut + + scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && + (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { + lut[4] = scaler3_cfg->sep_lut + + scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + + for (filter = 0; filter < QSEED3_FILTERS && config_lut; filter++) { + if (!lut[filter]) + continue; + lut_offset = 0; + for (i = 0; i < QSEED3_LUT_REGIONS; i++) { + lut_addr = QSEED3_COEF_LUT_OFF + offset + + off_tbl[filter][i][1]; + lut_len = off_tbl[filter][i][0] << 2; + REG_DMA_SETUP_OPS(*buf, lut_addr, + &lut[filter][lut_offset], lut_len * sizeof(u32), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(buf); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + lut_offset += lut_len; + } + } + + if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) { + i = BIT(0); + REG_DMA_SETUP_OPS(*buf, QSEED3_COEF_LUT_CTRL_OFF + offset, &i, + sizeof(i), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(buf); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + } + +} + +void reg_dmav1_setup_scaler3lite_lut( + struct sde_reg_dma_setup_ops_cfg *buf, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset) +{ + int i, filter, rc; + int config_lut = 0x0; + unsigned long lut_flags; + u32 lut_addr, lut_offset; + struct sde_hw_reg_dma_ops *dma_ops; + u32 *lut[QSEED3LITE_FILTERS] = {NULL, NULL}; + static const uint32_t off_tbl[QSEED3LITE_FILTERS] = {0x000, 0x200}; + + /* destination scaler case */ + if (!scaler3_cfg->sep_lut) + return; + + dma_ops = sde_reg_dma_get_ops(); + lut_flags = (unsigned long) scaler3_cfg->lut_flag; + if (test_bit(QSEED3L_COEF_LUT_Y_SEP_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3L_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3L_SEP_LUT_SIZE)) { + lut[Y_INDEX] = scaler3_cfg->sep_lut + + scaler3_cfg->y_rgb_sep_lut_idx * QSEED3L_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3L_COEF_LUT_UV_SEP_BIT, &lut_flags) && + (scaler3_cfg->uv_sep_lut_idx < QSEED3L_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3L_SEP_LUT_SIZE)) { + lut[UV_INDEX] = scaler3_cfg->sep_lut + + scaler3_cfg->uv_sep_lut_idx * QSEED3L_LUT_SIZE; + config_lut = 1; + } + + for (filter = 0; filter < QSEED3LITE_FILTERS && config_lut; filter++) { + if (!lut[filter]) + continue; + lut_offset = 0; + lut_addr = QSEED3L_COEF_LUT_OFF + offset + + off_tbl[filter]; + REG_DMA_SETUP_OPS(*buf, lut_addr, + &lut[filter][0], QSEED3L_LUT_SIZE * sizeof(u32), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(buf); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + } + + if (test_bit(QSEED3L_COEF_LUT_SWAP_BIT, &lut_flags)) { + i = BIT(0); + REG_DMA_SETUP_OPS(*buf, QSEED3L_COEF_LUT_CTRL_OFF + offset, &i, + sizeof(i), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(buf); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + } +} + +static int reg_dmav1_setup_scaler3_de(struct sde_reg_dma_setup_ops_cfg *buf, + struct sde_hw_scaler3_de_cfg *de_cfg, u32 offset) +{ + u32 de_config[7]; + struct sde_hw_reg_dma_ops *dma_ops; + int rc; + + dma_ops = sde_reg_dma_get_ops(); + de_config[0] = (de_cfg->sharpen_level1 & 0x1FF) | + ((de_cfg->sharpen_level2 & 0x1FF) << 16); + + de_config[1] = ((de_cfg->limit & 0xF) << 9) | + ((de_cfg->prec_shift & 0x7) << 13) | + ((de_cfg->clip & 0x7) << 16) | + ((de_cfg->blend & 0xF) << 20); + + de_config[2] = (de_cfg->thr_quiet & 0xFF) | + ((de_cfg->thr_dieout & 0x3FF) << 16); + + de_config[3] = (de_cfg->thr_low & 0x3FF) | + ((de_cfg->thr_high & 0x3FF) << 16); + + de_config[4] = (de_cfg->adjust_a[0] & 0x3FF) | + ((de_cfg->adjust_a[1] & 0x3FF) << 10) | + ((de_cfg->adjust_a[2] & 0x3FF) << 20); + + de_config[5] = (de_cfg->adjust_b[0] & 0x3FF) | + ((de_cfg->adjust_b[1] & 0x3FF) << 10) | + ((de_cfg->adjust_b[2] & 0x3FF) << 20); + + de_config[6] = (de_cfg->adjust_c[0] & 0x3FF) | + ((de_cfg->adjust_c[1] & 0x3FF) << 10) | + ((de_cfg->adjust_c[2] & 0x3FF) << 20); + + offset += QSEED3_DE_OFFSET; + REG_DMA_SETUP_OPS(*buf, offset, + de_config, sizeof(de_config), REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(buf); + if (rc) { + DRM_ERROR("de write failed ret %d\n", rc); + return rc; + } + return 0; +} + +void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *sspp, struct sde_hw_pixel_ext *pe, + void *scaler_cfg) +{ + struct sde_hw_scaler3_cfg *scaler3_cfg = scaler_cfg; + int rc; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_cp_cfg hw_cfg = {}; + u32 op_mode = 0, offset; + u32 preload, src_y_rgb, src_uv, dst, dir_weight; + u32 cache[4]; + enum sde_sspp_multirect_index idx = SDE_SSPP_RECT_0; + + if (!ctx || !pe || !scaler_cfg) { + DRM_ERROR("invalid params ctx %pK pe %pK scaler_cfg %pK", + ctx, pe, scaler_cfg); + return; + } + + hw_cfg.ctl = ctx->ctl; + hw_cfg.payload = scaler_cfg; + hw_cfg.len = sizeof(*scaler3_cfg); + rc = reg_dma_sspp_check(ctx, &hw_cfg, QSEED, idx); + if (rc || !sspp) { + DRM_ERROR("invalid params rc %d sspp %pK\n", rc, sspp); + return; + } + + offset = ctx->cap->sblk->scaler_blk.base - REG_DMA_VIG_SWI_DIFF; + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(sspp_buf[idx][QSEED][ctx->idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, sspp_mapping[ctx->idx], QSEED, + sspp_buf[idx][QSEED][ctx->idx]); + + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (!scaler3_cfg->enable) + goto end; + + op_mode = BIT(0); + op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16; + + if (sspp->layout.format && SDE_FORMAT_IS_YUV(sspp->layout.format)) { + op_mode |= BIT(12); + op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24; + } + + op_mode |= (scaler3_cfg->blend_cfg & 1) << 31; + op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0; + op_mode |= (scaler3_cfg->dyn_exp_disabled) ? BIT(13) : 0; + + preload = + ((scaler3_cfg->preload_x[0] & 0x7F) << 0) | + ((scaler3_cfg->preload_y[0] & 0x7F) << 8) | + ((scaler3_cfg->preload_x[1] & 0x7F) << 16) | + ((scaler3_cfg->preload_y[1] & 0x7F) << 24); + + src_y_rgb = (scaler3_cfg->src_width[0] & 0xFFFF) | + ((scaler3_cfg->src_height[0] & 0xFFFF) << 16); + + src_uv = (scaler3_cfg->src_width[1] & 0xFFFF) | + ((scaler3_cfg->src_height[1] & 0xFFFF) << 16); + + dst = (scaler3_cfg->dst_width & 0xFFFF) | + ((scaler3_cfg->dst_height & 0xFFFF) << 16); + + if (scaler3_cfg->de.enable) { + rc = reg_dmav1_setup_scaler3_de(&dma_write_cfg, + &scaler3_cfg->de, offset); + if (!rc) + op_mode |= BIT(8); + } + + ctx->ops.setup_scaler_lut(&dma_write_cfg, scaler3_cfg, offset); + + cache[0] = scaler3_cfg->init_phase_x[0] & 0x1FFFFF; + cache[1] = scaler3_cfg->init_phase_y[0] & 0x1FFFFF; + cache[2] = scaler3_cfg->init_phase_x[1] & 0x1FFFFF; + cache[3] = scaler3_cfg->init_phase_y[1] & 0x1FFFFF; + REG_DMA_SETUP_OPS(dma_write_cfg, + offset + 0x90, cache, sizeof(cache), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting phase failed ret %d\n", rc); + return; + } + + cache[0] = scaler3_cfg->phase_step_x[0] & 0xFFFFFF; + cache[1] = scaler3_cfg->phase_step_y[0] & 0xFFFFFF; + cache[2] = scaler3_cfg->phase_step_x[1] & 0xFFFFFF; + cache[3] = scaler3_cfg->phase_step_y[1] & 0xFFFFFF; + REG_DMA_SETUP_OPS(dma_write_cfg, + offset + 0x10, cache, sizeof(cache), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting phase failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + offset + 0x20, &preload, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting preload failed ret %d\n", rc); + return; + } + + cache[0] = src_y_rgb; + cache[1] = src_uv; + cache[2] = dst; + + REG_DMA_SETUP_OPS(dma_write_cfg, + offset + 0x40, cache, 3 * sizeof(u32), + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting sizes failed ret %d\n", rc); + return; + } + + if (is_qseed3_rev_qseed3lite(ctx->catalog)) { + dir_weight = (scaler3_cfg->dir_weight & 0xFF); + + REG_DMA_SETUP_OPS(dma_write_cfg, + offset + 0x60, &dir_weight, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("lut write failed ret %d\n", rc); + return; + } + } + +end: + if (sspp->layout.format) { + if (!SDE_FORMAT_IS_DX(sspp->layout.format)) + op_mode |= BIT(14); + if (sspp->layout.format->alpha_enable) { + op_mode |= BIT(10); + op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29; + } + } + + REG_DMA_SETUP_OPS(dma_write_cfg, + offset + 0x4, + &op_mode, sizeof(op_mode), REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("setting opmode failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg.ctl, + sspp_buf[idx][QSEED][ctx->idx], REG_DMA_WRITE, + DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) + DRM_ERROR("failed to kick off ret %d\n", rc); + +} + +int reg_dmav1_init_ltm_op_v6(int feature, enum sde_dspp dspp_idx) +{ + int rc = -ENOTSUPP; + struct sde_hw_reg_dma_ops *dma_ops; + bool is_supported = false; + u32 blk; + /* LTM blocks are hardwired to DSPP blocks */ + enum sde_ltm idx = (enum sde_ltm)dspp_idx; + + if (feature >= SDE_LTM_MAX || idx >= LTM_MAX) { + DRM_ERROR("invalid feature %x max %x ltm idx %x max %xd\n", + feature, SDE_LTM_MAX, idx, LTM_MAX); + return rc; + } + + if (ltm_feature_map[feature] >= REG_DMA_FEATURES_MAX) { + DRM_ERROR("invalid feature map %d for feature %d\n", + ltm_feature_map[feature], feature); + return -ENOTSUPP; + } + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + blk = ltm_mapping[idx]; + rc = dma_ops->check_support(ltm_feature_map[feature], blk, + &is_supported); + if (!rc) + rc = (is_supported) ? 0 : -ENOTSUPP; + + if (!rc) + rc = reg_dma_buf_init(<m_buf[ltm_feature_map[feature]][idx], + ltm_feature_reg_dma_sz[feature]); + return rc; +} + + +int reg_dmav1_deinit_ltm_ops(enum sde_dspp dspp_idx) +{ + int i; + struct sde_hw_reg_dma_ops *dma_ops; + /* LTM blocks are hardwired to DSPP blocks */ + enum sde_ltm idx = (enum sde_ltm)dspp_idx; + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -ENOTSUPP; + + if (idx >= LTM_MAX) { + DRM_DEBUG("invalid ltm idx %x max %xd\n", idx, LTM_MAX); + return -EINVAL; + } + + for (i = 0; i < REG_DMA_FEATURES_MAX; i++) { + if (!ltm_buf[i][idx]) + continue; + dma_ops->dealloc_reg_dma(ltm_buf[i][idx]); + ltm_buf[i][idx] = NULL; + } + return 0; +} + +static int reg_dma_ltm_check(struct sde_hw_dspp *ctx, void *cfg, + enum sde_reg_dma_features feature) +{ + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_hw_cp_cfg *hw_cfg = cfg; + + if (!ctx || !cfg) { + DRM_ERROR("invalid ctx %pK cfg %pK\n", ctx, cfg); + return -EINVAL; + } + + dma_ops = sde_reg_dma_get_ops(); + if (IS_ERR_OR_NULL(dma_ops)) + return -EINVAL; + + if (!hw_cfg->ctl || ctx->idx >= DSPP_MAX || + feature >= REG_DMA_FEATURES_MAX) { + DRM_ERROR("invalid ctl %pK dspp idx %d feature %d\n", + hw_cfg->ctl, ctx->idx, feature); + return -EINVAL; + } + + if (!ltm_buf[feature][ctx->idx]) { + DRM_ERROR("invalid dma_buf\n"); + return -EINVAL; + } + return 0; +} + +static int reg_dmav1_get_ltm_blk(struct sde_hw_cp_cfg *hw_cfg, + enum sde_ltm idx, enum sde_ltm *dspp_idx, u32 *blk) +{ + struct sde_hw_mixer *hw_lm = NULL; + u32 i = 0, num_mixers = 0; + + if (idx >= LTM_MAX) { + DRM_ERROR("invalid ltm idx %d\n", idx); + return -EINVAL; + } + + num_mixers = hw_cfg->num_of_mixers; + hw_lm = hw_cfg->mixer_info; + if (num_mixers == 1) { + *blk = ltm_mapping[idx]; + dspp_idx[0] = (enum sde_ltm)(hw_cfg->dspp[0]->idx); + } else if (num_mixers == 2) { + if (hw_lm->cfg.right_mixer) { + DRM_DEBUG_DRIVER("slave LTM instance\n"); + return -EALREADY; + } + *blk = 0; + for (i = 0; i < num_mixers; i++) { + if (hw_cfg->dspp[i] && (i < LTM_MAX)) { + dspp_idx[i] = + (enum sde_ltm)(hw_cfg->dspp[i]->idx); + *blk |= ltm_mapping[dspp_idx[i]]; + } else { + DRM_ERROR("invalid dspp = %pK, i = %d\n", + hw_cfg->dspp[i], i); + return -EINVAL; + } + } + } else { + DRM_ERROR("invalid num_of_mixers %d for LTM\n", + hw_cfg->num_of_mixers); + return -EINVAL; + } + return 0; +} + +static void ltm_initv1_disable(struct sde_hw_dspp *ctx, void *cfg, + u32 num_mixers, enum sde_ltm *dspp_idx) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + int rc, i = 0; + enum sde_ltm idx = 0; + u32 opmode = 0; + + idx = (enum sde_ltm)ctx->idx; + if (idx >= LTM_MAX) { + DRM_ERROR("invalid ltm idx %d\n", ctx->idx); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(ltm_buf[LTM_INIT][idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, ltm_mapping[idx], LTM_INIT, + ltm_buf[LTM_INIT][idx]); + + for (i = 0; i < num_mixers; i++) { + dma_write_cfg.blk = ltm_mapping[dspp_idx[i]]; + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, + 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + ltm_vlut_ops_mask[dspp_idx[i]] &= ~ltm_dither; + ltm_vlut_ops_mask[dspp_idx[i]] &= ~ltm_unsharp; + REG_DMA_SETUP_OPS(dma_write_cfg, 0x04, &opmode, sizeof(opmode), + REG_SINGLE_MODIFY, 0, 0, + 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, ltm_buf[LTM_INIT][idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} + +void reg_dmav1_setup_ltm_initv1(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct drm_msm_ltm_init_param *init_param = NULL; + struct sde_ltm_phase_info phase; + enum sde_ltm dspp_idx[LTM_MAX] = {0}; + enum sde_ltm idx = 0; + u32 blk = 0, opmode = 0, i = 0, num_mixers = 0; + u32 phase_data[3]; + int rc = 0; + + rc = reg_dma_ltm_check(ctx, cfg, LTM_INIT); + if (rc) + return; + + idx = (enum sde_ltm)ctx->idx; + rc = reg_dmav1_get_ltm_blk(hw_cfg, idx, &dspp_idx[0], &blk); + if (rc) { + if (rc != -EALREADY) + DRM_ERROR("failed to get the blk info\n"); + return; + } + + num_mixers = hw_cfg->num_of_mixers; + /* disable case */ + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable LTM init feature\n"); + ltm_initv1_disable(ctx, cfg, num_mixers, dspp_idx); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_ltm_init_param)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_ltm_init_param)); + return; + } + + init_param = hw_cfg->payload; + + + memset(&phase, 0, sizeof(phase)); + sde_ltm_get_phase_info(hw_cfg, &phase); + + if (phase.portrait_en) + opmode |= BIT(2); + else + opmode &= ~BIT(2); + + if (phase.merge_en) + opmode |= BIT(16); + else + opmode &= ~(BIT(16) | BIT(17)); + + phase_data[0] = phase.init_v; + phase_data[1] = phase.inc_h; + phase_data[2] = phase.inc_v; + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(ltm_buf[LTM_INIT][idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, LTM_INIT, ltm_buf[LTM_INIT][idx]); + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, 0x0c, phase_data, sizeof(u32) * 3, + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write phase data failed ret %d\n", + rc); + return; + } + + for (i = 0; i < num_mixers; i++) { + /* reset decode select to unicast for phase init_h value*/ + dma_write_cfg.blk = ltm_mapping[dspp_idx[i]]; + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, + 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, 0x08, + &phase.init_h[dspp_idx[i]], sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write failed ret %d\n", rc); + return; + } + + if (init_param->init_param_01) { + if (ltm_vlut_ops_mask[dspp_idx[i]] & ltm_vlut) + opmode |= BIT(6); + ltm_vlut_ops_mask[dspp_idx[i]] |= ltm_dither; + opmode |= ((init_param->init_param_02 & 0x7) << 12); + } else { + opmode &= ~BIT(6); + ltm_vlut_ops_mask[dspp_idx[i]] &= ~ltm_dither; + } + + if (init_param->init_param_03) { + if (ltm_vlut_ops_mask[dspp_idx[i]] & ltm_vlut) + opmode |= BIT(4); + ltm_vlut_ops_mask[dspp_idx[i]] |= ltm_unsharp; + opmode |= ((init_param->init_param_04 & 0x3) << 8); + } else { + opmode &= ~BIT(4); + ltm_vlut_ops_mask[dspp_idx[i]] &= ~ltm_unsharp; + } + + /* broadcast feature is not supported with REG_SINGLE_MODIFY */ + REG_DMA_SETUP_OPS(dma_write_cfg, 0x04, &opmode, sizeof(opmode), + REG_SINGLE_MODIFY, 0, 0, + REG_DMA_LTM_INIT_ENABLE_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write failed ret %d\n", rc); + return; + } + } + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, ltm_buf[LTM_INIT][idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} + +static void ltm_roiv1_disable(struct sde_hw_dspp *ctx, void *cfg, + u32 num_mixers, enum sde_ltm *dspp_idx) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + int rc, i = 0; + enum sde_ltm idx = 0; + u32 opmode = 0; + + idx = (enum sde_ltm)ctx->idx; + if (idx >= LTM_MAX) { + DRM_ERROR("invalid ltm idx %d\n", ctx->idx); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(ltm_buf[LTM_ROI][idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, ltm_mapping[idx], LTM_ROI, + ltm_buf[LTM_ROI][idx]); + + for (i = 0; i < num_mixers; i++) { + dma_write_cfg.blk = ltm_mapping[dspp_idx[i]]; + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, + 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + ltm_vlut_ops_mask[dspp_idx[i]] &= ~ltm_roi; + + REG_DMA_SETUP_OPS(dma_write_cfg, 0x04, &opmode, sizeof(opmode), + REG_SINGLE_MODIFY, 0, 0, REG_DMA_LTM_ROI_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, ltm_buf[LTM_ROI][idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} + +void reg_dmav1_setup_ltm_roiv1(struct sde_hw_dspp *ctx, void *cfg) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct drm_msm_ltm_cfg_param *cfg_param = NULL; + enum sde_ltm dspp_idx[LTM_MAX] = {0}; + enum sde_ltm idx = 0; + u32 blk = 0, opmode = 0, i = 0, num_mixers = 0; + u32 roi_data[3]; + int rc = 0; + + rc = reg_dma_ltm_check(ctx, cfg, LTM_ROI); + if (rc) + return; + + idx = (enum sde_ltm)ctx->idx; + rc = reg_dmav1_get_ltm_blk(hw_cfg, idx, &dspp_idx[0], &blk); + if (rc) { + if (rc != -EALREADY) + DRM_ERROR("failed to get the blk info\n"); + return; + } + + num_mixers = hw_cfg->num_of_mixers; + /* disable case */ + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable LTM roi feature\n"); + ltm_roiv1_disable(ctx, cfg, num_mixers, dspp_idx); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_ltm_cfg_param)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_ltm_cfg_param)); + return; + } + + cfg_param = hw_cfg->payload; + /* input param exceeds the display width */ + if (cfg_param->cfg_param_01 + cfg_param->cfg_param_03 > + hw_cfg->displayh) { + DRM_DEBUG_DRIVER("invalid input = [%u,%u], displayh = %u\n", + cfg_param->cfg_param_01, cfg_param->cfg_param_03, + hw_cfg->displayh); + /* set the roi width to max register value */ + cfg_param->cfg_param_03 = 0xFFFF; + } + + /* input param exceeds the display height */ + if (cfg_param->cfg_param_02 + cfg_param->cfg_param_04 > + hw_cfg->displayv) { + DRM_DEBUG_DRIVER("invalid input = [%u,%u], displayv = %u\n", + cfg_param->cfg_param_02, cfg_param->cfg_param_04, + hw_cfg->displayv); + /* set the roi height to max register value */ + cfg_param->cfg_param_04 = 0xFFFF; + } + + roi_data[0] = ((cfg_param->cfg_param_02 & 0xFFFF) << 16) | + (cfg_param->cfg_param_01 & 0xFFFF); + roi_data[1] = ((cfg_param->cfg_param_04 & 0xFFFF) << 16) | + (cfg_param->cfg_param_03 & 0xFFFF); + roi_data[2] = ((cfg_param->cfg_param_05 & 0x1FF) << 16) | + (cfg_param->cfg_param_06 & 0x1FF); + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(ltm_buf[LTM_ROI][idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, LTM_ROI, ltm_buf[LTM_ROI][idx]); + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + REG_DMA_SETUP_OPS(dma_write_cfg, 0xb0, roi_data, sizeof(u32) * 3, + REG_BLK_WRITE_SINGLE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write roi data failed ret %d\n", + rc); + return; + } + + for (i = 0; i < num_mixers; i++) { + /* broadcast feature is not supported with REG_SINGLE_MODIFY */ + /* reset decode select to unicast */ + dma_write_cfg.blk = ltm_mapping[dspp_idx[i]]; + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, + 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + if (ltm_vlut_ops_mask[dspp_idx[i]] & ltm_vlut) + opmode |= BIT(24); + ltm_vlut_ops_mask[dspp_idx[i]] |= ltm_roi; + + REG_DMA_SETUP_OPS(dma_write_cfg, 0x04, &opmode, sizeof(opmode), + REG_SINGLE_MODIFY, 0, 0, REG_DMA_LTM_ROI_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, ltm_buf[LTM_ROI][idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} + +static void ltm_vlutv1_disable(struct sde_hw_dspp *ctx, void *cfg, + u32 num_mixers, enum sde_ltm *dspp_idx) +{ + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_hw_reg_dma_ops *dma_ops; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + int rc, i = 0; + enum sde_ltm idx = 0; + u32 opmode = 0; + + idx = (enum sde_ltm)ctx->idx; + if (idx >= LTM_MAX) { + DRM_ERROR("invalid ltm idx %d\n", ctx->idx); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(ltm_buf[LTM_VLUT][idx]); + REG_DMA_INIT_OPS(dma_write_cfg, ltm_mapping[idx], LTM_VLUT, + ltm_buf[LTM_VLUT][idx]); + + for (i = 0; i < num_mixers; i++) { + dma_write_cfg.blk = ltm_mapping[dspp_idx[i]]; + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, + 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + ltm_vlut_ops_mask[dspp_idx[i]] &= ~ltm_vlut; + /* disable VLUT/INIT/ROI */ + REG_DMA_SETUP_OPS(dma_write_cfg, 0x04, &opmode, sizeof(opmode), + REG_SINGLE_MODIFY, 0, 0, + REG_DMA_LTM_VLUT_DISABLE_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("opmode write failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, ltm_buf[LTM_VLUT][idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} + +void reg_dmav1_setup_ltm_vlutv1(struct sde_hw_dspp *ctx, void *cfg) +{ + struct drm_msm_ltm_data *payload = NULL; + struct sde_reg_dma_setup_ops_cfg dma_write_cfg; + struct sde_hw_cp_cfg *hw_cfg = cfg; + struct sde_reg_dma_kickoff_cfg kick_off; + struct sde_hw_reg_dma_ops *dma_ops; + enum sde_ltm dspp_idx[LTM_MAX] = {0}; + enum sde_ltm idx = 0; + u32 offset, crs = 0, index = 0, len = 0, blk = 0, opmode = 0; + u32 i = 0, num_mixers = 0; + int rc = 0; + + rc = reg_dma_ltm_check(ctx, cfg, LTM_VLUT); + if (rc) + return; + + idx = (enum sde_ltm)ctx->idx; + num_mixers = hw_cfg->num_of_mixers; + rc = reg_dmav1_get_ltm_blk(hw_cfg, idx, &dspp_idx[0], &blk); + if (rc) { + if (rc != -EALREADY) + DRM_ERROR("failed to get the blk info\n"); + return; + } + + /* disable case */ + if (!hw_cfg->payload) { + DRM_DEBUG_DRIVER("Disable LTM vlut feature\n"); + ltm_vlutv1_disable(ctx, cfg, num_mixers, dspp_idx); + return; + } + + if (hw_cfg->len != sizeof(struct drm_msm_ltm_data)) { + DRM_ERROR("invalid size of payload len %d exp %zd\n", + hw_cfg->len, sizeof(struct drm_msm_ltm_data)); + return; + } + + offset = ctx->cap->sblk->ltm.base + 0x5c; + crs = SDE_REG_READ(&ctx->hw, offset); + if (!(crs & BIT(3))) { + DRM_ERROR("LTM VLUT buffer is not ready: crs = %d\n", crs); + return; + } + + dma_ops = sde_reg_dma_get_ops(); + dma_ops->reset_reg_dma_buf(ltm_buf[LTM_VLUT][idx]); + + REG_DMA_INIT_OPS(dma_write_cfg, blk, LTM_VLUT, ltm_buf[LTM_VLUT][idx]); + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + /* write VLUT index */ + REG_DMA_SETUP_OPS(dma_write_cfg, 0x38, &index, sizeof(u32), + REG_SINGLE_WRITE, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write VLUT index reg failed ret %d\n", rc); + return; + } + + payload = hw_cfg->payload; + len = sizeof(u32) * LTM_DATA_SIZE_0 * LTM_DATA_SIZE_3; + REG_DMA_SETUP_OPS(dma_write_cfg, 0x3c, &payload->data[0][0], + len, REG_BLK_WRITE_INC, 0, 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write VLUT data failed rc %d\n", rc); + return; + } + + for (i = 0; i < num_mixers; i++) { + /* broadcast feature is not supported with REG_SINGLE_MODIFY */ + /* reset decode select to unicast */ + dma_write_cfg.blk = ltm_mapping[dspp_idx[i]]; + REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, + 0, 0); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write decode select failed ret %d\n", rc); + return; + } + + /* set the UPDATE_REQ bit */ + crs = BIT(0); + REG_DMA_SETUP_OPS(dma_write_cfg, 0x5c, &crs, sizeof(u32), + REG_SINGLE_MODIFY, 0, 0, + REG_DMA_LTM_UPDATE_REQ_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write UPDATE_REQ failed ret %d\n", rc); + return; + } + + opmode = BIT(1); + if (ltm_vlut_ops_mask[dspp_idx[i]] & ltm_unsharp) + opmode |= BIT(4); + if (ltm_vlut_ops_mask[dspp_idx[i]] & ltm_dither) + opmode |= BIT(6); + if (ltm_vlut_ops_mask[dspp_idx[i]] & ltm_roi) + opmode |= BIT(24); + ltm_vlut_ops_mask[dspp_idx[i]] |= ltm_vlut; + + REG_DMA_SETUP_OPS(dma_write_cfg, 0x4, &opmode, sizeof(u32), + REG_SINGLE_MODIFY, 0, 0, + REG_DMA_LTM_VLUT_ENABLE_OP_MASK); + rc = dma_ops->setup_payload(&dma_write_cfg); + if (rc) { + DRM_ERROR("write UPDATE_REQ failed ret %d\n", rc); + return; + } + } + + REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl, ltm_buf[LTM_VLUT][idx], + REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE); + rc = dma_ops->kick_off(&kick_off); + if (rc) { + DRM_ERROR("failed to kick off ret %d\n", rc); + return; + } +} diff --git a/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.h b/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..cad0787ec473dac7122fc249df53e8bd106614c4 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_reg_dma_v1_color_proc.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _SDE_HW_REG_DMA_V1_COLOR_PROC_H +#define _SDE_HW_REG_DMA_V1_COLOR_PROC_H + +#include "sde_hw_util.h" +#include "sde_hw_catalog.h" +#include "sde_hw_dspp.h" +#include "sde_hw_sspp.h" + +/** + * reg_dmav1_init_dspp_op_v4() - initialize the dspp feature op for sde v4 + * using reg dma v1. + * @feature: dspp feature + * idx: dspp idx + */ +int reg_dmav1_init_dspp_op_v4(int feature, enum sde_dspp idx); + +/** + * reg_dmav1_setup_dspp_vlutv18() - vlut v18 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_vlutv18(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_3d_gamutv4() - gamut v4 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_3d_gamutv4(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_3d_gamutv41() - gamut v4_1 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_3d_gamutv41(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_3d_gamutv42() - gamut v4_2 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_3d_gamutv42(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_gcv18() - gc v18 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_gcv18(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_igcv31() - igc v31 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_igcv31(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_pccv4() - pcc v4 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_pa_hsicv17() - pa hsic v17 impl using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_pa_hsicv17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_sixzonev17() - sixzone v17 impl using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_sixzonev17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_memcol_skinv17() - memcol skin v17 impl using + * reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_memcol_skinv17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_memcol_skyv17() - memcol sky v17 impl using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_memcol_skyv17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_memcol_folv17() - memcol foliage v17 impl using + * reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_memcol_folv17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_dspp_memcol_protv17() - memcol prot v17 impl using + * reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_dspp_memcol_protv17(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_deinit_dspp_ops() - deinitialize the dspp feature op for sde v4 + * which were initialized. + * @idx: dspp idx + */ +int reg_dmav1_deinit_dspp_ops(enum sde_dspp idx); + +/** + * reg_dmav1_init_sspp_op_v4() - initialize the sspp feature op for sde v4 + * @feature: sspp feature + * @idx: sspp idx + */ +int reg_dmav1_init_sspp_op_v4(int feature, enum sde_sspp idx); + +/** + * reg_dmav1_setup_vig_gamutv5() - VIG 3D lut gamut v5 implementation + * using reg dma v1. + * @ctx: sspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_vig_gamutv5(struct sde_hw_pipe *ctx, void *cfg); + +/** + * reg_dmav1_setup_vig_gamutv6() - VIG 3D lut gamut v6 implementation + * using reg dma v1. + * @ctx: sspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_vig_gamutv6(struct sde_hw_pipe *ctx, void *cfg); + +/** + * reg_dmav1_setup_vig_igcv5() - VIG 1D lut IGC v5 implementation + * using reg dma v1. + * @ctx: sspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_vig_igcv5(struct sde_hw_pipe *ctx, void *cfg); + +/** + * reg_dmav1_setup_dma_igcv5() - DMA 1D lut IGC v5 implementation + * using reg dma v1. + * @ctx: sspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + * @idx: multirect index + */ +void reg_dmav1_setup_dma_igcv5(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx); +/** + * reg_dmav1_setup_vig_igcv6() - VIG ID lut IGC v6 implementation + * using reg dma v1. + * @ctx: sspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_vig_igcv6(struct sde_hw_pipe *ctx, void *cfg); + +/** + * reg_dmav1_setup_dma_gcv5() - DMA 1D lut GC v5 implementation + * using reg dma v1. + * @ctx: sspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + * @idx: multirect index + */ +void reg_dmav1_setup_dma_gcv5(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx); + +/** + * reg_dmav1_setup_vig_qseed3 - Qseed3 implementation using reg dma v1. + * @ctx: sspp ctx info + * @sspp: pointer to sspp hw config + * @pe: pointer to pixel extension config + * @scaler_cfg: pointer to scaler config + */ + +void reg_dmav1_setup_vig_qseed3(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *sspp, struct sde_hw_pixel_ext *pe, + void *scaler_cfg); + +/**reg_dmav1_setup_scaler3_lut - Qseed3 lut coefficient programming + * @buf: defines structure for reg dma ops on the reg dma buffer. + * @scaler3_cfg: QSEEDv3 configuration + * @offset: Scaler Offest + */ + +void reg_dmav1_setup_scaler3_lut(struct sde_reg_dma_setup_ops_cfg *buf, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset); + +/**reg_dmav1_setup_scaler3lite_lut - Qseed3lite lut coefficient programming + * @buf: defines structure for reg dma ops on the reg dma buffer. + * @scaler3_cfg: QSEEDv3 configuration + * @offset: Scaler Offest + */ + +void reg_dmav1_setup_scaler3lite_lut(struct sde_reg_dma_setup_ops_cfg *buf, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset); + +/** + * reg_dmav1_deinit_sspp_ops() - deinitialize the sspp feature op for sde v4 + * which were initialized. + * @idx: sspp idx + */ +int reg_dmav1_deinit_sspp_ops(enum sde_sspp idx); + +/** + * reg_dmav1_init_ltm_op_v6() - initialize the ltm feature op for sde v6 + * @feature: ltm feature + * @idx: dspp idx + */ +int reg_dmav1_init_ltm_op_v6(int feature, enum sde_dspp idx); + +/** + * reg_dmav1_setup_ltm_initv1() - LTM INIT v1 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_ltm_initv1(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_ltm_roiv1() - LTM ROI v1 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_ltm_roiv1(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_setup_ltm_vlutv1() - LTM VLUT v1 implementation using reg dma v1. + * @ctx: dspp ctx info + * @cfg: pointer to struct sde_hw_cp_cfg + */ +void reg_dmav1_setup_ltm_vlutv1(struct sde_hw_dspp *ctx, void *cfg); + +/** + * reg_dmav1_deinit_ltm_ops() - deinitialize the ltm feature op for sde v4 + * which were initialized. + * @idx: ltm idx + */ +int reg_dmav1_deinit_ltm_ops(enum sde_dspp idx); + + +#endif /* _SDE_HW_REG_DMA_V1_COLOR_PROC_H */ diff --git a/techpack/display/msm/sde/sde_hw_sspp.c b/techpack/display/msm/sde/sde_hw_sspp.c new file mode 100644 index 0000000000000000000000000000000000000000..a08746bc4af1872ea444fc0298854682fad48bd8 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_sspp.c @@ -0,0 +1,1385 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_util.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_lm.h" +#include "sde_hw_sspp.h" +#include "sde_hw_color_processing.h" +#include "sde_dbg.h" +#include "sde_kms.h" +#include "sde_hw_reg_dma_v1_color_proc.h" + +#define SDE_FETCH_CONFIG_RESET_VALUE 0x00000087 + +/* SDE_SSPP_SRC */ +#define SSPP_SRC_SIZE 0x00 +#define SSPP_SRC_XY 0x08 +#define SSPP_OUT_SIZE 0x0c +#define SSPP_OUT_XY 0x10 +#define SSPP_SRC0_ADDR 0x14 +#define SSPP_SRC1_ADDR 0x18 +#define SSPP_SRC2_ADDR 0x1C +#define SSPP_SRC3_ADDR 0x20 +#define SSPP_SRC_YSTRIDE0 0x24 +#define SSPP_SRC_YSTRIDE1 0x28 +#define SSPP_SRC_FORMAT 0x30 +#define SSPP_SRC_UNPACK_PATTERN 0x34 +#define SSPP_SRC_OP_MODE 0x38 + +/* SSPP_MULTIRECT*/ +#define SSPP_SRC_SIZE_REC1 0x16C +#define SSPP_SRC_XY_REC1 0x168 +#define SSPP_OUT_SIZE_REC1 0x160 +#define SSPP_OUT_XY_REC1 0x164 +#define SSPP_SRC_FORMAT_REC1 0x174 +#define SSPP_SRC_UNPACK_PATTERN_REC1 0x178 +#define SSPP_SRC_OP_MODE_REC1 0x17C +#define SSPP_MULTIRECT_OPMODE 0x170 +#define SSPP_SRC_CONSTANT_COLOR_REC1 0x180 +#define SSPP_EXCL_REC_SIZE_REC1 0x184 +#define SSPP_EXCL_REC_XY_REC1 0x188 + +#define SSPP_UIDLE_CTRL_VALUE 0x1f0 +#define SSPP_UIDLE_CTRL_VALUE_REC1 0x1f4 + +/* SSPP_DGM */ +#define SSPP_DGM_OP_MODE 0x804 +#define SSPP_DGM_OP_MODE_REC1 0x1804 +#define SSPP_GAMUT_UNMULT_MODE 0x1EA0 + +#define MDSS_MDP_OP_DEINTERLACE BIT(22) +#define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23) +#define MDSS_MDP_OP_IGC_ROM_1 BIT(18) +#define MDSS_MDP_OP_IGC_ROM_0 BIT(17) +#define MDSS_MDP_OP_IGC_EN BIT(16) +#define MDSS_MDP_OP_FLIP_UD BIT(14) +#define MDSS_MDP_OP_FLIP_LR BIT(13) +#define MDSS_MDP_OP_SPLIT_ORDER BIT(4) +#define MDSS_MDP_OP_BWC_EN BIT(0) +#define MDSS_MDP_OP_PE_OVERRIDE BIT(31) +#define MDSS_MDP_OP_BWC_LOSSLESS (0 << 1) +#define MDSS_MDP_OP_BWC_Q_HIGH (1 << 1) +#define MDSS_MDP_OP_BWC_Q_MED (2 << 1) + +#define SSPP_SRC_CONSTANT_COLOR 0x3c +#define SSPP_EXCL_REC_CTL 0x40 +#define SSPP_UBWC_STATIC_CTRL 0x44 +#define SSPP_FETCH_CONFIG 0x048 +#define SSPP_PRE_DOWN_SCALE 0x50 +#define SSPP_DANGER_LUT 0x60 +#define SSPP_SAFE_LUT 0x64 +#define SSPP_CREQ_LUT 0x68 +#define SSPP_QOS_CTRL 0x6C +#define SSPP_DECIMATION_CONFIG 0xB4 +#define SSPP_SRC_ADDR_SW_STATUS 0x70 +#define SSPP_CREQ_LUT_0 0x74 +#define SSPP_CREQ_LUT_1 0x78 +#define SSPP_SW_PIX_EXT_C0_LR 0x100 +#define SSPP_SW_PIX_EXT_C0_TB 0x104 +#define SSPP_SW_PIX_EXT_C0_REQ_PIXELS 0x108 +#define SSPP_SW_PIX_EXT_C1C2_LR 0x110 +#define SSPP_SW_PIX_EXT_C1C2_TB 0x114 +#define SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS 0x118 +#define SSPP_SW_PIX_EXT_C3_LR 0x120 +#define SSPP_SW_PIX_EXT_C3_TB 0x124 +#define SSPP_SW_PIX_EXT_C3_REQ_PIXELS 0x128 +#define SSPP_TRAFFIC_SHAPER 0x130 +#define SSPP_CDP_CNTL 0x134 +#define SSPP_UBWC_ERROR_STATUS 0x138 +#define SSPP_CDP_CNTL_REC1 0x13c +#define SSPP_TRAFFIC_SHAPER_PREFILL 0x150 +#define SSPP_TRAFFIC_SHAPER_REC1_PREFILL 0x154 +#define SSPP_TRAFFIC_SHAPER_REC1 0x158 +#define SSPP_EXCL_REC_SIZE 0x1B4 +#define SSPP_EXCL_REC_XY 0x1B8 +#define SSPP_VIG_OP_MODE 0x0 +#define SSPP_VIG_CSC_10_OP_MODE 0x0 +#define SSPP_TRAFFIC_SHAPER_BPC_MAX 0xFF + +/* SSPP_QOS_CTRL */ +#define SSPP_QOS_CTRL_VBLANK_EN BIT(16) +#define SSPP_QOS_CTRL_DANGER_SAFE_EN BIT(0) +#define SSPP_QOS_CTRL_DANGER_VBLANK_MASK 0x3 +#define SSPP_QOS_CTRL_DANGER_VBLANK_OFF 4 +#define SSPP_QOS_CTRL_CREQ_VBLANK_MASK 0x3 +#define SSPP_QOS_CTRL_CREQ_VBLANK_OFF 20 + +#define SSPP_SYS_CACHE_MODE 0x1BC +#define SSPP_SBUF_STATUS_PLANE0 0x1C0 +#define SSPP_SBUF_STATUS_PLANE1 0x1C4 +#define SSPP_SBUF_STATUS_PLANE_EMPTY BIT(16) + +/* SDE_SSPP_SCALER_QSEED2 */ +#define SCALE_CONFIG 0x04 +#define COMP0_3_PHASE_STEP_X 0x10 +#define COMP0_3_PHASE_STEP_Y 0x14 +#define COMP1_2_PHASE_STEP_X 0x18 +#define COMP1_2_PHASE_STEP_Y 0x1c +#define COMP0_3_INIT_PHASE_X 0x20 +#define COMP0_3_INIT_PHASE_Y 0x24 +#define COMP1_2_INIT_PHASE_X 0x28 +#define COMP1_2_INIT_PHASE_Y 0x2C +#define VIG_0_QSEED2_SHARP 0x30 + +/* + * Definitions for ViG op modes + */ +#define VIG_OP_CSC_DST_DATAFMT BIT(19) +#define VIG_OP_CSC_SRC_DATAFMT BIT(18) +#define VIG_OP_CSC_EN BIT(17) +#define VIG_OP_MEM_PROT_CONT BIT(15) +#define VIG_OP_MEM_PROT_VAL BIT(14) +#define VIG_OP_MEM_PROT_SAT BIT(13) +#define VIG_OP_MEM_PROT_HUE BIT(12) +#define VIG_OP_HIST BIT(8) +#define VIG_OP_SKY_COL BIT(7) +#define VIG_OP_FOIL BIT(6) +#define VIG_OP_SKIN_COL BIT(5) +#define VIG_OP_PA_EN BIT(4) +#define VIG_OP_PA_SAT_ZERO_EXP BIT(2) +#define VIG_OP_MEM_PROT_BLEND BIT(1) + +/* + * Definitions for CSC 10 op modes + */ +#define VIG_CSC_10_SRC_DATAFMT BIT(1) +#define VIG_CSC_10_EN BIT(0) +#define CSC_10BIT_OFFSET 4 +#define DGM_CSC_MATRIX_SHIFT 0 + +/* traffic shaper clock in Hz */ +#define TS_CLK 19200000 + +static inline int _sspp_subblk_offset(struct sde_hw_pipe *ctx, + int s_id, + u32 *idx) +{ + int rc = 0; + const struct sde_sspp_sub_blks *sblk; + + if (!ctx) + return -EINVAL; + + sblk = ctx->cap->sblk; + switch (s_id) { + case SDE_SSPP_SRC: + *idx = sblk->src_blk.base; + break; + case SDE_SSPP_SCALER_QSEED2: + case SDE_SSPP_SCALER_QSEED3: + case SDE_SSPP_SCALER_RGB: + *idx = sblk->scaler_blk.base; + break; + case SDE_SSPP_CSC: + case SDE_SSPP_CSC_10BIT: + *idx = sblk->csc_blk.base; + break; + case SDE_SSPP_HSIC: + *idx = sblk->hsic_blk.base; + break; + case SDE_SSPP_PCC: + *idx = sblk->pcc_blk.base; + break; + case SDE_SSPP_MEMCOLOR: + *idx = sblk->memcolor_blk.base; + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static void sde_hw_sspp_setup_multirect(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, + enum sde_sspp_multirect_mode mode) +{ + u32 mode_mask; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (index == SDE_SSPP_RECT_SOLO) { + /** + * if rect index is RECT_SOLO, we cannot expect a + * virtual plane sharing the same SSPP id. So we go + * and disable multirect + */ + mode_mask = 0; + } else { + mode_mask = SDE_REG_READ(&ctx->hw, SSPP_MULTIRECT_OPMODE + idx); + mode_mask |= index; + if (mode == SDE_SSPP_MULTIRECT_TIME_MX) + mode_mask |= BIT(2); + else + mode_mask &= ~BIT(2); + } + + SDE_REG_WRITE(&ctx->hw, SSPP_MULTIRECT_OPMODE + idx, mode_mask); +} + +static void _sspp_setup_opmode(struct sde_hw_pipe *ctx, + u32 mask, u8 en) +{ + u32 idx; + u32 opmode; + + if (!test_bit(SDE_SSPP_SCALER_QSEED2, &ctx->cap->features) || + _sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED2, &idx) || + !test_bit(SDE_SSPP_CSC, &ctx->cap->features)) + return; + + opmode = SDE_REG_READ(&ctx->hw, SSPP_VIG_OP_MODE + idx); + + if (en) + opmode |= mask; + else + opmode &= ~mask; + + SDE_REG_WRITE(&ctx->hw, SSPP_VIG_OP_MODE + idx, opmode); +} + +static void _sspp_setup_csc10_opmode(struct sde_hw_pipe *ctx, + u32 mask, u8 en) +{ + u32 idx; + u32 opmode; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_CSC_10BIT, &idx)) + return; + + opmode = SDE_REG_READ(&ctx->hw, SSPP_VIG_CSC_10_OP_MODE + idx); + if (en) + opmode |= mask; + else + opmode &= ~mask; + + SDE_REG_WRITE(&ctx->hw, SSPP_VIG_CSC_10_OP_MODE + idx, opmode); +} + +static void sde_hw_sspp_set_src_split_order(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index rect_mode, bool enable) +{ + struct sde_hw_blk_reg_map *c; + u32 opmode, idx, op_mode_off; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (rect_mode == SDE_SSPP_RECT_SOLO || rect_mode == SDE_SSPP_RECT_0) + op_mode_off = SSPP_SRC_OP_MODE; + else + op_mode_off = SSPP_SRC_OP_MODE_REC1; + + c = &ctx->hw; + opmode = SDE_REG_READ(c, op_mode_off + idx); + + if (enable) + opmode |= MDSS_MDP_OP_SPLIT_ORDER; + else + opmode &= ~MDSS_MDP_OP_SPLIT_ORDER; + + SDE_REG_WRITE(c, op_mode_off + idx, opmode); +} + +/** + * Setup source pixel format, flip, + */ +static void sde_hw_sspp_setup_format(struct sde_hw_pipe *ctx, + const struct sde_format *fmt, + bool const_alpha_en, u32 flags, + enum sde_sspp_multirect_index rect_mode) +{ + struct sde_hw_blk_reg_map *c; + u32 chroma_samp, unpack, src_format; + u32 opmode = 0; + u32 alpha_en_mask = 0, color_en_mask = 0; + u32 op_mode_off, unpack_pat_off, format_off; + u32 idx, core_rev; + bool const_color_en = true; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !fmt) + return; + + if (rect_mode == SDE_SSPP_RECT_SOLO || rect_mode == SDE_SSPP_RECT_0) { + op_mode_off = SSPP_SRC_OP_MODE; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN; + format_off = SSPP_SRC_FORMAT; + } else { + op_mode_off = SSPP_SRC_OP_MODE_REC1; + unpack_pat_off = SSPP_SRC_UNPACK_PATTERN_REC1; + format_off = SSPP_SRC_FORMAT_REC1; + } + + c = &ctx->hw; + core_rev = readl_relaxed(c->base_off + 0x0); + opmode = SDE_REG_READ(c, op_mode_off + idx); + opmode &= ~(MDSS_MDP_OP_FLIP_LR | MDSS_MDP_OP_FLIP_UD | + MDSS_MDP_OP_BWC_EN | MDSS_MDP_OP_PE_OVERRIDE); + + if (flags & SDE_SSPP_FLIP_LR) + opmode |= MDSS_MDP_OP_FLIP_LR; + if (flags & SDE_SSPP_FLIP_UD) + opmode |= MDSS_MDP_OP_FLIP_UD; + + chroma_samp = fmt->chroma_sample; + if (flags & SDE_SSPP_SOURCE_ROTATED_90) { + if (chroma_samp == SDE_CHROMA_H2V1) + chroma_samp = SDE_CHROMA_H1V2; + else if (chroma_samp == SDE_CHROMA_H1V2) + chroma_samp = SDE_CHROMA_H2V1; + } + + src_format = (chroma_samp << 23) | (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | (fmt->bits[C0_G_Y] << 0); + + if (flags & SDE_SSPP_ROT_90) + src_format |= BIT(11); /* ROT90 */ + + if (fmt->alpha_enable && fmt->fetch_planes == SDE_PLANE_INTERLEAVED) + src_format |= BIT(8); /* SRCC3_EN */ + + if (flags & SDE_SSPP_SOLID_FILL) + src_format |= BIT(22); + + unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) | + (fmt->element[1] << 8) | (fmt->element[0] << 0); + src_format |= ((fmt->unpack_count - 1) << 12) | + (fmt->unpack_tight << 17) | + (fmt->unpack_align_msb << 18) | + ((fmt->bpp - 1) << 9); + + if(IS_SDE_MAJOR_SAME(core_rev, SDE_HW_VER_600)) { + if(flags & SDE_SSPP_ROT_90) + const_color_en = false; + } + + if (fmt->fetch_mode != SDE_FETCH_LINEAR) { + if (SDE_FORMAT_IS_UBWC(fmt)) + opmode |= MDSS_MDP_OP_BWC_EN; + src_format |= (fmt->fetch_mode & 3) << 30; /*FRAME_FORMAT */ + SDE_REG_WRITE(c, SSPP_FETCH_CONFIG, + SDE_FETCH_CONFIG_RESET_VALUE | + ctx->mdp->highest_bank_bit << 18); + if (IS_UBWC_40_SUPPORTED(ctx->catalog->ubwc_version)) { + SDE_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + SDE_FORMAT_IS_YUV(fmt) ? 0 : BIT(30)); + } else if (IS_UBWC_10_SUPPORTED(ctx->catalog->ubwc_version)) { + alpha_en_mask = const_alpha_en ? BIT(31) : 0; + SDE_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + alpha_en_mask | (ctx->mdp->ubwc_swizzle & 0x1) | + BIT(8) | (ctx->mdp->highest_bank_bit << 4)); + } else if (IS_UBWC_20_SUPPORTED(ctx->catalog->ubwc_version)) { + alpha_en_mask = const_alpha_en ? BIT(31) : 0; + SDE_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + alpha_en_mask | (ctx->mdp->ubwc_swizzle) | + (ctx->mdp->highest_bank_bit << 4)); + } else if (IS_UBWC_30_SUPPORTED(ctx->catalog->ubwc_version)) { + color_en_mask = const_color_en ? BIT(30) : 0; + SDE_REG_WRITE(c, SSPP_UBWC_STATIC_CTRL, + color_en_mask | (ctx->mdp->ubwc_swizzle) | + (ctx->mdp->highest_bank_bit << 4)); + } + } + + opmode |= MDSS_MDP_OP_PE_OVERRIDE; + + /* if this is YUV pixel format, enable CSC */ + if (SDE_FORMAT_IS_YUV(fmt)) + src_format |= BIT(15); + + if (SDE_FORMAT_IS_DX(fmt)) + src_format |= BIT(14); + + /* update scaler opmode, if appropriate */ + if (test_bit(SDE_SSPP_CSC, &ctx->cap->features)) + _sspp_setup_opmode(ctx, VIG_OP_CSC_EN | VIG_OP_CSC_SRC_DATAFMT, + SDE_FORMAT_IS_YUV(fmt)); + else if (test_bit(SDE_SSPP_CSC_10BIT, &ctx->cap->features)) + _sspp_setup_csc10_opmode(ctx, + VIG_CSC_10_EN | VIG_CSC_10_SRC_DATAFMT, + SDE_FORMAT_IS_YUV(fmt)); + + SDE_REG_WRITE(c, format_off + idx, src_format); + SDE_REG_WRITE(c, unpack_pat_off + idx, unpack); + SDE_REG_WRITE(c, op_mode_off + idx, opmode); + + /* clear previous UBWC error */ + SDE_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS + idx, BIT(31)); +} + +static void sde_hw_sspp_clear_ubwc_error(struct sde_hw_pipe *ctx) +{ + struct sde_hw_blk_reg_map *c; + + c = &ctx->hw; + SDE_REG_WRITE(c, SSPP_UBWC_ERROR_STATUS, BIT(31)); +} + +static u32 sde_hw_sspp_get_ubwc_error(struct sde_hw_pipe *ctx) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_code; + + c = &ctx->hw; + reg_code = SDE_REG_READ(c, SSPP_UBWC_ERROR_STATUS); + + return reg_code; +} + +static void sde_hw_sspp_setup_secure(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index rect_mode, + bool enable) +{ + struct sde_hw_blk_reg_map *c; + u32 secure = 0, secure_bit_mask; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + c = &ctx->hw; + + if ((rect_mode == SDE_SSPP_RECT_SOLO) + || (rect_mode == SDE_SSPP_RECT_0)) + secure_bit_mask = + (rect_mode == SDE_SSPP_RECT_SOLO) ? 0xF : 0x5; + else + secure_bit_mask = 0xA; + + secure = SDE_REG_READ(c, SSPP_SRC_ADDR_SW_STATUS + idx); + + if (enable) + secure |= secure_bit_mask; + else + secure &= ~secure_bit_mask; + + SDE_REG_WRITE(c, SSPP_SRC_ADDR_SW_STATUS + idx, secure); + + /* multiple planes share same sw_status register */ + wmb(); +} + + +static void sde_hw_sspp_setup_pe_config(struct sde_hw_pipe *ctx, + struct sde_hw_pixel_ext *pe_ext) +{ + struct sde_hw_blk_reg_map *c; + u8 color; + u32 lr_pe[4], tb_pe[4], tot_req_pixels[4]; + const u32 bytemask = 0xff; + const u32 shortmask = 0xffff; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !pe_ext) + return; + + c = &ctx->hw; + + /* program SW pixel extension override for all pipes*/ + for (color = 0; color < SDE_MAX_PLANES; color++) { + /* color 2 has the same set of registers as color 1 */ + if (color == 2) + continue; + + lr_pe[color] = ((pe_ext->right_ftch[color] & bytemask) << 24)| + ((pe_ext->right_rpt[color] & bytemask) << 16)| + ((pe_ext->left_ftch[color] & bytemask) << 8)| + (pe_ext->left_rpt[color] & bytemask); + + tb_pe[color] = ((pe_ext->btm_ftch[color] & bytemask) << 24)| + ((pe_ext->btm_rpt[color] & bytemask) << 16)| + ((pe_ext->top_ftch[color] & bytemask) << 8)| + (pe_ext->top_rpt[color] & bytemask); + + tot_req_pixels[color] = (((pe_ext->roi_h[color] + + pe_ext->num_ext_pxls_top[color] + + pe_ext->num_ext_pxls_btm[color]) & shortmask) << 16) | + ((pe_ext->roi_w[color] + + pe_ext->num_ext_pxls_left[color] + + pe_ext->num_ext_pxls_right[color]) & shortmask); + } + + /* color 0 */ + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_LR + idx, lr_pe[0]); + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_TB + idx, tb_pe[0]); + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C0_REQ_PIXELS + idx, + tot_req_pixels[0]); + + /* color 1 and color 2 */ + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_LR + idx, lr_pe[1]); + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_TB + idx, tb_pe[1]); + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS + idx, + tot_req_pixels[1]); + + /* color 3 */ + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_LR + idx, lr_pe[3]); + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_TB + idx, lr_pe[3]); + SDE_REG_WRITE(c, SSPP_SW_PIX_EXT_C3_REQ_PIXELS + idx, + tot_req_pixels[3]); +} + +static void _sde_hw_sspp_setup_scaler(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *sspp, + struct sde_hw_pixel_ext *pe, + void *scaler_cfg) +{ + struct sde_hw_blk_reg_map *c; + int config_h = 0x0; + int config_v = 0x0; + u32 idx; + + (void)sspp; + (void)scaler_cfg; + if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED2, &idx) || !pe) + return; + + c = &ctx->hw; + + /* enable scaler(s) if valid filter set */ + if (pe->horz_filter[SDE_SSPP_COMP_0] < SDE_SCALE_FILTER_MAX) + config_h |= pe->horz_filter[SDE_SSPP_COMP_0] << 8; + if (pe->horz_filter[SDE_SSPP_COMP_1_2] < SDE_SCALE_FILTER_MAX) + config_h |= pe->horz_filter[SDE_SSPP_COMP_1_2] << 12; + if (pe->horz_filter[SDE_SSPP_COMP_3] < SDE_SCALE_FILTER_MAX) + config_h |= pe->horz_filter[SDE_SSPP_COMP_3] << 16; + + if (config_h) + config_h |= BIT(0); + + if (pe->vert_filter[SDE_SSPP_COMP_0] < SDE_SCALE_FILTER_MAX) + config_v |= pe->vert_filter[SDE_SSPP_COMP_0] << 10; + if (pe->vert_filter[SDE_SSPP_COMP_1_2] < SDE_SCALE_FILTER_MAX) + config_v |= pe->vert_filter[SDE_SSPP_COMP_1_2] << 14; + if (pe->vert_filter[SDE_SSPP_COMP_3] < SDE_SCALE_FILTER_MAX) + config_v |= pe->vert_filter[SDE_SSPP_COMP_3] << 18; + + if (config_v) + config_v |= BIT(1); + + SDE_REG_WRITE(c, SCALE_CONFIG + idx, config_h | config_v); + SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_X + idx, + pe->init_phase_x[SDE_SSPP_COMP_0]); + SDE_REG_WRITE(c, COMP0_3_INIT_PHASE_Y + idx, + pe->init_phase_y[SDE_SSPP_COMP_0]); + SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_X + idx, + pe->phase_step_x[SDE_SSPP_COMP_0]); + SDE_REG_WRITE(c, COMP0_3_PHASE_STEP_Y + idx, + pe->phase_step_y[SDE_SSPP_COMP_0]); + + SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_X + idx, + pe->init_phase_x[SDE_SSPP_COMP_1_2]); + SDE_REG_WRITE(c, COMP1_2_INIT_PHASE_Y + idx, + pe->init_phase_y[SDE_SSPP_COMP_1_2]); + SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_X + idx, + pe->phase_step_x[SDE_SSPP_COMP_1_2]); + SDE_REG_WRITE(c, COMP1_2_PHASE_STEP_Y + idx, + pe->phase_step_y[SDE_SSPP_COMP_1_2]); +} + +static void _sde_hw_sspp_setup_scaler3(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *sspp, + struct sde_hw_pixel_ext *pe, + void *scaler_cfg) +{ + u32 idx; + struct sde_hw_scaler3_cfg *scaler3_cfg = scaler_cfg; + + (void)pe; + if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx) || !sspp + || !scaler3_cfg || !ctx || !ctx->cap || !ctx->cap->sblk) + return; + + sde_hw_setup_scaler3(&ctx->hw, scaler3_cfg, + ctx->cap->sblk->scaler_blk.version, idx, sspp->layout.format); +} + +static void sde_hw_sspp_setup_pre_downscale(struct sde_hw_pipe *ctx, + struct sde_hw_inline_pre_downscale_cfg *pre_down) +{ + u32 idx, val; + + if (!ctx || !pre_down || _sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + val = pre_down->pre_downscale_x_0 | + (pre_down->pre_downscale_x_1 << 4) | + (pre_down->pre_downscale_y_0 << 8) | + (pre_down->pre_downscale_y_1 << 12); + + SDE_REG_WRITE(&ctx->hw, SSPP_PRE_DOWN_SCALE + idx, val); +} + +static u32 _sde_hw_sspp_get_scaler3_ver(struct sde_hw_pipe *ctx) +{ + u32 idx; + + if (!ctx || _sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED3, &idx)) + return 0; + + return sde_hw_get_scaler3_ver(&ctx->hw, idx); +} + +/** + * sde_hw_sspp_setup_rects() + */ +static void sde_hw_sspp_setup_rects(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *cfg, + enum sde_sspp_multirect_index rect_index) +{ + struct sde_hw_blk_reg_map *c; + u32 src_size, src_xy, dst_size, dst_xy, ystride0, ystride1; + u32 src_size_off, src_xy_off, out_size_off, out_xy_off; + u32 decimation = 0; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !cfg) + return; + + c = &ctx->hw; + + if (rect_index == SDE_SSPP_RECT_SOLO || rect_index == SDE_SSPP_RECT_0) { + src_size_off = SSPP_SRC_SIZE; + src_xy_off = SSPP_SRC_XY; + out_size_off = SSPP_OUT_SIZE; + out_xy_off = SSPP_OUT_XY; + } else { + src_size_off = SSPP_SRC_SIZE_REC1; + src_xy_off = SSPP_SRC_XY_REC1; + out_size_off = SSPP_OUT_SIZE_REC1; + out_xy_off = SSPP_OUT_XY_REC1; + } + + + /* src and dest rect programming */ + src_xy = (cfg->src_rect.y << 16) | (cfg->src_rect.x); + src_size = (cfg->src_rect.h << 16) | (cfg->src_rect.w); + dst_xy = (cfg->dst_rect.y << 16) | (cfg->dst_rect.x); + dst_size = (cfg->dst_rect.h << 16) | (cfg->dst_rect.w); + + if (rect_index == SDE_SSPP_RECT_SOLO) { + ystride0 = (cfg->layout.plane_pitch[0]) | + (cfg->layout.plane_pitch[1] << 16); + ystride1 = (cfg->layout.plane_pitch[2]) | + (cfg->layout.plane_pitch[3] << 16); + } else { + ystride0 = SDE_REG_READ(c, SSPP_SRC_YSTRIDE0 + idx); + ystride1 = SDE_REG_READ(c, SSPP_SRC_YSTRIDE1 + idx); + + if (rect_index == SDE_SSPP_RECT_0) { + ystride0 = (ystride0 & 0xFFFF0000) | + (cfg->layout.plane_pitch[0] & 0x0000FFFF); + ystride1 = (ystride1 & 0xFFFF0000)| + (cfg->layout.plane_pitch[2] & 0x0000FFFF); + } else { + ystride0 = (ystride0 & 0x0000FFFF) | + ((cfg->layout.plane_pitch[0] << 16) & + 0xFFFF0000); + ystride1 = (ystride1 & 0x0000FFFF) | + ((cfg->layout.plane_pitch[2] << 16) & + 0xFFFF0000); + } + } + + /* program scaler, phase registers, if pipes supporting scaling */ + if (ctx->cap->features & SDE_SSPP_SCALER) { + /* program decimation */ + decimation = ((1 << cfg->horz_decimation) - 1) << 8; + decimation |= ((1 << cfg->vert_decimation) - 1); + } + + /* rectangle register programming */ + SDE_REG_WRITE(c, src_size_off + idx, src_size); + SDE_REG_WRITE(c, src_xy_off + idx, src_xy); + SDE_REG_WRITE(c, out_size_off + idx, dst_size); + SDE_REG_WRITE(c, out_xy_off + idx, dst_xy); + + SDE_REG_WRITE(c, SSPP_SRC_YSTRIDE0 + idx, ystride0); + SDE_REG_WRITE(c, SSPP_SRC_YSTRIDE1 + idx, ystride1); + SDE_REG_WRITE(c, SSPP_DECIMATION_CONFIG + idx, decimation); +} + +/** + * _sde_hw_sspp_setup_excl_rect() - set exclusion rect configs + * @ctx: Pointer to pipe context + * @excl_rect: Exclusion rect configs + */ +static void _sde_hw_sspp_setup_excl_rect(struct sde_hw_pipe *ctx, + struct sde_rect *excl_rect, + enum sde_sspp_multirect_index rect_index) +{ + struct sde_hw_blk_reg_map *c; + u32 size, xy; + u32 idx; + u32 reg_xy, reg_size; + u32 excl_ctrl = BIT(0); + u32 enable_bit; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx) || !excl_rect) + return; + + if (rect_index == SDE_SSPP_RECT_0 || rect_index == SDE_SSPP_RECT_SOLO) { + reg_xy = SSPP_EXCL_REC_XY; + reg_size = SSPP_EXCL_REC_SIZE; + enable_bit = BIT(0); + } else { + reg_xy = SSPP_EXCL_REC_XY_REC1; + reg_size = SSPP_EXCL_REC_SIZE_REC1; + enable_bit = BIT(1); + } + + c = &ctx->hw; + + xy = (excl_rect->y << 16) | (excl_rect->x); + size = (excl_rect->h << 16) | (excl_rect->w); + + /* Set if multi-rect disabled, read+modify only if multi-rect enabled */ + if (rect_index != SDE_SSPP_RECT_SOLO) + excl_ctrl = SDE_REG_READ(c, SSPP_EXCL_REC_CTL + idx); + + if (!size) { + SDE_REG_WRITE(c, SSPP_EXCL_REC_CTL + idx, + excl_ctrl & ~enable_bit); + } else { + SDE_REG_WRITE(c, SSPP_EXCL_REC_CTL + idx, + excl_ctrl | enable_bit); + SDE_REG_WRITE(c, reg_size + idx, size); + SDE_REG_WRITE(c, reg_xy + idx, xy); + } +} + +static void sde_hw_sspp_setup_sourceaddress(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *cfg, + enum sde_sspp_multirect_index rect_mode) +{ + int i; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (rect_mode == SDE_SSPP_RECT_SOLO) { + for (i = 0; i < ARRAY_SIZE(cfg->layout.plane_addr); i++) + SDE_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx + i * 0x4, + cfg->layout.plane_addr[i]); + } else if (rect_mode == SDE_SSPP_RECT_0) { + SDE_REG_WRITE(&ctx->hw, SSPP_SRC0_ADDR + idx, + cfg->layout.plane_addr[0]); + SDE_REG_WRITE(&ctx->hw, SSPP_SRC2_ADDR + idx, + cfg->layout.plane_addr[2]); + } else { + SDE_REG_WRITE(&ctx->hw, SSPP_SRC1_ADDR + idx, + cfg->layout.plane_addr[0]); + SDE_REG_WRITE(&ctx->hw, SSPP_SRC3_ADDR + idx, + cfg->layout.plane_addr[2]); + } +} + +u32 sde_hw_sspp_get_source_addr(struct sde_hw_pipe *ctx, bool is_virtual) +{ + u32 idx; + u32 offset = 0; + + if (!ctx || _sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return 0; + + offset = is_virtual ? (SSPP_SRC1_ADDR + idx) : (SSPP_SRC0_ADDR + idx); + + return SDE_REG_READ(&ctx->hw, offset); +} + +static void sde_hw_sspp_setup_csc(struct sde_hw_pipe *ctx, + struct sde_csc_cfg *data) +{ + u32 idx; + bool csc10 = false; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_CSC, &idx) || !data) + return; + + if (test_bit(SDE_SSPP_CSC_10BIT, &ctx->cap->features)) { + idx += CSC_10BIT_OFFSET; + csc10 = true; + } + + sde_hw_csc_setup(&ctx->hw, idx, data, csc10); +} + +static void sde_hw_sspp_setup_sharpening(struct sde_hw_pipe *ctx, + struct sde_hw_sharp_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SCALER_QSEED2, &idx) || !cfg || + !test_bit(SDE_SSPP_SCALER_QSEED2, &ctx->cap->features)) + return; + + c = &ctx->hw; + + SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx, cfg->strength); + SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0x4, cfg->edge_thr); + SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0x8, cfg->smooth_thr); + SDE_REG_WRITE(c, VIG_0_QSEED2_SHARP + idx + 0xC, cfg->noise_thr); +} + +static void sde_hw_sspp_setup_solidfill(struct sde_hw_pipe *ctx, u32 color, enum + sde_sspp_multirect_index rect_index) +{ + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (rect_index == SDE_SSPP_RECT_SOLO || rect_index == SDE_SSPP_RECT_0) + SDE_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR + idx, color); + else + SDE_REG_WRITE(&ctx->hw, SSPP_SRC_CONSTANT_COLOR_REC1 + idx, + color); +} + +static void sde_hw_sspp_setup_qos_lut(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_qos_cfg *cfg) +{ + u32 idx; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + SDE_REG_WRITE(&ctx->hw, SSPP_DANGER_LUT + idx, cfg->danger_lut); + SDE_REG_WRITE(&ctx->hw, SSPP_SAFE_LUT + idx, cfg->safe_lut); + + if (ctx->cap && test_bit(SDE_PERF_SSPP_QOS_8LVL, + &ctx->cap->perf_features)) { + SDE_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_0 + idx, cfg->creq_lut); + SDE_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT_1 + idx, + cfg->creq_lut >> 32); + } else { + SDE_REG_WRITE(&ctx->hw, SSPP_CREQ_LUT + idx, cfg->creq_lut); + } +} + +static void sde_hw_sspp_setup_qos_ctrl(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_qos_cfg *cfg) +{ + u32 idx; + u32 qos_ctrl = 0; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (cfg->vblank_en) { + qos_ctrl |= ((cfg->creq_vblank & + SSPP_QOS_CTRL_CREQ_VBLANK_MASK) << + SSPP_QOS_CTRL_CREQ_VBLANK_OFF); + qos_ctrl |= ((cfg->danger_vblank & + SSPP_QOS_CTRL_DANGER_VBLANK_MASK) << + SSPP_QOS_CTRL_DANGER_VBLANK_OFF); + qos_ctrl |= SSPP_QOS_CTRL_VBLANK_EN; + } + + if (cfg->danger_safe_en) + qos_ctrl |= SSPP_QOS_CTRL_DANGER_SAFE_EN; + + SDE_REG_WRITE(&ctx->hw, SSPP_QOS_CTRL + idx, qos_ctrl); +} + +static void sde_hw_sspp_setup_ts_prefill(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_ts_cfg *cfg, + enum sde_sspp_multirect_index index) +{ + u32 idx; + u32 ts_offset, ts_prefill_offset; + u32 ts_count = 0, ts_bytes = 0; + const struct sde_sspp_cfg *cap; + + if (!ctx || !cfg || !ctx->cap) + return; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + cap = ctx->cap; + + if ((index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) && + test_bit(SDE_PERF_SSPP_TS_PREFILL, + &cap->perf_features)) { + ts_offset = SSPP_TRAFFIC_SHAPER; + ts_prefill_offset = SSPP_TRAFFIC_SHAPER_PREFILL; + } else if (index == SDE_SSPP_RECT_1 && + test_bit(SDE_PERF_SSPP_TS_PREFILL_REC1, + &cap->perf_features)) { + ts_offset = SSPP_TRAFFIC_SHAPER_REC1; + ts_prefill_offset = SSPP_TRAFFIC_SHAPER_REC1_PREFILL; + } else { + pr_err("%s: unexpected idx:%d\n", __func__, index); + return; + } + + if (cfg->time) { + u64 temp = DIV_ROUND_UP_ULL(TS_CLK * 1000000ULL, cfg->time); + + ts_bytes = temp * cfg->size; + if (ts_bytes > SSPP_TRAFFIC_SHAPER_BPC_MAX) + ts_bytes = SSPP_TRAFFIC_SHAPER_BPC_MAX; + } + + if (ts_bytes) { + ts_count = DIV_ROUND_UP_ULL(cfg->size, ts_bytes); + ts_bytes |= BIT(31) | BIT(27); + } + + SDE_REG_WRITE(&ctx->hw, ts_offset, ts_bytes); + SDE_REG_WRITE(&ctx->hw, ts_prefill_offset, ts_count); +} + +static void sde_hw_sspp_setup_cdp(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cdp_cfg *cfg, + enum sde_sspp_multirect_index index) +{ + u32 idx; + u32 cdp_cntl = 0; + u32 cdp_cntl_offset = 0; + + if (!ctx || !cfg) + return; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (index == SDE_SSPP_RECT_SOLO || index == SDE_SSPP_RECT_0) { + cdp_cntl_offset = SSPP_CDP_CNTL; + } else if (index == SDE_SSPP_RECT_1) { + cdp_cntl_offset = SSPP_CDP_CNTL_REC1; + } else { + pr_err("%s: unexpected idx:%d\n", __func__, index); + return; + } + + if (cfg->enable) + cdp_cntl |= BIT(0); + if (cfg->ubwc_meta_enable) + cdp_cntl |= BIT(1); + if (cfg->tile_amortize_enable) + cdp_cntl |= BIT(2); + if (cfg->preload_ahead == SDE_SSPP_CDP_PRELOAD_AHEAD_64) + cdp_cntl |= BIT(3); + + SDE_REG_WRITE(&ctx->hw, cdp_cntl_offset, cdp_cntl); +} + +static void sde_hw_sspp_setup_sys_cache(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_sc_cfg *cfg) +{ + u32 idx, val; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (!cfg) + return; + + val = SDE_REG_READ(&ctx->hw, SSPP_SYS_CACHE_MODE + idx); + + if (cfg->flags & SSPP_SYS_CACHE_EN_FLAG) + val = (val & ~BIT(15)) | ((cfg->rd_en & 0x1) << 15); + + if (cfg->flags & SSPP_SYS_CACHE_SCID) + val = (val & ~0x1F00) | ((cfg->rd_scid & 0x1f) << 8); + + if (cfg->flags & SSPP_SYS_CACHE_OP_MODE) + val = (val & ~0xC0000) | ((cfg->op_mode & 0x3) << 18); + + if (cfg->flags & SSPP_SYS_CACHE_OP_TYPE) + val = (val & ~0xF) | ((cfg->rd_op_type & 0xf) << 0); + + if (cfg->flags & SSPP_SYS_CACHE_NO_ALLOC) + val = (val & ~0x10) | ((cfg->rd_noallocate & 0x1) << 4); + + SDE_REG_WRITE(&ctx->hw, SSPP_SYS_CACHE_MODE + idx, val); +} + +static void sde_hw_sspp_setup_uidle(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_uidle_cfg *cfg, + enum sde_sspp_multirect_index index) +{ + u32 idx, val; + u32 offset; + + if (_sspp_subblk_offset(ctx, SDE_SSPP_SRC, &idx)) + return; + + if (index == SDE_SSPP_RECT_1) + offset = SSPP_UIDLE_CTRL_VALUE_REC1; + else + offset = SSPP_UIDLE_CTRL_VALUE; + + val = SDE_REG_READ(&ctx->hw, offset + idx); + val = (val & ~BIT(31)) | (cfg->enable ? 0x0 : BIT(31)); + val = (val & ~0xFF00000) | (cfg->fal_allowed_threshold << 20); + val = (val & ~0xF0000) | (cfg->fal10_exit_threshold << 16); + val = (val & ~0xF00) | (cfg->fal10_threshold << 8); + val = (val & ~0xF) | (cfg->fal1_threshold << 0); + + SDE_REG_WRITE(&ctx->hw, offset + idx, val); +} + +static void _setup_layer_ops_colorproc(struct sde_hw_pipe *c, + unsigned long features, bool is_virtual_pipe) +{ + int ret = 0; + + if (is_virtual_pipe) { + features &= + ~(BIT(SDE_SSPP_VIG_IGC) | BIT(SDE_SSPP_VIG_GAMUT)); + c->cap->features = features; + } + + if (test_bit(SDE_SSPP_HSIC, &features)) { + if (c->cap->sblk->hsic_blk.version == + (SDE_COLOR_PROCESS_VER(0x1, 0x7))) { + c->ops.setup_pa_hue = sde_setup_pipe_pa_hue_v1_7; + c->ops.setup_pa_sat = sde_setup_pipe_pa_sat_v1_7; + c->ops.setup_pa_val = sde_setup_pipe_pa_val_v1_7; + c->ops.setup_pa_cont = sde_setup_pipe_pa_cont_v1_7; + } + } + + if (test_bit(SDE_SSPP_MEMCOLOR, &features)) { + if (c->cap->sblk->memcolor_blk.version == + (SDE_COLOR_PROCESS_VER(0x1, 0x7))) + c->ops.setup_pa_memcolor = + sde_setup_pipe_pa_memcol_v1_7; + } + + if (test_bit(SDE_SSPP_VIG_GAMUT, &features)) { + if (c->cap->sblk->gamut_blk.version == + (SDE_COLOR_PROCESS_VER(0x5, 0x0))) { + ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_VIG_GAMUT, + c->idx); + if (!ret) + c->ops.setup_vig_gamut = + reg_dmav1_setup_vig_gamutv5; + else + c->ops.setup_vig_gamut = NULL; + } + + if (c->cap->sblk->gamut_blk.version == + (SDE_COLOR_PROCESS_VER(0x6, 0x0))) { + ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_VIG_GAMUT, + c->idx); + if (!ret) + c->ops.setup_vig_gamut = + reg_dmav1_setup_vig_gamutv6; + else + c->ops.setup_vig_gamut = NULL; + } + } + + if (test_bit(SDE_SSPP_VIG_IGC, &features)) { + if (c->cap->sblk->igc_blk[0].version == + (SDE_COLOR_PROCESS_VER(0x5, 0x0))) { + ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_VIG_IGC, + c->idx); + if (!ret) + c->ops.setup_vig_igc = + reg_dmav1_setup_vig_igcv5; + else + c->ops.setup_vig_igc = NULL; + } + + if (c->cap->sblk->igc_blk[0].version == + (SDE_COLOR_PROCESS_VER(0x6, 0x0))) { + ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_VIG_IGC, + c->idx); + if (!ret) + c->ops.setup_vig_igc = + reg_dmav1_setup_vig_igcv6; + else + c->ops.setup_vig_igc = NULL; + } + } + + if (test_bit(SDE_SSPP_DMA_IGC, &features)) { + if (c->cap->sblk->igc_blk[0].version == + (SDE_COLOR_PROCESS_VER(0x5, 0x0))) { + ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_DMA_IGC, + c->idx); + if (!ret) + c->ops.setup_dma_igc = + reg_dmav1_setup_dma_igcv5; + else + c->ops.setup_dma_igc = NULL; + } + } + + if (test_bit(SDE_SSPP_DMA_GC, &features)) { + if (c->cap->sblk->gc_blk[0].version == + (SDE_COLOR_PROCESS_VER(0x5, 0x0))) { + ret = reg_dmav1_init_sspp_op_v4(SDE_SSPP_DMA_GC, + c->idx); + if (!ret) + c->ops.setup_dma_gc = + reg_dmav1_setup_dma_gcv5; + else + c->ops.setup_dma_gc = NULL; + } + } +} + +static void sde_hw_sspp_setup_inverse_pma(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, u32 enable) +{ + u32 op_mode = 0; + + if (!ctx || (index == SDE_SSPP_RECT_1)) + return; + + if (enable) + op_mode |= BIT(0); + + SDE_REG_WRITE(&ctx->hw, SSPP_GAMUT_UNMULT_MODE, op_mode); +} + +static void sde_hw_sspp_setup_dgm_inverse_pma(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, u32 enable) +{ + u32 offset = SSPP_DGM_OP_MODE; + u32 op_mode = 0; + + if (!ctx) + return; + + if (index == SDE_SSPP_RECT_1) + offset = SSPP_DGM_OP_MODE_REC1; + + op_mode = SDE_REG_READ(&ctx->hw, offset); + + if (enable) + op_mode |= BIT(0); + else + op_mode &= ~BIT(0); + + SDE_REG_WRITE(&ctx->hw, offset, op_mode); +} + +static void sde_hw_sspp_setup_dgm_csc(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, struct sde_csc_cfg *data) +{ + u32 idx = 0; + u32 offset; + u32 op_mode = 0; + const struct sde_sspp_sub_blks *sblk; + + if (!ctx || !ctx->cap || !ctx->cap->sblk) + return; + + sblk = ctx->cap->sblk; + if (index == SDE_SSPP_RECT_1) + idx = 1; + + offset = sblk->dgm_csc_blk[idx].base; + if (data) { + op_mode |= BIT(0); + sde_hw_csc_matrix_coeff_setup(&ctx->hw, + offset + CSC_10BIT_OFFSET, data, DGM_CSC_MATRIX_SHIFT); + } + + SDE_REG_WRITE(&ctx->hw, offset, op_mode); +} + +static void _setup_layer_ops(struct sde_hw_pipe *c, + unsigned long features, unsigned long perf_features, + bool is_virtual_pipe) +{ + int ret; + + if (test_bit(SDE_SSPP_SRC, &features)) { + c->ops.setup_format = sde_hw_sspp_setup_format; + c->ops.setup_rects = sde_hw_sspp_setup_rects; + c->ops.setup_sourceaddress = sde_hw_sspp_setup_sourceaddress; + c->ops.get_sourceaddress = sde_hw_sspp_get_source_addr; + c->ops.setup_solidfill = sde_hw_sspp_setup_solidfill; + c->ops.setup_pe = sde_hw_sspp_setup_pe_config; + c->ops.setup_secure_address = sde_hw_sspp_setup_secure; + c->ops.set_src_split_order = sde_hw_sspp_set_src_split_order; + } + + if (test_bit(SDE_SSPP_EXCL_RECT, &features)) + c->ops.setup_excl_rect = _sde_hw_sspp_setup_excl_rect; + + if (test_bit(SDE_PERF_SSPP_QOS, &features)) { + c->ops.setup_qos_lut = + sde_hw_sspp_setup_qos_lut; + c->ops.setup_qos_ctrl = sde_hw_sspp_setup_qos_ctrl; + } + + if (test_bit(SDE_PERF_SSPP_TS_PREFILL, &perf_features)) + c->ops.setup_ts_prefill = sde_hw_sspp_setup_ts_prefill; + + if (test_bit(SDE_SSPP_CSC, &features) || + test_bit(SDE_SSPP_CSC_10BIT, &features)) + c->ops.setup_csc = sde_hw_sspp_setup_csc; + + if (test_bit(SDE_SSPP_DGM_CSC, &features)) + c->ops.setup_dgm_csc = sde_hw_sspp_setup_dgm_csc; + + if (test_bit(SDE_SSPP_SCALER_QSEED2, &features)) { + c->ops.setup_sharpening = sde_hw_sspp_setup_sharpening; + c->ops.setup_scaler = _sde_hw_sspp_setup_scaler; + } + + if (sde_hw_sspp_multirect_enabled(c->cap)) + c->ops.setup_multirect = sde_hw_sspp_setup_multirect; + + if (test_bit(SDE_SSPP_SCALER_QSEED3, &features) || + test_bit(SDE_SSPP_SCALER_QSEED3LITE, &features)) { + c->ops.setup_scaler = _sde_hw_sspp_setup_scaler3; + c->ops.get_scaler_ver = _sde_hw_sspp_get_scaler3_ver; + c->ops.setup_scaler_lut = is_qseed3_rev_qseed3lite( + c->catalog) ? reg_dmav1_setup_scaler3lite_lut + : reg_dmav1_setup_scaler3_lut; + ret = reg_dmav1_init_sspp_op_v4(is_qseed3_rev_qseed3lite( + c->catalog) ? SDE_SSPP_SCALER_QSEED3LITE + : SDE_SSPP_SCALER_QSEED3, c->idx); + if (!ret) + c->ops.setup_scaler = reg_dmav1_setup_vig_qseed3; + } + + if (test_bit(SDE_SSPP_PREDOWNSCALE, &features)) + c->ops.setup_pre_downscale = sde_hw_sspp_setup_pre_downscale; + + if (test_bit(SDE_PERF_SSPP_SYS_CACHE, &perf_features)) + c->ops.setup_sys_cache = sde_hw_sspp_setup_sys_cache; + + if (test_bit(SDE_PERF_SSPP_CDP, &perf_features)) + c->ops.setup_cdp = sde_hw_sspp_setup_cdp; + + if (test_bit(SDE_PERF_SSPP_UIDLE, &perf_features)) + c->ops.setup_uidle = sde_hw_sspp_setup_uidle; + + _setup_layer_ops_colorproc(c, features, is_virtual_pipe); + + if (test_bit(SDE_SSPP_DGM_INVERSE_PMA, &features)) + c->ops.setup_inverse_pma = sde_hw_sspp_setup_dgm_inverse_pma; + else if (test_bit(SDE_SSPP_INVERSE_PMA, &features)) + c->ops.setup_inverse_pma = sde_hw_sspp_setup_inverse_pma; + + c->ops.get_ubwc_error = sde_hw_sspp_get_ubwc_error; + c->ops.clear_ubwc_error = sde_hw_sspp_clear_ubwc_error; +} + +static struct sde_sspp_cfg *_sspp_offset(enum sde_sspp sspp, + void __iomem *addr, + struct sde_mdss_cfg *catalog, + struct sde_hw_blk_reg_map *b) +{ + int i; + struct sde_sspp_cfg *cfg; + + if ((sspp < SSPP_MAX) && catalog && addr && b) { + for (i = 0; i < catalog->sspp_count; i++) { + if (sspp == catalog->sspp[i].id) { + b->base_off = addr; + b->blk_off = catalog->sspp[i].base; + b->length = catalog->sspp[i].len; + b->hwversion = catalog->hwversion; + b->log_mask = SDE_DBG_MASK_SSPP; + + /* Only shallow copy is needed */ + cfg = kmemdup(&catalog->sspp[i], sizeof(*cfg), + GFP_KERNEL); + if (!cfg) + return ERR_PTR(-ENOMEM); + + return cfg; + } + } + } + + return ERR_PTR(-ENOMEM); +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, + void __iomem *addr, struct sde_mdss_cfg *catalog, + bool is_virtual_pipe) +{ + struct sde_hw_pipe *hw_pipe; + struct sde_sspp_cfg *cfg; + int rc; + + if (!addr || !catalog) + return ERR_PTR(-EINVAL); + + hw_pipe = kzalloc(sizeof(*hw_pipe), GFP_KERNEL); + if (!hw_pipe) + return ERR_PTR(-ENOMEM); + + cfg = _sspp_offset(idx, addr, catalog, &hw_pipe->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(hw_pipe); + return ERR_PTR(-EINVAL); + } + + /* Assign ops */ + hw_pipe->catalog = catalog; + hw_pipe->mdp = &catalog->mdp[0]; + hw_pipe->idx = idx; + hw_pipe->cap = cfg; + _setup_layer_ops(hw_pipe, hw_pipe->cap->features, + hw_pipe->cap->perf_features, is_virtual_pipe); + + if (hw_pipe->ops.get_scaler_ver) { + sde_init_scaler_blk(&hw_pipe->cap->sblk->scaler_blk, + hw_pipe->ops.get_scaler_ver(hw_pipe)); + } + + rc = sde_hw_blk_init(&hw_pipe->base, SDE_HW_BLK_SSPP, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + if (!is_virtual_pipe) + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, + hw_pipe->hw.blk_off, + hw_pipe->hw.blk_off + hw_pipe->hw.length, + hw_pipe->hw.xin_id); + + if (cfg->sblk->scaler_blk.len && !is_virtual_pipe) + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, + cfg->sblk->scaler_blk.name, + hw_pipe->hw.blk_off + cfg->sblk->scaler_blk.base, + hw_pipe->hw.blk_off + cfg->sblk->scaler_blk.base + + cfg->sblk->scaler_blk.len, + hw_pipe->hw.xin_id); + + return hw_pipe; + +blk_init_error: + kzfree(hw_pipe); + + return ERR_PTR(rc); +} + +void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx) +{ + if (ctx) { + sde_hw_blk_destroy(&ctx->base); + reg_dmav1_deinit_sspp_ops(ctx->idx); + kfree(ctx->cap); + } + kfree(ctx); +} + diff --git a/techpack/display/msm/sde/sde_hw_sspp.h b/techpack/display/msm/sde/sde_hw_sspp.h new file mode 100644 index 0000000000000000000000000000000000000000..46b93fe3997f059c951187f64086d322dad4264e --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_sspp.h @@ -0,0 +1,667 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_SSPP_H +#define _SDE_HW_SSPP_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_reg_dma.h" +#include "sde_hw_blk.h" +#include "sde_formats.h" +#include "sde_color_processing.h" + +struct sde_hw_pipe; + +/** + * Flags + */ +#define SDE_SSPP_SECURE_OVERLAY_SESSION 0x1 +#define SDE_SSPP_FLIP_LR 0x2 +#define SDE_SSPP_FLIP_UD 0x4 +#define SDE_SSPP_SOURCE_ROTATED_90 0x8 +#define SDE_SSPP_ROT_90 0x10 +#define SDE_SSPP_SOLID_FILL 0x20 +#define SDE_SSPP_RIGHT 0x40 + +/** + * Define all scaler feature bits in catalog + */ +#define SDE_SSPP_SCALER ((1UL << SDE_SSPP_SCALER_RGB) | \ + (1UL << SDE_SSPP_SCALER_QSEED2) | \ + (1UL << SDE_SSPP_SCALER_QSEED3) | \ + (1UL << SDE_SSPP_SCALER_QSEED3LITE)) + +/** + * Component indices + */ +enum { + SDE_SSPP_COMP_0, + SDE_SSPP_COMP_1_2, + SDE_SSPP_COMP_2, + SDE_SSPP_COMP_3, + + SDE_SSPP_COMP_MAX +}; + +/** + * SDE_SSPP_RECT_SOLO - multirect disabled + * SDE_SSPP_RECT_0 - rect0 of a multirect pipe + * SDE_SSPP_RECT_1 - rect1 of a multirect pipe + * SDE_SSPP_RECT_MAX - max enum of multirect pipe + * + * Note: HW supports multirect with either RECT0 or + * RECT1. Considering no benefit of such configs over + * SOLO mode and to keep the plane management simple, + * we dont support single rect multirect configs. + */ +enum sde_sspp_multirect_index { + SDE_SSPP_RECT_SOLO = 0, + SDE_SSPP_RECT_0, + SDE_SSPP_RECT_1, + SDE_SSPP_RECT_MAX, +}; + +enum sde_sspp_multirect_mode { + SDE_SSPP_MULTIRECT_NONE = 0, + SDE_SSPP_MULTIRECT_PARALLEL, + SDE_SSPP_MULTIRECT_TIME_MX, +}; + +enum { + SDE_FRAME_LINEAR, + SDE_FRAME_TILE_A4X, + SDE_FRAME_TILE_A5X, +}; + +enum sde_hw_filter { + SDE_SCALE_FILTER_NEAREST = 0, + SDE_SCALE_FILTER_BIL, + SDE_SCALE_FILTER_PCMN, + SDE_SCALE_FILTER_CA, + SDE_SCALE_FILTER_MAX +}; + +enum sde_hw_filter_alpa { + SDE_SCALE_ALPHA_PIXEL_REP, + SDE_SCALE_ALPHA_BIL +}; + +enum sde_hw_filter_yuv { + SDE_SCALE_2D_4X4, + SDE_SCALE_2D_CIR, + SDE_SCALE_1D_SEP, + SDE_SCALE_BIL +}; + +struct sde_hw_sharp_cfg { + u32 strength; + u32 edge_thr; + u32 smooth_thr; + u32 noise_thr; +}; + +struct sde_hw_pixel_ext { + /* scaling factors are enabled for this input layer */ + uint8_t enable_pxl_ext; + + int init_phase_x[SDE_MAX_PLANES]; + int phase_step_x[SDE_MAX_PLANES]; + int init_phase_y[SDE_MAX_PLANES]; + int phase_step_y[SDE_MAX_PLANES]; + + /* + * Number of pixels extension in left, right, top and bottom direction + * for all color components. This pixel value for each color component + * should be sum of fetch + repeat pixels. + */ + int num_ext_pxls_left[SDE_MAX_PLANES]; + int num_ext_pxls_right[SDE_MAX_PLANES]; + int num_ext_pxls_top[SDE_MAX_PLANES]; + int num_ext_pxls_btm[SDE_MAX_PLANES]; + + /* + * Number of pixels needs to be overfetched in left, right, top and + * bottom directions from source image for scaling. + */ + int left_ftch[SDE_MAX_PLANES]; + int right_ftch[SDE_MAX_PLANES]; + int top_ftch[SDE_MAX_PLANES]; + int btm_ftch[SDE_MAX_PLANES]; + + /* + * Number of pixels needs to be repeated in left, right, top and + * bottom directions for scaling. + */ + int left_rpt[SDE_MAX_PLANES]; + int right_rpt[SDE_MAX_PLANES]; + int top_rpt[SDE_MAX_PLANES]; + int btm_rpt[SDE_MAX_PLANES]; + + uint32_t roi_w[SDE_MAX_PLANES]; + uint32_t roi_h[SDE_MAX_PLANES]; + + /* + * Filter type to be used for scaling in horizontal and vertical + * directions + */ + enum sde_hw_filter horz_filter[SDE_MAX_PLANES]; + enum sde_hw_filter vert_filter[SDE_MAX_PLANES]; + +}; + +/** + * struct sde_hw_pipe_cfg : Pipe description + * @layout: format layout information for programming buffer to hardware + * @src_rect: src ROI, caller takes into account the different operations + * such as decimation, flip etc to program this field + * @dest_rect: destination ROI. + * @ horz_decimation : horizontal decimation factor( 0, 2, 4, 8, 16) + * @ vert_decimation : vertical decimation factor( 0, 2, 4, 8, 16) + * 2: Read 1 line/pixel drop 1 line/pixel + * 4: Read 1 line/pixel drop 3 lines/pixels + * 8: Read 1 line/pixel drop 7 lines/pixels + * 16: Read 1 line/pixel drop 15 line/pixels + * @index: index of the rectangle of SSPP + * @mode: parallel or time multiplex multirect mode + */ +struct sde_hw_pipe_cfg { + struct sde_hw_fmt_layout layout; + struct sde_rect src_rect; + struct sde_rect dst_rect; + u8 horz_decimation; + u8 vert_decimation; + enum sde_sspp_multirect_index index; + enum sde_sspp_multirect_mode mode; +}; + +/** + * struct sde_hw_pipe_qos_cfg : Source pipe QoS configuration + * @danger_lut: LUT for generate danger level based on fill level + * @safe_lut: LUT for generate safe level based on fill level + * @creq_lut: LUT for generate creq level based on fill level + * @creq_vblank: creq value generated to vbif during vertical blanking + * @danger_vblank: danger value generated during vertical blanking + * @vblank_en: enable creq_vblank and danger_vblank during vblank + * @danger_safe_en: enable danger safe generation + */ +struct sde_hw_pipe_qos_cfg { + u32 danger_lut; + u32 safe_lut; + u64 creq_lut; + u32 creq_vblank; + u32 danger_vblank; + bool vblank_en; + bool danger_safe_en; +}; + +/** + * enum CDP preload ahead address size + */ +enum { + SDE_SSPP_CDP_PRELOAD_AHEAD_32, + SDE_SSPP_CDP_PRELOAD_AHEAD_64 +}; + +/** + * struct sde_hw_pipe_cdp_cfg : CDP configuration + * @enable: true to enable CDP + * @ubwc_meta_enable: true to enable ubwc metadata preload + * @tile_amortize_enable: true to enable amortization control for tile format + * @preload_ahead: number of request to preload ahead + * SDE_SSPP_CDP_PRELOAD_AHEAD_32, + * SDE_SSPP_CDP_PRELOAD_AHEAD_64 + */ +struct sde_hw_pipe_cdp_cfg { + bool enable; + bool ubwc_meta_enable; + bool tile_amortize_enable; + u32 preload_ahead; +}; + +/** + * enum system cache rotation operation mode + */ +enum { + SDE_PIPE_SC_OP_MODE_OFFLINE, + SDE_PIPE_SC_OP_MODE_INLINE_SINGLE, + SDE_PIPE_SC_OP_MODE_INLINE_LEFT, + SDE_PIPE_SC_OP_MODE_INLINE_RIGHT, +}; + +/** + * enum system cache read operation type + */ +enum { + SDE_PIPE_SC_RD_OP_TYPE_CACHEABLE, + SDE_PIPE_SC_RD_OP_TYPE_INVALIDATE, + SDE_PIPE_SC_RD_OP_TYPE_EVICTION, +}; + +/** + * struct sde_hw_pipe_sc_cfg - system cache configuration + * @op_mode: rotation operating mode + * @rd_en: system cache read enable + * @rd_scid: system cache read block id + * @rd_noallocate: system cache read no allocate attribute + * @rd_op_type: system cache read operation type + * @flags: dirty flags to change the configuration + */ +struct sde_hw_pipe_sc_cfg { + u32 op_mode; + bool rd_en; + u32 rd_scid; + bool rd_noallocate; + u32 rd_op_type; + u32 flags; +}; + +/** + * struct sde_hw_pipe_uidle_cfg - uidle configuration + * @enable: disables uidle + * @fal_allowed_threshold: minimum fl to allow uidle + * @fal10_exit_threshold: number of lines to indicate fal_10_exit is okay + * @fal10_threshold: number of lines where fal_10_is okay + * @fal1_threshold: number of lines where fal_1 is okay + */ +struct sde_hw_pipe_uidle_cfg { + u32 enable; + u32 fal_allowed_threshold; + u32 fal10_exit_threshold; + u32 fal10_threshold; + u32 fal1_threshold; +}; + +/** + * struct sde_hw_pipe_ts_cfg - traffic shaper configuration + * @size: size to prefill in bytes, or zero to disable + * @time: time to prefill in usec, or zero to disable + */ +struct sde_hw_pipe_ts_cfg { + u64 size; + u64 time; +}; + +/** + * Maximum number of stream buffer plane + */ +#define SDE_PIPE_SBUF_PLANE_NUM 2 + +/** + * struct sde_hw_sspp_ops - interface to the SSPP Hw driver functions + * Caller must call the init function to get the pipe context for each pipe + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_sspp_ops { + /** + * setup_format - setup pixel format cropping rectangle, flip + * @ctx: Pointer to pipe context + * @fmt: Pointer to sde_format structure + * @blend_enabled: flag indicating blend enabled or disabled on plane + * @flags: Extra flags for format config + * @index: rectangle index in multirect + */ + void (*setup_format)(struct sde_hw_pipe *ctx, + const struct sde_format *fmt, + bool blend_enabled, u32 flags, + enum sde_sspp_multirect_index index); + + /** + * setup_rects - setup pipe ROI rectangles + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe config structure + * @index: rectangle index in multirect + */ + void (*setup_rects)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *cfg, + enum sde_sspp_multirect_index index); + + /** + * setup_pe - setup pipe pixel extension + * @ctx: Pointer to pipe context + * @pe_ext: Pointer to pixel ext settings + */ + void (*setup_pe)(struct sde_hw_pipe *ctx, + struct sde_hw_pixel_ext *pe_ext); + + /** + * setup_excl_rect - setup pipe exclusion rectangle + * @ctx: Pointer to pipe context + * @excl_rect: Pointer to exclclusion rect structure + * @index: rectangle index in multirect + */ + void (*setup_excl_rect)(struct sde_hw_pipe *ctx, + struct sde_rect *excl_rect, + enum sde_sspp_multirect_index index); + + /** + * setup_sourceaddress - setup pipe source addresses + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe config structure + * @index: rectangle index in multirect + */ + void (*setup_sourceaddress)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *cfg, + enum sde_sspp_multirect_index index); + + /* get_sourceaddress - get pipe current source addresses of a plane + * @ctx: Pointer to pipe context + * @is_virtual: If true get address programmed for R1 in multirect + */ + u32 (*get_sourceaddress)(struct sde_hw_pipe *ctx, bool is_virtual); + + /** + * setup_csc - setup color space conversion + * @ctx: Pointer to pipe context + * @data: Pointer to config structure + */ + void (*setup_csc)(struct sde_hw_pipe *ctx, struct sde_csc_cfg *data); + + /** + * setup_solidfill - enable/disable colorfill + * @ctx: Pointer to pipe context + * @const_color: Fill color value + * @flags: Pipe flags + * @index: rectangle index in multirect + */ + void (*setup_solidfill)(struct sde_hw_pipe *ctx, u32 color, + enum sde_sspp_multirect_index index); + + /** + * setup_multirect - setup multirect configuration + * @ctx: Pointer to pipe context + * @index: rectangle index in multirect + * @mode: parallel fetch / time multiplex multirect mode + */ + + void (*setup_multirect)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, + enum sde_sspp_multirect_mode mode); + + /** + * setup_sharpening - setup sharpening + * @ctx: Pointer to pipe context + * @cfg: Pointer to config structure + */ + void (*setup_sharpening)(struct sde_hw_pipe *ctx, + struct sde_hw_sharp_cfg *cfg); + + + /** + * setup_pa_hue(): Setup source hue adjustment + * @ctx: Pointer to pipe context + * @cfg: Pointer to hue data + */ + void (*setup_pa_hue)(struct sde_hw_pipe *ctx, void *cfg); + + /** + * setup_pa_sat(): Setup source saturation adjustment + * @ctx: Pointer to pipe context + * @cfg: Pointer to saturation data + */ + void (*setup_pa_sat)(struct sde_hw_pipe *ctx, void *cfg); + + /** + * setup_pa_val(): Setup source value adjustment + * @ctx: Pointer to pipe context + * @cfg: Pointer to value data + */ + void (*setup_pa_val)(struct sde_hw_pipe *ctx, void *cfg); + + /** + * setup_pa_cont(): Setup source contrast adjustment + * @ctx: Pointer to pipe context + * @cfg: Pointer contrast data + */ + void (*setup_pa_cont)(struct sde_hw_pipe *ctx, void *cfg); + + /** + * setup_pa_memcolor - setup source color processing + * @ctx: Pointer to pipe context + * @type: Memcolor type (Skin, sky or foliage) + * @cfg: Pointer to memory color config data + */ + void (*setup_pa_memcolor)(struct sde_hw_pipe *ctx, + enum sde_memcolor_type type, void *cfg); + + /** + * setup_vig_gamut - setup 3D LUT Gamut in VIG pipes + * @ctx: Pointer to pipe context + * @cfg: Pointer to vig gamut data + */ + void (*setup_vig_gamut)(struct sde_hw_pipe *ctx, void *cfg); + + /** + * setup_vig_igc - setup 1D LUT IGC in VIG pipes + * @ctx: Pointer to pipe context + * @cfg: Pointer to vig igc data + */ + void (*setup_vig_igc)(struct sde_hw_pipe *ctx, void *cfg); + + /** + * setup_dma_igc - setup 1D LUT IGC in DMA pipes + * @ctx: Pointer to pipe context + * @cfg: Pointer to dma igc data + * @idx: multirect index + */ + void (*setup_dma_igc)(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx); + + /** + * setup_dma_gc - setup 1D LUT GC in DMA pipes + * @ctx: Pointer to pipe context + * @cfg: Pointer to dma gc data + * @idx: multirect index + */ + void (*setup_dma_gc)(struct sde_hw_pipe *ctx, void *cfg, + enum sde_sspp_multirect_index idx); + + /** + * setup_qos_lut - setup danger, safe, creq LUTs + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe QoS configuration + * + */ + void (*setup_qos_lut)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_qos_cfg *cfg); + + /** + * setup_qos_ctrl - setup QoS control + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe QoS configuration + * + */ + void (*setup_qos_ctrl)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_qos_cfg *cfg); + + /** + * setup_histogram - setup histograms + * @ctx: Pointer to pipe context + * @cfg: Pointer to histogram configuration + */ + void (*setup_histogram)(struct sde_hw_pipe *ctx, + void *cfg); + + /** + * setup_scaler - setup scaler + * @ctx: Pointer to pipe context + * @pipe_cfg: Pointer to pipe configuration + * @pe_cfg: Pointer to pixel extension configuration + * @scaler_cfg: Pointer to scaler configuration + */ + void (*setup_scaler)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cfg *pipe_cfg, + struct sde_hw_pixel_ext *pe_cfg, + void *scaler_cfg); + + /** + * setup_scaler_lut - setup scaler lut + * @buf: Defines structure for reg dma ops on the reg dma buffer. + * @scaler3_cfg: QSEEDv3 configuration + * @offset: Scaler Offset + */ + void (*setup_scaler_lut)(struct sde_reg_dma_setup_ops_cfg *buf, + struct sde_hw_scaler3_cfg *scaler3_cfg, + u32 offset); + + /** + * setup_pre_downscale - setup pre-downscaler for inline rotation + * @ctx: Pointer to pipe context + * @pre_down: Pointer to pre-downscaler configuration + */ + void (*setup_pre_downscale)(struct sde_hw_pipe *ctx, + struct sde_hw_inline_pre_downscale_cfg *pre_down); + + /** + * get_scaler_ver - get scaler h/w version + * @ctx: Pointer to pipe context + */ + u32 (*get_scaler_ver)(struct sde_hw_pipe *ctx); + + /** + * setup_sys_cache - setup system cache configuration + * @ctx: Pointer to pipe context + * @cfg: Pointer to system cache configuration + */ + void (*setup_sys_cache)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_sc_cfg *cfg); + + /** + * setup_uidle - set uidle configuration + * @ctx: Pointer to pipe context + * @cfg: Pointer to uidle configuration + * @index: rectangle index in multirect + */ + void (*setup_uidle)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_uidle_cfg *cfg, + enum sde_sspp_multirect_index index); + + /** + * setup_ts_prefill - setup prefill traffic shaper + * @ctx: Pointer to pipe context + * @cfg: Pointer to traffic shaper configuration + * @index: rectangle index in multirect + */ + void (*setup_ts_prefill)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_ts_cfg *cfg, + enum sde_sspp_multirect_index index); + + /** + * setup_cdp - setup client driven prefetch + * @ctx: Pointer to pipe context + * @cfg: Pointer to cdp configuration + * @index: rectangle index in multirect + */ + void (*setup_cdp)(struct sde_hw_pipe *ctx, + struct sde_hw_pipe_cdp_cfg *cfg, + enum sde_sspp_multirect_index index); + + /** + * setup_secure_address - setup secureity status of the source address + * @ctx: Pointer to pipe context + * @index: rectangle index in multirect + * @enable: enable content protected buffer state + */ + void (*setup_secure_address)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, + bool enable); + + /** + * set_src_split_order - setup source split order priority + * @ctx: Pointer to pipe context + * @index: rectangle index in multirect + * @enable: enable src split order + */ + void (*set_src_split_order)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, bool enable); + + /** + * setup_inverse_pma - enable/disable alpha unmultiply unit (PMA) + * @ctx: Pointer to pipe context + * @index: Rectangle index in multirect + * @enable: PMA enable/disable settings + */ + void (*setup_inverse_pma)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, u32 enable); + + /** + * setup_dgm_csc - setup DGM color space conversion block and update lut + * @ctx: Pointer to pipe context + * @index: Rectangle index in multirect + * @data: Pointer to config structure + */ + void (*setup_dgm_csc)(struct sde_hw_pipe *ctx, + enum sde_sspp_multirect_index index, struct sde_csc_cfg *data); + + /** + * clear_ubwc_error - clear the ubwc error-code registers + * @ctx: Pointer to pipe context + */ + void (*clear_ubwc_error)(struct sde_hw_pipe *ctx); + + /** + * get_ubwc_error - get the ubwc error-code + * @ctx: Pointer to pipe context + */ + u32 (*get_ubwc_error)(struct sde_hw_pipe *ctx); +}; + +/** + * struct sde_hw_pipe - pipe description + * @base: hardware block base structure + * @hw: block hardware details + * @catalog: back pointer to catalog + * @mdp: pointer to associated mdp portion of the catalog + * @idx: pipe index + * @cap: pointer to layer_cfg + * @ops: pointer to operations possible for this pipe + */ +struct sde_hw_pipe { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + struct sde_mdss_cfg *catalog; + struct sde_mdp_cfg *mdp; + + /* Pipe */ + enum sde_sspp idx; + struct sde_sspp_cfg *cap; + + /* Ops */ + struct sde_hw_sspp_ops ops; + struct sde_hw_ctl *ctl; +}; + +/** + * sde_hw_pipe - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_pipe *to_sde_hw_pipe(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_pipe, base); +} + +/** + * sde_hw_sspp_init - initializes the sspp hw driver object. + * Should be called once before accessing every pipe. + * @idx: Pipe index for which driver object is required + * @addr: Mapped register io address of MDP + * @catalog : Pointer to mdss catalog data + * @is_virtual_pipe: is this pipe virtual pipe + */ +struct sde_hw_pipe *sde_hw_sspp_init(enum sde_sspp idx, + void __iomem *addr, struct sde_mdss_cfg *catalog, + bool is_virtual_pipe); + +/** + * sde_hw_sspp_destroy(): Destroys SSPP driver context + * should be called during Hw pipe cleanup. + * @ctx: Pointer to SSPP driver context returned by sde_hw_sspp_init + */ +void sde_hw_sspp_destroy(struct sde_hw_pipe *ctx); + +#endif /*_SDE_HW_SSPP_H */ + diff --git a/techpack/display/msm/sde/sde_hw_top.c b/techpack/display/msm/sde/sde_hw_top.c new file mode 100644 index 0000000000000000000000000000000000000000..b02cd17cbb280c1c2915b5934bcb294648e44c4a --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_top.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_top.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define SSPP_SPARE 0x28 +#define UBWC_DEC_HW_VERSION 0x058 +#define UBWC_STATIC 0x144 +#define UBWC_CTRL_2 0x150 +#define UBWC_PREDICTION_MODE 0x154 + +#define FLD_SPLIT_DISPLAY_CMD BIT(1) +#define FLD_SMART_PANEL_FREE_RUN BIT(2) +#define FLD_INTF_1_SW_TRG_MUX BIT(4) +#define FLD_INTF_2_SW_TRG_MUX BIT(8) +#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF + +#define MDP_DSPP_DBGBUS_CTRL 0x348 +#define MDP_DSPP_DBGBUS_STATUS 0x34C +#define DANGER_STATUS 0x360 +#define SAFE_STATUS 0x364 + +#define TE_LINE_INTERVAL 0x3F4 + +#define TRAFFIC_SHAPER_EN BIT(31) +#define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4)) +#define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) +#define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 + +#define MDP_WD_TIMER_0_CTL 0x380 +#define MDP_WD_TIMER_0_CTL2 0x384 +#define MDP_WD_TIMER_0_LOAD_VALUE 0x388 +#define MDP_WD_TIMER_1_CTL 0x390 +#define MDP_WD_TIMER_1_CTL2 0x394 +#define MDP_WD_TIMER_1_LOAD_VALUE 0x398 +#define MDP_PERIPH_DBGBUS_CTRL 0x418 +#define MDP_WD_TIMER_2_CTL 0x420 +#define MDP_WD_TIMER_2_CTL2 0x424 +#define MDP_WD_TIMER_2_LOAD_VALUE 0x428 +#define MDP_WD_TIMER_3_CTL 0x430 +#define MDP_WD_TIMER_3_CTL2 0x434 +#define MDP_WD_TIMER_3_LOAD_VALUE 0x438 +#define MDP_WD_TIMER_4_CTL 0x440 +#define MDP_WD_TIMER_4_CTL2 0x444 +#define MDP_WD_TIMER_4_LOAD_VALUE 0x448 + +#define MDP_TICK_COUNT 16 +#define XO_CLK_RATE 19200 +#define MS_TICKS_IN_SEC 1000 + +#define AUTOREFRESH_TEST_POINT 0x2 +#define TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0)) + +#define CALCULATE_WD_LOAD_VALUE(fps) \ + ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) + +#define DCE_SEL 0x450 + +#define ROT_SID_RD 0x20 +#define ROT_SID_WR 0x24 +#define ROT_SID_ID_VAL 0x1c + +static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp, + struct split_pipe_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 upper_pipe = 0; + u32 lower_pipe = 0; + + if (!mdp || !cfg) + return; + + c = &mdp->hw; + + if (cfg->en) { + if (cfg->mode == INTF_MODE_CMD) { + lower_pipe = FLD_SPLIT_DISPLAY_CMD; + /* interface controlling sw trigger */ + if (cfg->intf == INTF_2) + lower_pipe |= FLD_INTF_1_SW_TRG_MUX; + else + lower_pipe |= FLD_INTF_2_SW_TRG_MUX; + + /* free run */ + if (cfg->pp_split_slave != INTF_MAX) + lower_pipe = FLD_SMART_PANEL_FREE_RUN; + + upper_pipe = lower_pipe; + + /* smart panel align mode */ + lower_pipe |= BIT(mdp->caps->smart_panel_align_mode); + } else { + if (cfg->intf == INTF_2) { + lower_pipe = FLD_INTF_1_SW_TRG_MUX; + upper_pipe = FLD_INTF_2_SW_TRG_MUX; + } else { + lower_pipe = FLD_INTF_2_SW_TRG_MUX; + upper_pipe = FLD_INTF_1_SW_TRG_MUX; + } + } + } + + SDE_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0); + SDE_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe); + SDE_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe); + SDE_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1); +} + +static u32 sde_hw_get_split_flush(struct sde_hw_mdp *mdp) +{ + struct sde_hw_blk_reg_map *c; + + if (!mdp) + return 0; + + c = &mdp->hw; + + return (SDE_REG_READ(c, SSPP_SPARE) & 0x1); +} + +static void sde_hw_setup_pp_split(struct sde_hw_mdp *mdp, + struct split_pipe_cfg *cfg) +{ + u32 ppb_config = 0x0; + u32 ppb_control = 0x0; + + if (!mdp || !cfg) + return; + + if (cfg->split_link_en) { + ppb_config |= BIT(16); /* split enable */ + ppb_control = BIT(5); /* horz split*/ + } else if (cfg->en && cfg->pp_split_slave != INTF_MAX) { + ppb_config |= (cfg->pp_split_slave - INTF_0 + 1) << 20; + ppb_config |= BIT(16); /* split enable */ + ppb_control = BIT(5); /* horz split*/ + } + + if (cfg->pp_split_index && !cfg->split_link_en) { + SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, 0x0); + SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, 0x0); + SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, ppb_config); + SDE_REG_WRITE(&mdp->hw, PPB1_CNTL, ppb_control); + } else { + SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, ppb_config); + SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, ppb_control); + SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, 0x0); + SDE_REG_WRITE(&mdp->hw, PPB1_CNTL, 0x0); + } +} + +static void sde_hw_setup_cdm_output(struct sde_hw_mdp *mdp, + struct cdm_output_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 out_ctl = 0; + + if (!mdp || !cfg) + return; + + c = &mdp->hw; + + if (cfg->wb_en) + out_ctl |= BIT(24); + else if (cfg->intf_en) + out_ctl |= BIT(19); + + SDE_REG_WRITE(c, MDP_OUT_CTL_0, out_ctl); +} + +static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp, + enum sde_clk_ctrl_type clk_ctrl, bool enable) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_off, bit_off; + u32 reg_val, new_val; + bool clk_forced_on; + + if (!mdp) + return false; + + c = &mdp->hw; + + if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX) + return false; + + reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off; + bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off; + + reg_val = SDE_REG_READ(c, reg_off); + + if (enable) + new_val = reg_val | BIT(bit_off); + else + new_val = reg_val & ~BIT(bit_off); + + SDE_REG_WRITE(c, reg_off, new_val); + wmb(); /* ensure write finished before progressing */ + + clk_forced_on = !(reg_val & BIT(bit_off)); + + return clk_forced_on; +} + + +static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp, + struct sde_danger_safe_status *status) +{ + struct sde_hw_blk_reg_map *c; + u32 value; + + if (!mdp || !status) + return; + + c = &mdp->hw; + + value = SDE_REG_READ(c, DANGER_STATUS); + status->mdp = (value >> 0) & 0x3; + status->sspp[SSPP_VIG0] = (value >> 4) & 0x3; + status->sspp[SSPP_VIG1] = (value >> 6) & 0x3; + status->sspp[SSPP_VIG2] = (value >> 8) & 0x3; + status->sspp[SSPP_VIG3] = (value >> 10) & 0x3; + status->sspp[SSPP_RGB0] = (value >> 12) & 0x3; + status->sspp[SSPP_RGB1] = (value >> 14) & 0x3; + status->sspp[SSPP_RGB2] = (value >> 16) & 0x3; + status->sspp[SSPP_RGB3] = (value >> 18) & 0x3; + status->sspp[SSPP_DMA0] = (value >> 20) & 0x3; + status->sspp[SSPP_DMA1] = (value >> 22) & 0x3; + status->sspp[SSPP_DMA2] = (value >> 28) & 0x3; + status->sspp[SSPP_DMA3] = (value >> 30) & 0x3; + status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3; + status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3; + status->wb[WB_0] = 0; + status->wb[WB_1] = 0; + status->wb[WB_2] = (value >> 2) & 0x3; + status->wb[WB_3] = 0; +} + +static void _update_vsync_source(struct sde_hw_mdp *mdp, + struct sde_vsync_source_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 reg, wd_load_value, wd_ctl, wd_ctl2; + + if (!mdp || !cfg) + return; + + c = &mdp->hw; + + if (cfg->vsync_source >= SDE_VSYNC_SOURCE_WD_TIMER_4 && + cfg->vsync_source <= SDE_VSYNC_SOURCE_WD_TIMER_0) { + switch (cfg->vsync_source) { + case SDE_VSYNC_SOURCE_WD_TIMER_4: + wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_4_CTL; + wd_ctl2 = MDP_WD_TIMER_4_CTL2; + break; + case SDE_VSYNC_SOURCE_WD_TIMER_3: + wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_3_CTL; + wd_ctl2 = MDP_WD_TIMER_3_CTL2; + break; + case SDE_VSYNC_SOURCE_WD_TIMER_2: + wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_2_CTL; + wd_ctl2 = MDP_WD_TIMER_2_CTL2; + break; + case SDE_VSYNC_SOURCE_WD_TIMER_1: + wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_1_CTL; + wd_ctl2 = MDP_WD_TIMER_1_CTL2; + break; + case SDE_VSYNC_SOURCE_WD_TIMER_0: + default: + wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE; + wd_ctl = MDP_WD_TIMER_0_CTL; + wd_ctl2 = MDP_WD_TIMER_0_CTL2; + break; + } + + if (cfg->is_dummy) { + SDE_REG_WRITE(c, wd_ctl2, 0x0); + } else { + SDE_REG_WRITE(c, wd_load_value, + CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); + + SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */ + reg = SDE_REG_READ(c, wd_ctl2); + reg |= BIT(8); /* enable heartbeat timer */ + reg |= BIT(0); /* enable WD timer */ + SDE_REG_WRITE(c, wd_ctl2, reg); + } + + /* make sure that timers are enabled/disabled for vsync state */ + wmb(); + } +} + +static void sde_hw_setup_vsync_source(struct sde_hw_mdp *mdp, + struct sde_vsync_source_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 reg, i; + static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18}; + + if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber))) + return; + + c = &mdp->hw; + reg = SDE_REG_READ(c, MDP_VSYNC_SEL); + for (i = 0; i < cfg->pp_count; i++) { + int pp_idx = cfg->ppnumber[i] - PINGPONG_0; + + if (pp_idx >= ARRAY_SIZE(pp_offset)) + continue; + + reg &= ~(0xf << pp_offset[pp_idx]); + reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx]; + } + SDE_REG_WRITE(c, MDP_VSYNC_SEL, reg); + + _update_vsync_source(mdp, cfg); +} + +static void sde_hw_setup_vsync_source_v1(struct sde_hw_mdp *mdp, + struct sde_vsync_source_cfg *cfg) +{ + _update_vsync_source(mdp, cfg); +} + + +static void sde_hw_get_safe_status(struct sde_hw_mdp *mdp, + struct sde_danger_safe_status *status) +{ + struct sde_hw_blk_reg_map *c; + u32 value; + + if (!mdp || !status) + return; + + c = &mdp->hw; + + value = SDE_REG_READ(c, SAFE_STATUS); + status->mdp = (value >> 0) & 0x1; + status->sspp[SSPP_VIG0] = (value >> 4) & 0x1; + status->sspp[SSPP_VIG1] = (value >> 6) & 0x1; + status->sspp[SSPP_VIG2] = (value >> 8) & 0x1; + status->sspp[SSPP_VIG3] = (value >> 10) & 0x1; + status->sspp[SSPP_RGB0] = (value >> 12) & 0x1; + status->sspp[SSPP_RGB1] = (value >> 14) & 0x1; + status->sspp[SSPP_RGB2] = (value >> 16) & 0x1; + status->sspp[SSPP_RGB3] = (value >> 18) & 0x1; + status->sspp[SSPP_DMA0] = (value >> 20) & 0x1; + status->sspp[SSPP_DMA1] = (value >> 22) & 0x1; + status->sspp[SSPP_DMA2] = (value >> 28) & 0x1; + status->sspp[SSPP_DMA3] = (value >> 30) & 0x1; + status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1; + status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1; + status->wb[WB_0] = 0; + status->wb[WB_1] = 0; + status->wb[WB_2] = (value >> 2) & 0x1; + status->wb[WB_3] = 0; +} + +static void sde_hw_setup_dce(struct sde_hw_mdp *mdp, u32 dce_sel) +{ + struct sde_hw_blk_reg_map *c; + + if (!mdp) + return; + + c = &mdp->hw; + + SDE_REG_WRITE(c, DCE_SEL, dce_sel); +} + +void sde_hw_reset_ubwc(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m) +{ + struct sde_hw_blk_reg_map c; + u32 ubwc_version; + + if (!mdp || !m) + return; + + /* force blk offset to zero to access beginning of register region */ + c = mdp->hw; + c.blk_off = 0x0; + ubwc_version = SDE_REG_READ(&c, UBWC_DEC_HW_VERSION); + + if (IS_UBWC_40_SUPPORTED(ubwc_version)) { + u32 ver = 2; + u32 mode = 1; + u32 reg = (m->mdp[0].ubwc_swizzle & 0x7) | + ((m->mdp[0].ubwc_static & 0x1) << 3) | + ((m->mdp[0].highest_bank_bit & 0x7) << 4) | + ((m->macrotile_mode & 0x1) << 12); + + if (IS_UBWC_30_SUPPORTED(m->ubwc_version)) { + ver = 1; + mode = 0; + } + + SDE_REG_WRITE(&c, UBWC_STATIC, reg); + SDE_REG_WRITE(&c, UBWC_CTRL_2, ver); + SDE_REG_WRITE(&c, UBWC_PREDICTION_MODE, mode); + } else if (IS_UBWC_20_SUPPORTED(ubwc_version)) { + SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static); + } else if (IS_UBWC_30_SUPPORTED(ubwc_version)) { + u32 reg = m->mdp[0].ubwc_static | + (m->mdp[0].ubwc_swizzle & 0x1) | + ((m->mdp[0].highest_bank_bit & 0x3) << 4) | + ((m->macrotile_mode & 0x1) << 12); + + if (IS_UBWC_30_SUPPORTED(m->ubwc_version)) + reg |= BIT(10); + if (IS_UBWC_10_SUPPORTED(m->ubwc_version)) + reg |= BIT(8); + + SDE_REG_WRITE(&c, UBWC_STATIC, reg); + } else { + SDE_ERROR("Unsupported UBWC version 0x%08x\n", ubwc_version); + } +} + +static void sde_hw_intf_audio_select(struct sde_hw_mdp *mdp) +{ + struct sde_hw_blk_reg_map *c; + + if (!mdp) + return; + + c = &mdp->hw; + + SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1); +} + +static void sde_hw_mdp_events(struct sde_hw_mdp *mdp, bool enable) +{ + struct sde_hw_blk_reg_map *c; + + if (!mdp) + return; + + c = &mdp->hw; + + SDE_REG_WRITE(c, HW_EVENTS_CTL, enable); +} + +struct sde_hw_sid *sde_hw_sid_init(void __iomem *addr, + u32 sid_len, const struct sde_mdss_cfg *m) +{ + struct sde_hw_sid *c; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + c->hw.base_off = addr; + c->hw.blk_off = 0; + c->hw.length = sid_len; + c->hw.hwversion = m->hwversion; + c->hw.log_mask = SDE_DBG_MASK_SID; + + return c; +} + +void sde_hw_sid_rotator_set(struct sde_hw_sid *sid) +{ + SDE_REG_WRITE(&sid->hw, ROT_SID_RD, ROT_SID_ID_VAL); + SDE_REG_WRITE(&sid->hw, ROT_SID_WR, ROT_SID_ID_VAL); +} + +static void sde_hw_program_cwb_ppb_ctrl(struct sde_hw_mdp *mdp, + bool dual, bool dspp_out) +{ + u32 value = dspp_out ? 0x4 : 0x0; + + SDE_REG_WRITE(&mdp->hw, PPB2_CNTL, value); + if (dual) { + value |= 0x1; + SDE_REG_WRITE(&mdp->hw, PPB3_CNTL, value); + } +} + +static void sde_hw_set_hdr_plus_metadata(struct sde_hw_mdp *mdp, + u8 *payload, u32 len, u32 stream_id) +{ + u32 i; + size_t length = len - 1; + u32 offset = 0, data = 0, byte_idx = 0; + const u32 dword_size = sizeof(u32); + + if (!payload || !len) { + SDE_ERROR("invalid payload with length: %d\n", len); + return; + } + + if (stream_id) + offset = DP_DHDR_MEM_POOL_1_DATA - DP_DHDR_MEM_POOL_0_DATA; + + /* payload[0] is set in VSCEXT header byte 1, skip programming here */ + SDE_REG_WRITE(&mdp->hw, DP_DHDR_MEM_POOL_0_NUM_BYTES + offset, length); + for (i = 1; i < len; i++) { + if (byte_idx && !(byte_idx % dword_size)) { + SDE_REG_WRITE(&mdp->hw, DP_DHDR_MEM_POOL_0_DATA + + offset, data); + data = 0; + } + + data |= payload[i] << (8 * (byte_idx++ % dword_size)); + } + + SDE_REG_WRITE(&mdp->hw, DP_DHDR_MEM_POOL_0_DATA + offset, data); +} + +static u32 sde_hw_get_autorefresh_status(struct sde_hw_mdp *mdp, u32 intf_idx) +{ + struct sde_hw_blk_reg_map *c; + u32 autorefresh_status; + u32 blk_id = (intf_idx == INTF_2) ? 65 : 64; + + if (!mdp) + return 0; + + c = &mdp->hw; + + SDE_REG_WRITE(&mdp->hw, MDP_PERIPH_DBGBUS_CTRL, + TEST_MASK(blk_id, AUTOREFRESH_TEST_POINT)); + SDE_REG_WRITE(&mdp->hw, MDP_DSPP_DBGBUS_CTRL, 0x7001); + wmb(); /* make sure test bits were written */ + + autorefresh_status = SDE_REG_READ(&mdp->hw, MDP_DSPP_DBGBUS_STATUS); + SDE_REG_WRITE(&mdp->hw, MDP_PERIPH_DBGBUS_CTRL, 0x0); + + return autorefresh_status; +} + +static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, + unsigned long cap) +{ + ops->setup_split_pipe = sde_hw_setup_split_pipe; + ops->setup_pp_split = sde_hw_setup_pp_split; + ops->setup_cdm_output = sde_hw_setup_cdm_output; + ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl; + ops->get_danger_status = sde_hw_get_danger_status; + ops->setup_vsync_source = sde_hw_setup_vsync_source; + ops->set_cwb_ppb_cntl = sde_hw_program_cwb_ppb_ctrl; + ops->get_safe_status = sde_hw_get_safe_status; + ops->get_split_flush_status = sde_hw_get_split_flush; + ops->setup_dce = sde_hw_setup_dce; + ops->reset_ubwc = sde_hw_reset_ubwc; + ops->intf_audio_select = sde_hw_intf_audio_select; + ops->set_mdp_hw_events = sde_hw_mdp_events; + if (cap & BIT(SDE_MDP_VSYNC_SEL)) + ops->setup_vsync_source = sde_hw_setup_vsync_source; + else + ops->setup_vsync_source = sde_hw_setup_vsync_source_v1; + if (cap & BIT(SDE_MDP_DHDR_MEMPOOL)) + ops->set_hdr_plus_metadata = sde_hw_set_hdr_plus_metadata; + ops->get_autorefresh_status = sde_hw_get_autorefresh_status; +} + +static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp, + const struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + if (!m || !addr || !b) + return ERR_PTR(-EINVAL); + + for (i = 0; i < m->mdp_count; i++) { + if (mdp == m->mdp[i].id) { + b->base_off = addr; + b->blk_off = m->mdp[i].base; + b->length = m->mdp[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_TOP; + return &m->mdp[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, + void __iomem *addr, + const struct sde_mdss_cfg *m) +{ + struct sde_hw_mdp *mdp; + const struct sde_mdp_cfg *cfg; + int rc; + + if (!addr || !m) + return ERR_PTR(-EINVAL); + + mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); + if (!mdp) + return ERR_PTR(-ENOMEM); + + cfg = _top_offset(idx, m, addr, &mdp->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(mdp); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + mdp->idx = idx; + mdp->caps = cfg; + _setup_mdp_ops(&mdp->ops, mdp->caps->features); + + rc = sde_hw_blk_init(&mdp->base, SDE_HW_BLK_TOP, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, + mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length, + mdp->hw.xin_id); + sde_dbg_set_sde_top_offset(mdp->hw.blk_off); + + return mdp; + +blk_init_error: + kzfree(mdp); + + return ERR_PTR(rc); +} + +void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp) +{ + if (mdp) + sde_hw_blk_destroy(&mdp->base); + kfree(mdp); +} + diff --git a/techpack/display/msm/sde/sde_hw_top.h b/techpack/display/msm/sde/sde_hw_top.h new file mode 100644 index 0000000000000000000000000000000000000000..21f1daf1098f818a87461c97f6117c8eec8218c5 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_top.h @@ -0,0 +1,282 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_TOP_H +#define _SDE_HW_TOP_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" +#include "sde_hw_blk.h" + +struct sde_hw_mdp; + +/** + * struct traffic_shaper_cfg: traffic shaper configuration + * @en : enable/disable traffic shaper + * @rd_client : true if read client; false if write client + * @client_id : client identifier + * @bpc_denom : denominator of byte per clk + * @bpc_numer : numerator of byte per clk + */ +struct traffic_shaper_cfg { + bool en; + bool rd_client; + u32 client_id; + u32 bpc_denom; + u64 bpc_numer; +}; + +/** + * struct split_pipe_cfg - pipe configuration for dual display panels + * @en : Enable/disable dual pipe confguration + * @mode : Panel interface mode + * @intf : Interface id for main control path + * @pp_split_slave: Slave interface for ping pong split, INTF_MAX to disable + * @pp_split_idx: Ping pong index for ping pong split + * @split_flush_en: Allows both the paths to be flushed when master path is + * flushed + * @split_link_en: Check if split link is enabled + */ +struct split_pipe_cfg { + bool en; + enum sde_intf_mode mode; + enum sde_intf intf; + enum sde_intf pp_split_slave; + u32 pp_split_index; + bool split_flush_en; + bool split_link_en; +}; + +/** + * struct cdm_output_cfg: output configuration for cdm + * @wb_en : enable/disable writeback output + * @intf_en : enable/disable interface output + */ +struct cdm_output_cfg { + bool wb_en; + bool intf_en; +}; + +/** + * struct sde_danger_safe_status: danger and safe status signals + * @mdp: top level status + * @sspp: source pipe status + * @wb: writebck output status + */ +struct sde_danger_safe_status { + u8 mdp; + u8 sspp[SSPP_MAX]; + u8 wb[WB_MAX]; +}; + +/** + * struct sde_vsync_source_cfg - configure vsync source and configure the + * watchdog timers if required. + * @pp_count: number of ping pongs active + * @frame_rate: Display frame rate + * @ppnumber: ping pong index array + * @vsync_source: vsync source selection + * @is_dummy: a dummy source of vsync selection. It must not be selected for + * any case other than sde rsc idle request. + */ +struct sde_vsync_source_cfg { + u32 pp_count; + u32 frame_rate; + u32 ppnumber[PINGPONG_MAX]; + u32 vsync_source; + bool is_dummy; +}; + +/** + * struct sde_hw_mdp_ops - interface to the MDP TOP Hw driver functions + * Assumption is these functions will be called after clocks are enabled. + * @setup_split_pipe : Programs the pipe control registers + * @setup_pp_split : Programs the pp split control registers + * @setup_cdm_output : programs cdm control + * @setup_traffic_shaper : programs traffic shaper control + */ +struct sde_hw_mdp_ops { + /** setup_split_pipe() : Regsiters are not double buffered, thisk + * function should be called before timing control enable + * @mdp : mdp top context driver + * @cfg : upper and lower part of pipe configuration + */ + void (*setup_split_pipe)(struct sde_hw_mdp *mdp, + struct split_pipe_cfg *p); + + /** setup_pp_split() : Configure pp split related registers + * @mdp : mdp top context driver + * @cfg : upper and lower part of pipe configuration + */ + void (*setup_pp_split)(struct sde_hw_mdp *mdp, + struct split_pipe_cfg *cfg); + + /** + * setup_cdm_output() : Setup selection control of the cdm data path + * @mdp : mdp top context driver + * @cfg : cdm output configuration + */ + void (*setup_cdm_output)(struct sde_hw_mdp *mdp, + struct cdm_output_cfg *cfg); + + /** + * setup_traffic_shaper() : Setup traffic shaper control + * @mdp : mdp top context driver + * @cfg : traffic shaper configuration + */ + void (*setup_traffic_shaper)(struct sde_hw_mdp *mdp, + struct traffic_shaper_cfg *cfg); + + /** + * setup_clk_force_ctrl - set clock force control + * @mdp: mdp top context driver + * @clk_ctrl: clock to be controlled + * @enable: force on enable + * @return: if the clock is forced-on by this function + */ + bool (*setup_clk_force_ctrl)(struct sde_hw_mdp *mdp, + enum sde_clk_ctrl_type clk_ctrl, bool enable); + + /** + * setup_dce - set DCE mux for DSC ctrl path + * @mdp: mdp top context driver + * @dce_sel: dce_mux value + */ + void (*setup_dce)(struct sde_hw_mdp *mdp, u32 dce_sel); + + /** + * get_danger_status - get danger status + * @mdp: mdp top context driver + * @status: Pointer to danger safe status + */ + void (*get_danger_status)(struct sde_hw_mdp *mdp, + struct sde_danger_safe_status *status); + + /** + * setup_vsync_source - setup vsync source configuration details + * @mdp: mdp top context driver + * @cfg: vsync source selection configuration + */ + void (*setup_vsync_source)(struct sde_hw_mdp *mdp, + struct sde_vsync_source_cfg *cfg); + + /** + * get_safe_status - get safe status + * @mdp: mdp top context driver + * @status: Pointer to danger safe status + */ + void (*get_safe_status)(struct sde_hw_mdp *mdp, + struct sde_danger_safe_status *status); + + /** + * get_split_flush_status - get split flush status + * @mdp: mdp top context driver + */ + u32 (*get_split_flush_status)(struct sde_hw_mdp *mdp); + + /** + * reset_ubwc - reset top level UBWC configuration + * @mdp: mdp top context driver + * @m: pointer to mdss catalog data + */ + void (*reset_ubwc)(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m); + + /** + * intf_audio_select - select the external interface for audio + * @mdp: mdp top context driver + */ + void (*intf_audio_select)(struct sde_hw_mdp *mdp); + + /** + * set_mdp_hw_events - enable qdss hardware events for mdp + * @mdp: mdp top context driver + * @enable: enable/disable hw events + */ + void (*set_mdp_hw_events)(struct sde_hw_mdp *mdp, bool enable); + + /** + * set_cwb_ppb_cntl - select the data point for CWB + * @mdp: mdp top context driver + * @dual: indicates if dual pipe line needs to be programmed + * @dspp_out : true if dspp output required. LM is default tap point + */ + void (*set_cwb_ppb_cntl)(struct sde_hw_mdp *mdp, + bool dual, bool dspp_out); + + /** + * set_hdr_plus_metadata - program the dynamic hdr metadata + * @mdp: mdp top context driver + * @payload: pointer to payload data + * @len: size of the valid data within payload + * @stream_id: stream ID for MST (0 or 1) + */ + void (*set_hdr_plus_metadata)(struct sde_hw_mdp *mdp, + u8 *payload, u32 len, u32 stream_id); + + /** + * get_autorefresh_status - get autorefresh status + * @mdp: mdp top context driver + * @intf_idx: intf block index for relative information + */ + u32 (*get_autorefresh_status)(struct sde_hw_mdp *mdp, + u32 intf_idx); +}; + +struct sde_hw_mdp { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + + /* top */ + enum sde_mdp idx; + const struct sde_mdp_cfg *caps; + + /* ops */ + struct sde_hw_mdp_ops ops; +}; + +struct sde_hw_sid { + /* rotator base */ + struct sde_hw_blk_reg_map hw; +}; + +/** + * sde_hw_sid_rotator_set - initialize the sid blk reg map + * @addr: Mapped register io address + * @sid_len: Length of block + * @m: Pointer to mdss catalog data + */ +struct sde_hw_sid *sde_hw_sid_init(void __iomem *addr, + u32 sid_len, const struct sde_mdss_cfg *m); + +/** + * sde_hw_sid_rotator_set - set sid values for rotator + * sid: sde_hw_sid passed from kms + */ +void sde_hw_sid_rotator_set(struct sde_hw_sid *sid); + +/** + * to_sde_hw_mdp - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_mdp *to_sde_hw_mdp(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_mdp, base); +} + +/** + * sde_hw_mdptop_init - initializes the top driver for the passed idx + * @idx: Interface index for which driver object is required + * @addr: Mapped register io address of MDP + * @m: Pointer to mdss catalog data + */ +struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx, + void __iomem *addr, + const struct sde_mdss_cfg *m); + +void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp); + +#endif /*_SDE_HW_TOP_H */ diff --git a/techpack/display/msm/sde/sde_hw_uidle.c b/techpack/display/msm/sde/sde_hw_uidle.c new file mode 100644 index 0000000000000000000000000000000000000000..f1a8a8b1f78e0ad9fbd021215041808077802b74 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_uidle.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + */ + +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_top.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define UIDLE_CTL 0x0 +#define UIDLE_STATUS 0x4 +#define UIDLE_FAL10_VETO_OVERRIDE 0x8 + +#define UIDLE_WD_TIMER_CTL 0x10 +#define UIDLE_WD_TIMER_CTL2 0x14 +#define UIDLE_WD_TIMER_LOAD_VALUE 0x18 + +#define UIDLE_DANGER_STATUS_0 0x20 +#define UIDLE_DANGER_STATUS_1 0x24 +#define UIDLE_SAFE_STATUS_0 0x30 +#define UIDLE_SAFE_STATUS_1 0x34 +#define UIDLE_IDLE_STATUS_0 0x38 +#define UIDLE_IDLE_STATUS_1 0x3c +#define UIDLE_FAL_STATUS_0 0x40 +#define UIDLE_FAL_STATUS_1 0x44 + +#define UIDLE_GATE_CNTR_CTL 0x50 +#define UIDLE_FAL1_GATE_CNTR 0x54 +#define UIDLE_FAL10_GATE_CNTR 0x58 +#define UIDLE_FAL_WAIT_GATE_CNTR 0x5c +#define UIDLE_FAL1_NUM_TRANSITIONS_CNTR 0x60 +#define UIDLE_FAL10_NUM_TRANSITIONS_CNTR 0x64 +#define UIDLE_MIN_GATE_CNTR 0x68 +#define UIDLE_MAX_GATE_CNTR 0x6c + +static const struct sde_uidle_cfg *_top_offset(enum sde_uidle uidle, + struct sde_mdss_cfg *m, void __iomem *addr, + unsigned long len, struct sde_hw_blk_reg_map *b) +{ + + /* Make sure length of regs offsets is within the mapped memory */ + if ((uidle == m->uidle_cfg.id) && + (m->uidle_cfg.base + m->uidle_cfg.len) < len) { + + b->base_off = addr; + b->blk_off = m->uidle_cfg.base; + b->length = m->uidle_cfg.len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_UIDLE; + SDE_DEBUG("base:0x%p blk_off:0x%x length:%d hwversion:0x%x\n", + b->base_off, b->blk_off, b->length, b->hwversion); + return &m->uidle_cfg; + } + + SDE_ERROR("wrong uidle mapping params, will disable UIDLE!\n"); + SDE_ERROR("base_off:0x%pK id:%d base:0x%x len:%d mmio_len:%ld\n", + addr, m->uidle_cfg.id, m->uidle_cfg.base, + m->uidle_cfg.len, len); + m->uidle_cfg.uidle_rev = 0; + + return ERR_PTR(-EINVAL); +} + +void sde_hw_uidle_get_status(struct sde_hw_uidle *uidle, + struct sde_uidle_status *status) +{ + struct sde_hw_blk_reg_map *c = &uidle->hw; + + status->uidle_danger_status_0 = + SDE_REG_READ(c, UIDLE_DANGER_STATUS_0); + status->uidle_danger_status_1 = + SDE_REG_READ(c, UIDLE_DANGER_STATUS_1); + status->uidle_safe_status_0 = + SDE_REG_READ(c, UIDLE_SAFE_STATUS_0); + status->uidle_safe_status_1 = + SDE_REG_READ(c, UIDLE_SAFE_STATUS_1); + status->uidle_idle_status_0 = + SDE_REG_READ(c, UIDLE_IDLE_STATUS_0); + status->uidle_idle_status_1 = + SDE_REG_READ(c, UIDLE_IDLE_STATUS_1); + status->uidle_fal_status_0 = + SDE_REG_READ(c, UIDLE_FAL_STATUS_0); + status->uidle_fal_status_1 = + SDE_REG_READ(c, UIDLE_FAL_STATUS_1); + + status->uidle_status = + SDE_REG_READ(c, UIDLE_STATUS); + status->uidle_en_fal10 = + (status->uidle_status & BIT(2)) ? 1 : 0; +} + +void sde_hw_uidle_get_cntr(struct sde_hw_uidle *uidle, + struct sde_uidle_cntr *cntr) +{ + struct sde_hw_blk_reg_map *c = &uidle->hw; + u32 reg_val; + + cntr->fal1_gate_cntr = + SDE_REG_READ(c, UIDLE_FAL1_GATE_CNTR); + cntr->fal10_gate_cntr = + SDE_REG_READ(c, UIDLE_FAL10_GATE_CNTR); + cntr->fal_wait_gate_cntr = + SDE_REG_READ(c, UIDLE_FAL_WAIT_GATE_CNTR); + cntr->fal1_num_transitions_cntr = + SDE_REG_READ(c, UIDLE_FAL1_NUM_TRANSITIONS_CNTR); + cntr->fal10_num_transitions_cntr = + SDE_REG_READ(c, UIDLE_FAL10_NUM_TRANSITIONS_CNTR); + cntr->min_gate_cntr = + SDE_REG_READ(c, UIDLE_MIN_GATE_CNTR); + cntr->max_gate_cntr = + SDE_REG_READ(c, UIDLE_MAX_GATE_CNTR); + + /* clear counters after read */ + reg_val = SDE_REG_READ(c, UIDLE_GATE_CNTR_CTL); + reg_val = reg_val | BIT(31); + SDE_REG_WRITE(c, UIDLE_GATE_CNTR_CTL, reg_val); + reg_val = (reg_val & ~BIT(31)); + SDE_REG_WRITE(c, UIDLE_GATE_CNTR_CTL, reg_val); +} + +void sde_hw_uidle_setup_cntr(struct sde_hw_uidle *uidle, bool enable) +{ + struct sde_hw_blk_reg_map *c = &uidle->hw; + u32 reg_val; + + reg_val = SDE_REG_READ(c, UIDLE_GATE_CNTR_CTL); + reg_val = (reg_val & ~BIT(8)) | (enable ? BIT(8) : 0); + + SDE_REG_WRITE(c, UIDLE_GATE_CNTR_CTL, reg_val); +} + +void sde_hw_uidle_setup_wd_timer(struct sde_hw_uidle *uidle, + struct sde_uidle_wd_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c = &uidle->hw; + u32 val_ctl, val_ctl2, val_ld; + + val_ctl = SDE_REG_READ(c, UIDLE_WD_TIMER_CTL); + val_ctl2 = SDE_REG_READ(c, UIDLE_WD_TIMER_CTL2); + val_ld = SDE_REG_READ(c, UIDLE_WD_TIMER_LOAD_VALUE); + + val_ctl = (val_ctl & ~BIT(0)) | (cfg->clear ? BIT(0) : 0); + + val_ctl2 = (val_ctl2 & ~BIT(0)) | (cfg->enable ? BIT(0) : 0); + val_ctl2 = (val_ctl2 & ~GENMASK(4, 1)) | + ((cfg->granularity & 0xF) << 1); + val_ctl2 = (val_ctl2 & ~BIT(8)) | (cfg->heart_beat ? BIT(8) : 0); + + val_ld = cfg->load_value; + + SDE_REG_WRITE(c, UIDLE_WD_TIMER_CTL, val_ctl); + SDE_REG_WRITE(c, UIDLE_WD_TIMER_CTL2, val_ctl2); + SDE_REG_WRITE(c, UIDLE_WD_TIMER_LOAD_VALUE, val_ld); +} + +void sde_hw_uidle_setup_ctl(struct sde_hw_uidle *uidle, + struct sde_uidle_ctl_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c = &uidle->hw; + u32 reg_val; + + reg_val = SDE_REG_READ(c, UIDLE_CTL); + reg_val = (reg_val & ~BIT(31)) | (cfg->uidle_enable ? BIT(31) : 0); + reg_val = (reg_val & ~FAL10_DANGER_MSK) | + ((cfg->fal10_danger << FAL10_DANGER_SHFT) & + FAL10_DANGER_MSK); + reg_val = (reg_val & ~FAL10_EXIT_DANGER_MSK) | + ((cfg->fal10_exit_danger << FAL10_EXIT_DANGER_SHFT) & + FAL10_EXIT_DANGER_MSK); + reg_val = (reg_val & ~FAL10_EXIT_CNT_MSK) | + ((cfg->fal10_exit_cnt << FAL10_EXIT_CNT_SHFT) & + FAL10_EXIT_CNT_MSK); + + SDE_REG_WRITE(c, UIDLE_CTL, reg_val); +} + +static inline void _setup_uidle_ops(struct sde_hw_uidle_ops *ops, + unsigned long cap) +{ + ops->set_uidle_ctl = sde_hw_uidle_setup_ctl; + ops->setup_wd_timer = sde_hw_uidle_setup_wd_timer; + ops->uidle_setup_cntr = sde_hw_uidle_setup_cntr; + ops->uidle_get_cntr = sde_hw_uidle_get_cntr; + ops->uidle_get_status = sde_hw_uidle_get_status; +} + +struct sde_hw_uidle *sde_hw_uidle_init(enum sde_uidle idx, + void __iomem *addr, unsigned long len, + struct sde_mdss_cfg *m) +{ + struct sde_hw_uidle *c; + const struct sde_uidle_cfg *cfg; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _top_offset(idx, m, addr, len, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + c->idx = idx; + c->cap = cfg; + _setup_uidle_ops(&c->ops, c->cap->features); + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "uidle", c->hw.blk_off, + c->hw.blk_off + c->hw.length, 0); + + return c; +} + diff --git a/techpack/display/msm/sde/sde_hw_uidle.h b/techpack/display/msm/sde/sde_hw_uidle.h new file mode 100644 index 0000000000000000000000000000000000000000..a0b692b83e7eb26e7e6cd6d942b62f61a01eff48 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_uidle.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + */ + +#ifndef _SDE_HW_UIDLE_H +#define _SDE_HW_UIDLE_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" + +struct sde_hw_uidle; + +#define FAL10_DANGER_SHFT 0 +#define FAL10_EXIT_DANGER_SHFT 4 +#define FAL10_EXIT_CNT_SHFT 16 + +#define FAL10_DANGER_MSK GENMASK(2, FAL10_DANGER_SHFT) +#define FAL10_EXIT_DANGER_MSK GENMASK(6, FAL10_EXIT_DANGER_SHFT) +#define FAL10_EXIT_CNT_MSK GENMASK(23, FAL10_EXIT_CNT_SHFT) + +#define SDE_UIDLE_WD_GRANULARITY 1 +#define SDE_UIDLE_WD_HEART_BEAT 0 +#define SDE_UIDLE_WD_LOAD_VAL 12 + +struct sde_uidle_ctl_cfg { + u32 fal10_exit_cnt; + u32 fal10_exit_danger; + u32 fal10_danger; + bool uidle_enable; +}; + +struct sde_uidle_wd_cfg { + u32 granularity; + u32 heart_beat; + u32 load_value; + bool clear; + bool enable; +}; + +struct sde_uidle_cntr { + u32 fal1_gate_cntr; + u32 fal10_gate_cntr; + u32 fal_wait_gate_cntr; + u32 fal1_num_transitions_cntr; + u32 fal10_num_transitions_cntr; + u32 min_gate_cntr; + u32 max_gate_cntr; +}; + +struct sde_uidle_status { + u32 uidle_danger_status_0; + u32 uidle_danger_status_1; + u32 uidle_safe_status_0; + u32 uidle_safe_status_1; + u32 uidle_idle_status_0; + u32 uidle_idle_status_1; + u32 uidle_fal_status_0; + u32 uidle_fal_status_1; + u32 uidle_status; + u32 uidle_en_fal10; +}; + +struct sde_hw_uidle_ops { + /** + * set_uidle_ctl - set uidle global config + * @uidle: uidle context driver + * @cfg: uidle global config + */ + void (*set_uidle_ctl)(struct sde_hw_uidle *uidle, + struct sde_uidle_ctl_cfg *cfg); + + /** + * setup_wd_timer - set uidle watchdog timer + * @uidle: uidle context driver + * @cfg: uidle wd timer config + */ + void (*setup_wd_timer)(struct sde_hw_uidle *uidle, + struct sde_uidle_wd_cfg *cfg); + + /** + * uidle_setup_cntr - set uidle perf counters + * @uidle: uidle context driver + * @enable: true to enable the counters + */ + void (*uidle_setup_cntr)(struct sde_hw_uidle *uidle, + bool enable); + + /** + * uidle_get_cntr - get uidle perf counters + * @uidle: uidle context driver + * @cntr: pointer to return the counters + */ + void (*uidle_get_cntr)(struct sde_hw_uidle *uidle, + struct sde_uidle_cntr *cntr); + + /** + * uidle_get_status - get uidle status + * @uidle: uidle context driver + * @status: pointer to return the status of uidle + */ + void (*uidle_get_status)(struct sde_hw_uidle *uidle, + struct sde_uidle_status *status); + +}; + +struct sde_hw_uidle { + /* base */ + struct sde_hw_blk_reg_map hw; + + /* uidle */ + const struct sde_uidle_cfg *cap; + + /* ops */ + struct sde_hw_uidle_ops ops; + + /* + * uidle is common across all displays, lock to serialize access. + * must be taken by client before using any ops + */ + struct mutex uidle_lock; + + enum sde_uidle idx; +}; + +struct sde_hw_uidle *sde_hw_uidle_init(enum sde_uidle idx, + void __iomem *addr, unsigned long len, + struct sde_mdss_cfg *m); + +#endif /*_SDE_HW_UIDLE_H */ diff --git a/techpack/display/msm/sde/sde_hw_util.c b/techpack/display/msm/sde/sde_hw_util.c new file mode 100644 index 0000000000000000000000000000000000000000..ff4b5dfd08f0981c90d4d83570829d1243e46cf7 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_util.c @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <uapi/drm/sde_drm.h> +#include "msm_drv.h" +#include "sde_kms.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" + +/* using a file static variables for debugfs access */ +static u32 sde_hw_util_log_mask = SDE_DBG_MASK_NONE; + +/* SDE_SCALER_QSEED3 */ +#define QSEED3_HW_VERSION 0x00 +#define QSEED3_OP_MODE 0x04 +#define QSEED3_RGB2Y_COEFF 0x08 +#define QSEED3_PHASE_INIT 0x0C +#define QSEED3_PHASE_STEP_Y_H 0x10 +#define QSEED3_PHASE_STEP_Y_V 0x14 +#define QSEED3_PHASE_STEP_UV_H 0x18 +#define QSEED3_PHASE_STEP_UV_V 0x1C +#define QSEED3_PRELOAD 0x20 +#define QSEED3_DE_SHARPEN 0x24 +#define QSEED3_DE_SHARPEN_CTL 0x28 +#define QSEED3_DE_SHAPE_CTL 0x2C +#define QSEED3_DE_THRESHOLD 0x30 +#define QSEED3_DE_ADJUST_DATA_0 0x34 +#define QSEED3_DE_ADJUST_DATA_1 0x38 +#define QSEED3_DE_ADJUST_DATA_2 0x3C +#define QSEED3_SRC_SIZE_Y_RGB_A 0x40 +#define QSEED3_SRC_SIZE_UV 0x44 +#define QSEED3_DST_SIZE 0x48 +#define QSEED3_COEF_LUT_CTRL 0x4C +#define QSEED3_COEF_LUT_SWAP_BIT 0 +#define QSEED3_BUFFER_CTRL 0x50 +#define QSEED3_CLK_CTRL0 0x54 +#define QSEED3_CLK_CTRL1 0x58 +#define QSEED3_CLK_STATUS 0x5C +#define QSEED3_MISR_CTRL 0x70 +#define QSEED3_MISR_SIGNATURE_0 0x74 +#define QSEED3_MISR_SIGNATURE_1 0x78 +#define QSEED3_PHASE_INIT_Y_H 0x90 +#define QSEED3_PHASE_INIT_Y_V 0x94 +#define QSEED3_PHASE_INIT_UV_H 0x98 +#define QSEED3_PHASE_INIT_UV_V 0x9C +#define QSEED3_ENABLE 2 +#define CSC_MATRIX_SHIFT 7 + +/* SDE_SCALER_QSEED3LITE */ +#define QSEED3L_COEF_LUT_Y_SEP_BIT 4 +#define QSEED3L_COEF_LUT_UV_SEP_BIT 5 +#define QSEED3L_COEF_LUT_CTRL 0x4C +#define QSEED3L_COEF_LUT_SWAP_BIT 0 +#define QSEED3L_DIR_FILTER_WEIGHT 0x60 +#define QSEED3LITE_SCALER_VERSION 0x2004 +#define QSEED4_SCALER_VERSION 0x3000 + +#define QSEED3_DEFAULT_PRELOAD_V 0x3 +#define QSEED3_DEFAULT_PRELOAD_H 0x4 + +#define QSEED4_DEFAULT_PRELOAD_V 0x2 +#define QSEED4_DEFAULT_PRELOAD_H 0x4 + +typedef void (*scaler_lut_type)(struct sde_hw_blk_reg_map *, + struct sde_hw_scaler3_cfg *, u32); + +void sde_reg_write(struct sde_hw_blk_reg_map *c, + u32 reg_off, + u32 val, + const char *name) +{ + /* don't need to mutex protect this */ + if (c->log_mask & sde_hw_util_log_mask) + SDE_DEBUG_DRIVER("[%s:0x%X] <= 0x%X\n", + name, c->blk_off + reg_off, val); + writel_relaxed(val, c->base_off + c->blk_off + reg_off); +} + +int sde_reg_read(struct sde_hw_blk_reg_map *c, u32 reg_off) +{ + return readl_relaxed(c->base_off + c->blk_off + reg_off); +} + +u32 *sde_hw_util_get_log_mask_ptr(void) +{ + return &sde_hw_util_log_mask; +} + +void sde_init_scaler_blk(struct sde_scaler_blk *blk, u32 version) +{ + if (!blk) + return; + + blk->version = version; + blk->v_preload = QSEED4_DEFAULT_PRELOAD_V; + blk->h_preload = QSEED4_DEFAULT_PRELOAD_H; + if (version < QSEED4_SCALER_VERSION) { + blk->v_preload = QSEED3_DEFAULT_PRELOAD_V; + blk->h_preload = QSEED3_DEFAULT_PRELOAD_H; + } +} +void sde_set_scaler_v2(struct sde_hw_scaler3_cfg *cfg, + const struct sde_drm_scaler_v2 *scale_v2) +{ + int i; + + cfg->enable = scale_v2->enable; + cfg->dir_en = scale_v2->dir_en; + + for (i = 0; i < SDE_MAX_PLANES; i++) { + cfg->init_phase_x[i] = scale_v2->init_phase_x[i]; + cfg->phase_step_x[i] = scale_v2->phase_step_x[i]; + cfg->init_phase_y[i] = scale_v2->init_phase_y[i]; + cfg->phase_step_y[i] = scale_v2->phase_step_y[i]; + + cfg->preload_x[i] = scale_v2->preload_x[i]; + cfg->preload_y[i] = scale_v2->preload_y[i]; + cfg->src_width[i] = scale_v2->src_width[i]; + cfg->src_height[i] = scale_v2->src_height[i]; + } + + cfg->dst_width = scale_v2->dst_width; + cfg->dst_height = scale_v2->dst_height; + + cfg->y_rgb_filter_cfg = scale_v2->y_rgb_filter_cfg; + cfg->uv_filter_cfg = scale_v2->uv_filter_cfg; + cfg->alpha_filter_cfg = scale_v2->alpha_filter_cfg; + cfg->blend_cfg = scale_v2->blend_cfg; + + cfg->lut_flag = scale_v2->lut_flag; + cfg->dir_lut_idx = scale_v2->dir_lut_idx; + cfg->y_rgb_cir_lut_idx = scale_v2->y_rgb_cir_lut_idx; + cfg->uv_cir_lut_idx = scale_v2->uv_cir_lut_idx; + cfg->y_rgb_sep_lut_idx = scale_v2->y_rgb_sep_lut_idx; + cfg->uv_sep_lut_idx = scale_v2->uv_sep_lut_idx; + cfg->de.prec_shift = scale_v2->de.prec_shift; + cfg->dir_weight = scale_v2->dir_weight; + cfg->dyn_exp_disabled = (scale_v2->flags & SDE_DYN_EXP_DISABLE) ? 1 : 0; + + cfg->de.enable = scale_v2->de.enable; + cfg->de.sharpen_level1 = scale_v2->de.sharpen_level1; + cfg->de.sharpen_level2 = scale_v2->de.sharpen_level2; + cfg->de.clip = scale_v2->de.clip; + cfg->de.limit = scale_v2->de.limit; + cfg->de.thr_quiet = scale_v2->de.thr_quiet; + cfg->de.thr_dieout = scale_v2->de.thr_dieout; + cfg->de.thr_low = scale_v2->de.thr_low; + cfg->de.thr_high = scale_v2->de.thr_high; + cfg->de.blend = scale_v2->de_blend; + + for (i = 0; i < SDE_MAX_DE_CURVES; i++) { + cfg->de.adjust_a[i] = scale_v2->de.adjust_a[i]; + cfg->de.adjust_b[i] = scale_v2->de.adjust_b[i]; + cfg->de.adjust_c[i] = scale_v2->de.adjust_c[i]; + } +} + +static void _sde_hw_setup_scaler3_lut(struct sde_hw_blk_reg_map *c, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset) +{ + int i, j, filter; + int config_lut = 0x0; + unsigned long lut_flags; + u32 lut_addr, lut_offset, lut_len; + u32 *lut[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL}; + static const uint32_t off_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = { + {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} }, + {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} }, + {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} }, + {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} }, + {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} }, + }; + + lut_flags = (unsigned long) scaler3_cfg->lut_flag; + if (test_bit(QSEED3_COEF_LUT_DIR_BIT, &lut_flags) && + (scaler3_cfg->dir_len == QSEED3_DIR_LUT_SIZE)) { + lut[0] = scaler3_cfg->dir_lut; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_Y_CIR_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && + (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { + lut[1] = scaler3_cfg->cir_lut + + scaler3_cfg->y_rgb_cir_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_UV_CIR_BIT, &lut_flags) && + (scaler3_cfg->uv_cir_lut_idx < QSEED3_CIRCULAR_LUTS) && + (scaler3_cfg->cir_len == QSEED3_CIR_LUT_SIZE)) { + lut[2] = scaler3_cfg->cir_lut + + scaler3_cfg->uv_cir_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_Y_SEP_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { + lut[3] = scaler3_cfg->sep_lut + + scaler3_cfg->y_rgb_sep_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3_COEF_LUT_UV_SEP_BIT, &lut_flags) && + (scaler3_cfg->uv_sep_lut_idx < QSEED3_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3_SEP_LUT_SIZE)) { + lut[4] = scaler3_cfg->sep_lut + + scaler3_cfg->uv_sep_lut_idx * QSEED3_LUT_SIZE; + config_lut = 1; + } + + if (config_lut) { + for (filter = 0; filter < QSEED3_FILTERS; filter++) { + if (!lut[filter]) + continue; + lut_offset = 0; + for (i = 0; i < QSEED3_LUT_REGIONS; i++) { + lut_addr = QSEED3_COEF_LUT_OFF + offset + + off_tbl[filter][i][1]; + lut_len = off_tbl[filter][i][0] << 2; + for (j = 0; j < lut_len; j++) { + SDE_REG_WRITE(c, + lut_addr, + (lut[filter])[lut_offset++]); + lut_addr += 4; + } + } + } + } + + if (test_bit(QSEED3_COEF_LUT_SWAP_BIT, &lut_flags)) + SDE_REG_WRITE(c, QSEED3_COEF_LUT_CTRL + offset, BIT(0)); + +} + +static void _sde_hw_setup_scaler3lite_lut(struct sde_hw_blk_reg_map *c, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 offset) +{ + int i, filter; + int config_lut = 0x0; + unsigned long lut_flags; + u32 lut_addr, lut_offset; + u32 *lut[QSEED3LITE_FILTERS] = {NULL, NULL}; + static const uint32_t off_tbl[QSEED3LITE_FILTERS] = {0x000, 0x200}; + + SDE_REG_WRITE(c, QSEED3L_DIR_FILTER_WEIGHT + offset, + scaler3_cfg->dir_weight & 0xFF); + + /* destination scaler case */ + if (!scaler3_cfg->sep_lut) + return; + + lut_flags = (unsigned long) scaler3_cfg->lut_flag; + if (test_bit(QSEED3L_COEF_LUT_Y_SEP_BIT, &lut_flags) && + (scaler3_cfg->y_rgb_sep_lut_idx < QSEED3L_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3L_SEP_LUT_SIZE)) { + lut[0] = scaler3_cfg->sep_lut + + scaler3_cfg->y_rgb_sep_lut_idx * QSEED3L_LUT_SIZE; + config_lut = 1; + } + if (test_bit(QSEED3L_COEF_LUT_UV_SEP_BIT, &lut_flags) && + (scaler3_cfg->uv_sep_lut_idx < QSEED3L_SEPARABLE_LUTS) && + (scaler3_cfg->sep_len == QSEED3L_SEP_LUT_SIZE)) { + lut[1] = scaler3_cfg->sep_lut + + scaler3_cfg->uv_sep_lut_idx * QSEED3L_LUT_SIZE; + config_lut = 1; + } + + if (config_lut) { + for (filter = 0; filter < QSEED3LITE_FILTERS; filter++) { + if (!lut[filter]) + continue; + lut_offset = 0; + lut_addr = QSEED3L_COEF_LUT_OFF + offset + + off_tbl[filter]; + for (i = 0; i < QSEED3L_LUT_SIZE; i++) { + SDE_REG_WRITE(c, lut_addr, + (lut[filter])[lut_offset++]); + lut_addr += 4; + } + } + } + + if (test_bit(QSEED3L_COEF_LUT_SWAP_BIT, &lut_flags)) + SDE_REG_WRITE(c, QSEED3L_COEF_LUT_CTRL + offset, BIT(0)); +} + +static void _sde_hw_setup_scaler3_de(struct sde_hw_blk_reg_map *c, + struct sde_hw_scaler3_de_cfg *de_cfg, u32 offset) +{ + u32 sharp_lvl, sharp_ctl, shape_ctl, de_thr; + u32 adjust_a, adjust_b, adjust_c; + + if (!de_cfg->enable) + return; + + sharp_lvl = (de_cfg->sharpen_level1 & 0x1FF) | + ((de_cfg->sharpen_level2 & 0x1FF) << 16); + + sharp_ctl = ((de_cfg->limit & 0xF) << 9) | + ((de_cfg->prec_shift & 0x7) << 13) | + ((de_cfg->clip & 0x7) << 16) | + ((de_cfg->blend & 0xF) << 20); + + shape_ctl = (de_cfg->thr_quiet & 0xFF) | + ((de_cfg->thr_dieout & 0x3FF) << 16); + + de_thr = (de_cfg->thr_low & 0x3FF) | + ((de_cfg->thr_high & 0x3FF) << 16); + + adjust_a = (de_cfg->adjust_a[0] & 0x3FF) | + ((de_cfg->adjust_a[1] & 0x3FF) << 10) | + ((de_cfg->adjust_a[2] & 0x3FF) << 20); + + adjust_b = (de_cfg->adjust_b[0] & 0x3FF) | + ((de_cfg->adjust_b[1] & 0x3FF) << 10) | + ((de_cfg->adjust_b[2] & 0x3FF) << 20); + + adjust_c = (de_cfg->adjust_c[0] & 0x3FF) | + ((de_cfg->adjust_c[1] & 0x3FF) << 10) | + ((de_cfg->adjust_c[2] & 0x3FF) << 20); + + SDE_REG_WRITE(c, QSEED3_DE_SHARPEN + offset, sharp_lvl); + SDE_REG_WRITE(c, QSEED3_DE_SHARPEN_CTL + offset, sharp_ctl); + SDE_REG_WRITE(c, QSEED3_DE_SHAPE_CTL + offset, shape_ctl); + SDE_REG_WRITE(c, QSEED3_DE_THRESHOLD + offset, de_thr); + SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_0 + offset, adjust_a); + SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_1 + offset, adjust_b); + SDE_REG_WRITE(c, QSEED3_DE_ADJUST_DATA_2 + offset, adjust_c); + +} + +static inline scaler_lut_type get_scaler_lut( + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 scaler_version) +{ + scaler_lut_type lut_ptr = _sde_hw_setup_scaler3lite_lut; + + if (!(scaler3_cfg->lut_flag)) + return NULL; + + if (scaler_version < QSEED3LITE_SCALER_VERSION) + lut_ptr = _sde_hw_setup_scaler3_lut; + + return lut_ptr; +} + +void sde_hw_setup_scaler3(struct sde_hw_blk_reg_map *c, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 scaler_version, + u32 scaler_offset, const struct sde_format *format) +{ + u32 op_mode = 0; + u32 phase_init, preload, src_y_rgb, src_uv, dst; + scaler_lut_type setup_lut = NULL; + + if (!scaler3_cfg->enable) + goto end; + + op_mode |= BIT(0); + op_mode |= (scaler3_cfg->y_rgb_filter_cfg & 0x3) << 16; + + if (format && SDE_FORMAT_IS_YUV(format)) { + op_mode |= BIT(12); + op_mode |= (scaler3_cfg->uv_filter_cfg & 0x3) << 24; + } + + op_mode |= (scaler3_cfg->blend_cfg & 1) << 31; + op_mode |= (scaler3_cfg->dir_en) ? BIT(4) : 0; + op_mode |= (scaler3_cfg->dyn_exp_disabled) ? BIT(13) : 0; + + preload = + ((scaler3_cfg->preload_x[0] & 0x7F) << 0) | + ((scaler3_cfg->preload_y[0] & 0x7F) << 8) | + ((scaler3_cfg->preload_x[1] & 0x7F) << 16) | + ((scaler3_cfg->preload_y[1] & 0x7F) << 24); + + src_y_rgb = (scaler3_cfg->src_width[0] & 0x1FFFF) | + ((scaler3_cfg->src_height[0] & 0x1FFFF) << 16); + + src_uv = (scaler3_cfg->src_width[1] & 0x1FFFF) | + ((scaler3_cfg->src_height[1] & 0x1FFFF) << 16); + + dst = (scaler3_cfg->dst_width & 0x1FFFF) | + ((scaler3_cfg->dst_height & 0x1FFFF) << 16); + + if (scaler3_cfg->de.enable) { + _sde_hw_setup_scaler3_de(c, &scaler3_cfg->de, scaler_offset); + op_mode |= BIT(8); + } + + setup_lut = get_scaler_lut(scaler3_cfg, scaler_version); + if (setup_lut) + setup_lut(c, scaler3_cfg, scaler_offset); + + if (scaler_version == 0x1002) { + phase_init = + ((scaler3_cfg->init_phase_x[0] & 0x3F) << 0) | + ((scaler3_cfg->init_phase_y[0] & 0x3F) << 8) | + ((scaler3_cfg->init_phase_x[1] & 0x3F) << 16) | + ((scaler3_cfg->init_phase_y[1] & 0x3F) << 24); + SDE_REG_WRITE(c, QSEED3_PHASE_INIT + scaler_offset, phase_init); + } else { + SDE_REG_WRITE(c, QSEED3_PHASE_INIT_Y_H + scaler_offset, + scaler3_cfg->init_phase_x[0] & 0x1FFFFF); + SDE_REG_WRITE(c, QSEED3_PHASE_INIT_Y_V + scaler_offset, + scaler3_cfg->init_phase_y[0] & 0x1FFFFF); + SDE_REG_WRITE(c, QSEED3_PHASE_INIT_UV_H + scaler_offset, + scaler3_cfg->init_phase_x[1] & 0x1FFFFF); + SDE_REG_WRITE(c, QSEED3_PHASE_INIT_UV_V + scaler_offset, + scaler3_cfg->init_phase_y[1] & 0x1FFFFF); + } + + SDE_REG_WRITE(c, QSEED3_PHASE_STEP_Y_H + scaler_offset, + scaler3_cfg->phase_step_x[0] & 0xFFFFFF); + + SDE_REG_WRITE(c, QSEED3_PHASE_STEP_Y_V + scaler_offset, + scaler3_cfg->phase_step_y[0] & 0xFFFFFF); + + SDE_REG_WRITE(c, QSEED3_PHASE_STEP_UV_H + scaler_offset, + scaler3_cfg->phase_step_x[1] & 0xFFFFFF); + + SDE_REG_WRITE(c, QSEED3_PHASE_STEP_UV_V + scaler_offset, + scaler3_cfg->phase_step_y[1] & 0xFFFFFF); + + SDE_REG_WRITE(c, QSEED3_PRELOAD + scaler_offset, preload); + + SDE_REG_WRITE(c, QSEED3_SRC_SIZE_Y_RGB_A + scaler_offset, src_y_rgb); + + SDE_REG_WRITE(c, QSEED3_SRC_SIZE_UV + scaler_offset, src_uv); + + SDE_REG_WRITE(c, QSEED3_DST_SIZE + scaler_offset, dst); + +end: + if (format && !SDE_FORMAT_IS_DX(format)) + op_mode |= BIT(14); + + if (format && format->alpha_enable) { + op_mode |= BIT(10); + if (scaler_version == 0x1002) + op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x1) << 30; + else + op_mode |= (scaler3_cfg->alpha_filter_cfg & 0x3) << 29; + } + + SDE_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode); +} + +u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c, + u32 scaler_offset) +{ + return SDE_REG_READ(c, QSEED3_HW_VERSION + scaler_offset); +} + +void sde_hw_csc_matrix_coeff_setup(struct sde_hw_blk_reg_map *c, + u32 csc_reg_off, struct sde_csc_cfg *data, + u32 shift_bit) +{ + u32 val; + + if (!c || !data) + return; + + val = ((data->csc_mv[0] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[1] >> shift_bit) & 0x1FFF) << 16); + SDE_REG_WRITE(c, csc_reg_off, val); + val = ((data->csc_mv[2] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[3] >> shift_bit) & 0x1FFF) << 16); + SDE_REG_WRITE(c, csc_reg_off + 0x4, val); + val = ((data->csc_mv[4] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[5] >> shift_bit) & 0x1FFF) << 16); + SDE_REG_WRITE(c, csc_reg_off + 0x8, val); + val = ((data->csc_mv[6] >> shift_bit) & 0x1FFF) | + (((data->csc_mv[7] >> shift_bit) & 0x1FFF) << 16); + SDE_REG_WRITE(c, csc_reg_off + 0xc, val); + val = (data->csc_mv[8] >> shift_bit) & 0x1FFF; + SDE_REG_WRITE(c, csc_reg_off + 0x10, val); +} + +void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c, + u32 csc_reg_off, + struct sde_csc_cfg *data, bool csc10) +{ + u32 clamp_shift = csc10 ? 16 : 8; + u32 val; + + if (!c || !data) + return; + + /* matrix coeff - convert S15.16 to S4.9 */ + sde_hw_csc_matrix_coeff_setup(c, csc_reg_off, data, CSC_MATRIX_SHIFT); + + /* Pre clamp */ + val = (data->csc_pre_lv[0] << clamp_shift) | data->csc_pre_lv[1]; + SDE_REG_WRITE(c, csc_reg_off + 0x14, val); + val = (data->csc_pre_lv[2] << clamp_shift) | data->csc_pre_lv[3]; + SDE_REG_WRITE(c, csc_reg_off + 0x18, val); + val = (data->csc_pre_lv[4] << clamp_shift) | data->csc_pre_lv[5]; + SDE_REG_WRITE(c, csc_reg_off + 0x1c, val); + + /* Post clamp */ + val = (data->csc_post_lv[0] << clamp_shift) | data->csc_post_lv[1]; + SDE_REG_WRITE(c, csc_reg_off + 0x20, val); + val = (data->csc_post_lv[2] << clamp_shift) | data->csc_post_lv[3]; + SDE_REG_WRITE(c, csc_reg_off + 0x24, val); + val = (data->csc_post_lv[4] << clamp_shift) | data->csc_post_lv[5]; + SDE_REG_WRITE(c, csc_reg_off + 0x28, val); + + /* Pre-Bias */ + SDE_REG_WRITE(c, csc_reg_off + 0x2c, data->csc_pre_bv[0]); + SDE_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]); + SDE_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]); + + /* Post-Bias */ + SDE_REG_WRITE(c, csc_reg_off + 0x38, data->csc_post_bv[0]); + SDE_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); + SDE_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); +} + +/** + * _sde_copy_formats - copy formats from src_list to dst_list + * @dst_list: pointer to destination list where to copy formats + * @dst_list_size: size of destination list + * @dst_list_pos: starting position on the list where to copy formats + * @src_list: pointer to source list where to copy formats from + * @src_list_size: size of source list + * Return: number of elements populated + */ +uint32_t sde_copy_formats( + struct sde_format_extended *dst_list, + uint32_t dst_list_size, + uint32_t dst_list_pos, + const struct sde_format_extended *src_list, + uint32_t src_list_size) +{ + uint32_t cur_pos, i; + + if (!dst_list || !src_list || (dst_list_pos >= (dst_list_size - 1))) + return 0; + + for (i = 0, cur_pos = dst_list_pos; + (cur_pos < (dst_list_size - 1)) && (i < src_list_size) + && src_list[i].fourcc_format; ++i, ++cur_pos) + dst_list[cur_pos] = src_list[i]; + + dst_list[cur_pos].fourcc_format = 0; + + return i; +} + +/** + * sde_get_linetime - returns the line time for a given mode + * @mode: pointer to drm mode to calculate the line time + * @comp_ratio: compression ratio + * Return: line time of display mode in nS + */ +uint32_t sde_get_linetime(struct drm_display_mode *mode, int comp_ratio) +{ + u64 pclk_rate; + u32 pclk_period; + u32 line_time; + + pclk_rate = mode->clock; /* pixel clock in kHz */ + if (pclk_rate == 0) { + SDE_ERROR("pclk is 0, cannot calculate line time\n"); + return 0; + } + + pclk_period = DIV_ROUND_UP_ULL(1000000000ull, pclk_rate); + if (pclk_period == 0) { + SDE_ERROR("pclk period is 0\n"); + return 0; + } + + /* + * Line time calculation based on Pixel clock, HTOTAL, and comp_ratio. + * Final unit is in ns. + */ + line_time = DIV_ROUND_UP(mult_frac(pclk_period, mode->htotal, + comp_ratio), 1000); + if (line_time == 0) { + SDE_ERROR("line time calculation is 0\n"); + return 0; + } + + pr_debug("clk_rate=%lldkHz, clk_period=%d, linetime=%dns, htotal=%d\n", + pclk_rate, pclk_period, line_time, mode->htotal); + + return line_time; +} diff --git a/techpack/display/msm/sde/sde_hw_util.h b/techpack/display/msm/sde/sde_hw_util.h new file mode 100644 index 0000000000000000000000000000000000000000..84b16336c591d27a30b4cb43825ce2b6ed9897e6 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_util.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_UTIL_H +#define _SDE_HW_UTIL_H + +#include <linux/io.h> +#include <linux/slab.h> +#include "sde_hw_mdss.h" +#include "sde_hw_catalog.h" + +#define REG_MASK(n) ((BIT(n)) - 1) +#define LP_DDR4_TYPE 0x7 + +struct sde_format_extended; + +/* + * This is the common struct maintained by each sub block + * for mapping the register offsets in this block to the + * absoulute IO address + * @base_off: mdp register mapped offset + * @blk_off: pipe offset relative to mdss offset + * @length length of register block offset + * @xin_id xin id + * @hwversion mdss hw version number + */ +struct sde_hw_blk_reg_map { + void __iomem *base_off; + u32 blk_off; + u32 length; + u32 xin_id; + u32 hwversion; + u32 log_mask; +}; + +/** + * struct sde_hw_scaler3_de_cfg : QSEEDv3 detail enhancer configuration + * @enable: detail enhancer enable/disable + * @sharpen_level1: sharpening strength for noise + * @sharpen_level2: sharpening strength for signal + * @ clip: clip shift + * @ limit: limit value + * @ thr_quiet: quiet threshold + * @ thr_dieout: dieout threshold + * @ thr_high: low threshold + * @ thr_high: high threshold + * @ prec_shift: precision shift + * @ adjust_a: A-coefficients for mapping curve + * @ adjust_b: B-coefficients for mapping curve + * @ adjust_c: C-coefficients for mapping curve + * @ blend: Unsharp Blend Filter Ratio + */ +struct sde_hw_scaler3_de_cfg { + u32 enable; + int16_t sharpen_level1; + int16_t sharpen_level2; + uint16_t clip; + uint16_t limit; + uint16_t thr_quiet; + uint16_t thr_dieout; + uint16_t thr_low; + uint16_t thr_high; + uint16_t prec_shift; + int16_t adjust_a[SDE_MAX_DE_CURVES]; + int16_t adjust_b[SDE_MAX_DE_CURVES]; + int16_t adjust_c[SDE_MAX_DE_CURVES]; + uint32_t blend; +}; + + +/** + * struct sde_hw_scaler3_cfg : QSEEDv3 configuration + * @enable: scaler enable + * @dir_en: direction detection block enable + * @ init_phase_x: horizontal initial phase + * @ phase_step_x: horizontal phase step + * @ init_phase_y: vertical initial phase + * @ phase_step_y: vertical phase step + * @ preload_x: horizontal preload value + * @ preload_y: vertical preload value + * @ src_width: source width + * @ src_height: source height + * @ dst_width: destination width + * @ dst_height: destination height + * @ y_rgb_filter_cfg: y/rgb plane filter configuration + * @ uv_filter_cfg: uv plane filter configuration + * @ alpha_filter_cfg: alpha filter configuration + * @ blend_cfg: blend coefficients configuration + * @ lut_flag: scaler LUT update flags + * 0x1 swap LUT bank + * 0x2 update 2D filter LUT + * 0x4 update y circular filter LUT + * 0x8 update uv circular filter LUT + * 0x10 update y separable filter LUT + * 0x20 update uv separable filter LUT + * @ dir_lut_idx: 2D filter LUT index + * @ y_rgb_cir_lut_idx: y circular filter LUT index + * @ uv_cir_lut_idx: uv circular filter LUT index + * @ y_rgb_sep_lut_idx: y circular filter LUT index + * @ uv_sep_lut_idx: uv separable filter LUT index + * @ dir_lut: pointer to 2D LUT + * @ cir_lut: pointer to circular filter LUT + * @ sep_lut: pointer to separable filter LUT + * @ de: detail enhancer configuration + * @ dir_weight: Directional Weight + * @dyn_exp_disabled: Dynamic expansion disabled + */ +struct sde_hw_scaler3_cfg { + u32 enable; + u32 dir_en; + int32_t init_phase_x[SDE_MAX_PLANES]; + int32_t phase_step_x[SDE_MAX_PLANES]; + int32_t init_phase_y[SDE_MAX_PLANES]; + int32_t phase_step_y[SDE_MAX_PLANES]; + + u32 preload_x[SDE_MAX_PLANES]; + u32 preload_y[SDE_MAX_PLANES]; + u32 src_width[SDE_MAX_PLANES]; + u32 src_height[SDE_MAX_PLANES]; + + u32 dst_width; + u32 dst_height; + + u32 y_rgb_filter_cfg; + u32 uv_filter_cfg; + u32 alpha_filter_cfg; + u32 blend_cfg; + + u32 lut_flag; + u32 dir_lut_idx; + + u32 y_rgb_cir_lut_idx; + u32 uv_cir_lut_idx; + u32 y_rgb_sep_lut_idx; + u32 uv_sep_lut_idx; + u32 *dir_lut; + size_t dir_len; + u32 *cir_lut; + size_t cir_len; + u32 *sep_lut; + size_t sep_len; + + /* + * Detail enhancer settings + */ + struct sde_hw_scaler3_de_cfg de; + uint32_t dir_weight; + uint32_t dyn_exp_disabled; +}; + +struct sde_hw_scaler3_lut_cfg { + bool is_configured; + u32 *dir_lut; + size_t dir_len; + u32 *cir_lut; + size_t cir_len; + u32 *sep_lut; + size_t sep_len; +}; + +struct sde_hw_inline_pre_downscale_cfg { + u32 pre_downscale_x_0; + u32 pre_downscale_x_1; + u32 pre_downscale_y_0; + u32 pre_downscale_y_1; +}; + +u32 *sde_hw_util_get_log_mask_ptr(void); + +void sde_reg_write(struct sde_hw_blk_reg_map *c, + u32 reg_off, + u32 val, + const char *name); +int sde_reg_read(struct sde_hw_blk_reg_map *c, u32 reg_off); + +#define SDE_REG_WRITE(c, off, val) sde_reg_write(c, off, val, #off) +#define SDE_REG_READ(c, off) sde_reg_read(c, off) + +#define SDE_IMEM_WRITE(addr, val) writel_relaxed(val, addr) +#define SDE_IMEM_READ(addr) readl_relaxed(addr) + +#define MISR_FRAME_COUNT_MASK 0xFF +#define MISR_CTRL_ENABLE BIT(8) +#define MISR_CTRL_STATUS BIT(9) +#define MISR_CTRL_STATUS_CLEAR BIT(10) +#define INTF_MISR_CTRL_FREE_RUN_MASK BIT(31) +#define INTF_MISR_CTRL_INPUT_SEL_DATA BIT(24) + +void *sde_hw_util_get_dir(void); + +void sde_init_scaler_blk(struct sde_scaler_blk *blk, u32 version); + +void sde_set_scaler_v2(struct sde_hw_scaler3_cfg *cfg, + const struct sde_drm_scaler_v2 *scale_v2); + +void sde_hw_setup_scaler3(struct sde_hw_blk_reg_map *c, + struct sde_hw_scaler3_cfg *scaler3_cfg, u32 scaler_version, + u32 scaler_offset, const struct sde_format *format); + +u32 sde_hw_get_scaler3_ver(struct sde_hw_blk_reg_map *c, + u32 scaler_offset); + +void sde_hw_csc_matrix_coeff_setup(struct sde_hw_blk_reg_map *c, + u32 csc_reg_off, struct sde_csc_cfg *data, + u32 shift_bit); + +void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c, + u32 csc_reg_off, + struct sde_csc_cfg *data, bool csc10); + +uint32_t sde_copy_formats( + struct sde_format_extended *dst_list, + uint32_t dst_list_size, + uint32_t dst_list_pos, + const struct sde_format_extended *src_list, + uint32_t src_list_size); + +uint32_t sde_get_linetime(struct drm_display_mode *mode, int comp_ratio); + +static inline bool is_qseed3_rev_qseed3lite(struct sde_mdss_cfg *sde_cfg) +{ + return ((sde_cfg->qseed_type == SDE_SSPP_SCALER_QSEED3LITE) ? + true : false); +} +#endif /* _SDE_HW_UTIL_H */ diff --git a/techpack/display/msm/sde/sde_hw_vbif.c b/techpack/display/msm/sde/sde_hw_vbif.c new file mode 100644 index 0000000000000000000000000000000000000000..e5c089f83b48d04a75d7c01d3cb4fe9561d1e024 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_vbif.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_vbif.h" +#include "sde_dbg.h" + +#define VBIF_VERSION 0x0000 +#define VBIF_CLK_FORCE_CTRL0 0x0008 +#define VBIF_CLK_FORCE_CTRL1 0x000C +#define VBIF_QOS_REMAP_00 0x0020 +#define VBIF_QOS_REMAP_01 0x0024 +#define VBIF_QOS_REMAP_10 0x0028 +#define VBIF_QOS_REMAP_11 0x002C +#define VBIF_WRITE_GATHER_EN 0x00AC +#define VBIF_IN_RD_LIM_CONF0 0x00B0 +#define VBIF_IN_RD_LIM_CONF1 0x00B4 +#define VBIF_IN_RD_LIM_CONF2 0x00B8 +#define VBIF_IN_WR_LIM_CONF0 0x00C0 +#define VBIF_IN_WR_LIM_CONF1 0x00C4 +#define VBIF_IN_WR_LIM_CONF2 0x00C8 +#define VBIF_OUT_RD_LIM_CONF0 0x00D0 +#define VBIF_OUT_WR_LIM_CONF0 0x00D4 +#define VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160 +#define VBIF_OUT_AXI_AMEMTYPE_CONF1 0x0164 +#define VBIF_OUT_AXI_ASHARED 0x0170 +#define VBIF_OUT_AXI_AINNERSHARED 0x0174 +#define VBIF_XIN_PND_ERR 0x0190 +#define VBIF_XIN_SRC_ERR 0x0194 +#define VBIF_XIN_CLR_ERR 0x019C +#define VBIF_XIN_HALT_CTRL0 0x0200 +#define VBIF_XIN_HALT_CTRL1 0x0204 +#define VBIF_XINL_QOS_RP_REMAP_000 0x0550 +#define VBIF_XINL_QOS_LVL_REMAP_000 0x0590 + +static void sde_hw_clear_errors(struct sde_hw_vbif *vbif, + u32 *pnd_errors, u32 *src_errors) +{ + struct sde_hw_blk_reg_map *c; + u32 pnd, src; + + if (!vbif) + return; + c = &vbif->hw; + pnd = SDE_REG_READ(c, VBIF_XIN_PND_ERR); + src = SDE_REG_READ(c, VBIF_XIN_SRC_ERR); + + if (pnd_errors) + *pnd_errors = pnd; + if (src_errors) + *src_errors = src; + + SDE_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src); +} + +static void sde_hw_set_mem_type(struct sde_hw_vbif *vbif, + u32 xin_id, u32 value) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_off; + u32 bit_off; + u32 reg_val; + + /* + * Assume 4 bits per bit field, 8 fields per 32-bit register so + * 16 bit fields maximum across two registers + */ + if (!vbif || xin_id >= MAX_XIN_COUNT) + return; + + c = &vbif->hw; + + /* enable cacheable */ + if (xin_id >= 8) { + xin_id -= 8; + reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF1; + } else { + reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF0; + } + bit_off = (xin_id & 0x7) * 4; + reg_val = SDE_REG_READ(c, reg_off); + reg_val &= ~(0x7 << bit_off); + reg_val |= (value & 0x7) << bit_off; + SDE_REG_WRITE(c, reg_off, reg_val); +} + +static void sde_hw_set_mem_type_v1(struct sde_hw_vbif *vbif, + u32 xin_id, u32 value) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_val; + + if (!vbif || xin_id >= MAX_XIN_COUNT) + return; + + sde_hw_set_mem_type(vbif, xin_id, value); + + c = &vbif->hw; + + /* disable outer shareable */ + reg_val = SDE_REG_READ(c, VBIF_OUT_AXI_ASHARED); + reg_val &= ~BIT(xin_id); + SDE_REG_WRITE(c, VBIF_OUT_AXI_ASHARED, 0); + + /* disable inner shareable */ + reg_val = SDE_REG_READ(c, VBIF_OUT_AXI_AINNERSHARED); + reg_val &= ~BIT(xin_id); + SDE_REG_WRITE(c, VBIF_OUT_AXI_AINNERSHARED, 0); +} + +static void sde_hw_set_limit_conf(struct sde_hw_vbif *vbif, + u32 xin_id, bool rd, u32 limit) +{ + struct sde_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + u32 reg_off; + u32 bit_off; + + if (rd) + reg_off = VBIF_IN_RD_LIM_CONF0; + else + reg_off = VBIF_IN_WR_LIM_CONF0; + + reg_off += (xin_id / 4) * 4; + bit_off = (xin_id % 4) * 8; + reg_val = SDE_REG_READ(c, reg_off); + reg_val &= ~(0xFF << bit_off); + reg_val |= (limit) << bit_off; + SDE_REG_WRITE(c, reg_off, reg_val); +} + +static u32 sde_hw_get_limit_conf(struct sde_hw_vbif *vbif, + u32 xin_id, bool rd) +{ + struct sde_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + u32 reg_off; + u32 bit_off; + u32 limit; + + if (rd) + reg_off = VBIF_IN_RD_LIM_CONF0; + else + reg_off = VBIF_IN_WR_LIM_CONF0; + + reg_off += (xin_id / 4) * 4; + bit_off = (xin_id % 4) * 8; + reg_val = SDE_REG_READ(c, reg_off); + limit = (reg_val >> bit_off) & 0xFF; + + return limit; +} + +static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif, + u32 xin_id, bool enable) +{ + struct sde_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + + reg_val = SDE_REG_READ(c, VBIF_XIN_HALT_CTRL0); + + if (enable) + reg_val |= BIT(xin_id); + else + reg_val &= ~BIT(xin_id); + + SDE_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val); +} + +static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif, + u32 xin_id) +{ + struct sde_hw_blk_reg_map *c = &vbif->hw; + u32 reg_val; + + reg_val = SDE_REG_READ(c, VBIF_XIN_HALT_CTRL1); + + return ((reg_val >> 16) & BIT(xin_id)) ? true : false; +} + +static void sde_hw_set_qos_remap(struct sde_hw_vbif *vbif, + u32 xin_id, u32 level, u32 remap_level) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_val, reg_val_lvl, mask, reg_high, reg_shift; + + if (!vbif) + return; + + c = &vbif->hw; + + reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8); + reg_shift = (xin_id & 0x7) * 4; + + reg_val = SDE_REG_READ(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high); + reg_val_lvl = SDE_REG_READ(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high); + + mask = 0x7 << reg_shift; + + reg_val &= ~mask; + reg_val |= (remap_level << reg_shift) & mask; + + reg_val_lvl &= ~mask; + reg_val_lvl |= (remap_level << reg_shift) & mask; + + SDE_REG_WRITE(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high, reg_val); + SDE_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl); +} + +static void sde_hw_set_write_gather_en(struct sde_hw_vbif *vbif, u32 xin_id) +{ + struct sde_hw_blk_reg_map *c; + u32 reg_val; + + if (!vbif || xin_id >= MAX_XIN_COUNT) + return; + + c = &vbif->hw; + + reg_val = SDE_REG_READ(c, VBIF_WRITE_GATHER_EN); + reg_val |= BIT(xin_id); + SDE_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val); +} + +static void _setup_vbif_ops(const struct sde_mdss_cfg *m, + struct sde_hw_vbif_ops *ops, unsigned long cap) +{ + ops->set_limit_conf = sde_hw_set_limit_conf; + ops->get_limit_conf = sde_hw_get_limit_conf; + ops->set_halt_ctrl = sde_hw_set_halt_ctrl; + ops->get_halt_ctrl = sde_hw_get_halt_ctrl; + if (test_bit(SDE_VBIF_QOS_REMAP, &cap)) + ops->set_qos_remap = sde_hw_set_qos_remap; + if (IS_SM8150_TARGET(m->hwversion) || IS_SM6150_TARGET(m->hwversion) || + IS_SDMMAGPIE_TARGET(m->hwversion) || + IS_SDMTRINKET_TARGET(m->hwversion) || + IS_SDE_MAJOR_SAME(m->hwversion, SDE_HW_VER_600)) + ops->set_mem_type = sde_hw_set_mem_type_v1; + else + ops->set_mem_type = sde_hw_set_mem_type; + ops->clear_errors = sde_hw_clear_errors; + ops->set_write_gather_en = sde_hw_set_write_gather_en; +} + +static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif, + const struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->vbif_count; i++) { + if (vbif == m->vbif[i].id) { + b->base_off = addr; + b->blk_off = m->vbif[i].base; + b->length = m->vbif[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_VBIF; + return &m->vbif[i]; + } + } + + return ERR_PTR(-EINVAL); +} + +struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx, + void __iomem *addr, + const struct sde_mdss_cfg *m) +{ + struct sde_hw_vbif *c; + const struct sde_vbif_cfg *cfg; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _top_offset(idx, m, addr, &c->hw); + if (IS_ERR_OR_NULL(cfg)) { + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* + * Assign ops + */ + c->idx = idx; + c->cap = cfg; + _setup_vbif_ops(m, &c->ops, c->cap->features); + + /* no need to register sub-range in sde dbg, dump entire vbif io base */ + + mutex_init(&c->mutex); + + return c; +} + +void sde_hw_vbif_destroy(struct sde_hw_vbif *vbif) +{ + if (vbif) + mutex_destroy(&vbif->mutex); + kfree(vbif); +} diff --git a/techpack/display/msm/sde/sde_hw_vbif.h b/techpack/display/msm/sde/sde_hw_vbif.h new file mode 100644 index 0000000000000000000000000000000000000000..826b126a60b19a37a156426fa6d14d06a8b721d1 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_vbif.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_VBIF_H +#define _SDE_HW_VBIF_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_util.h" + +struct sde_hw_vbif; + +/** + * struct sde_hw_vbif_ops : Interface to the VBIF hardware driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_vbif_ops { + /** + * set_limit_conf - set transaction limit config + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @rd: true for read limit; false for write limit + * @limit: outstanding transaction limit + */ + void (*set_limit_conf)(struct sde_hw_vbif *vbif, + u32 xin_id, bool rd, u32 limit); + + /** + * get_limit_conf - get transaction limit config + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @rd: true for read limit; false for write limit + * @return: outstanding transaction limit + */ + u32 (*get_limit_conf)(struct sde_hw_vbif *vbif, + u32 xin_id, bool rd); + + /** + * set_halt_ctrl - set halt control + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @enable: halt control enable + */ + void (*set_halt_ctrl)(struct sde_hw_vbif *vbif, + u32 xin_id, bool enable); + + /** + * get_halt_ctrl - get halt control + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @return: halt control enable + */ + bool (*get_halt_ctrl)(struct sde_hw_vbif *vbif, + u32 xin_id); + + /** + * set_qos_remap - set QoS priority remap + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @level: priority level + * @remap_level: remapped level + */ + void (*set_qos_remap)(struct sde_hw_vbif *vbif, + u32 xin_id, u32 level, u32 remap_level); + + /** + * set_mem_type - set memory type + * @vbif: vbif context driver + * @xin_id: client interface identifier + * @value: memory type value + */ + void (*set_mem_type)(struct sde_hw_vbif *vbif, + u32 xin_id, u32 value); + + /** + * clear_errors - clear any vbif errors + * This function clears any detected pending/source errors + * on the VBIF interface, and optionally returns the detected + * error mask(s). + * @vbif: vbif context driver + * @pnd_errors: pointer to pending error reporting variable + * @src_errors: pointer to source error reporting variable + */ + void (*clear_errors)(struct sde_hw_vbif *vbif, + u32 *pnd_errors, u32 *src_errors); + + /** + * set_write_gather_en - set write_gather enable + * @vbif: vbif context driver + * @xin_id: client interface identifier + */ + void (*set_write_gather_en)(struct sde_hw_vbif *vbif, u32 xin_id); +}; + +struct sde_hw_vbif { + /* base */ + struct sde_hw_blk_reg_map hw; + + /* vbif */ + enum sde_vbif idx; + const struct sde_vbif_cfg *cap; + + /* ops */ + struct sde_hw_vbif_ops ops; + + /* + * vbif is common across all displays, lock to serialize access. + * must be take by client before using any ops + */ + struct mutex mutex; +}; + +/** + * sde_hw_vbif_init - initializes the vbif driver for the passed interface idx + * @idx: Interface index for which driver object is required + * @addr: Mapped register io address of MDSS + * @m: Pointer to mdss catalog data + */ +struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx, + void __iomem *addr, + const struct sde_mdss_cfg *m); + +void sde_hw_vbif_destroy(struct sde_hw_vbif *vbif); + +#endif /*_SDE_HW_VBIF_H */ diff --git a/techpack/display/msm/sde/sde_hw_wb.c b/techpack/display/msm/sde/sde_hw_wb.c new file mode 100644 index 0000000000000000000000000000000000000000..8fbf394612a68eb588a20ee4d949d85e52165c00 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_wb.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#include "sde_hw_mdss.h" +#include "sde_hwio.h" +#include "sde_hw_catalog.h" +#include "sde_hw_wb.h" +#include "sde_formats.h" +#include "sde_dbg.h" +#include "sde_kms.h" + +#define WB_DST_FORMAT 0x000 +#define WB_DST_OP_MODE 0x004 +#define WB_DST_PACK_PATTERN 0x008 +#define WB_DST0_ADDR 0x00C +#define WB_DST1_ADDR 0x010 +#define WB_DST2_ADDR 0x014 +#define WB_DST3_ADDR 0x018 +#define WB_DST_YSTRIDE0 0x01C +#define WB_DST_YSTRIDE1 0x020 +#define WB_DST_YSTRIDE1 0x020 +#define WB_DST_DITHER_BITDEPTH 0x024 +#define WB_DST_MATRIX_ROW0 0x030 +#define WB_DST_MATRIX_ROW1 0x034 +#define WB_DST_MATRIX_ROW2 0x038 +#define WB_DST_MATRIX_ROW3 0x03C +#define WB_DST_WRITE_CONFIG 0x048 +#define WB_ROTATION_DNSCALER 0x050 +#define WB_ROTATOR_PIPE_DOWNSCALER 0x054 +#define WB_N16_INIT_PHASE_X_C03 0x060 +#define WB_N16_INIT_PHASE_X_C12 0x064 +#define WB_N16_INIT_PHASE_Y_C03 0x068 +#define WB_N16_INIT_PHASE_Y_C12 0x06C +#define WB_OUT_SIZE 0x074 +#define WB_ALPHA_X_VALUE 0x078 +#define WB_DANGER_LUT 0x084 +#define WB_SAFE_LUT 0x088 +#define WB_QOS_CTRL 0x090 +#define WB_CREQ_LUT_0 0x098 +#define WB_CREQ_LUT_1 0x09C +#define WB_UBWC_STATIC_CTRL 0x144 +#define WB_MUX 0x150 +#define WB_CSC_BASE 0x260 +#define WB_DST_ADDR_SW_STATUS 0x2B0 +#define WB_CDP_CNTL 0x2B4 +#define WB_OUT_IMAGE_SIZE 0x2C0 +#define WB_OUT_XY 0x2C4 + +#define CWB_CTRL_SRC_SEL 0x0 +#define CWB_CTRL_MODE 0x4 +#define CWB_CTRL_BLK_SIZE 0x100 +#define CWB_CTRL_BASE_OFFSET 0x83000 + +/* WB_QOS_CTRL */ +#define WB_QOS_CTRL_DANGER_SAFE_EN BIT(0) + +static struct sde_wb_cfg *_wb_offset(enum sde_wb wb, + struct sde_mdss_cfg *m, + void __iomem *addr, + struct sde_hw_blk_reg_map *b) +{ + int i; + + for (i = 0; i < m->wb_count; i++) { + if (wb == m->wb[i].id) { + b->base_off = addr; + b->blk_off = m->wb[i].base; + b->length = m->wb[i].len; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_WB; + return &m->wb[i]; + } + } + return ERR_PTR(-EINVAL); +} + +static void _sde_hw_cwb_ctrl_init(struct sde_mdss_cfg *m, + void __iomem *addr, struct sde_hw_blk_reg_map *b) +{ + if (b) { + b->base_off = addr; + b->blk_off = CWB_CTRL_BASE_OFFSET; + b->length = CWB_CTRL_BLK_SIZE * m->pingpong_count; + b->hwversion = m->hwversion; + b->log_mask = SDE_DBG_MASK_WB; + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, "cwb", b->blk_off, + b->blk_off + b->length, 0xff); + } +} + +static void sde_hw_wb_setup_outaddress(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *data) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + + SDE_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]); + SDE_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]); + SDE_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]); + SDE_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]); +} + +static void sde_hw_wb_setup_format(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *data) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + const struct sde_format *fmt = data->dest.format; + u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp; + u32 write_config = 0; + u32 opmode = 0; + u32 dst_addr_sw = 0; + + chroma_samp = fmt->chroma_sample; + + dst_format = (chroma_samp << 23) | + (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | + (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C0_G_Y] << 0); + + if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) { + dst_format |= BIT(8); /* DSTC3_EN */ + if (!fmt->alpha_enable || + !(ctx->caps->features & BIT(SDE_WB_PIPE_ALPHA))) + dst_format |= BIT(14); /* DST_ALPHA_X */ + } + + if (SDE_FORMAT_IS_YUV(fmt) && + (ctx->caps->features & BIT(SDE_WB_YUV_CONFIG))) + dst_format |= BIT(15); + + if (SDE_FORMAT_IS_DX(fmt)) + dst_format |= BIT(21); + + pattern = (fmt->element[3] << 24) | + (fmt->element[2] << 16) | + (fmt->element[1] << 8) | + (fmt->element[0] << 0); + + dst_format |= (fmt->unpack_align_msb << 18) | + (fmt->unpack_tight << 17) | + ((fmt->unpack_count - 1) << 12) | + ((fmt->bpp - 1) << 9); + + ystride0 = data->dest.plane_pitch[0] | + (data->dest.plane_pitch[1] << 16); + ystride1 = data->dest.plane_pitch[2] | + (data->dest.plane_pitch[3] << 16); + + if (data->roi.h && data->roi.w) + outsize = (data->roi.h << 16) | data->roi.w; + else + outsize = (data->dest.height << 16) | data->dest.width; + + if (SDE_FORMAT_IS_UBWC(fmt)) { + opmode |= BIT(0); + dst_format |= BIT(31); + write_config |= (ctx->mdp->highest_bank_bit << 8); + if (fmt->base.pixel_format == DRM_FORMAT_RGB565) + write_config |= 0x8; + if (IS_UBWC_20_SUPPORTED(ctx->catalog->ubwc_version)) + SDE_REG_WRITE(c, WB_UBWC_STATIC_CTRL, + (ctx->mdp->ubwc_swizzle << 0) | + (ctx->mdp->highest_bank_bit << 4)); + if (IS_UBWC_10_SUPPORTED(ctx->catalog->ubwc_version)) + SDE_REG_WRITE(c, WB_UBWC_STATIC_CTRL, + (ctx->mdp->ubwc_swizzle << 0) | + BIT(8) | + (ctx->mdp->highest_bank_bit << 4)); + } + + if (data->is_secure) + dst_addr_sw |= BIT(0); + + SDE_REG_WRITE(c, WB_ALPHA_X_VALUE, 0xFF); + SDE_REG_WRITE(c, WB_DST_FORMAT, dst_format); + SDE_REG_WRITE(c, WB_DST_OP_MODE, opmode); + SDE_REG_WRITE(c, WB_DST_PACK_PATTERN, pattern); + SDE_REG_WRITE(c, WB_DST_YSTRIDE0, ystride0); + SDE_REG_WRITE(c, WB_DST_YSTRIDE1, ystride1); + SDE_REG_WRITE(c, WB_OUT_SIZE, outsize); + SDE_REG_WRITE(c, WB_DST_WRITE_CONFIG, write_config); + SDE_REG_WRITE(c, WB_DST_ADDR_SW_STATUS, dst_addr_sw); +} + +static void sde_hw_wb_roi(struct sde_hw_wb *ctx, struct sde_hw_wb_cfg *wb) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 image_size, out_size, out_xy; + + image_size = (wb->dest.height << 16) | wb->dest.width; + out_xy = (wb->roi.y << 16) | wb->roi.x; + out_size = (wb->roi.h << 16) | wb->roi.w; + + SDE_REG_WRITE(c, WB_OUT_IMAGE_SIZE, image_size); + SDE_REG_WRITE(c, WB_OUT_XY, out_xy); + SDE_REG_WRITE(c, WB_OUT_SIZE, out_size); +} + +static void sde_hw_wb_setup_qos_lut(struct sde_hw_wb *ctx, + struct sde_hw_wb_qos_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 qos_ctrl = 0; + + if (!ctx || !cfg) + return; + + SDE_REG_WRITE(c, WB_DANGER_LUT, cfg->danger_lut); + SDE_REG_WRITE(c, WB_SAFE_LUT, cfg->safe_lut); + + if (ctx->caps && test_bit(SDE_WB_QOS_8LVL, &ctx->caps->features)) { + SDE_REG_WRITE(c, WB_CREQ_LUT_0, cfg->creq_lut); + SDE_REG_WRITE(c, WB_CREQ_LUT_1, cfg->creq_lut >> 32); + } + + if (cfg->danger_safe_en) + qos_ctrl |= WB_QOS_CTRL_DANGER_SAFE_EN; + + SDE_REG_WRITE(c, WB_QOS_CTRL, qos_ctrl); +} + +static void sde_hw_wb_setup_cdp(struct sde_hw_wb *ctx, + struct sde_hw_wb_cdp_cfg *cfg) +{ + struct sde_hw_blk_reg_map *c; + u32 cdp_cntl = 0; + + if (!ctx || !cfg) + return; + + c = &ctx->hw; + + if (cfg->enable) + cdp_cntl |= BIT(0); + if (cfg->ubwc_meta_enable) + cdp_cntl |= BIT(1); + if (cfg->preload_ahead == SDE_WB_CDP_PRELOAD_AHEAD_64) + cdp_cntl |= BIT(3); + + SDE_REG_WRITE(c, WB_CDP_CNTL, cdp_cntl); +} + +static void sde_hw_wb_bind_pingpong_blk( + struct sde_hw_wb *ctx, + bool enable, + const enum sde_pingpong pp) +{ + struct sde_hw_blk_reg_map *c; + int mux_cfg = 0xF; + + if (!ctx) + return; + + c = &ctx->hw; + if (enable) + mux_cfg = (pp - PINGPONG_0) & 0x7; + + SDE_REG_WRITE(c, WB_MUX, mux_cfg); +} + +static void sde_hw_wb_program_cwb_ctrl(struct sde_hw_wb *ctx, + const enum sde_cwb cur_idx, const enum sde_cwb data_src, + bool dspp_out, bool enable) +{ + struct sde_hw_blk_reg_map *c; + u32 blk_base; + + if (!ctx) + return; + + c = &ctx->cwb_hw; + blk_base = CWB_CTRL_BLK_SIZE * (cur_idx - CWB_0); + + if (enable) { + SDE_REG_WRITE(c, blk_base + CWB_CTRL_SRC_SEL, data_src - CWB_0); + SDE_REG_WRITE(c, blk_base + CWB_CTRL_MODE, dspp_out); + } else { + SDE_REG_WRITE(c, blk_base + CWB_CTRL_SRC_SEL, 0xf); + SDE_REG_WRITE(c, blk_base + CWB_CTRL_MODE, 0x0); + } +} + +static void _setup_wb_ops(struct sde_hw_wb_ops *ops, + unsigned long features) +{ + ops->setup_outaddress = sde_hw_wb_setup_outaddress; + ops->setup_outformat = sde_hw_wb_setup_format; + + if (test_bit(SDE_WB_XY_ROI_OFFSET, &features)) + ops->setup_roi = sde_hw_wb_roi; + + if (test_bit(SDE_WB_QOS, &features)) + ops->setup_qos_lut = sde_hw_wb_setup_qos_lut; + + if (test_bit(SDE_WB_CDP, &features)) + ops->setup_cdp = sde_hw_wb_setup_cdp; + + if (test_bit(SDE_WB_INPUT_CTRL, &features)) + ops->bind_pingpong_blk = sde_hw_wb_bind_pingpong_blk; + + if (test_bit(SDE_WB_CWB_CTRL, &features)) + ops->program_cwb_ctrl = sde_hw_wb_program_cwb_ctrl; +} + +static struct sde_hw_blk_ops sde_hw_ops = { + .start = NULL, + .stop = NULL, +}; + +struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx, + void __iomem *addr, + struct sde_mdss_cfg *m, + struct sde_hw_mdp *hw_mdp) +{ + struct sde_hw_wb *c; + struct sde_wb_cfg *cfg; + int rc; + + if (!addr || !m || !hw_mdp) + return ERR_PTR(-EINVAL); + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + cfg = _wb_offset(idx, m, addr, &c->hw); + if (IS_ERR(cfg)) { + WARN(1, "Unable to find wb idx=%d\n", idx); + kfree(c); + return ERR_PTR(-EINVAL); + } + + /* Assign ops */ + c->catalog = m; + c->mdp = &m->mdp[0]; + c->idx = idx; + c->caps = cfg; + _setup_wb_ops(&c->ops, c->caps->features); + c->hw_mdp = hw_mdp; + + rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_WB, idx, &sde_hw_ops); + if (rc) { + SDE_ERROR("failed to init hw blk %d\n", rc); + goto blk_init_error; + } + + sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, + c->hw.blk_off + c->hw.length, c->hw.xin_id); + + if (test_bit(SDE_WB_CWB_CTRL, &cfg->features)) + _sde_hw_cwb_ctrl_init(m, addr, &c->cwb_hw); + + return c; + +blk_init_error: + kzfree(c); + + return ERR_PTR(rc); +} + +void sde_hw_wb_destroy(struct sde_hw_wb *hw_wb) +{ + if (hw_wb) + sde_hw_blk_destroy(&hw_wb->base); + kfree(hw_wb); +} diff --git a/techpack/display/msm/sde/sde_hw_wb.h b/techpack/display/msm/sde/sde_hw_wb.h new file mode 100644 index 0000000000000000000000000000000000000000..a6c95cc5ebbae0af4b4702c0f7e33fcdaa220231 --- /dev/null +++ b/techpack/display/msm/sde/sde_hw_wb.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HW_WB_H +#define _SDE_HW_WB_H + +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_top.h" +#include "sde_hw_util.h" + +struct sde_hw_wb; + +struct sde_hw_wb_cfg { + struct sde_hw_fmt_layout dest; + enum sde_intf_mode intf_mode; + struct sde_rect roi; + bool is_secure; +}; + +/** + * enum CDP preload ahead address size + */ +enum { + SDE_WB_CDP_PRELOAD_AHEAD_32, + SDE_WB_CDP_PRELOAD_AHEAD_64 +}; + +/** + * struct sde_hw_wb_cdp_cfg : CDP configuration + * @enable: true to enable CDP + * @ubwc_meta_enable: true to enable ubwc metadata preload + * @tile_amortize_enable: true to enable amortization control for tile format + * @preload_ahead: number of request to preload ahead + * SDE_WB_CDP_PRELOAD_AHEAD_32, + * SDE_WB_CDP_PRELOAD_AHEAD_64 + */ +struct sde_hw_wb_cdp_cfg { + bool enable; + bool ubwc_meta_enable; + bool tile_amortize_enable; + u32 preload_ahead; +}; + +/** + * struct sde_hw_wb_qos_cfg : Writeback pipe QoS configuration + * @danger_lut: LUT for generate danger level based on fill level + * @safe_lut: LUT for generate safe level based on fill level + * @creq_lut: LUT for generate creq level based on fill level + * @danger_safe_en: enable danger safe generation + */ +struct sde_hw_wb_qos_cfg { + u32 danger_lut; + u32 safe_lut; + u64 creq_lut; + bool danger_safe_en; +}; + +/** + * + * struct sde_hw_wb_ops : Interface to the wb Hw driver functions + * Assumption is these functions will be called after clocks are enabled + */ +struct sde_hw_wb_ops { + void (*setup_csc_data)(struct sde_hw_wb *ctx, + struct sde_csc_cfg *data); + + void (*setup_outaddress)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + void (*setup_outformat)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + void (*setup_rotator)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + void (*setup_dither)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + void (*setup_cdwn)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + void (*setup_trafficshaper)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + void (*setup_roi)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cfg *wb); + + /** + * setup_qos_lut - setup danger, safe, creq, etc. LUTs + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe QoS configuration + */ + void (*setup_qos_lut)(struct sde_hw_wb *ctx, + struct sde_hw_wb_qos_cfg *cfg); + + /** + * setup_cdp - setup CDP + * @ctx: Pointer to pipe context + * @cfg: Pointer to pipe CDP configuration + */ + void (*setup_cdp)(struct sde_hw_wb *ctx, + struct sde_hw_wb_cdp_cfg *cfg); + + /** + * bind_pingpong_blk - enable/disable the connection with pp + * @ctx: Pointer to wb context + * @enable: enable/disable connection + * @pp: pingpong blk id + */ + void (*bind_pingpong_blk)(struct sde_hw_wb *ctx, + bool enable, + const enum sde_pingpong pp); + + /** + * program_cwb_ctrl - program cwb block configp + * @ctx: Pointer to wb context + * @pp_idx: Current CWB block index to poram + * @data_src: Source CWB/PingPong block index + * @dspp_out: Tap dspp output or default LM output + * @enable: enable or disable the CWB path to tap the output + */ + void (*program_cwb_ctrl)(struct sde_hw_wb *ctx, const enum sde_cwb cwb, + const enum sde_cwb data_src, bool dspp_out, bool enable); +}; + +/** + * struct sde_hw_wb : WB driver object + * @base: hardware block base structure + * @hw: block hardware details + * @catalog: back pointer to catalog + * @mdp: pointer to associated mdp portion of the catalog + * @idx: hardware index number within type + * @wb_hw_caps: hardware capabilities + * @ops: function pointers + * @hw_mdp: MDP top level hardware block + * @cwb_hw: CWB control hwio details + */ +struct sde_hw_wb { + struct sde_hw_blk base; + struct sde_hw_blk_reg_map hw; + struct sde_mdss_cfg *catalog; + struct sde_mdp_cfg *mdp; + + /* wb path */ + int idx; + const struct sde_wb_cfg *caps; + + /* ops */ + struct sde_hw_wb_ops ops; + + struct sde_hw_mdp *hw_mdp; + struct sde_hw_blk_reg_map cwb_hw; +}; + +/** + * sde_hw_wb - convert base object sde_hw_base to container + * @hw: Pointer to base hardware block + * return: Pointer to hardware block container + */ +static inline struct sde_hw_wb *to_sde_hw_wb(struct sde_hw_blk *hw) +{ + return container_of(hw, struct sde_hw_wb, base); +} + +/** + * sde_hw_wb_init(): Initializes and return writeback hw driver object. + * @idx: wb_path index for which driver object is required + * @addr: mapped register io address of MDP + * @m : pointer to mdss catalog data + * @hw_mdp: pointer to mdp top hw driver object + */ +struct sde_hw_wb *sde_hw_wb_init(enum sde_wb idx, + void __iomem *addr, + struct sde_mdss_cfg *m, + struct sde_hw_mdp *hw_mdp); + +/** + * sde_hw_wb_destroy(): Destroy writeback hw driver object. + * @hw_wb: Pointer to writeback hw driver object + */ +void sde_hw_wb_destroy(struct sde_hw_wb *hw_wb); + +#endif /*_SDE_HW_WB_H */ diff --git a/techpack/display/msm/sde/sde_hwio.h b/techpack/display/msm/sde/sde_hwio.h new file mode 100644 index 0000000000000000000000000000000000000000..c3dbde0f2ada990e5ba8bab91aeefe0180e96f77 --- /dev/null +++ b/techpack/display/msm/sde/sde_hwio.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_HWIO_H +#define _SDE_HWIO_H + +#include "sde_hw_util.h" + +/** + * MDP TOP block Register and bit fields and defines + */ +#define DISP_INTF_SEL 0x004 +#define INTR_EN 0x010 +#define INTR_STATUS 0x014 +#define INTR_CLEAR 0x018 +#define INTR2_EN 0x008 +#define INTR2_STATUS 0x00c +#define INTR2_CLEAR 0x02c +#define HIST_INTR_EN 0x01c +#define HIST_INTR_STATUS 0x020 +#define HIST_INTR_CLEAR 0x024 +#define INTF_INTR_EN 0x1C0 +#define INTF_INTR_STATUS 0x1C4 +#define INTF_INTR_CLEAR 0x1C8 +#define SPLIT_DISPLAY_EN 0x2F4 +#define SPLIT_DISPLAY_UPPER_PIPE_CTRL 0x2F8 +#define DSPP_IGC_COLOR0_RAM_LUTN 0x300 +#define DSPP_IGC_COLOR1_RAM_LUTN 0x304 +#define DSPP_IGC_COLOR2_RAM_LUTN 0x308 +#define PPB0_CNTL 0x330 +#define PPB0_CONFIG 0x334 +#define PPB1_CNTL 0x338 +#define PPB1_CONFIG 0x33C +#define PPB2_CNTL 0x370 +#define PPB3_CNTL 0x374 +#define HW_EVENTS_CTL 0x37C +#define CLK_CTRL3 0x3A8 +#define CLK_STATUS3 0x3AC +#define CLK_CTRL4 0x3B0 +#define CLK_STATUS4 0x3B4 +#define CLK_CTRL5 0x3B8 +#define CLK_STATUS5 0x3BC +#define CLK_CTRL7 0x3D0 +#define CLK_STATUS7 0x3D4 +#define SPLIT_DISPLAY_LOWER_PIPE_CTRL 0x3F0 +#define SPLIT_DISPLAY_TE_LINE_INTERVAL 0x3F4 +#define INTF_SW_RESET_MASK 0x3FC +#define HDMI_DP_CORE_SELECT 0x408 +#define MDP_OUT_CTL_0 0x410 +#define MDP_VSYNC_SEL 0x414 +#define DCE_SEL 0x450 + +#define DP_DHDR_MEM_POOL_0_DATA 0x46c +#define DP_DHDR_MEM_POOL_1_DATA 0x470 +#define DP_DHDR_MEM_POOL_0_NUM_BYTES 0x47c +#define DP_DHDR_MEM_POOL_1_NUM_BYTES 0x480 + +/* SDE_SCALER_QSEED3 */ +#define QSEED3_COEF_LUT_OFF 0x100 +#define QSEED3_FILTERS 5 +#define QSEED3_LUT_REGIONS 4 +#define QSEED3_CIRCULAR_LUTS 9 +#define QSEED3_SEPARABLE_LUTS 10 +#define QSEED3_LUT_SIZE 60 +#define QSEED3_DIR_LUT_SIZE (200 * sizeof(u32)) +#define QSEED3_COEF_LUT_DIR_BIT 1 +#define QSEED3_COEF_LUT_Y_CIR_BIT 2 +#define QSEED3_COEF_LUT_UV_CIR_BIT 3 +#define QSEED3_COEF_LUT_Y_SEP_BIT 4 +#define QSEED3_COEF_LUT_UV_SEP_BIT 5 +#define QSEED3_CIR_LUT_SIZE \ + (QSEED3_LUT_SIZE * QSEED3_CIRCULAR_LUTS * sizeof(u32)) +#define QSEED3_SEP_LUT_SIZE \ + (QSEED3_LUT_SIZE * QSEED3_SEPARABLE_LUTS * sizeof(u32)) + +/* SDE_SCALER_QSEED3LITE */ +#define QSEED3L_COEF_LUT_OFF 0x100 +#define QSEED3LITE_FILTERS 2 +#define QSEED3L_SEPARABLE_LUTS 10 +#define QSEED3L_LUT_SIZE 33 +#define QSEED3L_SEP_LUT_SIZE \ + (QSEED3L_LUT_SIZE * QSEED3L_SEPARABLE_LUTS * sizeof(u32)) + +#endif /*_SDE_HWIO_H */ diff --git a/techpack/display/msm/sde/sde_irq.c b/techpack/display/msm/sde/sde_irq.c new file mode 100644 index 0000000000000000000000000000000000000000..e8574156512e449813a5ba32bf4bb76a50f757ae --- /dev/null +++ b/techpack/display/msm/sde/sde_irq.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/irqdomain.h> +#include <linux/irq.h> +#include <linux/kthread.h> + +#include "sde_irq.h" +#include "sde_core_irq.h" + +uint32_t g_sde_irq_status; + +void sde_irq_update(struct msm_kms *msm_kms, bool enable) +{ + struct sde_kms *sde_kms = to_sde_kms(msm_kms); + + if (!msm_kms || !sde_kms) { + SDE_ERROR("invalid kms arguments\n"); + return; + } + + sde_kms->irq_enabled = enable; + + if (enable) + enable_irq(sde_kms->irq_num); + else + disable_irq(sde_kms->irq_num); +} + +irqreturn_t sde_irq(struct msm_kms *kms) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + u32 interrupts; + + sde_kms->hw_intr->ops.get_interrupt_sources(sde_kms->hw_intr, + &interrupts); + + /* store irq status in case of irq-storm debugging */ + g_sde_irq_status = interrupts; + + /* + * Taking care of MDP interrupt + */ + if (interrupts & IRQ_SOURCE_MDP) { + interrupts &= ~IRQ_SOURCE_MDP; + sde_core_irq(sde_kms); + } + + /* + * Routing all other interrupts to external drivers + */ + while (interrupts) { + irq_hw_number_t hwirq = fls(interrupts) - 1; + unsigned int mapping; + int rc; + + mapping = irq_find_mapping(sde_kms->irq_controller.domain, + hwirq); + if (mapping == 0) { + SDE_EVT32(hwirq, SDE_EVTLOG_ERROR); + goto error; + } + + rc = generic_handle_irq(mapping); + if (rc < 0) { + SDE_EVT32(hwirq, mapping, rc, SDE_EVTLOG_ERROR); + goto error; + } + + interrupts &= ~(1 << hwirq); + } + + return IRQ_HANDLED; + +error: + /* bad situation, inform irq system, it may disable overall MDSS irq */ + return IRQ_NONE; +} + +void sde_irq_preinstall(struct msm_kms *kms) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + + if (!sde_kms->dev || !sde_kms->dev->dev) { + pr_err("invalid device handles\n"); + return; + } + + sde_core_irq_preinstall(sde_kms); + + sde_kms->irq_num = platform_get_irq( + to_platform_device(sde_kms->dev->dev), + 0); + if (sde_kms->irq_num < 0) { + SDE_ERROR("invalid irq number %d\n", sde_kms->irq_num); + return; + } + + /* disable irq until power event enables it */ + if (!sde_kms->splash_data.num_splash_displays && !sde_kms->irq_enabled) + irq_set_status_flags(sde_kms->irq_num, IRQ_NOAUTOEN); +} + +int sde_irq_postinstall(struct msm_kms *kms) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + int rc; + + if (!kms) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + rc = sde_core_irq_postinstall(sde_kms); + + return rc; +} + +void sde_irq_uninstall(struct msm_kms *kms) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + + if (!kms) { + SDE_ERROR("invalid parameters\n"); + return; + } + + sde_core_irq_uninstall(sde_kms); + sde_core_irq_domain_fini(sde_kms); +} diff --git a/techpack/display/msm/sde/sde_irq.h b/techpack/display/msm/sde/sde_irq.h new file mode 100644 index 0000000000000000000000000000000000000000..9a23873903ef2ce8a64f2144cf06f92718a3c09d --- /dev/null +++ b/techpack/display/msm/sde/sde_irq.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_IRQ_H__ +#define __SDE_IRQ_H__ + +#include <linux/kernel.h> +#include <linux/irqdomain.h> + +#include "msm_kms.h" + +/** + * sde_irq_controller - define MDSS level interrupt controller context + * @enabled_mask: enable status of MDSS level interrupt + * @domain: interrupt domain of this controller + */ +struct sde_irq_controller { + unsigned long enabled_mask; + struct irq_domain *domain; +}; + +/** + * sde_irq_preinstall - perform pre-installation of MDSS IRQ handler + * @kms: pointer to kms context + * @return: none + */ +void sde_irq_preinstall(struct msm_kms *kms); + +/** + * sde_irq_postinstall - perform post-installation of MDSS IRQ handler + * @kms: pointer to kms context + * @return: 0 if success; error code otherwise + */ +int sde_irq_postinstall(struct msm_kms *kms); + +/** + * sde_irq_uninstall - uninstall MDSS IRQ handler + * @drm_dev: pointer to kms context + * @return: none + */ +void sde_irq_uninstall(struct msm_kms *kms); + +/** + * sde_irq - MDSS level IRQ handler + * @kms: pointer to kms context + * @return: interrupt handling status + */ +irqreturn_t sde_irq(struct msm_kms *kms); + +/** + * sde_irq_update - enable/disable IRQ line + * @kms: pointer to kms context + * @enable: enable:true, disable:false + */ +void sde_irq_update(struct msm_kms *kms, bool enable); + +#endif /* __SDE_IRQ_H__ */ diff --git a/techpack/display/msm/sde/sde_kms.c b/techpack/display/msm/sde/sde_kms.c new file mode 100644 index 0000000000000000000000000000000000000000..ad510d8630e49d15b1a02d398eb1a8da553298f8 --- /dev/null +++ b/techpack/display/msm/sde/sde_kms.c @@ -0,0 +1,3886 @@ +/* + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <drm/drm_crtc.h> +#include <drm/drm_fixed.h> +#include <drm/drm_panel.h> +#include <linux/debugfs.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/dma-buf.h> +#include <linux/memblock.h> +#include <linux/bootmem.h> +#include <soc/qcom/scm.h> + +#include "msm_drv.h" +#include "msm_mmu.h" +#include "msm_gem.h" + +#include "dsi_display.h" +#include "dsi_drm.h" +#include "sde_wb.h" +#include "dp_display.h" +#include "dp_drm.h" + +#include "sde_kms.h" +#include "sde_core_irq.h" +#include "sde_formats.h" +#include "sde_hw_vbif.h" +#include "sde_vbif.h" +#include "sde_encoder.h" +#include "sde_plane.h" +#include "sde_crtc.h" +#include "sde_reg_dma.h" +#include "sde_connector.h" + +#include <soc/qcom/scm.h> +#include "soc/qcom/secure_buffer.h" +#include "soc/qcom/qtee_shmbridge.h" + +#define CREATE_TRACE_POINTS +#include "sde_trace.h" + +/* defines for secure channel call */ +#define MEM_PROTECT_SD_CTRL_SWITCH 0x18 +#define MDP_DEVICE_ID 0x1A + +#define TCSR_DISP_HF_SF_ARES_GLITCH_MASK 0x01FCA084 + +static const char * const iommu_ports[] = { + "mdp_0", +}; + +/** + * Controls size of event log buffer. Specified as a power of 2. + */ +#define SDE_EVTLOG_SIZE 1024 + +/* + * To enable overall DRM driver logging + * # echo 0x2 > /sys/module/drm/parameters/debug + * + * To enable DRM driver h/w logging + * # echo <mask> > /sys/kernel/debug/dri/0/debug/hw_log_mask + * + * See sde_hw_mdss.h for h/w logging mask definitions (search for SDE_DBG_MASK_) + */ +#define SDE_DEBUGFS_DIR "msm_sde" +#define SDE_DEBUGFS_HWMASKNAME "hw_log_mask" + +#define SDE_KMS_MODESET_LOCK_TIMEOUT_US 500 +#define SDE_KMS_MODESET_LOCK_MAX_TRIALS 20 + +#define SDE_KMS_PM_QOS_CPU_DMA_LATENCY 300 + +/** + * sdecustom - enable certain driver customizations for sde clients + * Enabling this modifies the standard DRM behavior slightly and assumes + * that the clients have specific knowledge about the modifications that + * are involved, so don't enable this unless you know what you're doing. + * + * Parts of the driver that are affected by this setting may be located by + * searching for invocations of the 'sde_is_custom_client()' function. + * + * This is disabled by default. + */ +static bool sdecustom = true; +module_param(sdecustom, bool, 0400); +MODULE_PARM_DESC(sdecustom, "Enable customizations for sde clients"); + +static int sde_kms_hw_init(struct msm_kms *kms); +static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms); +static int _sde_kms_mmu_init(struct sde_kms *sde_kms); +static int _sde_kms_register_events(struct msm_kms *kms, + struct drm_mode_object *obj, u32 event, bool en); +bool sde_is_custom_client(void) +{ + return sdecustom; +} + +#ifdef CONFIG_DEBUG_FS +void *sde_debugfs_get_root(struct sde_kms *sde_kms) +{ + struct msm_drm_private *priv; + + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) + return NULL; + + priv = sde_kms->dev->dev_private; + return priv->debug_root; +} + +static int _sde_debugfs_init(struct sde_kms *sde_kms) +{ + void *p; + int rc; + void *debugfs_root; + + p = sde_hw_util_get_log_mask_ptr(); + + if (!sde_kms || !p) + return -EINVAL; + + debugfs_root = sde_debugfs_get_root(sde_kms); + if (!debugfs_root) + return -EINVAL; + + /* allow debugfs_root to be NULL */ + debugfs_create_x32(SDE_DEBUGFS_HWMASKNAME, 0600, debugfs_root, p); + + (void) sde_debugfs_vbif_init(sde_kms, debugfs_root); + (void) sde_debugfs_core_irq_init(sde_kms, debugfs_root); + + rc = sde_core_perf_debugfs_init(&sde_kms->perf, debugfs_root); + if (rc) { + SDE_ERROR("failed to init perf %d\n", rc); + return rc; + } + + if (sde_kms->catalog->qdss_count) + debugfs_create_u32("qdss", 0600, debugfs_root, + (u32 *)&sde_kms->qdss_enabled); + + return 0; +} + +static void _sde_debugfs_destroy(struct sde_kms *sde_kms) +{ + /* don't need to NULL check debugfs_root */ + if (sde_kms) { + sde_debugfs_vbif_destroy(sde_kms); + sde_debugfs_core_irq_destroy(sde_kms); + } +} +#else +static int _sde_debugfs_init(struct sde_kms *sde_kms) +{ + return 0; +} + +static void _sde_debugfs_destroy(struct sde_kms *sde_kms) +{ +} +#endif + +static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + int ret = 0; + + SDE_ATRACE_BEGIN("sde_kms_enable_vblank"); + ret = sde_crtc_vblank(crtc, true); + SDE_ATRACE_END("sde_kms_enable_vblank"); + + return ret; +} + +static void sde_kms_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + SDE_ATRACE_BEGIN("sde_kms_disable_vblank"); + sde_crtc_vblank(crtc, false); + SDE_ATRACE_END("sde_kms_disable_vblank"); +} + +static void sde_kms_wait_for_frame_transfer_complete(struct msm_kms *kms, + struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev; + int ret; + + if (!kms || !crtc || !crtc->state || !crtc->dev) { + SDE_ERROR("invalid params\n"); + return; + } + + if (!crtc->state->enable) { + SDE_DEBUG("[crtc:%d] not enable\n", crtc->base.id); + return; + } + + if (!crtc->state->active) { + SDE_DEBUG("[crtc:%d] not active\n", crtc->base.id); + return; + } + + dev = crtc->dev; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + /* + * Video Mode - Wait for VSYNC + * Cmd Mode - Wait for PP_DONE. Will be no-op if transfer is + * complete + */ + SDE_EVT32_VERBOSE(DRMID(crtc)); + ret = sde_encoder_wait_for_event(encoder, MSM_ENC_TX_COMPLETE); + if (ret && ret != -EWOULDBLOCK) { + SDE_ERROR( + "[crtc: %d][enc: %d] wait for commit done returned %d\n", + crtc->base.id, encoder->base.id, ret); + break; + } + } +} + +static int _sde_kms_secure_ctrl_xin_clients(struct sde_kms *sde_kms, + struct drm_crtc *crtc, bool enable) +{ + struct drm_device *dev; + struct msm_drm_private *priv; + struct sde_mdss_cfg *sde_cfg; + struct drm_plane *plane; + int i, ret; + + dev = sde_kms->dev; + priv = dev->dev_private; + sde_cfg = sde_kms->catalog; + + ret = sde_vbif_halt_xin_mask(sde_kms, + sde_cfg->sui_block_xin_mask, enable); + if (ret) { + SDE_ERROR("failed to halt some xin-clients, ret:%d\n", ret); + return ret; + } + + if (enable) { + for (i = 0; i < priv->num_planes; i++) { + plane = priv->planes[i]; + sde_plane_secure_ctrl_xin_client(plane, crtc); + } + } + + return 0; +} + +/** + * _sde_kms_scm_call - makes secure channel call to switch the VMIDs + * @sde_kms: Pointer to sde_kms struct + * @vimd: switch the stage 2 translation to this VMID + */ +static int _sde_kms_scm_call(struct sde_kms *sde_kms, int vmid) +{ + struct scm_desc desc = {0}; + uint32_t num_sids; + uint32_t *sec_sid; + uint32_t mem_protect_sd_ctrl_id = MEM_PROTECT_SD_CTRL_SWITCH; + struct sde_mdss_cfg *sde_cfg = sde_kms->catalog; + int ret = 0, i; + struct qtee_shm shm; + bool qtee_en = qtee_shmbridge_is_enabled(); + + num_sids = sde_cfg->sec_sid_mask_count; + if (!num_sids) { + SDE_ERROR("secure SID masks not configured, vmid 0x%x\n", vmid); + return -EINVAL; + } + + if (qtee_en) { + ret = qtee_shmbridge_allocate_shm(num_sids * sizeof(uint32_t), + &shm); + if (ret) + return -ENOMEM; + + sec_sid = (uint32_t *) shm.vaddr; + desc.args[1] = shm.paddr; + /** + * SMMUSecureModeSwitch requires the size to be number of SID's + * but shm allocates size in pages. Modify the args as per + * client requirement. + */ + desc.args[2] = sizeof(uint32_t) * num_sids; + } else { + sec_sid = kcalloc(num_sids, sizeof(uint32_t), GFP_KERNEL); + if (!sec_sid) + return -ENOMEM; + + desc.args[1] = SCM_BUFFER_PHYS(sec_sid); + desc.args[2] = sizeof(uint32_t) * num_sids; + } + + desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL); + desc.args[0] = MDP_DEVICE_ID; + desc.args[3] = vmid; + + for (i = 0; i < num_sids; i++) { + sec_sid[i] = sde_cfg->sec_sid_mask[i]; + SDE_DEBUG("sid_mask[%d]: %d\n", i, sec_sid[i]); + } + dmac_flush_range(sec_sid, sec_sid + num_sids); + + SDE_DEBUG("calling scm_call for vmid 0x%x, num_sids %d, qtee_en %d", + vmid, num_sids, qtee_en); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + mem_protect_sd_ctrl_id), &desc); + if (ret) + SDE_ERROR("Error:scm_call2, vmid %lld, ret%d\n", + desc.args[3], ret); + SDE_EVT32(mem_protect_sd_ctrl_id, desc.args[0], desc.args[2], + desc.args[3], qtee_en, num_sids, ret); + + if (qtee_en) + qtee_shmbridge_free_shm(&shm); + else + kfree(sec_sid); + + return ret; +} + +static int _sde_kms_detach_all_cb(struct sde_kms *sde_kms, u32 vmid) +{ + u32 ret; + + if (atomic_inc_return(&sde_kms->detach_all_cb) > 1) + return 0; + + /* detach_all_contexts */ + ret = sde_kms_mmu_detach(sde_kms, false); + if (ret) { + SDE_ERROR("failed to detach all cb ret:%d\n", ret); + goto mmu_error; + } + + ret = _sde_kms_scm_call(sde_kms, vmid); + if (ret) { + SDE_ERROR("scm call failed for vmid:%d\n", vmid); + goto scm_error; + } + + return 0; + +scm_error: + sde_kms_mmu_attach(sde_kms, false); +mmu_error: + atomic_dec(&sde_kms->detach_all_cb); + return ret; +} + +static int _sde_kms_attach_all_cb(struct sde_kms *sde_kms, u32 vmid, + u32 old_vmid) +{ + u32 ret; + + if (atomic_dec_return(&sde_kms->detach_all_cb) != 0) + return 0; + + ret = _sde_kms_scm_call(sde_kms, vmid); + if (ret) { + SDE_ERROR("scm call failed for vmid:%d\n", vmid); + goto scm_error; + } + + /* attach_all_contexts */ + ret = sde_kms_mmu_attach(sde_kms, false); + if (ret) { + SDE_ERROR("failed to attach all cb ret:%d\n", ret); + goto mmu_error; + } + + return 0; + +mmu_error: + _sde_kms_scm_call(sde_kms, old_vmid); +scm_error: + atomic_inc(&sde_kms->detach_all_cb); + return ret; +} + +static int _sde_kms_detach_sec_cb(struct sde_kms *sde_kms, int vmid) +{ + u32 ret; + + if (atomic_inc_return(&sde_kms->detach_sec_cb) > 1) + return 0; + + /* detach secure_context */ + ret = sde_kms_mmu_detach(sde_kms, true); + if (ret) { + SDE_ERROR("failed to detach sec cb ret:%d\n", ret); + goto mmu_error; + } + + ret = _sde_kms_scm_call(sde_kms, vmid); + if (ret) { + SDE_ERROR("scm call failed for vmid:%d\n", vmid); + goto scm_error; + } + + return 0; + +scm_error: + sde_kms_mmu_attach(sde_kms, true); +mmu_error: + atomic_dec(&sde_kms->detach_sec_cb); + return ret; +} + +static int _sde_kms_attach_sec_cb(struct sde_kms *sde_kms, u32 vmid, + u32 old_vmid) +{ + u32 ret; + + if (atomic_dec_return(&sde_kms->detach_sec_cb) != 0) + return 0; + + ret = _sde_kms_scm_call(sde_kms, vmid); + if (ret) { + goto scm_error; + SDE_ERROR("scm call failed for vmid:%d\n", vmid); + } + + ret = sde_kms_mmu_attach(sde_kms, true); + if (ret) { + SDE_ERROR("failed to attach sec cb ret:%d\n", ret); + goto mmu_error; + } + + return 0; + +mmu_error: + _sde_kms_scm_call(sde_kms, old_vmid); +scm_error: + atomic_inc(&sde_kms->detach_sec_cb); + return ret; +} + +static int _sde_kms_sui_misr_ctrl(struct sde_kms *sde_kms, + struct drm_crtc *crtc, bool enable) +{ + int ret; + + if (enable) { + ret = pm_runtime_get_sync(sde_kms->dev->dev); + if (ret < 0) { + SDE_ERROR("failed to enable resource, ret:%d\n", ret); + return ret; + } + + sde_crtc_misr_setup(crtc, true, 1); + + ret = _sde_kms_secure_ctrl_xin_clients(sde_kms, crtc, true); + if (ret) { + sde_crtc_misr_setup(crtc, false, 0); + pm_runtime_put_sync(sde_kms->dev->dev); + return ret; + } + + } else { + _sde_kms_secure_ctrl_xin_clients(sde_kms, crtc, false); + sde_crtc_misr_setup(crtc, false, 0); + pm_runtime_put_sync(sde_kms->dev->dev); + } + + return 0; +} + +static int _sde_kms_secure_ctrl(struct sde_kms *sde_kms, struct drm_crtc *crtc, + bool post_commit) +{ + struct sde_kms_smmu_state_data *smmu_state = &sde_kms->smmu_state; + int old_smmu_state = smmu_state->state; + int ret = 0; + u32 vmid; + + if (!sde_kms || !crtc) { + SDE_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + + SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->transition_type, + post_commit, smmu_state->sui_misr_state, + smmu_state->secure_level, SDE_EVTLOG_FUNC_ENTRY); + + if ((!smmu_state->transition_type) || + ((smmu_state->transition_type == POST_COMMIT) && !post_commit)) + /* Bail out */ + return 0; + + /* enable sui misr if requested, before the transition */ + if (smmu_state->sui_misr_state == SUI_MISR_ENABLE_REQ) { + ret = _sde_kms_sui_misr_ctrl(sde_kms, crtc, true); + if (ret) { + smmu_state->sui_misr_state == NONE; + goto end; + } + } + + mutex_lock(&sde_kms->secure_transition_lock); + switch (smmu_state->state) { + case DETACH_ALL_REQ: + ret = _sde_kms_detach_all_cb(sde_kms, VMID_CP_SEC_DISPLAY); + if (!ret) + smmu_state->state = DETACHED; + break; + + case ATTACH_ALL_REQ: + ret = _sde_kms_attach_all_cb(sde_kms, VMID_CP_PIXEL, + VMID_CP_SEC_DISPLAY); + if (!ret) { + smmu_state->state = ATTACHED; + smmu_state->secure_level = SDE_DRM_SEC_NON_SEC; + } + break; + + case DETACH_SEC_REQ: + vmid = (smmu_state->secure_level == SDE_DRM_SEC_ONLY) ? + VMID_CP_SEC_DISPLAY : VMID_CP_CAMERA_PREVIEW; + + ret = _sde_kms_detach_sec_cb(sde_kms, vmid); + if (!ret) + smmu_state->state = DETACHED_SEC; + break; + + case ATTACH_SEC_REQ: + vmid = (smmu_state->secure_level == SDE_DRM_SEC_ONLY) ? + VMID_CP_SEC_DISPLAY : VMID_CP_CAMERA_PREVIEW; + ret = _sde_kms_attach_sec_cb(sde_kms, VMID_CP_PIXEL, vmid); + if (!ret) { + smmu_state->state = ATTACHED; + smmu_state->secure_level = SDE_DRM_SEC_NON_SEC; + } + break; + + default: + SDE_ERROR("crtc%d: invalid smmu state %d transition type %d\n", + DRMID(crtc), smmu_state->state, + smmu_state->transition_type); + ret = -EINVAL; + break; + } + mutex_unlock(&sde_kms->secure_transition_lock); + + /* disable sui misr if requested, after the transition */ + if (!ret && (smmu_state->sui_misr_state == SUI_MISR_DISABLE_REQ)) { + ret = _sde_kms_sui_misr_ctrl(sde_kms, crtc, false); + if (ret) + goto end; + } + +end: + smmu_state->transition_error = false; + + if (ret) { + smmu_state->transition_error = true; + SDE_ERROR( + "crtc%d: req_state %d, new_state %d, sec_lvl %d, ret %d\n", + DRMID(crtc), old_smmu_state, smmu_state->state, + smmu_state->secure_level, ret); + + smmu_state->state = smmu_state->prev_state; + smmu_state->secure_level = smmu_state->prev_secure_level; + + if (smmu_state->sui_misr_state == SUI_MISR_ENABLE_REQ) + _sde_kms_sui_misr_ctrl(sde_kms, crtc, false); + } + + SDE_DEBUG("crtc %d: req_state %d, new_state %d, sec_lvl %d, ret %d\n", + DRMID(crtc), old_smmu_state, smmu_state->state, + smmu_state->secure_level, ret); + SDE_EVT32(DRMID(crtc), smmu_state->state, smmu_state->prev_state, + smmu_state->transition_type, + smmu_state->transition_error, + smmu_state->secure_level, smmu_state->prev_secure_level, + smmu_state->sui_misr_state, ret, SDE_EVTLOG_FUNC_EXIT); + + smmu_state->sui_misr_state = NONE; + smmu_state->transition_type = NONE; + + return ret; +} + +static int sde_kms_prepare_secure_transition(struct msm_kms *kms, + struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_plane_state *old_plane_state, *new_plane_state; + + struct drm_plane *plane; + struct drm_plane_state *plane_state; + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev = sde_kms->dev; + int i, ops = 0, ret = 0; + bool old_valid_fb = false; + struct sde_kms_smmu_state_data *smmu_state = &sde_kms->smmu_state; + + for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) { + if (!crtc->state || !crtc->state->active) + continue; + /* + * It is safe to assume only one active crtc, + * and compatible translation modes on the + * planes staged on this crtc. + * otherwise validation would have failed. + * For this CRTC, + */ + + /* + * 1. Check if old state on the CRTC has planes + * staged with valid fbs + */ + for_each_old_plane_in_state(state, plane, plane_state, i) { + if (!plane_state->crtc) + continue; + if (plane_state->fb) { + old_valid_fb = true; + break; + } + } + + /* + * 2.Get the operations needed to be performed before + * secure transition can be initiated. + */ + ops = sde_crtc_get_secure_transition_ops(crtc, + old_crtc_state, old_valid_fb); + if (ops < 0) { + SDE_ERROR("invalid secure operations %x\n", ops); + return ops; + } + + if (!ops) { + smmu_state->transition_error = false; + goto no_ops; + } + + SDE_DEBUG("%d:secure operations(%x) started on state:%pK\n", + crtc->base.id, ops, crtc->state); + SDE_EVT32(DRMID(crtc), ops, crtc->state, old_valid_fb); + + /* 3. Perform operations needed for secure transition */ + if (ops & SDE_KMS_OPS_WAIT_FOR_TX_DONE) { + SDE_DEBUG("wait_for_transfer_done\n"); + sde_kms_wait_for_frame_transfer_complete(kms, crtc); + } + if (ops & SDE_KMS_OPS_CLEANUP_PLANE_FB) { + SDE_DEBUG("cleanup planes\n"); + drm_atomic_helper_cleanup_planes(dev, state); + for_each_oldnew_plane_in_state(state, plane, + old_plane_state, new_plane_state, i) + sde_plane_destroy_fb(old_plane_state); + } + if (ops & SDE_KMS_OPS_SECURE_STATE_CHANGE) { + SDE_DEBUG("secure ctrl\n"); + _sde_kms_secure_ctrl(sde_kms, crtc, false); + } + if (ops & SDE_KMS_OPS_PREPARE_PLANE_FB) { + SDE_DEBUG("prepare planes %d", + crtc->state->plane_mask); + drm_atomic_crtc_for_each_plane(plane, + crtc) { + const struct drm_plane_helper_funcs *funcs; + + plane_state = plane->state; + funcs = plane->helper_private; + + SDE_DEBUG("psde:%d FB[%u]\n", + plane->base.id, + plane->fb->base.id); + if (!funcs) + continue; + + if (funcs->prepare_fb(plane, plane_state)) { + ret = funcs->prepare_fb(plane, + plane_state); + if (ret) + return ret; + } + } + } + SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT); + SDE_DEBUG("secure operations completed\n"); + } + +no_ops: + return 0; +} + +static void _sde_clear_boot_config(struct sde_boot_config *boot_cfg) +{ + if (!boot_cfg) + return; + + SDE_IMEM_WRITE(&boot_cfg->header, 0x0); + SDE_IMEM_WRITE(&boot_cfg->addr1, 0x0); + SDE_IMEM_WRITE(&boot_cfg->addr2, 0x0); +} + +static int _sde_kms_release_splash_buffer(struct sde_kms *sde_kms, + unsigned int mem_addr, + unsigned int splash_buffer_size, + unsigned int ramdump_base, + unsigned int ramdump_buffer_size) +{ + unsigned long pfn_start, pfn_end, pfn_idx; + int ret = 0; + struct sde_boot_config *boot_cfg = sde_kms->imem; + + if (!mem_addr || !splash_buffer_size) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + /* leave ramdump memory only if base address matches */ + if (ramdump_base == mem_addr && + ramdump_buffer_size <= splash_buffer_size) { + mem_addr += ramdump_buffer_size; + splash_buffer_size -= ramdump_buffer_size; + } + + if (!ramdump_base) + _sde_clear_boot_config(boot_cfg); + + pfn_start = mem_addr >> PAGE_SHIFT; + pfn_end = (mem_addr + splash_buffer_size) >> PAGE_SHIFT; + + ret = memblock_free(mem_addr, splash_buffer_size); + if (ret) { + SDE_ERROR("continuous splash memory free failed:%d\n", ret); + return ret; + } + for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++) + free_reserved_page(pfn_to_page(pfn_idx)); + + return ret; + +} + +static int _sde_kms_splash_mem_get(struct sde_kms *sde_kms, + struct sde_splash_mem *splash) +{ + struct msm_mmu *mmu = NULL; + int ret = 0; + + if (!sde_kms->aspace[0]) { + SDE_ERROR("aspace not found for sde kms node\n"); + return -EINVAL; + } + + mmu = sde_kms->aspace[0]->mmu; + if (!mmu) { + SDE_ERROR("mmu not found for aspace\n"); + return -EINVAL; + } + + if (!splash || !mmu->funcs || !mmu->funcs->one_to_one_map) { + SDE_ERROR("invalid input params for map\n"); + return -EINVAL; + } + + if (!splash->ref_cnt) { + ret = mmu->funcs->one_to_one_map(mmu, splash->splash_buf_base, + splash->splash_buf_base, + splash->splash_buf_size, + IOMMU_READ | IOMMU_NOEXEC); + if (ret) + SDE_ERROR("splash memory smmu map failed:%d\n", ret); + } + + splash->ref_cnt++; + SDE_DEBUG("one2one mapping done for base:%lx size:%x ref_cnt:%d\n", + splash->splash_buf_base, + splash->splash_buf_size, + splash->ref_cnt); + + return ret; +} + +static int _sde_kms_map_all_splash_regions(struct sde_kms *sde_kms) +{ + int i = 0; + int ret = 0; + + if (!sde_kms) + return -EINVAL; + + for (i = 0; i < sde_kms->splash_data.num_splash_displays; i++) { + ret = _sde_kms_splash_mem_get(sde_kms, + sde_kms->splash_data.splash_display[i].splash); + if (ret) + return ret; + } + + return ret; +} + +static int _sde_kms_splash_mem_put(struct sde_kms *sde_kms, + struct sde_splash_mem *splash) +{ + struct msm_mmu *mmu = NULL; + int rc = 0; + + if (!sde_kms || !sde_kms->aspace[0] || !sde_kms->aspace[0]->mmu) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + mmu = sde_kms->aspace[0]->mmu; + + if (!splash || !splash->ref_cnt || + !mmu || !mmu->funcs || !mmu->funcs->one_to_one_unmap) + return -EINVAL; + + splash->ref_cnt--; + + SDE_DEBUG("splash base:%lx refcnt:%d\n", + splash->splash_buf_base, splash->ref_cnt); + + if (!splash->ref_cnt) { + mmu->funcs->one_to_one_unmap(mmu, splash->splash_buf_base, + splash->splash_buf_size); + rc = _sde_kms_release_splash_buffer(sde_kms, + splash->splash_buf_base, splash->splash_buf_size, + splash->ramdump_base, splash->ramdump_size); + splash->splash_buf_base = 0; + splash->splash_buf_size = 0; + } + + return rc; +} + +static int _sde_kms_unmap_all_splash_regions(struct sde_kms *sde_kms) +{ + int i = 0; + int ret = 0; + + if (!sde_kms) + return -EINVAL; + + for (i = 0; i < sde_kms->splash_data.num_splash_displays; i++) { + ret = _sde_kms_splash_mem_put(sde_kms, + sde_kms->splash_data.splash_display[i].splash); + if (ret) + return ret; + } + + return ret; +} + +static int _sde_kms_get_blank(struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + int lp_mode, blank; + + if (crtc_state->active) + lp_mode = sde_connector_get_property(conn_state, + CONNECTOR_PROP_LP); + else + lp_mode = SDE_MODE_DPMS_OFF; + + switch (lp_mode) { + case SDE_MODE_DPMS_ON: + blank = DRM_PANEL_BLANK_UNBLANK; + break; + case SDE_MODE_DPMS_LP1: + case SDE_MODE_DPMS_LP2: + blank = DRM_PANEL_BLANK_LP; + break; + case SDE_MODE_DPMS_OFF: + default: + blank = DRM_PANEL_BLANK_POWERDOWN; + break; + } + + return blank; +} + +static void _sde_kms_drm_check_dpms(struct drm_atomic_state *old_state, + unsigned long event) +{ + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + struct drm_crtc_state *old_crtc_state; + struct drm_crtc *crtc; + int i, old_mode, new_mode, old_fps, new_fps; + + for_each_old_connector_in_state(old_state, connector, + old_conn_state, i) { + crtc = connector->state->crtc ? connector->state->crtc : + old_conn_state->crtc; + if (!crtc) + continue; + + new_fps = crtc->state->mode.vrefresh; + new_mode = _sde_kms_get_blank(crtc->state, connector->state); + if (old_conn_state->crtc) { + old_crtc_state = drm_atomic_get_existing_crtc_state( + old_state, old_conn_state->crtc); + + old_fps = old_crtc_state->mode.vrefresh; + old_mode = _sde_kms_get_blank(old_crtc_state, + old_conn_state); + } else { + old_fps = 0; + old_mode = DRM_PANEL_BLANK_POWERDOWN; + } + + if ((old_mode != new_mode) || (old_fps != new_fps)) { + struct drm_panel_notifier notifier_data; + + SDE_EVT32(old_mode, new_mode, old_fps, new_fps, + connector->panel, crtc->state->active, + old_conn_state->crtc, event); + pr_debug("change detected (power mode %d->%d, fps %d->%d)\n", + old_mode, new_mode, old_fps, new_fps); + + /* If suspend resume and fps change are happening + * at the same time, give preference to power mode + * changes rather than fps change. + */ + + if ((old_mode == new_mode) && (old_fps != new_fps)) + new_mode = DRM_PANEL_BLANK_FPS_CHANGE; + + notifier_data.data = &new_mode; + notifier_data.refresh_rate = new_fps; + notifier_data.id = connector->base.id; + + if (connector->panel) + drm_panel_notifier_call_chain(connector->panel, + event, ¬ifier_data); + } + } +} + +static void sde_kms_prepare_commit(struct msm_kms *kms, + struct drm_atomic_state *state) +{ + struct sde_kms *sde_kms; + struct msm_drm_private *priv; + struct drm_device *dev; + struct drm_encoder *encoder; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, rc; + + if (!kms) + return; + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + + if (!dev || !dev->dev_private) + return; + priv = dev->dev_private; + + SDE_ATRACE_BEGIN("prepare_commit"); + rc = pm_runtime_get_sync(sde_kms->dev->dev); + if (rc < 0) { + SDE_ERROR("failed to enable power resources %d\n", rc); + SDE_EVT32(rc, SDE_EVTLOG_ERROR); + goto end; + } + + if (sde_kms->first_kickoff) { + sde_power_scale_reg_bus(&priv->phandle, VOTE_INDEX_HIGH, false); + sde_kms->first_kickoff = false; + } + + for_each_old_crtc_in_state(state, crtc, crtc_state, i) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + head) { + if (encoder->crtc != crtc) + continue; + + if (sde_encoder_prepare_commit(encoder) == -ETIMEDOUT) { + SDE_ERROR("crtc:%d, initiating hw reset\n", + DRMID(crtc)); + sde_encoder_needs_hw_reset(encoder); + sde_crtc_set_needs_hw_reset(crtc); + } + } + } + + /* + * NOTE: for secure use cases we want to apply the new HW + * configuration only after completing preparation for secure + * transitions prepare below if any transtions is required. + */ + sde_kms_prepare_secure_transition(kms, state); + + _sde_kms_drm_check_dpms(state, DRM_PANEL_EARLY_EVENT_BLANK); +end: + SDE_ATRACE_END("prepare_commit"); +} + +static void sde_kms_commit(struct msm_kms *kms, + struct drm_atomic_state *old_state) +{ + struct sde_kms *sde_kms; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + int i; + + if (!kms || !old_state) + return; + sde_kms = to_sde_kms(kms); + + if (!sde_kms_power_resource_is_enabled(sde_kms->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + SDE_ATRACE_BEGIN("sde_kms_commit"); + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { + if (crtc->state->active) { + SDE_EVT32(DRMID(crtc)); + sde_crtc_commit_kickoff(crtc, old_crtc_state); + } + } + + SDE_ATRACE_END("sde_kms_commit"); +} + +static void _sde_kms_free_splash_region(struct sde_kms *sde_kms, + struct sde_splash_display *splash_display) +{ + if (!sde_kms || !splash_display || + !sde_kms->splash_data.num_splash_displays) + return; + + _sde_kms_splash_mem_put(sde_kms, splash_display->splash); + sde_kms->splash_data.num_splash_displays--; + SDE_DEBUG("cont_splash handoff done, remaining:%d\n", + sde_kms->splash_data.num_splash_displays); + memset(splash_display, 0x0, sizeof(struct sde_splash_display)); +} + +static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms, + struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + struct sde_splash_display *splash_display; + int i; + + if (!sde_kms || !crtc) + return; + + priv = sde_kms->dev->dev_private; + + if (!crtc->state->active || !sde_kms->splash_data.num_splash_displays) + return; + + SDE_EVT32(DRMID(crtc), crtc->state->active, + sde_kms->splash_data.num_splash_displays); + + for (i = 0; i < MAX_DSI_DISPLAYS; i++) { + splash_display = &sde_kms->splash_data.splash_display[i]; + if (splash_display->encoder && + crtc == splash_display->encoder->crtc) + break; + } + + if (i >= MAX_DSI_DISPLAYS) + return; + + if (splash_display->cont_splash_enabled) { + sde_encoder_update_caps_for_cont_splash(splash_display->encoder, + splash_display, false); + _sde_kms_free_splash_region(sde_kms, splash_display); + } + + /* remove the votes if all displays are done with splash */ + if (!sde_kms->splash_data.num_splash_displays) { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(&priv->phandle, i, + SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + + pm_runtime_put_sync(sde_kms->dev->dev); + } +} + +static void sde_kms_check_for_ext_vote(struct sde_kms *sde_kms, + struct sde_power_handle *phandle) +{ + struct sde_crtc *sde_crtc; + struct drm_crtc *crtc; + struct drm_device *dev; + bool crtc_enabled = false; + + if (!sde_kms->catalog->allow_gdsc_toggle) + return; + + dev = sde_kms->dev; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + sde_crtc = to_sde_crtc(crtc); + if (sde_crtc->enabled) + crtc_enabled = true; + } + + mutex_lock(&phandle->ext_client_lock); + + /* In some targets, a gdsc toggle is needed after crtc is disabled. + * There are some scenarios where presence of an external vote like + * secure vote which can prevent this from happening. In those + * cases, allow the target to go through a gdsc toggle after + * crtc is disabled. + */ + if (!crtc_enabled && phandle->is_ext_vote_en) { + pm_runtime_put_sync(sde_kms->dev->dev); + SDE_EVT32(phandle->is_ext_vote_en); + pm_runtime_get_sync(sde_kms->dev->dev); + } + + mutex_unlock(&phandle->ext_client_lock); +} + +static void sde_kms_complete_commit(struct msm_kms *kms, + struct drm_atomic_state *old_state) +{ + struct sde_kms *sde_kms; + struct msm_drm_private *priv; + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + struct drm_connector *connector; + struct drm_connector_state *old_conn_state; + struct msm_display_conn_params params; + int i, rc = 0; + + if (!kms || !old_state) + return; + sde_kms = to_sde_kms(kms); + + if (!sde_kms->dev || !sde_kms->dev->dev_private) + return; + priv = sde_kms->dev->dev_private; + + if (sde_kms_power_resource_is_enabled(sde_kms->dev) < 0) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + SDE_ATRACE_BEGIN("sde_kms_complete_commit"); + + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { + sde_crtc_complete_commit(crtc, old_crtc_state); + + /* complete secure transitions if any */ + if (sde_kms->smmu_state.transition_type == POST_COMMIT) + _sde_kms_secure_ctrl(sde_kms, crtc, true); + } + + for_each_old_connector_in_state(old_state, connector, + old_conn_state, i) { + struct sde_connector *c_conn; + + c_conn = to_sde_connector(connector); + if (!c_conn->ops.post_kickoff) + continue; + + memset(¶ms, 0, sizeof(params)); + + sde_connector_complete_qsync_commit(connector, ¶ms); + + rc = c_conn->ops.post_kickoff(connector, ¶ms); + if (rc) { + pr_err("Connector Post kickoff failed rc=%d\n", + rc); + } + } + + _sde_kms_drm_check_dpms(old_state, DRM_PANEL_EVENT_BLANK); + + pm_runtime_put_sync(sde_kms->dev->dev); + + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) + _sde_kms_release_splash_resource(sde_kms, crtc); + + sde_kms_check_for_ext_vote(sde_kms, &priv->phandle); + + SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT); + SDE_ATRACE_END("sde_kms_complete_commit"); +} + +static void sde_kms_wait_for_commit_done(struct msm_kms *kms, + struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev; + int ret; + + if (!kms || !crtc || !crtc->state) { + SDE_ERROR("invalid params\n"); + return; + } + + dev = crtc->dev; + + if (!crtc->state->enable) { + SDE_DEBUG("[crtc:%d] not enable\n", crtc->base.id); + return; + } + + if (!crtc->state->active) { + SDE_DEBUG("[crtc:%d] not active\n", crtc->base.id); + return; + } + + if (!sde_kms_power_resource_is_enabled(crtc->dev)) { + SDE_ERROR("power resource is not enabled\n"); + return; + } + + SDE_ATRACE_BEGIN("sde_kms_wait_for_commit_done"); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + /* + * Wait for post-flush if necessary to delay before + * plane_cleanup. For example, wait for vsync in case of video + * mode panels. This may be a no-op for command mode panels. + */ + SDE_EVT32_VERBOSE(DRMID(crtc)); + ret = sde_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE); + if (ret && ret != -EWOULDBLOCK) { + SDE_ERROR("wait for commit done returned %d\n", ret); + sde_crtc_request_frame_reset(crtc); + break; + } + + sde_crtc_complete_flip(crtc, NULL); + } + + SDE_ATRACE_END("sde_ksm_wait_for_commit_done"); +} + +static void sde_kms_prepare_fence(struct msm_kms *kms, + struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *old_crtc_state; + int i; + + if (!kms || !old_state || !old_state->dev || !old_state->acquire_ctx) { + SDE_ERROR("invalid argument(s)\n"); + return; + } + + SDE_ATRACE_BEGIN("sde_kms_prepare_fence"); + + /* old_state actually contains updated crtc pointers */ + for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { + if (crtc->state->active || crtc->state->active_changed) + sde_crtc_prepare_commit(crtc, old_crtc_state); + } + + SDE_ATRACE_END("sde_kms_prepare_fence"); +} + +/** + * _sde_kms_get_displays - query for underlying display handles and cache them + * @sde_kms: Pointer to sde kms structure + * Returns: Zero on success + */ +static int _sde_kms_get_displays(struct sde_kms *sde_kms) +{ + int rc = -ENOMEM; + + if (!sde_kms) { + SDE_ERROR("invalid sde kms\n"); + return -EINVAL; + } + + /* dsi */ + sde_kms->dsi_displays = NULL; + sde_kms->dsi_display_count = dsi_display_get_num_of_displays(); + if (sde_kms->dsi_display_count) { + sde_kms->dsi_displays = kcalloc(sde_kms->dsi_display_count, + sizeof(void *), + GFP_KERNEL); + if (!sde_kms->dsi_displays) { + SDE_ERROR("failed to allocate dsi displays\n"); + goto exit_deinit_dsi; + } + sde_kms->dsi_display_count = + dsi_display_get_active_displays(sde_kms->dsi_displays, + sde_kms->dsi_display_count); + } + + /* wb */ + sde_kms->wb_displays = NULL; + sde_kms->wb_display_count = sde_wb_get_num_of_displays(); + if (sde_kms->wb_display_count) { + sde_kms->wb_displays = kcalloc(sde_kms->wb_display_count, + sizeof(void *), + GFP_KERNEL); + if (!sde_kms->wb_displays) { + SDE_ERROR("failed to allocate wb displays\n"); + goto exit_deinit_wb; + } + sde_kms->wb_display_count = + wb_display_get_displays(sde_kms->wb_displays, + sde_kms->wb_display_count); + } + + /* dp */ + sde_kms->dp_displays = NULL; + sde_kms->dp_display_count = dp_display_get_num_of_displays(); + if (sde_kms->dp_display_count) { + sde_kms->dp_displays = kcalloc(sde_kms->dp_display_count, + sizeof(void *), GFP_KERNEL); + if (!sde_kms->dp_displays) { + SDE_ERROR("failed to allocate dp displays\n"); + goto exit_deinit_dp; + } + sde_kms->dp_display_count = + dp_display_get_displays(sde_kms->dp_displays, + sde_kms->dp_display_count); + + sde_kms->dp_stream_count = dp_display_get_num_of_streams(); + } + return 0; + +exit_deinit_dp: + kfree(sde_kms->dp_displays); + sde_kms->dp_stream_count = 0; + sde_kms->dp_display_count = 0; + sde_kms->dp_displays = NULL; + +exit_deinit_wb: + kfree(sde_kms->wb_displays); + sde_kms->wb_display_count = 0; + sde_kms->wb_displays = NULL; + +exit_deinit_dsi: + kfree(sde_kms->dsi_displays); + sde_kms->dsi_display_count = 0; + sde_kms->dsi_displays = NULL; + return rc; +} + +/** + * _sde_kms_release_displays - release cache of underlying display handles + * @sde_kms: Pointer to sde kms structure + */ +static void _sde_kms_release_displays(struct sde_kms *sde_kms) +{ + if (!sde_kms) { + SDE_ERROR("invalid sde kms\n"); + return; + } + + kfree(sde_kms->wb_displays); + sde_kms->wb_displays = NULL; + sde_kms->wb_display_count = 0; + + kfree(sde_kms->dsi_displays); + sde_kms->dsi_displays = NULL; + sde_kms->dsi_display_count = 0; +} + +/** + * _sde_kms_setup_displays - create encoders, bridges and connectors + * for underlying displays + * @dev: Pointer to drm device structure + * @priv: Pointer to private drm device data + * @sde_kms: Pointer to sde kms structure + * Returns: Zero on success + */ +static int _sde_kms_setup_displays(struct drm_device *dev, + struct msm_drm_private *priv, + struct sde_kms *sde_kms) +{ + static const struct sde_connector_ops dsi_ops = { + .set_info_blob = dsi_conn_set_info_blob, + .detect = dsi_conn_detect, + .get_modes = dsi_connector_get_modes, + .pre_destroy = dsi_connector_put_modes, + .mode_valid = dsi_conn_mode_valid, + .get_info = dsi_display_get_info, + .set_backlight = dsi_display_set_backlight, + .soft_reset = dsi_display_soft_reset, + .pre_kickoff = dsi_conn_pre_kickoff, + .clk_ctrl = dsi_display_clk_ctrl, + .set_power = dsi_display_set_power, + .get_mode_info = dsi_conn_get_mode_info, + .get_dst_format = dsi_display_get_dst_format, + .post_kickoff = dsi_conn_post_kickoff, + .check_status = dsi_display_check_status, + .enable_event = dsi_conn_enable_event, + .cmd_transfer = dsi_display_cmd_transfer, + .cont_splash_config = dsi_display_cont_splash_config, + .get_panel_vfp = dsi_display_get_panel_vfp, + .get_default_lms = dsi_display_get_default_lms, + }; + static const struct sde_connector_ops wb_ops = { + .post_init = sde_wb_connector_post_init, + .set_info_blob = sde_wb_connector_set_info_blob, + .detect = sde_wb_connector_detect, + .get_modes = sde_wb_connector_get_modes, + .set_property = sde_wb_connector_set_property, + .get_info = sde_wb_get_info, + .soft_reset = NULL, + .get_mode_info = sde_wb_get_mode_info, + .get_dst_format = NULL, + .check_status = NULL, + .cmd_transfer = NULL, + .cont_splash_config = NULL, + .get_panel_vfp = NULL, + }; + static const struct sde_connector_ops dp_ops = { + .post_init = dp_connector_post_init, + .detect = dp_connector_detect, + .get_modes = dp_connector_get_modes, + .atomic_check = dp_connector_atomic_check, + .mode_valid = dp_connector_mode_valid, + .get_info = dp_connector_get_info, + .get_mode_info = dp_connector_get_mode_info, + .post_open = dp_connector_post_open, + .check_status = NULL, + .set_colorspace = dp_connector_set_colorspace, + .config_hdr = dp_connector_config_hdr, + .cmd_transfer = NULL, + .cont_splash_config = NULL, + .get_panel_vfp = NULL, + .update_pps = dp_connector_update_pps, + }; + struct msm_display_info info; + struct drm_encoder *encoder; + void *display, *connector; + int i, max_encoders; + int rc = 0; + + if (!dev || !priv || !sde_kms) { + SDE_ERROR("invalid argument(s)\n"); + return -EINVAL; + } + + max_encoders = sde_kms->dsi_display_count + sde_kms->wb_display_count + + sde_kms->dp_display_count + + sde_kms->dp_stream_count; + if (max_encoders > ARRAY_SIZE(priv->encoders)) { + max_encoders = ARRAY_SIZE(priv->encoders); + SDE_ERROR("capping number of displays to %d", max_encoders); + } + + /* dsi */ + for (i = 0; i < sde_kms->dsi_display_count && + priv->num_encoders < max_encoders; ++i) { + display = sde_kms->dsi_displays[i]; + encoder = NULL; + + memset(&info, 0x0, sizeof(info)); + rc = dsi_display_get_info(NULL, &info, display); + if (rc) { + SDE_ERROR("dsi get_info %d failed\n", i); + continue; + } + + encoder = sde_encoder_init(dev, &info); + if (IS_ERR_OR_NULL(encoder)) { + SDE_ERROR("encoder init failed for dsi %d\n", i); + continue; + } + + rc = dsi_display_drm_bridge_init(display, encoder); + if (rc) { + SDE_ERROR("dsi bridge %d init failed, %d\n", i, rc); + sde_encoder_destroy(encoder); + continue; + } + + connector = sde_connector_init(dev, + encoder, + dsi_display_get_drm_panel(display), + display, + &dsi_ops, + DRM_CONNECTOR_POLL_HPD, + DRM_MODE_CONNECTOR_DSI); + if (connector) { + priv->encoders[priv->num_encoders++] = encoder; + priv->connectors[priv->num_connectors++] = connector; + } else { + SDE_ERROR("dsi %d connector init failed\n", i); + dsi_display_drm_bridge_deinit(display); + sde_encoder_destroy(encoder); + continue; + } + + rc = dsi_display_drm_ext_bridge_init(display, + encoder, connector); + if (rc) { + SDE_ERROR("dsi %d ext bridge init failed\n", rc); + dsi_display_drm_bridge_deinit(display); + sde_connector_destroy(connector); + sde_encoder_destroy(encoder); + } + } + + + /* wb */ + for (i = 0; i < sde_kms->wb_display_count && + priv->num_encoders < max_encoders; ++i) { + display = sde_kms->wb_displays[i]; + encoder = NULL; + + memset(&info, 0x0, sizeof(info)); + rc = sde_wb_get_info(NULL, &info, display); + if (rc) { + SDE_ERROR("wb get_info %d failed\n", i); + continue; + } + + encoder = sde_encoder_init(dev, &info); + if (IS_ERR_OR_NULL(encoder)) { + SDE_ERROR("encoder init failed for wb %d\n", i); + continue; + } + + rc = sde_wb_drm_init(display, encoder); + if (rc) { + SDE_ERROR("wb bridge %d init failed, %d\n", i, rc); + sde_encoder_destroy(encoder); + continue; + } + + connector = sde_connector_init(dev, + encoder, + 0, + display, + &wb_ops, + DRM_CONNECTOR_POLL_HPD, + DRM_MODE_CONNECTOR_VIRTUAL); + if (connector) { + priv->encoders[priv->num_encoders++] = encoder; + priv->connectors[priv->num_connectors++] = connector; + } else { + SDE_ERROR("wb %d connector init failed\n", i); + sde_wb_drm_deinit(display); + sde_encoder_destroy(encoder); + } + } + /* dp */ + for (i = 0; i < sde_kms->dp_display_count && + priv->num_encoders < max_encoders; ++i) { + int idx; + + display = sde_kms->dp_displays[i]; + encoder = NULL; + + memset(&info, 0x0, sizeof(info)); + rc = dp_connector_get_info(NULL, &info, display); + if (rc) { + SDE_ERROR("dp get_info %d failed\n", i); + continue; + } + + encoder = sde_encoder_init(dev, &info); + if (IS_ERR_OR_NULL(encoder)) { + SDE_ERROR("dp encoder init failed %d\n", i); + continue; + } + + rc = dp_drm_bridge_init(display, encoder); + if (rc) { + SDE_ERROR("dp bridge %d init failed, %d\n", i, rc); + sde_encoder_destroy(encoder); + continue; + } + + connector = sde_connector_init(dev, + encoder, + NULL, + display, + &dp_ops, + DRM_CONNECTOR_POLL_HPD, + DRM_MODE_CONNECTOR_DisplayPort); + if (connector) { + priv->encoders[priv->num_encoders++] = encoder; + priv->connectors[priv->num_connectors++] = connector; + } else { + SDE_ERROR("dp %d connector init failed\n", i); + dp_drm_bridge_deinit(display); + sde_encoder_destroy(encoder); + } + + /* update display cap to MST_MODE for DP MST encoders */ + info.capabilities |= MSM_DISPLAY_CAP_MST_MODE; + sde_kms->dp_stream_count = dp_display_get_num_of_streams(); + for (idx = 0; idx < sde_kms->dp_stream_count && + priv->num_encoders < max_encoders; idx++) { + info.h_tile_instance[0] = idx; + encoder = sde_encoder_init(dev, &info); + if (IS_ERR_OR_NULL(encoder)) { + SDE_ERROR("dp mst encoder init failed %d\n", i); + continue; + } + + rc = dp_mst_drm_bridge_init(display, encoder); + if (rc) { + SDE_ERROR("dp mst bridge %d init failed, %d\n", + i, rc); + sde_encoder_destroy(encoder); + continue; + } + priv->encoders[priv->num_encoders++] = encoder; + } + } + + return 0; +} + +static void _sde_kms_drm_obj_destroy(struct sde_kms *sde_kms) +{ + struct msm_drm_private *priv; + int i; + + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return; + } else if (!sde_kms->dev) { + SDE_ERROR("invalid dev\n"); + return; + } else if (!sde_kms->dev->dev_private) { + SDE_ERROR("invalid dev_private\n"); + return; + } + priv = sde_kms->dev->dev_private; + + for (i = 0; i < priv->num_crtcs; i++) + priv->crtcs[i]->funcs->destroy(priv->crtcs[i]); + priv->num_crtcs = 0; + + for (i = 0; i < priv->num_planes; i++) + priv->planes[i]->funcs->destroy(priv->planes[i]); + priv->num_planes = 0; + + for (i = 0; i < priv->num_connectors; i++) + priv->connectors[i]->funcs->destroy(priv->connectors[i]); + priv->num_connectors = 0; + + for (i = 0; i < priv->num_encoders; i++) + priv->encoders[i]->funcs->destroy(priv->encoders[i]); + priv->num_encoders = 0; + + _sde_kms_release_displays(sde_kms); +} + +static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) +{ + struct drm_device *dev; + struct drm_plane *primary_planes[MAX_PLANES], *plane; + struct drm_crtc *crtc; + + struct msm_drm_private *priv; + struct sde_mdss_cfg *catalog; + + int primary_planes_idx = 0, i, ret; + int max_crtc_count; + + u32 sspp_id[MAX_PLANES]; + u32 master_plane_id[MAX_PLANES]; + u32 num_virt_planes = 0; + + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) { + SDE_ERROR("invalid sde_kms\n"); + return -EINVAL; + } + + dev = sde_kms->dev; + priv = dev->dev_private; + catalog = sde_kms->catalog; + + ret = sde_core_irq_domain_add(sde_kms); + if (ret) + goto fail_irq; + /* + * Query for underlying display drivers, and create connectors, + * bridges and encoders for them. + */ + if (!_sde_kms_get_displays(sde_kms)) + (void)_sde_kms_setup_displays(dev, priv, sde_kms); + + max_crtc_count = min(catalog->mixer_count, priv->num_encoders); + + /* Create the planes */ + for (i = 0; i < catalog->sspp_count; i++) { + bool primary = true; + + if (catalog->sspp[i].features & BIT(SDE_SSPP_CURSOR) + || primary_planes_idx >= max_crtc_count) + primary = false; + + plane = sde_plane_init(dev, catalog->sspp[i].id, primary, + (1UL << max_crtc_count) - 1, 0); + if (IS_ERR(plane)) { + SDE_ERROR("sde_plane_init failed\n"); + ret = PTR_ERR(plane); + goto fail; + } + priv->planes[priv->num_planes++] = plane; + + if (primary) + primary_planes[primary_planes_idx++] = plane; + + if (sde_hw_sspp_multirect_enabled(&catalog->sspp[i]) && + sde_is_custom_client()) { + int priority = + catalog->sspp[i].sblk->smart_dma_priority; + sspp_id[priority - 1] = catalog->sspp[i].id; + master_plane_id[priority - 1] = plane->base.id; + num_virt_planes++; + } + } + + /* Initialize smart DMA virtual planes */ + for (i = 0; i < num_virt_planes; i++) { + plane = sde_plane_init(dev, sspp_id[i], false, + (1UL << max_crtc_count) - 1, master_plane_id[i]); + if (IS_ERR(plane)) { + SDE_ERROR("sde_plane for virtual SSPP init failed\n"); + ret = PTR_ERR(plane); + goto fail; + } + priv->planes[priv->num_planes++] = plane; + } + + max_crtc_count = min(max_crtc_count, primary_planes_idx); + + /* Create one CRTC per encoder */ + for (i = 0; i < max_crtc_count; i++) { + crtc = sde_crtc_init(dev, primary_planes[i]); + if (IS_ERR(crtc)) { + ret = PTR_ERR(crtc); + goto fail; + } + priv->crtcs[priv->num_crtcs++] = crtc; + } + + if (sde_is_custom_client()) { + /* All CRTCs are compatible with all planes */ + for (i = 0; i < priv->num_planes; i++) + priv->planes[i]->possible_crtcs = + (1 << priv->num_crtcs) - 1; + } + + /* All CRTCs are compatible with all encoders */ + for (i = 0; i < priv->num_encoders; i++) + priv->encoders[i]->possible_crtcs = (1 << priv->num_crtcs) - 1; + + return 0; +fail: + _sde_kms_drm_obj_destroy(sde_kms); +fail_irq: + sde_core_irq_domain_fini(sde_kms); + return ret; +} + +/** + * sde_kms_timeline_status - provides current timeline status + * This API should be called without mode config lock. + * @dev: Pointer to drm device + */ +void sde_kms_timeline_status(struct drm_device *dev) +{ + struct drm_crtc *crtc; + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + + if (!dev) { + SDE_ERROR("invalid drm device node\n"); + return; + } + + drm_for_each_crtc(crtc, dev) + sde_crtc_timeline_status(crtc); + + if (mutex_is_locked(&dev->mode_config.mutex)) { + /* + *Probably locked from last close dumping status anyway + */ + SDE_ERROR("dumping conn_timeline without mode_config lock\n"); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) + sde_conn_timeline_status(conn); + drm_connector_list_iter_end(&conn_iter); + return; + } + + mutex_lock(&dev->mode_config.mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) + sde_conn_timeline_status(conn); + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); +} + +static int sde_kms_postinit(struct msm_kms *kms) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev; + struct drm_crtc *crtc; + int rc; + + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) { + SDE_ERROR("invalid sde_kms\n"); + return -EINVAL; + } + + dev = sde_kms->dev; + + rc = _sde_debugfs_init(sde_kms); + if (rc) + SDE_ERROR("sde_debugfs init failed: %d\n", rc); + + drm_for_each_crtc(crtc, dev) + sde_crtc_post_init(dev, crtc); + + return rc; +} + +static long sde_kms_round_pixclk(struct msm_kms *kms, unsigned long rate, + struct drm_encoder *encoder) +{ + return rate; +} + +static void _sde_kms_hw_destroy(struct sde_kms *sde_kms, + struct platform_device *pdev) +{ + struct drm_device *dev; + struct msm_drm_private *priv; + int i; + + if (!sde_kms || !pdev) + return; + + dev = sde_kms->dev; + if (!dev) + return; + + priv = dev->dev_private; + if (!priv) + return; + + if (sde_kms->genpd_init) { + sde_kms->genpd_init = false; + pm_genpd_remove(&sde_kms->genpd); + of_genpd_del_provider(pdev->dev.of_node); + } + + if (sde_kms->hw_intr) + sde_hw_intr_destroy(sde_kms->hw_intr); + sde_kms->hw_intr = NULL; + + if (sde_kms->power_event) + sde_power_handle_unregister_event( + &priv->phandle, sde_kms->power_event); + + _sde_kms_release_displays(sde_kms); + + _sde_kms_unmap_all_splash_regions(sde_kms); + + /* safe to call these more than once during shutdown */ + _sde_debugfs_destroy(sde_kms); + _sde_kms_mmu_destroy(sde_kms); + + if (sde_kms->catalog) { + for (i = 0; i < sde_kms->catalog->vbif_count; i++) { + u32 vbif_idx = sde_kms->catalog->vbif[i].id; + + if ((vbif_idx < VBIF_MAX) && sde_kms->hw_vbif[vbif_idx]) + sde_hw_vbif_destroy(sde_kms->hw_vbif[vbif_idx]); + } + } + + if (sde_kms->rm_init) + sde_rm_destroy(&sde_kms->rm); + sde_kms->rm_init = false; + + if (sde_kms->catalog) + sde_hw_catalog_deinit(sde_kms->catalog); + sde_kms->catalog = NULL; + + if (sde_kms->sid) + msm_iounmap(pdev, sde_kms->sid); + sde_kms->sid = NULL; + + if (sde_kms->reg_dma) + msm_iounmap(pdev, sde_kms->reg_dma); + sde_kms->reg_dma = NULL; + + if (sde_kms->vbif[VBIF_NRT]) + msm_iounmap(pdev, sde_kms->vbif[VBIF_NRT]); + sde_kms->vbif[VBIF_NRT] = NULL; + + if (sde_kms->vbif[VBIF_RT]) + msm_iounmap(pdev, sde_kms->vbif[VBIF_RT]); + sde_kms->vbif[VBIF_RT] = NULL; + + if (sde_kms->mmio) + msm_iounmap(pdev, sde_kms->mmio); + sde_kms->mmio = NULL; + + sde_reg_dma_deinit(); +} + +int sde_kms_mmu_detach(struct sde_kms *sde_kms, bool secure_only) +{ + int i; + + if (!sde_kms) + return -EINVAL; + + for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) { + struct msm_mmu *mmu; + struct msm_gem_address_space *aspace = sde_kms->aspace[i]; + + if (!aspace) + continue; + + mmu = sde_kms->aspace[i]->mmu; + + if (secure_only && + !aspace->mmu->funcs->is_domain_secure(mmu)) + continue; + + /* cleanup aspace before detaching */ + msm_gem_aspace_domain_attach_detach_update(aspace, true); + + SDE_DEBUG("Detaching domain:%d\n", i); + aspace->mmu->funcs->detach(mmu, (const char **)iommu_ports, + ARRAY_SIZE(iommu_ports)); + + aspace->domain_attached = false; + } + + return 0; +} + +int sde_kms_mmu_attach(struct sde_kms *sde_kms, bool secure_only) +{ + int i; + + if (!sde_kms) + return -EINVAL; + + for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) { + struct msm_mmu *mmu; + struct msm_gem_address_space *aspace = sde_kms->aspace[i]; + + if (!aspace) + continue; + + mmu = sde_kms->aspace[i]->mmu; + + if (secure_only && + !aspace->mmu->funcs->is_domain_secure(mmu)) + continue; + + SDE_DEBUG("Attaching domain:%d\n", i); + aspace->mmu->funcs->attach(mmu, (const char **)iommu_ports, + ARRAY_SIZE(iommu_ports)); + + aspace->domain_attached = true; + msm_gem_aspace_domain_attach_detach_update(aspace, false); + } + + return 0; +} + +static void sde_kms_destroy(struct msm_kms *kms) +{ + struct sde_kms *sde_kms; + struct drm_device *dev; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return; + } + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + if (!dev || !dev->dev) { + SDE_ERROR("invalid device\n"); + return; + } + + _sde_kms_hw_destroy(sde_kms, to_platform_device(dev->dev)); + kfree(sde_kms); +} + +static void _sde_kms_plane_force_remove(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state; + int ret = 0; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + SDE_ERROR("error %d getting plane %d state\n", + ret, plane->base.id); + return; + } + + plane->old_fb = plane->fb; + + SDE_DEBUG("disabling plane %d\n", plane->base.id); + + ret = __drm_atomic_helper_disable_plane(plane, plane_state); + if (ret != 0) + SDE_ERROR("error %d disabling plane %d\n", ret, + plane->base.id); +} + +static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file, + struct drm_atomic_state *state) +{ + struct drm_device *dev = sde_kms->dev; + struct drm_framebuffer *fb, *tfb; + struct list_head fbs; + struct drm_plane *plane; + int ret = 0; + u32 plane_mask = 0; + + INIT_LIST_HEAD(&fbs); + + list_for_each_entry_safe(fb, tfb, &file->fbs, filp_head) { + if (drm_framebuffer_read_refcount(fb) > 1) { + list_move_tail(&fb->filp_head, &fbs); + + drm_for_each_plane(plane, dev) { + if (plane->fb == fb) { + plane_mask |= + 1 << drm_plane_index(plane); + _sde_kms_plane_force_remove( + plane, state); + } + } + } else { + list_del_init(&fb->filp_head); + drm_framebuffer_put(fb); + } + } + + if (list_empty(&fbs)) { + SDE_DEBUG("skip commit as no fb(s)\n"); + drm_atomic_state_put(state); + return 0; + } + + SDE_DEBUG("committing after removing all the pipes\n"); + ret = drm_atomic_commit(state); + + if (ret) { + /* + * move the fbs back to original list, so it would be + * handled during drm_release + */ + list_for_each_entry_safe(fb, tfb, &fbs, filp_head) + list_move_tail(&fb->filp_head, &file->fbs); + + SDE_ERROR("atomic commit failed in preclose, ret:%d\n", ret); + goto end; + } + + while (!list_empty(&fbs)) { + fb = list_first_entry(&fbs, typeof(*fb), filp_head); + + list_del_init(&fb->filp_head); + drm_framebuffer_put(fb); + } + +end: + return ret; +} + +static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev = sde_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + unsigned int i; + struct drm_atomic_state *state = NULL; + struct drm_modeset_acquire_ctx ctx; + int ret = 0; + + /* cancel pending flip event */ + for (i = 0; i < priv->num_crtcs; i++) + sde_crtc_complete_flip(priv->crtcs[i], file); + + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (WARN_ON(ret)) { + goto end; + } + + state = drm_atomic_state_alloc(dev); + if (!state) { + ret = -ENOMEM; + goto end; + } + + state->acquire_ctx = &ctx; + + for (i = 0; i < TEARDOWN_DEADLOCK_RETRY_MAX; i++) { + ret = _sde_kms_remove_fbs(sde_kms, file, state); + if (ret != -EDEADLK) + break; + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + } + +end: + if (state) + drm_atomic_state_put(state); + + SDE_DEBUG("sde preclose done, ret:%d\n", ret); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +static int _sde_kms_helper_reset_custom_properties(struct sde_kms *sde_kms, + struct drm_atomic_state *state) +{ + struct drm_device *dev = sde_kms->dev; + struct drm_plane *plane; + struct drm_plane_state *plane_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + struct drm_connector_list_iter conn_iter; + int ret = 0; + + drm_for_each_plane(plane, dev) { + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + SDE_ERROR("error %d getting plane %d state\n", + ret, DRMID(plane)); + return ret; + } + + ret = sde_plane_helper_reset_custom_properties(plane, + plane_state); + if (ret) { + SDE_ERROR("error %d resetting plane props %d\n", + ret, DRMID(plane)); + return ret; + } + } + drm_for_each_crtc(crtc, dev) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + SDE_ERROR("error %d getting crtc %d state\n", + ret, DRMID(crtc)); + return ret; + } + + ret = sde_crtc_helper_reset_custom_properties(crtc, crtc_state); + if (ret) { + SDE_ERROR("error %d resetting crtc props %d\n", + ret, DRMID(crtc)); + return ret; + } + } + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + conn_state = drm_atomic_get_connector_state(state, conn); + if (IS_ERR(conn_state)) { + ret = PTR_ERR(conn_state); + SDE_ERROR("error %d getting connector %d state\n", + ret, DRMID(conn)); + return ret; + } + + ret = sde_connector_helper_reset_custom_properties(conn, + conn_state); + if (ret) { + SDE_ERROR("error %d resetting connector props %d\n", + ret, DRMID(conn)); + return ret; + } + } + drm_connector_list_iter_end(&conn_iter); + + return ret; +} + +static void sde_kms_lastclose(struct msm_kms *kms, + struct drm_modeset_acquire_ctx *ctx) +{ + struct sde_kms *sde_kms; + struct drm_device *dev; + struct drm_atomic_state *state; + int ret, i; + + if (!kms) { + SDE_ERROR("invalid argument\n"); + return; + } + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + + state = drm_atomic_state_alloc(dev); + if (!state) + return; + + state->acquire_ctx = ctx; + + for (i = 0; i < TEARDOWN_DEADLOCK_RETRY_MAX; i++) { + /* add reset of custom properties to the state */ + ret = _sde_kms_helper_reset_custom_properties(sde_kms, state); + if (ret) + break; + + ret = drm_atomic_commit(state); + if (ret != -EDEADLK) + break; + + drm_atomic_state_clear(state); + drm_modeset_backoff(ctx); + SDE_DEBUG("deadlock backoff on attempt %d\n", i); + } + + if (ret) + SDE_ERROR("failed to run last close: %d\n", ret); + + drm_atomic_state_put(state); +} + +static int sde_kms_check_secure_transition(struct msm_kms *kms, + struct drm_atomic_state *state) +{ + struct sde_kms *sde_kms; + struct drm_device *dev; + struct drm_crtc *crtc; + struct drm_crtc *cur_crtc = NULL, *global_crtc = NULL; + struct drm_crtc_state *crtc_state; + int active_crtc_cnt = 0, global_active_crtc_cnt = 0; + bool sec_session = false, global_sec_session = false; + uint32_t fb_ns = 0, fb_sec = 0, fb_sec_dir = 0; + int i; + + if (!kms || !state) { + return -EINVAL; + SDE_ERROR("invalid arguments\n"); + } + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + + /* iterate state object for active secure/non-secure crtc */ + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->active) + continue; + + active_crtc_cnt++; + sde_crtc_state_find_plane_fb_modes(crtc_state, &fb_ns, + &fb_sec, &fb_sec_dir); + if (fb_sec_dir) + sec_session = true; + cur_crtc = crtc; + } + + /* iterate global list for active and secure/non-secure crtc */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (!crtc->state->active) + continue; + + global_active_crtc_cnt++; + /* update only when crtc is not the same as current crtc */ + if (crtc != cur_crtc) { + fb_ns = fb_sec = fb_sec_dir = 0; + sde_crtc_find_plane_fb_modes(crtc, &fb_ns, + &fb_sec, &fb_sec_dir); + if (fb_sec_dir) + global_sec_session = true; + global_crtc = crtc; + } + } + + if (!global_sec_session && !sec_session) + return 0; + + /* + * - fail crtc commit, if secure-camera/secure-ui session is + * in-progress in any other display + * - fail secure-camera/secure-ui crtc commit, if any other display + * session is in-progress + */ + if ((global_active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE) || + (active_crtc_cnt > MAX_ALLOWED_CRTC_CNT_DURING_SECURE)) { + SDE_ERROR( + "crtc%d secure check failed global_active:%d active:%d\n", + cur_crtc ? cur_crtc->base.id : -1, + global_active_crtc_cnt, active_crtc_cnt); + return -EPERM; + + /* + * As only one crtc is allowed during secure session, the crtc + * in this commit should match with the global crtc + */ + } else if (global_crtc && cur_crtc && (global_crtc != cur_crtc)) { + SDE_ERROR("crtc%d-sec%d not allowed during crtc%d-sec%d\n", + cur_crtc->base.id, sec_session, + global_crtc->base.id, global_sec_session); + return -EPERM; + } + + return 0; +} + +static int sde_kms_atomic_check(struct msm_kms *kms, + struct drm_atomic_state *state) +{ + struct sde_kms *sde_kms; + struct drm_device *dev; + int ret; + + if (!kms || !state) + return -EINVAL; + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + + SDE_ATRACE_BEGIN("atomic_check"); + if (sde_kms_is_suspend_blocked(dev)) { + SDE_DEBUG("suspended, skip atomic_check\n"); + ret = -EBUSY; + goto end; + } + + ret = drm_atomic_helper_check(dev, state); + if (ret) + goto end; + /* + * Check if any secure transition(moving CRTC between secure and + * non-secure state and vice-versa) is allowed or not. when moving + * to secure state, planes with fb_mode set to dir_translated only can + * be staged on the CRTC, and only one CRTC can be active during + * Secure state + */ + ret = sde_kms_check_secure_transition(kms, state); +end: + SDE_ATRACE_END("atomic_check"); + return ret; +} + +static struct msm_gem_address_space* +_sde_kms_get_address_space(struct msm_kms *kms, + unsigned int domain) +{ + struct sde_kms *sde_kms; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return NULL; + } + + sde_kms = to_sde_kms(kms); + if (!sde_kms) { + SDE_ERROR("invalid sde_kms\n"); + return NULL; + } + + if (domain >= MSM_SMMU_DOMAIN_MAX) + return NULL; + + return (sde_kms->aspace[domain] && + sde_kms->aspace[domain]->domain_attached) ? + sde_kms->aspace[domain] : NULL; +} + +static struct device *_sde_kms_get_address_space_device(struct msm_kms *kms, + unsigned int domain) +{ + struct msm_gem_address_space *aspace = + _sde_kms_get_address_space(kms, domain); + + return (aspace && aspace->domain_attached) ? + msm_gem_get_aspace_device(aspace) : NULL; +} + +static void _sde_kms_post_open(struct msm_kms *kms, struct drm_file *file) +{ + struct drm_device *dev = NULL; + struct sde_kms *sde_kms = NULL; + struct drm_connector *connector = NULL; + struct drm_connector_list_iter conn_iter; + struct sde_connector *sde_conn = NULL; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return; + } + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + + if (!dev) { + SDE_ERROR("invalid device\n"); + return; + } + + if (!dev->mode_config.poll_enabled) + return; + + 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; + + sde_conn = to_sde_connector(connector); + + if (sde_conn->ops.post_open) + sde_conn->ops.post_open(&sde_conn->base, + sde_conn->display); + } + drm_connector_list_iter_end(&conn_iter); + mutex_unlock(&dev->mode_config.mutex); + +} + +static int _sde_kms_update_planes_for_cont_splash(struct sde_kms *sde_kms, + struct sde_splash_display *splash_display, + struct drm_crtc *crtc) +{ + struct msm_drm_private *priv; + struct drm_plane *plane; + struct sde_splash_mem *splash; + enum sde_sspp plane_id; + bool is_virtual; + int i, j; + + if (!sde_kms || !splash_display || !crtc) { + SDE_ERROR("invalid input args\n"); + return -EINVAL; + } + + priv = sde_kms->dev->dev_private; + for (i = 0; i < priv->num_planes; i++) { + plane = priv->planes[i]; + plane_id = sde_plane_pipe(plane); + is_virtual = is_sde_plane_virtual(plane); + splash = splash_display->splash; + + for (j = 0; j < splash_display->pipe_cnt; j++) { + if ((plane_id != splash_display->pipes[j].sspp) || + (splash_display->pipes[j].is_virtual + != is_virtual)) + continue; + + if (splash && sde_plane_validate_src_addr(plane, + splash->splash_buf_base, + splash->splash_buf_size)) { + SDE_ERROR("invalid adr on pipe:%d crtc:%d\n", + plane_id, crtc->base.id); + } + + SDE_DEBUG("set crtc:%d for plane:%d rect:%d\n", + crtc->base.id, plane_id, is_virtual); + } + } + + return 0; +} + +static int sde_kms_cont_splash_config(struct msm_kms *kms) +{ + void *display; + struct dsi_display *dsi_display; + struct msm_display_info info; + struct drm_encoder *encoder = NULL; + struct drm_crtc *crtc = NULL; + int i, rc = 0; + struct drm_display_mode *drm_mode = NULL; + struct drm_device *dev; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct drm_connector_list_iter conn_iter; + struct drm_connector *connector = NULL; + struct sde_connector *sde_conn = NULL; + struct sde_splash_display *splash_display; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + if (!dev) { + SDE_ERROR("invalid device\n"); + return -EINVAL; + } + + if (!sde_kms->splash_data.num_splash_regions || + !sde_kms->splash_data.num_splash_displays) { + DRM_INFO("cont_splash feature not enabled\n"); + return rc; + } + + DRM_INFO("cont_splash enabled in %d of %d display(s)\n", + sde_kms->splash_data.num_splash_displays, + sde_kms->dsi_display_count); + + /* dsi */ + for (i = 0; i < sde_kms->dsi_display_count; ++i) { + display = sde_kms->dsi_displays[i]; + dsi_display = (struct dsi_display *)display; + splash_display = &sde_kms->splash_data.splash_display[i]; + + if (!splash_display->cont_splash_enabled) { + SDE_DEBUG("display->name = %s splash not enabled\n", + dsi_display->name); + continue; + } + + SDE_DEBUG("display->name = %s\n", dsi_display->name); + + if (dsi_display->bridge->base.encoder) { + encoder = dsi_display->bridge->base.encoder; + SDE_DEBUG("encoder name = %s\n", encoder->name); + } + memset(&info, 0x0, sizeof(info)); + rc = dsi_display_get_info(NULL, &info, display); + if (rc) { + SDE_ERROR("dsi get_info %d failed\n", i); + encoder = NULL; + continue; + } + SDE_DEBUG("info.is_connected = %s, info.display_type = %d\n", + ((info.is_connected) ? "true" : "false"), + info.display_type); + + if (!encoder) { + SDE_ERROR("encoder not initialized\n"); + return -EINVAL; + } + + priv = sde_kms->dev->dev_private; + encoder->crtc = priv->crtcs[i]; + crtc = encoder->crtc; + splash_display->encoder = encoder; + + SDE_DEBUG("for dsi-display:%d crtc id = %d enc id =%d\n", + i, crtc->base.id, encoder->base.id); + + mutex_lock(&dev->mode_config.mutex); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + /** + * SDE_KMS doesn't attach more than one encoder to + * a DSI connector. So it is safe to check only with + * the first encoder entry. Revisit this logic if we + * ever have to support continuous splash for + * external displays in MST configuration. + */ + if (connector->encoder_ids[0] == encoder->base.id) + break; + } + drm_connector_list_iter_end(&conn_iter); + + if (!connector) { + SDE_ERROR("connector not initialized\n"); + mutex_unlock(&dev->mode_config.mutex); + return -EINVAL; + } + + if (connector->funcs->fill_modes) { + connector->funcs->fill_modes(connector, + dev->mode_config.max_width, + dev->mode_config.max_height); + } else { + SDE_ERROR("fill_modes api not defined\n"); + mutex_unlock(&dev->mode_config.mutex); + return -EINVAL; + } + mutex_unlock(&dev->mode_config.mutex); + + crtc->state->encoder_mask = (1 << drm_encoder_index(encoder)); + + /* currently consider modes[0] as the preferred mode */ + drm_mode = list_first_entry(&connector->modes, + struct drm_display_mode, head); + SDE_DEBUG("drm_mode->name = %s, id=%d, type=0x%x, flags=0x%x\n", + drm_mode->name, drm_mode->base.id, + drm_mode->type, drm_mode->flags); + + /* Update CRTC drm structure */ + crtc->state->active = true; + rc = drm_atomic_set_mode_for_crtc(crtc->state, drm_mode); + if (rc) { + SDE_ERROR("Failed: set mode for crtc. rc = %d\n", rc); + return rc; + } + drm_mode_copy(&crtc->state->adjusted_mode, drm_mode); + drm_mode_copy(&crtc->mode, drm_mode); + + /* Update encoder structure */ + sde_encoder_update_caps_for_cont_splash(encoder, + splash_display, true); + + sde_crtc_update_cont_splash_settings(crtc); + + sde_conn = to_sde_connector(connector); + if (sde_conn && sde_conn->ops.cont_splash_config) + sde_conn->ops.cont_splash_config(sde_conn->display); + + rc = _sde_kms_update_planes_for_cont_splash(sde_kms, + splash_display, crtc); + if (rc) { + SDE_ERROR("Failed: updating plane status rc=%d\n", rc); + return rc; + } + } + + return rc; +} + +static bool sde_kms_check_for_splash(struct msm_kms *kms, struct drm_crtc *crtc) +{ + struct sde_kms *sde_kms; + struct drm_encoder *encoder; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return false; + } + + sde_kms = to_sde_kms(kms); + + if (!crtc || !sde_kms->splash_data.num_splash_displays) + return !!sde_kms->splash_data.num_splash_displays; + + drm_for_each_encoder_mask(encoder, crtc->dev, + crtc->state->encoder_mask) { + if (sde_encoder_in_cont_splash(encoder)) + return true; + } + + return false; + +} + +static int sde_kms_get_mixer_count(const struct msm_kms *kms, + const struct drm_display_mode *mode, + const struct msm_resource_caps_info *res, u32 *num_lm) +{ + struct sde_kms *sde_kms; + s64 mode_clock_hz = 0; + s64 max_mdp_clock_hz = 0; + s64 mdp_fudge_factor = 0; + s64 temp = 0; + s64 htotal_fp = 0; + s64 vtotal_fp = 0; + s64 vrefresh_fp = 0; + + if (!num_lm) { + SDE_ERROR("invalid num_lm pointer\n"); + return -EINVAL; + } + + *num_lm = 1; + if (!kms || !mode || !res) { + SDE_ERROR("invalid input args\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(kms); + + max_mdp_clock_hz = drm_fixp_from_fraction( + sde_kms->perf.max_core_clk_rate, 1); + mdp_fudge_factor = drm_fixp_from_fraction(105, 100); /* 1.05 */ + htotal_fp = drm_fixp_from_fraction(mode->htotal, 1); + vtotal_fp = drm_fixp_from_fraction(mode->vtotal, 1); + vrefresh_fp = drm_fixp_from_fraction(mode->vrefresh, 1); + + temp = drm_fixp_mul(htotal_fp, vtotal_fp); + temp = drm_fixp_mul(temp, vrefresh_fp); + mode_clock_hz = drm_fixp_mul(temp, mdp_fudge_factor); + if (mode_clock_hz > max_mdp_clock_hz || + mode->hdisplay > res->max_mixer_width) + *num_lm = 2; + SDE_DEBUG("[%s] h=%d, v=%d, fps=%d, max_mdp_clk_hz=%llu, num_lm=%d\n", + mode->name, mode->htotal, mode->vtotal, mode->vrefresh, + sde_kms->perf.max_core_clk_rate, *num_lm); + + return 0; +} + +static void _sde_kms_null_commit(struct drm_device *dev, + struct drm_encoder *enc) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_connector *conn = NULL; + struct drm_connector *tmp_conn = NULL; + struct drm_connector_list_iter conn_iter; + struct drm_atomic_state *state = NULL; + struct drm_crtc_state *crtc_state = NULL; + struct drm_connector_state *conn_state = NULL; + int retry_cnt = 0; + int ret = 0; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret == -EDEADLK && retry_cnt < SDE_KMS_MODESET_LOCK_MAX_TRIALS) { + drm_modeset_backoff(&ctx); + retry_cnt++; + udelay(SDE_KMS_MODESET_LOCK_TIMEOUT_US); + goto retry; + } else if (WARN_ON(ret)) { + goto end; + } + + state = drm_atomic_state_alloc(dev); + if (!state) { + DRM_ERROR("failed to allocate atomic state, %d\n", ret); + goto end; + } + + state->acquire_ctx = &ctx; + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(tmp_conn, &conn_iter) { + if (enc == tmp_conn->state->best_encoder) { + conn = tmp_conn; + break; + } + } + drm_connector_list_iter_end(&conn_iter); + + if (!conn) { + SDE_ERROR("error in finding conn for enc:%d\n", DRMID(enc)); + goto end; + } + + crtc_state = drm_atomic_get_crtc_state(state, enc->crtc); + conn_state = drm_atomic_get_connector_state(state, conn); + if (IS_ERR(conn_state)) { + SDE_ERROR("error %d getting connector %d state\n", + ret, DRMID(conn)); + goto end; + } + + crtc_state->active = true; + ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc); + if (ret) + SDE_ERROR("error %d setting the crtc\n", ret); + + ret = drm_atomic_commit(state); + if (ret) + SDE_ERROR("Error %d doing the atomic commit\n", ret); + +end: + if (state) + drm_atomic_state_put(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + +static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms, + struct device *dev) +{ + int i, ret, crtc_id = 0; + struct drm_device *ddev = dev_get_drvdata(dev); + struct drm_connector *conn; + struct drm_connector_list_iter conn_iter; + struct msm_drm_private *priv = sde_kms->dev->dev_private; + + drm_connector_list_iter_begin(ddev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + uint64_t lp; + + lp = sde_connector_get_lp(conn); + if (lp != SDE_MODE_DPMS_LP2) + continue; + + if (sde_encoder_in_clone_mode(conn->encoder)) + continue; + + ret = sde_encoder_wait_for_event(conn->encoder, + MSM_ENC_TX_COMPLETE); + if (ret && ret != -EWOULDBLOCK) { + SDE_ERROR( + "[conn: %d] wait for commit done returned %d\n", + conn->base.id, ret); + } else if (!ret) { + crtc_id = drm_crtc_index(conn->state->crtc); + if (priv->event_thread[crtc_id].thread) + kthread_flush_worker( + &priv->event_thread[crtc_id].worker); + sde_encoder_idle_request(conn->encoder); + } + } + drm_connector_list_iter_end(&conn_iter); + + for (i = 0; i < priv->num_crtcs; i++) { + if (priv->disp_thread[i].thread) + kthread_flush_worker( + &priv->disp_thread[i].worker); + if (priv->event_thread[i].thread) + kthread_flush_worker( + &priv->event_thread[i].worker); + } + kthread_flush_worker(&priv->pp_event_worker); +} + +static int sde_kms_pm_suspend(struct device *dev) +{ + struct drm_device *ddev; + struct drm_modeset_acquire_ctx ctx; + struct drm_connector *conn; + struct drm_encoder *enc; + struct drm_connector_list_iter conn_iter; + struct drm_atomic_state *state = NULL; + struct sde_kms *sde_kms; + int ret = 0, num_crtcs = 0; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev_to_msm_kms(ddev)) + return -EINVAL; + + sde_kms = to_sde_kms(ddev_to_msm_kms(ddev)); + SDE_EVT32(0); + + /* disable hot-plug polling */ + drm_kms_helper_poll_disable(ddev); + + /* if a display stuck in CS trigger a null commit to complete handoff */ + drm_for_each_encoder(enc, ddev) { + if (sde_encoder_in_cont_splash(enc) && enc->crtc) + _sde_kms_null_commit(ddev, enc); + } + + /* acquire modeset lock(s) */ + drm_modeset_acquire_init(&ctx, 0); + +retry: + ret = drm_modeset_lock_all_ctx(ddev, &ctx); + if (ret) + goto unlock; + + /* save current state for resume */ + if (sde_kms->suspend_state) + drm_atomic_state_put(sde_kms->suspend_state); + sde_kms->suspend_state = drm_atomic_helper_duplicate_state(ddev, &ctx); + if (IS_ERR_OR_NULL(sde_kms->suspend_state)) { + ret = PTR_ERR(sde_kms->suspend_state); + DRM_ERROR("failed to back up suspend state, %d\n", ret); + sde_kms->suspend_state = NULL; + goto unlock; + } + + /* create atomic state to disable all CRTCs */ + state = drm_atomic_state_alloc(ddev); + if (!state) { + ret = -ENOMEM; + DRM_ERROR("failed to allocate crtc disable state, %d\n", ret); + goto unlock; + } + + state->acquire_ctx = &ctx; + drm_connector_list_iter_begin(ddev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + struct drm_crtc_state *crtc_state; + uint64_t lp; + + if (!conn->state || !conn->state->crtc || + conn->dpms != DRM_MODE_DPMS_ON || + sde_encoder_in_clone_mode(conn->encoder)) + continue; + + lp = sde_connector_get_lp(conn); + if (lp == SDE_MODE_DPMS_LP1) { + /* transition LP1->LP2 on pm suspend */ + ret = sde_connector_set_property_for_commit(conn, state, + CONNECTOR_PROP_LP, SDE_MODE_DPMS_LP2); + if (ret) { + DRM_ERROR("failed to set lp2 for conn %d\n", + conn->base.id); + drm_connector_list_iter_end(&conn_iter); + goto unlock; + } + } + + if (lp != SDE_MODE_DPMS_LP2) { + /* force CRTC to be inactive */ + crtc_state = drm_atomic_get_crtc_state(state, + conn->state->crtc); + if (IS_ERR_OR_NULL(crtc_state)) { + DRM_ERROR("failed to get crtc %d state\n", + conn->state->crtc->base.id); + drm_connector_list_iter_end(&conn_iter); + goto unlock; + } + + if (lp != SDE_MODE_DPMS_LP1) + crtc_state->active = false; + ++num_crtcs; + } + } + drm_connector_list_iter_end(&conn_iter); + + /* check for nothing to do */ + if (num_crtcs == 0) { + DRM_DEBUG("all crtcs are already in the off state\n"); + sde_kms->suspend_block = true; + _sde_kms_pm_suspend_idle_helper(sde_kms, dev); + goto unlock; + } + + /* commit the "disable all" state */ + ret = drm_atomic_commit(state); + if (ret < 0) { + DRM_ERROR("failed to disable crtcs, %d\n", ret); + goto unlock; + } + + sde_kms->suspend_block = true; + _sde_kms_pm_suspend_idle_helper(sde_kms, dev); + +unlock: + if (state) { + drm_atomic_state_put(state); + state = NULL; + } + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + /* + * pm runtime driver avoids multiple runtime_suspend API call by + * checking runtime_status. However, this call helps when there is a + * race condition between pm_suspend call and doze_suspend/power_off + * commit. It removes the extra vote from suspend and adds it back + * later to allow power collapse during pm_suspend call + */ + pm_runtime_put_sync(dev); + pm_runtime_get_noresume(dev); + + return ret; +} + +static int sde_kms_pm_resume(struct device *dev) +{ + struct drm_device *ddev; + struct sde_kms *sde_kms; + struct drm_modeset_acquire_ctx ctx; + int ret, i; + + if (!dev) + return -EINVAL; + + ddev = dev_get_drvdata(dev); + if (!ddev || !ddev_to_msm_kms(ddev)) + return -EINVAL; + + sde_kms = to_sde_kms(ddev_to_msm_kms(ddev)); + + SDE_EVT32(sde_kms->suspend_state != NULL); + + drm_mode_config_reset(ddev); + + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(ddev, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (WARN_ON(ret)) { + goto end; + } + + sde_kms->suspend_block = false; + + if (sde_kms->suspend_state) { + sde_kms->suspend_state->acquire_ctx = &ctx; + for (i = 0; i < TEARDOWN_DEADLOCK_RETRY_MAX; i++) { + ret = drm_atomic_helper_commit_duplicated_state( + sde_kms->suspend_state, &ctx); + if (ret != -EDEADLK) + break; + + drm_modeset_backoff(&ctx); + } + + if (ret < 0) + DRM_ERROR("failed to restore state, %d\n", ret); + + drm_atomic_state_put(sde_kms->suspend_state); + sde_kms->suspend_state = NULL; + } + +end: + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + /* enable hot-plug polling */ + drm_kms_helper_poll_enable(ddev); + + return 0; +} + +static const struct msm_kms_funcs kms_funcs = { + .hw_init = sde_kms_hw_init, + .postinit = sde_kms_postinit, + .irq_preinstall = sde_irq_preinstall, + .irq_postinstall = sde_irq_postinstall, + .irq_uninstall = sde_irq_uninstall, + .irq = sde_irq, + .preclose = sde_kms_preclose, + .lastclose = sde_kms_lastclose, + .prepare_fence = sde_kms_prepare_fence, + .prepare_commit = sde_kms_prepare_commit, + .commit = sde_kms_commit, + .complete_commit = sde_kms_complete_commit, + .wait_for_crtc_commit_done = sde_kms_wait_for_commit_done, + .wait_for_tx_complete = sde_kms_wait_for_frame_transfer_complete, + .enable_vblank = sde_kms_enable_vblank, + .disable_vblank = sde_kms_disable_vblank, + .check_modified_format = sde_format_check_modified_format, + .atomic_check = sde_kms_atomic_check, + .get_format = sde_get_msm_format, + .round_pixclk = sde_kms_round_pixclk, + .pm_suspend = sde_kms_pm_suspend, + .pm_resume = sde_kms_pm_resume, + .destroy = sde_kms_destroy, + .cont_splash_config = sde_kms_cont_splash_config, + .register_events = _sde_kms_register_events, + .get_address_space = _sde_kms_get_address_space, + .get_address_space_device = _sde_kms_get_address_space_device, + .postopen = _sde_kms_post_open, + .check_for_splash = sde_kms_check_for_splash, + .get_mixer_count = sde_kms_get_mixer_count, +}; + +/* the caller api needs to turn on clock before calling it */ +static inline void _sde_kms_core_hw_rev_init(struct sde_kms *sde_kms) +{ + sde_kms->core_rev = readl_relaxed(sde_kms->mmio + 0x0); +} + +static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms) +{ + int i; + + for (i = ARRAY_SIZE(sde_kms->aspace) - 1; i >= 0; i--) { + if (!sde_kms->aspace[i]) + continue; + + msm_gem_address_space_put(sde_kms->aspace[i]); + sde_kms->aspace[i] = NULL; + } + + return 0; +} + +static int _sde_kms_mmu_init(struct sde_kms *sde_kms) +{ + struct msm_mmu *mmu; + int i, ret; + int early_map = 0; + + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) + return -EINVAL; + + for (i = 0; i < MSM_SMMU_DOMAIN_MAX; i++) { + struct msm_gem_address_space *aspace; + + mmu = msm_smmu_new(sde_kms->dev->dev, i); + if (IS_ERR(mmu)) { + ret = PTR_ERR(mmu); + SDE_DEBUG("failed to init iommu id %d: rc:%d\n", + i, ret); + continue; + } + + aspace = msm_gem_smmu_address_space_create(sde_kms->dev, + mmu, "sde"); + if (IS_ERR(aspace)) { + ret = PTR_ERR(aspace); + mmu->funcs->destroy(mmu); + goto fail; + } + + sde_kms->aspace[i] = aspace; + aspace->domain_attached = true; + + /* Mapping splash memory block */ + if ((i == MSM_SMMU_DOMAIN_UNSECURE) && + sde_kms->splash_data.num_splash_regions) { + ret = _sde_kms_map_all_splash_regions(sde_kms); + if (ret) { + SDE_ERROR("failed to map ret:%d\n", ret); + goto fail; + } + } + + /* + * disable early-map which would have been enabled during + * bootup by smmu through the device-tree hint for cont-spash + */ + ret = mmu->funcs->set_attribute(mmu, DOMAIN_ATTR_EARLY_MAP, + &early_map); + if (ret) { + SDE_ERROR("failed to set_att ret:%d, early_map:%d\n", + ret, early_map); + goto early_map_fail; + } + } + + sde_kms->base.aspace = sde_kms->aspace[0]; + + return 0; + +early_map_fail: + _sde_kms_unmap_all_splash_regions(sde_kms); +fail: + _sde_kms_mmu_destroy(sde_kms); + + return ret; +} + +static void sde_kms_init_shared_hw(struct sde_kms *sde_kms) +{ + if (!sde_kms || !sde_kms->hw_mdp || !sde_kms->catalog) + return; + + if (sde_kms->hw_mdp->ops.reset_ubwc) + sde_kms->hw_mdp->ops.reset_ubwc(sde_kms->hw_mdp, + sde_kms->catalog); + + sde_hw_sid_rotator_set(sde_kms->hw_sid); +} + +static void _sde_kms_set_lutdma_vbif_remap(struct sde_kms *sde_kms) +{ + struct sde_vbif_set_qos_params qos_params; + struct sde_mdss_cfg *catalog; + + if (!sde_kms->catalog) + return; + + catalog = sde_kms->catalog; + + memset(&qos_params, 0, sizeof(qos_params)); + qos_params.vbif_idx = catalog->dma_cfg.vbif_idx; + qos_params.xin_id = catalog->dma_cfg.xin_id; + qos_params.clk_ctrl = catalog->dma_cfg.clk_ctrl; + qos_params.client_type = VBIF_LUTDMA_CLIENT; + + sde_vbif_set_qos_remap(sde_kms, &qos_params); +} + +void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms, + bool enable, bool skip_lock) +{ + struct msm_drm_private *priv; + + priv = sde_kms->dev->dev_private; + + if (!skip_lock) + mutex_lock(&priv->phandle.phandle_lock); + + if (enable) { + struct pm_qos_request *req; + u32 cpu_irq_latency; + + req = &sde_kms->pm_qos_irq_req; + req->type = PM_QOS_REQ_AFFINE_CORES; + req->cpus_affine = sde_kms->irq_cpu_mask; + cpu_irq_latency = sde_kms->catalog->perf.cpu_irq_latency; + + if (pm_qos_request_active(req)) + pm_qos_update_request(req, cpu_irq_latency); + else if (!cpumask_empty(&req->cpus_affine)) { + /** If request is not active yet and mask is not empty + * then it needs to be added initially + */ + pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY, + cpu_irq_latency); + } + } else if (!enable && pm_qos_request_active(&sde_kms->pm_qos_irq_req)) { + pm_qos_update_request(&sde_kms->pm_qos_irq_req, + PM_QOS_DEFAULT_VALUE); + } + + sde_kms->pm_qos_irq_req_en = enable; + + if (!skip_lock) + mutex_unlock(&priv->phandle.phandle_lock); +} + +static void sde_kms_irq_affinity_notify( + struct irq_affinity_notify *affinity_notify, + const cpumask_t *mask) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms = container_of(affinity_notify, + struct sde_kms, affinity_notify); + + if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev_private) + return; + + priv = sde_kms->dev->dev_private; + + mutex_lock(&priv->phandle.phandle_lock); + + // save irq cpu mask + sde_kms->irq_cpu_mask = *mask; + + // request vote with updated irq cpu mask + if (sde_kms->pm_qos_irq_req_en) + sde_kms_update_pm_qos_irq_request(sde_kms, true, true); + + mutex_unlock(&priv->phandle.phandle_lock); +} + +static void sde_kms_irq_affinity_release(struct kref *ref) {} + +static void sde_kms_handle_power_event(u32 event_type, void *usr) +{ + struct sde_kms *sde_kms = usr; + struct msm_kms *msm_kms; + + msm_kms = &sde_kms->base; + if (!sde_kms) + return; + + SDE_DEBUG("event_type:%d\n", event_type); + SDE_EVT32_VERBOSE(event_type); + + if (event_type == SDE_POWER_EVENT_POST_ENABLE) { + sde_irq_update(msm_kms, true); + sde_vbif_init_memtypes(sde_kms); + sde_kms_init_shared_hw(sde_kms); + _sde_kms_set_lutdma_vbif_remap(sde_kms); + sde_kms->first_kickoff = true; + sde_kms_update_pm_qos_irq_request(sde_kms, true, true); + } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) { + sde_kms_update_pm_qos_irq_request(sde_kms, false, true); + sde_irq_update(msm_kms, false); + sde_kms->first_kickoff = false; + } +} + +#define genpd_to_sde_kms(domain) container_of(domain, struct sde_kms, genpd) + +static int sde_kms_pd_enable(struct generic_pm_domain *genpd) +{ + struct sde_kms *sde_kms = genpd_to_sde_kms(genpd); + int rc = -EINVAL; + + SDE_DEBUG("\n"); + + rc = pm_runtime_get_sync(sde_kms->dev->dev); + if (rc > 0) + rc = 0; + + SDE_EVT32(rc, genpd->device_count); + + return rc; +} + +static int sde_kms_pd_disable(struct generic_pm_domain *genpd) +{ + struct sde_kms *sde_kms = genpd_to_sde_kms(genpd); + + SDE_DEBUG("\n"); + + pm_runtime_put_sync(sde_kms->dev->dev); + + SDE_EVT32(genpd->device_count); + + return 0; +} + +static int _sde_kms_get_splash_data(struct sde_splash_data *data) +{ + int i = 0; + int ret = 0; + struct device_node *parent, *node, *node1; + struct resource r, r1; + const char *node_name = "cont_splash_region"; + struct sde_splash_mem *mem; + bool share_splash_mem = false; + int num_displays, num_regions; + struct sde_splash_display *splash_display; + + if (!data) + return -EINVAL; + + memset(data, 0, sizeof(*data)); + + parent = of_find_node_by_path("/reserved-memory"); + if (!parent) { + SDE_ERROR("failed to find reserved-memory node\n"); + return -EINVAL; + } + + node = of_find_node_by_name(parent, node_name); + if (!node) { + SDE_DEBUG("failed to find node %s\n", node_name); + return -EINVAL; + } + + node1 = of_find_node_by_name(parent, "disp_rdump_region"); + if (!node1) + SDE_DEBUG("failed to find disp ramdump memory reservation\n"); + + /** + * Support sharing a single splash memory for all the built in displays + * and also independent splash region per displays. Incase of + * independent splash region for each connected display, dtsi node of + * cont_splash_region should be collection of all memory regions + * Ex: <r1.start r1.end r2.start r2.end ... rn.start, rn.end> + */ + num_displays = dsi_display_get_num_of_displays(); + num_regions = of_property_count_u64_elems(node, "reg") / 2; + + data->num_splash_displays = num_displays; + + SDE_DEBUG("splash mem num_regions:%d\n", num_regions); + if (num_displays > num_regions) { + share_splash_mem = true; + pr_info(":%d displays share same splash buf\n", num_displays); + } + + for (i = 0; i < num_displays; i++) { + splash_display = &data->splash_display[i]; + if (!i || !share_splash_mem) { + if (of_address_to_resource(node, i, &r)) { + SDE_ERROR("invalid data for:%s\n", node_name); + return -EINVAL; + } + + mem = &data->splash_mem[i]; + if (!node1 || of_address_to_resource(node1, i, &r1)) { + SDE_DEBUG("failed to find ramdump memory\n"); + mem->ramdump_base = 0; + mem->ramdump_size = 0; + } else { + mem->ramdump_base = (unsigned long)r1.start; + mem->ramdump_size = (r1.end - r1.start) + 1; + } + + mem->splash_buf_base = (unsigned long)r.start; + mem->splash_buf_size = (r.end - r.start) + 1; + mem->ref_cnt = 0; + splash_display->splash = mem; + data->num_splash_regions++; + } else { + data->splash_display[i].splash = &data->splash_mem[0]; + } + + SDE_DEBUG("splash mem for disp:%d add:%lx size:%x\n", (i + 1), + splash_display->splash->splash_buf_base, + splash_display->splash->splash_buf_size); + } + + return ret; +} + +static int _sde_kms_hw_init_ioremap(struct sde_kms *sde_kms, + struct platform_device *platformdev) +{ + int rc = -EINVAL; + + sde_kms->mmio = msm_ioremap(platformdev, "mdp_phys", "mdp_phys"); + if (IS_ERR(sde_kms->mmio)) { + rc = PTR_ERR(sde_kms->mmio); + SDE_ERROR("mdp register memory map failed: %d\n", rc); + sde_kms->mmio = NULL; + goto error; + } + DRM_INFO("mapped mdp address space @%pK\n", sde_kms->mmio); + sde_kms->mmio_len = msm_iomap_size(platformdev, "mdp_phys"); + + rc = sde_dbg_reg_register_base(SDE_DBG_NAME, sde_kms->mmio, + sde_kms->mmio_len); + if (rc) + SDE_ERROR("dbg base register kms failed: %d\n", rc); + + sde_kms->vbif[VBIF_RT] = msm_ioremap(platformdev, "vbif_phys", + "vbif_phys"); + if (IS_ERR(sde_kms->vbif[VBIF_RT])) { + rc = PTR_ERR(sde_kms->vbif[VBIF_RT]); + SDE_ERROR("vbif register memory map failed: %d\n", rc); + sde_kms->vbif[VBIF_RT] = NULL; + goto error; + } + sde_kms->vbif_len[VBIF_RT] = msm_iomap_size(platformdev, + "vbif_phys"); + rc = sde_dbg_reg_register_base("vbif_rt", sde_kms->vbif[VBIF_RT], + sde_kms->vbif_len[VBIF_RT]); + if (rc) + SDE_ERROR("dbg base register vbif_rt failed: %d\n", rc); + + sde_kms->vbif[VBIF_NRT] = msm_ioremap(platformdev, "vbif_nrt_phys", + "vbif_nrt_phys"); + if (IS_ERR(sde_kms->vbif[VBIF_NRT])) { + sde_kms->vbif[VBIF_NRT] = NULL; + SDE_DEBUG("VBIF NRT is not defined"); + } else { + sde_kms->vbif_len[VBIF_NRT] = msm_iomap_size(platformdev, + "vbif_nrt_phys"); + rc = sde_dbg_reg_register_base("vbif_nrt", + sde_kms->vbif[VBIF_NRT], + sde_kms->vbif_len[VBIF_NRT]); + if (rc) + SDE_ERROR("dbg base register vbif_nrt failed: %d\n", + rc); + } + + sde_kms->reg_dma = msm_ioremap(platformdev, "regdma_phys", + "regdma_phys"); + if (IS_ERR(sde_kms->reg_dma)) { + sde_kms->reg_dma = NULL; + SDE_DEBUG("REG_DMA is not defined"); + } else { + sde_kms->reg_dma_len = msm_iomap_size(platformdev, + "regdma_phys"); + rc = sde_dbg_reg_register_base("reg_dma", + sde_kms->reg_dma, + sde_kms->reg_dma_len); + if (rc) + SDE_ERROR("dbg base register reg_dma failed: %d\n", + rc); + } + + sde_kms->imem = msm_ioremap(platformdev, "sde_imem_phys", + "sde_imem_phys"); + + if (IS_ERR(sde_kms->imem)) { + sde_kms->imem = NULL; + sde_kms->imem_len = 0; + } else { + sde_kms->imem_len = msm_iomap_size(platformdev, + "sde_imem_phys"); + } + + sde_kms->sid = msm_ioremap(platformdev, "sid_phys", + "sid_phys"); + if (IS_ERR(sde_kms->sid)) { + rc = PTR_ERR(sde_kms->sid); + SDE_ERROR("sid register memory map failed: %d\n", rc); + sde_kms->sid = NULL; + goto error; + } + + sde_kms->sid_len = msm_iomap_size(platformdev, "sid_phys"); + rc = sde_dbg_reg_register_base("sid", sde_kms->sid, sde_kms->sid_len); + if (rc) + SDE_ERROR("dbg base register sid failed: %d\n", rc); + +error: + return rc; +} + +static int _sde_kms_hw_init_power_helper(struct drm_device *dev, + struct sde_kms *sde_kms) +{ + int rc = 0; + + if (of_find_property(dev->dev->of_node, "#power-domain-cells", NULL)) { + sde_kms->genpd.name = dev->unique; + sde_kms->genpd.power_off = sde_kms_pd_disable; + sde_kms->genpd.power_on = sde_kms_pd_enable; + + rc = pm_genpd_init(&sde_kms->genpd, NULL, true); + if (rc < 0) { + SDE_ERROR("failed to init genpd provider %s: %d\n", + sde_kms->genpd.name, rc); + return rc; + } + + rc = of_genpd_add_provider_simple(dev->dev->of_node, + &sde_kms->genpd); + if (rc < 0) { + SDE_ERROR("failed to add genpd provider %s: %d\n", + sde_kms->genpd.name, rc); + pm_genpd_remove(&sde_kms->genpd); + return rc; + } + + sde_kms->genpd_init = true; + SDE_DEBUG("added genpd provider %s\n", sde_kms->genpd.name); + } + + return rc; +} + +static void _sde_kms_update_tcsr_glitch_mask(struct sde_kms *sde_kms) +{ + u32 read_val, write_val; + + if (!sde_kms || !sde_kms->catalog || + !sde_kms->catalog->update_tcsr_disp_glitch) + return; + + read_val = scm_io_read(TCSR_DISP_HF_SF_ARES_GLITCH_MASK); + write_val = read_val | BIT(2); + scm_io_write(TCSR_DISP_HF_SF_ARES_GLITCH_MASK, write_val); + + pr_info("tcsr glitch programmed read_val:%x write_val:%x\n", + read_val, write_val); + +} + +static int _sde_kms_hw_init_blocks(struct sde_kms *sde_kms, + struct drm_device *dev, + struct msm_drm_private *priv) +{ + struct sde_rm *rm = NULL; + int i, rc = -EINVAL; + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(&priv->phandle, i, + SDE_POWER_HANDLE_CONT_SPLASH_BUS_AB_QUOTA, + SDE_POWER_HANDLE_CONT_SPLASH_BUS_IB_QUOTA); + + _sde_kms_core_hw_rev_init(sde_kms); + + pr_info("sde hardware revision:0x%x\n", sde_kms->core_rev); + + sde_kms->catalog = sde_hw_catalog_init(dev, sde_kms->core_rev); + if (IS_ERR_OR_NULL(sde_kms->catalog)) { + rc = PTR_ERR(sde_kms->catalog); + if (!sde_kms->catalog) + rc = -EINVAL; + SDE_ERROR("catalog init failed: %d\n", rc); + sde_kms->catalog = NULL; + goto power_error; + } + + /* mask glitch during gdsc power up */ + _sde_kms_update_tcsr_glitch_mask(sde_kms); + + /* initialize power domain if defined */ + rc = _sde_kms_hw_init_power_helper(dev, sde_kms); + if (rc) { + SDE_ERROR("_sde_kms_hw_init_power_helper failed: %d\n", rc); + goto genpd_err; + } + + rc = _sde_kms_mmu_init(sde_kms); + if (rc) { + SDE_ERROR("sde_kms_mmu_init failed: %d\n", rc); + goto power_error; + } + + /* Initialize reg dma block which is a singleton */ + rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog, + sde_kms->dev); + if (rc) { + SDE_ERROR("failed: reg dma init failed\n"); + goto power_error; + } + + sde_dbg_init_dbg_buses(sde_kms->core_rev); + + rm = &sde_kms->rm; + rc = sde_rm_init(rm, sde_kms->catalog, sde_kms->mmio, + sde_kms->dev); + if (rc) { + SDE_ERROR("rm init failed: %d\n", rc); + goto power_error; + } + + sde_kms->rm_init = true; + + sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog); + if (IS_ERR_OR_NULL(sde_kms->hw_intr)) { + rc = PTR_ERR(sde_kms->hw_intr); + SDE_ERROR("hw_intr init failed: %d\n", rc); + sde_kms->hw_intr = NULL; + goto hw_intr_init_err; + } + + /* + * Attempt continuous splash handoff only if reserved + * splash memory is found & release resources on any error + * in finding display hw config in splash + */ + if (sde_kms->splash_data.num_splash_regions) { + struct sde_splash_display *display; + int ret, display_count = + sde_kms->splash_data.num_splash_displays; + + ret = sde_rm_cont_splash_res_init(priv, &sde_kms->rm, + &sde_kms->splash_data, sde_kms->catalog); + + for (i = 0; i < display_count; i++) { + display = &sde_kms->splash_data.splash_display[i]; + /* + * free splash region on resource init failure and + * cont-splash disabled case + */ + if (!display->cont_splash_enabled || ret) + _sde_kms_free_splash_region(sde_kms, display); + } + } + + sde_kms->hw_mdp = sde_rm_get_mdp(&sde_kms->rm); + if (IS_ERR_OR_NULL(sde_kms->hw_mdp)) { + rc = PTR_ERR(sde_kms->hw_mdp); + if (!sde_kms->hw_mdp) + rc = -EINVAL; + SDE_ERROR("failed to get hw_mdp: %d\n", rc); + sde_kms->hw_mdp = NULL; + goto power_error; + } + + for (i = 0; i < sde_kms->catalog->vbif_count; i++) { + u32 vbif_idx = sde_kms->catalog->vbif[i].id; + + sde_kms->hw_vbif[i] = sde_hw_vbif_init(vbif_idx, + sde_kms->vbif[vbif_idx], sde_kms->catalog); + if (IS_ERR_OR_NULL(sde_kms->hw_vbif[vbif_idx])) { + rc = PTR_ERR(sde_kms->hw_vbif[vbif_idx]); + if (!sde_kms->hw_vbif[vbif_idx]) + rc = -EINVAL; + SDE_ERROR("failed to init vbif %d: %d\n", vbif_idx, rc); + sde_kms->hw_vbif[vbif_idx] = NULL; + goto power_error; + } + } + + if (sde_kms->catalog->uidle_cfg.uidle_rev) { + sde_kms->hw_uidle = sde_hw_uidle_init(UIDLE, sde_kms->mmio, + sde_kms->mmio_len, sde_kms->catalog); + if (IS_ERR_OR_NULL(sde_kms->hw_uidle)) { + rc = PTR_ERR(sde_kms->hw_uidle); + if (!sde_kms->hw_uidle) + rc = -EINVAL; + /* uidle is optional, so do not make it a fatal error */ + SDE_ERROR("failed to init uidle rc:%d\n", rc); + sde_kms->hw_uidle = NULL; + rc = 0; + } + } else { + sde_kms->hw_uidle = NULL; + } + + sde_kms->hw_sid = sde_hw_sid_init(sde_kms->sid, + sde_kms->sid_len, sde_kms->catalog); + if (IS_ERR(sde_kms->hw_sid)) { + SDE_ERROR("failed to init sid %ld\n", PTR_ERR(sde_kms->hw_sid)); + sde_kms->hw_sid = NULL; + goto power_error; + } + + rc = sde_core_perf_init(&sde_kms->perf, dev, sde_kms->catalog, + &priv->phandle, "core_clk"); + if (rc) { + SDE_ERROR("failed to init perf %d\n", rc); + goto perf_err; + } + + /* + * _sde_kms_drm_obj_init should create the DRM related objects + * i.e. CRTCs, planes, encoders, connectors and so forth + */ + rc = _sde_kms_drm_obj_init(sde_kms); + if (rc) { + SDE_ERROR("modeset init failed: %d\n", rc); + goto drm_obj_init_err; + } + + return 0; + +genpd_err: +drm_obj_init_err: + sde_core_perf_destroy(&sde_kms->perf); +hw_intr_init_err: +perf_err: +power_error: + return rc; +} + +static int sde_kms_hw_init(struct msm_kms *kms) +{ + struct sde_kms *sde_kms; + struct drm_device *dev; + struct msm_drm_private *priv; + struct platform_device *platformdev; + int i, irq_num, rc = -EINVAL; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + goto end; + } + + sde_kms = to_sde_kms(kms); + dev = sde_kms->dev; + if (!dev || !dev->dev) { + SDE_ERROR("invalid device\n"); + goto end; + } + + platformdev = to_platform_device(dev->dev); + priv = dev->dev_private; + if (!priv) { + SDE_ERROR("invalid private data\n"); + goto end; + } + + rc = _sde_kms_hw_init_ioremap(sde_kms, platformdev); + if (rc) + goto error; + + rc = _sde_kms_get_splash_data(&sde_kms->splash_data); + if (rc) + SDE_DEBUG("sde splash data fetch failed: %d\n", rc); + + rc = pm_runtime_get_sync(sde_kms->dev->dev); + if (rc < 0) { + SDE_ERROR("resource enable failed: %d\n", rc); + goto error; + } + + rc = _sde_kms_hw_init_blocks(sde_kms, dev, priv); + if (rc) + goto hw_init_err; + + dev->mode_config.min_width = sde_kms->catalog->min_display_width; + dev->mode_config.min_height = sde_kms->catalog->min_display_height; + dev->mode_config.max_width = sde_kms->catalog->max_display_width; + dev->mode_config.max_height = sde_kms->catalog->max_display_height; + + mutex_init(&sde_kms->secure_transition_lock); + mutex_init(&sde_kms->vblank_ctl_global_lock); + + atomic_set(&sde_kms->detach_sec_cb, 0); + atomic_set(&sde_kms->detach_all_cb, 0); + + /* + * Support format modifiers for compression etc. + */ + dev->mode_config.allow_fb_modifiers = true; + + /* + * Handle (re)initializations during power enable + */ + sde_kms_handle_power_event(SDE_POWER_EVENT_POST_ENABLE, sde_kms); + sde_kms->power_event = sde_power_handle_register_event(&priv->phandle, + SDE_POWER_EVENT_POST_ENABLE | + SDE_POWER_EVENT_PRE_DISABLE, + sde_kms_handle_power_event, sde_kms, "kms"); + + if (sde_kms->splash_data.num_splash_displays) { + SDE_DEBUG("Skipping MDP Resources disable\n"); + } else { + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(&priv->phandle, i, + SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + + pm_runtime_put_sync(sde_kms->dev->dev); + } + + sde_kms->affinity_notify.notify = sde_kms_irq_affinity_notify; + sde_kms->affinity_notify.release = sde_kms_irq_affinity_release; + + irq_num = platform_get_irq(to_platform_device(sde_kms->dev->dev), 0); + SDE_DEBUG("Registering for notification of irq_num: %d\n", irq_num); + irq_set_affinity_notifier(irq_num, &sde_kms->affinity_notify); + + return 0; + +hw_init_err: + pm_runtime_put_sync(sde_kms->dev->dev); +error: + _sde_kms_hw_destroy(sde_kms, platformdev); +end: + return rc; +} + +struct msm_kms *sde_kms_init(struct drm_device *dev) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!dev || !dev->dev_private) { + SDE_ERROR("drm device node invalid\n"); + return ERR_PTR(-EINVAL); + } + + priv = dev->dev_private; + + sde_kms = kzalloc(sizeof(*sde_kms), GFP_KERNEL); + if (!sde_kms) { + SDE_ERROR("failed to allocate sde kms\n"); + return ERR_PTR(-ENOMEM); + } + + msm_kms_init(&sde_kms->base, &kms_funcs); + sde_kms->dev = dev; + + return &sde_kms->base; +} + +static int _sde_kms_register_events(struct msm_kms *kms, + struct drm_mode_object *obj, u32 event, bool en) +{ + int ret = 0; + struct drm_crtc *crtc = NULL; + struct drm_connector *conn = NULL; + struct sde_kms *sde_kms = NULL; + + if (!kms || !obj) { + SDE_ERROR("invalid argument kms %pK obj %pK\n", kms, obj); + return -EINVAL; + } + + sde_kms = to_sde_kms(kms); + switch (obj->type) { + case DRM_MODE_OBJECT_CRTC: + crtc = obj_to_crtc(obj); + ret = sde_crtc_register_custom_event(sde_kms, crtc, event, en); + break; + case DRM_MODE_OBJECT_CONNECTOR: + conn = obj_to_connector(obj); + ret = sde_connector_register_custom_event(sde_kms, conn, event, + en); + break; + } + + return ret; +} + +int sde_kms_handle_recovery(struct drm_encoder *encoder) +{ + SDE_EVT32(DRMID(encoder), MSM_ENC_ACTIVE_REGION); + return sde_encoder_wait_for_event(encoder, MSM_ENC_ACTIVE_REGION); +} diff --git a/techpack/display/msm/sde/sde_kms.h b/techpack/display/msm/sde/sde_kms.h new file mode 100644 index 0000000000000000000000000000000000000000..6225705c6d619748a5301914604c2c70bc0bae49 --- /dev/null +++ b/techpack/display/msm/sde/sde_kms.h @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SDE_KMS_H__ +#define __SDE_KMS_H__ + +#include <linux/msm_ion.h> +#include <linux/pm_domain.h> +#include <linux/pm_qos.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "msm_mmu.h" +#include "msm_gem.h" +#include "sde_dbg.h" +#include "sde_hw_catalog.h" +#include "sde_hw_ctl.h" +#include "sde_hw_lm.h" +#include "sde_hw_pingpong.h" +#include "sde_hw_interrupts.h" +#include "sde_hw_wb.h" +#include "sde_hw_top.h" +#include "sde_hw_uidle.h" +#include "sde_rm.h" +#include "sde_power_handle.h" +#include "sde_irq.h" +#include "sde_core_perf.h" + +#define DRMID(x) ((x) ? (x)->base.id : -1) + +/** + * SDE_DEBUG - macro for kms/plane/crtc/encoder/connector logs + * @fmt: Pointer to format string + */ +#define SDE_DEBUG(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_KMS)) \ + DRM_DEBUG(fmt, ##__VA_ARGS__); \ + else \ + pr_debug(fmt, ##__VA_ARGS__); \ + } while (0) + +/** + * SDE_INFO - macro for kms/plane/crtc/encoder/connector logs + * @fmt: Pointer to format string + */ +#define SDE_INFO(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_KMS)) \ + DRM_INFO(fmt, ##__VA_ARGS__); \ + else \ + pr_info(fmt, ##__VA_ARGS__); \ + } while (0) + +/** + * SDE_DEBUG_DRIVER - macro for hardware driver logging + * @fmt: Pointer to format string + */ +#define SDE_DEBUG_DRIVER(fmt, ...) \ + do { \ + if (unlikely(drm_debug & DRM_UT_DRIVER)) \ + DRM_ERROR(fmt, ##__VA_ARGS__); \ + else \ + pr_debug(fmt, ##__VA_ARGS__); \ + } while (0) + +#define SDE_ERROR(fmt, ...) pr_err("[sde error]" fmt, ##__VA_ARGS__) + +#define POPULATE_RECT(rect, a, b, c, d, Q16_flag) \ + do { \ + (rect)->x = (Q16_flag) ? (a) >> 16 : (a); \ + (rect)->y = (Q16_flag) ? (b) >> 16 : (b); \ + (rect)->w = (Q16_flag) ? (c) >> 16 : (c); \ + (rect)->h = (Q16_flag) ? (d) >> 16 : (d); \ + } while (0) + +#define CHECK_LAYER_BOUNDS(offset, size, max_size) \ + (((size) > (max_size)) || ((offset) > ((max_size) - (size)))) + +/** + * ktime_compare_safe - compare two ktime structures + * This macro is similar to the standard ktime_compare() function, but + * attempts to also handle ktime overflows. + * @A: First ktime value + * @B: Second ktime value + * Returns: -1 if A < B, 0 if A == B, 1 if A > B + */ +#define ktime_compare_safe(A, B) \ + ktime_compare(ktime_sub((A), (B)), ktime_set(0, 0)) + +#define SDE_NAME_SIZE 12 + +/* timeout in frames waiting for frame done */ +#define SDE_FRAME_DONE_TIMEOUT 60 + +/* max active secure client counts allowed */ +#define MAX_ALLOWED_SECURE_CLIENT_CNT 1 + +/* max active crtc when secure client is active */ +#define MAX_ALLOWED_CRTC_CNT_DURING_SECURE 1 + +/* max virtual encoders per secure crtc */ +#define MAX_ALLOWED_ENCODER_CNT_PER_SECURE_CRTC 1 + +/* defines the operations required for secure state transition */ +#define SDE_KMS_OPS_SECURE_STATE_CHANGE BIT(0) +#define SDE_KMS_OPS_WAIT_FOR_TX_DONE BIT(1) +#define SDE_KMS_OPS_CLEANUP_PLANE_FB BIT(2) +#define SDE_KMS_OPS_PREPARE_PLANE_FB BIT(3) + +/* ESD status check interval in miliseconds */ +#define STATUS_CHECK_INTERVAL_MS 3000 + +/** + * enum sde_kms_smmu_state: smmu state + * @ATTACHED: all the context banks are attached. + * @DETACHED: all the context banks are detached. + * @DETACHED_SEC: secure context bank is detached. + * @ATTACH_ALL_REQ: transient state of attaching context banks. + * @DETACH_ALL_REQ: transient state of detaching context banks. + * @DETACH_SEC_REQ: tranisent state of secure context bank is detached + * @ATTACH_SEC_REQ: transient state of attaching secure context bank. + */ +enum sde_kms_smmu_state { + ATTACHED = 0, + DETACHED, + DETACHED_SEC, + ATTACH_ALL_REQ, + DETACH_ALL_REQ, + DETACH_SEC_REQ, + ATTACH_SEC_REQ, +}; + +/** + * enum sde_kms_smmu_state_transition_type: state transition type + * @NONE: no pending state transitions + * @PRE_COMMIT: state transitions should be done before processing the commit + * @POST_COMMIT: state transitions to be done after processing the commit. + */ +enum sde_kms_smmu_state_transition_type { + NONE, + PRE_COMMIT, + POST_COMMIT +}; + +/** + * enum sde_kms_sui_misr_state: state request for enabling/disabling MISR + * @NONE: no request + * @ENABLE_SUI_MISR_REQ: request to enable sui MISR + * @DISABLE_SUI_MISR_REQ: request to disable sui MISR + */ +enum sde_kms_sui_misr_state { + SUI_MISR_NONE, + SUI_MISR_ENABLE_REQ, + SUI_MISR_DISABLE_REQ +}; + +/* + * @FRAME_DONE_WAIT_DEFAULT: waits for frame N pp_done interrupt before + * triggering frame N+1. + * @FRAME_DONE_WAIT_SERIALIZE: serialize pp_done and ctl_start irq for frame + * N without next frame trigger wait. + * @FRAME_DONE_WAIT_POSTED_START: Do not wait for pp_done interrupt for any + * frame. Wait will trigger only for error case. + */ +enum frame_trigger_mode_type { + FRAME_DONE_WAIT_DEFAULT, + FRAME_DONE_WAIT_SERIALIZE, + FRAME_DONE_WAIT_POSTED_START, +}; + +/** + * struct sde_kms_smmu_state_data: stores the smmu state and transition type + * @state: current state of smmu context banks + * @prev_state: previous state of smmu context banks + * @secure_level: secure level cached from crtc + * @prev_secure_level: previous secure level + * @transition_type: transition request type + * @transition_error: whether there is error while transitioning the state + */ +struct sde_kms_smmu_state_data { + uint32_t state; + uint32_t prev_state; + uint32_t secure_level; + uint32_t prev_secure_level; + uint32_t transition_type; + uint32_t transition_error; + uint32_t sui_misr_state; +}; + +/* + * struct sde_irq_callback - IRQ callback handlers + * @list: list to callback + * @func: intr handler + * @arg: argument for the handler + */ +struct sde_irq_callback { + struct list_head list; + void (*func)(void *arg, int irq_idx); + void *arg; +}; + +/** + * struct sde_irq: IRQ structure contains callback registration info + * @total_irq: total number of irq_idx obtained from HW interrupts mapping + * @irq_cb_tbl: array of IRQ callbacks setting + * @enable_counts array of IRQ enable counts + * @cb_lock: callback lock + * @debugfs_file: debugfs file for irq statistics + */ +struct sde_irq { + u32 total_irqs; + struct list_head *irq_cb_tbl; + atomic_t *enable_counts; + atomic_t *irq_counts; + spinlock_t cb_lock; + struct dentry *debugfs_file; +}; + +struct sde_kms { + struct msm_kms base; + struct drm_device *dev; + int core_rev; + struct sde_mdss_cfg *catalog; + + struct generic_pm_domain genpd; + bool genpd_init; + + struct msm_gem_address_space *aspace[MSM_SMMU_DOMAIN_MAX]; + struct sde_power_event *power_event; + + /* directory entry for debugfs */ + struct dentry *debugfs_vbif; + + /* io/register spaces: */ + void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma, *sid, + *imem; + unsigned long mmio_len, vbif_len[VBIF_MAX], + reg_dma_len, sid_len, imem_len; + + struct regulator *vdd; + struct regulator *mmagic; + struct regulator *venus; + + struct sde_irq_controller irq_controller; + + struct sde_hw_intr *hw_intr; + struct sde_irq irq_obj; + int irq_num; /* mdss irq number */ + bool irq_enabled; + + struct sde_core_perf perf; + + /* saved atomic state during system suspend */ + struct drm_atomic_state *suspend_state; + bool suspend_block; + + struct sde_rm rm; + bool rm_init; + struct sde_splash_data splash_data; + struct sde_hw_vbif *hw_vbif[VBIF_MAX]; + struct sde_hw_mdp *hw_mdp; + struct sde_hw_uidle *hw_uidle; + struct sde_hw_sid *hw_sid; + int dsi_display_count; + void **dsi_displays; + int wb_display_count; + void **wb_displays; + int dp_display_count; + void **dp_displays; + int dp_stream_count; + + bool has_danger_ctrl; + + struct sde_kms_smmu_state_data smmu_state; + atomic_t detach_sec_cb; + atomic_t detach_all_cb; + struct mutex secure_transition_lock; + struct mutex vblank_ctl_global_lock; + + bool first_kickoff; + bool qdss_enabled; + + cpumask_t irq_cpu_mask; + struct pm_qos_request pm_qos_irq_req; + struct irq_affinity_notify affinity_notify; + bool pm_qos_irq_req_en; +}; + +/** + * struct sde_boot_config: display info stored in imem region + * @header: header info containing magic ID, frame buffer sizes, + * checksum & platformID + * @addr1: Lower 32 bits of Frame Buffer Address + * @addr2: Higher 32 bits of Frame Buffer Address + * @reserved: Reserved + */ +struct sde_boot_config { + u32 header; + u32 addr1; + u32 addr2; + u32 reserved; +}; + +struct vsync_info { + u32 frame_count; + u32 line_count; +}; + +#define to_sde_kms(x) container_of(x, struct sde_kms, base) + +/** + * sde_is_custom_client - whether or not to enable non-standard customizations + * + * Return: Whether or not the 'sdeclient' module parameter was set on boot up + */ +bool sde_is_custom_client(void); + +/** + * sde_kms_power_resource_is_enabled - whether or not power resource is enabled + * @dev: Pointer to drm device + * Return: true if power resource is enabled; false otherwise + */ +static inline bool sde_kms_power_resource_is_enabled(struct drm_device *dev) +{ + if (!dev) + return false; + + return pm_runtime_enabled(dev->dev); +} + +/** + * sde_kms_is_suspend_state - whether or not the system is pm suspended + * @dev: Pointer to drm device + * Return: Suspend status + */ +static inline bool sde_kms_is_suspend_state(struct drm_device *dev) +{ + if (!ddev_to_msm_kms(dev)) + return false; + + return to_sde_kms(ddev_to_msm_kms(dev))->suspend_state != NULL; +} + +/** + * sde_kms_is_suspend_blocked - whether or not commits are blocked due to pm + * suspend status + * @dev: Pointer to drm device + * Return: True if commits should be rejected due to pm suspend + */ +static inline bool sde_kms_is_suspend_blocked(struct drm_device *dev) +{ + if (!sde_kms_is_suspend_state(dev)) + return false; + + return to_sde_kms(ddev_to_msm_kms(dev))->suspend_block; +} + +/** + * sde_kms_is_secure_session_inprogress - to indicate if secure-session is in + * currently in-progress based on the current smmu_state + * + * @sde_kms: Pointer to sde_kms + * + * return: true if secure-session is in progress; false otherwise + */ +static inline bool sde_kms_is_secure_session_inprogress(struct sde_kms *sde_kms) +{ + bool ret = false; + + if (!sde_kms) + return false; + + mutex_lock(&sde_kms->secure_transition_lock); + if (((sde_kms->catalog->sui_ns_allowed) && + (sde_kms->smmu_state.secure_level == SDE_DRM_SEC_ONLY) && + ((sde_kms->smmu_state.state == DETACHED_SEC) || + (sde_kms->smmu_state.state == DETACH_SEC_REQ) || + (sde_kms->smmu_state.state == ATTACH_SEC_REQ))) + || (((sde_kms->smmu_state.state == DETACHED) || + (sde_kms->smmu_state.state == DETACH_ALL_REQ) || + (sde_kms->smmu_state.state == ATTACH_ALL_REQ)))) + ret = true; + mutex_unlock(&sde_kms->secure_transition_lock); + + return ret; +} + +/** + * sde_kms_is_vbif_operation_allowed - resticts the VBIF programming + * during secure-ui, if the sec_ui_misr feature is enabled + * + * @sde_kms: Pointer to sde_kms + * + * return: false if secure-session is in progress; true otherwise + */ +static inline bool sde_kms_is_vbif_operation_allowed(struct sde_kms *sde_kms) +{ + if (!sde_kms) + return false; + + if (!sde_kms->catalog->sui_misr_supported) + return true; + + return !sde_kms_is_secure_session_inprogress(sde_kms); +} + +/** + * sde_kms_is_cp_operation_allowed - resticts the CP programming + * during secure-ui, if the non-secure context banks are detached + * + * @sde_kms: Pointer to sde_kms + */ +static inline bool sde_kms_is_cp_operation_allowed(struct sde_kms *sde_kms) +{ + if (!sde_kms || !sde_kms->catalog) + return false; + + if (sde_kms->catalog->sui_ns_allowed) + return true; + + return !sde_kms_is_secure_session_inprogress(sde_kms); +} + +/** + * Debugfs functions - extra helper functions for debugfs support + * + * Main debugfs documentation is located at, + * + * Documentation/filesystems/debugfs.txt + * + * @sde_debugfs_get_root: Get root dentry for SDE_KMS's debugfs node + */ + +/** + * sde_debugfs_get_root - Return root directory entry for KMS's debugfs + * + * The return value should be passed as the 'parent' argument to subsequent + * debugfs create calls. + * + * @sde_kms: Pointer to SDE's KMS structure + * + * Return: dentry pointer for SDE's debugfs location + */ +void *sde_debugfs_get_root(struct sde_kms *sde_kms); + +/** + * SDE info management functions + * These functions/definitions allow for building up a 'sde_info' structure + * containing one or more "key=value\n" entries. + */ +#define SDE_KMS_INFO_MAX_SIZE 4096 + +/** + * struct sde_kms_info - connector information structure container + * @data: Array of information character data + * @len: Current length of information data + * @staged_len: Temporary data buffer length, commit to + * len using sde_kms_info_stop + * @start: Whether or not a partial data entry was just started + */ +struct sde_kms_info { + char data[SDE_KMS_INFO_MAX_SIZE]; + uint32_t len; + uint32_t staged_len; + bool start; +}; + +/** + * SDE_KMS_INFO_DATA - Macro for accessing sde_kms_info data bytes + * @S: Pointer to sde_kms_info structure + * Returns: Pointer to byte data + */ +#define SDE_KMS_INFO_DATA(S) ((S) ? ((struct sde_kms_info *)(S))->data \ + : NULL) + +/** + * SDE_KMS_INFO_DATALEN - Macro for accessing sde_kms_info data length + * it adds an extra character length to count null. + * @S: Pointer to sde_kms_info structure + * Returns: Size of available byte data + */ +#define SDE_KMS_INFO_DATALEN(S) ((S) ? ((struct sde_kms_info *)(S))->len + 1 \ + : 0) + +/** + * sde_kms_info_reset - reset sde_kms_info structure + * @info: Pointer to sde_kms_info structure + */ +void sde_kms_info_reset(struct sde_kms_info *info); + +/** + * sde_kms_info_add_keyint - add integer value to 'sde_kms_info' + * @info: Pointer to sde_kms_info structure + * @key: Pointer to key string + * @value: Signed 64-bit integer value + */ +void sde_kms_info_add_keyint(struct sde_kms_info *info, + const char *key, + int64_t value); + +/** + * sde_kms_info_add_keystr - add string value to 'sde_kms_info' + * @info: Pointer to sde_kms_info structure + * @key: Pointer to key string + * @value: Pointer to string value + */ +void sde_kms_info_add_keystr(struct sde_kms_info *info, + const char *key, + const char *value); + +/** + * sde_kms_info_start - begin adding key to 'sde_kms_info' + * Usage: + * sde_kms_info_start(key) + * sde_kms_info_append(val_1) + * ... + * sde_kms_info_append(val_n) + * sde_kms_info_stop + * @info: Pointer to sde_kms_info structure + * @key: Pointer to key string + */ +void sde_kms_info_start(struct sde_kms_info *info, + const char *key); + +/** + * sde_kms_info_append - append value string to 'sde_kms_info' + * Usage: + * sde_kms_info_start(key) + * sde_kms_info_append(val_1) + * ... + * sde_kms_info_append(val_n) + * sde_kms_info_stop + * @info: Pointer to sde_kms_info structure + * @str: Pointer to partial value string + */ +void sde_kms_info_append(struct sde_kms_info *info, + const char *str); + +/** + * sde_kms_info_append_format - append format code string to 'sde_kms_info' + * Usage: + * sde_kms_info_start(key) + * sde_kms_info_append_format(fourcc, modifier) + * ... + * sde_kms_info_stop + * @info: Pointer to sde_kms_info structure + * @pixel_format: FOURCC format code + * @modifier: 64-bit drm format modifier + */ +void sde_kms_info_append_format(struct sde_kms_info *info, + uint32_t pixel_format, + uint64_t modifier); + +/** + * sde_kms_info_stop - finish adding key to 'sde_kms_info' + * Usage: + * sde_kms_info_start(key) + * sde_kms_info_append(val_1) + * ... + * sde_kms_info_append(val_n) + * sde_kms_info_stop + * @info: Pointer to sde_kms_info structure + */ +void sde_kms_info_stop(struct sde_kms_info *info); + +/** + * sde_kms_rect_intersect - intersect two rectangles + * @r1: first rectangle + * @r2: scissor rectangle + * @result: result rectangle, all 0's on no intersection found + */ +void sde_kms_rect_intersect(const struct sde_rect *r1, + const struct sde_rect *r2, + struct sde_rect *result); + +/** + * sde_kms_rect_merge_rectangles - merge a rectangle list into one rect + * @rois: pointer to the list of rois + * @result: output rectangle, all 0 on error + */ +void sde_kms_rect_merge_rectangles(const struct msm_roi_list *rois, + struct sde_rect *result); + +/** + * sde_kms_rect_is_equal - compares two rects + * @r1: rect value to compare + * @r2: rect value to compare + * + * Returns 1 if the rects are same, 0 otherwise. + */ +static inline bool sde_kms_rect_is_equal(struct sde_rect *r1, + struct sde_rect *r2) +{ + if ((!r1 && r2) || (r1 && !r2)) + return false; + + if (!r1 && !r2) + return true; + + return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w && + r1->h == r2->h; +} + +/** + * sde_kms_rect_is_null - returns true if the width or height of a rect is 0 + * @rect: rectangle to check for zero size + * @Return: True if width or height of rectangle is 0 + */ +static inline bool sde_kms_rect_is_null(const struct sde_rect *r) +{ + if (!r) + return true; + + return (!r->w || !r->h); +} + +/** + * Vblank enable/disable functions + */ +int sde_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); +void sde_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); + +/** + * smmu attach/detach functions + * @sde_kms: poiner to sde_kms structure + * @secure_only: if true only secure contexts are attached/detached, else + * all contexts are attached/detached/ + */ +int sde_kms_mmu_attach(struct sde_kms *sde_kms, bool secure_only); +int sde_kms_mmu_detach(struct sde_kms *sde_kms, bool secure_only); + +/** + * sde_kms_timeline_status - provides current timeline status + * @dev: Pointer to drm device + */ +void sde_kms_timeline_status(struct drm_device *dev); + +/** + * sde_kms_handle_recovery - handler function for FIFO overflow issue + * @encoder: pointer to drm encoder structure + * return: 0 on success; error code otherwise + */ +int sde_kms_handle_recovery(struct drm_encoder *encoder); + +/** + * sde_kms_update_pm_qos_irq_request - Update Qos vote for CPU receiving + * display IRQ + * @sde_kms : pointer to sde_kms structure + * @enable : indicates request to be enabled or disabled + * @skip_lock : indicates if lock needs to be acquired + */ +void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms, + bool enable, bool skip_lock); +#endif /* __sde_kms_H__ */ diff --git a/techpack/display/msm/sde/sde_kms_utils.c b/techpack/display/msm/sde/sde_kms_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..7bb2445e2ba578511a8d2678ff763eff5c6872f4 --- /dev/null +++ b/techpack/display/msm/sde/sde_kms_utils.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "sde-kms_utils:[%s] " fmt, __func__ + +#include "sde_kms.h" + +void sde_kms_info_reset(struct sde_kms_info *info) +{ + if (info) { + info->len = 0; + info->staged_len = 0; + } +} + +void sde_kms_info_add_keyint(struct sde_kms_info *info, + const char *key, + int64_t value) +{ + uint32_t len; + + if (info && key) { + len = snprintf(info->data + info->len, + SDE_KMS_INFO_MAX_SIZE - info->len, + "%s=%lld\n", + key, + value); + + /* check if snprintf truncated the string */ + if ((info->len + len) < SDE_KMS_INFO_MAX_SIZE) + info->len += len; + } +} + +void sde_kms_info_add_keystr(struct sde_kms_info *info, + const char *key, + const char *value) +{ + uint32_t len; + + if (info && key && value) { + len = snprintf(info->data + info->len, + SDE_KMS_INFO_MAX_SIZE - info->len, + "%s=%s\n", + key, + value); + + /* check if snprintf truncated the string */ + if ((info->len + len) < SDE_KMS_INFO_MAX_SIZE) + info->len += len; + } +} + +void sde_kms_info_start(struct sde_kms_info *info, + const char *key) +{ + uint32_t len; + + if (info && key) { + len = snprintf(info->data + info->len, + SDE_KMS_INFO_MAX_SIZE - info->len, + "%s=", + key); + + info->start = true; + + /* check if snprintf truncated the string */ + if ((info->len + len) < SDE_KMS_INFO_MAX_SIZE) + info->staged_len = info->len + len; + } +} + +void sde_kms_info_append(struct sde_kms_info *info, + const char *str) +{ + uint32_t len; + + if (info) { + len = snprintf(info->data + info->staged_len, + SDE_KMS_INFO_MAX_SIZE - info->staged_len, + "%s", + str); + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < SDE_KMS_INFO_MAX_SIZE) { + info->staged_len += len; + info->start = false; + } + } +} + +void sde_kms_info_append_format(struct sde_kms_info *info, + uint32_t pixel_format, + uint64_t modifier) +{ + uint32_t len; + + if (!info) + return; + + if (modifier) { + len = snprintf(info->data + info->staged_len, + SDE_KMS_INFO_MAX_SIZE - info->staged_len, + info->start ? + "%c%c%c%c/%llX/%llX" : " %c%c%c%c/%llX/%llX", + (pixel_format >> 0) & 0xFF, + (pixel_format >> 8) & 0xFF, + (pixel_format >> 16) & 0xFF, + (pixel_format >> 24) & 0xFF, + (modifier >> 56) & 0xFF, + modifier & ((1ULL << 56) - 1)); + } else { + len = snprintf(info->data + info->staged_len, + SDE_KMS_INFO_MAX_SIZE - info->staged_len, + info->start ? + "%c%c%c%c" : " %c%c%c%c", + (pixel_format >> 0) & 0xFF, + (pixel_format >> 8) & 0xFF, + (pixel_format >> 16) & 0xFF, + (pixel_format >> 24) & 0xFF); + } + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < SDE_KMS_INFO_MAX_SIZE) { + info->staged_len += len; + info->start = false; + } +} + +void sde_kms_info_stop(struct sde_kms_info *info) +{ + uint32_t len; + + if (info) { + /* insert final delimiter */ + len = snprintf(info->data + info->staged_len, + SDE_KMS_INFO_MAX_SIZE - info->staged_len, + "\n"); + + /* check if snprintf truncated the string */ + if ((info->staged_len + len) < SDE_KMS_INFO_MAX_SIZE) + info->len = info->staged_len + len; + } +} + +void sde_kms_rect_intersect(const struct sde_rect *r1, + const struct sde_rect *r2, + struct sde_rect *result) +{ + int l, t, r, b; + + if (!r1 || !r2 || !result) + return; + + l = max(r1->x, r2->x); + t = max(r1->y, r2->y); + r = min((r1->x + r1->w), (r2->x + r2->w)); + b = min((r1->y + r1->h), (r2->y + r2->h)); + + if (r <= l || b <= t) { + memset(result, 0, sizeof(*result)); + } else { + result->x = l; + result->y = t; + result->w = r - l; + result->h = b - t; + } +} + +void sde_kms_rect_merge_rectangles(const struct msm_roi_list *rois, + struct sde_rect *result) +{ + struct drm_clip_rect clip; + const struct drm_clip_rect *roi_rect; + int i; + + if (!rois || !result) + return; + + memset(result, 0, sizeof(*result)); + + /* init to invalid range maxes */ + clip.x1 = ~0; + clip.y1 = ~0; + clip.x2 = 0; + clip.y2 = 0; + + /* aggregate all clipping rectangles together for overall roi */ + for (i = 0; i < rois->num_rects; i++) { + roi_rect = &rois->roi[i]; + + clip.x1 = min(clip.x1, roi_rect->x1); + clip.y1 = min(clip.y1, roi_rect->y1); + clip.x2 = max(clip.x2, roi_rect->x2); + clip.y2 = max(clip.y2, roi_rect->y2); + + SDE_DEBUG("roi%d (%d,%d),(%d,%d) -> crtc (%d,%d),(%d,%d)\n", i, + roi_rect->x1, roi_rect->y1, + roi_rect->x2, roi_rect->y2, + clip.x1, clip.y1, + clip.x2, clip.y2); + } + + if (clip.x2 && clip.y2) { + result->x = clip.x1; + result->y = clip.y1; + result->w = clip.x2 - clip.x1; + result->h = clip.y2 - clip.y1; + } +} + diff --git a/techpack/display/msm/sde/sde_plane.c b/techpack/display/msm/sde/sde_plane.c new file mode 100644 index 0000000000000000000000000000000000000000..b4e901718aac0405b9fd775a9cad6ad5ad5488de --- /dev/null +++ b/techpack/display/msm/sde/sde_plane.c @@ -0,0 +1,4652 @@ +/* + * Copyright (C) 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> +#include <linux/dma-buf.h> +#include <uapi/drm/sde_drm.h> +#include <uapi/drm/msm_drm_pp.h> + +#include "msm_prop.h" +#include "msm_drv.h" + +#include "sde_kms.h" +#include "sde_fence.h" +#include "sde_formats.h" +#include "sde_hw_sspp.h" +#include "sde_hw_catalog_format.h" +#include "sde_trace.h" +#include "sde_crtc.h" +#include "sde_vbif.h" +#include "sde_plane.h" +#include "sde_color_processing.h" + +#define SDE_DEBUG_PLANE(pl, fmt, ...) SDE_DEBUG("plane%d " fmt,\ + (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) + +#define SDE_ERROR_PLANE(pl, fmt, ...) SDE_ERROR("plane%d " fmt,\ + (pl) ? (pl)->base.base.id : -1, ##__VA_ARGS__) + +#define DECIMATED_DIMENSION(dim, deci) (((dim) + ((1 << (deci)) - 1)) >> (deci)) +#define PHASE_STEP_SHIFT 21 +#define PHASE_STEP_UNIT_SCALE ((int) (1 << PHASE_STEP_SHIFT)) +#define PHASE_RESIDUAL 15 + +#define SHARP_STRENGTH_DEFAULT 32 +#define SHARP_EDGE_THR_DEFAULT 112 +#define SHARP_SMOOTH_THR_DEFAULT 8 +#define SHARP_NOISE_THR_DEFAULT 2 + +#define SDE_NAME_SIZE 12 + +#define SDE_PLANE_COLOR_FILL_FLAG BIT(31) + +#define TIME_MULTIPLEX_RECT(r0, r1, buffer_lines) \ + ((r0).y >= ((r1).y + (r1).h + buffer_lines)) + +/* multirect rect index */ +enum { + R0, + R1, + R_MAX +}; + +#define SDE_QSEED_DEFAULT_DYN_EXP 0x0 + +#define DEFAULT_REFRESH_RATE 60 + +/** + * enum sde_plane_qos - Different qos configurations for each pipe + * + * @SDE_PLANE_QOS_VBLANK_CTRL: Setup VBLANK qos for the pipe. + * @SDE_PLANE_QOS_VBLANK_AMORTIZE: Enables Amortization within pipe. + * this configuration is mutually exclusive from VBLANK_CTRL. + * @SDE_PLANE_QOS_PANIC_CTRL: Setup panic for the pipe. + */ +enum sde_plane_qos { + SDE_PLANE_QOS_VBLANK_CTRL = BIT(0), + SDE_PLANE_QOS_VBLANK_AMORTIZE = BIT(1), + SDE_PLANE_QOS_PANIC_CTRL = BIT(2), +}; + +/* + * struct sde_plane - local sde plane structure + * @aspace: address space pointer + * @csc_cfg: Decoded user configuration for csc + * @csc_usr_ptr: Points to csc_cfg if valid user config available + * @csc_ptr: Points to sde_csc_cfg structure to use for current + * @mplane_list: List of multirect planes of the same pipe + * @catalog: Points to sde catalog structure + * @revalidate: force revalidation of all the plane properties + * @xin_halt_forced_clk: whether or not clocks were forced on for xin halt + * @blob_rot_caps: Pointer to rotator capability blob + */ +struct sde_plane { + struct drm_plane base; + + struct mutex lock; + + enum sde_sspp pipe; + uint32_t features; /* capabilities from catalog */ + uint32_t perf_features; /* perf capabilities from catalog */ + uint32_t nformats; + uint32_t formats[64]; + + struct sde_hw_pipe *pipe_hw; + struct sde_hw_pipe_cfg pipe_cfg; + struct sde_hw_sharp_cfg sharp_cfg; + struct sde_hw_pipe_qos_cfg pipe_qos_cfg; + struct sde_vbif_set_qos_params cached_qos_params; + uint32_t color_fill; + bool is_error; + bool is_rt_pipe; + bool is_virtual; + struct list_head mplane_list; + struct sde_mdss_cfg *catalog; + bool revalidate; + bool xin_halt_forced_clk; + + struct sde_csc_cfg csc_cfg; + struct sde_csc_cfg *csc_usr_ptr; + struct sde_csc_cfg *csc_ptr; + + const struct sde_sspp_sub_blks *pipe_sblk; + + char pipe_name[SDE_NAME_SIZE]; + + struct msm_property_info property_info; + struct msm_property_data property_data[PLANE_PROP_COUNT]; + struct drm_property_blob *blob_info; + struct drm_property_blob *blob_rot_caps; + + /* debugfs related stuff */ + struct dentry *debugfs_root; + bool debugfs_default_scale; +}; + +#define to_sde_plane(x) container_of(x, struct sde_plane, base) + +static int plane_prop_array[PLANE_PROP_COUNT] = {SDE_PLANE_DIRTY_ALL}; + +static struct sde_kms *_sde_plane_get_kms(struct drm_plane *plane) +{ + struct msm_drm_private *priv; + + if (!plane || !plane->dev) + return NULL; + priv = plane->dev->dev_private; + if (!priv) + return NULL; + return to_sde_kms(priv->kms); +} + +static struct sde_hw_ctl *_sde_plane_get_hw_ctl(const struct drm_plane *plane) +{ + struct drm_plane_state *pstate = NULL; + struct drm_crtc *drm_crtc = NULL; + struct sde_crtc *sde_crtc = NULL; + struct sde_crtc_mixer *mixer = NULL; + struct sde_hw_ctl *ctl = NULL; + + if (!plane) { + DRM_ERROR("Invalid plane %pK\n", plane); + return NULL; + } + + pstate = plane->state; + if (!pstate) { + DRM_ERROR("Invalid plane state %pK\n", pstate); + return NULL; + } + + drm_crtc = pstate->crtc; + if (!drm_crtc) { + DRM_ERROR("Invalid drm_crtc %pK\n", drm_crtc); + return NULL; + } + + sde_crtc = to_sde_crtc(drm_crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return NULL; + } + + /* it will always return the first mixer and single CTL */ + mixer = sde_crtc->mixers; + if (!mixer) { + DRM_ERROR("invalid mixer %pK\n", mixer); + return NULL; + } + + ctl = mixer->hw_ctl; + if (!mixer) { + DRM_ERROR("invalid ctl %pK\n", ctl); + return NULL; + } + + return ctl; +} + +static bool sde_plane_enabled(const struct drm_plane_state *state) +{ + return state && state->fb && state->crtc; +} + +bool sde_plane_is_sec_ui_allowed(struct drm_plane *plane) +{ + struct sde_plane *psde; + + if (!plane) + return false; + + psde = to_sde_plane(plane); + + return !(psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI)); +} + +void sde_plane_setup_src_split_order(struct drm_plane *plane, + enum sde_sspp_multirect_index rect_mode, bool enable) +{ + struct sde_plane *psde; + + if (!plane) + return; + + psde = to_sde_plane(plane); + if (psde->pipe_hw->ops.set_src_split_order) + psde->pipe_hw->ops.set_src_split_order(psde->pipe_hw, + rect_mode, enable); +} + +/** + * _sde_plane_set_qos_lut - set danger, safe and creq LUT of the given plane + * @crtc: Pointer to drm crtc to find refresh rate on mode + * @fb: Pointer to framebuffer associated with the given plane + */ +static void _sde_plane_set_qos_lut(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb) +{ + struct sde_plane *psde; + const struct sde_format *fmt = NULL; + u32 frame_rate, qos_count, fps_index = 0, lut_index, index; + struct sde_perf_cfg *perf; + struct sde_plane_state *pstate; + struct sde_kms *kms; + + if (!plane || !fb) { + SDE_ERROR("invalid arguments\n"); + return; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(plane->state); + kms = _sde_plane_get_kms(plane); + if (!kms) { + SDE_ERROR("invalid kms\n"); + return; + } + + if (!psde->pipe_hw || !psde->pipe_sblk || !psde->catalog) { + SDE_ERROR("invalid arguments\n"); + return; + } else if (!psde->pipe_hw->ops.setup_qos_lut) { + return; + } + + frame_rate = crtc->mode.vrefresh; + perf = &psde->catalog->perf; + qos_count = perf->qos_refresh_count; + while (qos_count && perf->qos_refresh_rate) { + if (frame_rate >= perf->qos_refresh_rate[qos_count - 1]) { + fps_index = qos_count - 1; + break; + } + qos_count--; + } + + if (!psde->is_rt_pipe) { + lut_index = SDE_QOS_LUT_USAGE_NRT; + } else { + fmt = sde_get_sde_format_ext( + fb->format->format, + fb->modifier); + + if (fmt && SDE_FORMAT_IS_LINEAR(fmt) && + pstate->scaler3_cfg.enable && + IS_SDE_MAJOR_MINOR_SAME(kms->catalog->hwversion, + SDE_HW_VER_640)) + lut_index = SDE_QOS_LUT_USAGE_MACROTILE_QSEED; + else if (fmt && SDE_FORMAT_IS_LINEAR(fmt)) + lut_index = SDE_QOS_LUT_USAGE_LINEAR; + else if (pstate->scaler3_cfg.enable) + lut_index = SDE_QOS_LUT_USAGE_MACROTILE_QSEED; + else + lut_index = SDE_QOS_LUT_USAGE_MACROTILE; + } + + index = (fps_index * SDE_QOS_LUT_USAGE_MAX) + lut_index; + psde->pipe_qos_cfg.danger_lut = perf->danger_lut[index]; + psde->pipe_qos_cfg.safe_lut = perf->safe_lut[index]; + psde->pipe_qos_cfg.creq_lut = perf->creq_lut[index]; + + trace_sde_perf_set_qos_luts(psde->pipe - SSPP_VIG0, + (fmt) ? fmt->base.pixel_format : 0, + (fmt) ? fmt->fetch_mode : 0, + psde->pipe_qos_cfg.danger_lut, + psde->pipe_qos_cfg.safe_lut, + psde->pipe_qos_cfg.creq_lut); + + SDE_DEBUG( + "plane:%u pnum:%d fmt:%4.4s fps:%d mode:%d luts[0x%x,0x%x 0x%llx]\n", + plane->base.id, + psde->pipe - SSPP_VIG0, + fmt ? (char *)&fmt->base.pixel_format : NULL, frame_rate, + fmt ? fmt->fetch_mode : -1, + psde->pipe_qos_cfg.danger_lut, + psde->pipe_qos_cfg.safe_lut, + psde->pipe_qos_cfg.creq_lut); + + psde->pipe_hw->ops.setup_qos_lut(psde->pipe_hw, &psde->pipe_qos_cfg); +} + +/** + * _sde_plane_set_qos_ctrl - set QoS control of the given plane + * @plane: Pointer to drm plane + * @enable: true to enable QoS control + * @flags: QoS control mode (enum sde_plane_qos) + */ +static void _sde_plane_set_qos_ctrl(struct drm_plane *plane, + bool enable, u32 flags) +{ + struct sde_plane *psde; + + if (!plane) { + SDE_ERROR("invalid arguments\n"); + return; + } + + psde = to_sde_plane(plane); + + if (!psde->pipe_hw || !psde->pipe_sblk) { + SDE_ERROR("invalid arguments\n"); + return; + } else if (!psde->pipe_hw->ops.setup_qos_ctrl) { + return; + } + + if (flags & SDE_PLANE_QOS_VBLANK_CTRL) { + psde->pipe_qos_cfg.creq_vblank = psde->pipe_sblk->creq_vblank; + psde->pipe_qos_cfg.danger_vblank = + psde->pipe_sblk->danger_vblank; + psde->pipe_qos_cfg.vblank_en = enable; + } + + if (flags & SDE_PLANE_QOS_VBLANK_AMORTIZE) { + /* this feature overrules previous VBLANK_CTRL */ + psde->pipe_qos_cfg.vblank_en = false; + psde->pipe_qos_cfg.creq_vblank = 0; /* clear vblank bits */ + } + + if (flags & SDE_PLANE_QOS_PANIC_CTRL) + psde->pipe_qos_cfg.danger_safe_en = enable; + + if (!psde->is_rt_pipe) { + psde->pipe_qos_cfg.vblank_en = false; + psde->pipe_qos_cfg.danger_safe_en = false; + } + + SDE_DEBUG("plane%u: pnum:%d ds:%d vb:%d pri[0x%x, 0x%x] is_rt:%d\n", + plane->base.id, + psde->pipe - SSPP_VIG0, + psde->pipe_qos_cfg.danger_safe_en, + psde->pipe_qos_cfg.vblank_en, + psde->pipe_qos_cfg.creq_vblank, + psde->pipe_qos_cfg.danger_vblank, + psde->is_rt_pipe); + + psde->pipe_hw->ops.setup_qos_ctrl(psde->pipe_hw, + &psde->pipe_qos_cfg); +} + +void sde_plane_set_revalidate(struct drm_plane *plane, bool enable) +{ + struct sde_plane *psde; + + if (!plane) + return; + + psde = to_sde_plane(plane); + psde->revalidate = enable; +} + +int sde_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) +{ + struct sde_plane *psde; + int rc; + + if (!plane) { + SDE_ERROR("invalid arguments\n"); + return -EINVAL; + } + + psde = to_sde_plane(plane); + + if (!psde->is_rt_pipe) + goto end; + + rc = pm_runtime_get_sync(plane->dev->dev); + if (rc < 0) { + SDE_ERROR("failed to enable power resource %d\n", rc); + SDE_EVT32(rc, SDE_EVTLOG_ERROR); + return rc; + } + + _sde_plane_set_qos_ctrl(plane, enable, SDE_PLANE_QOS_PANIC_CTRL); + + pm_runtime_put_sync(plane->dev->dev); + +end: + return 0; +} + +/** + * _sde_plane_set_ot_limit - set OT limit for the given plane + * @plane: Pointer to drm plane + * @crtc: Pointer to drm crtc + */ +static void _sde_plane_set_ot_limit(struct drm_plane *plane, + struct drm_crtc *crtc) +{ + struct sde_plane *psde; + struct sde_vbif_set_ot_params ot_params; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!plane || !plane->dev || !crtc) { + SDE_ERROR("invalid arguments plane %d crtc %d\n", + !plane, !crtc); + return; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return; + } + + sde_kms = to_sde_kms(priv->kms); + psde = to_sde_plane(plane); + if (!psde->pipe_hw) { + SDE_ERROR("invalid pipe reference\n"); + return; + } + + memset(&ot_params, 0, sizeof(ot_params)); + ot_params.xin_id = psde->pipe_hw->cap->xin_id; + ot_params.num = psde->pipe_hw->idx - SSPP_NONE; + ot_params.width = psde->pipe_cfg.src_rect.w; + ot_params.height = psde->pipe_cfg.src_rect.h; + ot_params.is_wfd = !psde->is_rt_pipe; + ot_params.frame_rate = crtc->mode.vrefresh; + ot_params.vbif_idx = VBIF_RT; + ot_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl; + ot_params.rd = true; + + sde_vbif_set_ot_limit(sde_kms, &ot_params); +} + +/** + * _sde_plane_set_vbif_qos - set vbif QoS for the given plane + * @plane: Pointer to drm plane + * @force: Force update of vbif QoS + */ +static void _sde_plane_set_qos_remap(struct drm_plane *plane, bool force) +{ + struct sde_plane *psde; + struct sde_vbif_set_qos_params qos_params; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!plane || !plane->dev) { + SDE_ERROR("invalid arguments\n"); + return; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return; + } + + sde_kms = to_sde_kms(priv->kms); + psde = to_sde_plane(plane); + if (!psde->pipe_hw) { + SDE_ERROR("invalid pipe reference\n"); + return; + } + + memset(&qos_params, 0, sizeof(qos_params)); + qos_params.vbif_idx = VBIF_RT; + qos_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl; + qos_params.xin_id = psde->pipe_hw->cap->xin_id; + qos_params.num = psde->pipe_hw->idx - SSPP_VIG0; + qos_params.client_type = psde->is_rt_pipe ? + VBIF_RT_CLIENT : VBIF_NRT_CLIENT; + + if (!force && !memcmp(&qos_params, &psde->cached_qos_params, + sizeof(struct sde_vbif_set_qos_params))) { + return; + } + SDE_DEBUG("changes in vbif QoS parameters, remap it\n"); + + memcpy(&psde->cached_qos_params, &qos_params, + sizeof(struct sde_vbif_set_qos_params)); + + SDE_DEBUG("plane%d pipe:%d vbif:%d xin:%d rt:%d, clk_ctrl:%d\n", + plane->base.id, qos_params.num, + qos_params.vbif_idx, + qos_params.xin_id, qos_params.client_type, + qos_params.clk_ctrl); + + sde_vbif_set_qos_remap(sde_kms, &qos_params); +} + +/** + * _sde_plane_set_ts_prefill - set prefill with traffic shaper + * @plane: Pointer to drm plane + * @pstate: Pointer to sde plane state + */ +static void _sde_plane_set_ts_prefill(struct drm_plane *plane, + struct sde_plane_state *pstate) +{ + struct sde_plane *psde; + struct sde_hw_pipe_ts_cfg cfg; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + if (!plane || !plane->dev) { + SDE_ERROR("invalid arguments"); + return; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return; + } + + sde_kms = to_sde_kms(priv->kms); + psde = to_sde_plane(plane); + if (!psde->pipe_hw) { + SDE_ERROR("invalid pipe reference\n"); + return; + } + + if (!psde->pipe_hw || !psde->pipe_hw->ops.setup_ts_prefill) + return; + + _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_VBLANK_AMORTIZE); + + memset(&cfg, 0, sizeof(cfg)); + cfg.size = sde_plane_get_property(pstate, + PLANE_PROP_PREFILL_SIZE); + cfg.time = sde_plane_get_property(pstate, + PLANE_PROP_PREFILL_TIME); + + SDE_DEBUG("plane%d size:%llu time:%llu\n", + plane->base.id, cfg.size, cfg.time); + SDE_EVT32_VERBOSE(DRMID(plane), cfg.size, cfg.time); + psde->pipe_hw->ops.setup_ts_prefill(psde->pipe_hw, &cfg, + pstate->multirect_index); +} + +/* helper to update a state's input fence pointer from the property */ +static void _sde_plane_set_input_fence(struct sde_plane *psde, + struct sde_plane_state *pstate, uint64_t fd) +{ + if (!psde || !pstate) { + SDE_ERROR("invalid arg(s), plane %d state %d\n", + !psde, !pstate); + return; + } + + /* clear previous reference */ + if (pstate->input_fence) + sde_sync_put(pstate->input_fence); + + /* get fence pointer for later */ + if (fd == 0) + pstate->input_fence = NULL; + else + pstate->input_fence = sde_sync_get(fd); + + SDE_DEBUG_PLANE(psde, "0x%llX\n", fd); +} + +int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + uint32_t prefix; + void *input_fence; + int ret = -EINVAL; + signed long rc; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + } else if (!plane->state) { + SDE_ERROR_PLANE(to_sde_plane(plane), "invalid state\n"); + } else { + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(plane->state); + input_fence = pstate->input_fence; + + if (input_fence) { + prefix = sde_sync_get_name_prefix(input_fence); + rc = sde_sync_wait(input_fence, wait_ms); + + switch (rc) { + case 0: + SDE_ERROR_PLANE(psde, "%ums timeout on %08X fd %d\n", + wait_ms, prefix, sde_plane_get_property(pstate, + PLANE_PROP_INPUT_FENCE)); + psde->is_error = true; + sde_kms_timeline_status(plane->dev); + ret = -ETIMEDOUT; + break; + case -ERESTARTSYS: + SDE_ERROR_PLANE(psde, + "%ums wait interrupted on %08X\n", + wait_ms, prefix); + psde->is_error = true; + ret = -ERESTARTSYS; + break; + case -EINVAL: + SDE_ERROR_PLANE(psde, + "invalid fence param for %08X\n", + prefix); + psde->is_error = true; + ret = -EINVAL; + break; + default: + SDE_DEBUG_PLANE(psde, "signaled\n"); + ret = 0; + break; + } + + SDE_EVT32_VERBOSE(DRMID(plane), -ret, prefix); + } else { + ret = 0; + } + } + return ret; +} + +/** + * _sde_plane_get_aspace: gets the address space based on the + * fb_translation mode property + */ +static int _sde_plane_get_aspace( + struct sde_plane *psde, + struct sde_plane_state *pstate, + struct msm_gem_address_space **aspace) +{ + struct sde_kms *kms; + int mode; + + if (!psde || !pstate || !aspace) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + kms = _sde_plane_get_kms(&psde->base); + if (!kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + mode = sde_plane_get_property(pstate, + PLANE_PROP_FB_TRANSLATION_MODE); + + switch (mode) { + case SDE_DRM_FB_NON_SEC: + *aspace = kms->aspace[MSM_SMMU_DOMAIN_UNSECURE]; + if (!aspace) + return -EINVAL; + break; + case SDE_DRM_FB_SEC: + *aspace = kms->aspace[MSM_SMMU_DOMAIN_SECURE]; + if (!aspace) + return -EINVAL; + break; + case SDE_DRM_FB_SEC_DIR_TRANS: + *aspace = NULL; + break; + default: + SDE_ERROR("invalid fb_translation mode:%d\n", mode); + return -EFAULT; + } + + return 0; +} + +static inline void _sde_plane_set_scanout(struct drm_plane *plane, + struct sde_plane_state *pstate, + struct sde_hw_pipe_cfg *pipe_cfg, + struct drm_framebuffer *fb) +{ + struct sde_plane *psde; + struct msm_gem_address_space *aspace = NULL; + int ret, mode; + bool secure = false; + + if (!plane || !pstate || !pipe_cfg || !fb) { + SDE_ERROR( + "invalid arg(s), plane %d state %d cfg %d fb %d\n", + !plane, !pstate, !pipe_cfg, !fb); + return; + } + + psde = to_sde_plane(plane); + if (!psde->pipe_hw) { + SDE_ERROR_PLANE(psde, "invalid pipe_hw\n"); + return; + } + + ret = _sde_plane_get_aspace(psde, pstate, &aspace); + if (ret) { + SDE_ERROR_PLANE(psde, "Failed to get aspace %d\n", ret); + return; + } + + /* + * framebuffer prepare is deferred for prepare_fb calls that + * happen during the transition from secure to non-secure. + * Handle the prepare at this point for such cases. This can be + * expected for one or two frames during the transition. + */ + if (aspace && pstate->defer_prepare_fb) { + SDE_EVT32(DRMID(plane), psde->pipe, aspace->domain_attached); + ret = msm_framebuffer_prepare(fb, pstate->aspace); + if (ret) { + SDE_ERROR_PLANE(psde, + "failed to prepare framebuffer %d\n", ret); + return; + } + pstate->defer_prepare_fb = false; + } + mode = sde_plane_get_property(pstate, PLANE_PROP_FB_TRANSLATION_MODE); + if ((mode == SDE_DRM_FB_SEC) || (mode == SDE_DRM_FB_SEC_DIR_TRANS)) + secure = true; + + ret = sde_format_populate_layout(aspace, fb, &pipe_cfg->layout); + if (ret == -EAGAIN) + SDE_DEBUG_PLANE(psde, "not updating same src addrs\n"); + else if (ret) { + SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret); + + /* + * Force solid fill color on error. This is to prevent + * smmu faults during secure session transition. + */ + psde->is_error = true; + } else if (psde->pipe_hw->ops.setup_sourceaddress) { + SDE_EVT32_VERBOSE(psde->pipe_hw->idx, + pipe_cfg->layout.width, + pipe_cfg->layout.height, + pipe_cfg->layout.plane_addr[0], + pipe_cfg->layout.plane_size[0], + pipe_cfg->layout.plane_addr[1], + pipe_cfg->layout.plane_size[1], + pipe_cfg->layout.plane_addr[2], + pipe_cfg->layout.plane_size[2], + pipe_cfg->layout.plane_addr[3], + pipe_cfg->layout.plane_size[3], + pstate->multirect_index, + secure); + psde->pipe_hw->ops.setup_sourceaddress(psde->pipe_hw, pipe_cfg, + pstate->multirect_index); + } +} + +static int _sde_plane_setup_scaler3_lut(struct sde_plane *psde, + struct sde_plane_state *pstate) +{ + struct sde_hw_scaler3_cfg *cfg; + int ret = 0; + + if (!psde || !pstate) { + SDE_ERROR("invalid args\n"); + return -EINVAL; + } + + cfg = &pstate->scaler3_cfg; + + cfg->dir_lut = msm_property_get_blob( + &psde->property_info, + &pstate->property_state, &cfg->dir_len, + PLANE_PROP_SCALER_LUT_ED); + cfg->cir_lut = msm_property_get_blob( + &psde->property_info, + &pstate->property_state, &cfg->cir_len, + PLANE_PROP_SCALER_LUT_CIR); + cfg->sep_lut = msm_property_get_blob( + &psde->property_info, + &pstate->property_state, &cfg->sep_len, + PLANE_PROP_SCALER_LUT_SEP); + if (!cfg->dir_lut || !cfg->cir_lut || !cfg->sep_lut) + ret = -ENODATA; + return ret; +} + +static int _sde_plane_setup_scaler3lite_lut(struct sde_plane *psde, + struct sde_plane_state *pstate) +{ + struct sde_hw_scaler3_cfg *cfg; + + cfg = &pstate->scaler3_cfg; + + cfg->sep_lut = msm_property_get_blob( + &psde->property_info, + &pstate->property_state, &cfg->sep_len, + PLANE_PROP_SCALER_LUT_SEP); + + return cfg->sep_lut ? 0 : -ENODATA; +} + +static void _sde_plane_setup_scaler3(struct sde_plane *psde, + struct sde_plane_state *pstate, const struct sde_format *fmt, + uint32_t chroma_subsmpl_h, uint32_t chroma_subsmpl_v) +{ + uint32_t decimated, i, src_w, src_h, dst_w, dst_h; + struct sde_hw_scaler3_cfg *scale_cfg; + + if (!psde || !pstate || !fmt || + !chroma_subsmpl_h || !chroma_subsmpl_v) { + SDE_ERROR("psde %d pstate %d fmt %d smp_h %d smp_v %d\n", + !!psde, !!pstate, !!fmt, chroma_subsmpl_h, + chroma_subsmpl_v); + return; + } + + scale_cfg = &pstate->scaler3_cfg; + src_w = psde->pipe_cfg.src_rect.w; + src_h = psde->pipe_cfg.src_rect.h; + dst_w = psde->pipe_cfg.dst_rect.w; + dst_h = psde->pipe_cfg.dst_rect.h; + + memset(scale_cfg, 0, sizeof(*scale_cfg)); + memset(&pstate->pixel_ext, 0, sizeof(struct sde_hw_pixel_ext)); + + /* + * For inline rotation cases, scaler config is post-rotation, + * so swap the dimensions here. However, pixel extension will + * need pre-rotation settings, this will be corrected below + * when calculating pixel extension settings. + */ + if (pstate->rotation & DRM_MODE_ROTATE_90) + swap(src_w, src_h); + + decimated = DECIMATED_DIMENSION(src_w, + psde->pipe_cfg.horz_decimation); + scale_cfg->phase_step_x[SDE_SSPP_COMP_0] = + mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_w); + decimated = DECIMATED_DIMENSION(src_h, + psde->pipe_cfg.vert_decimation); + scale_cfg->phase_step_y[SDE_SSPP_COMP_0] = + mult_frac((1 << PHASE_STEP_SHIFT), decimated, dst_h); + + + scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2] = + scale_cfg->phase_step_y[SDE_SSPP_COMP_0] / chroma_subsmpl_v; + scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2] = + scale_cfg->phase_step_x[SDE_SSPP_COMP_0] / chroma_subsmpl_h; + + scale_cfg->phase_step_x[SDE_SSPP_COMP_2] = + scale_cfg->phase_step_x[SDE_SSPP_COMP_1_2]; + scale_cfg->phase_step_y[SDE_SSPP_COMP_2] = + scale_cfg->phase_step_y[SDE_SSPP_COMP_1_2]; + + scale_cfg->phase_step_x[SDE_SSPP_COMP_3] = + scale_cfg->phase_step_x[SDE_SSPP_COMP_0]; + scale_cfg->phase_step_y[SDE_SSPP_COMP_3] = + scale_cfg->phase_step_y[SDE_SSPP_COMP_0]; + + for (i = 0; i < SDE_MAX_PLANES; i++) { + scale_cfg->src_width[i] = DECIMATED_DIMENSION(src_w, + psde->pipe_cfg.horz_decimation); + scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h, + psde->pipe_cfg.vert_decimation); + if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) { + scale_cfg->src_width[i] /= chroma_subsmpl_h; + scale_cfg->src_height[i] /= chroma_subsmpl_v; + } + scale_cfg->preload_x[i] = psde->pipe_sblk->scaler_blk.h_preload; + scale_cfg->preload_y[i] = psde->pipe_sblk->scaler_blk.v_preload; + + /* For pixel extension we need the pre-rotated orientation */ + if (pstate->rotation & DRM_MODE_ROTATE_90) { + pstate->pixel_ext.num_ext_pxls_top[i] = + scale_cfg->src_width[i]; + pstate->pixel_ext.num_ext_pxls_left[i] = + scale_cfg->src_height[i]; + } else { + pstate->pixel_ext.num_ext_pxls_top[i] = + scale_cfg->src_height[i]; + pstate->pixel_ext.num_ext_pxls_left[i] = + scale_cfg->src_width[i]; + } + } + + if ((!(SDE_FORMAT_IS_YUV(fmt)) && (src_h == dst_h) + && (src_w == dst_w)) || pstate->multirect_mode) + return; + + SDE_DEBUG_PLANE(psde, + "setting bilinear: src:%dx%d dst:%dx%d chroma:%dx%d fmt:%x\n", + src_w, src_h, dst_w, dst_h, + chroma_subsmpl_v, chroma_subsmpl_h, + fmt->base.pixel_format); + + scale_cfg->dst_width = dst_w; + scale_cfg->dst_height = dst_h; + scale_cfg->y_rgb_filter_cfg = SDE_SCALE_BIL; + scale_cfg->uv_filter_cfg = SDE_SCALE_BIL; + scale_cfg->alpha_filter_cfg = SDE_SCALE_ALPHA_BIL; + scale_cfg->lut_flag = 0; + scale_cfg->blend_cfg = 1; + scale_cfg->enable = 1; + scale_cfg->dyn_exp_disabled = SDE_QSEED_DEFAULT_DYN_EXP; +} + +/** + * _sde_plane_setup_scaler2 - determine default scaler phase steps/filter type + * @psde: Pointer to SDE plane object + * @src: Source size + * @dst: Destination size + * @phase_steps: Pointer to output array for phase steps + * @filter: Pointer to output array for filter type + * @fmt: Pointer to format definition + * @chroma_subsampling: Subsampling amount for chroma channel + * + * Returns: 0 on success + */ +static int _sde_plane_setup_scaler2(struct sde_plane *psde, + uint32_t src, uint32_t dst, uint32_t *phase_steps, + enum sde_hw_filter *filter, const struct sde_format *fmt, + uint32_t chroma_subsampling) +{ + if (!psde || !phase_steps || !filter || !fmt) { + SDE_ERROR( + "invalid arg(s), plane %d phase %d filter %d fmt %d\n", + !psde, !phase_steps, !filter, !fmt); + return -EINVAL; + } + + /* calculate phase steps, leave init phase as zero */ + phase_steps[SDE_SSPP_COMP_0] = + mult_frac(1 << PHASE_STEP_SHIFT, src, dst); + phase_steps[SDE_SSPP_COMP_1_2] = + phase_steps[SDE_SSPP_COMP_0] / chroma_subsampling; + phase_steps[SDE_SSPP_COMP_2] = phase_steps[SDE_SSPP_COMP_1_2]; + phase_steps[SDE_SSPP_COMP_3] = phase_steps[SDE_SSPP_COMP_0]; + + /* calculate scaler config, if necessary */ + if (SDE_FORMAT_IS_YUV(fmt) || src != dst) { + filter[SDE_SSPP_COMP_3] = + (src <= dst) ? SDE_SCALE_FILTER_BIL : + SDE_SCALE_FILTER_PCMN; + + if (SDE_FORMAT_IS_YUV(fmt)) { + filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_CA; + filter[SDE_SSPP_COMP_1_2] = filter[SDE_SSPP_COMP_3]; + } else { + filter[SDE_SSPP_COMP_0] = filter[SDE_SSPP_COMP_3]; + filter[SDE_SSPP_COMP_1_2] = + SDE_SCALE_FILTER_NEAREST; + } + } else { + /* disable scaler */ + filter[SDE_SSPP_COMP_0] = SDE_SCALE_FILTER_MAX; + filter[SDE_SSPP_COMP_1_2] = SDE_SCALE_FILTER_MAX; + filter[SDE_SSPP_COMP_3] = SDE_SCALE_FILTER_MAX; + } + return 0; +} + +/** + * _sde_plane_setup_pixel_ext - determine default pixel extension values + * @psde: Pointer to SDE plane object + * @src: Source size + * @dst: Destination size + * @decimated_src: Source size after decimation, if any + * @phase_steps: Pointer to output array for phase steps + * @out_src: Output array for pixel extension values + * @out_edge1: Output array for pixel extension first edge + * @out_edge2: Output array for pixel extension second edge + * @filter: Pointer to array for filter type + * @fmt: Pointer to format definition + * @chroma_subsampling: Subsampling amount for chroma channel + * @post_compare: Whether to chroma subsampled source size for comparisions + */ +static void _sde_plane_setup_pixel_ext(struct sde_plane *psde, + uint32_t src, uint32_t dst, uint32_t decimated_src, + uint32_t *phase_steps, uint32_t *out_src, int *out_edge1, + int *out_edge2, enum sde_hw_filter *filter, + const struct sde_format *fmt, uint32_t chroma_subsampling, + bool post_compare) +{ + int64_t edge1, edge2, caf; + uint32_t src_work; + int i, tmp; + + if (psde && phase_steps && out_src && out_edge1 && + out_edge2 && filter && fmt) { + /* handle CAF for YUV formats */ + if (SDE_FORMAT_IS_YUV(fmt) && *filter == SDE_SCALE_FILTER_CA) + caf = PHASE_STEP_UNIT_SCALE; + else + caf = 0; + + for (i = 0; i < SDE_MAX_PLANES; i++) { + src_work = decimated_src; + if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) + src_work /= chroma_subsampling; + if (post_compare) + src = src_work; + if (!SDE_FORMAT_IS_YUV(fmt) && (src == dst)) { + /* unity */ + edge1 = 0; + edge2 = 0; + } else if (dst >= src) { + /* upscale */ + edge1 = (1 << PHASE_RESIDUAL); + edge1 -= caf; + edge2 = (1 << PHASE_RESIDUAL); + edge2 += (dst - 1) * *(phase_steps + i); + edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE; + edge2 += caf; + edge2 = -(edge2); + } else { + /* downscale */ + edge1 = 0; + edge2 = (dst - 1) * *(phase_steps + i); + edge2 -= (src_work - 1) * PHASE_STEP_UNIT_SCALE; + edge2 += *(phase_steps + i); + edge2 = -(edge2); + } + + /* only enable CAF for luma plane */ + caf = 0; + + /* populate output arrays */ + *(out_src + i) = src_work; + + /* edge updates taken from __pxl_extn_helper */ + if (edge1 >= 0) { + tmp = (uint32_t)edge1; + tmp >>= PHASE_STEP_SHIFT; + *(out_edge1 + i) = -tmp; + } else { + tmp = (uint32_t)(-edge1); + *(out_edge1 + i) = + (tmp + PHASE_STEP_UNIT_SCALE - 1) >> + PHASE_STEP_SHIFT; + } + if (edge2 >= 0) { + tmp = (uint32_t)edge2; + tmp >>= PHASE_STEP_SHIFT; + *(out_edge2 + i) = -tmp; + } else { + tmp = (uint32_t)(-edge2); + *(out_edge2 + i) = + (tmp + PHASE_STEP_UNIT_SCALE - 1) >> + PHASE_STEP_SHIFT; + } + } + } +} + +static inline void _sde_plane_setup_csc(struct sde_plane *psde) +{ + static const struct sde_csc_cfg sde_csc_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xfff0, 0xff80, 0xff80,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, + { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, + }; + static const struct sde_csc_cfg sde_csc10_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xffc0, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, + { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, + }; + + if (!psde) { + SDE_ERROR("invalid plane\n"); + return; + } + + /* revert to kernel default if override not available */ + if (psde->csc_usr_ptr) + psde->csc_ptr = psde->csc_usr_ptr; + else if (BIT(SDE_SSPP_CSC_10BIT) & psde->features) + psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc10_YUV2RGB_601L; + else + psde->csc_ptr = (struct sde_csc_cfg *)&sde_csc_YUV2RGB_601L; + + SDE_DEBUG_PLANE(psde, "using 0x%X 0x%X 0x%X...\n", + psde->csc_ptr->csc_mv[0], + psde->csc_ptr->csc_mv[1], + psde->csc_ptr->csc_mv[2]); +} + +static void sde_color_process_plane_setup(struct drm_plane *plane) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + uint32_t hue, saturation, value, contrast; + struct drm_msm_memcol *memcol = NULL; + struct drm_msm_3d_gamut *vig_gamut = NULL; + struct drm_msm_igc_lut *igc = NULL; + struct drm_msm_pgc_lut *gc = NULL; + size_t memcol_sz = 0, size = 0; + struct sde_hw_cp_cfg hw_cfg = {}; + struct sde_hw_ctl *ctl = _sde_plane_get_hw_ctl(plane); + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(plane->state); + + hue = (uint32_t) sde_plane_get_property(pstate, PLANE_PROP_HUE_ADJUST); + if (psde->pipe_hw->ops.setup_pa_hue) + psde->pipe_hw->ops.setup_pa_hue(psde->pipe_hw, &hue); + saturation = (uint32_t) sde_plane_get_property(pstate, + PLANE_PROP_SATURATION_ADJUST); + if (psde->pipe_hw->ops.setup_pa_sat) + psde->pipe_hw->ops.setup_pa_sat(psde->pipe_hw, &saturation); + value = (uint32_t) sde_plane_get_property(pstate, + PLANE_PROP_VALUE_ADJUST); + if (psde->pipe_hw->ops.setup_pa_val) + psde->pipe_hw->ops.setup_pa_val(psde->pipe_hw, &value); + contrast = (uint32_t) sde_plane_get_property(pstate, + PLANE_PROP_CONTRAST_ADJUST); + if (psde->pipe_hw->ops.setup_pa_cont) + psde->pipe_hw->ops.setup_pa_cont(psde->pipe_hw, &contrast); + + if (psde->pipe_hw->ops.setup_pa_memcolor) { + /* Skin memory color setup */ + memcol = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &memcol_sz, + PLANE_PROP_SKIN_COLOR); + psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw, + MEMCOLOR_SKIN, memcol); + + /* Sky memory color setup */ + memcol = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &memcol_sz, + PLANE_PROP_SKY_COLOR); + psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw, + MEMCOLOR_SKY, memcol); + + /* Foliage memory color setup */ + memcol = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &memcol_sz, + PLANE_PROP_FOLIAGE_COLOR); + psde->pipe_hw->ops.setup_pa_memcolor(psde->pipe_hw, + MEMCOLOR_FOLIAGE, memcol); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_VIG_GAMUT && + psde->pipe_hw->ops.setup_vig_gamut) { + vig_gamut = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_VIG_GAMUT); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(struct drm_msm_3d_gamut); + hw_cfg.payload = vig_gamut; + psde->pipe_hw->ops.setup_vig_gamut(psde->pipe_hw, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_VIG_IGC && + psde->pipe_hw->ops.setup_vig_igc) { + igc = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_VIG_IGC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(struct drm_msm_igc_lut); + hw_cfg.payload = igc; + psde->pipe_hw->ops.setup_vig_igc(psde->pipe_hw, &hw_cfg); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_DMA_IGC && + psde->pipe_hw->ops.setup_dma_igc) { + igc = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_DMA_IGC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(struct drm_msm_igc_lut); + hw_cfg.payload = igc; + psde->pipe_hw->ops.setup_dma_igc(psde->pipe_hw, &hw_cfg, + pstate->multirect_index); + } + + if (pstate->dirty & SDE_PLANE_DIRTY_DMA_GC && + psde->pipe_hw->ops.setup_dma_gc) { + gc = msm_property_get_blob(&psde->property_info, + &pstate->property_state, + &size, + PLANE_PROP_DMA_GC); + hw_cfg.last_feature = 0; + hw_cfg.ctl = ctl; + hw_cfg.len = sizeof(struct drm_msm_pgc_lut); + hw_cfg.payload = gc; + psde->pipe_hw->ops.setup_dma_gc(psde->pipe_hw, &hw_cfg, + pstate->multirect_index); + } +} + +static void _sde_plane_setup_scaler(struct sde_plane *psde, + struct sde_plane_state *pstate, + const struct sde_format *fmt, bool color_fill) +{ + struct sde_hw_pixel_ext *pe; + uint32_t chroma_subsmpl_h, chroma_subsmpl_v; + + if (!psde || !fmt || !pstate) { + SDE_ERROR("invalid arg(s), plane %d fmt %d state %d\n", + !psde, !fmt, !pstate); + return; + } + + pe = &pstate->pixel_ext; + + psde->pipe_cfg.horz_decimation = + sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE); + psde->pipe_cfg.vert_decimation = + sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE); + + /* don't chroma subsample if decimating */ + chroma_subsmpl_h = psde->pipe_cfg.horz_decimation ? 1 : + drm_format_horz_chroma_subsampling(fmt->base.pixel_format); + chroma_subsmpl_v = psde->pipe_cfg.vert_decimation ? 1 : + drm_format_vert_chroma_subsampling(fmt->base.pixel_format); + + /* update scaler */ + if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3) || + (psde->features & BIT(SDE_SSPP_SCALER_QSEED3LITE))) { + int rc = -EINVAL; + + if (!color_fill && !psde->debugfs_default_scale) + rc = is_qseed3_rev_qseed3lite(psde->pipe_hw->catalog) ? + _sde_plane_setup_scaler3lite_lut(psde, pstate) : + _sde_plane_setup_scaler3_lut(psde, pstate); + if (rc || pstate->scaler_check_state != + SDE_PLANE_SCLCHECK_SCALER_V2) { + SDE_EVT32_VERBOSE(DRMID(&psde->base), color_fill, + pstate->scaler_check_state, + psde->debugfs_default_scale, rc, + psde->pipe_cfg.src_rect.w, + psde->pipe_cfg.src_rect.h, + psde->pipe_cfg.dst_rect.w, + psde->pipe_cfg.dst_rect.h, + pstate->multirect_mode); + + /* calculate default config for QSEED3 */ + _sde_plane_setup_scaler3(psde, pstate, fmt, + chroma_subsmpl_h, chroma_subsmpl_v); + } + } else if (pstate->scaler_check_state != SDE_PLANE_SCLCHECK_SCALER_V1 || + color_fill || psde->debugfs_default_scale) { + uint32_t deci_dim, i; + + /* calculate default configuration for QSEED2 */ + memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); + + SDE_DEBUG_PLANE(psde, "default config\n"); + deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.w, + psde->pipe_cfg.horz_decimation); + _sde_plane_setup_scaler2(psde, + deci_dim, + psde->pipe_cfg.dst_rect.w, + pe->phase_step_x, + pe->horz_filter, fmt, chroma_subsmpl_h); + + if (SDE_FORMAT_IS_YUV(fmt)) + deci_dim &= ~0x1; + _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.w, + psde->pipe_cfg.dst_rect.w, deci_dim, + pe->phase_step_x, + pe->roi_w, + pe->num_ext_pxls_left, + pe->num_ext_pxls_right, pe->horz_filter, fmt, + chroma_subsmpl_h, 0); + + deci_dim = DECIMATED_DIMENSION(psde->pipe_cfg.src_rect.h, + psde->pipe_cfg.vert_decimation); + _sde_plane_setup_scaler2(psde, + deci_dim, + psde->pipe_cfg.dst_rect.h, + pe->phase_step_y, + pe->vert_filter, fmt, chroma_subsmpl_v); + _sde_plane_setup_pixel_ext(psde, psde->pipe_cfg.src_rect.h, + psde->pipe_cfg.dst_rect.h, deci_dim, + pe->phase_step_y, + pe->roi_h, + pe->num_ext_pxls_top, + pe->num_ext_pxls_btm, pe->vert_filter, fmt, + chroma_subsmpl_v, 1); + + for (i = 0; i < SDE_MAX_PLANES; i++) { + if (pe->num_ext_pxls_left[i] >= 0) + pe->left_rpt[i] = pe->num_ext_pxls_left[i]; + else + pe->left_ftch[i] = pe->num_ext_pxls_left[i]; + + if (pe->num_ext_pxls_right[i] >= 0) + pe->right_rpt[i] = pe->num_ext_pxls_right[i]; + else + pe->right_ftch[i] = pe->num_ext_pxls_right[i]; + + if (pe->num_ext_pxls_top[i] >= 0) + pe->top_rpt[i] = pe->num_ext_pxls_top[i]; + else + pe->top_ftch[i] = pe->num_ext_pxls_top[i]; + + if (pe->num_ext_pxls_btm[i] >= 0) + pe->btm_rpt[i] = pe->num_ext_pxls_btm[i]; + else + pe->btm_ftch[i] = pe->num_ext_pxls_btm[i]; + } + } + if (psde->pipe_hw->ops.setup_pre_downscale) + psde->pipe_hw->ops.setup_pre_downscale(psde->pipe_hw, + &pstate->pre_down); +} + +/** + * _sde_plane_color_fill - enables color fill on plane + * @psde: Pointer to SDE plane object + * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red + * @alpha: 8-bit fill alpha value, 255 selects 100% alpha + * Returns: 0 on success + */ +static int _sde_plane_color_fill(struct sde_plane *psde, + uint32_t color, uint32_t alpha) +{ + const struct sde_format *fmt; + const struct drm_plane *plane; + struct sde_plane_state *pstate; + bool blend_enable = true; + + if (!psde || !psde->base.state) { + SDE_ERROR("invalid plane\n"); + return -EINVAL; + } + + if (!psde->pipe_hw) { + SDE_ERROR_PLANE(psde, "invalid plane h/w pointer\n"); + return -EINVAL; + } + + plane = &psde->base; + pstate = to_sde_plane_state(plane->state); + + SDE_DEBUG_PLANE(psde, "\n"); + + /* + * select fill format to match user property expectation, + * h/w only supports RGB variants + */ + fmt = sde_get_sde_format(DRM_FORMAT_ABGR8888); + + blend_enable = (SDE_DRM_BLEND_OP_OPAQUE != + sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP)); + + /* update sspp */ + if (fmt && psde->pipe_hw->ops.setup_solidfill) { + psde->pipe_hw->ops.setup_solidfill(psde->pipe_hw, + (color & 0xFFFFFF) | ((alpha & 0xFF) << 24), + pstate->multirect_index); + + /* override scaler/decimation if solid fill */ + psde->pipe_cfg.src_rect.x = 0; + psde->pipe_cfg.src_rect.y = 0; + psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w; + psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h; + _sde_plane_setup_scaler(psde, pstate, fmt, true); + + if (psde->pipe_hw->ops.setup_format) + psde->pipe_hw->ops.setup_format(psde->pipe_hw, + fmt, blend_enable, + SDE_SSPP_SOLID_FILL, + pstate->multirect_index); + + if (psde->pipe_hw->ops.setup_rects) + psde->pipe_hw->ops.setup_rects(psde->pipe_hw, + &psde->pipe_cfg, + pstate->multirect_index); + + if (psde->pipe_hw->ops.setup_pe) + psde->pipe_hw->ops.setup_pe(psde->pipe_hw, + &pstate->pixel_ext); + if (psde->pipe_hw->ops.setup_scaler && + pstate->multirect_index != SDE_SSPP_RECT_1) { + psde->pipe_hw->ctl = _sde_plane_get_hw_ctl(plane); + psde->pipe_hw->ops.setup_scaler(psde->pipe_hw, + &psde->pipe_cfg, &pstate->pixel_ext, + &pstate->scaler3_cfg); + } + } + + return 0; +} + +/** +* sde_plane_rot_atomic_check - verify rotator update of the given state +* @plane: Pointer to drm plane +* @state: Pointer to drm plane state to be validated +* return: 0 if success; error code otherwise +*/ +static int sde_plane_rot_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate, *old_pstate; + int ret = 0; + u32 rotation; + + if (!plane || !state) { + SDE_ERROR("invalid plane/state\n"); + return -EINVAL; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(state); + old_pstate = to_sde_plane_state(plane->state); + + /* check inline rotation and simplify the transform */ + rotation = drm_rotation_simplify( + state->rotation, + DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); + + if ((rotation & DRM_MODE_ROTATE_180) || + (rotation & DRM_MODE_ROTATE_270)) { + SDE_ERROR_PLANE(psde, + "invalid rotation transform must be simplified 0x%x\n", + rotation); + ret = -EINVAL; + goto exit; + } + + if (rotation & DRM_MODE_ROTATE_90) { + struct msm_drm_private *priv = plane->dev->dev_private; + struct sde_kms *sde_kms; + const struct msm_format *msm_fmt; + const struct sde_format *fmt; + struct sde_rect src; + bool q16_data = true; + + POPULATE_RECT(&src, state->src_x, state->src_y, + state->src_w, state->src_h, q16_data); + /* + * DRM framework expects rotation flag in counter-clockwise + * direction and the HW expects in clockwise direction. + * Flip the flags to match with HW. + */ + rotation ^= (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y); + + if (!psde->pipe_sblk->in_rot_maxdwnscale_rt_num || + !psde->pipe_sblk->in_rot_maxdwnscale_rt_denom || + !psde->pipe_sblk->in_rot_maxdwnscale_nrt || + !psde->pipe_sblk->in_rot_maxheight || + !psde->pipe_sblk->in_rot_format_list || + !(psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT))) { + SDE_ERROR_PLANE(psde, + "wrong config rt:%d/%d nrt:%d fmt:%d h:%d 0x%x\n", + !psde->pipe_sblk->in_rot_maxdwnscale_rt_num, + !psde->pipe_sblk->in_rot_maxdwnscale_rt_denom, + !psde->pipe_sblk->in_rot_maxdwnscale_nrt, + !psde->pipe_sblk->in_rot_format_list, + !psde->pipe_sblk->in_rot_maxheight, + psde->features); + ret = -EINVAL; + goto exit; + } + + /* check for valid height */ + if (src.h > psde->pipe_sblk->in_rot_maxheight) { + SDE_ERROR_PLANE(psde, + "invalid height for inline rot:%d max:%d\n", + src.h, psde->pipe_sblk->in_rot_maxheight); + ret = -EINVAL; + goto exit; + } + + if (!sde_plane_enabled(state)) + goto exit; + + /* check for valid formats supported by inline rot */ + sde_kms = to_sde_kms(priv->kms); + msm_fmt = msm_framebuffer_format(state->fb); + fmt = to_sde_format(msm_fmt); + ret = sde_format_validate_fmt(&sde_kms->base, fmt, + psde->pipe_sblk->in_rot_format_list); + } + +exit: + pstate->rotation = rotation; + return ret; +} + +static bool _sde_plane_halt_requests(struct drm_plane *plane, + uint32_t xin_id, bool halt_forced_clk, bool enable) +{ + struct sde_plane *psde; + struct msm_drm_private *priv; + struct sde_vbif_set_xin_halt_params halt_params; + + if (!plane || !plane->dev) { + SDE_ERROR("invalid arguments\n"); + return false; + } + + psde = to_sde_plane(plane); + if (!psde->pipe_hw || !psde->pipe_hw->cap) { + SDE_ERROR("invalid pipe reference\n"); + return false; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return false; + } + + memset(&halt_params, 0, sizeof(halt_params)); + halt_params.vbif_idx = VBIF_RT; + halt_params.xin_id = xin_id; + halt_params.clk_ctrl = psde->pipe_hw->cap->clk_ctrl; + halt_params.forced_on = halt_forced_clk; + halt_params.enable = enable; + + return sde_vbif_set_xin_halt(to_sde_kms(priv->kms), &halt_params); +} + +void sde_plane_halt_requests(struct drm_plane *plane, bool enable) +{ + struct sde_plane *psde; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return; + } + + psde = to_sde_plane(plane); + if (!psde->pipe_hw || !psde->pipe_hw->cap) { + SDE_ERROR("invalid pipe reference\n"); + return; + } + + SDE_EVT32(DRMID(plane), psde->xin_halt_forced_clk, enable); + + psde->xin_halt_forced_clk = + _sde_plane_halt_requests(plane, psde->pipe_hw->cap->xin_id, + psde->xin_halt_forced_clk, enable); +} + +void sde_plane_secure_ctrl_xin_client(struct drm_plane *plane, + struct drm_crtc *crtc) +{ + struct sde_plane *psde; + + if (!plane || !crtc) { + SDE_ERROR("invalid plane/crtc\n"); + return; + } + psde = to_sde_plane(plane); + + if (psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI)) + return; + + /* do all VBIF programming for the sec-ui allowed SSPP */ + _sde_plane_set_qos_remap(plane, true); + _sde_plane_set_ot_limit(plane, crtc); +} + +/** + * sde_plane_rot_install_properties - install plane rotator properties + * @plane: Pointer to drm plane + * @catalog: Pointer to mdss configuration + * return: none + */ +static void sde_plane_rot_install_properties(struct drm_plane *plane, + struct sde_mdss_cfg *catalog) +{ + struct sde_plane *psde = to_sde_plane(plane); + unsigned long supported_rotations = DRM_MODE_ROTATE_0 | + DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y; + int ret = 0; + + if (!plane || !psde) { + SDE_ERROR("invalid plane\n"); + return; + } else if (!catalog) { + SDE_ERROR("invalid catalog\n"); + return; + } + + if (psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT)) + supported_rotations |= DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 | + DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270; + + ret = drm_plane_create_rotation_property(plane, + DRM_MODE_ROTATE_0, supported_rotations); + if (ret) { + DRM_ERROR("create rotation property failed: %d\n", ret); + return; + } +} + +void sde_plane_clear_multirect(const struct drm_plane_state *drm_state) +{ + struct sde_plane_state *pstate; + + if (!drm_state) + return; + + pstate = to_sde_plane_state(drm_state); + + pstate->multirect_index = SDE_SSPP_RECT_SOLO; + pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE; +} + +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint +int sde_plane_check_fingerprint_layer(const struct drm_plane_state *drm_state) +{ + struct sde_plane_state *pstate; + + if (!drm_state) + return 0; + + pstate = to_sde_plane_state(drm_state); + + return sde_plane_get_property(pstate, PLANE_PROP_CUSTOM); +} +/** + * multi_rect validate API allows to validate only R0 and R1 RECT + * passing for each plane. Client of this API must not pass multiple + * plane which are not sharing same XIN client. Such calls will fail + * even though kernel client is passing valid multirect configuration. + */ +int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane) +{ + struct sde_plane_state *pstate[R_MAX]; + const struct drm_plane_state *drm_state[R_MAX]; + struct sde_rect src[R_MAX], dst[R_MAX]; + struct sde_plane *sde_plane[R_MAX]; + const struct sde_format *fmt[R_MAX]; + int xin_id[R_MAX]; + bool q16_data = true; + int i, j, buffer_lines, width_threshold[R_MAX]; + unsigned int max_tile_height = 1; + bool parallel_fetch_qualified = true; + enum sde_sspp_multirect_mode mode = SDE_SSPP_MULTIRECT_NONE; + const struct msm_format *msm_fmt; + bool const_alpha_enable = true; + + for (i = 0; i < R_MAX; i++) { + drm_state[i] = i ? plane->r1 : plane->r0; + if (!drm_state[i]) { + SDE_ERROR("drm plane state is NULL\n"); + return -EINVAL; + } + + pstate[i] = to_sde_plane_state(drm_state[i]); + sde_plane[i] = to_sde_plane(drm_state[i]->plane); + xin_id[i] = sde_plane[i]->pipe_hw->cap->xin_id; + + for (j = 0; j < i; j++) { + if (xin_id[i] != xin_id[j]) { + SDE_ERROR_PLANE(sde_plane[i], + "invalid multirect validate call base:%d xin_id:%d curr:%d xin:%d\n", + j, xin_id[j], i, xin_id[i]); + return -EINVAL; + } + } + + msm_fmt = msm_framebuffer_format(drm_state[i]->fb); + if (!msm_fmt) { + SDE_ERROR_PLANE(sde_plane[i], "null fb\n"); + return -EINVAL; + } + fmt[i] = to_sde_format(msm_fmt); + + if (SDE_FORMAT_IS_UBWC(fmt[i]) && + (fmt[i]->tile_height > max_tile_height)) + max_tile_height = fmt[i]->tile_height; + + POPULATE_RECT(&src[i], drm_state[i]->src_x, drm_state[i]->src_y, + drm_state[i]->src_w, drm_state[i]->src_h, q16_data); + POPULATE_RECT(&dst[i], drm_state[i]->crtc_x, + drm_state[i]->crtc_y, drm_state[i]->crtc_w, + drm_state[i]->crtc_h, !q16_data); + + if (src[i].w != dst[i].w || src[i].h != dst[i].h) { + SDE_ERROR_PLANE(sde_plane[i], + "scaling is not supported in multirect mode\n"); + return -EINVAL; + } + + if (SDE_FORMAT_IS_YUV(fmt[i])) { + SDE_ERROR_PLANE(sde_plane[i], + "Unsupported format for multirect mode\n"); + return -EINVAL; + } + + /** + * SSPP PD_MEM is split half - one for each RECT. + * Tiled formats need 5 lines of buffering while fetching + * whereas linear formats need only 2 lines. + * So we cannot support more than half of the supported SSPP + * width for tiled formats. + */ + width_threshold[i] = sde_plane[i]->pipe_sblk->maxlinewidth; + if (SDE_FORMAT_IS_UBWC(fmt[i])) + width_threshold[i] /= 2; + + if (parallel_fetch_qualified && src[i].w > width_threshold[i]) + parallel_fetch_qualified = false; + + if (sde_plane[i]->is_virtual) + mode = sde_plane_get_property(pstate[i], + PLANE_PROP_MULTIRECT_MODE); + + if (pstate[i]->const_alpha_en != const_alpha_enable) + const_alpha_enable = false; + + } + + buffer_lines = 2 * max_tile_height; + + /** + * fallback to driver mode selection logic if client is using + * multirect plane without setting property. + * + * validate multirect mode configuration based on rectangle + */ + switch (mode) { + case SDE_SSPP_MULTIRECT_NONE: + if (parallel_fetch_qualified) + mode = SDE_SSPP_MULTIRECT_PARALLEL; + else if (TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) || + TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) + mode = SDE_SSPP_MULTIRECT_TIME_MX; + else + SDE_ERROR( + "planes(%d - %d) multirect mode selection fail\n", + drm_state[R0]->plane->base.id, + drm_state[R1]->plane->base.id); + break; + + case SDE_SSPP_MULTIRECT_PARALLEL: + if (!parallel_fetch_qualified) { + SDE_ERROR("R0 plane:%d width_threshold:%d src_w:%d\n", + drm_state[R0]->plane->base.id, + width_threshold[R0], src[R0].w); + SDE_ERROR("R1 plane:%d width_threshold:%d src_w:%d\n", + drm_state[R1]->plane->base.id, + width_threshold[R1], src[R1].w); + SDE_ERROR("parallel fetch not qualified\n"); + mode = SDE_SSPP_MULTIRECT_NONE; + } + break; + + case SDE_SSPP_MULTIRECT_TIME_MX: + if (!TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) && + !TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) { + SDE_ERROR( + "buffer_lines:%d R0 plane:%d dst_y:%d dst_h:%d\n", + buffer_lines, drm_state[R0]->plane->base.id, + dst[R0].y, dst[R0].h); + SDE_ERROR( + "buffer_lines:%d R1 plane:%d dst_y:%d dst_h:%d\n", + buffer_lines, drm_state[R1]->plane->base.id, + dst[R1].y, dst[R1].h); + SDE_ERROR("time multiplexed fetch not qualified\n"); + mode = SDE_SSPP_MULTIRECT_NONE; + } + break; + + default: + SDE_ERROR("bad mode:%d selection\n", mode); + mode = SDE_SSPP_MULTIRECT_NONE; + break; + } + + for (i = 0; i < R_MAX; i++) { + pstate[i]->multirect_mode = mode; + pstate[i]->const_alpha_en = const_alpha_enable; + } + + if (mode == SDE_SSPP_MULTIRECT_NONE) + return -EINVAL; + + if (sde_plane[R0]->is_virtual) { + pstate[R0]->multirect_index = SDE_SSPP_RECT_1; + pstate[R1]->multirect_index = SDE_SSPP_RECT_0; + } else { + pstate[R0]->multirect_index = SDE_SSPP_RECT_0; + pstate[R1]->multirect_index = SDE_SSPP_RECT_1; + } + + SDE_DEBUG_PLANE(sde_plane[R0], "R0: %d - %d\n", + pstate[R0]->multirect_mode, pstate[R0]->multirect_index); + SDE_DEBUG_PLANE(sde_plane[R1], "R1: %d - %d\n", + pstate[R1]->multirect_mode, pstate[R1]->multirect_index); + + return 0; +} + +/** + * sde_plane_ctl_flush - set/clear control flush bitmask for the given plane + * @plane: Pointer to drm plane structure + * @ctl: Pointer to hardware control driver + * @set: set if true else clear + */ +void sde_plane_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl, + bool set) +{ + if (!plane || !ctl) { + SDE_ERROR("invalid parameters\n"); + return; + } + + if (!ctl->ops.update_bitmask_sspp) { + SDE_ERROR("invalid ops\n"); + return; + } + + ctl->ops.update_bitmask_sspp(ctl, sde_plane_pipe(plane), set); +} + +static int sde_plane_prepare_fb(struct drm_plane *plane, + struct drm_plane_state *new_state) +{ + struct drm_framebuffer *fb = new_state->fb; + struct sde_plane *psde = to_sde_plane(plane); + struct sde_plane_state *pstate = to_sde_plane_state(new_state); + struct sde_hw_fmt_layout layout; + struct msm_gem_address_space *aspace; + int ret; + + if (!fb) + return 0; + + SDE_DEBUG_PLANE(psde, "FB[%u]\n", fb->base.id); + + ret = _sde_plane_get_aspace(psde, pstate, &aspace); + if (ret) { + SDE_ERROR_PLANE(psde, "Failed to get aspace\n"); + return ret; + } + + /* cache aspace */ + pstate->aspace = aspace; + + /* + * when transitioning from secure to non-secure, + * plane->prepare_fb happens before the commit. In such case, + * defer the prepare_fb and handled it late, during the commit + * after attaching the domains as part of the transition + */ + pstate->defer_prepare_fb = (aspace && !aspace->domain_attached) ? + true : false; + + if (pstate->defer_prepare_fb) { + SDE_EVT32(DRMID(plane), psde->pipe); + SDE_DEBUG_PLANE(psde, + "domain not attached, prepare_fb handled later\n"); + return 0; + } + + if (pstate->aspace && fb) { + ret = msm_framebuffer_prepare(fb, + pstate->aspace); + if (ret) { + SDE_ERROR("failed to prepare framebuffer\n"); + return ret; + } + } + + /* validate framebuffer layout before commit */ + ret = sde_format_populate_layout(pstate->aspace, + fb, &layout); + if (ret) { + SDE_ERROR_PLANE(psde, "failed to get format layout, %d\n", ret); + return ret; + } + + return 0; +} + +/** + * _sde_plane_fetch_halt - halts vbif transactions for a plane + * @plane: Pointer to plane + * Returns: 0 on success + */ +static int _sde_plane_fetch_halt(struct drm_plane *plane) +{ + struct sde_plane *psde; + int xin_id; + enum sde_clk_ctrl_type clk_ctrl; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + + psde = to_sde_plane(plane); + if (!plane || !plane->dev || !psde->pipe_hw) { + SDE_ERROR("invalid arguments\n"); + return -EINVAL; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return -EINVAL; + } + + sde_kms = to_sde_kms(priv->kms); + clk_ctrl = psde->pipe_hw->cap->clk_ctrl; + xin_id = psde->pipe_hw->cap->xin_id; + SDE_DEBUG_PLANE(psde, "pipe:%d xin_id:%d clk_ctrl:%d\n", + psde->pipe - SSPP_VIG0, xin_id, clk_ctrl); + SDE_EVT32_VERBOSE(psde, psde->pipe - SSPP_VIG0, xin_id, clk_ctrl); + + return sde_vbif_halt_plane_xin(sde_kms, xin_id, clk_ctrl); +} + + +static void sde_plane_cleanup_fb(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct sde_plane *psde = to_sde_plane(plane); + struct sde_plane_state *old_pstate; + int ret; + + if (!old_state || !old_state->fb || !plane || !plane->state) + return; + + old_pstate = to_sde_plane_state(old_state); + + SDE_DEBUG_PLANE(psde, "FB[%u]\n", old_state->fb->base.id); + + /* + * plane->state gets populated for next frame after swap_state. If + * plane->state->crtc pointer is not populated then it is not used in + * the next frame, hence making it an unused plane. + */ + if ((plane->state->crtc == NULL) && !psde->is_virtual) { + SDE_DEBUG_PLANE(psde, "unused pipe:%u\n", + psde->pipe - SSPP_VIG0); + + /* halt this plane now */ + ret = pm_runtime_get_sync(plane->dev->dev); + if (ret < 0) { + SDE_ERROR("power resource enable failed with %d", ret); + SDE_EVT32(ret, SDE_EVTLOG_ERROR); + return; + } + + ret = _sde_plane_fetch_halt(plane); + if (ret) { + SDE_ERROR_PLANE(psde, + "unused pipe %u halt failed\n", + psde->pipe - SSPP_VIG0); + SDE_EVT32(DRMID(plane), psde->pipe - SSPP_VIG0, + ret, SDE_EVTLOG_ERROR); + } + pm_runtime_put_sync(plane->dev->dev); + } + + msm_framebuffer_cleanup(old_state->fb, old_pstate->aspace); + +} + +static void _sde_plane_sspp_atomic_check_mode_changed(struct sde_plane *psde, + struct drm_plane_state *state, + struct drm_plane_state *old_state) +{ + struct sde_plane_state *pstate = to_sde_plane_state(state); + struct sde_plane_state *old_pstate = to_sde_plane_state(old_state); + struct drm_framebuffer *fb, *old_fb; + + /* no need to check it again */ + if (pstate->dirty == SDE_PLANE_DIRTY_ALL) + return; + + if (!sde_plane_enabled(state) || !sde_plane_enabled(old_state) + || psde->is_error) { + SDE_DEBUG_PLANE(psde, + "enabling/disabling full modeset required\n"); + pstate->dirty |= SDE_PLANE_DIRTY_ALL; + } else if (to_sde_plane_state(old_state)->pending) { + SDE_DEBUG_PLANE(psde, "still pending\n"); + pstate->dirty |= SDE_PLANE_DIRTY_ALL; + } else if (pstate->multirect_index != old_pstate->multirect_index || + pstate->multirect_mode != old_pstate->multirect_mode) { + SDE_DEBUG_PLANE(psde, "multirect config updated\n"); + pstate->dirty |= SDE_PLANE_DIRTY_ALL; + } else if (state->src_w != old_state->src_w || + state->src_h != old_state->src_h || + state->src_x != old_state->src_x || + state->src_y != old_state->src_y) { + SDE_DEBUG_PLANE(psde, "src rect updated\n"); + pstate->dirty |= SDE_PLANE_DIRTY_RECTS; + } else if (state->crtc_w != old_state->crtc_w || + state->crtc_h != old_state->crtc_h || + state->crtc_x != old_state->crtc_x || + state->crtc_y != old_state->crtc_y) { + SDE_DEBUG_PLANE(psde, "crtc rect updated\n"); + pstate->dirty |= SDE_PLANE_DIRTY_RECTS; + } else if (pstate->excl_rect.w != old_pstate->excl_rect.w || + pstate->excl_rect.h != old_pstate->excl_rect.h || + pstate->excl_rect.x != old_pstate->excl_rect.x || + pstate->excl_rect.y != old_pstate->excl_rect.y) { + SDE_DEBUG_PLANE(psde, "excl_rect updated\n"); + pstate->dirty |= SDE_PLANE_DIRTY_RECTS; + } else if (pstate->rotation != old_pstate->rotation) { + SDE_DEBUG_PLANE(psde, "rotation updated 0x%x->0x%x\n", + pstate->rotation, old_pstate->rotation); + pstate->dirty |= SDE_PLANE_DIRTY_FORMAT; + } + + fb = state->fb; + old_fb = old_state->fb; + + if (!fb || !old_fb) { + SDE_DEBUG_PLANE(psde, "can't compare fb handles\n"); + } else if ((fb->format->format != old_fb->format->format) || + pstate->const_alpha_en != old_pstate->const_alpha_en) { + SDE_DEBUG_PLANE(psde, "format change\n"); + pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | SDE_PLANE_DIRTY_RECTS; + } else { + uint64_t new_mod = fb->modifier; + uint64_t old_mod = old_fb->modifier; + uint32_t *new_pitches = fb->pitches; + uint32_t *old_pitches = old_fb->pitches; + uint32_t *new_offset = fb->offsets; + uint32_t *old_offset = old_fb->offsets; + int i; + + if (new_mod != old_mod) { + SDE_DEBUG_PLANE(psde, + "format modifiers change new_mode:%llu old_mode:%llu\n", + new_mod, old_mod); + pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | + SDE_PLANE_DIRTY_RECTS; + } + + for (i = 0; i < ARRAY_SIZE(fb->pitches); i++) { + if (new_pitches[i] != old_pitches[i]) { + SDE_DEBUG_PLANE(psde, + "pitches change plane:%d old_pitches:%u new_pitches:%u\n", + i, old_pitches[i], new_pitches[i]); + pstate->dirty |= SDE_PLANE_DIRTY_RECTS; + break; + } + } + for (i = 0; i < ARRAY_SIZE(fb->offsets); i++) { + if (new_offset[i] != old_offset[i]) { + SDE_DEBUG_PLANE(psde, + "offset change plane:%d old_offset:%u new_offset:%u\n", + i, old_offset[i], new_offset[i]); + pstate->dirty |= SDE_PLANE_DIRTY_FORMAT | + SDE_PLANE_DIRTY_RECTS; + break; + } + } + } +} + +int sde_plane_validate_src_addr(struct drm_plane *plane, + unsigned long base_addr, u32 size) +{ + int ret = -EINVAL; + u32 addr; + struct sde_plane *psde = to_sde_plane(plane); + + if (!psde || !base_addr || !size) { + SDE_ERROR_PLANE(psde, "invalid arguments\n"); + return ret; + } + + if (psde->pipe_hw && psde->pipe_hw->ops.get_sourceaddress) { + addr = psde->pipe_hw->ops.get_sourceaddress(psde->pipe_hw, + is_sde_plane_virtual(plane)); + if ((addr >= base_addr) && (addr < (base_addr + size))) + ret = 0; + } + + return ret; +} + +static inline bool _sde_plane_is_pre_downscale_enabled( + struct sde_hw_inline_pre_downscale_cfg *pre_down) +{ + return pre_down->pre_downscale_x_0 || pre_down->pre_downscale_y_0; +} + +static int _sde_plane_validate_scaler_v2(struct sde_plane *psde, + struct sde_plane_state *pstate, + const struct sde_format *fmt, + uint32_t img_w, uint32_t img_h, + uint32_t src_w, uint32_t src_h, + uint32_t deci_w, uint32_t deci_h) +{ + struct sde_hw_inline_pre_downscale_cfg *pd_cfg; + bool pre_down_en; + int i; + + if (!psde || !pstate || !fmt) { + SDE_ERROR_PLANE(psde, "invalid arguments\n"); + return -EINVAL; + } + + if (psde->debugfs_default_scale || + (pstate->scaler_check_state != SDE_PLANE_SCLCHECK_SCALER_V2 && + pstate->scaler_check_state != SDE_PLANE_SCLCHECK_SCALER_V2_CHECK)) + return 0; + + pd_cfg = &pstate->pre_down; + pre_down_en = _sde_plane_is_pre_downscale_enabled(pd_cfg); + + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_INVALID; + + for (i = 0; i < SDE_MAX_PLANES; i++) { + uint32_t hor_req_pixels, hor_fetch_pixels; + uint32_t vert_req_pixels, vert_fetch_pixels; + uint32_t src_w_tmp, src_h_tmp; + uint32_t scaler_w, scaler_h; + uint32_t pre_down_ratio_x = 1, pre_down_ratio_y = 1; + bool rot; + + /* re-use color plane 1's config for plane 2 */ + if (i == 2) + continue; + + if (pre_down_en) { + if (i == 0 && pd_cfg->pre_downscale_x_0) + pre_down_ratio_x = pd_cfg->pre_downscale_x_0; + if (i == 0 && pd_cfg->pre_downscale_y_0) + pre_down_ratio_y = pd_cfg->pre_downscale_y_0; + if ((i == 1 || i == 2) && pd_cfg->pre_downscale_x_1) + pre_down_ratio_x = pd_cfg->pre_downscale_x_1; + if ((i == 1 || i == 2) && pd_cfg->pre_downscale_y_1) + pre_down_ratio_y = pd_cfg->pre_downscale_y_1; + SDE_DEBUG_PLANE(psde, "pre_down[%d]: x:%d, y:%d\n", + i, pre_down_ratio_x, pre_down_ratio_y); + } + + src_w_tmp = src_w; + src_h_tmp = src_h; + + /* + * For chroma plane, width is half for the following sub sampled + * formats. Except in case of decimation, where hardware avoids + * 1 line of decimation instead of downsampling. + */ + if (i == 1) { + if (!deci_w && + (fmt->chroma_sample == SDE_CHROMA_420 || + fmt->chroma_sample == SDE_CHROMA_H2V1)) + src_w_tmp >>= 1; + if (!deci_h && + (fmt->chroma_sample == SDE_CHROMA_420 || + fmt->chroma_sample == SDE_CHROMA_H1V2)) + src_h_tmp >>= 1; + } + + hor_req_pixels = pstate->pixel_ext.roi_w[i]; + vert_req_pixels = pstate->pixel_ext.roi_h[i]; + + hor_fetch_pixels = DECIMATED_DIMENSION(src_w_tmp + + (int8_t)(pstate->pixel_ext.left_ftch[i] & 0xFF) + + (int8_t)(pstate->pixel_ext.right_ftch[i] & 0xFF), + deci_w); + vert_fetch_pixels = DECIMATED_DIMENSION(src_h_tmp + + (int8_t)(pstate->pixel_ext.top_ftch[i] & 0xFF) + + (int8_t)(pstate->pixel_ext.btm_ftch[i] & 0xFF), + deci_h); + + if ((hor_req_pixels != hor_fetch_pixels) || + (hor_fetch_pixels > img_w) || + (vert_req_pixels != vert_fetch_pixels) || + (vert_fetch_pixels > img_h)) { + SDE_ERROR_PLANE(psde, + "req %d/%d, fetch %d/%d, src %dx%d\n", + hor_req_pixels, vert_req_pixels, + hor_fetch_pixels, vert_fetch_pixels, + img_w, img_h); + return -EINVAL; + } + + /* + * swap the scaler src width & height for inline-rotation 90 + * comparison with Pixel-Extension, as PE is based on + * pre-rotation and QSEED is based on post-rotation + */ + rot = pstate->rotation & DRM_MODE_ROTATE_90; + scaler_w = rot ? pstate->scaler3_cfg.src_height[i] + : pstate->scaler3_cfg.src_width[i]; + scaler_h = rot ? pstate->scaler3_cfg.src_width[i] + : pstate->scaler3_cfg.src_height[i]; + /* + * Alpha plane can only be scaled using bilinear or pixel + * repeat/drop, src_width and src_height are only specified + * for Y and UV plane + */ + if (i != 3 && (hor_req_pixels / pre_down_ratio_x != scaler_w || + vert_req_pixels / pre_down_ratio_y + != scaler_h)) { + SDE_ERROR_PLANE(psde, + "roi[%d] roi:%dx%d scaler:%dx%d src:%dx%d rot:%d pd:%d/%d\n", + i, pstate->pixel_ext.roi_w[i], + pstate->pixel_ext.roi_h[i], scaler_w, + scaler_h, src_w, src_h, rot, + pre_down_ratio_x, pre_down_ratio_y); + return -EINVAL; + } + + /* + * SSPP fetch , unpack output and QSEED3 input lines need + * to match for Y plane + */ + if (i == 0 && + (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) & + BIT(SDE_DRM_DEINTERLACE)) && + ((pstate->scaler3_cfg.src_height[i] != (src_h/2)) || + (pstate->pixel_ext.roi_h[i] != (src_h/2)))) { + SDE_ERROR_PLANE(psde, + "de-interlace fail roi[%d] %d/%d, src %dx%d, src %dx%d\n", + i, pstate->pixel_ext.roi_w[i], + pstate->pixel_ext.roi_h[i], + pstate->scaler3_cfg.src_width[i], + pstate->scaler3_cfg.src_height[i], + src_w, src_h); + return -EINVAL; + } + } + + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V2; + return 0; +} + +static inline bool _sde_plane_has_pre_downscale(struct sde_plane *psde) +{ + return (psde->features & BIT(SDE_SSPP_PREDOWNSCALE)); +} + +static int _sde_atomic_check_pre_downscale(struct sde_plane *psde, + struct sde_plane_state *pstate, struct sde_rect *dst, + u32 src_w, u32 src_h) +{ + int ret = 0; + u32 min_ratio_numer, min_ratio_denom; + struct sde_hw_inline_pre_downscale_cfg *pd_cfg = &pstate->pre_down; + bool pd_x; + bool pd_y; + + if (!_sde_plane_is_pre_downscale_enabled(pd_cfg)) + return ret; + + pd_x = pd_cfg->pre_downscale_x_0 > 1; + pd_y = pd_cfg->pre_downscale_y_0 > 1; + + min_ratio_numer = psde->pipe_sblk->in_rot_maxdwnscale_rt_nopd_num; + min_ratio_denom = psde->pipe_sblk->in_rot_maxdwnscale_rt_nopd_denom; + + if (pd_x && !(_sde_plane_has_pre_downscale(psde))) { + SDE_ERROR_PLANE(psde, + "hw does not support pre-downscaler X: 0x%x\n", + psde->features); + ret = -EINVAL; + } else if (pd_y && !(psde->features & BIT(SDE_SSPP_PREDOWNSCALE_Y))) { + SDE_ERROR_PLANE(psde, + "hw does not support pre-downscale Y: 0x%x\n", + psde->features); + ret = -EINVAL; + } else if (!min_ratio_numer || !min_ratio_denom) { + SDE_ERROR_PLANE(psde, + "min downscale ratio not set! %u / %u\n", + min_ratio_numer, min_ratio_denom); + ret = -EINVAL; + + /* compare pre-rotated src w/h with post-rotated dst h/w resp. */ + } else if (pd_x && (src_w < mult_frac(dst->h, min_ratio_numer, + min_ratio_denom))) { + SDE_ERROR_PLANE(psde, + "failed min downscale-x check %u->%u, %u/%u\n", + src_w, dst->h, min_ratio_numer, min_ratio_denom); + ret = -EINVAL; + } else if (pd_y && (src_h < mult_frac(dst->w, min_ratio_numer, + min_ratio_denom))) { + SDE_ERROR_PLANE(psde, + "failed min downscale-y check %u->%u, %u/%u\n", + src_h, dst->w, min_ratio_numer, min_ratio_denom); + ret = -EINVAL; + } + + return ret; + +} + +static void _sde_plane_get_max_downscale_limits(struct sde_plane *psde, + struct sde_plane_state *pstate, bool rt_client, + u32 *max_numer_w, u32 *max_denom_w, + u32 *max_numer_h, u32 *max_denom_h) +{ + bool rotated, has_predown; + const struct sde_sspp_sub_blks *sblk; + struct sde_hw_inline_pre_downscale_cfg *pd; + + rotated = pstate->rotation & DRM_MODE_ROTATE_90; + sblk = psde->pipe_sblk; + *max_numer_w = sblk->maxdwnscale; + *max_denom_w = 1; + *max_numer_h = sblk->maxdwnscale; + *max_denom_h = 1; + + has_predown = _sde_plane_has_pre_downscale(psde); + if (has_predown) + pd = &pstate->pre_down; + + /** + * Inline rotation has different max vertical downscaling limits since + * the source-width becomes the scaler's pre-downscaled source-height. + **/ + if (rotated) { + if (rt_client && has_predown) { + *max_numer_h = pd->pre_downscale_x_0 ? + sblk->in_rot_maxdwnscale_rt_num : + sblk->in_rot_maxdwnscale_rt_nopd_num; + *max_denom_h = pd->pre_downscale_x_0 ? + sblk->in_rot_maxdwnscale_rt_denom : + sblk->in_rot_maxdwnscale_rt_nopd_denom; + } else if (rt_client) { + *max_numer_h = sblk->in_rot_maxdwnscale_rt_num; + *max_denom_h = sblk->in_rot_maxdwnscale_rt_denom; + } else { + *max_numer_h = sblk->in_rot_maxdwnscale_nrt; + } + } +} + +static int _sde_atomic_check_decimation_scaler(struct drm_plane_state *state, + struct sde_plane *psde, const struct sde_format *fmt, + struct sde_plane_state *pstate, struct sde_rect *src, + struct sde_rect *dst, u32 width, u32 height) +{ + int ret = 0; + uint32_t deci_w, deci_h, src_deci_w, src_deci_h; + uint32_t scaler_src_w, scaler_src_h; + uint32_t max_downscale_num_w, max_downscale_denom_w; + uint32_t max_downscale_num_h, max_downscale_denom_h; + uint32_t max_upscale, max_linewidth = 0; + bool inline_rotation, rt_client; + struct drm_crtc *crtc; + struct drm_crtc_state *new_cstate; + struct sde_kms *kms; + const struct sde_sspp_sub_blks *sblk; + + if (!state || !state->state || !state->crtc) { + SDE_ERROR_PLANE(psde, "invalid arguments\n"); + return -EINVAL; + } + + kms = _sde_plane_get_kms(&psde->base); + + if (!kms || !kms->catalog) { + SDE_ERROR_PLANE(psde, "invalid kms"); + return -EINVAL; + } + + deci_w = sde_plane_get_property(pstate, PLANE_PROP_H_DECIMATE); + deci_h = sde_plane_get_property(pstate, PLANE_PROP_V_DECIMATE); + + src_deci_w = DECIMATED_DIMENSION(src->w, deci_w); + src_deci_h = DECIMATED_DIMENSION(src->h, deci_h); + + /* with inline rotator, the source of the scaler is post-rotated */ + inline_rotation = pstate->rotation & DRM_MODE_ROTATE_90 ? true : false; + if (inline_rotation) { + scaler_src_w = src_deci_h; + scaler_src_h = src_deci_w; + } else { + scaler_src_w = src_deci_w; + scaler_src_h = src_deci_h; + } + + sblk = psde->pipe_sblk; + max_upscale = psde->pipe_sblk->maxupscale; + + if ((scaler_src_w != state->crtc_w) || (scaler_src_h != state->crtc_h)) + max_linewidth = inline_rotation ? + psde->pipe_sblk->in_rot_maxheight : + kms->catalog->scaling_linewidth; + + if (!max_linewidth) + max_linewidth = psde->pipe_sblk->maxlinewidth; + + crtc = state->crtc; + new_cstate = drm_atomic_get_new_crtc_state(state->state, crtc); + rt_client = sde_crtc_is_rt_client(crtc, new_cstate); + + _sde_plane_get_max_downscale_limits(psde, pstate, rt_client, + &max_downscale_num_w, &max_downscale_denom_w, + &max_downscale_num_h, &max_downscale_denom_h); + + /* decimation validation */ + if ((deci_w || deci_h) + && ((deci_w > sblk->maxhdeciexp) + || (deci_h > sblk->maxvdeciexp))) { + SDE_ERROR_PLANE(psde, "too much decimation requested\n"); + ret = -EINVAL; + + } else if ((deci_w || deci_h) + && (fmt->fetch_mode != SDE_FETCH_LINEAR)) { + SDE_ERROR_PLANE(psde, "decimation requires linear fetch\n"); + ret = -EINVAL; + + } else if (!(psde->features & SDE_SSPP_SCALER) && + ((src->w != dst->w) || (src->h != dst->h))) { + SDE_ERROR_PLANE(psde, + "pipe doesn't support scaling %ux%u->%ux%u\n", + src->w, src->h, dst->w, dst->h); + ret = -EINVAL; + + /* check decimated source width */ + } else if (scaler_src_w > max_linewidth) { + SDE_ERROR_PLANE(psde, + "invalid src w:%u, deci w:%u, line w:%u, rot: %d\n", + src->w, src_deci_w, max_linewidth, inline_rotation); + ret = -E2BIG; + + /* check max scaler capability */ + } else if (((scaler_src_w * max_upscale) < dst->w) || + ((scaler_src_h * max_upscale) < dst->h) || + (mult_frac(dst->w, max_downscale_num_w, max_downscale_denom_w) + < scaler_src_w) || + (mult_frac(dst->h, max_downscale_num_h, max_downscale_denom_h) + < scaler_src_h)) { + SDE_ERROR_PLANE(psde, + "too much scaling %ux%u->%ux%u rot:%d dwn:%d/%d %d/%d\n", + scaler_src_w, scaler_src_h, dst->w, dst->h, + inline_rotation, max_downscale_num_w, + max_downscale_denom_w, max_downscale_num_h, + max_downscale_denom_h); + ret = -E2BIG; + + /* check inline pre-downscale support */ + } else if (inline_rotation && _sde_atomic_check_pre_downscale(psde, + pstate, dst, src_deci_w, src_deci_h)) { + ret = -EINVAL; + + /* QSEED validation */ + } else if (_sde_plane_validate_scaler_v2(psde, pstate, fmt, + width, height, + src->w, src->h, deci_w, deci_h)) { + ret = -EINVAL; + } + + return ret; +} + +static int _sde_atomic_check_excl_rect(struct sde_plane *psde, + struct sde_plane_state *pstate, struct sde_rect *src, + const struct sde_format *fmt, int ret) +{ + + /* check excl rect configs */ + if (!ret && pstate->excl_rect.w && pstate->excl_rect.h) { + struct sde_rect intersect; + + /* + * Check exclusion rect against src rect. + * it must intersect with source rect. + */ + sde_kms_rect_intersect(src, &pstate->excl_rect, &intersect); + if (intersect.w != pstate->excl_rect.w || + intersect.h != pstate->excl_rect.h || + SDE_FORMAT_IS_YUV(fmt)) { + SDE_ERROR_PLANE(psde, + "invalid excl_rect:{%d,%d,%d,%d} src:{%d,%d,%d,%d}, fmt: %4.4s\n", + pstate->excl_rect.x, pstate->excl_rect.y, + pstate->excl_rect.w, pstate->excl_rect.h, + src->x, src->y, src->w, src->h, + (char *)&fmt->base.pixel_format); + ret = -EINVAL; + } + SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n", + pstate->excl_rect.x, pstate->excl_rect.y, + pstate->excl_rect.w, pstate->excl_rect.h); + } + + return ret; +} + + +static int _sde_plane_validate_shared_crtc(struct sde_plane *psde, + struct drm_plane_state *state) +{ + struct sde_kms *sde_kms; + struct sde_splash_display *splash_display; + int i, j; + + sde_kms = _sde_plane_get_kms(&psde->base); + + if (!sde_kms || !state->crtc) + return 0; + + for (i = 0; i < MAX_DSI_DISPLAYS; i++) { + splash_display = &sde_kms->splash_data.splash_display[i]; + + if (splash_display && splash_display->cont_splash_enabled && + splash_display->encoder && + state->crtc != splash_display->encoder->crtc) { + + for (j = 0; j < MAX_DATA_PATH_PER_DSIPLAY; j++) { + + if (splash_display->pipes[j].sspp == + psde->pipe) { + SDE_ERROR_PLANE(psde, + "pipe:%d used in cont-splash on crtc:%d\n", + psde->pipe, + splash_display->encoder->crtc->base.id); + return -EINVAL; + } + } + } + } + + return 0; + +} + +static int sde_plane_sspp_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + int ret = 0; + struct sde_plane *psde; + struct sde_plane_state *pstate; + const struct msm_format *msm_fmt; + const struct sde_format *fmt; + struct sde_rect src, dst; + uint32_t min_src_size; + bool q16_data = true; + struct drm_framebuffer *fb; + u32 width; + u32 height; + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(state); + + if (!psde->pipe_sblk) { + SDE_ERROR_PLANE(psde, "invalid catalog\n"); + return -EINVAL; + } + + /* src values are in Q16 fixed point, convert to integer */ + POPULATE_RECT(&src, state->src_x, state->src_y, + state->src_w, state->src_h, q16_data); + POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, state->crtc_w, + state->crtc_h, !q16_data); + + SDE_DEBUG_PLANE(psde, "check %d -> %d\n", + sde_plane_enabled(plane->state), sde_plane_enabled(state)); + + if (!sde_plane_enabled(state)) + goto modeset_update; + + fb = state->fb; + width = fb ? state->fb->width : 0x0; + height = fb ? state->fb->height : 0x0; + + SDE_DEBUG("plane%d sspp:%x/%dx%d/%4.4s/%llx\n", + plane->base.id, + pstate->rotation, + width, height, + fb ? (char *) &state->fb->format->format : 0x0, + fb ? state->fb->modifier : 0x0); + SDE_DEBUG("src:%dx%d %d,%d crtc:%dx%d+%d+%d\n", + state->src_w >> 16, state->src_h >> 16, + state->src_x >> 16, state->src_y >> 16, + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); + + msm_fmt = msm_framebuffer_format(fb); + fmt = to_sde_format(msm_fmt); + + min_src_size = SDE_FORMAT_IS_YUV(fmt) ? 2 : 1; + + if (SDE_FORMAT_IS_YUV(fmt) && + (!(psde->features & SDE_SSPP_SCALER) || + !(psde->features & (BIT(SDE_SSPP_CSC) + | BIT(SDE_SSPP_CSC_10BIT))))) { + SDE_ERROR_PLANE(psde, + "plane doesn't have scaler/csc for yuv\n"); + ret = -EINVAL; + + /* check src bounds */ + } else if (width > MAX_IMG_WIDTH || + height > MAX_IMG_HEIGHT || + src.w < min_src_size || src.h < min_src_size || + CHECK_LAYER_BOUNDS(src.x, src.w, width) || + CHECK_LAYER_BOUNDS(src.y, src.h, height)) { + SDE_ERROR_PLANE(psde, "invalid source %u, %u, %ux%u\n", + src.x, src.y, src.w, src.h); + ret = -E2BIG; + + /* valid yuv image */ + } else if (SDE_FORMAT_IS_YUV(fmt) && ((src.x & 0x1) || (src.y & 0x1) || + (src.w & 0x1) || (src.h & 0x1))) { + SDE_ERROR_PLANE(psde, "invalid yuv source %u, %u, %ux%u\n", + src.x, src.y, src.w, src.h); + ret = -EINVAL; + + /* min dst support */ + } else if (dst.w < 0x1 || dst.h < 0x1) { + SDE_ERROR_PLANE(psde, "invalid dest rect %u, %u, %ux%u\n", + dst.x, dst.y, dst.w, dst.h); + ret = -EINVAL; + } else if (SDE_FORMAT_IS_UBWC(fmt) && + !psde->catalog->ubwc_version) { + SDE_ERROR_PLANE(psde, "ubwc not supported\n"); + ret = -EINVAL; + } + + + if (ret) + return ret; + + ret = _sde_atomic_check_decimation_scaler(state, psde, fmt, pstate, + &src, &dst, width, height); + + if (ret) + return ret; + + ret = _sde_atomic_check_excl_rect(psde, pstate, + &src, fmt, ret); + + if (ret) + return ret; + + ret = _sde_plane_validate_shared_crtc(psde, state); + + if (ret) + return ret; + + pstate->const_alpha_en = fmt->alpha_enable && + (SDE_DRM_BLEND_OP_OPAQUE != + sde_plane_get_property(pstate, PLANE_PROP_BLEND_OP)) && + (pstate->stage != SDE_STAGE_0); + +modeset_update: + if (!ret) + _sde_plane_sspp_atomic_check_mode_changed(psde, + state, plane->state); + return ret; +} + +static int sde_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + int ret = 0; + struct sde_plane *psde; + struct sde_plane_state *pstate; + + if (!plane || !state) { + SDE_ERROR("invalid arg(s), plane %d state %d\n", + !plane, !state); + ret = -EINVAL; + goto exit; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(state); + + SDE_DEBUG_PLANE(psde, "\n"); + + ret = sde_plane_rot_atomic_check(plane, state); + if (ret) + goto exit; + + ret = sde_plane_sspp_atomic_check(plane, state); + +exit: + return ret; +} + +void sde_plane_flush(struct drm_plane *plane) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + + if (!plane || !plane->state) { + SDE_ERROR("invalid plane\n"); + return; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(plane->state); + + /* + * These updates have to be done immediately before the plane flush + * timing, and may not be moved to the atomic_update/mode_set functions. + */ + if (psde->is_error) + /* force white frame with 100% alpha pipe output on error */ + _sde_plane_color_fill(psde, 0xFFFFFF, 0xFF); + else if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) + /* force 100% alpha */ + _sde_plane_color_fill(psde, psde->color_fill, 0xFF); + else if (psde->pipe_hw && psde->csc_ptr && psde->pipe_hw->ops.setup_csc) + psde->pipe_hw->ops.setup_csc(psde->pipe_hw, psde->csc_ptr); + + /* flag h/w flush complete */ + if (plane->state) + pstate->pending = false; +} + +/** + * sde_plane_set_error: enable/disable error condition + * @plane: pointer to drm_plane structure + */ +void sde_plane_set_error(struct drm_plane *plane, bool error) +{ + struct sde_plane *psde; + + if (!plane) + return; + + psde = to_sde_plane(plane); + psde->is_error = error; +} + +static void _sde_plane_sspp_setup_sys_cache(struct sde_plane *psde, + struct sde_plane_state *pstate, const struct sde_format *fmt) +{ + if (!psde->pipe_hw->ops.setup_sys_cache || + !(psde->perf_features & BIT(SDE_PERF_SSPP_SYS_CACHE))) + return; + + SDE_DEBUG("features:0x%x rotation:0x%x\n", + psde->features, pstate->rotation); + + if ((pstate->rotation & DRM_MODE_ROTATE_90) && + sde_format_is_tp10_ubwc(fmt)) { + pstate->sc_cfg.rd_en = true; + pstate->sc_cfg.rd_scid = + psde->pipe_sblk->llcc_scid; + pstate->sc_cfg.flags = SSPP_SYS_CACHE_EN_FLAG | + SSPP_SYS_CACHE_SCID; + } else { + pstate->sc_cfg.rd_en = false; + pstate->sc_cfg.rd_scid = 0x0; + pstate->sc_cfg.flags = SSPP_SYS_CACHE_EN_FLAG | + SSPP_SYS_CACHE_SCID; + } + + psde->pipe_hw->ops.setup_sys_cache( + psde->pipe_hw, &pstate->sc_cfg); +} + +static void _sde_plane_map_prop_to_dirty_bits(void) +{ + plane_prop_array[PLANE_PROP_SCALER_V1] = + plane_prop_array[PLANE_PROP_SCALER_V2] = + plane_prop_array[PLANE_PROP_SCALER_LUT_ED] = + plane_prop_array[PLANE_PROP_SCALER_LUT_CIR] = + plane_prop_array[PLANE_PROP_SCALER_LUT_SEP] = + plane_prop_array[PLANE_PROP_H_DECIMATE] = + plane_prop_array[PLANE_PROP_V_DECIMATE] = + plane_prop_array[PLANE_PROP_SRC_CONFIG] = + plane_prop_array[PLANE_PROP_ZPOS] = + plane_prop_array[PLANE_PROP_EXCL_RECT_V1] = + SDE_PLANE_DIRTY_RECTS; + + plane_prop_array[PLANE_PROP_CSC_V1] = + plane_prop_array[PLANE_PROP_CSC_DMA_V1] = + plane_prop_array[PLANE_PROP_INVERSE_PMA] = + SDE_PLANE_DIRTY_FORMAT; + + plane_prop_array[PLANE_PROP_MULTIRECT_MODE] = + plane_prop_array[PLANE_PROP_COLOR_FILL] = + SDE_PLANE_DIRTY_ALL; + + /* no special action required */ + plane_prop_array[PLANE_PROP_INFO] = + plane_prop_array[PLANE_PROP_ALPHA] = + plane_prop_array[PLANE_PROP_INPUT_FENCE] = + plane_prop_array[PLANE_PROP_BLEND_OP] = + plane_prop_array[PLANE_PROP_CUSTOM]= 0; + + plane_prop_array[PLANE_PROP_FB_TRANSLATION_MODE] = + SDE_PLANE_DIRTY_FB_TRANSLATION_MODE; + plane_prop_array[PLANE_PROP_PREFILL_SIZE] = + plane_prop_array[PLANE_PROP_PREFILL_TIME] = + SDE_PLANE_DIRTY_PERF; + + plane_prop_array[PLANE_PROP_VIG_GAMUT] = SDE_PLANE_DIRTY_VIG_GAMUT; + plane_prop_array[PLANE_PROP_VIG_IGC] = SDE_PLANE_DIRTY_VIG_IGC; + plane_prop_array[PLANE_PROP_DMA_IGC] = SDE_PLANE_DIRTY_DMA_IGC; + plane_prop_array[PLANE_PROP_DMA_GC] = SDE_PLANE_DIRTY_DMA_GC; + + plane_prop_array[PLANE_PROP_SKIN_COLOR] = + plane_prop_array[PLANE_PROP_SKY_COLOR] = + plane_prop_array[PLANE_PROP_FOLIAGE_COLOR] = + plane_prop_array[PLANE_PROP_HUE_ADJUST] = + plane_prop_array[PLANE_PROP_SATURATION_ADJUST] = + plane_prop_array[PLANE_PROP_VALUE_ADJUST] = + plane_prop_array[PLANE_PROP_CONTRAST_ADJUST] = + SDE_PLANE_DIRTY_ALL; +} + +static inline bool _sde_plane_allow_uidle(struct sde_plane *psde, + struct sde_rect *src, struct sde_rect *dst) +{ + u32 max_downscale = psde->catalog->uidle_cfg.max_dwnscale; + u32 downscale = (src->h * 1000)/dst->h; + + return (downscale > max_downscale) ? false : true; +} + +static void _sde_plane_setup_uidle(struct drm_crtc *crtc, + struct sde_plane *psde, struct sde_plane_state *pstate, + struct sde_rect *src, struct sde_rect *dst) +{ + struct sde_hw_pipe_uidle_cfg cfg; + struct sde_crtc *sde_crtc = to_sde_crtc(crtc); + + u32 line_time = sde_get_linetime(&crtc->mode, + sde_crtc->comp_ratio); /* nS */ + u32 fal1_target_idle_time_ns = + psde->catalog->uidle_cfg.fal1_target_idle_time * 1000; /* nS */ + u32 fal10_target_idle_time_ns = + psde->catalog->uidle_cfg.fal10_target_idle_time * 1000; /* nS */ + u32 fal10_threshold = + psde->catalog->uidle_cfg.fal10_threshold; /* uS */ + + if (line_time && fal10_threshold && fal10_target_idle_time_ns && + fal1_target_idle_time_ns) { + cfg.enable = _sde_plane_allow_uidle(psde, src, dst); + cfg.fal10_threshold = fal10_threshold; + cfg.fal10_exit_threshold = fal10_threshold + 2; + cfg.fal1_threshold = 1 + + (fal1_target_idle_time_ns*1000/line_time*2)/1000; + cfg.fal_allowed_threshold = fal10_threshold + + (fal10_target_idle_time_ns*1000/line_time*2)/1000; + } else { + SDE_ERROR("invalid settings, will disable UIDLE %d %d %d %d\n", + line_time, fal10_threshold, fal10_target_idle_time_ns, + fal1_target_idle_time_ns); + memset(&cfg, 0, sizeof(struct sde_hw_pipe_uidle_cfg)); + } + + SDE_DEBUG_PLANE(psde, + "tholds: fal10=%d fal10_exit=%d fal1=%d fal_allowed=%d\n", + cfg.fal10_threshold, cfg.fal10_exit_threshold, + cfg.fal1_threshold, cfg.fal_allowed_threshold); + SDE_DEBUG_PLANE(psde, + "times: line:%d fal1_idle:%d fal10_idle:%d dwnscale:%d\n", + line_time, fal1_target_idle_time_ns, + fal10_target_idle_time_ns, + psde->catalog->uidle_cfg.max_dwnscale); + SDE_EVT32_VERBOSE(cfg.enable, + cfg.fal10_threshold, cfg.fal10_exit_threshold, + cfg.fal1_threshold, cfg.fal_allowed_threshold, + psde->catalog->uidle_cfg.max_dwnscale); + + psde->pipe_hw->ops.setup_uidle( + psde->pipe_hw, &cfg, + pstate->multirect_index); +} + +static void _sde_plane_update_secure_session(struct sde_plane *psde, + struct sde_plane_state *pstate) +{ + bool enable = false; + int mode = sde_plane_get_property(pstate, + PLANE_PROP_FB_TRANSLATION_MODE); + + if ((mode == SDE_DRM_FB_SEC) || + (mode == SDE_DRM_FB_SEC_DIR_TRANS)) + enable = true; + + /* update secure session flag */ + psde->pipe_hw->ops.setup_secure_address(psde->pipe_hw, + pstate->multirect_index, + enable); +} + +static void _sde_plane_update_roi_config(struct drm_plane *plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ + const struct sde_format *fmt; + const struct msm_format *msm_fmt; + struct sde_plane *psde; + struct drm_plane_state *state; + struct sde_plane_state *pstate; + struct sde_rect src, dst; + const struct sde_rect *crtc_roi; + bool q16_data = true; + int idx; + + psde = to_sde_plane(plane); + state = plane->state; + + pstate = to_sde_plane_state(state); + + msm_fmt = msm_framebuffer_format(fb); + if (!msm_fmt) { + SDE_ERROR("crtc%d plane%d: null format\n", + DRMID(crtc), DRMID(plane)); + return; + } + + fmt = to_sde_format(msm_fmt); + + POPULATE_RECT(&src, state->src_x, state->src_y, + state->src_w, state->src_h, q16_data); + POPULATE_RECT(&dst, state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, !q16_data); + + SDE_DEBUG_PLANE(psde, + "FB[%u] %u,%u,%ux%u->crtc%u %d,%d,%ux%u, %4.4s ubwc %d\n", + fb->base.id, src.x, src.y, src.w, src.h, + crtc->base.id, dst.x, dst.y, dst.w, dst.h, + (char *)&fmt->base.pixel_format, + SDE_FORMAT_IS_UBWC(fmt)); + + if (sde_plane_get_property(pstate, PLANE_PROP_SRC_CONFIG) & + BIT(SDE_DRM_DEINTERLACE)) { + SDE_DEBUG_PLANE(psde, "deinterlace\n"); + for (idx = 0; idx < SDE_MAX_PLANES; ++idx) + psde->pipe_cfg.layout.plane_pitch[idx] <<= 1; + src.h /= 2; + src.y = DIV_ROUND_UP(src.y, 2); + src.y &= ~0x1; + } + + /* + * adjust layer mixer position of the sspp in the presence + * of a partial update to the active lm origin + */ + sde_crtc_get_crtc_roi(crtc->state, &crtc_roi); + dst.x -= crtc_roi->x; + dst.y -= crtc_roi->y; + + /* check for UIDLE */ + if (psde->pipe_hw->ops.setup_uidle) + _sde_plane_setup_uidle(crtc, psde, pstate, &src, &dst); + + psde->pipe_cfg.src_rect = src; + psde->pipe_cfg.dst_rect = dst; + + _sde_plane_setup_scaler(psde, pstate, fmt, false); + + /* check for color fill */ + psde->color_fill = (uint32_t)sde_plane_get_property(pstate, + PLANE_PROP_COLOR_FILL); + if (psde->color_fill & SDE_PLANE_COLOR_FILL_FLAG) { + /* skip remaining processing on color fill */ + pstate->dirty = 0x0; + } else if (psde->pipe_hw->ops.setup_rects) { + psde->pipe_hw->ops.setup_rects(psde->pipe_hw, + &psde->pipe_cfg, + pstate->multirect_index); + } + + if (psde->pipe_hw->ops.setup_pe && + (pstate->multirect_index != SDE_SSPP_RECT_1)) + psde->pipe_hw->ops.setup_pe(psde->pipe_hw, + &pstate->pixel_ext); + + /** + * when programmed in multirect mode, scalar block will be + * bypassed. Still we need to update alpha and bitwidth + * ONLY for RECT0 + */ + if (psde->pipe_hw->ops.setup_scaler && + pstate->multirect_index != SDE_SSPP_RECT_1) { + psde->pipe_hw->ctl = _sde_plane_get_hw_ctl(plane); + psde->pipe_hw->ops.setup_scaler(psde->pipe_hw, + &psde->pipe_cfg, &pstate->pixel_ext, + &pstate->scaler3_cfg); + } + + /* update excl rect */ + if (psde->pipe_hw->ops.setup_excl_rect) + psde->pipe_hw->ops.setup_excl_rect(psde->pipe_hw, + &pstate->excl_rect, + pstate->multirect_index); + + if (psde->pipe_hw->ops.setup_multirect) + psde->pipe_hw->ops.setup_multirect( + psde->pipe_hw, + pstate->multirect_index, + pstate->multirect_mode); +} + +static void _sde_plane_update_format_and_rects(struct sde_plane *psde, + struct sde_plane_state *pstate, const struct sde_format *fmt) +{ + uint32_t src_flags = 0; + + SDE_DEBUG_PLANE(psde, "rotation 0x%X\n", pstate->rotation); + if (pstate->rotation & DRM_MODE_REFLECT_X) + src_flags |= SDE_SSPP_FLIP_LR; + if (pstate->rotation & DRM_MODE_REFLECT_Y) + src_flags |= SDE_SSPP_FLIP_UD; + if (pstate->rotation & DRM_MODE_ROTATE_90) + src_flags |= SDE_SSPP_ROT_90; + + /* update format */ + psde->pipe_hw->ops.setup_format(psde->pipe_hw, fmt, + pstate->const_alpha_en, src_flags, + pstate->multirect_index); + + if (psde->pipe_hw->ops.setup_cdp) { + struct sde_hw_pipe_cdp_cfg *cdp_cfg = &pstate->cdp_cfg; + + memset(cdp_cfg, 0, sizeof(struct sde_hw_pipe_cdp_cfg)); + + cdp_cfg->enable = psde->catalog->perf.cdp_cfg + [SDE_PERF_CDP_USAGE_RT].rd_enable; + cdp_cfg->ubwc_meta_enable = + SDE_FORMAT_IS_UBWC(fmt); + cdp_cfg->tile_amortize_enable = + SDE_FORMAT_IS_UBWC(fmt) || + SDE_FORMAT_IS_TILE(fmt); + cdp_cfg->preload_ahead = SDE_WB_CDP_PRELOAD_AHEAD_64; + + psde->pipe_hw->ops.setup_cdp(psde->pipe_hw, cdp_cfg, + pstate->multirect_index); + } + + _sde_plane_sspp_setup_sys_cache(psde, pstate, fmt); + + /* update csc */ + if (SDE_FORMAT_IS_YUV(fmt)) + _sde_plane_setup_csc(psde); + else + psde->csc_ptr = 0; + + if (psde->pipe_hw->ops.setup_inverse_pma) { + uint32_t pma_mode = 0; + + if (fmt->alpha_enable) + pma_mode = (uint32_t) sde_plane_get_property( + pstate, PLANE_PROP_INVERSE_PMA); + psde->pipe_hw->ops.setup_inverse_pma(psde->pipe_hw, + pstate->multirect_index, pma_mode); + } + + if (psde->pipe_hw->ops.setup_dgm_csc) + psde->pipe_hw->ops.setup_dgm_csc(psde->pipe_hw, + pstate->multirect_index, psde->csc_usr_ptr); +} + +static void _sde_plane_update_sharpening(struct sde_plane *psde) +{ + psde->sharp_cfg.strength = SHARP_STRENGTH_DEFAULT; + psde->sharp_cfg.edge_thr = SHARP_EDGE_THR_DEFAULT; + psde->sharp_cfg.smooth_thr = SHARP_SMOOTH_THR_DEFAULT; + psde->sharp_cfg.noise_thr = SHARP_NOISE_THR_DEFAULT; + + psde->pipe_hw->ops.setup_sharpening(psde->pipe_hw, + &psde->sharp_cfg); +} + +static void _sde_plane_update_properties(struct drm_plane *plane, + struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ + uint32_t nplanes; + const struct msm_format *msm_fmt; + const struct sde_format *fmt; + struct sde_plane *psde; + struct drm_plane_state *state; + struct sde_plane_state *pstate; + + psde = to_sde_plane(plane); + state = plane->state; + + pstate = to_sde_plane_state(state); + if (!pstate) { + SDE_ERROR("invalid plane state for plane%d\n", DRMID(plane)); + return; + } + + msm_fmt = msm_framebuffer_format(fb); + if (!msm_fmt) { + SDE_ERROR("crtc%d plane%d: null format\n", + DRMID(crtc), DRMID(plane)); + return; + } + + fmt = to_sde_format(msm_fmt); + nplanes = fmt->num_planes; + + /* update secure session flag */ + if (pstate->dirty & SDE_PLANE_DIRTY_FB_TRANSLATION_MODE) + _sde_plane_update_secure_session(psde, pstate); + + /* update roi config */ + if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) + _sde_plane_update_roi_config(plane, crtc, fb); + + if ((pstate->dirty & SDE_PLANE_DIRTY_FORMAT || + pstate->dirty & SDE_PLANE_DIRTY_RECTS) && + psde->pipe_hw->ops.setup_format) + _sde_plane_update_format_and_rects(psde, pstate, fmt); + + sde_color_process_plane_setup(plane); + + /* update sharpening */ + if ((pstate->dirty & SDE_PLANE_DIRTY_SHARPEN) && + psde->pipe_hw->ops.setup_sharpening) + _sde_plane_update_sharpening(psde); + + _sde_plane_set_qos_lut(plane, crtc, fb); + + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL); + _sde_plane_set_ot_limit(plane, crtc); + if (pstate->dirty & SDE_PLANE_DIRTY_PERF) + _sde_plane_set_ts_prefill(plane, pstate); + } + + if ((pstate->dirty & SDE_PLANE_DIRTY_ALL) == SDE_PLANE_DIRTY_ALL) + _sde_plane_set_qos_remap(plane, true); + else + _sde_plane_set_qos_remap(plane, false); + + /* clear dirty */ + pstate->dirty = 0x0; +} + +static int sde_plane_sspp_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct sde_plane *psde; + struct drm_plane_state *state; + struct sde_plane_state *pstate; + struct sde_plane_state *old_pstate; + struct drm_crtc *crtc; + struct drm_framebuffer *fb; + int idx; + int dirty_prop_flag; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return -EINVAL; + } else if (!plane->state) { + SDE_ERROR("invalid plane state\n"); + return -EINVAL; + } else if (!old_state) { + SDE_ERROR("invalid old state\n"); + return -EINVAL; + } + + psde = to_sde_plane(plane); + state = plane->state; + + pstate = to_sde_plane_state(state); + + old_pstate = to_sde_plane_state(old_state); + + crtc = state->crtc; + fb = state->fb; + if (!crtc || !fb) { + SDE_ERROR_PLANE(psde, "invalid crtc %d or fb %d\n", + !crtc, !fb); + return -EINVAL; + } + + SDE_DEBUG( + "plane%d sspp:%dx%d/%4.4s/%llx/%dx%d+%d+%d/%x crtc:%dx%d+%d+%d\n", + plane->base.id, + state->fb->width, state->fb->height, + (char *) &state->fb->format->format, + state->fb->modifier, + state->src_w >> 16, state->src_h >> 16, + state->src_x >> 16, state->src_y >> 16, + pstate->rotation, + state->crtc_w, state->crtc_h, + state->crtc_x, state->crtc_y); + + /* force reprogramming of all the parameters, if the flag is set */ + if (psde->revalidate) { + SDE_DEBUG("plane:%d - reconfigure all the parameters\n", + plane->base.id); + pstate->dirty = SDE_PLANE_DIRTY_ALL | SDE_PLANE_DIRTY_CP; + psde->revalidate = false; + } + + /* determine what needs to be refreshed */ + mutex_lock(&psde->property_info.property_lock); + while ((idx = msm_property_pop_dirty(&psde->property_info, + &pstate->property_state)) >= 0) { + dirty_prop_flag = plane_prop_array[idx]; + pstate->dirty |= dirty_prop_flag; + } + mutex_unlock(&psde->property_info.property_lock); + + /** + * since plane_atomic_check is invoked before crtc_atomic_check + * in the commit sequence, all the parameters for updating the + * plane dirty flag will not be available during + * plane_atomic_check as some features params are updated + * in crtc_atomic_check (eg.:sDMA). So check for mode_change + * before sspp update. + */ + _sde_plane_sspp_atomic_check_mode_changed(psde, state, + old_state); + + /* re-program the output rects always if partial update roi changed */ + if (sde_crtc_is_crtc_roi_dirty(crtc->state)) + pstate->dirty |= SDE_PLANE_DIRTY_RECTS; + + if (pstate->dirty & SDE_PLANE_DIRTY_RECTS) + memset(&(psde->pipe_cfg), 0, sizeof(struct sde_hw_pipe_cfg)); + + _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb); + + /* early out if nothing dirty */ + if (!pstate->dirty) + return 0; + pstate->pending = true; + + psde->is_rt_pipe = sde_crtc_is_rt_client(crtc, crtc->state); + _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL); + + _sde_plane_update_properties(plane, crtc, fb); + + return 0; +} + +static void _sde_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct sde_plane *psde; + struct drm_plane_state *state; + struct sde_plane_state *pstate; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return; + } else if (!plane->state) { + SDE_ERROR("invalid plane state\n"); + return; + } else if (!old_state) { + SDE_ERROR("invalid old state\n"); + return; + } + + psde = to_sde_plane(plane); + state = plane->state; + pstate = to_sde_plane_state(state); + + SDE_EVT32(DRMID(plane), is_sde_plane_virtual(plane), + pstate->multirect_mode); + + pstate->pending = true; + + if (is_sde_plane_virtual(plane) && + psde->pipe_hw && psde->pipe_hw->ops.setup_multirect) + psde->pipe_hw->ops.setup_multirect(psde->pipe_hw, + SDE_SSPP_RECT_SOLO, SDE_SSPP_MULTIRECT_NONE); +} + +static void sde_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *old_state) +{ + struct sde_plane *psde; + struct drm_plane_state *state; + struct sde_plane_state *pstate; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return; + } else if (!plane->state) { + SDE_ERROR("invalid plane state\n"); + return; + } + + psde = to_sde_plane(plane); + state = plane->state; + pstate = to_sde_plane_state(state); + + if (psde->is_error && !(msm_property_is_dirty(&psde->property_info, + &pstate->property_state, PLANE_PROP_SCALER_V2))) + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_INVALID; + + psde->is_error = false; + SDE_DEBUG_PLANE(psde, "\n"); + + if (!sde_plane_enabled(state)) { + _sde_plane_atomic_disable(plane, old_state); + } else { + int ret; + + ret = sde_plane_sspp_atomic_update(plane, old_state); + /* atomic_check should have ensured that this doesn't fail */ + WARN_ON(ret < 0); + } +} + +void sde_plane_restore(struct drm_plane *plane) +{ + struct sde_plane *psde; + + if (!plane || !plane->state) { + SDE_ERROR("invalid plane\n"); + return; + } + + psde = to_sde_plane(plane); + + /* + * Revalidate is only true here if idle PC occurred and + * there is no plane state update in current commit cycle. + */ + if (!psde->revalidate) + return; + + SDE_DEBUG_PLANE(psde, "\n"); + + /* last plane state is same as current state */ + sde_plane_atomic_update(plane, plane->state); +} + +bool sde_plane_is_cache_required(struct drm_plane *plane) +{ + struct sde_plane_state *pstate; + + if (!plane || !plane->state) { + SDE_ERROR("invalid plane\n"); + return false; + } + + pstate = to_sde_plane_state(plane->state); + + /* check if llcc is required for the plane */ + if (pstate->sc_cfg.rd_en) + return true; + else + return false; +} + +static void _sde_plane_install_non_master_properties(struct sde_plane *psde) +{ + char feature_name[256]; + + if (psde->pipe_sblk->maxhdeciexp) { + msm_property_install_range(&psde->property_info, + "h_decimate", 0x0, 0, + psde->pipe_sblk->maxhdeciexp, 0, + PLANE_PROP_H_DECIMATE); + } + + if (psde->pipe_sblk->maxvdeciexp) { + msm_property_install_range(&psde->property_info, + "v_decimate", 0x0, 0, + psde->pipe_sblk->maxvdeciexp, 0, + PLANE_PROP_V_DECIMATE); + } + + if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3)) { + msm_property_install_range( + &psde->property_info, "scaler_v2", + 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2); + msm_property_install_blob(&psde->property_info, + "lut_ed", 0, PLANE_PROP_SCALER_LUT_ED); + msm_property_install_blob(&psde->property_info, + "lut_cir", 0, + PLANE_PROP_SCALER_LUT_CIR); + msm_property_install_blob(&psde->property_info, + "lut_sep", 0, + PLANE_PROP_SCALER_LUT_SEP); + } else if (psde->features & BIT(SDE_SSPP_SCALER_QSEED3LITE)) { + msm_property_install_range( + &psde->property_info, "scaler_v2", + 0x0, 0, ~0, 0, PLANE_PROP_SCALER_V2); + msm_property_install_blob(&psde->property_info, + "lut_sep", 0, + PLANE_PROP_SCALER_LUT_SEP); + } else if (psde->features & SDE_SSPP_SCALER) { + msm_property_install_range( + &psde->property_info, "scaler_v1", 0x0, + 0, ~0, 0, PLANE_PROP_SCALER_V1); + } + + if (psde->features & BIT(SDE_SSPP_CSC) || + psde->features & BIT(SDE_SSPP_CSC_10BIT)) + msm_property_install_volatile_range( + &psde->property_info, "csc_v1", 0x0, + 0, ~0, 0, PLANE_PROP_CSC_V1); + + if (psde->features & BIT(SDE_SSPP_HSIC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_HUE_V", + psde->pipe_sblk->hsic_blk.version >> 16); + msm_property_install_range(&psde->property_info, + feature_name, 0, 0, 0xFFFFFFFF, 0, + PLANE_PROP_HUE_ADJUST); + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_SATURATION_V", + psde->pipe_sblk->hsic_blk.version >> 16); + msm_property_install_range(&psde->property_info, + feature_name, 0, 0, 0xFFFFFFFF, 0, + PLANE_PROP_SATURATION_ADJUST); + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_VALUE_V", + psde->pipe_sblk->hsic_blk.version >> 16); + msm_property_install_range(&psde->property_info, + feature_name, 0, 0, 0xFFFFFFFF, 0, + PLANE_PROP_VALUE_ADJUST); + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_CONTRAST_V", + psde->pipe_sblk->hsic_blk.version >> 16); + msm_property_install_range(&psde->property_info, + feature_name, 0, 0, 0xFFFFFFFF, 0, + PLANE_PROP_CONTRAST_ADJUST); + } + +} + +/* helper to install properties which are common to planes and crtcs */ +static void _sde_plane_install_properties(struct drm_plane *plane, + struct sde_mdss_cfg *catalog, u32 master_plane_id) +{ + static const struct drm_prop_enum_list e_blend_op[] = { + {SDE_DRM_BLEND_OP_NOT_DEFINED, "not_defined"}, + {SDE_DRM_BLEND_OP_OPAQUE, "opaque"}, + {SDE_DRM_BLEND_OP_PREMULTIPLIED, "premultiplied"}, + {SDE_DRM_BLEND_OP_COVERAGE, "coverage"} + }; + static const struct drm_prop_enum_list e_src_config[] = { + {SDE_DRM_DEINTERLACE, "deinterlace"} + }; + static const struct drm_prop_enum_list e_fb_translation_mode[] = { + {SDE_DRM_FB_NON_SEC, "non_sec"}, + {SDE_DRM_FB_SEC, "sec"}, + {SDE_DRM_FB_NON_SEC_DIR_TRANS, "non_sec_direct_translation"}, + {SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"}, + }; + static const struct drm_prop_enum_list e_multirect_mode[] = { + {SDE_SSPP_MULTIRECT_NONE, "none"}, + {SDE_SSPP_MULTIRECT_PARALLEL, "parallel"}, + {SDE_SSPP_MULTIRECT_TIME_MX, "serial"}, + }; + const struct sde_format_extended *format_list; + struct sde_kms_info *info; + struct sde_plane *psde = to_sde_plane(plane); + int zpos_max = 255; + int zpos_def = 0; + char feature_name[256]; + + if (!plane || !psde) { + SDE_ERROR("invalid plane\n"); + return; + } else if (!psde->pipe_hw || !psde->pipe_sblk) { + SDE_ERROR("invalid plane, pipe_hw %d pipe_sblk %d\n", + !psde->pipe_hw, !psde->pipe_sblk); + return; + } else if (!catalog) { + SDE_ERROR("invalid catalog\n"); + return; + } + + psde->catalog = catalog; + + if (sde_is_custom_client()) { + if (catalog->mixer_count && + catalog->mixer[0].sblk->maxblendstages) { + zpos_max = catalog->mixer[0].sblk->maxblendstages - 1; + if (catalog->has_base_layer && + (zpos_max > SDE_STAGE_MAX - 1)) + zpos_max = SDE_STAGE_MAX - 1; + else if (zpos_max > SDE_STAGE_MAX - SDE_STAGE_0 - 1) + zpos_max = SDE_STAGE_MAX - SDE_STAGE_0 - 1; + } + } else if (plane->type != DRM_PLANE_TYPE_PRIMARY) { + /* reserve zpos == 0 for primary planes */ + zpos_def = drm_plane_index(plane) + 1; + } + + msm_property_install_range(&psde->property_info, "zpos", + 0x0, 0, zpos_max, zpos_def, PLANE_PROP_ZPOS); + +//Vikas@OnePlus.MultiMediaService,2020/03/13, add for fingerprint + msm_property_install_range(&psde->property_info, "PLANE_CUST", + 0x0, 0, INT_MAX, 0, PLANE_PROP_CUSTOM); + + msm_property_install_range(&psde->property_info, "alpha", + 0x0, 0, 255, 255, PLANE_PROP_ALPHA); + + /* linux default file descriptor range on each process */ + msm_property_install_range(&psde->property_info, "input_fence", + 0x0, 0, INR_OPEN_MAX, 0, PLANE_PROP_INPUT_FENCE); + + if (!master_plane_id) + _sde_plane_install_non_master_properties(psde); + + if (psde->features & BIT(SDE_SSPP_EXCL_RECT)) + msm_property_install_volatile_range(&psde->property_info, + "excl_rect_v1", 0x0, 0, ~0, 0, PLANE_PROP_EXCL_RECT_V1); + + sde_plane_rot_install_properties(plane, catalog); + + msm_property_install_enum(&psde->property_info, "blend_op", 0x0, 0, + e_blend_op, ARRAY_SIZE(e_blend_op), PLANE_PROP_BLEND_OP); + + msm_property_install_enum(&psde->property_info, "src_config", 0x0, 1, + e_src_config, ARRAY_SIZE(e_src_config), PLANE_PROP_SRC_CONFIG); + + if (psde->pipe_hw->ops.setup_solidfill) + msm_property_install_range(&psde->property_info, "color_fill", + 0, 0, 0xFFFFFFFF, 0, PLANE_PROP_COLOR_FILL); + + msm_property_install_range(&psde->property_info, + "prefill_size", 0x0, 0, ~0, 0, + PLANE_PROP_PREFILL_SIZE); + msm_property_install_range(&psde->property_info, + "prefill_time", 0x0, 0, ~0, 0, + PLANE_PROP_PREFILL_TIME); + + info = kzalloc(sizeof(struct sde_kms_info), GFP_KERNEL); + if (!info) { + SDE_ERROR("failed to allocate info memory\n"); + return; + } + + msm_property_install_blob(&psde->property_info, "capabilities", + DRM_MODE_PROP_IMMUTABLE, PLANE_PROP_INFO); + sde_kms_info_reset(info); + + if (!master_plane_id) { + format_list = psde->pipe_sblk->format_list; + } else { + format_list = psde->pipe_sblk->virt_format_list; + sde_kms_info_add_keyint(info, "primary_smart_plane_id", + master_plane_id); + msm_property_install_enum(&psde->property_info, + "multirect_mode", 0x0, 0, e_multirect_mode, + ARRAY_SIZE(e_multirect_mode), + PLANE_PROP_MULTIRECT_MODE); + } + + if (format_list) { + sde_kms_info_start(info, "pixel_formats"); + while (format_list->fourcc_format) { + sde_kms_info_append_format(info, + format_list->fourcc_format, + format_list->modifier); + ++format_list; + } + sde_kms_info_stop(info); + } + + if (psde->pipe_hw && psde->pipe_hw->ops.get_scaler_ver) + sde_kms_info_add_keyint(info, "scaler_step_ver", + psde->pipe_hw->ops.get_scaler_ver(psde->pipe_hw)); + + sde_kms_info_add_keyint(info, "max_linewidth", + psde->pipe_sblk->maxlinewidth); + sde_kms_info_add_keyint(info, "max_upscale", + psde->pipe_sblk->maxupscale); + sde_kms_info_add_keyint(info, "max_downscale", + psde->pipe_sblk->maxdwnscale); + sde_kms_info_add_keyint(info, "max_horizontal_deci", + psde->pipe_sblk->maxhdeciexp); + sde_kms_info_add_keyint(info, "max_vertical_deci", + psde->pipe_sblk->maxvdeciexp); + sde_kms_info_add_keyint(info, "max_per_pipe_bw", + psde->pipe_sblk->max_per_pipe_bw * 1000LL); + sde_kms_info_add_keyint(info, "max_per_pipe_bw_high", + psde->pipe_sblk->max_per_pipe_bw_high * 1000LL); + + if ((!master_plane_id && + (psde->features & BIT(SDE_SSPP_INVERSE_PMA))) || + (psde->features & BIT(SDE_SSPP_DGM_INVERSE_PMA))) { + msm_property_install_range(&psde->property_info, + "inverse_pma", 0x0, 0, 1, 0, PLANE_PROP_INVERSE_PMA); + sde_kms_info_add_keyint(info, "inverse_pma", 1); + } + + if (psde->features & BIT(SDE_SSPP_DGM_CSC)) { + msm_property_install_volatile_range( + &psde->property_info, "csc_dma_v1", 0x0, + 0, ~0, 0, PLANE_PROP_CSC_DMA_V1); + sde_kms_info_add_keyint(info, "csc_dma_v1", 1); + } + + if (psde->features & BIT(SDE_SSPP_SEC_UI_ALLOWED)) + sde_kms_info_add_keyint(info, "sec_ui_allowed", 1); + if (psde->features & BIT(SDE_SSPP_BLOCK_SEC_UI)) + sde_kms_info_add_keyint(info, "block_sec_ui", 1); + + if (psde->features & BIT(SDE_SSPP_TRUE_INLINE_ROT)) { + const struct sde_format_extended *inline_rot_fmt_list; + + sde_kms_info_add_keyint(info, "true_inline_rot_rev", + catalog->true_inline_rot_rev); + sde_kms_info_add_keyint(info, + "true_inline_dwnscale_rt", + (int) (psde->pipe_sblk->in_rot_maxdwnscale_rt_num / + psde->pipe_sblk->in_rot_maxdwnscale_rt_denom)); + sde_kms_info_add_keyint(info, + "true_inline_dwnscale_rt_numerator", + psde->pipe_sblk->in_rot_maxdwnscale_rt_num); + sde_kms_info_add_keyint(info, + "true_inline_dwnscale_rt_denominator", + psde->pipe_sblk->in_rot_maxdwnscale_rt_denom); + sde_kms_info_add_keyint(info, "true_inline_dwnscale_nrt", + psde->pipe_sblk->in_rot_maxdwnscale_nrt); + sde_kms_info_add_keyint(info, "true_inline_max_height", + psde->pipe_sblk->in_rot_maxheight); + + inline_rot_fmt_list = psde->pipe_sblk->in_rot_format_list; + + if (inline_rot_fmt_list) { + sde_kms_info_start(info, "inline_rot_pixel_formats"); + while (inline_rot_fmt_list->fourcc_format) { + sde_kms_info_append_format(info, + inline_rot_fmt_list->fourcc_format, + inline_rot_fmt_list->modifier); + ++inline_rot_fmt_list; + } + sde_kms_info_stop(info); + } + + } + + msm_property_set_blob(&psde->property_info, &psde->blob_info, + info->data, SDE_KMS_INFO_DATALEN(info), + PLANE_PROP_INFO); + + kfree(info); + + if (psde->features & BIT(SDE_SSPP_MEMCOLOR)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_SKIN_COLOR_V", + psde->pipe_sblk->memcolor_blk.version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_SKIN_COLOR); + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_SKY_COLOR_V", + psde->pipe_sblk->memcolor_blk.version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_SKY_COLOR); + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_SSPP_FOLIAGE_COLOR_V", + psde->pipe_sblk->memcolor_blk.version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_FOLIAGE_COLOR); + } + + if (psde->features & BIT(SDE_SSPP_VIG_GAMUT)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_VIG_3D_LUT_GAMUT_V", + psde->pipe_sblk->gamut_blk.version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_VIG_GAMUT); + } + + if (psde->features & BIT(SDE_SSPP_VIG_IGC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_VIG_1D_LUT_IGC_V", + psde->pipe_sblk->igc_blk[0].version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_VIG_IGC); + } + + if (psde->features & BIT(SDE_SSPP_DMA_IGC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_DGM_1D_LUT_IGC_V", + psde->pipe_sblk->igc_blk[0].version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_DMA_IGC); + } + + if (psde->features & BIT(SDE_SSPP_DMA_GC)) { + snprintf(feature_name, sizeof(feature_name), "%s%d", + "SDE_DGM_1D_LUT_GC_V", + psde->pipe_sblk->gc_blk[0].version >> 16); + msm_property_install_blob(&psde->property_info, feature_name, 0, + PLANE_PROP_DMA_GC); + } + + msm_property_install_enum(&psde->property_info, "fb_translation_mode", + 0x0, + 0, e_fb_translation_mode, + ARRAY_SIZE(e_fb_translation_mode), + PLANE_PROP_FB_TRANSLATION_MODE); +} + +static inline void _sde_plane_set_csc_v1(struct sde_plane *psde, + void __user *usr_ptr) +{ + struct sde_drm_csc_v1 csc_v1; + int i; + + if (!psde) { + SDE_ERROR("invalid plane\n"); + return; + } + + psde->csc_usr_ptr = NULL; + if (!usr_ptr) { + SDE_DEBUG_PLANE(psde, "csc data removed\n"); + return; + } + + if (copy_from_user(&csc_v1, usr_ptr, sizeof(csc_v1))) { + SDE_ERROR_PLANE(psde, "failed to copy csc data\n"); + return; + } + + /* populate from user space */ + for (i = 0; i < SDE_CSC_MATRIX_COEFF_SIZE; ++i) + psde->csc_cfg.csc_mv[i] = csc_v1.ctm_coeff[i] >> 16; + for (i = 0; i < SDE_CSC_BIAS_SIZE; ++i) { + psde->csc_cfg.csc_pre_bv[i] = csc_v1.pre_bias[i]; + psde->csc_cfg.csc_post_bv[i] = csc_v1.post_bias[i]; + } + for (i = 0; i < SDE_CSC_CLAMP_SIZE; ++i) { + psde->csc_cfg.csc_pre_lv[i] = csc_v1.pre_clamp[i]; + psde->csc_cfg.csc_post_lv[i] = csc_v1.post_clamp[i]; + } + psde->csc_usr_ptr = &psde->csc_cfg; +} + +static inline void _sde_plane_set_scaler_v1(struct sde_plane *psde, + struct sde_plane_state *pstate, void __user *usr) +{ + struct sde_drm_scaler_v1 scale_v1; + struct sde_hw_pixel_ext *pe; + int i; + + if (!psde || !pstate) { + SDE_ERROR("invalid argument(s)\n"); + return; + } + + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_NONE; + if (!usr) { + SDE_DEBUG_PLANE(psde, "scale data removed\n"); + return; + } + + if (copy_from_user(&scale_v1, usr, sizeof(scale_v1))) { + SDE_ERROR_PLANE(psde, "failed to copy scale data\n"); + return; + } + + /* force property to be dirty, even if the pointer didn't change */ + msm_property_set_dirty(&psde->property_info, + &pstate->property_state, PLANE_PROP_SCALER_V1); + + /* populate from user space */ + pe = &pstate->pixel_ext; + memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); + for (i = 0; i < SDE_MAX_PLANES; i++) { + pe->init_phase_x[i] = scale_v1.init_phase_x[i]; + pe->phase_step_x[i] = scale_v1.phase_step_x[i]; + pe->init_phase_y[i] = scale_v1.init_phase_y[i]; + pe->phase_step_y[i] = scale_v1.phase_step_y[i]; + + pe->horz_filter[i] = scale_v1.horz_filter[i]; + pe->vert_filter[i] = scale_v1.vert_filter[i]; + } + for (i = 0; i < SDE_MAX_PLANES; i++) { + pe->left_ftch[i] = scale_v1.pe.left_ftch[i]; + pe->right_ftch[i] = scale_v1.pe.right_ftch[i]; + pe->left_rpt[i] = scale_v1.pe.left_rpt[i]; + pe->right_rpt[i] = scale_v1.pe.right_rpt[i]; + pe->roi_w[i] = scale_v1.pe.num_ext_pxls_lr[i]; + + pe->top_ftch[i] = scale_v1.pe.top_ftch[i]; + pe->btm_ftch[i] = scale_v1.pe.btm_ftch[i]; + pe->top_rpt[i] = scale_v1.pe.top_rpt[i]; + pe->btm_rpt[i] = scale_v1.pe.btm_rpt[i]; + pe->roi_h[i] = scale_v1.pe.num_ext_pxls_tb[i]; + } + + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V1; + + SDE_EVT32_VERBOSE(DRMID(&psde->base)); + SDE_DEBUG_PLANE(psde, "user property data copied\n"); +} + +static void _sde_plane_clear_predownscale_settings( + struct sde_plane_state *pstate) +{ + pstate->pre_down.pre_downscale_x_0 = 0; + pstate->pre_down.pre_downscale_x_1 = 0; + pstate->pre_down.pre_downscale_y_0 = 0; + pstate->pre_down.pre_downscale_y_1 = 0; +} + +static inline void _sde_plane_set_scaler_v2(struct sde_plane *psde, + struct sde_plane_state *pstate, void __user *usr) +{ + struct sde_drm_scaler_v2 scale_v2; + struct sde_hw_pixel_ext *pe; + int i; + struct sde_hw_scaler3_cfg *cfg; + struct sde_hw_inline_pre_downscale_cfg *pd_cfg; + + if (!psde || !pstate) { + SDE_ERROR("invalid argument(s)\n"); + return; + } + + cfg = &pstate->scaler3_cfg; + pd_cfg = &pstate->pre_down; + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_NONE; + if (!usr) { + SDE_DEBUG_PLANE(psde, "scale data removed\n"); + cfg->enable = 0; + _sde_plane_clear_predownscale_settings(pstate); + goto end; + } + + if (copy_from_user(&scale_v2, usr, sizeof(scale_v2))) { + SDE_ERROR_PLANE(psde, "failed to copy scale data\n"); + return; + } + + /* detach/ignore user data if 'disabled' */ + if (!scale_v2.enable) { + SDE_DEBUG_PLANE(psde, "scale data removed\n"); + cfg->enable = 0; + _sde_plane_clear_predownscale_settings(pstate); + goto end; + } + + /* populate from user space */ + sde_set_scaler_v2(cfg, &scale_v2); + + if (_sde_plane_has_pre_downscale(psde)) { + pd_cfg->pre_downscale_x_0 = scale_v2.pre_downscale_x_0; + pd_cfg->pre_downscale_x_1 = scale_v2.pre_downscale_x_1; + pd_cfg->pre_downscale_y_0 = scale_v2.pre_downscale_y_0; + pd_cfg->pre_downscale_y_1 = scale_v2.pre_downscale_y_1; + } + + pe = &pstate->pixel_ext; + memset(pe, 0, sizeof(struct sde_hw_pixel_ext)); + + for (i = 0; i < SDE_MAX_PLANES; i++) { + pe->left_ftch[i] = scale_v2.pe.left_ftch[i]; + pe->right_ftch[i] = scale_v2.pe.right_ftch[i]; + pe->left_rpt[i] = scale_v2.pe.left_rpt[i]; + pe->right_rpt[i] = scale_v2.pe.right_rpt[i]; + pe->roi_w[i] = scale_v2.pe.num_ext_pxls_lr[i]; + + pe->top_ftch[i] = scale_v2.pe.top_ftch[i]; + pe->btm_ftch[i] = scale_v2.pe.btm_ftch[i]; + pe->top_rpt[i] = scale_v2.pe.top_rpt[i]; + pe->btm_rpt[i] = scale_v2.pe.btm_rpt[i]; + pe->roi_h[i] = scale_v2.pe.num_ext_pxls_tb[i]; + } + pstate->scaler_check_state = SDE_PLANE_SCLCHECK_SCALER_V2_CHECK; + +end: + /* force property to be dirty, even if the pointer didn't change */ + msm_property_set_dirty(&psde->property_info, + &pstate->property_state, PLANE_PROP_SCALER_V2); + + SDE_EVT32_VERBOSE(DRMID(&psde->base), cfg->enable, cfg->de.enable, + cfg->src_width[0], cfg->src_height[0], + cfg->dst_width, cfg->dst_height); + SDE_DEBUG_PLANE(psde, "user property data copied\n"); +} + +static void _sde_plane_set_excl_rect_v1(struct sde_plane *psde, + struct sde_plane_state *pstate, void __user *usr_ptr) +{ + struct drm_clip_rect excl_rect_v1; + + if (!psde || !pstate) { + SDE_ERROR("invalid argument(s)\n"); + return; + } + + if (!usr_ptr) { + memset(&pstate->excl_rect, 0, sizeof(pstate->excl_rect)); + SDE_DEBUG_PLANE(psde, "excl_rect data cleared\n"); + return; + } + + if (copy_from_user(&excl_rect_v1, usr_ptr, sizeof(excl_rect_v1))) { + SDE_ERROR_PLANE(psde, "failed to copy excl_rect data\n"); + return; + } + + /* populate from user space */ + pstate->excl_rect.x = excl_rect_v1.x1; + pstate->excl_rect.y = excl_rect_v1.y1; + pstate->excl_rect.w = excl_rect_v1.x2 - excl_rect_v1.x1; + pstate->excl_rect.h = excl_rect_v1.y2 - excl_rect_v1.y1; + + SDE_DEBUG_PLANE(psde, "excl_rect: {%d,%d,%d,%d}\n", + pstate->excl_rect.x, pstate->excl_rect.y, + pstate->excl_rect.w, pstate->excl_rect.h); +} + +static int sde_plane_atomic_set_property(struct drm_plane *plane, + struct drm_plane_state *state, struct drm_property *property, + uint64_t val) +{ + struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL; + struct sde_plane_state *pstate; + int idx, ret = -EINVAL; + + SDE_DEBUG_PLANE(psde, "\n"); + + if (!plane) { + SDE_ERROR("invalid plane\n"); + } else if (!state) { + SDE_ERROR_PLANE(psde, "invalid state\n"); + } else { + pstate = to_sde_plane_state(state); + ret = msm_property_atomic_set(&psde->property_info, + &pstate->property_state, property, val); + if (!ret) { + idx = msm_property_index(&psde->property_info, + property); + switch (idx) { + case PLANE_PROP_INPUT_FENCE: + _sde_plane_set_input_fence(psde, pstate, val); + break; + case PLANE_PROP_CSC_V1: + case PLANE_PROP_CSC_DMA_V1: + _sde_plane_set_csc_v1(psde, (void __user *)val); + break; + case PLANE_PROP_SCALER_V1: + _sde_plane_set_scaler_v1(psde, pstate, + (void *)(uintptr_t)val); + break; + case PLANE_PROP_SCALER_V2: + _sde_plane_set_scaler_v2(psde, pstate, + (void *)(uintptr_t)val); + break; + case PLANE_PROP_EXCL_RECT_V1: + _sde_plane_set_excl_rect_v1(psde, pstate, + (void *)(uintptr_t)val); + break; + default: + /* nothing to do */ + break; + } + } + } + + SDE_DEBUG_PLANE(psde, "%s[%d] <= 0x%llx ret=%d\n", + property->name, property->base.id, val, ret); + + return ret; +} + +static int sde_plane_atomic_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, uint64_t *val) +{ + struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL; + struct sde_plane_state *pstate; + int ret = -EINVAL; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + } else if (!state) { + SDE_ERROR("invalid state\n"); + } else { + SDE_DEBUG_PLANE(psde, "\n"); + pstate = to_sde_plane_state(state); + ret = msm_property_atomic_get(&psde->property_info, + &pstate->property_state, property, val); + } + + return ret; +} + +int sde_plane_helper_reset_custom_properties(struct drm_plane *plane, + struct drm_plane_state *plane_state) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + struct drm_property *drm_prop; + enum msm_mdp_plane_property prop_idx; + + if (!plane || !plane_state) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(plane_state); + + for (prop_idx = 0; prop_idx < PLANE_PROP_COUNT; prop_idx++) { + uint64_t val = pstate->property_values[prop_idx].value; + uint64_t def; + int ret; + + drm_prop = msm_property_index_to_drm_property( + &psde->property_info, prop_idx); + if (!drm_prop) { + /* not all props will be installed, based on caps */ + SDE_DEBUG_PLANE(psde, "invalid property index %d\n", + prop_idx); + continue; + } + + def = msm_property_get_default(&psde->property_info, prop_idx); + if (val == def) + continue; + + SDE_DEBUG_PLANE(psde, "set prop %s idx %d from %llu to %llu\n", + drm_prop->name, prop_idx, val, def); + + ret = sde_plane_atomic_set_property(plane, plane_state, + drm_prop, def); + if (ret) { + SDE_ERROR_PLANE(psde, + "set property failed, idx %d ret %d\n", + prop_idx, ret); + continue; + } + } + + return 0; +} + +static void sde_plane_destroy(struct drm_plane *plane) +{ + struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL; + + SDE_DEBUG_PLANE(psde, "\n"); + + if (psde) { + _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL); + + if (psde->blob_info) + drm_property_blob_put(psde->blob_info); + msm_property_destroy(&psde->property_info); + mutex_destroy(&psde->lock); + + drm_plane_helper_disable(plane, NULL); + + /* this will destroy the states as well */ + drm_plane_cleanup(plane); + + if (psde->pipe_hw) + sde_hw_sspp_destroy(psde->pipe_hw); + + kfree(psde); + } +} + +void sde_plane_destroy_fb(struct drm_plane_state *state) +{ + struct sde_plane_state *pstate; + + if (!state) { + SDE_ERROR("invalid arg state %d\n", !state); + return; + } + + pstate = to_sde_plane_state(state); + + if (sde_plane_get_property(pstate, PLANE_PROP_FB_TRANSLATION_MODE) == + SDE_DRM_FB_SEC) { + /* remove ref count for frame buffers */ + if (state->fb) { + drm_framebuffer_put(state->fb); + state->fb = NULL; + } + } + +} + +static void sde_plane_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + + if (!plane || !state) { + SDE_ERROR("invalid arg(s), plane %d state %d\n", + !plane, !state); + return; + } + + psde = to_sde_plane(plane); + pstate = to_sde_plane_state(state); + + SDE_DEBUG_PLANE(psde, "\n"); + + /* remove ref count for frame buffers */ + if (state->fb) + drm_framebuffer_put(state->fb); + + /* remove ref count for fence */ + if (pstate->input_fence) + sde_sync_put(pstate->input_fence); + + /* destroy value helper */ + msm_property_destroy_state(&psde->property_info, pstate, + &pstate->property_state); +} + +static struct drm_plane_state * +sde_plane_duplicate_state(struct drm_plane *plane) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + struct sde_plane_state *old_state; + struct drm_property *drm_prop; + uint64_t input_fence_default; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return NULL; + } else if (!plane->state) { + SDE_ERROR("invalid plane state\n"); + return NULL; + } + + old_state = to_sde_plane_state(plane->state); + psde = to_sde_plane(plane); + pstate = msm_property_alloc_state(&psde->property_info); + if (!pstate) { + SDE_ERROR_PLANE(psde, "failed to allocate state\n"); + return NULL; + } + + SDE_DEBUG_PLANE(psde, "\n"); + + /* duplicate value helper */ + msm_property_duplicate_state(&psde->property_info, old_state, pstate, + &pstate->property_state, pstate->property_values); + + /* clear out any input fence */ + pstate->input_fence = 0; + input_fence_default = msm_property_get_default( + &psde->property_info, PLANE_PROP_INPUT_FENCE); + drm_prop = msm_property_index_to_drm_property( + &psde->property_info, PLANE_PROP_INPUT_FENCE); + if (msm_property_atomic_set(&psde->property_info, + &pstate->property_state, drm_prop, + input_fence_default)) + SDE_DEBUG_PLANE(psde, + "error clearing duplicated input fence\n"); + + pstate->dirty = 0x0; + pstate->pending = false; + + __drm_atomic_helper_plane_duplicate_state(plane, &pstate->base); + + return &pstate->base; +} + +static void sde_plane_reset(struct drm_plane *plane) +{ + struct sde_plane *psde; + struct sde_plane_state *pstate; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return; + } + + psde = to_sde_plane(plane); + SDE_DEBUG_PLANE(psde, "\n"); + + if (plane->state && !sde_crtc_is_reset_required(plane->state->crtc)) { + SDE_DEBUG_PLANE(psde, "avoid reset for plane\n"); + return; + } + + /* remove previous state, if present */ + if (plane->state) { + sde_plane_destroy_state(plane, plane->state); + plane->state = 0; + } + + pstate = msm_property_alloc_state(&psde->property_info); + if (!pstate) { + SDE_ERROR_PLANE(psde, "failed to allocate state\n"); + return; + } + + /* reset value helper */ + msm_property_reset_state(&psde->property_info, pstate, + &pstate->property_state, + pstate->property_values); + + pstate->base.plane = plane; + + plane->state = &pstate->base; +} + +u32 sde_plane_get_ubwc_error(struct drm_plane *plane) +{ + u32 ubwc_error = 0; + struct sde_plane *psde; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return 0; + } + psde = to_sde_plane(plane); + + if (!psde->is_virtual && psde->pipe_hw->ops.get_ubwc_error) + ubwc_error = psde->pipe_hw->ops.get_ubwc_error(psde->pipe_hw); + + return ubwc_error; +} + +void sde_plane_clear_ubwc_error(struct drm_plane *plane) +{ + struct sde_plane *psde; + + if (!plane) { + SDE_ERROR("invalid plane\n"); + return; + } + psde = to_sde_plane(plane); + + if (psde->pipe_hw->ops.clear_ubwc_error) + psde->pipe_hw->ops.clear_ubwc_error(psde->pipe_hw); +} + +#ifdef CONFIG_DEBUG_FS +static ssize_t _sde_plane_danger_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct sde_kms *kms = file->private_data; + struct sde_mdss_cfg *cfg = kms->catalog; + int len = 0; + char buf[40] = {'\0'}; + + if (!cfg) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl); + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static void _sde_plane_set_danger_state(struct sde_kms *kms, bool enable) +{ + struct drm_plane *plane; + + drm_for_each_plane(plane, kms->dev) { + if (plane->fb && plane->state) { + sde_plane_danger_signal_ctrl(plane, enable); + SDE_DEBUG("plane:%d img:%dx%d ", + plane->base.id, plane->fb->width, + plane->fb->height); + SDE_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n", + plane->state->src_x >> 16, + plane->state->src_y >> 16, + plane->state->src_w >> 16, + plane->state->src_h >> 16, + plane->state->crtc_x, plane->state->crtc_y, + plane->state->crtc_w, plane->state->crtc_h); + } else { + SDE_DEBUG("Inactive plane:%d\n", plane->base.id); + } + } +} + +static ssize_t _sde_plane_danger_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_kms *kms = file->private_data; + struct sde_mdss_cfg *cfg = kms->catalog; + int disable_panic; + char buf[10]; + + if (!cfg) + return -EFAULT; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtoint(buf, 0, &disable_panic)) + return -EFAULT; + + if (disable_panic) { + /* Disable panic signal for all active pipes */ + SDE_DEBUG("Disabling danger:\n"); + _sde_plane_set_danger_state(kms, false); + kms->has_danger_ctrl = false; + } else { + /* Enable panic signal for all active pipes */ + SDE_DEBUG("Enabling danger:\n"); + kms->has_danger_ctrl = true; + _sde_plane_set_danger_state(kms, true); + } + + return count; +} + +static const struct file_operations sde_plane_danger_enable = { + .open = simple_open, + .read = _sde_plane_danger_read, + .write = _sde_plane_danger_write, +}; + +static int _sde_plane_init_debugfs(struct drm_plane *plane) +{ + struct sde_plane *psde; + struct sde_kms *kms; + struct msm_drm_private *priv; + const struct sde_sspp_sub_blks *sblk = 0; + const struct sde_sspp_cfg *cfg = 0; + + if (!plane || !plane->dev) { + SDE_ERROR("invalid arguments\n"); + return -EINVAL; + } + + priv = plane->dev->dev_private; + if (!priv || !priv->kms) { + SDE_ERROR("invalid KMS reference\n"); + return -EINVAL; + } + + kms = to_sde_kms(priv->kms); + psde = to_sde_plane(plane); + + if (psde && psde->pipe_hw) + cfg = psde->pipe_hw->cap; + if (cfg) + sblk = cfg->sblk; + + if (!sblk) + return 0; + + /* create overall sub-directory for the pipe */ + psde->debugfs_root = + debugfs_create_dir(psde->pipe_name, + plane->dev->primary->debugfs_root); + + if (!psde->debugfs_root) + return -ENOMEM; + + /* don't error check these */ + debugfs_create_x32("features", 0400, + psde->debugfs_root, &psde->features); + + if (cfg->features & BIT(SDE_SSPP_SCALER_QSEED3) || + cfg->features & BIT(SDE_SSPP_SCALER_QSEED3LITE) || + cfg->features & BIT(SDE_SSPP_SCALER_QSEED2)) + debugfs_create_bool("default_scaling", + 0600, + psde->debugfs_root, + &psde->debugfs_default_scale); + + if (cfg->features & BIT(SDE_SSPP_TRUE_INLINE_ROT)) { + debugfs_create_u32("in_rot_max_downscale_rt_num", + 0600, + psde->debugfs_root, + (u32 *) &psde->pipe_sblk->in_rot_maxdwnscale_rt_num); + debugfs_create_u32("in_rot_max_downscale_rt_denom", + 0600, + psde->debugfs_root, + (u32 *) &psde->pipe_sblk->in_rot_maxdwnscale_rt_denom); + debugfs_create_u32("in_rot_max_downscale_nrt", + 0600, + psde->debugfs_root, + (u32 *) &psde->pipe_sblk->in_rot_maxdwnscale_nrt); + debugfs_create_u32("in_rot_max_height", + 0600, + psde->debugfs_root, + (u32 *) &psde->pipe_sblk->in_rot_maxheight); + } + + debugfs_create_u32("xin_id", + 0400, + psde->debugfs_root, + (u32 *) &cfg->xin_id); + debugfs_create_x32("creq_vblank", + 0600, + psde->debugfs_root, + (u32 *) &sblk->creq_vblank); + debugfs_create_x32("danger_vblank", + 0600, + psde->debugfs_root, + (u32 *) &sblk->danger_vblank); + + debugfs_create_file("disable_danger", + 0600, + psde->debugfs_root, + kms, &sde_plane_danger_enable); + + return 0; +} + +static void _sde_plane_destroy_debugfs(struct drm_plane *plane) +{ + struct sde_plane *psde; + + if (!plane) + return; + psde = to_sde_plane(plane); + + debugfs_remove_recursive(psde->debugfs_root); +} +#else +static int _sde_plane_init_debugfs(struct drm_plane *plane) +{ + return 0; +} +static void _sde_plane_destroy_debugfs(struct drm_plane *plane) +{ +} +#endif + +static int sde_plane_late_register(struct drm_plane *plane) +{ + return _sde_plane_init_debugfs(plane); +} + +static void sde_plane_early_unregister(struct drm_plane *plane) +{ + _sde_plane_destroy_debugfs(plane); +} + +static const struct drm_plane_funcs sde_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sde_plane_destroy, + .atomic_set_property = sde_plane_atomic_set_property, + .atomic_get_property = sde_plane_atomic_get_property, + .reset = sde_plane_reset, + .atomic_duplicate_state = sde_plane_duplicate_state, + .atomic_destroy_state = sde_plane_destroy_state, + .late_register = sde_plane_late_register, + .early_unregister = sde_plane_early_unregister, +}; + +static const struct drm_plane_helper_funcs sde_plane_helper_funcs = { + .prepare_fb = sde_plane_prepare_fb, + .cleanup_fb = sde_plane_cleanup_fb, + .atomic_check = sde_plane_atomic_check, + .atomic_update = sde_plane_atomic_update, +}; + +enum sde_sspp sde_plane_pipe(struct drm_plane *plane) +{ + return plane ? to_sde_plane(plane)->pipe : SSPP_NONE; +} + +bool is_sde_plane_virtual(struct drm_plane *plane) +{ + return plane ? to_sde_plane(plane)->is_virtual : false; +} + +/* initialize plane */ +struct drm_plane *sde_plane_init(struct drm_device *dev, + uint32_t pipe, bool primary_plane, + unsigned long possible_crtcs, u32 master_plane_id) +{ + struct drm_plane *plane = NULL, *master_plane = NULL; + const struct sde_format_extended *format_list; + struct sde_plane *psde; + struct msm_drm_private *priv; + struct sde_kms *kms; + enum drm_plane_type type; + int ret = -EINVAL; + + if (!dev) { + SDE_ERROR("[%u]device is NULL\n", pipe); + goto exit; + } + + priv = dev->dev_private; + if (!priv) { + SDE_ERROR("[%u]private data is NULL\n", pipe); + goto exit; + } + + if (!priv->kms) { + SDE_ERROR("[%u]invalid KMS reference\n", pipe); + goto exit; + } + kms = to_sde_kms(priv->kms); + + if (!kms->catalog) { + SDE_ERROR("[%u]invalid catalog reference\n", pipe); + goto exit; + } + + /* create and zero local structure */ + psde = kzalloc(sizeof(*psde), GFP_KERNEL); + if (!psde) { + SDE_ERROR("[%u]failed to allocate local plane struct\n", pipe); + ret = -ENOMEM; + goto exit; + } + + /* cache local stuff for later */ + plane = &psde->base; + psde->pipe = pipe; + psde->is_virtual = (master_plane_id != 0); + INIT_LIST_HEAD(&psde->mplane_list); + master_plane = drm_plane_find(dev, NULL, master_plane_id); + if (master_plane) { + struct sde_plane *mpsde = to_sde_plane(master_plane); + + list_add_tail(&psde->mplane_list, &mpsde->mplane_list); + } + + /* initialize underlying h/w driver */ + psde->pipe_hw = sde_hw_sspp_init(pipe, kms->mmio, kms->catalog, + master_plane_id != 0); + if (IS_ERR(psde->pipe_hw)) { + SDE_ERROR("[%u]SSPP init failed\n", pipe); + ret = PTR_ERR(psde->pipe_hw); + goto clean_plane; + } else if (!psde->pipe_hw->cap || !psde->pipe_hw->cap->sblk) { + SDE_ERROR("[%u]SSPP init returned invalid cfg\n", pipe); + goto clean_sspp; + } + + /* cache features mask for later */ + psde->features = psde->pipe_hw->cap->features; + psde->perf_features = psde->pipe_hw->cap->perf_features; + psde->pipe_sblk = psde->pipe_hw->cap->sblk; + if (!psde->pipe_sblk) { + SDE_ERROR("[%u]invalid sblk\n", pipe); + goto clean_sspp; + } + + if (!master_plane_id) + format_list = psde->pipe_sblk->format_list; + else + format_list = psde->pipe_sblk->virt_format_list; + + psde->nformats = sde_populate_formats(format_list, + psde->formats, + 0, + ARRAY_SIZE(psde->formats)); + + if (!psde->nformats) { + SDE_ERROR("[%u]no valid formats for plane\n", pipe); + goto clean_sspp; + } + + if (psde->features & BIT(SDE_SSPP_CURSOR)) + type = DRM_PLANE_TYPE_CURSOR; + else if (primary_plane) + type = DRM_PLANE_TYPE_PRIMARY; + else + type = DRM_PLANE_TYPE_OVERLAY; + ret = drm_universal_plane_init(dev, plane, 0xff, &sde_plane_funcs, + psde->formats, psde->nformats, + NULL, type, NULL); + if (ret) + goto clean_sspp; + + /* Populate static array of plane property flags */ + _sde_plane_map_prop_to_dirty_bits(); + + /* success! finalize initialization */ + drm_plane_helper_add(plane, &sde_plane_helper_funcs); + + msm_property_init(&psde->property_info, &plane->base, dev, + priv->plane_property, psde->property_data, + PLANE_PROP_COUNT, PLANE_PROP_BLOBCOUNT, + sizeof(struct sde_plane_state)); + + _sde_plane_install_properties(plane, kms->catalog, master_plane_id); + + /* save user friendly pipe name for later */ + snprintf(psde->pipe_name, SDE_NAME_SIZE, "plane%u", plane->base.id); + + mutex_init(&psde->lock); + + SDE_DEBUG("%s created for pipe:%u id:%u virtual:%u\n", psde->pipe_name, + pipe, plane->base.id, master_plane_id); + return plane; + +clean_sspp: + if (psde && psde->pipe_hw) + sde_hw_sspp_destroy(psde->pipe_hw); +clean_plane: + kfree(psde); +exit: + return ERR_PTR(ret); +} diff --git a/techpack/display/msm/sde/sde_plane.h b/techpack/display/msm/sde/sde_plane.h new file mode 100644 index 0000000000000000000000000000000000000000..316bd75f47d95bdc11e4ef0b0d840f6ae6501200 --- /dev/null +++ b/techpack/display/msm/sde/sde_plane.h @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _SDE_PLANE_H_ +#define _SDE_PLANE_H_ + +#include <drm/drm_crtc.h> + +#include "msm_prop.h" +#include "sde_kms.h" +#include "sde_hw_mdss.h" +#include "sde_hw_sspp.h" + +/* dirty bits for update function */ +#define SDE_PLANE_DIRTY_RECTS 0x1 +#define SDE_PLANE_DIRTY_FORMAT 0x2 +#define SDE_PLANE_DIRTY_SHARPEN 0x4 +#define SDE_PLANE_DIRTY_PERF 0x8 +#define SDE_PLANE_DIRTY_FB_TRANSLATION_MODE 0x10 +#define SDE_PLANE_DIRTY_VIG_GAMUT 0x20 +#define SDE_PLANE_DIRTY_VIG_IGC 0x40 +#define SDE_PLANE_DIRTY_DMA_IGC 0x80 +#define SDE_PLANE_DIRTY_DMA_GC 0x100 +#define SDE_PLANE_DIRTY_CP (SDE_PLANE_DIRTY_VIG_GAMUT |\ + SDE_PLANE_DIRTY_VIG_IGC | SDE_PLANE_DIRTY_DMA_IGC |\ + SDE_PLANE_DIRTY_DMA_GC) +#define SDE_PLANE_DIRTY_ALL (0xFFFFFFFF & ~(SDE_PLANE_DIRTY_CP)) + +/** + * enum sde_plane_sclcheck_state - User scaler data status + * + * @SDE_PLANE_SCLCHECK_NONE: No user data provided + * @SDE_PLANE_SCLCHECK_INVALID: Invalid user data provided + * @SDE_PLANE_SCLCHECK_SCALER_V1: Valid scaler v1 data + * @SDE_PLANE_SCLCHECK_SCALER_V1_CHECK: Unchecked scaler v1 data + * @SDE_PLANE_SCLCHECK_SCALER_V2: Valid scaler v2 data + * @SDE_PLANE_SCLCHECK_SCALER_V2_CHECK: Unchecked scaler v2 data + */ +enum sde_plane_sclcheck_state { + SDE_PLANE_SCLCHECK_NONE, + SDE_PLANE_SCLCHECK_INVALID, + SDE_PLANE_SCLCHECK_SCALER_V1, + SDE_PLANE_SCLCHECK_SCALER_V1_CHECK, + SDE_PLANE_SCLCHECK_SCALER_V2, + SDE_PLANE_SCLCHECK_SCALER_V2_CHECK, +}; + +/** + * struct sde_plane_state: Define sde extension of drm plane state object + * @base: base drm plane state object + * @property_state: Local storage for msm_prop properties + * @property_values: cached plane property values + * @aspace: pointer to address space for input/output buffers + * @input_fence: dereferenced input fence pointer + * @stage: assigned by crtc blender + * @excl_rect: exclusion rect values + * @dirty: bitmask for which pipe h/w config functions need to be updated + * @multirect_index: index of the rectangle of SSPP + * @multirect_mode: parallel or time multiplex multirect mode + * @const_alpha_en: const alpha channel is enabled for this HW pipe + * @pending: whether the current update is still pending + * @defer_prepare_fb: indicate if prepare_fb call was deferred + * @pipe_order_flags: contains pipe order flags: + * SDE_SSPP_RIGHT - right pipe in source split pair + * @scaler3_cfg: configuration data for scaler3 + * @pixel_ext: configuration data for pixel extensions + * @scaler_check_state: indicates status of user provided pixel extension data + * @cdp_cfg: CDP configuration + */ +struct sde_plane_state { + struct drm_plane_state base; + struct msm_property_state property_state; + struct msm_property_value property_values[PLANE_PROP_COUNT]; + struct msm_gem_address_space *aspace; + void *input_fence; + enum sde_stage stage; + struct sde_rect excl_rect; + uint32_t dirty; + uint32_t multirect_index; + uint32_t multirect_mode; + bool const_alpha_en; + bool pending; + bool defer_prepare_fb; + uint32_t pipe_order_flags; + + /* scaler configuration */ + struct sde_hw_scaler3_cfg scaler3_cfg; + struct sde_hw_pixel_ext pixel_ext; + enum sde_plane_sclcheck_state scaler_check_state; + struct sde_hw_inline_pre_downscale_cfg pre_down; + + /* @sc_cfg: system_cache configuration */ + struct sde_hw_pipe_sc_cfg sc_cfg; + uint32_t rotation; + + struct sde_hw_pipe_cdp_cfg cdp_cfg; +}; + +/** + * struct sde_multirect_plane_states: Defines multirect pair of drm plane states + * @r0: drm plane configured on rect 0 + * @r1: drm plane configured on rect 1 + */ +struct sde_multirect_plane_states { + const struct drm_plane_state *r0; + const struct drm_plane_state *r1; +}; + +#define to_sde_plane_state(x) \ + container_of(x, struct sde_plane_state, base) + +/** + * sde_plane_get_property - Query integer value of plane property + * @S: Pointer to plane state + * @X: Property index, from enum msm_mdp_plane_property + * Returns: Integer value of requested property + */ +#define sde_plane_get_property(S, X) ((S) && ((X) < PLANE_PROP_COUNT) ? \ + ((S)->property_values[(X)].value) : 0) + +/** + * sde_plane_destroy_fb - destroy fb object and clear fb + * @state: old plane state + */ +void sde_plane_destroy_fb(struct drm_plane_state *state); + +/** + * sde_plane_pipe - return sspp identifier for the given plane + * @plane: Pointer to DRM plane object + * Returns: sspp identifier of the given plane + */ +enum sde_sspp sde_plane_pipe(struct drm_plane *plane); + +/** + * is_sde_plane_virtual - check for virtual plane + * @plane: Pointer to DRM plane object + * returns: true - if the plane is virtual + * false - if the plane is primary + */ +bool is_sde_plane_virtual(struct drm_plane *plane); + +/** + * sde_plane_ctl_flush - set/clear control flush mask + * @plane: Pointer to DRM plane object + * @ctl: Pointer to control hardware + * @set: set if true else clear + */ +void sde_plane_ctl_flush(struct drm_plane *plane, struct sde_hw_ctl *ctl, + bool set); + +/** + * sde_plane_restore - restore hw state if previously power collapsed + * @plane: Pointer to drm plane structure + */ +void sde_plane_restore(struct drm_plane *plane); + +/** + * sde_plane_flush - final plane operations before commit flush + * @plane: Pointer to drm plane structure + */ +void sde_plane_flush(struct drm_plane *plane); + +/** + * sde_plane_halt_requests - control halting of vbif transactions for this plane + * This function isn't thread safe. Plane halt enable/disable requests + * should always be made from the same commit cycle. + * @plane: Pointer to drm plane structure + * @enable: Whether to enable/disable halting of vbif transactions + */ +void sde_plane_halt_requests(struct drm_plane *plane, bool enable); + +/** + * sde_plane_set_error: enable/disable error condition + * @plane: pointer to drm_plane structure + */ +void sde_plane_set_error(struct drm_plane *plane, bool error); + +/** + * sde_plane_init - create new sde plane for the given pipe + * @dev: Pointer to DRM device + * @pipe: sde hardware pipe identifier + * @primary_plane: true if this pipe is primary plane for crtc + * @possible_crtcs: bitmask of crtc that can be attached to the given pipe + * @master_plane_id: primary plane id of a multirect pipe. 0 value passed for + * a regular plane initialization. A non-zero primary plane + * id will be passed for a virtual pipe initialization. + * + */ +struct drm_plane *sde_plane_init(struct drm_device *dev, + uint32_t pipe, bool primary_plane, + unsigned long possible_crtcs, u32 master_plane_id); + +/** + * sde_plane_validate_multirecti_v2 - validate the multirect planes + * against hw limitations + * @plane: drm plate states of the multirect pair + */ +int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane); + +/** + * sde_plane_clear_multirect - clear multirect bits for the given pipe + * @drm_state: Pointer to DRM plane state + */ +void sde_plane_clear_multirect(const struct drm_plane_state *drm_state); + +/** + * sde_plane_validate_src_addr - validate if current sspp addr of given + * plane is within the input address range + * @drm_plane: Pointer to DRM plane object + * @base_addr: Start address of the input address range + * @size: Size of the input address range + * @Return: Non-zero if source pipe current address is not in input range + */ +int sde_plane_validate_src_addr(struct drm_plane *plane, + unsigned long base_addr, u32 size); + +/** + * sde_plane_wait_input_fence - wait for input fence object + * @plane: Pointer to DRM plane object + * @wait_ms: Wait timeout value + * Returns: Zero on success + */ +int sde_plane_wait_input_fence(struct drm_plane *plane, uint32_t wait_ms); + +/** + * sde_plane_color_fill - enables color fill on plane + * @plane: Pointer to DRM plane object + * @color: RGB fill color value, [23..16] Blue, [15..8] Green, [7..0] Red + * @alpha: 8-bit fill alpha value, 255 selects 100% alpha + * Returns: 0 on success + */ +int sde_plane_color_fill(struct drm_plane *plane, + uint32_t color, uint32_t alpha); + +/** + * sde_plane_set_revalidate - sets revalidate flag which forces a full + * validation of the plane properties in the next atomic check + * @plane: Pointer to DRM plane object + * @enable: Boolean to set/unset the flag + */ +void sde_plane_set_revalidate(struct drm_plane *plane, bool enable); + +/** + * sde_plane_helper_reset_properties - reset properties to default values in the + * given DRM plane state object + * @plane: Pointer to DRM plane object + * @plane_state: Pointer to DRM plane state object + * Returns: 0 on success, negative errno on failure + */ +int sde_plane_helper_reset_custom_properties(struct drm_plane *plane, + struct drm_plane_state *plane_state); + +/* sde_plane_is_sec_ui_allowed - indicates if the sspp allows secure-ui layers + * @plane: Pointer to DRM plane object + * Returns: true if allowed; false otherwise + */ +bool sde_plane_is_sec_ui_allowed(struct drm_plane *plane); + +/* sde_plane_secure_ctrl_xin_client - controls the VBIF programming of + * the xin-client before the secure-ui session. Programs the QOS + * and OT limits in VBIF for the sec-ui allowed xins + * @plane: Pointer to DRM plane object + * @crtc: Pointer to DRM CRTC state object + */ +void sde_plane_secure_ctrl_xin_client(struct drm_plane *plane, + struct drm_crtc *crtc); + +/* + * sde_plane_get_ubwc_error - gets the ubwc error code + * @plane: Pointer to DRM plane object + */ +u32 sde_plane_get_ubwc_error(struct drm_plane *plane); + +/* + * sde_plane_clear_ubwc_error - clears the ubwc error code + * @plane: Pointer to DRM plane object + */ +void sde_plane_clear_ubwc_error(struct drm_plane *plane); + +/* + * sde_plane_setup_src_split_order - enable/disable pipe's src_split_order + * @plane: Pointer to DRM plane object + * @rect_mode: multirect mode + * @enable: enable/disable flag + */ +void sde_plane_setup_src_split_order(struct drm_plane *plane, + enum sde_sspp_multirect_index rect_mode, bool enable); + +/* sde_plane_is_cache_required - indicates if the system cache is + * required for the plane. + * @plane: Pointer to DRM plane object + * Returns: true if sys cache is required, otherwise false. + */ +bool sde_plane_is_cache_required(struct drm_plane *plane); + +#endif /* _SDE_PLANE_H_ */ diff --git a/techpack/display/msm/sde/sde_reg_dma.c b/techpack/display/msm/sde/sde_reg_dma.c new file mode 100644 index 0000000000000000000000000000000000000000..cd8568d606b09cea780c3a6a5f113fcbdcf8c3e5 --- /dev/null +++ b/techpack/display/msm/sde/sde_reg_dma.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ +#include "sde_reg_dma.h" +#include "sde_hw_reg_dma_v1.h" +#include "sde_dbg.h" + +#define REG_DMA_VER_1_0 0x00010000 +#define REG_DMA_VER_1_1 0x00010001 +#define REG_DMA_VER_1_2 0x00010002 + +static int default_check_support(enum sde_reg_dma_features feature, + enum sde_reg_dma_blk blk, + bool *is_supported) +{ + + if (!is_supported) + return -EINVAL; + + *is_supported = false; + return 0; +} + +static int default_setup_payload(struct sde_reg_dma_setup_ops_cfg *cfg) +{ + DRM_ERROR("not implemented\n"); + return -EINVAL; +} + +static int default_kick_off(struct sde_reg_dma_kickoff_cfg *cfg) +{ + DRM_ERROR("not implemented\n"); + return -EINVAL; + +} + +static int default_reset(struct sde_hw_ctl *ctl) +{ + DRM_ERROR("not implemented\n"); + return -EINVAL; +} + +struct sde_reg_dma_buffer *default_alloc_reg_dma_buf(u32 size) +{ + DRM_ERROR("not implemented\n"); + return ERR_PTR(-EINVAL); +} + +int default_dealloc_reg_dma(struct sde_reg_dma_buffer *lut_buf) +{ + DRM_ERROR("not implemented\n"); + return -EINVAL; +} + +static int default_buf_reset_reg_dma(struct sde_reg_dma_buffer *lut_buf) +{ + DRM_ERROR("not implemented\n"); + return -EINVAL; +} + +static int default_last_command(struct sde_hw_ctl *ctl, + enum sde_reg_dma_queue q, enum sde_reg_dma_last_cmd_mode mode) +{ + return 0; +} + +static void default_dump_reg(void) +{ +} + +static struct sde_hw_reg_dma reg_dma = { + .ops = {default_check_support, default_setup_payload, + default_kick_off, default_reset, default_alloc_reg_dma_buf, + default_dealloc_reg_dma, default_buf_reset_reg_dma, + default_last_command, default_dump_reg}, +}; + +int sde_reg_dma_init(void __iomem *addr, struct sde_mdss_cfg *m, + struct drm_device *dev) +{ + int rc = 0; + + if (!addr || !m || !dev) { + DRM_DEBUG("invalid addr %pK catalog %pK dev %pK\n", addr, m, + dev); + return 0; + } + + reg_dma.drm_dev = dev; + reg_dma.caps = &m->dma_cfg; + reg_dma.addr = addr; + + if (!m->reg_dma_count) + return 0; + + switch (reg_dma.caps->version) { + case REG_DMA_VER_1_0: + rc = init_v1(®_dma); + if (rc) + DRM_DEBUG("init v1 dma ops failed\n"); + break; + case REG_DMA_VER_1_1: + rc = init_v11(®_dma); + if (rc) + DRM_DEBUG("init v11 dma ops failed\n"); + break; + case REG_DMA_VER_1_2: + rc = init_v12(®_dma); + if (rc) + DRM_DEBUG("init v11 dma ops failed\n"); + break; + default: + break; + } + + return 0; +} + +struct sde_hw_reg_dma_ops *sde_reg_dma_get_ops(void) +{ + return ®_dma.ops; +} + +void sde_reg_dma_deinit(void) +{ + struct sde_hw_reg_dma op = { + .ops = {default_check_support, default_setup_payload, + default_kick_off, default_reset, default_alloc_reg_dma_buf, + default_dealloc_reg_dma, default_buf_reset_reg_dma, + default_last_command, default_dump_reg}, + }; + + if (!reg_dma.drm_dev || !reg_dma.caps) + return; + + switch (reg_dma.caps->version) { + case REG_DMA_VER_1_0: + deinit_v1(); + break; + case REG_DMA_VER_1_1: + case REG_DMA_VER_1_2: + deinit_v1(); + break; + default: + break; + } + memset(®_dma, 0, sizeof(reg_dma)); + memcpy(®_dma.ops, &op.ops, sizeof(op.ops)); +} diff --git a/techpack/display/msm/sde/sde_reg_dma.h b/techpack/display/msm/sde/sde_reg_dma.h new file mode 100644 index 0000000000000000000000000000000000000000..1454e41457b32eeb8b38710efc1539839ca16d99 --- /dev/null +++ b/techpack/display/msm/sde/sde_reg_dma.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_REG_DMA_H +#define _SDE_REG_DMA_H + +#include "msm_drv.h" +#include "sde_hw_catalog.h" +#include "sde_hw_mdss.h" +#include "sde_hw_top.h" +#include "sde_hw_util.h" + +/** + * enum sde_reg_dma_op - defines operations supported by reg dma + * @REG_DMA_READ: Read the histogram into buffer provided + * @REG_DMA_WRITE: Write the reg dma configuration into MDP block + * @REG_DMA_OP_MAX: Max operation which indicates that op is invalid + */ +enum sde_reg_dma_op { + REG_DMA_READ, + REG_DMA_WRITE, + REG_DMA_OP_MAX +}; + +/** + * enum sde_reg_dma_read_sel - defines the blocks for histogram read + * @DSPP0_HIST: select dspp0 + * @DSPP1_HIST: select dspp1 + * @DSPP2_HIST: select dspp2 + * @DSPP3_HIST: select dspp3 + * @DSPP_HIST_MAX: invalid selection + */ +enum sde_reg_dma_read_sel { + DSPP0_HIST, + DSPP1_HIST, + DSPP2_HIST, + DSPP3_HIST, + DSPP_HIST_MAX, +}; + +/** + * enum sde_reg_dma_features - defines features supported by reg dma + * @QSEED: qseed feature + * @GAMUT: gamut feature + * @IGC: inverse gamma correction + * @PCC: polynomical color correction + * @VLUT: PA vlut + * @MEMC_SKIN: memory color skin + * @MEMC_SKY: memory color sky + * @MEMC_FOLIAGE: memory color foliage + * @MEMC_PROT: memory color protect + * @SIX_ZONE: six zone + * @HSIC: Hue, saturation and contrast + * @GC: gamma correction + * @LTM_INIT: LTM INIT + * @LTM_ROI: LTM ROI + * @LTM_VLUT: LTM VLUT + * @REG_DMA_FEATURES_MAX: invalid selection + */ +enum sde_reg_dma_features { + QSEED, + GAMUT, + IGC, + PCC, + VLUT, + MEMC_SKIN, + MEMC_SKY, + MEMC_FOLIAGE, + MEMC_PROT, + SIX_ZONE, + HSIC, + GC, + LTM_INIT, + LTM_ROI, + LTM_VLUT, + REG_DMA_FEATURES_MAX, +}; + +/** + * enum sde_reg_dma_queue - defines reg dma write queue values + * @DMA_CTL_QUEUE0: select queue0 + * @DMA_CTL_QUEUE1: select queue1 + * @DMA_CTL_QUEUE_MAX: invalid selection + */ +enum sde_reg_dma_queue { + DMA_CTL_QUEUE0, + DMA_CTL_QUEUE1, + DMA_CTL_QUEUE_MAX, +}; + +/** + * enum sde_reg_dma_trigger_mode - defines reg dma ops trigger mode + * @WRITE_IMMEDIATE: trigger write op immediately + * @WRITE_TRIGGER: trigger write op when sw trigger is issued + * @READ_IMMEDIATE: trigger read op immediately + * @READ_TRIGGER: trigger read op when sw trigger is issued + * @TIGGER_MAX: invalid trigger selection + */ +enum sde_reg_dma_trigger_mode { + WRITE_IMMEDIATE, + WRITE_TRIGGER, + READ_IMMEDIATE, + READ_TRIGGER, + TIGGER_MAX, +}; + +/** + * enum sde_reg_dma_setup_ops - defines reg dma write configuration + * @HW_BLK_SELECT: op for selecting the hardware block + * @REG_SINGLE_WRITE: op for writing single register value + * at the address provided + * @REG_BLK_WRITE_SINGLE: op for writing multiple registers using auto address + * increment + * @REG_BLK_WRITE_INC: op for writing multiple registers using hw index + * register + * @REG_BLK_WRITE_MULTIPLE: op for writing hw index based registers at + * non-consecutive location + * @REG_SINGLE_MODIFY: op for modifying single register value + * with bitmask at the address provided + * @REG_DMA_SETUP_OPS_MAX: invalid operation + */ +enum sde_reg_dma_setup_ops { + HW_BLK_SELECT, + REG_SINGLE_WRITE, + REG_BLK_WRITE_SINGLE, + REG_BLK_WRITE_INC, + REG_BLK_WRITE_MULTIPLE, + REG_SINGLE_MODIFY, + REG_DMA_SETUP_OPS_MAX, +}; + +/** + * enum sde_reg_dma_blk - defines blocks for which reg dma op should be + * performed + * @VIG0: select vig0 block + * @VIG1: select vig1 block + * @VIG2: select vig2 block + * @VIG3: select vig3 block + * @LM0: select lm0 block + * @LM1: select lm1 block + * @LM2: select lm2 block + * @LM3: select lm3 block + * @DSPP0: select dspp0 block + * @DSPP1: select dspp1 block + * @DSPP2: select dspp2 block + * @DSPP3: select dspp3 block + * @DMA0: select dma0 block + * @DMA1: select dma1 block + * @DMA2: select dma2 block + * @DMA3: select dma3 block + * @SSPP_IGC: select sspp igc block + * @DSPP_IGC: select dspp igc block + * @LTM0: select LTM0 block + * @LTM1: select LTM1 block + * @MDSS: select mdss block + */ +enum sde_reg_dma_blk { + VIG0 = BIT(0), + VIG1 = BIT(1), + VIG2 = BIT(2), + VIG3 = BIT(3), + LM0 = BIT(4), + LM1 = BIT(5), + LM2 = BIT(6), + LM3 = BIT(7), + DSPP0 = BIT(8), + DSPP1 = BIT(9), + DSPP2 = BIT(10), + DSPP3 = BIT(11), + DMA0 = BIT(12), + DMA1 = BIT(13), + DMA2 = BIT(14), + DMA3 = BIT(15), + SSPP_IGC = BIT(16), + DSPP_IGC = BIT(17), + LTM0 = BIT(18), + LTM1 = BIT(19), + MDSS = BIT(31) +}; + +/** + * enum sde_reg_dma_last_cmd_mode - defines enums for kick off mode. + * @REG_DMA_WAIT4_COMP: last_command api will wait for max of 1 msec allowing + * reg dma trigger to complete. + * @REG_DMA_NOWAIT: last_command api will not wait for reg dma trigger + * completion. + */ +enum sde_reg_dma_last_cmd_mode { + REG_DMA_WAIT4_COMP, + REG_DMA_NOWAIT, +}; + +/** + * struct sde_reg_dma_buffer - defines reg dma buffer structure. + * @drm_gem_object *buf: drm gem handle for the buffer + * @asapce : pointer to address space + * @buffer_size: buffer size + * @index: write pointer index + * @iova: device address + * @vaddr: cpu address + * @next_op_allowed: operation allowed on the buffer + * @ops_completed: operations completed on buffer + */ +struct sde_reg_dma_buffer { + struct drm_gem_object *buf; + struct msm_gem_address_space *aspace; + u32 buffer_size; + u32 index; + u64 iova; + void *vaddr; + u32 next_op_allowed; + u32 ops_completed; +}; + +/** + * struct sde_reg_dma_setup_ops_cfg - defines structure for reg dma ops on the + * reg dma buffer. + * @sde_reg_dma_setup_ops ops: ops to be performed + * @sde_reg_dma_blk blk: block on which op needs to be performed + * @sde_reg_dma_features feature: feature on which op needs to be done + * @wrap_size: valid for REG_BLK_WRITE_MULTIPLE, indicates reg index location + * size + * @inc: valid for REG_BLK_WRITE_MULTIPLE indicates whether reg index location + * needs an increment or decrement. + * 0 - decrement + * 1 - increment + * @blk_offset: offset for blk, valid for HW_BLK_SELECT op only + * @sde_reg_dma_buffer *dma_buf: reg dma buffer on which op needs to be + * performed + * @data: pointer to payload which has to be written into reg dma buffer for + * selected op. + * @data_size: size of payload in data + */ +struct sde_reg_dma_setup_ops_cfg { + enum sde_reg_dma_setup_ops ops; + enum sde_reg_dma_blk blk; + enum sde_reg_dma_features feature; + u32 wrap_size; + u32 inc; + u32 blk_offset; + struct sde_reg_dma_buffer *dma_buf; + u32 *data; + u32 mask; + u32 data_size; +}; + +/** + * struct sde_reg_dma_kickoff_cfg - commit reg dma buffer to hw engine + * @ctl: ctl for which reg dma buffer needs to be committed. + * @dma_buf: reg dma buffer with iova address and size info + * @block_select: histogram read select + * @trigger_mode: reg dma ops trigger mode + * @queue_select: queue on which reg dma buffer will be submitted + * @last_command: last command for this vsync + */ +struct sde_reg_dma_kickoff_cfg { + struct sde_hw_ctl *ctl; + enum sde_reg_dma_op op; + struct sde_reg_dma_buffer *dma_buf; + enum sde_reg_dma_read_sel block_select; + enum sde_reg_dma_trigger_mode trigger_mode; + enum sde_reg_dma_queue queue_select; + u32 last_command; +}; + +/** + * struct sde_hw_reg_dma_ops - ops supported by reg dma frame work, based on + * version of reg dma appropriate ops will be + * installed during driver probe. + * @check_support: checks if reg dma is supported on this platform for a + * feature + * @setup_payload: setup reg dma buffer based on ops and payload provided by + * client + * @kick_off: submit the reg dma buffer to hw enginge + * @reset: reset the reg dma hw enginge for a ctl + * @alloc_reg_dma_buf: allocate reg dma buffer + * @dealloc_reg_dma: de-allocate reg dma buffer + * @reset_reg_dma_buf: reset the buffer to init state + * @last_command: notify control that last command is queued + * @dump_regs: dump reg dma registers + */ +struct sde_hw_reg_dma_ops { + int (*check_support)(enum sde_reg_dma_features feature, + enum sde_reg_dma_blk blk, + bool *is_supported); + int (*setup_payload)(struct sde_reg_dma_setup_ops_cfg *cfg); + int (*kick_off)(struct sde_reg_dma_kickoff_cfg *cfg); + int (*reset)(struct sde_hw_ctl *ctl); + struct sde_reg_dma_buffer* (*alloc_reg_dma_buf)(u32 size); + int (*dealloc_reg_dma)(struct sde_reg_dma_buffer *lut_buf); + int (*reset_reg_dma_buf)(struct sde_reg_dma_buffer *buf); + int (*last_command)(struct sde_hw_ctl *ctl, enum sde_reg_dma_queue q, + enum sde_reg_dma_last_cmd_mode mode); + void (*dump_regs)(void); +}; + +/** + * struct sde_hw_reg_dma - structure to hold reg dma hw info + * @drm_dev: drm driver dev handle + * @caps: reg dma hw caps on the platform + * @ops: reg dma ops supported on the platform + * @addr: reg dma hw block base address + */ +struct sde_hw_reg_dma { + struct drm_device *drm_dev; + const struct sde_reg_dma_cfg *caps; + struct sde_hw_reg_dma_ops ops; + void __iomem *addr; +}; + +/** + * sde_reg_dma_init() - function called to initialize reg dma during sde + * drm driver probe. If reg dma is supported by sde + * ops for reg dma version will be installed. + * if reg dma is not supported by sde default ops will + * be installed. check_support of default ops will + * return false, hence the clients should fall back to + * AHB programming. + * @addr: reg dma block base address + * @m: catalog which contains sde hw capabilities and offsets + * @dev: drm driver device handle + */ +int sde_reg_dma_init(void __iomem *addr, struct sde_mdss_cfg *m, + struct drm_device *dev); + +/** + * sde_reg_dma_get_ops() - singleton module, ops is returned to the clients + * who call this api. + */ +struct sde_hw_reg_dma_ops *sde_reg_dma_get_ops(void); + +/** + * sde_reg_dma_deinit() - de-initialize the reg dma + */ +void sde_reg_dma_deinit(void); +#endif /* _SDE_REG_DMA_H */ diff --git a/techpack/display/msm/sde/sde_rm.c b/techpack/display/msm/sde/sde_rm.c new file mode 100644 index 0000000000000000000000000000000000000000..7f3716b8bf287a50113e221a1d8e6e4c3f92966e --- /dev/null +++ b/techpack/display/msm/sde/sde_rm.c @@ -0,0 +1,2370 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s] " fmt, __func__ +#include "sde_kms.h" +#include "sde_hw_lm.h" +#include "sde_hw_ctl.h" +#include "sde_hw_cdm.h" +#include "sde_hw_dspp.h" +#include "sde_hw_ds.h" +#include "sde_hw_pingpong.h" +#include "sde_hw_intf.h" +#include "sde_hw_wb.h" +#include "sde_encoder.h" +#include "sde_connector.h" +#include "sde_hw_dsc.h" +#include "sde_crtc.h" +#include "sde_hw_qdss.h" + +#define RESERVED_BY_OTHER(h, r) \ + (((h)->rsvp && ((h)->rsvp->enc_id != (r)->enc_id)) ||\ + ((h)->rsvp_nxt && ((h)->rsvp_nxt->enc_id != (r)->enc_id))) + +#define RM_RQ_LOCK(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_RESERVE_LOCK)) +#define RM_RQ_CLEAR(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_RESERVE_CLEAR)) +#define RM_RQ_DSPP(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DSPP)) +#define RM_RQ_DS(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DS)) +#define RM_RQ_CWB(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_CWB)) +#define RM_IS_TOPOLOGY_MATCH(t, r) ((t).num_lm == (r).num_lm && \ + (t).num_comp_enc == (r).num_enc && \ + (t).num_intf == (r).num_intf) +#define IS_COMPATIBLE_PP_DSC(p, d) (p % 2 == d % 2) + +/* ~one vsync poll time for rsvp_nxt to cleared by modeset from commit thread */ +#define RM_NXT_CLEAR_POLL_TIMEOUT_US 16600 + +/** + * toplogy information to be used when ctl path version does not + * support driving more than one interface per ctl_path + */ +static const struct sde_rm_topology_def g_top_table[] = { + { SDE_RM_TOPOLOGY_NONE, 0, 0, 0, 0, false }, + { SDE_RM_TOPOLOGY_SINGLEPIPE, 1, 0, 1, 1, false }, + { SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, 1, 1, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE, 2, 0, 2, 2, true }, + { SDE_RM_TOPOLOGY_DUALPIPE_DSC, 2, 2, 2, 2, true }, + { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, 2, 0, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, 2, 1, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, 2, 2, 1, 1, false }, + { SDE_RM_TOPOLOGY_PPSPLIT, 1, 0, 2, 1, true }, +}; + +/** + * topology information to be used when the ctl path version + * is SDE_CTL_CFG_VERSION_1_0_0 + */ +static const struct sde_rm_topology_def g_ctl_ver_1_top_table[] = { + { SDE_RM_TOPOLOGY_NONE, 0, 0, 0, 0, false }, + { SDE_RM_TOPOLOGY_SINGLEPIPE, 1, 0, 1, 1, false }, + { SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, 1, 1, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE, 2, 0, 2, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_DSC, 2, 2, 2, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, 2, 0, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, 2, 1, 1, 1, false }, + { SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, 2, 2, 1, 1, false }, + { SDE_RM_TOPOLOGY_PPSPLIT, 1, 0, 2, 1, false }, +}; + + +/** + * struct sde_rm_requirements - Reservation requirements parameter bundle + * @top_ctrl: topology control preference from kernel client + * @top: selected topology for the display + * @hw_res: Hardware resources required as reported by the encoders + */ +struct sde_rm_requirements { + uint64_t top_ctrl; + const struct sde_rm_topology_def *topology; + struct sde_encoder_hw_resources hw_res; +}; + +/** + * struct sde_rm_rsvp - Use Case Reservation tagging structure + * Used to tag HW blocks as reserved by a CRTC->Encoder->Connector chain + * By using as a tag, rather than lists of pointers to HW blocks used + * we can avoid some list management since we don't know how many blocks + * of each type a given use case may require. + * @list: List head for list of all reservations + * @seq: Global RSVP sequence number for debugging, especially for + * differentiating differenct allocations for same encoder. + * @enc_id: Reservations are tracked by Encoder DRM object ID. + * CRTCs may be connected to multiple Encoders. + * An encoder or connector id identifies the display path. + * @topology DRM<->HW topology use case + */ +struct sde_rm_rsvp { + struct list_head list; + uint32_t seq; + uint32_t enc_id; + enum sde_rm_topology_name topology; +}; + +/** + * struct sde_rm_hw_blk - hardware block tracking list member + * @list: List head for list of all hardware blocks tracking items + * @rsvp: Pointer to use case reservation if reserved by a client + * @rsvp_nxt: Temporary pointer used during reservation to the incoming + * request. Will be swapped into rsvp if proposal is accepted + * @type: Type of hardware block this structure tracks + * @id: Hardware ID number, within it's own space, ie. LM_X + * @catalog: Pointer to the hardware catalog entry for this block + * @hw: Pointer to the hardware register access object for this block + */ +struct sde_rm_hw_blk { + struct list_head list; + struct sde_rm_rsvp *rsvp; + struct sde_rm_rsvp *rsvp_nxt; + enum sde_hw_blk_type type; + uint32_t id; + struct sde_hw_blk *hw; +}; + +/** + * sde_rm_dbg_rsvp_stage - enum of steps in making reservation for event logging + */ +enum sde_rm_dbg_rsvp_stage { + SDE_RM_STAGE_BEGIN, + SDE_RM_STAGE_AFTER_CLEAR, + SDE_RM_STAGE_AFTER_RSVPNEXT, + SDE_RM_STAGE_FINAL +}; + +static void _sde_rm_inc_resource_info_lm(struct sde_rm *rm, + struct msm_resource_caps_info *avail_res, + struct sde_rm_hw_blk *blk) +{ + struct sde_rm_hw_blk *blk2; + const struct sde_lm_cfg *lm_cfg, *lm_cfg2; + + avail_res->num_lm++; + + lm_cfg = to_sde_hw_mixer(blk->hw)->cap; + /* Check for 3d muxes by comparing paired lms */ + list_for_each_entry(blk2, &rm->hw_blks[SDE_HW_BLK_LM], list) { + lm_cfg2 = to_sde_hw_mixer(blk2->hw)->cap; + /* + * If lm2 is free, or + * lm1 & lm2 reserved by same enc, check mask + */ + if ((!blk2->rsvp || (blk->rsvp && + blk2->rsvp->enc_id == blk->rsvp->enc_id + && lm_cfg->id > lm_cfg2->id)) && + test_bit(lm_cfg->id, &lm_cfg2->lm_pair_mask)) + avail_res->num_3dmux++; + } +} + +static void _sde_rm_dec_resource_info_lm(struct sde_rm *rm, + struct msm_resource_caps_info *avail_res, + struct sde_rm_hw_blk *blk) +{ + struct sde_rm_hw_blk *blk2; + const struct sde_lm_cfg *lm_cfg, *lm_cfg2; + + avail_res->num_lm--; + + lm_cfg = to_sde_hw_mixer(blk->hw)->cap; + /* Check for 3d muxes by comparing paired lms */ + list_for_each_entry(blk2, &rm->hw_blks[SDE_HW_BLK_LM], list) { + lm_cfg2 = to_sde_hw_mixer(blk2->hw)->cap; + /* If lm2 is free and lm1 is now being reserved */ + if (!blk2->rsvp && + test_bit(lm_cfg->id, &lm_cfg2->lm_pair_mask)) + avail_res->num_3dmux--; + } +} + +static void _sde_rm_inc_resource_info(struct sde_rm *rm, + struct msm_resource_caps_info *avail_res, + struct sde_rm_hw_blk *blk) +{ + enum sde_hw_blk_type type = blk->type; + + if (type == SDE_HW_BLK_LM) + _sde_rm_inc_resource_info_lm(rm, avail_res, blk); + else if (type == SDE_HW_BLK_CTL) + avail_res->num_ctl++; + else if (type == SDE_HW_BLK_DSC) + avail_res->num_dsc++; +} + +static void _sde_rm_dec_resource_info(struct sde_rm *rm, + struct msm_resource_caps_info *avail_res, + struct sde_rm_hw_blk *blk) +{ + enum sde_hw_blk_type type = blk->type; + + if (type == SDE_HW_BLK_LM) + _sde_rm_dec_resource_info_lm(rm, avail_res, blk); + else if (type == SDE_HW_BLK_CTL) + avail_res->num_ctl--; + else if (type == SDE_HW_BLK_DSC) + avail_res->num_dsc--; +} + +void sde_rm_get_resource_info(struct sde_rm *rm, + struct drm_encoder *drm_enc, + struct msm_resource_caps_info *avail_res, + int display_type) +{ + struct sde_rm_hw_blk *blk; + enum sde_hw_blk_type type; + struct sde_rm_rsvp rsvp; + const struct sde_lm_cfg *lm_cfg; + + mutex_lock(&rm->rm_lock); + memcpy(avail_res, &rm->avail_res, + sizeof(rm->avail_res)); + + /** + * Layer Mixers which are primary display, secondary + * display preferred and are available must not be provided + * for connectors which are neither primary nor secondary. + */ + if (display_type != SDE_CONNECTOR_PRIMARY && + display_type != SDE_CONNECTOR_SECONDARY) { + list_for_each_entry(blk, &rm->hw_blks[SDE_HW_BLK_LM], list) { + lm_cfg = to_sde_hw_mixer(blk->hw)->cap; + if (!blk->rsvp && (lm_cfg->features & + (BIT(SDE_DISP_PRIMARY_PREF) + | BIT(SDE_DISP_SECONDARY_PREF)))) + avail_res->num_lm--; + } + } + + if (!drm_enc) + goto end; + + rsvp.enc_id = drm_enc->base.id; + + for (type = 0; type < SDE_HW_BLK_MAX; type++) + list_for_each_entry(blk, &rm->hw_blks[type], list) + if (blk->rsvp && blk->rsvp->enc_id == rsvp.enc_id) + _sde_rm_inc_resource_info(rm, avail_res, blk); +end: + mutex_unlock(&rm->rm_lock); + return; +} + +static void _sde_rm_print_rsvps( + struct sde_rm *rm, + enum sde_rm_dbg_rsvp_stage stage) +{ + struct sde_rm_rsvp *rsvp; + struct sde_rm_hw_blk *blk; + enum sde_hw_blk_type type; + + SDE_DEBUG("%d\n", stage); + + list_for_each_entry(rsvp, &rm->rsvps, list) { + SDE_DEBUG("%d rsvp[s%ue%u] topology %d\n", stage, rsvp->seq, + rsvp->enc_id, rsvp->topology); + SDE_EVT32(stage, rsvp->seq, rsvp->enc_id, rsvp->topology); + } + + for (type = 0; type < SDE_HW_BLK_MAX; type++) { + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (!blk->rsvp && !blk->rsvp_nxt) + continue; + + SDE_DEBUG("%d rsvp[s%ue%u->s%ue%u] %d %d\n", stage, + (blk->rsvp) ? blk->rsvp->seq : 0, + (blk->rsvp) ? blk->rsvp->enc_id : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, + blk->type, blk->id); + + SDE_EVT32(stage, + (blk->rsvp) ? blk->rsvp->seq : 0, + (blk->rsvp) ? blk->rsvp->enc_id : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, + blk->type, blk->id); + } + } +} + +static void _sde_rm_print_rsvps_by_type( + struct sde_rm *rm, + enum sde_hw_blk_type type) +{ + struct sde_rm_hw_blk *blk; + + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (!blk->rsvp && !blk->rsvp_nxt) + continue; + + SDE_ERROR("rsvp[s%ue%u->s%ue%u] %d %d\n", + (blk->rsvp) ? blk->rsvp->seq : 0, + (blk->rsvp) ? blk->rsvp->enc_id : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, + blk->type, blk->id); + + SDE_EVT32((blk->rsvp) ? blk->rsvp->seq : 0, + (blk->rsvp) ? blk->rsvp->enc_id : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->seq : 0, + (blk->rsvp_nxt) ? blk->rsvp_nxt->enc_id : 0, + blk->type, blk->id); + } +} + +struct sde_hw_mdp *sde_rm_get_mdp(struct sde_rm *rm) +{ + return rm->hw_mdp; +} + +void sde_rm_init_hw_iter( + struct sde_rm_hw_iter *iter, + uint32_t enc_id, + enum sde_hw_blk_type type) +{ + memset(iter, 0, sizeof(*iter)); + iter->enc_id = enc_id; + iter->type = type; +} + +enum sde_rm_topology_name sde_rm_get_topology_name( + struct msm_display_topology topology) +{ + int i; + + for (i = 0; i < SDE_RM_TOPOLOGY_MAX; i++) + if (RM_IS_TOPOLOGY_MATCH(g_top_table[i], topology)) + return g_top_table[i].top_name; + + return SDE_RM_TOPOLOGY_NONE; +} + +static bool _sde_rm_get_hw_locked(struct sde_rm *rm, struct sde_rm_hw_iter *i) +{ + struct list_head *blk_list; + + if (!rm || !i || i->type >= SDE_HW_BLK_MAX) { + SDE_ERROR("invalid rm\n"); + return false; + } + + i->hw = NULL; + blk_list = &rm->hw_blks[i->type]; + + if (i->blk && (&i->blk->list == blk_list)) { + SDE_DEBUG("attempt resume iteration past last\n"); + return false; + } + + i->blk = list_prepare_entry(i->blk, blk_list, list); + + list_for_each_entry_continue(i->blk, blk_list, list) { + struct sde_rm_rsvp *rsvp = i->blk->rsvp; + + if (i->blk->type != i->type) { + SDE_ERROR("found incorrect block type %d on %d list\n", + i->blk->type, i->type); + return false; + } + + if ((i->enc_id == 0) || (rsvp && rsvp->enc_id == i->enc_id)) { + i->hw = i->blk->hw; + SDE_DEBUG("found type %d id %d for enc %d\n", + i->type, i->blk->id, i->enc_id); + return true; + } + } + + SDE_DEBUG("no match, type %d for enc %d\n", i->type, i->enc_id); + + return false; +} + +static bool _sde_rm_request_hw_blk_locked(struct sde_rm *rm, + struct sde_rm_hw_request *hw_blk_info) +{ + struct list_head *blk_list; + struct sde_rm_hw_blk *blk = NULL; + + if (!rm || !hw_blk_info || hw_blk_info->type >= SDE_HW_BLK_MAX) { + SDE_ERROR("invalid rm\n"); + return false; + } + + hw_blk_info->hw = NULL; + blk_list = &rm->hw_blks[hw_blk_info->type]; + + blk = list_prepare_entry(blk, blk_list, list); + + list_for_each_entry_continue(blk, blk_list, list) { + if (blk->type != hw_blk_info->type) { + SDE_ERROR("found incorrect block type %d on %d list\n", + blk->type, hw_blk_info->type); + return false; + } + + if (blk->hw->id == hw_blk_info->id) { + hw_blk_info->hw = blk->hw; + SDE_DEBUG("found type %d id %d\n", + blk->type, blk->id); + return true; + } + } + + SDE_DEBUG("no match, type %d id %d\n", hw_blk_info->type, + hw_blk_info->id); + + return false; +} + +bool sde_rm_get_hw(struct sde_rm *rm, struct sde_rm_hw_iter *i) +{ + bool ret; + + mutex_lock(&rm->rm_lock); + ret = _sde_rm_get_hw_locked(rm, i); + mutex_unlock(&rm->rm_lock); + + return ret; +} + +bool sde_rm_request_hw_blk(struct sde_rm *rm, struct sde_rm_hw_request *hw) +{ + bool ret; + + mutex_lock(&rm->rm_lock); + ret = _sde_rm_request_hw_blk_locked(rm, hw); + mutex_unlock(&rm->rm_lock); + + return ret; +} + +static void _sde_rm_hw_destroy(enum sde_hw_blk_type type, void *hw) +{ + switch (type) { + case SDE_HW_BLK_LM: + sde_hw_lm_destroy(hw); + break; + case SDE_HW_BLK_DSPP: + sde_hw_dspp_destroy(hw); + break; + case SDE_HW_BLK_DS: + sde_hw_ds_destroy(hw); + break; + case SDE_HW_BLK_CTL: + sde_hw_ctl_destroy(hw); + break; + case SDE_HW_BLK_CDM: + sde_hw_cdm_destroy(hw); + break; + case SDE_HW_BLK_PINGPONG: + sde_hw_pingpong_destroy(hw); + break; + case SDE_HW_BLK_INTF: + sde_hw_intf_destroy(hw); + break; + case SDE_HW_BLK_WB: + sde_hw_wb_destroy(hw); + break; + case SDE_HW_BLK_DSC: + sde_hw_dsc_destroy(hw); + break; + case SDE_HW_BLK_QDSS: + sde_hw_qdss_destroy(hw); + break; + case SDE_HW_BLK_SSPP: + /* SSPPs are not managed by the resource manager */ + case SDE_HW_BLK_TOP: + /* Top is a singleton, not managed in hw_blks list */ + case SDE_HW_BLK_MAX: + default: + SDE_ERROR("unsupported block type %d\n", type); + break; + } +} + +int sde_rm_destroy(struct sde_rm *rm) +{ + + struct sde_rm_rsvp *rsvp_cur, *rsvp_nxt; + struct sde_rm_hw_blk *hw_cur, *hw_nxt; + enum sde_hw_blk_type type; + + if (!rm) { + SDE_ERROR("invalid rm\n"); + return -EINVAL; + } + + list_for_each_entry_safe(rsvp_cur, rsvp_nxt, &rm->rsvps, list) { + list_del(&rsvp_cur->list); + kfree(rsvp_cur); + } + + + for (type = 0; type < SDE_HW_BLK_MAX; type++) { + list_for_each_entry_safe(hw_cur, hw_nxt, &rm->hw_blks[type], + list) { + list_del(&hw_cur->list); + _sde_rm_hw_destroy(hw_cur->type, hw_cur->hw); + kfree(hw_cur); + } + } + + sde_hw_mdp_destroy(rm->hw_mdp); + rm->hw_mdp = NULL; + + mutex_destroy(&rm->rm_lock); + + return 0; +} + +static int _sde_rm_hw_blk_create( + struct sde_rm *rm, + struct sde_mdss_cfg *cat, + void __iomem *mmio, + enum sde_hw_blk_type type, + uint32_t id, + void *hw_catalog_info) +{ + struct sde_rm_hw_blk *blk; + struct sde_hw_mdp *hw_mdp; + void *hw; + + hw_mdp = rm->hw_mdp; + + switch (type) { + case SDE_HW_BLK_LM: + hw = sde_hw_lm_init(id, mmio, cat); + break; + case SDE_HW_BLK_DSPP: + hw = sde_hw_dspp_init(id, mmio, cat); + break; + case SDE_HW_BLK_DS: + hw = sde_hw_ds_init(id, mmio, cat); + break; + case SDE_HW_BLK_CTL: + hw = sde_hw_ctl_init(id, mmio, cat); + break; + case SDE_HW_BLK_CDM: + hw = sde_hw_cdm_init(id, mmio, cat, hw_mdp); + break; + case SDE_HW_BLK_PINGPONG: + hw = sde_hw_pingpong_init(id, mmio, cat); + break; + case SDE_HW_BLK_INTF: + hw = sde_hw_intf_init(id, mmio, cat); + break; + case SDE_HW_BLK_WB: + hw = sde_hw_wb_init(id, mmio, cat, hw_mdp); + break; + case SDE_HW_BLK_DSC: + hw = sde_hw_dsc_init(id, mmio, cat); + break; + case SDE_HW_BLK_QDSS: + hw = sde_hw_qdss_init(id, mmio, cat); + break; + case SDE_HW_BLK_SSPP: + /* SSPPs are not managed by the resource manager */ + case SDE_HW_BLK_TOP: + /* Top is a singleton, not managed in hw_blks list */ + case SDE_HW_BLK_MAX: + default: + SDE_ERROR("unsupported block type %d\n", type); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(hw)) { + SDE_ERROR("failed hw object creation: type %d, err %ld\n", + type, PTR_ERR(hw)); + return -EFAULT; + } + + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (!blk) { + _sde_rm_hw_destroy(type, hw); + return -ENOMEM; + } + + blk->type = type; + blk->id = id; + blk->hw = hw; + list_add_tail(&blk->list, &rm->hw_blks[type]); + + _sde_rm_inc_resource_info(rm, &rm->avail_res, blk); + + return 0; +} + +static int _sde_rm_hw_blk_create_new(struct sde_rm *rm, + struct sde_mdss_cfg *cat, + void __iomem *mmio) +{ + int i, rc = 0; + + for (i = 0; i < cat->dspp_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DSPP, + cat->dspp[i].id, &cat->dspp[i]); + if (rc) { + SDE_ERROR("failed: dspp hw not available\n"); + goto fail; + } + } + + if (cat->mdp[0].has_dest_scaler) { + for (i = 0; i < cat->ds_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DS, + cat->ds[i].id, &cat->ds[i]); + if (rc) { + SDE_ERROR("failed: ds hw not available\n"); + goto fail; + } + } + } + + for (i = 0; i < cat->pingpong_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_PINGPONG, + cat->pingpong[i].id, &cat->pingpong[i]); + if (rc) { + SDE_ERROR("failed: pp hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->dsc_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DSC, + cat->dsc[i].id, &cat->dsc[i]); + if (rc) { + SDE_ERROR("failed: dsc hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->intf_count; i++) { + if (cat->intf[i].type == INTF_NONE) { + SDE_DEBUG("skip intf %d with type none\n", i); + continue; + } + + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_INTF, + cat->intf[i].id, &cat->intf[i]); + if (rc) { + SDE_ERROR("failed: intf hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->wb_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_WB, + cat->wb[i].id, &cat->wb[i]); + if (rc) { + SDE_ERROR("failed: wb hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->ctl_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_CTL, + cat->ctl[i].id, &cat->ctl[i]); + if (rc) { + SDE_ERROR("failed: ctl hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->cdm_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_CDM, + cat->cdm[i].id, &cat->cdm[i]); + if (rc) { + SDE_ERROR("failed: cdm hw not available\n"); + goto fail; + } + } + + for (i = 0; i < cat->qdss_count; i++) { + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_QDSS, + cat->qdss[i].id, &cat->qdss[i]); + if (rc) { + SDE_ERROR("failed: qdss hw not available\n"); + goto fail; + } + } + +fail: + return rc; +} + +int sde_rm_init(struct sde_rm *rm, + struct sde_mdss_cfg *cat, + void __iomem *mmio, + struct drm_device *dev) +{ + int i, rc = 0; + enum sde_hw_blk_type type; + + if (!rm || !cat || !mmio || !dev) { + SDE_ERROR("invalid input params\n"); + return -EINVAL; + } + + /* Clear, setup lists */ + memset(rm, 0, sizeof(*rm)); + + mutex_init(&rm->rm_lock); + + INIT_LIST_HEAD(&rm->rsvps); + for (type = 0; type < SDE_HW_BLK_MAX; type++) + INIT_LIST_HEAD(&rm->hw_blks[type]); + + rm->dev = dev; + + if (IS_SDE_CTL_REV_100(cat->ctl_rev)) + rm->topology_tbl = g_ctl_ver_1_top_table; + else + rm->topology_tbl = g_top_table; + + /* Some of the sub-blocks require an mdptop to be created */ + rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat); + if (IS_ERR_OR_NULL(rm->hw_mdp)) { + rc = PTR_ERR(rm->hw_mdp); + rm->hw_mdp = NULL; + SDE_ERROR("failed: mdp hw not available\n"); + goto fail; + } + + /* Interrogate HW catalog and create tracking items for hw blocks */ + for (i = 0; i < cat->mixer_count; i++) { + struct sde_lm_cfg *lm = &cat->mixer[i]; + + if (lm->pingpong == PINGPONG_MAX) { + SDE_ERROR("mixer %d without pingpong\n", lm->id); + goto fail; + } + + rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM, + cat->mixer[i].id, &cat->mixer[i]); + if (rc) { + SDE_ERROR("failed: lm hw not available\n"); + goto fail; + } + + if (!rm->lm_max_width) { + rm->lm_max_width = lm->sblk->maxwidth; + } else if (rm->lm_max_width != lm->sblk->maxwidth) { + /* + * Don't expect to have hw where lm max widths differ. + * If found, take the min. + */ + SDE_ERROR("unsupported: lm maxwidth differs\n"); + if (rm->lm_max_width > lm->sblk->maxwidth) + rm->lm_max_width = lm->sblk->maxwidth; + } + } + + rc = _sde_rm_hw_blk_create_new(rm, cat, mmio); + if (!rc) + return 0; + +fail: + sde_rm_destroy(rm); + + return rc; +} + +static bool _sde_rm_check_lm( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + const struct sde_lm_cfg *lm_cfg, + struct sde_rm_hw_blk *lm, + struct sde_rm_hw_blk **dspp, + struct sde_rm_hw_blk **ds, + struct sde_rm_hw_blk **pp) +{ + bool is_valid_dspp, is_valid_ds, ret = true; + + is_valid_dspp = (lm_cfg->dspp != DSPP_MAX) ? true : false; + is_valid_ds = (lm_cfg->ds != DS_MAX) ? true : false; + + /** + * RM_RQ_X: specification of which LMs to choose + * is_valid_X: indicates whether LM is tied with block X + * ret: true if given LM matches the user requirement, + * false otherwise + */ + if (RM_RQ_DSPP(reqs) && RM_RQ_DS(reqs)) + ret = (is_valid_dspp && is_valid_ds); + else if (RM_RQ_DSPP(reqs)) + ret = is_valid_dspp; + else if (RM_RQ_DS(reqs)) + ret = is_valid_ds; + + if (!ret) { + SDE_DEBUG( + "fail:lm(%d)req_dspp(%d)dspp(%d)req_ds(%d)ds(%d)\n", + lm_cfg->id, (bool)(RM_RQ_DSPP(reqs)), + lm_cfg->dspp, (bool)(RM_RQ_DS(reqs)), + lm_cfg->ds); + + return ret; + } + return true; +} + +static bool _sde_rm_reserve_dspp( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + const struct sde_lm_cfg *lm_cfg, + struct sde_rm_hw_blk *lm, + struct sde_rm_hw_blk **dspp) +{ + struct sde_rm_hw_iter iter; + + if (lm_cfg->dspp != DSPP_MAX) { + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DSPP); + while (_sde_rm_get_hw_locked(rm, &iter)) { + if (iter.blk->id == lm_cfg->dspp) { + *dspp = iter.blk; + break; + } + } + + if (!*dspp) { + SDE_DEBUG("lm %d failed to retrieve dspp %d\n", lm->id, + lm_cfg->dspp); + return false; + } + + if (RESERVED_BY_OTHER(*dspp, rsvp)) { + SDE_DEBUG("lm %d dspp %d already reserved\n", + lm->id, (*dspp)->id); + return false; + } + } + + return true; +} + + +static bool _sde_rm_reserve_ds( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + const struct sde_lm_cfg *lm_cfg, + struct sde_rm_hw_blk *lm, + struct sde_rm_hw_blk **ds) +{ + struct sde_rm_hw_iter iter; + + if (lm_cfg->ds != DS_MAX) { + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DS); + while (_sde_rm_get_hw_locked(rm, &iter)) { + if (iter.blk->id == lm_cfg->ds) { + *ds = iter.blk; + break; + } + } + + if (!*ds) { + SDE_DEBUG("lm %d failed to retrieve ds %d\n", lm->id, + lm_cfg->ds); + return false; + } + + if (RESERVED_BY_OTHER(*ds, rsvp)) { + SDE_DEBUG("lm %d ds %d already reserved\n", + lm->id, (*ds)->id); + return false; + } + } + + return true; +} + +static bool _sde_rm_reserve_pp( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + const struct sde_lm_cfg *lm_cfg, + const struct sde_pingpong_cfg *pp_cfg, + struct sde_rm_hw_blk *lm, + struct sde_rm_hw_blk **dspp, + struct sde_rm_hw_blk **ds, + struct sde_rm_hw_blk **pp) +{ + struct sde_rm_hw_iter iter; + + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_PINGPONG); + while (_sde_rm_get_hw_locked(rm, &iter)) { + if (iter.blk->id == lm_cfg->pingpong) { + *pp = iter.blk; + break; + } + } + + if (!*pp) { + SDE_ERROR("failed to get pp on lm %d\n", lm_cfg->pingpong); + return false; + } + + if (RESERVED_BY_OTHER(*pp, rsvp)) { + SDE_DEBUG("lm %d pp %d already reserved\n", lm->id, + (*pp)->id); + *dspp = NULL; + *ds = NULL; + return false; + } + + pp_cfg = to_sde_hw_pingpong((*pp)->hw)->caps; + if ((reqs->topology->top_name == SDE_RM_TOPOLOGY_PPSPLIT) && + !(test_bit(SDE_PINGPONG_SPLIT, &pp_cfg->features))) { + SDE_DEBUG("pp %d doesn't support ppsplit\n", pp_cfg->id); + *dspp = NULL; + *ds = NULL; + return false; + } + return true; +} + +/** + * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets + * proposed use case requirements, incl. hardwired dependent blocks like + * pingpong, and dspp. + * @rm: sde resource manager handle + * @rsvp: reservation currently being created + * @reqs: proposed use case requirements + * @lm: proposed layer mixer, function checks if lm, and all other hardwired + * blocks connected to the lm (pp, dspp) are available and appropriate + * @dspp: output parameter, dspp block attached to the layer mixer. + * NULL if dspp was not available, or not matching requirements. + * @pp: output parameter, pingpong block attached to the layer mixer. + * NULL if dspp was not available, or not matching requirements. + * @primary_lm: if non-null, this function check if lm is compatible primary_lm + * as well as satisfying all other requirements + * @Return: true if lm matches all requirements, false otherwise + */ +static bool _sde_rm_check_lm_and_get_connected_blks( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + struct sde_rm_hw_blk *lm, + struct sde_rm_hw_blk **dspp, + struct sde_rm_hw_blk **ds, + struct sde_rm_hw_blk **pp, + struct sde_rm_hw_blk *primary_lm) +{ + const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap; + const struct sde_pingpong_cfg *pp_cfg; + bool ret, is_conn_primary, is_conn_secondary; + u32 lm_primary_pref, lm_secondary_pref, cwb_pref; + + *dspp = NULL; + *ds = NULL; + *pp = NULL; + + lm_primary_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF); + lm_secondary_pref = lm_cfg->features & BIT(SDE_DISP_SECONDARY_PREF); + cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF); + is_conn_primary = (reqs->hw_res.display_type == + SDE_CONNECTOR_PRIMARY) ? true : false; + is_conn_secondary = (reqs->hw_res.display_type == + SDE_CONNECTOR_SECONDARY) ? true : false; + + SDE_DEBUG("check lm %d: dspp %d ds %d pp %d features %d disp type %d\n", + lm_cfg->id, lm_cfg->dspp, lm_cfg->ds, lm_cfg->pingpong, + lm_cfg->features, (int)reqs->hw_res.display_type); + + /* Check if this layer mixer is a peer of the proposed primary LM */ + if (primary_lm) { + const struct sde_lm_cfg *prim_lm_cfg = + to_sde_hw_mixer(primary_lm->hw)->cap; + + if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) { + SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id, + prim_lm_cfg->id); + return false; + } + } + + /* bypass rest of the checks if LM for primary display is found */ + if (!lm_primary_pref && !lm_secondary_pref) { + /* Check lm for valid requirements */ + ret = _sde_rm_check_lm(rm, rsvp, reqs, lm_cfg, lm, + dspp, ds, pp); + if (!ret) + return ret; + + /** + * If CWB is enabled and LM is not CWB supported + * then return false. + */ + if (RM_RQ_CWB(reqs) && !cwb_pref) { + SDE_DEBUG("fail: cwb supported lm not allocated\n"); + return false; + } + } else if ((!is_conn_primary && lm_primary_pref) || + (!is_conn_secondary && lm_secondary_pref)) { + SDE_DEBUG( + "display preference is not met. display_type: %d lm_features: %x\n", + (int)reqs->hw_res.display_type, lm_cfg->features); + return false; + } + + /* Already reserved? */ + if (RESERVED_BY_OTHER(lm, rsvp)) { + SDE_DEBUG("lm %d already reserved\n", lm_cfg->id); + return false; + } + + /* Reserve dspp */ + ret = _sde_rm_reserve_dspp(rm, rsvp, lm_cfg, lm, dspp); + if (!ret) + return ret; + + /* Reserve ds */ + ret = _sde_rm_reserve_ds(rm, rsvp, lm_cfg, lm, ds); + if (!ret) + return ret; + + /* Reserve pp */ + ret = _sde_rm_reserve_pp(rm, rsvp, reqs, lm_cfg, pp_cfg, lm, + dspp, ds, pp); + if (!ret) + return ret; + + return true; +} + +static int _sde_rm_reserve_lms( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + u8 *_lm_ids) + +{ + struct sde_rm_hw_blk *lm[MAX_BLOCKS]; + struct sde_rm_hw_blk *dspp[MAX_BLOCKS]; + struct sde_rm_hw_blk *ds[MAX_BLOCKS]; + struct sde_rm_hw_blk *pp[MAX_BLOCKS]; + struct sde_rm_hw_iter iter_i, iter_j; + int lm_count = 0; + int i, rc = 0; + + if (!reqs->topology->num_lm) { + SDE_DEBUG("invalid number of lm: %d\n", reqs->topology->num_lm); + return 0; + } + + /* Find a primary mixer */ + sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_LM); + while (lm_count != reqs->topology->num_lm && + _sde_rm_get_hw_locked(rm, &iter_i)) { + memset(&lm, 0, sizeof(lm)); + memset(&dspp, 0, sizeof(dspp)); + memset(&ds, 0, sizeof(ds)); + memset(&pp, 0, sizeof(pp)); + + lm_count = 0; + lm[lm_count] = iter_i.blk; + + SDE_DEBUG("blk id = %d, _lm_ids[%d] = %d\n", + iter_i.blk->id, + lm_count, + _lm_ids ? _lm_ids[lm_count] : -1); + + if (_lm_ids && (lm[lm_count])->id != _lm_ids[lm_count]) + continue; + + if (!_sde_rm_check_lm_and_get_connected_blks( + rm, rsvp, reqs, lm[lm_count], + &dspp[lm_count], &ds[lm_count], + &pp[lm_count], NULL)) + continue; + + ++lm_count; + + /* Valid primary mixer found, find matching peers */ + sde_rm_init_hw_iter(&iter_j, 0, SDE_HW_BLK_LM); + + while (lm_count != reqs->topology->num_lm && + _sde_rm_get_hw_locked(rm, &iter_j)) { + if (iter_i.blk == iter_j.blk) + continue; + + if (!_sde_rm_check_lm_and_get_connected_blks( + rm, rsvp, reqs, iter_j.blk, + &dspp[lm_count], &ds[lm_count], + &pp[lm_count], iter_i.blk)) + continue; + + lm[lm_count] = iter_j.blk; + SDE_DEBUG("blk id = %d, _lm_ids[%d] = %d\n", + iter_i.blk->id, + lm_count, + _lm_ids ? _lm_ids[lm_count] : -1); + + if (_lm_ids && (lm[lm_count])->id != _lm_ids[lm_count]) + continue; + + ++lm_count; + } + } + + if (lm_count != reqs->topology->num_lm) { + SDE_DEBUG("unable to find appropriate mixers\n"); + return -ENAVAIL; + } + + for (i = 0; i < ARRAY_SIZE(lm); i++) { + if (!lm[i]) + break; + + lm[i]->rsvp_nxt = rsvp; + pp[i]->rsvp_nxt = rsvp; + if (dspp[i]) + dspp[i]->rsvp_nxt = rsvp; + + if (ds[i]) + ds[i]->rsvp_nxt = rsvp; + + SDE_EVT32(lm[i]->type, rsvp->enc_id, lm[i]->id, pp[i]->id, + dspp[i] ? dspp[i]->id : 0, + ds[i] ? ds[i]->id : 0); + } + + if (reqs->topology->top_name == SDE_RM_TOPOLOGY_PPSPLIT) { + /* reserve a free PINGPONG_SLAVE block */ + rc = -ENAVAIL; + sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_PINGPONG); + while (_sde_rm_get_hw_locked(rm, &iter_i)) { + const struct sde_hw_pingpong *pp = + to_sde_hw_pingpong(iter_i.blk->hw); + const struct sde_pingpong_cfg *pp_cfg = pp->caps; + + if (!(test_bit(SDE_PINGPONG_SLAVE, &pp_cfg->features))) + continue; + if (RESERVED_BY_OTHER(iter_i.blk, rsvp)) + continue; + + iter_i.blk->rsvp_nxt = rsvp; + rc = 0; + break; + } + } + + return rc; +} + +static int _sde_rm_reserve_ctls( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + const struct sde_rm_topology_def *top, + u8 *_ctl_ids) +{ + struct sde_rm_hw_blk *ctls[MAX_BLOCKS]; + struct sde_rm_hw_iter iter; + int i = 0; + + if (!top->num_ctl) { + SDE_DEBUG("invalid number of ctl: %d\n", top->num_ctl); + return 0; + } + + memset(&ctls, 0, sizeof(ctls)); + + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CTL); + while (_sde_rm_get_hw_locked(rm, &iter)) { + const struct sde_hw_ctl *ctl = to_sde_hw_ctl(iter.blk->hw); + unsigned long features = ctl->caps->features; + bool has_split_display, has_ppsplit, primary_pref; + + if (RESERVED_BY_OTHER(iter.blk, rsvp)) + continue; + + has_split_display = BIT(SDE_CTL_SPLIT_DISPLAY) & features; + has_ppsplit = BIT(SDE_CTL_PINGPONG_SPLIT) & features; + primary_pref = BIT(SDE_CTL_PRIMARY_PREF) & features; + + SDE_DEBUG("ctl %d caps 0x%lX\n", iter.blk->id, features); + + /* + * bypass rest feature checks on finding CTL preferred + * for primary displays. + */ + if (!primary_pref && !_ctl_ids) { + if (top->needs_split_display != has_split_display) + continue; + + if (top->top_name == SDE_RM_TOPOLOGY_PPSPLIT && + !has_ppsplit) + continue; + } else if (!(reqs->hw_res.display_type == + SDE_CONNECTOR_PRIMARY && primary_pref) && !_ctl_ids) { + SDE_DEBUG( + "display pref not met. display_type: %d primary_pref: %d\n", + reqs->hw_res.display_type, primary_pref); + continue; + } + + ctls[i] = iter.blk; + + SDE_DEBUG("blk id = %d, _ctl_ids[%d] = %d\n", + iter.blk->id, i, + _ctl_ids ? _ctl_ids[i] : -1); + + if (_ctl_ids && (ctls[i]->id != _ctl_ids[i])) + continue; + + SDE_DEBUG("ctl %d match\n", iter.blk->id); + + if (++i == top->num_ctl) + break; + } + + if (i != top->num_ctl) + return -ENAVAIL; + + for (i = 0; i < ARRAY_SIZE(ctls) && i < top->num_ctl; i++) { + ctls[i]->rsvp_nxt = rsvp; + SDE_EVT32(ctls[i]->type, rsvp->enc_id, ctls[i]->id); + } + + return 0; +} + +static bool _sde_rm_check_dsc(struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_rm_hw_blk *dsc, + struct sde_rm_hw_blk *paired_dsc, + struct sde_rm_hw_blk *pp_blk) +{ + const struct sde_dsc_cfg *dsc_cfg = to_sde_hw_dsc(dsc->hw)->caps; + + /* Already reserved? */ + if (RESERVED_BY_OTHER(dsc, rsvp)) { + SDE_DEBUG("dsc %d already reserved\n", dsc_cfg->id); + return false; + } + + /** + * This check is required for routing even numbered DSC + * blks to any of the even numbered PP blks and odd numbered + * DSC blks to any of the odd numbered PP blks. + */ + if (!pp_blk || !IS_COMPATIBLE_PP_DSC(pp_blk->id, dsc->id)) + return false; + + /* Check if this dsc is a peer of the proposed paired DSC */ + if (paired_dsc) { + const struct sde_dsc_cfg *paired_dsc_cfg = + to_sde_hw_dsc(paired_dsc->hw)->caps; + + if (!test_bit(dsc_cfg->id, paired_dsc_cfg->dsc_pair_mask)) { + SDE_DEBUG("dsc %d not peer of dsc %d\n", dsc_cfg->id, + paired_dsc_cfg->id); + return false; + } + } + + return true; +} + +static void sde_rm_get_rsvp_nxt_hw_blks( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + int type, + struct sde_rm_hw_blk **blk_arr) +{ + struct sde_rm_hw_blk *blk; + int i = 0; + + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (blk->rsvp_nxt && blk->rsvp_nxt->seq == + rsvp->seq) + blk_arr[i++] = blk; + } +} + +static int _sde_rm_reserve_dsc( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + const struct sde_rm_topology_def *top, + u8 *_dsc_ids) +{ + struct sde_rm_hw_iter iter_i, iter_j; + struct sde_rm_hw_blk *dsc[MAX_BLOCKS]; + struct sde_rm_hw_blk *pp[MAX_BLOCKS]; + int alloc_count = 0; + int num_dsc_enc = top->num_comp_enc; + int i; + + if (!top->num_comp_enc) + return 0; + + sde_rm_init_hw_iter(&iter_i, 0, SDE_HW_BLK_DSC); + sde_rm_get_rsvp_nxt_hw_blks(rm, rsvp, SDE_HW_BLK_PINGPONG, pp); + + /* Find a first DSC */ + while (alloc_count != num_dsc_enc && + _sde_rm_get_hw_locked(rm, &iter_i)) { + memset(&dsc, 0, sizeof(dsc)); + alloc_count = 0; + + if (_dsc_ids && (iter_i.blk->id != _dsc_ids[alloc_count])) + continue; + + if (!_sde_rm_check_dsc(rm, rsvp, iter_i.blk, NULL, + pp[alloc_count])) + continue; + + SDE_DEBUG("blk id = %d, _dsc_ids[%d] = %d\n", + iter_i.blk->id, + alloc_count, + _dsc_ids ? _dsc_ids[alloc_count] : -1); + + dsc[alloc_count++] = iter_i.blk; + + /* Valid first dsc found, find matching peers */ + sde_rm_init_hw_iter(&iter_j, 0, SDE_HW_BLK_DSC); + + while (alloc_count != num_dsc_enc && + _sde_rm_get_hw_locked(rm, &iter_j)) { + if (iter_i.blk == iter_j.blk) + continue; + + if (_dsc_ids && (iter_j.blk->id != + _dsc_ids[alloc_count])) + continue; + + if (!_sde_rm_check_dsc(rm, rsvp, iter_j.blk, + iter_i.blk, pp[alloc_count])) + continue; + + SDE_DEBUG("blk id = %d, _dsc_ids[%d] = %d\n", + iter_j.blk->id, + alloc_count, + _dsc_ids ? _dsc_ids[alloc_count] : -1); + + dsc[alloc_count++] = iter_j.blk; + } + } + + if (alloc_count != num_dsc_enc) { + SDE_ERROR("couldn't reserve %d dsc blocks for enc id %d\n", + num_dsc_enc, rsvp->enc_id); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(dsc); i++) { + if (!dsc[i]) + break; + + dsc[i]->rsvp_nxt = rsvp; + + SDE_EVT32(dsc[i]->type, rsvp->enc_id, dsc[i]->id); + } + + return 0; +} + +static int _sde_rm_reserve_qdss( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + const struct sde_rm_topology_def *top, + u8 *_qdss_ids) +{ + struct sde_rm_hw_iter iter; + struct msm_drm_private *priv = rm->dev->dev_private; + struct sde_kms *sde_kms; + + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + sde_kms = to_sde_kms(priv->kms); + + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_QDSS); + + while (_sde_rm_get_hw_locked(rm, &iter)) { + if (RESERVED_BY_OTHER(iter.blk, rsvp)) + continue; + + SDE_DEBUG("blk id = %d\n", iter.blk->id); + + iter.blk->rsvp_nxt = rsvp; + SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id); + return 0; + } + + if (!iter.hw && sde_kms->catalog->qdss_count) { + SDE_DEBUG("couldn't reserve qdss for type %d id %d\n", + SDE_HW_BLK_QDSS, iter.blk->id); + return -ENAVAIL; + } + + return 0; +} + +static int _sde_rm_reserve_cdm( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + uint32_t id, + enum sde_hw_blk_type type) +{ + struct sde_rm_hw_iter iter; + + sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_CDM); + while (_sde_rm_get_hw_locked(rm, &iter)) { + const struct sde_hw_cdm *cdm = to_sde_hw_cdm(iter.blk->hw); + const struct sde_cdm_cfg *caps = cdm->caps; + bool match = false; + + if (RESERVED_BY_OTHER(iter.blk, rsvp)) + continue; + + if (type == SDE_HW_BLK_INTF && id != INTF_MAX) + match = test_bit(id, &caps->intf_connect); + else if (type == SDE_HW_BLK_WB && id != WB_MAX) + match = test_bit(id, &caps->wb_connect); + + SDE_DEBUG("type %d id %d, cdm intfs %lu wbs %lu match %d\n", + type, id, caps->intf_connect, caps->wb_connect, + match); + + if (!match) + continue; + + iter.blk->rsvp_nxt = rsvp; + SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id); + break; + } + + if (!iter.hw) { + SDE_ERROR("couldn't reserve cdm for type %d id %d\n", type, id); + return -ENAVAIL; + } + + return 0; +} + +static int _sde_rm_reserve_intf_or_wb( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + uint32_t id, + enum sde_hw_blk_type type, + bool needs_cdm) +{ + struct sde_rm_hw_iter iter; + int ret = 0; + + /* Find the block entry in the rm, and note the reservation */ + sde_rm_init_hw_iter(&iter, 0, type); + while (_sde_rm_get_hw_locked(rm, &iter)) { + if (iter.blk->id != id) + continue; + + if (RESERVED_BY_OTHER(iter.blk, rsvp)) { + SDE_ERROR("type %d id %d already reserved\n", type, id); + return -ENAVAIL; + } + + iter.blk->rsvp_nxt = rsvp; + SDE_EVT32(iter.blk->type, rsvp->enc_id, iter.blk->id); + break; + } + + /* Shouldn't happen since wbs / intfs are fixed at probe */ + if (!iter.hw) { + SDE_ERROR("couldn't find type %d id %d\n", type, id); + return -EINVAL; + } + + /* Expected only one intf or wb will request cdm */ + if (needs_cdm) + ret = _sde_rm_reserve_cdm(rm, rsvp, id, type); + + return ret; +} + +static int _sde_rm_reserve_intf_related_hw( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct sde_encoder_hw_resources *hw_res) +{ + int i, ret = 0; + u32 id; + + for (i = 0; i < ARRAY_SIZE(hw_res->intfs); i++) { + if (hw_res->intfs[i] == INTF_MODE_NONE) + continue; + id = i + INTF_0; + ret = _sde_rm_reserve_intf_or_wb(rm, rsvp, id, + SDE_HW_BLK_INTF, hw_res->needs_cdm); + if (ret) + return ret; + } + + for (i = 0; i < ARRAY_SIZE(hw_res->wbs); i++) { + if (hw_res->wbs[i] == INTF_MODE_NONE) + continue; + id = i + WB_0; + ret = _sde_rm_reserve_intf_or_wb(rm, rsvp, id, + SDE_HW_BLK_WB, hw_res->needs_cdm); + if (ret) + return ret; + } + + return ret; +} + +static bool _sde_rm_is_display_in_cont_splash(struct sde_kms *sde_kms, + struct drm_encoder *enc) +{ + int i; + struct sde_splash_display *splash_dpy; + + for (i = 0; i < MAX_DSI_DISPLAYS; i++) { + splash_dpy = &sde_kms->splash_data.splash_display[i]; + if (splash_dpy->encoder == enc) + return splash_dpy->cont_splash_enabled; + } + + return false; +} + +static int _sde_rm_make_lm_rsvp(struct sde_rm *rm, struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + struct sde_splash_display *splash_display) +{ + int ret, i; + u8 *hw_ids = NULL; + + /* Check if splash data provided lm_ids */ + if (splash_display) { + hw_ids = splash_display->lm_ids; + for (i = 0; i < splash_display->lm_cnt; i++) + SDE_DEBUG("splash_display->lm_ids[%d] = %d\n", + i, splash_display->lm_ids[i]); + + if (splash_display->lm_cnt != reqs->topology->num_lm) + SDE_DEBUG("Configured splash LMs != needed LM cnt\n"); + } + + /* + * Assign LMs and blocks whose usage is tied to them: + * DSPP & Pingpong. + */ + ret = _sde_rm_reserve_lms(rm, rsvp, reqs, hw_ids); + + return ret; +} + +static int _sde_rm_make_ctl_rsvp(struct sde_rm *rm, struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + struct sde_splash_display *splash_display) +{ + int ret, i; + u8 *hw_ids = NULL; + struct sde_rm_topology_def topology; + + /* Check if splash data provided ctl_ids */ + if (splash_display) { + hw_ids = splash_display->ctl_ids; + for (i = 0; i < splash_display->ctl_cnt; i++) + SDE_DEBUG("splash_display->ctl_ids[%d] = %d\n", + i, splash_display->ctl_ids[i]); + } + + /* + * Do assignment preferring to give away low-resource CTLs first: + * - Check mixers without Split Display + * - Only then allow to grab from CTLs with split display capability + */ + ret = _sde_rm_reserve_ctls(rm, rsvp, reqs, reqs->topology, hw_ids); + if (ret && !reqs->topology->needs_split_display && + reqs->topology->num_ctl > SINGLE_CTL) { + memcpy(&topology, reqs->topology, sizeof(topology)); + topology.needs_split_display = true; + ret = _sde_rm_reserve_ctls(rm, rsvp, reqs, &topology, hw_ids); + } + + return ret; +} + +static int _sde_rm_make_dsc_rsvp(struct sde_rm *rm, struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs, + struct sde_splash_display *splash_display) +{ + int ret, i; + u8 *hw_ids = NULL; + + /* Check if splash data provided dsc_ids */ + if (splash_display) { + hw_ids = splash_display->dsc_ids; + for (i = 0; i < splash_display->dsc_cnt; i++) + SDE_DEBUG("splash_data.dsc_ids[%d] = %d\n", + i, splash_display->dsc_ids[i]); + } + + ret = _sde_rm_reserve_dsc(rm, rsvp, reqs->topology, hw_ids); + + return ret; +} + +static int _sde_rm_make_next_rsvp(struct sde_rm *rm, struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct sde_rm_rsvp *rsvp, + struct sde_rm_requirements *reqs) +{ + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + struct sde_splash_display *splash_display = NULL; + struct sde_splash_data *splash_data; + int i, ret; + + priv = enc->dev->dev_private; + sde_kms = to_sde_kms(priv->kms); + splash_data = &sde_kms->splash_data; + + if (_sde_rm_is_display_in_cont_splash(sde_kms, enc)) { + for (i = 0; i < ARRAY_SIZE(splash_data->splash_display); i++) { + if (enc == splash_data->splash_display[i].encoder) + splash_display = + &splash_data->splash_display[i]; + } + if (!splash_display) { + SDE_ERROR("rm is in cont_splash but data not found\n"); + return -EINVAL; + } + } + + /* Create reservation info, tag reserved blocks with it as we go */ + rsvp->seq = ++rm->rsvp_next_seq; + rsvp->enc_id = enc->base.id; + rsvp->topology = reqs->topology->top_name; + list_add_tail(&rsvp->list, &rm->rsvps); + + ret = _sde_rm_make_lm_rsvp(rm, rsvp, reqs, splash_display); + if (ret) { + SDE_ERROR("unable to find appropriate mixers\n"); + _sde_rm_print_rsvps_by_type(rm, SDE_HW_BLK_LM); + return ret; + } + + ret = _sde_rm_make_ctl_rsvp(rm, rsvp, reqs, splash_display); + if (ret) { + SDE_ERROR("unable to find appropriate CTL\n"); + return ret; + } + + /* Assign INTFs, WBs, and blks whose usage is tied to them: CTL & CDM */ + ret = _sde_rm_reserve_intf_related_hw(rm, rsvp, &reqs->hw_res); + if (ret) + return ret; + + ret = _sde_rm_make_dsc_rsvp(rm, rsvp, reqs, splash_display); + if (ret) + return ret; + + ret = _sde_rm_reserve_qdss(rm, rsvp, reqs->topology, NULL); + if (ret) + return ret; + + return ret; +} + +/** + * _sde_rm_get_hw_blk_for_cont_splash - retrieve the LM blocks on given CTL + * and populate the connected HW blk ids in sde_splash_display + * @rm: Pointer to resource manager structure + * @ctl: Pointer to CTL hardware block + * @splash_display: Pointer to struct sde_splash_display + * return: number of active LM blocks for this CTL block + */ +static int _sde_rm_get_hw_blk_for_cont_splash(struct sde_rm *rm, + struct sde_hw_ctl *ctl, + struct sde_splash_display *splash_display) +{ + u32 lm_reg; + struct sde_rm_hw_iter iter_lm, iter_pp; + struct sde_hw_pingpong *pp; + + if (!rm || !ctl || !splash_display) { + SDE_ERROR("invalid input parameters\n"); + return 0; + } + + sde_rm_init_hw_iter(&iter_lm, 0, SDE_HW_BLK_LM); + sde_rm_init_hw_iter(&iter_pp, 0, SDE_HW_BLK_PINGPONG); + while (_sde_rm_get_hw_locked(rm, &iter_lm)) { + _sde_rm_get_hw_locked(rm, &iter_pp); + + if (splash_display->lm_cnt >= MAX_DATA_PATH_PER_DSIPLAY) + break; + + lm_reg = ctl->ops.read_ctl_layers(ctl, iter_lm.blk->id); + if (!lm_reg) + continue; + + splash_display->lm_ids[splash_display->lm_cnt++] = + iter_lm.blk->id; + SDE_DEBUG("lm_cnt=%d lm_reg[%d]=0x%x\n", splash_display->lm_cnt, + iter_lm.blk->id - LM_0, lm_reg); + + if (ctl->ops.get_staged_sspp && + ctl->ops.get_staged_sspp(ctl, iter_lm.blk->id, + &splash_display->pipes[ + splash_display->pipe_cnt], 1)) { + splash_display->pipe_cnt++; + } else { + SDE_ERROR("no pipe detected on LM-%d\n", + iter_lm.blk->id - LM_0); + return 0; + } + + pp = to_sde_hw_pingpong(iter_pp.blk->hw); + if (pp && pp->ops.get_dsc_status && + pp->ops.get_dsc_status(pp)) { + splash_display->dsc_ids[splash_display->dsc_cnt++] = + iter_pp.blk->id; + SDE_DEBUG("lm/pp[%d] path, using dsc[%d]\n", + iter_lm.blk->id - LM_0, + iter_pp.blk->id - DSC_0); + } + } + + return splash_display->lm_cnt; +} + +int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, + struct sde_rm *rm, + struct sde_splash_data *splash_data, + struct sde_mdss_cfg *cat) +{ + struct sde_rm_hw_iter iter_c; + int index = 0, ctl_top_cnt; + struct sde_kms *sde_kms = NULL; + struct sde_hw_mdp *hw_mdp; + struct sde_splash_display *splash_display; + u8 intf_sel; + + if (!priv || !rm || !cat || !splash_data) { + SDE_ERROR("invalid input parameters\n"); + return -EINVAL; + } + + SDE_DEBUG("mixer_count=%d, ctl_count=%d, dsc_count=%d\n", + cat->mixer_count, + cat->ctl_count, + cat->dsc_count); + + ctl_top_cnt = cat->ctl_count; + + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + sde_kms = to_sde_kms(priv->kms); + + hw_mdp = sde_rm_get_mdp(rm); + + sde_rm_init_hw_iter(&iter_c, 0, SDE_HW_BLK_CTL); + while (_sde_rm_get_hw_locked(rm, &iter_c) + && (index < splash_data->num_splash_displays)) { + struct sde_hw_ctl *ctl = to_sde_hw_ctl(iter_c.blk->hw); + + if (!ctl->ops.get_ctl_intf) { + SDE_ERROR("get_ctl_intf not initialized\n"); + return -EINVAL; + } + + intf_sel = ctl->ops.get_ctl_intf(ctl); + if (intf_sel) { + splash_display = &splash_data->splash_display[index]; + SDE_DEBUG("finding resources for display=%d ctl=%d\n", + index, iter_c.blk->id - CTL_0); + + _sde_rm_get_hw_blk_for_cont_splash(rm, + ctl, splash_display); + splash_display->cont_splash_enabled = true; + splash_display->ctl_ids[splash_display->ctl_cnt++] = + iter_c.blk->id; + } + index++; + } + + return 0; +} + +static int _sde_rm_populate_requirements( + struct sde_rm *rm, + struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + struct sde_rm_requirements *reqs) +{ + const struct drm_display_mode *mode = &crtc_state->mode; + int i, num_lm; + + memset(reqs, 0, sizeof(*reqs)); + + reqs->top_ctrl = sde_connector_get_property(conn_state, + CONNECTOR_PROP_TOPOLOGY_CONTROL); + sde_encoder_get_hw_resources(enc, &reqs->hw_res, conn_state); + + for (i = 0; i < SDE_RM_TOPOLOGY_MAX; i++) { + if (RM_IS_TOPOLOGY_MATCH(rm->topology_tbl[i], + reqs->hw_res.topology)) { + reqs->topology = &rm->topology_tbl[i]; + break; + } + } + + if (!reqs->topology) { + SDE_ERROR("invalid topology for the display\n"); + return -EINVAL; + } + + /* + * select dspp HW block for all dsi displays and ds for only + * primary dsi display. + */ + if (conn_state->connector->connector_type == DRM_MODE_CONNECTOR_DSI) { + if (!RM_RQ_DSPP(reqs)) + reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DSPP); + + if (!RM_RQ_DS(reqs) && rm->hw_mdp->caps->has_dest_scaler && + sde_encoder_is_primary_display(enc)) + reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_DS); + } + + /** + * Set the requirement for LM which has CWB support if CWB is + * found enabled. + */ + if (!RM_RQ_CWB(reqs) && sde_encoder_in_clone_mode(enc)) { + reqs->top_ctrl |= BIT(SDE_RM_TOPCTL_CWB); + + /* + * topology selection based on conn mode is not valid for CWB + * as WB conn populates modes based on max_mixer_width check + * but primary can be using dual LMs. This topology override for + * CWB is to check number of datapath active in primary and + * allocate same number of LM/PP blocks reserved for CWB + */ + reqs->topology = + &rm->topology_tbl[SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE]; + + num_lm = sde_crtc_get_num_datapath(crtc_state->crtc, + conn_state->connector); + + if (num_lm == 1) + reqs->topology = + &rm->topology_tbl[SDE_RM_TOPOLOGY_SINGLEPIPE]; + else if (num_lm == 0) + SDE_ERROR("Primary layer mixer is not set\n"); + + SDE_EVT32(num_lm, reqs->topology->num_lm, + reqs->topology->top_name, reqs->topology->num_ctl); + } + + SDE_DEBUG("top_ctrl: 0x%llX num_h_tiles: %d\n", reqs->top_ctrl, + reqs->hw_res.display_num_of_h_tiles); + SDE_DEBUG("num_lm: %d num_ctl: %d topology: %d split_display: %d\n", + reqs->topology->num_lm, reqs->topology->num_ctl, + reqs->topology->top_name, + reqs->topology->needs_split_display); + SDE_EVT32(mode->hdisplay, rm->lm_max_width, reqs->topology->num_lm, + reqs->top_ctrl, reqs->topology->top_name, + reqs->topology->num_ctl); + + return 0; +} + +static struct sde_rm_rsvp *_sde_rm_get_rsvp( + struct sde_rm *rm, + struct drm_encoder *enc) +{ + struct sde_rm_rsvp *i; + + if (!rm || !enc) { + SDE_ERROR("invalid params\n"); + return NULL; + } + + if (list_empty(&rm->rsvps)) + return NULL; + + list_for_each_entry(i, &rm->rsvps, list) + if (i->enc_id == enc->base.id) + return i; + + return NULL; +} + +static struct sde_rm_rsvp *_sde_rm_get_rsvp_nxt( + struct sde_rm *rm, + struct drm_encoder *enc) +{ + struct sde_rm_rsvp *i; + + if (list_empty(&rm->rsvps)) + return NULL; + + list_for_each_entry(i, &rm->rsvps, list) + if (i->enc_id == enc->base.id) + break; + + list_for_each_entry_continue(i, &rm->rsvps, list) + if (i->enc_id == enc->base.id) + return i; + + return NULL; +} + +static struct drm_connector *_sde_rm_get_connector( + struct drm_encoder *enc) +{ + struct drm_connector *conn = NULL; + struct sde_connector *c_conn = NULL; + struct list_head *connector_list = + &enc->dev->mode_config.connector_list; + + list_for_each_entry(conn, connector_list, head) { + c_conn = to_sde_connector(conn); + if (c_conn->encoder == enc) + return conn; + } + + return NULL; +} + +int sde_rm_update_topology(struct drm_connector_state *conn_state, + struct msm_display_topology *topology) +{ + int i, ret = 0; + struct msm_display_topology top; + enum sde_rm_topology_name top_name = SDE_RM_TOPOLOGY_NONE; + + if (!conn_state) + return -EINVAL; + + if (topology) { + top = *topology; + for (i = 0; i < SDE_RM_TOPOLOGY_MAX; i++) + if (RM_IS_TOPOLOGY_MATCH(g_top_table[i], top)) { + top_name = g_top_table[i].top_name; + break; + } + } + + ret = msm_property_set_property( + sde_connector_get_propinfo(conn_state->connector), + sde_connector_get_property_state(conn_state), + CONNECTOR_PROP_TOPOLOGY_NAME, top_name); + + return ret; +} + +/** + * _sde_rm_release_rsvp - release resources and release a reservation + * @rm: KMS handle + * @rsvp: RSVP pointer to release and release resources for + */ +static void _sde_rm_release_rsvp( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct drm_connector *conn) +{ + struct sde_rm_rsvp *rsvp_c, *rsvp_n; + struct sde_rm_hw_blk *blk; + enum sde_hw_blk_type type; + + if (!rsvp) + return; + + SDE_DEBUG("rel rsvp %d enc %d\n", rsvp->seq, rsvp->enc_id); + + list_for_each_entry_safe(rsvp_c, rsvp_n, &rm->rsvps, list) { + if (rsvp == rsvp_c) { + list_del(&rsvp_c->list); + break; + } + } + + for (type = 0; type < SDE_HW_BLK_MAX; type++) { + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (blk->rsvp == rsvp) { + blk->rsvp = NULL; + SDE_DEBUG("rel rsvp %d enc %d %d %d\n", + rsvp->seq, rsvp->enc_id, + blk->type, blk->id); + _sde_rm_inc_resource_info(rm, + &rm->avail_res, blk); + } + if (blk->rsvp_nxt == rsvp) { + blk->rsvp_nxt = NULL; + SDE_DEBUG("rel rsvp_nxt %d enc %d %d %d\n", + rsvp->seq, rsvp->enc_id, + blk->type, blk->id); + } + } + } + + kfree(rsvp); +} + +void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc, bool nxt) +{ + struct sde_rm_rsvp *rsvp; + struct drm_connector *conn; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + uint64_t top_ctrl; + + if (!rm || !enc) { + SDE_ERROR("invalid params\n"); + return; + } + + priv = enc->dev->dev_private; + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return; + } + sde_kms = to_sde_kms(priv->kms); + + mutex_lock(&rm->rm_lock); + + if (nxt) + rsvp = _sde_rm_get_rsvp_nxt(rm, enc); + else + rsvp = _sde_rm_get_rsvp(rm, enc); + if (!rsvp) { + SDE_DEBUG("failed to find rsvp for enc %d, nxt %d", + enc->base.id, nxt); + goto end; + } + + if (_sde_rm_is_display_in_cont_splash(sde_kms, enc)) { + _sde_rm_release_rsvp(rm, rsvp, conn); + goto end; + } + + conn = _sde_rm_get_connector(enc); + if (!conn) { + SDE_ERROR("failed to get conn for enc %d nxt %d rsvp[s%de%d]\n", + enc->base.id, nxt, rsvp->seq, rsvp->enc_id); + goto end; + } + + top_ctrl = sde_connector_get_property(conn->state, + CONNECTOR_PROP_TOPOLOGY_CONTROL); + + SDE_EVT32(enc->base.id, conn->base.id, rsvp->seq, top_ctrl, nxt); + if (top_ctrl & BIT(SDE_RM_TOPCTL_RESERVE_LOCK)) { + SDE_DEBUG("rsvp[s%de%d] not releasing locked resources\n", + rsvp->seq, rsvp->enc_id); + } else { + SDE_DEBUG("release rsvp[s%de%d]\n", rsvp->seq, + rsvp->enc_id); + _sde_rm_release_rsvp(rm, rsvp, conn); + } + +end: + mutex_unlock(&rm->rm_lock); +} + +static int _sde_rm_commit_rsvp( + struct sde_rm *rm, + struct sde_rm_rsvp *rsvp, + struct drm_connector_state *conn_state) +{ + struct sde_rm_hw_blk *blk; + enum sde_hw_blk_type type; + int ret = 0; + + /* Swap next rsvp to be the active */ + for (type = 0; type < SDE_HW_BLK_MAX; type++) { + list_for_each_entry(blk, &rm->hw_blks[type], list) { + if (blk->rsvp_nxt && conn_state->best_encoder->base.id + == blk->rsvp_nxt->enc_id) { + blk->rsvp = blk->rsvp_nxt; + blk->rsvp_nxt = NULL; + _sde_rm_dec_resource_info(rm, + &rm->avail_res, blk); + } + } + } + + if (!ret) { + SDE_DEBUG("rsrv enc %d topology %d\n", rsvp->enc_id, + rsvp->topology); + SDE_EVT32(rsvp->enc_id, rsvp->topology); + } + + return ret; +} + +/* call this only after rm_mutex held */ +struct sde_rm_rsvp *_sde_rm_poll_get_rsvp_nxt_locked(struct sde_rm *rm, + struct drm_encoder *enc) +{ + int i; + u32 loop_count = 20; + struct sde_rm_rsvp *rsvp_nxt = NULL; + u32 sleep = RM_NXT_CLEAR_POLL_TIMEOUT_US / loop_count; + + for (i = 0; i < loop_count; i++) { + rsvp_nxt = _sde_rm_get_rsvp_nxt(rm, enc); + if (!rsvp_nxt) + return rsvp_nxt; + + mutex_unlock(&rm->rm_lock); + SDE_DEBUG("iteration i:%d sleep range:%uus to %uus\n", + i, sleep, sleep * 2); + usleep_range(sleep, sleep * 2); + mutex_lock(&rm->rm_lock); + } + + return rsvp_nxt; +} + +int sde_rm_reserve( + struct sde_rm *rm, + struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + bool test_only) +{ + struct sde_rm_rsvp *rsvp_cur, *rsvp_nxt; + struct sde_rm_requirements reqs; + struct msm_drm_private *priv; + struct sde_kms *sde_kms; + int ret; + + if (!rm || !enc || !crtc_state || !conn_state) { + SDE_ERROR("invalid arguments\n"); + return -EINVAL; + } + + if (!enc->dev || !enc->dev->dev_private) { + SDE_ERROR("drm device invalid\n"); + return -EINVAL; + } + priv = enc->dev->dev_private; + if (!priv->kms) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + sde_kms = to_sde_kms(priv->kms); + + /* Check if this is just a page-flip */ + if (!_sde_rm_is_display_in_cont_splash(sde_kms, enc) && + !drm_atomic_crtc_needs_modeset(crtc_state)) + return 0; + + SDE_DEBUG("reserving hw for conn %d enc %d crtc %d test_only %d\n", + conn_state->connector->base.id, enc->base.id, + crtc_state->crtc->base.id, test_only); + SDE_EVT32(enc->base.id, conn_state->connector->base.id); + + mutex_lock(&rm->rm_lock); + + _sde_rm_print_rsvps(rm, SDE_RM_STAGE_BEGIN); + + rsvp_cur = _sde_rm_get_rsvp(rm, enc); + rsvp_nxt = _sde_rm_get_rsvp_nxt(rm, enc); + + /* + * RM currently relies on rsvp_nxt assigned to the hw blocks to + * commit rsvps. This rsvp_nxt can be cleared by a back to back + * check_only commit with modeset when its predecessor atomic + * commit is delayed / not committed the reservation yet. + * Poll for rsvp_nxt clear, allow the check_only commit if rsvp_nxt + * gets cleared and bailout if it does not get cleared before timeout. + */ + if (test_only && rsvp_cur && rsvp_nxt) { + rsvp_nxt = _sde_rm_poll_get_rsvp_nxt_locked(rm, enc); + if (rsvp_nxt) { + SDE_ERROR("poll timeout cur %d nxt %d enc %d\n", + rsvp_cur->seq, rsvp_nxt->seq, enc->base.id); + SDE_EVT32(rsvp_cur->seq, rsvp_nxt->seq, + enc->base.id, SDE_EVTLOG_ERROR); + ret = -EINVAL; + goto end; + } + } + + if (!test_only && rsvp_nxt) + goto commit_rsvp; + + ret = _sde_rm_populate_requirements(rm, enc, crtc_state, + conn_state, &reqs); + if (ret) { + SDE_ERROR("failed to populate hw requirements\n"); + goto end; + } + + /* + * We only support one active reservation per-hw-block. But to implement + * transactional semantics for test-only, and for allowing failure while + * modifying your existing reservation, over the course of this + * function we can have two reservations: + * Current: Existing reservation + * Next: Proposed reservation. The proposed reservation may fail, or may + * be discarded if in test-only mode. + * If reservation is successful, and we're not in test-only, then we + * replace the current with the next. + */ + rsvp_nxt = kzalloc(sizeof(*rsvp_nxt), GFP_KERNEL); + if (!rsvp_nxt) { + ret = -ENOMEM; + goto end; + } + + /* + * User can request that we clear out any reservation during the + * atomic_check phase by using this CLEAR bit + */ + if (rsvp_cur && test_only && RM_RQ_CLEAR(&reqs)) { + SDE_DEBUG("test_only & CLEAR: clear rsvp[s%de%d]\n", + rsvp_cur->seq, rsvp_cur->enc_id); + _sde_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); + rsvp_cur = NULL; + _sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_CLEAR); + } + + /* Check the proposed reservation, store it in hw's "next" field */ + ret = _sde_rm_make_next_rsvp(rm, enc, crtc_state, conn_state, + rsvp_nxt, &reqs); + + _sde_rm_print_rsvps(rm, SDE_RM_STAGE_AFTER_RSVPNEXT); + + if (ret) { + SDE_ERROR("failed to reserve hw resources: %d, test_only %d\n", + ret, test_only); + _sde_rm_release_rsvp(rm, rsvp_nxt, conn_state->connector); + goto end; + } else if (test_only && !RM_RQ_LOCK(&reqs)) { + /* + * Normally, if test_only, test the reservation and then undo + * However, if the user requests LOCK, then keep the reservation + * made during the atomic_check phase. + */ + SDE_DEBUG("test_only: rsvp[s%de%d]\n", + rsvp_nxt->seq, rsvp_nxt->enc_id); + goto end; + } else { + if (test_only && RM_RQ_LOCK(&reqs)) + SDE_DEBUG("test_only & LOCK: lock rsvp[s%de%d]\n", + rsvp_nxt->seq, rsvp_nxt->enc_id); + } + +commit_rsvp: + _sde_rm_release_rsvp(rm, rsvp_cur, conn_state->connector); + ret = _sde_rm_commit_rsvp(rm, rsvp_nxt, conn_state); + +end: + _sde_rm_print_rsvps(rm, SDE_RM_STAGE_FINAL); + mutex_unlock(&rm->rm_lock); + + return ret; +} + +int sde_rm_ext_blk_create_reserve(struct sde_rm *rm, + struct sde_hw_blk *hw, struct drm_encoder *enc) +{ + struct sde_rm_hw_blk *blk; + struct sde_rm_rsvp *rsvp; + int ret = 0; + + if (!rm || !hw || !enc) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + if (hw->type >= SDE_HW_BLK_MAX) { + SDE_ERROR("invalid HW type\n"); + return -EINVAL; + } + + mutex_lock(&rm->rm_lock); + + rsvp = _sde_rm_get_rsvp(rm, enc); + if (!rsvp) { + rsvp = kzalloc(sizeof(*rsvp), GFP_KERNEL); + if (!rsvp) { + ret = -ENOMEM; + goto end; + } + + rsvp->seq = ++rm->rsvp_next_seq; + rsvp->enc_id = enc->base.id; + list_add_tail(&rsvp->list, &rm->rsvps); + + SDE_DEBUG("create rsvp %d for enc %d\n", + rsvp->seq, rsvp->enc_id); + } + + blk = kzalloc(sizeof(*blk), GFP_KERNEL); + if (!blk) { + ret = -ENOMEM; + goto end; + } + + blk->type = hw->type; + blk->id = hw->id; + blk->hw = hw; + blk->rsvp = rsvp; + list_add_tail(&blk->list, &rm->hw_blks[hw->type]); + + SDE_DEBUG("create blk %d %d for rsvp %d enc %d\n", blk->type, blk->id, + rsvp->seq, rsvp->enc_id); + +end: + mutex_unlock(&rm->rm_lock); + return ret; +} + +int sde_rm_ext_blk_destroy(struct sde_rm *rm, + struct drm_encoder *enc) +{ + struct sde_rm_hw_blk *blk = NULL, *p; + struct sde_rm_rsvp *rsvp; + enum sde_hw_blk_type type; + int ret = 0; + + if (!rm || !enc) { + SDE_ERROR("invalid parameters\n"); + return -EINVAL; + } + + mutex_lock(&rm->rm_lock); + + rsvp = _sde_rm_get_rsvp(rm, enc); + if (!rsvp) { + ret = -ENOENT; + SDE_ERROR("failed to find rsvp for enc %d\n", enc->base.id); + goto end; + } + + for (type = 0; type < SDE_HW_BLK_MAX; type++) { + list_for_each_entry_safe(blk, p, &rm->hw_blks[type], list) { + if (blk->rsvp == rsvp) { + list_del(&blk->list); + SDE_DEBUG("del blk %d %d from rsvp %d enc %d\n", + blk->type, blk->id, + rsvp->seq, rsvp->enc_id); + kfree(blk); + } + } + } + + SDE_DEBUG("del rsvp %d\n", rsvp->seq); + list_del(&rsvp->list); + kfree(rsvp); +end: + mutex_unlock(&rm->rm_lock); + return ret; +} diff --git a/techpack/display/msm/sde/sde_rm.h b/techpack/display/msm/sde/sde_rm.h new file mode 100644 index 0000000000000000000000000000000000000000..a397b0dc35dc9f08f585726c200c4018a6ea56d6 --- /dev/null +++ b/techpack/display/msm/sde/sde_rm.h @@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_RM_H__ +#define __SDE_RM_H__ + +#include <linux/list.h> + +#include "msm_kms.h" +#include "sde_hw_top.h" + +#define SINGLE_CTL 1 +#define DUAL_CTL 2 + +/** + * enum sde_rm_topology_name - HW resource use case in use by connector + * @SDE_RM_TOPOLOGY_NONE: No topology in use currently + * @SDE_RM_TOPOLOGY_SINGLEPIPE: 1 LM, 1 PP, 1 INTF/WB + * @SDE_RM_TOPOLOGY_SINGLEPIPE_DSC: 1 LM, 1 DSC, 1 PP, 1 INTF/WB + * @SDE_RM_TOPOLOGY_DUALPIPE: 2 LM, 2 PP, 2 INTF/WB + * @SDE_RM_TOPOLOGY_DUALPIPE_DSC: 2 LM, 2 DSC, 2 PP, 2 INTF/WB + * @SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE: 2 LM, 2 PP, 3DMux, 1 INTF/WB + * @SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC: 2 LM, 2 PP, 3DMux, 1 DSC, 1 INTF/WB + * @SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE: 2 LM, 2 PP, 2 DSC Merge, 1 INTF/WB + * @SDE_RM_TOPOLOGY_PPSPLIT: 1 LM, 2 PPs, 2 INTF/WB + */ +enum sde_rm_topology_name { + SDE_RM_TOPOLOGY_NONE = 0, + SDE_RM_TOPOLOGY_SINGLEPIPE, + SDE_RM_TOPOLOGY_SINGLEPIPE_DSC, + SDE_RM_TOPOLOGY_DUALPIPE, + SDE_RM_TOPOLOGY_DUALPIPE_DSC, + SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE, + SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC, + SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE, + SDE_RM_TOPOLOGY_PPSPLIT, + SDE_RM_TOPOLOGY_MAX, +}; + +/** + * enum sde_rm_topology_control - HW resource use case in use by connector + * @SDE_RM_TOPCTL_RESERVE_LOCK: If set, in AtomicTest phase, after a successful + * test, reserve the resources for this display. + * Normal behavior would not impact the reservation + * list during the AtomicTest phase. + * @SDE_RM_TOPCTL_RESERVE_CLEAR: If set, in AtomicTest phase, before testing, + * release any reservation held by this display. + * Normal behavior would not impact the + * reservation list during the AtomicTest phase. + * @SDE_RM_TOPCTL_DSPP: Require layer mixers with DSPP capabilities + * @SDE_RM_TOPCTL_DS : Require layer mixers with DS capabilities + * @SDE_RM_TOPCTL_CWB : Require layer mixers with CWB capabilities + */ +enum sde_rm_topology_control { + SDE_RM_TOPCTL_RESERVE_LOCK, + SDE_RM_TOPCTL_RESERVE_CLEAR, + SDE_RM_TOPCTL_DSPP, + SDE_RM_TOPCTL_DS, + SDE_RM_TOPCTL_CWB, +}; + +/** + * enum sde_rm_topology_control - HW resource use case in use by connector + * @SDE_RM_QSYNC_DISABLED: If set, Qsync feature is supported and in + * disable state. + * @SDE_RM_QSYNC_CONTINUOUS_MODE: If set, Qsync is enabled in continuous + * mode. + * @SDE_RM_QSYNC_ONE_SHOT_MODE: If set, Qsync is enabled in one shot mode. + * + */ +enum sde_rm_qsync_modes { + SDE_RM_QSYNC_DISABLED, + SDE_RM_QSYNC_CONTINUOUS_MODE, + SDE_RM_QSYNC_ONE_SHOT_MODE +}; + +/** + * struct sde_rm_topology_def - Topology table definition + * @top_name: name identifying this topology + * @num_lm: number of layer mixers used + * @num_comp_enc: number of encoders used + * @num_intf: number of interface used + * @num_ctl: number of control path used + * @needs_split_display: If set split display is enabled + */ +struct sde_rm_topology_def { + enum sde_rm_topology_name top_name; + int num_lm; + int num_comp_enc; + int num_intf; + int num_ctl; + int needs_split_display; +}; + +/** + * struct sde_rm - SDE dynamic hardware resource manager + * @dev: device handle for event logging purposes + * @rsvps: list of hardware reservations by each crtc->encoder->connector + * @hw_blks: array of lists of hardware resources present in the system, one + * list per type of hardware block + * @hw_mdp: hardware object for mdp_top + * @lm_max_width: cached layer mixer maximum width + * @rsvp_next_seq: sequence number for next reservation for debugging purposes + * @rm_lock: resource manager mutex + * @avail_res: Pointer with curr available resources + */ +struct sde_rm { + struct drm_device *dev; + struct list_head rsvps; + struct list_head hw_blks[SDE_HW_BLK_MAX]; + struct sde_hw_mdp *hw_mdp; + uint32_t lm_max_width; + uint32_t rsvp_next_seq; + struct mutex rm_lock; + const struct sde_rm_topology_def *topology_tbl; + struct msm_resource_caps_info avail_res; +}; + +/** + * struct sde_rm_hw_blk - resource manager internal structure + * forward declaration for single iterator definition without void pointer + */ +struct sde_rm_hw_blk; + +/** + * struct sde_rm_hw_iter - iterator for use with sde_rm + * @hw: sde_hw object requested, or NULL on failure + * @blk: sde_rm internal block representation. Clients ignore. Used as iterator. + * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder + * @type: Hardware Block Type client wishes to search for. + */ +struct sde_rm_hw_iter { + void *hw; + struct sde_rm_hw_blk *blk; + uint32_t enc_id; + enum sde_hw_blk_type type; +}; + +/** + * struct sde_rm_hw_request - data for requesting hw blk + * @hw: sde_hw object requested, or NULL on failure + * @type: Hardware Block Type client wishes to search for + * @id: Hardware block id + */ +struct sde_rm_hw_request { + void *hw; + enum sde_hw_blk_type type; + int id; +}; + +/** + * sde_rm_get_topology_name - get the name of the given topology config + * @topology: msm_display_topology topology config + * @Return: name of the given topology + */ +enum sde_rm_topology_name sde_rm_get_topology_name( + struct msm_display_topology topology); + + +/** + * sde_rm_init - Read hardware catalog and create reservation tracking objects + * for all HW blocks. + * @rm: SDE Resource Manager handle + * @cat: Pointer to hardware catalog + * @mmio: mapped register io address of MDP + * @dev: device handle for event logging purposes + * @Return: 0 on Success otherwise -ERROR + */ +int sde_rm_init(struct sde_rm *rm, + struct sde_mdss_cfg *cat, + void __iomem *mmio, + struct drm_device *dev); + +/** + * sde_rm_destroy - Free all memory allocated by sde_rm_init + * @rm: SDE Resource Manager handle + * @Return: 0 on Success otherwise -ERROR + */ +int sde_rm_destroy(struct sde_rm *rm); + +/** + * sde_rm_reserve - Given a CRTC->Encoder->Connector display chain, analyze + * the use connections and user requirements, specified through related + * topology control properties, and reserve hardware blocks to that + * display chain. + * HW blocks can then be accessed through sde_rm_get_* functions. + * HW Reservations should be released via sde_rm_release_hw. + * @rm: SDE Resource Manager handle + * @drm_enc: DRM Encoder handle + * @crtc_state: Proposed Atomic DRM CRTC State handle + * @conn_state: Proposed Atomic DRM Connector State handle + * @test_only: Atomic-Test phase, discard results (unless property overrides) + * @Return: 0 on Success otherwise -ERROR + */ +int sde_rm_reserve(struct sde_rm *rm, + struct drm_encoder *drm_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + bool test_only); + +/** + * sde_rm_release - Given the encoder for the display chain, release any + * HW blocks previously reserved for that use case. + * @rm: SDE Resource Manager handle + * @enc: DRM Encoder handle + * @nxt: Choose option to release rsvp_nxt + * @Return: 0 on Success otherwise -ERROR + */ +void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc, bool nxt); + +/** + * sde_rm_get_mdp - Retrieve HW block for MDP TOP. + * This is never reserved, and is usable by any display. + * @rm: SDE Resource Manager handle + * @Return: Pointer to hw block or NULL + */ +struct sde_hw_mdp *sde_rm_get_mdp(struct sde_rm *rm); + +/** + * sde_rm_init_hw_iter - setup given iterator for new iteration over hw list + * using sde_rm_get_hw + * @iter: iter object to initialize + * @enc_id: DRM ID of Encoder client wishes to search for, or 0 for Any Encoder + * @type: Hardware Block Type client wishes to search for. + */ +void sde_rm_init_hw_iter( + struct sde_rm_hw_iter *iter, + uint32_t enc_id, + enum sde_hw_blk_type type); +/** + * sde_rm_get_hw - retrieve reserved hw object given encoder and hw type + * Meant to do a single pass through the hardware list to iteratively + * retrieve hardware blocks of a given type for a given encoder. + * Initialize an iterator object. + * Set hw block type of interest. Set encoder id of interest, 0 for any. + * Function returns first hw of type for that encoder. + * Subsequent calls will return the next reserved hw of that type in-order. + * Iterator HW pointer will be null on failure to find hw. + * @rm: SDE Resource Manager handle + * @iter: iterator object + * @Return: true on match found, false on no match found + */ +bool sde_rm_get_hw(struct sde_rm *rm, struct sde_rm_hw_iter *iter); + +/** + * sde_rm_request_hw_blk - retrieve the requested hardware block + * @rm: SDE Resource Manager handle + * @hw: holds the input and output information of the requested hw block + * @Return: true on match found, false on no match found + */ +bool sde_rm_request_hw_blk(struct sde_rm *rm, struct sde_rm_hw_request *hw); + +/** + * sde_rm_cont_splash_res_init - Read the current MDSS configuration + * to update the splash data structure with the topology + * configured by the bootloader. + * @priv: DRM private structure handle + * @rm: SDE Resource Manager handle + * @splash_data: Pointer to the splash_data structure to be updated. + * @cat: Pointer to the SDE catalog + * @Return: 0 on success or error + */ +int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, + struct sde_rm *rm, + struct sde_splash_data *splash_data, + struct sde_mdss_cfg *cat); + +/** + * sde_rm_update_topology - sets topology property of the connector + * @conn_state: drm state of the connector + * @topology: topology selected for the display + * @return: 0 on success or error + */ +int sde_rm_update_topology(struct drm_connector_state *conn_state, + struct msm_display_topology *topology); + +/** + * sde_rm_topology_is_dual_ctl - checks if topoloy requires two control paths + * @rm: SDE Resource Manager handle + * @topology: topology selected for the display + * @return: true if two control paths are required or false + */ +static inline bool sde_rm_topology_is_dual_ctl(struct sde_rm *rm, + enum sde_rm_topology_name topology) +{ + if ((!rm) || (topology <= SDE_RM_TOPOLOGY_NONE) || + (topology >= SDE_RM_TOPOLOGY_MAX)) { + pr_err("invalid arguments: rm:%d topology:%d\n", + rm == NULL, topology); + + return false; + } + + return rm->topology_tbl[topology].num_ctl == DUAL_CTL; +} + +/** + * sde_rm_ext_blk_create_reserve - Create external HW blocks + * in resource manager and reserve for specific encoder. + * @rm: SDE Resource Manager handle + * @hw: external HW block + * @drm_enc: DRM Encoder handle + * @Return: 0 on Success otherwise -ERROR + */ +int sde_rm_ext_blk_create_reserve(struct sde_rm *rm, + struct sde_hw_blk *hw, + struct drm_encoder *enc); + +/** + * sde_rm_ext_blk_destroy - Given the encoder for the display chain, release + * external HW blocks created for that. + * @rm: SDE Resource Manager handle + * @enc: DRM Encoder handle + * @Return: 0 on Success otherwise -ERROR + */ +int sde_rm_ext_blk_destroy(struct sde_rm *rm, + struct drm_encoder *enc); + +/** + * sde_rm_get_resource_info - returns avail hw resource info + * @mr: sde rm object + * @drm_enc: drm encoder object + * @avail_res: out parameter, available resource object + * @display_type: type of the display in usage + */ +void sde_rm_get_resource_info(struct sde_rm *rm, + struct drm_encoder *drm_enc, + struct msm_resource_caps_info *avail_res, + int display_type); +#endif /* __SDE_RM_H__ */ diff --git a/techpack/display/msm/sde/sde_trace.h b/techpack/display/msm/sde/sde_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..fbfa9aa552b0f95e527a5a84b9b0913922811436 --- /dev/null +++ b/techpack/display/msm/sde/sde_trace.h @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + */ + +#if !defined(_SDE_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _SDE_TRACE_H_ + +#include <linux/stringify.h> +#include <linux/types.h> +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sde +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE sde_trace + +TRACE_EVENT(sde_perf_set_qos_luts, + TP_PROTO(u32 pnum, u32 fmt, u32 mode, u32 danger_lut, + u32 safe_lut, u64 creq_lut), + TP_ARGS(pnum, fmt, mode, danger_lut, safe_lut, creq_lut), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, fmt) + __field(u32, mode) + __field(u32, danger_lut) + __field(u32, safe_lut) + __field(u64, creq_lut) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->fmt = fmt; + __entry->mode = mode; + __entry->danger_lut = danger_lut; + __entry->safe_lut = safe_lut; + __entry->creq_lut = creq_lut; + ), + TP_printk("pnum=%d fmt=0x%x mode=%d luts[0x%x, 0x%x 0x%llx]", + __entry->pnum, __entry->fmt, + __entry->mode, __entry->danger_lut, + __entry->safe_lut, __entry->creq_lut) +); + +TRACE_EVENT(sde_perf_set_ot, + TP_PROTO(u32 pnum, u32 xin_id, u32 rd_lim, u32 vbif_idx), + TP_ARGS(pnum, xin_id, rd_lim, vbif_idx), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, xin_id) + __field(u32, rd_lim) + __field(u32, vbif_idx) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->xin_id = xin_id; + __entry->rd_lim = rd_lim; + __entry->vbif_idx = vbif_idx; + ), + TP_printk("pnum:%d xin_id:%d ot:%d vbif:%d", + __entry->pnum, __entry->xin_id, __entry->rd_lim, + __entry->vbif_idx) +) + +TRACE_EVENT(sde_perf_update_bus, + TP_PROTO(u32 bus_id, unsigned long long ab_quota, + unsigned long long ib_quota), + TP_ARGS(bus_id, ab_quota, ib_quota), + TP_STRUCT__entry( + __field(u32, bus_id); + __field(u64, ab_quota) + __field(u64, ib_quota) + ), + TP_fast_assign( + __entry->bus_id = bus_id; + __entry->ab_quota = ab_quota; + __entry->ib_quota = ib_quota; + ), + TP_printk("Request bus_id:%d ab=%llu ib=%llu", + __entry->bus_id, + __entry->ab_quota, + __entry->ib_quota) +) + + +TRACE_EVENT(sde_cmd_release_bw, + TP_PROTO(u32 crtc_id), + TP_ARGS(crtc_id), + TP_STRUCT__entry( + __field(u32, crtc_id) + ), + TP_fast_assign( + __entry->crtc_id = crtc_id; + ), + TP_printk("crtc:%d", __entry->crtc_id) +); + +TRACE_EVENT(sde_encoder_underrun, + TP_PROTO(u32 enc_id, u32 underrun_cnt), + TP_ARGS(enc_id, underrun_cnt), + TP_STRUCT__entry( + __field(u32, enc_id) + __field(u32, underrun_cnt) + ), + TP_fast_assign( + __entry->enc_id = enc_id; + __entry->underrun_cnt = underrun_cnt; + + ), + TP_printk("enc:%d underrun_cnt:%d", __entry->enc_id, + __entry->underrun_cnt) +); + +TRACE_EVENT(tracing_mark_write, + TP_PROTO(char trace_type, const struct task_struct *task, + const char *name, int value), + TP_ARGS(trace_type, task, name, value), + TP_STRUCT__entry( + __field(char, trace_type) + __field(int, pid) + __string(trace_name, name) + __field(int, value) + ), + TP_fast_assign( + __entry->trace_type = trace_type; + __entry->pid = task ? task->tgid : 0; + __assign_str(trace_name, name); + __entry->value = value; + ), + TP_printk("%c|%d|%s|%d", __entry->trace_type, + __entry->pid, __get_str(trace_name), __entry->value) +) + +#define SDE_TRACE_EVTLOG_SIZE 15 +TRACE_EVENT(sde_evtlog, + TP_PROTO(const char *tag, u32 tag_id, u32 cnt, u32 *data), + TP_ARGS(tag, tag_id, cnt, data), + TP_STRUCT__entry( + __field(int, pid) + __string(evtlog_tag, tag) + __field(u32, tag_id) + __array(u32, data, SDE_TRACE_EVTLOG_SIZE) + ), + TP_fast_assign( + __entry->pid = current->tgid; + __assign_str(evtlog_tag, tag); + __entry->tag_id = tag_id; + if (cnt > SDE_TRACE_EVTLOG_SIZE) + cnt = SDE_TRACE_EVTLOG_SIZE; + memcpy(__entry->data, data, cnt * sizeof(u32)); + memset(&__entry->data[cnt], 0, + (SDE_TRACE_EVTLOG_SIZE - cnt) * sizeof(u32)); + ), + TP_printk("%d|%s:%d|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x|0x%x", + __entry->pid, __get_str(evtlog_tag), + __entry->tag_id, + __entry->data[0], __entry->data[1], + __entry->data[2], __entry->data[3], + __entry->data[4], __entry->data[5], + __entry->data[6], __entry->data[7], + __entry->data[8], __entry->data[9], + __entry->data[10], __entry->data[11], + __entry->data[12], __entry->data[13], + __entry->data[14]) +) + +TRACE_EVENT(sde_perf_crtc_update, + TP_PROTO(u32 crtc, + u64 bw_ctl_mnoc, u64 per_pipe_ib_mnoc, + u64 bw_ctl_llcc, u64 per_pipe_ib_llcc, + u64 bw_ctl_ebi, u64 per_pipe_ib_ebi, + u32 core_clk_rate, bool stop_req, + u32 update_bus, u32 update_clk, int params), + TP_ARGS(crtc, + bw_ctl_mnoc, per_pipe_ib_mnoc, + bw_ctl_llcc, per_pipe_ib_llcc, + bw_ctl_ebi, per_pipe_ib_ebi, + core_clk_rate, stop_req, + update_bus, update_clk, params), + TP_STRUCT__entry( + __field(u32, crtc) + __field(u64, bw_ctl_mnoc) + __field(u64, per_pipe_ib_mnoc) + __field(u64, bw_ctl_llcc) + __field(u64, per_pipe_ib_llcc) + __field(u64, bw_ctl_ebi) + __field(u64, per_pipe_ib_ebi) + __field(u32, core_clk_rate) + __field(bool, stop_req) + __field(u32, update_bus) + __field(u32, update_clk) + __field(int, params) + ), + TP_fast_assign( + __entry->crtc = crtc; + __entry->bw_ctl_mnoc = bw_ctl_mnoc; + __entry->per_pipe_ib_mnoc = per_pipe_ib_mnoc; + __entry->bw_ctl_llcc = bw_ctl_llcc; + __entry->per_pipe_ib_llcc = per_pipe_ib_llcc; + __entry->bw_ctl_ebi = bw_ctl_ebi; + __entry->per_pipe_ib_ebi = per_pipe_ib_ebi; + __entry->core_clk_rate = core_clk_rate; + __entry->stop_req = stop_req; + __entry->update_bus = update_bus; + __entry->update_clk = update_clk; + __entry->params = params; + ), + TP_printk( + "crtc=%d mnoc=[%llu %llu] llcc=[%llu %llu] ebi=[%llu %llu] clk=%u stop=%d ubus=%d uclk=%d %d", + __entry->crtc, + __entry->bw_ctl_mnoc, + __entry->per_pipe_ib_mnoc, + __entry->bw_ctl_llcc, + __entry->per_pipe_ib_llcc, + __entry->bw_ctl_ebi, + __entry->per_pipe_ib_ebi, + __entry->core_clk_rate, + __entry->stop_req, + __entry->update_bus, + __entry->update_clk, + __entry->params) +); + +TRACE_EVENT(sde_perf_calc_crtc, + TP_PROTO(u32 crtc, + u64 bw_ctl_mnoc, + u64 bw_ctl_llcc, + u64 bw_ctl_ebi, + u64 ib_mnoc, + u64 ib_llcc, + u64 ib_ebi, + u32 core_clk_rate + ), + TP_ARGS(crtc, + bw_ctl_mnoc, + bw_ctl_llcc, + bw_ctl_ebi, + ib_mnoc, + ib_llcc, + ib_ebi, + core_clk_rate), + TP_STRUCT__entry( + __field(u32, crtc) + __field(u64, bw_ctl_mnoc) + __field(u64, bw_ctl_llcc) + __field(u64, bw_ctl_ebi) + __field(u64, ib_mnoc) + __field(u64, ib_llcc) + __field(u64, ib_ebi) + __field(u32, core_clk_rate) + + ), + TP_fast_assign( + __entry->crtc = crtc; + __entry->bw_ctl_mnoc = bw_ctl_mnoc; + __entry->bw_ctl_llcc = bw_ctl_llcc; + __entry->bw_ctl_ebi = bw_ctl_ebi; + __entry->ib_mnoc = ib_mnoc; + __entry->ib_llcc = ib_llcc; + __entry->ib_ebi = ib_ebi; + __entry->core_clk_rate = core_clk_rate; + ), + TP_printk( + "crtc=%d mnoc=[%llu, %llu] llcc=[%llu %llu] ebi=[%llu, %llu] clk_rate=%u", + __entry->crtc, + __entry->bw_ctl_mnoc, + __entry->ib_mnoc, + __entry->bw_ctl_llcc, + __entry->ib_llcc, + __entry->bw_ctl_ebi, + __entry->ib_ebi, + __entry->core_clk_rate) +); + +TRACE_EVENT(sde_perf_uidle_cntr, + TP_PROTO(u32 crtc, + u32 fal1_gate_cntr, + u32 fal10_gate_cntr, + u32 fal_wait_gate_cntr, + u32 fal1_num_transitions_cntr, + u32 fal10_num_transitions_cntr, + u32 min_gate_cntr, + u32 max_gate_cntr + ), + TP_ARGS(crtc, + fal1_gate_cntr, + fal10_gate_cntr, + fal_wait_gate_cntr, + fal1_num_transitions_cntr, + fal10_num_transitions_cntr, + min_gate_cntr, + max_gate_cntr), + TP_STRUCT__entry( + __field(u32, crtc) + __field(u32, fal1_gate_cntr) + __field(u32, fal10_gate_cntr) + __field(u32, fal_wait_gate_cntr) + __field(u32, fal1_num_transitions_cntr) + __field(u32, fal10_num_transitions_cntr) + __field(u32, min_gate_cntr) + __field(u32, max_gate_cntr) + ), + TP_fast_assign( + __entry->crtc = crtc; + __entry->fal1_gate_cntr = fal1_gate_cntr; + __entry->fal10_gate_cntr = fal10_gate_cntr; + __entry->fal_wait_gate_cntr = fal_wait_gate_cntr; + __entry->fal1_num_transitions_cntr = + fal1_num_transitions_cntr; + __entry->fal10_num_transitions_cntr = + fal10_num_transitions_cntr; + __entry->min_gate_cntr = min_gate_cntr; + __entry->max_gate_cntr = max_gate_cntr; + ), + TP_printk( + "crtc:%d gate:fal1=0x%x fal10=0x%x wait=0x%x min=0x%x max=0x%x trns:fal1=0x%x fal10=0x%x", + __entry->crtc, + __entry->fal1_gate_cntr, + __entry->fal10_gate_cntr, + __entry->fal_wait_gate_cntr, + __entry->min_gate_cntr, + __entry->max_gate_cntr, + __entry->fal1_num_transitions_cntr, + __entry->fal10_num_transitions_cntr + ) +); + +TRACE_EVENT(sde_perf_uidle_status, + TP_PROTO(u32 crtc, + u32 uidle_danger_status_0, + u32 uidle_danger_status_1, + u32 uidle_safe_status_0, + u32 uidle_safe_status_1, + u32 uidle_idle_status_0, + u32 uidle_idle_status_1, + u32 uidle_fal_status_0, + u32 uidle_fal_status_1, + u32 uidle_status, + u32 uidle_en_fal10), + TP_ARGS(crtc, + uidle_danger_status_0, + uidle_danger_status_1, + uidle_safe_status_0, + uidle_safe_status_1, + uidle_idle_status_0, + uidle_idle_status_1, + uidle_fal_status_0, + uidle_fal_status_1, + uidle_status, + uidle_en_fal10), + TP_STRUCT__entry( + __field(u32, crtc) + __field(u32, uidle_danger_status_0) + __field(u32, uidle_danger_status_1) + __field(u32, uidle_safe_status_0) + __field(u32, uidle_safe_status_1) + __field(u32, uidle_idle_status_0) + __field(u32, uidle_idle_status_1) + __field(u32, uidle_fal_status_0) + __field(u32, uidle_fal_status_1) + __field(u32, uidle_status) + __field(u32, uidle_en_fal10)), + TP_fast_assign( + __entry->crtc = crtc; + __entry->uidle_danger_status_0 = uidle_danger_status_0; + __entry->uidle_danger_status_1 = uidle_danger_status_1; + __entry->uidle_safe_status_0 = uidle_safe_status_0; + __entry->uidle_safe_status_1 = uidle_safe_status_1; + __entry->uidle_idle_status_0 = uidle_idle_status_0; + __entry->uidle_idle_status_1 = uidle_idle_status_1; + __entry->uidle_fal_status_0 = uidle_fal_status_0; + __entry->uidle_fal_status_1 = uidle_fal_status_1; + __entry->uidle_status = uidle_status; + __entry->uidle_en_fal10 = uidle_en_fal10;), + TP_printk( + "crtc:%d danger[0x%x, 0x%x] safe[0x%x, 0x%x] idle[0x%x, 0x%x] fal[0x%x, 0x%x] status:0x%x en_fal10:0x%x", + __entry->crtc, + __entry->uidle_danger_status_0, + __entry->uidle_danger_status_1, + __entry->uidle_safe_status_0, + __entry->uidle_safe_status_1, + __entry->uidle_idle_status_0, + __entry->uidle_idle_status_1, + __entry->uidle_fal_status_0, + __entry->uidle_fal_status_1, + __entry->uidle_status, + __entry->uidle_en_fal10 + ) +); + +#define sde_atrace trace_tracing_mark_write + +#define SDE_ATRACE_END(name) sde_atrace('E', current, name, 0) +#define SDE_ATRACE_BEGIN(name) sde_atrace('B', current, name, 0) +#define SDE_ATRACE_FUNC() SDE_ATRACE_BEGIN(__func__) + +#define SDE_ATRACE_INT(name, value) sde_atrace('C', current, name, value) + +#endif /* _SDE_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/techpack/display/msm/sde/sde_vbif.c b/techpack/display/msm/sde/sde_vbif.c new file mode 100644 index 0000000000000000000000000000000000000000..2dd7d3e2700faa9692806924d4a2bb589902c26a --- /dev/null +++ b/techpack/display/msm/sde/sde_vbif.c @@ -0,0 +1,630 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/debugfs.h> + +#include "sde_vbif.h" +#include "sde_hw_vbif.h" +#include "sde_trace.h" +#include "sde_rotator_vbif.h" + +#define MAX_XIN_CLIENT 16 + +/** + * _sde_vbif_wait_for_xin_halt - wait for the xin to halt + * @vbif: Pointer to hardware vbif driver + * @xin_id: Client interface identifier + * @return: 0 if success; error code otherwise + */ +static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id) +{ + ktime_t timeout; + bool status; + int rc; + + if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) { + SDE_ERROR("invalid arguments vbif %d\n", !vbif); + return -EINVAL; + } + + timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout); + for (;;) { + status = vbif->ops.get_halt_ctrl(vbif, xin_id); + if (status) + break; + if (ktime_compare_safe(ktime_get(), timeout) > 0) { + status = vbif->ops.get_halt_ctrl(vbif, xin_id); + break; + } + usleep_range(501, 1000); + } + + if (!status) { + rc = -ETIMEDOUT; + SDE_ERROR("VBIF %d client %d not halting. TIMEDOUT.\n", + vbif->idx - VBIF_0, xin_id); + } else { + rc = 0; + SDE_DEBUG("VBIF %d client %d is halted\n", + vbif->idx - VBIF_0, xin_id); + } + + return rc; +} + +int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) +{ + struct sde_hw_vbif *vbif = NULL; + struct sde_hw_mdp *mdp; + bool forced_on = false; + bool status; + int rc = 0; + + if (!sde_kms) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return 0; + } + + vbif = sde_kms->hw_vbif[VBIF_RT]; + mdp = sde_kms->hw_mdp; + if (!vbif || !mdp || !vbif->ops.get_halt_ctrl || + !vbif->ops.set_halt_ctrl || + !mdp->ops.setup_clk_force_ctrl) { + SDE_ERROR("invalid vbif or mdp arguments\n"); + return -EINVAL; + } + + mutex_lock(&vbif->mutex); + + SDE_EVT32_VERBOSE(vbif->idx, xin_id); + + /* + * If status is 0, then make sure client clock is not gated + * while halting by forcing it ON only if it was not previously + * forced on. If status is 1 then its already halted. + */ + status = vbif->ops.get_halt_ctrl(vbif, xin_id); + if (status) { + mutex_unlock(&vbif->mutex); + return 0; + } + + forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true); + + /* send halt request for unused plane's xin client */ + vbif->ops.set_halt_ctrl(vbif, xin_id, true); + + rc = _sde_vbif_wait_for_xin_halt(vbif, xin_id); + if (rc) { + SDE_ERROR( + "wait failed for pipe halt:xin_id %u, clk_ctrl %u, rc %u\n", + xin_id, clk_ctrl, rc); + SDE_EVT32(xin_id, clk_ctrl, rc, SDE_EVTLOG_ERROR); + } + + /* open xin client to enable transactions */ + vbif->ops.set_halt_ctrl(vbif, xin_id, false); + if (forced_on) + mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false); + + mutex_unlock(&vbif->mutex); + + return rc; +} + +/** + * _sde_vbif_apply_dynamic_ot_limit - determine OT based on usecase parameters + * @vbif: Pointer to hardware vbif driver + * @ot_lim: Pointer to OT limit to be modified + * @params: Pointer to usecase parameters + */ +static void _sde_vbif_apply_dynamic_ot_limit(struct sde_hw_vbif *vbif, + u32 *ot_lim, struct sde_vbif_set_ot_params *params) +{ + u64 pps; + const struct sde_vbif_dynamic_ot_tbl *tbl; + u32 i; + + if (!vbif || !(vbif->cap->features & BIT(SDE_VBIF_QOS_OTLIM))) + return; + + /* Dynamic OT setting done only for WFD */ + if (!params->is_wfd) + return; + + pps = params->frame_rate; + pps *= params->width; + pps *= params->height; + + tbl = params->rd ? &vbif->cap->dynamic_ot_rd_tbl : + &vbif->cap->dynamic_ot_wr_tbl; + + for (i = 0; i < tbl->count; i++) { + if (pps <= tbl->cfg[i].pps) { + *ot_lim = tbl->cfg[i].ot_limit; + break; + } + } + + SDE_DEBUG("vbif:%d xin:%d w:%d h:%d fps:%d pps:%llu ot:%u\n", + vbif->idx - VBIF_0, params->xin_id, + params->width, params->height, params->frame_rate, + pps, *ot_lim); +} + +/** + * _sde_vbif_get_ot_limit - get OT based on usecase & configuration parameters + * @vbif: Pointer to hardware vbif driver + * @params: Pointer to usecase parameters + * @return: OT limit + */ +static u32 _sde_vbif_get_ot_limit(struct sde_hw_vbif *vbif, + struct sde_vbif_set_ot_params *params) +{ + u32 ot_lim = 0; + u32 val; + + if (!vbif || !vbif->cap) { + SDE_ERROR("invalid arguments vbif %d\n", !vbif); + return -EINVAL; + } + + if (vbif->cap->default_ot_wr_limit && !params->rd) + ot_lim = vbif->cap->default_ot_wr_limit; + else if (vbif->cap->default_ot_rd_limit && params->rd) + ot_lim = vbif->cap->default_ot_rd_limit; + + /* + * If default ot is not set from dt/catalog, + * then do not configure it. + */ + if (ot_lim == 0) + goto exit; + + /* Modify the limits if the target and the use case requires it */ + _sde_vbif_apply_dynamic_ot_limit(vbif, &ot_lim, params); + + if (vbif && vbif->ops.get_limit_conf) { + val = vbif->ops.get_limit_conf(vbif, + params->xin_id, params->rd); + if (val == ot_lim) + ot_lim = 0; + } + +exit: + SDE_DEBUG("vbif:%d xin:%d ot_lim:%d\n", + vbif->idx - VBIF_0, params->xin_id, ot_lim); + return ot_lim; +} + +/** + * sde_vbif_set_ot_limit - set OT based on usecase & configuration parameters + * @vbif: Pointer to hardware vbif driver + * @params: Pointer to usecase parameters + * + * Note this function would block waiting for bus halt. + */ +void sde_vbif_set_ot_limit(struct sde_kms *sde_kms, + struct sde_vbif_set_ot_params *params) +{ + struct sde_hw_vbif *vbif = NULL; + struct sde_hw_mdp *mdp; + bool forced_on = false; + u32 ot_lim; + int ret, i; + + if (!sde_kms) { + SDE_ERROR("invalid arguments\n"); + return; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return; + } + + mdp = sde_kms->hw_mdp; + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + if (sde_kms->hw_vbif[i] && + sde_kms->hw_vbif[i]->idx == params->vbif_idx) { + vbif = sde_kms->hw_vbif[i]; + break; + } + } + + if (!vbif || !mdp) { + SDE_DEBUG("invalid arguments vbif %d mdp %d\n", + vbif != NULL, mdp != NULL); + return; + } + + if (!mdp->ops.setup_clk_force_ctrl || + !vbif->ops.set_limit_conf || + !vbif->ops.set_halt_ctrl) + return; + + mutex_lock(&vbif->mutex); + + SDE_EVT32_VERBOSE(vbif->idx, params->xin_id); + + /* set write_gather_en for all write clients */ + if (vbif->ops.set_write_gather_en && !params->rd) + vbif->ops.set_write_gather_en(vbif, params->xin_id); + + ot_lim = _sde_vbif_get_ot_limit(vbif, params) & 0xFF; + + if (ot_lim == 0) + goto exit; + + trace_sde_perf_set_ot(params->num, params->xin_id, ot_lim, + params->vbif_idx); + + forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true); + + vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim); + + vbif->ops.set_halt_ctrl(vbif, params->xin_id, true); + + ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id); + if (ret) + SDE_EVT32(vbif->idx, params->xin_id); + + vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); + + if (forced_on) + mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false); +exit: + mutex_unlock(&vbif->mutex); +} + +void mdp_vbif_lock(struct platform_device *parent_pdev, bool enable) +{ + struct drm_device *ddev; + struct sde_kms *sde_kms; + struct sde_hw_vbif *vbif = NULL; + int i; + + ddev = platform_get_drvdata(parent_pdev); + if (!ddev || !ddev_to_msm_kms(ddev)) { + SDE_ERROR("invalid drm device\n"); + return; + } + + sde_kms = to_sde_kms(ddev_to_msm_kms(ddev)); + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + if (sde_kms->hw_vbif[i] && + sde_kms->hw_vbif[i]->idx == VBIF_RT) { + vbif = sde_kms->hw_vbif[i]; + break; + } + } + + if (!vbif) { + SDE_DEBUG("invalid vbif structure\n"); + return; + } + + if (enable) + mutex_lock(&vbif->mutex); + else + mutex_unlock(&vbif->mutex); + +} + +bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms, + struct sde_vbif_set_xin_halt_params *params) +{ + struct sde_hw_vbif *vbif = NULL; + struct sde_hw_mdp *mdp; + bool forced_on = false; + int ret, i; + + if (!sde_kms || !params) { + SDE_ERROR("invalid arguments\n"); + return false; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return true; + } + + mdp = sde_kms->hw_mdp; + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + if (sde_kms->hw_vbif[i] && + sde_kms->hw_vbif[i]->idx == params->vbif_idx) { + vbif = sde_kms->hw_vbif[i]; + break; + } + } + + if (!vbif || !mdp) { + SDE_DEBUG("invalid arguments vbif %d mdp %d\n", + vbif != NULL, mdp != NULL); + return false; + } + + if (!mdp->ops.setup_clk_force_ctrl || + !vbif->ops.set_halt_ctrl) + return false; + + mutex_lock(&vbif->mutex); + + SDE_EVT32_VERBOSE(vbif->idx, params->xin_id); + + if (params->enable) { + forced_on = mdp->ops.setup_clk_force_ctrl(mdp, + params->clk_ctrl, true); + + vbif->ops.set_halt_ctrl(vbif, params->xin_id, true); + + ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id); + if (ret) + SDE_EVT32(vbif->idx, params->xin_id, SDE_EVTLOG_ERROR); + } else { + vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); + + if (params->forced_on) + mdp->ops.setup_clk_force_ctrl(mdp, + params->clk_ctrl, false); + } + + mutex_unlock(&vbif->mutex); + + return forced_on; +} + +void sde_vbif_set_qos_remap(struct sde_kms *sde_kms, + struct sde_vbif_set_qos_params *params) +{ + struct sde_hw_vbif *vbif = NULL; + struct sde_hw_mdp *mdp; + bool forced_on = false; + const struct sde_vbif_qos_tbl *qos_tbl; + int i; + + if (!sde_kms || !params || !sde_kms->hw_mdp) { + SDE_ERROR("invalid arguments\n"); + return; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return; + } + + mdp = sde_kms->hw_mdp; + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + if (sde_kms->hw_vbif[i] && + sde_kms->hw_vbif[i]->idx == params->vbif_idx) { + vbif = sde_kms->hw_vbif[i]; + break; + } + } + + if (!vbif || !vbif->cap) { + SDE_ERROR("invalid vbif %d\n", params->vbif_idx); + return; + } + + if (!vbif->ops.set_qos_remap || !mdp->ops.setup_clk_force_ctrl) { + SDE_DEBUG("qos remap not supported\n"); + return; + } + + if (params->client_type > VBIF_MAX_CLIENT) { + SDE_ERROR("invalid client type:%d\n", params->client_type); + return; + } + + qos_tbl = &vbif->cap->qos_tbl[params->client_type]; + if (!qos_tbl->npriority_lvl || !qos_tbl->priority_lvl) { + SDE_DEBUG("qos tbl not defined\n"); + return; + } + + mutex_lock(&vbif->mutex); + + forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true); + + for (i = 0; i < qos_tbl->npriority_lvl; i++) { + SDE_DEBUG("vbif:%d xin:%d lvl:%d/%d\n", + params->vbif_idx, params->xin_id, i, + qos_tbl->priority_lvl[i]); + vbif->ops.set_qos_remap(vbif, params->xin_id, i, + qos_tbl->priority_lvl[i]); + } + + if (forced_on) + mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false); + + mutex_unlock(&vbif->mutex); +} + +void sde_vbif_clear_errors(struct sde_kms *sde_kms) +{ + struct sde_hw_vbif *vbif; + u32 i, pnd, src; + + if (!sde_kms) { + SDE_ERROR("invalid argument\n"); + return; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + vbif = sde_kms->hw_vbif[i]; + if (vbif && vbif->ops.clear_errors) { + mutex_lock(&vbif->mutex); + vbif->ops.clear_errors(vbif, &pnd, &src); + if (pnd || src) { + SDE_EVT32(i, pnd, src); + SDE_DEBUG("VBIF %d: pnd 0x%X, src 0x%X\n", + vbif->idx - VBIF_0, pnd, src); + } + mutex_unlock(&vbif->mutex); + } + } +} + +void sde_vbif_init_memtypes(struct sde_kms *sde_kms) +{ + struct sde_hw_vbif *vbif; + int i, j; + + if (!sde_kms) { + SDE_ERROR("invalid argument\n"); + return; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + vbif = sde_kms->hw_vbif[i]; + if (vbif && vbif->cap && vbif->ops.set_mem_type) { + mutex_lock(&vbif->mutex); + for (j = 0; j < vbif->cap->memtype_count; j++) + vbif->ops.set_mem_type( + vbif, j, vbif->cap->memtype[j]); + mutex_unlock(&vbif->mutex); + } + } +} + +int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask, + bool halt) +{ + struct sde_hw_vbif *vbif; + int i = 0, status, rc; + + if (!sde_kms) { + SDE_ERROR("invalid argument\n"); + return -EINVAL; + } + + vbif = sde_kms->hw_vbif[VBIF_RT]; + + if (!vbif->ops.get_halt_ctrl || !vbif->ops.set_halt_ctrl) + return 0; + + SDE_EVT32(xin_id_mask, halt); + + for (i = 0; i < MAX_XIN_CLIENT; i++) { + if (xin_id_mask & BIT(i)) { + /* unhalt the xin-clients */ + if (!halt) { + vbif->ops.set_halt_ctrl(vbif, i, false); + continue; + } + + status = vbif->ops.get_halt_ctrl(vbif, i); + if (status) + continue; + + /* halt xin-clients and wait for ack */ + vbif->ops.set_halt_ctrl(vbif, i, true); + + rc = _sde_vbif_wait_for_xin_halt(vbif, i); + if (rc) { + SDE_ERROR("xin_halt failed for xin:%d, rc:%d\n", + i, rc); + SDE_EVT32(xin_id_mask, i, rc, SDE_EVTLOG_ERROR); + return rc; + } + } + } + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms) +{ + debugfs_remove_recursive(sde_kms->debugfs_vbif); + sde_kms->debugfs_vbif = NULL; +} + +int sde_debugfs_vbif_init(struct sde_kms *sde_kms, struct dentry *debugfs_root) +{ + char vbif_name[32]; + struct dentry *debugfs_vbif; + int i, j; + + sde_kms->debugfs_vbif = debugfs_create_dir("vbif", debugfs_root); + if (!sde_kms->debugfs_vbif) { + SDE_ERROR("failed to create vbif debugfs\n"); + return -EINVAL; + } + + for (i = 0; i < sde_kms->catalog->vbif_count; i++) { + struct sde_vbif_cfg *vbif = &sde_kms->catalog->vbif[i]; + + snprintf(vbif_name, sizeof(vbif_name), "%d", vbif->id); + + debugfs_vbif = debugfs_create_dir(vbif_name, + sde_kms->debugfs_vbif); + + debugfs_create_u32("features", 0400, debugfs_vbif, + (u32 *)&vbif->features); + + debugfs_create_u32("xin_halt_timeout", 0400, debugfs_vbif, + (u32 *)&vbif->xin_halt_timeout); + + debugfs_create_u32("default_rd_ot_limit", 0400, debugfs_vbif, + (u32 *)&vbif->default_ot_rd_limit); + + debugfs_create_u32("default_wr_ot_limit", 0400, debugfs_vbif, + (u32 *)&vbif->default_ot_wr_limit); + + for (j = 0; j < vbif->dynamic_ot_rd_tbl.count; j++) { + struct sde_vbif_dynamic_ot_cfg *cfg = + &vbif->dynamic_ot_rd_tbl.cfg[j]; + + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_rd_%d_pps", j); + debugfs_create_u64(vbif_name, 0400, debugfs_vbif, + (u64 *)&cfg->pps); + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_rd_%d_ot_limit", j); + debugfs_create_u32(vbif_name, 0400, debugfs_vbif, + (u32 *)&cfg->ot_limit); + } + + for (j = 0; j < vbif->dynamic_ot_wr_tbl.count; j++) { + struct sde_vbif_dynamic_ot_cfg *cfg = + &vbif->dynamic_ot_wr_tbl.cfg[j]; + + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_wr_%d_pps", j); + debugfs_create_u64(vbif_name, 0400, debugfs_vbif, + (u64 *)&cfg->pps); + snprintf(vbif_name, sizeof(vbif_name), + "dynamic_ot_wr_%d_ot_limit", j); + debugfs_create_u32(vbif_name, 0400, debugfs_vbif, + (u32 *)&cfg->ot_limit); + } + } + + return 0; +} +#endif diff --git a/techpack/display/msm/sde/sde_vbif.h b/techpack/display/msm/sde/sde_vbif.h new file mode 100644 index 0000000000000000000000000000000000000000..b16e0c757cdb9b56aa90e7a7362887468202f6f5 --- /dev/null +++ b/techpack/display/msm/sde/sde_vbif.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_VBIF_H__ +#define __SDE_VBIF_H__ + +#include "sde_kms.h" + +struct sde_vbif_set_ot_params { + u32 xin_id; + u32 num; + u32 width; + u32 height; + u32 frame_rate; + bool rd; + bool is_wfd; + u32 vbif_idx; + u32 clk_ctrl; +}; + +struct sde_vbif_set_memtype_params { + u32 xin_id; + u32 vbif_idx; + u32 clk_ctrl; + bool is_cacheable; +}; + +/** + * struct sde_vbif_set_xin_halt_params - xin halt parameters + * @vbif_idx: vbif identifier + * @xin_id: client interface identifier + * @clk_ctrl: clock control identifier of the xin + * @forced_on: whether or not previous call to xin halt forced the clocks on, + * only applicable to xin halt disable calls + * @enable: whether to enable/disable xin halts + */ +struct sde_vbif_set_xin_halt_params { + u32 vbif_idx; + u32 xin_id; + u32 clk_ctrl; + bool forced_on; + bool enable; +}; + +/** + * struct sde_vbif_set_qos_params - QoS remapper parameter + * @vbif_idx: vbif identifier + * @xin_id: client interface identifier + * @clk_ctrl: clock control identifier of the xin + * @num: pipe identifier (debug only) + * @client_type: client type enumerated by sde_vbif_client_type + */ +struct sde_vbif_set_qos_params { + u32 vbif_idx; + u32 xin_id; + u32 clk_ctrl; + u32 num; + enum sde_vbif_client_type client_type; +}; + +/** + * sde_vbif_set_ot_limit - set OT limit for vbif client + * @sde_kms: SDE handler + * @params: Pointer to OT configuration parameters + */ +void sde_vbif_set_ot_limit(struct sde_kms *sde_kms, + struct sde_vbif_set_ot_params *params); + +/** + * sde_vbif_set_xin_halt - halt one of the xin ports + * This function isn't thread safe. + * @sde_kms: SDE handler + * @params: Pointer to halt configuration parameters + * Returns: Whether or not VBIF clocks were forced on + */ +bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms, + struct sde_vbif_set_xin_halt_params *params); + +/** + * sde_vbif_set_qos_remap - set QoS priority level remap + * @sde_kms: SDE handler + * @params: Pointer to QoS configuration parameters + */ +void sde_vbif_set_qos_remap(struct sde_kms *sde_kms, + struct sde_vbif_set_qos_params *params); + +/** + * sde_vbif_clear_errors - clear any vbif errors + * @sde_kms: SDE handler + */ +void sde_vbif_clear_errors(struct sde_kms *sde_kms); + +/** + * sde_vbif_init_memtypes - initialize xin memory types for vbif + * @sde_kms: SDE handler + */ +void sde_vbif_init_memtypes(struct sde_kms *sde_kms); + +/** + * sde_vbif_halt_plane_xin - halts the xin client for the unused plane + * On unused plane, check if the vbif for this plane is idle or not. + * If not then first force_on the planes clock and then send the + * halt request. Wait for some time then check for the vbif idle + * or not again. + * @sde_kms: SDE handler + * @xin_id: xin id of the unused plane + * @clk_ctrl: clk ctrl type for the unused plane + * Returns: 0 on success, error code otherwise + */ +int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, + u32 clk_ctrl); + +/** + * sde_vbif_halt_xin_mask - halts/unhalts all the xin clients present in + * the mask. + * @sde_kms: SDE handler + * @xin_id_mask: Mask of all the xin-ids to be halted/unhalted + * halt: boolen to indicate halt/unhalt + */ +int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask, bool halt); + +#ifdef CONFIG_DEBUG_FS +int sde_debugfs_vbif_init(struct sde_kms *sde_kms, struct dentry *debugfs_root); +void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms); +#else +static inline int sde_debugfs_vbif_init(struct sde_kms *sde_kms, + struct dentry *debugfs_root) +{ + return 0; +} +static inline void sde_debugfs_vbif_destroy(struct sde_kms *sde_kms) +{ +} +#endif +#endif /* __SDE_VBIF_H__ */ diff --git a/techpack/display/msm/sde/sde_wb.c b/techpack/display/msm/sde/sde_wb.c new file mode 100644 index 0000000000000000000000000000000000000000..4fcc2c316d3df4f7063739274290be4387b5aa7b --- /dev/null +++ b/techpack/display/msm/sde/sde_wb.c @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <uapi/drm/sde_drm.h> + +#include "msm_kms.h" +#include "sde_kms.h" +#include "sde_wb.h" +#include "sde_formats.h" + +/* maximum display mode resolution if not available from catalog */ +#define SDE_WB_MODE_MAX_WIDTH 4096 +#define SDE_WB_MODE_MAX_HEIGHT 4096 + +/* Serialization lock for sde_wb_list */ +static DEFINE_MUTEX(sde_wb_list_lock); + +/* List of all writeback devices installed */ +static LIST_HEAD(sde_wb_list); + +/** + * sde_wb_is_format_valid - check if given format/modifier is supported + * @wb_dev: Pointer to writeback device + * @pixel_format: Fourcc pixel format + * @format_modifier: Format modifier + * Returns: true if valid; false otherwise + */ +static int sde_wb_is_format_valid(struct sde_wb_device *wb_dev, + u32 pixel_format, u64 format_modifier) +{ + const struct sde_format_extended *fmts = wb_dev->wb_cfg->format_list; + int i; + + if (!fmts) + return false; + + for (i = 0; fmts[i].fourcc_format; i++) + if ((fmts[i].modifier == format_modifier) && + (fmts[i].fourcc_format == pixel_format)) + return true; + + return false; +} + +enum drm_connector_status +sde_wb_connector_detect(struct drm_connector *connector, + bool force, + void *display) +{ + enum drm_connector_status rc = connector_status_unknown; + + SDE_DEBUG("\n"); + + if (display) + rc = ((struct sde_wb_device *)display)->detect_status; + + return rc; +} + +int sde_wb_connector_get_modes(struct drm_connector *connector, void *display, + const struct msm_resource_caps_info *avail_res) +{ + struct sde_wb_device *wb_dev; + int num_modes = 0; + + if (!connector || !display) + return 0; + + wb_dev = display; + + SDE_DEBUG("\n"); + + mutex_lock(&wb_dev->wb_lock); + if (wb_dev->count_modes && wb_dev->modes) { + struct drm_display_mode *mode; + int i, ret; + + for (i = 0; i < wb_dev->count_modes; i++) { + mode = drm_mode_create(connector->dev); + if (!mode) { + SDE_ERROR("failed to create mode\n"); + break; + } + ret = drm_mode_convert_umode(wb_dev->drm_dev, mode, + &wb_dev->modes[i]); + if (ret) { + SDE_ERROR("failed to convert mode %d\n", ret); + break; + } + + drm_mode_probed_add(connector, mode); + num_modes++; + } + } else { + u32 max_width = (wb_dev->wb_cfg && wb_dev->wb_cfg->sblk) ? + wb_dev->wb_cfg->sblk->maxlinewidth : + SDE_WB_MODE_MAX_WIDTH; + + num_modes = drm_add_modes_noedid(connector, max_width, + SDE_WB_MODE_MAX_HEIGHT); + } + mutex_unlock(&wb_dev->wb_lock); + return num_modes; +} + +struct drm_framebuffer * +sde_wb_connector_state_get_output_fb(struct drm_connector_state *state) +{ + if (!state || !state->connector || + (state->connector->connector_type != + DRM_MODE_CONNECTOR_VIRTUAL)) { + SDE_ERROR("invalid params\n"); + return NULL; + } + + SDE_DEBUG("\n"); + + return sde_connector_get_out_fb(state); +} + +int sde_wb_connector_state_get_output_roi(struct drm_connector_state *state, + struct sde_rect *roi) +{ + if (!state || !roi || !state->connector || + (state->connector->connector_type != + DRM_MODE_CONNECTOR_VIRTUAL)) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + roi->x = sde_connector_get_property(state, CONNECTOR_PROP_DST_X); + roi->y = sde_connector_get_property(state, CONNECTOR_PROP_DST_Y); + roi->w = sde_connector_get_property(state, CONNECTOR_PROP_DST_W); + roi->h = sde_connector_get_property(state, CONNECTOR_PROP_DST_H); + + return 0; +} + +/** + * sde_wb_connector_set_modes - set writeback modes and connection status + * @wb_dev: Pointer to write back device + * @count_modes: Count of modes + * @modes: Pointer to writeback mode requested + * @connected: Connection status requested + * Returns: 0 if success; error code otherwise + */ +static +int sde_wb_connector_set_modes(struct sde_wb_device *wb_dev, + u32 count_modes, struct drm_mode_modeinfo __user *modes, + bool connected) +{ + struct drm_mode_modeinfo *modeinfo = NULL; + int ret = 0; + int i; + + if (!wb_dev || !wb_dev->connector || + (wb_dev->connector->connector_type != + DRM_MODE_CONNECTOR_VIRTUAL)) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + if (connected) { + SDE_DEBUG("connect\n"); + + if (!count_modes || !modes) { + SDE_ERROR("invalid count_modes :%u and modes :%d\n", + count_modes, !modes); + return -EINVAL; + } + + modeinfo = kcalloc(count_modes, + sizeof(struct drm_mode_modeinfo), + GFP_KERNEL); + if (!modeinfo) { + SDE_ERROR("invalid params\n"); + ret = -ENOMEM; + goto error; + } + + if (copy_from_user(modeinfo, modes, + count_modes * + sizeof(struct drm_mode_modeinfo))) { + SDE_ERROR("failed to copy modes\n"); + kfree(modeinfo); + ret = -EFAULT; + goto error; + } + + for (i = 0; i < count_modes; i++) { + struct drm_display_mode dispmode; + + memset(&dispmode, 0, sizeof(dispmode)); + ret = drm_mode_convert_umode(wb_dev->drm_dev, + &dispmode, &modeinfo[i]); + if (ret) { + SDE_ERROR( + "failed to convert mode %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x status:%d rc:%d\n", + i, + modeinfo[i].name, + modeinfo[i].vrefresh, + modeinfo[i].clock, + modeinfo[i].hdisplay, + modeinfo[i].hsync_start, + modeinfo[i].hsync_end, + modeinfo[i].htotal, + modeinfo[i].vdisplay, + modeinfo[i].vsync_start, + modeinfo[i].vsync_end, + modeinfo[i].vtotal, + modeinfo[i].type, + modeinfo[i].flags, + dispmode.status, + ret); + kfree(modeinfo); + goto error; + } + } + + if (wb_dev->modes) { + wb_dev->count_modes = 0; + + kfree(wb_dev->modes); + wb_dev->modes = NULL; + } + + wb_dev->count_modes = count_modes; + wb_dev->modes = modeinfo; + wb_dev->detect_status = connector_status_connected; + } else { + SDE_DEBUG("disconnect\n"); + + if (wb_dev->modes) { + wb_dev->count_modes = 0; + + kfree(wb_dev->modes); + wb_dev->modes = NULL; + } + + wb_dev->detect_status = connector_status_disconnected; + } + +error: + return ret; +} + +int sde_wb_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t value, + void *display) +{ + struct sde_wb_device *wb_dev = display; + struct drm_framebuffer *out_fb; + int rc = 0; + + SDE_DEBUG("\n"); + + if (state && (property_index == CONNECTOR_PROP_OUT_FB)) { + const struct sde_format *sde_format; + + out_fb = sde_connector_get_out_fb(state); + if (!out_fb) + goto done; + + sde_format = sde_get_sde_format_ext(out_fb->format->format, + out_fb->modifier); + if (!sde_format) { + SDE_ERROR("failed to get sde format\n"); + rc = -EINVAL; + goto done; + } + + if (!sde_wb_is_format_valid(wb_dev, out_fb->format->format, + out_fb->modifier)) { + SDE_ERROR("unsupported writeback format 0x%x/0x%llx\n", + out_fb->format->format, + out_fb->modifier); + rc = -EINVAL; + goto done; + } + } + +done: + return rc; +} + +int sde_wb_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *display) +{ + struct sde_wb_device *wb_dev = display; + + if (!info || !wb_dev) { + pr_err("invalid params\n"); + return -EINVAL; + } + + memset(info, 0, sizeof(struct msm_display_info)); + info->intf_type = DRM_MODE_CONNECTOR_VIRTUAL; + info->num_of_h_tiles = 1; + info->h_tile_instance[0] = sde_wb_get_index(display); + info->is_connected = true; + info->capabilities = MSM_DISPLAY_CAP_HOT_PLUG | MSM_DISPLAY_CAP_EDID; + info->max_width = (wb_dev->wb_cfg && wb_dev->wb_cfg->sblk) ? + wb_dev->wb_cfg->sblk->maxlinewidth : + SDE_WB_MODE_MAX_WIDTH; + info->max_height = SDE_WB_MODE_MAX_HEIGHT; + return 0; +} + +int sde_wb_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res) +{ + const u32 dual_lm = 2; + const u32 single_lm = 1; + const u32 single_intf = 1; + const u32 no_enc = 0; + struct msm_display_topology *topology; + struct sde_wb_device *wb_dev = display; + u16 hdisplay; + int i; + + if (!drm_mode || !mode_info || !avail_res || + !avail_res->max_mixer_width || !display) { + pr_err("invalid params\n"); + return -EINVAL; + } + + hdisplay = drm_mode->hdisplay; + + /* find maximum display width to support */ + for (i = 0; i < wb_dev->count_modes; i++) + hdisplay = max(hdisplay, wb_dev->modes[i].hdisplay); + + topology = &mode_info->topology; + topology->num_lm = (avail_res->max_mixer_width <= hdisplay) ? + dual_lm : single_lm; + topology->num_enc = no_enc; + topology->num_intf = single_intf; + + mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; + mode_info->wide_bus_en = false; + mode_info->comp_info.comp_ratio = MSM_DISPLAY_COMPRESSION_RATIO_NONE; + + return 0; +} + +int sde_wb_connector_set_info_blob(struct drm_connector *connector, + void *info, void *display, struct msm_mode_info *mode_info) +{ + struct sde_wb_device *wb_dev = display; + const struct sde_format_extended *format_list; + + if (!connector || !info || !display || !wb_dev->wb_cfg) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + format_list = wb_dev->wb_cfg->format_list; + + /* + * Populate info buffer + */ + if (format_list) { + sde_kms_info_start(info, "pixel_formats"); + while (format_list->fourcc_format) { + sde_kms_info_append_format(info, + format_list->fourcc_format, + format_list->modifier); + ++format_list; + } + sde_kms_info_stop(info); + } + + sde_kms_info_add_keyint(info, + "wb_intf_index", + wb_dev->wb_idx - WB_0); + + sde_kms_info_add_keyint(info, + "maxlinewidth", + wb_dev->wb_cfg->sblk->maxlinewidth); + + sde_kms_info_start(info, "features"); + if (wb_dev->wb_cfg && (wb_dev->wb_cfg->features & BIT(SDE_WB_UBWC))) + sde_kms_info_append(info, "wb_ubwc"); + sde_kms_info_stop(info); + + return 0; +} + +int sde_wb_connector_post_init(struct drm_connector *connector, void *display) +{ + struct sde_connector *c_conn; + struct sde_wb_device *wb_dev = display; + static const struct drm_prop_enum_list e_fb_translation_mode[] = { + {SDE_DRM_FB_NON_SEC, "non_sec"}, + {SDE_DRM_FB_SEC, "sec"}, + }; + + if (!connector || !display || !wb_dev->wb_cfg) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + c_conn = to_sde_connector(connector); + wb_dev->connector = connector; + wb_dev->detect_status = connector_status_connected; + + /* + * Add extra connector properties + */ + msm_property_install_range(&c_conn->property_info, "FB_ID", + 0x0, 0, ~0, 0, CONNECTOR_PROP_OUT_FB); + msm_property_install_range(&c_conn->property_info, "DST_X", + 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_X); + msm_property_install_range(&c_conn->property_info, "DST_Y", + 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_Y); + msm_property_install_range(&c_conn->property_info, "DST_W", + 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_W); + msm_property_install_range(&c_conn->property_info, "DST_H", + 0x0, 0, UINT_MAX, 0, CONNECTOR_PROP_DST_H); + msm_property_install_enum(&c_conn->property_info, + "fb_translation_mode", + 0x0, + 0, e_fb_translation_mode, + ARRAY_SIZE(e_fb_translation_mode), + CONNECTOR_PROP_FB_TRANSLATION_MODE); + + return 0; +} + +struct drm_framebuffer *sde_wb_get_output_fb(struct sde_wb_device *wb_dev) +{ + struct drm_framebuffer *fb; + + if (!wb_dev || !wb_dev->connector) { + SDE_ERROR("invalid params\n"); + return NULL; + } + + SDE_DEBUG("\n"); + + mutex_lock(&wb_dev->wb_lock); + fb = sde_wb_connector_state_get_output_fb(wb_dev->connector->state); + mutex_unlock(&wb_dev->wb_lock); + + return fb; +} + +int sde_wb_get_output_roi(struct sde_wb_device *wb_dev, struct sde_rect *roi) +{ + int rc; + + if (!wb_dev || !wb_dev->connector || !roi) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + mutex_lock(&wb_dev->wb_lock); + rc = sde_wb_connector_state_get_output_roi( + wb_dev->connector->state, roi); + mutex_unlock(&wb_dev->wb_lock); + + return rc; +} + +u32 sde_wb_get_num_of_displays(void) +{ + u32 count = 0; + struct sde_wb_device *wb_dev; + + SDE_DEBUG("\n"); + + mutex_lock(&sde_wb_list_lock); + list_for_each_entry(wb_dev, &sde_wb_list, wb_list) { + count++; + } + mutex_unlock(&sde_wb_list_lock); + + return count; +} + +int wb_display_get_displays(void **display_array, u32 max_display_count) +{ + struct sde_wb_device *curr; + int i = 0; + + SDE_DEBUG("\n"); + + if (!display_array || !max_display_count) { + if (!display_array) + SDE_ERROR("invalid param\n"); + return 0; + } + + mutex_lock(&sde_wb_list_lock); + list_for_each_entry(curr, &sde_wb_list, wb_list) { + if (i >= max_display_count) + break; + display_array[i++] = curr; + } + mutex_unlock(&sde_wb_list_lock); + + return i; +} + +int sde_wb_config(struct drm_device *drm_dev, void *data, + struct drm_file *file_priv) +{ + struct sde_drm_wb_cfg *config = data; + struct msm_drm_private *priv; + struct sde_wb_device *wb_dev = NULL; + struct sde_wb_device *curr; + struct drm_connector *connector; + uint32_t flags; + uint32_t connector_id; + uint32_t count_modes; + uint64_t modes; + int rc; + + if (!drm_dev || !data) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + flags = config->flags; + connector_id = config->connector_id; + count_modes = config->count_modes; + modes = config->modes; + + priv = drm_dev->dev_private; + + connector = drm_connector_lookup(drm_dev, file_priv, connector_id); + if (!connector) { + SDE_ERROR("failed to find connector\n"); + rc = -ENOENT; + goto fail; + } + + mutex_lock(&sde_wb_list_lock); + list_for_each_entry(curr, &sde_wb_list, wb_list) { + if (curr->connector == connector) { + wb_dev = curr; + break; + } + } + mutex_unlock(&sde_wb_list_lock); + + if (!wb_dev) { + SDE_ERROR("failed to find wb device\n"); + rc = -ENOENT; + goto fail; + } + + mutex_lock(&wb_dev->wb_lock); + + rc = sde_wb_connector_set_modes(wb_dev, count_modes, + (struct drm_mode_modeinfo __user *) (uintptr_t) modes, + (flags & SDE_DRM_WB_CFG_FLAGS_CONNECTED) ? true : false); + + mutex_unlock(&wb_dev->wb_lock); + drm_helper_hpd_irq_event(drm_dev); +fail: + return rc; +} + +/** + * _sde_wb_dev_init - perform device initialization + * @wb_dev: Pointer to writeback device + */ +static int _sde_wb_dev_init(struct sde_wb_device *wb_dev) +{ + int rc = 0; + + if (!wb_dev) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + return rc; +} + +/** + * _sde_wb_dev_deinit - perform device de-initialization + * @wb_dev: Pointer to writeback device + */ +static int _sde_wb_dev_deinit(struct sde_wb_device *wb_dev) +{ + int rc = 0; + + if (!wb_dev) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + return rc; +} + +/** + * sde_wb_bind - bind writeback device with controlling device + * @dev: Pointer to base of platform device + * @master: Pointer to container of drm device + * @data: Pointer to private data + * Returns: Zero on success + */ +static int sde_wb_bind(struct device *dev, struct device *master, void *data) +{ + struct sde_wb_device *wb_dev; + + if (!dev || !master) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + wb_dev = platform_get_drvdata(to_platform_device(dev)); + if (!wb_dev) { + SDE_ERROR("invalid wb device\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + mutex_lock(&wb_dev->wb_lock); + wb_dev->drm_dev = dev_get_drvdata(master); + mutex_unlock(&wb_dev->wb_lock); + + return 0; +} + +/** + * sde_wb_unbind - unbind writeback from controlling device + * @dev: Pointer to base of platform device + * @master: Pointer to container of drm device + * @data: Pointer to private data + */ +static void sde_wb_unbind(struct device *dev, + struct device *master, void *data) +{ + struct sde_wb_device *wb_dev; + + if (!dev) { + SDE_ERROR("invalid params\n"); + return; + } + + wb_dev = platform_get_drvdata(to_platform_device(dev)); + if (!wb_dev) { + SDE_ERROR("invalid wb device\n"); + return; + } + + SDE_DEBUG("\n"); + + mutex_lock(&wb_dev->wb_lock); + wb_dev->drm_dev = NULL; + mutex_unlock(&wb_dev->wb_lock); +} + +static const struct component_ops sde_wb_comp_ops = { + .bind = sde_wb_bind, + .unbind = sde_wb_unbind, +}; + +/** + * sde_wb_drm_init - perform DRM initialization + * @wb_dev: Pointer to writeback device + * @encoder: Pointer to associated encoder + */ +int sde_wb_drm_init(struct sde_wb_device *wb_dev, struct drm_encoder *encoder) +{ + int rc = 0; + + if (!wb_dev || !wb_dev->drm_dev || !encoder) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + mutex_lock(&wb_dev->wb_lock); + + if (wb_dev->drm_dev->dev_private) { + struct msm_drm_private *priv = wb_dev->drm_dev->dev_private; + struct sde_kms *sde_kms = to_sde_kms(priv->kms); + + if (wb_dev->index < sde_kms->catalog->wb_count) { + wb_dev->wb_idx = sde_kms->catalog->wb[wb_dev->index].id; + wb_dev->wb_cfg = &sde_kms->catalog->wb[wb_dev->index]; + } + } + + wb_dev->drm_dev = encoder->dev; + wb_dev->encoder = encoder; + mutex_unlock(&wb_dev->wb_lock); + return rc; +} + +int sde_wb_drm_deinit(struct sde_wb_device *wb_dev) +{ + int rc = 0; + + if (!wb_dev) { + SDE_ERROR("invalid params\n"); + return -EINVAL; + } + + SDE_DEBUG("\n"); + + return rc; +} + +/** + * sde_wb_probe - load writeback module + * @pdev: Pointer to platform device + */ +static int sde_wb_probe(struct platform_device *pdev) +{ + struct sde_wb_device *wb_dev; + int ret; + + wb_dev = devm_kzalloc(&pdev->dev, sizeof(*wb_dev), GFP_KERNEL); + if (!wb_dev) + return -ENOMEM; + + SDE_DEBUG("\n"); + + ret = of_property_read_u32(pdev->dev.of_node, "cell-index", + &wb_dev->index); + if (ret) { + SDE_DEBUG("cell index not set, default to 0\n"); + wb_dev->index = 0; + } + + wb_dev->name = of_get_property(pdev->dev.of_node, "label", NULL); + if (!wb_dev->name) { + SDE_DEBUG("label not set, default to unknown\n"); + wb_dev->name = "unknown"; + } + + wb_dev->wb_idx = SDE_NONE; + + mutex_init(&wb_dev->wb_lock); + platform_set_drvdata(pdev, wb_dev); + + mutex_lock(&sde_wb_list_lock); + list_add(&wb_dev->wb_list, &sde_wb_list); + mutex_unlock(&sde_wb_list_lock); + + if (!_sde_wb_dev_init(wb_dev)) { + ret = component_add(&pdev->dev, &sde_wb_comp_ops); + if (ret) + pr_err("component add failed\n"); + } + + return ret; +} + +/** + * sde_wb_remove - unload writeback module + * @pdev: Pointer to platform device + */ +static int sde_wb_remove(struct platform_device *pdev) +{ + struct sde_wb_device *wb_dev; + struct sde_wb_device *curr, *next; + + wb_dev = platform_get_drvdata(pdev); + if (!wb_dev) + return 0; + + SDE_DEBUG("\n"); + + (void)_sde_wb_dev_deinit(wb_dev); + + mutex_lock(&sde_wb_list_lock); + list_for_each_entry_safe(curr, next, &sde_wb_list, wb_list) { + if (curr == wb_dev) { + list_del(&wb_dev->wb_list); + break; + } + } + mutex_unlock(&sde_wb_list_lock); + + kfree(wb_dev->modes); + mutex_destroy(&wb_dev->wb_lock); + + platform_set_drvdata(pdev, NULL); + devm_kfree(&pdev->dev, wb_dev); + + return 0; +} + +static const struct of_device_id dt_match[] = { + { .compatible = "qcom,wb-display"}, + {} +}; + +static struct platform_driver sde_wb_driver = { + .probe = sde_wb_probe, + .remove = sde_wb_remove, + .driver = { + .name = "sde_wb", + .of_match_table = dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init sde_wb_register(void) +{ + return platform_driver_register(&sde_wb_driver); +} + +static void __exit sde_wb_unregister(void) +{ + platform_driver_unregister(&sde_wb_driver); +} + +module_init(sde_wb_register); +module_exit(sde_wb_unregister); diff --git a/techpack/display/msm/sde/sde_wb.h b/techpack/display/msm/sde/sde_wb.h new file mode 100644 index 0000000000000000000000000000000000000000..51f63d955c306bba4eea2225e2467f3e533a3dc7 --- /dev/null +++ b/techpack/display/msm/sde/sde_wb.h @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_WB_H__ +#define __SDE_WB_H__ + +#include <linux/platform_device.h> + +#include "msm_kms.h" +#include "sde_kms.h" +#include "sde_connector.h" + +/** + * struct sde_wb_device - Writeback device context + * @drm_dev: Pointer to controlling DRM device + * @index: Index of hardware instance from device tree + * @wb_idx: Writeback identifier of enum sde_wb + * @wb_cfg: Writeback configuration catalog + * @name: Name of writeback device from device tree + * @display_type: Display type from device tree + * @wb_list List of all writeback devices + * @wb_lock Serialization lock for writeback context structure + * @connector: Connector associated with writeback device + * @encoder: Encoder associated with writeback device + * @max_mixer_width: Max width supported by SDE LM HW block + * @count_modes: Length of writeback connector modes array + * @modes: Writeback connector modes array + */ +struct sde_wb_device { + struct drm_device *drm_dev; + + u32 index; + u32 wb_idx; + struct sde_wb_cfg *wb_cfg; + const char *name; + + struct list_head wb_list; + struct mutex wb_lock; + + struct drm_connector *connector; + struct drm_encoder *encoder; + + enum drm_connector_status detect_status; + u32 max_mixer_width; + + u32 count_modes; + struct drm_mode_modeinfo *modes; +}; + +/** + * sde_wb_get_index - get device index of the given writeback device + * @wb_dev: Pointer to writeback device + * Returns: Index of hardware instance + */ +static inline +int sde_wb_get_index(struct sde_wb_device *wb_dev) +{ + return wb_dev ? wb_dev->index : -1; +} + +#ifdef CONFIG_DRM_SDE_WB +/** + * sde_wb_get_output_fb - get framebuffer in current atomic state + * @wb_dev: Pointer to writeback device + * Returns: Pointer to framebuffer + */ +struct drm_framebuffer *sde_wb_get_output_fb(struct sde_wb_device *wb_dev); + +/** + * sde_wb_get_output_roi - get region-of-interest in current atomic state + * @wb_dev: Pointer to writeback device + * @roi: Pointer to region of interest + * Returns: 0 if success; error code otherwise + */ +int sde_wb_get_output_roi(struct sde_wb_device *wb_dev, struct sde_rect *roi); + +/** + * sde_wb_get_num_of_displays - get total number of writeback devices + * Returns: Number of writeback devices + */ +u32 sde_wb_get_num_of_displays(void); + +/** + * wb_display_get_displays - returns pointers for supported display devices + * @display_array: Pointer to display array to be filled + * @max_display_count: Size of display_array + * @Returns: Number of display entries filled + */ +int wb_display_get_displays(void **display_array, u32 max_display_count); + +void sde_wb_set_active_state(struct sde_wb_device *wb_dev, bool is_active); +bool sde_wb_is_active(struct sde_wb_device *wb_dev); + +/** + * sde_wb_drm_init - perform DRM initialization + * @wb_dev: Pointer to writeback device + * @encoder: Pointer to associated encoder + * Returns: 0 if success; error code otherwise + */ +int sde_wb_drm_init(struct sde_wb_device *wb_dev, struct drm_encoder *encoder); + +/** + * sde_wb_drm_deinit - perform DRM de-initialization + * @wb_dev: Pointer to writeback device + * Returns: 0 if success; error code otherwise + */ +int sde_wb_drm_deinit(struct sde_wb_device *wb_dev); + +/** + * sde_wb_config - setup connection status and available drm modes of the + * given writeback connector + * @drm_dev: Pointer to DRM device + * @data: Pointer to writeback configuration + * @file_priv: Pointer file private data + * Returns: 0 if success; error code otherwise + * + * This function will initiate hot-plug detection event. + */ +int sde_wb_config(struct drm_device *drm_dev, void *data, + struct drm_file *file_priv); + +/** + * sde_wb_connector_post_init - perform writeback specific initialization + * @connector: Pointer to drm connector structure + * @display: Pointer to private display structure + * Returns: Zero on success + */ +int sde_wb_connector_post_init(struct drm_connector *connector, void *display); + +/** + * sde_wb_connector_set_info_blob - perform writeback info blob initialization + * @connector: Pointer to drm connector structure + * @info: Pointer to connector info + * @display: Pointer to private display structure + * @mode_info: Pointer to the mode info structure + * Returns: Zero on success + */ +int sde_wb_connector_set_info_blob(struct drm_connector *connector, + void *info, + void *display, + struct msm_mode_info *mode_info); + +/** + * sde_wb_connector_detect - perform writeback connection status detection + * @connector: Pointer to connector + * @force: Indicate force detection + * @display: Pointer to writeback device + * Returns: connector status + */ +enum drm_connector_status +sde_wb_connector_detect(struct drm_connector *connector, + bool force, + void *display); + +/** + * sde_wb_connector_get_modes - get display modes of connector + * @connector: Pointer to connector + * @display: Pointer to writeback device + * @avail_res: Pointer with curr available resources + * Returns: Number of modes + * + * If display modes are not specified in writeback configuration IOCTL, this + * function will install default EDID modes up to maximum resolution support. + */ +int sde_wb_connector_get_modes(struct drm_connector *connector, void *display, + const struct msm_resource_caps_info *avail_res); + +/** + * sde_wb_connector_set_property - set atomic connector property + * @connector: Pointer to drm connector structure + * @state: Pointer to drm connector state structure + * @property_index: DRM property index + * @value: Incoming property value + * @display: Pointer to private display structure + * Returns: Zero on success + */ +int sde_wb_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t value, + void *display); + +/** + * sde_wb_get_info - retrieve writeback 'display' information + * @connector: Pointer to drm connector structure + * @info: Pointer to display info structure + * @display: Pointer to private display structure + * Returns: Zero on success + */ +int sde_wb_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *display); + +/** + * sde_wb_get_mode_info - retrieve information of the mode selected + * @connector: Pointer to drm connector structure + * @drm_mode: Display mode set for the display + * @mode_info: Out parameter. information of the mode. + * @display: Pointer to private display structure + * @avail_res: Pointer with curr available resources + * Returns: zero on success + */ +int sde_wb_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res); + +/** + * sde_wb_connector_get_wb - retrieve writeback device of the given connector + * @connector: Pointer to drm connector + * Returns: Pointer to writeback device on success; NULL otherwise + */ +static inline +struct sde_wb_device *sde_wb_connector_get_wb(struct drm_connector *connector) +{ + if (!connector || + (connector->connector_type != DRM_MODE_CONNECTOR_VIRTUAL)) { + SDE_ERROR("invalid params\n"); + return NULL; + } + + return sde_connector_get_display(connector); +} + +/** + * sde_wb_connector_state_get_output_fb - get framebuffer of given state + * @state: Pointer to connector state + * Returns: Pointer to framebuffer + */ +struct drm_framebuffer * +sde_wb_connector_state_get_output_fb(struct drm_connector_state *state); + +/** + * sde_wb_connector_state_get_output_roi - get roi from given atomic state + * @state: Pointer to atomic state + * @roi: Pointer to region of interest + * Returns: 0 if success; error code otherwise + */ +int sde_wb_connector_state_get_output_roi(struct drm_connector_state *state, + struct sde_rect *roi); + +#else +static inline +struct drm_framebuffer *sde_wb_get_output_fb(struct sde_wb_device *wb_dev) +{ + return NULL; +} +static inline +int sde_wb_get_output_roi(struct sde_wb_device *wb_dev, struct sde_rect *roi) +{ + return 0; +} +static inline +u32 sde_wb_get_num_of_displays(void) +{ + return 0; +} +static inline +int wb_display_get_displays(void **display_array, u32 max_display_count) +{ + return 0; +} +static inline +void sde_wb_set_active_state(struct sde_wb_device *wb_dev, bool is_active) +{ +} +static inline +bool sde_wb_is_active(struct sde_wb_device *wb_dev) +{ + return false; +} +static inline +int sde_wb_drm_init(struct sde_wb_device *wb_dev, struct drm_encoder *encoder) +{ + return 0; +} +static inline +int sde_wb_drm_deinit(struct sde_wb_device *wb_dev) +{ + return 0; +} +static inline +int sde_wb_config(struct drm_device *drm_dev, void *data, + struct drm_file *file_priv) +{ + return 0; +} +static inline +int sde_wb_connector_post_init(struct drm_connector *connector, + void *display) +{ + return 0; +} +static inline +enum drm_connector_status +sde_wb_connector_detect(struct drm_connector *connector, + bool force, + void *display) +{ + return connector_status_disconnected; +} +static inline +int sde_wb_connector_get_modes(struct drm_connector *connector, void *display, + const struct msm_resource_caps_info *avail_res) +{ + return -EINVAL; +} +static inline +int sde_wb_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + int property_index, + uint64_t value, + void *display) +{ + return 0; +} +static inline +int sde_wb_get_info(struct drm_connector *connector, + struct msm_display_info *info, void *display) +{ + return 0; +} +static inline +struct sde_wb_device *sde_wb_connector_get_wb(struct drm_connector *connector) +{ + return NULL; +} + +static inline +struct drm_framebuffer * +sde_wb_connector_state_get_output_fb(struct drm_connector_state *state) +{ + return NULL; +} + +static inline +int sde_wb_connector_state_get_output_roi(struct drm_connector_state *state, + struct sde_rect *roi) +{ + return 0; +} +static inline +int sde_wb_connector_set_info_blob(struct drm_connector *connector, + void *info, + void *display, + struct msm_mode_info *mode_info) +{ + return 0; +} + +static inline +int sde_wb_get_mode_info(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + struct msm_mode_info *mode_info, + void *display, const struct msm_resource_caps_info *avail_res) +{ + return 0; +} +#endif +#endif /* __SDE_WB_H__ */ + diff --git a/techpack/display/msm/sde_dbg.c b/techpack/display/msm/sde_dbg.c new file mode 100644 index 0000000000000000000000000000000000000000..6178e1bf1696a9f47ba4c9a7862de9df6fdc5e14 --- /dev/null +++ b/techpack/display/msm/sde_dbg.c @@ -0,0 +1,4850 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2009-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ + +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/ktime.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/dma-buf.h> +#include <linux/slab.h> +#include <linux/list_sort.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#include "sde_dbg.h" +#include "sde/sde_hw_catalog.h" + +#define SDE_DBG_BASE_MAX 10 + +#define DEFAULT_PANIC 1 +#define DEFAULT_REGDUMP SDE_DBG_DUMP_IN_MEM +#define DEFAULT_DBGBUS_SDE SDE_DBG_DUMP_IN_MEM +#define DEFAULT_DBGBUS_VBIFRT SDE_DBG_DUMP_IN_MEM +#define DEFAULT_BASE_REG_CNT 0x100 +#define GROUP_BYTES 4 +#define ROW_BYTES 16 +#define RANGE_NAME_LEN 40 +#define REG_BASE_NAME_LEN 80 + +#define DBGBUS_FLAGS_DSPP BIT(0) +#define DBGBUS_DSPP_STATUS 0x34C + +#define DBGBUS_NAME_SDE "sde" +#define DBGBUS_NAME_VBIF_RT "vbif_rt" + +/* offsets from sde top address for the debug buses */ +#define DBGBUS_SSPP0 0x188 +#define DBGBUS_AXI_INTF 0x194 +#define DBGBUS_SSPP1 0x298 +#define DBGBUS_DSPP 0x348 +#define DBGBUS_PERIPH 0x418 + +#define TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0)) +#define TEST_EXT_MASK(id, tp) (((tp >> 3) << 24) | (id << 4) \ + | ((tp & 0x7) << 1) | BIT(0)) + +/* following offsets are with respect to MDP VBIF base for DBG BUS access */ +#define MMSS_VBIF_CLKON 0x4 +#define MMSS_VBIF_TEST_BUS_OUT_CTRL 0x210 +#define MMSS_VBIF_TEST_BUS_OUT 0x230 + +/* Vbif error info */ +#define MMSS_VBIF_PND_ERR 0x190 +#define MMSS_VBIF_SRC_ERR 0x194 +#define MMSS_VBIF_XIN_HALT_CTRL1 0x204 +#define MMSS_VBIF_ERR_INFO 0X1a0 +#define MMSS_VBIF_ERR_INFO_1 0x1a4 +#define MMSS_VBIF_CLIENT_NUM 14 + +/* print debug ranges in groups of 4 u32s */ +#define REG_DUMP_ALIGN 16 + +#define RSC_DEBUG_MUX_SEL_SDM845 9 + +#define DBG_CTRL_STOP_FTRACE BIT(0) +#define DBG_CTRL_PANIC_UNDERRUN BIT(1) +#define DBG_CTRL_RESET_HW_PANIC BIT(2) +#define DBG_CTRL_MAX BIT(3) + +#define DUMP_BUF_SIZE (4096 * 512) +#define DUMP_CLMN_COUNT 4 +#define DUMP_LINE_SIZE 256 +#define DUMP_MAX_LINES_PER_BLK 512 + +/** + * struct sde_dbg_reg_offset - tracking for start and end of region + * @start: start offset + * @start: end offset + */ +struct sde_dbg_reg_offset { + u32 start; + u32 end; +}; + +/** + * struct sde_dbg_reg_range - register dumping named sub-range + * @head: head of this node + * @reg_dump: address for the mem dump + * @range_name: name of this range + * @offset: offsets for range to dump + * @xin_id: client xin id + */ +struct sde_dbg_reg_range { + struct list_head head; + u32 *reg_dump; + char range_name[RANGE_NAME_LEN]; + struct sde_dbg_reg_offset offset; + uint32_t xin_id; +}; + +/** + * struct sde_dbg_reg_base - register region base. + * may sub-ranges: sub-ranges are used for dumping + * or may not have sub-ranges: dumping is base -> max_offset + * @reg_base_head: head of this node + * @sub_range_list: head to the list with dump ranges + * @name: register base name + * @base: base pointer + * @off: cached offset of region for manual register dumping + * @cnt: cached range of region for manual register dumping + * @max_offset: length of region + * @buf: buffer used for manual register dumping + * @buf_len: buffer length used for manual register dumping + * @reg_dump: address for the mem dump if no ranges used + * @cb: callback for external dump function, null if not defined + * @cb_ptr: private pointer to callback function + */ +struct sde_dbg_reg_base { + struct list_head reg_base_head; + struct list_head sub_range_list; + char name[REG_BASE_NAME_LEN]; + void __iomem *base; + size_t off; + size_t cnt; + size_t max_offset; + char *buf; + size_t buf_len; + u32 *reg_dump; + void (*cb)(void *ptr); + void *cb_ptr; +}; + +struct sde_debug_bus_entry { + u32 wr_addr; + u32 block_id; + u32 test_id; + void (*analyzer)(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val); +}; + +struct vbif_debug_bus_entry { + u32 disable_bus_addr; + u32 block_bus_addr; + u32 bit_offset; + u32 block_cnt; + u32 test_pnt_start; + u32 test_pnt_cnt; +}; + +struct sde_dbg_debug_bus_common { + char *name; + u32 enable_mask; + bool include_in_deferred_work; + u32 flags; + u32 entries_size; + u32 *dumped_content; +}; + +struct sde_dbg_sde_debug_bus { + struct sde_dbg_debug_bus_common cmn; + struct sde_debug_bus_entry *entries; + u32 top_blk_off; +}; + +struct sde_dbg_vbif_debug_bus { + struct sde_dbg_debug_bus_common cmn; + struct vbif_debug_bus_entry *entries; +}; + +struct sde_dbg_dsi_debug_bus { + u32 *entries; + u32 size; +}; + +/** + * struct sde_dbg_regbuf - wraps buffer and tracking params for register dumps + * @buf: pointer to allocated memory for storing register dumps in hw recovery + * @buf_size: size of the memory allocated + * @len: size of the dump data valid in the buffer + * @rpos: cursor points to the buffer position read by client + * @dump_done: to indicate if dumping to user memory is complete + * @cur_blk: points to the current sde_dbg_reg_base block + */ +struct sde_dbg_regbuf { + char *buf; + int buf_size; + int len; + int rpos; + int dump_done; + struct sde_dbg_reg_base *cur_blk; +}; + +/** + * struct sde_dbg_base - global sde debug base structure + * @evtlog: event log instance + * @reg_base_list: list of register dumping regions + * @dev: device pointer + * @mutex: mutex to serialize access to serialze dumps, debugfs access + * @req_dump_blks: list of blocks requested for dumping + * @panic_on_err: whether to kernel panic after triggering dump via debugfs + * @dump_work: work struct for deferring register dump work to separate thread + * @work_panic: panic after dump if internal user passed "panic" special region + * @enable_reg_dump: whether to dump registers into memory, kernel log, or both + * @dbgbus_sde: debug bus structure for the sde + * @dbgbus_vbif_rt: debug bus structure for the realtime vbif + * @dump_all: dump all entries in register dump + * @dump_secure: dump entries excluding few as it is in secure-session + * @dsi_dbg_bus: dump dsi debug bus register + * @regbuf: buffer data to track the register dumping in hw recovery + * @cur_evt_index: index used for tracking event logs dump in hw recovery + * @dbgbus_dump_idx: index used for tracking dbg-bus dump in hw recovery + * @vbif_dbgbus_dump_idx: index for tracking vbif dumps in hw recovery + */ +static struct sde_dbg_base { + struct sde_dbg_evtlog *evtlog; + struct list_head reg_base_list; + struct device *dev; + struct mutex mutex; + + struct sde_dbg_reg_base *req_dump_blks[SDE_DBG_BASE_MAX]; + + u32 panic_on_err; + struct work_struct dump_work; + bool work_panic; + u32 enable_reg_dump; + + struct sde_dbg_sde_debug_bus dbgbus_sde; + struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt; + struct sde_dbg_dsi_debug_bus dbgbus_dsi; + bool dump_all; + bool dump_secure; + bool dsi_dbg_bus; + u32 debugfs_ctrl; + + struct sde_dbg_regbuf regbuf; + u32 cur_evt_index; + u32 dbgbus_dump_idx; + u32 vbif_dbgbus_dump_idx; + enum sde_dbg_dump_context dump_mode; +} sde_dbg_base; + +/* sde_dbg_base_evtlog - global pointer to main sde event log for macro use */ +struct sde_dbg_evtlog *sde_dbg_base_evtlog; + +static void _sde_debug_bus_xbar_dump(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val) +{ + dev_err(sde_dbg_base.dev, "xbar 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _sde_debug_bus_lm_dump(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val) +{ + if (!(val & 0xFFF000)) + return; + + dev_err(sde_dbg_base.dev, "lm 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _sde_debug_bus_ppb0_dump(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val) +{ + if (!(val & BIT(15))) + return; + + dev_err(sde_dbg_base.dev, "ppb0 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _sde_debug_bus_ltm_dump(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val) +{ + dev_info(sde_dbg_base.dev, "ltm 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static void _sde_debug_bus_ppb1_dump(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val) +{ + if (!(val & BIT(15))) + return; + + dev_err(sde_dbg_base.dev, "ppb1 0x%x %d %d 0x%x\n", + entry->wr_addr, entry->block_id, entry->test_id, val); +} + +static struct sde_debug_bus_entry dbg_bus_sde_sm8150[] = { + + /* Unpack 0 sspp 0*/ + { DBGBUS_SSPP0, 35, 2 }, + { DBGBUS_SSPP0, 50, 2 }, + { DBGBUS_SSPP0, 60, 2 }, + { DBGBUS_SSPP0, 70, 2 }, + + /* Unpack 1 sspp 0*/ + { DBGBUS_SSPP0, 36, 2 }, + { DBGBUS_SSPP0, 51, 2 }, + { DBGBUS_SSPP0, 61, 2 }, + { DBGBUS_SSPP0, 71, 2 }, + + /* Unpack 2 sspp 0*/ + { DBGBUS_SSPP0, 37, 2 }, + { DBGBUS_SSPP0, 52, 2 }, + { DBGBUS_SSPP0, 62, 2 }, + { DBGBUS_SSPP0, 72, 2 }, + + + /* Unpack 3 sspp 0*/ + { DBGBUS_SSPP0, 38, 2 }, + { DBGBUS_SSPP0, 53, 2 }, + { DBGBUS_SSPP0, 63, 2 }, + { DBGBUS_SSPP0, 73, 2 }, + + /* Unpack 0 sspp 1*/ + { DBGBUS_SSPP1, 35, 2 }, + { DBGBUS_SSPP1, 50, 2 }, + { DBGBUS_SSPP1, 60, 2 }, + { DBGBUS_SSPP1, 70, 2 }, + + /* Unpack 1 sspp 1*/ + { DBGBUS_SSPP1, 36, 2 }, + { DBGBUS_SSPP1, 51, 2 }, + { DBGBUS_SSPP1, 61, 2 }, + { DBGBUS_SSPP1, 71, 2 }, + + /* Unpack 2 sspp 1*/ + { DBGBUS_SSPP1, 37, 2 }, + { DBGBUS_SSPP1, 52, 2 }, + { DBGBUS_SSPP1, 62, 2 }, + { DBGBUS_SSPP1, 72, 2 }, + + + /* Unpack 3 sspp 1*/ + { DBGBUS_SSPP1, 38, 2 }, + { DBGBUS_SSPP1, 53, 2 }, + { DBGBUS_SSPP1, 63, 2 }, + { DBGBUS_SSPP1, 73, 2 }, + + /* scheduler */ + { DBGBUS_DSPP, 130, 0 }, + { DBGBUS_DSPP, 130, 1 }, + { DBGBUS_DSPP, 130, 2 }, + { DBGBUS_DSPP, 130, 3 }, + { DBGBUS_DSPP, 130, 4 }, + { DBGBUS_DSPP, 130, 5 }, + + + /* fetch sspp0 */ + + /* vig 0 */ + { DBGBUS_SSPP0, 0, 0 }, + { DBGBUS_SSPP0, 0, 1 }, + { DBGBUS_SSPP0, 0, 2 }, + { DBGBUS_SSPP0, 0, 3 }, + { DBGBUS_SSPP0, 0, 4 }, + { DBGBUS_SSPP0, 0, 5 }, + { DBGBUS_SSPP0, 0, 6 }, + { DBGBUS_SSPP0, 0, 7 }, + + { DBGBUS_SSPP0, 1, 0 }, + { DBGBUS_SSPP0, 1, 1 }, + { DBGBUS_SSPP0, 1, 2 }, + { DBGBUS_SSPP0, 1, 3 }, + { DBGBUS_SSPP0, 1, 4 }, + { DBGBUS_SSPP0, 1, 5 }, + { DBGBUS_SSPP0, 1, 6 }, + { DBGBUS_SSPP0, 1, 7 }, + + { DBGBUS_SSPP0, 2, 0 }, + { DBGBUS_SSPP0, 2, 1 }, + { DBGBUS_SSPP0, 2, 2 }, + { DBGBUS_SSPP0, 2, 3 }, + { DBGBUS_SSPP0, 2, 4 }, + { DBGBUS_SSPP0, 2, 5 }, + { DBGBUS_SSPP0, 2, 6 }, + { DBGBUS_SSPP0, 2, 7 }, + + { DBGBUS_SSPP0, 4, 0 }, + { DBGBUS_SSPP0, 4, 1 }, + { DBGBUS_SSPP0, 4, 2 }, + { DBGBUS_SSPP0, 4, 3 }, + { DBGBUS_SSPP0, 4, 4 }, + { DBGBUS_SSPP0, 4, 5 }, + { DBGBUS_SSPP0, 4, 6 }, + { DBGBUS_SSPP0, 4, 7 }, + + { DBGBUS_SSPP0, 5, 0 }, + { DBGBUS_SSPP0, 5, 1 }, + { DBGBUS_SSPP0, 5, 2 }, + { DBGBUS_SSPP0, 5, 3 }, + { DBGBUS_SSPP0, 5, 4 }, + { DBGBUS_SSPP0, 5, 5 }, + { DBGBUS_SSPP0, 5, 6 }, + { DBGBUS_SSPP0, 5, 7 }, + + /* vig 2 */ + { DBGBUS_SSPP0, 20, 0 }, + { DBGBUS_SSPP0, 20, 1 }, + { DBGBUS_SSPP0, 20, 2 }, + { DBGBUS_SSPP0, 20, 3 }, + { DBGBUS_SSPP0, 20, 4 }, + { DBGBUS_SSPP0, 20, 5 }, + { DBGBUS_SSPP0, 20, 6 }, + { DBGBUS_SSPP0, 20, 7 }, + + { DBGBUS_SSPP0, 21, 0 }, + { DBGBUS_SSPP0, 21, 1 }, + { DBGBUS_SSPP0, 21, 2 }, + { DBGBUS_SSPP0, 21, 3 }, + { DBGBUS_SSPP0, 21, 4 }, + { DBGBUS_SSPP0, 21, 5 }, + { DBGBUS_SSPP0, 21, 6 }, + { DBGBUS_SSPP0, 21, 7 }, + + { DBGBUS_SSPP0, 22, 0 }, + { DBGBUS_SSPP0, 22, 1 }, + { DBGBUS_SSPP0, 22, 2 }, + { DBGBUS_SSPP0, 22, 3 }, + { DBGBUS_SSPP0, 22, 4 }, + { DBGBUS_SSPP0, 22, 5 }, + { DBGBUS_SSPP0, 22, 6 }, + { DBGBUS_SSPP0, 22, 7 }, + + { DBGBUS_SSPP0, 24, 0 }, + { DBGBUS_SSPP0, 24, 1 }, + { DBGBUS_SSPP0, 24, 2 }, + { DBGBUS_SSPP0, 24, 3 }, + { DBGBUS_SSPP0, 24, 4 }, + { DBGBUS_SSPP0, 24, 5 }, + { DBGBUS_SSPP0, 24, 6 }, + { DBGBUS_SSPP0, 24, 7 }, + + { DBGBUS_SSPP0, 25, 0 }, + { DBGBUS_SSPP0, 25, 1 }, + { DBGBUS_SSPP0, 25, 2 }, + { DBGBUS_SSPP0, 25, 3 }, + { DBGBUS_SSPP0, 25, 4 }, + { DBGBUS_SSPP0, 25, 5 }, + { DBGBUS_SSPP0, 25, 6 }, + { DBGBUS_SSPP0, 25, 7 }, + + /* dma 2 */ + { DBGBUS_SSPP0, 30, 0 }, + { DBGBUS_SSPP0, 30, 1 }, + { DBGBUS_SSPP0, 30, 2 }, + { DBGBUS_SSPP0, 30, 3 }, + { DBGBUS_SSPP0, 30, 4 }, + { DBGBUS_SSPP0, 30, 5 }, + { DBGBUS_SSPP0, 30, 6 }, + { DBGBUS_SSPP0, 30, 7 }, + + { DBGBUS_SSPP0, 31, 0 }, + { DBGBUS_SSPP0, 31, 1 }, + { DBGBUS_SSPP0, 31, 2 }, + { DBGBUS_SSPP0, 31, 3 }, + { DBGBUS_SSPP0, 31, 4 }, + { DBGBUS_SSPP0, 31, 5 }, + { DBGBUS_SSPP0, 31, 6 }, + { DBGBUS_SSPP0, 31, 7 }, + + { DBGBUS_SSPP0, 32, 0 }, + { DBGBUS_SSPP0, 32, 1 }, + { DBGBUS_SSPP0, 32, 2 }, + { DBGBUS_SSPP0, 32, 3 }, + { DBGBUS_SSPP0, 32, 4 }, + { DBGBUS_SSPP0, 32, 5 }, + { DBGBUS_SSPP0, 32, 6 }, + { DBGBUS_SSPP0, 32, 7 }, + + { DBGBUS_SSPP0, 33, 0 }, + { DBGBUS_SSPP0, 33, 1 }, + { DBGBUS_SSPP0, 33, 2 }, + { DBGBUS_SSPP0, 33, 3 }, + { DBGBUS_SSPP0, 33, 4 }, + { DBGBUS_SSPP0, 33, 5 }, + { DBGBUS_SSPP0, 33, 6 }, + { DBGBUS_SSPP0, 33, 7 }, + + { DBGBUS_SSPP0, 34, 0 }, + { DBGBUS_SSPP0, 34, 1 }, + { DBGBUS_SSPP0, 34, 2 }, + { DBGBUS_SSPP0, 34, 3 }, + { DBGBUS_SSPP0, 34, 4 }, + { DBGBUS_SSPP0, 34, 5 }, + { DBGBUS_SSPP0, 34, 6 }, + { DBGBUS_SSPP0, 34, 7 }, + + /* dma 0 */ + { DBGBUS_SSPP0, 40, 0 }, + { DBGBUS_SSPP0, 40, 1 }, + { DBGBUS_SSPP0, 40, 2 }, + { DBGBUS_SSPP0, 40, 3 }, + { DBGBUS_SSPP0, 40, 4 }, + { DBGBUS_SSPP0, 40, 5 }, + { DBGBUS_SSPP0, 40, 6 }, + { DBGBUS_SSPP0, 40, 7 }, + + { DBGBUS_SSPP0, 41, 0 }, + { DBGBUS_SSPP0, 41, 1 }, + { DBGBUS_SSPP0, 41, 2 }, + { DBGBUS_SSPP0, 41, 3 }, + { DBGBUS_SSPP0, 41, 4 }, + { DBGBUS_SSPP0, 41, 5 }, + { DBGBUS_SSPP0, 41, 6 }, + { DBGBUS_SSPP0, 41, 7 }, + + { DBGBUS_SSPP0, 42, 0 }, + { DBGBUS_SSPP0, 42, 1 }, + { DBGBUS_SSPP0, 42, 2 }, + { DBGBUS_SSPP0, 42, 3 }, + { DBGBUS_SSPP0, 42, 4 }, + { DBGBUS_SSPP0, 42, 5 }, + { DBGBUS_SSPP0, 42, 6 }, + { DBGBUS_SSPP0, 42, 7 }, + + { DBGBUS_SSPP0, 44, 0 }, + { DBGBUS_SSPP0, 44, 1 }, + { DBGBUS_SSPP0, 44, 2 }, + { DBGBUS_SSPP0, 44, 3 }, + { DBGBUS_SSPP0, 44, 4 }, + { DBGBUS_SSPP0, 44, 5 }, + { DBGBUS_SSPP0, 44, 6 }, + { DBGBUS_SSPP0, 44, 7 }, + + { DBGBUS_SSPP0, 45, 0 }, + { DBGBUS_SSPP0, 45, 1 }, + { DBGBUS_SSPP0, 45, 2 }, + { DBGBUS_SSPP0, 45, 3 }, + { DBGBUS_SSPP0, 45, 4 }, + { DBGBUS_SSPP0, 45, 5 }, + { DBGBUS_SSPP0, 45, 6 }, + { DBGBUS_SSPP0, 45, 7 }, + + /* fetch sspp1 */ + /* vig 1 */ + { DBGBUS_SSPP1, 0, 0 }, + { DBGBUS_SSPP1, 0, 1 }, + { DBGBUS_SSPP1, 0, 2 }, + { DBGBUS_SSPP1, 0, 3 }, + { DBGBUS_SSPP1, 0, 4 }, + { DBGBUS_SSPP1, 0, 5 }, + { DBGBUS_SSPP1, 0, 6 }, + { DBGBUS_SSPP1, 0, 7 }, + + { DBGBUS_SSPP1, 1, 0 }, + { DBGBUS_SSPP1, 1, 1 }, + { DBGBUS_SSPP1, 1, 2 }, + { DBGBUS_SSPP1, 1, 3 }, + { DBGBUS_SSPP1, 1, 4 }, + { DBGBUS_SSPP1, 1, 5 }, + { DBGBUS_SSPP1, 1, 6 }, + { DBGBUS_SSPP1, 1, 7 }, + + { DBGBUS_SSPP1, 2, 0 }, + { DBGBUS_SSPP1, 2, 1 }, + { DBGBUS_SSPP1, 2, 2 }, + { DBGBUS_SSPP1, 2, 3 }, + { DBGBUS_SSPP1, 2, 4 }, + { DBGBUS_SSPP1, 2, 5 }, + { DBGBUS_SSPP1, 2, 6 }, + { DBGBUS_SSPP1, 2, 7 }, + + { DBGBUS_SSPP1, 4, 0 }, + { DBGBUS_SSPP1, 4, 1 }, + { DBGBUS_SSPP1, 4, 2 }, + { DBGBUS_SSPP1, 4, 3 }, + { DBGBUS_SSPP1, 4, 4 }, + { DBGBUS_SSPP1, 4, 5 }, + { DBGBUS_SSPP1, 4, 6 }, + { DBGBUS_SSPP1, 4, 7 }, + + { DBGBUS_SSPP1, 5, 0 }, + { DBGBUS_SSPP1, 5, 1 }, + { DBGBUS_SSPP1, 5, 2 }, + { DBGBUS_SSPP1, 5, 3 }, + { DBGBUS_SSPP1, 5, 4 }, + { DBGBUS_SSPP1, 5, 5 }, + { DBGBUS_SSPP1, 5, 6 }, + { DBGBUS_SSPP1, 5, 7 }, + + /* vig 3 */ + { DBGBUS_SSPP1, 20, 0 }, + { DBGBUS_SSPP1, 20, 1 }, + { DBGBUS_SSPP1, 20, 2 }, + { DBGBUS_SSPP1, 20, 3 }, + { DBGBUS_SSPP1, 20, 4 }, + { DBGBUS_SSPP1, 20, 5 }, + { DBGBUS_SSPP1, 20, 6 }, + { DBGBUS_SSPP1, 20, 7 }, + + { DBGBUS_SSPP1, 21, 0 }, + { DBGBUS_SSPP1, 21, 1 }, + { DBGBUS_SSPP1, 21, 2 }, + { DBGBUS_SSPP1, 21, 3 }, + { DBGBUS_SSPP1, 21, 4 }, + { DBGBUS_SSPP1, 21, 5 }, + { DBGBUS_SSPP1, 21, 6 }, + { DBGBUS_SSPP1, 21, 7 }, + + { DBGBUS_SSPP1, 22, 0 }, + { DBGBUS_SSPP1, 22, 1 }, + { DBGBUS_SSPP1, 22, 2 }, + { DBGBUS_SSPP1, 22, 3 }, + { DBGBUS_SSPP1, 22, 4 }, + { DBGBUS_SSPP1, 22, 5 }, + { DBGBUS_SSPP1, 22, 6 }, + { DBGBUS_SSPP1, 22, 7 }, + + { DBGBUS_SSPP1, 24, 0 }, + { DBGBUS_SSPP1, 24, 1 }, + { DBGBUS_SSPP1, 24, 2 }, + { DBGBUS_SSPP1, 24, 3 }, + { DBGBUS_SSPP1, 24, 4 }, + { DBGBUS_SSPP1, 24, 5 }, + { DBGBUS_SSPP1, 24, 6 }, + { DBGBUS_SSPP1, 24, 7 }, + + { DBGBUS_SSPP1, 25, 0 }, + { DBGBUS_SSPP1, 25, 1 }, + { DBGBUS_SSPP1, 25, 2 }, + { DBGBUS_SSPP1, 25, 3 }, + { DBGBUS_SSPP1, 25, 4 }, + { DBGBUS_SSPP1, 25, 5 }, + { DBGBUS_SSPP1, 25, 6 }, + { DBGBUS_SSPP1, 25, 7 }, + + /* dma 3 */ + { DBGBUS_SSPP1, 30, 0 }, + { DBGBUS_SSPP1, 30, 1 }, + { DBGBUS_SSPP1, 30, 2 }, + { DBGBUS_SSPP1, 30, 3 }, + { DBGBUS_SSPP1, 30, 4 }, + { DBGBUS_SSPP1, 30, 5 }, + { DBGBUS_SSPP1, 30, 6 }, + { DBGBUS_SSPP1, 30, 7 }, + + { DBGBUS_SSPP1, 31, 0 }, + { DBGBUS_SSPP1, 31, 1 }, + { DBGBUS_SSPP1, 31, 2 }, + { DBGBUS_SSPP1, 31, 3 }, + { DBGBUS_SSPP1, 31, 4 }, + { DBGBUS_SSPP1, 31, 5 }, + { DBGBUS_SSPP1, 31, 6 }, + { DBGBUS_SSPP1, 31, 7 }, + + { DBGBUS_SSPP1, 32, 0 }, + { DBGBUS_SSPP1, 32, 1 }, + { DBGBUS_SSPP1, 32, 2 }, + { DBGBUS_SSPP1, 32, 3 }, + { DBGBUS_SSPP1, 32, 4 }, + { DBGBUS_SSPP1, 32, 5 }, + { DBGBUS_SSPP1, 32, 6 }, + { DBGBUS_SSPP1, 32, 7 }, + + { DBGBUS_SSPP1, 33, 0 }, + { DBGBUS_SSPP1, 33, 1 }, + { DBGBUS_SSPP1, 33, 2 }, + { DBGBUS_SSPP1, 33, 3 }, + { DBGBUS_SSPP1, 33, 4 }, + { DBGBUS_SSPP1, 33, 5 }, + { DBGBUS_SSPP1, 33, 6 }, + { DBGBUS_SSPP1, 33, 7 }, + + { DBGBUS_SSPP1, 34, 0 }, + { DBGBUS_SSPP1, 34, 1 }, + { DBGBUS_SSPP1, 34, 2 }, + { DBGBUS_SSPP1, 34, 3 }, + { DBGBUS_SSPP1, 34, 4 }, + { DBGBUS_SSPP1, 34, 5 }, + { DBGBUS_SSPP1, 34, 6 }, + { DBGBUS_SSPP1, 34, 7 }, + + /* dma 1 */ + { DBGBUS_SSPP1, 40, 0 }, + { DBGBUS_SSPP1, 40, 1 }, + { DBGBUS_SSPP1, 40, 2 }, + { DBGBUS_SSPP1, 40, 3 }, + { DBGBUS_SSPP1, 40, 4 }, + { DBGBUS_SSPP1, 40, 5 }, + { DBGBUS_SSPP1, 40, 6 }, + { DBGBUS_SSPP1, 40, 7 }, + + { DBGBUS_SSPP1, 41, 0 }, + { DBGBUS_SSPP1, 41, 1 }, + { DBGBUS_SSPP1, 41, 2 }, + { DBGBUS_SSPP1, 41, 3 }, + { DBGBUS_SSPP1, 41, 4 }, + { DBGBUS_SSPP1, 41, 5 }, + { DBGBUS_SSPP1, 41, 6 }, + { DBGBUS_SSPP1, 41, 7 }, + + { DBGBUS_SSPP1, 42, 0 }, + { DBGBUS_SSPP1, 42, 1 }, + { DBGBUS_SSPP1, 42, 2 }, + { DBGBUS_SSPP1, 42, 3 }, + { DBGBUS_SSPP1, 42, 4 }, + { DBGBUS_SSPP1, 42, 5 }, + { DBGBUS_SSPP1, 42, 6 }, + { DBGBUS_SSPP1, 42, 7 }, + + { DBGBUS_SSPP1, 44, 0 }, + { DBGBUS_SSPP1, 44, 1 }, + { DBGBUS_SSPP1, 44, 2 }, + { DBGBUS_SSPP1, 44, 3 }, + { DBGBUS_SSPP1, 44, 4 }, + { DBGBUS_SSPP1, 44, 5 }, + { DBGBUS_SSPP1, 44, 6 }, + { DBGBUS_SSPP1, 44, 7 }, + + { DBGBUS_SSPP1, 45, 0 }, + { DBGBUS_SSPP1, 45, 1 }, + { DBGBUS_SSPP1, 45, 2 }, + { DBGBUS_SSPP1, 45, 3 }, + { DBGBUS_SSPP1, 45, 4 }, + { DBGBUS_SSPP1, 45, 5 }, + { DBGBUS_SSPP1, 45, 6 }, + { DBGBUS_SSPP1, 45, 7 }, + + /* ppb_0 */ + { DBGBUS_DSPP, 31, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 33, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 35, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 42, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 47, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 49, 0, _sde_debug_bus_ppb0_dump }, + + /* ppb_1 */ + { DBGBUS_DSPP, 32, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 34, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 36, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 43, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 48, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 50, 0, _sde_debug_bus_ppb1_dump }, + + /* crossbar */ + { DBGBUS_DSPP, 0, 0, _sde_debug_bus_xbar_dump }, + + /* rotator */ + { DBGBUS_DSPP, 9, 0}, + + /* blend */ + /* LM0 */ + { DBGBUS_DSPP, 63, 1}, + { DBGBUS_DSPP, 63, 2}, + { DBGBUS_DSPP, 63, 3}, + { DBGBUS_DSPP, 63, 4}, + { DBGBUS_DSPP, 63, 5}, + { DBGBUS_DSPP, 63, 6}, + { DBGBUS_DSPP, 63, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 64, 1}, + { DBGBUS_DSPP, 64, 2}, + { DBGBUS_DSPP, 64, 3}, + { DBGBUS_DSPP, 64, 4}, + { DBGBUS_DSPP, 64, 5}, + { DBGBUS_DSPP, 64, 6}, + { DBGBUS_DSPP, 64, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 65, 1}, + { DBGBUS_DSPP, 65, 2}, + { DBGBUS_DSPP, 65, 3}, + { DBGBUS_DSPP, 65, 4}, + { DBGBUS_DSPP, 65, 5}, + { DBGBUS_DSPP, 65, 6}, + { DBGBUS_DSPP, 65, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 66, 1}, + { DBGBUS_DSPP, 66, 2}, + { DBGBUS_DSPP, 66, 3}, + { DBGBUS_DSPP, 66, 4}, + { DBGBUS_DSPP, 66, 5}, + { DBGBUS_DSPP, 66, 6}, + { DBGBUS_DSPP, 66, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 67, 1}, + { DBGBUS_DSPP, 67, 2}, + { DBGBUS_DSPP, 67, 3}, + { DBGBUS_DSPP, 67, 4}, + { DBGBUS_DSPP, 67, 5}, + { DBGBUS_DSPP, 67, 6}, + { DBGBUS_DSPP, 67, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 68, 1}, + { DBGBUS_DSPP, 68, 2}, + { DBGBUS_DSPP, 68, 3}, + { DBGBUS_DSPP, 68, 4}, + { DBGBUS_DSPP, 68, 5}, + { DBGBUS_DSPP, 68, 6}, + { DBGBUS_DSPP, 68, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 69, 1}, + { DBGBUS_DSPP, 69, 2}, + { DBGBUS_DSPP, 69, 3}, + { DBGBUS_DSPP, 69, 4}, + { DBGBUS_DSPP, 69, 5}, + { DBGBUS_DSPP, 69, 6}, + { DBGBUS_DSPP, 69, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 84, 1}, + { DBGBUS_DSPP, 84, 2}, + { DBGBUS_DSPP, 84, 3}, + { DBGBUS_DSPP, 84, 4}, + { DBGBUS_DSPP, 84, 5}, + { DBGBUS_DSPP, 84, 6}, + { DBGBUS_DSPP, 84, 7, _sde_debug_bus_lm_dump }, + + + { DBGBUS_DSPP, 85, 1}, + { DBGBUS_DSPP, 85, 2}, + { DBGBUS_DSPP, 85, 3}, + { DBGBUS_DSPP, 85, 4}, + { DBGBUS_DSPP, 85, 5}, + { DBGBUS_DSPP, 85, 6}, + { DBGBUS_DSPP, 85, 7, _sde_debug_bus_lm_dump }, + + + { DBGBUS_DSPP, 86, 1}, + { DBGBUS_DSPP, 86, 2}, + { DBGBUS_DSPP, 86, 3}, + { DBGBUS_DSPP, 86, 4}, + { DBGBUS_DSPP, 86, 5}, + { DBGBUS_DSPP, 86, 6}, + { DBGBUS_DSPP, 86, 7, _sde_debug_bus_lm_dump }, + + + { DBGBUS_DSPP, 87, 1}, + { DBGBUS_DSPP, 87, 2}, + { DBGBUS_DSPP, 87, 3}, + { DBGBUS_DSPP, 87, 4}, + { DBGBUS_DSPP, 87, 5}, + { DBGBUS_DSPP, 87, 6}, + { DBGBUS_DSPP, 87, 7, _sde_debug_bus_lm_dump }, + + /* LM1 */ + { DBGBUS_DSPP, 70, 1}, + { DBGBUS_DSPP, 70, 2}, + { DBGBUS_DSPP, 70, 3}, + { DBGBUS_DSPP, 70, 4}, + { DBGBUS_DSPP, 70, 5}, + { DBGBUS_DSPP, 70, 6}, + { DBGBUS_DSPP, 70, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 71, 1}, + { DBGBUS_DSPP, 71, 2}, + { DBGBUS_DSPP, 71, 3}, + { DBGBUS_DSPP, 71, 4}, + { DBGBUS_DSPP, 71, 5}, + { DBGBUS_DSPP, 71, 6}, + { DBGBUS_DSPP, 71, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 72, 1}, + { DBGBUS_DSPP, 72, 2}, + { DBGBUS_DSPP, 72, 3}, + { DBGBUS_DSPP, 72, 4}, + { DBGBUS_DSPP, 72, 5}, + { DBGBUS_DSPP, 72, 6}, + { DBGBUS_DSPP, 72, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 73, 1}, + { DBGBUS_DSPP, 73, 2}, + { DBGBUS_DSPP, 73, 3}, + { DBGBUS_DSPP, 73, 4}, + { DBGBUS_DSPP, 73, 5}, + { DBGBUS_DSPP, 73, 6}, + { DBGBUS_DSPP, 73, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 74, 1}, + { DBGBUS_DSPP, 74, 2}, + { DBGBUS_DSPP, 74, 3}, + { DBGBUS_DSPP, 74, 4}, + { DBGBUS_DSPP, 74, 5}, + { DBGBUS_DSPP, 74, 6}, + { DBGBUS_DSPP, 74, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 75, 1}, + { DBGBUS_DSPP, 75, 2}, + { DBGBUS_DSPP, 75, 3}, + { DBGBUS_DSPP, 75, 4}, + { DBGBUS_DSPP, 75, 5}, + { DBGBUS_DSPP, 75, 6}, + { DBGBUS_DSPP, 75, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 76, 1}, + { DBGBUS_DSPP, 76, 2}, + { DBGBUS_DSPP, 76, 3}, + { DBGBUS_DSPP, 76, 4}, + { DBGBUS_DSPP, 76, 5}, + { DBGBUS_DSPP, 76, 6}, + { DBGBUS_DSPP, 76, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 88, 1}, + { DBGBUS_DSPP, 88, 2}, + { DBGBUS_DSPP, 88, 3}, + { DBGBUS_DSPP, 88, 4}, + { DBGBUS_DSPP, 88, 5}, + { DBGBUS_DSPP, 88, 6}, + { DBGBUS_DSPP, 88, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 89, 1}, + { DBGBUS_DSPP, 89, 2}, + { DBGBUS_DSPP, 89, 3}, + { DBGBUS_DSPP, 89, 4}, + { DBGBUS_DSPP, 89, 5}, + { DBGBUS_DSPP, 89, 6}, + { DBGBUS_DSPP, 89, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 90, 1}, + { DBGBUS_DSPP, 90, 2}, + { DBGBUS_DSPP, 90, 3}, + { DBGBUS_DSPP, 90, 4}, + { DBGBUS_DSPP, 90, 5}, + { DBGBUS_DSPP, 90, 6}, + { DBGBUS_DSPP, 90, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 91, 1}, + { DBGBUS_DSPP, 91, 2}, + { DBGBUS_DSPP, 91, 3}, + { DBGBUS_DSPP, 91, 4}, + { DBGBUS_DSPP, 91, 5}, + { DBGBUS_DSPP, 91, 6}, + { DBGBUS_DSPP, 91, 7, _sde_debug_bus_lm_dump }, + + /* LM2 */ + { DBGBUS_DSPP, 77, 0}, + { DBGBUS_DSPP, 77, 1}, + { DBGBUS_DSPP, 77, 2}, + { DBGBUS_DSPP, 77, 3}, + { DBGBUS_DSPP, 77, 4}, + { DBGBUS_DSPP, 77, 5}, + { DBGBUS_DSPP, 77, 6}, + { DBGBUS_DSPP, 77, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 78, 0}, + { DBGBUS_DSPP, 78, 1}, + { DBGBUS_DSPP, 78, 2}, + { DBGBUS_DSPP, 78, 3}, + { DBGBUS_DSPP, 78, 4}, + { DBGBUS_DSPP, 78, 5}, + { DBGBUS_DSPP, 78, 6}, + { DBGBUS_DSPP, 78, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 79, 0}, + { DBGBUS_DSPP, 79, 1}, + { DBGBUS_DSPP, 79, 2}, + { DBGBUS_DSPP, 79, 3}, + { DBGBUS_DSPP, 79, 4}, + { DBGBUS_DSPP, 79, 5}, + { DBGBUS_DSPP, 79, 6}, + { DBGBUS_DSPP, 79, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 80, 0}, + { DBGBUS_DSPP, 80, 1}, + { DBGBUS_DSPP, 80, 2}, + { DBGBUS_DSPP, 80, 3}, + { DBGBUS_DSPP, 80, 4}, + { DBGBUS_DSPP, 80, 5}, + { DBGBUS_DSPP, 80, 6}, + { DBGBUS_DSPP, 80, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 81, 0}, + { DBGBUS_DSPP, 81, 1}, + { DBGBUS_DSPP, 81, 2}, + { DBGBUS_DSPP, 81, 3}, + { DBGBUS_DSPP, 81, 4}, + { DBGBUS_DSPP, 81, 5}, + { DBGBUS_DSPP, 81, 6}, + { DBGBUS_DSPP, 81, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 82, 0}, + { DBGBUS_DSPP, 82, 1}, + { DBGBUS_DSPP, 82, 2}, + { DBGBUS_DSPP, 82, 3}, + { DBGBUS_DSPP, 82, 4}, + { DBGBUS_DSPP, 82, 5}, + { DBGBUS_DSPP, 82, 6}, + { DBGBUS_DSPP, 82, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 83, 0}, + { DBGBUS_DSPP, 83, 1}, + { DBGBUS_DSPP, 83, 2}, + { DBGBUS_DSPP, 83, 3}, + { DBGBUS_DSPP, 83, 4}, + { DBGBUS_DSPP, 83, 5}, + { DBGBUS_DSPP, 83, 6}, + { DBGBUS_DSPP, 83, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 92, 1}, + { DBGBUS_DSPP, 92, 2}, + { DBGBUS_DSPP, 92, 3}, + { DBGBUS_DSPP, 92, 4}, + { DBGBUS_DSPP, 92, 5}, + { DBGBUS_DSPP, 92, 6}, + { DBGBUS_DSPP, 92, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 93, 1}, + { DBGBUS_DSPP, 93, 2}, + { DBGBUS_DSPP, 93, 3}, + { DBGBUS_DSPP, 93, 4}, + { DBGBUS_DSPP, 93, 5}, + { DBGBUS_DSPP, 93, 6}, + { DBGBUS_DSPP, 93, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 94, 1}, + { DBGBUS_DSPP, 94, 2}, + { DBGBUS_DSPP, 94, 3}, + { DBGBUS_DSPP, 94, 4}, + { DBGBUS_DSPP, 94, 5}, + { DBGBUS_DSPP, 94, 6}, + { DBGBUS_DSPP, 94, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 95, 1}, + { DBGBUS_DSPP, 95, 2}, + { DBGBUS_DSPP, 95, 3}, + { DBGBUS_DSPP, 95, 4}, + { DBGBUS_DSPP, 95, 5}, + { DBGBUS_DSPP, 95, 6}, + { DBGBUS_DSPP, 95, 7, _sde_debug_bus_lm_dump }, + + + /* LM3 */ + { DBGBUS_DSPP, 110, 1}, + { DBGBUS_DSPP, 110, 2}, + { DBGBUS_DSPP, 110, 3}, + { DBGBUS_DSPP, 110, 4}, + { DBGBUS_DSPP, 110, 5}, + { DBGBUS_DSPP, 110, 6}, + { DBGBUS_DSPP, 110, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 111, 1}, + { DBGBUS_DSPP, 111, 2}, + { DBGBUS_DSPP, 111, 3}, + { DBGBUS_DSPP, 111, 4}, + { DBGBUS_DSPP, 111, 5}, + { DBGBUS_DSPP, 111, 6}, + { DBGBUS_DSPP, 111, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 112, 1}, + { DBGBUS_DSPP, 112, 2}, + { DBGBUS_DSPP, 112, 3}, + { DBGBUS_DSPP, 112, 4}, + { DBGBUS_DSPP, 112, 5}, + { DBGBUS_DSPP, 112, 6}, + { DBGBUS_DSPP, 112, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 113, 1}, + { DBGBUS_DSPP, 113, 2}, + { DBGBUS_DSPP, 113, 3}, + { DBGBUS_DSPP, 113, 4}, + { DBGBUS_DSPP, 113, 5}, + { DBGBUS_DSPP, 113, 6}, + { DBGBUS_DSPP, 113, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 114, 1}, + { DBGBUS_DSPP, 114, 2}, + { DBGBUS_DSPP, 114, 3}, + { DBGBUS_DSPP, 114, 4}, + { DBGBUS_DSPP, 114, 5}, + { DBGBUS_DSPP, 114, 6}, + { DBGBUS_DSPP, 114, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 115, 1}, + { DBGBUS_DSPP, 115, 2}, + { DBGBUS_DSPP, 115, 3}, + { DBGBUS_DSPP, 115, 4}, + { DBGBUS_DSPP, 115, 5}, + { DBGBUS_DSPP, 115, 6}, + { DBGBUS_DSPP, 115, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 116, 1}, + { DBGBUS_DSPP, 116, 2}, + { DBGBUS_DSPP, 116, 3}, + { DBGBUS_DSPP, 116, 4}, + { DBGBUS_DSPP, 116, 5}, + { DBGBUS_DSPP, 116, 6}, + { DBGBUS_DSPP, 116, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 117, 1}, + { DBGBUS_DSPP, 117, 2}, + { DBGBUS_DSPP, 117, 3}, + { DBGBUS_DSPP, 117, 4}, + { DBGBUS_DSPP, 117, 5}, + { DBGBUS_DSPP, 117, 6}, + { DBGBUS_DSPP, 117, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 118, 1}, + { DBGBUS_DSPP, 118, 2}, + { DBGBUS_DSPP, 118, 3}, + { DBGBUS_DSPP, 118, 4}, + { DBGBUS_DSPP, 118, 5}, + { DBGBUS_DSPP, 118, 6}, + { DBGBUS_DSPP, 118, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 119, 1}, + { DBGBUS_DSPP, 119, 2}, + { DBGBUS_DSPP, 119, 3}, + { DBGBUS_DSPP, 119, 4}, + { DBGBUS_DSPP, 119, 5}, + { DBGBUS_DSPP, 119, 6}, + { DBGBUS_DSPP, 119, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 120, 1}, + { DBGBUS_DSPP, 120, 2}, + { DBGBUS_DSPP, 120, 3}, + { DBGBUS_DSPP, 120, 4}, + { DBGBUS_DSPP, 120, 5}, + { DBGBUS_DSPP, 120, 6}, + { DBGBUS_DSPP, 120, 7, _sde_debug_bus_lm_dump }, + + /* LM4 */ + { DBGBUS_DSPP, 96, 1}, + { DBGBUS_DSPP, 96, 2}, + { DBGBUS_DSPP, 96, 3}, + { DBGBUS_DSPP, 96, 4}, + { DBGBUS_DSPP, 96, 5}, + { DBGBUS_DSPP, 96, 6}, + { DBGBUS_DSPP, 96, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 97, 1}, + { DBGBUS_DSPP, 97, 2}, + { DBGBUS_DSPP, 97, 3}, + { DBGBUS_DSPP, 97, 4}, + { DBGBUS_DSPP, 97, 5}, + { DBGBUS_DSPP, 97, 6}, + { DBGBUS_DSPP, 97, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 98, 1}, + { DBGBUS_DSPP, 98, 2}, + { DBGBUS_DSPP, 98, 3}, + { DBGBUS_DSPP, 98, 4}, + { DBGBUS_DSPP, 98, 5}, + { DBGBUS_DSPP, 98, 6}, + { DBGBUS_DSPP, 98, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 99, 1}, + { DBGBUS_DSPP, 99, 2}, + { DBGBUS_DSPP, 99, 3}, + { DBGBUS_DSPP, 99, 4}, + { DBGBUS_DSPP, 99, 5}, + { DBGBUS_DSPP, 99, 6}, + { DBGBUS_DSPP, 99, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 100, 1}, + { DBGBUS_DSPP, 100, 2}, + { DBGBUS_DSPP, 100, 3}, + { DBGBUS_DSPP, 100, 4}, + { DBGBUS_DSPP, 100, 5}, + { DBGBUS_DSPP, 100, 6}, + { DBGBUS_DSPP, 100, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 101, 1}, + { DBGBUS_DSPP, 101, 2}, + { DBGBUS_DSPP, 101, 3}, + { DBGBUS_DSPP, 101, 4}, + { DBGBUS_DSPP, 101, 5}, + { DBGBUS_DSPP, 101, 6}, + { DBGBUS_DSPP, 101, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 103, 1}, + { DBGBUS_DSPP, 103, 2}, + { DBGBUS_DSPP, 103, 3}, + { DBGBUS_DSPP, 103, 4}, + { DBGBUS_DSPP, 103, 5}, + { DBGBUS_DSPP, 103, 6}, + { DBGBUS_DSPP, 103, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 105, 1}, + { DBGBUS_DSPP, 105, 2}, + { DBGBUS_DSPP, 105, 3}, + { DBGBUS_DSPP, 105, 4}, + { DBGBUS_DSPP, 105, 5}, + { DBGBUS_DSPP, 105, 6}, + { DBGBUS_DSPP, 105, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 106, 1}, + { DBGBUS_DSPP, 106, 2}, + { DBGBUS_DSPP, 106, 3}, + { DBGBUS_DSPP, 106, 4}, + { DBGBUS_DSPP, 106, 5}, + { DBGBUS_DSPP, 106, 6}, + { DBGBUS_DSPP, 106, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 109, 1}, + { DBGBUS_DSPP, 109, 2}, + { DBGBUS_DSPP, 109, 3}, + { DBGBUS_DSPP, 109, 4}, + { DBGBUS_DSPP, 109, 5}, + { DBGBUS_DSPP, 109, 6}, + { DBGBUS_DSPP, 109, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 122, 1}, + { DBGBUS_DSPP, 122, 2}, + { DBGBUS_DSPP, 122, 3}, + { DBGBUS_DSPP, 122, 4}, + { DBGBUS_DSPP, 122, 5}, + { DBGBUS_DSPP, 122, 6}, + { DBGBUS_DSPP, 122, 7, _sde_debug_bus_lm_dump }, + + /* LM5 */ + { DBGBUS_DSPP, 124, 1}, + { DBGBUS_DSPP, 124, 2}, + { DBGBUS_DSPP, 124, 3}, + { DBGBUS_DSPP, 124, 4}, + { DBGBUS_DSPP, 124, 5}, + { DBGBUS_DSPP, 124, 6}, + { DBGBUS_DSPP, 124, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 125, 1}, + { DBGBUS_DSPP, 125, 2}, + { DBGBUS_DSPP, 125, 3}, + { DBGBUS_DSPP, 125, 4}, + { DBGBUS_DSPP, 125, 5}, + { DBGBUS_DSPP, 125, 6}, + { DBGBUS_DSPP, 125, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 126, 1}, + { DBGBUS_DSPP, 126, 2}, + { DBGBUS_DSPP, 126, 3}, + { DBGBUS_DSPP, 126, 4}, + { DBGBUS_DSPP, 126, 5}, + { DBGBUS_DSPP, 126, 6}, + { DBGBUS_DSPP, 126, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 127, 1}, + { DBGBUS_DSPP, 127, 2}, + { DBGBUS_DSPP, 127, 3}, + { DBGBUS_DSPP, 127, 4}, + { DBGBUS_DSPP, 127, 5}, + { DBGBUS_DSPP, 127, 6}, + { DBGBUS_DSPP, 127, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 128, 1}, + { DBGBUS_DSPP, 128, 2}, + { DBGBUS_DSPP, 128, 3}, + { DBGBUS_DSPP, 128, 4}, + { DBGBUS_DSPP, 128, 5}, + { DBGBUS_DSPP, 128, 6}, + { DBGBUS_DSPP, 128, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 129, 1}, + { DBGBUS_DSPP, 129, 2}, + { DBGBUS_DSPP, 129, 3}, + { DBGBUS_DSPP, 129, 4}, + { DBGBUS_DSPP, 129, 5}, + { DBGBUS_DSPP, 129, 6}, + { DBGBUS_DSPP, 129, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 131, 1}, + { DBGBUS_DSPP, 131, 2}, + { DBGBUS_DSPP, 131, 3}, + { DBGBUS_DSPP, 131, 4}, + { DBGBUS_DSPP, 131, 5}, + { DBGBUS_DSPP, 131, 6}, + { DBGBUS_DSPP, 131, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 132, 1}, + { DBGBUS_DSPP, 132, 2}, + { DBGBUS_DSPP, 132, 3}, + { DBGBUS_DSPP, 132, 4}, + { DBGBUS_DSPP, 132, 5}, + { DBGBUS_DSPP, 132, 6}, + { DBGBUS_DSPP, 132, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 133, 1}, + { DBGBUS_DSPP, 133, 2}, + { DBGBUS_DSPP, 133, 3}, + { DBGBUS_DSPP, 133, 4}, + { DBGBUS_DSPP, 133, 5}, + { DBGBUS_DSPP, 133, 6}, + { DBGBUS_DSPP, 133, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 134, 1}, + { DBGBUS_DSPP, 134, 2}, + { DBGBUS_DSPP, 134, 3}, + { DBGBUS_DSPP, 134, 4}, + { DBGBUS_DSPP, 134, 5}, + { DBGBUS_DSPP, 134, 6}, + { DBGBUS_DSPP, 134, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 135, 1}, + { DBGBUS_DSPP, 135, 2}, + { DBGBUS_DSPP, 135, 3}, + { DBGBUS_DSPP, 135, 4}, + { DBGBUS_DSPP, 135, 5}, + { DBGBUS_DSPP, 135, 6}, + { DBGBUS_DSPP, 135, 7, _sde_debug_bus_lm_dump }, + + /* csc */ + { DBGBUS_SSPP0, 7, 0}, + { DBGBUS_SSPP0, 7, 1}, + { DBGBUS_SSPP0, 7, 2}, + { DBGBUS_SSPP0, 27, 0}, + { DBGBUS_SSPP0, 27, 1}, + { DBGBUS_SSPP0, 27, 2}, + { DBGBUS_SSPP1, 7, 0}, + { DBGBUS_SSPP1, 7, 1}, + { DBGBUS_SSPP1, 7, 2}, + { DBGBUS_SSPP1, 27, 0}, + { DBGBUS_SSPP1, 27, 1}, + { DBGBUS_SSPP1, 27, 2}, + + /* pcc */ + { DBGBUS_SSPP0, 43, 3}, + { DBGBUS_SSPP0, 47, 3}, + { DBGBUS_SSPP1, 43, 3}, + { DBGBUS_SSPP1, 47, 3}, + + /* spa */ + { DBGBUS_SSPP0, 8, 0}, + { DBGBUS_SSPP0, 28, 0}, + { DBGBUS_SSPP1, 8, 0}, + { DBGBUS_SSPP1, 28, 0}, + + /* dspp pa */ + { DBGBUS_DSPP, 13, 0}, + { DBGBUS_DSPP, 19, 0}, + { DBGBUS_DSPP, 24, 0}, + { DBGBUS_DSPP, 37, 0}, + + /* igc */ + { DBGBUS_SSPP0, 39, 0}, + { DBGBUS_SSPP0, 39, 1}, + { DBGBUS_SSPP0, 39, 2}, + + { DBGBUS_SSPP1, 39, 0}, + { DBGBUS_SSPP1, 39, 1}, + { DBGBUS_SSPP1, 39, 2}, + + { DBGBUS_SSPP0, 46, 0}, + { DBGBUS_SSPP0, 46, 1}, + { DBGBUS_SSPP0, 46, 2}, + + { DBGBUS_SSPP1, 46, 0}, + { DBGBUS_SSPP1, 46, 1}, + { DBGBUS_SSPP1, 46, 2}, + + { DBGBUS_DSPP, 14, 0}, + { DBGBUS_DSPP, 14, 1}, + { DBGBUS_DSPP, 14, 2}, + { DBGBUS_DSPP, 20, 0}, + { DBGBUS_DSPP, 20, 1}, + { DBGBUS_DSPP, 20, 2}, + { DBGBUS_DSPP, 25, 0}, + { DBGBUS_DSPP, 25, 1}, + { DBGBUS_DSPP, 25, 2}, + { DBGBUS_DSPP, 38, 0}, + { DBGBUS_DSPP, 38, 1}, + { DBGBUS_DSPP, 38, 2}, + + /* intf0-3 */ + { DBGBUS_PERIPH, 0, 0}, + { DBGBUS_PERIPH, 1, 0}, + { DBGBUS_PERIPH, 2, 0}, + { DBGBUS_PERIPH, 3, 0}, + { DBGBUS_PERIPH, 4, 0}, + { DBGBUS_PERIPH, 5, 0}, + + /* te counter wrapper */ + { DBGBUS_PERIPH, 60, 0}, + { DBGBUS_PERIPH, 60, 1}, + { DBGBUS_PERIPH, 60, 2}, + { DBGBUS_PERIPH, 60, 3}, + { DBGBUS_PERIPH, 60, 4}, + { DBGBUS_PERIPH, 60, 5}, + + /* dsc0 */ + { DBGBUS_PERIPH, 47, 0}, + { DBGBUS_PERIPH, 47, 1}, + { DBGBUS_PERIPH, 47, 2}, + { DBGBUS_PERIPH, 47, 3}, + { DBGBUS_PERIPH, 47, 4}, + { DBGBUS_PERIPH, 47, 5}, + { DBGBUS_PERIPH, 47, 6}, + { DBGBUS_PERIPH, 47, 7}, + + /* dsc1 */ + { DBGBUS_PERIPH, 48, 0}, + { DBGBUS_PERIPH, 48, 1}, + { DBGBUS_PERIPH, 48, 2}, + { DBGBUS_PERIPH, 48, 3}, + { DBGBUS_PERIPH, 48, 4}, + { DBGBUS_PERIPH, 48, 5}, + { DBGBUS_PERIPH, 48, 6}, + { DBGBUS_PERIPH, 48, 7}, + + /* dsc2 */ + { DBGBUS_PERIPH, 50, 0}, + { DBGBUS_PERIPH, 50, 1}, + { DBGBUS_PERIPH, 50, 2}, + { DBGBUS_PERIPH, 50, 3}, + { DBGBUS_PERIPH, 50, 4}, + { DBGBUS_PERIPH, 50, 5}, + { DBGBUS_PERIPH, 50, 6}, + { DBGBUS_PERIPH, 50, 7}, + + /* dsc3 */ + { DBGBUS_PERIPH, 51, 0}, + { DBGBUS_PERIPH, 51, 1}, + { DBGBUS_PERIPH, 51, 2}, + { DBGBUS_PERIPH, 51, 3}, + { DBGBUS_PERIPH, 51, 4}, + { DBGBUS_PERIPH, 51, 5}, + { DBGBUS_PERIPH, 51, 6}, + { DBGBUS_PERIPH, 51, 7}, + + /* dsc4 */ + { DBGBUS_PERIPH, 52, 0}, + { DBGBUS_PERIPH, 52, 1}, + { DBGBUS_PERIPH, 52, 2}, + { DBGBUS_PERIPH, 52, 3}, + { DBGBUS_PERIPH, 52, 4}, + { DBGBUS_PERIPH, 52, 5}, + { DBGBUS_PERIPH, 52, 6}, + { DBGBUS_PERIPH, 52, 7}, + + /* dsc5 */ + { DBGBUS_PERIPH, 53, 0}, + { DBGBUS_PERIPH, 53, 1}, + { DBGBUS_PERIPH, 53, 2}, + { DBGBUS_PERIPH, 53, 3}, + { DBGBUS_PERIPH, 53, 4}, + { DBGBUS_PERIPH, 53, 5}, + { DBGBUS_PERIPH, 53, 6}, + { DBGBUS_PERIPH, 53, 7}, + + /* tear-check */ + /* INTF_0 */ + { DBGBUS_PERIPH, 63, 0 }, + { DBGBUS_PERIPH, 63, 1 }, + { DBGBUS_PERIPH, 63, 2 }, + { DBGBUS_PERIPH, 63, 3 }, + { DBGBUS_PERIPH, 63, 4 }, + { DBGBUS_PERIPH, 63, 5 }, + { DBGBUS_PERIPH, 63, 6 }, + { DBGBUS_PERIPH, 63, 7 }, + + /* INTF_1 */ + { DBGBUS_PERIPH, 64, 0 }, + { DBGBUS_PERIPH, 64, 1 }, + { DBGBUS_PERIPH, 64, 2 }, + { DBGBUS_PERIPH, 64, 3 }, + { DBGBUS_PERIPH, 64, 4 }, + { DBGBUS_PERIPH, 64, 5 }, + { DBGBUS_PERIPH, 64, 6 }, + { DBGBUS_PERIPH, 64, 7 }, + + /* INTF_2 */ + { DBGBUS_PERIPH, 65, 0 }, + { DBGBUS_PERIPH, 65, 1 }, + { DBGBUS_PERIPH, 65, 2 }, + { DBGBUS_PERIPH, 65, 3 }, + { DBGBUS_PERIPH, 65, 4 }, + { DBGBUS_PERIPH, 65, 5 }, + { DBGBUS_PERIPH, 65, 6 }, + { DBGBUS_PERIPH, 65, 7 }, + + /* INTF_4 */ + { DBGBUS_PERIPH, 66, 0 }, + { DBGBUS_PERIPH, 66, 1 }, + { DBGBUS_PERIPH, 66, 2 }, + { DBGBUS_PERIPH, 66, 3 }, + { DBGBUS_PERIPH, 66, 4 }, + { DBGBUS_PERIPH, 66, 5 }, + { DBGBUS_PERIPH, 66, 6 }, + { DBGBUS_PERIPH, 66, 7 }, + + /* INTF_5 */ + { DBGBUS_PERIPH, 67, 0 }, + { DBGBUS_PERIPH, 67, 1 }, + { DBGBUS_PERIPH, 67, 2 }, + { DBGBUS_PERIPH, 67, 3 }, + { DBGBUS_PERIPH, 67, 4 }, + { DBGBUS_PERIPH, 67, 5 }, + { DBGBUS_PERIPH, 67, 6 }, + { DBGBUS_PERIPH, 67, 7 }, + + /* INTF_3 */ + { DBGBUS_PERIPH, 73, 0 }, + { DBGBUS_PERIPH, 73, 1 }, + { DBGBUS_PERIPH, 73, 2 }, + { DBGBUS_PERIPH, 73, 3 }, + { DBGBUS_PERIPH, 73, 4 }, + { DBGBUS_PERIPH, 73, 5 }, + { DBGBUS_PERIPH, 73, 6 }, + { DBGBUS_PERIPH, 73, 7 }, + + /* cdwn */ + { DBGBUS_PERIPH, 80, 0}, + { DBGBUS_PERIPH, 80, 1}, + { DBGBUS_PERIPH, 80, 2}, + + { DBGBUS_PERIPH, 81, 0}, + { DBGBUS_PERIPH, 81, 1}, + { DBGBUS_PERIPH, 81, 2}, + + { DBGBUS_PERIPH, 82, 0}, + { DBGBUS_PERIPH, 82, 1}, + { DBGBUS_PERIPH, 82, 2}, + { DBGBUS_PERIPH, 82, 3}, + { DBGBUS_PERIPH, 82, 4}, + { DBGBUS_PERIPH, 82, 5}, + { DBGBUS_PERIPH, 82, 6}, + { DBGBUS_PERIPH, 82, 7}, + + /* DPTX1 */ + { DBGBUS_PERIPH, 68, 0}, + { DBGBUS_PERIPH, 68, 1}, + { DBGBUS_PERIPH, 68, 2}, + { DBGBUS_PERIPH, 68, 3}, + { DBGBUS_PERIPH, 68, 4}, + { DBGBUS_PERIPH, 68, 5}, + { DBGBUS_PERIPH, 68, 6}, + { DBGBUS_PERIPH, 68, 7}, + + /* DP */ + { DBGBUS_PERIPH, 69, 0}, + { DBGBUS_PERIPH, 69, 1}, + { DBGBUS_PERIPH, 69, 2}, + { DBGBUS_PERIPH, 69, 3}, + { DBGBUS_PERIPH, 69, 4}, + { DBGBUS_PERIPH, 69, 5}, + + /* dsi0 */ + { DBGBUS_PERIPH, 70, 0}, + { DBGBUS_PERIPH, 70, 1}, + { DBGBUS_PERIPH, 70, 2}, + { DBGBUS_PERIPH, 70, 3}, + { DBGBUS_PERIPH, 70, 4}, + { DBGBUS_PERIPH, 70, 5}, + + /* dsi1 */ + { DBGBUS_PERIPH, 71, 0}, + { DBGBUS_PERIPH, 71, 1}, + { DBGBUS_PERIPH, 71, 2}, + { DBGBUS_PERIPH, 71, 3}, + { DBGBUS_PERIPH, 71, 4}, + { DBGBUS_PERIPH, 71, 5}, + + /* eDP */ + { DBGBUS_PERIPH, 72, 0}, + { DBGBUS_PERIPH, 72, 1}, + { DBGBUS_PERIPH, 72, 2}, + { DBGBUS_PERIPH, 72, 3}, + { DBGBUS_PERIPH, 72, 4}, + { DBGBUS_PERIPH, 72, 5}, + +}; + +static struct sde_debug_bus_entry dbg_bus_sde_kona[] = { + + /* Unpack 0 sspp 0*/ + { DBGBUS_SSPP0, 35, 2 }, + { DBGBUS_SSPP0, 50, 2 }, + { DBGBUS_SSPP0, 60, 2 }, + { DBGBUS_SSPP0, 70, 2 }, + + /* Unpack 1 sspp 0*/ + { DBGBUS_SSPP0, 36, 2 }, + { DBGBUS_SSPP0, 51, 2 }, + { DBGBUS_SSPP0, 61, 2 }, + { DBGBUS_SSPP0, 71, 2 }, + + /* Unpack 2 sspp 0*/ + { DBGBUS_SSPP0, 37, 2 }, + { DBGBUS_SSPP0, 52, 2 }, + { DBGBUS_SSPP0, 62, 2 }, + { DBGBUS_SSPP0, 72, 2 }, + + + /* Unpack 3 sspp 0*/ + { DBGBUS_SSPP0, 38, 2 }, + { DBGBUS_SSPP0, 53, 2 }, + { DBGBUS_SSPP0, 63, 2 }, + { DBGBUS_SSPP0, 73, 2 }, + + /* Unpack 0 sspp 1*/ + { DBGBUS_SSPP1, 35, 2 }, + { DBGBUS_SSPP1, 50, 2 }, + { DBGBUS_SSPP1, 60, 2 }, + { DBGBUS_SSPP1, 70, 2 }, + + /* Unpack 1 sspp 1*/ + { DBGBUS_SSPP1, 36, 2 }, + { DBGBUS_SSPP1, 51, 2 }, + { DBGBUS_SSPP1, 61, 2 }, + { DBGBUS_SSPP1, 71, 2 }, + + /* Unpack 2 sspp 1*/ + { DBGBUS_SSPP1, 37, 2 }, + { DBGBUS_SSPP1, 52, 2 }, + { DBGBUS_SSPP1, 62, 2 }, + { DBGBUS_SSPP1, 72, 2 }, + + + /* Unpack 3 sspp 1*/ + { DBGBUS_SSPP1, 38, 2 }, + { DBGBUS_SSPP1, 53, 2 }, + { DBGBUS_SSPP1, 63, 2 }, + { DBGBUS_SSPP1, 73, 2 }, + + /* scheduler */ + { DBGBUS_DSPP, 130, 0 }, + { DBGBUS_DSPP, 130, 1 }, + { DBGBUS_DSPP, 130, 2 }, + { DBGBUS_DSPP, 130, 3 }, + { DBGBUS_DSPP, 130, 4 }, + { DBGBUS_DSPP, 130, 5 }, + + + /* fetch sspp0 */ + + /* vig 0 */ + { DBGBUS_SSPP0, 0, 0 }, + { DBGBUS_SSPP0, 0, 1 }, + { DBGBUS_SSPP0, 0, 2 }, + { DBGBUS_SSPP0, 0, 3 }, + { DBGBUS_SSPP0, 0, 4 }, + { DBGBUS_SSPP0, 0, 5 }, + { DBGBUS_SSPP0, 0, 6 }, + { DBGBUS_SSPP0, 0, 7 }, + + { DBGBUS_SSPP0, 1, 0 }, + { DBGBUS_SSPP0, 1, 1 }, + { DBGBUS_SSPP0, 1, 2 }, + { DBGBUS_SSPP0, 1, 3 }, + { DBGBUS_SSPP0, 1, 4 }, + { DBGBUS_SSPP0, 1, 5 }, + { DBGBUS_SSPP0, 1, 6 }, + { DBGBUS_SSPP0, 1, 7 }, + + { DBGBUS_SSPP0, 2, 0 }, + { DBGBUS_SSPP0, 2, 1 }, + { DBGBUS_SSPP0, 2, 2 }, + { DBGBUS_SSPP0, 2, 3 }, + { DBGBUS_SSPP0, 2, 4 }, + { DBGBUS_SSPP0, 2, 5 }, + { DBGBUS_SSPP0, 2, 6 }, + { DBGBUS_SSPP0, 2, 7 }, + + { DBGBUS_SSPP0, 4, 0 }, + { DBGBUS_SSPP0, 4, 1 }, + { DBGBUS_SSPP0, 4, 2 }, + { DBGBUS_SSPP0, 4, 3 }, + { DBGBUS_SSPP0, 4, 4 }, + { DBGBUS_SSPP0, 4, 5 }, + { DBGBUS_SSPP0, 4, 6 }, + { DBGBUS_SSPP0, 4, 7 }, + + { DBGBUS_SSPP0, 5, 0 }, + { DBGBUS_SSPP0, 5, 1 }, + { DBGBUS_SSPP0, 5, 2 }, + { DBGBUS_SSPP0, 5, 3 }, + { DBGBUS_SSPP0, 5, 4 }, + { DBGBUS_SSPP0, 5, 5 }, + { DBGBUS_SSPP0, 5, 6 }, + { DBGBUS_SSPP0, 5, 7 }, + + /* vig 2 */ + { DBGBUS_SSPP0, 20, 0 }, + { DBGBUS_SSPP0, 20, 1 }, + { DBGBUS_SSPP0, 20, 2 }, + { DBGBUS_SSPP0, 20, 3 }, + { DBGBUS_SSPP0, 20, 4 }, + { DBGBUS_SSPP0, 20, 5 }, + { DBGBUS_SSPP0, 20, 6 }, + { DBGBUS_SSPP0, 20, 7 }, + + { DBGBUS_SSPP0, 21, 0 }, + { DBGBUS_SSPP0, 21, 1 }, + { DBGBUS_SSPP0, 21, 2 }, + { DBGBUS_SSPP0, 21, 3 }, + { DBGBUS_SSPP0, 21, 4 }, + { DBGBUS_SSPP0, 21, 5 }, + { DBGBUS_SSPP0, 21, 6 }, + { DBGBUS_SSPP0, 21, 7 }, + + { DBGBUS_SSPP0, 22, 0 }, + { DBGBUS_SSPP0, 22, 1 }, + { DBGBUS_SSPP0, 22, 2 }, + { DBGBUS_SSPP0, 22, 3 }, + { DBGBUS_SSPP0, 22, 4 }, + { DBGBUS_SSPP0, 22, 5 }, + { DBGBUS_SSPP0, 22, 6 }, + { DBGBUS_SSPP0, 22, 7 }, + + { DBGBUS_SSPP0, 24, 0 }, + { DBGBUS_SSPP0, 24, 1 }, + { DBGBUS_SSPP0, 24, 2 }, + { DBGBUS_SSPP0, 24, 3 }, + { DBGBUS_SSPP0, 24, 4 }, + { DBGBUS_SSPP0, 24, 5 }, + { DBGBUS_SSPP0, 24, 6 }, + { DBGBUS_SSPP0, 24, 7 }, + + { DBGBUS_SSPP0, 25, 0 }, + { DBGBUS_SSPP0, 25, 1 }, + { DBGBUS_SSPP0, 25, 2 }, + { DBGBUS_SSPP0, 25, 3 }, + { DBGBUS_SSPP0, 25, 4 }, + { DBGBUS_SSPP0, 25, 5 }, + { DBGBUS_SSPP0, 25, 6 }, + { DBGBUS_SSPP0, 25, 7 }, + + /* dma 2 */ + { DBGBUS_SSPP0, 30, 0 }, + { DBGBUS_SSPP0, 30, 1 }, + { DBGBUS_SSPP0, 30, 2 }, + { DBGBUS_SSPP0, 30, 3 }, + { DBGBUS_SSPP0, 30, 4 }, + { DBGBUS_SSPP0, 30, 5 }, + { DBGBUS_SSPP0, 30, 6 }, + { DBGBUS_SSPP0, 30, 7 }, + + { DBGBUS_SSPP0, 31, 0 }, + { DBGBUS_SSPP0, 31, 1 }, + { DBGBUS_SSPP0, 31, 2 }, + { DBGBUS_SSPP0, 31, 3 }, + { DBGBUS_SSPP0, 31, 4 }, + { DBGBUS_SSPP0, 31, 5 }, + { DBGBUS_SSPP0, 31, 6 }, + { DBGBUS_SSPP0, 31, 7 }, + + { DBGBUS_SSPP0, 32, 0 }, + { DBGBUS_SSPP0, 32, 1 }, + { DBGBUS_SSPP0, 32, 2 }, + { DBGBUS_SSPP0, 32, 3 }, + { DBGBUS_SSPP0, 32, 4 }, + { DBGBUS_SSPP0, 32, 5 }, + { DBGBUS_SSPP0, 32, 6 }, + { DBGBUS_SSPP0, 32, 7 }, + + { DBGBUS_SSPP0, 33, 0 }, + { DBGBUS_SSPP0, 33, 1 }, + { DBGBUS_SSPP0, 33, 2 }, + { DBGBUS_SSPP0, 33, 3 }, + { DBGBUS_SSPP0, 33, 4 }, + { DBGBUS_SSPP0, 33, 5 }, + { DBGBUS_SSPP0, 33, 6 }, + { DBGBUS_SSPP0, 33, 7 }, + + { DBGBUS_SSPP0, 34, 0 }, + { DBGBUS_SSPP0, 34, 1 }, + { DBGBUS_SSPP0, 34, 2 }, + { DBGBUS_SSPP0, 34, 3 }, + { DBGBUS_SSPP0, 34, 4 }, + { DBGBUS_SSPP0, 34, 5 }, + { DBGBUS_SSPP0, 34, 6 }, + { DBGBUS_SSPP0, 34, 7 }, + + /* dma 0 */ + { DBGBUS_SSPP0, 40, 0 }, + { DBGBUS_SSPP0, 40, 1 }, + { DBGBUS_SSPP0, 40, 2 }, + { DBGBUS_SSPP0, 40, 3 }, + { DBGBUS_SSPP0, 40, 4 }, + { DBGBUS_SSPP0, 40, 5 }, + { DBGBUS_SSPP0, 40, 6 }, + { DBGBUS_SSPP0, 40, 7 }, + + { DBGBUS_SSPP0, 41, 0 }, + { DBGBUS_SSPP0, 41, 1 }, + { DBGBUS_SSPP0, 41, 2 }, + { DBGBUS_SSPP0, 41, 3 }, + { DBGBUS_SSPP0, 41, 4 }, + { DBGBUS_SSPP0, 41, 5 }, + { DBGBUS_SSPP0, 41, 6 }, + { DBGBUS_SSPP0, 41, 7 }, + + { DBGBUS_SSPP0, 42, 0 }, + { DBGBUS_SSPP0, 42, 1 }, + { DBGBUS_SSPP0, 42, 2 }, + { DBGBUS_SSPP0, 42, 3 }, + { DBGBUS_SSPP0, 42, 4 }, + { DBGBUS_SSPP0, 42, 5 }, + { DBGBUS_SSPP0, 42, 6 }, + { DBGBUS_SSPP0, 42, 7 }, + + { DBGBUS_SSPP0, 44, 0 }, + { DBGBUS_SSPP0, 44, 1 }, + { DBGBUS_SSPP0, 44, 2 }, + { DBGBUS_SSPP0, 44, 3 }, + { DBGBUS_SSPP0, 44, 4 }, + { DBGBUS_SSPP0, 44, 5 }, + { DBGBUS_SSPP0, 44, 6 }, + { DBGBUS_SSPP0, 44, 7 }, + + { DBGBUS_SSPP0, 45, 0 }, + { DBGBUS_SSPP0, 45, 1 }, + { DBGBUS_SSPP0, 45, 2 }, + { DBGBUS_SSPP0, 45, 3 }, + { DBGBUS_SSPP0, 45, 4 }, + { DBGBUS_SSPP0, 45, 5 }, + { DBGBUS_SSPP0, 45, 6 }, + { DBGBUS_SSPP0, 45, 7 }, + + /* fetch sspp1 */ + /* vig 1 */ + { DBGBUS_SSPP1, 0, 0 }, + { DBGBUS_SSPP1, 0, 1 }, + { DBGBUS_SSPP1, 0, 2 }, + { DBGBUS_SSPP1, 0, 3 }, + { DBGBUS_SSPP1, 0, 4 }, + { DBGBUS_SSPP1, 0, 5 }, + { DBGBUS_SSPP1, 0, 6 }, + { DBGBUS_SSPP1, 0, 7 }, + + { DBGBUS_SSPP1, 1, 0 }, + { DBGBUS_SSPP1, 1, 1 }, + { DBGBUS_SSPP1, 1, 2 }, + { DBGBUS_SSPP1, 1, 3 }, + { DBGBUS_SSPP1, 1, 4 }, + { DBGBUS_SSPP1, 1, 5 }, + { DBGBUS_SSPP1, 1, 6 }, + { DBGBUS_SSPP1, 1, 7 }, + + { DBGBUS_SSPP1, 2, 0 }, + { DBGBUS_SSPP1, 2, 1 }, + { DBGBUS_SSPP1, 2, 2 }, + { DBGBUS_SSPP1, 2, 3 }, + { DBGBUS_SSPP1, 2, 4 }, + { DBGBUS_SSPP1, 2, 5 }, + { DBGBUS_SSPP1, 2, 6 }, + { DBGBUS_SSPP1, 2, 7 }, + + { DBGBUS_SSPP1, 4, 0 }, + { DBGBUS_SSPP1, 4, 1 }, + { DBGBUS_SSPP1, 4, 2 }, + { DBGBUS_SSPP1, 4, 3 }, + { DBGBUS_SSPP1, 4, 4 }, + { DBGBUS_SSPP1, 4, 5 }, + { DBGBUS_SSPP1, 4, 6 }, + { DBGBUS_SSPP1, 4, 7 }, + + { DBGBUS_SSPP1, 5, 0 }, + { DBGBUS_SSPP1, 5, 1 }, + { DBGBUS_SSPP1, 5, 2 }, + { DBGBUS_SSPP1, 5, 3 }, + { DBGBUS_SSPP1, 5, 4 }, + { DBGBUS_SSPP1, 5, 5 }, + { DBGBUS_SSPP1, 5, 6 }, + { DBGBUS_SSPP1, 5, 7 }, + + /* vig 3 */ + { DBGBUS_SSPP1, 20, 0 }, + { DBGBUS_SSPP1, 20, 1 }, + { DBGBUS_SSPP1, 20, 2 }, + { DBGBUS_SSPP1, 20, 3 }, + { DBGBUS_SSPP1, 20, 4 }, + { DBGBUS_SSPP1, 20, 5 }, + { DBGBUS_SSPP1, 20, 6 }, + { DBGBUS_SSPP1, 20, 7 }, + + { DBGBUS_SSPP1, 21, 0 }, + { DBGBUS_SSPP1, 21, 1 }, + { DBGBUS_SSPP1, 21, 2 }, + { DBGBUS_SSPP1, 21, 3 }, + { DBGBUS_SSPP1, 21, 4 }, + { DBGBUS_SSPP1, 21, 5 }, + { DBGBUS_SSPP1, 21, 6 }, + { DBGBUS_SSPP1, 21, 7 }, + + { DBGBUS_SSPP1, 22, 0 }, + { DBGBUS_SSPP1, 22, 1 }, + { DBGBUS_SSPP1, 22, 2 }, + { DBGBUS_SSPP1, 22, 3 }, + { DBGBUS_SSPP1, 22, 4 }, + { DBGBUS_SSPP1, 22, 5 }, + { DBGBUS_SSPP1, 22, 6 }, + { DBGBUS_SSPP1, 22, 7 }, + + { DBGBUS_SSPP1, 24, 0 }, + { DBGBUS_SSPP1, 24, 1 }, + { DBGBUS_SSPP1, 24, 2 }, + { DBGBUS_SSPP1, 24, 3 }, + { DBGBUS_SSPP1, 24, 4 }, + { DBGBUS_SSPP1, 24, 5 }, + { DBGBUS_SSPP1, 24, 6 }, + { DBGBUS_SSPP1, 24, 7 }, + + { DBGBUS_SSPP1, 25, 0 }, + { DBGBUS_SSPP1, 25, 1 }, + { DBGBUS_SSPP1, 25, 2 }, + { DBGBUS_SSPP1, 25, 3 }, + { DBGBUS_SSPP1, 25, 4 }, + { DBGBUS_SSPP1, 25, 5 }, + { DBGBUS_SSPP1, 25, 6 }, + { DBGBUS_SSPP1, 25, 7 }, + + /* dma 3 */ + { DBGBUS_SSPP1, 30, 0 }, + { DBGBUS_SSPP1, 30, 1 }, + { DBGBUS_SSPP1, 30, 2 }, + { DBGBUS_SSPP1, 30, 3 }, + { DBGBUS_SSPP1, 30, 4 }, + { DBGBUS_SSPP1, 30, 5 }, + { DBGBUS_SSPP1, 30, 6 }, + { DBGBUS_SSPP1, 30, 7 }, + + { DBGBUS_SSPP1, 31, 0 }, + { DBGBUS_SSPP1, 31, 1 }, + { DBGBUS_SSPP1, 31, 2 }, + { DBGBUS_SSPP1, 31, 3 }, + { DBGBUS_SSPP1, 31, 4 }, + { DBGBUS_SSPP1, 31, 5 }, + { DBGBUS_SSPP1, 31, 6 }, + { DBGBUS_SSPP1, 31, 7 }, + + { DBGBUS_SSPP1, 32, 0 }, + { DBGBUS_SSPP1, 32, 1 }, + { DBGBUS_SSPP1, 32, 2 }, + { DBGBUS_SSPP1, 32, 3 }, + { DBGBUS_SSPP1, 32, 4 }, + { DBGBUS_SSPP1, 32, 5 }, + { DBGBUS_SSPP1, 32, 6 }, + { DBGBUS_SSPP1, 32, 7 }, + + { DBGBUS_SSPP1, 33, 0 }, + { DBGBUS_SSPP1, 33, 1 }, + { DBGBUS_SSPP1, 33, 2 }, + { DBGBUS_SSPP1, 33, 3 }, + { DBGBUS_SSPP1, 33, 4 }, + { DBGBUS_SSPP1, 33, 5 }, + { DBGBUS_SSPP1, 33, 6 }, + { DBGBUS_SSPP1, 33, 7 }, + + { DBGBUS_SSPP1, 34, 0 }, + { DBGBUS_SSPP1, 34, 1 }, + { DBGBUS_SSPP1, 34, 2 }, + { DBGBUS_SSPP1, 34, 3 }, + { DBGBUS_SSPP1, 34, 4 }, + { DBGBUS_SSPP1, 34, 5 }, + { DBGBUS_SSPP1, 34, 6 }, + { DBGBUS_SSPP1, 34, 7 }, + + /* dma 1 */ + { DBGBUS_SSPP1, 40, 0 }, + { DBGBUS_SSPP1, 40, 1 }, + { DBGBUS_SSPP1, 40, 2 }, + { DBGBUS_SSPP1, 40, 3 }, + { DBGBUS_SSPP1, 40, 4 }, + { DBGBUS_SSPP1, 40, 5 }, + { DBGBUS_SSPP1, 40, 6 }, + { DBGBUS_SSPP1, 40, 7 }, + + { DBGBUS_SSPP1, 41, 0 }, + { DBGBUS_SSPP1, 41, 1 }, + { DBGBUS_SSPP1, 41, 2 }, + { DBGBUS_SSPP1, 41, 3 }, + { DBGBUS_SSPP1, 41, 4 }, + { DBGBUS_SSPP1, 41, 5 }, + { DBGBUS_SSPP1, 41, 6 }, + { DBGBUS_SSPP1, 41, 7 }, + + { DBGBUS_SSPP1, 42, 0 }, + { DBGBUS_SSPP1, 42, 1 }, + { DBGBUS_SSPP1, 42, 2 }, + { DBGBUS_SSPP1, 42, 3 }, + { DBGBUS_SSPP1, 42, 4 }, + { DBGBUS_SSPP1, 42, 5 }, + { DBGBUS_SSPP1, 42, 6 }, + { DBGBUS_SSPP1, 42, 7 }, + + { DBGBUS_SSPP1, 44, 0 }, + { DBGBUS_SSPP1, 44, 1 }, + { DBGBUS_SSPP1, 44, 2 }, + { DBGBUS_SSPP1, 44, 3 }, + { DBGBUS_SSPP1, 44, 4 }, + { DBGBUS_SSPP1, 44, 5 }, + { DBGBUS_SSPP1, 44, 6 }, + { DBGBUS_SSPP1, 44, 7 }, + + { DBGBUS_SSPP1, 45, 0 }, + { DBGBUS_SSPP1, 45, 1 }, + { DBGBUS_SSPP1, 45, 2 }, + { DBGBUS_SSPP1, 45, 3 }, + { DBGBUS_SSPP1, 45, 4 }, + { DBGBUS_SSPP1, 45, 5 }, + { DBGBUS_SSPP1, 45, 6 }, + { DBGBUS_SSPP1, 45, 7 }, + + /* ppb_0 */ + { DBGBUS_DSPP, 31, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 33, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 35, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 42, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 47, 0, _sde_debug_bus_ppb0_dump }, + { DBGBUS_DSPP, 49, 0, _sde_debug_bus_ppb0_dump }, + + /* ppb_1 */ + { DBGBUS_DSPP, 32, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 34, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 36, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 43, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 48, 0, _sde_debug_bus_ppb1_dump }, + { DBGBUS_DSPP, 50, 0, _sde_debug_bus_ppb1_dump }, + + /* crossbar */ + { DBGBUS_DSPP, 0, 0, _sde_debug_bus_xbar_dump }, + + /* rotator */ + { DBGBUS_DSPP, 9, 0}, + + /* ltm */ + { DBGBUS_DSPP, 45, 0, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 1, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 2, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 3, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 4, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 5, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 6, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 7, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 8, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 9, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 10, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 11, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 12, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 13, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 14, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 15, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 16, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 17, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 18, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 45, 31, _sde_debug_bus_ltm_dump}, + + { DBGBUS_DSPP, 46, 0, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 1, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 2, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 3, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 4, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 5, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 6, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 7, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 8, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 9, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 10, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 11, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 12, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 13, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 14, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 15, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 16, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 17, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 18, _sde_debug_bus_ltm_dump}, + { DBGBUS_DSPP, 46, 31, _sde_debug_bus_ltm_dump}, + + /* blend */ + /* LM0 */ + { DBGBUS_DSPP, 63, 1}, + { DBGBUS_DSPP, 63, 2}, + { DBGBUS_DSPP, 63, 3}, + { DBGBUS_DSPP, 63, 4}, + { DBGBUS_DSPP, 63, 5}, + { DBGBUS_DSPP, 63, 6}, + { DBGBUS_DSPP, 63, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 64, 1}, + { DBGBUS_DSPP, 64, 2}, + { DBGBUS_DSPP, 64, 3}, + { DBGBUS_DSPP, 64, 4}, + { DBGBUS_DSPP, 64, 5}, + { DBGBUS_DSPP, 64, 6}, + { DBGBUS_DSPP, 64, 7}, + + { DBGBUS_DSPP, 65, 1}, + { DBGBUS_DSPP, 65, 2}, + { DBGBUS_DSPP, 65, 3}, + { DBGBUS_DSPP, 65, 4}, + { DBGBUS_DSPP, 65, 5}, + { DBGBUS_DSPP, 65, 6}, + { DBGBUS_DSPP, 65, 7}, + + { DBGBUS_DSPP, 66, 1}, + { DBGBUS_DSPP, 66, 2}, + { DBGBUS_DSPP, 66, 3}, + { DBGBUS_DSPP, 66, 4}, + { DBGBUS_DSPP, 66, 5}, + { DBGBUS_DSPP, 66, 6}, + { DBGBUS_DSPP, 66, 7}, + + { DBGBUS_DSPP, 67, 1}, + { DBGBUS_DSPP, 67, 2}, + { DBGBUS_DSPP, 67, 3}, + { DBGBUS_DSPP, 67, 4}, + { DBGBUS_DSPP, 67, 5}, + { DBGBUS_DSPP, 67, 6}, + { DBGBUS_DSPP, 67, 7}, + + { DBGBUS_DSPP, 68, 1}, + { DBGBUS_DSPP, 68, 2}, + { DBGBUS_DSPP, 68, 3}, + { DBGBUS_DSPP, 68, 4}, + { DBGBUS_DSPP, 68, 5}, + { DBGBUS_DSPP, 68, 6}, + { DBGBUS_DSPP, 68, 7}, + + { DBGBUS_DSPP, 69, 1}, + { DBGBUS_DSPP, 69, 2}, + { DBGBUS_DSPP, 69, 3}, + { DBGBUS_DSPP, 69, 4}, + { DBGBUS_DSPP, 69, 5}, + { DBGBUS_DSPP, 69, 6}, + { DBGBUS_DSPP, 69, 7}, + + { DBGBUS_DSPP, 84, 1}, + { DBGBUS_DSPP, 84, 2}, + { DBGBUS_DSPP, 84, 3}, + { DBGBUS_DSPP, 84, 4}, + { DBGBUS_DSPP, 84, 5}, + { DBGBUS_DSPP, 84, 6}, + { DBGBUS_DSPP, 84, 7}, + + { DBGBUS_DSPP, 85, 1}, + { DBGBUS_DSPP, 85, 2}, + { DBGBUS_DSPP, 85, 3}, + { DBGBUS_DSPP, 85, 4}, + { DBGBUS_DSPP, 85, 5}, + { DBGBUS_DSPP, 85, 6}, + { DBGBUS_DSPP, 85, 7}, + + { DBGBUS_DSPP, 86, 1}, + { DBGBUS_DSPP, 86, 2}, + { DBGBUS_DSPP, 86, 3}, + { DBGBUS_DSPP, 86, 4}, + { DBGBUS_DSPP, 86, 5}, + { DBGBUS_DSPP, 86, 6}, + { DBGBUS_DSPP, 86, 7}, + + { DBGBUS_DSPP, 87, 1}, + { DBGBUS_DSPP, 87, 2}, + { DBGBUS_DSPP, 87, 3}, + { DBGBUS_DSPP, 87, 4}, + { DBGBUS_DSPP, 87, 5}, + { DBGBUS_DSPP, 87, 6}, + { DBGBUS_DSPP, 87, 7}, + + /* LM1 */ + { DBGBUS_DSPP, 70, 1}, + { DBGBUS_DSPP, 70, 2}, + { DBGBUS_DSPP, 70, 3}, + { DBGBUS_DSPP, 70, 4}, + { DBGBUS_DSPP, 70, 5}, + { DBGBUS_DSPP, 70, 6}, + { DBGBUS_DSPP, 70, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 71, 1}, + { DBGBUS_DSPP, 71, 2}, + { DBGBUS_DSPP, 71, 3}, + { DBGBUS_DSPP, 71, 4}, + { DBGBUS_DSPP, 71, 5}, + { DBGBUS_DSPP, 71, 6}, + { DBGBUS_DSPP, 71, 7}, + + { DBGBUS_DSPP, 72, 1}, + { DBGBUS_DSPP, 72, 2}, + { DBGBUS_DSPP, 72, 3}, + { DBGBUS_DSPP, 72, 4}, + { DBGBUS_DSPP, 72, 5}, + { DBGBUS_DSPP, 72, 6}, + { DBGBUS_DSPP, 72, 7}, + + { DBGBUS_DSPP, 73, 1}, + { DBGBUS_DSPP, 73, 2}, + { DBGBUS_DSPP, 73, 3}, + { DBGBUS_DSPP, 73, 4}, + { DBGBUS_DSPP, 73, 5}, + { DBGBUS_DSPP, 73, 6}, + { DBGBUS_DSPP, 73, 7}, + + { DBGBUS_DSPP, 74, 1}, + { DBGBUS_DSPP, 74, 2}, + { DBGBUS_DSPP, 74, 3}, + { DBGBUS_DSPP, 74, 4}, + { DBGBUS_DSPP, 74, 5}, + { DBGBUS_DSPP, 74, 6}, + { DBGBUS_DSPP, 74, 7}, + + { DBGBUS_DSPP, 75, 1}, + { DBGBUS_DSPP, 75, 2}, + { DBGBUS_DSPP, 75, 3}, + { DBGBUS_DSPP, 75, 4}, + { DBGBUS_DSPP, 75, 5}, + { DBGBUS_DSPP, 75, 6}, + { DBGBUS_DSPP, 75, 7}, + + { DBGBUS_DSPP, 76, 1}, + { DBGBUS_DSPP, 76, 2}, + { DBGBUS_DSPP, 76, 3}, + { DBGBUS_DSPP, 76, 4}, + { DBGBUS_DSPP, 76, 5}, + { DBGBUS_DSPP, 76, 6}, + { DBGBUS_DSPP, 76, 7}, + + { DBGBUS_DSPP, 88, 1}, + { DBGBUS_DSPP, 88, 2}, + { DBGBUS_DSPP, 88, 3}, + { DBGBUS_DSPP, 88, 4}, + { DBGBUS_DSPP, 88, 5}, + { DBGBUS_DSPP, 88, 6}, + { DBGBUS_DSPP, 88, 7}, + + { DBGBUS_DSPP, 89, 1}, + { DBGBUS_DSPP, 89, 2}, + { DBGBUS_DSPP, 89, 3}, + { DBGBUS_DSPP, 89, 4}, + { DBGBUS_DSPP, 89, 5}, + { DBGBUS_DSPP, 89, 6}, + { DBGBUS_DSPP, 89, 7}, + + { DBGBUS_DSPP, 90, 1}, + { DBGBUS_DSPP, 90, 2}, + { DBGBUS_DSPP, 90, 3}, + { DBGBUS_DSPP, 90, 4}, + { DBGBUS_DSPP, 90, 5}, + { DBGBUS_DSPP, 90, 6}, + { DBGBUS_DSPP, 90, 7}, + + { DBGBUS_DSPP, 91, 1}, + { DBGBUS_DSPP, 91, 2}, + { DBGBUS_DSPP, 91, 3}, + { DBGBUS_DSPP, 91, 4}, + { DBGBUS_DSPP, 91, 5}, + { DBGBUS_DSPP, 91, 6}, + { DBGBUS_DSPP, 91, 7}, + + /* LM2 */ + { DBGBUS_DSPP, 77, 0}, + { DBGBUS_DSPP, 77, 1}, + { DBGBUS_DSPP, 77, 2}, + { DBGBUS_DSPP, 77, 3}, + { DBGBUS_DSPP, 77, 4}, + { DBGBUS_DSPP, 77, 5}, + { DBGBUS_DSPP, 77, 6}, + { DBGBUS_DSPP, 77, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 78, 0}, + { DBGBUS_DSPP, 78, 1}, + { DBGBUS_DSPP, 78, 2}, + { DBGBUS_DSPP, 78, 3}, + { DBGBUS_DSPP, 78, 4}, + { DBGBUS_DSPP, 78, 5}, + { DBGBUS_DSPP, 78, 6}, + { DBGBUS_DSPP, 78, 7}, + + { DBGBUS_DSPP, 79, 0}, + { DBGBUS_DSPP, 79, 1}, + { DBGBUS_DSPP, 79, 2}, + { DBGBUS_DSPP, 79, 3}, + { DBGBUS_DSPP, 79, 4}, + { DBGBUS_DSPP, 79, 5}, + { DBGBUS_DSPP, 79, 6}, + { DBGBUS_DSPP, 79, 7}, + + { DBGBUS_DSPP, 80, 0}, + { DBGBUS_DSPP, 80, 1}, + { DBGBUS_DSPP, 80, 2}, + { DBGBUS_DSPP, 80, 3}, + { DBGBUS_DSPP, 80, 4}, + { DBGBUS_DSPP, 80, 5}, + { DBGBUS_DSPP, 80, 6}, + { DBGBUS_DSPP, 80, 7}, + + { DBGBUS_DSPP, 81, 0}, + { DBGBUS_DSPP, 81, 1}, + { DBGBUS_DSPP, 81, 2}, + { DBGBUS_DSPP, 81, 3}, + { DBGBUS_DSPP, 81, 4}, + { DBGBUS_DSPP, 81, 5}, + { DBGBUS_DSPP, 81, 6}, + { DBGBUS_DSPP, 81, 7}, + + { DBGBUS_DSPP, 82, 0}, + { DBGBUS_DSPP, 82, 1}, + { DBGBUS_DSPP, 82, 2}, + { DBGBUS_DSPP, 82, 3}, + { DBGBUS_DSPP, 82, 4}, + { DBGBUS_DSPP, 82, 5}, + { DBGBUS_DSPP, 82, 6}, + { DBGBUS_DSPP, 82, 7}, + + { DBGBUS_DSPP, 83, 0}, + { DBGBUS_DSPP, 83, 1}, + { DBGBUS_DSPP, 83, 2}, + { DBGBUS_DSPP, 83, 3}, + { DBGBUS_DSPP, 83, 4}, + { DBGBUS_DSPP, 83, 5}, + { DBGBUS_DSPP, 83, 6}, + { DBGBUS_DSPP, 83, 7}, + + { DBGBUS_DSPP, 92, 1}, + { DBGBUS_DSPP, 92, 2}, + { DBGBUS_DSPP, 92, 3}, + { DBGBUS_DSPP, 92, 4}, + { DBGBUS_DSPP, 92, 5}, + { DBGBUS_DSPP, 92, 6}, + { DBGBUS_DSPP, 92, 7}, + + { DBGBUS_DSPP, 93, 1}, + { DBGBUS_DSPP, 93, 2}, + { DBGBUS_DSPP, 93, 3}, + { DBGBUS_DSPP, 93, 4}, + { DBGBUS_DSPP, 93, 5}, + { DBGBUS_DSPP, 93, 6}, + { DBGBUS_DSPP, 93, 7}, + + { DBGBUS_DSPP, 94, 1}, + { DBGBUS_DSPP, 94, 2}, + { DBGBUS_DSPP, 94, 3}, + { DBGBUS_DSPP, 94, 4}, + { DBGBUS_DSPP, 94, 5}, + { DBGBUS_DSPP, 94, 6}, + { DBGBUS_DSPP, 94, 7}, + + { DBGBUS_DSPP, 95, 1}, + { DBGBUS_DSPP, 95, 2}, + { DBGBUS_DSPP, 95, 3}, + { DBGBUS_DSPP, 95, 4}, + { DBGBUS_DSPP, 95, 5}, + { DBGBUS_DSPP, 95, 6}, + { DBGBUS_DSPP, 95, 7}, + + /* LM3 */ + { DBGBUS_DSPP, 110, 1}, + { DBGBUS_DSPP, 110, 2}, + { DBGBUS_DSPP, 110, 3}, + { DBGBUS_DSPP, 110, 4}, + { DBGBUS_DSPP, 110, 5}, + { DBGBUS_DSPP, 110, 6}, + { DBGBUS_DSPP, 110, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 111, 1}, + { DBGBUS_DSPP, 111, 2}, + { DBGBUS_DSPP, 111, 3}, + { DBGBUS_DSPP, 111, 4}, + { DBGBUS_DSPP, 111, 5}, + { DBGBUS_DSPP, 111, 6}, + { DBGBUS_DSPP, 111, 7}, + + { DBGBUS_DSPP, 112, 1}, + { DBGBUS_DSPP, 112, 2}, + { DBGBUS_DSPP, 112, 3}, + { DBGBUS_DSPP, 112, 4}, + { DBGBUS_DSPP, 112, 5}, + { DBGBUS_DSPP, 112, 6}, + { DBGBUS_DSPP, 112, 7}, + + { DBGBUS_DSPP, 113, 1}, + { DBGBUS_DSPP, 113, 2}, + { DBGBUS_DSPP, 113, 3}, + { DBGBUS_DSPP, 113, 4}, + { DBGBUS_DSPP, 113, 5}, + { DBGBUS_DSPP, 113, 6}, + { DBGBUS_DSPP, 113, 7}, + + { DBGBUS_DSPP, 114, 1}, + { DBGBUS_DSPP, 114, 2}, + { DBGBUS_DSPP, 114, 3}, + { DBGBUS_DSPP, 114, 4}, + { DBGBUS_DSPP, 114, 5}, + { DBGBUS_DSPP, 114, 6}, + { DBGBUS_DSPP, 114, 7}, + + { DBGBUS_DSPP, 115, 1}, + { DBGBUS_DSPP, 115, 2}, + { DBGBUS_DSPP, 115, 3}, + { DBGBUS_DSPP, 115, 4}, + { DBGBUS_DSPP, 115, 5}, + { DBGBUS_DSPP, 115, 6}, + { DBGBUS_DSPP, 115, 7}, + + { DBGBUS_DSPP, 116, 1}, + { DBGBUS_DSPP, 116, 2}, + { DBGBUS_DSPP, 116, 3}, + { DBGBUS_DSPP, 116, 4}, + { DBGBUS_DSPP, 116, 5}, + { DBGBUS_DSPP, 116, 6}, + { DBGBUS_DSPP, 116, 7}, + + { DBGBUS_DSPP, 117, 1}, + { DBGBUS_DSPP, 117, 2}, + { DBGBUS_DSPP, 117, 3}, + { DBGBUS_DSPP, 117, 4}, + { DBGBUS_DSPP, 117, 5}, + { DBGBUS_DSPP, 117, 6}, + { DBGBUS_DSPP, 117, 7}, + + { DBGBUS_DSPP, 118, 1}, + { DBGBUS_DSPP, 118, 2}, + { DBGBUS_DSPP, 118, 3}, + { DBGBUS_DSPP, 118, 4}, + { DBGBUS_DSPP, 118, 5}, + { DBGBUS_DSPP, 118, 6}, + { DBGBUS_DSPP, 118, 7}, + + { DBGBUS_DSPP, 119, 1}, + { DBGBUS_DSPP, 119, 2}, + { DBGBUS_DSPP, 119, 3}, + { DBGBUS_DSPP, 119, 4}, + { DBGBUS_DSPP, 119, 5}, + { DBGBUS_DSPP, 119, 6}, + { DBGBUS_DSPP, 119, 7}, + + { DBGBUS_DSPP, 120, 1}, + { DBGBUS_DSPP, 120, 2}, + { DBGBUS_DSPP, 120, 3}, + { DBGBUS_DSPP, 120, 4}, + { DBGBUS_DSPP, 120, 5}, + { DBGBUS_DSPP, 120, 6}, + { DBGBUS_DSPP, 120, 7}, + + /* LM4 */ + { DBGBUS_DSPP, 96, 1}, + { DBGBUS_DSPP, 96, 2}, + { DBGBUS_DSPP, 96, 3}, + { DBGBUS_DSPP, 96, 4}, + { DBGBUS_DSPP, 96, 5}, + { DBGBUS_DSPP, 96, 6}, + { DBGBUS_DSPP, 96, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 97, 1}, + { DBGBUS_DSPP, 97, 2}, + { DBGBUS_DSPP, 97, 3}, + { DBGBUS_DSPP, 97, 4}, + { DBGBUS_DSPP, 97, 5}, + { DBGBUS_DSPP, 97, 6}, + { DBGBUS_DSPP, 97, 7}, + + { DBGBUS_DSPP, 98, 1}, + { DBGBUS_DSPP, 98, 2}, + { DBGBUS_DSPP, 98, 3}, + { DBGBUS_DSPP, 98, 4}, + { DBGBUS_DSPP, 98, 5}, + { DBGBUS_DSPP, 98, 6}, + { DBGBUS_DSPP, 98, 7}, + + { DBGBUS_DSPP, 99, 1}, + { DBGBUS_DSPP, 99, 2}, + { DBGBUS_DSPP, 99, 3}, + { DBGBUS_DSPP, 99, 4}, + { DBGBUS_DSPP, 99, 5}, + { DBGBUS_DSPP, 99, 6}, + { DBGBUS_DSPP, 99, 7}, + + { DBGBUS_DSPP, 100, 1}, + { DBGBUS_DSPP, 100, 2}, + { DBGBUS_DSPP, 100, 3}, + { DBGBUS_DSPP, 100, 4}, + { DBGBUS_DSPP, 100, 5}, + { DBGBUS_DSPP, 100, 6}, + { DBGBUS_DSPP, 100, 7}, + + { DBGBUS_DSPP, 101, 1}, + { DBGBUS_DSPP, 101, 2}, + { DBGBUS_DSPP, 101, 3}, + { DBGBUS_DSPP, 101, 4}, + { DBGBUS_DSPP, 101, 5}, + { DBGBUS_DSPP, 101, 6}, + { DBGBUS_DSPP, 101, 7}, + + { DBGBUS_DSPP, 103, 1}, + { DBGBUS_DSPP, 103, 2}, + { DBGBUS_DSPP, 103, 3}, + { DBGBUS_DSPP, 103, 4}, + { DBGBUS_DSPP, 103, 5}, + { DBGBUS_DSPP, 103, 6}, + { DBGBUS_DSPP, 103, 7}, + + { DBGBUS_DSPP, 105, 1}, + { DBGBUS_DSPP, 105, 2}, + { DBGBUS_DSPP, 105, 3}, + { DBGBUS_DSPP, 105, 4}, + { DBGBUS_DSPP, 105, 5}, + { DBGBUS_DSPP, 105, 6}, + { DBGBUS_DSPP, 105, 7}, + + { DBGBUS_DSPP, 106, 1}, + { DBGBUS_DSPP, 106, 2}, + { DBGBUS_DSPP, 106, 3}, + { DBGBUS_DSPP, 106, 4}, + { DBGBUS_DSPP, 106, 5}, + { DBGBUS_DSPP, 106, 6}, + { DBGBUS_DSPP, 106, 7}, + + { DBGBUS_DSPP, 109, 1}, + { DBGBUS_DSPP, 109, 2}, + { DBGBUS_DSPP, 109, 3}, + { DBGBUS_DSPP, 109, 4}, + { DBGBUS_DSPP, 109, 5}, + { DBGBUS_DSPP, 109, 6}, + { DBGBUS_DSPP, 109, 7}, + + { DBGBUS_DSPP, 122, 1}, + { DBGBUS_DSPP, 122, 2}, + { DBGBUS_DSPP, 122, 3}, + { DBGBUS_DSPP, 122, 4}, + { DBGBUS_DSPP, 122, 5}, + { DBGBUS_DSPP, 122, 6}, + { DBGBUS_DSPP, 122, 7}, + + /* LM5 */ + { DBGBUS_DSPP, 124, 1}, + { DBGBUS_DSPP, 124, 2}, + { DBGBUS_DSPP, 124, 3}, + { DBGBUS_DSPP, 124, 4}, + { DBGBUS_DSPP, 124, 5}, + { DBGBUS_DSPP, 124, 6}, + { DBGBUS_DSPP, 124, 7, _sde_debug_bus_lm_dump }, + + { DBGBUS_DSPP, 125, 1}, + { DBGBUS_DSPP, 125, 2}, + { DBGBUS_DSPP, 125, 3}, + { DBGBUS_DSPP, 125, 4}, + { DBGBUS_DSPP, 125, 5}, + { DBGBUS_DSPP, 125, 6}, + { DBGBUS_DSPP, 125, 7}, + + { DBGBUS_DSPP, 126, 1}, + { DBGBUS_DSPP, 126, 2}, + { DBGBUS_DSPP, 126, 3}, + { DBGBUS_DSPP, 126, 4}, + { DBGBUS_DSPP, 126, 5}, + { DBGBUS_DSPP, 126, 6}, + { DBGBUS_DSPP, 126, 7}, + + { DBGBUS_DSPP, 127, 1}, + { DBGBUS_DSPP, 127, 2}, + { DBGBUS_DSPP, 127, 3}, + { DBGBUS_DSPP, 127, 4}, + { DBGBUS_DSPP, 127, 5}, + { DBGBUS_DSPP, 127, 6}, + { DBGBUS_DSPP, 127, 7}, + + { DBGBUS_DSPP, 128, 1}, + { DBGBUS_DSPP, 128, 2}, + { DBGBUS_DSPP, 128, 3}, + { DBGBUS_DSPP, 128, 4}, + { DBGBUS_DSPP, 128, 5}, + { DBGBUS_DSPP, 128, 6}, + { DBGBUS_DSPP, 128, 7}, + + { DBGBUS_DSPP, 129, 1}, + { DBGBUS_DSPP, 129, 2}, + { DBGBUS_DSPP, 129, 3}, + { DBGBUS_DSPP, 129, 4}, + { DBGBUS_DSPP, 129, 5}, + { DBGBUS_DSPP, 129, 6}, + { DBGBUS_DSPP, 129, 7}, + + { DBGBUS_DSPP, 131, 1}, + { DBGBUS_DSPP, 131, 2}, + { DBGBUS_DSPP, 131, 3}, + { DBGBUS_DSPP, 131, 4}, + { DBGBUS_DSPP, 131, 5}, + { DBGBUS_DSPP, 131, 6}, + { DBGBUS_DSPP, 131, 7}, + + { DBGBUS_DSPP, 132, 1}, + { DBGBUS_DSPP, 132, 2}, + { DBGBUS_DSPP, 132, 3}, + { DBGBUS_DSPP, 132, 4}, + { DBGBUS_DSPP, 132, 5}, + { DBGBUS_DSPP, 132, 6}, + { DBGBUS_DSPP, 132, 7}, + + { DBGBUS_DSPP, 133, 1}, + { DBGBUS_DSPP, 133, 2}, + { DBGBUS_DSPP, 133, 3}, + { DBGBUS_DSPP, 133, 4}, + { DBGBUS_DSPP, 133, 5}, + { DBGBUS_DSPP, 133, 6}, + { DBGBUS_DSPP, 133, 7}, + + { DBGBUS_DSPP, 134, 1}, + { DBGBUS_DSPP, 134, 2}, + { DBGBUS_DSPP, 134, 3}, + { DBGBUS_DSPP, 134, 4}, + { DBGBUS_DSPP, 134, 5}, + { DBGBUS_DSPP, 134, 6}, + { DBGBUS_DSPP, 134, 7}, + + { DBGBUS_DSPP, 135, 1}, + { DBGBUS_DSPP, 135, 2}, + { DBGBUS_DSPP, 135, 3}, + { DBGBUS_DSPP, 135, 4}, + { DBGBUS_DSPP, 135, 5}, + { DBGBUS_DSPP, 135, 6}, + { DBGBUS_DSPP, 135, 7}, + + /* csc */ + { DBGBUS_SSPP0, 7, 0}, + { DBGBUS_SSPP0, 7, 1}, + { DBGBUS_SSPP0, 7, 2}, + { DBGBUS_SSPP0, 27, 0}, + { DBGBUS_SSPP0, 27, 1}, + { DBGBUS_SSPP0, 27, 2}, + { DBGBUS_SSPP1, 7, 0}, + { DBGBUS_SSPP1, 7, 1}, + { DBGBUS_SSPP1, 7, 2}, + { DBGBUS_SSPP1, 27, 0}, + { DBGBUS_SSPP1, 27, 1}, + { DBGBUS_SSPP1, 27, 2}, + + /* pcc */ + { DBGBUS_SSPP0, 43, 3}, + { DBGBUS_SSPP0, 47, 3}, + { DBGBUS_SSPP1, 43, 3}, + { DBGBUS_SSPP1, 47, 3}, + + /* spa */ + { DBGBUS_SSPP0, 8, 0}, + { DBGBUS_SSPP0, 28, 0}, + { DBGBUS_SSPP1, 8, 0}, + { DBGBUS_SSPP1, 28, 0}, + + /* dspp pa */ + { DBGBUS_DSPP, 13, 0}, + { DBGBUS_DSPP, 19, 0}, + { DBGBUS_DSPP, 24, 0}, + { DBGBUS_DSPP, 37, 0}, + + /* igc */ + { DBGBUS_SSPP0, 39, 0}, + { DBGBUS_SSPP0, 39, 1}, + { DBGBUS_SSPP0, 39, 2}, + + { DBGBUS_SSPP1, 39, 0}, + { DBGBUS_SSPP1, 39, 1}, + { DBGBUS_SSPP1, 39, 2}, + + { DBGBUS_SSPP0, 46, 0}, + { DBGBUS_SSPP0, 46, 1}, + { DBGBUS_SSPP0, 46, 2}, + + { DBGBUS_SSPP1, 46, 0}, + { DBGBUS_SSPP1, 46, 1}, + { DBGBUS_SSPP1, 46, 2}, + + { DBGBUS_DSPP, 14, 0}, + { DBGBUS_DSPP, 14, 1}, + { DBGBUS_DSPP, 14, 2}, + { DBGBUS_DSPP, 20, 0}, + { DBGBUS_DSPP, 20, 1}, + { DBGBUS_DSPP, 20, 2}, + { DBGBUS_DSPP, 25, 0}, + { DBGBUS_DSPP, 25, 1}, + { DBGBUS_DSPP, 25, 2}, + { DBGBUS_DSPP, 38, 0}, + { DBGBUS_DSPP, 38, 1}, + { DBGBUS_DSPP, 38, 2}, + + /* intf0-3 */ + { DBGBUS_PERIPH, 0, 0}, + { DBGBUS_PERIPH, 1, 0}, + { DBGBUS_PERIPH, 2, 0}, + { DBGBUS_PERIPH, 3, 0}, + { DBGBUS_PERIPH, 4, 0}, + { DBGBUS_PERIPH, 5, 0}, + + /* te counter wrapper */ + { DBGBUS_PERIPH, 60, 0}, + { DBGBUS_PERIPH, 60, 1}, + { DBGBUS_PERIPH, 60, 2}, + { DBGBUS_PERIPH, 60, 3}, + { DBGBUS_PERIPH, 60, 4}, + { DBGBUS_PERIPH, 60, 5}, + + /* dsc0 */ + { DBGBUS_PERIPH, 47, 0}, + { DBGBUS_PERIPH, 47, 1}, + { DBGBUS_PERIPH, 47, 2}, + { DBGBUS_PERIPH, 47, 3}, + { DBGBUS_PERIPH, 47, 4}, + { DBGBUS_PERIPH, 47, 5}, + { DBGBUS_PERIPH, 47, 6}, + { DBGBUS_PERIPH, 47, 7}, + + /* dsc1 */ + { DBGBUS_PERIPH, 48, 0}, + { DBGBUS_PERIPH, 48, 1}, + { DBGBUS_PERIPH, 48, 2}, + { DBGBUS_PERIPH, 48, 3}, + { DBGBUS_PERIPH, 48, 4}, + { DBGBUS_PERIPH, 48, 5}, + { DBGBUS_PERIPH, 48, 6}, + { DBGBUS_PERIPH, 48, 7}, + + /* dsc2 */ + { DBGBUS_PERIPH, 50, 0}, + { DBGBUS_PERIPH, 50, 1}, + { DBGBUS_PERIPH, 50, 2}, + { DBGBUS_PERIPH, 50, 3}, + { DBGBUS_PERIPH, 50, 4}, + { DBGBUS_PERIPH, 50, 5}, + { DBGBUS_PERIPH, 50, 6}, + { DBGBUS_PERIPH, 50, 7}, + + /* dsc3 */ + { DBGBUS_PERIPH, 51, 0}, + { DBGBUS_PERIPH, 51, 1}, + { DBGBUS_PERIPH, 51, 2}, + { DBGBUS_PERIPH, 51, 3}, + { DBGBUS_PERIPH, 51, 4}, + { DBGBUS_PERIPH, 51, 5}, + { DBGBUS_PERIPH, 51, 6}, + { DBGBUS_PERIPH, 51, 7}, + + /* dsc4 */ + { DBGBUS_PERIPH, 52, 0}, + { DBGBUS_PERIPH, 52, 1}, + { DBGBUS_PERIPH, 52, 2}, + { DBGBUS_PERIPH, 52, 3}, + { DBGBUS_PERIPH, 52, 4}, + { DBGBUS_PERIPH, 52, 5}, + { DBGBUS_PERIPH, 52, 6}, + { DBGBUS_PERIPH, 52, 7}, + + /* dsc5 */ + { DBGBUS_PERIPH, 53, 0}, + { DBGBUS_PERIPH, 53, 1}, + { DBGBUS_PERIPH, 53, 2}, + { DBGBUS_PERIPH, 53, 3}, + { DBGBUS_PERIPH, 53, 4}, + { DBGBUS_PERIPH, 53, 5}, + { DBGBUS_PERIPH, 53, 6}, + { DBGBUS_PERIPH, 53, 7}, + + /* tear-check */ + /* INTF_0 */ + { DBGBUS_PERIPH, 63, 0 }, + { DBGBUS_PERIPH, 63, 1 }, + { DBGBUS_PERIPH, 63, 2 }, + { DBGBUS_PERIPH, 63, 3 }, + { DBGBUS_PERIPH, 63, 4 }, + { DBGBUS_PERIPH, 63, 5 }, + { DBGBUS_PERIPH, 63, 6 }, + { DBGBUS_PERIPH, 63, 7 }, + + /* INTF_1 */ + { DBGBUS_PERIPH, 64, 0 }, + { DBGBUS_PERIPH, 64, 1 }, + { DBGBUS_PERIPH, 64, 2 }, + { DBGBUS_PERIPH, 64, 3 }, + { DBGBUS_PERIPH, 64, 4 }, + { DBGBUS_PERIPH, 64, 5 }, + { DBGBUS_PERIPH, 64, 6 }, + { DBGBUS_PERIPH, 64, 7 }, + + /* INTF_2 */ + { DBGBUS_PERIPH, 65, 0 }, + { DBGBUS_PERIPH, 65, 1 }, + { DBGBUS_PERIPH, 65, 2 }, + { DBGBUS_PERIPH, 65, 3 }, + { DBGBUS_PERIPH, 65, 4 }, + { DBGBUS_PERIPH, 65, 5 }, + { DBGBUS_PERIPH, 65, 6 }, + { DBGBUS_PERIPH, 65, 7 }, + + /* INTF_4 */ + { DBGBUS_PERIPH, 66, 0 }, + { DBGBUS_PERIPH, 66, 1 }, + { DBGBUS_PERIPH, 66, 2 }, + { DBGBUS_PERIPH, 66, 3 }, + { DBGBUS_PERIPH, 66, 4 }, + { DBGBUS_PERIPH, 66, 5 }, + { DBGBUS_PERIPH, 66, 6 }, + { DBGBUS_PERIPH, 66, 7 }, + + /* INTF_5 */ + { DBGBUS_PERIPH, 67, 0 }, + { DBGBUS_PERIPH, 67, 1 }, + { DBGBUS_PERIPH, 67, 2 }, + { DBGBUS_PERIPH, 67, 3 }, + { DBGBUS_PERIPH, 67, 4 }, + { DBGBUS_PERIPH, 67, 5 }, + { DBGBUS_PERIPH, 67, 6 }, + { DBGBUS_PERIPH, 67, 7 }, + + /* INTF_3 */ + { DBGBUS_PERIPH, 73, 0 }, + { DBGBUS_PERIPH, 73, 1 }, + { DBGBUS_PERIPH, 73, 2 }, + { DBGBUS_PERIPH, 73, 3 }, + { DBGBUS_PERIPH, 73, 4 }, + { DBGBUS_PERIPH, 73, 5 }, + { DBGBUS_PERIPH, 73, 6 }, + { DBGBUS_PERIPH, 73, 7 }, + + /* cdwn */ + { DBGBUS_PERIPH, 80, 0}, + { DBGBUS_PERIPH, 80, 1}, + { DBGBUS_PERIPH, 80, 2}, + + { DBGBUS_PERIPH, 81, 0}, + { DBGBUS_PERIPH, 81, 1}, + { DBGBUS_PERIPH, 81, 2}, + + { DBGBUS_PERIPH, 82, 0}, + { DBGBUS_PERIPH, 82, 1}, + { DBGBUS_PERIPH, 82, 2}, + { DBGBUS_PERIPH, 82, 3}, + { DBGBUS_PERIPH, 82, 4}, + { DBGBUS_PERIPH, 82, 5}, + { DBGBUS_PERIPH, 82, 6}, + { DBGBUS_PERIPH, 82, 7}, + + /* DPTX1 */ + { DBGBUS_PERIPH, 68, 0}, + { DBGBUS_PERIPH, 68, 1}, + { DBGBUS_PERIPH, 68, 2}, + { DBGBUS_PERIPH, 68, 3}, + { DBGBUS_PERIPH, 68, 4}, + { DBGBUS_PERIPH, 68, 5}, + { DBGBUS_PERIPH, 68, 6}, + { DBGBUS_PERIPH, 68, 7}, + + /* DP */ + { DBGBUS_PERIPH, 69, 0}, + { DBGBUS_PERIPH, 69, 1}, + { DBGBUS_PERIPH, 69, 2}, + { DBGBUS_PERIPH, 69, 3}, + { DBGBUS_PERIPH, 69, 4}, + { DBGBUS_PERIPH, 69, 5}, + + /* dsi0 */ + { DBGBUS_PERIPH, 70, 0}, + { DBGBUS_PERIPH, 70, 1}, + { DBGBUS_PERIPH, 70, 2}, + { DBGBUS_PERIPH, 70, 3}, + { DBGBUS_PERIPH, 70, 4}, + { DBGBUS_PERIPH, 70, 5}, + + /* dsi1 */ + { DBGBUS_PERIPH, 71, 0}, + { DBGBUS_PERIPH, 71, 1}, + { DBGBUS_PERIPH, 71, 2}, + { DBGBUS_PERIPH, 71, 3}, + { DBGBUS_PERIPH, 71, 4}, + { DBGBUS_PERIPH, 71, 5}, + + /* eDP */ + { DBGBUS_PERIPH, 72, 0}, + { DBGBUS_PERIPH, 72, 1}, + { DBGBUS_PERIPH, 72, 2}, + { DBGBUS_PERIPH, 72, 3}, + { DBGBUS_PERIPH, 72, 4}, + { DBGBUS_PERIPH, 72, 5}, + +}; + +static struct vbif_debug_bus_entry vbif_dbg_bus_msm8998[] = { + {0x214, 0x21c, 16, 2, 0x0, 0xd}, /* arb clients */ + {0x214, 0x21c, 16, 2, 0x80, 0xc0}, /* arb clients */ + {0x214, 0x21c, 16, 2, 0x100, 0x140}, /* arb clients */ + {0x214, 0x21c, 0, 16, 0x0, 0xf}, /* xin blocks - axi side */ + {0x214, 0x21c, 0, 16, 0x80, 0xa4}, /* xin blocks - axi side */ + {0x214, 0x21c, 0, 15, 0x100, 0x124}, /* xin blocks - axi side */ + {0x21c, 0x214, 0, 14, 0, 0xc}, /* xin blocks - clock side */ +}; + +u32 dsi_dbg_bus_kona[] = { + 0x0001, 0x1001, 0x0001, 0x0011, + 0x1021, 0x0021, 0x0031, 0x0041, + 0x0051, 0x0061, 0x3061, 0x0061, + 0x2061, 0x2061, 0x1061, 0x1061, + 0x1061, 0x0071, 0x0071, 0x0071, + 0x0081, 0x0081, 0x00A1, 0x00A1, + 0x10A1, 0x20A1, 0x30A1, 0x10A1, + 0x10A1, 0x30A1, 0x20A1, 0x00B1, + 0x00C1, 0x00C1, 0x10C1, 0x20C1, + 0x30C1, 0x00D1, 0x00D1, 0x20D1, + 0x30D1, 0x00E1, 0x00E1, 0x00E1, + 0x00F1, 0x00F1, 0x0101, 0x0101, + 0x1101, 0x2101, 0x3101, 0x0111, + 0x0141, 0x1141, 0x0141, 0x1141, + 0x1141, 0x0151, 0x0151, 0x1151, + 0x2151, 0x3151, 0x0161, 0x0161, + 0x1161, 0x0171, 0x0171, 0x0181, + 0x0181, 0x0191, 0x0191, 0x01A1, + 0x01A1, 0x01B1, 0x01B1, 0x11B1, + 0x21B1, 0x01C1, 0x01C1, 0x11C1, + 0x21C1, 0x31C1, 0x01D1, 0x01D1, + 0x01D1, 0x01D1, 0x11D1, 0x21D1, + 0x21D1, 0x01E1, 0x01E1, 0x01F1, + 0x01F1, 0x0201, 0x0201, 0x0211, + 0x0221, 0x0231, 0x0241, 0x0251, + 0x0281, 0x0291, 0x0281, 0x0291, + 0x02A1, 0x02B1, 0x02C1, 0x0321, + 0x0321, 0x1321, 0x2321, 0x3321, + 0x0331, 0x0331, 0x1331, 0x0341, + 0x0341, 0x1341, 0x2341, 0x3341, + 0x0351, 0x0361, 0x0361, 0x1361, + 0x2361, 0x0371, 0x0381, 0x0391, + 0x03C1, 0x03D1, 0x03E1, 0x03F1, +}; + +/** + * _sde_power_check - check if power needs to enabled + * @dump_mode: to check if power need to be enabled + * Return: true if success; false otherwise + */ +static inline bool _sde_power_check(enum sde_dbg_dump_context dump_mode) +{ + return (dump_mode == SDE_DBG_DUMP_CLK_ENABLED_CTX || + dump_mode == SDE_DBG_DUMP_IRQ_CTX) ? false : true; +} + +/** + * _sde_dump_reg - helper function for dumping rotator register set content + * @dump_name: register set name + * @reg_dump_flag: dumping flag controlling in-log/memory dump location + * @base_addr: starting address of io region for calculating offsets to print + * @addr: starting address offset for dumping + * @len_bytes: range of the register set + * @dump_mem: output buffer for memory dump location option + * @from_isr: whether being called from isr context + */ +static void _sde_dump_reg(const char *dump_name, u32 reg_dump_flag, + char *base_addr, char *addr, size_t len_bytes, u32 **dump_mem) +{ + u32 in_log, in_mem, len_align, len_padded; + u32 *dump_addr = NULL; + char *end_addr; + int i; + int rc; + + if (!len_bytes) + return; + + in_log = (reg_dump_flag & SDE_DBG_DUMP_IN_LOG); + in_mem = (reg_dump_flag & SDE_DBG_DUMP_IN_MEM); + + pr_debug("%s: reg_dump_flag=%d in_log=%d in_mem=%d\n", + dump_name, reg_dump_flag, in_log, in_mem); + + if (!in_log && !in_mem) + return; + + if (in_log) + dev_info(sde_dbg_base.dev, "%s: start_offset 0x%lx len 0x%zx\n", + dump_name, (unsigned long)(addr - base_addr), + len_bytes); + + len_align = (len_bytes + REG_DUMP_ALIGN - 1) / REG_DUMP_ALIGN; + len_padded = len_align * REG_DUMP_ALIGN; + end_addr = addr + len_bytes; + + if (in_mem) { + if (dump_mem && !(*dump_mem)) { + phys_addr_t phys = 0; + *dump_mem = dma_alloc_coherent(sde_dbg_base.dev, + len_padded, &phys, GFP_KERNEL); + } + + if (dump_mem && *dump_mem) { + dump_addr = *dump_mem; + dev_info(sde_dbg_base.dev, + "%s: start_addr:0x%pK len:0x%x reg_offset=0x%lx\n", + dump_name, dump_addr, len_padded, + (unsigned long)(addr - base_addr)); + } else { + in_mem = 0; + pr_err("dump_mem: kzalloc fails!\n"); + } + } + + if (_sde_power_check(sde_dbg_base.dump_mode)) { + rc = pm_runtime_get_sync(sde_dbg_base.dev); + if (rc < 0) { + pr_err("failed to enable power %d\n", rc); + return; + } + } + + for (i = 0; i < len_align; i++) { + u32 x0, x4, x8, xc; + + x0 = (addr < end_addr) ? readl_relaxed(addr + 0x0) : 0; + x4 = (addr + 0x4 < end_addr) ? readl_relaxed(addr + 0x4) : 0; + x8 = (addr + 0x8 < end_addr) ? readl_relaxed(addr + 0x8) : 0; + xc = (addr + 0xc < end_addr) ? readl_relaxed(addr + 0xc) : 0; + + if (in_log) + dev_info(sde_dbg_base.dev, + "0x%lx : %08x %08x %08x %08x\n", + (unsigned long)(addr - base_addr), + x0, x4, x8, xc); + + if (dump_addr) { + dump_addr[i * 4] = x0; + dump_addr[i * 4 + 1] = x4; + dump_addr[i * 4 + 2] = x8; + dump_addr[i * 4 + 3] = xc; + } + + addr += REG_DUMP_ALIGN; + } + + if (_sde_power_check(sde_dbg_base.dump_mode)) + pm_runtime_put_sync(sde_dbg_base.dev); +} + +/** + * _sde_dbg_get_dump_range - helper to retrieve dump length for a range node + * @range_node: range node to dump + * @max_offset: max offset of the register base + * @Return: length + */ +static u32 _sde_dbg_get_dump_range(struct sde_dbg_reg_offset *range_node, + size_t max_offset) +{ + u32 length = 0; + + if (range_node->start == 0 && range_node->end == 0) { + length = max_offset; + } else if (range_node->start < max_offset) { + if (range_node->end > max_offset) + length = max_offset - range_node->start; + else if (range_node->start < range_node->end) + length = range_node->end - range_node->start; + } + + return length; +} + +static int _sde_dump_reg_range_cmp(void *priv, struct list_head *a, + struct list_head *b) +{ + struct sde_dbg_reg_range *ar, *br; + + if (!a || !b) + return 0; + + ar = container_of(a, struct sde_dbg_reg_range, head); + br = container_of(b, struct sde_dbg_reg_range, head); + + return ar->offset.start - br->offset.start; +} + +static const char *const exclude_modules[] = { + "vbif_rt", + "vbif_nrt", + "wb_2", + NULL +}; + +static bool is_block_exclude(char **modules, char *name) +{ + char **ptr = modules; + + while (*ptr != NULL) { + if (!strcmp(name, *ptr)) + return true; + ++ptr; + } + return false; +} + +/** + * _sde_dump_reg_by_ranges - dump ranges or full range of the register blk base + * @dbg: register blk base structure + * @reg_dump_flag: dump target, memory, kernel log, or both + * @dump_secure: flag to indicate dumping in secure-session + */ +static void _sde_dump_reg_by_ranges(struct sde_dbg_reg_base *dbg, + u32 reg_dump_flag, bool dump_secure) +{ + char *addr; + size_t len; + struct sde_dbg_reg_range *range_node; + + if (!dbg || !(dbg->base || dbg->cb)) { + pr_err("dbg base is null!\n"); + return; + } + + dev_info(sde_dbg_base.dev, "%s:=========%s DUMP=========\n", __func__, + dbg->name); + if (dbg->cb) { + dbg->cb(dbg->cb_ptr); + /* If there is a list to dump the registers by ranges, use the ranges */ + } else if (!list_empty(&dbg->sub_range_list)) { + /* sort the list by start address first */ + list_sort(NULL, &dbg->sub_range_list, _sde_dump_reg_range_cmp); + list_for_each_entry(range_node, &dbg->sub_range_list, head) { + len = _sde_dbg_get_dump_range(&range_node->offset, + dbg->max_offset); + addr = dbg->base + range_node->offset.start; + + if (dump_secure && + is_block_exclude((char**)exclude_modules, + range_node->range_name)) + continue; + + pr_debug("%s: range_base=0x%pK start=0x%x end=0x%x\n", + range_node->range_name, + addr, range_node->offset.start, + range_node->offset.end); + + _sde_dump_reg(range_node->range_name, reg_dump_flag, + dbg->base, addr, len, + &range_node->reg_dump); + } + } else { + /* If there is no list to dump ranges, dump all registers */ + dev_info(sde_dbg_base.dev, + "Ranges not found, will dump full registers\n"); + dev_info(sde_dbg_base.dev, "base:0x%pK len:0x%zx\n", dbg->base, + dbg->max_offset); + addr = dbg->base; + len = dbg->max_offset; + _sde_dump_reg(dbg->name, reg_dump_flag, dbg->base, addr, len, + &dbg->reg_dump); + } +} + +/** + * _sde_dump_reg_by_blk - dump a named register base region + * @blk_name: register blk name + * @dump_secure: flag to indicate dumping in secure-session + */ +static void _sde_dump_reg_by_blk(const char *blk_name, bool dump_secure) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *blk_base; + + if (!dbg_base) + return; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) { + if (strlen(blk_base->name) && + !strcmp(blk_base->name, blk_name)) { + _sde_dump_reg_by_ranges(blk_base, + dbg_base->enable_reg_dump, dump_secure); + break; + } + } +} + +/** + * _sde_dump_reg_all - dump all register regions + */ +static void _sde_dump_reg_all(bool dump_secure) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *blk_base; + + if (!dbg_base) + return; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) { + + if (!strlen(blk_base->name)) + continue; + + if (dump_secure && + is_block_exclude((char **)exclude_modules, + blk_base->name)) + continue; + + _sde_dump_reg_by_blk(blk_base->name, dump_secure); + } +} + +/** + * _sde_dump_get_blk_addr - retrieve register block address by name + * @blk_name: register blk name + * @Return: register blk base, or NULL + */ +static struct sde_dbg_reg_base *_sde_dump_get_blk_addr(const char *blk_name) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *blk_base; + + list_for_each_entry(blk_base, &dbg_base->reg_base_list, reg_base_head) + if (strlen(blk_base->name) && !strcmp(blk_base->name, blk_name)) + return blk_base; + + return NULL; +} + +static void _sde_dbg_dump_sde_dbg_bus(struct sde_dbg_sde_debug_bus *bus) +{ + bool in_log, in_mem; + u32 **dump_mem = NULL; + u32 *dump_addr = NULL; + u32 status = 0; + struct sde_debug_bus_entry *head; + phys_addr_t phys = 0; + int list_size; + int i; + u32 offset; + void __iomem *mem_base = NULL; + struct sde_dbg_reg_base *reg_base; + int rc; + + if (!bus || !bus->cmn.entries_size) + return; + + list_for_each_entry(reg_base, &sde_dbg_base.reg_base_list, + reg_base_head) + if (strlen(reg_base->name) && + !strcmp(reg_base->name, bus->cmn.name)) + mem_base = reg_base->base + bus->top_blk_off; + + if (!mem_base) { + pr_err("unable to find mem_base for %s\n", bus->cmn.name); + return; + } + + dump_mem = &bus->cmn.dumped_content; + + /* will keep in memory 4 entries of 4 bytes each */ + list_size = (bus->cmn.entries_size * 4 * 4); + + in_log = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_LOG); + in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM); + + if (!in_log && !in_mem) + return; + + dev_info(sde_dbg_base.dev, "======== start %s dump =========\n", + bus->cmn.name); + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(sde_dbg_base.dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + dev_info(sde_dbg_base.dev, + "%s: start_addr:0x%pK len:0x%x\n", + __func__, dump_addr, list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + rc = pm_runtime_get_sync(sde_dbg_base.dev); + if (rc < 0) { + pr_err("failed to enable power %d\n", rc); + return; + } + + for (i = 0; i < bus->cmn.entries_size; i++) { + head = bus->entries + i; + if (head->test_id > 0x7) + writel_relaxed(TEST_EXT_MASK(head->block_id, + head->test_id), mem_base + head->wr_addr); + else + writel_relaxed(TEST_MASK(head->block_id, head->test_id), + mem_base + head->wr_addr); + wmb(); /* make sure test bits were written */ + + if (bus->cmn.flags & DBGBUS_FLAGS_DSPP) { + offset = DBGBUS_DSPP_STATUS; + /* keep DSPP test point enabled */ + if (head->wr_addr != DBGBUS_DSPP) + writel_relaxed(0x7001, mem_base + DBGBUS_DSPP); + } else { + offset = head->wr_addr + 0x4; + } + + status = readl_relaxed(mem_base + offset); + + if (in_log) + dev_info(sde_dbg_base.dev, + "waddr=0x%x blk=%d tst=%d val=0x%x\n", + head->wr_addr, head->block_id, + head->test_id, status); + + if (dump_addr && in_mem) { + dump_addr[i*4] = head->wr_addr; + dump_addr[i*4 + 1] = head->block_id; + dump_addr[i*4 + 2] = head->test_id; + dump_addr[i*4 + 3] = status; + } + + if (head->analyzer) + head->analyzer(mem_base, head, status); + + /* Disable debug bus once we are done */ + writel_relaxed(0, mem_base + head->wr_addr); + if (bus->cmn.flags & DBGBUS_FLAGS_DSPP && + head->wr_addr != DBGBUS_DSPP) + writel_relaxed(0x0, mem_base + DBGBUS_DSPP); + } + pm_runtime_put_sync(sde_dbg_base.dev); + + dev_info(sde_dbg_base.dev, "======== end %s dump =========\n", + bus->cmn.name); +} + +static void _sde_dbg_dump_vbif_debug_bus_entry( + struct vbif_debug_bus_entry *head, void __iomem *mem_base, + u32 *dump_addr, bool in_log) +{ + int i, j; + u32 val; + + if (!dump_addr && !in_log) + return; + + for (i = 0; i < head->block_cnt; i++) { + writel_relaxed(1 << (i + head->bit_offset), + mem_base + head->block_bus_addr); + /* make sure that current bus blcok enable */ + wmb(); + for (j = head->test_pnt_start; j < head->test_pnt_cnt; j++) { + writel_relaxed(j, mem_base + head->block_bus_addr + 4); + /* make sure that test point is enabled */ + wmb(); + val = readl_relaxed(mem_base + MMSS_VBIF_TEST_BUS_OUT); + if (dump_addr) { + *dump_addr++ = head->block_bus_addr; + *dump_addr++ = i; + *dump_addr++ = j; + *dump_addr++ = val; + } + if (in_log) + dev_info(sde_dbg_base.dev, + "testpoint:%x arb/xin id=%d index=%d val=0x%x\n", + head->block_bus_addr, i, j, val); + } + } +} + +static void _sde_dbg_dump_vbif_dbg_bus(struct sde_dbg_vbif_debug_bus *bus) +{ + bool in_log, in_mem; + u32 **dump_mem = NULL; + u32 *dump_addr = NULL; + u32 value, d0, d1; + unsigned long reg, reg1, reg2; + struct vbif_debug_bus_entry *head; + phys_addr_t phys = 0; + int i, list_size = 0; + void __iomem *mem_base = NULL; + struct vbif_debug_bus_entry *dbg_bus; + u32 bus_size; + struct sde_dbg_reg_base *reg_base; + int rc; + + if (!bus || !bus->cmn.entries_size) + return; + + list_for_each_entry(reg_base, &sde_dbg_base.reg_base_list, + reg_base_head) + if (strlen(reg_base->name) && + !strcmp(reg_base->name, bus->cmn.name)) + mem_base = reg_base->base; + + if (!mem_base) { + pr_err("unable to find mem_base for %s\n", bus->cmn.name); + return; + } + + dbg_bus = bus->entries; + bus_size = bus->cmn.entries_size; + list_size = bus->cmn.entries_size; + dump_mem = &bus->cmn.dumped_content; + + dev_info(sde_dbg_base.dev, "======== start %s dump =========\n", + bus->cmn.name); + + if (!dump_mem || !dbg_bus || !bus_size || !list_size) + return; + + /* allocate memory for each test point */ + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + list_size += (head->block_cnt * head->test_pnt_cnt); + } + + /* 4 bytes * 4 entries for each test point*/ + list_size *= 16; + + in_log = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_LOG); + in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM); + + if (!in_log && !in_mem) + return; + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(sde_dbg_base.dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + dev_info(sde_dbg_base.dev, + "%s: start_addr:0x%pK len:0x%x\n", + __func__, dump_addr, list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + rc = pm_runtime_get_sync(sde_dbg_base.dev); + if (rc < 0) { + pr_err("failed to enable power %d\n", rc); + return; + } + + value = readl_relaxed(mem_base + MMSS_VBIF_CLKON); + writel_relaxed(value | BIT(1), mem_base + MMSS_VBIF_CLKON); + + /* make sure that vbif core is on */ + wmb(); + + /** + * Extract VBIF error info based on XIN halt and error status. + * If the XIN client is not in HALT state, or an error is detected, + * then retrieve the VBIF error info for it. + */ + reg = readl_relaxed(mem_base + MMSS_VBIF_XIN_HALT_CTRL1); + reg1 = readl_relaxed(mem_base + MMSS_VBIF_PND_ERR); + reg2 = readl_relaxed(mem_base + MMSS_VBIF_SRC_ERR); + dev_err(sde_dbg_base.dev, + "XIN HALT:0x%lX, PND ERR:0x%lX, SRC ERR:0x%lX\n", + reg, reg1, reg2); + reg >>= 16; + reg &= ~(reg1 | reg2); + for (i = 0; i < MMSS_VBIF_CLIENT_NUM; i++) { + if (!test_bit(0, ®)) { + writel_relaxed(i, mem_base + MMSS_VBIF_ERR_INFO); + /* make sure reg write goes through */ + wmb(); + + d0 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO); + d1 = readl_relaxed(mem_base + MMSS_VBIF_ERR_INFO_1); + + dev_err(sde_dbg_base.dev, + "Client:%d, errinfo=0x%X, errinfo1=0x%X\n", + i, d0, d1); + } + reg >>= 1; + } + + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + + writel_relaxed(0, mem_base + head->disable_bus_addr); + writel_relaxed(BIT(0), mem_base + MMSS_VBIF_TEST_BUS_OUT_CTRL); + /* make sure that other bus is off */ + wmb(); + + _sde_dbg_dump_vbif_debug_bus_entry(head, mem_base, dump_addr, + in_log); + if (dump_addr) + dump_addr += (head->block_cnt * head->test_pnt_cnt * 4); + } + + pm_runtime_put_sync(sde_dbg_base.dev); + + dev_info(sde_dbg_base.dev, "======== end %s dump =========\n", + bus->cmn.name); +} + +/** + * _sde_dump_array - dump array of register bases + * @blk_arr: array of register base pointers + * @len: length of blk_arr + * @do_panic: whether to trigger a panic after dumping + * @name: string indicating origin of dump + * @dump_dbgbus_sde: whether to dump the sde debug bus + * @dump_dbgbus_vbif_rt: whether to dump the vbif rt debug bus + * @dump_secure: flag to indicate dumping in secure-session + */ +static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[], + u32 len, bool do_panic, const char *name, bool dump_dbgbus_sde, + bool dump_dbgbus_vbif_rt, bool dump_all, bool dump_secure) +{ + int i; + + mutex_lock(&sde_dbg_base.mutex); + + if (dump_all) + sde_evtlog_dump_all(sde_dbg_base.evtlog); + + if (dump_all || !blk_arr || !len) { + _sde_dump_reg_all(dump_secure); + } else { + for (i = 0; i < len; i++) { + if (blk_arr[i] != NULL) + _sde_dump_reg_by_ranges(blk_arr[i], + sde_dbg_base.enable_reg_dump, + dump_secure); + } + } + + if (dump_dbgbus_sde) + _sde_dbg_dump_sde_dbg_bus(&sde_dbg_base.dbgbus_sde); + + if (dump_dbgbus_vbif_rt) + _sde_dbg_dump_vbif_dbg_bus(&sde_dbg_base.dbgbus_vbif_rt); + + if (sde_dbg_base.dsi_dbg_bus || dump_all) + dsi_ctrl_debug_dump(sde_dbg_base.dbgbus_dsi.entries, + sde_dbg_base.dbgbus_dsi.size); + + if (do_panic && sde_dbg_base.panic_on_err) + panic(name); + + mutex_unlock(&sde_dbg_base.mutex); +} + +/** + * _sde_dump_work - deferred dump work function + * @work: work structure + */ +static void _sde_dump_work(struct work_struct *work) +{ + _sde_dump_array(sde_dbg_base.req_dump_blks, + ARRAY_SIZE(sde_dbg_base.req_dump_blks), + sde_dbg_base.work_panic, "evtlog_workitem", + sde_dbg_base.dbgbus_sde.cmn.include_in_deferred_work, + sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work, + sde_dbg_base.dump_all, sde_dbg_base.dump_secure); +} + +void sde_dbg_dump(enum sde_dbg_dump_context dump_mode, const char *name, ...) +{ + int i, index = 0; + bool do_panic = false; + bool dump_dbgbus_sde = false; + bool dump_dbgbus_vbif_rt = false; + bool dump_all = false; + bool dump_secure = false; + va_list args; + char *blk_name = NULL; + struct sde_dbg_reg_base *blk_base = NULL; + struct sde_dbg_reg_base **blk_arr; + u32 blk_len; + + if (!sde_evtlog_is_enabled(sde_dbg_base.evtlog, SDE_EVTLOG_ALWAYS)) + return; + + if ((dump_mode == SDE_DBG_DUMP_IRQ_CTX) && + work_pending(&sde_dbg_base.dump_work)) + return; + + blk_arr = &sde_dbg_base.req_dump_blks[0]; + blk_len = ARRAY_SIZE(sde_dbg_base.req_dump_blks); + + memset(sde_dbg_base.req_dump_blks, 0, + sizeof(sde_dbg_base.req_dump_blks)); + sde_dbg_base.dump_all = false; + sde_dbg_base.dump_mode = dump_mode; + + va_start(args, name); + i = 0; + while ((blk_name = va_arg(args, char*))) { + if (i++ >= SDE_EVTLOG_MAX_DATA) { + pr_err("could not parse all dump arguments\n"); + break; + } + if (IS_ERR_OR_NULL(blk_name)) + break; + + blk_base = _sde_dump_get_blk_addr(blk_name); + if (blk_base) { + if (index < blk_len) { + blk_arr[index] = blk_base; + index++; + } else { + pr_err("insufficient space to to dump %s\n", + blk_name); + } + } + + if (!strcmp(blk_name, "all")) + dump_all = true; + + if (!strcmp(blk_name, "dbg_bus")) + dump_dbgbus_sde = true; + + if (!strcmp(blk_name, "vbif_dbg_bus")) + dump_dbgbus_vbif_rt = true; + + if (!strcmp(blk_name, "dsi_dbg_bus")) + sde_dbg_base.dsi_dbg_bus = true; + + if (!strcmp(blk_name, "panic")) + do_panic = true; + + if (!strcmp(blk_name, "secure")) + dump_secure = true; + } + va_end(args); + + if (dump_mode == SDE_DBG_DUMP_IRQ_CTX) { + /* schedule work to dump later */ + sde_dbg_base.work_panic = do_panic; + sde_dbg_base.dbgbus_sde.cmn.include_in_deferred_work = + dump_dbgbus_sde; + sde_dbg_base.dbgbus_vbif_rt.cmn.include_in_deferred_work = + dump_dbgbus_vbif_rt; + sde_dbg_base.dump_all = dump_all; + schedule_work(&sde_dbg_base.dump_work); + } else { + _sde_dump_array(blk_arr, blk_len, do_panic, name, + dump_dbgbus_sde, dump_dbgbus_vbif_rt, + dump_all, dump_secure); + } +} + +void sde_dbg_ctrl(const char *name, ...) +{ + int i = 0; + va_list args; + char *blk_name = NULL; + + /* no debugfs controlled events are enabled, just return */ + if (!sde_dbg_base.debugfs_ctrl) + return; + + va_start(args, name); + + while ((blk_name = va_arg(args, char*))) { + if (i++ >= SDE_EVTLOG_MAX_DATA) { + pr_err("could not parse all dbg arguments\n"); + break; + } + + if (IS_ERR_OR_NULL(blk_name)) + break; + + if (!strcmp(blk_name, "stop_ftrace") && + sde_dbg_base.debugfs_ctrl & + DBG_CTRL_STOP_FTRACE) { + pr_debug("tracing off\n"); + tracing_off(); + } + + if (!strcmp(blk_name, "panic_underrun") && + sde_dbg_base.debugfs_ctrl & + DBG_CTRL_PANIC_UNDERRUN) { + pr_err("panic underrun\n"); + SDE_DBG_DUMP_WQ("all", "dbg_bus", "vbif_dbg_bus", + "panic"); + } + + if (!strcmp(blk_name, "reset_hw_panic") && + sde_dbg_base.debugfs_ctrl & + DBG_CTRL_RESET_HW_PANIC) { + pr_debug("reset hw panic\n"); + panic("reset_hw"); + } + } + + va_end(args); +} + + +/* + * sde_dbg_debugfs_open - debugfs open handler for evtlog dump + * @inode: debugfs inode + * @file: file handle + */ +static int sde_dbg_debugfs_open(struct inode *inode, struct file *file) +{ + if (!inode || !file) + return -EINVAL; + + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + mutex_lock(&sde_dbg_base.mutex); + sde_dbg_base.cur_evt_index = 0; + sde_dbg_base.evtlog->first = sde_dbg_base.evtlog->curr + 1; + sde_dbg_base.evtlog->last = + sde_dbg_base.evtlog->first + SDE_EVTLOG_ENTRY; + mutex_unlock(&sde_dbg_base.mutex); + return 0; +} + +/* + * sde_dbg_reg_base_open - debugfs open handler for reg base + * @inode: debugfs inode + * @file: file handle + */ +static int sde_dbg_reg_base_open(struct inode *inode, struct file *file) +{ + char base_name[64] = {0}; + struct sde_dbg_reg_base *reg_base = NULL; + + if (!inode || !file) + return -EINVAL; + + snprintf(base_name, sizeof(base_name), "%s", + file->f_path.dentry->d_iname); + + base_name[strlen(file->f_path.dentry->d_iname) - 4] = '\0'; + reg_base = _sde_dump_get_blk_addr(base_name); + if (!reg_base) { + pr_err("error: unable to locate base %s\n", + base_name); + return -EINVAL; + } + + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = reg_base; + return 0; +} + +/** + * sde_evtlog_dump_read - debugfs read handler for evtlog dump + * @file: file handler + * @buff: user buffer content for debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char evtlog_buf[SDE_EVTLOG_BUF_MAX]; + + if (!buff || !ppos) + return -EINVAL; + + mutex_lock(&sde_dbg_base.mutex); + len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, + evtlog_buf, SDE_EVTLOG_BUF_MAX, + !sde_dbg_base.cur_evt_index, true); + sde_dbg_base.cur_evt_index++; + mutex_unlock(&sde_dbg_base.mutex); + + if (len < 0 || len > count) { + pr_err("len is more than user buffer size\n"); + return 0; + } + + if (copy_to_user(buff, evtlog_buf, len)) + return -EFAULT; + *ppos += len; + + return len; +} + +/** + * sde_evtlog_dump_write - debugfs write handler for evtlog dump + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_evtlog_dump_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + _sde_dump_array(NULL, 0, sde_dbg_base.panic_on_err, "dump_debugfs", + true, true, true, false); + + return count; +} + +static const struct file_operations sde_evtlog_fops = { + .open = sde_dbg_debugfs_open, + .read = sde_evtlog_dump_read, + .write = sde_evtlog_dump_write, +}; + +/** + * sde_dbg_ctrl_read - debugfs read handler for debug ctrl read + * @file: file handler + * @buff: user buffer content for debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_ctrl_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char buf[24] = {'\0'}; + + if (!buff || !ppos) + return -EINVAL; + + if (*ppos) + return 0; /* the end */ + + len = snprintf(buf, sizeof(buf), "0x%x\n", sde_dbg_base.debugfs_ctrl); + pr_debug("%s: ctrl:0x%x len:0x%zx\n", + __func__, sde_dbg_base.debugfs_ctrl, len); + + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) { + pr_err("error copying the buffer! count:0x%zx\n", count); + return -EFAULT; + } + + *ppos += len; /* increase offset */ + return len; +} + +/** + * sde_dbg_ctrl_write - debugfs read handler for debug ctrl write + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_ctrl_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + u32 dbg_ctrl = 0; + char buf[24]; + + if (!file) { + pr_err("DbgDbg: %s: error no file --\n", __func__); + return -EINVAL; + } + + if (count >= sizeof(buf)) + return -EFAULT; + + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (kstrtouint(buf, 0, &dbg_ctrl)) { + pr_err("%s: error in the number of bytes\n", __func__); + return -EFAULT; + } + + pr_debug("dbg_ctrl_read:0x%x\n", dbg_ctrl); + sde_dbg_base.debugfs_ctrl = dbg_ctrl; + + return count; +} + +static const struct file_operations sde_dbg_ctrl_fops = { + .open = sde_dbg_debugfs_open, + .read = sde_dbg_ctrl_read, + .write = sde_dbg_ctrl_write, +}; + +static int sde_recovery_regdump_open(struct inode *inode, struct file *file) +{ + if (!inode || !file) + return -EINVAL; + + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + + /* initialize to start position */ + sde_dbg_base.regbuf.rpos = 0; + sde_dbg_base.regbuf.cur_blk = NULL; + sde_dbg_base.regbuf.dump_done = false; + + return 0; +} + +static ssize_t _sde_dbg_dump_reg_rows(u32 reg_start, + void *start, int count, char *buf, int buflen) +{ + int i; + int len = 0; + u32 *addr; + u32 reg_offset = 0; + int rows = min(count / DUMP_CLMN_COUNT, DUMP_MAX_LINES_PER_BLK); + + if (!start || !buf) { + pr_err("invalid address for dump\n"); + return len; + } + + if (buflen < PAGE_SIZE) { + pr_err("buffer too small for dump\n"); + return len; + } + + for (i = 0; i < rows; i++) { + addr = start + (i * DUMP_CLMN_COUNT * sizeof(u32)); + reg_offset = reg_start + (i * DUMP_CLMN_COUNT * sizeof(u32)); + if (buflen < (len + DUMP_LINE_SIZE)) + break; + + len += snprintf(buf + len, DUMP_LINE_SIZE, + "0x%.8X | %.8X %.8X %.8X %.8X\n", + reg_offset, addr[0], addr[1], addr[2], addr[3]); + } + + return len; +} + +static int _sde_dbg_recovery_dump_sub_blk(struct sde_dbg_reg_range *sub_blk, + char *buf, int buflen) +{ + int count = 0; + int len = 0; + + if (!sub_blk || (buflen < PAGE_SIZE)) { + pr_err("invalid params buflen:%d subblk valid:%d\n", + buflen, sub_blk != NULL); + return len; + } + + count = (sub_blk->offset.end - sub_blk->offset.start) / (sizeof(u32)); + if (count < DUMP_CLMN_COUNT) { + pr_err("invalid count for register dumps :%d\n", count); + return len; + } + + len += snprintf(buf + len, DUMP_LINE_SIZE, + "------------------------------------------\n"); + len += snprintf(buf + len, DUMP_LINE_SIZE, + "**** sub block [%s] - size:%d ****\n", + sub_blk->range_name, count); + len += _sde_dbg_dump_reg_rows(sub_blk->offset.start, sub_blk->reg_dump, + count, buf + len, buflen - len); + + return len; +} + +static int _sde_dbg_recovery_dump_reg_blk(struct sde_dbg_reg_base *blk, + char *buf, int buf_size, int *out_len) +{ + int ret = 0; + int len = 0; + struct sde_dbg_reg_range *sub_blk; + + if (buf_size < PAGE_SIZE) { + pr_err("buffer too small for dump\n"); + return len; + } + + if (!blk || !strlen(blk->name)) { + len += snprintf(buf + len, DUMP_LINE_SIZE, + "Found one invalid block - skip dump\n"); + *out_len = len; + return len; + } + + len += snprintf(buf + len, DUMP_LINE_SIZE, + "******************************************\n"); + len += snprintf(buf + len, DUMP_LINE_SIZE, + "==========================================\n"); + len += snprintf(buf + len, DUMP_LINE_SIZE, + "*********** DUMP of %s block *************\n", + blk->name); + len += snprintf(buf + len, DUMP_LINE_SIZE, + "count:%ld max-off:0x%lx has_sub_blk:%d\n", + blk->cnt, blk->max_offset, + !list_empty(&blk->sub_range_list)); + + if (list_empty(&blk->sub_range_list)) { + len += _sde_dbg_dump_reg_rows(0, blk->reg_dump, + blk->max_offset / sizeof(u32), buf + len, + buf_size - len); + } else { + list_for_each_entry(sub_blk, &blk->sub_range_list, head) + len += _sde_dbg_recovery_dump_sub_blk(sub_blk, + buf + len, buf_size - len); + } + *out_len = len; + + return ret; +} + +static ssize_t sde_recovery_regdump_read(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + int usize = 0; + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_regbuf *rbuf = &dbg_base->regbuf; + + mutex_lock(&sde_dbg_base.mutex); + if (!rbuf->dump_done && !rbuf->cur_blk) { + if (!rbuf->buf) + rbuf->buf = kzalloc(DUMP_BUF_SIZE, GFP_KERNEL); + if (!rbuf->buf) { + len = -ENOMEM; + goto err; + } + rbuf->rpos = 0; + rbuf->len = 0; + rbuf->buf_size = DUMP_BUF_SIZE; + + rbuf->cur_blk = list_first_entry(&dbg_base->reg_base_list, + struct sde_dbg_reg_base, reg_base_head); + if (rbuf->cur_blk) + _sde_dbg_recovery_dump_reg_blk(rbuf->cur_blk, + rbuf->buf, + rbuf->buf_size, + &rbuf->len); + pr_debug("dumping done for blk:%s len:%d\n", rbuf->cur_blk ? + rbuf->cur_blk->name : "unknown", rbuf->len); + } else if (rbuf->len == rbuf->rpos && rbuf->cur_blk) { + rbuf->rpos = 0; + rbuf->len = 0; + rbuf->buf_size = DUMP_BUF_SIZE; + + if (rbuf->cur_blk == list_last_entry(&dbg_base->reg_base_list, + struct sde_dbg_reg_base, reg_base_head)) + rbuf->cur_blk = NULL; + else + rbuf->cur_blk = list_next_entry(rbuf->cur_blk, + reg_base_head); + + if (rbuf->cur_blk) + _sde_dbg_recovery_dump_reg_blk(rbuf->cur_blk, + rbuf->buf, + rbuf->buf_size, + &rbuf->len); + pr_debug("dumping done for blk:%s len:%d\n", rbuf->cur_blk ? + rbuf->cur_blk->name : "unknown", rbuf->len); + } + + if ((rbuf->len - rbuf->rpos) > 0) { + usize = ((rbuf->len - rbuf->rpos) > count) ? + count : rbuf->len - rbuf->rpos; + if (copy_to_user(ubuf, rbuf->buf + rbuf->rpos, usize)) { + len = -EFAULT; + goto err; + } + + len = usize; + rbuf->rpos += usize; + *ppos += usize; + } + + if (!len && rbuf->buf) + rbuf->dump_done = true; +err: + mutex_unlock(&sde_dbg_base.mutex); + + return len; +} + +static const struct file_operations sde_recovery_reg_fops = { + .open = sde_recovery_regdump_open, + .read = sde_recovery_regdump_read, +}; + +static int sde_recovery_dbgbus_dump_open(struct inode *inode, struct file *file) +{ + if (!inode || !file) + return -EINVAL; + + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + + mutex_lock(&sde_dbg_base.mutex); + sde_dbg_base.dbgbus_dump_idx = 0; + mutex_unlock(&sde_dbg_base.mutex); + + return 0; +} + +static ssize_t sde_recovery_dbgbus_dump_read(struct file *file, + char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char evtlog_buf[SDE_EVTLOG_BUF_MAX]; + u32 *data; + struct sde_dbg_sde_debug_bus *bus; + + mutex_lock(&sde_dbg_base.mutex); + bus = &sde_dbg_base.dbgbus_sde; + if (!bus->cmn.dumped_content || !bus->cmn.entries_size) + goto dump_done; + + if (sde_dbg_base.dbgbus_dump_idx <= + ((bus->cmn.entries_size - 1) * DUMP_CLMN_COUNT)) { + data = &bus->cmn.dumped_content[ + sde_dbg_base.dbgbus_dump_idx]; + len = snprintf(evtlog_buf, SDE_EVTLOG_BUF_MAX, + "0x%.8X | %.8X %.8X %.8X %.8X\n", + sde_dbg_base.dbgbus_dump_idx, + data[0], data[1], data[2], data[3]); + sde_dbg_base.dbgbus_dump_idx += DUMP_CLMN_COUNT; + if ((count < len) || copy_to_user(buff, evtlog_buf, len)) { + len = -EFAULT; + goto dump_done; + } + *ppos += len; + } +dump_done: + mutex_unlock(&sde_dbg_base.mutex); + + return len; +} + +static const struct file_operations sde_recovery_dbgbus_fops = { + .open = sde_recovery_dbgbus_dump_open, + .read = sde_recovery_dbgbus_dump_read, +}; + +static int sde_recovery_vbif_dbgbus_dump_open(struct inode *inode, + struct file *file) +{ + if (!inode || !file) + return -EINVAL; + + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + + mutex_lock(&sde_dbg_base.mutex); + sde_dbg_base.vbif_dbgbus_dump_idx = 0; + mutex_unlock(&sde_dbg_base.mutex); + + return 0; +} + +static ssize_t sde_recovery_vbif_dbgbus_dump_read(struct file *file, + char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char evtlog_buf[SDE_EVTLOG_BUF_MAX]; + int i; + u32 *data; + u32 list_size = 0; + struct vbif_debug_bus_entry *head; + struct sde_dbg_vbif_debug_bus *bus; + + mutex_lock(&sde_dbg_base.mutex); + bus = &sde_dbg_base.dbgbus_vbif_rt; + if (!bus->cmn.dumped_content || !bus->cmn.entries_size) + goto dump_done; + + /* calculate total number of test point */ + for (i = 0; i < bus->cmn.entries_size; i++) { + head = bus->entries + i; + list_size += (head->block_cnt * head->test_pnt_cnt); + } + + /* 4 entries for each test point*/ + list_size *= DUMP_CLMN_COUNT; + if (sde_dbg_base.vbif_dbgbus_dump_idx < list_size) { + data = &bus->cmn.dumped_content[ + sde_dbg_base.vbif_dbgbus_dump_idx]; + len = snprintf(evtlog_buf, SDE_EVTLOG_BUF_MAX, + "0x%.8X | %.8X %.8X %.8X %.8X\n", + sde_dbg_base.vbif_dbgbus_dump_idx, + data[0], data[1], data[2], data[3]); + sde_dbg_base.vbif_dbgbus_dump_idx += DUMP_CLMN_COUNT; + if ((count < len) || copy_to_user(buff, evtlog_buf, len)) { + len = -EFAULT; + goto dump_done; + } + *ppos += len; + } +dump_done: + mutex_unlock(&sde_dbg_base.mutex); + + return len; +} + +static const struct file_operations sde_recovery_vbif_dbgbus_fops = { + .open = sde_recovery_vbif_dbgbus_dump_open, + .read = sde_recovery_vbif_dbgbus_dump_read, +}; + +/** + * sde_dbg_reg_base_release - release allocated reg dump file private data + * @inode: debugfs inode + * @file: file handle + * @Return: 0 on success + */ +static int sde_dbg_reg_base_release(struct inode *inode, struct file *file) +{ + struct sde_dbg_reg_base *dbg; + + if (!file) + return -EINVAL; + + dbg = file->private_data; + if (!dbg) + return -ENODEV; + + mutex_lock(&sde_dbg_base.mutex); + if (dbg && dbg->buf) { + kfree(dbg->buf); + dbg->buf_len = 0; + dbg->buf = NULL; + } + mutex_unlock(&sde_dbg_base.mutex); + + return 0; +} + +/** + * sde_dbg_reg_base_is_valid_range - verify if requested memory range is valid + * @off: address offset in bytes + * @cnt: memory size in bytes + * Return: true if valid; false otherwise + */ +static bool sde_dbg_reg_base_is_valid_range( + struct sde_dbg_reg_base *base, + u32 off, u32 cnt) +{ + struct sde_dbg_reg_range *node; + + pr_debug("check offset=0x%x cnt=0x%x\n", off, cnt); + + list_for_each_entry(node, &base->sub_range_list, head) { + pr_debug("%s: start=0x%x end=0x%x\n", node->range_name, + node->offset.start, node->offset.end); + + if (node->offset.start <= off + && off <= node->offset.end + && off + cnt <= node->offset.end) { + pr_debug("valid range requested\n"); + return true; + } + } + + pr_err("invalid range requested\n"); + return false; +} + +/** + * sde_dbg_reg_base_offset_write - set new offset and len to debugfs reg base + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_reg_base_offset_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_dbg_reg_base *dbg; + u32 off = 0; + u32 cnt = DEFAULT_BASE_REG_CNT; + char buf[24]; + int rc; + + if (!file) + return -EINVAL; + + dbg = file->private_data; + if (!dbg) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + if (sscanf(buf, "%5x %x", &off, &cnt) != 2) + return -EFAULT; + + if (off > dbg->max_offset) + return -EINVAL; + + if (off % sizeof(u32)) + return -EINVAL; + + if (cnt > (dbg->max_offset - off)) + cnt = dbg->max_offset - off; + + if (cnt == 0) + return -EINVAL; + + if (!list_empty(&dbg->sub_range_list)) { + rc = sde_dbg_reg_base_is_valid_range(dbg, off, cnt); + if (!rc) + return -EINVAL; + } + + mutex_lock(&sde_dbg_base.mutex); + dbg->off = off; + dbg->cnt = cnt; + mutex_unlock(&sde_dbg_base.mutex); + + pr_debug("offset=%x cnt=%x\n", off, cnt); + + return count; +} + +/** + * sde_dbg_reg_base_offset_read - read current offset and len of register base + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_reg_base_offset_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct sde_dbg_reg_base *dbg; + int len = 0; + char buf[24] = {'\0'}; + + if (!file) + return -EINVAL; + + dbg = file->private_data; + if (!dbg) + return -ENODEV; + + if (!ppos) + return -EINVAL; + + if (*ppos) + return 0; /* the end */ + + mutex_lock(&sde_dbg_base.mutex); + if (dbg->off % sizeof(u32)) { + mutex_unlock(&sde_dbg_base.mutex); + return -EFAULT; + } + + len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt); + if (len < 0 || len >= sizeof(buf)) { + mutex_unlock(&sde_dbg_base.mutex); + return 0; + } + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) { + mutex_unlock(&sde_dbg_base.mutex); + return -EFAULT; + } + + *ppos += len; /* increase offset */ + mutex_unlock(&sde_dbg_base.mutex); + + return len; +} + +#ifdef CONFIG_DYNAMIC_DEBUG +/** + * sde_dbg_reg_base_reg_write - write to reg base hw at offset a given value + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_reg_base_reg_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_dbg_reg_base *dbg; + size_t off; + u32 data, cnt; + char buf[24]; + int rc; + + if (!file) + return -EINVAL; + + dbg = file->private_data; + if (!dbg) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; /* end of string */ + + cnt = sscanf(buf, "%zx %x", &off, &data); + + if (cnt < 2) + return -EFAULT; + + if (off % sizeof(u32)) + return -EFAULT; + + mutex_lock(&sde_dbg_base.mutex); + if (off >= dbg->max_offset) { + mutex_unlock(&sde_dbg_base.mutex); + return -EFAULT; + } + + if (!list_empty(&dbg->sub_range_list)) { + rc = sde_dbg_reg_base_is_valid_range(dbg, off, cnt); + if (!rc) + return -EINVAL; + } + + rc = pm_runtime_get_sync(sde_dbg_base.dev); + if (rc < 0) { + mutex_unlock(&sde_dbg_base.mutex); + pr_err("failed to enable power %d\n", rc); + return rc; + } + + writel_relaxed(data, dbg->base + off); + + pm_runtime_put_sync(sde_dbg_base.dev); + + mutex_unlock(&sde_dbg_base.mutex); + + pr_debug("addr=%zx data=%x\n", off, data); + + return count; +} +#endif + +/** + * sde_dbg_reg_base_reg_read - read len from reg base hw at current offset + * @file: file handler + * @user_buf: user buffer content from debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_dbg_reg_base_reg_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_dbg_reg_base *dbg; + size_t len; + int rc; + + if (!file) + return -EINVAL; + + dbg = file->private_data; + if (!dbg) { + pr_err("invalid handle\n"); + return -ENODEV; + } + + if (!ppos) + return -EINVAL; + + mutex_lock(&sde_dbg_base.mutex); + if (!dbg->buf) { + char dump_buf[64]; + char *ptr; + int cnt, tot; + + dbg->buf_len = sizeof(dump_buf) * + DIV_ROUND_UP(dbg->cnt, ROW_BYTES); + dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL); + + if (!dbg->buf) { + mutex_unlock(&sde_dbg_base.mutex); + return -ENOMEM; + } + + if (dbg->off % sizeof(u32)) { + mutex_unlock(&sde_dbg_base.mutex); + return -EFAULT; + } + + ptr = dbg->base + dbg->off; + tot = 0; + + rc = pm_runtime_get_sync(sde_dbg_base.dev); + if (rc < 0) { + mutex_unlock(&sde_dbg_base.mutex); + pr_err("failed to enable power %d\n", rc); + return rc; + } + + for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) { + hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES), + ROW_BYTES, GROUP_BYTES, dump_buf, + sizeof(dump_buf), false); + len = scnprintf(dbg->buf + tot, dbg->buf_len - tot, + "0x%08x: %s\n", + ((int) (unsigned long) ptr) - + ((int) (unsigned long) dbg->base), + dump_buf); + + ptr += ROW_BYTES; + tot += len; + if (tot >= dbg->buf_len) + break; + } + + pm_runtime_put_sync(sde_dbg_base.dev); + + dbg->buf_len = tot; + } + + if (*ppos >= dbg->buf_len) { + mutex_unlock(&sde_dbg_base.mutex); + return 0; /* done reading */ + } + + len = min(count, dbg->buf_len - (size_t) *ppos); + if (copy_to_user(user_buf, dbg->buf + *ppos, len)) { + mutex_unlock(&sde_dbg_base.mutex); + pr_err("failed to copy to user\n"); + return -EFAULT; + } + + *ppos += len; /* increase offset */ + mutex_unlock(&sde_dbg_base.mutex); + + return len; +} + +static const struct file_operations sde_off_fops = { + .open = sde_dbg_reg_base_open, + .release = sde_dbg_reg_base_release, + .read = sde_dbg_reg_base_offset_read, + .write = sde_dbg_reg_base_offset_write, +}; + +static const struct file_operations sde_reg_fops = { + .open = sde_dbg_reg_base_open, + .release = sde_dbg_reg_base_release, + .read = sde_dbg_reg_base_reg_read, +#ifdef CONFIG_DYNAMIC_DEBUG + .write = sde_dbg_reg_base_reg_write, +#endif +}; + +int sde_dbg_debugfs_register(struct device *dev) +{ + static struct sde_dbg_base *dbg = &sde_dbg_base; + struct sde_dbg_reg_base *blk_base; + char debug_name[80] = ""; + struct dentry *debugfs_root = NULL; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = NULL; + + if (!ddev) { + pr_err("Invalid drm device node\n"); + return -EINVAL; + } + + priv = ddev->dev_private; + if (!priv) { + pr_err("Invalid msm drm private node\n"); + return -EINVAL; + } + + debugfs_root = debugfs_create_dir("debug", + ddev->primary->debugfs_root); + if (IS_ERR_OR_NULL(debugfs_root)) { + pr_err("debugfs_root create_dir fail, error %ld\n", + PTR_ERR(debugfs_root)); + priv->debug_root = NULL; + return -EINVAL; + } + + priv->debug_root = debugfs_root; + + debugfs_create_file("dbg_ctrl", 0600, debugfs_root, NULL, + &sde_dbg_ctrl_fops); + debugfs_create_file("dump", 0600, debugfs_root, NULL, + &sde_evtlog_fops); + debugfs_create_u32("enable", 0600, debugfs_root, + &(sde_dbg_base.evtlog->enable)); + debugfs_create_u32("panic", 0600, debugfs_root, + &sde_dbg_base.panic_on_err); + debugfs_create_u32("reg_dump", 0600, debugfs_root, + &sde_dbg_base.enable_reg_dump); + debugfs_create_file("recovery_reg", 0400, debugfs_root, NULL, + &sde_recovery_reg_fops); + debugfs_create_file("recovery_dbgbus", 0400, debugfs_root, NULL, + &sde_recovery_dbgbus_fops); + debugfs_create_file("recovery_vbif_dbgbus", 0400, debugfs_root, NULL, + &sde_recovery_vbif_dbgbus_fops); + + if (dbg->dbgbus_sde.entries) { + snprintf(debug_name, sizeof(debug_name), "%s_dbgbus", + dbg->dbgbus_sde.cmn.name); + debugfs_create_u32(debug_name, 0600, debugfs_root, + &dbg->dbgbus_sde.cmn.enable_mask); + } + + if (dbg->dbgbus_vbif_rt.entries) { + snprintf(debug_name, sizeof(debug_name), "%s_dbgbus", + dbg->dbgbus_vbif_rt.cmn.name); + debugfs_create_u32(debug_name, 0600, debugfs_root, + &dbg->dbgbus_vbif_rt.cmn.enable_mask); + } + + list_for_each_entry(blk_base, &dbg->reg_base_list, reg_base_head) { + snprintf(debug_name, sizeof(debug_name), "%s_off", + blk_base->name); + debugfs_create_file(debug_name, 0600, debugfs_root, blk_base, + &sde_off_fops); + + snprintf(debug_name, sizeof(debug_name), "%s_reg", + blk_base->name); + debugfs_create_file(debug_name, 0400, debugfs_root, blk_base, + &sde_reg_fops); + } + + return 0; +} + +static void _sde_dbg_debugfs_destroy(void) +{ +} + +void sde_dbg_init_dbg_buses(u32 hwversion) +{ + static struct sde_dbg_base *dbg = &sde_dbg_base; + + memset(&dbg->dbgbus_sde, 0, sizeof(dbg->dbgbus_sde)); + memset(&dbg->dbgbus_vbif_rt, 0, sizeof(dbg->dbgbus_vbif_rt)); + + if (IS_SM8150_TARGET(hwversion) || IS_SM6150_TARGET(hwversion) || + IS_SDMMAGPIE_TARGET(hwversion) || + IS_SDMTRINKET_TARGET(hwversion)) { + dbg->dbgbus_sde.entries = dbg_bus_sde_sm8150; + dbg->dbgbus_sde.cmn.entries_size = + ARRAY_SIZE(dbg_bus_sde_sm8150); + dbg->dbgbus_sde.cmn.flags = DBGBUS_FLAGS_DSPP; + dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE; + dbg->dbgbus_sde.cmn.enable_mask = DEFAULT_DBGBUS_SDE; + + dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; + dbg->dbgbus_vbif_rt.cmn.entries_size = + ARRAY_SIZE(vbif_dbg_bus_msm8998); + dbg->dbgbus_dsi.entries = NULL; + dbg->dbgbus_dsi.size = 0; + dbg->dbgbus_vbif_rt.cmn.name = DBGBUS_NAME_VBIF_RT; + dbg->dbgbus_vbif_rt.cmn.enable_mask = DEFAULT_DBGBUS_VBIFRT; + } else if (IS_SDE_MAJOR_SAME(hwversion, SDE_HW_VER_600)) { + dbg->dbgbus_sde.entries = dbg_bus_sde_kona; + dbg->dbgbus_sde.cmn.entries_size = + ARRAY_SIZE(dbg_bus_sde_kona); + dbg->dbgbus_sde.cmn.flags = DBGBUS_FLAGS_DSPP; + dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE; + dbg->dbgbus_sde.cmn.enable_mask = DEFAULT_DBGBUS_SDE; + + dbg->dbgbus_vbif_rt.entries = vbif_dbg_bus_msm8998; + dbg->dbgbus_vbif_rt.cmn.entries_size = + ARRAY_SIZE(vbif_dbg_bus_msm8998); + dbg->dbgbus_dsi.entries = dsi_dbg_bus_kona; + dbg->dbgbus_dsi.size = ARRAY_SIZE(dsi_dbg_bus_kona); + dbg->dbgbus_vbif_rt.cmn.name = DBGBUS_NAME_VBIF_RT; + dbg->dbgbus_vbif_rt.cmn.enable_mask = DEFAULT_DBGBUS_VBIFRT; + } else { + pr_err("unsupported chipset id %X\n", hwversion); + } +} + +int sde_dbg_init(struct device *dev) +{ + if (!dev) { + pr_err("invalid params\n"); + return -EINVAL; + } + + mutex_init(&sde_dbg_base.mutex); + INIT_LIST_HEAD(&sde_dbg_base.reg_base_list); + sde_dbg_base.dev = dev; + + sde_dbg_base.evtlog = sde_evtlog_init(); + if (IS_ERR_OR_NULL(sde_dbg_base.evtlog)) + return PTR_ERR(sde_dbg_base.evtlog); + + sde_dbg_base_evtlog = sde_dbg_base.evtlog; + + INIT_WORK(&sde_dbg_base.dump_work, _sde_dump_work); + sde_dbg_base.work_panic = false; + sde_dbg_base.panic_on_err = DEFAULT_PANIC; + sde_dbg_base.enable_reg_dump = DEFAULT_REGDUMP; + memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); + + pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n", + sde_dbg_base.evtlog->enable, sde_dbg_base.panic_on_err, + sde_dbg_base.enable_reg_dump); + + return 0; +} + +static void sde_dbg_reg_base_destroy(void) +{ + struct sde_dbg_reg_range *range_node, *range_tmp; + struct sde_dbg_reg_base *blk_base, *blk_tmp; + struct sde_dbg_base *dbg_base = &sde_dbg_base; + + if (!dbg_base) + return; + + list_for_each_entry_safe(blk_base, blk_tmp, &dbg_base->reg_base_list, + reg_base_head) { + list_for_each_entry_safe(range_node, range_tmp, + &blk_base->sub_range_list, head) { + list_del(&range_node->head); + kfree(range_node); + } + list_del(&blk_base->reg_base_head); + kfree(blk_base); + } +} +/** + * sde_dbg_destroy - destroy sde debug facilities + */ +void sde_dbg_destroy(void) +{ + kfree(sde_dbg_base.regbuf.buf); + memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); + _sde_dbg_debugfs_destroy(); + sde_dbg_base_evtlog = NULL; + sde_evtlog_destroy(sde_dbg_base.evtlog); + sde_dbg_base.evtlog = NULL; + sde_dbg_reg_base_destroy(); + mutex_destroy(&sde_dbg_base.mutex); +} + +int sde_dbg_reg_register_base(const char *name, void __iomem *base, + size_t max_offset) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *reg_base; + + if (!name || !strlen(name)) { + pr_err("no debug name provided\n"); + return -EINVAL; + } + + reg_base = kzalloc(sizeof(*reg_base), GFP_KERNEL); + if (!reg_base) + return -ENOMEM; + + strlcpy(reg_base->name, name, sizeof(reg_base->name)); + reg_base->base = base; + reg_base->max_offset = max_offset; + reg_base->off = 0; + reg_base->cnt = DEFAULT_BASE_REG_CNT; + reg_base->reg_dump = NULL; + + /* Initialize list to make sure check for null list will be valid */ + INIT_LIST_HEAD(®_base->sub_range_list); + + pr_debug("%s base: %pK max_offset 0x%zX\n", reg_base->name, + reg_base->base, reg_base->max_offset); + + list_add(®_base->reg_base_head, &dbg_base->reg_base_list); + + return 0; +} + +int sde_dbg_reg_register_cb(const char *name, void (*cb)(void *), void *ptr) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *reg_base; + + if (!name || !strlen(name)) { + pr_err("no debug name provided\n"); + return -EINVAL; + } + + reg_base = kzalloc(sizeof(*reg_base), GFP_KERNEL); + if (!reg_base) + return -ENOMEM; + + strlcpy(reg_base->name, name, sizeof(reg_base->name)); + reg_base->base = NULL; + reg_base->max_offset = 0; + reg_base->off = 0; + reg_base->cnt = DEFAULT_BASE_REG_CNT; + reg_base->reg_dump = NULL; + reg_base->cb = cb; + reg_base->cb_ptr = ptr; + + /* Initialize list to make sure check for null list will be valid */ + INIT_LIST_HEAD(®_base->sub_range_list); + + pr_debug("%s cb: %pK cb_ptr: %pK\n", reg_base->name, + reg_base->cb, reg_base->cb_ptr); + + list_add(®_base->reg_base_head, &dbg_base->reg_base_list); + + return 0; +} + +void sde_dbg_reg_unregister_cb(const char *name, void (*cb)(void *), void *ptr) +{ + struct sde_dbg_base *dbg_base = &sde_dbg_base; + struct sde_dbg_reg_base *reg_base; + + if (!dbg_base) + return; + + list_for_each_entry(reg_base, &dbg_base->reg_base_list, reg_base_head) { + if (strlen(reg_base->name) && + !strcmp(reg_base->name, name)) { + pr_debug("%s cb: %pK cb_ptr: %pK\n", reg_base->name, + reg_base->cb, reg_base->cb_ptr); + list_del(®_base->reg_base_head); + kfree(reg_base); + break; + } + } +} + +void sde_dbg_reg_register_dump_range(const char *base_name, + const char *range_name, u32 offset_start, u32 offset_end, + uint32_t xin_id) +{ + struct sde_dbg_reg_base *reg_base; + struct sde_dbg_reg_range *range; + + reg_base = _sde_dump_get_blk_addr(base_name); + if (!reg_base) { + pr_err("error: for range %s unable to locate base %s\n", + range_name, base_name); + return; + } + + if (!range_name || strlen(range_name) == 0) { + pr_err("%pS: bad range name, base_name %s, offset_start 0x%X, end 0x%X\n", + __builtin_return_address(0), base_name, + offset_start, offset_end); + return; + } + + if (offset_end - offset_start < REG_DUMP_ALIGN || + offset_start > offset_end) { + pr_err("%pS: bad range, base_name %s, range_name %s, offset_start 0x%X, end 0x%X\n", + __builtin_return_address(0), base_name, + range_name, offset_start, offset_end); + return; + } + + range = kzalloc(sizeof(*range), GFP_KERNEL); + if (!range) + return; + + strlcpy(range->range_name, range_name, sizeof(range->range_name)); + range->offset.start = offset_start; + range->offset.end = offset_end; + range->xin_id = xin_id; + list_add_tail(&range->head, ®_base->sub_range_list); + + pr_debug("base %s, range %s, start 0x%X, end 0x%X\n", + base_name, range->range_name, + range->offset.start, range->offset.end); +} + +void sde_dbg_set_sde_top_offset(u32 blk_off) +{ + sde_dbg_base.dbgbus_sde.top_blk_off = blk_off; +} diff --git a/techpack/display/msm/sde_dbg.h b/techpack/display/msm/sde_dbg.h new file mode 100644 index 0000000000000000000000000000000000000000..e336f3236978859b5797e6c6c3671f60707ec054 --- /dev/null +++ b/techpack/display/msm/sde_dbg.h @@ -0,0 +1,471 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_DBG_H_ +#define SDE_DBG_H_ + +#include <stdarg.h> +#include <linux/debugfs.h> +#include <linux/list.h> + +/* select an uncommon hex value for the limiter */ +#define SDE_EVTLOG_DATA_LIMITER (0xC0DEBEEF) +#define SDE_EVTLOG_FUNC_ENTRY 0x1111 +#define SDE_EVTLOG_FUNC_EXIT 0x2222 +#define SDE_EVTLOG_FUNC_CASE1 0x3333 +#define SDE_EVTLOG_FUNC_CASE2 0x4444 +#define SDE_EVTLOG_FUNC_CASE3 0x5555 +#define SDE_EVTLOG_FUNC_CASE4 0x6666 +#define SDE_EVTLOG_FUNC_CASE5 0x7777 +#define SDE_EVTLOG_FUNC_CASE6 0x8888 +#define SDE_EVTLOG_FUNC_CASE7 0x9999 +#define SDE_EVTLOG_FUNC_CASE8 0xaaaa +#define SDE_EVTLOG_FUNC_CASE9 0xbbbb +#define SDE_EVTLOG_FUNC_CASE10 0xcccc +#define SDE_EVTLOG_PANIC 0xdead +#define SDE_EVTLOG_FATAL 0xbad +#define SDE_EVTLOG_ERROR 0xebad + +#define SDE_DBG_DUMP_DATA_LIMITER (NULL) + +enum sde_dbg_evtlog_flag { + SDE_EVTLOG_CRITICAL = BIT(0), + SDE_EVTLOG_IRQ = BIT(1), + SDE_EVTLOG_VERBOSE = BIT(2), + SDE_EVTLOG_EXTERNAL = BIT(3), + SDE_EVTLOG_ALWAYS = -1 +}; + +enum sde_dbg_dump_flag { + SDE_DBG_DUMP_IN_LOG = BIT(0), + SDE_DBG_DUMP_IN_MEM = BIT(1), +}; + +enum sde_dbg_dump_context { + SDE_DBG_DUMP_PROC_CTX, + SDE_DBG_DUMP_IRQ_CTX, + SDE_DBG_DUMP_CLK_ENABLED_CTX, +}; + +#define SDE_EVTLOG_DEFAULT_ENABLE (SDE_EVTLOG_CRITICAL | SDE_EVTLOG_IRQ | \ + SDE_EVTLOG_EXTERNAL) + +/* + * evtlog will print this number of entries when it is called through + * sysfs node or panic. This prevents kernel log from evtlog message + * flood. + */ +#define SDE_EVTLOG_PRINT_ENTRY 256 + +/* + * evtlog keeps this number of entries in memory for debug purpose. This + * number must be greater than print entry to prevent out of bound evtlog + * entry array access. + */ +#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 32) +#define SDE_EVTLOG_MAX_DATA 15 +#define SDE_EVTLOG_BUF_MAX 512 +#define SDE_EVTLOG_BUF_ALIGN 32 + +struct sde_dbg_power_ctrl { + void *handle; + void *client; + int (*enable_fn)(void *handle, void *client, bool enable); +}; + +struct sde_dbg_evtlog_log { + s64 time; + const char *name; + int line; + u32 data[SDE_EVTLOG_MAX_DATA]; + u32 data_cnt; + int pid; + u8 cpu; +}; + +/** + * @last_dump: Index of last entry to be output during evtlog dumps + * @filter_list: Linked list of currently active filter strings + */ +struct sde_dbg_evtlog { + struct sde_dbg_evtlog_log logs[SDE_EVTLOG_ENTRY]; + u32 first; + u32 last; + u32 last_dump; + u32 curr; + u32 next; + u32 enable; + spinlock_t spin_lock; + struct list_head filter_list; +}; + +extern struct sde_dbg_evtlog *sde_dbg_base_evtlog; + +/** + * SDE_EVT32 - Write a list of 32bit values to the event log, default area + * ... - variable arguments + */ +#define SDE_EVT32(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \ + __LINE__, SDE_EVTLOG_ALWAYS, ##__VA_ARGS__, \ + SDE_EVTLOG_DATA_LIMITER) + +/** + * SDE_EVT32_VERBOSE - Write a list of 32bit values for verbose event logging + * ... - variable arguments + */ +#define SDE_EVT32_VERBOSE(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \ + __LINE__, SDE_EVTLOG_VERBOSE, ##__VA_ARGS__, \ + SDE_EVTLOG_DATA_LIMITER) + +/** + * SDE_EVT32_IRQ - Write a list of 32bit values to the event log, IRQ area + * ... - variable arguments + */ +#define SDE_EVT32_IRQ(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \ + __LINE__, SDE_EVTLOG_IRQ, ##__VA_ARGS__, \ + SDE_EVTLOG_DATA_LIMITER) + +/** + * SDE_EVT32_EXTERNAL - Write a list of 32bit values for external display events + * ... - variable arguments + */ +#define SDE_EVT32_EXTERNAL(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \ + __LINE__, SDE_EVTLOG_EXTERNAL, ##__VA_ARGS__, \ + SDE_EVTLOG_DATA_LIMITER) + +/** + * SDE_DBG_DUMP - trigger dumping of all sde_dbg facilities + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through sde_dbg_reg_register_base and + * sde_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + */ +#define SDE_DBG_DUMP(...) sde_dbg_dump(SDE_DBG_DUMP_PROC_CTX, __func__, \ + ##__VA_ARGS__, SDE_DBG_DUMP_DATA_LIMITER) + +/** + * SDE_DBG_DUMP_WQ - trigger dumping of all sde_dbg facilities, queuing the work + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through sde_dbg_reg_register_base and + * sde_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + */ +#define SDE_DBG_DUMP_WQ(...) sde_dbg_dump(SDE_DBG_DUMP_IRQ_CTX, __func__, \ + ##__VA_ARGS__, SDE_DBG_DUMP_DATA_LIMITER) + +/** + * SDE_DBG_DUMP_CLK_EN - trigger dumping of all sde_dbg facilities, without clk + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through sde_dbg_reg_register_base and + * sde_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + */ +#define SDE_DBG_DUMP_CLK_EN(...) sde_dbg_dump(SDE_DBG_DUMP_CLK_ENABLED_CTX, \ + __func__, ##__VA_ARGS__, SDE_DBG_DUMP_DATA_LIMITER) + +/** + * SDE_DBG_EVT_CTRL - trigger a different driver events + * event: event that trigger different behavior in the driver + */ +#define SDE_DBG_CTRL(...) sde_dbg_ctrl(__func__, ##__VA_ARGS__, \ + SDE_DBG_DUMP_DATA_LIMITER) + +#if defined(CONFIG_DEBUG_FS) + +/** + * sde_evtlog_init - allocate a new event log object + * Returns: evtlog or -ERROR + */ +struct sde_dbg_evtlog *sde_evtlog_init(void); + +/** + * sde_evtlog_destroy - destroy previously allocated event log + * @evtlog: pointer to evtlog + * Returns: none + */ +void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog); + +/** + * sde_evtlog_log - log an entry into the event log. + * log collection may be enabled/disabled entirely via debugfs + * log area collection may be filtered by user provided flags via debugfs. + * @evtlog: pointer to evtlog + * @name: function name of call site + * @line: line number of call site + * @flag: log area filter flag checked against user's debugfs request + * Returns: none + */ +void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line, + int flag, ...); + +/** + * sde_evtlog_dump_all - print all entries in event log to kernel log + * @evtlog: pointer to evtlog + * Returns: none + */ +void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog); + +/** + * sde_evtlog_is_enabled - check whether log collection is enabled for given + * event log and log area flag + * @evtlog: pointer to evtlog + * @flag: log area filter flag + * Returns: none + */ +bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag); + +/** + * sde_evtlog_dump_to_buffer - print content of event log to the given buffer + * @evtlog: pointer to evtlog + * @evtlog_buf: target buffer to print into + * @evtlog_buf_size: size of target buffer + * @update_last_entry: whether or not to stop at most recent entry + * @full_dump: whether to dump full or to limit print entries + * Returns: number of bytes written to buffer + */ +ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, + char *evtlog_buf, ssize_t evtlog_buf_size, + bool update_last_entry, bool full_dump); + +/** + * sde_dbg_init_dbg_buses - initialize debug bus dumping support for the chipset + * @hwversion: Chipset revision + */ +void sde_dbg_init_dbg_buses(u32 hwversion); + +/** + * sde_dbg_init - initialize global sde debug facilities: evtlog, regdump + * @dev: device handle + * Returns: 0 or -ERROR + */ +int sde_dbg_init(struct device *dev); + +/** + * sde_dbg_debugfs_register - register entries at the given debugfs dir + * @debugfs_root: debugfs root in which to create sde debug entries + * Returns: 0 or -ERROR + */ +int sde_dbg_debugfs_register(struct device *dev); + +/** + * sde_dbg_destroy - destroy the global sde debug facilities + * Returns: none + */ +void sde_dbg_destroy(void); + +/** + * sde_dbg_dump - trigger dumping of all sde_dbg facilities + * @queue_work: whether to queue the dumping work to the work_struct + * @name: string indicating origin of dump + * @va_args: list of named register dump ranges and regions to dump, as + * registered previously through sde_dbg_reg_register_base and + * sde_dbg_reg_register_dump_range. + * Including the special name "panic" will trigger a panic after + * the dumping work has completed. + * Returns: none + */ +void sde_dbg_dump(enum sde_dbg_dump_context mode, const char *name, ...); + +/** + * sde_dbg_ctrl - trigger specific actions for the driver with debugging + * purposes. Those actions need to be enabled by the debugfs entry + * so the driver executes those actions in the corresponding calls. + * @va_args: list of actions to trigger + * Returns: none + */ +void sde_dbg_ctrl(const char *name, ...); + +/** + * sde_dbg_reg_register_base - register a hw register address section for later + * dumping. call this before calling sde_dbg_reg_register_dump_range + * to be able to specify sub-ranges within the base hw range. + * @name: name of base region + * @base: base pointer of region + * @max_offset: length of region + * Returns: 0 or -ERROR + */ +int sde_dbg_reg_register_base(const char *name, void __iomem *base, + size_t max_offset); + +/** + * sde_dbg_reg_register_cb - register a hw register callback for later + * dumping. + * @name: name of base region + * @cb: callback of external region + * @cb_ptr: private pointer of external region + * Returns: 0 or -ERROR + */ +int sde_dbg_reg_register_cb(const char *name, void (*cb)(void *), void *ptr); + +/** + * sde_dbg_reg_unregister_cb - register a hw unregister callback for later + * dumping. + * @name: name of base region + * @cb: callback of external region + * @cb_ptr: private pointer of external region + * Returns: None + */ +void sde_dbg_reg_unregister_cb(const char *name, void (*cb)(void *), void *ptr); + +/** + * sde_dbg_reg_register_dump_range - register a hw register sub-region for + * later register dumping associated with base specified by + * sde_dbg_reg_register_base + * @base_name: name of base region + * @range_name: name of sub-range within base region + * @offset_start: sub-range's start offset from base's base pointer + * @offset_end: sub-range's end offset from base's base pointer + * @xin_id: xin id + * Returns: none + */ +void sde_dbg_reg_register_dump_range(const char *base_name, + const char *range_name, u32 offset_start, u32 offset_end, + uint32_t xin_id); + +/** + * sde_dbg_set_sde_top_offset - set the target specific offset from mdss base + * address of the top registers. Used for accessing debug bus controls. + * @blk_off: offset from mdss base of the top block + */ +void sde_dbg_set_sde_top_offset(u32 blk_off); + +/** + * sde_evtlog_set_filter - update evtlog filtering + * @evtlog: pointer to evtlog + * @filter: pointer to optional function name filter, set to NULL to disable + */ +void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter); + +/** + * sde_evtlog_get_filter - query configured evtlog filters + * @evtlog: pointer to evtlog + * @index: filter index to retrieve + * @buf: pointer to output filter buffer + * @bufsz: size of output filter buffer + * Returns: zero if a filter string was returned + */ +int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index, + char *buf, size_t bufsz); + +#ifndef CONFIG_DRM_SDE_RSC +static inline void sde_rsc_debug_dump(u32 mux_sel) +{ +} +#else +/** + * sde_rsc_debug_dump - sde rsc debug dump status + * @mux_sel:» select mux on rsc debug bus + */ +void sde_rsc_debug_dump(u32 mux_sel); +#endif + +/** + * dsi_ctrl_debug_dump - dump dsi debug dump status + * @entries: array of debug bus control values + * @size: size of the debug bus control array + */ +void dsi_ctrl_debug_dump(u32 *entries, u32 size); + +#else +static inline struct sde_dbg_evtlog *sde_evtlog_init(void) +{ + return NULL; +} + +static inline void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog) +{ +} + +static inline void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, + const char *name, int line, int flag, ...) +{ +} + +static inline void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog) +{ +} + +static inline bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, + u32 flag) +{ + return false; +} + +static inline ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, + char *evtlog_buf, ssize_t evtlog_buf_size, + bool update_last_entry) +{ + return 0; +} + +static inline void sde_dbg_init_dbg_buses(u32 hwversion) +{ +} + +static inline int sde_dbg_init(struct device *dev) +{ + return 0; +} + +static inline int sde_dbg_debugfs_register(struct device *dev) +{ + return 0; +} + +static inline void sde_dbg_destroy(void) +{ +} + +static inline void sde_dbg_dump(enum sde_dbg_dump_context mode, + const char *name, ...) +{ +} + +static inline void sde_dbg_ctrl(const char *name, ...) +{ +} + +static inline int sde_dbg_reg_register_base(const char *name, + void __iomem *base, size_t max_offset) +{ + return 0; +} + +static inline void sde_dbg_reg_register_dump_range(const char *base_name, + const char *range_name, u32 offset_start, u32 offset_end, + uint32_t xin_id) +{ +} + +static inline void sde_dbg_set_sde_top_offset(u32 blk_off) +{ +} + +static inline void sde_evtlog_set_filter( + struct sde_dbg_evtlog *evtlog, char *filter) +{ +} + +static inline int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, + int index, char *buf, size_t bufsz) +{ + return -EINVAL; +} + +static inline void sde_rsc_debug_dump(u32 mux_sel) +{ +} + +static inline void dsi_ctrl_debug_dump(u32 *entries, u32 size) +{ +} + +#endif /* defined(CONFIG_DEBUG_FS) */ + + +#endif /* SDE_DBG_H_ */ diff --git a/techpack/display/msm/sde_dbg_evtlog.c b/techpack/display/msm/sde_dbg_evtlog.c new file mode 100644 index 0000000000000000000000000000000000000000..71ec32830d6253360432a3a0d90d0170156e8ca0 --- /dev/null +++ b/techpack/display/msm/sde_dbg_evtlog.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "sde_dbg:[%s] " fmt, __func__ + +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/ktime.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/dma-buf.h> +#include <linux/slab.h> +#include <linux/sched/clock.h> + +#include "sde_dbg.h" +#include "sde_trace.h" + +#define SDE_EVTLOG_FILTER_STRSIZE 64 + +struct sde_evtlog_filter { + struct list_head list; + char filter[SDE_EVTLOG_FILTER_STRSIZE]; +}; + +static bool _sde_evtlog_is_filtered_no_lock( + struct sde_dbg_evtlog *evtlog, const char *str) +{ + struct sde_evtlog_filter *filter_node; + size_t len; + bool rc; + + if (!str) + return true; + + len = strlen(str); + + /* + * Filter the incoming string IFF the list is not empty AND + * a matching entry is not in the list. + */ + rc = !list_empty(&evtlog->filter_list); + list_for_each_entry(filter_node, &evtlog->filter_list, list) + if (strnstr(str, filter_node->filter, len)) { + rc = false; + break; + } + + return rc; +} + +bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag) +{ + return evtlog && (evtlog->enable & flag); +} + +void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line, + int flag, ...) +{ + unsigned long flags; + int i, val = 0; + va_list args; + struct sde_dbg_evtlog_log *log; + + if (!evtlog) + return; + + if (!sde_evtlog_is_enabled(evtlog, flag)) + return; + + spin_lock_irqsave(&evtlog->spin_lock, flags); + + if (_sde_evtlog_is_filtered_no_lock(evtlog, name)) + goto exit; + + log = &evtlog->logs[evtlog->curr]; + log->time = local_clock(); + log->name = name; + log->line = line; + log->data_cnt = 0; + log->pid = current->pid; + log->cpu = raw_smp_processor_id(); + + va_start(args, flag); + for (i = 0; i < SDE_EVTLOG_MAX_DATA; i++) { + + val = va_arg(args, int); + if (val == SDE_EVTLOG_DATA_LIMITER) + break; + + log->data[i] = val; + } + va_end(args); + log->data_cnt = i; + evtlog->curr = (evtlog->curr + 1) % SDE_EVTLOG_ENTRY; + evtlog->last++; + + trace_sde_evtlog(name, line, log->data_cnt, log->data); +exit: + spin_unlock_irqrestore(&evtlog->spin_lock, flags); +} + +/* always dump the last entries which are not dumped yet */ +static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog, + bool update_last_entry, bool full_dump) +{ + int max_entries = full_dump ? SDE_EVTLOG_ENTRY : SDE_EVTLOG_PRINT_ENTRY; + + if (!evtlog) + return false; + + evtlog->first = evtlog->next; + + if (update_last_entry) + evtlog->last_dump = evtlog->last; + + if (evtlog->last_dump == evtlog->first) + return false; + + if (evtlog->last_dump < evtlog->first) { + evtlog->first %= SDE_EVTLOG_ENTRY; + if (evtlog->last_dump < evtlog->first) + evtlog->last_dump += SDE_EVTLOG_ENTRY; + } + + if ((evtlog->last_dump - evtlog->first) > max_entries) { + pr_info("evtlog skipping %d entries, last=%d\n", + evtlog->last_dump - evtlog->first - + max_entries, evtlog->last_dump - 1); + evtlog->first = evtlog->last_dump - max_entries; + } + evtlog->next = evtlog->first + 1; + + return true; +} + +ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog, + char *evtlog_buf, ssize_t evtlog_buf_size, + bool update_last_entry, bool full_dump) +{ + int i; + ssize_t off = 0; + struct sde_dbg_evtlog_log *log, *prev_log; + unsigned long flags; + + if (!evtlog || !evtlog_buf) + return 0; + + spin_lock_irqsave(&evtlog->spin_lock, flags); + + /* update markers, exit if nothing to print */ + if (!_sde_evtlog_dump_calc_range(evtlog, update_last_entry, full_dump)) + goto exit; + + log = &evtlog->logs[evtlog->first % SDE_EVTLOG_ENTRY]; + + prev_log = &evtlog->logs[(evtlog->first - 1) % SDE_EVTLOG_ENTRY]; + + off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d", + log->name, log->line); + + if (off < SDE_EVTLOG_BUF_ALIGN) { + memset((evtlog_buf + off), 0x20, (SDE_EVTLOG_BUF_ALIGN - off)); + off = SDE_EVTLOG_BUF_ALIGN; + } + + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), + "=>[%-8d:%-11llu:%9llu][%-4d]:[%-4d]:", evtlog->first, + log->time, (log->time - prev_log->time), log->pid, log->cpu); + + for (i = 0; i < log->data_cnt; i++) + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), + "%x ", log->data[i]); + + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n"); +exit: + spin_unlock_irqrestore(&evtlog->spin_lock, flags); + + return off; +} + +void sde_evtlog_dump_all(struct sde_dbg_evtlog *evtlog) +{ + char buf[SDE_EVTLOG_BUF_MAX]; + bool update_last_entry = true; + + if (!evtlog) + return; + + while (sde_evtlog_dump_to_buffer(evtlog, buf, sizeof(buf), + update_last_entry, false)) { + pr_info("%s\n", buf); + update_last_entry = false; + } +} + +struct sde_dbg_evtlog *sde_evtlog_init(void) +{ + struct sde_dbg_evtlog *evtlog; + + evtlog = kzalloc(sizeof(*evtlog), GFP_KERNEL); + if (!evtlog) + return ERR_PTR(-ENOMEM); + + spin_lock_init(&evtlog->spin_lock); + evtlog->enable = SDE_EVTLOG_DEFAULT_ENABLE; + + INIT_LIST_HEAD(&evtlog->filter_list); + + return evtlog; +} + +int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index, + char *buf, size_t bufsz) +{ + struct sde_evtlog_filter *filter_node; + unsigned long flags; + int rc = -EFAULT; + + if (!evtlog || !buf || !bufsz || index < 0) + return -EINVAL; + + spin_lock_irqsave(&evtlog->spin_lock, flags); + list_for_each_entry(filter_node, &evtlog->filter_list, list) { + if (index--) + continue; + + /* don't care about return value */ + (void)strlcpy(buf, filter_node->filter, bufsz); + rc = 0; + break; + } + spin_unlock_irqrestore(&evtlog->spin_lock, flags); + + return rc; +} + +void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter) +{ + struct sde_evtlog_filter *filter_node, *tmp; + struct list_head free_list; + unsigned long flags; + char *flt; + + if (!evtlog) + return; + + INIT_LIST_HEAD(&free_list); + + /* + * Clear active filter list and cache filter_nodes locally + * to reduce memory fragmentation. + */ + spin_lock_irqsave(&evtlog->spin_lock, flags); + list_for_each_entry_safe(filter_node, tmp, &evtlog->filter_list, list) { + list_del_init(&filter_node->list); + list_add_tail(&filter_node->list, &free_list); + } + spin_unlock_irqrestore(&evtlog->spin_lock, flags); + + /* + * Parse incoming filter request string and build up a new + * filter list. New filter nodes are taken from the local + * free list, if available, and allocated from the system + * heap once the free list is empty. + */ + while (filter && (flt = strsep(&filter, "|\r\n\t ")) != NULL) { + if (!*flt) + continue; + + if (list_empty(&free_list)) { + filter_node = kzalloc(sizeof(*filter_node), GFP_KERNEL); + if (!filter_node) + break; + + INIT_LIST_HEAD(&filter_node->list); + } else { + filter_node = list_first_entry(&free_list, + struct sde_evtlog_filter, list); + list_del_init(&filter_node->list); + } + + /* don't care if copy truncated */ + (void)strlcpy(filter_node->filter, flt, + SDE_EVTLOG_FILTER_STRSIZE); + + spin_lock_irqsave(&evtlog->spin_lock, flags); + list_add_tail(&filter_node->list, &evtlog->filter_list); + spin_unlock_irqrestore(&evtlog->spin_lock, flags); + } + + /* + * Free any unused filter_nodes back to the system. + */ + list_for_each_entry_safe(filter_node, tmp, &free_list, list) { + list_del(&filter_node->list); + kfree(filter_node); + } +} + +void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog) +{ + struct sde_evtlog_filter *filter_node, *tmp; + + if (!evtlog) + return; + + list_for_each_entry_safe(filter_node, tmp, &evtlog->filter_list, list) { + list_del(&filter_node->list); + kfree(filter_node); + } + kfree(evtlog); +} diff --git a/techpack/display/msm/sde_edid_parser.c b/techpack/display/msm/sde_edid_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..0fc473da9f87a11f3f29037d9aef4f31c0c6b4df --- /dev/null +++ b/techpack/display/msm/sde_edid_parser.c @@ -0,0 +1,630 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include <drm/drm_edid.h> +#include <linux/hdmi.h> + +#include "sde_kms.h" +#include "sde_edid_parser.h" + +#define DBC_START_OFFSET 4 +#define EDID_DTD_LEN 18 + +enum data_block_types { + RESERVED, + AUDIO_DATA_BLOCK, + VIDEO_DATA_BLOCK, + VENDOR_SPECIFIC_DATA_BLOCK, + SPEAKER_ALLOCATION_DATA_BLOCK, + VESA_DTC_DATA_BLOCK, + RESERVED2, + USE_EXTENDED_TAG +}; + +static u8 *sde_find_edid_extension(struct edid *edid, int ext_id) +{ + u8 *edid_ext = NULL; + int i; + + /* No EDID or EDID extensions */ + if (edid == NULL || edid->extensions == 0) + return NULL; + + /* Find CEA extension */ + for (i = 0; i < edid->extensions; i++) { + edid_ext = (u8 *)edid + EDID_LENGTH * (i + 1); + if (edid_ext[0] == ext_id) + break; + } + + if (i == edid->extensions) + return NULL; + + return edid_ext; +} + +static u8 *sde_find_cea_extension(struct edid *edid) +{ + return sde_find_edid_extension(edid, SDE_CEA_EXT); +} + +static int +sde_cea_db_payload_len(const u8 *db) +{ + return db[0] & 0x1f; +} + +static int +sde_cea_db_tag(const u8 *db) +{ + return db[0] >> 5; +} + +static int +sde_cea_revision(const u8 *cea) +{ + return cea[1]; +} + +static int +sde_cea_db_offsets(const u8 *cea, int *start, int *end) +{ + /* Data block offset in CEA extension block */ + *start = 4; + *end = cea[2]; + if (*end == 0) + *end = 127; + if (*end < 4 || *end > 127) + return -ERANGE; + return 0; +} + +#define sde_for_each_cea_db(cea, i, start, end) \ +for ((i) = (start); \ +(i) < (end) && (i) + sde_cea_db_payload_len(&(cea)[(i)]) < (end); \ +(i) += sde_cea_db_payload_len(&(cea)[(i)]) + 1) + +static bool sde_cea_db_is_hdmi_hf_vsdb(const u8 *db) +{ + int hdmi_id; + + if (sde_cea_db_tag(db) != VENDOR_SPECIFIC_DATA_BLOCK) + return false; + + if (sde_cea_db_payload_len(db) < 7) + return false; + + hdmi_id = db[1] | (db[2] << 8) | (db[3] << 16); + + return hdmi_id == HDMI_FORUM_IEEE_OUI; +} + +static u8 *sde_edid_find_extended_tag_block(struct edid *edid, int blk_id) +{ + u8 *db = NULL; + u8 *cea = NULL; + + if (!edid) { + SDE_ERROR("%s: invalid input\n", __func__); + return NULL; + } + + cea = sde_find_cea_extension(edid); + + if (cea && sde_cea_revision(cea) >= 3) { + int i, start, end; + + if (sde_cea_db_offsets(cea, &start, &end)) + return NULL; + + sde_for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + if ((sde_cea_db_tag(db) == SDE_EXTENDED_TAG) && + (db[1] == blk_id)) + return db; + } + } + return NULL; +} + +static u8 * +sde_edid_find_block(struct edid *edid, int blk_id) +{ + u8 *db = NULL; + u8 *cea = NULL; + + if (!edid) { + SDE_ERROR("%s: invalid input\n", __func__); + return NULL; + } + + cea = sde_find_cea_extension(edid); + + if (cea && sde_cea_revision(cea) >= 3) { + int i, start, end; + + if (sde_cea_db_offsets(cea, &start, &end)) + return NULL; + + sde_for_each_cea_db(cea, i, start, end) { + db = &cea[i]; + if (sde_cea_db_tag(db) == blk_id) + return db; + } + } + return NULL; +} + + +static const u8 *_sde_edid_find_block(const u8 *in_buf, u32 start_offset, + u8 type, u8 *len) +{ + /* the start of data block collection, start of Video Data Block */ + u32 offset = start_offset; + u32 dbc_offset = in_buf[2]; + + SDE_EDID_DEBUG("%s +", __func__); + /* + * * edid buffer 1, byte 2 being 4 means no non-DTD/Data block + * collection present. + * * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block + * collection present and no DTD data present. + */ + + if ((dbc_offset == 0) || (dbc_offset == 4)) { + SDE_EDID_DEBUG("EDID: no DTD or non-DTD data present\n"); + return NULL; + } + + while (offset < dbc_offset) { + u8 block_len = in_buf[offset] & 0x1F; + + if ((offset + block_len <= dbc_offset) && + (in_buf[offset] >> 5) == type) { + *len = block_len; + SDE_EDID_DEBUG("block=%d found @ 0x%x w/ len=%d\n", + type, offset, block_len); + + return in_buf + offset; + } + offset += 1 + block_len; + } + + return NULL; +} + +static void sde_edid_extract_vendor_id(struct sde_edid_ctrl *edid_ctrl) +{ + char *vendor_id; + u32 id_codes; + + SDE_EDID_DEBUG("%s +", __func__); + if (!edid_ctrl) { + SDE_ERROR("%s: invalid input\n", __func__); + return; + } + + vendor_id = edid_ctrl->vendor_id; + id_codes = ((u32)edid_ctrl->edid->mfg_id[0] << 8) + + edid_ctrl->edid->mfg_id[1]; + + vendor_id[0] = 'A' - 1 + ((id_codes >> 10) & 0x1F); + vendor_id[1] = 'A' - 1 + ((id_codes >> 5) & 0x1F); + vendor_id[2] = 'A' - 1 + (id_codes & 0x1F); + vendor_id[3] = 0; + SDE_EDID_DEBUG("vendor id is %s ", vendor_id); + SDE_EDID_DEBUG("%s -", __func__); +} + +static void sde_edid_set_y420_support(struct drm_connector *connector, +u32 video_format) +{ + u8 cea_mode = 0; + struct drm_display_mode *mode; + u32 mode_fmt_flags = 0; + + /* Need to add Y420 support flag to the modes */ + list_for_each_entry(mode, &connector->probed_modes, head) { + /* Cache the format flags before clearing */ + mode_fmt_flags = mode->flags; + /* Clear the RGB/YUV format flags before calling upstream API */ + mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK; + cea_mode = drm_match_cea_mode(mode); + /* Restore the format flags */ + mode->flags = mode_fmt_flags; + if ((cea_mode != 0) && (cea_mode == video_format)) { + SDE_EDID_DEBUG("%s found match for %d ", __func__, + video_format); + mode->flags |= DRM_MODE_FLAG_SUPPORTS_YUV; + } + } +} + +static void sde_edid_parse_Y420CMDB( +struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl, +const u8 *db) +{ + u32 offset = 0; + u8 cmdb_len = 0; + u8 svd_len = 0; + const u8 *svd = NULL; + u32 i = 0, j = 0; + u32 video_format = 0; + + if (!edid_ctrl) { + SDE_ERROR("%s: edid_ctrl is NULL\n", __func__); + return; + } + + if (!db) { + SDE_ERROR("%s: invalid input\n", __func__); + return; + } + SDE_EDID_DEBUG("%s +\n", __func__); + cmdb_len = db[0] & 0x1f; + + /* Byte 3 to L+1 contain SVDs */ + offset += 2; + + svd = sde_edid_find_block(edid_ctrl->edid, VIDEO_DATA_BLOCK); + + if (svd) { + /*moving to the next byte as vic info begins there*/ + svd_len = svd[0] & 0x1f; + ++svd; + } + + for (i = 0; i < svd_len; i++, j++) { + video_format = *(svd + i) & 0x7F; + if (cmdb_len == 1) { + /* If cmdb_len is 1, it means all SVDs support YUV */ + sde_edid_set_y420_support(connector, video_format); + } else if (db[offset] & (1 << j)) { + sde_edid_set_y420_support(connector, video_format); + + if (j & 0x80) { + j = j/8; + offset++; + if (offset >= cmdb_len) + break; + } + } + } + + SDE_EDID_DEBUG("%s -\n", __func__); + +} + +static void sde_edid_parse_Y420VDB( +struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl, +const u8 *db) +{ + u8 len = db[0] & 0x1f; + u32 i = 0; + u32 video_format = 0; + + if (!edid_ctrl) { + SDE_ERROR("%s: invalid input\n", __func__); + return; + } + + SDE_EDID_DEBUG("%s +\n", __func__); + + /* Offset to byte 3 */ + db += 2; + for (i = 0; i < len - 1; i++) { + video_format = *(db + i) & 0x7F; + /* + * mode was already added in get_modes() + * only need to set the Y420 support flag + */ + sde_edid_set_y420_support(connector, video_format); + } + SDE_EDID_DEBUG("%s -", __func__); +} + +static void sde_edid_set_mode_format( +struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl) +{ + const u8 *db = NULL; + struct drm_display_mode *mode; + + SDE_EDID_DEBUG("%s +\n", __func__); + /* Set YUV mode support flags for YCbcr420VDB */ + db = sde_edid_find_extended_tag_block(edid_ctrl->edid, + Y420_VIDEO_DATA_BLOCK); + if (db) + sde_edid_parse_Y420VDB(connector, edid_ctrl, db); + else + SDE_EDID_DEBUG("YCbCr420 VDB is not present\n"); + + /* Set RGB supported on all modes where YUV is not set */ + list_for_each_entry(mode, &connector->probed_modes, head) { + if (!(mode->flags & DRM_MODE_FLAG_SUPPORTS_YUV)) + mode->flags |= DRM_MODE_FLAG_SUPPORTS_RGB; + } + + + db = sde_edid_find_extended_tag_block(edid_ctrl->edid, + Y420_CAPABILITY_MAP_DATA_BLOCK); + if (db) + sde_edid_parse_Y420CMDB(connector, edid_ctrl, db); + else + SDE_EDID_DEBUG("YCbCr420 CMDB is not present\n"); + + SDE_EDID_DEBUG("%s -\n", __func__); +} + +static void _sde_edid_update_dc_modes( +struct drm_connector *connector, struct sde_edid_ctrl *edid_ctrl) +{ + int i, start, end; + u8 *edid_ext, *hdmi; + struct drm_display_info *disp_info; + u32 hdmi_dc_yuv_modes = 0; + + SDE_EDID_DEBUG("%s +\n", __func__); + + if (!connector || !edid_ctrl) { + SDE_ERROR("invalid input\n"); + return; + } + + disp_info = &connector->display_info; + + edid_ext = sde_find_cea_extension(edid_ctrl->edid); + + if (!edid_ext) { + SDE_DEBUG("no cea extension\n"); + return; + } + + if (sde_cea_db_offsets(edid_ext, &start, &end)) + return; + + sde_for_each_cea_db(edid_ext, i, start, end) { + if (sde_cea_db_is_hdmi_hf_vsdb(&edid_ext[i])) { + + hdmi = &edid_ext[i]; + + if (sde_cea_db_payload_len(hdmi) < 7) + continue; + + if (hdmi[7] & DRM_EDID_YCBCR420_DC_30) { + hdmi_dc_yuv_modes |= DRM_EDID_YCBCR420_DC_30; + SDE_EDID_DEBUG("Y420 30-bit supported\n"); + } + + if (hdmi[7] & DRM_EDID_YCBCR420_DC_36) { + hdmi_dc_yuv_modes |= DRM_EDID_YCBCR420_DC_36; + SDE_EDID_DEBUG("Y420 36-bit supported\n"); + } + + if (hdmi[7] & DRM_EDID_YCBCR420_DC_48) { + hdmi_dc_yuv_modes |= DRM_EDID_YCBCR420_DC_36; + SDE_EDID_DEBUG("Y420 48-bit supported\n"); + } + } + } + + disp_info->edid_hdmi_dc_modes |= hdmi_dc_yuv_modes; + + SDE_EDID_DEBUG("%s -\n", __func__); +} + +static void _sde_edid_extract_audio_data_blocks( + struct sde_edid_ctrl *edid_ctrl) +{ + u8 len = 0; + u8 adb_max = 0; + const u8 *adb = NULL; + u32 offset = DBC_START_OFFSET; + u8 *cea = NULL; + + if (!edid_ctrl) { + SDE_ERROR("invalid edid_ctrl\n"); + return; + } + SDE_EDID_DEBUG("%s +", __func__); + cea = sde_find_cea_extension(edid_ctrl->edid); + if (!cea) { + SDE_DEBUG("CEA extension not found\n"); + return; + } + + edid_ctrl->adb_size = 0; + + memset(edid_ctrl->audio_data_block, 0, + sizeof(edid_ctrl->audio_data_block)); + + do { + len = 0; + adb = _sde_edid_find_block(cea, offset, AUDIO_DATA_BLOCK, + &len); + + if ((adb == NULL) || (len > MAX_AUDIO_DATA_BLOCK_SIZE || + adb_max >= MAX_NUMBER_ADB)) { + if (!edid_ctrl->adb_size) { + SDE_DEBUG("No/Invalid Audio Data Block\n"); + return; + } + + continue; + } + + memcpy(edid_ctrl->audio_data_block + edid_ctrl->adb_size, + adb + 1, len); + offset = (adb - cea) + 1 + len; + + edid_ctrl->adb_size += len; + adb_max++; + } while (adb); + SDE_EDID_DEBUG("%s -", __func__); +} + +static void _sde_edid_extract_speaker_allocation_data( + struct sde_edid_ctrl *edid_ctrl) +{ + u8 len; + const u8 *sadb = NULL; + u8 *cea = NULL; + + if (!edid_ctrl) { + SDE_ERROR("invalid edid_ctrl\n"); + return; + } + SDE_EDID_DEBUG("%s +", __func__); + cea = sde_find_cea_extension(edid_ctrl->edid); + if (!cea) { + SDE_DEBUG("CEA extension not found\n"); + return; + } + + sadb = _sde_edid_find_block(cea, DBC_START_OFFSET, + SPEAKER_ALLOCATION_DATA_BLOCK, &len); + if ((sadb == NULL) || (len != MAX_SPKR_ALLOC_DATA_BLOCK_SIZE)) { + SDE_DEBUG("No/Invalid Speaker Allocation Data Block\n"); + return; + } + + memcpy(edid_ctrl->spkr_alloc_data_block, sadb + 1, len); + edid_ctrl->sadb_size = len; + + SDE_EDID_DEBUG("speaker alloc data SP byte = %08x %s%s%s%s%s%s%s\n", + sadb[1], + (sadb[1] & BIT(0)) ? "FL/FR," : "", + (sadb[1] & BIT(1)) ? "LFE," : "", + (sadb[1] & BIT(2)) ? "FC," : "", + (sadb[1] & BIT(3)) ? "RL/RR," : "", + (sadb[1] & BIT(4)) ? "RC," : "", + (sadb[1] & BIT(5)) ? "FLC/FRC," : "", + (sadb[1] & BIT(6)) ? "RLC/RRC," : ""); + SDE_EDID_DEBUG("%s -", __func__); +} + +struct sde_edid_ctrl *sde_edid_init(void) +{ + struct sde_edid_ctrl *edid_ctrl = NULL; + + SDE_EDID_DEBUG("%s +\n", __func__); + edid_ctrl = kzalloc(sizeof(*edid_ctrl), GFP_KERNEL); + if (!edid_ctrl) { + SDE_ERROR("edid_ctrl alloc failed\n"); + return NULL; + } + memset((edid_ctrl), 0, sizeof(*edid_ctrl)); + SDE_EDID_DEBUG("%s -\n", __func__); + return edid_ctrl; +} + +void sde_free_edid(void **input) +{ + struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input); + + SDE_EDID_DEBUG("%s +", __func__); + kfree(edid_ctrl->edid); + edid_ctrl->edid = NULL; +} + +void sde_edid_deinit(void **input) +{ + struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input); + + SDE_EDID_DEBUG("%s +", __func__); + sde_free_edid((void *)&edid_ctrl); + kfree(edid_ctrl); + SDE_EDID_DEBUG("%s -", __func__); +} + +int _sde_edid_update_modes(struct drm_connector *connector, + void *input) +{ + int rc = 0; + struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input); + + SDE_EDID_DEBUG("%s +", __func__); + if (edid_ctrl->edid) { + drm_connector_update_edid_property(connector, + edid_ctrl->edid); + + rc = drm_add_edid_modes(connector, edid_ctrl->edid); + sde_edid_set_mode_format(connector, edid_ctrl); + _sde_edid_update_dc_modes(connector, edid_ctrl); + SDE_EDID_DEBUG("%s -", __func__); + return rc; + } + + drm_connector_update_edid_property(connector, NULL); + SDE_EDID_DEBUG("%s null edid -", __func__); + return rc; +} + +u8 sde_get_edid_checksum(void *input) +{ + struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input); + struct edid *edid = NULL, *last_block = NULL; + u8 *raw_edid = NULL; + + if (!edid_ctrl || !edid_ctrl->edid) { + SDE_ERROR("invalid edid input\n"); + return 0; + } + + edid = edid_ctrl->edid; + + raw_edid = (u8 *)edid; + raw_edid += (edid->extensions * EDID_LENGTH); + last_block = (struct edid *)raw_edid; + + if (last_block) + return last_block->checksum; + + SDE_ERROR("Invalid block, no checksum\n"); + return 0; +} + +bool sde_detect_hdmi_monitor(void *input) +{ + struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(input); + + return drm_detect_hdmi_monitor(edid_ctrl->edid); +} + +void sde_parse_edid(void *input) +{ + struct sde_edid_ctrl *edid_ctrl; + + if (!input) { + SDE_ERROR("Invalid input\n"); + return; + } + + edid_ctrl = (struct sde_edid_ctrl *)(input); + + if (edid_ctrl->edid) { + sde_edid_extract_vendor_id(edid_ctrl); + _sde_edid_extract_audio_data_blocks(edid_ctrl); + _sde_edid_extract_speaker_allocation_data(edid_ctrl); + } else { + SDE_ERROR("edid not present\n"); + } +} + +void sde_get_edid(struct drm_connector *connector, + struct i2c_adapter *adapter, void **input) +{ + struct sde_edid_ctrl *edid_ctrl = (struct sde_edid_ctrl *)(*input); + + edid_ctrl->edid = drm_get_edid(connector, adapter); + SDE_EDID_DEBUG("%s +\n", __func__); + + if (!edid_ctrl->edid) + SDE_ERROR("EDID read failed\n"); + + if (edid_ctrl->edid) + sde_parse_edid(edid_ctrl); + + SDE_EDID_DEBUG("%s -\n", __func__); +}; diff --git a/techpack/display/msm/sde_edid_parser.h b/techpack/display/msm/sde_edid_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..6501f329d57f7ded1139a6f035ddb425b0666289 --- /dev/null +++ b/techpack/display/msm/sde_edid_parser.h @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_EDID_PARSER_H_ +#define _SDE_EDID_PARSER_H_ + +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/debugfs.h> +#include <linux/of_device.h> +#include <linux/i2c.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_edid.h> + + +#define MAX_NUMBER_ADB 5 +#define MAX_AUDIO_DATA_BLOCK_SIZE 30 +#define MAX_SPKR_ALLOC_DATA_BLOCK_SIZE 3 +#define EDID_VENDOR_ID_SIZE 4 + +#define SDE_CEA_EXT 0x02 +#define SDE_EXTENDED_TAG 0x07 + +#define SDE_DRM_MODE_FLAG_FMT_MASK (0x3 << 20) + +enum extended_data_block_types { + VIDEO_CAPABILITY_DATA_BLOCK = 0x0, + VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01, + HDMI_VIDEO_DATA_BLOCK = 0x04, + HDR_STATIC_METADATA_DATA_BLOCK = 0x06, + Y420_VIDEO_DATA_BLOCK = 0x0E, + VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D, + Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F, + VENDOR_SPECIFIC_AUDIO_DATA_BLOCK = 0x11, + INFOFRAME_DATA_BLOCK = 0x20, +}; + +#ifdef SDE_EDID_DEBUG_ENABLE +#define SDE_EDID_DEBUG(fmt, args...) SDE_ERROR(fmt, ##args) +#else +#define SDE_EDID_DEBUG(fmt, args...) SDE_DEBUG(fmt, ##args) +#endif + +/* + * struct hdmi_edid_hdr_data - HDR Static Metadata + * @eotf: Electro-Optical Transfer Function + * @metadata_type_one: Static Metadata Type 1 support + * @max_luminance: Desired Content Maximum Luminance + * @avg_luminance: Desired Content Frame-average Luminance + * @min_luminance: Desired Content Minimum Luminance + */ +struct sde_edid_hdr_data { + u32 eotf; + bool metadata_type_one; + u32 max_luminance; + u32 avg_luminance; + u32 min_luminance; +}; + +struct sde_edid_sink_caps { + u32 max_pclk_in_hz; + bool scdc_present; + bool scramble_support; /* scramble support for less than 340Mcsc */ + bool read_req_support; + bool osd_disparity; + bool dual_view_support; + bool ind_view_support; +}; + +struct sde_edid_ctrl { + struct edid *edid; + u8 pt_scan_info; + u8 it_scan_info; + u8 ce_scan_info; + u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE]; + int adb_size; + u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE]; + int sadb_size; + bool hdr_supported; + char vendor_id[EDID_VENDOR_ID_SIZE]; + struct sde_edid_sink_caps sink_caps; + struct sde_edid_hdr_data hdr_data; +}; + +/** + * sde_edid_init() - init edid structure. + * @edid_ctrl: Handle to the edid_ctrl structure. + * Return: handle to sde_edid_ctrl for the client. + */ +struct sde_edid_ctrl *sde_edid_init(void); + +/** + * sde_edid_deinit() - deinit edid structure. + * @edid_ctrl: Handle to the edid_ctrl structure. + * + * Return: void. + */ +void sde_edid_deinit(void **edid_ctrl); + +/** + * sde_get_edid() - get edid info. + * @connector: Handle to the drm_connector. + * @adapter: handle to i2c adapter for DDC read + * @edid_ctrl: Handle to the edid_ctrl structure. + * + * Return: void. + */ +void sde_get_edid(struct drm_connector *connector, +struct i2c_adapter *adapter, +void **edid_ctrl); + +/** + * sde_parse_edid() - parses edid info. + * @edid_ctrl: Handle to the edid_ctrl structure. + * + * Return: void. + */ +void sde_parse_edid(void *edid_ctrl); + +/** + * sde_free_edid() - free edid structure. + * @edid_ctrl: Handle to the edid_ctrl structure. + * + * Return: void. + */ +void sde_free_edid(void **edid_ctrl); + +/** + * sde_detect_hdmi_monitor() - detect HDMI mode. + * @edid_ctrl: Handle to the edid_ctrl structure. + * + * Return: error code. + */ +bool sde_detect_hdmi_monitor(void *edid_ctrl); + +/** + * sde_get_edid_checksum() - return the checksum of last block of EDID. + * @input: Handle to the edid_ctrl structure. + * + * Return: checksum of the last EDID block. + */ +u8 sde_get_edid_checksum(void *input); + +/** + * _sde_edid_update_modes() - populate EDID modes. + * @edid_ctrl: Handle to the edid_ctrl structure. + * + * Return: error code. + */ +int _sde_edid_update_modes(struct drm_connector *connector, + void *edid_ctrl); + +#endif /* _SDE_EDID_PARSER_H_ */ + diff --git a/techpack/display/msm/sde_hdcp.h b/techpack/display/msm/sde_hdcp.h new file mode 100644 index 0000000000000000000000000000000000000000..f449b04b334963b70d97cb37737a3243235c7849 --- /dev/null +++ b/techpack/display/msm/sde_hdcp.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012, 2014-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_HDCP_H__ +#define __SDE_HDCP_H__ + +#include <soc/qcom/scm.h> + +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/debugfs.h> +#include <linux/of_device.h> +#include <linux/i2c.h> +#include <linux/list.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_edid.h> +#include <linux/hdcp_qseecom.h> +#include "sde_kms.h" + +#define MAX_STREAM_COUNT 2 + +enum sde_hdcp_client_id { + HDCP_CLIENT_HDMI, + HDCP_CLIENT_DP, +}; + +enum sde_hdcp_state { + HDCP_STATE_INACTIVE, + HDCP_STATE_AUTHENTICATING, + HDCP_STATE_AUTHENTICATED, + HDCP_STATE_AUTH_FAIL, +}; + +enum sde_hdcp_version { + HDCP_VERSION_NONE, + HDCP_VERSION_1X = BIT(0), + HDCP_VERSION_2P2 = BIT(1), + HDCP_VERSION_MAX = BIT(2), +}; + +struct stream_info { + u8 stream_id; + u8 virtual_channel; +}; + +struct sde_hdcp_stream { + struct list_head list; + u8 stream_id; + u8 virtual_channel; + u32 stream_handle; + bool active; +}; + +struct sde_hdcp_init_data { + struct device *msm_hdcp_dev; + struct dss_io_data *core_io; + struct dss_io_data *dp_ahb; + struct dss_io_data *dp_aux; + struct dss_io_data *dp_link; + struct dss_io_data *dp_p0; + struct dss_io_data *qfprom_io; + struct dss_io_data *hdcp_io; + struct drm_dp_aux *drm_aux; + struct mutex *mutex; + struct workqueue_struct *workq; + void *cb_data; + void (*notify_status)(void *cb_data, enum sde_hdcp_state state); + u8 sink_rx_status; + unsigned char *revision; + u32 phy_addr; + bool sec_access; + enum sde_hdcp_client_id client_id; +}; + +struct sde_hdcp_ops { + int (*isr)(void *ptr); + int (*cp_irq)(void *ptr); + int (*reauthenticate)(void *input); + int (*authenticate)(void *hdcp_ctrl); + bool (*feature_supported)(void *input); + void (*force_encryption)(void *input, bool enable); + bool (*sink_support)(void *input); + void (*abort)(void *input, bool abort); + int (*set_mode)(void *input, bool mst_enabled); + int (*on)(void *input); + void (*off)(void *hdcp_ctrl); + int (*register_streams)(void *input, u8 num_streams, + struct stream_info *streams); + int (*deregister_streams)(void *input, u8 num_streams, + struct stream_info *streams); +}; + +static inline const char *sde_hdcp_state_name(enum sde_hdcp_state hdcp_state) +{ + switch (hdcp_state) { + case HDCP_STATE_INACTIVE: return "HDCP_STATE_INACTIVE"; + case HDCP_STATE_AUTHENTICATING: return "HDCP_STATE_AUTHENTICATING"; + case HDCP_STATE_AUTHENTICATED: return "HDCP_STATE_AUTHENTICATED"; + case HDCP_STATE_AUTH_FAIL: return "HDCP_STATE_AUTH_FAIL"; + default: return "???"; + } +} + +static inline const char *sde_hdcp_version(enum sde_hdcp_version hdcp_version) +{ + switch (hdcp_version) { + case HDCP_VERSION_NONE: return "HDCP_VERSION_NONE"; + case HDCP_VERSION_1X: return "HDCP_VERSION_1X"; + case HDCP_VERSION_2P2: return "HDCP_VERSION_2P2"; + default: return "???"; + } +} + +void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data); +void sde_hdcp_1x_deinit(void *input); +struct sde_hdcp_ops *sde_hdcp_1x_get(void *input); +void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data); +void sde_dp_hdcp2p2_deinit(void *input); +struct sde_hdcp_ops *sde_dp_hdcp2p2_get(void *input); +#endif /* __SDE_HDCP_H__ */ diff --git a/techpack/display/msm/sde_hdcp_1x.c b/techpack/display/msm/sde_hdcp_1x.c new file mode 100644 index 0000000000000000000000000000000000000000..538ef0b655ce8e26b849c09d568116b9fa1545bc --- /dev/null +++ b/techpack/display/msm/sde_hdcp_1x.c @@ -0,0 +1,1577 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[sde-hdcp1x] %s: " fmt, __func__ + +#include <linux/io.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/iopoll.h> +#include <linux/msm_hdcp.h> +#include <drm/drm_dp_helper.h> +#include "sde_hdcp.h" +#include "video/msm_hdmi_hdcp_mgr.h" +#include "dp/dp_reg.h" + +#define SDE_HDCP_STATE_NAME (sde_hdcp_state_name(hdcp->hdcp_state)) + +/* QFPROM Registers for HDMI/HDCP */ +#define QFPROM_RAW_FEAT_CONFIG_ROW0_LSB (0x000000F8) +#define QFPROM_RAW_FEAT_CONFIG_ROW0_MSB (0x000000FC) +#define QFPROM_RAW_VERSION_4 (0x000000A8) +#define SEC_CTRL_HW_VERSION (0x00006000) +#define HDCP_KSV_LSB (0x000060D8) +#define HDCP_KSV_MSB (0x000060DC) +#define HDCP_KSV_VERSION_4_OFFSET (0x00000014) + +/* SEC_CTRL version that supports HDCP SEL */ +#define HDCP_SEL_MIN_SEC_VERSION (0x50010000) + +/* HDCP Keys state based on HDMI_HDCP_LINK0_STATUS:KEYS_STATE */ +#define HDCP_KEYS_STATE_NO_KEYS 0 +#define HDCP_KEYS_STATE_NOT_CHECKED 1 +#define HDCP_KEYS_STATE_CHECKING 2 +#define HDCP_KEYS_STATE_VALID 3 +#define HDCP_KEYS_STATE_AKSV_NOT_VALID 4 +#define HDCP_KEYS_STATE_CHKSUM_MISMATCH 5 +#define HDCP_KEYS_STATE_PROD_AKSV 6 +#define HDCP_KEYS_STATE_RESERVED 7 + +#define TZ_HDCP_CMD_ID 0x00004401 + +#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \ + isr->auth_fail_info_ack | isr->tx_req_ack | \ + isr->encryption_ready_ack | \ + isr->encryption_not_ready_ack | isr->tx_req_done_ack) + +#define HDCP_INT_EN (isr->auth_success_mask | isr->auth_fail_mask | \ + isr->encryption_ready_mask | \ + isr->encryption_not_ready_mask) + +#define HDCP_POLL_SLEEP_US (20 * 1000) +#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 100) + +#define sde_hdcp_1x_state(x) (hdcp->hdcp_state == x) + +struct sde_hdcp_sink_addr { + char *name; + u32 addr; + u32 len; +}; + +struct sde_hdcp_1x_reg_data { + u32 reg_id; + struct sde_hdcp_sink_addr *sink; +}; + +struct sde_hdcp_sink_addr_map { + /* addresses to read from sink */ + struct sde_hdcp_sink_addr bcaps; + struct sde_hdcp_sink_addr bksv; + struct sde_hdcp_sink_addr r0; + struct sde_hdcp_sink_addr bstatus; + struct sde_hdcp_sink_addr cp_irq_status; + struct sde_hdcp_sink_addr ksv_fifo; + struct sde_hdcp_sink_addr v_h0; + struct sde_hdcp_sink_addr v_h1; + struct sde_hdcp_sink_addr v_h2; + struct sde_hdcp_sink_addr v_h3; + struct sde_hdcp_sink_addr v_h4; + + /* addresses to write to sink */ + struct sde_hdcp_sink_addr an; + struct sde_hdcp_sink_addr aksv; + struct sde_hdcp_sink_addr ainfo; +}; + +struct sde_hdcp_int_set { + /* interrupt register */ + u32 int_reg; + + /* interrupt enable/disable masks */ + u32 auth_success_mask; + u32 auth_fail_mask; + u32 encryption_ready_mask; + u32 encryption_not_ready_mask; + u32 tx_req_mask; + u32 tx_req_done_mask; + + /* interrupt acknowledgment */ + u32 auth_success_ack; + u32 auth_fail_ack; + u32 auth_fail_info_ack; + u32 encryption_ready_ack; + u32 encryption_not_ready_ack; + u32 tx_req_ack; + u32 tx_req_done_ack; + + /* interrupt status */ + u32 auth_success_int; + u32 auth_fail_int; + u32 encryption_ready; + u32 encryption_not_ready; + u32 tx_req_int; + u32 tx_req_done_int; +}; + +struct sde_hdcp_reg_set { + u32 status; + u32 keys_offset; + u32 r0_offset; + u32 v_offset; + u32 ctrl; + u32 aksv_lsb; + u32 aksv_msb; + u32 entropy_ctrl0; + u32 entropy_ctrl1; + u32 sec_sha_ctrl; + u32 sec_sha_data; + u32 sha_status; + + u32 data2_0; + u32 data3; + u32 data4; + u32 data5; + u32 data6; + + u32 sec_data0; + u32 sec_data1; + u32 sec_data7; + u32 sec_data8; + u32 sec_data9; + u32 sec_data10; + u32 sec_data11; + u32 sec_data12; + + u32 reset; + u32 reset_bit; + + u32 repeater; +}; + +#define HDCP_REG_SET_CLIENT_HDMI \ + {0} + +#define HDCP_REG_SET_CLIENT_DP \ +{DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \ + DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \ + DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA, \ + DP_HDCP_SHA_STATUS, DP_HDCP_RCVPORT_DATA2_0, \ + DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \ + DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \ + DP_SW_RESET, BIT(1), BIT(1)} + +#define HDCP_HDMI_SINK_ADDR_MAP \ + {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \ + {"bstatus", 0x41, 2}, {"??", 0x0, 0}, {"ksv-fifo", 0x43, 0}, \ + {"v_h0", 0x20, 4}, {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, \ + {"v_h3", 0x2c, 4}, {"v_h4", 0x30, 4}, {"an", 0x18, 8}, \ + {"aksv", 0x10, 5}, {"ainfo", 0x00, 0},} + +#define HDCP_DP_SINK_ADDR_MAP \ + {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \ + {"binfo", 0x6802A, 2}, {"cp_irq_status", 0x68029, 1}, \ + {"ksv-fifo", 0x6802C, 0}, {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, \ + {"v_h2", 0x6801C, 4}, {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, \ + {"an", 0x6800C, 8}, {"aksv", 0x68007, 5}, {"ainfo", 0x6803B, 1} } + +#define HDCP_HDMI_INT_SET \ + {0} + +#define HDCP_DP_INT_SET \ + {DP_INTR_STATUS2, \ + BIT(17), BIT(20), BIT(24), BIT(27), 0, 0, \ + BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \ + BIT(15), BIT(18), BIT(22), BIT(25), 0, 0} + +struct sde_hdcp_1x { + u8 bcaps; + u32 tp_msgid; + u32 an_0, an_1, aksv_0, aksv_1; + u32 aksv_msb, aksv_lsb; + bool sink_r0_ready; + bool reauth; + bool ksv_ready; + bool force_encryption; + atomic_t abort; + enum sde_hdcp_state hdcp_state; + struct HDCP_V2V1_MSG_TOPOLOGY current_tp; + struct delayed_work hdcp_auth_work; + struct completion r0_checked; + struct completion sink_r0_available; + struct sde_hdcp_init_data init_data; + struct sde_hdcp_ops *ops; + struct sde_hdcp_reg_set reg_set; + struct sde_hdcp_int_set int_set; + struct sde_hdcp_sink_addr_map sink_addr; + struct workqueue_struct *workq; + void *hdcp1_handle; +}; + +static int sde_hdcp_1x_count_one(u8 *array, u8 len) +{ + int i, j, count = 0; + + for (i = 0; i < len; i++) + for (j = 0; j < 8; j++) + count += (((array[i] >> j) & 0x1) ? 1 : 0); + return count; +} + +static int sde_hdcp_1x_enable_hdcp_engine(void *input) +{ + int rc = 0; + struct dss_io_data *dp_ahb; + struct dss_io_data *dp_aux; + struct dss_io_data *dp_link; + struct sde_hdcp_1x *hdcp = input; + struct sde_hdcp_reg_set *reg_set; + + if (!hdcp || !hdcp->init_data.dp_ahb || + !hdcp->init_data.dp_aux || + !hdcp->init_data.dp_link) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto end; + } + + if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE) && + !sde_hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) { + pr_err("%s: invalid state. returning\n", + SDE_HDCP_STATE_NAME); + rc = -EINVAL; + goto end; + } + + dp_ahb = hdcp->init_data.dp_ahb; + dp_aux = hdcp->init_data.dp_aux; + dp_link = hdcp->init_data.dp_link; + reg_set = &hdcp->reg_set; + + DSS_REG_W(dp_aux, reg_set->aksv_lsb, hdcp->aksv_lsb); + DSS_REG_W(dp_aux, reg_set->aksv_msb, hdcp->aksv_msb); + + /* Setup seed values for random number An */ + DSS_REG_W(dp_link, reg_set->entropy_ctrl0, 0xB1FFB0FF); + DSS_REG_W(dp_link, reg_set->entropy_ctrl1, 0xF00DFACE); + + /* make sure hw is programmed */ + wmb(); + + /* enable hdcp engine */ + DSS_REG_W(dp_ahb, reg_set->ctrl, 0x1); + + hdcp->hdcp_state = HDCP_STATE_AUTHENTICATING; +end: + return rc; +} + +static int sde_hdcp_1x_read(struct sde_hdcp_1x *hdcp, + struct sde_hdcp_sink_addr *sink, + u8 *buf, bool realign) +{ + int const max_size = 15; + int rc = 0, read_size = 0, bytes_read = 0; + + if (hdcp->init_data.client_id == HDCP_CLIENT_DP) { + int size = sink->len, offset = sink->addr; + + do { + read_size = min(size, max_size); + + bytes_read = drm_dp_dpcd_read(hdcp->init_data.drm_aux, + offset, buf, read_size); + if (bytes_read != read_size) { + pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", + offset, read_size, bytes_read); + rc = -EIO; + break; + } + + buf += read_size; + size -= read_size; + + if (!realign) + offset += read_size; + } while (size > 0); + } + + return rc; +} + +static int sde_hdcp_1x_write(struct sde_hdcp_1x *hdcp, + struct sde_hdcp_sink_addr *sink, u8 *buf) +{ + int const max_size = 16; + int rc = 0, write_size = 0, bytes_written = 0; + + if (hdcp->init_data.client_id == HDCP_CLIENT_DP) { + int size = sink->len, offset = sink->addr; + + do { + write_size = min(size, max_size); + + bytes_written = + drm_dp_dpcd_write(hdcp->init_data.drm_aux, + offset, buf, write_size); + if (bytes_written != write_size) { + pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", + offset, write_size, bytes_written); + rc = -EIO; + break; + } + + buf += write_size; + offset += write_size; + size -= write_size; + } while (size > 0); + } + + return rc; +} + +static void sde_hdcp_1x_enable_interrupts(struct sde_hdcp_1x *hdcp) +{ + u32 intr_reg; + struct dss_io_data *io; + struct sde_hdcp_int_set *isr; + + io = hdcp->init_data.dp_ahb; + isr = &hdcp->int_set; + + intr_reg = DSS_REG_R(io, isr->int_reg); + + intr_reg |= HDCP_INT_CLR | HDCP_INT_EN; + + DSS_REG_W(io, isr->int_reg, intr_reg); +} + +static int sde_hdcp_1x_read_bcaps(struct sde_hdcp_1x *hdcp) +{ + int rc; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps, + &hdcp->bcaps, false); + if (rc) { + pr_err("error reading bcaps\n"); + goto error; + } + + pr_debug("bcaps read: 0x%x\n", hdcp->bcaps); + + hdcp->current_tp.ds_type = hdcp->bcaps & reg_set->repeater ? + DS_REPEATER : DS_RECEIVER; + + pr_debug("ds: %s\n", hdcp->current_tp.ds_type == DS_REPEATER ? + "repeater" : "receiver"); + + /* Write BCAPS to the hardware */ + DSS_REG_W(hdcp_io, reg_set->sec_data12, hdcp->bcaps); +error: + return rc; +} + +static int sde_hdcp_1x_wait_for_hw_ready(struct sde_hdcp_1x *hdcp) +{ + int rc; + u32 link0_status; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + struct dss_io_data *dp_ahb = hdcp->init_data.dp_ahb; + struct dss_io_data *dp_aux = hdcp->init_data.dp_aux; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + /* Wait for HDCP keys to be checked and validated */ + rc = readl_poll_timeout(dp_ahb->base + reg_set->status, link0_status, + ((link0_status >> reg_set->keys_offset) & 0x7) + == HDCP_KEYS_STATE_VALID || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (rc) { + pr_err("key not ready\n"); + goto error; + } + + /* + * 1.1_Features turned off by default. + * No need to write AInfo since 1.1_Features is disabled. + */ + DSS_REG_W(dp_aux, reg_set->data4, 0); + + /* Wait for An0 and An1 bit to be ready */ + rc = readl_poll_timeout(dp_ahb->base + reg_set->status, link0_status, + (link0_status & (BIT(8) | BIT(9))) || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (rc) { + pr_err("An not ready\n"); + goto error; + } + + /* As per hardware recommendations, wait before reading An */ + msleep(20); +error: + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + rc = -EINVAL; + + return rc; +} + +static int sde_hdcp_1x_send_an_aksv_to_sink(struct sde_hdcp_1x *hdcp) +{ + int rc; + u8 an[8], aksv[5]; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + an[0] = hdcp->an_0 & 0xFF; + an[1] = (hdcp->an_0 >> 8) & 0xFF; + an[2] = (hdcp->an_0 >> 16) & 0xFF; + an[3] = (hdcp->an_0 >> 24) & 0xFF; + an[4] = hdcp->an_1 & 0xFF; + an[5] = (hdcp->an_1 >> 8) & 0xFF; + an[6] = (hdcp->an_1 >> 16) & 0xFF; + an[7] = (hdcp->an_1 >> 24) & 0xFF; + + pr_debug("an read: 0x%2x%2x%2x%2x%2x%2x%2x%2x\n", + an[7], an[6], an[5], an[4], an[3], an[2], an[1], an[0]); + + rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.an, an); + if (rc) { + pr_err("error writing an to sink\n"); + goto error; + } + + /* Copy An and AKSV to byte arrays for transmission */ + aksv[0] = hdcp->aksv_0 & 0xFF; + aksv[1] = (hdcp->aksv_0 >> 8) & 0xFF; + aksv[2] = (hdcp->aksv_0 >> 16) & 0xFF; + aksv[3] = (hdcp->aksv_0 >> 24) & 0xFF; + aksv[4] = hdcp->aksv_1 & 0xFF; + + pr_debug("aksv read: 0x%2x%2x%2x%2x%2x\n", + aksv[4], aksv[3], aksv[2], aksv[1], aksv[0]); + + rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.aksv, aksv); + if (rc) { + pr_err("error writing aksv to sink\n"); + goto error; + } +error: + return rc; +} + +static int sde_hdcp_1x_read_an_aksv_from_hw(struct sde_hdcp_1x *hdcp) +{ + struct dss_io_data *dp_ahb = hdcp->init_data.dp_ahb; + struct dss_io_data *dp_aux = hdcp->init_data.dp_aux; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + hdcp->an_0 = DSS_REG_R(dp_ahb, reg_set->data5); + if (hdcp->init_data.client_id == HDCP_CLIENT_DP) { + udelay(1); + hdcp->an_0 = DSS_REG_R(dp_ahb, reg_set->data5); + } + + hdcp->an_1 = DSS_REG_R(dp_ahb, reg_set->data6); + if (hdcp->init_data.client_id == HDCP_CLIENT_DP) { + udelay(1); + hdcp->an_1 = DSS_REG_R(dp_ahb, reg_set->data6); + } + + /* Read AKSV */ + hdcp->aksv_0 = DSS_REG_R(dp_aux, reg_set->data3); + hdcp->aksv_1 = DSS_REG_R(dp_aux, reg_set->data4); + + return 0; +} + +static int sde_hdcp_1x_get_bksv_from_sink(struct sde_hdcp_1x *hdcp) +{ + int rc; + u8 *bksv = hdcp->current_tp.bksv; + u32 link0_bksv_0, link0_bksv_1; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + struct dss_io_data *hdcp_io = hdcp->init_data.hdcp_io; + + rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bksv, bksv, false); + if (rc) { + pr_err("error reading bksv from sink\n"); + goto error; + } + + pr_debug("bksv read: 0x%2x%2x%2x%2x%2x\n", + bksv[4], bksv[3], bksv[2], bksv[1], bksv[0]); + + /* check there are 20 ones in BKSV */ + if (sde_hdcp_1x_count_one(bksv, 5) != 20) { + pr_err("%s: BKSV doesn't have 20 1's and 20 0's\n", + SDE_HDCP_STATE_NAME); + rc = -EINVAL; + goto error; + } + + link0_bksv_0 = bksv[3]; + link0_bksv_0 = (link0_bksv_0 << 8) | bksv[2]; + link0_bksv_0 = (link0_bksv_0 << 8) | bksv[1]; + link0_bksv_0 = (link0_bksv_0 << 8) | bksv[0]; + link0_bksv_1 = bksv[4]; + + DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); + DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); +error: + return rc; +} + +static void sde_hdcp_1x_enable_sink_irq_hpd(struct sde_hdcp_1x *hdcp) +{ + u8 const required_major = 1, required_minor = 2; + u8 sink_major = 0, sink_minor = 0; + u8 enable_hpd_irq = 0x1; + int rc; + unsigned char revision = *hdcp->init_data.revision; + + sink_major = (revision >> 4) & 0x0f; + sink_minor = revision & 0x0f; + pr_debug("revision: %d.%d\n", sink_major, sink_minor); + + if ((sink_minor < required_minor) || (sink_major < required_major) || + (hdcp->current_tp.ds_type != DS_REPEATER)) { + pr_debug("sink irq hpd not enabled\n"); + return; + } + + rc = sde_hdcp_1x_write(hdcp, &hdcp->sink_addr.ainfo, &enable_hpd_irq); + if (rc) + pr_debug("error writing ainfo to sink\n"); +} + +static int sde_hdcp_1x_verify_r0(struct sde_hdcp_1x *hdcp) +{ + int rc, r0_retry = 3; + u8 buf[2]; + u32 link0_status, timeout_count; + u32 const r0_read_delay_us = 1; + u32 const r0_read_timeout_us = r0_read_delay_us * 10; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + struct dss_io_data *io = hdcp->init_data.dp_ahb; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + /* Wait for HDCP R0 computation to be completed */ + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + (link0_status & BIT(reg_set->r0_offset)) || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (rc) { + pr_err("R0 not ready\n"); + goto error; + } + + /* + * HDCP Compliace Test case 1A-01: + * Wait here at least 100ms before reading R0' + */ + if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) { + msleep(100); + } else { + if (!hdcp->sink_r0_ready) { + reinit_completion(&hdcp->sink_r0_available); + timeout_count = wait_for_completion_timeout( + &hdcp->sink_r0_available, HZ / 2); + + if (hdcp->reauth) { + pr_err("sink R0 not ready\n"); + rc = -EINVAL; + goto error; + } + } + } + + do { + memset(buf, 0, sizeof(buf)); + + rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.r0, + buf, false); + if (rc) { + pr_err("error reading R0' from sink\n"); + goto error; + } + + pr_debug("sink R0'read: %2x%2x\n", buf[1], buf[0]); + + DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]); + + rc = readl_poll_timeout(io->base + reg_set->status, + link0_status, (link0_status & BIT(12)) || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + r0_read_delay_us, r0_read_timeout_us); + } while (rc && --r0_retry); +error: + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + rc = -EINVAL; + + return rc; +} + +static int sde_hdcp_1x_authentication_part1(struct sde_hdcp_1x *hdcp) +{ + int rc; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + sde_hdcp_1x_enable_interrupts(hdcp); + + rc = sde_hdcp_1x_read_bcaps(hdcp); + if (rc) + goto error; + + rc = sde_hdcp_1x_wait_for_hw_ready(hdcp); + if (rc) + goto error; + + rc = sde_hdcp_1x_read_an_aksv_from_hw(hdcp); + if (rc) + goto error; + + rc = sde_hdcp_1x_get_bksv_from_sink(hdcp); + if (rc) + goto error; + + rc = sde_hdcp_1x_send_an_aksv_to_sink(hdcp); + if (rc) + goto error; + + sde_hdcp_1x_enable_sink_irq_hpd(hdcp); + + rc = sde_hdcp_1x_verify_r0(hdcp); + if (rc) + goto error; + + pr_info("SUCCESSFUL\n"); + + return 0; +error: + pr_err("%s: FAILED\n", SDE_HDCP_STATE_NAME); + + return rc; +} + +static int sde_hdcp_1x_transfer_v_h(struct sde_hdcp_1x *hdcp) +{ + int rc = 0; + struct dss_io_data *io = hdcp->init_data.hdcp_io; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + struct sde_hdcp_1x_reg_data reg_data[] = { + {reg_set->sec_data7, &hdcp->sink_addr.v_h0}, + {reg_set->sec_data8, &hdcp->sink_addr.v_h1}, + {reg_set->sec_data9, &hdcp->sink_addr.v_h2}, + {reg_set->sec_data10, &hdcp->sink_addr.v_h3}, + {reg_set->sec_data11, &hdcp->sink_addr.v_h4}, + }; + struct sde_hdcp_sink_addr sink = {"V", reg_data->sink->addr}; + u32 size = ARRAY_SIZE(reg_data); + u8 buf[0xFF] = {0}; + u32 i = 0, len = 0; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + for (i = 0; i < size; i++) { + struct sde_hdcp_1x_reg_data *rd = reg_data + i; + + len += rd->sink->len; + } + + sink.len = len; + + rc = sde_hdcp_1x_read(hdcp, &sink, buf, false); + if (rc) { + pr_err("error reading %s\n", sink.name); + goto end; + } + + for (i = 0; i < size; i++) { + struct sde_hdcp_1x_reg_data *rd = reg_data + i; + u32 reg_data; + + memcpy(®_data, buf + (sizeof(u32) * i), sizeof(u32)); + DSS_REG_W(io, rd->reg_id, reg_data); + } +end: + return rc; +} + +static int sde_hdcp_1x_validate_downstream(struct sde_hdcp_1x *hdcp) +{ + int rc; + u8 buf[2] = {0, 0}; + u8 device_count, depth; + u8 max_cascade_exceeded, max_devs_exceeded; + u16 bstatus; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bstatus, + buf, false); + if (rc) { + pr_err("error reading bstatus\n"); + goto end; + } + + bstatus = buf[1]; + bstatus = (bstatus << 8) | buf[0]; + + device_count = bstatus & 0x7F; + + pr_debug("device count %d\n", device_count); + + /* Cascaded repeater depth */ + depth = (bstatus >> 8) & 0x7; + pr_debug("depth %d\n", depth); + + /* + * HDCP Compliance 1B-05: + * Check if no. of devices connected to repeater + * exceed max_devices_connected from bit 7 of Bstatus. + */ + max_devs_exceeded = (bstatus & BIT(7)) >> 7; + if (max_devs_exceeded == 0x01) { + pr_err("no. of devs connected exceed max allowed\n"); + rc = -EINVAL; + goto end; + } + + /* + * HDCP Compliance 1B-06: + * Check if no. of cascade connected to repeater + * exceed max_cascade_connected from bit 11 of Bstatus. + */ + max_cascade_exceeded = (bstatus & BIT(11)) >> 11; + if (max_cascade_exceeded == 0x01) { + pr_err("no. of cascade connections exceed max allowed\n"); + rc = -EINVAL; + goto end; + } + + /* Update topology information */ + hdcp->current_tp.dev_count = device_count; + hdcp->current_tp.max_cascade_exceeded = max_cascade_exceeded; + hdcp->current_tp.max_dev_exceeded = max_devs_exceeded; + hdcp->current_tp.depth = depth; + + DSS_REG_W(hdcp->init_data.hdcp_io, + reg_set->sec_data12, hdcp->bcaps | (bstatus << 8)); +end: + return rc; +} + +static int sde_hdcp_1x_read_ksv_fifo(struct sde_hdcp_1x *hdcp) +{ + u32 ksv_read_retry = 20, ksv_bytes, rc = 0; + u8 *ksv_fifo = hdcp->current_tp.ksv_list; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + memset(ksv_fifo, 0, sizeof(hdcp->current_tp.ksv_list)); + + /* each KSV is 5 bytes long */ + ksv_bytes = 5 * hdcp->current_tp.dev_count; + hdcp->sink_addr.ksv_fifo.len = ksv_bytes; + + while (ksv_bytes && --ksv_read_retry) { + rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.ksv_fifo, + ksv_fifo, true); + if (rc) + pr_err("could not read ksv fifo (%d)\n", + ksv_read_retry); + else + break; + } + + if (rc) + pr_err("error reading ksv_fifo\n"); + + return rc; +} + +static int sde_hdcp_1x_write_ksv_fifo(struct sde_hdcp_1x *hdcp) +{ + int i, rc = 0; + u8 *ksv_fifo = hdcp->current_tp.ksv_list; + u32 ksv_bytes = hdcp->sink_addr.ksv_fifo.len; + struct dss_io_data *io = hdcp->init_data.dp_ahb; + struct dss_io_data *sec_io = hdcp->init_data.hdcp_io; + struct sde_hdcp_reg_set *reg_set = &hdcp->reg_set; + u32 sha_status = 0, status; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + /* reset SHA Controller */ + DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x1); + DSS_REG_W(sec_io, reg_set->sec_sha_ctrl, 0x0); + + for (i = 0; i < ksv_bytes - 1; i++) { + /* Write KSV byte and do not set DONE bit[0] */ + DSS_REG_W_ND(sec_io, reg_set->sec_sha_data, ksv_fifo[i] << 16); + + /* + * Once 64 bytes have been written, we need to poll for + * HDCP_SHA_BLOCK_DONE before writing any further + */ + if (i && !((i + 1) % 64)) { + rc = readl_poll_timeout(io->base + reg_set->sha_status, + sha_status, (sha_status & BIT(0)) || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (rc) { + pr_err("block not done\n"); + goto error; + } + } + } + + /* Write l to DONE bit[0] */ + DSS_REG_W_ND(sec_io, reg_set->sec_sha_data, + (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); + + /* Now wait for HDCP_SHA_COMP_DONE */ + rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status, + (sha_status & BIT(4)) || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (rc) { + pr_err("V computation not done\n"); + goto error; + } + + /* Wait for V_MATCHES */ + rc = readl_poll_timeout(io->base + reg_set->status, status, + (status & BIT(reg_set->v_offset)) || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (rc) { + pr_err("V mismatch\n"); + rc = -EINVAL; + } +error: + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + rc = -EINVAL; + + return rc; +} + +static int sde_hdcp_1x_wait_for_ksv_ready(struct sde_hdcp_1x *hdcp) +{ + int rc, timeout; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + /* + * Wait until READY bit is set in BCAPS, as per HDCP specifications + * maximum permitted time to check for READY bit is five seconds. + */ + rc = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.bcaps, + &hdcp->bcaps, false); + if (rc) { + pr_err("error reading bcaps\n"); + goto error; + } + + if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI) { + timeout = 50; + + while (!(hdcp->bcaps & BIT(5)) && --timeout) { + rc = sde_hdcp_1x_read(hdcp, + &hdcp->sink_addr.bcaps, + &hdcp->bcaps, false); + if (rc || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("error reading bcaps\n"); + goto error; + } + msleep(100); + } + } else { + u8 cp_buf = 0; + struct sde_hdcp_sink_addr *sink = + &hdcp->sink_addr.cp_irq_status; + + timeout = jiffies_to_msecs(jiffies); + + while (1) { + rc = sde_hdcp_1x_read(hdcp, sink, &cp_buf, false); + if (rc) + goto error; + + if (cp_buf & BIT(0)) + break; + + /* max timeout of 5 sec as per hdcp 1.x spec */ + if (abs(timeout - jiffies_to_msecs(jiffies)) > 5000) { + timeout = 0; + break; + } + + if (hdcp->ksv_ready || hdcp->reauth || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + break; + + /* re-read after a minimum delay */ + msleep(20); + } + } + + if (!timeout || hdcp->reauth || + !sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("DS KSV not ready\n"); + rc = -EINVAL; + } else { + hdcp->ksv_ready = true; + } +error: + return rc; +} + +static int sde_hdcp_1x_authentication_part2(struct sde_hdcp_1x *hdcp) +{ + int rc; + int v_retry = 3; + + rc = sde_hdcp_1x_validate_downstream(hdcp); + if (rc) + goto error; + + rc = sde_hdcp_1x_read_ksv_fifo(hdcp); + if (rc) + goto error; + + do { + rc = sde_hdcp_1x_transfer_v_h(hdcp); + if (rc) + goto error; + + /* do not proceed further if no device connected */ + if (!hdcp->current_tp.dev_count) + goto error; + + rc = sde_hdcp_1x_write_ksv_fifo(hdcp); + } while (--v_retry && rc); +error: + if (rc) { + pr_err("%s: FAILED\n", SDE_HDCP_STATE_NAME); + } else { + hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED; + + pr_info("SUCCESSFUL\n"); + } + + return rc; +} + +static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp) +{ + if (IS_ENABLED(CONFIG_HDCP_QSEECOM) && + sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) { + msm_hdcp_cache_repeater_topology(hdcp->init_data.msm_hdcp_dev, + &hdcp->current_tp); + msm_hdcp_notify_topology(hdcp->init_data.msm_hdcp_dev); + } + + if (hdcp->init_data.notify_status && + !sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) { + hdcp->init_data.notify_status( + hdcp->init_data.cb_data, + hdcp->hdcp_state); + } +} + +static void sde_hdcp_1x_auth_work(struct work_struct *work) +{ + int rc; + struct delayed_work *dw = to_delayed_work(work); + struct sde_hdcp_1x *hdcp = container_of(dw, + struct sde_hdcp_1x, hdcp_auth_work); + struct dss_io_data *io; + + if (!hdcp) { + pr_err("invalid input\n"); + return; + } + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + pr_err("invalid state\n"); + return; + } + + if (atomic_read(&hdcp->abort)) { + rc = -EINVAL; + goto end; + } + + hdcp->sink_r0_ready = false; + hdcp->reauth = false; + hdcp->ksv_ready = false; + + io = hdcp->init_data.core_io; + /* Enabling Software DDC for HDMI and REF timer for DP */ + if (hdcp->init_data.client_id == HDCP_CLIENT_DP) { + io = hdcp->init_data.dp_aux; + DSS_REG_W(io, DP_DP_HPD_REFTIMER, 0x10013); + } + + /* + * Program h/w to enable encryption as soon as authentication is + * successful. This is applicable for HDMI sinks and HDCP 1.x compliance + * test cases. + */ + if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI || + hdcp->force_encryption) + hdcp1_set_enc(hdcp->hdcp1_handle, true); + + rc = sde_hdcp_1x_authentication_part1(hdcp); + if (rc) + goto end; + + if (hdcp->current_tp.ds_type == DS_REPEATER) { + rc = sde_hdcp_1x_wait_for_ksv_ready(hdcp); + if (rc) + goto end; + } else { + hdcp->hdcp_state = HDCP_STATE_AUTHENTICATED; + goto end; + } + + hdcp->ksv_ready = false; + + rc = sde_hdcp_1x_authentication_part2(hdcp); + if (rc) + goto end; + + /* + * Disabling software DDC before going into part3 to make sure + * there is no Arbitration between software and hardware for DDC + */ +end: + if (rc && !sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) + hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL; + + sde_hdcp_1x_update_auth_status(hdcp); +} + +static int sde_hdcp_1x_authenticate(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + int rc = 0; + + if (!hdcp) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + flush_delayed_work(&hdcp->hdcp_auth_work); + + if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) { + pr_err("invalid state\n"); + rc = -EINVAL; + goto error; + } + + rc = hdcp1_start(hdcp->hdcp1_handle, &hdcp->aksv_msb, &hdcp->aksv_lsb); + if (rc) { + pr_err("hdcp1_start failed (%d)\n", rc); + goto error; + } + + if (!sde_hdcp_1x_enable_hdcp_engine(input)) { + + queue_delayed_work(hdcp->workq, + &hdcp->hdcp_auth_work, HZ/2); + } else { + hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL; + sde_hdcp_1x_update_auth_status(hdcp); + } + +error: + return rc; +} /* hdcp_1x_authenticate */ + +static int sde_hdcp_1x_reauthenticate(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + struct dss_io_data *io; + struct sde_hdcp_reg_set *reg_set; + struct sde_hdcp_int_set *isr; + u32 reg; + + if (!hdcp || !hdcp->init_data.dp_ahb) { + pr_err("invalid input\n"); + return -EINVAL; + } + + io = hdcp->init_data.dp_ahb; + reg_set = &hdcp->reg_set; + isr = &hdcp->int_set; + + if (!sde_hdcp_1x_state(HDCP_STATE_AUTH_FAIL)) { + pr_err("invalid state\n"); + return -EINVAL; + } + + /* Disable HDCP interrupts */ + DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN); + + reg = DSS_REG_R(io, reg_set->reset); + DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit); + + /* Disable encryption and disable the HDCP block */ + DSS_REG_W(io, reg_set->ctrl, 0); + + DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); + + hdcp->hdcp_state = HDCP_STATE_INACTIVE; + + return sde_hdcp_1x_authenticate(hdcp); +} /* hdcp_1x_reauthenticate */ + +static void sde_hdcp_1x_off(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + struct dss_io_data *io; + struct sde_hdcp_reg_set *reg_set; + struct sde_hdcp_int_set *isr; + int rc = 0; + u32 reg; + + if (!hdcp || !hdcp->init_data.dp_ahb) { + pr_err("invalid input\n"); + return; + } + + io = hdcp->init_data.dp_ahb; + reg_set = &hdcp->reg_set; + isr = &hdcp->int_set; + + if (sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) { + pr_err("invalid state\n"); + return; + } + + /* + * Disable HDCP interrupts. + * Also, need to set the state to inactive here so that any ongoing + * reauth works will know that the HDCP session has been turned off. + */ + DSS_REG_W(io, isr->int_reg, + DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN); + hdcp->hdcp_state = HDCP_STATE_INACTIVE; + + /* complete any wait pending */ + complete_all(&hdcp->sink_r0_available); + complete_all(&hdcp->r0_checked); + /* + * Cancel any pending auth/reauth attempts. + * If one is ongoing, this will wait for it to finish. + * No more reauthentiaction attempts will be scheduled since we + * set the currect state to inactive. + */ + rc = cancel_delayed_work_sync(&hdcp->hdcp_auth_work); + if (rc) + pr_debug("%s: Deleted hdcp auth work\n", + SDE_HDCP_STATE_NAME); + + if (hdcp->init_data.client_id == HDCP_CLIENT_HDMI || + hdcp->force_encryption) + hdcp1_set_enc(hdcp->hdcp1_handle, false); + + reg = DSS_REG_R(io, reg_set->reset); + DSS_REG_W(io, reg_set->reset, reg | reg_set->reset_bit); + + /* Disable encryption and disable the HDCP block */ + DSS_REG_W(io, reg_set->ctrl, 0); + + DSS_REG_W(io, reg_set->reset, reg & ~reg_set->reset_bit); + + hdcp->sink_r0_ready = false; + + hdcp1_stop(hdcp->hdcp1_handle); + + pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME); +} /* hdcp_1x_off */ + +static int sde_hdcp_1x_isr(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + int rc = 0; + struct dss_io_data *io; + u32 hdcp_int_val; + struct sde_hdcp_reg_set *reg_set; + struct sde_hdcp_int_set *isr; + + if (!hdcp || !hdcp->init_data.dp_ahb) { + pr_err("invalid input\n"); + rc = -EINVAL; + goto error; + } + + io = hdcp->init_data.dp_ahb; + reg_set = &hdcp->reg_set; + isr = &hdcp->int_set; + + hdcp_int_val = DSS_REG_R(io, isr->int_reg); + + /* Ignore HDCP interrupts if HDCP is disabled */ + if (sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) { + DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR); + return 0; + } + + if (hdcp_int_val & isr->auth_success_int) { + /* AUTH_SUCCESS_INT */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->auth_success_ack)); + pr_debug("%s: AUTH SUCCESS\n", SDE_HDCP_STATE_NAME); + + if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + complete_all(&hdcp->r0_checked); + } + + if (hdcp_int_val & isr->auth_fail_int) { + /* AUTH_FAIL_INT */ + u32 link_status = DSS_REG_R(io, reg_set->status); + + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->auth_fail_ack)); + + pr_debug("%s: AUTH FAIL, LINK0_STATUS=0x%08x\n", + SDE_HDCP_STATE_NAME, link_status); + + if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATED)) { + hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL; + sde_hdcp_1x_update_auth_status(hdcp); + } else if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) { + complete_all(&hdcp->r0_checked); + } + + /* Clear AUTH_FAIL_INFO as well */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->auth_fail_info_ack)); + } + + if (hdcp_int_val & isr->tx_req_int) { + /* DDC_XFER_REQ_INT */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->tx_req_ack)); + pr_debug("%s: DDC_XFER_REQ_INT received\n", + SDE_HDCP_STATE_NAME); + } + + if (hdcp_int_val & isr->tx_req_done_int) { + /* DDC_XFER_DONE_INT */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->tx_req_done_ack)); + pr_debug("%s: DDC_XFER_DONE received\n", + SDE_HDCP_STATE_NAME); + } + + if (hdcp_int_val & isr->encryption_ready) { + /* Encryption enabled */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->encryption_ready_ack)); + pr_debug("%s: encryption ready received\n", + SDE_HDCP_STATE_NAME); + } + + if (hdcp_int_val & isr->encryption_not_ready) { + /* Encryption enabled */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->encryption_not_ready_ack)); + pr_debug("%s: encryption not ready received\n", + SDE_HDCP_STATE_NAME); + } + +error: + return rc; +} + +static bool sde_hdcp_1x_feature_supported(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + bool feature_supported = false; + + if (!hdcp) { + pr_err("invalid input\n"); + return -EINVAL; + } + + feature_supported = hdcp1_feature_supported(hdcp->hdcp1_handle); + + pr_debug("feature_supported = %d\n", feature_supported); + + return feature_supported; +} + +static void sde_hdcp_1x_force_encryption(void *input, bool enable) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + + if (!hdcp) { + pr_err("invalid input\n"); + return; + } + hdcp->force_encryption = enable; + pr_info("force_encryption=%d\n", hdcp->force_encryption); +} + +static bool sde_hdcp_1x_sink_support(void *input) +{ + return true; +} + +void sde_hdcp_1x_deinit(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + + if (!hdcp) { + pr_err("invalid input\n"); + return; + } + + if (hdcp->workq) + destroy_workqueue(hdcp->workq); + + hdcp1_deinit(hdcp->hdcp1_handle); + + kfree(hdcp); +} /* hdcp_1x_deinit */ + +static void sde_hdcp_1x_update_client_reg_set(struct sde_hdcp_1x *hdcp) +{ + if (hdcp->init_data.client_id == HDCP_CLIENT_DP) { + struct sde_hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_DP; + struct sde_hdcp_sink_addr_map sink_addr = HDCP_DP_SINK_ADDR_MAP; + struct sde_hdcp_int_set isr = HDCP_DP_INT_SET; + + hdcp->reg_set = reg_set; + hdcp->sink_addr = sink_addr; + hdcp->int_set = isr; + } +} + +static bool sde_hdcp_1x_is_cp_irq_raised(struct sde_hdcp_1x *hdcp) +{ + int ret; + u8 buf = 0; + struct sde_hdcp_sink_addr sink = {"irq", 0x201, 1}; + + ret = sde_hdcp_1x_read(hdcp, &sink, &buf, false); + if (ret) + pr_err("error reading irq_vector\n"); + + return buf & BIT(2) ? true : false; +} + +static void sde_hdcp_1x_clear_cp_irq(struct sde_hdcp_1x *hdcp) +{ + int ret; + u8 buf = BIT(2); + struct sde_hdcp_sink_addr sink = {"irq", 0x201, 1}; + + ret = sde_hdcp_1x_write(hdcp, &sink, &buf); + if (ret) + pr_err("error clearing irq_vector\n"); +} + +static int sde_hdcp_1x_cp_irq(void *input) +{ + struct sde_hdcp_1x *hdcp = (struct sde_hdcp_1x *)input; + u8 buf = 0; + int ret; + + if (!hdcp) { + pr_err("invalid input\n"); + goto irq_not_handled; + } + + if (!sde_hdcp_1x_is_cp_irq_raised(hdcp)) { + pr_debug("cp_irq not raised\n"); + goto irq_not_handled; + } + + ret = sde_hdcp_1x_read(hdcp, &hdcp->sink_addr.cp_irq_status, + &buf, false); + if (ret) { + pr_err("error reading cp_irq_status\n"); + goto irq_not_handled; + } + + if ((buf & BIT(2)) || (buf & BIT(3))) { + pr_err("%s\n", + buf & BIT(2) ? "LINK_INTEGRITY_FAILURE" : + "REAUTHENTICATION_REQUEST"); + + hdcp->reauth = true; + + if (!sde_hdcp_1x_state(HDCP_STATE_INACTIVE)) + hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL; + + complete_all(&hdcp->sink_r0_available); + sde_hdcp_1x_update_auth_status(hdcp); + } else if (buf & BIT(1)) { + pr_debug("R0' AVAILABLE\n"); + hdcp->sink_r0_ready = true; + complete_all(&hdcp->sink_r0_available); + } else if ((buf & BIT(0))) { + pr_debug("KSVs READY\n"); + + hdcp->ksv_ready = true; + } else { + pr_debug("spurious interrupt\n"); + } + + sde_hdcp_1x_clear_cp_irq(hdcp); + return 0; + +irq_not_handled: + return -EINVAL; +} + +static void sde_hdcp_1x_abort(void *data, bool abort) +{ + struct sde_hdcp_1x *hdcp = data; + + atomic_set(&hdcp->abort, abort); + cancel_delayed_work_sync(&hdcp->hdcp_auth_work); + flush_workqueue(hdcp->workq); + if (sde_hdcp_1x_state(HDCP_STATE_AUTHENTICATING)) + hdcp->hdcp_state = HDCP_STATE_AUTH_FAIL; +} + +void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data) +{ + struct sde_hdcp_1x *hdcp = NULL; + char name[20]; + static struct sde_hdcp_ops ops = { + .isr = sde_hdcp_1x_isr, + .cp_irq = sde_hdcp_1x_cp_irq, + .reauthenticate = sde_hdcp_1x_reauthenticate, + .authenticate = sde_hdcp_1x_authenticate, + .feature_supported = sde_hdcp_1x_feature_supported, + .force_encryption = sde_hdcp_1x_force_encryption, + .sink_support = sde_hdcp_1x_sink_support, + .abort = sde_hdcp_1x_abort, + .off = sde_hdcp_1x_off + }; + + if (!init_data || !init_data->notify_status || + !init_data->workq || !init_data->cb_data) { + pr_err("invalid input\n"); + goto error; + } + + if (init_data->sec_access && !init_data->hdcp_io) { + pr_err("hdcp_io required\n"); + goto error; + } + + hdcp = kzalloc(sizeof(*hdcp), GFP_KERNEL); + if (!hdcp) + goto error; + + hdcp->init_data = *init_data; + hdcp->ops = &ops; + + snprintf(name, sizeof(name), "hdcp_1x_%d", + hdcp->init_data.client_id); + + hdcp->workq = create_workqueue(name); + if (!hdcp->workq) { + pr_err("Error creating workqueue\n"); + goto workqueue_error; + } + + hdcp->hdcp1_handle = hdcp1_init(); + if (!hdcp->hdcp1_handle) { + pr_err("Error creating HDCP 1.x handle\n"); + goto hdcp1_handle_error; + } + + sde_hdcp_1x_update_client_reg_set(hdcp); + + INIT_DELAYED_WORK(&hdcp->hdcp_auth_work, sde_hdcp_1x_auth_work); + + hdcp->hdcp_state = HDCP_STATE_INACTIVE; + init_completion(&hdcp->r0_checked); + init_completion(&hdcp->sink_r0_available); + hdcp->force_encryption = false; + + pr_debug("HDCP module initialized. HDCP_STATE=%s\n", + SDE_HDCP_STATE_NAME); + + return (void *)hdcp; +hdcp1_handle_error: + destroy_workqueue(hdcp->workq); +workqueue_error: + kfree(hdcp); +error: + return NULL; +} /* hdcp_1x_init */ + +struct sde_hdcp_ops *sde_hdcp_1x_get(void *input) +{ + return ((struct sde_hdcp_1x *)input)->ops; +} diff --git a/techpack/display/msm/sde_hdcp_2x.c b/techpack/display/msm/sde_hdcp_2x.c new file mode 100644 index 0000000000000000000000000000000000000000..dbb56c40796b749475b9dce2e0db4b90430cb66e --- /dev/null +++ b/techpack/display/msm/sde_hdcp_2x.c @@ -0,0 +1,1103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[sde-hdcp-2x] %s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kthread.h> +#include <linux/kfifo.h> + +#include "sde_hdcp_2x.h" + +/* all message IDs */ +#define INVALID_MESSAGE 0 +#define AKE_INIT 2 +#define AKE_SEND_CERT 3 +#define AKE_NO_STORED_KM 4 +#define AKE_STORED_KM 5 +#define AKE_SEND_H_PRIME 7 +#define AKE_SEND_PAIRING_INFO 8 +#define LC_INIT 9 +#define LC_SEND_L_PRIME 10 +#define SKE_SEND_EKS 11 +#define REP_SEND_RECV_ID_LIST 12 +#define REP_SEND_ACK 15 +#define REP_STREAM_MANAGE 16 +#define REP_STREAM_READY 17 +#define SKE_SEND_TYPE_ID 18 +#define HDCP2P2_MAX_MESSAGES 19 + +#define REAUTH_REQ BIT(3) +#define LINK_INTEGRITY_FAILURE BIT(4) + +/* Temporary define to override wrong TZ value */ +#define AKE_SEND_CERT_MSG_DELAY 100 + +struct sde_hdcp_2x_ctrl { + DECLARE_KFIFO(cmd_q, enum sde_hdcp_2x_wakeup_cmd, 8); + wait_queue_head_t wait_q; + struct hdcp2_app_data app_data; + u32 timeout_left; + u32 wait_timeout_ms; + u32 total_message_length; + atomic_t enable_pending; + bool no_stored_km; + bool feature_supported; + bool force_encryption; + bool authenticated; + bool resend_lc_init; + bool resend_stream_manage; + void *client_data; + void *hdcp2_ctx; + struct hdcp_transport_ops *client_ops; + bool repeater_flag; + bool update_stream; + int last_msg; + atomic_t hdcp_off; + enum sde_hdcp_2x_device_type device_type; + u8 min_enc_level; + struct list_head stream_handles; + u8 stream_count; + + struct task_struct *thread; + struct completion response_completion; +}; + +static void sde_hdcp_2x_clean(struct sde_hdcp_2x_ctrl *hdcp); + +static const char *sde_hdcp_2x_message_name(int msg_id) +{ + switch (msg_id) { + case INVALID_MESSAGE: return TO_STR(INVALID_MESSAGE); + case AKE_INIT: return TO_STR(AKE_INIT); + case AKE_SEND_CERT: return TO_STR(AKE_SEND_CERT); + case AKE_NO_STORED_KM: return TO_STR(AKE_NO_STORED_KM); + case AKE_STORED_KM: return TO_STR(AKE_STORED_KM); + case AKE_SEND_H_PRIME: return TO_STR(AKE_SEND_H_PRIME); + case AKE_SEND_PAIRING_INFO: return TO_STR(AKE_SEND_PAIRING_INFO); + case LC_INIT: return TO_STR(LC_INIT); + case LC_SEND_L_PRIME: return TO_STR(LC_SEND_L_PRIME); + case SKE_SEND_EKS: return TO_STR(SKE_SEND_EKS); + case REP_SEND_RECV_ID_LIST: return TO_STR(REP_SEND_RECV_ID_LIST); + case REP_STREAM_MANAGE: return TO_STR(REP_STREAM_MANAGE); + case REP_STREAM_READY: return TO_STR(REP_STREAM_READY); + case SKE_SEND_TYPE_ID: return TO_STR(SKE_SEND_TYPE_ID); + default: + return "UNKNOWN"; + } +} + +static const struct sde_hdcp_2x_msg_data + hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = { + [AKE_INIT] = { 2, + { {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} }, + 0, 0 }, + [AKE_SEND_CERT] = { 3, + { {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8}, + {"RxCaps", 0x6921D, 3} }, + 0, 110 }, + [AKE_NO_STORED_KM] = { 1, + { {"Ekpub_km", 0x69220, 128} }, + 0, 0 }, + [AKE_STORED_KM] = { 2, + { {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} }, + 0, 0 }, + [AKE_SEND_H_PRIME] = { 1, + { {"H'", 0x692C0, 32} }, + (1 << 1), 7 }, + [AKE_SEND_PAIRING_INFO] = { 1, + { {"Ekh_km", 0x692E0, 16} }, + (1 << 2), 5 }, + [LC_INIT] = { 1, + { {"rn", 0x692F0, 8} }, + 0, 0 }, + [LC_SEND_L_PRIME] = { 1, + { {"L'", 0x692F8, 32} }, + 0, 0 }, + [SKE_SEND_EKS] = { 2, + { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} }, + 0, 0 }, + [SKE_SEND_TYPE_ID] = { 1, + { {"type", 0x69494, 1} }, + 0, 0 }, + [REP_SEND_RECV_ID_LIST] = { 4, + { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3}, + {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} }, + (1 << 0), 0 }, + [REP_SEND_ACK] = { 1, + { {"V", 0x693E0, 16} }, + 0, 0 }, + [REP_STREAM_MANAGE] = { 3, + { {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2}, + {"streamID_Type", 0x693F5, 126} }, + 0, 0 }, + [REP_STREAM_READY] = { 1, + { {"M'", 0x69473, 32} }, + 0, 7 }, +}; + +static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp, + struct hdcp_transport_wakeup_data *data) +{ + switch (hdcp->last_msg) { + case INVALID_MESSAGE: + return AKE_INIT; + case AKE_INIT: + return AKE_SEND_CERT; + case AKE_SEND_CERT: + if (hdcp->no_stored_km) + return AKE_NO_STORED_KM; + else + return AKE_STORED_KM; + case AKE_STORED_KM: + case AKE_NO_STORED_KM: + return AKE_SEND_H_PRIME; + case AKE_SEND_H_PRIME: + if (hdcp->no_stored_km) + return AKE_SEND_PAIRING_INFO; + else + return LC_INIT; + case AKE_SEND_PAIRING_INFO: + return LC_INIT; + case LC_INIT: + return LC_SEND_L_PRIME; + case LC_SEND_L_PRIME: + if (hdcp->resend_lc_init) + return LC_INIT; + else + return SKE_SEND_EKS; + case SKE_SEND_EKS: + if (!hdcp->repeater_flag) + return SKE_SEND_TYPE_ID; + case SKE_SEND_TYPE_ID: + if (!hdcp->repeater_flag) + return SKE_SEND_TYPE_ID; + case REP_STREAM_READY: + case REP_SEND_ACK: + if (!hdcp->repeater_flag) + return INVALID_MESSAGE; + + if (data->cmd == HDCP_TRANSPORT_CMD_SEND_MESSAGE) + return REP_STREAM_MANAGE; + else + return REP_SEND_RECV_ID_LIST; + case REP_SEND_RECV_ID_LIST: + return REP_SEND_ACK; + case REP_STREAM_MANAGE: + hdcp->resend_stream_manage = false; + return REP_STREAM_READY; + default: + pr_err("Unknown message ID (%d)\n", hdcp->last_msg); + return -EINVAL; + } +} + +static void sde_hdcp_2x_wait_for_response(struct sde_hdcp_2x_ctrl *hdcp) +{ + u32 timeout; + + switch (hdcp->last_msg) { + case AKE_SEND_H_PRIME: + if (hdcp->no_stored_km) + hdcp->wait_timeout_ms = HZ; + else + hdcp->wait_timeout_ms = HZ / 4; + break; + case AKE_SEND_PAIRING_INFO: + hdcp->wait_timeout_ms = HZ / 4; + break; + case REP_SEND_RECV_ID_LIST: + if (!hdcp->authenticated) + hdcp->wait_timeout_ms = HZ * 3; + else + hdcp->wait_timeout_ms = 0; + break; + default: + hdcp->wait_timeout_ms = 0; + } + + if (!hdcp->wait_timeout_ms) + return; + + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state: hdcp off\n"); + return; + } + + reinit_completion(&hdcp->response_completion); + timeout = wait_for_completion_timeout(&hdcp->response_completion, + hdcp->wait_timeout_ms); + if (!timeout) { + pr_err("completion expired, last message = %s\n", + sde_hdcp_2x_message_name(hdcp->last_msg)); + + if (!atomic_read(&hdcp->hdcp_off)) + sde_hdcp_2x_clean(hdcp); + } + + hdcp->wait_timeout_ms = 0; +} + +static void sde_hdcp_2x_adjust_transaction_params( + struct sde_hdcp_2x_ctrl *hdcp, + struct hdcp_transport_wakeup_data *data) +{ + switch (hdcp->last_msg) { + case AKE_SEND_CERT: + data->transaction_delay = AKE_SEND_CERT_MSG_DELAY; + case REP_STREAM_READY: + break; + default: + data->transaction_delay = 0; + break; + } + + data->transaction_timeout = + hdcp_msg_lookup[hdcp->last_msg].transaction_timeout; + + pr_debug("%s: transaction delay: %ums, transaction timeout: %ums\n", + sde_hdcp_2x_message_name(hdcp->last_msg), + data->transaction_delay, data->transaction_timeout); +} + +static void sde_hdcp_2x_wakeup_client(struct sde_hdcp_2x_ctrl *hdcp, + struct hdcp_transport_wakeup_data *data) +{ + int rc = 0; + + if (!hdcp || !hdcp->client_ops || !hdcp->client_ops->wakeup || + !data || (data->cmd == HDCP_TRANSPORT_CMD_INVALID)) + return; + + data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE; + + if (data->cmd == HDCP_TRANSPORT_CMD_SEND_MESSAGE || + data->cmd == HDCP_TRANSPORT_CMD_RECV_MESSAGE || + data->cmd == HDCP_TRANSPORT_CMD_LINK_POLL) { + hdcp->last_msg = + sde_hdcp_2x_get_next_message(hdcp, data); + if (hdcp->last_msg <= INVALID_MESSAGE) { + hdcp->last_msg = INVALID_MESSAGE; + return; + } + + data->message_data = &hdcp_msg_lookup[hdcp->last_msg]; + } + + sde_hdcp_2x_adjust_transaction_params(hdcp, data); + + rc = hdcp->client_ops->wakeup(data); + if (rc) + pr_err("error sending %s to client\n", + hdcp_transport_cmd_to_str(data->cmd)); + + sde_hdcp_2x_wait_for_response(hdcp); +} + +static inline void sde_hdcp_2x_send_message(struct sde_hdcp_2x_ctrl *hdcp) +{ + struct hdcp_transport_wakeup_data cdata = { + HDCP_TRANSPORT_CMD_SEND_MESSAGE }; + + cdata.context = hdcp->client_data; + cdata.transaction_delay = hdcp->app_data.timeout; + cdata.buf_len = hdcp->app_data.response.length; + + /* ignore the first byte as it contains the message id */ + cdata.buf = hdcp->app_data.response.data + 1; + + sde_hdcp_2x_wakeup_client(hdcp, &cdata); +} + +static bool sde_hdcp_2x_client_feature_supported(void *data) +{ + struct sde_hdcp_2x_ctrl *hdcp = data; + + while (atomic_read(&hdcp->enable_pending)) + usleep_range(1000, 1500); + + return hdcp2_feature_supported(hdcp->hdcp2_ctx); +} + +static void sde_hdcp_2x_force_encryption(void *data, bool enable) +{ + struct sde_hdcp_2x_ctrl *hdcp = data; + + if (!hdcp) { + pr_err("invalid input\n"); + return; + } + + hdcp->force_encryption = enable; + pr_info("force_encryption=%d\n", hdcp->force_encryption); +} + +static void sde_hdcp_2x_clean(struct sde_hdcp_2x_ctrl *hdcp) +{ + struct list_head *element; + struct sde_hdcp_stream *stream_entry; + struct hdcp_transport_wakeup_data cdata = {HDCP_TRANSPORT_CMD_INVALID}; + + hdcp->authenticated = false; + + cdata.context = hdcp->client_data; + cdata.cmd = HDCP_TRANSPORT_CMD_STATUS_FAILED; + + while (!list_empty(&hdcp->stream_handles)) { + element = hdcp->stream_handles.next; + list_del(element); + + stream_entry = list_entry(element, struct sde_hdcp_stream, + list); + hdcp2_close_stream(hdcp->hdcp2_ctx, + stream_entry->stream_handle); + kzfree(stream_entry); + hdcp->stream_count--; + } + + if (!atomic_xchg(&hdcp->hdcp_off, 1)) + sde_hdcp_2x_wakeup_client(hdcp, &cdata); + + hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_STOP, &hdcp->app_data); +} + +static u8 sde_hdcp_2x_stream_type(u8 min_enc_level) +{ + u8 stream_type = 0; + + switch (min_enc_level) { + case 0: + case 1: + stream_type = 0; + break; + case 2: + stream_type = 1; + break; + default: + stream_type = 0; + break; + } + + pr_debug("min_enc_level = %u, type = %u\n", min_enc_level, stream_type); + + return stream_type; +} + +static void sde_hdcp_2x_send_type(struct sde_hdcp_2x_ctrl *hdcp) +{ + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state, hdcp off\n"); + return; + } + + if (hdcp->repeater_flag) { + pr_debug("invalid state, not receiver\n"); + return; + } + + hdcp->app_data.response.data[0] = SKE_SEND_TYPE_ID; + hdcp->app_data.response.data[1] = + sde_hdcp_2x_stream_type(hdcp->min_enc_level); + hdcp->app_data.response.length = 1; + hdcp->app_data.timeout = 100; + + if (!atomic_read(&hdcp->hdcp_off)) + sde_hdcp_2x_send_message(hdcp); +} + +static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp) +{ + int rc = 0; + + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state, hdcp off\n"); + return; + } + + if (!hdcp->repeater_flag) { + pr_debug("invalid state, not a repeater\n"); + return; + } + + if (!hdcp->authenticated && + hdcp->app_data.response.data[0] != REP_SEND_ACK) { + pr_debug("invalid state. HDCP repeater not authenticated\n"); + return; + } + + rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_QUERY_STREAM, + &hdcp->app_data); + if (rc) + goto exit; + + if (!hdcp->app_data.response.data || !hdcp->app_data.request.data) { + pr_err("invalid response/request buffers\n"); + rc = -EINVAL; + goto exit; + } + + pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name( + hdcp->app_data.response.data[0])); +exit: + if (!rc && !atomic_read(&hdcp->hdcp_off)) { + /* Modify last message to ensure the proper message is sent */ + hdcp->last_msg = REP_SEND_ACK; + sde_hdcp_2x_send_message(hdcp); + } +} + +static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp, + enum hdcp_transport_wakeup_cmd cmd, + struct hdcp_transport_wakeup_data *cdata) +{ + cdata->cmd = cmd; + cdata->transaction_delay = hdcp->timeout_left; + cdata->buf = hdcp->app_data.request.data + 1; +} + +static void sde_hdcp_2x_msg_sent(struct sde_hdcp_2x_ctrl *hdcp) +{ + struct hdcp_transport_wakeup_data cdata = { + HDCP_TRANSPORT_CMD_INVALID, + hdcp->client_data}; + + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state, hdcp off\n"); + return; + } + + switch (hdcp->app_data.response.data[0]) { + case SKE_SEND_TYPE_ID: + if (!hdcp2_app_comm(hdcp->hdcp2_ctx, + HDCP2_CMD_EN_ENCRYPTION, &hdcp->app_data)) { + hdcp->authenticated = true; + + if (hdcp->force_encryption) + hdcp2_force_encryption(hdcp->hdcp2_ctx, 1); + + cdata.cmd = HDCP_TRANSPORT_CMD_STATUS_SUCCESS; + sde_hdcp_2x_wakeup_client(hdcp, &cdata); + } + + /* poll for link check */ + sde_hdcp_2x_initialize_command(hdcp, + HDCP_TRANSPORT_CMD_LINK_POLL, &cdata); + break; + case SKE_SEND_EKS: + if (hdcp->repeater_flag && !atomic_read(&hdcp->hdcp_off)) { + /* poll for link check */ + sde_hdcp_2x_initialize_command(hdcp, + HDCP_TRANSPORT_CMD_LINK_POLL, &cdata); + } else { + hdcp->app_data.response.data[0] = SKE_SEND_TYPE_ID; + hdcp->app_data.response.data[1] = + sde_hdcp_2x_stream_type(hdcp->min_enc_level); + hdcp->app_data.response.length = 1; + hdcp->app_data.timeout = 100; + + sde_hdcp_2x_send_message(hdcp); + } + break; + case REP_SEND_ACK: + pr_debug("Repeater authentication successful. update_stream=%d\n", + hdcp->update_stream); + + if (hdcp->update_stream) { + sde_hdcp_2x_query_stream(hdcp); + hdcp->update_stream = false; + } else { + sde_hdcp_2x_initialize_command(hdcp, + HDCP_TRANSPORT_CMD_LINK_POLL, &cdata); + } + break; + default: + cdata.cmd = HDCP_TRANSPORT_CMD_RECV_MESSAGE; + cdata.transaction_delay = hdcp->app_data.timeout; + cdata.buf = hdcp->app_data.request.data + 1; + } + + sde_hdcp_2x_wakeup_client(hdcp, &cdata); +} + +static void sde_hdcp_2x_init(struct sde_hdcp_2x_ctrl *hdcp) +{ + int rc; + rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_START, &hdcp->app_data); + if (rc) + sde_hdcp_2x_clean(hdcp); +} + +static void sde_hdcp_2x_start_auth(struct sde_hdcp_2x_ctrl *hdcp) +{ + int rc; + + rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_START_AUTH, + &hdcp->app_data); + if (rc) { + sde_hdcp_2x_clean(hdcp); + return; + } + + pr_debug("message received from TZ: %s\n", + sde_hdcp_2x_message_name(hdcp->app_data.response.data[0])); + + sde_hdcp_2x_send_message(hdcp); +} + +static void sde_hdcp_2x_timeout(struct sde_hdcp_2x_ctrl *hdcp) +{ + int rc = 0; + int message_id; + + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state, hdcp off\n"); + return; + } + + rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_TIMEOUT, + &hdcp->app_data); + if (rc) + goto error; + + message_id = (int)hdcp->app_data.response.data[0]; + if (message_id == LC_INIT && !atomic_read(&hdcp->hdcp_off)) + sde_hdcp_2x_send_message(hdcp); + return; +error: + if (!atomic_read(&hdcp->hdcp_off)) + sde_hdcp_2x_clean(hdcp); +} + +static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp) +{ + int rc = 0; + char *msg = NULL; + u32 message_id_bytes = 0; + u32 request_length, out_msg; + struct hdcp_transport_wakeup_data cdata = {HDCP_TRANSPORT_CMD_INVALID}; + + if (atomic_read(&hdcp->hdcp_off)) { + pr_debug("invalid state, hdcp off\n"); + return; + } + + cdata.context = hdcp->client_data; + + request_length = hdcp->total_message_length; + msg = hdcp->app_data.request.data; + + if (request_length == 0) { + pr_err("invalid message length\n"); + goto exit; + } + + if (hdcp->device_type == HDCP_TXMTR_DP || + hdcp->device_type == HDCP_TXMTR_DP_MST) { + msg[0] = hdcp->last_msg; + message_id_bytes = 1; + } + + request_length += message_id_bytes; + + pr_debug("[sink]: %s\n", sde_hdcp_2x_message_name(msg[0])); + + hdcp->app_data.request.length = request_length; + rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_PROCESS_MSG, + &hdcp->app_data); + if (rc) { + pr_err("failed to process sink's response to %s (%d)\n", + sde_hdcp_2x_message_name(msg[0]), rc); + rc = -EINVAL; + goto exit; + } + + if (msg[0] == AKE_SEND_H_PRIME && hdcp->no_stored_km) { + cdata.cmd = HDCP_TRANSPORT_CMD_RECV_MESSAGE; + cdata.transaction_delay = hdcp->app_data.timeout; + cdata.buf = hdcp->app_data.request.data + 1; + goto exit; + } + + if (hdcp->app_data.response.length == 0) + out_msg = INVALID_MESSAGE; + else + out_msg = (u32)hdcp->app_data.response.data[0]; + + pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(out_msg)); + + if (msg[0] == REP_STREAM_READY && out_msg != REP_STREAM_MANAGE) { + if (hdcp->resend_stream_manage) { + pr_debug("resend stream management\n"); + } else if (!hdcp->authenticated) { + rc = hdcp2_app_comm(hdcp->hdcp2_ctx, + HDCP2_CMD_EN_ENCRYPTION, + &hdcp->app_data); + if (!rc) { + hdcp->authenticated = true; + + if (hdcp->force_encryption) + hdcp2_force_encryption( + hdcp->hdcp2_ctx, 1); + + cdata.cmd = HDCP_TRANSPORT_CMD_STATUS_SUCCESS; + sde_hdcp_2x_wakeup_client(hdcp, &cdata); + } else { + pr_err("failed to enable encryption (%d)\n", + rc); + } + } + + sde_hdcp_2x_initialize_command(hdcp, + HDCP_TRANSPORT_CMD_LINK_POLL, &cdata); + goto exit; + } + + hdcp->resend_lc_init = false; + if (msg[0] == LC_SEND_L_PRIME && out_msg == LC_INIT) + hdcp->resend_lc_init = true; + + if (msg[0] == REP_STREAM_READY && out_msg == REP_STREAM_MANAGE) + pr_debug("resend %s\n", sde_hdcp_2x_message_name(out_msg)); + + if (out_msg == AKE_NO_STORED_KM) + hdcp->no_stored_km = true; + else + hdcp->no_stored_km = false; + + if (out_msg == SKE_SEND_EKS) { + hdcp->repeater_flag = hdcp->app_data.repeater_flag; + hdcp->update_stream = true; + } + + if (!atomic_read(&hdcp->hdcp_off)) { + cdata.cmd = HDCP_TRANSPORT_CMD_SEND_MESSAGE; + cdata.buf = hdcp->app_data.response.data + 1; + cdata.buf_len = hdcp->app_data.response.length; + cdata.transaction_delay = hdcp->app_data.timeout; + } +exit: + sde_hdcp_2x_wakeup_client(hdcp, &cdata); + + if (rc && !atomic_read(&hdcp->hdcp_off)) + sde_hdcp_2x_clean(hdcp); +} + +static struct list_head *sde_hdcp_2x_stream_present( + struct sde_hdcp_2x_ctrl *hdcp, u8 stream_id, u8 virtual_channel) +{ + struct sde_hdcp_stream *stream_entry; + struct list_head *entry; + bool present = false; + + list_for_each(entry, &hdcp->stream_handles) { + stream_entry = list_entry(entry, + struct sde_hdcp_stream, list); + if (stream_entry->virtual_channel == virtual_channel && + stream_entry->stream_id == stream_id) { + present = true; + break; + } + } + + if (!present) + entry = NULL; + return entry; +} + + +static void sde_hdcp_2x_manage_stream(struct sde_hdcp_2x_ctrl *hdcp) +{ + struct list_head *entry; + struct list_head *element; + struct sde_hdcp_stream *stream_entry; + bool query_streams = false; + + entry = hdcp->stream_handles.next; + while (entry != &hdcp->stream_handles) { + stream_entry = list_entry(entry, struct sde_hdcp_stream, list); + element = entry; + entry = entry->next; + + if (!stream_entry->active) { + hdcp2_close_stream(hdcp->hdcp2_ctx, + stream_entry->stream_handle); + hdcp->stream_count--; + list_del(element); + kzfree(stream_entry); + query_streams = true; + } else if (!stream_entry->stream_handle) { + if (hdcp2_open_stream(hdcp->hdcp2_ctx, + stream_entry->virtual_channel, + stream_entry->stream_id, + &stream_entry->stream_handle)) + pr_err("Unable to open stream %d, virtual channel %d\n", + stream_entry->stream_id, + stream_entry->virtual_channel); + else + query_streams = true; + } + } + + if (query_streams) { + if (hdcp->authenticated) { + sde_hdcp_2x_query_stream(hdcp); + } else if (hdcp->last_msg == REP_STREAM_MANAGE || + hdcp->last_msg == REP_STREAM_READY) { + hdcp->resend_stream_manage = true; + } + } +} + + +static bool sde_hdcp_2x_remove_streams(struct sde_hdcp_2x_ctrl *hdcp, + struct stream_info *streams, u8 num_streams) +{ + u8 i; + u8 stream_id; + u8 virtual_channel; + struct list_head *entry; + struct sde_hdcp_stream *stream_entry; + bool changed = false; + + for (i = 0 ; i < num_streams; i++) { + stream_id = streams[i].stream_id; + virtual_channel = streams[i].virtual_channel; + entry = sde_hdcp_2x_stream_present(hdcp, stream_id, + virtual_channel); + if (!entry) + continue; + + stream_entry = list_entry(entry, struct sde_hdcp_stream, + list); + + if (!stream_entry->stream_handle) { + /* Stream wasn't fully initialized so remove it */ + hdcp->stream_count--; + list_del(entry); + kzfree(stream_entry); + } else { + stream_entry->active = false; + } + changed = true; + } + + return changed; +} + +static bool sde_hdcp_2x_add_streams(struct sde_hdcp_2x_ctrl *hdcp, + struct stream_info *streams, u8 num_streams) +{ + u8 i; + u8 stream_id; + u8 virtual_channel; + struct sde_hdcp_stream *stream; + bool changed = false; + + for (i = 0 ; i < num_streams; i++) { + stream_id = streams[i].stream_id; + virtual_channel = streams[i].virtual_channel; + + if (sde_hdcp_2x_stream_present(hdcp, stream_id, + virtual_channel)) + continue; + + stream = kzalloc(sizeof(struct sde_hdcp_stream), GFP_KERNEL); + if (!stream) + continue; + + INIT_LIST_HEAD(&stream->list); + stream->stream_handle = 0; + stream->stream_id = stream_id; + stream->virtual_channel = virtual_channel; + stream->active = true; + + list_add(&stream->list, &hdcp->stream_handles); + hdcp->stream_count++; + changed = true; + } + + return changed; +} + + +/** sde_hdcp_2x_wakeup() - wakeup the module to execute a requested command + * @data: data required for executing corresponding command. + * + * This function is executed on caller's thread. Update the local data + * and wakeup the local thread to execute the command. Once the local + * thread is activated, caller's thread is returned and this function + * is ready to receive next command. + */ +static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data) +{ + struct sde_hdcp_2x_ctrl *hdcp; + int rc = 0; + + if (!data) + return -EINVAL; + + hdcp = data->context; + if (!hdcp) + return -EINVAL; + + hdcp->timeout_left = data->timeout; + hdcp->total_message_length = data->total_message_length; + + if (!completion_done(&hdcp->response_completion)) + complete_all(&hdcp->response_completion); + + switch (data->cmd) { + case HDCP_2X_CMD_ENABLE: + if (!atomic_cmpxchg(&hdcp->enable_pending, 0, 1)) { + hdcp->device_type = data->device_type; + kfifo_put(&hdcp->cmd_q, data->cmd); + kthread_unpark(hdcp->thread); + wake_up(&hdcp->wait_q); + } + break; + case HDCP_2X_CMD_DISABLE: + if (!atomic_xchg(&hdcp->hdcp_off, 1)) + kfifo_put(&hdcp->cmd_q, HDCP_2X_CMD_STOP); + kfifo_put(&hdcp->cmd_q, data->cmd); + kthread_park(hdcp->thread); + break; + case HDCP_2X_CMD_STOP: + atomic_set(&hdcp->hdcp_off, 1); + + kfifo_put(&hdcp->cmd_q, data->cmd); + kthread_park(hdcp->thread); + break; + case HDCP_2X_CMD_START: + hdcp->no_stored_km = false; + hdcp->repeater_flag = false; + hdcp->update_stream = false; + hdcp->authenticated = false; + hdcp->last_msg = INVALID_MESSAGE; + hdcp->timeout_left = 0; + atomic_set(&hdcp->hdcp_off, 0); + + kfifo_put(&hdcp->cmd_q, data->cmd); + kthread_unpark(hdcp->thread); + wake_up(&hdcp->wait_q); + break; + case HDCP_2X_CMD_OPEN_STREAMS: + if (sde_hdcp_2x_add_streams(hdcp, data->streams, + data->num_streams)) { + kfifo_put(&hdcp->cmd_q, data->cmd); + wake_up(&hdcp->wait_q); + } + break; + case HDCP_2X_CMD_CLOSE_STREAMS: + if (sde_hdcp_2x_remove_streams(hdcp, data->streams, + data->num_streams)) { + kfifo_put(&hdcp->cmd_q, data->cmd); + wake_up(&hdcp->wait_q); + } + break; + case HDCP_2X_CMD_MIN_ENC_LEVEL: + hdcp->min_enc_level = data->min_enc_level; + if (hdcp->authenticated) { + kfifo_put(&hdcp->cmd_q, data->cmd); + wake_up(&hdcp->wait_q); + } + break; + default: + kfifo_put(&hdcp->cmd_q, data->cmd); + wake_up(&hdcp->wait_q); + break; + } + + return rc; +} + +static void sde_hdcp_2x_enable(struct sde_hdcp_2x_ctrl *hdcp) +{ + if (!hdcp) + return; + + if (hdcp->hdcp2_ctx) { + pr_debug("HDCP library context already acquired\n"); + return; + } + + hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type); + if (!hdcp->hdcp2_ctx) + pr_err("Unable to acquire HDCP library handle\n"); +} + +static void sde_hdcp_2x_disable(struct sde_hdcp_2x_ctrl *hdcp) +{ + if (!hdcp->hdcp2_ctx) + return; + + hdcp2_deinit(hdcp->hdcp2_ctx); + hdcp->hdcp2_ctx = NULL; +} + +static int sde_hdcp_2x_main(void *data) +{ + struct sde_hdcp_2x_ctrl *hdcp = data; + enum sde_hdcp_2x_wakeup_cmd cmd; + + while (1) { + wait_event(hdcp->wait_q, + !kfifo_is_empty(&hdcp->cmd_q) || + kthread_should_stop() || + kthread_should_park()); + + if (kthread_should_stop()) + break; + + if (kfifo_is_empty(&hdcp->cmd_q) && kthread_should_park()) { + kthread_parkme(); + continue; + } + + if (!kfifo_get(&hdcp->cmd_q, &cmd)) + continue; + + switch (cmd) { + case HDCP_2X_CMD_ENABLE: + sde_hdcp_2x_enable(hdcp); + atomic_set(&hdcp->enable_pending, 0); + break; + case HDCP_2X_CMD_DISABLE: + sde_hdcp_2x_disable(hdcp); + break; + case HDCP_2X_CMD_START: + sde_hdcp_2x_init(hdcp); + break; + case HDCP_2X_CMD_STOP: + sde_hdcp_2x_clean(hdcp); + break; + case HDCP_2X_CMD_START_AUTH: + sde_hdcp_2x_start_auth(hdcp); + break; + case HDCP_2X_CMD_MSG_SEND_SUCCESS: + sde_hdcp_2x_msg_sent(hdcp); + break; + case HDCP_2X_CMD_MSG_SEND_FAILED: + case HDCP_2X_CMD_MSG_RECV_FAILED: + case HDCP_2X_CMD_LINK_FAILED: + sde_hdcp_2x_clean(hdcp); + break; + case HDCP_2X_CMD_MSG_RECV_SUCCESS: + sde_hdcp_2x_msg_recvd(hdcp); + break; + case HDCP_2X_CMD_MSG_RECV_TIMEOUT: + sde_hdcp_2x_timeout(hdcp); + break; + case HDCP_2X_CMD_QUERY_STREAM_TYPE: + sde_hdcp_2x_query_stream(hdcp); + break; + case HDCP_2X_CMD_MIN_ENC_LEVEL: + if (!hdcp->repeater_flag) { + sde_hdcp_2x_send_type(hdcp); + break; + } + sde_hdcp_2x_query_stream(hdcp); + break; + case HDCP_2X_CMD_OPEN_STREAMS: + case HDCP_2X_CMD_CLOSE_STREAMS: + sde_hdcp_2x_manage_stream(hdcp); + break; + default: + break; + } + } + + return 0; +} + +int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data) +{ + int rc = 0; + struct sde_hdcp_2x_ctrl *hdcp = NULL; + + if (!data) { + pr_err("invalid input\n"); + return -EINVAL; + } + + if (!data->ops) { + pr_err("invalid input: txmtr context\n"); + return -EINVAL; + } + + if (!data->client_ops) { + pr_err("invalid input: client_ops\n"); + return -EINVAL; + } + + if (!data->hdcp_data) { + pr_err("invalid input: hdcp_data\n"); + return -EINVAL; + } + + /* populate ops to be called by client */ + data->ops->feature_supported = sde_hdcp_2x_client_feature_supported; + data->ops->wakeup = sde_hdcp_2x_wakeup; + data->ops->force_encryption = sde_hdcp_2x_force_encryption; + + hdcp = kzalloc(sizeof(*hdcp), GFP_KERNEL); + if (!hdcp) { + rc = -ENOMEM; + goto unlock; + } + + INIT_LIST_HEAD(&hdcp->stream_handles); + hdcp->client_data = data->client_data; + hdcp->client_ops = data->client_ops; + + INIT_KFIFO(hdcp->cmd_q); + + init_waitqueue_head(&hdcp->wait_q); + atomic_set(&hdcp->hdcp_off, 1); + atomic_set(&hdcp->enable_pending, 0); + + init_completion(&hdcp->response_completion); + + *data->hdcp_data = hdcp; + + hdcp->thread = kthread_run(sde_hdcp_2x_main, hdcp, "hdcp_2x"); + + if (IS_ERR(hdcp->thread)) { + pr_err("unable to start lib thread\n"); + rc = PTR_ERR(hdcp->thread); + hdcp->thread = NULL; + goto error; + } + + hdcp->force_encryption = false; + + return 0; +error: + kzfree(hdcp); + hdcp = NULL; +unlock: + return rc; +} + +void sde_hdcp_2x_deregister(void *data) +{ + struct sde_hdcp_2x_ctrl *hdcp = data; + + if (!hdcp) + return; + + kthread_stop(hdcp->thread); + sde_hdcp_2x_disable(data); + kzfree(hdcp); +} diff --git a/techpack/display/msm/sde_hdcp_2x.h b/techpack/display/msm/sde_hdcp_2x.h new file mode 100644 index 0000000000000000000000000000000000000000..3a525aefc39377a6c3d2dc6a3085d67810a4ef71 --- /dev/null +++ b/techpack/display/msm/sde_hdcp_2x.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_HDCP_2X_H__ +#define __SDE_HDCP_2X_H__ + +#include "sde_hdcp.h" + +#define TO_STR(x) #x + +#define HDCP_MAX_MESSAGE_PARTS 4 + +/** + * enum sde_hdcp_2x_wakeup_cmd - commands for interacting with HDCP driver + * @HDCP_2X_CMD_INVALID: initialization value + * @HDCP_2X_CMD_START: start HDCP driver + * @HDCP_2X_CMD_START_AUTH: start authentication + * @HDCP_2X_CMD_STOP: stop HDCP driver + * @HDCP_2X_CMD_MSG_SEND_SUCCESS: sending message to sink succeeded + * @HDCP_2X_CMD_MSG_SEND_FAILED: sending message to sink failed + * @HDCP_2X_CMD_MSG_SEND_TIMEOUT: sending message to sink timed out + * @HDCP_2X_CMD_MSG_RECV_SUCCESS: receiving message from sink succeeded + * @HDCP_2X_CMD_MSG_RECV_FAILED: receiving message from sink failed + * @HDCP_2X_CMD_MSG_RECV_TIMEOUT: receiving message from sink timed out + * @HDCP_2X_CMD_QUERY_STREAM_TYPE: start content stream processing + * @HDCP_2X_CMD_LINK_FAILED: link failure notification + * @HDCP_2X_CMD_MIN_ENC_LEVEL: trigger minimum encryption level change + * @HDCP_2X_CMD_OPEN_STREAMS: open a virtual channel + * @HDCP_2X_CMD_CLOSE_STREAMS: close a virtual channel + */ +enum sde_hdcp_2x_wakeup_cmd { + HDCP_2X_CMD_INVALID, + HDCP_2X_CMD_ENABLE, + HDCP_2X_CMD_DISABLE, + HDCP_2X_CMD_START, + HDCP_2X_CMD_START_AUTH, + HDCP_2X_CMD_STOP, + HDCP_2X_CMD_MSG_SEND_SUCCESS, + HDCP_2X_CMD_MSG_SEND_FAILED, + HDCP_2X_CMD_MSG_SEND_TIMEOUT, + HDCP_2X_CMD_MSG_RECV_SUCCESS, + HDCP_2X_CMD_MSG_RECV_FAILED, + HDCP_2X_CMD_MSG_RECV_TIMEOUT, + HDCP_2X_CMD_QUERY_STREAM_TYPE, + HDCP_2X_CMD_LINK_FAILED, + HDCP_2X_CMD_MIN_ENC_LEVEL, + HDCP_2X_CMD_OPEN_STREAMS, + HDCP_2X_CMD_CLOSE_STREAMS, +}; + +/** + * enum hdcp_transport_wakeup_cmd - commands to instruct display transport layer + * @HDCP_TRANSPORT_CMD_INVALID: initialization value + * @HDCP_TRANSPORT_CMD_SEND_MESSAGE: send message to sink + * @HDCP_TRANSPORT_CMD_RECV_MESSAGE: receive message from sink + * @HDCP_TRANSPORT_CMD_STATUS_SUCCESS: successfully communicated with TrustZone + * @HDCP_TRANSPORT_CMD_STATUS_FAILED: failed to communicate with TrustZone + * @HDCP_TRANSPORT_CMD_LINK_POLL: poll the HDCP link + * @HDCP_TRANSPORT_CMD_LINK_CHECK: check link status in response to cp_irq + * @HDCP_TRANSPORT_CMD_AUTHENTICATE: start authentication + */ +enum hdcp_transport_wakeup_cmd { + HDCP_TRANSPORT_CMD_INVALID, + HDCP_TRANSPORT_CMD_SEND_MESSAGE, + HDCP_TRANSPORT_CMD_RECV_MESSAGE, + HDCP_TRANSPORT_CMD_STATUS_SUCCESS, + HDCP_TRANSPORT_CMD_STATUS_FAILED, + HDCP_TRANSPORT_CMD_LINK_POLL, + HDCP_TRANSPORT_CMD_LINK_CHECK, + HDCP_TRANSPORT_CMD_AUTHENTICATE, +}; + +enum sde_hdcp_2x_device_type { + HDCP_TXMTR_HDMI = 0x8001, + HDCP_TXMTR_DP = 0x8002, + HDCP_TXMTR_DP_MST = 0x8003 +}; + +/** + * struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver + * @cmd: command type + * @device_type type of device in use by the HDCP driver + * @context: void pointer to the HDCP driver instance + * @buf: message received from the sink + * @buf_len: length of message received from the sink + * @timeout: time out value for timed transactions + * @streams: list indicating which streams need adjustment + * @num_streams: number of entries in streams + */ +struct sde_hdcp_2x_wakeup_data { + enum sde_hdcp_2x_wakeup_cmd cmd; + enum sde_hdcp_2x_device_type device_type; + void *context; + uint32_t total_message_length; + uint32_t timeout; + u8 min_enc_level; + struct stream_info *streams; + u8 num_streams; +}; + +/** + * struct sde_hdcp_2x_msg_part - a single part of an HDCP 2.2 message + * @name: user readable message name + * @offset: message part offset + * @length message part length + */ +struct sde_hdcp_2x_msg_part { + char *name; + uint32_t offset; + uint32_t length; +}; + +/** + * struct sde_hdcp_2x_msg_data - HDCP 2.2 message containing one or more parts + * @num_messages: total number of parts in a full message + * @messages: array containing num_messages parts + * @rx_status: value of rx_status register + * @transaction_timeout: maximum duration to read/write message from/to sink + */ +struct sde_hdcp_2x_msg_data { + uint32_t num_messages; + struct sde_hdcp_2x_msg_part messages[HDCP_MAX_MESSAGE_PARTS]; + uint8_t rx_status; + uint32_t transaction_timeout; +}; + +/** + * struct hdcp_transport_wakeup_data - data sent to display transport layer + * @cmd: command type + * @context: void pointer to the display transport layer + * @send_msg_buf: buffer containing message to be sent to sink + * @send_msg_len: length of the message to be sent to sink + * @timeout: timeout value for timed transactions + * @abort_mask: mask used to determine whether HDCP link is valid + * @message_data: a pointer to the message description + * @transaction_delay: amount of time to delay before performing transaction + * @transaction_timeout: maximum duration to read/write message from/to sink + */ +struct hdcp_transport_wakeup_data { + enum hdcp_transport_wakeup_cmd cmd; + void *context; + unsigned char *buf; + u32 buf_len; + u32 transaction_delay; + u32 transaction_timeout; + u8 abort_mask; + const struct sde_hdcp_2x_msg_data *message_data; +}; + +static inline const char *sde_hdcp_2x_cmd_to_str( + enum sde_hdcp_2x_wakeup_cmd cmd) +{ + switch (cmd) { + case HDCP_2X_CMD_START: + return TO_STR(HDCP_2X_CMD_START); + case HDCP_2X_CMD_STOP: + return TO_STR(HDCP_2X_CMD_STOP); + case HDCP_2X_CMD_MSG_SEND_SUCCESS: + return TO_STR(HDCP_2X_CMD_MSG_SEND_SUCCESS); + case HDCP_2X_CMD_MSG_SEND_FAILED: + return TO_STR(HDCP_2X_CMD_MSG_SEND_FAILED); + case HDCP_2X_CMD_MSG_SEND_TIMEOUT: + return TO_STR(HDCP_2X_CMD_MSG_SEND_TIMEOUT); + case HDCP_2X_CMD_MSG_RECV_SUCCESS: + return TO_STR(HDCP_2X_CMD_MSG_RECV_SUCCESS); + case HDCP_2X_CMD_MSG_RECV_FAILED: + return TO_STR(HDCP_2X_CMD_MSG_RECV_FAILED); + case HDCP_2X_CMD_MSG_RECV_TIMEOUT: + return TO_STR(HDCP_2X_CMD_MSG_RECV_TIMEOUT); + case HDCP_2X_CMD_QUERY_STREAM_TYPE: + return TO_STR(HDCP_2X_CMD_QUERY_STREAM_TYPE); + case HDCP_2X_CMD_OPEN_STREAMS: + return TO_STR(HDCP_2X_CMD_OPEN_STREAMS); + case HDCP_2X_CMD_CLOSE_STREAMS: + return TO_STR(HDCP_2X_CMD_CLOSE_STREAMS); + default: + return "UNKNOWN"; + } +} + +static inline const char *hdcp_transport_cmd_to_str( + enum hdcp_transport_wakeup_cmd cmd) +{ + switch (cmd) { + case HDCP_TRANSPORT_CMD_SEND_MESSAGE: + return TO_STR(HDCP_TRANSPORT_CMD_SEND_MESSAGE); + case HDCP_TRANSPORT_CMD_RECV_MESSAGE: + return TO_STR(HDCP_TRANSPORT_CMD_RECV_MESSAGE); + case HDCP_TRANSPORT_CMD_STATUS_SUCCESS: + return TO_STR(HDCP_TRANSPORT_CMD_STATUS_SUCCESS); + case HDCP_TRANSPORT_CMD_STATUS_FAILED: + return TO_STR(HDCP_TRANSPORT_CMD_STATUS_FAILED); + case HDCP_TRANSPORT_CMD_LINK_POLL: + return TO_STR(HDCP_TRANSPORT_CMD_LINK_POLL); + case HDCP_TRANSPORT_CMD_AUTHENTICATE: + return TO_STR(HDCP_TRANSPORT_CMD_AUTHENTICATE); + default: + return "UNKNOWN"; + } +} + +struct sde_hdcp_2x_ops { + int (*wakeup)(struct sde_hdcp_2x_wakeup_data *data); + bool (*feature_supported)(void *data); + void (*force_encryption)(void *data, bool enable); +}; + +struct hdcp_transport_ops { + int (*wakeup)(struct hdcp_transport_wakeup_data *data); +}; + +struct sde_hdcp_2x_register_data { + struct hdcp_transport_ops *client_ops; + struct sde_hdcp_2x_ops *ops; + void *client_data; + void **hdcp_data; +}; + +/* functions for the HDCP 2.2 state machine module */ +int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data); +void sde_hdcp_2x_deregister(void *data); +#endif diff --git a/techpack/display/msm/sde_io_util.c b/techpack/display/msm/sde_io_util.c new file mode 100644 index 0000000000000000000000000000000000000000..09649c59819a7bda5e20de9bd09c6415628caf77 --- /dev/null +++ b/techpack/display/msm/sde_io_util.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2015, 2017-2019 The Linux Foundation. All rights reserved. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> +#include <linux/sde_io_util.h> + +#define MAX_I2C_CMDS 16 +void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug) +{ + u32 in_val; + + if (!io || !io->base) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + if (offset > io->len) { + DEV_ERR("%pS->%s: offset out of range\n", + __builtin_return_address(0), __func__); + return; + } + + writel_relaxed(value, io->base + offset); + if (debug) { + in_val = readl_relaxed(io->base + offset); + DEV_DBG("[%08x] => %08x [%08x]\n", + (u32)(unsigned long)(io->base + offset), + value, in_val); + } +} /* dss_reg_w */ +EXPORT_SYMBOL(dss_reg_w); + +u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug) +{ + u32 value; + + if (!io || !io->base) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + if (offset > io->len) { + DEV_ERR("%pS->%s: offset out of range\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + value = readl_relaxed(io->base + offset); + if (debug) + DEV_DBG("[%08x] <= %08x\n", + (u32)(unsigned long)(io->base + offset), value); + + return value; +} /* dss_reg_r */ +EXPORT_SYMBOL(dss_reg_r); + +void dss_reg_dump(void __iomem *base, u32 length, const char *prefix, + u32 debug) +{ + if (debug) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, + (void *)base, length, false); +} /* dss_reg_dump */ +EXPORT_SYMBOL(dss_reg_dump); + +static struct resource *msm_dss_get_res_byname(struct platform_device *pdev, + unsigned int type, const char *name) +{ + struct resource *res = NULL; + + res = platform_get_resource_byname(pdev, type, name); + if (!res) + DEV_ERR("%s: '%s' resource not found\n", __func__, name); + + return res; +} /* msm_dss_get_res_byname */ +EXPORT_SYMBOL(msm_dss_get_res_byname); + +int msm_dss_ioremap_byname(struct platform_device *pdev, + struct dss_io_data *io_data, const char *name) +{ + struct resource *res = NULL; + + if (!pdev || !io_data) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + res = msm_dss_get_res_byname(pdev, IORESOURCE_MEM, name); + if (!res) { + DEV_ERR("%pS->%s: '%s' msm_dss_get_res_byname failed\n", + __builtin_return_address(0), __func__, name); + return -ENODEV; + } + + io_data->len = (u32)resource_size(res); + io_data->base = ioremap(res->start, io_data->len); + if (!io_data->base) { + DEV_ERR("%pS->%s: '%s' ioremap failed\n", + __builtin_return_address(0), __func__, name); + return -EIO; + } + + return 0; +} /* msm_dss_ioremap_byname */ +EXPORT_SYMBOL(msm_dss_ioremap_byname); + +void msm_dss_iounmap(struct dss_io_data *io_data) +{ + if (!io_data) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + if (io_data->base) { + iounmap(io_data->base); + io_data->base = NULL; + } + io_data->len = 0; +} /* msm_dss_iounmap */ +EXPORT_SYMBOL(msm_dss_iounmap); + +int msm_dss_config_vreg(struct device *dev, struct dss_vreg *in_vreg, + int num_vreg, int config) +{ + int i = 0, rc = 0; + struct dss_vreg *curr_vreg = NULL; + enum dss_vreg_type type; + + if (!in_vreg || !num_vreg) + return rc; + + if (config) { + for (i = 0; i < num_vreg; i++) { + curr_vreg = &in_vreg[i]; + curr_vreg->vreg = regulator_get(dev, + curr_vreg->vreg_name); + rc = PTR_RET(curr_vreg->vreg); + if (rc) { + DEV_ERR("%pS->%s: %s get failed. rc=%d\n", + __builtin_return_address(0), __func__, + curr_vreg->vreg_name, rc); + curr_vreg->vreg = NULL; + goto vreg_get_fail; + } + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? DSS_REG_LDO : DSS_REG_VS; + if (type == DSS_REG_LDO) { + rc = regulator_set_voltage( + curr_vreg->vreg, + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + DEV_ERR("%pS->%s: %s set vltg fail\n", + __builtin_return_address(0), + __func__, + curr_vreg->vreg_name); + goto vreg_set_voltage_fail; + } + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + if (curr_vreg->vreg) { + type = (regulator_count_voltages( + curr_vreg->vreg) > 0) + ? DSS_REG_LDO : DSS_REG_VS; + if (type == DSS_REG_LDO) { + regulator_set_voltage(curr_vreg->vreg, + 0, curr_vreg->max_voltage); + } + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (type == DSS_REG_LDO) + regulator_set_load(curr_vreg->vreg, 0); + +vreg_set_voltage_fail: + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? DSS_REG_LDO : DSS_REG_VS; + goto vreg_unconfig; + } + return rc; +} /* msm_dss_config_vreg */ +EXPORT_SYMBOL(msm_dss_config_vreg); + +static bool msm_dss_is_hw_controlled(struct dss_vreg in_vreg) +{ + u32 mode = 0; + char const *regulator_gdsc = "gdsc"; + + /* + * For gdsc-regulator devices only, REGULATOR_MODE_FAST specifies that + * the GDSC is in HW controlled mode. + */ + mode = regulator_get_mode(in_vreg.vreg); + if (!strcmp(regulator_gdsc, in_vreg.vreg_name) && + mode == REGULATOR_MODE_FAST) { + DEV_DBG("%pS->%s: %s is HW controlled\n", + __builtin_return_address(0), __func__, + in_vreg.vreg_name); + return true; + } + + return false; +} + +int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) +{ + int i = 0, rc = 0; + bool need_sleep; + + if (enable) { + for (i = 0; i < num_vreg; i++) { + rc = PTR_RET(in_vreg[i].vreg); + if (rc) { + DEV_ERR("%pS->%s: %s regulator error. rc=%d\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name, rc); + goto vreg_set_opt_mode_fail; + } + if (msm_dss_is_hw_controlled(in_vreg[i])) + continue; + + need_sleep = !regulator_is_enabled(in_vreg[i].vreg); + if (in_vreg[i].pre_on_sleep && need_sleep) + usleep_range(in_vreg[i].pre_on_sleep * 1000, + (in_vreg[i].pre_on_sleep * 1000) + 10); + rc = regulator_set_load(in_vreg[i].vreg, + in_vreg[i].enable_load); + if (rc < 0) { + DEV_ERR("%pS->%s: %s set opt m fail\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + goto vreg_set_opt_mode_fail; + } + rc = regulator_enable(in_vreg[i].vreg); + if (in_vreg[i].post_on_sleep && need_sleep) + usleep_range(in_vreg[i].post_on_sleep * 1000, + (in_vreg[i].post_on_sleep * 1000) + 10); + if (rc < 0) { + DEV_ERR("%pS->%s: %s enable failed\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + goto disable_vreg; + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + if (msm_dss_is_hw_controlled(in_vreg[i])) + continue; + + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + (in_vreg[i].pre_off_sleep * 1000) + 10); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + (in_vreg[i].post_off_sleep * 1000) + 10); + } + } + return rc; + +disable_vreg: + regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); + +vreg_set_opt_mode_fail: + for (i--; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + (in_vreg[i].pre_off_sleep * 1000) + 10); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + (in_vreg[i].post_off_sleep * 1000) + 10); + } + + return rc; +} /* msm_dss_enable_vreg */ +EXPORT_SYMBOL(msm_dss_enable_vreg); + +int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable) +{ + int i = 0, rc = 0; + + if (enable) { + for (i = 0; i < num_gpio; i++) { + DEV_DBG("%pS->%s: %s enable\n", + __builtin_return_address(0), __func__, + in_gpio[i].gpio_name); + + rc = gpio_request(in_gpio[i].gpio, + in_gpio[i].gpio_name); + if (rc < 0) { + DEV_ERR("%pS->%s: %s enable failed\n", + __builtin_return_address(0), __func__, + in_gpio[i].gpio_name); + goto disable_gpio; + } + gpio_set_value(in_gpio[i].gpio, in_gpio[i].value); + } + } else { + for (i = num_gpio-1; i >= 0; i--) { + DEV_DBG("%pS->%s: %s disable\n", + __builtin_return_address(0), __func__, + in_gpio[i].gpio_name); + if (in_gpio[i].gpio) + gpio_free(in_gpio[i].gpio); + } + } + return rc; + +disable_gpio: + for (i--; i >= 0; i--) + if (in_gpio[i].gpio) + gpio_free(in_gpio[i].gpio); + + return rc; +} /* msm_dss_enable_gpio */ +EXPORT_SYMBOL(msm_dss_enable_gpio); + +void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk) +{ + int i; + + for (i = num_clk - 1; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } +} /* msm_dss_put_clk */ +EXPORT_SYMBOL(msm_dss_put_clk); + +int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name); + rc = PTR_RET(clk_arry[i].clk); + if (rc) { + DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, rc); + goto error; + } + } + + return rc; + +error: + for (i--; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } + + return rc; +} /* msm_dss_get_clk */ +EXPORT_SYMBOL(msm_dss_get_clk); + +int msm_dss_single_clk_set_rate(struct dss_clk *clk) +{ + int rc = 0; + + if (!clk) { + DEV_ERR("invalid clk struct\n"); + return -EINVAL; + } + + DEV_DBG("%pS->%s: set_rate '%s'\n", + __builtin_return_address(0), __func__, + clk->clk_name); + + if (clk->type != DSS_CLK_AHB) { + rc = clk_set_rate(clk->clk, clk->rate); + if (rc) + DEV_ERR("%pS->%s: %s failed. rc=%d\n", + __builtin_return_address(0), + __func__, + clk->clk_name, rc); + } + + return rc; +} /* msm_dss_single_clk_set_rate */ +EXPORT_SYMBOL(msm_dss_single_clk_set_rate); + +int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + for (i = 0; i < num_clk; i++) { + if (clk_arry[i].clk) { + rc = msm_dss_single_clk_set_rate(&clk_arry[i]); + if (rc) + break; + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + break; + } + } + + return rc; +} /* msm_dss_clk_set_rate */ +EXPORT_SYMBOL(msm_dss_clk_set_rate); + +int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable) +{ + int i, rc = 0; + + if (enable) { + for (i = 0; i < num_clk; i++) { + DEV_DBG("%pS->%s: enable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + if (clk_arry[i].clk) { + rc = clk_prepare_enable(clk_arry[i].clk); + if (rc) + DEV_ERR("%pS->%s: %s en fail. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + } + + if (rc) { + msm_dss_enable_clk(clk_arry, i, false); + break; + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + DEV_DBG("%pS->%s: disable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + + if (clk_arry[i].clk) + clk_disable_unprepare(clk_arry[i].clk); + else + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + } + } + + return rc; +} /* msm_dss_enable_clk */ +EXPORT_SYMBOL(msm_dss_enable_clk); + + +int sde_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr, + uint8_t reg_offset, uint8_t *read_buf) +{ + struct i2c_msg msgs[2]; + int ret = -1; + + pr_debug("%s: reading from slave_addr=[%x] and offset=[%x]\n", + __func__, slave_addr, reg_offset); + + msgs[0].addr = slave_addr >> 1; + msgs[0].flags = 0; + msgs[0].buf = ®_offset; + msgs[0].len = 1; + + msgs[1].addr = slave_addr >> 1; + msgs[1].flags = I2C_M_RD; + msgs[1].buf = read_buf; + msgs[1].len = 1; + + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 1) { + pr_err("%s: I2C READ FAILED=[%d]\n", __func__, ret); + return -EACCES; + } + pr_debug("%s: i2c buf is [%x]\n", __func__, *read_buf); + return 0; +} +EXPORT_SYMBOL(sde_i2c_byte_read); + +int sde_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr, + uint8_t reg_offset, uint8_t *value) +{ + struct i2c_msg msgs[1]; + uint8_t data[2]; + int status = -EACCES; + + pr_debug("%s: writing from slave_addr=[%x] and offset=[%x]\n", + __func__, slave_addr, reg_offset); + + data[0] = reg_offset; + data[1] = *value; + + msgs[0].addr = slave_addr >> 1; + msgs[0].flags = 0; + msgs[0].len = 2; + msgs[0].buf = data; + + status = i2c_transfer(client->adapter, msgs, 1); + if (status < 1) { + pr_err("I2C WRITE FAILED=[%d]\n", status); + return -EACCES; + } + pr_debug("%s: I2C write status=%x\n", __func__, status); + return status; +} +EXPORT_SYMBOL(sde_i2c_byte_write); diff --git a/techpack/display/msm/sde_power_handle.c b/techpack/display/msm/sde_power_handle.c new file mode 100644 index 0000000000000000000000000000000000000000..9f66039966d5b2deaf815b64110185f828437521 --- /dev/null +++ b/techpack/display/msm/sde_power_handle.c @@ -0,0 +1,1035 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[drm:%s:%d]: " fmt, __func__, __LINE__ + +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/string.h> +#include <linux/of_address.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/of_platform.h> + +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#include <linux/sde_io_util.h> +#include <linux/sde_rsc.h> + +#include "sde_power_handle.h" +#include "sde_trace.h" +#include "sde_dbg.h" + +static const char *data_bus_name[SDE_POWER_HANDLE_DBUS_ID_MAX] = { + [SDE_POWER_HANDLE_DBUS_ID_MNOC] = "qcom,sde-data-bus", + [SDE_POWER_HANDLE_DBUS_ID_LLCC] = "qcom,sde-llcc-bus", + [SDE_POWER_HANDLE_DBUS_ID_EBI] = "qcom,sde-ebi-bus", +}; + +const char *sde_power_handle_get_dbus_name(u32 bus_id) +{ + if (bus_id < SDE_POWER_HANDLE_DBUS_ID_MAX) + return data_bus_name[bus_id]; + + return NULL; +} + +static void sde_power_event_trigger_locked(struct sde_power_handle *phandle, + u32 event_type) +{ + struct sde_power_event *event; + + phandle->last_event_handled = event_type; + list_for_each_entry(event, &phandle->event_list, list) { + if (event->event_type & event_type) { + event->cb_fnc(event_type, event->usr); + } + } +} + +static inline void sde_power_rsc_client_init(struct sde_power_handle *phandle) +{ + /* creates the rsc client */ + if (!phandle->rsc_client_init) { + phandle->rsc_client = sde_rsc_client_create(SDE_RSC_INDEX, + "sde_power_handle", SDE_RSC_CLK_CLIENT, 0); + if (IS_ERR_OR_NULL(phandle->rsc_client)) { + pr_debug("sde rsc client create failed :%ld\n", + PTR_ERR(phandle->rsc_client)); + phandle->rsc_client = NULL; + } + phandle->rsc_client_init = true; + } +} + +static int sde_power_rsc_update(struct sde_power_handle *phandle, bool enable) +{ + u32 rsc_state; + int ret = 0; + + rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE; + + if (phandle->rsc_client) + ret = sde_rsc_client_state_update(phandle->rsc_client, + rsc_state, NULL, SDE_RSC_INVALID_CRTC_ID, NULL); + + return ret; +} + +static int sde_power_parse_dt_supply(struct platform_device *pdev, + struct dss_module_power *mp) +{ + int i = 0, rc = 0; + u32 tmp = 0; + struct device_node *of_node = NULL, *supply_root_node = NULL; + struct device_node *supply_node = NULL; + + if (!pdev || !mp) { + pr_err("invalid input param pdev:%pK mp:%pK\n", pdev, mp); + return -EINVAL; + } + + of_node = pdev->dev.of_node; + + mp->num_vreg = 0; + supply_root_node = of_get_child_by_name(of_node, + "qcom,platform-supply-entries"); + if (!supply_root_node) { + pr_debug("no supply entry present\n"); + return rc; + } + + for_each_child_of_node(supply_root_node, supply_node) + mp->num_vreg++; + + if (mp->num_vreg == 0) { + pr_debug("no vreg\n"); + return rc; + } + + pr_debug("vreg found. count=%d\n", mp->num_vreg); + mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct dss_vreg) * + mp->num_vreg, GFP_KERNEL); + if (!mp->vreg_config) { + rc = -ENOMEM; + return rc; + } + + for_each_child_of_node(supply_root_node, supply_node) { + + const char *st = NULL; + + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + pr_err("error reading name. rc=%d\n", rc); + goto error; + } + + strlcpy(mp->vreg_config[i].vreg_name, st, + sizeof(mp->vreg_config[i].vreg_name)); + + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + pr_err("error reading min volt. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].min_voltage = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + pr_err("error reading max volt. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].max_voltage = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + pr_err("error reading enable load. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].enable_load = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + pr_err("error reading disable load. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].disable_load = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-on-sleep", &tmp); + if (rc) + pr_debug("error reading supply pre sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-off-sleep", &tmp); + if (rc) + pr_debug("error reading supply pre sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-on-sleep", &tmp); + if (rc) + pr_debug("error reading supply post sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-off-sleep", &tmp); + if (rc) + pr_debug("error reading supply post sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0); + + pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n", + mp->vreg_config[i].vreg_name, + mp->vreg_config[i].min_voltage, + mp->vreg_config[i].max_voltage, + mp->vreg_config[i].enable_load, + mp->vreg_config[i].disable_load, + mp->vreg_config[i].pre_on_sleep, + mp->vreg_config[i].post_on_sleep, + mp->vreg_config[i].pre_off_sleep, + mp->vreg_config[i].post_off_sleep); + ++i; + + rc = 0; + } + + return rc; + +error: + if (mp->vreg_config) { + devm_kfree(&pdev->dev, mp->vreg_config); + mp->vreg_config = NULL; + mp->num_vreg = 0; + } + + return rc; +} + +static int sde_power_parse_dt_clock(struct platform_device *pdev, + struct dss_module_power *mp) +{ + u32 i = 0, rc = 0; + const char *clock_name; + u32 clock_rate = 0; + u32 clock_max_rate = 0; + int num_clk = 0; + + if (!pdev || !mp) { + pr_err("invalid input param pdev:%pK mp:%pK\n", pdev, mp); + return -EINVAL; + } + + mp->num_clk = 0; + num_clk = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if (num_clk <= 0) { + pr_debug("clocks are not defined\n"); + goto clk_err; + } + + mp->num_clk = num_clk; + mp->clk_config = devm_kzalloc(&pdev->dev, + sizeof(struct dss_clk) * num_clk, GFP_KERNEL); + if (!mp->clk_config) { + rc = -ENOMEM; + mp->num_clk = 0; + goto clk_err; + } + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(pdev->dev.of_node, "clock-names", + i, &clock_name); + strlcpy(mp->clk_config[i].clk_name, clock_name, + sizeof(mp->clk_config[i].clk_name)); + + of_property_read_u32_index(pdev->dev.of_node, "clock-rate", + i, &clock_rate); + mp->clk_config[i].rate = clock_rate; + + if (!clock_rate) + mp->clk_config[i].type = DSS_CLK_AHB; + else + mp->clk_config[i].type = DSS_CLK_PCLK; + + clock_max_rate = 0; + of_property_read_u32_index(pdev->dev.of_node, "clock-max-rate", + i, &clock_max_rate); + mp->clk_config[i].max_rate = clock_max_rate; + } + +clk_err: + return rc; +} + +#ifdef CONFIG_QCOM_BUS_SCALING + +#define MAX_AXI_PORT_COUNT 3 + +static int _sde_power_data_bus_set_quota( + struct sde_power_data_bus_handle *pdbus, + u64 in_ab_quota, u64 in_ib_quota) +{ + int new_uc_idx; + u64 ab_quota[MAX_AXI_PORT_COUNT] = {0, 0}; + u64 ib_quota[MAX_AXI_PORT_COUNT] = {0, 0}; + int rc; + + if (pdbus->data_bus_hdl < 1) { + pr_err("invalid bus handle %d\n", pdbus->data_bus_hdl); + return -EINVAL; + } + + if (!in_ab_quota && !in_ib_quota) { + new_uc_idx = 0; + } else { + int i; + struct msm_bus_vectors *vect = NULL; + struct msm_bus_scale_pdata *bw_table = + pdbus->data_bus_scale_table; + u32 total_data_paths_cnt = pdbus->data_paths_cnt; + + if (!bw_table || !total_data_paths_cnt || + total_data_paths_cnt > MAX_AXI_PORT_COUNT) { + pr_err("invalid input\n"); + return -EINVAL; + } + + ab_quota[0] = div_u64(in_ab_quota, total_data_paths_cnt); + ib_quota[0] = div_u64(in_ib_quota, total_data_paths_cnt); + + for (i = 1; i < total_data_paths_cnt; i++) { + ab_quota[i] = ab_quota[0]; + ib_quota[i] = ib_quota[0]; + } + + new_uc_idx = (pdbus->curr_bw_uc_idx % + (bw_table->num_usecases - 1)) + 1; + + for (i = 0; i < total_data_paths_cnt; i++) { + vect = &bw_table->usecase[new_uc_idx].vectors[i]; + vect->ab = ab_quota[i]; + vect->ib = ib_quota[i]; + + pr_debug( + "%s uc_idx=%d idx=%d ab=%llu ib=%llu\n", + bw_table->name, new_uc_idx, i, vect->ab, + vect->ib); + } + } + pdbus->curr_bw_uc_idx = new_uc_idx; + + SDE_ATRACE_BEGIN("msm_bus_scale_req"); + rc = msm_bus_scale_client_update_request(pdbus->data_bus_hdl, + new_uc_idx); + SDE_ATRACE_END("msm_bus_scale_req"); + + return rc; +} + +int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, + u32 bus_id, u64 ab_quota, u64 ib_quota) +{ + int rc = 0; + + if (!phandle || bus_id >= SDE_POWER_HANDLE_DBUS_ID_MAX) { + pr_err("invalid parameters\n"); + return -EINVAL; + } + + mutex_lock(&phandle->phandle_lock); + + trace_sde_perf_update_bus(bus_id, ab_quota, ib_quota); + + if (phandle->data_bus_handle[bus_id].data_bus_hdl) + rc = _sde_power_data_bus_set_quota( + &phandle->data_bus_handle[bus_id], ab_quota, ib_quota); + + mutex_unlock(&phandle->phandle_lock); + + return rc; +} + +static void sde_power_data_bus_unregister( + struct sde_power_data_bus_handle *pdbus) +{ + if (pdbus->data_bus_hdl) { + msm_bus_scale_unregister_client(pdbus->data_bus_hdl); + pdbus->data_bus_hdl = 0; + } +} + +static int sde_power_data_bus_parse(struct platform_device *pdev, + struct sde_power_data_bus_handle *pdbus, const char *name) +{ + struct device_node *node; + int rc = 0; + int paths; + + node = of_get_child_by_name(pdev->dev.of_node, name); + if (!node) + goto end; + + rc = of_property_read_u32(node, "qcom,msm-bus,num-paths", &paths); + if (rc) { + pr_err("Error. qcom,msm-bus,num-paths not found\n"); + return rc; + } + pdbus->data_paths_cnt = paths; + + pdbus->data_bus_scale_table = msm_bus_pdata_from_node(pdev, node); + if (IS_ERR_OR_NULL(pdbus->data_bus_scale_table)) { + pr_err("reg bus handle parsing failed\n"); + rc = PTR_ERR(pdbus->data_bus_scale_table); + if (!pdbus->data_bus_scale_table) + rc = -EINVAL; + goto end; + } + pdbus->data_bus_hdl = msm_bus_scale_register_client( + pdbus->data_bus_scale_table); + if (!pdbus->data_bus_hdl) { + pr_err("data_bus_client register failed\n"); + rc = -EINVAL; + goto end; + } + pr_debug("register %s data_bus_hdl=%x\n", name, pdbus->data_bus_hdl); + +end: + return rc; +} + +static int sde_power_reg_bus_parse(struct platform_device *pdev, + struct sde_power_handle *phandle) +{ + struct device_node *node; + struct msm_bus_scale_pdata *bus_scale_table; + int rc = 0; + + node = of_get_child_by_name(pdev->dev.of_node, "qcom,sde-reg-bus"); + if (node) { + bus_scale_table = msm_bus_pdata_from_node(pdev, node); + if (IS_ERR_OR_NULL(bus_scale_table)) { + pr_err("reg bus handle parsing failed\n"); + rc = PTR_ERR(bus_scale_table); + if (!bus_scale_table) + rc = -EINVAL; + goto end; + } + phandle->reg_bus_hdl = msm_bus_scale_register_client( + bus_scale_table); + if (!phandle->reg_bus_hdl) { + pr_err("reg_bus_client register failed\n"); + rc = -EINVAL; + goto end; + } + pr_debug("register reg_bus_hdl=%x\n", phandle->reg_bus_hdl); + } + +end: + return rc; +} + +static void sde_power_reg_bus_unregister(u32 reg_bus_hdl) +{ + if (reg_bus_hdl) + msm_bus_scale_unregister_client(reg_bus_hdl); +} + +static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) +{ + int rc = 0; + + if (reg_bus_hdl) { + SDE_ATRACE_BEGIN("msm_bus_scale_req"); + rc = msm_bus_scale_client_update_request(reg_bus_hdl, + usecase_ndx); + SDE_ATRACE_END("msm_bus_scale_req"); + } + + if (rc) + pr_err("failed to set reg bus vote rc=%d\n", rc); + + return rc; +} +#else +static int _sde_power_data_bus_set_quota( + struct sde_power_data_bus_handle *pdbus, + u64 in_ab_quota, u64 in_ib_quota) +{ + return 0; +} + +static int sde_power_data_bus_parse(struct platform_device *pdev, + struct sde_power_data_bus_handle *pdbus, const char *name) +{ + return 0; +} + +static void sde_power_data_bus_unregister( + struct sde_power_data_bus_handle *pdbus) +{ +} + +int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, + u32 bus_id, u64 ab_quota, u64 ib_quota) +{ + return 0; +} + +static int sde_power_reg_bus_parse(struct platform_device *pdev, + struct sde_power_handle *phandle) +{ + return 0; +} + +static void sde_power_reg_bus_unregister(u32 reg_bus_hdl) +{ +} + +static int sde_power_reg_bus_update(u32 reg_bus_hdl, u32 usecase_ndx) +{ + return 0; +} + +int sde_power_data_bus_state_update(struct sde_power_handle *phandle, + bool enable) +{ + return 0; +} +#endif + +int sde_power_resource_init(struct platform_device *pdev, + struct sde_power_handle *phandle) +{ + int rc = 0, i; + struct dss_module_power *mp; + + if (!phandle || !pdev) { + pr_err("invalid input param\n"); + rc = -EINVAL; + goto end; + } + mp = &phandle->mp; + phandle->dev = &pdev->dev; + + rc = sde_power_parse_dt_clock(pdev, mp); + if (rc) { + pr_err("device clock parsing failed\n"); + goto end; + } + + rc = sde_power_parse_dt_supply(pdev, mp); + if (rc) { + pr_err("device vreg supply parsing failed\n"); + goto parse_vreg_err; + } + + rc = msm_dss_config_vreg(&pdev->dev, + mp->vreg_config, mp->num_vreg, 1); + if (rc) { + pr_err("vreg config failed rc=%d\n", rc); + goto vreg_err; + } + + rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk); + if (rc) { + pr_err("clock get failed rc=%d\n", rc); + goto clk_err; + } + + rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); + if (rc) { + pr_err("clock set rate failed rc=%d\n", rc); + goto bus_err; + } + + rc = sde_power_reg_bus_parse(pdev, phandle); + if (rc) { + pr_err("register bus parse failed rc=%d\n", rc); + goto bus_err; + } + + for (i = SDE_POWER_HANDLE_DBUS_ID_MNOC; + i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + rc = sde_power_data_bus_parse(pdev, + &phandle->data_bus_handle[i], + data_bus_name[i]); + if (rc) { + pr_err("register data bus parse failed id=%d rc=%d\n", + i, rc); + goto data_bus_err; + } + } + + if (of_find_property(pdev->dev.of_node, "qcom,dss-cx-ipeak", NULL)) + phandle->dss_cx_ipeak = cx_ipeak_register(pdev->dev.of_node, + "qcom,dss-cx-ipeak"); + else + pr_debug("cx ipeak client parse failed\n"); + + INIT_LIST_HEAD(&phandle->event_list); + + phandle->rsc_client = NULL; + phandle->rsc_client_init = false; + + mutex_init(&phandle->phandle_lock); + mutex_init(&phandle->ext_client_lock); + + return rc; + +data_bus_err: + for (i--; i >= 0; i--) + sde_power_data_bus_unregister(&phandle->data_bus_handle[i]); + sde_power_reg_bus_unregister(phandle->reg_bus_hdl); +bus_err: + msm_dss_put_clk(mp->clk_config, mp->num_clk); +clk_err: + msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0); +vreg_err: + if (mp->vreg_config) + devm_kfree(&pdev->dev, mp->vreg_config); + mp->num_vreg = 0; +parse_vreg_err: + if (mp->clk_config) + devm_kfree(&pdev->dev, mp->clk_config); + mp->num_clk = 0; +end: + return rc; +} + +void sde_power_resource_deinit(struct platform_device *pdev, + struct sde_power_handle *phandle) +{ + struct dss_module_power *mp; + struct sde_power_event *curr_event, *next_event; + int i; + + if (!phandle || !pdev) { + pr_err("invalid input param\n"); + return; + } + mp = &phandle->mp; + + mutex_lock(&phandle->phandle_lock); + list_for_each_entry_safe(curr_event, next_event, + &phandle->event_list, list) { + pr_err("event:%d, client:%s still registered\n", + curr_event->event_type, + curr_event->client_name); + curr_event->active = false; + list_del(&curr_event->list); + } + mutex_unlock(&phandle->phandle_lock); + + if (phandle->dss_cx_ipeak) + cx_ipeak_unregister(phandle->dss_cx_ipeak); + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_unregister(&phandle->data_bus_handle[i]); + + sde_power_reg_bus_unregister(phandle->reg_bus_hdl); + + msm_dss_put_clk(mp->clk_config, mp->num_clk); + + msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0); + + if (mp->clk_config) + devm_kfree(&pdev->dev, mp->clk_config); + + if (mp->vreg_config) + devm_kfree(&pdev->dev, mp->vreg_config); + + mp->num_vreg = 0; + mp->num_clk = 0; + + if (phandle->rsc_client) + sde_rsc_client_destroy(phandle->rsc_client); +} + +int sde_power_scale_reg_bus(struct sde_power_handle *phandle, + u32 usecase_ndx, bool skip_lock) +{ + int rc = 0; + + if (!skip_lock) + mutex_lock(&phandle->phandle_lock); + + pr_debug("%pS: requested:%d\n", + __builtin_return_address(0), usecase_ndx); + + rc = sde_power_reg_bus_update(phandle->reg_bus_hdl, + usecase_ndx); + if (rc) + pr_err("failed to set reg bus vote rc=%d\n", rc); + + if (!skip_lock) + mutex_unlock(&phandle->phandle_lock); + + return rc; +} + +static inline bool _resource_changed(u32 current_usecase_ndx, + u32 max_usecase_ndx) +{ + WARN_ON((current_usecase_ndx >= VOTE_INDEX_MAX) + || (max_usecase_ndx >= VOTE_INDEX_MAX)); + + if (((current_usecase_ndx >= VOTE_INDEX_LOW) && /* enabled */ + (max_usecase_ndx == VOTE_INDEX_DISABLE)) || /* max disabled */ + ((current_usecase_ndx == VOTE_INDEX_DISABLE) && /* disabled */ + (max_usecase_ndx >= VOTE_INDEX_LOW))) /* max enabled */ + return true; + + return false; +} + +int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable) +{ + int rc = 0, i = 0; + struct dss_module_power *mp; + + if (!phandle) { + pr_err("invalid input argument\n"); + return -EINVAL; + } + + mp = &phandle->mp; + + mutex_lock(&phandle->phandle_lock); + + pr_debug("enable:%d\n", enable); + + SDE_ATRACE_BEGIN("sde_power_resource_enable"); + + /* RSC client init */ + sde_power_rsc_client_init(phandle); + + if (enable) { + sde_power_event_trigger_locked(phandle, + SDE_POWER_EVENT_PRE_ENABLE); + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX && + phandle->data_bus_handle[i].data_bus_hdl; i++) { + rc = _sde_power_data_bus_set_quota( + &phandle->data_bus_handle[i], + SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + if (rc) { + pr_err("failed to set data bus vote id=%d rc=%d\n", + i, rc); + goto vreg_err; + } + } + rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, + enable); + if (rc) { + pr_err("failed to enable vregs rc=%d\n", rc); + goto vreg_err; + } + + rc = sde_power_scale_reg_bus(phandle, VOTE_INDEX_LOW, true); + if (rc) { + pr_err("failed to set reg bus vote rc=%d\n", rc); + goto reg_bus_hdl_err; + } + + SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE1); + rc = sde_power_rsc_update(phandle, true); + if (rc) { + pr_err("failed to update rsc\n"); + goto rsc_err; + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); + if (rc) { + pr_err("clock enable failed rc:%d\n", rc); + goto clk_err; + } + + sde_power_event_trigger_locked(phandle, + SDE_POWER_EVENT_POST_ENABLE); + + } else { + sde_power_event_trigger_locked(phandle, + SDE_POWER_EVENT_PRE_DISABLE); + + SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE2); + sde_power_rsc_update(phandle, false); + + msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); + + sde_power_scale_reg_bus(phandle, VOTE_INDEX_DISABLE, true); + + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); + + for (i = SDE_POWER_HANDLE_DBUS_ID_MAX - 1; i >= 0; i--) + if (phandle->data_bus_handle[i].data_bus_hdl) + _sde_power_data_bus_set_quota( + &phandle->data_bus_handle[i], + SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); + + sde_power_event_trigger_locked(phandle, + SDE_POWER_EVENT_POST_DISABLE); + } + + SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_EXIT); + SDE_ATRACE_END("sde_power_resource_enable"); + mutex_unlock(&phandle->phandle_lock); + return rc; + +clk_err: + sde_power_rsc_update(phandle, false); +rsc_err: + sde_power_scale_reg_bus(phandle, VOTE_INDEX_DISABLE, true); +reg_bus_hdl_err: + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0); +vreg_err: + for (i-- ; i >= 0 && phandle->data_bus_handle[i].data_bus_hdl; i--) + _sde_power_data_bus_set_quota( + &phandle->data_bus_handle[i], + SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA); + SDE_ATRACE_END("sde_power_resource_enable"); + mutex_unlock(&phandle->phandle_lock); + return rc; +} + +int sde_cx_ipeak_vote(struct sde_power_handle *phandle, struct dss_clk *clock, + u64 requested_clk_rate, u64 prev_clk_rate, bool enable_vote) +{ + int ret = 0; + u64 curr_core_clk_rate, max_core_clk_rate, prev_core_clk_rate; + + if (!phandle->dss_cx_ipeak) { + pr_debug("%pS->%s: Invalid input\n", + __builtin_return_address(0), __func__); + return -EOPNOTSUPP; + } + + if (strcmp("core_clk", clock->clk_name)) { + pr_debug("Not a core clk , cx_ipeak vote not needed\n"); + return -EOPNOTSUPP; + } + + curr_core_clk_rate = clock->rate; + max_core_clk_rate = clock->max_rate; + prev_core_clk_rate = prev_clk_rate; + + if (enable_vote && requested_clk_rate == max_core_clk_rate && + curr_core_clk_rate != requested_clk_rate) + ret = cx_ipeak_update(phandle->dss_cx_ipeak, true); + else if (!enable_vote && requested_clk_rate != max_core_clk_rate && + prev_core_clk_rate == max_core_clk_rate) + ret = cx_ipeak_update(phandle->dss_cx_ipeak, false); + + if (ret) + SDE_EVT32(ret, enable_vote, requested_clk_rate, + curr_core_clk_rate, prev_core_clk_rate); + + return ret; +} + +int sde_power_clk_set_rate(struct sde_power_handle *phandle, char *clock_name, + u64 rate) +{ + int i, rc = -EINVAL; + struct dss_module_power *mp; + u64 prev_clk_rate, requested_clk_rate; + + if (!phandle) { + pr_err("invalid input power handle\n"); + return -EINVAL; + } + + mutex_lock(&phandle->phandle_lock); + if (phandle->last_event_handled & SDE_POWER_EVENT_POST_DISABLE) { + pr_debug("invalid power state %u\n", + phandle->last_event_handled); + SDE_EVT32(phandle->last_event_handled, SDE_EVTLOG_ERROR); + mutex_unlock(&phandle->phandle_lock); + return -EINVAL; + } + + mp = &phandle->mp; + + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clock_name)) { + if (mp->clk_config[i].max_rate && + (rate > mp->clk_config[i].max_rate)) + rate = mp->clk_config[i].max_rate; + + prev_clk_rate = mp->clk_config[i].rate; + requested_clk_rate = rate; + sde_cx_ipeak_vote(phandle, &mp->clk_config[i], + requested_clk_rate, prev_clk_rate, true); + mp->clk_config[i].rate = rate; + rc = msm_dss_single_clk_set_rate(&mp->clk_config[i]); + if (!rc) + sde_cx_ipeak_vote(phandle, &mp->clk_config[i], + requested_clk_rate, prev_clk_rate, false); + break; + } + } + mutex_unlock(&phandle->phandle_lock); + + return rc; +} + +u64 sde_power_clk_get_rate(struct sde_power_handle *phandle, char *clock_name) +{ + int i; + struct dss_module_power *mp; + u64 rate = -EINVAL; + + if (!phandle) { + pr_err("invalid input power handle\n"); + return -EINVAL; + } + mp = &phandle->mp; + + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clock_name)) { + rate = clk_get_rate(mp->clk_config[i].clk); + break; + } + } + + return rate; +} + +u64 sde_power_clk_get_max_rate(struct sde_power_handle *phandle, + char *clock_name) +{ + int i; + struct dss_module_power *mp; + u64 rate = 0; + + if (!phandle) { + pr_err("invalid input power handle\n"); + return 0; + } + mp = &phandle->mp; + + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clock_name)) { + rate = mp->clk_config[i].max_rate; + break; + } + } + + return rate; +} + +struct clk *sde_power_clk_get_clk(struct sde_power_handle *phandle, + char *clock_name) +{ + int i; + struct dss_module_power *mp; + struct clk *clk = NULL; + + if (!phandle) { + pr_err("invalid input power handle\n"); + return 0; + } + mp = &phandle->mp; + + for (i = 0; i < mp->num_clk; i++) { + if (!strcmp(mp->clk_config[i].clk_name, clock_name)) { + clk = mp->clk_config[i].clk; + break; + } + } + + return clk; +} + +int sde_power_clk_set_flags(struct sde_power_handle *phandle, + char *clock_name, unsigned long flags) +{ + struct clk *clk; + + if (!phandle) { + pr_err("invalid input power handle\n"); + return -EINVAL; + } + + if (!clock_name) { + pr_err("invalid input clock name\n"); + return -EINVAL; + } + + clk = sde_power_clk_get_clk(phandle, clock_name); + if (!clk) { + pr_err("get_clk failed for clk: %s\n", clock_name); + return -EINVAL; + } + + return clk_set_flags(clk, flags); +} + +struct sde_power_event *sde_power_handle_register_event( + struct sde_power_handle *phandle, + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), + void *usr, char *client_name) +{ + struct sde_power_event *event; + + if (!phandle) { + pr_err("invalid power handle\n"); + return ERR_PTR(-EINVAL); + } else if (!cb_fnc || !event_type) { + pr_err("no callback fnc or event type\n"); + return ERR_PTR(-EINVAL); + } + + event = kzalloc(sizeof(struct sde_power_event), GFP_KERNEL); + if (!event) + return ERR_PTR(-ENOMEM); + + event->event_type = event_type; + event->cb_fnc = cb_fnc; + event->usr = usr; + strlcpy(event->client_name, client_name, MAX_CLIENT_NAME_LEN); + event->active = true; + + mutex_lock(&phandle->phandle_lock); + list_add(&event->list, &phandle->event_list); + mutex_unlock(&phandle->phandle_lock); + + return event; +} + +void sde_power_handle_unregister_event( + struct sde_power_handle *phandle, + struct sde_power_event *event) +{ + if (!phandle || !event) { + pr_err("invalid phandle or event\n"); + } else if (!event->active) { + pr_err("power handle deinit already done\n"); + kfree(event); + } else { + mutex_lock(&phandle->phandle_lock); + list_del_init(&event->list); + mutex_unlock(&phandle->phandle_lock); + kfree(event); + } +} diff --git a/techpack/display/msm/sde_power_handle.h b/techpack/display/msm/sde_power_handle.h new file mode 100644 index 0000000000000000000000000000000000000000..257c844d56ac707eaf64e362ebf3e48736785d7b --- /dev/null +++ b/techpack/display/msm/sde_power_handle.h @@ -0,0 +1,307 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_POWER_HANDLE_H_ +#define _SDE_POWER_HANDLE_H_ + +#define MAX_CLIENT_NAME_LEN 128 + +#define SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA 0 +#define SDE_POWER_HANDLE_DISABLE_BUS_AB_QUOTA 0 +#define SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA 400000000 +#define SDE_POWER_HANDLE_ENABLE_NRT_BUS_IB_QUOTA 0 +#define SDE_POWER_HANDLE_DISABLE_BUS_IB_QUOTA 0 + +#define SDE_POWER_HANDLE_CONT_SPLASH_BUS_IB_QUOTA 3000000000ULL +#define SDE_POWER_HANDLE_CONT_SPLASH_BUS_AB_QUOTA 3000000000ULL + +#include <linux/sde_io_util.h> +#include <soc/qcom/cx_ipeak.h> + +/* event will be triggered before power handler disable */ +#define SDE_POWER_EVENT_PRE_DISABLE 0x1 + +/* event will be triggered after power handler disable */ +#define SDE_POWER_EVENT_POST_DISABLE 0x2 + +/* event will be triggered before power handler enable */ +#define SDE_POWER_EVENT_PRE_ENABLE 0x4 + +/* event will be triggered after power handler enable */ +#define SDE_POWER_EVENT_POST_ENABLE 0x8 + +/** + * mdss_bus_vote_type: register bus vote type + * VOTE_INDEX_DISABLE: removes the client vote + * VOTE_INDEX_LOW: keeps the lowest vote for register bus + * VOTE_INDEX_MEDIUM: keeps medium vote for register bus + * VOTE_INDEX_HIGH: keeps the highest vote for register bus + * VOTE_INDEX_MAX: invalid + */ +enum mdss_bus_vote_type { + VOTE_INDEX_DISABLE, + VOTE_INDEX_LOW, + VOTE_INDEX_MEDIUM, + VOTE_INDEX_HIGH, + VOTE_INDEX_MAX, +}; + +/** + * enum sde_power_handle_data_bus_client - type of axi bus clients + * @SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT: core real-time bus client + * @SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT: core non-real-time bus client + * @SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX: maximum number of bus client type + */ +enum sde_power_handle_data_bus_client { + SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, + SDE_POWER_HANDLE_DATA_BUS_CLIENT_NRT, + SDE_POWER_HANDLE_DATA_BUS_CLIENT_MAX +}; + +/** + * enum SDE_POWER_HANDLE_DBUS_ID - data bus identifier + * @SDE_POWER_HANDLE_DBUS_ID_MNOC: DPU/MNOC data bus + * @SDE_POWER_HANDLE_DBUS_ID_LLCC: MNOC/LLCC data bus + * @SDE_POWER_HANDLE_DBUS_ID_EBI: LLCC/EBI data bus + */ +enum SDE_POWER_HANDLE_DBUS_ID { + SDE_POWER_HANDLE_DBUS_ID_MNOC, + SDE_POWER_HANDLE_DBUS_ID_LLCC, + SDE_POWER_HANDLE_DBUS_ID_EBI, + SDE_POWER_HANDLE_DBUS_ID_MAX, +}; + +/** + * struct sde_power_data_handle: power handle struct for data bus + * @data_bus_scale_table: pointer to bus scaling table + * @data_bus_hdl: current data bus handle + * @data_paths_cnt: number of rt data path ports + * @curr_bw_uc_idx: current use case index of data bus + * @ao_bw_uc_idx: active only use case index of data bus + * @ab_rt: realtime ab quota + * @ib_rt: realtime ib quota + * @ab_nrt: non-realtime ab quota + * @ib_nrt: non-realtime ib quota + * @enable: true if bus is enabled + */ +struct sde_power_data_bus_handle { + struct msm_bus_scale_pdata *data_bus_scale_table; + u32 data_bus_hdl; + u32 data_paths_cnt; + u32 curr_bw_uc_idx; + u32 ao_bw_uc_idx; + u64 ab_rt; + u64 ib_rt; + u64 ab_nrt; + u64 ib_nrt; + bool enable; +}; + +/* + * struct sde_power_event - local event registration structure + * @client_name: name of the client registering + * @cb_fnc: pointer to desired callback function + * @usr: user pointer to pass to callback event trigger + * @event: refer to SDE_POWER_HANDLE_EVENT_* + * @list: list to attach event master list + * @active: indicates the state of sde power handle + */ +struct sde_power_event { + char client_name[MAX_CLIENT_NAME_LEN]; + void (*cb_fnc)(u32 event_type, void *usr); + void *usr; + u32 event_type; + struct list_head list; + bool active; +}; + +/** + * struct sde_power_handle: power handle main struct + * @mp: module power for clock and regulator + * @phandle_lock: lock to synchronize the enable/disable + * @dev: pointer to device structure + * @usecase_ndx: current usecase index + * @reg_bus_hdl: current register bus handle + * @data_bus_handle: context structure for data bus control + * @event_list: current power handle event list + * @rsc_client: sde rsc client pointer + * @rsc_client_init: boolean to control rsc client create + * @dss_cx_ipeak: client pointer for cx ipeak driver + * @is_ext_vote_en: flag to check if external vote is present + * @ext_client_lock: external client vote mutex + */ +struct sde_power_handle { + struct dss_module_power mp; + struct mutex phandle_lock; + struct device *dev; + u32 current_usecase_ndx; + u32 reg_bus_hdl; + struct sde_power_data_bus_handle data_bus_handle + [SDE_POWER_HANDLE_DBUS_ID_MAX]; + struct list_head event_list; + u32 last_event_handled; + struct sde_rsc_client *rsc_client; + bool rsc_client_init; + struct cx_ipeak_client *dss_cx_ipeak; + bool is_ext_vote_en; + struct mutex ext_client_lock; +}; + +/** + * sde_power_resource_init() - initializes the sde power handle + * @pdev: platform device to search the power resources + * @pdata: power handle to store the power resources + * + * Return: error code. + */ +int sde_power_resource_init(struct platform_device *pdev, + struct sde_power_handle *pdata); + +/** + * sde_power_resource_deinit() - release the sde power handle + * @pdev: platform device for power resources + * @pdata: power handle containing the resources + * + * Return: error code. + */ +void sde_power_resource_deinit(struct platform_device *pdev, + struct sde_power_handle *pdata); + +/** + * sde_power_resource_enable() - enable/disable the power resources + * @pdata: power handle containing the resources + * @enable: boolean request for enable/disable + * + * Return: error code. + */ +int sde_power_resource_enable(struct sde_power_handle *pdata, bool enable); + +/** + * sde_power_scale_reg_bus() - Scale the registers bus for the specified client + * @phandle: power handle containing the resources + * @usecase_ndx: new use case to scale the reg bus + * @skip_lock: will skip holding the power rsrc mutex during the call, this is + * for internal callers that already hold this required lock. + * + * Return: error code. + */ +int sde_power_scale_reg_bus(struct sde_power_handle *phandle, + u32 usecase_ndx, bool skip_lock); + +/** + * sde_power_data_bus_state_update() - update data bus state + * @pdata: power handle containing the resources + * @enable: take enable vs disable path + * + * Return: error code. + */ +int sde_power_data_bus_state_update(struct sde_power_handle *phandle, + bool enable); + +/** + * sde_power_clk_set_rate() - set the clock rate + * @pdata: power handle containing the resources + * @clock_name: clock name which needs rate update. + * @rate: Requested rate. + * + * Return: error code. + */ +int sde_power_clk_set_rate(struct sde_power_handle *pdata, char *clock_name, + u64 rate); + +/** + * sde_power_clk_get_rate() - get the clock rate + * @pdata: power handle containing the resources + * @clock_name: clock name to get the rate + * + * Return: current clock rate + */ +u64 sde_power_clk_get_rate(struct sde_power_handle *pdata, char *clock_name); + +/** + * sde_power_clk_get_max_rate() - get the maximum clock rate + * @pdata: power handle containing the resources + * @clock_name: clock name to get the max rate. + * + * Return: maximum clock rate or 0 if not found. + */ +u64 sde_power_clk_get_max_rate(struct sde_power_handle *pdata, + char *clock_name); + +/** + * sde_power_clk_get_clk() - get the clock + * @pdata: power handle containing the resources + * @clock_name: clock name to get the clk pointer. + * + * Return: Pointer to clock + */ +struct clk *sde_power_clk_get_clk(struct sde_power_handle *phandle, + char *clock_name); + +/** + * sde_power_clk_set_flags() - set the clock flags + * @pdata: power handle containing the resources + * @clock_name: clock name to get the clk pointer. + * @flags: flags to set + * + * Return: error code. + */ +int sde_power_clk_set_flags(struct sde_power_handle *pdata, + char *clock_name, unsigned long flags); + +/** + * sde_power_data_bus_set_quota() - set data bus quota for power client + * @phandle: power handle containing the resources + * @bus_id: identifier of data bus, see SDE_POWER_HANDLE_DBUS_ID + * @ab_quota: arbitrated bus bandwidth + * @ib_quota: instantaneous bus bandwidth + * + * Return: zero if success, or error code otherwise + */ +int sde_power_data_bus_set_quota(struct sde_power_handle *phandle, + u32 bus_id, u64 ab_quota, u64 ib_quota); + +/** + * sde_power_data_bus_bandwidth_ctrl() - control data bus bandwidth enable + * @phandle: power handle containing the resources + * @enable: true to enable bandwidth for data base + * + * Return: none + */ +void sde_power_data_bus_bandwidth_ctrl(struct sde_power_handle *phandle, + int enable); + +/** + * sde_power_handle_register_event - register a callback function for an event. + * Clients can register for multiple events with a single register. + * Any block with access to phandle can register for the event + * notification. + * @phandle: power handle containing the resources + * @event_type: event type to register; refer SDE_POWER_HANDLE_EVENT_* + * @cb_fnc: pointer to desired callback function + * @usr: user pointer to pass to callback on event trigger + * + * Return: event pointer if success, or error code otherwise + */ +struct sde_power_event *sde_power_handle_register_event( + struct sde_power_handle *phandle, + u32 event_type, void (*cb_fnc)(u32 event_type, void *usr), + void *usr, char *client_name); +/** + * sde_power_handle_unregister_event - unregister callback for event(s) + * @phandle: power handle containing the resources + * @event: event pointer returned after power handle register + */ +void sde_power_handle_unregister_event(struct sde_power_handle *phandle, + struct sde_power_event *event); + +/** + * sde_power_handle_get_dbus_name - get name of given data bus identifier + * @bus_id: data bus identifier + * Return: Pointer to name string if success; NULL otherwise + */ +const char *sde_power_handle_get_dbus_name(u32 bus_id); + +#endif /* _SDE_POWER_HANDLE_H_ */ diff --git a/techpack/display/msm/sde_rsc.c b/techpack/display/msm/sde_rsc.c new file mode 100644 index 0000000000000000000000000000000000000000..b6397a96508fc43449d39cd45eac0cb841d54961 --- /dev/null +++ b/techpack/display/msm/sde_rsc.c @@ -0,0 +1,1698 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[sde_rsc:%s:%d]: " fmt, __func__, __LINE__ + +#include <linux/kernel.h> +#include <linux/debugfs.h> +#include <linux/of.h> +#include <linux/string.h> +#include <linux/of_address.h> +#include <linux/component.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/of_platform.h> +#include <linux/module.h> +#include <linux/msm-bus.h> + +#include <soc/qcom/rpmh.h> +#include <drm/drmP.h> +#include <drm/drm_irq.h> +#include "sde_rsc_priv.h" +#include "sde_dbg.h" +#include "sde_trace.h" + +#define SDE_RSC_DRV_DBG_NAME "sde_rsc_drv" +#define SDE_RSC_WRAPPER_DBG_NAME "sde_rsc_wrapper" + +#define SINGLE_TCS_EXECUTION_TIME_V1 1064000 +#define SINGLE_TCS_EXECUTION_TIME_V2 930000 + +#define RSC_MODE_INSTRUCTION_TIME 100 +#define RSC_MODE_THRESHOLD_OVERHEAD 2700 + +/** + * rsc_min_threshold will be set to MIN_THRESHOLD_OVERHEAD_TIME which + * takes into account back off time + overhead from RSC/RSC_WRAPPER. The + * overhead buffer time is required to be greater than 14. Program it + * with a higher value (3.3 ms), so it has sufficient time to complete + * the sequence in rare cases. + */ +#define MIN_THRESHOLD_OVERHEAD_TIME 64 + +#define DEFAULT_PANEL_FPS 60 +#define DEFAULT_PANEL_JITTER_NUMERATOR 2 +#define DEFAULT_PANEL_JITTER_DENOMINATOR 1 +#define DEFAULT_PANEL_PREFILL_LINES 25 +#define DEFAULT_PANEL_VTOTAL (480 + DEFAULT_PANEL_PREFILL_LINES) +#define TICKS_IN_NANO_SECOND 1000000000 + +#define MAX_BUFFER_SIZE 256 + +#define CMD_MODE_SWITCH_SUCCESS 0xFFFF +#define VID_MODE_SWITCH_SUCCESS 0xFFFE +#define CLK_MODE_SWITCH_SUCCESS 0xFFFD +#define STATE_UPDATE_NOT_ALLOWED 0xFFFC + +/* Primary panel worst case VSYNC expected to be no less than 30fps */ +#define PRIMARY_VBLANK_WORST_CASE_MS 34 + +#define DEFAULT_PANEL_MIN_V_PREFILL 35 + +static struct sde_rsc_priv *rsc_prv_list[MAX_RSC_COUNT]; +static struct device *rpmh_dev[MAX_RSC_COUNT]; + +/** + * sde_rsc_client_create() - create the client for sde rsc. + * Different displays like DSI, HDMI, DP, WB, etc should call this + * api to register their vote for rpmh. They still need to vote for + * power handle to get the clocks. + + * @rsc_index: A client will be created on this RSC. As of now only + * SDE_RSC_INDEX is valid rsc index. + * @name: Caller needs to provide some valid string to identify + * the client. "primary", "dp", "hdmi" are suggested name. + * @is_primary: Caller needs to provide information if client is primary + * or not. Primary client votes will be redirected to + * display rsc. + * @vsync_source: This parameter is only valid for primary display. It provides + * vsync source information + * + * Return: client node pointer. + */ +struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *client_name, + enum sde_rsc_client_type client_type, u32 vsync_source) +{ + struct sde_rsc_client *client; + struct sde_rsc_priv *rsc; + static int id; + + if (!client_name) { + pr_err("client name is null- not supported\n"); + return ERR_PTR(-EINVAL); + } else if (rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + return ERR_PTR(-EINVAL); + } else if (!rsc_prv_list[rsc_index]) { + pr_debug("rsc not probed yet or not available\n"); + return NULL; + } + + rsc = rsc_prv_list[rsc_index]; + client = kzalloc(sizeof(struct sde_rsc_client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + mutex_lock(&rsc->client_lock); + strlcpy(client->name, client_name, MAX_RSC_CLIENT_NAME_LEN); + client->current_state = SDE_RSC_IDLE_STATE; + client->rsc_index = rsc_index; + client->id = id; + client->client_type = client_type; + if (client->client_type == SDE_RSC_PRIMARY_DISP_CLIENT) { + rsc->primary_client = client; + rsc->vsync_source = vsync_source; + } + pr_debug("client %s rsc index:%d client_type:%d\n", client_name, + rsc_index, client->client_type); + + list_add(&client->list, &rsc->client_list); + id++; + mutex_unlock(&rsc->client_lock); + + return client; +} +EXPORT_SYMBOL(sde_rsc_client_create); + +/** + * sde_rsc_client_destroy() - Destroy the sde rsc client. + * + * @client: Client pointer provided by sde_rsc_client_create(). + * + * Return: none + */ +void sde_rsc_client_destroy(struct sde_rsc_client *client) +{ + struct sde_rsc_priv *rsc; + enum sde_rsc_state state; + + if (!client) { + pr_debug("invalid client\n"); + goto end; + } else if (client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + goto end; + } + + pr_debug("client %s destroyed\n", client->name); + rsc = rsc_prv_list[client->rsc_index]; + if (!rsc) + goto end; + + mutex_lock(&rsc->client_lock); + state = client->current_state; + mutex_unlock(&rsc->client_lock); + + if (state != SDE_RSC_IDLE_STATE) { + int wait_vblank_crtc_id; + + sde_rsc_client_state_update(client, SDE_RSC_IDLE_STATE, NULL, + SDE_RSC_INVALID_CRTC_ID, &wait_vblank_crtc_id); + + /* if vblank wait required at shutdown, use a simple sleep */ + if (wait_vblank_crtc_id != SDE_RSC_INVALID_CRTC_ID) { + pr_err("unexpected sleep required on crtc %d at rsc client destroy\n", + wait_vblank_crtc_id); + SDE_EVT32(client->id, state, rsc->current_state, + client->crtc_id, wait_vblank_crtc_id, + SDE_EVTLOG_ERROR); + msleep(PRIMARY_VBLANK_WORST_CASE_MS); + } + } + mutex_lock(&rsc->client_lock); + list_del_init(&client->list); + mutex_unlock(&rsc->client_lock); + + kfree(client); +end: + return; +} +EXPORT_SYMBOL(sde_rsc_client_destroy); + +struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type, + void (*cb_func)(uint32_t event_type, void *usr), void *usr) +{ + struct sde_rsc_event *evt; + struct sde_rsc_priv *rsc; + + if (rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index:%d\n", rsc_index); + return ERR_PTR(-EINVAL); + } else if (!rsc_prv_list[rsc_index]) { + pr_err("rsc idx:%d not probed yet or not available\n", + rsc_index); + return ERR_PTR(-EINVAL); + } else if (!cb_func || !event_type) { + pr_err("no event or cb func\n"); + return ERR_PTR(-EINVAL); + } + + rsc = rsc_prv_list[rsc_index]; + evt = kzalloc(sizeof(struct sde_rsc_event), GFP_KERNEL); + if (!evt) + return ERR_PTR(-ENOMEM); + + evt->event_type = event_type; + evt->rsc_index = rsc_index; + evt->usr = usr; + evt->cb_func = cb_func; + pr_debug("event register type:%d rsc index:%d\n", + event_type, rsc_index); + + mutex_lock(&rsc->client_lock); + list_add(&evt->list, &rsc->event_list); + mutex_unlock(&rsc->client_lock); + + return evt; +} +EXPORT_SYMBOL(sde_rsc_register_event); + +void sde_rsc_unregister_event(struct sde_rsc_event *event) +{ + struct sde_rsc_priv *rsc; + + if (!event) { + pr_debug("invalid event client\n"); + goto end; + } else if (event->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + goto end; + } + + pr_debug("event client destroyed\n"); + rsc = rsc_prv_list[event->rsc_index]; + if (!rsc) + goto end; + + mutex_lock(&rsc->client_lock); + list_del_init(&event->list); + mutex_unlock(&rsc->client_lock); + + kfree(event); +end: + return; +} +EXPORT_SYMBOL(sde_rsc_unregister_event); + +bool is_sde_rsc_available(int rsc_index) +{ + if (rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index:%d\n", rsc_index); + return false; + } else if (!rsc_prv_list[rsc_index]) { + pr_debug("rsc idx:%d not probed yet or not available\n", + rsc_index); + return false; + } + + return true; +} +EXPORT_SYMBOL(is_sde_rsc_available); + +enum sde_rsc_state get_sde_rsc_current_state(int rsc_index) +{ + struct sde_rsc_priv *rsc; + + if (rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index:%d\n", rsc_index); + return SDE_RSC_IDLE_STATE; + } else if (!rsc_prv_list[rsc_index]) { + pr_err("rsc idx:%d not probed yet or not available\n", + rsc_index); + return SDE_RSC_IDLE_STATE; + } + + rsc = rsc_prv_list[rsc_index]; + return rsc->current_state; +} +EXPORT_SYMBOL(get_sde_rsc_current_state); + +static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, + struct sde_rsc_cmd_config *cmd_config, enum sde_rsc_state state) +{ + const u32 cxo_period_ns = 52; + u64 rsc_backoff_time_ns = rsc->backoff_time_ns; + u64 rsc_mode_threshold_time_ns = rsc->mode_threshold_time_ns; + u64 rsc_time_slot_0_ns = rsc->time_slot_0_ns; + u64 rsc_time_slot_1_ns; + const u64 pdc_jitter = 20; /* 20% more */ + + u64 frame_time_ns, frame_jitter; + u64 line_time_ns, prefill_time_ns; + u64 pdc_backoff_time_ns; + s64 total; + int ret = 0; + u32 default_prefill_lines; + + if (cmd_config) + memcpy(&rsc->cmd_config, cmd_config, sizeof(*cmd_config)); + + /* calculate for 640x480 60 fps resolution by default */ + if (!rsc->cmd_config.fps) + rsc->cmd_config.fps = DEFAULT_PANEL_FPS; + if (!rsc->cmd_config.jitter_numer) + rsc->cmd_config.jitter_numer = DEFAULT_PANEL_JITTER_NUMERATOR; + if (!rsc->cmd_config.jitter_denom) + rsc->cmd_config.jitter_denom = DEFAULT_PANEL_JITTER_DENOMINATOR; + if (!rsc->cmd_config.vtotal) + rsc->cmd_config.vtotal = DEFAULT_PANEL_VTOTAL; + + default_prefill_lines = (rsc->cmd_config.fps * + DEFAULT_PANEL_MIN_V_PREFILL) / DEFAULT_PANEL_FPS; + if ((state == SDE_RSC_CMD_STATE) || !rsc->cmd_config.prefill_lines) + rsc->cmd_config.prefill_lines = default_prefill_lines; + + pr_debug("frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n", + rsc->cmd_config.fps, rsc->cmd_config.jitter_numer, + rsc->cmd_config.jitter_denom, rsc->cmd_config.vtotal, + rsc->cmd_config.prefill_lines); + + /* 1 nano second */ + frame_time_ns = TICKS_IN_NANO_SECOND; + frame_time_ns = div_u64(frame_time_ns, rsc->cmd_config.fps); + + frame_jitter = frame_time_ns * rsc->cmd_config.jitter_numer; + frame_jitter = div_u64(frame_jitter, rsc->cmd_config.jitter_denom); + /* convert it to percentage */ + frame_jitter = div_u64(frame_jitter, 100); + + line_time_ns = frame_time_ns; + line_time_ns = div_u64(line_time_ns, rsc->cmd_config.vtotal); + prefill_time_ns = line_time_ns * rsc->cmd_config.prefill_lines; + + /* only take jitter into account for CMD mode */ + if (state == SDE_RSC_CMD_STATE) + total = frame_time_ns - frame_jitter - prefill_time_ns; + else + total = frame_time_ns - prefill_time_ns; + + if (total < 0) { + pr_err("invalid total time period time:%llu jiter_time:%llu blanking time:%llu\n", + frame_time_ns, frame_jitter, prefill_time_ns); + total = 0; + } + + total = div_u64(total, cxo_period_ns); + rsc->timer_config.static_wakeup_time_ns = total; + + pr_debug("frame time:%llu frame jiter_time:%llu\n", + frame_time_ns, frame_jitter); + pr_debug("line time:%llu prefill time ps:%llu\n", + line_time_ns, prefill_time_ns); + pr_debug("static wakeup time:%lld cxo:%u\n", total, cxo_period_ns); + + pdc_backoff_time_ns = rsc_backoff_time_ns; + rsc_backoff_time_ns = div_u64(rsc_backoff_time_ns, cxo_period_ns); + rsc->timer_config.rsc_backoff_time_ns = (u32) rsc_backoff_time_ns; + + pdc_backoff_time_ns *= pdc_jitter; + pdc_backoff_time_ns = div_u64(pdc_backoff_time_ns, 100); + rsc->timer_config.pdc_backoff_time_ns = (u32) pdc_backoff_time_ns; + + rsc_mode_threshold_time_ns = + div_u64(rsc_mode_threshold_time_ns, cxo_period_ns); + rsc->timer_config.rsc_mode_threshold_time_ns + = (u32) rsc_mode_threshold_time_ns; + + /* time_slot_0 for mode0 latency */ + rsc_time_slot_0_ns = div_u64(rsc_time_slot_0_ns, cxo_period_ns); + rsc->timer_config.rsc_time_slot_0_ns = (u32) rsc_time_slot_0_ns; + + /* time_slot_1 for mode1 latency */ + rsc_time_slot_1_ns = frame_time_ns; + rsc_time_slot_1_ns = div_u64(rsc_time_slot_1_ns, cxo_period_ns); + rsc->timer_config.rsc_time_slot_1_ns = (u32) rsc_time_slot_1_ns; + + /* mode 2 is infinite */ + rsc->timer_config.rsc_time_slot_2_ns = 0xFFFFFFFF; + + rsc->timer_config.min_threshold_time_ns = MIN_THRESHOLD_OVERHEAD_TIME; + rsc->timer_config.bwi_threshold_time_ns = + rsc->timer_config.rsc_time_slot_0_ns; + + /* timer update should be called with client call */ + if (cmd_config && rsc->hw_ops.timer_update) { + ret = rsc->hw_ops.timer_update(rsc); + if (ret) + pr_err("sde rsc: hw timer update failed ret:%d\n", ret); + /* rsc init should be called during rsc probe - one time only */ + } else if (rsc->hw_ops.init) { + ret = rsc->hw_ops.init(rsc); + if (ret) + pr_err("sde rsc: hw init failed ret:%d\n", ret); + } + + return ret; +} + +static int sde_rsc_resource_disable(struct sde_rsc_priv *rsc) +{ + struct dss_module_power *mp; + u32 reg_bus_hdl; + + if (!rsc) { + pr_err("invalid drv data\n"); + return -EINVAL; + } + + if (atomic_read(&rsc->resource_refcount) == 0) { + pr_err("%pS: invalid rsc resource disable call\n", + __builtin_return_address(0)); + return -EINVAL; + } + + if (atomic_dec_return(&rsc->resource_refcount) != 0) + return 0; + + mp = &rsc->phandle.mp; + msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); + reg_bus_hdl = rsc->phandle.reg_bus_hdl; + if (reg_bus_hdl) + msm_bus_scale_client_update_request(reg_bus_hdl, + VOTE_INDEX_DISABLE); + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false); + + return 0; +} + +static int sde_rsc_resource_enable(struct sde_rsc_priv *rsc) +{ + struct dss_module_power *mp; + int rc = 0; + u32 reg_bus_hdl; + + if (!rsc) { + pr_err("invalid drv data\n"); + return -EINVAL; + } + + if (atomic_inc_return(&rsc->resource_refcount) != 1) + return 0; + + mp = &rsc->phandle.mp; + rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, true); + if (rc) { + pr_err("failed to enable vregs rc=%d\n", rc); + goto end; + } + + reg_bus_hdl = rsc->phandle.reg_bus_hdl; + if (reg_bus_hdl) { + rc = msm_bus_scale_client_update_request(reg_bus_hdl, + VOTE_INDEX_LOW); + if (rc) { + pr_err("failed to set reg bus vote rc=%d\n", rc); + goto reg_bus_hdl_err; + } + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); + if (rc) { + pr_err("clock enable failed rc:%d\n", rc); + goto clk_err; + } + + return rc; + +clk_err: + if (reg_bus_hdl) + msm_bus_scale_client_update_request(reg_bus_hdl, + VOTE_INDEX_DISABLE); +reg_bus_hdl_err: + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false); +end: + atomic_dec(&rsc->resource_refcount); + return rc; +} + +static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc, + struct sde_rsc_cmd_config *config, + struct sde_rsc_client *caller_client, + int *wait_vblank_crtc_id) +{ + struct sde_rsc_client *client; + int rc = STATE_UPDATE_NOT_ALLOWED; + + if (!rsc->primary_client) { + pr_err("primary client not available for cmd state switch\n"); + rc = -EINVAL; + goto end; + } else if (caller_client != rsc->primary_client) { + pr_err("primary client state:%d not cmd state request\n", + rsc->primary_client->current_state); + rc = -EINVAL; + goto end; + } + + /* update timers - might not be available at next switch */ + if (config) + sde_rsc_timer_calculate(rsc, config, SDE_RSC_CMD_STATE); + + /** + * rsc clients can still send config at any time. If a config is + * received during cmd_state then vsync_wait will execute with the logic + * below. If a config is received when rsc is in AMC mode; A mode + * switch will do the vsync wait. updated checks still support all cases + * for dynamic mode switch and inline rotation. + */ + if (rsc->current_state == SDE_RSC_CMD_STATE) { + rc = 0; + if (config && rsc->version < SDE_RSC_REV_3) + goto vsync_wait; + else + goto end; + } + + /* any non-primary clk state client blocks the cmd state switch */ + list_for_each_entry(client, &rsc->client_list, list) + if (client->current_state == SDE_RSC_CLK_STATE && + client->client_type == SDE_RSC_EXTERNAL_DISP_CLIENT) + goto end; + + if (rsc->hw_ops.state_update) { + rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CMD_STATE); + if (!rc) + rpmh_mode_solver_set(rsc->rpmh_dev, true); + } + +vsync_wait: + /* indicate wait for vsync for vid to cmd state switch & cfg update */ + if (!rc && (rsc->current_state == SDE_RSC_VID_STATE || + rsc->current_state == SDE_RSC_CMD_STATE)) { + rsc->post_poms = true; + + /* clear VSYNC timestamp for indication when update completes */ + if (rsc->hw_ops.hw_vsync) + rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0); + if (!wait_vblank_crtc_id) { + pr_err("invalid crtc id wait pointer, client %d\n", + caller_client->id); + SDE_EVT32(caller_client->id, rsc->current_state, + caller_client->crtc_id, + wait_vblank_crtc_id, SDE_EVTLOG_ERROR); + msleep(PRIMARY_VBLANK_WORST_CASE_MS); + } else { + *wait_vblank_crtc_id = rsc->primary_client->crtc_id; + } + } +end: + return rc; +} + +static int sde_rsc_switch_to_clk(struct sde_rsc_priv *rsc, + int *wait_vblank_crtc_id) +{ + struct sde_rsc_client *client; + int rc = STATE_UPDATE_NOT_ALLOWED; + bool multi_display_active = false; + bool vid_display_active = false, cmd_display_active = false; + + list_for_each_entry(client, &rsc->client_list, list) { + if (client->current_state == SDE_RSC_CLK_STATE && + client->client_type == SDE_RSC_EXTERNAL_DISP_CLIENT) + multi_display_active = true; + else if (client->current_state == SDE_RSC_VID_STATE) + vid_display_active = true; + else if (client->current_state == SDE_RSC_CMD_STATE) + cmd_display_active = true; + } + + pr_debug("multi_display:%d vid_display:%d cmd_display:%d\n", + multi_display_active, vid_display_active, cmd_display_active); + if (!multi_display_active && (vid_display_active || cmd_display_active)) + goto end; + + if (rsc->hw_ops.state_update) { + rc = rsc->hw_ops.state_update(rsc, SDE_RSC_CLK_STATE); + if (!rc) + rpmh_mode_solver_set(rsc->rpmh_dev, false); + } + + /* indicate wait for vsync for cmd/vid to clk state switch */ + if (!rc && rsc->primary_client && + (rsc->current_state == SDE_RSC_CMD_STATE || + rsc->current_state == SDE_RSC_VID_STATE)) { + /* clear VSYNC timestamp for indication when update completes */ + if (rsc->hw_ops.hw_vsync) + rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0); + if (!wait_vblank_crtc_id) { + pr_err("invalid crtc id wait pointer provided\n"); + msleep(PRIMARY_VBLANK_WORST_CASE_MS); + } else { + *wait_vblank_crtc_id = rsc->primary_client->crtc_id; + + /* increase refcount, so we wait for the next vsync */ + atomic_inc(&rsc->rsc_vsync_wait); + SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait)); + } + } else if (atomic_read(&rsc->rsc_vsync_wait)) { + SDE_EVT32(rsc->primary_client, rsc->current_state, + atomic_read(&rsc->rsc_vsync_wait)); + + /* Wait for the vsync, if the refcount is set */ + rc = wait_event_timeout(rsc->rsc_vsync_waitq, + atomic_read(&rsc->rsc_vsync_wait) == 0, + msecs_to_jiffies(PRIMARY_VBLANK_WORST_CASE_MS*2)); + if (!rc) { + pr_err("Timeout waiting for vsync\n"); + rc = -ETIMEDOUT; + SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait), rc, + SDE_EVTLOG_ERROR); + } else { + SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait), rc); + rc = 0; + } + } +end: + return rc; +} + +static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc, + struct sde_rsc_cmd_config *config, + struct sde_rsc_client *caller_client, + int *wait_vblank_crtc_id) +{ + struct sde_rsc_client *client; + int rc = STATE_UPDATE_NOT_ALLOWED; + + if (!rsc->primary_client) { + pr_err("primary client not available for vid state switch\n"); + rc = -EINVAL; + goto end; + } else if (caller_client != rsc->primary_client) { + pr_err("primary client state:%d not vid state request\n", + rsc->primary_client->current_state); + rc = -EINVAL; + goto end; + } + + /* update timers - might not be available at next switch */ + if (config) + sde_rsc_timer_calculate(rsc, config, SDE_RSC_VID_STATE); + + /** + * rsc clients can still send config at any time. If a config is + * received during vid_state then vsync_wait will execute with the logic + * below. + */ + if (rsc->current_state == SDE_RSC_VID_STATE) { + rc = 0; + if (config && rsc->version < SDE_RSC_REV_3) + goto vsync_wait; + else + goto end; + } + + /* any non-primary clk state client blocks the vid state switch */ + list_for_each_entry(client, &rsc->client_list, list) + if (client->current_state == SDE_RSC_CLK_STATE && + client->client_type == SDE_RSC_EXTERNAL_DISP_CLIENT) + goto end; + + if (rsc->hw_ops.state_update) { + rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE); + if (!rc) + rpmh_mode_solver_set(rsc->rpmh_dev, + rsc->version == SDE_RSC_REV_3 ? true : false); + } + +vsync_wait: + /* indicate wait for vsync for vid to cmd state switch & cfg update */ + if (!rc && (rsc->current_state == SDE_RSC_VID_STATE || + rsc->current_state == SDE_RSC_CMD_STATE)) { + rsc->post_poms = true; + + /* clear VSYNC timestamp for indication when update completes */ + if (rsc->hw_ops.hw_vsync) + rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, 0, 0); + if (!wait_vblank_crtc_id) { + pr_err("invalid crtc id wait pointer, client %d\n", + caller_client->id); + SDE_EVT32(caller_client->id, rsc->current_state, + caller_client->crtc_id, + wait_vblank_crtc_id, SDE_EVTLOG_ERROR); + msleep(PRIMARY_VBLANK_WORST_CASE_MS); + } else { + *wait_vblank_crtc_id = rsc->primary_client->crtc_id; + } + } +end: + return rc; +} + +static int sde_rsc_switch_to_idle(struct sde_rsc_priv *rsc, + struct sde_rsc_cmd_config *config, + struct sde_rsc_client *caller_client, + int *wait_vblank_crtc_id) +{ + struct sde_rsc_client *client; + int rc = STATE_UPDATE_NOT_ALLOWED; + bool clk_client_active = false, multi_display_active = false; + bool vid_display_active = false, cmd_display_active = false; + + /* + * following code needs to run the loop through each + * client because they might be in different order + * sorting is not possible; only preference is available + */ + list_for_each_entry(client, &rsc->client_list, list) { + if (client->current_state == SDE_RSC_CLK_STATE && + client->client_type == SDE_RSC_EXTERNAL_DISP_CLIENT) + multi_display_active = true; + else if (client->current_state == SDE_RSC_CLK_STATE && + client->client_type == SDE_RSC_CLK_CLIENT) + clk_client_active = true; + else if (client->current_state == SDE_RSC_VID_STATE) + vid_display_active = true; + else if (client->current_state == SDE_RSC_CMD_STATE) + cmd_display_active = true; + pr_debug("client state:%d type:%d\n", + client->current_state, client->client_type); + } + + pr_debug("multi_display:%d clk_client:%d vid_display:%d cmd_display:%d\n", + multi_display_active, clk_client_active, vid_display_active, + cmd_display_active); + if (vid_display_active && !multi_display_active) { + rc = sde_rsc_switch_to_vid(rsc, NULL, rsc->primary_client, + wait_vblank_crtc_id); + if (!rc) + rc = VID_MODE_SWITCH_SUCCESS; + } else if (cmd_display_active && !multi_display_active) { + rc = sde_rsc_switch_to_cmd(rsc, NULL, rsc->primary_client, + wait_vblank_crtc_id); + if (!rc) + rc = CMD_MODE_SWITCH_SUCCESS; + } else if (clk_client_active) { + rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id); + if (!rc) + rc = CLK_MODE_SWITCH_SUCCESS; + } else if (rsc->hw_ops.state_update) { + rc = rsc->hw_ops.state_update(rsc, SDE_RSC_IDLE_STATE); + rsc->post_poms = false; + if (!rc) + rpmh_mode_solver_set(rsc->rpmh_dev, true); + } + + return rc; +} + +/** + * sde_rsc_client_get_vsync_refcount() - returns the status of the vsync + * refcount, to signal if the client needs to reset the refcounting logic + * @client: Client pointer provided by sde_rsc_client_create(). + * + * Return: value of the vsync refcount. + */ +int sde_rsc_client_get_vsync_refcount( + struct sde_rsc_client *caller_client) +{ + struct sde_rsc_priv *rsc; + + if (!caller_client) { + pr_err("invalid client for rsc state update\n"); + return -EINVAL; + } else if (caller_client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + return -EINVAL; + } + + rsc = rsc_prv_list[caller_client->rsc_index]; + if (!rsc) + return 0; + + return atomic_read(&rsc->rsc_vsync_wait); +} + +/** + * sde_rsc_client_reset_vsync_refcount() - reduces the refcounting + * logic that waits for the vsync. + * @client: Client pointer provided by sde_rsc_client_create(). + * + * Return: zero if refcount was already zero. + */ +int sde_rsc_client_reset_vsync_refcount( + struct sde_rsc_client *caller_client) +{ + struct sde_rsc_priv *rsc; + int ret; + + if (!caller_client) { + pr_err("invalid client for rsc state update\n"); + return -EINVAL; + } else if (caller_client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + return -EINVAL; + } + + rsc = rsc_prv_list[caller_client->rsc_index]; + if (!rsc) + return 0; + + ret = atomic_add_unless(&rsc->rsc_vsync_wait, -1, 0); + wake_up_all(&rsc->rsc_vsync_waitq); + SDE_EVT32(atomic_read(&rsc->rsc_vsync_wait)); + + return ret; +} + +/** + * sde_rsc_client_is_state_update_complete() - check if state update is complete + * RSC state transition is not complete until HW receives VBLANK signal. This + * function checks RSC HW to determine whether that signal has been received. + * @client: Client pointer provided by sde_rsc_client_create(). + * + * Return: true if the state update has completed. + */ +bool sde_rsc_client_is_state_update_complete( + struct sde_rsc_client *caller_client) +{ + struct sde_rsc_priv *rsc; + u32 vsync_timestamp0 = 0; + + if (!caller_client) { + pr_err("invalid client for rsc state update\n"); + return false; + } else if (caller_client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + return false; + } + + rsc = rsc_prv_list[caller_client->rsc_index]; + if (!rsc) + return false; + + /** + * state updates clear VSYNC timestamp, check if a new one arrived. + * use VSYNC mode 0 (CMD TE) always for this, per HW recommendation. + */ + if (rsc->hw_ops.hw_vsync) + vsync_timestamp0 = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ_VSYNC0, + NULL, 0, 0); + + return vsync_timestamp0 != 0; +} + +/** + * sde_rsc_client_state_update() - rsc client state update + * Video mode, cmd mode and clk state are suppoed as modes. A client need to + * set this property during panel config time. A switching client can set the + * property to change the state + * + * @client: Client pointer provided by sde_rsc_client_create(). + * @state: Client state - video/cmd + * @config: fps, vtotal, porches, etc configuration for command mode + * panel + * @crtc_id: current client's crtc id + * @wait_vblank_crtc_id: Output parameter. If set to non-zero, rsc hw + * state update requires a wait for one vblank on + * the primary crtc. In that case, this output + * param will be set to the crtc on which to wait. + * If SDE_RSC_INVALID_CRTC_ID, no wait necessary + * + * Return: error code. + */ +int sde_rsc_client_state_update(struct sde_rsc_client *caller_client, + enum sde_rsc_state state, + struct sde_rsc_cmd_config *config, int crtc_id, + int *wait_vblank_crtc_id) +{ + int rc = 0; + struct sde_rsc_priv *rsc; + + if (!caller_client) { + pr_err("invalid client for rsc state update\n"); + return -EINVAL; + } else if (caller_client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + return -EINVAL; + } + + rsc = rsc_prv_list[caller_client->rsc_index]; + if (!rsc) + return -EINVAL; + + if (wait_vblank_crtc_id) + *wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID; + + mutex_lock(&rsc->client_lock); + SDE_EVT32_VERBOSE(caller_client->id, caller_client->current_state, + state, rsc->current_state, SDE_EVTLOG_FUNC_ENTRY); + caller_client->crtc_id = crtc_id; + caller_client->current_state = state; + + if (rsc->master_drm == NULL) { + pr_err("invalid master component binding\n"); + rc = -EINVAL; + goto end; + } else if ((rsc->current_state == state) && !config) { + pr_debug("no state change: %d\n", state); + goto end; + } + + pr_debug("%pS: rsc state:%d request client:%s state:%d\n", + __builtin_return_address(0), rsc->current_state, + caller_client->name, state); + + if (rsc->current_state == SDE_RSC_IDLE_STATE) + sde_rsc_resource_enable(rsc); + + switch (state) { + case SDE_RSC_IDLE_STATE: + rc = sde_rsc_switch_to_idle(rsc, NULL, rsc->primary_client, + wait_vblank_crtc_id); + + if (rc == CMD_MODE_SWITCH_SUCCESS) { + state = SDE_RSC_CMD_STATE; + rc = 0; + } else if (rc == VID_MODE_SWITCH_SUCCESS) { + state = SDE_RSC_VID_STATE; + rc = 0; + } else if (rc == CLK_MODE_SWITCH_SUCCESS) { + state = SDE_RSC_CLK_STATE; + rc = 0; + } + break; + + case SDE_RSC_CMD_STATE: + rc = sde_rsc_switch_to_cmd(rsc, config, caller_client, + wait_vblank_crtc_id); + break; + + case SDE_RSC_VID_STATE: + rc = sde_rsc_switch_to_vid(rsc, config, caller_client, + wait_vblank_crtc_id); + break; + + case SDE_RSC_CLK_STATE: + rc = sde_rsc_switch_to_clk(rsc, wait_vblank_crtc_id); + break; + + default: + pr_err("invalid state handling %d\n", state); + break; + } + + if (rc == STATE_UPDATE_NOT_ALLOWED) { + rc = 0; + SDE_EVT32(caller_client->id, caller_client->current_state, + state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE1); + goto clk_disable; + } else if (rc) { + pr_debug("state:%d update failed rc:%d\n", state, rc); + SDE_EVT32(caller_client->id, caller_client->current_state, + state, rsc->current_state, rc, SDE_EVTLOG_FUNC_CASE2); + goto clk_disable; + } + + pr_debug("state switch successfully complete: %d\n", state); + SDE_ATRACE_INT("rsc_state", state); + rsc->current_state = state; + SDE_EVT32(caller_client->id, caller_client->current_state, + state, rsc->current_state, SDE_EVTLOG_FUNC_EXIT); + +clk_disable: + if (rsc->current_state == SDE_RSC_IDLE_STATE) + sde_rsc_resource_disable(rsc); +end: + mutex_unlock(&rsc->client_lock); + return rc; +} +EXPORT_SYMBOL(sde_rsc_client_state_update); + +/** + * sde_rsc_client_vote() - ab/ib vote from rsc client + * + * @client: Client pointer provided by sde_rsc_client_create(). + * @bus_id: data bus for which to be voted + * @ab: aggregated bandwidth vote from client. + * @ib: instant bandwidth vote from client. + * + * Return: error code. + */ +int sde_rsc_client_vote(struct sde_rsc_client *caller_client, + u32 bus_id, u64 ab_vote, u64 ib_vote) +{ + int rsc_index; + struct sde_rsc_priv *rsc; + + if (caller_client && caller_client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc client or client index\n"); + return -EINVAL; + } + + rsc_index = caller_client ? caller_client->rsc_index : SDE_RSC_INDEX; + rsc = rsc_prv_list[rsc_index]; + if (!rsc || bus_id >= SDE_POWER_HANDLE_DBUS_ID_MAX) + return -EINVAL; + + pr_debug("client:%s ab:%llu ib:%llu\n", + caller_client ? caller_client->name : "unknown", + ab_vote, ib_vote); + + mutex_lock(&rsc->client_lock); + rsc->bw_config.new_ab_vote[bus_id] = ab_vote; + rsc->bw_config.new_ib_vote[bus_id] = ib_vote; + mutex_unlock(&rsc->client_lock); + + return 0; +} +EXPORT_SYMBOL(sde_rsc_client_vote); + +int sde_rsc_client_trigger_vote(struct sde_rsc_client *caller_client, + bool delta_vote) +{ + int rc = 0, rsc_index, i; + struct sde_rsc_priv *rsc; + bool bw_increase = false; + + if (caller_client && caller_client->rsc_index >= MAX_RSC_COUNT) { + pr_err("invalid rsc index\n"); + return -EINVAL; + } + + rsc_index = caller_client ? caller_client->rsc_index : SDE_RSC_INDEX; + rsc = rsc_prv_list[rsc_index]; + if (!rsc) + return -EINVAL; + + pr_debug("client:%s trigger bw delta vote:%d\n", + caller_client ? caller_client->name : "unknown", delta_vote); + + mutex_lock(&rsc->client_lock); + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX && delta_vote; i++) { + if (rsc->bw_config.new_ab_vote[i] > rsc->bw_config.ab_vote[i] || + rsc->bw_config.new_ib_vote[i] > rsc->bw_config.ib_vote[i]) + bw_increase = true; + + rsc->bw_config.ab_vote[i] = rsc->bw_config.new_ab_vote[i]; + rsc->bw_config.ib_vote[i] = rsc->bw_config.new_ib_vote[i]; + } + + rc = sde_rsc_resource_enable(rsc); + if (rc < 0) + goto clk_enable_fail; + + if (delta_vote) { + if (rsc->hw_ops.tcs_wait) { + rc = rsc->hw_ops.tcs_wait(rsc); + if (rc) { + pr_err("tcs is still busy; can't send command\n"); + if (rsc->hw_ops.tcs_use_ok) + rsc->hw_ops.tcs_use_ok(rsc); + goto end; + } + } + + rpmh_invalidate(rsc->rpmh_dev); + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(&rsc->phandle, + i, rsc->bw_config.ab_vote[i], + rsc->bw_config.ib_vote[i]); + rpmh_flush(rsc->rpmh_dev); + } + + if (rsc->hw_ops.bwi_status && + (rsc->current_state == SDE_RSC_CMD_STATE || + rsc->current_state == SDE_RSC_VID_STATE)) + rsc->hw_ops.bwi_status(rsc, bw_increase); + else if (rsc->hw_ops.tcs_use_ok) + rsc->hw_ops.tcs_use_ok(rsc); + +end: + sde_rsc_resource_disable(rsc); +clk_enable_fail: + mutex_unlock(&rsc->client_lock); + + return rc; +} +EXPORT_SYMBOL(sde_rsc_client_trigger_vote); + +#if defined(CONFIG_DEBUG_FS) +void sde_rsc_debug_dump(u32 mux_sel) +{ + struct sde_rsc_priv *rsc; + + rsc = rsc_prv_list[SDE_RSC_INDEX]; + if (!rsc) + return; + + /* this must be called with rsc clocks enabled */ + if (rsc->hw_ops.debug_dump) + rsc->hw_ops.debug_dump(rsc, mux_sel); +} + +static int _sde_debugfs_status_show(struct seq_file *s, void *data) +{ + struct sde_rsc_priv *rsc; + struct sde_rsc_client *client; + int ret; + + if (!s || !s->private) + return -EINVAL; + + rsc = s->private; + + mutex_lock(&rsc->client_lock); + + seq_printf(s, "rsc current state:%d\n", rsc->current_state); + seq_printf(s, "wraper backoff time(ns):%d\n", + rsc->timer_config.static_wakeup_time_ns); + seq_printf(s, "rsc backoff time(ns):%d\n", + rsc->timer_config.rsc_backoff_time_ns); + seq_printf(s, "pdc backoff time(ns):%d\n", + rsc->timer_config.pdc_backoff_time_ns); + seq_printf(s, "rsc mode threshold time(ns):%d\n", + rsc->timer_config.rsc_mode_threshold_time_ns); + seq_printf(s, "rsc time slot 0(ns):%d\n", + rsc->timer_config.rsc_time_slot_0_ns); + seq_printf(s, "rsc time slot 1(ns):%d\n", + rsc->timer_config.rsc_time_slot_1_ns); + seq_printf(s, "frame fps:%d jitter_numer:%d jitter_denom:%d vtotal:%d prefill lines:%d\n", + rsc->cmd_config.fps, rsc->cmd_config.jitter_numer, + rsc->cmd_config.jitter_denom, + rsc->cmd_config.vtotal, rsc->cmd_config.prefill_lines); + + seq_puts(s, "\n"); + + list_for_each_entry(client, &rsc->client_list, list) + seq_printf(s, "\t client:%s state:%d\n", + client->name, client->current_state); + + if (rsc->current_state == SDE_RSC_IDLE_STATE) { + pr_debug("debug node is not supported during idle state\n"); + seq_puts(s, "hw state is not supported during idle pc\n"); + goto end; + } + + if (rsc->hw_ops.debug_show) { + ret = rsc->hw_ops.debug_show(s, rsc); + if (ret) + pr_err("sde rsc: hw debug failed ret:%d\n", ret); + } + +end: + mutex_unlock(&rsc->client_lock); + return 0; +} + +static int _sde_debugfs_status_open(struct inode *inode, struct file *file) +{ + return single_open(file, _sde_debugfs_status_show, inode->i_private); +} + +static int _sde_debugfs_mode_ctrl_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->private_data = inode->i_private; + return nonseekable_open(inode, file); +} + +static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct sde_rsc_priv *rsc = file->private_data; + char buffer[MAX_BUFFER_SIZE]; + int blen = 0; + + if (*ppos || !rsc || !rsc->hw_ops.mode_ctrl) + return 0; + + mutex_lock(&rsc->client_lock); + if (rsc->current_state == SDE_RSC_IDLE_STATE) { + pr_debug("debug node is not supported during idle state\n"); + blen = snprintf(buffer, MAX_BUFFER_SIZE, + "hw state is not supported during idle pc\n"); + goto end; + } + + blen = rsc->hw_ops.mode_ctrl(rsc, MODE_READ, buffer, + MAX_BUFFER_SIZE, 0); + +end: + mutex_unlock(&rsc->client_lock); + if (blen <= 0) + return 0; + + if (blen > count) + blen = count; + + blen = min_t(size_t, blen, MAX_BUFFER_SIZE); + if (copy_to_user(buf, buffer, blen)) + return -EFAULT; + + *ppos += blen; + return blen; +} + +static ssize_t _sde_debugfs_mode_ctrl_write(struct file *file, + const char __user *p, size_t count, loff_t *ppos) +{ + struct sde_rsc_priv *rsc = file->private_data; + char *input; + u32 mode_state = 0; + int rc; + + if (!rsc || !rsc->hw_ops.mode_ctrl || !count || + count > MAX_COUNT_SIZE_SUPPORTED) + return 0; + + input = kmalloc(count + 1, GFP_KERNEL); + if (!input) + return -ENOMEM; + + if (copy_from_user(input, p, count)) { + kfree(input); + return -EFAULT; + } + input[count] = '\0'; + + rc = kstrtoint(input, 0, &mode_state); + if (rc) { + pr_err("mode_state: int conversion failed rc:%d\n", rc); + goto end; + } + + pr_debug("mode_state: %d\n", mode_state); + mode_state &= 0x7; + if (mode_state != ALL_MODES_DISABLED && + mode_state != ALL_MODES_ENABLED && + mode_state != ONLY_MODE_0_ENABLED && + mode_state != ONLY_MODE_0_1_ENABLED) { + pr_err("invalid mode:%d combination\n", mode_state); + goto end; + } + + mutex_lock(&rsc->client_lock); + if (rsc->current_state == SDE_RSC_IDLE_STATE) { + pr_debug("debug node is not supported during idle state\n"); + goto state_check; + } + + rsc->hw_ops.mode_ctrl(rsc, MODE_UPDATE, NULL, 0, mode_state); + +state_check: + mutex_unlock(&rsc->client_lock); +end: + kfree(input); + return count; +} + +static int _sde_debugfs_vsync_mode_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->private_data = inode->i_private; + return nonseekable_open(inode, file); +} + +static ssize_t _sde_debugfs_vsync_mode_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct sde_rsc_priv *rsc = file->private_data; + char buffer[MAX_BUFFER_SIZE]; + int blen = 0; + + if (*ppos || !rsc || !rsc->hw_ops.hw_vsync) + return 0; + + mutex_lock(&rsc->client_lock); + if (rsc->current_state == SDE_RSC_IDLE_STATE) { + pr_debug("debug node is not supported during idle state\n"); + blen = snprintf(buffer, MAX_BUFFER_SIZE, + "hw state is not supported during idle pc\n"); + goto end; + } + + blen = rsc->hw_ops.hw_vsync(rsc, VSYNC_READ, buffer, + MAX_BUFFER_SIZE, 0); + +end: + mutex_unlock(&rsc->client_lock); + if (blen <= 0) + return 0; + + if (blen > count) + blen = count; + + blen = min_t(size_t, blen, MAX_BUFFER_SIZE); + if (copy_to_user(buf, buffer, blen)) + return -EFAULT; + + *ppos += blen; + return blen; +} + +static ssize_t _sde_debugfs_vsync_mode_write(struct file *file, + const char __user *p, size_t count, loff_t *ppos) +{ + struct sde_rsc_priv *rsc = file->private_data; + char *input; + u32 vsync_state = 0; + int rc; + + if (!rsc || !rsc->hw_ops.hw_vsync || !count || + count > MAX_COUNT_SIZE_SUPPORTED) + return 0; + + input = kmalloc(count + 1, GFP_KERNEL); + if (!input) + return -ENOMEM; + + if (copy_from_user(input, p, count)) { + kfree(input); + return -EFAULT; + } + input[count] = '\0'; + + rc = kstrtoint(input, 0, &vsync_state); + if (rc) { + pr_err("vsync_state: int conversion failed rc:%d\n", rc); + goto end; + } + + pr_debug("vsync_state: %d\n", vsync_state); + vsync_state &= 0x7; + + mutex_lock(&rsc->client_lock); + if (rsc->current_state == SDE_RSC_IDLE_STATE) { + pr_debug("debug node is not supported during idle state\n"); + goto state_check; + } + + if (vsync_state) + rsc->hw_ops.hw_vsync(rsc, VSYNC_ENABLE, NULL, + 0, vsync_state - 1); + else + rsc->hw_ops.hw_vsync(rsc, VSYNC_DISABLE, NULL, 0, 0); + +state_check: + mutex_unlock(&rsc->client_lock); +end: + kfree(input); + return count; +} + +static const struct file_operations debugfs_status_fops = { + .open = _sde_debugfs_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations mode_control_fops = { + .open = _sde_debugfs_mode_ctrl_open, + .read = _sde_debugfs_mode_ctrl_read, + .write = _sde_debugfs_mode_ctrl_write, +}; + +static const struct file_operations vsync_status_fops = { + .open = _sde_debugfs_vsync_mode_open, + .read = _sde_debugfs_vsync_mode_read, + .write = _sde_debugfs_vsync_mode_write, +}; + +static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name) +{ + rsc->debugfs_root = debugfs_create_dir(name, NULL); + if (!rsc->debugfs_root) + return; + + /* don't error check these */ + debugfs_create_file("status", 0400, rsc->debugfs_root, rsc, + &debugfs_status_fops); + debugfs_create_file("mode_control", 0600, rsc->debugfs_root, rsc, + &mode_control_fops); + debugfs_create_file("vsync_mode", 0600, rsc->debugfs_root, rsc, + &vsync_status_fops); + debugfs_create_x32("debug_mode", 0600, rsc->debugfs_root, + &rsc->debug_mode); +} +#else +static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name) +{ +} +#endif /* defined(CONFIG_DEBUG_FS) */ + +static void sde_rsc_deinit(struct platform_device *pdev, + struct sde_rsc_priv *rsc) +{ + if (!rsc) + return; + + sde_rsc_resource_disable(rsc); + if (rsc->sw_fs_enabled) + regulator_disable(rsc->fs); + if (rsc->fs) + devm_regulator_put(rsc->fs); + if (rsc->wrapper_io.base) + msm_dss_iounmap(&rsc->wrapper_io); + if (rsc->drv_io.base) + msm_dss_iounmap(&rsc->drv_io); + + sde_power_resource_deinit(pdev, &rsc->phandle); + debugfs_remove_recursive(rsc->debugfs_root); + kfree(rsc); +} + +/** + * sde_rsc_bind - bind rsc device with controlling device + * @dev: Pointer to base of platform device + * @master: Pointer to container of drm device + * @data: Pointer to private data + * Returns: Zero on success + */ +static int sde_rsc_bind(struct device *dev, + struct device *master, + void *data) +{ + struct sde_rsc_priv *rsc; + struct drm_device *drm; + struct platform_device *pdev = to_platform_device(dev); + + if (!dev || !pdev || !master) { + pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n", + dev, pdev, master); + return -EINVAL; + } + + drm = dev_get_drvdata(master); + rsc = platform_get_drvdata(pdev); + if (!drm || !rsc) { + pr_err("invalid param(s), drm %pK, rsc %pK\n", + drm, rsc); + return -EINVAL; + } + + mutex_lock(&rsc->client_lock); + rsc->master_drm = drm; + mutex_unlock(&rsc->client_lock); + + sde_dbg_reg_register_base(SDE_RSC_DRV_DBG_NAME, rsc->drv_io.base, + rsc->drv_io.len); + sde_dbg_reg_register_base(SDE_RSC_WRAPPER_DBG_NAME, + rsc->wrapper_io.base, rsc->wrapper_io.len); + return 0; +} + +/** + * sde_rsc_unbind - unbind rsc from controlling device + * @dev: Pointer to base of platform device + * @master: Pointer to container of drm device + * @data: Pointer to private data + */ +static void sde_rsc_unbind(struct device *dev, + struct device *master, void *data) +{ + struct sde_rsc_priv *rsc; + struct platform_device *pdev = to_platform_device(dev); + + if (!dev || !pdev) { + pr_err("invalid param(s)\n"); + return; + } + + rsc = platform_get_drvdata(pdev); + if (!rsc) { + pr_err("invalid display rsc\n"); + return; + } + + mutex_lock(&rsc->client_lock); + rsc->master_drm = NULL; + mutex_unlock(&rsc->client_lock); +} + +static const struct component_ops sde_rsc_comp_ops = { + .bind = sde_rsc_bind, + .unbind = sde_rsc_unbind, +}; + +static int sde_rsc_probe(struct platform_device *pdev) +{ + int ret; + struct sde_rsc_priv *rsc; + static int counter; + char name[MAX_RSC_CLIENT_NAME_LEN]; + + if (counter >= MAX_RSC_COUNT) { + pr_err("sde rsc supports probe till MAX_RSC_COUNT=%d devices\n", + MAX_RSC_COUNT); + return -EINVAL; + } + + rsc = kzalloc(sizeof(*rsc), GFP_KERNEL); + if (!rsc) { + ret = -ENOMEM; + goto rsc_alloc_fail; + } + + platform_set_drvdata(pdev, rsc); + rsc->dev = &pdev->dev; + of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version", + &rsc->version); + + if (rsc->version == SDE_RSC_REV_2) + rsc->single_tcs_execution_time = SINGLE_TCS_EXECUTION_TIME_V2; + else + rsc->single_tcs_execution_time = SINGLE_TCS_EXECUTION_TIME_V1; + + if (rsc->version == SDE_RSC_REV_3) { + rsc->time_slot_0_ns = rsc->single_tcs_execution_time + + RSC_MODE_INSTRUCTION_TIME; + rsc->backoff_time_ns = RSC_MODE_INSTRUCTION_TIME; + rsc->mode_threshold_time_ns = rsc->time_slot_0_ns; + } else { + rsc->time_slot_0_ns = (rsc->single_tcs_execution_time * 2) + + RSC_MODE_INSTRUCTION_TIME; + rsc->backoff_time_ns = rsc->single_tcs_execution_time + + RSC_MODE_INSTRUCTION_TIME; + rsc->mode_threshold_time_ns = rsc->backoff_time_ns + + RSC_MODE_THRESHOLD_OVERHEAD; + } + + ret = sde_power_resource_init(pdev, &rsc->phandle); + if (ret) { + pr_err("sde rsc:power resource init failed ret:%d\n", ret); + goto sde_rsc_fail; + } + + rsc->rpmh_dev = rpmh_dev[SDE_RSC_INDEX + counter]; + if (IS_ERR_OR_NULL(rsc->rpmh_dev)) { + ret = !rsc->rpmh_dev ? -EINVAL : PTR_ERR(rsc->rpmh_dev); + rsc->rpmh_dev = NULL; + pr_err("rpmh device node is not available ret:%d\n", ret); + goto sde_rsc_fail; + } + + ret = msm_dss_ioremap_byname(pdev, &rsc->wrapper_io, "wrapper"); + if (ret) { + pr_err("sde rsc: wrapper io data mapping failed ret=%d\n", ret); + goto sde_rsc_fail; + } + + ret = msm_dss_ioremap_byname(pdev, &rsc->drv_io, "drv"); + if (ret) { + pr_err("sde rsc: drv io data mapping failed ret:%d\n", ret); + goto sde_rsc_fail; + } + + rsc->fs = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR_OR_NULL(rsc->fs)) { + rsc->fs = NULL; + pr_err("unable to get regulator\n"); + goto sde_rsc_fail; + } + + if (rsc->version >= SDE_RSC_REV_3) + ret = sde_rsc_hw_register_v3(rsc); + else + ret = sde_rsc_hw_register(rsc); + if (ret) { + pr_err("sde rsc: hw register failed ret:%d\n", ret); + goto sde_rsc_fail; + } + + ret = regulator_enable(rsc->fs); + if (ret) { + pr_err("sde rsc: fs on failed ret:%d\n", ret); + goto sde_rsc_fail; + } + + rsc->sw_fs_enabled = true; + + ret = sde_rsc_resource_enable(rsc); + if (ret < 0) { + pr_err("failed to enable sde rsc power resources rc:%d\n", ret); + goto sde_rsc_fail; + } + + if (sde_rsc_timer_calculate(rsc, NULL, SDE_RSC_IDLE_STATE)) + goto sde_rsc_fail; + + sde_rsc_resource_disable(rsc); + + INIT_LIST_HEAD(&rsc->client_list); + INIT_LIST_HEAD(&rsc->event_list); + mutex_init(&rsc->client_lock); + init_waitqueue_head(&rsc->rsc_vsync_waitq); + atomic_set(&rsc->resource_refcount, 0); + + pr_info("sde rsc index:%d probed successfully\n", + SDE_RSC_INDEX + counter); + + rsc_prv_list[SDE_RSC_INDEX + counter] = rsc; + snprintf(name, MAX_RSC_CLIENT_NAME_LEN, "%s%d", "sde_rsc", counter); + _sde_rsc_init_debugfs(rsc, name); + counter++; + + ret = component_add(&pdev->dev, &sde_rsc_comp_ops); + if (ret) + pr_debug("component add failed, ret=%d\n", ret); + ret = 0; + + return ret; + +sde_rsc_fail: + sde_rsc_deinit(pdev, rsc); +rsc_alloc_fail: + return ret; +} + +static int sde_rsc_remove(struct platform_device *pdev) +{ + struct sde_rsc_priv *rsc = platform_get_drvdata(pdev); + + sde_rsc_deinit(pdev, rsc); + return 0; +} + +static int sde_rsc_rpmh_probe(struct platform_device *pdev) +{ + int ret = 0; + uint32_t index = 0; + + ret = of_property_read_u32(pdev->dev.of_node, "cell-index", &index); + if (ret) { + pr_err("unable to find sde rsc cell index\n"); + return ret; + } else if (index >= MAX_RSC_COUNT) { + pr_err("invalid cell index for sde rsc:%d\n", index); + return -EINVAL; + } + + rpmh_dev[index] = &pdev->dev; + return 0; +} + +int sde_rsc_rpmh_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < MAX_RSC_COUNT; i++) + rpmh_dev[i] = NULL; + + return 0; +} + +static const struct of_device_id dt_match[] = { + { .compatible = "qcom,sde-rsc"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, dt_match); + +static struct platform_driver sde_rsc_platform_driver = { + .probe = sde_rsc_probe, + .remove = sde_rsc_remove, + .driver = { + .name = "sde_rsc", + .of_match_table = dt_match, + .suppress_bind_attrs = true, + }, +}; + +static const struct of_device_id sde_rsc_rpmh_match[] = { + {.compatible = "qcom,sde-rsc-rpmh"}, + {}, +}; + +static struct platform_driver sde_rsc_rpmh_driver = { + .probe = sde_rsc_rpmh_probe, + .remove = sde_rsc_rpmh_remove, + .driver = { + .name = "sde_rsc_rpmh", + .of_match_table = sde_rsc_rpmh_match, + }, +}; + +static int __init sde_rsc_register(void) +{ + return platform_driver_register(&sde_rsc_platform_driver); +} + +static void __exit sde_rsc_unregister(void) +{ + platform_driver_unregister(&sde_rsc_platform_driver); +} + +static int __init sde_rsc_rpmh_register(void) +{ + return platform_driver_register(&sde_rsc_rpmh_driver); +} + +subsys_initcall(sde_rsc_rpmh_register); +module_init(sde_rsc_register); +module_exit(sde_rsc_unregister); diff --git a/techpack/display/msm/sde_rsc_hw.c b/techpack/display/msm/sde_rsc_hw.c new file mode 100644 index 0000000000000000000000000000000000000000..c624c868eeb6bb2f9464d9be3bebbb5cb7b053a4 --- /dev/null +++ b/techpack/display/msm/sde_rsc_hw.c @@ -0,0 +1,918 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[sde_rsc_hw:%s:%d]: " fmt, __func__, __LINE__ + +#include <linux/kernel.h> +#include <linux/debugfs.h> +#include <linux/delay.h> + +#include "sde_rsc_priv.h" +#include "sde_dbg.h" +#include "sde_rsc_hw.h" + +static void rsc_event_trigger(struct sde_rsc_priv *rsc, uint32_t event_type) +{ + struct sde_rsc_event *event; + + list_for_each_entry(event, &rsc->event_list, list) + if (event->event_type & event_type) + event->cb_func(event_type, event->usr); +} + +static int rsc_hw_qtimer_init(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware qtimer init\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_1, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_2, + 0xffffffff, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR0_FG0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR1_FG0, + 0x1, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CTL, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CTL, + 0x1, rsc->debug_mode); + + return 0; +} + +static int rsc_hw_pdc_init(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware pdc init\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0, + 0x4520, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0, + 0x4510, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0, + 0x4514, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SLAVE_ID_DRV0, + 0x1, rsc->debug_mode); + + return 0; +} + +static int rsc_hw_wrapper_init(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware wrapper init\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0, + rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD, + rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(8), rsc->debug_mode); + return 0; +} + +static int rsc_hw_seq_memory_init_v2(struct sde_rsc_priv *rsc) +{ + const u32 mode_0_start_addr = 0x0; + const u32 mode_1_start_addr = 0xc; + const u32 mode_2_start_addr = 0x18; + + pr_debug("rsc sequencer memory init v2\n"); + + /* Mode - 0 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x0, + 0xe0bb9ebe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x4, + 0x9ebeff39, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x8, + 0x2020209b, rsc->debug_mode); + + /* Mode - 1 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0xc, + 0x38bb9ebe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x10, + 0xbeff39e0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x14, + 0x20209b9e, rsc->debug_mode); + + /* Mode - 2 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18, + 0xb9bae5a0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c, + 0xbdbbf9fa, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20, + 0x38999afe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24, + 0xac81e1a1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28, + 0x82e2a2e0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c, + 0x8cfd9d39, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30, + 0xbc20209b, rsc->debug_mode); + + /* tcs sleep & wake sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34, + 0xe601a6fc, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x38, + 0xbc20209c, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x3c, + 0xe701a7fc, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x40, + 0x0000209c, rsc->debug_mode); + + /* branch address */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0, + 0x33, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0, + 0x3b, rsc->debug_mode); + + /* start address */ + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0, + mode_0_start_addr, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0, + mode_0_start_addr, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1, + mode_1_start_addr, + rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2, + mode_2_start_addr, + rsc->debug_mode); + return 0; + +} +static int rsc_hw_seq_memory_init(struct sde_rsc_priv *rsc) +{ + const u32 mode_0_start_addr = 0x0; + const u32 mode_1_start_addr = 0xa; + const u32 mode_2_start_addr = 0x15; + + pr_debug("rsc sequencer memory init\n"); + + /* Mode - 0 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x0, + 0xe0a88bab, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x4, + 0x8babec39, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x8, + 0x8bab2088, rsc->debug_mode); + + /* Mode - 1 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0xc, + 0x39e038a8, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x10, + 0x888babec, rsc->debug_mode); + + /* Mode - 2 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x14, + 0xaaa8a020, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18, + 0xe1a138eb, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c, + 0xe0aca581, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20, + 0x82e2a2ed, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24, + 0x8cea8a39, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28, + 0xe9a92088, rsc->debug_mode); + + /* tcs sleep & wake sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c, + 0x89e686a6, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30, + 0xa7e9a920, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34, + 0x2089e787, rsc->debug_mode); + + /* branch address */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0, + 0x2a, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0, + 0x31, rsc->debug_mode); + + /* start address */ + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0, + mode_0_start_addr, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0, + mode_0_start_addr, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1, + mode_1_start_addr, + rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2, + mode_2_start_addr, + rsc->debug_mode); + + return 0; +} + +static int rsc_hw_solver_init(struct sde_rsc_priv *rsc) +{ + + pr_debug("rsc solver init\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0, + 0xFFFFFFFF, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0, + 0xFFFFFFFF, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_MAX_IDLE_DURATION_DRV0, + 0xEFFFFFFF, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0, + rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0, + rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0, + rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x7, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT0_PRI0_DRV0, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI0_DRV0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI3_DRV0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI0_DRV0, + 0x2, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI3_DRV0, + 0x2, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_MODE_DRV0, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_TIMERS_CONSIDERED_DRV0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_IDLE_TIME_DRV0, + 0x01000010, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0, + 0x80000000, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0, + rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1, + 0x80000000, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1, + rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2, + 0x80000000, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + return 0; +} + +static int rsc_hw_timer_update(struct sde_rsc_priv *rsc) +{ + if (!rsc) { + pr_debug("invalid input param\n"); + return -EINVAL; + } + + pr_debug("rsc hw timer update\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0, + rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0, + rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0, + rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0, + rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1, + rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0, + rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD, + rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode); + + /* make sure that hw timers are updated */ + wmb(); + + return 0; +} + +int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc, enum sde_rsc_state state) +{ + int rc = -EBUSY; + int count, reg; + unsigned long power_status; + + rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_RESTORE); + + /** + * force busy and idle during clk & video mode state because it + * is trying to entry in mode-2 without turning on the vysnc. + */ + if ((state == SDE_RSC_VID_STATE) || (state == SDE_RSC_CLK_STATE)) { + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg &= ~(BIT(8) | BIT(0)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + } + + // needs review with HPG sequence + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + + reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + rsc->debug_mode); + reg &= ~BIT(3); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + reg, rsc->debug_mode); + + if (rsc->version < SDE_RSC_REV_2) { + reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + rsc->debug_mode); + reg |= BIT(13); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + reg, rsc->debug_mode); + } + + /* make sure that mode-2 exit before wait*/ + wmb(); + + /* this wait is required to make sure that gdsc is powered on */ + for (count = MAX_CHECK_LOOPS; count > 0; count--) { + power_status = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_PWR_CTRL, rsc->debug_mode); + if (!test_bit(POWER_CTRL_BIT_12, &power_status)) { + reg = dss_reg_r(&rsc->drv_io, + SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode); + SDE_EVT32_VERBOSE(count, reg, power_status); + rc = 0; + break; + } + usleep_range(10, 100); + } + + if (rsc->version < SDE_RSC_REV_2) { + reg = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + rsc->debug_mode); + reg &= ~BIT(13); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_SPARE_PWR_EVENT, + reg, rsc->debug_mode); + } + + if (rc) + pr_err("vdd reg is not enabled yet\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x3, rsc->debug_mode); + + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg &= ~(BIT(0) | BIT(8)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + wmb(); /* make sure to disable rsc solver state */ + + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg |= (BIT(0) | BIT(8)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + wmb(); /* make sure to enable rsc solver state */ + + rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_RESTORE); + + return rc; +} + +static int sde_rsc_mode2_entry_trigger(struct sde_rsc_priv *rsc) +{ + int rc; + int count, wrapper_status; + unsigned long reg; + + /* update qtimers to high during clk & video mode state */ + if ((rsc->current_state == SDE_RSC_VID_STATE) || + (rsc->current_state == SDE_RSC_CLK_STATE)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + } + + wrapper_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + rsc->debug_mode); + wrapper_status |= BIT(3); + wrapper_status |= BIT(0); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + wrapper_status, rsc->debug_mode); + + /** + * force busy and idle during clk & video mode state because it + * is trying to entry in mode-2 without turning on the vysnc. + */ + if ((rsc->current_state == SDE_RSC_VID_STATE) || + (rsc->current_state == SDE_RSC_CLK_STATE)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(0) | BIT(1), rsc->debug_mode); + wmb(); /* force busy gurantee */ + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(0) | BIT(9), rsc->debug_mode); + } + + /* make sure that mode-2 is triggered before wait*/ + wmb(); + + rc = -EBUSY; + /* this wait is required to turn off the rscc clocks */ + for (count = MAX_CHECK_LOOPS; count > 0; count--) { + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_PWR_CTRL, rsc->debug_mode); + if (test_bit(POWER_CTRL_BIT_12, ®)) { + rc = 0; + break; + } + usleep_range(10, 100); + } + + return rc; +} + +static void sde_rsc_reset_mode_0_1(struct sde_rsc_priv *rsc) +{ + u32 seq_busy, current_mode, curr_inst_addr; + + seq_busy = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0, + rsc->debug_mode); + current_mode = dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0, + rsc->debug_mode); + curr_inst_addr = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_PROGRAM_COUNTER, + rsc->debug_mode); + SDE_EVT32(seq_busy, current_mode, curr_inst_addr); + + if (seq_busy && (current_mode == SDE_RSC_MODE_0_VAL || + current_mode == SDE_RSC_MODE_1_VAL)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0xffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + /* unstick f1 qtimer */ + wmb(); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + /* manually trigger f1 qtimer interrupt */ + wmb(); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + /* unstick f0 qtimer */ + wmb(); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + /* manually trigger f0 qtimer interrupt */ + wmb(); + } +} + +static int sde_rsc_mode2_entry(struct sde_rsc_priv *rsc) +{ + int rc = 0, i; + u32 reg; + + if (rsc->power_collapse_block) + return -EINVAL; + + if (rsc->sw_fs_enabled) { + rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST); + if (rc) { + pr_err("vdd reg fast mode set failed rc:%d\n", rc); + return rc; + } + } + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x7, rsc->debug_mode); + rsc_event_trigger(rsc, SDE_RSC_EVENT_PRE_CORE_PC); + + for (i = 0; i <= MAX_MODE2_ENTRY_TRY; i++) { + rc = sde_rsc_mode2_entry_trigger(rsc); + if (!rc) + break; + + reg = dss_reg_r(&rsc->drv_io, + SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode); + pr_err("mdss gdsc power down failed, instruction:0x%x, rc:%d\n", + reg, rc); + SDE_EVT32(rc, reg, SDE_EVTLOG_ERROR); + + /* avoid touching f1 qtimer for last try */ + if (i != MAX_MODE2_ENTRY_TRY) + sde_rsc_reset_mode_0_1(rsc); + } + + if (rc) + goto end; + + if ((rsc->current_state == SDE_RSC_VID_STATE) || + (rsc->current_state == SDE_RSC_CLK_STATE)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(0) | BIT(8), rsc->debug_mode); + wmb(); /* force busy on vsync */ + } + + rsc_event_trigger(rsc, SDE_RSC_EVENT_POST_CORE_PC); + + if (rsc->sw_fs_enabled) { + regulator_disable(rsc->fs); + rsc->sw_fs_enabled = false; + } + + return 0; + +end: + sde_rsc_mode2_exit(rsc, rsc->current_state); + + return rc; +} + +static int sde_rsc_state_update(struct sde_rsc_priv *rsc, + enum sde_rsc_state state) +{ + int rc = 0; + int reg; + + if (rsc->power_collapse) { + rc = sde_rsc_mode2_exit(rsc, state); + if (rc) + pr_err("power collapse: mode2 exit failed\n"); + else + rsc->power_collapse = false; + } + + switch (state) { + case SDE_RSC_CMD_STATE: + pr_debug("command mode handling\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0, + 0x0, rsc->debug_mode); + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg |= (BIT(0) | BIT(8)); + reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7) | BIT(9)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + /* make sure that solver is enabled */ + wmb(); + + rsc_event_trigger(rsc, SDE_RSC_EVENT_SOLVER_ENABLED); + break; + + case SDE_RSC_VID_STATE: + pr_debug("video mode handling\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg |= BIT(8); + reg &= ~(BIT(1) | BIT(0)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + /* make sure that solver mode is override */ + wmb(); + + rsc_event_trigger(rsc, SDE_RSC_EVENT_SOLVER_DISABLED); + break; + + case SDE_RSC_CLK_STATE: + pr_debug("clk state handling\n"); + + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg &= ~BIT(0); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + /* make sure that solver mode is disabled */ + wmb(); + break; + + case SDE_RSC_IDLE_STATE: + rc = sde_rsc_mode2_entry(rsc); + if (rc) + pr_err("power collapse - mode 2 entry failed\n"); + else + rsc->power_collapse = true; + break; + + default: + pr_err("state:%d handling is not supported\n", state); + break; + } + + return rc; +} + +int rsc_hw_init(struct sde_rsc_priv *rsc) +{ + int rc = 0; + + rc = rsc_hw_qtimer_init(rsc); + if (rc) { + pr_err("rsc hw qtimer init failed\n"); + goto end; + } + + rc = rsc_hw_wrapper_init(rsc); + if (rc) { + pr_err("rsc hw wrapper init failed\n"); + goto end; + } + + if (rsc->version == SDE_RSC_REV_2) + rc = rsc_hw_seq_memory_init_v2(rsc); + else + rc = rsc_hw_seq_memory_init(rsc); + if (rc) { + pr_err("rsc sequencer memory init failed\n"); + goto end; + } + + rc = rsc_hw_solver_init(rsc); + if (rc) { + pr_err("rsc solver init failed\n"); + goto end; + } + + rc = rsc_hw_pdc_init(rsc); + if (rc) { + pr_err("rsc hw pdc init failed\n"); + goto end; + } + + /* make sure that hw is initialized */ + wmb(); + + pr_info("sde rsc init successfully done\n"); +end: + return rc; +} + +int rsc_hw_mode_ctrl(struct sde_rsc_priv *rsc, enum rsc_mode_req request, + char *buffer, int buffer_size, u32 mode) +{ + u32 blen = 0; + u32 slot_time; + + switch (request) { + case MODE_READ: + if (!buffer || !buffer_size) + return blen; + + blen = snprintf(buffer, buffer_size - blen, + "mode_status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0, + rsc->debug_mode)); + break; + + case MODE_UPDATE: + slot_time = mode & BIT(0) ? 0x0 : + rsc->timer_config.rsc_time_slot_2_ns; + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0, + slot_time, rsc->debug_mode); + + slot_time = mode & BIT(1) ? + rsc->timer_config.rsc_time_slot_0_ns : + rsc->timer_config.rsc_time_slot_2_ns; + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0, + slot_time, rsc->debug_mode); + + rsc->power_collapse_block = !(mode & BIT(2)); + break; + + default: + break; + } + + return blen; +} + +int sde_rsc_debug_show(struct seq_file *s, struct sde_rsc_priv *rsc) +{ + seq_printf(s, "override ctrl:0x%x\n", + dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + rsc->debug_mode)); + seq_printf(s, "power ctrl:0x%x\n", + dss_reg_r(&rsc->wrapper_io, SDE_RSCC_PWR_CTRL, + rsc->debug_mode)); + seq_printf(s, "vsycn timestamp0:0x%x\n", + dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0, + rsc->debug_mode)); + seq_printf(s, "vsycn timestamp1:0x%x\n", + dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP1, + rsc->debug_mode)); + + seq_printf(s, "error irq status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_ERROR_IRQ_STATUS_DRV0, + rsc->debug_mode)); + + seq_printf(s, "seq busy status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0, + rsc->debug_mode)); + + seq_printf(s, "solver override ctrl status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0, + rsc->debug_mode)); + seq_printf(s, "solver override status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS0_DRV0, + rsc->debug_mode)); + seq_printf(s, "solver timeslot status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS1_DRV0, + rsc->debug_mode)); + seq_printf(s, "solver mode status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0, + rsc->debug_mode)); + + seq_printf(s, "amc status:0x%x\n", + dss_reg_r(&rsc->drv_io, SDE_RSCC_AMC_TCS_MODE_IRQ_STATUS_DRV0, + rsc->debug_mode)); + + return 0; +} + +int rsc_hw_vsync(struct sde_rsc_priv *rsc, enum rsc_vsync_req request, + char *buffer, int buffer_size, u32 mode) +{ + u32 blen = 0, reg; + + switch (request) { + case VSYNC_READ: + if (!buffer || !buffer_size) + return blen; + + blen = snprintf(buffer, buffer_size - blen, "vsync0:0x%x\n", + dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0, + rsc->debug_mode)); + if (blen >= buffer_size) + return blen; + + blen += snprintf(buffer + blen, buffer_size - blen, + "vsync1:0x%x\n", + dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP1, + rsc->debug_mode)); + break; + + case VSYNC_READ_VSYNC0: + return dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0, + rsc->debug_mode); + + case VSYNC_ENABLE: + /* clear the current VSYNC value */ + reg = BIT(9) | ((mode & 0x7) << 10); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS, + reg, rsc->debug_mode); + + /* enable the VSYNC logging */ + reg = BIT(8) | ((mode & 0x7) << 10); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS, + reg, rsc->debug_mode); + + /* ensure vsync config has been written before waiting on it */ + wmb(); + break; + + case VSYNC_DISABLE: + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS, + 0x0, rsc->debug_mode); + break; + } + + return blen; +} + +void rsc_hw_debug_dump(struct sde_rsc_priv *rsc, u32 mux_sel) +{ + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_BUS, + ((mux_sel & 0xf) << 1) | BIT(0), rsc->debug_mode); +} + +bool rsc_hw_is_amc_mode(struct sde_rsc_priv *rsc) +{ + return dss_reg_r(&rsc->drv_io, SDE_RSCC_TCS_DRV0_CONTROL, + rsc->debug_mode) & BIT(16); +} + +int rsc_hw_tcs_wait(struct sde_rsc_priv *rsc) +{ + int rc = -EBUSY; + int count, seq_status; + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x0, rsc->debug_mode); + seq_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + rsc->debug_mode) & BIT(1); + /* if seq busy - set TCS use OK to high and wait for 200us */ + if (seq_status) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + usleep_range(100, 200); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x0, rsc->debug_mode); + } + + /* check for sequence running status before exiting */ + for (count = (MAX_CHECK_LOOPS / 4); count > 0; count--) { + seq_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + rsc->debug_mode) & BIT(1); + if (!seq_status) { + rc = 0; + break; + } + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + usleep_range(3, 4); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x0, rsc->debug_mode); + } + + return rc; +} + +int rsc_hw_tcs_use_ok(struct sde_rsc_priv *rsc) +{ + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + return 0; +} + +int sde_rsc_hw_register(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware register\n"); + + rsc->hw_ops.init = rsc_hw_init; + rsc->hw_ops.timer_update = rsc_hw_timer_update; + + rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait; + rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok; + rsc->hw_ops.is_amc_mode = rsc_hw_is_amc_mode; + + rsc->hw_ops.hw_vsync = rsc_hw_vsync; + rsc->hw_ops.state_update = sde_rsc_state_update; + rsc->hw_ops.debug_show = sde_rsc_debug_show; + rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl; + rsc->hw_ops.debug_dump = rsc_hw_debug_dump; + + return 0; +} diff --git a/techpack/display/msm/sde_rsc_hw.h b/techpack/display/msm/sde_rsc_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..719962a3f627dd8d20059b8e23540681e4d591e1 --- /dev/null +++ b/techpack/display/msm/sde_rsc_hw.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_RSC_HW_H_ +#define _SDE_RSC_HW_H_ + +#include <linux/kernel.h> +#include <linux/sde_io_util.h> +#include <linux/sde_rsc.h> + +/* display rsc offset */ +#define SDE_RSCC_RSC_ID_DRV0 0x0 +#define SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0 0x020 +#define SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0 0x024 +#define SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0 0x028 +#define SDE_RSCC_PDC_SLAVE_ID_DRV0 0x02c +#define SDE_RSCC_SEQ_PROGRAM_COUNTER 0x408 +#define SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0 0x410 +#define SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0 0x414 +#define SDE_RSCC_SEQ_MEM_0_DRV0 0x600 +#define SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0 0xc14 +#define SDE_RSCC_ERROR_IRQ_STATUS_DRV0 0x0d0 +#define SDE_RSCC_SEQ_BUSY_DRV0 0x404 +#define SDE_RSCC_SOLVER_STATUS0_DRV0 0xc24 +#define SDE_RSCC_SOLVER_STATUS1_DRV0 0xc28 +#define SDE_RSCC_SOLVER_STATUS2_DRV0 0xc2c +#define SDE_RSCC_AMC_TCS_MODE_IRQ_STATUS_DRV0 0x1c00 + +#define SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0 0xc04 +#define SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0 0xc08 +#define SDE_RSCC_MAX_IDLE_DURATION_DRV0 0xc0c +#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0 0x1000 +#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0 0x1004 +#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0 0x1008 +#define SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0 0x100c + +#define SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0 0xc20 +#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT0_PRI0_DRV0 0x1080 +#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI0_DRV0 0x1100 +#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI3_DRV0 0x110c +#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI0_DRV0 0x1180 +#define SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI3_DRV0 0x118c + +#define SDE_RSC_SOLVER_OVERRIDE_MODE_DRV0 0xc18 +#define SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0 0xc14 +#define SDE_RSC_TIMERS_CONSIDERED_DRV0 0xc00 +#define SDE_RSC_SOLVER_OVERRIDE_IDLE_TIME_DRV0 0xc1c + +#define SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0 0xc30 +#define SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0 0xc34 +#define SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0 0xc38 +#define SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0 0xc40 + +#define SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1 0xc4c +#define SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1 0xc50 +#define SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1 0xc54 +#define SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1 0xc5c + +#define SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2 0xc68 +#define SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2 0xc6c +#define SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2 0xc70 +#define SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2 0xc78 + +#define SDE_RSCC_TCS_DRV0_CONTROL 0x1c14 + +#define SDE_RSCC_WRAPPER_CTRL 0x000 +#define SDE_RSCC_WRAPPER_OVERRIDE_CTRL 0x004 +#define SDE_RSCC_WRAPPER_STATIC_WAKEUP_0 0x008 +#define SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD 0x00c +#define SDE_RSCC_WRAPPER_DEBUG_BUS 0x010 +#define SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP0 0x018 +#define SDE_RSCC_WRAPPER_VSYNC_TIMESTAMP1 0x01c +#define SDE_RSCC_SPARE_PWR_EVENT 0x020 +#define SDE_RSCC_PWR_CTRL 0x024 +#define SDE_RSCC_WRAPPER_OVERRIDE_CTRL2 0x040 +#define SDE_RSCC_WRAPPER_MODE_MIN_THRESHOLD 0x044 +#define SDE_RSCC_WRAPPER_BW_INDICATION 0x048 +#define SDE_RSCC_WRAPPER_DEBUG_CTRL2 0x050 + +/* qtimer offset */ +#define SDE_RSCC_QTMR_AC_HW_FRAME_SEL_1 0x1FE0 +#define SDE_RSCC_QTMR_AC_HW_FRAME_SEL_2 0x1FF0 +#define SDE_RSCC_QTMR_AC_CNTACR0_FG0 0x1040 +#define SDE_RSCC_QTMR_AC_CNTACR1_FG0 0x1044 +#define SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO 0x2020 +#define SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI 0x2024 +#define SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO 0x3020 +#define SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI 0x3024 +#define SDE_RSCC_F0_QTMR_V1_CNTP_CTL 0x202C +#define SDE_RSCC_F1_QTMR_V1_CNTP_CTL 0x302C + +#define MAX_CHECK_LOOPS 500 +#define POWER_CTRL_BIT_12 12 + +#define SDE_RSC_MODE_0_VAL 0 +#define SDE_RSC_MODE_1_VAL 1 +#define MAX_MODE2_ENTRY_TRY 3 + +int rsc_hw_vsync(struct sde_rsc_priv *rsc, enum rsc_vsync_req request, + char *buffer, int buffer_size, u32 mode); + +bool rsc_hw_is_amc_mode(struct sde_rsc_priv *rsc); + +void rsc_hw_debug_dump(struct sde_rsc_priv *rsc, u32 mux_sel); + +int sde_rsc_debug_show(struct seq_file *s, struct sde_rsc_priv *rsc); + +int rsc_hw_mode_ctrl(struct sde_rsc_priv *rsc, enum rsc_mode_req request, + char *buffer, int buffer_size, u32 mode); + +int sde_rsc_mode2_exit(struct sde_rsc_priv *rsc, enum sde_rsc_state state); + +int rsc_hw_tcs_use_ok(struct sde_rsc_priv *rsc); + +int rsc_hw_tcs_wait(struct sde_rsc_priv *rsc); + +#endif /* _SDE_RSC_HW_H_ */ diff --git a/techpack/display/msm/sde_rsc_hw_v3.c b/techpack/display/msm/sde_rsc_hw_v3.c new file mode 100644 index 0000000000000000000000000000000000000000..d3a589ccf301837d39a485fe5ca0f8087af0dbad --- /dev/null +++ b/techpack/display/msm/sde_rsc_hw_v3.c @@ -0,0 +1,632 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[sde_rsc_hw:%s:%d]: " fmt, __func__, __LINE__ + +#include <linux/kernel.h> +#include <linux/debugfs.h> +#include <linux/delay.h> + +#include "sde_rsc_priv.h" +#include "sde_rsc_hw.h" +#include "sde_dbg.h" + +static int _rsc_hw_qtimer_init(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware qtimer init\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_1, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_HW_FRAME_SEL_2, + 0xffffffff, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR0_FG0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_QTMR_AC_CNTACR1_FG0, + 0x1, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CTL, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CTL, + 0x1, rsc->debug_mode); + + return 0; +} + +static int _rsc_hw_pdc_init(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware pdc init\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SEQ_START_ADDR_REG_OFFSET_DRV0, + 0x4520, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_LO_REG_OFFSET_DRV0, + 0x4510, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_MATCH_VALUE_HI_REG_OFFSET_DRV0, + 0x4514, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_PDC_SLAVE_ID_DRV0, + 0x1, rsc->debug_mode); + + return 0; +} + +static int _rsc_hw_wrapper_init(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware wrapper init\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0, + rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD, + rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(8), rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_MODE_MIN_THRESHOLD, + rsc->timer_config.min_threshold_time_ns, rsc->debug_mode); + + return 0; +} + +static int _rsc_hw_seq_memory_init_v3(struct sde_rsc_priv *rsc) +{ + const u32 mode_0_start_addr = 0x0; + const u32 mode_1_start_addr = 0xc; + const u32 mode_2_start_addr = 0x18; + u32 br_offset = 0; + + pr_debug("rsc sequencer memory init v2\n"); + + /* Mode - 0 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x0, + 0xff399ebe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x4, + 0x20209ebe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x8, + 0x20202020, rsc->debug_mode); + + /* Mode - 1 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0xc, + 0xe0389ebe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x10, + 0x9ebeff39, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x14, + 0x20202020, rsc->debug_mode); + + /* Mode - 2 sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x18, + 0xbdf9b9a0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x1c, + 0xa13899fe, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x20, + 0xe0ac81e1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x24, + 0x3982e2a2, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x28, + 0x208cfd9d, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x2c, + 0x20202020, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x30, + 0x20202020, rsc->debug_mode); + + /* tcs sleep & wake sequence */ + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x34, + 0x01a6fcbc, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x38, + 0x20209ce6, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x3c, + 0x01a7fcbc, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_MEM_0_DRV0 + 0x40, + 0x00209ce7, rsc->debug_mode); + + /* branch address */ + if (rsc->hw_drv_ver == SDE_RSC_HW_MAJOR_MINOR_STEP(2, 0, 5) || + rsc->hw_drv_ver == SDE_RSC_HW_MAJOR_MINOR_STEP(1, 9, 0)) + br_offset = 0xf0; + + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_0_DRV0 + br_offset, + 0x34, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SEQ_CFG_BR_ADDR_1_DRV0 + br_offset, + 0x3c, rsc->debug_mode); + + /* start address */ + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_CTRL_DRV0, + mode_0_start_addr, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE0, + mode_0_start_addr, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE1, + mode_1_start_addr, + rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM0_DRV0_MODE2, + mode_2_start_addr, + rsc->debug_mode); + return 0; +} + +static int _rsc_hw_solver_init(struct sde_rsc_priv *rsc) +{ + + pr_debug("rsc solver init\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_LO_DRV0, + 0xFFFFFFFF, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOFT_WAKEUP_TIME_HI_DRV0, + 0xFFFFFFFF, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_MAX_IDLE_DURATION_DRV0, + 0xEFFFFFFF, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_0_DRV0, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0, + rsc->timer_config.bwi_threshold_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0, + rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0, + rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x7, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT0_PRI0_DRV0, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI0_DRV0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT1_PRI3_DRV0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI0_DRV0, + 0x2, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PRI_TABLE_SLOT2_PRI3_DRV0, + 0x2, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_MODE_DRV0, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_TIMERS_CONSIDERED_DRV0, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_OVERRIDE_IDLE_TIME_DRV0, + 0x01000010, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE0, + 0x80000000, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0, + rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE1, + 0x80000000, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1, + rsc->timer_config.rsc_backoff_time_ns * 2, + rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM1_DRV0_MODE2, + 0x80000000, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE2, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + return 0; +} + +static int sde_rsc_mode2_entry_trigger(struct sde_rsc_priv *rsc) +{ + int rc; + int count, wrapper_status, ctrl2_status; + unsigned long reg; + + /* update qtimers to high during clk & video mode state */ + if ((rsc->current_state == SDE_RSC_VID_STATE) || + (rsc->current_state == SDE_RSC_CLK_STATE)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + } + + wrapper_status = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + rsc->debug_mode); + wrapper_status |= BIT(3); + wrapper_status |= BIT(0); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + wrapper_status, rsc->debug_mode); + + ctrl2_status = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, rsc->debug_mode); + ctrl2_status &= ~BIT(3); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, + ctrl2_status, rsc->debug_mode); + wmb(); /* make sure that vsync source is disabled */ + + + /** + * force busy and idle during clk & video mode state because it + * is trying to entry in mode-2 without turning on the vysnc. + */ + if ((rsc->current_state == SDE_RSC_VID_STATE) || + (rsc->current_state == SDE_RSC_CLK_STATE)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(0) | BIT(1), rsc->debug_mode); + wmb(); /* force busy gurantee */ + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(0) | BIT(9), rsc->debug_mode); + } + + wmb(); /* make sure that mode-2 is triggered before wait*/ + + rc = -EBUSY; + /* this wait is required to turn off the rscc clocks */ + for (count = MAX_CHECK_LOOPS; count > 0; count--) { + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_PWR_CTRL, rsc->debug_mode); + if (test_bit(POWER_CTRL_BIT_12, ®)) { + rc = 0; + break; + } + usleep_range(50, 100); + } + + return rc; +} + +static void sde_rsc_reset_mode_0_1(struct sde_rsc_priv *rsc) +{ + u32 seq_busy, current_mode, curr_inst_addr; + + seq_busy = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_BUSY_DRV0, + rsc->debug_mode); + current_mode = dss_reg_r(&rsc->drv_io, SDE_RSCC_SOLVER_STATUS2_DRV0, + rsc->debug_mode); + curr_inst_addr = dss_reg_r(&rsc->drv_io, SDE_RSCC_SEQ_PROGRAM_COUNTER, + rsc->debug_mode); + SDE_EVT32(seq_busy, current_mode, curr_inst_addr); + + if (seq_busy && (current_mode == SDE_RSC_MODE_0_VAL || + current_mode == SDE_RSC_MODE_1_VAL)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0xffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + wmb(); /* unstick f1 qtimer */ + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F1_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + wmb(); /* manually trigger f1 qtimer interrupt */ + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0xffffff, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0xffffffff, rsc->debug_mode); + wmb(); /* unstick f0 qtimer */ + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_HI, + 0x0, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_F0_QTMR_V1_CNTP_CVAL_LO, + 0x0, rsc->debug_mode); + wmb(); /* manually trigger f0 qtimer interrupt */ + } +} + +static int sde_rsc_mode2_entry_v3(struct sde_rsc_priv *rsc) +{ + int rc = 0, i; + u32 reg; + + if (rsc->power_collapse_block) + return -EINVAL; + + if (rsc->sw_fs_enabled) { + rc = regulator_set_mode(rsc->fs, REGULATOR_MODE_FAST); + if (rc) { + pr_err("vdd reg fast mode set failed rc:%d\n", rc); + return rc; + } + } + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_SOLVER_MODES_ENABLED_DRV0, + 0x7, rsc->debug_mode); + + /** + * increase delay time to wait before mode2 entry, + * longer time required subsequent to panel mode change + */ + if (rsc->post_poms) + usleep_range(750, 1000); + for (i = 0; i <= MAX_MODE2_ENTRY_TRY; i++) { + rc = sde_rsc_mode2_entry_trigger(rsc); + if (!rc) + break; + + reg = dss_reg_r(&rsc->drv_io, + SDE_RSCC_SEQ_PROGRAM_COUNTER, rsc->debug_mode); + pr_err("mdss gdsc power down failed, instruction:0x%x, rc:%d\n", + reg, rc); + SDE_EVT32(rc, reg, SDE_EVTLOG_ERROR); + + /* avoid touching f1 qtimer for last try */ + if (i != MAX_MODE2_ENTRY_TRY) + sde_rsc_reset_mode_0_1(rsc); + } + + if (rc) + goto end; + + if ((rsc->current_state == SDE_RSC_VID_STATE) || + (rsc->current_state == SDE_RSC_CLK_STATE)) { + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + BIT(0) | BIT(8), rsc->debug_mode); + wmb(); /* force busy on vsync */ + } + + if (rsc->sw_fs_enabled) { + regulator_disable(rsc->fs); + rsc->sw_fs_enabled = false; + } + + return 0; + +end: + sde_rsc_mode2_exit(rsc, rsc->current_state); + + return rc; +} + +static int sde_rsc_state_update_v3(struct sde_rsc_priv *rsc, + enum sde_rsc_state state) +{ + int rc = 0; + int reg, ctrl2_config; + + if (rsc->power_collapse) { + rc = sde_rsc_mode2_exit(rsc, state); + if (rc) + pr_err("power collapse: mode2 exit failed\n"); + else + rsc->power_collapse = false; + } + + switch (state) { + case SDE_RSC_CMD_STATE: + pr_debug("command mode handling\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + 0x0, rsc->debug_mode); + wmb(); /* disable double buffer config before vsync select */ + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, + BIT(1) | BIT(2) | BIT(3), rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0, + 0x0, rsc->debug_mode); + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg |= (BIT(0) | BIT(8)); + reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7) | BIT(9)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + wmb(); /* make sure that solver is enabled */ + + break; + + case SDE_RSC_VID_STATE: + pr_debug("video mode handling\n"); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + 0x0, rsc->debug_mode); + wmb(); /* disable double buffer config before vsync select */ + + ctrl2_config = (rsc->vsync_source & 0x7) << 4; + ctrl2_config |= (BIT(0) | BIT(1) | BIT(3)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, + ctrl2_config, rsc->debug_mode); + wmb(); /* select vsync before double buffer config enabled */ + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSCC_SOLVER_OVERRIDE_CTRL_DRV0, + 0x0, rsc->debug_mode); + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg |= (BIT(0) | BIT(8)); + reg &= ~(BIT(1) | BIT(2) | BIT(3) | BIT(6) | BIT(7) | BIT(9)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + wmb(); /* make sure that solver is enabled */ + + break; + + case SDE_RSC_CLK_STATE: + pr_debug("clk state handling\n"); + + ctrl2_config = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, rsc->debug_mode); + ctrl2_config &= ~(BIT(0) | BIT(1) | BIT(2)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL2, + ctrl2_config, rsc->debug_mode); + + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg &= ~(BIT(0) | BIT(8)); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + wmb(); /* make sure that solver mode is disabled */ + + reg = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_OVERRIDE_CTRL, rsc->debug_mode); + reg |= BIT(8); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_OVERRIDE_CTRL, + reg, rsc->debug_mode); + wmb(); /* enable double buffer vsync configuration */ + break; + + case SDE_RSC_IDLE_STATE: + rc = sde_rsc_mode2_entry_v3(rsc); + if (rc) + pr_err("power collapse - mode 2 entry failed\n"); + else + rsc->power_collapse = true; + break; + + default: + pr_err("state:%d handling is not supported\n", state); + break; + } + + return rc; +} + +int rsc_hw_init_v3(struct sde_rsc_priv *rsc) +{ + int rc = 0; + + rsc->hw_drv_ver = dss_reg_r(&rsc->drv_io, + SDE_RSCC_RSC_ID_DRV0, rsc->debug_mode); + + rc = _rsc_hw_qtimer_init(rsc); + if (rc) { + pr_err("rsc hw qtimer init failed\n"); + goto end; + } + + rc = _rsc_hw_wrapper_init(rsc); + if (rc) { + pr_err("rsc hw wrapper init failed\n"); + goto end; + } + + rc = _rsc_hw_seq_memory_init_v3(rsc); + if (rc) { + pr_err("rsc sequencer memory init failed\n"); + goto end; + } + + rc = _rsc_hw_solver_init(rsc); + if (rc) { + pr_err("rsc solver init failed\n"); + goto end; + } + + rc = _rsc_hw_pdc_init(rsc); + if (rc) { + pr_err("rsc hw pdc init failed\n"); + goto end; + } + + wmb(); /* make sure that hw is initialized */ + + pr_info("sde rsc init successfully done\n"); +end: + return rc; +} + +int rsc_hw_bwi_status_v3(struct sde_rsc_priv *rsc, bool bw_indication) +{ + int count, bw_ack; + int rc = 0; + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_BW_INDICATION, + bw_indication, rsc->debug_mode); + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_CTRL, + 0x1, rsc->debug_mode); + + bw_ack = dss_reg_r(&rsc->wrapper_io, SDE_RSCC_WRAPPER_DEBUG_CTRL2, + rsc->debug_mode) & BIT(14); + + /* check for sequence running status before exiting */ + for (count = MAX_CHECK_LOOPS; count > 0 && !bw_ack; count--) { + usleep_range(8, 10); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_BW_INDICATION, + bw_indication, rsc->debug_mode); + bw_ack = dss_reg_r(&rsc->wrapper_io, + SDE_RSCC_WRAPPER_DEBUG_CTRL2, rsc->debug_mode) & BIT(14); + } + + if (!bw_ack) + rc = -EINVAL; + + return rc; +} + +static int rsc_hw_timer_update_v3(struct sde_rsc_priv *rsc) +{ + if (!rsc) { + pr_debug("invalid input param\n"); + return -EINVAL; + } + + pr_debug("rsc hw timer update\n"); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_1_DRV0, + rsc->timer_config.rsc_time_slot_0_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_2_DRV0, + rsc->timer_config.rsc_time_slot_1_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_TIME_SLOT_TABLE_3_DRV0, + rsc->timer_config.rsc_time_slot_2_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE0, + rsc->timer_config.rsc_backoff_time_ns, rsc->debug_mode); + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE0, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM2_DRV0_MODE1, + rsc->timer_config.rsc_backoff_time_ns * 2, + rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE1, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->drv_io, SDE_RSC_SOLVER_MODE_PARM3_DRV0_MODE2, + rsc->timer_config.pdc_backoff_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_STATIC_WAKEUP_0, + rsc->timer_config.static_wakeup_time_ns, rsc->debug_mode); + + dss_reg_w(&rsc->wrapper_io, SDE_RSCC_WRAPPER_RSCC_MODE_THRESHOLD, + rsc->timer_config.rsc_mode_threshold_time_ns, rsc->debug_mode); + + /* make sure that hw timers are updated */ + wmb(); + + return 0; +} + +int sde_rsc_hw_register_v3(struct sde_rsc_priv *rsc) +{ + pr_debug("rsc hardware register v3\n"); + + rsc->hw_ops.init = rsc_hw_init_v3; + rsc->hw_ops.state_update = sde_rsc_state_update_v3; + rsc->hw_ops.bwi_status = rsc_hw_bwi_status_v3; + rsc->hw_ops.timer_update = rsc_hw_timer_update_v3; + + rsc->hw_ops.tcs_wait = rsc_hw_tcs_wait; + rsc->hw_ops.tcs_use_ok = rsc_hw_tcs_use_ok; + rsc->hw_ops.is_amc_mode = rsc_hw_is_amc_mode; + rsc->hw_ops.hw_vsync = rsc_hw_vsync; + rsc->hw_ops.debug_show = sde_rsc_debug_show; + rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl; + rsc->hw_ops.debug_dump = rsc_hw_debug_dump; + + return 0; +} diff --git a/techpack/display/msm/sde_rsc_priv.h b/techpack/display/msm/sde_rsc_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..4779506a28143a9e5e074ab9da6b25698701244f --- /dev/null +++ b/techpack/display/msm/sde_rsc_priv.h @@ -0,0 +1,253 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_RSC_PRIV_H_ +#define _SDE_RSC_PRIV_H_ + +#include <linux/kernel.h> +#include <linux/sde_io_util.h> +#include <linux/sde_rsc.h> + +#include <soc/qcom/tcs.h> +#include "sde_power_handle.h" + +#define SDE_RSC_COMPATIBLE "disp_rscc" + +#define MAX_RSC_COUNT 5 + +#define ALL_MODES_DISABLED 0x0 +#define ONLY_MODE_0_ENABLED 0x1 +#define ONLY_MODE_0_1_ENABLED 0x3 +#define ALL_MODES_ENABLED 0x7 + +#define MAX_COUNT_SIZE_SUPPORTED 128 + +#define SDE_RSC_REV_1 0x1 +#define SDE_RSC_REV_2 0x2 +#define SDE_RSC_REV_3 0x3 + +#define SDE_RSC_HW_MAJOR_MINOR_STEP(major, minor, step) \ + (((major & 0xff) << 16) |\ + ((minor & 0xff) << 8) | \ + (step & 0xff)) + +struct sde_rsc_priv; + +/** + * rsc_mode_req: sde rsc mode request information + * MODE_READ: read vsync status + * MODE_UPDATE: mode timeslot update + * 0x0: all modes are disabled. + * 0x1: Mode-0 is enabled and other two modes are disabled. + * 0x3: Mode-0 & Mode-1 are enabled and mode-2 is disabled. + * 0x7: all modes are enabled. + */ +enum rsc_mode_req { + MODE_READ, + MODE_UPDATE = 0x1, +}; + +/** + * rsc_vsync_req: sde rsc vsync request information + * VSYNC_READ: read vsync status + * VSYNC_READ_VSYNC0: read value vsync0 timestamp (cast to int from u32) + * VSYNC_ENABLE: enable rsc wrapper vsync status + * VSYNC_DISABLE: disable rsc wrapper vsync status + */ +enum rsc_vsync_req { + VSYNC_READ, + VSYNC_READ_VSYNC0, + VSYNC_ENABLE, + VSYNC_DISABLE, +}; + +/** + * struct sde_rsc_hw_ops - sde resource state coordinator hardware ops + * @init: Initialize the sequencer, solver, qtimer, + etc. hardware blocks on RSC. + * @timer_update: update the static wrapper time and pdc/rsc + backoff time. + * @tcs_wait: Waits for TCS block OK to allow sending a + * TCS command. + * @hw_vsync: Enables the vsync on RSC block. + * @tcs_use_ok: set TCS set to high to allow RSC to use it. + * @bwi_status: It updates the BW increase/decrease status. + * @is_amc_mode: Check current amc mode status + * @debug_dump: dump debug bus registers or enable debug bus + * @state_update: Enable/override the solver based on rsc state + * status (command/video) + * @mode_show: shows current mode status, mode0/1/2 + * @debug_show: Show current debug status. + */ + +struct sde_rsc_hw_ops { + int (*init)(struct sde_rsc_priv *rsc); + int (*timer_update)(struct sde_rsc_priv *rsc); + int (*tcs_wait)(struct sde_rsc_priv *rsc); + int (*hw_vsync)(struct sde_rsc_priv *rsc, enum rsc_vsync_req request, + char *buffer, int buffer_size, u32 mode); + int (*tcs_use_ok)(struct sde_rsc_priv *rsc); + int (*bwi_status)(struct sde_rsc_priv *rsc, bool bw_indication); + bool (*is_amc_mode)(struct sde_rsc_priv *rsc); + void (*debug_dump)(struct sde_rsc_priv *rsc, u32 mux_sel); + int (*state_update)(struct sde_rsc_priv *rsc, enum sde_rsc_state state); + int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc); + int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request, + char *buffer, int buffer_size, u32 mode); +}; + +/** + * struct sde_rsc_timer_config: this is internal configuration between + * rsc and rsc_hw API. + * + * @static_wakeup_time_ns: wrapper backoff time in nano seconds + * @rsc_backoff_time_ns: rsc backoff time in nano seconds + * @pdc_backoff_time_ns: pdc backoff time in nano seconds + * @rsc_mode_threshold_time_ns: rsc mode threshold time in nano seconds + * @rsc_time_slot_0_ns: mode-0 time slot threshold in nano seconds + * @rsc_time_slot_1_ns: mode-1 time slot threshold in nano seconds + * @rsc_time_slot_2_ns: mode-2 time slot threshold in nano seconds + * + * @min_threshold_time_ns: minimum time required to enter & exit mode0 + * @bwi_threshold_time_ns: worst case time to increase the BW vote + */ +struct sde_rsc_timer_config { + u32 static_wakeup_time_ns; + + u32 rsc_backoff_time_ns; + u32 pdc_backoff_time_ns; + u32 rsc_mode_threshold_time_ns; + u32 rsc_time_slot_0_ns; + u32 rsc_time_slot_1_ns; + u32 rsc_time_slot_2_ns; + + u32 min_threshold_time_ns; + u32 bwi_threshold_time_ns; +}; + +/** + * struct sde_rsc_bw_config: bandwidth configuration + * + * @ab_vote: Stored ab_vote for SDE_POWER_HANDLE_DBUS_ID_MAX + * @ib_vote: Stored ib_vote for SDE_POWER_HANDLE_DBUS_ID_MAX + * @new_ab_vote: ab_vote for incoming frame. + * @new_ib_vote: ib_vote for incoming frame. + */ +struct sde_rsc_bw_config { + u64 ab_vote[SDE_POWER_HANDLE_DBUS_ID_MAX]; + u64 ib_vote[SDE_POWER_HANDLE_DBUS_ID_MAX]; + + u64 new_ab_vote[SDE_POWER_HANDLE_DBUS_ID_MAX]; + u64 new_ib_vote[SDE_POWER_HANDLE_DBUS_ID_MAX]; +}; +/** + * struct sde_rsc_priv: sde resource state coordinator(rsc) private handle + * @version: rsc sequence version + * @hw_drv_ver: rscc hw version + * @phandle: module power handle for clocks + * @fs: "MDSS GDSC" handle + * @sw_fs_enabled: track "MDSS GDSC" sw vote during probe + * + * @rpmh_dev: rpmh device node + * @drv_io: sde drv io data mapping + * @wrapper_io: wrapper io data mapping + * + * @client_list: current rsc client list handle + * @event_list: current rsc event list handle + * @client_lock: current rsc client synchronization lock + * + * timer_config: current rsc timer configuration + * cmd_config: current panel config + * current_state: current rsc state (video/command), solver + * override/enabled. + * vsync_source: Interface index to provide the vsync ticks + * debug_mode: enables the logging for each register read/write + * debugfs_root: debugfs file system root node + * + * hw_ops: sde rsc hardware operations + * power_collapse: if all clients are in IDLE state then it enters in + * mode2 state and enable the power collapse state + * power_collapse_block:By default, rsc move to mode-2 if all clients are in + * invalid state. It can be blocked by this boolean entry. + * primary_client: A client which is allowed to make command state request + * and ab/ib vote on display rsc + * single_tcs_execution_time: worst case time to execute one tcs vote + * (sleep/wake) + * backoff_time_ns: time to only wake tcs in any mode + * mode_threshold_time_ns: time to wake TCS in mode-0, must be greater than + * backoff time + * time_slot_0_ns: time for sleep & wake TCS in mode-1 + * master_drm: Primary client waits for vsync on this drm object based + * on crtc id + * rsc_vsync_wait: Refcount to indicate if we have to wait for the vsync. + * rsc_vsync_waitq: Queue to wait for the vsync. + * bw_config: check sde_rsc_bw_config structure description. + * dev: rsc device node + * resource_refcount: Track rsc resource refcount + * post_poms: bool if a panel mode change occurred + */ +struct sde_rsc_priv { + u32 version; + u32 hw_drv_ver; + struct sde_power_handle phandle; + struct regulator *fs; + bool sw_fs_enabled; + + struct device *rpmh_dev; + struct dss_io_data drv_io; + struct dss_io_data wrapper_io; + + struct list_head client_list; + struct list_head event_list; + struct mutex client_lock; + + struct sde_rsc_timer_config timer_config; + struct sde_rsc_cmd_config cmd_config; + u32 current_state; + u32 vsync_source; + + u32 debug_mode; + struct dentry *debugfs_root; + + struct sde_rsc_hw_ops hw_ops; + bool power_collapse; + bool power_collapse_block; + struct sde_rsc_client *primary_client; + + u32 single_tcs_execution_time; + u32 backoff_time_ns; + u32 mode_threshold_time_ns; + u32 time_slot_0_ns; + + struct drm_device *master_drm; + atomic_t rsc_vsync_wait; + wait_queue_head_t rsc_vsync_waitq; + + struct sde_rsc_bw_config bw_config; + struct device *dev; + atomic_t resource_refcount; + + bool post_poms; +}; + +/** + * sde_rsc_hw_register() - register hardware API. It manages V1 and V2 support. + * + * @client: Client pointer provided by sde_rsc_client_create(). + * + * Return: error code. + */ +int sde_rsc_hw_register(struct sde_rsc_priv *rsc); + +/** + * sde_rsc_hw_register_v3() - register hardware API. It manages V3 support. + * + * @client: Client pointer provided by sde_rsc_client_create(). + * + * Return: error code. + */ +int sde_rsc_hw_register_v3(struct sde_rsc_priv *rsc); + +#endif /* _SDE_RSC_PRIV_H_ */ diff --git a/techpack/display/pll/Makefile b/techpack/display/pll/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0b29a90caf87e1258923933f785537f85f1dcc5d --- /dev/null +++ b/techpack/display/pll/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y := -I$(srctree)/drivers/clk/qcom/ + +obj-$(CONFIG_QCOM_MDSS_PLL) += pll_util.o +obj-$(CONFIG_QCOM_MDSS_PLL) += pll_drv.o +obj-$(CONFIG_QCOM_MDSS_PLL) += dsi_pll_10nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += dsi_pll_7nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += dsi_pll_28lpm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += dsi_pll_28nm_util.o +obj-$(CONFIG_QCOM_MDSS_PLL) += dsi_pll_14nm.o +obj-$(CONFIG_QCOM_MDSS_PLL) += dsi_pll_14nm_util.o +obj-$(CONFIG_QCOM_MDSS_PLL) += hdmi_pll_28lpm.o +obj-$(CONFIG_QCOM_MDSS_DP_PLL) += dp_pll_7nm.o \ + dp_pll_7nm_util.o \ + dp_pll_10nm.o \ + dp_pll_10nm_util.o \ + dp_pll_14nm.o \ diff --git a/techpack/display/pll/dp_pll.h b/techpack/display/pll/dp_pll.h new file mode 100644 index 0000000000000000000000000000000000000000..2ef735833002b76db6a320217f5e924ac661f009 --- /dev/null +++ b/techpack/display/pll/dp_pll.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_DP_PLL_H +#define __MDSS_DP_PLL_H + +struct dp_pll_vco_clk { + struct clk_hw hw; + unsigned long rate; /* current vco rate */ + u64 min_rate; /* min vco rate */ + u64 max_rate; /* max vco rate */ + void *priv; +}; + +static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw) +{ + return container_of(hw, struct dp_pll_vco_clk, hw); +} + +#ifdef CONFIG_QCOM_MDSS_DP_PLL +int dp_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int dp_pll_clock_register_10nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int dp_pll_clock_register_7nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); +#else +static inline int dp_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return 0; +} + +static inline int dp_pll_clock_register_10nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return 0; +} + +static inline int dp_pll_clock_register_7nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return 0; +} +#endif +#endif /* __MDSS_DP_PLL_H */ diff --git a/techpack/display/pll/dp_pll_10nm.c b/techpack/display/pll/dp_pll_10nm.c new file mode 100644 index 0000000000000000000000000000000000000000..926723ff0769abe67cb636f51cda256d9550ab61 --- /dev/null +++ b/techpack/display/pll/dp_pll_10nm.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------------+ + * | DP_VCO_CLK | + * | | + * | +-------------------+ | + * | | (DP PLL/VCO) | | + * | +---------+---------+ | + * | v | + * | +----------+-----------+ | + * | | hsclk_divsel_clk_src | | + * | +----------+-----------+ | + * +------------------------------+ + * | + * +------------<---------v------------>----------+ + * | | + * +-----v------------+ | + * | dp_link_clk_src | | + * | divsel_ten | | + * +---------+--------+ | + * | | + * | | + * v v + * Input to DISPCC block | + * for link clk, crypto clk | + * and interface clock | + * | + * | + * +--------<------------+-----------------+---<---+ + * | | | + * +-------v------+ +--------v-----+ +--------v------+ + * | vco_divided | | vco_divided | | vco_divided | + * | _clk_src | | _clk_src | | _clk_src | + * | | | | | | + * |divsel_six | | divsel_two | | divsel_four | + * +-------+------+ +-----+--------+ +--------+------+ + * | | | + * v------->----------v-------------<------v + * | + * +----------+---------+ + * | vco_divided_clk | + * | _src_mux | + * +---------+----------+ + * | + * v + * Input to DISPCC block + * for DP pixel clock + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <dt-bindings/clock/mdss-10nm-pll-clk.h> + +#include "pll_drv.h" +#include "dp_pll.h" +#include "dp_pll_10nm.h" + +static struct dp_pll_db dp_pdb; +static struct clk_ops mux_clk_ops; + +static struct regmap_config dp_pll_10nm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x910, +}; + +static struct regmap_bus dp_pixel_mux_regmap_ops = { + .reg_write = dp_mux_set_parent_10nm, + .reg_read = dp_mux_get_parent_10nm, +}; + +/* Op structures */ +static const struct clk_ops dp_10nm_vco_clk_ops = { + .recalc_rate = dp_vco_recalc_rate_10nm, + .set_rate = dp_vco_set_rate_10nm, + .round_rate = dp_vco_round_rate_10nm, + .prepare = dp_vco_prepare_10nm, + .unprepare = dp_vco_unprepare_10nm, +}; + +static struct dp_pll_vco_clk dp_vco_clk = { + .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000, + .max_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000, + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_clk", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &dp_10nm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor dp_phy_pll_link_clk = { + .div = 10, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_phy_pll_link_clk", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_six_clk_src = { + .div = 6, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_six_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + + +static int clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int ret = 0; + + ret = __clk_mux_determine_rate_closest(hw, req); + if (ret) + return ret; + + /* Set the new parent of mux if there is a new valid parent */ + if (hw->clk && req->best_parent_hw->clk) + clk_set_parent(hw->clk, req->best_parent_hw->clk); + + return 0; +} + +static unsigned long mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk *div_clk = NULL, *vco_clk = NULL; + struct dp_pll_vco_clk *vco = NULL; + + div_clk = clk_get_parent(hw->clk); + if (!div_clk) + return 0; + + vco_clk = clk_get_parent(div_clk); + if (!vco_clk) + return 0; + + vco = to_dp_vco_hw(__clk_get_hw(vco_clk)); + if (!vco) + return 0; + + if (vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) + return (vco->rate / 6); + else if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + return (vco->rate / 4); + else + return (vco->rate / 2); +} + +static struct clk_regmap_mux dp_phy_pll_vco_div_clk = { + .reg = 0x64, + .shift = 0, + .width = 2, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dp_phy_pll_vco_div_clk", + .parent_names = + (const char *[]){"dp_vco_divsel_two_clk_src", + "dp_vco_divsel_four_clk_src", + "dp_vco_divsel_six_clk_src"}, + .num_parents = 3, + .ops = &mux_clk_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + }, + }, +}; + +static struct clk_hw *mdss_dp_pllcc_10nm[] = { + [DP_VCO_CLK] = &dp_vco_clk.hw, + [DP_PHY_PLL_LINK_CLK] = &dp_phy_pll_link_clk.hw, + [DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw, + [DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw, + [DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw, + [DP_PHY_PLL_VCO_DIV_CLK] = &dp_phy_pll_vco_div_clk.clkr.hw, +}; + +int dp_pll_clock_register_10nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i = 0; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dp_pllcc_10nm); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + pll_res->priv = &dp_pdb; + dp_pdb.pll = pll_res; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops, + pll_res, &dp_pll_10nm_cfg); + dp_phy_pll_vco_div_clk.clkr.regmap = regmap; + mux_clk_ops = clk_regmap_mux_closest_ops; + mux_clk_ops.determine_rate = clk_mux_determine_rate; + mux_clk_ops.recalc_rate = mux_recalc_rate; + + dp_vco_clk.priv = pll_res; + + for (i = DP_VCO_CLK; i <= DP_PHY_PLL_VCO_DIV_CLK; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dp_pllcc_10nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DP: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (rc) { + pr_err("%s: Clock register failed rc=%d\n", __func__, rc); + rc = -EPROBE_DEFER; + } else { + pr_debug("%s SUCCESS\n", __func__); + } + return 0; +clk_reg_fail: + return rc; +} diff --git a/techpack/display/pll/dp_pll_10nm.h b/techpack/display/pll/dp_pll_10nm.h new file mode 100644 index 0000000000000000000000000000000000000000..2adbdf3e66cbbe97646721b3c2cfcb4a0bc255bf --- /dev/null +++ b/techpack/display/pll/dp_pll_10nm.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_DP_PLL_10NM_H +#define __MDSS_DP_PLL_10NM_H + +#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL +#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL +#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL +#define DP_VCO_HSCLK_RATE_8100MHZDIV1000 8100000UL + +struct dp_pll_db { + struct mdss_pll_resources *pll; + + /* lane and orientation settings */ + u8 lane_cnt; + u8 orientation; + + /* COM PHY settings */ + u32 hsclk_sel; + u32 dec_start_mode0; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 integloop_gain0_mode0; + u32 integloop_gain1_mode0; + u32 vco_tune_map; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp3_mode0; + u32 lock_cmp_en; + + /* PHY vco divider */ + u32 phy_vco_div; +}; + +int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw, + unsigned long parent_rate); +long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int dp_vco_prepare_10nm(struct clk_hw *hw); +void dp_vco_unprepare_10nm(struct clk_hw *hw); +int dp_mux_set_parent_10nm(void *context, + unsigned int reg, unsigned int val); +int dp_mux_get_parent_10nm(void *context, + unsigned int reg, unsigned int *val); +#endif /* __MDSS_DP_PLL_10NM_H */ diff --git a/techpack/display/pll/dp_pll_10nm_util.c b/techpack/display/pll/dp_pll_10nm_util.c new file mode 100644 index 0000000000000000000000000000000000000000..4eb859c31922be7c1d4976fe8982f0a1a75d6368 --- /dev/null +++ b/techpack/display/pll/dp_pll_10nm_util.c @@ -0,0 +1,757 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/usb/usbpd.h> + +#include "pll_drv.h" +#include "dp_pll.h" +#include "dp_pll_10nm.h" + +#define DP_PHY_REVISION_ID0 0x0000 +#define DP_PHY_REVISION_ID1 0x0004 +#define DP_PHY_REVISION_ID2 0x0008 +#define DP_PHY_REVISION_ID3 0x000C + +#define DP_PHY_CFG 0x0010 +#define DP_PHY_PD_CTL 0x0018 +#define DP_PHY_MODE 0x001C + +#define DP_PHY_AUX_CFG0 0x0020 +#define DP_PHY_AUX_CFG1 0x0024 +#define DP_PHY_AUX_CFG2 0x0028 +#define DP_PHY_AUX_CFG3 0x002C +#define DP_PHY_AUX_CFG4 0x0030 +#define DP_PHY_AUX_CFG5 0x0034 +#define DP_PHY_AUX_CFG6 0x0038 +#define DP_PHY_AUX_CFG7 0x003C +#define DP_PHY_AUX_CFG8 0x0040 +#define DP_PHY_AUX_CFG9 0x0044 +#define DP_PHY_AUX_INTERRUPT_MASK 0x0048 +#define DP_PHY_AUX_INTERRUPT_CLEAR 0x004C +#define DP_PHY_AUX_BIST_CFG 0x0050 + +#define DP_PHY_VCO_DIV 0x0064 +#define DP_PHY_TX0_TX1_LANE_CTL 0x006C +#define DP_PHY_TX2_TX3_LANE_CTL 0x0088 + +#define DP_PHY_SPARE0 0x00AC +#define DP_PHY_STATUS 0x00C0 + +/* Tx registers */ +#define TXn_BIST_MODE_LANENO 0x0000 +#define TXn_CLKBUF_ENABLE 0x0008 +#define TXn_TX_EMP_POST1_LVL 0x000C + +#define TXn_TX_DRV_LVL 0x001C + +#define TXn_RESET_TSYNC_EN 0x0024 +#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028 +#define TXn_TX_BAND 0x002C +#define TXn_SLEW_CNTL 0x0030 +#define TXn_INTERFACE_SELECT 0x0034 + +#define TXn_RES_CODE_LANE_TX 0x003C +#define TXn_RES_CODE_LANE_RX 0x0040 +#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044 +#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048 + +#define TXn_DEBUG_BUS_SEL 0x0058 +#define TXn_TRANSCEIVER_BIAS_EN 0x005C +#define TXn_HIGHZ_DRVR_EN 0x0060 +#define TXn_TX_POL_INV 0x0064 +#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068 + +#define TXn_LANE_MODE_1 0x008C + +#define TXn_TRAN_DRVR_EMP_EN 0x00C0 +#define TXn_TX_INTERFACE_MODE 0x00C4 + +#define TXn_VMODE_CTRL1 0x00F0 + +/* PLL register offset */ +#define QSERDES_COM_ATB_SEL1 0x0000 +#define QSERDES_COM_ATB_SEL2 0x0004 +#define QSERDES_COM_FREQ_UPDATE 0x0008 +#define QSERDES_COM_BG_TIMER 0x000C +#define QSERDES_COM_SSC_EN_CENTER 0x0010 +#define QSERDES_COM_SSC_ADJ_PER1 0x0014 +#define QSERDES_COM_SSC_ADJ_PER2 0x0018 +#define QSERDES_COM_SSC_PER1 0x001C +#define QSERDES_COM_SSC_PER2 0x0020 +#define QSERDES_COM_SSC_STEP_SIZE1 0x0024 +#define QSERDES_COM_SSC_STEP_SIZE2 0x0028 +#define QSERDES_COM_POST_DIV 0x002C +#define QSERDES_COM_POST_DIV_MUX 0x0030 +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034 +#define QSERDES_COM_CLK_ENABLE1 0x0038 +#define QSERDES_COM_SYS_CLK_CTRL 0x003C +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040 +#define QSERDES_COM_PLL_EN 0x0044 +#define QSERDES_COM_PLL_IVCO 0x0048 +#define QSERDES_COM_CMN_IETRIM 0x004C +#define QSERDES_COM_CMN_IPTRIM 0x0050 + +#define QSERDES_COM_CP_CTRL_MODE0 0x0060 +#define QSERDES_COM_CP_CTRL_MODE1 0x0064 +#define QSERDES_COM_PLL_RCTRL_MODE0 0x0068 +#define QSERDES_COM_PLL_RCTRL_MODE1 0x006C +#define QSERDES_COM_PLL_CCTRL_MODE0 0x0070 +#define QSERDES_COM_PLL_CCTRL_MODE1 0x0074 +#define QSERDES_COM_PLL_CNTRL 0x0078 +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM 0x007C +#define QSERDES_COM_SYSCLK_EN_SEL 0x0080 +#define QSERDES_COM_CML_SYSCLK_SEL 0x0084 +#define QSERDES_COM_RESETSM_CNTRL 0x0088 +#define QSERDES_COM_RESETSM_CNTRL2 0x008C +#define QSERDES_COM_LOCK_CMP_EN 0x0090 +#define QSERDES_COM_LOCK_CMP_CFG 0x0094 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x0098 +#define QSERDES_COM_LOCK_CMP2_MODE0 0x009C +#define QSERDES_COM_LOCK_CMP3_MODE0 0x00A0 + +#define QSERDES_COM_DEC_START_MODE0 0x00B0 +#define QSERDES_COM_DEC_START_MODE1 0x00B4 +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00B8 +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00BC +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00C0 +#define QSERDES_COM_DIV_FRAC_START1_MODE1 0x00C4 +#define QSERDES_COM_DIV_FRAC_START2_MODE1 0x00C8 +#define QSERDES_COM_DIV_FRAC_START3_MODE1 0x00CC +#define QSERDES_COM_INTEGLOOP_INITVAL 0x00D0 +#define QSERDES_COM_INTEGLOOP_EN 0x00D4 +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00D8 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00DC +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 0x00E0 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 0x00E4 +#define QSERDES_COM_VCOCAL_DEADMAN_CTRL 0x00E8 +#define QSERDES_COM_VCO_TUNE_CTRL 0x00EC +#define QSERDES_COM_VCO_TUNE_MAP 0x00F0 + +#define QSERDES_COM_CMN_STATUS 0x0124 +#define QSERDES_COM_RESET_SM_STATUS 0x0128 + +#define QSERDES_COM_CLK_SEL 0x0138 +#define QSERDES_COM_HSCLK_SEL 0x013C + +#define QSERDES_COM_CORECLK_DIV_MODE0 0x0148 + +#define QSERDES_COM_SW_RESET 0x0150 +#define QSERDES_COM_CORE_CLK_EN 0x0154 +#define QSERDES_COM_C_READY_STATUS 0x0158 +#define QSERDES_COM_CMN_CONFIG 0x015C + +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x0164 + +#define DP_PHY_PLL_POLL_SLEEP_US 500 +#define DP_PHY_PLL_POLL_TIMEOUT_US 10000 + +#define DP_VCO_RATE_8100MHZDIV1000 8100000UL +#define DP_VCO_RATE_9720MHZDIV1000 9720000UL +#define DP_VCO_RATE_10800MHZDIV1000 10800000UL + +int dp_mux_set_parent_10nm(void *context, unsigned int reg, unsigned int val) +{ + struct mdss_pll_resources *dp_res = context; + int rc; + u32 auxclk_div; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP PLL resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= ~0x03; /* bits 0 to 1 */ + + if (val == 0) /* mux parent index = 0 */ + auxclk_div |= 1; + else if (val == 1) /* mux parent index = 1 */ + auxclk_div |= 2; + else if (val == 2) /* mux parent index = 2 */ + auxclk_div |= 0; + + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_VCO_DIV, auxclk_div); + /* Make sure the PHY registers writes are done */ + wmb(); + pr_debug("%s: mux=%d auxclk_div=%x\n", __func__, val, auxclk_div); + + mdss_pll_resource_enable(dp_res, false); + + return 0; +} + +int dp_mux_get_parent_10nm(void *context, unsigned int reg, unsigned int *val) +{ + int rc; + u32 auxclk_div = 0; + struct mdss_pll_resources *dp_res = context; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable dp_res resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= 0x03; + + if (auxclk_div == 1) /* Default divider */ + *val = 0; + else if (auxclk_div == 2) + *val = 1; + else if (auxclk_div == 0) + *val = 2; + + mdss_pll_resource_enable(dp_res, false); + + pr_debug("%s: auxclk_div=%d, val=%d\n", __func__, auxclk_div, *val); + + return 0; +} + +static int dp_vco_pll_init_db_10nm(struct dp_pll_db *pdb, + unsigned long rate) +{ + struct mdss_pll_resources *dp_res = pdb->pll; + u32 spare_value = 0; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + pdb->lane_cnt = spare_value & 0x0F; + pdb->orientation = (spare_value & 0xF0) >> 4; + + pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + __func__, spare_value, pdb->lane_cnt, pdb->orientation); + + switch (rate) { + case DP_VCO_HSCLK_RATE_1620MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_9720MHZDIV1000); + pdb->hsclk_sel = 0x0c; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x6f; + pdb->lock_cmp2_mode0 = 0x08; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x00; + break; + case DP_VCO_HSCLK_RATE_2700MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x04; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x0f; + pdb->lock_cmp2_mode0 = 0x0e; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x00; + break; + case DP_VCO_HSCLK_RATE_5400MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x00; + pdb->dec_start_mode0 = 0x8c; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x00; + pdb->div_frac_start3_mode0 = 0x0a; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x1f; + pdb->lock_cmp2_mode0 = 0x1c; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x2; + pdb->lock_cmp_en = 0x00; + break; + case DP_VCO_HSCLK_RATE_8100MHZDIV1000: + pr_debug("%s: VCO rate: %ld\n", __func__, + DP_VCO_RATE_8100MHZDIV1000); + pdb->hsclk_sel = 0x03; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->lock_cmp1_mode0 = 0x2f; + pdb->lock_cmp2_mode0 = 0x2a; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x0; + pdb->lock_cmp_en = 0x08; + break; + default: + return -EINVAL; + } + return 0; +} + +static int dp_config_vco_rate_10nm(struct dp_pll_vco_clk *vco, + unsigned long rate) +{ + u32 res = 0; + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + + res = dp_vco_pll_init_db_10nm(pdb, rate); + if (res) { + pr_err("VCO Init DB failed\n"); + return res; + } + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x6d); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x75); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x7d); + } + + /* Make sure the PHY register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, 0x01); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0e); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_SEL, 0x30); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CMN_CONFIG, 0x02); + + /* Different for each clock rates */ + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN0_MODE0, pdb->integloop_gain0_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN1_MODE0, pdb->integloop_gain1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_MAP, pdb->vco_tune_map); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP3_MODE0, pdb->lock_cmp3_mode0); + /* Make sure the PLL register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BG_TIMER, 0x0a); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORECLK_DIV_MODE0, 0x0a); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_VCO_TUNE_CTRL, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORE_CLK_EN, 0x1f); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_IVCO, 0x07); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP_EN, pdb->lock_cmp_en); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CP_CTRL_MODE0, 0x06); + /* Make sure the PHY register writes are done */ + wmb(); + + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x4c); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x5c); + /* Make sure the PLL register writes are done */ + wmb(); + + /* TX Lane configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX0_TX1_LANE_CTL, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX2_TX3_LANE_CTL, 0x05); + + /* TX-0 register configuration */ + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_BAND, 0x4); + + /* TX-1 register configuration */ + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_BAND, 0x4); + /* Make sure the PHY register writes are done */ + wmb(); + + /* dependent on the vco frequency */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, pdb->phy_vco_div); + + return res; +} + +static bool dp_10nm_pll_lock_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool pll_locked; + + /* poll for PLL lock status */ + if (readl_poll_timeout_atomic((dp_res->pll_base + + QSERDES_COM_C_READY_STATUS), + status, + ((status & BIT(0)) > 0), + DP_PHY_PLL_POLL_SLEEP_US, + DP_PHY_PLL_POLL_TIMEOUT_US)) { + pr_err("%s: C_READY status is not high. Status=%x\n", + __func__, status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +static bool dp_10nm_phy_rdy_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool phy_ready = true; + + /* poll for PHY ready status */ + if (readl_poll_timeout_atomic((dp_res->phy_base + + DP_PHY_STATUS), + status, + ((status & (BIT(1))) > 0), + DP_PHY_PLL_POLL_SLEEP_US, + DP_PHY_PLL_POLL_TIMEOUT_US)) { + pr_err("%s: Phy_ready is not high. Status=%x\n", + __func__, status); + phy_ready = false; + } + + return phy_ready; +} + +static int dp_pll_enable_10nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + u32 bias_en, drvr_en; + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_AUX_CFG2, 0x04); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09); + wmb(); /* Make sure the PHY register writes are done */ + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20); + wmb(); /* Make sure the PLL register writes are done */ + + if (!dp_10nm_pll_lock_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + /* Make sure the PHY register writes are done */ + wmb(); + /* poll for PHY ready status */ + if (!dp_10nm_phy_rdy_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + pr_debug("%s: PLL is locked\n", __func__); + + if (pdb->lane_cnt == 1) { + bias_en = 0x3e; + drvr_en = 0x13; + } else { + bias_en = 0x3f; + drvr_en = 0x10; + } + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC1) { + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + } else { + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + } + } else { + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_HIGHZ_DRVR_EN, drvr_en); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_TRANSCEIVER_BIAS_EN, bias_en); + } + + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_POL_INV, 0x0a); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_POL_INV, 0x0a); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x18); + udelay(2000); + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + + /* + * Make sure all the register writes are completed before + * doing any other operation + */ + wmb(); + + /* poll for PHY ready status */ + if (!dp_10nm_phy_rdy_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_DRV_LVL, 0x38); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_DRV_LVL, 0x38); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_EMP_POST1_LVL, 0x20); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_EMP_POST1_LVL, 0x20); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x06); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x07); + /* Make sure the PHY register writes are done */ + wmb(); + +lock_err: + return rc; +} + +static int dp_pll_disable_10nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + /* Assert DP PHY power down */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2); + /* + * Make sure all the register writes to disable PLL are + * completed before doing any other operation + */ + wmb(); + + return 0; +} + + +int dp_vco_prepare_10nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + pr_debug("rate=%ld\n", vco->rate); + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll resources\n"); + goto error; + } + + if ((dp_res->vco_cached_rate != 0) + && (dp_res->vco_cached_rate == vco->rate)) { + rc = vco->hw.init->ops->set_rate(hw, + dp_res->vco_cached_rate, dp_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, dp_res->index); + mdss_pll_resource_enable(dp_res, false); + goto error; + } + } + + rc = dp_pll_enable_10nm(hw); + if (rc) { + mdss_pll_resource_enable(dp_res, false); + pr_err("ndx=%d failed to enable dp pll\n", + dp_res->index); + goto error; + } + + mdss_pll_resource_enable(dp_res, false); +error: + return rc; +} + +void dp_vco_unprepare_10nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + if (!dp_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!dp_res->pll_on && + mdss_pll_resource_enable(dp_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + dp_res->vco_cached_rate = vco->rate; + dp_pll_disable_10nm(hw); + + dp_res->handoff_resources = false; + mdss_pll_resource_enable(dp_res, false); + dp_res->pll_on = false; +} + +int dp_vco_set_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + int rc; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + pr_debug("DP lane CLK rate=%ld\n", rate); + + rc = dp_config_vco_rate_10nm(vco, rate); + if (rc) + pr_err("%s: Failed to set clk rate\n", __func__); + + mdss_pll_resource_enable(dp_res, false); + + vco->rate = rate; + + return 0; +} + +unsigned long dp_vco_recalc_rate_10nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + int rc; + u32 div, hsclk_div, link_clk_div = 0; + u64 vco_rate; + struct mdss_pll_resources *dp_res = vco->priv; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index); + return rc; + } + + div = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL); + div &= 0x0f; + + if (div == 12) + hsclk_div = 6; /* Default */ + else if (div == 4) + hsclk_div = 4; + else if (div == 0) + hsclk_div = 2; + else if (div == 3) + hsclk_div = 1; + else { + pr_debug("unknown divider. forcing to default\n"); + hsclk_div = 5; + } + + div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_AUX_CFG2); + div >>= 2; + + if ((div & 0x3) == 0) + link_clk_div = 5; + else if ((div & 0x3) == 1) + link_clk_div = 10; + else if ((div & 0x3) == 2) + link_clk_div = 20; + else + pr_err("%s: unsupported div. Phy_mode: %d\n", __func__, div); + + if (link_clk_div == 20) { + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + } else { + if (hsclk_div == 6) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 4) + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (hsclk_div == 2) + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + vco_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000; + } + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(dp_res, false); + + dp_res->vco_cached_rate = vco->rate = vco_rate; + return (unsigned long)vco_rate; +} + +long dp_vco_round_rate_10nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + + if (rate <= vco->min_rate) + rrate = vco->min_rate; + else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + rrate = vco->max_rate; + + pr_debug("%s: rrate=%ld\n", __func__, rrate); + + *parent_rate = rrate; + return rrate; +} + diff --git a/techpack/display/pll/dp_pll_14nm.c b/techpack/display/pll/dp_pll_14nm.c new file mode 100644 index 0000000000000000000000000000000000000000..05641bb8432cab9156f49e94c0e9f494274891f7 --- /dev/null +++ b/techpack/display/pll/dp_pll_14nm.c @@ -0,0 +1,820 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +/* + *************************************************************************** + ******** Display Port PLL driver block diagram for branch clocks ********** + *************************************************************************** + + +--------------------------+ + | DP_VCO_CLK | + | | + | +-------------------+ | + | | (DP PLL/VCO) | | + | +---------+---------+ | + | v | + | +----------+-----------+ | + | | hsclk_divsel_clk_src | | + | +----------+-----------+ | + +--------------------------+ + | + v + +------------<------------|------------>-------------+ + | | | ++----------v----------+ +----------v----------+ +----------v----------+ +| dp_link_2x_clk | | vco_divided_clk_src | | vco_divided_clk_src | +| divsel_five | | | | | +v----------+----------v | divsel_two | | divsel_four | + | +----------+----------+ +----------+----------+ + | | | + v v v + | +---------------------+ | + Input to MMSSCC block | | (aux_clk_ops) | | + for link clk, crypto clk +--> vco_divided_clk <-+ + and interface clock | _src_mux | + +----------+----------+ + | + v + Input to MMSSCC block + for DP pixel clock + + ****************************************************************************** + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/usb/usbpd.h> + +#include <dt-bindings/clock/mdss-14nm-pll-clk.h> + +#include "pll_drv.h" +#include "dp_pll.h" +#include "dp_pll_14nm.h" + +static struct dp_pll_db dp_pdb; +static struct clk_ops mux_clk_ops; + +static struct regmap_config dp_pll_14nm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x910, +}; + +static struct regmap_bus dp_pixel_mux_regmap_ops = { + .reg_write = dp_mux_set_parent_14nm, + .reg_read = dp_mux_get_parent_14nm, +}; + +/* Op structures */ +static const struct clk_ops dp_14nm_vco_clk_ops = { + .recalc_rate = dp_vco_recalc_rate_14nm, + .set_rate = dp_vco_set_rate_14nm, + .round_rate = dp_vco_round_rate_14nm, + .prepare = dp_vco_prepare_14nm, + .unprepare = dp_vco_unprepare_14nm, +}; + +static struct dp_pll_vco_clk dp_vco_clk = { + .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000, + .max_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000, + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_clk", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &dp_14nm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor dp_phy_pll_link_clk = { + .div = 10, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_phy_pll_link_clk", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE), + .ops = &clk_fixed_factor_ops, + }, +}; + +static int clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int ret = 0; + + ret = __clk_mux_determine_rate_closest(hw, req); + if (ret) + return ret; + + /* Set the new parent of mux if there is a new valid parent */ + if (hw->clk && req->best_parent_hw->clk) + clk_set_parent(hw->clk, req->best_parent_hw->clk); + + return 0; +} + + +static unsigned long mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk *div_clk = NULL, *vco_clk = NULL; + struct dp_pll_vco_clk *vco = NULL; + + div_clk = clk_get_parent(hw->clk); + if (!div_clk) + return 0; + + vco_clk = clk_get_parent(div_clk); + if (!vco_clk) + return 0; + + vco = to_dp_vco_hw(__clk_get_hw(vco_clk)); + if (!vco) + return 0; + + if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + return (vco->rate / 4); + else + return (vco->rate / 2); +} + +static struct clk_regmap_mux dp_phy_pll_vco_div_clk = { + .reg = 0x64, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dp_phy_pll_vco_div_clk", + .parent_names = + (const char *[]){"dp_vco_divsel_two_clk_src", + "dp_vco_divsel_four_clk_src"}, + .num_parents = 2, + .ops = &mux_clk_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + }, + }, +}; + +static struct clk_hw *mdss_dp_pllcc_14nm[] = { + [DP_VCO_CLK] = &dp_vco_clk.hw, + [DP_PHY_PLL_LINK_CLK] = &dp_phy_pll_link_clk.hw, + [DP_VCO_DIVSEL_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw, + [DP_VCO_DIVSEL_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw, + [DP_PHY_PLL_VCO_DIV_CLK] = &dp_phy_pll_vco_div_clk.clkr.hw, +}; + + +int dp_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val) +{ + struct mdss_pll_resources *dp_res = context; + int rc; + u32 auxclk_div; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP PLL resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= ~0x03; /* bits 0 to 1 */ + + if (val == 0) /* mux parent index = 0 */ + auxclk_div |= 1; + else if (val == 1) /* mux parent index = 1 */ + auxclk_div |= 2; + + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_VCO_DIV, auxclk_div); + /* Make sure the PHY registers writes are done */ + wmb(); + pr_debug("mux=%d auxclk_div=%x\n", val, auxclk_div); + + mdss_pll_resource_enable(dp_res, false); + + return 0; +} + +int dp_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val) +{ + int rc; + u32 auxclk_div = 0; + struct mdss_pll_resources *dp_res = context; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable dp_res resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= 0x03; + + if (auxclk_div == 1) /* Default divider */ + *val = 0; + else if (auxclk_div == 2) + *val = 1; + + mdss_pll_resource_enable(dp_res, false); + + pr_debug("auxclk_div=%d, val=%d\n", auxclk_div, *val); + + return 0; +} + +static int dp_vco_pll_init_db_14nm(struct dp_pll_db *pdb, + unsigned long rate) +{ + struct mdss_pll_resources *dp_res = pdb->pll; + u32 spare_value = 0; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + pdb->lane_cnt = spare_value & 0x0F; + pdb->orientation = (spare_value & 0xF0) >> 4; + + pr_debug("spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + spare_value, pdb->lane_cnt, pdb->orientation); + + switch (rate) { + case DP_VCO_HSCLK_RATE_1620MHZDIV1000: + pdb->hsclk_sel = 0x2c; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0xbf; + pdb->lock_cmp2_mode0 = 0x21; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + pdb->lane_mode_1 = 0xc6; + break; + case DP_VCO_HSCLK_RATE_2700MHZDIV1000: + pdb->hsclk_sel = 0x24; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x3f; + pdb->lock_cmp2_mode0 = 0x38; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x1; + pdb->lane_mode_1 = 0xc4; + break; + case DP_VCO_HSCLK_RATE_5400MHZDIV1000: + pdb->hsclk_sel = 0x20; + pdb->dec_start_mode0 = 0x8c; + pdb->div_frac_start1_mode0 = 0x00; + pdb->div_frac_start2_mode0 = 0x00; + pdb->div_frac_start3_mode0 = 0x0a; + pdb->lock_cmp1_mode0 = 0x7f; + pdb->lock_cmp2_mode0 = 0x70; + pdb->lock_cmp3_mode0 = 0x00; + pdb->phy_vco_div = 0x2; + pdb->lane_mode_1 = 0xc4; + break; + default: + return -EINVAL; + } + return 0; +} + +int dp_config_vco_rate_14nm(struct dp_pll_vco_clk *vco, + unsigned long rate) +{ + u32 res = 0; + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db *pdb = (struct dp_pll_db *)dp_res->priv; + + res = dp_vco_pll_init_db_14nm(pdb, rate); + if (res) { + pr_err("VCO Init DB failed\n"); + return res; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x3d); + + /* Make sure the PHY register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SVS_MODE_CLK_SEL, 0x01); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SYSCLK_EN_SEL, 0x37); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CLK_SELECT, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SYS_CLK_CTRL, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CLK_ENABLE1, 0x0e); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_BG_CTRL, 0x0f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CLK_SELECT, 0x30); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_PLL_IVCO, 0x0f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_PLL_CCTRL_MODE0, 0x28); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_PLL_RCTRL_MODE0, 0x16); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CP_CTRL_MODE0, 0x0b); + + /* Parameters dependent on vco clock frequency */ + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP3_MODE0, pdb->lock_cmp3_mode0); + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x40); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_MAP, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_BG_TIMER, 0x08); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CORECLK_DIV, 0x05); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_CTRL, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE1_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE2_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_VCO_TUNE_CTRL, 0x00); + wmb(); /* make sure write happens */ + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CORE_CLK_EN, 0x0f); + wmb(); /* make sure write happens */ + + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xc9); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0xd9); + wmb(); /* make sure write happens */ + + /* TX Lane configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX0_TX1_LANE_CTL, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_TX2_TX3_LANE_CTL, 0x05); + + /* TX-0 register configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_EMP_POST1_LVL, 0x2b); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_DRV_LVL, 0x2f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_BAND, 0x4); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX, 0x12); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX, 0x12); + + /* TX-1 register configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x1a); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_INTERFACE_SELECT, 0x3d); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_EMP_POST1_LVL, 0x2b); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_DRV_LVL, 0x2f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_BAND, 0x4); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_TX, 0x12); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_RES_CODE_LANE_OFFSET_RX, 0x12); + wmb(); /* make sure write happens */ + + /* PHY VCO divider programming */ + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_VCO_DIV, pdb->phy_vco_div); + wmb(); /* make sure write happens */ + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_CMN_CONFIG, 0x02); + wmb(); /* make sure write happens */ + + return res; +} + +static bool dp_14nm_pll_lock_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool pll_locked; + + /* poll for PLL lock status */ + if (readl_poll_timeout_atomic((dp_res->pll_base + + QSERDES_COM_C_READY_STATUS), + status, + ((status & BIT(0)) > 0), + DP_PLL_POLL_SLEEP_US, + DP_PLL_POLL_TIMEOUT_US)) { + pr_err("C_READY status is not high. Status=%x\n", status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +static bool dp_14nm_phy_rdy_status(struct mdss_pll_resources *dp_res) +{ + u32 status; + bool phy_ready = true; + + /* poll for PHY ready status */ + if (readl_poll_timeout_atomic((dp_res->phy_base + + DP_PHY_STATUS), + status, + ((status & (BIT(1) | BIT(0))) > 0), + DP_PHY_POLL_SLEEP_US, + DP_PHY_POLL_TIMEOUT_US)) { + pr_err("Phy_ready is not high. Status=%x\n", status); + phy_ready = false; + } + + return phy_ready; +} + +static int dp_pll_enable_14nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09); + wmb(); /* Make sure the PHY register writes are done */ + + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_RESETSM_CNTRL, 0x20); + wmb(); /* Make sure the PLL register writes are done */ + + udelay(900); /* hw recommended delay for full PU */ + + if (!dp_14nm_pll_lock_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + wmb(); /* Make sure the PHY register writes are done */ + + udelay(10); /* hw recommended delay */ + + if (!dp_14nm_phy_rdy_status(dp_res)) { + rc = -EINVAL; + goto lock_err; + } + + pr_debug("PLL is locked\n"); + + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, 0x10); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, 0x3f); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, 0x10); + + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TX_POL_INV, 0x0a); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TX_POL_INV, 0x0a); + + /* + * Switch DP Mainlink clock (cc_dpphy_link_clk) from DP + * controller side with final frequency + */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x18); + wmb(); /* Make sure the PHY register writes are done */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + wmb(); /* Make sure the PHY register writes are done */ + +lock_err: + return rc; +} + +static int dp_pll_disable_14nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + /* Assert DP PHY power down */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2); + /* + * Make sure all the register writes to disable PLL are + * completed before doing any other operation + */ + wmb(); + + return 0; +} + + +int dp_vco_prepare_14nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + pr_debug("rate=%ld\n", vco->rate); + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll resources\n"); + goto error; + } + + if ((dp_res->vco_cached_rate != 0) + && (dp_res->vco_cached_rate == vco->rate)) { + rc = vco->hw.init->ops->set_rate(hw, + dp_res->vco_cached_rate, dp_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, dp_res->index); + mdss_pll_resource_enable(dp_res, false); + goto error; + } + } + + rc = dp_pll_enable_14nm(hw); + if (rc) { + mdss_pll_resource_enable(dp_res, false); + pr_err("ndx=%d failed to enable dp pll\n", + dp_res->index); + goto error; + } + + mdss_pll_resource_enable(dp_res, false); +error: + return rc; +} + +void dp_vco_unprepare_14nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + if (!dp_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!dp_res->pll_on && + mdss_pll_resource_enable(dp_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + dp_res->vco_cached_rate = vco->rate; + dp_pll_disable_14nm(hw); + + dp_res->handoff_resources = false; + mdss_pll_resource_enable(dp_res, false); + dp_res->pll_on = false; +} + +int dp_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + int rc; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + pr_debug("DP lane CLK rate=%ld\n", rate); + + rc = dp_config_vco_rate_14nm(vco, rate); + if (rc) + pr_err("Failed to set clk rate\n"); + + mdss_pll_resource_enable(dp_res, false); + + vco->rate = rate; + + return 0; +} + +unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + int rc; + u32 div, hsclk_div; + u64 vco_rate; + struct mdss_pll_resources *dp_res = vco->priv; + + if (is_gdsc_disabled(dp_res)) + return 0; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index); + return rc; + } + + div = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL); + div &= 0x0f; + + if (div == 12) + hsclk_div = 5; /* Default */ + else if (div == 4) + hsclk_div = 3; + else if (div == 0) + hsclk_div = 2; + else { + pr_debug("unknown divider. forcing to default\n"); + hsclk_div = 5; + } + + if (hsclk_div == 5) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 3) + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(dp_res, false); + + dp_res->vco_cached_rate = vco->rate = vco_rate; + return (unsigned long)vco_rate; +} + +long dp_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + + if (rate <= vco->min_rate) + rrate = vco->min_rate; + else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else + rrate = vco->max_rate; + + pr_debug("rrate=%ld\n", rrate); + + *parent_rate = rrate; + return rrate; +} + +int dp_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i = 0; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dp_pllcc_14nm); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + pll_res->priv = &dp_pdb; + dp_pdb.pll = pll_res; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops, + pll_res, &dp_pll_14nm_cfg); + dp_phy_pll_vco_div_clk.clkr.regmap = regmap; + mux_clk_ops = clk_regmap_mux_closest_ops; + mux_clk_ops.determine_rate = clk_mux_determine_rate; + mux_clk_ops.recalc_rate = mux_recalc_rate; + + dp_vco_clk.priv = pll_res; + + for (i = DP_VCO_CLK; i <= DP_PHY_PLL_VCO_DIV_CLK; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dp_pllcc_14nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DP: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (rc) { + pr_err("Clock register failed rc=%d\n", rc); + rc = -EPROBE_DEFER; + } else { + pr_debug("SUCCESS\n"); + } + return 0; +clk_reg_fail: + return rc; +} diff --git a/techpack/display/pll/dp_pll_14nm.h b/techpack/display/pll/dp_pll_14nm.h new file mode 100644 index 0000000000000000000000000000000000000000..f8c9c3043bdf7311a78f8c0e9d799250a1011bdb --- /dev/null +++ b/techpack/display/pll/dp_pll_14nm.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_DP_PLL_14NM_H +#define __MDSS_DP_PLL_14NM_H + +#define DP_PHY_REVISION_ID0 0x0000 +#define DP_PHY_REVISION_ID1 0x0004 +#define DP_PHY_REVISION_ID2 0x0008 +#define DP_PHY_REVISION_ID3 0x000C + +#define DP_PHY_CFG 0x0010 +#define DP_PHY_CFG_1 0x0014 +#define DP_PHY_PD_CTL 0x0018 +#define DP_PHY_MODE 0x001C + +#define DP_PHY_AUX_CFG0 0x0020 +#define DP_PHY_AUX_CFG1 0x0024 +#define DP_PHY_AUX_CFG2 0x0028 +#define DP_PHY_AUX_CFG3 0x002C +#define DP_PHY_AUX_CFG4 0x0030 +#define DP_PHY_AUX_CFG5 0x0034 +#define DP_PHY_AUX_CFG6 0x0038 +#define DP_PHY_AUX_CFG7 0x003C +#define DP_PHY_AUX_CFG8 0x0040 +#define DP_PHY_AUX_CFG9 0x0044 +#define DP_PHY_AUX_INTERRUPT_MASK 0x0048 +#define DP_PHY_AUX_INTERRUPT_CLEAR 0x004C +#define DP_PHY_AUX_BIST_CFG 0x0050 + +#define DP_PHY_VCO_DIV 0x0068 +#define DP_PHY_TX0_TX1_LANE_CTL 0x006C + +#define DP_PHY_TX2_TX3_LANE_CTL 0x0088 +#define DP_PHY_SPARE0 0x00AC +#define DP_PHY_STATUS 0x00C0 + +/* Tx registers */ +#define QSERDES_TX0_OFFSET 0x0400 +#define QSERDES_TX1_OFFSET 0x0800 + +#define TXn_BIST_MODE_LANENO 0x0000 +#define TXn_CLKBUF_ENABLE 0x0008 +#define TXn_TX_EMP_POST1_LVL 0x000C + +#define TXn_TX_DRV_LVL 0x001C + +#define TXn_RESET_TSYNC_EN 0x0024 +#define TXn_PRE_STALL_LDO_BOOST_EN 0x0028 +#define TXn_TX_BAND 0x002C +#define TXn_SLEW_CNTL 0x0030 +#define TXn_INTERFACE_SELECT 0x0034 + +#define TXn_RES_CODE_LANE_TX 0x003C +#define TXn_RES_CODE_LANE_RX 0x0040 +#define TXn_RES_CODE_LANE_OFFSET_TX 0x0044 +#define TXn_RES_CODE_LANE_OFFSET_RX 0x0048 + +#define TXn_DEBUG_BUS_SEL 0x0058 +#define TXn_TRANSCEIVER_BIAS_EN 0x005C +#define TXn_HIGHZ_DRVR_EN 0x0060 +#define TXn_TX_POL_INV 0x0064 +#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0068 + +#define TXn_LANE_MODE_1 0x008C + +#define TXn_TRAN_DRVR_EMP_EN 0x00C0 +#define TXn_TX_INTERFACE_MODE 0x00C4 + +#define TXn_VMODE_CTRL1 0x00F0 + + +/* PLL register offset */ +#define QSERDES_COM_ATB_SEL1 0x0000 +#define QSERDES_COM_ATB_SEL2 0x0004 +#define QSERDES_COM_FREQ_UPDATE 0x0008 +#define QSERDES_COM_BG_TIMER 0x000C +#define QSERDES_COM_SSC_EN_CENTER 0x0010 +#define QSERDES_COM_SSC_ADJ_PER1 0x0014 +#define QSERDES_COM_SSC_ADJ_PER2 0x0018 +#define QSERDES_COM_SSC_PER1 0x001C +#define QSERDES_COM_SSC_PER2 0x0020 +#define QSERDES_COM_SSC_STEP_SIZE1 0x0024 +#define QSERDES_COM_SSC_STEP_SIZE2 0x0028 +#define QSERDES_COM_POST_DIV 0x002C +#define QSERDES_COM_POST_DIV_MUX 0x0030 +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0034 +#define QSERDES_COM_CLK_ENABLE1 0x0038 +#define QSERDES_COM_SYS_CLK_CTRL 0x003C +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0040 +#define QSERDES_COM_PLL_EN 0x0044 +#define QSERDES_COM_PLL_IVCO 0x0048 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x004C +#define QSERDES_COM_LOCK_CMP2_MODE0 0x0050 +#define QSERDES_COM_LOCK_CMP3_MODE0 0x0054 + +#define QSERDES_COM_CP_CTRL_MODE0 0x0078 +#define QSERDES_COM_CP_CTRL_MODE1 0x007C +#define QSERDES_COM_PLL_RCTRL_MODE0 0x0084 +#define QSERDES_COM_PLL_CCTRL_MODE0 0x0090 +#define QSERDES_COM_PLL_CNTRL 0x009C + +#define QSERDES_COM_SYSCLK_EN_SEL 0x00AC +#define QSERDES_COM_CML_SYSCLK_SEL 0x00B0 +#define QSERDES_COM_RESETSM_CNTRL 0x00B4 +#define QSERDES_COM_RESETSM_CNTRL2 0x00B8 +#define QSERDES_COM_LOCK_CMP_EN 0x00C8 +#define QSERDES_COM_LOCK_CMP_CFG 0x00CC + + +#define QSERDES_COM_DEC_START_MODE0 0x00D0 +#define QSERDES_COM_DEC_START_MODE1 0x00D4 +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00DC +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00E0 +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00E4 + +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x0108 +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x010C +#define QSERDES_COM_VCO_TUNE_CTRL 0x0124 +#define QSERDES_COM_VCO_TUNE_MAP 0x0128 +#define QSERDES_COM_VCO_TUNE1_MODE0 0x012C +#define QSERDES_COM_VCO_TUNE2_MODE0 0x0130 + +#define QSERDES_COM_CMN_STATUS 0x015C +#define QSERDES_COM_RESET_SM_STATUS 0x0160 + +#define QSERDES_COM_BG_CTRL 0x0170 +#define QSERDES_COM_CLK_SELECT 0x0174 +#define QSERDES_COM_HSCLK_SEL 0x0178 +#define QSERDES_COM_CORECLK_DIV 0x0184 +#define QSERDES_COM_SW_RESET 0x0188 +#define QSERDES_COM_CORE_CLK_EN 0x018C +#define QSERDES_COM_C_READY_STATUS 0x0190 +#define QSERDES_COM_CMN_CONFIG 0x0194 +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x019C + +#define DP_PLL_POLL_SLEEP_US 500 +#define DP_PLL_POLL_TIMEOUT_US 10000 + +#define DP_PHY_POLL_SLEEP_US 500 +#define DP_PHY_POLL_TIMEOUT_US 10000 + +#define DP_VCO_RATE_8100MHZDIV1000 8100000UL +#define DP_VCO_RATE_10800MHZDIV1000 10800000UL + +#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL +#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL +#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL + +struct dp_pll_db { + struct mdss_pll_resources *pll; + + /* lane and orientation settings */ + u8 lane_cnt; + u8 orientation; + + /* COM PHY settings */ + u32 hsclk_sel; + u32 dec_start_mode0; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp3_mode0; + + /* PHY vco divider */ + u32 phy_vco_div; + + /* TX settings */ + u32 lane_mode_1; +}; + +int dp_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long dp_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate); +long dp_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int dp_vco_prepare_14nm(struct clk_hw *hw); +void dp_vco_unprepare_14nm(struct clk_hw *hw); +int dp_mux_set_parent_14nm(void *context, + unsigned int reg, unsigned int val); +int dp_mux_get_parent_14nm(void *context, + unsigned int reg, unsigned int *val); +#endif /* __MDSS_DP_PLL_14NM_H */ diff --git a/techpack/display/pll/dp_pll_7nm.c b/techpack/display/pll/dp_pll_7nm.c new file mode 100644 index 0000000000000000000000000000000000000000..8db4747d4ff25e7cf7cfe59b3e3b06003a749e5c --- /dev/null +++ b/techpack/display/pll/dp_pll_7nm.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +/* + * Display Port PLL driver block diagram for branch clocks + * + * +------------------------------+ + * | DP_VCO_CLK | + * | | + * | +-------------------+ | + * | | (DP PLL/VCO) | | + * | +---------+---------+ | + * | v | + * | +----------+-----------+ | + * | | hsclk_divsel_clk_src | | + * | +----------+-----------+ | + * +------------------------------+ + * | + * +------------<---------v------------>----------+ + * | | + * +-----v------------+ | + * | dp_link_clk_src | | + * | divsel_ten | | + * +---------+--------+ | + * | | + * | | + * v v + * Input to DISPCC block | + * for link clk, crypto clk | + * and interface clock | + * | + * | + * +--------<------------+-----------------+---<---+ + * | | | + * +-------v------+ +--------v-----+ +--------v------+ + * | vco_divided | | vco_divided | | vco_divided | + * | _clk_src | | _clk_src | | _clk_src | + * | | | | | | + * |divsel_six | | divsel_two | | divsel_four | + * +-------+------+ +-----+--------+ +--------+------+ + * | | | + * v------->----------v-------------<------v + * | + * +----------+---------+ + * | vco_divided_clk | + * | _src_mux | + * +---------+----------+ + * | + * v + * Input to DISPCC block + * for DP pixel clock + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <dt-bindings/clock/mdss-7nm-pll-clk.h> + +#include "pll_drv.h" +#include "dp_pll.h" +#include "dp_pll_7nm.h" + +static struct dp_pll_db_7nm dp_pdb_7nm; +static struct clk_ops mux_clk_ops; + +static struct regmap_config dp_pll_7nm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x910, +}; + +static struct regmap_bus dp_pixel_mux_regmap_ops = { + .reg_write = dp_mux_set_parent_7nm, + .reg_read = dp_mux_get_parent_7nm, +}; + +/* Op structures */ +static const struct clk_ops dp_7nm_vco_clk_ops = { + .recalc_rate = dp_vco_recalc_rate_7nm, + .set_rate = dp_vco_set_rate_7nm, + .round_rate = dp_vco_round_rate_7nm, + .prepare = dp_vco_prepare_7nm, + .unprepare = dp_vco_unprepare_7nm, +}; + +static struct dp_pll_vco_clk dp_vco_clk = { + .min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000, + .max_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000, + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_clk", + .parent_names = (const char *[]){ "xo_board" }, + .num_parents = 1, + .ops = &dp_7nm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor dp_phy_pll_link_clk = { + .div = 10, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_phy_pll_link_clk", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_link_clk_divsel_ten = { + .div = 10, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_link_clk_divsel_ten", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dp_vco_divsel_six_clk_src = { + .div = 6, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divsel_six_clk_src", + .parent_names = + (const char *[]){ "dp_vco_clk" }, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + + +static int clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int ret = 0; + + if (!hw || !req) { + pr_err("Invalid input parameters\n"); + return -EINVAL; + } + + ret = __clk_mux_determine_rate_closest(hw, req); + if (ret) + return ret; + + /* Set the new parent of mux if there is a new valid parent */ + if (hw->clk && req->best_parent_hw->clk) + clk_set_parent(hw->clk, req->best_parent_hw->clk); + + return 0; +} + +static unsigned long mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk *div_clk = NULL, *vco_clk = NULL; + struct dp_pll_vco_clk *vco = NULL; + + if (!hw) { + pr_err("Invalid input parameter\n"); + return 0; + } + + div_clk = clk_get_parent(hw->clk); + if (!div_clk) + return 0; + + vco_clk = clk_get_parent(div_clk); + if (!vco_clk) + return 0; + + vco = to_dp_vco_hw(__clk_get_hw(vco_clk)); + if (!vco) + return 0; + + if (vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) + return (vco->rate / 6); + else if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000) + return (vco->rate / 4); + else + return (vco->rate / 2); +} + +static struct clk_regmap_mux dp_phy_pll_vco_div_clk = { + .reg = 0x64, + .shift = 0, + .width = 2, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dp_phy_pll_vco_div_clk", + .parent_names = + (const char *[]){"dp_vco_divsel_two_clk_src", + "dp_vco_divsel_four_clk_src", + "dp_vco_divsel_six_clk_src"}, + .num_parents = 3, + .ops = &mux_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_regmap_mux dp_vco_divided_clk_src_mux = { + .reg = 0x64, + .shift = 0, + .width = 2, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dp_vco_divided_clk_src_mux", + .parent_names = + (const char *[]){"dp_vco_divsel_two_clk_src", + "dp_vco_divsel_four_clk_src", + "dp_vco_divsel_six_clk_src"}, + .num_parents = 3, + .ops = &mux_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_hw *mdss_dp_pllcc_7nm[] = { + [DP_VCO_CLK] = &dp_vco_clk.hw, + [DP_LINK_CLK_DIVSEL_TEN] = &dp_link_clk_divsel_ten.hw, + [DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw, + [DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw, + [DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw, + [DP_VCO_DIVIDED_CLK_SRC_MUX] = &dp_vco_divided_clk_src_mux.clkr.hw, +}; + +int dp_pll_clock_register_7nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i = 0; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dp_pllcc_7nm); + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + pll_res->priv = &dp_pdb_7nm; + dp_pdb_7nm.pll = pll_res; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops, + pll_res, &dp_pll_7nm_cfg); + mux_clk_ops = clk_regmap_mux_closest_ops; + mux_clk_ops.determine_rate = clk_mux_determine_rate; + mux_clk_ops.recalc_rate = mux_recalc_rate; + + dp_vco_clk.priv = pll_res; + + /* + * Consumer for the pll clock expects, the DP_LINK_CLK_DIVSEL_TEN and + * DP_VCO_DIVIDED_CLK_SRC_MUX clock names to be "dp_phy_pll_link_clk" + * and "dp_phy_pll_vco_div_clk" respectively for a V2 pll interface + * target. + */ + if (pll_res->pll_interface_type == MDSS_DP_PLL_7NM_V2) { + mdss_dp_pllcc_7nm[DP_LINK_CLK_DIVSEL_TEN] = + &dp_phy_pll_link_clk.hw; + mdss_dp_pllcc_7nm[DP_VCO_DIVIDED_CLK_SRC_MUX] = + &dp_phy_pll_vco_div_clk.clkr.hw; + dp_phy_pll_vco_div_clk.clkr.regmap = regmap; + } else + dp_vco_divided_clk_src_mux.clkr.regmap = regmap; + + for (i = DP_VCO_CLK; i <= DP_VCO_DIVIDED_CLK_SRC_MUX; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, mdss_dp_pllcc_7nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DP: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (rc) { + pr_err("Clock register failed rc=%d\n", rc); + rc = -EPROBE_DEFER; + goto clk_reg_fail; + } else { + pr_debug("SUCCESS\n"); + } + return rc; +clk_reg_fail: + return rc; +} diff --git a/techpack/display/pll/dp_pll_7nm.h b/techpack/display/pll/dp_pll_7nm.h new file mode 100644 index 0000000000000000000000000000000000000000..87037f9c60fa1084d245ee96a42c6a47b58bac32 --- /dev/null +++ b/techpack/display/pll/dp_pll_7nm.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_DP_PLL_7NM_H +#define __MDSS_DP_PLL_7NM_H + +#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL +#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL +#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL +#define DP_VCO_HSCLK_RATE_8100MHZDIV1000 8100000UL + +struct dp_pll_db_7nm { + struct mdss_pll_resources *pll; + + /* lane and orientation settings */ + u8 lane_cnt; + u8 orientation; + + /* COM PHY settings */ + u32 hsclk_sel; + u32 dec_start_mode0; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 integloop_gain0_mode0; + u32 integloop_gain1_mode0; + u32 vco_tune_map; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp_en; + u32 cmn_config; + u32 txn_tran_drv_emp_en; + + /* PHY vco divider */ + u32 phy_vco_div; +}; + +int dp_vco_set_rate_7nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +unsigned long dp_vco_recalc_rate_7nm(struct clk_hw *hw, + unsigned long parent_rate); +long dp_vco_round_rate_7nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int dp_vco_prepare_7nm(struct clk_hw *hw); +void dp_vco_unprepare_7nm(struct clk_hw *hw); +int dp_mux_set_parent_7nm(void *context, + unsigned int reg, unsigned int val); +int dp_mux_get_parent_7nm(void *context, + unsigned int reg, unsigned int *val); +#endif /* __MDSS_DP_PLL_7NM_H */ diff --git a/techpack/display/pll/dp_pll_7nm_util.c b/techpack/display/pll/dp_pll_7nm_util.c new file mode 100644 index 0000000000000000000000000000000000000000..4ce47a7f5497d81f4567e4056c46ce982d0b4004 --- /dev/null +++ b/techpack/display/pll/dp_pll_7nm_util.c @@ -0,0 +1,739 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "[dp-pll] %s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/usb/usbpd.h> + +#include "pll_drv.h" +#include "dp_pll.h" +#include "dp_pll_7nm.h" + +#define DP_PHY_CFG 0x0010 +#define DP_PHY_CFG_1 0x0014 +#define DP_PHY_PD_CTL 0x0018 +#define DP_PHY_MODE 0x001C + +#define DP_PHY_AUX_CFG1 0x0024 +#define DP_PHY_AUX_CFG2 0x0028 + +#define DP_PHY_VCO_DIV 0x0070 +#define DP_PHY_TX0_TX1_LANE_CTL 0x0078 +#define DP_PHY_TX2_TX3_LANE_CTL 0x009C + +#define DP_PHY_SPARE0 0x00C8 +#define DP_PHY_STATUS 0x00DC + +/* Tx registers */ +#define TXn_CLKBUF_ENABLE 0x0008 +#define TXn_TX_EMP_POST1_LVL 0x000C + +#define TXn_TX_DRV_LVL 0x0014 + +#define TXn_RESET_TSYNC_EN 0x001C +#define TXn_PRE_STALL_LDO_BOOST_EN 0x0020 +#define TXn_TX_BAND 0x0024 +#define TXn_INTERFACE_SELECT 0x002C + +#define TXn_RES_CODE_LANE_OFFSET_TX 0x003C +#define TXn_RES_CODE_LANE_OFFSET_RX 0x0040 + +#define TXn_TRANSCEIVER_BIAS_EN 0x0054 +#define TXn_HIGHZ_DRVR_EN 0x0058 +#define TXn_TX_POL_INV 0x005C +#define TXn_PARRATE_REC_DETECT_IDLE_EN 0x0060 + +/* PLL register offset */ +#define QSERDES_COM_BG_TIMER 0x000C +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN 0x0044 +#define QSERDES_COM_CLK_ENABLE1 0x0048 +#define QSERDES_COM_SYS_CLK_CTRL 0x004C +#define QSERDES_COM_SYSCLK_BUF_ENABLE 0x0050 +#define QSERDES_COM_PLL_IVCO 0x0058 + +#define QSERDES_COM_CP_CTRL_MODE0 0x0074 +#define QSERDES_COM_PLL_RCTRL_MODE0 0x007C +#define QSERDES_COM_PLL_CCTRL_MODE0 0x0084 +#define QSERDES_COM_SYSCLK_EN_SEL 0x0094 +#define QSERDES_COM_RESETSM_CNTRL 0x009C +#define QSERDES_COM_LOCK_CMP_EN 0x00A4 +#define QSERDES_COM_LOCK_CMP1_MODE0 0x00AC +#define QSERDES_COM_LOCK_CMP2_MODE0 0x00B0 + +#define QSERDES_COM_DEC_START_MODE0 0x00BC +#define QSERDES_COM_DIV_FRAC_START1_MODE0 0x00CC +#define QSERDES_COM_DIV_FRAC_START2_MODE0 0x00D0 +#define QSERDES_COM_DIV_FRAC_START3_MODE0 0x00D4 +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 0x00EC +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 0x00F0 +#define QSERDES_COM_VCO_TUNE_CTRL 0x0108 +#define QSERDES_COM_VCO_TUNE_MAP 0x010C + +#define QSERDES_COM_CMN_STATUS 0x0140 +#define QSERDES_COM_CLK_SEL 0x0154 +#define QSERDES_COM_HSCLK_SEL 0x0158 + +#define QSERDES_COM_CORECLK_DIV_MODE0 0x0168 + +#define QSERDES_COM_CORE_CLK_EN 0x0174 +#define QSERDES_COM_C_READY_STATUS 0x0178 +#define QSERDES_COM_CMN_CONFIG 0x017C + +#define QSERDES_COM_SVS_MODE_CLK_SEL 0x0184 + +/* Tx tran offsets */ +#define DP_TRAN_DRVR_EMP_EN 0x0000 +#define DP_TX_INTERFACE_MODE 0x0004 + +/* Tx VMODE offsets */ +#define DP_VMODE_CTRL1 0x0000 + +#define DP_PHY_PLL_POLL_SLEEP_US 500 +#define DP_PHY_PLL_POLL_TIMEOUT_US 10000 + +#define DP_VCO_RATE_8100MHZDIV1000 8100000UL +#define DP_VCO_RATE_9720MHZDIV1000 9720000UL +#define DP_VCO_RATE_10800MHZDIV1000 10800000UL + +#define DP_7NM_C_READY BIT(0) +#define DP_7NM_FREQ_DONE BIT(0) +#define DP_7NM_PLL_LOCKED BIT(1) +#define DP_7NM_PHY_READY BIT(1) +#define DP_7NM_TSYNC_DONE BIT(0) + +int dp_mux_set_parent_7nm(void *context, unsigned int reg, unsigned int val) +{ + struct mdss_pll_resources *dp_res = context; + int rc; + u32 auxclk_div; + + if (!context) { + pr_err("invalid input parameters\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP PLL resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= ~0x03; + + if (val == 0) + auxclk_div |= 1; + else if (val == 1) + auxclk_div |= 2; + else if (val == 2) + auxclk_div |= 0; + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, auxclk_div); + /* Make sure the PHY registers writes are done */ + wmb(); + pr_debug("mux=%d auxclk_div=%x\n", val, auxclk_div); + + mdss_pll_resource_enable(dp_res, false); + + return 0; +} + +int dp_mux_get_parent_7nm(void *context, unsigned int reg, unsigned int *val) +{ + int rc; + u32 auxclk_div = 0; + struct mdss_pll_resources *dp_res = context; + + if (!context || !val) { + pr_err("invalid input parameters\n"); + return -EINVAL; + } + + if (is_gdsc_disabled(dp_res)) + return 0; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable dp_res resources\n"); + return rc; + } + + auxclk_div = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_VCO_DIV); + auxclk_div &= 0x03; + + if (auxclk_div == 1) /* Default divider */ + *val = 0; + else if (auxclk_div == 2) + *val = 1; + else if (auxclk_div == 0) + *val = 2; + + mdss_pll_resource_enable(dp_res, false); + + pr_debug("auxclk_div=%d, val=%d\n", auxclk_div, *val); + + return 0; +} + +static int dp_vco_pll_init_db_7nm(struct dp_pll_db_7nm *pdb, + unsigned long rate) +{ + struct mdss_pll_resources *dp_res = pdb->pll; + u32 spare_value = 0; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + pdb->lane_cnt = spare_value & 0x0F; + pdb->orientation = (spare_value & 0xF0) >> 4; + + pr_debug("spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + spare_value, pdb->lane_cnt, pdb->orientation); + + pdb->div_frac_start1_mode0 = 0x00; + pdb->integloop_gain0_mode0 = 0x3f; + pdb->integloop_gain1_mode0 = 0x00; + pdb->vco_tune_map = 0x00; + pdb->cmn_config = 0x02; + + switch (rate) { + case DP_VCO_HSCLK_RATE_1620MHZDIV1000: + pr_debug("VCO rate: %ld\n", DP_VCO_RATE_9720MHZDIV1000); + pdb->hsclk_sel = 0x05; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x6f; + pdb->lock_cmp2_mode0 = 0x08; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x04; + break; + case DP_VCO_HSCLK_RATE_2700MHZDIV1000: + pr_debug("VCO rate: %ld\n", DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x03; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x0f; + pdb->lock_cmp2_mode0 = 0x0e; + pdb->phy_vco_div = 0x1; + pdb->lock_cmp_en = 0x08; + break; + case DP_VCO_HSCLK_RATE_5400MHZDIV1000: + pr_debug("VCO rate: %ld\n", DP_VCO_RATE_10800MHZDIV1000); + pdb->hsclk_sel = 0x01; + pdb->dec_start_mode0 = 0x8c; + pdb->div_frac_start2_mode0 = 0x00; + pdb->div_frac_start3_mode0 = 0x0a; + pdb->lock_cmp1_mode0 = 0x1f; + pdb->lock_cmp2_mode0 = 0x1c; + pdb->phy_vco_div = 0x2; + pdb->lock_cmp_en = 0x08; + break; + case DP_VCO_HSCLK_RATE_8100MHZDIV1000: + pr_debug("VCO rate: %ld\n", DP_VCO_RATE_8100MHZDIV1000); + pdb->hsclk_sel = 0x00; + pdb->dec_start_mode0 = 0x69; + pdb->div_frac_start2_mode0 = 0x80; + pdb->div_frac_start3_mode0 = 0x07; + pdb->lock_cmp1_mode0 = 0x2f; + pdb->lock_cmp2_mode0 = 0x2a; + pdb->phy_vco_div = 0x0; + pdb->lock_cmp_en = 0x08; + break; + default: + pr_err("unsupported rate %ld\n", rate); + return -EINVAL; + } + return 0; +} + +static int dp_config_vco_rate_7nm(struct dp_pll_vco_clk *vco, + unsigned long rate) +{ + u32 res = 0; + struct mdss_pll_resources *dp_res = vco->priv; + struct dp_pll_db_7nm *pdb = (struct dp_pll_db_7nm *)dp_res->priv; + + res = dp_vco_pll_init_db_7nm(pdb, rate); + if (res) { + pr_err("VCO Init DB failed\n"); + return res; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG_1, 0x0F); + + if (pdb->lane_cnt != 4) { + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x6d); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x75); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x7d); + } + + /* Make sure the PHY register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, 0x05); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x3b); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0c); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x06); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CLK_SEL, 0x30); + /* Make sure the PHY register writes are done */ + wmb(); + + /* PLL Optimization */ + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_IVCO, 0x0f); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CP_CTRL_MODE0, 0x06); + /* Make sure the PHY register writes are done */ + wmb(); + + /* link rate dependent params */ + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_HSCLK_SEL, pdb->hsclk_sel); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DEC_START_MODE0, pdb->dec_start_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START1_MODE0, pdb->div_frac_start1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START2_MODE0, pdb->div_frac_start2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_DIV_FRAC_START3_MODE0, pdb->div_frac_start3_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP1_MODE0, pdb->lock_cmp1_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_LOCK_CMP2_MODE0, pdb->lock_cmp2_mode0); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_LOCK_CMP_EN, + pdb->lock_cmp_en); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_VCO_DIV, pdb->phy_vco_div); + /* Make sure the PLL register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CMN_CONFIG, 0x02); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f); + MDSS_PLL_REG_W(dp_res->pll_base, + QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_VCO_TUNE_MAP, 0x00); + /* Make sure the PHY register writes are done */ + wmb(); + + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BG_TIMER, 0x0a); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORECLK_DIV_MODE0, 0x0a); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_VCO_TUNE_CTRL, 0x00); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_CORE_CLK_EN, 0x1f); + /* Make sure the PHY register writes are done */ + wmb(); + + if (pdb->orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x4c); + else + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_MODE, 0x5c); + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_AUX_CFG1, 0x13); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_AUX_CFG2, 0xA4); + /* Make sure the PLL register writes are done */ + wmb(); + + /* TX-0 register configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_TX0_TX1_LANE_CTL, 0x05); + MDSS_PLL_REG_W(dp_res->ln_tx0_vmode_base, DP_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_INTERFACE_SELECT, 0x3b); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx0_tran_base, DP_TRAN_DRVR_EMP_EN, 0xf); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx0_tran_base, DP_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x11); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x11); + MDSS_PLL_REG_W(dp_res->ln_tx0_base, TXn_TX_BAND, 0x04); + + /* TX-1 register configuration */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_TX2_TX3_LANE_CTL, 0x05); + MDSS_PLL_REG_W(dp_res->ln_tx1_vmode_base, DP_VMODE_CTRL1, 0x40); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_PRE_STALL_LDO_BOOST_EN, 0x30); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_INTERFACE_SELECT, 0x3b); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_CLKBUF_ENABLE, 0x0f); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(dp_res->ln_tx1_tran_base, DP_TRAN_DRVR_EMP_EN, 0xf); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, + TXn_PARRATE_REC_DETECT_IDLE_EN, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx1_tran_base, DP_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_TX, 0x11); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_RES_CODE_LANE_OFFSET_RX, 0x11); + MDSS_PLL_REG_W(dp_res->ln_tx1_base, TXn_TX_BAND, 0x04); + /* Make sure the PHY register writes are done */ + wmb(); + + return res; +} + +enum dp_7nm_pll_status { + C_READY, + FREQ_DONE, + PLL_LOCKED, + PHY_READY, + TSYNC_DONE, +}; + +char *dp_7nm_pll_get_status_name(enum dp_7nm_pll_status status) +{ + switch (status) { + case C_READY: + return "C_READY"; + case FREQ_DONE: + return "FREQ_DONE"; + case PLL_LOCKED: + return "PLL_LOCKED"; + case PHY_READY: + return "PHY_READY"; + case TSYNC_DONE: + return "TSYNC_DONE"; + default: + return "unknown"; + } + + +} + +static bool dp_7nm_pll_get_status(struct mdss_pll_resources *dp_res, + enum dp_7nm_pll_status status) +{ + u32 reg, state, bit; + void __iomem *base; + bool success = true; + + switch (status) { + case C_READY: + base = dp_res->pll_base; + reg = QSERDES_COM_C_READY_STATUS; + bit = DP_7NM_C_READY; + break; + case FREQ_DONE: + base = dp_res->pll_base; + reg = QSERDES_COM_CMN_STATUS; + bit = DP_7NM_FREQ_DONE; + break; + case PLL_LOCKED: + base = dp_res->pll_base; + reg = QSERDES_COM_CMN_STATUS; + bit = DP_7NM_PLL_LOCKED; + break; + case PHY_READY: + base = dp_res->phy_base; + reg = DP_PHY_STATUS; + bit = DP_7NM_PHY_READY; + break; + case TSYNC_DONE: + base = dp_res->phy_base; + reg = DP_PHY_STATUS; + bit = DP_7NM_TSYNC_DONE; + break; + default: + return false; + } + + if (readl_poll_timeout_atomic((base + reg), state, + ((state & bit) > 0), + DP_PHY_PLL_POLL_SLEEP_US, + DP_PHY_PLL_POLL_TIMEOUT_US)) { + pr_err("%s failed, status=%x\n", + dp_7nm_pll_get_status_name(status), state); + + success = false; + } + + return success; +} + +static int dp_pll_enable_7nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x05); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x09); + MDSS_PLL_REG_W(dp_res->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20); + wmb(); /* Make sure the PLL register writes are done */ + + if (!dp_7nm_pll_get_status(dp_res, C_READY)) { + rc = -EINVAL; + goto lock_err; + } + + if (!dp_7nm_pll_get_status(dp_res, FREQ_DONE)) { + rc = -EINVAL; + goto lock_err; + } + + if (!dp_7nm_pll_get_status(dp_res, PLL_LOCKED)) { + rc = -EINVAL; + goto lock_err; + } + + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x19); + /* Make sure the PHY register writes are done */ + wmb(); + + if (!dp_7nm_pll_get_status(dp_res, TSYNC_DONE)) { + rc = -EINVAL; + goto lock_err; + } + + if (!dp_7nm_pll_get_status(dp_res, PHY_READY)) { + rc = -EINVAL; + goto lock_err; + } + + pr_debug("PLL is locked\n"); +lock_err: + return rc; +} + +static int dp_pll_disable_7nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw); + struct mdss_pll_resources *dp_res = vco->priv; + + /* Assert DP PHY power down */ + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_PD_CTL, 0x2); + /* + * Make sure all the register writes to disable PLL are + * completed before doing any other operation + */ + wmb(); + + return 0; +} + +int dp_vco_prepare_7nm(struct clk_hw *hw) +{ + int rc = 0; + struct dp_pll_vco_clk *vco; + struct mdss_pll_resources *dp_res; + + if (!hw) { + pr_err("invalid input parameters\n"); + return -EINVAL; + } + + vco = to_dp_vco_hw(hw); + dp_res = vco->priv; + + pr_debug("rate=%ld\n", vco->rate); + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll resources\n"); + goto error; + } + + if ((dp_res->vco_cached_rate != 0) + && (dp_res->vco_cached_rate == vco->rate)) { + rc = vco->hw.init->ops->set_rate(hw, + dp_res->vco_cached_rate, dp_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, dp_res->index); + mdss_pll_resource_enable(dp_res, false); + goto error; + } + } + + rc = dp_pll_enable_7nm(hw); + if (rc) { + mdss_pll_resource_enable(dp_res, false); + pr_err("ndx=%d failed to enable dp pll\n", dp_res->index); + goto error; + } + + mdss_pll_resource_enable(dp_res, false); +error: + return rc; +} + +void dp_vco_unprepare_7nm(struct clk_hw *hw) +{ + struct dp_pll_vco_clk *vco; + struct mdss_pll_resources *dp_res; + + if (!hw) { + pr_err("invalid input parameters\n"); + return; + } + + vco = to_dp_vco_hw(hw); + dp_res = vco->priv; + + if (!dp_res) { + pr_err("invalid input parameter\n"); + return; + } + + if (!dp_res->pll_on && + mdss_pll_resource_enable(dp_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + dp_res->vco_cached_rate = vco->rate; + dp_pll_disable_7nm(hw); + + dp_res->handoff_resources = false; + mdss_pll_resource_enable(dp_res, false); + dp_res->pll_on = false; +} + +int dp_vco_set_rate_7nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco; + struct mdss_pll_resources *dp_res; + int rc; + + if (!hw) { + pr_err("invalid input parameters\n"); + return -EINVAL; + } + + vco = to_dp_vco_hw(hw); + dp_res = vco->priv; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + pr_debug("DP lane CLK rate=%ld\n", rate); + + rc = dp_config_vco_rate_7nm(vco, rate); + if (rc) + pr_err("Failed to set clk rate\n"); + + mdss_pll_resource_enable(dp_res, false); + + vco->rate = rate; + + return 0; +} + +unsigned long dp_vco_recalc_rate_7nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dp_pll_vco_clk *vco; + int rc; + u32 hsclk_sel, link_clk_divsel, hsclk_div, link_clk_div = 0; + unsigned long vco_rate; + struct mdss_pll_resources *dp_res; + + if (!hw) { + pr_err("invalid input parameters\n"); + return 0; + } + + vco = to_dp_vco_hw(hw); + dp_res = vco->priv; + + if (is_gdsc_disabled(dp_res)) + return 0; + + rc = mdss_pll_resource_enable(dp_res, true); + if (rc) { + pr_err("Failed to enable mdss DP pll=%d\n", dp_res->index); + return 0; + } + + pr_debug("input rates: parent=%lu, vco=%lu\n", parent_rate, vco->rate); + + hsclk_sel = MDSS_PLL_REG_R(dp_res->pll_base, QSERDES_COM_HSCLK_SEL); + hsclk_sel &= 0x0f; + + if (hsclk_sel == 5) + hsclk_div = 5; + else if (hsclk_sel == 3) + hsclk_div = 3; + else if (hsclk_sel == 1) + hsclk_div = 2; + else if (hsclk_sel == 0) + hsclk_div = 1; + else { + pr_debug("unknown divider. forcing to default\n"); + hsclk_div = 5; + } + + link_clk_divsel = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_AUX_CFG2); + link_clk_divsel >>= 2; + link_clk_divsel &= 0x3; + + if (link_clk_divsel == 0) + link_clk_div = 5; + else if (link_clk_divsel == 1) + link_clk_div = 10; + else if (link_clk_divsel == 2) + link_clk_div = 20; + else + pr_err("unsupported div. Phy_mode: %d\n", link_clk_divsel); + + if (link_clk_div == 20) { + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + } else { + if (hsclk_div == 5) + vco_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000; + else if (hsclk_div == 3) + vco_rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (hsclk_div == 2) + vco_rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + vco_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000; + } + + pr_debug("hsclk: sel=0x%x, div=0x%x; lclk: sel=%u, div=%u, rate=%lu\n", + hsclk_sel, hsclk_div, link_clk_divsel, link_clk_div, vco_rate); + + mdss_pll_resource_enable(dp_res, false); + + dp_res->vco_cached_rate = vco->rate = vco_rate; + return vco_rate; +} + +long dp_vco_round_rate_7nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dp_pll_vco_clk *vco; + + if (!hw) { + pr_err("invalid input parameters\n"); + return 0; + } + + vco = to_dp_vco_hw(hw); + if (rate <= vco->min_rate) + rrate = vco->min_rate; + else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000; + else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000) + rrate = DP_VCO_HSCLK_RATE_5400MHZDIV1000; + else + rrate = vco->max_rate; + + pr_debug("rrate=%ld\n", rrate); + + if (parent_rate) + *parent_rate = rrate; + return rrate; +} + diff --git a/techpack/display/pll/dsi_20nm_pll_util.c b/techpack/display/pll/dsi_20nm_pll_util.c new file mode 100644 index 0000000000000000000000000000000000000000..2a0ab26e7011129450c8719855546e64ab2e59a7 --- /dev/null +++ b/techpack/display/pll/dsi_20nm_pll_util.c @@ -0,0 +1,1004 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/clk/msm-clock-generic.h> + +#include "pll_drv.h" +#include "dsi_pll.h" + +#define MMSS_DSI_PHY_PLL_SYS_CLK_CTRL 0x0000 +#define MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN 0x0004 +#define MMSS_DSI_PHY_PLL_CMN_MODE 0x0008 +#define MMSS_DSI_PHY_PLL_IE_TRIM 0x000C +#define MMSS_DSI_PHY_PLL_IP_TRIM 0x0010 + +#define MMSS_DSI_PHY_PLL_PLL_PHSEL_CONTROL 0x0018 +#define MMSS_DSI_PHY_PLL_IPTAT_TRIM_VCCA_TX_SEL 0x001C +#define MMSS_DSI_PHY_PLL_PLL_PHSEL_DC 0x0020 +#define MMSS_DSI_PHY_PLL_PLL_IP_SETI 0x0024 +#define MMSS_DSI_PHY_PLL_CORE_CLK_IN_SYNC_SEL 0x0028 + +#define MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN 0x0030 +#define MMSS_DSI_PHY_PLL_PLL_CP_SETI 0x0034 +#define MMSS_DSI_PHY_PLL_PLL_IP_SETP 0x0038 +#define MMSS_DSI_PHY_PLL_PLL_CP_SETP 0x003C +#define MMSS_DSI_PHY_PLL_ATB_SEL1 0x0040 +#define MMSS_DSI_PHY_PLL_ATB_SEL2 0x0044 +#define MMSS_DSI_PHY_PLL_SYSCLK_EN_SEL_TXBAND 0x0048 +#define MMSS_DSI_PHY_PLL_RESETSM_CNTRL 0x004C +#define MMSS_DSI_PHY_PLL_RESETSM_CNTRL2 0x0050 +#define MMSS_DSI_PHY_PLL_RESETSM_CNTRL3 0x0054 +#define MMSS_DSI_PHY_PLL_RESETSM_PLL_CAL_COUNT1 0x0058 +#define MMSS_DSI_PHY_PLL_RESETSM_PLL_CAL_COUNT2 0x005C +#define MMSS_DSI_PHY_PLL_DIV_REF1 0x0060 +#define MMSS_DSI_PHY_PLL_DIV_REF2 0x0064 +#define MMSS_DSI_PHY_PLL_KVCO_COUNT1 0x0068 +#define MMSS_DSI_PHY_PLL_KVCO_COUNT2 0x006C +#define MMSS_DSI_PHY_PLL_KVCO_CAL_CNTRL 0x0070 +#define MMSS_DSI_PHY_PLL_KVCO_CODE 0x0074 +#define MMSS_DSI_PHY_PLL_VREF_CFG1 0x0078 +#define MMSS_DSI_PHY_PLL_VREF_CFG2 0x007C +#define MMSS_DSI_PHY_PLL_VREF_CFG3 0x0080 +#define MMSS_DSI_PHY_PLL_VREF_CFG4 0x0084 +#define MMSS_DSI_PHY_PLL_VREF_CFG5 0x0088 +#define MMSS_DSI_PHY_PLL_VREF_CFG6 0x008C +#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP1 0x0090 +#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP2 0x0094 +#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP3 0x0098 + +#define MMSS_DSI_PHY_PLL_BGTC 0x00A0 +#define MMSS_DSI_PHY_PLL_PLL_TEST_UPDN 0x00A4 +#define MMSS_DSI_PHY_PLL_PLL_VCO_TUNE 0x00A8 +#define MMSS_DSI_PHY_PLL_DEC_START1 0x00AC +#define MMSS_DSI_PHY_PLL_PLL_AMP_OS 0x00B0 +#define MMSS_DSI_PHY_PLL_SSC_EN_CENTER 0x00B4 +#define MMSS_DSI_PHY_PLL_SSC_ADJ_PER1 0x00B8 +#define MMSS_DSI_PHY_PLL_SSC_ADJ_PER2 0x00BC +#define MMSS_DSI_PHY_PLL_SSC_PER1 0x00C0 +#define MMSS_DSI_PHY_PLL_SSC_PER2 0x00C4 +#define MMSS_DSI_PHY_PLL_SSC_STEP_SIZE1 0x00C8 +#define MMSS_DSI_PHY_PLL_SSC_STEP_SIZE2 0x00CC +#define MMSS_DSI_PHY_PLL_RES_CODE_UP 0x00D0 +#define MMSS_DSI_PHY_PLL_RES_CODE_DN 0x00D4 +#define MMSS_DSI_PHY_PLL_RES_CODE_UP_OFFSET 0x00D8 +#define MMSS_DSI_PHY_PLL_RES_CODE_DN_OFFSET 0x00DC +#define MMSS_DSI_PHY_PLL_RES_CODE_START_SEG1 0x00E0 +#define MMSS_DSI_PHY_PLL_RES_CODE_START_SEG2 0x00E4 +#define MMSS_DSI_PHY_PLL_RES_CODE_CAL_CSR 0x00E8 +#define MMSS_DSI_PHY_PLL_RES_CODE 0x00EC +#define MMSS_DSI_PHY_PLL_RES_TRIM_CONTROL 0x00F0 +#define MMSS_DSI_PHY_PLL_RES_TRIM_CONTROL2 0x00F4 +#define MMSS_DSI_PHY_PLL_RES_TRIM_EN_VCOCALDONE 0x00F8 +#define MMSS_DSI_PHY_PLL_FAUX_EN 0x00FC + +#define MMSS_DSI_PHY_PLL_DIV_FRAC_START1 0x0100 +#define MMSS_DSI_PHY_PLL_DIV_FRAC_START2 0x0104 +#define MMSS_DSI_PHY_PLL_DIV_FRAC_START3 0x0108 +#define MMSS_DSI_PHY_PLL_DEC_START2 0x010C +#define MMSS_DSI_PHY_PLL_PLL_RXTXEPCLK_EN 0x0110 +#define MMSS_DSI_PHY_PLL_PLL_CRCTRL 0x0114 +#define MMSS_DSI_PHY_PLL_LOW_POWER_RO_CONTROL 0x013C +#define MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL 0x0140 +#define MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER 0x0144 +#define MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER 0x0148 +#define MMSS_DSI_PHY_PLL_PLL_VCO_HIGH 0x014C +#define MMSS_DSI_PHY_PLL_RESET_SM 0x0150 +#define MMSS_DSI_PHY_PLL_MUXVAL 0x0154 +#define MMSS_DSI_PHY_PLL_CORE_RES_CODE_DN 0x0158 +#define MMSS_DSI_PHY_PLL_CORE_RES_CODE_UP 0x015C +#define MMSS_DSI_PHY_PLL_CORE_VCO_TUNE 0x0160 +#define MMSS_DSI_PHY_PLL_CORE_VCO_TAIL 0x0164 +#define MMSS_DSI_PHY_PLL_CORE_KVCO_CODE 0x0168 + +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL0 0x014 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL1 0x018 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL2 0x01C +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL3 0x020 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL4 0x024 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL5 0x028 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL6 0x02C +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL7 0x030 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL8 0x034 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL9 0x038 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL10 0x03C +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL11 0x040 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL12 0x044 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL13 0x048 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL14 0x04C +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL15 0x050 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL16 0x054 +#define MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL17 0x058 + +#define DSI_PLL_POLL_DELAY_US 1000 +#define DSI_PLL_POLL_TIMEOUT_US 15000 + +int set_mdss_byte_mux_sel(struct mux_clk *clk, int sel) +{ + return 0; +} + +int get_mdss_byte_mux_sel(struct mux_clk *clk) +{ + return 0; +} + +int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel) +{ + return 0; +} + +int get_mdss_pixel_mux_sel(struct mux_clk *clk) +{ + return 0; +} + +static void pll_20nm_cache_trim_codes(struct mdss_pll_resources *dsi_pll_res) +{ + int rc; + + if (dsi_pll_res->reg_upd) + return; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return; + } + + dsi_pll_res->cache_pll_trim_codes[0] = + MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_CORE_KVCO_CODE); + dsi_pll_res->cache_pll_trim_codes[1] = + MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_CORE_VCO_TUNE); + + pr_debug("core_kvco_code=0x%x core_vco_turn=0x%x\n", + dsi_pll_res->cache_pll_trim_codes[0], + dsi_pll_res->cache_pll_trim_codes[1]); + + mdss_pll_resource_enable(dsi_pll_res, false); + + dsi_pll_res->reg_upd = true; +} + +static void pll_20nm_override_trim_codes(struct mdss_pll_resources *dsi_pll_res) +{ + u32 reg_data; + void __iomem *pll_base = dsi_pll_res->pll_base; + + /* + * Override mux config for all cached trim codes from + * saved config except for VCO Tune + */ + reg_data = (dsi_pll_res->cache_pll_trim_codes[0] & 0x3f) | BIT(5); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_KVCO_CODE, reg_data); + + reg_data = (dsi_pll_res->cache_pll_trim_codes[1] & 0x7f) | BIT(7); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCO_TUNE, reg_data); +} + + +int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel) +{ + struct mdss_pll_resources *dsi_pll_res = clk->priv; + int reg_data; + + pr_debug("bypass_lp_div mux set to %s mode\n", + sel ? "indirect" : "direct"); + + pr_debug("POST_DIVIDER_CONTROL = 0x%x\n", + MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL)); + + reg_data = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL); + reg_data |= BIT(7); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + reg_data | (sel << 5)); + pr_debug("POST_DIVIDER_CONTROL = 0x%x\n", + MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL)); + + return 0; +} + +int set_shadow_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel) +{ + struct mdss_pll_resources *dsi_pll_res = clk->priv; + int reg_data, rem; + + if (!dsi_pll_res->resource_enable) { + pr_err("PLL resources disabled. Dynamic fps invalid\n"); + return -EINVAL; + } + + reg_data = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL); + reg_data |= BIT(7); + + pr_debug("%d: reg_data = %x\n", __LINE__, reg_data); + + /* Repeat POST DIVIDER 2 times (4 writes)*/ + for (rem = 0; rem < 2; rem++) + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL16 + (4 * rem), + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + (reg_data | (sel << 5)), (reg_data | (sel << 5))); + + return 0; +} + +int get_bypass_lp_div_mux_sel(struct mux_clk *clk) +{ + int mux_mode, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + mux_mode = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL) & BIT(5); + + pr_debug("bypass_lp_div mux mode = %s\n", + mux_mode ? "indirect" : "direct"); + mdss_pll_resource_enable(dsi_pll_res, false); + + return !!mux_mode; +} + +int ndiv_set_div(struct div_clk *clk, int div) +{ + int rc, reg_data; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + reg_data = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + reg_data | div); + + pr_debug("POST_DIVIDER_CONTROL = 0x%x\n", + MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL)); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int shadow_ndiv_set_div(struct div_clk *clk, int div) +{ + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (!dsi_pll_res->resource_enable) { + pr_err("PLL resources disabled. Dynamic fps invalid\n"); + return -EINVAL; + } + + pr_debug("%d div=%i\n", __LINE__, div); + + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL14, + MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + 0x07, (0xB | div)); + + return 0; +} + +int ndiv_get_div(struct div_clk *clk) +{ + int div = 0, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(clk->priv, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL) & 0x0F; + + mdss_pll_resource_enable(dsi_pll_res, false); + + return div; +} + +int fixed_hr_oclk2_set_div(struct div_clk *clk, int div) +{ + int rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER, + (div - 1)); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int shadow_fixed_hr_oclk2_set_div(struct div_clk *clk, int div) +{ + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (!dsi_pll_res->resource_enable) { + pr_err("PLL resources disabled. Dynamic fps invalid\n"); + return -EINVAL; + } + pr_debug("%d div = %d\n", __LINE__, div); + + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL5, + MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER, + MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER, + (div - 1), (div - 1)); + + return 0; +} + +int fixed_hr_oclk2_get_div(struct div_clk *clk) +{ + int div = 0, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_HR_OCLK2_DIVIDER); + + mdss_pll_resource_enable(dsi_pll_res, false); + return div + 1; +} + +int hr_oclk3_set_div(struct div_clk *clk, int div) +{ + int rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + pr_debug("%d div = %d\n", __LINE__, div); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER, + (div - 1)); + pr_debug("%s: HR_OCLK3_DIVIDER = 0x%x\n", __func__, + MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER)); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int shadow_hr_oclk3_set_div(struct div_clk *clk, int div) +{ + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (!dsi_pll_res->resource_enable) { + pr_err("PLL resources disabled. Dynamic fps invalid\n"); + return -EINVAL; + } + + pr_debug("%d div = %d\n", __LINE__, div); + + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL6, + MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER, + MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER, + (div - 1), (div - 1)); + + return 0; +} + +int hr_oclk3_get_div(struct div_clk *clk) +{ + int div = 0, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_HR_OCLK3_DIVIDER); + + mdss_pll_resource_enable(dsi_pll_res, false); + return div + 1; +} + +static bool pll_20nm_is_pll_locked(struct mdss_pll_resources *dsi_pll_res) +{ + u32 status; + bool pll_locked; + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((dsi_pll_res->pll_base + + MMSS_DSI_PHY_PLL_RESET_SM), + status, + ((status & BIT(5)) > 0), + DSI_PLL_POLL_DELAY_US, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_debug("DSI PLL status=%x failed to Lock\n", status); + pll_locked = false; + } else if (readl_poll_timeout_atomic((dsi_pll_res->pll_base + + MMSS_DSI_PHY_PLL_RESET_SM), + status, + ((status & BIT(6)) > 0), + DSI_PLL_POLL_DELAY_US, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_debug("DSI PLL status=%x PLl not ready\n", status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +void __dsi_pll_disable(void __iomem *pll_base) +{ + if (!pll_base) { + pr_err("Invalid pll base\n"); + return; + } + pr_debug("Disabling PHY PLL for PLL_BASE=%p\n", pll_base); + + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x02); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x06); +} + +static void pll_20nm_config_powerdown(void __iomem *pll_base) +{ + if (!pll_base) { + pr_err("Invalid pll base.\n"); + return; + } + + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_SYS_CLK_CTRL, 0x00); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_CMN_MODE, 0x01); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x82); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x02); +} + +static int dsi_pll_enable(struct clk *c) +{ + int i, rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < vco->pll_en_seq_cnt; i++) { + rc = vco->pll_enable_seqs[i](dsi_pll_res); + pr_debug("DSI PLL %s after sequence #%d\n", + rc ? "unlocked" : "locked", i + 1); + if (!rc) + break; + } + /* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */ + if (dsi_pll_res->pll_1_base) + pll_20nm_config_powerdown(dsi_pll_res->pll_1_base); + + if (rc) { + mdss_pll_resource_enable(dsi_pll_res, false); + pr_err("DSI PLL failed to lock\n"); + } + dsi_pll_res->pll_on = true; + + return rc; +} + +static void dsi_pll_disable(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res->pll_on && + mdss_pll_resource_enable(dsi_pll_res, true)) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return; + } + + dsi_pll_res->handoff_resources = false; + + __dsi_pll_disable(dsi_pll_res->pll_base); + + /* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */ + if (dsi_pll_res->pll_1_base) + pll_20nm_config_powerdown(dsi_pll_res->pll_1_base); + + pll_20nm_config_powerdown(dsi_pll_res->pll_base); + + mdss_pll_resource_enable(dsi_pll_res, false); + + dsi_pll_res->pll_on = false; + + pr_debug("DSI PLL Disabled\n"); +} + +static void pll_20nm_config_common_block_1(void __iomem *pll_base) +{ + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x82); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x2a); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x2b); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02); +} + +static void pll_20nm_config_common_block_2(void __iomem *pll_base) +{ + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_SYS_CLK_CTRL, 0x40); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_IE_TRIM, 0x0F); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_IP_TRIM, 0x0F); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_PHSEL_CONTROL, 0x08); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_IPTAT_TRIM_VCCA_TX_SEL, 0x0E); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN, 0x08); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_SYSCLK_EN_SEL_TXBAND, 0x4A); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DIV_REF1, 0x00); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DIV_REF2, 0x01); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_CNTRL, 0x07); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_KVCO_CAL_CNTRL, 0x1f); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_KVCO_COUNT1, 0x8A); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_VREF_CFG3, 0x10); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_SSC_EN_CENTER, 0x00); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_FAUX_EN, 0x0C); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_RXTXEPCLK_EN, 0x0a); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_LOW_POWER_RO_CONTROL, 0x0f); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_CMN_MODE, 0x00); +} + +static void pll_20nm_config_loop_bw(void __iomem *pll_base) +{ + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_IP_SETI, 0x03); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_CP_SETI, 0x3F); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_IP_SETP, 0x03); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_CP_SETP, 0x1F); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_CRCTRL, 0x77); +} + +static void pll_20nm_vco_rate_calc(struct mdss_pll_vco_calc *vco_calc, + s64 vco_clk_rate, s64 ref_clk_rate) +{ + s64 multiplier = (1 << 20); + s64 duration = 1024, pll_comp_val; + s64 dec_start_multiple, dec_start; + s32 div_frac_start; + s64 dec_start1, dec_start2; + s32 div_frac_start1, div_frac_start2, div_frac_start3; + s64 pll_plllock_cmp1, pll_plllock_cmp2, pll_plllock_cmp3; + + memset(vco_calc, 0, sizeof(*vco_calc)); + pr_debug("vco_clk_rate=%lld ref_clk_rate=%lld\n", vco_clk_rate, + ref_clk_rate); + + dec_start_multiple = div_s64(vco_clk_rate * multiplier, + 2 * ref_clk_rate); + div_s64_rem(dec_start_multiple, + multiplier, &div_frac_start); + + dec_start = div_s64(dec_start_multiple, multiplier); + dec_start1 = (dec_start & 0x7f) | BIT(7); + dec_start2 = ((dec_start & 0x80) >> 7) | BIT(1); + div_frac_start1 = (div_frac_start & 0x7f) | BIT(7); + div_frac_start2 = ((div_frac_start >> 7) & 0x7f) | BIT(7); + div_frac_start3 = ((div_frac_start >> 14) & 0x3f) | BIT(6); + pll_comp_val = (div_s64(dec_start_multiple * 2 * duration, + 10 * multiplier)) - 1; + pll_plllock_cmp1 = pll_comp_val & 0xff; + pll_plllock_cmp2 = (pll_comp_val >> 8) & 0xff; + pll_plllock_cmp3 = (pll_comp_val >> 16) & 0xff; + + pr_debug("dec_start_multiple = 0x%llx\n", dec_start_multiple); + pr_debug("dec_start = 0x%llx, div_frac_start = 0x%x\n", + dec_start, div_frac_start); + pr_debug("dec_start1 = 0x%llx, dec_start2 = 0x%llx\n", + dec_start1, dec_start2); + pr_debug("div_frac_start1 = 0x%x, div_frac_start2 = 0x%x\n", + div_frac_start1, div_frac_start2); + pr_debug("div_frac_start3 = 0x%x\n", div_frac_start3); + pr_debug("pll_comp_val = 0x%llx\n", pll_comp_val); + pr_debug("pll_plllock_cmp1 = 0x%llx, pll_plllock_cmp2 =%llx\n", + pll_plllock_cmp1, pll_plllock_cmp2); + pr_debug("pll_plllock_cmp3 = 0x%llx\n", pll_plllock_cmp3); + + /* Assign to vco struct */ + vco_calc->div_frac_start1 = div_frac_start1; + vco_calc->div_frac_start2 = div_frac_start2; + vco_calc->div_frac_start3 = div_frac_start3; + vco_calc->dec_start1 = dec_start1; + vco_calc->dec_start2 = dec_start2; + vco_calc->pll_plllock_cmp1 = pll_plllock_cmp1; + vco_calc->pll_plllock_cmp2 = pll_plllock_cmp2; + vco_calc->pll_plllock_cmp3 = pll_plllock_cmp3; +} + +static void pll_20nm_config_vco_rate(void __iomem *pll_base, + struct mdss_pll_vco_calc *vco_calc) +{ + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DIV_FRAC_START1, + vco_calc->div_frac_start1); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DIV_FRAC_START2, + vco_calc->div_frac_start2); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DIV_FRAC_START3, + vco_calc->div_frac_start3); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DEC_START1, + vco_calc->dec_start1); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_DEC_START2, + vco_calc->dec_start2); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLLLOCK_CMP1, + vco_calc->pll_plllock_cmp1); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLLLOCK_CMP2, + vco_calc->pll_plllock_cmp2); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLLLOCK_CMP3, + vco_calc->pll_plllock_cmp3); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN, 0x01); +} + +int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate) +{ + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + dsi_pll_res->vco_current_rate = rate; + dsi_pll_res->vco_ref_clk_rate = vco->ref_clk_rate; + + return 0; +} + +int shadow_pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, + unsigned long rate) +{ + struct mdss_pll_resources *dsi_pll_res = vco->priv; + struct mdss_pll_vco_calc vco_calc; + s64 vco_clk_rate = rate; + u32 rem; + + if (!dsi_pll_res->resource_enable) { + pr_err("PLL resources disabled. Dynamic fps invalid\n"); + return -EINVAL; + } + + pr_debug("req vco set rate: %lld\n", vco_clk_rate); + + pll_20nm_override_trim_codes(dsi_pll_res); + + /* div fraction, start and comp calculations */ + pll_20nm_vco_rate_calc(&vco_calc, vco_clk_rate, + dsi_pll_res->vco_ref_clk_rate); + + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL0, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN, + 0xB1, 0); + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL1, + MMSS_DSI_PHY_PLL_PLLLOCK_CMP1, + MMSS_DSI_PHY_PLL_PLLLOCK_CMP2, + vco_calc.pll_plllock_cmp1, vco_calc.pll_plllock_cmp2); + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL2, + MMSS_DSI_PHY_PLL_PLLLOCK_CMP3, + MMSS_DSI_PHY_PLL_DEC_START1, + vco_calc.pll_plllock_cmp3, vco_calc.dec_start1); + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL3, + MMSS_DSI_PHY_PLL_DEC_START2, + MMSS_DSI_PHY_PLL_DIV_FRAC_START1, + vco_calc.dec_start2, vco_calc.div_frac_start1); + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL4, + MMSS_DSI_PHY_PLL_DIV_FRAC_START2, + MMSS_DSI_PHY_PLL_DIV_FRAC_START3, + vco_calc.div_frac_start2, vco_calc.div_frac_start3); + /* Method 2 - Auto PLL calibration */ + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL7, + MMSS_DSI_PHY_PLL_PLL_VCO_TUNE, + MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN, + 0, 0x0D); + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL8, + MMSS_DSI_PHY_PLL_POST_DIVIDER_CONTROL, + MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, + 0xF0, 0x07); + + /* + * RESETSM_CTRL3 has to be set for 12 times (6 reg writes), + * Each register setting write 2 times, running in loop for 5 + * times (5 reg writes) and other two iterations are taken + * care (one above and other in shadow_bypass + */ + for (rem = 0; rem < 5; rem++) { + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL9 + (4 * rem), + MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, + MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, + 0x07, 0x07); + } + + MDSS_DYN_PLL_REG_W(dsi_pll_res->dyn_pll_base, + MMSS_DSI_DYNAMIC_REFRESH_PLL_CTRL15, + MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, + MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, + 0x03, 0x03); + + /* memory barrier */ + wmb(); + return 0; +} + +unsigned long pll_20nm_vco_get_rate(struct clk *c) +{ + u64 vco_rate, multiplier = (1 << 20); + s32 div_frac_start; + u32 dec_start; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + u64 ref_clk = vco->ref_clk_rate; + int rc; + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + dec_start = (MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_DEC_START2) & BIT(0)) << 7; + dec_start |= (MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_DEC_START1) & 0x7f); + pr_debug("dec_start = 0x%x\n", dec_start); + + div_frac_start = (MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_DIV_FRAC_START3) & 0x3f) << 14; + div_frac_start |= (MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_DIV_FRAC_START2) & 0x7f) << 7; + div_frac_start |= MDSS_PLL_REG_R(dsi_pll_res->pll_base, + MMSS_DSI_PHY_PLL_DIV_FRAC_START1) & 0x7f; + pr_debug("div_frac_start = 0x%x\n", div_frac_start); + + vco_rate = ref_clk * 2 * dec_start; + vco_rate += ((ref_clk * 2 * div_frac_start) / multiplier); + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(dsi_pll_res, false); + + return (unsigned long)vco_rate; +} +long pll_20nm_vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + return rrate; +} + +enum handoff pll_20nm_vco_handoff(struct clk *c) +{ + int rc; + enum handoff ret = HANDOFF_DISABLED_CLK; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return HANDOFF_DISABLED_CLK; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return ret; + } + + if (pll_20nm_is_pll_locked(dsi_pll_res)) { + dsi_pll_res->handoff_resources = true; + dsi_pll_res->pll_on = true; + c->rate = pll_20nm_vco_get_rate(c); + ret = HANDOFF_ENABLED_CLK; + dsi_pll_res->vco_locking_rate = c->rate; + dsi_pll_res->is_init_locked = true; + pll_20nm_cache_trim_codes(dsi_pll_res); + pr_debug("handoff vco_locking_rate=%llu\n", + dsi_pll_res->vco_locking_rate); + } else { + mdss_pll_resource_enable(dsi_pll_res, false); + dsi_pll_res->vco_locking_rate = 0; + dsi_pll_res->is_init_locked = false; + } + + return ret; +} + +int pll_20nm_vco_prepare(struct clk *c) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res) { + pr_err("Dsi pll resources are not available\n"); + return -EINVAL; + } + + if ((dsi_pll_res->vco_cached_rate != 0) + && (dsi_pll_res->vco_cached_rate == c->rate)) { + rc = c->ops->set_rate(c, dsi_pll_res->vco_cached_rate); + if (rc) { + pr_err("vco_set_rate failed. rc=%d\n", rc); + goto error; + } + } + + rc = dsi_pll_enable(c); + +error: + return rc; +} + +void pll_20nm_vco_unprepare(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res) { + pr_err("Dsi pll resources are not available\n"); + return; + } + + dsi_pll_res->vco_cached_rate = c->rate; + dsi_pll_disable(c); +} + +static void pll_20nm_config_resetsm(void __iomem *pll_base) +{ + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL, 0x24); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL2, 0x07); +} + +static void pll_20nm_config_vco_start(void __iomem *pll_base) +{ + + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x03); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02); + udelay(10); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x03); +} + +static void pll_20nm_config_bypass_cal(void __iomem *pll_base) +{ + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL, 0xac); + MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN, 0x28); +} + +static int pll_20nm_vco_relock(struct mdss_pll_resources *dsi_pll_res) +{ + int rc = 0; + + pll_20nm_override_trim_codes(dsi_pll_res); + pll_20nm_config_bypass_cal(dsi_pll_res->pll_base); + pll_20nm_config_vco_start(dsi_pll_res->pll_base); + + if (!pll_20nm_is_pll_locked(dsi_pll_res)) { + pr_err("DSI PLL re-lock failed\n"); + rc = -EINVAL; + } + + return rc; +} + +static int pll_20nm_vco_init_lock(struct mdss_pll_resources *dsi_pll_res) +{ + int rc = 0; + + pll_20nm_config_resetsm(dsi_pll_res->pll_base); + pll_20nm_config_vco_start(dsi_pll_res->pll_base); + + if (!pll_20nm_is_pll_locked(dsi_pll_res)) { + pr_err("DSI PLL init lock failed\n"); + rc = -EINVAL; + goto init_lock_err; + } + + pll_20nm_cache_trim_codes(dsi_pll_res); + +init_lock_err: + return rc; +} + +int pll_20nm_vco_enable_seq(struct mdss_pll_resources *dsi_pll_res) +{ + int rc = 0; + struct mdss_pll_vco_calc vco_calc; + + if (!dsi_pll_res) { + pr_err("Invalid PLL resources\n"); + return -EINVAL; + } + + pll_20nm_config_common_block_1(dsi_pll_res->pll_1_base); + pll_20nm_config_common_block_1(dsi_pll_res->pll_base); + pll_20nm_config_common_block_2(dsi_pll_res->pll_base); + pll_20nm_config_loop_bw(dsi_pll_res->pll_base); + + pll_20nm_vco_rate_calc(&vco_calc, dsi_pll_res->vco_current_rate, + dsi_pll_res->vco_ref_clk_rate); + pll_20nm_config_vco_rate(dsi_pll_res->pll_base, &vco_calc); + + pr_debug("init lock=%d prev vco_rate=%llu, new vco_rate=%llu\n", + dsi_pll_res->is_init_locked, dsi_pll_res->vco_locking_rate, + dsi_pll_res->vco_current_rate); + /* + * Run auto-lock sequence if it is either bootup initial + * locking or when the vco rate is changed. Otherwise, just + * use stored codes and bypass caliberation. + */ + if (!dsi_pll_res->is_init_locked || (dsi_pll_res->vco_locking_rate != + dsi_pll_res->vco_current_rate)) { + rc = pll_20nm_vco_init_lock(dsi_pll_res); + dsi_pll_res->is_init_locked = (rc) ? false : true; + } else { + rc = pll_20nm_vco_relock(dsi_pll_res); + } + + dsi_pll_res->vco_locking_rate = (rc) ? 0 : + dsi_pll_res->vco_current_rate; + + return rc; +} diff --git a/techpack/display/pll/dsi_pll.h b/techpack/display/pll/dsi_pll.h new file mode 100644 index 0000000000000000000000000000000000000000..35aa8149412042bc9e75fb5946a54bb079715c4d --- /dev/null +++ b/techpack/display/pll/dsi_pll.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_DSI_PLL_H +#define __MDSS_DSI_PLL_H + +#include <linux/clk-provider.h> +#include "pll_drv.h" +#define MAX_DSI_PLL_EN_SEQS 10 + +/* Register offsets for 20nm PHY PLL */ +#define MMSS_DSI_PHY_PLL_PLL_CNTRL (0x0014) +#define MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN (0x002C) +#define MMSS_DSI_PHY_PLL_PLLLOCK_CMP_EN (0x009C) + +struct lpfr_cfg { + unsigned long vco_rate; + u32 r; +}; + +struct dsi_pll_vco_clk { + struct clk_hw hw; + unsigned long ref_clk_rate; + u64 min_rate; + u64 max_rate; + u32 pll_en_seq_cnt; + struct lpfr_cfg *lpfr_lut; + u32 lpfr_lut_size; + void *priv; + + int (*pll_enable_seqs[MAX_DSI_PLL_EN_SEQS]) + (struct mdss_pll_resources *dsi_pll_Res); +}; + +int dsi_pll_clock_register_10nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int dsi_pll_clock_register_7nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); +int dsi_pll_clock_register_28lpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +static inline struct dsi_pll_vco_clk *to_vco_clk_hw(struct clk_hw *hw) +{ + return container_of(hw, struct dsi_pll_vco_clk, hw); +} + +int dsi_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); +#endif diff --git a/techpack/display/pll/dsi_pll_10nm.c b/techpack/display/pll/dsi_pll_10nm.c new file mode 100644 index 0000000000000000000000000000000000000000..3988de1248c56602a1ab3bb6cc004226f4e97d0f --- /dev/null +++ b/techpack/display/pll/dsi_pll_10nm.c @@ -0,0 +1,2181 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include "dsi_pll.h" +#include "pll_drv.h" +#include <dt-bindings/clock/mdss-10nm-pll-clk.h> +#define CREATE_TRACE_POINTS +#include "pll_trace.h" + +#define VCO_DELAY_USEC 1 + +#define MHZ_250 250000000UL +#define MHZ_500 500000000UL +#define MHZ_1000 1000000000UL +#define MHZ_1100 1100000000UL +#define MHZ_1900 1900000000UL +#define MHZ_3000 3000000000UL + +/* Register Offsets from PLL base address */ +#define PLL_ANALOG_CONTROLS_ONE 0x000 +#define PLL_ANALOG_CONTROLS_TWO 0x004 +#define PLL_INT_LOOP_SETTINGS 0x008 +#define PLL_INT_LOOP_SETTINGS_TWO 0x00c +#define PLL_ANALOG_CONTROLS_THREE 0x010 +#define PLL_ANALOG_CONTROLS_FOUR 0x014 +#define PLL_INT_LOOP_CONTROLS 0x018 +#define PLL_DSM_DIVIDER 0x01c +#define PLL_FEEDBACK_DIVIDER 0x020 +#define PLL_SYSTEM_MUXES 0x024 +#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x028 +#define PLL_CMODE 0x02c +#define PLL_CALIBRATION_SETTINGS 0x030 +#define PLL_BAND_SEL_CAL_TIMER_LOW 0x034 +#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x038 +#define PLL_BAND_SEL_CAL_SETTINGS 0x03c +#define PLL_BAND_SEL_MIN 0x040 +#define PLL_BAND_SEL_MAX 0x044 +#define PLL_BAND_SEL_PFILT 0x048 +#define PLL_BAND_SEL_IFILT 0x04c +#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x050 +#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x054 +#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x058 +#define PLL_BAND_SEL_ICODE_HIGH 0x05c +#define PLL_BAND_SEL_ICODE_LOW 0x060 +#define PLL_FREQ_DETECT_SETTINGS_ONE 0x064 +#define PLL_PFILT 0x07c +#define PLL_IFILT 0x080 +#define PLL_GAIN 0x084 +#define PLL_ICODE_LOW 0x088 +#define PLL_ICODE_HIGH 0x08c +#define PLL_LOCKDET 0x090 +#define PLL_OUTDIV 0x094 +#define PLL_FASTLOCK_CONTROL 0x098 +#define PLL_PASS_OUT_OVERRIDE_ONE 0x09c +#define PLL_PASS_OUT_OVERRIDE_TWO 0x0a0 +#define PLL_CORE_OVERRIDE 0x0a4 +#define PLL_CORE_INPUT_OVERRIDE 0x0a8 +#define PLL_RATE_CHANGE 0x0ac +#define PLL_PLL_DIGITAL_TIMERS 0x0b0 +#define PLL_PLL_DIGITAL_TIMERS_TWO 0x0b4 +#define PLL_DEC_FRAC_MUXES 0x0c8 +#define PLL_DECIMAL_DIV_START_1 0x0cc +#define PLL_FRAC_DIV_START_LOW_1 0x0d0 +#define PLL_FRAC_DIV_START_MID_1 0x0d4 +#define PLL_FRAC_DIV_START_HIGH_1 0x0d8 +#define PLL_MASH_CONTROL 0x0ec +#define PLL_SSC_MUX_CONTROL 0x108 +#define PLL_SSC_STEPSIZE_LOW_1 0x10c +#define PLL_SSC_STEPSIZE_HIGH_1 0x110 +#define PLL_SSC_DIV_PER_LOW_1 0x114 +#define PLL_SSC_DIV_PER_HIGH_1 0x118 +#define PLL_SSC_DIV_ADJPER_LOW_1 0x11c +#define PLL_SSC_DIV_ADJPER_HIGH_1 0x120 +#define PLL_SSC_CONTROL 0x13c +#define PLL_PLL_OUTDIV_RATE 0x140 +#define PLL_PLL_LOCKDET_RATE_1 0x144 +#define PLL_PLL_PROP_GAIN_RATE_1 0x14c +#define PLL_PLL_BAND_SET_RATE_1 0x154 +#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x15c +#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x164 +#define PLL_FASTLOCK_EN_BAND 0x16c +#define PLL_FREQ_TUNE_ACCUM_INIT_LOW 0x170 +#define PLL_FREQ_TUNE_ACCUM_INIT_MID 0x174 +#define PLL_FREQ_TUNE_ACCUM_INIT_HIGH 0x178 +#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x17c +#define PLL_PLL_LOCK_OVERRIDE 0x180 +#define PLL_PLL_LOCK_DELAY 0x184 +#define PLL_PLL_LOCK_MIN_DELAY 0x188 +#define PLL_CLOCK_INVERTERS 0x18c +#define PLL_SPARE_AND_JPC_OVERRIDES 0x190 +#define PLL_BIAS_CONTROL_1 0x194 +#define PLL_BIAS_CONTROL_2 0x198 +#define PLL_ALOG_OBSV_BUS_CTRL_1 0x19c +#define PLL_COMMON_STATUS_ONE 0x1a0 + +/* Register Offsets from PHY base address */ +#define PHY_CMN_CLK_CFG0 0x010 +#define PHY_CMN_CLK_CFG1 0x014 +#define PHY_CMN_RBUF_CTRL 0x01c +#define PHY_CMN_PLL_CNTRL 0x038 +#define PHY_CMN_CTRL_0 0x024 +#define PHY_CMN_CTRL_2 0x02c + +/* Bit definition of SSC control registers */ +#define SSC_CENTER BIT(0) +#define SSC_EN BIT(1) +#define SSC_FREQ_UPDATE BIT(2) +#define SSC_FREQ_UPDATE_MUX BIT(3) +#define SSC_UPDATE_SSC BIT(4) +#define SSC_UPDATE_SSC_MUX BIT(5) +#define SSC_START BIT(6) +#define SSC_START_MUX BIT(7) + +/* Dynamic Refresh Control Registers */ +#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x014) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x018) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x01C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x020) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x024) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x028) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x02C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x030) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x034) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x038) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x03C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x040) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x044) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x048) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x04C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x050) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x054) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x058) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x05C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x060) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x064) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x068) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x06C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x070) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x074) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x078) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x07C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x080) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x084) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x088) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x08C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x090) +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x094) +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x098) + +#define DSI_PHY_TO_PLL_OFFSET (0x600) +enum { + DSI_PLL_0, + DSI_PLL_1, + DSI_PLL_MAX +}; + +struct dsi_pll_regs { + u32 pll_prop_gain_rate; + u32 pll_lockdet_rate; + u32 decimal_div_start; + u32 frac_div_start_low; + u32 frac_div_start_mid; + u32 frac_div_start_high; + u32 pll_clock_inverters; + u32 ssc_stepsize_low; + u32 ssc_stepsize_high; + u32 ssc_div_per_low; + u32 ssc_div_per_high; + u32 ssc_adjper_low; + u32 ssc_adjper_high; + u32 ssc_control; +}; + +struct dsi_pll_config { + u32 ref_freq; + bool div_override; + u32 output_div; + bool ignore_frac; + bool disable_prescaler; + bool enable_ssc; + bool ssc_center; + u32 dec_bits; + u32 frac_bits; + u32 lock_timer; + u32 ssc_freq; + u32 ssc_offset; + u32 ssc_adj_per; + u32 thresh_cycles; + u32 refclk_cycles; +}; + +struct dsi_pll_10nm { + struct mdss_pll_resources *rsc; + struct dsi_pll_config pll_configuration; + struct dsi_pll_regs reg_setup; +}; + +static inline int pll_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + u32 data; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + /* + * DSI PHY/PLL should be both powered on when reading PLL + * registers. Since PHY power has been enabled in DSI PHY + * driver, only PLL power is needed to enable here. + */ + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5)); + ndelay(250); + *val = MDSS_PLL_REG_R(rsc->pll_base, reg); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data); + + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int pll_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + MDSS_PLL_REG_W(rsc->pll_base, reg, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *val = MDSS_PLL_REG_R(rsc->phy_base, reg); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + MDSS_PLL_REG_W(rsc->phy_base, reg, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_update_bits_sub(struct mdss_pll_resources *rsc, + unsigned int reg, unsigned int mask, unsigned int val) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg); + reg_val &= ~mask; + reg_val |= (val & mask); + MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val); + + return 0; +} + +static inline int phy_reg_update_bits(void *context, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + rc = phy_reg_update_bits_sub(rsc, reg, mask, val); + if (!rc && rsc->slave) + rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int pclk_mux_read_sel(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + else + *val = (MDSS_PLL_REG_R(rsc->phy_base, reg) & 0x3); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + + +static inline int pclk_mux_write_sel_sub(struct mdss_pll_resources *rsc, + unsigned int reg, unsigned int val) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg); + reg_val &= ~0x03; + reg_val |= val; + + MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val); + + return 0; +} + +static inline int pclk_mux_write_sel(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + rc = pclk_mux_write_sel_sub(rsc, reg, val); + if (!rc && rsc->slave) + rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); + + (void)mdss_pll_resource_enable(rsc, false); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + rsc->cached_cfg1 = val; + + return rc; +} + +static struct mdss_pll_resources *pll_rsc_db[DSI_PLL_MAX]; +static struct dsi_pll_10nm plls[DSI_PLL_MAX]; + +static void dsi_pll_config_slave(struct mdss_pll_resources *rsc) +{ + u32 reg; + struct mdss_pll_resources *orsc = pll_rsc_db[DSI_PLL_1]; + + if (!rsc) + return; + + /* Only DSI PLL0 can act as a master */ + if (rsc->index != DSI_PLL_0) + return; + + /* default configuration: source is either internal or ref clock */ + rsc->slave = NULL; + + if (!orsc) { + pr_debug("slave PLL unavilable, assuming standalone config\n"); + return; + } + + /* check to see if the source of DSI1 PLL bitclk is set to external */ + reg = MDSS_PLL_REG_R(orsc->phy_base, PHY_CMN_CLK_CFG1); + reg &= (BIT(2) | BIT(3)); + if (reg == 0x04) + rsc->slave = pll_rsc_db[DSI_PLL_1]; /* external source */ + + pr_debug("Slave PLL %s\n", rsc->slave ? "configured" : "absent"); +} + +static void dsi_pll_setup_config(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + + config->ref_freq = 19200000; + config->output_div = 1; + config->dec_bits = 8; + config->frac_bits = 18; + config->lock_timer = 64; + config->ssc_freq = 31500; + config->ssc_offset = 5000; + config->ssc_adj_per = 2; + config->thresh_cycles = 32; + config->refclk_cycles = 256; + + config->div_override = false; + config->ignore_frac = false; + config->disable_prescaler = false; + config->enable_ssc = rsc->ssc_en; + config->ssc_center = rsc->ssc_center; + + if (config->enable_ssc) { + if (rsc->ssc_freq) + config->ssc_freq = rsc->ssc_freq; + if (rsc->ssc_ppm) + config->ssc_offset = rsc->ssc_ppm; + } + + dsi_pll_config_slave(rsc); +} + +static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u64 fref = rsc->vco_ref_clk_rate; + u64 pll_freq; + u64 divider; + u64 dec, dec_multiple; + u32 frac; + u64 multiplier; + + pll_freq = rsc->vco_current_rate; + + if (config->disable_prescaler) + divider = fref; + else + divider = fref * 2; + + multiplier = 1 << config->frac_bits; + dec_multiple = div_u64(pll_freq * multiplier, divider); + div_u64_rem(dec_multiple, multiplier, &frac); + + dec = div_u64(dec_multiple, multiplier); + + if (pll_freq <= MHZ_1900) + regs->pll_prop_gain_rate = 8; + else if (pll_freq <= MHZ_3000) + regs->pll_prop_gain_rate = 10; + else + regs->pll_prop_gain_rate = 12; + if (pll_freq < MHZ_1100) + regs->pll_clock_inverters = 8; + else + regs->pll_clock_inverters = 0; + + regs->pll_lockdet_rate = config->lock_timer; + regs->decimal_div_start = dec; + regs->frac_div_start_low = (frac & 0xff); + regs->frac_div_start_mid = (frac & 0xff00) >> 8; + regs->frac_div_start_high = (frac & 0x30000) >> 16; +} + +static void dsi_pll_calc_ssc(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u32 ssc_per; + u32 ssc_mod; + u64 ssc_step_size; + u64 frac; + + if (!config->enable_ssc) { + pr_debug("SSC not enabled\n"); + return; + } + + ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1; + ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); + ssc_per -= ssc_mod; + + frac = regs->frac_div_start_low | + (regs->frac_div_start_mid << 8) | + (regs->frac_div_start_high << 16); + ssc_step_size = regs->decimal_div_start; + ssc_step_size *= (1 << config->frac_bits); + ssc_step_size += frac; + ssc_step_size *= config->ssc_offset; + ssc_step_size *= (config->ssc_adj_per + 1); + ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); + ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); + + regs->ssc_div_per_low = ssc_per & 0xFF; + regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; + regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); + regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); + regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; + regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; + + regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; + + pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", + regs->decimal_div_start, frac, config->frac_bits); + pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", + ssc_per, (u32)ssc_step_size, config->ssc_adj_per); +} + +static void dsi_pll_ssc_commit(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + struct dsi_pll_regs *regs = &pll->reg_setup; + + if (pll->pll_configuration.enable_ssc) { + pr_debug("SSC is enabled\n"); + + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1, + regs->ssc_stepsize_low); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1, + regs->ssc_stepsize_high); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1, + regs->ssc_div_per_low); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1, + regs->ssc_div_per_high); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_ADJPER_LOW_1, + regs->ssc_adjper_low); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_ADJPER_HIGH_1, + regs->ssc_adjper_high); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, + SSC_EN | regs->ssc_control); + } +} + +static void dsi_pll_config_hzindep_reg(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_ONE, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_TWO, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_THREE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_DSM_DIVIDER, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_FEEDBACK_DIVIDER, 0x4e); + MDSS_PLL_REG_W(pll_base, PLL_CALIBRATION_SETTINGS, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); + MDSS_PLL_REG_W(pll_base, PLL_OUTDIV, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_CORE_OVERRIDE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SET_RATE_1, 0xc0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0xfa); + MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_PFILT, 0x29); + MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3f); +} + +static void dsi_pll_init_val(struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x10); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x3f); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x02); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x82); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0xff); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x25); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x4f); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0a); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_GAIN, 0x42); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x30); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x04); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x01); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_EN_BAND, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x19); + MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x0); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x20); + MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x0); +} + +static void dsi_pll_commit(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + struct dsi_pll_regs *reg = &pll->reg_setup; + + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x12); + MDSS_PLL_REG_W(pll_base, PLL_DECIMAL_DIV_START_1, + reg->decimal_div_start); + MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_LOW_1, + reg->frac_div_start_low); + MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_MID_1, + reg->frac_div_start_mid); + MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1, + reg->frac_div_start_high); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06); + MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x10); + MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, reg->pll_clock_inverters); + +} + +static int vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_10nm *pll; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + if (rsc->pll_on) + return 0; + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + + rsc->vco_current_rate = rate; + rsc->vco_ref_clk_rate = vco->ref_clk_rate; + rsc->dfps_trigger = false; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable mdss dsi pll(%d), rc=%d\n", + rsc->index, rc); + return rc; + } + + dsi_pll_init_val(rsc); + + dsi_pll_setup_config(pll, rsc); + + dsi_pll_calc_dec_frac(pll, rsc); + + dsi_pll_calc_ssc(pll, rsc); + + dsi_pll_commit(pll, rsc); + + dsi_pll_config_hzindep_reg(pll, rsc); + + dsi_pll_ssc_commit(pll, rsc); + + /* flush, ensure all register writes are done*/ + wmb(); + + mdss_pll_resource_enable(rsc, false); + + return 0; +} + +static int dsi_pll_read_stored_trim_codes(struct mdss_pll_resources *pll_res, + unsigned long vco_clk_rate) +{ + int i; + bool found = false; + + if (!pll_res->dfps) + return -EINVAL; + + for (i = 0; i < pll_res->dfps->vco_rate_cnt; i++) { + struct dfps_codes_info *codes_info = + &pll_res->dfps->codes_dfps[i]; + + pr_debug("valid=%d vco_rate=%d, code %d %d %d\n", + codes_info->is_valid, codes_info->clk_rate, + codes_info->pll_codes.pll_codes_1, + codes_info->pll_codes.pll_codes_2, + codes_info->pll_codes.pll_codes_3); + + if (vco_clk_rate != codes_info->clk_rate && + codes_info->is_valid) + continue; + + pll_res->cache_pll_trim_codes[0] = + codes_info->pll_codes.pll_codes_1; + pll_res->cache_pll_trim_codes[1] = + codes_info->pll_codes.pll_codes_2; + pll_res->cache_pll_trim_codes[2] = + codes_info->pll_codes.pll_codes_3; + found = true; + break; + } + + if (!found) + return -EINVAL; + + pr_debug("trim_code_0=0x%x trim_code_1=0x%x trim_code_2=0x%x\n", + pll_res->cache_pll_trim_codes[0], + pll_res->cache_pll_trim_codes[1], + pll_res->cache_pll_trim_codes[2]); + + return 0; +} + +static void shadow_dsi_pll_dynamic_refresh_10nm(struct dsi_pll_10nm *pll, + struct mdss_pll_resources *rsc) +{ + u32 data; + u32 offset = DSI_PHY_TO_PLL_OFFSET; + u32 upper_addr = 0; + struct dsi_pll_regs *reg = &pll->reg_setup; + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + data &= ~BIT(5); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL0, + PHY_CMN_CLK_CFG1, PHY_CMN_PLL_CNTRL, data, 0); + upper_addr |= (upper_8_bit(PHY_CMN_CLK_CFG1) << 0); + upper_addr |= (upper_8_bit(PHY_CMN_PLL_CNTRL) << 1); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL1, + PHY_CMN_RBUF_CTRL, + (PLL_DECIMAL_DIV_START_1 + offset), + 0, reg->decimal_div_start); + upper_addr |= (upper_8_bit(PHY_CMN_RBUF_CTRL) << 2); + upper_addr |= (upper_8_bit(PLL_DECIMAL_DIV_START_1 + offset) << 3); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL2, + (PLL_FRAC_DIV_START_LOW_1 + offset), + (PLL_FRAC_DIV_START_MID_1 + offset), + reg->frac_div_start_low, reg->frac_div_start_mid); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_LOW_1 + offset) << 4); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_MID_1 + offset) << 5); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL3, + (PLL_FRAC_DIV_START_HIGH_1 + offset), + (PLL_PLL_PROP_GAIN_RATE_1 + offset), + reg->frac_div_start_high, reg->pll_prop_gain_rate); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_HIGH_1 + offset) << 6); + upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 7); + + data = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE) & 0x03; + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL4, + (PLL_PLL_OUTDIV_RATE + offset), + (PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset), + data, 0); + upper_addr |= (upper_8_bit(PLL_PLL_OUTDIV_RATE + offset) << 8); + upper_addr |= (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_LOW + offset) << 9); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL5, + (PLL_FREQ_TUNE_ACCUM_INIT_MID + offset), + (PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset), + rsc->cache_pll_trim_codes[1], + rsc->cache_pll_trim_codes[0]); + upper_addr |= + (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MID + offset) << 10); + upper_addr |= + (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_HIGH + offset) << 11); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL6, + (PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset), + (PLL_PLL_BAND_SET_RATE_1 + offset), + 0x07, rsc->cache_pll_trim_codes[2]); + upper_addr |= + (upper_8_bit(PLL_FREQ_TUNE_ACCUM_INIT_MUX + offset) << 12); + upper_addr |= (upper_8_bit(PLL_PLL_BAND_SET_RATE_1 + offset) << 13); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL7, + (PLL_CALIBRATION_SETTINGS + offset), + (PLL_BAND_SEL_CAL_SETTINGS + offset), 0x44, 0x3a); + upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 14); + upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS + offset) << 15); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8, + (PLL_PLL_LOCKDET_RATE_1 + offset), + (PLL_PLL_LOCK_DELAY + offset), 0x10, 0x06); + upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 16); + upper_addr |= (upper_8_bit(PLL_PLL_LOCK_DELAY + offset) << 17); + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL17, + PHY_CMN_CTRL_2, PHY_CMN_CLK_CFG0, 0x40, data); + if (rsc->slave) + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL10, + PHY_CMN_CLK_CFG0, PHY_CMN_CTRL_0, + data, 0x7f); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + /* Dummy register writes */ + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL19, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL20, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL21, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL22, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL23, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL24, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL25, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL26, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL28, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL29, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + + /* Registers to configure after PLL enable delay */ + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1) | BIT(5); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL30, + PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, data, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL31, + PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, data, data); + if (rsc->slave) { + data = MDSS_PLL_REG_R(rsc->slave->phy_base, PHY_CMN_CLK_CFG1) | + BIT(5); + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL30, + PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, + data, 0x01); + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL31, + PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, + data, data); + } + + MDSS_PLL_REG_W(rsc->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, upper_addr); + MDSS_PLL_REG_W(rsc->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0); + wmb(); /* commit register writes */ +} + +static int shadow_vco_10nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_10nm *pll; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + rc = dsi_pll_read_stored_trim_codes(rsc, rate); + if (rc) { + pr_err("cannot find pll codes rate=%ld\n", rate); + return -EINVAL; + } + pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + + rsc->vco_current_rate = rate; + rsc->vco_ref_clk_rate = vco->ref_clk_rate; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable mdss dsi pll(%d), rc=%d\n", + rsc->index, rc); + return rc; + } + + dsi_pll_setup_config(pll, rsc); + + dsi_pll_calc_dec_frac(pll, rsc); + + /* program dynamic refresh control registers */ + shadow_dsi_pll_dynamic_refresh_10nm(pll, rsc); + + /* update cached vco rate */ + rsc->vco_cached_rate = rate; + rsc->dfps_trigger = true; + + mdss_pll_resource_enable(rsc, false); + + return 0; +} + +static int dsi_pll_10nm_lock_status(struct mdss_pll_resources *pll) +{ + int rc; + u32 status; + u32 const delay_us = 100; + u32 const timeout_us = 5000; + + rc = readl_poll_timeout_atomic(pll->pll_base + PLL_COMMON_STATUS_ONE, + status, + ((status & BIT(0)) > 0), + delay_us, + timeout_us); + if (rc) + pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", + pll->index, status); + + return rc; +} + +static void dsi_pll_disable_pll_bias(struct mdss_pll_resources *rsc) +{ + u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + + MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5)); + ndelay(250); +} + +static void dsi_pll_enable_pll_bias(struct mdss_pll_resources *rsc) +{ + u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5)); + MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0xc0); + ndelay(250); +} + +static void dsi_pll_disable_global_clk(struct mdss_pll_resources *rsc) +{ + u32 data; + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data & ~BIT(5))); +} + +static void dsi_pll_enable_global_clk(struct mdss_pll_resources *rsc) +{ + u32 data; + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data | BIT(5))); +} + +static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) +{ + int rc; + struct mdss_pll_resources *rsc = vco->priv; + + dsi_pll_enable_pll_bias(rsc); + if (rsc->slave) + dsi_pll_enable_pll_bias(rsc->slave); + + phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1); + if (rsc->slave) + phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1, + 0x03, rsc->slave->cached_cfg1); + wmb(); /* ensure dsiclk_sel is always programmed before pll start */ + + /* Start PLL */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); + + /* + * ensure all PLL configurations are written prior to checking + * for PLL lock. + */ + wmb(); + + /* Check for PLL lock */ + rc = dsi_pll_10nm_lock_status(rsc); + if (rc) { + pr_err("PLL(%d) lock failed\n", rsc->index); + goto error; + } + + rsc->pll_on = true; + + dsi_pll_enable_global_clk(rsc); + if (rsc->slave) + dsi_pll_enable_global_clk(rsc->slave); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0x01); + if (rsc->slave) + MDSS_PLL_REG_W(rsc->slave->phy_base, PHY_CMN_RBUF_CTRL, 0x01); + +error: + return rc; +} + +static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc) +{ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0); + dsi_pll_disable_pll_bias(rsc); +} + +static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) +{ + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc->pll_on && + mdss_pll_resource_enable(rsc, true)) { + pr_err("failed to enable pll (%d) resources\n", rsc->index); + return; + } + + rsc->handoff_resources = false; + rsc->dfps_trigger = false; + + pr_debug("stop PLL (%d)\n", rsc->index); + + /* + * To avoid any stray glitches while + * abruptly powering down the PLL + * make sure to gate the clock using + * the clock enable bit before powering + * down the PLL + */ + dsi_pll_disable_global_clk(rsc); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0); + dsi_pll_disable_sub(rsc); + if (rsc->slave) { + dsi_pll_disable_global_clk(rsc->slave); + dsi_pll_disable_sub(rsc->slave); + } + /* flush, ensure all register writes are done*/ + wmb(); + rsc->pll_on = false; +} + +long vco_10nm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + *parent_rate = rrate; + + return rrate; +} + +static void vco_10nm_unprepare(struct clk_hw *hw) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("dsi pll resources not available\n"); + return; + } + + /* + * During unprepare in continuous splash use case we want driver + * to pick all dividers instead of retaining bootloader configurations. + * Also handle use cases where dynamic refresh triggered before + * first suspend/resume. + */ + if (!pll->handoff_resources || pll->dfps_trigger) { + pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, + PHY_CMN_CLK_CFG0); + pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, + PLL_PLL_OUTDIV_RATE); + pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0, + pll->cached_cfg1, pll->cached_outdiv); + + pll->vco_cached_rate = clk_get_rate(hw->clk); + } + + /* + * When continuous splash screen feature is enabled, we need to cache + * the mux configuration for the pixel_clk_src mux clock. The clock + * framework does not call back to re-configure the mux value if it is + * does not change.For such usecases, we need to ensure that the cached + * value is programmed prior to PLL being locked + */ + if (pll->handoff_resources) { + pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base, + PHY_CMN_CLK_CFG1); + if (pll->slave) + pll->slave->cached_cfg1 = + MDSS_PLL_REG_R(pll->slave->phy_base, + PHY_CMN_CLK_CFG1); + } + + dsi_pll_disable(vco); + mdss_pll_resource_enable(pll, false); +} + +static int vco_10nm_prepare(struct clk_hw *hw) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("dsi pll resources are not available\n"); + return -EINVAL; + } + + /* Skip vco recalculation for continuous splash use case */ + if (pll->handoff_resources) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("failed to enable pll (%d) resource, rc=%d\n", + pll->index, rc); + return rc; + } + + if ((pll->vco_cached_rate != 0) && + (pll->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate, + pll->vco_cached_rate); + if (rc) { + pr_err("pll(%d) set_rate failed, rc=%d\n", + pll->index, rc); + mdss_pll_resource_enable(pll, false); + return rc; + } + pr_debug("cfg0=%d, cfg1=%d\n", pll->cached_cfg0, + pll->cached_cfg1); + MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, + pll->cached_cfg0); + if (pll->slave) + MDSS_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, + pll->cached_cfg0); + MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, + pll->cached_outdiv); + } + MDSS_PLL_ATRACE_BEGIN("pll_lock"); + trace_mdss_pll_lock_start((u64)pll->vco_cached_rate, + pll->vco_current_rate, + pll->cached_cfg0, pll->cached_cfg1, + pll->cached_outdiv, pll->resource_ref_cnt); + rc = dsi_pll_enable(vco); + MDSS_PLL_ATRACE_END("pll_lock"); + if (rc) { + mdss_pll_resource_enable(pll, false); + pr_err("pll(%d) enable failed, rc=%d\n", pll->index, rc); + return rc; + } + + return rc; +} + +static unsigned long vco_10nm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + int rc; + + if (!vco->priv) + pr_err("vco priv is null\n"); + + if (!pll) { + pr_err("pll is null\n"); + return 0; + } + + /* + * In the case when vco arte is set, the recalculation function should + * return the current rate as to avoid trying to set the vco rate + * again. However durng handoff, recalculation should set the flag + * according to the status of PLL. + */ + if (pll->vco_current_rate != 0) { + pr_debug("returning vco rate = %lld\n", pll->vco_current_rate); + return pll->vco_current_rate; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("failed to enable pll(%d) resource, rc=%d\n", + pll->index, rc); + return 0; + } + + if (!dsi_pll_10nm_lock_status(pll)) + pll->handoff_resources = true; + + + (void)mdss_pll_resource_enable(pll, false); + + return rc; +} + +static int pixel_clk_get_div(void *context, unsigned int reg, unsigned int *div) +{ + int rc; + struct mdss_pll_resources *pll = context; + u32 reg_val; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); + *div = (reg_val & 0xF0) >> 4; + + /** + * Common clock framework the divider value is interpreted as one less + * hence we return one less for all dividers except when zero + */ + if (*div != 0) + *div -= 1; + + (void)mdss_pll_resource_enable(pll, false); + + return rc; +} + +static void pixel_clk_set_div_sub(struct mdss_pll_resources *pll, int div) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); + reg_val &= ~0xF0; + reg_val |= (div << 4); + MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + pll->cached_cfg0 = reg_val; +} + +static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div) +{ + int rc; + struct mdss_pll_resources *pll = context; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + /** + * In common clock framework the divider value provided is one less and + * and hence adjusting the divider value by one prior to writing it to + * hardware + */ + div++; + pixel_clk_set_div_sub(pll, div); + if (pll->slave) + pixel_clk_set_div_sub(pll->slave, div); + (void)mdss_pll_resource_enable(pll, false); + + return 0; +} + +static int bit_clk_get_div(void *context, unsigned int reg, unsigned int *div) +{ + int rc; + struct mdss_pll_resources *pll = context; + u32 reg_val; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); + *div = (reg_val & 0x0F); + + /** + *Common clock framework the divider value is interpreted as one less + * hence we return one less for all dividers except when zero + */ + if (*div != 0) + *div -= 1; + (void)mdss_pll_resource_enable(pll, false); + + return rc; +} + +static void bit_clk_set_div_sub(struct mdss_pll_resources *rsc, int div) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); + reg_val &= ~0x0F; + reg_val |= div; + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG0, reg_val); +} + +static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div) +{ + int rc; + struct mdss_pll_resources *rsc = context; + struct dsi_pll_8998 *pll; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + /** + * In common clock framework the divider value provided is one less and + * and hence adjusting the divider value by one prior to writing it to + * hardware + */ + div++; + + bit_clk_set_div_sub(rsc, div); + /* For slave PLL, this divider always should be set to 1 */ + if (rsc->slave) + bit_clk_set_div_sub(rsc->slave, 1); + + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static struct regmap_config dsi_pll_10nm_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x7c0, +}; + +static struct regmap_bus pll_regmap_bus = { + .reg_write = pll_reg_write, + .reg_read = pll_reg_read, +}; + +static struct regmap_bus pclk_src_mux_regmap_bus = { + .reg_read = pclk_mux_read_sel, + .reg_write = pclk_mux_write_sel, +}; + +static struct regmap_bus pclk_src_regmap_bus = { + .reg_write = pixel_clk_set_div, + .reg_read = pixel_clk_get_div, +}; + +static struct regmap_bus bitclk_src_regmap_bus = { + .reg_write = bit_clk_set_div, + .reg_read = bit_clk_get_div, +}; + +static const struct clk_ops clk_ops_vco_10nm = { + .recalc_rate = vco_10nm_recalc_rate, + .set_rate = vco_10nm_set_rate, + .round_rate = vco_10nm_round_rate, + .prepare = vco_10nm_prepare, + .unprepare = vco_10nm_unprepare, +}; + +static const struct clk_ops clk_ops_shadow_vco_10nm = { + .recalc_rate = vco_10nm_recalc_rate, + .set_rate = shadow_vco_10nm_set_rate, + .round_rate = vco_10nm_round_rate, +}; + +static struct regmap_bus mdss_mux_regmap_bus = { + .reg_write = mdss_set_mux_sel, + .reg_read = mdss_get_mux_sel, +}; + +/* + * Clock tree for generating DSI byte and pixel clocks. + * + * + * +---------------+ + * | vco_clk | + * +-------+-------+ + * | + * | + * +---------------+ + * | pll_out_div | + * | DIV(1,2,4,8) | + * +-------+-------+ + * | + * +-----------------------------+--------+ + * | | | + * +-------v-------+ | | + * | bitclk_src | | | + * | DIV(1..15) | | | + * +-------+-------+ | | + * | | | + * +----------+---------+ | | + * Shadow Path | | | | | + * + +-------v-------+ | +------v------+ | +------v-------+ + * | | byteclk_src | | |post_bit_div | | |post_vco_div | + * | | DIV(8) | | |DIV (2) | | |DIV(4) | + * | +-------+-------+ | +------+------+ | +------+-------+ + * | | | | | | | + * | | | +------+ | | + * | | +-------------+ | | +----+ + * | +--------+ | | | | + * | | +-v--v-v---v------+ + * +-v---------v----+ \ pclk_src_mux / + * \ byteclk_mux / \ / + * \ / +-----+-----+ + * +----+-----+ | Shadow Path + * | | + + * v +-----v------+ | + * dsi_byte_clk | pclk_src | | + * | DIV(1..15) | | + * +-----+------+ | + * | | + * | | + * +--------+ | + * | | + * +---v----v----+ + * \ pclk_mux / + * \ / + * +---+---+ + * | + * | + * v + * dsi_pclk + * + */ + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_vco_10nm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_shadow_vco_10nm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_vco_10nm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_shadow_vco_10nm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap_div dsi0pll_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pll_out_div", + .parent_names = (const char *[]){"dsi0pll_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pll_out_div", + .parent_names = (const char *[]){ + "dsi0pll_shadow_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pll_out_div", + .parent_names = (const char *[]){"dsi1pll_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pll_out_div", + .parent_names = (const char *[]){ + "dsi1pll_shadow_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_bitclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_bitclk_src", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_bitclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_bitclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_bitclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_bitclk_src", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_bitclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_bitclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_vco_div", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_vco_div", + .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_vco_div", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_vco_div", + .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_bit_div", + .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_bit_div", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_bit_div", + .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_bit_div", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_byteclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0_phy_pll_out_byteclk", + .parent_names = (const char *[]){"dsi0pll_byteclk_src", + "dsi0pll_shadow_byteclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_byteclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1_phy_pll_out_byteclk", + .parent_names = (const char *[]){"dsi1pll_byteclk_src", + "dsi1pll_shadow_byteclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pclk_src_mux", + .parent_names = (const char *[]){"dsi0pll_bitclk_src", + "dsi0pll_post_bit_div", + "dsi0pll_pll_out_div", + "dsi0pll_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_shadow_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pclk_src_mux", + .parent_names = (const char *[]){ + "dsi0pll_shadow_bitclk_src", + "dsi0pll_shadow_post_bit_div", + "dsi0pll_shadow_pll_out_div", + "dsi0pll_shadow_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pclk_src_mux", + .parent_names = (const char *[]){"dsi1pll_bitclk_src", + "dsi1pll_post_bit_div", + "dsi1pll_pll_out_div", + "dsi1pll_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_shadow_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pclk_src_mux", + .parent_names = (const char *[]){ + "dsi1pll_shadow_bitclk_src", + "dsi1pll_shadow_post_bit_div", + "dsi1pll_shadow_pll_out_div", + "dsi1pll_shadow_post_vco_div"}, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_pclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_pclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_pclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_pclk_src = { + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_pclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0_phy_pll_out_dsiclk", + .parent_names = (const char *[]){"dsi0pll_pclk_src", + "dsi0pll_shadow_pclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_pclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1_phy_pll_out_dsiclk", + .parent_names = (const char *[]){"dsi1pll_pclk_src", + "dsi1pll_shadow_pclk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_hw *mdss_dsi_pllcc_10nm[] = { + [VCO_CLK_0] = &dsi0pll_vco_clk.hw, + [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw, + [BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw, + [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw, + [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw, + [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw, + [BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw, + [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw, + [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, + [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw, + [SHADOW_VCO_CLK_0] = &dsi0pll_shadow_vco_clk.hw, + [SHADOW_PLL_OUT_DIV_0_CLK] = &dsi0pll_shadow_pll_out_div.clkr.hw, + [SHADOW_BITCLK_SRC_0_CLK] = &dsi0pll_shadow_bitclk_src.clkr.hw, + [SHADOW_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_byteclk_src.hw, + [SHADOW_POST_BIT_DIV_0_CLK] = &dsi0pll_shadow_post_bit_div.hw, + [SHADOW_POST_VCO_DIV_0_CLK] = &dsi0pll_shadow_post_vco_div.hw, + [SHADOW_PCLK_SRC_MUX_0_CLK] = &dsi0pll_shadow_pclk_src_mux.clkr.hw, + [SHADOW_PCLK_SRC_0_CLK] = &dsi0pll_shadow_pclk_src.clkr.hw, + [VCO_CLK_1] = &dsi1pll_vco_clk.hw, + [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw, + [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw, + [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw, + [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw, + [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw, + [BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw, + [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw, + [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, + [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw, + [SHADOW_VCO_CLK_1] = &dsi1pll_shadow_vco_clk.hw, + [SHADOW_PLL_OUT_DIV_1_CLK] = &dsi1pll_shadow_pll_out_div.clkr.hw, + [SHADOW_BITCLK_SRC_1_CLK] = &dsi1pll_shadow_bitclk_src.clkr.hw, + [SHADOW_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_byteclk_src.hw, + [SHADOW_POST_BIT_DIV_1_CLK] = &dsi1pll_shadow_post_bit_div.hw, + [SHADOW_POST_VCO_DIV_1_CLK] = &dsi1pll_shadow_post_vco_div.hw, + [SHADOW_PCLK_SRC_MUX_1_CLK] = &dsi1pll_shadow_pclk_src_mux.clkr.hw, + [SHADOW_PCLK_SRC_1_CLK] = &dsi1pll_shadow_pclk_src.clkr.hw, +}; + +int dsi_pll_clock_register_10nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx, i; + struct clk *clk; + struct clk_onecell_data *clk_data; + int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_10nm); + struct regmap *rmap; + + ndx = pll_res->index; + + if (ndx >= DSI_PLL_MAX) { + pr_err("pll index(%d) NOT supported\n", ndx); + return -EINVAL; + } + + pll_rsc_db[ndx] = pll_res; + plls[ndx].rsc = pll_res; + pll_res->priv = &plls[ndx]; + pll_res->vco_delay = VCO_DELAY_USEC; + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + /* Establish client data */ + if (ndx == 0) { + rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi0pll_pll_out_div.clkr.regmap = rmap; + dsi0pll_shadow_pll_out_div.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi0pll_bitclk_src.clkr.regmap = rmap; + dsi0pll_shadow_bitclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi0pll_pclk_src.clkr.regmap = rmap; + dsi0pll_shadow_pclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi0pll_pclk_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi0pll_pclk_src_mux.clkr.regmap = rmap; + dsi0pll_shadow_pclk_src_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi0pll_byteclk_mux.clkr.regmap = rmap; + + dsi0pll_vco_clk.priv = pll_res; + dsi0pll_shadow_vco_clk.priv = pll_res; + + for (i = VCO_CLK_0; i <= SHADOW_PCLK_SRC_0_CLK; i++) { + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_10nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI clock:%d\n", + pll_res->index); + rc = -EINVAL; + goto clk_register_fail; + } + clk_data->clks[i] = clk; + + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } else { + rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi1pll_pll_out_div.clkr.regmap = rmap; + dsi1pll_shadow_pll_out_div.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi1pll_bitclk_src.clkr.regmap = rmap; + dsi1pll_shadow_bitclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi1pll_pclk_src.clkr.regmap = rmap; + dsi1pll_shadow_pclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi1pll_pclk_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi1pll_pclk_src_mux.clkr.regmap = rmap; + dsi1pll_shadow_pclk_src_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_10nm_config); + dsi1pll_byteclk_mux.clkr.regmap = rmap; + + dsi1pll_vco_clk.priv = pll_res; + dsi1pll_shadow_vco_clk.priv = pll_res; + + for (i = VCO_CLK_1; i <= SHADOW_PCLK_SRC_1_CLK; i++) { + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_10nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI clock:%d\n", + pll_res->index); + rc = -EINVAL; + goto clk_register_fail; + } + clk_data->clks[i] = clk; + + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } + if (!rc) { + pr_info("Registered DSI PLL ndx=%d, clocks successfully\n", + ndx); + + return rc; + } +clk_register_fail: + return rc; +} diff --git a/techpack/display/pll/dsi_pll_14nm.c b/techpack/display/pll/dsi_pll_14nm.c new file mode 100644 index 0000000000000000000000000000000000000000..c1cb867f675f49ebabea97ff2a4fd5196ca42289 --- /dev/null +++ b/techpack/display/pll/dsi_pll_14nm.c @@ -0,0 +1,596 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/workqueue.h> + +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dsi_pll_14nm.h" +#include <dt-bindings/clock/mdss-14nm-pll-clk.h> + +#define VCO_DELAY_USEC 1 + +static struct dsi_pll_db pll_db[DSI_PLL_NUM]; + +static struct regmap_config dsi_pll_14nm_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x588, +}; + +static struct regmap_bus post_n1_div_regmap_bus = { + .reg_write = post_n1_div_set_div, + .reg_read = post_n1_div_get_div, +}; + +static struct regmap_bus n2_div_regmap_bus = { + .reg_write = n2_div_set_div, + .reg_read = n2_div_get_div, +}; + +static struct regmap_bus shadow_n2_div_regmap_bus = { + .reg_write = shadow_n2_div_set_div, + .reg_read = n2_div_get_div, +}; + +static struct regmap_bus dsi_mux_regmap_bus = { + .reg_write = dsi_mux_set_parent_14nm, + .reg_read = dsi_mux_get_parent_14nm, +}; + +/* Op structures */ +static const struct clk_ops clk_ops_dsi_vco = { + .recalc_rate = pll_vco_recalc_rate_14nm, + .set_rate = pll_vco_set_rate_14nm, + .round_rate = pll_vco_round_rate_14nm, + .prepare = pll_vco_prepare_14nm, + .unprepare = pll_vco_unprepare_14nm, +}; + +/* Shadow ops for dynamic refresh */ +static const struct clk_ops clk_ops_shadow_dsi_vco = { + .recalc_rate = pll_vco_recalc_rate_14nm, + .set_rate = shadow_pll_vco_set_rate_14nm, + .round_rate = pll_vco_round_rate_14nm, +}; + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1300000000UL, + .max_rate = 2600000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_vco_clk_14nm", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_ops_dsi_vco, + }, +}; + +static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { + .ref_clk_rate = 19200000u, + .min_rate = 1300000000u, + .max_rate = 2600000000u, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_vco_clk_14nm", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_ops_shadow_dsi_vco, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1300000000UL, + .max_rate = 2600000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_vco_clk_14nm", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_ops_dsi_vco, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { + .ref_clk_rate = 19200000u, + .min_rate = 1300000000u, + .max_rate = 2600000000u, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_14nm, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_vco_clk_14nm", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_ops_shadow_dsi_vco, + }, +}; + +static struct clk_regmap_div dsi0pll_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_n1_div_clk", + .parent_names = + (const char *[]){ "dsi0pll_vco_clk_14nm" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_n1_div_clk", + .parent_names = + (const char *[]){"dsi0pll_shadow_vco_clk_14nm"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_n1_div_clk", + .parent_names = + (const char *[]){ "dsi1pll_vco_clk_14nm" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_post_n1_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_n1_div_clk", + .parent_names = + (const char *[]){"dsi1pll_shadow_vco_clk_14nm"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_n2_div_clk", + .parent_names = + (const char *[]){ "dsi0pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_n2_div_clk", + .parent_names = + (const char *[]){ "dsi0pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_n2_div_clk", + .parent_names = + (const char *[]){ "dsi1pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_n2_div_clk = { + .reg = 0x48, + .shift = 0, + .width = 4, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_n2_div_clk", + .parent_names = + (const char *[]){ "dsi1pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pixel_clk_src", + .parent_names = (const char *[]){ "dsi0pll_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pixel_clk_src", + .parent_names = (const char *[]){ "dsi0pll_shadow_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pixel_clk_src", + .parent_names = (const char *[]){ "dsi1pll_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_pixel_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pixel_clk_src", + .parent_names = (const char *[]){ "dsi1pll_shadow_n2_div_clk" }, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_pixel_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0_phy_pll_out_dsiclk", + .parent_names = + (const char *[]){ "dsi0pll_pixel_clk_src", + "dsi0pll_shadow_pixel_clk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_pixel_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pixel_clk_mux", + .parent_names = + (const char *[]){ "dsi1pll_pixel_clk_src", + "dsi1pll_shadow_pixel_clk_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byte_clk_src", + .parent_names = (const char *[]){ "dsi0pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_byte_clk_src", + .parent_names = + (const char *[]){ "dsi0pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byte_clk_src", + .parent_names = (const char *[]){ "dsi1pll_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_byte_clk_src = { + .div = 8, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_byte_clk_src", + .parent_names = + (const char *[]){ "dsi1pll_shadow_post_n1_div_clk" }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_byte_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0_phy_pll_out_byteclk", + .parent_names = + (const char *[]){"dsi0pll_byte_clk_src", + "dsi0pll_shadow_byte_clk_src"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_byte_clk_mux = { + .reg = 0x48, + .shift = 0, + .width = 1, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byte_clk_mux", + .parent_names = + (const char *[]){"dsi1pll_byte_clk_src", + "dsi1pll_shadow_byte_clk_src"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + }, + }, +}; + +static struct clk_hw *mdss_dsi_pllcc_14nm[] = { + [BYTE0_MUX_CLK] = &dsi0pll_byte_clk_mux.clkr.hw, + [BYTE0_SRC_CLK] = &dsi0pll_byte_clk_src.hw, + [PIX0_MUX_CLK] = &dsi0pll_pixel_clk_mux.clkr.hw, + [PIX0_SRC_CLK] = &dsi0pll_pixel_clk_src.hw, + [N2_DIV_0_CLK] = &dsi0pll_n2_div_clk.clkr.hw, + [POST_N1_DIV_0_CLK] = &dsi0pll_post_n1_div_clk.clkr.hw, + [VCO_CLK_0_CLK] = &dsi0pll_vco_clk.hw, + [SHADOW_BYTE0_SRC_CLK] = &dsi0pll_shadow_byte_clk_src.hw, + [SHADOW_PIX0_SRC_CLK] = &dsi0pll_shadow_pixel_clk_src.hw, + [SHADOW_N2_DIV_0_CLK] = &dsi0pll_shadow_n2_div_clk.clkr.hw, + [SHADOW_POST_N1_DIV_0_CLK] = &dsi0pll_shadow_post_n1_div_clk.clkr.hw, + [SHADOW_VCO_CLK_0_CLK] = &dsi0pll_shadow_vco_clk.hw, + [BYTE1_MUX_CLK] = &dsi1pll_byte_clk_mux.clkr.hw, + [BYTE1_SRC_CLK] = &dsi1pll_byte_clk_src.hw, + [PIX1_MUX_CLK] = &dsi1pll_pixel_clk_mux.clkr.hw, + [PIX1_SRC_CLK] = &dsi1pll_pixel_clk_src.hw, + [N2_DIV_1_CLK] = &dsi1pll_n2_div_clk.clkr.hw, + [POST_N1_DIV_1_CLK] = &dsi1pll_post_n1_div_clk.clkr.hw, + [VCO_CLK_1_CLK] = &dsi1pll_vco_clk.hw, + [SHADOW_BYTE1_SRC_CLK] = &dsi1pll_shadow_byte_clk_src.hw, + [SHADOW_PIX1_SRC_CLK] = &dsi1pll_shadow_pixel_clk_src.hw, + [SHADOW_N2_DIV_1_CLK] = &dsi1pll_shadow_n2_div_clk.clkr.hw, + [SHADOW_POST_N1_DIV_1_CLK] = &dsi1pll_shadow_post_n1_div_clk.clkr.hw, + [SHADOW_VCO_CLK_1_CLK] = &dsi1pll_shadow_vco_clk.hw, +}; + +int dsi_pll_clock_register_14nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx, i; + int const ssc_freq_default = 31500; /* default h/w recommended value */ + int const ssc_ppm_default = 5000; /* default h/w recommended value */ + struct dsi_pll_db *pdb; + struct clk_onecell_data *clk_data; + struct clk *clk; + struct regmap *regmap; + int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_14nm); + + if (pll_res->index >= DSI_PLL_NUM) { + pr_err("pll ndx=%d is NOT supported\n", pll_res->index); + return -EINVAL; + } + + ndx = pll_res->index; + pdb = &pll_db[ndx]; + pll_res->priv = pdb; + pdb->pll = pll_res; + ndx++; + ndx %= DSI_PLL_NUM; + pdb->next = &pll_db[ndx]; + + if (pll_res->ssc_en) { + if (!pll_res->ssc_freq) + pll_res->ssc_freq = ssc_freq_default; + if (!pll_res->ssc_ppm) + pll_res->ssc_ppm = ssc_ppm_default; + } + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + /* Set client data to mux, div and vco clocks. */ + if (pll_res->index == DSI_PLL_1) { + regmap = devm_regmap_init(&pdev->dev, &post_n1_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_post_n1_div_clk.clkr.regmap = regmap; + dsi1pll_shadow_post_n1_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &shadow_n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_shadow_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi1pll_byte_clk_mux.clkr.regmap = regmap; + dsi1pll_pixel_clk_mux.clkr.regmap = regmap; + + dsi1pll_vco_clk.priv = pll_res; + dsi1pll_shadow_vco_clk.priv = pll_res; + + pll_res->vco_delay = VCO_DELAY_USEC; + + for (i = BYTE1_MUX_CLK; i <= SHADOW_VCO_CLK_1_CLK; i++) { + pr_debug("register clk: %d index: %d\n", + i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_14nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } else { + regmap = devm_regmap_init(&pdev->dev, &post_n1_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_post_n1_div_clk.clkr.regmap = regmap; + dsi0pll_shadow_post_n1_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &shadow_n2_div_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_shadow_n2_div_clk.clkr.regmap = regmap; + + regmap = devm_regmap_init(&pdev->dev, &dsi_mux_regmap_bus, + pll_res, &dsi_pll_14nm_config); + dsi0pll_byte_clk_mux.clkr.regmap = regmap; + dsi0pll_pixel_clk_mux.clkr.regmap = regmap; + + dsi0pll_vco_clk.priv = pll_res; + dsi0pll_shadow_vco_clk.priv = pll_res; + pll_res->vco_delay = VCO_DELAY_USEC; + + for (i = BYTE0_MUX_CLK; i <= SHADOW_VCO_CLK_0_CLK; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_14nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } + + if (!rc) { + pr_info("Registered DSI PLL ndx=%d clocks successfully\n", + pll_res->index); + return rc; + } + +clk_reg_fail: + return rc; +} diff --git a/techpack/display/pll/dsi_pll_14nm.h b/techpack/display/pll/dsi_pll_14nm.h new file mode 100644 index 0000000000000000000000000000000000000000..abc08f639a570ea0b98606a2678e8c7413b8b8ea --- /dev/null +++ b/techpack/display/pll/dsi_pll_14nm.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef MDSS_DSI_PLL_14NM_H +#define MDSS_DSI_PLL_14NM_H + +#define DSIPHY_CMN_CLK_CFG0 0x0010 +#define DSIPHY_CMN_CLK_CFG1 0x0014 +#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018 + +#define DSIPHY_CMN_PLL_CNTRL 0x0048 +#define DSIPHY_CMN_CTRL_0 0x001c +#define DSIPHY_CMN_CTRL_1 0x0020 + +#define DSIPHY_CMN_LDO_CNTRL 0x004c + +#define DSIPHY_PLL_IE_TRIM 0x0400 +#define DSIPHY_PLL_IP_TRIM 0x0404 + +#define DSIPHY_PLL_IPTAT_TRIM 0x0410 + +#define DSIPHY_PLL_CLKBUFLR_EN 0x041c + +#define DSIPHY_PLL_SYSCLK_EN_RESET 0x0428 +#define DSIPHY_PLL_RESETSM_CNTRL 0x042c +#define DSIPHY_PLL_RESETSM_CNTRL2 0x0430 +#define DSIPHY_PLL_RESETSM_CNTRL3 0x0434 +#define DSIPHY_PLL_RESETSM_CNTRL4 0x0438 +#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c +#define DSIPHY_PLL_KVCO_DIV_REF1 0x0440 +#define DSIPHY_PLL_KVCO_DIV_REF2 0x0444 +#define DSIPHY_PLL_KVCO_COUNT1 0x0448 +#define DSIPHY_PLL_KVCO_COUNT2 0x044c +#define DSIPHY_PLL_VREF_CFG1 0x045c + +#define DSIPHY_PLL_KVCO_CODE 0x0458 + +#define DSIPHY_PLL_VCO_DIV_REF1 0x046c +#define DSIPHY_PLL_VCO_DIV_REF2 0x0470 +#define DSIPHY_PLL_VCO_COUNT1 0x0474 +#define DSIPHY_PLL_VCO_COUNT2 0x0478 +#define DSIPHY_PLL_PLLLOCK_CMP1 0x047c +#define DSIPHY_PLL_PLLLOCK_CMP2 0x0480 +#define DSIPHY_PLL_PLLLOCK_CMP3 0x0484 +#define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488 +#define DSIPHY_PLL_PLL_VCO_TUNE 0x048C +#define DSIPHY_PLL_DEC_START 0x0490 +#define DSIPHY_PLL_SSC_EN_CENTER 0x0494 +#define DSIPHY_PLL_SSC_ADJ_PER1 0x0498 +#define DSIPHY_PLL_SSC_ADJ_PER2 0x049c +#define DSIPHY_PLL_SSC_PER1 0x04a0 +#define DSIPHY_PLL_SSC_PER2 0x04a4 +#define DSIPHY_PLL_SSC_STEP_SIZE1 0x04a8 +#define DSIPHY_PLL_SSC_STEP_SIZE2 0x04ac +#define DSIPHY_PLL_DIV_FRAC_START1 0x04b4 +#define DSIPHY_PLL_DIV_FRAC_START2 0x04b8 +#define DSIPHY_PLL_DIV_FRAC_START3 0x04bc +#define DSIPHY_PLL_TXCLK_EN 0x04c0 +#define DSIPHY_PLL_PLL_CRCTRL 0x04c4 + +#define DSIPHY_PLL_RESET_SM_READY_STATUS 0x04cc + +#define DSIPHY_PLL_PLL_MISC1 0x04e8 + +#define DSIPHY_PLL_CP_SET_CUR 0x04f0 +#define DSIPHY_PLL_PLL_ICPMSET 0x04f4 +#define DSIPHY_PLL_PLL_ICPCSET 0x04f8 +#define DSIPHY_PLL_PLL_ICP_SET 0x04fc +#define DSIPHY_PLL_PLL_LPF1 0x0500 +#define DSIPHY_PLL_PLL_LPF2_POSTDIV 0x0504 +#define DSIPHY_PLL_PLL_BANDGAP 0x0508 + +#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 0x050 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 0x060 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 0x064 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 0x068 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 0x06C +#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 0x070 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 0x074 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 0x078 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 0x07C +#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 0x080 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 0x084 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 0x088 +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR 0x094 +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 0x098 + +struct dsi_pll_input { + u32 fref; /* 19.2 Mhz, reference clk */ + u32 fdata; /* bit clock rate */ + u32 dsiclk_sel; /* 1, reg: 0x0014 */ + u32 n2div; /* 1, reg: 0x0010, bit 4-7 */ + u32 ssc_en; /* 1, reg: 0x0494, bit 0 */ + u32 ldo_en; /* 0, reg: 0x004c, bit 0 */ + + /* fixed */ + u32 refclk_dbler_en; /* 0, reg: 0x04c0, bit 1 */ + u32 vco_measure_time; /* 5, unknown */ + u32 kvco_measure_time; /* 5, unknown */ + u32 bandgap_timer; /* 4, reg: 0x0430, bit 3 - 5 */ + u32 pll_wakeup_timer; /* 5, reg: 0x043c, bit 0 - 2 */ + u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */ + u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */ + u32 ssc_center; /* 0, reg: 0x0494, bit 1 */ + u32 ssc_adj_period; /* 37, reg: 0x498, bit 0 - 9 */ + u32 ssc_spread; /* 0.005 */ + u32 ssc_freq; /* unknown */ + u32 pll_ie_trim; /* 4, reg: 0x0400 */ + u32 pll_ip_trim; /* 4, reg: 0x0404 */ + u32 pll_iptat_trim; /* reg: 0x0410 */ + u32 pll_cpcset_cur; /* 1, reg: 0x04f0, bit 0 - 2 */ + u32 pll_cpmset_cur; /* 1, reg: 0x04f0, bit 3 - 5 */ + + u32 pll_icpmset; /* 4, reg: 0x04fc, bit 3 - 5 */ + u32 pll_icpcset; /* 4, reg: 0x04fc, bit 0 - 2 */ + + u32 pll_icpmset_p; /* 0, reg: 0x04f4, bit 0 - 2 */ + u32 pll_icpmset_m; /* 0, reg: 0x04f4, bit 3 - 5 */ + + u32 pll_icpcset_p; /* 0, reg: 0x04f8, bit 0 - 2 */ + u32 pll_icpcset_m; /* 0, reg: 0x04f8, bit 3 - 5 */ + + u32 pll_lpf_res1; /* 3, reg: 0x0504, bit 0 - 3 */ + u32 pll_lpf_cap1; /* 11, reg: 0x0500, bit 0 - 3 */ + u32 pll_lpf_cap2; /* 1, reg: 0x0500, bit 4 - 7 */ + u32 pll_c3ctrl; /* 2, reg: 0x04c4 */ + u32 pll_r3ctrl; /* 1, reg: 0x04c4 */ +}; + +struct dsi_pll_output { + u32 pll_txclk_en; /* reg: 0x04c0 */ + u32 dec_start; /* reg: 0x0490 */ + u32 div_frac_start; /* reg: 0x04b4, 0x4b8, 0x04bc */ + u32 ssc_period; /* reg: 0x04a0, 0x04a4 */ + u32 ssc_step_size; /* reg: 0x04a8, 0x04ac */ + u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */ + u32 pll_vco_div_ref; /* reg: 0x046c, 0x0470 */ + u32 pll_vco_count; /* reg: 0x0474, 0x0478 */ + u32 pll_kvco_div_ref; /* reg: 0x0440, 0x0444 */ + u32 pll_kvco_count; /* reg: 0x0448, 0x044c */ + u32 pll_misc1; /* reg: 0x04e8 */ + u32 pll_lpf2_postdiv; /* reg: 0x0504 */ + u32 pll_resetsm_cntrl; /* reg: 0x042c */ + u32 pll_resetsm_cntrl2; /* reg: 0x0430 */ + u32 pll_resetsm_cntrl5; /* reg: 0x043c */ + u32 pll_kvco_code; /* reg: 0x0458 */ + + u32 cmn_clk_cfg0; /* reg: 0x0010 */ + u32 cmn_clk_cfg1; /* reg: 0x0014 */ + u32 cmn_ldo_cntrl; /* reg: 0x004c */ + + u32 pll_postdiv; /* vco */ + u32 pll_n1div; /* vco */ + u32 pll_n2div; /* hr_oclk3, pixel */ + u32 fcvo; +}; + +enum { + DSI_PLL_0, + DSI_PLL_1, + DSI_PLL_NUM +}; + +struct dsi_pll_db { + struct dsi_pll_db *next; + struct mdss_pll_resources *pll; + struct dsi_pll_input in; + struct dsi_pll_output out; + int source_setup_done; +}; + +enum { + PLL_OUTPUT_NONE, + PLL_OUTPUT_RIGHT, + PLL_OUTPUT_LEFT, + PLL_OUTPUT_BOTH +}; + +enum { + PLL_SOURCE_FROM_LEFT, + PLL_SOURCE_FROM_RIGHT +}; + +enum { + PLL_UNKNOWN, + PLL_STANDALONE, + PLL_SLAVE, + PLL_MASTER +}; + +int pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +int shadow_pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +long pll_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +unsigned long pll_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate); + +int pll_vco_prepare_14nm(struct clk_hw *hw); +void pll_vco_unprepare_14nm(struct clk_hw *hw); + +int shadow_post_n1_div_set_div(void *context, + unsigned int reg, unsigned int div); +int shadow_post_n1_div_get_div(void *context, + unsigned int reg, unsigned int *div); +int shadow_n2_div_set_div(void *context, unsigned int reg, unsigned int div); +int shadow_n2_div_get_div(void *context, unsigned int reg, unsigned int *div); + +int post_n1_div_set_div(void *context, unsigned int reg, unsigned int div); +int post_n1_div_get_div(void *context, unsigned int reg, unsigned int *div); +int n2_div_set_div(void *context, unsigned int reg, unsigned int div); +int n2_div_get_div(void *context, unsigned int reg, unsigned int *div); +int dsi_pll_enable_seq_14nm(struct mdss_pll_resources *pll); +int dsi_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val); +int dsi_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val); + +#endif /* MDSS_DSI_PLL_14NM_H */ diff --git a/techpack/display/pll/dsi_pll_14nm_util.c b/techpack/display/pll/dsi_pll_14nm_util.c new file mode 100644 index 0000000000000000000000000000000000000000..c089ecdf551c44ed878cd790c0b6b4de7aceac20 --- /dev/null +++ b/techpack/display/pll/dsi_pll_14nm_util.c @@ -0,0 +1,1119 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> + +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dsi_pll_14nm.h" + +#define DSI_PLL_POLL_MAX_READS 15 +#define DSI_PLL_POLL_TIMEOUT_US 1000 +#define MSM8996_DSI_PLL_REVISION_2 2 + +#define VCO_REF_CLK_RATE 19200000 + +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) + +static int mdss_pll_read_stored_trim_codes( + struct mdss_pll_resources *dsi_pll_res, s64 vco_clk_rate) +{ + int i; + int rc = 0; + bool found = false; + + if (!dsi_pll_res->dfps) { + rc = -EINVAL; + goto end_read; + } + + for (i = 0; i < dsi_pll_res->dfps->vco_rate_cnt; i++) { + struct dfps_codes_info *codes_info = + &dsi_pll_res->dfps->codes_dfps[i]; + + pr_debug("valid=%d vco_rate=%d, code %d %d\n", + codes_info->is_valid, codes_info->clk_rate, + codes_info->pll_codes.pll_codes_1, + codes_info->pll_codes.pll_codes_2); + + if (vco_clk_rate != codes_info->clk_rate && + codes_info->is_valid) + continue; + + dsi_pll_res->cache_pll_trim_codes[0] = + codes_info->pll_codes.pll_codes_1; + dsi_pll_res->cache_pll_trim_codes[1] = + codes_info->pll_codes.pll_codes_2; + found = true; + break; + } + + if (!found) { + rc = -EINVAL; + goto end_read; + } + + pr_debug("core_kvco_code=0x%x core_vco_tune=0x%x\n", + dsi_pll_res->cache_pll_trim_codes[0], + dsi_pll_res->cache_pll_trim_codes[1]); + +end_read: + return rc; +} + +int post_n1_div_set_div(void *context, unsigned int reg, unsigned int div) +{ + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + int rc; + u32 n1div = 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* in common clock framework the divider value provided is one less */ + div++; + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + + /* + * vco rate = bit_clk * postdiv * n1div + * vco range from 1300 to 2600 Mhz + * postdiv = 1 + * n1div = 1 to 15 + * n1div = roundup(1300Mhz / bit_clk) + * support bit_clk above 86.67Mhz + */ + + pout->pll_n1div = div; + + n1div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + n1div &= ~0xf; + n1div |= (div & 0xf); + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n1div); + /* ensure n1 divider is programed */ + wmb(); + pr_debug("ndx=%d div=%d postdiv=%x n1div=%x\n", + pll->index, div, pout->pll_postdiv, pout->pll_n1div); + + mdss_pll_resource_enable(pll, false); + + return 0; +} + +int post_n1_div_get_div(void *context, unsigned int reg, unsigned int *div) +{ + int rc; + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* + * postdiv = 1/2/4/8 + * n1div = 1 - 15 + * fot the time being, assume postdiv = 1 + */ + + *div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + *div &= 0xF; + + /* + * initialize n1div here, it will get updated when + * corresponding set_div is called. + */ + pout->pll_n1div = *div; + + /* common clock framework will add one to the divider value sent */ + if (*div == 0) + *div = 1; /* value of zero means div is 2 as per SWI */ + else + *div -= 1; + + pr_debug("post n1 get div = %d\n", *div); + + mdss_pll_resource_enable(pll, false); + + return rc; +} + +int n2_div_set_div(void *context, unsigned int reg, unsigned int div) +{ + int rc; + u32 n2div; + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + struct mdss_pll_resources *slave; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* + * in common clock framework the actual divider value + * provided is one less. + */ + div++; + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + + /* this is for pixel clock */ + n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + n2div &= ~0xf0; /* bits 4 to 7 */ + n2div |= (div << 4); + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n2div); + + /* commit slave if split display is enabled */ + slave = pll->slave; + if (slave) + MDSS_PLL_REG_W(slave->pll_base, DSIPHY_CMN_CLK_CFG0, n2div); + + pout->pll_n2div = div; + + /* set dsiclk_sel=1 so that n2div *= 2 */ + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG1, 1); + pr_debug("ndx=%d div=%d n2div=%x\n", pll->index, div, n2div); + + mdss_pll_resource_enable(pll, false); + + return rc; +} + +int shadow_n2_div_set_div(void *context, unsigned int reg, unsigned int div) +{ + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + u32 data; + + pdb = pll->priv; + pout = &pdb->out; + + /* + * in common clock framework the actual divider value + * provided is one less. + */ + div++; + + pout->pll_n2div = div; + + data = (pout->pll_n1div | (pout->pll_n2div << 4)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL19, + DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_CLK_CFG1, + data, 1); + return 0; +} + +int n2_div_get_div(void *context, unsigned int reg, unsigned int *div) +{ + int rc; + u32 n2div; + struct mdss_pll_resources *pll = context; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + + if (is_gdsc_disabled(pll)) + return 0; + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d resources\n", + pll->index); + return rc; + } + + n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + n2div >>= 4; + n2div &= 0x0f; + /* + * initialize n2div here, it will get updated when + * corresponding set_div is called. + */ + pout->pll_n2div = n2div; + mdss_pll_resource_enable(pll, false); + + *div = n2div; + + /* common clock framework will add one to the divider value sent */ + if (*div == 0) + *div = 1; /* value of zero means div is 2 as per SWI */ + else + *div -= 1; + + pr_debug("ndx=%d div=%d\n", pll->index, *div); + + return rc; +} + +static bool pll_is_pll_locked_14nm(struct mdss_pll_resources *pll) +{ + u32 status; + bool pll_locked; + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((pll->pll_base + + DSIPHY_PLL_RESET_SM_READY_STATUS), + status, + ((status & BIT(5)) > 0), + DSI_PLL_POLL_MAX_READS, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_err("DSI PLL ndx=%d status=%x failed to Lock\n", + pll->index, status); + pll_locked = false; + } else if (readl_poll_timeout_atomic((pll->pll_base + + DSIPHY_PLL_RESET_SM_READY_STATUS), + status, + ((status & BIT(0)) > 0), + DSI_PLL_POLL_MAX_READS, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_err("DSI PLL ndx=%d status=%x PLl not ready\n", + pll->index, status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +static void dsi_pll_start_14nm(void __iomem *pll_base) +{ + pr_debug("start PLL at base=%pK\n", pll_base); + + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VREF_CFG1, 0x10); + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1); +} + +static void dsi_pll_stop_14nm(void __iomem *pll_base) +{ + pr_debug("stop PLL at base=%pK\n", pll_base); + + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0); +} + +int dsi_pll_enable_seq_14nm(struct mdss_pll_resources *pll) +{ + int rc = 0; + + if (!pll) { + pr_err("Invalid PLL resources\n"); + return -EINVAL; + } + + dsi_pll_start_14nm(pll->pll_base); + + /* + * both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL + * enabled at mdss_dsi_14nm_phy_config() + */ + + if (!pll_is_pll_locked_14nm(pll)) { + pr_err("DSI PLL ndx=%d lock failed\n", pll->index); + rc = -EINVAL; + goto init_lock_err; + } + + pr_debug("DSI PLL ndx=%d Lock success\n", pll->index); + +init_lock_err: + return rc; +} + +static int dsi_pll_enable(struct clk_hw *hw) +{ + int i, rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < vco->pll_en_seq_cnt; i++) { + rc = vco->pll_enable_seqs[i](pll); + pr_debug("DSI PLL %s after sequence #%d\n", + rc ? "unlocked" : "locked", i + 1); + if (!rc) + break; + } + + if (rc) + pr_err("ndx=%d DSI PLL failed to lock\n", pll->index); + else + pll->pll_on = true; + + return rc; +} + +static void dsi_pll_disable(struct clk_hw *hw) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + struct mdss_pll_resources *slave; + + if (!pll->pll_on && + mdss_pll_resource_enable(pll, true)) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return; + } + + pll->handoff_resources = false; + slave = pll->slave; + + dsi_pll_stop_14nm(pll->pll_base); + + mdss_pll_resource_enable(pll, false); + + pll->pll_on = false; + + pr_debug("DSI PLL ndx=%d Disabled\n", pll->index); +} + +static void mdss_dsi_pll_14nm_input_init(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + pdb->in.fref = 19200000; /* 19.2 Mhz*/ + pdb->in.fdata = 0; /* bit clock rate */ + pdb->in.dsiclk_sel = 1; /* 1, reg: 0x0014 */ + pdb->in.ssc_en = pll->ssc_en; /* 1, reg: 0x0494, bit 0 */ + pdb->in.ldo_en = 0; /* 0, reg: 0x004c, bit 0 */ + + /* fixed input */ + pdb->in.refclk_dbler_en = 0; /* 0, reg: 0x04c0, bit 1 */ + pdb->in.vco_measure_time = 5; /* 5, unknown */ + pdb->in.kvco_measure_time = 5; /* 5, unknown */ + pdb->in.bandgap_timer = 4; /* 4, reg: 0x0430, bit 3 - 5 */ + pdb->in.pll_wakeup_timer = 5; /* 5, reg: 0x043c, bit 0 - 2 */ + pdb->in.plllock_cnt = 1; /* 1, reg: 0x0488, bit 1 - 2 */ + pdb->in.plllock_rng = 0; /* 0, reg: 0x0488, bit 3 - 4 */ + pdb->in.ssc_center = pll->ssc_center;/* 0, reg: 0x0494, bit 1 */ + pdb->in.ssc_adj_period = 37; /* 37, reg: 0x498, bit 0 - 9 */ + pdb->in.ssc_spread = pll->ssc_ppm / 1000; + pdb->in.ssc_freq = pll->ssc_freq; + + pdb->in.pll_ie_trim = 4; /* 4, reg: 0x0400 */ + pdb->in.pll_ip_trim = 4; /* 4, reg: 0x0404 */ + pdb->in.pll_cpcset_cur = 0; /* 0, reg: 0x04f0, bit 0 - 2 */ + pdb->in.pll_cpmset_cur = 1; /* 1, reg: 0x04f0, bit 3 - 5 */ + pdb->in.pll_icpmset = 7; /* 7, reg: 0x04fc, bit 3 - 5 */ + pdb->in.pll_icpcset = 7; /* 7, reg: 0x04fc, bit 0 - 2 */ + pdb->in.pll_icpmset_p = 0; /* 0, reg: 0x04f4, bit 0 - 2 */ + pdb->in.pll_icpmset_m = 0; /* 0, reg: 0x04f4, bit 3 - 5 */ + pdb->in.pll_icpcset_p = 0; /* 0, reg: 0x04f8, bit 0 - 2 */ + pdb->in.pll_icpcset_m = 0; /* 0, reg: 0x04f8, bit 3 - 5 */ + pdb->in.pll_lpf_res1 = 3; /* 3, reg: 0x0504, bit 0 - 3 */ + pdb->in.pll_lpf_cap1 = 11; /* 11, reg: 0x0500, bit 0 - 3 */ + pdb->in.pll_lpf_cap2 = 1; /* 1, reg: 0x0500, bit 4 - 7 */ + pdb->in.pll_iptat_trim = 7; + pdb->in.pll_c3ctrl = 2; /* 2 */ + pdb->in.pll_r3ctrl = 1; /* 1 */ + pdb->out.pll_postdiv = 1; +} + +static void pll_14nm_ssc_calc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + u32 period, ssc_period; + u32 ref, rem; + s64 step_size; + + pr_debug("%s: vco=%lld ref=%lld\n", __func__, + pll->vco_current_rate, pll->vco_ref_clk_rate); + + ssc_period = pdb->in.ssc_freq / 500; + period = (unsigned long)pll->vco_ref_clk_rate / 1000; + ssc_period = CEIL(period, ssc_period); + ssc_period -= 1; + pdb->out.ssc_period = ssc_period; + + pr_debug("%s: ssc, freq=%d spread=%d period=%d\n", __func__, + pdb->in.ssc_freq, pdb->in.ssc_spread, pdb->out.ssc_period); + + step_size = (u32)pll->vco_current_rate; + ref = pll->vco_ref_clk_rate; + ref /= 1000; + step_size = div_s64(step_size, ref); + step_size <<= 20; + step_size = div_s64(step_size, 1000); + step_size *= pdb->in.ssc_spread; + step_size = div_s64(step_size, 1000); + step_size *= (pdb->in.ssc_adj_period + 1); + + rem = 0; + step_size = div_s64_rem(step_size, ssc_period + 1, &rem); + if (rem) + step_size++; + + pr_debug("%s: step_size=%lld\n", __func__, step_size); + + step_size &= 0x0ffff; /* take lower 16 bits */ + + pdb->out.ssc_step_size = step_size; +} + +static void pll_14nm_dec_frac_calc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + u64 multiplier = BIT(20); + u64 dec_start_multiple, dec_start, pll_comp_val; + s32 duration, div_frac_start; + s64 vco_clk_rate = pll->vco_current_rate; + s64 fref = pll->vco_ref_clk_rate; + + pr_debug("vco_clk_rate=%lld ref_clk_rate=%lld\n", + vco_clk_rate, fref); + + dec_start_multiple = div_s64(vco_clk_rate * multiplier, fref); + div_s64_rem(dec_start_multiple, multiplier, &div_frac_start); + + dec_start = div_s64(dec_start_multiple, multiplier); + + pout->dec_start = (u32)dec_start; + pout->div_frac_start = div_frac_start; + + if (pin->plllock_cnt == 0) + duration = 1024; + else if (pin->plllock_cnt == 1) + duration = 256; + else if (pin->plllock_cnt == 2) + duration = 128; + else + duration = 32; + + pll_comp_val = duration * dec_start_multiple; + pll_comp_val = div_u64(pll_comp_val, multiplier); + do_div(pll_comp_val, 10); + + pout->plllock_cmp = (u32)pll_comp_val; + + pout->pll_txclk_en = 1; + if (pll->revision == MSM8996_DSI_PLL_REVISION_2) + pout->cmn_ldo_cntrl = 0x3c; + else + pout->cmn_ldo_cntrl = 0x1c; +} + +static u32 pll_14nm_kvco_slop(u32 vrate) +{ + u32 slop = 0; + + if (vrate > 1300000000UL && vrate <= 1800000000UL) + slop = 600; + else if (vrate > 1800000000UL && vrate < 2300000000UL) + slop = 400; + else if (vrate > 2300000000UL && vrate < 2600000000UL) + slop = 280; + + return slop; +} + +static void pll_14nm_calc_vco_count(struct dsi_pll_db *pdb, + s64 vco_clk_rate, s64 fref) +{ + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + u64 data; + u32 cnt; + + data = fref * pin->vco_measure_time; + do_div(data, 1000000); + data &= 0x03ff; /* 10 bits */ + data -= 2; + pout->pll_vco_div_ref = data; + + data = (unsigned long)vco_clk_rate / 1000000; /* unit is Mhz */ + data *= pin->vco_measure_time; + do_div(data, 10); + pout->pll_vco_count = data; /* reg: 0x0474, 0x0478 */ + + data = fref * pin->kvco_measure_time; + do_div(data, 1000000); + data &= 0x03ff; /* 10 bits */ + data -= 1; + pout->pll_kvco_div_ref = data; + + cnt = pll_14nm_kvco_slop(vco_clk_rate); + cnt *= 2; + cnt /= 100; + cnt *= pin->kvco_measure_time; + pout->pll_kvco_count = cnt; + + pout->pll_misc1 = 16; + pout->pll_resetsm_cntrl = 48; + pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3; + pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer; + pout->pll_kvco_code = 0; +} + +static void pll_db_commit_ssc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + data = pin->ssc_adj_period; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER1, data); + data = (pin->ssc_adj_period >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER2, data); + + data = pout->ssc_period; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER1, data); + data = (pout->ssc_period >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER2, data); + + data = pout->ssc_step_size; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE1, data); + data = (pout->ssc_step_size >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE2, data); + + data = (pin->ssc_center & 0x01); + data <<= 1; + data |= 0x01; /* enable */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_EN_CENTER, data); + + wmb(); /* make sure register committed */ +} + +static void pll_db_commit_common(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + /* confgiure the non frequency dependent pll registers */ + data = 0; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SYSCLK_EN_RESET, data); + + /* DSIPHY_PLL_CLKBUFLR_EN updated at dsi phy */ + + data = pout->pll_txclk_en; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_TXCLK_EN, data); + + data = pout->pll_resetsm_cntrl; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data); + data = pout->pll_resetsm_cntrl2; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL2, data); + data = pout->pll_resetsm_cntrl5; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL5, data); + + data = pout->pll_vco_div_ref; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF1, data); + data = (pout->pll_vco_div_ref >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF2, data); + + data = pout->pll_kvco_div_ref; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF1, data); + data = (pout->pll_kvco_div_ref >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF2, data); + + data = pout->pll_misc1; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_MISC1, data); + + data = pin->pll_ie_trim; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IE_TRIM, data); + + data = pin->pll_ip_trim; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IP_TRIM, data); + + data = ((pin->pll_cpmset_cur << 3) | pin->pll_cpcset_cur); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CP_SET_CUR, data); + + data = ((pin->pll_icpcset_p << 3) | pin->pll_icpcset_m); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPCSET, data); + + data = ((pin->pll_icpmset_p << 3) | pin->pll_icpcset_m); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPMSET, data); + + data = ((pin->pll_icpmset << 3) | pin->pll_icpcset); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICP_SET, data); + + data = ((pdb->in.pll_lpf_cap2 << 4) | pdb->in.pll_lpf_cap1); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF1, data); + + data = pin->pll_iptat_trim; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IPTAT_TRIM, data); + + data = (pdb->in.pll_c3ctrl | (pdb->in.pll_r3ctrl << 4)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data); +} + +static void pll_db_commit_14nm(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + data = pout->cmn_ldo_cntrl; + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data); + + pll_db_commit_common(pll, pdb); + + /* de assert pll start and apply pll sw reset */ + /* stop pll */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0); + + /* pll sw reset */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0x20); + wmb(); /* make sure register committed */ + udelay(10); + + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0); + wmb(); /* make sure register committed */ + + data = pdb->in.dsiclk_sel; /* set dsiclk_sel = 1 */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG1, data); + + data = 0xff; /* data, clk, pll normal operation */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data); + + /* confgiure the frequency dependent pll registers */ + data = pout->dec_start; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DEC_START, data); + + data = pout->div_frac_start; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START1, data); + data = (pout->div_frac_start >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START2, data); + data = (pout->div_frac_start >> 16); + data &= 0x0f; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START3, data); + + data = pout->plllock_cmp; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP1, data); + data = (pout->plllock_cmp >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP2, data); + data = (pout->plllock_cmp >> 16); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP3, data); + + data = ((pin->plllock_cnt << 1) | (pin->plllock_rng << 3)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP_EN, data); + + data = pout->pll_vco_count; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT1, data); + data = (pout->pll_vco_count >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT2, data); + + data = pout->pll_kvco_count; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT1, data); + data = (pout->pll_kvco_count >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT2, data); + + /* + * tx_band = pll_postdiv + * 0: divided by 1 <== for now + * 1: divided by 2 + * 2: divided by 4 + * 3: divided by 8 + */ + data = (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF2_POSTDIV, data); + + data = (pout->pll_n1div | (pout->pll_n2div << 4)); + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data); + + if (pll->ssc_en) + pll_db_commit_ssc(pll, pdb); + + wmb(); /* make sure register committed */ +} + +/* + * pll_source_finding: + * Both GLBL_TEST_CTRL and CLKBUFLR_EN are configured + * at mdss_dsi_14nm_phy_config() + */ +static int pll_source_finding(struct mdss_pll_resources *pll) +{ + u32 clk_buf_en; + u32 glbl_test_ctrl; + + glbl_test_ctrl = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_CMN_GLBL_TEST_CTRL); + clk_buf_en = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_CLKBUFLR_EN); + + glbl_test_ctrl &= BIT(2); + glbl_test_ctrl >>= 2; + + pr_debug("%s: pll=%d clk_buf_en=%x glbl_test_ctrl=%x\n", + __func__, pll->index, clk_buf_en, glbl_test_ctrl); + + clk_buf_en &= (PLL_OUTPUT_RIGHT | PLL_OUTPUT_LEFT); + + if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) && + (clk_buf_en == PLL_OUTPUT_BOTH)) + return PLL_MASTER; + + if ((glbl_test_ctrl == PLL_SOURCE_FROM_RIGHT) && + (clk_buf_en == PLL_OUTPUT_NONE)) + return PLL_SLAVE; + + if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) && + (clk_buf_en == PLL_OUTPUT_RIGHT)) + return PLL_STANDALONE; + + pr_debug("%s: Error pll setup, clk_buf_en=%x glbl_test_ctrl=%x\n", + __func__, clk_buf_en, glbl_test_ctrl); + + return PLL_UNKNOWN; +} + +static void pll_source_setup(struct mdss_pll_resources *pll) +{ + int status; + struct dsi_pll_db *pdb = (struct dsi_pll_db *)pll->priv; + struct mdss_pll_resources *other; + + if (pdb->source_setup_done) + return; + + pdb->source_setup_done++; + + status = pll_source_finding(pll); + + if (status == PLL_STANDALONE || status == PLL_UNKNOWN) + return; + + other = pdb->next->pll; + if (!other) + return; + + pr_debug("%s: status=%d pll=%d other=%d\n", __func__, + status, pll->index, other->index); + + if (status == PLL_MASTER) + pll->slave = other; + else + other->slave = pll; +} + +unsigned long pll_vco_recalc_rate_14nm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (pll->vco_current_rate) + return (unsigned long)pll->vco_current_rate; + + return 0; +} + +int pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + struct mdss_pll_resources *slave; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; + if (!pdb) { + pr_err("No prov found\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi plla=%d\n", pll->index); + return rc; + } + + pll_source_setup(pll); + + pr_debug("%s: ndx=%d base=%pK rate=%lu slave=%pK\n", __func__, + pll->index, pll->pll_base, rate, pll->slave); + + pll->vco_current_rate = rate; + pll->vco_ref_clk_rate = vco->ref_clk_rate; + + mdss_dsi_pll_14nm_input_init(pll, pdb); + + pll_14nm_dec_frac_calc(pll, pdb); + + if (pll->ssc_en) + pll_14nm_ssc_calc(pll, pdb); + + pll_14nm_calc_vco_count(pdb, pll->vco_current_rate, + pll->vco_ref_clk_rate); + + /* commit slave if split display is enabled */ + slave = pll->slave; + if (slave) + pll_db_commit_14nm(slave, pdb); + + /* commit master itself */ + pll_db_commit_14nm(pll, pdb); + + mdss_pll_resource_enable(pll, false); + + return rc; +} + +static void shadow_pll_dynamic_refresh_14nm(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + struct dsi_pll_output *pout = &pdb->out; + u32 data = 0; + + data = (pout->pll_n1div | (pout->pll_n2div << 4)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL19, + DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_CLK_CFG1, + data, 1); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL20, + DSIPHY_CMN_CTRL_0, DSIPHY_PLL_SYSCLK_EN_RESET, + 0xFF, 0x0); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL21, + DSIPHY_PLL_DEC_START, DSIPHY_PLL_DIV_FRAC_START1, + pout->dec_start, (pout->div_frac_start & 0x0FF)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL22, + DSIPHY_PLL_DIV_FRAC_START2, DSIPHY_PLL_DIV_FRAC_START3, + ((pout->div_frac_start >> 8) & 0x0FF), + ((pout->div_frac_start >> 16) & 0x0F)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL23, + DSIPHY_PLL_PLLLOCK_CMP1, DSIPHY_PLL_PLLLOCK_CMP2, + (pout->plllock_cmp & 0x0FF), + ((pout->plllock_cmp >> 8) & 0x0FF)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL24, + DSIPHY_PLL_PLLLOCK_CMP3, DSIPHY_PLL_PLL_VCO_TUNE, + ((pout->plllock_cmp >> 16) & 0x03), + (pll->cache_pll_trim_codes[1] | BIT(7))); /* VCO tune*/ + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL25, + DSIPHY_PLL_KVCO_CODE, DSIPHY_PLL_RESETSM_CNTRL, + (pll->cache_pll_trim_codes[0] | BIT(5)), 0x38); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL26, + DSIPHY_PLL_PLL_LPF2_POSTDIV, DSIPHY_CMN_PLL_CNTRL, + (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1), 0x01); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL27, + DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL, + 0x01, 0x01); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL28, + DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL, + 0x01, 0x01); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL29, + DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL, + 0x01, 0x01); + MDSS_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, 0x0000001E); + MDSS_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0x001FFE00); + + /* + * Ensure all the dynamic refresh registers are written before + * dynamic refresh to change the fps is triggered + */ + wmb(); +} + +int shadow_pll_vco_set_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + struct dsi_pll_db *pdb; + s64 vco_clk_rate = (s64)rate; + + if (!pll) { + pr_err("PLL data not found\n"); + return -EINVAL; + } + + pdb = pll->priv; + if (!pdb) { + pr_err("No priv data found\n"); + return -EINVAL; + } + + rc = mdss_pll_read_stored_trim_codes(pll, vco_clk_rate); + if (rc) { + pr_err("cannot find pll codes rate=%lld\n", vco_clk_rate); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi plla=%d\n", pll->index); + return rc; + } + + pr_debug("%s: ndx=%d base=%pK rate=%lu\n", __func__, + pll->index, pll->pll_base, rate); + + pll->vco_current_rate = rate; + pll->vco_ref_clk_rate = vco->ref_clk_rate; + + mdss_dsi_pll_14nm_input_init(pll, pdb); + + pll_14nm_dec_frac_calc(pll, pdb); + + pll_14nm_calc_vco_count(pdb, pll->vco_current_rate, + pll->vco_ref_clk_rate); + + shadow_pll_dynamic_refresh_14nm(pll, pdb); + + rc = mdss_pll_resource_enable(pll, false); + if (rc) { + pr_err("Failed to enable mdss dsi plla=%d\n", pll->index); + return rc; + } + + return rc; +} + +long pll_vco_round_rate_14nm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + u64 div; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + + div = vco->min_rate; + do_div(div, rate); + if (div > 15) { + /* rate < 86.67 Mhz */ + pr_err("rate=%lu NOT supportted\n", rate); + return -EINVAL; + } + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + *parent_rate = rrate; + return rrate; +} + +int pll_vco_prepare_14nm(struct clk_hw *hw) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("ndx=%d Failed to enable mdss dsi pll resources\n", + pll->index); + return rc; + } + + if ((pll->vco_cached_rate != 0) + && (pll->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate, + pll->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, pll->index); + mdss_pll_resource_enable(pll, false); + goto error; + } + } + + rc = dsi_pll_enable(hw); + + if (rc) { + mdss_pll_resource_enable(pll, false); + pr_err("ndx=%d failed to enable dsi pll\n", pll->index); + } + +error: + return rc; +} + +void pll_vco_unprepare_14nm(struct clk_hw *hw) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return; + } + + pll->vco_cached_rate = clk_hw_get_rate(hw); + dsi_pll_disable(hw); +} + +int dsi_mux_set_parent_14nm(void *context, unsigned int reg, unsigned int val) +{ + return 0; +} + +int dsi_mux_get_parent_14nm(void *context, unsigned int reg, unsigned int *val) +{ + *val = 0; + return 0; +} diff --git a/techpack/display/pll/dsi_pll_20nm.c b/techpack/display/pll/dsi_pll_20nm.c new file mode 100644 index 0000000000000000000000000000000000000000..f9e22c6abe251713a58010dc5ff39b29ea2b402c --- /dev/null +++ b/techpack/display/pll/dsi_pll_20nm.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/workqueue.h> +#include <linux/clk/msm-clock-generic.h> +#include <dt-bindings/clock/msm-clocks-8994.h> + +#include "pll_drv.h" +#include "dsi_pll.h" + +#define VCO_DELAY_USEC 1 + +static const struct clk_ops bypass_lp_div_mux_clk_ops; +static const struct clk_ops pixel_clk_src_ops; +static const struct clk_ops byte_clk_src_ops; +static const struct clk_ops ndiv_clk_ops; + +static const struct clk_ops shadow_pixel_clk_src_ops; +static const struct clk_ops shadow_byte_clk_src_ops; +static const struct clk_ops clk_ops_gen_mux_dsi; + +static int vco_set_rate_20nm(struct clk *c, unsigned long rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + pr_debug("Cancel pending pll off work\n"); + cancel_work_sync(&dsi_pll_res->pll_off); + rc = pll_20nm_vco_set_rate(vco, rate); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +static int pll1_vco_set_rate_20nm(struct clk *c, unsigned long rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll_res = vco->priv; + + mdss_pll_resource_enable(pll_res, true); + __dsi_pll_disable(pll_res->pll_base); + mdss_pll_resource_enable(pll_res, false); + + pr_debug("Configuring PLL1 registers.\n"); + + return 0; +} + +static int shadow_vco_set_rate_20nm(struct clk *c, unsigned long rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res->resource_enable) { + pr_err("PLL resources disabled. Dynamic fps invalid\n"); + return -EINVAL; + } + + rc = shadow_pll_20nm_vco_set_rate(vco, rate); + + return rc; +} + +/* Op structures */ + +static const struct clk_ops pll1_clk_ops_dsi_vco = { + .set_rate = pll1_vco_set_rate_20nm, +}; + +static const struct clk_ops clk_ops_dsi_vco = { + .set_rate = vco_set_rate_20nm, + .round_rate = pll_20nm_vco_round_rate, + .handoff = pll_20nm_vco_handoff, + .prepare = pll_20nm_vco_prepare, + .unprepare = pll_20nm_vco_unprepare, +}; + +static struct clk_div_ops fixed_hr_oclk2_div_ops = { + .set_div = fixed_hr_oclk2_set_div, + .get_div = fixed_hr_oclk2_get_div, +}; + +static struct clk_div_ops ndiv_ops = { + .set_div = ndiv_set_div, + .get_div = ndiv_get_div, +}; + +static struct clk_div_ops hr_oclk3_div_ops = { + .set_div = hr_oclk3_set_div, + .get_div = hr_oclk3_get_div, +}; + +static struct clk_mux_ops bypass_lp_div_mux_ops = { + .set_mux_sel = set_bypass_lp_div_mux_sel, + .get_mux_sel = get_bypass_lp_div_mux_sel, +}; + +static const struct clk_ops shadow_clk_ops_dsi_vco = { + .set_rate = shadow_vco_set_rate_20nm, + .round_rate = pll_20nm_vco_round_rate, + .handoff = pll_20nm_vco_handoff, +}; + +static struct clk_div_ops shadow_fixed_hr_oclk2_div_ops = { + .set_div = shadow_fixed_hr_oclk2_set_div, + .get_div = fixed_hr_oclk2_get_div, +}; + +static struct clk_div_ops shadow_ndiv_ops = { + .set_div = shadow_ndiv_set_div, + .get_div = ndiv_get_div, +}; + +static struct clk_div_ops shadow_hr_oclk3_div_ops = { + .set_div = shadow_hr_oclk3_set_div, + .get_div = hr_oclk3_get_div, +}; + +static struct clk_mux_ops shadow_bypass_lp_div_mux_ops = { + .set_mux_sel = set_shadow_bypass_lp_div_mux_sel, + .get_mux_sel = get_bypass_lp_div_mux_sel, +}; + +static struct clk_mux_ops mdss_byte_mux_ops = { + .set_mux_sel = set_mdss_byte_mux_sel, + .get_mux_sel = get_mdss_byte_mux_sel, +}; + +static struct clk_mux_ops mdss_pixel_mux_ops = { + .set_mux_sel = set_mdss_pixel_mux_sel, + .get_mux_sel = get_mdss_pixel_mux_sel, +}; + +static struct dsi_pll_vco_clk mdss_dsi1_vco_clk_src = { + .c = { + .dbg_name = "mdss_dsi1_vco_clk_src", + .ops = &pll1_clk_ops_dsi_vco, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(mdss_dsi1_vco_clk_src.c), + }, +}; + +static struct dsi_pll_vco_clk dsi_vco_clk_8994 = { + .ref_clk_rate = 19200000, + .min_rate = 300000000, + .max_rate = 1500000000, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = pll_20nm_vco_enable_seq, + .c = { + .dbg_name = "dsi_vco_clk_8994", + .ops = &clk_ops_dsi_vco, + CLK_INIT(dsi_vco_clk_8994.c), + }, +}; + +static struct dsi_pll_vco_clk shadow_dsi_vco_clk_8994 = { + .ref_clk_rate = 19200000, + .min_rate = 300000000, + .max_rate = 1500000000, + .c = { + .dbg_name = "shadow_dsi_vco_clk_8994", + .ops = &shadow_clk_ops_dsi_vco, + CLK_INIT(shadow_dsi_vco_clk_8994.c), + }, +}; + +static struct div_clk ndiv_clk_8994 = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &ndiv_ops, + .c = { + .parent = &dsi_vco_clk_8994.c, + .dbg_name = "ndiv_clk_8994", + .ops = &ndiv_clk_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(ndiv_clk_8994.c), + }, +}; + +static struct div_clk shadow_ndiv_clk_8994 = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &shadow_ndiv_ops, + .c = { + .parent = &shadow_dsi_vco_clk_8994.c, + .dbg_name = "shadow_ndiv_clk_8994", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(shadow_ndiv_clk_8994.c), + }, +}; + +static struct div_clk indirect_path_div2_clk_8994 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &ndiv_clk_8994.c, + .dbg_name = "indirect_path_div2_clk_8994", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(indirect_path_div2_clk_8994.c), + }, +}; + +static struct div_clk shadow_indirect_path_div2_clk_8994 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &shadow_ndiv_clk_8994.c, + .dbg_name = "shadow_indirect_path_div2_clk_8994", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(shadow_indirect_path_div2_clk_8994.c), + }, +}; + +static struct div_clk hr_oclk3_div_clk_8994 = { + .data = { + .max_div = 255, + .min_div = 1, + }, + .ops = &hr_oclk3_div_ops, + .c = { + .parent = &dsi_vco_clk_8994.c, + .dbg_name = "hr_oclk3_div_clk_8994", + .ops = &pixel_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(hr_oclk3_div_clk_8994.c), + }, +}; + +static struct div_clk shadow_hr_oclk3_div_clk_8994 = { + .data = { + .max_div = 255, + .min_div = 1, + }, + .ops = &shadow_hr_oclk3_div_ops, + .c = { + .parent = &shadow_dsi_vco_clk_8994.c, + .dbg_name = "shadow_hr_oclk3_div_clk_8994", + .ops = &shadow_pixel_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(shadow_hr_oclk3_div_clk_8994.c), + }, +}; + +static struct div_clk pixel_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &hr_oclk3_div_clk_8994.c, + .dbg_name = "pixel_clk_src", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(pixel_clk_src.c), + }, +}; + +static struct div_clk shadow_pixel_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &shadow_hr_oclk3_div_clk_8994.c, + .dbg_name = "shadow_pixel_clk_src", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(shadow_pixel_clk_src.c), + }, +}; + +static struct mux_clk bypass_lp_div_mux_8994 = { + .num_parents = 2, + .parents = (struct clk_src[]){ + {&dsi_vco_clk_8994.c, 0}, + {&indirect_path_div2_clk_8994.c, 1}, + }, + .ops = &bypass_lp_div_mux_ops, + .c = { + .parent = &dsi_vco_clk_8994.c, + .dbg_name = "bypass_lp_div_mux_8994", + .ops = &bypass_lp_div_mux_clk_ops, + CLK_INIT(bypass_lp_div_mux_8994.c), + }, +}; + +static struct mux_clk shadow_bypass_lp_div_mux_8994 = { + .num_parents = 2, + .parents = (struct clk_src[]){ + {&shadow_dsi_vco_clk_8994.c, 0}, + {&shadow_indirect_path_div2_clk_8994.c, 1}, + }, + .ops = &shadow_bypass_lp_div_mux_ops, + .c = { + .parent = &shadow_dsi_vco_clk_8994.c, + .dbg_name = "shadow_bypass_lp_div_mux_8994", + .ops = &clk_ops_gen_mux, + CLK_INIT(shadow_bypass_lp_div_mux_8994.c), + }, +}; + +static struct div_clk fixed_hr_oclk2_div_clk_8994 = { + .ops = &fixed_hr_oclk2_div_ops, + .data = { + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &bypass_lp_div_mux_8994.c, + .dbg_name = "fixed_hr_oclk2_div_clk_8994", + .ops = &byte_clk_src_ops, + CLK_INIT(fixed_hr_oclk2_div_clk_8994.c), + }, +}; + +static struct div_clk shadow_fixed_hr_oclk2_div_clk_8994 = { + .ops = &shadow_fixed_hr_oclk2_div_ops, + .data = { + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &shadow_bypass_lp_div_mux_8994.c, + .dbg_name = "shadow_fixed_hr_oclk2_div_clk_8994", + .ops = &shadow_byte_clk_src_ops, + CLK_INIT(shadow_fixed_hr_oclk2_div_clk_8994.c), + }, +}; + +static struct div_clk byte_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &fixed_hr_oclk2_div_clk_8994.c, + .dbg_name = "byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(byte_clk_src.c), + }, +}; + +static struct div_clk shadow_byte_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &shadow_fixed_hr_oclk2_div_clk_8994.c, + .dbg_name = "shadow_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(shadow_byte_clk_src.c), + }, +}; + +static struct mux_clk mdss_pixel_clk_mux = { + .num_parents = 2, + .parents = (struct clk_src[]) { + {&pixel_clk_src.c, 0}, + {&shadow_pixel_clk_src.c, 1}, + }, + .ops = &mdss_pixel_mux_ops, + .c = { + .parent = &pixel_clk_src.c, + .dbg_name = "mdss_pixel_clk_mux", + .ops = &clk_ops_gen_mux, + CLK_INIT(mdss_pixel_clk_mux.c), + } +}; + +static struct mux_clk mdss_byte_clk_mux = { + .num_parents = 2, + .parents = (struct clk_src[]) { + {&byte_clk_src.c, 0}, + {&shadow_byte_clk_src.c, 1}, + }, + .ops = &mdss_byte_mux_ops, + .c = { + .parent = &byte_clk_src.c, + .dbg_name = "mdss_byte_clk_mux", + .ops = &clk_ops_gen_mux_dsi, + CLK_INIT(mdss_byte_clk_mux.c), + } +}; + +static struct clk_lookup mdss_dsi_pll_1_cc_8994[] = { + CLK_LIST(mdss_dsi1_vco_clk_src), +}; + +static struct clk_lookup mdss_dsi_pllcc_8994[] = { + CLK_LIST(mdss_pixel_clk_mux), + CLK_LIST(mdss_byte_clk_mux), + CLK_LIST(pixel_clk_src), + CLK_LIST(byte_clk_src), + CLK_LIST(fixed_hr_oclk2_div_clk_8994), + CLK_LIST(bypass_lp_div_mux_8994), + CLK_LIST(hr_oclk3_div_clk_8994), + CLK_LIST(indirect_path_div2_clk_8994), + CLK_LIST(ndiv_clk_8994), + CLK_LIST(dsi_vco_clk_8994), + CLK_LIST(shadow_pixel_clk_src), + CLK_LIST(shadow_byte_clk_src), + CLK_LIST(shadow_fixed_hr_oclk2_div_clk_8994), + CLK_LIST(shadow_bypass_lp_div_mux_8994), + CLK_LIST(shadow_hr_oclk3_div_clk_8994), + CLK_LIST(shadow_indirect_path_div2_clk_8994), + CLK_LIST(shadow_ndiv_clk_8994), + CLK_LIST(shadow_dsi_vco_clk_8994), +}; + +static void dsi_pll_off_work(struct work_struct *work) +{ + struct mdss_pll_resources *pll_res; + + if (!work) { + pr_err("pll_resource is invalid\n"); + return; + } + + pr_debug("Starting PLL off Worker%s\n", __func__); + + pll_res = container_of(work, struct + mdss_pll_resources, pll_off); + + mdss_pll_resource_enable(pll_res, true); + __dsi_pll_disable(pll_res->pll_base); + if (pll_res->pll_1_base) + __dsi_pll_disable(pll_res->pll_1_base); + mdss_pll_resource_enable(pll_res, false); +} + +static int dsi_pll_regulator_notifier_call(struct notifier_block *self, + unsigned long event, void *data) +{ + + struct mdss_pll_resources *pll_res; + + if (!self) { + pr_err("pll_resource is invalid\n"); + goto error; + } + + pll_res = container_of(self, struct + mdss_pll_resources, gdsc_cb); + + if (event & REGULATOR_EVENT_ENABLE) { + pr_debug("Regulator ON event. Scheduling pll off worker\n"); + schedule_work(&pll_res->pll_off); + } + + if (event & REGULATOR_EVENT_DISABLE) + pr_debug("Regulator OFF event.\n"); + +error: + return NOTIFY_OK; +} + +int dsi_pll_clock_register_20nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc; + struct dss_vreg *pll_reg; + + /* + * Set client data to mux, div and vco clocks. + * This needs to be done only for PLL0 since, that is the one in + * use. + **/ + if (!pll_res->index) { + byte_clk_src.priv = pll_res; + pixel_clk_src.priv = pll_res; + bypass_lp_div_mux_8994.priv = pll_res; + indirect_path_div2_clk_8994.priv = pll_res; + ndiv_clk_8994.priv = pll_res; + fixed_hr_oclk2_div_clk_8994.priv = pll_res; + hr_oclk3_div_clk_8994.priv = pll_res; + dsi_vco_clk_8994.priv = pll_res; + + shadow_byte_clk_src.priv = pll_res; + shadow_pixel_clk_src.priv = pll_res; + shadow_bypass_lp_div_mux_8994.priv = pll_res; + shadow_indirect_path_div2_clk_8994.priv = pll_res; + shadow_ndiv_clk_8994.priv = pll_res; + shadow_fixed_hr_oclk2_div_clk_8994.priv = pll_res; + shadow_hr_oclk3_div_clk_8994.priv = pll_res; + shadow_dsi_vco_clk_8994.priv = pll_res; + + pll_res->vco_delay = VCO_DELAY_USEC; + + /* Set clock source operations */ + pixel_clk_src_ops = clk_ops_slave_div; + pixel_clk_src_ops.prepare = dsi_pll_div_prepare; + + ndiv_clk_ops = clk_ops_div; + ndiv_clk_ops.prepare = dsi_pll_div_prepare; + + byte_clk_src_ops = clk_ops_div; + byte_clk_src_ops.prepare = dsi_pll_div_prepare; + + bypass_lp_div_mux_clk_ops = clk_ops_gen_mux; + bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare; + + clk_ops_gen_mux_dsi = clk_ops_gen_mux; + clk_ops_gen_mux_dsi.round_rate = parent_round_rate; + clk_ops_gen_mux_dsi.set_rate = parent_set_rate; + + shadow_pixel_clk_src_ops = clk_ops_slave_div; + shadow_pixel_clk_src_ops.prepare = dsi_pll_div_prepare; + + shadow_byte_clk_src_ops = clk_ops_div; + shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare; + } else { + mdss_dsi1_vco_clk_src.priv = pll_res; + } + + if ((pll_res->target_id == MDSS_PLL_TARGET_8994) || + (pll_res->target_id == MDSS_PLL_TARGET_8992)) { + if (pll_res->index) { + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pll_1_cc_8994, + ARRAY_SIZE(mdss_dsi_pll_1_cc_8994)); + if (rc) { + pr_err("Clock register failed\n"); + rc = -EPROBE_DEFER; + } + } else { + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pllcc_8994, + ARRAY_SIZE(mdss_dsi_pllcc_8994)); + if (rc) { + pr_err("Clock register failed\n"); + rc = -EPROBE_DEFER; + } + pll_res->gdsc_cb.notifier_call = + dsi_pll_regulator_notifier_call; + INIT_WORK(&pll_res->pll_off, dsi_pll_off_work); + + pll_reg = mdss_pll_get_mp_by_reg_name(pll_res, "gdsc"); + if (pll_reg) { + pr_debug("Registering for gdsc regulator events\n"); + if (regulator_register_notifier(pll_reg->vreg, + &(pll_res->gdsc_cb))) + pr_err("Regulator notification registration failed!\n"); + } + } + + } else { + pr_err("Invalid target ID\n"); + rc = -EINVAL; + } + + if (!rc) + pr_info("Registered DSI PLL clocks successfully\n"); + + return rc; +} diff --git a/techpack/display/pll/dsi_pll_28hpm.c b/techpack/display/pll/dsi_pll_28hpm.c new file mode 100644 index 0000000000000000000000000000000000000000..ba9052342d2aa44b00da392d66536afd5d26f38d --- /dev/null +++ b/techpack/display/pll/dsi_pll_28hpm.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> +#include <dt-bindings/clock/msm-clocks-8974.h> + +#include "pll_drv.h" +#include "dsi_pll.h" + +#define VCO_DELAY_USEC 1 + +static struct clk_div_ops fixed_2div_ops; +static const struct clk_ops byte_mux_clk_ops; +static const struct clk_ops pixel_clk_src_ops; +static const struct clk_ops byte_clk_src_ops; +static const struct clk_ops analog_postdiv_clk_ops; +static struct lpfr_cfg lpfr_lut_struct[] = { + {479500000, 8}, + {480000000, 11}, + {575500000, 8}, + {576000000, 12}, + {610500000, 8}, + {659500000, 9}, + {671500000, 10}, + {672000000, 14}, + {708500000, 10}, + {750000000, 11}, +}; + +static void dsi_pll_software_reset(struct mdss_pll_resources *dsi_pll_res) +{ + /* + * Add HW recommended delays after toggling the software + * reset bit off and back on. + */ + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01); + udelay(1); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00); + udelay(1); +} + +static int vco_set_rate_hpm(struct clk *c, unsigned long rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + rc = vco_set_rate(vco, rate); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +static int dsi_pll_enable_seq_8974(struct mdss_pll_resources *dsi_pll_res) +{ + int i, rc = 0; + int pll_locked; + + dsi_pll_software_reset(dsi_pll_res); + + /* + * PLL power up sequence. + * Add necessary delays recommeded by hardware. + */ + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01); + udelay(1); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05); + udelay(200); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07); + udelay(500); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f); + udelay(500); + + for (i = 0; i < 2; i++) { + udelay(100); + /* DSI Uniphy lock detect setting */ + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0c); + udelay(100); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d); + + pll_locked = dsi_pll_lock_status(dsi_pll_res); + if (pll_locked) + break; + + dsi_pll_software_reset(dsi_pll_res); + /* + * PLL power up sequence. + * Add necessary delays recommeded by hardware. + */ + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x1); + udelay(1); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5); + udelay(200); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7); + udelay(250); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x5); + udelay(200); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x7); + udelay(500); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0xf); + udelay(500); + + } + + if (!pll_locked) { + pr_err("DSI PLL lock failed\n"); + rc = -EINVAL; + } else { + pr_debug("DSI PLL Lock success\n"); + } + + return rc; +} + +/* Op structures */ + +static const struct clk_ops clk_ops_dsi_vco = { + .set_rate = vco_set_rate_hpm, + .round_rate = vco_round_rate, + .handoff = vco_handoff, + .prepare = vco_prepare, + .unprepare = vco_unprepare, +}; + + +static struct clk_div_ops fixed_4div_ops = { + .set_div = fixed_4div_set_div, + .get_div = fixed_4div_get_div, +}; + +static struct clk_div_ops analog_postdiv_ops = { + .set_div = analog_set_div, + .get_div = analog_get_div, +}; + +static struct clk_div_ops digital_postdiv_ops = { + .set_div = digital_set_div, + .get_div = digital_get_div, +}; + +static struct clk_mux_ops byte_mux_ops = { + .set_mux_sel = set_byte_mux_sel, + .get_mux_sel = get_byte_mux_sel, +}; + +static struct dsi_pll_vco_clk dsi_vco_clk_8974 = { + .ref_clk_rate = 19200000, + .min_rate = 350000000, + .max_rate = 750000000, + .pll_en_seq_cnt = 3, + .pll_enable_seqs[0] = dsi_pll_enable_seq_8974, + .pll_enable_seqs[1] = dsi_pll_enable_seq_8974, + .pll_enable_seqs[2] = dsi_pll_enable_seq_8974, + .lpfr_lut_size = 10, + .lpfr_lut = lpfr_lut_struct, + .c = { + .dbg_name = "dsi_vco_clk_8974", + .ops = &clk_ops_dsi_vco, + CLK_INIT(dsi_vco_clk_8974.c), + }, +}; + +static struct div_clk analog_postdiv_clk_8974 = { + .data = { + .max_div = 255, + .min_div = 1, + }, + .ops = &analog_postdiv_ops, + .c = { + .parent = &dsi_vco_clk_8974.c, + .dbg_name = "analog_postdiv_clk", + .ops = &analog_postdiv_clk_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(analog_postdiv_clk_8974.c), + }, +}; + +static struct div_clk indirect_path_div2_clk_8974 = { + .ops = &fixed_2div_ops, + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &analog_postdiv_clk_8974.c, + .dbg_name = "indirect_path_div2_clk", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(indirect_path_div2_clk_8974.c), + }, +}; + +static struct div_clk pixel_clk_src_8974 = { + .data = { + .max_div = 255, + .min_div = 1, + }, + .ops = &digital_postdiv_ops, + .c = { + .parent = &dsi_vco_clk_8974.c, + .dbg_name = "pixel_clk_src_8974", + .ops = &pixel_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(pixel_clk_src_8974.c), + }, +}; + +static struct mux_clk byte_mux_8974 = { + .num_parents = 2, + .parents = (struct clk_src[]){ + {&dsi_vco_clk_8974.c, 0}, + {&indirect_path_div2_clk_8974.c, 1}, + }, + .ops = &byte_mux_ops, + .c = { + .parent = &dsi_vco_clk_8974.c, + .dbg_name = "byte_mux_8974", + .ops = &byte_mux_clk_ops, + CLK_INIT(byte_mux_8974.c), + }, +}; + +static struct div_clk byte_clk_src_8974 = { + .ops = &fixed_4div_ops, + .data = { + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &byte_mux_8974.c, + .dbg_name = "byte_clk_src_8974", + .ops = &byte_clk_src_ops, + CLK_INIT(byte_clk_src_8974.c), + }, +}; + +static struct clk_lookup mdss_dsi_pllcc_8974[] = { + CLK_LOOKUP_OF("pixel_src", pixel_clk_src_8974, + "fd8c0000.qcom,mmsscc-mdss"), + CLK_LOOKUP_OF("byte_src", byte_clk_src_8974, + "fd8c0000.qcom,mmsscc-mdss"), +}; + +int dsi_pll_clock_register_hpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc; + + /* Set client data to mux, div and vco clocks */ + byte_clk_src_8974.priv = pll_res; + pixel_clk_src_8974.priv = pll_res; + byte_mux_8974.priv = pll_res; + indirect_path_div2_clk_8974.priv = pll_res; + analog_postdiv_clk_8974.priv = pll_res; + dsi_vco_clk_8974.priv = pll_res; + pll_res->vco_delay = VCO_DELAY_USEC; + + /* Set clock source operations */ + pixel_clk_src_ops = clk_ops_slave_div; + pixel_clk_src_ops.prepare = dsi_pll_div_prepare; + + analog_postdiv_clk_ops = clk_ops_div; + analog_postdiv_clk_ops.prepare = dsi_pll_div_prepare; + + byte_clk_src_ops = clk_ops_div; + byte_clk_src_ops.prepare = dsi_pll_div_prepare; + + byte_mux_clk_ops = clk_ops_gen_mux; + byte_mux_clk_ops.prepare = dsi_pll_mux_prepare; + + if (pll_res->target_id == MDSS_PLL_TARGET_8974) { + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pllcc_8974, ARRAY_SIZE(mdss_dsi_pllcc_8974)); + if (rc) { + pr_err("Clock register failed\n"); + rc = -EPROBE_DEFER; + } + } else { + pr_err("Invalid target ID\n"); + rc = -EINVAL; + } + + if (!rc) + pr_info("Registered DSI PLL clocks successfully\n"); + + return rc; +} diff --git a/techpack/display/pll/dsi_pll_28lpm.c b/techpack/display/pll/dsi_pll_28lpm.c new file mode 100644 index 0000000000000000000000000000000000000000..16c2eff92e6be90b79586a1568336f44e23d0415 --- /dev/null +++ b/techpack/display/pll/dsi_pll_28lpm.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <dt-bindings/clock/mdss-28nm-pll-clk.h> + +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dsi_pll_28nm.h" + +#define VCO_DELAY_USEC 1000 + +enum { + DSI_PLL_0, + DSI_PLL_1, + DSI_PLL_MAX +}; + +static struct lpfr_cfg lpfr_lut_struct[] = { + {479500000, 8}, + {480000000, 11}, + {575500000, 8}, + {576000000, 12}, + {610500000, 8}, + {659500000, 9}, + {671500000, 10}, + {672000000, 14}, + {708500000, 10}, + {750000000, 11}, +}; + +static void dsi_pll_sw_reset(struct mdss_pll_resources *rsc) +{ + /* + * DSI PLL software reset. Add HW recommended delays after toggling + * the software reset bit off and back on. + */ + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01); + ndelay(500); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00); +} + +static void dsi_pll_toggle_lock_detect( + struct mdss_pll_resources *rsc) +{ + /* DSI PLL toggle lock detect setting */ + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x04); + ndelay(500); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x05); + udelay(512); +} + +static int dsi_pll_check_lock_status( + struct mdss_pll_resources *rsc) +{ + int rc = 0; + + rc = dsi_pll_lock_status(rsc); + if (rc) + pr_debug("PLL Locked\n"); + else + pr_err("PLL failed to lock\n"); + + return rc; +} + + +static int dsi_pll_enable_seq_gf2(struct mdss_pll_resources *rsc) +{ + int pll_locked = 0; + + dsi_pll_sw_reset(rsc); + + /* + * GF PART 2 PLL power up sequence. + * Add necessary delays recommended by hardware. + */ + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x04); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05); + udelay(3); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f); + udelay(500); + + dsi_pll_toggle_lock_detect(rsc); + + pll_locked = dsi_pll_check_lock_status(rsc); + return pll_locked ? 0 : -EINVAL; +} + +static int dsi_pll_enable_seq_gf1(struct mdss_pll_resources *rsc) +{ + int pll_locked = 0; + + dsi_pll_sw_reset(rsc); + /* + * GF PART 1 PLL power up sequence. + * Add necessary delays recommended by hardware. + */ + + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x14); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05); + udelay(3); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f); + udelay(500); + + dsi_pll_toggle_lock_detect(rsc); + + pll_locked = dsi_pll_check_lock_status(rsc); + return pll_locked ? 0 : -EINVAL; +} + +static int dsi_pll_enable_seq_tsmc(struct mdss_pll_resources *rsc) +{ + int pll_locked = 0; + + dsi_pll_sw_reset(rsc); + /* + * TSMC PLL power up sequence. + * Add necessary delays recommended by hardware. + */ + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1, 0x34); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f); + udelay(500); + + dsi_pll_toggle_lock_detect(rsc); + + pll_locked = dsi_pll_check_lock_status(rsc); + return pll_locked ? 0 : -EINVAL; +} + +static struct regmap_config dsi_pll_28lpm_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xF4, +}; + +static struct regmap_bus analog_postdiv_regmap_bus = { + .reg_write = analog_postdiv_reg_write, + .reg_read = analog_postdiv_reg_read, +}; + +static struct regmap_bus byteclk_src_mux_regmap_bus = { + .reg_write = byteclk_mux_write_sel, + .reg_read = byteclk_mux_read_sel, +}; + +static struct regmap_bus pclk_src_regmap_bus = { + .reg_write = pixel_clk_set_div, + .reg_read = pixel_clk_get_div, +}; + +static const struct clk_ops clk_ops_vco_28lpm = { + .recalc_rate = vco_28nm_recalc_rate, + .set_rate = vco_28nm_set_rate, + .round_rate = vco_28nm_round_rate, + .prepare = vco_28nm_prepare, + .unprepare = vco_28nm_unprepare, +}; + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 350000000UL, + .max_rate = 750000000UL, + .pll_en_seq_cnt = 9, + .pll_enable_seqs[0] = dsi_pll_enable_seq_tsmc, + .pll_enable_seqs[1] = dsi_pll_enable_seq_tsmc, + .pll_enable_seqs[2] = dsi_pll_enable_seq_tsmc, + .pll_enable_seqs[3] = dsi_pll_enable_seq_gf1, + .pll_enable_seqs[4] = dsi_pll_enable_seq_gf1, + .pll_enable_seqs[5] = dsi_pll_enable_seq_gf1, + .pll_enable_seqs[6] = dsi_pll_enable_seq_gf2, + .pll_enable_seqs[7] = dsi_pll_enable_seq_gf2, + .pll_enable_seqs[8] = dsi_pll_enable_seq_gf2, + .lpfr_lut_size = 10, + .lpfr_lut = lpfr_lut_struct, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_vco_clk", + .parent_names = (const char *[]){"cxo"}, + .num_parents = 1, + .ops = &clk_ops_vco_28lpm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 350000000UL, + .max_rate = 750000000UL, + .pll_en_seq_cnt = 9, + .pll_enable_seqs[0] = dsi_pll_enable_seq_tsmc, + .pll_enable_seqs[1] = dsi_pll_enable_seq_tsmc, + .pll_enable_seqs[2] = dsi_pll_enable_seq_tsmc, + .pll_enable_seqs[3] = dsi_pll_enable_seq_gf1, + .pll_enable_seqs[4] = dsi_pll_enable_seq_gf1, + .pll_enable_seqs[5] = dsi_pll_enable_seq_gf1, + .pll_enable_seqs[6] = dsi_pll_enable_seq_gf2, + .pll_enable_seqs[7] = dsi_pll_enable_seq_gf2, + .pll_enable_seqs[8] = dsi_pll_enable_seq_gf2, + .lpfr_lut_size = 10, + .lpfr_lut = lpfr_lut_struct, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_vco_clk", + .parent_names = (const char *[]){"cxo"}, + .num_parents = 1, + .ops = &clk_ops_vco_28lpm, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_regmap_div dsi0pll_analog_postdiv = { + .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_analog_postdiv", + .parent_names = (const char *[]){"dsi0pll_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_analog_postdiv = { + .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, + .shift = 0, + .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_analog_postdiv", + .parent_names = (const char *[]){"dsi1pll_vco_clk"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_indirect_path_src = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_indirect_path_src", + .parent_names = (const char *[]){"dsi0pll_analog_postdiv"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_indirect_path_src = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_indirect_path_src", + .parent_names = (const char *[]){"dsi1pll_analog_postdiv"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_byteclk_src_mux = { + .reg = DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG, + .shift = 1, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byteclk_src_mux", + .parent_names = (const char *[]){ + "dsi0pll_vco_clk", + "dsi0pll_indirect_path_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_byteclk_src_mux = { + .reg = DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG, + .shift = 1, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byteclk_src_mux", + .parent_names = (const char *[]){ + "dsi1pll_vco_clk", + "dsi1pll_indirect_path_src"}, + .num_parents = 2, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_byteclk_src = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byteclk_src", + .parent_names = (const char *[]){ + "dsi0pll_byteclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_byteclk_src = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byteclk_src", + .parent_names = (const char *[]){ + "dsi1pll_byteclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_div dsi0pll_pclk_src = { + .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, + .shift = 0, + .width = 8, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pclk_src", + .parent_names = (const char *[]){"dsi0pll_vco_clk"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_pclk_src = { + .reg = DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, + .shift = 0, + .width = 8, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pclk_src", + .parent_names = (const char *[]){"dsi1pll_vco_clk"}, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_hw *mdss_dsi_pllcc_28lpm[] = { + [VCO_CLK_0] = &dsi0pll_vco_clk.hw, + [ANALOG_POSTDIV_0_CLK] = &dsi0pll_analog_postdiv.clkr.hw, + [INDIRECT_PATH_SRC_0_CLK] = &dsi0pll_indirect_path_src.hw, + [BYTECLK_SRC_MUX_0_CLK] = &dsi0pll_byteclk_src_mux.clkr.hw, + [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw, + [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, + [VCO_CLK_1] = &dsi1pll_vco_clk.hw, + [ANALOG_POSTDIV_1_CLK] = &dsi1pll_analog_postdiv.clkr.hw, + [INDIRECT_PATH_SRC_1_CLK] = &dsi1pll_indirect_path_src.hw, + [BYTECLK_SRC_MUX_1_CLK] = &dsi1pll_byteclk_src_mux.clkr.hw, + [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw, + [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, +}; + +int dsi_pll_clock_register_28lpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx, i; + struct clk *clk; + struct clk_onecell_data *clk_data; + int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_28lpm); + struct regmap *rmap; + + int const ssc_freq_min = 30000; /* min. recommended freq. value */ + int const ssc_freq_max = 33000; /* max. recommended freq. value */ + int const ssc_ppm_max = 5000; /* max. recommended ppm */ + + ndx = pll_res->index; + + if (ndx >= DSI_PLL_MAX) { + pr_err("pll index(%d) NOT supported\n", ndx); + return -EINVAL; + } + + pll_res->vco_delay = VCO_DELAY_USEC; + + if (pll_res->ssc_en) { + if (!pll_res->ssc_freq || (pll_res->ssc_freq < ssc_freq_min) || + (pll_res->ssc_freq > ssc_freq_max)) { + pll_res->ssc_freq = ssc_freq_min; + pr_debug("SSC frequency out of recommended range. Set to default=%d\n", + pll_res->ssc_freq); + } + + if (!pll_res->ssc_ppm || (pll_res->ssc_ppm > ssc_ppm_max)) { + pll_res->ssc_ppm = ssc_ppm_max; + pr_debug("SSC PPM out of recommended range. Set to default=%d\n", + pll_res->ssc_ppm); + } + } + + clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kcalloc(&pdev->dev, num_clks, + sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + /* Establish client data */ + if (ndx == 0) { + rmap = devm_regmap_init(&pdev->dev, &byteclk_src_mux_regmap_bus, + pll_res, &dsi_pll_28lpm_config); + if (IS_ERR(rmap)) { + pr_err("regmap init failed for DSI clock:%d\n", + pll_res->index); + return -EINVAL; + } + dsi0pll_byteclk_src_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &analog_postdiv_regmap_bus, + pll_res, &dsi_pll_28lpm_config); + if (IS_ERR(rmap)) { + pr_err("regmap init failed for DSI clock:%d\n", + pll_res->index); + return -EINVAL; + } + dsi0pll_analog_postdiv.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, + pll_res, &dsi_pll_28lpm_config); + if (IS_ERR(rmap)) { + pr_err("regmap init failed for DSI clock:%d\n", + pll_res->index); + return -EINVAL; + } + dsi0pll_pclk_src.clkr.regmap = rmap; + + dsi0pll_vco_clk.priv = pll_res; + for (i = VCO_CLK_0; i <= PCLK_SRC_0_CLK; i++) { + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_28lpm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI clock:%d\n", + pll_res->index); + rc = -EINVAL; + goto clk_register_fail; + } + clk_data->clks[i] = clk; + + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + + } else { + rmap = devm_regmap_init(&pdev->dev, &byteclk_src_mux_regmap_bus, + pll_res, &dsi_pll_28lpm_config); + if (IS_ERR(rmap)) { + pr_err("regmap init failed for DSI clock:%d\n", + pll_res->index); + return -EINVAL; + } + dsi1pll_byteclk_src_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &analog_postdiv_regmap_bus, + pll_res, &dsi_pll_28lpm_config); + if (IS_ERR(rmap)) { + pr_err("regmap init failed for DSI clock:%d\n", + pll_res->index); + return -EINVAL; + } + dsi1pll_analog_postdiv.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, + pll_res, &dsi_pll_28lpm_config); + if (IS_ERR(rmap)) { + pr_err("regmap init failed for DSI clock:%d\n", + pll_res->index); + return -EINVAL; + } + dsi1pll_pclk_src.clkr.regmap = rmap; + + dsi1pll_vco_clk.priv = pll_res; + for (i = VCO_CLK_1; i <= PCLK_SRC_1_CLK; i++) { + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_28lpm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI clock:%d\n", + pll_res->index); + rc = -EINVAL; + goto clk_register_fail; + } + clk_data->clks[i] = clk; + + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } + if (!rc) { + pr_info("Registered DSI PLL ndx=%d, clocks successfully\n", + ndx); + + return rc; + } + +clk_register_fail: + return rc; +} diff --git a/techpack/display/pll/dsi_pll_28nm.h b/techpack/display/pll/dsi_pll_28nm.h new file mode 100644 index 0000000000000000000000000000000000000000..2c59a6477f6550830a5ece32aa07d3b17be3112c --- /dev/null +++ b/techpack/display/pll/dsi_pll_28nm.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_DSI_PLL_28NM_H +#define __MDSS_DSI_PLL_28NM_H + +#define DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG (0x0020) +#define DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2 (0x0064) +#define DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG (0x0068) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG1 (0x0070) + +#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG (0x0004) +#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG (0x0028) +#define DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG (0x0010) + +struct ssc_params { + s32 kdiv; + s64 triang_inc_7_0; + s64 triang_inc_9_8; + s64 triang_steps; + s64 dc_offset; + s64 freq_seed_7_0; + s64 freq_seed_15_8; +}; + +struct mdss_dsi_vco_calc { + s64 sdm_cfg0; + s64 sdm_cfg1; + s64 sdm_cfg2; + s64 sdm_cfg3; + s64 cal_cfg10; + s64 cal_cfg11; + s64 refclk_cfg; + s64 gen_vco_clk; + u32 lpfr_lut_res; + struct ssc_params ssc; +}; + +unsigned long vco_28nm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate); +int vco_28nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate); +long vco_28nm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate); +int vco_28nm_prepare(struct clk_hw *hw); +void vco_28nm_unprepare(struct clk_hw *hw); + +int analog_postdiv_reg_write(void *context, + unsigned int reg, unsigned int div); +int analog_postdiv_reg_read(void *context, + unsigned int reg, unsigned int *div); +int byteclk_mux_write_sel(void *context, + unsigned int reg, unsigned int val); +int byteclk_mux_read_sel(void *context, + unsigned int reg, unsigned int *val); +int pixel_clk_set_div(void *context, + unsigned int reg, unsigned int div); +int pixel_clk_get_div(void *context, + unsigned int reg, unsigned int *div); + +int dsi_pll_lock_status(struct mdss_pll_resources *rsc); +#endif /* __MDSS_DSI_PLL_28NM_H */ diff --git a/techpack/display/pll/dsi_pll_28nm_util.c b/techpack/display/pll/dsi_pll_28nm_util.c new file mode 100644 index 0000000000000000000000000000000000000000..6ec5a70b83222de4eb20599a2a0e78fb7c635937 --- /dev/null +++ b/techpack/display/pll/dsi_pll_28nm_util.c @@ -0,0 +1,652 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> + +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dsi_pll_28nm.h" + +#define DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG (0x0) +#define DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG (0x0008) +#define DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG (0x000C) +#define DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG (0x0014) +#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG (0x0024) +#define DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG (0x002C) +#define DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG (0x0030) +#define DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG (0x0034) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0 (0x0038) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1 (0x003C) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2 (0x0040) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3 (0x0044) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4 (0x0048) +#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG0 (0x004C) +#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG1 (0x0050) +#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG2 (0x0054) +#define DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG3 (0x0058) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0 (0x006C) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG2 (0x0074) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3 (0x0078) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4 (0x007C) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG5 (0x0080) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6 (0x0084) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7 (0x0088) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8 (0x008C) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9 (0x0090) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10 (0x0094) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11 (0x0098) +#define DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG (0x009C) +#define DSI_PHY_PLL_UNIPHY_PLL_STATUS (0x00C0) + +#define DSI_PLL_POLL_DELAY_US 50 +#define DSI_PLL_POLL_TIMEOUT_US 500 + +int analog_postdiv_reg_read(void *context, unsigned int reg, + unsigned int *div) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *div = MDSS_PLL_REG_R(rsc->pll_base, reg); + + pr_debug("analog_postdiv div = %d\n", *div); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + +int analog_postdiv_reg_write(void *context, unsigned int reg, + unsigned int div) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + pr_debug("analog_postdiv div = %d\n", div); + + MDSS_PLL_REG_W(rsc->pll_base, reg, div); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + +int byteclk_mux_read_sel(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *val = (MDSS_PLL_REG_R(rsc->pll_base, reg) & BIT(1)); + pr_debug("byteclk mux mode = %s\n", *val ? "indirect" : "direct"); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + +int byteclk_mux_write_sel(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + u32 reg_val = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + pr_debug("byteclk mux set to %s mode\n", val ? "indirect" : "direct"); + + reg_val = MDSS_PLL_REG_R(rsc->pll_base, reg); + reg_val &= ~0x02; + reg_val |= val; + + MDSS_PLL_REG_W(rsc->pll_base, reg, reg_val); + + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +int pixel_clk_get_div(void *context, unsigned int reg, + unsigned int *div) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *div = MDSS_PLL_REG_R(rsc->pll_base, reg); + + pr_debug("pclk_src div = %d\n", *div); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + +int pixel_clk_set_div(void *context, unsigned int reg, + unsigned int div) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + pr_debug("pclk_src div = %d\n", div); + + MDSS_PLL_REG_W(rsc->pll_base, reg, div); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + +int dsi_pll_lock_status(struct mdss_pll_resources *rsc) +{ + u32 status; + int pll_locked; + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((rsc->pll_base + + DSI_PHY_PLL_UNIPHY_PLL_STATUS), + status, + ((status & BIT(0)) == 1), + DSI_PLL_POLL_DELAY_US, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_debug("DSI PLL status=%x failed to Lock\n", status); + pll_locked = 0; + } else { + pll_locked = 1; + } + + return pll_locked; +} + +static int pll_28nm_vco_rate_calc(struct dsi_pll_vco_clk *vco, + struct mdss_dsi_vco_calc *vco_calc, unsigned long vco_clk_rate) +{ + s32 rem; + s64 frac_n_mode, ref_doubler_en_b; + s64 ref_clk_to_pll, div_fb, frac_n_value; + int i; + + /* Configure the Loop filter resistance */ + for (i = 0; i < vco->lpfr_lut_size; i++) + if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate) + break; + if (i == vco->lpfr_lut_size) { + pr_err("unable to get loop filter resistance. vco=%ld\n", + vco_clk_rate); + return -EINVAL; + } + vco_calc->lpfr_lut_res = vco->lpfr_lut[i].r; + + div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem); + if (rem) { + vco_calc->refclk_cfg = 0x1; + frac_n_mode = 1; + ref_doubler_en_b = 0; + } else { + vco_calc->refclk_cfg = 0x0; + frac_n_mode = 0; + ref_doubler_en_b = 1; + } + + pr_debug("refclk_cfg = %lld\n", vco_calc->refclk_cfg); + + ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (vco_calc->refclk_cfg)) + + (ref_doubler_en_b * vco->ref_clk_rate)); + + div_fb = div_s64_rem(vco_clk_rate, ref_clk_to_pll, &rem); + frac_n_value = div_s64(((s64)rem * (1 << 16)), ref_clk_to_pll); + vco_calc->gen_vco_clk = vco_clk_rate; + + pr_debug("ref_clk_to_pll = %lld\n", ref_clk_to_pll); + pr_debug("div_fb = %lld\n", div_fb); + pr_debug("frac_n_value = %lld\n", frac_n_value); + + pr_debug("Generated VCO Clock: %lld\n", vco_calc->gen_vco_clk); + rem = 0; + if (frac_n_mode) { + vco_calc->sdm_cfg0 = 0; + vco_calc->sdm_cfg1 = (div_fb & 0x3f) - 1; + vco_calc->sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem); + vco_calc->sdm_cfg2 = rem; + } else { + vco_calc->sdm_cfg0 = (0x1 << 5); + vco_calc->sdm_cfg0 |= (div_fb & 0x3f) - 1; + vco_calc->sdm_cfg1 = 0; + vco_calc->sdm_cfg2 = 0; + vco_calc->sdm_cfg3 = 0; + } + + pr_debug("sdm_cfg0=%lld\n", vco_calc->sdm_cfg0); + pr_debug("sdm_cfg1=%lld\n", vco_calc->sdm_cfg1); + pr_debug("sdm_cfg2=%lld\n", vco_calc->sdm_cfg2); + pr_debug("sdm_cfg3=%lld\n", vco_calc->sdm_cfg3); + + vco_calc->cal_cfg11 = div_s64_rem(vco_calc->gen_vco_clk, + 256 * 1000000, &rem); + vco_calc->cal_cfg10 = rem / 1000000; + pr_debug("cal_cfg10=%lld, cal_cfg11=%lld\n", + vco_calc->cal_cfg10, vco_calc->cal_cfg11); + + return 0; +} + +static void pll_28nm_ssc_param_calc(struct dsi_pll_vco_clk *vco, + struct mdss_dsi_vco_calc *vco_calc) +{ + struct mdss_pll_resources *rsc = vco->priv; + s64 ppm_freq, incr, spread_freq, div_rf, frac_n_value; + s32 rem; + + if (!rsc->ssc_en) { + pr_debug("DSI PLL SSC not enabled\n"); + return; + } + + vco_calc->ssc.kdiv = DIV_ROUND_CLOSEST(vco->ref_clk_rate, + 1000000) - 1; + vco_calc->ssc.triang_steps = DIV_ROUND_CLOSEST(vco->ref_clk_rate, + rsc->ssc_freq * (vco_calc->ssc.kdiv + 1)); + ppm_freq = div_s64(vco_calc->gen_vco_clk * rsc->ssc_ppm, + 1000000); + incr = div64_s64(ppm_freq * 65536, vco->ref_clk_rate * 2 * + vco_calc->ssc.triang_steps); + + vco_calc->ssc.triang_inc_7_0 = incr & 0xff; + vco_calc->ssc.triang_inc_9_8 = (incr >> 8) & 0x3; + + if (!rsc->ssc_center) + spread_freq = vco_calc->gen_vco_clk - ppm_freq; + else + spread_freq = vco_calc->gen_vco_clk - (ppm_freq / 2); + + div_rf = div_s64(spread_freq, 2 * vco->ref_clk_rate); + vco_calc->ssc.dc_offset = (div_rf - 1); + + div_s64_rem(spread_freq, 2 * vco->ref_clk_rate, &rem); + frac_n_value = div_s64((s64)rem * 65536, 2 * vco->ref_clk_rate); + + vco_calc->ssc.freq_seed_7_0 = frac_n_value & 0xff; + vco_calc->ssc.freq_seed_15_8 = (frac_n_value >> 8) & 0xff; +} + +static void pll_28nm_vco_config(struct dsi_pll_vco_clk *vco, + struct mdss_dsi_vco_calc *vco_calc) +{ + struct mdss_pll_resources *rsc = vco->priv; + void __iomem *pll_base = rsc->pll_base; + u32 vco_delay_us = rsc->vco_delay; + bool ssc_en = rsc->ssc_en; + + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG, + vco_calc->lpfr_lut_res); + + /* Loop filter capacitance values : c1 and c2 */ + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15); + + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d); + + if (!ssc_en) { + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1, + (u32)(vco_calc->sdm_cfg1 & 0xff)); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2, + (u32)(vco_calc->sdm_cfg2 & 0xff)); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3, + (u32)(vco_calc->sdm_cfg3 & 0xff)); + } else { + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1, + (u32)vco_calc->ssc.dc_offset); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2, + (u32)vco_calc->ssc.freq_seed_7_0); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3, + (u32)vco_calc->ssc.freq_seed_15_8); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG0, + (u32)vco_calc->ssc.kdiv); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG1, + (u32)vco_calc->ssc.triang_inc_7_0); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG2, + (u32)vco_calc->ssc.triang_inc_9_8); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SSC_CFG3, + (u32)vco_calc->ssc.triang_steps); + } + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00); + + /* Add hardware recommended delay for correct PLL configuration */ + if (vco_delay_us) + udelay(vco_delay_us); + + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG, + (u32)vco_calc->refclk_cfg); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0, + (u32)vco_calc->sdm_cfg0); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10, + (u32)(vco_calc->cal_cfg10 & 0xff)); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11, + (u32)(vco_calc->cal_cfg11 & 0xff)); + MDSS_PLL_REG_W(pll_base, DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG, 0x3); /* Fixed div-4 */ +} + +static int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate) +{ + struct mdss_dsi_vco_calc vco_calc = {0}; + int rc = 0; + + rc = pll_28nm_vco_rate_calc(vco, &vco_calc, rate); + if (rc) { + pr_err("vco rate calculation failed\n"); + return rc; + } + + pll_28nm_ssc_param_calc(vco, &vco_calc); + pll_28nm_vco_config(vco, &vco_calc); + + return 0; +} + +static unsigned long vco_get_rate(struct dsi_pll_vco_clk *vco) +{ + struct mdss_pll_resources *rsc = vco->priv; + int rc; + u32 sdm0, doubler, sdm_byp_div; + u64 vco_rate; + u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; + u64 ref_clk = vco->ref_clk_rate; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* Check to see if the ref clk doubler is enabled */ + doubler = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG) & BIT(0); + ref_clk += (doubler * vco->ref_clk_rate); + + /* see if it is integer mode or sdm mode */ + sdm0 = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0); + if (sdm0 & BIT(6)) { + /* integer mode */ + sdm_byp_div = (MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1; + vco_rate = ref_clk * sdm_byp_div; + } else { + /* sdm mode */ + sdm_dc_off = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF; + pr_debug("sdm_dc_off = %d\n", sdm_dc_off); + sdm2 = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF; + sdm3 = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF; + sdm_freq_seed = (sdm3 << 8) | sdm2; + pr_debug("sdm_freq_seed = %d\n", sdm_freq_seed); + + vco_rate = (ref_clk * (sdm_dc_off + 1)) + + mult_frac(ref_clk, sdm_freq_seed, BIT(16)); + pr_debug("vco rate = %lld\n", vco_rate); + } + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(rsc, false); + + return (unsigned long)vco_rate; +} + +static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) +{ + int i, rc; + struct mdss_pll_resources *rsc = vco->priv; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable dsi pll(%d) resources\n", + rsc->index); + return rc; + } + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < vco->pll_en_seq_cnt; i++) { + rc = vco->pll_enable_seqs[i](rsc); + pr_debug("DSI PLL %s after sequence #%d\n", + rc ? "unlocked" : "locked", i + 1); + if (!rc) + break; + } + + if (rc) { + mdss_pll_resource_enable(rsc, false); + pr_err("DSI PLL failed to lock\n"); + } + rsc->pll_on = true; + + return rc; +} + +static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) +{ + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc->pll_on && + mdss_pll_resource_enable(rsc, true)) { + pr_err("failed to enable dsi pll(%d) resources\n", + rsc->index); + return; + } + + rsc->handoff_resources = false; + + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00); + + mdss_pll_resource_enable(rsc, false); + rsc->pll_on = false; + + pr_debug("DSI PLL Disabled\n"); +} + +int vco_28nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + int rc; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + if (rsc->pll_on) + return 0; + + pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable mdss dsi pll(%d), rc=%d\n", + rsc->index, rc); + return rc; + } + + /* + * DSI PLL software reset. Add HW recommended delays after toggling + * the software reset bit off and back on. + */ + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x01); + udelay(1000); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_TEST_CFG, 0x00); + udelay(1000); + + rc = vco_set_rate(vco, rate); + rsc->vco_current_rate = rate; + + mdss_pll_resource_enable(rsc, false); + + return 0; +} + +long vco_28nm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + *parent_rate = rrate; + + return rrate; +} + +unsigned long vco_28nm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + int rc; + u64 vco_rate = 0; + + if (!rsc) { + pr_err("dsi pll resources not available\n"); + return 0; + } + + if (rsc->vco_current_rate) + return (unsigned long)rsc->vco_current_rate; + + if (is_gdsc_disabled(rsc)) + return 0; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable dsi pll(%d) resources\n", + rsc->index); + return 0; + } + + if (dsi_pll_lock_status(rsc)) { + rsc->handoff_resources = true; + rsc->pll_on = true; + vco_rate = vco_get_rate(vco); + } else { + mdss_pll_resource_enable(rsc, false); + } + + return (unsigned long)vco_rate; +} + +int vco_28nm_prepare(struct clk_hw *hw) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc) { + pr_err("dsi pll resources not available\n"); + return -EINVAL; + } + + if ((rsc->vco_cached_rate != 0) + && (rsc->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = hw->init->ops->set_rate(hw, rsc->vco_cached_rate, + rsc->vco_cached_rate); + if (rc) { + pr_err("pll(%d ) set_rate failed. rc=%d\n", + rsc->index, rc); + goto error; + } + + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, + rsc->cached_postdiv1); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, + rsc->cached_postdiv3); + MDSS_PLL_REG_W(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG, + rsc->cached_vreg_cfg); + } + + rc = dsi_pll_enable(vco); + +error: + return rc; +} + +void vco_28nm_unprepare(struct clk_hw *hw) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc) { + pr_err("dsi pll resources not available\n"); + return; + } + + rsc->cached_postdiv1 = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG); + rsc->cached_postdiv3 = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG); + rsc->cached_vreg_cfg = MDSS_PLL_REG_R(rsc->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG); + + rsc->vco_cached_rate = clk_hw_get_rate(hw); + + dsi_pll_disable(vco); +} diff --git a/techpack/display/pll/dsi_pll_7nm.c b/techpack/display/pll/dsi_pll_7nm.c new file mode 100644 index 0000000000000000000000000000000000000000..581fa3ba13b8f6287f2b63bbd73777a45de923ea --- /dev/null +++ b/techpack/display/pll/dsi_pll_7nm.c @@ -0,0 +1,2835 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include "dsi_pll.h" +#include "pll_drv.h" +#include <dt-bindings/clock/mdss-7nm-pll-clk.h> + +#define VCO_DELAY_USEC 1 + +#define MHZ_250 250000000UL +#define MHZ_500 500000000UL +#define MHZ_1000 1000000000UL +#define MHZ_1100 1100000000UL +#define MHZ_1900 1900000000UL +#define MHZ_3000 3000000000UL + +/* Register Offsets from PLL base address */ +#define PLL_ANALOG_CONTROLS_ONE 0x0000 +#define PLL_ANALOG_CONTROLS_TWO 0x0004 +#define PLL_INT_LOOP_SETTINGS 0x0008 +#define PLL_INT_LOOP_SETTINGS_TWO 0x000C +#define PLL_ANALOG_CONTROLS_THREE 0x0010 +#define PLL_ANALOG_CONTROLS_FOUR 0x0014 +#define PLL_ANALOG_CONTROLS_FIVE 0x0018 +#define PLL_INT_LOOP_CONTROLS 0x001C +#define PLL_DSM_DIVIDER 0x0020 +#define PLL_FEEDBACK_DIVIDER 0x0024 +#define PLL_SYSTEM_MUXES 0x0028 +#define PLL_FREQ_UPDATE_CONTROL_OVERRIDES 0x002C +#define PLL_CMODE 0x0030 +#define PLL_PSM_CTRL 0x0034 +#define PLL_RSM_CTRL 0x0038 +#define PLL_VCO_TUNE_MAP 0x003C +#define PLL_PLL_CNTRL 0x0040 +#define PLL_CALIBRATION_SETTINGS 0x0044 +#define PLL_BAND_SEL_CAL_TIMER_LOW 0x0048 +#define PLL_BAND_SEL_CAL_TIMER_HIGH 0x004C +#define PLL_BAND_SEL_CAL_SETTINGS 0x0050 +#define PLL_BAND_SEL_MIN 0x0054 +#define PLL_BAND_SEL_MAX 0x0058 +#define PLL_BAND_SEL_PFILT 0x005C +#define PLL_BAND_SEL_IFILT 0x0060 +#define PLL_BAND_SEL_CAL_SETTINGS_TWO 0x0064 +#define PLL_BAND_SEL_CAL_SETTINGS_THREE 0x0068 +#define PLL_BAND_SEL_CAL_SETTINGS_FOUR 0x006C +#define PLL_BAND_SEL_ICODE_HIGH 0x0070 +#define PLL_BAND_SEL_ICODE_LOW 0x0074 +#define PLL_FREQ_DETECT_SETTINGS_ONE 0x0078 +#define PLL_FREQ_DETECT_THRESH 0x007C +#define PLL_FREQ_DET_REFCLK_HIGH 0x0080 +#define PLL_FREQ_DET_REFCLK_LOW 0x0084 +#define PLL_FREQ_DET_PLLCLK_HIGH 0x0088 +#define PLL_FREQ_DET_PLLCLK_LOW 0x008C +#define PLL_PFILT 0x0090 +#define PLL_IFILT 0x0094 +#define PLL_PLL_GAIN 0x0098 +#define PLL_ICODE_LOW 0x009C +#define PLL_ICODE_HIGH 0x00A0 +#define PLL_LOCKDET 0x00A4 +#define PLL_OUTDIV 0x00A8 +#define PLL_FASTLOCK_CONTROL 0x00AC +#define PLL_PASS_OUT_OVERRIDE_ONE 0x00B0 +#define PLL_PASS_OUT_OVERRIDE_TWO 0x00B4 +#define PLL_CORE_OVERRIDE 0x00B8 +#define PLL_CORE_INPUT_OVERRIDE 0x00BC +#define PLL_RATE_CHANGE 0x00C0 +#define PLL_PLL_DIGITAL_TIMERS 0x00C4 +#define PLL_PLL_DIGITAL_TIMERS_TWO 0x00C8 +#define PLL_DECIMAL_DIV_START 0x00CC +#define PLL_FRAC_DIV_START_LOW 0x00D0 +#define PLL_FRAC_DIV_START_MID 0x00D4 +#define PLL_FRAC_DIV_START_HIGH 0x00D8 +#define PLL_DEC_FRAC_MUXES 0x00DC +#define PLL_DECIMAL_DIV_START_1 0x00E0 +#define PLL_FRAC_DIV_START_LOW_1 0x00E4 +#define PLL_FRAC_DIV_START_MID_1 0x00E8 +#define PLL_FRAC_DIV_START_HIGH_1 0x00EC +#define PLL_DECIMAL_DIV_START_2 0x00F0 +#define PLL_FRAC_DIV_START_LOW_2 0x00F4 +#define PLL_FRAC_DIV_START_MID_2 0x00F8 +#define PLL_FRAC_DIV_START_HIGH_2 0x00FC +#define PLL_MASH_CONTROL 0x0100 +#define PLL_SSC_STEPSIZE_LOW 0x0104 +#define PLL_SSC_STEPSIZE_HIGH 0x0108 +#define PLL_SSC_DIV_PER_LOW 0x010C +#define PLL_SSC_DIV_PER_HIGH 0x0110 +#define PLL_SSC_ADJPER_LOW 0x0114 +#define PLL_SSC_ADJPER_HIGH 0x0118 +#define PLL_SSC_MUX_CONTROL 0x011C +#define PLL_SSC_STEPSIZE_LOW_1 0x0120 +#define PLL_SSC_STEPSIZE_HIGH_1 0x0124 +#define PLL_SSC_DIV_PER_LOW_1 0x0128 +#define PLL_SSC_DIV_PER_HIGH_1 0x012C +#define PLL_SSC_ADJPER_LOW_1 0x0130 +#define PLL_SSC_ADJPER_HIGH_1 0x0134 +#define PLL_SSC_STEPSIZE_LOW_2 0x0138 +#define PLL_SSC_STEPSIZE_HIGH_2 0x013C +#define PLL_SSC_DIV_PER_LOW_2 0x0140 +#define PLL_SSC_DIV_PER_HIGH_2 0x0144 +#define PLL_SSC_ADJPER_LOW_2 0x0148 +#define PLL_SSC_ADJPER_HIGH_2 0x014C +#define PLL_SSC_CONTROL 0x0150 +#define PLL_PLL_OUTDIV_RATE 0x0154 +#define PLL_PLL_LOCKDET_RATE_1 0x0158 +#define PLL_PLL_LOCKDET_RATE_2 0x015C +#define PLL_PLL_PROP_GAIN_RATE_1 0x0160 +#define PLL_PLL_PROP_GAIN_RATE_2 0x0164 +#define PLL_PLL_BAND_SEL_RATE_1 0x0168 +#define PLL_PLL_BAND_SEL_RATE_2 0x016C +#define PLL_PLL_INT_GAIN_IFILT_BAND_1 0x0170 +#define PLL_PLL_INT_GAIN_IFILT_BAND_2 0x0174 +#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 0x0178 +#define PLL_PLL_FL_INT_GAIN_PFILT_BAND_2 0x017C +#define PLL_PLL_FASTLOCK_EN_BAND 0x0180 +#define PLL_FREQ_TUNE_ACCUM_INIT_MID 0x0184 +#define PLL_FREQ_TUNE_ACCUM_INIT_HIGH 0x0188 +#define PLL_FREQ_TUNE_ACCUM_INIT_MUX 0x018C +#define PLL_PLL_LOCK_OVERRIDE 0x0190 +#define PLL_PLL_LOCK_DELAY 0x0194 +#define PLL_PLL_LOCK_MIN_DELAY 0x0198 +#define PLL_CLOCK_INVERTERS 0x019C +#define PLL_SPARE_AND_JPC_OVERRIDES 0x01A0 +#define PLL_BIAS_CONTROL_1 0x01A4 +#define PLL_BIAS_CONTROL_2 0x01A8 +#define PLL_ALOG_OBSV_BUS_CTRL_1 0x01AC +#define PLL_COMMON_STATUS_ONE 0x01B0 +#define PLL_COMMON_STATUS_TWO 0x01B4 +#define PLL_BAND_SEL_CAL 0x01B8 +#define PLL_ICODE_ACCUM_STATUS_LOW 0x01BC +#define PLL_ICODE_ACCUM_STATUS_HIGH 0x01C0 +#define PLL_FD_OUT_LOW 0x01C4 +#define PLL_FD_OUT_HIGH 0x01C8 +#define PLL_ALOG_OBSV_BUS_STATUS_1 0x01CC +#define PLL_PLL_MISC_CONFIG 0x01D0 +#define PLL_FLL_CONFIG 0x01D4 +#define PLL_FLL_FREQ_ACQ_TIME 0x01D8 +#define PLL_FLL_CODE0 0x01DC +#define PLL_FLL_CODE1 0x01E0 +#define PLL_FLL_GAIN0 0x01E4 +#define PLL_FLL_GAIN1 0x01E8 +#define PLL_SW_RESET 0x01EC +#define PLL_FAST_PWRUP 0x01F0 +#define PLL_LOCKTIME0 0x01F4 +#define PLL_LOCKTIME1 0x01F8 +#define PLL_DEBUG_BUS_SEL 0x01FC +#define PLL_DEBUG_BUS0 0x0200 +#define PLL_DEBUG_BUS1 0x0204 +#define PLL_DEBUG_BUS2 0x0208 +#define PLL_DEBUG_BUS3 0x020C +#define PLL_ANALOG_FLL_CONTROL_OVERRIDES 0x0210 +#define PLL_VCO_CONFIG 0x0214 +#define PLL_VCO_CAL_CODE1_MODE0_STATUS 0x0218 +#define PLL_VCO_CAL_CODE1_MODE1_STATUS 0x021C +#define PLL_RESET_SM_STATUS 0x0220 +#define PLL_TDC_OFFSET 0x0224 +#define PLL_PS3_PWRDOWN_CONTROLS 0x0228 +#define PLL_PS4_PWRDOWN_CONTROLS 0x022C +#define PLL_PLL_RST_CONTROLS 0x0230 +#define PLL_GEAR_BAND_SELECT_CONTROLS 0x0234 +#define PLL_PSM_CLK_CONTROLS 0x0238 +#define PLL_SYSTEM_MUXES_2 0x023C +#define PLL_VCO_CONFIG_1 0x0240 +#define PLL_VCO_CONFIG_2 0x0244 +#define PLL_CLOCK_INVERTERS_1 0x0248 +#define PLL_CLOCK_INVERTERS_2 0x024C +#define PLL_CMODE_1 0x0250 +#define PLL_CMODE_2 0x0254 +#define PLL_ANALOG_CONTROLS_FIVE_1 0x0258 +#define PLL_ANALOG_CONTROLS_FIVE_2 0x025C +#define PLL_PERF_OPTIMIZE 0x0260 + +/* Register Offsets from PHY base address */ +#define PHY_CMN_CLK_CFG0 0x010 +#define PHY_CMN_CLK_CFG1 0x014 +#define PHY_CMN_GLBL_CTRL 0x018 +#define PHY_CMN_RBUF_CTRL 0x01C +#define PHY_CMN_CTRL_0 0x024 +#define PHY_CMN_CTRL_2 0x02C +#define PHY_CMN_CTRL_3 0x030 +#define PHY_CMN_PLL_CNTRL 0x03C +#define PHY_CMN_GLBL_DIGTOP_SPARE4 0x128 + +/* Bit definition of SSC control registers */ +#define SSC_CENTER BIT(0) +#define SSC_EN BIT(1) +#define SSC_FREQ_UPDATE BIT(2) +#define SSC_FREQ_UPDATE_MUX BIT(3) +#define SSC_UPDATE_SSC BIT(4) +#define SSC_UPDATE_SSC_MUX BIT(5) +#define SSC_START BIT(6) +#define SSC_START_MUX BIT(7) + +/* Dynamic Refresh Control Registers */ +#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x014) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x018) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x01C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x020) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x024) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x028) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x02C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x030) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x034) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x038) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x03C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x040) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x044) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x048) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x04C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x050) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x054) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x058) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x05C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x060) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x064) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x068) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x06C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x070) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x074) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x078) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x07C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x080) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x084) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x088) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x08C) +#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x090) +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x094) +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x098) + +#define DSI_PHY_TO_PLL_OFFSET (0x500) +enum { + DSI_PLL_0, + DSI_PLL_1, + DSI_PLL_MAX +}; + +struct dsi_pll_regs { + u32 pll_prop_gain_rate; + u32 pll_lockdet_rate; + u32 decimal_div_start; + u32 frac_div_start_low; + u32 frac_div_start_mid; + u32 frac_div_start_high; + u32 pll_clock_inverters; + u32 ssc_stepsize_low; + u32 ssc_stepsize_high; + u32 ssc_div_per_low; + u32 ssc_div_per_high; + u32 ssc_adjper_low; + u32 ssc_adjper_high; + u32 ssc_control; +}; + +struct dsi_pll_config { + u32 ref_freq; + bool div_override; + u32 output_div; + bool ignore_frac; + bool disable_prescaler; + bool enable_ssc; + bool ssc_center; + u32 dec_bits; + u32 frac_bits; + u32 lock_timer; + u32 ssc_freq; + u32 ssc_offset; + u32 ssc_adj_per; + u32 thresh_cycles; + u32 refclk_cycles; +}; + +struct dsi_pll_7nm { + struct mdss_pll_resources *rsc; + struct dsi_pll_config pll_configuration; + struct dsi_pll_regs reg_setup; + bool cphy_enabled; +}; + +static inline bool dsi_pll_7nm_is_hw_revision_v1( + struct mdss_pll_resources *rsc) +{ + return (rsc->pll_interface_type == MDSS_DSI_PLL_7NM) ? true : false; +} + +static inline bool dsi_pll_7nm_is_hw_revision_v2( + struct mdss_pll_resources *rsc) +{ + return (rsc->pll_interface_type == MDSS_DSI_PLL_7NM_V2) ? true : false; +} + +static inline bool dsi_pll_7nm_is_hw_revision_v4_1( + struct mdss_pll_resources *rsc) +{ + return (rsc->pll_interface_type == MDSS_DSI_PLL_7NM_V4_1) ? + true : false; +} + +static inline int pll_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + u32 data; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + /* + * DSI PHY/PLL should be both powered on when reading PLL + * registers. Since PHY power has been enabled in DSI PHY + * driver, only PLL power is needed to enable here. + */ + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5)); + ndelay(250); + + *val = MDSS_PLL_REG_R(rsc->pll_base, reg); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data); + + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int pll_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + MDSS_PLL_REG_W(rsc->pll_base, reg, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + *val = MDSS_PLL_REG_R(rsc->phy_base, reg); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + MDSS_PLL_REG_W(rsc->phy_base, reg, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int phy_reg_update_bits_sub(struct mdss_pll_resources *rsc, + unsigned int reg, unsigned int mask, unsigned int val) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg); + reg_val &= ~mask; + reg_val |= (val & mask); + MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val); + + return 0; +} + +static inline int phy_reg_update_bits(void *context, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + rc = phy_reg_update_bits_sub(rsc, reg, mask, val); + if (!rc && rsc->slave) + rc = phy_reg_update_bits_sub(rsc->slave, reg, mask, val); + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static inline int pclk_mux_read_sel(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + /* Return cached cfg1 as its updated with cached cfg1 in pll_enable */ + if (!rsc->handoff_resources) { + *val = (rsc->cached_cfg1) & 0x3; + return rc; + } + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + else + *val = (MDSS_PLL_REG_R(rsc->phy_base, reg) & 0x3); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + + +static inline int pclk_mux_write_sel_sub(struct mdss_pll_resources *rsc, + unsigned int reg, unsigned int val) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, reg); + reg_val &= ~0x03; + reg_val |= val; + + MDSS_PLL_REG_W(rsc->phy_base, reg, reg_val); + + return 0; +} + +static inline int pclk_mux_write_sel(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + struct dsi_pll_7nm *pll = rsc->priv; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + if (pll->cphy_enabled) + WARN_ON("PHY is in CPHY mode. PLL config is incorrect\n"); + rc = pclk_mux_write_sel_sub(rsc, reg, val); + if (!rc && rsc->slave) + rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); + + (void)mdss_pll_resource_enable(rsc, false); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + rsc->cached_cfg1 = val; + + return rc; +} + +static inline int cphy_pclk_mux_read_sel(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + else + *val = (MDSS_PLL_REG_R(rsc->phy_base, reg) & 0x3); + + (void)mdss_pll_resource_enable(rsc, false); + return rc; +} + +static inline int cphy_pclk_mux_write_sel(void *context, unsigned int reg, + unsigned int val) +{ + int rc = 0; + struct mdss_pll_resources *rsc = context; + struct dsi_pll_7nm *pll = rsc->priv; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + if (!pll->cphy_enabled) + WARN_ON("PHY-> not in CPHY mode. PLL config is incorrect\n"); + /* For Cphy configuration, val should always be 3 */ + val = 3; + + rc = pclk_mux_write_sel_sub(rsc, reg, val); + if (!rc && rsc->slave) + rc = pclk_mux_write_sel_sub(rsc->slave, reg, val); + + (void)mdss_pll_resource_enable(rsc, false); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + rsc->cached_cfg1 = val; + + return rc; +} + +static struct mdss_pll_resources *pll_rsc_db[DSI_PLL_MAX]; +static struct dsi_pll_7nm plls[DSI_PLL_MAX]; + +static void dsi_pll_config_slave(struct mdss_pll_resources *rsc) +{ + u32 reg; + struct mdss_pll_resources *orsc = pll_rsc_db[DSI_PLL_1]; + + if (!rsc) + return; + + /* Only DSI PLL0 can act as a master */ + if (rsc->index != DSI_PLL_0) + return; + + /* default configuration: source is either internal or ref clock */ + rsc->slave = NULL; + + if (!orsc) { + pr_warn("slave PLL unavilable, assuming standalone config\n"); + return; + } + + /* check to see if the source of DSI1 PLL bitclk is set to external */ + reg = MDSS_PLL_REG_R(orsc->phy_base, PHY_CMN_CLK_CFG1); + reg &= (BIT(2) | BIT(3)); + if (reg == 0x04) + rsc->slave = pll_rsc_db[DSI_PLL_1]; /* external source */ + + pr_debug("Slave PLL %s\n", rsc->slave ? "configured" : "absent"); +} + +static void dsi_pll_setup_config(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + + config->ref_freq = 19200000; + config->output_div = 1; + config->dec_bits = 8; + config->frac_bits = 18; + config->lock_timer = 64; + config->ssc_freq = 31500; + config->ssc_offset = 4800; + config->ssc_adj_per = 2; + config->thresh_cycles = 32; + config->refclk_cycles = 256; + + config->div_override = false; + config->ignore_frac = false; + config->disable_prescaler = false; + config->enable_ssc = rsc->ssc_en; + config->ssc_center = rsc->ssc_center; + + if (config->enable_ssc) { + if (rsc->ssc_freq) + config->ssc_freq = rsc->ssc_freq; + if (rsc->ssc_ppm) + config->ssc_offset = rsc->ssc_ppm; + } + + dsi_pll_config_slave(rsc); +} + +static void dsi_pll_calc_dec_frac(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u64 fref = rsc->vco_ref_clk_rate; + u64 pll_freq; + u64 divider; + u64 dec, dec_multiple; + u32 frac; + u64 multiplier; + + pll_freq = rsc->vco_current_rate; + + if (config->disable_prescaler) + divider = fref; + else + divider = fref * 2; + + multiplier = 1 << config->frac_bits; + dec_multiple = div_u64(pll_freq * multiplier, divider); + div_u64_rem(dec_multiple, multiplier, &frac); + + dec = div_u64(dec_multiple, multiplier); + + switch (rsc->pll_interface_type) { + case MDSS_DSI_PLL_7NM: + regs->pll_clock_inverters = 0x0; + break; + case MDSS_DSI_PLL_7NM_V2: + regs->pll_clock_inverters = 0x28; + break; + case MDSS_DSI_PLL_7NM_V4_1: + default: + if (pll_freq <= 1000000000ULL) + regs->pll_clock_inverters = 0xA0; + else if (pll_freq <= 2500000000ULL) + regs->pll_clock_inverters = 0x20; + else if (pll_freq <= 3020000000ULL) + regs->pll_clock_inverters = 0x00; + else + regs->pll_clock_inverters = 0x40; + break; + } + + regs->pll_lockdet_rate = config->lock_timer; + regs->decimal_div_start = dec; + regs->frac_div_start_low = (frac & 0xff); + regs->frac_div_start_mid = (frac & 0xff00) >> 8; + regs->frac_div_start_high = (frac & 0x30000) >> 16; + regs->pll_prop_gain_rate = 10; +} + +static void dsi_pll_calc_ssc(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + struct dsi_pll_config *config = &pll->pll_configuration; + struct dsi_pll_regs *regs = &pll->reg_setup; + u32 ssc_per; + u32 ssc_mod; + u64 ssc_step_size; + u64 frac; + + if (!config->enable_ssc) { + pr_debug("SSC not enabled\n"); + return; + } + + ssc_per = DIV_ROUND_CLOSEST(config->ref_freq, config->ssc_freq) / 2 - 1; + ssc_mod = (ssc_per + 1) % (config->ssc_adj_per + 1); + ssc_per -= ssc_mod; + + frac = regs->frac_div_start_low | + (regs->frac_div_start_mid << 8) | + (regs->frac_div_start_high << 16); + ssc_step_size = regs->decimal_div_start; + ssc_step_size *= (1 << config->frac_bits); + ssc_step_size += frac; + ssc_step_size *= config->ssc_offset; + ssc_step_size *= (config->ssc_adj_per + 1); + ssc_step_size = div_u64(ssc_step_size, (ssc_per + 1)); + ssc_step_size = DIV_ROUND_CLOSEST_ULL(ssc_step_size, 1000000); + + regs->ssc_div_per_low = ssc_per & 0xFF; + regs->ssc_div_per_high = (ssc_per & 0xFF00) >> 8; + regs->ssc_stepsize_low = (u32)(ssc_step_size & 0xFF); + regs->ssc_stepsize_high = (u32)((ssc_step_size & 0xFF00) >> 8); + regs->ssc_adjper_low = config->ssc_adj_per & 0xFF; + regs->ssc_adjper_high = (config->ssc_adj_per & 0xFF00) >> 8; + + regs->ssc_control = config->ssc_center ? SSC_CENTER : 0; + + pr_debug("SCC: Dec:%d, frac:%llu, frac_bits:%d\n", + regs->decimal_div_start, frac, config->frac_bits); + pr_debug("SSC: div_per:0x%X, stepsize:0x%X, adjper:0x%X\n", + ssc_per, (u32)ssc_step_size, config->ssc_adj_per); +} + +static void dsi_pll_ssc_commit(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + struct dsi_pll_regs *regs = &pll->reg_setup; + + if (pll->pll_configuration.enable_ssc) { + pr_debug("SSC is enabled\n"); + + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1, + regs->ssc_stepsize_low); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1, + regs->ssc_stepsize_high); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1, + regs->ssc_div_per_low); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1, + regs->ssc_div_per_high); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW_1, + regs->ssc_adjper_low); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH_1, + regs->ssc_adjper_high); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, + SSC_EN | regs->ssc_control); + } +} + +static void dsi_pll_config_hzindep_reg(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + u64 vco_rate = rsc->vco_current_rate; + + switch (rsc->pll_interface_type) { + case MDSS_DSI_PLL_7NM: + case MDSS_DSI_PLL_7NM_V2: + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FIVE_1, 0x01); + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x00); + break; + case MDSS_DSI_PLL_7NM_V4_1: + default: + if (vco_rate < 3100000000ULL) + MDSS_PLL_REG_W(pll_base, + PLL_ANALOG_CONTROLS_FIVE_1, 0x01); + else + MDSS_PLL_REG_W(pll_base, + PLL_ANALOG_CONTROLS_FIVE_1, 0x03); + + if (vco_rate < 1520000000ULL) + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x08); + else if (vco_rate < 2990000000ULL) + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x01); + else + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x00); + + break; + } + + if (dsi_pll_7nm_is_hw_revision_v1(rsc)) + MDSS_PLL_REG_W(pll_base, PLL_GEAR_BAND_SELECT_CONTROLS, 0x21); + + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FIVE, 0x01); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_TWO, 0x03); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_THREE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_DSM_DIVIDER, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_FEEDBACK_DIVIDER, 0x4e); + MDSS_PLL_REG_W(pll_base, PLL_CALIBRATION_SETTINGS, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0xba); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0c); + MDSS_PLL_REG_W(pll_base, PLL_OUTDIV, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_CORE_OVERRIDE, 0x00); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x08); + MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x0a); + MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SEL_RATE_1, 0xc0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x84); + MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x82); + MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x4c); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x80); + MDSS_PLL_REG_W(pll_base, PLL_PFILT, 0x29); + MDSS_PLL_REG_W(pll_base, PLL_PFILT, 0x2f); + MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x2a); + + switch (rsc->pll_interface_type) { + case MDSS_DSI_PLL_7NM: + MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x30); + break; + case MDSS_DSI_PLL_7NM_V2: + MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x22); + break; + case MDSS_DSI_PLL_7NM_V4_1: + default: + MDSS_PLL_REG_W(pll_base, PLL_IFILT, 0x3F); + break; + } + + if (dsi_pll_7nm_is_hw_revision_v4_1(rsc)) { + MDSS_PLL_REG_W(pll_base, PLL_PERF_OPTIMIZE, 0x22); + if (rsc->slave) + MDSS_PLL_REG_W(rsc->slave->pll_base, PLL_PERF_OPTIMIZE, 0x22); + } +} + +static void dsi_pll_init_val(struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_ONE, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS, 0x0000003F); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_SETTINGS_TWO, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FOUR, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_INT_LOOP_CONTROLS, 0x00000080); + MDSS_PLL_REG_W(pll_base, PLL_SYSTEM_MUXES, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_UPDATE_CONTROL_OVERRIDES, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_CMODE, 0x00000010); + MDSS_PLL_REG_W(pll_base, PLL_PSM_CTRL, 0x00000020); + MDSS_PLL_REG_W(pll_base, PLL_RSM_CTRL, 0x00000010); + MDSS_PLL_REG_W(pll_base, PLL_VCO_TUNE_MAP, 0x00000002); + MDSS_PLL_REG_W(pll_base, PLL_PLL_CNTRL, 0x0000001C); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_TIMER_HIGH, 0x00000002); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS, 0x00000020); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MIN, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_MAX, 0x000000FF); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_PFILT, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_IFILT, 0x0000000A); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_TWO, 0x00000025); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_THREE, 0x000000BA); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL_SETTINGS_FOUR, 0x0000004F); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_HIGH, 0x0000000A); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_ICODE_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_SETTINGS_ONE, 0x0000000C); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DETECT_THRESH, 0x00000020); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DET_REFCLK_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DET_REFCLK_LOW, 0x000000FF); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DET_PLLCLK_HIGH, 0x00000010); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_DET_PLLCLK_LOW, 0x00000046); + MDSS_PLL_REG_W(pll_base, PLL_PLL_GAIN, 0x00000054); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_LOCKDET, 0x00000040); + MDSS_PLL_REG_W(pll_base, PLL_FASTLOCK_CONTROL, 0x00000004); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_ONE, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PASS_OUT_OVERRIDE_TWO, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_CORE_OVERRIDE, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x00000010); + MDSS_PLL_REG_W(pll_base, PLL_RATE_CHANGE, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS, 0x00000008); + MDSS_PLL_REG_W(pll_base, PLL_PLL_DIGITAL_TIMERS_TWO, 0x00000008); + MDSS_PLL_REG_W(pll_base, PLL_DEC_FRAC_MUXES, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_MASH_CONTROL, 0x00000003); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_MUX_CONTROL, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_LOW_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_STEPSIZE_HIGH_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_LOW_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_DIV_PER_HIGH_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_LOW_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_ADJPER_HIGH_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SSC_CONTROL, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PLL_OUTDIV_RATE, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x00000040); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_2, 0x00000040); + MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_1, 0x0000000C); + MDSS_PLL_REG_W(pll_base, PLL_PLL_PROP_GAIN_RATE_2, 0x0000000A); + MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SEL_RATE_1, 0x000000C0); + MDSS_PLL_REG_W(pll_base, PLL_PLL_BAND_SEL_RATE_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_1, 0x00000054); + MDSS_PLL_REG_W(pll_base, PLL_PLL_INT_GAIN_IFILT_BAND_2, 0x00000054); + MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_1, 0x0000004C); + MDSS_PLL_REG_W(pll_base, PLL_PLL_FL_INT_GAIN_PFILT_BAND_2, 0x0000004C); + MDSS_PLL_REG_W(pll_base, PLL_PLL_FASTLOCK_EN_BAND, 0x00000003); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MID, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FREQ_TUNE_ACCUM_INIT_MUX, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_OVERRIDE, 0x00000080); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x00000006); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_MIN_DELAY, 0x00000019); + MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SPARE_AND_JPC_OVERRIDES, 0x00000000); + + if (dsi_pll_7nm_is_hw_revision_v1(rsc)) + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x00000066); + else + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_1, 0x00000040); + + MDSS_PLL_REG_W(pll_base, PLL_BIAS_CONTROL_2, 0x00000020); + MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_CTRL_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_COMMON_STATUS_ONE, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_COMMON_STATUS_TWO, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_BAND_SEL_CAL, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_ACCUM_STATUS_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_ICODE_ACCUM_STATUS_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FD_OUT_LOW, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FD_OUT_HIGH, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_ALOG_OBSV_BUS_STATUS_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PLL_MISC_CONFIG, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FLL_CONFIG, 0x00000002); + MDSS_PLL_REG_W(pll_base, PLL_FLL_FREQ_ACQ_TIME, 0x00000011); + MDSS_PLL_REG_W(pll_base, PLL_FLL_CODE0, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FLL_CODE1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FLL_GAIN0, 0x00000080); + MDSS_PLL_REG_W(pll_base, PLL_FLL_GAIN1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_SW_RESET, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_FAST_PWRUP, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_LOCKTIME0, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_LOCKTIME1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_DEBUG_BUS_SEL, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_DEBUG_BUS0, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_DEBUG_BUS1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_DEBUG_BUS2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_DEBUG_BUS3, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_FLL_CONTROL_OVERRIDES, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_VCO_CAL_CODE1_MODE0_STATUS, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_VCO_CAL_CODE1_MODE1_STATUS, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_RESET_SM_STATUS, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_TDC_OFFSET, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_PS3_PWRDOWN_CONTROLS, 0x0000001D); + MDSS_PLL_REG_W(pll_base, PLL_PS4_PWRDOWN_CONTROLS, 0x0000001C); + MDSS_PLL_REG_W(pll_base, PLL_PLL_RST_CONTROLS, 0x000000FF); + MDSS_PLL_REG_W(pll_base, PLL_GEAR_BAND_SELECT_CONTROLS, 0x00000022); + MDSS_PLL_REG_W(pll_base, PLL_PSM_CLK_CONTROLS, 0x00000009); + MDSS_PLL_REG_W(pll_base, PLL_SYSTEM_MUXES_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG_1, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_VCO_CONFIG_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS_1, 0x00000040); + MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS_2, 0x00000000); + MDSS_PLL_REG_W(pll_base, PLL_CMODE_1, 0x00000010); + MDSS_PLL_REG_W(pll_base, PLL_CMODE_2, 0x00000010); + MDSS_PLL_REG_W(pll_base, PLL_ANALOG_CONTROLS_FIVE_2, 0x00000003); + +} + +static void dsi_pll_detect_phy_mode(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_GLBL_CTRL); + pll->cphy_enabled = (reg_val & BIT(6)) ? true : false; +} + +static void dsi_pll_commit(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + void __iomem *pll_base = rsc->pll_base; + struct dsi_pll_regs *reg = &pll->reg_setup; + + MDSS_PLL_REG_W(pll_base, PLL_CORE_INPUT_OVERRIDE, 0x12); + MDSS_PLL_REG_W(pll_base, PLL_DECIMAL_DIV_START_1, + reg->decimal_div_start); + MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_LOW_1, + reg->frac_div_start_low); + MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_MID_1, + reg->frac_div_start_mid); + MDSS_PLL_REG_W(pll_base, PLL_FRAC_DIV_START_HIGH_1, + reg->frac_div_start_high); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCKDET_RATE_1, 0x40); + MDSS_PLL_REG_W(pll_base, PLL_PLL_LOCK_DELAY, 0x06); + MDSS_PLL_REG_W(pll_base, PLL_CMODE_1, + pll->cphy_enabled ? 0x00 : 0x10); + MDSS_PLL_REG_W(pll_base, PLL_CLOCK_INVERTERS_1, + reg->pll_clock_inverters); +} + +static int vco_7nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_7nm *pll; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + if (rsc->pll_on) + return 0; + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + + rsc->vco_current_rate = rate; + rsc->vco_ref_clk_rate = vco->ref_clk_rate; + rsc->dfps_trigger = false; + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable mdss dsi pll(%d), rc=%d\n", + rsc->index, rc); + return rc; + } + + dsi_pll_init_val(rsc); + + dsi_pll_detect_phy_mode(pll, rsc); + + dsi_pll_setup_config(pll, rsc); + + dsi_pll_calc_dec_frac(pll, rsc); + + dsi_pll_calc_ssc(pll, rsc); + + dsi_pll_commit(pll, rsc); + + dsi_pll_config_hzindep_reg(pll, rsc); + + dsi_pll_ssc_commit(pll, rsc); + + /* flush, ensure all register writes are done*/ + wmb(); + + mdss_pll_resource_enable(rsc, false); + + return 0; +} + +static int dsi_pll_read_stored_trim_codes(struct mdss_pll_resources *pll_res, + unsigned long vco_clk_rate) +{ + int i; + bool found = false; + + if (!pll_res->dfps) + return -EINVAL; + + for (i = 0; i < pll_res->dfps->vco_rate_cnt; i++) { + struct dfps_codes_info *codes_info = + &pll_res->dfps->codes_dfps[i]; + + pr_debug("valid=%d vco_rate=%d, code %d %d %d\n", + codes_info->is_valid, codes_info->clk_rate, + codes_info->pll_codes.pll_codes_1, + codes_info->pll_codes.pll_codes_2, + codes_info->pll_codes.pll_codes_3); + + if (vco_clk_rate != codes_info->clk_rate && + codes_info->is_valid) + continue; + + pll_res->cache_pll_trim_codes[0] = + codes_info->pll_codes.pll_codes_1; + pll_res->cache_pll_trim_codes[1] = + codes_info->pll_codes.pll_codes_2; + pll_res->cache_pll_trim_codes[2] = + codes_info->pll_codes.pll_codes_3; + found = true; + break; + } + + if (!found) + return -EINVAL; + + pr_debug("trim_code_0=0x%x trim_code_1=0x%x trim_code_2=0x%x\n", + pll_res->cache_pll_trim_codes[0], + pll_res->cache_pll_trim_codes[1], + pll_res->cache_pll_trim_codes[2]); + + return 0; +} + +static void shadow_dsi_pll_dynamic_refresh_7nm(struct dsi_pll_7nm *pll, + struct mdss_pll_resources *rsc) +{ + u32 data; + u32 offset = DSI_PHY_TO_PLL_OFFSET; + u32 upper_addr = 0; + u32 upper_addr2 = 0; + struct dsi_pll_regs *reg = &pll->reg_setup; + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + data &= ~BIT(5); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL0, + PHY_CMN_CLK_CFG1, PHY_CMN_PLL_CNTRL, data, 0); + upper_addr |= (upper_8_bit(PHY_CMN_CLK_CFG1) << 0); + upper_addr |= (upper_8_bit(PHY_CMN_PLL_CNTRL) << 1); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL1, + PHY_CMN_RBUF_CTRL, + (PLL_CORE_INPUT_OVERRIDE + offset), + 0, 0x12); + upper_addr |= (upper_8_bit(PHY_CMN_RBUF_CTRL) << 2); + upper_addr |= (upper_8_bit(PLL_CORE_INPUT_OVERRIDE + offset) << 3); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL2, + (PLL_DECIMAL_DIV_START_1 + offset), + (PLL_FRAC_DIV_START_LOW_1 + offset), + reg->decimal_div_start, reg->frac_div_start_low); + upper_addr |= (upper_8_bit(PLL_DECIMAL_DIV_START_1 + offset) << 4); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_LOW_1 + offset) << 5); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL3, + (PLL_FRAC_DIV_START_MID_1 + offset), + (PLL_FRAC_DIV_START_HIGH_1 + offset), + reg->frac_div_start_mid, reg->frac_div_start_high); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_MID_1 + offset) << 6); + upper_addr |= (upper_8_bit(PLL_FRAC_DIV_START_HIGH_1 + offset) << 7); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL4, + (PLL_SYSTEM_MUXES + offset), + (PLL_PLL_LOCKDET_RATE_1 + offset), + 0xc0, 0x10); + upper_addr |= (upper_8_bit(PLL_SYSTEM_MUXES + offset) << 8); + upper_addr |= (upper_8_bit(PLL_PLL_LOCKDET_RATE_1 + offset) << 9); + + data = MDSS_PLL_REG_R(rsc->pll_base, PLL_PLL_OUTDIV_RATE) & 0x03; + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL5, + (PLL_PLL_OUTDIV_RATE + offset), + (PLL_PLL_LOCK_DELAY + offset), + data, 0x06); + + upper_addr |= (upper_8_bit(PLL_PLL_OUTDIV_RATE + offset) << 10); + upper_addr |= (upper_8_bit(PLL_PLL_LOCK_DELAY + offset) << 11); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL6, + (PLL_CMODE_1 + offset), + (PLL_CLOCK_INVERTERS_1 + offset), + pll->cphy_enabled ? 0x00 : 0x10, + reg->pll_clock_inverters); + upper_addr |= + (upper_8_bit(PLL_CMODE_1 + offset) << 12); + upper_addr |= (upper_8_bit(PLL_CLOCK_INVERTERS_1 + offset) << 13); + + data = MDSS_PLL_REG_R(rsc->pll_base, PLL_VCO_CONFIG_1); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL7, + (PLL_ANALOG_CONTROLS_FIVE_1 + offset), + (PLL_VCO_CONFIG_1 + offset), + 0x01, data); + upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_FIVE_1 + offset) << 14); + upper_addr |= (upper_8_bit(PLL_VCO_CONFIG_1 + offset) << 15); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL8, + (PLL_ANALOG_CONTROLS_FIVE + offset), + (PLL_ANALOG_CONTROLS_TWO + offset), 0x01, 0x03); + upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_FIVE + offset) << 16); + upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_TWO + offset) << 17); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL9, + (PLL_ANALOG_CONTROLS_THREE + offset), + (PLL_DSM_DIVIDER + offset), + rsc->cache_pll_trim_codes[2], 0x00); + upper_addr |= (upper_8_bit(PLL_ANALOG_CONTROLS_THREE + offset) << 18); + upper_addr |= (upper_8_bit(PLL_DSM_DIVIDER + offset) << 19); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL10, + (PLL_FEEDBACK_DIVIDER + offset), + (PLL_CALIBRATION_SETTINGS + offset), 0x4E, 0x40); + upper_addr |= (upper_8_bit(PLL_FEEDBACK_DIVIDER + offset) << 20); + upper_addr |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 21); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL11, + (PLL_BAND_SEL_CAL_SETTINGS_THREE + offset), + (PLL_FREQ_DETECT_SETTINGS_ONE + offset), 0xBA, 0x0C); + upper_addr |= (upper_8_bit(PLL_BAND_SEL_CAL_SETTINGS_THREE + offset) + << 22); + upper_addr |= (upper_8_bit(PLL_FREQ_DETECT_SETTINGS_ONE + offset) + << 23); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL12, + (PLL_OUTDIV + offset), + (PLL_CORE_OVERRIDE + offset), 0, 0); + upper_addr |= (upper_8_bit(PLL_OUTDIV + offset) << 24); + upper_addr |= (upper_8_bit(PLL_CORE_OVERRIDE + offset) << 25); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL13, + (PLL_PLL_DIGITAL_TIMERS_TWO + offset), + (PLL_PLL_PROP_GAIN_RATE_1 + offset), + 0x08, reg->pll_prop_gain_rate); + upper_addr |= (upper_8_bit(PLL_PLL_DIGITAL_TIMERS_TWO + offset) << 26); + upper_addr |= (upper_8_bit(PLL_PLL_PROP_GAIN_RATE_1 + offset) << 27); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL14, + (PLL_PLL_BAND_SEL_RATE_1 + offset), + (PLL_PLL_INT_GAIN_IFILT_BAND_1 + offset), + 0xC0, 0x82); + upper_addr |= (upper_8_bit(PLL_PLL_BAND_SEL_RATE_1 + offset) << 28); + upper_addr |= (upper_8_bit(PLL_PLL_INT_GAIN_IFILT_BAND_1 + offset) + << 29); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL15, + (PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 + offset), + (PLL_PLL_LOCK_OVERRIDE + offset), + 0x4c, 0x80); + upper_addr |= (upper_8_bit(PLL_PLL_FL_INT_GAIN_PFILT_BAND_1 + offset) + << 30); + upper_addr |= (upper_8_bit(PLL_PLL_LOCK_OVERRIDE + offset) << 31); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL16, + (PLL_PFILT + offset), + (PLL_IFILT + offset), + 0x29, 0x3f); + upper_addr2 |= (upper_8_bit(PLL_PFILT + offset) << 0); + upper_addr2 |= (upper_8_bit(PLL_IFILT + offset) << 1); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL17, + (PLL_SYSTEM_MUXES + offset), + (PLL_CALIBRATION_SETTINGS + offset), + 0xe0, 0x44); + upper_addr2 |= (upper_8_bit(PLL_BAND_SEL_CAL + offset) << 2); + upper_addr2 |= (upper_8_bit(PLL_CALIBRATION_SETTINGS + offset) << 3); + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL18, + PHY_CMN_CTRL_2, PHY_CMN_CLK_CFG0, 0x40, data); + + if (rsc->slave) + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL10, + PHY_CMN_CLK_CFG0, PHY_CMN_CTRL_0, + data, 0x7f); + + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL27, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL28, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL29, + PHY_CMN_PLL_CNTRL, PHY_CMN_PLL_CNTRL, 0x01, 0x01); + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1) | BIT(5); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL30, + PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, data, 0x01); + MDSS_DYN_PLL_REG_W(rsc->dyn_pll_base, DSI_DYNAMIC_REFRESH_PLL_CTRL31, + PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, data, data); + + if (rsc->slave) { + data = MDSS_PLL_REG_R(rsc->slave->phy_base, PHY_CMN_CLK_CFG1) | + BIT(5); + + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL30, + PHY_CMN_CLK_CFG1, PHY_CMN_RBUF_CTRL, + data, 0x01); + MDSS_DYN_PLL_REG_W(rsc->slave->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL31, + PHY_CMN_CLK_CFG1, PHY_CMN_CLK_CFG1, + data, data); + } + + MDSS_PLL_REG_W(rsc->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, upper_addr); + MDSS_PLL_REG_W(rsc->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, upper_addr2); + wmb(); /* commit register writes */ +} + +static int shadow_vco_7nm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int rc; + struct dsi_pll_7nm *pll; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + rc = dsi_pll_read_stored_trim_codes(rsc, rate); + if (rc) { + pr_err("cannot find pll codes rate=%ld\n", rate); + return -EINVAL; + } + pr_debug("ndx=%d, rate=%lu\n", rsc->index, rate); + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("failed to enable mdss dsi pll(%d), rc=%d\n", + rsc->index, rc); + return rc; + } + + rsc->vco_current_rate = rate; + rsc->vco_ref_clk_rate = vco->ref_clk_rate; + + dsi_pll_setup_config(pll, rsc); + + dsi_pll_calc_dec_frac(pll, rsc); + + /* program dynamic refresh control registers */ + shadow_dsi_pll_dynamic_refresh_7nm(pll, rsc); + + /* update cached vco rate */ + rsc->vco_cached_rate = rate; + rsc->dfps_trigger = true; + + mdss_pll_resource_enable(rsc, false); + + return 0; +} + +static int dsi_pll_7nm_lock_status(struct mdss_pll_resources *pll) +{ + int rc; + u32 status; + u32 const delay_us = 100; + u32 const timeout_us = 5000; + + rc = readl_poll_timeout_atomic(pll->pll_base + PLL_COMMON_STATUS_ONE, + status, + ((status & BIT(0)) > 0), + delay_us, + timeout_us); + if (rc && !pll->handoff_resources) + pr_err("DSI PLL(%d) lock failed, status=0x%08x\n", + pll->index, status); + + return rc; +} + +static void dsi_pll_disable_pll_bias(struct mdss_pll_resources *rsc) +{ + u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + + MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data & ~BIT(5)); + ndelay(250); +} + +static void dsi_pll_enable_pll_bias(struct mdss_pll_resources *rsc) +{ + u32 data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5)); + MDSS_PLL_REG_W(rsc->pll_base, PLL_SYSTEM_MUXES, 0xc0); + ndelay(250); +} + +static void dsi_pll_disable_global_clk(struct mdss_pll_resources *rsc) +{ + u32 data; + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data & ~BIT(5))); +} + +static void dsi_pll_enable_global_clk(struct mdss_pll_resources *rsc) +{ + u32 data; + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_3, 0x04); + + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG1); + + /* Turn on clk_en_sel bit prior to resync toggle fifo */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG1, (data | BIT(5) | + BIT(4))); +} + +static void dsi_pll_phy_dig_reset(struct mdss_pll_resources *rsc) +{ + /* + * Reset the PHY digital domain. This would be needed when + * coming out of a CX or analog rail power collapse while + * ensuring that the pads maintain LP00 or LP11 state + */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_GLBL_DIGTOP_SPARE4, BIT(0)); + wmb(); /* Ensure that the reset is asserted */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_GLBL_DIGTOP_SPARE4, 0x0); + wmb(); /* Ensure that the reset is deasserted */ +} + +static int dsi_pll_enable(struct dsi_pll_vco_clk *vco) +{ + int rc; + struct mdss_pll_resources *rsc = vco->priv; + struct dsi_pll_7nm *pll = rsc->priv; + + dsi_pll_enable_pll_bias(rsc); + if (rsc->slave) + dsi_pll_enable_pll_bias(rsc->slave); + + /* For Cphy configuration, pclk_mux is always set to 3 divider */ + if (pll->cphy_enabled) { + rsc->cached_cfg1 |= 0x3; + if (rsc->slave) + rsc->slave->cached_cfg1 |= 0x3; + } + + phy_reg_update_bits_sub(rsc, PHY_CMN_CLK_CFG1, 0x03, rsc->cached_cfg1); + if (rsc->slave) + phy_reg_update_bits_sub(rsc->slave, PHY_CMN_CLK_CFG1, + 0x03, rsc->slave->cached_cfg1); + wmb(); /* ensure dsiclk_sel is always programmed before pll start */ + + /* Start PLL */ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0x01); + + /* + * ensure all PLL configurations are written prior to checking + * for PLL lock. + */ + wmb(); + + /* Check for PLL lock */ + rc = dsi_pll_7nm_lock_status(rsc); + if (rc) { + pr_err("PLL(%d) lock failed\n", rsc->index); + goto error; + } + + rsc->pll_on = true; + + /* + * assert power on reset for PHY digital in case the PLL is + * enabled after CX of analog domain power collapse. This needs + * to be done before enabling the global clk. + */ + dsi_pll_phy_dig_reset(rsc); + if (rsc->slave) + dsi_pll_phy_dig_reset(rsc->slave); + + dsi_pll_enable_global_clk(rsc); + if (rsc->slave) + dsi_pll_enable_global_clk(rsc->slave); + +error: + return rc; +} + +static void dsi_pll_disable_sub(struct mdss_pll_resources *rsc) +{ + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_RBUF_CTRL, 0); + dsi_pll_disable_pll_bias(rsc); +} + +static void dsi_pll_disable(struct dsi_pll_vco_clk *vco) +{ + struct mdss_pll_resources *rsc = vco->priv; + + if (!rsc->pll_on && + mdss_pll_resource_enable(rsc, true)) { + pr_err("failed to enable pll (%d) resources\n", rsc->index); + return; + } + + rsc->handoff_resources = false; + rsc->dfps_trigger = false; + + pr_debug("stop PLL (%d)\n", rsc->index); + + /* + * To avoid any stray glitches while + * abruptly powering down the PLL + * make sure to gate the clock using + * the clock enable bit before powering + * down the PLL + */ + dsi_pll_disable_global_clk(rsc); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_PLL_CNTRL, 0); + dsi_pll_disable_sub(rsc); + if (rsc->slave) { + dsi_pll_disable_global_clk(rsc->slave); + dsi_pll_disable_sub(rsc->slave); + } + /* flush, ensure all register writes are done*/ + wmb(); + rsc->pll_on = false; +} + +long vco_7nm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + *parent_rate = rrate; + + return rrate; +} + +static void vco_7nm_unprepare(struct clk_hw *hw) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("dsi pll resources not available\n"); + return; + } + + /* + * During unprepare in continuous splash use case we want driver + * to pick all dividers instead of retaining bootloader configurations. + * Also handle the usecases when dynamic refresh gets triggered while + * handoff_resources flag is still set. For video mode, this flag does + * not get cleared until first suspend. Whereas for command mode, it + * doesnt get cleared until first idle power collapse. We need to make + * sure that we save and restore the divider settings when dynamic FPS + * is triggered. + */ + if (!pll->handoff_resources || pll->dfps_trigger) { + pll->cached_cfg0 = MDSS_PLL_REG_R(pll->phy_base, + PHY_CMN_CLK_CFG0); + pll->cached_outdiv = MDSS_PLL_REG_R(pll->pll_base, + PLL_PLL_OUTDIV_RATE); + pr_debug("cfg0=%d,cfg1=%d, outdiv=%d\n", pll->cached_cfg0, + pll->cached_cfg1, pll->cached_outdiv); + + pll->vco_cached_rate = clk_get_rate(hw->clk); + } + + /* + * When continuous splash screen feature is enabled, we need to cache + * the mux configuration for the pixel_clk_src mux clock. The clock + * framework does not call back to re-configure the mux value if it is + * does not change.For such usecases, we need to ensure that the cached + * value is programmed prior to PLL being locked + */ + if (pll->handoff_resources) { + pll->cached_cfg1 = MDSS_PLL_REG_R(pll->phy_base, + PHY_CMN_CLK_CFG1); + if (pll->slave) + pll->slave->cached_cfg1 = + MDSS_PLL_REG_R(pll->slave->phy_base, + PHY_CMN_CLK_CFG1); + } + + dsi_pll_disable(vco); + mdss_pll_resource_enable(pll, false); +} + +static int vco_7nm_prepare(struct clk_hw *hw) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("dsi pll resources are not available\n"); + return -EINVAL; + } + + /* Skip vco recalculation for continuous splash use case */ + if (pll->handoff_resources) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("failed to enable pll (%d) resource, rc=%d\n", + pll->index, rc); + return rc; + } + + if ((pll->vco_cached_rate != 0) && + (pll->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = hw->init->ops->set_rate(hw, pll->vco_cached_rate, + pll->vco_cached_rate); + if (rc) { + pr_err("pll(%d) set_rate failed, rc=%d\n", + pll->index, rc); + mdss_pll_resource_enable(pll, false); + return rc; + } + pr_debug("cfg0=%d, cfg1=%d\n", pll->cached_cfg0, + pll->cached_cfg1); + MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, + pll->cached_cfg0); + if (pll->slave) + MDSS_PLL_REG_W(pll->slave->phy_base, PHY_CMN_CLK_CFG0, + pll->cached_cfg0); + MDSS_PLL_REG_W(pll->pll_base, PLL_PLL_OUTDIV_RATE, + pll->cached_outdiv); + } + + rc = dsi_pll_enable(vco); + if (rc) { + mdss_pll_resource_enable(pll, false); + pr_err("pll(%d) enable failed, rc=%d\n", pll->index, rc); + return rc; + } + + return rc; +} + +static unsigned long vco_7nm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk_hw(hw); + struct mdss_pll_resources *pll = vco->priv; + int rc; + + if (!vco->priv) { + pr_err("vco priv is null\n"); + return 0; + } + + if (!pll->priv) { + pr_err("pll priv is null\n"); + return 0; + } + + /* + * In the case when vco arte is set, the recalculation function should + * return the current rate as to avoid trying to set the vco rate + * again. However durng handoff, recalculation should set the flag + * according to the status of PLL. + */ + if (pll->vco_current_rate != 0) { + pr_debug("returning vco rate = %lld\n", pll->vco_current_rate); + return pll->vco_current_rate; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("failed to enable pll(%d) resource, rc=%d\n", + pll->index, rc); + return 0; + } + + pll->handoff_resources = true; + dsi_pll_detect_phy_mode(pll->priv, pll); + if (dsi_pll_7nm_lock_status(pll)) { + pr_debug("PLL not enabled\n"); + pll->handoff_resources = false; + } + + (void)mdss_pll_resource_enable(pll, false); + return rc; +} + +static int pixel_clk_get_div(void *context, unsigned int reg, unsigned int *div) +{ + int rc; + struct mdss_pll_resources *pll = context; + u32 reg_val; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); + *div = (reg_val & 0xF0) >> 4; + + (void)mdss_pll_resource_enable(pll, false); + + return rc; +} + +static void pixel_clk_set_div_sub(struct mdss_pll_resources *pll, int div) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); + reg_val &= ~0xF0; + reg_val |= (div << 4); + MDSS_PLL_REG_W(pll->phy_base, PHY_CMN_CLK_CFG0, reg_val); + + /* + * cache the current parent index for cases where parent + * is not changing but rate is changing. In that case + * clock framework won't call parent_set and hence dsiclk_sel + * bit won't be programmed. e.g. dfps update use case. + */ + pll->cached_cfg0 = reg_val; +} + +static int pixel_clk_set_div(void *context, unsigned int reg, unsigned int div) +{ + int rc; + struct mdss_pll_resources *pll = context; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + pixel_clk_set_div_sub(pll, div); + if (pll->slave) + pixel_clk_set_div_sub(pll->slave, div); + (void)mdss_pll_resource_enable(pll, false); + + return 0; +} + +static int bit_clk_get_div(void *context, unsigned int reg, unsigned int *div) +{ + int rc; + struct mdss_pll_resources *pll = context; + u32 reg_val; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + reg_val = MDSS_PLL_REG_R(pll->phy_base, PHY_CMN_CLK_CFG0); + *div = (reg_val & 0x0F); + + (void)mdss_pll_resource_enable(pll, false); + + return rc; +} + +static void bit_clk_set_div_sub(struct mdss_pll_resources *rsc, int div) +{ + u32 reg_val; + + reg_val = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CLK_CFG0); + reg_val &= ~0x0F; + reg_val |= div; + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CLK_CFG0, reg_val); +} + +static int bit_clk_set_div(void *context, unsigned int reg, unsigned int div) +{ + int rc; + struct mdss_pll_resources *rsc = context; + struct dsi_pll_8998 *pll; + + if (!rsc) { + pr_err("pll resource not found\n"); + return -EINVAL; + } + + pll = rsc->priv; + if (!pll) { + pr_err("pll configuration not found\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(rsc, true); + if (rc) { + pr_err("Failed to enable dsi pll resources, rc=%d\n", rc); + return rc; + } + + bit_clk_set_div_sub(rsc, div); + /* For slave PLL, this divider always should be set to 1 */ + if (rsc->slave) + bit_clk_set_div_sub(rsc->slave, 1); + + (void)mdss_pll_resource_enable(rsc, false); + + return rc; +} + +static struct regmap_config dsi_pll_7nm_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x7c0, +}; + +static struct regmap_bus pll_regmap_bus = { + .reg_write = pll_reg_write, + .reg_read = pll_reg_read, +}; + +static struct regmap_bus pclk_src_mux_regmap_bus = { + .reg_read = pclk_mux_read_sel, + .reg_write = pclk_mux_write_sel, +}; + +static struct regmap_bus cphy_pclk_src_mux_regmap_bus = { + .reg_read = cphy_pclk_mux_read_sel, + .reg_write = cphy_pclk_mux_write_sel, +}; + +static struct regmap_bus pclk_src_regmap_bus = { + .reg_write = pixel_clk_set_div, + .reg_read = pixel_clk_get_div, +}; + +static struct regmap_bus bitclk_src_regmap_bus = { + .reg_write = bit_clk_set_div, + .reg_read = bit_clk_get_div, +}; + +static const struct clk_ops clk_ops_vco_7nm = { + .recalc_rate = vco_7nm_recalc_rate, + .set_rate = vco_7nm_set_rate, + .round_rate = vco_7nm_round_rate, + .prepare = vco_7nm_prepare, + .unprepare = vco_7nm_unprepare, +}; + +static const struct clk_ops clk_ops_shadow_vco_7nm = { + .recalc_rate = vco_7nm_recalc_rate, + .set_rate = shadow_vco_7nm_set_rate, + .round_rate = vco_7nm_round_rate, +}; + +static struct regmap_bus mdss_mux_regmap_bus = { + .reg_write = mdss_set_mux_sel, + .reg_read = mdss_get_mux_sel, +}; + +/* + * Clock tree for generating DSI byte and pclk. + * + * + * +---------------+ + * | vco_clk | + * +-------+-------+ + * | + * | + * +---------------+ + * | pll_out_div | + * | DIV(1,2,4,8) | + * +-------+-------+ + * | + * +-----------------------------+-------+---------------+ + * | | | | + * +-------v-------+ | | | + * | bitclk_src | | + * | DIV(1..15) | Not supported for DPHY | + * +-------+-------+ | + * | | | | + * +-------------v+---------+---------+ | | | + * | | | | | | | + * +-----v-----+ +-----v-----+ | +------v------+ | +-----v------+ +-----v------+ + * |byteclk_src| |byteclk_src| | |post_bit_div | | |post_vco_div| |post_vco_div| + * | DIV(8) | | DIV(7) | | | DIV (2) | | | DIV(4) | | DIV(3.5) | + * +-----+-----+ +-----+-----+ | +------+------+ | +-----+------+ +------+-----+ + * | | | | | | | + *Shadow DPHY | Shadow CPHY Path | | | | +----v + * Path | CPHY Path | +------+ | | +---+ | + * +---+ | | +-----+ | | | | | + * | | | | +-v--v----v---v---+ +--------v--------+ + * +---v--v----v---v---+ \ pclk_src_mux / \ cphy_pclk_src / + * \ byteclk_mux / \ / \ mux / + * \ / +-----+-----+ +-----+-----+ + * +------+------+ | Shadow | + * | | DPHY Path | + * v +-----v------+ | +------v------+ + * dsi_byte_clk | pclk_src | | |cphy_pclk_src| + * | DIV(1..15) | | | DIV(1..15) | + * +-----+------+ | +------+------+ + * | | | + * | | CPHY Path + * | | | Shadow CPHY Path + * +-------+ | +-------+ | + * | | | |---------------- + * +---v---v----v---v--+ + * \ pclk_mux / + * +------+------+ + * | + * v + * dsi_pclk + * + */ + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_vco_7nm, + }, +}; + +static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_shadow_vco_7nm, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_vco_7nm, + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 3500000000UL, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_vco_clk", + .parent_names = (const char *[]){"bi_tcxo"}, + .num_parents = 1, + .ops = &clk_ops_shadow_vco_7nm, + }, +}; + +static struct clk_regmap_div dsi0pll_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pll_out_div", + .parent_names = (const char *[]){"dsi0pll_vco_clk"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pll_out_div", + .parent_names = (const char *[]){ + "dsi0pll_shadow_vco_clk"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pll_out_div", + .parent_names = (const char *[]){"dsi1pll_vco_clk"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_pll_out_div = { + .reg = PLL_PLL_OUTDIV_RATE, + .shift = 0, + .width = 2, + .flags = CLK_DIVIDER_POWER_OF_TWO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pll_out_div", + .parent_names = (const char *[]){ + "dsi1pll_shadow_vco_clk"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_bitclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_bitclk_src", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_bitclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_bitclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_bitclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_bitclk_src", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_bitclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_bitclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_fixed_factor dsi0pll_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_vco_div", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_vco_div", + .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_vco_div", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_post_vco_div3_5 = { + .div = 7, + .mult = 2, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_vco_div3_5", + .parent_names = (const char *[]){"dsi0pll_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_post_vco_div3_5 = { + .div = 7, + .mult = 2, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_vco_div3_5", + .parent_names = (const char *[]){"dsi0pll_shadow_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_post_vco_div3_5 = { + .div = 7, + .mult = 2, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_vco_div3_5", + .parent_names = (const char *[]){"dsi1pll_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_post_vco_div3_5 = { + .div = 7, + .mult = 2, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_vco_div3_5", + .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_post_vco_div = { + .div = 4, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_vco_div", + .parent_names = (const char *[]){"dsi1pll_shadow_pll_out_div"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_cphy_byteclk_src = { + .div = 7, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_cphy_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_cphy_byteclk_src = { + .div = 7, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_cphy_byteclk_src", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_cphy_byteclk_src = { + .div = 7, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_cphy_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_cphy_byteclk_src = { + .div = 7, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_cphy_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_byteclk_src = { + .div = 8, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_byteclk_src", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_post_bit_div", + .parent_names = (const char *[]){"dsi0pll_bitclk_src"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi0pll_shadow_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_post_bit_div", + .parent_names = (const char *[]){"dsi0pll_shadow_bitclk_src"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_post_bit_div", + .parent_names = (const char *[]){"dsi1pll_bitclk_src"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor dsi1pll_shadow_post_bit_div = { + .div = 2, + .mult = 1, + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_post_bit_div", + .parent_names = (const char *[]){"dsi1pll_shadow_bitclk_src"}, + .num_parents = 1, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux dsi0pll_byteclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0_phy_pll_out_byteclk", + .parent_names = (const char *[]){"dsi0pll_byteclk_src", + "dsi0pll_shadow_byteclk_src", + "dsi0pll_cphy_byteclk_src", + "dsi0pll_shadow_cphy_byteclk_src"}, + .num_parents = 4, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_byteclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1_phy_pll_out_byteclk", + .parent_names = (const char *[]){"dsi1pll_byteclk_src", + "dsi1pll_shadow_byteclk_src", + "dsi1pll_cphy_byteclk_src", + "dsi1pll_shadow_cphy_byteclk_src"}, + .num_parents = 4, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pclk_src_mux", + .parent_names = (const char *[]){"dsi0pll_bitclk_src", + "dsi0pll_post_bit_div"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_shadow_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pclk_src_mux", + .parent_names = (const char *[]){ + "dsi0pll_shadow_bitclk_src", + "dsi0pll_shadow_post_bit_div"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_cphy_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_cphy_pclk_src_mux", + .parent_names = + (const char *[]){"dsi0pll_post_vco_div3_5"}, + .num_parents = 1, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_shadow_cphy_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_cphy_pclk_src_mux", + .parent_names = + (const char *[]){ + "dsi0pll_shadow_post_vco_div3_5"}, + .num_parents = 1, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pclk_src_mux", + .parent_names = (const char *[]){"dsi1pll_bitclk_src", + "dsi1pll_post_bit_div"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_shadow_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pclk_src_mux", + .parent_names = (const char *[]){ + "dsi1pll_shadow_bitclk_src", + "dsi1pll_shadow_post_bit_div"}, + .num_parents = 2, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_cphy_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_cphy_pclk_src_mux", + .parent_names = + (const char *[]){"dsi1pll_post_vco_div3_5"}, + .num_parents = 1, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_shadow_cphy_pclk_src_mux = { + .reg = PHY_CMN_CLK_CFG1, + .shift = 0, + .width = 2, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_cphy_pclk_src_mux", + .parent_names = + (const char *[]){ + "dsi1pll_shadow_post_vco_div3_5"}, + .num_parents = 1, + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_pclk_src_mux"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_pclk_src_mux"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_cphy_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_cphy_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_cphy_pclk_src_mux"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi0pll_shadow_cphy_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0pll_shadow_cphy_pclk_src", + .parent_names = (const char *[]){ + "dsi0pll_shadow_cphy_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_pclk_src_mux"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_pclk_src_mux"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_cphy_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_cphy_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_cphy_pclk_src_mux"}, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_div dsi1pll_shadow_cphy_pclk_src = { + .shift = 0, + .width = 4, + .flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1pll_shadow_cphy_pclk_src", + .parent_names = (const char *[]){ + "dsi1pll_shadow_cphy_pclk_src_mux"}, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT), + .ops = &clk_regmap_div_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi0pll_pclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi0_phy_pll_out_dsiclk", + .parent_names = (const char *[]){"dsi0pll_pclk_src", + "dsi0pll_shadow_pclk_src", + "dsi0pll_cphy_pclk_src", + "dsi0pll_shadow_cphy_pclk_src"}, + .num_parents = 4, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux dsi1pll_pclk_mux = { + .shift = 0, + .width = 1, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "dsi1_phy_pll_out_dsiclk", + .parent_names = (const char *[]){"dsi1pll_pclk_src", + "dsi1pll_shadow_pclk_src", + "dsi1pll_cphy_pclk_src", + "dsi1pll_shadow_cphy_pclk_src"}, + .num_parents = 4, + .flags = (CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_hw *mdss_dsi_pllcc_7nm[] = { + [VCO_CLK_0] = &dsi0pll_vco_clk.hw, + [PLL_OUT_DIV_0_CLK] = &dsi0pll_pll_out_div.clkr.hw, + [BITCLK_SRC_0_CLK] = &dsi0pll_bitclk_src.clkr.hw, + [BYTECLK_SRC_0_CLK] = &dsi0pll_byteclk_src.hw, + [CPHY_BYTECLK_SRC_0_CLK] = &dsi0pll_cphy_byteclk_src.hw, + [POST_BIT_DIV_0_CLK] = &dsi0pll_post_bit_div.hw, + [POST_VCO_DIV_0_CLK] = &dsi0pll_post_vco_div.hw, + [POST_VCO_DIV3_5_0_CLK] = &dsi0pll_post_vco_div3_5.hw, + [BYTECLK_MUX_0_CLK] = &dsi0pll_byteclk_mux.clkr.hw, + [PCLK_SRC_MUX_0_CLK] = &dsi0pll_pclk_src_mux.clkr.hw, + [PCLK_SRC_0_CLK] = &dsi0pll_pclk_src.clkr.hw, + [PCLK_MUX_0_CLK] = &dsi0pll_pclk_mux.clkr.hw, + [CPHY_PCLK_SRC_MUX_0_CLK] = &dsi0pll_cphy_pclk_src_mux.clkr.hw, + [CPHY_PCLK_SRC_0_CLK] = &dsi0pll_cphy_pclk_src.clkr.hw, + [SHADOW_VCO_CLK_0] = &dsi0pll_shadow_vco_clk.hw, + [SHADOW_PLL_OUT_DIV_0_CLK] = &dsi0pll_shadow_pll_out_div.clkr.hw, + [SHADOW_BITCLK_SRC_0_CLK] = &dsi0pll_shadow_bitclk_src.clkr.hw, + [SHADOW_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_byteclk_src.hw, + [SHADOW_CPHY_BYTECLK_SRC_0_CLK] = &dsi0pll_shadow_cphy_byteclk_src.hw, + [SHADOW_POST_BIT_DIV_0_CLK] = &dsi0pll_shadow_post_bit_div.hw, + [SHADOW_POST_VCO_DIV_0_CLK] = &dsi0pll_shadow_post_vco_div.hw, + [SHADOW_POST_VCO_DIV3_5_0_CLK] = &dsi0pll_shadow_post_vco_div3_5.hw, + [SHADOW_PCLK_SRC_MUX_0_CLK] = &dsi0pll_shadow_pclk_src_mux.clkr.hw, + [SHADOW_PCLK_SRC_0_CLK] = &dsi0pll_shadow_pclk_src.clkr.hw, + [SHADOW_CPHY_PCLK_SRC_MUX_0_CLK] = + &dsi0pll_shadow_cphy_pclk_src_mux.clkr.hw, + [SHADOW_CPHY_PCLK_SRC_0_CLK] = &dsi0pll_shadow_cphy_pclk_src.clkr.hw, + [VCO_CLK_1] = &dsi1pll_vco_clk.hw, + [PLL_OUT_DIV_1_CLK] = &dsi1pll_pll_out_div.clkr.hw, + [BITCLK_SRC_1_CLK] = &dsi1pll_bitclk_src.clkr.hw, + [BYTECLK_SRC_1_CLK] = &dsi1pll_byteclk_src.hw, + [CPHY_BYTECLK_SRC_1_CLK] = &dsi1pll_cphy_byteclk_src.hw, + [POST_BIT_DIV_1_CLK] = &dsi1pll_post_bit_div.hw, + [POST_VCO_DIV_1_CLK] = &dsi1pll_post_vco_div.hw, + [POST_VCO_DIV3_5_1_CLK] = &dsi1pll_post_vco_div3_5.hw, + [BYTECLK_MUX_1_CLK] = &dsi1pll_byteclk_mux.clkr.hw, + [PCLK_SRC_MUX_1_CLK] = &dsi1pll_pclk_src_mux.clkr.hw, + [PCLK_SRC_1_CLK] = &dsi1pll_pclk_src.clkr.hw, + [PCLK_MUX_1_CLK] = &dsi1pll_pclk_mux.clkr.hw, + [CPHY_PCLK_SRC_MUX_1_CLK] = &dsi1pll_cphy_pclk_src_mux.clkr.hw, + [CPHY_PCLK_SRC_1_CLK] = &dsi1pll_cphy_pclk_src.clkr.hw, + [SHADOW_VCO_CLK_1] = &dsi1pll_shadow_vco_clk.hw, + [SHADOW_PLL_OUT_DIV_1_CLK] = &dsi1pll_shadow_pll_out_div.clkr.hw, + [SHADOW_BITCLK_SRC_1_CLK] = &dsi1pll_shadow_bitclk_src.clkr.hw, + [SHADOW_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_byteclk_src.hw, + [SHADOW_CPHY_BYTECLK_SRC_1_CLK] = &dsi1pll_shadow_cphy_byteclk_src.hw, + [SHADOW_POST_BIT_DIV_1_CLK] = &dsi1pll_shadow_post_bit_div.hw, + [SHADOW_POST_VCO_DIV_1_CLK] = &dsi1pll_shadow_post_vco_div.hw, + [SHADOW_POST_VCO_DIV3_5_1_CLK] = &dsi1pll_shadow_post_vco_div3_5.hw, + [SHADOW_PCLK_SRC_MUX_1_CLK] = &dsi1pll_shadow_pclk_src_mux.clkr.hw, + [SHADOW_PCLK_SRC_1_CLK] = &dsi1pll_shadow_pclk_src.clkr.hw, + [SHADOW_CPHY_PCLK_SRC_MUX_1_CLK] = + &dsi1pll_shadow_cphy_pclk_src_mux.clkr.hw, + [SHADOW_CPHY_PCLK_SRC_1_CLK] = &dsi1pll_shadow_cphy_pclk_src.clkr.hw, +}; + +int dsi_pll_clock_register_7nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx, i; + struct clk *clk; + struct clk_onecell_data *clk_data; + int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_7nm); + struct regmap *rmap; + + if (!pdev || !pdev->dev.of_node || + !pll_res || !pll_res->pll_base || !pll_res->phy_base) { + pr_err("Invalid params\n"); + return -EINVAL; + } + + ndx = pll_res->index; + + if (ndx >= DSI_PLL_MAX) { + pr_err("pll index(%d) NOT supported\n", ndx); + return -EINVAL; + } + + pll_rsc_db[ndx] = pll_res; + plls[ndx].rsc = pll_res; + pll_res->priv = &plls[ndx]; + pll_res->vco_delay = VCO_DELAY_USEC; + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) + return -ENOMEM; + + clk_data->clk_num = num_clks; + + /* Establish client data */ + if (ndx == 0) { + rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_pll_out_div.clkr.regmap = rmap; + dsi0pll_shadow_pll_out_div.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_bitclk_src.clkr.regmap = rmap; + dsi0pll_shadow_bitclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_pclk_src.clkr.regmap = rmap; + dsi0pll_cphy_pclk_src.clkr.regmap = rmap; + dsi0pll_shadow_pclk_src.clkr.regmap = rmap; + dsi0pll_shadow_cphy_pclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_pclk_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_pclk_src_mux.clkr.regmap = rmap; + dsi0pll_shadow_pclk_src_mux.clkr.regmap = rmap; + rmap = devm_regmap_init(&pdev->dev, + &cphy_pclk_src_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_cphy_pclk_src_mux.clkr.regmap = rmap; + dsi0pll_shadow_cphy_pclk_src_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi0pll_byteclk_mux.clkr.regmap = rmap; + + dsi0pll_vco_clk.priv = pll_res; + dsi0pll_shadow_vco_clk.priv = pll_res; + + if (dsi_pll_7nm_is_hw_revision_v4_1(pll_res)) { + dsi0pll_vco_clk.min_rate = 600000000; + dsi0pll_vco_clk.max_rate = 5000000000; + dsi0pll_shadow_vco_clk.min_rate = 600000000; + dsi0pll_shadow_vco_clk.max_rate = 5000000000; + } + + for (i = VCO_CLK_0; i <= SHADOW_CPHY_PCLK_SRC_0_CLK; i++) { + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_7nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI clock:%d\n", + pll_res->index); + rc = -EINVAL; + goto clk_register_fail; + } + clk_data->clks[i] = clk; + + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } else { + rmap = devm_regmap_init(&pdev->dev, &pll_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_pll_out_div.clkr.regmap = rmap; + dsi1pll_shadow_pll_out_div.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &bitclk_src_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_bitclk_src.clkr.regmap = rmap; + dsi1pll_shadow_bitclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_pclk_src.clkr.regmap = rmap; + dsi1pll_cphy_pclk_src.clkr.regmap = rmap; + dsi1pll_shadow_pclk_src.clkr.regmap = rmap; + dsi1pll_shadow_cphy_pclk_src.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_pclk_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &pclk_src_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_pclk_src_mux.clkr.regmap = rmap; + dsi1pll_shadow_pclk_src_mux.clkr.regmap = rmap; + rmap = devm_regmap_init(&pdev->dev, + &cphy_pclk_src_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_cphy_pclk_src_mux.clkr.regmap = rmap; + dsi1pll_shadow_cphy_pclk_src_mux.clkr.regmap = rmap; + + rmap = devm_regmap_init(&pdev->dev, &mdss_mux_regmap_bus, + pll_res, &dsi_pll_7nm_config); + dsi1pll_byteclk_mux.clkr.regmap = rmap; + dsi1pll_vco_clk.priv = pll_res; + dsi1pll_shadow_vco_clk.priv = pll_res; + + if (dsi_pll_7nm_is_hw_revision_v4_1(pll_res)) { + dsi1pll_vco_clk.min_rate = 600000000; + dsi1pll_vco_clk.max_rate = 5000000000; + dsi1pll_shadow_vco_clk.min_rate = 600000000; + dsi1pll_shadow_vco_clk.max_rate = 5000000000; + } + + for (i = VCO_CLK_1; i <= SHADOW_CPHY_PCLK_SRC_1_CLK; i++) { + clk = devm_clk_register(&pdev->dev, + mdss_dsi_pllcc_7nm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for DSI clock:%d\n", + pll_res->index); + rc = -EINVAL; + goto clk_register_fail; + } + clk_data->clks[i] = clk; + + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + } + if (!rc) { + pr_info("Registered DSI PLL ndx=%d, clocks successfully\n", + ndx); + + return rc; + } +clk_register_fail: + return rc; +} diff --git a/techpack/display/pll/dsi_pll_8996.c b/techpack/display/pll/dsi_pll_8996.c new file mode 100644 index 0000000000000000000000000000000000000000..963c56c06fb2cf72b023742b1964a378cbc25964 --- /dev/null +++ b/techpack/display/pll/dsi_pll_8996.c @@ -0,0 +1,548 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/workqueue.h> +#include <linux/clk/msm-clock-generic.h> +#include <dt-bindings/clock/msm-clocks-8996.h> + +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dsi_pll_8996.h" + +#define VCO_DELAY_USEC 1 + +static struct dsi_pll_db pll_db[DSI_PLL_NUM]; + +static const struct clk_ops n2_clk_src_ops; +static const struct clk_ops shadow_n2_clk_src_ops; +static const struct clk_ops byte_clk_src_ops; +static const struct clk_ops post_n1_div_clk_src_ops; +static const struct clk_ops shadow_post_n1_div_clk_src_ops; + +static const struct clk_ops clk_ops_gen_mux_dsi; + +/* Op structures */ +static const struct clk_ops clk_ops_dsi_vco = { + .set_rate = pll_vco_set_rate_8996, + .round_rate = pll_vco_round_rate_8996, + .handoff = pll_vco_handoff_8996, + .prepare = pll_vco_prepare_8996, + .unprepare = pll_vco_unprepare_8996, +}; + +static struct clk_div_ops post_n1_div_ops = { + .set_div = post_n1_div_set_div, + .get_div = post_n1_div_get_div, +}; + +static struct clk_div_ops n2_div_ops = { /* hr_oclk3 */ + .set_div = n2_div_set_div, + .get_div = n2_div_get_div, +}; + +static struct clk_mux_ops mdss_byte_mux_ops = { + .set_mux_sel = set_mdss_byte_mux_sel_8996, + .get_mux_sel = get_mdss_byte_mux_sel_8996, +}; + +static struct clk_mux_ops mdss_pixel_mux_ops = { + .set_mux_sel = set_mdss_pixel_mux_sel_8996, + .get_mux_sel = get_mdss_pixel_mux_sel_8996, +}; + +/* Shadow ops for dynamic refresh */ +static const struct clk_ops clk_ops_shadow_dsi_vco = { + .set_rate = shadow_pll_vco_set_rate_8996, + .round_rate = pll_vco_round_rate_8996, + .handoff = shadow_pll_vco_handoff_8996, +}; + +static struct clk_div_ops shadow_post_n1_div_ops = { + .set_div = post_n1_div_set_div, +}; + +static struct clk_div_ops shadow_n2_div_ops = { + .set_div = shadow_n2_div_set_div, +}; + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1300000000UL, + .max_rate = 2600000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_8996, + .c = { + .dbg_name = "dsi0pll_vco_clk_8996", + .ops = &clk_ops_dsi_vco, + CLK_INIT(dsi0pll_vco_clk.c), + }, +}; + +static struct dsi_pll_vco_clk dsi0pll_shadow_vco_clk = { + .ref_clk_rate = 19200000u, + .min_rate = 1300000000u, + .max_rate = 2600000000u, + .c = { + .dbg_name = "dsi0pll_shadow_vco_clk", + .ops = &clk_ops_shadow_dsi_vco, + CLK_INIT(dsi0pll_shadow_vco_clk.c), + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1300000000UL, + .max_rate = 2600000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_8996, + .c = { + .dbg_name = "dsi1pll_vco_clk_8996", + .ops = &clk_ops_dsi_vco, + CLK_INIT(dsi1pll_vco_clk.c), + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_shadow_vco_clk = { + .ref_clk_rate = 19200000u, + .min_rate = 1300000000u, + .max_rate = 2600000000u, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_8996, + .c = { + .dbg_name = "dsi1pll_shadow_vco_clk", + .ops = &clk_ops_shadow_dsi_vco, + CLK_INIT(dsi1pll_shadow_vco_clk.c), + }, +}; + +static struct div_clk dsi0pll_post_n1_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &post_n1_div_ops, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_n1_div_clk", + .ops = &post_n1_div_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_n1_div_clk.c), + }, +}; + +static struct div_clk dsi0pll_shadow_post_n1_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &shadow_post_n1_div_ops, + .c = { + .parent = &dsi0pll_shadow_vco_clk.c, + .dbg_name = "dsi0pll_shadow_post_n1_div_clk", + .ops = &shadow_post_n1_div_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_shadow_post_n1_div_clk.c), + }, +}; + +static struct div_clk dsi1pll_post_n1_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &post_n1_div_ops, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_n1_div_clk", + .ops = &post_n1_div_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_n1_div_clk.c), + }, +}; + +static struct div_clk dsi1pll_shadow_post_n1_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &shadow_post_n1_div_ops, + .c = { + .parent = &dsi1pll_shadow_vco_clk.c, + .dbg_name = "dsi1pll_shadow_post_n1_div_clk", + .ops = &shadow_post_n1_div_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_shadow_post_n1_div_clk.c), + }, +}; + +static struct div_clk dsi0pll_n2_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &n2_div_ops, + .c = { + .parent = &dsi0pll_post_n1_div_clk.c, + .dbg_name = "dsi0pll_n2_div_clk", + .ops = &n2_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_n2_div_clk.c), + }, +}; + +static struct div_clk dsi0pll_shadow_n2_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &shadow_n2_div_ops, + .c = { + .parent = &dsi0pll_shadow_post_n1_div_clk.c, + .dbg_name = "dsi0pll_shadow_n2_div_clk", + .ops = &shadow_n2_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_shadow_n2_div_clk.c), + }, +}; + +static struct div_clk dsi1pll_n2_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &n2_div_ops, + .c = { + .parent = &dsi1pll_post_n1_div_clk.c, + .dbg_name = "dsi1pll_n2_div_clk", + .ops = &n2_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_n2_div_clk.c), + }, +}; + +static struct div_clk dsi1pll_shadow_n2_div_clk = { + .data = { + .max_div = 15, + .min_div = 1, + }, + .ops = &shadow_n2_div_ops, + .c = { + .parent = &dsi1pll_shadow_post_n1_div_clk.c, + .dbg_name = "dsi1pll_shadow_n2_div_clk", + .ops = &shadow_n2_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_shadow_n2_div_clk.c), + }, +}; + +static struct div_clk dsi0pll_pixel_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi0pll_n2_div_clk.c, + .dbg_name = "dsi0pll_pixel_clk_src", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pixel_clk_src.c), + }, +}; + +static struct div_clk dsi0pll_shadow_pixel_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi0pll_shadow_n2_div_clk.c, + .dbg_name = "dsi0pll_shadow_pixel_clk_src", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_shadow_pixel_clk_src.c), + }, +}; + +static struct div_clk dsi1pll_pixel_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi1pll_n2_div_clk.c, + .dbg_name = "dsi1pll_pixel_clk_src", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pixel_clk_src.c), + }, +}; + +static struct div_clk dsi1pll_shadow_pixel_clk_src = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi1pll_shadow_n2_div_clk.c, + .dbg_name = "dsi1pll_shadow_pixel_clk_src", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_shadow_pixel_clk_src.c), + }, +}; + +static struct mux_clk dsi0pll_pixel_clk_mux = { + .num_parents = 2, + .parents = (struct clk_src[]) { + {&dsi0pll_pixel_clk_src.c, 0}, + {&dsi0pll_shadow_pixel_clk_src.c, 1}, + }, + .ops = &mdss_pixel_mux_ops, + .c = { + .parent = &dsi0pll_pixel_clk_src.c, + .dbg_name = "dsi0pll_pixel_clk_mux", + .ops = &clk_ops_gen_mux_dsi, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pixel_clk_mux.c), + } +}; + +static struct mux_clk dsi1pll_pixel_clk_mux = { + .num_parents = 2, + .parents = (struct clk_src[]) { + {&dsi1pll_pixel_clk_src.c, 0}, + {&dsi1pll_shadow_pixel_clk_src.c, 1}, + }, + .ops = &mdss_pixel_mux_ops, + .c = { + .parent = &dsi1pll_pixel_clk_src.c, + .dbg_name = "dsi1pll_pixel_clk_mux", + .ops = &clk_ops_gen_mux_dsi, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pixel_clk_mux.c), + } +}; + +static struct div_clk dsi0pll_byte_clk_src = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi0pll_post_n1_div_clk.c, + .dbg_name = "dsi0pll_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(dsi0pll_byte_clk_src.c), + }, +}; + +static struct div_clk dsi0pll_shadow_byte_clk_src = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi0pll_shadow_post_n1_div_clk.c, + .dbg_name = "dsi0pll_shadow_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(dsi0pll_shadow_byte_clk_src.c), + }, +}; + +static struct div_clk dsi1pll_byte_clk_src = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi1pll_post_n1_div_clk.c, + .dbg_name = "dsi1pll_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(dsi1pll_byte_clk_src.c), + }, +}; + +static struct div_clk dsi1pll_shadow_byte_clk_src = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi1pll_shadow_post_n1_div_clk.c, + .dbg_name = "dsi1pll_shadow_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(dsi1pll_shadow_byte_clk_src.c), + }, +}; + +static struct mux_clk dsi0pll_byte_clk_mux = { + .num_parents = 2, + .parents = (struct clk_src[]) { + {&dsi0pll_byte_clk_src.c, 0}, + {&dsi0pll_shadow_byte_clk_src.c, 1}, + }, + .ops = &mdss_byte_mux_ops, + .c = { + .parent = &dsi0pll_byte_clk_src.c, + .dbg_name = "dsi0pll_byte_clk_mux", + .ops = &clk_ops_gen_mux_dsi, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_byte_clk_mux.c), + } +}; +static struct mux_clk dsi1pll_byte_clk_mux = { + .num_parents = 2, + .parents = (struct clk_src[]) { + {&dsi1pll_byte_clk_src.c, 0}, + {&dsi1pll_shadow_byte_clk_src.c, 1}, + }, + .ops = &mdss_byte_mux_ops, + .c = { + .parent = &dsi1pll_byte_clk_src.c, + .dbg_name = "dsi1pll_byte_clk_mux", + .ops = &clk_ops_gen_mux_dsi, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_byte_clk_mux.c), + } +}; + +static struct clk_lookup mdss_dsi_pllcc_8996[] = { + CLK_LIST(dsi0pll_byte_clk_mux), + CLK_LIST(dsi0pll_byte_clk_src), + CLK_LIST(dsi0pll_pixel_clk_mux), + CLK_LIST(dsi0pll_pixel_clk_src), + CLK_LIST(dsi0pll_n2_div_clk), + CLK_LIST(dsi0pll_post_n1_div_clk), + CLK_LIST(dsi0pll_vco_clk), + CLK_LIST(dsi0pll_shadow_byte_clk_src), + CLK_LIST(dsi0pll_shadow_pixel_clk_src), + CLK_LIST(dsi0pll_shadow_n2_div_clk), + CLK_LIST(dsi0pll_shadow_post_n1_div_clk), + CLK_LIST(dsi0pll_shadow_vco_clk), +}; + +static struct clk_lookup mdss_dsi_pllcc_8996_1[] = { + CLK_LIST(dsi1pll_byte_clk_mux), + CLK_LIST(dsi1pll_byte_clk_src), + CLK_LIST(dsi1pll_pixel_clk_mux), + CLK_LIST(dsi1pll_pixel_clk_src), + CLK_LIST(dsi1pll_n2_div_clk), + CLK_LIST(dsi1pll_post_n1_div_clk), + CLK_LIST(dsi1pll_vco_clk), + CLK_LIST(dsi1pll_shadow_byte_clk_src), + CLK_LIST(dsi1pll_shadow_pixel_clk_src), + CLK_LIST(dsi1pll_shadow_n2_div_clk), + CLK_LIST(dsi1pll_shadow_post_n1_div_clk), + CLK_LIST(dsi1pll_shadow_vco_clk), +}; + +int dsi_pll_clock_register_8996(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx; + int const ssc_freq_default = 31500; /* default h/w recommended value */ + int const ssc_ppm_default = 5000; /* default h/w recommended value */ + struct dsi_pll_db *pdb; + + if (pll_res->index >= DSI_PLL_NUM) { + pr_err("pll ndx=%d is NOT supported\n", pll_res->index); + return -EINVAL; + } + + ndx = pll_res->index; + pdb = &pll_db[ndx]; + pll_res->priv = pdb; + pdb->pll = pll_res; + ndx++; + ndx %= DSI_PLL_NUM; + pdb->next = &pll_db[ndx]; + + /* Set clock source operations */ + + /* hr_oclk3, pixel */ + n2_clk_src_ops = clk_ops_slave_div; + n2_clk_src_ops.prepare = mdss_pll_div_prepare; + + shadow_n2_clk_src_ops = clk_ops_slave_div; + + /* hr_ockl2, byte, vco pll */ + post_n1_div_clk_src_ops = clk_ops_div; + post_n1_div_clk_src_ops.prepare = mdss_pll_div_prepare; + + shadow_post_n1_div_clk_src_ops = clk_ops_div; + + byte_clk_src_ops = clk_ops_div; + byte_clk_src_ops.prepare = mdss_pll_div_prepare; + + clk_ops_gen_mux_dsi = clk_ops_gen_mux; + clk_ops_gen_mux_dsi.round_rate = parent_round_rate; + clk_ops_gen_mux_dsi.set_rate = parent_set_rate; + + if (pll_res->ssc_en) { + if (!pll_res->ssc_freq) + pll_res->ssc_freq = ssc_freq_default; + if (!pll_res->ssc_ppm) + pll_res->ssc_ppm = ssc_ppm_default; + } + + /* Set client data to mux, div and vco clocks. */ + if (pll_res->index == DSI_PLL_1) { + dsi1pll_byte_clk_src.priv = pll_res; + dsi1pll_pixel_clk_src.priv = pll_res; + dsi1pll_post_n1_div_clk.priv = pll_res; + dsi1pll_n2_div_clk.priv = pll_res; + dsi1pll_vco_clk.priv = pll_res; + + dsi1pll_shadow_byte_clk_src.priv = pll_res; + dsi1pll_shadow_pixel_clk_src.priv = pll_res; + dsi1pll_shadow_post_n1_div_clk.priv = pll_res; + dsi1pll_shadow_n2_div_clk.priv = pll_res; + dsi1pll_shadow_vco_clk.priv = pll_res; + + pll_res->vco_delay = VCO_DELAY_USEC; + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pllcc_8996_1, + ARRAY_SIZE(mdss_dsi_pllcc_8996_1)); + } else { + dsi0pll_byte_clk_src.priv = pll_res; + dsi0pll_pixel_clk_src.priv = pll_res; + dsi0pll_post_n1_div_clk.priv = pll_res; + dsi0pll_n2_div_clk.priv = pll_res; + dsi0pll_vco_clk.priv = pll_res; + + dsi0pll_shadow_byte_clk_src.priv = pll_res; + dsi0pll_shadow_pixel_clk_src.priv = pll_res; + dsi0pll_shadow_post_n1_div_clk.priv = pll_res; + dsi0pll_shadow_n2_div_clk.priv = pll_res; + dsi0pll_shadow_vco_clk.priv = pll_res; + + pll_res->vco_delay = VCO_DELAY_USEC; + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pllcc_8996, + ARRAY_SIZE(mdss_dsi_pllcc_8996)); + } + + if (!rc) { + pr_info("Registered DSI PLL ndx=%d clocks successfully\n", + pll_res->index); + } + + return rc; +} diff --git a/techpack/display/pll/dsi_pll_8996.h b/techpack/display/pll/dsi_pll_8996.h new file mode 100644 index 0000000000000000000000000000000000000000..94e16d86fd2399441ae755a1652a2fd61c01b386 --- /dev/null +++ b/techpack/display/pll/dsi_pll_8996.h @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef MDSS_DSI_PLL_8996_H +#define MDSS_DSI_PLL_8996_H + +#define DSIPHY_CMN_CLK_CFG0 0x0010 +#define DSIPHY_CMN_CLK_CFG1 0x0014 +#define DSIPHY_CMN_GLBL_TEST_CTRL 0x0018 + +#define DSIPHY_CMN_PLL_CNTRL 0x0048 +#define DSIPHY_CMN_CTRL_0 0x001c +#define DSIPHY_CMN_CTRL_1 0x0020 + +#define DSIPHY_CMN_LDO_CNTRL 0x004c + +#define DSIPHY_PLL_IE_TRIM 0x0400 +#define DSIPHY_PLL_IP_TRIM 0x0404 + +#define DSIPHY_PLL_IPTAT_TRIM 0x0410 + +#define DSIPHY_PLL_CLKBUFLR_EN 0x041c + +#define DSIPHY_PLL_SYSCLK_EN_RESET 0x0428 +#define DSIPHY_PLL_RESETSM_CNTRL 0x042c +#define DSIPHY_PLL_RESETSM_CNTRL2 0x0430 +#define DSIPHY_PLL_RESETSM_CNTRL3 0x0434 +#define DSIPHY_PLL_RESETSM_CNTRL4 0x0438 +#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c +#define DSIPHY_PLL_KVCO_DIV_REF1 0x0440 +#define DSIPHY_PLL_KVCO_DIV_REF2 0x0444 +#define DSIPHY_PLL_KVCO_COUNT1 0x0448 +#define DSIPHY_PLL_KVCO_COUNT2 0x044c +#define DSIPHY_PLL_VREF_CFG1 0x045c + +#define DSIPHY_PLL_KVCO_CODE 0x0458 + +#define DSIPHY_PLL_VCO_DIV_REF1 0x046c +#define DSIPHY_PLL_VCO_DIV_REF2 0x0470 +#define DSIPHY_PLL_VCO_COUNT1 0x0474 +#define DSIPHY_PLL_VCO_COUNT2 0x0478 +#define DSIPHY_PLL_PLLLOCK_CMP1 0x047c +#define DSIPHY_PLL_PLLLOCK_CMP2 0x0480 +#define DSIPHY_PLL_PLLLOCK_CMP3 0x0484 +#define DSIPHY_PLL_PLLLOCK_CMP_EN 0x0488 +#define DSIPHY_PLL_PLL_VCO_TUNE 0x048C +#define DSIPHY_PLL_DEC_START 0x0490 +#define DSIPHY_PLL_SSC_EN_CENTER 0x0494 +#define DSIPHY_PLL_SSC_ADJ_PER1 0x0498 +#define DSIPHY_PLL_SSC_ADJ_PER2 0x049c +#define DSIPHY_PLL_SSC_PER1 0x04a0 +#define DSIPHY_PLL_SSC_PER2 0x04a4 +#define DSIPHY_PLL_SSC_STEP_SIZE1 0x04a8 +#define DSIPHY_PLL_SSC_STEP_SIZE2 0x04ac +#define DSIPHY_PLL_DIV_FRAC_START1 0x04b4 +#define DSIPHY_PLL_DIV_FRAC_START2 0x04b8 +#define DSIPHY_PLL_DIV_FRAC_START3 0x04bc +#define DSIPHY_PLL_TXCLK_EN 0x04c0 +#define DSIPHY_PLL_PLL_CRCTRL 0x04c4 + +#define DSIPHY_PLL_RESET_SM_READY_STATUS 0x04cc + +#define DSIPHY_PLL_PLL_MISC1 0x04e8 + +#define DSIPHY_PLL_CP_SET_CUR 0x04f0 +#define DSIPHY_PLL_PLL_ICPMSET 0x04f4 +#define DSIPHY_PLL_PLL_ICPCSET 0x04f8 +#define DSIPHY_PLL_PLL_ICP_SET 0x04fc +#define DSIPHY_PLL_PLL_LPF1 0x0500 +#define DSIPHY_PLL_PLL_LPF2_POSTDIV 0x0504 +#define DSIPHY_PLL_PLL_BANDGAP 0x0508 + +#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 0x050 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 0x060 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 0x064 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 0x068 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 0x06C +#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 0x070 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 0x074 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 0x078 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 0x07C +#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 0x080 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 0x084 +#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 0x088 +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR 0x094 +#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 0x098 + +struct dsi_pll_input { + u32 fref; /* 19.2 Mhz, reference clk */ + u32 fdata; /* bit clock rate */ + u32 dsiclk_sel; /* 1, reg: 0x0014 */ + u32 n2div; /* 1, reg: 0x0010, bit 4-7 */ + u32 ssc_en; /* 1, reg: 0x0494, bit 0 */ + u32 ldo_en; /* 0, reg: 0x004c, bit 0 */ + + /* fixed */ + u32 refclk_dbler_en; /* 0, reg: 0x04c0, bit 1 */ + u32 vco_measure_time; /* 5, unknown */ + u32 kvco_measure_time; /* 5, unknown */ + u32 bandgap_timer; /* 4, reg: 0x0430, bit 3 - 5 */ + u32 pll_wakeup_timer; /* 5, reg: 0x043c, bit 0 - 2 */ + u32 plllock_cnt; /* 1, reg: 0x0488, bit 1 - 2 */ + u32 plllock_rng; /* 1, reg: 0x0488, bit 3 - 4 */ + u32 ssc_center; /* 0, reg: 0x0494, bit 1 */ + u32 ssc_adj_period; /* 37, reg: 0x498, bit 0 - 9 */ + u32 ssc_spread; /* 0.005 */ + u32 ssc_freq; /* unknown */ + u32 pll_ie_trim; /* 4, reg: 0x0400 */ + u32 pll_ip_trim; /* 4, reg: 0x0404 */ + u32 pll_iptat_trim; /* reg: 0x0410 */ + u32 pll_cpcset_cur; /* 1, reg: 0x04f0, bit 0 - 2 */ + u32 pll_cpmset_cur; /* 1, reg: 0x04f0, bit 3 - 5 */ + + u32 pll_icpmset; /* 4, reg: 0x04fc, bit 3 - 5 */ + u32 pll_icpcset; /* 4, reg: 0x04fc, bit 0 - 2 */ + + u32 pll_icpmset_p; /* 0, reg: 0x04f4, bit 0 - 2 */ + u32 pll_icpmset_m; /* 0, reg: 0x04f4, bit 3 - 5 */ + + u32 pll_icpcset_p; /* 0, reg: 0x04f8, bit 0 - 2 */ + u32 pll_icpcset_m; /* 0, reg: 0x04f8, bit 3 - 5 */ + + u32 pll_lpf_res1; /* 3, reg: 0x0504, bit 0 - 3 */ + u32 pll_lpf_cap1; /* 11, reg: 0x0500, bit 0 - 3 */ + u32 pll_lpf_cap2; /* 1, reg: 0x0500, bit 4 - 7 */ + u32 pll_c3ctrl; /* 2, reg: 0x04c4 */ + u32 pll_r3ctrl; /* 1, reg: 0x04c4 */ +}; + +struct dsi_pll_output { + u32 pll_txclk_en; /* reg: 0x04c0 */ + u32 dec_start; /* reg: 0x0490 */ + u32 div_frac_start; /* reg: 0x04b4, 0x4b8, 0x04bc */ + u32 ssc_period; /* reg: 0x04a0, 0x04a4 */ + u32 ssc_step_size; /* reg: 0x04a8, 0x04ac */ + u32 plllock_cmp; /* reg: 0x047c, 0x0480, 0x0484 */ + u32 pll_vco_div_ref; /* reg: 0x046c, 0x0470 */ + u32 pll_vco_count; /* reg: 0x0474, 0x0478 */ + u32 pll_kvco_div_ref; /* reg: 0x0440, 0x0444 */ + u32 pll_kvco_count; /* reg: 0x0448, 0x044c */ + u32 pll_misc1; /* reg: 0x04e8 */ + u32 pll_lpf2_postdiv; /* reg: 0x0504 */ + u32 pll_resetsm_cntrl; /* reg: 0x042c */ + u32 pll_resetsm_cntrl2; /* reg: 0x0430 */ + u32 pll_resetsm_cntrl5; /* reg: 0x043c */ + u32 pll_kvco_code; /* reg: 0x0458 */ + + u32 cmn_clk_cfg0; /* reg: 0x0010 */ + u32 cmn_clk_cfg1; /* reg: 0x0014 */ + u32 cmn_ldo_cntrl; /* reg: 0x004c */ + + u32 pll_postdiv; /* vco */ + u32 pll_n1div; /* vco */ + u32 pll_n2div; /* hr_oclk3, pixel */ + u32 fcvo; +}; + +enum { + DSI_PLL_0, + DSI_PLL_1, + DSI_PLL_NUM +}; + +struct dsi_pll_db { + struct dsi_pll_db *next; + struct mdss_pll_resources *pll; + struct dsi_pll_input in; + struct dsi_pll_output out; + int source_setup_done; +}; + +enum { + PLL_OUTPUT_NONE, + PLL_OUTPUT_RIGHT, + PLL_OUTPUT_LEFT, + PLL_OUTPUT_BOTH +}; + +enum { + PLL_SOURCE_FROM_LEFT, + PLL_SOURCE_FROM_RIGHT +}; + +enum { + PLL_UNKNOWN, + PLL_STANDALONE, + PLL_SLAVE, + PLL_MASTER +}; + +int pll_vco_set_rate_8996(struct clk *c, unsigned long rate); +long pll_vco_round_rate_8996(struct clk *c, unsigned long rate); +enum handoff pll_vco_handoff_8996(struct clk *c); +enum handoff shadow_pll_vco_handoff_8996(struct clk *c); +int shadow_post_n1_div_set_div(struct div_clk *clk, int div); +int shadow_post_n1_div_get_div(struct div_clk *clk); +int shadow_n2_div_set_div(struct div_clk *clk, int div); +int shadow_n2_div_get_div(struct div_clk *clk); +int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate); +int pll_vco_prepare_8996(struct clk *c); +void pll_vco_unprepare_8996(struct clk *c); +int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel); +int get_mdss_byte_mux_sel_8996(struct mux_clk *clk); +int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel); +int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk); +int post_n1_div_set_div(struct div_clk *clk, int div); +int post_n1_div_get_div(struct div_clk *clk); +int n2_div_set_div(struct div_clk *clk, int div); +int n2_div_get_div(struct div_clk *clk); +int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll); + +#endif /* MDSS_DSI_PLL_8996_H */ diff --git a/techpack/display/pll/dsi_pll_8996_util.c b/techpack/display/pll/dsi_pll_8996_util.c new file mode 100644 index 0000000000000000000000000000000000000000..8ce261caf3c34b6a83df6df7036db11dd19608bd --- /dev/null +++ b/techpack/display/pll/dsi_pll_8996_util.c @@ -0,0 +1,1130 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/clk/msm-clock-generic.h> + +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dsi_pll_8996.h" + +#define DSI_PLL_POLL_MAX_READS 15 +#define DSI_PLL_POLL_TIMEOUT_US 1000 +#define MSM8996_DSI_PLL_REVISION_2 2 + +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) + +int set_mdss_byte_mux_sel_8996(struct mux_clk *clk, int sel) +{ + return 0; +} + +int get_mdss_byte_mux_sel_8996(struct mux_clk *clk) +{ + return 0; +} + +int set_mdss_pixel_mux_sel_8996(struct mux_clk *clk, int sel) +{ + return 0; +} + +int get_mdss_pixel_mux_sel_8996(struct mux_clk *clk) +{ + return 0; +} + +static int mdss_pll_read_stored_trim_codes( + struct mdss_pll_resources *dsi_pll_res, s64 vco_clk_rate) +{ + int i; + int rc = 0; + bool found = false; + + if (!dsi_pll_res->dfps) { + rc = -EINVAL; + goto end_read; + } + + for (i = 0; i < dsi_pll_res->dfps->panel_dfps.frame_rate_cnt; i++) { + struct dfps_codes_info *codes_info = + &dsi_pll_res->dfps->codes_dfps[i]; + + pr_debug("valid=%d frame_rate=%d, vco_rate=%d, code %d %d\n", + codes_info->is_valid, codes_info->frame_rate, + codes_info->clk_rate, codes_info->pll_codes.pll_codes_1, + codes_info->pll_codes.pll_codes_2); + + if (vco_clk_rate != codes_info->clk_rate && + codes_info->is_valid) + continue; + + dsi_pll_res->cache_pll_trim_codes[0] = + codes_info->pll_codes.pll_codes_1; + dsi_pll_res->cache_pll_trim_codes[1] = + codes_info->pll_codes.pll_codes_2; + found = true; + break; + } + + if (!found) { + rc = -EINVAL; + goto end_read; + } + + pr_debug("core_kvco_code=0x%x core_vco_tune=0x%x\n", + dsi_pll_res->cache_pll_trim_codes[0], + dsi_pll_res->cache_pll_trim_codes[1]); + +end_read: + return rc; +} + +int post_n1_div_set_div(struct div_clk *clk, int div) +{ + struct mdss_pll_resources *pll = clk->priv; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + int rc; + u32 n1div = 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + + /* + * vco rate = bit_clk * postdiv * n1div + * vco range from 1300 to 2600 Mhz + * postdiv = 1 + * n1div = 1 to 15 + * n1div = roundup(1300Mhz / bit_clk) + * support bit_clk above 86.67Mhz + */ + + /* this is for vco/bit clock */ + pout->pll_postdiv = 1; /* fixed, divided by 1 */ + pout->pll_n1div = div; + + n1div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + n1div &= ~0xf; + n1div |= (div & 0xf); + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n1div); + /* ensure n1 divider is programed */ + wmb(); + pr_debug("ndx=%d div=%d postdiv=%x n1div=%x\n", + pll->index, div, pout->pll_postdiv, pout->pll_n1div); + + mdss_pll_resource_enable(pll, false); + + return 0; +} + +int post_n1_div_get_div(struct div_clk *clk) +{ + u32 div; + int rc; + struct mdss_pll_resources *pll = clk->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* + * postdiv = 1/2/4/8 + * n1div = 1 - 15 + * fot the time being, assume postdiv = 1 + */ + + div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + div &= 0xF; + pr_debug("n1 div = %d\n", div); + + mdss_pll_resource_enable(pll, false); + + return div; +} + +int n2_div_set_div(struct div_clk *clk, int div) +{ + int rc; + u32 n2div; + struct mdss_pll_resources *pll = clk->priv; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + struct mdss_pll_resources *slave; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + pdb = (struct dsi_pll_db *)pll->priv; + pout = &pdb->out; + + /* this is for pixel clock */ + n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + n2div &= ~0xf0; /* bits 4 to 7 */ + n2div |= (div << 4); + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG0, n2div); + + /* commit slave if split display is enabled */ + slave = pll->slave; + if (slave) + MDSS_PLL_REG_W(slave->pll_base, DSIPHY_CMN_CLK_CFG0, n2div); + + pout->pll_n2div = div; + + /* set dsiclk_sel=1 so that n2div *= 2 */ + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_CMN_CLK_CFG1, 1); + pr_debug("ndx=%d div=%d n2div=%x\n", pll->index, div, n2div); + + mdss_pll_resource_enable(pll, false); + + return rc; +} + +int shadow_n2_div_set_div(struct div_clk *clk, int div) +{ + struct mdss_pll_resources *pll = clk->priv; + struct dsi_pll_db *pdb; + struct dsi_pll_output *pout; + u32 data; + + pdb = pll->priv; + pout = &pdb->out; + + pout->pll_n2div = div; + + data = (pout->pll_n1div | (pout->pll_n2div << 4)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL19, + DSIPHY_CMN_CLK_CFG0, DSIPHY_CMN_CLK_CFG1, + data, 1); + return 0; +} + +int n2_div_get_div(struct div_clk *clk) +{ + int rc; + u32 n2div; + struct mdss_pll_resources *pll = clk->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d resources\n", + pll->index); + return rc; + } + + n2div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_CMN_CLK_CFG0); + n2div >>= 4; + n2div &= 0x0f; + + mdss_pll_resource_enable(pll, false); + + pr_debug("ndx=%d div=%d\n", pll->index, n2div); + + return n2div; +} + +static bool pll_is_pll_locked_8996(struct mdss_pll_resources *pll) +{ + u32 status; + bool pll_locked; + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((pll->pll_base + + DSIPHY_PLL_RESET_SM_READY_STATUS), + status, + ((status & BIT(5)) > 0), + DSI_PLL_POLL_MAX_READS, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_err("DSI PLL ndx=%d status=%x failed to Lock\n", + pll->index, status); + pll_locked = false; + } else if (readl_poll_timeout_atomic((pll->pll_base + + DSIPHY_PLL_RESET_SM_READY_STATUS), + status, + ((status & BIT(0)) > 0), + DSI_PLL_POLL_MAX_READS, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_err("DSI PLL ndx=%d status=%x PLl not ready\n", + pll->index, status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +static void dsi_pll_start_8996(void __iomem *pll_base) +{ + pr_debug("start PLL at base=%p\n", pll_base); + + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VREF_CFG1, 0x10); + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 1); +} + +static void dsi_pll_stop_8996(void __iomem *pll_base) +{ + pr_debug("stop PLL at base=%p\n", pll_base); + + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0); +} + +int dsi_pll_enable_seq_8996(struct mdss_pll_resources *pll) +{ + int rc = 0; + + if (!pll) { + pr_err("Invalid PLL resources\n"); + return -EINVAL; + } + + dsi_pll_start_8996(pll->pll_base); + + /* + * both DSIPHY_PLL_CLKBUFLR_EN and DSIPHY_CMN_GLBL_TEST_CTRL + * enabled at mdss_dsi_8996_phy_config() + */ + + if (!pll_is_pll_locked_8996(pll)) { + pr_err("DSI PLL ndx=%d lock failed\n", pll->index); + rc = -EINVAL; + goto init_lock_err; + } + + pr_debug("DSI PLL ndx=%d Lock success\n", pll->index); + +init_lock_err: + return rc; +} + +static int dsi_pll_enable(struct clk *c) +{ + int i, rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < vco->pll_en_seq_cnt; i++) { + rc = vco->pll_enable_seqs[i](pll); + pr_debug("DSI PLL %s after sequence #%d\n", + rc ? "unlocked" : "locked", i + 1); + if (!rc) + break; + } + + if (rc) + pr_err("ndx=%d DSI PLL failed to lock\n", pll->index); + else + pll->pll_on = true; + + return rc; +} + +static void dsi_pll_disable(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + struct mdss_pll_resources *slave; + + if (!pll->pll_on && + mdss_pll_resource_enable(pll, true)) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return; + } + + pll->handoff_resources = false; + slave = pll->slave; + + dsi_pll_stop_8996(pll->pll_base); + + mdss_pll_resource_enable(pll, false); + + pll->pll_on = false; + + pr_debug("DSI PLL ndx=%d Disabled\n", pll->index); +} + +static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + pdb->in.fref = 19200000; /* 19.2 Mhz*/ + pdb->in.fdata = 0; /* bit clock rate */ + pdb->in.dsiclk_sel = 1; /* 1, reg: 0x0014 */ + pdb->in.ssc_en = pll->ssc_en; /* 1, reg: 0x0494, bit 0 */ + pdb->in.ldo_en = 0; /* 0, reg: 0x004c, bit 0 */ + + /* fixed input */ + pdb->in.refclk_dbler_en = 0; /* 0, reg: 0x04c0, bit 1 */ + pdb->in.vco_measure_time = 5; /* 5, unknown */ + pdb->in.kvco_measure_time = 5; /* 5, unknown */ + pdb->in.bandgap_timer = 4; /* 4, reg: 0x0430, bit 3 - 5 */ + pdb->in.pll_wakeup_timer = 5; /* 5, reg: 0x043c, bit 0 - 2 */ + pdb->in.plllock_cnt = 1; /* 1, reg: 0x0488, bit 1 - 2 */ + pdb->in.plllock_rng = 0; /* 0, reg: 0x0488, bit 3 - 4 */ + pdb->in.ssc_center = pll->ssc_center;/* 0, reg: 0x0494, bit 1 */ + pdb->in.ssc_adj_period = 37; /* 37, reg: 0x498, bit 0 - 9 */ + pdb->in.ssc_spread = pll->ssc_ppm / 1000; + pdb->in.ssc_freq = pll->ssc_freq; + + pdb->in.pll_ie_trim = 4; /* 4, reg: 0x0400 */ + pdb->in.pll_ip_trim = 4; /* 4, reg: 0x0404 */ + pdb->in.pll_cpcset_cur = 1; /* 1, reg: 0x04f0, bit 0 - 2 */ + pdb->in.pll_cpmset_cur = 1; /* 1, reg: 0x04f0, bit 3 - 5 */ + pdb->in.pll_icpmset = 7; /* 7, reg: 0x04fc, bit 3 - 5 */ + pdb->in.pll_icpcset = 7; /* 7, reg: 0x04fc, bit 0 - 2 */ + pdb->in.pll_icpmset_p = 0; /* 0, reg: 0x04f4, bit 0 - 2 */ + pdb->in.pll_icpmset_m = 0; /* 0, reg: 0x04f4, bit 3 - 5 */ + pdb->in.pll_icpcset_p = 0; /* 0, reg: 0x04f8, bit 0 - 2 */ + pdb->in.pll_icpcset_m = 0; /* 0, reg: 0x04f8, bit 3 - 5 */ + pdb->in.pll_lpf_res1 = 3; /* 3, reg: 0x0504, bit 0 - 3 */ + pdb->in.pll_lpf_cap1 = 11; /* 11, reg: 0x0500, bit 0 - 3 */ + pdb->in.pll_lpf_cap2 = 1; /* 1, reg: 0x0500, bit 4 - 7 */ + pdb->in.pll_iptat_trim = 7; + pdb->in.pll_c3ctrl = 2; /* 2 */ + pdb->in.pll_r3ctrl = 1; /* 1 */ +} + +static void pll_8996_ssc_calc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + u32 period, ssc_period; + u32 ref, rem; + s64 step_size; + + pr_debug("%s: vco=%lld ref=%lld\n", __func__, + pll->vco_current_rate, pll->vco_ref_clk_rate); + + ssc_period = pdb->in.ssc_freq / 500; + period = (unsigned long)pll->vco_ref_clk_rate / 1000; + ssc_period = CEIL(period, ssc_period); + ssc_period -= 1; + pdb->out.ssc_period = ssc_period; + + pr_debug("%s: ssc, freq=%d spread=%d period=%d\n", __func__, + pdb->in.ssc_freq, pdb->in.ssc_spread, pdb->out.ssc_period); + + step_size = (u32)pll->vco_current_rate; + ref = pll->vco_ref_clk_rate; + ref /= 1000; + step_size = div_s64(step_size, ref); + step_size <<= 20; + step_size = div_s64(step_size, 1000); + step_size *= pdb->in.ssc_spread; + step_size = div_s64(step_size, 1000); + step_size *= (pdb->in.ssc_adj_period + 1); + + rem = 0; + step_size = div_s64_rem(step_size, ssc_period + 1, &rem); + if (rem) + step_size++; + + pr_debug("%s: step_size=%lld\n", __func__, step_size); + + step_size &= 0x0ffff; /* take lower 16 bits */ + + pdb->out.ssc_step_size = step_size; +} + +static void pll_8996_dec_frac_calc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + s64 multiplier = BIT(20); + s64 dec_start_multiple, dec_start, pll_comp_val; + s32 duration, div_frac_start; + s64 vco_clk_rate = pll->vco_current_rate; + s64 fref = pll->vco_ref_clk_rate; + + pr_debug("vco_clk_rate=%lld ref_clk_rate=%lld\n", + vco_clk_rate, fref); + + dec_start_multiple = div_s64(vco_clk_rate * multiplier, fref); + div_s64_rem(dec_start_multiple, multiplier, &div_frac_start); + + dec_start = div_s64(dec_start_multiple, multiplier); + + pout->dec_start = (u32)dec_start; + pout->div_frac_start = div_frac_start; + + if (pin->plllock_cnt == 0) + duration = 1024; + else if (pin->plllock_cnt == 1) + duration = 256; + else if (pin->plllock_cnt == 2) + duration = 128; + else + duration = 32; + + pll_comp_val = duration * dec_start_multiple; + pll_comp_val = div_s64(pll_comp_val, multiplier); + do_div(pll_comp_val, 10); + + pout->plllock_cmp = (u32)pll_comp_val; + + pout->pll_txclk_en = 1; + if (pll->revision == MSM8996_DSI_PLL_REVISION_2) + pout->cmn_ldo_cntrl = 0x3c; + else + pout->cmn_ldo_cntrl = 0x1c; +} + +static u32 pll_8996_kvco_slop(u32 vrate) +{ + u32 slop = 0; + + if (vrate > 1300000000UL && vrate <= 1800000000UL) + slop = 600; + else if (vrate > 1800000000UL && vrate < 2300000000UL) + slop = 400; + else if (vrate > 2300000000UL && vrate < 2600000000UL) + slop = 280; + + return slop; +} + +static void pll_8996_calc_vco_count(struct dsi_pll_db *pdb, + s64 vco_clk_rate, s64 fref) +{ + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + s64 data; + u32 cnt; + + data = fref * pin->vco_measure_time; + do_div(data, 1000000); + data &= 0x03ff; /* 10 bits */ + data -= 2; + pout->pll_vco_div_ref = data; + + data = (unsigned long)vco_clk_rate / 1000000; /* unit is Mhz */ + data *= pin->vco_measure_time; + do_div(data, 10); + pout->pll_vco_count = data; /* reg: 0x0474, 0x0478 */ + + data = fref * pin->kvco_measure_time; + do_div(data, 1000000); + data &= 0x03ff; /* 10 bits */ + data -= 1; + pout->pll_kvco_div_ref = data; + + cnt = pll_8996_kvco_slop(vco_clk_rate); + cnt *= 2; + do_div(cnt, 100); + cnt *= pin->kvco_measure_time; + pout->pll_kvco_count = cnt; + + pout->pll_misc1 = 16; + pout->pll_resetsm_cntrl = 48; + pout->pll_resetsm_cntrl2 = pin->bandgap_timer << 3; + pout->pll_resetsm_cntrl5 = pin->pll_wakeup_timer; + pout->pll_kvco_code = 0; +} + +static void pll_db_commit_ssc(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + data = pin->ssc_adj_period; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER1, data); + data = (pin->ssc_adj_period >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_ADJ_PER2, data); + + data = pout->ssc_period; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER1, data); + data = (pout->ssc_period >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_PER2, data); + + data = pout->ssc_step_size; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE1, data); + data = (pout->ssc_step_size >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_STEP_SIZE2, data); + + data = (pin->ssc_center & 0x01); + data <<= 1; + data |= 0x01; /* enable */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SSC_EN_CENTER, data); + + wmb(); /* make sure register committed */ +} + +static void pll_db_commit_common(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + /* confgiure the non frequency dependent pll registers */ + data = 0; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_SYSCLK_EN_RESET, data); + + /* DSIPHY_PLL_CLKBUFLR_EN updated at dsi phy */ + + data = pout->pll_txclk_en; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_TXCLK_EN, data); + + data = pout->pll_resetsm_cntrl; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL, data); + data = pout->pll_resetsm_cntrl2; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL2, data); + data = pout->pll_resetsm_cntrl5; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_RESETSM_CNTRL5, data); + + data = pout->pll_vco_div_ref; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF1, data); + data = (pout->pll_vco_div_ref >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_DIV_REF2, data); + + data = pout->pll_kvco_div_ref; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF1, data); + data = (pout->pll_kvco_div_ref >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_DIV_REF2, data); + + data = pout->pll_misc1; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_MISC1, data); + + data = pin->pll_ie_trim; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IE_TRIM, data); + + data = pin->pll_ip_trim; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IP_TRIM, data); + + data = ((pin->pll_cpmset_cur << 3) | pin->pll_cpcset_cur); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CP_SET_CUR, data); + + data = ((pin->pll_icpcset_p << 3) | pin->pll_icpcset_m); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPCSET, data); + + data = ((pin->pll_icpmset_p << 3) | pin->pll_icpcset_m); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICPMSET, data); + + data = ((pin->pll_icpmset << 3) | pin->pll_icpcset); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_ICP_SET, data); + + data = ((pdb->in.pll_lpf_cap2 << 4) | pdb->in.pll_lpf_cap1); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF1, data); + + data = pin->pll_iptat_trim; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_IPTAT_TRIM, data); + + data = (pdb->in.pll_c3ctrl | (pdb->in.pll_r3ctrl << 4)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_CRCTRL, data); +} + +static void pll_db_commit_8996(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_input *pin = &pdb->in; + struct dsi_pll_output *pout = &pdb->out; + char data; + + data = pout->cmn_ldo_cntrl; + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_LDO_CNTRL, data); + + pll_db_commit_common(pll, pdb); + + /* de assert pll start and apply pll sw reset */ + /* stop pll */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_PLL_CNTRL, 0); + + /* pll sw reset */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0x20); + wmb(); /* make sure register committed */ + udelay(10); + + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_1, 0); + wmb(); /* make sure register committed */ + + data = pdb->in.dsiclk_sel; /* set dsiclk_sel = 1 */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG1, data); + + data = 0xff; /* data, clk, pll normal operation */ + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CTRL_0, data); + + /* confgiure the frequency dependent pll registers */ + data = pout->dec_start; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DEC_START, data); + + data = pout->div_frac_start; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START1, data); + data = (pout->div_frac_start >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START2, data); + data = (pout->div_frac_start >> 16); + data &= 0x0f; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_DIV_FRAC_START3, data); + + data = pout->plllock_cmp; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP1, data); + data = (pout->plllock_cmp >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP2, data); + data = (pout->plllock_cmp >> 16); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP3, data); + + data = ((pin->plllock_cnt << 1) | (pin->plllock_rng << 3)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLLLOCK_CMP_EN, data); + + data = pout->pll_vco_count; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT1, data); + data = (pout->pll_vco_count >> 8); + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_COUNT2, data); + + data = pout->pll_kvco_count; + data &= 0x0ff; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT1, data); + data = (pout->pll_kvco_count >> 8); + data &= 0x03; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_KVCO_COUNT2, data); + + /* + * tx_band = pll_postdiv + * 0: divided by 1 <== for now + * 1: divided by 2 + * 2: divided by 4 + * 3: divided by 8 + */ + data = (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PLL_LPF2_POSTDIV, data); + + data = (pout->pll_n1div | (pout->pll_n2div << 4)); + MDSS_PLL_REG_W(pll_base, DSIPHY_CMN_CLK_CFG0, data); + + if (pll->ssc_en) + pll_db_commit_ssc(pll, pdb); + + wmb(); /* make sure register committed */ +} + +/* + * pll_source_finding: + * Both GLBL_TEST_CTRL and CLKBUFLR_EN are configured + * at mdss_dsi_8996_phy_config() + */ +static int pll_source_finding(struct mdss_pll_resources *pll) +{ + u32 clk_buf_en; + u32 glbl_test_ctrl; + + glbl_test_ctrl = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_CMN_GLBL_TEST_CTRL); + clk_buf_en = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_CLKBUFLR_EN); + + glbl_test_ctrl &= BIT(2); + glbl_test_ctrl >>= 2; + + pr_debug("%s: pll=%d clk_buf_en=%x glbl_test_ctrl=%x\n", + __func__, pll->index, clk_buf_en, glbl_test_ctrl); + + clk_buf_en &= (PLL_OUTPUT_RIGHT | PLL_OUTPUT_LEFT); + + if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) && + (clk_buf_en == PLL_OUTPUT_BOTH)) + return PLL_MASTER; + + if ((glbl_test_ctrl == PLL_SOURCE_FROM_RIGHT) && + (clk_buf_en == PLL_OUTPUT_NONE)) + return PLL_SLAVE; + + if ((glbl_test_ctrl == PLL_SOURCE_FROM_LEFT) && + (clk_buf_en == PLL_OUTPUT_RIGHT)) + return PLL_STANDALONE; + + pr_debug("%s: Error pll setup, clk_buf_en=%x glbl_test_ctrl=%x\n", + __func__, clk_buf_en, glbl_test_ctrl); + + return PLL_UNKNOWN; +} + +static void pll_source_setup(struct mdss_pll_resources *pll) +{ + int status; + struct dsi_pll_db *pdb = (struct dsi_pll_db *)pll->priv; + struct mdss_pll_resources *other; + + if (pdb->source_setup_done) + return; + + pdb->source_setup_done++; + + status = pll_source_finding(pll); + + if (status == PLL_STANDALONE || status == PLL_UNKNOWN) + return; + + other = pdb->next->pll; + if (!other) + return; + + pr_debug("%s: status=%d pll=%d other=%d\n", __func__, + status, pll->index, other->index); + + if (status == PLL_MASTER) + pll->slave = other; + else + other->slave = pll; +} + +int pll_vco_set_rate_8996(struct clk *c, unsigned long rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + struct mdss_pll_resources *slave; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; + if (!pdb) { + pr_err("No prov found\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi plla=%d\n", pll->index); + return rc; + } + + pll_source_setup(pll); + + pr_debug("%s: ndx=%d base=%p rate=%lu slave=%p\n", __func__, + pll->index, pll->pll_base, rate, pll->slave); + + pll->vco_current_rate = rate; + pll->vco_ref_clk_rate = vco->ref_clk_rate; + + mdss_dsi_pll_8996_input_init(pll, pdb); + + pll_8996_dec_frac_calc(pll, pdb); + + if (pll->ssc_en) + pll_8996_ssc_calc(pll, pdb); + + pll_8996_calc_vco_count(pdb, pll->vco_current_rate, + pll->vco_ref_clk_rate); + + /* commit slave if split display is enabled */ + slave = pll->slave; + if (slave) + pll_db_commit_8996(slave, pdb); + + /* commit master itself */ + pll_db_commit_8996(pll, pdb); + + mdss_pll_resource_enable(pll, false); + + return rc; +} + +static void shadow_pll_dynamic_refresh_8996(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + struct dsi_pll_output *pout = &pdb->out; + + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL20, + DSIPHY_CMN_CTRL_0, DSIPHY_PLL_SYSCLK_EN_RESET, + 0xFF, 0x0); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL21, + DSIPHY_PLL_DEC_START, DSIPHY_PLL_DIV_FRAC_START1, + pout->dec_start, (pout->div_frac_start & 0x0FF)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL22, + DSIPHY_PLL_DIV_FRAC_START2, DSIPHY_PLL_DIV_FRAC_START3, + ((pout->div_frac_start >> 8) & 0x0FF), + ((pout->div_frac_start >> 16) & 0x0F)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL23, + DSIPHY_PLL_PLLLOCK_CMP1, DSIPHY_PLL_PLLLOCK_CMP2, + (pout->plllock_cmp & 0x0FF), + ((pout->plllock_cmp >> 8) & 0x0FF)); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL24, + DSIPHY_PLL_PLLLOCK_CMP3, DSIPHY_PLL_PLL_VCO_TUNE, + ((pout->plllock_cmp >> 16) & 0x03), + (pll->cache_pll_trim_codes[1] | BIT(7))); /* VCO tune*/ + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL25, + DSIPHY_PLL_KVCO_CODE, DSIPHY_PLL_RESETSM_CNTRL, + (pll->cache_pll_trim_codes[0] | BIT(5)), 0x38); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL26, + DSIPHY_PLL_PLL_LPF2_POSTDIV, DSIPHY_CMN_PLL_CNTRL, + (((pout->pll_postdiv - 1) << 4) | pdb->in.pll_lpf_res1), 0x01); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL27, + DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL, + 0x01, 0x01); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL28, + DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL, + 0x01, 0x01); + MDSS_DYN_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_CTRL29, + DSIPHY_CMN_PLL_CNTRL, DSIPHY_CMN_PLL_CNTRL, + 0x01, 0x01); + MDSS_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR, 0x0000001E); + MDSS_PLL_REG_W(pll->dyn_pll_base, + DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2, 0x001FFE00); + + /* + * Ensure all the dynamic refresh registers are written before + * dynamic refresh to change the fps is triggered + */ + wmb(); +} + +int shadow_pll_vco_set_rate_8996(struct clk *c, unsigned long rate) +{ + int rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + struct dsi_pll_db *pdb; + s64 vco_clk_rate = (s64)rate; + + if (!pll) { + pr_err("PLL data not found\n"); + return -EINVAL; + } + + pdb = pll->priv; + if (!pdb) { + pr_err("No priv data found\n"); + return -EINVAL; + } + + rc = mdss_pll_read_stored_trim_codes(pll, vco_clk_rate); + if (rc) { + pr_err("cannot find pll codes rate=%lld\n", vco_clk_rate); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi plla=%d\n", pll->index); + return rc; + } + + pr_debug("%s: ndx=%d base=%p rate=%lu\n", __func__, + pll->index, pll->pll_base, rate); + + pll->vco_current_rate = rate; + pll->vco_ref_clk_rate = vco->ref_clk_rate; + + mdss_dsi_pll_8996_input_init(pll, pdb); + + pll_8996_dec_frac_calc(pll, pdb); + + pll_8996_calc_vco_count(pdb, pll->vco_current_rate, + pll->vco_ref_clk_rate); + + shadow_pll_dynamic_refresh_8996(pll, pdb); + + rc = mdss_pll_resource_enable(pll, false); + if (rc) { + pr_err("Failed to enable mdss dsi plla=%d\n", pll->index); + return rc; + } + + return rc; +} + +unsigned long pll_vco_get_rate_8996(struct clk *c) +{ + u64 vco_rate, multiplier = BIT(20); + s32 div_frac_start; + u32 dec_start; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + u64 ref_clk = vco->ref_clk_rate; + int rc; + struct mdss_pll_resources *pll = vco->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return rc; + } + + dec_start = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DEC_START); + dec_start &= 0x0ff; + pr_debug("dec_start = 0x%x\n", dec_start); + + div_frac_start = (MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DIV_FRAC_START3) & 0x0f) << 16; + div_frac_start |= (MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DIV_FRAC_START2) & 0x0ff) << 8; + div_frac_start |= MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_DIV_FRAC_START1) & 0x0ff; + pr_debug("div_frac_start = 0x%x\n", div_frac_start); + + vco_rate = ref_clk * dec_start; + vco_rate += ((ref_clk * div_frac_start) / multiplier); + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(pll, false); + + return (unsigned long)vco_rate; +} + +long pll_vco_round_rate_8996(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + u32 div; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + + div = vco->min_rate / rate; + if (div > 15) { + /* rate < 86.67 Mhz */ + pr_err("rate=%lu NOT supportted\n", rate); + return -EINVAL; + } + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + return rrate; +} + +enum handoff pll_vco_handoff_8996(struct clk *c) +{ + int rc; + enum handoff ret = HANDOFF_DISABLED_CLK; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + if (is_gdsc_disabled(pll)) + return HANDOFF_DISABLED_CLK; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return ret; + } + + if (pll_is_pll_locked_8996(pll)) { + pll->handoff_resources = true; + pll->pll_on = true; + c->rate = pll_vco_get_rate_8996(c); + ret = HANDOFF_ENABLED_CLK; + } else { + mdss_pll_resource_enable(pll, false); + } + + return ret; +} + +enum handoff shadow_pll_vco_handoff_8996(struct clk *c) +{ + return HANDOFF_DISABLED_CLK; +} + +int pll_vco_prepare_8996(struct clk *c) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("ndx=%d Failed to enable mdss dsi pll resources\n", + pll->index); + return rc; + } + + if ((pll->vco_cached_rate != 0) + && (pll->vco_cached_rate == c->rate)) { + rc = c->ops->set_rate(c, pll->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, pll->index); + mdss_pll_resource_enable(pll, false); + goto error; + } + } + + rc = dsi_pll_enable(c); + + if (rc) { + mdss_pll_resource_enable(pll, false); + pr_err("ndx=%d failed to enable dsi pll\n", pll->index); + } + +error: + return rc; +} + +void pll_vco_unprepare_8996(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return; + } + + pll->vco_cached_rate = c->rate; + dsi_pll_disable(c); +} diff --git a/techpack/display/pll/dsi_pll_util.c b/techpack/display/pll/dsi_pll_util.c new file mode 100644 index 0000000000000000000000000000000000000000..0769bf3061cbc98bfd616fe62612efb13425479f --- /dev/null +++ b/techpack/display/pll/dsi_pll_util.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <linux/delay.h> +#include <linux/clk/msm-clock-generic.h> + +#include "pll_drv.h" +#include "dsi_pll.h" + +#define DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG (0x0) +#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG (0x0004) +#define DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG (0x0008) +#define DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG (0x000C) +#define DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG (0x0010) +#define DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG (0x0014) +#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG (0x0024) +#define DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG (0x0028) +#define DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG (0x002C) +#define DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG (0x0030) +#define DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG (0x0034) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0 (0x0038) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1 (0x003C) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2 (0x0040) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3 (0x0044) +#define DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4 (0x0048) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0 (0x006C) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG2 (0x0074) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3 (0x0078) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4 (0x007C) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG5 (0x0080) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6 (0x0084) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7 (0x0088) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8 (0x008C) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9 (0x0090) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10 (0x0094) +#define DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11 (0x0098) +#define DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG (0x009C) +#define DSI_PHY_PLL_UNIPHY_PLL_STATUS (0x00C0) + +#define DSI_PLL_POLL_DELAY_US 50 +#define DSI_PLL_POLL_TIMEOUT_US 500 + +int set_byte_mux_sel(struct mux_clk *clk, int sel) +{ + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + pr_debug("byte mux set to %s mode\n", sel ? "indirect" : "direct"); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG, (sel << 1)); + + return 0; +} + +int get_byte_mux_sel(struct mux_clk *clk) +{ + int mux_mode, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + mux_mode = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_VREG_CFG) & BIT(1); + + pr_debug("byte mux mode = %s\n", mux_mode ? "indirect" : "direct"); + mdss_pll_resource_enable(dsi_pll_res, false); + + return !!mux_mode; +} + +int dsi_pll_div_prepare(struct clk *c) +{ + struct div_clk *div = to_div_clk(c); + /* Restore the divider's value */ + return div->ops->set_div(div, div->data.div); +} + +int dsi_pll_mux_prepare(struct clk *c) +{ + struct mux_clk *mux = to_mux_clk(c); + int i, rc, sel = 0; + struct mdss_pll_resources *dsi_pll_res = mux->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + for (i = 0; i < mux->num_parents; i++) + if (mux->parents[i].src == c->parent) { + sel = mux->parents[i].sel; + break; + } + + if (i == mux->num_parents) { + pr_err("Failed to select the parent clock\n"); + rc = -EINVAL; + goto error; + } + + /* Restore the mux source select value */ + rc = mux->ops->set_mux_sel(mux, sel); + +error: + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int fixed_4div_set_div(struct div_clk *clk, int div) +{ + int rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG, (div - 1)); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int fixed_4div_get_div(struct div_clk *clk) +{ + int div = 0, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG); + + mdss_pll_resource_enable(dsi_pll_res, false); + return div + 1; +} + +int digital_set_div(struct div_clk *clk, int div) +{ + int rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, (div - 1)); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int digital_get_div(struct div_clk *clk) +{ + int div = 0, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG); + + mdss_pll_resource_enable(dsi_pll_res, false); + return div + 1; +} + +int analog_set_div(struct div_clk *clk, int div) +{ + int rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, div - 1); + + mdss_pll_resource_enable(dsi_pll_res, false); + return rc; +} + +int analog_get_div(struct div_clk *clk) +{ + int div = 0, rc; + struct mdss_pll_resources *dsi_pll_res = clk->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(clk->priv, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG) + 1; + + mdss_pll_resource_enable(dsi_pll_res, false); + + return div; +} + +int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res) +{ + u32 status; + int pll_locked; + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((dsi_pll_res->pll_base + + DSI_PHY_PLL_UNIPHY_PLL_STATUS), + status, + ((status & BIT(0)) == 1), + DSI_PLL_POLL_DELAY_US, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_debug("DSI PLL status=%x failed to Lock\n", status); + pll_locked = 0; + } else { + pll_locked = 1; + } + + return pll_locked; +} + +int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate) +{ + s64 vco_clk_rate = rate; + s32 rem; + s64 refclk_cfg, frac_n_mode, ref_doubler_en_b; + s64 ref_clk_to_pll, div_fbx1000, frac_n_value; + s64 sdm_cfg0, sdm_cfg1, sdm_cfg2, sdm_cfg3; + s64 gen_vco_clk, cal_cfg10, cal_cfg11; + u32 res; + int i; + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + /* Configure the Loop filter resistance */ + for (i = 0; i < vco->lpfr_lut_size; i++) + if (vco_clk_rate <= vco->lpfr_lut[i].vco_rate) + break; + if (i == vco->lpfr_lut_size) { + pr_err("unable to get loop filter resistance. vco=%ld\n", rate); + return -EINVAL; + } + res = vco->lpfr_lut[i].r; + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LPFR_CFG, res); + + /* Loop filter capacitance values : c1 and c2 */ + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LPFC1_CFG, 0x70); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LPFC2_CFG, 0x15); + + div_s64_rem(vco_clk_rate, vco->ref_clk_rate, &rem); + if (rem) { + refclk_cfg = 0x1; + frac_n_mode = 1; + ref_doubler_en_b = 0; + } else { + refclk_cfg = 0x0; + frac_n_mode = 0; + ref_doubler_en_b = 1; + } + + pr_debug("refclk_cfg = %lld\n", refclk_cfg); + + ref_clk_to_pll = ((vco->ref_clk_rate * 2 * (refclk_cfg)) + + (ref_doubler_en_b * vco->ref_clk_rate)); + div_fbx1000 = div_s64((vco_clk_rate * 1000), ref_clk_to_pll); + + div_s64_rem(div_fbx1000, 1000, &rem); + frac_n_value = div_s64((rem * (1 << 16)), 1000); + gen_vco_clk = div_s64(div_fbx1000 * ref_clk_to_pll, 1000); + + pr_debug("ref_clk_to_pll = %lld\n", ref_clk_to_pll); + pr_debug("div_fb = %lld\n", div_fbx1000); + pr_debug("frac_n_value = %lld\n", frac_n_value); + + pr_debug("Generated VCO Clock: %lld\n", gen_vco_clk); + rem = 0; + if (frac_n_mode) { + sdm_cfg0 = (0x0 << 5); + sdm_cfg0 |= (0x0 & 0x3f); + sdm_cfg1 = (div_s64(div_fbx1000, 1000) & 0x3f) - 1; + sdm_cfg3 = div_s64_rem(frac_n_value, 256, &rem); + sdm_cfg2 = rem; + } else { + sdm_cfg0 = (0x1 << 5); + sdm_cfg0 |= (div_s64(div_fbx1000, 1000) & 0x3f) - 1; + sdm_cfg1 = (0x0 & 0x3f); + sdm_cfg2 = 0; + sdm_cfg3 = 0; + } + + pr_debug("sdm_cfg0=%lld\n", sdm_cfg0); + pr_debug("sdm_cfg1=%lld\n", sdm_cfg1); + pr_debug("sdm_cfg2=%lld\n", sdm_cfg2); + pr_debug("sdm_cfg3=%lld\n", sdm_cfg3); + + cal_cfg11 = div_s64_rem(gen_vco_clk, 256 * 1000000, &rem); + cal_cfg10 = rem / 1000000; + pr_debug("cal_cfg10=%lld, cal_cfg11=%lld\n", cal_cfg10, cal_cfg11); + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CHGPUMP_CFG, 0x02); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG3, 0x2b); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG4, 0x66); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d); + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1, (u32)(sdm_cfg1 & 0xff)); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2, (u32)(sdm_cfg2 & 0xff)); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3, (u32)(sdm_cfg3 & 0xff)); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00); + + /* Add hardware recommended delay for correct PLL configuration */ + if (dsi_pll_res->vco_delay) + udelay(dsi_pll_res->vco_delay); + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG, (u32)refclk_cfg); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_PWRGEN_CFG, 0x00); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x71); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0, (u32)sdm_cfg0); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x30); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x00); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG10, (u32)(cal_cfg10 & 0xff)); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_CAL_CFG11, (u32)(cal_cfg11 & 0xff)); + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_EFUSE_CFG, 0x20); + + return 0; +} + +unsigned long vco_get_rate(struct clk *c) +{ + u32 sdm0, doubler, sdm_byp_div; + u64 vco_rate; + u32 sdm_dc_off, sdm_freq_seed, sdm2, sdm3; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + u64 ref_clk = vco->ref_clk_rate; + int rc; + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* Check to see if the ref clk doubler is enabled */ + doubler = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_REFCLK_CFG) & BIT(0); + ref_clk += (doubler * vco->ref_clk_rate); + + /* see if it is integer mode or sdm mode */ + sdm0 = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0); + if (sdm0 & BIT(6)) { + /* integer mode */ + sdm_byp_div = (MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG0) & 0x3f) + 1; + vco_rate = ref_clk * sdm_byp_div; + } else { + /* sdm mode */ + sdm_dc_off = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG1) & 0xFF; + pr_debug("sdm_dc_off = %d\n", sdm_dc_off); + sdm2 = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG2) & 0xFF; + sdm3 = MDSS_PLL_REG_R(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_SDM_CFG3) & 0xFF; + sdm_freq_seed = (sdm3 << 8) | sdm2; + pr_debug("sdm_freq_seed = %d\n", sdm_freq_seed); + + vco_rate = (ref_clk * (sdm_dc_off + 1)) + + mult_frac(ref_clk, sdm_freq_seed, BIT(16)); + pr_debug("vco rate = %lld\n", vco_rate); + } + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(dsi_pll_res, false); + + return (unsigned long)vco_rate; +} + +static int dsi_pll_enable(struct clk *c) +{ + int i, rc; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < vco->pll_en_seq_cnt; i++) { + rc = vco->pll_enable_seqs[i](dsi_pll_res); + pr_debug("DSI PLL %s after sequence #%d\n", + rc ? "unlocked" : "locked", i + 1); + if (!rc) + break; + } + + if (rc) { + mdss_pll_resource_enable(dsi_pll_res, false); + pr_err("DSI PLL failed to lock\n"); + } + dsi_pll_res->pll_on = true; + + return rc; +} + +static void dsi_pll_disable(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res->pll_on && + mdss_pll_resource_enable(dsi_pll_res, true)) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return; + } + + dsi_pll_res->handoff_resources = false; + + MDSS_PLL_REG_W(dsi_pll_res->pll_base, + DSI_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x00); + + mdss_pll_resource_enable(dsi_pll_res, false); + dsi_pll_res->pll_on = false; + + pr_debug("DSI PLL Disabled\n"); +} + +long vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + return rrate; +} + +enum handoff vco_handoff(struct clk *c) +{ + int rc; + enum handoff ret = HANDOFF_DISABLED_CLK; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (is_gdsc_disabled(dsi_pll_res)) + return HANDOFF_DISABLED_CLK; + + rc = mdss_pll_resource_enable(dsi_pll_res, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return ret; + } + + if (dsi_pll_lock_status(dsi_pll_res)) { + dsi_pll_res->handoff_resources = true; + dsi_pll_res->pll_on = true; + c->rate = vco_get_rate(c); + ret = HANDOFF_ENABLED_CLK; + } else { + mdss_pll_resource_enable(dsi_pll_res, false); + } + + return ret; +} + +int vco_prepare(struct clk *c) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res) { + pr_err("Dsi pll resources are not available\n"); + return -EINVAL; + } + + if ((dsi_pll_res->vco_cached_rate != 0) + && (dsi_pll_res->vco_cached_rate == c->rate)) { + rc = c->ops->set_rate(c, dsi_pll_res->vco_cached_rate); + if (rc) { + pr_err("vco_set_rate failed. rc=%d\n", rc); + goto error; + } + } + + rc = dsi_pll_enable(c); + +error: + return rc; +} + +void vco_unprepare(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *dsi_pll_res = vco->priv; + + if (!dsi_pll_res) { + pr_err("Dsi pll resources are not available\n"); + return; + } + + dsi_pll_res->vco_cached_rate = c->rate; + dsi_pll_disable(c); +} + diff --git a/techpack/display/pll/edp_pll_28hpm.c b/techpack/display/pll/edp_pll_28hpm.c new file mode 100644 index 0000000000000000000000000000000000000000..b2053ec891f88e83685c082b07feb106ed478e91 --- /dev/null +++ b/techpack/display/pll/edp_pll_28hpm.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/iopoll.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> + +#include <dt-bindings/clock/msm-clocks-8974.h> + +#include "pll_drv.h" +#include "edp_pll.h" + +#define EDP_PHY_PLL_UNIPHY_PLL_REFCLK_CFG (0x0) +#define EDP_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG (0x0004) +#define EDP_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG (0x000C) +#define EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG (0x0020) +#define EDP_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG (0x0024) +#define EDP_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG (0x0028) +#define EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG0 (0x0038) +#define EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG1 (0x003C) +#define EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG2 (0x0040) +#define EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG3 (0x0044) +#define EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG4 (0x0048) +#define EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG0 (0x004C) +#define EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG1 (0x0050) +#define EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG2 (0x0054) +#define EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG3 (0x0058) +#define EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG2 (0x0064) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG0 (0x006C) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG2 (0x0074) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG6 (0x0084) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG7 (0x0088) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG8 (0x008C) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG9 (0x0090) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG10 (0x0094) +#define EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG11 (0x0098) +#define EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG0 (0x005C) +#define EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG1 (0x0060) + +#define EDP_PLL_POLL_DELAY_US 50 +#define EDP_PLL_POLL_TIMEOUT_US 500 + +static const struct clk_ops edp_mainlink_clk_src_ops; +static struct clk_div_ops fixed_5div_ops; /* null ops */ +static const struct clk_ops edp_pixel_clk_ops; + +static inline struct edp_pll_vco_clk *to_edp_vco_clk(struct clk *clk) +{ + return container_of(clk, struct edp_pll_vco_clk, c); +} + +int edp_div_prepare(struct clk *c) +{ + struct div_clk *div = to_div_clk(c); + /* Restore the divider's value */ + return div->ops->set_div(div, div->data.div); +} + +static int edp_vco_set_rate(struct clk *c, unsigned long vco_rate) +{ + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + struct mdss_pll_resources *edp_pll_res = vco->priv; + int rc; + + pr_debug("vco_rate=%d\n", (int)vco_rate); + + rc = mdss_pll_resource_enable(edp_pll_res, true); + if (rc) { + pr_err("failed to enable edp pll res rc=%d\n", rc); + rc = -EINVAL; + } + + if (vco_rate == 810000000) { + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_VCOLPF_CFG, 0x18); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_REFCLK_CFG, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG0, 0x36); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG1, 0x69); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG2, 0xff); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG3, 0x2f); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG0, 0x80); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG1, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG2, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG3, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x5a); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x0); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x0); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG10, 0x2a); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG11, 0x3); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG1, 0x1a); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, 0x00); + } else if (vco_rate == 1350000000) { + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG2, 0x0d); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG0, 0x36); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG1, 0x62); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG2, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG3, 0x28); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG0, 0x80); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG1, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG2, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_SSC_CFG3, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG0, 0x12); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG6, 0x5a); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG7, 0x0); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG9, 0x0); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG10, 0x46); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_CAL_CFG11, 0x5); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_LKDET_CFG1, 0x1a); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_POSTDIV1_CFG, 0x00); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_POSTDIV3_CFG, 0x00); + } else { + pr_err("rate=%d is NOT supported\n", (int)vco_rate); + vco_rate = 0; + rc = -EINVAL; + } + + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01); + udelay(100); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05); + udelay(100); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07); + udelay(100); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f); + udelay(100); + mdss_pll_resource_enable(edp_pll_res, false); + + vco->rate = vco_rate; + + return rc; +} + +static int edp_pll_ready_poll(struct mdss_pll_resources *edp_pll_res) +{ + int cnt; + u32 status; + + cnt = 100; + while (cnt--) { + udelay(100); + status = MDSS_PLL_REG_R(edp_pll_res->pll_base, 0xc0); + status &= 0x01; + if (status) + break; + } + pr_debug("cnt=%d status=%d\n", cnt, (int)status); + + if (status) + return 1; + + return 0; +} + +static int edp_vco_enable(struct clk *c) +{ + int i, ready; + int rc; + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + struct mdss_pll_resources *edp_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(edp_pll_res, true); + if (rc) { + pr_err("edp pll resources not available\n"); + return rc; + } + + for (i = 0; i < 3; i++) { + ready = edp_pll_ready_poll(edp_pll_res); + if (ready) + break; + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x01); + udelay(100); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x05); + udelay(100); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x07); + udelay(100); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG, 0x0f); + udelay(100); + } + + if (ready) { + pr_debug("EDP PLL lock success\n"); + edp_pll_res->pll_on = true; + rc = 0; + } else { + pr_err("EDP PLL failed to lock\n"); + mdss_pll_resource_enable(edp_pll_res, false); + rc = -EINVAL; + } + + return rc; +} + +static void edp_vco_disable(struct clk *c) +{ + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + struct mdss_pll_resources *edp_pll_res = vco->priv; + + if (!edp_pll_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!edp_pll_res->pll_on && + mdss_pll_resource_enable(edp_pll_res, true)) { + pr_err("edp pll resources not available\n"); + return; + } + + MDSS_PLL_REG_W(edp_pll_res->pll_base, 0x20, 0x00); + + edp_pll_res->handoff_resources = false; + edp_pll_res->pll_on = false; + + mdss_pll_resource_enable(edp_pll_res, false); + + pr_debug("EDP PLL Disabled\n"); +} + +static unsigned long edp_vco_get_rate(struct clk *c) +{ + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + struct mdss_pll_resources *edp_pll_res = vco->priv; + u32 pll_status, div2; + int rc; + + if (is_gdsc_disabled(edp_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(edp_pll_res, true); + if (rc) { + pr_err("edp pll resources not available\n"); + return rc; + } + + if (vco->rate == 0) { + pll_status = MDSS_PLL_REG_R(edp_pll_res->pll_base, 0xc0); + if (pll_status & 0x01) { + div2 = MDSS_PLL_REG_R(edp_pll_res->pll_base, 0x24); + if (div2 & 0x01) + vco->rate = 1350000000; + else + vco->rate = 810000000; + } + } + mdss_pll_resource_enable(edp_pll_res, false); + + pr_debug("rate=%d\n", (int)vco->rate); + + return vco->rate; +} + +static long edp_vco_round_rate(struct clk *c, unsigned long rate) +{ + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + unsigned long rrate = -ENOENT; + unsigned long *lp; + + lp = vco->rate_list; + while (*lp) { + rrate = *lp; + if (rate <= rrate) + break; + lp++; + } + + pr_debug("rrate=%d\n", (int)rrate); + + return rrate; +} + +static int edp_vco_prepare(struct clk *c) +{ + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + + pr_debug("rate=%d\n", (int)vco->rate); + + return edp_vco_set_rate(c, vco->rate); +} + +static void edp_vco_unprepare(struct clk *c) +{ + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + + pr_debug("rate=%d\n", (int)vco->rate); + + edp_vco_disable(c); +} + +static int edp_pll_lock_status(struct mdss_pll_resources *edp_pll_res) +{ + u32 status; + int pll_locked = 0; + int rc; + + rc = mdss_pll_resource_enable(edp_pll_res, true); + if (rc) { + pr_err("edp pll resources not available\n"); + return rc; + } + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((edp_pll_res->pll_base + 0xc0), + status, ((status & BIT(0)) == 1), + EDP_PLL_POLL_DELAY_US, + EDP_PLL_POLL_TIMEOUT_US)) { + pr_debug("EDP PLL status=%x failed to Lock\n", status); + pll_locked = 0; + } else { + pll_locked = 1; + } + mdss_pll_resource_enable(edp_pll_res, false); + + return pll_locked; +} + +static enum handoff edp_vco_handoff(struct clk *c) +{ + enum handoff ret = HANDOFF_DISABLED_CLK; + struct edp_pll_vco_clk *vco = to_edp_vco_clk(c); + struct mdss_pll_resources *edp_pll_res = vco->priv; + + if (is_gdsc_disabled(edp_pll_res)) + return HANDOFF_DISABLED_CLK; + + if (mdss_pll_resource_enable(edp_pll_res, true)) { + pr_err("edp pll resources not available\n"); + return ret; + } + + edp_pll_res->handoff_resources = true; + + if (edp_pll_lock_status(edp_pll_res)) { + c->rate = edp_vco_get_rate(c); + edp_pll_res->pll_on = true; + ret = HANDOFF_ENABLED_CLK; + } else { + edp_pll_res->handoff_resources = false; + mdss_pll_resource_enable(edp_pll_res, false); + } + + pr_debug("done, ret=%d\n", ret); + return ret; +} + +static unsigned long edp_vco_rate_list[] = { + 810000000, 1350000000, 0}; + +struct const clk_ops edp_vco_clk_ops = { + .enable = edp_vco_enable, + .set_rate = edp_vco_set_rate, + .get_rate = edp_vco_get_rate, + .round_rate = edp_vco_round_rate, + .prepare = edp_vco_prepare, + .unprepare = edp_vco_unprepare, + .handoff = edp_vco_handoff, +}; + +struct edp_pll_vco_clk edp_vco_clk = { + .ref_clk_rate = 19200000, + .rate = 0, + .rate_list = edp_vco_rate_list, + .c = { + .dbg_name = "edp_vco_clk", + .ops = &edp_vco_clk_ops, + CLK_INIT(edp_vco_clk.c), + }, +}; + +static unsigned long edp_mainlink_get_rate(struct clk *c) +{ + struct div_clk *mclk = to_div_clk(c); + struct clk *pclk; + unsigned long rate = 0; + + pclk = clk_get_parent(c); + + if (pclk && pclk->ops->get_rate) { + rate = pclk->ops->get_rate(pclk); + rate /= mclk->data.div; + } + + pr_debug("rate=%d div=%d\n", (int)rate, mclk->data.div); + + return rate; +} + + +struct div_clk edp_mainlink_clk_src = { + .ops = &fixed_5div_ops, + .data = { + .div = 5, + .min_div = 5, + .max_div = 5, + }, + .c = { + .parent = &edp_vco_clk.c, + .dbg_name = "edp_mainlink_clk_src", + .ops = &edp_mainlink_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(edp_mainlink_clk_src.c), + } +}; + +/* + * this rate is from pll to clock controller + * output from pll to CC has two possibilities + * 1: if mainlink rate is 270M, then 675M + * 2: if mainlink rate is 162M, then 810M + */ +static int edp_pixel_set_div(struct div_clk *clk, int div) +{ + int rc; + struct mdss_pll_resources *edp_pll_res = clk->priv; + + rc = mdss_pll_resource_enable(edp_pll_res, true); + if (rc) { + pr_err("edp pll resources not available\n"); + return rc; + } + + pr_debug("div=%d\n", div); + MDSS_PLL_REG_W(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG, (div - 1)); + mdss_pll_resource_enable(edp_pll_res, false); + + return 0; +} + +static int edp_pixel_get_div(struct div_clk *clk) +{ + int div = 0; + int rc; + struct mdss_pll_resources *edp_pll_res = clk->priv; + + if (is_gdsc_disabled(edp_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(edp_pll_res, true); + if (rc) { + pr_err("edp pll resources not available\n"); + return rc; + } + + div = MDSS_PLL_REG_R(edp_pll_res->pll_base, + EDP_PHY_PLL_UNIPHY_PLL_POSTDIV2_CFG); + mdss_pll_resource_enable(edp_pll_res, false); + div &= 0x01; + pr_debug("div=%d\n", div); + return div + 1; +} + +static struct clk_div_ops edp_pixel_ops = { + .set_div = edp_pixel_set_div, + .get_div = edp_pixel_get_div, +}; + +struct div_clk edp_pixel_clk_src = { + .data = { + .max_div = 2, + .min_div = 1, + }, + .ops = &edp_pixel_ops, + .c = { + .parent = &edp_vco_clk.c, + .dbg_name = "edp_pixel_clk_src", + .ops = &edp_pixel_clk_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(edp_pixel_clk_src.c), + }, +}; + +static struct clk_lookup mdss_edp_pllcc_8974[] = { + CLK_LOOKUP("edp_pixel_src", edp_pixel_clk_src.c, + "fd8c0000.qcom,mmsscc-mdss"), + CLK_LOOKUP("edp_mainlink_src", edp_mainlink_clk_src.c, + "fd8c0000.qcom,mmsscc-mdss"), +}; + +int edp_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP; + + /* Set client data to div and vco clocks */ + edp_pixel_clk_src.priv = pll_res; + edp_mainlink_clk_src.priv = pll_res; + edp_vco_clk.priv = pll_res; + + /* Set clock operation for mainlink and pixel clock */ + edp_mainlink_clk_src_ops = clk_ops_div; + edp_mainlink_clk_src_ops.get_parent = clk_get_parent; + edp_mainlink_clk_src_ops.get_rate = edp_mainlink_get_rate; + + edp_pixel_clk_ops = clk_ops_slave_div; + edp_pixel_clk_ops.prepare = edp_div_prepare; + + rc = of_msm_clock_register(pdev->dev.of_node, mdss_edp_pllcc_8974, + ARRAY_SIZE(mdss_edp_pllcc_8974)); + if (rc) { + pr_err("Clock register failed rc=%d\n", rc); + rc = -EPROBE_DEFER; + } + + return rc; +} diff --git a/techpack/display/pll/hdmi_pll.h b/techpack/display/pll/hdmi_pll.h new file mode 100644 index 0000000000000000000000000000000000000000..03f6fa20ea801565511871d111f3a688c9b72914 --- /dev/null +++ b/techpack/display/pll/hdmi_pll.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_HDMI_PLL_H +#define __MDSS_HDMI_PLL_H + +struct hdmi_pll_cfg { + unsigned long vco_rate; + u32 reg; +}; + +struct hdmi_pll_vco_clk { + struct clk_hw hw; + unsigned long rate; /* current vco rate */ + unsigned long min_rate; /* min vco rate */ + unsigned long max_rate; /* max vco rate */ + bool rate_set; + struct hdmi_pll_cfg *ip_seti; + struct hdmi_pll_cfg *cp_seti; + struct hdmi_pll_cfg *ip_setp; + struct hdmi_pll_cfg *cp_setp; + struct hdmi_pll_cfg *crctrl; + void *priv; + +}; + +static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk_hw(struct clk_hw *hw) +{ + return container_of(hw, struct hdmi_pll_vco_clk, hw); +} + +int hdmi_pll_clock_register_28lpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_20nm_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); + +int hdmi_8998_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); +#endif diff --git a/techpack/display/pll/hdmi_pll_20nm.c b/techpack/display/pll/hdmi_pll_20nm.c new file mode 100644 index 0000000000000000000000000000000000000000..847ddf261a8b8a3b08a4e9d79156d74f9e0e542b --- /dev/null +++ b/techpack/display/pll/hdmi_pll_20nm.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> +#include <dt-bindings/clock/msm-clocks-8994.h> + +#include "pll_drv.h" +#include "hdmi_pll.h" + +/* hdmi phy registers */ + +#define HDMI_PHY_CMD_SIZE 68 +#define HDMI_PHY_CLK_SIZE 97 + +/* Set to 1 for auto KVCO cal; set to 0 for fixed value */ +#define HDMI_PHY_AUTO_KVCO_CAL 1 + +/* PLL REGISTERS */ +#define QSERDES_COM_SYS_CLK_CTRL (0x000) +#define QSERDES_COM_PLL_VCOTAIL_EN (0x004) +#define QSERDES_COM_CMN_MODE (0x008) +#define QSERDES_COM_IE_TRIM (0x00C) +#define QSERDES_COM_IP_TRIM (0x010) +#define QSERDES_COM_PLL_CNTRL (0x014) +#define QSERDES_COM_PLL_PHSEL_CONTROL (0x018) +#define QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL (0x01C) +#define QSERDES_COM_PLL_PHSEL_DC (0x020) +#define QSERDES_COM_PLL_IP_SETI (0x024) +#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL (0x028) +#define QSERDES_COM_PLL_BKG_KVCO_CAL_EN (0x02C) +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x030) +#define QSERDES_COM_PLL_CP_SETI (0x034) +#define QSERDES_COM_PLL_IP_SETP (0x038) +#define QSERDES_COM_PLL_CP_SETP (0x03C) +#define QSERDES_COM_ATB_SEL1 (0x040) +#define QSERDES_COM_ATB_SEL2 (0x044) +#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND (0x048) +#define QSERDES_COM_RESETSM_CNTRL (0x04C) +#define QSERDES_COM_RESETSM_CNTRL2 (0x050) +#define QSERDES_COM_RESETSM_CNTRL3 (0x054) +#define QSERDES_COM_RESETSM_PLL_CAL_COUNT1 (0x058) +#define QSERDES_COM_RESETSM_PLL_CAL_COUNT2 (0x05C) +#define QSERDES_COM_DIV_REF1 (0x060) +#define QSERDES_COM_DIV_REF2 (0x064) +#define QSERDES_COM_KVCO_COUNT1 (0x068) +#define QSERDES_COM_KVCO_COUNT2 (0x06C) +#define QSERDES_COM_KVCO_CAL_CNTRL (0x070) +#define QSERDES_COM_KVCO_CODE (0x074) +#define QSERDES_COM_VREF_CFG1 (0x078) +#define QSERDES_COM_VREF_CFG2 (0x07C) +#define QSERDES_COM_VREF_CFG3 (0x080) +#define QSERDES_COM_VREF_CFG4 (0x084) +#define QSERDES_COM_VREF_CFG5 (0x088) +#define QSERDES_COM_VREF_CFG6 (0x08C) +#define QSERDES_COM_PLLLOCK_CMP1 (0x090) +#define QSERDES_COM_PLLLOCK_CMP2 (0x094) +#define QSERDES_COM_PLLLOCK_CMP3 (0x098) +#define QSERDES_COM_PLLLOCK_CMP_EN (0x09C) +#define QSERDES_COM_BGTC (0x0A0) +#define QSERDES_COM_PLL_TEST_UPDN (0x0A4) +#define QSERDES_COM_PLL_VCO_TUNE (0x0A8) +#define QSERDES_COM_DEC_START1 (0x0AC) +#define QSERDES_COM_PLL_AMP_OS (0x0B0) +#define QSERDES_COM_SSC_EN_CENTER (0x0B4) +#define QSERDES_COM_SSC_ADJ_PER1 (0x0B8) +#define QSERDES_COM_SSC_ADJ_PER2 (0x0BC) +#define QSERDES_COM_SSC_PER1 (0x0C0) +#define QSERDES_COM_SSC_PER2 (0x0C4) +#define QSERDES_COM_SSC_STEP_SIZE1 (0x0C8) +#define QSERDES_COM_SSC_STEP_SIZE2 (0x0CC) +#define QSERDES_COM_RES_CODE_UP (0x0D0) +#define QSERDES_COM_RES_CODE_DN (0x0D4) +#define QSERDES_COM_RES_CODE_UP_OFFSET (0x0D8) +#define QSERDES_COM_RES_CODE_DN_OFFSET (0x0DC) +#define QSERDES_COM_RES_CODE_START_SEG1 (0x0E0) +#define QSERDES_COM_RES_CODE_START_SEG2 (0x0E4) +#define QSERDES_COM_RES_CODE_CAL_CSR (0x0E8) +#define QSERDES_COM_RES_CODE (0x0EC) +#define QSERDES_COM_RES_TRIM_CONTROL (0x0F0) +#define QSERDES_COM_RES_TRIM_CONTROL2 (0x0F4) +#define QSERDES_COM_RES_TRIM_EN_VCOCALDONE (0x0F8) +#define QSERDES_COM_FAUX_EN (0x0FC) +#define QSERDES_COM_DIV_FRAC_START1 (0x100) +#define QSERDES_COM_DIV_FRAC_START2 (0x104) +#define QSERDES_COM_DIV_FRAC_START3 (0x108) +#define QSERDES_COM_DEC_START2 (0x10C) +#define QSERDES_COM_PLL_RXTXEPCLK_EN (0x110) +#define QSERDES_COM_PLL_CRCTRL (0x114) +#define QSERDES_COM_PLL_CLKEPDIV (0x118) +#define QSERDES_COM_PLL_FREQUPDATE (0x11C) +#define QSERDES_COM_PLL_BKGCAL_TRIM_UP (0x120) +#define QSERDES_COM_PLL_BKGCAL_TRIM_DN (0x124) +#define QSERDES_COM_PLL_BKGCAL_TRIM_MUX (0x128) +#define QSERDES_COM_PLL_BKGCAL_VREF_CFG (0x12C) +#define QSERDES_COM_PLL_BKGCAL_DIV_REF1 (0x130) +#define QSERDES_COM_PLL_BKGCAL_DIV_REF2 (0x134) +#define QSERDES_COM_MUXADDR (0x138) +#define QSERDES_COM_LOW_POWER_RO_CONTROL (0x13C) +#define QSERDES_COM_POST_DIVIDER_CONTROL (0x140) +#define QSERDES_COM_HR_OCLK2_DIVIDER (0x144) +#define QSERDES_COM_HR_OCLK3_DIVIDER (0x148) +#define QSERDES_COM_PLL_VCO_HIGH (0x14C) +#define QSERDES_COM_RESET_SM (0x150) +#define QSERDES_COM_MUXVAL (0x154) +#define QSERDES_COM_CORE_RES_CODE_DN (0x158) +#define QSERDES_COM_CORE_RES_CODE_UP (0x15C) +#define QSERDES_COM_CORE_VCO_TUNE (0x160) +#define QSERDES_COM_CORE_VCO_TAIL (0x164) +#define QSERDES_COM_CORE_KVCO_CODE (0x168) + +/* Tx Channel 0 REGISTERS */ +#define QSERDES_TX_L0_BIST_MODE_LANENO (0x00) +#define QSERDES_TX_L0_CLKBUF_ENABLE (0x04) +#define QSERDES_TX_L0_TX_EMP_POST1_LVL (0x08) +#define QSERDES_TX_L0_TX_DRV_LVL (0x0C) +#define QSERDES_TX_L0_RESET_TSYNC_EN (0x10) +#define QSERDES_TX_L0_LPB_EN (0x14) +#define QSERDES_TX_L0_RES_CODE_UP (0x18) +#define QSERDES_TX_L0_RES_CODE_DN (0x1C) +#define QSERDES_TX_L0_PERL_LENGTH1 (0x20) +#define QSERDES_TX_L0_PERL_LENGTH2 (0x24) +#define QSERDES_TX_L0_SERDES_BYP_EN_OUT (0x28) +#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C) +#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN (0x30) +#define QSERDES_TX_L0_BIST_PATTERN1 (0x34) +#define QSERDES_TX_L0_BIST_PATTERN2 (0x38) +#define QSERDES_TX_L0_BIST_PATTERN3 (0x3C) +#define QSERDES_TX_L0_BIST_PATTERN4 (0x40) +#define QSERDES_TX_L0_BIST_PATTERN5 (0x44) +#define QSERDES_TX_L0_BIST_PATTERN6 (0x48) +#define QSERDES_TX_L0_BIST_PATTERN7 (0x4C) +#define QSERDES_TX_L0_BIST_PATTERN8 (0x50) +#define QSERDES_TX_L0_LANE_MODE (0x54) +#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE (0x58) +#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C) +#define QSERDES_TX_L0_ATB_SEL1 (0x60) +#define QSERDES_TX_L0_ATB_SEL2 (0x64) +#define QSERDES_TX_L0_RCV_DETECT_LVL (0x68) +#define QSERDES_TX_L0_PRBS_SEED1 (0x6C) +#define QSERDES_TX_L0_PRBS_SEED2 (0x70) +#define QSERDES_TX_L0_PRBS_SEED3 (0x74) +#define QSERDES_TX_L0_PRBS_SEED4 (0x78) +#define QSERDES_TX_L0_RESET_GEN (0x7C) +#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN (0x80) +#define QSERDES_TX_L0_TX_INTERFACE_MODE (0x84) +#define QSERDES_TX_L0_PWM_CTRL (0x88) +#define QSERDES_TX_L0_PWM_DATA (0x8C) +#define QSERDES_TX_L0_PWM_ENC_DIV_CTRL (0x90) +#define QSERDES_TX_L0_VMODE_CTRL1 (0x94) +#define QSERDES_TX_L0_VMODE_CTRL2 (0x98) +#define QSERDES_TX_L0_VMODE_CTRL3 (0x9C) +#define QSERDES_TX_L0_VMODE_CTRL4 (0xA0) +#define QSERDES_TX_L0_VMODE_CTRL5 (0xA4) +#define QSERDES_TX_L0_VMODE_CTRL6 (0xA8) +#define QSERDES_TX_L0_VMODE_CTRL7 (0xAC) +#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL (0xB0) +#define QSERDES_TX_L0_BIST_STATUS (0xB4) +#define QSERDES_TX_L0_BIST_ERROR_COUNT1 (0xB8) +#define QSERDES_TX_L0_BIST_ERROR_COUNT2 (0xBC) +#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV (0xC0) +#define QSERDES_TX_L0_PWM_DEC_STATUS (0xC4) + +/* Tx Channel 1 REGISTERS */ +#define QSERDES_TX_L1_BIST_MODE_LANENO (0x00) +#define QSERDES_TX_L1_CLKBUF_ENABLE (0x04) +#define QSERDES_TX_L1_TX_EMP_POST1_LVL (0x08) +#define QSERDES_TX_L1_TX_DRV_LVL (0x0C) +#define QSERDES_TX_L1_RESET_TSYNC_EN (0x10) +#define QSERDES_TX_L1_LPB_EN (0x14) +#define QSERDES_TX_L1_RES_CODE_UP (0x18) +#define QSERDES_TX_L1_RES_CODE_DN (0x1C) +#define QSERDES_TX_L1_PERL_LENGTH1 (0x20) +#define QSERDES_TX_L1_PERL_LENGTH2 (0x24) +#define QSERDES_TX_L1_SERDES_BYP_EN_OUT (0x28) +#define QSERDES_TX_L1_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C) +#define QSERDES_TX_L1_PARRATE_REC_DETECT_IDLE_EN (0x30) +#define QSERDES_TX_L1_BIST_PATTERN1 (0x34) +#define QSERDES_TX_L1_BIST_PATTERN2 (0x38) +#define QSERDES_TX_L1_BIST_PATTERN3 (0x3C) +#define QSERDES_TX_L1_BIST_PATTERN4 (0x40) +#define QSERDES_TX_L1_BIST_PATTERN5 (0x44) +#define QSERDES_TX_L1_BIST_PATTERN6 (0x48) +#define QSERDES_TX_L1_BIST_PATTERN7 (0x4C) +#define QSERDES_TX_L1_BIST_PATTERN8 (0x50) +#define QSERDES_TX_L1_LANE_MODE (0x54) +#define QSERDES_TX_L1_IDAC_CAL_LANE_MODE (0x58) +#define QSERDES_TX_L1_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C) +#define QSERDES_TX_L1_ATB_SEL1 (0x60) +#define QSERDES_TX_L1_ATB_SEL2 (0x64) +#define QSERDES_TX_L1_RCV_DETECT_LVL (0x68) +#define QSERDES_TX_L1_PRBS_SEED1 (0x6C) +#define QSERDES_TX_L1_PRBS_SEED2 (0x70) +#define QSERDES_TX_L1_PRBS_SEED3 (0x74) +#define QSERDES_TX_L1_PRBS_SEED4 (0x78) +#define QSERDES_TX_L1_RESET_GEN (0x7C) +#define QSERDES_TX_L1_TRAN_DRVR_EMP_EN (0x80) +#define QSERDES_TX_L1_TX_INTERFACE_MODE (0x84) +#define QSERDES_TX_L1_PWM_CTRL (0x88) +#define QSERDES_TX_L1_PWM_DATA (0x8C) +#define QSERDES_TX_L1_PWM_ENC_DIV_CTRL (0x90) +#define QSERDES_TX_L1_VMODE_CTRL1 (0x94) +#define QSERDES_TX_L1_VMODE_CTRL2 (0x98) +#define QSERDES_TX_L1_VMODE_CTRL3 (0x9C) +#define QSERDES_TX_L1_VMODE_CTRL4 (0xA0) +#define QSERDES_TX_L1_VMODE_CTRL5 (0xA4) +#define QSERDES_TX_L1_VMODE_CTRL6 (0xA8) +#define QSERDES_TX_L1_VMODE_CTRL7 (0xAC) +#define QSERDES_TX_L1_TX_ALOG_INTF_OBSV_CNTL (0xB0) +#define QSERDES_TX_L1_BIST_STATUS (0xB4) +#define QSERDES_TX_L1_BIST_ERROR_COUNT1 (0xB8) +#define QSERDES_TX_L1_BIST_ERROR_COUNT2 (0xBC) +#define QSERDES_TX_L1_TX_ALOG_INTF_OBSV (0xC0) +#define QSERDES_TX_L1_PWM_DEC_STATUS (0xC4) + +/* Tx Channel 2 REGISERS */ +#define QSERDES_TX_L2_BIST_MODE_LANENO (0x00) +#define QSERDES_TX_L2_CLKBUF_ENABLE (0x04) +#define QSERDES_TX_L2_TX_EMP_POST1_LVL (0x08) +#define QSERDES_TX_L2_TX_DRV_LVL (0x0C) +#define QSERDES_TX_L2_RESET_TSYNC_EN (0x10) +#define QSERDES_TX_L2_LPB_EN (0x14) +#define QSERDES_TX_L2_RES_CODE_UP (0x18) +#define QSERDES_TX_L2_RES_CODE_DN (0x1C) +#define QSERDES_TX_L2_PERL_LENGTH1 (0x20) +#define QSERDES_TX_L2_PERL_LENGTH2 (0x24) +#define QSERDES_TX_L2_SERDES_BYP_EN_OUT (0x28) +#define QSERDES_TX_L2_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C) +#define QSERDES_TX_L2_PARRATE_REC_DETECT_IDLE_EN (0x30) +#define QSERDES_TX_L2_BIST_PATTERN1 (0x34) +#define QSERDES_TX_L2_BIST_PATTERN2 (0x38) +#define QSERDES_TX_L2_BIST_PATTERN3 (0x3C) +#define QSERDES_TX_L2_BIST_PATTERN4 (0x40) +#define QSERDES_TX_L2_BIST_PATTERN5 (0x44) +#define QSERDES_TX_L2_BIST_PATTERN6 (0x48) +#define QSERDES_TX_L2_BIST_PATTERN7 (0x4C) +#define QSERDES_TX_L2_BIST_PATTERN8 (0x50) +#define QSERDES_TX_L2_LANE_MODE (0x54) +#define QSERDES_TX_L2_IDAC_CAL_LANE_MODE (0x58) +#define QSERDES_TX_L2_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C) +#define QSERDES_TX_L2_ATB_SEL1 (0x60) +#define QSERDES_TX_L2_ATB_SEL2 (0x64) +#define QSERDES_TX_L2_RCV_DETECT_LVL (0x68) +#define QSERDES_TX_L2_PRBS_SEED1 (0x6C) +#define QSERDES_TX_L2_PRBS_SEED2 (0x70) +#define QSERDES_TX_L2_PRBS_SEED3 (0x74) +#define QSERDES_TX_L2_PRBS_SEED4 (0x78) +#define QSERDES_TX_L2_RESET_GEN (0x7C) +#define QSERDES_TX_L2_TRAN_DRVR_EMP_EN (0x80) +#define QSERDES_TX_L2_TX_INTERFACE_MODE (0x84) +#define QSERDES_TX_L2_PWM_CTRL (0x88) +#define QSERDES_TX_L2_PWM_DATA (0x8C) +#define QSERDES_TX_L2_PWM_ENC_DIV_CTRL (0x90) +#define QSERDES_TX_L2_VMODE_CTRL1 (0x94) +#define QSERDES_TX_L2_VMODE_CTRL2 (0x98) +#define QSERDES_TX_L2_VMODE_CTRL3 (0x9C) +#define QSERDES_TX_L2_VMODE_CTRL4 (0xA0) +#define QSERDES_TX_L2_VMODE_CTRL5 (0xA4) +#define QSERDES_TX_L2_VMODE_CTRL6 (0xA8) +#define QSERDES_TX_L2_VMODE_CTRL7 (0xAC) +#define QSERDES_TX_L2_TX_ALOG_INTF_OBSV_CNTL (0xB0) +#define QSERDES_TX_L2_BIST_STATUS (0xB4) +#define QSERDES_TX_L2_BIST_ERROR_COUNT1 (0xB8) +#define QSERDES_TX_L2_BIST_ERROR_COUNT2 (0xBC) +#define QSERDES_TX_L2_TX_ALOG_INTF_OBSV (0xC0) +#define QSERDES_TX_L2_PWM_DEC_STATUS (0xC4) + +/* Tx Channel 3 REGISERS */ +#define QSERDES_TX_L3_BIST_MODE_LANENO (0x00) +#define QSERDES_TX_L3_CLKBUF_ENABLE (0x04) +#define QSERDES_TX_L3_TX_EMP_POST1_LVL (0x08) +#define QSERDES_TX_L3_TX_DRV_LVL (0x0C) +#define QSERDES_TX_L3_RESET_TSYNC_EN (0x10) +#define QSERDES_TX_L3_LPB_EN (0x14) +#define QSERDES_TX_L3_RES_CODE_UP (0x18) +#define QSERDES_TX_L3_RES_CODE_DN (0x1C) +#define QSERDES_TX_L3_PERL_LENGTH1 (0x20) +#define QSERDES_TX_L3_PERL_LENGTH2 (0x24) +#define QSERDES_TX_L3_SERDES_BYP_EN_OUT (0x28) +#define QSERDES_TX_L3_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x2C) +#define QSERDES_TX_L3_PARRATE_REC_DETECT_IDLE_EN (0x30) +#define QSERDES_TX_L3_BIST_PATTERN1 (0x34) +#define QSERDES_TX_L3_BIST_PATTERN2 (0x38) +#define QSERDES_TX_L3_BIST_PATTERN3 (0x3C) +#define QSERDES_TX_L3_BIST_PATTERN4 (0x40) +#define QSERDES_TX_L3_BIST_PATTERN5 (0x44) +#define QSERDES_TX_L3_BIST_PATTERN6 (0x48) +#define QSERDES_TX_L3_BIST_PATTERN7 (0x4C) +#define QSERDES_TX_L3_BIST_PATTERN8 (0x50) +#define QSERDES_TX_L3_LANE_MODE (0x54) +#define QSERDES_TX_L3_IDAC_CAL_LANE_MODE (0x58) +#define QSERDES_TX_L3_IDAC_CAL_LANE_MODE_CONFIGURATION (0x5C) +#define QSERDES_TX_L3_ATB_SEL1 (0x60) +#define QSERDES_TX_L3_ATB_SEL2 (0x64) +#define QSERDES_TX_L3_RCV_DETECT_LVL (0x68) +#define QSERDES_TX_L3_PRBS_SEED1 (0x6C) +#define QSERDES_TX_L3_PRBS_SEED2 (0x70) +#define QSERDES_TX_L3_PRBS_SEED3 (0x74) +#define QSERDES_TX_L3_PRBS_SEED4 (0x78) +#define QSERDES_TX_L3_RESET_GEN (0x7C) +#define QSERDES_TX_L3_TRAN_DRVR_EMP_EN (0x80) +#define QSERDES_TX_L3_TX_INTERFACE_MODE (0x84) +#define QSERDES_TX_L3_PWM_CTRL (0x88) +#define QSERDES_TX_L3_PWM_DATA (0x8C) +#define QSERDES_TX_L3_PWM_ENC_DIV_CTRL (0x90) +#define QSERDES_TX_L3_VMODE_CTRL1 (0x94) +#define QSERDES_TX_L3_VMODE_CTRL2 (0x98) +#define QSERDES_TX_L3_VMODE_CTRL3 (0x9C) +#define QSERDES_TX_L3_VMODE_CTRL4 (0xA0) +#define QSERDES_TX_L3_VMODE_CTRL5 (0xA4) +#define QSERDES_TX_L3_VMODE_CTRL6 (0xA8) +#define QSERDES_TX_L3_VMODE_CTRL7 (0xAC) +#define QSERDES_TX_L3_TX_ALOG_INTF_OBSV_CNTL (0xB0) +#define QSERDES_TX_L3_BIST_STATUS (0xB4) +#define QSERDES_TX_L3_BIST_ERROR_COUNT1 (0xB8) +#define QSERDES_TX_L3_BIST_ERROR_COUNT2 (0xBC) +#define QSERDES_TX_L3_TX_ALOG_INTF_OBSV (0xC0) +#define QSERDES_TX_L3_PWM_DEC_STATUS (0xC4) + +/* HDMI PHY REGISTERS */ +#define HDMI_PHY_CFG (0x00) +#define HDMI_PHY_PD_CTL (0x04) +#define HDMI_PHY_MODE (0x08) +#define HDMI_PHY_MISR_CLEAR (0x0C) +#define HDMI_PHY_TX0_TX1_BIST_CFG0 (0x10) +#define HDMI_PHY_TX0_TX1_BIST_CFG1 (0x14) +#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0 (0x18) +#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1 (0x1C) +#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE2 (0x20) +#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE3 (0x24) +#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE0 (0x28) +#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE1 (0x2C) +#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE2 (0x30) +#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE3 (0x34) +#define HDMI_PHY_TX2_TX3_BIST_CFG0 (0x38) +#define HDMI_PHY_TX2_TX3_BIST_CFG1 (0x3C) +#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0 (0x40) +#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1 (0x44) +#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE2 (0x48) +#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE3 (0x4C) +#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE0 (0x50) +#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE1 (0x54) +#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE2 (0x58) +#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE3 (0x5C) +#define HDMI_PHY_DEBUG_BUS_SEL (0x60) +#define HDMI_PHY_TXCAL_CFG0 (0x64) +#define HDMI_PHY_TXCAL_CFG1 (0x68) +#define HDMI_PHY_TX0_TX1_BIST_STATUS0 (0x6C) +#define HDMI_PHY_TX0_TX1_BIST_STATUS1 (0x70) +#define HDMI_PHY_TX0_TX1_BIST_STATUS2 (0x74) +#define HDMI_PHY_TX2_TX3_BIST_STATUS0 (0x78) +#define HDMI_PHY_TX2_TX3_BIST_STATUS1 (0x7C) +#define HDMI_PHY_TX2_TX3_BIST_STATUS2 (0x80) +#define HDMI_PHY_PRE_MISR_STATUS0 (0x84) +#define HDMI_PHY_PRE_MISR_STATUS1 (0x88) +#define HDMI_PHY_PRE_MISR_STATUS2 (0x8C) +#define HDMI_PHY_PRE_MISR_STATUS3 (0x90) +#define HDMI_PHY_POST_MISR_STATUS0 (0x94) +#define HDMI_PHY_POST_MISR_STATUS1 (0x98) +#define HDMI_PHY_POST_MISR_STATUS2 (0x9C) +#define HDMI_PHY_POST_MISR_STATUS3 (0xA0) +#define HDMI_PHY_STATUS (0xA4) +#define HDMI_PHY_MISC3_STATUS (0xA8) +#define HDMI_PHY_DEBUG_BUS0 (0xAC) +#define HDMI_PHY_DEBUG_BUS1 (0xB0) +#define HDMI_PHY_DEBUG_BUS2 (0xB4) +#define HDMI_PHY_DEBUG_BUS3 (0xB8) +#define HDMI_PHY_REVISION_ID0 (0xBC) +#define HDMI_PHY_REVISION_ID1 (0xC0) +#define HDMI_PHY_REVISION_ID2 (0xC4) +#define HDMI_PHY_REVISION_ID3 (0xC8) + +#define HDMI_PLL_POLL_DELAY_US 50 +#define HDMI_PLL_POLL_TIMEOUT_US 125000 +#define HDMI_PLL_REF_CLK_RATE 192ULL +#define HDMI_PLL_DIVISOR 10000000000ULL +#define HDMI_PLL_DIVISOR_32 100000U +#define HDMI_PLL_MIN_VCO_CLK 160000000ULL +#define HDMI_PLL_TMDS_MAX 800000000U + + +static int hdmi_20nm_pll_lock_status(struct mdss_pll_resources *io) +{ + u32 status; + int pll_locked = 0; + int phy_ready = 0; + int rc; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + /* Poll for C_READY and PHY READY */ + pr_debug("%s: Waiting for PHY Ready\n", __func__); + + /* poll for PLL ready status */ + if (!readl_poll_timeout_atomic( + (io->pll_base + QSERDES_COM_RESET_SM), + status, ((status & BIT(6)) == 1), + HDMI_PLL_POLL_DELAY_US, + HDMI_PLL_POLL_TIMEOUT_US)) { + pr_debug("%s: C READY\n", __func__); + pll_locked = 1; + } else { + pr_debug("%s: C READY TIMEOUT\n", __func__); + pll_locked = 0; + } + + /* poll for PHY ready status */ + if (pll_locked && !readl_poll_timeout_atomic( + (io->phy_base + HDMI_PHY_STATUS), + status, ((status & BIT(0)) == 1), + HDMI_PLL_POLL_DELAY_US, + HDMI_PLL_POLL_TIMEOUT_US)) { + pr_debug("%s: PHY READY\n", __func__); + phy_ready = 1; + } else { + pr_debug("%s: PHY READY TIMEOUT\n", __func__); + phy_ready = 0; + } + mdss_pll_resource_enable(io, false); + + return phy_ready; +} + +static inline struct hdmi_pll_vco_clk *to_hdmi_20nm_vco_clk(struct clk *clk) +{ + return container_of(clk, struct hdmi_pll_vco_clk, c); +} + +static inline u32 hdmi_20nm_phy_pll_vco_reg_val(struct hdmi_pll_cfg *pll_cfg, + u32 tmds_clk) +{ + u32 index = 0; + + while (pll_cfg[index].vco_rate < HDMI_PLL_TMDS_MAX && + pll_cfg[index].vco_rate < tmds_clk) + index++; + return pll_cfg[index].reg; +} + +static void hdmi_20nm_phy_pll_calc_settings(struct mdss_pll_resources *io, + struct hdmi_pll_vco_clk *vco, u32 vco_clk, u32 tmds_clk) +{ + u32 val = 0; + u64 dec_start_val, frac_start_val, pll_lock_cmp; + + /* Calculate decimal and fractional values */ + dec_start_val = 1000000UL * vco_clk; + do_div(dec_start_val, HDMI_PLL_REF_CLK_RATE); + do_div(dec_start_val, 2U); + frac_start_val = dec_start_val; + do_div(frac_start_val, HDMI_PLL_DIVISOR_32); + do_div(frac_start_val, HDMI_PLL_DIVISOR_32); + frac_start_val *= HDMI_PLL_DIVISOR; + frac_start_val = dec_start_val - frac_start_val; + frac_start_val *= (u64)(2 << 19); + do_div(frac_start_val, HDMI_PLL_DIVISOR_32); + do_div(frac_start_val, HDMI_PLL_DIVISOR_32); + pll_lock_cmp = dec_start_val; + do_div(pll_lock_cmp, 10U); + pll_lock_cmp *= 0x800; + do_div(pll_lock_cmp, HDMI_PLL_DIVISOR_32); + do_div(pll_lock_cmp, HDMI_PLL_DIVISOR_32); + pll_lock_cmp -= 1U; + do_div(dec_start_val, HDMI_PLL_DIVISOR_32); + do_div(dec_start_val, HDMI_PLL_DIVISOR_32); + + /* PLL loop bandwidth */ + val = hdmi_20nm_phy_pll_vco_reg_val(vco->ip_seti, tmds_clk); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_IP_SETI, val); + val = hdmi_20nm_phy_pll_vco_reg_val(vco->cp_seti, tmds_clk); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CP_SETI, val); + val = hdmi_20nm_phy_pll_vco_reg_val(vco->cp_setp, tmds_clk); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CP_SETP, val); + val = hdmi_20nm_phy_pll_vco_reg_val(vco->ip_setp, tmds_clk); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_IP_SETP, val); + val = hdmi_20nm_phy_pll_vco_reg_val(vco->crctrl, tmds_clk); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CRCTRL, val); + + /* PLL calibration */ + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START1, + 0x80 | (frac_start_val & 0x7F)); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START2, + 0x80 | ((frac_start_val >> 7) & 0x7F)); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START3, + 0x40 | ((frac_start_val >> 14) & 0x3F)); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEC_START1, + 0x80 | (dec_start_val & 0x7F)); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEC_START2, + 0x02 | (0x01 & (dec_start_val >> 7))); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLLLOCK_CMP1, + pll_lock_cmp & 0xFF); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLLLOCK_CMP2, + (pll_lock_cmp >> 8) & 0xFF); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLLLOCK_CMP3, + (pll_lock_cmp >> 16) & 0xFF); +} + +static u32 hdmi_20nm_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk) +{ + u32 tx_band = 0; + + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + u64 vco_clk = tmds_clk; + + while (vco_clk > 0 && vco_clk < HDMI_PLL_MIN_VCO_CLK) { + tx_band++; + vco_clk *= 2; + } + + /* Initially shut down PHY */ + pr_debug("%s: Disabling PHY\n", __func__); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x0); + udelay(1000); + /* memory barrier */ + mb(); + + /* power-up and recommended common block settings */ + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1F); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x01); + udelay(1000); + /* memory barrier */ + mb(); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x07); + udelay(1000); + /* memory barrier */ + mb(); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x05); + udelay(1000); + /* memory barrier */ + mb(); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x42); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_VCOTAIL_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MODE, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_IE_TRIM, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_IP_TRIM, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CNTRL, 0x07); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_PHSEL_CONTROL, 0x04); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL, 0xA0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_PHSEL_DC, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORE_CLK_IN_SYNC_SEL, 0x00); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_BKG_KVCO_CAL_EN, 0x00); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x0F); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x01); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x01); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_EN_SEL_TXBAND, + 0x4A + (0x10 * tx_band)); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VREF_CFG1, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VREF_CFG2, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BGTC, 0xFF); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_TEST_UPDN, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_VCO_TUNE, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_AMP_OS, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_EN_CENTER, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_CODE_UP, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_CODE_DN, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_KVCO_CODE, + tmds_clk > 300000000 ? 0x3F : 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_KVCO_COUNT1, + tmds_clk > 300000000 ? 0x00 : 0x8A); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_REF1, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_REF2, + tmds_clk > 300000000 ? 0x00 : 0x01); + + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_KVCO_CAL_CNTRL, + tmds_clk > 300000000 ? 0x00 : 0x1F); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VREF_CFG3, + tmds_clk > 300000000 ? 0x00 : 0x40); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VREF_CFG4, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VREF_CFG5, 0x10); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL, + tmds_clk > 300000000 ? 0x80 : 0x00); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_CODE_CAL_CSR, 0x77); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_TRIM_EN_VCOCALDONE, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_RXTXEPCLK_EN, 0x0C); + + hdmi_20nm_phy_pll_calc_settings(io, vco, vco_clk, tmds_clk); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLLLOCK_CMP_EN, 0x11); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CNTRL, 0x07); + + /* Resistor calibration linear search */ + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_CODE_START_SEG1, 0x60); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_CODE_START_SEG2, 0x60); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RES_TRIM_CONTROL, 0x01); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL2, 0x07); + + udelay(1000); + /* memory barrier */ + mb(); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_MODE, tx_band); + + /* TX lanes (transceivers) power-up sequence */ + MDSS_PLL_REG_W(io->pll_base + 0x400, QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + 0x600, QSERDES_TX_L1_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + 0x800, QSERDES_TX_L2_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + 0xA00, QSERDES_TX_L3_CLKBUF_ENABLE, 0x03); + + MDSS_PLL_REG_W(io->pll_base + 0x400, + QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + 0x600, + QSERDES_TX_L1_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + 0x800, + QSERDES_TX_L2_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + 0xA00, + QSERDES_TX_L3_TRAN_DRVR_EMP_EN, 0x03); + + MDSS_PLL_REG_W(io->pll_base + 0x400, + QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x6F); + MDSS_PLL_REG_W(io->pll_base + 0x600, + QSERDES_TX_L1_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x6F); + MDSS_PLL_REG_W(io->pll_base + 0x800, + QSERDES_TX_L2_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x6F); + MDSS_PLL_REG_W(io->pll_base + 0xA00, + QSERDES_TX_L3_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x6F); + + MDSS_PLL_REG_W(io->pll_base + 0x400, + QSERDES_TX_L0_TX_EMP_POST1_LVL, 0x0000002F); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x000000AF); + + MDSS_PLL_REG_W(io->pll_base + 0x400, QSERDES_TX_L0_VMODE_CTRL1, 0x08); + MDSS_PLL_REG_W(io->pll_base + 0x800, QSERDES_TX_L2_VMODE_CTRL1, 0x09); + MDSS_PLL_REG_W(io->pll_base + 0x400, QSERDES_TX_L0_VMODE_CTRL5, 0xA0); + MDSS_PLL_REG_W(io->pll_base + 0x400, QSERDES_TX_L0_VMODE_CTRL6, 0x01); + MDSS_PLL_REG_W(io->pll_base + 0x800, QSERDES_TX_L2_VMODE_CTRL5, 0xA0); + MDSS_PLL_REG_W(io->pll_base + 0x800, QSERDES_TX_L2_VMODE_CTRL6, 0x01); + + MDSS_PLL_REG_W(io->pll_base + 0x400, + QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + 0x400, + QSERDES_TX_L0_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(io->pll_base + 0x600, + QSERDES_TX_L1_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + 0x600, + QSERDES_TX_L1_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(io->pll_base + 0x800, + QSERDES_TX_L2_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + 0x800, + QSERDES_TX_L2_TX_INTERFACE_MODE, 0x00); + MDSS_PLL_REG_W(io->pll_base + 0xA00, + QSERDES_TX_L3_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + 0xA00, + QSERDES_TX_L3_TX_INTERFACE_MODE, 0x00); + + return 0; +} + +static int hdmi_20nm_vco_enable(struct clk *c) +{ + u32 ready_poll; + u32 time_out_loop; + /* Hardware recommended timeout iterator */ + u32 time_out_max = 50000; + + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x00000000); + udelay(100); + /* memory barrier */ + mb(); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x00000003); + udelay(100); + /* memory barrier */ + mb(); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x00000009); + udelay(100); + /* memory barrier */ + mb(); + + /* Poll for C_READY and PHY READY */ + pr_debug("%s: Waiting for PHY Ready\n", __func__); + time_out_loop = 0; + do { + ready_poll = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_RESET_SM); + time_out_loop++; + udelay(10); + } while (((ready_poll & (1 << 6)) == 0) && + (time_out_loop < time_out_max)); + if (time_out_loop >= time_out_max) + pr_err("%s: ERROR: TIMED OUT BEFORE C READY\n", __func__); + else + pr_debug("%s: C READY\n", __func__); + + /* Poll for PHY READY */ + pr_debug("%s: Waiting for PHY Ready\n", __func__); + time_out_loop = 0; + do { + ready_poll = MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS); + time_out_loop++; + udelay(1); + } while (((ready_poll & 0x1) == 0) && (time_out_loop < time_out_max)); + + if (time_out_loop >= time_out_max) + pr_err("%s: TIMED OUT BEFORE PHY READY\n", __func__); + else + pr_debug("%s: HDMI PHY READY\n", __func__); + + io->pll_on = true; + + return 0; +} + + +static int hdmi_20nm_vco_set_rate(struct clk *c, unsigned long rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + void __iomem *pll_base; + void __iomem *phy_base; + unsigned int set_power_dwn = 0; + int rc; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + if (io->pll_on) + set_power_dwn = 1; + + pll_base = io->pll_base; + phy_base = io->phy_base; + + pr_debug("rate=%ld\n", rate); + + hdmi_20nm_phy_pll_set_clk_rate(c, rate); + + mdss_pll_resource_enable(io, false); + + if (set_power_dwn) + hdmi_20nm_vco_enable(c); + + vco->rate = rate; + vco->rate_set = true; + + return 0; +} + +static unsigned long hdmi_20nm_vco_get_rate(struct clk *c) +{ + unsigned long freq = 0; + int rc; + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + if (is_gdsc_disabled(io)) + return 0; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + mdss_pll_resource_enable(io, false); + + return freq; +} + +static long hdmi_20nm_vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + + pr_debug("rrate=%ld\n", rrate); + + return rrate; +} + +static int hdmi_20nm_vco_prepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + int ret = 0; + + pr_debug("rate=%ld\n", vco->rate); + + if (!vco->rate_set && vco->rate) + ret = hdmi_20nm_vco_set_rate(c, vco->rate); + + if (!ret) { + ret = mdss_pll_resource_enable(io, true); + if (ret) + pr_err("pll resource can't be enabled\n"); + } + + return ret; +} + +static void hdmi_20nm_vco_unprepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + vco->rate_set = false; + + if (!io) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!io->pll_on && + mdss_pll_resource_enable(io, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + + io->handoff_resources = false; + mdss_pll_resource_enable(io, false); + io->pll_on = false; +} + +static enum handoff hdmi_20nm_vco_handoff(struct clk *c) +{ + enum handoff ret = HANDOFF_DISABLED_CLK; + struct hdmi_pll_vco_clk *vco = to_hdmi_20nm_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + if (is_gdsc_disabled(io)) + return HANDOFF_DISABLED_CLK; + + if (mdss_pll_resource_enable(io, true)) { + pr_err("pll resource can't be enabled\n"); + return ret; + } + + io->handoff_resources = true; + + if (hdmi_20nm_pll_lock_status(io)) { + io->pll_on = true; + c->rate = hdmi_20nm_vco_get_rate(c); + ret = HANDOFF_ENABLED_CLK; + } else { + io->handoff_resources = false; + mdss_pll_resource_enable(io, false); + } + + pr_debug("done, ret=%d\n", ret); + return ret; +} + +static const struct clk_ops hdmi_20nm_vco_clk_ops = { + .enable = hdmi_20nm_vco_enable, + .set_rate = hdmi_20nm_vco_set_rate, + .get_rate = hdmi_20nm_vco_get_rate, + .round_rate = hdmi_20nm_vco_round_rate, + .prepare = hdmi_20nm_vco_prepare, + .unprepare = hdmi_20nm_vco_unprepare, + .handoff = hdmi_20nm_vco_handoff, +}; + +static struct hdmi_pll_vco_clk hdmi_20nm_vco_clk = { + .ip_seti = (struct hdmi_pll_cfg[]){ + {550890000, 0x03}, + {589240000, 0x07}, + {689290000, 0x03}, + {727600000, 0x07}, + {HDMI_PLL_TMDS_MAX, 0x03}, + }, + .cp_seti = (struct hdmi_pll_cfg[]){ + {34440000, 0x3F}, + {36830000, 0x2F}, + {68870000, 0x3F}, + {73660000, 0x2F}, + {137730000, 0x3F}, + {147310000, 0x2F}, + {275450000, 0x3F}, + {294620000, 0x2F}, + {344650000, 0x3F}, + {363800000, 0x2F}, + {477960000, 0x3F}, + {512530000, 0x2F}, + {550890000, 0x1F}, + {589240000, 0x2F}, + {630900000, 0x3F}, + {650590000, 0x2F}, + {689290000, 0x1F}, + {727600000, 0x2F}, + {HDMI_PLL_TMDS_MAX, 0x3F}, + }, + .ip_setp = (struct hdmi_pll_cfg[]){ + {497340000, 0x03}, + {512530000, 0x07}, + {535680000, 0x03}, + {550890000, 0x07}, + {574060000, 0x03}, + {727600000, 0x07}, + {HDMI_PLL_TMDS_MAX, 0x03}, + }, + .cp_setp = (struct hdmi_pll_cfg[]){ + {36830000, 0x1F}, + {40010000, 0x17}, + {73660000, 0x1F}, + {80000000, 0x17}, + {147310000, 0x1F}, + {160010000, 0x17}, + {294620000, 0x1F}, + {363800000, 0x17}, + {497340000, 0x0F}, + {512530000, 0x1F}, + {535680000, 0x0F}, + {550890000, 0x1F}, + {574060000, 0x0F}, + {589240000, 0x1F}, + {727600000, 0x17}, + {HDMI_PLL_TMDS_MAX, 0x07}, + }, + .crctrl = (struct hdmi_pll_cfg[]){ + {40010000, 0xBB}, + {40030000, 0x77}, + {80000000, 0xBB}, + {80060000, 0x77}, + {160010000, 0xBB}, + {160120000, 0x77}, + {772930000, 0xBB}, + {HDMI_PLL_TMDS_MAX, 0xFF}, + }, + .c = { + .dbg_name = "hdmi_20nm_vco_clk", + .ops = &hdmi_20nm_vco_clk_ops, + CLK_INIT(hdmi_20nm_vco_clk.c), + }, +}; + +static struct clk_lookup hdmipllcc_8994[] = { + CLK_LIST(hdmi_20nm_vco_clk), +}; + +int hdmi_20nm_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP; + + /* Set client data for vco, mux and div clocks */ + hdmi_20nm_vco_clk.priv = pll_res; + + rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8994, + ARRAY_SIZE(hdmipllcc_8994)); + if (rc) { + pr_err("Clock register failed rc=%d\n", rc); + rc = -EPROBE_DEFER; + } else { + pr_debug("%s: SUCCESS\n", __func__); + } + + return rc; +} diff --git a/techpack/display/pll/hdmi_pll_28hpm.c b/techpack/display/pll/hdmi_pll_28hpm.c new file mode 100644 index 0000000000000000000000000000000000000000..962a4cec498403cac90ea9df4bc7d823fa75858d --- /dev/null +++ b/techpack/display/pll/hdmi_pll_28hpm.c @@ -0,0 +1,1091 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> + +#include "pll_drv.h" +#include "hdmi_pll.h" + +/* hdmi phy registers */ +#define HDMI_PHY_ANA_CFG0 (0x0000) +#define HDMI_PHY_ANA_CFG1 (0x0004) +#define HDMI_PHY_ANA_CFG2 (0x0008) +#define HDMI_PHY_ANA_CFG3 (0x000C) +#define HDMI_PHY_PD_CTRL0 (0x0010) +#define HDMI_PHY_PD_CTRL1 (0x0014) +#define HDMI_PHY_GLB_CFG (0x0018) +#define HDMI_PHY_DCC_CFG0 (0x001C) +#define HDMI_PHY_DCC_CFG1 (0x0020) +#define HDMI_PHY_TXCAL_CFG0 (0x0024) +#define HDMI_PHY_TXCAL_CFG1 (0x0028) +#define HDMI_PHY_TXCAL_CFG2 (0x002C) +#define HDMI_PHY_TXCAL_CFG3 (0x0030) +#define HDMI_PHY_BIST_CFG0 (0x0034) +#define HDMI_PHY_BIST_CFG1 (0x0038) +#define HDMI_PHY_BIST_PATN0 (0x003C) +#define HDMI_PHY_BIST_PATN1 (0x0040) +#define HDMI_PHY_BIST_PATN2 (0x0044) +#define HDMI_PHY_BIST_PATN3 (0x0048) +#define HDMI_PHY_STATUS (0x005C) + +/* hdmi phy unified pll registers */ +#define HDMI_UNI_PLL_REFCLK_CFG (0x0000) +#define HDMI_UNI_PLL_POSTDIV1_CFG (0x0004) +#define HDMI_UNI_PLL_CHFPUMP_CFG (0x0008) +#define HDMI_UNI_PLL_VCOLPF_CFG (0x000C) +#define HDMI_UNI_PLL_VREG_CFG (0x0010) +#define HDMI_UNI_PLL_PWRGEN_CFG (0x0014) +#define HDMI_UNI_PLL_GLB_CFG (0x0020) +#define HDMI_UNI_PLL_POSTDIV2_CFG (0x0024) +#define HDMI_UNI_PLL_POSTDIV3_CFG (0x0028) +#define HDMI_UNI_PLL_LPFR_CFG (0x002C) +#define HDMI_UNI_PLL_LPFC1_CFG (0x0030) +#define HDMI_UNI_PLL_LPFC2_CFG (0x0034) +#define HDMI_UNI_PLL_SDM_CFG0 (0x0038) +#define HDMI_UNI_PLL_SDM_CFG1 (0x003C) +#define HDMI_UNI_PLL_SDM_CFG2 (0x0040) +#define HDMI_UNI_PLL_SDM_CFG3 (0x0044) +#define HDMI_UNI_PLL_SDM_CFG4 (0x0048) +#define HDMI_UNI_PLL_SSC_CFG0 (0x004C) +#define HDMI_UNI_PLL_SSC_CFG1 (0x0050) +#define HDMI_UNI_PLL_SSC_CFG2 (0x0054) +#define HDMI_UNI_PLL_SSC_CFG3 (0x0058) +#define HDMI_UNI_PLL_LKDET_CFG0 (0x005C) +#define HDMI_UNI_PLL_LKDET_CFG1 (0x0060) +#define HDMI_UNI_PLL_LKDET_CFG2 (0x0064) +#define HDMI_UNI_PLL_CAL_CFG0 (0x006C) +#define HDMI_UNI_PLL_CAL_CFG1 (0x0070) +#define HDMI_UNI_PLL_CAL_CFG2 (0x0074) +#define HDMI_UNI_PLL_CAL_CFG3 (0x0078) +#define HDMI_UNI_PLL_CAL_CFG4 (0x007C) +#define HDMI_UNI_PLL_CAL_CFG5 (0x0080) +#define HDMI_UNI_PLL_CAL_CFG6 (0x0084) +#define HDMI_UNI_PLL_CAL_CFG7 (0x0088) +#define HDMI_UNI_PLL_CAL_CFG8 (0x008C) +#define HDMI_UNI_PLL_CAL_CFG9 (0x0090) +#define HDMI_UNI_PLL_CAL_CFG10 (0x0094) +#define HDMI_UNI_PLL_CAL_CFG11 (0x0098) +#define HDMI_UNI_PLL_STATUS (0x00C0) + +#define HDMI_PLL_POLL_DELAY_US 50 +#define HDMI_PLL_POLL_TIMEOUT_US 500 + +static inline struct hdmi_pll_vco_clk *to_hdmi_vco_clk(struct clk *clk) +{ + return container_of(clk, struct hdmi_pll_vco_clk, c); +} + +static void hdmi_vco_disable(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + + if (!hdmi_pll_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!hdmi_pll_res->pll_on && + mdss_pll_resource_enable(hdmi_pll_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0); + udelay(5); + MDSS_PLL_REG_W(hdmi_pll_res->phy_base, HDMI_PHY_GLB_CFG, 0x0); + + hdmi_pll_res->handoff_resources = false; + mdss_pll_resource_enable(hdmi_pll_res, false); + hdmi_pll_res->pll_on = false; +} /* hdmi_vco_disable */ + +static int hdmi_vco_enable(struct clk *c) +{ + u32 status; + u32 delay_us, timeout_us; + int rc; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + /* Global Enable */ + MDSS_PLL_REG_W(hdmi_pll_res->phy_base, HDMI_PHY_GLB_CFG, 0x81); + /* Power up power gen */ + MDSS_PLL_REG_W(hdmi_pll_res->phy_base, HDMI_PHY_PD_CTRL0, 0x00); + udelay(350); + + /* PLL Power-Up */ + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + udelay(5); + /* Power up PLL LDO */ + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_UNI_PLL_GLB_CFG, 0x03); + udelay(350); + + /* PLL Power-Up */ + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + udelay(350); + + /* poll for PLL ready status */ + delay_us = 100; + timeout_us = 2000; + if (readl_poll_timeout_atomic( + (hdmi_pll_res->pll_base + HDMI_UNI_PLL_STATUS), + status, ((status & BIT(0)) == 1), delay_us, timeout_us)) { + pr_err("hdmi phy pll status=%x failed to Lock\n", status); + hdmi_vco_disable(c); + mdss_pll_resource_enable(hdmi_pll_res, false); + return -EINVAL; + } + pr_debug("hdmi phy pll is locked\n"); + + udelay(350); + /* poll for PHY ready status */ + delay_us = 100; + timeout_us = 2000; + if (readl_poll_timeout_atomic( + (hdmi_pll_res->phy_base + HDMI_PHY_STATUS), + status, ((status & BIT(0)) == 1), delay_us, timeout_us)) { + pr_err("hdmi phy status=%x failed to Lock\n", status); + hdmi_vco_disable(c); + mdss_pll_resource_enable(hdmi_pll_res, false); + return -EINVAL; + } + hdmi_pll_res->pll_on = true; + pr_debug("hdmi phy is locked\n"); + + return 0; +} /* hdmi_vco_enable */ + + +static void hdmi_phy_pll_calculator(u32 vco_freq, + struct mdss_pll_resources *hdmi_pll_res) +{ + u32 ref_clk = 19200000; + u32 sdm_mode = 1; + u32 ref_clk_multiplier = sdm_mode == 1 ? 2 : 1; + u32 int_ref_clk_freq = ref_clk * ref_clk_multiplier; + u32 fbclk_pre_div = 1; + u32 ssc_mode = 0; + u32 kvco = 270; + u32 vdd = 95; + u32 ten_power_six = 1000000; + u32 ssc_ds_ppm = ssc_mode ? 5000 : 0; + u32 sdm_res = 16; + u32 ssc_tri_step = 32; + u32 ssc_freq = 2; + u64 ssc_ds = vco_freq * ssc_ds_ppm; + u32 div_in_freq = vco_freq / fbclk_pre_div; + u64 dc_offset = (div_in_freq / int_ref_clk_freq - 1) * + ten_power_six * 10; + u32 ssc_kdiv = (int_ref_clk_freq / ssc_freq) - + ten_power_six; + u64 sdm_freq_seed; + u32 ssc_tri_inc; + u64 fb_div_n; + void __iomem *pll_base = hdmi_pll_res->pll_base; + u32 val; + + pr_debug("vco_freq = %u\n", vco_freq); + + do_div(ssc_ds, (u64)ten_power_six); + + fb_div_n = (u64)div_in_freq * (u64)ten_power_six * 10; + do_div(fb_div_n, int_ref_clk_freq); + + sdm_freq_seed = ((fb_div_n - dc_offset - ten_power_six * 10) * + (1 << sdm_res) * 10) + 5; + do_div(sdm_freq_seed, ((u64)ten_power_six * 100)); + + ssc_tri_inc = (u32)ssc_ds; + ssc_tri_inc = (ssc_tri_inc / int_ref_clk_freq) * (1 << 16) / + ssc_tri_step; + + val = (ref_clk_multiplier == 2 ? 1 : 0) + + ((fbclk_pre_div == 2 ? 1 : 0) * 16); + pr_debug("HDMI_UNI_PLL_REFCLK_CFG = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, val); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CHFPUMP_CFG, 0x02); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_PWRGEN_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + + do_div(dc_offset, (u64)ten_power_six * 10); + val = sdm_mode == 0 ? 64 + dc_offset : 0; + pr_debug("HDMI_UNI_PLL_SDM_CFG0 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, val); + + val = 64 + dc_offset; + pr_debug("HDMI_UNI_PLL_SDM_CFG1 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, val); + + val = sdm_freq_seed & 0xFF; + pr_debug("HDMI_UNI_PLL_SDM_CFG2 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, val); + + val = (sdm_freq_seed >> 8) & 0xFF; + pr_debug("HDMI_UNI_PLL_SDM_CFG3 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, val); + + val = (sdm_freq_seed >> 16) & 0xFF; + pr_debug("HDMI_UNI_PLL_SDM_CFG4 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, val); + + val = (ssc_mode == 0 ? 128 : 0) + (ssc_kdiv / ten_power_six); + pr_debug("HDMI_UNI_PLL_SSC_CFG0 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SSC_CFG0, val); + + val = ssc_tri_inc & 0xFF; + pr_debug("HDMI_UNI_PLL_SSC_CFG1 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SSC_CFG1, val); + + val = (ssc_tri_inc >> 8) & 0xFF; + pr_debug("HDMI_UNI_PLL_SSC_CFG2 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SSC_CFG2, val); + + pr_debug("HDMI_UNI_PLL_SSC_CFG3 = 0x%x\n", ssc_tri_step); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SSC_CFG3, ssc_tri_step); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG0, 0x0A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG1, 0x04); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG5, 0x00); + + val = (kvco * vdd * 10000) / 6; + val += 500000; + val /= ten_power_six; + pr_debug("HDMI_UNI_PLL_CAL_CFG6 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG6, val & 0xFF); + + val = (kvco * vdd * 10000) / 6; + val -= ten_power_six; + val /= ten_power_six; + val = (val >> 8) & 0xFF; + pr_debug("HDMI_UNI_PLL_CAL_CFG7 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG7, val); + + val = (ref_clk * 5) / ten_power_six; + pr_debug("HDMI_UNI_PLL_CAL_CFG8 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, val); + + val = ((ref_clk * 5) / ten_power_six) >> 8; + pr_debug("HDMI_UNI_PLL_CAL_CFG9 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, val); + + vco_freq /= ten_power_six; + val = vco_freq & 0xFF; + pr_debug("HDMI_UNI_PLL_CAL_CFG10 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, val); + + val = vco_freq >> 8; + pr_debug("HDMI_UNI_PLL_CAL_CFG11 = 0x%x\n", val); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, val); +} /* hdmi_phy_pll_calculator */ + +static int hdmi_vco_set_rate(struct clk *c, unsigned long rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + void __iomem *pll_base; + void __iomem *phy_base; + unsigned int set_power_dwn = 0; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + if (hdmi_pll_res->pll_on) { + hdmi_vco_disable(c); + set_power_dwn = 1; + } + + pll_base = hdmi_pll_res->pll_base; + phy_base = hdmi_pll_res->phy_base; + + pr_debug("rate=%ld\n", rate); + + switch (rate) { + case 0: + break; + + case 756000000: + /* 640x480p60 */ + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x52); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0xB0); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0xF4); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 810000000: + /* 576p50/576i50 case */ + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x54); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0x18); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0x2A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x03); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 810900000: + /* 480p60/480i60 case */ + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x54); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x66); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0x1D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0x2A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x03); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 650000000: + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x4F); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x55); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0xED); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0x8A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 742500000: + /* + * 720p60/720p50/1080i60/1080i50 + * 1080p24/1080p30/1080p25 case + */ + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x52); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0x56); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0xE6); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 1080000000: + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x5B); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0x38); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 1342500000: + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x36); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x61); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0xF6); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0x3E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x05); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x05); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x11); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + case 1485000000: + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_REFCLK_CFG, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VCOLPF_CFG, 0x19); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFR_CFG, 0x0E); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC1_CFG, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LPFC2_CFG, 0x0D); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG0, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG1, 0x65); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG3, 0xAC); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_SDM_CFG4, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG1, 0x1A); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_LKDET_CFG2, 0x05); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV2_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_POSTDIV3_CFG, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG2, 0x01); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG8, 0x60); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG9, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG10, 0xCD); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_CAL_CFG11, 0x05); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x06); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x03); + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x02); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + udelay(200); + break; + + default: + pr_debug("Use pll settings calculator for rate=%ld\n", rate); + + MDSS_PLL_REG_W(phy_base, HDMI_PHY_GLB_CFG, 0x81); + hdmi_phy_pll_calculator(rate, hdmi_pll_res); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL0, 0x1F); + udelay(50); + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_GLB_CFG, 0x0F); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_PD_CTRL1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x10); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG0, 0xDB); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG1, 0x43); + + if (rate < 825000000) { + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x01); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x00); + } else if (rate >= 825000000 && rate < 1342500000) { + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x05); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x03); + } else { + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG2, 0x06); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_ANA_CFG3, 0x03); + } + + MDSS_PLL_REG_W(pll_base, HDMI_UNI_PLL_VREG_CFG, 0x04); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG0, 0xD0); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_DCC_CFG1, 0x1A); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG1, 0x00); + + if (rate < 825000000) + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x01); + else + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG2, 0x00); + + MDSS_PLL_REG_W(phy_base, HDMI_PHY_TXCAL_CFG3, 0x05); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_BIST_PATN0, 0x62); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_BIST_PATN1, 0x03); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_BIST_PATN2, 0x69); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_BIST_PATN3, 0x02); + + udelay(200); + + MDSS_PLL_REG_W(phy_base, HDMI_PHY_BIST_CFG1, 0x00); + MDSS_PLL_REG_W(phy_base, HDMI_PHY_BIST_CFG0, 0x00); + } + + /* Make sure writes complete before disabling iface clock */ + mb(); + + mdss_pll_resource_enable(hdmi_pll_res, false); + + if (set_power_dwn) + hdmi_vco_enable(c); + + vco->rate = rate; + vco->rate_set = true; + + return 0; +} /* hdmi_pll_set_rate */ + +/* HDMI PLL DIV CLK */ + +static unsigned long hdmi_vco_get_rate(struct clk *c) +{ + unsigned long freq = 0; + int rc; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + + if (is_gdsc_disabled(hdmi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + freq = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_UNI_PLL_CAL_CFG11) << 8 | + MDSS_PLL_REG_R(hdmi_pll_res->pll_base, HDMI_UNI_PLL_CAL_CFG10); + + switch (freq) { + case 742: + freq = 742500000; + break; + case 810: + if (MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_UNI_PLL_SDM_CFG3) == 0x18) + freq = 810000000; + else + freq = 810900000; + break; + case 1342: + freq = 1342500000; + break; + default: + freq *= 1000000; + } + mdss_pll_resource_enable(hdmi_pll_res, false); + + return freq; +} + +static long hdmi_vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + pr_debug("rrate=%ld\n", rrate); + + return rrate; +} + +static int hdmi_vco_prepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + int ret = 0; + + pr_debug("rate=%ld\n", vco->rate); + + if (!vco->rate_set && vco->rate) + ret = hdmi_vco_set_rate(c, vco->rate); + + return ret; +} + +static void hdmi_vco_unprepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + + vco->rate_set = false; +} + +static int hdmi_pll_lock_status(struct mdss_pll_resources *hdmi_pll_res) +{ + u32 status; + int pll_locked = 0; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic( + (hdmi_pll_res->phy_base + HDMI_PHY_STATUS), + status, ((status & BIT(0)) == 1), + HDMI_PLL_POLL_DELAY_US, + HDMI_PLL_POLL_TIMEOUT_US)) { + pr_debug("HDMI PLL status=%x failed to Lock\n", status); + pll_locked = 0; + } else { + pll_locked = 1; + } + mdss_pll_resource_enable(hdmi_pll_res, false); + + return pll_locked; +} + +static enum handoff hdmi_vco_handoff(struct clk *c) +{ + enum handoff ret = HANDOFF_DISABLED_CLK; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + + if (is_gdsc_disabled(hdmi_pll_res)) + return HANDOFF_DISABLED_CLK; + + if (mdss_pll_resource_enable(hdmi_pll_res, true)) { + pr_err("pll resource can't be enabled\n"); + return ret; + } + + hdmi_pll_res->handoff_resources = true; + + if (hdmi_pll_lock_status(hdmi_pll_res)) { + hdmi_pll_res->pll_on = true; + c->rate = hdmi_vco_get_rate(c); + ret = HANDOFF_ENABLED_CLK; + } else { + hdmi_pll_res->handoff_resources = false; + mdss_pll_resource_enable(hdmi_pll_res, false); + } + + pr_debug("done, ret=%d\n", ret); + return ret; +} + +static const struct clk_ops hdmi_vco_clk_ops = { + .enable = hdmi_vco_enable, + .set_rate = hdmi_vco_set_rate, + .get_rate = hdmi_vco_get_rate, + .round_rate = hdmi_vco_round_rate, + .prepare = hdmi_vco_prepare, + .unprepare = hdmi_vco_unprepare, + .disable = hdmi_vco_disable, + .handoff = hdmi_vco_handoff, +}; + +static struct hdmi_pll_vco_clk hdmi_vco_clk = { + .min_rate = 600000000, + .max_rate = 1800000000, + .c = { + .dbg_name = "hdmi_vco_clk", + .ops = &hdmi_vco_clk_ops, + CLK_INIT(hdmi_vco_clk.c), + }, +}; + +struct div_clk hdmipll_div1_clk = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &hdmi_vco_clk.c, + .dbg_name = "hdmipll_div1_clk", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(hdmipll_div1_clk.c), + }, +}; + +struct div_clk hdmipll_div2_clk = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &hdmi_vco_clk.c, + .dbg_name = "hdmipll_div2_clk", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(hdmipll_div2_clk.c), + }, +}; + +struct div_clk hdmipll_div4_clk = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &hdmi_vco_clk.c, + .dbg_name = "hdmipll_div4_clk", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(hdmipll_div4_clk.c), + }, +}; + +struct div_clk hdmipll_div6_clk = { + .data = { + .div = 6, + .min_div = 6, + .max_div = 6, + }, + .c = { + .parent = &hdmi_vco_clk.c, + .dbg_name = "hdmipll_div6_clk", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(hdmipll_div6_clk.c), + }, +}; + +static int hdmipll_set_mux_sel(struct mux_clk *clk, int mux_sel) +{ + struct mdss_pll_resources *hdmi_pll_res = clk->priv; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + pr_debug("mux_sel=%d\n", mux_sel); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, + HDMI_UNI_PLL_POSTDIV1_CFG, mux_sel); + mdss_pll_resource_enable(hdmi_pll_res, false); + + return 0; +} + +static int hdmipll_get_mux_sel(struct mux_clk *clk) +{ + int rc; + int mux_sel = 0; + struct mdss_pll_resources *hdmi_pll_res = clk->priv; + + if (is_gdsc_disabled(hdmi_pll_res)) + return 0; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + mux_sel = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_UNI_PLL_POSTDIV1_CFG); + mdss_pll_resource_enable(hdmi_pll_res, false); + mux_sel &= 0x03; + pr_debug("mux_sel=%d\n", mux_sel); + + return mux_sel; +} + +static struct clk_mux_ops hdmipll_mux_ops = { + .set_mux_sel = hdmipll_set_mux_sel, + .get_mux_sel = hdmipll_get_mux_sel, +}; + +static const struct clk_ops hdmi_mux_ops; + +static int hdmi_mux_prepare(struct clk *c) +{ + int ret = 0; + + if (c && c->ops && c->ops->set_rate) + ret = c->ops->set_rate(c, c->rate); + + return ret; +} + +struct mux_clk hdmipll_mux_clk = { + MUX_SRC_LIST( + { &hdmipll_div1_clk.c, 0 }, + { &hdmipll_div2_clk.c, 1 }, + { &hdmipll_div4_clk.c, 2 }, + { &hdmipll_div6_clk.c, 3 }, + ), + .ops = &hdmipll_mux_ops, + .c = { + .parent = &hdmipll_div1_clk.c, + .dbg_name = "hdmipll_mux_clk", + .ops = &hdmi_mux_ops, + CLK_INIT(hdmipll_mux_clk.c), + }, +}; + +struct div_clk hdmipll_clk_src = { + .data = { + .div = 5, + .min_div = 5, + .max_div = 5, + }, + .c = { + .parent = &hdmipll_mux_clk.c, + .dbg_name = "hdmipll_clk_src", + .ops = &clk_ops_div, + CLK_INIT(hdmipll_clk_src.c), + }, +}; + +static struct clk_lookup hdmipllcc_8974[] = { + CLK_LOOKUP("extp_clk_src", hdmipll_clk_src.c, + "fd8c0000.qcom,mmsscc-mdss"), +}; + +int hdmi_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP; + + /* Set client data for vco, mux and div clocks */ + hdmipll_clk_src.priv = pll_res; + hdmipll_mux_clk.priv = pll_res; + hdmipll_div1_clk.priv = pll_res; + hdmipll_div2_clk.priv = pll_res; + hdmipll_div4_clk.priv = pll_res; + hdmipll_div6_clk.priv = pll_res; + hdmi_vco_clk.priv = pll_res; + + /* Set hdmi mux clock operation */ + hdmi_mux_ops = clk_ops_gen_mux; + hdmi_mux_ops.prepare = hdmi_mux_prepare; + + rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8974, + ARRAY_SIZE(hdmipllcc_8974)); + if (rc) { + pr_err("Clock register failed rc=%d\n", rc); + rc = -EPROBE_DEFER; + } + + return rc; +} diff --git a/techpack/display/pll/hdmi_pll_28lpm.c b/techpack/display/pll/hdmi_pll_28lpm.c new file mode 100644 index 0000000000000000000000000000000000000000..a0fba39c2c23603491aba5a1aae9f102abec0263 --- /dev/null +++ b/techpack/display/pll/hdmi_pll_28lpm.c @@ -0,0 +1,790 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <dt-bindings/clock/mdss-28nm-pll-clk.h> +#include "pll_drv.h" +#include "hdmi_pll.h" + +/* HDMI PLL macros */ +#define HDMI_PHY_PLL_REFCLK_CFG (0x0400) +#define HDMI_PHY_PLL_CHRG_PUMP_CFG (0x0404) +#define HDMI_PHY_PLL_LOOP_FLT_CFG0 (0x0408) +#define HDMI_PHY_PLL_LOOP_FLT_CFG1 (0x040c) +#define HDMI_PHY_PLL_IDAC_ADJ_CFG (0x0410) +#define HDMI_PHY_PLL_I_VI_KVCO_CFG (0x0414) +#define HDMI_PHY_PLL_PWRDN_B (0x0418) +#define HDMI_PHY_PLL_SDM_CFG0 (0x041c) +#define HDMI_PHY_PLL_SDM_CFG1 (0x0420) +#define HDMI_PHY_PLL_SDM_CFG2 (0x0424) +#define HDMI_PHY_PLL_SDM_CFG3 (0x0428) +#define HDMI_PHY_PLL_SDM_CFG4 (0x042c) +#define HDMI_PHY_PLL_SSC_CFG0 (0x0430) +#define HDMI_PHY_PLL_SSC_CFG1 (0x0434) +#define HDMI_PHY_PLL_SSC_CFG2 (0x0438) +#define HDMI_PHY_PLL_SSC_CFG3 (0x043c) +#define HDMI_PHY_PLL_LOCKDET_CFG0 (0x0440) +#define HDMI_PHY_PLL_LOCKDET_CFG1 (0x0444) +#define HDMI_PHY_PLL_LOCKDET_CFG2 (0x0448) +#define HDMI_PHY_PLL_VCOCAL_CFG0 (0x044c) +#define HDMI_PHY_PLL_VCOCAL_CFG1 (0x0450) +#define HDMI_PHY_PLL_VCOCAL_CFG2 (0x0454) +#define HDMI_PHY_PLL_VCOCAL_CFG3 (0x0458) +#define HDMI_PHY_PLL_VCOCAL_CFG4 (0x045c) +#define HDMI_PHY_PLL_VCOCAL_CFG5 (0x0460) +#define HDMI_PHY_PLL_VCOCAL_CFG6 (0x0464) +#define HDMI_PHY_PLL_VCOCAL_CFG7 (0x0468) +#define HDMI_PHY_PLL_DEBUG_SEL (0x046c) +#define HDMI_PHY_PLL_MISC0 (0x0470) +#define HDMI_PHY_PLL_MISC1 (0x0474) +#define HDMI_PHY_PLL_MISC2 (0x0478) +#define HDMI_PHY_PLL_MISC3 (0x047c) +#define HDMI_PHY_PLL_MISC4 (0x0480) +#define HDMI_PHY_PLL_MISC5 (0x0484) +#define HDMI_PHY_PLL_MISC6 (0x0488) +#define HDMI_PHY_PLL_DEBUG_BUS0 (0x048c) +#define HDMI_PHY_PLL_DEBUG_BUS1 (0x0490) +#define HDMI_PHY_PLL_DEBUG_BUS2 (0x0494) +#define HDMI_PHY_PLL_STATUS0 (0x0498) +#define HDMI_PHY_PLL_STATUS1 (0x049c) + +#define HDMI_PHY_REG_0 (0x0000) +#define HDMI_PHY_REG_1 (0x0004) +#define HDMI_PHY_REG_2 (0x0008) +#define HDMI_PHY_REG_3 (0x000c) +#define HDMI_PHY_REG_4 (0x0010) +#define HDMI_PHY_REG_5 (0x0014) +#define HDMI_PHY_REG_6 (0x0018) +#define HDMI_PHY_REG_7 (0x001c) +#define HDMI_PHY_REG_8 (0x0020) +#define HDMI_PHY_REG_9 (0x0024) +#define HDMI_PHY_REG_10 (0x0028) +#define HDMI_PHY_REG_11 (0x002c) +#define HDMI_PHY_REG_12 (0x0030) +#define HDMI_PHY_REG_BIST_CFG (0x0034) +#define HDMI_PHY_DEBUG_BUS_SEL (0x0038) +#define HDMI_PHY_REG_MISC0 (0x003c) +#define HDMI_PHY_REG_13 (0x0040) +#define HDMI_PHY_REG_14 (0x0044) +#define HDMI_PHY_REG_15 (0x0048) + +/* HDMI PHY/PLL bit field macros */ +#define SW_RESET BIT(2) +#define SW_RESET_PLL BIT(0) +#define PWRDN_B BIT(7) + +#define PLL_PWRDN_B BIT(3) +#define REG_VTEST_EN BIT(2) +#define PD_PLL BIT(1) +#define PD_PLL_REG BIT(0) + + +#define HDMI_PLL_POLL_DELAY_US 50 +#define HDMI_PLL_POLL_TIMEOUT_US 500 + +static int hdmi_pll_lock_status(struct mdss_pll_resources *hdmi_pll_res) +{ + u32 status; + int pll_locked = 0; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic( + (hdmi_pll_res->pll_base + HDMI_PHY_PLL_STATUS0), + status, ((status & BIT(0)) == 1), + HDMI_PLL_POLL_DELAY_US, + HDMI_PLL_POLL_TIMEOUT_US)) { + pr_debug("HDMI PLL status=%x failed to Lock\n", status); + pll_locked = 0; + } else { + pr_debug("HDMI PLL locked\n"); + pll_locked = 1; + } + mdss_pll_resource_enable(hdmi_pll_res, false); + + return pll_locked; +} + +static void hdmi_pll_disable_28lpm(struct clk_hw *hw) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + u32 val; + + if (!hdmi_pll_res) { + pr_err("Invalid input parameter\n"); + return; + } + + val = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, HDMI_PHY_REG_12); + val &= (~PWRDN_B); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_PHY_REG_12, val); + + val = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, HDMI_PHY_PLL_PWRDN_B); + val |= PD_PLL; + val &= (~PLL_PWRDN_B); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, HDMI_PHY_PLL_PWRDN_B, val); + + /* Make sure HDMI PHY/PLL are powered down */ + wmb(); + +} /* hdmi_pll_disable_28lpm */ + +static int hdmi_pll_enable_28lpm(struct clk_hw *hw) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + void __iomem *pll_base; + u32 val; + int pll_lock_retry = 10; + + pll_base = hdmi_pll_res->pll_base; + + /* Assert PLL S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG2, 0x8d); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG1, 0x1a); + udelay(10); + /* De-assert PLL S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG2, 0x0d); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_1, 0xf2); + + udelay(10); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_2, 0x1f); + + val = MDSS_PLL_REG_R(pll_base, HDMI_PHY_REG_12); + val |= BIT(5); + /* Assert PHY S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_12, val); + val &= ~BIT(5); + udelay(10); + /* De-assert PHY S/W reset */ + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_12, val); + + val = MDSS_PLL_REG_R(pll_base, HDMI_PHY_REG_12); + val |= PWRDN_B; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_12, val); + + /* Wait 10 us for enabling global power for PHY */ + wmb(); + udelay(10); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_3, 0x20); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_4, 0x10); + + val = MDSS_PLL_REG_R(pll_base, HDMI_PHY_PLL_PWRDN_B); + val |= PLL_PWRDN_B; + val |= REG_VTEST_EN; + val &= ~PD_PLL; + val |= PD_PLL_REG; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_PWRDN_B, val); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_REG_2, 0x81); + + do { + if (!hdmi_pll_lock_status(hdmi_pll_res)) { + /* PLL has still not locked. + * Do a software reset and try again + * Assert PLL S/W reset first + */ + MDSS_PLL_REG_W(pll_base, + HDMI_PHY_PLL_LOCKDET_CFG2, 0x8d); + + /* Wait for a short time before de-asserting + * to allow the hardware to complete its job. + * This much of delay should be fine for hardware + * to assert and de-assert. + */ + udelay(10); + MDSS_PLL_REG_W(pll_base, + HDMI_PHY_PLL_LOCKDET_CFG2, 0xd); + + /* Wait for a short duration for the PLL calibration + * before checking if the PLL gets locked + */ + udelay(350); + } else { + pr_debug("HDMI PLL locked\n"); + break; + } + + } while (--pll_lock_retry); + + if (!pll_lock_retry) { + pr_err("HDMI PLL not locked\n"); + hdmi_pll_disable_28lpm(hw); + return -EAGAIN; + } + + return 0; +} /* hdmi_pll_enable_28lpm */ + +static void hdmi_phy_pll_calculator_28lpm(unsigned long vco_rate, + struct mdss_pll_resources *hdmi_pll_res) +{ + u32 ref_clk = 19200000; + u32 integer_mode = 0; + u32 ref_clk_multiplier = integer_mode == 0 ? 2 : 1; + u32 int_ref_clk_freq = ref_clk * ref_clk_multiplier; + u32 refclk_cfg = 0; + u32 ten_power_six = 1000000; + u64 multiplier_q = 0; + u64 multiplier_r = 0; + u32 lf_cfg0 = 0; + u32 lf_cfg1 = 0; + u64 vco_cfg0 = 0; + u64 vco_cfg4 = 0; + u64 sdm_cfg0 = 0; + u64 sdm_cfg1 = 0; + u64 sdm_cfg2 = 0; + u32 val1 = 0; + u32 val2 = 0; + u32 val3 = 0; + void __iomem *pll_base = hdmi_pll_res->pll_base; + + multiplier_q = vco_rate; + multiplier_r = do_div(multiplier_q, int_ref_clk_freq); + + lf_cfg0 = multiplier_q > 30 ? 0 : (multiplier_q > 16 ? 16 : 32); + lf_cfg0 += integer_mode; + + lf_cfg1 = multiplier_q > 30 ? 0xc3 : (multiplier_q > 16 ? 0xbb : 0xf9); + + vco_cfg0 = vco_rate / ten_power_six; + vco_cfg4 = ((ref_clk * 5) / ten_power_six) - 1; + + sdm_cfg0 = (integer_mode * 64) + multiplier_q - 1; + sdm_cfg1 = 64 + multiplier_q - 1; + + sdm_cfg2 = (multiplier_r) * 65536; + do_div(sdm_cfg2, int_ref_clk_freq); + + pr_debug("lf_cfg0 = 0x%x lf_cfg1 = 0x%x\n", lf_cfg0, lf_cfg1); + pr_debug("vco_cfg0 = 0x%llx vco_cfg4 = 0x%llx\n", vco_cfg0, vco_cfg4); + pr_debug("sdm_cfg0 = 0x%llx sdm_cfg1 = 0x%llx sdm_cfg2 = 0x%llx\n", + sdm_cfg0, sdm_cfg1, sdm_cfg2); + + refclk_cfg = MDSS_PLL_REG_R(pll_base, HDMI_PHY_PLL_REFCLK_CFG); + refclk_cfg &= ~0xf; + refclk_cfg |= (ref_clk_multiplier == 2) ? 0x8 + : (ref_clk_multiplier == 1) ? 0 : 0x2; + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_REFCLK_CFG, refclk_cfg); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_CHRG_PUMP_CFG, 0x02); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOOP_FLT_CFG0, lf_cfg0); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOOP_FLT_CFG1, lf_cfg1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_IDAC_ADJ_CFG, 0x2c); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_I_VI_KVCO_CFG, 0x06); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_PWRDN_B, 0x0a); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG0, sdm_cfg0); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG1, sdm_cfg1); + + val1 = sdm_cfg2 & 0xff; + val2 = (sdm_cfg2 >> 8) & 0xff; + val3 = (sdm_cfg2 >> 16) & 0xff; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG2, val1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG3, val2); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SDM_CFG4, val3); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG0, 0x9a); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG1, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG2, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_SSC_CFG3, 0x00); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG0, 0x10); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG1, 0x1a); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_LOCKDET_CFG2, 0x0d); + + val1 = vco_cfg0 & 0xff; + val2 = (vco_cfg0 >> 8) & 0xff; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG0, val1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG1, val2); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG2, 0x3b); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG3, 0x00); + + val1 = vco_cfg4 & 0xff; + val2 = (vco_cfg4 >> 8) & 0xff; + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG4, val1); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG5, val2); + + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG6, 0x33); + MDSS_PLL_REG_W(pll_base, HDMI_PHY_PLL_VCOCAL_CFG7, 0x03); + +} + +int hdmi_vco_set_rate_28lpm(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + void __iomem *pll_base; + int rc; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + if (hdmi_pll_res->pll_on) + return 0; + + pll_base = hdmi_pll_res->pll_base; + + pr_debug("rate=%ld\n", rate); + + hdmi_phy_pll_calculator_28lpm(rate, hdmi_pll_res); + + /* Make sure writes complete before disabling iface clock */ + wmb(); + + vco->rate = rate; + hdmi_pll_res->vco_current_rate = rate; + + mdss_pll_resource_enable(hdmi_pll_res, false); + + + return 0; +} /* hdmi_pll_set_rate */ + +static unsigned long hdmi_vco_get_rate(struct hdmi_pll_vco_clk *vco) +{ + unsigned long freq = 0; + int rc = 0; + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("Failed to enable hdmi pll resources\n"); + return 0; + } + + freq = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_VCOCAL_CFG1) << 8 | + MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_VCOCAL_CFG0); + + switch (freq) { + case 742: + freq = 742500000; + break; + case 810: + if (MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_SDM_CFG3) == 0x18) + freq = 810000000; + else + freq = 810900000; + break; + case 1342: + freq = 1342500000; + break; + default: + freq *= 1000000; + } + mdss_pll_resource_enable(hdmi_pll_res, false); + + return freq; +} + +long hdmi_vco_round_rate_28lpm(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long rrate = rate; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + *parent_rate = rrate; + pr_debug("rrate=%ld\n", rrate); + + return rrate; +} + +int hdmi_vco_prepare_28lpm(struct clk_hw *hw) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_res = vco->priv; + + pr_debug("rate=%ld\n", clk_hw_get_rate(hw)); + rc = mdss_pll_resource_enable(hdmi_res, true); + if (rc) { + pr_err("Failed to enable mdss HDMI pll resources\n"); + goto error; + } + + if ((hdmi_res->vco_cached_rate != 0) + && (hdmi_res->vco_cached_rate == clk_hw_get_rate(hw))) { + rc = vco->hw.init->ops->set_rate(hw, + hdmi_res->vco_cached_rate, hdmi_res->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, hdmi_res->index); + mdss_pll_resource_enable(hdmi_res, false); + goto error; + } + } + + rc = hdmi_pll_enable_28lpm(hw); + if (rc) { + mdss_pll_resource_enable(hdmi_res, false); + pr_err("ndx=%d failed to enable hdmi pll\n", + hdmi_res->index); + goto error; + } + + mdss_pll_resource_enable(hdmi_res, false); + pr_debug("HDMI PLL enabled\n"); +error: + return rc; +} + +void hdmi_vco_unprepare_28lpm(struct clk_hw *hw) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_res = vco->priv; + + if (!hdmi_res) { + pr_err("Invalid input parameter\n"); + return; + } + + if (!hdmi_res->pll_on && + mdss_pll_resource_enable(hdmi_res, true)) { + pr_err("pll resource can't be enabled\n"); + return; + } + + hdmi_res->vco_cached_rate = clk_hw_get_rate(hw); + hdmi_pll_disable_28lpm(hw); + + hdmi_res->handoff_resources = false; + mdss_pll_resource_enable(hdmi_res, false); + hdmi_res->pll_on = false; + + pr_debug("HDMI PLL disabled\n"); +} + + +unsigned long hdmi_vco_recalc_rate_28lpm(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk_hw(hw); + struct mdss_pll_resources *hdmi_pll_res = vco->priv; + u64 vco_rate = 0; + + if (!hdmi_pll_res) { + pr_err("dsi pll resources not available\n"); + return 0; + } + + if (hdmi_pll_res->vco_current_rate) { + vco_rate = (unsigned long)hdmi_pll_res->vco_current_rate; + pr_debug("vco_rate=%lld\n", vco_rate); + return vco_rate; + } + + if (is_gdsc_disabled(hdmi_pll_res)) + return 0; + + if (mdss_pll_resource_enable(hdmi_pll_res, true)) { + pr_err("Failed to enable hdmi pll resources\n"); + return 0; + } + + if (hdmi_pll_lock_status(hdmi_pll_res)) { + hdmi_pll_res->handoff_resources = true; + hdmi_pll_res->pll_on = true; + vco_rate = hdmi_vco_get_rate(vco); + } else { + hdmi_pll_res->handoff_resources = false; + mdss_pll_resource_enable(hdmi_pll_res, false); + } + + pr_debug("vco_rate = %lld\n", vco_rate); + + return (unsigned long)vco_rate; +} + +static int hdmi_mux_set_parent(void *context, unsigned int reg, + unsigned int mux_sel) +{ + struct mdss_pll_resources *hdmi_pll_res = context; + int rc = 0; + u32 reg_val = 0; + const u32 div_4 = 0x20; + const u32 div_6 = 0x30; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + pr_err("Failed to enable hdmi pll resources\n"); + return rc; + } + + /* + * divsel_six is preferred over divsel_four to keep + * vco range within goal limits to maintain margin. + * To achieve this, its precedence order is toggled + * at mux level. So reverse toggle the mux_sel value + * here. + */ + switch (mux_sel) { + case 0x20: /* intended divider is divsel_six */ + mux_sel = div_6; + break; + case 0x30: /* intended divider is divsel_four */ + mux_sel = div_4; + break; + } + pr_debug("mux_sel = %d\n", mux_sel); + + reg_val = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_REFCLK_CFG); + reg_val &= ~0x70; + reg_val |= (mux_sel & 0x70); + pr_debug("pll_refclk_cfg = 0x%x\n", reg_val); + MDSS_PLL_REG_W(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_REFCLK_CFG, reg_val); + + (void)mdss_pll_resource_enable(hdmi_pll_res, false); + + return 0; +} + +static int hdmi_mux_get_parent(void *context, unsigned int reg, + unsigned int *val) +{ + int rc = 0; + int mux_sel = 0; + struct mdss_pll_resources *hdmi_pll_res = context; + + rc = mdss_pll_resource_enable(hdmi_pll_res, true); + if (rc) { + *val = 0; + pr_err("Failed to enable hdmi pll resources\n"); + } else { + mux_sel = MDSS_PLL_REG_R(hdmi_pll_res->pll_base, + HDMI_PHY_PLL_REFCLK_CFG); + mux_sel &= 0x70; + *val = mux_sel; + pr_debug("mux_sel = %d\n", *val); + } + + (void)mdss_pll_resource_enable(hdmi_pll_res, false); + + return rc; +} + +static struct regmap_config hdmi_pll_28lpm_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x49c, +}; + +static struct regmap_bus hdmi_pclk_src_mux_regmap_ops = { + .reg_write = hdmi_mux_set_parent, + .reg_read = hdmi_mux_get_parent, +}; + +/* Op structures */ +static const struct clk_ops hdmi_28lpm_vco_clk_ops = { + .recalc_rate = hdmi_vco_recalc_rate_28lpm, + .set_rate = hdmi_vco_set_rate_28lpm, + .round_rate = hdmi_vco_round_rate_28lpm, + .prepare = hdmi_vco_prepare_28lpm, + .unprepare = hdmi_vco_unprepare_28lpm, +}; + +static struct hdmi_pll_vco_clk hdmi_vco_clk = { + .min_rate = 540000000, + .max_rate = 1125000000, + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_clk", + .parent_names = (const char *[]){ "cxo" }, + .num_parents = 1, + .ops = &hdmi_28lpm_vco_clk_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_one_clk_src = { + .div = 1, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_one_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_two_clk_src = { + .div = 2, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_two_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_four_clk_src = { + .div = 4, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_four_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_fixed_factor hdmi_vco_divsel_six_clk_src = { + .div = 6, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_vco_divsel_six_clk_src", + .parent_names = + (const char *[]){ "hdmi_vco_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_regmap_mux hdmi_pclk_src_mux = { + .reg = HDMI_PHY_PLL_REFCLK_CFG, + .shift = 4, + .width = 2, + + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "hdmi_pclk_src_mux", + .parent_names = + (const char *[]){"hdmi_vco_divsel_one_clk_src", + "hdmi_vco_divsel_two_clk_src", + "hdmi_vco_divsel_six_clk_src", + "hdmi_vco_divsel_four_clk_src"}, + .num_parents = 4, + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_fixed_factor hdmi_pclk_src = { + .div = 5, + .mult = 1, + + .hw.init = &(struct clk_init_data){ + .name = "hdmi_phy_pll_clk", + .parent_names = + (const char *[]){ "hdmi_pclk_src_mux" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static struct clk_hw *mdss_hdmi_pllcc_28lpm[] = { + [HDMI_VCO_CLK] = &hdmi_vco_clk.hw, + [HDMI_VCO_DIVIDED_1_CLK_SRC] = &hdmi_vco_divsel_one_clk_src.hw, + [HDMI_VCO_DIVIDED_TWO_CLK_SRC] = &hdmi_vco_divsel_two_clk_src.hw, + [HDMI_VCO_DIVIDED_FOUR_CLK_SRC] = &hdmi_vco_divsel_four_clk_src.hw, + [HDMI_VCO_DIVIDED_SIX_CLK_SRC] = &hdmi_vco_divsel_six_clk_src.hw, + [HDMI_PCLK_SRC_MUX] = &hdmi_pclk_src_mux.clkr.hw, + [HDMI_PCLK_SRC] = &hdmi_pclk_src.hw, +}; + +int hdmi_pll_clock_register_28lpm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = -ENOTSUPP, i; + struct clk *clk; + struct clk_onecell_data *clk_data; + int num_clks = ARRAY_SIZE(mdss_hdmi_pllcc_28lpm); + struct regmap *regmap; + + if (!pdev || !pdev->dev.of_node || + !pll_res || !pll_res->pll_base) { + pr_err("Invalid input parameters\n"); + return -EPROBE_DEFER; + } + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) { + devm_kfree(&pdev->dev, clk_data); + return -ENOMEM; + } + clk_data->clk_num = num_clks; + + /* Set client data for vco, mux and div clocks */ + regmap = devm_regmap_init(&pdev->dev, &hdmi_pclk_src_mux_regmap_ops, + pll_res, &hdmi_pll_28lpm_cfg); + hdmi_pclk_src_mux.clkr.regmap = regmap; + + hdmi_vco_clk.priv = pll_res; + + for (i = HDMI_VCO_CLK; i <= HDMI_PCLK_SRC; i++) { + pr_debug("reg clk: %d index: %d\n", i, pll_res->index); + clk = devm_clk_register(&pdev->dev, + mdss_hdmi_pllcc_28lpm[i]); + if (IS_ERR(clk)) { + pr_err("clk registration failed for HDMI: %d\n", + pll_res->index); + rc = -EINVAL; + goto clk_reg_fail; + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, clk_data); + if (rc) { + pr_err("%s: Clock register failed rc=%d\n", __func__, rc); + rc = -EPROBE_DEFER; + } else { + pr_debug("%s SUCCESS\n", __func__); + rc = 0; + } + return rc; +clk_reg_fail: + return rc; +} diff --git a/techpack/display/pll/hdmi_pll_8996.c b/techpack/display/pll/hdmi_pll_8996.c new file mode 100644 index 0000000000000000000000000000000000000000..04e93fd9504219d9552d3ab0c4d6ba32f0fec2b5 --- /dev/null +++ b/techpack/display/pll/hdmi_pll_8996.c @@ -0,0 +1,2675 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> +#include <dt-bindings/clock/msm-clocks-8996.h> + +#include "pll_drv.h" +#include "hdmi_pll.h" + +/* CONSTANTS */ +#define HDMI_BIT_CLK_TO_PIX_CLK_RATIO 10 +#define HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD 3400000000UL +#define HDMI_DIG_FREQ_BIT_CLK_THRESHOLD 1500000000UL +#define HDMI_MID_FREQ_BIT_CLK_THRESHOLD 750000000 +#define HDMI_CLKS_PLL_DIVSEL 0 +#define HDMI_CORECLK_DIV 5 +#define HDMI_REF_CLOCK 19200000 +#define HDMI_64B_ERR_VAL 0xFFFFFFFFFFFFFFFF +#define HDMI_VERSION_8996_V1 1 +#define HDMI_VERSION_8996_V2 2 +#define HDMI_VERSION_8996_V3 3 +#define HDMI_VERSION_8996_V3_1_8 4 + +#define HDMI_VCO_MAX_FREQ 12000000000 +#define HDMI_VCO_MIN_FREQ 8000000000 +#define HDMI_2400MHZ_BIT_CLK_HZ 2400000000UL +#define HDMI_2250MHZ_BIT_CLK_HZ 2250000000UL +#define HDMI_2000MHZ_BIT_CLK_HZ 2000000000UL +#define HDMI_1700MHZ_BIT_CLK_HZ 1700000000UL +#define HDMI_1200MHZ_BIT_CLK_HZ 1200000000UL +#define HDMI_1334MHZ_BIT_CLK_HZ 1334000000UL +#define HDMI_1000MHZ_BIT_CLK_HZ 1000000000UL +#define HDMI_850MHZ_BIT_CLK_HZ 850000000 +#define HDMI_667MHZ_BIT_CLK_HZ 667000000 +#define HDMI_600MHZ_BIT_CLK_HZ 600000000 +#define HDMI_500MHZ_BIT_CLK_HZ 500000000 +#define HDMI_450MHZ_BIT_CLK_HZ 450000000 +#define HDMI_334MHZ_BIT_CLK_HZ 334000000 +#define HDMI_300MHZ_BIT_CLK_HZ 300000000 +#define HDMI_282MHZ_BIT_CLK_HZ 282000000 +#define HDMI_250MHZ_BIT_CLK_HZ 250000000 +#define HDMI_KHZ_TO_HZ 1000 + +/* PLL REGISTERS */ +#define QSERDES_COM_ATB_SEL1 (0x000) +#define QSERDES_COM_ATB_SEL2 (0x004) +#define QSERDES_COM_FREQ_UPDATE (0x008) +#define QSERDES_COM_BG_TIMER (0x00C) +#define QSERDES_COM_SSC_EN_CENTER (0x010) +#define QSERDES_COM_SSC_ADJ_PER1 (0x014) +#define QSERDES_COM_SSC_ADJ_PER2 (0x018) +#define QSERDES_COM_SSC_PER1 (0x01C) +#define QSERDES_COM_SSC_PER2 (0x020) +#define QSERDES_COM_SSC_STEP_SIZE1 (0x024) +#define QSERDES_COM_SSC_STEP_SIZE2 (0x028) +#define QSERDES_COM_POST_DIV (0x02C) +#define QSERDES_COM_POST_DIV_MUX (0x030) +#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x034) +#define QSERDES_COM_CLK_ENABLE1 (0x038) +#define QSERDES_COM_SYS_CLK_CTRL (0x03C) +#define QSERDES_COM_SYSCLK_BUF_ENABLE (0x040) +#define QSERDES_COM_PLL_EN (0x044) +#define QSERDES_COM_PLL_IVCO (0x048) +#define QSERDES_COM_LOCK_CMP1_MODE0 (0x04C) +#define QSERDES_COM_LOCK_CMP2_MODE0 (0x050) +#define QSERDES_COM_LOCK_CMP3_MODE0 (0x054) +#define QSERDES_COM_LOCK_CMP1_MODE1 (0x058) +#define QSERDES_COM_LOCK_CMP2_MODE1 (0x05C) +#define QSERDES_COM_LOCK_CMP3_MODE1 (0x060) +#define QSERDES_COM_LOCK_CMP1_MODE2 (0x064) +#define QSERDES_COM_CMN_RSVD0 (0x064) +#define QSERDES_COM_LOCK_CMP2_MODE2 (0x068) +#define QSERDES_COM_EP_CLOCK_DETECT_CTRL (0x068) +#define QSERDES_COM_LOCK_CMP3_MODE2 (0x06C) +#define QSERDES_COM_SYSCLK_DET_COMP_STATUS (0x06C) +#define QSERDES_COM_BG_TRIM (0x070) +#define QSERDES_COM_CLK_EP_DIV (0x074) +#define QSERDES_COM_CP_CTRL_MODE0 (0x078) +#define QSERDES_COM_CP_CTRL_MODE1 (0x07C) +#define QSERDES_COM_CP_CTRL_MODE2 (0x080) +#define QSERDES_COM_CMN_RSVD1 (0x080) +#define QSERDES_COM_PLL_RCTRL_MODE0 (0x084) +#define QSERDES_COM_PLL_RCTRL_MODE1 (0x088) +#define QSERDES_COM_PLL_RCTRL_MODE2 (0x08C) +#define QSERDES_COM_CMN_RSVD2 (0x08C) +#define QSERDES_COM_PLL_CCTRL_MODE0 (0x090) +#define QSERDES_COM_PLL_CCTRL_MODE1 (0x094) +#define QSERDES_COM_PLL_CCTRL_MODE2 (0x098) +#define QSERDES_COM_CMN_RSVD3 (0x098) +#define QSERDES_COM_PLL_CNTRL (0x09C) +#define QSERDES_COM_PHASE_SEL_CTRL (0x0A0) +#define QSERDES_COM_PHASE_SEL_DC (0x0A4) +#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL (0x0A8) +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM (0x0A8) +#define QSERDES_COM_SYSCLK_EN_SEL (0x0AC) +#define QSERDES_COM_CML_SYSCLK_SEL (0x0B0) +#define QSERDES_COM_RESETSM_CNTRL (0x0B4) +#define QSERDES_COM_RESETSM_CNTRL2 (0x0B8) +#define QSERDES_COM_RESTRIM_CTRL (0x0BC) +#define QSERDES_COM_RESTRIM_CTRL2 (0x0C0) +#define QSERDES_COM_RESCODE_DIV_NUM (0x0C4) +#define QSERDES_COM_LOCK_CMP_EN (0x0C8) +#define QSERDES_COM_LOCK_CMP_CFG (0x0CC) +#define QSERDES_COM_DEC_START_MODE0 (0x0D0) +#define QSERDES_COM_DEC_START_MODE1 (0x0D4) +#define QSERDES_COM_DEC_START_MODE2 (0x0D8) +#define QSERDES_COM_VCOCAL_DEADMAN_CTRL (0x0D8) +#define QSERDES_COM_DIV_FRAC_START1_MODE0 (0x0DC) +#define QSERDES_COM_DIV_FRAC_START2_MODE0 (0x0E0) +#define QSERDES_COM_DIV_FRAC_START3_MODE0 (0x0E4) +#define QSERDES_COM_DIV_FRAC_START1_MODE1 (0x0E8) +#define QSERDES_COM_DIV_FRAC_START2_MODE1 (0x0EC) +#define QSERDES_COM_DIV_FRAC_START3_MODE1 (0x0F0) +#define QSERDES_COM_DIV_FRAC_START1_MODE2 (0x0F4) +#define QSERDES_COM_VCO_TUNE_MINVAL1 (0x0F4) +#define QSERDES_COM_DIV_FRAC_START2_MODE2 (0x0F8) +#define QSERDES_COM_VCO_TUNE_MINVAL2 (0x0F8) +#define QSERDES_COM_DIV_FRAC_START3_MODE2 (0x0FC) +#define QSERDES_COM_CMN_RSVD4 (0x0FC) +#define QSERDES_COM_INTEGLOOP_INITVAL (0x100) +#define QSERDES_COM_INTEGLOOP_EN (0x104) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 (0x108) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 (0x10C) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 (0x110) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 (0x114) +#define QSERDES_COM_INTEGLOOP_GAIN0_MODE2 (0x118) +#define QSERDES_COM_VCO_TUNE_MAXVAL1 (0x118) +#define QSERDES_COM_INTEGLOOP_GAIN1_MODE2 (0x11C) +#define QSERDES_COM_VCO_TUNE_MAXVAL2 (0x11C) +#define QSERDES_COM_RES_TRIM_CONTROL2 (0x120) +#define QSERDES_COM_VCO_TUNE_CTRL (0x124) +#define QSERDES_COM_VCO_TUNE_MAP (0x128) +#define QSERDES_COM_VCO_TUNE1_MODE0 (0x12C) +#define QSERDES_COM_VCO_TUNE2_MODE0 (0x130) +#define QSERDES_COM_VCO_TUNE1_MODE1 (0x134) +#define QSERDES_COM_VCO_TUNE2_MODE1 (0x138) +#define QSERDES_COM_VCO_TUNE1_MODE2 (0x13C) +#define QSERDES_COM_VCO_TUNE_INITVAL1 (0x13C) +#define QSERDES_COM_VCO_TUNE2_MODE2 (0x140) +#define QSERDES_COM_VCO_TUNE_INITVAL2 (0x140) +#define QSERDES_COM_VCO_TUNE_TIMER1 (0x144) +#define QSERDES_COM_VCO_TUNE_TIMER2 (0x148) +#define QSERDES_COM_SAR (0x14C) +#define QSERDES_COM_SAR_CLK (0x150) +#define QSERDES_COM_SAR_CODE_OUT_STATUS (0x154) +#define QSERDES_COM_SAR_CODE_READY_STATUS (0x158) +#define QSERDES_COM_CMN_STATUS (0x15C) +#define QSERDES_COM_RESET_SM_STATUS (0x160) +#define QSERDES_COM_RESTRIM_CODE_STATUS (0x164) +#define QSERDES_COM_PLLCAL_CODE1_STATUS (0x168) +#define QSERDES_COM_PLLCAL_CODE2_STATUS (0x16C) +#define QSERDES_COM_BG_CTRL (0x170) +#define QSERDES_COM_CLK_SELECT (0x174) +#define QSERDES_COM_HSCLK_SEL (0x178) +#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS (0x17C) +#define QSERDES_COM_PLL_ANALOG (0x180) +#define QSERDES_COM_CORECLK_DIV (0x184) +#define QSERDES_COM_SW_RESET (0x188) +#define QSERDES_COM_CORE_CLK_EN (0x18C) +#define QSERDES_COM_C_READY_STATUS (0x190) +#define QSERDES_COM_CMN_CONFIG (0x194) +#define QSERDES_COM_CMN_RATE_OVERRIDE (0x198) +#define QSERDES_COM_SVS_MODE_CLK_SEL (0x19C) +#define QSERDES_COM_DEBUG_BUS0 (0x1A0) +#define QSERDES_COM_DEBUG_BUS1 (0x1A4) +#define QSERDES_COM_DEBUG_BUS2 (0x1A8) +#define QSERDES_COM_DEBUG_BUS3 (0x1AC) +#define QSERDES_COM_DEBUG_BUS_SEL (0x1B0) +#define QSERDES_COM_CMN_MISC1 (0x1B4) +#define QSERDES_COM_CMN_MISC2 (0x1B8) +#define QSERDES_COM_CORECLK_DIV_MODE1 (0x1BC) +#define QSERDES_COM_CORECLK_DIV_MODE2 (0x1C0) +#define QSERDES_COM_CMN_RSVD5 (0x1C0) + +/* Tx Channel base addresses */ +#define HDMI_TX_L0_BASE_OFFSET (0x400) +#define HDMI_TX_L1_BASE_OFFSET (0x600) +#define HDMI_TX_L2_BASE_OFFSET (0x800) +#define HDMI_TX_L3_BASE_OFFSET (0xA00) + +/* Tx Channel PHY registers */ +#define QSERDES_TX_L0_BIST_MODE_LANENO (0x000) +#define QSERDES_TX_L0_BIST_INVERT (0x004) +#define QSERDES_TX_L0_CLKBUF_ENABLE (0x008) +#define QSERDES_TX_L0_CMN_CONTROL_ONE (0x00C) +#define QSERDES_TX_L0_CMN_CONTROL_TWO (0x010) +#define QSERDES_TX_L0_CMN_CONTROL_THREE (0x014) +#define QSERDES_TX_L0_TX_EMP_POST1_LVL (0x018) +#define QSERDES_TX_L0_TX_POST2_EMPH (0x01C) +#define QSERDES_TX_L0_TX_BOOST_LVL_UP_DN (0x020) +#define QSERDES_TX_L0_HP_PD_ENABLES (0x024) +#define QSERDES_TX_L0_TX_IDLE_LVL_LARGE_AMP (0x028) +#define QSERDES_TX_L0_TX_DRV_LVL (0x02C) +#define QSERDES_TX_L0_TX_DRV_LVL_OFFSET (0x030) +#define QSERDES_TX_L0_RESET_TSYNC_EN (0x034) +#define QSERDES_TX_L0_PRE_STALL_LDO_BOOST_EN (0x038) +#define QSERDES_TX_L0_TX_BAND (0x03C) +#define QSERDES_TX_L0_SLEW_CNTL (0x040) +#define QSERDES_TX_L0_INTERFACE_SELECT (0x044) +#define QSERDES_TX_L0_LPB_EN (0x048) +#define QSERDES_TX_L0_RES_CODE_LANE_TX (0x04C) +#define QSERDES_TX_L0_RES_CODE_LANE_RX (0x050) +#define QSERDES_TX_L0_RES_CODE_LANE_OFFSET (0x054) +#define QSERDES_TX_L0_PERL_LENGTH1 (0x058) +#define QSERDES_TX_L0_PERL_LENGTH2 (0x05C) +#define QSERDES_TX_L0_SERDES_BYP_EN_OUT (0x060) +#define QSERDES_TX_L0_DEBUG_BUS_SEL (0x064) +#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN (0x068) +#define QSERDES_TX_L0_TX_POL_INV (0x06C) +#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN (0x070) +#define QSERDES_TX_L0_BIST_PATTERN1 (0x074) +#define QSERDES_TX_L0_BIST_PATTERN2 (0x078) +#define QSERDES_TX_L0_BIST_PATTERN3 (0x07C) +#define QSERDES_TX_L0_BIST_PATTERN4 (0x080) +#define QSERDES_TX_L0_BIST_PATTERN5 (0x084) +#define QSERDES_TX_L0_BIST_PATTERN6 (0x088) +#define QSERDES_TX_L0_BIST_PATTERN7 (0x08C) +#define QSERDES_TX_L0_BIST_PATTERN8 (0x090) +#define QSERDES_TX_L0_LANE_MODE (0x094) +#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE (0x098) +#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION (0x09C) +#define QSERDES_TX_L0_ATB_SEL1 (0x0A0) +#define QSERDES_TX_L0_ATB_SEL2 (0x0A4) +#define QSERDES_TX_L0_RCV_DETECT_LVL (0x0A8) +#define QSERDES_TX_L0_RCV_DETECT_LVL_2 (0x0AC) +#define QSERDES_TX_L0_PRBS_SEED1 (0x0B0) +#define QSERDES_TX_L0_PRBS_SEED2 (0x0B4) +#define QSERDES_TX_L0_PRBS_SEED3 (0x0B8) +#define QSERDES_TX_L0_PRBS_SEED4 (0x0BC) +#define QSERDES_TX_L0_RESET_GEN (0x0C0) +#define QSERDES_TX_L0_RESET_GEN_MUXES (0x0C4) +#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN (0x0C8) +#define QSERDES_TX_L0_TX_INTERFACE_MODE (0x0CC) +#define QSERDES_TX_L0_PWM_CTRL (0x0D0) +#define QSERDES_TX_L0_PWM_ENCODED_OR_DATA (0x0D4) +#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND2 (0x0D8) +#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND2 (0x0DC) +#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND2 (0x0E0) +#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND2 (0x0E4) +#define QSERDES_TX_L0_PWM_GEAR_1_DIVIDER_BAND0_1 (0x0E8) +#define QSERDES_TX_L0_PWM_GEAR_2_DIVIDER_BAND0_1 (0x0EC) +#define QSERDES_TX_L0_PWM_GEAR_3_DIVIDER_BAND0_1 (0x0F0) +#define QSERDES_TX_L0_PWM_GEAR_4_DIVIDER_BAND0_1 (0x0F4) +#define QSERDES_TX_L0_VMODE_CTRL1 (0x0F8) +#define QSERDES_TX_L0_VMODE_CTRL2 (0x0FC) +#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL (0x100) +#define QSERDES_TX_L0_BIST_STATUS (0x104) +#define QSERDES_TX_L0_BIST_ERROR_COUNT1 (0x108) +#define QSERDES_TX_L0_BIST_ERROR_COUNT2 (0x10C) +#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV (0x110) + +/* HDMI PHY REGISTERS */ +#define HDMI_PHY_BASE_OFFSET (0xC00) + +#define HDMI_PHY_CFG (0x00) +#define HDMI_PHY_PD_CTL (0x04) +#define HDMI_PHY_MODE (0x08) +#define HDMI_PHY_MISR_CLEAR (0x0C) +#define HDMI_PHY_TX0_TX1_BIST_CFG0 (0x10) +#define HDMI_PHY_TX0_TX1_BIST_CFG1 (0x14) +#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0 (0x18) +#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1 (0x1C) +#define HDMI_PHY_TX0_TX1_BIST_PATTERN0 (0x20) +#define HDMI_PHY_TX0_TX1_BIST_PATTERN1 (0x24) +#define HDMI_PHY_TX2_TX3_BIST_CFG0 (0x28) +#define HDMI_PHY_TX2_TX3_BIST_CFG1 (0x2C) +#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0 (0x30) +#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1 (0x34) +#define HDMI_PHY_TX2_TX3_BIST_PATTERN0 (0x38) +#define HDMI_PHY_TX2_TX3_BIST_PATTERN1 (0x3C) +#define HDMI_PHY_DEBUG_BUS_SEL (0x40) +#define HDMI_PHY_TXCAL_CFG0 (0x44) +#define HDMI_PHY_TXCAL_CFG1 (0x48) +#define HDMI_PHY_TX0_TX1_LANE_CTL (0x4C) +#define HDMI_PHY_TX2_TX3_LANE_CTL (0x50) +#define HDMI_PHY_LANE_BIST_CONFIG (0x54) +#define HDMI_PHY_CLOCK (0x58) +#define HDMI_PHY_MISC1 (0x5C) +#define HDMI_PHY_MISC2 (0x60) +#define HDMI_PHY_TX0_TX1_BIST_STATUS0 (0x64) +#define HDMI_PHY_TX0_TX1_BIST_STATUS1 (0x68) +#define HDMI_PHY_TX0_TX1_BIST_STATUS2 (0x6C) +#define HDMI_PHY_TX2_TX3_BIST_STATUS0 (0x70) +#define HDMI_PHY_TX2_TX3_BIST_STATUS1 (0x74) +#define HDMI_PHY_TX2_TX3_BIST_STATUS2 (0x78) +#define HDMI_PHY_PRE_MISR_STATUS0 (0x7C) +#define HDMI_PHY_PRE_MISR_STATUS1 (0x80) +#define HDMI_PHY_PRE_MISR_STATUS2 (0x84) +#define HDMI_PHY_PRE_MISR_STATUS3 (0x88) +#define HDMI_PHY_POST_MISR_STATUS0 (0x8C) +#define HDMI_PHY_POST_MISR_STATUS1 (0x90) +#define HDMI_PHY_POST_MISR_STATUS2 (0x94) +#define HDMI_PHY_POST_MISR_STATUS3 (0x98) +#define HDMI_PHY_STATUS (0x9C) +#define HDMI_PHY_MISC3_STATUS (0xA0) +#define HDMI_PHY_MISC4_STATUS (0xA4) +#define HDMI_PHY_DEBUG_BUS0 (0xA8) +#define HDMI_PHY_DEBUG_BUS1 (0xAC) +#define HDMI_PHY_DEBUG_BUS2 (0xB0) +#define HDMI_PHY_DEBUG_BUS3 (0xB4) +#define HDMI_PHY_PHY_REVISION_ID0 (0xB8) +#define HDMI_PHY_PHY_REVISION_ID1 (0xBC) +#define HDMI_PHY_PHY_REVISION_ID2 (0xC0) +#define HDMI_PHY_PHY_REVISION_ID3 (0xC4) + +#define HDMI_PLL_POLL_MAX_READS 100 +#define HDMI_PLL_POLL_TIMEOUT_US 1500 + +enum hdmi_pll_freqs { + HDMI_PCLK_25200_KHZ, + HDMI_PCLK_27027_KHZ, + HDMI_PCLK_27000_KHZ, + HDMI_PCLK_74250_KHZ, + HDMI_PCLK_148500_KHZ, + HDMI_PCLK_154000_KHZ, + HDMI_PCLK_268500_KHZ, + HDMI_PCLK_297000_KHZ, + HDMI_PCLK_594000_KHZ, + HDMI_PCLK_MAX +}; + +struct hdmi_8996_phy_pll_reg_cfg { + u32 tx_l0_lane_mode; + u32 tx_l2_lane_mode; + u32 tx_l0_tx_band; + u32 tx_l1_tx_band; + u32 tx_l2_tx_band; + u32 tx_l3_tx_band; + u32 com_svs_mode_clk_sel; + u32 com_hsclk_sel; + u32 com_pll_cctrl_mode0; + u32 com_pll_rctrl_mode0; + u32 com_cp_ctrl_mode0; + u32 com_dec_start_mode0; + u32 com_div_frac_start1_mode0; + u32 com_div_frac_start2_mode0; + u32 com_div_frac_start3_mode0; + u32 com_integloop_gain0_mode0; + u32 com_integloop_gain1_mode0; + u32 com_lock_cmp_en; + u32 com_lock_cmp1_mode0; + u32 com_lock_cmp2_mode0; + u32 com_lock_cmp3_mode0; + u32 com_core_clk_en; + u32 com_coreclk_div; + u32 com_restrim_ctrl; + u32 com_vco_tune_ctrl; + + u32 tx_l0_tx_drv_lvl; + u32 tx_l0_tx_emp_post1_lvl; + u32 tx_l1_tx_drv_lvl; + u32 tx_l1_tx_emp_post1_lvl; + u32 tx_l2_tx_drv_lvl; + u32 tx_l2_tx_emp_post1_lvl; + u32 tx_l3_tx_drv_lvl; + u32 tx_l3_tx_emp_post1_lvl; + u32 tx_l0_vmode_ctrl1; + u32 tx_l0_vmode_ctrl2; + u32 tx_l1_vmode_ctrl1; + u32 tx_l1_vmode_ctrl2; + u32 tx_l2_vmode_ctrl1; + u32 tx_l2_vmode_ctrl2; + u32 tx_l3_vmode_ctrl1; + u32 tx_l3_vmode_ctrl2; + u32 tx_l0_res_code_lane_tx; + u32 tx_l1_res_code_lane_tx; + u32 tx_l2_res_code_lane_tx; + u32 tx_l3_res_code_lane_tx; + + u32 phy_mode; +}; + +struct hdmi_8996_v3_post_divider { + u64 vco_freq; + u64 hsclk_divsel; + u64 vco_ratio; + u64 tx_band_sel; + u64 half_rate_mode; +}; + +static inline struct hdmi_pll_vco_clk *to_hdmi_8996_vco_clk(struct clk *clk) +{ + return container_of(clk, struct hdmi_pll_vco_clk, c); +} + +static inline u64 hdmi_8996_v1_get_post_div_lt_2g(u64 bclk) +{ + if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ) + return 2; + else if (bclk >= HDMI_1700MHZ_BIT_CLK_HZ) + return 3; + else if (bclk >= HDMI_1200MHZ_BIT_CLK_HZ) + return 4; + else if (bclk >= HDMI_850MHZ_BIT_CLK_HZ) + return 3; + else if (bclk >= HDMI_600MHZ_BIT_CLK_HZ) + return 4; + else if (bclk >= HDMI_450MHZ_BIT_CLK_HZ) + return 3; + else if (bclk >= HDMI_300MHZ_BIT_CLK_HZ) + return 4; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_v2_get_post_div_lt_2g(u64 bclk, u64 vco_range) +{ + u64 hdmi_8ghz = vco_range; + u64 tmp_calc; + + hdmi_8ghz <<= 2; + tmp_calc = hdmi_8ghz; + do_div(tmp_calc, 6U); + + if (bclk >= vco_range) + return 2; + else if (bclk >= tmp_calc) + return 3; + else if (bclk >= vco_range >> 1) + return 4; + + tmp_calc = hdmi_8ghz; + do_div(tmp_calc, 12U); + if (bclk >= tmp_calc) + return 3; + else if (bclk >= vco_range >> 2) + return 4; + + tmp_calc = hdmi_8ghz; + do_div(tmp_calc, 24U); + if (bclk >= tmp_calc) + return 3; + else if (bclk >= vco_range >> 3) + return 4; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_v2_get_post_div_gt_2g(u64 hsclk) +{ + if (hsclk >= 0 && hsclk <= 3) + return hsclk + 1; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_get_coreclk_div_lt_2g(u64 bclk) +{ + if (bclk >= HDMI_1334MHZ_BIT_CLK_HZ) + return 1; + else if (bclk >= HDMI_1000MHZ_BIT_CLK_HZ) + return 1; + else if (bclk >= HDMI_667MHZ_BIT_CLK_HZ) + return 2; + else if (bclk >= HDMI_500MHZ_BIT_CLK_HZ) + return 2; + else if (bclk >= HDMI_334MHZ_BIT_CLK_HZ) + return 3; + else if (bclk >= HDMI_250MHZ_BIT_CLK_HZ) + return 3; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_get_coreclk_div_ratio(u64 clks_pll_divsel, + u64 coreclk_div) +{ + if (clks_pll_divsel == 0) + return coreclk_div*2; + else if (clks_pll_divsel == 1) + return coreclk_div*4; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_v1_get_tx_band(u64 bclk) +{ + if (bclk >= 2400000000UL) + return 0; + if (bclk >= 1200000000UL) + return 1; + if (bclk >= 600000000UL) + return 2; + if (bclk >= 300000000UL) + return 3; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_v2_get_tx_band(u64 bclk, u64 vco_range) +{ + if (bclk >= vco_range) + return 0; + else if (bclk >= vco_range >> 1) + return 1; + else if (bclk >= vco_range >> 2) + return 2; + else if (bclk >= vco_range >> 3) + return 3; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_v1_get_hsclk(u64 fdata) +{ + if (fdata >= 9600000000UL) + return 0; + else if (fdata >= 4800000000UL) + return 1; + else if (fdata >= 3200000000UL) + return 2; + else if (fdata >= 2400000000UL) + return 3; + + return HDMI_64B_ERR_VAL; +} + +static inline u64 hdmi_8996_v2_get_hsclk(u64 fdata, u64 vco_range) +{ + u64 tmp_calc = vco_range; + + tmp_calc <<= 2; + do_div(tmp_calc, 3U); + if (fdata >= (vco_range << 2)) + return 0; + else if (fdata >= (vco_range << 1)) + return 1; + else if (fdata >= tmp_calc) + return 2; + else if (fdata >= vco_range) + return 3; + + return HDMI_64B_ERR_VAL; + +} + +static inline u64 hdmi_8996_v2_get_vco_freq(u64 bclk, u64 vco_range) +{ + u64 tx_band_div_ratio = 1U << hdmi_8996_v2_get_tx_band(bclk, vco_range); + u64 pll_post_div_ratio; + + if (bclk >= vco_range) { + u64 hsclk = hdmi_8996_v2_get_hsclk(bclk, vco_range); + + pll_post_div_ratio = hdmi_8996_v2_get_post_div_gt_2g(hsclk); + } else { + pll_post_div_ratio = hdmi_8996_v2_get_post_div_lt_2g(bclk, + vco_range); + } + + return bclk * (pll_post_div_ratio * tx_band_div_ratio); +} + +static inline u64 hdmi_8996_v2_get_fdata(u64 bclk, u64 vco_range) +{ + if (bclk >= vco_range) + return bclk; + u64 tmp_calc = hdmi_8996_v2_get_vco_freq(bclk, vco_range); + u64 pll_post_div_ratio_lt_2g = hdmi_8996_v2_get_post_div_lt_2g( + bclk, vco_range); + if (pll_post_div_ratio_lt_2g == HDMI_64B_ERR_VAL) + return HDMI_64B_ERR_VAL; + + do_div(tmp_calc, pll_post_div_ratio_lt_2g); + return tmp_calc; +} + +static inline u64 hdmi_8996_get_cpctrl(u64 frac_start, bool gen_ssc) +{ + if ((frac_start != 0) || gen_ssc) + /* + * This should be ROUND(11/(19.2/20))). + * Since ref clock does not change, hardcoding to 11 + */ + return 0xB; + + return 0x23; +} + +static inline u64 hdmi_8996_get_rctrl(u64 frac_start, bool gen_ssc) +{ + if ((frac_start != 0) || gen_ssc) + return 0x16; + + return 0x10; +} + +static inline u64 hdmi_8996_get_cctrl(u64 frac_start, bool gen_ssc) +{ + if ((frac_start != 0) || (gen_ssc)) + return 0x28; + + return 0x1; +} + +static inline u64 hdmi_8996_get_integloop_gain(u64 frac_start, bool gen_ssc) +{ + if ((frac_start != 0) || gen_ssc) + return 0x80; + + return 0xC4; +} + +static inline u64 hdmi_8996_v3_get_integloop_gain(u64 frac_start, u64 bclk, + bool gen_ssc) +{ + u64 digclk_divsel = bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2; + u64 base = ((frac_start != 0) || gen_ssc) ? 0x40 : 0xC4; + + base <<= digclk_divsel; + + return (base <= 2046 ? base : 0x7FE); +} + +static inline u64 hdmi_8996_get_vco_tune(u64 fdata, u64 div) +{ + u64 vco_tune; + + vco_tune = fdata * div; + do_div(vco_tune, 1000000); + vco_tune = 13000 - vco_tune - 256; + do_div(vco_tune, 5); + + return vco_tune; +} + +static inline u64 hdmi_8996_get_pll_cmp(u64 pll_cmp_cnt, u64 core_clk) +{ + u64 pll_cmp; + u64 rem; + + pll_cmp = pll_cmp_cnt * core_clk; + rem = do_div(pll_cmp, HDMI_REF_CLOCK); + if (rem > (HDMI_REF_CLOCK >> 1)) + pll_cmp++; + pll_cmp -= 1; + + return pll_cmp; +} + +static inline u64 hdmi_8996_v3_get_pll_cmp(u64 pll_cmp_cnt, u64 fdata) +{ + u64 dividend = pll_cmp_cnt * fdata; + u64 divisor = HDMI_REF_CLOCK * 10; + u64 rem; + + rem = do_div(dividend, divisor); + if (rem > (divisor >> 1)) + dividend++; + + return dividend - 1; +} + +static int hdmi_8996_v3_get_post_div(struct hdmi_8996_v3_post_divider *pd, + u64 bclk) +{ + u32 ratio[] = {2, 3, 4, 5, 6, 9, 10, 12, 14, 15, 20, 21, 25, 28, 35}; + u32 tx_band_sel[] = {0, 1, 2, 3}; + u64 vco_freq[60]; + u64 vco, vco_optimal, half_rate_mode = 0; + int vco_optimal_index, vco_freq_index; + int i, j, k, x; + + for (i = 0; i <= 1; i++) { + vco_optimal = HDMI_VCO_MAX_FREQ; + vco_optimal_index = -1; + vco_freq_index = 0; + for (j = 0; j < 15; j++) { + for (k = 0; k < 4; k++) { + u64 ratio_mult = ratio[j] << tx_band_sel[k]; + + vco = bclk >> half_rate_mode; + vco *= ratio_mult; + vco_freq[vco_freq_index++] = vco; + } + } + + for (x = 0; x < 60; x++) { + u64 vco_tmp = vco_freq[x]; + + if ((vco_tmp >= HDMI_VCO_MIN_FREQ) && + (vco_tmp <= vco_optimal)) { + vco_optimal = vco_tmp; + vco_optimal_index = x; + } + } + + if (vco_optimal_index == -1) { + if (!half_rate_mode) + half_rate_mode++; + else + return -EINVAL; + } else { + pd->vco_freq = vco_optimal; + pd->tx_band_sel = tx_band_sel[vco_optimal_index % 4]; + pd->vco_ratio = ratio[vco_optimal_index / 4]; + break; + } + } + + switch (pd->vco_ratio) { + case 2: + pd->hsclk_divsel = 0; + break; + case 3: + pd->hsclk_divsel = 4; + break; + case 4: + pd->hsclk_divsel = 8; + break; + case 5: + pd->hsclk_divsel = 12; + break; + case 6: + pd->hsclk_divsel = 1; + break; + case 9: + pd->hsclk_divsel = 5; + break; + case 10: + pd->hsclk_divsel = 2; + break; + case 12: + pd->hsclk_divsel = 9; + break; + case 14: + pd->hsclk_divsel = 3; + break; + case 15: + pd->hsclk_divsel = 13; + break; + case 20: + pd->hsclk_divsel = 10; + break; + case 21: + pd->hsclk_divsel = 7; + break; + case 25: + pd->hsclk_divsel = 14; + break; + case 28: + pd->hsclk_divsel = 11; + break; + case 35: + pd->hsclk_divsel = 15; + break; + } + + return 0; +} + +static int hdmi_8996_v1_calculate(u32 pix_clk, + struct hdmi_8996_phy_pll_reg_cfg *cfg) +{ + int rc = -EINVAL; + u64 fdata, clk_divtx, tmds_clk; + u64 bclk; + u64 post_div_gt_2g; + u64 post_div_lt_2g; + u64 coreclk_div1_lt_2g; + u64 core_clk_div_ratio; + u64 core_clk; + u64 pll_cmp; + u64 tx_band; + u64 tx_band_div_ratio; + u64 hsclk; + u64 dec_start; + u64 frac_start; + u64 pll_divisor = 4 * HDMI_REF_CLOCK; + u64 cpctrl; + u64 rctrl; + u64 cctrl; + u64 integloop_gain; + u64 vco_tune; + u64 vco_freq; + u64 rem; + + /* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */ + bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) + tmds_clk = bclk/4; + else + tmds_clk = bclk; + + post_div_lt_2g = hdmi_8996_v1_get_post_div_lt_2g(bclk); + if (post_div_lt_2g == HDMI_64B_ERR_VAL) + goto fail; + + coreclk_div1_lt_2g = hdmi_8996_get_coreclk_div_lt_2g(bclk); + + core_clk_div_ratio = hdmi_8996_get_coreclk_div_ratio( + HDMI_CLKS_PLL_DIVSEL, HDMI_CORECLK_DIV); + + tx_band = hdmi_8996_v1_get_tx_band(bclk); + if (tx_band == HDMI_64B_ERR_VAL) + goto fail; + + tx_band_div_ratio = 1 << tx_band; + + if (bclk >= HDMI_2400MHZ_BIT_CLK_HZ) { + fdata = bclk; + hsclk = hdmi_8996_v1_get_hsclk(fdata); + if (hsclk == HDMI_64B_ERR_VAL) + goto fail; + + post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL; + if (post_div_gt_2g == HDMI_64B_ERR_VAL) + goto fail; + + vco_freq = bclk * (post_div_gt_2g * tx_band_div_ratio); + clk_divtx = vco_freq; + do_div(clk_divtx, post_div_gt_2g); + } else { + vco_freq = bclk * (post_div_lt_2g * tx_band_div_ratio); + fdata = vco_freq; + do_div(fdata, post_div_lt_2g); + hsclk = hdmi_8996_v1_get_hsclk(fdata); + if (hsclk == HDMI_64B_ERR_VAL) + goto fail; + + clk_divtx = vco_freq; + do_div(clk_divtx, post_div_lt_2g); + post_div_gt_2g = (hsclk <= 3) ? (hsclk + 1) : HDMI_64B_ERR_VAL; + if (post_div_gt_2g == HDMI_64B_ERR_VAL) + goto fail; + } + + /* Decimal and fraction values */ + dec_start = fdata * post_div_gt_2g; + do_div(dec_start, pll_divisor); + frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) - + (fdata * post_div_gt_2g))) * (1 << 20)); + rem = do_div(frac_start, pll_divisor); + /* Round off frac_start to closest integer */ + if (rem >= (pll_divisor >> 1)) + frac_start++; + + cpctrl = hdmi_8996_get_cpctrl(frac_start, false); + rctrl = hdmi_8996_get_rctrl(frac_start, false); + cctrl = hdmi_8996_get_cctrl(frac_start, false); + integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false); + vco_tune = hdmi_8996_get_vco_tune(fdata, post_div_gt_2g); + + core_clk = clk_divtx; + do_div(core_clk, core_clk_div_ratio); + pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk); + + /* Debug dump */ + DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); + DEV_DBG("%s: fdata: %llu\n", __func__, fdata); + DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx); + DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); + DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); + DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); + DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); + DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); + DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); + DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); + DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); + DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); + DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune); + DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); + DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); + + /* Convert these values to register specific values */ + cfg->tx_l0_lane_mode = 0x3; + cfg->tx_l2_lane_mode = 0x3; + cfg->tx_l0_tx_band = tx_band + 4; + cfg->tx_l1_tx_band = tx_band + 4; + cfg->tx_l2_tx_band = tx_band + 4; + cfg->tx_l3_tx_band = tx_band + 4; + cfg->tx_l0_res_code_lane_tx = 0x33; + cfg->tx_l1_res_code_lane_tx = 0x33; + cfg->tx_l2_res_code_lane_tx = 0x33; + cfg->tx_l3_res_code_lane_tx = 0x33; + cfg->com_restrim_ctrl = 0x0; + cfg->com_vco_tune_ctrl = 0x1C; + + cfg->com_svs_mode_clk_sel = + (bclk >= HDMI_DIG_FREQ_BIT_CLK_THRESHOLD ? 1 : 2); + cfg->com_hsclk_sel = (0x28 | hsclk); + cfg->com_pll_cctrl_mode0 = cctrl; + cfg->com_pll_rctrl_mode0 = rctrl; + cfg->com_cp_ctrl_mode0 = cpctrl; + cfg->com_dec_start_mode0 = dec_start; + cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); + cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); + cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); + cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); + cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); + cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); + cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); + cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); + cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4)); + cfg->com_coreclk_div = HDMI_CORECLK_DIV; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x22; + cfg->tx_l3_tx_emp_post1_lvl = 0x27; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + cfg->com_restrim_ctrl = 0x0; + } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x25; + cfg->tx_l3_tx_emp_post1_lvl = 0x23; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + cfg->com_restrim_ctrl = 0x0; + } else { + cfg->tx_l0_tx_drv_lvl = 0x20; + cfg->tx_l0_tx_emp_post1_lvl = 0x20; + cfg->tx_l1_tx_drv_lvl = 0x20; + cfg->tx_l1_tx_emp_post1_lvl = 0x20; + cfg->tx_l2_tx_drv_lvl = 0x20; + cfg->tx_l2_tx_emp_post1_lvl = 0x20; + cfg->tx_l3_tx_drv_lvl = 0x20; + cfg->tx_l3_tx_emp_post1_lvl = 0x20; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0E; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0E; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0E; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x0E; + cfg->com_restrim_ctrl = 0xD8; + } + + cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; + DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); + DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); + DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); + DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); + DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); + DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); + DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); + DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", + cfg->com_svs_mode_clk_sel); + DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); + DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", + cfg->com_pll_cctrl_mode0); + DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", + cfg->com_pll_rctrl_mode0); + DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", + cfg->com_cp_ctrl_mode0); + DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", + cfg->com_dec_start_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", + cfg->com_div_frac_start1_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", + cfg->com_div_frac_start2_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", + cfg->com_div_frac_start3_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", + cfg->com_integloop_gain0_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", + cfg->com_integloop_gain1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", + cfg->com_lock_cmp1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", + cfg->com_lock_cmp2_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", + cfg->com_lock_cmp3_mode0); + DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); + DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); + DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n", cfg->com_restrim_ctrl); + + DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); + DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l0_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); + DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l1_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); + DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l2_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); + DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l3_tx_emp_post1_lvl); + + DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); + DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); + DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); + DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); + DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); + DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); + DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); + DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); + DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n", + cfg->tx_l0_res_code_lane_tx); + DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n", + cfg->tx_l1_res_code_lane_tx); + DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n", + cfg->tx_l2_res_code_lane_tx); + DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n", + cfg->tx_l3_res_code_lane_tx); + + DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); + rc = 0; +fail: + return rc; +} + +static int hdmi_8996_v2_calculate(u32 pix_clk, + struct hdmi_8996_phy_pll_reg_cfg *cfg) +{ + int rc = -EINVAL; + u64 fdata, clk_divtx, tmds_clk; + u64 bclk; + u64 post_div; + u64 core_clk_div; + u64 core_clk_div_ratio; + u64 core_clk; + u64 pll_cmp; + u64 tx_band; + u64 tx_band_div_ratio; + u64 hsclk; + u64 dec_start; + u64 frac_start; + u64 pll_divisor = 4 * HDMI_REF_CLOCK; + u64 cpctrl; + u64 rctrl; + u64 cctrl; + u64 integloop_gain; + u64 vco_tune; + u64 vco_freq; + u64 vco_range; + u64 rem; + + /* FDATA, CLK_DIVTX, PIXEL_CLK, TMDS_CLK */ + bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) + tmds_clk = pix_clk >> 2; + else + tmds_clk = pix_clk; + + vco_range = bclk < HDMI_282MHZ_BIT_CLK_HZ ? HDMI_2000MHZ_BIT_CLK_HZ : + HDMI_2250MHZ_BIT_CLK_HZ; + + fdata = hdmi_8996_v2_get_fdata(bclk, vco_range); + if (fdata == HDMI_64B_ERR_VAL) + goto fail; + + hsclk = hdmi_8996_v2_get_hsclk(fdata, vco_range); + if (hsclk == HDMI_64B_ERR_VAL) + goto fail; + + if (bclk >= vco_range) + post_div = hdmi_8996_v2_get_post_div_gt_2g(hsclk); + else + post_div = hdmi_8996_v2_get_post_div_lt_2g(bclk, vco_range); + + if (post_div == HDMI_64B_ERR_VAL) + goto fail; + + core_clk_div = 5; + core_clk_div_ratio = core_clk_div * 2; + + tx_band = hdmi_8996_v2_get_tx_band(bclk, vco_range); + if (tx_band == HDMI_64B_ERR_VAL) + goto fail; + + tx_band_div_ratio = 1 << tx_band; + + vco_freq = hdmi_8996_v2_get_vco_freq(bclk, vco_range); + clk_divtx = vco_freq; + do_div(clk_divtx, post_div); + + /* Decimal and fraction values */ + dec_start = fdata * post_div; + do_div(dec_start, pll_divisor); + frac_start = ((pll_divisor - (((dec_start + 1) * pll_divisor) - + (fdata * post_div))) * (1 << 20)); + rem = do_div(frac_start, pll_divisor); + /* Round off frac_start to closest integer */ + if (rem >= (pll_divisor >> 1)) + frac_start++; + + cpctrl = hdmi_8996_get_cpctrl(frac_start, false); + rctrl = hdmi_8996_get_rctrl(frac_start, false); + cctrl = hdmi_8996_get_cctrl(frac_start, false); + integloop_gain = hdmi_8996_get_integloop_gain(frac_start, false); + vco_tune = hdmi_8996_get_vco_tune(fdata, post_div); + + core_clk = clk_divtx; + do_div(core_clk, core_clk_div_ratio); + pll_cmp = hdmi_8996_get_pll_cmp(1024, core_clk); + + /* Debug dump */ + DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); + DEV_DBG("%s: fdata: %llu\n", __func__, fdata); + DEV_DBG("%s: CLK_DIVTX: %llu\n", __func__, clk_divtx); + DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); + DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); + DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); + DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); + DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); + DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); + DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); + DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); + DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); + DEV_DBG("%s: VCO_TUNE: %llu\n", __func__, vco_tune); + DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); + DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); + + /* Convert these values to register specific values */ + cfg->tx_l0_lane_mode = 0x3; + cfg->tx_l2_lane_mode = 0x3; + cfg->tx_l0_tx_band = tx_band + 4; + cfg->tx_l1_tx_band = tx_band + 4; + cfg->tx_l2_tx_band = tx_band + 4; + cfg->tx_l3_tx_band = tx_band + 4; + + if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) + cfg->com_svs_mode_clk_sel = 1; + else + cfg->com_svs_mode_clk_sel = 2; + + cfg->com_hsclk_sel = (0x28 | hsclk); + cfg->com_pll_cctrl_mode0 = cctrl; + cfg->com_pll_rctrl_mode0 = rctrl; + cfg->com_cp_ctrl_mode0 = cpctrl; + cfg->com_dec_start_mode0 = dec_start; + cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); + cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); + cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); + cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); + cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); + cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); + cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); + cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); + cfg->com_core_clk_en = (0x6C | (HDMI_CLKS_PLL_DIVSEL << 4)); + cfg->com_coreclk_div = HDMI_CORECLK_DIV; + cfg->com_vco_tune_ctrl = 0x0; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x22; + cfg->tx_l3_tx_emp_post1_lvl = 0x27; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + cfg->tx_l0_res_code_lane_tx = 0x3F; + cfg->tx_l1_res_code_lane_tx = 0x3F; + cfg->tx_l2_res_code_lane_tx = 0x3F; + cfg->tx_l3_res_code_lane_tx = 0x3F; + cfg->com_restrim_ctrl = 0x0; + } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x25; + cfg->tx_l3_tx_emp_post1_lvl = 0x23; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + cfg->tx_l0_res_code_lane_tx = 0x39; + cfg->tx_l1_res_code_lane_tx = 0x39; + cfg->tx_l2_res_code_lane_tx = 0x39; + cfg->tx_l3_res_code_lane_tx = 0x39; + cfg->com_restrim_ctrl = 0x0; + } else { + cfg->tx_l0_tx_drv_lvl = 0x20; + cfg->tx_l0_tx_emp_post1_lvl = 0x20; + cfg->tx_l1_tx_drv_lvl = 0x20; + cfg->tx_l1_tx_emp_post1_lvl = 0x20; + cfg->tx_l2_tx_drv_lvl = 0x20; + cfg->tx_l2_tx_emp_post1_lvl = 0x20; + cfg->tx_l3_tx_drv_lvl = 0x20; + cfg->tx_l3_tx_emp_post1_lvl = 0x20; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0E; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0E; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0E; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x0E; + cfg->tx_l0_res_code_lane_tx = 0x3F; + cfg->tx_l1_res_code_lane_tx = 0x3F; + cfg->tx_l2_res_code_lane_tx = 0x3F; + cfg->tx_l3_res_code_lane_tx = 0x3F; + cfg->com_restrim_ctrl = 0xD8; + } + + cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; + DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); + DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); + DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); + DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); + DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); + DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); + DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); + DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", + cfg->com_svs_mode_clk_sel); + DEV_DBG("PLL PARAM: com_vco_tune_ctrl = 0x%x\n", + cfg->com_vco_tune_ctrl); + DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); + DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en); + DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", + cfg->com_pll_cctrl_mode0); + DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", + cfg->com_pll_rctrl_mode0); + DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", + cfg->com_cp_ctrl_mode0); + DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", + cfg->com_dec_start_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", + cfg->com_div_frac_start1_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", + cfg->com_div_frac_start2_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", + cfg->com_div_frac_start3_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", + cfg->com_integloop_gain0_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", + cfg->com_integloop_gain1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", + cfg->com_lock_cmp1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", + cfg->com_lock_cmp2_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", + cfg->com_lock_cmp3_mode0); + DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); + DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); + + DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); + DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l0_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); + DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l1_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); + DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l2_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); + DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l3_tx_emp_post1_lvl); + + DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); + DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); + DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); + DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); + DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); + DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); + DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); + DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); + DEV_DBG("PLL PARAM: tx_l0_res_code_lane_tx = 0x%x\n", + cfg->tx_l0_res_code_lane_tx); + DEV_DBG("PLL PARAM: tx_l1_res_code_lane_tx = 0x%x\n", + cfg->tx_l1_res_code_lane_tx); + DEV_DBG("PLL PARAM: tx_l2_res_code_lane_tx = 0x%x\n", + cfg->tx_l2_res_code_lane_tx); + DEV_DBG("PLL PARAM: tx_l3_res_code_lane_tx = 0x%x\n", + cfg->tx_l3_res_code_lane_tx); + DEV_DBG("PLL PARAM: com_restrim_ctrl = 0x%x\n", cfg->com_restrim_ctrl); + + DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); + rc = 0; +fail: + return rc; +} + +static int hdmi_8996_v3_calculate(u32 pix_clk, + struct hdmi_8996_phy_pll_reg_cfg *cfg) +{ + int rc = -EINVAL; + struct hdmi_8996_v3_post_divider pd; + u64 fdata, tmds_clk; + u64 bclk; + u64 pll_cmp; + u64 tx_band; + u64 hsclk; + u64 dec_start; + u64 frac_start; + u64 pll_divisor = 4 * HDMI_REF_CLOCK; + u64 cpctrl; + u64 rctrl; + u64 cctrl; + u64 integloop_gain; + u64 vco_freq; + u64 rem; + + /* FDATA, HSCLK, PIXEL_CLK, TMDS_CLK */ + bclk = ((u64)pix_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) + tmds_clk = pix_clk >> 2; + else + tmds_clk = pix_clk; + + if (hdmi_8996_v3_get_post_div(&pd, bclk) || pd.vco_ratio <= 0 || + pd.vco_freq <= 0) + goto fail; + + vco_freq = pd.vco_freq; + fdata = pd.vco_freq; + do_div(fdata, pd.vco_ratio); + + hsclk = pd.hsclk_divsel; + dec_start = vco_freq; + do_div(dec_start, pll_divisor); + + frac_start = vco_freq * (1 << 20); + rem = do_div(frac_start, pll_divisor); + frac_start -= dec_start * (1 << 20); + if (rem > (pll_divisor >> 1)) + frac_start++; + + cpctrl = hdmi_8996_get_cpctrl(frac_start, false); + rctrl = hdmi_8996_get_rctrl(frac_start, false); + cctrl = hdmi_8996_get_cctrl(frac_start, false); + integloop_gain = hdmi_8996_v3_get_integloop_gain(frac_start, bclk, + false); + pll_cmp = hdmi_8996_v3_get_pll_cmp(1024, fdata); + tx_band = pd.tx_band_sel; + + /* Debug dump */ + DEV_DBG("%s: VCO freq: %llu\n", __func__, vco_freq); + DEV_DBG("%s: fdata: %llu\n", __func__, fdata); + DEV_DBG("%s: pix_clk: %d\n", __func__, pix_clk); + DEV_DBG("%s: tmds clk: %llu\n", __func__, tmds_clk); + DEV_DBG("%s: HSCLK_SEL: %llu\n", __func__, hsclk); + DEV_DBG("%s: DEC_START: %llu\n", __func__, dec_start); + DEV_DBG("%s: DIV_FRAC_START: %llu\n", __func__, frac_start); + DEV_DBG("%s: PLL_CPCTRL: %llu\n", __func__, cpctrl); + DEV_DBG("%s: PLL_RCTRL: %llu\n", __func__, rctrl); + DEV_DBG("%s: PLL_CCTRL: %llu\n", __func__, cctrl); + DEV_DBG("%s: INTEGLOOP_GAIN: %llu\n", __func__, integloop_gain); + DEV_DBG("%s: TX_BAND: %llu\n", __func__, tx_band); + DEV_DBG("%s: PLL_CMP: %llu\n", __func__, pll_cmp); + + /* Convert these values to register specific values */ + cfg->tx_l0_tx_band = tx_band + 4; + cfg->tx_l1_tx_band = tx_band + 4; + cfg->tx_l2_tx_band = tx_band + 4; + cfg->tx_l3_tx_band = tx_band + 4; + + if (bclk > HDMI_DIG_FREQ_BIT_CLK_THRESHOLD) + cfg->com_svs_mode_clk_sel = 1; + else + cfg->com_svs_mode_clk_sel = 2; + + cfg->com_hsclk_sel = (0x20 | hsclk); + cfg->com_pll_cctrl_mode0 = cctrl; + cfg->com_pll_rctrl_mode0 = rctrl; + cfg->com_cp_ctrl_mode0 = cpctrl; + cfg->com_dec_start_mode0 = dec_start; + cfg->com_div_frac_start1_mode0 = (frac_start & 0xFF); + cfg->com_div_frac_start2_mode0 = ((frac_start & 0xFF00) >> 8); + cfg->com_div_frac_start3_mode0 = ((frac_start & 0xF0000) >> 16); + cfg->com_integloop_gain0_mode0 = (integloop_gain & 0xFF); + cfg->com_integloop_gain1_mode0 = ((integloop_gain & 0xF00) >> 8); + cfg->com_lock_cmp1_mode0 = (pll_cmp & 0xFF); + cfg->com_lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); + cfg->com_lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); + cfg->com_lock_cmp_en = 0x04; + cfg->com_core_clk_en = 0x2C; + cfg->com_coreclk_div = HDMI_CORECLK_DIV; + cfg->phy_mode = (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) ? 0x10 : 0x0; + cfg->com_vco_tune_ctrl = 0x0; + + cfg->tx_l0_lane_mode = 0x43; + cfg->tx_l2_lane_mode = 0x43; + + if (bclk > HDMI_HIGH_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x22; + cfg->tx_l3_tx_emp_post1_lvl = 0x27; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + } else if (bclk > HDMI_MID_FREQ_BIT_CLK_THRESHOLD) { + cfg->tx_l0_tx_drv_lvl = 0x25; + cfg->tx_l0_tx_emp_post1_lvl = 0x23; + cfg->tx_l1_tx_drv_lvl = 0x25; + cfg->tx_l1_tx_emp_post1_lvl = 0x23; + cfg->tx_l2_tx_drv_lvl = 0x25; + cfg->tx_l2_tx_emp_post1_lvl = 0x23; + cfg->tx_l3_tx_drv_lvl = 0x25; + cfg->tx_l3_tx_emp_post1_lvl = 0x23; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0D; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0D; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0D; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x00; + } else { + cfg->tx_l0_tx_drv_lvl = 0x20; + cfg->tx_l0_tx_emp_post1_lvl = 0x20; + cfg->tx_l1_tx_drv_lvl = 0x20; + cfg->tx_l1_tx_emp_post1_lvl = 0x20; + cfg->tx_l2_tx_drv_lvl = 0x20; + cfg->tx_l2_tx_emp_post1_lvl = 0x20; + cfg->tx_l3_tx_drv_lvl = 0x20; + cfg->tx_l3_tx_emp_post1_lvl = 0x20; + cfg->tx_l0_vmode_ctrl1 = 0x00; + cfg->tx_l0_vmode_ctrl2 = 0x0E; + cfg->tx_l1_vmode_ctrl1 = 0x00; + cfg->tx_l1_vmode_ctrl2 = 0x0E; + cfg->tx_l2_vmode_ctrl1 = 0x00; + cfg->tx_l2_vmode_ctrl2 = 0x0E; + cfg->tx_l3_vmode_ctrl1 = 0x00; + cfg->tx_l3_vmode_ctrl2 = 0x0E; + } + + DEV_DBG("HDMI 8996 PLL: PLL Settings\n"); + DEV_DBG("PLL PARAM: tx_l0_tx_band = 0x%x\n", cfg->tx_l0_tx_band); + DEV_DBG("PLL PARAM: tx_l1_tx_band = 0x%x\n", cfg->tx_l1_tx_band); + DEV_DBG("PLL PARAM: tx_l2_tx_band = 0x%x\n", cfg->tx_l2_tx_band); + DEV_DBG("PLL PARAM: tx_l3_tx_band = 0x%x\n", cfg->tx_l3_tx_band); + DEV_DBG("PLL PARAM: com_svs_mode_clk_sel = 0x%x\n", + cfg->com_svs_mode_clk_sel); + DEV_DBG("PLL PARAM: com_hsclk_sel = 0x%x\n", cfg->com_hsclk_sel); + DEV_DBG("PLL PARAM: com_lock_cmp_en = 0x%x\n", cfg->com_lock_cmp_en); + DEV_DBG("PLL PARAM: com_pll_cctrl_mode0 = 0x%x\n", + cfg->com_pll_cctrl_mode0); + DEV_DBG("PLL PARAM: com_pll_rctrl_mode0 = 0x%x\n", + cfg->com_pll_rctrl_mode0); + DEV_DBG("PLL PARAM: com_cp_ctrl_mode0 = 0x%x\n", + cfg->com_cp_ctrl_mode0); + DEV_DBG("PLL PARAM: com_dec_start_mode0 = 0x%x\n", + cfg->com_dec_start_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start1_mode0 = 0x%x\n", + cfg->com_div_frac_start1_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start2_mode0 = 0x%x\n", + cfg->com_div_frac_start2_mode0); + DEV_DBG("PLL PARAM: com_div_frac_start3_mode0 = 0x%x\n", + cfg->com_div_frac_start3_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain0_mode0 = 0x%x\n", + cfg->com_integloop_gain0_mode0); + DEV_DBG("PLL PARAM: com_integloop_gain1_mode0 = 0x%x\n", + cfg->com_integloop_gain1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp1_mode0 = 0x%x\n", + cfg->com_lock_cmp1_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp2_mode0 = 0x%x\n", + cfg->com_lock_cmp2_mode0); + DEV_DBG("PLL PARAM: com_lock_cmp3_mode0 = 0x%x\n", + cfg->com_lock_cmp3_mode0); + DEV_DBG("PLL PARAM: com_core_clk_en = 0x%x\n", cfg->com_core_clk_en); + DEV_DBG("PLL PARAM: com_coreclk_div = 0x%x\n", cfg->com_coreclk_div); + DEV_DBG("PLL PARAM: phy_mode = 0x%x\n", cfg->phy_mode); + + DEV_DBG("PLL PARAM: tx_l0_lane_mode = 0x%x\n", cfg->tx_l0_lane_mode); + DEV_DBG("PLL PARAM: tx_l2_lane_mode = 0x%x\n", cfg->tx_l2_lane_mode); + DEV_DBG("PLL PARAM: l0_tx_drv_lvl = 0x%x\n", cfg->tx_l0_tx_drv_lvl); + DEV_DBG("PLL PARAM: l0_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l0_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l1_tx_drv_lvl = 0x%x\n", cfg->tx_l1_tx_drv_lvl); + DEV_DBG("PLL PARAM: l1_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l1_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l2_tx_drv_lvl = 0x%x\n", cfg->tx_l2_tx_drv_lvl); + DEV_DBG("PLL PARAM: l2_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l2_tx_emp_post1_lvl); + DEV_DBG("PLL PARAM: l3_tx_drv_lvl = 0x%x\n", cfg->tx_l3_tx_drv_lvl); + DEV_DBG("PLL PARAM: l3_tx_emp_post1_lvl = 0x%x\n", + cfg->tx_l3_tx_emp_post1_lvl); + + DEV_DBG("PLL PARAM: l0_vmode_ctrl1 = 0x%x\n", cfg->tx_l0_vmode_ctrl1); + DEV_DBG("PLL PARAM: l0_vmode_ctrl2 = 0x%x\n", cfg->tx_l0_vmode_ctrl2); + DEV_DBG("PLL PARAM: l1_vmode_ctrl1 = 0x%x\n", cfg->tx_l1_vmode_ctrl1); + DEV_DBG("PLL PARAM: l1_vmode_ctrl2 = 0x%x\n", cfg->tx_l1_vmode_ctrl2); + DEV_DBG("PLL PARAM: l2_vmode_ctrl1 = 0x%x\n", cfg->tx_l2_vmode_ctrl1); + DEV_DBG("PLL PARAM: l2_vmode_ctrl2 = 0x%x\n", cfg->tx_l2_vmode_ctrl2); + DEV_DBG("PLL PARAM: l3_vmode_ctrl1 = 0x%x\n", cfg->tx_l3_vmode_ctrl1); + DEV_DBG("PLL PARAM: l3_vmode_ctrl2 = 0x%x\n", cfg->tx_l3_vmode_ctrl2); + rc = 0; +fail: + return rc; +} + +static int hdmi_8996_calculate(u32 pix_clk, + struct hdmi_8996_phy_pll_reg_cfg *cfg, u32 ver) +{ + switch (ver) { + case HDMI_VERSION_8996_V3: + case HDMI_VERSION_8996_V3_1_8: + return hdmi_8996_v3_calculate(pix_clk, cfg); + case HDMI_VERSION_8996_V2: + return hdmi_8996_v2_calculate(pix_clk, cfg); + default: + return hdmi_8996_v1_calculate(pix_clk, cfg); + } +} + +static int hdmi_8996_phy_pll_set_clk_rate(struct clk *c, u32 tmds_clk, u32 ver) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + struct hdmi_8996_phy_pll_reg_cfg cfg = {0}; + + rc = hdmi_8996_calculate(tmds_clk, &cfg, ver); + if (rc) { + DEV_ERR("%s: PLL calculation failed\n", __func__); + return rc; + } + + /* Initially shut down PHY */ + DEV_DBG("%s: Disabling PHY\n", __func__); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x0); + udelay(500); + + /* Power up sequence */ + switch (ver) { + case HDMI_VERSION_8996_V2: + case HDMI_VERSION_8996_V3: + case HDMI_VERSION_8996_V3_1_8: + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x04); + break; + } + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESETSM_CNTRL, 0x20); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX0_TX1_LANE_CTL, 0x0F); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TX2_TX3_LANE_CTL, 0x0F); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_CLKBUF_ENABLE, 0x03); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_LANE_MODE, cfg.tx_l0_lane_mode); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_LANE_MODE, cfg.tx_l2_lane_mode); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TX_BAND, cfg.tx_l0_tx_band); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_TX_BAND, cfg.tx_l1_tx_band); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_TX_BAND, cfg.tx_l2_tx_band); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_TX_BAND, cfg.tx_l3_tx_band); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_RESET_TSYNC_EN, 0x03); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1E); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x07); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYSCLK_EN_SEL, 0x37); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SYS_CLK_CTRL, 0x02); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_ENABLE1, 0x0E); + if (ver == HDMI_VERSION_8996_V1) + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06); + + /* Bypass VCO calibration */ + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, + cfg.com_svs_mode_clk_sel); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_TRIM, 0x0F); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_IVCO, 0x0F); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_CTRL, + cfg.com_vco_tune_ctrl); + + switch (ver) { + case HDMI_VERSION_8996_V1: + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SVS_MODE_CLK_SEL, + cfg.com_svs_mode_clk_sel); + break; + default: + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_BG_CTRL, 0x06); + } + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CLK_SELECT, 0x30); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_HSCLK_SEL, + cfg.com_hsclk_sel); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_EN, + cfg.com_lock_cmp_en); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_CCTRL_MODE0, + cfg.com_pll_cctrl_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_PLL_RCTRL_MODE0, + cfg.com_pll_rctrl_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CP_CTRL_MODE0, + cfg.com_cp_ctrl_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEC_START_MODE0, + cfg.com_dec_start_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START1_MODE0, + cfg.com_div_frac_start1_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START2_MODE0, + cfg.com_div_frac_start2_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DIV_FRAC_START3_MODE0, + cfg.com_div_frac_start3_mode0); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN0_MODE0, + cfg.com_integloop_gain0_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_INTEGLOOP_GAIN1_MODE0, + cfg.com_integloop_gain1_mode0); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0, + cfg.com_lock_cmp1_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0, + cfg.com_lock_cmp2_mode0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0, + cfg.com_lock_cmp3_mode0); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE_MAP, 0x00); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORE_CLK_EN, + cfg.com_core_clk_en); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CORECLK_DIV, + cfg.com_coreclk_div); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_CONFIG, 0x02); + + if (ver == HDMI_VERSION_8996_V3 || ver == HDMI_VERSION_8996_V3_1_8) + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESCODE_DIV_NUM, 0x15); + + /* TX lanes setup (TX 0/1/2/3) */ + if (ver == HDMI_VERSION_8996_V3_1_8) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + 0x00000023); + } else { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + cfg.tx_l0_tx_drv_lvl); + } + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TX_EMP_POST1_LVL, + cfg.tx_l0_tx_emp_post1_lvl); + + if (ver == HDMI_VERSION_8996_V3_1_8) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + 0x00000023); + } else { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + cfg.tx_l1_tx_drv_lvl); + } + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_TX_EMP_POST1_LVL, + cfg.tx_l1_tx_emp_post1_lvl); + + if (ver == HDMI_VERSION_8996_V3_1_8) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + 0x00000023); + } else { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + cfg.tx_l2_tx_drv_lvl); + } + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_TX_EMP_POST1_LVL, + cfg.tx_l2_tx_emp_post1_lvl); + + if (ver == HDMI_VERSION_8996_V3_1_8) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + 0x00000020); + } else { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL, + cfg.tx_l3_tx_drv_lvl); + } + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_TX_EMP_POST1_LVL, + cfg.tx_l3_tx_emp_post1_lvl); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL1, + cfg.tx_l0_vmode_ctrl1); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL2, + cfg.tx_l0_vmode_ctrl2); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL1, + cfg.tx_l1_vmode_ctrl1); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL2, + cfg.tx_l1_vmode_ctrl2); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL1, + cfg.tx_l2_vmode_ctrl1); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL2, + cfg.tx_l2_vmode_ctrl2); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL1, + cfg.tx_l3_vmode_ctrl1); + if (ver == HDMI_VERSION_8996_V3_1_8) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL2, + 0x0000000D); + } else { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_VMODE_CTRL2, + cfg.tx_l3_vmode_ctrl2); + } + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_TX_DRV_LVL_OFFSET, 0x00); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_OFFSET, 0x00); + + if (ver < HDMI_VERSION_8996_V3) { + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l0_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l1_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l2_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_RES_CODE_LANE_TX, + cfg.tx_l3_res_code_lane_tx); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_RESTRIM_CTRL, + cfg.com_restrim_ctrl); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG0, 0x00); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_TXCAL_CFG1, 0x05); + } + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_MODE, cfg.phy_mode); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_PD_CTL, 0x1F); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_TRAN_DRVR_EMP_EN, 0x03); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN, 0x40); + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_HP_PD_ENABLES, 0x0C); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_HP_PD_ENABLES, 0x0C); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_HP_PD_ENABLES, 0x0C); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_HP_PD_ENABLES, 0x03); + + if (ver == HDMI_VERSION_8996_V2) { + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x01); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x01); + } + /* + * Ensure that vco configuration gets flushed to hardware before + * enabling the PLL + */ + wmb(); + return 0; +} + +static int hdmi_8996_phy_ready_status(struct mdss_pll_resources *io) +{ + u32 status = 0; + int phy_ready = 0; + int rc; + u32 read_count = 0; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + DEV_ERR("%s: pll resource can't be enabled\n", __func__); + return rc; + } + + DEV_DBG("%s: Waiting for PHY Ready\n", __func__); + + /* Poll for PHY read status */ + while (read_count < HDMI_PLL_POLL_MAX_READS) { + status = MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS); + if ((status & BIT(0)) == 1) { + phy_ready = 1; + DEV_DBG("%s: PHY READY\n", __func__); + break; + } + udelay(HDMI_PLL_POLL_TIMEOUT_US); + read_count++; + } + + if (read_count == HDMI_PLL_POLL_MAX_READS) { + phy_ready = 0; + DEV_DBG("%s: PHY READY TIMEOUT\n", __func__); + } + + mdss_pll_resource_enable(io, false); + + return phy_ready; +} + +static int hdmi_8996_pll_lock_status(struct mdss_pll_resources *io) +{ + u32 status; + int pll_locked = 0; + int rc; + u32 read_count = 0; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + DEV_ERR("%s: pll resource can't be enabled\n", __func__); + return rc; + } + + DEV_DBG("%s: Waiting for PLL lock\n", __func__); + + while (read_count < HDMI_PLL_POLL_MAX_READS) { + status = MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_C_READY_STATUS); + if ((status & BIT(0)) == 1) { + pll_locked = 1; + DEV_DBG("%s: C READY\n", __func__); + break; + } + udelay(HDMI_PLL_POLL_TIMEOUT_US); + read_count++; + } + + if (read_count == HDMI_PLL_POLL_MAX_READS) { + pll_locked = 0; + DEV_DBG("%s: C READY TIMEOUT\n", __func__); + } + + mdss_pll_resource_enable(io, false); + + return pll_locked; +} + +static int hdmi_8996_v1_perform_sw_calibration(struct clk *c) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + u32 max_code = 0x190; + u32 min_code = 0x0; + u32 max_cnt = 0; + u32 min_cnt = 0; + u32 expected_counter_value = 0; + u32 step = 0; + u32 dbus_all = 0; + u32 dbus_sel = 0; + u32 vco_code = 0; + u32 val = 0; + + vco_code = 0xC8; + + DEV_DBG("%s: Starting SW calibration with vco_code = %d\n", __func__, + vco_code); + + expected_counter_value = + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP3_MODE0) << 16) | + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP2_MODE0) << 8) | + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP1_MODE0)); + + DEV_DBG("%s: expected_counter_value = %d\n", __func__, + expected_counter_value); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); + val |= BIT(4); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); + val |= BIT(3); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); + + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x4); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); + val |= BIT(1); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); + + udelay(60); + + while (1) { + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0, + vco_code & 0xFF); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0, + (vco_code >> 8) & 0x3); + + udelay(20); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); + val &= ~BIT(1); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); + + udelay(60); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); + val |= BIT(1); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); + + udelay(60); + + dbus_all = + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS3) << 24) | + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS2) << 16) | + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS1) << 8) | + (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEBUG_BUS0)); + + dbus_sel = (dbus_all >> 9) & 0x3FFFF; + DEV_DBG("%s: loop[%d], dbus_all = 0x%x, dbus_sel = 0x%x\n", + __func__, step, dbus_all, dbus_sel); + if (dbus_sel == 0) + DEV_ERR("%s: CHECK HDMI REF CLK\n", __func__); + + if (dbus_sel == expected_counter_value) { + max_code = vco_code; + max_cnt = dbus_sel; + min_code = vco_code; + min_cnt = dbus_sel; + } else if (dbus_sel == 0) { + max_code = vco_code; + max_cnt = dbus_sel; + vco_code = (max_code + min_code)/2; + } else if (dbus_sel > expected_counter_value) { + min_code = vco_code; + min_cnt = dbus_sel; + vco_code = (max_code + min_code)/2; + } else if (dbus_sel < expected_counter_value) { + max_code = vco_code; + max_cnt = dbus_sel; + vco_code = (max_code + min_code)/2; + } + + step++; + + if ((vco_code == 0) || (vco_code == 0x3FF) || (step > 0x3FF)) { + DEV_ERR("%s: VCO tune code search failed\n", __func__); + rc = -ENOTSUPP; + break; + } + if ((max_code - min_code) <= 1) { + if ((max_code - min_code) == 1) { + if (abs((int)(max_cnt - expected_counter_value)) + < abs((int)(min_cnt - expected_counter_value + ))) { + vco_code = max_code; + } else { + vco_code = min_code; + } + } + break; + } + DEV_DBG("%s: loop[%d], new vco_code = %d\n", __func__, step, + vco_code); + } + + DEV_DBG("%s: CALIB done. vco_code = %d\n", __func__, vco_code); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE1_MODE0, + vco_code & 0xFF); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_VCO_TUNE2_MODE0, + (vco_code >> 8) & 0x3); + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_LOCK_CMP_CFG); + val &= ~BIT(1); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_LOCK_CMP_CFG, val); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); + val |= BIT(4); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); + + val = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_CMN_MISC1); + val &= ~BIT(3); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_CMN_MISC1, val); + + return rc; +} + +static int hdmi_8996_v2_perform_sw_calibration(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + u32 vco_code1, vco_code2, integral_loop, ready_poll; + u32 read_count = 0; + + while (read_count < (HDMI_PLL_POLL_MAX_READS << 1)) { + ready_poll = MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_C_READY_STATUS); + if ((ready_poll & BIT(0)) == 1) { + ready_poll = 1; + DEV_DBG("%s: C READY\n", __func__); + break; + } + udelay(HDMI_PLL_POLL_TIMEOUT_US); + read_count++; + } + + if (read_count == (HDMI_PLL_POLL_MAX_READS << 1)) { + ready_poll = 0; + DEV_DBG("%s: C READY TIMEOUT, TRYING SW CALIBRATION\n", + __func__); + } + + vco_code1 = MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_PLLCAL_CODE1_STATUS); + vco_code2 = MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_PLLCAL_CODE2_STATUS); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_DEBUG_BUS_SEL, 0x5); + integral_loop = MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_DEBUG_BUS0); + + if (((ready_poll & 0x1) == 0) || (((ready_poll & 1) == 1) && + (vco_code1 == 0xFF) && ((vco_code2 & 0x3) == 0x1) && + (integral_loop > 0xC0))) { + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL1, 0x04); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_ATB_SEL2, 0x00); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x17); + udelay(100); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x11); + udelay(100); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19); + } + return 0; +} + +static int hdmi_8996_perform_sw_calibration(struct clk *c, u32 ver) +{ + switch (ver) { + case HDMI_VERSION_8996_V1: + return hdmi_8996_v1_perform_sw_calibration(c); + case HDMI_VERSION_8996_V2: + return hdmi_8996_v2_perform_sw_calibration(c); + } + return 0; +} + +static int hdmi_8996_vco_enable(struct clk *c, u32 ver) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x1); + udelay(100); + + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19); + udelay(100); + + rc = hdmi_8996_perform_sw_calibration(c, ver); + if (rc) { + DEV_ERR("%s: software calibration failed\n", __func__); + return rc; + } + + rc = hdmi_8996_pll_lock_status(io); + if (!rc) { + DEV_ERR("%s: PLL not locked\n", __func__); + return rc; + } + + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, + 0x6F); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L1_BASE_OFFSET, + QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, + 0x6F); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L2_BASE_OFFSET, + QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, + 0x6F); + MDSS_PLL_REG_W(io->pll_base + HDMI_TX_L3_BASE_OFFSET, + QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, + 0x6F); + + /* Disable SSC */ + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER1, 0x0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_PER2, 0x0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE1, 0x0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_STEP_SIZE2, 0x0); + MDSS_PLL_REG_W(io->pll_base, QSERDES_COM_SSC_EN_CENTER, 0x2); + + rc = hdmi_8996_phy_ready_status(io); + if (!rc) { + DEV_ERR("%s: PHY not READY\n", __func__); + return rc; + } + + /* Restart the retiming buffer */ + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x18); + udelay(1); + MDSS_PLL_REG_W(io->phy_base, HDMI_PHY_CFG, 0x19); + + io->pll_on = true; + return 0; +} + +static int hdmi_8996_v1_vco_enable(struct clk *c) +{ + return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V1); +} + +static int hdmi_8996_v2_vco_enable(struct clk *c) +{ + return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V2); +} + +static int hdmi_8996_v3_vco_enable(struct clk *c) +{ + return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3); +} + +static int hdmi_8996_v3_1p8_vco_enable(struct clk *c) +{ + return hdmi_8996_vco_enable(c, HDMI_VERSION_8996_V3_1_8); +} + +static int hdmi_8996_vco_get_lock_range(struct clk *c, unsigned long pixel_clk) +{ + u32 rng = 64, cmp_cnt = 1024; + u32 coreclk_div = 5, clks_pll_divsel = 2; + u32 vco_freq, vco_ratio, ppm_range; + u64 bclk; + struct hdmi_8996_v3_post_divider pd; + + bclk = ((u64)pixel_clk) * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + + DEV_DBG("%s: rate=%ld\n", __func__, pixel_clk); + + if (hdmi_8996_v3_get_post_div(&pd, bclk) || + pd.vco_ratio <= 0 || pd.vco_freq <= 0) { + DEV_ERR("%s: couldn't get post div\n", __func__); + return -EINVAL; + } + + do_div(pd.vco_freq, HDMI_KHZ_TO_HZ * HDMI_KHZ_TO_HZ); + + vco_freq = (u32) pd.vco_freq; + vco_ratio = (u32) pd.vco_ratio; + + DEV_DBG("%s: freq %d, ratio %d\n", __func__, + vco_freq, vco_ratio); + + ppm_range = (rng * HDMI_REF_CLOCK) / cmp_cnt; + ppm_range /= vco_freq / vco_ratio; + ppm_range *= coreclk_div * clks_pll_divsel; + + DEV_DBG("%s: ppm range: %d\n", __func__, ppm_range); + + return ppm_range; +} + +static int hdmi_8996_vco_rate_atomic_update(struct clk *c, + unsigned long rate, u32 ver) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + void __iomem *pll; + struct hdmi_8996_phy_pll_reg_cfg cfg = {0}; + int rc = 0; + + rc = hdmi_8996_calculate(rate, &cfg, ver); + if (rc) { + DEV_ERR("%s: PLL calculation failed\n", __func__); + goto end; + } + + pll = io->pll_base; + + MDSS_PLL_REG_W(pll, QSERDES_COM_DEC_START_MODE0, + cfg.com_dec_start_mode0); + MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START1_MODE0, + cfg.com_div_frac_start1_mode0); + MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START2_MODE0, + cfg.com_div_frac_start2_mode0); + MDSS_PLL_REG_W(pll, QSERDES_COM_DIV_FRAC_START3_MODE0, + cfg.com_div_frac_start3_mode0); + + MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x01); + MDSS_PLL_REG_W(pll, QSERDES_COM_FREQ_UPDATE, 0x00); + + DEV_DBG("%s: updated to rate %ld\n", __func__, rate); +end: + return rc; +} + +static int hdmi_8996_vco_set_rate(struct clk *c, unsigned long rate, u32 ver) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + unsigned int set_power_dwn = 0; + bool atomic_update = false; + int rc, pll_lock_range; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + DEV_ERR("pll resource can't be enabled\n"); + return rc; + } + + DEV_DBG("%s: rate %ld\n", __func__, rate); + + if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0) && + MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) { + pll_lock_range = hdmi_8996_vco_get_lock_range(c, vco->rate); + + if (pll_lock_range > 0 && vco->rate) { + u32 range_limit; + + range_limit = vco->rate * + (pll_lock_range / HDMI_KHZ_TO_HZ); + range_limit /= HDMI_KHZ_TO_HZ; + + DEV_DBG("%s: range limit %d\n", __func__, range_limit); + + if (abs(rate - vco->rate) < range_limit) + atomic_update = true; + } + } + + if (io->pll_on && !atomic_update) + set_power_dwn = 1; + + if (atomic_update) { + hdmi_8996_vco_rate_atomic_update(c, rate, ver); + } else { + rc = hdmi_8996_phy_pll_set_clk_rate(c, rate, ver); + if (rc) + DEV_ERR("%s: Failed to set clk rate\n", __func__); + } + + mdss_pll_resource_enable(io, false); + + if (set_power_dwn) + hdmi_8996_vco_enable(c, ver); + + vco->rate = rate; + vco->rate_set = true; + + return 0; +} + +static int hdmi_8996_v1_vco_set_rate(struct clk *c, unsigned long rate) +{ + return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V1); +} + +static int hdmi_8996_v2_vco_set_rate(struct clk *c, unsigned long rate) +{ + return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V2); +} + +static int hdmi_8996_v3_vco_set_rate(struct clk *c, unsigned long rate) +{ + return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3); +} + +static int hdmi_8996_v3_1p8_vco_set_rate(struct clk *c, unsigned long rate) +{ + return hdmi_8996_vco_set_rate(c, rate, HDMI_VERSION_8996_V3_1_8); +} + +static unsigned long hdmi_get_hsclk_sel_divisor(unsigned long hsclk_sel) +{ + unsigned long divisor; + + switch (hsclk_sel) { + case 0: + divisor = 2; + break; + case 1: + divisor = 6; + break; + case 2: + divisor = 10; + break; + case 3: + divisor = 14; + break; + case 4: + divisor = 3; + break; + case 5: + divisor = 9; + break; + case 6: + case 13: + divisor = 15; + break; + case 7: + divisor = 21; + break; + case 8: + divisor = 4; + break; + case 9: + divisor = 12; + break; + case 10: + divisor = 20; + break; + case 11: + divisor = 28; + break; + case 12: + divisor = 5; + break; + case 14: + divisor = 25; + break; + case 15: + divisor = 35; + break; + default: + divisor = 1; + DEV_ERR("%s: invalid hsclk_sel value = %lu", + __func__, hsclk_sel); + break; + } + + return divisor; +} + +static unsigned long hdmi_8996_vco_get_rate(struct clk *c) +{ + unsigned long freq = 0, hsclk_sel = 0, tx_band = 0, dec_start = 0, + div_frac_start = 0, vco_clock_freq = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + if (mdss_pll_resource_enable(io, true)) { + DEV_ERR("%s: pll resource can't be enabled\n", __func__); + return freq; + } + + dec_start = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_DEC_START_MODE0); + + div_frac_start = + MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_DIV_FRAC_START1_MODE0) | + MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_DIV_FRAC_START2_MODE0) << 8 | + MDSS_PLL_REG_R(io->pll_base, + QSERDES_COM_DIV_FRAC_START3_MODE0) << 16; + + vco_clock_freq = (dec_start + (div_frac_start / (1 << 20))) + * 4 * (HDMI_REF_CLOCK); + + hsclk_sel = MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_HSCLK_SEL) & 0x15; + hsclk_sel = hdmi_get_hsclk_sel_divisor(hsclk_sel); + tx_band = MDSS_PLL_REG_R(io->pll_base + HDMI_TX_L0_BASE_OFFSET, + QSERDES_TX_L0_TX_BAND) & 0x3; + + freq = vco_clock_freq / (10 * hsclk_sel * (1 << tx_band)); + + mdss_pll_resource_enable(io, false); + + DEV_DBG("%s: freq = %lu\n", __func__, freq); + + return freq; +} + +static long hdmi_8996_vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + + DEV_DBG("rrate=%ld\n", rrate); + + return rrate; +} + +static int hdmi_8996_vco_prepare(struct clk *c, u32 ver) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + int ret = 0; + + DEV_DBG("rate=%ld\n", vco->rate); + + if (!vco->rate_set && vco->rate) + ret = hdmi_8996_vco_set_rate(c, vco->rate, ver); + + if (!ret) { + ret = mdss_pll_resource_enable(io, true); + if (ret) + DEV_ERR("pll resource can't be enabled\n"); + } + + return ret; +} + +static int hdmi_8996_v1_vco_prepare(struct clk *c) +{ + return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V1); +} + +static int hdmi_8996_v2_vco_prepare(struct clk *c) +{ + return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V2); +} + +static int hdmi_8996_v3_vco_prepare(struct clk *c) +{ + return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3); +} + +static int hdmi_8996_v3_1p8_vco_prepare(struct clk *c) +{ + return hdmi_8996_vco_prepare(c, HDMI_VERSION_8996_V3_1_8); +} + +static void hdmi_8996_vco_unprepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + vco->rate_set = false; + + if (!io) { + DEV_ERR("Invalid input parameter\n"); + return; + } + + if (!io->pll_on && + mdss_pll_resource_enable(io, true)) { + DEV_ERR("pll resource can't be enabled\n"); + return; + } + + io->handoff_resources = false; + mdss_pll_resource_enable(io, false); + io->pll_on = false; +} + +static enum handoff hdmi_8996_vco_handoff(struct clk *c) +{ + enum handoff ret = HANDOFF_DISABLED_CLK; + struct hdmi_pll_vco_clk *vco = to_hdmi_8996_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + if (is_gdsc_disabled(io)) + return HANDOFF_DISABLED_CLK; + + if (mdss_pll_resource_enable(io, true)) { + DEV_ERR("pll resource can't be enabled\n"); + return ret; + } + + io->handoff_resources = true; + + if (MDSS_PLL_REG_R(io->pll_base, QSERDES_COM_C_READY_STATUS) & BIT(0)) { + if (MDSS_PLL_REG_R(io->phy_base, HDMI_PHY_STATUS) & BIT(0)) { + io->pll_on = true; + c->rate = hdmi_8996_vco_get_rate(c); + vco->rate = c->rate; + ret = HANDOFF_ENABLED_CLK; + } else { + io->handoff_resources = false; + mdss_pll_resource_enable(io, false); + DEV_DBG("%s: PHY not ready\n", __func__); + } + } else { + io->handoff_resources = false; + mdss_pll_resource_enable(io, false); + DEV_DBG("%s: PLL not locked\n", __func__); + } + + DEV_DBG("done, ret=%d\n", ret); + return ret; +} + +static const struct clk_ops hdmi_8996_v1_vco_clk_ops = { + .enable = hdmi_8996_v1_vco_enable, + .set_rate = hdmi_8996_v1_vco_set_rate, + .get_rate = hdmi_8996_vco_get_rate, + .round_rate = hdmi_8996_vco_round_rate, + .prepare = hdmi_8996_v1_vco_prepare, + .unprepare = hdmi_8996_vco_unprepare, + .handoff = hdmi_8996_vco_handoff, +}; + +static const struct clk_ops hdmi_8996_v2_vco_clk_ops = { + .enable = hdmi_8996_v2_vco_enable, + .set_rate = hdmi_8996_v2_vco_set_rate, + .get_rate = hdmi_8996_vco_get_rate, + .round_rate = hdmi_8996_vco_round_rate, + .prepare = hdmi_8996_v2_vco_prepare, + .unprepare = hdmi_8996_vco_unprepare, + .handoff = hdmi_8996_vco_handoff, +}; + +static const struct clk_ops hdmi_8996_v3_vco_clk_ops = { + .enable = hdmi_8996_v3_vco_enable, + .set_rate = hdmi_8996_v3_vco_set_rate, + .get_rate = hdmi_8996_vco_get_rate, + .round_rate = hdmi_8996_vco_round_rate, + .prepare = hdmi_8996_v3_vco_prepare, + .unprepare = hdmi_8996_vco_unprepare, + .handoff = hdmi_8996_vco_handoff, +}; + +static const struct clk_ops hdmi_8996_v3_1p8_vco_clk_ops = { + .enable = hdmi_8996_v3_1p8_vco_enable, + .set_rate = hdmi_8996_v3_1p8_vco_set_rate, + .get_rate = hdmi_8996_vco_get_rate, + .round_rate = hdmi_8996_vco_round_rate, + .prepare = hdmi_8996_v3_1p8_vco_prepare, + .unprepare = hdmi_8996_vco_unprepare, + .handoff = hdmi_8996_vco_handoff, +}; + + +static struct hdmi_pll_vco_clk hdmi_vco_clk = { + .c = { + .dbg_name = "hdmi_8996_vco_clk", + .ops = &hdmi_8996_v1_vco_clk_ops, + CLK_INIT(hdmi_vco_clk.c), + }, +}; + +static struct clk_lookup hdmipllcc_8996[] = { + CLK_LIST(hdmi_vco_clk), +}; + +int hdmi_8996_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res, u32 ver) +{ + int rc = -ENOTSUPP; + + if (!pll_res || !pll_res->phy_base || !pll_res->pll_base) { + DEV_ERR("%s: Invalid input parameters\n", __func__); + return -EPROBE_DEFER; + } + + /* Set client data for vco, mux and div clocks */ + hdmi_vco_clk.priv = pll_res; + + switch (ver) { + case HDMI_VERSION_8996_V2: + hdmi_vco_clk.c.ops = &hdmi_8996_v2_vco_clk_ops; + break; + case HDMI_VERSION_8996_V3: + hdmi_vco_clk.c.ops = &hdmi_8996_v3_vco_clk_ops; + break; + case HDMI_VERSION_8996_V3_1_8: + hdmi_vco_clk.c.ops = &hdmi_8996_v3_1p8_vco_clk_ops; + break; + default: + hdmi_vco_clk.c.ops = &hdmi_8996_v1_vco_clk_ops; + break; + } + + rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8996, + ARRAY_SIZE(hdmipllcc_8996)); + if (rc) { + DEV_ERR("%s: Clock register failed rc=%d\n", __func__, rc); + rc = -EPROBE_DEFER; + } else { + DEV_DBG("%s SUCCESS\n", __func__); + } + + return rc; +} + +int hdmi_8996_v1_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return hdmi_8996_pll_clock_register(pdev, pll_res, + HDMI_VERSION_8996_V1); +} + +int hdmi_8996_v2_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return hdmi_8996_pll_clock_register(pdev, pll_res, + HDMI_VERSION_8996_V2); +} + +int hdmi_8996_v3_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return hdmi_8996_pll_clock_register(pdev, pll_res, + HDMI_VERSION_8996_V3); +} + +int hdmi_8996_v3_1p8_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + return hdmi_8996_pll_clock_register(pdev, pll_res, + HDMI_VERSION_8996_V3_1_8); +} diff --git a/techpack/display/pll/hdmi_pll_8998.c b/techpack/display/pll/hdmi_pll_8998.c new file mode 100644 index 0000000000000000000000000000000000000000..b4321df435f60a47002b51c4c5ddc7bf6c5f6380 --- /dev/null +++ b/techpack/display/pll/hdmi_pll_8998.c @@ -0,0 +1,827 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> +#include <linux/clk/msm-clock-generic.h> +#include <dt-bindings/clock/msm-clocks-8998.h> + +#include "pll_drv.h" +#include "hdmi_pll.h" + +#define _W(x, y, z) MDSS_PLL_REG_W(x, y, z) +#define _R(x, y) MDSS_PLL_REG_R(x, y) + +/* PLL REGISTERS */ +#define BIAS_EN_CLKBUFLR_EN (0x034) +#define CLK_ENABLE1 (0x038) +#define SYS_CLK_CTRL (0x03C) +#define SYSCLK_BUF_ENABLE (0x040) +#define PLL_IVCO (0x048) +#define CP_CTRL_MODE0 (0x060) +#define PLL_RCTRL_MODE0 (0x068) +#define PLL_CCTRL_MODE0 (0x070) +#define SYSCLK_EN_SEL (0x080) +#define RESETSM_CNTRL (0x088) +#define LOCK_CMP_EN (0x090) +#define LOCK_CMP1_MODE0 (0x098) +#define LOCK_CMP2_MODE0 (0x09C) +#define LOCK_CMP3_MODE0 (0x0A0) +#define DEC_START_MODE0 (0x0B0) +#define DIV_FRAC_START1_MODE0 (0x0B8) +#define DIV_FRAC_START2_MODE0 (0x0BC) +#define DIV_FRAC_START3_MODE0 (0x0C0) +#define INTEGLOOP_GAIN0_MODE0 (0x0D8) +#define INTEGLOOP_GAIN1_MODE0 (0x0DC) +#define VCO_TUNE_CTRL (0x0EC) +#define VCO_TUNE_MAP (0x0F0) +#define CLK_SELECT (0x138) +#define HSCLK_SEL (0x13C) +#define CORECLK_DIV_MODE0 (0x148) +#define CORE_CLK_EN (0x154) +#define C_READY_STATUS (0x158) +#define SVS_MODE_CLK_SEL (0x164) + +/* Tx Channel PHY registers */ +#define PHY_TX_EMP_POST1_LVL(n) ((((n) * 0x200) + 0x400) + 0x000) +#define PHY_TX_INTERFACE_SELECT_TX_BAND(n) ((((n) * 0x200) + 0x400) + 0x008) +#define PHY_TX_CLKBUF_TERM_ENABLE(n) ((((n) * 0x200) + 0x400) + 0x00C) +#define PHY_TX_DRV_LVL_RES_CODE_OFFSET(n) ((((n) * 0x200) + 0x400) + 0x014) +#define PHY_TX_DRV_LVL(n) ((((n) * 0x200) + 0x400) + 0x018) +#define PHY_TX_LANE_CONFIG(n) ((((n) * 0x200) + 0x400) + 0x01C) +#define PHY_TX_PRE_DRIVER_1(n) ((((n) * 0x200) + 0x400) + 0x024) +#define PHY_TX_PRE_DRIVER_2(n) ((((n) * 0x200) + 0x400) + 0x028) +#define PHY_TX_LANE_MODE(n) ((((n) * 0x200) + 0x400) + 0x02C) + +/* HDMI PHY registers */ +#define PHY_CFG (0x00) +#define PHY_PD_CTL (0x04) +#define PHY_MODE (0x10) +#define PHY_CLOCK (0x5C) +#define PHY_CMN_CTRL (0x68) +#define PHY_STATUS (0xB4) + +#define HDMI_BIT_CLK_TO_PIX_CLK_RATIO 10 +#define HDMI_MHZ_TO_HZ 1000000 +#define HDMI_HZ_TO_MHZ 1000000 +#define HDMI_REF_CLOCK_MHZ 19.2 +#define HDMI_REF_CLOCK_HZ (HDMI_REF_CLOCK_MHZ * 1000000) +#define HDMI_VCO_MIN_RATE_HZ 25000000 +#define HDMI_VCO_MAX_RATE_HZ 600000000 + +struct 8998_reg_cfg { + u32 tx_band; + u32 svs_mode_clk_sel; + u32 hsclk_sel; + u32 lock_cmp_en; + u32 cctrl_mode0; + u32 rctrl_mode0; + u32 cpctrl_mode0; + u32 dec_start_mode0; + u32 div_frac_start1_mode0; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 integloop_gain0_mode0; + u32 integloop_gain1_mode0; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 lock_cmp3_mode0; + u32 ssc_per1; + u32 ssc_per2; + u32 ssc_step_size1; + u32 ssc_step_size2; + u32 core_clk_en; + u32 coreclk_div_mode0; + u32 phy_mode; + u32 vco_freq; + u32 hsclk_divsel; + u32 vco_ratio; + u32 ssc_en_center; + + u32 l0_tx_drv_lvl; + u32 l0_tx_emp_post1_lvl; + u32 l1_tx_drv_lvl; + u32 l1_tx_emp_post1_lvl; + u32 l2_tx_drv_lvl; + u32 l2_tx_emp_post1_lvl; + u32 l3_tx_drv_lvl; + u32 l3_tx_emp_post1_lvl; + + u32 l0_pre_driver_1; + u32 l0_pre_driver_2; + u32 l1_pre_driver_1; + u32 l1_pre_driver_2; + u32 l2_pre_driver_1; + u32 l2_pre_driver_2; + u32 l3_pre_driver_1; + u32 l3_pre_driver_2; + + bool debug; +}; + +static void hdmi_8998_get_div(struct 8998_reg_cfg * cfg, unsigned long pclk) +{ + u32 const ratio_list[] = {1, 2, 3, 4, 5, 6, + 9, 10, 12, 15, 25}; + u32 const band_list[] = {0, 1, 2, 3}; + u32 const sz_ratio = ARRAY_SIZE(ratio_list); + u32 const sz_band = ARRAY_SIZE(band_list); + u32 const min_freq = 8000, max_freq = 12000; + u32 const cmp_cnt = 1024; + u32 const th_min = 500, th_max = 1000; + u64 bit_clk = pclk * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + u32 half_rate_mode = 0; + u32 freq_optimal, list_elements; + int optimal_index; + u32 i, j, k; + u32 freq_list[sz_ratio * sz_band]; + u32 found_hsclk_divsel = 0, found_vco_ratio; + u32 found_tx_band_sel, found_vco_freq; + +find_optimal_index: + freq_optimal = max_freq; + optimal_index = -1; + list_elements = 0; + + for (i = 0; i < sz_ratio; i++) { + for (j = 0; j < sz_band; j++) { + u64 freq = (bit_clk / (1 << half_rate_mode)); + + freq *= (ratio_list[i] * (1 << band_list[j])); + do_div(freq, (u64) HDMI_MHZ_TO_HZ); + freq_list[list_elements++] = freq; + } + } + + for (k = 0; k < ARRAY_SIZE(freq_list); k++) { + u32 const clks_pll_div = 2, core_clk_div = 5; + u32 const rng1 = 16, rng2 = 8; + u32 core_clk, rvar1; + u32 th1, th2; + + core_clk = (((freq_list[k] / + ratio_list[k / sz_band]) / + clks_pll_div) / core_clk_div); + + rvar1 = HDMI_REF_CLOCK_HZ / cmp_cnt; + rvar1 *= rng1; + rvar1 /= core_clk; + + th1 = rvar1; + + rvar1 = HDMI_REF_CLOCK_HZ / cmp_cnt; + rvar1 *= rng2; + rvar1 /= core_clk; + + th2 = rvar1; + + if (freq_list[k] >= min_freq && + freq_list[k] <= max_freq) { + if ((th1 >= th_min && th1 <= th_max) || + (th2 >= th_min && th2 <= th_max)) { + if (freq_list[k] <= freq_optimal) { + freq_optimal = freq_list[k]; + optimal_index = k; + } + } + } + } + + if (optimal_index == -1) { + if (!half_rate_mode) { + half_rate_mode = 1; + goto find_optimal_index; + } else { + /* set to default values */ + found_vco_freq = max_freq; + found_hsclk_divsel = 0; + found_vco_ratio = 2; + found_tx_band_sel = 0; + pr_err("Config error for pclk %ld\n", pclk); + } + } else { + found_vco_ratio = ratio_list[optimal_index / sz_band]; + found_tx_band_sel = band_list[optimal_index % sz_band]; + found_vco_freq = freq_optimal; + } + + switch (found_vco_ratio) { + case 1: + found_hsclk_divsel = 15; + break; + case 2: + found_hsclk_divsel = 0; + break; + case 3: + found_hsclk_divsel = 4; + break; + case 4: + found_hsclk_divsel = 8; + break; + case 5: + found_hsclk_divsel = 12; + break; + case 6: + found_hsclk_divsel = 1; + break; + case 9: + found_hsclk_divsel = 5; + break; + case 10: + found_hsclk_divsel = 2; + break; + case 12: + found_hsclk_divsel = 9; + break; + case 15: + found_hsclk_divsel = 13; + break; + case 25: + found_hsclk_divsel = 14; + break; + } + + pr_debug("found_vco_freq=%d\n", found_vco_freq); + pr_debug("found_hsclk_divsel=%d\n", found_hsclk_divsel); + pr_debug("found_vco_ratio=%d\n", found_vco_ratio); + pr_debug("found_tx_band_sel=%d\n", found_tx_band_sel); + pr_debug("half_rate_mode=%d\n", half_rate_mode); + pr_debug("optimal_index=%d\n", optimal_index); + + cfg->vco_freq = found_vco_freq; + cfg->hsclk_divsel = found_hsclk_divsel; + cfg->vco_ratio = found_vco_ratio; + cfg->tx_band = found_tx_band_sel; +} + +static int hdmi_8998_config_phy(unsigned long rate, + struct 8998_reg_cfg * cfg) +{ + u64 const high_freq_bit_clk_threshold = 3400000000UL; + u64 const dig_freq_bit_clk_threshold = 1500000000UL; + u64 const mid_freq_bit_clk_threshold = 750000000; + u64 fdata, tmds_clk; + u64 pll_div = 4 * HDMI_REF_CLOCK_HZ; + u64 bclk; + u64 vco_freq_mhz; + u64 hsclk_sel, dec_start, div_frac_start; + u64 rem; + u64 cpctrl, rctrl, cctrl; + u64 integloop_gain; + u32 digclk_divsel; + u32 tmds_bclk_ratio; + u64 cmp_rng, cmp_cnt = 1024, pll_cmp; + bool gen_ssc = false; + + bclk = rate * HDMI_BIT_CLK_TO_PIX_CLK_RATIO; + + if (bclk > high_freq_bit_clk_threshold) { + tmds_clk = rate / 4; + tmds_bclk_ratio = 1; + } else { + tmds_clk = rate; + tmds_bclk_ratio = 0; + } + + hdmi_8998_get_div(cfg, rate); + + vco_freq_mhz = cfg->vco_freq * (u64) HDMI_HZ_TO_MHZ; + fdata = cfg->vco_freq; + do_div(fdata, cfg->vco_ratio); + + hsclk_sel = cfg->hsclk_divsel; + dec_start = vco_freq_mhz; + do_div(dec_start, pll_div); + + div_frac_start = vco_freq_mhz * (1 << 20); + rem = do_div(div_frac_start, pll_div); + div_frac_start -= (dec_start * (1 << 20)); + if (rem > (pll_div >> 1)) + div_frac_start++; + + if ((div_frac_start != 0) || gen_ssc) { + cpctrl = 0x8; + rctrl = 0x16; + cctrl = 0x34; + } else { + cpctrl = 0x30; + rctrl = 0x18; + cctrl = 0x2; + } + + digclk_divsel = (bclk > dig_freq_bit_clk_threshold) ? 0x1 : 0x2; + + integloop_gain = ((div_frac_start != 0) || + gen_ssc) ? 0x3F : 0xC4; + integloop_gain <<= digclk_divsel; + integloop_gain = (integloop_gain <= 2046 ? integloop_gain : 0x7FE); + + cmp_rng = gen_ssc ? 0x40 : 0x10; + + pll_cmp = cmp_cnt * fdata; + rem = do_div(pll_cmp, (u64)(HDMI_REF_CLOCK_MHZ * 10)); + if (rem > ((u64)(HDMI_REF_CLOCK_MHZ * 10) >> 1)) + pll_cmp++; + + pll_cmp = pll_cmp - 1; + + pr_debug("VCO_FREQ = %u\n", cfg->vco_freq); + pr_debug("FDATA = %llu\n", fdata); + pr_debug("DEC_START = %llu\n", dec_start); + pr_debug("DIV_FRAC_START = %llu\n", div_frac_start); + pr_debug("CPCTRL = %llu\n", cpctrl); + pr_debug("RCTRL = %llu\n", rctrl); + pr_debug("CCTRL = %llu\n", cctrl); + pr_debug("DIGCLK_DIVSEL = %u\n", digclk_divsel); + pr_debug("INTEGLOOP_GAIN = %llu\n", integloop_gain); + pr_debug("CMP_RNG = %llu\n", cmp_rng); + pr_debug("PLL_CMP = %llu\n", pll_cmp); + + cfg->svs_mode_clk_sel = (digclk_divsel & 0xFF); + cfg->hsclk_sel = (0x20 | hsclk_sel); + cfg->lock_cmp_en = (gen_ssc ? 0x4 : 0x0); + cfg->cctrl_mode0 = (cctrl & 0xFF); + cfg->rctrl_mode0 = (rctrl & 0xFF); + cfg->cpctrl_mode0 = (cpctrl & 0xFF); + cfg->dec_start_mode0 = (dec_start & 0xFF); + cfg->div_frac_start1_mode0 = (div_frac_start & 0xFF); + cfg->div_frac_start2_mode0 = ((div_frac_start & 0xFF00) >> 8); + cfg->div_frac_start3_mode0 = ((div_frac_start & 0xF0000) >> 16); + cfg->integloop_gain0_mode0 = (integloop_gain & 0xFF); + cfg->integloop_gain1_mode0 = (integloop_gain & 0xF00) >> 8; + cfg->lock_cmp1_mode0 = (pll_cmp & 0xFF); + cfg->lock_cmp2_mode0 = ((pll_cmp & 0xFF00) >> 8); + cfg->lock_cmp3_mode0 = ((pll_cmp & 0x30000) >> 16); + cfg->ssc_per1 = 0; + cfg->ssc_per2 = 0; + cfg->ssc_step_size1 = 0; + cfg->ssc_step_size2 = 0; + cfg->core_clk_en = 0x2C; + cfg->coreclk_div_mode0 = 0x5; + cfg->phy_mode = (tmds_bclk_ratio ? 0x5 : 0x4); + cfg->ssc_en_center = 0x0; + + if (bclk > high_freq_bit_clk_threshold) { + cfg->l0_tx_drv_lvl = 0xA; + cfg->l0_tx_emp_post1_lvl = 0x3; + cfg->l1_tx_drv_lvl = 0xA; + cfg->l1_tx_emp_post1_lvl = 0x3; + cfg->l2_tx_drv_lvl = 0xA; + cfg->l2_tx_emp_post1_lvl = 0x3; + cfg->l3_tx_drv_lvl = 0x8; + cfg->l3_tx_emp_post1_lvl = 0x3; + cfg->l0_pre_driver_1 = 0x0; + cfg->l0_pre_driver_2 = 0x1C; + cfg->l1_pre_driver_1 = 0x0; + cfg->l1_pre_driver_2 = 0x1C; + cfg->l2_pre_driver_1 = 0x0; + cfg->l2_pre_driver_2 = 0x1C; + cfg->l3_pre_driver_1 = 0x0; + cfg->l3_pre_driver_2 = 0x0; + } else if (bclk > dig_freq_bit_clk_threshold) { + cfg->l0_tx_drv_lvl = 0x9; + cfg->l0_tx_emp_post1_lvl = 0x3; + cfg->l1_tx_drv_lvl = 0x9; + cfg->l1_tx_emp_post1_lvl = 0x3; + cfg->l2_tx_drv_lvl = 0x9; + cfg->l2_tx_emp_post1_lvl = 0x3; + cfg->l3_tx_drv_lvl = 0x8; + cfg->l3_tx_emp_post1_lvl = 0x3; + cfg->l0_pre_driver_1 = 0x0; + cfg->l0_pre_driver_2 = 0x16; + cfg->l1_pre_driver_1 = 0x0; + cfg->l1_pre_driver_2 = 0x16; + cfg->l2_pre_driver_1 = 0x0; + cfg->l2_pre_driver_2 = 0x16; + cfg->l3_pre_driver_1 = 0x0; + cfg->l3_pre_driver_2 = 0x0; + } else if (bclk > mid_freq_bit_clk_threshold) { + cfg->l0_tx_drv_lvl = 0x9; + cfg->l0_tx_emp_post1_lvl = 0x3; + cfg->l1_tx_drv_lvl = 0x9; + cfg->l1_tx_emp_post1_lvl = 0x3; + cfg->l2_tx_drv_lvl = 0x9; + cfg->l2_tx_emp_post1_lvl = 0x3; + cfg->l3_tx_drv_lvl = 0x8; + cfg->l3_tx_emp_post1_lvl = 0x3; + cfg->l0_pre_driver_1 = 0x0; + cfg->l0_pre_driver_2 = 0x0E; + cfg->l1_pre_driver_1 = 0x0; + cfg->l1_pre_driver_2 = 0x0E; + cfg->l2_pre_driver_1 = 0x0; + cfg->l2_pre_driver_2 = 0x0E; + cfg->l3_pre_driver_1 = 0x0; + cfg->l3_pre_driver_2 = 0x0; + } else { + cfg->l0_tx_drv_lvl = 0x0; + cfg->l0_tx_emp_post1_lvl = 0x0; + cfg->l1_tx_drv_lvl = 0x0; + cfg->l1_tx_emp_post1_lvl = 0x0; + cfg->l2_tx_drv_lvl = 0x0; + cfg->l2_tx_emp_post1_lvl = 0x0; + cfg->l3_tx_drv_lvl = 0x0; + cfg->l3_tx_emp_post1_lvl = 0x0; + cfg->l0_pre_driver_1 = 0x0; + cfg->l0_pre_driver_2 = 0x01; + cfg->l1_pre_driver_1 = 0x0; + cfg->l1_pre_driver_2 = 0x01; + cfg->l2_pre_driver_1 = 0x0; + cfg->l2_pre_driver_2 = 0x01; + cfg->l3_pre_driver_1 = 0x0; + cfg->l3_pre_driver_2 = 0x0; + } + + return 0; +} + +static int hdmi_8998_pll_set_clk_rate(struct clk *c, unsigned long rate) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + struct 8998_reg_cfg cfg = {0}; + void __iomem *phy = io->phy_base, *pll = io->pll_base; + + rc = hdmi_8998_config_phy(rate, &cfg); + if (rc) { + pr_err("rate calculation failed\n, rc=%d\n", rc); + return rc; + } + + _W(phy, PHY_PD_CTL, 0x0); + udelay(500); + + _W(phy, PHY_PD_CTL, 0x1); + _W(pll, RESETSM_CNTRL, 0x20); + _W(phy, PHY_CMN_CTRL, 0x6); + _W(pll, PHY_TX_INTERFACE_SELECT_TX_BAND(0), cfg.tx_band); + _W(pll, PHY_TX_INTERFACE_SELECT_TX_BAND(1), cfg.tx_band); + _W(pll, PHY_TX_INTERFACE_SELECT_TX_BAND(2), cfg.tx_band); + _W(pll, PHY_TX_INTERFACE_SELECT_TX_BAND(3), cfg.tx_band); + _W(pll, PHY_TX_CLKBUF_TERM_ENABLE(0), 0x1); + _W(pll, PHY_TX_LANE_MODE(0), 0x20); + _W(pll, PHY_TX_LANE_MODE(1), 0x20); + _W(pll, PHY_TX_LANE_MODE(2), 0x20); + _W(pll, PHY_TX_LANE_MODE(3), 0x20); + _W(pll, PHY_TX_CLKBUF_TERM_ENABLE(1), 0x1); + _W(pll, PHY_TX_CLKBUF_TERM_ENABLE(2), 0x1); + _W(pll, PHY_TX_CLKBUF_TERM_ENABLE(3), 0x1); + _W(pll, SYSCLK_BUF_ENABLE, 0x2); + _W(pll, BIAS_EN_CLKBUFLR_EN, 0xB); + _W(pll, SYSCLK_EN_SEL, 0x37); + _W(pll, SYS_CLK_CTRL, 0x2); + _W(pll, CLK_ENABLE1, 0xE); + _W(pll, PLL_IVCO, 0xF); + _W(pll, VCO_TUNE_CTRL, 0x0); + _W(pll, SVS_MODE_CLK_SEL, cfg.svs_mode_clk_sel); + _W(pll, CLK_SELECT, 0x30); + _W(pll, HSCLK_SEL, cfg.hsclk_sel); + _W(pll, LOCK_CMP_EN, cfg.lock_cmp_en); + _W(pll, PLL_CCTRL_MODE0, cfg.cctrl_mode0); + _W(pll, PLL_RCTRL_MODE0, cfg.rctrl_mode0); + _W(pll, CP_CTRL_MODE0, cfg.cpctrl_mode0); + _W(pll, DEC_START_MODE0, cfg.dec_start_mode0); + _W(pll, DIV_FRAC_START1_MODE0, cfg.div_frac_start1_mode0); + _W(pll, DIV_FRAC_START2_MODE0, cfg.div_frac_start2_mode0); + _W(pll, DIV_FRAC_START3_MODE0, cfg.div_frac_start3_mode0); + _W(pll, INTEGLOOP_GAIN0_MODE0, cfg.integloop_gain0_mode0); + _W(pll, INTEGLOOP_GAIN1_MODE0, cfg.integloop_gain1_mode0); + _W(pll, LOCK_CMP1_MODE0, cfg.lock_cmp1_mode0); + _W(pll, LOCK_CMP2_MODE0, cfg.lock_cmp2_mode0); + _W(pll, LOCK_CMP3_MODE0, cfg.lock_cmp3_mode0); + _W(pll, VCO_TUNE_MAP, 0x0); + _W(pll, CORE_CLK_EN, cfg.core_clk_en); + _W(pll, CORECLK_DIV_MODE0, cfg.coreclk_div_mode0); + + _W(pll, PHY_TX_DRV_LVL(0), cfg.l0_tx_drv_lvl); + _W(pll, PHY_TX_DRV_LVL(1), cfg.l1_tx_drv_lvl); + _W(pll, PHY_TX_DRV_LVL(2), cfg.l2_tx_drv_lvl); + _W(pll, PHY_TX_DRV_LVL(3), cfg.l3_tx_drv_lvl); + + _W(pll, PHY_TX_EMP_POST1_LVL(0), cfg.l0_tx_emp_post1_lvl); + _W(pll, PHY_TX_EMP_POST1_LVL(1), cfg.l1_tx_emp_post1_lvl); + _W(pll, PHY_TX_EMP_POST1_LVL(2), cfg.l2_tx_emp_post1_lvl); + _W(pll, PHY_TX_EMP_POST1_LVL(3), cfg.l3_tx_emp_post1_lvl); + + _W(pll, PHY_TX_PRE_DRIVER_1(0), cfg.l0_pre_driver_1); + _W(pll, PHY_TX_PRE_DRIVER_1(1), cfg.l1_pre_driver_1); + _W(pll, PHY_TX_PRE_DRIVER_1(2), cfg.l2_pre_driver_1); + _W(pll, PHY_TX_PRE_DRIVER_1(3), cfg.l3_pre_driver_1); + + _W(pll, PHY_TX_PRE_DRIVER_2(0), cfg.l0_pre_driver_2); + _W(pll, PHY_TX_PRE_DRIVER_2(1), cfg.l1_pre_driver_2); + _W(pll, PHY_TX_PRE_DRIVER_2(2), cfg.l2_pre_driver_2); + _W(pll, PHY_TX_PRE_DRIVER_2(3), cfg.l3_pre_driver_2); + + _W(pll, PHY_TX_DRV_LVL_RES_CODE_OFFSET(0), 0x0); + _W(pll, PHY_TX_DRV_LVL_RES_CODE_OFFSET(1), 0x0); + _W(pll, PHY_TX_DRV_LVL_RES_CODE_OFFSET(2), 0x0); + _W(pll, PHY_TX_DRV_LVL_RES_CODE_OFFSET(3), 0x0); + + _W(phy, PHY_MODE, cfg.phy_mode); + + _W(pll, PHY_TX_LANE_CONFIG(0), 0x10); + _W(pll, PHY_TX_LANE_CONFIG(1), 0x10); + _W(pll, PHY_TX_LANE_CONFIG(2), 0x10); + _W(pll, PHY_TX_LANE_CONFIG(3), 0x10); + + /* Ensure all registers are flushed to hardware */ + wmb(); + + return 0; +} + +static int hdmi_8998_pll_lock_status(struct mdss_pll_resources *io) +{ + u32 const delay_us = 100; + u32 const timeout_us = 5000; + u32 status; + int rc = 0; + void __iomem *pll = io->pll_base; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + rc = readl_poll_timeout_atomic(pll + C_READY_STATUS, + status, + ((status & BIT(0)) > 0), + delay_us, + timeout_us); + if (rc) + pr_err("HDMI PLL(%d) lock failed, status=0x%08x\n", + io->index, status); + else + pr_debug("HDMI PLL(%d) lock passed, status=0x%08x\n", + io->index, status); + + mdss_pll_resource_enable(io, false); + + return rc; +} + +static int hdmi_8998_phy_ready_status(struct mdss_pll_resources *io) +{ + u32 const delay_us = 100; + u32 const timeout_us = 5000; + u32 status; + int rc = 0; + void __iomem *phy = io->phy_base; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource can't be enabled\n"); + return rc; + } + + rc = readl_poll_timeout_atomic(phy + PHY_STATUS, + status, + ((status & BIT(0)) > 0), + delay_us, + timeout_us); + if (rc) + pr_err("HDMI PHY(%d) not ready, status=0x%08x\n", + io->index, status); + else + pr_debug("HDMI PHY(%d) ready, status=0x%08x\n", + io->index, status); + + mdss_pll_resource_enable(io, false); + + return rc; +} + +static int hdmi_8998_vco_set_rate(struct clk *c, unsigned long rate) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource enable failed, rc=%d\n", rc); + return rc; + } + + if (io->pll_on) + goto error; + + rc = hdmi_8998_pll_set_clk_rate(c, rate); + if (rc) { + pr_err("failed to set clk rate, rc=%d\n", rc); + goto error; + } + + vco->rate = rate; + vco->rate_set = true; + +error: + (void)mdss_pll_resource_enable(io, false); + + return rc; +} + +static long hdmi_8998_vco_round_rate(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + return rrate; +} + +static int hdmi_8998_pll_enable(struct clk *c) +{ + int rc = 0; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + void __iomem *phy = io->phy_base, *pll = io->pll_base; + + _W(phy, PHY_CFG, 0x1); + udelay(100); + _W(phy, PHY_CFG, 0x59); + udelay(100); + + _W(phy, PHY_CLOCK, 0x6); + + /* Ensure all registers are flushed to hardware */ + wmb(); + + rc = hdmi_8998_pll_lock_status(io); + if (rc) { + pr_err("PLL not locked, rc=%d\n", rc); + return rc; + } + + _W(pll, PHY_TX_LANE_CONFIG(0), 0x1F); + _W(pll, PHY_TX_LANE_CONFIG(1), 0x1F); + _W(pll, PHY_TX_LANE_CONFIG(2), 0x1F); + _W(pll, PHY_TX_LANE_CONFIG(3), 0x1F); + + /* Ensure all registers are flushed to hardware */ + wmb(); + + rc = hdmi_8998_phy_ready_status(io); + if (rc) { + pr_err("PHY NOT READY, rc=%d\n", rc); + return rc; + } + + _W(phy, PHY_CFG, 0x58); + udelay(1); + _W(phy, PHY_CFG, 0x59); + + /* Ensure all registers are flushed to hardware */ + wmb(); + + io->pll_on = true; + return rc; +} + +static int hdmi_8998_vco_prepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + int rc = 0; + + if (!io) { + pr_err("hdmi pll resources are not available\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(io, true); + if (rc) { + pr_err("pll resource enable failed, rc=%d\n", rc); + return rc; + } + + if (!vco->rate_set && vco->rate) { + rc = hdmi_8998_pll_set_clk_rate(c, vco->rate); + if (rc) { + pr_err("set rate failed, rc=%d\n", rc); + goto error; + } + } + + rc = hdmi_8998_pll_enable(c); + if (rc) + pr_err("pll enabled failed, rc=%d\n", rc); + +error: + if (rc) + mdss_pll_resource_enable(io, false); + + return rc; +} + +static void hdmi_8998_pll_disable(struct hdmi_pll_vco_clk *vco) +{ + struct mdss_pll_resources *io = vco->priv; + void __iomem *phy = io->phy_base; + + if (!io->pll_on) + return; + + _W(phy, PHY_PD_CTL, 0x0); + + /* Ensure all registers are flushed to hardware */ + wmb(); + + vco->rate_set = false; + io->handoff_resources = false; + io->pll_on = false; +} + +static void hdmi_8998_vco_unprepare(struct clk *c) +{ + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + if (!io) { + pr_err("HDMI pll resources not available\n"); + return; + } + + hdmi_8998_pll_disable(vco); + mdss_pll_resource_enable(io, false); +} + +static enum handoff hdmi_8998_vco_handoff(struct clk *c) +{ + enum handoff ret = HANDOFF_DISABLED_CLK; + struct hdmi_pll_vco_clk *vco = to_hdmi_vco_clk(c); + struct mdss_pll_resources *io = vco->priv; + + if (mdss_pll_resource_enable(io, true)) { + pr_err("pll resource can't be enabled\n"); + return ret; + } + + io->handoff_resources = true; + + if (_R(io->pll_base, C_READY_STATUS) & BIT(0) && + _R(io->phy_base, PHY_STATUS) & BIT(0)) { + io->pll_on = true; + /* TODO: calculate rate based on the phy/pll register values. */ + ret = HANDOFF_ENABLED_CLK; + } else { + io->handoff_resources = false; + mdss_pll_resource_enable(io, false); + pr_debug("%s: PHY/PLL not ready\n", __func__); + } + + pr_debug("done, ret=%d\n", ret); + return ret; +} + +static const struct clk_ops hdmi_8998_vco_clk_ops = { + .set_rate = hdmi_8998_vco_set_rate, + .round_rate = hdmi_8998_vco_round_rate, + .prepare = hdmi_8998_vco_prepare, + .unprepare = hdmi_8998_vco_unprepare, + .handoff = hdmi_8998_vco_handoff, +}; + +static struct hdmi_pll_vco_clk hdmi_vco_clk = { + .min_rate = HDMI_VCO_MIN_RATE_HZ, + .max_rate = HDMI_VCO_MAX_RATE_HZ, + .c = { + .dbg_name = "hdmi_8998_vco_clk", + .ops = &hdmi_8998_vco_clk_ops, + CLK_INIT(hdmi_vco_clk.c), + }, +}; + +static struct clk_lookup hdmipllcc_8998[] = { + CLK_LIST(hdmi_vco_clk), +}; + +int hdmi_8998_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0; + + hdmi_vco_clk.priv = pll_res; + + rc = of_msm_clock_register(pdev->dev.of_node, hdmipllcc_8998, + ARRAY_SIZE(hdmipllcc_8998)); + if (rc) { + pr_err("clock register failed, rc=%d\n", rc); + return rc; + } + + return rc; +} diff --git a/techpack/display/pll/pll_drv.c b/techpack/display/pll/pll_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..5e0cd4cf4e7acdc51295b9963f16871e3a5838c7 --- /dev/null +++ b/techpack/display/pll/pll_drv.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include "pll_drv.h" +#include "dsi_pll.h" +#include "dp_pll.h" +#include "hdmi_pll.h" + +int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable) +{ + int rc = 0; + int changed = 0; + + if (!pll_res) { + pr_err("Invalid input parameters\n"); + return -EINVAL; + } + + /* + * Don't turn off resources during handoff or add more than + * 1 refcount. + */ + if (pll_res->handoff_resources && + (!enable || (enable & pll_res->resource_enable))) { + pr_debug("Do not turn on/off pll resources during handoff case\n"); + return rc; + } + + if (enable) { + if (pll_res->resource_ref_cnt == 0) + changed++; + pll_res->resource_ref_cnt++; + } else { + if (pll_res->resource_ref_cnt) { + pll_res->resource_ref_cnt--; + if (pll_res->resource_ref_cnt == 0) + changed++; + } else { + pr_err("PLL Resources already OFF\n"); + } + } + + if (changed) { + rc = mdss_pll_util_resource_enable(pll_res, enable); + if (rc) + pr_err("Resource update failed rc=%d\n", rc); + else + pll_res->resource_enable = enable; + } + + return rc; +} + +static int mdss_pll_resource_init(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0; + struct dss_module_power *mp = &pll_res->mp; + + rc = msm_dss_config_vreg(&pdev->dev, + mp->vreg_config, mp->num_vreg, 1); + if (rc) { + pr_err("Vreg config failed rc=%d\n", rc); + goto vreg_err; + } + + rc = msm_dss_get_clk(&pdev->dev, mp->clk_config, mp->num_clk); + if (rc) { + pr_err("Clock get failed rc=%d\n", rc); + goto clk_err; + } + + return rc; + +clk_err: + msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0); +vreg_err: + return rc; +} + +static void mdss_pll_resource_deinit(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + struct dss_module_power *mp = &pll_res->mp; + + msm_dss_put_clk(mp->clk_config, mp->num_clk); + + msm_dss_config_vreg(&pdev->dev, mp->vreg_config, mp->num_vreg, 0); +} + +static void mdss_pll_resource_release(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + struct dss_module_power *mp = &pll_res->mp; + + mp->num_vreg = 0; + mp->num_clk = 0; +} + +static int mdss_pll_resource_parse(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0; + const char *compatible_stream; + + rc = mdss_pll_util_resource_parse(pdev, pll_res); + if (rc) { + pr_err("Failed to parse the resources rc=%d\n", rc); + goto end; + } + + compatible_stream = of_get_property(pdev->dev.of_node, + "compatible", NULL); + if (!compatible_stream) { + pr_err("Failed to parse the compatible stream\n"); + goto err; + } + + if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_10nm")) + pll_res->pll_interface_type = MDSS_DSI_PLL_10NM; + if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_10nm")) + pll_res->pll_interface_type = MDSS_DP_PLL_10NM; + else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_7nm")) + pll_res->pll_interface_type = MDSS_DP_PLL_7NM; + else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_7nm_v2")) + pll_res->pll_interface_type = MDSS_DP_PLL_7NM_V2; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_7nm")) + pll_res->pll_interface_type = MDSS_DSI_PLL_7NM; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_7nm_v2")) + pll_res->pll_interface_type = MDSS_DSI_PLL_7NM_V2; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_7nm_v4_1")) + pll_res->pll_interface_type = MDSS_DSI_PLL_7NM_V4_1; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_28lpm")) + pll_res->pll_interface_type = MDSS_DSI_PLL_28LPM; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_14nm")) + pll_res->pll_interface_type = MDSS_DSI_PLL_14NM; + else if (!strcmp(compatible_stream, "qcom,mdss_dp_pll_14nm")) + pll_res->pll_interface_type = MDSS_DP_PLL_14NM; + else if (!strcmp(compatible_stream, "qcom,mdss_hdmi_pll_28lpm")) + pll_res->pll_interface_type = MDSS_HDMI_PLL_28LPM; + else + goto err; + + return rc; + +err: + mdss_pll_resource_release(pdev, pll_res); +end: + return rc; +} +static int mdss_pll_clock_register(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc; + + switch (pll_res->pll_interface_type) { + case MDSS_DSI_PLL_10NM: + rc = dsi_pll_clock_register_10nm(pdev, pll_res); + break; + case MDSS_DP_PLL_10NM: + rc = dp_pll_clock_register_10nm(pdev, pll_res); + break; + case MDSS_DSI_PLL_7NM: + case MDSS_DSI_PLL_7NM_V2: + case MDSS_DSI_PLL_7NM_V4_1: + rc = dsi_pll_clock_register_7nm(pdev, pll_res); + break; + case MDSS_DP_PLL_7NM: + case MDSS_DP_PLL_7NM_V2: + rc = dp_pll_clock_register_7nm(pdev, pll_res); + break; + case MDSS_DSI_PLL_28LPM: + rc = dsi_pll_clock_register_28lpm(pdev, pll_res); + break; + case MDSS_DSI_PLL_14NM: + rc = dsi_pll_clock_register_14nm(pdev, pll_res); + break; + case MDSS_DP_PLL_14NM: + rc = dp_pll_clock_register_14nm(pdev, pll_res); + break; + case MDSS_HDMI_PLL_28LPM: + rc = hdmi_pll_clock_register_28lpm(pdev, pll_res); + break; + case MDSS_UNKNOWN_PLL: + default: + rc = -EINVAL; + break; + } + + if (rc) + pr_err("Pll ndx=%d clock register failed rc=%d\n", + pll_res->index, rc); + + return rc; +} + +static inline int mdss_pll_get_ioresurces(struct platform_device *pdev, + void __iomem **regmap, char *resource_name) +{ + int rc = 0; + struct resource *rsc = platform_get_resource_byname(pdev, + IORESOURCE_MEM, resource_name); + if (rsc) { + if (!regmap) + return -ENOMEM; + + *regmap = devm_ioremap(&pdev->dev, + rsc->start, resource_size(rsc)); + if (!*regmap) + return -ENOMEM; + } + return rc; +} + +static int mdss_pll_probe(struct platform_device *pdev) +{ + int rc = 0; + const char *label; + struct mdss_pll_resources *pll_res; + + if (!pdev->dev.of_node) { + pr_err("MDSS pll driver only supports device tree probe\n"); + return -ENOTSUPP; + } + + label = of_get_property(pdev->dev.of_node, "label", NULL); + if (!label) + pr_info("MDSS pll label not specified\n"); + else + pr_info("MDSS pll label = %s\n", label); + + pll_res = devm_kzalloc(&pdev->dev, sizeof(struct mdss_pll_resources), + GFP_KERNEL); + if (!pll_res) + return -ENOMEM; + + platform_set_drvdata(pdev, pll_res); + + rc = of_property_read_u32(pdev->dev.of_node, "cell-index", + &pll_res->index); + if (rc) { + pr_err("Unable to get the cell-index rc=%d\n", rc); + pll_res->index = 0; + } + + pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node, + "qcom,dsi-pll-ssc-en"); + + if (pll_res->ssc_en) { + pr_info("%s: label=%s PLL SSC enabled\n", __func__, label); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,ssc-frequency-hz", &pll_res->ssc_freq); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,ssc-ppm", &pll_res->ssc_ppm); + + pll_res->ssc_center = false; + + label = of_get_property(pdev->dev.of_node, + "qcom,dsi-pll-ssc-mode", NULL); + + if (label && !strcmp(label, "center-spread")) + pll_res->ssc_center = true; + } + + + if (mdss_pll_get_ioresurces(pdev, &pll_res->pll_base, "pll_base")) { + pr_err("Unable to remap pll base resources\n"); + return -ENOMEM; + } + + pr_debug("%s: ndx=%d base=%p\n", __func__, + pll_res->index, pll_res->pll_base); + + rc = mdss_pll_resource_parse(pdev, pll_res); + if (rc) { + pr_err("Pll resource parsing from dt failed rc=%d\n", rc); + return rc; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->phy_base, "phy_base")) { + pr_err("Unable to remap pll phy base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->dyn_pll_base, + "dynamic_pll_base")) { + pr_err("Unable to remap dynamic pll base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->ln_tx0_base, + "ln_tx0_base")) { + pr_err("Unable to remap Lane TX0 base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->ln_tx0_tran_base, + "ln_tx0_tran_base")) { + pr_err("Unable to remap Lane TX0 base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->ln_tx0_vmode_base, + "ln_tx0_vmode_base")) { + pr_err("Unable to remap Lane TX0 base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->ln_tx1_base, + "ln_tx1_base")) { + pr_err("Unable to remap Lane TX1 base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->ln_tx1_tran_base, + "ln_tx1_tran_base")) { + pr_err("Unable to remap Lane TX1 base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->ln_tx1_vmode_base, + "ln_tx1_vmode_base")) { + pr_err("Unable to remap Lane TX1 base resources\n"); + return -ENOMEM; + } + + if (mdss_pll_get_ioresurces(pdev, &pll_res->gdsc_base, "gdsc_base")) { + pr_err("Unable to remap gdsc base resources\n"); + return -ENOMEM; + } + + rc = mdss_pll_resource_init(pdev, pll_res); + if (rc) { + pr_err("Pll ndx=%d resource init failed rc=%d\n", + pll_res->index, rc); + return rc; + } + + rc = mdss_pll_clock_register(pdev, pll_res); + if (rc) { + pr_err("Pll ndx=%d clock register failed rc=%d\n", + pll_res->index, rc); + goto clock_register_error; + } + + return rc; + +clock_register_error: + mdss_pll_resource_deinit(pdev, pll_res); + return rc; +} + +static int mdss_pll_remove(struct platform_device *pdev) +{ + struct mdss_pll_resources *pll_res; + + pll_res = platform_get_drvdata(pdev); + if (!pll_res) { + pr_err("Invalid PLL resource data\n"); + return 0; + } + + mdss_pll_resource_deinit(pdev, pll_res); + mdss_pll_resource_release(pdev, pll_res); + return 0; +} + +static const struct of_device_id mdss_pll_dt_match[] = { + {.compatible = "qcom,mdss_dsi_pll_10nm"}, + {.compatible = "qcom,mdss_dp_pll_10nm"}, + {.compatible = "qcom,mdss_dsi_pll_7nm"}, + {.compatible = "qcom,mdss_dsi_pll_7nm_v2"}, + {.compatible = "qcom,mdss_dsi_pll_7nm_v4_1"}, + {.compatible = "qcom,mdss_dp_pll_7nm"}, + {.compatible = "qcom,mdss_dp_pll_7nm_v2"}, + {.compatible = "qcom,mdss_dsi_pll_28lpm"}, + {.compatible = "qcom,mdss_dsi_pll_14nm"}, + {.compatible = "qcom,mdss_dp_pll_14nm"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, mdss_clock_dt_match); + +static struct platform_driver mdss_pll_driver = { + .probe = mdss_pll_probe, + .remove = mdss_pll_remove, + .driver = { + .name = "mdss_pll", + .of_match_table = mdss_pll_dt_match, + }, +}; + +static int __init mdss_pll_driver_init(void) +{ + int rc; + + rc = platform_driver_register(&mdss_pll_driver); + if (rc) + pr_err("mdss_register_pll_driver() failed!\n"); + + return rc; +} +fs_initcall(mdss_pll_driver_init); + +static void __exit mdss_pll_driver_deinit(void) +{ + platform_driver_unregister(&mdss_pll_driver); +} +module_exit(mdss_pll_driver_deinit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("mdss pll driver"); diff --git a/techpack/display/pll/pll_drv.h b/techpack/display/pll/pll_drv.h new file mode 100644 index 0000000000000000000000000000000000000000..2f03d860ec7288c41adb5447e6a018ef09beee1d --- /dev/null +++ b/techpack/display/pll/pll_drv.h @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __MDSS_PLL_H +#define __MDSS_PLL_H + +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/regmap.h> +#include "clk-regmap.h" +#include "clk-regmap-divider.h" +#include "clk-regmap-mux.h" + +#if defined(CONFIG_DRM) +#include <linux/sde_io_util.h> +#else +#include <linux/mdss_io_util.h> +#endif + +#define MDSS_PLL_REG_W(base, offset, data) \ + writel_relaxed((data), (base) + (offset)) +#define MDSS_PLL_REG_R(base, offset) readl_relaxed((base) + (offset)) + +#define PLL_CALC_DATA(addr0, addr1, data0, data1) \ + (((data1) << 24) | ((((addr1) / 4) & 0xFF) << 16) | \ + ((data0) << 8) | (((addr0) / 4) & 0xFF)) + +#define MDSS_DYN_PLL_REG_W(base, offset, addr0, addr1, data0, data1) \ + writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \ + (base) + (offset)) + +#define upper_8_bit(x) ((((x) >> 2) & 0x100) >> 8) + +enum { + MDSS_DSI_PLL_10NM, + MDSS_DP_PLL_10NM, + MDSS_DSI_PLL_7NM, + MDSS_DSI_PLL_7NM_V2, + MDSS_DSI_PLL_7NM_V4_1, + MDSS_DP_PLL_7NM, + MDSS_DP_PLL_7NM_V2, + MDSS_DSI_PLL_28LPM, + MDSS_DSI_PLL_14NM, + MDSS_DP_PLL_14NM, + MDSS_HDMI_PLL_28LPM, + MDSS_UNKNOWN_PLL, +}; + +enum { + MDSS_PLL_TARGET_8996, +}; + +#define DFPS_MAX_NUM_OF_FRAME_RATES 16 + +struct dfps_pll_codes { + uint32_t pll_codes_1; + uint32_t pll_codes_2; + uint32_t pll_codes_3; +}; + +struct dfps_codes_info { + uint32_t is_valid; + uint32_t clk_rate; /* hz */ + struct dfps_pll_codes pll_codes; +}; + +struct dfps_info { + uint32_t vco_rate_cnt; + struct dfps_codes_info codes_dfps[DFPS_MAX_NUM_OF_FRAME_RATES]; +}; + +struct mdss_pll_resources { + + /* Pll specific resources like GPIO, power supply, clocks, etc*/ + struct dss_module_power mp; + + /* + * dsi/edp/hmdi plls' base register, phy, gdsc and dynamic refresh + * register mapping + */ + void __iomem *pll_base; + void __iomem *phy_base; + void __iomem *ln_tx0_base; + void __iomem *ln_tx0_tran_base; + void __iomem *ln_tx0_vmode_base; + void __iomem *ln_tx1_base; + void __iomem *ln_tx1_tran_base; + void __iomem *ln_tx1_vmode_base; + void __iomem *gdsc_base; + void __iomem *dyn_pll_base; + + bool is_init_locked; + s64 vco_current_rate; + s64 vco_locking_rate; + s64 vco_ref_clk_rate; + + /* + * Certain pll's needs to update the same vco rate after resume in + * suspend/resume scenario. Cached the vco rate for such plls. + */ + unsigned long vco_cached_rate; + u32 cached_cfg0; + u32 cached_cfg1; + u32 cached_outdiv; + + u32 cached_postdiv1; + u32 cached_postdiv3; + u32 cached_vreg_cfg; + + /* dsi/edp/hmdi pll interface type */ + u32 pll_interface_type; + + /* + * Target ID. Used in pll_register API for valid target check before + * registering the PLL clocks. + */ + u32 target_id; + + /* HW recommended delay during configuration of vco clock rate */ + u32 vco_delay; + + /* Ref-count of the PLL resources */ + u32 resource_ref_cnt; + + /* + * Keep track to resource status to avoid updating same status for the + * pll from different paths + */ + bool resource_enable; + + /* + * Certain plls' do not allow vco rate update if it is on. Keep track of + * status for them to turn on/off after set rate success. + */ + bool pll_on; + + /* + * handoff_status is true of pll is already enabled by bootloader with + * continuous splash enable case. Clock API will call the handoff API + * to enable the status. It is disabled if continuous splash + * feature is disabled. + */ + bool handoff_resources; + + /* + * caching the pll trim codes in the case of dynamic refresh + */ + int cache_pll_trim_codes[3]; + + /* + * for maintaining the status of saving trim codes + */ + bool reg_upd; + + /* + * Notifier callback for MDSS gdsc regulator events + */ + struct notifier_block gdsc_cb; + + /* + * Worker function to call PLL off event + */ + struct work_struct pll_off; + + /* + * PLL index if multiple index are available. Eg. in case of + * DSI we have 2 plls. + */ + uint32_t index; + + bool ssc_en; /* share pll with master */ + bool ssc_center; /* default is down spread */ + u32 ssc_freq; + u32 ssc_ppm; + + struct mdss_pll_resources *slave; + + /* + * target pll revision information + */ + int revision; + + void *priv; + + /* + * dynamic refresh pll codes stored in this structure + */ + struct dfps_info *dfps; + + /* + * for cases where dfps trigger happens before first + * suspend/resume and handoff is not finished. + */ + bool dfps_trigger; +}; + +struct mdss_pll_vco_calc { + s32 div_frac_start1; + s32 div_frac_start2; + s32 div_frac_start3; + s64 dec_start1; + s64 dec_start2; + s64 pll_plllock_cmp1; + s64 pll_plllock_cmp2; + s64 pll_plllock_cmp3; +}; + +static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res) +{ + if (!pll_res->gdsc_base) { + WARN(1, "gdsc_base register is not defined\n"); + return true; + } + return readl_relaxed(pll_res->gdsc_base) & BIT(31) ? false : true; +} + +static inline int mdss_pll_div_prepare(struct clk_hw *hw) +{ + struct clk_hw *parent_hw = clk_hw_get_parent(hw); + /* Restore the divider's value */ + return hw->init->ops->set_rate(hw, clk_hw_get_rate(hw), + clk_hw_get_rate(parent_hw)); +} + +static inline int mdss_set_mux_sel(void *context, unsigned int reg, + unsigned int val) +{ + return 0; +} + +static inline int mdss_get_mux_sel(void *context, unsigned int reg, + unsigned int *val) +{ + *val = 0; + return 0; +} + +int mdss_pll_resource_enable(struct mdss_pll_resources *pll_res, bool enable); +int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res, + bool enable); +int mdss_pll_util_resource_parse(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); +struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res + , char *name); +#endif diff --git a/techpack/display/pll/pll_trace.h b/techpack/display/pll/pll_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..d847920c99c58a6ccdfbbed551335aeeccc33bd3 --- /dev/null +++ b/techpack/display/pll/pll_trace.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#if !defined(_MDSS_PLL_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _MDSS_PLL_TRACE_H_ + +#include <linux/stringify.h> +#include <linux/types.h> +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mdss_pll +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE pll_trace + + +TRACE_EVENT(mdss_pll_lock_start, + TP_PROTO( + u64 vco_cached_rate, + s64 vco_current_rate, + u32 cached_cfg0, + u32 cached_cfg1, + u32 cached_outdiv, + u32 resource_ref_cnt), + TP_ARGS( + vco_cached_rate, + vco_current_rate, + cached_cfg0, + cached_cfg1, + cached_outdiv, + resource_ref_cnt), + TP_STRUCT__entry( + __field(u64, vco_cached_rate) + __field(s64, vco_current_rate) + __field(u32, cached_cfg0) + __field(u32, cached_cfg1) + __field(u32, cached_outdiv) + __field(u32, resource_ref_cnt) + + ), + TP_fast_assign( + __entry->vco_cached_rate = vco_cached_rate; + __entry->vco_current_rate = vco_current_rate; + __entry->cached_cfg0 = cached_cfg0; + __entry->cached_cfg1 = cached_cfg1; + __entry->cached_outdiv = cached_outdiv; + __entry->resource_ref_cnt = resource_ref_cnt; + ), + TP_printk( + "vco_cached_rate=%llu vco_current_rate=%lld cached_cfg0=%d cached_cfg1=%d cached_outdiv=%d resource_ref_cnt=%d", + __entry->vco_cached_rate, + __entry->vco_current_rate, + __entry->cached_cfg0, + __entry->cached_cfg1, + __entry->cached_outdiv, + __entry->resource_ref_cnt) +); + +TRACE_EVENT(pll_tracing_mark_write, + TP_PROTO(int pid, const char *name, bool trace_begin), + TP_ARGS(pid, name, trace_begin), + TP_STRUCT__entry( + __field(int, pid) + __string(trace_name, name) + __field(bool, trace_begin) + ), + TP_fast_assign( + __entry->pid = pid; + __assign_str(trace_name, name); + __entry->trace_begin = trace_begin; + ), + TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E", + __entry->pid, __get_str(trace_name)) +) + +TRACE_EVENT(mdss_pll_trace_counter, + TP_PROTO(int pid, char *name, int value), + TP_ARGS(pid, name, value), + TP_STRUCT__entry( + __field(int, pid) + __string(counter_name, name) + __field(int, value) + ), + TP_fast_assign( + __entry->pid = current->tgid; + __assign_str(counter_name, name); + __entry->value = value; + ), + TP_printk("%d|%s|%d", __entry->pid, + __get_str(counter_name), __entry->value) +) + +#define MDSS_PLL_ATRACE_END(name) trace_pll_tracing_mark_write(current->tgid,\ + name, 0) +#define MDSS_PLL_ATRACE_BEGIN(name) trace_pll_tracing_mark_write(current->tgid,\ + name, 1) +#define MDSS_PLL_ATRACE_FUNC() MDSS_PLL_ATRACE_BEGIN(__func__) +#define MDSS_PLL_ATRACE_INT(name, value) \ + trace_mdss_pll_trace_counter(current->tgid, name, value) + + +#endif /* _MDSS_PLL_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/techpack/display/pll/pll_util.c b/techpack/display/pll/pll_util.c new file mode 100644 index 0000000000000000000000000000000000000000..e8c37726789871019377ac08c022d5739427f288 --- /dev/null +++ b/techpack/display/pll/pll_util.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/of_address.h> +#include <linux/dma-mapping.h> +#include <linux/vmalloc.h> +#include <linux/memblock.h> + +#include "pll_drv.h" + +/** + * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name + *@pll_res: Pointer to the PLL resource + *@name: Regulator name as specified in the pll dtsi + * + * This is a helper function to retrieve the regulator information + * for each pll resource. + */ +struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res + , char *name) +{ + + struct dss_vreg *regulator = NULL; + int i; + + if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) { + pr_err("%s Invalid PLL resource\n", __func__); + goto error; + } + + regulator = pll_res->mp.vreg_config; + + for (i = 0; i < pll_res->mp.num_vreg; i++) { + if (!strcmp(name, regulator->vreg_name)) { + pr_debug("Found regulator match for %s\n", name); + break; + } + regulator++; + } + +error: + return regulator; +} + +int mdss_pll_util_resource_enable(struct mdss_pll_resources *pll_res, + bool enable) +{ + int rc = 0; + struct dss_module_power *mp = &pll_res->mp; + + if (enable) { + rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); + if (rc) { + pr_err("Failed to enable vregs rc=%d\n", rc); + goto vreg_err; + } + + rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); + if (rc) { + pr_err("Failed to set clock rate rc=%d\n", rc); + goto clk_err; + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); + if (rc) { + pr_err("clock enable failed rc:%d\n", rc); + goto clk_err; + } + } else { + msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable); + + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, enable); + } + + return rc; + +clk_err: + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, 0); +vreg_err: + return rc; +} + +static int mdss_pll_util_parse_dt_supply(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int i = 0, rc = 0; + u32 tmp = 0; + struct device_node *of_node = NULL, *supply_root_node = NULL; + struct device_node *supply_node = NULL; + struct dss_module_power *mp = &pll_res->mp; + + of_node = pdev->dev.of_node; + + mp->num_vreg = 0; + supply_root_node = of_get_child_by_name(of_node, + "qcom,platform-supply-entries"); + if (!supply_root_node) { + pr_debug("no supply entry present\n"); + return rc; + } + + for_each_child_of_node(supply_root_node, supply_node) { + mp->num_vreg++; + } + + if (mp->num_vreg == 0) { + pr_debug("no vreg\n"); + return rc; + } + pr_debug("vreg found. count=%d\n", mp->num_vreg); + + mp->vreg_config = devm_kzalloc(&pdev->dev, sizeof(struct dss_vreg) * + mp->num_vreg, GFP_KERNEL); + if (!mp->vreg_config) { + rc = -ENOMEM; + return rc; + } + + for_each_child_of_node(supply_root_node, supply_node) { + + const char *st = NULL; + + rc = of_property_read_string(supply_node, + "qcom,supply-name", &st); + if (rc) { + pr_err(":error reading name. rc=%d\n", rc); + goto error; + } + + strlcpy(mp->vreg_config[i].vreg_name, st, + sizeof(mp->vreg_config[i].vreg_name)); + + rc = of_property_read_u32(supply_node, + "qcom,supply-min-voltage", &tmp); + if (rc) { + pr_err(": error reading min volt. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].min_voltage = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-max-voltage", &tmp); + if (rc) { + pr_err(": error reading max volt. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].max_voltage = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-enable-load", &tmp); + if (rc) { + pr_err(": error reading enable load. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].enable_load = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-disable-load", &tmp); + if (rc) { + pr_err(": error reading disable load. rc=%d\n", rc); + goto error; + } + mp->vreg_config[i].disable_load = tmp; + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-on-sleep", &tmp); + if (rc) + pr_debug("error reading supply pre sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-pre-off-sleep", &tmp); + if (rc) + pr_debug("error reading supply pre sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-on-sleep", &tmp); + if (rc) + pr_debug("error reading supply post sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0); + + rc = of_property_read_u32(supply_node, + "qcom,supply-post-off-sleep", &tmp); + if (rc) + pr_debug("error reading supply post sleep value. rc=%d\n", + rc); + + mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0); + + pr_debug("%s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n", + mp->vreg_config[i].vreg_name, + mp->vreg_config[i].min_voltage, + mp->vreg_config[i].max_voltage, + mp->vreg_config[i].enable_load, + mp->vreg_config[i].disable_load, + mp->vreg_config[i].pre_on_sleep, + mp->vreg_config[i].post_on_sleep, + mp->vreg_config[i].pre_off_sleep, + mp->vreg_config[i].post_off_sleep); + ++i; + + rc = 0; + } + + return rc; + +error: + if (mp->vreg_config) { + devm_kfree(&pdev->dev, mp->vreg_config); + mp->vreg_config = NULL; + mp->num_vreg = 0; + } + + return rc; +} + +static int mdss_pll_util_parse_dt_clock(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + u32 i = 0, rc = 0; + struct dss_module_power *mp = &pll_res->mp; + const char *clock_name; + u32 clock_rate; + + mp->num_clk = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if (mp->num_clk <= 0) { + pr_err("clocks are not defined\n"); + goto clk_err; + } + + mp->clk_config = devm_kzalloc(&pdev->dev, + sizeof(struct dss_clk) * mp->num_clk, GFP_KERNEL); + if (!mp->clk_config) { + rc = -ENOMEM; + mp->num_clk = 0; + goto clk_err; + } + + for (i = 0; i < mp->num_clk; i++) { + of_property_read_string_index(pdev->dev.of_node, "clock-names", + i, &clock_name); + strlcpy(mp->clk_config[i].clk_name, clock_name, + sizeof(mp->clk_config[i].clk_name)); + + of_property_read_u32_index(pdev->dev.of_node, "clock-rate", + i, &clock_rate); + mp->clk_config[i].rate = clock_rate; + + if (!clock_rate) + mp->clk_config[i].type = DSS_CLK_AHB; + else + mp->clk_config[i].type = DSS_CLK_PCLK; + } + +clk_err: + return rc; +} + +static void mdss_pll_free_bootmem(u32 mem_addr, u32 size) +{ + unsigned long pfn_start, pfn_end, pfn_idx; + + pfn_start = mem_addr >> PAGE_SHIFT; + pfn_end = (mem_addr + size) >> PAGE_SHIFT; + for (pfn_idx = pfn_start; pfn_idx < pfn_end; pfn_idx++) + free_reserved_page(pfn_to_page(pfn_idx)); +} + +static int mdss_pll_util_parse_dt_dfps(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0; + struct device_node *pnode; + const u32 *addr; + struct vm_struct *area; + u64 size; + u32 offsets[2]; + unsigned long virt_add; + + pnode = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (IS_ERR_OR_NULL(pnode)) { + rc = PTR_ERR(pnode); + goto pnode_err; + } + + addr = of_get_address(pnode, 0, &size, NULL); + if (!addr) { + pr_err("failed to parse the dfps memory address\n"); + rc = -EINVAL; + goto pnode_err; + } + /* maintain compatibility for 32/64 bit */ + offsets[0] = (u32) of_read_ulong(addr, 2); + offsets[1] = (u32) size; + + area = get_vm_area(offsets[1], VM_IOREMAP); + if (!area) { + rc = -ENOMEM; + goto dfps_mem_err; + } + + virt_add = (unsigned long)area->addr; + rc = ioremap_page_range(virt_add, (virt_add + offsets[1]), + offsets[0], PAGE_KERNEL); + if (rc) { + rc = -ENOMEM; + goto ioremap_err; + } + + pll_res->dfps = kzalloc(sizeof(struct dfps_info), GFP_KERNEL); + if (IS_ERR_OR_NULL(pll_res->dfps)) { + rc = PTR_ERR(pll_res->dfps); + pr_err("couldn't allocate dfps kernel memory\n"); + goto addr_err; + } + + /* memcopy complete dfps structure from kernel virtual memory */ + memcpy_fromio(pll_res->dfps, area->addr, sizeof(struct dfps_info)); + +addr_err: + if (virt_add) + unmap_kernel_range(virt_add, (unsigned long) size); +ioremap_err: + if (area) + vfree(area->addr); +dfps_mem_err: + /* free the dfps memory here */ + memblock_free(offsets[0], offsets[1]); + mdss_pll_free_bootmem(offsets[0], offsets[1]); +pnode_err: + if (pnode) + of_node_put(pnode); + + dma_release_declared_memory(&pdev->dev); + return rc; +} + +int mdss_pll_util_resource_parse(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0; + struct dss_module_power *mp = &pll_res->mp; + + rc = mdss_pll_util_parse_dt_supply(pdev, pll_res); + if (rc) { + pr_err("vreg parsing failed rc=%d\n", rc); + goto end; + } + + rc = mdss_pll_util_parse_dt_clock(pdev, pll_res); + if (rc) { + pr_err("clock name parsing failed rc=%d\n", rc); + goto clk_err; + } + + if (mdss_pll_util_parse_dt_dfps(pdev, pll_res)) + pr_err("dfps not enabled!\n"); + + return rc; + +clk_err: + devm_kfree(&pdev->dev, mp->vreg_config); + mp->num_vreg = 0; +end: + return rc; +} diff --git a/techpack/display/rotator/Makefile b/techpack/display/rotator/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d72ac73a8bbcd86259f9ed97a0d801fa240d6a13 --- /dev/null +++ b/techpack/display/rotator/Makefile @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-only + +ccflags-y += -I$(src) -Idrivers/staging/android + +obj-$(CONFIG_MSM_SDE_ROTATOR) += sde_rotator_dev.o \ + sde_rotator_dev.o \ + sde_rotator_core.o \ + sde_rotator_base.o \ + sde_rotator_formats.o \ + sde_rotator_util.o \ + sde_rotator_io_util.o \ + sde_rotator_smmu.o \ + sde_rotator_r1_wb.o \ + sde_rotator_r1_pipe.o \ + sde_rotator_r1_ctl.o \ + sde_rotator_r1.o \ + sde_rotator_r3.o \ + +obj-$(CONFIG_SYNC_FILE) += \ + sde_rotator_sync.o \ + +obj-$(CONFIG_DEBUG_FS) += \ + sde_rotator_debug.o \ + sde_rotator_r1_debug.o \ + sde_rotator_r3_debug.o \ diff --git a/techpack/display/rotator/sde_rotator_base.c b/techpack/display/rotator/sde_rotator_base.c new file mode 100644 index 0000000000000000000000000000000000000000..3cf850753aca5dbe2e4137f776aa10062f0bb35d --- /dev/null +++ b/techpack/display/rotator/sde_rotator_base.c @@ -0,0 +1,984 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/errno.h> +#include <linux/file.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/debugfs.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#include <linux/regulator/consumer.h> + +#define CREATE_TRACE_POINTS +#include "sde_rotator_base.h" +#include "sde_rotator_util.h" +#include "sde_rotator_trace.h" +#include "sde_rotator_debug.h" +#include "sde_rotator_dev.h" +#include "sde_rotator_vbif.h" + +static inline u64 fudge_factor(u64 val, u32 numer, u32 denom) +{ + u64 result = (val * (u64)numer); + + do_div(result, denom); + return result; +} + +static inline u64 apply_fudge_factor(u64 val, + struct sde_mult_factor *factor) +{ + return fudge_factor(val, factor->numer, factor->denom); +} + +static inline u64 apply_inverse_fudge_factor(u64 val, + struct sde_mult_factor *factor) +{ + return fudge_factor(val, factor->denom, factor->numer); +} + +static inline bool validate_comp_ratio(struct sde_mult_factor *factor) +{ + return factor->numer && factor->denom; +} + +u32 sde_apply_comp_ratio_factor(u32 quota, + struct sde_mdp_format_params *fmt, + struct sde_mult_factor *factor) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + if (!mdata || !test_bit(SDE_QOS_OVERHEAD_FACTOR, + mdata->sde_qos_map)) + return quota; + + /* apply compression ratio, only for compressed formats */ + if (sde_mdp_is_ubwc_format(fmt) && + validate_comp_ratio(factor)) + quota = apply_inverse_fudge_factor(quota, factor); + + return quota; +} + +#define RES_1080p (1088*1920) +#define RES_UHD (3840*2160) +#define RES_WQXGA (2560*1600) +#define XIN_HALT_TIMEOUT_US 0x4000 + +static int sde_mdp_wait_for_xin_halt(u32 xin_id) +{ + void __iomem *vbif_base; + u32 status; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 idle_mask = BIT(xin_id); + int rc; + + vbif_base = mdata->vbif_nrt_io.base; + + rc = readl_poll_timeout(vbif_base + MMSS_VBIF_XIN_HALT_CTRL1, + status, (status & idle_mask), + 1000, XIN_HALT_TIMEOUT_US); + if (rc == -ETIMEDOUT) { + SDEROT_ERR("VBIF client %d not halting. TIMEDOUT.\n", + xin_id); + } else { + SDEROT_DBG("VBIF client %d is halted\n", xin_id); + } + + return rc; +} + +/** + * force_on_xin_clk() - enable/disable the force-on for the pipe clock + * @bit_off: offset of the bit to enable/disable the force-on. + * @reg_off: register offset for the clock control. + * @enable: boolean to indicate if the force-on of the clock needs to be + * enabled or disabled. + * + * This function returns: + * true - if the clock is forced-on by this function + * false - if the clock was already forced on + * It is the caller responsibility to check if this function is forcing + * the clock on; if so, it will need to remove the force of the clock, + * otherwise it should avoid to remove the force-on. + * Clocks must be on when calling this function. + */ +static bool force_on_xin_clk(u32 bit_off, u32 clk_ctl_reg_off, bool enable) +{ + u32 val; + u32 force_on_mask; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + bool clk_forced_on = false; + + force_on_mask = BIT(bit_off); + val = readl_relaxed(mdata->mdp_base + clk_ctl_reg_off); + + clk_forced_on = !(force_on_mask & val); + + if (enable) + val |= force_on_mask; + else + val &= ~force_on_mask; + + writel_relaxed(val, mdata->mdp_base + clk_ctl_reg_off); + + return clk_forced_on; +} + +void vbif_lock(struct platform_device *parent_pdev) +{ + if (!parent_pdev) + return; + + mdp_vbif_lock(parent_pdev, true); +} + +void vbif_unlock(struct platform_device *parent_pdev) +{ + if (!parent_pdev) + return; + + mdp_vbif_lock(parent_pdev, false); +} + +void sde_mdp_halt_vbif_xin(struct sde_mdp_vbif_halt_params *params) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 reg_val; + bool forced_on; + int rc = 0; + + if (!mdata || !params || !params->reg_off_mdp_clk_ctrl) { + SDEROT_ERR("null input parameter\n"); + return; + } + + if (!mdata->parent_pdev && + params->xin_id > MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1) { + SDEROT_ERR("xin_id:%d exceed max limit\n", params->xin_id); + return; + } + + forced_on = force_on_xin_clk(params->bit_off_mdp_clk_ctrl, + params->reg_off_mdp_clk_ctrl, true); + + vbif_lock(mdata->parent_pdev); + + SDEROT_EVTLOG(forced_on, params->xin_id); + + reg_val = SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL0); + SDE_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0, + reg_val | BIT(params->xin_id)); + + /* this is a polling operation */ + rc = sde_mdp_wait_for_xin_halt(params->xin_id); + if (rc == -ETIMEDOUT) + params->xin_timeout = BIT(params->xin_id); + + reg_val = SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL0); + SDE_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0, + reg_val & ~BIT(params->xin_id)); + + vbif_unlock(mdata->parent_pdev); + + if (forced_on) + force_on_xin_clk(params->bit_off_mdp_clk_ctrl, + params->reg_off_mdp_clk_ctrl, false); +} + +u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_mdp_format_params *fmt; + u32 ot_lim; + u32 is_yuv; + u64 res; + + ot_lim = (is_rd) ? mdata->default_ot_rd_limit : + mdata->default_ot_wr_limit; + + /* + * If default ot is not set from dt, + * then do not configure it. + */ + if (ot_lim == 0) + goto exit; + + /* Modify the limits if the target and the use case requires it */ + if (false == test_bit(SDE_QOS_OTLIM, mdata->sde_qos_map)) + goto exit; + + width = min_t(u32, width, SDE_ROT_MAX_IMG_WIDTH); + height = min_t(u32, height, SDE_ROT_MAX_IMG_HEIGHT); + + res = width * height; + res = res * fps; + + fmt = sde_get_format_params(pixfmt); + + if (!fmt) { + SDEROT_WARN("invalid format %8.8x\n", pixfmt); + goto exit; + } + + is_yuv = sde_mdp_is_yuv_format(fmt); + + SDEROT_DBG("w:%d h:%d fps:%d pixfmt:%8.8x yuv:%d res:%llu rd:%d\n", + width, height, fps, pixfmt, is_yuv, res, is_rd); + + /* + * If (total_source_pixels <= 62208000 && YUV) -> RD/WROT=2 //1080p30 + * If (total_source_pixels <= 124416000 && YUV) -> RD/WROT=4 //1080p60 + * If (total_source_pixels <= 2160p && YUV && FPS <= 30) -> RD/WROT = 32 + */ + if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_540)) { + if (is_yuv) { + if (res <= (RES_1080p * 30)) + ot_lim = 2; + else if (res <= (RES_1080p * 60)) + ot_lim = 4; + else if (res <= (RES_WQXGA * 60)) + ot_lim = 4; + else if (res <= (RES_UHD * 30)) + ot_lim = 8; + } else if (fmt->bpp == 4 && res <= (RES_WQXGA * 60)) { + ot_lim = 16; + } + } else if (IS_SDE_MAJOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_600) || is_yuv) { + if (res <= (RES_1080p * 30)) + ot_lim = 2; + else if (res <= (RES_1080p * 60)) + ot_lim = 4; + } +exit: + SDEROT_DBG("ot_lim=%d\n", ot_lim); + return ot_lim; +} + +static u32 get_ot_limit(u32 reg_off, u32 bit_off, + struct sde_mdp_set_ot_params *params) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 ot_lim; + u32 val; + + ot_lim = sde_mdp_get_ot_limit( + params->width, params->height, + params->fmt, params->fps, + params->reg_off_vbif_lim_conf == MMSS_VBIF_RD_LIM_CONF); + + /* + * If default ot is not set from dt, + * then do not configure it. + */ + if (ot_lim == 0) + goto exit; + + val = SDE_VBIF_READ(mdata, reg_off); + val &= (0xFF << bit_off); + val = val >> bit_off; + + SDEROT_EVTLOG(val, ot_lim); + + if (val == ot_lim) + ot_lim = 0; + +exit: + SDEROT_DBG("ot_lim=%d\n", ot_lim); + SDEROT_EVTLOG(params->width, params->height, params->fmt, params->fps, + ot_lim); + return ot_lim; +} + +void sde_mdp_set_ot_limit(struct sde_mdp_set_ot_params *params) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 ot_lim; + u32 reg_off_vbif_lim_conf = ((params->xin_id / mdata->npriority_lvl) + * mdata->npriority_lvl) + + params->reg_off_vbif_lim_conf; + u32 bit_off_vbif_lim_conf = (params->xin_id % mdata->npriority_lvl) * 8; + u32 reg_val; + u32 sts; + bool forced_on; + + vbif_lock(mdata->parent_pdev); + + ot_lim = get_ot_limit( + reg_off_vbif_lim_conf, + bit_off_vbif_lim_conf, + params) & 0xFF; + + if (ot_lim == 0) + goto exit; + + if (params->rotsts_base && params->rotsts_busy_mask) { + sts = readl_relaxed(params->rotsts_base); + if (sts & params->rotsts_busy_mask) { + SDEROT_ERR( + "Rotator still busy, should not modify VBIF\n"); + SDEROT_EVTLOG_TOUT_HANDLER( + "rot", "vbif_dbg_bus", "panic"); + } + } + + trace_rot_perf_set_ot(params->num, params->xin_id, ot_lim); + + forced_on = force_on_xin_clk(params->bit_off_mdp_clk_ctrl, + params->reg_off_mdp_clk_ctrl, true); + + reg_val = SDE_VBIF_READ(mdata, reg_off_vbif_lim_conf); + reg_val &= ~(0xFF << bit_off_vbif_lim_conf); + reg_val |= (ot_lim) << bit_off_vbif_lim_conf; + SDE_VBIF_WRITE(mdata, reg_off_vbif_lim_conf, reg_val); + + reg_val = SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL0); + SDE_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0, + reg_val | BIT(params->xin_id)); + + /* this is a polling operation */ + sde_mdp_wait_for_xin_halt(params->xin_id); + + reg_val = SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL0); + SDE_VBIF_WRITE(mdata, MMSS_VBIF_XIN_HALT_CTRL0, + reg_val & ~BIT(params->xin_id)); + + if (forced_on) + force_on_xin_clk(params->bit_off_mdp_clk_ctrl, + params->reg_off_mdp_clk_ctrl, false); + + SDEROT_EVTLOG(params->num, params->xin_id, ot_lim); +exit: + vbif_unlock(mdata->parent_pdev); + return; +} + +/* + * sde_mdp_set_vbif_memtype - set memtype output for the given xin port + * @mdata: pointer to global rotator data + * @xin_id: xin identifier + * @memtype: memtype output configuration + * return: none + */ +static void sde_mdp_set_vbif_memtype(struct sde_rot_data_type *mdata, + u32 xin_id, u32 memtype) +{ + u32 reg_off; + u32 bit_off; + u32 reg_val; + + /* + * Assume 4 bits per bit field, 8 fields per 32-bit register. + */ + if (xin_id >= 8) + return; + + reg_off = MMSS_VBIF_NRT_VBIF_OUT_AXI_AMEMTYPE_CONF0; + + bit_off = (xin_id & 0x7) * 4; + reg_val = SDE_VBIF_READ(mdata, reg_off); + reg_val &= ~(0x7 << bit_off); + reg_val |= (memtype & 0x7) << bit_off; + SDE_VBIF_WRITE(mdata, reg_off, reg_val); +} + +/* + * sde_mdp_init_vbif - initialize static vbif configuration + * return: 0 if success; error code otherwise + */ +int sde_mdp_init_vbif(void) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int i; + + if (!mdata) + return -EINVAL; + + if (mdata->vbif_memtype_count && mdata->vbif_memtype) { + for (i = 0; i < mdata->vbif_memtype_count; i++) + sde_mdp_set_vbif_memtype(mdata, i, + mdata->vbif_memtype[i]); + + SDEROT_DBG("amemtype=0x%x\n", SDE_VBIF_READ(mdata, + MMSS_VBIF_NRT_VBIF_OUT_AXI_AMEMTYPE_CONF0)); + } + + return 0; +} + +struct reg_bus_client *sde_reg_bus_vote_client_create(char *client_name) +{ + struct reg_bus_client *client; + struct sde_rot_data_type *sde_res = sde_rot_get_mdata(); + static u32 id; + + if (client_name == NULL) { + SDEROT_ERR("client name is null\n"); + return ERR_PTR(-EINVAL); + } + + client = kzalloc(sizeof(struct reg_bus_client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + mutex_lock(&sde_res->reg_bus_lock); + strlcpy(client->name, client_name, MAX_CLIENT_NAME_LEN); + client->usecase_ndx = VOTE_INDEX_DISABLE; + client->id = id; + SDEROT_DBG("bus vote client %s created:%pK id :%d\n", client_name, + client, id); + id++; + list_add(&client->list, &sde_res->reg_bus_clist); + mutex_unlock(&sde_res->reg_bus_lock); + + return client; +} + +void sde_reg_bus_vote_client_destroy(struct reg_bus_client *client) +{ + struct sde_rot_data_type *sde_res = sde_rot_get_mdata(); + + if (!client) { + SDEROT_ERR("reg bus vote: invalid client handle\n"); + } else { + SDEROT_DBG("bus vote client %s destroyed:%pK id:%u\n", + client->name, client, client->id); + mutex_lock(&sde_res->reg_bus_lock); + list_del_init(&client->list); + mutex_unlock(&sde_res->reg_bus_lock); + kfree(client); + } +} + +int sde_update_reg_bus_vote(struct reg_bus_client *bus_client, u32 usecase_ndx) +{ + int ret = 0; + bool changed = false; + u32 max_usecase_ndx = VOTE_INDEX_DISABLE; + struct reg_bus_client *client, *temp_client; + struct sde_rot_data_type *sde_res = sde_rot_get_mdata(); + + if (!sde_res || !sde_res->reg_bus_hdl || !bus_client) + return 0; + + mutex_lock(&sde_res->reg_bus_lock); + bus_client->usecase_ndx = usecase_ndx; + list_for_each_entry_safe(client, temp_client, &sde_res->reg_bus_clist, + list) { + + if (client->usecase_ndx < VOTE_INDEX_MAX && + client->usecase_ndx > max_usecase_ndx) + max_usecase_ndx = client->usecase_ndx; + } + + if (sde_res->reg_bus_usecase_ndx != max_usecase_ndx) { + changed = true; + sde_res->reg_bus_usecase_ndx = max_usecase_ndx; + } + + SDEROT_DBG( + "%pS: changed=%d current idx=%d request client %s id:%u idx:%d\n", + __builtin_return_address(0), changed, max_usecase_ndx, + bus_client->name, bus_client->id, usecase_ndx); + if (changed) + ret = msm_bus_scale_client_update_request(sde_res->reg_bus_hdl, + max_usecase_ndx); + + mutex_unlock(&sde_res->reg_bus_lock); + return ret; +} + +static int sde_mdp_parse_dt_handler(struct platform_device *pdev, + char *prop_name, u32 *offsets, int len) +{ + int rc; + + rc = of_property_read_u32_array(pdev->dev.of_node, prop_name, + offsets, len); + if (rc) { + SDEROT_DBG("Error from prop %s : u32 array read\n", prop_name); + return -EINVAL; + } + + return 0; +} + +static int sde_mdp_parse_dt_prop_len(struct platform_device *pdev, + char *prop_name) +{ + int len = 0; + + of_find_property(pdev->dev.of_node, prop_name, &len); + + if (len < 1) { + SDEROT_INFO("prop %s : doesn't exist in device tree\n", + prop_name); + return 0; + } + + len = len/sizeof(u32); + + return len; +} + +static void sde_mdp_parse_vbif_memtype(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + int rc; + + mdata->vbif_memtype_count = sde_mdp_parse_dt_prop_len(pdev, + "qcom,mdss-rot-vbif-memtype"); + mdata->vbif_memtype = kcalloc(mdata->vbif_memtype_count, + sizeof(u32), GFP_KERNEL); + if (!mdata->vbif_memtype || !mdata->vbif_memtype_count) { + mdata->vbif_memtype_count = 0; + return; + } + + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-rot-vbif-memtype", mdata->vbif_memtype, + mdata->vbif_memtype_count); + if (rc) { + SDEROT_DBG("vbif memtype not found\n"); + kfree(mdata->vbif_memtype); + mdata->vbif_memtype = NULL; + mdata->vbif_memtype_count = 0; + return; + } +} + +static void sde_mdp_parse_vbif_qos(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + int rc; + + mdata->vbif_rt_qos = NULL; + + mdata->npriority_lvl = sde_mdp_parse_dt_prop_len(pdev, + "qcom,mdss-rot-vbif-qos-setting"); + mdata->vbif_nrt_qos = kcalloc(mdata->npriority_lvl, + sizeof(u32), GFP_KERNEL); + if (!mdata->vbif_nrt_qos || !mdata->npriority_lvl) { + mdata->npriority_lvl = 0; + return; + } + + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-rot-vbif-qos-setting", mdata->vbif_nrt_qos, + mdata->npriority_lvl); + if (rc) { + SDEROT_DBG("vbif setting not found\n"); + kfree(mdata->vbif_nrt_qos); + mdata->vbif_nrt_qos = NULL; + mdata->npriority_lvl = 0; + return; + } +} + +static void sde_mdp_parse_vbif_xin_id(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + mdata->vbif_xin_id[XIN_SSPP] = XIN_SSPP; + mdata->vbif_xin_id[XIN_WRITEBACK] = XIN_WRITEBACK; + + sde_mdp_parse_dt_handler(pdev, "qcom,mdss-rot-xin-id", + mdata->vbif_xin_id, MAX_XIN); +} + +static void sde_mdp_parse_cdp_setting(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + int rc; + u32 len, data[SDE_ROT_OP_MAX] = {0}; + + len = sde_mdp_parse_dt_prop_len(pdev, + "qcom,mdss-rot-cdp-setting"); + if (len == SDE_ROT_OP_MAX) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-rot-cdp-setting", data, len); + if (rc) { + SDEROT_ERR("invalid CDP setting\n"); + goto end; + } + + set_bit(SDE_QOS_CDP, mdata->sde_qos_map); + mdata->enable_cdp[SDE_ROT_RD] = data[SDE_ROT_RD]; + mdata->enable_cdp[SDE_ROT_WR] = data[SDE_ROT_WR]; + return; + } +end: + clear_bit(SDE_QOS_CDP, mdata->sde_qos_map); +} + +static void sde_mdp_parse_rot_lut_setting(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + int rc; + u32 len, data[4]; + + len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-qos-lut"); + if (len == 4) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-rot-qos-lut", data, len); + if (!rc) { + mdata->lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0]; + mdata->lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1]; + mdata->lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2]; + mdata->lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3]; + set_bit(SDE_QOS_LUT, mdata->sde_qos_map); + } else { + SDEROT_DBG("qos lut setting not found\n"); + } + } + + len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-danger-lut"); + if (len == SDE_ROT_OP_MAX) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-rot-danger-lut", data, len); + if (!rc) { + mdata->lut_cfg[SDE_ROT_RD].danger_lut + = data[SDE_ROT_RD]; + mdata->lut_cfg[SDE_ROT_WR].danger_lut + = data[SDE_ROT_WR]; + set_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map); + } else { + SDEROT_DBG("danger lut setting not found\n"); + } + } + + len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-rot-safe-lut"); + if (len == SDE_ROT_OP_MAX) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-rot-safe-lut", data, len); + if (!rc) { + mdata->lut_cfg[SDE_ROT_RD].safe_lut = data[SDE_ROT_RD]; + mdata->lut_cfg[SDE_ROT_WR].safe_lut = data[SDE_ROT_WR]; + set_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map); + } else { + SDEROT_DBG("safe lut setting not found\n"); + } + } +} + +static void sde_mdp_parse_inline_rot_lut_setting(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + int rc; + u32 len, data[4]; + + len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-qos-lut"); + if (len == 4) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-inline-rot-qos-lut", data, len); + if (!rc) { + mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0 = data[0]; + mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1 = data[1]; + mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0 = data[2]; + mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1 = data[3]; + set_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map); + } else { + SDEROT_DBG("inline qos lut setting not found\n"); + } + } + + len = sde_mdp_parse_dt_prop_len(pdev, + "qcom,mdss-inline-rot-danger-lut"); + if (len == SDE_ROT_OP_MAX) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-inline-rot-danger-lut", data, len); + if (!rc) { + mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut + = data[SDE_ROT_RD]; + mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut + = data[SDE_ROT_WR]; + set_bit(SDE_INLINE_QOS_DANGER_LUT, + mdata->sde_inline_qos_map); + } else { + SDEROT_DBG("inline danger lut setting not found\n"); + } + } + + len = sde_mdp_parse_dt_prop_len(pdev, "qcom,mdss-inline-rot-safe-lut"); + if (len == SDE_ROT_OP_MAX) { + rc = sde_mdp_parse_dt_handler(pdev, + "qcom,mdss-inline-rot-safe-lut", data, len); + if (!rc) { + mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut + = data[SDE_ROT_RD]; + mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut + = data[SDE_ROT_WR]; + set_bit(SDE_INLINE_QOS_SAFE_LUT, + mdata->sde_inline_qos_map); + } else { + SDEROT_DBG("inline safe lut setting not found\n"); + } + } +} + +static void sde_mdp_parse_rt_rotator(struct device_node *np) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct platform_device *pdev; + struct of_phandle_args phargs; + int rc = 0; + + rc = of_parse_phandle_with_args(np, + "qcom,mdss-rot-parent", "#list-cells", 0, &phargs); + + if (rc) + return; + + if (!phargs.np || !phargs.args_count) { + SDEROT_ERR("invalid args\n"); + return; + } + + pdev = of_find_device_by_node(phargs.np); + if (pdev) { + mdata->parent_pdev = pdev; + } else { + mdata->parent_pdev = NULL; + SDEROT_ERR("Parent mdp node not available\n"); + } + + of_node_put(phargs.np); +} + +static int sde_mdp_parse_dt_misc(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + int rc; + u32 data; + + rc = of_property_read_u32(pdev->dev.of_node, "qcom,mdss-rot-block-size", + &data); + mdata->rot_block_size = (!rc ? data : 128); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mdss-default-ot-rd-limit", &data); + mdata->default_ot_rd_limit = (!rc ? data : 0); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mdss-default-ot-wr-limit", &data); + mdata->default_ot_wr_limit = (!rc ? data : 0); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mdss-highest-bank-bit", &(mdata->highest_bank_bit)); + if (rc) + SDEROT_DBG( + "Could not read optional property: highest bank bit\n"); + + sde_mdp_parse_cdp_setting(pdev, mdata); + + sde_mdp_parse_vbif_qos(pdev, mdata); + + sde_mdp_parse_vbif_xin_id(pdev, mdata); + + sde_mdp_parse_vbif_memtype(pdev, mdata); + + sde_mdp_parse_rot_lut_setting(pdev, mdata); + + sde_mdp_parse_inline_rot_lut_setting(pdev, mdata); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mdss-rot-qos-cpu-mask", &data); + mdata->rot_pm_qos_cpu_mask = (!rc ? data : 0); + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mdss-rot-qos-cpu-dma-latency", &data); + mdata->rot_pm_qos_cpu_dma_latency = (!rc ? data : 0); + + mdata->mdp_base = mdata->sde_io.base + SDE_MDP_OFFSET; + + return 0; +} + +static void sde_mdp_destroy_dt_misc(struct platform_device *pdev, + struct sde_rot_data_type *mdata) +{ + kfree(mdata->vbif_memtype); + mdata->vbif_memtype = NULL; + kfree(mdata->vbif_rt_qos); + mdata->vbif_rt_qos = NULL; + kfree(mdata->vbif_nrt_qos); + mdata->vbif_nrt_qos = NULL; +} + +#define MDP_REG_BUS_VECTOR_ENTRY(ab_val, ib_val) \ + { \ + .src = MSM_BUS_MASTER_AMPSS_M0, \ + .dst = MSM_BUS_SLAVE_DISPLAY_CFG, \ + .ab = (ab_val), \ + .ib = (ib_val), \ + } + +#define BUS_VOTE_19_MHZ 153600000 +#define BUS_VOTE_40_MHZ 320000000 +#define BUS_VOTE_80_MHZ 640000000 + +#ifdef CONFIG_QCOM_BUS_SCALING + +static struct msm_bus_vectors mdp_reg_bus_vectors[] = { + MDP_REG_BUS_VECTOR_ENTRY(0, 0), + MDP_REG_BUS_VECTOR_ENTRY(0, BUS_VOTE_19_MHZ), + MDP_REG_BUS_VECTOR_ENTRY(0, BUS_VOTE_40_MHZ), + MDP_REG_BUS_VECTOR_ENTRY(0, BUS_VOTE_80_MHZ), +}; +static struct msm_bus_paths mdp_reg_bus_usecases[ARRAY_SIZE( + mdp_reg_bus_vectors)]; +static struct msm_bus_scale_pdata mdp_reg_bus_scale_table = { + .usecase = mdp_reg_bus_usecases, + .num_usecases = ARRAY_SIZE(mdp_reg_bus_usecases), + .name = "sde_reg", + .active_only = true, +}; + +static int sde_mdp_bus_scale_register(struct sde_rot_data_type *mdata) +{ + struct msm_bus_scale_pdata *reg_bus_pdata; + int i; + + if (!mdata->reg_bus_hdl) { + reg_bus_pdata = &mdp_reg_bus_scale_table; + for (i = 0; i < reg_bus_pdata->num_usecases; i++) { + mdp_reg_bus_usecases[i].num_paths = 1; + mdp_reg_bus_usecases[i].vectors = + &mdp_reg_bus_vectors[i]; + } + + mdata->reg_bus_hdl = + msm_bus_scale_register_client(reg_bus_pdata); + if (!mdata->reg_bus_hdl) { + /* Continue without reg_bus scaling */ + SDEROT_WARN("reg_bus_client register failed\n"); + } else + SDEROT_DBG("register reg_bus_hdl=%x\n", + mdata->reg_bus_hdl); + } + + return 0; +} +#else +static inline int sde_mdp_bus_scale_register(struct sde_rot_data_type *mdata) +{ + return 0; +} +#endif + +static void sde_mdp_bus_scale_unregister(struct sde_rot_data_type *mdata) +{ + SDEROT_DBG("unregister reg_bus_hdl=%x\n", mdata->reg_bus_hdl); + + if (mdata->reg_bus_hdl) { + msm_bus_scale_unregister_client(mdata->reg_bus_hdl); + mdata->reg_bus_hdl = 0; + } +} + +static struct sde_rot_data_type *sde_rot_res; + +struct sde_rot_data_type *sde_rot_get_mdata(void) +{ + return sde_rot_res; +} + +/* + * sde_rotator_base_init - initialize base rotator data/resource + */ +int sde_rotator_base_init(struct sde_rot_data_type **pmdata, + struct platform_device *pdev, + const void *drvdata) +{ + int rc; + struct sde_rot_data_type *mdata; + + + /* if probe deferral happened, return early*/ + if (sde_rot_res) { + SDEROT_ERR("Rotator data already initialized, skip init\n"); + return 0; + } + + mdata = devm_kzalloc(&pdev->dev, sizeof(*mdata), GFP_KERNEL); + if (mdata == NULL) + return -ENOMEM; + + mdata->pdev = pdev; + sde_rot_res = mdata; + mutex_init(&mdata->reg_bus_lock); + INIT_LIST_HEAD(&mdata->reg_bus_clist); + + rc = sde_rot_ioremap_byname(pdev, &mdata->sde_io, "mdp_phys"); + if (rc) { + SDEROT_ERR("unable to map SDE base\n"); + goto probe_done; + } + SDEROT_DBG("SDE ROT HW Base addr=0x%x len=0x%x\n", + (int) (unsigned long) mdata->sde_io.base, + mdata->sde_io.len); + + rc = sde_rot_ioremap_byname(pdev, &mdata->vbif_nrt_io, "rot_vbif_phys"); + if (rc) { + SDEROT_ERR("unable to map SDE ROT VBIF base\n"); + goto probe_done; + } + SDEROT_DBG("SDE ROT VBIF HW Base addr=%pK len=0x%x\n", + mdata->vbif_nrt_io.base, mdata->vbif_nrt_io.len); + + sde_mdp_parse_rt_rotator(pdev->dev.of_node); + + rc = sde_mdp_parse_dt_misc(pdev, mdata); + if (rc) { + SDEROT_ERR("Error in device tree : misc\n"); + goto probe_done; + } + + rc = sde_mdp_bus_scale_register(mdata); + if (rc) { + SDEROT_ERR("unable to register bus scaling\n"); + goto probe_done; + } + + rc = sde_smmu_init(&pdev->dev); + if (rc) { + SDEROT_ERR("sde smmu init failed %d\n", rc); + goto probe_done; + } + + *pmdata = mdata; + + return 0; +probe_done: + return rc; +} + +/* + * sde_rotator_base_destroy - clean up base rotator data/resource + */ +void sde_rotator_base_destroy(struct sde_rot_data_type *mdata) +{ + struct platform_device *pdev; + + if (!mdata || !mdata->pdev) + return; + + pdev = mdata->pdev; + + sde_rot_res = NULL; + sde_mdp_bus_scale_unregister(mdata); + sde_mdp_destroy_dt_misc(pdev, mdata); + sde_rot_iounmap(&mdata->vbif_nrt_io); + sde_rot_iounmap(&mdata->sde_io); + devm_kfree(&pdev->dev, mdata); +} diff --git a/techpack/display/rotator/sde_rotator_base.h b/techpack/display/rotator/sde_rotator_base.h new file mode 100644 index 0000000000000000000000000000000000000000..bdb319dc28a9f9f16bb61622a0a4f42d6422e3fc --- /dev/null +++ b/techpack/display/rotator/sde_rotator_base.h @@ -0,0 +1,338 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_BASE_H__ +#define __SDE_ROTATOR_BASE_H__ + +#include <linux/types.h> +#include <linux/file.h> +#include <linux/kref.h> +#include <linux/kernel.h> +#include <linux/regulator/consumer.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include "sde_rotator_hwio.h" +#include "sde_rotator_io_util.h" +#include "sde_rotator_smmu.h" +#include "sde_rotator_formats.h" +#include <linux/pm_qos.h> + +/* HW Revisions for different targets */ +#define SDE_GET_MAJOR_REV(rev) ((rev) >> 28) +#define SDE_GET_MAJOR_MINOR(rev) ((rev) >> 16) + +#define IS_SDE_MAJOR_SAME(rev1, rev2) \ + (SDE_GET_MAJOR_REV((rev1)) == SDE_GET_MAJOR_REV((rev2))) + +#define IS_SDE_MAJOR_MINOR_SAME(rev1, rev2) \ + (SDE_GET_MAJOR_MINOR(rev1) == SDE_GET_MAJOR_MINOR(rev2)) + +#define SDE_MDP_REV(major, minor, step) \ + ((((major) & 0x000F) << 28) | \ + (((minor) & 0x0FFF) << 16) | \ + ((step) & 0xFFFF)) + +#define SDE_MDP_HW_REV_107 SDE_MDP_REV(1, 0, 7) /* 8996 v1.0 */ +#define SDE_MDP_HW_REV_300 SDE_MDP_REV(3, 0, 0) /* 8998 v1.0 */ +#define SDE_MDP_HW_REV_301 SDE_MDP_REV(3, 0, 1) /* 8998 v1.1 */ +#define SDE_MDP_HW_REV_400 SDE_MDP_REV(4, 0, 0) /* sdm845 v1.0 */ +#define SDE_MDP_HW_REV_410 SDE_MDP_REV(4, 1, 0) /* sdm670 v1.0 */ +#define SDE_MDP_HW_REV_500 SDE_MDP_REV(5, 0, 0) /* sm8150 v1.0 */ +#define SDE_MDP_HW_REV_520 SDE_MDP_REV(5, 2, 0) /* sdmmagpie v1.0 */ +#define SDE_MDP_HW_REV_530 SDE_MDP_REV(5, 3, 0) /* sm6150 v1.0 */ +#define SDE_MDP_HW_REV_540 SDE_MDP_REV(5, 4, 0) /* sdmtrinket v1.0 */ +#define SDE_MDP_HW_REV_600 SDE_MDP_REV(6, 0, 0) /* msmnile+ v1.0 */ +#define SDE_MDP_HW_REV_630 SDE_MDP_REV(6, 3, 0) /* bengal v1.0 */ + +#define SDE_MDP_VBIF_4_LEVEL_REMAPPER 4 +#define SDE_MDP_VBIF_8_LEVEL_REMAPPER 8 + +/* XIN mapping */ +#define XIN_SSPP 0 +#define XIN_WRITEBACK 1 +#define MAX_XIN 2 + +struct sde_mult_factor { + uint32_t numer; + uint32_t denom; +}; + +struct sde_mdp_set_ot_params { + u32 xin_id; + u32 num; + u32 width; + u32 height; + u32 fps; + u32 fmt; + u32 reg_off_vbif_lim_conf; + u32 reg_off_mdp_clk_ctrl; + u32 bit_off_mdp_clk_ctrl; + char __iomem *rotsts_base; + u32 rotsts_busy_mask; +}; + +/* + * struct sde_mdp_vbif_halt_params: parameters for issue halt request to vbif + * @xin_id: xin port number of vbif + * @reg_off_mdp_clk_ctrl: reg offset for vbif clock control + * @bit_off_mdp_clk_ctrl: bit offset for vbif clock control + * @xin_timeout: bit position indicates timeout on corresponding xin id + */ +struct sde_mdp_vbif_halt_params { + u32 xin_id; + u32 reg_off_mdp_clk_ctrl; + u32 bit_off_mdp_clk_ctrl; + u32 xin_timeout; +}; + +enum sde_bus_vote_type { + VOTE_INDEX_DISABLE, + VOTE_INDEX_19_MHZ, + VOTE_INDEX_40_MHZ, + VOTE_INDEX_80_MHZ, + VOTE_INDEX_MAX, +}; + +#define MAX_CLIENT_NAME_LEN 64 + +enum sde_qos_settings { + SDE_QOS_PER_PIPE_IB, + SDE_QOS_OVERHEAD_FACTOR, + SDE_QOS_CDP, + SDE_QOS_OTLIM, + SDE_QOS_PER_PIPE_LUT, + SDE_QOS_SIMPLIFIED_PREFILL, + SDE_QOS_VBLANK_PANIC_CTRL, + SDE_QOS_LUT, + SDE_QOS_DANGER_LUT, + SDE_QOS_SAFE_LUT, + SDE_QOS_MAX, +}; + +enum sde_inline_qos_settings { + SDE_INLINE_QOS_LUT, + SDE_INLINE_QOS_DANGER_LUT, + SDE_INLINE_QOS_SAFE_LUT, + SDE_INLINE_QOS_MAX, +}; + +/** + * enum sde_rot_type: SDE rotator HW version + * @SDE_ROT_TYPE_V1_0: V1.0 HW version + * @SDE_ROT_TYPE_V1_1: V1.1 HW version + */ +enum sde_rot_type { + SDE_ROT_TYPE_V1_0 = 0x10000000, + SDE_ROT_TYPE_V1_1 = 0x10010000, + SDE_ROT_TYPE_MAX, +}; + +/** + * enum sde_caps_settings: SDE rotator capability definition + * @SDE_CAPS_R1_WB: MDSS V1.x WB block + * @SDE_CAPS_R3_WB: MDSS V3.x WB block + * @SDE_CAPS_R3_1P5_DOWNSCALE: 1.5x downscale rotator support + * @SDE_CAPS_SBUF_1: stream buffer support for inline rotation + * @SDE_CAPS_UBWC_2: universal bandwidth compression version 2 + * @SDE_CAPS_PARTIALWR: partial write override + * @SDE_CAPS_HW_TIMESTAMP: rotator has hw timestamp support + * @SDE_CAPS_UBWC_3: universal bandwidth compression version 3 + * @SDE_CAPS_UBWC_4: universal bandwidth compression version 4 + */ +enum sde_caps_settings { + SDE_CAPS_R1_WB, + SDE_CAPS_R3_WB, + SDE_CAPS_R3_1P5_DOWNSCALE, + SDE_CAPS_SEC_ATTACH_DETACH_SMMU, + SDE_CAPS_SBUF_1, + SDE_CAPS_UBWC_2, + SDE_CAPS_PARTIALWR, + SDE_CAPS_HW_TIMESTAMP, + SDE_CAPS_UBWC_3, + SDE_CAPS_UBWC_4, + SDE_CAPS_MAX, +}; + +enum sde_bus_clients { + SDE_ROT_RT, + SDE_ROT_NRT, + SDE_MAX_BUS_CLIENTS +}; + +enum sde_rot_op { + SDE_ROT_RD, + SDE_ROT_WR, + SDE_ROT_OP_MAX +}; + +enum sde_rot_regdump_access { + SDE_ROT_REGDUMP_READ, + SDE_ROT_REGDUMP_WRITE, + SDE_ROT_REGDUMP_VBIF, + SDE_ROT_REGDUMP_MAX +}; + +struct reg_bus_client { + char name[MAX_CLIENT_NAME_LEN]; + short usecase_ndx; + u32 id; + struct list_head list; +}; + +struct sde_smmu_client { + struct device *dev; + struct iommu_domain *rot_domain; + struct sde_module_power mp; + struct reg_bus_client *reg_bus_clt; + bool domain_attached; + int domain; + u32 sid; +}; + +/* + * struct sde_rot_debug_bus: rotator debugbus header structure + * @wr_addr: write address for debugbus controller + * @block_id: rotator debugbus block id + * @test_id: rotator debugbus test id + */ +struct sde_rot_debug_bus { + u32 wr_addr; + u32 block_id; + u32 test_id; +}; + +struct sde_rot_vbif_debug_bus { + u32 disable_bus_addr; + u32 block_bus_addr; + u32 bit_offset; + u32 block_cnt; + u32 test_pnt_cnt; +}; + +struct sde_rot_regdump { + char *name; + u32 offset; + u32 len; + enum sde_rot_regdump_access access; + u32 value; +}; + +struct sde_rot_lut_cfg { + u32 creq_lut_0; + u32 creq_lut_1; + u32 danger_lut; + u32 safe_lut; +}; + +struct sde_rot_data_type { + u32 mdss_version; + + struct platform_device *pdev; + struct platform_device *parent_pdev; + struct sde_io_data sde_io; + struct sde_io_data vbif_nrt_io; + char __iomem *mdp_base; + + struct sde_smmu_client sde_smmu[SDE_IOMMU_MAX_DOMAIN]; + + /* bitmap to track qos applicable settings */ + DECLARE_BITMAP(sde_qos_map, SDE_QOS_MAX); + DECLARE_BITMAP(sde_inline_qos_map, SDE_QOS_MAX); + + /* bitmap to track capability settings */ + DECLARE_BITMAP(sde_caps_map, SDE_CAPS_MAX); + + u32 default_ot_rd_limit; + u32 default_ot_wr_limit; + u32 highest_bank_bit; + u32 rot_block_size; + + /* register bus (AHB) */ + u32 reg_bus_hdl; + u32 reg_bus_usecase_ndx; + struct list_head reg_bus_clist; + struct mutex reg_bus_lock; + + u32 *vbif_rt_qos; + u32 *vbif_nrt_qos; + u32 npriority_lvl; + + u32 vbif_xin_id[MAX_XIN]; + + struct pm_qos_request pm_qos_rot_cpu_req; + u32 rot_pm_qos_cpu_count; + u32 rot_pm_qos_cpu_mask; + u32 rot_pm_qos_cpu_dma_latency; + + u32 vbif_memtype_count; + u32 *vbif_memtype; + + int iommu_attached; + int iommu_ref_cnt; + + struct sde_rot_vbif_debug_bus *nrt_vbif_dbg_bus; + u32 nrt_vbif_dbg_bus_size; + struct sde_rot_debug_bus *rot_dbg_bus; + u32 rot_dbg_bus_size; + + struct sde_rot_regdump *regdump; + u32 regdump_size; + + void *sde_rot_hw; + int sec_cam_en; + + u32 enable_cdp[SDE_ROT_OP_MAX]; + + struct sde_rot_lut_cfg lut_cfg[SDE_ROT_OP_MAX]; + struct sde_rot_lut_cfg inline_lut_cfg[SDE_ROT_OP_MAX]; + + bool clk_always_on; +}; + +int sde_rotator_base_init(struct sde_rot_data_type **pmdata, + struct platform_device *pdev, + const void *drvdata); + +void sde_rotator_base_destroy(struct sde_rot_data_type *data); + +struct sde_rot_data_type *sde_rot_get_mdata(void); + +struct reg_bus_client *sde_reg_bus_vote_client_create(char *client_name); + +void sde_reg_bus_vote_client_destroy(struct reg_bus_client *client); + +int sde_update_reg_bus_vote(struct reg_bus_client *bus_client, u32 usecase_ndx); + +u32 sde_apply_comp_ratio_factor(u32 quota, + struct sde_mdp_format_params *fmt, + struct sde_mult_factor *factor); + +u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd); + +void sde_mdp_set_ot_limit(struct sde_mdp_set_ot_params *params); + +void vbif_lock(struct platform_device *parent_pdev); +void vbif_unlock(struct platform_device *parent_pdev); + +void sde_mdp_halt_vbif_xin(struct sde_mdp_vbif_halt_params *params); + +int sde_mdp_init_vbif(void); + +#define SDE_VBIF_WRITE(mdata, offset, value) \ + (sde_reg_w(&mdata->vbif_nrt_io, offset, value, 0)) +#define SDE_VBIF_READ(mdata, offset) \ + (sde_reg_r(&mdata->vbif_nrt_io, offset, 0)) +#define SDE_REG_WRITE(mdata, offset, value) \ + sde_reg_w(&mdata->sde_io, offset, value, 0) +#define SDE_REG_READ(mdata, offset) \ + sde_reg_r(&mdata->sde_io, offset, 0) + +#define ATRACE_END(name) trace_rot_mark_write(current->tgid, name, 0) +#define ATRACE_BEGIN(name) trace_rot_mark_write(current->tgid, name, 1) +#define ATRACE_INT(name, value) \ + trace_rot_trace_counter(current->tgid, name, value) + +#endif /* __SDE_ROTATOR_BASE__ */ diff --git a/techpack/display/rotator/sde_rotator_core.c b/techpack/display/rotator/sde_rotator_core.c new file mode 100644 index 0000000000000000000000000000000000000000..cad29dfa58b125a924b81079ad1b2b50e57d57d2 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_core.c @@ -0,0 +1,3586 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/uaccess.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#include <linux/regulator/consumer.h> +#include <linux/dma-direction.h> +#include <soc/qcom/scm.h> +#include <soc/qcom/secure_buffer.h> +#include <asm/cacheflush.h> +#include <uapi/linux/sched/types.h> +#include <soc/qcom/qtee_shmbridge.h> + +#include "sde_rotator_base.h" +#include "sde_rotator_core.h" +#include "sde_rotator_dev.h" +#include "sde_rotator_util.h" +#include "sde_rotator_io_util.h" +#include "sde_rotator_smmu.h" +#include "sde_rotator_r1.h" +#include "sde_rotator_r3.h" +#include "sde_rotator_trace.h" +#include "sde_rotator_debug.h" + + +/* Rotator device id to be used in SCM call */ +#define SDE_ROTATOR_DEVICE 21 + +/* + * SCM call function id to be used for switching between secure and non + * secure context + */ +#define MEM_PROTECT_SD_CTRL_SWITCH 0x18 + +/* waiting for hw time out, 3 vsync for 30fps*/ +#define ROT_HW_ACQUIRE_TIMEOUT_IN_MS 100 + +/* waiting for inline hw start */ +#define ROT_INLINE_START_TIMEOUT_IN_MS (10000 + 500) + +/* default pixel per clock ratio */ +#define ROT_PIXEL_PER_CLK_NUMERATOR 36 +#define ROT_PIXEL_PER_CLK_DENOMINATOR 10 +#define ROT_FUDGE_FACTOR_NUMERATOR 105 +#define ROT_FUDGE_FACTOR_DENOMINATOR 100 +#define ROT_OVERHEAD_NUMERATOR 27 +#define ROT_OVERHEAD_DENOMINATOR 10000 + +/* Minimum Rotator Clock value */ +#define ROT_MIN_ROT_CLK 20000000 + +/* default minimum bandwidth vote */ +#define ROT_ENABLE_BW_VOTE 64000 +/* + * Max rotator hw blocks possible. Used for upper array limits instead of + * alloc and freeing small array + */ +#define ROT_MAX_HW_BLOCKS 2 + +#define SDE_REG_BUS_VECTOR_ENTRY(ab_val, ib_val) \ + { \ + .src = MSM_BUS_MASTER_AMPSS_M0, \ + .dst = MSM_BUS_SLAVE_DISPLAY_CFG, \ + .ab = (ab_val), \ + .ib = (ib_val), \ + } + +#define BUS_VOTE_19_MHZ 153600000 + +/* forward prototype */ +static int sde_rotator_update_perf(struct sde_rot_mgr *mgr); + +#ifdef CONFIG_QCOM_BUS_SCALING +static struct msm_bus_vectors rot_reg_bus_vectors[] = { + SDE_REG_BUS_VECTOR_ENTRY(0, 0), + SDE_REG_BUS_VECTOR_ENTRY(0, BUS_VOTE_19_MHZ), +}; +static struct msm_bus_paths rot_reg_bus_usecases[ARRAY_SIZE( + rot_reg_bus_vectors)]; +static struct msm_bus_scale_pdata rot_reg_bus_scale_table = { + .usecase = rot_reg_bus_usecases, + .num_usecases = ARRAY_SIZE(rot_reg_bus_usecases), + .name = "mdss_rot_reg", + .active_only = 1, +}; + +static int sde_rotator_bus_scale_set_quota(struct sde_rot_bus_data_type *bus, + u64 quota) +{ + int new_uc_idx; + int ret; + + if (!bus) { + SDEROT_ERR("null parameter\n"); + return -EINVAL; + } + + if (!bus->bus_hdl) { + SDEROT_DBG("bus scaling not enabled\n"); + return 0; + } else if (bus->bus_hdl < 0) { + SDEROT_ERR("invalid bus handle %d\n", bus->bus_hdl); + return -EINVAL; + } + + if (bus->curr_quota_val == quota) { + SDEROT_DBG("bw request already requested\n"); + return 0; + } + + if (!bus->bus_scale_pdata || !bus->bus_scale_pdata->num_usecases) { + SDEROT_ERR("invalid bus scale data\n"); + return -EINVAL; + } + + if (!quota) { + new_uc_idx = 0; + } else { + struct msm_bus_vectors *vect = NULL; + struct msm_bus_scale_pdata *bw_table = + bus->bus_scale_pdata; + u64 port_quota = quota; + u32 total_axi_port_cnt; + int i; + + new_uc_idx = (bus->curr_bw_uc_idx % + (bw_table->num_usecases - 1)) + 1; + + total_axi_port_cnt = bw_table->usecase[new_uc_idx].num_paths; + if (total_axi_port_cnt == 0) { + SDEROT_ERR("Number of bw paths is 0\n"); + return -ENODEV; + } + do_div(port_quota, total_axi_port_cnt); + + for (i = 0; i < total_axi_port_cnt; i++) { + vect = &bw_table->usecase[new_uc_idx].vectors[i]; + vect->ab = port_quota; + vect->ib = 0; + } + } + bus->curr_bw_uc_idx = new_uc_idx; + bus->curr_quota_val = quota; + + SDEROT_EVTLOG(new_uc_idx, quota); + SDEROT_DBG("uc_idx=%d quota=%llu\n", new_uc_idx, quota); + ATRACE_BEGIN("msm_bus_scale_req_rot"); + ret = msm_bus_scale_client_update_request(bus->bus_hdl, + new_uc_idx); + ATRACE_END("msm_bus_scale_req_rot"); + + return ret; +} + +static int sde_rotator_enable_reg_bus(struct sde_rot_mgr *mgr, u64 quota) +{ + int ret = 0, changed = 0; + u32 usecase_ndx = 0; + + if (!mgr || !mgr->reg_bus.bus_hdl) + return 0; + + if (quota) + usecase_ndx = 1; + + if (usecase_ndx != mgr->reg_bus.curr_bw_uc_idx) { + mgr->reg_bus.curr_bw_uc_idx = usecase_ndx; + changed++; + } + + SDEROT_DBG("%s, changed=%d register bus %s\n", __func__, changed, + quota ? "Enable":"Disable"); + + if (changed) { + ATRACE_BEGIN("msm_bus_scale_req_rot_reg"); + ret = msm_bus_scale_client_update_request(mgr->reg_bus.bus_hdl, + usecase_ndx); + ATRACE_END("msm_bus_scale_req_rot_reg"); + } + + return ret; +} +#else +static inline int sde_rotator_enable_reg_bus(struct sde_rot_mgr *mgr, u64 quota) +{ + return 0; +} + +static inline int sde_rotator_bus_scale_set_quota( + struct sde_rot_bus_data_type *bus, u64 quota) +{ + return 0; +} +#endif + +/* + * Clock rate of all open sessions working a particular hw block + * are added together to get the required rate for that hw block. + * The max of each hw block becomes the final clock rate voted for + */ +static unsigned long sde_rotator_clk_rate_calc( + struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private) +{ + struct sde_rot_perf *perf; + unsigned long clk_rate[ROT_MAX_HW_BLOCKS] = {0}; + unsigned long total_clk_rate = 0; + int i, wb_idx; + + list_for_each_entry(perf, &private->perf_list, list) { + bool rate_accounted_for = false; + /* + * If there is one session that has two work items across + * different hw blocks rate is accounted for in both blocks. + */ + for (i = 0; i < mgr->queue_count; i++) { + if (perf->work_distribution[i]) { + clk_rate[i] += perf->clk_rate; + rate_accounted_for = true; + } + } + + /* + * Sessions that are open but not distributed on any hw block + * Still need to be accounted for. Rate is added to last known + * wb idx. + */ + wb_idx = perf->last_wb_idx; + if ((!rate_accounted_for) && (wb_idx >= 0) && + (wb_idx < mgr->queue_count)) + clk_rate[wb_idx] += perf->clk_rate; + } + + for (i = 0; i < mgr->queue_count; i++) + total_clk_rate = max(clk_rate[i], total_clk_rate); + + SDEROT_DBG("Total clk rate calc=%lu\n", total_clk_rate); + return total_clk_rate; +} + +static struct clk *sde_rotator_get_clk(struct sde_rot_mgr *mgr, u32 clk_idx) +{ + if (clk_idx >= mgr->num_rot_clk) { + SDEROT_ERR("Invalid clk index:%u", clk_idx); + return NULL; + } + + return mgr->rot_clk[clk_idx].clk; +} + +static void sde_rotator_set_clk_rate(struct sde_rot_mgr *mgr, + unsigned long rate, u32 clk_idx) +{ + unsigned long clk_rate; + struct clk *clk = sde_rotator_get_clk(mgr, clk_idx); + int ret; + + if (clk) { + clk_rate = clk_round_rate(clk, rate); + if (IS_ERR_VALUE(clk_rate)) { + SDEROT_ERR("unable to round rate err=%ld\n", clk_rate); + } else { + ret = clk_set_rate(clk, clk_rate); + if (ret < 0) + SDEROT_ERR("clk_set_rate failed, err:%d\n", + ret); + else + SDEROT_DBG("rotator clk rate=%lu\n", clk_rate); + } + } else { + SDEROT_ERR("rotator clk not setup properly\n"); + } +} + +/* + * Update clock according to all open files on rotator block. + */ +static int sde_rotator_update_clk(struct sde_rot_mgr *mgr) +{ + struct sde_rot_file_private *priv; + unsigned long clk_rate, total_clk_rate; + + total_clk_rate = 0; + list_for_each_entry(priv, &mgr->file_list, list) { + clk_rate = sde_rotator_clk_rate_calc(mgr, priv); + total_clk_rate += clk_rate; + } + + SDEROT_DBG("core_clk %lu\n", total_clk_rate); + ATRACE_INT("core_clk", total_clk_rate); + sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_MDSS_ROT); + + return 0; +} + +static int sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on) +{ + int ret = 0; + + if (mgr->regulator_enable == on) { + SDEROT_DBG("Regulators already in selected mode on=%d\n", on); + return 0; + } + + SDEROT_EVTLOG(on); + SDEROT_DBG("%s: rotator regulators\n", on ? "Enable" : "Disable"); + + if (on) { + mgr->minimum_bw_vote = mgr->enable_bw_vote; + sde_rotator_update_perf(mgr); + } + + if (mgr->ops_hw_pre_pmevent) + mgr->ops_hw_pre_pmevent(mgr, on); + + if (!sde_rot_mgr_pd_enabled(mgr)) + ret = sde_rot_enable_vreg(mgr->module_power.vreg_config, + mgr->module_power.num_vreg, on); + if (ret) { + pr_err("rotator regulator failed to %s ret:%d client:%d\n", + on ? "enable" : "disable", ret, + sde_rot_mgr_pd_enabled(mgr)); + return ret; + } + + if (mgr->ops_hw_post_pmevent) + mgr->ops_hw_post_pmevent(mgr, on); + + if (!on) { + mgr->minimum_bw_vote = 0; + sde_rotator_update_perf(mgr); + } + + mgr->regulator_enable = on; + return 0; +} + +static int sde_rotator_enable_clk(struct sde_rot_mgr *mgr, int clk_idx) +{ + struct clk *clk; + int ret = 0; + + clk = sde_rotator_get_clk(mgr, clk_idx); + if (clk) { + ret = clk_prepare_enable(clk); + if (ret) + SDEROT_ERR("enable failed clk_idx %d\n", clk_idx); + } + + return ret; +} + +static void sde_rotator_disable_clk(struct sde_rot_mgr *mgr, int clk_idx) +{ + struct clk *clk; + + clk = sde_rotator_get_clk(mgr, clk_idx); + if (clk) + clk_disable_unprepare(clk); +} + +int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable) +{ + int ret = 0; + int changed = 0; + + if (enable) { + if (mgr->rot_enable_clk_cnt == 0) + changed++; + mgr->rot_enable_clk_cnt++; + } else { + if (mgr->rot_enable_clk_cnt) { + mgr->rot_enable_clk_cnt--; + if (mgr->rot_enable_clk_cnt == 0) + changed++; + } else { + SDEROT_ERR("Can not be turned off\n"); + } + } + + if (changed) { + SDEROT_EVTLOG(enable); + SDEROT_DBG("Rotator clk %s\n", enable ? "enable" : "disable"); + + if (enable) { + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_MNOC_AHB); + if (ret) + goto error_mnoc_ahb; + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_GCC_AHB); + if (ret) + goto error_gcc_ahb; + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_GCC_AXI); + if (ret) + goto error_gcc_axi; + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_MDSS_AHB); + if (ret) + goto error_mdss_ahb; + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_MDSS_AXI); + if (ret) + goto error_mdss_axi; + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_MDSS_ROT); + if (ret) + goto error_mdss_rot; + ret = sde_rotator_enable_clk(mgr, + SDE_ROTATOR_CLK_MDSS_ROT_SUB); + if (ret) + goto error_rot_sub; + + /* Active+Sleep */ + msm_bus_scale_client_update_context( + mgr->data_bus.bus_hdl, false, + mgr->data_bus.curr_bw_uc_idx); + trace_rot_bw_ao_as_context(0); + } else { + sde_rotator_disable_clk(mgr, + SDE_ROTATOR_CLK_MDSS_ROT_SUB); + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT); + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI); + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB); + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_GCC_AXI); + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_GCC_AHB); + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MNOC_AHB); + + /* Active Only */ + msm_bus_scale_client_update_context( + mgr->data_bus.bus_hdl, true, + mgr->data_bus.curr_bw_uc_idx); + trace_rot_bw_ao_as_context(1); + } + } + + return ret; +error_rot_sub: + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT); +error_mdss_rot: + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI); +error_mdss_axi: + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB); +error_mdss_ahb: + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_GCC_AXI); +error_gcc_axi: + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_GCC_AHB); +error_gcc_ahb: + sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MNOC_AHB); +error_mnoc_ahb: + return ret; +} + +/* sde_rotator_resource_ctrl - control state of power resource + * @mgr: Pointer to rotator manager + * @enable: 1 to enable; 0 to disable + * + * This function returns 1 if resource is already in the requested state, + * return 0 if the state is changed successfully, or negative error code + * if not successful. + */ +static int sde_rotator_resource_ctrl(struct sde_rot_mgr *mgr, int enable) +{ + int ret; + + if (enable) { + mgr->res_ref_cnt++; + ret = pm_runtime_get_sync(&mgr->pdev->dev); + } else { + mgr->res_ref_cnt--; + ret = pm_runtime_put_sync(&mgr->pdev->dev); + } + + SDEROT_DBG("%s: res_cnt=%d pm=%d enable=%d\n", + __func__, mgr->res_ref_cnt, ret, enable); + ATRACE_INT("res_cnt", mgr->res_ref_cnt); + + return ret; +} + +/* caller is expected to hold perf->work_dis_lock lock */ +static bool sde_rotator_is_work_pending(struct sde_rot_mgr *mgr, + struct sde_rot_perf *perf) +{ + int i; + + for (i = 0; i < mgr->queue_count; i++) { + if (perf->work_distribution[i]) { + SDEROT_DBG("Work is still scheduled to complete\n"); + return true; + } + } + return false; +} + +static void sde_rotator_clear_fence(struct sde_rot_entry *entry) +{ + if (entry->input_fence) { + SDEROT_EVTLOG(entry->input_fence, 1111); + SDEROT_DBG("sys_fence_put i:%pK\n", entry->input_fence); + sde_rotator_put_sync_fence(entry->input_fence); + entry->input_fence = NULL; + } + + /* fence failed to copy to user space */ + if (entry->output_fence) { + if (entry->fenceq && entry->fenceq->timeline) + sde_rotator_resync_timeline(entry->fenceq->timeline); + + SDEROT_EVTLOG(entry->output_fence, 2222); + SDEROT_DBG("sys_fence_put o:%pK\n", entry->output_fence); + sde_rotator_put_sync_fence(entry->output_fence); + entry->output_fence = NULL; + } +} + +static int sde_rotator_signal_output(struct sde_rot_entry *entry) +{ + struct sde_rot_timeline *rot_timeline; + + if (!entry->fenceq) + return -EINVAL; + + rot_timeline = entry->fenceq->timeline; + + if (entry->output_signaled) { + SDEROT_DBG("output already signaled\n"); + return 0; + } + + SDEROT_DBG("signal fence s:%d.%d\n", entry->item.session_id, + entry->item.sequence_id); + + sde_rotator_inc_timeline(rot_timeline, 1); + + entry->output_signaled = true; + + return 0; +} + +static int sde_rotator_import_buffer(struct sde_layer_buffer *buffer, + struct sde_mdp_data *data, u32 flags, struct device *dev, bool input) +{ + int i, ret = 0; + struct sde_fb_data planes[SDE_ROT_MAX_PLANES]; + int dir = DMA_TO_DEVICE; + + if (!input) + dir = DMA_FROM_DEVICE; + + if (buffer->plane_count > SDE_ROT_MAX_PLANES) { + SDEROT_ERR("buffer plane_count exceeds MAX_PLANE limit:%d\n", + buffer->plane_count); + return -EINVAL; + } + + data->sbuf = buffer->sbuf; + data->scid = buffer->scid; + data->writeback = buffer->writeback; + + memset(planes, 0, sizeof(planes)); + + for (i = 0; i < buffer->plane_count; i++) { + planes[i].memory_id = buffer->planes[i].fd; + planes[i].offset = buffer->planes[i].offset; + planes[i].buffer = buffer->planes[i].buffer; + planes[i].addr = buffer->planes[i].addr; + planes[i].len = buffer->planes[i].len; + } + + ret = sde_mdp_data_get_and_validate_size(data, planes, + buffer->plane_count, flags, dev, true, dir, buffer); + + return ret; +} + +static int sde_rotator_secure_session_ctrl(bool enable) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + uint32_t *sid_info = NULL; + struct scm_desc desc = {0}; + unsigned int resp = 0; + int ret = 0; + struct qtee_shm shm; + bool qtee_en = qtee_shmbridge_is_enabled(); + + if (test_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU, mdata->sde_caps_map)) { + + desc.arginfo = SCM_ARGS(4, SCM_VAL, SCM_RW, SCM_VAL, SCM_VAL); + desc.args[0] = SDE_ROTATOR_DEVICE; + + if (qtee_en) { + ret = qtee_shmbridge_allocate_shm(sizeof(uint32_t), + &shm); + if (ret) + return -ENOMEM; + + sid_info = (uint32_t *) shm.vaddr; + desc.args[1] = shm.paddr; + desc.args[2] = sizeof(uint32_t); + } else { + sid_info = kzalloc(sizeof(uint32_t), GFP_KERNEL); + if (!sid_info) + return -ENOMEM; + + desc.args[1] = SCM_BUFFER_PHYS(sid_info); + desc.args[2] = sizeof(uint32_t); + } + + sid_info[0] = mdata->sde_smmu[SDE_IOMMU_DOMAIN_ROT_SECURE].sid; + + if (!mdata->sec_cam_en && enable) { + /* + * Enable secure camera operation + * Send SCM call to hypervisor to switch the + * secure_vmid to secure context + */ + desc.args[3] = VMID_CP_CAMERA_PREVIEW; + + mdata->sec_cam_en = 1; + sde_smmu_secure_ctrl(0); + + dmac_flush_range(sid_info, sid_info + 1); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + MEM_PROTECT_SD_CTRL_SWITCH), &desc); + resp = desc.ret[0]; + if (ret) { + SDEROT_ERR("scm_call(1) ret=%d, resp=%x\n", + ret, resp); + /* failure, attach smmu */ + mdata->sec_cam_en = 0; + sde_smmu_secure_ctrl(1); + ret = -EINVAL; + goto end; + } + + SDEROT_DBG( + "scm(1) sid0x%x dev0x%llx vmid0x%llx qtee_en%d ret%d resp%x\n", + sid_info[0], desc.args[0], desc.args[3], + qtee_en, ret, resp); + SDEROT_EVTLOG(1, sid_info, sid_info[0], desc.args[0], + desc.args[3], qtee_en, ret, resp); + } else if (mdata->sec_cam_en && !enable) { + /* + * Disable secure camera operation + * Send SCM call to hypervisor to switch the + * secure_vmid to non-secure context + */ + desc.args[3] = VMID_CP_PIXEL; + mdata->sec_cam_en = 0; + + dmac_flush_range(sid_info, sid_info + 1); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + MEM_PROTECT_SD_CTRL_SWITCH), &desc); + resp = desc.ret[0]; + + SDEROT_DBG( + "scm(0) sid0x%x dev0x%llx vmid0x%llx qtee_en%d ret%d resp%d\n", + sid_info[0], desc.args[0], desc.args[3], + qtee_en, ret, resp); + + /* force smmu to reattach */ + sde_smmu_secure_ctrl(1); + + SDEROT_EVTLOG(0, sid_info, sid_info[0], desc.args[0], + desc.args[3], qtee_en, ret, resp); + } + } else { + return 0; + } + +end: + if (qtee_en) + qtee_shmbridge_free_shm(&shm); + else + kfree(sid_info); + + if (ret) + return ret; + + return resp; +} + + +static int sde_rotator_map_and_check_data(struct sde_rot_entry *entry) +{ + int ret; + struct sde_layer_buffer *input; + struct sde_layer_buffer *output; + struct sde_mdp_format_params *in_fmt, *out_fmt; + struct sde_mdp_plane_sizes ps; + bool rotation; + bool secure; + + input = &entry->item.input; + output = &entry->item.output; + + rotation = (entry->item.flags & SDE_ROTATION_90) ? true : false; + + ret = sde_smmu_ctrl(1); + if (ret < 0) + return ret; + + secure = (entry->item.flags & SDE_ROTATION_SECURE_CAMERA) ? + true : false; + ret = sde_rotator_secure_session_ctrl(secure); + if (ret) { + SDEROT_ERR("failed secure session enabling/disabling %d\n", + ret); + goto end; + } + + in_fmt = sde_get_format_params(input->format); + if (!in_fmt) { + SDEROT_ERR("invalid input format:%d\n", input->format); + ret = -EINVAL; + goto end; + } + + out_fmt = sde_get_format_params(output->format); + if (!out_fmt) { + SDEROT_ERR("invalid output format:%d\n", output->format); + ret = -EINVAL; + goto end; + } + + /* if error during map, the caller will release the data */ + ret = sde_mdp_data_map(&entry->src_buf, true, DMA_TO_DEVICE); + if (ret) { + SDEROT_ERR("source buffer mapping failed ret:%d\n", ret); + goto end; + } + + ret = sde_mdp_data_map(&entry->dst_buf, true, DMA_FROM_DEVICE); + if (ret) { + SDEROT_ERR("destination buffer mapping failed ret:%d\n", ret); + goto end; + } + + ret = sde_mdp_get_plane_sizes( + in_fmt, input->width, input->height, &ps, 0, rotation); + if (ret) { + SDEROT_ERR("fail to get input plane size ret=%d\n", ret); + goto end; + } + + ret = sde_mdp_data_check(&entry->src_buf, &ps, in_fmt); + if (ret) { + SDEROT_ERR("fail to check input data ret=%d\n", ret); + goto end; + } + + ret = sde_mdp_get_plane_sizes(out_fmt, output->width, output->height, + &ps, 0, rotation); + if (ret) { + SDEROT_ERR("fail to get output plane size ret=%d\n", ret); + goto end; + } + + ret = sde_mdp_data_check(&entry->dst_buf, &ps, out_fmt); + if (ret) { + SDEROT_ERR("fail to check output data ret=%d\n", ret); + goto end; + } + +end: + sde_smmu_ctrl(0); + + return ret; +} + +static struct sde_rot_perf *__sde_rotator_find_session( + struct sde_rot_file_private *private, + u32 session_id) +{ + struct sde_rot_perf *perf, *perf_next; + bool found = false; + + list_for_each_entry_safe(perf, perf_next, &private->perf_list, list) { + if (perf->config.session_id == session_id) { + found = true; + break; + } + } + if (!found) + perf = NULL; + return perf; +} + +static struct sde_rot_perf *sde_rotator_find_session( + struct sde_rot_file_private *private, + u32 session_id) +{ + struct sde_rot_perf *perf; + + perf = __sde_rotator_find_session(private, session_id); + return perf; +} + +static void sde_rotator_release_data(struct sde_rot_entry *entry) +{ + SDEROT_EVTLOG(entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr); + sde_mdp_data_free(&entry->src_buf, true, DMA_TO_DEVICE); + sde_mdp_data_free(&entry->dst_buf, true, DMA_FROM_DEVICE); +} + +static int sde_rotator_import_data(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry) +{ + int ret; + struct sde_layer_buffer *input; + struct sde_layer_buffer *output; + u32 flag = 0; + + input = &entry->item.input; + output = &entry->item.output; + + if (entry->item.flags & SDE_ROTATION_SECURE) + flag = SDE_SECURE_OVERLAY_SESSION; + + if (entry->item.flags & SDE_ROTATION_EXT_DMA_BUF) + flag |= SDE_ROT_EXT_DMA_BUF; + + if (entry->item.flags & SDE_ROTATION_EXT_IOVA) + flag |= SDE_ROT_EXT_IOVA; + + if (entry->item.flags & SDE_ROTATION_SECURE_CAMERA) + flag |= SDE_SECURE_CAMERA_SESSION; + + ret = sde_rotator_import_buffer(input, &entry->src_buf, flag, + &mgr->pdev->dev, true); + if (ret) { + SDEROT_ERR("fail to import input buffer ret=%d\n", ret); + return ret; + } + + /* + * driver assumes output buffer is ready to be written + * immediately + */ + ret = sde_rotator_import_buffer(output, &entry->dst_buf, flag, + &mgr->pdev->dev, false); + if (ret) { + SDEROT_ERR("fail to import output buffer ret=%d\n", ret); + return ret; + } + + return ret; +} + +/* + * sde_rotator_require_reconfiguration - check if reconfiguration is required + * @mgr: Pointer to rotator manager + * @hw: Pointer to rotator hw resource + * @entry: Pointer to next rotation entry + * + * Parameters are validated by caller. + */ +static int sde_rotator_require_reconfiguration(struct sde_rot_mgr *mgr, + struct sde_rot_hw_resource *hw, struct sde_rot_entry *entry) +{ + /* OT setting change may impact queued entries */ + if (entry->perf && (entry->perf->rdot_limit != mgr->rdot_limit || + entry->perf->wrot_limit != mgr->wrot_limit)) + return true; + + /* sbuf mode is exclusive and may impact queued entries */ + if (!mgr->sbuf_ctx && entry->perf && entry->perf->config.output.sbuf) + return true; + + return false; +} + +/* + * sde_rotator_is_hw_idle - check if hw block is not processing request + * @mgr: Pointer to rotator manager + * @hw: Pointer to rotator hw resource + * + * Parameters are validated by caller. + */ +static int sde_rotator_is_hw_idle(struct sde_rot_mgr *mgr, + struct sde_rot_hw_resource *hw) +{ + int i; + + /* + * Wait until all queues are idle in order to update global + * setting such as VBIF QoS. This check can be relaxed if global + * settings can be updated individually by entries already + * queued in hw queue, i.e. REGDMA can update VBIF directly. + */ + for (i = 0; i < mgr->queue_count; i++) { + struct sde_rot_hw_resource *hw_res = mgr->commitq[i].hw; + + if (hw_res && atomic_read(&hw_res->num_active)) + return false; + } + + return true; +} + +/* + * sde_rotator_is_hw_available - check if hw is available for the given entry + * @mgr: Pointer to rotator manager + * @hw: Pointer to rotator hw resource + * @entry: Pointer to rotation entry + * + * Parameters are validated by caller. + */ +static int sde_rotator_is_hw_available(struct sde_rot_mgr *mgr, + struct sde_rot_hw_resource *hw, struct sde_rot_entry *entry) +{ + /* + * Wait until hw is idle if reconfiguration is required; otherwise, + * wait until free queue entry is available + */ + if (sde_rotator_require_reconfiguration(mgr, hw, entry)) { + SDEROT_DBG( + "wait4idle active=%d pending=%d rdot:%u/%u wrot:%u/%u s:%d.%d\n", + atomic_read(&hw->num_active), hw->pending_count, + mgr->rdot_limit, entry->perf->rdot_limit, + mgr->wrot_limit, entry->perf->wrot_limit, + entry->item.session_id, + entry->item.sequence_id); + return sde_rotator_is_hw_idle(mgr, hw); + } else if (mgr->sbuf_ctx && mgr->sbuf_ctx != entry->private) { + SDEROT_DBG("wait until sbuf mode is off\n"); + return false; + } else { + return (atomic_read(&hw->num_active) < hw->max_active); + } +} + +/* + * sde_rotator_req_wait_for_idle - wait for hw for a request to be idle + * @mgr: Pointer to rotator manager + * @req: Pointer to rotation request + */ +static void sde_rotator_req_wait_for_idle(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req) +{ + struct sde_rot_queue *queue; + struct sde_rot_hw_resource *hw; + int i, ret; + + if (!mgr || !req) { + SDEROT_ERR("invalid params\n"); + return; + } + + for (i = 0; i < req->count; i++) { + queue = req->entries[i].commitq; + if (!queue || !queue->hw) + continue; + hw = queue->hw; + while (atomic_read(&hw->num_active) > 1) { + sde_rot_mgr_unlock(mgr); + ret = wait_event_timeout(hw->wait_queue, + atomic_read(&hw->num_active) <= 1, + msecs_to_jiffies(mgr->hwacquire_timeout)); + sde_rot_mgr_lock(mgr); + if (!ret) { + SDEROT_ERR( + "timeout waiting for hw idle, a:%d\n", + atomic_read(&hw->num_active)); + return; + } + } + } +} + +/* + * sde_rotator_get_hw_resource - block waiting for hw availability or timeout + * @queue: Pointer to rotator queue + * @entry: Pointer to rotation entry + */ +static struct sde_rot_hw_resource *sde_rotator_get_hw_resource( + struct sde_rot_queue *queue, struct sde_rot_entry *entry) +{ + struct sde_rot_hw_resource *hw; + struct sde_rot_mgr *mgr; + int ret; + + if (!queue || !entry || !queue->hw) { + SDEROT_ERR("null parameters\n"); + return NULL; + } + + hw = queue->hw; + mgr = entry->private->mgr; + + WARN_ON(atomic_read(&hw->num_active) > hw->max_active); + while (!sde_rotator_is_hw_available(mgr, hw, entry)) { + sde_rot_mgr_unlock(mgr); + ret = wait_event_timeout(hw->wait_queue, + sde_rotator_is_hw_available(mgr, hw, entry), + msecs_to_jiffies(mgr->hwacquire_timeout)); + sde_rot_mgr_lock(mgr); + if (!ret) { + SDEROT_ERR( + "timeout waiting for hw resource, a:%d p:%d\n", + atomic_read(&hw->num_active), + hw->pending_count); + SDEROT_EVTLOG(entry->item.session_id, + entry->item.sequence_id, + atomic_read(&hw->num_active), + hw->pending_count, + SDE_ROT_EVTLOG_ERROR); + return NULL; + } + } + atomic_inc(&hw->num_active); + SDEROT_EVTLOG(atomic_read(&hw->num_active), hw->pending_count, + mgr->rdot_limit, entry->perf->rdot_limit, + mgr->wrot_limit, entry->perf->wrot_limit, + entry->item.session_id, entry->item.sequence_id); + SDEROT_DBG("active=%d pending=%d rdot=%u/%u wrot=%u/%u s:%d.%d\n", + atomic_read(&hw->num_active), hw->pending_count, + mgr->rdot_limit, entry->perf->rdot_limit, + mgr->wrot_limit, entry->perf->wrot_limit, + entry->item.session_id, entry->item.sequence_id); + mgr->rdot_limit = entry->perf->rdot_limit; + mgr->wrot_limit = entry->perf->wrot_limit; + + if (!mgr->sbuf_ctx && entry->perf->config.output.sbuf) { + SDEROT_DBG("acquire sbuf s:%d.%d\n", entry->item.session_id, + entry->item.sequence_id); + SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id); + mgr->sbuf_ctx = entry->private; + } + + return hw; +} + +/* + * sde_rotator_put_hw_resource - return hw resource and wake up waiting clients + * @queue: Pointer to rotator queue + * @entry: Pointer to rotation entry + * @hw: Pointer to hw resource to be returned + */ +static void sde_rotator_put_hw_resource(struct sde_rot_queue *queue, + struct sde_rot_entry *entry, struct sde_rot_hw_resource *hw) +{ + struct sde_rot_mgr *mgr; + int i; + + if (!queue || !entry || !hw) { + SDEROT_ERR("null parameters\n"); + return; + } + + mgr = entry->private->mgr; + + WARN_ON(atomic_read(&hw->num_active) < 1); + if (!atomic_add_unless(&hw->num_active, -1, 0)) + SDEROT_ERR("underflow active=%d pending=%d s:%d.%d\n", + atomic_read(&hw->num_active), hw->pending_count, + entry->item.session_id, entry->item.sequence_id); + /* + * Wake up all queues in case any entry is waiting for hw idle, + * in order to update global settings, such as VBIF QoS. + * This can be relaxed to the given hw resource if global + * settings can be updated individually by entries already + * queued in hw queue. + */ + for (i = 0; i < mgr->queue_count; i++) { + struct sde_rot_hw_resource *hw_res = mgr->commitq[i].hw; + + if (hw_res) + wake_up(&hw_res->wait_queue); + } + SDEROT_EVTLOG(atomic_read(&hw->num_active), hw->pending_count, + entry->item.session_id, entry->item.sequence_id); + SDEROT_DBG("active=%d pending=%d s:%d.%d\n", + atomic_read(&hw->num_active), hw->pending_count, + entry->item.session_id, entry->item.sequence_id); +} + +/* + * caller will need to call sde_rotator_deinit_queue when + * the function returns error + */ +static int sde_rotator_init_queue(struct sde_rot_mgr *mgr) +{ + int i, size, ret = 0; + char name[32]; + struct sched_param param = { .sched_priority = 5 }; + + size = sizeof(struct sde_rot_queue) * mgr->queue_count; + mgr->commitq = devm_kzalloc(mgr->device, size, GFP_KERNEL); + if (!mgr->commitq) + return -ENOMEM; + + for (i = 0; i < mgr->queue_count; i++) { + snprintf(name, sizeof(name), "rot_commitq_%d_%d", + mgr->device->id, i); + SDEROT_DBG("work queue name=%s\n", name); + kthread_init_worker(&mgr->commitq[i].rot_kw); + mgr->commitq[i].rot_thread = kthread_run(kthread_worker_fn, + &mgr->commitq[i].rot_kw, name); + if (IS_ERR(mgr->commitq[i].rot_thread)) { + ret = -EPERM; + mgr->commitq[i].rot_thread = NULL; + break; + } + + ret = sched_setscheduler(mgr->commitq[i].rot_thread, + SCHED_FIFO, ¶m); + if (ret) { + SDEROT_ERR( + "failed to set kthread priority for commitq %d\n", + ret); + break; + } + + /* timeline not used */ + mgr->commitq[i].timeline = NULL; + } + + size = sizeof(struct sde_rot_queue) * mgr->queue_count; + mgr->doneq = devm_kzalloc(mgr->device, size, GFP_KERNEL); + if (!mgr->doneq) + return -ENOMEM; + + for (i = 0; i < mgr->queue_count; i++) { + snprintf(name, sizeof(name), "rot_doneq_%d_%d", + mgr->device->id, i); + SDEROT_DBG("work queue name=%s\n", name); + kthread_init_worker(&mgr->doneq[i].rot_kw); + mgr->doneq[i].rot_thread = kthread_run(kthread_worker_fn, + &mgr->doneq[i].rot_kw, name); + if (IS_ERR(mgr->doneq[i].rot_thread)) { + ret = -EPERM; + mgr->doneq[i].rot_thread = NULL; + break; + } + + ret = sched_setscheduler(mgr->doneq[i].rot_thread, + SCHED_FIFO, ¶m); + if (ret) { + SDEROT_ERR( + "failed to set kthread priority for doneq %d\n", + ret); + break; + } + + /* timeline not used */ + mgr->doneq[i].timeline = NULL; + } + return ret; +} + +static void sde_rotator_deinit_queue(struct sde_rot_mgr *mgr) +{ + int i; + + if (mgr->commitq) { + for (i = 0; i < mgr->queue_count; i++) { + if (mgr->commitq[i].rot_thread) { + kthread_flush_worker(&mgr->commitq[i].rot_kw); + kthread_stop(mgr->commitq[i].rot_thread); + } + } + devm_kfree(mgr->device, mgr->commitq); + mgr->commitq = NULL; + } + if (mgr->doneq) { + for (i = 0; i < mgr->queue_count; i++) { + if (mgr->doneq[i].rot_thread) { + kthread_flush_worker(&mgr->doneq[i].rot_kw); + kthread_stop(mgr->doneq[i].rot_thread); + } + } + devm_kfree(mgr->device, mgr->doneq); + mgr->doneq = NULL; + } + mgr->queue_count = 0; +} + +/* + * sde_rotator_assign_queue() - Function assign rotation work onto hw + * @mgr: Rotator manager. + * @entry: Contains details on rotator work item being requested + * @private: Private struct used for access rot session performance struct + * + * This Function allocates hw required to complete rotation work item + * requested. + * + * Caller is responsible for calling cleanup function if error is returned + */ +static int sde_rotator_assign_queue(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry, + struct sde_rot_file_private *private) +{ + struct sde_rot_perf *perf; + struct sde_rot_queue *queue; + struct sde_rot_hw_resource *hw; + struct sde_rotation_item *item = &entry->item; + u32 wb_idx = item->wb_idx; + u32 pipe_idx = item->pipe_idx; + int ret = 0; + + if (wb_idx >= mgr->queue_count) { + /* assign to the lowest priority queue */ + wb_idx = mgr->queue_count - 1; + } + + entry->doneq = &mgr->doneq[wb_idx]; + entry->commitq = &mgr->commitq[wb_idx]; + queue = mgr->commitq; + + if (!queue->hw) { + hw = mgr->ops_hw_alloc(mgr, pipe_idx, wb_idx); + if (IS_ERR_OR_NULL(hw)) { + SDEROT_ERR("fail to allocate hw\n"); + ret = PTR_ERR(hw); + } else { + queue->hw = hw; + } + } + + if (queue->hw) { + entry->commitq = queue; + queue->hw->pending_count++; + } + + perf = sde_rotator_find_session(private, item->session_id); + if (!perf) { + SDEROT_ERR( + "Could not find session based on rotation work item\n"); + return -EINVAL; + } + + entry->perf = perf; + perf->last_wb_idx = wb_idx; + + return ret; +} + +static void sde_rotator_unassign_queue(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry) +{ + struct sde_rot_queue *queue = entry->commitq; + + if (!queue) + return; + + entry->fenceq = NULL; + entry->commitq = NULL; + entry->doneq = NULL; + + if (!queue->hw) { + SDEROT_ERR("entry assigned a queue with no hw\n"); + return; + } + + queue->hw->pending_count--; + if (queue->hw->pending_count == 0) { + mgr->ops_hw_free(mgr, queue->hw); + queue->hw = NULL; + } +} + +void sde_rotator_queue_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + struct sde_rot_entry *entry; + struct sde_rot_queue *queue; + u32 wb_idx; + int i; + + if (!mgr || !private || !req) { + SDEROT_ERR("null parameters\n"); + return; + } + + if (!req->entries) { + SDEROT_DBG("no entries in request\n"); + return; + } + + for (i = 0; i < req->count; i++) { + entry = req->entries + i; + queue = entry->commitq; + wb_idx = queue->hw->wb_id; + entry->perf->work_distribution[wb_idx]++; + entry->work_assigned = true; + } + + for (i = 0; i < req->count; i++) { + entry = req->entries + i; + queue = entry->commitq; + entry->output_fence = NULL; + + if (entry->item.ts) + entry->item.ts[SDE_ROTATOR_TS_QUEUE] = ktime_get(); + kthread_queue_work(&queue->rot_kw, &entry->commit_work); + } +} + +static u32 sde_rotator_calc_buf_bw(struct sde_mdp_format_params *fmt, + uint32_t width, uint32_t height, uint32_t frame_rate) +{ + u32 bw; + + bw = width * height * frame_rate; + + if (sde_mdp_is_tp10_format(fmt)) + bw *= 2; + else if (sde_mdp_is_p010_format(fmt)) + bw *= 3; + else if (fmt->chroma_sample == SDE_MDP_CHROMA_420) + bw = (bw * 3) / 2; + else + bw *= fmt->bpp; + SDEROT_EVTLOG(bw, width, height, frame_rate, fmt->format); + return bw; +} + +static int sde_rotator_find_max_fps(struct sde_rot_mgr *mgr) +{ + struct sde_rot_file_private *priv; + struct sde_rot_perf *perf; + int max_fps = 0; + + list_for_each_entry(priv, &mgr->file_list, list) { + list_for_each_entry(perf, &priv->perf_list, list) { + if (perf->config.frame_rate > max_fps) + max_fps = perf->config.frame_rate; + } + } + + SDEROT_DBG("Max fps:%d\n", max_fps); + return max_fps; +} + +static int sde_rotator_calc_perf(struct sde_rot_mgr *mgr, + struct sde_rot_perf *perf) +{ + struct sde_rotation_config *config = &perf->config; + u32 read_bw, write_bw; + struct sde_mdp_format_params *in_fmt, *out_fmt; + struct sde_rotator_device *rot_dev; + int max_fps; + + rot_dev = platform_get_drvdata(mgr->pdev); + + in_fmt = sde_get_format_params(config->input.format); + if (!in_fmt) { + SDEROT_ERR("invalid input format %d\n", config->input.format); + return -EINVAL; + } + out_fmt = sde_get_format_params(config->output.format); + if (!out_fmt) { + SDEROT_ERR("invalid output format %d\n", config->output.format); + return -EINVAL; + } + + /* + * rotator processes 4 pixels per clock, but the actual throughtput + * is 3.6. We also need to take into account for overhead time. Final + * equation is: + * W x H / throughput / (1/fps - overhead) * fudge_factor + */ + max_fps = sde_rotator_find_max_fps(mgr); + perf->clk_rate = config->input.width * config->input.height; + perf->clk_rate = (perf->clk_rate * mgr->pixel_per_clk.denom) / + mgr->pixel_per_clk.numer; + perf->clk_rate *= max_fps; + perf->clk_rate = (perf->clk_rate * mgr->fudge_factor.numer) / + mgr->fudge_factor.denom; + perf->clk_rate *= mgr->overhead.denom; + + /* + * check for override overhead default value + */ + if (rot_dev->min_overhead_us > (mgr->overhead.numer * 100)) + perf->clk_rate = DIV_ROUND_UP_ULL(perf->clk_rate, + (mgr->overhead.denom - max_fps * + (rot_dev->min_overhead_us / 100))); + else + perf->clk_rate = DIV_ROUND_UP_ULL(perf->clk_rate, + (mgr->overhead.denom - max_fps * + mgr->overhead.numer)); + + /* use client provided clock if specified */ + if (config->flags & SDE_ROTATION_EXT_PERF) + perf->clk_rate = config->clk_rate; + + /* + * check for Override clock calculation + */ + if (rot_dev->min_rot_clk > perf->clk_rate) + perf->clk_rate = rot_dev->min_rot_clk; + + if (mgr->min_rot_clk > perf->clk_rate) + perf->clk_rate = mgr->min_rot_clk; + + if (mgr->max_rot_clk && (perf->clk_rate > mgr->max_rot_clk)) { + SDEROT_ERR("invalid clock:%ld exceeds max:%ld allowed\n", + perf->clk_rate, mgr->max_rot_clk); + return -EINVAL; + } + + read_bw = sde_rotator_calc_buf_bw(in_fmt, config->input.width, + config->input.height, max_fps); + + write_bw = sde_rotator_calc_buf_bw(out_fmt, config->output.width, + config->output.height, max_fps); + + read_bw = sde_apply_comp_ratio_factor(read_bw, in_fmt, + &config->input.comp_ratio); + write_bw = sde_apply_comp_ratio_factor(write_bw, out_fmt, + &config->output.comp_ratio); + + perf->bw = read_bw + write_bw; + + /* + * check for override bw calculation + */ + if (rot_dev->min_bw > perf->bw) + perf->bw = rot_dev->min_bw; + + /* use client provided bandwidth if specified */ + if (config->flags & SDE_ROTATION_EXT_PERF) + perf->bw = config->data_bw; + + perf->rdot_limit = sde_mdp_get_ot_limit( + config->input.width, config->input.height, + config->input.format, config->frame_rate, true); + perf->wrot_limit = sde_mdp_get_ot_limit( + config->input.width, config->input.height, + config->input.format, config->frame_rate, false); + + SDEROT_DBG("clk:%lu, rdBW:%d, wrBW:%d, rdOT:%d, wrOT:%d\n", + perf->clk_rate, read_bw, write_bw, perf->rdot_limit, + perf->wrot_limit); + SDEROT_EVTLOG(perf->clk_rate, read_bw, write_bw, perf->rdot_limit, + perf->wrot_limit); + return 0; +} + +static int sde_rotator_update_perf(struct sde_rot_mgr *mgr) +{ + struct sde_rot_file_private *priv; + struct sde_rot_perf *perf; + int not_in_suspend_mode; + u64 total_bw = 0; + + not_in_suspend_mode = !atomic_read(&mgr->device_suspended); + + if (not_in_suspend_mode) { + list_for_each_entry(priv, &mgr->file_list, list) { + list_for_each_entry(perf, &priv->perf_list, list) { + total_bw += perf->bw; + } + } + } + + total_bw += mgr->pending_close_bw_vote; + total_bw = max_t(u64, total_bw, mgr->minimum_bw_vote); + sde_rotator_enable_reg_bus(mgr, total_bw); + ATRACE_INT("bus_quota", total_bw); + sde_rotator_bus_scale_set_quota(&mgr->data_bus, total_bw); + + return 0; +} + +static void sde_rotator_release_from_work_distribution( + struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry) +{ + if (entry->work_assigned) { + bool free_perf = false; + u32 wb_idx = entry->commitq->hw->wb_id; + + if (entry->perf->work_distribution[wb_idx]) + entry->perf->work_distribution[wb_idx]--; + + if (!entry->perf->work_distribution[wb_idx] + && list_empty(&entry->perf->list)) { + /* close session has offloaded perf free to us */ + free_perf = true; + } + + entry->work_assigned = false; + if (free_perf) { + if (mgr->pending_close_bw_vote < entry->perf->bw) { + SDEROT_ERR( + "close bw vote underflow %llu / %llu\n", + mgr->pending_close_bw_vote, + entry->perf->bw); + mgr->pending_close_bw_vote = 0; + } else { + mgr->pending_close_bw_vote -= entry->perf->bw; + } + devm_kfree(&mgr->pdev->dev, + entry->perf->work_distribution); + devm_kfree(&mgr->pdev->dev, entry->perf); + sde_rotator_update_perf(mgr); + sde_rotator_clk_ctrl(mgr, false); + sde_rotator_resource_ctrl(mgr, false); + entry->perf = NULL; + } + } +} + +static void sde_rotator_release_entry(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry) +{ + sde_rotator_release_from_work_distribution(mgr, entry); + sde_rotator_clear_fence(entry); + sde_rotator_release_data(entry); + sde_rotator_unassign_queue(mgr, entry); +} + +/* + * sde_rotator_commit_handler - Commit workqueue handler. + * @file: Pointer to work struct. + * + * This handler is responsible for commit the job to h/w. + * Once the job is committed, the job entry is added to the done queue. + * + * Note this asynchronous handler is protected by hal lock. + */ +static void sde_rotator_commit_handler(struct kthread_work *work) +{ + struct sde_rot_entry *entry; + struct sde_rot_entry_container *request; + struct sde_rot_hw_resource *hw; + struct sde_rot_mgr *mgr; + struct sched_param param = { .sched_priority = 5 }; + struct sde_rot_trace_entry rot_trace; + int ret; + + entry = container_of(work, struct sde_rot_entry, commit_work); + request = entry->request; + + if (!request || !entry->private || !entry->private->mgr) { + SDEROT_ERR("fatal error, null request/context/device\n"); + return; + } + + ret = sched_setscheduler(entry->fenceq->rot_thread, SCHED_FIFO, ¶m); + if (ret) { + SDEROT_WARN("Fail to set kthread priority for fenceq: %d\n", + ret); + } + + mgr = entry->private->mgr; + + SDEROT_EVTLOG( + entry->item.session_id, entry->item.sequence_id, + entry->item.src_rect.x, entry->item.src_rect.y, + entry->item.src_rect.w, entry->item.src_rect.h, + entry->item.dst_rect.x, entry->item.dst_rect.y, + entry->item.dst_rect.w, entry->item.dst_rect.h, + entry->item.flags, + entry->dnsc_factor_w, entry->dnsc_factor_h); + + SDEDEV_DBG(mgr->device, + "commit handler s:%d.%u src:(%d,%d,%d,%d) dst:(%d,%d,%d,%d) f:0x%x dnsc:%u/%u\n", + entry->item.session_id, entry->item.sequence_id, + entry->item.src_rect.x, entry->item.src_rect.y, + entry->item.src_rect.w, entry->item.src_rect.h, + entry->item.dst_rect.x, entry->item.dst_rect.y, + entry->item.dst_rect.w, entry->item.dst_rect.h, + entry->item.flags, + entry->dnsc_factor_w, entry->dnsc_factor_h); + + sde_rot_mgr_lock(mgr); + + hw = sde_rotator_get_hw_resource(entry->commitq, entry); + if (!hw) { + SDEROT_ERR("no hw for the queue\n"); + goto get_hw_res_err; + } + + if (entry->item.ts) + entry->item.ts[SDE_ROTATOR_TS_COMMIT] = ktime_get(); + + /* Set values to pass to trace */ + rot_trace.wb_idx = entry->item.wb_idx; + rot_trace.flags = entry->item.flags; + rot_trace.input_format = entry->item.input.format; + rot_trace.input_width = entry->item.input.width; + rot_trace.input_height = entry->item.input.height; + rot_trace.src_x = entry->item.src_rect.x; + rot_trace.src_y = entry->item.src_rect.y; + rot_trace.src_w = entry->item.src_rect.w; + rot_trace.src_h = entry->item.src_rect.h; + rot_trace.output_format = entry->item.output.format; + rot_trace.output_width = entry->item.output.width; + rot_trace.output_height = entry->item.output.height; + rot_trace.dst_x = entry->item.dst_rect.x; + rot_trace.dst_y = entry->item.dst_rect.y; + rot_trace.dst_w = entry->item.dst_rect.w; + rot_trace.dst_h = entry->item.dst_rect.h; + + trace_rot_entry_commit( + entry->item.session_id, entry->item.sequence_id, &rot_trace); + + ATRACE_INT("sde_smmu_ctrl", 0); + ret = sde_smmu_ctrl(1); + if (ret < 0) { + SDEROT_ERR("IOMMU attach failed\n"); + goto smmu_error; + } + ATRACE_INT("sde_smmu_ctrl", 1); + + ret = sde_rotator_map_and_check_data(entry); + if (ret) { + SDEROT_ERR("fail to prepare input/output data %d\n", ret); + goto error; + } + + ret = mgr->ops_config_hw(hw, entry); + if (ret) { + SDEROT_ERR("fail to configure hw resource %d\n", ret); + goto error; + } + + if (entry->item.ts) + entry->item.ts[SDE_ROTATOR_TS_START] = ktime_get(); + + ret = sde_rotator_req_wait_start(mgr, request); + if (ret) { + SDEROT_WARN("timeout waiting for inline start\n"); + SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id, + SDE_ROT_EVTLOG_ERROR); + goto kickoff_error; + } + + ret = mgr->ops_kickoff_entry(hw, entry); + if (ret) { + SDEROT_ERR("fail to do kickoff %d\n", ret); + SDEROT_EVTLOG(entry->item.session_id, entry->item.sequence_id, + SDE_ROT_EVTLOG_ERROR); + goto kickoff_error; + } + + if (entry->item.ts) + entry->item.ts[SDE_ROTATOR_TS_FLUSH] = ktime_get(); + + SDEROT_EVTLOG(entry->item.session_id, 1); + + kthread_queue_work(&entry->doneq->rot_kw, &entry->done_work); + sde_rot_mgr_unlock(mgr); + return; +kickoff_error: + /* + * Wait for any pending operations to complete before cancelling this + * one so that the system is left in a consistent state. + */ + sde_rotator_req_wait_for_idle(mgr, request); + mgr->ops_cancel_hw(hw, entry); +error: + sde_smmu_ctrl(0); +smmu_error: + sde_rotator_put_hw_resource(entry->commitq, entry, hw); +get_hw_res_err: + sde_rotator_signal_output(entry); + sde_rotator_release_entry(mgr, entry); + atomic_dec(&request->pending_count); + atomic_inc(&request->failed_count); + if (request->retire_kw && request->retire_work) + kthread_queue_work(request->retire_kw, request->retire_work); + sde_rot_mgr_unlock(mgr); +} + +/* + * sde_rotator_done_handler - Done workqueue handler. + * @file: Pointer to work struct. + * + * This handler is responsible for waiting for h/w done event. + * Once the job is done, the output fence will be signaled and the job entry + * will be retired. + * + * Note this asynchronous handler is protected by hal lock. + */ +static void sde_rotator_done_handler(struct kthread_work *work) +{ + struct sde_rot_entry *entry; + struct sde_rot_entry_container *request; + struct sde_rot_hw_resource *hw; + struct sde_rot_mgr *mgr; + struct sde_rot_trace_entry rot_trace; + int ret; + + entry = container_of(work, struct sde_rot_entry, done_work); + request = entry->request; + + if (!request || !entry->private || !entry->private->mgr) { + SDEROT_ERR("fatal error, null request/context/device\n"); + return; + } + + mgr = entry->private->mgr; + hw = entry->commitq->hw; + + SDEDEV_DBG(mgr->device, + "done handler s:%d.%u src:(%d,%d,%d,%d) dst:(%d,%d,%d,%d) f:0x%x dsnc:%u/%u\n", + entry->item.session_id, entry->item.sequence_id, + entry->item.src_rect.x, entry->item.src_rect.y, + entry->item.src_rect.w, entry->item.src_rect.h, + entry->item.dst_rect.x, entry->item.dst_rect.y, + entry->item.dst_rect.w, entry->item.dst_rect.h, + entry->item.flags, + entry->dnsc_factor_w, entry->dnsc_factor_h); + + SDEROT_EVTLOG(entry->item.session_id, 0); + ret = mgr->ops_wait_for_entry(hw, entry); + if (ret) { + SDEROT_ERR("fail to wait for completion %d\n", ret); + atomic_inc(&request->failed_count); + } + SDEROT_EVTLOG(entry->item.session_id, 1); + + if (entry->item.ts) + entry->item.ts[SDE_ROTATOR_TS_DONE] = ktime_get(); + + /* Set values to pass to trace */ + rot_trace.wb_idx = entry->item.wb_idx; + rot_trace.flags = entry->item.flags; + rot_trace.input_format = entry->item.input.format; + rot_trace.input_width = entry->item.input.width; + rot_trace.input_height = entry->item.input.height; + rot_trace.src_x = entry->item.src_rect.x; + rot_trace.src_y = entry->item.src_rect.y; + rot_trace.src_w = entry->item.src_rect.w; + rot_trace.src_h = entry->item.src_rect.h; + rot_trace.output_format = entry->item.output.format; + rot_trace.output_width = entry->item.output.width; + rot_trace.output_height = entry->item.output.height; + rot_trace.dst_x = entry->item.dst_rect.x; + rot_trace.dst_y = entry->item.dst_rect.y; + rot_trace.dst_w = entry->item.dst_rect.w; + rot_trace.dst_h = entry->item.dst_rect.h; + + trace_rot_entry_done(entry->item.session_id, entry->item.sequence_id, + &rot_trace); + + sde_rot_mgr_lock(mgr); + sde_rotator_put_hw_resource(entry->commitq, entry, entry->commitq->hw); + sde_rotator_signal_output(entry); + ATRACE_INT("sde_rot_done", 1); + sde_rotator_release_entry(mgr, entry); + atomic_dec(&request->pending_count); + if (request->retire_kw && request->retire_work) + kthread_queue_work(request->retire_kw, request->retire_work); + if (entry->item.ts) + entry->item.ts[SDE_ROTATOR_TS_RETIRE] = ktime_get(); + sde_rot_mgr_unlock(mgr); + + ATRACE_INT("sde_smmu_ctrl", 3); + sde_smmu_ctrl(0); + ATRACE_INT("sde_smmu_ctrl", 4); +} + +static bool sde_rotator_verify_format(struct sde_rot_mgr *mgr, + struct sde_mdp_format_params *in_fmt, + struct sde_mdp_format_params *out_fmt, bool rotation, u32 mode) +{ + u8 in_v_subsample, in_h_subsample; + u8 out_v_subsample, out_h_subsample; + + if (!sde_rotator_is_valid_pixfmt(mgr, in_fmt->format, true, mode)) { + SDEROT_ERR("Invalid input format 0x%x (%4.4s)\n", + in_fmt->format, (char *)&in_fmt->format); + goto verify_error; + } + + if (!sde_rotator_is_valid_pixfmt(mgr, out_fmt->format, false, mode)) { + SDEROT_ERR("Invalid output format 0x%x (%4.4s)\n", + out_fmt->format, (char *)&out_fmt->format); + goto verify_error; + } + + if ((in_fmt->is_yuv != out_fmt->is_yuv) || + (in_fmt->pixel_mode != out_fmt->pixel_mode) || + (in_fmt->unpack_tight != out_fmt->unpack_tight)) { + SDEROT_ERR( + "Rotator does not support CSC yuv:%d/%d pm:%d/%d ut:%d/%d\n", + in_fmt->is_yuv, out_fmt->is_yuv, + in_fmt->pixel_mode, out_fmt->pixel_mode, + in_fmt->unpack_tight, out_fmt->unpack_tight); + goto verify_error; + } + + /* Forcing same pixel depth */ + if (memcmp(in_fmt->bits, out_fmt->bits, sizeof(in_fmt->bits))) { + /* Exception is that RGB can drop alpha or add X */ + if (in_fmt->is_yuv || out_fmt->alpha_enable || + (in_fmt->bits[C2_R_Cr] != out_fmt->bits[C2_R_Cr]) || + (in_fmt->bits[C0_G_Y] != out_fmt->bits[C0_G_Y]) || + (in_fmt->bits[C1_B_Cb] != out_fmt->bits[C1_B_Cb])) { + SDEROT_ERR("Bit format does not match\n"); + goto verify_error; + } + } + + /* Need to make sure that sub-sampling persists through rotation */ + if (rotation) { + sde_mdp_get_v_h_subsample_rate(in_fmt->chroma_sample, + &in_v_subsample, &in_h_subsample); + sde_mdp_get_v_h_subsample_rate(out_fmt->chroma_sample, + &out_v_subsample, &out_h_subsample); + + if ((in_v_subsample != out_h_subsample) || + (in_h_subsample != out_v_subsample)) { + SDEROT_ERR("Rotation has invalid subsampling\n"); + goto verify_error; + } + } else { + if (in_fmt->chroma_sample != out_fmt->chroma_sample) { + SDEROT_ERR("Format subsampling mismatch\n"); + goto verify_error; + } + } + + return true; + +verify_error: + SDEROT_ERR("in_fmt=0x%x (%4.4s), out_fmt=0x%x (%4.4s), mode=%d\n", + in_fmt->format, (char *)&in_fmt->format, + out_fmt->format, (char *)&out_fmt->format, + mode); + return false; +} + +static struct sde_mdp_format_params *__verify_input_config( + struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *in_fmt; + u8 in_v_subsample, in_h_subsample; + u32 input; + int verify_input_only; + + if (!mgr || !config) { + SDEROT_ERR("null parameters\n"); + return NULL; + } + + input = config->input.format; + verify_input_only = + (config->flags & SDE_ROTATION_VERIFY_INPUT_ONLY) ? 1 : 0; + + in_fmt = sde_get_format_params(input); + if (!in_fmt) { + if (!verify_input_only) + SDEROT_ERR("Unrecognized input format:0x%x\n", input); + return NULL; + } + + sde_mdp_get_v_h_subsample_rate(in_fmt->chroma_sample, + &in_v_subsample, &in_h_subsample); + + /* Dimension of image needs to be divisible by subsample rate */ + if ((config->input.height % in_v_subsample) || + (config->input.width % in_h_subsample)) { + if (!verify_input_only) + SDEROT_ERR( + "In ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n", + config->input.width, + config->input.height, + in_v_subsample, in_h_subsample); + return NULL; + } + + return in_fmt; +} + +static struct sde_mdp_format_params *__verify_output_config( + struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *out_fmt; + u8 out_v_subsample, out_h_subsample; + u32 output; + int verify_input_only; + + if (!mgr || !config) { + SDEROT_ERR("null parameters\n"); + return NULL; + } + + output = config->output.format; + verify_input_only = + (config->flags & SDE_ROTATION_VERIFY_INPUT_ONLY) ? 1 : 0; + + out_fmt = sde_get_format_params(output); + if (!out_fmt) { + if (!verify_input_only) + SDEROT_ERR("Unrecognized output format:0x%x\n", output); + return NULL; + } + + sde_mdp_get_v_h_subsample_rate(out_fmt->chroma_sample, + &out_v_subsample, &out_h_subsample); + + /* Dimension of image needs to be divisible by subsample rate */ + if ((config->output.height % out_v_subsample) || + (config->output.width % out_h_subsample)) { + if (!verify_input_only) + SDEROT_ERR( + "Out ROI, subsample mismatch, w=%d, h=%d, vss%d, hss%d\n", + config->output.width, + config->output.height, + out_v_subsample, out_h_subsample); + return NULL; + } + + return out_fmt; +} + +int sde_rotator_verify_config_input(struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *in_fmt; + + in_fmt = __verify_input_config(mgr, config); + if (!in_fmt) + return -EINVAL; + + return 0; +} + +int sde_rotator_verify_config_output(struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *out_fmt; + + out_fmt = __verify_output_config(mgr, config); + if (!out_fmt) + return -EINVAL; + + return 0; +} + +int sde_rotator_verify_config_all(struct sde_rot_mgr *mgr, + struct sde_rotation_config *config) +{ + struct sde_mdp_format_params *in_fmt, *out_fmt; + bool rotation; + u32 mode; + + if (!mgr || !config) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + rotation = (config->flags & SDE_ROTATION_90) ? true : false; + + mode = config->output.sbuf ? SDE_ROTATOR_MODE_SBUF : + SDE_ROTATOR_MODE_OFFLINE; + + in_fmt = __verify_input_config(mgr, config); + if (!in_fmt) + return -EINVAL; + + out_fmt = __verify_output_config(mgr, config); + if (!out_fmt) + return -EINVAL; + + if (!sde_rotator_verify_format(mgr, in_fmt, out_fmt, rotation, mode)) { + SDEROT_ERR( + "Rot format pairing invalid, in_fmt:0x%x, out_fmt:0x%x\n", + config->input.format, + config->output.format); + return -EINVAL; + } + + return 0; +} + +static int sde_rotator_validate_item_matches_session( + struct sde_rotation_config *config, struct sde_rotation_item *item) +{ + int ret; + + ret = __compare_session_item_rect(&config->input, + &item->src_rect, item->input.format, true); + if (ret) + return ret; + + ret = __compare_session_item_rect(&config->output, + &item->dst_rect, item->output.format, false); + if (ret) + return ret; + + ret = __compare_session_rotations(config->flags, item->flags); + if (ret) + return ret; + + return 0; +} + +/* Only need to validate x and y offset for ubwc dst fmt */ +static int sde_rotator_validate_img_roi(struct sde_rotation_item *item) +{ + struct sde_mdp_format_params *fmt; + int ret = 0; + + fmt = sde_get_format_params(item->output.format); + if (!fmt) { + SDEROT_DBG("invalid output format:%d\n", + item->output.format); + return -EINVAL; + } + + if (sde_mdp_is_ubwc_format(fmt)) + ret = sde_validate_offset_for_ubwc_format(fmt, + item->dst_rect.x, item->dst_rect.y); + + return ret; +} + +static int sde_rotator_validate_fmt_and_item_flags( + struct sde_rotation_config *config, struct sde_rotation_item *item) +{ + struct sde_mdp_format_params *fmt; + + fmt = sde_get_format_params(item->input.format); + if ((item->flags & SDE_ROTATION_DEINTERLACE) && + sde_mdp_is_ubwc_format(fmt)) { + SDEROT_DBG("cannot perform deinterlace on tiled formats\n"); + return -EINVAL; + } + return 0; +} + +static int sde_rotator_validate_entry(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry *entry) +{ + int ret; + struct sde_rotation_item *item; + struct sde_rot_perf *perf; + + item = &entry->item; + + if (item->wb_idx >= mgr->queue_count) + item->wb_idx = mgr->queue_count - 1; + + perf = sde_rotator_find_session(private, item->session_id); + if (!perf) { + SDEROT_DBG("Could not find session:%u\n", item->session_id); + return -EINVAL; + } + + ret = sde_rotator_validate_item_matches_session(&perf->config, item); + if (ret) { + SDEROT_DBG("Work item does not match session:%u\n", + item->session_id); + return ret; + } + + ret = sde_rotator_validate_img_roi(item); + if (ret) { + SDEROT_DBG("Image roi is invalid\n"); + return ret; + } + + ret = sde_rotator_validate_fmt_and_item_flags(&perf->config, item); + if (ret) + return ret; + + ret = mgr->ops_hw_validate_entry(mgr, entry); + if (ret) { + SDEROT_DBG("fail to configure downscale factor\n"); + return ret; + } + return ret; +} + +/* + * Upon failure from the function, caller needs to make sure + * to call sde_rotator_remove_request to clean up resources. + */ +static int sde_rotator_add_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + struct sde_rot_entry *entry; + struct sde_rotation_item *item; + int i, ret; + + for (i = 0; i < req->count; i++) { + entry = req->entries + i; + item = &entry->item; + entry->fenceq = private->fenceq; + + ret = sde_rotator_validate_entry(mgr, private, entry); + if (ret) { + SDEROT_ERR("fail to validate the entry\n"); + return ret; + } + + ret = sde_rotator_import_data(mgr, entry); + if (ret) { + SDEROT_ERR("fail to import the data\n"); + return ret; + } + + entry->input_fence = item->input.fence; + entry->output_fence = item->output.fence; + + ret = sde_rotator_assign_queue(mgr, entry, private); + if (ret) { + SDEROT_ERR("fail to assign queue to entry\n"); + return ret; + } + + entry->request = req; + + kthread_init_work(&entry->commit_work, + sde_rotator_commit_handler); + kthread_init_work(&entry->done_work, + sde_rotator_done_handler); + SDEROT_DBG( + "Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%x dst{%u,%u,%u,%u}f=%x session_id=%u\n", + item->wb_idx, + item->src_rect.x, item->src_rect.y, + item->src_rect.w, item->src_rect.h, item->input.format, + item->dst_rect.x, item->dst_rect.y, + item->dst_rect.w, item->dst_rect.h, item->output.format, + item->session_id); + } + + list_add(&req->list, &private->req_list); + + return 0; +} + +void sde_rotator_remove_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + int i; + + if (!mgr || !private || !req) { + SDEROT_ERR("null parameters\n"); + return; + } + + for (i = 0; i < req->count; i++) + sde_rotator_release_entry(mgr, req->entries + i); + list_del_init(&req->list); +} + +/* This function should be called with req_lock */ +static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req) +{ + struct sde_rot_entry *entry; + int i; + + if (atomic_read(&req->pending_count)) { + /* + * To avoid signal the rotation entry output fence in the wrong + * order, all the entries in the same request needs to be + * canceled first, before signaling the output fence. + */ + SDEROT_DBG("cancel work start\n"); + sde_rot_mgr_unlock(mgr); + for (i = req->count - 1; i >= 0; i--) { + entry = req->entries + i; + kthread_cancel_work_sync(&entry->commit_work); + kthread_cancel_work_sync(&entry->done_work); + } + sde_rot_mgr_lock(mgr); + SDEROT_DBG("cancel work done\n"); + for (i = req->count - 1; i >= 0; i--) { + entry = req->entries + i; + sde_rotator_signal_output(entry); + sde_rotator_release_entry(mgr, entry); + } + } + + list_del_init(&req->list); + devm_kfree(&mgr->pdev->dev, req); +} + +void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private) +{ + struct sde_rot_entry_container *req, *req_next; + + SDEROT_DBG("Canceling all rotator requests\n"); + + list_for_each_entry_safe(req, req_next, &private->req_list, list) + sde_rotator_cancel_request(mgr, req); +} + +static void sde_rotator_free_completed_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private) +{ + struct sde_rot_entry_container *req, *req_next; + + list_for_each_entry_safe(req, req_next, &private->req_list, list) { + if ((atomic_read(&req->pending_count) == 0) && req->finished) { + list_del_init(&req->list); + devm_kfree(&mgr->pdev->dev, req); + } + } +} + +static void sde_rotator_release_rotator_perf_session( + struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private) +{ + struct sde_rot_perf *perf, *perf_next; + + SDEROT_DBG("Releasing all rotator request\n"); + sde_rotator_cancel_all_requests(mgr, private); + + list_for_each_entry_safe(perf, perf_next, &private->perf_list, list) { + list_del_init(&perf->list); + devm_kfree(&mgr->pdev->dev, perf->work_distribution); + devm_kfree(&mgr->pdev->dev, perf); + } +} + +static void sde_rotator_release_all(struct sde_rot_mgr *mgr) +{ + struct sde_rot_file_private *priv, *priv_next; + + list_for_each_entry_safe(priv, priv_next, &mgr->file_list, list) { + sde_rotator_release_rotator_perf_session(mgr, priv); + sde_rotator_resource_ctrl(mgr, false); + list_del_init(&priv->list); + } + + sde_rotator_update_perf(mgr); +} + +int sde_rotator_validate_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + int i, ret = 0; + struct sde_rot_entry *entry; + + if (!mgr || !private || !req) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + for (i = 0; i < req->count; i++) { + entry = req->entries + i; + ret = sde_rotator_validate_entry(mgr, private, + entry); + if (ret) { + SDEROT_DBG("invalid entry\n"); + return ret; + } + } + + return ret; +} + +static int sde_rotator_open_session(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, u32 session_id) +{ + struct sde_rotation_config config; + struct sde_rot_perf *perf; + int ret; + + if (!mgr || !private) + return -EINVAL; + + memset(&config, 0, sizeof(struct sde_rotation_config)); + + /* initialize with default parameters */ + config.frame_rate = 30; + config.input.comp_ratio.numer = 1; + config.input.comp_ratio.denom = 1; + config.input.format = SDE_PIX_FMT_Y_CBCR_H2V2; + config.input.width = 640; + config.input.height = 480; + config.output.comp_ratio.numer = 1; + config.output.comp_ratio.denom = 1; + config.output.format = SDE_PIX_FMT_Y_CBCR_H2V2; + config.output.width = 640; + config.output.height = 480; + + perf = devm_kzalloc(&mgr->pdev->dev, sizeof(*perf), GFP_KERNEL); + if (!perf) + return -ENOMEM; + + perf->work_distribution = devm_kzalloc(&mgr->pdev->dev, + sizeof(u32) * mgr->queue_count, GFP_KERNEL); + if (!perf->work_distribution) { + ret = -ENOMEM; + goto alloc_err; + } + + config.session_id = session_id; + perf->config = config; + perf->last_wb_idx = 0; + + INIT_LIST_HEAD(&perf->list); + list_add(&perf->list, &private->perf_list); + + ret = sde_rotator_resource_ctrl(mgr, true); + if (ret < 0) { + SDEROT_ERR("Failed to acquire rotator resources\n"); + goto resource_err; + } + + ret = sde_rotator_update_clk(mgr); + if (ret) { + SDEROT_ERR("failed to update clk %d\n", ret); + goto update_clk_err; + } + + ret = sde_rotator_clk_ctrl(mgr, true); + if (ret) { + SDEROT_ERR("failed to enable clk %d\n", ret); + goto enable_clk_err; + } + + SDEROT_DBG("open session id=%u in{%u,%u}f:%u out{%u,%u}f:%u\n", + config.session_id, config.input.width, config.input.height, + config.input.format, config.output.width, config.output.height, + config.output.format); + + goto done; +enable_clk_err: +update_clk_err: + sde_rotator_resource_ctrl(mgr, false); +resource_err: + list_del_init(&perf->list); + devm_kfree(&mgr->pdev->dev, perf->work_distribution); +alloc_err: + devm_kfree(&mgr->pdev->dev, perf); +done: + return ret; +} + +static int sde_rotator_close_session(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, u32 session_id) +{ + struct sde_rot_perf *perf; + bool offload_release_work = false; + u32 id; + + id = (u32)session_id; + perf = __sde_rotator_find_session(private, id); + if (!perf) { + SDEROT_ERR("Trying to close session that does not exist\n"); + return -EINVAL; + } + + if (sde_rotator_is_work_pending(mgr, perf)) { + SDEROT_DBG("Work is still pending, offload free to wq\n"); + mgr->pending_close_bw_vote += perf->bw; + offload_release_work = true; + } + list_del_init(&perf->list); + + if (offload_release_work) + goto done; + + devm_kfree(&mgr->pdev->dev, perf->work_distribution); + devm_kfree(&mgr->pdev->dev, perf); + sde_rotator_update_perf(mgr); + sde_rotator_clk_ctrl(mgr, false); + sde_rotator_update_clk(mgr); + sde_rotator_resource_ctrl(mgr, false); +done: + if (mgr->sbuf_ctx == private) { + SDEROT_DBG("release sbuf session id:%u\n", id); + SDEROT_EVTLOG(id); + mgr->sbuf_ctx = NULL; + } + + SDEROT_DBG("Closed session id:%u\n", id); + return 0; +} + +static int sde_rotator_config_session(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rotation_config *config) +{ + int ret = 0; + struct sde_rot_perf *perf; + + ret = sde_rotator_verify_config_all(mgr, config); + if (ret) { + SDEROT_ERR("Rotator verify format failed\n"); + return ret; + } + + perf = sde_rotator_find_session(private, config->session_id); + if (!perf) { + SDEROT_ERR("No session with id=%u could be found\n", + config->session_id); + return -EINVAL; + } + + perf->config = *config; + ret = sde_rotator_calc_perf(mgr, perf); + + if (ret) { + SDEROT_ERR("error in configuring the session %d\n", ret); + goto done; + } + + ret = sde_rotator_update_perf(mgr); + if (ret) { + SDEROT_ERR("error in updating perf: %d\n", ret); + goto done; + } + + ret = sde_rotator_update_clk(mgr); + if (ret) { + SDEROT_ERR("error in updating the rotator clk: %d\n", ret); + goto done; + } + + if (config->output.sbuf && mgr->sbuf_ctx != private && mgr->sbuf_ctx) { + SDEROT_ERR("too many sbuf sessions\n"); + ret = -EBUSY; + goto done; + } + + SDEROT_DBG( + "reconfig session id=%u in{%u,%u}f:%x out{%u,%u}f:%x fps:%d clk:%lu bw:%llu\n", + config->session_id, config->input.width, config->input.height, + config->input.format, config->output.width, + config->output.height, config->output.format, + config->frame_rate, perf->clk_rate, perf->bw); + SDEROT_EVTLOG(config->session_id, config->input.width, + config->input.height, config->input.format, + config->output.width, config->output.height, + config->output.format, config->frame_rate); +done: + return ret; +} + +struct sde_rot_entry_container *sde_rotator_req_init( + struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rotation_item *items, + u32 count, u32 flags) +{ + struct sde_rot_entry_container *req; + int size, i; + + if (!mgr || !private || !items) { + SDEROT_ERR("null parameters\n"); + return ERR_PTR(-EINVAL); + } + + size = sizeof(struct sde_rot_entry_container); + size += sizeof(struct sde_rot_entry) * count; + req = devm_kzalloc(&mgr->pdev->dev, size, GFP_KERNEL); + + if (!req) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&req->list); + req->count = count; + req->entries = (struct sde_rot_entry *) + ((void *)req + sizeof(struct sde_rot_entry_container)); + req->flags = flags; + atomic_set(&req->pending_count, count); + atomic_set(&req->failed_count, 0); + + for (i = 0; i < count; i++) { + req->entries[i].item = items[i]; + req->entries[i].private = private; + + init_completion(&req->entries[i].item.inline_start); + complete_all(&req->entries[i].item.inline_start); + } + + return req; +} + +void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req) +{ + int i; + + if (!mgr || !req) + return; + + for (i = 0; i < req->count; i++) + reinit_completion(&req->entries[i].item.inline_start); +} + +void sde_rotator_req_set_start(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req) +{ + struct kthread_work *commit_work; + int i; + + if (!mgr || !req || !req->entries) + return; + + /* signal ready to start */ + for (i = 0; i < req->count; i++) + complete_all(&req->entries[i].item.inline_start); + + for (i = 0; i < req->count; i++) { + commit_work = &req->entries[i].commit_work; + + SDEROT_EVTLOG(i, req->count); + + sde_rot_mgr_unlock(mgr); + kthread_flush_work(commit_work); + sde_rot_mgr_lock(mgr); + } +} + +int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req) +{ + struct completion *inline_start; + int i, ret; + + if (!mgr || !req || !req->entries) + return -EINVAL; + + /* only wait for sbuf mode */ + if (!mgr->sbuf_ctx || !req->count || + mgr->sbuf_ctx != req->entries[0].private) + return 0; + + for (i = 0; i < req->count; i++) { + inline_start = &req->entries[i].item.inline_start; + + sde_rot_mgr_unlock(mgr); + ret = wait_for_completion_timeout(inline_start, + msecs_to_jiffies(ROT_INLINE_START_TIMEOUT_IN_MS)); + sde_rot_mgr_lock(mgr); + } + + /* wait call returns zero on timeout */ + return ret ? 0 : -EBUSY; +} + +void sde_rotator_req_finish(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + if (!mgr || !private || !req) { + SDEROT_ERR("null parameters\n"); + return; + } + + req->finished = true; +} + +void sde_rotator_abort_inline_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + struct kthread_work *commit_work; + struct kthread_work *done_work; + struct sde_rot_entry *entry; + struct sde_rot_hw_resource *hw; + int i; + + if (!mgr || !private || !req || !req->entries) + return; + + for (i = 0; i < req->count; i++) { + entry = &req->entries[i]; + if (!entry) + continue; + + commit_work = &entry->commit_work; + done_work = &entry->done_work; + + hw = sde_rotator_get_hw_resource(entry->commitq, entry); + if (!hw) { + SDEROT_ERR("no hw for the queue\n"); + SDEROT_EVTLOG(i, req->count, SDE_ROT_EVTLOG_ERROR); + continue; + } + + SDEROT_EVTLOG(i, req->count); + + mgr->ops_abort_hw(hw, entry); + + sde_rot_mgr_unlock(mgr); + kthread_flush_work(commit_work); + kthread_flush_work(done_work); + sde_rot_mgr_lock(mgr); + } +} + +int sde_rotator_handle_request_common(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req) +{ + int ret; + + if (!mgr || !private || !req) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + sde_rotator_free_completed_request(mgr, private); + + ret = sde_rotator_add_request(mgr, private, req); + if (ret) { + SDEROT_ERR("fail to add rotation request\n"); + sde_rotator_remove_request(mgr, private, req); + return ret; + } + return ret; +} + +static int sde_rotator_open(struct sde_rot_mgr *mgr, + struct sde_rot_file_private **pprivate) +{ + struct sde_rot_file_private *private; + + if (!mgr || !pprivate) + return -ENODEV; + + if (atomic_read(&mgr->device_suspended)) + return -EPERM; + + private = devm_kzalloc(&mgr->pdev->dev, sizeof(*private), + GFP_KERNEL); + if (!private) + return -ENOMEM; + + INIT_LIST_HEAD(&private->req_list); + INIT_LIST_HEAD(&private->perf_list); + INIT_LIST_HEAD(&private->list); + + list_add(&private->list, &mgr->file_list); + + *pprivate = private; + + return 0; +} + +static bool sde_rotator_file_priv_allowed(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *priv) +{ + struct sde_rot_file_private *_priv, *_priv_next; + bool ret = false; + + list_for_each_entry_safe(_priv, _priv_next, &mgr->file_list, list) { + if (_priv == priv) { + ret = true; + break; + } + } + return ret; +} + +static int sde_rotator_close(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private) +{ + if (!mgr || !private) + return -ENODEV; + + if (!(sde_rotator_file_priv_allowed(mgr, private))) { + SDEROT_ERR( + "Calling close with unrecognized rot_file_private\n"); + return -EINVAL; + } + + /* + * if secure camera session was enabled + * go back to non secure state + */ + sde_rotator_secure_session_ctrl(false); + sde_rotator_release_rotator_perf_session(mgr, private); + + list_del_init(&private->list); + devm_kfree(&mgr->pdev->dev, private); + + sde_rotator_update_perf(mgr); + return 0; +} + +static ssize_t caps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t len = PAGE_SIZE; + int cnt = 0; + struct sde_rot_mgr *mgr = sde_rot_mgr_from_device(dev); + + if (!mgr) + return cnt; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + SPRINT("queue_count=%d\n", mgr->queue_count); + SPRINT("downscale=1\n"); + SPRINT("ubwc=1\n"); + + if (mgr->ops_hw_show_caps) + cnt += mgr->ops_hw_show_caps(mgr, attr, buf + cnt, len - cnt); + + return cnt; +} + +static ssize_t state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t len = PAGE_SIZE; + int cnt = 0; + struct sde_rot_mgr *mgr = sde_rot_mgr_from_device(dev); + int i; + + if (!mgr) + return cnt; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + SPRINT("reg_bus_bw=%llu\n", mgr->reg_bus.curr_quota_val); + SPRINT("data_bus_bw=%llu\n", mgr->data_bus.curr_quota_val); + SPRINT("pending_close_bw_vote=%llu\n", mgr->pending_close_bw_vote); + SPRINT("device_suspended=%d\n", atomic_read(&mgr->device_suspended)); + SPRINT("footswitch_cnt=%d\n", mgr->res_ref_cnt); + SPRINT("regulator_enable=%d\n", mgr->regulator_enable); + SPRINT("enable_clk_cnt=%d\n", mgr->rot_enable_clk_cnt); + for (i = 0; i < mgr->num_rot_clk; i++) + if (mgr->rot_clk[i].clk) + SPRINT("%s=%lu\n", mgr->rot_clk[i].clk_name, + clk_get_rate(mgr->rot_clk[i].clk)); + + if (mgr->ops_hw_show_state) + cnt += mgr->ops_hw_show_state(mgr, attr, buf + cnt, len - cnt); + + return cnt; +} + +static DEVICE_ATTR_RO(caps); +static DEVICE_ATTR_RO(state); + +static struct attribute *sde_rotator_fs_attrs[] = { + &dev_attr_caps.attr, + &dev_attr_state.attr, + NULL +}; + +static struct attribute_group sde_rotator_fs_attr_group = { + .attrs = sde_rotator_fs_attrs +}; + +#ifdef CONFIG_QCOM_BUS_SCALING +static int sde_rotator_parse_dt_bus(struct sde_rot_mgr *mgr, + struct platform_device *dev) +{ + int ret = 0, i; + int usecases; + struct device_node *node; + + mgr->data_bus.bus_scale_pdata = msm_bus_cl_get_pdata(dev); + if (IS_ERR_OR_NULL(mgr->data_bus.bus_scale_pdata)) { + ret = PTR_ERR(mgr->data_bus.bus_scale_pdata); + if (ret) { + SDEROT_ERR("msm_bus_cl_get_pdata failed. ret=%d\n", + ret); + mgr->data_bus.bus_scale_pdata = NULL; + } + } + + node = of_get_child_by_name(dev->dev.of_node, "qcom,rot-reg-bus"); + if (node) { + mgr->reg_bus.bus_scale_pdata + = msm_bus_pdata_from_node(dev, node); + if (IS_ERR_OR_NULL(mgr->reg_bus.bus_scale_pdata)) { + SDEROT_ERR("reg bus pdata parsing failed\n"); + ret = PTR_ERR(mgr->reg_bus.bus_scale_pdata); + if (!mgr->reg_bus.bus_scale_pdata) + ret = -EINVAL; + mgr->reg_bus.bus_scale_pdata = NULL; + } + } else { + SDEROT_DBG( + "no DT entries, configuring default reg bus table\n"); + mgr->reg_bus.bus_scale_pdata = &rot_reg_bus_scale_table; + usecases = mgr->reg_bus.bus_scale_pdata->num_usecases; + for (i = 0; i < usecases; i++) { + rot_reg_bus_usecases[i].num_paths = 1; + rot_reg_bus_usecases[i].vectors = + &rot_reg_bus_vectors[i]; + } + } + + return ret; +} +#else +static inline int sde_rotator_parse_dt_bus(struct sde_rot_mgr *mgr, + struct platform_device *dev) +{ + return 0; +} +#endif + +static int sde_rotator_parse_dt(struct sde_rot_mgr *mgr, + struct platform_device *dev) +{ + int ret = 0; + u32 data; + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,mdss-wb-count", &data); + if (!ret) { + if (data > ROT_MAX_HW_BLOCKS) { + SDEROT_ERR( + "Err, num of wb block (%d) larger than sw max %d\n", + data, ROT_MAX_HW_BLOCKS); + return -EINVAL; + } + + mgr->queue_count = data; + } + + ret = sde_rotator_parse_dt_bus(mgr, dev); + if (ret) + SDEROT_ERR("Failed to parse bus data\n"); + + return ret; +} + +static void sde_rotator_put_dt_vreg_data(struct device *dev, + struct sde_module_power *mp) +{ + if (!mp) { + SDEROT_ERR("%s: invalid input\n", __func__); + return; + } + + sde_rot_config_vreg(dev, mp->vreg_config, mp->num_vreg, 0); + if (mp->vreg_config) { + devm_kfree(dev, mp->vreg_config); + mp->vreg_config = NULL; + } + mp->num_vreg = 0; +} + +static int sde_rotator_get_dt_vreg_data(struct device *dev, + struct sde_module_power *mp) +{ + const char *st = NULL; + struct device_node *of_node = NULL; + int dt_vreg_total = 0; + int i; + int rc; + + if (!dev || !mp) { + SDEROT_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + of_node = dev->of_node; + + dt_vreg_total = of_property_count_strings(of_node, "qcom,supply-names"); + if (dt_vreg_total < 0) { + SDEROT_ERR("%s: vreg not found. rc=%d\n", __func__, + dt_vreg_total); + return 0; + } + mp->num_vreg = dt_vreg_total; + mp->vreg_config = devm_kzalloc(dev, sizeof(struct sde_vreg) * + dt_vreg_total, GFP_KERNEL); + if (!mp->vreg_config) + return -ENOMEM; + + /* vreg-name */ + for (i = 0; i < dt_vreg_total; i++) { + rc = of_property_read_string_index(of_node, + "qcom,supply-names", i, &st); + if (rc) { + SDEROT_ERR("%s: error reading name. i=%d, rc=%d\n", + __func__, i, rc); + goto error; + } + snprintf(mp->vreg_config[i].vreg_name, 32, "%s", st); + } + sde_rot_config_vreg(dev, mp->vreg_config, mp->num_vreg, 1); + + for (i = 0; i < dt_vreg_total; i++) { + SDEROT_DBG("%s: %s min=%d, max=%d, enable=%d disable=%d\n", + __func__, + mp->vreg_config[i].vreg_name, + mp->vreg_config[i].min_voltage, + mp->vreg_config[i].max_voltage, + mp->vreg_config[i].enable_load, + mp->vreg_config[i].disable_load); + } + return rc; + +error: + if (mp->vreg_config) { + devm_kfree(dev, mp->vreg_config); + mp->vreg_config = NULL; + } + mp->num_vreg = 0; + return rc; +} + +#ifdef CONFIG_QCOM_BUS_SCALING +static void sde_rotator_bus_scale_unregister(struct sde_rot_mgr *mgr) +{ + SDEROT_DBG("unregister bus_hdl=%x, reg_bus_hdl=%x\n", + mgr->data_bus.bus_hdl, mgr->reg_bus.bus_hdl); + + if (mgr->data_bus.bus_hdl) + msm_bus_scale_unregister_client(mgr->data_bus.bus_hdl); + + if (mgr->reg_bus.bus_hdl) + msm_bus_scale_unregister_client(mgr->reg_bus.bus_hdl); +} + +static int sde_rotator_bus_scale_register(struct sde_rot_mgr *mgr) +{ + if (!mgr->data_bus.bus_scale_pdata) { + SDEROT_DBG("Bus scaling is not enabled\n"); + return 0; + } + + mgr->data_bus.bus_hdl = + msm_bus_scale_register_client( + mgr->data_bus.bus_scale_pdata); + if (!mgr->data_bus.bus_hdl) { + SDEROT_ERR("bus_client register failed\n"); + return -EINVAL; + } + SDEROT_DBG("registered bus_hdl=%x\n", mgr->data_bus.bus_hdl); + + if (mgr->reg_bus.bus_scale_pdata) { + mgr->reg_bus.bus_hdl = + msm_bus_scale_register_client( + mgr->reg_bus.bus_scale_pdata); + if (!mgr->reg_bus.bus_hdl) { + SDEROT_ERR("register bus_client register failed\n"); + sde_rotator_bus_scale_unregister(mgr); + } else { + SDEROT_DBG("registered register bus_hdl=%x\n", + mgr->reg_bus.bus_hdl); + } + } + + return 0; +} +#else +static inline void sde_rotator_bus_scale_unregister(struct sde_rot_mgr *mgr) +{ +} +static inline int sde_rotator_bus_scale_register(struct sde_rot_mgr *mgr) +{ + return 0; +} +#endif + +static inline int sde_rotator_search_dt_clk(struct platform_device *pdev, + struct sde_rot_mgr *mgr, char *clk_name, int clk_idx, + bool mandatory) +{ + struct clk *tmp; + int rc = 0; + + if (clk_idx >= SDE_ROTATOR_CLK_MAX) { + SDEROT_ERR("invalid clk index %d\n", clk_idx); + return -EINVAL; + } + + tmp = devm_clk_get(&pdev->dev, clk_name); + if (IS_ERR(tmp)) { + if (mandatory) + SDEROT_ERR("unable to get clk: %s\n", clk_name); + else + tmp = NULL; + rc = PTR_ERR(tmp); + } + + strlcpy(mgr->rot_clk[clk_idx].clk_name, clk_name, + sizeof(mgr->rot_clk[clk_idx].clk_name)); + + mgr->rot_clk[clk_idx].clk = tmp; + return mandatory ? rc : 0; +} + +static int sde_rotator_parse_dt_clk(struct platform_device *pdev, + struct sde_rot_mgr *mgr) +{ + u32 rc = 0; + int num_clk; + + num_clk = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if ((num_clk <= 0) || (num_clk > SDE_ROTATOR_CLK_MAX)) { + SDEROT_ERR("Number of clocks are out of range: %d\n", num_clk); + goto clk_err; + } + + mgr->num_rot_clk = SDE_ROTATOR_CLK_MAX; + mgr->rot_clk = devm_kzalloc(&pdev->dev, + sizeof(struct sde_rot_clk) * mgr->num_rot_clk, + GFP_KERNEL); + if (!mgr->rot_clk) { + rc = -ENOMEM; + mgr->num_rot_clk = 0; + goto clk_err; + } + + if (sde_rotator_search_dt_clk(pdev, mgr, "mnoc_clk", + SDE_ROTATOR_CLK_MNOC_AHB, false) || + sde_rotator_search_dt_clk(pdev, mgr, "gcc_iface", + SDE_ROTATOR_CLK_GCC_AHB, false) || + sde_rotator_search_dt_clk(pdev, mgr, "gcc_bus", + SDE_ROTATOR_CLK_GCC_AXI, false) || + sde_rotator_search_dt_clk(pdev, mgr, "iface_clk", + SDE_ROTATOR_CLK_MDSS_AHB, true) || + sde_rotator_search_dt_clk(pdev, mgr, "axi_clk", + SDE_ROTATOR_CLK_MDSS_AXI, false) || + sde_rotator_search_dt_clk(pdev, mgr, "rot_core_clk", + SDE_ROTATOR_CLK_MDSS_ROT, false)) { + rc = -EINVAL; + goto clk_err; + } + + /* + * If 'MDSS_ROT' is already present, place 'rot_clk' under + * MDSS_ROT_SUB. Otherwise, place it directly into MDSS_ROT. + */ + if (sde_rotator_get_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT)) + rc = sde_rotator_search_dt_clk(pdev, mgr, "rot_clk", + SDE_ROTATOR_CLK_MDSS_ROT_SUB, true); + else + rc = sde_rotator_search_dt_clk(pdev, mgr, "rot_clk", + SDE_ROTATOR_CLK_MDSS_ROT, true); +clk_err: + return rc; +} + +static int sde_rotator_register_clk(struct platform_device *pdev, + struct sde_rot_mgr *mgr) +{ + int ret; + + ret = sde_rotator_parse_dt_clk(pdev, mgr); + if (ret) { + SDEROT_ERR("unable to parse clocks\n"); + return -EINVAL; + } + + return 0; +} + +static void sde_rotator_unregister_clk(struct sde_rot_mgr *mgr) +{ + devm_kfree(mgr->device, mgr->rot_clk); + mgr->rot_clk = NULL; + mgr->num_rot_clk = 0; +} + +static int sde_rotator_res_init(struct platform_device *pdev, + struct sde_rot_mgr *mgr) +{ + int ret; + + if (!sde_rot_mgr_pd_enabled(mgr)) { + ret = sde_rotator_get_dt_vreg_data( + &pdev->dev, &mgr->module_power); + if (ret) + return ret; + } + + ret = sde_rotator_register_clk(pdev, mgr); + if (ret) + goto error; + + ret = sde_rotator_bus_scale_register(mgr); + if (ret) + goto error; + + return 0; +error: + sde_rotator_put_dt_vreg_data(&pdev->dev, &mgr->module_power); + return ret; +} + +static void sde_rotator_res_destroy(struct sde_rot_mgr *mgr) +{ + struct platform_device *pdev = mgr->pdev; + + sde_rotator_unregister_clk(mgr); + sde_rotator_bus_scale_unregister(mgr); + + if (!sde_rot_mgr_pd_enabled(mgr)) + sde_rotator_put_dt_vreg_data(&pdev->dev, &mgr->module_power); +} + +int sde_rotator_core_init(struct sde_rot_mgr **pmgr, + struct platform_device *pdev) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_rot_mgr *mgr; + int ret; + + if (!pmgr || !pdev) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + mgr = devm_kzalloc(&pdev->dev, sizeof(struct sde_rot_mgr), + GFP_KERNEL); + if (!mgr) + return -ENOMEM; + + mgr->pdev = pdev; + mgr->device = &pdev->dev; + mgr->pending_close_bw_vote = 0; + mgr->enable_bw_vote = ROT_ENABLE_BW_VOTE; + mgr->hwacquire_timeout = ROT_HW_ACQUIRE_TIMEOUT_IN_MS; + mgr->queue_count = 1; + mgr->pixel_per_clk.numer = ROT_PIXEL_PER_CLK_NUMERATOR; + mgr->pixel_per_clk.denom = ROT_PIXEL_PER_CLK_DENOMINATOR; + mgr->fudge_factor.numer = ROT_FUDGE_FACTOR_NUMERATOR; + mgr->fudge_factor.denom = ROT_FUDGE_FACTOR_DENOMINATOR; + mgr->overhead.numer = ROT_OVERHEAD_NUMERATOR; + mgr->overhead.denom = ROT_OVERHEAD_DENOMINATOR; + + mutex_init(&mgr->lock); + atomic_set(&mgr->device_suspended, 0); + INIT_LIST_HEAD(&mgr->file_list); + + ret = sysfs_create_group(&mgr->device->kobj, + &sde_rotator_fs_attr_group); + if (ret) { + SDEROT_ERR("unable to register rotator sysfs nodes\n"); + goto error_create_sysfs; + } + + ret = sde_rotator_parse_dt(mgr, pdev); + if (ret) { + SDEROT_ERR("fail to parse the dt\n"); + goto error_parse_dt; + } + + ret = sde_rotator_res_init(pdev, mgr); + if (ret) { + SDEROT_ERR("res_init failed %d\n", ret); + goto error_res_init; + } + + *pmgr = mgr; + ret = sde_rotator_footswitch_ctrl(mgr, true); + if (ret) { + SDEROT_INFO("res_init failed %d, use probe defer\n", ret); + ret = -EPROBE_DEFER; + goto error_fs_en_fail; + } + + /* enable power and clock before h/w initialization/query */ + sde_rotator_update_clk(mgr); + sde_rotator_resource_ctrl(mgr, true); + sde_rotator_clk_ctrl(mgr, true); + + mdata->mdss_version = SDE_REG_READ(mdata, SDE_REG_HW_VERSION); + SDEROT_DBG("mdss revision %x\n", mdata->mdss_version); + + if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_107)) { + mgr->ops_hw_init = sde_rotator_r1_init; + } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_300) || + IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_400) || + IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_410) || + IS_SDE_MAJOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_500) || + IS_SDE_MAJOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_600)) { + mgr->ops_hw_init = sde_rotator_r3_init; + mgr->min_rot_clk = ROT_MIN_ROT_CLK; + + /* + * on platforms where the maxlinewidth is greater than + * default we need to have a max clock rate check to + * ensure we do not cross the max allowed clock for rotator + */ + if (IS_SDE_MAJOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_500)) + mgr->max_rot_clk = ROT_R3_MAX_ROT_CLK; + + if (!IS_SDE_MAJOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_600) && + !sde_rotator_get_clk(mgr, + SDE_ROTATOR_CLK_MDSS_AXI)) { + SDEROT_ERR("unable to get mdss_axi_clk\n"); + ret = -EINVAL; + goto error_map_hw_ops; + } + } else { + ret = -ENODEV; + SDEROT_ERR("unsupported sde version %x\n", + mdata->mdss_version); + goto error_map_hw_ops; + } + + ret = mgr->ops_hw_init(mgr); + if (ret) { + SDEROT_ERR("hw init failed %d\n", ret); + goto error_hw_init; + } + + sde_rotator_pm_qos_add(mdata); + + ret = sde_rotator_init_queue(mgr); + if (ret) { + SDEROT_ERR("fail to init queue\n"); + goto error_init_queue; + } + + /* disable power and clock after h/w initialization/query */ + sde_rotator_clk_ctrl(mgr, false); + sde_rotator_resource_ctrl(mgr, false); + sde_rotator_footswitch_ctrl(mgr, false); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return 0; + +error_init_queue: + mgr->ops_hw_destroy(mgr); +error_hw_init: +error_map_hw_ops: + sde_rotator_clk_ctrl(mgr, false); + sde_rotator_resource_ctrl(mgr, false); + sde_rotator_footswitch_ctrl(mgr, false); +error_fs_en_fail: + sde_rotator_res_destroy(mgr); +error_res_init: +error_parse_dt: + sysfs_remove_group(&mgr->device->kobj, &sde_rotator_fs_attr_group); +error_create_sysfs: + devm_kfree(&pdev->dev, mgr); + *pmgr = NULL; + return ret; +} + +void sde_rotator_core_destroy(struct sde_rot_mgr *mgr) +{ + struct device *dev; + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return; + } + + dev = mgr->device; + sde_rotator_deinit_queue(mgr); + mgr->ops_hw_destroy(mgr); + sde_rotator_release_all(mgr); + pm_runtime_disable(mgr->device); + sde_rotator_res_destroy(mgr); + sysfs_remove_group(&mgr->device->kobj, &sde_rotator_fs_attr_group); + devm_kfree(dev, mgr); +} + +void sde_rotator_core_dump(struct sde_rot_mgr *mgr) +{ + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return; + } + + sde_rotator_resource_ctrl(mgr, true); + + if (mgr->ops_hw_dump_status) + mgr->ops_hw_dump_status(mgr); + + SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus", "vbif_dbg_bus"); + + sde_rotator_resource_ctrl(mgr, false); +} + +static void sde_rotator_suspend_cancel_rot_work(struct sde_rot_mgr *mgr) +{ + struct sde_rot_file_private *priv, *priv_next; + + list_for_each_entry_safe(priv, priv_next, &mgr->file_list, list) { + sde_rotator_cancel_all_requests(mgr, priv); + } +} + +#if defined(CONFIG_PM) +/* + * sde_rotator_runtime_suspend - Turn off power upon runtime suspend event + * @dev: Pointer to device structure + */ +int sde_rotator_runtime_suspend(struct device *dev) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_device(dev); + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return -ENODEV; + } + + if (mgr->rot_enable_clk_cnt) { + SDEROT_ERR("invalid runtime suspend request %d\n", + mgr->rot_enable_clk_cnt); + return -EBUSY; + } + + sde_rotator_footswitch_ctrl(mgr, false); + ATRACE_END("runtime_active"); + SDEROT_DBG("exit runtime_active\n"); + return 0; +} + +/* + * sde_rotator_runtime_resume - Turn on power upon runtime resume event + * @dev: Pointer to device structure + */ +int sde_rotator_runtime_resume(struct device *dev) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_device(dev); + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return -ENODEV; + } + + SDEROT_DBG("begin runtime_active\n"); + ATRACE_BEGIN("runtime_active"); + return sde_rotator_footswitch_ctrl(mgr, true); +} + +/* + * sde_rotator_runtime_idle - check if device is idling + * @dev: Pointer to device structure + */ +int sde_rotator_runtime_idle(struct device *dev) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_device(dev); + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return -ENODEV; + } + + /* add check for any busy status, if any */ + SDEROT_DBG("idling ...\n"); + return 0; +} + +#endif + +#ifdef CONFIG_PM_SLEEP +/* + * sde_rotator_pm_suspend - put the device in pm suspend state by cancelling + * all active requests + * @dev: Pointer to device structure + */ +int sde_rotator_pm_suspend(struct device *dev) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_device(dev); + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return -ENODEV; + } + + + sde_rot_mgr_lock(mgr); + atomic_inc(&mgr->device_suspended); + sde_rotator_suspend_cancel_rot_work(mgr); + mgr->minimum_bw_vote = 0; + sde_rotator_update_perf(mgr); + ATRACE_END("pm_active"); + SDEROT_DBG("end pm active %d\n", atomic_read(&mgr->device_suspended)); + sde_rot_mgr_unlock(mgr); + return 0; +} + +/* + * sde_rotator_pm_resume - put the device in pm active state + * @dev: Pointer to device structure + */ +int sde_rotator_pm_resume(struct device *dev) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_device(dev); + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return -ENODEV; + } + + /* + * It is possible that the runtime status of the device may + * have been active when the system was suspended. Reset the runtime + * status to suspended state after a complete system resume. + */ + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + sde_rot_mgr_lock(mgr); + SDEROT_DBG("begin pm active %d\n", atomic_read(&mgr->device_suspended)); + ATRACE_BEGIN("pm_active"); + atomic_dec(&mgr->device_suspended); + sde_rotator_update_perf(mgr); + sde_rot_mgr_unlock(mgr); + return 0; +} +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP) +int sde_rotator_suspend(struct platform_device *dev, pm_message_t state) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_pdevice(dev); + + if (!mgr) { + SDEROT_ERR("null_parameters\n"); + return -ENODEV; + } + + sde_rot_mgr_lock(mgr); + atomic_inc(&mgr->device_suspended); + sde_rotator_suspend_cancel_rot_work(mgr); + sde_rotator_update_perf(mgr); + sde_rot_mgr_unlock(mgr); + return 0; +} + +int sde_rotator_resume(struct platform_device *dev) +{ + struct sde_rot_mgr *mgr; + + mgr = sde_rot_mgr_from_pdevice(dev); + + if (!mgr) { + SDEROT_ERR("null parameters\n"); + return -ENODEV; + } + + sde_rot_mgr_lock(mgr); + atomic_dec(&mgr->device_suspended); + sde_rotator_update_perf(mgr); + sde_rot_mgr_unlock(mgr); + return 0; +} +#endif + +/* + * sde_rotator_session_open - external wrapper for open function + * + * Note each file open (sde_rot_file_private) is mapped to one session only. + */ +int sde_rotator_session_open(struct sde_rot_mgr *mgr, + struct sde_rot_file_private **pprivate, int session_id, + struct sde_rot_queue_v1 *queue) +{ + int ret; + struct sde_rot_file_private *private; + + if (!mgr || !pprivate || !queue) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + ret = sde_rotator_open(mgr, &private); + if (ret) + goto error_open; + + private->mgr = mgr; + private->fenceq = queue; + + ret = sde_rotator_open_session(mgr, private, session_id); + if (ret) + goto error_open_session; + + *pprivate = private; + + return 0; +error_open_session: + sde_rotator_close(mgr, private); +error_open: + return ret; +} + +/* + * sde_rotator_session_close - external wrapper for close function + */ +void sde_rotator_session_close(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, int session_id) +{ + if (!mgr || !private) { + SDEROT_ERR("null parameters\n"); + return; + } + + sde_rotator_close_session(mgr, private, session_id); + sde_rotator_close(mgr, private); + + SDEROT_DBG("session closed s:%d\n", session_id); +} + +/* + * sde_rotator_session_config - external wrapper for config function + */ +int sde_rotator_session_config(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rotation_config *config) +{ + if (!mgr || !private || !config) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + return sde_rotator_config_session(mgr, private, config); +} + +/* + * sde_rotator_session_validate - validate session + */ +int sde_rotator_session_validate(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rotation_config *config) +{ + int ret; + + if (!mgr || !private || !config) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + SDEROT_DBG( + "validate session id=%u in{%u,%u}f:%x out{%u,%u}f:%x fps:%d\n", + config->session_id, config->input.width, config->input.height, + config->input.format, config->output.width, + config->output.height, config->output.format, + config->frame_rate); + + ret = sde_rotator_verify_config_all(mgr, config); + if (ret) { + SDEROT_WARN("rotator verify format failed %d\n", ret); + return ret; + } + + if (config->output.sbuf && mgr->sbuf_ctx != private && mgr->sbuf_ctx) { + SDEROT_WARN("too many sbuf sessions\n"); + return -EBUSY; + } + + return 0; +} diff --git a/techpack/display/rotator/sde_rotator_core.h b/techpack/display/rotator/sde_rotator_core.h new file mode 100644 index 0000000000000000000000000000000000000000..f9ce3350dc97a13d2b61d0912f71529bb87ef1d0 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_core.h @@ -0,0 +1,848 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_ROTATOR_CORE_H +#define SDE_ROTATOR_CORE_H + +#include <linux/list.h> +#include <linux/file.h> +#include <linux/ktime.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/cdev.h> +#include <linux/pm_runtime.h> +#include <linux/kthread.h> + +#include "sde_rotator_base.h" +#include "sde_rotator_util.h" +#include "sde_rotator_sync.h" + +/********************************************************************** + * Rotation request flag + **********************************************************************/ +/* no rotation flag */ +#define SDE_ROTATION_NOP 0x01 + +/* left/right flip */ +#define SDE_ROTATION_FLIP_LR 0x02 + +/* up/down flip */ +#define SDE_ROTATION_FLIP_UD 0x04 + +/* rotate 90 degree */ +#define SDE_ROTATION_90 0x08 + +/* rotate 180 degre */ +#define SDE_ROTATION_180 (SDE_ROTATION_FLIP_LR | SDE_ROTATION_FLIP_UD) + +/* rotate 270 degree */ +#define SDE_ROTATION_270 (SDE_ROTATION_90 | SDE_ROTATION_180) + +/* format is interlaced */ +#define SDE_ROTATION_DEINTERLACE 0x10 + +/* secure data */ +#define SDE_ROTATION_SECURE 0x80 + +/* verify input configuration only */ +#define SDE_ROTATION_VERIFY_INPUT_ONLY 0x10000 + +/* use client provided dma buf instead of ion fd */ +#define SDE_ROTATION_EXT_DMA_BUF 0x20000 + +/* secure camera operation*/ +#define SDE_ROTATION_SECURE_CAMERA 0x40000 + +/* use client mapped i/o virtual address */ +#define SDE_ROTATION_EXT_IOVA 0x80000 + +/* use client provided clock/bandwidth parameters */ +#define SDE_ROTATION_EXT_PERF 0x100000 + +/********************************************************************** + * configuration structures + **********************************************************************/ + +/* + * struct sde_rotation_buf_info - input/output buffer configuration + * @width: width of buffer region to be processed + * @height: height of buffer region to be processed + * @format: pixel format of buffer + * @comp_ratio: compression ratio for the session + * @sbuf: true if buffer is streaming buffer + */ +struct sde_rotation_buf_info { + uint32_t width; + uint32_t height; + uint32_t format; + struct sde_mult_factor comp_ratio; + bool sbuf; +}; + +/* + * struct sde_rotation_config - rotation configuration for given session + * @session_id: identifier of the given session + * @input: input buffer information + * @output: output buffer information + * @frame_rate: session frame rate in fps + * @clk_rate: requested rotator clock rate if SDE_ROTATION_EXT_PERF is set + * @data_bw: requested data bus bandwidth if SDE_ROTATION_EXT_PERF is set + * @flags: configuration flags, e.g. rotation angle, flip, etc... + */ +struct sde_rotation_config { + uint32_t session_id; + struct sde_rotation_buf_info input; + struct sde_rotation_buf_info output; + uint32_t frame_rate; + uint64_t clk_rate; + uint64_t data_bw; + uint32_t flags; +}; + +enum sde_rotator_ts { + SDE_ROTATOR_TS_SRCQB, /* enqueue source buffer */ + SDE_ROTATOR_TS_DSTQB, /* enqueue destination buffer */ + SDE_ROTATOR_TS_FENCE, /* wait for source buffer fence */ + SDE_ROTATOR_TS_QUEUE, /* wait for h/w resource */ + SDE_ROTATOR_TS_COMMIT, /* prepare h/w command */ + SDE_ROTATOR_TS_START, /* wait for h/w kickoff rdy (inline) */ + SDE_ROTATOR_TS_FLUSH, /* initiate h/w processing */ + SDE_ROTATOR_TS_DONE, /* receive h/w completion */ + SDE_ROTATOR_TS_RETIRE, /* signal destination buffer fence */ + SDE_ROTATOR_TS_SRCDQB, /* dequeue source buffer */ + SDE_ROTATOR_TS_DSTDQB, /* dequeue destination buffer */ + SDE_ROTATOR_TS_MAX +}; + +enum sde_rotator_clk_type { + SDE_ROTATOR_CLK_MDSS_AHB, + SDE_ROTATOR_CLK_MDSS_AXI, + SDE_ROTATOR_CLK_MDSS_ROT_SUB, + SDE_ROTATOR_CLK_MDSS_ROT, + SDE_ROTATOR_CLK_MNOC_AHB, + SDE_ROTATOR_CLK_GCC_AHB, + SDE_ROTATOR_CLK_GCC_AXI, + SDE_ROTATOR_CLK_MAX +}; + +enum sde_rotator_trigger { + SDE_ROTATOR_TRIGGER_IMMEDIATE, + SDE_ROTATOR_TRIGGER_VIDEO, + SDE_ROTATOR_TRIGGER_COMMAND, +}; + +enum sde_rotator_mode { + SDE_ROTATOR_MODE_OFFLINE, + SDE_ROTATOR_MODE_SBUF, + SDE_ROTATOR_MODE_MAX, +}; + +struct sde_rotation_item { + /* rotation request flag */ + uint32_t flags; + + /* rotation trigger mode */ + uint32_t trigger; + + /* prefill bandwidth in Bps */ + uint64_t prefill_bw; + + /* Source crop rectangle */ + struct sde_rect src_rect; + + /* Destination rectangle */ + struct sde_rect dst_rect; + + /* Input buffer for the request */ + struct sde_layer_buffer input; + + /* The output buffer for the request */ + struct sde_layer_buffer output; + + /* + * DMA pipe selection for this request by client: + * 0: DMA pipe 0 + * 1: DMA pipe 1 + * or SDE_ROTATION_HW_ANY if client wants + * driver to allocate any that is available + * + * OR + * + * Reserved + */ + uint32_t pipe_idx; + + /* + * Write-back block selection for this request by client: + * 0: Write-back block 0 + * 1: Write-back block 1 + * or SDE_ROTATION_HW_ANY if client wants + * driver to allocate any that is available + * + * OR + * + * Priority selection for this request by client: + * 0: Highest + * 1..n: Limited by the lowest available priority + */ + uint32_t wb_idx; + + /* + * Sequence ID of this request within the session + */ + uint32_t sequence_id; + + /* Which session ID is this request scheduled on */ + uint32_t session_id; + + /* Time stamp for profiling purposes */ + ktime_t *ts; + + /* Completion structure for inline rotation */ + struct completion inline_start; +}; + +/* + * Defining characteristics about rotation work, that has corresponding + * fmt and roi checks in open session + */ +#define SDE_ROT_DEFINING_FLAG_BITS SDE_ROTATION_90 + +struct sde_rot_entry; +struct sde_rot_perf; + +struct sde_rot_clk { + struct clk *clk; + char clk_name[32]; + unsigned long rate; +}; + +struct sde_rot_hw_resource { + u32 wb_id; + u32 pending_count; + atomic_t num_active; + int max_active; + wait_queue_head_t wait_queue; +}; + +struct sde_rot_queue { + struct kthread_worker rot_kw; + struct task_struct *rot_thread; + struct sde_rot_timeline *timeline; + struct sde_rot_hw_resource *hw; +}; + +struct sde_rot_queue_v1 { + struct kthread_worker *rot_kw; + struct task_struct *rot_thread; + struct sde_rot_timeline *timeline; + struct sde_rot_hw_resource *hw; +}; +/* + * struct sde_rot_entry_container - rotation request + * @list: list of active requests managed by rotator manager + * @flags: reserved + * @count: size of rotation entries + * @pending_count: count of entries pending completion + * @failed_count: count of entries failed completion + * @finished: true if client is finished with the request + * @retireq: workqueue to post completion notification + * @retire_work: work for completion notification + * @entries: array of rotation entries + */ +struct sde_rot_entry_container { + struct list_head list; + u32 flags; + u32 count; + atomic_t pending_count; + atomic_t failed_count; + struct kthread_worker *retire_kw; + struct kthread_work *retire_work; + bool finished; + struct sde_rot_entry *entries; +}; + +struct sde_rot_mgr; +struct sde_rot_file_private; + +/* + * struct sde_rot_entry - rotation entry + * @item: rotation item + * @commit_work: work descriptor for commit handler + * @done_work: work descriptor for done handler + * @commitq: pointer to commit handler rotator queue + * @fenceq: pointer to fence signaling rotator queue + * @doneq: pointer to done handler rotator queue + * @request: pointer to containing request + * @src_buf: descriptor of source buffer + * @dst_buf: descriptor of destination buffer + * @input_fence: pointer to input fence for when input content is available + * @output_fence: pointer to output fence for when output content is available + * @output_signaled: true if output fence of this entry has been signaled + * @dnsc_factor_w: calculated width downscale factor for this entry + * @dnsc_factor_w: calculated height downscale factor for this entry + * @perf: pointer to performance configuration associated with this entry + * @work_assigned: true if this item is assigned to h/w queue/unit + * @private: pointer to controlling session context + */ +struct sde_rot_entry { + struct sde_rotation_item item; + struct kthread_work commit_work; + struct kthread_work done_work; + struct sde_rot_queue *commitq; + struct sde_rot_queue_v1 *fenceq; + struct sde_rot_queue *doneq; + struct sde_rot_entry_container *request; + + struct sde_mdp_data src_buf; + struct sde_mdp_data dst_buf; + + struct sde_rot_sync_fence *input_fence; + + struct sde_rot_sync_fence *output_fence; + bool output_signaled; + + u32 dnsc_factor_w; + u32 dnsc_factor_h; + + struct sde_rot_perf *perf; + bool work_assigned; /* Used when cleaning up work_distribution */ + struct sde_rot_file_private *private; +}; + +/* + * struct sde_rot_trace_entry - structure used to pass info to trace + */ +struct sde_rot_trace_entry { + u32 wb_idx; + u32 flags; + u32 input_format; + u32 input_width; + u32 input_height; + u32 src_x; + u32 src_y; + u32 src_w; + u32 src_h; + u32 output_format; + u32 output_width; + u32 output_height; + u32 dst_x; + u32 dst_y; + u32 dst_w; + u32 dst_h; +}; + +/* + * struct sde_rot_perf - rotator session performance configuration + * @list: list of performance configuration under one session + * @config: current rotation configuration + * @clk_rate: current clock rate in Hz + * @bw: current bandwidth in byte per second + * @work_dis_lock: serialization lock for updating work distribution (not used) + * @work_distribution: work distribution among multiple hardware queue/unit + * @last_wb_idx: last queue/unit index, used to account for pre-distributed work + * @rdot_limit: read OT limit of this session + * @wrot_limit: write OT limit of this session + */ +struct sde_rot_perf { + struct list_head list; + struct sde_rotation_config config; + unsigned long clk_rate; + u64 bw; + struct mutex work_dis_lock; + u32 *work_distribution; + int last_wb_idx; /* last known wb index, used when above count is 0 */ + u32 rdot_limit; + u32 wrot_limit; +}; + +/* + * struct sde_rot_file_private - rotator manager per session context + * @list: list of all session context + * @req_list: list of rotation request for this session + * @perf_list: list of performance configuration for this session (only one) + * @mgr: pointer to the controlling rotator manager + * @fenceq: pointer to rotator queue to signal when entry is done + */ +struct sde_rot_file_private { + struct list_head list; + struct list_head req_list; + struct list_head perf_list; + struct sde_rot_mgr *mgr; + struct sde_rot_queue_v1 *fenceq; +}; + +/* + * struct sde_rot_bus_data_type - rotator bus scaling configuration + * @bus_cale_pdata: pointer to bus scaling configuration table + * @bus_hdl: msm bus scaling handle + * @curr_bw_uc_idx; current usecase index into configuration table + * @curr_quota_val: current bandwidth request in byte per second + */ +struct sde_rot_bus_data_type { + struct msm_bus_scale_pdata *bus_scale_pdata; + u32 bus_hdl; + u32 curr_bw_uc_idx; + u64 curr_quota_val; +}; + +/* + * struct sde_rot_mgr - core rotator manager + * @lock: serialization lock to rotator manager functions + * @device_suspended: 0 if device is not suspended; non-zero suspended + * @pdev: pointer to controlling platform device + * @device: pointer to controlling device + * @queue_count: number of hardware queue/unit available + * @commitq: array of rotator commit queue corresponding to hardware queue + * @doneq: array of rotator done queue corresponding to hardware queue + * @file_list: list of all sessions managed by rotator manager + * @pending_close_bw_vote: bandwidth of closed sessions with pending work + * @minimum_bw_vote: minimum bandwidth required for current use case + * @enable_bw_vote: minimum bandwidth required for power enable + * @data_bus: data bus configuration state + * @reg_bus: register bus configuration state + * @module_power: power/clock configuration state + * @regulator_enable: true if foot switch is enabled; false otherwise + * @res_ref_cnt: reference count of how many times resource is requested + * @rot_enable_clk_cnt: reference count of how many times clock is requested + * @rot_clk: array of rotator and periphery clocks + * @num_rot_clk: size of the rotator clock array + * @rdot_limit: current read OT limit + * @wrot_limit: current write OT limit + * @hwacquire_timeout: maximum wait time for hardware availability in msec + * @pixel_per_clk: rotator hardware performance in pixel for clock + * @fudge_factor: fudge factor for clock calculation + * @overhead: software overhead for offline rotation in msec + * @min_rot_clk: minimum rotator clock rate + * @max_rot_clk: maximum allowed rotator clock rate + * @sbuf_ctx: pointer to sbuf session context + * @ops_xxx: function pointers of rotator HAL layer + * @hw_data: private handle of rotator HAL layer + */ +struct sde_rot_mgr { + struct mutex lock; + atomic_t device_suspended; + struct platform_device *pdev; + struct device *device; + + /* + * Managing rotation queues, depends on + * how many hw pipes available on the system + */ + int queue_count; + struct sde_rot_queue *commitq; + struct sde_rot_queue *doneq; + + /* + * managing all the open file sessions to bw calculations, + * and resource clean up during suspend + */ + struct list_head file_list; + + u64 pending_close_bw_vote; + u64 minimum_bw_vote; + u64 enable_bw_vote; + struct sde_rot_bus_data_type data_bus; + struct sde_rot_bus_data_type reg_bus; + + /* Module power is only used for regulator management */ + struct sde_module_power module_power; + bool regulator_enable; + + int res_ref_cnt; + int rot_enable_clk_cnt; + struct sde_rot_clk *rot_clk; + int num_rot_clk; + u32 rdot_limit; + u32 wrot_limit; + + u32 hwacquire_timeout; + struct sde_mult_factor pixel_per_clk; + struct sde_mult_factor fudge_factor; + struct sde_mult_factor overhead; + unsigned long min_rot_clk; + unsigned long max_rot_clk; + + struct sde_rot_file_private *sbuf_ctx; + + int (*ops_config_hw)(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry); + int (*ops_cancel_hw)(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry); + int (*ops_abort_hw)(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry); + int (*ops_kickoff_entry)(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry); + int (*ops_wait_for_entry)(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry); + struct sde_rot_hw_resource *(*ops_hw_alloc)(struct sde_rot_mgr *mgr, + u32 pipe_id, u32 wb_id); + void (*ops_hw_free)(struct sde_rot_mgr *mgr, + struct sde_rot_hw_resource *hw); + int (*ops_hw_init)(struct sde_rot_mgr *mgr); + void (*ops_hw_pre_pmevent)(struct sde_rot_mgr *mgr, bool pmon); + void (*ops_hw_post_pmevent)(struct sde_rot_mgr *mgr, bool pmon); + void (*ops_hw_destroy)(struct sde_rot_mgr *mgr); + ssize_t (*ops_hw_show_caps)(struct sde_rot_mgr *mgr, + struct device_attribute *attr, char *buf, ssize_t len); + ssize_t (*ops_hw_show_state)(struct sde_rot_mgr *mgr, + struct device_attribute *attr, char *buf, ssize_t len); + int (*ops_hw_create_debugfs)(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root); + int (*ops_hw_validate_entry)(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry); + u32 (*ops_hw_get_pixfmt)(struct sde_rot_mgr *mgr, int index, + bool input, u32 mode); + int (*ops_hw_is_valid_pixfmt)(struct sde_rot_mgr *mgr, u32 pixfmt, + bool input, u32 mode); + int (*ops_hw_get_downscale_caps)(struct sde_rot_mgr *mgr, char *caps, + int len); + int (*ops_hw_get_maxlinewidth)(struct sde_rot_mgr *mgr); + void (*ops_hw_dump_status)(struct sde_rot_mgr *mgr); + + void *hw_data; +}; + +static inline int sde_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, + u32 pixfmt, bool input, u32 mode) +{ + if (mgr && mgr->ops_hw_is_valid_pixfmt) + return mgr->ops_hw_is_valid_pixfmt(mgr, pixfmt, input, mode); + + return false; +} + +static inline u32 sde_rotator_get_pixfmt(struct sde_rot_mgr *mgr, + int index, bool input, u32 mode) +{ + if (mgr && mgr->ops_hw_get_pixfmt) + return mgr->ops_hw_get_pixfmt(mgr, index, input, mode); + + return 0; +} + +static inline int sde_rotator_get_downscale_caps(struct sde_rot_mgr *mgr, + char *caps, int len) +{ + if (mgr && mgr->ops_hw_get_downscale_caps) + return mgr->ops_hw_get_downscale_caps(mgr, caps, len); + + return 0; +} + +static inline int sde_rotator_get_maxlinewidth(struct sde_rot_mgr *mgr) +{ + if (mgr && mgr->ops_hw_get_maxlinewidth) + return mgr->ops_hw_get_maxlinewidth(mgr); + + return 2048; +} + +static inline int __compare_session_item_rect( + struct sde_rotation_buf_info *s_rect, + struct sde_rect *i_rect, uint32_t i_fmt, bool src) +{ + if ((s_rect->width != i_rect->w) || (s_rect->height != i_rect->h) || + (s_rect->format != i_fmt)) { + SDEROT_DBG( + "%s: session{%u,%u}f:%u mismatch from item{%u,%u}f:%u\n", + (src ? "src":"dst"), s_rect->width, s_rect->height, + s_rect->format, i_rect->w, i_rect->h, i_fmt); + return -EINVAL; + } + return 0; +} + +/* + * Compare all important flag bits associated with rotation between session + * config and item request. Format and roi validation is done during open + * session and is based certain defining bits. If these defining bits are + * different in item request, there is a possibility that rotation item + * is not a valid configuration. + */ +static inline int __compare_session_rotations(uint32_t cfg_flag, + uint32_t item_flag) +{ + cfg_flag &= SDE_ROT_DEFINING_FLAG_BITS; + item_flag &= SDE_ROT_DEFINING_FLAG_BITS; + if (cfg_flag != item_flag) { + SDEROT_DBG( + "Rotation degree request different from open session\n"); + return -EINVAL; + } + return 0; +} + +/* + * sde_rotator_core_init - initialize rotator manager for the given platform + * device + * @pmgr: Pointer to pointer of the newly initialized rotator manager + * @pdev: Pointer to platform device + * return: 0 if success; error code otherwise + */ +int sde_rotator_core_init(struct sde_rot_mgr **pmgr, + struct platform_device *pdev); + +/* + * sde_rotator_core_destroy - destroy given rotator manager + * @mgr: Pointer to rotator manager + * return: none + */ +void sde_rotator_core_destroy(struct sde_rot_mgr *mgr); + +/* + * sde_rotator_core_dump - perform register dump + * @mgr: Pointer to rotator manager + */ +void sde_rotator_core_dump(struct sde_rot_mgr *mgr); + +/* + * sde_rotator_session_open - open a new rotator per file session + * @mgr: Pointer to rotator manager + * @pprivate: Pointer to pointer of the newly initialized per file session + * @session_id: identifier of the newly created session + * @queue: Pointer to fence queue of the new session + * return: 0 if success; error code otherwise + */ +int sde_rotator_session_open(struct sde_rot_mgr *mgr, + struct sde_rot_file_private **pprivate, int session_id, + struct sde_rot_queue_v1 *queue); + +/* + * sde_rotator_session_close - close the given rotator per file session + * @mgr: Pointer to rotator manager + * @private: Pointer to per file session + * @session_id: identifier of the session + * return: none + */ +void sde_rotator_session_close(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, int session_id); + +/* + * sde_rotator_session_config - configure the given rotator per file session + * @mgr: Pointer to rotator manager + * @private: Pointer to per file session + * @config: Pointer to rotator configuration + * return: 0 if success; error code otherwise + */ +int sde_rotator_session_config(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rotation_config *config); + +/* + * sde_rotator_session_validate - validate session configuration + * @mgr: Pointer to rotator manager + * @private: Pointer to per file session + * @config: Pointer to rotator configuration + * return: 0 if success; error code otherwise + */ +int sde_rotator_session_validate(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rotation_config *config); + +/* + * sde_rotator_req_init - allocate a new request and initialzie with given + * array of rotation items + * @rot_dev: Pointer to rotator device + * @private: Pointer to rotator manager per file context + * @items: Pointer to array of rotation item + * @count: size of rotation item array + * @flags: rotation request flags + * return: Pointer to new rotation request if success; ERR_PTR otherwise + */ +struct sde_rot_entry_container *sde_rotator_req_init( + struct sde_rot_mgr *rot_dev, + struct sde_rot_file_private *private, + struct sde_rotation_item *items, + u32 count, u32 flags); + +/* + * sde_rotator_req_reset_start - reset inline h/w 'start' indicator + * For inline rotations, the time of rotation start is not controlled + * by the rotator driver. This function resets an internal 'start' + * indicator that allows the rotator to delay its rotator + * timeout waiting until such time as the inline rotation has + * really started. + * @mgr: Pointer to rotator manager + * @req: Pointer to rotation request + */ +void sde_rotator_req_reset_start(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_req_set_start - set inline h/w 'start' indicator + * @mgr: Pointer to rotator manager + * @req: Pointer to rotation request + */ +void sde_rotator_req_set_start(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_req_wait_start - wait for inline h/w 'start' indicator + * @mgr: Pointer to rotator manager + * @req: Pointer to rotation request + * return: Zero on success + */ +int sde_rotator_req_wait_start(struct sde_rot_mgr *mgr, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_req_finish - notify manager that client is finished with the + * given request and manager can release the request as required + * @mgr: Pointer to rotator manager + * @private: Pointer to rotator manager per file context + * @req: Pointer to rotation request + * return: none + */ +void sde_rotator_req_finish(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_abort_inline_request - abort inline rotation request after start + * This function allows inline rotation requests to be aborted after + * sde_rotator_req_set_start has already been issued. + * @mgr: Pointer to rotator manager + * @private: Pointer to rotator manager per file context + * @req: Pointer to rotation request + * return: none + */ +void sde_rotator_abort_inline_request(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_handle_request_common - add the given request to rotator + * manager and clean up completed requests + * @rot_dev: Pointer to rotator device + * @private: Pointer to rotator manager per file context + * @req: Pointer to rotation request + * return: 0 if success; error code otherwise + */ +int sde_rotator_handle_request_common(struct sde_rot_mgr *rot_dev, + struct sde_rot_file_private *ctx, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_queue_request - queue/schedule the given request for h/w commit + * @rot_dev: Pointer to rotator device + * @private: Pointer to rotator manager per file context + * @req: Pointer to rotation request + * return: 0 if success; error code otherwise + */ +void sde_rotator_queue_request(struct sde_rot_mgr *rot_dev, + struct sde_rot_file_private *ctx, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_verify_config_all - verify given rotation configuration + * @rot_dev: Pointer to rotator device + * @config: Pointer to rotator configuration + * return: 0 if success; error code otherwise + */ +int sde_rotator_verify_config_all(struct sde_rot_mgr *rot_dev, + struct sde_rotation_config *config); + +/* + * sde_rotator_verify_config_input - verify rotation input configuration + * @rot_dev: Pointer to rotator device + * @config: Pointer to rotator configuration + * return: 0 if success; error code otherwise + */ +int sde_rotator_verify_config_input(struct sde_rot_mgr *rot_dev, + struct sde_rotation_config *config); + +/* + * sde_rotator_verify_config_output - verify rotation output configuration + * @rot_dev: Pointer to rotator device + * @config: Pointer to rotator configuration + * return: 0 if success; error code otherwise + */ +int sde_rotator_verify_config_output(struct sde_rot_mgr *rot_dev, + struct sde_rotation_config *config); + +/* + * sde_rotator_validate_request - validates given rotation request with + * previous rotator configuration + * @rot_dev: Pointer to rotator device + * @private: Pointer to rotator manager per file context + * @req: Pointer to rotation request + * return: 0 if success; error code otherwise + */ +int sde_rotator_validate_request(struct sde_rot_mgr *rot_dev, + struct sde_rot_file_private *ctx, + struct sde_rot_entry_container *req); + +/* + * sde_rotator_clk_ctrl - enable/disable rotator clock with reference counting + * @mgr: Pointer to rotator manager + * @enable: true to enable clock; false to disable clock + * return: 0 if success; error code otherwise + */ +int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable); + +/* sde_rotator_resource_ctrl_enabled - check if resource control is enabled + * @mgr: Pointer to rotator manager + * Return: true if enabled; false otherwise + */ +static inline int sde_rotator_resource_ctrl_enabled(struct sde_rot_mgr *mgr) +{ + return mgr->regulator_enable; +} + +/* + * sde_rotator_cancel_all_requests - cancel all outstanding requests + * @mgr: Pointer to rotator manager + * @private: Pointer to rotator manager per file context + */ +void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr, + struct sde_rot_file_private *private); + +/* + * sde_rot_mgr_lock - serialization lock prior to rotator manager calls + * @mgr: Pointer to rotator manager + */ +static inline void sde_rot_mgr_lock(struct sde_rot_mgr *mgr) +{ + mutex_lock(&mgr->lock); +} + +/* + * sde_rot_mgr_lock - serialization unlock after rotator manager calls + * @mgr: Pointer to rotator manager + */ +static inline void sde_rot_mgr_unlock(struct sde_rot_mgr *mgr) +{ + mutex_unlock(&mgr->lock); +} + +/* + * sde_rot_mgr_pd_enabled - return true if power domain is enabled + * @mgr: Pointer to rotator manager + */ +static inline bool sde_rot_mgr_pd_enabled(struct sde_rot_mgr *mgr) +{ + return mgr && mgr->device && mgr->device->pm_domain; +} + +#if defined(CONFIG_PM) +int sde_rotator_runtime_resume(struct device *dev); +int sde_rotator_runtime_suspend(struct device *dev); +int sde_rotator_runtime_idle(struct device *dev); +#endif + +#if defined(CONFIG_PM_SLEEP) +int sde_rotator_pm_suspend(struct device *dev); +int sde_rotator_pm_resume(struct device *dev); +#endif + +#if defined(CONFIG_PM) && !defined(CONFIG_PM_SLEEP) +int sde_rotator_suspend(struct platform_device *dev, pm_message_t state); +int sde_rotator_resume(struct platform_device *dev); +#else +#define sde_rotator_suspend NULL +#define sde_rotator_resume NULL +#endif +#endif /* __SDE_ROTATOR_CORE_H__ */ diff --git a/techpack/display/rotator/sde_rotator_debug.c b/techpack/display/rotator/sde_rotator_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..0ef5192bc84497f904679bf5b5d0147ae417ab19 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_debug.c @@ -0,0 +1,1363 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> + +#include "sde_rotator_debug.h" +#include "sde_rotator_base.h" +#include "sde_rotator_core.h" +#include "sde_rotator_dev.h" +#include "sde_rotator_trace.h" + +#ifdef CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG +#define SDE_EVTLOG_DEFAULT_ENABLE 1 +#else +#define SDE_EVTLOG_DEFAULT_ENABLE 0 +#endif +#define SDE_EVTLOG_DEFAULT_PANIC 1 +#define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_MEM +#define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM +#define SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM + +/* + * evtlog will print this number of entries when it is called through + * sysfs node or panic. This prevents kernel log from evtlog message + * flood. + */ +#define SDE_ROT_EVTLOG_PRINT_ENTRY 256 + +/* + * evtlog keeps this number of entries in memory for debug purpose. This + * number must be greater than print entry to prevent out of bound evtlog + * entry array access. + */ +#define SDE_ROT_EVTLOG_ENTRY (SDE_ROT_EVTLOG_PRINT_ENTRY * 4) +#define SDE_ROT_EVTLOG_MAX_DATA 15 +#define SDE_ROT_EVTLOG_BUF_MAX 512 +#define SDE_ROT_EVTLOG_BUF_ALIGN 32 +#define SDE_ROT_DEBUG_BASE_MAX 10 + +#define SDE_ROT_DEFAULT_BASE_REG_CNT 0x100 +#define GROUP_BYTES 4 +#define ROW_BYTES 16 + +#define SDE_ROT_TEST_MASK(id, tp) ((id << 4) | (tp << 1) | BIT(0)) + +static DEFINE_SPINLOCK(sde_rot_xlock); + +/* + * tlog - EVTLOG entry structure + * @counter - EVTLOG entriy counter + * @time - timestamp of EVTLOG entry + * @name - function name of EVTLOG entry + * @line - line number of EVTLOG entry + * @data - EVTLOG data contents + * @data_cnt - number of data contents + * @pid - pid of current calling thread + */ +struct tlog { + u32 counter; + s64 time; + const char *name; + int line; + u32 data[SDE_ROT_EVTLOG_MAX_DATA]; + u32 data_cnt; + int pid; +}; + +/* + * sde_rot_dbg_evtlog - EVTLOG debug data structure + * @logs - EVTLOG entries + * @first - first entry index in the EVTLOG + * @last - last entry index in the EVTLOG + * @curr - curr entry index in the EVTLOG + * @evtlog - EVTLOG debugfs handle + * @evtlog_enable - boolean indicates EVTLOG enable/disable + * @panic_on_err - boolean indicates issue panic after EVTLOG dump + * @enable_reg_dump - control in-log/memory dump for rotator registers + * @enable_vbif_dbgbus_dump - control in-log/memory dump for VBIF debug bus + * @enable_rot_dbgbus_dump - control in-log/memroy dump for rotator debug bus + * @evtlog_dump_work - schedule work strucutre for timeout handler + * @work_dump_reg - storage for register dump control in schedule work + * @work_panic - storage for panic control in schedule work + * @work_vbif_dbgbus - storage for VBIF debug bus control in schedule work + * @work_rot_dbgbus - storage for rotator debug bus control in schedule work + * @nrt_vbif_dbgbus_dump - memory buffer for VBIF debug bus dumping + * @rot_dbgbus_dump - memory buffer for rotator debug bus dumping + * @reg_dump_array - memory buffer for rotator registers dumping + */ +struct sde_rot_dbg_evtlog { + struct tlog logs[SDE_ROT_EVTLOG_ENTRY]; + u32 first; + u32 last; + u32 curr; + struct dentry *evtlog; + u32 evtlog_enable; + u32 panic_on_err; + u32 enable_reg_dump; + u32 enable_vbif_dbgbus_dump; + u32 enable_rot_dbgbus_dump; + struct work_struct evtlog_dump_work; + bool work_dump_reg; + bool work_panic; + bool work_vbif_dbgbus; + bool work_rot_dbgbus; + u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */ + u32 *rot_dbgbus_dump; + u32 *reg_dump_array[SDE_ROT_DEBUG_BASE_MAX]; +} sde_rot_dbg_evtlog; + +static void sde_rot_dump_debug_bus(u32 bus_dump_flag, u32 **dump_mem) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + bool in_log, in_mem; + u32 *dump_addr = NULL; + u32 status = 0; + struct sde_rot_debug_bus *head; + phys_addr_t phys = 0; + int i; + u32 offset; + void __iomem *base; + + in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG); + in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM); + base = mdata->sde_io.base; + + if (!base || !mdata->rot_dbg_bus || !mdata->rot_dbg_bus_size) + return; + + pr_info("======== SDE Rotator Debug bus DUMP =========\n"); + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(&mdata->pdev->dev, + mdata->rot_dbg_bus_size * 4 * sizeof(u32), + &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n", + __func__, dump_addr, + dump_addr + (u32)mdata->rot_dbg_bus_size * 16); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + sde_smmu_ctrl(1); + + for (i = 0; i < mdata->rot_dbg_bus_size; i++) { + head = mdata->rot_dbg_bus + i; + writel_relaxed(SDE_ROT_TEST_MASK(head->block_id, head->test_id), + base + head->wr_addr); + wmb(); /* make sure test bits were written */ + + offset = head->wr_addr + 0x4; + + status = readl_relaxed(base + offset); + + if (in_log) + pr_err("waddr=0x%x blk=%d tst=%d val=0x%x\n", + head->wr_addr, head->block_id, head->test_id, + status); + + if (dump_addr && in_mem) { + dump_addr[i*4] = head->wr_addr; + dump_addr[i*4 + 1] = head->block_id; + dump_addr[i*4 + 2] = head->test_id; + dump_addr[i*4 + 3] = status; + } + + /* Disable debug bus once we are done */ + writel_relaxed(0, base + head->wr_addr); + } + + sde_smmu_ctrl(0); + + pr_info("========End Debug bus=========\n"); +} + +/* + * sde_rot_evtlog_is_enabled - helper function for checking EVTLOG + * enable/disable + * @flag - EVTLOG option flag + */ +static inline bool sde_rot_evtlog_is_enabled(u32 flag) +{ + return (flag & sde_rot_dbg_evtlog.evtlog_enable) || + (flag == SDE_ROT_EVTLOG_ALL && + sde_rot_dbg_evtlog.evtlog_enable); +} + +/* + * __vbif_debug_bus - helper function for VBIF debug bus dump + * @head - VBIF debug bus data structure + * @vbif_base - VBIF IO mapped address + * @dump_addr - output buffer for memory dump option + * @in_log - boolean indicates in-log dump option + */ +static void __vbif_debug_bus(struct sde_rot_vbif_debug_bus *head, + void __iomem *vbif_base, u32 *dump_addr, bool in_log) +{ + int i, j; + u32 val; + + if (!dump_addr && !in_log) + return; + + for (i = 0; i < head->block_cnt; i++) { + writel_relaxed(1 << (i + head->bit_offset), + vbif_base + head->block_bus_addr); + /* make sure that current bus blcok enable */ + wmb(); + for (j = 0; j < head->test_pnt_cnt; j++) { + writel_relaxed(j, vbif_base + head->block_bus_addr + 4); + /* make sure that test point is enabled */ + wmb(); + val = readl_relaxed(vbif_base + MMSS_VBIF_TEST_BUS_OUT); + if (dump_addr) { + *dump_addr++ = head->block_bus_addr; + *dump_addr++ = i; + *dump_addr++ = j; + *dump_addr++ = val; + } + if (in_log) + pr_err("testpoint:%x arb/xin id=%d index=%d val=0x%x\n", + head->block_bus_addr, i, j, val); + } + } +} + +/* + * sde_rot_dump_vbif_debug_bus - VBIF debug bus dump + * @bus_dump_flag - dump flag controlling in-log/memory dump option + * @dump_mem - output buffer for memory dump location + */ +static void sde_rot_dump_vbif_debug_bus(u32 bus_dump_flag, + u32 **dump_mem) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + bool in_log, in_mem; + u32 *dump_addr = NULL; + u32 value; + struct sde_rot_vbif_debug_bus *head; + phys_addr_t phys = 0; + int i, list_size = 0; + void __iomem *vbif_base; + struct sde_rot_vbif_debug_bus *dbg_bus; + u32 bus_size; + + pr_info("======== NRT VBIF Debug bus DUMP =========\n"); + vbif_base = mdata->vbif_nrt_io.base; + dbg_bus = mdata->nrt_vbif_dbg_bus; + bus_size = mdata->nrt_vbif_dbg_bus_size; + + if (!vbif_base || !dbg_bus || !bus_size) + return; + + /* allocate memory for each test point */ + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + list_size += (head->block_cnt * head->test_pnt_cnt); + } + + /* 4 bytes * 4 entries for each test point*/ + list_size *= 16; + + in_log = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG); + in_mem = (bus_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM); + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(&mdata->pdev->dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n", + __func__, dump_addr, dump_addr + list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + sde_smmu_ctrl(1); + + value = readl_relaxed(vbif_base + MMSS_VBIF_CLKON); + writel_relaxed(value | BIT(1), vbif_base + MMSS_VBIF_CLKON); + + /* make sure that vbif core is on */ + wmb(); + + for (i = 0; i < bus_size; i++) { + head = dbg_bus + i; + + writel_relaxed(0, vbif_base + head->disable_bus_addr); + writel_relaxed(BIT(0), vbif_base + MMSS_VBIF_TEST_BUS_OUT_CTRL); + /* make sure that other bus is off */ + wmb(); + + __vbif_debug_bus(head, vbif_base, dump_addr, in_log); + if (dump_addr) + dump_addr += (head->block_cnt * head->test_pnt_cnt * 4); + } + + sde_smmu_ctrl(0); + + pr_info("========End VBIF Debug bus=========\n"); +} + +/* + * sde_rot_dump_reg - helper function for dumping rotator register set content + * @dump_name - register set name + * @reg_dump_flag - dumping flag controlling in-log/memory dump location + * @access - access type, sde registers or vbif registers + * @addr - starting address offset for dumping + * @len - range of the register set + * @dump_mem - output buffer for memory dump location option + */ +void sde_rot_dump_reg(const char *dump_name, u32 reg_dump_flag, + enum sde_rot_regdump_access access, u32 addr, + int len, u32 **dump_mem) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + bool in_log, in_mem; + u32 *dump_addr = NULL; + phys_addr_t phys = 0; + int i; + void __iomem *base; + + in_log = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_LOG); + in_mem = (reg_dump_flag & SDE_ROT_DBG_DUMP_IN_MEM); + + pr_debug("reg_dump_flag=%d in_log=%d in_mem=%d\n", + reg_dump_flag, in_log, in_mem); + + if (len % 16) + len += 16; + len /= 16; + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(&mdata->pdev->dev, + len * 16, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + pr_info("%s: start_addr:0x%pK end_addr:0x%pK reg_addr=0x%X\n", + dump_name, dump_addr, dump_addr + (u32)len * 16, + addr); + } else { + in_mem = false; + pr_err("dump_mem: kzalloc fails!\n"); + } + } + + base = mdata->sde_io.base; + /* + * VBIF NRT base handling + */ + if (access == SDE_ROT_REGDUMP_VBIF) + base = mdata->vbif_nrt_io.base; + + for (i = 0; i < len; i++) { + u32 x0, x4, x8, xc; + + x0 = readl_relaxed(base + addr+0x0); + x4 = readl_relaxed(base + addr+0x4); + x8 = readl_relaxed(base + addr+0x8); + xc = readl_relaxed(base + addr+0xc); + + if (in_log) + pr_info("0x%08X : %08x %08x %08x %08x\n", + addr, x0, x4, x8, xc); + + if (dump_addr && in_mem) { + dump_addr[i*4] = x0; + dump_addr[i*4 + 1] = x4; + dump_addr[i*4 + 2] = x8; + dump_addr[i*4 + 3] = xc; + } + + addr += 16; + } +} + +/* + * sde_rot_dump_reg_all - dumping all SDE rotator registers + */ +static void sde_rot_dump_reg_all(void) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_rot_regdump *head, *regdump; + u32 regdump_size; + int i; + + regdump = mdata->regdump; + regdump_size = mdata->regdump_size; + + if (!regdump || !regdump_size) + return; + + /* Enable clock to rotator if not yet enabled */ + sde_smmu_ctrl(1); + + for (i = 0; (i < regdump_size) && (i < SDE_ROT_DEBUG_BASE_MAX); i++) { + head = ®dump[i]; + + if (head->access == SDE_ROT_REGDUMP_WRITE) { + if (head->len != 1) { + SDEROT_ERR("invalid write len %u\n", head->len); + continue; + } + writel_relaxed(head->value, + mdata->sde_io.base + head->offset); + /* Make sure write go through */ + wmb(); + } else { + sde_rot_dump_reg(head->name, + sde_rot_dbg_evtlog.enable_reg_dump, + head->access, + head->offset, head->len, + &sde_rot_dbg_evtlog.reg_dump_array[i]); + } + } + + /* Disable rotator clock */ + sde_smmu_ctrl(0); +} + +/* + * __sde_rot_evtlog_dump_calc_range - calculate dump range for EVTLOG + */ +static bool __sde_rot_evtlog_dump_calc_range(void) +{ + static u32 next; + bool need_dump = true; + unsigned long flags; + struct sde_rot_dbg_evtlog *evtlog = &sde_rot_dbg_evtlog; + + spin_lock_irqsave(&sde_rot_xlock, flags); + + evtlog->first = next; + + if (evtlog->last == evtlog->first) { + need_dump = false; + goto dump_exit; + } + + if (evtlog->last < evtlog->first) { + evtlog->first %= SDE_ROT_EVTLOG_ENTRY; + if (evtlog->last < evtlog->first) + evtlog->last += SDE_ROT_EVTLOG_ENTRY; + } + + if ((evtlog->last - evtlog->first) > SDE_ROT_EVTLOG_PRINT_ENTRY) { + pr_warn("evtlog buffer overflow before dump: %d\n", + evtlog->last - evtlog->first); + evtlog->first = evtlog->last - SDE_ROT_EVTLOG_PRINT_ENTRY; + } + next = evtlog->first + 1; + +dump_exit: + spin_unlock_irqrestore(&sde_rot_xlock, flags); + + return need_dump; +} + +/* + * sde_rot_evtlog_dump_entry - helper function for EVTLOG content dumping + * @evtlog_buf: EVTLOG dump output buffer + * @evtlog_buf_size: EVTLOG output buffer size + */ +static ssize_t sde_rot_evtlog_dump_entry(char *evtlog_buf, + ssize_t evtlog_buf_size) +{ + int i; + ssize_t off = 0; + struct tlog *log, *prev_log; + unsigned long flags; + + spin_lock_irqsave(&sde_rot_xlock, flags); + + log = &sde_rot_dbg_evtlog.logs[sde_rot_dbg_evtlog.first % + SDE_ROT_EVTLOG_ENTRY]; + + prev_log = &sde_rot_dbg_evtlog.logs[(sde_rot_dbg_evtlog.first - 1) % + SDE_ROT_EVTLOG_ENTRY]; + + off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d", + log->name, log->line); + + if (off < SDE_ROT_EVTLOG_BUF_ALIGN) { + memset((evtlog_buf + off), 0x20, + (SDE_ROT_EVTLOG_BUF_ALIGN - off)); + off = SDE_ROT_EVTLOG_BUF_ALIGN; + } + + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), + "=>[%-8d:%-11llu:%9llu][%-4d]:", sde_rot_dbg_evtlog.first, + log->time, (log->time - prev_log->time), log->pid); + + for (i = 0; i < log->data_cnt; i++) + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), + "%x ", log->data[i]); + + off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n"); + + spin_unlock_irqrestore(&sde_rot_xlock, flags); + + return off; +} + +/* + * sde_rot_evtlog_dump_all - Dumping all content in EVTLOG buffer + */ +static void sde_rot_evtlog_dump_all(void) +{ + char evtlog_buf[SDE_ROT_EVTLOG_BUF_MAX]; + + while (__sde_rot_evtlog_dump_calc_range()) { + sde_rot_evtlog_dump_entry(evtlog_buf, SDE_ROT_EVTLOG_BUF_MAX); + pr_info("%s\n", evtlog_buf); + } +} + +/* + * sde_rot_evtlog_dump_open - debugfs open handler for evtlog dump + * @inode: debugfs inode + * @file: file handler + */ +static int sde_rot_evtlog_dump_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + return 0; +} + +/* + * sde_rot_evtlog_dump_read - debugfs read handler for evtlog dump + * @file: file handler + * @buff: user buffer content for debugfs + * @count: size of user buffer + * @ppos: position offset of user buffer + */ +static ssize_t sde_rot_evtlog_dump_read(struct file *file, char __user *buff, + size_t count, loff_t *ppos) +{ + ssize_t len = 0; + char evtlog_buf[SDE_ROT_EVTLOG_BUF_MAX]; + + if (__sde_rot_evtlog_dump_calc_range()) { + len = sde_rot_evtlog_dump_entry(evtlog_buf, + SDE_ROT_EVTLOG_BUF_MAX); + if (len < 0 || len > count) { + pr_err("len is more than the user buffer size\n"); + return 0; + } + + if (copy_to_user(buff, evtlog_buf, len)) + return -EFAULT; + *ppos += len; + } + + return len; +} + +/* + * sde_rot_evtlog_dump_helper - helper function for evtlog dump + * @dead: boolean indicates panic after dump + * @panic_name: Panic signature name show up in log + * @dump_rot: boolean indicates rotator register dump + * @dump_vbif_debug_bus: boolean indicates VBIF debug bus dump + */ +static void sde_rot_evtlog_dump_helper(bool dead, const char *panic_name, + bool dump_rot, bool dump_vbif_debug_bus, bool dump_rot_debug_bus) +{ + sde_rot_evtlog_dump_all(); + + if (dump_rot_debug_bus) + sde_rot_dump_debug_bus( + sde_rot_dbg_evtlog.enable_rot_dbgbus_dump, + &sde_rot_dbg_evtlog.rot_dbgbus_dump); + + if (dump_vbif_debug_bus) + sde_rot_dump_vbif_debug_bus( + sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump, + &sde_rot_dbg_evtlog.nrt_vbif_dbgbus_dump); + + /* + * Rotator registers always dump last + */ + if (dump_rot) + sde_rot_dump_reg_all(); + + if (dead) + panic(panic_name); +} + +/* + * sde_rot_evtlog_debug_work - schedule work function for evtlog dump + * @work: schedule work structure + */ +static void sde_rot_evtlog_debug_work(struct work_struct *work) +{ + sde_rot_evtlog_dump_helper( + sde_rot_dbg_evtlog.work_panic, + "evtlog_workitem", + sde_rot_dbg_evtlog.work_dump_reg, + sde_rot_dbg_evtlog.work_vbif_dbgbus, + sde_rot_dbg_evtlog.work_rot_dbgbus); +} + +/* + * sde_rot_evtlog_tout_handler - log dump timeout handler + * @queue: boolean indicate putting log dump into queue + * @name: function name having timeout + */ +void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...) +{ + int i; + bool dead = false; + bool dump_rot = false; + bool dump_vbif_dbgbus = false; + bool dump_rot_dbgbus = false; + char *blk_name = NULL; + va_list args; + + if (!sde_rot_evtlog_is_enabled(SDE_ROT_EVTLOG_DEFAULT)) + return; + + if (queue && work_pending(&sde_rot_dbg_evtlog.evtlog_dump_work)) + return; + + va_start(args, name); + for (i = 0; i < SDE_ROT_EVTLOG_MAX_DATA; i++) { + blk_name = va_arg(args, char*); + if (IS_ERR_OR_NULL(blk_name)) + break; + + if (!strcmp(blk_name, "rot")) + dump_rot = true; + + if (!strcmp(blk_name, "vbif_dbg_bus")) + dump_vbif_dbgbus = true; + + if (!strcmp(blk_name, "rot_dbg_bus")) + dump_rot_dbgbus = true; + + if (!strcmp(blk_name, "panic")) + dead = true; + } + va_end(args); + + if (queue) { + /* schedule work to dump later */ + sde_rot_dbg_evtlog.work_panic = dead; + sde_rot_dbg_evtlog.work_dump_reg = dump_rot; + sde_rot_dbg_evtlog.work_vbif_dbgbus = dump_vbif_dbgbus; + sde_rot_dbg_evtlog.work_rot_dbgbus = dump_rot_dbgbus; + schedule_work(&sde_rot_dbg_evtlog.evtlog_dump_work); + } else { + sde_rot_evtlog_dump_helper(dead, name, dump_rot, + dump_vbif_dbgbus, dump_rot_dbgbus); + } +} + +/* + * sde_rot_evtlog - log contents into memory for dump analysis + * @name: Name of function calling evtlog + * @line: line number of calling function + * @flag: Log control flag + */ +void sde_rot_evtlog(const char *name, int line, int flag, ...) +{ + unsigned long flags; + int i, val = 0; + va_list args; + struct tlog *log; + + if (!sde_rot_evtlog_is_enabled(flag)) + return; + + spin_lock_irqsave(&sde_rot_xlock, flags); + log = &sde_rot_dbg_evtlog.logs[sde_rot_dbg_evtlog.curr]; + log->time = ktime_to_us(ktime_get()); + log->name = name; + log->line = line; + log->data_cnt = 0; + log->pid = current->pid; + + va_start(args, flag); + for (i = 0; i < SDE_ROT_EVTLOG_MAX_DATA; i++) { + + val = va_arg(args, int); + if (val == SDE_ROT_DATA_LIMITER) + break; + + log->data[i] = val; + } + va_end(args); + log->data_cnt = i; + sde_rot_dbg_evtlog.curr = + (sde_rot_dbg_evtlog.curr + 1) % SDE_ROT_EVTLOG_ENTRY; + sde_rot_dbg_evtlog.last++; + + trace_sde_rot_evtlog(name, line, log->data_cnt, log->data); + + spin_unlock_irqrestore(&sde_rot_xlock, flags); +} + +/* + * sde_rotator_stat_show - Show statistics on read to this debugfs file + * @s: Pointer to sequence file structure + * @data: Pointer to private data structure + */ +static int sde_rotator_stat_show(struct seq_file *s, void *data) +{ + int i, offset; + struct sde_rotator_device *rot_dev = s->private; + struct sde_rotator_statistics *stats = &rot_dev->stats; + u64 count = stats->count; + int num_events; + s64 proc_max, proc_min, proc_avg; + s64 swoh_max, swoh_min, swoh_avg; + + proc_max = 0; + proc_min = S64_MAX; + proc_avg = 0; + swoh_max = 0; + swoh_min = S64_MAX; + swoh_avg = 0; + + if (count > SDE_ROTATOR_NUM_EVENTS) { + num_events = SDE_ROTATOR_NUM_EVENTS; + offset = count % SDE_ROTATOR_NUM_EVENTS; + } else { + num_events = count; + offset = 0; + } + + for (i = 0; i < num_events; i++) { + int k = (offset + i) % SDE_ROTATOR_NUM_EVENTS; + ktime_t *ts = stats->ts[k]; + ktime_t start_time = + ktime_before(ts[SDE_ROTATOR_TS_SRCQB], + ts[SDE_ROTATOR_TS_DSTQB]) ? + ts[SDE_ROTATOR_TS_SRCQB] : + ts[SDE_ROTATOR_TS_DSTQB]; + s64 proc_time = + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE], + start_time)); + s64 sw_overhead_time = + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH], + start_time)); + + seq_printf(s, + "s:%d sq:%lld dq:%lld fe:%lld q:%lld c:%lld st:%lld fl:%lld d:%lld sdq:%lld ddq:%lld t:%lld oht:%lld\n", + i, + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE], + ts[SDE_ROTATOR_TS_SRCQB])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FENCE], + ts[SDE_ROTATOR_TS_DSTQB])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_QUEUE], + ts[SDE_ROTATOR_TS_FENCE])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_COMMIT], + ts[SDE_ROTATOR_TS_QUEUE])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_START], + ts[SDE_ROTATOR_TS_COMMIT])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_FLUSH], + ts[SDE_ROTATOR_TS_START])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DONE], + ts[SDE_ROTATOR_TS_FLUSH])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_RETIRE], + ts[SDE_ROTATOR_TS_DONE])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_SRCDQB], + ts[SDE_ROTATOR_TS_RETIRE])), + ktime_to_us(ktime_sub(ts[SDE_ROTATOR_TS_DSTDQB], + ts[SDE_ROTATOR_TS_RETIRE])), + proc_time, sw_overhead_time); + + proc_max = max(proc_max, proc_time); + proc_min = min(proc_min, proc_time); + proc_avg += proc_time; + + swoh_max = max(swoh_max, sw_overhead_time); + swoh_min = min(swoh_min, sw_overhead_time); + swoh_avg += sw_overhead_time; + } + + proc_avg = (num_events) ? + DIV_ROUND_CLOSEST_ULL(proc_avg, num_events) : 0; + swoh_avg = (num_events) ? + DIV_ROUND_CLOSEST_ULL(swoh_avg, num_events) : 0; + + seq_printf(s, "count:%llu\n", count); + seq_printf(s, "fai1:%llu\n", stats->fail_count); + seq_printf(s, "t_max:%lld\n", proc_max); + seq_printf(s, "t_min:%lld\n", proc_min); + seq_printf(s, "t_avg:%lld\n", proc_avg); + seq_printf(s, "swoh_max:%lld\n", swoh_max); + seq_printf(s, "swoh_min:%lld\n", swoh_min); + seq_printf(s, "swoh_avg:%lld\n", swoh_avg); + + return 0; +} + +/* + * sde_rotator_raw_show - Show raw statistics on read from this debugfs file + * @s: Pointer to sequence file structure + * @data: Pointer to private data structure + */ +static int sde_rotator_raw_show(struct seq_file *s, void *data) +{ + int i, j, offset; + struct sde_rotator_device *rot_dev = s->private; + struct sde_rotator_statistics *stats = &rot_dev->stats; + u64 count = stats->count; + int num_events; + + if (count > SDE_ROTATOR_NUM_EVENTS) { + num_events = SDE_ROTATOR_NUM_EVENTS; + offset = count % SDE_ROTATOR_NUM_EVENTS; + } else { + num_events = count; + offset = 0; + } + + for (i = 0; i < num_events; i++) { + int k = (offset + i) % SDE_ROTATOR_NUM_EVENTS; + ktime_t *ts = stats->ts[k]; + + seq_printf(s, "%d ", i); + for (j = 0; j < SDE_ROTATOR_NUM_TIMESTAMPS; j++) + seq_printf(s, "%lld ", ktime_to_us(ts[j])); + seq_puts(s, "\n"); + } + + return 0; +} + +/* + * sde_rotator_dbg_open - Processed statistics debugfs file open function + * @inode: + * @file: + */ +static int sde_rotator_stat_open(struct inode *inode, struct file *file) +{ + return single_open(file, sde_rotator_stat_show, inode->i_private); +} + +/* + * sde_rotator_dbg_open - Raw statistics debugfs file open function + * @inode: + * @file: + */ +static int sde_rotator_raw_open(struct inode *inode, struct file *file) +{ + return single_open(file, sde_rotator_raw_show, inode->i_private); +} + +/* + * sde_rotator_dbg_open - Raw statistics debugfs file open function + * @mdata: Pointer to rotator global data + * @debugfs_root: Pointer to parent debugfs node + */ +static int sde_rotator_base_create_debugfs( + struct sde_rot_data_type *mdata, + struct dentry *debugfs_root) +{ + if (!debugfs_create_u32("iommu_ref_cnt", 0444, + debugfs_root, &mdata->iommu_ref_cnt)) { + SDEROT_WARN("failed to create debugfs iommu ref cnt\n"); + return -EINVAL; + } + + mdata->clk_always_on = false; + if (!debugfs_create_bool("clk_always_on", 0644, + debugfs_root, &mdata->clk_always_on)) { + SDEROT_WARN("failed to create debugfs clk_always_on\n"); + return -EINVAL; + } + + return 0; +} + +/* + * sde_rotator_dbg_open - Raw statistics debugfs file open function + * @mgr: Pointer to rotator manager structure + * @debugfs_root: Pointer to parent debugfs node + */ +static int sde_rotator_core_create_debugfs( + struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + int ret; + + if (!debugfs_create_u32("hwacquire_timeout", 0400, + debugfs_root, &mgr->hwacquire_timeout)) { + SDEROT_WARN("failed to create debugfs hw acquire timeout\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("ppc_numer", 0644, + debugfs_root, &mgr->pixel_per_clk.numer)) { + SDEROT_WARN("failed to create debugfs ppc numerator\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("ppc_denom", 0600, + debugfs_root, &mgr->pixel_per_clk.denom)) { + SDEROT_WARN("failed to create debugfs ppc denominator\n"); + return -EINVAL; + } + + if (!debugfs_create_u64("enable_bw_vote", 0644, + debugfs_root, &mgr->enable_bw_vote)) { + SDEROT_WARN("failed to create enable_bw_vote\n"); + return -EINVAL; + } + + if (mgr->ops_hw_create_debugfs) { + ret = mgr->ops_hw_create_debugfs(mgr, debugfs_root); + if (ret) + return ret; + } + return 0; +} + +static const struct file_operations sde_rot_evtlog_fops = { + .open = sde_rot_evtlog_dump_open, + .read = sde_rot_evtlog_dump_read, +}; + +static int sde_rotator_evtlog_create_debugfs( + struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + int i; + + sde_rot_dbg_evtlog.evtlog = debugfs_create_dir("evtlog", debugfs_root); + if (IS_ERR_OR_NULL(sde_rot_dbg_evtlog.evtlog)) { + pr_err("debugfs_create_dir fail, error %ld\n", + PTR_ERR(sde_rot_dbg_evtlog.evtlog)); + sde_rot_dbg_evtlog.evtlog = NULL; + return -ENODEV; + } + + INIT_WORK(&sde_rot_dbg_evtlog.evtlog_dump_work, + sde_rot_evtlog_debug_work); + sde_rot_dbg_evtlog.work_panic = false; + + for (i = 0; i < SDE_ROT_EVTLOG_ENTRY; i++) + sde_rot_dbg_evtlog.logs[i].counter = i; + + debugfs_create_file("dump", 0644, sde_rot_dbg_evtlog.evtlog, NULL, + &sde_rot_evtlog_fops); + debugfs_create_u32("enable", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.evtlog_enable); + debugfs_create_u32("panic", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.panic_on_err); + debugfs_create_u32("reg_dump", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.enable_reg_dump); + debugfs_create_u32("vbif_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump); + debugfs_create_u32("rot_dbgbus_dump", 0644, sde_rot_dbg_evtlog.evtlog, + &sde_rot_dbg_evtlog.enable_rot_dbgbus_dump); + + sde_rot_dbg_evtlog.evtlog_enable = SDE_EVTLOG_DEFAULT_ENABLE; + sde_rot_dbg_evtlog.panic_on_err = SDE_EVTLOG_DEFAULT_PANIC; + sde_rot_dbg_evtlog.enable_reg_dump = SDE_EVTLOG_DEFAULT_REGDUMP; + sde_rot_dbg_evtlog.enable_vbif_dbgbus_dump = + SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP; + sde_rot_dbg_evtlog.enable_rot_dbgbus_dump = + SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP; + + pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n", + sde_rot_dbg_evtlog.evtlog_enable, + sde_rot_dbg_evtlog.panic_on_err, + sde_rot_dbg_evtlog.enable_reg_dump); + + return 0; +} + +/* + * struct sde_rotator_stat_ops - processed statistics file operations + */ +static const struct file_operations sde_rotator_stat_ops = { + .open = sde_rotator_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +/* + * struct sde_rotator_raw_ops - raw statistics file operations + */ +static const struct file_operations sde_rotator_raw_ops = { + .open = sde_rotator_raw_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +static int sde_rotator_debug_base_open(struct inode *inode, struct file *file) +{ + /* non-seekable */ + file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); + file->private_data = inode->i_private; + return 0; +} + +static int sde_rotator_debug_base_release(struct inode *inode, + struct file *file) +{ + struct sde_rotator_debug_base *dbg = file->private_data; + + if (dbg) { + mutex_lock(&dbg->buflock); + kfree(dbg->buf); + dbg->buf_len = 0; + dbg->buf = NULL; + mutex_unlock(&dbg->buflock); + } + + return 0; +} + +static ssize_t sde_rotator_debug_base_offset_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_rotator_debug_base *dbg = file->private_data; + u32 off = 0; + u32 cnt = SDE_ROT_DEFAULT_BASE_REG_CNT; + char buf[24]; + + if (!dbg) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; + + if (sscanf(buf, "%5x %x", &off, &cnt) < 2) + return -EINVAL; + + if (off % sizeof(u32)) + return -EINVAL; + + if (off > dbg->max_offset) + return -EINVAL; + + if (cnt > (dbg->max_offset - off)) + cnt = dbg->max_offset - off; + + mutex_lock(&dbg->buflock); + dbg->off = off; + dbg->cnt = cnt; + mutex_unlock(&dbg->buflock); + + SDEROT_DBG("offset=%x cnt=%x\n", off, cnt); + + return count; +} + +static ssize_t sde_rotator_debug_base_offset_read(struct file *file, + char __user *buff, size_t count, loff_t *ppos) +{ + struct sde_rotator_debug_base *dbg = file->private_data; + int len = 0; + char buf[24] = {'\0'}; + + if (!dbg) + return -ENODEV; + + if (*ppos) + return 0; /* the end */ + + mutex_lock(&dbg->buflock); + len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt); + mutex_unlock(&dbg->buflock); + + if (len < 0 || len >= sizeof(buf)) + return 0; + + if ((count < sizeof(buf)) || copy_to_user(buff, buf, len)) + return -EFAULT; + + *ppos += len; /* increase offset */ + + return len; +} + +static ssize_t sde_rotator_debug_base_reg_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_rotator_debug_base *dbg = file->private_data; + size_t off; + u32 data, cnt; + char buf[24]; + + if (!dbg) + return -ENODEV; + + if (count >= sizeof(buf)) + return -EFAULT; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + buf[count] = 0; + + cnt = sscanf(buf, "%zx %x", &off, &data); + + if (cnt < 2) + return -EFAULT; + + if (off % sizeof(u32)) + return -EFAULT; + + if (off >= dbg->max_offset) + return -EFAULT; + + mutex_lock(&dbg->buflock); + + /* Enable Clock for register access */ + sde_rot_mgr_lock(dbg->mgr); + if (!sde_rotator_resource_ctrl_enabled(dbg->mgr)) { + SDEROT_WARN("resource ctrl is not enabled\n"); + sde_rot_mgr_unlock(dbg->mgr); + goto debug_write_error; + } + sde_rotator_clk_ctrl(dbg->mgr, true); + + writel_relaxed(data, dbg->base + off); + + /* Disable Clock after register access */ + sde_rotator_clk_ctrl(dbg->mgr, false); + sde_rot_mgr_unlock(dbg->mgr); + + mutex_unlock(&dbg->buflock); + + SDEROT_DBG("addr=%zx data=%x\n", off, data); + + return count; + +debug_write_error: + mutex_unlock(&dbg->buflock); + return 0; +} + +static ssize_t sde_rotator_debug_base_reg_read(struct file *file, + char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sde_rotator_debug_base *dbg = file->private_data; + size_t len; + int rc = 0; + + if (!dbg) { + SDEROT_ERR("invalid handle\n"); + return -ENODEV; + } + + mutex_lock(&dbg->buflock); + if (!dbg->buf) { + char dump_buf[64]; + char *ptr; + int cnt, tot; + + dbg->buf_len = sizeof(dump_buf) * + DIV_ROUND_UP(dbg->cnt, ROW_BYTES); + dbg->buf = kzalloc(dbg->buf_len, GFP_KERNEL); + + if (!dbg->buf) { + SDEROT_ERR("not enough memory to hold reg dump\n"); + rc = -ENOMEM; + goto debug_read_error; + } + + if (dbg->off % sizeof(u32)) { + rc = -EFAULT; + goto debug_read_error; + } + + ptr = dbg->base + dbg->off; + tot = 0; + + /* Enable clock for register access */ + sde_rot_mgr_lock(dbg->mgr); + if (!sde_rotator_resource_ctrl_enabled(dbg->mgr)) { + SDEROT_WARN("resource ctrl is not enabled\n"); + sde_rot_mgr_unlock(dbg->mgr); + goto debug_read_error; + } + sde_rotator_clk_ctrl(dbg->mgr, true); + + for (cnt = dbg->cnt; cnt > 0; cnt -= ROW_BYTES) { + hex_dump_to_buffer(ptr, min(cnt, ROW_BYTES), + ROW_BYTES, GROUP_BYTES, dump_buf, + sizeof(dump_buf), false); + len = scnprintf(dbg->buf + tot, dbg->buf_len - tot, + "0x%08x: %s\n", + ((int) (unsigned long) ptr) - + ((int) (unsigned long) dbg->base), + dump_buf); + + ptr += ROW_BYTES; + tot += len; + if (tot >= dbg->buf_len) + break; + } + /* Disable clock after register access */ + sde_rotator_clk_ctrl(dbg->mgr, false); + sde_rot_mgr_unlock(dbg->mgr); + + dbg->buf_len = tot; + } + + if (*ppos >= dbg->buf_len) { + rc = 0; /* done reading */ + goto debug_read_error; + } + + len = min(count, dbg->buf_len - (size_t) *ppos); + if (copy_to_user(user_buf, dbg->buf + *ppos, len)) { + SDEROT_ERR("failed to copy to user\n"); + rc = -EFAULT; + goto debug_read_error; + } + + *ppos += len; /* increase offset */ + + mutex_unlock(&dbg->buflock); + return len; + +debug_read_error: + mutex_unlock(&dbg->buflock); + return rc; +} + +static const struct file_operations sde_rotator_off_fops = { + .open = sde_rotator_debug_base_open, + .release = sde_rotator_debug_base_release, + .read = sde_rotator_debug_base_offset_read, + .write = sde_rotator_debug_base_offset_write, +}; + +static const struct file_operations sde_rotator_reg_fops = { + .open = sde_rotator_debug_base_open, + .release = sde_rotator_debug_base_release, + .read = sde_rotator_debug_base_reg_read, + .write = sde_rotator_debug_base_reg_write, +}; + +/* + * sde_rotator_create_debugfs - Setup rotator debugfs directory structure. + * @rot_dev: Pointer to rotator device + */ +struct dentry *sde_rotator_create_debugfs( + struct sde_rotator_device *rot_dev) +{ + struct dentry *debugfs_root; + char dirname[32] = {0}; + + snprintf(dirname, sizeof(dirname), "%s%d", + SDE_ROTATOR_DRV_NAME, rot_dev->dev->id); + debugfs_root = debugfs_create_dir(dirname, NULL); + if (!debugfs_root) { + SDEROT_ERR("fail create debugfs root\n"); + return NULL; + } + + if (!debugfs_create_file("stats", 0400, + debugfs_root, rot_dev, &sde_rotator_stat_ops)) { + SDEROT_ERR("fail create debugfs stats\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (!debugfs_create_file("raw", 0400, + debugfs_root, rot_dev, &sde_rotator_raw_ops)) { + SDEROT_ERR("fail create debugfs raw\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (!debugfs_create_u32("fence_timeout", 0400, + debugfs_root, &rot_dev->fence_timeout)) { + SDEROT_ERR("fail create fence_timeout\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (!debugfs_create_u32("open_timeout", 0400, + debugfs_root, &rot_dev->open_timeout)) { + SDEROT_ERR("fail create open_timeout\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (!debugfs_create_u32("disable_syscache", 0400, + debugfs_root, &rot_dev->disable_syscache)) { + SDEROT_ERR("fail create disable_syscache\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (!debugfs_create_u32("streamoff_timeout", 0400, + debugfs_root, &rot_dev->streamoff_timeout)) { + SDEROT_ERR("fail create streamoff_timeout\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (!debugfs_create_u32("early_submit", 0400, + debugfs_root, &rot_dev->early_submit)) { + SDEROT_ERR("fail create early_submit\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (sde_rotator_base_create_debugfs(rot_dev->mdata, debugfs_root)) { + SDEROT_ERR("fail create base debugfs\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (sde_rotator_core_create_debugfs(rot_dev->mgr, debugfs_root)) { + SDEROT_ERR("fail create core debugfs\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + if (sde_rotator_evtlog_create_debugfs(rot_dev->mgr, debugfs_root)) { + SDEROT_ERR("fail create evtlog debugfs\n"); + debugfs_remove_recursive(debugfs_root); + return NULL; + } + + return debugfs_root; +} + +/* + * sde_rotator_destroy_debugfs - Destroy rotator debugfs directory structure. + * @rot_dev: Pointer to rotator debugfs + */ +void sde_rotator_destroy_debugfs(struct dentry *debugfs) +{ + debugfs_remove_recursive(debugfs); +} diff --git a/techpack/display/rotator/sde_rotator_debug.h b/techpack/display/rotator/sde_rotator_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..8b988ff3083c6293a0d787b6711f6cb70acf9858 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_debug.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_DEBUG_H__ +#define __SDE_ROTATOR_DEBUG_H__ + +#include <linux/types.h> +#include <linux/dcache.h> + +#define SDE_ROT_DATA_LIMITER (-1) +#define SDE_ROT_EVTLOG_TOUT_DATA_LIMITER (NULL) +#define SDE_ROT_EVTLOG_PANIC 0xdead +#define SDE_ROT_EVTLOG_FATAL 0xbad +#define SDE_ROT_EVTLOG_ERROR 0xebad + +enum sde_rot_dbg_reg_dump_flag { + SDE_ROT_DBG_DUMP_IN_LOG = BIT(0), + SDE_ROT_DBG_DUMP_IN_MEM = BIT(1), +}; + +enum sde_rot_dbg_evtlog_flag { + SDE_ROT_EVTLOG_DEFAULT = BIT(0), + SDE_ROT_EVTLOG_IOMMU = BIT(1), + SDE_ROT_EVTLOG_DBG = BIT(6), + SDE_ROT_EVTLOG_ALL = BIT(7) +}; + +#define SDEROT_EVTLOG(...) sde_rot_evtlog(__func__, __LINE__, \ + SDE_ROT_EVTLOG_DEFAULT, ##__VA_ARGS__, SDE_ROT_DATA_LIMITER) + +#define SDEROT_EVTLOG_TOUT_HANDLER(...) \ + sde_rot_evtlog_tout_handler(false, __func__, ##__VA_ARGS__, \ + SDE_ROT_EVTLOG_TOUT_DATA_LIMITER) + +#if defined(CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG) && \ + defined(CONFIG_DEBUG_FS) +void sde_rot_evtlog(const char *name, int line, int flag, ...); +void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...); +#else +static inline +void sde_rot_evtlog(const char *name, int line, int flag, ...) +{ +} +static inline +void sde_rot_evtlog_tout_handler(bool queue, const char *name, ...) +{ +} +#endif + +struct sde_rotator_device; + +struct sde_rotator_debug_base { + char name[80]; + void __iomem *base; + size_t off; + size_t cnt; + size_t max_offset; + char *buf; + size_t buf_len; + struct sde_rot_mgr *mgr; + struct mutex buflock; +}; + +#if defined(CONFIG_DEBUG_FS) +struct dentry *sde_rotator_create_debugfs( + struct sde_rotator_device *rot_dev); + +void sde_rotator_destroy_debugfs(struct dentry *debugfs); +#else +static inline +struct dentry *sde_rotator_create_debugfs( + struct sde_rotator_device *rot_dev) +{ + return NULL; +} + +static inline +void sde_rotator_destroy_debugfs(struct dentry *debugfs) +{ +} +#endif +#endif /* __SDE_ROTATOR_DEBUG_H__ */ diff --git a/techpack/display/rotator/sde_rotator_dev.c b/techpack/display/rotator/sde_rotator_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..bdb9c57376cea897d9f59a1d3a47146dc9f61064 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_dev.c @@ -0,0 +1,3738 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ +#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__ + +#include <linux/vmalloc.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/of.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-v4l2.h> +#include <media/v4l2-mem2mem.h> + +#include "sde_rotator_inline.h" +#include "sde_rotator_base.h" +#include "sde_rotator_core.h" +#include "sde_rotator_dev.h" +#include "sde_rotator_debug.h" +#include "sde_rotator_trace.h" + +/* Start v4l2 device number (default allocation) */ +#define SDE_ROTATOR_BASE_DEVICE_NUMBER -1 + +/* Default value for early_submit flag */ +#define SDE_ROTATOR_EARLY_SUBMIT 1 + +/* Timeout (msec) waiting for stream to turn off. */ +#define SDE_ROTATOR_STREAM_OFF_TIMEOUT 500 + +/* acquire fence time out, following other driver fence time out practice */ +#define SDE_ROTATOR_FENCE_TIMEOUT MSEC_PER_SEC + +/* Timeout (msec) waiting for ctx open */ +#define SDE_ROTATOR_CTX_OPEN_TIMEOUT 500 + +/* Rotator default fps */ +#define SDE_ROTATOR_DEFAULT_FPS 60 + +/* Rotator rotation angles */ +#define SDE_ROTATOR_DEGREE_270 270 +#define SDE_ROTATOR_DEGREE_180 180 +#define SDE_ROTATOR_DEGREE_90 90 + +/* Inline rotator qos request */ +#define SDE_ROTATOR_ADD_REQUEST 1 +#define SDE_ROTATOR_REMOVE_REQUEST 0 + + +static void sde_rotator_submit_handler(struct kthread_work *work); +static void sde_rotator_retire_handler(struct kthread_work *work); +static void sde_rotator_pm_qos_request(struct sde_rotator_device *rot_dev, + bool add_request); +#ifdef CONFIG_COMPAT +static long sde_rotator_compat_ioctl32(struct file *file, + unsigned int cmd, unsigned long arg); +#endif + +/* + * sde_rotator_ctx_from_fh - Get rotator context from v4l2 fh. + * @fh: Pointer to v4l2 fh. + */ +static inline struct sde_rotator_ctx *sde_rotator_ctx_from_fh( + struct v4l2_fh *fh) +{ + return container_of(fh, struct sde_rotator_ctx, fh); +} + +/* + * sde_rotator_get_flags_from_ctx - Get low-level command flag + * @ctx: Pointer to rotator context. + */ +static uint32_t sde_rotator_get_flags_from_ctx(struct sde_rotator_ctx *ctx) +{ + uint32_t ret_flags = 0; + + if (ctx->rotate == SDE_ROTATOR_DEGREE_270) + ret_flags |= SDE_ROTATION_270; + else if (ctx->rotate == SDE_ROTATOR_DEGREE_180) + ret_flags |= SDE_ROTATION_180; + else if (ctx->rotate == SDE_ROTATOR_DEGREE_90) + ret_flags |= SDE_ROTATION_90; + if (ctx->hflip) + ret_flags ^= SDE_ROTATION_FLIP_LR; + if (ctx->vflip) + ret_flags ^= SDE_ROTATION_FLIP_UD; + if (ctx->secure) + ret_flags |= SDE_ROTATION_SECURE; + if (ctx->secure_camera) + ret_flags |= SDE_ROTATION_SECURE_CAMERA; + if (ctx->format_out.fmt.pix.field == V4L2_FIELD_INTERLACED && + ctx->format_cap.fmt.pix.field == V4L2_FIELD_NONE) + ret_flags |= SDE_ROTATION_DEINTERLACE; + + return ret_flags; +} + +/* + * sde_rotator_get_config_from_ctx - Fill rotator configure structure. + * @ctx: Pointer to rotator ctx. + * @config: Pointer to config structure. + */ +static void sde_rotator_get_config_from_ctx(struct sde_rotator_ctx *ctx, + struct sde_rotation_config *config) +{ + memset(config, 0, sizeof(struct sde_rotation_config)); + config->flags = sde_rotator_get_flags_from_ctx(ctx); + config->frame_rate = (ctx->timeperframe.numerator) ? + ctx->timeperframe.denominator + / ctx->timeperframe.numerator : 0; + config->session_id = ctx->session_id; + config->input.width = ctx->crop_out.width; + config->input.height = ctx->crop_out.height; + config->input.format = ctx->format_out.fmt.pix.pixelformat; + config->input.comp_ratio.numer = 1; + config->input.comp_ratio.denom = 1; + config->output.width = ctx->crop_cap.width; + config->output.height = ctx->crop_cap.height; + config->output.format = ctx->format_cap.fmt.pix.pixelformat; + config->output.comp_ratio.numer = 1; + config->output.comp_ratio.denom = 1; + + /* + * Use compression ratio of the first buffer to estimate + * performance requirement of the session. If core layer does + * not support dynamic per buffer compression ratio recalculation, + * this configuration will determine the overall static compression + * ratio of the session. + */ + if (ctx->vbinfo_out) + config->input.comp_ratio = ctx->vbinfo_out[0].comp_ratio; + if (ctx->vbinfo_cap) + config->output.comp_ratio = ctx->vbinfo_cap[0].comp_ratio; + + SDEDEV_DBG(ctx->rot_dev->dev, "config s:%d out_cr:%u/%u cap_cr:%u/%u\n", + ctx->session_id, + config->input.comp_ratio.numer, + config->input.comp_ratio.denom, + config->output.comp_ratio.numer, + config->output.comp_ratio.denom); +} + +/* + * sde_rotator_get_item_from_ctx - Fill rotator item structure. + * @ctx: Pointer to rotator ctx. + * @item: Pointer to item structure. + */ +static void sde_rotator_get_item_from_ctx(struct sde_rotator_ctx *ctx, + struct sde_rotation_item *item) +{ + memset(item, 0, sizeof(struct sde_rotation_item)); + item->flags = sde_rotator_get_flags_from_ctx(ctx); + item->session_id = ctx->session_id; + item->sequence_id = 0; + /* assign high/low priority */ + item->wb_idx = (ctx->fh.prio >= V4L2_PRIORITY_DEFAULT) ? 0 : 1; + item->src_rect.x = ctx->crop_out.left; + item->src_rect.y = ctx->crop_out.top; + item->src_rect.w = ctx->crop_out.width; + item->src_rect.h = ctx->crop_out.height; + item->input.width = ctx->format_out.fmt.pix.width; + item->input.height = ctx->format_out.fmt.pix.height; + item->input.format = ctx->format_out.fmt.pix.pixelformat; + item->input.planes[0].fd = -1; + item->input.planes[0].offset = 0; + item->input.planes[0].stride = ctx->format_out.fmt.pix.bytesperline; + item->input.plane_count = 1; + item->input.fence = NULL; + item->input.comp_ratio.numer = 1; + item->input.comp_ratio.denom = 1; + + item->dst_rect.x = ctx->crop_cap.left; + item->dst_rect.y = ctx->crop_cap.top; + item->dst_rect.w = ctx->crop_cap.width; + item->dst_rect.h = ctx->crop_cap.height; + item->output.width = ctx->format_cap.fmt.pix.width; + item->output.height = ctx->format_cap.fmt.pix.height; + item->output.format = ctx->format_cap.fmt.pix.pixelformat; + item->output.planes[0].fd = -1; + item->output.planes[0].offset = 0; + item->output.planes[0].stride = ctx->format_cap.fmt.pix.bytesperline; + item->output.plane_count = 1; + item->output.fence = NULL; + item->output.comp_ratio.numer = 1; + item->output.comp_ratio.denom = 1; +} + +/* + * sde_rotator_format_recalc - Recalculate format parameters. + * @f: v4l2 format. + */ +static void sde_rotator_format_recalc(struct v4l2_format *f) +{ + int ret; + struct sde_mdp_format_params *fmt; + struct sde_mdp_plane_sizes ps; + + fmt = sde_get_format_params(f->fmt.pix.pixelformat); + if (!fmt) { + SDEROT_ERR("invalid format\n"); + goto error_fmt; + } + + ret = sde_mdp_get_plane_sizes(fmt, + f->fmt.pix.width, f->fmt.pix.height, &ps, 0, 0); + if (ret) { + SDEROT_ERR("invalid plane size\n"); + goto error_fmt; + } + + f->fmt.pix.bytesperline = ps.ystride[0]; + f->fmt.pix.sizeimage = ps.total_size; + + return; +error_fmt: + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = 0; +} + +/* + * sde_rotator_validate_item - Check if rotator item is valid for processing. + * @ctx: Pointer to rotator ctx. + * @item: Pointer to item structure + */ +static int sde_rotator_validate_item(struct sde_rotator_ctx *ctx, + struct sde_rotation_item *item) +{ + int ret; + struct sde_rot_entry_container *req; + struct sde_rotator_device *rot_dev = ctx->rot_dev; + + sde_rot_mgr_lock(rot_dev->mgr); + req = sde_rotator_req_init(rot_dev->mgr, ctx->private, item, 1, 0); + if (IS_ERR_OR_NULL(req)) { + SDEDEV_ERR(rot_dev->dev, "fail allocate item\n"); + return -ENOMEM; + } + + ret = sde_rotator_validate_request(rot_dev->mgr, ctx->private, req); + sde_rot_mgr_unlock(rot_dev->mgr); + devm_kfree(rot_dev->dev, req); + return ret; +} + +/* + * sde_rotator_queue_setup - vb2_ops queue_setup callback. + * @q: Pointer to vb2 queue struct. + * @num_buffers: Pointer of number of buffers requested. + * @num_planes: Pointer to number of planes requested. + * @sizes: Array containing sizes of planes. + * @alloc_ctxs: Array of allocated contexts for each plane. + */ +static int sde_rotator_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q); + int i; + + if (!num_buffers) + return -EINVAL; + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + sizes[0] = ctx->format_out.fmt.pix.sizeimage; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + sizes[0] = ctx->format_cap.fmt.pix.sizeimage; + break; + default: + return -EINVAL; + } + + *num_planes = 1; + alloc_devs[0] = (struct device *)ctx; + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + ctx->nbuf_out = *num_buffers; + kfree(ctx->vbinfo_out); + ctx->vbinfo_out = kcalloc(ctx->nbuf_out, + sizeof(struct sde_rotator_vbinfo), GFP_KERNEL); + if (!ctx->vbinfo_out) + return -ENOMEM; + for (i = 0; i < ctx->nbuf_out; i++) { + ctx->vbinfo_out[i].fd = -1; + ctx->vbinfo_out[i].comp_ratio.numer = 1; + ctx->vbinfo_out[i].comp_ratio.denom = 1; + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + ctx->nbuf_cap = *num_buffers; + kfree(ctx->vbinfo_cap); + ctx->vbinfo_cap = kcalloc(ctx->nbuf_cap, + sizeof(struct sde_rotator_vbinfo), GFP_KERNEL); + if (!ctx->vbinfo_cap) + return -ENOMEM; + for (i = 0; i < ctx->nbuf_cap; i++) { + ctx->vbinfo_cap[i].fd = -1; + ctx->vbinfo_cap[i].comp_ratio.numer = 1; + ctx->vbinfo_cap[i].comp_ratio.denom = 1; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * sde_rotator_buf_queue - vb2_ops buf_queue callback. + * @vb: Pointer to vb2 buffer struct. + */ +static void sde_rotator_buf_queue(struct vb2_buffer *vb) +{ + struct sde_rotator_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +/* + * sde_rotator_buf_finish - vb2_ops buf_finish to finalize buffer before going + * back to user space + * @vb: Pointer to vb2 buffer struct. + */ +static void sde_rotator_buf_finish(struct vb2_buffer *vb) +{ + struct sde_rotator_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + int i; + + SDEDEV_DBG(ctx->rot_dev->dev, + "buf_finish t:%d i:%d s:%d m:%u np:%d up:%lu\n", + vb->type, vb->index, vb->state, + vb->vb2_queue->memory, + vb->num_planes, + vb->planes[0].m.userptr); + + if (vb->vb2_queue->memory != VB2_MEMORY_USERPTR) + return; + + /* + * We use userptr to tunnel fd, and fd can be the same across qbuf + * even though the underlying buffer is different. Since vb2 layer + * optimizes memory mapping for userptr by first checking if userptr + * has changed, it will not trigger put_userptr if fd value does + * not change. In order to force buffer release, we need to clear + * userptr when the current buffer is done and ready to go back to + * user mode. Since 0 is a valid fd, reset userptr to -1 instead. + */ + for (i = 0; i < vb->num_planes; i++) + vb->planes[i].m.userptr = ~0; +} + +/* + * sde_rotator_return_all_buffers - Return all buffers with the given status. + * @q: Pointer to vb2 buffer queue struct. + * @state: State of the buffer + */ +static void sde_rotator_return_all_buffers(struct vb2_queue *q, + enum vb2_buffer_state state) +{ + struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + + SDEDEV_DBG(rot_dev->dev, + "return q t:%d c:%d dc:%d s:%d\n", + q->type, q->queued_count, + atomic_read(&q->owned_by_drv_count), + state); + + /* return buffers according videobuffer2-core.h */ + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) { + SDEDEV_DBG(rot_dev->dev, + "return vb t:%d i:%d\n", + buf->vb2_buf.type, + buf->vb2_buf.index); + v4l2_m2m_buf_done(buf, state); + } + } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + struct vb2_v4l2_buffer *buf; + + while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) { + SDEDEV_DBG(rot_dev->dev, + "return vb t:%d i:%d\n", + buf->vb2_buf.type, + buf->vb2_buf.index); + v4l2_m2m_buf_done(buf, state); + } + } else { + SDEDEV_ERR(rot_dev->dev, "unsupported vb t:%d\n", q->type); + } +} + +/* + * sde_rotator_start_streaming - vb2_ops start_streaming callback. + * @q: Pointer to vb2 queue struct. + * @count: Number of buffer queued before stream on call. + */ +static int sde_rotator_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + + SDEDEV_DBG(rot_dev->dev, "start streaming s:%d t:%d\n", + ctx->session_id, q->type); + + if (!list_empty(&ctx->pending_list)) { + SDEDEV_ERR(rot_dev->dev, + "command pending error s:%d t:%d p:%d\n", + ctx->session_id, q->type, + !list_empty(&ctx->pending_list)); + return -EINVAL; + } + + ctx->abort_pending = 0; + + return 0; +} + +/* + * sde_rotator_stop_streaming - vb2_ops stop_streaming callback. + * @q: Pointer to vb2 queue struct. + * + * This function will block waiting for stream to stop. Unlock queue + * lock to avoid deadlock. + */ +static void sde_rotator_stop_streaming(struct vb2_queue *q) +{ + struct sde_rotator_ctx *ctx = vb2_get_drv_priv(q); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotator_request *request; + struct list_head *curr, *next; + int i; + int ret; + + SDEDEV_DBG(rot_dev->dev, "stop streaming s:%d t:%d p:%d\n", + ctx->session_id, q->type, + !list_empty(&ctx->pending_list)); + ctx->abort_pending = 1; + mutex_unlock(q->lock); + ret = wait_event_timeout(ctx->wait_queue, + list_empty(&ctx->pending_list), + msecs_to_jiffies(rot_dev->streamoff_timeout)); + mutex_lock(q->lock); + if (!ret) { + SDEDEV_ERR(rot_dev->dev, + "timeout to stream off s:%d t:%d p:%d\n", + ctx->session_id, q->type, + !list_empty(&ctx->pending_list)); + SDEROT_EVTLOG(ctx->session_id, q->type, + !list_empty(&ctx->pending_list), + SDE_ROT_EVTLOG_ERROR); + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private); + sde_rot_mgr_unlock(rot_dev->mgr); + list_for_each_safe(curr, next, &ctx->pending_list) { + request = container_of(curr, struct sde_rotator_request, + list); + + SDEDEV_DBG(rot_dev->dev, "cancel request s:%d\n", + ctx->session_id); + mutex_unlock(q->lock); + kthread_cancel_work_sync(&request->submit_work); + kthread_cancel_work_sync(&request->retire_work); + mutex_lock(q->lock); + spin_lock(&ctx->list_lock); + list_del_init(&request->list); + list_add_tail(&request->list, &ctx->retired_list); + spin_unlock(&ctx->list_lock); + } + } + + sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR); + + /* clear fence for buffer */ + sde_rotator_resync_timeline(ctx->work_queue.timeline); + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + for (i = 0; i < ctx->nbuf_cap; i++) { + struct sde_rotator_vbinfo *vbinfo = + &ctx->vbinfo_cap[i]; + + if (vbinfo->fence) { + /* fence is not used */ + SDEDEV_DBG(rot_dev->dev, + "put fence s:%d t:%d i:%d\n", + ctx->session_id, q->type, i); + sde_rotator_put_sync_fence(vbinfo->fence); + } + vbinfo->fence = NULL; + vbinfo->fd = -1; + } + } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + for (i = 0; i < ctx->nbuf_out; i++) { + struct sde_rotator_vbinfo *vbinfo = + &ctx->vbinfo_out[i]; + + if (vbinfo->fence) { + SDEDEV_DBG(rot_dev->dev, + "put fence s:%d t:%d i:%d\n", + ctx->session_id, q->type, i); + sde_rotator_put_sync_fence(vbinfo->fence); + } + vbinfo->fence = NULL; + vbinfo->fd = -1; + } + } +} + +/* Videobuf2 queue callbacks. */ +static const struct vb2_ops sde_rotator_vb2_q_ops = { + .queue_setup = sde_rotator_queue_setup, + .buf_queue = sde_rotator_buf_queue, + .start_streaming = sde_rotator_start_streaming, + .stop_streaming = sde_rotator_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_finish = sde_rotator_buf_finish, +}; + +/* + * sde_rotator_get_userptr - Map and get buffer handler for user pointer buffer. + * @dev: device allocated in buf_setup. + * @vaddr: Virtual addr passed from userpsace (in our case ion fd) + * @size: Size of the buffer + * @dma_dir: DMA data direction of the given buffer. + */ +static void *sde_rotator_get_userptr(struct device *dev, + unsigned long vaddr, unsigned long size, + enum dma_data_direction dma_dir) +{ + struct sde_rotator_ctx *ctx = (struct sde_rotator_ctx *)dev; + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotator_buf_handle *buf; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + buf->fd = vaddr; + buf->secure = ctx->secure || ctx->secure_camera; + buf->ctx = ctx; + buf->rot_dev = rot_dev; + buf->size = size; + buf->buffer = dma_buf_get(buf->fd); + if (IS_ERR_OR_NULL(buf->buffer)) { + SDEDEV_ERR(rot_dev->dev, + "fail get dmabuf fd:%d r:%ld\n", + buf->fd, PTR_ERR(buf->buffer)); + goto error_buf_get; + } + SDEDEV_DBG(rot_dev->dev, + "get dmabuf s:%d fd:%d buf:%pad\n", + buf->ctx->session_id, + buf->fd, &buf->buffer); + + return buf; +error_buf_get: + kfree(buf); + return ERR_PTR(-ENOMEM); +} + +/* + * sde_rotator_put_userptr - Unmap and free buffer handler. + * @buf_priv: Buffer handler allocated get_userptr callback. + */ +static void sde_rotator_put_userptr(void *buf_priv) +{ + struct sde_rotator_buf_handle *buf = buf_priv; + + if (IS_ERR_OR_NULL(buf)) + return; + + if (!buf->rot_dev || !buf->ctx) { + WARN_ON(!buf->rot_dev || !buf->ctx); + SDEROT_ERR("null rotator device/context\n"); + return; + } + + SDEDEV_DBG(buf->rot_dev->dev, "put dmabuf s:%d fd:%d buf:%pad\n", + buf->ctx->session_id, + buf->fd, &buf->buffer); + + if (buf->buffer) { + dma_buf_put(buf->buffer); + buf->buffer = NULL; + } + + kfree(buf_priv); +} + +/* Videobuf2 memory callbacks. */ +static struct vb2_mem_ops sde_rotator_vb2_mem_ops = { + .get_userptr = sde_rotator_get_userptr, + .put_userptr = sde_rotator_put_userptr, +}; + +/* + * sde_rotator_s_ctx_ctrl - set context control variable to v4l2 control + * @ctx: Pointer to rotator context. + * @ctx_ctrl: Pointer to context control variable + * @ctrl: Pointer to v4l2 control variable + */ +static int sde_rotator_s_ctx_ctrl(struct sde_rotator_ctx *ctx, + s32 *ctx_ctrl, struct v4l2_ctrl *ctrl) +{ + *ctx_ctrl = ctrl->val; + return 0; +} + +/* + * sde_rotator_s_ctrl - Set control. + * @ctrl: Pointer to v4l2 control structure. + */ +static int sde_rotator_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct sde_rotator_ctx *ctx = + container_of(ctrl->handler, + struct sde_rotator_ctx, ctrl_handler); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + int ret; + + SDEDEV_DBG(rot_dev->dev, "set %s:%d s:%d\n", ctrl->name, ctrl->val, + ctx->session_id); + + sde_rot_mgr_lock(rot_dev->mgr); + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->hflip, ctrl); + break; + + case V4L2_CID_VFLIP: + ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->vflip, ctrl); + break; + + case V4L2_CID_ROTATE: + ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->rotate, ctrl); + break; + + case V4L2_CID_SDE_ROTATOR_SECURE: + ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->secure, ctrl); + break; + + case V4L2_CID_SDE_ROTATOR_SECURE_CAMERA: + ret = sde_rotator_s_ctx_ctrl(ctx, &ctx->secure_camera, ctrl); + break; + default: + v4l2_warn(&rot_dev->v4l2_dev, "invalid control %d\n", ctrl->id); + ret = -EINVAL; + } + + sde_rot_mgr_unlock(rot_dev->mgr); + return ret; +} + +/* + * sde_rotator_ctrl_ops - Control operations. + */ +static const struct v4l2_ctrl_ops sde_rotator_ctrl_ops = { + .s_ctrl = sde_rotator_s_ctrl, +}; + +/* + * sde_rotator_ctrl_secure - Non-secure/Secure. + */ +static const struct v4l2_ctrl_config sde_rotator_ctrl_secure = { + .ops = &sde_rotator_ctrl_ops, + .id = V4L2_CID_SDE_ROTATOR_SECURE, + .name = "Non-secure/Secure Domain", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = 0, + .min = 0, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config sde_rotator_ctrl_secure_camera = { + .ops = &sde_rotator_ctrl_ops, + .id = V4L2_CID_SDE_ROTATOR_SECURE_CAMERA, + .name = "Secure Camera content", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = 0, + .min = 0, + .max = 1, + .step = 1, +}; + +/* + * sde_rotator_ctx_show - show context state. + */ +static ssize_t sde_rotator_ctx_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + size_t len = PAGE_SIZE; + int cnt = 0; + struct sde_rotator_ctx *ctx = + container_of(kobj, struct sde_rotator_ctx, kobj); + + if (!ctx) + return cnt; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + SPRINT("rotate=%d\n", ctx->rotate); + SPRINT("hflip=%d\n", ctx->hflip); + SPRINT("vflip=%d\n", ctx->vflip); + SPRINT("priority=%d\n", ctx->fh.prio); + SPRINT("secure=%d\n", ctx->secure); + SPRINT("timeperframe=%u %u\n", ctx->timeperframe.numerator, + ctx->timeperframe.denominator); + SPRINT("nbuf_out=%d\n", ctx->nbuf_out); + SPRINT("nbuf_cap=%d\n", ctx->nbuf_cap); + SPRINT("crop_out=%u %u %u %u\n", + ctx->crop_out.left, ctx->crop_out.top, + ctx->crop_out.width, ctx->crop_out.height); + SPRINT("crop_cap=%u %u %u %u\n", + ctx->crop_cap.left, ctx->crop_cap.top, + ctx->crop_cap.width, ctx->crop_cap.height); + SPRINT("fmt_out=%c%c%c%c %u %u %u %u\n", + (ctx->format_out.fmt.pix.pixelformat>>0)&0xff, + (ctx->format_out.fmt.pix.pixelformat>>8)&0xff, + (ctx->format_out.fmt.pix.pixelformat>>16)&0xff, + (ctx->format_out.fmt.pix.pixelformat>>24)&0xff, + ctx->format_out.fmt.pix.width, + ctx->format_out.fmt.pix.height, + ctx->format_out.fmt.pix.bytesperline, + ctx->format_out.fmt.pix.sizeimage); + SPRINT("fmt_cap=%c%c%c%c %u %u %u %u\n", + (ctx->format_cap.fmt.pix.pixelformat>>0)&0xff, + (ctx->format_cap.fmt.pix.pixelformat>>8)&0xff, + (ctx->format_cap.fmt.pix.pixelformat>>16)&0xff, + (ctx->format_cap.fmt.pix.pixelformat>>24)&0xff, + ctx->format_cap.fmt.pix.width, + ctx->format_cap.fmt.pix.height, + ctx->format_cap.fmt.pix.bytesperline, + ctx->format_cap.fmt.pix.sizeimage); + SPRINT("abort_pending=%d\n", ctx->abort_pending); + SPRINT("command_pending=%d\n", !list_empty(&ctx->pending_list)); + SPRINT("sequence=%u\n", + sde_rotator_get_timeline_commit_ts(ctx->work_queue.timeline)); + SPRINT("timestamp=%u\n", + sde_rotator_get_timeline_retire_ts(ctx->work_queue.timeline)); + return cnt; +} + +static struct kobj_attribute sde_rotator_ctx_attr = + __ATTR(state, 0664, sde_rotator_ctx_show, NULL); + +static struct attribute *sde_rotator_fs_attrs[] = { + &sde_rotator_ctx_attr.attr, + NULL +}; + +static struct attribute_group sde_rotator_fs_attr_group = { + .attrs = sde_rotator_fs_attrs +}; + +/* + * sde_rotator_ctx_show - sysfs show callback. + */ +static ssize_t sde_rotator_fs_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + ssize_t ret = -EIO; + struct kobj_attribute *kattr = + container_of(attr, struct kobj_attribute, attr); + if (kattr->show) + ret = kattr->show(kobj, kattr, buf); + return ret; +} + +/* + * sde_rotator_fs_store - sysfs store callback. + */ +static ssize_t sde_rotator_fs_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t count) +{ + ssize_t ret = -EIO; + struct kobj_attribute *kattr = + container_of(attr, struct kobj_attribute, attr); + if (kattr->store) + ret = kattr->store(kobj, kattr, buf, count); + return ret; +} + +static const struct sysfs_ops sde_rotator_fs_ops = { + .show = sde_rotator_fs_show, + .store = sde_rotator_fs_store, +}; + +static struct kobj_type sde_rotator_fs_ktype = { + .sysfs_ops = &sde_rotator_fs_ops, +}; + +/* + * sde_rotator_queue_init - m2m_ops queue_setup callback. + * @priv: Pointer to rotator ctx. + * @src_vq: vb2 source queue. + * @dst_vq: vb2 destination queue. + */ +static int sde_rotator_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct sde_rotator_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->mem_ops = &sde_rotator_vb2_mem_ops; + src_vq->ops = &sde_rotator_vb2_q_ops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->rot_dev->lock; + src_vq->min_buffers_needed = 1; + src_vq->dev = ctx->rot_dev->dev; + + ret = vb2_queue_init(src_vq); + if (ret) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail init src queue r:%d\n", ret); + return ret; + } + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->mem_ops = &sde_rotator_vb2_mem_ops; + dst_vq->ops = &sde_rotator_vb2_q_ops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->rot_dev->lock; + dst_vq->min_buffers_needed = 1; + src_vq->dev = ctx->rot_dev->dev; + + ret = vb2_queue_init(dst_vq); + if (ret) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail init dst queue r:%d\n", ret); + return ret; + } + + return 0; +} + +/* + * sde_rotator_ctx_open - Rotator device open method. + * @rot_dev: Pointer to rotator device structure + * @file: Pointer to file struct (optional) + * return: Pointer rotator context if success; ptr error code, otherwise. + */ +struct sde_rotator_ctx *sde_rotator_ctx_open( + struct sde_rotator_device *rot_dev, struct file *file) +{ + struct video_device *video = file ? video_devdata(file) : NULL; + struct sde_rotator_ctx *ctx; + struct v4l2_ctrl_handler *ctrl_handler; + char name[32]; + int i, ret; + + if (atomic_read(&rot_dev->mgr->device_suspended)) + return ERR_PTR(-EPERM); + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + if (mutex_lock_interruptible(&rot_dev->lock)) { + ret = -ERESTARTSYS; + goto error_lock; + } + + /* wait until exclusive ctx, if exists, finishes or timeout */ + while (rot_dev->excl_ctx) { + SDEROT_DBG("waiting to open %s session %d ...\n", + file ? "v4l2" : "excl", rot_dev->session_id); + mutex_unlock(&rot_dev->lock); + ret = wait_event_interruptible_timeout(rot_dev->open_wq, + !rot_dev->excl_ctx, + msecs_to_jiffies(rot_dev->open_timeout)); + if (ret < 0) { + goto error_lock; + } else if (!ret) { + SDEROT_WARN("timeout to open session %d\n", + rot_dev->session_id); + SDEROT_EVTLOG(rot_dev->session_id, + SDE_ROT_EVTLOG_ERROR); + ret = -EBUSY; + goto error_lock; + } else if (mutex_lock_interruptible(&rot_dev->lock)) { + ret = -ERESTARTSYS; + goto error_lock; + } + } + + ctx->rot_dev = rot_dev; + ctx->file = file; + + /* Set context defaults */ + ctx->session_id = rot_dev->session_id++; + SDEDEV_DBG(ctx->rot_dev->dev, "open %d\n", ctx->session_id); + ctx->timeperframe.numerator = 1; + ctx->timeperframe.denominator = SDE_ROTATOR_DEFAULT_FPS; + ctx->hflip = 0; + ctx->vflip = 0; + ctx->rotate = 0; + ctx->secure = 0; + ctx->abort_pending = 0; + ctx->kthread_id = -1; + ctx->format_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ctx->format_cap.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2; + ctx->format_cap.fmt.pix.width = 640; + ctx->format_cap.fmt.pix.height = 480; + ctx->crop_cap.width = 640; + ctx->crop_cap.height = 480; + ctx->format_out.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ctx->format_out.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2; + ctx->format_out.fmt.pix.width = 640; + ctx->format_out.fmt.pix.height = 480; + ctx->crop_out.width = 640; + ctx->crop_out.height = 480; + init_waitqueue_head(&ctx->wait_queue); + spin_lock_init(&ctx->list_lock); + INIT_LIST_HEAD(&ctx->pending_list); + INIT_LIST_HEAD(&ctx->retired_list); + + for (i = 0 ; i < ARRAY_SIZE(ctx->requests); i++) { + struct sde_rotator_request *request = &ctx->requests[i]; + + kthread_init_work(&request->submit_work, + sde_rotator_submit_handler); + kthread_init_work(&request->retire_work, + sde_rotator_retire_handler); + request->ctx = ctx; + INIT_LIST_HEAD(&request->list); + list_add_tail(&request->list, &ctx->retired_list); + } + + if (ctx->file) { + v4l2_fh_init(&ctx->fh, video); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rot_dev->m2m_dev, + ctx, sde_rotator_queue_init); + if (IS_ERR_OR_NULL(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + ctx->fh.m2m_ctx = NULL; + goto error_m2m_init; + } + } + + ret = kobject_init_and_add(&ctx->kobj, &sde_rotator_fs_ktype, + &rot_dev->dev->kobj, "session_%d", ctx->session_id); + if (ret) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail initialize context kobject\n"); + goto error_kobj_init; + } + + ret = sysfs_create_group(&ctx->kobj, &sde_rotator_fs_attr_group); + if (ret) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail register rotator sysfs nodes\n"); + goto error_create_sysfs; + } + + for (i = 0; i < MAX_ROT_OPEN_SESSION; i++) { + if (rot_dev->kthread_free[i]) { + rot_dev->kthread_free[i] = false; + ctx->kthread_id = i; + ctx->work_queue.rot_kw = &rot_dev->rot_kw[i]; + ctx->work_queue.rot_thread = rot_dev->rot_thread[i]; + break; + } + } + + if (ctx->kthread_id < 0) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail to acquire the kthread\n"); + ret = -EINVAL; + goto error_alloc_kthread; + } + + snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id, + ctx->session_id); + ctx->work_queue.timeline = sde_rotator_create_timeline(name); + if (!ctx->work_queue.timeline) + SDEDEV_DBG(ctx->rot_dev->dev, "timeline is not available\n"); + + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_pm_qos_request(rot_dev, + SDE_ROTATOR_ADD_REQUEST); + ret = sde_rotator_session_open(rot_dev->mgr, &ctx->private, + ctx->session_id, &ctx->work_queue); + if (ret < 0) { + SDEDEV_ERR(ctx->rot_dev->dev, "fail open session\n"); + goto error_open_session; + } + sde_rot_mgr_unlock(rot_dev->mgr); + + if (ctx->file) { + /* Create control */ + ctrl_handler = &ctx->ctrl_handler; + v4l2_ctrl_handler_init(ctrl_handler, 4); + v4l2_ctrl_new_std(ctrl_handler, + &sde_rotator_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(ctrl_handler, + &sde_rotator_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(ctrl_handler, + &sde_rotator_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); + v4l2_ctrl_new_custom(ctrl_handler, + &sde_rotator_ctrl_secure, NULL); + v4l2_ctrl_new_custom(ctrl_handler, + &sde_rotator_ctrl_secure_camera, NULL); + if (ctrl_handler->error) { + ret = ctrl_handler->error; + v4l2_ctrl_handler_free(ctrl_handler); + goto error_ctrl_handler; + } + ctx->fh.ctrl_handler = ctrl_handler; + v4l2_ctrl_handler_setup(ctrl_handler); + } else { + /* acquire exclusive context */ + SDEDEV_DBG(rot_dev->dev, "acquire exclusive session id:%u\n", + ctx->session_id); + SDEROT_EVTLOG(ctx->session_id); + rot_dev->excl_ctx = ctx; + } + + mutex_unlock(&rot_dev->lock); + + SDEDEV_DBG(ctx->rot_dev->dev, "SDE v4l2 rotator open success\n"); + + ATRACE_BEGIN(ctx->kobj.name); + + return ctx; +error_ctrl_handler: +error_open_session: + sde_rot_mgr_unlock(rot_dev->mgr); + sde_rotator_destroy_timeline(ctx->work_queue.timeline); + rot_dev->kthread_free[ctx->kthread_id] = true; + ctx->kthread_id = -1; +error_alloc_kthread: + sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); +error_create_sysfs: + kobject_put(&ctx->kobj); +error_kobj_init: + if (ctx->file) { + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + ctx->fh.m2m_ctx = NULL; + } +error_m2m_init: + if (ctx->file) { + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + } + mutex_unlock(&rot_dev->lock); +error_lock: + kfree(ctx); + ctx = NULL; + return ERR_PTR(ret); +} + +/* + * sde_rotator_ctx_release - Rotator device release method. + * @ctx: Pointer rotator context. + * @file: Pointer to file struct (optional) + * return: 0 if success; error code, otherwise + */ +static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, + struct file *file) +{ + struct sde_rotator_device *rot_dev; + u32 session_id; + struct list_head *curr, *next; + + if (!ctx) { + SDEROT_DBG("ctx is NULL\n"); + return -EINVAL; + } + + rot_dev = ctx->rot_dev; + session_id = ctx->session_id; + + ATRACE_END(ctx->kobj.name); + + SDEDEV_DBG(rot_dev->dev, "release s:%d\n", session_id); + mutex_lock(&rot_dev->lock); + if (rot_dev->excl_ctx == ctx) { + SDEDEV_DBG(rot_dev->dev, "release exclusive session id:%u\n", + session_id); + SDEROT_EVTLOG(session_id); + rot_dev->excl_ctx = NULL; + } + if (ctx->file) { + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + SDEDEV_DBG(rot_dev->dev, "release streams s:%d\n", session_id); + if (ctx->fh.m2m_ctx) { + v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT); + v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + } + } + mutex_unlock(&rot_dev->lock); + SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id); + list_for_each_safe(curr, next, &ctx->pending_list) { + struct sde_rotator_request *request = + container_of(curr, struct sde_rotator_request, list); + + SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", + session_id); + kthread_cancel_work_sync(&request->submit_work); + } + SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id); + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_pm_qos_request(rot_dev, + SDE_ROTATOR_REMOVE_REQUEST); + sde_rotator_session_close(rot_dev->mgr, ctx->private, session_id); + sde_rot_mgr_unlock(rot_dev->mgr); + SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n", session_id); + list_for_each_safe(curr, next, &ctx->pending_list) { + struct sde_rotator_request *request = + container_of(curr, struct sde_rotator_request, list); + + SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n", + session_id); + kthread_cancel_work_sync(&request->retire_work); + } + mutex_lock(&rot_dev->lock); + SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id); + sde_rotator_destroy_timeline(ctx->work_queue.timeline); + if (ctx->kthread_id >= 0 && ctx->work_queue.rot_kw) { + kthread_flush_worker(ctx->work_queue.rot_kw); + rot_dev->kthread_free[ctx->kthread_id] = true; + } + sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); + kobject_put(&ctx->kobj); + if (ctx->file) { + if (ctx->fh.m2m_ctx) + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + if (ctx->fh.vdev) { + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + } + } + kfree(ctx->vbinfo_out); + kfree(ctx->vbinfo_cap); + kfree(ctx); + wake_up_interruptible(&rot_dev->open_wq); + mutex_unlock(&rot_dev->lock); + SDEDEV_DBG(rot_dev->dev, "release complete s:%d\n", session_id); + return 0; +} + +/* + * sde_rotator_update_retire_sequence - update retired sequence of the context + * referenced in the request, and wake up any waiting for update event + * @request: Pointer to rotator request + */ +static void sde_rotator_update_retire_sequence( + struct sde_rotator_request *request) +{ + struct sde_rotator_ctx *ctx; + + if (!request || !request->ctx) { + SDEROT_ERR("invalid parameters\n"); + return; + } + + ctx = request->ctx; + ctx->retired_sequence_id = request->sequence_id; + + wake_up(&ctx->wait_queue); + + SDEROT_DBG("update sequence s:%d.%d\n", + ctx->session_id, ctx->retired_sequence_id); +} + +/* + * sde_rotator_retire_request - retire the given rotator request with + * device mutex locked + * @request: Pointer to rotator request + */ +static void sde_rotator_retire_request(struct sde_rotator_request *request) +{ + struct sde_rotator_ctx *ctx; + + if (!request || !request->ctx) { + SDEROT_ERR("invalid parameters\n"); + return; + } + + ctx = request->ctx; + + request->req = NULL; + request->sequence_id = 0; + request->committed = false; + spin_lock(&ctx->list_lock); + list_del_init(&request->list); + list_add_tail(&request->list, &ctx->retired_list); + spin_unlock(&ctx->list_lock); + + wake_up(&ctx->wait_queue); + + SDEROT_DBG("retire request s:%d.%d\n", + ctx->session_id, ctx->retired_sequence_id); +} + +/* + * sde_rotator_is_request_retired - Return true if given request already expired + * @request: Pointer to rotator request + */ +static bool sde_rotator_is_request_retired(struct sde_rotator_request *request) +{ + struct sde_rotator_ctx *ctx; + u32 sequence_id; + s32 retire_delta; + + if (!request || !request->ctx) + return true; + + ctx = request->ctx; + sequence_id = request->sequence_id; + + retire_delta = (s32) (ctx->retired_sequence_id - sequence_id); + + SDEROT_DBG("sequence:%u/%u\n", sequence_id, ctx->retired_sequence_id); + + return retire_delta >= 0; +} + +static void sde_rotator_pm_qos_remove(struct sde_rot_data_type *rot_mdata) +{ + struct pm_qos_request *req; + u32 cpu_mask; + + if (!rot_mdata) { + SDEROT_DBG("invalid rot device or context\n"); + return; + } + + cpu_mask = rot_mdata->rot_pm_qos_cpu_mask; + + if (!cpu_mask) + return; + + req = &rot_mdata->pm_qos_rot_cpu_req; + pm_qos_remove_request(req); +} + +void sde_rotator_pm_qos_add(struct sde_rot_data_type *rot_mdata) +{ + struct pm_qos_request *req; + u32 cpu_mask; + int cpu; + + if (!rot_mdata) { + SDEROT_DBG("invalid rot device or context\n"); + return; + } + + cpu_mask = rot_mdata->rot_pm_qos_cpu_mask; + + if (!cpu_mask) + return; + + req = &rot_mdata->pm_qos_rot_cpu_req; + req->type = PM_QOS_REQ_AFFINE_CORES; + cpumask_empty(&req->cpus_affine); + for_each_possible_cpu(cpu) { + if ((1 << cpu) & cpu_mask) + cpumask_set_cpu(cpu, &req->cpus_affine); + } + pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + + SDEROT_DBG("rotator pmqos add mask %x latency %x\n", + rot_mdata->rot_pm_qos_cpu_mask, + rot_mdata->rot_pm_qos_cpu_dma_latency); +} + +static void sde_rotator_pm_qos_request(struct sde_rotator_device *rot_dev, + bool add_request) +{ + u32 cpu_mask; + u32 cpu_dma_latency; + bool changed = false; + + if (!rot_dev) { + SDEROT_DBG("invalid rot device or context\n"); + return; + } + + cpu_mask = rot_dev->mdata->rot_pm_qos_cpu_mask; + cpu_dma_latency = rot_dev->mdata->rot_pm_qos_cpu_dma_latency; + + if (!cpu_mask) + return; + + if (add_request) { + if (rot_dev->mdata->rot_pm_qos_cpu_count == 0) + changed = true; + rot_dev->mdata->rot_pm_qos_cpu_count++; + } else { + if (rot_dev->mdata->rot_pm_qos_cpu_count != 0) { + rot_dev->mdata->rot_pm_qos_cpu_count--; + if (rot_dev->mdata->rot_pm_qos_cpu_count == 0) + changed = true; + } else { + SDEROT_DBG("%s: ref_count is not balanced\n", + __func__); + } + } + + if (!changed) + return; + + SDEROT_EVTLOG(add_request, cpu_mask, cpu_dma_latency); + + if (!add_request) { + pm_qos_update_request(&rot_dev->mdata->pm_qos_rot_cpu_req, + PM_QOS_DEFAULT_VALUE); + return; + } + + pm_qos_update_request(&rot_dev->mdata->pm_qos_rot_cpu_req, + cpu_dma_latency); +} + +/* + * sde_rotator_inline_open - open inline rotator session + * @pdev: Pointer to rotator platform device + * @video_mode: true if video mode is requested + * return: Pointer to new rotator session context + */ +void *sde_rotator_inline_open(struct platform_device *pdev) +{ + struct sde_rotator_device *rot_dev; + struct sde_rotator_ctx *ctx; + int rc; + + if (!pdev) { + SDEROT_ERR("invalid platform device\n"); + return ERR_PTR(-EINVAL); + } + + rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev); + if (!rot_dev) { + SDEROT_ERR("invalid rotator device\n"); + return ERR_PTR(-EINVAL); + } + + ctx = sde_rotator_ctx_open(rot_dev, NULL); + if (IS_ERR_OR_NULL(ctx)) { + rc = PTR_ERR(ctx); + SDEROT_ERR("failed to open rotator context %d\n", rc); + goto rotator_open_error; + } + + ctx->slice = llcc_slice_getd(LLCC_ROTATOR); + if (IS_ERR(ctx->slice)) { + rc = PTR_ERR(ctx->slice); + SDEROT_ERR("failed to get system cache %d\n", rc); + goto slice_getd_error; + } + + if (!rot_dev->disable_syscache) { + rc = llcc_slice_activate(ctx->slice); + if (rc) { + SDEROT_ERR("failed to activate slice %d\n", rc); + goto activate_error; + } + SDEROT_DBG("scid %d size %zukb\n", + llcc_get_slice_id(ctx->slice), + llcc_get_slice_size(ctx->slice)); + } else { + SDEROT_DBG("syscache bypassed\n"); + } + + SDEROT_EVTLOG(ctx->session_id, llcc_get_slice_id(ctx->slice), + llcc_get_slice_size(ctx->slice), + rot_dev->disable_syscache); + + return ctx; + +activate_error: + llcc_slice_putd(ctx->slice); + ctx->slice = NULL; +slice_getd_error: + sde_rotator_ctx_release(ctx, NULL); +rotator_open_error: + return ERR_PTR(rc); +} +EXPORT_SYMBOL(sde_rotator_inline_open); + +int sde_rotator_inline_release(void *handle) +{ + struct sde_rotator_device *rot_dev; + struct sde_rotator_ctx *ctx; + + if (!handle) { + SDEROT_ERR("invalid rotator ctx\n"); + return -EINVAL; + } + + ctx = handle; + rot_dev = ctx->rot_dev; + + if (!rot_dev) { + SDEROT_ERR("invalid rotator device\n"); + return -EINVAL; + } + + if (ctx->slice) { + if (!rot_dev->disable_syscache) + llcc_slice_deactivate(ctx->slice); + llcc_slice_putd(ctx->slice); + ctx->slice = NULL; + } + + SDEROT_EVTLOG(ctx->session_id); + + return sde_rotator_ctx_release(ctx, NULL); +} +EXPORT_SYMBOL(sde_rotator_inline_release); + +/* + * sde_rotator_inline_get_dst_pixfmt - determine output pixel format + * @pdev: Pointer to platform device + * @src_pixfmt: input pixel format + * @dst_pixfmt: Pointer to output pixel format (output) + * return: 0 if success; error code otherwise + */ +int sde_rotator_inline_get_dst_pixfmt(struct platform_device *pdev, + u32 src_pixfmt, u32 *dst_pixfmt) +{ + int rc; + + if (!src_pixfmt || !dst_pixfmt) + return -EINVAL; + + rc = sde_rot_get_base_tilea5x_pixfmt(src_pixfmt, dst_pixfmt); + if (rc) + return rc; + + /* + * Currently, NV21 tile is not supported as output; hence, + * override with NV12 tile. + */ + if (*dst_pixfmt == SDE_PIX_FMT_Y_CRCB_H2V2_TILE) + *dst_pixfmt = SDE_PIX_FMT_Y_CBCR_H2V2_TILE; + + return 0; +} +EXPORT_SYMBOL(sde_rotator_inline_get_dst_pixfmt); + +/* + * sde_rotator_inline_get_downscale_caps - get scaling capability + * @pdev: Pointer to platform device + * @caps: string buffer for capability + * @len: length of string buffer + * return: length of capability string + */ +int sde_rotator_inline_get_downscale_caps(struct platform_device *pdev, + char *caps, int len) +{ + struct sde_rotator_device *rot_dev; + int rc; + + if (!pdev) { + SDEROT_ERR("invalid platform device\n"); + return -EINVAL; + } + + rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev); + if (!rot_dev || !rot_dev->mgr) { + SDEROT_ERR("invalid rotator device\n"); + return -EINVAL; + } + + sde_rot_mgr_lock(rot_dev->mgr); + rc = sde_rotator_get_downscale_caps(rot_dev->mgr, caps, len); + sde_rot_mgr_unlock(rot_dev->mgr); + + return rc; +} +EXPORT_SYMBOL(sde_rotator_inline_get_downscale_caps); + +/* + * sde_rotator_inline_get_maxlinewidth - get maximum line width of rotator + * @pdev: Pointer to platform device + * return: maximum line width + */ +int sde_rotator_inline_get_maxlinewidth(struct platform_device *pdev) +{ + struct sde_rotator_device *rot_dev; + int maxlinewidth; + + if (!pdev) { + SDEROT_ERR("invalid platform device\n"); + return -EINVAL; + } + + rot_dev = (struct sde_rotator_device *)platform_get_drvdata(pdev); + if (!rot_dev || !rot_dev->mgr) { + SDEROT_ERR("invalid rotator device\n"); + return -EINVAL; + } + + sde_rot_mgr_lock(rot_dev->mgr); + maxlinewidth = sde_rotator_get_maxlinewidth(rot_dev->mgr); + sde_rot_mgr_unlock(rot_dev->mgr); + + return maxlinewidth; +} +EXPORT_SYMBOL(sde_rotator_inline_get_maxlinewidth); + +/* + * sde_rotator_inline_get_pixfmt_caps - get pixel format capability + * @pdev: Pointer to platform device + * @pixfmt: array of pixel format buffer + * @len: length of pixel format buffer + * return: length of pixel format capability if success; error code otherwise + */ +int sde_rotator_inline_get_pixfmt_caps(struct platform_device *pdev, + bool input, u32 *pixfmts, int len) +{ + struct sde_rotator_device *rot_dev; + u32 i, pixfmt; + + if (!pdev) { + SDEROT_ERR("invalid platform device\n"); + return -EINVAL; + } + + rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev); + if (!rot_dev || !rot_dev->mgr) { + SDEROT_ERR("invalid rotator device\n"); + return -EINVAL; + } + + sde_rot_mgr_lock(rot_dev->mgr); + for (i = 0;; i++) { + pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, input, + SDE_ROTATOR_MODE_SBUF); + if (!pixfmt) + break; + if (pixfmts && i < len) + pixfmts[i] = pixfmt; + } + sde_rot_mgr_unlock(rot_dev->mgr); + + return i; +} +EXPORT_SYMBOL(sde_rotator_inline_get_pixfmt_caps); + +/* + * _sde_rotator_inline_cleanup - perform inline related request cleanup + * This function assumes rot_dev->mgr lock has been taken when called. + * @handle: Pointer to rotator context + * @request: Pointer to rotation request + * return: 0 if success; -EAGAIN if cleanup should be retried + */ +static int _sde_rotator_inline_cleanup(void *handle, + struct sde_rotator_request *request) +{ + struct sde_rotator_ctx *ctx; + struct sde_rotator_device *rot_dev; + int ret; + + if (!handle || !request) { + SDEROT_ERR("invalid rotator handle/request\n"); + return -EINVAL; + } + + ctx = handle; + rot_dev = ctx->rot_dev; + + if (!rot_dev || !rot_dev->mgr) { + SDEROT_ERR("invalid rotator device\n"); + return -EINVAL; + } + + if (request->committed) { + /* wait until request is finished */ + sde_rot_mgr_unlock(rot_dev->mgr); + mutex_unlock(&rot_dev->lock); + ret = wait_event_timeout(ctx->wait_queue, + sde_rotator_is_request_retired(request), + msecs_to_jiffies(rot_dev->streamoff_timeout)); + mutex_lock(&rot_dev->lock); + sde_rot_mgr_lock(rot_dev->mgr); + + if (!ret) { + SDEROT_ERR("timeout w/o retire s:%d\n", + ctx->session_id); + SDEROT_EVTLOG(ctx->session_id, SDE_ROT_EVTLOG_ERROR); + sde_rotator_abort_inline_request(rot_dev->mgr, + ctx->private, request->req); + return -EAGAIN; + } else if (ret == 1) { + SDEROT_ERR("timeout w/ retire s:%d\n", ctx->session_id); + SDEROT_EVTLOG(ctx->session_id, SDE_ROT_EVTLOG_ERROR); + } + } + + sde_rotator_req_finish(rot_dev->mgr, ctx->private, request->req); + sde_rotator_retire_request(request); + return 0; +} + +/* + * sde_rotator_inline_commit - commit given rotator command + * @handle: Pointer to rotator context + * @cmd: Pointer to rotator command + * @cmd_type: command type - validate/prepare/commit/cleanup + * return: 0 if success; error code otherwise + */ +int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd, + enum sde_rotator_inline_cmd_type cmd_type) +{ + struct sde_rotator_ctx *ctx; + struct sde_rotator_device *rot_dev; + struct sde_rotator_request *request = NULL; + struct sde_rot_entry_container *req = NULL; + struct sde_rotation_config rotcfg; + struct sde_rot_trace_entry rot_trace; + ktime_t *ts; + u32 flags = 0; + int i, ret = 0; + + if (!handle || !cmd) { + SDEROT_ERR("invalid rotator handle/cmd\n"); + return -EINVAL; + } + + ctx = handle; + rot_dev = ctx->rot_dev; + + if (!rot_dev || !rot_dev->mgr) { + SDEROT_ERR("invalid rotator device\n"); + return -EINVAL; + } + + SDEROT_DBG( + "s:%d.%u src:(%u,%u,%u,%u)/%ux%u/%c%c%c%c dst:(%u,%u,%u,%u)/%c%c%c%c r:%d f:%d/%d s:%d fps:%u clk:%llu bw:%llu prefill:%llu wb:%d vid:%d cmd:%d\n", + ctx->session_id, cmd->sequence_id, + cmd->src_rect_x, cmd->src_rect_y, + cmd->src_rect_w, cmd->src_rect_h, + cmd->src_width, cmd->src_height, + cmd->src_pixfmt >> 0, cmd->src_pixfmt >> 8, + cmd->src_pixfmt >> 16, cmd->src_pixfmt >> 24, + cmd->dst_rect_x, cmd->dst_rect_y, + cmd->dst_rect_w, cmd->dst_rect_h, + cmd->dst_pixfmt >> 0, cmd->dst_pixfmt >> 8, + cmd->dst_pixfmt >> 16, cmd->dst_pixfmt >> 24, + cmd->rot90, cmd->hflip, cmd->vflip, cmd->secure, cmd->fps, + cmd->clkrate, cmd->data_bw, cmd->prefill_bw, + cmd->dst_writeback, cmd->video_mode, cmd_type); + SDEROT_EVTLOG(ctx->session_id, cmd->sequence_id, + cmd->src_rect_x, cmd->src_rect_y, + cmd->src_rect_w, cmd->src_rect_h, + cmd->src_pixfmt, + cmd->dst_rect_w, cmd->dst_rect_h, + cmd->dst_pixfmt, + cmd->fps, cmd->clkrate, cmd->data_bw, cmd->prefill_bw, + (cmd->rot90 << 0) | (cmd->hflip << 1) | (cmd->vflip << 2) | + (cmd->secure << 3) | (cmd->dst_writeback << 4) | + (cmd->video_mode << 5) | + (cmd_type << 24)); + + mutex_lock(&rot_dev->lock); + sde_rot_mgr_lock(rot_dev->mgr); + + if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE || + cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) { + + struct sde_rotation_item item; + struct sde_rotator_statistics *stats = &rot_dev->stats; + int scid = llcc_get_slice_id(ctx->slice); + + /* allocate slot for timestamp */ + ts = stats->ts[stats->count % SDE_ROTATOR_NUM_EVENTS]; + if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) + stats->count++; + + if (cmd->rot90) + flags |= SDE_ROTATION_90; + if (cmd->hflip) + flags |= SDE_ROTATION_FLIP_LR; + if (cmd->vflip) + flags |= SDE_ROTATION_FLIP_UD; + if (cmd->secure) + flags |= SDE_ROTATION_SECURE; + + flags |= SDE_ROTATION_EXT_PERF; + + /* fill in item work structure */ + memset(&item, 0, sizeof(struct sde_rotation_item)); + item.flags = flags | SDE_ROTATION_EXT_IOVA; + item.trigger = cmd->video_mode ? SDE_ROTATOR_TRIGGER_VIDEO : + SDE_ROTATOR_TRIGGER_COMMAND; + item.prefill_bw = cmd->prefill_bw; + item.session_id = ctx->session_id; + item.sequence_id = cmd->sequence_id; + item.src_rect.x = cmd->src_rect_x; + item.src_rect.y = cmd->src_rect_y; + item.src_rect.w = cmd->src_rect_w; + item.src_rect.h = cmd->src_rect_h; + item.input.width = cmd->src_width; + item.input.height = cmd->src_height; + item.input.format = cmd->src_pixfmt; + + for (i = 0; i < SDE_ROTATOR_INLINE_PLANE_MAX; i++) { + item.input.planes[i].addr = cmd->src_addr[i]; + item.input.planes[i].len = cmd->src_len[i]; + item.input.planes[i].fd = -1; + } + item.input.plane_count = cmd->src_planes; + item.input.comp_ratio.numer = 1; + item.input.comp_ratio.denom = 1; + + item.output.width = cmd->dst_rect_x + cmd->dst_rect_w; + item.output.height = cmd->dst_rect_y + cmd->dst_rect_h; + item.dst_rect.x = cmd->dst_rect_x; + item.dst_rect.y = cmd->dst_rect_y; + item.dst_rect.w = cmd->dst_rect_w; + item.dst_rect.h = cmd->dst_rect_h; + item.output.sbuf = true; + item.output.scid = scid; + item.output.writeback = cmd->dst_writeback; + item.output.format = cmd->dst_pixfmt; + + for (i = 0; i < SDE_ROTATOR_INLINE_PLANE_MAX; i++) { + item.output.planes[i].addr = cmd->dst_addr[i]; + item.output.planes[i].len = cmd->dst_len[i]; + item.output.planes[i].fd = -1; + } + item.output.plane_count = cmd->dst_planes; + item.output.comp_ratio.numer = 1; + item.output.comp_ratio.denom = 1; + item.sequence_id = ++(ctx->commit_sequence_id); + item.ts = ts; + + req = sde_rotator_req_init(rot_dev->mgr, ctx->private, + &item, 1, 0); + if (IS_ERR_OR_NULL(req)) { + SDEROT_ERR("fail allocate request s:%d\n", + ctx->session_id); + ret = -ENOMEM; + goto error_init_request; + } + + /* initialize session configuration */ + memset(&rotcfg, 0, sizeof(struct sde_rotation_config)); + rotcfg.flags = flags; + rotcfg.frame_rate = cmd->fps; + rotcfg.clk_rate = cmd->clkrate; + rotcfg.data_bw = cmd->data_bw; + rotcfg.session_id = ctx->session_id; + rotcfg.input.width = cmd->src_rect_w; + rotcfg.input.height = cmd->src_rect_h; + rotcfg.input.format = cmd->src_pixfmt; + rotcfg.input.comp_ratio.numer = 1; + rotcfg.input.comp_ratio.denom = 1; + rotcfg.output.width = cmd->dst_rect_w; + rotcfg.output.height = cmd->dst_rect_h; + rotcfg.output.format = cmd->dst_pixfmt; + rotcfg.output.comp_ratio.numer = 1; + rotcfg.output.comp_ratio.denom = 1; + rotcfg.output.sbuf = true; + } + + if (cmd_type == SDE_ROTATOR_INLINE_CMD_VALIDATE) { + + ret = sde_rotator_session_validate(rot_dev->mgr, + ctx->private, &rotcfg); + if (ret) { + SDEROT_WARN("fail session validation s:%d\n", + ctx->session_id); + goto error_session_validate; + } + + devm_kfree(rot_dev->dev, req); + req = NULL; + + } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_COMMIT) { + + if (memcmp(&rotcfg, &ctx->rotcfg, sizeof(rotcfg))) { + ret = sde_rotator_session_config(rot_dev->mgr, + ctx->private, &rotcfg); + if (ret) { + SDEROT_ERR("fail session config s:%d\n", + ctx->session_id); + goto error_session_config; + } + + ctx->rotcfg = rotcfg; + } + + request = list_first_entry_or_null(&ctx->retired_list, + struct sde_rotator_request, list); + if (!request) { + /* should not happen */ + ret = -ENOMEM; + SDEROT_ERR("no free request s:%d\n", ctx->session_id); + goto error_retired_list; + } + + request->req = req; + request->sequence_id = req->entries[0].item.sequence_id; + + spin_lock(&ctx->list_lock); + list_del_init(&request->list); + list_add_tail(&request->list, &ctx->pending_list); + spin_unlock(&ctx->list_lock); + + ts = req->entries[0].item.ts; + if (ts) { + ts[SDE_ROTATOR_TS_SRCQB] = ktime_get(); + ts[SDE_ROTATOR_TS_DSTQB] = ktime_get(); + ts[SDE_ROTATOR_TS_FENCE] = ktime_get(); + } else { + SDEROT_ERR("invalid stats timestamp\n"); + } + req->retire_kw = ctx->work_queue.rot_kw; + req->retire_work = &request->retire_work; + + /* Set values to pass to trace */ + rot_trace.wb_idx = req->entries[0].item.wb_idx; + rot_trace.flags = req->entries[0].item.flags; + rot_trace.input_format = req->entries[0].item.input.format; + rot_trace.input_width = req->entries[0].item.input.width; + rot_trace.input_height = req->entries[0].item.input.height; + rot_trace.src_x = req->entries[0].item.src_rect.x; + rot_trace.src_y = req->entries[0].item.src_rect.y; + rot_trace.src_w = req->entries[0].item.src_rect.w; + rot_trace.src_h = req->entries[0].item.src_rect.h; + rot_trace.output_format = req->entries[0].item.output.format; + rot_trace.output_width = req->entries[0].item.output.width; + rot_trace.output_height = req->entries[0].item.output.height; + rot_trace.dst_x = req->entries[0].item.dst_rect.x; + rot_trace.dst_y = req->entries[0].item.dst_rect.y; + rot_trace.dst_w = req->entries[0].item.dst_rect.w; + rot_trace.dst_h = req->entries[0].item.dst_rect.h; + + + trace_rot_entry_fence( + ctx->session_id, cmd->sequence_id, &rot_trace); + + ret = sde_rotator_handle_request_common( + rot_dev->mgr, ctx->private, req); + if (ret) { + SDEROT_ERR("fail handle request s:%d\n", + ctx->session_id); + goto error_handle_request; + } + + sde_rotator_req_reset_start(rot_dev->mgr, req); + + sde_rotator_queue_request(rot_dev->mgr, ctx->private, req); + + request->committed = true; + + /* save request in private handle */ + cmd->priv_handle = request; + + } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_START) { + if (!cmd->priv_handle) { + ret = -EINVAL; + SDEROT_ERR("invalid private handle\n"); + goto error_invalid_handle; + } + + request = cmd->priv_handle; + sde_rotator_req_set_start(rot_dev->mgr, request->req); + } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_CLEANUP) { + if (!cmd->priv_handle) { + ret = -EINVAL; + SDEROT_ERR("invalid private handle\n"); + goto error_invalid_handle; + } + + request = cmd->priv_handle; + + /* attempt single retry if first cleanup attempt failed */ + if (_sde_rotator_inline_cleanup(handle, request) == -EAGAIN) + _sde_rotator_inline_cleanup(handle, request); + + cmd->priv_handle = NULL; + } else if (cmd_type == SDE_ROTATOR_INLINE_CMD_ABORT) { + if (!cmd->priv_handle) { + ret = -EINVAL; + SDEROT_ERR("invalid private handle\n"); + goto error_invalid_handle; + } + + request = cmd->priv_handle; + if (!sde_rotator_is_request_retired(request)) + sde_rotator_abort_inline_request(rot_dev->mgr, + ctx->private, request->req); + } + + sde_rot_mgr_unlock(rot_dev->mgr); + mutex_unlock(&rot_dev->lock); + return 0; + +error_handle_request: + sde_rotator_update_retire_sequence(request); + sde_rotator_retire_request(request); +error_retired_list: +error_session_validate: +error_session_config: + devm_kfree(rot_dev->dev, req); +error_invalid_handle: +error_init_request: + sde_rot_mgr_unlock(rot_dev->mgr); + mutex_unlock(&rot_dev->lock); + return ret; +} +EXPORT_SYMBOL(sde_rotator_inline_commit); + +void sde_rotator_inline_reg_dump(struct platform_device *pdev) +{ + struct sde_rotator_device *rot_dev; + + if (!pdev) { + SDEROT_ERR("invalid platform device\n"); + return; + } + + rot_dev = (struct sde_rotator_device *) platform_get_drvdata(pdev); + if (!rot_dev || !rot_dev->mgr) { + SDEROT_ERR("invalid rotator device\n"); + return; + } + + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_core_dump(rot_dev->mgr); + sde_rot_mgr_unlock(rot_dev->mgr); +} +EXPORT_SYMBOL(sde_rotator_inline_reg_dump); + +/* + * sde_rotator_open - Rotator device open method. + * @file: Pointer to file struct. + */ +static int sde_rotator_open(struct file *file) +{ + struct sde_rotator_device *rot_dev = video_drvdata(file); + struct sde_rotator_ctx *ctx; + int ret = 0; + + ctx = sde_rotator_ctx_open(rot_dev, file); + if (IS_ERR_OR_NULL(ctx)) { + SDEDEV_DBG(rot_dev->dev, "failed to open %d\n", ret); + ret = PTR_ERR(ctx); + } + + return ret; +} + +/* + * sde_rotator_release - Rotator device release method. + * @file: Pointer to file struct. + */ +static int sde_rotator_release(struct file *file) +{ + struct sde_rotator_ctx *ctx = + sde_rotator_ctx_from_fh(file->private_data); + + return sde_rotator_ctx_release(ctx, file); +} + +/* + * sde_rotator_poll - rotator device pool method. + * @file: Pointer to file struct. + * @wait: Pointer to poll table struct. + */ +static unsigned int sde_rotator_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct sde_rotator_device *rot_dev = video_drvdata(file); + struct sde_rotator_ctx *ctx = + sde_rotator_ctx_from_fh(file->private_data); + int ret; + + mutex_lock(&rot_dev->lock); + ret = v4l2_m2m_poll(file, ctx->fh.m2m_ctx, wait); + mutex_unlock(&rot_dev->lock); + return ret; +} + +/* rotator device file operations callbacks */ +static const struct v4l2_file_operations sde_rotator_fops = { + .owner = THIS_MODULE, + .open = sde_rotator_open, + .release = sde_rotator_release, + .poll = sde_rotator_poll, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = sde_rotator_compat_ioctl32, +#endif +}; + +/* + * sde_rotator_querycap - V4l2 ioctl query capability handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @cap: Pointer to v4l2_capability struct need to be filled. + */ +static int sde_rotator_querycap(struct file *file, + void *fh, struct v4l2_capability *cap) +{ + cap->bus_info[0] = 0; + strlcpy(cap->driver, SDE_ROTATOR_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->card, SDE_ROTATOR_DRV_NAME, sizeof(cap->card)); + cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M | + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +/* + * sde_rotator_enum_fmt_vid_cap - V4l2 ioctl enumerate output format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_fmtdesc struct need to be filled. + */ +static int sde_rotator_enum_fmt_vid_cap(struct file *file, + void *fh, struct v4l2_fmtdesc *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_mdp_format_params *fmt; + u32 i, index, pixfmt; + bool found = false; + + for (i = 0, index = 0; index <= f->index; i++) { + pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, false, + SDE_ROTATOR_MODE_OFFLINE); + if (!pixfmt) + return -EINVAL; + + fmt = sde_get_format_params(pixfmt); + if (!fmt) + return -EINVAL; + + if (sde_mdp_is_private_format(fmt)) + continue; + + if (index == f->index) { + found = true; + break; + } + + index++; + } + + if (!found) + return -EINVAL; + + f->pixelformat = pixfmt; + strlcpy(f->description, fmt->description, sizeof(f->description)); + + return 0; +} + +/* + * sde_rotator_enum_fmt_vid_out - V4l2 ioctl enumerate capture format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_fmtdesc struct need to be filled. + */ +static int sde_rotator_enum_fmt_vid_out(struct file *file, + void *fh, struct v4l2_fmtdesc *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_mdp_format_params *fmt; + u32 i, index, pixfmt; + bool found = false; + + for (i = 0, index = 0; index <= f->index; i++) { + pixfmt = sde_rotator_get_pixfmt(rot_dev->mgr, i, true, + SDE_ROTATOR_MODE_OFFLINE); + if (!pixfmt) + return -EINVAL; + + fmt = sde_get_format_params(pixfmt); + if (!fmt) + return -EINVAL; + + if (sde_mdp_is_private_format(fmt)) + continue; + + if (index == f->index) { + found = true; + break; + } + + index++; + } + + if (!found) + return -EINVAL; + + f->pixelformat = pixfmt; + strlcpy(f->description, fmt->description, sizeof(f->description)); + + return 0; +} + +/* + * sde_rotator_g_fmt_cap - V4l2 ioctl get capture format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_format struct need to be filled. + */ +static int sde_rotator_g_fmt_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + *f = ctx->format_cap; + + return 0; +} + +/* + * sde_rotator_g_fmt_out - V4l2 ioctl get output format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_format struct need to be filled. + */ +static int sde_rotator_g_fmt_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + *f = ctx->format_out; + + return 0; +} + +/* + * sde_rotator_try_fmt_vid_cap - V4l2 ioctl try capture format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_format struct. + */ +static int sde_rotator_try_fmt_vid_cap(struct file *file, + void *fh, struct v4l2_format *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotation_config config; + int ret; + + if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0)) { + SDEDEV_WARN(ctx->rot_dev->dev, + "Not supporting 0 width/height: %dx%d\n", + f->fmt.pix.width, f->fmt.pix.height); + return -EINVAL; + } + + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_get_config_from_ctx(ctx, &config); + config.output.format = f->fmt.pix.pixelformat; + config.output.width = f->fmt.pix.width; + config.output.height = f->fmt.pix.height; + config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY; + ret = sde_rotator_verify_config_output(rot_dev->mgr, &config); + sde_rot_mgr_unlock(rot_dev->mgr); + if (ret) { + if ((config.output.width == f->fmt.pix.width) && + (config.output.height == f->fmt.pix.height)) { + SDEDEV_WARN(ctx->rot_dev->dev, + "invalid capture format 0x%8.8x %dx%d\n", + f->fmt.pix.pixelformat, + f->fmt.pix.width, + f->fmt.pix.height); + return -EINVAL; + } + f->fmt.pix.width = config.output.width; + f->fmt.pix.height = config.output.height; + } + + sde_rotator_format_recalc(f); + return ret; +} + +/* + * sde_rotator_try_fmt_vid_out - V4l2 ioctl try output format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_format struct. + */ +static int sde_rotator_try_fmt_vid_out(struct file *file, + void *fh, struct v4l2_format *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotation_config config; + int ret; + + if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0)) { + SDEDEV_WARN(ctx->rot_dev->dev, + "Not supporting 0 width/height: %dx%d\n", + f->fmt.pix.width, f->fmt.pix.height); + return -EINVAL; + } + + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_get_config_from_ctx(ctx, &config); + config.input.format = f->fmt.pix.pixelformat; + config.input.width = f->fmt.pix.width; + config.input.height = f->fmt.pix.height; + config.flags |= SDE_ROTATION_VERIFY_INPUT_ONLY; + ret = sde_rotator_verify_config_input(rot_dev->mgr, &config); + sde_rot_mgr_unlock(rot_dev->mgr); + if (ret) { + if ((config.input.width == f->fmt.pix.width) && + (config.input.height == f->fmt.pix.height)) { + SDEDEV_WARN(ctx->rot_dev->dev, + "invalid output format 0x%8.8x %dx%d\n", + f->fmt.pix.pixelformat, + f->fmt.pix.width, + f->fmt.pix.height); + return -EINVAL; + } + f->fmt.pix.width = config.input.width; + f->fmt.pix.height = config.input.height; + } + + sde_rotator_format_recalc(f); + return ret; +} + +/* + * sde_rotator_s_fmt_vid_cap - V4l2 ioctl set capture format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_format struct. + */ +static int sde_rotator_s_fmt_vid_cap(struct file *file, + void *fh, struct v4l2_format *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + int ret; + + ret = sde_rotator_try_fmt_vid_cap(file, fh, f); + if (ret) + return -EINVAL; + + /* Initialize crop */ + ctx->crop_cap.top = 0; + ctx->crop_cap.left = 0; + ctx->crop_cap.width = f->fmt.pix.width; + ctx->crop_cap.height = f->fmt.pix.height; + + ctx->format_cap = *f; + + SDEDEV_DBG(rot_dev->dev, + "s_fmt s:%d t:%d fmt:0x%8.8x field:%u (%u,%u)\n", + ctx->session_id, f->type, + f->fmt.pix.pixelformat, + f->fmt.pix.field, + f->fmt.pix.width, f->fmt.pix.height); + + return 0; +} + +/* + * sde_rotator_s_fmt_vid_out - V4l2 ioctl set output format handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @f: Pointer to v4l2_format struct. + */ +static int sde_rotator_s_fmt_vid_out(struct file *file, + void *fh, struct v4l2_format *f) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + int ret; + + ret = sde_rotator_try_fmt_vid_out(file, fh, f); + if (ret) + return -EINVAL; + + /* Initialize crop */ + ctx->crop_out.top = 0; + ctx->crop_out.left = 0; + ctx->crop_out.width = f->fmt.pix.width; + ctx->crop_out.height = f->fmt.pix.height; + + ctx->format_out = *f; + + SDEDEV_DBG(rot_dev->dev, + "s_fmt s:%d t:%d fmt:0x%8.8x field:%u (%u,%u)\n", + ctx->session_id, f->type, + f->fmt.pix.pixelformat, + f->fmt.pix.field, + f->fmt.pix.width, f->fmt.pix.height); + + return 0; +} + +/* + * sde_rotator_reqbufs - V4l2 ioctl request buffers handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @req: Pointer to v4l2_requestbuffer struct. + */ +static int sde_rotator_reqbufs(struct file *file, + void *fh, struct v4l2_requestbuffers *req) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + return v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, req); +} + +/* + * sde_rotator_qbuf - V4l2 ioctl queue buffer handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @buf: Pointer to v4l2_buffer struct. + */ +static int sde_rotator_qbuf(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + int ret; + + /* create fence for capture buffer */ + if ((buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + && (buf->index < ctx->nbuf_cap)) { + int idx = buf->index; + + ctx->vbinfo_cap[idx].fd = -1; + ctx->vbinfo_cap[idx].fence = sde_rotator_get_sync_fence( + ctx->work_queue.timeline, NULL, + &ctx->vbinfo_cap[idx].fence_ts); + ctx->vbinfo_cap[idx].qbuf_ts = ktime_get(); + ctx->vbinfo_cap[idx].dqbuf_ts = NULL; + SDEDEV_DBG(ctx->rot_dev->dev, + "create buffer fence s:%d.%u i:%d f:%pK\n", + ctx->session_id, + ctx->vbinfo_cap[idx].fence_ts, + idx, + ctx->vbinfo_cap[idx].fence); + } else if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + && (buf->index < ctx->nbuf_out)) { + int idx = buf->index; + + ctx->vbinfo_out[idx].qbuf_ts = ktime_get(); + ctx->vbinfo_out[idx].dqbuf_ts = NULL; + } + + ret = v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); + if (ret < 0) + SDEDEV_ERR(ctx->rot_dev->dev, "fail qbuf s:%d t:%d r:%d\n", + ctx->session_id, buf->type, ret); + SDEROT_EVTLOG(buf->type, buf->bytesused, buf->length, buf->m.fd, ret); + + return ret; +} + +/* + * sde_rotator_dqbuf - V4l2 ioctl dequeue buffer handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @buf: Pointer to v4l2_buffer struct. + */ +static int sde_rotator_dqbuf(struct file *file, + void *fh, struct v4l2_buffer *buf) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + int ret; + + ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); + + if (ret) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail dqbuf s:%d t:%d i:%d r:%d\n", + ctx->session_id, buf->type, buf->index, ret); + return ret; + } + + /* clear fence for buffer */ + if ((buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + && (buf->index < ctx->nbuf_cap)) { + int idx = buf->index; + + if (ctx->vbinfo_cap[idx].fence) { + /* fence is not used */ + SDEDEV_DBG(ctx->rot_dev->dev, "put fence s:%d i:%d\n", + ctx->session_id, idx); + sde_rotator_put_sync_fence(ctx->vbinfo_cap[idx].fence); + } + ctx->vbinfo_cap[idx].fence = NULL; + ctx->vbinfo_cap[idx].fd = -1; + if (ctx->vbinfo_cap[idx].dqbuf_ts) + *(ctx->vbinfo_cap[idx].dqbuf_ts) = ktime_get(); + } else if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + && (buf->index < ctx->nbuf_out)) { + int idx = buf->index; + + ctx->vbinfo_out[idx].fence = NULL; + ctx->vbinfo_out[idx].fd = -1; + if (ctx->vbinfo_out[idx].dqbuf_ts) + *(ctx->vbinfo_out[idx].dqbuf_ts) = ktime_get(); + } else { + SDEDEV_WARN(ctx->rot_dev->dev, "invalid dq s:%d t:%d i:%d\n", + ctx->session_id, buf->type, buf->index); + } + + return 0; +} + +/* + * sde_rotator_querybuf - V4l2 ioctl query buffer handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @buf: Pointer to v4l2_buffer struct. + */ +static int sde_rotator_querybuf(struct file *file, + void *fh, struct v4l2_buffer *buf) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + return v4l2_m2m_querybuf(file, ctx->fh.m2m_ctx, buf); +} + +/* + * sde_rotator_streamon - V4l2 ioctl stream on handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @buf_type: V4l2 buffer type. + */ +static int sde_rotator_streamon(struct file *file, + void *fh, enum v4l2_buf_type buf_type) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotation_config config; + struct vb2_queue *vq; + int ret; + + SDEDEV_DBG(ctx->rot_dev->dev, "stream on s:%d t:%d\n", + ctx->session_id, buf_type); + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? + V4L2_BUF_TYPE_VIDEO_CAPTURE : + V4L2_BUF_TYPE_VIDEO_OUTPUT); + + if (!vq) { + SDEDEV_ERR(ctx->rot_dev->dev, "fail to get vq on s:%d t:%d\n", + ctx->session_id, buf_type); + return -EINVAL; + } + + if (vb2_is_streaming(vq)) { + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_get_config_from_ctx(ctx, &config); + config.flags &= ~SDE_ROTATION_VERIFY_INPUT_ONLY; + ret = sde_rotator_session_config(rot_dev->mgr, ctx->private, + &config); + sde_rot_mgr_unlock(rot_dev->mgr); + if (ret < 0) { + SDEDEV_ERR(rot_dev->dev, + "fail config in stream on s:%d t:%d r:%d\n", + ctx->session_id, buf_type, ret); + return ret; + } + ctx->rotcfg = config; + } + + ret = v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, buf_type); + if (ret < 0) + SDEDEV_ERR(ctx->rot_dev->dev, "fail stream on s:%d t:%d\n", + ctx->session_id, buf_type); + + return ret; +} + +/* + * sde_rotator_streamoff - V4l2 ioctl stream off handler. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @buf_type: V4l2 buffer type. + */ +static int sde_rotator_streamoff(struct file *file, + void *fh, enum v4l2_buf_type buf_type) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + int ret; + + SDEDEV_DBG(ctx->rot_dev->dev, "stream off s:%d t:%d\n", + ctx->session_id, buf_type); + + ret = v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, buf_type); + if (ret < 0) + SDEDEV_ERR(ctx->rot_dev->dev, "fail stream off s:%d t:%d\n", + ctx->session_id, buf_type); + + return ret; +} + +/* + * sde_rotator_cropcap - V4l2 ioctl crop capabilities. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @a: Pointer to v4l2_cropcap struct need to be set. + */ +static int sde_rotator_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *a) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct v4l2_format *format; + struct v4l2_rect *crop; + + switch (a->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + format = &ctx->format_out; + crop = &ctx->crop_out; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + format = &ctx->format_cap; + crop = &ctx->crop_cap; + break; + default: + return -EINVAL; + } + + a->bounds.top = 0; + a->bounds.left = 0; + a->bounds.width = format->fmt.pix.width; + a->bounds.height = format->fmt.pix.height; + + a->defrect = *crop; + + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + SDEROT_EVTLOG(format->fmt.pix.width, format->fmt.pix.height, a->type); + return 0; +} + +/* + * sde_rotator_g_crop - V4l2 ioctl get crop. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @crop: Pointer to v4l2_crop struct need to be set. + */ +static int sde_rotator_g_crop(struct file *file, void *fh, + struct v4l2_crop *crop) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + switch (crop->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + crop->c = ctx->crop_out; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + crop->c = ctx->crop_cap; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * sde_rotator_s_crop - V4l2 ioctl set crop. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @crop: Pointer to v4l2_crop struct need to be set. + */ +static int sde_rotator_s_crop(struct file *file, void *fh, + const struct v4l2_crop *crop) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotation_item item; + struct v4l2_rect rect; + + sde_rotator_get_item_from_ctx(ctx, &item); + + rect.left = max_t(__u32, crop->c.left, 0); + rect.top = max_t(__u32, crop->c.top, 0); + rect.height = max_t(__u32, crop->c.height, 0); + rect.width = max_t(__u32, crop->c.width, 0); + + if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + rect.left = min_t(__u32, rect.left, + ctx->format_out.fmt.pix.width - 1); + rect.top = min_t(__u32, rect.top, + ctx->format_out.fmt.pix.height - 1); + rect.width = min_t(__u32, rect.width, + (ctx->format_out.fmt.pix.width - rect.left)); + rect.height = min_t(__u32, rect.height, + (ctx->format_out.fmt.pix.height - rect.top)); + + item.src_rect.x = rect.left; + item.src_rect.y = rect.top; + item.src_rect.w = rect.width; + item.src_rect.h = rect.height; + + sde_rotator_validate_item(ctx, &item); + + SDEDEV_DBG(rot_dev->dev, + "s_crop s:%d t:%d (%u,%u,%u,%u)->(%u,%u,%u,%u)\n", + ctx->session_id, crop->type, + crop->c.left, crop->c.top, + crop->c.width, crop->c.height, + item.src_rect.x, item.src_rect.y, + item.src_rect.w, item.src_rect.h); + + ctx->crop_out.left = item.src_rect.x; + ctx->crop_out.top = item.src_rect.y; + ctx->crop_out.width = item.src_rect.w; + ctx->crop_out.height = item.src_rect.h; + } else if (crop->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + rect.left = min_t(__u32, rect.left, + ctx->format_cap.fmt.pix.width - 1); + rect.top = min_t(__u32, rect.top, + ctx->format_cap.fmt.pix.height - 1); + rect.width = min_t(__u32, rect.width, + (ctx->format_cap.fmt.pix.width - rect.left)); + rect.height = min_t(__u32, rect.height, + (ctx->format_cap.fmt.pix.height - rect.top)); + + item.dst_rect.x = rect.left; + item.dst_rect.y = rect.top; + item.dst_rect.w = rect.width; + item.dst_rect.h = rect.height; + + sde_rotator_validate_item(ctx, &item); + + SDEDEV_DBG(rot_dev->dev, + "s_crop s:%d t:%d (%u,%u,%u,%u)->(%u,%u,%u,%u)\n", + ctx->session_id, crop->type, + crop->c.left, crop->c.top, + crop->c.width, crop->c.height, + item.dst_rect.x, item.dst_rect.y, + item.dst_rect.w, item.dst_rect.h); + + ctx->crop_cap.left = item.dst_rect.x; + ctx->crop_cap.top = item.dst_rect.y; + ctx->crop_cap.width = item.dst_rect.w; + ctx->crop_cap.height = item.dst_rect.h; + } else { + return -EINVAL; + } + + return 0; +} + +/* + * sde_rotator_g_parm - V4l2 ioctl get parm. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @a: Pointer to v4l2_streamparm struct need to be filled. + */ +static int sde_rotator_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + /* Get param is supported only for input buffers */ + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + a->parm.output.capability = 0; + a->parm.output.extendedmode = 0; + a->parm.output.outputmode = 0; + a->parm.output.writebuffers = 0; + a->parm.output.timeperframe = ctx->timeperframe; + + return 0; +} + +/* + * sde_rotator_s_parm - V4l2 ioctl set parm. + * @file: Pointer to file struct. + * @fh: V4l2 File handle. + * @a: Pointer to v4l2_streamparm struct need to be set. + */ +static int sde_rotator_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct sde_rotator_ctx *ctx = sde_rotator_ctx_from_fh(fh); + + /* Set param is supported only for input buffers */ + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + if (!a->parm.output.timeperframe.numerator || + !a->parm.output.timeperframe.denominator) + return -EINVAL; + + ctx->timeperframe = a->parm.output.timeperframe; + return 0; +} + +/* + * sde_rotator_private_ioctl - V4l2 private ioctl handler. + * @file: Pointer to file struct. + * @fd: V4l2 device file handle. + * @valid_prio: Priority ioctl valid flag. + * @cmd: Ioctl command. + * @arg: Ioctl argument. + */ +static long sde_rotator_private_ioctl(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + struct sde_rotator_ctx *ctx = + sde_rotator_ctx_from_fh(file->private_data); + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct msm_sde_rotator_fence *fence = arg; + struct msm_sde_rotator_comp_ratio *comp_ratio = arg; + struct sde_rotator_vbinfo *vbinfo; + int ret; + + switch (cmd) { + case VIDIOC_S_SDE_ROTATOR_FENCE: + if (!fence) + return -EINVAL; + + if (fence->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + if (fence->index >= ctx->nbuf_out) + return -EINVAL; + + SDEDEV_DBG(rot_dev->dev, + "VIDIOC_S_SDE_ROTATOR_FENCE s:%d i:%d fd:%d\n", + ctx->session_id, fence->index, + fence->fd); + + vbinfo = &ctx->vbinfo_out[fence->index]; + + if (vbinfo->fd >= 0) { + if (vbinfo->fence) { + SDEDEV_DBG(rot_dev->dev, + "put fence s:%d t:%d i:%d\n", + ctx->session_id, + fence->type, fence->index); + sde_rotator_put_sync_fence(vbinfo->fence); + } + vbinfo->fence = NULL; + vbinfo->fd = -1; + } + + vbinfo->fd = fence->fd; + if (vbinfo->fd >= 0) { + vbinfo->fence = + sde_rotator_get_fd_sync_fence(vbinfo->fd); + if (!vbinfo->fence) { + SDEDEV_WARN(rot_dev->dev, + "invalid input fence fd s:%d fd:%d\n", + ctx->session_id, vbinfo->fd); + vbinfo->fd = -1; + return -EINVAL; + } + } else { + vbinfo->fence = NULL; + } + break; + case VIDIOC_G_SDE_ROTATOR_FENCE: + if (!fence) + return -EINVAL; + + if (fence->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (fence->index >= ctx->nbuf_cap) + return -EINVAL; + + vbinfo = &ctx->vbinfo_cap[fence->index]; + + if (!vbinfo) + return -EINVAL; + + if (vbinfo->fence) { + ret = sde_rotator_get_sync_fence_fd(vbinfo->fence); + if (ret < 0) { + SDEDEV_ERR(rot_dev->dev, + "fail get fence fd s:%d\n", + ctx->session_id); + return ret; + } + + /** + * Cache fence descriptor in case user calls this + * ioctl multiple times. Cached value would be stale + * if user duplicated and closed old descriptor. + */ + vbinfo->fd = ret; + } else if (!sde_rotator_get_fd_sync_fence(vbinfo->fd)) { + /** + * User has closed cached fence descriptor. + * Invalidate descriptor cache. + */ + vbinfo->fd = -1; + } + fence->fd = vbinfo->fd; + + SDEDEV_DBG(rot_dev->dev, + "VIDIOC_G_SDE_ROTATOR_FENCE s:%d i:%d fd:%d\n", + ctx->session_id, fence->index, + fence->fd); + break; + case VIDIOC_S_SDE_ROTATOR_COMP_RATIO: + if (!comp_ratio) + return -EINVAL; + else if (!comp_ratio->numer || !comp_ratio->denom) + return -EINVAL; + else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + comp_ratio->index < ctx->nbuf_out) + vbinfo = &ctx->vbinfo_out[comp_ratio->index]; + else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + comp_ratio->index < ctx->nbuf_cap) + vbinfo = &ctx->vbinfo_cap[comp_ratio->index]; + else + return -EINVAL; + + vbinfo->comp_ratio.numer = comp_ratio->numer; + vbinfo->comp_ratio.denom = comp_ratio->denom; + + SDEDEV_DBG(rot_dev->dev, + "VIDIOC_S_SDE_ROTATOR_COMP_RATIO s:%d i:%d t:%d cr:%u/%u\n", + ctx->session_id, comp_ratio->index, + comp_ratio->type, + vbinfo->comp_ratio.numer, + vbinfo->comp_ratio.denom); + break; + case VIDIOC_G_SDE_ROTATOR_COMP_RATIO: + if (!comp_ratio) + return -EINVAL; + else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + comp_ratio->index < ctx->nbuf_out) + vbinfo = &ctx->vbinfo_out[comp_ratio->index]; + else if (comp_ratio->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + comp_ratio->index < ctx->nbuf_cap) + vbinfo = &ctx->vbinfo_cap[comp_ratio->index]; + else + return -EINVAL; + + comp_ratio->numer = vbinfo->comp_ratio.numer; + comp_ratio->denom = vbinfo->comp_ratio.denom; + + SDEDEV_DBG(rot_dev->dev, + "VIDIOC_G_SDE_ROTATOR_COMP_RATIO s:%d i:%d t:%d cr:%u/%u\n", + ctx->session_id, comp_ratio->index, + comp_ratio->type, + comp_ratio->numer, + comp_ratio->denom); + break; + default: + SDEDEV_WARN(rot_dev->dev, "invalid ioctl type %x\n", cmd); + return -ENOTTY; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +/* + * sde_rotator_compat_ioctl32 - Compat ioctl handler function. + * @file: Pointer to file struct. + * @cmd: Ioctl command. + * @arg: Ioctl argument. + */ +static long sde_rotator_compat_ioctl32(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = video_devdata(file); + struct sde_rotator_ctx *ctx = + sde_rotator_ctx_from_fh(file->private_data); + long ret; + + mutex_lock(vdev->lock); + + switch (cmd) { + case VIDIOC_S_SDE_ROTATOR_FENCE: + case VIDIOC_G_SDE_ROTATOR_FENCE: + { + struct msm_sde_rotator_fence fence; + + if (copy_from_user(&fence, (void __user *)arg, + sizeof(struct msm_sde_rotator_fence))) + goto ioctl32_error; + + ret = sde_rotator_private_ioctl(file, file->private_data, + 0, cmd, (void *)&fence); + + if (copy_to_user((void __user *)arg, &fence, + sizeof(struct msm_sde_rotator_fence))) + goto ioctl32_error; + + break; + } + case VIDIOC_S_SDE_ROTATOR_COMP_RATIO: + case VIDIOC_G_SDE_ROTATOR_COMP_RATIO: + { + struct msm_sde_rotator_comp_ratio comp_ratio; + + if (copy_from_user(&comp_ratio, (void __user *)arg, + sizeof(struct msm_sde_rotator_comp_ratio))) + goto ioctl32_error; + + ret = sde_rotator_private_ioctl(file, file->private_data, + 0, cmd, (void *)&comp_ratio); + + if (copy_to_user((void __user *)arg, &comp_ratio, + sizeof(struct msm_sde_rotator_comp_ratio))) + goto ioctl32_error; + + break; + } + default: + SDEDEV_ERR(ctx->rot_dev->dev, "invalid ioctl32 type:%x\n", cmd); + ret = -ENOIOCTLCMD; + break; + + } + + mutex_unlock(vdev->lock); + return ret; + +ioctl32_error: + mutex_unlock(vdev->lock); + SDEDEV_ERR(ctx->rot_dev->dev, "error handling ioctl32 cmd:%x\n", cmd); + return -EFAULT; +} +#endif + +static int sde_rotator_ctrl_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return -EINVAL; +} + +static int sde_rotator_event_unsubscribe(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + return -EINVAL; +} + +/* V4l2 ioctl handlers */ +static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = { + .vidioc_querycap = sde_rotator_querycap, + .vidioc_enum_fmt_vid_out = sde_rotator_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = sde_rotator_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_out = sde_rotator_g_fmt_out, + .vidioc_g_fmt_vid_cap = sde_rotator_g_fmt_cap, + .vidioc_try_fmt_vid_out = sde_rotator_try_fmt_vid_out, + .vidioc_try_fmt_vid_cap = sde_rotator_try_fmt_vid_cap, + .vidioc_s_fmt_vid_out = sde_rotator_s_fmt_vid_out, + .vidioc_s_fmt_vid_cap = sde_rotator_s_fmt_vid_cap, + .vidioc_reqbufs = sde_rotator_reqbufs, + .vidioc_qbuf = sde_rotator_qbuf, + .vidioc_dqbuf = sde_rotator_dqbuf, + .vidioc_querybuf = sde_rotator_querybuf, + .vidioc_streamon = sde_rotator_streamon, + .vidioc_streamoff = sde_rotator_streamoff, + .vidioc_cropcap = sde_rotator_cropcap, + .vidioc_g_crop = sde_rotator_g_crop, + .vidioc_s_crop = sde_rotator_s_crop, + .vidioc_g_parm = sde_rotator_g_parm, + .vidioc_s_parm = sde_rotator_s_parm, + .vidioc_default = sde_rotator_private_ioctl, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = sde_rotator_ctrl_subscribe_event, + .vidioc_unsubscribe_event = sde_rotator_event_unsubscribe, +}; + +/* + * sde_rotator_retire_handler - Invoked by hal when processing is done. + * @work: Pointer to work structure. + * + * This function is scheduled in work queue context. + */ +static void sde_rotator_retire_handler(struct kthread_work *work) +{ + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct sde_rotator_ctx *ctx; + struct sde_rotator_device *rot_dev; + struct sde_rotator_request *request; + + request = container_of(work, struct sde_rotator_request, retire_work); + ctx = request->ctx; + + if (!ctx || !ctx->rot_dev) { + SDEROT_ERR("null context/device\n"); + return; + } + + rot_dev = ctx->rot_dev; + + SDEDEV_DBG(rot_dev->dev, "retire handler s:%d\n", ctx->session_id); + + mutex_lock(&rot_dev->lock); + if (ctx->abort_pending) { + SDEDEV_DBG(rot_dev->dev, "abort command in retire s:%d\n", + ctx->session_id); + sde_rotator_update_retire_sequence(request); + sde_rotator_retire_request(request); + mutex_unlock(&rot_dev->lock); + return; + } + + if (!ctx->file) { + sde_rotator_update_retire_sequence(request); + } else if (rot_dev->early_submit) { + if (IS_ERR_OR_NULL(request->req)) { + /* fail pending request or something wrong */ + SDEDEV_ERR(rot_dev->dev, + "pending request fail in retire s:%d\n", + ctx->session_id); + } + + /* pending request. reschedule this context. */ + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + } else { + /* no pending request. acknowledge the usual way. */ + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (!src_buf || !dst_buf) { + SDEDEV_ERR(rot_dev->dev, + "null buffer in retire s:%d sb:%pK db:%pK\n", + ctx->session_id, + src_buf, dst_buf); + } + + sde_rotator_update_retire_sequence(request); + sde_rotator_retire_request(request); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); + } + mutex_unlock(&rot_dev->lock); +} + +/* + * sde_rotator_process_buffers - Start rotator processing. + * @ctx: Pointer rotator context. + * @src_buf: Pointer to Vb2 source buffer. + * @dst_buf: Pointer to Vb2 destination buffer. + * @request: Pointer to rotator request + */ +static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx, + struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf, + struct sde_rotator_request *request) +{ + struct sde_rotator_device *rot_dev = ctx->rot_dev; + struct sde_rotation_item item; + struct sde_rot_entry_container *req = NULL; + struct sde_rotator_buf_handle *src_handle; + struct sde_rotator_buf_handle *dst_handle; + struct sde_rotator_statistics *stats = &rot_dev->stats; + struct sde_rotator_vbinfo *vbinfo_out; + struct sde_rotator_vbinfo *vbinfo_cap; + struct sde_rot_trace_entry rot_trace; + ktime_t *ts; + int ret; + + if (!src_buf || !dst_buf) { + SDEDEV_ERR(rot_dev->dev, "null vb2 buffers\n"); + ret = -EINVAL; + goto error_null_buffer; + } + + src_handle = src_buf->planes[0].mem_priv; + dst_handle = dst_buf->planes[0].mem_priv; + + if (!src_handle || !dst_handle) { + SDEDEV_ERR(rot_dev->dev, "null buffer handle\n"); + ret = -EINVAL; + goto error_null_buffer; + } + + vbinfo_out = &ctx->vbinfo_out[src_buf->index]; + vbinfo_cap = &ctx->vbinfo_cap[dst_buf->index]; + + SDEDEV_DBG(rot_dev->dev, + "process buffer s:%d.%u src:(%u,%u,%u,%u) dst:(%u,%u,%u,%u) rot:%d flip:%d/%d sec:%d src_cr:%u/%u dst_cr:%u/%u\n", + ctx->session_id, vbinfo_cap->fence_ts, + ctx->crop_out.left, ctx->crop_out.top, + ctx->crop_out.width, ctx->crop_out.height, + ctx->crop_cap.left, ctx->crop_cap.top, + ctx->crop_cap.width, ctx->crop_cap.height, + ctx->rotate, ctx->hflip, ctx->vflip, ctx->secure, + vbinfo_out->comp_ratio.numer, vbinfo_out->comp_ratio.denom, + vbinfo_cap->comp_ratio.numer, vbinfo_cap->comp_ratio.denom); + + /* allocate slot for timestamp */ + ts = stats->ts[stats->count++ % SDE_ROTATOR_NUM_EVENTS]; + ts[SDE_ROTATOR_TS_SRCQB] = vbinfo_out->qbuf_ts; + ts[SDE_ROTATOR_TS_DSTQB] = vbinfo_cap->qbuf_ts; + vbinfo_out->dqbuf_ts = &ts[SDE_ROTATOR_TS_SRCDQB]; + vbinfo_cap->dqbuf_ts = &ts[SDE_ROTATOR_TS_DSTDQB]; + + ts[SDE_ROTATOR_TS_FENCE] = ktime_get(); + + /* Set values to pass to trace */ + rot_trace.wb_idx = ctx->fh.prio; + rot_trace.flags = (ctx->rotate << 0) | (ctx->hflip << 8) | + (ctx->hflip << 9) | (ctx->secure << 10); + rot_trace.input_format = ctx->format_out.fmt.pix.pixelformat; + rot_trace.input_width = ctx->format_out.fmt.pix.width; + rot_trace.input_height = ctx->format_out.fmt.pix.height; + rot_trace.src_x = ctx->crop_out.left; + rot_trace.src_y = ctx->crop_out.top; + rot_trace.src_w = ctx->crop_out.width; + rot_trace.src_h = ctx->crop_out.height; + rot_trace.output_format = ctx->format_cap.fmt.pix.pixelformat; + rot_trace.output_width = ctx->format_cap.fmt.pix.width; + rot_trace.output_height = ctx->format_cap.fmt.pix.height; + rot_trace.dst_x = ctx->crop_cap.left; + rot_trace.dst_y = ctx->crop_cap.top; + rot_trace.dst_w = ctx->crop_cap.width; + rot_trace.dst_h = ctx->crop_cap.height; + + trace_rot_entry_fence( + ctx->session_id, vbinfo_cap->fence_ts, &rot_trace); + + if (vbinfo_out->fence) { + sde_rot_mgr_unlock(rot_dev->mgr); + mutex_unlock(&rot_dev->lock); + SDEDEV_DBG(rot_dev->dev, "fence enter s:%d.%d fd:%d\n", + ctx->session_id, vbinfo_cap->fence_ts, vbinfo_out->fd); + ret = sde_rotator_wait_sync_fence(vbinfo_out->fence, + rot_dev->fence_timeout); + mutex_lock(&rot_dev->lock); + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_put_sync_fence(vbinfo_out->fence); + vbinfo_out->fence = NULL; + if (ret) { + SDEDEV_ERR(rot_dev->dev, + "error waiting for fence s:%d.%d fd:%d r:%d\n", + ctx->session_id, + vbinfo_cap->fence_ts, vbinfo_out->fd, ret); + SDEROT_EVTLOG(ctx->session_id, vbinfo_cap->fence_ts, + vbinfo_out->fd, ret, + SDE_ROT_EVTLOG_ERROR); + goto error_fence_wait; + } else { + SDEDEV_DBG(rot_dev->dev, "fence exit s:%d.%d fd:%d\n", + ctx->session_id, + vbinfo_cap->fence_ts, vbinfo_out->fd); + } + } + + /* fill in item work structure */ + sde_rotator_get_item_from_ctx(ctx, &item); + item.flags |= SDE_ROTATION_EXT_DMA_BUF; + item.input.planes[0].fd = src_handle->fd; + item.input.planes[0].buffer = src_handle->buffer; + item.input.planes[0].offset = src_handle->addr; + item.input.planes[0].stride = ctx->format_out.fmt.pix.bytesperline; + item.input.plane_count = 1; + item.input.fence = NULL; + item.input.comp_ratio = vbinfo_out->comp_ratio; + item.output.planes[0].fd = dst_handle->fd; + item.output.planes[0].buffer = dst_handle->buffer; + item.output.planes[0].offset = dst_handle->addr; + item.output.planes[0].stride = ctx->format_cap.fmt.pix.bytesperline; + item.output.plane_count = 1; + item.output.fence = NULL; + item.output.comp_ratio = vbinfo_cap->comp_ratio; + item.sequence_id = vbinfo_cap->fence_ts; + item.ts = ts; + + req = sde_rotator_req_init(rot_dev->mgr, ctx->private, &item, 1, 0); + if (IS_ERR_OR_NULL(req)) { + SDEDEV_ERR(rot_dev->dev, "fail allocate rotation request\n"); + ret = -ENOMEM; + goto error_init_request; + } + + req->retire_kw = ctx->work_queue.rot_kw; + req->retire_work = &request->retire_work; + + ret = sde_rotator_handle_request_common( + rot_dev->mgr, ctx->private, req); + if (ret) { + SDEDEV_ERR(rot_dev->dev, "fail handle request\n"); + goto error_handle_request; + } + + sde_rotator_queue_request(rot_dev->mgr, ctx->private, req); + request->req = req; + request->sequence_id = item.sequence_id; + request->committed = true; + + return 0; +error_handle_request: + devm_kfree(rot_dev->dev, req); +error_init_request: +error_fence_wait: +error_null_buffer: + request->req = NULL; + request->sequence_id = 0; + request->committed = false; + return ret; +} + +/* + * sde_rotator_submit_handler - Invoked by m2m to submit job. + * @work: Pointer to work structure. + * + * This function is scheduled in work queue context. + */ +static void sde_rotator_submit_handler(struct kthread_work *work) +{ + struct sde_rotator_ctx *ctx; + struct sde_rotator_device *rot_dev; + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct sde_rotator_request *request; + int ret; + + request = container_of(work, struct sde_rotator_request, submit_work); + ctx = request->ctx; + + if (!ctx || !ctx->rot_dev) { + SDEROT_ERR("null device\n"); + return; + } + + rot_dev = ctx->rot_dev; + SDEDEV_DBG(rot_dev->dev, "submit handler s:%d\n", ctx->session_id); + + mutex_lock(&rot_dev->lock); + if (ctx->abort_pending) { + SDEDEV_DBG(rot_dev->dev, "abort command in submit s:%d\n", + ctx->session_id); + sde_rotator_update_retire_sequence(request); + sde_rotator_retire_request(request); + mutex_unlock(&rot_dev->lock); + return; + } + + /* submit new request */ + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + sde_rot_mgr_lock(rot_dev->mgr); + ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf, request); + sde_rot_mgr_unlock(rot_dev->mgr); + if (ret) { + SDEDEV_ERR(rot_dev->dev, + "fail process buffer in submit s:%d\n", + ctx->session_id); + /* advance to device run to clean up buffers */ + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + } + + mutex_unlock(&rot_dev->lock); +} + +/* + * sde_rotator_device_run - rotator m2m device run callback + * @priv: Pointer rotator context. + */ +static void sde_rotator_device_run(void *priv) +{ + struct sde_rotator_ctx *ctx = priv; + struct sde_rotator_device *rot_dev; + struct vb2_v4l2_buffer *src_buf; + struct vb2_v4l2_buffer *dst_buf; + struct sde_rotator_request *request; + int ret; + + if (!ctx || !ctx->rot_dev) { + SDEROT_ERR("null context/device\n"); + return; + } + + rot_dev = ctx->rot_dev; + SDEDEV_DBG(rot_dev->dev, "device run s:%d\n", ctx->session_id); + + if (rot_dev->early_submit) { + request = list_first_entry_or_null(&ctx->pending_list, + struct sde_rotator_request, list); + + /* pending request mode, check for completion */ + if (!request || IS_ERR_OR_NULL(request->req)) { + /* pending request fails or something wrong. */ + SDEDEV_ERR(rot_dev->dev, + "pending request fail in device run s:%d\n", + ctx->session_id); + rot_dev->stats.fail_count++; + ATRACE_INT("fail_count", rot_dev->stats.fail_count); + goto error_process_buffers; + + } else if (!atomic_read(&request->req->pending_count)) { + /* pending request completed. signal done. */ + int failed_count = + atomic_read(&request->req->failed_count); + SDEDEV_DBG(rot_dev->dev, + "pending request completed in device run s:%d\n", + ctx->session_id); + + /* disconnect request (will be freed by core layer) */ + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_req_finish(rot_dev->mgr, ctx->private, + request->req); + sde_rot_mgr_unlock(rot_dev->mgr); + + if (failed_count) { + SDEDEV_ERR(rot_dev->dev, + "pending request failed in device run s:%d f:%d\n", + ctx->session_id, + failed_count); + rot_dev->stats.fail_count++; + ATRACE_INT("fail_count", + rot_dev->stats.fail_count); + goto error_process_buffers; + } + + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!src_buf || !dst_buf) { + SDEDEV_ERR(rot_dev->dev, + "null buffer in device run s:%d sb:%pK db:%pK\n", + ctx->session_id, + src_buf, dst_buf); + goto error_process_buffers; + } + + sde_rotator_update_retire_sequence(request); + sde_rotator_retire_request(request); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); + } else { + /* pending request not complete. something wrong. */ + SDEDEV_ERR(rot_dev->dev, + "Incomplete pending request in device run s:%d\n", + ctx->session_id); + + /* disconnect request (will be freed by core layer) */ + sde_rot_mgr_lock(rot_dev->mgr); + sde_rotator_req_finish(rot_dev->mgr, ctx->private, + request->req); + sde_rot_mgr_unlock(rot_dev->mgr); + + goto error_process_buffers; + } + } else { + request = list_first_entry_or_null(&ctx->retired_list, + struct sde_rotator_request, list); + if (!request) { + SDEDEV_ERR(rot_dev->dev, + "no free request in device run s:%d\n", + ctx->session_id); + goto error_retired_list; + } + + spin_lock(&ctx->list_lock); + list_del_init(&request->list); + list_add_tail(&request->list, &ctx->pending_list); + spin_unlock(&ctx->list_lock); + + /* no pending request. submit buffer the usual way. */ + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + if (!src_buf || !dst_buf) { + SDEDEV_ERR(rot_dev->dev, + "null buffer in device run s:%d sb:%pK db:%pK\n", + ctx->session_id, + src_buf, dst_buf); + goto error_empty_buffer; + } + + sde_rot_mgr_lock(rot_dev->mgr); + ret = sde_rotator_process_buffers(ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf, request); + sde_rot_mgr_unlock(rot_dev->mgr); + if (ret) { + SDEDEV_ERR(rot_dev->dev, + "fail process buffer in device run s:%d\n", + ctx->session_id); + rot_dev->stats.fail_count++; + ATRACE_INT("fail_count", rot_dev->stats.fail_count); + goto error_process_buffers; + } + } + + return; +error_process_buffers: +error_empty_buffer: +error_retired_list: + sde_rotator_update_retire_sequence(request); + sde_rotator_retire_request(request); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (src_buf) + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + if (dst_buf) + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + sde_rotator_resync_timeline(ctx->work_queue.timeline); + v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); +} + +/* + * sde_rotator_job_abort - rotator m2m job abort callback + * @priv: Pointer rotator context. + */ +static void sde_rotator_job_abort(void *priv) +{ + struct sde_rotator_ctx *ctx = priv; + struct sde_rotator_device *rot_dev; + + if (!ctx || !ctx->rot_dev) { + SDEROT_ERR("null context/device\n"); + return; + } + + rot_dev = ctx->rot_dev; + SDEDEV_DBG(rot_dev->dev, "job abort s:%d\n", ctx->session_id); + + v4l2_m2m_job_finish(rot_dev->m2m_dev, ctx->fh.m2m_ctx); +} + +/* + * sde_rotator_job_ready - rotator m2m job ready callback + * @priv: Pointer rotator context. + */ +static int sde_rotator_job_ready(void *priv) +{ + struct sde_rotator_ctx *ctx = priv; + struct sde_rotator_device *rot_dev; + struct sde_rotator_request *request; + int ret = 0; + + if (!ctx || !ctx->rot_dev) { + SDEROT_ERR("null context/device\n"); + return 0; + } + + rot_dev = ctx->rot_dev; + SDEDEV_DBG(rot_dev->dev, "job ready s:%d\n", ctx->session_id); + + request = list_first_entry_or_null(&ctx->pending_list, + struct sde_rotator_request, list); + + if (!rot_dev->early_submit) { + /* always ready in normal mode. */ + ret = 1; + } else if (request && IS_ERR_OR_NULL(request->req)) { + /* if pending request fails, forward to device run state. */ + SDEDEV_DBG(rot_dev->dev, + "pending request fail in job ready s:%d\n", + ctx->session_id); + ret = 1; + } else if (list_empty(&ctx->pending_list)) { + /* if no pending request, submit a new request. */ + SDEDEV_DBG(rot_dev->dev, + "submit job s:%d sc:%d dc:%d p:%d\n", + ctx->session_id, + v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx), + !list_empty(&ctx->pending_list)); + + request = list_first_entry_or_null(&ctx->retired_list, + struct sde_rotator_request, list); + if (!request) { + /* should not happen */ + SDEDEV_ERR(rot_dev->dev, + "no free request in job ready s:%d\n", + ctx->session_id); + } else { + spin_lock(&ctx->list_lock); + list_del_init(&request->list); + list_add_tail(&request->list, &ctx->pending_list); + spin_unlock(&ctx->list_lock); + kthread_queue_work(ctx->work_queue.rot_kw, + &request->submit_work); + } + } else if (request && !atomic_read(&request->req->pending_count)) { + /* if pending request completed, forward to device run state */ + SDEDEV_DBG(rot_dev->dev, + "pending request completed in job ready s:%d\n", + ctx->session_id); + ret = 1; + } + + return ret; +} + +/* V4l2 mem2mem handlers */ +static struct v4l2_m2m_ops sde_rotator_m2m_ops = { + .device_run = sde_rotator_device_run, + .job_abort = sde_rotator_job_abort, + .job_ready = sde_rotator_job_ready, +}; + +/* Device tree match struct */ +static const struct of_device_id sde_rotator_dt_match[] = { + { + .compatible = "qcom,sde_rotator", + .data = NULL, + }, + {} +}; + +/* + * sde_rotator_get_drv_data - rotator device driver data. + * @dev: Pointer to device. + */ +static const void *sde_rotator_get_drv_data(struct device *dev) +{ + const struct of_device_id *match; + + match = of_match_node(sde_rotator_dt_match, dev->of_node); + + if (match) + return match->data; + + return NULL; +} + +/* + * sde_rotator_probe - rotator device probe method. + * @pdev: Pointer to rotator platform device. + */ +static int sde_rotator_probe(struct platform_device *pdev) +{ + struct sde_rotator_device *rot_dev; + struct video_device *vdev; + int ret, i; + char name[32]; + + SDEDEV_DBG(&pdev->dev, "SDE v4l2 rotator probed\n"); + + /* sde rotator device struct */ + rot_dev = kzalloc(sizeof(struct sde_rotator_device), GFP_KERNEL); + if (!rot_dev) + return -ENOMEM; + + mutex_init(&rot_dev->lock); + rot_dev->early_submit = SDE_ROTATOR_EARLY_SUBMIT; + rot_dev->fence_timeout = SDE_ROTATOR_FENCE_TIMEOUT; + rot_dev->streamoff_timeout = SDE_ROTATOR_STREAM_OFF_TIMEOUT; + rot_dev->min_rot_clk = 0; + rot_dev->min_bw = 0; + rot_dev->min_overhead_us = 0; + rot_dev->drvdata = sde_rotator_get_drv_data(&pdev->dev); + rot_dev->open_timeout = SDE_ROTATOR_CTX_OPEN_TIMEOUT; + init_waitqueue_head(&rot_dev->open_wq); + + rot_dev->pdev = pdev; + rot_dev->dev = &pdev->dev; + platform_set_drvdata(pdev, rot_dev); + + ret = sde_rotator_base_init(&rot_dev->mdata, pdev, rot_dev->drvdata); + if (ret < 0) { + SDEDEV_ERR(&pdev->dev, "fail init base data %d\n", ret); + goto error_rotator_base_init; + } + + ret = sde_rotator_core_init(&rot_dev->mgr, pdev); + if (ret < 0) { + if (ret == -EPROBE_DEFER) + SDEDEV_INFO(&pdev->dev, "probe defer for core init\n"); + else + SDEDEV_ERR(&pdev->dev, "fail init core %d\n", ret); + goto error_rotator_core_init; + } + + /* mem2mem device */ + rot_dev->m2m_dev = v4l2_m2m_init(&sde_rotator_m2m_ops); + if (IS_ERR(rot_dev->m2m_dev)) { + ret = PTR_ERR(rot_dev->m2m_dev); + SDEDEV_ERR(&pdev->dev, "fail init mem2mem device %d\n", ret); + goto error_m2m_init; + } + + /* v4l2 device */ + ret = v4l2_device_register(&pdev->dev, &rot_dev->v4l2_dev); + if (ret < 0) { + SDEDEV_ERR(&pdev->dev, "fail register v4l2 device %d\n", ret); + goto error_v4l2_register; + } + + vdev = video_device_alloc(); + if (!vdev) { + SDEDEV_ERR(&pdev->dev, "fail allocate video device\n"); + goto error_alloc_video_device; + } + + vdev->fops = &sde_rotator_fops; + vdev->ioctl_ops = &sde_rotator_ioctl_ops; + vdev->lock = &rot_dev->lock; + vdev->minor = -1; + vdev->release = video_device_release; + vdev->v4l2_dev = &rot_dev->v4l2_dev; + vdev->vfl_dir = VFL_DIR_M2M; + vdev->vfl_type = VFL_TYPE_GRABBER; + strlcpy(vdev->name, SDE_ROTATOR_DRV_NAME, sizeof(vdev->name)); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, + SDE_ROTATOR_BASE_DEVICE_NUMBER); + if (ret < 0) { + SDEDEV_ERR(&pdev->dev, "fail register video device %d\n", + ret); + goto error_video_register; + } + + rot_dev->vdev = vdev; + video_set_drvdata(rot_dev->vdev, rot_dev); + + rot_dev->debugfs_root = sde_rotator_create_debugfs(rot_dev); + + for (i = 0; i < MAX_ROT_OPEN_SESSION; i++) { + snprintf(name, sizeof(name), "rot_fenceq_%d_%d", + rot_dev->dev->id, i); + kthread_init_worker(&rot_dev->rot_kw[i]); + rot_dev->rot_thread[i] = kthread_run(kthread_worker_fn, + &rot_dev->rot_kw[i], name); + if (IS_ERR(rot_dev->rot_thread[i])) { + SDEDEV_ERR(rot_dev->dev, + "fail allocate kthread i:%d\n", i); + ret = -EPERM; + goto error_kthread_create; + } + rot_dev->kthread_free[i] = true; + } + + SDEDEV_INFO(&pdev->dev, "SDE v4l2 rotator probe success\n"); + + return 0; +error_kthread_create: + for (i--; i >= 0; i--) + kthread_stop(rot_dev->rot_thread[i]); + sde_rotator_destroy_debugfs(rot_dev->debugfs_root); + video_unregister_device(rot_dev->vdev); +error_video_register: + video_device_release(vdev); +error_alloc_video_device: + v4l2_device_unregister(&rot_dev->v4l2_dev); +error_v4l2_register: + v4l2_m2m_release(rot_dev->m2m_dev); +error_m2m_init: + sde_rotator_core_destroy(rot_dev->mgr); +error_rotator_core_init: + sde_rotator_base_destroy(rot_dev->mdata); +error_rotator_base_init: + kfree(rot_dev); + return ret; +} + +/* + * sde_rotator_remove - rotator device remove method. + * @pdev: Pointer rotator platform device. + */ +static int sde_rotator_remove(struct platform_device *pdev) +{ + struct sde_rotator_device *rot_dev; + int i; + + rot_dev = platform_get_drvdata(pdev); + if (rot_dev == NULL) { + SDEDEV_ERR(&pdev->dev, "fail get rotator drvdata\n"); + return 0; + } + + sde_rotator_pm_qos_remove(rot_dev->mdata); + for (i = MAX_ROT_OPEN_SESSION - 1; i >= 0; i--) + kthread_stop(rot_dev->rot_thread[i]); + sde_rotator_destroy_debugfs(rot_dev->debugfs_root); + video_unregister_device(rot_dev->vdev); + video_device_release(rot_dev->vdev); + v4l2_device_unregister(&rot_dev->v4l2_dev); + v4l2_m2m_release(rot_dev->m2m_dev); + sde_rotator_core_destroy(rot_dev->mgr); + sde_rotator_base_destroy(rot_dev->mdata); + kfree(rot_dev); + return 0; +} + +static const struct dev_pm_ops sde_rotator_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sde_rotator_pm_suspend, sde_rotator_pm_resume) + SET_RUNTIME_PM_OPS(sde_rotator_runtime_suspend, + sde_rotator_runtime_resume, + sde_rotator_runtime_idle) +}; + +/* SDE Rotator platform driver definition */ +static struct platform_driver rotator_driver = { + .probe = sde_rotator_probe, + .remove = sde_rotator_remove, + .suspend = sde_rotator_suspend, + .resume = sde_rotator_resume, + .driver = { + .name = SDE_ROTATOR_DRV_NAME, + .of_match_table = sde_rotator_dt_match, + .pm = &sde_rotator_pm_ops, + }, +}; + +static int __init sde_rotator_init_module(void) +{ + return platform_driver_register(&rotator_driver); +} + +static void __exit sde_rotator_exit_module(void) +{ + platform_driver_unregister(&rotator_driver); +} + +late_initcall(sde_rotator_init_module); +module_exit(sde_rotator_exit_module); +MODULE_DESCRIPTION("MSM SDE ROTATOR driver"); diff --git a/techpack/display/rotator/sde_rotator_dev.h b/techpack/display/rotator/sde_rotator_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..711d8d87b80bcf6ac2cdf0cc3f4a988b26352d5d --- /dev/null +++ b/techpack/display/rotator/sde_rotator_dev.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_DEV_H__ +#define __SDE_ROTATOR_DEV_H__ + +#include <linux/types.h> +#include <linux/atomic.h> +#include <linux/slab.h> +#include <linux/ktime.h> +#include <linux/iommu.h> +#include <linux/dma-buf.h> +#include <linux/msm-bus.h> +#include <linux/platform_device.h> +#include <linux/soc/qcom/llcc-qcom.h> +#include <linux/kthread.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ctrls.h> +#include <media/msm_sde_rotator.h> + +#include "sde_rotator_core.h" +#include "sde_rotator_sync.h" + +/* Rotator device name */ +#define SDE_ROTATOR_DRV_NAME "sde_rotator" + +/* Event logging constants */ +#define SDE_ROTATOR_NUM_EVENTS 4096 +#define SDE_ROTATOR_NUM_TIMESTAMPS SDE_ROTATOR_TS_MAX + +/* maximum number of outstanding requests per ctx session */ +#define SDE_ROTATOR_REQUEST_MAX 2 + +#define MAX_ROT_OPEN_SESSION 16 + +struct sde_rotator_device; +struct sde_rotator_ctx; + +/* + * struct sde_rotator_buf_handle - Structure contain rotator buffer information. + * @fd: ion file descriptor from which this buffer is imported. + * @rot_dev: Pointer to rotator device. + * @ctx: Pointer to rotator context. + * @size: Size of the buffer. + * @addr: Address of rotator mmu mapped buffer. + * @secure: Non-secure/secure buffer. + * @buffer: Pointer to dma buf associated with this fd. + */ +struct sde_rotator_buf_handle { + int fd; + struct sde_rotator_device *rot_dev; + struct sde_rotator_ctx *ctx; + unsigned long size; + dma_addr_t addr; + int secure; + struct dma_buf *buffer; +}; + +/* + * struct sde_rotator_vbinfo - Structure define video buffer info. + * @fd: fence file descriptor. + * @fence: fence associated with fd. + * @fence_ts: completion timestamp associated with fd + * @qbuf_ts: timestamp associated with buffer queue event + * @dqbuf_ts: Pointer to timestamp associated with buffer dequeue event + * @comp_ratio: compression ratio of this buffer + */ +struct sde_rotator_vbinfo { + int fd; + struct sde_rot_sync_fence *fence; + u32 fence_ts; + ktime_t qbuf_ts; + ktime_t *dqbuf_ts; + struct sde_mult_factor comp_ratio; +}; + +/* + * struct sde_rotator_request - device layer rotation request + * @list: list head for submit/retire list + * @submit_work: submit work structure + * @retire_work: retire work structure + * @req: Pointer to core layer rotator manager request + * Request can be freed by core layer during sde_rotator_stop_streaming. + * Avoid dereference in dev layer if possible. + * @ctx: Pointer to parent context + * @committed: true if request committed to hardware + * @sequence_id: sequence identifier of this request + */ +struct sde_rotator_request { + struct list_head list; + struct kthread_work submit_work; + struct kthread_work retire_work; + struct sde_rot_entry_container *req; + struct sde_rotator_ctx *ctx; + bool committed; + u32 sequence_id; +}; + +/* + * struct sde_rotator_ctx - Structure contains per open file handle context. + * @kobj: kernel object of this context + * @rot_dev: Pointer to rotator device. + * @file: Pointer to device file handle + * @fh: V4l2 file handle. + * @ctrl_handler: control handler + * @format_cap: Current capture format. + * @format_out: Current output format. + * @crop_cap: Current capture crop. + * @crop_out: Current output crop. + * @timeperframe: Time per frame in seconds. + * @session_id: unique id for this context + * @hflip: horizontal flip (1-flip) + * @vflip: vertical flip (1-flip) + * @rotate: rotation angle (0,90,180,270) + * @secure: Non-secure (0) / Secure processing + * @abort_pending: True if abort is requested for async handling. + * @nbuf_cap: Number of requested buffer for capture queue + * @nbuf_out: Number of requested buffer for output queue + * @fence_cap: Fence info for each requested capture buffer + * @fence_out: Fence info for each requested output buffer + * @wait_queue: Wait queue for signaling end of job + * @work_queue: work queue for submit and retire processing + * @private: Pointer to session private information + * @slice: Pointer to system cache slice descriptor + * @commit_sequence_id: last committed sequence id + * @retired_sequence_id: last retired sequence id + * @list_lock: lock for pending/retired list + * @pending_list: list of pending request + * @retired_list: list of retired/free request + * @requests: static allocation of free requests + * @rotcfg: current core rotation configuration + * @kthread_id: thread_id used for fence management + */ +struct sde_rotator_ctx { + struct kobject kobj; + struct sde_rotator_device *rot_dev; + struct file *file; + struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_format format_cap; + struct v4l2_format format_out; + struct v4l2_rect crop_cap; + struct v4l2_rect crop_out; + struct v4l2_fract timeperframe; + u32 session_id; + s32 hflip; + s32 vflip; + s32 rotate; + s32 secure; + s32 secure_camera; + int abort_pending; + int nbuf_cap; + int nbuf_out; + struct sde_rotator_vbinfo *vbinfo_cap; + struct sde_rotator_vbinfo *vbinfo_out; + wait_queue_head_t wait_queue; + struct sde_rot_queue_v1 work_queue; + struct sde_rot_file_private *private; + struct llcc_slice_desc *slice; + u32 commit_sequence_id; + u32 retired_sequence_id; + spinlock_t list_lock; + struct list_head pending_list; + struct list_head retired_list; + struct sde_rotator_request requests[SDE_ROTATOR_REQUEST_MAX]; + struct sde_rotation_config rotcfg; + + int kthread_id; +}; + +/* + * struct sde_rotator_statistics - Storage for statistics + * @count: Number of processed request + * @fail_count: Number of failed request + * @ts: Timestamps of most recent requests + */ +struct sde_rotator_statistics { + u64 count; + u64 fail_count; + ktime_t ts[SDE_ROTATOR_NUM_EVENTS][SDE_ROTATOR_NUM_TIMESTAMPS]; +}; + +/* + * struct sde_rotator_device - FD device structure. + * @lock: Lock protecting this device structure and serializing IOCTL. + * @dev: Pointer to device struct. + * @v4l2_dev: V4l2 device. + * @vdev: Pointer to video device. + * @m2m_dev: Memory to memory device. + * @pdev: Pointer to platform device. + * @drvdata: Pointer to driver data. + * @early_submit: flag enable job submission in ready state. + * @disable_syscache: true to disable system cache + * @mgr: Pointer to core rotator manager. + * @mdata: Pointer to common rotator data/resource. + * @session_id: Next context session identifier + * @fence_timeout: Timeout value in msec for fence wait + * @streamoff_timeout: Timeout value in msec for stream off + * @min_rot_clk: Override the minimum rotator clock from perf calculation + * @min_bw: Override the minimum bandwidth from perf calculation + * @min_overhead_us: Override the minimum overhead in us from perf calculation + * @debugfs_root: Pointer to debugfs directory entry. + * @stats: placeholder for rotator statistics + * @open_timeout: maximum wait time for ctx open in msec + * @open_wq: wait queue for ctx open + * @excl_ctx: Pointer to exclusive ctx + * @rot_kw: rotator thread work + * @rot_thread: rotator threads + * @kthread_free: check if thread is available or not + */ +struct sde_rotator_device { + struct mutex lock; + struct device *dev; + struct v4l2_device v4l2_dev; + struct video_device *vdev; + struct v4l2_m2m_dev *m2m_dev; + struct platform_device *pdev; + const void *drvdata; + u32 early_submit; + u32 disable_syscache; + struct sde_rot_mgr *mgr; + struct sde_rot_data_type *mdata; + u32 session_id; + u32 fence_timeout; + u32 streamoff_timeout; + u32 min_rot_clk; + u32 min_bw; + u32 min_overhead_us; + struct sde_rotator_statistics stats; + struct dentry *debugfs_root; + struct dentry *perf_root; + u32 open_timeout; + wait_queue_head_t open_wq; + struct sde_rotator_ctx *excl_ctx; + + struct kthread_worker rot_kw[MAX_ROT_OPEN_SESSION]; + struct task_struct *rot_thread[MAX_ROT_OPEN_SESSION]; + bool kthread_free[MAX_ROT_OPEN_SESSION]; +}; + +static inline +struct sde_rot_mgr *sde_rot_mgr_from_pdevice(struct platform_device *pdev) +{ + return ((struct sde_rotator_device *) platform_get_drvdata(pdev))->mgr; +} + +static inline +struct sde_rot_mgr *sde_rot_mgr_from_device(struct device *dev) +{ + return ((struct sde_rotator_device *) dev_get_drvdata(dev))->mgr; +} + +void sde_rotator_pm_qos_add(struct sde_rot_data_type *rot_mdata); + +#endif /* __SDE_ROTATOR_DEV_H__ */ diff --git a/techpack/display/rotator/sde_rotator_formats.c b/techpack/display/rotator/sde_rotator_formats.c new file mode 100644 index 0000000000000000000000000000000000000000..56c51e9ae9016b1e92bab4d4b1dafcd1e4db0d37 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_formats.c @@ -0,0 +1,943 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include <media/msm_sde_rotator.h> + +#include "sde_rotator_formats.h" +#include "sde_rotator_util.h" + +#define FMT_RGB_565(fmt, desc, frame_fmt, flag_arg, e0, e1, e2, isubwc) \ + { \ + .format = (fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0, \ + .alpha_enable = 0, \ + .unpack_count = 3, \ + .bpp = 2, \ + .frame_format = (frame_fmt), \ + .pixel_mode = SDE_MDP_PIXEL_NORMAL, \ + .element = { (e0), (e1), (e2) }, \ + .bits = { \ + [C2_R_Cr] = SDE_COLOR_5BIT, \ + [C0_G_Y] = SDE_COLOR_6BIT, \ + [C1_B_Cb] = SDE_COLOR_5BIT, \ + }, \ + .is_ubwc = isubwc, \ + } + +#define FMT_RGB_888(fmt, desc, frame_fmt, flag_arg, e0, e1, e2, isubwc) \ + { \ + .format = (fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0, \ + .alpha_enable = 0, \ + .unpack_count = 3, \ + .bpp = 3, \ + .frame_format = (frame_fmt), \ + .pixel_mode = SDE_MDP_PIXEL_NORMAL, \ + .element = { (e0), (e1), (e2) }, \ + .bits = { \ + [C2_R_Cr] = SDE_COLOR_8BIT, \ + [C0_G_Y] = SDE_COLOR_8BIT, \ + [C1_B_Cb] = SDE_COLOR_8BIT, \ + }, \ + .is_ubwc = isubwc, \ + } + +#define FMT_RGB_8888(fmt, desc, frame_fmt, flag_arg, \ + alpha_en, e0, e1, e2, e3, isubwc) \ + { \ + .format = (fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0, \ + .alpha_enable = (alpha_en), \ + .unpack_count = 4, \ + .bpp = 4, \ + .frame_format = (frame_fmt), \ + .pixel_mode = SDE_MDP_PIXEL_NORMAL, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { \ + [C3_ALPHA] = SDE_COLOR_8BIT, \ + [C2_R_Cr] = SDE_COLOR_8BIT, \ + [C0_G_Y] = SDE_COLOR_8BIT, \ + [C1_B_Cb] = SDE_COLOR_8BIT, \ + }, \ + .is_ubwc = isubwc, \ + } + +#define FMT_YUV10_COMMON(fmt) \ + .format = (fmt), \ + .is_yuv = 1, \ + .bits = { \ + [C2_R_Cr] = SDE_COLOR_8BIT, \ + [C0_G_Y] = SDE_COLOR_8BIT, \ + [C1_B_Cb] = SDE_COLOR_8BIT, \ + }, \ + .alpha_enable = 0 + +#define FMT_YUV_COMMON(fmt) \ + .format = (fmt), \ + .is_yuv = 1, \ + .bits = { \ + [C2_R_Cr] = SDE_COLOR_8BIT, \ + [C0_G_Y] = SDE_COLOR_8BIT, \ + [C1_B_Cb] = SDE_COLOR_8BIT, \ + }, \ + .alpha_enable = 0, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0 + +#define FMT_YUV_PSEUDO(fmt, desc, frame_fmt, samp, pixel_type, \ + flag_arg, e0, e1, isubwc) \ + { \ + FMT_YUV_COMMON(fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, \ + .chroma_sample = samp, \ + .unpack_count = 2, \ + .bpp = 2, \ + .frame_format = (frame_fmt), \ + .pixel_mode = (pixel_type), \ + .element = { (e0), (e1) }, \ + .is_ubwc = isubwc, \ + } + +#define FMT_YUV_PLANR(fmt, desc, frame_fmt, samp, \ + flag_arg, e0, e1) \ + { \ + FMT_YUV_COMMON(fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_PLANAR, \ + .chroma_sample = samp, \ + .bpp = 1, \ + .unpack_count = 1, \ + .frame_format = (frame_fmt), \ + .pixel_mode = SDE_MDP_PIXEL_NORMAL, \ + .element = { (e0), (e1) }, \ + .is_ubwc = SDE_MDP_COMPRESS_NONE, \ + } + +#define FMT_RGB_1555(fmt, desc, alpha_en, flag_arg, e0, e1, e2, e3) \ + { \ + .format = (fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0, \ + .alpha_enable = (alpha_en), \ + .unpack_count = 4, \ + .bpp = 2, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .frame_format = SDE_MDP_FMT_LINEAR, \ + .pixel_mode = SDE_MDP_PIXEL_NORMAL, \ + .bits = { \ + [C3_ALPHA] = SDE_COLOR_ALPHA_1BIT, \ + [C2_R_Cr] = SDE_COLOR_5BIT, \ + [C0_G_Y] = SDE_COLOR_5BIT, \ + [C1_B_Cb] = SDE_COLOR_5BIT, \ + }, \ + .is_ubwc = SDE_MDP_COMPRESS_NONE, \ + } + +#define FMT_RGB_4444(fmt, desc, alpha_en, flag_arg, e0, e1, e2, e3) \ + { \ + .format = (fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0, \ + .alpha_enable = (alpha_en), \ + .unpack_count = 4, \ + .bpp = 2, \ + .frame_format = SDE_MDP_FMT_LINEAR, \ + .pixel_mode = SDE_MDP_PIXEL_NORMAL, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { \ + [C3_ALPHA] = SDE_COLOR_ALPHA_4BIT, \ + [C2_R_Cr] = SDE_COLOR_4BIT, \ + [C0_G_Y] = SDE_COLOR_4BIT, \ + [C1_B_Cb] = SDE_COLOR_4BIT, \ + }, \ + .is_ubwc = SDE_MDP_COMPRESS_NONE, \ + } + +#define FMT_RGB_1010102(fmt, desc, frame_fmt, flag_arg, \ + alpha_en, e0, e1, e2, e3, isubwc) \ + { \ + .format = (fmt), \ + .description = (desc), \ + .flag = flag_arg, \ + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, \ + .unpack_tight = 1, \ + .unpack_align_msb = 0, \ + .alpha_enable = (alpha_en), \ + .unpack_count = 4, \ + .bpp = 4, \ + .frame_format = frame_fmt, \ + .pixel_mode = SDE_MDP_PIXEL_10BIT, \ + .element = { (e0), (e1), (e2), (e3) }, \ + .bits = { \ + [C3_ALPHA] = SDE_COLOR_8BIT, \ + [C2_R_Cr] = SDE_COLOR_8BIT, \ + [C0_G_Y] = SDE_COLOR_8BIT, \ + [C1_B_Cb] = SDE_COLOR_8BIT, \ + }, \ + .is_ubwc = isubwc, \ + } + +/* + * UBWC formats table: + * This table holds the UBWC formats supported. + * If a compression ratio needs to be used for this or any other format, + * the data will be passed by user-space. + */ +static struct sde_mdp_format_params_ubwc sde_mdp_format_ubwc_map[] = { + { + .mdp_format = FMT_RGB_565(SDE_PIX_FMT_RGB_565_UBWC, + "SDE/RGB_565_UBWC", + SDE_MDP_FMT_TILE_A5X, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = FMT_RGB_8888(SDE_PIX_FMT_RGBA_8888_UBWC, + "SDE/RGBA_8888_UBWC", + SDE_MDP_FMT_TILE_A5X, 0, 1, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = FMT_RGB_8888(SDE_PIX_FMT_RGBX_8888_UBWC, + "SDE/RGBX_8888_UBWC", + SDE_MDP_FMT_TILE_A5X, 0, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, + "SDE/Y_CBCR_H2V2_UBWC", + SDE_MDP_FMT_TILE_A5X, SDE_MDP_CHROMA_420, + SDE_MDP_PIXEL_NORMAL, + 0, C1_B_Cb, C2_R_Cr, + SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 8, + .tile_width = 32, + }, + }, + { + .mdp_format = FMT_RGB_1010102(SDE_PIX_FMT_RGBA_1010102_UBWC, + "SDE/RGBA_1010102_UBWC", + SDE_MDP_FMT_TILE_A5X, 0, 1, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = FMT_RGB_1010102(SDE_PIX_FMT_RGBX_1010102_UBWC, + "SDE/RGBX_1010102_UBWC", + SDE_MDP_FMT_TILE_A5X, 0, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, + "SDE/Y_CBCR_H2V2_TP10_UBWC", + SDE_MDP_FMT_TILE_A5X, SDE_MDP_CHROMA_420, + SDE_MDP_PIXEL_10BIT, + 0, + C1_B_Cb, C2_R_Cr, SDE_MDP_COMPRESS_UBWC), + .micro = { + .tile_height = 4, + .tile_width = 48, + }, + }, + { + .mdp_format = { + FMT_YUV_COMMON(SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC), + .description = "SDE/Y_CBCR_H2V2_P010_UBWC", + .flag = 0, + .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, + .chroma_sample = SDE_MDP_CHROMA_420, + .unpack_count = 2, + .bpp = 2, + .frame_format = SDE_MDP_FMT_TILE_A5X, + .pixel_mode = SDE_MDP_PIXEL_10BIT, + .element = { C1_B_Cb, C2_R_Cr }, + .unpack_tight = 0, + .unpack_align_msb = 1, + .is_ubwc = SDE_MDP_COMPRESS_UBWC + }, + .micro = { + .tile_height = 4, + .tile_width = 32, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_RGBA_1010102_TILE, + "SDE/RGBA_1010102_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_RGBX_1010102_TILE, + "SDE/RGBX_1010102102_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_BGRA_1010102_TILE, + "SDE/BGRA_1010102_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_BGRX_1010102_TILE, + "SDE/BGRX_1010102_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_ARGB_2101010_TILE, + "SDE/ARGB_2101010_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_XRGB_2101010_TILE, + "SDE/XRGB_2101010_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_ABGR_2101010_TILE, + "SDE/ABGR_2101010_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_1010102(SDE_PIX_FMT_XBGR_2101010_TILE, + "SDE/XBGR_2101010_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V2_TILE, + "Y_CRCB_H2V2_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_CHROMA_420, SDE_MDP_PIXEL_NORMAL, + SDE_MDP_FORMAT_FLAG_PRIVATE, + C2_R_Cr, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 8, + .tile_width = 32, + }, + }, + { + .mdp_format = + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H2V2_TILE, + "Y_CBCR_H2V2_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_CHROMA_420, SDE_MDP_PIXEL_NORMAL, + SDE_MDP_FORMAT_FLAG_PRIVATE, + C1_B_Cb, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 8, + .tile_width = 32, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_ABGR_8888_TILE, + "SDE/ABGR_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_XRGB_8888_TILE, + "SDE/XRGB_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 32, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_ARGB_8888_TILE, + "SDE/ARGB_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_RGBA_8888_TILE, + "SDE/RGBA_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_RGBX_8888_TILE, + "SDE/RGBX_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_BGRA_8888_TILE, + "SDE/BGRA_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_BGRX_8888_TILE, + "SDE/BGRX_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = + FMT_RGB_8888(SDE_PIX_FMT_XBGR_8888_TILE, + "SDE/XBGR_8888_TILE", + SDE_MDP_FMT_TILE_A5X, + SDE_MDP_FORMAT_FLAG_PRIVATE, + 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + .micro = { + .tile_height = 4, + .tile_width = 16, + }, + }, + { + .mdp_format = { + FMT_YUV_COMMON(SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE), + .description = "SDE/Y_CBCR_H2V2_P010_TILE", + .flag = SDE_MDP_FORMAT_FLAG_PRIVATE, + .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, + .chroma_sample = SDE_MDP_CHROMA_420, + .unpack_count = 2, + .bpp = 2, + .frame_format = SDE_MDP_FMT_TILE_A5X, + .pixel_mode = SDE_MDP_PIXEL_10BIT, + .element = { C1_B_Cb, C2_R_Cr }, + .unpack_tight = 0, + .unpack_align_msb = 1, + .is_ubwc = SDE_MDP_COMPRESS_NONE, + }, + .micro = { + .tile_height = 4, + .tile_width = 32, + }, + }, +}; + +static struct sde_mdp_format_params sde_mdp_format_map[] = { + FMT_RGB_565( + SDE_PIX_FMT_RGB_565, "RGB_565", SDE_MDP_FMT_LINEAR, + 0, C1_B_Cb, C0_G_Y, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + FMT_RGB_565( + SDE_PIX_FMT_BGR_565, "BGR_565", SDE_MDP_FMT_LINEAR, + 0, C2_R_Cr, C0_G_Y, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + FMT_RGB_888( + SDE_PIX_FMT_RGB_888, "RGB_888", SDE_MDP_FMT_LINEAR, + 0, C2_R_Cr, C0_G_Y, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + FMT_RGB_888( + SDE_PIX_FMT_BGR_888, "BGR_888", SDE_MDP_FMT_LINEAR, + 0, C1_B_Cb, C0_G_Y, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + + FMT_RGB_8888( + SDE_PIX_FMT_ABGR_8888, "SDE/ABGR_8888", SDE_MDP_FMT_LINEAR, + 0, 1, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + + FMT_RGB_8888( + SDE_PIX_FMT_XRGB_8888, "SDE/XRGB_8888", SDE_MDP_FMT_LINEAR, + 0, 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_ARGB_8888, "SDE/ARGB_8888", SDE_MDP_FMT_LINEAR, + 0, 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_RGBA_8888, "SDE/RGBA_8888", SDE_MDP_FMT_LINEAR, + 0, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_RGBX_8888, "SDE/RGBX_8888", SDE_MDP_FMT_LINEAR, + 0, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_BGRA_8888, "SDE/BGRA_8888", SDE_MDP_FMT_LINEAR, + 0, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_BGRX_8888, "SDE/BGRX_8888", SDE_MDP_FMT_LINEAR, + 0, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_XBGR_8888, "SDE/XBGR_8888", SDE_MDP_FMT_LINEAR, + 0, 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V1, "Y_CRCB_H2V1", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_H2V1, SDE_MDP_PIXEL_NORMAL, + 0, C2_R_Cr, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H2V1, "Y_CBCR_H2V1", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_H2V1, SDE_MDP_PIXEL_NORMAL, + 0, C1_B_Cb, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H1V2, "Y_CRCB_H1V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_H1V2, SDE_MDP_PIXEL_NORMAL, + 0, C2_R_Cr, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H1V2, "Y_CBCR_H1V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_H1V2, SDE_MDP_PIXEL_NORMAL, + 0, C1_B_Cb, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V2, "Y_CRCB_H2V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, SDE_MDP_PIXEL_NORMAL, + 0, C2_R_Cr, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H2V2, "Y_CBCR_H2V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, SDE_MDP_PIXEL_NORMAL, + 0, C1_B_Cb, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, "SDE/Y_CBCR_H2V2_VENUS", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, SDE_MDP_PIXEL_NORMAL, + 0, C1_B_Cb, C2_R_Cr, SDE_MDP_COMPRESS_NONE), + FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, "SDE/Y_CRCB_H2V2_VENUS", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, SDE_MDP_PIXEL_NORMAL, + 0, C2_R_Cr, C1_B_Cb, SDE_MDP_COMPRESS_NONE), + + { + FMT_YUV10_COMMON(SDE_PIX_FMT_Y_CBCR_H2V2_P010), + .description = "SDE/Y_CBCR_H2V2_P010", + .flag = 0, + .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, + .chroma_sample = SDE_MDP_CHROMA_420, + .unpack_count = 2, + .bpp = 2, + .frame_format = SDE_MDP_FMT_LINEAR, + .pixel_mode = SDE_MDP_PIXEL_10BIT, + .element = { C1_B_Cb, C2_R_Cr }, + .unpack_tight = 0, + .unpack_align_msb = 1, + .is_ubwc = SDE_MDP_COMPRESS_NONE, + }, + { + FMT_YUV10_COMMON(SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS), + .description = "SDE/Y_CBCR_H2V2_P010_VENUS", + .flag = 0, + .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, + .chroma_sample = SDE_MDP_CHROMA_420, + .unpack_count = 2, + .bpp = 2, + .frame_format = SDE_MDP_FMT_LINEAR, + .pixel_mode = SDE_MDP_PIXEL_10BIT, + .element = { C1_B_Cb, C2_R_Cr }, + .unpack_tight = 0, + .unpack_align_msb = 1, + .is_ubwc = SDE_MDP_COMPRESS_NONE, + }, + { + FMT_YUV_COMMON(SDE_PIX_FMT_Y_CBCR_H2V2_TP10), + .description = "SDE/Y_CBCR_H2V2_TP10", + .flag = 0, + .fetch_planes = SDE_MDP_PLANE_PSEUDO_PLANAR, + .chroma_sample = SDE_MDP_CHROMA_420, + .unpack_count = 2, + .bpp = 2, + .frame_format = SDE_MDP_FMT_TILE_A5X, + .pixel_mode = SDE_MDP_PIXEL_10BIT, + .element = { C1_B_Cb, C2_R_Cr }, + .unpack_tight = 1, + .unpack_align_msb = 0, + .is_ubwc = SDE_MDP_COMPRESS_NONE, + }, + + FMT_YUV_PLANR(SDE_PIX_FMT_Y_CB_CR_H2V2, "Y_CB_CR_H2V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, 0, C2_R_Cr, C1_B_Cb), + FMT_YUV_PLANR(SDE_PIX_FMT_Y_CR_CB_H2V2, "Y_CR_CB_H2V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, 0, C1_B_Cb, C2_R_Cr), + FMT_YUV_PLANR(SDE_PIX_FMT_Y_CR_CB_GH2V2, "SDE/Y_CR_CB_GH2V2", + SDE_MDP_FMT_LINEAR, + SDE_MDP_CHROMA_420, 0, C1_B_Cb, C2_R_Cr), + + { + FMT_YUV_COMMON(SDE_PIX_FMT_YCBYCR_H2V1), + .description = "YCBYCR_H2V1", + .flag = 0, + .fetch_planes = SDE_MDP_PLANE_INTERLEAVED, + .chroma_sample = SDE_MDP_CHROMA_H2V1, + .unpack_count = 4, + .bpp = 2, + .frame_format = SDE_MDP_FMT_LINEAR, + .pixel_mode = SDE_MDP_PIXEL_NORMAL, + .element = { C2_R_Cr, C0_G_Y, C1_B_Cb, C0_G_Y }, + .is_ubwc = SDE_MDP_COMPRESS_NONE, + }, + FMT_RGB_1555(SDE_PIX_FMT_RGBA_5551, "RGBA_5551", 1, 0, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_1555(SDE_PIX_FMT_ARGB_1555, "ARGB_1555", 1, 0, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_ABGR_1555, "ABGR_1555", 1, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_BGRA_5551, "BGRA_5551", 1, 0, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_1555(SDE_PIX_FMT_BGRX_5551, "BGRX_5551", 0, 0, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_1555(SDE_PIX_FMT_RGBX_5551, "RGBX_5551", 0, 0, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_1555(SDE_PIX_FMT_XBGR_1555, "XBGR_1555", 0, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_XRGB_1555, "XRGB_1555", 0, 0, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_RGBA_4444, "RGBA_4444", 1, 0, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_4444(SDE_PIX_FMT_ARGB_4444, "ARGB_4444", 1, 0, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_BGRA_4444, "BGRA_4444", 1, 0, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_4444(SDE_PIX_FMT_ABGR_4444, "ABGR_4444", 1, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_RGBX_4444, "RGBX_4444", 0, 0, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_4444(SDE_PIX_FMT_XRGB_4444, "XRGB_4444", 0, 0, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_BGRX_4444, "BGRX_4444", 0, 0, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_4444(SDE_PIX_FMT_XBGR_4444, "XBGR_4444", 0, 0, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1010102(SDE_PIX_FMT_RGBA_1010102, "SDE/RGBA_1010102", + SDE_MDP_FMT_LINEAR, + 0, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_RGBX_1010102, "SDE/RGBX_1010102", + SDE_MDP_FMT_LINEAR, + 0, 0, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_BGRA_1010102, "SDE/BGRA_1010102", + SDE_MDP_FMT_LINEAR, + 0, 1, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_BGRX_1010102, "SDE/BGRX_1010102", + SDE_MDP_FMT_LINEAR, + 0, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_ARGB_2101010, "SDE/ARGB_2101010", + SDE_MDP_FMT_LINEAR, + 0, 1, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_XRGB_2101010, "SDE/XRGB_2101010", + SDE_MDP_FMT_LINEAR, + 0, 0, C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_ABGR_2101010, "SDE/ABGR_2101010", + SDE_MDP_FMT_LINEAR, + 0, 1, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), + FMT_RGB_1010102(SDE_PIX_FMT_XBGR_2101010, "SDE/XBGR_2101010", + SDE_MDP_FMT_LINEAR, + 0, 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, + SDE_MDP_COMPRESS_NONE), +}; + +/* + * sde_get_format_params - return format parameter of the given format + * @format: format to lookup + */ +struct sde_mdp_format_params *sde_get_format_params(u32 format) +{ + struct sde_mdp_format_params *fmt = NULL; + int i; + bool fmt_found = false; + + for (i = 0; i < ARRAY_SIZE(sde_mdp_format_map); i++) { + fmt = &sde_mdp_format_map[i]; + if (format == fmt->format) { + fmt_found = true; + break; + } + } + + if (!fmt_found) { + for (i = 0; i < ARRAY_SIZE(sde_mdp_format_ubwc_map); i++) { + fmt = &sde_mdp_format_ubwc_map[i].mdp_format; + if (format == fmt->format) { + fmt_found = true; + break; + } + } + } + /* If format not supported than return NULL */ + if (!fmt_found) + fmt = NULL; + + return fmt; +} + +/* + * sde_rot_get_ubwc_micro_dim - return micro dimension of the given ubwc format + * @format: format to lookup + * @w: Pointer to returned width dimension + * @h: Pointer to returned height dimension + */ +int sde_rot_get_ubwc_micro_dim(u32 format, u16 *w, u16 *h) +{ + struct sde_mdp_format_params_ubwc *fmt = NULL; + bool fmt_found = false; + int i; + + for (i = 0; i < ARRAY_SIZE(sde_mdp_format_ubwc_map); i++) { + fmt = &sde_mdp_format_ubwc_map[i]; + if (format == fmt->mdp_format.format) { + fmt_found = true; + break; + } + } + + if (!fmt_found) + return -EINVAL; + + *w = fmt->micro.tile_width; + *h = fmt->micro.tile_height; + + return 0; +} + +/* + * sde_rot_get_tilea5x_pixfmt - get base a5x tile format of given source format + * @src_pixfmt: source pixel format to be converted + * @dst_pixfmt: pointer to base a5x tile pixel format + * return: 0 if success; error code otherwise + */ +int sde_rot_get_base_tilea5x_pixfmt(u32 src_pixfmt, u32 *dst_pixfmt) +{ + int rc = 0; + + if (!dst_pixfmt) { + SDEROT_ERR("invalid parameters\n"); + return -EINVAL; + } + + switch (src_pixfmt) { + case SDE_PIX_FMT_Y_CBCR_H2V2: + case SDE_PIX_FMT_Y_CBCR_H2V2_UBWC: + case SDE_PIX_FMT_Y_CBCR_H2V2_TILE: + *dst_pixfmt = SDE_PIX_FMT_Y_CBCR_H2V2_TILE; + break; + case SDE_PIX_FMT_Y_CRCB_H2V2: + case SDE_PIX_FMT_Y_CRCB_H2V2_TILE: + *dst_pixfmt = SDE_PIX_FMT_Y_CRCB_H2V2_TILE; + break; + case V4L2_PIX_FMT_RGB565: + case SDE_PIX_FMT_RGB_565_UBWC: + case SDE_PIX_FMT_RGB_565_TILE: + *dst_pixfmt = SDE_PIX_FMT_RGB_565_TILE; + break; + case SDE_PIX_FMT_RGBA_8888: + case SDE_PIX_FMT_RGBA_8888_UBWC: + case SDE_PIX_FMT_RGBA_8888_TILE: + *dst_pixfmt = SDE_PIX_FMT_RGBA_8888_TILE; + break; + case SDE_PIX_FMT_RGBX_8888: + case SDE_PIX_FMT_RGBX_8888_UBWC: + case SDE_PIX_FMT_RGBX_8888_TILE: + *dst_pixfmt = SDE_PIX_FMT_RGBX_8888_TILE; + break; + case SDE_PIX_FMT_ARGB_8888: + case SDE_PIX_FMT_ARGB_8888_TILE: + *dst_pixfmt = SDE_PIX_FMT_ARGB_8888_TILE; + break; + case SDE_PIX_FMT_XRGB_8888: + case SDE_PIX_FMT_XRGB_8888_TILE: + *dst_pixfmt = SDE_PIX_FMT_XRGB_8888_TILE; + break; + case SDE_PIX_FMT_ABGR_8888: + case SDE_PIX_FMT_ABGR_8888_TILE: + *dst_pixfmt = SDE_PIX_FMT_ABGR_8888_TILE; + break; + case SDE_PIX_FMT_XBGR_8888: + case SDE_PIX_FMT_XBGR_8888_TILE: + *dst_pixfmt = SDE_PIX_FMT_XBGR_8888_TILE; + break; + case SDE_PIX_FMT_ARGB_2101010: + case SDE_PIX_FMT_ARGB_2101010_TILE: + *dst_pixfmt = SDE_PIX_FMT_ARGB_2101010_TILE; + break; + case SDE_PIX_FMT_XRGB_2101010: + case SDE_PIX_FMT_XRGB_2101010_TILE: + *dst_pixfmt = SDE_PIX_FMT_XRGB_2101010_TILE; + break; + case SDE_PIX_FMT_ABGR_2101010: + case SDE_PIX_FMT_ABGR_2101010_TILE: + *dst_pixfmt = SDE_PIX_FMT_ABGR_2101010_TILE; + break; + case SDE_PIX_FMT_XBGR_2101010: + case SDE_PIX_FMT_XBGR_2101010_TILE: + *dst_pixfmt = SDE_PIX_FMT_XBGR_2101010_TILE; + break; + case SDE_PIX_FMT_BGRA_1010102: + case SDE_PIX_FMT_BGRA_1010102_TILE: + *dst_pixfmt = SDE_PIX_FMT_BGRA_1010102_TILE; + break; + case SDE_PIX_FMT_BGRX_1010102: + case SDE_PIX_FMT_BGRX_1010102_TILE: + *dst_pixfmt = SDE_PIX_FMT_BGRX_1010102_TILE; + break; + case SDE_PIX_FMT_Y_CBCR_H2V2_P010: + case SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE: + case SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC: + *dst_pixfmt = SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE; + break; + case SDE_PIX_FMT_Y_CBCR_H2V2_TP10: + case SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC: + *dst_pixfmt = SDE_PIX_FMT_Y_CBCR_H2V2_TP10; + break; + default: + SDEROT_ERR("invalid src pixel format %c%c%c%c\n", + src_pixfmt >> 0, src_pixfmt >> 8, + src_pixfmt >> 16, src_pixfmt >> 24); + rc = -EINVAL; + break; + } + + return rc; +} diff --git a/techpack/display/rotator/sde_rotator_formats.h b/techpack/display/rotator/sde_rotator_formats.h new file mode 100644 index 0000000000000000000000000000000000000000..71fa47b1caeb287410b3c10f1b952b0c2f085c15 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_formats.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_ROTATOR_FORMATS_H +#define SDE_ROTATOR_FORMATS_H + +#include <linux/types.h> +#include <media/msm_sde_rotator.h> + +/* Internal rotator pixel formats */ +#define SDE_PIX_FMT_RGBA_8888_TILE v4l2_fourcc('Q', 'T', '0', '0') +#define SDE_PIX_FMT_RGBX_8888_TILE v4l2_fourcc('Q', 'T', '0', '1') +#define SDE_PIX_FMT_BGRA_8888_TILE v4l2_fourcc('Q', 'T', '0', '2') +#define SDE_PIX_FMT_BGRX_8888_TILE v4l2_fourcc('Q', 'T', '0', '3') +#define SDE_PIX_FMT_ARGB_8888_TILE v4l2_fourcc('Q', 'T', '0', '4') +#define SDE_PIX_FMT_XRGB_8888_TILE v4l2_fourcc('Q', 'T', '0', '5') +#define SDE_PIX_FMT_ABGR_8888_TILE v4l2_fourcc('Q', 'T', '0', '6') +#define SDE_PIX_FMT_XBGR_8888_TILE v4l2_fourcc('Q', 'T', '0', '7') +#define SDE_PIX_FMT_Y_CBCR_H2V2_TILE v4l2_fourcc('Q', 'T', '0', '8') +#define SDE_PIX_FMT_Y_CRCB_H2V2_TILE v4l2_fourcc('Q', 'T', '0', '9') +#define SDE_PIX_FMT_ARGB_2101010_TILE v4l2_fourcc('Q', 'T', '0', 'A') +#define SDE_PIX_FMT_XRGB_2101010_TILE v4l2_fourcc('Q', 'T', '0', 'B') +#define SDE_PIX_FMT_ABGR_2101010_TILE v4l2_fourcc('Q', 'T', '0', 'C') +#define SDE_PIX_FMT_XBGR_2101010_TILE v4l2_fourcc('Q', 'T', '0', 'D') +#define SDE_PIX_FMT_BGRA_1010102_TILE v4l2_fourcc('Q', 'T', '0', 'E') +#define SDE_PIX_FMT_BGRX_1010102_TILE v4l2_fourcc('Q', 'T', '0', 'F') +#define SDE_PIX_FMT_RGBA_1010102_TILE v4l2_fourcc('Q', 'T', '1', '0') +#define SDE_PIX_FMT_RGBX_1010102_TILE v4l2_fourcc('Q', 'T', '1', '1') +#define SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE v4l2_fourcc('Q', 'T', '1', '2') +#define SDE_PIX_FMT_RGB_565_TILE v4l2_fourcc('Q', 'T', '1', '3') + +#define SDE_ROT_MAX_PLANES 4 + +#define UBWC_META_MACRO_W_H 16 +#define UBWC_META_BLOCK_SIZE 256 + +/* + * Value of enum chosen to fit the number of bits + * expected by the HW programming. + */ +enum { + SDE_COLOR_4BIT, + SDE_COLOR_5BIT, + SDE_COLOR_6BIT, + SDE_COLOR_8BIT, + SDE_COLOR_ALPHA_1BIT = 0, + SDE_COLOR_ALPHA_4BIT = 1, +}; + +#define C3_ALPHA 3 /* alpha */ +#define C2_R_Cr 2 /* R/Cr */ +#define C1_B_Cb 1 /* B/Cb */ +#define C0_G_Y 0 /* G/luma */ + +enum sde_mdp_compress_type { + SDE_MDP_COMPRESS_NONE, + SDE_MDP_COMPRESS_UBWC, +}; + +enum sde_mdp_frame_format_type { + SDE_MDP_FMT_LINEAR, + SDE_MDP_FMT_TILE_A4X, + SDE_MDP_FMT_TILE_A5X, +}; + +enum sde_mdp_pixel_type { + SDE_MDP_PIXEL_NORMAL, + SDE_MDP_PIXEL_10BIT, +}; + +enum sde_mdp_sspp_fetch_type { + SDE_MDP_PLANE_INTERLEAVED, + SDE_MDP_PLANE_PLANAR, + SDE_MDP_PLANE_PSEUDO_PLANAR, +}; + +enum sde_mdp_sspp_chroma_samp_type { + SDE_MDP_CHROMA_RGB, + SDE_MDP_CHROMA_H2V1, + SDE_MDP_CHROMA_H1V2, + SDE_MDP_CHROMA_420 +}; + +enum sde_mdp_format_flag_type { + SDE_MDP_FORMAT_FLAG_PRIVATE = BIT(0) +}; + +struct sde_mdp_format_params { + u32 format; + const char *description; + u32 flag; + u8 is_yuv; + u8 is_ubwc; + + u8 frame_format; + u8 chroma_sample; + u8 solid_fill; + u8 fetch_planes; + u8 unpack_align_msb; /* 0 to LSB, 1 to MSB */ + u8 unpack_tight; /* 0 for loose, 1 for tight */ + u8 unpack_count; /* 0 = 1 component, 1 = 2 component ... */ + u8 bpp; + u8 alpha_enable; /* source has alpha */ + u8 pixel_mode; /* 0: normal, 1:10bit */ + u8 bits[SDE_ROT_MAX_PLANES]; + u8 element[SDE_ROT_MAX_PLANES]; +}; + +struct sde_mdp_format_ubwc_tile_info { + u16 tile_height; + u16 tile_width; +}; + +struct sde_mdp_format_params_ubwc { + struct sde_mdp_format_params mdp_format; + struct sde_mdp_format_ubwc_tile_info micro; +}; + +struct sde_mdp_format_params *sde_get_format_params(u32 format); + +int sde_rot_get_ubwc_micro_dim(u32 format, u16 *w, u16 *h); + +int sde_rot_get_base_tilea5x_pixfmt(u32 src_pixfmt, u32 *dst_pixfmt); + +static inline bool sde_mdp_is_tilea4x_format(struct sde_mdp_format_params *fmt) +{ + return fmt && (fmt->frame_format == SDE_MDP_FMT_TILE_A4X); +} + +static inline bool sde_mdp_is_tilea5x_format(struct sde_mdp_format_params *fmt) +{ + return fmt && (fmt->frame_format == SDE_MDP_FMT_TILE_A5X); +} + +static inline bool sde_mdp_is_ubwc_format(struct sde_mdp_format_params *fmt) +{ + return fmt && (fmt->is_ubwc == SDE_MDP_COMPRESS_UBWC); +} + +static inline bool sde_mdp_is_linear_format(struct sde_mdp_format_params *fmt) +{ + return fmt && (fmt->frame_format == SDE_MDP_FMT_LINEAR); +} + +static inline bool sde_mdp_is_nv12_format(struct sde_mdp_format_params *fmt) +{ + return fmt && (fmt->fetch_planes == SDE_MDP_PLANE_PSEUDO_PLANAR) && + (fmt->chroma_sample == SDE_MDP_CHROMA_420); +} + +static inline bool sde_mdp_is_nv12_8b_format(struct sde_mdp_format_params *fmt) +{ + return fmt && sde_mdp_is_nv12_format(fmt) && + (fmt->pixel_mode == SDE_MDP_PIXEL_NORMAL); +} + +static inline bool sde_mdp_is_nv12_10b_format(struct sde_mdp_format_params *fmt) +{ + return fmt && sde_mdp_is_nv12_format(fmt) && + (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT); +} + +static inline bool sde_mdp_is_tp10_format(struct sde_mdp_format_params *fmt) +{ + return fmt && sde_mdp_is_nv12_10b_format(fmt) && + fmt->unpack_tight; +} + +static inline bool sde_mdp_is_p010_format(struct sde_mdp_format_params *fmt) +{ + return fmt && sde_mdp_is_nv12_10b_format(fmt) && + !fmt->unpack_tight; +} + +static inline bool sde_mdp_is_yuv_format(struct sde_mdp_format_params *fmt) +{ + return fmt && fmt->is_yuv; +} + +static inline bool sde_mdp_is_rgb_format(struct sde_mdp_format_params *fmt) +{ + return !sde_mdp_is_yuv_format(fmt); +} + +static inline bool sde_mdp_is_private_format(struct sde_mdp_format_params *fmt) +{ + return fmt && (fmt->flag & SDE_MDP_FORMAT_FLAG_PRIVATE); +} + +static inline int sde_mdp_format_blk_size(struct sde_mdp_format_params *fmt) +{ + return sde_mdp_is_tp10_format(fmt) ? 96 : 128; +} +#endif diff --git a/techpack/display/rotator/sde_rotator_hwio.h b/techpack/display/rotator/sde_rotator_hwio.h new file mode 100644 index 0000000000000000000000000000000000000000..2ef6cf7dabb708b676e5148b44b8f1ed5ae2f46a --- /dev/null +++ b/techpack/display/rotator/sde_rotator_hwio.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_ROTATOR_HWIO_H +#define SDE_ROTATOR_HWIO_H + +#include <linux/bitops.h> + +#define SDE_REG_HW_VERSION 0x0 +#define SDE_REG_HW_INTR_STATUS 0x10 + +#define SDE_INTR_MDP BIT(0) + +#define SDE_MDP_OFFSET 0x1000 + +#define MMSS_MDP_PANIC_ROBUST_CTRL 0x00178 +#define MMSS_MDP_PANIC_LUT0 0x0017C +#define MMSS_MDP_PANIC_LUT1 0x00180 +#define MMSS_MDP_ROBUST_LUT 0x00184 +#define MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL 0x00190 + +/* following offsets are with respect to MDP VBIF base */ +#define MMSS_VBIF_CLKON 0x4 +#define MMSS_VBIF_RD_LIM_CONF 0x0B0 +#define MMSS_VBIF_WR_LIM_CONF 0x0C0 + +#define MMSS_VBIF_XIN_HALT_CTRL0 0x200 +#define MMSS_VBIF_XIN_HALT_CTRL1 0x204 +#define MMSS_VBIF_AXI_HALT_CTRL0 0x208 +#define MMSS_VBIF_AXI_HALT_CTRL1 0x20C +#define MMSS_VBIF_TEST_BUS_OUT_CTRL 0x210 +#define MMSS_VBIF_TEST_BUS_OUT 0x230 + +#define SDE_VBIF_QOS_REMAP_BASE 0x020 +#define SDE_VBIF_QOS_REMAP_ENTRIES 0x4 + +#define SDE_VBIF_FIXED_SORT_EN 0x30 +#define SDE_VBIF_FIXED_SORT_SEL0 0x34 + +/* MMSS_VBIF_NRT - offset relative to base offset */ +#define MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0 0x0008 +#define MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0 0 +#define MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1 1 +#define MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1 0x000C +#define MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 0x0020 +#define MMSS_VBIF_NRT_VBIF_QOS_REMAP_01 0x0024 +#define MMSS_VBIF_NRT_VBIF_QOS_REMAP_10 0x0028 +#define MMSS_VBIF_NRT_VBIF_QOS_REMAP_11 0x002C +#define MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN 0x00AC +#define MMSS_VBIF_NRT_VBIF_IN_RD_LIM_CONF0 0x00B0 +#define MMSS_VBIF_NRT_VBIF_IN_RD_LIM_CONF1 0x00B4 +#define MMSS_VBIF_NRT_VBIF_IN_RD_LIM_CONF2 0x00B8 +#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF0 0x00C0 +#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF1 0x00C4 +#define MMSS_VBIF_NRT_VBIF_IN_WR_LIM_CONF2 0x00C8 +#define MMSS_VBIF_NRT_VBIF_OUT_RD_LIM_CONF0 0x00D0 +#define MMSS_VBIF_NRT_VBIF_OUT_WR_LIM_CONF0 0x00D4 +#define MMSS_VBIF_NRT_VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160 +#define MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 0x0550 +#define MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 0x0590 + +#define SDE_MDP_REG_TRAFFIC_SHAPER_EN BIT(31) +#define SDE_MDP_REG_TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4)) +#define SDE_MDP_REG_TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) +#define SDE_MDP_REG_TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 + +#endif diff --git a/techpack/display/rotator/sde_rotator_inline.h b/techpack/display/rotator/sde_rotator_inline.h new file mode 100644 index 0000000000000000000000000000000000000000..809a7d0f9a1960a498daa40385bca4e04418e692 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_inline.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_INLINE_H__ +#define __SDE_ROTATOR_INLINE_H__ + +#include <linux/types.h> +#include <linux/dma-buf.h> +#include <linux/platform_device.h> + +#include "sde_rotator_formats.h" + +#define SDE_ROTATOR_INLINE_PLANE_MAX 4 + +/* + * enum sde_rotator_inline_cmd_type - inline rotator command stages + * @SDE_ROTATOR_INLINE_CMD_VALIDATE: validate command only + * @SDE_ROTATOR_INLINE_CMD_COMMIT: commit command to hardware + * @SDE_ROTATOR_INLINE_CMD_START: ready to start inline rotation + * @SDE_ROTATOR_INLINE_CMD_CLEANUP: cleanup after commit is done + * @SDE_ROTATOR_INLINE_CMD_ABORT: abort current commit and reset + */ +enum sde_rotator_inline_cmd_type { + SDE_ROTATOR_INLINE_CMD_VALIDATE, + SDE_ROTATOR_INLINE_CMD_COMMIT, + SDE_ROTATOR_INLINE_CMD_START, + SDE_ROTATOR_INLINE_CMD_CLEANUP, + SDE_ROTATOR_INLINE_CMD_ABORT, +}; + +/** + * sde_rotator_inline_cmd - inline rotation command + * @sequence_id: unique command sequence identifier + * @video_mode: true if video interface is connected + * @fps: frame rate in frame-per-second + * @rot90: rotate 90 counterclockwise + * @hflip: horizontal flip prior to rotation + * @vflip: vertical flip prior to rotation + * @secure: true if buffer is in secure domain + * @prefill_bw: prefill bandwidth in Bps + * @clkrate: clock rate in Hz + * @data_bw: data bus bandwidth in Bps + * @src_addr: source i/o buffer virtual address + * @src_len: source i/o buffer length + * @src_planes: source plane number + * @src_pixfmt: v4l2 fourcc pixel format of source buffer + * @src_width: width of source buffer + * @src_height: height of source buffer + * @src_rect_x: roi x coordinate of source buffer + * @src_rect_y: roi y coordinate of source buffer + * @src_rect_w: roi width of source buffer + * @src_rect_h: roi height of source buffer + * @dst_addr: destination i/o virtual buffer address + * @dst_len: destination i/o buffer length + * @dst_planes: destination plane number + * @dst_pixfmt: v4l2 fourcc pixel format of destination buffer + * @dst_rect_x: roi x coordinate of destination buffer + * @dst_rect_y: roi y coordinate of destination buffer + * @dst_rect_w: roi width of destination buffer + * @dst_rect_h: roi height of destination buffer + * @dst_writeback: true if cache writeback is required + * @priv_handle: private handle of rotator session + */ +struct sde_rotator_inline_cmd { + u32 sequence_id; + bool video_mode; + u32 fps; + bool rot90; + bool hflip; + bool vflip; + bool secure; + u64 prefill_bw; + u64 clkrate; + u64 data_bw; + dma_addr_t src_addr[SDE_ROTATOR_INLINE_PLANE_MAX]; + u32 src_len[SDE_ROTATOR_INLINE_PLANE_MAX]; + u32 src_planes; + u32 src_pixfmt; + u32 src_width; + u32 src_height; + u32 src_rect_x; + u32 src_rect_y; + u32 src_rect_w; + u32 src_rect_h; + dma_addr_t dst_addr[SDE_ROTATOR_INLINE_PLANE_MAX]; + u32 dst_len[SDE_ROTATOR_INLINE_PLANE_MAX]; + u32 dst_planes; + u32 dst_pixfmt; + u32 dst_rect_x; + u32 dst_rect_y; + u32 dst_rect_w; + u32 dst_rect_h; + bool dst_writeback; + void *priv_handle; +}; + +#if defined(CONFIG_MSM_SDE_ROTATOR) + +void *sde_rotator_inline_open(struct platform_device *pdev); +int sde_rotator_inline_get_dst_pixfmt(struct platform_device *pdev, + u32 src_pixfmt, u32 *dst_pixfmt); +int sde_rotator_inline_get_downscale_caps(struct platform_device *pdev, + char *downscale_caps, int len); +int sde_rotator_inline_get_maxlinewidth(struct platform_device *pdev); +int sde_rotator_inline_get_pixfmt_caps(struct platform_device *pdev, + bool input, u32 *pixfmt, int len); +int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd, + enum sde_rotator_inline_cmd_type cmd_type); +int sde_rotator_inline_release(void *handle); +void sde_rotator_inline_reg_dump(struct platform_device *pdev); + +#else + +void *sde_rotator_inline_open(struct platform_device *pdev) +{ + return NULL; +} + +int sde_rotator_inline_get_dst_pixfmt(struct platform_device *pdev, + u32 src_pixfmt, u32 *dst_pixfmt) +{ + return 0; +} + +int sde_rotator_inline_get_downscale_caps(struct platform_device *pdev, + char *downscale_caps, int len) +{ + return 0; +} + +int sde_rotator_inline_get_maxlinewidth(struct platform_device *pdev) +{ + return 0; +} + +int sde_rotator_inline_get_pixfmt_caps(struct platform_device *pdev, + bool input, u32 *pixfmt, int len) +{ + return 0; +} + +int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd, + enum sde_rotator_inline_cmd_type cmd_type) +{ + return 0; +} + +int sde_rotator_inline_release(void *handle) +{ + return 0; +} + +void sde_rotator_inline_reg_dump(struct platform_device *pdev) +{ +} + +#endif + +#endif /* __SDE_ROTATOR_INLINE_H__ */ diff --git a/techpack/display/rotator/sde_rotator_io_util.c b/techpack/display/rotator/sde_rotator_io_util.c new file mode 100644 index 0000000000000000000000000000000000000000..3fe1de7f29847d12fb6791eb37f29791428c5c0f --- /dev/null +++ b/techpack/display/rotator/sde_rotator_io_util.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> + +#include "sde_rotator_io_util.h" + +void sde_reg_w(struct sde_io_data *io, u32 offset, u32 value, u32 debug) +{ + u32 in_val; + + if (!io || !io->base) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + if (offset > io->len) { + DEV_ERR("%pS->%s: offset out of range\n", + __builtin_return_address(0), __func__); + return; + } + + DEV_DBG("sdeio:%6.6x:%8.8x\n", offset, value); + writel_relaxed(value, io->base + offset); + if (debug) { + /* ensure register read is ordered after register write */ + mb(); + in_val = readl_relaxed(io->base + offset); + DEV_DBG("[%08x] => %08x [%08x]\n", + (u32)(unsigned long)(io->base + offset), + value, in_val); + } +} /* sde_reg_w */ + +u32 sde_reg_r(struct sde_io_data *io, u32 offset, u32 debug) +{ + u32 value; + + if (!io || !io->base) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + if (offset > io->len) { + DEV_ERR("%pS->%s: offset out of range\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + value = readl_relaxed(io->base + offset); + if (debug) + DEV_DBG("[%08x] <= %08x\n", + (u32)(unsigned long)(io->base + offset), value); + + DEV_DBG("sdeio:%6.6x:%8.8x\n", offset, value); + return value; +} /* sde_reg_r */ + +void sde_reg_dump(void __iomem *base, u32 length, const char *prefix, + u32 debug) +{ + if (debug) + print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_OFFSET, 32, 4, + (void *)base, length, false); +} /* sde_reg_dump */ + +static struct resource *sde_rot_get_res_byname(struct platform_device *pdev, + unsigned int type, const char *name) +{ + struct resource *res = NULL; + + res = platform_get_resource_byname(pdev, type, name); + if (!res) + DEV_ERR("%s: '%s' resource not found\n", __func__, name); + + return res; +} /* sde_rot_get_res_byname */ + +int sde_rot_ioremap_byname(struct platform_device *pdev, + struct sde_io_data *io_data, const char *name) +{ + struct resource *res = NULL; + + if (!pdev || !io_data) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + res = sde_rot_get_res_byname(pdev, IORESOURCE_MEM, name); + if (!res) { + DEV_ERR("%pS->%s: '%s' sde_rot_get_res_byname failed\n", + __builtin_return_address(0), __func__, name); + return -ENODEV; + } + + io_data->len = (u32)resource_size(res); + io_data->base = ioremap(res->start, io_data->len); + if (!io_data->base) { + DEV_ERR("%pS->%s: '%s' ioremap failed\n", + __builtin_return_address(0), __func__, name); + return -EIO; + } + + return 0; +} /* sde_rot_ioremap_byname */ + +void sde_rot_iounmap(struct sde_io_data *io_data) +{ + if (!io_data) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + if (io_data->base) { + iounmap(io_data->base); + io_data->base = NULL; + } + io_data->len = 0; +} /* sde_rot_iounmap */ + +int sde_rot_config_vreg(struct device *dev, struct sde_vreg *in_vreg, + int num_vreg, int config) +{ + int i = 0, rc = 0; + struct sde_vreg *curr_vreg = NULL; + enum sde_vreg_type type; + + if (!dev || !in_vreg || !num_vreg) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + if (config) { + for (i = 0; i < num_vreg; i++) { + curr_vreg = &in_vreg[i]; + curr_vreg->vreg = regulator_get(dev, + curr_vreg->vreg_name); + rc = PTR_RET(curr_vreg->vreg); + if (rc) { + DEV_ERR("%pS->%s: %s get failed. rc=%d\n", + __builtin_return_address(0), __func__, + curr_vreg->vreg_name, rc); + curr_vreg->vreg = NULL; + goto vreg_get_fail; + } + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? SDE_REG_LDO : SDE_REG_VS; + if (type == SDE_REG_LDO) { + rc = regulator_set_voltage( + curr_vreg->vreg, + curr_vreg->min_voltage, + curr_vreg->max_voltage); + if (rc < 0) { + DEV_ERR("%pS->%s: %s set vltg fail\n", + __builtin_return_address(0), + __func__, + curr_vreg->vreg_name); + goto vreg_set_voltage_fail; + } + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + if (curr_vreg->vreg) { + type = (regulator_count_voltages( + curr_vreg->vreg) > 0) + ? SDE_REG_LDO : SDE_REG_VS; + if (type == SDE_REG_LDO) { + regulator_set_voltage(curr_vreg->vreg, + 0, curr_vreg->max_voltage); + } + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + } + } + } + return 0; + +vreg_unconfig: +if (type == SDE_REG_LDO) + regulator_set_load(curr_vreg->vreg, 0); + +vreg_set_voltage_fail: + regulator_put(curr_vreg->vreg); + curr_vreg->vreg = NULL; + +vreg_get_fail: + for (i--; i >= 0; i--) { + curr_vreg = &in_vreg[i]; + type = (regulator_count_voltages(curr_vreg->vreg) > 0) + ? SDE_REG_LDO : SDE_REG_VS; + goto vreg_unconfig; + } + return rc; +} /* sde_rot_config_vreg */ + +int sde_rot_enable_vreg(struct sde_vreg *in_vreg, int num_vreg, int enable) +{ + int i = 0, rc = 0; + bool need_sleep; + + if (!in_vreg) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + if (enable) { + for (i = 0; i < num_vreg; i++) { + rc = PTR_RET(in_vreg[i].vreg); + if (rc) { + DEV_ERR("%pS->%s: %s regulator error. rc=%d\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name, rc); + goto vreg_set_opt_mode_fail; + } + need_sleep = !regulator_is_enabled(in_vreg[i].vreg); + if (in_vreg[i].pre_on_sleep && need_sleep) + usleep_range(in_vreg[i].pre_on_sleep * 1000, + in_vreg[i].pre_on_sleep * 1000); + rc = regulator_set_load(in_vreg[i].vreg, + in_vreg[i].enable_load); + if (rc < 0) { + DEV_ERR("%pS->%s: %s set opt m fail\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + goto vreg_set_opt_mode_fail; + } + rc = regulator_enable(in_vreg[i].vreg); + if (in_vreg[i].post_on_sleep && need_sleep) + usleep_range(in_vreg[i].post_on_sleep * 1000, + in_vreg[i].post_on_sleep * 1000); + if (rc < 0) { + DEV_ERR("%pS->%s: %s enable failed\n", + __builtin_return_address(0), __func__, + in_vreg[i].vreg_name); + goto disable_vreg; + } + } + } else { + for (i = num_vreg-1; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + in_vreg[i].pre_off_sleep * 1000); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + in_vreg[i].post_off_sleep * 1000); + } + } + return rc; + +disable_vreg: + regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); + +vreg_set_opt_mode_fail: + for (i--; i >= 0; i--) { + if (in_vreg[i].pre_off_sleep) + usleep_range(in_vreg[i].pre_off_sleep * 1000, + in_vreg[i].pre_off_sleep * 1000); + regulator_set_load(in_vreg[i].vreg, + in_vreg[i].disable_load); + regulator_disable(in_vreg[i].vreg); + if (in_vreg[i].post_off_sleep) + usleep_range(in_vreg[i].post_off_sleep * 1000, + in_vreg[i].post_off_sleep * 1000); + } + + return rc; +} /* sde_rot_enable_vreg */ + +void sde_rot_put_clk(struct sde_clk *clk_arry, int num_clk) +{ + int i; + + if (!clk_arry) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return; + } + + for (i = num_clk - 1; i >= 0; i--) { + if (clk_arry[i].clk) + clk_put(clk_arry[i].clk); + clk_arry[i].clk = NULL; + } +} /* sde_rot_put_clk */ + +int sde_rot_get_clk(struct device *dev, struct sde_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + if (!dev || !clk_arry) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + for (i = 0; i < num_clk; i++) { + clk_arry[i].clk = clk_get(dev, clk_arry[i].clk_name); + rc = PTR_RET(clk_arry[i].clk); + if (rc) { + DEV_ERR("%pS->%s: '%s' get failed. rc=%d\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, rc); + goto error; + } + } + + return rc; + +error: + sde_rot_put_clk(clk_arry, num_clk); + + return rc; +} /* sde_rot_get_clk */ + +int sde_rot_clk_set_rate(struct sde_clk *clk_arry, int num_clk) +{ + int i, rc = 0; + + if (!clk_arry) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + for (i = 0; i < num_clk; i++) { + if (clk_arry[i].clk) { + if (clk_arry[i].type != SDE_CLK_AHB) { + DEV_DBG("%pS->%s: '%s' rate %ld\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name, + clk_arry[i].rate); + rc = clk_set_rate(clk_arry[i].clk, + clk_arry[i].rate); + if (rc) { + DEV_ERR("%pS->%s: %s failed. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + break; + } + } + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + break; + } + } + + return rc; +} /* sde_rot_clk_set_rate */ + +int sde_rot_enable_clk(struct sde_clk *clk_arry, int num_clk, int enable) +{ + int i, rc = 0; + + if (!clk_arry) { + DEV_ERR("%pS->%s: invalid input\n", + __builtin_return_address(0), __func__); + return -EINVAL; + } + + if (enable) { + for (i = 0; i < num_clk; i++) { + DEV_DBG("%pS->%s: enable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + if (clk_arry[i].clk) { + rc = clk_prepare_enable(clk_arry[i].clk); + if (rc) + DEV_ERR("%pS->%s: %s en fail. rc=%d\n", + __builtin_return_address(0), + __func__, + clk_arry[i].clk_name, rc); + } else { + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + rc = -EPERM; + } + + if (rc) { + sde_rot_enable_clk(&clk_arry[i], + i, false); + break; + } + } + } else { + for (i = num_clk - 1; i >= 0; i--) { + DEV_DBG("%pS->%s: disable '%s'\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + + if (clk_arry[i].clk) + clk_disable_unprepare(clk_arry[i].clk); + else + DEV_ERR("%pS->%s: '%s' is not available\n", + __builtin_return_address(0), __func__, + clk_arry[i].clk_name); + } + } + + return rc; +} /* sde_rot_enable_clk */ diff --git a/techpack/display/rotator/sde_rotator_io_util.h b/techpack/display/rotator/sde_rotator_io_util.h new file mode 100644 index 0000000000000000000000000000000000000000..f78ba0fb87e769173de07f504dad8f14731ea63e --- /dev/null +++ b/techpack/display/rotator/sde_rotator_io_util.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ + + +#ifndef __SDE_ROTATOR_IO_UTIL_H__ +#define __SDE_ROTATOR_IO_UTIL_H__ + +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/i2c.h> +#include <linux/types.h> + +#ifdef DEBUG +#define DEV_DBG(fmt, args...) pr_err("<SDEROT_ERR> " fmt, ##args) +#else +#define DEV_DBG(fmt, args...) pr_debug("<SDEROT_DBG> " fmt, ##args) +#endif +#define DEV_INFO(fmt, args...) pr_info("<SDEROT_INFO> " fmt, ##args) +#define DEV_WARN(fmt, args...) pr_warn("<SDEROT_WARN> " fmt, ##args) +#define DEV_ERR(fmt, args...) pr_err("<SDEROT_ERR> " fmt, ##args) + +struct sde_io_data { + u32 len; + void __iomem *base; +}; + +void sde_reg_w(struct sde_io_data *io, u32 offset, u32 value, u32 debug); +u32 sde_reg_r(struct sde_io_data *io, u32 offset, u32 debug); +void sde_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug); + +#define SDE_REG_W_ND(io, offset, val) sde_reg_w(io, offset, val, false) +#define SDE_REG_W(io, offset, val) sde_reg_w(io, offset, val, true) +#define SDE_REG_R_ND(io, offset) sde_reg_r(io, offset, false) +#define SDE_REG_R(io, offset) sde_reg_r(io, offset, true) + +enum sde_vreg_type { + SDE_REG_LDO, + SDE_REG_VS, +}; + +struct sde_vreg { + struct regulator *vreg; /* vreg handle */ + char vreg_name[32]; + int min_voltage; + int max_voltage; + int enable_load; + int disable_load; + int pre_on_sleep; + int post_on_sleep; + int pre_off_sleep; + int post_off_sleep; +}; + +struct sde_gpio { + unsigned int gpio; + unsigned int value; + char gpio_name[32]; +}; + +enum sde_clk_type { + SDE_CLK_AHB, /* no set rate. rate controlled through rpm */ + SDE_CLK_PCLK, + SDE_CLK_OTHER, +}; + +struct sde_clk { + struct clk *clk; /* clk handle */ + char clk_name[32]; + enum sde_clk_type type; + unsigned long rate; +}; + +struct sde_module_power { + unsigned int num_vreg; + struct sde_vreg *vreg_config; + unsigned int num_gpio; + struct sde_gpio *gpio_config; + unsigned int num_clk; + struct sde_clk *clk_config; +}; + +int sde_rot_ioremap_byname(struct platform_device *pdev, + struct sde_io_data *io_data, const char *name); +void sde_rot_iounmap(struct sde_io_data *io_data); + +int sde_rot_config_vreg(struct device *dev, struct sde_vreg *in_vreg, + int num_vreg, int config); +int sde_rot_enable_vreg(struct sde_vreg *in_vreg, int num_vreg, int enable); + +int sde_rot_get_clk(struct device *dev, struct sde_clk *clk_arry, int num_clk); +void sde_rot_put_clk(struct sde_clk *clk_arry, int num_clk); +int sde_rot_clk_set_rate(struct sde_clk *clk_arry, int num_clk); +int sde_rot_enable_clk(struct sde_clk *clk_arry, int num_clk, int enable); + +#endif /* __SDE_ROTATOR_IO_UTIL_H__ */ diff --git a/techpack/display/rotator/sde_rotator_r1.c b/techpack/display/rotator/sde_rotator_r1.c new file mode 100644 index 0000000000000000000000000000000000000000..c7234e505e081e9e741609c560963eec43c45425 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1.c @@ -0,0 +1,745 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/interrupt.h> + +#include "sde_rotator_r1_hwio.h" +#include "sde_rotator_core.h" +#include "sde_rotator_util.h" +#include "sde_rotator_r1_internal.h" +#include "sde_rotator_r1.h" +#include "sde_rotator_r1_debug.h" + +struct sde_mdp_hw_resource { + struct sde_rot_hw_resource hw; + struct sde_mdp_ctl *ctl; + struct sde_mdp_mixer *mixer; + struct sde_mdp_pipe *pipe; + struct sde_mdp_writeback *wb; +}; + +struct sde_rotator_r1_data { + struct sde_rot_mgr *mgr; + int wb_id; + int ctl_id; + int irq_num; + struct sde_mdp_hw_resource *mdp_hw; +}; + +static u32 sde_hw_rotator_input_pixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + SDE_PIX_FMT_Y_CB_CR_H2V2, + SDE_PIX_FMT_Y_CR_CB_H2V2, + SDE_PIX_FMT_Y_CR_CB_GH2V2, + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + SDE_PIX_FMT_YCBYCR_H2V1, + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + SDE_PIX_FMT_RGBA_8888_UBWC, + SDE_PIX_FMT_RGBX_8888_UBWC, + SDE_PIX_FMT_RGB_565_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, +}; + +static u32 sde_hw_rotator_output_pixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + SDE_PIX_FMT_Y_CB_CR_H2V2, + SDE_PIX_FMT_Y_CR_CB_H2V2, + SDE_PIX_FMT_Y_CR_CB_GH2V2, + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + SDE_PIX_FMT_YCBYCR_H2V1, + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + SDE_PIX_FMT_RGBA_8888_UBWC, + SDE_PIX_FMT_RGBX_8888_UBWC, + SDE_PIX_FMT_RGB_565_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, +}; + +static struct sde_mdp_hw_resource *sde_rotator_hw_alloc( + struct sde_rot_mgr *mgr, u32 ctl_id, u32 wb_id, int irq_num) +{ + struct sde_mdp_hw_resource *mdp_hw; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int pipe_ndx, offset = ctl_id; + int ret = 0; + + mdp_hw = devm_kzalloc(&mgr->pdev->dev, + sizeof(struct sde_mdp_hw_resource), GFP_KERNEL); + if (!mdp_hw) + return ERR_PTR(-ENOMEM); + + mdp_hw->ctl = sde_mdp_ctl_alloc(mdata, offset); + if (IS_ERR_OR_NULL(mdp_hw->ctl)) { + SDEROT_ERR("unable to allocate ctl\n"); + ret = -ENODEV; + goto error; + } + mdp_hw->ctl->irq_num = irq_num; + + mdp_hw->wb = sde_mdp_wb_assign(wb_id, mdp_hw->ctl->num); + if (IS_ERR_OR_NULL(mdp_hw->wb)) { + SDEROT_ERR("unable to allocate wb\n"); + ret = -ENODEV; + goto error; + } + + mdp_hw->ctl->wb = mdp_hw->wb; + mdp_hw->mixer = sde_mdp_mixer_assign(mdp_hw->wb->num, true); + if (IS_ERR_OR_NULL(mdp_hw->mixer)) { + SDEROT_ERR("unable to allocate wb mixer\n"); + ret = -ENODEV; + goto error; + } + + mdp_hw->ctl->mixer_left = mdp_hw->mixer; + mdp_hw->mixer->ctl = mdp_hw->ctl; + + mdp_hw->mixer->rotator_mode = true; + + switch (mdp_hw->mixer->num) { + case SDE_MDP_WB_LAYERMIXER0: + mdp_hw->ctl->opmode = SDE_MDP_CTL_OP_ROT0_MODE; + break; + case SDE_MDP_WB_LAYERMIXER1: + mdp_hw->ctl->opmode = SDE_MDP_CTL_OP_ROT1_MODE; + break; + default: + SDEROT_ERR("invalid layer mixer=%d\n", mdp_hw->mixer->num); + ret = -EINVAL; + goto error; + } + + mdp_hw->ctl->ops.start_fnc = sde_mdp_writeback_start; + mdp_hw->ctl->wb_type = SDE_MDP_WB_CTL_TYPE_BLOCK; + + if (mdp_hw->ctl->ops.start_fnc) + ret = mdp_hw->ctl->ops.start_fnc(mdp_hw->ctl); + + if (ret) + goto error; + + /* override from dt */ + pipe_ndx = wb_id; + mdp_hw->pipe = sde_mdp_pipe_assign(mdata, mdp_hw->mixer, pipe_ndx); + if (IS_ERR_OR_NULL(mdp_hw->pipe)) { + SDEROT_ERR("dma pipe allocation failed\n"); + ret = -ENODEV; + goto error; + } + + mdp_hw->pipe->mixer_left = mdp_hw->mixer; + mdp_hw->hw.wb_id = mdp_hw->wb->num; + mdp_hw->hw.pending_count = 0; + atomic_set(&mdp_hw->hw.num_active, 0); + mdp_hw->hw.max_active = 1; + init_waitqueue_head(&mdp_hw->hw.wait_queue); + + return mdp_hw; +error: + if (!IS_ERR_OR_NULL(mdp_hw->pipe)) + sde_mdp_pipe_destroy(mdp_hw->pipe); + if (!IS_ERR_OR_NULL(mdp_hw->ctl)) { + if (mdp_hw->ctl->ops.stop_fnc) + mdp_hw->ctl->ops.stop_fnc(mdp_hw->ctl, 0); + sde_mdp_ctl_free(mdp_hw->ctl); + } + devm_kfree(&mgr->pdev->dev, mdp_hw); + + return ERR_PTR(ret); +} + +static void sde_rotator_hw_free(struct sde_rot_mgr *mgr, + struct sde_mdp_hw_resource *mdp_hw) +{ + struct sde_mdp_mixer *mixer; + struct sde_mdp_ctl *ctl; + + if (!mgr || !mdp_hw) + return; + + mixer = mdp_hw->pipe->mixer_left; + + sde_mdp_pipe_destroy(mdp_hw->pipe); + + ctl = sde_mdp_ctl_mixer_switch(mixer->ctl, + SDE_MDP_WB_CTL_TYPE_BLOCK); + if (ctl) { + if (ctl->ops.stop_fnc) + ctl->ops.stop_fnc(ctl, 0); + sde_mdp_ctl_free(ctl); + } + + devm_kfree(&mgr->pdev->dev, mdp_hw); +} + +static struct sde_rot_hw_resource *sde_rotator_hw_alloc_ext( + struct sde_rot_mgr *mgr, u32 pipe_id, u32 wb_id) +{ + struct sde_mdp_hw_resource *mdp_hw; + struct sde_rotator_r1_data *hw_data; + + if (!mgr || !mgr->hw_data) + return NULL; + + hw_data = mgr->hw_data; + mdp_hw = hw_data->mdp_hw; + + return &mdp_hw->hw; +} + +static void sde_rotator_hw_free_ext(struct sde_rot_mgr *mgr, + struct sde_rot_hw_resource *hw) +{ + /* currently nothing specific for this device */ +} + +static void sde_rotator_translate_rect(struct sde_rect *dst, + struct sde_rect *src) +{ + dst->x = src->x; + dst->y = src->y; + dst->w = src->w; + dst->h = src->h; +} + +static u32 sde_rotator_translate_flags(u32 input) +{ + u32 output = 0; + + if (input & SDE_ROTATION_NOP) + output |= SDE_ROT_NOP; + if (input & SDE_ROTATION_FLIP_LR) + output |= SDE_FLIP_LR; + if (input & SDE_ROTATION_FLIP_UD) + output |= SDE_FLIP_UD; + if (input & SDE_ROTATION_90) + output |= SDE_ROT_90; + if (input & SDE_ROTATION_DEINTERLACE) + output |= SDE_DEINTERLACE; + if (input & SDE_ROTATION_SECURE) + output |= SDE_SECURE_OVERLAY_SESSION; + return output; +} + +static int sde_rotator_config_hw(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_mdp_hw_resource *mdp_hw; + struct sde_mdp_pipe *pipe; + struct sde_rotation_item *item; + int ret; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry"); + return -EINVAL; + } + + mdp_hw = container_of(hw, struct sde_mdp_hw_resource, hw); + + pipe = mdp_hw->pipe; + item = &entry->item; + + pipe->flags = sde_rotator_translate_flags(item->flags); + pipe->src_fmt = sde_get_format_params(item->input.format); + pipe->img_width = item->input.width; + pipe->img_height = item->input.height; + sde_rotator_translate_rect(&pipe->src, &item->src_rect); + sde_rotator_translate_rect(&pipe->dst, &item->src_rect); + + pipe->params_changed++; + + ret = sde_mdp_pipe_queue_data(pipe, &entry->src_buf); + SDEROT_DBG("Config pipe. src{%u,%u,%u,%u}f=%u\n" + "dst{%u,%u,%u,%u}f=%u session_id=%u\n", + item->src_rect.x, item->src_rect.y, + item->src_rect.w, item->src_rect.h, item->input.format, + item->dst_rect.x, item->dst_rect.y, + item->dst_rect.w, item->dst_rect.h, item->output.format, + item->session_id); + + return ret; +} + +static int sde_rotator_cancel_hw(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + return 0; +} + +static int sde_rotator_abort_hw(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + return 0; +} + +static int sde_rotator_kickoff_entry(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_mdp_hw_resource *mdp_hw; + int ret; + struct sde_mdp_writeback_arg wb_args; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry"); + return -EINVAL; + } + + wb_args.data = &entry->dst_buf; + wb_args.priv_data = entry; + + mdp_hw = container_of(hw, struct sde_mdp_hw_resource, hw); + + ret = sde_mdp_writeback_display_commit(mdp_hw->ctl, &wb_args); + return ret; +} + +static int sde_rotator_wait_for_entry(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_mdp_hw_resource *mdp_hw; + int ret; + struct sde_mdp_ctl *ctl; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry"); + return -EINVAL; + } + + mdp_hw = container_of(hw, struct sde_mdp_hw_resource, hw); + + ctl = mdp_hw->ctl; + + ret = sde_mdp_display_wait4comp(ctl); + + return ret; +} + +static int sde_rotator_hw_validate_entry(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry) +{ + int ret = 0; + u16 src_w, src_h, dst_w, dst_h, bit; + struct sde_rotation_item *item = &entry->item; + struct sde_mdp_format_params *fmt; + + src_w = item->src_rect.w; + src_h = item->src_rect.h; + + if (item->flags & SDE_ROTATION_90) { + dst_w = item->dst_rect.h; + dst_h = item->dst_rect.w; + } else { + dst_w = item->dst_rect.w; + dst_h = item->dst_rect.h; + } + + entry->dnsc_factor_w = 0; + entry->dnsc_factor_h = 0; + + if ((src_w != dst_w) || (src_h != dst_h)) { + if ((src_w % dst_w) || (src_h % dst_h)) { + SDEROT_DBG("non integral scale not support\n"); + ret = -EINVAL; + goto dnsc_err; + } + entry->dnsc_factor_w = src_w / dst_w; + bit = fls(entry->dnsc_factor_w); + if ((entry->dnsc_factor_w & ~BIT(bit - 1)) || (bit > 5)) { + SDEROT_DBG("non power-of-2 scale not support\n"); + ret = -EINVAL; + goto dnsc_err; + } + entry->dnsc_factor_h = src_h / dst_h; + bit = fls(entry->dnsc_factor_h); + if ((entry->dnsc_factor_h & ~BIT(bit - 1)) || (bit > 5)) { + SDEROT_DBG("non power-of-2 dscale not support\n"); + ret = -EINVAL; + goto dnsc_err; + } + } + + fmt = sde_get_format_params(item->output.format); + if (sde_mdp_is_ubwc_format(fmt) && + (entry->dnsc_factor_h || entry->dnsc_factor_w)) { + SDEROT_DBG("downscale with ubwc not support\n"); + ret = -EINVAL; + } + +dnsc_err: + + /* Downscaler does not support asymmetrical dnsc */ + if (entry->dnsc_factor_w != entry->dnsc_factor_h) { + SDEROT_DBG("asymmetric downscale not support\n"); + ret = -EINVAL; + } + + if (ret) { + entry->dnsc_factor_w = 0; + entry->dnsc_factor_h = 0; + } + return ret; +} + +static ssize_t sde_rotator_hw_show_caps(struct sde_rot_mgr *mgr, + struct device_attribute *attr, char *buf, ssize_t len) +{ + struct sde_rotator_r1_data *hw_data; + int cnt = 0; + + if (!mgr || !buf) + return 0; + + hw_data = mgr->hw_data; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + SPRINT("wb_id=%d\n", hw_data->wb_id); + SPRINT("ctl_id=%d\n", hw_data->ctl_id); + return cnt; +} + +static ssize_t sde_rotator_hw_show_state(struct sde_rot_mgr *mgr, + struct device_attribute *attr, char *buf, ssize_t len) +{ + struct sde_rotator_r1_data *hw_data; + int cnt = 0; + + if (!mgr || !buf) + return 0; + + hw_data = mgr->hw_data; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + if (hw_data && hw_data->mdp_hw) { + struct sde_rot_hw_resource *hw = &hw_data->mdp_hw->hw; + + SPRINT("irq_num=%d\n", hw_data->irq_num); + SPRINT("max_active=%d\n", hw->max_active); + SPRINT("num_active=%d\n", atomic_read(&hw->num_active)); + SPRINT("pending_cnt=%u\n", hw->pending_count); + } + + return cnt; +} + +/* + * sde_hw_rotator_get_pixfmt - get the indexed pixel format + * @mgr: Pointer to rotator manager + * @index: index of pixel format + * @input: true for input port; false for output port + * @mode: operating mode + */ +static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr, + int index, bool input, u32 mode) +{ + if (input) { + if (index < ARRAY_SIZE(sde_hw_rotator_input_pixfmts)) + return sde_hw_rotator_input_pixfmts[index]; + else + return 0; + } else { + if (index < ARRAY_SIZE(sde_hw_rotator_output_pixfmts)) + return sde_hw_rotator_output_pixfmts[index]; + else + return 0; + } +} + +/* + * sde_hw_rotator_is_valid_pixfmt - verify if the given pixel format is valid + * @mgr: Pointer to rotator manager + * @pixfmt: pixel format to be verified + * @input: true for input port; false for output port + * @mode: operating mode + */ +static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt, + bool input, u32 mode) +{ + int i; + + if (input) { + for (i = 0; i < ARRAY_SIZE(sde_hw_rotator_input_pixfmts); i++) + if (sde_hw_rotator_input_pixfmts[i] == pixfmt) + return true; + } else { + for (i = 0; i < ARRAY_SIZE(sde_hw_rotator_output_pixfmts); i++) + if (sde_hw_rotator_output_pixfmts[i] == pixfmt) + return true; + } + + return false; +} + +static int sde_rotator_hw_parse_dt(struct sde_rotator_r1_data *hw_data, + struct platform_device *dev) +{ + int ret = 0; + u32 data; + + if (!hw_data || !dev) + return -EINVAL; + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,mdss-wb-id", &data); + if (ret) + hw_data->wb_id = -1; + else + hw_data->wb_id = (int) data; + ret = of_property_read_u32(dev->dev.of_node, + "qcom,mdss-ctl-id", &data); + if (ret) + hw_data->ctl_id = -1; + else + hw_data->ctl_id = (int) data; + + return ret; +} + +static int sde_rotator_hw_rev_init(struct sde_rot_data_type *mdata) +{ + if (!mdata) { + SDEROT_ERR("null rotator data\n"); + return -EINVAL; + } + + clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map); + set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map); + clear_bit(SDE_QOS_CDP, mdata->sde_qos_map); + set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map); + set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map); + clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map); + set_bit(SDE_CAPS_R1_WB, mdata->sde_caps_map); + + return 0; +} + +enum { + SDE_ROTATOR_INTR_WB_0, + SDE_ROTATOR_INTR_WB_1, + SDE_ROTATOR_INTR_MAX, +}; + +struct intr_callback { + void (*func)(void *data); + void *arg; +}; + +struct intr_callback sde_intr_cb[SDE_ROTATOR_INTR_MAX]; + +int sde_mdp_set_intr_callback(u32 intr_type, u32 intf_num, + void (*fnc_ptr)(void *), void *arg) +{ + if (intf_num >= SDE_ROTATOR_INTR_MAX) { + SDEROT_WARN("invalid intr type=%u intf_num=%u\n", + intr_type, intf_num); + return -EINVAL; + } + + sde_intr_cb[intf_num].func = fnc_ptr; + sde_intr_cb[intf_num].arg = arg; + + return 0; +} + +static irqreturn_t sde_irq_handler(int irq, void *ptr) +{ + struct sde_rot_data_type *mdata = ptr; + irqreturn_t ret = IRQ_NONE; + u32 isr; + + isr = readl_relaxed(mdata->mdp_base + SDE_MDP_REG_INTR_STATUS); + + SDEROT_DBG("intr_status = %8.8x\n", isr); + + if (isr & SDE_MDP_INTR_WB_0_DONE) { + struct intr_callback *cb = &sde_intr_cb[SDE_ROTATOR_INTR_WB_0]; + + if (cb->func) { + writel_relaxed(SDE_MDP_INTR_WB_0_DONE, + mdata->mdp_base + SDE_MDP_REG_INTR_CLEAR); + cb->func(cb->arg); + ret = IRQ_HANDLED; + } + } + + if (isr & SDE_MDP_INTR_WB_1_DONE) { + struct intr_callback *cb = &sde_intr_cb[SDE_ROTATOR_INTR_WB_1]; + + if (cb->func) { + writel_relaxed(SDE_MDP_INTR_WB_1_DONE, + mdata->mdp_base + SDE_MDP_REG_INTR_CLEAR); + cb->func(cb->arg); + ret = IRQ_HANDLED; + } + } + + return ret; +} + +static void sde_rotator_hw_destroy(struct sde_rot_mgr *mgr) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_rotator_r1_data *hw_data; + + if (!mgr || !mgr->pdev || !mgr->hw_data) + return; + + hw_data = mgr->hw_data; + if (hw_data->irq_num >= 0) + devm_free_irq(&mgr->pdev->dev, hw_data->irq_num, mdata); + sde_rotator_hw_free(mgr, hw_data->mdp_hw); + devm_kfree(&mgr->pdev->dev, mgr->hw_data); + mgr->hw_data = NULL; +} + +int sde_rotator_r1_init(struct sde_rot_mgr *mgr) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_rotator_r1_data *hw_data; + int ret; + + if (!mgr || !mgr->pdev) { + SDEROT_ERR("null rotator manager/platform device"); + return -EINVAL; + } + + hw_data = devm_kzalloc(&mgr->pdev->dev, + sizeof(struct sde_rotator_r1_data), GFP_KERNEL); + if (hw_data == NULL) + return -ENOMEM; + + mgr->hw_data = hw_data; + mgr->ops_config_hw = sde_rotator_config_hw; + mgr->ops_cancel_hw = sde_rotator_cancel_hw; + mgr->ops_abort_hw = sde_rotator_abort_hw; + mgr->ops_kickoff_entry = sde_rotator_kickoff_entry; + mgr->ops_wait_for_entry = sde_rotator_wait_for_entry; + mgr->ops_hw_alloc = sde_rotator_hw_alloc_ext; + mgr->ops_hw_free = sde_rotator_hw_free_ext; + mgr->ops_hw_destroy = sde_rotator_hw_destroy; + mgr->ops_hw_validate_entry = sde_rotator_hw_validate_entry; + mgr->ops_hw_show_caps = sde_rotator_hw_show_caps; + mgr->ops_hw_show_state = sde_rotator_hw_show_state; + mgr->ops_hw_create_debugfs = sde_rotator_r1_create_debugfs; + mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt; + mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt; + + ret = sde_rotator_hw_parse_dt(mgr->hw_data, mgr->pdev); + if (ret) + goto error_parse_dt; + + hw_data->irq_num = platform_get_irq(mgr->pdev, 0); + if (hw_data->irq_num < 0) { + SDEROT_ERR("fail to get rotator irq\n"); + } else { + ret = devm_request_threaded_irq(&mgr->pdev->dev, + hw_data->irq_num, + sde_irq_handler, NULL, + 0, "sde_rotator_r1", mdata); + if (ret) { + SDEROT_ERR("fail to request irq r:%d\n", ret); + hw_data->irq_num = -1; + } else { + disable_irq(hw_data->irq_num); + } + } + + hw_data->mdp_hw = sde_rotator_hw_alloc(mgr, hw_data->ctl_id, + hw_data->wb_id, hw_data->irq_num); + if (IS_ERR_OR_NULL(hw_data->mdp_hw)) + goto error_hw_alloc; + + ret = sde_rotator_hw_rev_init(sde_rot_get_mdata()); + if (ret) + goto error_hw_rev_init; + + hw_data->mgr = mgr; + + return 0; +error_hw_rev_init: + if (hw_data->irq_num >= 0) + devm_free_irq(&mgr->pdev->dev, hw_data->irq_num, mdata); + sde_rotator_hw_free(mgr, hw_data->mdp_hw); +error_hw_alloc: + devm_kfree(&mgr->pdev->dev, mgr->hw_data); +error_parse_dt: + return ret; +} diff --git a/techpack/display/rotator/sde_rotator_r1.h b/techpack/display/rotator/sde_rotator_r1.h new file mode 100644 index 0000000000000000000000000000000000000000..a56b389fc9fe614722c0d75de0135105d070ea4b --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_R1_H__ +#define __SDE_ROTATOR_R1_H__ + +#include <linux/types.h> + +#include "sde_rotator_core.h" + +int sde_rotator_r1_init(struct sde_rot_mgr *mgr); + +#endif /* __SDE_ROTATOR_R1_H__ */ diff --git a/techpack/display/rotator/sde_rotator_r1_ctl.c b/techpack/display/rotator/sde_rotator_r1_ctl.c new file mode 100644 index 0000000000000000000000000000000000000000..fdc44f5bb95676afc13fd6fcbf8562532488fe35 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_ctl.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/errno.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/sort.h> +#include <linux/clk.h> +#include <linux/bitmap.h> + +#include "sde_rotator_r1_hwio.h" +#include "sde_rotator_util.h" +#include "sde_rotator_r1_internal.h" +#include "sde_rotator_core.h" + +struct sde_mdp_ctl *sde_mdp_ctl_alloc(struct sde_rot_data_type *mdata, + u32 off) +{ + struct sde_mdp_ctl *ctl = NULL; + static struct sde_mdp_ctl sde_ctl[5]; + static const u32 offset[] = {0x00002000, 0x00002200, 0x00002400, + 0x00002600, 0x00002800}; + + if (off >= ARRAY_SIZE(offset)) { + SDEROT_ERR("invalid parameters\n"); + return ERR_PTR(-EINVAL); + } + + ctl = &sde_ctl[off]; + ctl->mdata = mdata; + ctl->num = off; + ctl->offset = offset[ctl->num]; + ctl->base = mdata->sde_io.base + ctl->offset; + return ctl; +} + +int sde_mdp_ctl_free(struct sde_mdp_ctl *ctl) +{ + if (!ctl) + return -ENODEV; + + if (ctl->wb) + sde_mdp_wb_free(ctl->wb); + + ctl->is_secure = false; + ctl->mixer_left = NULL; + ctl->mixer_right = NULL; + ctl->wb = NULL; + memset(&ctl->ops, 0, sizeof(ctl->ops)); + + return 0; +} + +struct sde_mdp_mixer *sde_mdp_mixer_assign(u32 id, bool wb) +{ + struct sde_mdp_mixer *mixer = NULL; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + static struct sde_mdp_mixer sde_mixer[16]; + static const u32 offset[] = {0x00048000, 0x00049000}; + + if (id >= ARRAY_SIZE(offset)) { + SDEROT_ERR("invalid parameters\n"); + return ERR_PTR(-EINVAL); + } + + mixer = &sde_mixer[id]; + mixer->num = id; + mixer->offset = offset[mixer->num]; + mixer->base = mdata->sde_io.base + mixer->offset; + return mixer; +} + +static void sde_mdp_mixer_setup(struct sde_mdp_ctl *master_ctl, + int mixer_mux) +{ + int i; + struct sde_mdp_ctl *ctl = NULL; + struct sde_mdp_mixer *mixer = sde_mdp_mixer_get(master_ctl, + mixer_mux); + + if (!mixer) + return; + + ctl = mixer->ctl; + if (!ctl) + return; + + /* check if mixer setup for rotator is needed */ + if (mixer->rotator_mode) { + int nmixers = 5; + + for (i = 0; i < nmixers; i++) + sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_LAYER(i), 0); + return; + } +} + +struct sde_mdp_mixer *sde_mdp_mixer_get(struct sde_mdp_ctl *ctl, int mux) +{ + struct sde_mdp_mixer *mixer = NULL; + + if (!ctl) { + SDEROT_ERR("ctl not initialized\n"); + return NULL; + } + + switch (mux) { + case SDE_MDP_MIXER_MUX_DEFAULT: + case SDE_MDP_MIXER_MUX_LEFT: + mixer = ctl->mixer_left; + break; + case SDE_MDP_MIXER_MUX_RIGHT: + mixer = ctl->mixer_right; + break; + } + + return mixer; +} + +int sde_mdp_get_pipe_flush_bits(struct sde_mdp_pipe *pipe) +{ + u32 flush_bits = 0; + + if (pipe->type == SDE_MDP_PIPE_TYPE_DMA) + flush_bits |= BIT(pipe->num) << 5; + else if (pipe->num == SDE_MDP_SSPP_VIG3 || + pipe->num == SDE_MDP_SSPP_RGB3) + flush_bits |= BIT(pipe->num) << 10; + else if (pipe->type == SDE_MDP_PIPE_TYPE_CURSOR) + flush_bits |= BIT(22 + pipe->num - SDE_MDP_SSPP_CURSOR0); + else /* RGB/VIG 0-2 pipes */ + flush_bits |= BIT(pipe->num); + + return flush_bits; +} + +int sde_mdp_mixer_pipe_update(struct sde_mdp_pipe *pipe, + struct sde_mdp_mixer *mixer, int params_changed) +{ + struct sde_mdp_ctl *ctl; + + if (!pipe) + return -EINVAL; + if (!mixer) + return -EINVAL; + ctl = mixer->ctl; + if (!ctl) + return -EINVAL; + + ctl->flush_bits |= sde_mdp_get_pipe_flush_bits(pipe); + return 0; +} + +int sde_mdp_display_wait4comp(struct sde_mdp_ctl *ctl) +{ + int ret = 0; + + if (!ctl) { + SDEROT_ERR("invalid ctl\n"); + return -ENODEV; + } + + if (ctl->ops.wait_fnc) + ret = ctl->ops.wait_fnc(ctl, NULL); + + return ret; +} + +int sde_mdp_display_commit(struct sde_mdp_ctl *ctl, void *arg, + struct sde_mdp_commit_cb *commit_cb) +{ + int ret = 0; + u32 ctl_flush_bits = 0; + + if (!ctl) { + SDEROT_ERR("display function not set\n"); + return -ENODEV; + } + + if (ctl->ops.prepare_fnc) + ret = ctl->ops.prepare_fnc(ctl, arg); + + if (ret) { + SDEROT_ERR("error preparing display\n"); + goto done; + } + + sde_mdp_mixer_setup(ctl, SDE_MDP_MIXER_MUX_LEFT); + sde_mdp_mixer_setup(ctl, SDE_MDP_MIXER_MUX_RIGHT); + + sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_TOP, ctl->opmode); + ctl->flush_bits |= BIT(17); /* CTL */ + + ctl_flush_bits = ctl->flush_bits; + + sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_FLUSH, ctl_flush_bits); + /* ensure the flush command is issued after the barrier */ + wmb(); + ctl->flush_reg_data = ctl_flush_bits; + ctl->flush_bits = 0; + if (ctl->ops.display_fnc) + ret = ctl->ops.display_fnc(ctl, arg); /* DSI0 kickoff */ + if (ret) + SDEROT_WARN("ctl %d error displaying frame\n", ctl->num); + +done: + return ret; +} + +/** + * @sde_mdp_ctl_mixer_switch() - return ctl mixer of @return_type + * @ctl: Pointer to ctl structure to be switched. + * @return_type: wb_type of the ctl to be switched to. + * + * Virtual mixer switch should be performed only when there is no + * dedicated wfd block and writeback block is shared. + */ +struct sde_mdp_ctl *sde_mdp_ctl_mixer_switch(struct sde_mdp_ctl *ctl, + u32 return_type) +{ + if (ctl->wb_type == return_type) + return ctl; + + SDEROT_ERR("unable to switch mixer to type=%d\n", return_type); + return NULL; +} + +struct sde_mdp_writeback *sde_mdp_wb_assign(u32 num, u32 reg_index) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_mdp_writeback *wb = NULL; + static struct sde_mdp_writeback sde_wb[16]; + static const u32 offset[] = {0x00065000, 0x00065800, 0x00066000}; + + if (num >= ARRAY_SIZE(offset)) { + SDEROT_ERR("invalid parameters\n"); + return ERR_PTR(-EINVAL); + } + + wb = &sde_wb[num]; + wb->num = num; + wb->offset = offset[wb->num]; + if (!wb) + return NULL; + + wb->base = mdata->sde_io.base; + wb->base += wb->offset; + return wb; +} + +void sde_mdp_wb_free(struct sde_mdp_writeback *wb) +{ +} diff --git a/techpack/display/rotator/sde_rotator_r1_debug.c b/techpack/display/rotator/sde_rotator_r1_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..06bc11c3cdd596c86a40f0c5ebf8023cbb34ea86 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_debug.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> + +#include "sde_rotator_r1_debug.h" +#include "sde_rotator_core.h" +#include "sde_rotator_r1.h" +#include "sde_rotator_r1_internal.h" + +/* + * sde_rotator_r1_create_debugfs - Setup rotator r1 debugfs directory structure. + * @rot_dev: Pointer to rotator device + */ +int sde_rotator_r1_create_debugfs(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + struct sde_rotator_r1_data *hw_data; + + if (!mgr || !debugfs_root || !mgr->hw_data) + return -EINVAL; + + hw_data = mgr->hw_data; + + /* add debugfs */ + + return 0; +} diff --git a/techpack/display/rotator/sde_rotator_r1_debug.h b/techpack/display/rotator/sde_rotator_r1_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..0d75e2f94c1448d1ab2a36cb6f75107a0086078e --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_debug.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_R3_DEBUG_H__ +#define __SDE_ROTATOR_R3_DEBUG_H__ + +#include <linux/types.h> +#include <linux/dcache.h> + +struct sde_rot_mgr; + +#if defined(CONFIG_DEBUG_FS) +int sde_rotator_r1_create_debugfs(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root); +#else +static inline +int sde_rotator_r1_create_debugfs(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + return 0; +} +#endif +#endif /* __SDE_ROTATOR_R3_DEBUG_H__ */ diff --git a/techpack/display/rotator/sde_rotator_r1_hwio.h b/techpack/display/rotator/sde_rotator_r1_hwio.h new file mode 100644 index 0000000000000000000000000000000000000000..14b3507eeeba04eee8099fbb5ea03e2c448b77e6 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_hwio.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_ROTATOR_R1_HWIO_H +#define SDE_ROTATOR_R1_HWIO_H + +#include <linux/bitops.h> + +#define SDE_MDP_FETCH_CONFIG_RESET_VALUE 0x00000087 + +#define SDE_MDP_REG_HW_VERSION 0x0 +#define SDE_MDP_REG_INTR_EN 0x00010 +#define SDE_MDP_REG_INTR_STATUS 0x00014 +#define SDE_MDP_REG_INTR_CLEAR 0x00018 + +#define SDE_MDP_INTR_WB_0_DONE BIT(0) +#define SDE_MDP_INTR_WB_1_DONE BIT(1) + +enum mdss_mdp_intr_type { + SDE_MDP_IRQ_WB_ROT_COMP = 0, + SDE_MDP_IRQ_WB_WFD = 4, + SDE_MDP_IRQ_PING_PONG_COMP = 8, + SDE_MDP_IRQ_PING_PONG_RD_PTR = 12, + SDE_MDP_IRQ_PING_PONG_WR_PTR = 16, + SDE_MDP_IRQ_PING_PONG_AUTO_REF = 20, + SDE_MDP_IRQ_INTF_UNDER_RUN = 24, + SDE_MDP_IRQ_INTF_VSYNC = 25, +}; + +enum mdss_mdp_ctl_index { + SDE_MDP_CTL0, + SDE_MDP_CTL1, + SDE_MDP_CTL2, + SDE_MDP_CTL3, + SDE_MDP_CTL4, + SDE_MDP_CTL5, + SDE_MDP_MAX_CTL +}; + +#define SDE_MDP_REG_CTL_LAYER(lm) \ + ((lm == 5) ? (0x024) : ((lm) * 0x004)) +#define SDE_MDP_REG_CTL_TOP 0x014 +#define SDE_MDP_REG_CTL_FLUSH 0x018 +#define SDE_MDP_REG_CTL_START 0x01C + +#define SDE_MDP_CTL_OP_ROT0_MODE 0x1 +#define SDE_MDP_CTL_OP_ROT1_MODE 0x2 + +enum sde_mdp_sspp_index { + SDE_MDP_SSPP_VIG0, + SDE_MDP_SSPP_VIG1, + SDE_MDP_SSPP_VIG2, + SDE_MDP_SSPP_RGB0, + SDE_MDP_SSPP_RGB1, + SDE_MDP_SSPP_RGB2, + SDE_MDP_SSPP_DMA0, + SDE_MDP_SSPP_DMA1, + SDE_MDP_SSPP_VIG3, + SDE_MDP_SSPP_RGB3, + SDE_MDP_SSPP_CURSOR0, + SDE_MDP_SSPP_CURSOR1, + SDE_MDP_MAX_SSPP +}; + +#define SDE_MDP_REG_SSPP_SRC_SIZE 0x000 +#define SDE_MDP_REG_SSPP_SRC_IMG_SIZE 0x004 +#define SDE_MDP_REG_SSPP_SRC_XY 0x008 +#define SDE_MDP_REG_SSPP_OUT_SIZE 0x00C +#define SDE_MDP_REG_SSPP_OUT_XY 0x010 +#define SDE_MDP_REG_SSPP_SRC0_ADDR 0x014 +#define SDE_MDP_REG_SSPP_SRC1_ADDR 0x018 +#define SDE_MDP_REG_SSPP_SRC2_ADDR 0x01C +#define SDE_MDP_REG_SSPP_SRC3_ADDR 0x020 +#define SDE_MDP_REG_SSPP_SRC_YSTRIDE0 0x024 +#define SDE_MDP_REG_SSPP_SRC_YSTRIDE1 0x028 +#define SDE_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C +#define SDE_MDP_REG_SSPP_SRC_FORMAT 0x030 +#define SDE_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034 +#define SDE_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C +#define SDE_MDP_REG_SSPP_REQPRIO_FIFO_WM_0 0x050 +#define SDE_MDP_REG_SSPP_REQPRIO_FIFO_WM_1 0x054 +#define SDE_MDP_REG_SSPP_REQPRIO_FIFO_WM_2 0x058 +#define SDE_MDP_REG_SSPP_DANGER_LUT 0x060 +#define SDE_MDP_REG_SSPP_SAFE_LUT 0x064 +#define SDE_MDP_REG_SSPP_CREQ_LUT 0x068 +#define SDE_MDP_REG_SSPP_QOS_CTRL 0x06C +#define SDE_MDP_REG_SSPP_CDP_CTRL 0x134 +#define SDE_MDP_REG_SSPP_UBWC_ERROR_STATUS 0x138 + +#define SDE_MDP_REG_SSPP_SRC_OP_MODE 0x038 +#define SDE_MDP_OP_FLIP_UD BIT(14) +#define SDE_MDP_OP_FLIP_LR BIT(13) +#define SDE_MDP_OP_BWC_EN BIT(0) +#define SDE_MDP_OP_BWC_LOSSLESS (0 << 1) +#define SDE_MDP_OP_BWC_Q_HIGH (1 << 1) +#define SDE_MDP_OP_BWC_Q_MED (2 << 1) + +#define SDE_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C +#define SDE_MDP_REG_SSPP_FETCH_CONFIG 0x048 +#define SDE_MDP_REG_SSPP_VC1_RANGE 0x04C +#define SDE_MDP_REG_SSPP_SRC_ADDR_SW_STATUS 0x070 +#define SDE_MDP_REG_SSPP_CURRENT_SRC0_ADDR 0x0A4 +#define SDE_MDP_REG_SSPP_CURRENT_SRC1_ADDR 0x0A8 +#define SDE_MDP_REG_SSPP_CURRENT_SRC2_ADDR 0x0AC +#define SDE_MDP_REG_SSPP_CURRENT_SRC3_ADDR 0x0B0 +#define SDE_MDP_REG_SSPP_DECIMATION_CONFIG 0x0B4 + +enum sde_mdp_mixer_wb_index { + SDE_MDP_WB_LAYERMIXER0, + SDE_MDP_WB_LAYERMIXER1, + SDE_MDP_WB_MAX_LAYERMIXER, +}; + +enum mdss_mdp_writeback_index { + SDE_MDP_WRITEBACK0, + SDE_MDP_WRITEBACK1, + SDE_MDP_WRITEBACK2, + SDE_MDP_WRITEBACK3, + SDE_MDP_WRITEBACK4, + SDE_MDP_MAX_WRITEBACK +}; + +#define SDE_MDP_REG_WB_DST_FORMAT 0x000 +#define SDE_MDP_REG_WB_DST_OP_MODE 0x004 +#define SDE_MDP_REG_WB_DST_PACK_PATTERN 0x008 +#define SDE_MDP_REG_WB_DST0_ADDR 0x00C +#define SDE_MDP_REG_WB_DST1_ADDR 0x010 +#define SDE_MDP_REG_WB_DST2_ADDR 0x014 +#define SDE_MDP_REG_WB_DST3_ADDR 0x018 +#define SDE_MDP_REG_WB_DST_YSTRIDE0 0x01C +#define SDE_MDP_REG_WB_DST_YSTRIDE1 0x020 +#define SDE_MDP_REG_WB_DST_WRITE_CONFIG 0x048 +#define SDE_MDP_REG_WB_ROTATION_DNSCALER 0x050 +#define SDE_MDP_REG_WB_ROTATOR_PIPE_DOWNSCALER 0x054 +#define SDE_MDP_REG_WB_OUT_SIZE 0x074 +#define SDE_MDP_REG_WB_ALPHA_X_VALUE 0x078 +#define SDE_MDP_REG_WB_DST_ADDR_SW_STATUS 0x2B0 + +#endif diff --git a/techpack/display/rotator/sde_rotator_r1_internal.h b/techpack/display/rotator/sde_rotator_r1_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..b5356609c4646d2f7959676d2d3553009e9d2f93 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_internal.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_R1_INTERNAL_H__ +#define __SDE_ROTATOR_R1_INTERNAL_H__ + +#include <linux/types.h> +#include <linux/file.h> +#include <linux/kref.h> +#include <linux/kernel.h> + +#include "sde_rotator_util.h" + +/** + * enum sde_commit_stage_type - Indicate different commit stages + */ +enum sde_commit_stage_type { + SDE_COMMIT_STAGE_SETUP_DONE, + SDE_COMMIT_STAGE_READY_FOR_KICKOFF, +}; + +enum sde_mdp_wb_ctl_type { + SDE_MDP_WB_CTL_TYPE_BLOCK = 1, + SDE_MDP_WB_CTL_TYPE_LINE +}; + +enum sde_mdp_mixer_mux { + SDE_MDP_MIXER_MUX_DEFAULT, + SDE_MDP_MIXER_MUX_LEFT, + SDE_MDP_MIXER_MUX_RIGHT, +}; + +enum sde_mdp_pipe_type { + SDE_MDP_PIPE_TYPE_UNUSED, + SDE_MDP_PIPE_TYPE_VIG, + SDE_MDP_PIPE_TYPE_RGB, + SDE_MDP_PIPE_TYPE_DMA, + SDE_MDP_PIPE_TYPE_CURSOR, +}; + +struct sde_mdp_data; +struct sde_mdp_ctl; +struct sde_mdp_pipe; +struct sde_mdp_mixer; +struct sde_mdp_wb; + +struct sde_mdp_writeback { + u32 num; + char __iomem *base; + u32 offset; +}; + +struct sde_mdp_ctl_intfs_ops { + int (*start_fnc)(struct sde_mdp_ctl *ctl); + int (*stop_fnc)(struct sde_mdp_ctl *ctl, int panel_power_state); + int (*prepare_fnc)(struct sde_mdp_ctl *ctl, void *arg); + int (*display_fnc)(struct sde_mdp_ctl *ctl, void *arg); + int (*wait_fnc)(struct sde_mdp_ctl *ctl, void *arg); +}; + +struct sde_mdp_ctl { + u32 num; + char __iomem *base; + u32 opmode; + u32 flush_bits; + u32 flush_reg_data; + bool is_secure; + struct sde_rot_data_type *mdata; + struct sde_mdp_mixer *mixer_left; + struct sde_mdp_mixer *mixer_right; + void *priv_data; + u32 wb_type; + struct sde_mdp_writeback *wb; + struct sde_mdp_ctl_intfs_ops ops; + u32 offset; + int irq_num; +}; + +struct sde_mdp_mixer { + u32 num; + char __iomem *base; + u8 rotator_mode; + struct sde_mdp_ctl *ctl; + u32 offset; +}; + +struct sde_mdp_shared_reg_ctrl { + u32 reg_off; + u32 bit_off; +}; + +struct sde_mdp_pipe { + u32 num; + u32 type; + u32 ndx; + char __iomem *base; + u32 xin_id; + u32 flags; + u32 bwc_mode; + u16 img_width; + u16 img_height; + u8 horz_deci; + u8 vert_deci; + struct sde_rect src; + struct sde_rect dst; + struct sde_mdp_format_params *src_fmt; + struct sde_mdp_plane_sizes src_planes; + struct sde_mdp_mixer *mixer_left; + struct sde_mdp_mixer *mixer_right; + struct sde_mdp_shared_reg_ctrl clk_ctrl; + u32 params_changed; + u32 offset; +}; + +struct sde_mdp_writeback_arg { + struct sde_mdp_data *data; + void *priv_data; +}; + +struct sde_mdp_commit_cb { + void *data; + int (*commit_cb_fnc)(enum sde_commit_stage_type commit_state, + void *data); +}; + +static inline void sde_mdp_ctl_write(struct sde_mdp_ctl *ctl, + u32 reg, u32 val) +{ + SDEROT_DBG("ctl%d:%6.6x:%8.8x\n", ctl->num, ctl->offset + reg, val); + writel_relaxed(val, ctl->base + reg); +} + +static inline bool sde_mdp_is_nrt_vbif_client(struct sde_rot_data_type *mdata, + struct sde_mdp_pipe *pipe) +{ + return mdata->vbif_nrt_io.base && pipe->mixer_left && + pipe->mixer_left->rotator_mode; +} +int sde_mdp_set_intr_callback(u32 intr_type, u32 intf_num, + void (*fnc_ptr)(void *), void *arg); +int sde_mdp_display_wait4comp(struct sde_mdp_ctl *ctl); +int sde_mdp_writeback_display_commit(struct sde_mdp_ctl *ctl, void *arg); +int sde_mdp_pipe_queue_data(struct sde_mdp_pipe *pipe, + struct sde_mdp_data *src_data); +struct sde_mdp_ctl *sde_mdp_ctl_alloc(struct sde_rot_data_type *mdata, + u32 off); +struct sde_mdp_writeback *sde_mdp_wb_assign(u32 num, u32 reg_index); +void sde_mdp_wb_free(struct sde_mdp_writeback *wb); +struct sde_mdp_mixer *sde_mdp_mixer_assign(u32 id, bool wb); +int sde_mdp_writeback_start(struct sde_mdp_ctl *ctl); +struct sde_mdp_pipe *sde_mdp_pipe_assign(struct sde_rot_data_type *mdata, + struct sde_mdp_mixer *mixer, u32 ndx); +int sde_mdp_pipe_destroy(struct sde_mdp_pipe *pipe); +int sde_mdp_ctl_free(struct sde_mdp_ctl *ctl); +int sde_mdp_display_commit(struct sde_mdp_ctl *ctl, void *arg, + struct sde_mdp_commit_cb *commit_cb); +int sde_mdp_mixer_pipe_update(struct sde_mdp_pipe *pipe, + struct sde_mdp_mixer *mixer, int params_changed); +int sde_mdp_get_pipe_flush_bits(struct sde_mdp_pipe *pipe); +struct sde_mdp_ctl *sde_mdp_ctl_mixer_switch(struct sde_mdp_ctl *ctl, + u32 return_type); +struct sde_mdp_mixer *sde_mdp_mixer_get(struct sde_mdp_ctl *ctl, int mux); +#endif /* __SDE_ROTATOR_R1_INTERNAL_H__ */ diff --git a/techpack/display/rotator/sde_rotator_r1_pipe.c b/techpack/display/rotator/sde_rotator_r1_pipe.c new file mode 100644 index 0000000000000000000000000000000000000000..5c6cb2c5cce178641848ecbf69ac98f70b5f9988 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_pipe.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/bitmap.h> +#include <linux/errno.h> +#include <linux/iopoll.h> +#include <linux/mutex.h> + +#include "sde_rotator_r1_hwio.h" +#include "sde_rotator_base.h" +#include "sde_rotator_util.h" +#include "sde_rotator_r1_internal.h" +#include "sde_rotator_core.h" +#include "sde_rotator_trace.h" + +#define SMP_MB_SIZE (mdss_res->smp_mb_size) +#define SMP_MB_CNT (mdss_res->smp_mb_cnt) +#define SMP_MB_ENTRY_SIZE 16 +#define MAX_BPP 4 + +#define PIPE_CLEANUP_TIMEOUT_US 100000 + +/* following offsets are relative to ctrl register bit offset */ +#define CLK_FORCE_ON_OFFSET 0x0 +#define CLK_FORCE_OFF_OFFSET 0x1 +/* following offsets are relative to status register bit offset */ +#define CLK_STATUS_OFFSET 0x0 + +#define QOS_LUT_NRT_READ 0x0 +#define PANIC_LUT_NRT_READ 0x0 +#define ROBUST_LUT_NRT_READ 0xFFFF + +/* Priority 2, no panic */ +#define VBLANK_PANIC_DEFAULT_CONFIG 0x200000 + +static inline void sde_mdp_pipe_write(struct sde_mdp_pipe *pipe, + u32 reg, u32 val) +{ + SDEROT_DBG("pipe%d:%6.6x:%8.8x\n", pipe->num, pipe->offset + reg, val); + writel_relaxed(val, pipe->base + reg); +} + +static int sde_mdp_pipe_qos_lut(struct sde_mdp_pipe *pipe) +{ + u32 qos_lut; + + qos_lut = QOS_LUT_NRT_READ; /* low priority for nrt */ + + trace_rot_perf_set_qos_luts(pipe->num, pipe->src_fmt->format, + qos_lut, sde_mdp_is_linear_format(pipe->src_fmt)); + + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_CREQ_LUT, + qos_lut); + + return 0; +} + +/** + * @sde_mdp_pipe_nrt_vbif_setup - + * @mdata: pointer to global driver data. + * @pipe: pointer to a pipe + * + * This function assumes that clocks are enabled, so it is callers + * responsibility to enable clocks before calling this function. + */ +static void sde_mdp_pipe_nrt_vbif_setup(struct sde_rot_data_type *mdata, + struct sde_mdp_pipe *pipe) +{ + uint32_t nrt_vbif_client_sel; + + if (pipe->type != SDE_MDP_PIPE_TYPE_DMA) + return; + + nrt_vbif_client_sel = readl_relaxed(mdata->mdp_base + + MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL); + if (sde_mdp_is_nrt_vbif_client(mdata, pipe)) + nrt_vbif_client_sel |= BIT(pipe->num - SDE_MDP_SSPP_DMA0); + else + nrt_vbif_client_sel &= ~BIT(pipe->num - SDE_MDP_SSPP_DMA0); + SDEROT_DBG("mdp:%6.6x:%8.8x\n", MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL, + nrt_vbif_client_sel); + writel_relaxed(nrt_vbif_client_sel, + mdata->mdp_base + MMSS_MDP_RT_NRT_VBIF_CLIENT_SEL); +} + +/** + * sde_mdp_qos_vbif_remapper_setup - Program the VBIF QoS remapper + * registers based on real or non real time clients + * @mdata: Pointer to the global mdss data structure. + * @pipe: Pointer to source pipe struct to get xin id's. + * @is_realtime: To determine if pipe's client is real or + * non real time. + * This function assumes that clocks are on, so it is caller responsibility to + * call this function with clocks enabled. + */ +static void sde_mdp_qos_vbif_remapper_setup(struct sde_rot_data_type *mdata, + struct sde_mdp_pipe *pipe, bool is_realtime) +{ + u32 mask, reg_val, i, vbif_qos; + + if (mdata->npriority_lvl == 0) + return; + + for (i = 0; i < mdata->npriority_lvl; i++) { + reg_val = SDE_VBIF_READ(mdata, SDE_VBIF_QOS_REMAP_BASE + i*4); + mask = 0x3 << (pipe->xin_id * 2); + reg_val &= ~(mask); + vbif_qos = is_realtime ? + mdata->vbif_rt_qos[i] : mdata->vbif_nrt_qos[i]; + reg_val |= vbif_qos << (pipe->xin_id * 2); + SDE_VBIF_WRITE(mdata, SDE_VBIF_QOS_REMAP_BASE + i*4, reg_val); + } +} + +struct sde_mdp_pipe *sde_mdp_pipe_assign(struct sde_rot_data_type *mdata, + struct sde_mdp_mixer *mixer, u32 ndx) +{ + struct sde_mdp_pipe *pipe = NULL; + static struct sde_mdp_pipe sde_pipe[16]; + static const u32 offset[] = {0x00025000, 0x00027000}; + static const u32 xin_id[] = {2, 10}; + static const struct sde_mdp_shared_reg_ctrl clk_ctrl[] = { + {0x2AC, 8}, + {0x2B4, 8} + }; + + if (ndx >= ARRAY_SIZE(offset)) { + SDEROT_ERR("invalid parameters\n"); + return ERR_PTR(-EINVAL); + } + + pipe = &sde_pipe[ndx]; + pipe->num = ndx + SDE_MDP_SSPP_DMA0; + pipe->offset = offset[pipe->num - SDE_MDP_SSPP_DMA0]; + pipe->xin_id = xin_id[pipe->num - SDE_MDP_SSPP_DMA0]; + pipe->base = mdata->sde_io.base + pipe->offset; + pipe->type = SDE_MDP_PIPE_TYPE_DMA; + pipe->mixer_left = mixer; + pipe->clk_ctrl = clk_ctrl[pipe->num - SDE_MDP_SSPP_DMA0]; + + return pipe; +} + +int sde_mdp_pipe_destroy(struct sde_mdp_pipe *pipe) +{ + return 0; +} + +void sde_mdp_pipe_position_update(struct sde_mdp_pipe *pipe, + struct sde_rect *src, struct sde_rect *dst) +{ + u32 src_size, src_xy, dst_size, dst_xy; + + src_size = (src->h << 16) | src->w; + src_xy = (src->y << 16) | src->x; + dst_size = (dst->h << 16) | dst->w; + dst_xy = (dst->y << 16) | dst->x; + + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_SIZE, src_size); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_XY, src_xy); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_OUT_SIZE, dst_size); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_OUT_XY, dst_xy); +} + +static int sde_mdp_image_setup(struct sde_mdp_pipe *pipe, + struct sde_mdp_data *data) +{ + u32 img_size, ystride0, ystride1; + u32 width, height, decimation; + int ret = 0; + struct sde_rect dst, src; + bool rotation = false; + + SDEROT_DBG( + "ctl: %d pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n", + pipe->mixer_left->ctl->num, pipe->num, + pipe->img_width, pipe->img_height, + pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h, + pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h); + + width = pipe->img_width; + height = pipe->img_height; + + if (pipe->flags & SDE_SOURCE_ROTATED_90) + rotation = true; + + sde_mdp_get_plane_sizes(pipe->src_fmt, width, height, + &pipe->src_planes, pipe->bwc_mode, rotation); + + if (data != NULL) { + ret = sde_mdp_data_check(data, &pipe->src_planes, + pipe->src_fmt); + if (ret) + return ret; + } + + if ((pipe->flags & SDE_DEINTERLACE) && + !(pipe->flags & SDE_SOURCE_ROTATED_90)) { + int i; + + for (i = 0; i < pipe->src_planes.num_planes; i++) + pipe->src_planes.ystride[i] *= 2; + width *= 2; + height /= 2; + } + + decimation = ((1 << pipe->horz_deci) - 1) << 8; + decimation |= ((1 << pipe->vert_deci) - 1); + if (decimation) + SDEROT_DBG("Image decimation h=%d v=%d\n", + pipe->horz_deci, pipe->vert_deci); + + dst = pipe->dst; + src = pipe->src; + + ystride0 = (pipe->src_planes.ystride[0]) | + (pipe->src_planes.ystride[1] << 16); + ystride1 = (pipe->src_planes.ystride[2]) | + (pipe->src_planes.ystride[3] << 16); + + img_size = (height << 16) | width; + + sde_mdp_pipe_position_update(pipe, &src, &dst); + + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_IMG_SIZE, img_size); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_YSTRIDE0, ystride0); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_YSTRIDE1, ystride1); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_DECIMATION_CONFIG, + decimation); + + return 0; +} + +static int sde_mdp_format_setup(struct sde_mdp_pipe *pipe) +{ + struct sde_mdp_format_params *fmt; + u32 chroma_samp, unpack, src_format; + u32 secure = 0; + u32 opmode; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + fmt = pipe->src_fmt; + + if (pipe->flags & SDE_SECURE_OVERLAY_SESSION) + secure = 0xF; + + opmode = pipe->bwc_mode; + if (pipe->flags & SDE_FLIP_LR) + opmode |= SDE_MDP_OP_FLIP_LR; + if (pipe->flags & SDE_FLIP_UD) + opmode |= SDE_MDP_OP_FLIP_UD; + + SDEROT_DBG("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format, + opmode); + + chroma_samp = fmt->chroma_sample; + if (pipe->flags & SDE_SOURCE_ROTATED_90) { + if (chroma_samp == SDE_MDP_CHROMA_H2V1) + chroma_samp = SDE_MDP_CHROMA_H1V2; + else if (chroma_samp == SDE_MDP_CHROMA_H1V2) + chroma_samp = SDE_MDP_CHROMA_H2V1; + } + + src_format = (chroma_samp << 23) | + (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | + (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C0_G_Y] << 0); + + if (sde_mdp_is_tilea4x_format(fmt)) + src_format |= BIT(30); + + if (sde_mdp_is_tilea5x_format(fmt)) + src_format |= BIT(31); + + if (pipe->flags & SDE_ROT_90) + src_format |= BIT(11); /* ROT90 */ + + if (fmt->alpha_enable && + fmt->fetch_planes != SDE_MDP_PLANE_INTERLEAVED) + src_format |= BIT(8); /* SRCC3_EN */ + + unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) | + (fmt->element[1] << 8) | (fmt->element[0] << 0); + src_format |= ((fmt->unpack_count - 1) << 12) | + (fmt->unpack_tight << 17) | + (fmt->unpack_align_msb << 18) | + ((fmt->bpp - 1) << 9); + + if (sde_mdp_is_ubwc_format(fmt)) + opmode |= BIT(0); + + if (fmt->is_yuv) + src_format |= BIT(15); + + if (fmt->frame_format != SDE_MDP_FMT_LINEAR + && mdata->highest_bank_bit) { + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_FETCH_CONFIG, + SDE_MDP_FETCH_CONFIG_RESET_VALUE | + mdata->highest_bank_bit << 18); + } + + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_FORMAT, src_format); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_UNPACK_PATTERN, unpack); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_OP_MODE, opmode); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC_ADDR_SW_STATUS, secure); + + /* clear UBWC error */ + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_UBWC_ERROR_STATUS, BIT(31)); + + return 0; +} + +static int sde_mdp_src_addr_setup(struct sde_mdp_pipe *pipe, + struct sde_mdp_data *src_data) +{ + struct sde_mdp_data data = *src_data; + u32 x = 0, y = 0; + int ret = 0; + + SDEROT_DBG("pnum=%d\n", pipe->num); + + ret = sde_mdp_data_check(&data, &pipe->src_planes, pipe->src_fmt); + if (ret) + return ret; + + sde_rot_data_calc_offset(&data, x, y, + &pipe->src_planes, pipe->src_fmt); + + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC0_ADDR, data.p[0].addr); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC1_ADDR, data.p[1].addr); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC2_ADDR, data.p[2].addr); + sde_mdp_pipe_write(pipe, SDE_MDP_REG_SSPP_SRC3_ADDR, data.p[3].addr); + + return 0; +} + +static void sde_mdp_set_ot_limit_pipe(struct sde_mdp_pipe *pipe) +{ + struct sde_mdp_set_ot_params ot_params = {0,}; + + ot_params.xin_id = pipe->xin_id; + ot_params.num = pipe->num; + ot_params.width = pipe->src.w; + ot_params.height = pipe->src.h; + ot_params.fps = 60; + ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_RD_LIM_CONF; + ot_params.reg_off_mdp_clk_ctrl = pipe->clk_ctrl.reg_off; + ot_params.bit_off_mdp_clk_ctrl = pipe->clk_ctrl.bit_off + + CLK_FORCE_ON_OFFSET; + ot_params.fmt = (pipe->src_fmt) ? pipe->src_fmt->format : 0; + + sde_mdp_set_ot_limit(&ot_params); +} + +int sde_mdp_pipe_queue_data(struct sde_mdp_pipe *pipe, + struct sde_mdp_data *src_data) +{ + int ret = 0; + u32 params_changed; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + if (!pipe) { + SDEROT_ERR("pipe not setup properly for queue\n"); + return -ENODEV; + } + + /* + * Reprogram the pipe when there is no dedicated wfd blk and + * virtual mixer is allocated for the DMA pipe during concurrent + * line and block mode operations + */ + + params_changed = (pipe->params_changed); + if (params_changed) { + bool is_realtime = !(pipe->mixer_left->rotator_mode); + + sde_mdp_qos_vbif_remapper_setup(mdata, pipe, is_realtime); + + if (mdata->vbif_nrt_io.base) + sde_mdp_pipe_nrt_vbif_setup(mdata, pipe); + } + + if (params_changed) { + pipe->params_changed = 0; + + ret = sde_mdp_image_setup(pipe, src_data); + if (ret) { + SDEROT_ERR("image setup error for pnum=%d\n", + pipe->num); + goto done; + } + + ret = sde_mdp_format_setup(pipe); + if (ret) { + SDEROT_ERR("format %d setup error pnum=%d\n", + pipe->src_fmt->format, pipe->num); + goto done; + } + + if (test_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map)) + sde_mdp_pipe_qos_lut(pipe); + + sde_mdp_set_ot_limit_pipe(pipe); + } + + ret = sde_mdp_src_addr_setup(pipe, src_data); + if (ret) { + SDEROT_ERR("addr setup error for pnum=%d\n", pipe->num); + goto done; + } + + sde_mdp_mixer_pipe_update(pipe, pipe->mixer_left, + params_changed); +done: + return ret; +} diff --git a/techpack/display/rotator/sde_rotator_r1_wb.c b/techpack/display/rotator/sde_rotator_r1_wb.c new file mode 100644 index 0000000000000000000000000000000000000000..5de8e8b3d38105493a1815f9abb268067b65bb3d --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r1_wb.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include "sde_rotator_r1_hwio.h" +#include "sde_rotator_util.h" +#include "sde_rotator_r1_internal.h" +#include "sde_rotator_core.h" + +/* wait for at most 2 vsync for lowest refresh rate (24hz) */ +#define KOFF_TIMEOUT msecs_to_jiffies(84) + +/* + * if BWC enabled and format is H1V2 or 420, do not use site C or I. + * Hence, set the bits 29:26 in format register, as zero. + */ +#define BWC_FMT_MASK 0xC3FFFFFF +#define MDSS_DEFAULT_OT_SETTING 0x10 + +enum sde_mdp_writeback_type { + SDE_MDP_WRITEBACK_TYPE_ROTATOR, + SDE_MDP_WRITEBACK_TYPE_LINE, + SDE_MDP_WRITEBACK_TYPE_WFD, +}; + +struct sde_mdp_writeback_ctx { + u32 wb_num; + char __iomem *base; + u8 ref_cnt; + u8 type; + struct completion wb_comp; + int comp_cnt; + + u32 intr_type; + u32 intf_num; + + u32 xin_id; + u32 wr_lim; + struct sde_mdp_shared_reg_ctrl clk_ctrl; + + u32 opmode; + struct sde_mdp_format_params *dst_fmt; + u16 img_width; + u16 img_height; + u16 width; + u16 height; + struct sde_rect dst_rect; + + u32 dnsc_factor_w; + u32 dnsc_factor_h; + + u8 rot90; + u32 bwc_mode; + + struct sde_mdp_plane_sizes dst_planes; + + ktime_t start_time; + ktime_t end_time; + u32 offset; +}; + +static struct sde_mdp_writeback_ctx wb_ctx_list[SDE_MDP_MAX_WRITEBACK] = { + { + .type = SDE_MDP_WRITEBACK_TYPE_ROTATOR, + .intr_type = SDE_MDP_IRQ_WB_ROT_COMP, + .intf_num = 0, + .xin_id = 3, + .clk_ctrl.reg_off = 0x2BC, + .clk_ctrl.bit_off = 0x8, + }, + { + .type = SDE_MDP_WRITEBACK_TYPE_ROTATOR, + .intr_type = SDE_MDP_IRQ_WB_ROT_COMP, + .intf_num = 1, + .xin_id = 11, + .clk_ctrl.reg_off = 0x2BC, + .clk_ctrl.bit_off = 0xC, + }, +}; + +static inline void sde_wb_write(struct sde_mdp_writeback_ctx *ctx, + u32 reg, u32 val) +{ + SDEROT_DBG("wb%d:%6.6x:%8.8x\n", ctx->wb_num, ctx->offset + reg, val); + writel_relaxed(val, ctx->base + reg); +} + +static int sde_mdp_writeback_addr_setup(struct sde_mdp_writeback_ctx *ctx, + const struct sde_mdp_data *in_data) +{ + int ret; + struct sde_mdp_data data; + + if (!in_data) + return -EINVAL; + data = *in_data; + + SDEROT_DBG("wb_num=%d addr=0x%pa\n", ctx->wb_num, &data.p[0].addr); + + ret = sde_mdp_data_check(&data, &ctx->dst_planes, ctx->dst_fmt); + if (ret) + return ret; + + sde_rot_data_calc_offset(&data, ctx->dst_rect.x, ctx->dst_rect.y, + &ctx->dst_planes, ctx->dst_fmt); + + if ((ctx->dst_fmt->fetch_planes == SDE_MDP_PLANE_PLANAR) && + (ctx->dst_fmt->element[0] == C1_B_Cb)) + swap(data.p[1].addr, data.p[2].addr); + + sde_wb_write(ctx, SDE_MDP_REG_WB_DST0_ADDR, data.p[0].addr); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST1_ADDR, data.p[1].addr); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST2_ADDR, data.p[2].addr); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST3_ADDR, data.p[3].addr); + + return 0; +} + +static int sde_mdp_writeback_format_setup(struct sde_mdp_writeback_ctx *ctx, + u32 format, struct sde_mdp_ctl *ctl) +{ + struct sde_mdp_format_params *fmt; + u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp; + u32 dnsc_factor, write_config = 0; + u32 opmode = ctx->opmode; + bool rotation = false; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + SDEROT_DBG("wb_num=%d format=%d\n", ctx->wb_num, format); + + if (ctx->rot90) + rotation = true; + + fmt = sde_get_format_params(format); + if (!fmt) { + SDEROT_ERR("wb format=%d not supported\n", format); + return -EINVAL; + } + + sde_mdp_get_plane_sizes(fmt, ctx->img_width, ctx->img_height, + &ctx->dst_planes, + ctx->opmode & SDE_MDP_OP_BWC_EN, rotation); + + ctx->dst_fmt = fmt; + + chroma_samp = fmt->chroma_sample; + + dst_format = (chroma_samp << 23) | + (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | + (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C0_G_Y] << 0); + + dst_format &= BWC_FMT_MASK; + + if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) { + dst_format |= BIT(8); /* DSTC3_EN */ + if (!fmt->alpha_enable) + dst_format |= BIT(14); /* DST_ALPHA_X */ + } + + if (fmt->is_yuv) + dst_format |= BIT(15); + + pattern = (fmt->element[3] << 24) | + (fmt->element[2] << 16) | + (fmt->element[1] << 8) | + (fmt->element[0] << 0); + + dst_format |= (fmt->unpack_align_msb << 18) | + (fmt->unpack_tight << 17) | + ((fmt->unpack_count - 1) << 12) | + ((fmt->bpp - 1) << 9); + + ystride0 = (ctx->dst_planes.ystride[0]) | + (ctx->dst_planes.ystride[1] << 16); + ystride1 = (ctx->dst_planes.ystride[2]) | + (ctx->dst_planes.ystride[3] << 16); + outsize = (ctx->dst_rect.h << 16) | ctx->dst_rect.w; + + if (sde_mdp_is_ubwc_format(fmt)) { + opmode |= BIT(0); + + dst_format |= BIT(31); + if (mdata->highest_bank_bit) + write_config |= (mdata->highest_bank_bit << 8); + + if (fmt->format == SDE_PIX_FMT_RGB_565_UBWC) + write_config |= 0x8; + } + + if (ctx->type == SDE_MDP_WRITEBACK_TYPE_ROTATOR) { + dnsc_factor = (ctx->dnsc_factor_h) | (ctx->dnsc_factor_w << 16); + sde_wb_write(ctx, SDE_MDP_REG_WB_ROTATOR_PIPE_DOWNSCALER, + dnsc_factor); + } + sde_wb_write(ctx, SDE_MDP_REG_WB_ALPHA_X_VALUE, 0xFF); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_FORMAT, dst_format); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_OP_MODE, opmode); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_PACK_PATTERN, pattern); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_YSTRIDE0, ystride0); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_YSTRIDE1, ystride1); + sde_wb_write(ctx, SDE_MDP_REG_WB_OUT_SIZE, outsize); + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_WRITE_CONFIG, write_config); + return 0; +} + +static int sde_mdp_writeback_prepare_rot(struct sde_mdp_ctl *ctl, void *arg) +{ + struct sde_mdp_writeback_ctx *ctx; + struct sde_mdp_writeback_arg *wb_args; + struct sde_rot_entry *entry; + struct sde_rotation_item *item; + struct sde_rot_data_type *mdata; + u32 format; + + ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data; + if (!ctx) + return -ENODEV; + wb_args = (struct sde_mdp_writeback_arg *) arg; + if (!wb_args) + return -ENOENT; + + entry = (struct sde_rot_entry *) wb_args->priv_data; + if (!entry) { + SDEROT_ERR("unable to retrieve rot session ctl=%d\n", ctl->num); + return -ENODEV; + } + item = &entry->item; + mdata = ctl->mdata; + if (!mdata) { + SDEROT_ERR("no mdata attached to ctl=%d", ctl->num); + return -ENODEV; + } + SDEROT_DBG("rot setup wb_num=%d\n", ctx->wb_num); + + ctx->opmode = BIT(6); /* ROT EN */ + if (ctl->mdata->rot_block_size == 128) + ctx->opmode |= BIT(4); /* block size 128 */ + + ctx->bwc_mode = 0; + ctx->opmode |= ctx->bwc_mode; + + ctx->img_width = item->output.width; + ctx->img_height = item->output.height; + ctx->width = ctx->dst_rect.w = item->dst_rect.w; + ctx->height = ctx->dst_rect.h = item->dst_rect.h; + ctx->dst_rect.x = item->dst_rect.x; + ctx->dst_rect.y = item->dst_rect.y; + ctx->dnsc_factor_w = entry->dnsc_factor_w; + ctx->dnsc_factor_h = entry->dnsc_factor_h; + + ctx->rot90 = !!(item->flags & SDE_ROTATION_90); + + format = item->output.format; + + if (ctx->rot90) + ctx->opmode |= BIT(5); /* ROT 90 */ + + return sde_mdp_writeback_format_setup(ctx, format, ctl); +} + +static int sde_mdp_writeback_stop(struct sde_mdp_ctl *ctl, + int panel_power_state) +{ + struct sde_mdp_writeback_ctx *ctx; + + SDEROT_DBG("stop ctl=%d\n", ctl->num); + + ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data; + if (ctx) { + sde_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num, + NULL, NULL); + + complete_all(&ctx->wb_comp); + + ctl->priv_data = NULL; + ctx->ref_cnt--; + } + + return 0; +} + +static void sde_mdp_writeback_intr_done(void *arg) +{ + struct sde_mdp_ctl *ctl = arg; + struct sde_mdp_writeback_ctx *ctx = ctl->priv_data; + + if (!ctx) { + SDEROT_ERR("invalid ctx\n"); + return; + } + + SDEROT_DBG("intr wb_num=%d\n", ctx->wb_num); + if (ctl->irq_num >= 0) + disable_irq_nosync(ctl->irq_num); + complete_all(&ctx->wb_comp); +} + +static int sde_mdp_wb_wait4comp(struct sde_mdp_ctl *ctl, void *arg) +{ + struct sde_mdp_writeback_ctx *ctx; + int rc = 0; + u64 rot_time = 0; + u32 status, mask, isr = 0; + + ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data; + if (!ctx) { + SDEROT_ERR("invalid ctx\n"); + return -ENODEV; + } + + if (ctx->comp_cnt == 0) + return rc; + + if (ctl->irq_num >= 0) { + rc = wait_for_completion_timeout(&ctx->wb_comp, + KOFF_TIMEOUT); + sde_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num, + NULL, NULL); + + if (rc == 0) { + mask = BIT(ctx->intr_type + ctx->intf_num); + + isr = readl_relaxed(ctl->mdata->mdp_base + + SDE_MDP_REG_INTR_STATUS); + status = mask & isr; + + SDEROT_INFO_ONCE( + "mask: 0x%x, isr: 0x%x, status: 0x%x\n", + mask, isr, status); + + if (status) { + SDEROT_WARN("wb done but irq not triggered\n"); + writel_relaxed(BIT(ctl->wb->num), + ctl->mdata->mdp_base + + SDE_MDP_REG_INTR_CLEAR); + sde_mdp_writeback_intr_done(ctl); + rc = 0; + } else { + rc = -ENODEV; + WARN(1, "wb timeout (%d) ctl=%d\n", + rc, ctl->num); + if (ctl->irq_num >= 0) + disable_irq_nosync(ctl->irq_num); + } + } else { + rc = 0; + } + } else { + /* use polling if interrupt is not available */ + int cnt = 200; + + mask = BIT(ctl->wb->num); + do { + udelay(500); + isr = readl_relaxed(ctl->mdata->mdp_base + + SDE_MDP_REG_INTR_STATUS); + status = mask & isr; + cnt--; + } while (cnt > 0 && !status); + writel_relaxed(mask, ctl->mdata->mdp_base + + SDE_MDP_REG_INTR_CLEAR); + + rc = (status) ? 0 : -ENODEV; + } + + if (rc == 0) + ctx->end_time = ktime_get(); + + sde_smmu_ctrl(0); + ctx->comp_cnt--; + + if (!rc) { + rot_time = (u64)ktime_to_us(ctx->end_time) - + (u64)ktime_to_us(ctx->start_time); + SDEROT_DBG( + "ctx%d type:%d xin_id:%d intf_num:%d took %llu microsecs\n", + ctx->wb_num, ctx->type, ctx->xin_id, + ctx->intf_num, rot_time); + } + + SDEROT_DBG("s:%8.8x %s t:%llu c:%d\n", isr, + (rc)?"Timeout":"Done", rot_time, ctx->comp_cnt); + return rc; +} + +static void sde_mdp_set_ot_limit_wb(struct sde_mdp_writeback_ctx *ctx) +{ + struct sde_mdp_set_ot_params ot_params = {0,}; + + ot_params.xin_id = ctx->xin_id; + ot_params.num = ctx->wb_num; + ot_params.width = ctx->width; + ot_params.height = ctx->height; + ot_params.fps = 60; + ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF; + ot_params.reg_off_mdp_clk_ctrl = ctx->clk_ctrl.reg_off; + ot_params.bit_off_mdp_clk_ctrl = ctx->clk_ctrl.bit_off; + ot_params.fmt = (ctx->dst_fmt) ? ctx->dst_fmt->format : 0; + + sde_mdp_set_ot_limit(&ot_params); +} + +static int sde_mdp_writeback_display(struct sde_mdp_ctl *ctl, void *arg) +{ + struct sde_mdp_writeback_ctx *ctx; + struct sde_mdp_writeback_arg *wb_args; + u32 flush_bits = 0; + int ret; + + if (!ctl || !ctl->mdata) + return -ENODEV; + + ctx = (struct sde_mdp_writeback_ctx *) ctl->priv_data; + if (!ctx) + return -ENODEV; + + if (ctx->comp_cnt) { + SDEROT_ERR("previous kickoff not completed yet, ctl=%d\n", + ctl->num); + return -EPERM; + } + + if (ctl->mdata->default_ot_wr_limit || + ctl->mdata->default_ot_rd_limit) + sde_mdp_set_ot_limit_wb(ctx); + + wb_args = (struct sde_mdp_writeback_arg *) arg; + if (!wb_args) + return -ENOENT; + + ret = sde_mdp_writeback_addr_setup(ctx, wb_args->data); + if (ret) { + SDEROT_ERR("writeback data setup error ctl=%d\n", ctl->num); + return ret; + } + + sde_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num, + sde_mdp_writeback_intr_done, ctl); + + flush_bits |= ctl->flush_reg_data; + flush_bits |= BIT(16); /* WB */ + sde_wb_write(ctx, SDE_MDP_REG_WB_DST_ADDR_SW_STATUS, ctl->is_secure); + sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_FLUSH, flush_bits); + + reinit_completion(&ctx->wb_comp); + if (ctl->irq_num >= 0) + enable_irq(ctl->irq_num); + ret = sde_smmu_ctrl(1); + if (ret < 0) { + SDEROT_ERR("IOMMU attach failed\n"); + return ret; + } + + ctx->start_time = ktime_get(); + sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_START, 1); + /* ensure that start command is issued after the barrier */ + wmb(); + + SDEROT_DBG("ctx%d type:%d xin_id:%d intf_num:%d start\n", + ctx->wb_num, ctx->type, ctx->xin_id, ctx->intf_num); + + ctx->comp_cnt++; + + return 0; +} + +int sde_mdp_writeback_start(struct sde_mdp_ctl *ctl) +{ + struct sde_mdp_writeback_ctx *ctx; + struct sde_mdp_writeback *wb; + u32 mem_sel; + + SDEROT_DBG("start ctl=%d\n", ctl->num); + + if (!ctl->wb) { + SDEROT_DBG("wb not setup in the ctl\n"); + return 0; + } + + wb = ctl->wb; + mem_sel = (ctl->opmode & 0xF) - 1; + if (mem_sel < SDE_MDP_MAX_WRITEBACK) { + ctx = &wb_ctx_list[mem_sel]; + if (ctx->ref_cnt) { + SDEROT_ERR("writeback in use %d\n", mem_sel); + return -EBUSY; + } + ctx->ref_cnt++; + } else { + SDEROT_ERR("invalid writeback mode %d\n", mem_sel); + return -EINVAL; + } + + ctl->priv_data = ctx; + ctx->wb_num = wb->num; + ctx->base = wb->base; + ctx->offset = wb->offset; + + init_completion(&ctx->wb_comp); + + if (ctx->type == SDE_MDP_WRITEBACK_TYPE_ROTATOR) + ctl->ops.prepare_fnc = sde_mdp_writeback_prepare_rot; + + ctl->ops.stop_fnc = sde_mdp_writeback_stop; + ctl->ops.display_fnc = sde_mdp_writeback_display; + ctl->ops.wait_fnc = sde_mdp_wb_wait4comp; + + return 0; +} + +int sde_mdp_writeback_display_commit(struct sde_mdp_ctl *ctl, void *arg) +{ + return sde_mdp_display_commit(ctl, arg, NULL); +} diff --git a/techpack/display/rotator/sde_rotator_r3.c b/techpack/display/rotator/sde_rotator_r3.c new file mode 100644 index 0000000000000000000000000000000000000000..0d36bd549c433dab9b72bb95b659ca8b2a399cc1 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r3.c @@ -0,0 +1,4083 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s:%d: " fmt, __func__, __LINE__ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/dma-buf.h> +#include <linux/clk.h> +#include <linux/clk/qcom.h> + +#include "sde_rotator_core.h" +#include "sde_rotator_util.h" +#include "sde_rotator_smmu.h" +#include "sde_rotator_r3.h" +#include "sde_rotator_r3_internal.h" +#include "sde_rotator_r3_hwio.h" +#include "sde_rotator_r3_debug.h" +#include "sde_rotator_trace.h" +#include "sde_rotator_debug.h" +#include "sde_rotator_vbif.h" + +#define RES_UHD (3840*2160) +#define MS_TO_US(t) ((t) * USEC_PER_MSEC) + +/* traffic shaping clock ticks = finish_time x 19.2MHz */ +#define TRAFFIC_SHAPE_CLKTICK_14MS 268800 +#define TRAFFIC_SHAPE_CLKTICK_12MS 230400 +#define TRAFFIC_SHAPE_VSYNC_CLK 19200000 + +/* wait for at most 2 vsync for lowest refresh rate (24hz) */ +#define KOFF_TIMEOUT (42 * 8) + +/* + * When in sbuf mode, select a much longer wait, to allow the other driver + * to detect timeouts and abort if necessary. + */ +#define KOFF_TIMEOUT_SBUF (10000) + +/* default stream buffer headroom in lines */ +#define DEFAULT_SBUF_HEADROOM 20 +#define DEFAULT_UBWC_MALSIZE 0 +#define DEFAULT_UBWC_SWIZZLE 0 + +#define DEFAULT_MAXLINEWIDTH 4096 + +/* stride alignment requirement for avoiding partial writes */ +#define PARTIAL_WRITE_ALIGNMENT 0x1F + +/* Macro for constructing the REGDMA command */ +#define SDE_REGDMA_WRITE(p, off, data) \ + do { \ + SDEROT_DBG("SDEREG.W:[%s:0x%X] <= 0x%X\n", #off, (off),\ + (u32)(data));\ + writel_relaxed_no_log( \ + (REGDMA_OP_REGWRITE | \ + ((off) & REGDMA_ADDR_OFFSET_MASK)), \ + p); \ + p += sizeof(u32); \ + writel_relaxed_no_log(data, p); \ + p += sizeof(u32); \ + } while (0) + +#define SDE_REGDMA_MODIFY(p, off, mask, data) \ + do { \ + SDEROT_DBG("SDEREG.M:[%s:0x%X] <= 0x%X\n", #off, (off),\ + (u32)(data));\ + writel_relaxed_no_log( \ + (REGDMA_OP_REGMODIFY | \ + ((off) & REGDMA_ADDR_OFFSET_MASK)), \ + p); \ + p += sizeof(u32); \ + writel_relaxed_no_log(mask, p); \ + p += sizeof(u32); \ + writel_relaxed_no_log(data, p); \ + p += sizeof(u32); \ + } while (0) + +#define SDE_REGDMA_BLKWRITE_INC(p, off, len) \ + do { \ + SDEROT_DBG("SDEREG.B:[%s:0x%X:0x%X]\n", #off, (off),\ + (u32)(len));\ + writel_relaxed_no_log( \ + (REGDMA_OP_BLKWRITE_INC | \ + ((off) & REGDMA_ADDR_OFFSET_MASK)), \ + p); \ + p += sizeof(u32); \ + writel_relaxed_no_log(len, p); \ + p += sizeof(u32); \ + } while (0) + +#define SDE_REGDMA_BLKWRITE_DATA(p, data) \ + do { \ + SDEROT_DBG("SDEREG.I:[:] <= 0x%X\n", (u32)(data));\ + writel_relaxed_no_log(data, p); \ + p += sizeof(u32); \ + } while (0) + +#define SDE_REGDMA_READ(p, data) \ + do { \ + data = readl_relaxed_no_log(p); \ + p += sizeof(u32); \ + } while (0) + +/* Macro for directly accessing mapped registers */ +#define SDE_ROTREG_WRITE(base, off, data) \ + do { \ + SDEROT_DBG("SDEREG.D:[%s:0x%X] <= 0x%X\n", #off, (off)\ + , (u32)(data));\ + writel_relaxed(data, (base + (off))); \ + } while (0) + +#define SDE_ROTREG_READ(base, off) \ + readl_relaxed(base + (off)) + +#define SDE_ROTTOP_IN_OFFLINE_MODE(_rottop_op_mode_) \ + (((_rottop_op_mode_) & ROTTOP_OP_MODE_ROT_OUT_MASK) == 0) + +static const u32 sde_hw_rotator_v3_inpixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + SDE_PIX_FMT_Y_CB_CR_H2V2, + SDE_PIX_FMT_Y_CR_CB_H2V2, + SDE_PIX_FMT_Y_CR_CB_GH2V2, + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + SDE_PIX_FMT_YCBYCR_H2V1, + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + SDE_PIX_FMT_RGBA_8888_UBWC, + SDE_PIX_FMT_RGBX_8888_UBWC, + SDE_PIX_FMT_RGB_565_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, + SDE_PIX_FMT_RGBA_1010102, + SDE_PIX_FMT_RGBX_1010102, + SDE_PIX_FMT_ARGB_2101010, + SDE_PIX_FMT_XRGB_2101010, + SDE_PIX_FMT_BGRA_1010102, + SDE_PIX_FMT_BGRX_1010102, + SDE_PIX_FMT_ABGR_2101010, + SDE_PIX_FMT_XBGR_2101010, + SDE_PIX_FMT_RGBA_1010102_UBWC, + SDE_PIX_FMT_RGBX_1010102_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, +}; + +static const u32 sde_hw_rotator_v3_outpixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + /* SDE_PIX_FMT_Y_CB_CR_H2V2 */ + /* SDE_PIX_FMT_Y_CR_CB_H2V2 */ + /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */ + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + /* SDE_PIX_FMT_YCBYCR_H2V1 */ + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + SDE_PIX_FMT_RGBA_8888_UBWC, + SDE_PIX_FMT_RGBX_8888_UBWC, + SDE_PIX_FMT_RGB_565_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, + SDE_PIX_FMT_RGBA_1010102, + SDE_PIX_FMT_RGBX_1010102, + /* SDE_PIX_FMT_ARGB_2101010 */ + /* SDE_PIX_FMT_XRGB_2101010 */ + SDE_PIX_FMT_BGRA_1010102, + SDE_PIX_FMT_BGRX_1010102, + /* SDE_PIX_FMT_ABGR_2101010 */ + /* SDE_PIX_FMT_XBGR_2101010 */ + SDE_PIX_FMT_RGBA_1010102_UBWC, + SDE_PIX_FMT_RGBX_1010102_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, +}; + +static const u32 sde_hw_rotator_v4_inpixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + SDE_PIX_FMT_Y_CB_CR_H2V2, + SDE_PIX_FMT_Y_CR_CB_H2V2, + SDE_PIX_FMT_Y_CR_CB_GH2V2, + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + SDE_PIX_FMT_YCBYCR_H2V1, + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + SDE_PIX_FMT_RGBA_8888_UBWC, + SDE_PIX_FMT_RGBX_8888_UBWC, + SDE_PIX_FMT_RGB_565_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, + SDE_PIX_FMT_RGBA_1010102, + SDE_PIX_FMT_RGBX_1010102, + SDE_PIX_FMT_ARGB_2101010, + SDE_PIX_FMT_XRGB_2101010, + SDE_PIX_FMT_BGRA_1010102, + SDE_PIX_FMT_BGRX_1010102, + SDE_PIX_FMT_ABGR_2101010, + SDE_PIX_FMT_XBGR_2101010, + SDE_PIX_FMT_RGBA_1010102_UBWC, + SDE_PIX_FMT_RGBX_1010102_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE, + SDE_PIX_FMT_Y_CBCR_H2V2_TILE, + SDE_PIX_FMT_Y_CRCB_H2V2_TILE, + SDE_PIX_FMT_XRGB_8888_TILE, + SDE_PIX_FMT_ARGB_8888_TILE, + SDE_PIX_FMT_ABGR_8888_TILE, + SDE_PIX_FMT_XBGR_8888_TILE, + SDE_PIX_FMT_RGBA_8888_TILE, + SDE_PIX_FMT_BGRA_8888_TILE, + SDE_PIX_FMT_RGBX_8888_TILE, + SDE_PIX_FMT_BGRX_8888_TILE, + SDE_PIX_FMT_RGBA_1010102_TILE, + SDE_PIX_FMT_RGBX_1010102_TILE, + SDE_PIX_FMT_ARGB_2101010_TILE, + SDE_PIX_FMT_XRGB_2101010_TILE, + SDE_PIX_FMT_BGRA_1010102_TILE, + SDE_PIX_FMT_BGRX_1010102_TILE, + SDE_PIX_FMT_ABGR_2101010_TILE, + SDE_PIX_FMT_XBGR_2101010_TILE, +}; + +static const u32 sde_hw_rotator_v4_outpixfmts[] = { + SDE_PIX_FMT_XRGB_8888, + SDE_PIX_FMT_ARGB_8888, + SDE_PIX_FMT_ABGR_8888, + SDE_PIX_FMT_RGBA_8888, + SDE_PIX_FMT_BGRA_8888, + SDE_PIX_FMT_RGBX_8888, + SDE_PIX_FMT_BGRX_8888, + SDE_PIX_FMT_XBGR_8888, + SDE_PIX_FMT_RGBA_5551, + SDE_PIX_FMT_ARGB_1555, + SDE_PIX_FMT_ABGR_1555, + SDE_PIX_FMT_BGRA_5551, + SDE_PIX_FMT_BGRX_5551, + SDE_PIX_FMT_RGBX_5551, + SDE_PIX_FMT_XBGR_1555, + SDE_PIX_FMT_XRGB_1555, + SDE_PIX_FMT_ARGB_4444, + SDE_PIX_FMT_RGBA_4444, + SDE_PIX_FMT_BGRA_4444, + SDE_PIX_FMT_ABGR_4444, + SDE_PIX_FMT_RGBX_4444, + SDE_PIX_FMT_XRGB_4444, + SDE_PIX_FMT_BGRX_4444, + SDE_PIX_FMT_XBGR_4444, + SDE_PIX_FMT_RGB_888, + SDE_PIX_FMT_BGR_888, + SDE_PIX_FMT_RGB_565, + SDE_PIX_FMT_BGR_565, + /* SDE_PIX_FMT_Y_CB_CR_H2V2 */ + /* SDE_PIX_FMT_Y_CR_CB_H2V2 */ + /* SDE_PIX_FMT_Y_CR_CB_GH2V2 */ + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H1V2, + SDE_PIX_FMT_Y_CRCB_H1V2, + SDE_PIX_FMT_Y_CBCR_H2V1, + SDE_PIX_FMT_Y_CRCB_H2V1, + /* SDE_PIX_FMT_YCBYCR_H2V1 */ + SDE_PIX_FMT_Y_CBCR_H2V2_VENUS, + SDE_PIX_FMT_Y_CRCB_H2V2_VENUS, + SDE_PIX_FMT_RGBA_8888_UBWC, + SDE_PIX_FMT_RGBX_8888_UBWC, + SDE_PIX_FMT_RGB_565_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, + SDE_PIX_FMT_RGBA_1010102, + SDE_PIX_FMT_RGBX_1010102, + SDE_PIX_FMT_ARGB_2101010, + SDE_PIX_FMT_XRGB_2101010, + SDE_PIX_FMT_BGRA_1010102, + SDE_PIX_FMT_BGRX_1010102, + SDE_PIX_FMT_ABGR_2101010, + SDE_PIX_FMT_XBGR_2101010, + SDE_PIX_FMT_RGBA_1010102_UBWC, + SDE_PIX_FMT_RGBX_1010102_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE, + SDE_PIX_FMT_Y_CBCR_H2V2_TILE, + SDE_PIX_FMT_Y_CRCB_H2V2_TILE, + SDE_PIX_FMT_XRGB_8888_TILE, + SDE_PIX_FMT_ARGB_8888_TILE, + SDE_PIX_FMT_ABGR_8888_TILE, + SDE_PIX_FMT_XBGR_8888_TILE, + SDE_PIX_FMT_RGBA_8888_TILE, + SDE_PIX_FMT_BGRA_8888_TILE, + SDE_PIX_FMT_RGBX_8888_TILE, + SDE_PIX_FMT_BGRX_8888_TILE, + SDE_PIX_FMT_RGBA_1010102_TILE, + SDE_PIX_FMT_RGBX_1010102_TILE, + SDE_PIX_FMT_ARGB_2101010_TILE, + SDE_PIX_FMT_XRGB_2101010_TILE, + SDE_PIX_FMT_BGRA_1010102_TILE, + SDE_PIX_FMT_BGRX_1010102_TILE, + SDE_PIX_FMT_ABGR_2101010_TILE, + SDE_PIX_FMT_XBGR_2101010_TILE, +}; + +static const u32 sde_hw_rotator_v4_inpixfmts_sbuf[] = { + SDE_PIX_FMT_Y_CBCR_H2V2_P010, + SDE_PIX_FMT_Y_CBCR_H2V2, + SDE_PIX_FMT_Y_CRCB_H2V2, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_UBWC, + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE, + SDE_PIX_FMT_Y_CBCR_H2V2_TILE, +}; + +static const u32 sde_hw_rotator_v4_outpixfmts_sbuf[] = { + SDE_PIX_FMT_Y_CBCR_H2V2_TP10, + SDE_PIX_FMT_Y_CBCR_H2V2_P010_TILE, + SDE_PIX_FMT_Y_CBCR_H2V2_TILE, +}; + +static struct sde_rot_vbif_debug_bus nrt_vbif_dbg_bus_r3[] = { + {0x214, 0x21c, 16, 1, 0x200}, /* arb clients main */ + {0x214, 0x21c, 0, 12, 0x13}, /* xin blocks - axi side */ + {0x21c, 0x214, 0, 12, 0xc}, /* xin blocks - clock side */ +}; + +static struct sde_rot_debug_bus rot_dbgbus_r3[] = { + /* + * rottop - 0xA8850 + */ + /* REGDMA */ + { 0XA8850, 0, 0 }, + { 0XA8850, 0, 1 }, + { 0XA8850, 0, 2 }, + { 0XA8850, 0, 3 }, + { 0XA8850, 0, 4 }, + + /* ROT_WB */ + { 0XA8850, 1, 0 }, + { 0XA8850, 1, 1 }, + { 0XA8850, 1, 2 }, + { 0XA8850, 1, 3 }, + { 0XA8850, 1, 4 }, + { 0XA8850, 1, 5 }, + { 0XA8850, 1, 6 }, + { 0XA8850, 1, 7 }, + + /* UBWC_DEC */ + { 0XA8850, 2, 0 }, + + /* UBWC_ENC */ + { 0XA8850, 3, 0 }, + + /* ROT_FETCH_0 */ + { 0XA8850, 4, 0 }, + { 0XA8850, 4, 1 }, + { 0XA8850, 4, 2 }, + { 0XA8850, 4, 3 }, + { 0XA8850, 4, 4 }, + { 0XA8850, 4, 5 }, + { 0XA8850, 4, 6 }, + { 0XA8850, 4, 7 }, + + /* ROT_FETCH_1 */ + { 0XA8850, 5, 0 }, + { 0XA8850, 5, 1 }, + { 0XA8850, 5, 2 }, + { 0XA8850, 5, 3 }, + { 0XA8850, 5, 4 }, + { 0XA8850, 5, 5 }, + { 0XA8850, 5, 6 }, + { 0XA8850, 5, 7 }, + + /* ROT_FETCH_2 */ + { 0XA8850, 6, 0 }, + { 0XA8850, 6, 1 }, + { 0XA8850, 6, 2 }, + { 0XA8850, 6, 3 }, + { 0XA8850, 6, 4 }, + { 0XA8850, 6, 5 }, + { 0XA8850, 6, 6 }, + { 0XA8850, 6, 7 }, + + /* ROT_FETCH_3 */ + { 0XA8850, 7, 0 }, + { 0XA8850, 7, 1 }, + { 0XA8850, 7, 2 }, + { 0XA8850, 7, 3 }, + { 0XA8850, 7, 4 }, + { 0XA8850, 7, 5 }, + { 0XA8850, 7, 6 }, + { 0XA8850, 7, 7 }, + + /* ROT_FETCH_4 */ + { 0XA8850, 8, 0 }, + { 0XA8850, 8, 1 }, + { 0XA8850, 8, 2 }, + { 0XA8850, 8, 3 }, + { 0XA8850, 8, 4 }, + { 0XA8850, 8, 5 }, + { 0XA8850, 8, 6 }, + { 0XA8850, 8, 7 }, + + /* ROT_UNPACK_0*/ + { 0XA8850, 9, 0 }, + { 0XA8850, 9, 1 }, + { 0XA8850, 9, 2 }, + { 0XA8850, 9, 3 }, +}; + +static struct sde_rot_regdump sde_rot_r3_regdump[] = { + { "SDEROT_ROTTOP", SDE_ROT_ROTTOP_OFFSET, 0x100, SDE_ROT_REGDUMP_READ }, + { "SDEROT_SSPP", SDE_ROT_SSPP_OFFSET, 0x200, SDE_ROT_REGDUMP_READ }, + { "SDEROT_WB", SDE_ROT_WB_OFFSET, 0x300, SDE_ROT_REGDUMP_READ }, + { "SDEROT_REGDMA_CSR", SDE_ROT_REGDMA_OFFSET, 0x100, + SDE_ROT_REGDUMP_READ }, + /* + * Need to perform a SW reset to REGDMA in order to access the + * REGDMA RAM especially if REGDMA is waiting for Rotator IDLE. + * REGDMA RAM should be dump at last. + */ + { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1, + SDE_ROT_REGDUMP_WRITE, 1 }, + { "SDEROT_REGDMA_RAM", SDE_ROT_REGDMA_RAM_OFFSET, 0x2000, + SDE_ROT_REGDUMP_READ }, + { "SDEROT_VBIF_NRT", SDE_ROT_VBIF_NRT_OFFSET, 0x590, + SDE_ROT_REGDUMP_VBIF }, + { "SDEROT_REGDMA_RESET", ROTTOP_SW_RESET_OVERRIDE, 1, + SDE_ROT_REGDUMP_WRITE, 0 }, +}; + +struct sde_rot_cdp_params { + bool enable; + struct sde_mdp_format_params *fmt; + u32 offset; +}; + +/* Invalid software timestamp value for initialization */ +#define SDE_REGDMA_SWTS_INVALID (~0) + +/** + * __sde_hw_rotator_get_timestamp - obtain rotator current timestamp + * @rot: rotator context + * @q_id: regdma queue id (low/high) + * @return: current timestmap + */ +static u32 __sde_hw_rotator_get_timestamp(struct sde_hw_rotator *rot, u32 q_id) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 ts; + + if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map)) { + if (q_id == ROT_QUEUE_HIGH_PRIORITY) + ts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_ROT_CNTR_0); + else + ts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_ROT_CNTR_1); + } else { + ts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); + if (q_id == ROT_QUEUE_LOW_PRIORITY) + ts >>= SDE_REGDMA_SWTS_SHIFT; + } + + return ts & SDE_REGDMA_SWTS_MASK; +} + +/** + * sde_hw_rotator_disable_irq - Disable hw rotator interrupt with ref. count + * Also, clear rotator/regdma irq enable masks. + * @rot: Pointer to hw rotator + */ +static void sde_hw_rotator_disable_irq(struct sde_hw_rotator *rot) +{ + SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num, + atomic_read(&rot->irq_enabled)); + + if (!atomic_read(&rot->irq_enabled)) { + SDEROT_ERR("irq %d is already disabled\n", rot->irq_num); + return; + } + + if (!atomic_dec_return(&rot->irq_enabled)) { + if (rot->mode == ROT_REGDMA_OFF) + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_EN, 0); + else + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_INT_EN, 0); + /* disable irq after last pending irq is handled, if any */ + synchronize_irq(rot->irq_num); + disable_irq_nosync(rot->irq_num); + } +} + +/** + * sde_hw_rotator_elapsed_swts - Find difference of 2 software timestamps + * @ts_curr: current software timestamp + * @ts_prev: previous software timestamp + * @return: the amount ts_curr is ahead of ts_prev + */ +static int sde_hw_rotator_elapsed_swts(u32 ts_curr, u32 ts_prev) +{ + u32 diff = (ts_curr - ts_prev) & SDE_REGDMA_SWTS_MASK; + + return sign_extend32(diff, (SDE_REGDMA_SWTS_SHIFT - 1)); +} + +/* + * sde_hw_rotator_rotirq_handler - non-regdma interrupt handler + * @irq: Interrupt number + * @ptr: Pointer to private handle provided during registration + * + * This function services rotator interrupt and wakes up waiting client + * with pending rotation requests already submitted to h/w. + */ +static irqreturn_t sde_hw_rotator_rotirq_handler(int irq, void *ptr) +{ + struct sde_hw_rotator *rot = ptr; + struct sde_hw_rotator_context *ctx; + irqreturn_t ret = IRQ_NONE; + u32 isr; + + isr = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_INTR_STATUS); + + SDEROT_DBG("intr_status = %8.8x\n", isr); + + if (isr & ROT_DONE_MASK) { + sde_hw_rotator_disable_irq(rot); + SDEROT_DBG("Notify rotator complete\n"); + + /* Normal rotator only 1 session, no need to lookup */ + ctx = rot->rotCtx[0][0]; + WARN_ON(ctx == NULL); + complete_all(&ctx->rot_comp); + + spin_lock(&rot->rotisr_lock); + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR, + ROT_DONE_CLEAR); + spin_unlock(&rot->rotisr_lock); + ret = IRQ_HANDLED; + } + + return ret; +} + +/* + * sde_hw_rotator_regdmairq_handler - regdma interrupt handler + * @irq: Interrupt number + * @ptr: Pointer to private handle provided during registration + * + * This function services rotator interrupt, decoding the source of + * events (high/low priority queue), and wakes up all waiting clients + * with pending rotation requests already submitted to h/w. + */ +static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_hw_rotator *rot = ptr; + struct sde_hw_rotator_context *ctx, *tmp; + irqreturn_t ret = IRQ_NONE; + u32 isr, isr_tmp; + u32 ts; + u32 q_id; + + isr = SDE_ROTREG_READ(rot->mdss_base, REGDMA_CSR_REGDMA_INT_STATUS); + /* acknowledge interrupt before reading latest timestamp */ + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, isr); + + SDEROT_DBG("intr_status = %8.8x\n", isr); + + /* Any REGDMA status, including error and watchdog timer, should + * trigger and wake up waiting thread + */ + if (isr & (REGDMA_INT_HIGH_MASK | REGDMA_INT_LOW_MASK)) { + spin_lock(&rot->rotisr_lock); + + /* + * Obtain rotator context based on timestamp from regdma + * and low/high interrupt status + */ + if (isr & REGDMA_INT_HIGH_MASK) { + q_id = ROT_QUEUE_HIGH_PRIORITY; + } else if (isr & REGDMA_INT_LOW_MASK) { + q_id = ROT_QUEUE_LOW_PRIORITY; + } else { + SDEROT_ERR("unknown ISR status: isr=0x%X\n", isr); + goto done_isr_handle; + } + + ts = __sde_hw_rotator_get_timestamp(rot, q_id); + + /* + * Timestamp packet is not available in sbuf mode. + * Simulate timestamp update in the handler instead. + */ + if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) || + list_empty(&rot->sbuf_ctx[q_id])) + goto skip_sbuf; + + ctx = NULL; + isr_tmp = isr; + list_for_each_entry(tmp, &rot->sbuf_ctx[q_id], list) { + u32 mask; + + mask = tmp->timestamp & 0x1 ? REGDMA_INT_1_MASK : + REGDMA_INT_0_MASK; + if (isr_tmp & mask) { + isr_tmp &= ~mask; + ctx = tmp; + ts = ctx->timestamp; + rot->ops.update_ts(rot, ctx->q_id, ts); + SDEROT_DBG("update swts:0x%X\n", ts); + } + SDEROT_EVTLOG(isr, tmp->timestamp); + } + if (ctx == NULL) + SDEROT_ERR("invalid swts ctx\n"); +skip_sbuf: + ctx = rot->rotCtx[q_id][ts & SDE_HW_ROT_REGDMA_SEG_MASK]; + + /* + * Wake up all waiting context from the current and previous + * SW Timestamp. + */ + while (ctx && + sde_hw_rotator_elapsed_swts(ctx->timestamp, ts) >= 0) { + ctx->last_regdma_isr_status = isr; + ctx->last_regdma_timestamp = ts; + SDEROT_DBG( + "regdma complete: ctx:%pK, ts:%X\n", ctx, ts); + wake_up_all(&ctx->regdma_waitq); + + ts = (ts - 1) & SDE_REGDMA_SWTS_MASK; + ctx = rot->rotCtx[q_id] + [ts & SDE_HW_ROT_REGDMA_SEG_MASK]; + }; + +done_isr_handle: + spin_unlock(&rot->rotisr_lock); + ret = IRQ_HANDLED; + } else if (isr & REGDMA_INT_ERR_MASK) { + /* + * For REGDMA Err, we save the isr info and wake up + * all waiting contexts + */ + int i, j; + + SDEROT_ERR( + "regdma err isr:%X, wake up all waiting contexts\n", + isr); + + spin_lock(&rot->rotisr_lock); + + for (i = 0; i < ROT_QUEUE_MAX; i++) { + for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) { + ctx = rot->rotCtx[i][j]; + if (ctx && ctx->last_regdma_isr_status == 0) { + ts = __sde_hw_rotator_get_timestamp( + rot, i); + ctx->last_regdma_isr_status = isr; + ctx->last_regdma_timestamp = ts; + wake_up_all(&ctx->regdma_waitq); + SDEROT_DBG("Wake rotctx[%d][%d]:%pK\n", + i, j, ctx); + } + } + } + + spin_unlock(&rot->rotisr_lock); + ret = IRQ_HANDLED; + } + + return ret; +} + +/** + * sde_hw_rotator_pending_hwts - Check if the given context is still pending + * @rot: Pointer to hw rotator + * @ctx: Pointer to rotator context + * @phwts: Pointer to returned reference hw timestamp, optional + * @return: true if context has pending requests + */ +static int sde_hw_rotator_pending_hwts(struct sde_hw_rotator *rot, + struct sde_hw_rotator_context *ctx, u32 *phwts) +{ + u32 hwts; + int ts_diff; + bool pending; + + if (ctx->last_regdma_timestamp == SDE_REGDMA_SWTS_INVALID) { + if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY) + hwts = SDE_ROTREG_READ(rot->mdss_base, + ROTTOP_ROT_CNTR_1); + else + hwts = SDE_ROTREG_READ(rot->mdss_base, + ROTTOP_ROT_CNTR_0); + } else { + hwts = ctx->last_regdma_timestamp; + } + + hwts &= SDE_REGDMA_SWTS_MASK; + + ts_diff = sde_hw_rotator_elapsed_swts(ctx->timestamp, hwts); + + if (phwts) + *phwts = hwts; + + pending = (ts_diff > 0) ? true : false; + + SDEROT_DBG("ts:0x%x, queue_id:%d, hwts:0x%x, pending:%d\n", + ctx->timestamp, ctx->q_id, hwts, pending); + SDEROT_EVTLOG(ctx->timestamp, hwts, ctx->q_id, ts_diff); + return pending; +} + +/** + * sde_hw_rotator_update_hwts - update hw timestamp with given value + * @rot: Pointer to hw rotator + * @q_id: rotator queue id + * @hwts: new hw timestamp + */ +static void sde_hw_rotator_update_hwts(struct sde_hw_rotator *rot, + u32 q_id, u32 hwts) +{ + if (q_id == ROT_QUEUE_LOW_PRIORITY) + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_ROT_CNTR_1, hwts); + else + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_ROT_CNTR_0, hwts); +} + +/** + * sde_hw_rotator_pending_swts - Check if the given context is still pending + * @rot: Pointer to hw rotator + * @ctx: Pointer to rotator context + * @pswts: Pointer to returned reference software timestamp, optional + * @return: true if context has pending requests + */ +static int sde_hw_rotator_pending_swts(struct sde_hw_rotator *rot, + struct sde_hw_rotator_context *ctx, u32 *pswts) +{ + u32 swts; + int ts_diff; + bool pending; + + if (ctx->last_regdma_timestamp == SDE_REGDMA_SWTS_INVALID) + swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG); + else + swts = ctx->last_regdma_timestamp; + + if (ctx->q_id == ROT_QUEUE_LOW_PRIORITY) + swts >>= SDE_REGDMA_SWTS_SHIFT; + + swts &= SDE_REGDMA_SWTS_MASK; + + ts_diff = sde_hw_rotator_elapsed_swts(ctx->timestamp, swts); + + if (pswts) + *pswts = swts; + + pending = (ts_diff > 0) ? true : false; + + SDEROT_DBG("ts:0x%x, queue_id:%d, swts:0x%x, pending:%d\n", + ctx->timestamp, ctx->q_id, swts, pending); + SDEROT_EVTLOG(ctx->timestamp, swts, ctx->q_id, ts_diff); + return pending; +} + +/** + * sde_hw_rotator_update_swts - update software timestamp with given value + * @rot: Pointer to hw rotator + * @q_id: rotator queue id + * @swts: new software timestamp + */ +static void sde_hw_rotator_update_swts(struct sde_hw_rotator *rot, + u32 q_id, u32 swts) +{ + u32 mask = SDE_REGDMA_SWTS_MASK; + + swts &= SDE_REGDMA_SWTS_MASK; + if (q_id == ROT_QUEUE_LOW_PRIORITY) { + swts <<= SDE_REGDMA_SWTS_SHIFT; + mask <<= SDE_REGDMA_SWTS_SHIFT; + } + + swts |= (SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG) & ~mask); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, swts); +} + +/* + * sde_hw_rotator_irq_setup - setup rotator irq + * @mgr: Pointer to rotator manager + * return: none + */ +static int sde_hw_rotator_irq_setup(struct sde_hw_rotator *rot) +{ + int rc = 0; + + /* return early if irq is already setup */ + if (rot->irq_num >= 0) + return 0; + + rot->irq_num = platform_get_irq(rot->pdev, 0); + if (rot->irq_num < 0) { + rc = rot->irq_num; + SDEROT_ERR("fail to get rot irq, fallback to poll %d\n", rc); + } else { + if (rot->mode == ROT_REGDMA_OFF) + rc = devm_request_threaded_irq(&rot->pdev->dev, + rot->irq_num, + sde_hw_rotator_rotirq_handler, + NULL, 0, "sde_rotator_r3", rot); + else + rc = devm_request_threaded_irq(&rot->pdev->dev, + rot->irq_num, + sde_hw_rotator_regdmairq_handler, + NULL, 0, "sde_rotator_r3", rot); + if (rc) { + SDEROT_ERR("fail to request irq r:%d\n", rc); + rot->irq_num = -1; + } else { + disable_irq(rot->irq_num); + } + } + + return rc; +} + +/** + * sde_hw_rotator_enable_irq - Enable hw rotator interrupt with ref. count + * Also, clear rotator/regdma irq status. + * @rot: Pointer to hw rotator + */ +static int sde_hw_rotator_enable_irq(struct sde_hw_rotator *rot) +{ + int ret = 0; + SDEROT_DBG("irq_num:%d enabled:%d\n", rot->irq_num, + atomic_read(&rot->irq_enabled)); + + ret = sde_hw_rotator_irq_setup(rot); + if (ret < 0) { + SDEROT_ERR("Rotator irq setup failed %d\n", ret); + return ret; + } + + if (!atomic_read(&rot->irq_enabled)) { + + if (rot->mode == ROT_REGDMA_OFF) + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR, + ROT_DONE_MASK); + else + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_INT_CLEAR, REGDMA_INT_MASK); + + enable_irq(rot->irq_num); + } + atomic_inc(&rot->irq_enabled); + + return ret; +} + +static int sde_hw_rotator_halt_vbif_xin_client(void) +{ + struct sde_mdp_vbif_halt_params halt_params; + int rc = 0; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + memset(&halt_params, 0, sizeof(struct sde_mdp_vbif_halt_params)); + halt_params.xin_id = mdata->vbif_xin_id[XIN_SSPP]; + halt_params.reg_off_mdp_clk_ctrl = MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0; + halt_params.bit_off_mdp_clk_ctrl = + MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0; + sde_mdp_halt_vbif_xin(&halt_params); + rc |= halt_params.xin_timeout; + + memset(&halt_params, 0, sizeof(struct sde_mdp_vbif_halt_params)); + halt_params.xin_id = mdata->vbif_xin_id[XIN_WRITEBACK]; + halt_params.reg_off_mdp_clk_ctrl = MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0; + halt_params.bit_off_mdp_clk_ctrl = + MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1; + sde_mdp_halt_vbif_xin(&halt_params); + rc |= halt_params.xin_timeout; + + return rc; +} + +/** + * sde_hw_rotator_reset - Reset rotator hardware + * @rot: pointer to hw rotator + * @ctx: pointer to current rotator context during the hw hang (optional) + */ +static int sde_hw_rotator_reset(struct sde_hw_rotator *rot, + struct sde_hw_rotator_context *ctx) +{ + struct sde_hw_rotator_context *rctx = NULL; + u32 int_mask = (REGDMA_INT_0_MASK | REGDMA_INT_1_MASK | + REGDMA_INT_2_MASK); + u32 last_ts[ROT_QUEUE_MAX] = {0,}; + u32 latest_ts, opmode; + int elapsed_time, t; + int i, j; + unsigned long flags; + + if (!rot) { + SDEROT_ERR("NULL rotator\n"); + return -EINVAL; + } + + /* sw reset the hw rotator */ + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_SW_RESET_OVERRIDE, 1); + /* ensure write is issued to the rotator HW */ + wmb(); + usleep_range(MS_TO_US(10), MS_TO_US(20)); + + /* force rotator into offline mode */ + opmode = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_OP_MODE); + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_OP_MODE, + opmode & ~(BIT(5) | BIT(4) | BIT(1) | BIT(0))); + + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_SW_RESET_OVERRIDE, 0); + + /* halt vbif xin client to ensure no pending transaction */ + sde_hw_rotator_halt_vbif_xin_client(); + + /* if no ctx is specified, skip ctx wake up */ + if (!ctx) + return 0; + + if (ctx->q_id >= ROT_QUEUE_MAX) { + SDEROT_ERR("context q_id out of range: %d\n", ctx->q_id); + return -EINVAL; + } + + spin_lock_irqsave(&rot->rotisr_lock, flags); + + /* update timestamp register with current context */ + last_ts[ctx->q_id] = ctx->timestamp; + rot->ops.update_ts(rot, ctx->q_id, ctx->timestamp); + SDEROT_EVTLOG(ctx->timestamp); + + /* + * Search for any pending rot session, and look for last timestamp + * per hw queue. + */ + for (i = 0; i < ROT_QUEUE_MAX; i++) { + latest_ts = atomic_read(&rot->timestamp[i]); + latest_ts &= SDE_REGDMA_SWTS_MASK; + elapsed_time = sde_hw_rotator_elapsed_swts(latest_ts, + last_ts[i]); + + for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) { + rctx = rot->rotCtx[i][j]; + if (rctx && rctx != ctx) { + rctx->last_regdma_isr_status = int_mask; + rctx->last_regdma_timestamp = rctx->timestamp; + + t = sde_hw_rotator_elapsed_swts(latest_ts, + rctx->timestamp); + if (t < elapsed_time) { + elapsed_time = t; + last_ts[i] = rctx->timestamp; + rot->ops.update_ts(rot, i, last_ts[i]); + } + + SDEROT_DBG("rotctx[%d][%d], ts:%d\n", + i, j, rctx->timestamp); + SDEROT_EVTLOG(i, j, rctx->timestamp, + last_ts[i]); + } + } + } + + /* Finally wakeup all pending rotator context in queue */ + for (i = 0; i < ROT_QUEUE_MAX; i++) { + for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; j++) { + rctx = rot->rotCtx[i][j]; + if (rctx && rctx != ctx) + wake_up_all(&rctx->regdma_waitq); + } + } + + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + return 0; +} + +/** + * _sde_hw_rotator_dump_status - Dump hw rotator status on error + * @rot: Pointer to hw rotator + */ +static void _sde_hw_rotator_dump_status(struct sde_hw_rotator *rot, + u32 *ubwcerr) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 reg = 0; + + SDEROT_ERR( + "op_mode = %x, int_en = %x, int_status = %x\n", + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_OP_MODE), + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_INT_EN), + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_INT_STATUS)); + + SDEROT_ERR( + "ts0/ts1 = %x/%x, q0_status = %x, q1_status = %x, block_status = %x\n", + __sde_hw_rotator_get_timestamp(rot, ROT_QUEUE_HIGH_PRIORITY), + __sde_hw_rotator_get_timestamp(rot, ROT_QUEUE_LOW_PRIORITY), + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_QUEUE_0_STATUS), + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_QUEUE_1_STATUS), + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_BLOCK_STATUS)); + + SDEROT_ERR( + "invalid_cmd_offset = %x, fsm_state = %x\n", + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET), + SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_FSM_STATE)); + + SDEROT_ERR("rottop: op_mode = %x, status = %x, clk_status = %x\n", + SDE_ROTREG_READ(rot->mdss_base, ROTTOP_OP_MODE), + SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS), + SDE_ROTREG_READ(rot->mdss_base, ROTTOP_CLK_STATUS)); + + reg = SDE_ROTREG_READ(rot->mdss_base, ROT_SSPP_UBWC_ERROR_STATUS); + if (ubwcerr) + *ubwcerr = reg; + SDEROT_ERR( + "UBWC decode status = %x, UBWC encode status = %x\n", reg, + SDE_ROTREG_READ(rot->mdss_base, ROT_WB_UBWC_ERROR_STATUS)); + + SDEROT_ERR("VBIF XIN HALT status = %x VBIF AXI HALT status = %x\n", + SDE_VBIF_READ(mdata, MMSS_VBIF_XIN_HALT_CTRL1), + SDE_VBIF_READ(mdata, MMSS_VBIF_AXI_HALT_CTRL1)); + + SDEROT_ERR("sspp unpack wr: plane0 = %x, plane1 = %x, plane2 = %x\n", + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_FETCH_SMP_WR_PLANE0), + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_FETCH_SMP_WR_PLANE1), + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_FETCH_SMP_WR_PLANE2)); + SDEROT_ERR("sspp unpack rd: plane0 = %x, plane1 = %x, plane2 = %x\n", + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_SMP_UNPACK_RD_PLANE0), + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_SMP_UNPACK_RD_PLANE1), + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_SMP_UNPACK_RD_PLANE2)); + SDEROT_ERR("sspp: unpack_ln = %x, unpack_blk = %x, fill_lvl = %x\n", + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_UNPACK_LINE_COUNT), + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_UNPACK_BLK_COUNT), + SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_FILL_LEVELS)); + + SDEROT_ERR("wb: sbuf0 = %x, sbuf1 = %x, sys_cache = %x\n", + SDE_ROTREG_READ(rot->mdss_base, + ROT_WB_SBUF_STATUS_PLANE0), + SDE_ROTREG_READ(rot->mdss_base, + ROT_WB_SBUF_STATUS_PLANE1), + SDE_ROTREG_READ(rot->mdss_base, + ROT_WB_SYS_CACHE_MODE)); +} + +/** + * sde_hw_rotator_get_ctx(): Retrieve rotator context from rotator HW based + * on provided session_id. Each rotator has a different session_id. + * @rot: Pointer to rotator hw + * @session_id: Identifier for rotator session + * @sequence_id: Identifier for rotation request within the session + * @q_id: Rotator queue identifier + */ +static struct sde_hw_rotator_context *sde_hw_rotator_get_ctx( + struct sde_hw_rotator *rot, u32 session_id, u32 sequence_id, + enum sde_rot_queue_prio q_id) +{ + int i; + struct sde_hw_rotator_context *ctx = NULL; + + for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++) { + ctx = rot->rotCtx[q_id][i]; + + if (ctx && (ctx->session_id == session_id) && + (ctx->sequence_id == sequence_id)) { + SDEROT_DBG( + "rotCtx sloti[%d][%d] ==> ctx:%pK | session-id:%d | sequence-id:%d\n", + q_id, i, ctx, ctx->session_id, + ctx->sequence_id); + return ctx; + } + } + + return NULL; +} + +/* + * sde_hw_rotator_map_vaddr - map the debug buffer to kernel space + * @dbgbuf: Pointer to debug buffer + * @buf: Pointer to layer buffer structure + * @data: Pointer to h/w mapped buffer structure + */ +static void sde_hw_rotator_map_vaddr(struct sde_dbg_buf *dbgbuf, + struct sde_layer_buffer *buf, struct sde_mdp_data *data) +{ + dbgbuf->dmabuf = data->p[0].srcp_dma_buf; + dbgbuf->buflen = data->p[0].srcp_dma_buf->size; + + dbgbuf->vaddr = NULL; + dbgbuf->width = buf->width; + dbgbuf->height = buf->height; + + if (dbgbuf->dmabuf && (dbgbuf->buflen > 0)) { + dma_buf_begin_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE); + dbgbuf->vaddr = dma_buf_kmap(dbgbuf->dmabuf, 0); + SDEROT_DBG("vaddr mapping: 0x%pK/%ld w:%d/h:%d\n", + dbgbuf->vaddr, dbgbuf->buflen, + dbgbuf->width, dbgbuf->height); + } +} + +/* + * sde_hw_rotator_unmap_vaddr - unmap the debug buffer from kernel space + * @dbgbuf: Pointer to debug buffer + */ +static void sde_hw_rotator_unmap_vaddr(struct sde_dbg_buf *dbgbuf) +{ + if (dbgbuf->vaddr) { + dma_buf_kunmap(dbgbuf->dmabuf, 0, dbgbuf->vaddr); + dma_buf_end_cpu_access(dbgbuf->dmabuf, DMA_FROM_DEVICE); + } + + dbgbuf->vaddr = NULL; + dbgbuf->dmabuf = NULL; + dbgbuf->buflen = 0; + dbgbuf->width = 0; + dbgbuf->height = 0; +} + +static void sde_hw_rotator_vbif_rt_setting(void) +{ + u32 reg_high, reg_shift, reg_val, reg_val_lvl, mask, vbif_qos; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int i, j; + + vbif_lock(mdata->parent_pdev); + + for (i = 0; i < mdata->npriority_lvl; i++) { + for (j = 0; j < MAX_XIN; j++) { + reg_high = ((mdata->vbif_xin_id[j] + & 0x8) >> 3) * 4 + (i * 8); + reg_shift = mdata->vbif_xin_id[j] * 4; + + reg_val = SDE_VBIF_READ(mdata, + MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 + reg_high); + reg_val_lvl = SDE_VBIF_READ(mdata, + MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 + reg_high); + + mask = 0x7 << (mdata->vbif_xin_id[j] * 4); + + vbif_qos = mdata->vbif_nrt_qos[i]; + + reg_val &= ~mask; + reg_val |= (vbif_qos << reg_shift) & mask; + + reg_val_lvl &= ~mask; + reg_val_lvl |= (vbif_qos << reg_shift) & mask; + + SDE_VBIF_WRITE(mdata, + MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 + reg_high, + reg_val); + SDE_VBIF_WRITE(mdata, + MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 + reg_high, + reg_val_lvl); + } + } + + vbif_unlock(mdata->parent_pdev); +} + +/* + * sde_hw_rotator_vbif_setting - helper function to set vbif QoS remapper + * levels, enable write gather enable and avoid clk gating setting for + * debug purpose. + * + * @rot: Pointer to rotator hw + */ +static void sde_hw_rotator_vbif_setting(struct sde_hw_rotator *rot) +{ + u32 i, mask, vbif_qos, reg_val = 0; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + /* VBIF_ROT QoS remapper setting */ + switch (mdata->npriority_lvl) { + + case SDE_MDP_VBIF_4_LEVEL_REMAPPER: + for (i = 0; i < mdata->npriority_lvl; i++) { + reg_val = SDE_VBIF_READ(mdata, + MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4); + mask = 0x3 << (XIN_SSPP * 2); + vbif_qos = mdata->vbif_nrt_qos[i]; + reg_val |= vbif_qos << (XIN_SSPP * 2); + /* ensure write is issued after the read operation */ + mb(); + SDE_VBIF_WRITE(mdata, + MMSS_VBIF_NRT_VBIF_QOS_REMAP_00 + i*4, + reg_val); + } + break; + + case SDE_MDP_VBIF_8_LEVEL_REMAPPER: + mask = mdata->npriority_lvl - 1; + for (i = 0; i < mdata->npriority_lvl; i++) { + /* RD and WR client */ + reg_val |= (mdata->vbif_nrt_qos[i] & mask) + << (XIN_SSPP * 4); + reg_val |= (mdata->vbif_nrt_qos[i] & mask) + << (XIN_WRITEBACK * 4); + + SDE_VBIF_WRITE(mdata, + MMSS_VBIF_NRT_VBIF_QOS_RP_REMAP_000 + i*8, + reg_val); + SDE_VBIF_WRITE(mdata, + MMSS_VBIF_NRT_VBIF_QOS_LVL_REMAP_000 + i*8, + reg_val); + } + break; + + default: + SDEROT_DBG("invalid vbif remapper levels\n"); + } + + /* Enable write gather for writeback to remove write gaps, which + * may hang AXI/BIMC/SDE. + */ + SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN, + BIT(XIN_WRITEBACK)); + + /* + * For debug purpose, disable clock gating, i.e. Clocks always on + */ + if (mdata->clk_always_on) { + SDE_VBIF_WRITE(mdata, MMSS_VBIF_CLKON, 0x3); + SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0, 0x3); + SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL1, + 0xFFFF); + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_CLK_CTRL, 1); + } +} + +/* + * sde_hw_rotator_setup_timestamp_packet - setup timestamp writeback command + * @ctx: Pointer to rotator context + * @mask: Bit mask location of the timestamp + * @swts: Software timestamp + */ +static void sde_hw_rotator_setup_timestamp_packet( + struct sde_hw_rotator_context *ctx, u32 mask, u32 swts) +{ + char __iomem *wrptr; + + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + /* + * Create a dummy packet write out to 1 location for timestamp + * generation. + */ + SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_SIZE, 6); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x00010001); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x00010001); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); + SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->ts_addr); + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_YSTRIDE0, 4); + SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_FORMAT, 4); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x004037FF); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x80000000); + SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->timestamp); + /* + * Must clear secure buffer setting for SW timestamp because + * SW timstamp buffer allocation is always non-secure region. + */ + if (ctx->is_secure) { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0); + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0); + } + SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 4); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x000037FF); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0x03020100); + SDE_REGDMA_BLKWRITE_DATA(wrptr, ctx->ts_addr); + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_YSTRIDE0, 4); + SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE, 0x00010001); + SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE, 0x00010001); + SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY, 0); + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG, + (ctx->rot->highest_bank & 0x3) << 8); + SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC, 0); + SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, 1); + SDE_REGDMA_MODIFY(wrptr, REGDMA_TIMESTAMP_REG, mask, swts); + SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, 1); + + sde_hw_rotator_put_regdma_segment(ctx, wrptr); +} + +/* + * sde_hw_rotator_cdp_configs - configures the CDP registers + * @ctx: Pointer to rotator context + * @params: Pointer to parameters needed for CDP configs + */ +static void sde_hw_rotator_cdp_configs(struct sde_hw_rotator_context *ctx, + struct sde_rot_cdp_params *params) +{ + int reg_val; + char __iomem *wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + if (!params->enable) { + SDE_REGDMA_WRITE(wrptr, params->offset, 0x0); + goto end; + } + + reg_val = BIT(0); /* enable cdp */ + + if (sde_mdp_is_ubwc_format(params->fmt)) + reg_val |= BIT(1); /* enable UBWC meta cdp */ + + if (sde_mdp_is_ubwc_format(params->fmt) + || sde_mdp_is_tilea4x_format(params->fmt) + || sde_mdp_is_tilea5x_format(params->fmt)) + reg_val |= BIT(2); /* enable tile amortize */ + + reg_val |= BIT(3); /* enable preload addr ahead cnt 64 */ + + SDE_REGDMA_WRITE(wrptr, params->offset, reg_val); + +end: + sde_hw_rotator_put_regdma_segment(ctx, wrptr); +} + +/* + * sde_hw_rotator_setup_qos_lut_wr - Set QoS LUT/Danger LUT/Safe LUT configs + * for the WRITEBACK rotator for inline and offline rotation. + * + * @ctx: Pointer to rotator context + */ +static void sde_hw_rotator_setup_qos_lut_wr(struct sde_hw_rotator_context *ctx) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + char __iomem *wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + /* Offline rotation setting */ + if (!ctx->sbuf_mode) { + /* QOS LUT WR setting */ + if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) { + SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0, + mdata->lut_cfg[SDE_ROT_WR].creq_lut_0); + SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1, + mdata->lut_cfg[SDE_ROT_WR].creq_lut_1); + } + + /* Danger LUT WR setting */ + if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT, + mdata->lut_cfg[SDE_ROT_WR].danger_lut); + + /* Safe LUT WR setting */ + if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT, + mdata->lut_cfg[SDE_ROT_WR].safe_lut); + + /* Inline rotation setting */ + } else { + /* QOS LUT WR setting */ + if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) { + SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_0, + mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_0); + SDE_REGDMA_WRITE(wrptr, ROT_WB_CREQ_LUT_1, + mdata->inline_lut_cfg[SDE_ROT_WR].creq_lut_1); + } + + /* Danger LUT WR setting */ + if (test_bit(SDE_INLINE_QOS_DANGER_LUT, + mdata->sde_inline_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_DANGER_LUT, + mdata->inline_lut_cfg[SDE_ROT_WR].danger_lut); + + /* Safe LUT WR setting */ + if (test_bit(SDE_INLINE_QOS_SAFE_LUT, + mdata->sde_inline_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_SAFE_LUT, + mdata->inline_lut_cfg[SDE_ROT_WR].safe_lut); + } + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); +} + +/* + * sde_hw_rotator_setup_qos_lut_rd - Set QoS LUT/Danger LUT/Safe LUT configs + * for the SSPP rotator for inline and offline rotation. + * + * @ctx: Pointer to rotator context + */ +static void sde_hw_rotator_setup_qos_lut_rd(struct sde_hw_rotator_context *ctx) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + char __iomem *wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + /* Offline rotation setting */ + if (!ctx->sbuf_mode) { + /* QOS LUT RD setting */ + if (test_bit(SDE_QOS_LUT, mdata->sde_qos_map)) { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0, + mdata->lut_cfg[SDE_ROT_RD].creq_lut_0); + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1, + mdata->lut_cfg[SDE_ROT_RD].creq_lut_1); + } + + /* Danger LUT RD setting */ + if (test_bit(SDE_QOS_DANGER_LUT, mdata->sde_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT, + mdata->lut_cfg[SDE_ROT_RD].danger_lut); + + /* Safe LUT RD setting */ + if (test_bit(SDE_QOS_SAFE_LUT, mdata->sde_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT, + mdata->lut_cfg[SDE_ROT_RD].safe_lut); + + /* inline rotation setting */ + } else { + /* QOS LUT RD setting */ + if (test_bit(SDE_INLINE_QOS_LUT, mdata->sde_inline_qos_map)) { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_0, + mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_0); + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_CREQ_LUT_1, + mdata->inline_lut_cfg[SDE_ROT_RD].creq_lut_1); + } + + /* Danger LUT RD setting */ + if (test_bit(SDE_INLINE_QOS_DANGER_LUT, + mdata->sde_inline_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_DANGER_LUT, + mdata->inline_lut_cfg[SDE_ROT_RD].danger_lut); + + /* Safe LUT RD setting */ + if (test_bit(SDE_INLINE_QOS_SAFE_LUT, + mdata->sde_inline_qos_map)) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SAFE_LUT, + mdata->inline_lut_cfg[SDE_ROT_RD].safe_lut); + } + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); +} + +static void sde_hw_rotator_setup_fetchengine_helper( + struct sde_hw_rot_sspp_cfg *cfg, + struct sde_rot_data_type *mdata, + struct sde_hw_rotator_context *ctx, char __iomem *wrptr, + u32 flags, u32 *width, u32 *height) +{ + int i; + + /* + * initialize start control trigger selection first + */ + if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) { + if (ctx->sbuf_mode) + SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, + ctx->start_ctrl); + else + SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, 0); + } + + /* source image setup */ + if ((flags & SDE_ROT_FLAG_DEINTERLACE) + && !(flags & SDE_ROT_FLAG_SOURCE_ROTATED_90)) { + for (i = 0; i < cfg->src_plane.num_planes; i++) + cfg->src_plane.ystride[i] *= 2; + *width *= 2; + *height /= 2; + } +} + +/* + * sde_hw_rotator_setup_fetchengine - setup fetch engine + * @ctx: Pointer to rotator context + * @queue_id: Priority queue identifier + * @cfg: Fetch configuration + * @danger_lut: real-time QoS LUT for danger setting (not used) + * @safe_lut: real-time QoS LUT for safe setting (not used) + * @dnsc_factor_w: downscale factor for width + * @dnsc_factor_h: downscale factor for height + * @flags: Control flag + */ +static void sde_hw_rotator_setup_fetchengine(struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, + struct sde_hw_rot_sspp_cfg *cfg, u32 danger_lut, u32 safe_lut, + u32 dnsc_factor_w, u32 dnsc_factor_h, u32 flags) +{ + struct sde_hw_rotator *rot = ctx->rot; + struct sde_mdp_format_params *fmt; + struct sde_mdp_data *data; + struct sde_rot_cdp_params cdp_params = {0}; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + char __iomem *wrptr; + u32 opmode = 0; + u32 chroma_samp = 0; + u32 src_format = 0; + u32 unpack = 0; + u32 width = cfg->img_width; + u32 height = cfg->img_height; + u32 fetch_blocksize = 0; + int i; + + if (ctx->rot->mode == ROT_REGDMA_ON) { + if (rot->irq_num >= 0) + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_INT_EN, + REGDMA_INT_MASK); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_OP_MODE, + REGDMA_EN); + } + + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + sde_hw_rotator_setup_fetchengine_helper(cfg, mdata, ctx, wrptr, + flags, &width, &height); + + /* + * REGDMA BLK write from SRC_SIZE to OP_MODE, total 15 registers + */ + SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_SSPP_SRC_SIZE, 15); + + /* SRC_SIZE, SRC_IMG_SIZE, SRC_XY, OUT_SIZE, OUT_XY */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, + cfg->src_rect->w | (cfg->src_rect->h << 16)); + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); /* SRC_IMG_SIZE unused */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, + cfg->src_rect->x | (cfg->src_rect->y << 16)); + SDE_REGDMA_BLKWRITE_DATA(wrptr, + cfg->src_rect->w | (cfg->src_rect->h << 16)); + SDE_REGDMA_BLKWRITE_DATA(wrptr, + cfg->src_rect->x | (cfg->src_rect->y << 16)); + + /* SRC_ADDR [0-3], SRC_YSTRIDE [0-1] */ + data = cfg->data; + for (i = 0; i < SDE_ROT_MAX_PLANES; i++) + SDE_REGDMA_BLKWRITE_DATA(wrptr, data->p[i].addr); + SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->src_plane.ystride[0] | + (cfg->src_plane.ystride[1] << 16)); + SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->src_plane.ystride[2] | + (cfg->src_plane.ystride[3] << 16)); + + /* UNUSED, write 0 */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); + + /* setup source format */ + fmt = cfg->fmt; + + chroma_samp = fmt->chroma_sample; + if (flags & SDE_ROT_FLAG_SOURCE_ROTATED_90) { + if (chroma_samp == SDE_MDP_CHROMA_H2V1) + chroma_samp = SDE_MDP_CHROMA_H1V2; + else if (chroma_samp == SDE_MDP_CHROMA_H1V2) + chroma_samp = SDE_MDP_CHROMA_H2V1; + } + + src_format = (chroma_samp << 23) | + (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | + (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C0_G_Y] << 0); + + if (fmt->alpha_enable && + (fmt->fetch_planes == SDE_MDP_PLANE_INTERLEAVED)) + src_format |= BIT(8); /* SRCC3_EN */ + + src_format |= ((fmt->unpack_count - 1) << 12) | + (fmt->unpack_tight << 17) | + (fmt->unpack_align_msb << 18) | + ((fmt->bpp - 1) << 9) | + ((fmt->frame_format & 3) << 30); + + if (flags & SDE_ROT_FLAG_ROT_90) + src_format |= BIT(11); /* ROT90 */ + + if (sde_mdp_is_ubwc_format(fmt)) + opmode |= BIT(0); /* BWC_DEC_EN */ + + /* if this is YUV pixel format, enable CSC */ + if (sde_mdp_is_yuv_format(fmt)) + src_format |= BIT(15); /* SRC_COLOR_SPACE */ + + if (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT) + src_format |= BIT(14); /* UNPACK_DX_FORMAT */ + + if (rot->solid_fill) + src_format |= BIT(22); /* SOLID_FILL */ + + /* SRC_FORMAT */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, src_format); + + /* setup source unpack pattern */ + unpack = (fmt->element[3] << 24) | (fmt->element[2] << 16) | + (fmt->element[1] << 8) | (fmt->element[0] << 0); + + /* SRC_UNPACK_PATTERN */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, unpack); + + /* setup source op mode */ + if (flags & SDE_ROT_FLAG_FLIP_LR) + opmode |= BIT(13); /* FLIP_MODE L/R horizontal flip */ + if (flags & SDE_ROT_FLAG_FLIP_UD) + opmode |= BIT(14); /* FLIP_MODE U/D vertical flip */ + opmode |= BIT(31); /* MDSS_MDP_OP_PE_OVERRIDE */ + + /* SRC_OP_MODE */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, opmode); + + /* setup source fetch config, TP10 uses different block size */ + if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map) && + (dnsc_factor_w == 1) && (dnsc_factor_h == 1)) { + if (sde_mdp_is_tp10_format(fmt)) + fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_144_EXT; + else + fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_192_EXT; + } else { + if (sde_mdp_is_tp10_format(fmt)) + fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_96; + else + fetch_blocksize = SDE_ROT_SSPP_FETCH_BLOCKSIZE_128; + } + + if (rot->solid_fill) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_CONSTANT_COLOR, + rot->constant_color); + + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_FETCH_CONFIG, + fetch_blocksize | + SDE_ROT_SSPP_FETCH_CONFIG_RESET_VALUE | + ((rot->highest_bank & 0x3) << 18)); + + if (test_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map)) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_UBWC_STATIC_CTRL, + ((ctx->rot->ubwc_malsize & 0x3) << 8) | + ((ctx->rot->highest_bank & 0x3) << 4) | + ((ctx->rot->ubwc_swizzle & 0x1) << 0)); + else if (test_bit(SDE_CAPS_UBWC_3, mdata->sde_caps_map) || + test_bit(SDE_CAPS_UBWC_4, mdata->sde_caps_map)) + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_UBWC_STATIC_CTRL, BIT(30)); + + /* setup source buffer plane security status */ + if (flags & (SDE_ROT_FLAG_SECURE_OVERLAY_SESSION | + SDE_ROT_FLAG_SECURE_CAMERA_SESSION)) { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0xF); + ctx->is_secure = true; + } else { + SDE_REGDMA_WRITE(wrptr, ROT_SSPP_SRC_ADDR_SW_STATUS, 0); + ctx->is_secure = false; + } + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); + + /* CDP register RD setting */ + cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ? + mdata->enable_cdp[SDE_ROT_RD] : false; + cdp_params.fmt = fmt; + cdp_params.offset = ROT_SSPP_CDP_CNTL; + sde_hw_rotator_cdp_configs(ctx, &cdp_params); + + /* QOS LUT/ Danger LUT/ Safe Lut WR setting */ + sde_hw_rotator_setup_qos_lut_rd(ctx); + + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + /* + * Determine if traffic shaping is required. Only enable traffic + * shaping when content is 4k@30fps. The actual traffic shaping + * bandwidth calculation is done in output setup. + */ + if (((!ctx->sbuf_mode) + && (cfg->src_rect->w * cfg->src_rect->h) >= RES_UHD) + && (cfg->fps <= 30)) { + SDEROT_DBG("Enable Traffic Shaper\n"); + ctx->is_traffic_shaping = true; + } else { + SDEROT_DBG("Disable Traffic Shaper\n"); + ctx->is_traffic_shaping = false; + } + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); +} + +/* + * sde_hw_rotator_setup_wbengine - setup writeback engine + * @ctx: Pointer to rotator context + * @queue_id: Priority queue identifier + * @cfg: Writeback configuration + * @flags: Control flag + */ +static void sde_hw_rotator_setup_wbengine(struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, + struct sde_hw_rot_wb_cfg *cfg, + u32 flags) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_mdp_format_params *fmt; + struct sde_rot_cdp_params cdp_params = {0}; + char __iomem *wrptr; + u32 pack = 0; + u32 dst_format = 0; + u32 no_partial_writes = 0; + int i; + + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + fmt = cfg->fmt; + + /* setup WB DST format */ + dst_format |= (fmt->chroma_sample << 23) | + (fmt->fetch_planes << 19) | + (fmt->bits[C3_ALPHA] << 6) | + (fmt->bits[C2_R_Cr] << 4) | + (fmt->bits[C1_B_Cb] << 2) | + (fmt->bits[C0_G_Y] << 0); + + /* alpha control */ + if (fmt->alpha_enable || (!fmt->is_yuv && (fmt->unpack_count == 4))) { + dst_format |= BIT(8); + if (!fmt->alpha_enable) { + dst_format |= BIT(14); + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ALPHA_X_VALUE, 0); + } + } + + dst_format |= ((fmt->unpack_count - 1) << 12) | + (fmt->unpack_tight << 17) | + (fmt->unpack_align_msb << 18) | + ((fmt->bpp - 1) << 9) | + ((fmt->frame_format & 3) << 30); + + if (sde_mdp_is_yuv_format(fmt)) + dst_format |= BIT(15); + + if (fmt->pixel_mode == SDE_MDP_PIXEL_10BIT) + dst_format |= BIT(21); /* PACK_DX_FORMAT */ + + /* + * REGDMA BLK write, from DST_FORMAT to DST_YSTRIDE 1, total 9 regs + */ + SDE_REGDMA_BLKWRITE_INC(wrptr, ROT_WB_DST_FORMAT, 9); + + /* DST_FORMAT */ + SDE_REGDMA_BLKWRITE_DATA(wrptr, dst_format); + + /* DST_OP_MODE */ + if (sde_mdp_is_ubwc_format(fmt)) + SDE_REGDMA_BLKWRITE_DATA(wrptr, BIT(0)); + else + SDE_REGDMA_BLKWRITE_DATA(wrptr, 0); + + /* DST_PACK_PATTERN */ + pack = (fmt->element[3] << 24) | (fmt->element[2] << 16) | + (fmt->element[1] << 8) | (fmt->element[0] << 0); + SDE_REGDMA_BLKWRITE_DATA(wrptr, pack); + + /* DST_ADDR [0-3], DST_YSTRIDE [0-1] */ + for (i = 0; i < SDE_ROT_MAX_PLANES; i++) + SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->data->p[i].addr); + SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->dst_plane.ystride[0] | + (cfg->dst_plane.ystride[1] << 16)); + SDE_REGDMA_BLKWRITE_DATA(wrptr, cfg->dst_plane.ystride[2] | + (cfg->dst_plane.ystride[3] << 16)); + + /* setup WB out image size and ROI */ + SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_IMG_SIZE, + cfg->img_width | (cfg->img_height << 16)); + SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_SIZE, + cfg->dst_rect->w | (cfg->dst_rect->h << 16)); + SDE_REGDMA_WRITE(wrptr, ROT_WB_OUT_XY, + cfg->dst_rect->x | (cfg->dst_rect->y << 16)); + + if (flags & (SDE_ROT_FLAG_SECURE_OVERLAY_SESSION | + SDE_ROT_FLAG_SECURE_CAMERA_SESSION)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0x1); + else + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_ADDR_SW_STATUS, 0); + + /* + * setup Downscale factor + */ + SDE_REGDMA_WRITE(wrptr, ROTTOP_DNSC, + cfg->v_downscale_factor | + (cfg->h_downscale_factor << 16)); + + /* partial write check */ + if (test_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map)) { + no_partial_writes = BIT(10); + + /* + * For simplicity, don't disable partial writes if + * the ROI does not span the entire width of the + * output image, and require the total stride to + * also be properly aligned. + * + * This avoids having to determine the memory access + * alignment of the actual horizontal ROI on a per + * color format basis. + */ + if (sde_mdp_is_ubwc_format(fmt)) { + no_partial_writes = 0x0; + } else if (cfg->dst_rect->x || + cfg->dst_rect->w != cfg->img_width) { + no_partial_writes = 0x0; + } else { + for (i = 0; i < SDE_ROT_MAX_PLANES; i++) + if (cfg->dst_plane.ystride[i] & + PARTIAL_WRITE_ALIGNMENT) + no_partial_writes = 0x0; + } + } + + /* write config setup for bank configuration */ + SDE_REGDMA_WRITE(wrptr, ROT_WB_DST_WRITE_CONFIG, no_partial_writes | + (ctx->rot->highest_bank & 0x3) << 8); + + if (test_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_UBWC_STATIC_CTRL, + ((ctx->rot->ubwc_malsize & 0x3) << 8) | + ((ctx->rot->highest_bank & 0x3) << 4) | + ((ctx->rot->ubwc_swizzle & 0x1) << 0)); + + if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) + SDE_REGDMA_WRITE(wrptr, ROT_WB_SYS_CACHE_MODE, + ctx->sys_cache_mode); + + SDE_REGDMA_WRITE(wrptr, ROTTOP_OP_MODE, ctx->op_mode | + (flags & SDE_ROT_FLAG_ROT_90 ? BIT(1) : 0) | BIT(0)); + + sde_hw_rotator_put_regdma_segment(ctx, wrptr); + + /* CDP register WR setting */ + cdp_params.enable = test_bit(SDE_QOS_CDP, mdata->sde_qos_map) ? + mdata->enable_cdp[SDE_ROT_WR] : false; + cdp_params.fmt = fmt; + cdp_params.offset = ROT_WB_CDP_CNTL; + sde_hw_rotator_cdp_configs(ctx, &cdp_params); + + /* QOS LUT/ Danger LUT/ Safe LUT WR setting */ + sde_hw_rotator_setup_qos_lut_wr(ctx); + + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + /* setup traffic shaper for 4k 30fps content or if prefill_bw is set */ + if (ctx->is_traffic_shaping || cfg->prefill_bw) { + u32 bw; + + /* + * Target to finish in 12ms, and we need to set number of bytes + * per clock tick for traffic shaping. + * Each clock tick run @ 19.2MHz, so we need we know total of + * clock ticks in 14ms, i.e. 12ms/(1/19.2MHz) ==> 23040 + * Finally, calcualte the byte count per clock tick based on + * resolution, bpp and compression ratio. + */ + bw = cfg->dst_rect->w * cfg->dst_rect->h; + + if (fmt->chroma_sample == SDE_MDP_CHROMA_420) + bw = (bw * 3) / 2; + else + bw *= fmt->bpp; + + bw /= TRAFFIC_SHAPE_CLKTICK_12MS; + + /* use prefill bandwidth instead if specified */ + if (cfg->prefill_bw) + bw = DIV_ROUND_UP_SECTOR_T(cfg->prefill_bw, + TRAFFIC_SHAPE_VSYNC_CLK); + + if (bw > 0xFF) + bw = 0xFF; + else if (bw == 0) + bw = 1; + + SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT, + BIT(31) | (cfg->prefill_bw ? BIT(27) : 0) | bw); + SDEROT_DBG("Enable ROT_WB Traffic Shaper:%d\n", bw); + } else { + SDE_REGDMA_WRITE(wrptr, ROT_WB_TRAFFIC_SHAPER_WR_CLIENT, 0); + SDEROT_DBG("Disable ROT_WB Traffic Shaper\n"); + } + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); +} + +/* + * sde_hw_rotator_start_no_regdma - start non-regdma operation + * @ctx: Pointer to rotator context + * @queue_id: Priority queue identifier + */ +static u32 sde_hw_rotator_start_no_regdma(struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id) +{ + struct sde_hw_rotator *rot = ctx->rot; + char __iomem *wrptr; + char __iomem *mem_rdptr; + char __iomem *addr; + u32 mask; + u32 cmd0, cmd1, cmd2; + u32 blksize; + + /* + * when regdma is not using, the regdma segment is just a normal + * DRAM, and not an iomem. + */ + mem_rdptr = sde_hw_rotator_get_regdma_segment_base(ctx); + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + if (!sde_hw_rotator_enable_irq(rot)) { + SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_EN, 1); + SDE_REGDMA_WRITE(wrptr, ROTTOP_INTR_CLEAR, 1); + reinit_completion(&ctx->rot_comp); + } + + SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl); + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); + + SDEROT_DBG("BEGIN %d\n", ctx->timestamp); + /* Write all command stream to Rotator blocks */ + /* Rotator will start right away after command stream finish writing */ + while (mem_rdptr < wrptr) { + u32 op = REGDMA_OP_MASK & readl_relaxed_no_log(mem_rdptr); + + switch (op) { + case REGDMA_OP_NOP: + SDEROT_DBG("NOP\n"); + mem_rdptr += sizeof(u32); + break; + case REGDMA_OP_REGWRITE: + SDE_REGDMA_READ(mem_rdptr, cmd0); + SDE_REGDMA_READ(mem_rdptr, cmd1); + SDEROT_DBG("REGW %6.6x %8.8x\n", + cmd0 & REGDMA_ADDR_OFFSET_MASK, + cmd1); + addr = rot->mdss_base + + (cmd0 & REGDMA_ADDR_OFFSET_MASK); + writel_relaxed(cmd1, addr); + break; + case REGDMA_OP_REGMODIFY: + SDE_REGDMA_READ(mem_rdptr, cmd0); + SDE_REGDMA_READ(mem_rdptr, cmd1); + SDE_REGDMA_READ(mem_rdptr, cmd2); + SDEROT_DBG("REGM %6.6x %8.8x %8.8x\n", + cmd0 & REGDMA_ADDR_OFFSET_MASK, + cmd1, cmd2); + addr = rot->mdss_base + + (cmd0 & REGDMA_ADDR_OFFSET_MASK); + mask = cmd1; + writel_relaxed((readl_relaxed(addr) & mask) | cmd2, + addr); + break; + case REGDMA_OP_BLKWRITE_SINGLE: + SDE_REGDMA_READ(mem_rdptr, cmd0); + SDE_REGDMA_READ(mem_rdptr, cmd1); + SDEROT_DBG("BLKWS %6.6x %6.6x\n", + cmd0 & REGDMA_ADDR_OFFSET_MASK, + cmd1); + addr = rot->mdss_base + + (cmd0 & REGDMA_ADDR_OFFSET_MASK); + blksize = cmd1; + while (blksize--) { + SDE_REGDMA_READ(mem_rdptr, cmd0); + SDEROT_DBG("DATA %8.8x\n", cmd0); + writel_relaxed(cmd0, addr); + } + break; + case REGDMA_OP_BLKWRITE_INC: + SDE_REGDMA_READ(mem_rdptr, cmd0); + SDE_REGDMA_READ(mem_rdptr, cmd1); + SDEROT_DBG("BLKWI %6.6x %6.6x\n", + cmd0 & REGDMA_ADDR_OFFSET_MASK, + cmd1); + addr = rot->mdss_base + + (cmd0 & REGDMA_ADDR_OFFSET_MASK); + blksize = cmd1; + while (blksize--) { + SDE_REGDMA_READ(mem_rdptr, cmd0); + SDEROT_DBG("DATA %8.8x\n", cmd0); + writel_relaxed(cmd0, addr); + addr += 4; + } + break; + default: + /* Other not supported OP mode + * Skip data for now for unregonized OP mode + */ + SDEROT_DBG("UNDEFINED\n"); + mem_rdptr += sizeof(u32); + break; + } + } + SDEROT_DBG("END %d\n", ctx->timestamp); + + return ctx->timestamp; +} + +/* + * sde_hw_rotator_start_regdma - start regdma operation + * @ctx: Pointer to rotator context + * @queue_id: Priority queue identifier + */ +static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_hw_rotator *rot = ctx->rot; + char __iomem *wrptr; + u32 regdmaSlot; + u32 offset; + u32 length; + u32 ts_length; + u32 enableInt; + u32 swts = 0; + u32 mask = 0; + u32 trig_sel; + bool int_trigger = false; + + wrptr = sde_hw_rotator_get_regdma_segment(ctx); + + /* Enable HW timestamp if supported in rotator */ + if (test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map)) { + SDE_REGDMA_MODIFY(wrptr, ROTTOP_ROT_CNTR_CTRL, + ~BIT(queue_id), BIT(queue_id)); + int_trigger = true; + } else if (ctx->sbuf_mode) { + int_trigger = true; + } + + /* + * Last ROT command must be ROT_START before REGDMA start + */ + SDE_REGDMA_WRITE(wrptr, ROTTOP_START_CTRL, ctx->start_ctrl); + + sde_hw_rotator_put_regdma_segment(ctx, wrptr); + + /* + * Start REGDMA with command offset and size + */ + regdmaSlot = sde_hw_rotator_get_regdma_ctxidx(ctx); + length = (wrptr - ctx->regdma_base) / 4; + offset = (ctx->regdma_base - (rot->mdss_base + + REGDMA_RAM_REGDMA_CMD_RAM)) / sizeof(u32); + enableInt = ((ctx->timestamp & 1) + 1) << 30; + trig_sel = ctx->sbuf_mode ? REGDMA_CMD_TRIG_SEL_MDP_FLUSH : + REGDMA_CMD_TRIG_SEL_SW_START; + + SDEROT_DBG( + "regdma(%d)[%d] <== INT:0x%X|length:%d|offset:0x%X, ts:%X\n", + queue_id, regdmaSlot, enableInt, length, offset, + ctx->timestamp); + + /* ensure the command packet is issued before the submit command */ + wmb(); + + /* REGDMA submission for current context */ + if (queue_id == ROT_QUEUE_HIGH_PRIORITY) { + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_QUEUE_0_SUBMIT, + (int_trigger ? enableInt : 0) | trig_sel | + ((length & 0x3ff) << 14) | offset); + swts = ctx->timestamp; + mask = ~SDE_REGDMA_SWTS_MASK; + } else { + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT, + (int_trigger ? enableInt : 0) | trig_sel | + ((length & 0x3ff) << 14) | offset); + swts = ctx->timestamp << SDE_REGDMA_SWTS_SHIFT; + mask = ~(SDE_REGDMA_SWTS_MASK << SDE_REGDMA_SWTS_SHIFT); + } + + SDEROT_EVTLOG(ctx->timestamp, queue_id, length, offset, ctx->sbuf_mode); + + /* sw timestamp update can only be used in offline multi-context mode */ + if (!int_trigger) { + /* Write timestamp after previous rotator job finished */ + sde_hw_rotator_setup_timestamp_packet(ctx, mask, swts); + offset += length; + ts_length = sde_hw_rotator_get_regdma_segment(ctx) - wrptr; + ts_length /= sizeof(u32); + WARN_ON((length + ts_length) > SDE_HW_ROT_REGDMA_SEG_SIZE); + + /* ensure command packet is issue before the submit command */ + wmb(); + + SDEROT_EVTLOG(queue_id, enableInt, ts_length, offset); + + if (queue_id == ROT_QUEUE_HIGH_PRIORITY) { + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_QUEUE_0_SUBMIT, + enableInt | (ts_length << 14) | offset); + } else { + SDE_ROTREG_WRITE(rot->mdss_base, + REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT, + enableInt | (ts_length << 14) | offset); + } + } + + /* Update command queue write ptr */ + sde_hw_rotator_put_regdma_segment(ctx, wrptr); + + return ctx->timestamp; +} + +/* + * sde_hw_rotator_wait_done_no_regdma - wait for non-regdma completion + * @ctx: Pointer to rotator context + * @queue_id: Priority queue identifier + * @flags: Option flag + */ +static u32 sde_hw_rotator_wait_done_no_regdma( + struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, u32 flag) +{ + struct sde_hw_rotator *rot = ctx->rot; + int rc = 0; + u32 sts = 0; + u32 status; + unsigned long flags; + + if (rot->irq_num >= 0) { + SDEROT_DBG("Wait for Rotator completion\n"); + rc = wait_for_completion_timeout(&ctx->rot_comp, + ctx->sbuf_mode ? + msecs_to_jiffies(KOFF_TIMEOUT_SBUF) : + msecs_to_jiffies(rot->koff_timeout)); + + spin_lock_irqsave(&rot->rotisr_lock, flags); + status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS); + if (rc == 0) { + /* + * Timeout, there might be error, + * or rotator still busy + */ + if (status & ROT_BUSY_BIT) + SDEROT_ERR( + "Timeout waiting for rotator done\n"); + else if (status & ROT_ERROR_BIT) + SDEROT_ERR( + "Rotator report error status\n"); + else + SDEROT_WARN( + "Timeout waiting, but rotator job is done!!\n"); + + sde_hw_rotator_disable_irq(rot); + } + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + } else { + int cnt = 200; + + do { + udelay(500); + status = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS); + cnt--; + } while ((cnt > 0) && (status & ROT_BUSY_BIT) + && ((status & ROT_ERROR_BIT) == 0)); + + if (status & ROT_ERROR_BIT) + SDEROT_ERR("Rotator error\n"); + else if (status & ROT_BUSY_BIT) + SDEROT_ERR("Rotator busy\n"); + + SDE_ROTREG_WRITE(rot->mdss_base, ROTTOP_INTR_CLEAR, + ROT_DONE_CLEAR); + } + + sts = (status & ROT_ERROR_BIT) ? -ENODEV : 0; + + return sts; +} + +/* + * sde_hw_rotator_wait_done_regdma - wait for regdma completion + * @ctx: Pointer to rotator context + * @queue_id: Priority queue identifier + * @flags: Option flag + */ +static u32 sde_hw_rotator_wait_done_regdma( + struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, u32 flag) +{ + struct sde_hw_rotator *rot = ctx->rot; + int rc = 0; + bool timeout = false; + bool pending; + bool abort; + u32 status; + u32 last_isr; + u32 last_ts; + u32 int_id; + u32 swts; + u32 sts = 0; + u32 ubwcerr; + u32 hwts[ROT_QUEUE_MAX]; + unsigned long flags; + + if (rot->irq_num >= 0) { + SDEROT_DBG("Wait for REGDMA completion, ctx:%pK, ts:%X\n", + ctx, ctx->timestamp); + rc = wait_event_timeout(ctx->regdma_waitq, + !rot->ops.get_pending_ts(rot, ctx, &swts), + ctx->sbuf_mode ? + msecs_to_jiffies(KOFF_TIMEOUT_SBUF) : + msecs_to_jiffies(rot->koff_timeout)); + + ATRACE_INT("sde_rot_done", 0); + spin_lock_irqsave(&rot->rotisr_lock, flags); + + last_isr = ctx->last_regdma_isr_status; + last_ts = ctx->last_regdma_timestamp; + abort = ctx->abort; + status = last_isr & REGDMA_INT_MASK; + int_id = last_ts & 1; + SDEROT_DBG("INT status:0x%X, INT id:%d, timestamp:0x%X\n", + status, int_id, last_ts); + + if (rc == 0 || (status & REGDMA_INT_ERR_MASK) || abort) { + timeout = true; + pending = rot->ops.get_pending_ts(rot, ctx, &swts); + + /* cache ubwcerr and hw timestamps while locked */ + ubwcerr = SDE_ROTREG_READ(rot->mdss_base, + ROT_SSPP_UBWC_ERROR_STATUS); + hwts[ROT_QUEUE_HIGH_PRIORITY] = + __sde_hw_rotator_get_timestamp(rot, + ROT_QUEUE_HIGH_PRIORITY); + hwts[ROT_QUEUE_LOW_PRIORITY] = + __sde_hw_rotator_get_timestamp(rot, + ROT_QUEUE_LOW_PRIORITY); + + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + if (ubwcerr || abort || + sde_hw_rotator_halt_vbif_xin_client()) { + /* + * Perform recovery for ROT SSPP UBWC decode + * error. + * - SW reset rotator hw block + * - reset TS logic so all pending rotation + * in hw queue got done signalled + */ + if (!sde_hw_rotator_reset(rot, ctx)) + status = REGDMA_INCOMPLETE_CMD; + else + status = ROT_ERROR_BIT; + } else { + status = ROT_ERROR_BIT; + } + + spin_lock_irqsave(&rot->rotisr_lock, flags); + } else { + if (rc == 1) + SDEROT_WARN( + "REGDMA done but no irq, ts:0x%X/0x%X\n", + ctx->timestamp, swts); + status = 0; + } + + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + /* dump rot status after releasing lock if timeout occurred */ + if (timeout) { + SDEROT_ERR( + "TIMEOUT, ts:0x%X/0x%X, pending:%d, abort:%d\n", + ctx->timestamp, swts, pending, abort); + SDEROT_ERR( + "Cached: HW ts0/ts1 = %x/%x, ubwcerr = %x\n", + hwts[ROT_QUEUE_HIGH_PRIORITY], + hwts[ROT_QUEUE_LOW_PRIORITY], ubwcerr); + + if (status & REGDMA_WATCHDOG_INT) + SDEROT_ERR("REGDMA watchdog interrupt\n"); + else if (status & REGDMA_INVALID_DESCRIPTOR) + SDEROT_ERR("REGDMA invalid descriptor\n"); + else if (status & REGDMA_INCOMPLETE_CMD) + SDEROT_ERR("REGDMA incomplete command\n"); + else if (status & REGDMA_INVALID_CMD) + SDEROT_ERR("REGDMA invalid command\n"); + + _sde_hw_rotator_dump_status(rot, &ubwcerr); + } + } else { + int cnt = 200; + bool pending; + + do { + udelay(500); + last_isr = SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_INT_STATUS); + pending = rot->ops.get_pending_ts(rot, ctx, &swts); + cnt--; + } while ((cnt > 0) && pending && + ((last_isr & REGDMA_INT_ERR_MASK) == 0)); + + if (last_isr & REGDMA_INT_ERR_MASK) { + SDEROT_ERR("Rotator error, ts:0x%X/0x%X status:%x\n", + ctx->timestamp, swts, last_isr); + _sde_hw_rotator_dump_status(rot, NULL); + status = ROT_ERROR_BIT; + } else if (pending) { + SDEROT_ERR("Rotator timeout, ts:0x%X/0x%X status:%x\n", + ctx->timestamp, swts, last_isr); + _sde_hw_rotator_dump_status(rot, NULL); + status = ROT_ERROR_BIT; + } else { + status = 0; + } + + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_CSR_REGDMA_INT_CLEAR, + last_isr); + } + + sts = (status & (ROT_ERROR_BIT | REGDMA_INCOMPLETE_CMD)) ? -ENODEV : 0; + + if (status & ROT_ERROR_BIT) + SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus", + "vbif_dbg_bus", "panic"); + + return sts; +} + +/* + * setup_rotator_ops - setup callback functions for the low-level HAL + * @ops: Pointer to low-level ops callback + * @mode: Operation mode (non-regdma or regdma) + * @use_hwts: HW timestamp support mode + */ +static void setup_rotator_ops(struct sde_hw_rotator_ops *ops, + enum sde_rotator_regdma_mode mode, + bool use_hwts) +{ + ops->setup_rotator_fetchengine = sde_hw_rotator_setup_fetchengine; + ops->setup_rotator_wbengine = sde_hw_rotator_setup_wbengine; + if (mode == ROT_REGDMA_ON) { + ops->start_rotator = sde_hw_rotator_start_regdma; + ops->wait_rotator_done = sde_hw_rotator_wait_done_regdma; + } else { + ops->start_rotator = sde_hw_rotator_start_no_regdma; + ops->wait_rotator_done = sde_hw_rotator_wait_done_no_regdma; + } + + if (use_hwts) { + ops->get_pending_ts = sde_hw_rotator_pending_hwts; + ops->update_ts = sde_hw_rotator_update_hwts; + } else { + ops->get_pending_ts = sde_hw_rotator_pending_swts; + ops->update_ts = sde_hw_rotator_update_swts; + } +} + +/* + * sde_hw_rotator_swts_create - create software timestamp buffer + * @rot: Pointer to rotator hw + * + * This buffer is used by regdma to keep track of last completed command. + */ +static int sde_hw_rotator_swts_create(struct sde_hw_rotator *rot) +{ + int rc = 0; + struct sde_mdp_img_data *data; + u32 bufsize = sizeof(int) * SDE_HW_ROT_REGDMA_TOTAL_CTX * 2; + + if (bufsize < SZ_4K) + bufsize = SZ_4K; + + data = &rot->swts_buf; + data->len = bufsize; + data->srcp_dma_buf = sde_rot_get_dmabuf(data); + if (!data->srcp_dma_buf) { + SDEROT_ERR("Fail dmabuf create\n"); + return -ENOMEM; + } + + sde_smmu_ctrl(1); + + data->srcp_attachment = sde_smmu_dma_buf_attach(data->srcp_dma_buf, + &rot->pdev->dev, SDE_IOMMU_DOMAIN_ROT_UNSECURE); + if (IS_ERR_OR_NULL(data->srcp_attachment)) { + SDEROT_ERR("sde_smmu_dma_buf_attach error\n"); + rc = -ENOMEM; + goto err_put; + } + + data->srcp_table = dma_buf_map_attachment(data->srcp_attachment, + DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(data->srcp_table)) { + SDEROT_ERR("dma_buf_map_attachment error\n"); + rc = -ENOMEM; + goto err_detach; + } + + rc = sde_smmu_map_dma_buf(data->srcp_dma_buf, data->srcp_table, + SDE_IOMMU_DOMAIN_ROT_UNSECURE, &data->addr, + &data->len, DMA_BIDIRECTIONAL); + if (rc < 0) { + SDEROT_ERR("smmu_map_dma_buf failed: (%d)\n", rc); + goto err_unmap; + } + + data->mapped = true; + SDEROT_DBG("swts buffer mapped: %pad/%lx va:%pK\n", &data->addr, + data->len, rot->swts_buffer); + + sde_smmu_ctrl(0); + + return rc; +err_unmap: + dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, + DMA_FROM_DEVICE); +err_detach: + dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); +err_put: + data->srcp_dma_buf = NULL; + + sde_smmu_ctrl(0); + return rc; +} + +/* + * sde_hw_rotator_swts_destroy - destroy software timestamp buffer + * @rot: Pointer to rotator hw + */ +static void sde_hw_rotator_swts_destroy(struct sde_hw_rotator *rot) +{ + struct sde_mdp_img_data *data; + + data = &rot->swts_buf; + + sde_smmu_unmap_dma_buf(data->srcp_table, SDE_IOMMU_DOMAIN_ROT_UNSECURE, + DMA_FROM_DEVICE, data->srcp_dma_buf); + dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, + DMA_FROM_DEVICE); + dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); + dma_buf_put(data->srcp_dma_buf); + data->addr = 0; + data->srcp_dma_buf = NULL; + data->srcp_attachment = NULL; + data->mapped = false; +} + +/* + * sde_hw_rotator_pre_pmevent - SDE rotator core will call this before a + * PM event occurs + * @mgr: Pointer to rotator manager + * @pmon: Boolean indicate an on/off power event + */ +void sde_hw_rotator_pre_pmevent(struct sde_rot_mgr *mgr, bool pmon) +{ + struct sde_hw_rotator *rot; + u32 l_ts, h_ts, l_hwts, h_hwts; + u32 rotsts, regdmasts, rotopmode; + + /* + * Check last HW timestamp with SW timestamp before power off event. + * If there is a mismatch, that will be quite possible the rotator HW + * is either hang or not finishing last submitted job. In that case, + * it is best to do a timeout eventlog to capture some good events + * log data for analysis. + */ + if (!pmon && mgr && mgr->hw_data) { + rot = mgr->hw_data; + h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]) & + SDE_REGDMA_SWTS_MASK; + l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]) & + SDE_REGDMA_SWTS_MASK; + + /* Need to turn on clock to access rotator register */ + sde_rotator_clk_ctrl(mgr, true); + l_hwts = __sde_hw_rotator_get_timestamp(rot, + ROT_QUEUE_LOW_PRIORITY); + h_hwts = __sde_hw_rotator_get_timestamp(rot, + ROT_QUEUE_HIGH_PRIORITY); + regdmasts = SDE_ROTREG_READ(rot->mdss_base, + REGDMA_CSR_REGDMA_BLOCK_STATUS); + rotsts = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_STATUS); + rotopmode = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_OP_MODE); + + SDEROT_DBG( + "swts(l/h):0x%x/0x%x, hwts(l/h):0x%x/0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n", + l_ts, h_ts, l_hwts, h_hwts, + regdmasts, rotsts); + SDEROT_EVTLOG(l_ts, h_ts, l_hwts, h_hwts, regdmasts, rotsts); + + if (((l_ts != l_hwts) || (h_ts != h_hwts)) && + ((regdmasts & REGDMA_BUSY) || + (rotsts & ROT_STATUS_MASK))) { + SDEROT_ERR( + "Mismatch SWTS with HWTS: swts(l/h):0x%x/0x%x, hwts(l/h):0x%x/0x%x, regdma-sts:0x%x, rottop-sts:0x%x\n", + l_ts, h_ts, l_hwts, h_hwts, + regdmasts, rotsts); + _sde_hw_rotator_dump_status(rot, NULL); + SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus", + "vbif_dbg_bus", "panic"); + } else if (!SDE_ROTTOP_IN_OFFLINE_MODE(rotopmode) && + ((regdmasts & REGDMA_BUSY) || + (rotsts & ROT_BUSY_BIT))) { + /* + * rotator can stuck in inline while mdp is detached + */ + SDEROT_WARN( + "Inline Rot busy: regdma-sts:0x%x, rottop-sts:0x%x, rottop-opmode:0x%x\n", + regdmasts, rotsts, rotopmode); + sde_hw_rotator_reset(rot, NULL); + } else if ((regdmasts & REGDMA_BUSY) || + (rotsts & ROT_BUSY_BIT)) { + _sde_hw_rotator_dump_status(rot, NULL); + SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus", + "vbif_dbg_bus", "panic"); + sde_hw_rotator_reset(rot, NULL); + } + + /* Turn off rotator clock after checking rotator registers */ + sde_rotator_clk_ctrl(mgr, false); + } +} + +/* + * sde_hw_rotator_post_pmevent - SDE rotator core will call this after a + * PM event occurs + * @mgr: Pointer to rotator manager + * @pmon: Boolean indicate an on/off power event + */ +void sde_hw_rotator_post_pmevent(struct sde_rot_mgr *mgr, bool pmon) +{ + struct sde_hw_rotator *rot; + u32 l_ts, h_ts; + + /* + * After a power on event, the rotator HW is reset to default setting. + * It is necessary to synchronize the SW timestamp with the HW. + */ + if (pmon && mgr && mgr->hw_data) { + rot = mgr->hw_data; + h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]); + l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]); + + SDEROT_DBG("h_ts:0x%x, l_ts;0x%x\n", h_ts, l_ts); + SDEROT_EVTLOG(h_ts, l_ts); + rot->reset_hw_ts = true; + rot->last_hwts[ROT_QUEUE_LOW_PRIORITY] = + l_ts & SDE_REGDMA_SWTS_MASK; + rot->last_hwts[ROT_QUEUE_HIGH_PRIORITY] = + h_ts & SDE_REGDMA_SWTS_MASK; + } +} + +/* + * sde_hw_rotator_destroy - Destroy hw rotator and free allocated resources + * @mgr: Pointer to rotator manager + */ +static void sde_hw_rotator_destroy(struct sde_rot_mgr *mgr) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_hw_rotator *rot; + + if (!mgr || !mgr->pdev || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return; + } + + rot = mgr->hw_data; + if (rot->irq_num >= 0) + devm_free_irq(&mgr->pdev->dev, rot->irq_num, mdata); + + if (!test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) && + rot->mode == ROT_REGDMA_ON) + sde_hw_rotator_swts_destroy(rot); + + devm_kfree(&mgr->pdev->dev, mgr->hw_data); + mgr->hw_data = NULL; +} + +/* + * sde_hw_rotator_alloc_ext - allocate rotator resource from rotator hw + * @mgr: Pointer to rotator manager + * @pipe_id: pipe identifier (not used) + * @wb_id: writeback identifier/priority queue identifier + * + * This function allocates a new hw rotator resource for the given priority. + */ +static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext( + struct sde_rot_mgr *mgr, u32 pipe_id, u32 wb_id) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_hw_rotator_resource_info *resinfo; + + if (!mgr || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return NULL; + } + + /* + * Allocate rotator resource info. Each allocation is per + * HW priority queue + */ + resinfo = devm_kzalloc(&mgr->pdev->dev, sizeof(*resinfo), GFP_KERNEL); + if (!resinfo) { + SDEROT_ERR("Failed allocation HW rotator resource info\n"); + return NULL; + } + + resinfo->rot = mgr->hw_data; + resinfo->hw.wb_id = wb_id; + atomic_set(&resinfo->hw.num_active, 0); + init_waitqueue_head(&resinfo->hw.wait_queue); + + /* For non-regdma, only support one active session */ + if (resinfo->rot->mode == ROT_REGDMA_OFF) + resinfo->hw.max_active = 1; + else { + resinfo->hw.max_active = SDE_HW_ROT_REGDMA_TOTAL_CTX - 1; + + if (!test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map) && + (!resinfo->rot->swts_buf.mapped)) + sde_hw_rotator_swts_create(resinfo->rot); + } + + sde_hw_rotator_enable_irq(resinfo->rot); + + SDEROT_DBG("New rotator resource:%pK, priority:%d\n", + resinfo, wb_id); + + return &resinfo->hw; +} + +/* + * sde_hw_rotator_free_ext - free the given rotator resource + * @mgr: Pointer to rotator manager + * @hw: Pointer to rotator resource + */ +static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr, + struct sde_rot_hw_resource *hw) +{ + struct sde_hw_rotator_resource_info *resinfo; + + if (!mgr || !mgr->hw_data) + return; + + resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw); + + SDEROT_DBG( + "Free rotator resource:%pK, priority:%d, active:%d, pending:%d\n", + resinfo, hw->wb_id, atomic_read(&hw->num_active), + hw->pending_count); + + sde_hw_rotator_disable_irq(resinfo->rot); + + devm_kfree(&mgr->pdev->dev, resinfo); +} + +/* + * sde_hw_rotator_alloc_rotctx - allocate rotator context + * @rot: Pointer to rotator hw + * @hw: Pointer to rotator resource + * @session_id: Session identifier of this context + * @sequence_id: Sequence identifier of this request + * @sbuf_mode: true if stream buffer is requested + * + * This function allocates a new rotator context for the given session id. + */ +static struct sde_hw_rotator_context *sde_hw_rotator_alloc_rotctx( + struct sde_hw_rotator *rot, + struct sde_rot_hw_resource *hw, + u32 session_id, + u32 sequence_id, + bool sbuf_mode) +{ + struct sde_hw_rotator_context *ctx; + + /* Allocate rotator context */ + ctx = devm_kzalloc(&rot->pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + SDEROT_ERR("Failed allocation HW rotator context\n"); + return NULL; + } + + ctx->rot = rot; + ctx->q_id = hw->wb_id; + ctx->session_id = session_id; + ctx->sequence_id = sequence_id; + ctx->hwres = hw; + ctx->timestamp = atomic_add_return(1, &rot->timestamp[ctx->q_id]); + ctx->timestamp &= SDE_REGDMA_SWTS_MASK; + ctx->is_secure = false; + ctx->sbuf_mode = sbuf_mode; + INIT_LIST_HEAD(&ctx->list); + + ctx->regdma_base = rot->cmd_wr_ptr[ctx->q_id] + [sde_hw_rotator_get_regdma_ctxidx(ctx)]; + ctx->regdma_wrptr = ctx->regdma_base; + ctx->ts_addr = (dma_addr_t)((u32 *)rot->swts_buf.addr + + ctx->q_id * SDE_HW_ROT_REGDMA_TOTAL_CTX + + sde_hw_rotator_get_regdma_ctxidx(ctx)); + + ctx->last_regdma_timestamp = SDE_REGDMA_SWTS_INVALID; + + init_completion(&ctx->rot_comp); + init_waitqueue_head(&ctx->regdma_waitq); + + /* Store rotator context for lookup purpose */ + sde_hw_rotator_put_ctx(ctx); + + SDEROT_DBG( + "New rot CTX:%pK, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n", + ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id, + ctx->q_id, ctx->timestamp, + atomic_read(&ctx->hwres->num_active), + ctx->sbuf_mode); + + return ctx; +} + +/* + * sde_hw_rotator_free_rotctx - free the given rotator context + * @rot: Pointer to rotator hw + * @ctx: Pointer to rotator context + */ +static void sde_hw_rotator_free_rotctx(struct sde_hw_rotator *rot, + struct sde_hw_rotator_context *ctx) +{ + if (!rot || !ctx) + return; + + SDEROT_DBG( + "Free rot CTX:%pK, ctxidx:%d, session-id:%d, prio:%d, timestamp:%X, active:%d sbuf:%d\n", + ctx, sde_hw_rotator_get_regdma_ctxidx(ctx), ctx->session_id, + ctx->q_id, ctx->timestamp, + atomic_read(&ctx->hwres->num_active), + ctx->sbuf_mode); + + /* Clear rotator context from lookup purpose */ + sde_hw_rotator_clr_ctx(ctx); + + devm_kfree(&rot->pdev->dev, ctx); +} + +/* + * sde_hw_rotator_config - configure hw for the given rotation entry + * @hw: Pointer to rotator resource + * @entry: Pointer to rotation entry + * + * This function setup the fetch/writeback/rotator blocks, as well as VBIF + * based on the given rotation entry. + */ +static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_hw_rotator *rot; + struct sde_hw_rotator_resource_info *resinfo; + struct sde_hw_rotator_context *ctx; + struct sde_hw_rot_sspp_cfg sspp_cfg; + struct sde_hw_rot_wb_cfg wb_cfg; + u32 danger_lut = 0; /* applicable for realtime client only */ + u32 safe_lut = 0; /* applicable for realtime client only */ + u32 flags = 0; + u32 rststs = 0; + struct sde_rotation_item *item; + int ret; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry\n"); + return -EINVAL; + } + + resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw); + rot = resinfo->rot; + item = &entry->item; + + ctx = sde_hw_rotator_alloc_rotctx(rot, hw, item->session_id, + item->sequence_id, item->output.sbuf); + if (!ctx) { + SDEROT_ERR("Failed allocating rotator context!!\n"); + return -EINVAL; + } + + /* save entry for debugging purposes */ + ctx->last_entry = entry; + + if (test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) { + if (entry->dst_buf.sbuf) { + u32 op_mode; + + if (entry->item.trigger == + SDE_ROTATOR_TRIGGER_COMMAND) + ctx->start_ctrl = (rot->cmd_trigger << 4); + else if (entry->item.trigger == + SDE_ROTATOR_TRIGGER_VIDEO) + ctx->start_ctrl = (rot->vid_trigger << 4); + else + ctx->start_ctrl = 0; + + ctx->sys_cache_mode = BIT(15) | + ((item->output.scid & 0x1f) << 8) | + (item->output.writeback ? 0x5 : 0); + + ctx->op_mode = BIT(4) | + ((ctx->rot->sbuf_headroom & 0xff) << 8); + + /* detect transition to inline mode */ + op_mode = (SDE_ROTREG_READ(rot->mdss_base, + ROTTOP_OP_MODE) >> 4) & 0x3; + if (!op_mode) { + u32 status; + + status = SDE_ROTREG_READ(rot->mdss_base, + ROTTOP_STATUS); + if (status & BIT(0)) { + SDEROT_ERR("rotator busy 0x%x\n", + status); + _sde_hw_rotator_dump_status(rot, NULL); + SDEROT_EVTLOG_TOUT_HANDLER("rot", + "vbif_dbg_bus", + "panic"); + } + } + + } else { + ctx->start_ctrl = BIT(0); + ctx->sys_cache_mode = 0; + ctx->op_mode = 0; + } + } else { + ctx->start_ctrl = BIT(0); + } + + SDEROT_EVTLOG(ctx->start_ctrl, ctx->sys_cache_mode, ctx->op_mode); + + /* + * if Rotator HW is reset, but missing PM event notification, we + * need to init the SW timestamp automatically. + */ + rststs = SDE_ROTREG_READ(rot->mdss_base, REGDMA_RESET_STATUS_REG); + if (!rot->reset_hw_ts && rststs) { + u32 l_ts, h_ts, l_hwts, h_hwts; + + h_hwts = __sde_hw_rotator_get_timestamp(rot, + ROT_QUEUE_HIGH_PRIORITY); + l_hwts = __sde_hw_rotator_get_timestamp(rot, + ROT_QUEUE_LOW_PRIORITY); + h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]); + l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]); + SDEROT_EVTLOG(0xbad0, rststs, l_hwts, h_hwts, l_ts, h_ts); + + if (ctx->q_id == ROT_QUEUE_HIGH_PRIORITY) { + h_ts = (h_ts - 1) & SDE_REGDMA_SWTS_MASK; + l_ts &= SDE_REGDMA_SWTS_MASK; + } else { + l_ts = (l_ts - 1) & SDE_REGDMA_SWTS_MASK; + h_ts &= SDE_REGDMA_SWTS_MASK; + } + + SDEROT_DBG("h_ts:0x%x, l_ts;0x%x\n", h_ts, l_ts); + SDEROT_EVTLOG(0x900d, h_ts, l_ts); + rot->last_hwts[ROT_QUEUE_LOW_PRIORITY] = l_ts; + rot->last_hwts[ROT_QUEUE_HIGH_PRIORITY] = h_ts; + + rot->ops.update_ts(rot, ROT_QUEUE_HIGH_PRIORITY, h_ts); + rot->ops.update_ts(rot, ROT_QUEUE_LOW_PRIORITY, l_ts); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_RESET_STATUS_REG, 0); + + /* ensure write is issued to the rotator HW */ + wmb(); + } + + if (rot->reset_hw_ts) { + SDEROT_EVTLOG(rot->last_hwts[ROT_QUEUE_LOW_PRIORITY], + rot->last_hwts[ROT_QUEUE_HIGH_PRIORITY]); + rot->ops.update_ts(rot, ROT_QUEUE_HIGH_PRIORITY, + rot->last_hwts[ROT_QUEUE_HIGH_PRIORITY]); + rot->ops.update_ts(rot, ROT_QUEUE_LOW_PRIORITY, + rot->last_hwts[ROT_QUEUE_LOW_PRIORITY]); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_RESET_STATUS_REG, 0); + + /* ensure write is issued to the rotator HW */ + wmb(); + rot->reset_hw_ts = false; + } + + flags = (item->flags & SDE_ROTATION_FLIP_LR) ? + SDE_ROT_FLAG_FLIP_LR : 0; + flags |= (item->flags & SDE_ROTATION_FLIP_UD) ? + SDE_ROT_FLAG_FLIP_UD : 0; + flags |= (item->flags & SDE_ROTATION_90) ? + SDE_ROT_FLAG_ROT_90 : 0; + flags |= (item->flags & SDE_ROTATION_DEINTERLACE) ? + SDE_ROT_FLAG_DEINTERLACE : 0; + flags |= (item->flags & SDE_ROTATION_SECURE) ? + SDE_ROT_FLAG_SECURE_OVERLAY_SESSION : 0; + flags |= (item->flags & SDE_ROTATION_SECURE_CAMERA) ? + SDE_ROT_FLAG_SECURE_CAMERA_SESSION : 0; + + + sspp_cfg.img_width = item->input.width; + sspp_cfg.img_height = item->input.height; + sspp_cfg.fps = entry->perf->config.frame_rate; + sspp_cfg.bw = entry->perf->bw; + sspp_cfg.fmt = sde_get_format_params(item->input.format); + if (!sspp_cfg.fmt) { + SDEROT_ERR("null format\n"); + ret = -EINVAL; + goto error; + } + sspp_cfg.src_rect = &item->src_rect; + sspp_cfg.data = &entry->src_buf; + sde_mdp_get_plane_sizes(sspp_cfg.fmt, item->input.width, + item->input.height, &sspp_cfg.src_plane, + 0, /* No bwc_mode */ + (flags & SDE_ROT_FLAG_SOURCE_ROTATED_90) ? + true : false); + + rot->ops.setup_rotator_fetchengine(ctx, ctx->q_id, + &sspp_cfg, danger_lut, safe_lut, + entry->dnsc_factor_w, entry->dnsc_factor_h, flags); + + wb_cfg.img_width = item->output.width; + wb_cfg.img_height = item->output.height; + wb_cfg.fps = entry->perf->config.frame_rate; + wb_cfg.bw = entry->perf->bw; + wb_cfg.fmt = sde_get_format_params(item->output.format); + if (!wb_cfg.fmt) { + SDEROT_ERR("null format\n"); + ret = -EINVAL; + goto error; + } + + wb_cfg.dst_rect = &item->dst_rect; + wb_cfg.data = &entry->dst_buf; + sde_mdp_get_plane_sizes(wb_cfg.fmt, item->output.width, + item->output.height, &wb_cfg.dst_plane, + 0, /* No bwc_mode */ + (flags & SDE_ROT_FLAG_ROT_90) ? true : false); + + wb_cfg.v_downscale_factor = entry->dnsc_factor_h; + wb_cfg.h_downscale_factor = entry->dnsc_factor_w; + wb_cfg.prefill_bw = item->prefill_bw; + + rot->ops.setup_rotator_wbengine(ctx, ctx->q_id, &wb_cfg, flags); + + /* setup VA mapping for debugfs */ + if (rot->dbgmem) { + sde_hw_rotator_map_vaddr(&ctx->src_dbgbuf, + &item->input, + &entry->src_buf); + + sde_hw_rotator_map_vaddr(&ctx->dst_dbgbuf, + &item->output, + &entry->dst_buf); + } + + SDEROT_EVTLOG(ctx->timestamp, flags, + item->input.width, item->input.height, + item->output.width, item->output.height, + entry->src_buf.p[0].addr, entry->dst_buf.p[0].addr, + item->input.format, item->output.format, + entry->perf->config.frame_rate); + + /* initialize static vbif setting */ + sde_mdp_init_vbif(); + + if (!ctx->sbuf_mode && mdata->default_ot_rd_limit) { + struct sde_mdp_set_ot_params ot_params; + + memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params)); + ot_params.xin_id = mdata->vbif_xin_id[XIN_SSPP]; + ot_params.num = 0; /* not used */ + ot_params.width = entry->perf->config.input.width; + ot_params.height = entry->perf->config.input.height; + ot_params.fps = entry->perf->config.frame_rate; + ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_RD_LIM_CONF; + ot_params.reg_off_mdp_clk_ctrl = + MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0; + ot_params.bit_off_mdp_clk_ctrl = + MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN0; + ot_params.fmt = ctx->is_traffic_shaping ? + SDE_PIX_FMT_ABGR_8888 : + entry->perf->config.input.format; + ot_params.rotsts_base = rot->mdss_base + ROTTOP_STATUS; + ot_params.rotsts_busy_mask = ROT_BUSY_BIT; + sde_mdp_set_ot_limit(&ot_params); + } + + if (!ctx->sbuf_mode && mdata->default_ot_wr_limit) { + struct sde_mdp_set_ot_params ot_params; + + memset(&ot_params, 0, sizeof(struct sde_mdp_set_ot_params)); + ot_params.xin_id = mdata->vbif_xin_id[XIN_WRITEBACK]; + ot_params.num = 0; /* not used */ + ot_params.width = entry->perf->config.input.width; + ot_params.height = entry->perf->config.input.height; + ot_params.fps = entry->perf->config.frame_rate; + ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF; + ot_params.reg_off_mdp_clk_ctrl = + MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0; + ot_params.bit_off_mdp_clk_ctrl = + MMSS_VBIF_NRT_VBIF_CLK_FORCE_CTRL0_XIN1; + ot_params.fmt = ctx->is_traffic_shaping ? + SDE_PIX_FMT_ABGR_8888 : + entry->perf->config.input.format; + ot_params.rotsts_base = rot->mdss_base + ROTTOP_STATUS; + ot_params.rotsts_busy_mask = ROT_BUSY_BIT; + sde_mdp_set_ot_limit(&ot_params); + } + + if (test_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map)) { + u32 qos_lut = 0; /* low priority for nrt read client */ + + trace_rot_perf_set_qos_luts(mdata->vbif_xin_id[XIN_SSPP], + sspp_cfg.fmt->format, qos_lut, + sde_mdp_is_linear_format(sspp_cfg.fmt)); + + SDE_ROTREG_WRITE(rot->mdss_base, ROT_SSPP_CREQ_LUT, qos_lut); + } + + /* VBIF QoS and other settings */ + if (!ctx->sbuf_mode) { + if (mdata->parent_pdev) + sde_hw_rotator_vbif_rt_setting(); + else + sde_hw_rotator_vbif_setting(rot); + } + + return 0; + +error: + sde_hw_rotator_free_rotctx(rot, ctx); + return ret; +} + +/* + * sde_hw_rotator_cancel - cancel hw configuration for the given rotation entry + * @hw: Pointer to rotator resource + * @entry: Pointer to rotation entry + * + * This function cancels a previously configured rotation entry. + */ +static int sde_hw_rotator_cancel(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_hw_rotator *rot; + struct sde_hw_rotator_resource_info *resinfo; + struct sde_hw_rotator_context *ctx; + unsigned long flags; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry\n"); + return -EINVAL; + } + + resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw); + rot = resinfo->rot; + + /* Lookup rotator context from session-id */ + ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, + entry->item.sequence_id, hw->wb_id); + if (!ctx) { + SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n", + entry->item.session_id); + return -EINVAL; + } + + spin_lock_irqsave(&rot->rotisr_lock, flags); + rot->ops.update_ts(rot, ctx->q_id, ctx->timestamp); + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + SDEROT_EVTLOG(entry->item.session_id, ctx->timestamp); + + if (rot->dbgmem) { + sde_hw_rotator_unmap_vaddr(&ctx->src_dbgbuf); + sde_hw_rotator_unmap_vaddr(&ctx->dst_dbgbuf); + } + + /* Current rotator context job is finished, time to free up */ + sde_hw_rotator_free_rotctx(rot, ctx); + + return 0; +} + +/* + * sde_hw_rotator_kickoff - kickoff processing on the given entry + * @hw: Pointer to rotator resource + * @entry: Pointer to rotation entry + */ +static int sde_hw_rotator_kickoff(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_hw_rotator *rot; + struct sde_hw_rotator_resource_info *resinfo; + struct sde_hw_rotator_context *ctx; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry\n"); + return -EINVAL; + } + + resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw); + rot = resinfo->rot; + + /* Lookup rotator context from session-id */ + ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, + entry->item.sequence_id, hw->wb_id); + if (!ctx) { + SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n", + entry->item.session_id); + return -EINVAL; + } + + rot->ops.start_rotator(ctx, ctx->q_id); + + return 0; +} + +static int sde_hw_rotator_abort_kickoff(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_hw_rotator *rot; + struct sde_hw_rotator_resource_info *resinfo; + struct sde_hw_rotator_context *ctx; + unsigned long flags; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry\n"); + return -EINVAL; + } + + resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw); + rot = resinfo->rot; + + /* Lookup rotator context from session-id */ + ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, + entry->item.sequence_id, hw->wb_id); + if (!ctx) { + SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n", + entry->item.session_id); + return -EINVAL; + } + + spin_lock_irqsave(&rot->rotisr_lock, flags); + rot->ops.update_ts(rot, ctx->q_id, ctx->timestamp); + ctx->abort = true; + wake_up_all(&ctx->regdma_waitq); + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + SDEROT_EVTLOG(entry->item.session_id, ctx->timestamp); + + return 0; +} + +/* + * sde_hw_rotator_wait4done - wait for completion notification + * @hw: Pointer to rotator resource + * @entry: Pointer to rotation entry + * + * This function blocks until the given entry is complete, error + * is detected, or timeout. + */ +static int sde_hw_rotator_wait4done(struct sde_rot_hw_resource *hw, + struct sde_rot_entry *entry) +{ + struct sde_hw_rotator *rot; + struct sde_hw_rotator_resource_info *resinfo; + struct sde_hw_rotator_context *ctx; + int ret; + + if (!hw || !entry) { + SDEROT_ERR("null hw resource/entry\n"); + return -EINVAL; + } + + resinfo = container_of(hw, struct sde_hw_rotator_resource_info, hw); + rot = resinfo->rot; + + /* Lookup rotator context from session-id */ + ctx = sde_hw_rotator_get_ctx(rot, entry->item.session_id, + entry->item.sequence_id, hw->wb_id); + if (!ctx) { + SDEROT_ERR("Cannot locate rotator ctx from sesison id:%d\n", + entry->item.session_id); + return -EINVAL; + } + + ret = rot->ops.wait_rotator_done(ctx, ctx->q_id, 0); + + if (rot->dbgmem) { + sde_hw_rotator_unmap_vaddr(&ctx->src_dbgbuf); + sde_hw_rotator_unmap_vaddr(&ctx->dst_dbgbuf); + } + + /* Current rotator context job is finished, time to free up*/ + sde_hw_rotator_free_rotctx(rot, ctx); + + return ret; +} + +/* + * sde_rotator_hw_rev_init - setup feature and/or capability bitmask + * @rot: Pointer to hw rotator + * + * This function initializes feature and/or capability bitmask based on + * h/w version read from the device. + */ +static int sde_rotator_hw_rev_init(struct sde_hw_rotator *rot) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + u32 hw_version; + + if (!mdata) { + SDEROT_ERR("null rotator data\n"); + return -EINVAL; + } + + hw_version = SDE_ROTREG_READ(rot->mdss_base, ROTTOP_HW_VERSION); + SDEROT_DBG("hw version %8.8x\n", hw_version); + + clear_bit(SDE_QOS_PER_PIPE_IB, mdata->sde_qos_map); + set_bit(SDE_QOS_OVERHEAD_FACTOR, mdata->sde_qos_map); + set_bit(SDE_QOS_OTLIM, mdata->sde_qos_map); + set_bit(SDE_QOS_PER_PIPE_LUT, mdata->sde_qos_map); + clear_bit(SDE_QOS_SIMPLIFIED_PREFILL, mdata->sde_qos_map); + + set_bit(SDE_CAPS_R3_WB, mdata->sde_caps_map); + + /* features exposed via rotator top h/w version */ + if (hw_version != SDE_ROT_TYPE_V1_0) { + SDEROT_DBG("Supporting 1.5 downscale for SDE Rotator\n"); + set_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map); + } + + set_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU, mdata->sde_caps_map); + + mdata->nrt_vbif_dbg_bus = nrt_vbif_dbg_bus_r3; + mdata->nrt_vbif_dbg_bus_size = + ARRAY_SIZE(nrt_vbif_dbg_bus_r3); + + mdata->rot_dbg_bus = rot_dbgbus_r3; + mdata->rot_dbg_bus_size = ARRAY_SIZE(rot_dbgbus_r3); + + mdata->regdump = sde_rot_r3_regdump; + mdata->regdump_size = ARRAY_SIZE(sde_rot_r3_regdump); + SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG, 0); + + /* features exposed via mdss h/w version */ + if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, SDE_MDP_HW_REV_600)) { + SDEROT_DBG("Supporting sys cache inline rotation\n"); + set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map); + set_bit(SDE_CAPS_UBWC_4, mdata->sde_caps_map); + set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); + set_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map); + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_inpixfmts_sbuf; + rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf); + rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_outpixfmts_sbuf; + rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf); + rot->downscale_caps = + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_500)) { + SDEROT_DBG("Supporting sys cache inline rotation\n"); + set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map); + set_bit(SDE_CAPS_UBWC_3, mdata->sde_caps_map); + set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); + set_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map); + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_inpixfmts_sbuf; + rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf); + rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_outpixfmts_sbuf; + rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf); + rot->downscale_caps = + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_530) || + IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_520)) { + SDEROT_DBG("Supporting sys cache inline rotation\n"); + set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map); + set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map); + set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); + set_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map); + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_inpixfmts_sbuf; + rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf); + rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_outpixfmts_sbuf; + rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf); + rot->downscale_caps = + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_540)) { + SDEROT_DBG("Sys cache inline rotation not supported\n"); + set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map); + set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); + set_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map); + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + rot->downscale_caps = + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_400) || + IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_410)) { + SDEROT_DBG("Supporting sys cache inline rotation\n"); + set_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map); + set_bit(SDE_CAPS_UBWC_2, mdata->sde_caps_map); + set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + rot->inpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_inpixfmts_sbuf; + rot->num_inpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts_sbuf); + rot->outpixfmts[SDE_ROTATOR_MODE_SBUF] = + sde_hw_rotator_v4_outpixfmts_sbuf; + rot->num_outpixfmt[SDE_ROTATOR_MODE_SBUF] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts_sbuf); + rot->downscale_caps = + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } else if (IS_SDE_MAJOR_MINOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_630)) { + SDEROT_DBG("Sys cache inline rotation not supported\n"); + set_bit(SDE_CAPS_PARTIALWR, mdata->sde_caps_map); + set_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map); + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v4_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v4_outpixfmts); + rot->downscale_caps = + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } else { + rot->inpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v3_inpixfmts; + rot->num_inpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v3_inpixfmts); + rot->outpixfmts[SDE_ROTATOR_MODE_OFFLINE] = + sde_hw_rotator_v3_outpixfmts; + rot->num_outpixfmt[SDE_ROTATOR_MODE_OFFLINE] = + ARRAY_SIZE(sde_hw_rotator_v3_outpixfmts); + rot->downscale_caps = (hw_version == SDE_ROT_TYPE_V1_0) ? + "LINEAR/2/4/8/16/32/64 TILE/2/4 TP10/2" : + "LINEAR/1.5/2/4/8/16/32/64 TILE/1.5/2/4 TP10/1.5/2"; + } + + return 0; +} + +/* + * sde_hw_rotator_validate_entry - validate rotation entry + * @mgr: Pointer to rotator manager + * @entry: Pointer to rotation entry + * + * This function validates the given rotation entry and provides possible + * fixup (future improvement) if available. This function returns 0 if + * the entry is valid, and returns error code otherwise. + */ +static int sde_hw_rotator_validate_entry(struct sde_rot_mgr *mgr, + struct sde_rot_entry *entry) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_hw_rotator *hw_data; + int ret = 0; + u16 src_w, src_h, dst_w, dst_h; + struct sde_rotation_item *item = &entry->item; + struct sde_mdp_format_params *fmt; + + if (!mgr || !entry || !mgr->hw_data) { + SDEROT_ERR("invalid parameters\n"); + return -EINVAL; + } + + hw_data = mgr->hw_data; + + if (hw_data->maxlinewidth < item->src_rect.w) { + SDEROT_ERR("invalid src width %u\n", item->src_rect.w); + return -EINVAL; + } + + src_w = item->src_rect.w; + src_h = item->src_rect.h; + + if (item->flags & SDE_ROTATION_90) { + dst_w = item->dst_rect.h; + dst_h = item->dst_rect.w; + } else { + dst_w = item->dst_rect.w; + dst_h = item->dst_rect.h; + } + + entry->dnsc_factor_w = 0; + entry->dnsc_factor_h = 0; + + if (item->output.sbuf && + !test_bit(SDE_CAPS_SBUF_1, mdata->sde_caps_map)) { + SDEROT_ERR("stream buffer not supported\n"); + return -EINVAL; + } + + if ((src_w != dst_w) || (src_h != dst_h)) { + if (!dst_w || !dst_h) { + SDEROT_DBG("zero output width/height not support\n"); + ret = -EINVAL; + goto dnsc_err; + } + if ((src_w % dst_w) || (src_h % dst_h)) { + SDEROT_DBG("non integral scale not support\n"); + ret = -EINVAL; + goto dnsc_1p5_check; + } + entry->dnsc_factor_w = src_w / dst_w; + if ((entry->dnsc_factor_w & (entry->dnsc_factor_w - 1)) || + (entry->dnsc_factor_w > 64)) { + SDEROT_DBG("non power-of-2 w_scale not support\n"); + ret = -EINVAL; + goto dnsc_err; + } + entry->dnsc_factor_h = src_h / dst_h; + if ((entry->dnsc_factor_h & (entry->dnsc_factor_h - 1)) || + (entry->dnsc_factor_h > 64)) { + SDEROT_DBG("non power-of-2 h_scale not support\n"); + ret = -EINVAL; + goto dnsc_err; + } + } + + fmt = sde_get_format_params(item->output.format); + /* + * Rotator downscale support max 4 times for UBWC format and + * max 2 times for TP10/TP10_UBWC format + */ + if (sde_mdp_is_ubwc_format(fmt) && (entry->dnsc_factor_h > 4)) { + SDEROT_DBG("max downscale for UBWC format is 4\n"); + ret = -EINVAL; + goto dnsc_err; + } + if (sde_mdp_is_tp10_format(fmt) && (entry->dnsc_factor_h > 2)) { + SDEROT_DBG("downscale with TP10 cannot be more than 2\n"); + ret = -EINVAL; + } + goto dnsc_err; + +dnsc_1p5_check: + /* Check for 1.5 downscale that only applies to V2 HW */ + if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map)) { + entry->dnsc_factor_w = src_w / dst_w; + if ((entry->dnsc_factor_w != 1) || + ((dst_w * 3) != (src_w * 2))) { + SDEROT_DBG( + "No supporting non 1.5 downscale width ratio, src_w:%d, dst_w:%d\n", + src_w, dst_w); + ret = -EINVAL; + goto dnsc_err; + } + + entry->dnsc_factor_h = src_h / dst_h; + if ((entry->dnsc_factor_h != 1) || + ((dst_h * 3) != (src_h * 2))) { + SDEROT_DBG( + "Not supporting non 1.5 downscale height ratio, src_h:%d, dst_h:%d\n", + src_h, dst_h); + ret = -EINVAL; + goto dnsc_err; + } + ret = 0; + } + +dnsc_err: + /* Downscaler does not support asymmetrical dnsc */ + if (entry->dnsc_factor_w != entry->dnsc_factor_h) { + SDEROT_DBG("asymmetric downscale not support\n"); + ret = -EINVAL; + } + + if (ret) { + entry->dnsc_factor_w = 0; + entry->dnsc_factor_h = 0; + } + return ret; +} + +/* + * sde_hw_rotator_show_caps - output capability info to sysfs 'caps' file + * @mgr: Pointer to rotator manager + * @attr: Pointer to device attribute interface + * @buf: Pointer to output buffer + * @len: Length of output buffer + */ +static ssize_t sde_hw_rotator_show_caps(struct sde_rot_mgr *mgr, + struct device_attribute *attr, char *buf, ssize_t len) +{ + struct sde_hw_rotator *hw_data; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int cnt = 0; + + if (!mgr || !buf) + return 0; + + hw_data = mgr->hw_data; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + /* insert capabilities here */ + if (test_bit(SDE_CAPS_R3_1P5_DOWNSCALE, mdata->sde_caps_map)) + SPRINT("min_downscale=1.5\n"); + else + SPRINT("min_downscale=2.0\n"); + + SPRINT("downscale_compression=1\n"); + + if (hw_data->downscale_caps) + SPRINT("downscale_ratios=%s\n", hw_data->downscale_caps); + + SPRINT("max_line_width=%d\n", sde_rotator_get_maxlinewidth(mgr)); + +#undef SPRINT + return cnt; +} + +/* + * sde_hw_rotator_show_state - output state info to sysfs 'state' file + * @mgr: Pointer to rotator manager + * @attr: Pointer to device attribute interface + * @buf: Pointer to output buffer + * @len: Length of output buffer + */ +static ssize_t sde_hw_rotator_show_state(struct sde_rot_mgr *mgr, + struct device_attribute *attr, char *buf, ssize_t len) +{ + struct sde_hw_rotator *rot; + struct sde_hw_rotator_context *ctx; + int cnt = 0; + int num_active = 0; + int i, j; + + if (!mgr || !buf) { + SDEROT_ERR("null parameters\n"); + return 0; + } + + rot = mgr->hw_data; + +#define SPRINT(fmt, ...) \ + (cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__)) + + if (rot) { + SPRINT("rot_mode=%d\n", rot->mode); + SPRINT("irq_num=%d\n", rot->irq_num); + + if (rot->mode == ROT_REGDMA_OFF) { + SPRINT("max_active=1\n"); + SPRINT("num_active=%d\n", rot->rotCtx[0][0] ? 1 : 0); + } else { + for (i = 0; i < ROT_QUEUE_MAX; i++) { + for (j = 0; j < SDE_HW_ROT_REGDMA_TOTAL_CTX; + j++) { + ctx = rot->rotCtx[i][j]; + + if (ctx) { + SPRINT( + "rotCtx[%d][%d]:%pK\n", + i, j, ctx); + ++num_active; + } + } + } + + SPRINT("max_active=%d\n", SDE_HW_ROT_REGDMA_TOTAL_CTX); + SPRINT("num_active=%d\n", num_active); + } + } + +#undef SPRINT + return cnt; +} + +/* + * sde_hw_rotator_get_pixfmt - get the indexed pixel format + * @mgr: Pointer to rotator manager + * @index: index of pixel format + * @input: true for input port; false for output port + * @mode: operating mode + */ +static u32 sde_hw_rotator_get_pixfmt(struct sde_rot_mgr *mgr, + int index, bool input, u32 mode) +{ + struct sde_hw_rotator *rot; + + if (!mgr || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return 0; + } + + rot = mgr->hw_data; + + if (mode >= SDE_ROTATOR_MODE_MAX) { + SDEROT_ERR("invalid rotator mode %d\n", mode); + return 0; + } + + if (input) { + if ((index < rot->num_inpixfmt[mode]) && rot->inpixfmts[mode]) + return rot->inpixfmts[mode][index]; + else + return 0; + } else { + if ((index < rot->num_outpixfmt[mode]) && rot->outpixfmts[mode]) + return rot->outpixfmts[mode][index]; + else + return 0; + } +} + +/* + * sde_hw_rotator_is_valid_pixfmt - verify if the given pixel format is valid + * @mgr: Pointer to rotator manager + * @pixfmt: pixel format to be verified + * @input: true for input port; false for output port + * @mode: operating mode + */ +static int sde_hw_rotator_is_valid_pixfmt(struct sde_rot_mgr *mgr, u32 pixfmt, + bool input, u32 mode) +{ + struct sde_hw_rotator *rot; + const u32 *pixfmts; + u32 num_pixfmt; + int i; + + if (!mgr || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return false; + } + + rot = mgr->hw_data; + + if (mode >= SDE_ROTATOR_MODE_MAX) { + SDEROT_ERR("invalid rotator mode %d\n", mode); + return false; + } + + if (input) { + pixfmts = rot->inpixfmts[mode]; + num_pixfmt = rot->num_inpixfmt[mode]; + } else { + pixfmts = rot->outpixfmts[mode]; + num_pixfmt = rot->num_outpixfmt[mode]; + } + + if (!pixfmts || !num_pixfmt) { + SDEROT_ERR("invalid pixel format tables\n"); + return false; + } + + for (i = 0; i < num_pixfmt; i++) + if (pixfmts[i] == pixfmt) + return true; + + return false; +} + +/* + * sde_hw_rotator_get_downscale_caps - get scaling capability string + * @mgr: Pointer to rotator manager + * @caps: Pointer to capability string buffer; NULL to return maximum length + * @len: length of capability string buffer + * return: length of capability string + */ +static int sde_hw_rotator_get_downscale_caps(struct sde_rot_mgr *mgr, + char *caps, int len) +{ + struct sde_hw_rotator *rot; + int rc = 0; + + if (!mgr || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + rot = mgr->hw_data; + + if (rot->downscale_caps) { + if (caps) + rc = snprintf(caps, len, "%s", rot->downscale_caps); + else + rc = strlen(rot->downscale_caps); + } + + return rc; +} + +/* + * sde_hw_rotator_get_maxlinewidth - get maximum line width supported + * @mgr: Pointer to rotator manager + * return: maximum line width supported by hardware + */ +static int sde_hw_rotator_get_maxlinewidth(struct sde_rot_mgr *mgr) +{ + struct sde_hw_rotator *rot; + + if (!mgr || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return -EINVAL; + } + + rot = mgr->hw_data; + + return rot->maxlinewidth; +} + +/* + * sde_hw_rotator_dump_status - dump status to debug output + * @mgr: Pointer to rotator manager + * return: none + */ +static void sde_hw_rotator_dump_status(struct sde_rot_mgr *mgr) +{ + if (!mgr || !mgr->hw_data) { + SDEROT_ERR("null parameters\n"); + return; + } + + _sde_hw_rotator_dump_status(mgr->hw_data, NULL); +} + +/* + * sde_hw_rotator_parse_dt - parse r3 specific device tree settings + * @hw_data: Pointer to rotator hw + * @dev: Pointer to platform device + */ +static int sde_hw_rotator_parse_dt(struct sde_hw_rotator *hw_data, + struct platform_device *dev) +{ + int ret = 0; + u32 data; + + if (!hw_data || !dev) + return -EINVAL; + + ret = of_property_read_u32(dev->dev.of_node, "qcom,mdss-rot-mode", + &data); + if (ret) { + SDEROT_DBG("default to regdma off\n"); + ret = 0; + hw_data->mode = ROT_REGDMA_OFF; + } else if (data < ROT_REGDMA_MAX) { + SDEROT_DBG("set to regdma mode %d\n", data); + hw_data->mode = data; + } else { + SDEROT_ERR("regdma mode out of range. default to regdma off\n"); + hw_data->mode = ROT_REGDMA_OFF; + } + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,mdss-highest-bank-bit", &data); + if (ret) { + SDEROT_DBG("default to A5X bank\n"); + ret = 0; + hw_data->highest_bank = 2; + } else { + SDEROT_DBG("set highest bank bit to %d\n", data); + hw_data->highest_bank = data; + } + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,sde-ubwc-malsize", &data); + if (ret) { + ret = 0; + hw_data->ubwc_malsize = DEFAULT_UBWC_MALSIZE; + } else { + SDEROT_DBG("set ubwc malsize to %d\n", data); + hw_data->ubwc_malsize = data; + } + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,sde-ubwc_swizzle", &data); + if (ret) { + ret = 0; + hw_data->ubwc_swizzle = DEFAULT_UBWC_SWIZZLE; + } else { + SDEROT_DBG("set ubwc swizzle to %d\n", data); + hw_data->ubwc_swizzle = data; + } + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,mdss-sbuf-headroom", &data); + if (ret) { + ret = 0; + hw_data->sbuf_headroom = DEFAULT_SBUF_HEADROOM; + } else { + SDEROT_DBG("set sbuf headroom to %d\n", data); + hw_data->sbuf_headroom = data; + } + + ret = of_property_read_u32(dev->dev.of_node, + "qcom,mdss-rot-linewidth", &data); + if (ret) { + ret = 0; + hw_data->maxlinewidth = DEFAULT_MAXLINEWIDTH; + } else { + SDEROT_DBG("set mdss-rot-linewidth to %d\n", data); + hw_data->maxlinewidth = data; + } + + return ret; +} + +/* + * sde_rotator_r3_init - initialize the r3 module + * @mgr: Pointer to rotator manager + * + * This function setup r3 callback functions, parses r3 specific + * device tree settings, installs r3 specific interrupt handler, + * as well as initializes r3 internal data structure. + */ +int sde_rotator_r3_init(struct sde_rot_mgr *mgr) +{ + struct sde_hw_rotator *rot; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int i; + int ret; + + rot = devm_kzalloc(&mgr->pdev->dev, sizeof(*rot), GFP_KERNEL); + if (!rot) + return -ENOMEM; + + mgr->hw_data = rot; + mgr->queue_count = ROT_QUEUE_MAX; + + rot->mdss_base = mdata->sde_io.base; + rot->pdev = mgr->pdev; + rot->koff_timeout = KOFF_TIMEOUT; + rot->vid_trigger = ROTTOP_START_CTRL_TRIG_SEL_MDP; + rot->cmd_trigger = ROTTOP_START_CTRL_TRIG_SEL_MDP; + + /* Assign ops */ + mgr->ops_hw_destroy = sde_hw_rotator_destroy; + mgr->ops_hw_alloc = sde_hw_rotator_alloc_ext; + mgr->ops_hw_free = sde_hw_rotator_free_ext; + mgr->ops_config_hw = sde_hw_rotator_config; + mgr->ops_cancel_hw = sde_hw_rotator_cancel; + mgr->ops_abort_hw = sde_hw_rotator_abort_kickoff; + mgr->ops_kickoff_entry = sde_hw_rotator_kickoff; + mgr->ops_wait_for_entry = sde_hw_rotator_wait4done; + mgr->ops_hw_validate_entry = sde_hw_rotator_validate_entry; + mgr->ops_hw_show_caps = sde_hw_rotator_show_caps; + mgr->ops_hw_show_state = sde_hw_rotator_show_state; + mgr->ops_hw_create_debugfs = sde_rotator_r3_create_debugfs; + mgr->ops_hw_get_pixfmt = sde_hw_rotator_get_pixfmt; + mgr->ops_hw_is_valid_pixfmt = sde_hw_rotator_is_valid_pixfmt; + mgr->ops_hw_pre_pmevent = sde_hw_rotator_pre_pmevent; + mgr->ops_hw_post_pmevent = sde_hw_rotator_post_pmevent; + mgr->ops_hw_get_downscale_caps = sde_hw_rotator_get_downscale_caps; + mgr->ops_hw_get_maxlinewidth = sde_hw_rotator_get_maxlinewidth; + mgr->ops_hw_dump_status = sde_hw_rotator_dump_status; + + ret = sde_hw_rotator_parse_dt(mgr->hw_data, mgr->pdev); + if (ret) + goto error_parse_dt; + + rot->irq_num = -EINVAL; + atomic_set(&rot->irq_enabled, 0); + + ret = sde_rotator_hw_rev_init(rot); + if (ret) + goto error_hw_rev_init; + + setup_rotator_ops(&rot->ops, rot->mode, + test_bit(SDE_CAPS_HW_TIMESTAMP, mdata->sde_caps_map)); + + spin_lock_init(&rot->rotctx_lock); + spin_lock_init(&rot->rotisr_lock); + + /* REGDMA initialization */ + if (rot->mode == ROT_REGDMA_OFF) { + for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++) + rot->cmd_wr_ptr[0][i] = (char __iomem *)( + &rot->cmd_queue[ + SDE_HW_ROT_REGDMA_SEG_SIZE * i]); + } else { + for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++) + rot->cmd_wr_ptr[ROT_QUEUE_HIGH_PRIORITY][i] = + rot->mdss_base + + REGDMA_RAM_REGDMA_CMD_RAM + + SDE_HW_ROT_REGDMA_SEG_SIZE * 4 * i; + + for (i = 0; i < SDE_HW_ROT_REGDMA_TOTAL_CTX; i++) + rot->cmd_wr_ptr[ROT_QUEUE_LOW_PRIORITY][i] = + rot->mdss_base + + REGDMA_RAM_REGDMA_CMD_RAM + + SDE_HW_ROT_REGDMA_SEG_SIZE * 4 * + (i + SDE_HW_ROT_REGDMA_TOTAL_CTX); + } + + for (i = 0; i < ROT_QUEUE_MAX; i++) { + atomic_set(&rot->timestamp[i], 0); + INIT_LIST_HEAD(&rot->sbuf_ctx[i]); + } + + /* set rotator CBCR to shutoff memory/periphery on clock off.*/ + clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_MDSS_ROT].clk, + CLKFLAG_NORETAIN_MEM); + clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_MDSS_ROT].clk, + CLKFLAG_NORETAIN_PERIPH); + + mdata->sde_rot_hw = rot; + return 0; +error_hw_rev_init: + devm_kfree(&mgr->pdev->dev, mgr->hw_data); +error_parse_dt: + return ret; +} diff --git a/techpack/display/rotator/sde_rotator_r3.h b/techpack/display/rotator/sde_rotator_r3.h new file mode 100644 index 0000000000000000000000000000000000000000..de7b6139b4459e940e3435f11a6794cf8ff59afd --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r3.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_R3_H__ +#define __SDE_ROTATOR_R3_H__ + +#include "sde_rotator_core.h" + +/* Maximum allowed Rotator clock value */ +#define ROT_R3_MAX_ROT_CLK 345000000 + +int sde_rotator_r3_init(struct sde_rot_mgr *mgr); + +#endif /* __SDE_ROTATOR_R3_H__ */ diff --git a/techpack/display/rotator/sde_rotator_r3_debug.c b/techpack/display/rotator/sde_rotator_r3_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..d2060afb0fae7b59284724a8ade01dd674eded37 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r3_debug.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> + +#include "sde_rotator_r3_debug.h" +#include "sde_rotator_core.h" +#include "sde_rotator_r3.h" +#include "sde_rotator_r3_internal.h" + +/* + * sde_rotator_r3_create_debugfs - Setup rotator r3 debugfs directory structure. + * @rot_dev: Pointer to rotator device + */ +int sde_rotator_r3_create_debugfs(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + struct sde_hw_rotator *hw_data; + + if (!mgr || !debugfs_root || !mgr->hw_data) + return -EINVAL; + + hw_data = mgr->hw_data; + + if (!debugfs_create_bool("dbgmem", 0644, + debugfs_root, &hw_data->dbgmem)) { + SDEROT_ERR("fail create dbgmem\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("koff_timeout", 0644, + debugfs_root, &hw_data->koff_timeout)) { + SDEROT_ERR("fail create koff_timeout\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("vid_trigger", 0644, + debugfs_root, &hw_data->vid_trigger)) { + SDEROT_ERR("fail create vid_trigger\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("cmd_trigger", 0644, + debugfs_root, &hw_data->cmd_trigger)) { + SDEROT_ERR("fail create cmd_trigger\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("sbuf_headroom", 0644, + debugfs_root, &hw_data->sbuf_headroom)) { + SDEROT_ERR("fail create sbuf_headroom\n"); + return -EINVAL; + } + + if (!debugfs_create_u32("solid_fill", 0644, + debugfs_root, &hw_data->solid_fill)) { + SDEROT_ERR("fail create solid_fill\n"); + return -EINVAL; + } + + return 0; +} diff --git a/techpack/display/rotator/sde_rotator_r3_debug.h b/techpack/display/rotator/sde_rotator_r3_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..eef53979fbb28edce9dffbebad1618022b061aa7 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r3_debug.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_R3_DEBUG_H__ +#define __SDE_ROTATOR_R3_DEBUG_H__ + +#include <linux/types.h> +#include <linux/dcache.h> + +struct sde_rot_mgr; + +#if defined(CONFIG_DEBUG_FS) +int sde_rotator_r3_create_debugfs(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root); +#else +static inline +int sde_rotator_r3_create_debugfs(struct sde_rot_mgr *mgr, + struct dentry *debugfs_root) +{ + return 0; +} +#endif +#endif /* __SDE_ROTATOR_R3_DEBUG_H__ */ diff --git a/techpack/display/rotator/sde_rotator_r3_hwio.h b/techpack/display/rotator/sde_rotator_r3_hwio.h new file mode 100644 index 0000000000000000000000000000000000000000..70a5206979cfde805784624740b2c2cbb7b4d1d2 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r3_hwio.h @@ -0,0 +1,305 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_ROTATOR_R3_HWIO_H +#define _SDE_ROTATOR_R3_HWIO_H + +#include <linux/bitops.h> + +/* MMSS_MDSS: + * OFFSET=0x000000 + */ +#define MMSS_MDSS_HW_INTR_STATUS 0x10 +#define MMSS_MDSS_HW_INTR_STATUS_ROT BIT(2) + +/* SDE_ROT_ROTTOP: + * OFFSET=0x0A8800 + */ +#define SDE_ROT_ROTTOP_OFFSET 0xA8800 +#define ROTTOP_HW_VERSION (SDE_ROT_ROTTOP_OFFSET+0x00) +#define ROTTOP_CLK_CTRL (SDE_ROT_ROTTOP_OFFSET+0x10) +#define ROTTOP_CLK_STATUS (SDE_ROT_ROTTOP_OFFSET+0x14) +#define ROTTOP_ROT_NEWROI_PRIOR_TO_START (SDE_ROT_ROTTOP_OFFSET+0x18) +#define ROTTOP_SW_RESET (SDE_ROT_ROTTOP_OFFSET+0x20) +#define ROTTOP_SW_RESET_CTRL (SDE_ROT_ROTTOP_OFFSET+0x24) +#define ROTTOP_SW_RESET_OVERRIDE (SDE_ROT_ROTTOP_OFFSET+0x28) +#define ROTTOP_INTR_EN (SDE_ROT_ROTTOP_OFFSET+0x30) +#define ROTTOP_INTR_STATUS (SDE_ROT_ROTTOP_OFFSET+0x34) +#define ROTTOP_INTR_CLEAR (SDE_ROT_ROTTOP_OFFSET+0x38) +#define ROTTOP_START_CTRL (SDE_ROT_ROTTOP_OFFSET+0x40) +#define ROTTOP_STATUS (SDE_ROT_ROTTOP_OFFSET+0x44) +#define ROTTOP_OP_MODE (SDE_ROT_ROTTOP_OFFSET+0x48) +#define ROTTOP_DNSC (SDE_ROT_ROTTOP_OFFSET+0x4C) +#define ROTTOP_DEBUGBUS_CTRL (SDE_ROT_ROTTOP_OFFSET+0x50) +#define ROTTOP_DEBUGBUS_STATUS (SDE_ROT_ROTTOP_OFFSET+0x54) +#define ROTTOP_ROT_UBWC_DEC_VERSION (SDE_ROT_ROTTOP_OFFSET+0x58) +#define ROTTOP_ROT_UBWC_ENC_VERSION (SDE_ROT_ROTTOP_OFFSET+0x5C) +#define ROTTOP_ROT_CNTR_CTRL (SDE_ROT_ROTTOP_OFFSET+0x60) +#define ROTTOP_ROT_CNTR_0 (SDE_ROT_ROTTOP_OFFSET+0x64) +#define ROTTOP_ROT_CNTR_1 (SDE_ROT_ROTTOP_OFFSET+0x68) +#define ROTTOP_ROT_SCRATCH_0 (SDE_ROT_ROTTOP_OFFSET+0x70) +#define ROTTOP_ROT_SCRATCH_1 (SDE_ROT_ROTTOP_OFFSET+0x74) +#define ROTTOP_ROT_SCRATCH_2 (SDE_ROT_ROTTOP_OFFSET+0x78) +#define ROTTOP_ROT_SCRATCH_3 (SDE_ROT_ROTTOP_OFFSET+0x7C) + +#define ROTTOP_START_CTRL_TRIG_SEL_SW 0 +#define ROTTOP_START_CTRL_TRIG_SEL_DONE 1 +#define ROTTOP_START_CTRL_TRIG_SEL_REGDMA 2 +#define ROTTOP_START_CTRL_TRIG_SEL_MDP 3 + +#define ROTTOP_OP_MODE_ROT_OUT_MASK (0x3 << 4) + +/* SDE_ROT_SSPP: + * OFFSET=0x0A8900 + */ +#define SDE_ROT_SSPP_OFFSET 0xA8900 +#define ROT_SSPP_SRC_SIZE (SDE_ROT_SSPP_OFFSET+0x00) +#define ROT_SSPP_SRC_IMG_SIZE (SDE_ROT_SSPP_OFFSET+0x04) +#define ROT_SSPP_SRC_XY (SDE_ROT_SSPP_OFFSET+0x08) +#define ROT_SSPP_OUT_SIZE (SDE_ROT_SSPP_OFFSET+0x0C) +#define ROT_SSPP_OUT_XY (SDE_ROT_SSPP_OFFSET+0x10) +#define ROT_SSPP_SRC0_ADDR (SDE_ROT_SSPP_OFFSET+0x14) +#define ROT_SSPP_SRC1_ADDR (SDE_ROT_SSPP_OFFSET+0x18) +#define ROT_SSPP_SRC2_ADDR (SDE_ROT_SSPP_OFFSET+0x1C) +#define ROT_SSPP_SRC3_ADDR (SDE_ROT_SSPP_OFFSET+0x20) +#define ROT_SSPP_SRC_YSTRIDE0 (SDE_ROT_SSPP_OFFSET+0x24) +#define ROT_SSPP_SRC_YSTRIDE1 (SDE_ROT_SSPP_OFFSET+0x28) +#define ROT_SSPP_TILE_FRAME_SIZE (SDE_ROT_SSPP_OFFSET+0x2C) +#define ROT_SSPP_SRC_FORMAT (SDE_ROT_SSPP_OFFSET+0x30) +#define ROT_SSPP_SRC_UNPACK_PATTERN (SDE_ROT_SSPP_OFFSET+0x34) +#define ROT_SSPP_SRC_OP_MODE (SDE_ROT_SSPP_OFFSET+0x38) +#define ROT_SSPP_SRC_CONSTANT_COLOR (SDE_ROT_SSPP_OFFSET+0x3C) +#define ROT_SSPP_UBWC_STATIC_CTRL (SDE_ROT_SSPP_OFFSET+0x44) +#define ROT_SSPP_FETCH_CONFIG (SDE_ROT_SSPP_OFFSET+0x48) +#define ROT_SSPP_VC1_RANGE (SDE_ROT_SSPP_OFFSET+0x4C) +#define ROT_SSPP_REQPRIORITY_FIFO_WATERMARK_0 (SDE_ROT_SSPP_OFFSET+0x50) +#define ROT_SSPP_REQPRIORITY_FIFO_WATERMARK_1 (SDE_ROT_SSPP_OFFSET+0x54) +#define ROT_SSPP_REQPRIORITY_FIFO_WATERMARK_2 (SDE_ROT_SSPP_OFFSET+0x58) +#define ROT_SSPP_DANGER_LUT (SDE_ROT_SSPP_OFFSET+0x60) +#define ROT_SSPP_SAFE_LUT (SDE_ROT_SSPP_OFFSET+0x64) +#define ROT_SSPP_CREQ_LUT (SDE_ROT_SSPP_OFFSET+0x68) +#define ROT_SSPP_QOS_CTRL (SDE_ROT_SSPP_OFFSET+0x6C) +#define ROT_SSPP_SRC_ADDR_SW_STATUS (SDE_ROT_SSPP_OFFSET+0x70) +#define ROT_SSPP_CREQ_LUT_0 (SDE_ROT_SSPP_OFFSET+0x74) +#define ROT_SSPP_CREQ_LUT_1 (SDE_ROT_SSPP_OFFSET+0x78) +#define ROT_SSPP_CURRENT_SRC0_ADDR (SDE_ROT_SSPP_OFFSET+0xA4) +#define ROT_SSPP_CURRENT_SRC1_ADDR (SDE_ROT_SSPP_OFFSET+0xA8) +#define ROT_SSPP_CURRENT_SRC2_ADDR (SDE_ROT_SSPP_OFFSET+0xAC) +#define ROT_SSPP_CURRENT_SRC3_ADDR (SDE_ROT_SSPP_OFFSET+0xB0) +#define ROT_SSPP_DECIMATION_CONFIG (SDE_ROT_SSPP_OFFSET+0xB4) +#define ROT_SSPP_FETCH_SMP_WR_PLANE0 (SDE_ROT_SSPP_OFFSET+0xD0) +#define ROT_SSPP_FETCH_SMP_WR_PLANE1 (SDE_ROT_SSPP_OFFSET+0xD4) +#define ROT_SSPP_FETCH_SMP_WR_PLANE2 (SDE_ROT_SSPP_OFFSET+0xD8) +#define ROT_SSPP_SMP_UNPACK_RD_PLANE0 (SDE_ROT_SSPP_OFFSET+0xE0) +#define ROT_SSPP_SMP_UNPACK_RD_PLANE1 (SDE_ROT_SSPP_OFFSET+0xE4) +#define ROT_SSPP_SMP_UNPACK_RD_PLANE2 (SDE_ROT_SSPP_OFFSET+0xE8) +#define ROT_SSPP_FILL_LEVELS (SDE_ROT_SSPP_OFFSET+0xF0) +#define ROT_SSPP_STATUS (SDE_ROT_SSPP_OFFSET+0xF4) +#define ROT_SSPP_UNPACK_LINE_COUNT (SDE_ROT_SSPP_OFFSET+0xF8) +#define ROT_SSPP_UNPACK_BLK_COUNT (SDE_ROT_SSPP_OFFSET+0xFC) +#define ROT_SSPP_SW_PIX_EXT_C0_LR (SDE_ROT_SSPP_OFFSET+0x100) +#define ROT_SSPP_SW_PIX_EXT_C0_TB (SDE_ROT_SSPP_OFFSET+0x104) +#define ROT_SSPP_SW_PIX_EXT_C0_REQ_PIXELS (SDE_ROT_SSPP_OFFSET+0x108) +#define ROT_SSPP_SW_PIX_EXT_C1C2_LR (SDE_ROT_SSPP_OFFSET+0x110) +#define ROT_SSPP_SW_PIX_EXT_C1C2_TB (SDE_ROT_SSPP_OFFSET+0x114) +#define ROT_SSPP_SW_PIX_EXT_C1C2_REQ_PIXELS (SDE_ROT_SSPP_OFFSET+0x118) +#define ROT_SSPP_SW_PIX_EXT_C3_LR (SDE_ROT_SSPP_OFFSET+0x120) +#define ROT_SSPP_SW_PIX_EXT_C3_TB (SDE_ROT_SSPP_OFFSET+0x124) +#define ROT_SSPP_SW_PIX_EXT_C3_REQ_PIXELS (SDE_ROT_SSPP_OFFSET+0x128) +#define ROT_SSPP_TRAFFIC_SHAPER (SDE_ROT_SSPP_OFFSET+0x130) +#define ROT_SSPP_CDP_CNTL (SDE_ROT_SSPP_OFFSET+0x134) +#define ROT_SSPP_UBWC_ERROR_STATUS (SDE_ROT_SSPP_OFFSET+0x138) +#define ROT_SSPP_SW_CROP_W_C0C3 (SDE_ROT_SSPP_OFFSET+0x140) +#define ROT_SSPP_SW_CROP_W_C1C2 (SDE_ROT_SSPP_OFFSET+0x144) +#define ROT_SSPP_SW_CROP_H_C0C3 (SDE_ROT_SSPP_OFFSET+0x148) +#define ROT_SSPP_SW_CROP_H_C1C2 (SDE_ROT_SSPP_OFFSET+0x14C) +#define ROT_SSPP_TRAFFIC_SHAPER_PREFILL (SDE_ROT_SSPP_OFFSET+0x150) +#define ROT_SSPP_TRAFFIC_SHAPER_REC1_PREFILL (SDE_ROT_SSPP_OFFSET+0x154) +#define ROT_SSPP_OUT_SIZE_REC1 (SDE_ROT_SSPP_OFFSET+0x160) +#define ROT_SSPP_OUT_XY_REC1 (SDE_ROT_SSPP_OFFSET+0x164) +#define ROT_SSPP_SRC_XY_REC1 (SDE_ROT_SSPP_OFFSET+0x168) +#define ROT_SSPP_SRC_SIZE_REC1 (SDE_ROT_SSPP_OFFSET+0x16C) +#define ROT_SSPP_MULTI_REC_OP_MODE (SDE_ROT_SSPP_OFFSET+0x170) +#define ROT_SSPP_SRC_FORMAT_REC1 (SDE_ROT_SSPP_OFFSET+0x174) +#define ROT_SSPP_SRC_UNPACK_PATTERN_REC1 (SDE_ROT_SSPP_OFFSET+0x178) +#define ROT_SSPP_SRC_OP_MODE_REC1 (SDE_ROT_SSPP_OFFSET+0x17C) +#define ROT_SSPP_SRC_CONSTANT_COLOR_REC1 (SDE_ROT_SSPP_OFFSET+0x180) +#define ROT_SSPP_TPG_CONTROL (SDE_ROT_SSPP_OFFSET+0x190) +#define ROT_SSPP_TPG_CONFIG (SDE_ROT_SSPP_OFFSET+0x194) +#define ROT_SSPP_TPG_COMPONENT_LIMITS (SDE_ROT_SSPP_OFFSET+0x198) +#define ROT_SSPP_TPG_RECTANGLE (SDE_ROT_SSPP_OFFSET+0x19C) +#define ROT_SSPP_TPG_BLACK_WHITE_PATTERN_FRAMES (SDE_ROT_SSPP_OFFSET+0x1A0) +#define ROT_SSPP_TPG_RGB_MAPPING (SDE_ROT_SSPP_OFFSET+0x1A4) +#define ROT_SSPP_TPG_PATTERN_GEN_INIT_VAL (SDE_ROT_SSPP_OFFSET+0x1A8) + +#define SDE_ROT_SSPP_FETCH_CONFIG_RESET_VALUE 0x00087 +#define SDE_ROT_SSPP_FETCH_BLOCKSIZE_128 (0 << 16) +#define SDE_ROT_SSPP_FETCH_BLOCKSIZE_96 (2 << 16) +#define SDE_ROT_SSPP_FETCH_BLOCKSIZE_192_EXT ((0 << 16) | (1 << 15)) +#define SDE_ROT_SSPP_FETCH_BLOCKSIZE_144_EXT ((2 << 16) | (1 << 15)) + + +/* SDE_ROT_WB: + * OFFSET=0x0A8B00 + */ +#define SDE_ROT_WB_OFFSET 0xA8B00 +#define ROT_WB_DST_FORMAT (SDE_ROT_WB_OFFSET+0x000) +#define ROT_WB_DST_OP_MODE (SDE_ROT_WB_OFFSET+0x004) +#define ROT_WB_DST_PACK_PATTERN (SDE_ROT_WB_OFFSET+0x008) +#define ROT_WB_DST0_ADDR (SDE_ROT_WB_OFFSET+0x00C) +#define ROT_WB_DST1_ADDR (SDE_ROT_WB_OFFSET+0x010) +#define ROT_WB_DST2_ADDR (SDE_ROT_WB_OFFSET+0x014) +#define ROT_WB_DST3_ADDR (SDE_ROT_WB_OFFSET+0x018) +#define ROT_WB_DST_YSTRIDE0 (SDE_ROT_WB_OFFSET+0x01C) +#define ROT_WB_DST_YSTRIDE1 (SDE_ROT_WB_OFFSET+0x020) +#define ROT_WB_DST_DITHER_BITDEPTH (SDE_ROT_WB_OFFSET+0x024) +#define ROT_WB_DITHER_MATRIX_ROW0 (SDE_ROT_WB_OFFSET+0x030) +#define ROT_WB_DITHER_MATRIX_ROW1 (SDE_ROT_WB_OFFSET+0x034) +#define ROT_WB_DITHER_MATRIX_ROW2 (SDE_ROT_WB_OFFSET+0x038) +#define ROT_WB_DITHER_MATRIX_ROW3 (SDE_ROT_WB_OFFSET+0x03C) +#define ROT_WB_TRAFFIC_SHAPER_WR_CLIENT (SDE_ROT_WB_OFFSET+0x040) +#define ROT_WB_DST_WRITE_CONFIG (SDE_ROT_WB_OFFSET+0x048) +#define ROT_WB_ROTATOR_PIPE_DOWNSCALER (SDE_ROT_WB_OFFSET+0x054) +#define ROT_WB_OUT_SIZE (SDE_ROT_WB_OFFSET+0x074) +#define ROT_WB_DST_ALPHA_X_VALUE (SDE_ROT_WB_OFFSET+0x078) +#define ROT_WB_HW_VERSION (SDE_ROT_WB_OFFSET+0x080) +#define ROT_WB_DANGER_LUT (SDE_ROT_WB_OFFSET+0x084) +#define ROT_WB_SAFE_LUT (SDE_ROT_WB_OFFSET+0x088) +#define ROT_WB_CREQ_LUT (SDE_ROT_WB_OFFSET+0x08C) +#define ROT_WB_QOS_CTRL (SDE_ROT_WB_OFFSET+0x090) +#define ROT_WB_SYS_CACHE_MODE (SDE_ROT_WB_OFFSET+0x094) +#define ROT_WB_CREQ_LUT_0 (SDE_ROT_WB_OFFSET+0x098) +#define ROT_WB_CREQ_LUT_1 (SDE_ROT_WB_OFFSET+0x09C) +#define ROT_WB_UBWC_STATIC_CTRL (SDE_ROT_WB_OFFSET+0x144) +#define ROT_WB_SBUF_STATUS_PLANE0 (SDE_ROT_WB_OFFSET+0x148) +#define ROT_WB_SBUF_STATUS_PLANE1 (SDE_ROT_WB_OFFSET+0x14C) +#define ROT_WB_CSC_MATRIX_COEFF_0 (SDE_ROT_WB_OFFSET+0x260) +#define ROT_WB_CSC_MATRIX_COEFF_1 (SDE_ROT_WB_OFFSET+0x264) +#define ROT_WB_CSC_MATRIX_COEFF_2 (SDE_ROT_WB_OFFSET+0x268) +#define ROT_WB_CSC_MATRIX_COEFF_3 (SDE_ROT_WB_OFFSET+0x26C) +#define ROT_WB_CSC_MATRIX_COEFF_4 (SDE_ROT_WB_OFFSET+0x270) +#define ROT_WB_CSC_COMP0_PRECLAMP (SDE_ROT_WB_OFFSET+0x274) +#define ROT_WB_CSC_COMP1_PRECLAMP (SDE_ROT_WB_OFFSET+0x278) +#define ROT_WB_CSC_COMP2_PRECLAMP (SDE_ROT_WB_OFFSET+0x27C) +#define ROT_WB_CSC_COMP0_POSTCLAMP (SDE_ROT_WB_OFFSET+0x280) +#define ROT_WB_CSC_COMP1_POSTCLAMP (SDE_ROT_WB_OFFSET+0x284) +#define ROT_WB_CSC_COMP2_POSTCLAMP (SDE_ROT_WB_OFFSET+0x288) +#define ROT_WB_CSC_COMP0_PREBIAS (SDE_ROT_WB_OFFSET+0x28C) +#define ROT_WB_CSC_COMP1_PREBIAS (SDE_ROT_WB_OFFSET+0x290) +#define ROT_WB_CSC_COMP2_PREBIAS (SDE_ROT_WB_OFFSET+0x294) +#define ROT_WB_CSC_COMP0_POSTBIAS (SDE_ROT_WB_OFFSET+0x298) +#define ROT_WB_CSC_COMP1_POSTBIAS (SDE_ROT_WB_OFFSET+0x29C) +#define ROT_WB_CSC_COMP2_POSTBIAS (SDE_ROT_WB_OFFSET+0x2A0) +#define ROT_WB_DST_ADDR_SW_STATUS (SDE_ROT_WB_OFFSET+0x2B0) +#define ROT_WB_CDP_CNTL (SDE_ROT_WB_OFFSET+0x2B4) +#define ROT_WB_STATUS (SDE_ROT_WB_OFFSET+0x2B8) +#define ROT_WB_UBWC_ERROR_STATUS (SDE_ROT_WB_OFFSET+0x2BC) +#define ROT_WB_OUT_IMG_SIZE (SDE_ROT_WB_OFFSET+0x2C0) +#define ROT_WB_OUT_XY (SDE_ROT_WB_OFFSET+0x2C4) + + +/* SDE_ROT_REGDMA_RAM: + * OFFSET=0x0A8E00 + */ +#define SDE_ROT_REGDMA_RAM_OFFSET 0xA8E00 +#define REGDMA_RAM_REGDMA_CMD_RAM (SDE_ROT_REGDMA_RAM_OFFSET+0x00) + + +/* SDE_ROT_REGDMA_CSR: + * OFFSET=0x0AAE00 + */ +#define SDE_ROT_REGDMA_OFFSET 0xAAE00 +#define REGDMA_CSR_REGDMA_VERSION (SDE_ROT_REGDMA_OFFSET+0x00) +#define REGDMA_CSR_REGDMA_OP_MODE (SDE_ROT_REGDMA_OFFSET+0x04) +#define REGDMA_CSR_REGDMA_QUEUE_0_SUBMIT (SDE_ROT_REGDMA_OFFSET+0x10) +#define REGDMA_CSR_REGDMA_QUEUE_0_STATUS (SDE_ROT_REGDMA_OFFSET+0x14) +#define REGDMA_CSR_REGDMA_QUEUE_1_SUBMIT (SDE_ROT_REGDMA_OFFSET+0x18) +#define REGDMA_CSR_REGDMA_QUEUE_1_STATUS (SDE_ROT_REGDMA_OFFSET+0x1C) +#define REGDMA_CSR_REGDMA_BLOCK_LO_0 (SDE_ROT_REGDMA_OFFSET+0x20) +#define REGDMA_CSR_REGDMA_BLOCK_HI_0 (SDE_ROT_REGDMA_OFFSET+0x24) +#define REGDMA_CSR_REGDMA_BLOCK_LO_1 (SDE_ROT_REGDMA_OFFSET+0x28) +#define REGDMA_CSR_REGDMA_BLOCK_HI_1 (SDE_ROT_REGDMA_OFFSET+0x2C) +#define REGDMA_CSR_REGDMA_BLOCK_LO_2 (SDE_ROT_REGDMA_OFFSET+0x30) +#define REGDMA_CSR_REGDMA_BLOCK_HI_2 (SDE_ROT_REGDMA_OFFSET+0x34) +#define REGDMA_CSR_REGDMA_BLOCK_LO_3 (SDE_ROT_REGDMA_OFFSET+0x38) +#define REGDMA_CSR_REGDMA_BLOCK_HI_3 (SDE_ROT_REGDMA_OFFSET+0x3C) +#define REGDMA_CSR_REGDMA_WD_TIMER_CTL (SDE_ROT_REGDMA_OFFSET+0x40) +#define REGDMA_CSR_REGDMA_WD_TIMER_CTL2 (SDE_ROT_REGDMA_OFFSET+0x44) +#define REGDMA_CSR_REGDMA_WD_TIMER_LOAD_VALUE (SDE_ROT_REGDMA_OFFSET+0x48) +#define REGDMA_CSR_REGDMA_WD_TIMER_STATUS_VALUE (SDE_ROT_REGDMA_OFFSET+0x4C) +#define REGDMA_CSR_REGDMA_INT_STATUS (SDE_ROT_REGDMA_OFFSET+0x50) +#define REGDMA_CSR_REGDMA_INT_EN (SDE_ROT_REGDMA_OFFSET+0x54) +#define REGDMA_CSR_REGDMA_INT_CLEAR (SDE_ROT_REGDMA_OFFSET+0x58) +#define REGDMA_CSR_REGDMA_BLOCK_STATUS (SDE_ROT_REGDMA_OFFSET+0x5C) +#define REGDMA_CSR_REGDMA_INVALID_CMD_RAM_OFFSET (SDE_ROT_REGDMA_OFFSET+0x60) +#define REGDMA_CSR_REGDMA_FSM_STATE (SDE_ROT_REGDMA_OFFSET+0x64) +#define REGDMA_CSR_REGDMA_DEBUG_SEL (SDE_ROT_REGDMA_OFFSET+0x68) + + +/* SDE_ROT_QDSS: + * OFFSET=0x0AAF00 + */ +#define ROT_QDSS_CONFIG 0x00 +#define ROT_QDSS_ATB_DATA_ENABLE0 0x04 +#define ROT_QDSS_ATB_DATA_ENABLE1 0x08 +#define ROT_QDSS_ATB_DATA_ENABLE2 0x0C +#define ROT_QDSS_ATB_DATA_ENABLE3 0x10 +#define ROT_QDSS_CLK_CTRL 0x14 +#define ROT_QDSS_CLK_STATUS 0x18 +#define ROT_QDSS_PULSE_TRIGGER 0x20 + +/* + * SDE_ROT_VBIF_NRT: + */ +#define SDE_ROT_VBIF_NRT_OFFSET 0 + +/* REGDMA OP Code */ +#define REGDMA_OP_NOP (0 << 28) +#define REGDMA_OP_REGWRITE (1 << 28) +#define REGDMA_OP_REGMODIFY (2 << 28) +#define REGDMA_OP_BLKWRITE_SINGLE (3 << 28) +#define REGDMA_OP_BLKWRITE_INC (4 << 28) +#define REGDMA_OP_MASK 0xF0000000 + +/* REGDMA ADDR offset Mask */ +#define REGDMA_ADDR_OFFSET_MASK 0xFFFFF + +/* REGDMA command trigger select */ +#define REGDMA_CMD_TRIG_SEL_SW_START (0 << 27) +#define REGDMA_CMD_TRIG_SEL_MDP_FLUSH (1 << 27) + +/* General defines */ +#define ROT_DONE_MASK 0x1 +#define ROT_DONE_CLEAR 0x1 +#define ROT_BUSY_BIT BIT(0) +#define ROT_ERROR_BIT BIT(8) +#define ROT_STATUS_MASK (ROT_BUSY_BIT | ROT_ERROR_BIT) +#define REGDMA_BUSY BIT(0) +#define REGDMA_EN 0x1 +#define REGDMA_SECURE_EN BIT(8) +#define REGDMA_HALT BIT(16) + +#define REGDMA_WATCHDOG_INT BIT(19) +#define REGDMA_INVALID_DESCRIPTOR BIT(18) +#define REGDMA_INCOMPLETE_CMD BIT(17) +#define REGDMA_INVALID_CMD BIT(16) +#define REGDMA_QUEUE1_INT2 BIT(10) +#define REGDMA_QUEUE1_INT1 BIT(9) +#define REGDMA_QUEUE1_INT0 BIT(8) +#define REGDMA_QUEUE0_INT2 BIT(2) +#define REGDMA_QUEUE0_INT1 BIT(1) +#define REGDMA_QUEUE0_INT0 BIT(0) +#define REGDMA_INT_MASK 0x000F0707 +#define REGDMA_INT_HIGH_MASK 0x00000007 +#define REGDMA_INT_LOW_MASK 0x00000700 +#define REGDMA_INT_ERR_MASK 0x000F0000 +#define REGDMA_TIMESTAMP_REG ROT_SSPP_TPG_PATTERN_GEN_INIT_VAL +#define REGDMA_RESET_STATUS_REG ROT_SSPP_TPG_RGB_MAPPING + +#define REGDMA_INT_0_MASK 0x101 +#define REGDMA_INT_1_MASK 0x202 +#define REGDMA_INT_2_MASK 0x404 + +#endif /*_SDE_ROTATOR_R3_HWIO_H */ diff --git a/techpack/display/rotator/sde_rotator_r3_internal.h b/techpack/display/rotator/sde_rotator_r3_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..7d99fd9ed43befd796ae3e59149e8e70307b0fe4 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_r3_internal.h @@ -0,0 +1,452 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef _SDE_ROTATOR_R3_INTERNAL_H +#define _SDE_ROTATOR_R3_INTERNAL_H + +#include "sde_rotator_core.h" + +struct sde_hw_rotator; +struct sde_hw_rotator_context; + +/** + * Flags + */ +#define SDE_ROT_FLAG_SECURE_OVERLAY_SESSION 0x1 +#define SDE_ROT_FLAG_FLIP_LR 0x2 +#define SDE_ROT_FLAG_FLIP_UD 0x4 +#define SDE_ROT_FLAG_SOURCE_ROTATED_90 0x8 +#define SDE_ROT_FLAG_ROT_90 0x10 +#define SDE_ROT_FLAG_DEINTERLACE 0x20 +#define SDE_ROT_FLAG_SECURE_CAMERA_SESSION 0x40 + +/** + * General defines + */ +#define SDE_HW_ROT_REGDMA_RAM_SIZE 1024 +#define SDE_HW_ROT_REGDMA_TOTAL_CTX 8 +#define SDE_HW_ROT_REGDMA_SEG_MASK (SDE_HW_ROT_REGDMA_TOTAL_CTX - 1) +#define SDE_HW_ROT_REGDMA_SEG_SIZE \ + (SDE_HW_ROT_REGDMA_RAM_SIZE / SDE_HW_ROT_REGDMA_TOTAL_CTX) +#define SDE_REGDMA_SWTS_MASK 0x00000FFF +#define SDE_REGDMA_SWTS_SHIFT 12 + +enum sde_rot_queue_prio { + ROT_QUEUE_HIGH_PRIORITY, + ROT_QUEUE_LOW_PRIORITY, + ROT_QUEUE_MAX +}; + +enum sde_rot_angle { + ROT_ANGLE_0, + ROT_ANGLE_90, + ROT_ANGEL_MAX +}; + +enum sde_rotator_regdma_mode { + ROT_REGDMA_OFF, + ROT_REGDMA_ON, + ROT_REGDMA_MAX +}; + +/** + * struct sde_hw_rot_sspp_cfg: Rotator SSPP Configration description + * @src: source surface information + * @src_rect: src ROI, caller takes into account the different operations + * such as decimation, flip etc to program this field + * @addr: source surface address + */ +struct sde_hw_rot_sspp_cfg { + struct sde_mdp_format_params *fmt; + struct sde_mdp_plane_sizes src_plane; + struct sde_rect *src_rect; + struct sde_mdp_data *data; + u32 img_width; + u32 img_height; + u32 fps; + u64 bw; +}; + + + +/** + * struct sde_hw_rot_wb_cfg: Rotator WB Configration description + * @dest: destination surface information + * @dest_rect: dest ROI, caller takes into account the different operations + * such as decimation, flip etc to program this field + * @addr: destination surface address + * @prefill_bw: prefill bandwidth in Bps + */ +struct sde_hw_rot_wb_cfg { + struct sde_mdp_format_params *fmt; + struct sde_mdp_plane_sizes dst_plane; + struct sde_rect *dst_rect; + struct sde_mdp_data *data; + u32 img_width; + u32 img_height; + u32 v_downscale_factor; + u32 h_downscale_factor; + u32 fps; + u64 bw; + u64 prefill_bw; +}; + + + +/** + * + * struct sde_hw_rotator_ops: Interface to the Rotator Hw driver functions + * + * Pre-requsises: + * - Caller must call the init function to get the rotator context + * - These functions will be called after clocks are enabled + */ +struct sde_hw_rotator_ops { + /** + * setup_rotator_fetchengine(): + * Setup Source format + * Setup Source dimension/cropping rectangle (ROI) + * Setup Source surface base address and stride + * Setup fetch engine op mode (linear/tiled/compression/...) + * @ctx: Rotator context created in sde_hw_rotator_config + * @queue_id: Select either low / high priority queue + * @cfg: Rotator Fetch engine configuration parameters + * @danger_lut: Danger LUT setting + * @safe_lut: Safe LUT setting + * @dnsc_factor_w: Downscale factor for width + * @dnsc_factor_h: Downscale factor for height + * @flags: Specific config flag, see SDE_ROT_FLAG_ for details + */ + void (*setup_rotator_fetchengine)( + struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, + struct sde_hw_rot_sspp_cfg *cfg, + u32 danger_lut, + u32 safe_lut, + u32 dnsc_factor_w, + u32 dnsc_factor_h, + u32 flags); + + /** + * setup_rotator_wbengine(): + * Setup destination formats + * Setup destination dimension/cropping rectangle (ROI) + * Setup destination surface base address and strides + * Setup writeback engine op mode (linear/tiled/compression) + * @ctx: Rotator context created in sde_hw_rotator_config + * @queue_id: Select either low / high priority queue + * @cfg: Rotator WriteBack engine configuration parameters + * @flags: Specific config flag, see SDE_ROT_FLAG_ for details + */ + void (*setup_rotator_wbengine)( + struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, + struct sde_hw_rot_wb_cfg *cfg, + u32 flags); + + /** + * start_rotator(): + * Kick start rotator operation based on cached setup parameters + * REGDMA commands will get generated at this points + * @ctx: Rotator context + * @queue_id: Select either low / high priority queue + * Returns: unique job timestamp per submit. Used for tracking + * rotator finished job. + */ + u32 (*start_rotator)( + struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id); + + /** + * wait_rotator_done(): + * Notify Rotator HAL layer previously submitted job finished. + * A job timestamp will return to caller. + * @ctx: Rotator context + * @flags: Reserved + * Returns: job timestamp for tracking purpose + * + */ + u32 (*wait_rotator_done)( + struct sde_hw_rotator_context *ctx, + enum sde_rot_queue_prio queue_id, + u32 flags); + + /** + * get_pending_ts(): + * Obtain current active timestamp from rotator hw + * @rot: HW Rotator structure + * @ctx: Rotator context + * @ts: current timestamp return from rot hw + * Returns: true if context has pending requests + */ + int (*get_pending_ts)( + struct sde_hw_rotator *rot, + struct sde_hw_rotator_context *ctx, + u32 *ts); + + /** + * update_ts(): + * Update rotator timestmap with given value + * @rot: HW Rotator structure + * @q_id: rotator queue id + * @ts: new timestamp for rotator + */ + void (*update_ts)( + struct sde_hw_rotator *rot, + u32 q_id, + u32 ts); +}; + +/** + * struct sde_dbg_buf : Debug buffer used by debugfs + * @vaddr: VA address mapped from dma buffer + * @dmabuf: DMA buffer + * @buflen: Length of DMA buffer + * @width: pixel width of buffer + * @height: pixel height of buffer + */ +struct sde_dbg_buf { + void *vaddr; + struct dma_buf *dmabuf; + unsigned long buflen; + u32 width; + u32 height; +}; + +/** + * struct sde_hw_rotator_context : Each rotator context ties to each priority + * queue. Max number of concurrent contexts in regdma is limited to regdma + * ram segment size allocation. Each rotator context can be any priority. A + * incremental timestamp is used to identify and assigned to each context. + * @list: list of pending context + * @sequence_id: unique sequence identifier for rotation request + * @sbuf_mode: true if stream buffer is requested + * @start_ctrl: start control register update value + * @sys_cache_mode: sys cache mode register update value + * @op_mode: rot top op mode selection + * @last_entry: pointer to last configured entry (for debugging purposes) + */ +struct sde_hw_rotator_context { + struct list_head list; + struct sde_hw_rotator *rot; + struct sde_rot_hw_resource *hwres; + enum sde_rot_queue_prio q_id; + u32 session_id; + u32 sequence_id; + char __iomem *regdma_base; + char __iomem *regdma_wrptr; + u32 timestamp; + struct completion rot_comp; + wait_queue_head_t regdma_waitq; + struct sde_dbg_buf src_dbgbuf; + struct sde_dbg_buf dst_dbgbuf; + u32 last_regdma_isr_status; + u32 last_regdma_timestamp; + dma_addr_t ts_addr; + bool is_secure; + bool is_traffic_shaping; + bool sbuf_mode; + bool abort; + u32 start_ctrl; + u32 sys_cache_mode; + u32 op_mode; + struct sde_rot_entry *last_entry; +}; + +/** + * struct sde_hw_rotator_resource_info : Each rotator resource ties to each + * priority queue + */ +struct sde_hw_rotator_resource_info { + struct sde_hw_rotator *rot; + struct sde_rot_hw_resource hw; +}; + +/** + * struct sde_hw_rotator : Rotator description + * @hw: mdp register mapped offset + * @ops: pointer to operations possible for the rotator HW + * @highest_bank: highest bank size of memory + * @ubwc_malsize: ubwc minimum allowable length + * @ubwc_swizzle: ubwc swizzle enable + * @sbuf_headroom: stream buffer headroom in lines + * @solid_fill: true if solid fill is requested + * @constant_color: solid fill constant color + * @sbuf_ctx: list of active sbuf context in FIFO order + * @vid_trigger: video mode trigger select + * @cmd_trigger: command mode trigger select + * @inpixfmts: array of supported input pixel formats fourcc per mode + * @num_inpixfmt: size of the supported input pixel format array per mode + * @outpixfmts: array of supported output pixel formats in fourcc per mode + * @num_outpixfmt: size of the supported output pixel formats array per mode + * @downscale_caps: capability string of scaling + * @maxlinewidth: maximum line width supported + */ +struct sde_hw_rotator { + /* base */ + char __iomem *mdss_base; + + /* Platform device from upper manager */ + struct platform_device *pdev; + + /* Ops */ + struct sde_hw_rotator_ops ops; + + /* Cmd Queue */ + u32 cmd_queue[SDE_HW_ROT_REGDMA_RAM_SIZE]; + + /* Cmd Queue Write Ptr */ + char __iomem *cmd_wr_ptr[ROT_QUEUE_MAX][SDE_HW_ROT_REGDMA_TOTAL_CTX]; + + /* Rotator Context */ + struct sde_hw_rotator_context + *rotCtx[ROT_QUEUE_MAX][SDE_HW_ROT_REGDMA_TOTAL_CTX]; + + /* Cmd timestamp sequence for different priority*/ + atomic_t timestamp[ROT_QUEUE_MAX]; + + /* regdma mode */ + enum sde_rotator_regdma_mode mode; + + /* logical interrupt number */ + int irq_num; + atomic_t irq_enabled; + + /* internal ION memory for SW timestamp */ + struct ion_client *iclient; + struct sde_mdp_img_data swts_buf; + void *swts_buffer; + + u32 highest_bank; + u32 ubwc_malsize; + u32 ubwc_swizzle; + u32 sbuf_headroom; + u32 solid_fill; + u32 constant_color; + + spinlock_t rotctx_lock; + spinlock_t rotisr_lock; + + bool dbgmem; + bool reset_hw_ts; + u32 last_hwts[ROT_QUEUE_MAX]; + u32 koff_timeout; + u32 vid_trigger; + u32 cmd_trigger; + + struct list_head sbuf_ctx[ROT_QUEUE_MAX]; + + const u32 *inpixfmts[SDE_ROTATOR_MODE_MAX]; + u32 num_inpixfmt[SDE_ROTATOR_MODE_MAX]; + const u32 *outpixfmts[SDE_ROTATOR_MODE_MAX]; + u32 num_outpixfmt[SDE_ROTATOR_MODE_MAX]; + const char *downscale_caps; + u32 maxlinewidth; +}; + +/** + * sde_hw_rotator_get_regdma_ctxidx(): regdma segment index is based on + * timestamp. For non-regdma, just return 0 (i.e. first index) + * @ctx: Rotator Context + * return: regdma segment index + */ +static inline u32 sde_hw_rotator_get_regdma_ctxidx( + struct sde_hw_rotator_context *ctx) +{ + if (ctx->rot->mode == ROT_REGDMA_OFF) + return 0; + else + return ctx->timestamp & SDE_HW_ROT_REGDMA_SEG_MASK; +} + +/** + * sde_hw_rotator_get_regdma_segment_base: return the base pointe of current + * regdma command buffer + * @ctx: Rotator Context + * return: base segment address + */ +static inline char __iomem *sde_hw_rotator_get_regdma_segment_base( + struct sde_hw_rotator_context *ctx) +{ + SDEROT_DBG("regdma base @slot[%d]: %pK\n", + sde_hw_rotator_get_regdma_ctxidx(ctx), + ctx->regdma_base); + + return ctx->regdma_base; +} + +/** + * sde_hw_rotator_get_regdma_segment(): return current regdma command buffer + * pointer for current regdma segment. + * @ctx: Rotator Context + * return: segment address + */ +static inline char __iomem *sde_hw_rotator_get_regdma_segment( + struct sde_hw_rotator_context *ctx) +{ + u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx); + char __iomem *addr = ctx->regdma_wrptr; + + SDEROT_DBG("regdma slot[%d] ==> %pK\n", idx, addr); + return addr; +} + +/** + * sde_hw_rotator_put_regdma_segment(): update current regdma command buffer + * pointer for current regdma segment + * @ctx: Rotator Context + * @wrptr: current regdma segment location + */ +static inline void sde_hw_rotator_put_regdma_segment( + struct sde_hw_rotator_context *ctx, + char __iomem *wrptr) +{ + u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx); + + ctx->regdma_wrptr = wrptr; + SDEROT_DBG("regdma slot[%d] <== %pK\n", idx, wrptr); +} + +/** + * sde_hw_rotator_put_ctx(): Storing rotator context according to its + * timestamp. + */ +static inline void sde_hw_rotator_put_ctx(struct sde_hw_rotator_context *ctx) +{ + struct sde_hw_rotator *rot = ctx->rot; + u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx); + unsigned long flags; + + spin_lock_irqsave(&rot->rotisr_lock, flags); + rot->rotCtx[ctx->q_id][idx] = ctx; + if (ctx->sbuf_mode) + list_add_tail(&ctx->list, &rot->sbuf_ctx[ctx->q_id]); + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + SDEROT_DBG("rotCtx[%d][%d] <== ctx:%pK | session-id:%d\n", + ctx->q_id, idx, ctx, ctx->session_id); +} + +/** + * sde_hw_rotator_clr_ctx(): Clearing rotator context according to its + * timestamp. + */ +static inline void sde_hw_rotator_clr_ctx(struct sde_hw_rotator_context *ctx) +{ + struct sde_hw_rotator *rot = ctx->rot; + u32 idx = sde_hw_rotator_get_regdma_ctxidx(ctx); + unsigned long flags; + + spin_lock_irqsave(&rot->rotisr_lock, flags); + rot->rotCtx[ctx->q_id][idx] = NULL; + if (ctx->sbuf_mode) + list_del_init(&ctx->list); + spin_unlock_irqrestore(&rot->rotisr_lock, flags); + + SDEROT_DBG("rotCtx[%d][%d] <== null | session-id:%d\n", + ctx->q_id, idx, ctx->session_id); +} + +#endif /*_SDE_ROTATOR_R3_INTERNAL_H */ diff --git a/techpack/display/rotator/sde_rotator_smmu.c b/techpack/display/rotator/sde_rotator_smmu.c new file mode 100644 index 0000000000000000000000000000000000000000..14669fdf4097dd40b2b2fb3cf0577a7dd34ef34e --- /dev/null +++ b/techpack/display/rotator/sde_rotator_smmu.c @@ -0,0 +1,700 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/iommu.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/dma-mapping.h> +#include <linux/dma-buf.h> +#include <linux/of_platform.h> +#include <linux/msm_dma_iommu_mapping.h> +#include <asm/dma-iommu.h> + +#include "soc/qcom/secure_buffer.h" +#include "sde_rotator_base.h" +#include "sde_rotator_util.h" +#include "sde_rotator_io_util.h" +#include "sde_rotator_smmu.h" +#include "sde_rotator_debug.h" + +#define SMMU_SDE_ROT_SEC "qcom,smmu_sde_rot_sec" +#define SMMU_SDE_ROT_UNSEC "qcom,smmu_sde_rot_unsec" + +struct sde_smmu_domain { + char *ctx_name; + int domain; +}; + +static inline bool sde_smmu_is_valid_domain_type( + struct sde_rot_data_type *mdata, int domain_type) +{ + return true; +} + +static inline bool sde_smmu_is_valid_domain_condition( + struct sde_rot_data_type *mdata, + int domain_type, + bool is_attach) +{ + if (is_attach) { + if (test_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU, + mdata->sde_caps_map) && + (mdata->sec_cam_en && + domain_type == SDE_IOMMU_DOMAIN_ROT_SECURE)) + return false; + else + return true; + } else { + if (test_bit(SDE_CAPS_SEC_ATTACH_DETACH_SMMU, + mdata->sde_caps_map) && + (mdata->sec_cam_en && + domain_type == SDE_IOMMU_DOMAIN_ROT_SECURE)) + return true; + else + return false; + } +} + +struct sde_smmu_client *sde_smmu_get_cb(u32 domain) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + if (!sde_smmu_is_valid_domain_type(mdata, domain)) + return NULL; + + return (domain >= SDE_IOMMU_MAX_DOMAIN) ? NULL : + &mdata->sde_smmu[domain]; +} + +static int sde_smmu_util_parse_dt_clock(struct platform_device *pdev, + struct sde_module_power *mp) +{ + u32 i = 0, rc = 0; + const char *clock_name; + u32 clock_rate; + int num_clk; + + num_clk = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if (num_clk < 0) { + SDEROT_DBG("clocks are not defined\n"); + num_clk = 0; + } + + mp->num_clk = num_clk; + mp->clk_config = devm_kzalloc(&pdev->dev, + sizeof(struct sde_clk) * mp->num_clk, GFP_KERNEL); + if (num_clk && !mp->clk_config) { + rc = -ENOMEM; + mp->num_clk = 0; + goto clk_err; + } + + for (i = 0; i < mp->num_clk; i++) { + of_property_read_string_index(pdev->dev.of_node, "clock-names", + i, &clock_name); + strlcpy(mp->clk_config[i].clk_name, clock_name, + sizeof(mp->clk_config[i].clk_name)); + + of_property_read_u32_index(pdev->dev.of_node, "clock-rate", + i, &clock_rate); + mp->clk_config[i].rate = clock_rate; + + if (!clock_rate) + mp->clk_config[i].type = SDE_CLK_AHB; + else + mp->clk_config[i].type = SDE_CLK_PCLK; + } + +clk_err: + return rc; +} + +static int sde_smmu_clk_register(struct platform_device *pdev, + struct sde_module_power *mp) +{ + int i, ret; + struct clk *clk; + + ret = sde_smmu_util_parse_dt_clock(pdev, mp); + if (ret) { + SDEROT_ERR("unable to parse clocks\n"); + return -EINVAL; + } + + for (i = 0; i < mp->num_clk; i++) { + clk = devm_clk_get(&pdev->dev, + mp->clk_config[i].clk_name); + if (IS_ERR(clk)) { + SDEROT_ERR("unable to get clk: %s\n", + mp->clk_config[i].clk_name); + return PTR_ERR(clk); + } + mp->clk_config[i].clk = clk; + } + return 0; +} + +static int sde_smmu_enable_power(struct sde_smmu_client *sde_smmu, + bool enable) +{ + int rc = 0; + struct sde_module_power *mp; + + if (!sde_smmu) + return -EINVAL; + + mp = &sde_smmu->mp; + + if (!mp->num_vreg && !mp->num_clk) + return 0; + + if (enable) { + rc = sde_rot_enable_vreg(mp->vreg_config, mp->num_vreg, true); + if (rc) { + SDEROT_ERR("vreg enable failed - rc:%d\n", rc); + goto end; + } + sde_update_reg_bus_vote(sde_smmu->reg_bus_clt, + VOTE_INDEX_19_MHZ); + rc = sde_rot_enable_clk(mp->clk_config, mp->num_clk, true); + if (rc) { + SDEROT_ERR("clock enable failed - rc:%d\n", rc); + sde_update_reg_bus_vote(sde_smmu->reg_bus_clt, + VOTE_INDEX_DISABLE); + sde_rot_enable_vreg(mp->vreg_config, mp->num_vreg, + false); + goto end; + } + } else { + sde_rot_enable_clk(mp->clk_config, mp->num_clk, false); + sde_update_reg_bus_vote(sde_smmu->reg_bus_clt, + VOTE_INDEX_DISABLE); + sde_rot_enable_vreg(mp->vreg_config, mp->num_vreg, false); + } +end: + return rc; +} + +/* + * sde_smmu_attach() + * + * Associates each configured VA range with the corresponding smmu context + * bank device. Enables the clks as smmu requires voting it before the usage. + * And iommu attach is done only once during the initial attach and it is never + * detached as smmu v2 uses a feature called 'retention'. + */ +int sde_smmu_attach(struct sde_rot_data_type *mdata) +{ + struct sde_smmu_client *sde_smmu; + int i, rc = 0; + + for (i = 0; i < SDE_IOMMU_MAX_DOMAIN; i++) { + if (!sde_smmu_is_valid_domain_type(mdata, i)) + continue; + + sde_smmu = sde_smmu_get_cb(i); + if (sde_smmu && sde_smmu->dev) { + rc = sde_smmu_enable_power(sde_smmu, true); + if (rc) { + SDEROT_ERR( + "power enable failed - domain:[%d] rc:%d\n", + i, rc); + goto err; + } + + if (!sde_smmu->domain_attached && + sde_smmu_is_valid_domain_condition(mdata, + i, + true)) { + rc = iommu_attach_device( + sde_smmu->rot_domain, sde_smmu->dev); + if (rc) { + SDEROT_ERR( + "iommu attach device failed for domain[%d] with err:%d\n", + i, rc); + sde_smmu_enable_power(sde_smmu, + false); + goto err; + } + sde_smmu->domain_attached = true; + SDEROT_DBG("iommu v2 domain[%i] attached\n", i); + } + } else { + SDEROT_DBG( + "iommu device not attached for domain[%d]\n", + i); + } + } + return 0; + +err: + for (i--; i >= 0; i--) { + sde_smmu = sde_smmu_get_cb(i); + if (sde_smmu && sde_smmu->dev) { + iommu_detach_device(sde_smmu->rot_domain, + sde_smmu->dev); + sde_smmu_enable_power(sde_smmu, false); + sde_smmu->domain_attached = false; + } + } + return rc; +} + +/* + * sde_smmu_detach() + * + * Only disables the clks as it is not required to detach the iommu mapped + * VA range from the device in smmu as explained in the sde_smmu_attach + */ +int sde_smmu_detach(struct sde_rot_data_type *mdata) +{ + struct sde_smmu_client *sde_smmu; + int i; + + for (i = 0; i < SDE_IOMMU_MAX_DOMAIN; i++) { + if (!sde_smmu_is_valid_domain_type(mdata, i)) + continue; + + sde_smmu = sde_smmu_get_cb(i); + if (sde_smmu && sde_smmu->dev) { + if (sde_smmu->domain_attached && + sde_smmu_is_valid_domain_condition(mdata, + i, false)) { + iommu_detach_device(sde_smmu->rot_domain, + sde_smmu->dev); + SDEROT_DBG("iommu domain[%i] detached\n", i); + sde_smmu->domain_attached = false; + } + else { + sde_smmu_enable_power(sde_smmu, false); + } + } + } + return 0; +} + +int sde_smmu_get_domain_id(u32 type) +{ + return type; +} + +/* + * sde_smmu_dma_buf_attach() + * + * Same as sde_smmu_dma_buf_attach except that the device is got from + * the configured smmu v2 context banks. + */ +struct dma_buf_attachment *sde_smmu_dma_buf_attach( + struct dma_buf *dma_buf, struct device *dev, int domain) +{ + struct sde_smmu_client *sde_smmu = sde_smmu_get_cb(domain); + + if (!sde_smmu) { + SDEROT_ERR("not able to get smmu context\n"); + return NULL; + } + + return dma_buf_attach(dma_buf, sde_smmu->dev); +} + +/* + * sde_smmu_map_dma_buf() + * + * Maps existing buffer (by struct scatterlist) into SMMU context bank device. + * From which we can take the virtual address and size allocated. + * msm_map_dma_buf is depricated with smmu v2 and it uses dma_map_sg instead + */ +int sde_smmu_map_dma_buf(struct dma_buf *dma_buf, + struct sg_table *table, int domain, dma_addr_t *iova, + unsigned long *size, int dir) +{ + int rc; + struct sde_smmu_client *sde_smmu = sde_smmu_get_cb(domain); + unsigned long attrs = 0; + + if (!sde_smmu) { + SDEROT_ERR("not able to get smmu context\n"); + return -EINVAL; + } + + rc = dma_map_sg_attrs(sde_smmu->dev, table->sgl, table->nents, dir, + attrs); + if (!rc) { + SDEROT_ERR("dma map sg failed\n"); + return -ENOMEM; + } + + *iova = table->sgl->dma_address; + *size = table->sgl->dma_length; + return 0; +} + +void sde_smmu_unmap_dma_buf(struct sg_table *table, int domain, + int dir, struct dma_buf *dma_buf) +{ + struct sde_smmu_client *sde_smmu = sde_smmu_get_cb(domain); + + if (!sde_smmu) { + SDEROT_ERR("not able to get smmu context\n"); + return; + } + + dma_unmap_sg(sde_smmu->dev, table->sgl, table->nents, dir); +} + +static DEFINE_MUTEX(sde_smmu_ref_cnt_lock); + +int sde_smmu_ctrl(int enable) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int rc = 0; + + mutex_lock(&sde_smmu_ref_cnt_lock); + SDEROT_EVTLOG(__builtin_return_address(0), enable, mdata->iommu_ref_cnt, + mdata->iommu_attached); + SDEROT_DBG("%pS: enable:%d ref_cnt:%d attach:%d\n", + __builtin_return_address(0), enable, mdata->iommu_ref_cnt, + mdata->iommu_attached); + + if (enable) { + if (!mdata->iommu_attached) { + rc = sde_smmu_attach(mdata); + if (!rc) + mdata->iommu_attached = true; + } + mdata->iommu_ref_cnt++; + } else { + if (mdata->iommu_ref_cnt) { + mdata->iommu_ref_cnt--; + if (mdata->iommu_ref_cnt == 0) + if (mdata->iommu_attached) { + rc = sde_smmu_detach(mdata); + if (!rc) + mdata->iommu_attached = false; + } + } else { + SDEROT_ERR("unbalanced iommu ref\n"); + } + } + mutex_unlock(&sde_smmu_ref_cnt_lock); + + if (rc < 0) + return rc; + else + return mdata->iommu_ref_cnt; +} + +int sde_smmu_secure_ctrl(int enable) +{ + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + int rc = 0; + + mutex_lock(&sde_smmu_ref_cnt_lock); + /* + * Attach/detach secure context irrespective of ref count, + * We come here only when secure camera is disabled + */ + if (enable) { + rc = sde_smmu_attach(mdata); + if (!rc) + mdata->iommu_attached = true; + } else { + rc = sde_smmu_detach(mdata); + /* + * keep iommu_attached equal to true, + * so that driver does not attemp to attach + * while in secure state + */ + } + + mutex_unlock(&sde_smmu_ref_cnt_lock); + return rc; +} + +/* + * sde_smmu_device_create() + * @dev: sde_mdp device + * + * For smmu, each context bank is a separate child device of sde rot. + * Platform devices are created for those smmu related child devices of + * sde rot here. This would facilitate probes to happen for these devices in + * which the smmu mapping and initialization is handled. + */ +void sde_smmu_device_create(struct device *dev) +{ + struct device_node *parent, *child; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + + parent = dev->of_node; + for_each_child_of_node(parent, child) { + if (of_device_is_compatible(child, SMMU_SDE_ROT_SEC)) { + of_platform_device_create(child, NULL, dev); + mdata->sde_smmu + [SDE_IOMMU_DOMAIN_ROT_SECURE].domain_attached = true; + } else if (of_device_is_compatible(child, SMMU_SDE_ROT_UNSEC)) { + of_platform_device_create(child, NULL, dev); + mdata->sde_smmu + [SDE_IOMMU_DOMAIN_ROT_UNSECURE].domain_attached = true; + } + } +} + +int sde_smmu_init(struct device *dev) +{ + sde_smmu_device_create(dev); + + return 0; +} + +static int sde_smmu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, + int flags, void *token) +{ + struct sde_smmu_client *sde_smmu; + int rc = -EINVAL; + + if (!token) { + SDEROT_ERR("Error: token is NULL\n"); + return -EINVAL; + } + + sde_smmu = (struct sde_smmu_client *)token; + + /* trigger rotator dump */ + SDEROT_ERR("trigger rotator dump, iova=0x%08lx, flags=0x%x\n", + iova, flags); + SDEROT_ERR("SMMU device:%s", sde_smmu->dev->kobj.name); + + /* generate dump, but no panic */ + SDEROT_EVTLOG_TOUT_HANDLER("rot", "rot_dbg_bus", "vbif_dbg_bus"); + + /* + * return -ENOSYS to allow smmu driver to dump out useful + * debug info. + */ + return rc; +} + +static struct sde_smmu_domain sde_rot_unsec = { + "rot_0", SDE_IOMMU_DOMAIN_ROT_UNSECURE}; +static struct sde_smmu_domain sde_rot_sec = { + "rot_1", SDE_IOMMU_DOMAIN_ROT_SECURE}; + +static const struct of_device_id sde_smmu_dt_match[] = { + { .compatible = SMMU_SDE_ROT_UNSEC, .data = &sde_rot_unsec}, + { .compatible = SMMU_SDE_ROT_SEC, .data = &sde_rot_sec}, + {} +}; +MODULE_DEVICE_TABLE(of, sde_smmu_dt_match); + +/* + * sde_smmu_probe() + * @pdev: platform device + * + * Each smmu context acts as a separate device and the context banks are + * configured with a VA range. + * Registeres the clks as each context bank has its own clks, for which voting + * has to be done everytime before using that context bank. + */ +int sde_smmu_probe(struct platform_device *pdev) +{ + struct device *dev; + struct sde_rot_data_type *mdata = sde_rot_get_mdata(); + struct sde_smmu_client *sde_smmu; + int rc = 0; + struct sde_smmu_domain smmu_domain; + const struct of_device_id *match; + struct sde_module_power *mp; + char name[MAX_CLIENT_NAME_LEN]; + u32 sid = 0; + + if (!mdata) { + SDEROT_INFO( + "probe failed as mdata is not initializedi, probe defer\n"); + return -EPROBE_DEFER; + } + + match = of_match_device(sde_smmu_dt_match, &pdev->dev); + if (!match || !match->data) { + SDEROT_ERR("probe failed as match data is invalid\n"); + return -EINVAL; + } + + smmu_domain = *(struct sde_smmu_domain *) (match->data); + if (smmu_domain.domain >= SDE_IOMMU_MAX_DOMAIN) { + SDEROT_ERR("no matching device found\n"); + return -EINVAL; + } + + if (of_find_property(pdev->dev.of_node, "iommus", NULL)) { + dev = &pdev->dev; + rc = of_property_read_u32_index(pdev->dev.of_node, "iommus", + 1, &sid); + if (rc) + SDEROT_DBG("SID not defined for domain:%d", + smmu_domain.domain); + } else { + SDEROT_ERR("Invalid SMMU ctx for domain:%d\n", + smmu_domain.domain); + return -EINVAL; + } + + sde_smmu = &mdata->sde_smmu[smmu_domain.domain]; + sde_smmu->domain = smmu_domain.domain; + sde_smmu->sid = sid; + mp = &sde_smmu->mp; + memset(mp, 0, sizeof(struct sde_module_power)); + + if (of_find_property(pdev->dev.of_node, + "gdsc-mdss-supply", NULL)) { + + mp->vreg_config = devm_kzalloc(&pdev->dev, + sizeof(struct sde_vreg), GFP_KERNEL); + if (!mp->vreg_config) + return -ENOMEM; + + strlcpy(mp->vreg_config->vreg_name, "gdsc-mdss", + sizeof(mp->vreg_config->vreg_name)); + mp->num_vreg = 1; + } + + if (mp->vreg_config) { + rc = sde_rot_config_vreg(&pdev->dev, mp->vreg_config, + mp->num_vreg, true); + if (rc) { + SDEROT_ERR("vreg config failed rc=%d\n", rc); + goto release_vreg; + } + } + + rc = sde_smmu_clk_register(pdev, mp); + if (rc) { + SDEROT_ERR( + "smmu clk register failed for domain[%d] with err:%d\n", + smmu_domain.domain, rc); + goto disable_vreg; + } + + snprintf(name, MAX_CLIENT_NAME_LEN, "smmu:%u", smmu_domain.domain); + sde_smmu->reg_bus_clt = sde_reg_bus_vote_client_create(name); + if (IS_ERR_OR_NULL(sde_smmu->reg_bus_clt)) { + SDEROT_ERR("mdss bus client register failed\n"); + rc = PTR_ERR(sde_smmu->reg_bus_clt); + sde_smmu->reg_bus_clt = NULL; + goto unregister_clk; + } + + rc = sde_smmu_enable_power(sde_smmu, true); + if (rc) { + SDEROT_ERR("power enable failed - domain:[%d] rc:%d\n", + smmu_domain.domain, rc); + goto bus_client_destroy; + } + + sde_smmu->dev = &pdev->dev; + sde_smmu->rot_domain = iommu_get_domain_for_dev(sde_smmu->dev); + if (!sde_smmu->rot_domain) { + dev_err(&pdev->dev, "iommu get domain failed\n"); + return -EINVAL; + } + + if (!dev->dma_parms) + dev->dma_parms = devm_kzalloc(dev, + sizeof(*dev->dma_parms), GFP_KERNEL); + + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64)); + + iommu_set_fault_handler(sde_smmu->rot_domain, + sde_smmu_fault_handler, (void *)sde_smmu); + + sde_smmu_enable_power(sde_smmu, false); + + SDEROT_INFO( + "iommu v2 domain[%d] mapping and clk register successful!\n", + smmu_domain.domain); + return 0; + +bus_client_destroy: + sde_reg_bus_vote_client_destroy(sde_smmu->reg_bus_clt); + sde_smmu->reg_bus_clt = NULL; +unregister_clk: +disable_vreg: + sde_rot_config_vreg(&pdev->dev, sde_smmu->mp.vreg_config, + sde_smmu->mp.num_vreg, false); +release_vreg: + devm_kfree(&pdev->dev, sde_smmu->mp.vreg_config); + sde_smmu->mp.vreg_config = NULL; + sde_smmu->mp.num_vreg = 0; + return rc; +} + +int sde_smmu_remove(struct platform_device *pdev) +{ + int i; + struct sde_smmu_client *sde_smmu; + + for (i = 0; i < SDE_IOMMU_MAX_DOMAIN; i++) { + sde_smmu = sde_smmu_get_cb(i); + if (!sde_smmu || !sde_smmu->dev || + (sde_smmu->dev != &pdev->dev)) + continue; + + sde_smmu->dev = NULL; + sde_smmu->rot_domain = NULL; + sde_smmu_enable_power(sde_smmu, false); + sde_reg_bus_vote_client_destroy(sde_smmu->reg_bus_clt); + sde_smmu->reg_bus_clt = NULL; + sde_rot_config_vreg(&pdev->dev, sde_smmu->mp.vreg_config, + sde_smmu->mp.num_vreg, false); + devm_kfree(&pdev->dev, sde_smmu->mp.vreg_config); + sde_smmu->mp.vreg_config = NULL; + sde_smmu->mp.num_vreg = 0; + } + return 0; +} + +static struct platform_driver sde_smmu_driver = { + .probe = sde_smmu_probe, + .remove = sde_smmu_remove, + .shutdown = NULL, + .driver = { + .name = "sde_smmu", + .of_match_table = sde_smmu_dt_match, + }, +}; + +static int sde_smmu_register_driver(void) +{ + return platform_driver_register(&sde_smmu_driver); +} + +static int __init sde_smmu_driver_init(void) +{ + int ret; + + ret = sde_smmu_register_driver(); + if (ret) + SDEROT_ERR("sde_smmu_register_driver() failed!\n"); + + return ret; +} +module_init(sde_smmu_driver_init); + +static void __exit sde_smmu_driver_cleanup(void) +{ + platform_driver_unregister(&sde_smmu_driver); +} +module_exit(sde_smmu_driver_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("SDE SMMU driver"); diff --git a/techpack/display/rotator/sde_rotator_smmu.h b/techpack/display/rotator/sde_rotator_smmu.h new file mode 100644 index 0000000000000000000000000000000000000000..e0c666f91b6d80f9267a77ba97d4d9636b1809b7 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_smmu.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_ROTATOR_SMMU_H +#define SDE_ROTATOR_SMMU_H + +#include <linux/types.h> +#include <linux/device.h> +#include <linux/dma-buf.h> + +#include "sde_rotator_io_util.h" + +enum sde_iommu_domain_type { + SDE_IOMMU_DOMAIN_ROT_UNSECURE, + SDE_IOMMU_DOMAIN_ROT_SECURE, + SDE_IOMMU_MAX_DOMAIN +}; + +int sde_smmu_init(struct device *dev); + +static inline int sde_smmu_dma_data_direction(int dir) +{ + return dir; +} + +int sde_smmu_ctrl(int enable); + +struct dma_buf_attachment *sde_smmu_dma_buf_attach( + struct dma_buf *dma_buf, struct device *dev, int domain); + +int sde_smmu_map_dma_buf(struct dma_buf *dma_buf, + struct sg_table *table, int domain, dma_addr_t *iova, + unsigned long *size, int dir); + +void sde_smmu_unmap_dma_buf(struct sg_table *table, int domain, + int dir, struct dma_buf *dma_buf); + +int sde_smmu_secure_ctrl(int enable); + +#endif /* SDE_ROTATOR_SMMU_H */ diff --git a/techpack/display/rotator/sde_rotator_sync.c b/techpack/display/rotator/sde_rotator_sync.c new file mode 100644 index 0000000000000000000000000000000000000000..a4f28cfe05c87829cc2e9b830796ca0c030eb531 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_sync.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/dma-fence.h> +#include <linux/sync_file.h> + +#include "sde_rotator_util.h" +#include "sde_rotator_sync.h" + +#define SDE_ROT_SYNC_NAME_SIZE 64 +#define SDE_ROT_SYNC_DRIVER_NAME "sde_rot" + +/** + * struct sde_rot_fence - sync fence context + * @base: base sync fence object + * @name: name of this sync fence + * @fence_list: linked list of outstanding sync fence + */ +struct sde_rot_fence { + struct dma_fence base; + char name[SDE_ROT_SYNC_NAME_SIZE]; + struct list_head fence_list; +}; + +/** + * struct sde_rot_timeline - sync timeline context + * @kref: reference count of timeline + * @lock: serialization lock for timeline and fence update + * @name: name of timeline + * @fence_name: fence name prefix + * @next_value: next commit sequence number + * @curr_value: current retired sequence number + * @context: fence context identifier + * @fence_list_head: linked list of outstanding sync fence + */ +struct sde_rot_timeline { + struct kref kref; + spinlock_t lock; + char name[SDE_ROT_SYNC_NAME_SIZE]; + char fence_name[SDE_ROT_SYNC_NAME_SIZE]; + u32 next_value; + u32 curr_value; + u64 context; + struct list_head fence_list_head; +}; + +/* + * to_sde_rot_fence - get rotator fence from fence base object + * @fence: Pointer to fence base object + */ +static struct sde_rot_fence *to_sde_rot_fence(struct dma_fence *fence) +{ + return container_of(fence, struct sde_rot_fence, base); +} + +/* + * to_sde_rot_timeline - get rotator timeline from fence base object + * @fence: Pointer to fence base object + */ +static struct sde_rot_timeline *to_sde_rot_timeline(struct dma_fence *fence) +{ + return container_of(fence->lock, struct sde_rot_timeline, lock); +} + +/* + * sde_rotator_free_timeline - Free the given timeline object + * @kref: Pointer to timeline kref object. + */ +static void sde_rotator_free_timeline(struct kref *kref) +{ + struct sde_rot_timeline *tl = + container_of(kref, struct sde_rot_timeline, kref); + + kfree(tl); +} + +/* + * sde_rotator_put_timeline - Put the given timeline object + * @tl: Pointer to timeline object. + */ +static void sde_rotator_put_timeline(struct sde_rot_timeline *tl) +{ + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return; + } + + kref_put(&tl->kref, sde_rotator_free_timeline); +} + +/* + * sde_rotator_get_timeline - Get the given timeline object + * @tl: Pointer to timeline object. + */ +static void sde_rotator_get_timeline(struct sde_rot_timeline *tl) +{ + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return; + } + + kref_get(&tl->kref); +} + +static const char *sde_rot_fence_get_driver_name(struct dma_fence *fence) +{ + return SDE_ROT_SYNC_DRIVER_NAME; +} + +static const char *sde_rot_fence_get_timeline_name(struct dma_fence *fence) +{ + struct sde_rot_timeline *tl = to_sde_rot_timeline(fence); + + return tl->name; +} + +static bool sde_rot_fence_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static bool sde_rot_fence_signaled(struct dma_fence *fence) +{ + struct sde_rot_timeline *tl = to_sde_rot_timeline(fence); + bool status; + + status = ((s32) (tl->curr_value - fence->seqno)) >= 0; + SDEROT_DBG("status:%d fence seq:%d and timeline:%d\n", + status, fence->seqno, tl->curr_value); + return status; +} + +static void sde_rot_fence_release(struct dma_fence *fence) +{ + struct sde_rot_fence *f = to_sde_rot_fence(fence); + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); + if (!list_empty(&f->fence_list)) + list_del(&f->fence_list); + spin_unlock_irqrestore(fence->lock, flags); + sde_rotator_put_timeline(to_sde_rot_timeline(fence)); + kfree_rcu(f, base.rcu); +} + +static void sde_rot_fence_value_str(struct dma_fence *fence, char *str, + int size) +{ + snprintf(str, size, "%u", fence->seqno); +} + +static void sde_rot_fence_timeline_value_str(struct dma_fence *fence, + char *str, int size) +{ + struct sde_rot_timeline *tl = to_sde_rot_timeline(fence); + + snprintf(str, size, "%u", tl->curr_value); +} + +static struct dma_fence_ops sde_rot_fence_ops = { + .get_driver_name = sde_rot_fence_get_driver_name, + .get_timeline_name = sde_rot_fence_get_timeline_name, + .enable_signaling = sde_rot_fence_enable_signaling, + .signaled = sde_rot_fence_signaled, + .wait = dma_fence_default_wait, + .release = sde_rot_fence_release, + .fence_value_str = sde_rot_fence_value_str, + .timeline_value_str = sde_rot_fence_timeline_value_str, +}; + +/* + * sde_rotator_create_timeline - Create timeline object with the given name + * @name: Pointer to name character string. + */ +struct sde_rot_timeline *sde_rotator_create_timeline(const char *name) +{ + struct sde_rot_timeline *tl; + + if (!name) { + SDEROT_ERR("invalid parameters\n"); + return NULL; + } + + tl = kzalloc(sizeof(struct sde_rot_timeline), GFP_KERNEL); + if (!tl) + return NULL; + + kref_init(&tl->kref); + snprintf(tl->name, sizeof(tl->name), "rot_timeline_%s", name); + snprintf(tl->fence_name, sizeof(tl->fence_name), "rot_fence_%s", name); + spin_lock_init(&tl->lock); + tl->context = dma_fence_context_alloc(1); + INIT_LIST_HEAD(&tl->fence_list_head); + + return tl; +} + +/* + * sde_rotator_destroy_timeline - Destroy the given timeline object + * @tl: Pointer to timeline object. + */ +void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl) +{ + sde_rotator_put_timeline(tl); +} + +/* + * sde_rotator_inc_timeline_locked - Increment timeline by given amount + * @tl: Pointer to timeline object. + * @increment: the amount to increase the timeline by. + */ +static int sde_rotator_inc_timeline_locked(struct sde_rot_timeline *tl, + int increment) +{ + struct sde_rot_fence *f, *next; + + tl->curr_value += increment; + list_for_each_entry_safe(f, next, &tl->fence_list_head, fence_list) { + if (dma_fence_is_signaled_locked(&f->base)) { + SDEROT_DBG("%s signaled\n", f->name); + list_del_init(&f->fence_list); + } + } + + return 0; +} + +/* + * sde_rotator_resync_timeline - Resync timeline to last committed value + * @tl: Pointer to timeline object. + */ +void sde_rotator_resync_timeline(struct sde_rot_timeline *tl) +{ + unsigned long flags; + s32 val; + + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return; + } + + spin_lock_irqsave(&tl->lock, flags); + val = tl->next_value - tl->curr_value; + if (val > 0) { + SDEROT_WARN("flush %s:%d\n", tl->name, val); + sde_rotator_inc_timeline_locked(tl, val); + } + spin_unlock_irqrestore(&tl->lock, flags); +} + +/* + * sde_rotator_get_sync_fence - Create fence object from the given timeline + * @tl: Pointer to timeline object + * @fence_fd: Pointer to file descriptor associated with the returned fence. + * Null if not required. + * @timestamp: Pointer to timestamp of the returned fence. Null if not required. + */ +struct sde_rot_sync_fence *sde_rotator_get_sync_fence( + struct sde_rot_timeline *tl, int *fence_fd, u32 *timestamp) +{ + struct sde_rot_fence *f; + unsigned long flags; + u32 val; + + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return NULL; + } + + f = kzalloc(sizeof(struct sde_rot_fence), GFP_KERNEL); + if (!f) + return NULL; + + INIT_LIST_HEAD(&f->fence_list); + spin_lock_irqsave(&tl->lock, flags); + val = ++(tl->next_value); + dma_fence_init(&f->base, &sde_rot_fence_ops, &tl->lock, + tl->context, val); + list_add_tail(&f->fence_list, &tl->fence_list_head); + sde_rotator_get_timeline(tl); + spin_unlock_irqrestore(&tl->lock, flags); + snprintf(f->name, sizeof(f->name), "%s_%u", tl->fence_name, val); + + if (fence_fd) + *fence_fd = sde_rotator_get_sync_fence_fd( + (struct sde_rot_sync_fence *) &f->base); + + if (timestamp) + *timestamp = val; + + SDEROT_DBG("output sync fence created at val=%u\n", val); + + return (struct sde_rot_sync_fence *) &f->base; +} + +/* + * sde_rotator_inc_timeline - Increment timeline by given amount + * @tl: Pointer to timeline object. + * @increment: the amount to increase the timeline by. + */ +int sde_rotator_inc_timeline(struct sde_rot_timeline *tl, int increment) +{ + unsigned long flags; + int rc; + + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return -EINVAL; + } + + spin_lock_irqsave(&tl->lock, flags); + rc = sde_rotator_inc_timeline_locked(tl, increment); + spin_unlock_irqrestore(&tl->lock, flags); + + return rc; +} + +/* + * sde_rotator_get_timeline_commit_ts - Return commit tick of given timeline + * @tl: Pointer to timeline object. + */ +u32 sde_rotator_get_timeline_commit_ts(struct sde_rot_timeline *tl) +{ + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return 0; + } + + return tl->next_value; +} + +/* + * sde_rotator_get_timeline_retire_ts - Return retire tick of given timeline + * @tl: Pointer to timeline object. + */ +u32 sde_rotator_get_timeline_retire_ts(struct sde_rot_timeline *tl) +{ + if (!tl) { + SDEROT_ERR("invalid parameters\n"); + return 0; + } + + return tl->curr_value; +} + +/* + * sde_rotator_put_sync_fence - Destroy given fence object + * @fence: Pointer to fence object. + */ +void sde_rotator_put_sync_fence(struct sde_rot_sync_fence *fence) +{ + if (!fence) { + SDEROT_ERR("invalid parameters\n"); + return; + } + + dma_fence_put((struct dma_fence *) fence); +} + +/* + * sde_rotator_wait_sync_fence - Wait until fence signal or timeout + * @fence: Pointer to fence object. + * @timeout: maximum wait time, in msec, for fence to signal. + */ +int sde_rotator_wait_sync_fence(struct sde_rot_sync_fence *fence, + long timeout) +{ + int rc; + + if (!fence) { + SDEROT_ERR("invalid parameters\n"); + return -EINVAL; + } + + rc = dma_fence_wait_timeout((struct dma_fence *) fence, false, + msecs_to_jiffies(timeout)); + if (rc > 0) { + SDEROT_DBG("fence signaled\n"); + rc = 0; + } else if (rc == 0) { + SDEROT_DBG("fence timeout\n"); + rc = -ETIMEDOUT; + } + + return rc; +} + +/* + * sde_rotator_get_sync_fence_fd - Get fence object of given file descriptor + * @fd: File description of fence object. + */ +struct sde_rot_sync_fence *sde_rotator_get_fd_sync_fence(int fd) +{ + return (struct sde_rot_sync_fence *) sync_file_get_fence(fd); +} + +/* + * sde_rotator_get_sync_fence_fd - Get file descriptor of given fence object + * @fence: Pointer to fence object. + */ +int sde_rotator_get_sync_fence_fd(struct sde_rot_sync_fence *fence) +{ + int fd; + struct sync_file *sync_file; + + if (!fence) { + SDEROT_ERR("invalid parameters\n"); + return -EINVAL; + } + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + SDEROT_ERR("fail to get unused fd\n"); + return fd; + } + + sync_file = sync_file_create((struct dma_fence *) fence); + if (!sync_file) { + put_unused_fd(fd); + SDEROT_ERR("failed to create sync file\n"); + return -ENOMEM; + } + + fd_install(fd, sync_file->file); + + return fd; +} diff --git a/techpack/display/rotator/sde_rotator_sync.h b/techpack/display/rotator/sde_rotator_sync.h new file mode 100644 index 0000000000000000000000000000000000000000..55dbd0732ad22f5d39d7d641f92cdb28948935d8 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_sync.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef SDE_ROTATOR_SYNC_H +#define SDE_ROTATOR_SYNC_H + +#include <linux/types.h> +#include <linux/errno.h> + +struct sde_rot_sync_fence; +struct sde_rot_timeline; + +#if defined(CONFIG_SYNC_FILE) +struct sde_rot_timeline *sde_rotator_create_timeline(const char *name); + +void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl); + +struct sde_rot_sync_fence *sde_rotator_get_sync_fence( + struct sde_rot_timeline *tl, int *fence_fd, u32 *timestamp); + +void sde_rotator_resync_timeline(struct sde_rot_timeline *tl); + +u32 sde_rotator_get_timeline_commit_ts(struct sde_rot_timeline *tl); + +u32 sde_rotator_get_timeline_retire_ts(struct sde_rot_timeline *tl); + +int sde_rotator_inc_timeline(struct sde_rot_timeline *tl, int increment); + +void sde_rotator_put_sync_fence(struct sde_rot_sync_fence *fence); + +int sde_rotator_wait_sync_fence(struct sde_rot_sync_fence *fence, + long timeout); + +struct sde_rot_sync_fence *sde_rotator_get_fd_sync_fence(int fd); + +int sde_rotator_get_sync_fence_fd(struct sde_rot_sync_fence *fence); + +#else +static inline +struct sde_rot_timeline *sde_rotator_create_timeline(const char *name) +{ + return NULL; +} + +static inline +void sde_rotator_destroy_timeline(struct sde_rot_timeline *tl) +{ +} + +static inline +struct sde_rot_sync_fence *sde_rotator_get_sync_fence( + struct sde_rot_timeline *tl, int *fence_fd, u32 *timestamp) +{ + return NULL; +} + +static inline +void sde_rotator_resync_timeline(struct sde_rot_timeline *tl) +{ +} + +static inline +int sde_rotator_inc_timeline(struct sde_rot_timeline *tl, int increment) +{ + return 0; +} + +static inline +u32 sde_rotator_get_timeline_commit_ts(struct sde_rot_timeline *tl) +{ + return 0; +} + +static inline +u32 sde_rotator_get_timeline_retire_ts(struct sde_rot_timeline *tl) +{ + return 0; +} + +static inline +void sde_rotator_put_sync_fence(struct sde_rot_sync_fence *fence) +{ +} + +static inline +int sde_rotator_wait_sync_fence(struct sde_rot_sync_fence *fence, + long timeout) +{ + return 0; +} + +static inline +struct sde_rot_sync_fence *sde_rotator_get_fd_sync_fence(int fd) +{ + return NULL; +} + +static inline +int sde_rotator_get_sync_fence_fd(struct sde_rot_sync_fence *fence) +{ + return -EBADF; +} +#endif + +#endif /* SDE_ROTATOR_SYNC_H */ diff --git a/techpack/display/rotator/sde_rotator_trace.h b/techpack/display/rotator/sde_rotator_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..307cee86f5302f911e83505e14419695520ecb0a --- /dev/null +++ b/techpack/display/rotator/sde_rotator_trace.h @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. + */ +#if !defined(TRACE_SDE_ROTATOR_H) || defined(TRACE_HEADER_MULTI_READ) +#define TRACE_SDE_ROTATOR_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM sde_rotator +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE sde_rotator_trace + +#include <linux/tracepoint.h> +#include <sde_rotator_core.h> + +DECLARE_EVENT_CLASS(rot_entry_template, + TP_PROTO(u32 ss_id, u32 sq_id, struct sde_rot_trace_entry *rot), + TP_ARGS(ss_id, sq_id, rot), + TP_STRUCT__entry( + __field(u32, ss_id) + __field(u32, sq_id) + __field(u32, pr_id) + __field(u32, flags) + __field(u32, src_fmt) + __field(u16, src_bw) + __field(u16, src_bh) + __field(u16, src_x) + __field(u16, src_y) + __field(u16, src_w) + __field(u16, src_h) + __field(u32, dst_fmt) + __field(u16, dst_bw) + __field(u16, dst_bh) + __field(u16, dst_x) + __field(u16, dst_y) + __field(u16, dst_w) + __field(u16, dst_h) + ), + TP_fast_assign( + __entry->ss_id = ss_id; + __entry->sq_id = sq_id; + __entry->pr_id = rot->wb_idx; + __entry->flags = rot->flags; + __entry->src_fmt = rot->input_format; + __entry->src_bw = rot->input_width; + __entry->src_bh = rot->input_height; + __entry->src_x = rot->src_x; + __entry->src_y = rot->src_y; + __entry->src_w = rot->src_w; + __entry->src_h = rot->src_h; + __entry->dst_fmt = rot->output_format; + __entry->dst_bw = rot->output_width; + __entry->dst_bh = rot->output_height; + __entry->dst_x = rot->dst_x; + __entry->dst_y = rot->dst_y; + __entry->dst_w = rot->dst_w; + __entry->dst_h = rot->dst_h; + ), + + TP_printk("%d.%d|%d|%x|%x|%u,%u|%u,%u,%u,%u|%x|%u,%u|%u,%u,%u,%u|", + __entry->ss_id, __entry->sq_id, __entry->pr_id, + __entry->flags, + __entry->src_fmt, __entry->src_bw, __entry->src_bh, + __entry->src_x, __entry->src_y, + __entry->src_w, __entry->src_h, + __entry->dst_fmt, __entry->dst_bw, __entry->dst_bh, + __entry->dst_x, __entry->dst_y, + __entry->dst_w, __entry->dst_h) +); + +DEFINE_EVENT(rot_entry_template, rot_entry_fence, + TP_PROTO(u32 ss_id, u32 sq_id, struct sde_rot_trace_entry *rot), + TP_ARGS(ss_id, sq_id, rot) +); + +DEFINE_EVENT(rot_entry_template, rot_entry_commit, + TP_PROTO(u32 ss_id, u32 sq_id, struct sde_rot_trace_entry *rot), + TP_ARGS(ss_id, sq_id, rot) +); + +DEFINE_EVENT(rot_entry_template, rot_entry_done, + TP_PROTO(u32 ss_id, u32 sq_id, struct sde_rot_trace_entry *rot), + TP_ARGS(ss_id, sq_id, rot) +); + +TRACE_EVENT(rot_perf_set_qos_luts, + TP_PROTO(u32 pnum, u32 fmt, u32 lut, bool linear), + TP_ARGS(pnum, fmt, lut, linear), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, fmt) + __field(u32, lut) + __field(bool, linear) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->fmt = fmt; + __entry->lut = lut; + __entry->linear = linear; + ), + TP_printk("pnum=%d fmt=%d lut=0x%x lin:%d", + __entry->pnum, __entry->fmt, + __entry->lut, __entry->linear) +); + +TRACE_EVENT(rot_perf_set_panic_luts, + TP_PROTO(u32 pnum, u32 fmt, u32 mode, u32 panic_lut, + u32 robust_lut), + TP_ARGS(pnum, fmt, mode, panic_lut, robust_lut), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, fmt) + __field(u32, mode) + __field(u32, panic_lut) + __field(u32, robust_lut) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->fmt = fmt; + __entry->mode = mode; + __entry->panic_lut = panic_lut; + __entry->robust_lut = robust_lut; + ), + TP_printk("pnum=%d fmt=%d mode=%d luts[0x%x, 0x%x]", + __entry->pnum, __entry->fmt, + __entry->mode, __entry->panic_lut, + __entry->robust_lut) +); + +TRACE_EVENT(rot_perf_set_wm_levels, + TP_PROTO(u32 pnum, u32 use_space, u32 priority_bytes, u32 wm0, u32 wm1, + u32 wm2, u32 mb_cnt, u32 mb_size), + TP_ARGS(pnum, use_space, priority_bytes, wm0, wm1, wm2, mb_cnt, + mb_size), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, use_space) + __field(u32, priority_bytes) + __field(u32, wm0) + __field(u32, wm1) + __field(u32, wm2) + __field(u32, mb_cnt) + __field(u32, mb_size) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->use_space = use_space; + __entry->priority_bytes = priority_bytes; + __entry->wm0 = wm0; + __entry->wm1 = wm1; + __entry->wm2 = wm2; + __entry->mb_cnt = mb_cnt; + __entry->mb_size = mb_size; + ), + TP_printk( + "pnum:%d useable_space:%d priority_bytes:%d watermark:[%d | %d | %d] nmb=%d mb_size=%d", + __entry->pnum, __entry->use_space, + __entry->priority_bytes, __entry->wm0, __entry->wm1, + __entry->wm2, __entry->mb_cnt, __entry->mb_size) +); + +TRACE_EVENT(rot_perf_set_ot, + TP_PROTO(u32 pnum, u32 xin_id, u32 rd_lim), + TP_ARGS(pnum, xin_id, rd_lim), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, xin_id) + __field(u32, rd_lim) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->xin_id = xin_id; + __entry->rd_lim = rd_lim; + ), + TP_printk("pnum:%d xin_id:%d ot:%d", + __entry->pnum, __entry->xin_id, __entry->rd_lim) +); + +TRACE_EVENT(rot_perf_prefill_calc, + TP_PROTO(u32 pnum, u32 latency_buf, u32 ot, u32 y_buf, u32 y_scaler, + u32 pp_lines, u32 pp_bytes, u32 post_sc, u32 fbc_bytes, + u32 prefill_bytes), + TP_ARGS(pnum, latency_buf, ot, y_buf, y_scaler, pp_lines, pp_bytes, + post_sc, fbc_bytes, prefill_bytes), + TP_STRUCT__entry( + __field(u32, pnum) + __field(u32, latency_buf) + __field(u32, ot) + __field(u32, y_buf) + __field(u32, y_scaler) + __field(u32, pp_lines) + __field(u32, pp_bytes) + __field(u32, post_sc) + __field(u32, fbc_bytes) + __field(u32, prefill_bytes) + ), + TP_fast_assign( + __entry->pnum = pnum; + __entry->latency_buf = latency_buf; + __entry->ot = ot; + __entry->y_buf = y_buf; + __entry->y_scaler = y_scaler; + __entry->pp_lines = pp_lines; + __entry->pp_bytes = pp_bytes; + __entry->post_sc = post_sc; + __entry->fbc_bytes = fbc_bytes; + __entry->prefill_bytes = prefill_bytes; + ), + TP_printk( + "pnum:%d latency_buf:%d ot:%d y_buf:%d y_scaler:%d pp_lines:%d, pp_bytes=%d post_sc:%d fbc_bytes:%d prefill:%d", + __entry->pnum, __entry->latency_buf, __entry->ot, + __entry->y_buf, __entry->y_scaler, __entry->pp_lines, + __entry->pp_bytes, __entry->post_sc, + __entry->fbc_bytes, __entry->prefill_bytes) +); + +TRACE_EVENT(rot_mark_write, + TP_PROTO(int pid, const char *name, bool trace_begin), + TP_ARGS(pid, name, trace_begin), + TP_STRUCT__entry( + __field(int, pid) + __string(trace_name, name) + __field(bool, trace_begin) + ), + TP_fast_assign( + __entry->pid = pid; + __assign_str(trace_name, name); + __entry->trace_begin = trace_begin; + ), + TP_printk("%s|%d|%s", __entry->trace_begin ? "B" : "E", + __entry->pid, __get_str(trace_name)) +); + +TRACE_EVENT(rot_trace_counter, + TP_PROTO(int pid, char *name, s64 value), + TP_ARGS(pid, name, value), + TP_STRUCT__entry( + __field(int, pid) + __string(counter_name, name) + __field(s64, value) + ), + TP_fast_assign( + __entry->pid = current->tgid; + __assign_str(counter_name, name); + __entry->value = value; + ), + TP_printk("%d|%s|%lld", __entry->pid, + __get_str(counter_name), __entry->value) +); + +TRACE_EVENT(rot_bw_ao_as_context, + TP_PROTO(u32 state), + TP_ARGS(state), + TP_STRUCT__entry( + __field(u32, state) + ), + TP_fast_assign( + __entry->state = state; + ), + TP_printk("Rotator bw context %s", + __entry->state ? "Active Only" : "Active+Sleep") + +); + +#define SDE_ROT_TRACE_EVTLOG_SIZE 15 +TRACE_EVENT(sde_rot_evtlog, + TP_PROTO(const char *tag, u32 tag_id, u32 cnt, u32 *data), + TP_ARGS(tag, tag_id, cnt, data), + TP_STRUCT__entry( + __field(int, pid) + __string(evtlog_tag, tag) + __field(u32, tag_id) + __array(u32, data, SDE_ROT_TRACE_EVTLOG_SIZE) + ), + TP_fast_assign( + __entry->pid = current->tgid; + __assign_str(evtlog_tag, tag); + __entry->tag_id = tag_id; + if (cnt > SDE_ROT_TRACE_EVTLOG_SIZE) + cnt = SDE_ROT_TRACE_EVTLOG_SIZE; + memcpy(__entry->data, data, cnt * sizeof(u32)); + memset(&__entry->data[cnt], 0, + (SDE_ROT_TRACE_EVTLOG_SIZE - cnt) * + sizeof(u32)); + ), + TP_printk("%d|%s:%d|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x|%x", + __entry->pid, __get_str(evtlog_tag), + __entry->tag_id, + __entry->data[0], __entry->data[1], + __entry->data[2], __entry->data[3], + __entry->data[4], __entry->data[5], + __entry->data[6], __entry->data[7], + __entry->data[8], __entry->data[9], + __entry->data[10], __entry->data[11], + __entry->data[12], __entry->data[13], + __entry->data[14]) +) + +#endif /* if !defined(TRACE_SDE_ROTATOR_H) || + * defined(TRACE_HEADER_MULTI_READ) + */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/techpack/display/rotator/sde_rotator_util.c b/techpack/display/rotator/sde_rotator_util.c new file mode 100644 index 0000000000000000000000000000000000000000..0dcb2413fc025fcca8bf5ef9788db36ab3f0a83c --- /dev/null +++ b/techpack/display/rotator/sde_rotator_util.c @@ -0,0 +1,1229 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012, 2015-2019, The Linux Foundation. All rights reserved. + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/file.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/major.h> +#include <linux/dma-buf.h> +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#include <linux/regulator/consumer.h> +#include <media/msm_media_info.h> +#include <linux/videodev2.h> +#include <linux/ion.h> + +#include "sde_rotator_util.h" +#include "sde_rotator_smmu.h" +#include "sde_rotator_debug.h" + +#define Y_TILEWIDTH 48 +#define Y_TILEHEIGHT 4 +#define UV_TILEWIDTH 48 +#define UV_TILEHEIGHT 8 +#define TILEWIDTH_SIZE 64 +#define TILEHEIGHT_SIZE 4 + +void sde_mdp_get_v_h_subsample_rate(u8 chroma_sample, + u8 *v_sample, u8 *h_sample) +{ + switch (chroma_sample) { + case SDE_MDP_CHROMA_H2V1: + *v_sample = 1; + *h_sample = 2; + break; + case SDE_MDP_CHROMA_H1V2: + *v_sample = 2; + *h_sample = 1; + break; + case SDE_MDP_CHROMA_420: + *v_sample = 2; + *h_sample = 2; + break; + default: + *v_sample = 1; + *h_sample = 1; + break; + } +} + +void sde_rot_intersect_rect(struct sde_rect *res_rect, + const struct sde_rect *dst_rect, + const struct sde_rect *sci_rect) +{ + int l = max(dst_rect->x, sci_rect->x); + int t = max(dst_rect->y, sci_rect->y); + int r = min((dst_rect->x + dst_rect->w), (sci_rect->x + sci_rect->w)); + int b = min((dst_rect->y + dst_rect->h), (sci_rect->y + sci_rect->h)); + + if (r < l || b < t) + *res_rect = (struct sde_rect){0, 0, 0, 0}; + else + *res_rect = (struct sde_rect){l, t, (r-l), (b-t)}; +} + +void sde_rot_crop_rect(struct sde_rect *src_rect, + struct sde_rect *dst_rect, + const struct sde_rect *sci_rect) +{ + struct sde_rect res; + + sde_rot_intersect_rect(&res, dst_rect, sci_rect); + + if (res.w && res.h) { + if ((res.w != dst_rect->w) || (res.h != dst_rect->h)) { + src_rect->x = src_rect->x + (res.x - dst_rect->x); + src_rect->y = src_rect->y + (res.y - dst_rect->y); + src_rect->w = res.w; + src_rect->h = res.h; + } + *dst_rect = (struct sde_rect) + {(res.x - sci_rect->x), (res.y - sci_rect->y), + res.w, res.h}; + } +} + +/* + * sde_rect_cmp() - compares two rects + * @rect1 - rect value to compare + * @rect2 - rect value to compare + * + * Returns 1 if the rects are same, 0 otherwise. + */ +int sde_rect_cmp(struct sde_rect *rect1, struct sde_rect *rect2) +{ + return rect1->x == rect2->x && rect1->y == rect2->y && + rect1->w == rect2->w && rect1->h == rect2->h; +} + +/* + * sde_rect_overlap_check() - compare two rects and check if they overlap + * @rect1 - rect value to compare + * @rect2 - rect value to compare + * + * Returns true if rects overlap, false otherwise. + */ +bool sde_rect_overlap_check(struct sde_rect *rect1, struct sde_rect *rect2) +{ + u32 rect1_left = rect1->x, rect1_right = rect1->x + rect1->w; + u32 rect1_top = rect1->y, rect1_bottom = rect1->y + rect1->h; + u32 rect2_left = rect2->x, rect2_right = rect2->x + rect2->w; + u32 rect2_top = rect2->y, rect2_bottom = rect2->y + rect2->h; + + if ((rect1_right <= rect2_left) || + (rect1_left >= rect2_right) || + (rect1_bottom <= rect2_top) || + (rect1_top >= rect2_bottom)) + return false; + + return true; +} + +int sde_mdp_get_rau_strides(u32 w, u32 h, + struct sde_mdp_format_params *fmt, + struct sde_mdp_plane_sizes *ps) +{ + if (fmt->is_yuv) { + ps->rau_cnt = DIV_ROUND_UP(w, 64); + ps->ystride[0] = 64 * 4; + ps->rau_h[0] = 4; + ps->rau_h[1] = 2; + if (fmt->chroma_sample == SDE_MDP_CHROMA_H1V2) + ps->ystride[1] = 64 * 2; + else if (fmt->chroma_sample == SDE_MDP_CHROMA_H2V1) { + ps->ystride[1] = 32 * 4; + ps->rau_h[1] = 4; + } else + ps->ystride[1] = 32 * 2; + + /* account for both chroma components */ + ps->ystride[1] <<= 1; + } else if (fmt->fetch_planes == SDE_MDP_PLANE_INTERLEAVED) { + ps->rau_cnt = DIV_ROUND_UP(w, 32); + ps->ystride[0] = 32 * 4 * fmt->bpp; + ps->ystride[1] = 0; + ps->rau_h[0] = 4; + ps->rau_h[1] = 0; + } else { + SDEROT_ERR("Invalid format=%d\n", fmt->format); + return -EINVAL; + } + + ps->ystride[0] *= ps->rau_cnt; + ps->ystride[1] *= ps->rau_cnt; + ps->num_planes = 2; + + SDEROT_DBG("BWC rau_cnt=%d strides={%d,%d} heights={%d,%d}\n", + ps->rau_cnt, ps->ystride[0], ps->ystride[1], + ps->rau_h[0], ps->rau_h[1]); + + return 0; +} + +static int sde_mdp_get_a5x_plane_size(struct sde_mdp_format_params *fmt, + u32 width, u32 height, struct sde_mdp_plane_sizes *ps) +{ + int rc = 0; + + if (sde_mdp_is_nv12_8b_format(fmt)) { + ps->num_planes = 2; + /* Y bitstream stride and plane size */ + ps->ystride[0] = ALIGN(width, 128); + ps->plane_size[0] = ALIGN(ps->ystride[0] * ALIGN(height, 32), + 4096); + + /* CbCr bitstream stride and plane size */ + ps->ystride[1] = ALIGN(width, 128); + ps->plane_size[1] = ALIGN(ps->ystride[1] * + ALIGN(height / 2, 32), 4096); + + if (!sde_mdp_is_ubwc_format(fmt)) + goto done; + + ps->num_planes += 2; + + /* Y meta data stride and plane size */ + ps->ystride[2] = ALIGN(DIV_ROUND_UP(width, 32), 64); + ps->plane_size[2] = ALIGN(ps->ystride[2] * + ALIGN(DIV_ROUND_UP(height, 8), 16), 4096); + + /* CbCr meta data stride and plane size */ + ps->ystride[3] = ALIGN(DIV_ROUND_UP(width / 2, 16), 64); + ps->plane_size[3] = ALIGN(ps->ystride[3] * + ALIGN(DIV_ROUND_UP(height / 2, 8), 16), 4096); + } else if (sde_mdp_is_p010_format(fmt)) { + ps->num_planes = 2; + /* Y bitstream stride and plane size */ + ps->ystride[0] = ALIGN(width * 2, 256); + ps->plane_size[0] = ALIGN(ps->ystride[0] * ALIGN(height, 16), + 4096); + + /* CbCr bitstream stride and plane size */ + ps->ystride[1] = ALIGN(width * 2, 256); + ps->plane_size[1] = ALIGN(ps->ystride[1] * + ALIGN(height / 2, 16), 4096); + + if (!sde_mdp_is_ubwc_format(fmt)) + goto done; + + ps->num_planes += 2; + + /* Y meta data stride and plane size */ + ps->ystride[2] = ALIGN(DIV_ROUND_UP(width, 32), 64); + ps->plane_size[2] = ALIGN(ps->ystride[2] * + ALIGN(DIV_ROUND_UP(height, 4), 16), 4096); + + /* CbCr meta data stride and plane size */ + ps->ystride[3] = ALIGN(DIV_ROUND_UP(width / 2, 16), 64); + ps->plane_size[3] = ALIGN(ps->ystride[3] * + ALIGN(DIV_ROUND_UP(height / 2, 4), 16), 4096); + } else if (sde_mdp_is_tp10_format(fmt)) { + u32 yWidth = sde_mdp_general_align(width, 192); + u32 yHeight = ALIGN(height, 16); + u32 uvWidth = sde_mdp_general_align(width, 192); + u32 uvHeight = ALIGN(height, 32); + + ps->num_planes = 2; + + /* Y bitstream stride and plane size */ + ps->ystride[0] = yWidth * TILEWIDTH_SIZE / Y_TILEWIDTH; + ps->plane_size[0] = ALIGN(ps->ystride[0] * + (yHeight * TILEHEIGHT_SIZE / Y_TILEHEIGHT), + 4096); + + /* CbCr bitstream stride and plane size */ + ps->ystride[1] = uvWidth * TILEWIDTH_SIZE / UV_TILEWIDTH; + ps->plane_size[1] = ALIGN(ps->ystride[1] * + (uvHeight * TILEHEIGHT_SIZE / UV_TILEHEIGHT), + 4096); + + if (!sde_mdp_is_ubwc_format(fmt)) + goto done; + + ps->num_planes += 2; + + /* Y meta data stride and plane size */ + ps->ystride[2] = ALIGN(yWidth / Y_TILEWIDTH, 64); + ps->plane_size[2] = ALIGN(ps->ystride[2] * + ALIGN((yHeight / Y_TILEHEIGHT), 16), 4096); + + /* CbCr meta data stride and plane size */ + ps->ystride[3] = ALIGN(uvWidth / UV_TILEWIDTH, 64); + ps->plane_size[3] = ALIGN(ps->ystride[3] * + ALIGN((uvHeight / UV_TILEHEIGHT), 16), 4096); + } else if (sde_mdp_is_rgb_format(fmt)) { + uint32_t stride_alignment, bpp, aligned_bitstream_width; + + if (fmt->format == SDE_PIX_FMT_RGB_565_UBWC) { + stride_alignment = 128; + bpp = 2; + } else { + stride_alignment = 64; + bpp = 4; + } + + ps->num_planes = 1; + + /* RGB bitstream stride and plane size */ + aligned_bitstream_width = ALIGN(width, stride_alignment); + ps->ystride[0] = aligned_bitstream_width * bpp; + ps->plane_size[0] = ALIGN(bpp * aligned_bitstream_width * + ALIGN(height, 16), 4096); + + if (!sde_mdp_is_ubwc_format(fmt)) + goto done; + + ps->num_planes += 1; + + /* RGB meta data stride and plane size */ + ps->ystride[2] = ALIGN(DIV_ROUND_UP(aligned_bitstream_width, + 16), 64); + ps->plane_size[2] = ALIGN(ps->ystride[2] * + ALIGN(DIV_ROUND_UP(height, 4), 16), 4096); + } else { + SDEROT_ERR("%s: UBWC format not supported for fmt:%d\n", + __func__, fmt->format); + rc = -EINVAL; + } +done: + return rc; +} + +int sde_mdp_get_plane_sizes(struct sde_mdp_format_params *fmt, u32 w, u32 h, + struct sde_mdp_plane_sizes *ps, u32 bwc_mode, bool rotation) +{ + int i, rc = 0; + u32 bpp; + + if (ps == NULL) + return -EINVAL; + + if ((w > SDE_ROT_MAX_IMG_WIDTH) || (h > SDE_ROT_MAX_IMG_HEIGHT)) + return -ERANGE; + + bpp = fmt->bpp; + memset(ps, 0, sizeof(struct sde_mdp_plane_sizes)); + + if (sde_mdp_is_tilea5x_format(fmt)) { + rc = sde_mdp_get_a5x_plane_size(fmt, w, h, ps); + } else if (bwc_mode) { + u32 height, meta_size; + + rc = sde_mdp_get_rau_strides(w, h, fmt, ps); + if (rc) + return rc; + + height = DIV_ROUND_UP(h, ps->rau_h[0]); + meta_size = DIV_ROUND_UP(ps->rau_cnt, 8); + ps->ystride[1] += meta_size; + ps->ystride[0] += ps->ystride[1] + meta_size; + ps->plane_size[0] = ps->ystride[0] * height; + + ps->ystride[1] = 2; + ps->plane_size[1] = 2 * ps->rau_cnt * height; + + SDEROT_DBG("BWC data stride=%d size=%d meta size=%d\n", + ps->ystride[0], ps->plane_size[0], ps->plane_size[1]); + } else { + if (fmt->fetch_planes == SDE_MDP_PLANE_INTERLEAVED) { + ps->num_planes = 1; + ps->plane_size[0] = w * h * bpp; + ps->ystride[0] = w * bpp; + } else if (fmt->format == SDE_PIX_FMT_Y_CBCR_H2V2_VENUS || + fmt->format == SDE_PIX_FMT_Y_CRCB_H2V2_VENUS || + fmt->format == SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS) { + + int cf; + + switch (fmt->format) { + case SDE_PIX_FMT_Y_CBCR_H2V2_VENUS: + cf = COLOR_FMT_NV12; + break; + case SDE_PIX_FMT_Y_CRCB_H2V2_VENUS: + cf = COLOR_FMT_NV21; + break; + case SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS: + cf = COLOR_FMT_P010; + break; + default: + SDEROT_ERR("unknown color format %d\n", + fmt->format); + return -EINVAL; + } + + ps->num_planes = 2; + ps->ystride[0] = VENUS_Y_STRIDE(cf, w); + ps->ystride[1] = VENUS_UV_STRIDE(cf, w); + ps->plane_size[0] = VENUS_Y_SCANLINES(cf, h) * + ps->ystride[0]; + ps->plane_size[1] = VENUS_UV_SCANLINES(cf, h) * + ps->ystride[1]; + } else if (fmt->format == SDE_PIX_FMT_Y_CBCR_H2V2_P010) { + /* + * |<---Y1--->000000<---Y0--->000000| Plane0 + * |rrrrrrrrrr000000bbbbbbbbbb000000| Plane1 + * |--------------------------------| + * 33222222222211111111110000000000 Bit + * 10987654321098765432109876543210 Location + */ + ps->num_planes = 2; + ps->ystride[0] = w * 2; + ps->ystride[1] = w * 2; + ps->plane_size[0] = ps->ystride[0] * h; + ps->plane_size[1] = ps->ystride[1] * h / 2; + } else if (fmt->format == SDE_PIX_FMT_Y_CBCR_H2V2_TP10) { + u32 yWidth = sde_mdp_general_align(w, 192); + u32 yHeight = ALIGN(h, 16); + u32 uvWidth = sde_mdp_general_align(w, 192); + u32 uvHeight = (ALIGN(h, 32)) / 2; + + ps->num_planes = 2; + + ps->ystride[0] = (yWidth / 3) * 4; + ps->ystride[1] = (uvWidth / 3) * 4; + ps->plane_size[0] = ALIGN(ps->ystride[0] * yHeight, + 4096); + ps->plane_size[1] = ALIGN(ps->ystride[1] * uvHeight, + 4096); + } else { + u8 v_subsample, h_subsample, stride_align, height_align; + u32 chroma_samp; + + chroma_samp = fmt->chroma_sample; + + sde_mdp_get_v_h_subsample_rate(chroma_samp, + &v_subsample, &h_subsample); + + switch (fmt->format) { + case SDE_PIX_FMT_Y_CR_CB_GH2V2: + stride_align = 16; + height_align = 1; + break; + default: + stride_align = 1; + height_align = 1; + break; + } + + ps->ystride[0] = ALIGN(w, stride_align); + ps->ystride[1] = ALIGN(w / h_subsample, stride_align); + ps->plane_size[0] = ps->ystride[0] * + ALIGN(h, height_align); + ps->plane_size[1] = ps->ystride[1] * (h / v_subsample); + + if (fmt->fetch_planes == SDE_MDP_PLANE_PSEUDO_PLANAR) { + ps->num_planes = 2; + ps->plane_size[1] *= 2; + ps->ystride[1] *= 2; + } else { /* planar */ + ps->num_planes = 3; + ps->plane_size[2] = ps->plane_size[1]; + ps->ystride[2] = ps->ystride[1]; + } + } + } + + /* Safe to use MAX_PLANES as ps is memset at start of function */ + for (i = 0; i < SDE_ROT_MAX_PLANES; i++) + ps->total_size += ps->plane_size[i]; + + return rc; +} + +static int sde_mdp_a5x_data_check(struct sde_mdp_data *data, + struct sde_mdp_plane_sizes *ps, + struct sde_mdp_format_params *fmt) +{ + int i, inc; + unsigned long data_size = 0; + dma_addr_t base_addr; + + if (data->p[0].len == ps->plane_size[0]) + goto end; + + /* From this point, assumption is plane 0 is to be divided */ + data_size = data->p[0].len; + if (data_size < ps->total_size) { + SDEROT_ERR( + "insufficient current mem len=%lu required mem len=%u\n", + data_size, ps->total_size); + return -ENOMEM; + } + + base_addr = data->p[0].addr; + + if (sde_mdp_is_yuv_format(fmt)) { + /************************************************/ + /* UBWC ** */ + /* buffer ** MDP PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | Y meta | ** | Y bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Y bitstream | ** | CbCr bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | Cbcr metadata | ** | Y meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | CbCr bitstream | ** | CbCr meta | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /************************************************/ + + /* configure Y bitstream plane */ + data->p[0].addr = base_addr + ps->plane_size[2]; + data->p[0].len = ps->plane_size[0]; + + /* configure CbCr bitstream plane */ + data->p[1].addr = base_addr + ps->plane_size[0] + + ps->plane_size[2] + ps->plane_size[3]; + data->p[1].len = ps->plane_size[1]; + + if (!sde_mdp_is_ubwc_format(fmt)) + goto done; + + /* configure Y metadata plane */ + data->p[2].addr = base_addr; + data->p[2].len = ps->plane_size[2]; + + /* configure CbCr metadata plane */ + data->p[3].addr = base_addr + ps->plane_size[0] + + ps->plane_size[2]; + data->p[3].len = ps->plane_size[3]; + } else { + /************************************************/ + /* UBWC ** */ + /* buffer ** MDP PLANE */ + /* format ** */ + /************************************************/ + /* ------------------- ** -------------------- */ + /* | RGB meta | ** | RGB bitstream | */ + /* | data | ** | plane | */ + /* ------------------- ** -------------------- */ + /* | RGB bitstream | ** | NONE | */ + /* | data | ** | | */ + /* ------------------- ** -------------------- */ + /* ** | RGB meta | */ + /* ** | plane | */ + /* ** -------------------- */ + /************************************************/ + + /* configure RGB bitstream plane */ + data->p[0].addr = base_addr + ps->plane_size[2]; + data->p[0].len = ps->plane_size[0]; + + if (!sde_mdp_is_ubwc_format(fmt)) + goto done; + + /* configure RGB metadata plane */ + data->p[2].addr = base_addr; + data->p[2].len = ps->plane_size[2]; + } +done: + data->num_planes = ps->num_planes; + +end: + if (data->num_planes != ps->num_planes) { + SDEROT_ERR("num_planes don't match: fmt:%d, data:%d, ps:%d\n", + fmt->format, data->num_planes, ps->num_planes); + return -EINVAL; + } + + inc = (sde_mdp_is_yuv_format(fmt) ? 1 : 2); + for (i = 0; i < SDE_ROT_MAX_PLANES; i += inc) { + if (data->p[i].len != ps->plane_size[i]) { + SDEROT_ERR( + "plane:%d fmt:%d, len does not match: data:%lu, ps:%d\n", + i, fmt->format, data->p[i].len, + ps->plane_size[i]); + return -EINVAL; + } + } + + return 0; +} + +int sde_mdp_data_check(struct sde_mdp_data *data, + struct sde_mdp_plane_sizes *ps, + struct sde_mdp_format_params *fmt) +{ + struct sde_mdp_img_data *prev, *curr; + int i; + + if (!ps) + return 0; + + if (!data || data->num_planes == 0) + return -ENOMEM; + + if (sde_mdp_is_tilea5x_format(fmt)) + return sde_mdp_a5x_data_check(data, ps, fmt); + + SDEROT_DBG("srcp0=%pa len=%lu frame_size=%u\n", &data->p[0].addr, + data->p[0].len, ps->total_size); + + for (i = 0; i < ps->num_planes; i++) { + curr = &data->p[i]; + if (i >= data->num_planes) { + u32 psize = ps->plane_size[i-1]; + + prev = &data->p[i-1]; + if (prev->len > psize) { + curr->len = prev->len - psize; + prev->len = psize; + } + curr->addr = prev->addr + psize; + } + if (curr->len < ps->plane_size[i]) { + SDEROT_ERR("insufficient mem=%lu p=%d len=%u\n", + curr->len, i, ps->plane_size[i]); + return -ENOMEM; + } + SDEROT_DBG("plane[%d] addr=%pa len=%lu\n", i, + &curr->addr, curr->len); + } + data->num_planes = ps->num_planes; + + return 0; +} + +int sde_validate_offset_for_ubwc_format( + struct sde_mdp_format_params *fmt, u16 x, u16 y) +{ + int ret; + u16 micro_w = 0, micro_h = 0; + + ret = sde_rot_get_ubwc_micro_dim(fmt->format, µ_w, µ_h); + if (ret || !micro_w || !micro_h) { + SDEROT_ERR("Could not get valid micro tile dimensions\n"); + return -EINVAL; + } + + if (x % (micro_w * UBWC_META_MACRO_W_H)) { + SDEROT_ERR("x=%d does not align with meta width=%d\n", x, + micro_w * UBWC_META_MACRO_W_H); + return -EINVAL; + } + + if (y % (micro_h * UBWC_META_MACRO_W_H)) { + SDEROT_ERR("y=%d does not align with meta height=%d\n", y, + UBWC_META_MACRO_W_H); + return -EINVAL; + } + return ret; +} + +/* x and y are assumed to be valid, expected to line up with start of tiles */ +void sde_rot_ubwc_data_calc_offset(struct sde_mdp_data *data, u16 x, u16 y, + struct sde_mdp_plane_sizes *ps, struct sde_mdp_format_params *fmt) +{ + u16 macro_w, micro_w, micro_h; + u32 offset = 0; + int ret; + + ret = sde_rot_get_ubwc_micro_dim(fmt->format, µ_w, µ_h); + if (ret || !micro_w || !micro_h) { + SDEROT_ERR("Could not get valid micro tile dimensions\n"); + return; + } + macro_w = 4 * micro_w; + + if (sde_mdp_is_nv12_8b_format(fmt)) { + u16 chroma_macro_w = macro_w / 2; + u16 chroma_micro_w = micro_w / 2; + + /* plane 1 and 3 are chroma, with sub sample of 2 */ + offset = y * ps->ystride[0] + + (x / macro_w) * 4096; + if (offset < data->p[0].len) { + data->p[0].addr += offset; + } else { + ret = 1; + goto done; + } + + offset = y / 2 * ps->ystride[1] + + ((x / 2) / chroma_macro_w) * 4096; + if (offset < data->p[1].len) { + data->p[1].addr += offset; + } else { + ret = 2; + goto done; + } + + offset = (y / micro_h) * ps->ystride[2] + + ((x / micro_w) / UBWC_META_MACRO_W_H) * + UBWC_META_BLOCK_SIZE; + if (offset < data->p[2].len) { + data->p[2].addr += offset; + } else { + ret = 3; + goto done; + } + + offset = ((y / 2) / micro_h) * ps->ystride[3] + + (((x / 2) / chroma_micro_w) / UBWC_META_MACRO_W_H) * + UBWC_META_BLOCK_SIZE; + if (offset < data->p[3].len) { + data->p[3].addr += offset; + } else { + ret = 4; + goto done; + } + } else if (sde_mdp_is_nv12_10b_format(fmt)) { + /* TODO: */ + SDEROT_ERR("%c%c%c%c format not implemented yet", + fmt->format >> 0, fmt->format >> 8, + fmt->format >> 16, fmt->format >> 24); + ret = 1; + goto done; + } else { + offset = y * ps->ystride[0] + + (x / macro_w) * 4096; + if (offset < data->p[0].len) { + data->p[0].addr += offset; + } else { + ret = 1; + goto done; + } + + offset = DIV_ROUND_UP(y, micro_h) * ps->ystride[2] + + ((x / micro_w) / UBWC_META_MACRO_W_H) * + UBWC_META_BLOCK_SIZE; + if (offset < data->p[2].len) { + data->p[2].addr += offset; + } else { + ret = 3; + goto done; + } + } + +done: + if (ret) { + WARN(1, "idx %d, offsets:%u too large for buflen%lu\n", + (ret - 1), offset, data->p[(ret - 1)].len); + } +} + +void sde_rot_data_calc_offset(struct sde_mdp_data *data, u16 x, u16 y, + struct sde_mdp_plane_sizes *ps, struct sde_mdp_format_params *fmt) +{ + if ((x == 0) && (y == 0)) + return; + + if (sde_mdp_is_tilea5x_format(fmt)) { + sde_rot_ubwc_data_calc_offset(data, x, y, ps, fmt); + return; + } + + data->p[0].addr += y * ps->ystride[0]; + + if (data->num_planes == 1) { + data->p[0].addr += x * fmt->bpp; + } else { + u16 xoff, yoff; + u8 v_subsample, h_subsample; + + sde_mdp_get_v_h_subsample_rate(fmt->chroma_sample, + &v_subsample, &h_subsample); + + xoff = x / h_subsample; + yoff = y / v_subsample; + + data->p[0].addr += x; + data->p[1].addr += xoff + (yoff * ps->ystride[1]); + if (data->num_planes == 2) /* pseudo planar */ + data->p[1].addr += xoff; + else /* planar */ + data->p[2].addr += xoff + (yoff * ps->ystride[2]); + } +} + +static int sde_smmu_get_domain_type(u32 flags, bool rotator) +{ + int type; + + if (flags & SDE_SECURE_OVERLAY_SESSION) + type = SDE_IOMMU_DOMAIN_ROT_SECURE; + else + type = SDE_IOMMU_DOMAIN_ROT_UNSECURE; + + return type; +} + +static int sde_mdp_is_map_needed(struct sde_mdp_img_data *data) +{ + if (data->flags & SDE_SECURE_CAMERA_SESSION) + return false; + return true; +} + +static int sde_mdp_put_img(struct sde_mdp_img_data *data, bool rotator, + int dir) +{ + u32 domain; + + if (data->flags & SDE_ROT_EXT_IOVA) { + SDEROT_DBG("buffer %pad/%lx is client mapped\n", + &data->addr, data->len); + return 0; + } + + if (!IS_ERR_OR_NULL(data->srcp_dma_buf)) { + SDEROT_DBG("ion hdl=%pK buf=0x%pa\n", data->srcp_dma_buf, + &data->addr); + if (sde_mdp_is_map_needed(data) && data->mapped) { + domain = sde_smmu_get_domain_type(data->flags, + rotator); + data->mapped = false; + SDEROT_DBG("unmap %pad/%lx d:%u f:%x\n", &data->addr, + data->len, domain, data->flags); + } + if (!data->skip_detach) { + data->srcp_attachment->dma_map_attrs |= + DMA_ATTR_DELAYED_UNMAP; + dma_buf_unmap_attachment(data->srcp_attachment, + data->srcp_table, dir); + dma_buf_detach(data->srcp_dma_buf, + data->srcp_attachment); + if (!(data->flags & SDE_ROT_EXT_DMA_BUF)) { + dma_buf_put(data->srcp_dma_buf); + data->srcp_dma_buf = NULL; + } + data->skip_detach = true; + } + } else { + return -ENOMEM; + } + + return 0; +} + +static int sde_mdp_get_img(struct sde_fb_data *img, + struct sde_mdp_img_data *data, struct device *dev, + bool rotator, int dir) +{ + int ret = -EINVAL; + u32 domain; + + data->flags |= img->flags; + data->offset = img->offset; + if (data->flags & SDE_ROT_EXT_DMA_BUF) { + data->srcp_dma_buf = img->buffer; + } else if (data->flags & SDE_ROT_EXT_IOVA) { + data->addr = img->addr; + data->len = img->len; + SDEROT_DBG("use client %pad/%lx\n", &data->addr, data->len); + return 0; + } else if (IS_ERR(data->srcp_dma_buf)) { + SDEROT_ERR("error on ion_import_fd\n"); + ret = PTR_ERR(data->srcp_dma_buf); + data->srcp_dma_buf = NULL; + return ret; + } + + if (sde_mdp_is_map_needed(data)) { + domain = sde_smmu_get_domain_type(data->flags, rotator); + + SDEROT_DBG("%d domain=%d ihndl=%pK\n", + __LINE__, domain, data->srcp_dma_buf); + data->srcp_attachment = + sde_smmu_dma_buf_attach(data->srcp_dma_buf, dev, + domain); + if (IS_ERR(data->srcp_attachment)) { + SDEROT_ERR("%d Failed to attach dma buf\n", __LINE__); + ret = PTR_ERR(data->srcp_attachment); + goto err_put; + } + } else { + data->srcp_attachment = dma_buf_attach( + data->srcp_dma_buf, dev); + if (IS_ERR(data->srcp_attachment)) { + SDEROT_ERR( + "Failed to attach dma buf for secure camera\n"); + ret = PTR_ERR(data->srcp_attachment); + goto err_put; + } + } + + SDEROT_DBG("%d attach=%pK\n", __LINE__, data->srcp_attachment); + data->addr = 0; + data->len = 0; + data->mapped = false; + data->skip_detach = false; + /* return early, mapping will be done later */ + + return 0; +err_put: + if (!(data->flags & SDE_ROT_EXT_DMA_BUF)) { + dma_buf_put(data->srcp_dma_buf); + data->srcp_dma_buf = NULL; + } + return ret; +} + +static int sde_mdp_map_buffer(struct sde_mdp_img_data *data, bool rotator, + int dir) +{ + int ret = -EINVAL; + struct scatterlist *sg; + struct sg_table *sgt = NULL; + unsigned int i; + unsigned long flags = 0; + + if (data->addr && data->len) + return 0; + + if (data->flags & SDE_ROT_EXT_IOVA) { + SDEROT_DBG("buffer %pad/%lx is client mapped\n", + &data->addr, data->len); + return 0; + } + + if (!IS_ERR_OR_NULL(data->srcp_dma_buf)) { + /* + * dma_buf_map_attachment will call into + * dma_map_sg_attrs, and so all cache maintenance + * attribute and lazy unmap attribute will be all + * provided here. + */ + data->srcp_attachment->dma_map_attrs |= + DMA_ATTR_DELAYED_UNMAP; + + if (data->srcp_dma_buf && data->srcp_dma_buf->ops && + data->srcp_dma_buf->ops->get_flags) { + if (data->srcp_dma_buf->ops->get_flags( + data->srcp_dma_buf, + &flags) == 0) { + if ((flags & ION_FLAG_CACHED) == 0) { + SDEROT_DBG("dmabuf is uncached type\n"); + data->srcp_attachment->dma_map_attrs |= + DMA_ATTR_SKIP_CPU_SYNC; + } + } + } + + sgt = dma_buf_map_attachment( + data->srcp_attachment, dir); + if (IS_ERR_OR_NULL(sgt) || + IS_ERR_OR_NULL(sgt->sgl)) { + SDEROT_ERR("Failed to map attachment\n"); + ret = PTR_ERR(sgt); + goto err_detach; + } + data->srcp_table = sgt; + + data->len = 0; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + data->len += sg->length; + } + + if (sde_mdp_is_map_needed(data)) { + data->addr = data->srcp_table->sgl->dma_address; + SDEROT_DBG("map %pad/%lx f:%x\n", + &data->addr, + data->len, + data->flags); + data->mapped = true; + ret = 0; + } else { + if (sgt->nents != 1) { + SDEROT_ERR( + "Fail ion buffer mapping for secure camera\n"); + ret = -EINVAL; + goto err_unmap; + } + + if (((uint64_t)sg_dma_address(sgt->sgl) >= + PHY_ADDR_4G - sgt->sgl->length)) { + SDEROT_ERR( + "ion buffer mapped size invalid, size=%d\n", + sgt->sgl->length); + ret = -EINVAL; + goto err_unmap; + } + + data->addr = sg_phys(data->srcp_table->sgl); + ret = 0; + } + } + + if (!data->addr) { + SDEROT_ERR("start address is zero!\n"); + sde_mdp_put_img(data, rotator, dir); + return -ENOMEM; + } + + if (!ret && (data->offset < data->len)) { + data->addr += data->offset; + data->len -= data->offset; + + SDEROT_DBG("ihdl=%pK buf=0x%pa len=0x%lx\n", + data->srcp_dma_buf, &data->addr, data->len); + } else { + sde_mdp_put_img(data, rotator, dir); + return ret ? : -EOVERFLOW; + } + + return ret; + +err_unmap: + dma_buf_unmap_attachment(data->srcp_attachment, data->srcp_table, dir); +err_detach: + dma_buf_detach(data->srcp_dma_buf, data->srcp_attachment); + if (!(data->flags & SDE_ROT_EXT_DMA_BUF)) { + dma_buf_put(data->srcp_dma_buf); + data->srcp_dma_buf = NULL; + } + return ret; +} + +static int sde_mdp_data_get(struct sde_mdp_data *data, + struct sde_fb_data *planes, int num_planes, u32 flags, + struct device *dev, bool rotator, int dir) +{ + int i, rc = 0; + + if ((num_planes <= 0) || (num_planes > SDE_ROT_MAX_PLANES)) + return -EINVAL; + + for (i = 0; i < num_planes; i++) { + data->p[i].flags = flags; + rc = sde_mdp_get_img(&planes[i], &data->p[i], dev, rotator, + dir); + if (rc) { + SDEROT_ERR("failed to get buf p=%d flags=%x\n", + i, flags); + while (i > 0) { + i--; + sde_mdp_put_img(&data->p[i], rotator, dir); + } + break; + } + } + + data->num_planes = i; + + return rc; +} + +int sde_mdp_data_map(struct sde_mdp_data *data, bool rotator, int dir) +{ + int i, rc = 0; + + if (!data || !data->num_planes || data->num_planes > SDE_ROT_MAX_PLANES) + return -EINVAL; + + for (i = 0; i < data->num_planes; i++) { + rc = sde_mdp_map_buffer(&data->p[i], rotator, dir); + if (rc) { + SDEROT_ERR("failed to map buf p=%d\n", i); + while (i > 0) { + i--; + sde_mdp_put_img(&data->p[i], rotator, dir); + } + break; + } + } + SDEROT_EVTLOG(data->num_planes, dir, data->p[0].addr, data->p[0].len, + data->p[0].mapped); + + return rc; +} + +void sde_mdp_data_free(struct sde_mdp_data *data, bool rotator, int dir) +{ + int i; + + sde_smmu_ctrl(1); + for (i = 0; i < data->num_planes && data->p[i].len; i++) + sde_mdp_put_img(&data->p[i], rotator, dir); + sde_smmu_ctrl(0); + + data->num_planes = 0; +} + +int sde_mdp_data_get_and_validate_size(struct sde_mdp_data *data, + struct sde_fb_data *planes, int num_planes, u32 flags, + struct device *dev, bool rotator, int dir, + struct sde_layer_buffer *buffer) +{ + struct sde_mdp_format_params *fmt; + struct sde_mdp_plane_sizes ps; + int ret, i; + unsigned long total_buf_len = 0; + + fmt = sde_get_format_params(buffer->format); + if (!fmt) { + SDEROT_ERR("Format %d not supported\n", buffer->format); + return -EINVAL; + } + + ret = sde_mdp_data_get(data, planes, num_planes, + flags, dev, rotator, dir); + if (ret) + return ret; + + sde_mdp_get_plane_sizes(fmt, buffer->width, buffer->height, &ps, 0, 0); + + for (i = 0; i < num_planes ; i++) { + unsigned long plane_len = (data->p[i].srcp_dma_buf) ? + data->p[i].srcp_dma_buf->size : data->p[i].len; + + if (plane_len < planes[i].offset) { + SDEROT_ERR("Offset=%d larger than buffer size=%lu\n", + planes[i].offset, plane_len); + ret = -EINVAL; + goto buf_too_small; + } + total_buf_len += plane_len - planes[i].offset; + } + + if (total_buf_len < ps.total_size) { + SDEROT_ERR("Buffer size=%lu, expected size=%d\n", + total_buf_len, + ps.total_size); + ret = -EINVAL; + goto buf_too_small; + } + return 0; + +buf_too_small: + sde_mdp_data_free(data, rotator, dir); + return ret; +} + +static struct sg_table *sde_rot_dmabuf_map_tiny( + struct dma_buf_attachment *attach, enum dma_data_direction dir) +{ + struct sde_mdp_img_data *data = attach->dmabuf->priv; + struct sg_table *sgt; + unsigned int order; + struct page *p; + + if (!data) { + SDEROT_ERR("NULL img data\n"); + return NULL; + } + + if (data->len > PAGE_SIZE) { + SDEROT_ERR("DMA buffer size is larger than %ld, bufsize:%ld\n", + PAGE_SIZE, data->len); + return NULL; + } + + order = get_order(data->len); + p = alloc_pages(GFP_KERNEL, order); + if (!p) { + SDEROT_ERR("Fail allocating page for datasize:%ld\n", + data->len); + return NULL; + } + + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + goto free_alloc_pages; + + /* only alloc a single page */ + if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { + SDEROT_ERR("fail sg_alloc_table\n"); + goto free_sgt; + } + + sg_set_page(sgt->sgl, p, data->len, 0); + + if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) { + SDEROT_ERR("fail dma_map_sg\n"); + goto free_table; + } + + SDEROT_DBG("Successful generate sg_table:%pK datalen:%ld\n", + sgt, data->len); + return sgt; + +free_table: + sg_free_table(sgt); +free_sgt: + kfree(sgt); +free_alloc_pages: + __free_pages(p, order); + return NULL; +} + +static void sde_rot_dmabuf_unmap(struct dma_buf_attachment *attach, + struct sg_table *sgt, enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + SDEROT_DBG("DMABUF unmap, sgt:%pK\n", sgt); + dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir); + + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + put_page(sg_page(sg)); + __free_page(sg_page(sg)); + } + + sg_free_table(sgt); + kfree(sgt); +} + +static void *sde_rot_dmabuf_no_map(struct dma_buf *buf, unsigned long n) +{ + SDEROT_WARN("NOT SUPPORTING dmabuf map\n"); + return NULL; +} + +static void sde_rot_dmabuf_no_unmap(struct dma_buf *buf, unsigned long n, + void *addr) +{ + SDEROT_WARN("NOT SUPPORTING dmabuf unmap\n"); +} + +static void sde_rot_dmabuf_release(struct dma_buf *buf) +{ + SDEROT_DBG("Release dmabuf:%pK\n", buf); +} + +static int sde_rot_dmabuf_no_mmap(struct dma_buf *buf, + struct vm_area_struct *vma) +{ + SDEROT_WARN("NOT SUPPORTING dmabuf mmap\n"); + return -EINVAL; +} + +static const struct dma_buf_ops sde_rot_dmabuf_ops = { + .map_dma_buf = sde_rot_dmabuf_map_tiny, + .unmap_dma_buf = sde_rot_dmabuf_unmap, + .release = sde_rot_dmabuf_release, + .map = sde_rot_dmabuf_no_map, + .unmap = sde_rot_dmabuf_no_unmap, + .mmap = sde_rot_dmabuf_no_mmap, +}; + +struct dma_buf *sde_rot_get_dmabuf(struct sde_mdp_img_data *data) +{ + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + + exp_info.ops = &sde_rot_dmabuf_ops; + exp_info.size = (size_t)data->len; + exp_info.flags = O_RDWR; + exp_info.priv = data; + + return dma_buf_export(&exp_info); +} diff --git a/techpack/display/rotator/sde_rotator_util.h b/techpack/display/rotator/sde_rotator_util.h new file mode 100644 index 0000000000000000000000000000000000000000..85998200d7a23d8c56353e7fd104c648e5cbce4e --- /dev/null +++ b/techpack/display/rotator/sde_rotator_util.h @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __SDE_ROTATOR_UTIL_H__ +#define __SDE_ROTATOR_UTIL_H__ + +#include <linux/types.h> +#include <linux/file.h> +#include <linux/kref.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/dma-buf.h> + +#include "sde_rotator_hwio.h" +#include "sde_rotator_base.h" +#include "sde_rotator_sync.h" +#include "sde_rotator_io_util.h" +#include "sde_rotator_formats.h" + +#define SDE_ROT_MAX_IMG_WIDTH 0x3FFF +#define SDE_ROT_MAX_IMG_HEIGHT 0x3FFF + +#define SDEROT_DBG(fmt, ...) pr_debug("<SDEROT_DBG> " fmt, ##__VA_ARGS__) +#define SDEROT_INFO(fmt, ...) pr_info("<SDEROT_INFO> " fmt, ##__VA_ARGS__) +#define SDEROT_INFO_ONCE(fmt, ...) \ + pr_info_once("<SDEROT_INFO> " fmt, ##__VA_ARGS__) +#define SDEROT_WARN(fmt, ...) pr_warn("<SDEROT_WARN> " fmt, ##__VA_ARGS__) +#define SDEROT_ERR(fmt, ...) pr_err("<SDEROT_ERR> " fmt, ##__VA_ARGS__) +#define SDEDEV_DBG(dev, fmt, ...) \ + dev_dbg(dev, "<SDEROT_DBG> " fmt, ##__VA_ARGS__) +#define SDEDEV_INFO(dev, fmt, ...) \ + dev_info(dev, "<SDEROT_INFO> " fmt, ##__VA_ARGS__) +#define SDEDEV_WARN(dev, fmt, ...) \ + dev_warn(dev, "<SDEROT_WARN> " fmt, ##__VA_ARGS__) +#define SDEDEV_ERR(dev, fmt, ...) \ + dev_err(dev, "<SDEROT_ERR> " fmt, ##__VA_ARGS__) + +#define PHY_ADDR_4G (1ULL<<32) + +struct sde_rect { + u16 x; + u16 y; + u16 w; + u16 h; +}; + +/* sde flag values */ +#define SDE_ROT_NOP 0 +#define SDE_FLIP_LR 0x1 +#define SDE_FLIP_UD 0x2 +#define SDE_ROT_90 0x4 +#define SDE_ROT_180 (SDE_FLIP_UD|SDE_FLIP_LR) +#define SDE_ROT_270 (SDE_ROT_90|SDE_FLIP_UD|SDE_FLIP_LR) +#define SDE_DEINTERLACE 0x80000000 +#define SDE_SOURCE_ROTATED_90 0x00100000 +#define SDE_SECURE_OVERLAY_SESSION 0x00008000 +#define SDE_ROT_EXT_DMA_BUF 0x00010000 +#define SDE_SECURE_CAMERA_SESSION 0x00020000 +#define SDE_ROT_EXT_IOVA 0x00040000 + +struct sde_rot_data_type; + +struct sde_fb_data { + uint32_t offset; + struct dma_buf *buffer; + int memory_id; + int id; + uint32_t flags; + uint32_t priv; + dma_addr_t addr; + u32 len; +}; + +struct sde_layer_plane { + /* DMA buffer file descriptor information. */ + int fd; + struct dma_buf *buffer; + + /* i/o virtual address & length */ + dma_addr_t addr; + u32 len; + + /* Pixel offset in the dma buffer. */ + uint32_t offset; + + /* Number of bytes in one scan line including padding bytes. */ + uint32_t stride; +}; + +struct sde_layer_buffer { + /* layer width in pixels. */ + uint32_t width; + + /* layer height in pixels. */ + uint32_t height; + + /* + * layer format in DRM-style fourcc, refer drm_fourcc.h for + * standard formats + */ + uint32_t format; + + /* plane to hold the fd, offset, etc for all color components */ + struct sde_layer_plane planes[SDE_ROT_MAX_PLANES]; + + /* valid planes count in layer planes list */ + uint32_t plane_count; + + /* compression ratio factor, value depends on the pixel format */ + struct sde_mult_factor comp_ratio; + + /* + * SyncFence associated with this buffer. It is used in two ways. + * + * 1. Driver waits to consume the buffer till producer signals in case + * of primary and external display. + * + * 2. Writeback device uses buffer structure for output buffer where + * driver is producer. However, client sends the fence with buffer to + * indicate that consumer is still using the buffer and it is not ready + * for new content. + */ + struct sde_rot_sync_fence *fence; + + /* indicate if this is a stream (inline) buffer */ + bool sbuf; + + /* specify the system cache id in stream buffer mode */ + int scid; + + /* indicate if system cache writeback is required */ + bool writeback; +}; + +struct sde_mdp_plane_sizes { + u32 num_planes; + u32 plane_size[SDE_ROT_MAX_PLANES]; + u32 total_size; + u32 ystride[SDE_ROT_MAX_PLANES]; + u32 rau_cnt; + u32 rau_h[2]; +}; + +struct sde_mdp_img_data { + dma_addr_t addr; + unsigned long len; + u32 offset; + u32 flags; + bool mapped; + bool skip_detach; + struct fd srcp_f; + struct dma_buf *srcp_dma_buf; + struct dma_buf_attachment *srcp_attachment; + struct sg_table *srcp_table; +}; + +struct sde_mdp_data { + u8 num_planes; + struct sde_mdp_img_data p[SDE_ROT_MAX_PLANES]; + bool sbuf; + int scid; + bool writeback; +}; + +void sde_mdp_get_v_h_subsample_rate(u8 chroma_sample, + u8 *v_sample, u8 *h_sample); + +static inline u32 sde_mdp_general_align(u32 data, u32 alignment) +{ + return ((data + alignment - 1)/alignment) * alignment; +} + +void sde_rot_data_calc_offset(struct sde_mdp_data *data, u16 x, u16 y, + struct sde_mdp_plane_sizes *ps, struct sde_mdp_format_params *fmt); + +int sde_validate_offset_for_ubwc_format( + struct sde_mdp_format_params *fmt, u16 x, u16 y); + +int sde_mdp_data_get_and_validate_size(struct sde_mdp_data *data, + struct sde_fb_data *planes, int num_planes, u32 flags, + struct device *dev, bool rotator, int dir, + struct sde_layer_buffer *buffer); + +int sde_mdp_get_plane_sizes(struct sde_mdp_format_params *fmt, u32 w, u32 h, + struct sde_mdp_plane_sizes *ps, u32 bwc_mode, + bool rotation); + +int sde_mdp_data_map(struct sde_mdp_data *data, bool rotator, int dir); + +int sde_mdp_data_check(struct sde_mdp_data *data, + struct sde_mdp_plane_sizes *ps, + struct sde_mdp_format_params *fmt); + +void sde_mdp_data_free(struct sde_mdp_data *data, bool rotator, int dir); + +struct dma_buf *sde_rot_get_dmabuf(struct sde_mdp_img_data *data); +#endif /* __SDE_ROTATOR_UTIL_H__ */ diff --git a/techpack/display/rotator/sde_rotator_vbif.h b/techpack/display/rotator/sde_rotator_vbif.h new file mode 100644 index 0000000000000000000000000000000000000000..c7b671f3df878ab7627f4c97ff8e355f51820699 --- /dev/null +++ b/techpack/display/rotator/sde_rotator_vbif.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ +#ifndef __SDE_ROTATOR_VBIF_H__ +#define __SDE_ROTATOR_VBIF_H__ + +void mdp_vbif_lock(struct platform_device *parent_pdev, bool enable); + +#endif /* __SDE_ROTATOR_VBIF_H__ */ \ No newline at end of file diff --git a/techpack/video/Makefile b/techpack/video/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0235ce8844585d5f5102141e1d30d3427a7a1fb8 --- /dev/null +++ b/techpack/video/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only + +# auto-detect subdirs +ifeq ($(CONFIG_ARCH_KONA), y) +include $(srctree)/techpack/video/config/konavid.conf +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +LINUXINCLUDE += -include $(srctree)/techpack/video/config/konavidconf.h +endif + +# auto-detect subdirs +ifeq ($(CONFIG_ARCH_LITO), y) +include $(srctree)/techpack/video/config/litovid.conf +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +LINUXINCLUDE += -include $(srctree)/techpack/video/config/litovidconf.h +endif + +# auto-detect subdirs +ifeq ($(CONFIG_ARCH_BENGAL), y) +include $(srctree)/techpack/video/config/bengalvid.conf +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +LINUXINCLUDE += -include $(srctree)/techpack/video/config/bengalvidconf.h +endif + +obj-y +=msm/ diff --git a/techpack/video/config/bengalvid.conf b/techpack/video/config/bengalvid.conf new file mode 100644 index 0000000000000000000000000000000000000000..efb4eedfb73eff55cfc5454163fc78904565a16f --- /dev/null +++ b/techpack/video/config/bengalvid.conf @@ -0,0 +1 @@ +export CONFIG_MSM_VIDC_V4L2=y diff --git a/techpack/video/config/bengalvidconf.h b/techpack/video/config/bengalvidconf.h new file mode 100644 index 0000000000000000000000000000000000000000..78d6c57a69203362ec4f707dfb6eb4847125d84a --- /dev/null +++ b/techpack/video/config/bengalvidconf.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_MSM_VIDC_V4L2 1 diff --git a/techpack/video/config/konavid.conf b/techpack/video/config/konavid.conf new file mode 100644 index 0000000000000000000000000000000000000000..efb4eedfb73eff55cfc5454163fc78904565a16f --- /dev/null +++ b/techpack/video/config/konavid.conf @@ -0,0 +1 @@ +export CONFIG_MSM_VIDC_V4L2=y diff --git a/techpack/video/config/konavidconf.h b/techpack/video/config/konavidconf.h new file mode 100644 index 0000000000000000000000000000000000000000..da305d52ecd116a7a4ab84b49dd228154c2d12f2 --- /dev/null +++ b/techpack/video/config/konavidconf.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_MSM_VIDC_V4L2 1 diff --git a/techpack/video/config/litovid.conf b/techpack/video/config/litovid.conf new file mode 100644 index 0000000000000000000000000000000000000000..efb4eedfb73eff55cfc5454163fc78904565a16f --- /dev/null +++ b/techpack/video/config/litovid.conf @@ -0,0 +1 @@ +export CONFIG_MSM_VIDC_V4L2=y diff --git a/techpack/video/config/litovidconf.h b/techpack/video/config/litovidconf.h new file mode 100644 index 0000000000000000000000000000000000000000..78d6c57a69203362ec4f707dfb6eb4847125d84a --- /dev/null +++ b/techpack/video/config/litovidconf.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_MSM_VIDC_V4L2 1 diff --git a/techpack/video/msm/Makefile b/techpack/video/msm/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d0544d5c6a5588d30350de2cf370db51869badcb --- /dev/null +++ b/techpack/video/msm/Makefile @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-only +ccflags-y += -I$(srctree)/techpack/video/msm/vidc/ \ + -I$(srctree)/drivers/devfreq/ + +msm-vidc-objs := vidc/msm_v4l2_vidc.o \ + vidc/msm_v4l2_private.o \ + vidc/msm_vidc_platform.o \ + vidc/msm_vidc_common.o \ + vidc/msm_vidc.o \ + vidc/msm_vdec.o \ + vidc/msm_venc.o \ + vidc/msm_cvp_internal.o \ + vidc/msm_smem.o \ + vidc/msm_vidc_debug.o \ + vidc/msm_vidc_res_parse.o \ + vidc/hfi_common.o \ + vidc/hfi_ar50.o \ + vidc/hfi_ar50_lt.o \ + vidc/hfi_iris1.o \ + vidc/hfi_iris2.o \ + vidc/hfi_response_handler.o \ + vidc/hfi_packetization.o \ + vidc/vidc_hfi.o \ + vidc/msm_vidc_clocks.o \ + vidc/msm_vidc_bus_ar50lite.o\ + vidc/msm_vidc_bus_iris1.o \ + vidc/msm_vidc_bus_iris2.o \ + vidc/msm_vidc_buffer_calculations.o + +obj-$(CONFIG_MSM_VIDC_V4L2) := msm-vidc.o + diff --git a/techpack/video/msm/vidc/fixedpoint.h b/techpack/video/msm/vidc/fixedpoint.h new file mode 100644 index 0000000000000000000000000000000000000000..6a28ed839f684616aee4b79debb8f23129581c35 --- /dev/null +++ b/techpack/video/msm/vidc/fixedpoint.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#ifdef _FIXP_ARITH_H +#error "This implementation is meant to override fixp-arith.h, don't use both" +#endif + +#ifndef _FIXEDPOINT_H_ +#define _FIXEDPOINT_H_ + +#include <linux/types.h> +#include <linux/bits.h> + +/* + * Normally would typedef'ed, but checkpatch doesn't like typedef. + * Also should be normally typedef'ed to intmax_t but that doesn't seem to be + * available in the kernel + */ +#define fp_t size_t + +/* (Arbitrarily) make the first 25% of the bits to be the fractional bits */ +#define FP_FRACTIONAL_BITS ((sizeof(fp_t) * 8) / 4) + +#define FP(__i, __f_n, __f_d) \ + ((((fp_t)(__i)) << FP_FRACTIONAL_BITS) + \ + (((__f_n) << FP_FRACTIONAL_BITS) / (__f_d))) + +#define FP_INT(__i) FP(__i, 0, 1) +#define FP_ONE FP_INT(1) +#define FP_ZERO FP_INT(0) + +static inline size_t fp_frac_base(void) +{ + return GENMASK(FP_FRACTIONAL_BITS - 1, 0); +} + +static inline size_t fp_frac(fp_t a) +{ + return a & GENMASK(FP_FRACTIONAL_BITS - 1, 0); +} + +static inline size_t fp_int(fp_t a) +{ + return a >> FP_FRACTIONAL_BITS; +} + +static inline size_t fp_round(fp_t a) +{ + /* is the fractional part >= frac_max / 2? */ + bool round_up = fp_frac(a) >= fp_frac_base() / 2; + + return fp_int(a) + round_up; +} + +static inline fp_t fp_mult(fp_t a, fp_t b) +{ + return (a * b) >> FP_FRACTIONAL_BITS; +} + + +static inline fp_t fp_div(fp_t a, fp_t b) +{ + return (a << FP_FRACTIONAL_BITS) / b; +} + +#endif diff --git a/techpack/video/msm/vidc/hfi_ar50.c b/techpack/video/msm/vidc/hfi_ar50.c new file mode 100644 index 0000000000000000000000000000000000000000..55f3f5ee924786764e3bd18a01d2063060520700 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_ar50.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "hfi_common.h" +#include "hfi_io_common.h" + +void __interrupt_init_ar50(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, WRAPPER_INTR_MASK, + WRAPPER_INTR_MASK_A2HVCODEC_BMSK, sid); +} diff --git a/techpack/video/msm/vidc/hfi_ar50_lt.c b/techpack/video/msm/vidc/hfi_ar50_lt.c new file mode 100644 index 0000000000000000000000000000000000000000..db709a0d028153c767e7d3803bfe37c967e2ba7a --- /dev/null +++ b/techpack/video/msm/vidc/hfi_ar50_lt.c @@ -0,0 +1,276 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_debug.h" +#include "hfi_common.h" + +#define VIDC_CPU_BASE_OFFS_AR50_LT 0x000A0000 +#define VIDEO_GCC_BASE_OFFS_AR50_LT 0x00000000 +#define VIDEO_CC_BASE_OFFS_AR50_LT 0x00100000 + +#define VIDC_CPU_CS_BASE_OFFS_AR50_LT (VIDC_CPU_BASE_OFFS_AR50_LT) +#define VIDC_CPU_IC_BASE_OFFS_AR50_LT (VIDC_CPU_BASE_OFFS_AR50_LT) + +#define VIDC_CPU_CS_A2HSOFTINTCLR_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x1C) +#define VIDC_CPU_CS_VMIMSG_AR50_LTi (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x34) +#define VIDC_CPU_CS_VMIMSGAG0_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x38) +#define VIDC_CPU_CS_VMIMSGAG1_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x3C) +#define VIDC_CPU_CS_VMIMSGAG2_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x40) +#define VIDC_CPU_CS_VMIMSGAG3_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x44) +#define VIDC_CPU_CS_SCIACMD_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x48) + +/* HFI_CTRL_STATUS */ +#define VIDC_CPU_CS_SCIACMDARG0_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x4C) +#define VIDC_CPU_CS_SCIACMDARG0_BMSK_AR50_LT 0xff +#define VIDC_CPU_CS_SCIACMDARG0_SHFT_AR50_LT 0x0 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_AR50_LT 0xfe +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT_AR50_LT 0x1 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK_AR50_LT 0x1 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT_AR50_LT 0x0 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_AR50_LT 0x100 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT 0x40000000 + +/* HFI_QTBL_INFO */ +#define VIDC_CPU_CS_SCIACMDARG1_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x50) + +/* HFI_QTBL_ADDR */ +#define VIDC_CPU_CS_SCIACMDARG2_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x54) + +/* HFI_VERSION_INFO */ +#define VIDC_CPU_CS_SCIACMDARG3_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x58) + +/* VIDC_SFR_ADDR */ +#define VIDC_CPU_CS_SCIBCMD_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x5C) + +/* VIDC_MMAP_ADDR */ +#define VIDC_CPU_CS_SCIBCMDARG0_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x60) + +/* VIDC_UC_REGION_ADDR */ +#define VIDC_CPU_CS_SCIBARG1_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x64) + +/* VIDC_UC_REGION_ADDR */ +#define VIDC_CPU_CS_SCIBARG2_AR50_LT (VIDC_CPU_CS_BASE_OFFS_AR50_LT + 0x68) + +#define VIDC_CPU_IC_SOFTINT_EN_AR50_LT (VIDC_CPU_IC_BASE_OFFS_AR50_LT + 0x148) +#define VIDC_CPU_IC_SOFTINT_AR50_LT (VIDC_CPU_IC_BASE_OFFS_AR50_LT + 0x150) +#define VIDC_CPU_IC_SOFTINT_H2A_BMSK_AR50_LT 0x8000 +#define VIDC_CPU_IC_SOFTINT_H2A_SHFT_AR50_LT 0x1 + +/* + * -------------------------------------------------------------------------- + * MODULE: vidc_wrapper + * -------------------------------------------------------------------------- + */ +#define VIDC_WRAPPER_BASE_OFFS_AR50_LT 0x000B0000 + +#define VIDC_WRAPPER_HW_VERSION_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x00) +#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK_AR50_LT 0x78000000 +#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT_AR50_LT 28 +#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK_AR50_LT 0xFFF0000 +#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT_AR50_LT 16 +#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK_AR50_LT 0xFFFF + +#define VIDC_WRAPPER_CLOCK_CONFIG_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x04) + +#define VIDC_WRAPPER_INTR_STATUS_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x0C) +#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK_AR50_LT 0x10 +#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT_AR50_LT 0x4 +#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK_AR50_LT 0x4 +#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT_AR50_LT 0x2 + +#define VIDC_WRAPPER_INTR_MASK_AR50_LT (VIDC_WRAPPER_BASE_OFFS_AR50_LT + 0x10) +#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK_AR50_LT 0x10 +#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT_AR50_LT 0x4 +#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK_AR50_LT 0x8 +#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK_AR50_LT 0x4 +#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT_AR50_LT 0x2 + +#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK_AR50_LT 0x10 +#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT_AR50_LT 0x4 +#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK_AR50_LT 0x4 +#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT_AR50_LT 0x2 + +/* + * -------------------------------------------------------------------------- + * MODULE: tz_wrapper + * -------------------------------------------------------------------------- + */ +#define VIDC_WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define VIDC_WRAPPER_TZ_CPU_CLOCK_CONFIG (VIDC_WRAPPER_TZ_BASE_OFFS) +#define VIDC_WRAPPER_TZ_CPU_STATUS (VIDC_WRAPPER_TZ_BASE_OFFS + 0x10) + +#define VIDC_CTRL_INIT_AR50_LT VIDC_CPU_CS_SCIACMD_AR50_LT + +#define VIDC_CTRL_STATUS_AR50_LT VIDC_CPU_CS_SCIACMDARG0_AR50_LT +#define VIDC_CTRL_ERROR_STATUS__M_AR50_LT \ + VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_AR50_LT +#define VIDC_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT \ + VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT +#define VIDC_CTRL_STATUS_PC_READY_AR50_LT \ + VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_AR50_LT + +#define VIDC_QTBL_INFO_AR50_LT VIDC_CPU_CS_SCIACMDARG1_AR50_LT +#define VIDC_QTBL_ADDR_AR50_LT VIDC_CPU_CS_SCIACMDARG2_AR50_LT +#define VIDC_VERSION_INFO_AR50_LT VIDC_CPU_CS_SCIACMDARG3_AR50_LT + +#define VIDC_SFR_ADDR_AR50_LT VIDC_CPU_CS_SCIBCMD_AR50_LT +#define VIDC_MMAP_ADDR_AR50_LT VIDC_CPU_CS_SCIBCMDARG0_AR50_LT +#define VIDC_UC_REGION_ADDR_AR50_LT VIDC_CPU_CS_SCIBARG1_AR50_LT +#define VIDC_UC_REGION_SIZE_AR50_LT VIDC_CPU_CS_SCIBARG2_AR50_LT + +void __interrupt_init_ar50_lt(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, VIDC_WRAPPER_INTR_MASK_AR50_LT, + VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK_AR50_LT, sid); +} + +void __setup_ucregion_memory_map_ar50_lt(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, VIDC_UC_REGION_ADDR_AR50_LT, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, VIDC_UC_REGION_SIZE_AR50_LT, SHARED_QSIZE, sid); + __write_register(device, VIDC_QTBL_ADDR_AR50_LT, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, VIDC_QTBL_INFO_AR50_LT, 0x01, sid); + if (device->sfr.align_device_addr) + __write_register(device, VIDC_SFR_ADDR_AR50_LT, + (u32)device->sfr.align_device_addr, sid); + if (device->qdss.align_device_addr) + __write_register(device, VIDC_MMAP_ADDR_AR50_LT, + (u32)device->qdss.align_device_addr, sid); +} + +void __power_off_ar50_lt(struct venus_hfi_device *device) +{ + if (!device->power_enabled) + return; + + if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK_AR50_LT)) + disable_irq_nosync(device->hal_data->irq); + device->intr_status = 0; + + __disable_unprepare_clks(device); + if (__disable_regulators(device)) + d_vpr_e("Failed to disable regulators\n"); + + if (__unvote_buses(device, DEFAULT_SID)) + d_vpr_e("Failed to unvote for buses\n"); + device->power_enabled = false; +} + +int __prepare_pc_ar50_lt(struct venus_hfi_device *device) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 ctrl_status = 0; + u32 count = 0, max_tries = 10; + + ctrl_status = __read_register(device, VIDC_CTRL_STATUS_AR50_LT, DEFAULT_SID); + pc_ready = ctrl_status & VIDC_CTRL_STATUS_PC_READY_AR50_LT; + idle_status = ctrl_status & BIT(30); + + if (pc_ready) { + d_vpr_l("Already in pc_ready state\n"); + return 0; + } + + wfi_status = BIT(0) & __read_register(device, + VIDC_WRAPPER_TZ_CPU_STATUS, DEFAULT_SID); + if (!wfi_status || !idle_status) { + d_vpr_e("Skipping PC, wfi status not set\n"); + goto skip_power_off; + } + + rc = __prepare_pc(device); + if (rc) { + d_vpr_e("Failed __prepare_pc %d\n", rc); + goto skip_power_off; + } + + while (count < max_tries) { + wfi_status = BIT(0) & __read_register(device, + VIDC_WRAPPER_TZ_CPU_STATUS, DEFAULT_SID); + ctrl_status = __read_register(device, + VIDC_CTRL_STATUS_AR50_LT, DEFAULT_SID); + pc_ready = ctrl_status & VIDC_CTRL_STATUS_PC_READY_AR50_LT; + if (wfi_status && pc_ready) + break; + usleep_range(150, 250); + count++; + } + + if (count == max_tries) { + d_vpr_e("Skip PC. Core is not in right state\n"); + goto skip_power_off; + } + + return rc; + +skip_power_off: + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + return -EAGAIN; +} + +void __raise_interrupt_ar50_lt(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, VIDC_CPU_IC_SOFTINT_AR50_LT, + VIDC_CPU_IC_SOFTINT_H2A_SHFT_AR50_LT, sid); +} + +void __core_clear_interrupt_ar50_lt(struct venus_hfi_device *device) +{ + u32 intr_status = 0, mask = 0; + + if (!device) { + d_vpr_e("%s: NULL device\n", __func__); + return; + } + + intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS_AR50_LT, DEFAULT_SID); + mask = (VIDC_WRAPPER_INTR_STATUS_A2H_BMSK_AR50_LT | + VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK_AR50_LT | + VIDC_CTRL_INIT_IDLE_MSG_BMSK_AR50_LT); + + if (intr_status & mask) { + device->intr_status |= intr_status; + device->reg_count++; + d_vpr_l( + "INTERRUPT for device: %pK: times: %d interrupt_status: %d\n", + device, device->reg_count, intr_status); + } else { + device->spur_count++; + } + + __write_register(device, VIDC_CPU_CS_A2HSOFTINTCLR_AR50_LT, 1, DEFAULT_SID); +} + +int __boot_firmware_ar50_lt(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000; + + ctrl_init_val = BIT(0); + + __write_register(device, VIDC_CTRL_INIT_AR50_LT, ctrl_init_val, sid); + while (!ctrl_status && count < max_tries) { + ctrl_status = __read_register(device, VIDC_CTRL_STATUS_AR50_LT, sid); + if ((ctrl_status & VIDC_CTRL_ERROR_STATUS__M_AR50_LT) == 0x4) { + s_vpr_e(sid, "invalid setting for UC_REGION\n"); + break; + } + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + s_vpr_e(sid, "Error booting up vidc firmware\n"); + rc = -ETIME; + } + + /* Enable interrupt before sending commands to venus */ + __write_register(device, VIDC_CPU_IC_SOFTINT_EN_AR50_LT, 0x1, sid); + return rc; +} diff --git a/techpack/video/msm/vidc/hfi_common.c b/techpack/video/msm/vidc/hfi_common.c new file mode 100644 index 0000000000000000000000000000000000000000..d7223d8287b3ce5b371f49ad334f73befb09b001 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_common.c @@ -0,0 +1,4947 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <asm/dma-iommu.h> +#include <asm/memory.h> +#include <linux/clk/qcom.h> +#include <linux/coresight-stm.h> +#include <linux/delay.h> +#include <linux/hash.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iommu.h> +#include <linux/iopoll.h> +#include <linux/of.h> +#include <linux/pm_qos.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/soc/qcom/llcc-qcom.h> +#include <soc/qcom/cx_ipeak.h> +#include <soc/qcom/scm.h> +#include <soc/qcom/socinfo.h> +#include <linux/soc/qcom/smem.h> +#include <soc/qcom/subsystem_restart.h> +#include <linux/dma-mapping.h> +#include <linux/fastcvpd.h> +#include <linux/reset.h> +#include "hfi_packetization.h" +#include "msm_vidc_debug.h" +#include "hfi_common.h" +#include "hfi_io_common.h" + +#define FIRMWARE_SIZE 0X00A00000 +#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF +#define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 + +static struct hal_device_data hal_ctxt; +static struct venus_hfi_device venus_hfi_dev; + +#define TZBSP_MEM_PROTECT_VIDEO_VAR 0x8 +struct tzbsp_memprot { + u32 cp_start; + u32 cp_size; + u32 cp_nonpixel_start; + u32 cp_nonpixel_size; +}; + +struct tzbsp_resp { + int ret; +}; + +#define TZBSP_VIDEO_SET_STATE 0xa + +/* Poll interval in uS */ +#define POLL_INTERVAL_US 50 + +enum tzbsp_video_state { + TZBSP_VIDEO_STATE_SUSPEND = 0, + TZBSP_VIDEO_STATE_RESUME = 1, + TZBSP_VIDEO_STATE_RESTORE_THRESHOLD = 2, +}; + +struct tzbsp_video_set_state_req { + u32 state; /* should be tzbsp_video_state enum value */ + u32 spare; /* reserved for future, should be zero */ +}; + +const struct msm_vidc_bus_data DEFAULT_BUS_VOTE = { + .total_bw_ddr = 0, + .total_bw_llcc = 0, +}; + +/* Less than 50MBps is treated as trivial BW change */ +#define TRIVIAL_BW_THRESHOLD 50000 +#define TRIVIAL_BW_CHANGE(a, b) \ + ((a) > (b) ? (a) - (b) < TRIVIAL_BW_THRESHOLD : \ + (b) - (a) < TRIVIAL_BW_THRESHOLD) + +const int max_packets = 480; /* 16 sessions x 30 packets */ + +static void venus_hfi_pm_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_hfi_pm_handler); +static inline int __resume(struct venus_hfi_device *device, u32 sid); +static inline int __suspend(struct venus_hfi_device *device); +static int __enable_regulators(struct venus_hfi_device *device, u32 sid); +static inline int __prepare_enable_clks( + struct venus_hfi_device *device, u32 sid); +static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet); +static int __initialize_packetization(struct venus_hfi_device *device); +static struct hal_session *__get_session(struct venus_hfi_device *device, + u32 sid); +static bool __is_session_valid(struct venus_hfi_device *device, + struct hal_session *session, const char *func); +static int __set_clocks(struct venus_hfi_device *device, u32 freq, u32 sid); +static int __iface_cmdq_write(struct venus_hfi_device *device, + void *pkt, u32 sid); +static int __load_fw(struct venus_hfi_device *device); +static void __unload_fw(struct venus_hfi_device *device); +static int __tzbsp_set_video_state(enum tzbsp_video_state state, u32 sid); +static int __enable_subcaches(struct venus_hfi_device *device, u32 sid); +static int __set_subcaches(struct venus_hfi_device *device, u32 sid); +static int __release_subcaches(struct venus_hfi_device *device, u32 sid); +static int __disable_subcaches(struct venus_hfi_device *device, u32 sid); +static int __power_collapse(struct venus_hfi_device *device, bool force); +static int venus_hfi_noc_error_info(void *dev); +static int __set_ubwc_config(struct venus_hfi_device *device); +static void __power_off_common(struct venus_hfi_device *device); +static int __prepare_pc_common(struct venus_hfi_device *device); +static void __raise_interrupt_common(struct venus_hfi_device *device, u32 sid); +static bool __watchdog_common(u32 intr_status); +static void __noc_error_info_common(struct venus_hfi_device *device); +static void __core_clear_interrupt_common(struct venus_hfi_device *device); +static inline int __boot_firmware_common( + struct venus_hfi_device *device, u32 sid); +static void __setup_ucregion_memory_map_common( + struct venus_hfi_device *device, u32 sid); + +struct venus_hfi_vpu_ops vpu4_ops = { + .interrupt_init = __interrupt_init_ar50, + .setup_ucregion_memmap = __setup_ucregion_memory_map_common, + .clock_config_on_enable = NULL, + .reset_ahb2axi_bridge = NULL, + .power_off = __power_off_common, + .prepare_pc = __prepare_pc_common, + .raise_interrupt = __raise_interrupt_common, + .watchdog = __watchdog_common, + .noc_error_info = __noc_error_info_common, + .core_clear_interrupt = __core_clear_interrupt_common, + .boot_firmware = __boot_firmware_common, +}; + +struct venus_hfi_vpu_ops ar50_lite_ops = { + .interrupt_init = __interrupt_init_ar50_lt, + .setup_ucregion_memmap = __setup_ucregion_memory_map_ar50_lt, + .clock_config_on_enable = NULL, + .reset_ahb2axi_bridge = NULL, + .power_off = __power_off_ar50_lt, + .prepare_pc = __prepare_pc_ar50_lt, + .raise_interrupt = __raise_interrupt_ar50_lt, + .watchdog = __watchdog_common, + .noc_error_info = NULL, + .core_clear_interrupt = __core_clear_interrupt_ar50_lt, + .boot_firmware = __boot_firmware_ar50_lt, +}; + +struct venus_hfi_vpu_ops iris1_ops = { + .interrupt_init = __interrupt_init_iris1, + .setup_ucregion_memmap = __setup_ucregion_memory_map_iris1, + .clock_config_on_enable = __clock_config_on_enable_iris1, + .reset_ahb2axi_bridge = __reset_ahb2axi_bridge_common, + .power_off = __power_off_common, + .prepare_pc = __prepare_pc_common, + .raise_interrupt = __raise_interrupt_common, + .watchdog = __watchdog_common, + .noc_error_info = __noc_error_info_common, + .core_clear_interrupt = __core_clear_interrupt_common, + .boot_firmware = __boot_firmware_common, +}; + +struct venus_hfi_vpu_ops iris2_ops = { + .interrupt_init = __interrupt_init_iris2, + .setup_ucregion_memmap = __setup_ucregion_memory_map_iris2, + .clock_config_on_enable = NULL, + .reset_ahb2axi_bridge = __reset_ahb2axi_bridge_common, + .power_off = __power_off_iris2, + .prepare_pc = __prepare_pc_iris2, + .raise_interrupt = __raise_interrupt_iris2, + .watchdog = __watchdog_iris2, + .noc_error_info = __noc_error_info_iris2, + .core_clear_interrupt = __core_clear_interrupt_iris2, + .boot_firmware = __boot_firmware_iris2, +}; + +/** + * Utility function to enforce some of our assumptions. Spam calls to this + * in hotspots in code to double check some of the assumptions that we hold. + */ +static inline void __strict_check(struct venus_hfi_device *device) +{ + msm_vidc_res_handle_fatal_hw_error(device->res, + !mutex_is_locked(&device->lock)); +} + +static inline void __set_state(struct venus_hfi_device *device, + enum venus_hfi_state state) +{ + device->state = state; +} + +static inline bool __core_in_valid_state(struct venus_hfi_device *device) +{ + return device->state != VENUS_STATE_DEINIT; +} + +static inline bool is_sys_cache_present(struct venus_hfi_device *device) +{ + return device->res->sys_cache_present; +} + +static void __dump_packet(u8 *packet, u32 sid) +{ + u32 c = 0, packet_size = *(u32 *)packet; + const int row_size = 32; + /* + * row must contain enough for 0xdeadbaad * 8 to be converted into + * "de ad ba ab " * 8 + '\0' + */ + char row[3 * 32]; + + for (c = 0; c * row_size < packet_size; ++c) { + int bytes_to_read = ((c + 1) * row_size > packet_size) ? + packet_size % row_size : row_size; + hex_dump_to_buffer(packet + c * row_size, bytes_to_read, + row_size, 4, row, sizeof(row), false); + s_vpr_t(sid, "%s\n", row); + } +} + +static void __sim_modify_cmd_packet(u8 *packet, struct venus_hfi_device *device) +{ + struct hfi_cmd_sys_session_init_packet *sys_init; + struct hal_session *session = NULL; + u8 i; + phys_addr_t fw_bias = 0; + + sys_init = (struct hfi_cmd_sys_session_init_packet *)packet; + if (!device || !sys_init) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, device, sys_init); + return; + } else if (!device->hal_data->firmware_base + || is_iommu_present(device->res)) { + return; + } + fw_bias = device->hal_data->firmware_base; + + session = __get_session(device, sys_init->sid); + if (!session) { + d_vpr_e("%s: Invalid session id\n", __func__); + return; + } + + switch (sys_init->packet_type) { + case HFI_CMD_SESSION_EMPTY_BUFFER: + if (session->is_decoder) { + struct hfi_cmd_session_empty_buffer_compressed_packet + *pkt = (struct + hfi_cmd_session_empty_buffer_compressed_packet + *) packet; + pkt->packet_buffer -= fw_bias; + } else { + struct + hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + *pkt = (struct + hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + *) packet; + pkt->packet_buffer -= fw_bias; + } + break; + case HFI_CMD_SESSION_FILL_BUFFER: + { + struct hfi_cmd_session_fill_buffer_packet *pkt = + (struct hfi_cmd_session_fill_buffer_packet *)packet; + pkt->packet_buffer -= fw_bias; + break; + } + case HFI_CMD_SESSION_SET_BUFFERS: + { + struct hfi_cmd_session_set_buffers_packet *pkt = + (struct hfi_cmd_session_set_buffers_packet *)packet; + if (pkt->buffer_type == HFI_BUFFER_OUTPUT || + pkt->buffer_type == HFI_BUFFER_OUTPUT2) { + struct hfi_buffer_info *buff; + + buff = (struct hfi_buffer_info *) pkt->rg_buffer_info; + buff->buffer_addr -= fw_bias; + if (buff->extra_data_addr >= fw_bias) + buff->extra_data_addr -= fw_bias; + } else { + for (i = 0; i < pkt->num_buffers; i++) + pkt->rg_buffer_info[i] -= fw_bias; + } + break; + } + case HFI_CMD_SESSION_RELEASE_BUFFERS: + { + struct hfi_cmd_session_release_buffer_packet *pkt = + (struct hfi_cmd_session_release_buffer_packet *)packet; + + if (pkt->buffer_type == HFI_BUFFER_OUTPUT || + pkt->buffer_type == HFI_BUFFER_OUTPUT2) { + struct hfi_buffer_info *buff; + + buff = (struct hfi_buffer_info *) pkt->rg_buffer_info; + buff->buffer_addr -= fw_bias; + buff->extra_data_addr -= fw_bias; + } else { + for (i = 0; i < pkt->num_buffers; i++) + pkt->rg_buffer_info[i] -= fw_bias; + } + break; + } + case HFI_CMD_SESSION_REGISTER_BUFFERS: + { + struct hfi_cmd_session_register_buffers_packet *pkt = + (struct hfi_cmd_session_register_buffers_packet *) + packet; + struct hfi_buffer_mapping_type *buf = + (struct hfi_buffer_mapping_type *)pkt->buffer; + for (i = 0; i < pkt->num_buffers; i++) + buf[i].device_addr -= fw_bias; + break; + } + default: + break; + } +} + +static int __dsp_send_hfi_queue(struct venus_hfi_device *device) +{ + int rc; + + if (!device->res->cvp_internal) + return 0; + + if (!device->dsp_iface_q_table.mem_data.dma_handle) { + d_vpr_e("%s: invalid dsm_handle\n", __func__); + return -EINVAL; + } + + if (device->dsp_flags & DSP_INIT) { + d_vpr_h("%s: dsp already inited\n", __func__); + return 0; + } + + d_vpr_h("%s: hfi queue %#llx size %d\n", + __func__, device->dsp_iface_q_table.mem_data.dma_handle, + device->dsp_iface_q_table.mem_data.size); + rc = fastcvpd_video_send_cmd_hfi_queue( + (phys_addr_t *)device->dsp_iface_q_table.mem_data.dma_handle, + device->dsp_iface_q_table.mem_data.size); + if (rc) { + d_vpr_e("%s: dsp init failed\n", __func__); + return rc; + } + + device->dsp_flags |= DSP_INIT; + d_vpr_h("%s: dsp inited\n", __func__); + return rc; +} + +static int __dsp_suspend(struct venus_hfi_device *device, bool force, u32 flags) +{ + int rc; + struct hal_session *temp; + + if (!device->res->cvp_internal) + return 0; + + if (!(device->dsp_flags & DSP_INIT)) + return 0; + + if (device->dsp_flags & DSP_SUSPEND) + return 0; + + list_for_each_entry(temp, &device->sess_head, list) { + /* if forceful suspend, don't check session pause info */ + if (force) + continue; + if (temp->domain == HAL_VIDEO_DOMAIN_CVP) { + /* don't suspend if cvp session is not paused */ + if (!(temp->flags & SESSION_PAUSE)) { + s_vpr_h(temp->sid, + "%s: cvp session not paused\n", + __func__); + return -EBUSY; + } + } + } + + d_vpr_h("%s: suspend dsp\n", __func__); + rc = fastcvpd_video_suspend(flags); + if (rc) { + d_vpr_e("%s: dsp suspend failed with error %d\n", + __func__, rc); + return -EINVAL; + } + + device->dsp_flags |= DSP_SUSPEND; + d_vpr_h("%s: dsp suspended\n", __func__); + return 0; +} + +static int __dsp_resume(struct venus_hfi_device *device, u32 flags) +{ + int rc; + + if (!device->res->cvp_internal) + return 0; + + if (!(device->dsp_flags & DSP_SUSPEND)) { + d_vpr_h("%s: dsp not suspended\n", __func__); + return 0; + } + + d_vpr_h("%s: resume dsp\n", __func__); + rc = fastcvpd_video_resume(flags); + if (rc) { + d_vpr_e("%s: dsp resume failed with error %d\n", + __func__, rc); + return rc; + } + + device->dsp_flags &= ~DSP_SUSPEND; + d_vpr_h("%s: dsp resumed\n", __func__); + return rc; +} + +static int __dsp_shutdown(struct venus_hfi_device *device, u32 flags) +{ + int rc; + + if (!device->res->cvp_internal) + return 0; + + if (!(device->dsp_flags & DSP_INIT)) { + d_vpr_h("%s: dsp not inited\n", __func__); + return 0; + } + + d_vpr_h("%s: shutdown dsp\n", __func__); + rc = fastcvpd_video_shutdown(flags); + if (rc) { + d_vpr_e("%s: dsp shutdown failed with error %d\n", + __func__, rc); + WARN_ON(1); + } + + device->dsp_flags &= ~DSP_INIT; + d_vpr_h("%s: dsp shutdown successful\n", __func__); + return rc; +} + +static int __session_pause(struct venus_hfi_device *device, + struct hal_session *session) +{ + int rc = 0; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + /* ignore if session paused already */ + if (session->flags & SESSION_PAUSE) + return 0; + + session->flags |= SESSION_PAUSE; + s_vpr_h(session->sid, "%s: cvp session paused\n", __func__); + + return rc; +} + +static int __session_resume(struct venus_hfi_device *device, + struct hal_session *session) +{ + int rc = 0; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + /* ignore if session already resumed */ + if (!(session->flags & SESSION_PAUSE)) + return 0; + + session->flags &= ~SESSION_PAUSE; + s_vpr_h(session->sid, "%s: cvp session resumed\n", __func__); + + rc = __resume(device, session->sid); + if (rc) { + s_vpr_e(session->sid, "%s: resume failed\n", __func__); + goto exit; + } + + if (device->dsp_flags & DSP_SUSPEND) { + s_vpr_e(session->sid, "%s: dsp not resumed\n", __func__); + rc = -EINVAL; + goto exit; + } + +exit: + return rc; +} + +static int venus_hfi_session_pause(void *sess) +{ + int rc; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + mutex_lock(&device->lock); + rc = __session_pause(device, session); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_resume(void *sess) +{ + int rc; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + mutex_lock(&device->lock); + rc = __session_resume(device, session); + mutex_unlock(&device->lock); + + return rc; +} + +static int __acquire_regulator(struct regulator_info *rinfo, + struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + + if (rinfo->has_hw_power_collapse) { + rc = regulator_set_mode(rinfo->regulator, + REGULATOR_MODE_NORMAL); + if (rc) { + /* + * This is somewhat fatal, but nothing we can do + * about it. We can't disable the regulator w/o + * getting it back under s/w control + */ + s_vpr_e(sid, + "Failed to acquire regulator control: %s\n", + rinfo->name); + } else { + + s_vpr_h(sid, "Acquire regulator control from HW: %s\n", + rinfo->name); + + } + } + + if (!regulator_is_enabled(rinfo->regulator)) { + s_vpr_e(sid, "Regulator is not enabled %s\n", + rinfo->name); + msm_vidc_res_handle_fatal_hw_error(device->res, true); + } + + return rc; +} + +static int __hand_off_regulator(struct regulator_info *rinfo, u32 sid) +{ + int rc = 0; + + if (rinfo->has_hw_power_collapse) { + rc = regulator_set_mode(rinfo->regulator, + REGULATOR_MODE_FAST); + if (rc) { + s_vpr_e(sid, + "Failed to hand off regulator control: %s\n", + rinfo->name); + } else { + s_vpr_h(sid, "Hand off regulator control to HW: %s\n", + rinfo->name); + } + } + + return rc; +} + +static int __hand_off_regulators(struct venus_hfi_device *device, u32 sid) +{ + struct regulator_info *rinfo; + int rc = 0, c = 0; + + venus_hfi_for_each_regulator(device, rinfo) { + rc = __hand_off_regulator(rinfo, sid); + /* + * If one regulator hand off failed, driver should take + * the control for other regulators back. + */ + if (rc) + goto err_reg_handoff_failed; + c++; + } + + return rc; +err_reg_handoff_failed: + venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c) + __acquire_regulator(rinfo, device, sid); + + return rc; +} + +static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, + bool *rx_req_is_set, u32 sid) +{ + struct hfi_queue_header *queue; + u32 packet_size_in_words, new_write_idx; + u32 empty_space, read_idx, write_idx; + u32 *write_ptr; + + if (!qinfo || !packet) { + s_vpr_e(sid, "%s: invalid params %pK %pK\n", + __func__, qinfo, packet); + return -EINVAL; + } else if (!qinfo->q_array.align_virtual_addr) { + s_vpr_e(sid, "Queues have already been freed\n"); + return -EINVAL; + } + + queue = (struct hfi_queue_header *) qinfo->q_hdr; + if (!queue) { + s_vpr_e(sid, "queue not present\n"); + return -ENOENT; + } + + if (msm_vidc_debug & VIDC_PKT) { + s_vpr_t(sid, "%s: %pK\n", __func__, qinfo); + __dump_packet(packet, sid); + } + + packet_size_in_words = (*(u32 *)packet) >> 2; + if (!packet_size_in_words || packet_size_in_words > + qinfo->q_array.mem_size>>2) { + s_vpr_e(sid, "Invalid packet size\n"); + return -ENODATA; + } + + read_idx = queue->qhdr_read_idx; + write_idx = queue->qhdr_write_idx; + + empty_space = (write_idx >= read_idx) ? + ((qinfo->q_array.mem_size>>2) - (write_idx - read_idx)) : + (read_idx - write_idx); + if (empty_space <= packet_size_in_words) { + queue->qhdr_tx_req = 1; + s_vpr_e(sid, "Insufficient size (%d) to write (%d)\n", + empty_space, packet_size_in_words); + return -ENOTEMPTY; + } + + queue->qhdr_tx_req = 0; + + new_write_idx = write_idx + packet_size_in_words; + write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + + (write_idx << 2)); + if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr || + write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr + + qinfo->q_array.mem_size)) { + s_vpr_e(sid, "Invalid write index"); + return -ENODATA; + } + + if (new_write_idx < (qinfo->q_array.mem_size >> 2)) { + memcpy(write_ptr, packet, packet_size_in_words << 2); + } else { + new_write_idx -= qinfo->q_array.mem_size >> 2; + memcpy(write_ptr, packet, (packet_size_in_words - + new_write_idx) << 2); + memcpy((void *)qinfo->q_array.align_virtual_addr, + packet + ((packet_size_in_words - new_write_idx) << 2), + new_write_idx << 2); + } + + /* + * Memory barrier to make sure packet is written before updating the + * write index + */ + mb(); + queue->qhdr_write_idx = new_write_idx; + if (rx_req_is_set) + *rx_req_is_set = queue->qhdr_rx_req == 1; + /* + * Memory barrier to make sure write index is updated before an + * interrupt is raised on venus. + */ + mb(); + return 0; +} + +static void __hal_sim_modify_msg_packet(u8 *packet, + struct venus_hfi_device *device) +{ + struct hfi_msg_sys_session_init_done_packet *init_done; + struct hal_session *session = NULL; + phys_addr_t fw_bias = 0; + + if (!device || !packet) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, device, packet); + return; + } else if (!device->hal_data->firmware_base + || is_iommu_present(device->res)) { + return; + } + + fw_bias = device->hal_data->firmware_base; + init_done = (struct hfi_msg_sys_session_init_done_packet *)packet; + session = __get_session(device, init_done->sid); + if (!session) { + d_vpr_e("%s: Invalid session id: %x\n", + __func__, init_done->sid); + return; + } + + switch (init_done->packet_type) { + case HFI_MSG_SESSION_FILL_BUFFER_DONE: + if (session->is_decoder) { + struct + hfi_msg_session_fbd_uncompressed_plane0_packet + *pkt_uc = (struct + hfi_msg_session_fbd_uncompressed_plane0_packet + *) packet; + pkt_uc->packet_buffer += fw_bias; + } else { + struct + hfi_msg_session_fill_buffer_done_compressed_packet + *pkt = (struct + hfi_msg_session_fill_buffer_done_compressed_packet + *) packet; + pkt->packet_buffer += fw_bias; + } + break; + case HFI_MSG_SESSION_EMPTY_BUFFER_DONE: + { + struct hfi_msg_session_empty_buffer_done_packet *pkt = + (struct hfi_msg_session_empty_buffer_done_packet *)packet; + pkt->packet_buffer += fw_bias; + break; + } + default: + break; + } +} + +static int __read_queue(struct vidc_iface_q_info *qinfo, u8 *packet, + u32 *pb_tx_req_is_set) +{ + struct hfi_queue_header *queue; + u32 packet_size_in_words, new_read_idx; + u32 *read_ptr; + u32 receive_request = 0; + u32 read_idx, write_idx; + int rc = 0; + u32 sid; + + if (!qinfo || !packet || !pb_tx_req_is_set) { + d_vpr_e("%s: invalid params %pK %pK %pK\n", + __func__, qinfo, packet, pb_tx_req_is_set); + return -EINVAL; + } else if (!qinfo->q_array.align_virtual_addr) { + d_vpr_e("Queues have already been freed\n"); + return -EINVAL; + } + + /* + * Memory barrier to make sure data is valid before + *reading it + */ + mb(); + queue = (struct hfi_queue_header *) qinfo->q_hdr; + + if (!queue) { + d_vpr_e("Queue memory is not allocated\n"); + return -ENOMEM; + } + + /* + * Do not set receive request for debug queue, if set, + * Venus generates interrupt for debug messages even + * when there is no response message available. + * In general debug queue will not become full as it + * is being emptied out for every interrupt from Venus. + * Venus will anyway generates interrupt if it is full. + */ + if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q) + receive_request = 1; + + read_idx = queue->qhdr_read_idx; + write_idx = queue->qhdr_write_idx; + + if (read_idx == write_idx) { + queue->qhdr_rx_req = receive_request; + /* + * mb() to ensure qhdr is updated in main memory + * so that venus reads the updated header values + */ + mb(); + *pb_tx_req_is_set = 0; + d_vpr_l( + "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", + receive_request ? "message" : "debug", + queue->qhdr_rx_req, queue->qhdr_tx_req, + queue->qhdr_read_idx); + return -ENODATA; + } + + read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + + (read_idx << 2)); + if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr || + read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr + + qinfo->q_array.mem_size - sizeof(*read_ptr))) { + d_vpr_e("Invalid read index\n"); + return -ENODATA; + } + + packet_size_in_words = (*read_ptr) >> 2; + if (!packet_size_in_words) { + d_vpr_e("Zero packet size\n"); + return -ENODATA; + } + + new_read_idx = read_idx + packet_size_in_words; + if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) && + read_idx <= (qinfo->q_array.mem_size >> 2)) { + if (new_read_idx < (qinfo->q_array.mem_size >> 2)) { + memcpy(packet, read_ptr, + packet_size_in_words << 2); + } else { + new_read_idx -= (qinfo->q_array.mem_size >> 2); + memcpy(packet, read_ptr, + (packet_size_in_words - new_read_idx) << 2); + memcpy(packet + ((packet_size_in_words - + new_read_idx) << 2), + (u8 *)qinfo->q_array.align_virtual_addr, + new_read_idx << 2); + } + } else { + d_vpr_e("BAD packet received, read_idx: %#x, pkt_size: %d\n", + read_idx, packet_size_in_words << 2); + d_vpr_e("Dropping this packet\n"); + new_read_idx = write_idx; + rc = -ENODATA; + } + + if (new_read_idx != write_idx) + queue->qhdr_rx_req = 0; + else + queue->qhdr_rx_req = receive_request; + + queue->qhdr_read_idx = new_read_idx; + /* + * mb() to ensure qhdr is updated in main memory + * so that venus reads the updated header values + */ + mb(); + + *pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0; + + if ((msm_vidc_debug & VIDC_PKT) && + !(queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q)) { + sid = *((u32 *)packet + 2); + s_vpr_t(sid, "%s: %pK\n", __func__, qinfo); + __dump_packet(packet, sid); + } + + return rc; +} + +static int __smem_alloc(struct venus_hfi_device *dev, + struct vidc_mem_addr *mem, u32 size, u32 align, + u32 flags, u32 usage) +{ + struct msm_smem *alloc = &mem->mem_data; + int rc = 0; + + if (!dev || !mem || !size) { + d_vpr_e("%s: invalid params %pK %pK %pK\n", + __func__, dev, mem, size); + return -EINVAL; + } + + d_vpr_h("start to alloc size: %d, flags: %d\n", size, flags); + rc = msm_smem_alloc( + size, align, flags, usage, 1, (void *)dev->res, + MSM_VIDC_UNKNOWN, alloc, DEFAULT_SID); + if (rc) { + d_vpr_e("%s: alloc failed\n", __func__); + rc = -ENOMEM; + goto fail_smem_alloc; + } + + d_vpr_h("%s: ptr = %pK, size = %d\n", __func__, + alloc->kvaddr, size); + + mem->mem_size = alloc->size; + mem->align_virtual_addr = alloc->kvaddr; + mem->align_device_addr = alloc->device_addr; + + return rc; +fail_smem_alloc: + return rc; +} + +static void __smem_free(struct venus_hfi_device *dev, struct msm_smem *mem) +{ + if (!dev || !mem) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, dev, mem); + return; + } + + msm_smem_free(mem, DEFAULT_SID); +} + +void __write_register(struct venus_hfi_device *device, + u32 reg, u32 value, u32 sid) +{ + u32 hwiosymaddr = reg; + u8 *base_addr; + + if (!device) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return; + } + + __strict_check(device); + + if (!device->power_enabled) { + s_vpr_e(sid, "HFI Write register failed : Power is OFF\n"); + msm_vidc_res_handle_fatal_hw_error(device->res, true); + return; + } + + base_addr = device->hal_data->register_base; + s_vpr_l(sid, "Base addr: %pK, writing to: %#x, Value: %#x...\n", + base_addr, hwiosymaddr, value); + base_addr += hwiosymaddr; + writel_relaxed(value, base_addr); + + /* + * Memory barrier to make sure value is written into the register. + */ + wmb(); +} + +int __read_register(struct venus_hfi_device *device, u32 reg, u32 sid) +{ + int rc = 0; + u8 *base_addr; + + if (!device) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return -EINVAL; + } + + __strict_check(device); + + if (!device->power_enabled) { + s_vpr_e(sid, "HFI Read register failed : Power is OFF\n"); + msm_vidc_res_handle_fatal_hw_error(device->res, true); + return -EINVAL; + } + + base_addr = device->hal_data->register_base; + + rc = readl_relaxed(base_addr + reg); + /* + * Memory barrier to make sure value is read correctly from the + * register. + */ + rmb(); + s_vpr_l(sid, "Base addr: %pK, read from: %#x, value: %#x...\n", + base_addr, reg, rc); + + return rc; +} + +static void __set_registers(struct venus_hfi_device *device, u32 sid) +{ + struct reg_set *reg_set; + int i; + + if (!device->res) { + s_vpr_e(sid, "device resources null, cannot set registers\n"); + return; + } + + reg_set = &device->res->reg_set; + for (i = 0; i < reg_set->count; i++) { + __write_register(device, reg_set->reg_tbl[i].reg, + reg_set->reg_tbl[i].value, sid); + } +} + +static int __vote_bandwidth(struct bus_info *bus, + unsigned long bw_kbps, u32 sid) +{ + int rc = 0; + uint64_t ab = 0; + + /* Bus Driver expects values in Bps */ + ab = bw_kbps * 1000; + s_vpr_p(sid, "Voting bus %s to ab %llu bps\n", bus->name, ab); + rc = msm_bus_scale_update_bw(bus->client, ab, 0); + if (rc) + s_vpr_e(sid, "Failed voting bus %s to ab %llu, rc=%d\n", + bus->name, ab, rc); + + return rc; +} + +int __unvote_buses(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + struct bus_info *bus = NULL; + + device->bus_vote = DEFAULT_BUS_VOTE; + + venus_hfi_for_each_bus(device, bus) { + rc = __vote_bandwidth(bus, 0, sid); + if (rc) + goto err_unknown_device; + } + +err_unknown_device: + return rc; +} + +static int __vote_buses(struct venus_hfi_device *device, + unsigned long bw_ddr, unsigned long bw_llcc, u32 sid) +{ + int rc = 0; + struct bus_info *bus = NULL; + unsigned long bw_kbps = 0, bw_prev = 0; + enum vidc_bus_type type; + + venus_hfi_for_each_bus(device, bus) { + if (bus && bus->client) { + type = get_type_frm_name(bus->name); + + if (type == DDR) { + bw_kbps = bw_ddr; + bw_prev = device->bus_vote.total_bw_ddr; + } else if (type == LLCC) { + bw_kbps = bw_llcc; + bw_prev = device->bus_vote.total_bw_llcc; + } else { + bw_kbps = bus->range[1]; + bw_prev = device->bus_vote.total_bw_ddr ? + bw_kbps : 0; + } + + /* ensure freq is within limits */ + bw_kbps = clamp_t(typeof(bw_kbps), bw_kbps, + bus->range[0], bus->range[1]); + + if (TRIVIAL_BW_CHANGE(bw_kbps, bw_prev) && bw_prev) { + s_vpr_l(sid, "Skip voting bus %s to %llu bps", + bus->name, bw_kbps * 1000); + continue; + } + + rc = __vote_bandwidth(bus, bw_kbps, sid); + + if (type == DDR) + device->bus_vote.total_bw_ddr = bw_kbps; + else if (type == LLCC) + device->bus_vote.total_bw_llcc = bw_kbps; + } else { + s_vpr_e(sid, "No BUS to Vote\n"); + } + } + + return rc; +} + +static int venus_hfi_vote_buses(void *dev, unsigned long bw_ddr, + unsigned long bw_llcc, u32 sid) +{ + int rc = 0; + struct venus_hfi_device *device = dev; + + if (!device) + return -EINVAL; + + mutex_lock(&device->lock); + rc = __vote_buses(device, bw_ddr, bw_llcc, sid); + mutex_unlock(&device->lock); + + return rc; +} +static int __core_set_resource(struct venus_hfi_device *device, + struct vidc_resource_hdr *resource_hdr, void *resource_value) +{ + struct hfi_cmd_sys_set_resource_packet *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int rc = 0; + + if (!device || !resource_hdr || !resource_value) { + d_vpr_e("%s: invalid params %pK %pK %pK\n", __func__, + device, resource_hdr, resource_value); + return -EINVAL; + } + + pkt = (struct hfi_cmd_sys_set_resource_packet *) packet; + + rc = call_hfi_pkt_op(device, sys_set_resource, + pkt, resource_hdr, resource_value); + if (rc) { + d_vpr_e("set_res: failed to create packet\n"); + goto err_create_pkt; + } + + rc = __iface_cmdq_write(device, pkt, DEFAULT_SID); + if (rc) + rc = -ENOTEMPTY; + +err_create_pkt: + return rc; +} + +static int __core_release_resource(struct venus_hfi_device *device, + struct vidc_resource_hdr *resource_hdr) +{ + struct hfi_cmd_sys_release_resource_packet *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int rc = 0; + + if (!device || !resource_hdr) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, device, resource_hdr); + return -EINVAL; + } + + pkt = (struct hfi_cmd_sys_release_resource_packet *) packet; + + rc = call_hfi_pkt_op(device, sys_release_resource, + pkt, resource_hdr); + + if (rc) { + d_vpr_e("release_res: failed to create packet\n"); + goto err_create_pkt; + } + + rc = __iface_cmdq_write(device, pkt, DEFAULT_SID); + if (rc) + rc = -ENOTEMPTY; + +err_create_pkt: + return rc; +} + +static int __tzbsp_set_video_state(enum tzbsp_video_state state, u32 sid) +{ + struct tzbsp_video_set_state_req cmd = {0}; + int tzbsp_rsp = 0; + int rc = 0; + struct scm_desc desc = {0}; + + desc.args[0] = cmd.state = state; + desc.args[1] = cmd.spare = 0; + desc.arginfo = SCM_ARGS(2); + + rc = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, + TZBSP_VIDEO_SET_STATE), &desc); + tzbsp_rsp = desc.ret[0]; + + if (rc) { + s_vpr_e(sid, "Failed scm_call %d\n", rc); + return rc; + } + + s_vpr_l(sid, "Set state %d, resp %d\n", state, tzbsp_rsp); + if (tzbsp_rsp) { + s_vpr_e(sid, "Failed to set video core state to suspend: %d\n", + tzbsp_rsp); + return -EINVAL; + } + + return 0; +} + +static inline int __boot_firmware_common( + struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000; + + ctrl_init_val = BIT(0); + if (device->res->cvp_internal) + ctrl_init_val |= BIT(1); + + __write_register(device, CTRL_INIT, ctrl_init_val, sid); + while (!ctrl_status && count < max_tries) { + ctrl_status = __read_register(device, CTRL_STATUS, sid); + if ((ctrl_status & CTRL_ERROR_STATUS__M) == 0x4) { + s_vpr_e(sid, "invalid setting for UC_REGION\n"); + break; + } + + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + s_vpr_e(sid, "Error booting up vidc firmware\n"); + rc = -ETIME; + } + + return rc; +} + +static int venus_hfi_suspend(void *dev) +{ + int rc = 0; + struct venus_hfi_device *device = (struct venus_hfi_device *) dev; + + if (!device) { + d_vpr_e("%s: invalid device\n", __func__); + return -EINVAL; + } else if (!device->res->sw_power_collapsible) { + return -ENOTSUPP; + } + + d_vpr_h("Suspending Venus\n"); + mutex_lock(&device->lock); + rc = __power_collapse(device, true); + if (rc) { + d_vpr_e("%s: Venus is busy\n", __func__); + rc = -EBUSY; + } + mutex_unlock(&device->lock); + + /* Cancel pending delayed works if any */ + if (!rc) + cancel_delayed_work(&venus_hfi_pm_work); + + return rc; +} + +static int venus_hfi_flush_debug_queue(void *dev) +{ + int rc = 0; + struct venus_hfi_device *device = (struct venus_hfi_device *) dev; + + if (!device) { + d_vpr_e("%s: invalid device\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + if (!device->power_enabled) { + d_vpr_e("%s: venus power off\n", __func__); + rc = -EINVAL; + goto exit; + } + __flush_debug_queue(device, NULL); +exit: + mutex_unlock(&device->lock); + return rc; +} + +static int __set_clk_rate(struct venus_hfi_device *device, + struct clock_info *cl, u64 rate, u32 sid) +{ + int rc = 0; + u64 threshold_freq = device->res->clk_freq_threshold; + struct cx_ipeak_client *ipeak = device->res->cx_ipeak_context; + struct clk *clk = cl->clk; + + if (ipeak && device->clk_freq < threshold_freq && rate >= threshold_freq) { + rc = cx_ipeak_update(ipeak, true); + if (rc) { + s_vpr_e(sid, "%s: cx_ipeak_update failed!\n", __func__); + return rc; + } + s_vpr_p(sid, + "cx_ipeak_update: up, clk freq = %lu rate = %lu threshold_freq = %lu\n", + device->clk_freq, rate, threshold_freq); + } + + rc = clk_set_rate(clk, rate); + if (rc) { + s_vpr_e(sid, + "%s: Failed to set clock rate %llu %s: %d\n", + __func__, rate, cl->name, rc); + return rc; + } + + if (ipeak && device->clk_freq >= threshold_freq && rate < threshold_freq) { + rc = cx_ipeak_update(ipeak, false); + if (rc) { + s_vpr_e(sid, + "cx_ipeak_update failed! ipeak %pK\n", ipeak); + device->clk_freq = rate; + return rc; + } + s_vpr_p(sid, + "cx_ipeak_update: up, clk freq = %lu rate = %lu threshold_freq = %lu\n", + device->clk_freq, rate, threshold_freq); + } + + device->clk_freq = rate; + + return rc; +} + +static int __set_clocks(struct venus_hfi_device *device, u32 freq, u32 sid) +{ + struct clock_info *cl; + int rc = 0; + + /* bail early if requested clk_freq is not changed */ + if (freq == device->clk_freq) + return 0; + + venus_hfi_for_each_clock(device, cl) { + if (cl->has_scaling) {/* has_scaling */ + rc = __set_clk_rate(device, cl, freq, sid); + if (rc) + return rc; + + trace_msm_vidc_perf_clock_scale(cl->name, freq); + s_vpr_p(sid, "Scaling clock %s to %u\n", + cl->name, freq); + } + } + + return 0; +} + +static int venus_hfi_scale_clocks(void *dev, u32 freq, u32 sid) +{ + int rc = 0; + struct venus_hfi_device *device = dev; + + if (!device) { + s_vpr_e(sid, "Invalid args: %pK\n", device); + return -EINVAL; + } + + mutex_lock(&device->lock); + + if (__resume(device, sid)) { + s_vpr_e(sid, "Resume from power collapse failed\n"); + rc = -ENODEV; + goto exit; + } + + rc = __set_clocks(device, freq, sid); +exit: + mutex_unlock(&device->lock); + + return rc; +} + +static int __scale_clocks(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + u32 rate = 0; + + allowed_clks_tbl = device->res->allowed_clks_tbl; + rate = device->clk_freq ? device->clk_freq : + allowed_clks_tbl[0].clock_rate; + + rc = __set_clocks(device, rate, sid); + return rc; +} + +/* Writes into cmdq without raising an interrupt */ +static int __iface_cmdq_write_relaxed(struct venus_hfi_device *device, + void *pkt, bool *requires_interrupt, u32 sid) +{ + struct vidc_iface_q_info *q_info; + struct vidc_hal_cmd_pkt_hdr *cmd_packet; + int result = -E2BIG; + + if (!device || !pkt) { + s_vpr_e(sid, "%s: invalid params %pK %pK\n", + __func__, device, pkt); + return -EINVAL; + } + + __strict_check(device); + + if (!__core_in_valid_state(device)) { + s_vpr_e(sid, "%s: fw not in init state\n", __func__); + result = -EINVAL; + goto err_q_null; + } + + cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt; + device->last_packet_type = cmd_packet->packet_type; + + q_info = &device->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; + if (!q_info) { + s_vpr_e(sid, "cannot write to shared Q's\n"); + goto err_q_null; + } + + if (!q_info->q_array.align_virtual_addr) { + s_vpr_e(sid, "cannot write to shared CMD Q's\n"); + result = -ENODATA; + goto err_q_null; + } + + __sim_modify_cmd_packet((u8 *)pkt, device); + if (__resume(device, sid)) { + s_vpr_e(sid, "%s: Power on failed\n", __func__); + goto err_q_write; + } + + if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt, sid)) { + if (device->res->sw_power_collapsible) { + cancel_delayed_work(&venus_hfi_pm_work); + if (!queue_delayed_work(device->venus_pm_workq, + &venus_hfi_pm_work, + msecs_to_jiffies( + device->res->msm_vidc_pwr_collapse_delay))) { + s_vpr_l(sid, "PM work already scheduled\n"); + } + } + + result = 0; + } else { + s_vpr_e(sid, "__iface_cmdq_write: queue full\n"); + } + +err_q_write: +err_q_null: + return result; +} + +static void __raise_interrupt_common(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, CPU_IC_SOFTINT, + 1 << CPU_IC_SOFTINT_H2A_SHFT, sid); +} + +static int __iface_cmdq_write(struct venus_hfi_device *device, + void *pkt, u32 sid) +{ + bool needs_interrupt = false; + int rc = __iface_cmdq_write_relaxed(device, pkt, &needs_interrupt, sid); + + if (!rc && needs_interrupt) + call_venus_op(device, raise_interrupt, device, sid); + + return rc; +} + +static int __iface_msgq_read(struct venus_hfi_device *device, void *pkt) +{ + u32 tx_req_is_set = 0; + int rc = 0; + struct vidc_iface_q_info *q_info; + + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + __strict_check(device); + + if (!__core_in_valid_state(device)) { + d_vpr_e("%s: fw not in init state\n", __func__); + rc = -EINVAL; + goto read_error_null; + } + + q_info = &device->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; + if (!q_info->q_array.align_virtual_addr) { + d_vpr_e("cannot read from shared MSG Q's\n"); + rc = -ENODATA; + goto read_error_null; + } + + if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { + __hal_sim_modify_msg_packet((u8 *)pkt, device); + if (tx_req_is_set) + call_venus_op(device, raise_interrupt, device, + DEFAULT_SID); + rc = 0; + } else + rc = -ENODATA; + +read_error_null: + return rc; +} + +static int __iface_dbgq_read(struct venus_hfi_device *device, void *pkt) +{ + u32 tx_req_is_set = 0; + int rc = 0; + struct vidc_iface_q_info *q_info; + + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + __strict_check(device); + + q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + if (!q_info->q_array.align_virtual_addr) { + d_vpr_e("cannot read from shared DBG Q's\n"); + rc = -ENODATA; + goto dbg_error_null; + } + + if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { + if (tx_req_is_set) + call_venus_op(device, raise_interrupt, device, + DEFAULT_SID); + rc = 0; + } else + rc = -ENODATA; + +dbg_error_null: + return rc; +} + +static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr) +{ + q_hdr->qhdr_status = 0x1; + q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR; + q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4; + q_hdr->qhdr_pkt_size = 0; + q_hdr->qhdr_rx_wm = 0x1; + q_hdr->qhdr_tx_wm = 0x1; + q_hdr->qhdr_rx_req = 0x1; + q_hdr->qhdr_tx_req = 0x0; + q_hdr->qhdr_rx_irq_status = 0x0; + q_hdr->qhdr_tx_irq_status = 0x0; + q_hdr->qhdr_read_idx = 0x0; + q_hdr->qhdr_write_idx = 0x0; +} + +static void __interface_dsp_queues_release(struct venus_hfi_device *device) +{ + int i; + struct msm_smem *mem_data = &device->dsp_iface_q_table.mem_data; + struct context_bank_info *cb = mem_data->mapping_info.cb_info; + + if (!device->dsp_iface_q_table.align_virtual_addr) { + d_vpr_e("%s: already released\n", __func__); + return; + } + + dma_unmap_single_attrs(cb->dev, mem_data->device_addr, + mem_data->size, DMA_BIDIRECTIONAL, 0); + dma_free_coherent(device->res->mem_cdsp.dev, mem_data->size, + mem_data->kvaddr, mem_data->dma_handle); + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + device->dsp_iface_queues[i].q_hdr = NULL; + device->dsp_iface_queues[i].q_array.align_virtual_addr = NULL; + device->dsp_iface_queues[i].q_array.align_device_addr = 0; + } + device->dsp_iface_q_table.align_virtual_addr = NULL; + device->dsp_iface_q_table.align_device_addr = 0; +} + +static int __interface_dsp_queues_init(struct venus_hfi_device *dev) +{ + int rc = 0; + u32 i; + struct hfi_queue_table_header *q_tbl_hdr; + struct hfi_queue_header *q_hdr; + struct vidc_iface_q_info *iface_q; + int offset = 0; + phys_addr_t fw_bias = 0; + size_t q_size; + struct msm_smem *mem_data; + void *kvaddr; + dma_addr_t dma_handle; + dma_addr_t iova; + struct context_bank_info *cb; + + q_size = ALIGN(QUEUE_SIZE, SZ_1M); + mem_data = &dev->dsp_iface_q_table.mem_data; + + /* Allocate dsp queues from ADSP device memory */ + kvaddr = dma_alloc_coherent(dev->res->mem_cdsp.dev, q_size, + &dma_handle, GFP_KERNEL); + if (IS_ERR_OR_NULL(kvaddr)) { + d_vpr_e("%s: failed dma allocation\n", __func__); + goto fail_dma_alloc; + } + cb = msm_smem_get_context_bank(MSM_VIDC_UNKNOWN, 0, + dev->res, HAL_BUFFER_INTERNAL_CMD_QUEUE, DEFAULT_SID); + if (!cb) { + d_vpr_e("%s: failed to get context bank\n", __func__); + goto fail_dma_map; + } + iova = dma_map_single_attrs(cb->dev, phys_to_virt(dma_handle), + q_size, DMA_BIDIRECTIONAL, 0); + if (dma_mapping_error(cb->dev, iova)) { + d_vpr_e("%s: failed dma mapping\n", __func__); + goto fail_dma_map; + } + d_vpr_h("%s: kvaddr %pK dma_handle %#llx iova %#llx size %zd\n", + __func__, kvaddr, dma_handle, iova, q_size); + + memset(mem_data, 0, sizeof(struct msm_smem)); + mem_data->kvaddr = kvaddr; + mem_data->device_addr = iova; + mem_data->dma_handle = dma_handle; + mem_data->size = q_size; + mem_data->buffer_type = HAL_BUFFER_INTERNAL_CMD_QUEUE; + mem_data->mapping_info.cb_info = cb; + + if (!is_iommu_present(dev->res)) + fw_bias = dev->hal_data->firmware_base; + + dev->dsp_iface_q_table.align_virtual_addr = kvaddr; + dev->dsp_iface_q_table.align_device_addr = iova - fw_bias; + dev->dsp_iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE; + offset = dev->dsp_iface_q_table.mem_size; + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + iface_q = &dev->dsp_iface_queues[i]; + iface_q->q_array.align_device_addr = iova + offset - fw_bias; + iface_q->q_array.align_virtual_addr = + (void *)((char *)kvaddr + offset); + iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE; + offset += iface_q->q_array.mem_size; + iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR( + dev->dsp_iface_q_table.align_virtual_addr, i); + __set_queue_hdr_defaults(iface_q->q_hdr); + } + + q_tbl_hdr = (struct hfi_queue_table_header *) + dev->dsp_iface_q_table.align_virtual_addr; + q_tbl_hdr->qtbl_version = 0; + q_tbl_hdr->device_addr = (void *)dev; + strlcpy(q_tbl_hdr->name, "msm_v4l2_vidc", sizeof(q_tbl_hdr->name)); + q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE; + q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_table_header); + q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header); + q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ; + q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ; + + iface_q = &dev->dsp_iface_queues[VIDC_IFACEQ_CMDQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q; + + iface_q = &dev->dsp_iface_queues[VIDC_IFACEQ_MSGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q; + + iface_q = &dev->dsp_iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; + /* + * Set receive request to zero on debug queue as there is no + * need of interrupt from video hardware for debug messages + */ + q_hdr->qhdr_rx_req = 0; + return rc; + +fail_dma_map: + dma_free_coherent(dev->res->mem_cdsp.dev, q_size, kvaddr, dma_handle); +fail_dma_alloc: + return -ENOMEM; +} + +static void __interface_queues_release(struct venus_hfi_device *device) +{ + int i; + struct hfi_mem_map_table *qdss; + struct hfi_mem_map *mem_map; + int num_entries = device->res->qdss_addr_set.count; + unsigned long mem_map_table_base_addr; + struct context_bank_info *cb; + + if (device->qdss.align_virtual_addr) { + qdss = (struct hfi_mem_map_table *) + device->qdss.align_virtual_addr; + qdss->mem_map_num_entries = num_entries; + mem_map_table_base_addr = + device->qdss.align_device_addr + + sizeof(struct hfi_mem_map_table); + qdss->mem_map_table_base_addr = + (u32)mem_map_table_base_addr; + if ((unsigned long)qdss->mem_map_table_base_addr != + mem_map_table_base_addr) { + d_vpr_e("Invalid mem_map_table_base_addr %#lx", + mem_map_table_base_addr); + } + + mem_map = (struct hfi_mem_map *)(qdss + 1); + cb = msm_smem_get_context_bank(MSM_VIDC_UNKNOWN, + false, device->res, HAL_BUFFER_INTERNAL_CMD_QUEUE, + DEFAULT_SID); + + for (i = 0; cb && i < num_entries; i++) { + iommu_unmap(cb->domain, + mem_map[i].virtual_addr, + mem_map[i].size); + } + + __smem_free(device, &device->qdss.mem_data); + } + + __smem_free(device, &device->iface_q_table.mem_data); + __smem_free(device, &device->sfr.mem_data); + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + device->iface_queues[i].q_hdr = NULL; + device->iface_queues[i].q_array.align_virtual_addr = NULL; + device->iface_queues[i].q_array.align_device_addr = 0; + } + + device->iface_q_table.align_virtual_addr = NULL; + device->iface_q_table.align_device_addr = 0; + + device->qdss.align_virtual_addr = NULL; + device->qdss.align_device_addr = 0; + + device->sfr.align_virtual_addr = NULL; + device->sfr.align_device_addr = 0; + + device->mem_addr.align_virtual_addr = NULL; + device->mem_addr.align_device_addr = 0; + + if (device->res->cvp_internal) + __interface_dsp_queues_release(device); +} + +static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev, + struct hfi_mem_map *mem_map, struct iommu_domain *domain) +{ + int i; + int rc = 0; + dma_addr_t iova = QDSS_IOVA_START; + int num_entries = dev->res->qdss_addr_set.count; + struct addr_range *qdss_addr_tbl = dev->res->qdss_addr_set.addr_tbl; + + if (!num_entries) + return -ENODATA; + + for (i = 0; i < num_entries; i++) { + if (domain) { + rc = iommu_map(domain, iova, + qdss_addr_tbl[i].start, + qdss_addr_tbl[i].size, + IOMMU_READ | IOMMU_WRITE); + + if (rc) { + d_vpr_e( + "IOMMU QDSS mapping failed for addr %#x\n", + qdss_addr_tbl[i].start); + rc = -ENOMEM; + break; + } + } else { + iova = qdss_addr_tbl[i].start; + } + + mem_map[i].virtual_addr = (u32)iova; + mem_map[i].physical_addr = qdss_addr_tbl[i].start; + mem_map[i].size = qdss_addr_tbl[i].size; + mem_map[i].attr = 0x0; + + iova += mem_map[i].size; + } + + if (i < num_entries) { + d_vpr_e("QDSS mapping failed, Freeing other entries %d\n", i); + + for (--i; domain && i >= 0; i--) { + iommu_unmap(domain, + mem_map[i].virtual_addr, + mem_map[i].size); + } + } + + return rc; +} + +static void __setup_ucregion_memory_map_common(struct venus_hfi_device *device, + u32 sid) +{ + __write_register(device, UC_REGION_ADDR, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, UC_REGION_SIZE, SHARED_QSIZE, sid); + __write_register(device, QTBL_ADDR, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, QTBL_INFO, 0x01, sid); + if (device->sfr.align_device_addr) + __write_register(device, SFR_ADDR, + (u32)device->sfr.align_device_addr, sid); + if (device->qdss.align_device_addr) + __write_register(device, MMAP_ADDR, + (u32)device->qdss.align_device_addr, sid); +} + +static int __interface_queues_init(struct venus_hfi_device *dev) +{ + struct hfi_queue_table_header *q_tbl_hdr; + struct hfi_queue_header *q_hdr; + u32 i; + int rc = 0; + struct hfi_mem_map_table *qdss; + struct hfi_mem_map *mem_map; + struct vidc_iface_q_info *iface_q; + struct hfi_sfr_struct *vsfr; + struct vidc_mem_addr *mem_addr; + int offset = 0; + int num_entries = dev->res->qdss_addr_set.count; + phys_addr_t fw_bias = 0; + size_t q_size; + unsigned long mem_map_table_base_addr; + struct context_bank_info *cb; + + q_size = SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE; + mem_addr = &dev->mem_addr; + if (!is_iommu_present(dev->res)) + fw_bias = dev->hal_data->firmware_base; + rc = __smem_alloc(dev, mem_addr, q_size, 1, SMEM_UNCACHED, + HAL_BUFFER_INTERNAL_CMD_QUEUE); + if (rc) { + d_vpr_e("iface_q_table_alloc_fail\n"); + goto fail_alloc_queue; + } + + dev->iface_q_table.align_virtual_addr = mem_addr->align_virtual_addr; + dev->iface_q_table.align_device_addr = mem_addr->align_device_addr - + fw_bias; + dev->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE; + dev->iface_q_table.mem_data = mem_addr->mem_data; + offset += dev->iface_q_table.mem_size; + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + iface_q = &dev->iface_queues[i]; + iface_q->q_array.align_device_addr = mem_addr->align_device_addr + + offset - fw_bias; + iface_q->q_array.align_virtual_addr = + mem_addr->align_virtual_addr + offset; + iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE; + offset += iface_q->q_array.mem_size; + iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR( + dev->iface_q_table.align_virtual_addr, i); + __set_queue_hdr_defaults(iface_q->q_hdr); + } + + if ((msm_vidc_fw_debug_mode & HFI_DEBUG_MODE_QDSS) && num_entries) { + rc = __smem_alloc(dev, mem_addr, + ALIGNED_QDSS_SIZE, 1, SMEM_UNCACHED, + HAL_BUFFER_INTERNAL_CMD_QUEUE); + if (rc) { + d_vpr_e( + "qdss_alloc_fail: QDSS messages logging will not work\n"); + dev->qdss.align_device_addr = 0; + } else { + dev->qdss.align_device_addr = + mem_addr->align_device_addr - fw_bias; + dev->qdss.align_virtual_addr = + mem_addr->align_virtual_addr; + dev->qdss.mem_size = ALIGNED_QDSS_SIZE; + dev->qdss.mem_data = mem_addr->mem_data; + } + } + + rc = __smem_alloc(dev, mem_addr, + ALIGNED_SFR_SIZE, 1, SMEM_UNCACHED, + HAL_BUFFER_INTERNAL_CMD_QUEUE); + if (rc) { + d_vpr_e("sfr_alloc_fail: SFR not will work\n"); + dev->sfr.align_device_addr = 0; + } else { + dev->sfr.align_device_addr = mem_addr->align_device_addr - + fw_bias; + dev->sfr.align_virtual_addr = mem_addr->align_virtual_addr; + dev->sfr.mem_size = ALIGNED_SFR_SIZE; + dev->sfr.mem_data = mem_addr->mem_data; + vsfr = (struct hfi_sfr_struct *) dev->sfr.align_virtual_addr; + vsfr->bufSize = ALIGNED_SFR_SIZE; + } + + q_tbl_hdr = (struct hfi_queue_table_header *) + dev->iface_q_table.align_virtual_addr; + q_tbl_hdr->qtbl_version = 0; + q_tbl_hdr->device_addr = (void *)dev; + strlcpy(q_tbl_hdr->name, "msm_v4l2_vidc", sizeof(q_tbl_hdr->name)); + q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE; + q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_table_header); + q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header); + q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ; + q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ; + + iface_q = &dev->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q; + + iface_q = &dev->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q; + + iface_q = &dev->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; + /* + * Set receive request to zero on debug queue as there is no + * need of interrupt from video hardware for debug messages + */ + q_hdr->qhdr_rx_req = 0; + + if (dev->qdss.align_virtual_addr) { + qdss = (struct hfi_mem_map_table *)dev->qdss.align_virtual_addr; + qdss->mem_map_num_entries = num_entries; + mem_map_table_base_addr = dev->qdss.align_device_addr + + sizeof(struct hfi_mem_map_table); + qdss->mem_map_table_base_addr = mem_map_table_base_addr; + + mem_map = (struct hfi_mem_map *)(qdss + 1); + cb = msm_smem_get_context_bank(MSM_VIDC_UNKNOWN, false, + dev->res, HAL_BUFFER_INTERNAL_CMD_QUEUE, DEFAULT_SID); + if (!cb) { + d_vpr_e("%s: failed to get context bank\n", __func__); + return -EINVAL; + } + + rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->domain); + if (rc) { + d_vpr_e("IOMMU mapping failed, Freeing qdss memdata\n"); + __smem_free(dev, &dev->qdss.mem_data); + dev->qdss.align_virtual_addr = NULL; + dev->qdss.align_device_addr = 0; + } + } + + + if (dev->res->cvp_internal) { + rc = __interface_dsp_queues_init(dev); + if (rc) { + d_vpr_e("dsp_queues_init failed\n"); + goto fail_alloc_queue; + } + } + + call_venus_op(dev, setup_ucregion_memmap, dev, DEFAULT_SID); + return 0; +fail_alloc_queue: + return -ENOMEM; +} + +static int __sys_set_debug(struct venus_hfi_device *device, u32 debug, u32 sid) +{ + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int rc = 0; + struct hfi_cmd_sys_set_property_packet *pkt = + (struct hfi_cmd_sys_set_property_packet *) &packet; + + rc = call_hfi_pkt_op(device, sys_debug_config, pkt, debug); + if (rc) { + s_vpr_e(sid, "Debug mode setting to FW failed\n"); + return -ENOTEMPTY; + } + + if (__iface_cmdq_write(device, pkt, sid)) + return -ENOTEMPTY; + return 0; +} + +static int __sys_set_coverage(struct venus_hfi_device *device, + u32 mode, u32 sid) +{ + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int rc = 0; + struct hfi_cmd_sys_set_property_packet *pkt = + (struct hfi_cmd_sys_set_property_packet *) &packet; + + rc = call_hfi_pkt_op(device, sys_coverage_config, + pkt, mode, sid); + if (rc) { + s_vpr_e(sid, "Coverage mode setting to FW failed\n"); + return -ENOTEMPTY; + } + + if (__iface_cmdq_write(device, pkt, sid)) { + s_vpr_e(sid, "Failed to send coverage pkt to f/w\n"); + return -ENOTEMPTY; + } + + return 0; +} + +static int __sys_set_power_control(struct venus_hfi_device *device, + bool enable, u32 sid) +{ + struct regulator_info *rinfo; + bool supported = false; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + struct hfi_cmd_sys_set_property_packet *pkt = + (struct hfi_cmd_sys_set_property_packet *) &packet; + + venus_hfi_for_each_regulator(device, rinfo) { + if (rinfo->has_hw_power_collapse) { + supported = true; + break; + } + } + + if (!supported) + return 0; + + call_hfi_pkt_op(device, sys_power_control, pkt, enable); + if (__iface_cmdq_write(device, pkt, sid)) + return -ENOTEMPTY; + return 0; +} + +static int venus_hfi_core_init(void *device) +{ + int rc = 0; + struct hfi_cmd_sys_init_packet pkt; + struct hfi_cmd_sys_get_property_packet version_pkt; + struct venus_hfi_device *dev; + + if (!device) { + d_vpr_e("Invalid device\n"); + return -ENODEV; + } + + dev = device; + + d_vpr_h("Core initializing\n"); + + mutex_lock(&dev->lock); + + dev->bus_vote = DEFAULT_BUS_VOTE; + + rc = __load_fw(dev); + if (rc) { + d_vpr_e("Failed to load Venus FW\n"); + goto err_load_fw; + } + + __set_state(dev, VENUS_STATE_INIT); + + d_vpr_h("Dev_Virt: %pa, Reg_Virt: %pK\n", + &dev->hal_data->firmware_base, + dev->hal_data->register_base); + + + rc = __interface_queues_init(dev); + if (rc) { + d_vpr_e("failed to init queues\n"); + rc = -ENOMEM; + goto err_core_init; + } + + rc = call_venus_op(dev, boot_firmware, dev, DEFAULT_SID); + if (rc) { + d_vpr_e("Failed to start core\n"); + rc = -ENODEV; + goto err_core_init; + } + + rc = call_hfi_pkt_op(dev, sys_init, &pkt, HFI_VIDEO_ARCH_OX); + if (rc) { + d_vpr_e("Failed to create sys init pkt\n"); + goto err_core_init; + } + + if (__iface_cmdq_write(dev, &pkt, DEFAULT_SID)) { + rc = -ENOTEMPTY; + goto err_core_init; + } + + rc = call_hfi_pkt_op(dev, sys_image_version, &version_pkt); + if (rc || __iface_cmdq_write(dev, &version_pkt, DEFAULT_SID)) + d_vpr_e("Failed to send image version pkt to f/w\n"); + + __sys_set_debug(device, (msm_vidc_debug & FW_LOGMASK) >> FW_LOGSHIFT, + DEFAULT_SID); + + __enable_subcaches(device, DEFAULT_SID); + __set_subcaches(device, DEFAULT_SID); + __dsp_send_hfi_queue(device); + + __set_ubwc_config(device); + + if (dev->res->pm_qos_latency_us) { +#ifdef CONFIG_SMP + dev->qos.type = PM_QOS_REQ_AFFINE_IRQ; + dev->qos.irq = dev->hal_data->irq; +#endif + pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY, + dev->res->pm_qos_latency_us); + } + d_vpr_h("Core inited successfully\n"); + mutex_unlock(&dev->lock); + return rc; +err_core_init: + __set_state(dev, VENUS_STATE_DEINIT); + __unload_fw(dev); +err_load_fw: + d_vpr_e("Core init failed\n"); + mutex_unlock(&dev->lock); + return rc; +} + +static int venus_hfi_core_release(void *dev) +{ + int rc = 0; + struct venus_hfi_device *device = dev; + struct hal_session *session, *next; + + if (!device) { + d_vpr_e("invalid device\n"); + return -ENODEV; + } + + mutex_lock(&device->lock); + d_vpr_h("Core releasing\n"); + if (device->res->pm_qos_latency_us && + pm_qos_request_active(&device->qos)) + pm_qos_remove_request(&device->qos); + + __resume(device, DEFAULT_SID); + __set_state(device, VENUS_STATE_DEINIT); + __dsp_shutdown(device, 0); + + __unload_fw(device); + + /* unlink all sessions from device */ + list_for_each_entry_safe(session, next, &device->sess_head, list) + list_del(&session->list); + + d_vpr_h("Core released successfully\n"); + mutex_unlock(&device->lock); + + return rc; +} + +static void __core_clear_interrupt_common(struct venus_hfi_device *device) +{ + u32 intr_status = 0, mask = 0; + + if (!device) { + d_vpr_e("%s: NULL device\n", __func__); + return; + } + + intr_status = __read_register(device, WRAPPER_INTR_STATUS, DEFAULT_SID); + mask = (WRAPPER_INTR_STATUS_A2H_BMSK | + WRAPPER_INTR_STATUS_A2HWD_BMSK | + CTRL_INIT_IDLE_MSG_BMSK); + + if (intr_status & mask) { + device->intr_status |= intr_status; + device->reg_count++; + d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n", + device->reg_count, intr_status); + } else { + device->spur_count++; + } + + __write_register(device, CPU_CS_A2HSOFTINTCLR, 1, DEFAULT_SID); + __write_register(device, WRAPPER_INTR_CLEAR, intr_status, DEFAULT_SID); +} + +static int venus_hfi_core_trigger_ssr(void *device, + enum hal_ssr_trigger_type type) +{ + struct hfi_cmd_sys_test_ssr_packet pkt; + int rc = 0; + struct venus_hfi_device *dev; + + if (!device) { + d_vpr_e("invalid device\n"); + return -ENODEV; + } + + dev = device; + mutex_lock(&dev->lock); + + rc = call_hfi_pkt_op(dev, ssr_cmd, type, &pkt); + if (rc) { + d_vpr_e("core_ping: failed to create packet\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(dev, &pkt, DEFAULT_SID)) + rc = -ENOTEMPTY; + +err_create_pkt: + mutex_unlock(&dev->lock); + return rc; +} + +static int venus_hfi_session_set_property(void *sess, + u32 ptype, void *pdata, u32 size) +{ + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + struct hfi_cmd_session_set_property_packet *pkt = + (struct hfi_cmd_session_set_property_packet *) &packet; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_set_prop; + } + s_vpr_h(session->sid, "in set_prop,with prop id: %#x\n", ptype); + + rc = call_hfi_pkt_op(device, session_set_property, + pkt, session->sid, ptype, pdata, size); + + if (rc == -ENOTSUPP) { + s_vpr_e(session->sid, + "set property: unsupported prop id: %#x\n", ptype); + rc = 0; + goto err_set_prop; + } else if (rc) { + s_vpr_e(session->sid, + "set property: failed to create packet\n"); + rc = -EINVAL; + goto err_set_prop; + } + + if (__iface_cmdq_write(device, pkt, session->sid)) { + rc = -ENOTEMPTY; + goto err_set_prop; + } + +err_set_prop: + mutex_unlock(&device->lock); + return rc; +} + +static void __set_default_sys_properties(struct venus_hfi_device *device, + u32 sid) +{ + if (__sys_set_debug(device, + (msm_vidc_debug & FW_LOGMASK) >> FW_LOGSHIFT, sid)) + s_vpr_e(sid, "Setting fw_debug msg ON failed\n"); + if (__sys_set_power_control(device, true, sid)) + s_vpr_e(sid, "Setting h/w power collapse ON failed\n"); +} + +static void __session_clean(struct hal_session *session) +{ + struct hal_session *temp, *next; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!__is_session_valid(device, session, __func__)) + return; + s_vpr_h(session->sid, "deleted the session: %pK\n", session); + /* + * session might have been removed from the device list in + * core_release, so check and remove if it is in the list + */ + list_for_each_entry_safe(temp, next, &device->sess_head, list) { + if (session == temp) { + list_del(&session->list); + break; + } + } + /* Poison the session handle with zeros */ + *session = (struct hal_session){ {0} }; + kfree(session); +} + +static int venus_hfi_session_clean(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + mutex_lock(&device->lock); + __session_clean(session); + mutex_unlock(&device->lock); + return 0; +} + +static int venus_hfi_session_init(void *device, void *inst_id, + enum hal_domain session_type, enum hal_video_codec codec_type, + void **new_session, u32 sid) +{ + struct hfi_cmd_sys_session_init_packet pkt; + struct venus_hfi_device *dev; + struct hal_session *s; + + if (!device || !new_session) { + d_vpr_e("%s: invalid input\n", __func__); + return -EINVAL; + } + + dev = device; + mutex_lock(&dev->lock); + + s = kzalloc(sizeof(struct hal_session), GFP_KERNEL); + if (!s) { + s_vpr_e(sid, "new session fail: Out of memory\n"); + goto err_session_init_fail; + } + + s->inst_id = inst_id; + s->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER); + s->codec = codec_type; + s->domain = session_type; + s->sid = sid; + s_vpr_hp(sid, "%s: inst %pK, session %pK, codec 0x%x, domain 0x%x\n", + __func__, inst_id, s, s->codec, s->domain); + + list_add_tail(&s->list, &dev->sess_head); + + __set_default_sys_properties(device, sid); + + if (call_hfi_pkt_op(dev, session_init, &pkt, + sid, session_type, codec_type)) { + s_vpr_e(sid, "session_init: failed to create packet\n"); + goto err_session_init_fail; + } + + *new_session = s; + if (__iface_cmdq_write(dev, &pkt, sid)) + goto err_session_init_fail; + + mutex_unlock(&dev->lock); + return 0; + +err_session_init_fail: + if (s) + __session_clean(s); + *new_session = NULL; + mutex_unlock(&dev->lock); + return -EINVAL; +} + +static int __send_session_cmd(struct hal_session *session, int pkt_type) +{ + struct vidc_hal_session_cmd_pkt pkt; + int rc = 0; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + rc = call_hfi_pkt_op(device, session_cmd, + &pkt, pkt_type, session->sid); + if (rc == -EPERM) + return 0; + + if (rc) { + s_vpr_e(session->sid, "send session cmd: create pkt failed\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(device, &pkt, session->sid)) + rc = -ENOTEMPTY; + +err_create_pkt: + return rc; +} + +static int venus_hfi_session_end(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto exit; + } + + if (msm_vidc_fw_coverage) { + if (__sys_set_coverage(device, msm_vidc_fw_coverage, + session->sid)) + s_vpr_e(session->sid, "Fw_coverage msg ON failed\n"); + } + rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_END); +exit: + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_abort(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + + __flush_debug_queue(device, NULL); + rc = __send_session_cmd(session, HFI_CMD_SYS_SESSION_ABORT); + + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_set_buffers(void *sess, + struct vidc_buffer_addr_info *buffer_info) +{ + struct hfi_cmd_session_set_buffers_packet *pkt; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + int rc = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!buffer_info) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_create_pkt; + } + if (buffer_info->buffer_type == HAL_BUFFER_INPUT) { + /* + * Hardware doesn't care about input buffers being + * published beforehand + */ + rc = 0; + goto err_create_pkt; + } + + pkt = (struct hfi_cmd_session_set_buffers_packet *)packet; + + rc = call_hfi_pkt_op(device, session_set_buffers, + pkt, session->sid, buffer_info); + if (rc) { + s_vpr_e(session->sid, "set buffers: failed to create packet\n"); + goto err_create_pkt; + } + + s_vpr_h(session->sid, "set buffers: %#x\n", buffer_info->buffer_type); + if (__iface_cmdq_write(device, pkt, session->sid)) + rc = -ENOTEMPTY; + +err_create_pkt: + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_release_buffers(void *sess, + struct vidc_buffer_addr_info *buffer_info) +{ + struct hfi_cmd_session_release_buffer_packet *pkt; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + int rc = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!buffer_info) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_create_pkt; + } + if (buffer_info->buffer_type == HAL_BUFFER_INPUT) { + rc = 0; + goto err_create_pkt; + } + + pkt = (struct hfi_cmd_session_release_buffer_packet *) packet; + + rc = call_hfi_pkt_op(device, session_release_buffers, + pkt, session->sid, buffer_info); + if (rc) { + s_vpr_e(session->sid, "%s: failed to create packet\n", + __func__); + goto err_create_pkt; + } + + s_vpr_h(session->sid, "Release buffers: %#x\n", + buffer_info->buffer_type); + if (__iface_cmdq_write(device, pkt, session->sid)) + rc = -ENOTEMPTY; + +err_create_pkt: + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_register_buffer(void *sess, + struct vidc_register_buffer *buffer) +{ + int rc = 0; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + struct hfi_cmd_session_register_buffers_packet *pkt; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!buffer) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto exit; + } + pkt = (struct hfi_cmd_session_register_buffers_packet *)packet; + rc = call_hfi_pkt_op(device, session_register_buffer, pkt, + session->sid, buffer); + if (rc) { + s_vpr_e(session->sid, + "%s: failed to create packet\n", __func__); + goto exit; + } + if (__iface_cmdq_write(device, pkt, session->sid)) + rc = -ENOTEMPTY; +exit: + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_unregister_buffer(void *sess, + struct vidc_unregister_buffer *buffer) +{ + int rc = 0; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + struct hfi_cmd_session_unregister_buffers_packet *pkt; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!buffer) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto exit; + } + pkt = (struct hfi_cmd_session_unregister_buffers_packet *)packet; + rc = call_hfi_pkt_op(device, session_unregister_buffer, pkt, + session->sid, buffer); + if (rc) { + s_vpr_e(session->sid, + "%s: failed to create packet\n", __func__); + goto exit; + } + if (__iface_cmdq_write(device, pkt, session->sid)) + rc = -ENOTEMPTY; +exit: + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_load_res(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + rc = __send_session_cmd(session, HFI_CMD_SESSION_LOAD_RESOURCES); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_release_res(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + rc = __send_session_cmd(session, HFI_CMD_SESSION_RELEASE_RESOURCES); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_start(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + rc = __send_session_cmd(session, HFI_CMD_SESSION_START); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_continue(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + rc = __send_session_cmd(session, HFI_CMD_SESSION_CONTINUE); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_stop(void *sess) +{ + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + int rc = 0; + + mutex_lock(&device->lock); + rc = __send_session_cmd(session, HFI_CMD_SESSION_STOP); + mutex_unlock(&device->lock); + + return rc; +} + +static int __session_etb(struct hal_session *session, + struct vidc_frame_data *input_frame, bool relaxed) +{ + int rc = 0; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + if (session->is_decoder) { + struct hfi_cmd_session_empty_buffer_compressed_packet pkt; + + rc = call_hfi_pkt_op(device, session_etb_decoder, + &pkt, session->sid, input_frame); + if (rc) { + s_vpr_e(session->sid, + "etb decoder: failed to create pkt\n"); + goto err_create_pkt; + } + + if (!relaxed) + rc = __iface_cmdq_write(device, &pkt, session->sid); + else + rc = __iface_cmdq_write_relaxed(device, + &pkt, NULL, session->sid); + if (rc) + goto err_create_pkt; + } else { + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + pkt; + + rc = call_hfi_pkt_op(device, session_etb_encoder, + &pkt, session->sid, input_frame); + if (rc) { + s_vpr_e(session->sid, + "etb encoder: failed to create pkt\n"); + goto err_create_pkt; + } + + if (!relaxed) + rc = __iface_cmdq_write(device, &pkt, session->sid); + else + rc = __iface_cmdq_write_relaxed(device, + &pkt, NULL, session->sid); + if (rc) + goto err_create_pkt; + } + +err_create_pkt: + return rc; +} + +static int venus_hfi_session_etb(void *sess, + struct vidc_frame_data *input_frame) +{ + int rc = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!input_frame) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + rc = __session_etb(session, input_frame, false); + mutex_unlock(&device->lock); + return rc; +} + +static int __session_ftb(struct hal_session *session, + struct vidc_frame_data *output_frame, bool relaxed) +{ + int rc = 0; + struct venus_hfi_device *device = &venus_hfi_dev; + struct hfi_cmd_session_fill_buffer_packet pkt; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + rc = call_hfi_pkt_op(device, session_ftb, + &pkt, session->sid, output_frame); + if (rc) { + s_vpr_e(session->sid, "Session ftb: failed to create pkt\n"); + goto err_create_pkt; + } + + if (!relaxed) + rc = __iface_cmdq_write(device, &pkt, session->sid); + else + rc = __iface_cmdq_write_relaxed(device, + &pkt, NULL, session->sid); + +err_create_pkt: + return rc; +} + +static int venus_hfi_session_ftb(void *sess, + struct vidc_frame_data *output_frame) +{ + int rc = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + if (!output_frame) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + rc = __session_ftb(session, output_frame, false); + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_process_batch(void *sess, + int num_etbs, struct vidc_frame_data etbs[], + int num_ftbs, struct vidc_frame_data ftbs[]) +{ + int rc = 0, c = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + struct hfi_cmd_session_sync_process_packet pkt; + + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_etbs_and_ftbs; + } + + for (c = 0; c < num_ftbs; ++c) { + rc = __session_ftb(session, &ftbs[c], true); + if (rc) { + s_vpr_e(session->sid, + "Failed to queue batched ftb: %d\n", rc); + goto err_etbs_and_ftbs; + } + } + + for (c = 0; c < num_etbs; ++c) { + rc = __session_etb(session, &etbs[c], true); + if (rc) { + s_vpr_e(session->sid, + "Failed to queue batched etb: %d\n", rc); + goto err_etbs_and_ftbs; + } + } + + rc = call_hfi_pkt_op(device, session_sync_process, &pkt, session->sid); + if (rc) { + s_vpr_e(session->sid, "Failed to create sync packet\n"); + goto err_etbs_and_ftbs; + } + + if (__iface_cmdq_write(device, &pkt, session->sid)) + rc = -ENOTEMPTY; + +err_etbs_and_ftbs: + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_get_buf_req(void *sess) +{ + struct hfi_cmd_session_get_property_packet pkt; + int rc = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -ENODEV; + goto err_create_pkt; + } + rc = call_hfi_pkt_op(device, session_get_buf_req, + &pkt, session->sid); + if (rc) { + s_vpr_e(session->sid, "%s: failed to create pkt\n", __func__); + goto err_create_pkt; + } + + if (__iface_cmdq_write(device, &pkt, session->sid)) + rc = -ENOTEMPTY; +err_create_pkt: + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode) +{ + struct hfi_cmd_session_flush_packet pkt; + int rc = 0; + struct hal_session *session = sess; + struct venus_hfi_device *device = &venus_hfi_dev; + + mutex_lock(&device->lock); + if (!__is_session_valid(device, session, __func__)) { + rc = -ENODEV; + goto err_create_pkt; + } + rc = call_hfi_pkt_op(device, session_flush, + &pkt, session->sid, flush_mode); + if (rc) { + s_vpr_e(session->sid, "Session flush: failed to create pkt\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(device, &pkt, session->sid)) + rc = -ENOTEMPTY; +err_create_pkt: + mutex_unlock(&device->lock); + return rc; +} + +static int __check_core_registered(struct hal_device_data core, + phys_addr_t fw_addr, u8 *reg_addr, u32 reg_size, + phys_addr_t irq) +{ + struct venus_hfi_device *device; + struct hal_data *hal_data; + struct list_head *curr, *next; + + if (!core.dev_count) { + d_vpr_e("no device Registered\n"); + return -EINVAL; + } + + list_for_each_safe(curr, next, &core.dev_head) { + device = list_entry(curr, + struct venus_hfi_device, list); + hal_data = device->hal_data; + if (hal_data && hal_data->irq == irq && + (CONTAINS(hal_data->firmware_base, + FIRMWARE_SIZE, fw_addr) || + CONTAINS(fw_addr, FIRMWARE_SIZE, + hal_data->firmware_base) || + CONTAINS(hal_data->register_base, + reg_size, reg_addr) || + CONTAINS(reg_addr, reg_size, + hal_data->register_base) || + OVERLAPS(hal_data->register_base, + reg_size, reg_addr, reg_size) || + OVERLAPS(reg_addr, reg_size, + hal_data->register_base, + reg_size) || + OVERLAPS(hal_data->firmware_base, + FIRMWARE_SIZE, fw_addr, + FIRMWARE_SIZE) || + OVERLAPS(fw_addr, FIRMWARE_SIZE, + hal_data->firmware_base, + FIRMWARE_SIZE))) { + return 0; + } + + d_vpr_e("Device not registered\n"); + return -EINVAL; + } + return -EINVAL; +} + +static void __process_fatal_error( + struct venus_hfi_device *device) +{ + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + cmd_done.device_id = device->device_id; + device->callback(HAL_SYS_ERROR, &cmd_done); +} + +int __prepare_pc(struct venus_hfi_device *device) +{ + int rc = 0; + struct hfi_cmd_sys_pc_prep_packet pkt; + + rc = call_hfi_pkt_op(device, sys_pc_prep, &pkt); + if (rc) { + d_vpr_e("Failed to create sys pc prep pkt\n"); + goto err_pc_prep; + } + + if (__iface_cmdq_write(device, &pkt, DEFAULT_SID)) + rc = -ENOTEMPTY; + if (rc) + d_vpr_e("Failed to prepare venus for power off"); +err_pc_prep: + return rc; +} + +static void venus_hfi_pm_handler(struct work_struct *work) +{ + int rc = 0; + struct venus_hfi_device *device = list_first_entry( + &hal_ctxt.dev_head, struct venus_hfi_device, list); + + if (!device) { + d_vpr_e("%s: NULL device\n", __func__); + return; + } + + d_vpr_h("Entering %s\n", __func__); + /* + * It is ok to check this variable outside the lock since + * it is being updated in this context only + */ + if (device->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) { + d_vpr_e("Failed to PC for %d times\n", + device->skip_pc_count); + device->skip_pc_count = 0; + __process_fatal_error(device); + return; + } + + mutex_lock(&device->lock); + rc = __power_collapse(device, false); + mutex_unlock(&device->lock); + switch (rc) { + case 0: + device->skip_pc_count = 0; + /* Cancel pending delayed works if any */ + cancel_delayed_work(&venus_hfi_pm_work); + d_vpr_h("%s: power collapse successful!\n", __func__); + break; + case -EBUSY: + device->skip_pc_count = 0; + d_vpr_h("%s: retry PC as dsp is busy\n", __func__); + queue_delayed_work(device->venus_pm_workq, + &venus_hfi_pm_work, msecs_to_jiffies( + device->res->msm_vidc_pwr_collapse_delay)); + break; + case -EAGAIN: + device->skip_pc_count++; + d_vpr_e("%s: retry power collapse (count %d)\n", + __func__, device->skip_pc_count); + queue_delayed_work(device->venus_pm_workq, + &venus_hfi_pm_work, msecs_to_jiffies( + device->res->msm_vidc_pwr_collapse_delay)); + break; + default: + d_vpr_e("%s: power collapse failed\n", __func__); + break; + } +} + +static int __prepare_pc_common(struct venus_hfi_device *device) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 ctrl_status = 0; + int count = 0; + const int max_tries = 10; + + ctrl_status = __read_register(device, CTRL_STATUS, DEFAULT_SID); + pc_ready = ctrl_status & CTRL_STATUS_PC_READY; + idle_status = ctrl_status & BIT(30); + + if (pc_ready) { + d_vpr_h("Already in pc_ready state\n"); + return 0; + } + + wfi_status = BIT(0) & __read_register(device, + WRAPPER_CPU_STATUS, DEFAULT_SID); + if (!wfi_status || !idle_status) { + d_vpr_e("Skipping PC, wfi status not set\n"); + goto skip_power_off; + } + + rc = __prepare_pc(device); + if (rc) { + d_vpr_e("Failed __prepare_pc %d\n", rc); + goto skip_power_off; + } + + while (count < max_tries) { + wfi_status = BIT(0) & __read_register(device, + WRAPPER_CPU_STATUS, DEFAULT_SID); + ctrl_status = __read_register(device, CTRL_STATUS, DEFAULT_SID); + if (wfi_status && (ctrl_status & CTRL_STATUS_PC_READY)) + break; + usleep_range(150, 250); + count++; + } + + if (count == max_tries) { + d_vpr_e("Skip PC. Core is not in right state\n"); + goto skip_power_off; + } + + return rc; + +skip_power_off: + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + return -EAGAIN; +} + +static int __power_collapse(struct venus_hfi_device *device, bool force) +{ + int rc = 0; + u32 flags = 0; + + if (!device) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + if (!device->power_enabled) { + d_vpr_h("%s: Power already disabled\n", __func__); + goto exit; + } + + if (!__core_in_valid_state(device)) { + d_vpr_e("%s: Core not in init state\n", __func__); + return -EINVAL; + } + + rc = __dsp_suspend(device, force, flags); + if (rc == -EBUSY) + goto exit; + else if (rc) + goto skip_power_off; + + rc = call_venus_op(device, prepare_pc, device); + if (rc) + goto skip_power_off; + + __flush_debug_queue(device, device->raw_packet); + + rc = __suspend(device); + if (rc) + d_vpr_e("Failed __suspend\n"); + +exit: + return rc; + +skip_power_off: + return -EAGAIN; +} + +static void print_sfr_message(struct venus_hfi_device *device) +{ + struct hfi_sfr_struct *vsfr = NULL; + u32 vsfr_size = 0; + void *p = NULL; + + vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr; + if (vsfr) { + if (vsfr->bufSize != device->sfr.mem_size) { + d_vpr_e("Invalid SFR buf size %d actual %d\n", + vsfr->bufSize, device->sfr.mem_size); + return; + } + vsfr_size = vsfr->bufSize - sizeof(u32); + p = memchr(vsfr->rg_data, '\0', vsfr_size); + /* SFR isn't guaranteed to be NULL terminated */ + if (p == NULL) + vsfr->rg_data[vsfr_size - 1] = '\0'; + + d_vpr_e("SFR Message from FW: %s\n", vsfr->rg_data); + } +} + +static void __flush_debug_queue(struct venus_hfi_device *device, u8 *packet) +{ + bool local_packet = false; + enum vidc_msg_prio log_level = msm_vidc_debug; + + if (!device) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + if (!packet) { + packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_KERNEL); + if (!packet) { + d_vpr_e("In %s() Fail to allocate mem\n", __func__); + return; + } + + local_packet = true; + + /* + * Local packek is used when error occurred. + * It is good to print these logs to printk as well. + */ + log_level |= FW_PRINTK; + } + +#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \ + if (pkt_size < pkt_hdr_size || \ + payload_size < MIN_PAYLOAD_SIZE || \ + payload_size > \ + (pkt_size - pkt_hdr_size + sizeof(u8))) { \ + d_vpr_e("%s: invalid msg size - %d\n", \ + __func__, pkt->msg_size); \ + continue; \ + } \ + }) + + while (!__iface_dbgq_read(device, packet)) { + struct hfi_packet_header *pkt = + (struct hfi_packet_header *) packet; + + if (pkt->size < sizeof(struct hfi_packet_header)) { + d_vpr_e("Invalid pkt size - %s\n", __func__); + continue; + } + + if (pkt->packet_type == HFI_MSG_SYS_COV) { + struct hfi_msg_sys_coverage_packet *pkt = + (struct hfi_msg_sys_coverage_packet *) packet; + int stm_size = 0; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + + stm_size = stm_log_inv_ts(0, 0, + pkt->rg_msg_data, pkt->msg_size); + if (stm_size == 0) + d_vpr_e("In %s, stm_log returned size of 0\n", + __func__); + + } else if (pkt->packet_type == HFI_MSG_SYS_DEBUG) { + struct hfi_msg_sys_debug_packet *pkt = + (struct hfi_msg_sys_debug_packet *) packet; + + SKIP_INVALID_PKT(pkt->size, + pkt->msg_size, sizeof(*pkt)); + + /* + * All fw messages starts with new line character. This + * causes dprintk to print this message in two lines + * in the kernel log. Ignoring the first character + * from the message fixes this to print it in a single + * line. + */ + pkt->rg_msg_data[pkt->msg_size-1] = '\0'; + dprintk_firmware(log_level, "%s", &pkt->rg_msg_data[1]); + } + } +#undef SKIP_INVALID_PKT + + if (local_packet) + kfree(packet); +} + +static bool __is_session_valid(struct venus_hfi_device *device, + struct hal_session *session, const char *func) +{ + struct hal_session *temp = NULL; + + if (!device || !session) + goto invalid; + + list_for_each_entry(temp, &device->sess_head, list) + if (session == temp) + return true; + +invalid: + d_vpr_e("%s: device %pK, invalid session %pK\n", func, device, session); + return false; +} + +static struct hal_session *__get_session(struct venus_hfi_device *device, + u32 sid) +{ + struct hal_session *temp = NULL; + + list_for_each_entry(temp, &device->sess_head, list) { + if (sid == temp->sid) + return temp; + } + + return NULL; +} + +static bool __watchdog_common(u32 intr_status) +{ + bool rc = false; + + if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK) + rc = true; + + return rc; +} + +static int __response_handler(struct venus_hfi_device *device) +{ + struct msm_vidc_cb_info *packets; + int packet_count = 0; + u8 *raw_packet = NULL; + bool requeue_pm_work = true; + + if (!device || device->state != VENUS_STATE_INIT) + return 0; + + packets = device->response_pkt; + + raw_packet = device->raw_packet; + + if (!raw_packet || !packets) { + d_vpr_e("%s: Invalid args %pK, %pK\n", + __func__, raw_packet, packets); + return 0; + } + + if (call_venus_op(device, watchdog, device->intr_status)) { + struct msm_vidc_cb_info info = { + .response_type = HAL_SYS_WATCHDOG_TIMEOUT, + .response.cmd = { + .device_id = device->device_id, + } + }; + + print_sfr_message(device); + + d_vpr_e("Received watchdog timeout\n"); + packets[packet_count++] = info; + goto exit; + } + + /* Bleed the msg queue dry of packets */ + while (!__iface_msgq_read(device, raw_packet)) { + void **inst_id = NULL; + struct msm_vidc_cb_info *info = &packets[packet_count++]; + int rc = 0; + + rc = hfi_process_msg_packet(device->device_id, + (struct vidc_hal_msg_pkt_hdr *)raw_packet, info); + if (rc) { + d_vpr_e("Corrupt/unknown packet found, discarding\n"); + --packet_count; + continue; + } + + /* Process the packet types that we're interested in */ + switch (info->response_type) { + case HAL_SYS_ERROR: + print_sfr_message(device); + break; + case HAL_SYS_RELEASE_RESOURCE_DONE: + d_vpr_h("Received SYS_RELEASE_RESOURCE\n"); + break; + case HAL_SYS_INIT_DONE: + d_vpr_h("Received SYS_INIT_DONE\n"); + break; + case HAL_SESSION_LOAD_RESOURCE_DONE: + break; + default: + break; + } + + /* For session-related packets, validate session */ + switch (info->response_type) { + case HAL_SESSION_LOAD_RESOURCE_DONE: + case HAL_SESSION_INIT_DONE: + case HAL_SESSION_END_DONE: + case HAL_SESSION_ABORT_DONE: + case HAL_SESSION_START_DONE: + case HAL_SESSION_STOP_DONE: + case HAL_SESSION_FLUSH_DONE: + case HAL_SESSION_SUSPEND_DONE: + case HAL_SESSION_RESUME_DONE: + case HAL_SESSION_SET_PROP_DONE: + case HAL_SESSION_GET_PROP_DONE: + case HAL_SESSION_RELEASE_BUFFER_DONE: + case HAL_SESSION_REGISTER_BUFFER_DONE: + case HAL_SESSION_UNREGISTER_BUFFER_DONE: + case HAL_SESSION_RELEASE_RESOURCE_DONE: + case HAL_SESSION_PROPERTY_INFO: + inst_id = &info->response.cmd.inst_id; + break; + case HAL_SESSION_ERROR: + case HAL_SESSION_ETB_DONE: + case HAL_SESSION_FTB_DONE: + inst_id = &info->response.data.inst_id; + break; + case HAL_SESSION_EVENT_CHANGE: + inst_id = &info->response.event.inst_id; + break; + case HAL_RESPONSE_UNUSED: + default: + inst_id = NULL; + break; + } + + /* + * hfi_process_msg_packet provides a sid, we need to coerce + * the sid value back to pointer(inst_id) that we can + * use. Ideally, hfi_process_msg_packet should take care of + * this, but it doesn't have required information for it + */ + if (inst_id) { + struct hal_session *session = NULL; + + if (upper_32_bits((uintptr_t)*inst_id) != 0) { + d_vpr_e("Upper 32-bits != 0 for sess_id=%pK\n", + *inst_id); + } + session = __get_session(device, + (u32)(uintptr_t)*inst_id); + if (!session) { + d_vpr_e( + "Received a packet (%#x) for an unrecognized session (%pK), discarding\n", + info->response_type, *inst_id); + --packet_count; + continue; + } + + *inst_id = session->inst_id; + } + + if (packet_count >= max_packets) { + d_vpr_e( + "Too many packets in message queue to handle at once, deferring read\n"); + break; + } + + /* do not read packets after sys error packet */ + if (info->response_type == HAL_SYS_ERROR) + break; + } + + if (requeue_pm_work && device->res->sw_power_collapsible) { + cancel_delayed_work(&venus_hfi_pm_work); + if (!queue_delayed_work(device->venus_pm_workq, + &venus_hfi_pm_work, + msecs_to_jiffies( + device->res->msm_vidc_pwr_collapse_delay))) { + d_vpr_e("PM work already scheduled\n"); + } + } + +exit: + __flush_debug_queue(device, raw_packet); + + return packet_count; +} + +static void venus_hfi_core_work_handler(struct work_struct *work) +{ + struct venus_hfi_device *device = list_first_entry( + &hal_ctxt.dev_head, struct venus_hfi_device, list); + int num_responses = 0, i = 0; + u32 intr_status; + + mutex_lock(&device->lock); + if (!__core_in_valid_state(device)) { + d_vpr_e("%s: Core not in init state\n", __func__); + goto err_no_work; + } + + if (!device->callback) { + d_vpr_e("No interrupt callback function: %pK\n", + device); + goto err_no_work; + } + + if (__resume(device, DEFAULT_SID)) { + d_vpr_e("%s: Power enable failed\n", __func__); + goto err_no_work; + } + + call_venus_op(device, core_clear_interrupt, device); + num_responses = __response_handler(device); + +err_no_work: + + /* Keep the interrupt status before releasing device lock */ + intr_status = device->intr_status; + mutex_unlock(&device->lock); + + /* + * Issue the callbacks outside of the locked contex to preserve + * re-entrancy. + */ + + for (i = 0; !IS_ERR_OR_NULL(device->response_pkt) && + i < num_responses; ++i) { + struct msm_vidc_cb_info *r = &device->response_pkt[i]; + + if (!__core_in_valid_state(device)) { + d_vpr_e( + "Ignore responses from %d to %d as device is in invalid state", + (i + 1), num_responses); + break; + } + device->callback(r->response_type, &r->response); + } + + /* We need re-enable the irq which was disabled in ISR handler */ + if (!call_venus_op(device, watchdog, intr_status)) + enable_irq(device->hal_data->irq); + + /* + * XXX: Don't add any code beyond here. Reacquiring locks after release + * it above doesn't guarantee the atomicity that we're aiming for. + */ +} + +static DECLARE_WORK(venus_hfi_work, venus_hfi_core_work_handler); + +static irqreturn_t venus_hfi_isr(int irq, void *dev) +{ + struct venus_hfi_device *device = dev; + + disable_irq_nosync(irq); + queue_work(device->vidc_workq, &venus_hfi_work); + return IRQ_HANDLED; +} + +static int __init_regs_and_interrupts(struct venus_hfi_device *device, + struct msm_vidc_platform_resources *res) +{ + struct hal_data *hal = NULL; + int rc = 0; + + rc = __check_core_registered(hal_ctxt, res->firmware_base, + (u8 *)(uintptr_t)res->register_base, + res->register_size, res->irq); + if (!rc) { + d_vpr_e("Core present/Already added\n"); + rc = -EEXIST; + goto err_core_init; + } + + d_vpr_h("HAL_DATA will be assigned now\n"); + hal = kzalloc(sizeof(struct hal_data), GFP_KERNEL); + if (!hal) { + d_vpr_e("Failed to alloc\n"); + rc = -ENOMEM; + goto err_core_init; + } + + hal->irq = res->irq; + hal->firmware_base = res->firmware_base; + hal->register_base = devm_ioremap_nocache(&res->pdev->dev, + res->register_base, res->register_size); + hal->register_size = res->register_size; + if (!hal->register_base) { + d_vpr_e("could not map reg addr %pa of size %d\n", + &res->register_base, res->register_size); + goto error_irq_fail; + } + + device->hal_data = hal; + rc = request_irq(res->irq, venus_hfi_isr, IRQF_TRIGGER_HIGH, + "msm_vidc", device); + if (unlikely(rc)) { + d_vpr_e("%s: request_irq failed\n", __func__); + goto error_irq_fail; + } + + disable_irq_nosync(res->irq); + d_vpr_h("firmware_base = %pa, reg_base = %pa, reg_size = %d\n", + &res->firmware_base, &res->register_base, + res->register_size); + + return rc; + +error_irq_fail: + kfree(hal); +err_core_init: + return rc; + +} + +static inline void __deinit_clocks(struct venus_hfi_device *device) +{ + struct clock_info *cl; + + device->clk_freq = 0; + venus_hfi_for_each_clock_reverse(device, cl) { + if (cl->clk) { + clk_put(cl->clk); + cl->clk = NULL; + } + } +} + +static inline int __init_clocks(struct venus_hfi_device *device) +{ + int rc = 0; + struct clock_info *cl = NULL; + + if (!device) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + venus_hfi_for_each_clock(device, cl) { + d_vpr_h("%s: scalable? %d, count %d\n", + cl->name, cl->has_scaling, cl->count); + } + + venus_hfi_for_each_clock(device, cl) { + if (!cl->clk) { + cl->clk = clk_get(&device->res->pdev->dev, cl->name); + if (IS_ERR_OR_NULL(cl->clk)) { + d_vpr_e("Failed to get clock: %s\n", cl->name); + rc = PTR_ERR(cl->clk) ? + PTR_ERR(cl->clk) : -EINVAL; + cl->clk = NULL; + goto err_clk_get; + } + } + } + device->clk_freq = 0; + return 0; + +err_clk_get: + __deinit_clocks(device); + return rc; +} + +static int __handle_reset_clk(struct msm_vidc_platform_resources *res, + int reset_index, enum reset_state state, u32 sid) +{ + int rc = 0; + struct reset_control *rst; + struct reset_set *rst_set = &res->reset_set; + + if (!rst_set->reset_tbl) + return 0; + + rst = rst_set->reset_tbl[reset_index].rst; + s_vpr_h(sid, "reset_clk: name %s reset_state %d rst %pK\n", + rst_set->reset_tbl[reset_index].name, state, rst); + + switch (state) { + case INIT: + if (rst) + goto skip_reset_init; + + rst = devm_reset_control_get(&res->pdev->dev, + rst_set->reset_tbl[reset_index].name); + if (IS_ERR(rst)) + rc = PTR_ERR(rst); + + rst_set->reset_tbl[reset_index].rst = rst; + break; + case ASSERT: + if (!rst) { + rc = PTR_ERR(rst); + goto failed_to_reset; + } + + rc = reset_control_assert(rst); + break; + case DEASSERT: + if (!rst) { + rc = PTR_ERR(rst); + goto failed_to_reset; + } + rc = reset_control_deassert(rst); + break; + default: + s_vpr_e(sid, "Invalid reset request\n"); + if (rc) + goto failed_to_reset; + } + + return 0; + +skip_reset_init: +failed_to_reset: + return rc; +} + +void __disable_unprepare_clks(struct venus_hfi_device *device) +{ + struct clock_info *cl; + int rc = 0; + + if (!device) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + venus_hfi_for_each_clock_reverse(device, cl) { + d_vpr_h("Clock: %s disable and unprepare\n", + cl->name); + rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH); + if (rc) { + d_vpr_e("Failed set flag NORETAIN_PERIPH %s\n", + cl->name); + } + rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM); + if (rc) { + d_vpr_e("Failed set flag NORETAIN_MEM %s\n", + cl->name); + } + + if (!__clk_is_enabled(cl->clk)) + d_vpr_e("%s: clock %s already disabled\n", + __func__, cl->name); + + clk_disable_unprepare(cl->clk); + + if (__clk_is_enabled(cl->clk)) + d_vpr_e("%s: clock %s not disabled\n", + __func__, cl->name); + } +} + +int __reset_ahb2axi_bridge_common(struct venus_hfi_device *device, u32 sid) +{ + int rc, i; + + if (!device) { + s_vpr_e(sid, "NULL device\n"); + rc = -EINVAL; + goto failed_to_reset; + } + + for (i = 0; i < device->res->reset_set.count; i++) { + rc = __handle_reset_clk(device->res, i, ASSERT, sid); + if (rc) { + s_vpr_e(sid, "failed to assert reset clocks\n"); + goto failed_to_reset; + } + + /* wait for deassert */ + usleep_range(150, 250); + + rc = __handle_reset_clk(device->res, i, DEASSERT, sid); + if (rc) { + s_vpr_e(sid, "failed to deassert reset clocks\n"); + goto failed_to_reset; + } + } + + return 0; + +failed_to_reset: + return rc; +} + +static inline int __prepare_enable_clks(struct venus_hfi_device *device, + u32 sid) +{ + struct clock_info *cl = NULL, *cl_fail = NULL; + int rc = 0, c = 0; + + if (!device) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return -EINVAL; + } + + venus_hfi_for_each_clock(device, cl) { + /* + * For the clocks we control, set the rate prior to preparing + * them. Since we don't really have a load at this point, scale + * it to the lowest frequency possible + */ + if (cl->has_scaling) + __set_clk_rate(device, cl, + clk_round_rate(cl->clk, 0), sid); + + rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_PERIPH); + if (rc) { + s_vpr_e(sid, "Failed set flag RETAIN_PERIPH %s\n", + cl->name); + } + rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_MEM); + if (rc) { + s_vpr_e(sid, "Failed set flag RETAIN_MEM %s\n", + cl->name); + } + + if (__clk_is_enabled(cl->clk)) + s_vpr_e(sid, "%s: clock %s already enabled\n", + __func__, cl->name); + + rc = clk_prepare_enable(cl->clk); + if (rc) { + s_vpr_e(sid, "Failed to enable clocks\n"); + cl_fail = cl; + goto fail_clk_enable; + } + + if (!__clk_is_enabled(cl->clk)) + s_vpr_e(sid, "%s: clock %s not enabled\n", + __func__, cl->name); + + c++; + s_vpr_h(sid, "Clock: %s prepared and enabled\n", cl->name); + } + + call_venus_op(device, clock_config_on_enable, device, sid); + return rc; + +fail_clk_enable: + venus_hfi_for_each_clock_reverse_continue(device, cl, c) { + s_vpr_e(sid, "Clock: %s disable and unprepare\n", + cl->name); + clk_disable_unprepare(cl->clk); + } + + return rc; +} + +static void __deinit_bus(struct venus_hfi_device *device) +{ + struct bus_info *bus = NULL; + + if (!device) + return; + + device->bus_vote = DEFAULT_BUS_VOTE; + + venus_hfi_for_each_bus_reverse(device, bus) { + msm_bus_scale_unregister(bus->client); + bus->client = NULL; + } +} + +static int __init_bus(struct venus_hfi_device *device) +{ + struct bus_info *bus = NULL; + int rc = 0; + + if (!device) + return -EINVAL; + + venus_hfi_for_each_bus(device, bus) { + if (!strcmp(bus->mode, "msm-vidc-llcc")) { + if (msm_vidc_syscache_disable) { + d_vpr_h("Skipping LLC bus init %s: %s\n", + bus->name, bus->mode); + continue; + } + } + bus->client = msm_bus_scale_register(bus->master, bus->slave, + bus->name, false); + if (IS_ERR_OR_NULL(bus->client)) { + rc = PTR_ERR(bus->client) ? + PTR_ERR(bus->client) : -EBADHANDLE; + d_vpr_e("Failed to register bus %s: %d\n", + bus->name, rc); + bus->client = NULL; + goto err_add_dev; + } + } + + return 0; + +err_add_dev: + __deinit_bus(device); + return rc; +} + +static void __deinit_regulators(struct venus_hfi_device *device) +{ + struct regulator_info *rinfo = NULL; + + venus_hfi_for_each_regulator_reverse(device, rinfo) { + if (rinfo->regulator) { + regulator_put(rinfo->regulator); + rinfo->regulator = NULL; + } + } +} + +static int __init_regulators(struct venus_hfi_device *device) +{ + int rc = 0; + struct regulator_info *rinfo = NULL; + + venus_hfi_for_each_regulator(device, rinfo) { + rinfo->regulator = regulator_get(&device->res->pdev->dev, + rinfo->name); + if (IS_ERR_OR_NULL(rinfo->regulator)) { + rc = PTR_ERR(rinfo->regulator) ? + PTR_ERR(rinfo->regulator) : -EBADHANDLE; + d_vpr_e("Failed to get regulator: %s\n", rinfo->name); + rinfo->regulator = NULL; + goto err_reg_get; + } + } + + return 0; + +err_reg_get: + __deinit_regulators(device); + return rc; +} + +static void __deinit_subcaches(struct venus_hfi_device *device) +{ + struct subcache_info *sinfo = NULL; + + if (!device) { + d_vpr_e("deinit_subcaches: invalid device %pK\n", device); + goto exit; + } + + if (!is_sys_cache_present(device)) + goto exit; + + venus_hfi_for_each_subcache_reverse(device, sinfo) { + if (sinfo->subcache) { + d_vpr_h("deinit_subcaches: %s\n", sinfo->name); + llcc_slice_putd(sinfo->subcache); + sinfo->subcache = NULL; + } + } + +exit: + return; +} + +static int __init_subcaches(struct venus_hfi_device *device) +{ + int rc = 0; + struct subcache_info *sinfo = NULL; + + if (!device) { + d_vpr_e("init_subcaches: invalid device %pK\n", + device); + return -EINVAL; + } + + if (!is_sys_cache_present(device)) + return 0; + + venus_hfi_for_each_subcache(device, sinfo) { + if (!strcmp("vidsc0", sinfo->name)) { + sinfo->subcache = llcc_slice_getd(LLCC_VIDSC0); + } else if (!strcmp("vidsc1", sinfo->name)) { + sinfo->subcache = llcc_slice_getd(LLCC_VIDSC1); + } else if (!strcmp("vidscfw", sinfo->name)) { + sinfo->subcache = llcc_slice_getd(LLCC_VIDFW); + } else { + d_vpr_e("Invalid subcache name %s\n", + sinfo->name); + } + if (IS_ERR_OR_NULL(sinfo->subcache)) { + rc = PTR_ERR(sinfo->subcache) ? + PTR_ERR(sinfo->subcache) : -EBADHANDLE; + d_vpr_e("init_subcaches: invalid subcache: %s rc %d\n", + sinfo->name, rc); + sinfo->subcache = NULL; + goto err_subcache_get; + } + d_vpr_h("init_subcaches: %s\n", sinfo->name); + } + + return 0; + +err_subcache_get: + __deinit_subcaches(device); + return rc; +} + +static int __init_resources(struct venus_hfi_device *device, + struct msm_vidc_platform_resources *res) +{ + int i, rc = 0; + + rc = __init_regulators(device); + if (rc) { + d_vpr_e("Failed to get all regulators\n"); + return -ENODEV; + } + + rc = __init_clocks(device); + if (rc) { + d_vpr_e("Failed to init clocks\n"); + rc = -ENODEV; + goto err_init_clocks; + } + + for (i = 0; i < device->res->reset_set.count; i++) { + rc = __handle_reset_clk(res, i, INIT, DEFAULT_SID); + if (rc) { + d_vpr_e("Failed to init reset clocks\n"); + rc = -ENODEV; + goto err_init_reset_clk; + } + } + + rc = __init_bus(device); + if (rc) { + d_vpr_e("Failed to init bus: %d\n", rc); + goto err_init_bus; + } + + rc = __init_subcaches(device); + if (rc) + d_vpr_e("Failed to init subcaches: %d\n", rc); + + return rc; + +err_init_reset_clk: +err_init_bus: + __deinit_clocks(device); +err_init_clocks: + __deinit_regulators(device); + return rc; +} + +static void __deinit_resources(struct venus_hfi_device *device) +{ + __deinit_subcaches(device); + __deinit_bus(device); + __deinit_clocks(device); + __deinit_regulators(device); +} + +static int __protect_cp_mem(struct venus_hfi_device *device) +{ + struct tzbsp_memprot memprot; + unsigned int resp = 0; + int rc = 0; + struct context_bank_info *cb; + struct scm_desc desc = {0}; + + if (!device) + return -EINVAL; + + memprot.cp_start = 0x0; + memprot.cp_size = 0x0; + memprot.cp_nonpixel_start = 0x0; + memprot.cp_nonpixel_size = 0x0; + + mutex_lock(&device->res->cb_lock); + list_for_each_entry(cb, &device->res->context_banks, list) { + if (!strcmp(cb->name, "venus_ns")) { + desc.args[1] = memprot.cp_size = + cb->addr_range.start; + d_vpr_h("%s: memprot.cp_size: %#x\n", + __func__, memprot.cp_size); + } + + if (!strcmp(cb->name, "venus_sec_non_pixel")) { + desc.args[2] = memprot.cp_nonpixel_start = + cb->addr_range.start; + desc.args[3] = memprot.cp_nonpixel_size = + cb->addr_range.size; + d_vpr_h("%s: cp_nonpixel_start: %#x size: %#x\n", + __func__, memprot.cp_nonpixel_start, + memprot.cp_nonpixel_size); + } + } + mutex_unlock(&device->res->cb_lock); + + desc.arginfo = SCM_ARGS(4); + rc = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + TZBSP_MEM_PROTECT_VIDEO_VAR), &desc); + resp = desc.ret[0]; + + if (rc) { + d_vpr_e("Failed to protect memory(%d) response: %d\n", + rc, resp); + } + + trace_venus_hfi_var_done( + memprot.cp_start, memprot.cp_size, + memprot.cp_nonpixel_start, memprot.cp_nonpixel_size); + return rc; +} + +static int __disable_regulator(struct regulator_info *rinfo, + struct venus_hfi_device *device) +{ + int rc = 0; + + d_vpr_h("Disabling regulator %s\n", rinfo->name); + + /* + * This call is needed. Driver needs to acquire the control back + * from HW in order to disable the regualtor. Else the behavior + * is unknown. + */ + + rc = __acquire_regulator(rinfo, device, DEFAULT_SID); + if (rc) { + /* + * This is somewhat fatal, but nothing we can do + * about it. We can't disable the regulator w/o + * getting it back under s/w control + */ + d_vpr_e("Failed to acquire control on %s\n", + rinfo->name); + + goto disable_regulator_failed; + } + + if (!regulator_is_enabled(rinfo->regulator)) + d_vpr_e("%s: regulator %s already disabled\n", + __func__, rinfo->name); + + rc = regulator_disable(rinfo->regulator); + if (rc) { + d_vpr_e("Failed to disable %s: %d\n", + rinfo->name, rc); + goto disable_regulator_failed; + } + + if (regulator_is_enabled(rinfo->regulator)) + d_vpr_e("%s: regulator %s not disabled\n", + __func__, rinfo->name); + + return 0; +disable_regulator_failed: + + /* Bring attention to this issue */ + msm_vidc_res_handle_fatal_hw_error(device->res, true); + return rc; +} + +static int __enable_hw_power_collapse(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + + rc = __hand_off_regulators(device, sid); + if (rc) + s_vpr_e(sid, "%s: Failed to enable HW power collapse %d\n", + __func__, rc); + return rc; +} + +static int __enable_regulators(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0, c = 0; + struct regulator_info *rinfo; + + s_vpr_h(sid, "Enabling regulators\n"); + + venus_hfi_for_each_regulator(device, rinfo) { + if (regulator_is_enabled(rinfo->regulator)) + s_vpr_e(sid, "%s: regulator %s already enabled\n", + __func__, rinfo->name); + + rc = regulator_enable(rinfo->regulator); + if (rc) { + s_vpr_e(sid, "Failed to enable %s: %d\n", + rinfo->name, rc); + goto err_reg_enable_failed; + } + + if (!regulator_is_enabled(rinfo->regulator)) + s_vpr_e(sid, "%s: regulator %s not enabled\n", + __func__, rinfo->name); + + s_vpr_h(sid, "Enabled regulator %s\n", + rinfo->name); + c++; + } + + return 0; + +err_reg_enable_failed: + venus_hfi_for_each_regulator_reverse_continue(device, rinfo, c) + __disable_regulator(rinfo, device); + + return rc; +} + +int __disable_regulators(struct venus_hfi_device *device) +{ + struct regulator_info *rinfo; + + d_vpr_h("Disabling regulators\n"); + venus_hfi_for_each_regulator_reverse(device, rinfo) + __disable_regulator(rinfo, device); + + return 0; +} + +static int __enable_subcaches(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + u32 c = 0; + struct subcache_info *sinfo; + + if (msm_vidc_syscache_disable || !is_sys_cache_present(device)) + return 0; + + /* Activate subcaches */ + venus_hfi_for_each_subcache(device, sinfo) { + rc = llcc_slice_activate(sinfo->subcache); + if (rc) { + s_vpr_e(sid, "Failed to activate %s: %d\n", + sinfo->name, rc); + msm_vidc_res_handle_fatal_hw_error(device->res, true); + goto err_activate_fail; + } + sinfo->isactive = true; + s_vpr_h(sid, "Activated subcache %s\n", sinfo->name); + c++; + } + + s_vpr_h(sid, "Activated %d Subcaches to Venus\n", c); + + return 0; + +err_activate_fail: + __release_subcaches(device, sid); + __disable_subcaches(device, sid); + return 0; +} + +static int __set_subcaches(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + u32 c = 0; + struct subcache_info *sinfo; + u32 resource[VIDC_MAX_SUBCACHE_SIZE]; + struct hfi_resource_syscache_info_type *sc_res_info; + struct hfi_resource_subcache_type *sc_res; + struct vidc_resource_hdr rhdr; + + if (device->res->sys_cache_res_set) { + s_vpr_h(sid, "Subcaches already set to Venus\n"); + return 0; + } + + memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE)); + + sc_res_info = (struct hfi_resource_syscache_info_type *)resource; + sc_res = &(sc_res_info->rg_subcache_entries[0]); + + venus_hfi_for_each_subcache(device, sinfo) { + if (sinfo->isactive) { + sc_res[c].size = sinfo->subcache->slice_size; + sc_res[c].sc_id = sinfo->subcache->slice_id; + c++; + } + } + + /* Set resource to Venus for activated subcaches */ + if (c) { + s_vpr_h(sid, "Setting %d Subcaches\n", c); + + rhdr.resource_handle = sc_res_info; /* cookie */ + rhdr.resource_id = VIDC_RESOURCE_SYSCACHE; + + sc_res_info->num_entries = c; + + rc = __core_set_resource(device, &rhdr, (void *)sc_res_info); + if (rc) { + s_vpr_e(sid, "Failed to set subcaches %d\n", rc); + goto err_fail_set_subacaches; + } + + venus_hfi_for_each_subcache(device, sinfo) { + if (sinfo->isactive) + sinfo->isset = true; + } + + s_vpr_h(sid, "Set Subcaches done to Venus\n"); + device->res->sys_cache_res_set = true; + } + + return 0; + +err_fail_set_subacaches: + __disable_subcaches(device, sid); + + return 0; +} + +static int __release_subcaches(struct venus_hfi_device *device, u32 sid) +{ + struct subcache_info *sinfo; + int rc = 0; + u32 c = 0; + u32 resource[VIDC_MAX_SUBCACHE_SIZE]; + struct hfi_resource_syscache_info_type *sc_res_info; + struct hfi_resource_subcache_type *sc_res; + struct vidc_resource_hdr rhdr; + + if (msm_vidc_syscache_disable || !is_sys_cache_present(device)) + return 0; + + memset((void *)resource, 0x0, (sizeof(u32) * VIDC_MAX_SUBCACHE_SIZE)); + + sc_res_info = (struct hfi_resource_syscache_info_type *)resource; + sc_res = &(sc_res_info->rg_subcache_entries[0]); + + /* Release resource command to Venus */ + venus_hfi_for_each_subcache_reverse(device, sinfo) { + if (sinfo->isset) { + /* Update the entry */ + sc_res[c].size = sinfo->subcache->slice_size; + sc_res[c].sc_id = sinfo->subcache->slice_id; + c++; + sinfo->isset = false; + } + } + + if (c > 0) { + s_vpr_h(sid, "Releasing %d subcaches\n", c); + rhdr.resource_handle = sc_res_info; /* cookie */ + rhdr.resource_id = VIDC_RESOURCE_SYSCACHE; + + rc = __core_release_resource(device, &rhdr); + if (rc) + s_vpr_e(sid, "Failed to release %d subcaches\n", c); + } + + device->res->sys_cache_res_set = false; + + return 0; +} + +static int __disable_subcaches(struct venus_hfi_device *device, u32 sid) +{ + struct subcache_info *sinfo; + int rc = 0; + + if (msm_vidc_syscache_disable || !is_sys_cache_present(device)) + return 0; + + /* De-activate subcaches */ + venus_hfi_for_each_subcache_reverse(device, sinfo) { + if (sinfo->isactive) { + s_vpr_h(sid, "De-activate subcache %s\n", + sinfo->name); + rc = llcc_slice_deactivate(sinfo->subcache); + if (rc) { + s_vpr_e(sid, "Failed to de-activate %s: %d\n", + sinfo->name, rc); + } + sinfo->isactive = false; + } + } + + return 0; +} + +static int __set_ubwc_config(struct venus_hfi_device *device) +{ + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int rc = 0; + + struct hfi_cmd_sys_set_property_packet *pkt = + (struct hfi_cmd_sys_set_property_packet *) &packet; + + if (!device->res->ubwc_config) + return 0; + + rc = call_hfi_pkt_op(device, sys_ubwc_config, pkt, + device->res->ubwc_config); + if (rc) { + d_vpr_e("ubwc config setting to FW failed\n"); + rc = -ENOTEMPTY; + goto fail_to_set_ubwc_config; + } + + if (__iface_cmdq_write(device, pkt, DEFAULT_SID)) { + rc = -ENOTEMPTY; + goto fail_to_set_ubwc_config; + } + + d_vpr_h("Configured UBWC Config to Venus\n"); + +fail_to_set_ubwc_config: + return rc; +} + +static int __venus_power_on(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + + if (device->power_enabled) + return 0; + + device->power_enabled = true; + /* Vote for all hardware resources */ + rc = __vote_buses(device, INT_MAX, INT_MAX, sid); + if (rc) { + s_vpr_e(sid, "Failed to vote buses, err: %d\n", rc); + goto fail_vote_buses; + } + + rc = __enable_regulators(device, sid); + if (rc) { + s_vpr_e(sid, "Failed to enable GDSC, err = %d\n", rc); + goto fail_enable_gdsc; + } + + rc = call_venus_op(device, reset_ahb2axi_bridge, device, sid); + if (rc) { + s_vpr_e(sid, "Failed to reset ahb2axi: %d\n", rc); + goto fail_enable_clks; + } + + rc = __prepare_enable_clks(device, sid); + if (rc) { + s_vpr_e(sid, "Failed to enable clocks: %d\n", rc); + goto fail_enable_clks; + } + + rc = __scale_clocks(device, sid); + if (rc) { + s_vpr_e(sid, + "Failed to scale clocks, performance might be affected\n"); + rc = 0; + } + + /* + * Re-program all of the registers that get reset as a result of + * regulator_disable() and _enable() + */ + __set_registers(device, sid); + + call_venus_op(device, interrupt_init, device, sid); + device->intr_status = 0; + enable_irq(device->hal_data->irq); + + return rc; + +fail_enable_clks: + __disable_regulators(device); +fail_enable_gdsc: + __unvote_buses(device, sid); +fail_vote_buses: + device->power_enabled = false; + return rc; +} + +static void __power_off_common(struct venus_hfi_device *device) +{ + if (!device->power_enabled) + return; + + if (!(device->intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK)) + disable_irq_nosync(device->hal_data->irq); + device->intr_status = 0; + + __disable_unprepare_clks(device); + if (call_venus_op(device, reset_ahb2axi_bridge, device, DEFAULT_SID)) + d_vpr_e("Failed to reset ahb2axi\n"); + + if (__disable_regulators(device)) + d_vpr_e("Failed to disable regulators\n"); + + if (__unvote_buses(device, DEFAULT_SID)) + d_vpr_e("Failed to unvote for buses\n"); + device->power_enabled = false; +} + +static inline int __suspend(struct venus_hfi_device *device) +{ + int rc = 0; + + if (!device) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } else if (!device->power_enabled) { + d_vpr_h("Power already disabled\n"); + return 0; + } + + d_vpr_h("Entering suspend\n"); + + if (device->res->pm_qos_latency_us && + pm_qos_request_active(&device->qos)) + pm_qos_remove_request(&device->qos); + + rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND, DEFAULT_SID); + if (rc) { + d_vpr_e("Failed to suspend video core %d\n", rc); + goto err_tzbsp_suspend; + } + + __disable_subcaches(device, DEFAULT_SID); + + call_venus_op(device, power_off, device); + d_vpr_h("Venus power off\n"); + return rc; + +err_tzbsp_suspend: + return rc; +} + +static inline int __resume(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + u32 flags = 0; + + if (!device) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return -EINVAL; + } else if (device->power_enabled) { + goto exit; + } else if (!__core_in_valid_state(device)) { + s_vpr_e(sid, "venus_hfi_device in deinit state."); + return -EINVAL; + } + + s_vpr_h(sid, "Resuming from power collapse\n"); + rc = __venus_power_on(device, sid); + if (rc) { + s_vpr_e(sid, "Failed to power on venus\n"); + goto err_venus_power_on; + } + + /* Reboot the firmware */ + rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME, sid); + if (rc) { + s_vpr_e(sid, "Failed to resume video core %d\n", rc); + goto err_set_video_state; + } + + /* + * Hand off control of regulators to h/w _after_ loading fw. + * Note that the GDSC will turn off when switching from normal + * (s/w triggered) to fast (HW triggered) unless the h/w vote is + * present. + */ + if (__enable_hw_power_collapse(device, sid)) + s_vpr_e(sid, "Failed to enabled inter-frame PC\n"); + + call_venus_op(device, setup_ucregion_memmap, device, sid); + + /* Wait for boot completion */ + rc = call_venus_op(device, boot_firmware, device, sid); + if (rc) { + s_vpr_e(sid, "Failed to reset venus core\n"); + goto err_reset_core; + } + + if (device->res->pm_qos_latency_us) { +#ifdef CONFIG_SMP + device->qos.type = PM_QOS_REQ_AFFINE_IRQ; + device->qos.irq = device->hal_data->irq; +#endif + pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY, + device->res->pm_qos_latency_us); + } + + __sys_set_debug(device, (msm_vidc_debug & FW_LOGMASK) >> FW_LOGSHIFT, + sid); + + __enable_subcaches(device, sid); + __set_subcaches(device, sid); + __dsp_resume(device, flags); + + s_vpr_h(sid, "Resumed from power collapse\n"); +exit: + /* Don't reset skip_pc_count for SYS_PC_PREP cmd */ + if (device->last_packet_type != HFI_CMD_SYS_PC_PREP) + device->skip_pc_count = 0; + return rc; +err_reset_core: + __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND, sid); +err_set_video_state: + call_venus_op(device, power_off, device); +err_venus_power_on: + s_vpr_e(sid, "Failed to resume from power collapse\n"); + return rc; +} + +static int __load_fw(struct venus_hfi_device *device) +{ + int rc = 0; + + /* Initialize resources */ + rc = __init_resources(device, device->res); + if (rc) { + d_vpr_e("Failed to init resources: %d\n", rc); + goto fail_init_res; + } + + rc = __initialize_packetization(device); + if (rc) { + d_vpr_e("Failed to initialize packetization\n"); + goto fail_init_pkt; + } + trace_msm_v4l2_vidc_fw_load_start("msm_v4l2_vidc venus_fw load start"); + + rc = __venus_power_on(device, DEFAULT_SID); + if (rc) { + d_vpr_e("Failed to power on venus in in load_fw\n"); + goto fail_venus_power_on; + } + + if (!device->res->firmware_base) { + if (!device->resources.fw.cookie) + device->resources.fw.cookie = + subsystem_get_with_fwname("venus", + device->res->fw_name); + + if (IS_ERR_OR_NULL(device->resources.fw.cookie)) { + d_vpr_e("Failed to download firmware\n"); + device->resources.fw.cookie = NULL; + rc = -ENOMEM; + goto fail_load_fw; + } + } else { + d_vpr_e("Firmware base must be 0\n"); + } + + if (!device->res->firmware_base) { + rc = __protect_cp_mem(device); + if (rc) { + d_vpr_e("Failed to protect memory\n"); + goto fail_protect_mem; + } + } + /* + * Hand off control of regulators to h/w _after_ loading fw. + * Note that the GDSC will turn off when switching from normal + * (s/w triggered) to fast (HW triggered) unless the h/w vote is + * present. + */ + if (__enable_hw_power_collapse(device, DEFAULT_SID)) + d_vpr_e("Failed to enabled inter-frame PC\n"); + + trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end"); + return rc; +fail_protect_mem: + if (device->resources.fw.cookie) + subsystem_put(device->resources.fw.cookie); + device->resources.fw.cookie = NULL; +fail_load_fw: + call_venus_op(device, power_off, device); +fail_venus_power_on: +fail_init_pkt: + __deinit_resources(device); +fail_init_res: + trace_msm_v4l2_vidc_fw_load_end("msm_v4l2_vidc venus_fw load end"); + return rc; +} + +static void __unload_fw(struct venus_hfi_device *device) +{ + if (!device->resources.fw.cookie) + return; + + cancel_delayed_work(&venus_hfi_pm_work); + if (device->state != VENUS_STATE_DEINIT) + flush_workqueue(device->venus_pm_workq); + + subsystem_put(device->resources.fw.cookie); + __interface_queues_release(device); + call_venus_op(device, power_off, device); + device->resources.fw.cookie = NULL; + __deinit_resources(device); + + d_vpr_h("Firmware unloaded successfully\n"); +} + +static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info) +{ + int i = 0, j = 0; + struct venus_hfi_device *device = dev; + size_t smem_block_size = 0; + u8 *smem_table_ptr; + char version[VENUS_VERSION_LENGTH] = ""; + const u32 smem_image_index_venus = 14 * 128; + + if (!device || !fw_info) { + d_vpr_e("%s: Invalid parameter: device = %pK fw_info = %pK\n", + __func__, device, fw_info); + return -EINVAL; + } + + mutex_lock(&device->lock); + + smem_table_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_IMAGE_VERSION_TABLE, &smem_block_size); + if (smem_table_ptr && + ((smem_image_index_venus + + VENUS_VERSION_LENGTH) <= smem_block_size)) + memcpy(version, + smem_table_ptr + smem_image_index_venus, + VENUS_VERSION_LENGTH); + + while (version[i++] != 'V' && i < VENUS_VERSION_LENGTH) + ; + + if (i == VENUS_VERSION_LENGTH - 1) { + d_vpr_e("Venus version string is not proper\n"); + fw_info->version[0] = '\0'; + goto fail_version_string; + } + + for (i--; i < VENUS_VERSION_LENGTH && j < VENUS_VERSION_LENGTH - 1; i++) + fw_info->version[j++] = version[i]; + fw_info->version[j] = '\0'; + +fail_version_string: + d_vpr_h("F/W version retrieved : %s\n", fw_info->version); + fw_info->base_addr = device->hal_data->firmware_base; + fw_info->register_base = device->res->register_base; + fw_info->register_size = device->hal_data->register_size; + fw_info->irq = device->hal_data->irq; + + mutex_unlock(&device->lock); + return 0; +} + +static int venus_hfi_get_core_capabilities(void *dev) +{ + struct venus_hfi_device *device = dev; + int rc = 0; + + if (!device) + return -EINVAL; + + mutex_lock(&device->lock); + + rc = HAL_VIDEO_ENCODER_ROTATION_CAPABILITY | + HAL_VIDEO_ENCODER_SCALING_CAPABILITY | + HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY | + HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY; + + mutex_unlock(&device->lock); + + return rc; +} + +static void __noc_error_info(struct venus_hfi_device *device, u32 core_type) +{ + u32 noc_base_offs, val; + u32 sid = DEFAULT_SID; + + if (!device) { + d_vpr_e("%s: null device\n", __func__); + return; + } + if (!core_type) { + noc_base_offs = + VCODEC_CORE0_VIDEO_NOC_BASE_OFFS; + } else if (core_type == 1) { + noc_base_offs = + CVP_NOC_BASE_OFFS; + } else { + d_vpr_e("%s: invalid core_type %u\n", __func__, core_type); + return; + } + + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_SWID_LOW_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_SWID_LOW: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_SWID_HIGH_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_SWID_HIGH: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_MAINCTL_LOW_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_MAINCTL_LOW: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_LOW_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG0_LOW: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_HIGH_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG0_HIGH: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_LOW_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG1_LOW: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_HIGH_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG1_HIGH: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_LOW_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG2_LOW: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_HIGH_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG2_HIGH: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_LOW_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG3_LOW: %#x\n", core_type, val); + val = __read_register(device, noc_base_offs + + VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_HIGH_OFFS, sid); + d_vpr_e("CORE%d_NOC_ERR_ERRLOG3_HIGH: %#x\n", core_type, val); +} + +static void __noc_error_info_common(struct venus_hfi_device *device) +{ + const u32 vcodec = 0, cvp = 1; + + if (__read_register(device, VCODEC_CORE0_VIDEO_NOC_BASE_OFFS + + VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS, + DEFAULT_SID)) + __noc_error_info(device, vcodec); + + if (device->res->vpu_ver == VPU_VERSION_IRIS1) { + if (__read_register(device, CVP_NOC_BASE_OFFS + + VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS, + DEFAULT_SID)) + __noc_error_info(device, cvp); + } +} + +static int venus_hfi_noc_error_info(void *dev) +{ + struct venus_hfi_device *device; + + if (!dev) { + d_vpr_e("%s: null device\n", __func__); + return -EINVAL; + } + device = dev; + + mutex_lock(&device->lock); + d_vpr_e("%s: non error information\n", __func__); + + call_venus_op(device, noc_error_info, device); + + mutex_unlock(&device->lock); + + return 0; +} + +static int __initialize_packetization(struct venus_hfi_device *device) +{ + int rc = 0; + + if (!device || !device->res) { + d_vpr_e("%s: invalid params %pK\n", __func__, device); + return -EINVAL; + } + + device->packetization_type = HFI_PACKETIZATION_4XX; + + device->pkt_ops = hfi_get_pkt_ops_handle(device->packetization_type); + if (!device->pkt_ops) { + rc = -EINVAL; + d_vpr_e("Failed to get pkt_ops handle\n"); + } + + return rc; +} + +void __init_venus_ops(struct venus_hfi_device *device) +{ + if (device->res->vpu_ver == VPU_VERSION_AR50) + device->vpu_ops = &vpu4_ops; + else if (device->res->vpu_ver == VPU_VERSION_AR50_LITE) + device->vpu_ops = &ar50_lite_ops; + else if (device->res->vpu_ver == VPU_VERSION_IRIS1) + device->vpu_ops = &iris1_ops; + else + device->vpu_ops = &iris2_ops; +} + +static struct venus_hfi_device *__add_device(u32 device_id, + struct msm_vidc_platform_resources *res, + hfi_cmd_response_callback callback) +{ + struct venus_hfi_device *hdevice = &venus_hfi_dev; + int rc = 0; + + if (!res || !callback) { + d_vpr_e("%s: Invalid Parameters %pK %pK\n", + __func__, res, callback); + return NULL; + } + + d_vpr_h("%s: entered, device_id: %d\n", __func__, device_id); + + hdevice->response_pkt = kmalloc_array(max_packets, + sizeof(*hdevice->response_pkt), GFP_KERNEL); + if (!hdevice->response_pkt) { + d_vpr_e("failed to allocate response_pkt\n"); + goto err_cleanup; + } + + hdevice->raw_packet = + kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_KERNEL); + if (!hdevice->raw_packet) { + d_vpr_e("failed to allocate raw packet\n"); + goto err_cleanup; + } + + rc = __init_regs_and_interrupts(hdevice, res); + if (rc) + goto err_cleanup; + + hdevice->res = res; + hdevice->device_id = device_id; + hdevice->callback = (msm_vidc_callback) callback; + + __init_venus_ops(hdevice); + + hdevice->vidc_workq = create_singlethread_workqueue( + "msm_vidc_workerq_venus"); + if (!hdevice->vidc_workq) { + d_vpr_e("%s: create vidc workq failed\n", __func__); + goto err_cleanup; + } + + hdevice->venus_pm_workq = create_singlethread_workqueue( + "pm_workerq_venus"); + if (!hdevice->venus_pm_workq) { + d_vpr_e("%s: create pm workq failed\n", __func__); + goto err_cleanup; + } + + if (!hal_ctxt.dev_count) + INIT_LIST_HEAD(&hal_ctxt.dev_head); + + mutex_init(&hdevice->lock); + INIT_LIST_HEAD(&hdevice->list); + INIT_LIST_HEAD(&hdevice->sess_head); + list_add_tail(&hdevice->list, &hal_ctxt.dev_head); + hal_ctxt.dev_count++; + + return hdevice; + +err_cleanup: + if (hdevice->vidc_workq) + destroy_workqueue(hdevice->vidc_workq); + kfree(hdevice->response_pkt); + kfree(hdevice->raw_packet); + return NULL; +} + +static struct venus_hfi_device *__get_device(u32 device_id, + struct msm_vidc_platform_resources *res, + hfi_cmd_response_callback callback) +{ + if (!res || !callback) { + d_vpr_e("%s: invalid params: %pK %pK\n", + __func__, res, callback); + return NULL; + } + + return __add_device(device_id, res, callback); +} + +void venus_hfi_delete_device(void *device) +{ + struct venus_hfi_device *close, *tmp, *dev; + + if (!device) + return; + + dev = (struct venus_hfi_device *) device; + + list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) { + if (close->hal_data->irq == dev->hal_data->irq) { + hal_ctxt.dev_count--; + list_del(&close->list); + mutex_destroy(&close->lock); + destroy_workqueue(close->vidc_workq); + destroy_workqueue(close->venus_pm_workq); + free_irq(dev->hal_data->irq, close); + iounmap(dev->hal_data->register_base); + kfree(close->hal_data); + kfree(close->response_pkt); + kfree(close->raw_packet); + break; + } + } +} + +static void venus_init_hfi_callbacks(struct hfi_device *hdev) +{ + hdev->core_init = venus_hfi_core_init; + hdev->core_release = venus_hfi_core_release; + hdev->core_trigger_ssr = venus_hfi_core_trigger_ssr; + hdev->session_init = venus_hfi_session_init; + hdev->session_end = venus_hfi_session_end; + hdev->session_abort = venus_hfi_session_abort; + hdev->session_clean = venus_hfi_session_clean; + hdev->session_set_buffers = venus_hfi_session_set_buffers; + hdev->session_release_buffers = venus_hfi_session_release_buffers; + hdev->session_register_buffer = venus_hfi_session_register_buffer; + hdev->session_unregister_buffer = venus_hfi_session_unregister_buffer; + hdev->session_load_res = venus_hfi_session_load_res; + hdev->session_release_res = venus_hfi_session_release_res; + hdev->session_start = venus_hfi_session_start; + hdev->session_continue = venus_hfi_session_continue; + hdev->session_stop = venus_hfi_session_stop; + hdev->session_etb = venus_hfi_session_etb; + hdev->session_ftb = venus_hfi_session_ftb; + hdev->session_process_batch = venus_hfi_session_process_batch; + hdev->session_get_buf_req = venus_hfi_session_get_buf_req; + hdev->session_flush = venus_hfi_session_flush; + hdev->session_set_property = venus_hfi_session_set_property; + hdev->session_pause = venus_hfi_session_pause; + hdev->session_resume = venus_hfi_session_resume; + hdev->scale_clocks = venus_hfi_scale_clocks; + hdev->vote_bus = venus_hfi_vote_buses; + hdev->get_fw_info = venus_hfi_get_fw_info; + hdev->get_core_capabilities = venus_hfi_get_core_capabilities; + hdev->suspend = venus_hfi_suspend; + hdev->flush_debug_queue = venus_hfi_flush_debug_queue; + hdev->noc_error_info = venus_hfi_noc_error_info; +} + +int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id, + struct msm_vidc_platform_resources *res, + hfi_cmd_response_callback callback) +{ + int rc = 0; + + if (!hdev || !res || !callback) { + d_vpr_e("%s: invalid params: %pK %pK %pK\n", + __func__, hdev, res, callback); + rc = -EINVAL; + goto err_venus_hfi_init; + } + + hdev->hfi_device_data = __get_device(device_id, res, callback); + + if (IS_ERR_OR_NULL(hdev->hfi_device_data)) { + rc = PTR_ERR(hdev->hfi_device_data) ? + PTR_ERR(hdev->hfi_device_data) : -EINVAL; + goto err_venus_hfi_init; + } + + venus_init_hfi_callbacks(hdev); + +err_venus_hfi_init: + return rc; +} diff --git a/techpack/video/msm/vidc/hfi_common.h b/techpack/video/msm/vidc/hfi_common.h new file mode 100644 index 0000000000000000000000000000000000000000..9d288c1a19f257e4355962ddb3e1e95e3cdb69f8 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_common.h @@ -0,0 +1,333 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __HFI_COMMON_H__ +#define __HFI_COMMON_H__ + +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/pm_qos.h> +#include <linux/spinlock.h> +#include <linux/clk-provider.h> +#include "vidc_hfi_api.h" +#include "vidc_hfi_helper.h" +#include "vidc_hfi_api.h" +#include "vidc_hfi.h" +#include "msm_vidc_resources.h" +#include "hfi_packetization.h" +#include "msm_vidc_bus.h" + +#define HFI_MASK_QHDR_TX_TYPE 0xFF000000 +#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000 +#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00 +#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000FF +#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q 0x00 +#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q 0x01 +#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q 0x02 +#define HFI_MASK_QHDR_STATUS 0x000000FF + +#define VIDC_MAX_UNCOMPRESSED_FMT_PLANES 3 + +#define VIDC_IFACEQ_NUMQ 3 +#define VIDC_IFACEQ_CMDQ_IDX 0 +#define VIDC_IFACEQ_MSGQ_IDX 1 +#define VIDC_IFACEQ_DBGQ_IDX 2 +#define VIDC_IFACEQ_MAX_BUF_COUNT 50 +#define VIDC_IFACE_MAX_PARALLEL_CLNTS 16 +#define VIDC_IFACEQ_DFLT_QHDR 0x01010000 + +#define VIDC_MAX_NAME_LENGTH 64 +#define VIDC_MAX_PC_SKIP_COUNT 10 +#define VIDC_MAX_SUBCACHES 4 +#define VIDC_MAX_SUBCACHE_SIZE 52 + +struct hfi_queue_table_header { + u32 qtbl_version; + u32 qtbl_size; + u32 qtbl_qhdr0_offset; + u32 qtbl_qhdr_size; + u32 qtbl_num_q; + u32 qtbl_num_active_q; + void *device_addr; + char name[256]; +}; + +struct hfi_queue_header { + u32 qhdr_status; + u32 qhdr_start_addr; + u32 qhdr_type; + u32 qhdr_q_size; + u32 qhdr_pkt_size; + u32 qhdr_pkt_drop_cnt; + u32 qhdr_rx_wm; + u32 qhdr_tx_wm; + u32 qhdr_rx_req; + u32 qhdr_tx_req; + u32 qhdr_rx_irq_status; + u32 qhdr_tx_irq_status; + u32 qhdr_read_idx; + u32 qhdr_write_idx; +}; + +struct hfi_mem_map_table { + u32 mem_map_num_entries; + u32 mem_map_table_base_addr; +}; + +struct hfi_mem_map { + u32 virtual_addr; + u32 physical_addr; + u32 size; + u32 attr; +}; + +#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \ + + sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ) + +#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \ + VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS) + +#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \ + (void *)((ptr + sizeof(struct hfi_queue_table_header)) + \ + (i * sizeof(struct hfi_queue_header))) + +#define QDSS_SIZE 4096 +#define SFR_SIZE 4096 + +#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \ + (VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ)) + +#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K) +#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K) +#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K) +#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \ + ALIGNED_QDSS_SIZE, SZ_1M) + +enum vidc_hw_reg { + VIDC_HWREG_CTRL_STATUS = 0x1, + VIDC_HWREG_QTBL_INFO = 0x2, + VIDC_HWREG_QTBL_ADDR = 0x3, + VIDC_HWREG_CTRLR_RESET = 0x4, + VIDC_HWREG_IFACEQ_FWRXREQ = 0x5, + VIDC_HWREG_IFACEQ_FWTXREQ = 0x6, + VIDC_HWREG_VHI_SOFTINTEN = 0x7, + VIDC_HWREG_VHI_SOFTINTSTATUS = 0x8, + VIDC_HWREG_VHI_SOFTINTCLR = 0x9, + VIDC_HWREG_HVI_SOFTINTEN = 0xA, +}; + +struct vidc_mem_addr { + u32 align_device_addr; + u8 *align_virtual_addr; + u32 mem_size; + struct msm_smem mem_data; +}; + +struct vidc_iface_q_info { + void *q_hdr; + struct vidc_mem_addr q_array; +}; + +/* + * These are helper macros to iterate over various lists within + * venus_hfi_device->res. The intention is to cut down on a lot of boiler-plate + * code + */ + +/* Read as "for each 'thing' in a set of 'thingies'" */ +#define venus_hfi_for_each_thing(__device, __thing, __thingy) \ + venus_hfi_for_each_thing_continue(__device, __thing, __thingy, 0) + +#define venus_hfi_for_each_thing_reverse(__device, __thing, __thingy) \ + venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \ + (__device)->res->__thingy##_set.count - 1) + +/* TODO: the __from parameter technically not required since we can figure it + * out with some pointer magic (i.e. __thing - __thing##_tbl[0]). If this macro + * sees extensive use, probably worth cleaning it up but for now omitting it + * since it introduces unnecessary complexity. + */ +#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \ + for (__thing = &(__device)->res->\ + __thingy##_set.__thingy##_tbl[__from]; \ + __thing < &(__device)->res->__thingy##_set.__thingy##_tbl[0] + \ + ((__device)->res->__thingy##_set.count - __from); \ + ++__thing) + +#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \ + __from) \ + for (__thing = &(__device)->res->\ + __thingy##_set.__thingy##_tbl[__from]; \ + __thing >= &(__device)->res->__thingy##_set.__thingy##_tbl[0]; \ + --__thing) + +/* Regular set helpers */ +#define venus_hfi_for_each_regulator(__device, __rinfo) \ + venus_hfi_for_each_thing(__device, __rinfo, regulator) + +#define venus_hfi_for_each_regulator_reverse(__device, __rinfo) \ + venus_hfi_for_each_thing_reverse(__device, __rinfo, regulator) + +#define venus_hfi_for_each_regulator_reverse_continue(__device, __rinfo, \ + __from) \ + venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \ + regulator, __from) + +/* Clock set helpers */ +#define venus_hfi_for_each_clock(__device, __cinfo) \ + venus_hfi_for_each_thing(__device, __cinfo, clock) + +#define venus_hfi_for_each_clock_reverse(__device, __cinfo) \ + venus_hfi_for_each_thing_reverse(__device, __cinfo, clock) + +#define venus_hfi_for_each_clock_reverse_continue(__device, __rinfo, \ + __from) \ + venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \ + clock, __from) + +/* Bus set helpers */ +#define venus_hfi_for_each_bus(__device, __binfo) \ + venus_hfi_for_each_thing(__device, __binfo, bus) +#define venus_hfi_for_each_bus_reverse(__device, __binfo) \ + venus_hfi_for_each_thing_reverse(__device, __binfo, bus) + +/* Subcache set helpers */ +#define venus_hfi_for_each_subcache(__device, __sinfo) \ + venus_hfi_for_each_thing(__device, __sinfo, subcache) +#define venus_hfi_for_each_subcache_reverse(__device, __sinfo) \ + venus_hfi_for_each_thing_reverse(__device, __sinfo, subcache) + +#define call_venus_op(d, op, ...) \ + (((d) && (d)->vpu_ops && (d)->vpu_ops->op) ? \ + ((d)->vpu_ops->op(__VA_ARGS__)):0) + +/* Internal data used in vidc_hal not exposed to msm_vidc*/ +struct hal_data { + u32 irq; + phys_addr_t firmware_base; + u8 __iomem *register_base; + u32 register_size; +}; + +struct venus_resources { + struct msm_vidc_fw fw; +}; + +enum dsp_flag { + DSP_INIT = BIT(0), + DSP_SUSPEND = BIT(1), +}; + +enum venus_hfi_state { + VENUS_STATE_DEINIT = 1, + VENUS_STATE_INIT, +}; + +enum reset_state { + INIT = 1, + ASSERT, + DEASSERT, +}; + +struct venus_hfi_device; + +struct venus_hfi_vpu_ops { + void (*interrupt_init)(struct venus_hfi_device *device, u32 sid); + void (*setup_ucregion_memmap)(struct venus_hfi_device *device, u32 sid); + void (*clock_config_on_enable)(struct venus_hfi_device *device, + u32 sid); + int (*reset_ahb2axi_bridge)(struct venus_hfi_device *device, u32 sid); + void (*power_off)(struct venus_hfi_device *device); + int (*prepare_pc)(struct venus_hfi_device *device); + void (*raise_interrupt)(struct venus_hfi_device *device, u32 sid); + bool (*watchdog)(u32 intr_status); + void (*noc_error_info)(struct venus_hfi_device *device); + void (*core_clear_interrupt)(struct venus_hfi_device *device); + int (*boot_firmware)(struct venus_hfi_device *device, u32 sid); +}; + +struct venus_hfi_device { + struct list_head list; + struct list_head sess_head; + u32 intr_status; + u32 device_id; + u32 clk_freq; + u32 last_packet_type; + struct msm_vidc_bus_data bus_vote; + bool power_enabled; + struct mutex lock; + msm_vidc_callback callback; + struct vidc_mem_addr iface_q_table; + struct vidc_mem_addr dsp_iface_q_table; + struct vidc_mem_addr qdss; + struct vidc_mem_addr sfr; + struct vidc_mem_addr mem_addr; + struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ]; + struct vidc_iface_q_info dsp_iface_queues[VIDC_IFACEQ_NUMQ]; + u32 dsp_flags; + struct hal_data *hal_data; + struct workqueue_struct *vidc_workq; + struct workqueue_struct *venus_pm_workq; + int spur_count; + int reg_count; + struct venus_resources resources; + struct msm_vidc_platform_resources *res; + enum venus_hfi_state state; + struct hfi_packetization_ops *pkt_ops; + enum hfi_packetization_type packetization_type; + struct msm_vidc_cb_info *response_pkt; + u8 *raw_packet; + struct pm_qos_request qos; + unsigned int skip_pc_count; + struct venus_hfi_vpu_ops *vpu_ops; +}; + +void venus_hfi_delete_device(void *device); + +int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id, + struct msm_vidc_platform_resources *res, + hfi_cmd_response_callback callback); + +void __write_register(struct venus_hfi_device *device, + u32 reg, u32 value, u32 sid); +int __read_register(struct venus_hfi_device *device, u32 reg, u32 sid); +void __disable_unprepare_clks(struct venus_hfi_device *device); +int __disable_regulators(struct venus_hfi_device *device); +int __unvote_buses(struct venus_hfi_device *device, u32 sid); +int __reset_ahb2axi_bridge_common(struct venus_hfi_device *device, u32 sid); +int __prepare_pc(struct venus_hfi_device *device); + +/* AR50 specific */ +void __interrupt_init_ar50(struct venus_hfi_device *device, u32 sid); +/* IRIS1 specific */ +void __interrupt_init_iris1(struct venus_hfi_device *device, u32 sid); +void __setup_dsp_uc_memmap_iris1(struct venus_hfi_device *device); +void __clock_config_on_enable_iris1(struct venus_hfi_device *device, + u32 sid); +void __setup_ucregion_memory_map_iris1(struct venus_hfi_device *device, + u32 sid); +/* IRIS2 specific */ +void __interrupt_init_iris2(struct venus_hfi_device *device, u32 sid); +void __setup_ucregion_memory_map_iris2(struct venus_hfi_device *device, + u32 sid); +void __power_off_iris2(struct venus_hfi_device *device); +int __prepare_pc_iris2(struct venus_hfi_device *device); +void __raise_interrupt_iris2(struct venus_hfi_device *device, u32 sid); +bool __watchdog_iris2(u32 intr_status); +void __noc_error_info_iris2(struct venus_hfi_device *device); +void __core_clear_interrupt_iris2(struct venus_hfi_device *device); +int __boot_firmware_iris2(struct venus_hfi_device *device, u32 sid); + +/* AR50_LITE specific */ +void __interrupt_init_ar50_lt(struct venus_hfi_device *device, u32 sid); +void __setup_ucregion_memory_map_ar50_lt(struct venus_hfi_device *device, u32 sid); +void __power_off_ar50_lt(struct venus_hfi_device *device); +int __prepare_pc_ar50_lt(struct venus_hfi_device *device); +void __raise_interrupt_ar50_lt(struct venus_hfi_device *device, u32 sid); +void __core_clear_interrupt_ar50_lt(struct venus_hfi_device *device); +int __boot_firmware_ar50_lt(struct venus_hfi_device *device, u32 sid); + +#endif diff --git a/techpack/video/msm/vidc/hfi_io_common.h b/techpack/video/msm/vidc/hfi_io_common.h new file mode 100644 index 0000000000000000000000000000000000000000..1adc50d38e9d9c216770d86cdf2025425215dd5a --- /dev/null +++ b/techpack/video/msm/vidc/hfi_io_common.h @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __HFI_IO_COMMON_H__ +#define __HFI_IO_COMMON_H__ + +#include <linux/io.h> + +#define VBIF_BASE_OFFS 0x00080000 + +#define CPU_BASE_OFFS 0x000C0000 +#define CPU_CS_BASE_OFFS (CPU_BASE_OFFS + 0x00012000) +#define CPU_IC_BASE_OFFS (CPU_BASE_OFFS + 0x0001F000) + +#define CPU_CS_A2HSOFTINT (CPU_CS_BASE_OFFS + 0x18) +#define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE_OFFS + 0x1C) +#define CPU_CS_VMIMSG (CPU_CS_BASE_OFFS + 0x34) +#define CPU_CS_VMIMSGAG0 (CPU_CS_BASE_OFFS + 0x38) +#define CPU_CS_VMIMSGAG1 (CPU_CS_BASE_OFFS + 0x3C) +#define CPU_CS_SCIACMD (CPU_CS_BASE_OFFS + 0x48) + +/* HFI_CTRL_STATUS */ +#define CPU_CS_SCIACMDARG0 (CPU_CS_BASE_OFFS + 0x4C) +#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK 0xfe +#define CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY 0x100 +#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK 0x40000000 + +/* HFI_QTBL_INFO */ +#define CPU_CS_SCIACMDARG1 (CPU_CS_BASE_OFFS + 0x50) + +/* HFI_QTBL_ADDR */ +#define CPU_CS_SCIACMDARG2 (CPU_CS_BASE_OFFS + 0x54) + +/* HFI_VERSION_INFO */ +#define CPU_CS_SCIACMDARG3 (CPU_CS_BASE_OFFS + 0x58) + +/* SFR_ADDR */ +#define CPU_CS_SCIBCMD (CPU_CS_BASE_OFFS + 0x5C) + +/* MMAP_ADDR */ +#define CPU_CS_SCIBCMDARG0 (CPU_CS_BASE_OFFS + 0x60) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG1 (CPU_CS_BASE_OFFS + 0x64) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG2 (CPU_CS_BASE_OFFS + 0x68) + +#define CPU_IC_SOFTINT (CPU_IC_BASE_OFFS + 0x18) +#define CPU_IC_SOFTINT_H2A_SHFT 0xF + +/* + * -------------------------------------------------------------------------- + * MODULE: wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_BASE_OFFS 0x000E0000 +#define WRAPPER_INTR_STATUS (WRAPPER_BASE_OFFS + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK 0x10 +#define WRAPPER_INTR_STATUS_A2H_BMSK 0x4 + +#define WRAPPER_INTR_MASK (WRAPPER_BASE_OFFS + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK 0x10 +#define WRAPPER_INTR_MASK_A2HVCODEC_BMSK 0x8 +#define WRAPPER_INTR_MASK_A2HCPU_BMSK 0x4 +#define WRAPPER_INTR_CLEAR (WRAPPER_BASE_OFFS + 0x14) + +#define WRAPPER_CPU_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x2000) +#define WRAPPER_CPU_CGC_DIS (WRAPPER_BASE_OFFS + 0x2010) +#define WRAPPER_CPU_STATUS (WRAPPER_BASE_OFFS + 0x2014) + +#define CTRL_INIT CPU_CS_SCIACMD + +#define CTRL_STATUS CPU_CS_SCIACMDARG0 +#define CTRL_ERROR_STATUS__M \ + CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK +#define CTRL_INIT_IDLE_MSG_BMSK \ + CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK +#define CTRL_STATUS_PC_READY \ + CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY + + +#define QTBL_INFO CPU_CS_SCIACMDARG1 + +#define QTBL_ADDR CPU_CS_SCIACMDARG2 + +#define VERSION_INFO CPU_CS_SCIACMDARG3 + +#define SFR_ADDR CPU_CS_SCIBCMD +#define MMAP_ADDR CPU_CS_SCIBCMDARG0 +#define UC_REGION_ADDR CPU_CS_SCIBARG1 +#define UC_REGION_SIZE CPU_CS_SCIBARG2 + +/* HFI_DSP_QTBL_ADDR + * 31:3 - HFI_DSP_QTBL_ADDR + * 4-byte aligned Address + */ +#define HFI_DSP_QTBL_ADDR CPU_CS_VMIMSG + +/* HFI_DSP_UC_REGION_ADDR + * 31:20 - HFI_DSP_UC_REGION_ADDR + * 1MB aligned address. + * Uncached Region start Address. This region covers + * HFI DSP QTable, + * HFI DSP Queue Headers, + * HFI DSP Queues, + */ +#define HFI_DSP_UC_REGION_ADDR CPU_CS_VMIMSGAG0 + +/* HFI_DSP_UC_REGION_SIZE + * 31:20 - HFI_DSP_UC_REGION_SIZE + * Multiples of 1MB. + * Size of the DSP_UC_REGION Uncached Region + */ +#define HFI_DSP_UC_REGION_SIZE CPU_CS_VMIMSGAG1 + +/* + * -------------------------------------------------------------------------- + * MODULE: vcodec noc error log registers + * -------------------------------------------------------------------------- + */ +#define VCODEC_CORE0_VIDEO_NOC_BASE_OFFS 0x00004000 +#define CVP_NOC_BASE_OFFS 0x0000C000 +#define VCODEC_COREX_VIDEO_NOC_ERR_SWID_LOW_OFFS 0x0500 +#define VCODEC_COREX_VIDEO_NOC_ERR_SWID_HIGH_OFFS 0x0504 +#define VCODEC_COREX_VIDEO_NOC_ERR_MAINCTL_LOW_OFFS 0x0508 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS 0x0510 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRCLR_LOW_OFFS 0x0518 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_LOW_OFFS 0x0520 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_HIGH_OFFS 0x0524 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_LOW_OFFS 0x0528 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_HIGH_OFFS 0x052C +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_LOW_OFFS 0x0530 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_HIGH_OFFS 0x0534 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_LOW_OFFS 0x0538 +#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_HIGH_OFFS 0x053C +#endif diff --git a/techpack/video/msm/vidc/hfi_iris1.c b/techpack/video/msm/vidc/hfi_iris1.c new file mode 100644 index 0000000000000000000000000000000000000000..f7d2c19e379c035b049a2a08175b281f6c37ba11 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_iris1.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "hfi_common.h" +#include "hfi_io_common.h" + +void __interrupt_init_iris1(struct venus_hfi_device *device, u32 sid) +{ + u32 mask_val = 0; + + /* All interrupts should be disabled initially 0x1F6 : Reset value */ + mask_val = __read_register(device, WRAPPER_INTR_MASK, sid); + + /* Write 0 to unmask CPU and WD interrupts */ + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK | + WRAPPER_INTR_MASK_A2HCPU_BMSK); + __write_register(device, WRAPPER_INTR_MASK, mask_val, sid); +} + +void __setup_ucregion_memory_map_iris1(struct venus_hfi_device *device, u32 sid) +{ + /* initialize CPU QTBL & UCREGION */ + __write_register(device, UC_REGION_ADDR, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, UC_REGION_SIZE, SHARED_QSIZE, sid); + __write_register(device, QTBL_ADDR, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, QTBL_INFO, 0x01, sid); + if (device->sfr.align_device_addr) + __write_register(device, SFR_ADDR, + (u32)device->sfr.align_device_addr, sid); + if (device->qdss.align_device_addr) + __write_register(device, MMAP_ADDR, + (u32)device->qdss.align_device_addr, sid); + + /* initialize DSP QTBL & UCREGION with CPU queues by default */ + __write_register(device, HFI_DSP_QTBL_ADDR, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, HFI_DSP_UC_REGION_ADDR, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, HFI_DSP_UC_REGION_SIZE, SHARED_QSIZE, sid); + if (device->res->cvp_internal) { + /* initialize DSP QTBL & UCREGION with DSP queues */ + __write_register(device, HFI_DSP_QTBL_ADDR, + (u32)device->dsp_iface_q_table.align_device_addr, sid); + __write_register(device, HFI_DSP_UC_REGION_ADDR, + (u32)device->dsp_iface_q_table.align_device_addr, sid); + __write_register(device, HFI_DSP_UC_REGION_SIZE, + device->dsp_iface_q_table.mem_data.size, sid); + } +} + +void __clock_config_on_enable_iris1(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, WRAPPER_CPU_CGC_DIS, 0, sid); + __write_register(device, WRAPPER_CPU_CLOCK_CONFIG, 0, sid); +} + diff --git a/techpack/video/msm/vidc/hfi_iris2.c b/techpack/video/msm/vidc/hfi_iris2.c new file mode 100644 index 0000000000000000000000000000000000000000..179fb2abaefbf4f8b70fca5c7afe32c7cb9f9ecc --- /dev/null +++ b/techpack/video/msm/vidc/hfi_iris2.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_debug.h" +#include "hfi_common.h" + +#define VBIF_BASE_OFFS_IRIS2 0x00080000 + +#define CPU_BASE_OFFS_IRIS2 0x000A0000 +#define AON_BASE_OFFS 0x000E0000 +#define CPU_CS_BASE_OFFS_IRIS2 (CPU_BASE_OFFS_IRIS2) +#define CPU_IC_BASE_OFFS_IRIS2 (CPU_BASE_OFFS_IRIS2) + +#define CPU_CS_A2HSOFTINTCLR_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x1C) +#define CPU_CS_VCICMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x20) +#define CPU_CS_VCICMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x24) +#define CPU_CS_VCICMDARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x28) +#define CPU_CS_VCICMDARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x2C) +#define CPU_CS_VCICMDARG3_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x30) +#define CPU_CS_VMIMSG_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x34) +#define CPU_CS_VMIMSGAG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x38) +#define CPU_CS_VMIMSGAG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x3C) +#define CPU_CS_SCIACMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x48) +#define CPU_CS_H2XSOFTINTEN_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x148) + +/* HFI_CTRL_STATUS */ +#define CPU_CS_SCIACMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x4C) +#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS2 0xfe +#define CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS2 0x100 +#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS2 0x40000000 + +/* HFI_QTBL_INFO */ +#define CPU_CS_SCIACMDARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x50) + +/* HFI_QTBL_ADDR */ +#define CPU_CS_SCIACMDARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x54) + +/* HFI_VERSION_INFO */ +#define CPU_CS_SCIACMDARG3_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x58) + +/* SFR_ADDR */ +#define CPU_CS_SCIBCMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x5C) + +/* MMAP_ADDR */ +#define CPU_CS_SCIBCMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x60) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x64) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x68) + +/* FAL10 Feature Control */ +#define CPU_CS_X2RPMh_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x168) +#define CPU_CS_X2RPMh_MASK0_BMSK_IRIS2 0x1 +#define CPU_CS_X2RPMh_MASK0_SHFT_IRIS2 0x0 +#define CPU_CS_X2RPMh_MASK1_BMSK_IRIS2 0x2 +#define CPU_CS_X2RPMh_MASK1_SHFT_IRIS2 0x1 +#define CPU_CS_X2RPMh_SWOVERRIDE_BMSK_IRIS2 0x4 +#define CPU_CS_X2RPMh_SWOVERRIDE_SHFT_IRIS2 0x3 + +#define CPU_IC_SOFTINT_IRIS2 (CPU_IC_BASE_OFFS_IRIS2 + 0x150) +#define CPU_IC_SOFTINT_H2A_SHFT_IRIS2 0x0 + +/* + * -------------------------------------------------------------------------- + * MODULE: wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_BASE_OFFS_IRIS2 0x000B0000 +#define WRAPPER_INTR_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2 0x8 +#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS2 0x4 + +#define WRAPPER_INTR_MASK_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS2 0x8 +#define WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS2 0x4 + +#define WRAPPER_CPU_CLOCK_CONFIG_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2000) +#define WRAPPER_CPU_CGC_DIS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2010) +#define WRAPPER_CPU_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2014) + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x58) +/* + * -------------------------------------------------------------------------- + * MODULE: tz_wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define WRAPPER_TZ_CPU_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS) +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) + +#define CTRL_INIT_IRIS2 CPU_CS_SCIACMD_IRIS2 + +#define CTRL_STATUS_IRIS2 CPU_CS_SCIACMDARG0_IRIS2 +#define CTRL_ERROR_STATUS__M_IRIS2 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS2 +#define CTRL_INIT_IDLE_MSG_BMSK_IRIS2 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS2 +#define CTRL_STATUS_PC_READY_IRIS2 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS2 + + +#define QTBL_INFO_IRIS2 CPU_CS_SCIACMDARG1_IRIS2 + +#define QTBL_ADDR_IRIS2 CPU_CS_SCIACMDARG2_IRIS2 + +#define VERSION_INFO_IRIS2 CPU_CS_SCIACMDARG3_IRIS2 + +#define SFR_ADDR_IRIS2 CPU_CS_SCIBCMD_IRIS2 +#define MMAP_ADDR_IRIS2 CPU_CS_SCIBCMDARG0_IRIS2 +#define UC_REGION_ADDR_IRIS2 CPU_CS_SCIBARG1_IRIS2 +#define UC_REGION_SIZE_IRIS2 CPU_CS_SCIBARG2_IRIS2 + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) + +/* + * -------------------------------------------------------------------------- + * MODULE: vcodec noc error log registers (iris2) + * -------------------------------------------------------------------------- + */ +#define VCODEC_NOC_VIDEO_A_NOC_BASE_OFFS 0x00010000 +#define VCODEC_NOC_ERL_MAIN_SWID_LOW 0x00011200 +#define VCODEC_NOC_ERL_MAIN_SWID_HIGH 0x00011204 +#define VCODEC_NOC_ERL_MAIN_MAINCTL_LOW 0x00011208 +#define VCODEC_NOC_ERL_MAIN_ERRVLD_LOW 0x00011210 +#define VCODEC_NOC_ERL_MAIN_ERRCLR_LOW 0x00011218 +#define VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW 0x00011220 +#define VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH 0x00011224 +#define VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW 0x00011228 +#define VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH 0x0001122C +#define VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW 0x00011230 +#define VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH 0x00011234 +#define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW 0x00011238 +#define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH 0x0001123C + +void __interrupt_init_iris2(struct venus_hfi_device *device, u32 sid) +{ + u32 mask_val = 0; + + /* All interrupts should be disabled initially 0x1F6 : Reset value */ + mask_val = __read_register(device, WRAPPER_INTR_MASK_IRIS2, sid); + + /* Write 0 to unmask CPU and WD interrupts */ + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS2| + WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS2); + __write_register(device, WRAPPER_INTR_MASK_IRIS2, mask_val, sid); +} + +void __setup_ucregion_memory_map_iris2(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, UC_REGION_ADDR_IRIS2, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, UC_REGION_SIZE_IRIS2, SHARED_QSIZE, sid); + __write_register(device, QTBL_ADDR_IRIS2, + (u32)device->iface_q_table.align_device_addr, sid); + __write_register(device, QTBL_INFO_IRIS2, 0x01, sid); + if (device->sfr.align_device_addr) + __write_register(device, SFR_ADDR_IRIS2, + (u32)device->sfr.align_device_addr, sid); + if (device->qdss.align_device_addr) + __write_register(device, MMAP_ADDR_IRIS2, + (u32)device->qdss.align_device_addr, sid); + /* update queues vaddr for debug purpose */ + __write_register(device, CPU_CS_VCICMDARG0_IRIS2, + (u32)device->iface_q_table.align_virtual_addr, sid); + __write_register(device, CPU_CS_VCICMDARG1_IRIS2, + (u32)((u64)device->iface_q_table.align_virtual_addr >> 32), + sid); +} + +void __power_off_iris2(struct venus_hfi_device *device) +{ + u32 lpi_status, reg_status = 0, count = 0, max_count = 10; + u32 sid = DEFAULT_SID; + + if (!device->power_enabled) + return; + + if (!(device->intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2)) + disable_irq_nosync(device->hal_data->irq); + device->intr_status = 0; + + /* HPG 6.1.2 Step 1 */ + __write_register(device, CPU_CS_X2RPMh_IRIS2, 0x3, sid); + + /* HPG 6.1.2 Step 2, noc to low power */ + if (device->res->vpu_ver == VPU_VERSION_IRIS2_1) + goto skip_aon_mvp_noc; + __write_register(device, AON_WRAPPER_MVP_NOC_LPI_CONTROL, 0x1, sid); + while (!reg_status && count < max_count) { + lpi_status = + __read_register(device, + AON_WRAPPER_MVP_NOC_LPI_STATUS, sid); + reg_status = lpi_status & BIT(0); + d_vpr_h("Noc: lpi_status %d noc_status %d (count %d)\n", + lpi_status, reg_status, count); + usleep_range(50, 100); + count++; + } + if (count == max_count) { + d_vpr_e("NOC not in qaccept status %d\n", reg_status); + } + + /* HPG 6.1.2 Step 3, debug bridge to low power */ +skip_aon_mvp_noc: + __write_register(device, + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x7, sid); + reg_status = 0; + count = 0; + while ((reg_status != 0x7) && count < max_count) { + lpi_status = __read_register(device, + WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2, sid); + reg_status = lpi_status & 0x7; + d_vpr_h("DBLP Set : lpi_status %d reg_status %d (count %d)\n", + lpi_status, reg_status, count); + usleep_range(50, 100); + count++; + } + if (count == max_count) + d_vpr_e("DBLP Set: status %d\n", reg_status); + + /* HPG 6.1.2 Step 4, debug bridge to lpi release */ + __write_register(device, + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x0, sid); + lpi_status = 0x1; + count = 0; + while (lpi_status && count < max_count) { + lpi_status = __read_register(device, + WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2, sid); + d_vpr_h("DBLP Release: lpi_status %d(count %d)\n", + lpi_status, count); + usleep_range(50, 100); + count++; + } + if (count == max_count) + d_vpr_e("DBLP Release: lpi_status %d\n", lpi_status); + + /* HPG 6.1.2 Step 6 */ + __disable_unprepare_clks(device); + + /* HPG 6.1.2 Step 7 & 8 */ + if (call_venus_op(device, reset_ahb2axi_bridge, device, sid)) + d_vpr_e("%s: Failed to reset ahb2axi\n", __func__); + + /* HPG 6.1.2 Step 5 */ + if (__disable_regulators(device)) + d_vpr_e("%s: Failed to disable regulators\n", __func__); + + if (__unvote_buses(device, sid)) + d_vpr_e("%s: Failed to unvote for buses\n", __func__); + device->power_enabled = false; +} + +int __prepare_pc_iris2(struct venus_hfi_device *device) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 ctrl_status = 0; + int count = 0; + const int max_tries = 10; + + ctrl_status = __read_register(device, CTRL_STATUS_IRIS2, DEFAULT_SID); + pc_ready = ctrl_status & CTRL_STATUS_PC_READY_IRIS2; + idle_status = ctrl_status & BIT(30); + + if (pc_ready) { + d_vpr_h("Already in pc_ready state\n"); + return 0; + } + + wfi_status = BIT(0) & __read_register(device, WRAPPER_TZ_CPU_STATUS, + DEFAULT_SID); + if (!wfi_status || !idle_status) { + d_vpr_e("Skipping PC, wfi status not set\n"); + goto skip_power_off; + } + + rc = __prepare_pc(device); + if (rc) { + d_vpr_e("Failed __prepare_pc %d\n", rc); + goto skip_power_off; + } + + while (count < max_tries) { + wfi_status = BIT(0) & __read_register(device, + WRAPPER_TZ_CPU_STATUS, DEFAULT_SID); + ctrl_status = __read_register(device, + CTRL_STATUS_IRIS2, DEFAULT_SID); + if (wfi_status && (ctrl_status & CTRL_STATUS_PC_READY_IRIS2)) + break; + usleep_range(150, 250); + count++; + } + + if (count == max_tries) { + d_vpr_e("Skip PC. Core is not in right state\n"); + goto skip_power_off; + } + + return rc; + +skip_power_off: + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + return -EAGAIN; +} + +void __raise_interrupt_iris2(struct venus_hfi_device *device, u32 sid) +{ + __write_register(device, CPU_IC_SOFTINT_IRIS2, + 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS2, sid); +} + +bool __watchdog_iris2(u32 intr_status) +{ + bool rc = false; + + if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2) + rc = true; + + return rc; +} + +void __noc_error_info_iris2(struct venus_hfi_device *device) +{ + u32 val = 0; + u32 sid = DEFAULT_SID; + + if (device->res->vpu_ver == VPU_VERSION_IRIS2_1) + return; + val = __read_register(device, VCODEC_NOC_ERL_MAIN_SWID_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_SWID_HIGH, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_HIGH: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_MAINCTL_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_MAINCTL_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRVLD_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRVLD_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRCLR_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRCLR_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW: %#x\n", val); + val = __read_register(device, VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH, sid); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH: %#x\n", val); +} + +void __core_clear_interrupt_iris2(struct venus_hfi_device *device) +{ + u32 intr_status = 0, mask = 0; + + if (!device) { + d_vpr_e("%s: NULL device\n", __func__); + return; + } + + intr_status = __read_register(device, WRAPPER_INTR_STATUS_IRIS2, + DEFAULT_SID); + mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS2| + WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2| + CTRL_INIT_IDLE_MSG_BMSK_IRIS2); + + if (intr_status & mask) { + device->intr_status |= intr_status; + device->reg_count++; + d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n", + device->reg_count, intr_status); + } else { + device->spur_count++; + } + + __write_register(device, CPU_CS_A2HSOFTINTCLR_IRIS2, 1, DEFAULT_SID); +} + +int __boot_firmware_iris2(struct venus_hfi_device *device, u32 sid) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 5000; + + ctrl_init_val = BIT(0); + if (device->res->cvp_internal) + ctrl_init_val |= BIT(1); + + __write_register(device, CTRL_INIT_IRIS2, ctrl_init_val, sid); + while (!ctrl_status && count < max_tries) { + ctrl_status = __read_register(device, CTRL_STATUS_IRIS2, sid); + if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS2) == 0x4) { + s_vpr_e(sid, "invalid setting for UC_REGION\n"); + break; + } + + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + s_vpr_e(sid, "Error booting up vidc firmware\n"); + rc = -ETIME; + } + + /* Enable interrupt before sending commands to venus */ + __write_register(device, CPU_CS_H2XSOFTINTEN_IRIS2, 0x1, sid); + __write_register(device, CPU_CS_X2RPMh_IRIS2, 0x0, sid); + + return rc; +} diff --git a/techpack/video/msm/vidc/hfi_packetization.c b/techpack/video/msm/vidc/hfi_packetization.c new file mode 100644 index 0000000000000000000000000000000000000000..27cd92c17c70ec2b2c90fee52f6e79165639e1f5 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_packetization.c @@ -0,0 +1,800 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ +#include "hfi_packetization.h" +#include "msm_vidc_debug.h" + +u32 vidc_get_hfi_domain(enum hal_domain hal_domain, u32 sid) +{ + u32 hfi_domain; + + switch (hal_domain) { + case HAL_VIDEO_DOMAIN_VPE: + hfi_domain = HFI_VIDEO_DOMAIN_VPE; + break; + case HAL_VIDEO_DOMAIN_ENCODER: + hfi_domain = HFI_VIDEO_DOMAIN_ENCODER; + break; + case HAL_VIDEO_DOMAIN_DECODER: + hfi_domain = HFI_VIDEO_DOMAIN_DECODER; + break; + case HAL_VIDEO_DOMAIN_CVP: + hfi_domain = HFI_VIDEO_DOMAIN_CVP; + break; + default: + s_vpr_e(sid, "%s: invalid domain 0x%x\n", + __func__, hal_domain); + hfi_domain = 0; + break; + } + return hfi_domain; +} + +u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec, u32 sid) +{ + u32 hfi_codec = 0; + + switch (hal_codec) { + case HAL_VIDEO_CODEC_H264: + hfi_codec = HFI_VIDEO_CODEC_H264; + break; + case HAL_VIDEO_CODEC_MPEG1: + hfi_codec = HFI_VIDEO_CODEC_MPEG1; + break; + case HAL_VIDEO_CODEC_MPEG2: + hfi_codec = HFI_VIDEO_CODEC_MPEG2; + break; + case HAL_VIDEO_CODEC_VP8: + hfi_codec = HFI_VIDEO_CODEC_VP8; + break; + case HAL_VIDEO_CODEC_HEVC: + hfi_codec = HFI_VIDEO_CODEC_HEVC; + break; + case HAL_VIDEO_CODEC_VP9: + hfi_codec = HFI_VIDEO_CODEC_VP9; + break; + case HAL_VIDEO_CODEC_TME: + hfi_codec = HFI_VIDEO_CODEC_TME; + break; + case HAL_VIDEO_CODEC_CVP: + hfi_codec = HFI_VIDEO_CODEC_CVP; + break; + default: + s_vpr_h(sid, "%s: invalid codec 0x%x\n", + __func__, hal_codec); + hfi_codec = 0; + break; + } + return hfi_codec; +} + +int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt, + u32 arch_type) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SYS_INIT; + pkt->size = sizeof(struct hfi_cmd_sys_init_packet); + pkt->arch_type = arch_type; + return rc; +} + +int create_pkt_cmd_sys_pc_prep(struct hfi_cmd_sys_pc_prep_packet *pkt) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SYS_PC_PREP; + pkt->size = sizeof(struct hfi_cmd_sys_pc_prep_packet); + return rc; +} + +int create_pkt_cmd_sys_debug_config( + struct hfi_cmd_sys_set_property_packet *pkt, + u32 mode) +{ + struct hfi_debug_config *hfi; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) + + sizeof(struct hfi_debug_config) + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG; + hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1]; + hfi->debug_config = mode; + hfi->debug_mode = HFI_DEBUG_MODE_QUEUE; + if (msm_vidc_fw_debug_mode + <= (HFI_DEBUG_MODE_QUEUE | HFI_DEBUG_MODE_QDSS)) + hfi->debug_mode = msm_vidc_fw_debug_mode; + return 0; +} + +int create_pkt_cmd_sys_coverage_config( + struct hfi_cmd_sys_set_property_packet *pkt, + u32 mode, u32 sid) +{ + if (!pkt) { + s_vpr_e(sid, "In %s(), No input packet\n", __func__); + return -EINVAL; + } + + pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) + + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE; + pkt->rg_property_data[1] = mode; + s_vpr_h(sid, "Firmware coverage mode %d\n", pkt->rg_property_data[1]); + return 0; +} + +int create_pkt_cmd_sys_set_resource( + struct hfi_cmd_sys_set_resource_packet *pkt, + struct vidc_resource_hdr *res_hdr, + void *res_value) +{ + int rc = 0; + u32 i = 0; + + if (!pkt || !res_hdr || !res_value) { + d_vpr_e("Invalid paramas pkt %pK res_hdr %pK res_value %pK\n", + pkt, res_hdr, res_value); + return -EINVAL; + } + + pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE; + pkt->size = sizeof(struct hfi_cmd_sys_set_resource_packet); + pkt->resource_handle = hash32_ptr(res_hdr->resource_handle); + + switch (res_hdr->resource_id) { + case VIDC_RESOURCE_SYSCACHE: + { + struct hfi_resource_syscache_info_type *res_sc_info = + (struct hfi_resource_syscache_info_type *) res_value; + struct hfi_resource_subcache_type *res_sc = + (struct hfi_resource_subcache_type *) + &(res_sc_info->rg_subcache_entries[0]); + + struct hfi_resource_syscache_info_type *hfi_sc_info = + (struct hfi_resource_syscache_info_type *) + &pkt->rg_resource_data[0]; + + struct hfi_resource_subcache_type *hfi_sc = + (struct hfi_resource_subcache_type *) + &(hfi_sc_info->rg_subcache_entries[0]); + + pkt->resource_type = HFI_RESOURCE_SYSCACHE; + hfi_sc_info->num_entries = res_sc_info->num_entries; + + pkt->size += (sizeof(struct hfi_resource_subcache_type)) + * hfi_sc_info->num_entries; + + for (i = 0; i < hfi_sc_info->num_entries; i++) { + hfi_sc[i] = res_sc[i]; + d_vpr_h("entry hfi#%d, sc_id %d, size %d\n", + i, hfi_sc[i].sc_id, hfi_sc[i].size); + } + break; + } + default: + d_vpr_e("Invalid resource_id %d\n", res_hdr->resource_id); + rc = -ENOTSUPP; + } + + return rc; +} + +int create_pkt_cmd_sys_release_resource( + struct hfi_cmd_sys_release_resource_packet *pkt, + struct vidc_resource_hdr *res_hdr) +{ + int rc = 0; + + if (!pkt || !res_hdr) { + d_vpr_e("Invalid paramas pkt %pK res_hdr %pK\n", + pkt, res_hdr); + return -EINVAL; + } + + pkt->size = sizeof(struct hfi_cmd_sys_release_resource_packet); + pkt->packet_type = HFI_CMD_SYS_RELEASE_RESOURCE; + pkt->resource_handle = hash32_ptr(res_hdr->resource_handle); + + switch (res_hdr->resource_id) { + case VIDC_RESOURCE_SYSCACHE: + pkt->resource_type = HFI_RESOURCE_SYSCACHE; + break; + default: + d_vpr_e("Invalid resource_id %d\n", res_hdr->resource_id); + rc = -ENOTSUPP; + } + + d_vpr_h("rel_res: pkt_type 0x%x res_type 0x%x prepared\n", + pkt->packet_type, pkt->resource_type); + + return rc; +} + +inline int create_pkt_cmd_sys_session_init( + struct hfi_cmd_sys_session_init_packet *pkt, + u32 sid, u32 session_domain, u32 session_codec) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_sys_session_init_packet); + pkt->packet_type = HFI_CMD_SYS_SESSION_INIT; + pkt->sid = sid; + pkt->session_domain = vidc_get_hfi_domain(session_domain, sid); + pkt->session_codec = vidc_get_hfi_codec(session_codec, sid); + if (!pkt->session_codec) + return -EINVAL; + + return rc; +} + + +int create_pkt_cmd_sys_ubwc_config( + struct hfi_cmd_sys_set_property_packet *pkt, + struct msm_vidc_ubwc_config_data *ubwc_config) +{ + int rc = 0; + struct hfi_cmd_sys_set_ubwc_config_packet_type *hfi; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) + + sizeof(struct hfi_cmd_sys_set_ubwc_config_packet_type) + + sizeof(u32); + + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG; + hfi = (struct hfi_cmd_sys_set_ubwc_config_packet_type *) + &pkt->rg_property_data[1]; + + hfi->max_channels = ubwc_config->max_channels; + hfi->override_bit_info.max_channel_override = + ubwc_config->override_bit_info.max_channel_override; + + hfi->mal_length = ubwc_config->mal_length; + hfi->override_bit_info.mal_length_override = + ubwc_config->override_bit_info.mal_length_override; + + hfi->highest_bank_bit = ubwc_config->highest_bank_bit; + hfi->override_bit_info.hb_override = + ubwc_config->override_bit_info.hb_override; + + hfi->bank_swzl_level = ubwc_config->bank_swzl_level; + hfi->override_bit_info.bank_swzl_level_override = + ubwc_config->override_bit_info.bank_swzl_level_override; + + hfi->bank_spreading = ubwc_config->bank_spreading; + hfi->override_bit_info.bank_spreading_override = + ubwc_config->override_bit_info.bank_spreading_override; + + return rc; +} + +int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt, + int pkt_type, u32 sid) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct vidc_hal_session_cmd_pkt); + pkt->packet_type = pkt_type; + pkt->sid = sid; + + return rc; +} + +int create_pkt_cmd_sys_power_control( + struct hfi_cmd_sys_set_property_packet *pkt, u32 enable) +{ + struct hfi_enable *hfi; + + if (!pkt) { + d_vpr_e("%s: No input packet\n", __func__); + return -EINVAL; + } + + pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) + + sizeof(struct hfi_enable) + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = enable; + return 0; +} + +static u32 get_hfi_buffer(int hal_buffer, u32 sid) +{ + u32 buffer; + + switch (hal_buffer) { + case HAL_BUFFER_INPUT: + buffer = HFI_BUFFER_INPUT; + break; + case HAL_BUFFER_OUTPUT: + buffer = HFI_BUFFER_OUTPUT; + break; + case HAL_BUFFER_OUTPUT2: + buffer = HFI_BUFFER_OUTPUT2; + break; + case HAL_BUFFER_EXTRADATA_INPUT: + buffer = HFI_BUFFER_EXTRADATA_INPUT; + break; + case HAL_BUFFER_EXTRADATA_OUTPUT: + buffer = HFI_BUFFER_EXTRADATA_OUTPUT; + break; + case HAL_BUFFER_EXTRADATA_OUTPUT2: + buffer = HFI_BUFFER_EXTRADATA_OUTPUT2; + break; + case HAL_BUFFER_INTERNAL_SCRATCH: + buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH; + break; + case HAL_BUFFER_INTERNAL_SCRATCH_1: + buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1; + break; + case HAL_BUFFER_INTERNAL_SCRATCH_2: + buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2; + break; + case HAL_BUFFER_INTERNAL_PERSIST: + buffer = HFI_BUFFER_INTERNAL_PERSIST; + break; + case HAL_BUFFER_INTERNAL_PERSIST_1: + buffer = HFI_BUFFER_INTERNAL_PERSIST_1; + break; + default: + s_vpr_e(sid, "Invalid buffer: %#x\n", hal_buffer); + buffer = 0; + break; + } + return buffer; +} + +int create_pkt_cmd_session_set_buffers( + struct hfi_cmd_session_set_buffers_packet *pkt, + u32 sid, struct vidc_buffer_addr_info *buffer_info) +{ + int rc = 0; + u32 i = 0; + + if (!pkt) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS; + pkt->sid = sid; + pkt->buffer_size = buffer_info->buffer_size; + pkt->min_buffer_size = buffer_info->buffer_size; + pkt->num_buffers = buffer_info->num_buffers; + + if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT || + buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) { + struct hfi_buffer_info *buff; + + pkt->extra_data_size = buffer_info->extradata_size; + + pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) - + sizeof(u32) + (buffer_info->num_buffers * + sizeof(struct hfi_buffer_info)); + buff = (struct hfi_buffer_info *) pkt->rg_buffer_info; + for (i = 0; i < pkt->num_buffers; i++) { + buff->buffer_addr = + (u32)buffer_info->align_device_addr; + buff->extra_data_addr = + (u32)buffer_info->extradata_addr; + } + } else { + pkt->extra_data_size = 0; + pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) + + ((buffer_info->num_buffers - 1) * sizeof(u32)); + for (i = 0; i < pkt->num_buffers; i++) { + pkt->rg_buffer_info[i] = + (u32)buffer_info->align_device_addr; + } + } + + pkt->buffer_type = + get_hfi_buffer(buffer_info->buffer_type, pkt->sid); + if (!pkt->buffer_type) + return -EINVAL; + + return rc; +} + +int create_pkt_cmd_session_release_buffers( + struct hfi_cmd_session_release_buffer_packet *pkt, + u32 sid, struct vidc_buffer_addr_info *buffer_info) +{ + int rc = 0; + u32 i = 0; + + if (!pkt) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS; + pkt->sid = sid; + pkt->buffer_size = buffer_info->buffer_size; + pkt->num_buffers = buffer_info->num_buffers; + + if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT || + buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) { + struct hfi_buffer_info *buff; + + buff = (struct hfi_buffer_info *) pkt->rg_buffer_info; + for (i = 0; i < pkt->num_buffers; i++) { + buff->buffer_addr = + (u32)buffer_info->align_device_addr; + buff->extra_data_addr = + (u32)buffer_info->extradata_addr; + } + pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) - + sizeof(u32) + (buffer_info->num_buffers * + sizeof(struct hfi_buffer_info)); + } else { + for (i = 0; i < pkt->num_buffers; i++) { + pkt->rg_buffer_info[i] = + (u32)buffer_info->align_device_addr; + } + pkt->extra_data_size = 0; + pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) + + ((buffer_info->num_buffers - 1) * sizeof(u32)); + } + pkt->response_req = buffer_info->response_required; + pkt->buffer_type = + get_hfi_buffer(buffer_info->buffer_type, pkt->sid); + if (!pkt->buffer_type) + return -EINVAL; + return rc; +} + +int create_pkt_cmd_session_register_buffer( + struct hfi_cmd_session_register_buffers_packet *pkt, + u32 sid, struct vidc_register_buffer *buffer) +{ + int rc = 0; + u32 i; + struct hfi_buffer_mapping_type *buf; + + if (!pkt) { + d_vpr_e("%s: invalid params %pK\n", __func__, pkt); + return -EINVAL; + } + pkt->packet_type = HFI_CMD_SESSION_REGISTER_BUFFERS; + pkt->sid = sid; + pkt->client_data = buffer->client_data; + pkt->response_req = buffer->response_required; + pkt->num_buffers = 1; + pkt->size = sizeof(struct hfi_cmd_session_register_buffers_packet) - + sizeof(u32) + (pkt->num_buffers * + sizeof(struct hfi_buffer_mapping_type)); + + buf = (struct hfi_buffer_mapping_type *)pkt->buffer; + for (i = 0; i < pkt->num_buffers; i++) { + buf->index = buffer->index; + buf->device_addr = buffer->device_addr; + buf->size = buffer->size; + buf++; + } + + return rc; +} + +int create_pkt_cmd_session_unregister_buffer( + struct hfi_cmd_session_unregister_buffers_packet *pkt, + u32 sid, struct vidc_unregister_buffer *buffer) +{ + int rc = 0; + u32 i; + struct hfi_buffer_mapping_type *buf; + + if (!pkt) { + d_vpr_e("%s: invalid params %pK\n", __func__, pkt); + return -EINVAL; + } + pkt->packet_type = HFI_CMD_SESSION_UNREGISTER_BUFFERS; + pkt->sid = sid; + pkt->client_data = buffer->client_data; + pkt->response_req = buffer->response_required; + pkt->num_buffers = 1; + pkt->size = sizeof(struct hfi_cmd_session_unregister_buffers_packet) - + sizeof(u32) + (pkt->num_buffers * + sizeof(struct hfi_buffer_mapping_type)); + + buf = (struct hfi_buffer_mapping_type *)pkt->buffer; + for (i = 0; i < pkt->num_buffers; i++) { + buf->index = buffer->index; + buf->device_addr = buffer->device_addr; + buf->size = buffer->size; + buf++; + } + + return rc; +} + +int create_pkt_cmd_session_etb_decoder( + struct hfi_cmd_session_empty_buffer_compressed_packet *pkt, + u32 sid, struct vidc_frame_data *input_frame) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = + sizeof(struct hfi_cmd_session_empty_buffer_compressed_packet); + pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER; + pkt->sid = sid; + pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp); + pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp); + pkt->flags = input_frame->flags; + pkt->offset = input_frame->offset; + pkt->alloc_len = input_frame->alloc_len; + pkt->filled_len = input_frame->filled_len; + pkt->input_tag = input_frame->input_tag; + pkt->packet_buffer = (u32)input_frame->device_addr; + + trace_msm_v4l2_vidc_buffer_event_start("ETB", + input_frame->device_addr, input_frame->timestamp, + input_frame->alloc_len, input_frame->filled_len, + input_frame->offset); + + if (!pkt->packet_buffer) + rc = -EINVAL; + return rc; +} + +int create_pkt_cmd_session_etb_encoder( + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet *pkt, + u32 sid, struct vidc_frame_data *input_frame) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct + hfi_cmd_session_empty_buffer_uncompressed_plane0_packet); + pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER; + pkt->sid = sid; + pkt->view_id = 0; + pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp); + pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp); + pkt->flags = input_frame->flags; + pkt->offset = input_frame->offset; + pkt->alloc_len = input_frame->alloc_len; + pkt->filled_len = input_frame->filled_len; + pkt->input_tag = input_frame->input_tag; + pkt->packet_buffer = (u32)input_frame->device_addr; + pkt->extra_data_buffer = (u32)input_frame->extradata_addr; + + trace_msm_v4l2_vidc_buffer_event_start("ETB", + input_frame->device_addr, input_frame->timestamp, + input_frame->alloc_len, input_frame->filled_len, + input_frame->offset); + + if (!pkt->packet_buffer) + rc = -EINVAL; + return rc; +} + +int create_pkt_cmd_session_ftb(struct hfi_cmd_session_fill_buffer_packet *pkt, + u32 sid, struct vidc_frame_data *output_frame) +{ + int rc = 0; + + if (!pkt || !output_frame) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_fill_buffer_packet); + pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER; + pkt->sid = sid; + + if (output_frame->buffer_type == HAL_BUFFER_OUTPUT) + pkt->stream_id = 0; + else if (output_frame->buffer_type == HAL_BUFFER_OUTPUT2) + pkt->stream_id = 1; + + if (!output_frame->device_addr) + return -EINVAL; + + pkt->packet_buffer = (u32)output_frame->device_addr; + pkt->extra_data_buffer = (u32)output_frame->extradata_addr; + pkt->alloc_len = output_frame->alloc_len; + pkt->filled_len = output_frame->filled_len; + pkt->offset = output_frame->offset; + pkt->rgData[0] = output_frame->extradata_size; + + trace_msm_v4l2_vidc_buffer_event_start("FTB", + output_frame->device_addr, output_frame->timestamp, + output_frame->alloc_len, output_frame->filled_len, + output_frame->offset); + + return rc; +} + +int create_pkt_cmd_session_get_buf_req( + struct hfi_cmd_session_get_property_packet *pkt, + u32 sid) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_get_property_packet); + pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY; + pkt->sid = sid; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS; + + return rc; +} + +int create_pkt_cmd_session_flush(struct hfi_cmd_session_flush_packet *pkt, + u32 sid, enum hal_flush flush_mode) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_flush_packet); + pkt->packet_type = HFI_CMD_SESSION_FLUSH; + pkt->sid = sid; + switch (flush_mode) { + case HAL_FLUSH_INPUT: + pkt->flush_type = HFI_FLUSH_INPUT; + break; + case HAL_FLUSH_OUTPUT: + pkt->flush_type = HFI_FLUSH_OUTPUT; + break; + case HAL_FLUSH_ALL: + pkt->flush_type = HFI_FLUSH_ALL; + break; + default: + s_vpr_e(pkt->sid, "Invalid flush mode: %#x\n", flush_mode); + return -EINVAL; + } + return rc; +} + +int create_pkt_cmd_session_set_property( + struct hfi_cmd_session_set_property_packet *pkt, + u32 sid, + u32 ptype, void *pdata, u32 size) +{ + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_set_property_packet); + pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY; + pkt->sid = sid; + pkt->num_properties = 1; + pkt->size += size; + pkt->rg_property_data[0] = ptype; + if (size && pdata) + memcpy(&pkt->rg_property_data[1], pdata, size); + + s_vpr_h(pkt->sid, "Setting HAL Property = 0x%x\n", ptype); + return 0; +} + +static int get_hfi_ssr_type(enum hal_ssr_trigger_type type) +{ + int rc = HFI_TEST_SSR_HW_WDOG_IRQ; + + switch (type) { + case SSR_ERR_FATAL: + rc = HFI_TEST_SSR_SW_ERR_FATAL; + break; + case SSR_SW_DIV_BY_ZERO: + rc = HFI_TEST_SSR_SW_DIV_BY_ZERO; + break; + case SSR_HW_WDOG_IRQ: + rc = HFI_TEST_SSR_HW_WDOG_IRQ; + break; + default: + d_vpr_e("SSR trigger type not recognized, using WDOG.\n"); + } + return rc; +} + +int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type, + struct hfi_cmd_sys_test_ssr_packet *pkt) +{ + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet); + pkt->packet_type = HFI_CMD_SYS_TEST_SSR; + pkt->trigger_type = get_hfi_ssr_type(type); + return 0; +} + +int create_pkt_cmd_sys_image_version( + struct hfi_cmd_sys_get_property_packet *pkt) +{ + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + pkt->size = sizeof(struct hfi_cmd_sys_get_property_packet); + pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION; + return 0; +} + +int create_pkt_cmd_session_sync_process( + struct hfi_cmd_session_sync_process_packet *pkt, u32 sid) +{ + if (!pkt) + return -EINVAL; + + *pkt = (struct hfi_cmd_session_sync_process_packet) {0}; + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_SYNC; + pkt->sid = sid; + pkt->sync_id = 0; + + return 0; +} + +static struct hfi_packetization_ops hfi_default = { + .sys_init = create_pkt_cmd_sys_init, + .sys_pc_prep = create_pkt_cmd_sys_pc_prep, + .sys_power_control = create_pkt_cmd_sys_power_control, + .sys_set_resource = create_pkt_cmd_sys_set_resource, + .sys_debug_config = create_pkt_cmd_sys_debug_config, + .sys_coverage_config = create_pkt_cmd_sys_coverage_config, + .sys_release_resource = create_pkt_cmd_sys_release_resource, + .sys_image_version = create_pkt_cmd_sys_image_version, + .sys_ubwc_config = create_pkt_cmd_sys_ubwc_config, + .ssr_cmd = create_pkt_ssr_cmd, + .session_init = create_pkt_cmd_sys_session_init, + .session_cmd = create_pkt_cmd_session_cmd, + .session_set_buffers = create_pkt_cmd_session_set_buffers, + .session_release_buffers = create_pkt_cmd_session_release_buffers, + .session_register_buffer = create_pkt_cmd_session_register_buffer, + .session_unregister_buffer = create_pkt_cmd_session_unregister_buffer, + .session_etb_decoder = create_pkt_cmd_session_etb_decoder, + .session_etb_encoder = create_pkt_cmd_session_etb_encoder, + .session_ftb = create_pkt_cmd_session_ftb, + .session_get_buf_req = create_pkt_cmd_session_get_buf_req, + .session_flush = create_pkt_cmd_session_flush, + .session_set_property = create_pkt_cmd_session_set_property, + .session_sync_process = create_pkt_cmd_session_sync_process, +}; + +struct hfi_packetization_ops *hfi_get_pkt_ops_handle( + enum hfi_packetization_type type) +{ + d_vpr_h("%s selected\n", type == HFI_PACKETIZATION_4XX ? + "4xx packetization" : "Unknown hfi"); + + switch (type) { + case HFI_PACKETIZATION_4XX: + return &hfi_default; + } + + return NULL; +} diff --git a/techpack/video/msm/vidc/hfi_packetization.h b/techpack/video/msm/vidc/hfi_packetization.h new file mode 100644 index 0000000000000000000000000000000000000000..95278637bd0b3b5eb3c23cb446db3a0e1bcbb652 --- /dev/null +++ b/techpack/video/msm/vidc/hfi_packetization.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ +#ifndef __HFI_PACKETIZATION_H__ +#define __HFI_PACKETIZATION_H__ + +#include <linux/types.h> +#include "vidc_hfi_helper.h" +#include "vidc_hfi.h" +#include "vidc_hfi_api.h" + +#define call_hfi_pkt_op(q, op, ...) \ + (((q) && (q)->pkt_ops && (q)->pkt_ops->op) ? \ + ((q)->pkt_ops->op(__VA_ARGS__)) : 0) + +enum hfi_packetization_type { + HFI_PACKETIZATION_4XX, +}; + +struct hfi_packetization_ops { + int (*sys_init)(struct hfi_cmd_sys_init_packet *pkt, u32 arch_type); + int (*sys_pc_prep)(struct hfi_cmd_sys_pc_prep_packet *pkt); + int (*sys_power_control)(struct hfi_cmd_sys_set_property_packet *pkt, + u32 enable); + int (*sys_set_resource)( + struct hfi_cmd_sys_set_resource_packet *pkt, + struct vidc_resource_hdr *resource_hdr, + void *resource_value); + int (*sys_debug_config)(struct hfi_cmd_sys_set_property_packet *pkt, + u32 mode); + int (*sys_coverage_config)(struct hfi_cmd_sys_set_property_packet *pkt, + u32 mode, u32 sid); + int (*sys_release_resource)( + struct hfi_cmd_sys_release_resource_packet *pkt, + struct vidc_resource_hdr *resource_hdr); + int (*sys_image_version)(struct hfi_cmd_sys_get_property_packet *pkt); + int (*sys_ubwc_config)(struct hfi_cmd_sys_set_property_packet *pkt, + struct msm_vidc_ubwc_config_data *ubwc_config); + int (*ssr_cmd)(enum hal_ssr_trigger_type type, + struct hfi_cmd_sys_test_ssr_packet *pkt); + int (*session_init)( + struct hfi_cmd_sys_session_init_packet *pkt, + u32 sid, u32 session_domain, u32 session_codec); + int (*session_cmd)(struct vidc_hal_session_cmd_pkt *pkt, + int pkt_type, u32 sid); + int (*session_set_buffers)( + struct hfi_cmd_session_set_buffers_packet *pkt, + u32 sid, struct vidc_buffer_addr_info *buffer_info); + int (*session_release_buffers)( + struct hfi_cmd_session_release_buffer_packet *pkt, + u32 sid, struct vidc_buffer_addr_info *buffer_info); + int (*session_register_buffer)( + struct hfi_cmd_session_register_buffers_packet *pkt, + u32 sid, struct vidc_register_buffer *buffer); + int (*session_unregister_buffer)( + struct hfi_cmd_session_unregister_buffers_packet *pkt, + u32 sid, struct vidc_unregister_buffer *buffer); + int (*session_etb_decoder)( + struct hfi_cmd_session_empty_buffer_compressed_packet *pkt, + u32 sid, struct vidc_frame_data *input_frame); + int (*session_etb_encoder)( + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + *pkt, u32 sid, struct vidc_frame_data *input_frame); + int (*session_ftb)(struct hfi_cmd_session_fill_buffer_packet *pkt, + u32 sid, struct vidc_frame_data *output_frame); + int (*session_get_buf_req)( + struct hfi_cmd_session_get_property_packet *pkt, u32 sid); + int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt, + u32 sid, enum hal_flush flush_mode); + int (*session_set_property)( + struct hfi_cmd_session_set_property_packet *pkt, + u32 sid, u32 ptype, void *pdata, u32 size); + int (*session_sync_process)( + struct hfi_cmd_session_sync_process_packet *pkt, u32 sid); +}; + +struct hfi_packetization_ops *hfi_get_pkt_ops_handle( + enum hfi_packetization_type); +#endif diff --git a/techpack/video/msm/vidc/hfi_response_handler.c b/techpack/video/msm/vidc/hfi_response_handler.c new file mode 100644 index 0000000000000000000000000000000000000000..c46b15ff99835196918e277c98af997a92bdae9f --- /dev/null +++ b/techpack/video/msm/vidc/hfi_response_handler.c @@ -0,0 +1,1272 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/bitops.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/hash.h> +#include <linux/soc/qcom/smem.h> +#include <soc/qcom/socinfo.h> +#include "vidc_hfi_helper.h" +#include "msm_vidc_debug.h" +#include "vidc_hfi.h" + +static enum vidc_status hfi_map_err_status(u32 hfi_err) +{ + enum vidc_status vidc_err; + + switch (hfi_err) { + case HFI_ERR_NONE: + case HFI_ERR_SESSION_SAME_STATE_OPERATION: + vidc_err = VIDC_ERR_NONE; + break; + case HFI_ERR_SYS_FATAL: + vidc_err = VIDC_ERR_HW_FATAL; + break; + case HFI_ERR_SYS_NOC_ERROR: + vidc_err = VIDC_ERR_NOC_ERROR; + break; + case HFI_ERR_SYS_VERSION_MISMATCH: + case HFI_ERR_SYS_INVALID_PARAMETER: + case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE: + case HFI_ERR_SESSION_INVALID_PARAMETER: + case HFI_ERR_SESSION_INVALID_SESSION_ID: + case HFI_ERR_SESSION_INVALID_STREAM_ID: + vidc_err = VIDC_ERR_BAD_PARAM; + break; + case HFI_ERR_SYS_INSUFFICIENT_RESOURCES: + case HFI_ERR_SYS_UNSUPPORTED_DOMAIN: + case HFI_ERR_SYS_UNSUPPORTED_CODEC: + case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY: + case HFI_ERR_SESSION_UNSUPPORTED_SETTING: + case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES: + case HFI_ERR_SESSION_UNSUPPORTED_STREAM: + vidc_err = VIDC_ERR_NOT_SUPPORTED; + break; + case HFI_ERR_SYS_MAX_SESSIONS_REACHED: + vidc_err = VIDC_ERR_MAX_CLIENTS; + break; + case HFI_ERR_SYS_SESSION_IN_USE: + vidc_err = VIDC_ERR_CLIENT_PRESENT; + break; + case HFI_ERR_SESSION_FATAL: + vidc_err = VIDC_ERR_CLIENT_FATAL; + break; + case HFI_ERR_SESSION_BAD_POINTER: + vidc_err = VIDC_ERR_BAD_PARAM; + break; + case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION: + vidc_err = VIDC_ERR_BAD_STATE; + break; + case HFI_ERR_SESSION_STREAM_CORRUPT: + case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED: + vidc_err = VIDC_ERR_BITSTREAM_ERR; + break; + case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED: + vidc_err = VIDC_ERR_IFRAME_EXPECTED; + break; + case HFI_ERR_SESSION_START_CODE_NOT_FOUND: + vidc_err = VIDC_ERR_START_CODE_NOT_FOUND; + break; + case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING: + default: + vidc_err = VIDC_ERR_FAIL; + break; + } + return vidc_err; +} + +static int get_hal_pixel_depth(u32 hfi_bit_depth, u32 sid) +{ + switch (hfi_bit_depth) { + case HFI_BITDEPTH_8: return MSM_VIDC_BIT_DEPTH_8; + case HFI_BITDEPTH_9: + case HFI_BITDEPTH_10: return MSM_VIDC_BIT_DEPTH_10; + } + s_vpr_e(sid, "Unsupported bit depth: %d\n", hfi_bit_depth); + return MSM_VIDC_BIT_DEPTH_UNSUPPORTED; +} + +static inline int validate_pkt_size(u32 rem_size, u32 msg_size) +{ + if (rem_size < msg_size) { + d_vpr_e("%s: bad_packet_size: %d\n", __func__, rem_size); + return false; + } + return true; +} + +static int hfi_process_sess_evt_seq_changed(u32 device_id, + struct hfi_msg_event_notify_packet *pkt, + struct msm_vidc_cb_info *info) +{ + struct msm_vidc_cb_event event_notify = {0}; + u32 num_properties_changed; + struct hfi_frame_size *frame_sz; + struct hfi_profile_level *profile_level; + struct hfi_bit_depth *pixel_depth; + struct hfi_pic_struct *pic_struct; + struct hfi_dpb_counts *dpb_counts; + u32 rem_size,entropy_mode = 0; + u8 *data_ptr; + int prop_id; + int luma_bit_depth, chroma_bit_depth; + struct hfi_colour_space *colour_info; + u32 sid; + + if (!validate_pkt_size(pkt->size, + sizeof(struct hfi_msg_event_notify_packet))) + return -E2BIG; + + sid = pkt->sid; + event_notify.device_id = device_id; + event_notify.inst_id = (void *)(uintptr_t)pkt->sid; + event_notify.status = VIDC_ERR_NONE; + num_properties_changed = pkt->event_data2; + switch (pkt->event_data1) { + case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES: + event_notify.hal_event_type = + HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES; + break; + case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES: + event_notify.hal_event_type = + HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES; + break; + default: + break; + } + + if (num_properties_changed) { + data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; + rem_size = pkt->size - sizeof(struct + hfi_msg_event_notify_packet) + sizeof(u32); + do { + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; + prop_id = (int) *((u32 *)data_ptr); + rem_size -= sizeof(u32); + switch (prop_id) { + case HFI_PROPERTY_PARAM_FRAME_SIZE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_frame_size))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + frame_sz = + (struct hfi_frame_size *) data_ptr; + event_notify.width = frame_sz->width; + event_notify.height = frame_sz->height; + s_vpr_hp(sid, "height: %d width: %d\n", + frame_sz->height, frame_sz->width); + data_ptr += + sizeof(struct hfi_frame_size); + rem_size -= sizeof(struct hfi_frame_size); + break; + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_profile_level))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + profile_level = + (struct hfi_profile_level *) data_ptr; + event_notify.profile = profile_level->profile; + event_notify.level = profile_level->level; + s_vpr_hp(sid, "profile: %d level: %d\n", + profile_level->profile, + profile_level->level); + data_ptr += + sizeof(struct hfi_profile_level); + rem_size -= sizeof(struct hfi_profile_level); + break; + case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_bit_depth))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + pixel_depth = (struct hfi_bit_depth *) data_ptr; + /* + * Luma and chroma can have different bitdepths. + * Driver should rely on luma and chroma + * bitdepth for determining output bitdepth + * type. + * + * pixel_depth->bitdepth will include luma + * bitdepth info in bits 0..15 and chroma + * bitdept in bits 16..31. + */ + luma_bit_depth = get_hal_pixel_depth( + pixel_depth->bit_depth & + GENMASK(15, 0), sid); + chroma_bit_depth = get_hal_pixel_depth( + (pixel_depth->bit_depth & + GENMASK(31, 16)) >> 16, sid); + if (luma_bit_depth == MSM_VIDC_BIT_DEPTH_10 || + chroma_bit_depth == + MSM_VIDC_BIT_DEPTH_10) + event_notify.bit_depth = + MSM_VIDC_BIT_DEPTH_10; + else + event_notify.bit_depth = luma_bit_depth; + s_vpr_hp(sid, + "bitdepth(%d), luma_bit_depth(%d), chroma_bit_depth(%d)\n", + event_notify.bit_depth, luma_bit_depth, + chroma_bit_depth); + data_ptr += sizeof(struct hfi_bit_depth); + rem_size -= sizeof(struct hfi_bit_depth); + break; + case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_pic_struct))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + pic_struct = (struct hfi_pic_struct *) data_ptr; + event_notify.pic_struct = + pic_struct->progressive_only; + s_vpr_hp(sid, "Progressive only flag: %d\n", + pic_struct->progressive_only); + data_ptr += + sizeof(struct hfi_pic_struct); + rem_size -= sizeof(struct hfi_pic_struct); + break; + case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_colour_space))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + colour_info = + (struct hfi_colour_space *) data_ptr; + event_notify.colour_space = + colour_info->colour_space; + s_vpr_h(sid, "Colour space value is: %d\n", + colour_info->colour_space); + data_ptr += + sizeof(struct hfi_colour_space); + rem_size -= sizeof(struct hfi_colour_space); + break; + case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + entropy_mode = *(u32 *)data_ptr; + event_notify.entropy_mode = entropy_mode; + s_vpr_hp(sid, "Entropy Mode: 0x%x\n", + entropy_mode); + data_ptr += + sizeof(u32); + rem_size -= sizeof(u32); + break; + case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_buffer_requirements))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + data_ptr += + sizeof(struct hfi_buffer_requirements); + rem_size -= + sizeof(struct hfi_buffer_requirements); + break; + case HFI_INDEX_EXTRADATA_INPUT_CROP: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_index_extradata_input_crop_payload))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + data_ptr += + sizeof(struct + hfi_index_extradata_input_crop_payload); + rem_size -= sizeof(struct + hfi_index_extradata_input_crop_payload); + break; + case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: + if (!validate_pkt_size(rem_size, sizeof(struct + hfi_dpb_counts))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + dpb_counts = (struct hfi_dpb_counts *) data_ptr; + event_notify.max_dpb_count = + dpb_counts->max_dpb_count; + event_notify.max_ref_frames = + dpb_counts->max_ref_frames; + event_notify.max_dec_buffering = + dpb_counts->max_dec_buffering; + event_notify.max_reorder_frames = + dpb_counts->max_reorder_frames; + event_notify.fw_min_cnt = + dpb_counts->fw_min_cnt; + s_vpr_h(sid, + "FW DPB counts: dpb %d ref %d buff %d reorder %d fw_min_cnt %d\n", + dpb_counts->max_dpb_count, + dpb_counts->max_ref_frames, + dpb_counts->max_dec_buffering, + dpb_counts->max_reorder_frames, + dpb_counts->fw_min_cnt); + data_ptr += + sizeof(struct hfi_dpb_counts); + rem_size -= sizeof(struct hfi_dpb_counts); + break; + default: + s_vpr_e(sid, "%s: cmd: %#x not supported\n", + __func__, prop_id); + break; + } + num_properties_changed--; + } while (num_properties_changed > 0); + } + + info->response_type = HAL_SESSION_EVENT_CHANGE; + info->response.event = event_notify; + + return 0; +} + +static int hfi_process_evt_release_buffer_ref(u32 device_id, + struct hfi_msg_event_notify_packet *pkt, + struct msm_vidc_cb_info *info) +{ + struct msm_vidc_cb_event event_notify = {0}; + struct hfi_msg_release_buffer_ref_event_packet *data; + + if (sizeof(struct hfi_msg_event_notify_packet) + > pkt->size) { + d_vpr_e("%s: bad_pkt_size\n", __func__); + return -E2BIG; + } + if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32) + + sizeof(struct hfi_msg_release_buffer_ref_event_packet)) { + d_vpr_e("%s: bad_pkt_size: %d\n", __func__, pkt->size); + return -E2BIG; + } + + data = (struct hfi_msg_release_buffer_ref_event_packet *) + pkt->rg_ext_event_data; + s_vpr_l(pkt->sid, + "RECEIVED: EVENT_NOTIFY - release_buffer_reference\n"); + + event_notify.device_id = device_id; + event_notify.inst_id = (void *)(uintptr_t)pkt->sid; + event_notify.status = VIDC_ERR_NONE; + event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE; + event_notify.packet_buffer = data->packet_buffer; + event_notify.extra_data_buffer = data->extra_data_buffer; + + info->response_type = HAL_SESSION_EVENT_CHANGE; + info->response.event = event_notify; + + return 0; +} + +static int hfi_process_sys_error(u32 device_id, + struct hfi_msg_event_notify_packet *pkt, + struct msm_vidc_cb_info *info) +{ + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + cmd_done.device_id = device_id; + cmd_done.status = hfi_map_err_status(pkt->event_data1); + + info->response_type = HAL_SYS_ERROR; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_error(u32 device_id, + struct hfi_msg_event_notify_packet *pkt, + struct msm_vidc_cb_info *info) +{ + struct msm_vidc_cb_cmd_done cmd_done = {0}; + u32 sid = pkt->sid; + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->event_data1); + info->response.cmd = cmd_done; + s_vpr_h(sid, "RECEIVED: SESSION_ERROR with event id : %#x %#x\n", + pkt->event_data1, pkt->event_data2); + switch (pkt->event_data1) { + /* Ignore below errors */ + case HFI_ERR_SESSION_INVALID_SCALE_FACTOR: + case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED: + s_vpr_h(sid, "Non Fatal: HFI_EVENT_SESSION_ERROR\n"); + info->response_type = HAL_RESPONSE_UNUSED; + break; + default: + s_vpr_e(sid, "%s: data1 %#x, data2 %#x\n", __func__, + pkt->event_data1, pkt->event_data2); + info->response_type = HAL_SESSION_ERROR; + break; + } + + return 0; +} + +static int hfi_process_event_notify(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_event_notify_packet *pkt = _pkt; + + if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { + d_vpr_e("%s: invalid params %u %u\n", __func__, + pkt->size, sizeof(struct hfi_msg_event_notify_packet)); + return -E2BIG; + } + + s_vpr_l(pkt->sid, "RECEIVED: EVENT_NOTIFY\n"); + + switch (pkt->event_id) { + case HFI_EVENT_SYS_ERROR: + s_vpr_e(pkt->sid, "HFI_EVENT_SYS_ERROR: %d, %#x\n", + pkt->event_data1, pkt->event_data2); + return hfi_process_sys_error(device_id, pkt, info); + case HFI_EVENT_SESSION_ERROR: + s_vpr_h(pkt->sid, "HFI_EVENT_SESSION_ERROR\n"); + return hfi_process_session_error(device_id, pkt, info); + + case HFI_EVENT_SESSION_SEQUENCE_CHANGED: + s_vpr_h(pkt->sid, "HFI_EVENT_SESSION_SEQUENCE_CHANGED\n"); + return hfi_process_sess_evt_seq_changed(device_id, pkt, info); + + case HFI_EVENT_RELEASE_BUFFER_REFERENCE: + s_vpr_l(pkt->sid, "HFI_EVENT_RELEASE_BUFFER_REFERENCE\n"); + return hfi_process_evt_release_buffer_ref(device_id, pkt, info); + + case HFI_EVENT_SESSION_PROPERTY_CHANGED: + default: + *info = (struct msm_vidc_cb_info) { + .response_type = HAL_RESPONSE_UNUSED, + }; + + return 0; + } +} + +static int hfi_process_sys_init_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_sys_init_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + enum vidc_status status = VIDC_ERR_NONE; + + if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) { + d_vpr_e("%s: bad_pkt_size: %d\n", __func__, + pkt->size); + return -E2BIG; + } + d_vpr_h("RECEIVED: SYS_INIT_DONE\n"); + + status = hfi_map_err_status(pkt->error_type); + if (status) + d_vpr_e("%s: status %#x\n", __func__, status); + + cmd_done.device_id = device_id; + cmd_done.inst_id = NULL; + cmd_done.status = (u32)status; + cmd_done.size = sizeof(struct vidc_hal_sys_init_done); + + info->response_type = HAL_SYS_INIT_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_sys_rel_resource_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_sys_release_resource_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + enum vidc_status status = VIDC_ERR_NONE; + u32 pkt_size; + + pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet); + if (pkt_size > pkt->size) { + d_vpr_e("hal_process_sys_rel_resource_done: bad size: %d\n", + pkt->size); + return -E2BIG; + } + d_vpr_h("RECEIVED: SYS_RELEASE_RESOURCE_DONE\n"); + + status = hfi_map_err_status(pkt->error_type); + cmd_done.device_id = device_id; + cmd_done.inst_id = NULL; + cmd_done.status = (u32) status; + cmd_done.size = 0; + + info->response_type = HAL_SYS_RELEASE_RESOURCE_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static void hfi_process_sess_get_prop_buf_req( + struct hfi_msg_session_property_info_packet *prop, + struct buffer_requirements *buffreq, u32 sid) +{ + struct hfi_buffer_requirements *hfi_buf_req; + u32 req_bytes; + + if (!prop) { + s_vpr_e(sid, "%s: bad_prop: %pK\n", __func__, prop); + return; + } + + req_bytes = prop->size - sizeof( + struct hfi_msg_session_property_info_packet); + if (!req_bytes || req_bytes % sizeof(struct hfi_buffer_requirements) || + !prop->rg_property_data[1]) { + s_vpr_e(sid, "%s: bad_pkt: %d\n", __func__, req_bytes); + return; + } + + hfi_buf_req = (struct hfi_buffer_requirements *) + &prop->rg_property_data[1]; + + if (!hfi_buf_req) { + s_vpr_e(sid, "%s: invalid buffer req pointer\n", __func__); + return; + } + + while (req_bytes) { + s_vpr_h(sid, "got buffer requirements for: %d\n", + hfi_buf_req->buffer_type); + switch (hfi_buf_req->buffer_type) { + case HFI_BUFFER_INPUT: + memcpy(&buffreq->buffer[0], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[0].buffer_type = HAL_BUFFER_INPUT; + break; + case HFI_BUFFER_OUTPUT: + memcpy(&buffreq->buffer[1], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[1].buffer_type = HAL_BUFFER_OUTPUT; + break; + case HFI_BUFFER_OUTPUT2: + memcpy(&buffreq->buffer[2], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[2].buffer_type = HAL_BUFFER_OUTPUT2; + break; + case HFI_BUFFER_EXTRADATA_INPUT: + memcpy(&buffreq->buffer[3], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[3].buffer_type = + HAL_BUFFER_EXTRADATA_INPUT; + break; + case HFI_BUFFER_EXTRADATA_OUTPUT: + memcpy(&buffreq->buffer[4], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[4].buffer_type = + HAL_BUFFER_EXTRADATA_OUTPUT; + break; + case HFI_BUFFER_EXTRADATA_OUTPUT2: + memcpy(&buffreq->buffer[5], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[5].buffer_type = + HAL_BUFFER_EXTRADATA_OUTPUT2; + break; + case HFI_BUFFER_COMMON_INTERNAL_SCRATCH: + memcpy(&buffreq->buffer[6], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[6].buffer_type = + HAL_BUFFER_INTERNAL_SCRATCH; + break; + case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1: + memcpy(&buffreq->buffer[7], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[7].buffer_type = + HAL_BUFFER_INTERNAL_SCRATCH_1; + break; + case HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2: + memcpy(&buffreq->buffer[8], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[8].buffer_type = + HAL_BUFFER_INTERNAL_SCRATCH_2; + break; + case HFI_BUFFER_INTERNAL_PERSIST: + memcpy(&buffreq->buffer[9], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[9].buffer_type = + HAL_BUFFER_INTERNAL_PERSIST; + break; + case HFI_BUFFER_INTERNAL_PERSIST_1: + memcpy(&buffreq->buffer[10], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[10].buffer_type = + HAL_BUFFER_INTERNAL_PERSIST_1; + break; + case HFI_BUFFER_COMMON_INTERNAL_RECON: + memcpy(&buffreq->buffer[11], hfi_buf_req, + sizeof(struct hfi_buffer_requirements)); + buffreq->buffer[11].buffer_type = + HAL_BUFFER_INTERNAL_RECON; + break; + default: + s_vpr_e(sid, "%s: bad_buffer_type: %d\n", + __func__, hfi_buf_req->buffer_type); + break; + } + req_bytes -= sizeof(struct hfi_buffer_requirements); + hfi_buf_req++; + } +} + +static int hfi_process_session_prop_info(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_property_info_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + struct buffer_requirements buff_req = { { {0} } }; + + if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) { + d_vpr_e("hal_process_session_prop_info: bad_pkt_size\n"); + return -E2BIG; + } else if (!pkt->num_properties) { + d_vpr_e("hal_process_session_prop_info: no_properties\n"); + return -EINVAL; + } + s_vpr_h(pkt->sid, "Received SESSION_PROPERTY_INFO\n"); + + switch (pkt->rg_property_data[0]) { + case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + hfi_process_sess_get_prop_buf_req(pkt, &buff_req, pkt->sid); + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = VIDC_ERR_NONE; + cmd_done.data.property.buf_req = buff_req; + cmd_done.size = sizeof(buff_req); + + info->response_type = HAL_SESSION_PROPERTY_INFO; + info->response.cmd = cmd_done; + + return 0; + default: + s_vpr_h(pkt->sid, "%s: unknown_prop_id: %x\n", + __func__, pkt->rg_property_data[0]); + return -ENOTSUPP; + } +} + +static int hfi_process_session_init_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_sys_session_init_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (sizeof(struct hfi_msg_sys_session_init_done_packet) > pkt->size) { + d_vpr_e("hal_process_session_init_done: bad_pkt_size\n"); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_INIT_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + + info->response_type = HAL_SESSION_INIT_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_load_res_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_load_resources_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (sizeof(struct hfi_msg_session_load_resources_done_packet) != + pkt->size) { + d_vpr_e("%s: bad packet size: %d\n", __func__, pkt->size); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_LOAD_RESOURCES_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_LOAD_RESOURCE_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_flush_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_flush_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) { + d_vpr_e("hal_process_session_flush_done: bad packet size: %d\n", + pkt->size); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_FLUSH_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = sizeof(u32); + + switch (pkt->flush_type) { + case HFI_FLUSH_OUTPUT: + cmd_done.data.flush_type = HAL_FLUSH_OUTPUT; + break; + case HFI_FLUSH_INPUT: + cmd_done.data.flush_type = HAL_FLUSH_INPUT; + break; + case HFI_FLUSH_ALL: + cmd_done.data.flush_type = HAL_FLUSH_ALL; + break; + default: + s_vpr_e(pkt->sid, "%s: invalid flush type!", __func__); + return -EINVAL; + } + + info->response_type = HAL_SESSION_FLUSH_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_etb_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; + struct msm_vidc_cb_data_done data_done = {0}; + + if (!pkt || pkt->size < + sizeof(struct hfi_msg_session_empty_buffer_done_packet)) + goto bad_packet_size; + + s_vpr_l(pkt->sid, "RECEIVED: SESSION_ETB_DONE\n"); + + data_done.device_id = device_id; + data_done.inst_id = (void *)(uintptr_t)pkt->sid; + data_done.status = hfi_map_err_status(pkt->error_type); + data_done.size = sizeof(struct msm_vidc_cb_data_done); + data_done.input_done.input_tag = pkt->input_tag; + data_done.input_done.recon_stats.buffer_index = + pkt->ubwc_cr_stats.frame_index; + memcpy(&data_done.input_done.recon_stats.ubwc_stats_info, + &pkt->ubwc_cr_stats.ubwc_stats_info, + sizeof(data_done.input_done.recon_stats.ubwc_stats_info)); + data_done.input_done.recon_stats.complexity_number = + pkt->ubwc_cr_stats.complexity_number; + data_done.input_done.offset = pkt->offset; + data_done.input_done.filled_len = pkt->filled_len; + data_done.input_done.flags = pkt->flags; + data_done.input_done.packet_buffer = pkt->packet_buffer; + data_done.input_done.extra_data_buffer = pkt->extra_data_buffer; + data_done.input_done.status = + hfi_map_err_status(pkt->error_type); + + trace_msm_v4l2_vidc_buffer_event_end("ETB", + (u32)pkt->packet_buffer, -1, -1, + pkt->filled_len, pkt->offset); + + info->response_type = HAL_SESSION_ETB_DONE; + info->response.data = data_done; + + return 0; +bad_packet_size: + d_vpr_e("%s: ebd - bad_pkt_size: %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; +} + +static int hfi_process_session_ftb_done( + u32 device_id, void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct vidc_hal_msg_pkt_hdr *msg_hdr = _pkt; + struct msm_vidc_cb_data_done data_done = {0}; + bool is_decoder = false, is_encoder = false; + + if (!msg_hdr) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + is_encoder = msg_hdr->size == sizeof(struct + hfi_msg_session_fill_buffer_done_compressed_packet) + 4; + is_decoder = msg_hdr->size == sizeof(struct + hfi_msg_session_fbd_uncompressed_plane0_packet) + 4; + + if (!(is_encoder ^ is_decoder)) { + d_vpr_e("Ambiguous packet (%#x) received (size %d)\n", + msg_hdr->packet, msg_hdr->size); + return -EBADHANDLE; + } + + if (is_encoder) { + struct hfi_msg_session_fill_buffer_done_compressed_packet *pkt = + (struct hfi_msg_session_fill_buffer_done_compressed_packet *) + msg_hdr; + if (sizeof(struct + hfi_msg_session_fill_buffer_done_compressed_packet) + > pkt->size) { + d_vpr_e("hal_process_session_ftb_done: bad_pkt_size\n"); + return -E2BIG; + } else if (pkt->error_type != HFI_ERR_NONE) { + s_vpr_e(pkt->sid, "got buffer back with error %x\n", + pkt->error_type); + /* Proceed with the FBD */ + } + s_vpr_l(pkt->sid, "RECEIVED: SESSION_FTB_DONE\n"); + + data_done.device_id = device_id; + data_done.inst_id = (void *)(uintptr_t)pkt->sid; + data_done.status = hfi_map_err_status(pkt->error_type); + data_done.size = sizeof(struct msm_vidc_cb_data_done); + + data_done.output_done.input_tag = pkt->input_tag; + data_done.output_done.timestamp_hi = pkt->time_stamp_hi; + data_done.output_done.timestamp_lo = pkt->time_stamp_lo; + data_done.output_done.flags1 = pkt->flags; + data_done.output_done.stats = pkt->stats; + data_done.output_done.offset1 = pkt->offset; + data_done.output_done.alloc_len1 = pkt->alloc_len; + data_done.output_done.filled_len1 = pkt->filled_len; + data_done.output_done.picture_type = pkt->picture_type; + data_done.output_done.packet_buffer1 = pkt->packet_buffer; + data_done.output_done.extra_data_buffer = + pkt->extra_data_buffer; + data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT; + } else /* if (is_decoder) */ { + struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt = + (struct hfi_msg_session_fbd_uncompressed_plane0_packet *) + msg_hdr; + if (sizeof( + struct hfi_msg_session_fbd_uncompressed_plane0_packet) > + pkt->size) { + d_vpr_e("hal_process_session_ftb_done: bad_pkt_size\n"); + return -E2BIG; + } + s_vpr_l(pkt->sid, "RECEIVED: SESSION_FTB_DONE\n"); + + data_done.device_id = device_id; + data_done.inst_id = (void *)(uintptr_t)pkt->sid; + data_done.status = hfi_map_err_status(pkt->error_type); + data_done.size = sizeof(struct msm_vidc_cb_data_done); + + data_done.output_done.stream_id = pkt->stream_id; + data_done.output_done.view_id = pkt->view_id; + data_done.output_done.timestamp_hi = pkt->time_stamp_hi; + data_done.output_done.timestamp_lo = pkt->time_stamp_lo; + data_done.output_done.flags1 = pkt->flags; + data_done.output_done.stats = pkt->stats; + data_done.output_done.alloc_len1 = pkt->alloc_len; + data_done.output_done.filled_len1 = pkt->filled_len; + data_done.output_done.offset1 = pkt->offset; + data_done.output_done.frame_width = pkt->frame_width; + data_done.output_done.frame_height = pkt->frame_height; + data_done.output_done.start_x_coord = pkt->start_x_coord; + data_done.output_done.start_y_coord = pkt->start_y_coord; + data_done.output_done.input_tag = pkt->input_tag; + data_done.output_done.input_tag2 = pkt->input_tag2; + data_done.output_done.picture_type = pkt->picture_type; + data_done.output_done.packet_buffer1 = pkt->packet_buffer; + data_done.output_done.extra_data_buffer = + pkt->extra_data_buffer; + + if (!pkt->stream_id) + data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT; + else if (pkt->stream_id == 1) + data_done.output_done.buffer_type = HAL_BUFFER_OUTPUT2; + } + + trace_msm_v4l2_vidc_buffer_event_end("FTB", + (u32)data_done.output_done.packet_buffer1, + (((u64)data_done.output_done.timestamp_hi) << 32) + + ((u64)data_done.output_done.timestamp_lo), + data_done.output_done.alloc_len1, + data_done.output_done.filled_len1, + data_done.output_done.offset1); + + info->response_type = HAL_SESSION_FTB_DONE; + info->response.data = data_done; + + return 0; +} + +static int hfi_process_session_start_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_start_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_session_start_done_packet)) { + d_vpr_e("%s: bad packet/packet size\n", __func__); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_START_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_START_DONE; + info->response.cmd = cmd_done; + return 0; +} + +static int hfi_process_session_stop_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_stop_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_session_stop_done_packet)) { + d_vpr_e("%s: bad packet/packet size\n", __func__); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_STOP_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_STOP_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_rel_res_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_release_resources_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_session_release_resources_done_packet)) { + d_vpr_e("%s: bad packet/packet size\n", __func__); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_RELEASE_RESOURCE_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_rel_buf_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_release_buffers_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size < + sizeof(struct hfi_msg_session_release_buffers_done_packet)) { + d_vpr_e("bad packet/packet size %d\n", + pkt ? pkt->size : 0); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED:SESSION_RELEASE_BUFFER_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.data.buffer_info.buffer_addr = *pkt->rg_buffer_info; + cmd_done.size = sizeof(struct hal_buffer_info); + + info->response_type = HAL_SESSION_RELEASE_BUFFER_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_register_buffer_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_register_buffers_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size < + sizeof(struct hfi_msg_session_register_buffers_done_packet)) { + d_vpr_e("%s: bad packet/packet size %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_REGISTER_BUFFERS_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.data.regbuf.client_data = pkt->client_data; + + info->response_type = HAL_SESSION_REGISTER_BUFFER_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_unregister_buffer_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_session_unregister_buffers_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size < + sizeof(struct hfi_msg_session_unregister_buffers_done_packet)) { + d_vpr_e("%s: bad packet/packet size %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_UNREGISTER_BUFFERS_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.data.unregbuf.client_data = pkt->client_data; + + info->response_type = HAL_SESSION_UNREGISTER_BUFFER_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_end_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_sys_session_end_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_sys_session_end_done_packet)) { + d_vpr_e("%s: bad packet/packet size\n", __func__); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_END_DONE\n"); + + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_END_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static int hfi_process_session_abort_done(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_sys_session_abort_done_packet *pkt = _pkt; + struct msm_vidc_cb_cmd_done cmd_done = {0}; + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_sys_session_abort_done_packet)) { + d_vpr_e("%s: bad packet/packet size: %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + s_vpr_h(pkt->sid, "RECEIVED: SESSION_ABORT_DONE\n"); + cmd_done.device_id = device_id; + cmd_done.inst_id = (void *)(uintptr_t)pkt->sid; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.size = 0; + + info->response_type = HAL_SESSION_ABORT_DONE; + info->response.cmd = cmd_done; + + return 0; +} + +static void hfi_process_sys_get_prop_image_version( + struct hfi_msg_sys_property_info_packet *pkt) +{ + u32 i = 0; + size_t smem_block_size = 0; + u8 *smem_table_ptr; + char version[256]; + const u32 version_string_size = 128; + const u32 smem_image_index_venus = 14 * 128; + u8 *str_image_version; + u32 req_bytes; + + req_bytes = pkt->size - sizeof(*pkt); + if (req_bytes < version_string_size || + !pkt->rg_property_data[1] || + pkt->num_properties > 1) { + d_vpr_e("%s: bad_pkt: %d\n", __func__, req_bytes); + return; + } + str_image_version = (u8 *)&pkt->rg_property_data[1]; + /* + * The version string returned by firmware includes null + * characters at the start and in between. Replace the null + * characters with space, to print the version info. + */ + for (i = 0; i < version_string_size; i++) { + if (str_image_version[i] != '\0') + version[i] = str_image_version[i]; + else + version[i] = ' '; + } + version[i] = '\0'; + d_vpr_h("F/W version: %s\n", version); + + smem_table_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_IMAGE_VERSION_TABLE, &smem_block_size); + if ((smem_image_index_venus + version_string_size) <= smem_block_size && + smem_table_ptr) + memcpy(smem_table_ptr + smem_image_index_venus, + str_image_version, version_string_size); +} + +static int hfi_process_sys_property_info(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + struct hfi_msg_sys_property_info_packet *pkt = _pkt; + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } else if (pkt->size < sizeof(*pkt)) { + d_vpr_e("%s: bad_pkt_size\n", __func__); + return -E2BIG; + } else if (!pkt->num_properties) { + d_vpr_e("%s: no_properties\n", __func__); + return -EINVAL; + } + + switch (pkt->rg_property_data[0]) { + case HFI_PROPERTY_SYS_IMAGE_VERSION: + hfi_process_sys_get_prop_image_version(pkt); + + *info = (struct msm_vidc_cb_info) { + .response_type = HAL_RESPONSE_UNUSED, + }; + return 0; + default: + d_vpr_h("%s: unknown_prop_id: %x\n", + __func__, pkt->rg_property_data[0]); + return -ENOTSUPP; + } + +} + +static int hfi_process_ignore(u32 device_id, + void *_pkt, + struct msm_vidc_cb_info *info) +{ + *info = (struct msm_vidc_cb_info) { + .response_type = HAL_RESPONSE_UNUSED, + }; + d_vpr_h("RECEIVED: SESSION_SYNC_DONE\n"); + + return 0; +} + +int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + struct msm_vidc_cb_info *info) +{ + typedef int (*pkt_func_def)(u32, void *, struct msm_vidc_cb_info *info); + pkt_func_def pkt_func = NULL; + + if (!info || !msg_hdr || msg_hdr->size < VIDC_IFACEQ_MIN_PKT_SIZE) { + d_vpr_e("%s: bad packet/packet size\n", __func__); + return -EINVAL; + } + + switch (msg_hdr->packet) { + case HFI_MSG_EVENT_NOTIFY: + pkt_func = (pkt_func_def)hfi_process_event_notify; + break; + case HFI_MSG_SYS_INIT_DONE: + pkt_func = (pkt_func_def)hfi_process_sys_init_done; + break; + case HFI_MSG_SYS_SESSION_INIT_DONE: + pkt_func = (pkt_func_def)hfi_process_session_init_done; + break; + case HFI_MSG_SYS_PROPERTY_INFO: + pkt_func = (pkt_func_def)hfi_process_sys_property_info; + break; + case HFI_MSG_SYS_SESSION_END_DONE: + pkt_func = (pkt_func_def)hfi_process_session_end_done; + break; + case HFI_MSG_SESSION_LOAD_RESOURCES_DONE: + pkt_func = (pkt_func_def)hfi_process_session_load_res_done; + break; + case HFI_MSG_SESSION_START_DONE: + pkt_func = (pkt_func_def)hfi_process_session_start_done; + break; + case HFI_MSG_SESSION_STOP_DONE: + pkt_func = (pkt_func_def)hfi_process_session_stop_done; + break; + case HFI_MSG_SESSION_EMPTY_BUFFER_DONE: + pkt_func = (pkt_func_def)hfi_process_session_etb_done; + break; + case HFI_MSG_SESSION_FILL_BUFFER_DONE: + pkt_func = (pkt_func_def)hfi_process_session_ftb_done; + break; + case HFI_MSG_SESSION_FLUSH_DONE: + pkt_func = (pkt_func_def)hfi_process_session_flush_done; + break; + case HFI_MSG_SESSION_PROPERTY_INFO: + pkt_func = (pkt_func_def)hfi_process_session_prop_info; + break; + case HFI_MSG_SESSION_RELEASE_RESOURCES_DONE: + pkt_func = (pkt_func_def)hfi_process_session_rel_res_done; + break; + case HFI_MSG_SYS_RELEASE_RESOURCE: + pkt_func = (pkt_func_def)hfi_process_sys_rel_resource_done; + break; + case HFI_MSG_SESSION_RELEASE_BUFFERS_DONE: + pkt_func = (pkt_func_def)hfi_process_session_rel_buf_done; + break; + case HFI_MSG_SESSION_REGISTER_BUFFERS_DONE: + pkt_func = (pkt_func_def) + hfi_process_session_register_buffer_done; + break; + case HFI_MSG_SESSION_UNREGISTER_BUFFERS_DONE: + pkt_func = (pkt_func_def) + hfi_process_session_unregister_buffer_done; + break; + case HFI_MSG_SYS_SESSION_ABORT_DONE: + pkt_func = (pkt_func_def)hfi_process_session_abort_done; + break; + case HFI_MSG_SESSION_SYNC_DONE: + pkt_func = (pkt_func_def)hfi_process_ignore; + break; + default: + d_vpr_l("Unable to parse message: %#x\n", msg_hdr->packet); + break; + } + + return pkt_func ? + pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; +} diff --git a/techpack/video/msm/vidc/msm_cvp_internal.c b/techpack/video/msm/vidc/msm_cvp_internal.c new file mode 100644 index 0000000000000000000000000000000000000000..48efca59d755cdb3939b7f42fbd862e1fbcf59a9 --- /dev/null +++ b/techpack/video/msm/vidc/msm_cvp_internal.c @@ -0,0 +1,620 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#include "msm_cvp_internal.h" + +#define MSM_VIDC_NOMINAL_CYCLES (444 * 1000 * 1000) +#define MSM_VIDC_UHD60E_VPSS_CYCLES (111 * 1000 * 1000) +#define MSM_VIDC_UHD60E_ISE_CYCLES (175 * 1000 * 1000) +#define MAX_CVP_VPSS_CYCLES (MSM_VIDC_NOMINAL_CYCLES - \ + MSM_VIDC_UHD60E_VPSS_CYCLES) +#define MAX_CVP_ISE_CYCLES (MSM_VIDC_NOMINAL_CYCLES - \ + MSM_VIDC_UHD60E_ISE_CYCLES) + +static void print_client_buffer(u32 tag, const char *str, + struct msm_vidc_inst *inst, struct msm_cvp_buffer *cbuf) +{ + if (!(tag & msm_vidc_debug) || !inst || !cbuf) + return; + + dprintk(tag, inst->sid, + "%s: idx %2d fd %d off %d size %d type %d flags 0x%x\n", + str, cbuf->index, cbuf->fd, + cbuf->offset, cbuf->size, cbuf->type, cbuf->flags); +} + +static void print_cvp_buffer(u32 tag, const char *str, + struct msm_vidc_inst *inst, struct msm_vidc_cvp_buffer *cbuf) +{ + if (!(tag & msm_vidc_debug) || !inst || !cbuf) + return; + + dprintk(tag, inst->sid, + "%s: idx %2d fd %d off %d daddr %x size %d type %d flags 0x%x\n", + str, cbuf->buf.index, cbuf->buf.fd, + cbuf->buf.offset, cbuf->smem.device_addr, cbuf->buf.size, + cbuf->buf.type, cbuf->buf.flags); +} + +static enum hal_buffer get_hal_buftype(const char *str, + unsigned int type, u32 sid) +{ + enum hal_buffer buftype = HAL_BUFFER_NONE; + + if (type == MSM_CVP_BUFTYPE_INPUT) + buftype = HAL_BUFFER_INPUT; + else if (type == MSM_CVP_BUFTYPE_OUTPUT) + buftype = HAL_BUFFER_OUTPUT; + else if (type == MSM_CVP_BUFTYPE_INTERNAL_1) + buftype = HAL_BUFFER_INTERNAL_SCRATCH_1; + else if (type == MSM_CVP_BUFTYPE_INTERNAL_2) + buftype = HAL_BUFFER_INTERNAL_SCRATCH_1; + else + s_vpr_e(sid, "%s: unknown buffer type %#x\n", + str, type); + + return buftype; +} + +void handle_session_register_buffer_done(enum hal_command_response cmd, + void *resp) +{ + struct msm_vidc_cb_cmd_done *response = resp; + struct msm_vidc_inst *inst; + struct msm_vidc_cvp_buffer *cbuf; + struct v4l2_event event = {0}; + u32 *data; + bool found; + + if (!response) { + d_vpr_e("%s: invalid response\n", __func__); + return; + } + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("%s: invalid session %pK\n", __func__, + response->inst_id); + return; + } + + mutex_lock(&inst->cvpbufs.lock); + found = false; + list_for_each_entry(cbuf, &inst->cvpbufs.list, list) { + if (response->data.regbuf.client_data == + cbuf->smem.device_addr) { + found = true; + break; + } + } + mutex_unlock(&inst->cvpbufs.lock); + if (!found) { + s_vpr_e(inst->sid, "%s: client_data %x not found\n", + __func__, response->data.regbuf.client_data); + goto exit; + } + print_cvp_buffer(VIDC_HIGH, "register_done", inst, cbuf); + + event.type = V4L2_EVENT_MSM_VIDC_REGISTER_BUFFER_DONE; + data = (u32 *)event.u.data; + data[0] = cbuf->buf.index; + data[1] = cbuf->buf.type; + data[2] = cbuf->buf.fd; + data[3] = cbuf->buf.offset; + v4l2_event_queue_fh(&inst->event_handler, &event); + +exit: + s_vpr_l(inst->sid, "handled: SESSION_REGISTER_BUFFER_DONE\n"); + put_inst(inst); +} + +void handle_session_unregister_buffer_done(enum hal_command_response cmd, + void *resp) +{ + int rc; + struct msm_vidc_cb_cmd_done *response = resp; + struct msm_vidc_inst *inst; + struct msm_vidc_cvp_buffer *cbuf, *dummy; + struct v4l2_event event = {0}; + u32 *data; + bool found; + + if (!response) { + d_vpr_e("%s: invalid response\n", __func__); + return; + } + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("%s: invalid session %pK\n", __func__, + response->inst_id); + return; + } + + mutex_lock(&inst->cvpbufs.lock); + found = false; + list_for_each_entry_safe(cbuf, dummy, &inst->cvpbufs.list, list) { + if (response->data.unregbuf.client_data == + cbuf->smem.device_addr) { + found = true; + break; + } + } + mutex_unlock(&inst->cvpbufs.lock); + if (!found) { + s_vpr_e(inst->sid, "%s: client_data %x not found\n", + __func__, response->data.unregbuf.client_data); + goto exit; + } + print_cvp_buffer(VIDC_HIGH, "unregister_done", inst, cbuf); + + rc = inst->smem_ops->smem_unmap_dma_buf(inst, &cbuf->smem); + if (rc) { + print_cvp_buffer(VIDC_ERR, "unmap fail", inst, cbuf); + goto exit; + } + + event.type = V4L2_EVENT_MSM_VIDC_UNREGISTER_BUFFER_DONE; + data = (u32 *)event.u.data; + data[0] = cbuf->buf.index; + data[1] = cbuf->buf.type; + data[2] = cbuf->buf.fd; + data[3] = cbuf->buf.offset; + v4l2_event_queue_fh(&inst->event_handler, &event); + + mutex_lock(&inst->cvpbufs.lock); + list_del(&cbuf->list); + mutex_unlock(&inst->cvpbufs.lock); + kfree(cbuf); + cbuf = NULL; +exit: + s_vpr_l(inst->sid, "handled: SESSION_UNREGISTER_BUFFER_DONE\n"); + put_inst(inst); +} + +static void print_cvp_cycles(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + + if (!inst || !inst->core) + return; + core = inst->core; + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + if (temp->session_type == MSM_VIDC_CVP) { + s_vpr_e(temp->sid, "vpss %d ise %d\n", + temp->clk_data.vpss_cycles, + temp->clk_data.ise_cycles); + } + } + mutex_unlock(&core->lock); +} + +static bool msm_cvp_check_session_supported(struct msm_vidc_inst *inst, + u32 vpss_cycles, u32 ise_cycles) +{ + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + u32 total_vpss_cycles = 0; + u32 total_ise_cycles = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return false; + } + core = inst->core; + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + if (temp->session_type == MSM_VIDC_CVP) { + total_vpss_cycles += inst->clk_data.vpss_cycles; + total_ise_cycles += inst->clk_data.ise_cycles; + } + } + mutex_unlock(&core->lock); + + if ((total_vpss_cycles > MAX_CVP_VPSS_CYCLES) || + (total_ise_cycles > MAX_CVP_ISE_CYCLES)) + return false; + + return true; +} + +static int msm_cvp_scale_clocks_and_bus(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + rc = msm_vidc_set_clocks(inst->core, inst->sid); + if (rc) { + s_vpr_e(inst->sid, "%s: failed set_clocks for inst %pK\n", + __func__, inst); + goto exit; + } + + rc = msm_comm_vote_bus(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed vote_bus for inst %pK\n", __func__, inst); + goto exit; + } + +exit: + return rc; +} + +static int msm_cvp_get_session_info(struct msm_vidc_inst *inst, + struct msm_cvp_session_info *session) +{ + int rc = 0; + + if (!inst || !inst->core || !session) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, session); + return -EINVAL; + } + + session->session_id = inst->sid; + s_vpr_h(inst->sid, "%s: id 0x%x\n", __func__, session->session_id); + + return rc; +} + +static int msm_cvp_request_power(struct msm_vidc_inst *inst, + struct msm_cvp_request_power *power) +{ + int rc = 0; + + if (!inst || !power) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, power); + return -EINVAL; + } + + s_vpr_h(inst->sid, + "%s: clock_cycles_a %d, clock_cycles_b %d, ddr_bw %d sys_cache_bw %d\n", + __func__, power->clock_cycles_a, power->clock_cycles_b, + power->ddr_bw, power->sys_cache_bw); + + rc = msm_cvp_check_session_supported(inst, power->clock_cycles_a, + power->clock_cycles_b); + if (!rc) { + s_vpr_e(inst->sid, "%s: rejected, cycles: vpss %d, ise %d\n", + __func__, power->clock_cycles_a, power->clock_cycles_b); + print_cvp_cycles(inst); + msm_comm_kill_session(inst); + return -EOVERFLOW; + } + + inst->clk_data.min_freq = max(power->clock_cycles_a, + power->clock_cycles_b); + /* convert client provided bps into kbps as expected by driver */ + inst->clk_data.ddr_bw = power->ddr_bw / 1000; + inst->clk_data.sys_cache_bw = power->sys_cache_bw / 1000; + rc = msm_cvp_scale_clocks_and_bus(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed to scale clocks and bus for inst %pK\n", + __func__, inst); + goto exit; + } + + if (!inst->clk_data.min_freq && !inst->clk_data.ddr_bw && + !inst->clk_data.sys_cache_bw) { + rc = msm_cvp_inst_pause(inst); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to pause\n", __func__); + goto exit; + } + } else { + rc = msm_cvp_inst_resume(inst); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to resume\n", __func__); + goto exit; + } + } + +exit: + return rc; +} + +static int msm_cvp_register_buffer(struct msm_vidc_inst *inst, + struct msm_cvp_buffer *buf) +{ + int rc = 0; + bool found; + struct hfi_device *hdev; + struct msm_vidc_cvp_buffer *cbuf; + struct vidc_register_buffer vbuf; + + if (!inst || !inst->core || !buf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, buf); + return -EINVAL; + } + hdev = inst->core->device; + print_client_buffer(VIDC_HIGH, "register", inst, buf); + + mutex_lock(&inst->cvpbufs.lock); + found = false; + list_for_each_entry(cbuf, &inst->cvpbufs.list, list) { + if (cbuf->buf.index == buf->index && + cbuf->buf.fd == buf->fd && + cbuf->buf.offset == buf->offset) { + found = true; + break; + } + } + mutex_unlock(&inst->cvpbufs.lock); + if (found) { + print_client_buffer(VIDC_ERR, "duplicate", inst, buf); + return -EINVAL; + } + + cbuf = kzalloc(sizeof(struct msm_vidc_cvp_buffer), GFP_KERNEL); + if (!cbuf) { + s_vpr_e(inst->sid, "%s: cbuf alloc failed\n", __func__); + return -ENOMEM; + } + + memcpy(&cbuf->buf, buf, sizeof(struct msm_cvp_buffer)); + cbuf->smem.buffer_type = get_hal_buftype(__func__, buf->type, + inst->sid); + cbuf->smem.fd = buf->fd; + cbuf->smem.offset = buf->offset; + cbuf->smem.size = buf->size; + rc = inst->smem_ops->smem_map_dma_buf(inst, &cbuf->smem); + if (rc) { + print_client_buffer(VIDC_ERR, "map failed", inst, buf); + goto exit; + } + + memset(&vbuf, 0, sizeof(struct vidc_register_buffer)); + vbuf.index = buf->index; + vbuf.type = get_hal_buftype(__func__, buf->type, inst->sid); + vbuf.size = buf->size; + vbuf.device_addr = cbuf->smem.device_addr; + vbuf.client_data = cbuf->smem.device_addr; + vbuf.response_required = true; + rc = call_hfi_op(hdev, session_register_buffer, + (void *)inst->session, &vbuf); + if (rc) { + print_cvp_buffer(VIDC_ERR, "register failed", inst, cbuf); + goto exit; + } + mutex_lock(&inst->cvpbufs.lock); + list_add_tail(&cbuf->list, &inst->cvpbufs.list); + mutex_unlock(&inst->cvpbufs.lock); + return rc; + +exit: + if (cbuf->smem.device_addr) + inst->smem_ops->smem_unmap_dma_buf(inst, &cbuf->smem); + kfree(cbuf); + cbuf = NULL; + + return rc; +} + +static int msm_cvp_unregister_buffer(struct msm_vidc_inst *inst, + struct msm_cvp_buffer *buf) +{ + int rc = 0; + bool found; + struct hfi_device *hdev; + struct msm_vidc_cvp_buffer *cbuf; + struct vidc_unregister_buffer vbuf; + + if (!inst || !inst->core || !buf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, buf); + return -EINVAL; + } + hdev = inst->core->device; + print_client_buffer(VIDC_HIGH, "unregister", inst, buf); + + mutex_lock(&inst->cvpbufs.lock); + found = false; + list_for_each_entry(cbuf, &inst->cvpbufs.list, list) { + if (cbuf->buf.index == buf->index && + cbuf->buf.fd == buf->fd && + cbuf->buf.offset == buf->offset) { + found = true; + break; + } + } + mutex_unlock(&inst->cvpbufs.lock); + if (!found) { + print_client_buffer(VIDC_ERR, "invalid", inst, buf); + return -EINVAL; + } + + memset(&vbuf, 0, sizeof(struct vidc_unregister_buffer)); + vbuf.index = cbuf->buf.index; + vbuf.type = get_hal_buftype(__func__, cbuf->buf.type, inst->sid); + vbuf.size = cbuf->buf.size; + vbuf.device_addr = cbuf->smem.device_addr; + vbuf.client_data = cbuf->smem.device_addr; + vbuf.response_required = true; + rc = call_hfi_op(hdev, session_unregister_buffer, + (void *)inst->session, &vbuf); + if (rc) + print_cvp_buffer(VIDC_ERR, "unregister failed", inst, cbuf); + + return rc; +} + +int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg) +{ + int rc = 0; + + if (!inst || !arg) { + d_vpr_e("%s: invalid args %pK %pK\n", + __func__, inst, arg); + return -EINVAL; + } + + switch (arg->type) { + case MSM_CVP_GET_SESSION_INFO: + { + struct msm_cvp_session_info *session = + (struct msm_cvp_session_info *)&arg->data.session; + + rc = msm_cvp_get_session_info(inst, session); + break; + } + case MSM_CVP_REQUEST_POWER: + { + struct msm_cvp_request_power *power = + (struct msm_cvp_request_power *)&arg->data.req_power; + + rc = msm_cvp_request_power(inst, power); + break; + } + case MSM_CVP_REGISTER_BUFFER: + { + struct msm_cvp_buffer *buf = + (struct msm_cvp_buffer *)&arg->data.regbuf; + + rc = msm_cvp_register_buffer(inst, buf); + break; + } + case MSM_CVP_UNREGISTER_BUFFER: + { + struct msm_cvp_buffer *buf = + (struct msm_cvp_buffer *)&arg->data.unregbuf; + + rc = msm_cvp_unregister_buffer(inst, buf); + break; + } + default: + s_vpr_e(inst->sid, "%s: unknown arg type 0x%x\n", + __func__, arg->type); + rc = -ENOTSUPP; + break; + } + + return rc; +} + +static struct msm_vidc_ctrl msm_cvp_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDEO_UNKNOWN, + .name = "Invalid control", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, +}; + +int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, + const struct v4l2_ctrl_ops *ctrl_ops) +{ + return msm_comm_ctrl_init(inst, msm_cvp_ctrls, + ARRAY_SIZE(msm_cvp_ctrls), ctrl_ops); +} + +int msm_cvp_inst_pause(struct msm_vidc_inst *inst) +{ + int rc; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_pause, (void *)inst->session); + if (rc) + s_vpr_e(inst->sid, "%s: failed to pause\n", __func__); + + return rc; +} + +int msm_cvp_inst_resume(struct msm_vidc_inst *inst) +{ + int rc; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_resume, (void *)inst->session); + if (rc) + s_vpr_e(inst->sid, "%s: failed to resume\n", __func__); + + return rc; +} + +int msm_cvp_inst_deinit(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_cvp_buffer *cbuf, *temp; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + + rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE); + if (rc) + s_vpr_e(inst->sid, "%s: close failed\n", __func__); + + mutex_lock(&inst->cvpbufs.lock); + list_for_each_entry_safe(cbuf, temp, &inst->cvpbufs.list, list) { + print_cvp_buffer(VIDC_ERR, "unregistered", inst, cbuf); + rc = inst->smem_ops->smem_unmap_dma_buf(inst, &cbuf->smem); + if (rc) + s_vpr_e(inst->sid, "%s: unmap failed\n", __func__); + list_del(&cbuf->list); + kfree(cbuf); + } + mutex_unlock(&inst->cvpbufs.lock); + + inst->clk_data.min_freq = 0; + inst->clk_data.ddr_bw = 0; + inst->clk_data.sys_cache_bw = 0; + rc = msm_cvp_scale_clocks_and_bus(inst); + if (rc) + s_vpr_e(inst->sid, "%s: failed to scale_clocks_and_bus\n", + __func__); + + return rc; +} + +int msm_cvp_inst_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + + /* set default frequency */ + inst->clk_data.core_id = VIDC_CORE_ID_2; + inst->clk_data.min_freq = 1000; + inst->clk_data.ddr_bw = 1000; + inst->clk_data.sys_cache_bw = 1000; + + return rc; +} diff --git a/techpack/video/msm/vidc/msm_cvp_internal.h b/techpack/video/msm/vidc/msm_cvp_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..1a6f4ce63476055b9982bcfe299e2c56ba8b6ed2 --- /dev/null +++ b/techpack/video/msm/vidc/msm_cvp_internal.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_CVP_INTERNAL_H_ +#define _MSM_CVP_INTERNAL_H_ + +#include "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "msm_vidc_clocks.h" +#include "msm_vidc_debug.h" + +void handle_session_register_buffer_done(enum hal_command_response cmd, + void *resp); +void handle_session_unregister_buffer_done(enum hal_command_response cmd, + void *resp); +int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg); +int msm_cvp_inst_init(struct msm_vidc_inst *inst); +int msm_cvp_inst_deinit(struct msm_vidc_inst *inst); +int msm_cvp_inst_pause(struct msm_vidc_inst *inst); +int msm_cvp_inst_resume(struct msm_vidc_inst *inst); +int msm_cvp_ctrl_init(struct msm_vidc_inst *inst, + const struct v4l2_ctrl_ops *ctrl_ops); +#endif diff --git a/techpack/video/msm/vidc/msm_smem.c b/techpack/video/msm/vidc/msm_smem.c new file mode 100644 index 0000000000000000000000000000000000000000..33e89fbf7b17f4fc208fa011f6b16688042c08fe --- /dev/null +++ b/techpack/video/msm/vidc/msm_smem.c @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <asm/dma-iommu.h> +#include <linux/dma-buf.h> +#include <linux/dma-direction.h> +#include <linux/iommu.h> +#include <linux/msm_dma_iommu_mapping.h> +#include <linux/msm_ion.h> +#include <linux/ion_kernel.h> +#include <linux/slab.h> +#include <linux/types.h> +#include "msm_vidc.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_resources.h" + + +static int msm_dma_get_device_address(struct dma_buf *dbuf, unsigned long align, + dma_addr_t *iova, unsigned long *buffer_size, + unsigned long flags, enum hal_buffer buffer_type, + unsigned long session_type, struct msm_vidc_platform_resources *res, + struct dma_mapping_info *mapping_info, u32 sid) +{ + int rc = 0; + struct dma_buf_attachment *attach; + struct sg_table *table = NULL; + struct context_bank_info *cb = NULL; + + if (!dbuf || !iova || !buffer_size || !mapping_info) { + s_vpr_e(sid, "%s: invalid params: %pK, %pK, %pK, %pK\n", + __func__, dbuf, iova, buffer_size, mapping_info); + return -EINVAL; + } + + if (is_iommu_present(res)) { + cb = msm_smem_get_context_bank( + session_type, (flags & SMEM_SECURE), + res, buffer_type, sid); + if (!cb) { + s_vpr_e(sid, "%s: Failed to get context bank device\n", + __func__); + rc = -EIO; + goto mem_map_failed; + } + + /* Check if the dmabuf size matches expected size */ + if (dbuf->size < *buffer_size) { + rc = -EINVAL; + s_vpr_e(sid, + "Size mismatch: Dmabuf size: %zu Expected Size: %lu", + dbuf->size, *buffer_size); + msm_vidc_res_handle_fatal_hw_error(res, + true); + goto mem_buf_size_mismatch; + } + + /* Prepare a dma buf for dma on the given device */ + attach = dma_buf_attach(dbuf, cb->dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach) ? PTR_ERR(attach) : -ENOMEM; + s_vpr_e(sid, "Failed to attach dmabuf\n"); + goto mem_buf_attach_failed; + } + + /* + * Get the scatterlist for the given attachment + * Mapping of sg is taken care by map attachment + */ + attach->dma_map_attrs = DMA_ATTR_DELAYED_UNMAP; + /* + * We do not need dma_map function to perform cache operations + * on the whole buffer size and hence pass skip sync flag. + * We do the required cache operations separately for the + * required buffer size + */ + attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + if (res->sys_cache_present) + attach->dma_map_attrs |= + DMA_ATTR_IOMMU_USE_UPSTREAM_HINT; + + table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table) ? PTR_ERR(table) : -ENOMEM; + s_vpr_e(sid, "Failed to map table\n"); + goto mem_map_table_failed; + } + + /* debug trace's need to be updated later */ + trace_msm_smem_buffer_iommu_op_start("MAP", 0, 0, + align, *iova, *buffer_size); + + if (table->sgl) { + *iova = table->sgl->dma_address; + *buffer_size = table->sgl->dma_length; + } else { + s_vpr_e(sid, "sgl is NULL\n"); + rc = -ENOMEM; + goto mem_map_sg_failed; + } + + mapping_info->dev = cb->dev; + mapping_info->domain = cb->domain; + mapping_info->table = table; + mapping_info->attach = attach; + mapping_info->buf = dbuf; + mapping_info->cb_info = (void *)cb; + + trace_msm_smem_buffer_iommu_op_end("MAP", 0, 0, + align, *iova, *buffer_size); + } else { + s_vpr_h(sid, "iommu not present, use phys mem addr\n"); + } + + return 0; +mem_map_sg_failed: + dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL); +mem_map_table_failed: + dma_buf_detach(dbuf, attach); +mem_buf_size_mismatch: +mem_buf_attach_failed: +mem_map_failed: + return rc; +} + +static int msm_dma_put_device_address(u32 flags, + struct dma_mapping_info *mapping_info, + enum hal_buffer buffer_type, u32 sid) +{ + int rc = 0; + struct sg_table *table = NULL; + dma_addr_t iova; + unsigned long buffer_size; + + if (!mapping_info) { + s_vpr_e(sid, "Invalid mapping_info\n"); + return -EINVAL; + } + + if (!mapping_info->dev || !mapping_info->table || + !mapping_info->buf || !mapping_info->attach || + !mapping_info->cb_info) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return -EINVAL; + } + + table = mapping_info->table; + iova = table->sgl->dma_address; + buffer_size = table->sgl->dma_length; + trace_msm_smem_buffer_iommu_op_start("UNMAP", 0, 0, + 0, iova, buffer_size); + dma_buf_unmap_attachment(mapping_info->attach, + mapping_info->table, DMA_BIDIRECTIONAL); + dma_buf_detach(mapping_info->buf, mapping_info->attach); + trace_msm_smem_buffer_iommu_op_end("UNMAP", 0, 0, 0, 0, 0); + + mapping_info->dev = NULL; + mapping_info->domain = NULL; + mapping_info->table = NULL; + mapping_info->attach = NULL; + mapping_info->buf = NULL; + mapping_info->cb_info = NULL; + + return rc; +} + +struct dma_buf *msm_smem_get_dma_buf(int fd, u32 sid) +{ + struct dma_buf *dma_buf; + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + s_vpr_e(sid, "Failed to get dma_buf for %d, error %ld\n", + fd, PTR_ERR(dma_buf)); + dma_buf = NULL; + } + + return dma_buf; +} + +void msm_smem_put_dma_buf(void *dma_buf, u32 sid) +{ + if (!dma_buf) { + s_vpr_e(sid, "%s: NULL dma_buf\n", __func__); + return; + } + + dma_buf_put((struct dma_buf *)dma_buf); +} + +int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem) +{ + int rc = 0; + + dma_addr_t iova = 0; + u32 temp = 0; + unsigned long buffer_size = 0; + unsigned long align = SZ_4K; + struct dma_buf *dbuf; + unsigned long ion_flags = 0; + u32 b_type = HAL_BUFFER_INPUT | HAL_BUFFER_OUTPUT | HAL_BUFFER_OUTPUT2; + + if (!inst || !smem) { + d_vpr_e("%s: invalid params: %pK %pK\n", + __func__, inst, smem); + rc = -EINVAL; + goto exit; + } + + if (smem->refcount) { + smem->refcount++; + goto exit; + } + + dbuf = msm_smem_get_dma_buf(smem->fd, inst->sid); + if (!dbuf) { + rc = -EINVAL; + goto exit; + } + + smem->dma_buf = dbuf; + + rc = dma_buf_get_flags(dbuf, &ion_flags); + if (rc) { + s_vpr_e(inst->sid, "Failed to get dma buf flags: %d\n", rc); + goto exit; + } + if (ion_flags & ION_FLAG_CACHED) + smem->flags |= SMEM_CACHED; + + if (ion_flags & ION_FLAG_SECURE) + smem->flags |= SMEM_SECURE; + + if ((smem->buffer_type & b_type) && + !!(smem->flags & SMEM_SECURE) ^ !!(inst->flags & VIDC_SECURE)) { + s_vpr_e(inst->sid, "Failed to map %s buffer with %s session\n", + smem->flags & SMEM_SECURE ? "secure" : "non-secure", + inst->flags & VIDC_SECURE ? "secure" : "non-secure"); + rc = -EINVAL; + goto exit; + } + buffer_size = smem->size; + + rc = msm_dma_get_device_address(dbuf, align, &iova, &buffer_size, + smem->flags, smem->buffer_type, inst->session_type, + &(inst->core->resources), &smem->mapping_info, + inst->sid); + if (rc) { + s_vpr_e(inst->sid, "Failed to get device address: %d\n", rc); + goto exit; + } + temp = (u32)iova; + if ((dma_addr_t)temp != iova) { + s_vpr_e(inst->sid, "iova(%pa) truncated to %#x", &iova, temp); + rc = -EINVAL; + goto exit; + } + + smem->device_addr = (u32)iova + smem->offset; + + smem->refcount++; +exit: + return rc; +} + +int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem) +{ + int rc = 0; + + if (!inst || !smem) { + d_vpr_e("%s: invalid params: %pK %pK\n", + __func__, inst, smem); + rc = -EINVAL; + goto exit; + } + + if (smem->refcount) { + smem->refcount--; + } else { + s_vpr_e(inst->sid, + "unmap called while refcount is zero already\n"); + return -EINVAL; + } + + if (smem->refcount) + goto exit; + + rc = msm_dma_put_device_address(smem->flags, &smem->mapping_info, + smem->buffer_type, inst->sid); + if (rc) { + s_vpr_e(inst->sid, "Failed to put device address: %d\n", rc); + goto exit; + } + + msm_smem_put_dma_buf(smem->dma_buf, inst->sid); + + smem->device_addr = 0x0; + smem->dma_buf = NULL; + +exit: + return rc; +} + +static int get_secure_flag_for_buffer_type( + u32 session_type, enum hal_buffer buffer_type) +{ + switch (buffer_type) { + case HAL_BUFFER_INPUT: + if (session_type == MSM_VIDC_ENCODER) + return ION_FLAG_CP_PIXEL; + else + return ION_FLAG_CP_BITSTREAM; + case HAL_BUFFER_OUTPUT: + case HAL_BUFFER_OUTPUT2: + if (session_type == MSM_VIDC_ENCODER) + return ION_FLAG_CP_BITSTREAM; + else + return ION_FLAG_CP_PIXEL; + case HAL_BUFFER_INTERNAL_SCRATCH: + return ION_FLAG_CP_BITSTREAM; + case HAL_BUFFER_INTERNAL_SCRATCH_1: + return ION_FLAG_CP_NON_PIXEL; + case HAL_BUFFER_INTERNAL_SCRATCH_2: + return ION_FLAG_CP_PIXEL; + case HAL_BUFFER_INTERNAL_PERSIST: + if (session_type == MSM_VIDC_ENCODER) + return ION_FLAG_CP_NON_PIXEL; + else + return ION_FLAG_CP_BITSTREAM; + case HAL_BUFFER_INTERNAL_PERSIST_1: + return ION_FLAG_CP_NON_PIXEL; + default: + WARN(1, "No matching secure flag for buffer type : %x\n", + buffer_type); + return -EINVAL; + } +} + +static int alloc_dma_mem(size_t size, u32 align, u32 flags, + enum hal_buffer buffer_type, int map_kernel, + struct msm_vidc_platform_resources *res, u32 session_type, + struct msm_smem *mem, u32 sid) +{ + dma_addr_t iova = 0; + unsigned long buffer_size = 0; + unsigned long heap_mask = 0; + int rc = 0; + int ion_flags = 0; + struct dma_buf *dbuf = NULL; + + if (!res) { + s_vpr_e(sid, "%s: NULL res\n", __func__); + return -EINVAL; + } + + align = ALIGN(align, SZ_4K); + size = ALIGN(size, SZ_4K); + + if (is_iommu_present(res)) { + if (flags & SMEM_ADSP) { + s_vpr_h(sid, "Allocating from ADSP heap\n"); + heap_mask = ION_HEAP(ION_ADSP_HEAP_ID); + } else { + heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID); + } + } else { + s_vpr_h(sid, + "allocate shared memory from adsp heap size %zx align %d\n", + size, align); + heap_mask = ION_HEAP(ION_ADSP_HEAP_ID); + } + + if (flags & SMEM_CACHED) + ion_flags |= ION_FLAG_CACHED; + + if ((flags & SMEM_SECURE) || + (buffer_type == HAL_BUFFER_INTERNAL_PERSIST && + session_type == MSM_VIDC_ENCODER)) { + int secure_flag = + get_secure_flag_for_buffer_type( + session_type, buffer_type); + if (secure_flag < 0) { + rc = secure_flag; + goto fail_shared_mem_alloc; + } + + ion_flags |= ION_FLAG_SECURE | secure_flag; + heap_mask = ION_HEAP(ION_SECURE_HEAP_ID); + + if (res->slave_side_cp) { + heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID); + size = ALIGN(size, SZ_1M); + align = ALIGN(size, SZ_1M); + } + flags |= SMEM_SECURE; + } + + trace_msm_smem_buffer_dma_op_start("ALLOC", (u32)buffer_type, + heap_mask, size, align, flags, map_kernel); + dbuf = ion_alloc(size, heap_mask, ion_flags); + if (IS_ERR_OR_NULL(dbuf)) { + s_vpr_e(sid, "Failed to allocate shared memory = %zx, %#x\n", + size, flags); + rc = -ENOMEM; + goto fail_shared_mem_alloc; + } + trace_msm_smem_buffer_dma_op_end("ALLOC", (u32)buffer_type, + heap_mask, size, align, flags, map_kernel); + + mem->flags = flags; + mem->buffer_type = buffer_type; + mem->offset = 0; + mem->size = size; + mem->dma_buf = dbuf; + mem->kvaddr = NULL; + + rc = msm_dma_get_device_address(dbuf, align, &iova, + &buffer_size, flags, buffer_type, + session_type, res, &mem->mapping_info, sid); + if (rc) { + s_vpr_e(sid, "Failed to get device address: %d\n", + rc); + goto fail_device_address; + } + mem->device_addr = (u32)iova; + if ((dma_addr_t)mem->device_addr != iova) { + s_vpr_e(sid, "iova(%pa) truncated to %#x", + &iova, mem->device_addr); + goto fail_device_address; + } + + if (map_kernel) { + dma_buf_begin_cpu_access(dbuf, DMA_BIDIRECTIONAL); + mem->kvaddr = dma_buf_vmap(dbuf); + if (!mem->kvaddr) { + s_vpr_e(sid, "Failed to map shared mem in kernel\n"); + rc = -EIO; + goto fail_map; + } + } + + s_vpr_h(sid, + "%s: dma_buf = %pK, device_addr = %x, size = %d, kvaddr = %pK, buffer_type = %#x, flags = %#lx\n", + __func__, mem->dma_buf, mem->device_addr, mem->size, + mem->kvaddr, mem->buffer_type, mem->flags); + return rc; + +fail_map: + if (map_kernel) + dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL); +fail_device_address: + dma_buf_put(dbuf); +fail_shared_mem_alloc: + return rc; +} + +static int free_dma_mem(struct msm_smem *mem, u32 sid) +{ + s_vpr_h(sid, + "%s: dma_buf = %pK, device_addr = %x, size = %d, kvaddr = %pK, buffer_type = %#x\n", + __func__, mem->dma_buf, mem->device_addr, mem->size, + mem->kvaddr, mem->buffer_type); + + if (mem->device_addr) { + msm_dma_put_device_address(mem->flags, + &mem->mapping_info, mem->buffer_type, sid); + mem->device_addr = 0x0; + } + + if (mem->kvaddr) { + dma_buf_vunmap(mem->dma_buf, mem->kvaddr); + mem->kvaddr = NULL; + dma_buf_end_cpu_access(mem->dma_buf, DMA_BIDIRECTIONAL); + } + + if (mem->dma_buf) { + trace_msm_smem_buffer_dma_op_start("FREE", + (u32)mem->buffer_type, -1, mem->size, -1, + mem->flags, -1); + dma_buf_put(mem->dma_buf); + mem->dma_buf = NULL; + trace_msm_smem_buffer_dma_op_end("FREE", (u32)mem->buffer_type, + -1, mem->size, -1, mem->flags, -1); + } + + return 0; +} + +int msm_smem_alloc(size_t size, u32 align, u32 flags, + enum hal_buffer buffer_type, int map_kernel, + void *res, u32 session_type, struct msm_smem *smem, u32 sid) +{ + int rc = 0; + + if (!smem || !size) { + s_vpr_e(sid, "%s: NULL smem or %d size\n", + __func__, (u32)size); + return -EINVAL; + } + + rc = alloc_dma_mem(size, align, flags, buffer_type, map_kernel, + (struct msm_vidc_platform_resources *)res, + session_type, smem, sid); + + return rc; +} + +int msm_smem_free(struct msm_smem *smem, u32 sid) +{ + int rc = 0; + + if (!smem) { + s_vpr_e(sid, "NULL smem passed\n"); + return -EINVAL; + } + rc = free_dma_mem(smem, sid); + + return rc; +}; + +int msm_smem_cache_operations(struct dma_buf *dbuf, + enum smem_cache_ops cache_op, unsigned long offset, + unsigned long size, u32 sid) +{ + int rc = 0; + unsigned long flags = 0; + + if (!dbuf) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return -EINVAL; + } + + /* Return if buffer doesn't support caching */ + rc = dma_buf_get_flags(dbuf, &flags); + if (rc) { + s_vpr_e(sid, "%s: dma_buf_get_flags failed, err %d\n", + __func__, rc); + return rc; + } else if (!(flags & ION_FLAG_CACHED)) { + return rc; + } + + switch (cache_op) { + case SMEM_CACHE_CLEAN: + case SMEM_CACHE_CLEAN_INVALIDATE: + rc = dma_buf_begin_cpu_access_partial(dbuf, DMA_TO_DEVICE, + offset, size); + if (rc) + break; + rc = dma_buf_end_cpu_access_partial(dbuf, DMA_TO_DEVICE, + offset, size); + break; + case SMEM_CACHE_INVALIDATE: + rc = dma_buf_begin_cpu_access_partial(dbuf, DMA_TO_DEVICE, + offset, size); + if (rc) + break; + rc = dma_buf_end_cpu_access_partial(dbuf, DMA_FROM_DEVICE, + offset, size); + break; + default: + s_vpr_e(sid, "%s: cache (%d) operation not supported\n", + __func__, cache_op); + rc = -EINVAL; + break; + } + + return rc; +} + +struct context_bank_info *msm_smem_get_context_bank(u32 session_type, + bool is_secure, struct msm_vidc_platform_resources *res, + enum hal_buffer buffer_type, u32 sid) +{ + struct context_bank_info *cb = NULL, *match = NULL; + + /* + * HAL_BUFFER_INPUT is directly mapped to bitstream CB in DT + * as the buffer type structure was initially designed + * just for decoder. For Encoder, input should be mapped to + * yuvpixel CB. Persist is mapped to nonpixel CB. + * So swap the buffer types just in this local scope. + */ + if (is_secure && session_type == MSM_VIDC_ENCODER) { + if (buffer_type == HAL_BUFFER_INPUT) + buffer_type = HAL_BUFFER_OUTPUT; + else if (buffer_type == HAL_BUFFER_OUTPUT) + buffer_type = HAL_BUFFER_INPUT; + else if (buffer_type == HAL_BUFFER_INTERNAL_PERSIST) + buffer_type = HAL_BUFFER_INTERNAL_PERSIST_1; + } + + mutex_lock(&res->cb_lock); + list_for_each_entry(cb, &res->context_banks, list) { + if (cb->is_secure == is_secure && + cb->buffer_type & buffer_type) { + match = cb; + break; + } + } + mutex_unlock(&res->cb_lock); + if (!match) + s_vpr_e(sid, + "%s: cb not found for buffer_type %x, is_secure %d\n", + __func__, buffer_type, is_secure); + + return match; +} + diff --git a/techpack/video/msm/vidc/msm_v4l2_private.c b/techpack/video/msm/vidc/msm_v4l2_private.c new file mode 100644 index 0000000000000000000000000000000000000000..f7428e4fb9e97786f2830360272285670efcf12d --- /dev/null +++ b/techpack/video/msm/vidc/msm_v4l2_private.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + */ + +#include "msm_v4l2_private.h" + +static int convert_from_user(struct msm_vidc_arg *kp, unsigned long arg) +{ + int rc = 0; + int i; + struct msm_vidc_arg __user *up = (struct msm_vidc_arg *)arg; + + if (!kp || !up) { + d_vpr_e("%s: invalid params%pK %pK\n", __func__, kp, up); + return -EINVAL; + } + + if (get_user(kp->type, &up->type)) + return -EFAULT; + + switch (kp->type) { + case MSM_CVP_GET_SESSION_INFO: + { + struct msm_cvp_session_info *k, *u; + + k = &kp->data.session; + u = &up->data.session; + if (get_user(k->session_id, &u->session_id)) + return -EFAULT; + for (i = 0; i < 10; i++) + if (get_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + case MSM_CVP_REQUEST_POWER: + { + struct msm_cvp_request_power *k, *u; + + k = &kp->data.req_power; + u = &up->data.req_power; + if (get_user(k->clock_cycles_a, &u->clock_cycles_a) || + get_user(k->clock_cycles_b, &u->clock_cycles_b) || + get_user(k->ddr_bw, &u->ddr_bw) || + get_user(k->sys_cache_bw, &u->sys_cache_bw)) + return -EFAULT; + for (i = 0; i < 8; i++) + if (get_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + case MSM_CVP_REGISTER_BUFFER: + { + struct msm_cvp_buffer *k, *u; + + k = &kp->data.regbuf; + u = &up->data.regbuf; + if (get_user(k->type, &u->type) || + get_user(k->index, &u->index) || + get_user(k->fd, &u->fd) || + get_user(k->size, &u->size) || + get_user(k->offset, &u->offset) || + get_user(k->pixelformat, &u->pixelformat) || + get_user(k->flags, &u->flags)) + return -EFAULT; + for (i = 0; i < 5; i++) + if (get_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + case MSM_CVP_UNREGISTER_BUFFER: + { + struct msm_cvp_buffer *k, *u; + + k = &kp->data.unregbuf; + u = &up->data.unregbuf; + if (get_user(k->type, &u->type) || + get_user(k->index, &u->index) || + get_user(k->fd, &u->fd) || + get_user(k->size, &u->size) || + get_user(k->offset, &u->offset) || + get_user(k->pixelformat, &u->pixelformat) || + get_user(k->flags, &u->flags)) + return -EFAULT; + for (i = 0; i < 5; i++) + if (get_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + default: + d_vpr_e("%s: unknown cmd type 0x%x\n", + __func__, kp->type); + rc = -EINVAL; + break; + } + + return rc; +} + +static int convert_to_user(struct msm_vidc_arg *kp, unsigned long arg) +{ + int rc = 0; + int i; + struct msm_vidc_arg __user *up = (struct msm_vidc_arg *)arg; + + if (!kp || !up) { + d_vpr_e("%s: invalid params %pK %pK\n", __func__, kp, up); + return -EINVAL; + } + + if (put_user(kp->type, &up->type)) + return -EFAULT; + + switch (kp->type) { + case MSM_CVP_GET_SESSION_INFO: + { + struct msm_cvp_session_info *k, *u; + + k = &kp->data.session; + u = &up->data.session; + if (put_user(k->session_id, &u->session_id)) + return -EFAULT; + for (i = 0; i < 10; i++) + if (put_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + case MSM_CVP_REQUEST_POWER: + { + struct msm_cvp_request_power *k, *u; + + k = &kp->data.req_power; + u = &up->data.req_power; + if (put_user(k->clock_cycles_a, &u->clock_cycles_a) || + put_user(k->clock_cycles_b, &u->clock_cycles_b) || + put_user(k->ddr_bw, &u->ddr_bw) || + put_user(k->sys_cache_bw, &u->sys_cache_bw)) + return -EFAULT; + for (i = 0; i < 8; i++) + if (put_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + case MSM_CVP_REGISTER_BUFFER: + { + struct msm_cvp_buffer *k, *u; + + k = &kp->data.regbuf; + u = &up->data.regbuf; + if (put_user(k->type, &u->type) || + put_user(k->index, &u->index) || + put_user(k->fd, &u->fd) || + put_user(k->size, &u->size) || + put_user(k->offset, &u->offset) || + put_user(k->pixelformat, &u->pixelformat) || + put_user(k->flags, &u->flags)) + return -EFAULT; + for (i = 0; i < 5; i++) + if (put_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + case MSM_CVP_UNREGISTER_BUFFER: + { + struct msm_cvp_buffer *k, *u; + + k = &kp->data.unregbuf; + u = &up->data.unregbuf; + if (put_user(k->type, &u->type) || + put_user(k->index, &u->index) || + put_user(k->fd, &u->fd) || + put_user(k->size, &u->size) || + put_user(k->offset, &u->offset) || + put_user(k->pixelformat, &u->pixelformat) || + put_user(k->flags, &u->flags)) + return -EFAULT; + for (i = 0; i < 5; i++) + if (put_user(k->reserved[i], &u->reserved[i])) + return -EFAULT; + break; + } + default: + d_vpr_e("%s: unknown cmd type 0x%x\n", __func__, kp->type); + rc = -EINVAL; + break; + } + + return rc; +} + +long msm_v4l2_private(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int rc; + struct msm_vidc_inst *inst; + struct msm_vidc_arg karg; + + if (!filp || !filp->private_data) { + d_vpr_e("%s: invalid params %pK\n", __func__, filp); + return -EINVAL; + } + + inst = container_of(filp->private_data, struct msm_vidc_inst, + event_handler); + memset(&karg, 0, sizeof(struct msm_vidc_arg)); + + /* + * the arg points to user space memory and needs + * to be converted to kernel space before using it. + * Check do_video_ioctl() for more details. + */ + if (convert_from_user(&karg, arg)) + return -EFAULT; + + rc = msm_vidc_private((void *)inst, cmd, &karg); + if (rc) { + d_vpr_e("%s: failed cmd type %x\n", __func__, karg.type); + return -EINVAL; + } + + if (convert_to_user(&karg, arg)) + return -EFAULT; + + return rc; +} diff --git a/techpack/video/msm/vidc/msm_v4l2_private.h b/techpack/video/msm/vidc/msm_v4l2_private.h new file mode 100644 index 0000000000000000000000000000000000000000..5f1602aca410488f871f905fa1faefcb3a348228 --- /dev/null +++ b/techpack/video/msm/vidc/msm_v4l2_private.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_V4L2_PRIVATE_H_ +#define _MSM_V4L2_PRIVATE_H_ + +#include <media/msm_vidc_private.h> +#include "msm_vidc_debug.h" + +long msm_v4l2_private(struct file *file, unsigned int cmd, unsigned long arg); + +#endif diff --git a/techpack/video/msm/vidc/msm_v4l2_vidc.c b/techpack/video/msm/vidc/msm_v4l2_vidc.c new file mode 100644 index 0000000000000000000000000000000000000000..0fd761e87343874f15449bfc4124eafcc4037503 --- /dev/null +++ b/techpack/video/msm/vidc/msm_v4l2_vidc.c @@ -0,0 +1,800 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/ioctl.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/io.h> +#include "msm_vidc.h" +#include "msm_vidc_common.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_res_parse.h" +#include "msm_vidc_resources.h" +#include "vidc_hfi_api.h" +#include "msm_v4l2_private.h" +#include "msm_vidc_clocks.h" + +#define BASE_DEVICE_NUMBER 32 + +struct msm_vidc_drv *vidc_driver; + + +static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh) +{ + if (!filp->private_data) + return NULL; + return container_of(filp->private_data, + struct msm_vidc_inst, event_handler); +} + +static int msm_v4l2_open(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct msm_video_device *vid_dev = + container_of(vdev, struct msm_video_device, vdev); + struct msm_vidc_core *core = video_drvdata(filp); + struct msm_vidc_inst *vidc_inst; + + trace_msm_v4l2_vidc_open_start("msm v4l2_open start"); + vidc_inst = msm_vidc_open(core->id, vid_dev->type); + if (!vidc_inst) { + d_vpr_e("Failed to create instance, core: %d, type = %d\n", + core->id, vid_dev->type); + return -ENOMEM; + } + clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags); + filp->private_data = &(vidc_inst->event_handler); + trace_msm_v4l2_vidc_open_end("msm v4l2_open end"); + return 0; +} + +static int msm_v4l2_close(struct file *filp) +{ + int rc = 0; + struct msm_vidc_inst *vidc_inst; + + trace_msm_v4l2_vidc_close_start("msm v4l2_close start"); + vidc_inst = get_vidc_inst(filp, NULL); + + rc = msm_vidc_close(vidc_inst); + filp->private_data = NULL; + trace_msm_v4l2_vidc_close_end("msm v4l2_close end"); + return rc; +} + +static int msm_v4l2_querycap(struct file *filp, void *fh, + struct v4l2_capability *cap) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh); + + return msm_vidc_querycap((void *)vidc_inst, cap); +} + +int msm_v4l2_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_enum_fmt((void *)vidc_inst, f); +} + +int msm_v4l2_s_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_s_fmt((void *)vidc_inst, f); +} + +int msm_v4l2_g_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_g_fmt((void *)vidc_inst, f); +} + +int msm_v4l2_s_ctrl(struct file *file, void *fh, + struct v4l2_control *a) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_s_ctrl((void *)vidc_inst, a); +} + +int msm_v4l2_g_ctrl(struct file *file, void *fh, + struct v4l2_control *a) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_g_ctrl((void *)vidc_inst, a); +} + +int msm_v4l2_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *b) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_reqbufs((void *)vidc_inst, b); +} + +int msm_v4l2_qbuf(struct file *file, void *fh, + struct v4l2_buffer *b) +{ + return msm_vidc_qbuf(get_vidc_inst(file, fh), b); +} + +int msm_v4l2_dqbuf(struct file *file, void *fh, + struct v4l2_buffer *b) +{ + return msm_vidc_dqbuf(get_vidc_inst(file, fh), b); +} + +int msm_v4l2_streamon(struct file *file, void *fh, + enum v4l2_buf_type i) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_streamon((void *)vidc_inst, i); +} + +int msm_v4l2_streamoff(struct file *file, void *fh, + enum v4l2_buf_type i) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_streamoff((void *)vidc_inst, i); +} + +static int msm_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct msm_vidc_inst *vidc_inst = container_of(fh, + struct msm_vidc_inst, event_handler); + + return msm_vidc_subscribe_event((void *)vidc_inst, sub); +} + +static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct msm_vidc_inst *vidc_inst = container_of(fh, + struct msm_vidc_inst, event_handler); + + return msm_vidc_unsubscribe_event((void *)vidc_inst, sub); +} + +static int msm_v4l2_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dec) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)dec); +} + +static int msm_v4l2_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)enc); +} + +static int msm_v4l2_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_enum_framesizes((void *)vidc_inst, fsize); +} + +static int msm_v4l2_queryctrl(struct file *file, void *fh, + struct v4l2_queryctrl *ctrl) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_query_ctrl((void *)vidc_inst, ctrl); +} + +static int msm_v4l2_querymenu(struct file *file, void *fh, + struct v4l2_querymenu *qmenu) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_query_menu((void *)vidc_inst, qmenu); +} + +static long msm_v4l2_default(struct file *file, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_private((void *)vidc_inst, cmd, arg); +} + + +const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = { + .vidioc_querycap = msm_v4l2_querycap, + .vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt, + .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt, + .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt, + .vidioc_reqbufs = msm_v4l2_reqbufs, + .vidioc_qbuf = msm_v4l2_qbuf, + .vidioc_dqbuf = msm_v4l2_dqbuf, + .vidioc_streamon = msm_v4l2_streamon, + .vidioc_streamoff = msm_v4l2_streamoff, + .vidioc_s_ctrl = msm_v4l2_s_ctrl, + .vidioc_g_ctrl = msm_v4l2_g_ctrl, + .vidioc_queryctrl = msm_v4l2_queryctrl, + .vidioc_querymenu = msm_v4l2_querymenu, + .vidioc_subscribe_event = msm_v4l2_subscribe_event, + .vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event, + .vidioc_decoder_cmd = msm_v4l2_decoder_cmd, + .vidioc_encoder_cmd = msm_v4l2_encoder_cmd, + .vidioc_enum_framesizes = msm_v4l2_enum_framesizes, + .vidioc_default = msm_v4l2_default, +}; + +static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = { 0 }; + +static unsigned int msm_v4l2_poll(struct file *filp, + struct poll_table_struct *pt) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL); + + return msm_vidc_poll((void *)vidc_inst, filp, pt); +} + +static const struct v4l2_file_operations msm_v4l2_vidc_fops = { + .owner = THIS_MODULE, + .open = msm_v4l2_open, + .release = msm_v4l2_close, + .unlocked_ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = msm_v4l2_private, +#endif + .poll = msm_v4l2_poll, +}; + +void msm_vidc_release_video_device(struct video_device *pvdev) +{ +} + +static int read_platform_resources(struct msm_vidc_core *core, + struct platform_device *pdev) +{ + int rc = 0; + + if (!core || !pdev) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, core, pdev); + return -EINVAL; + } + core->hfi_type = VIDC_HFI_VENUS; + core->resources.pdev = pdev; + if (pdev->dev.of_node) { + /* Target supports DT, parse from it */ + rc = read_platform_resources_from_drv_data(core); + rc = read_platform_resources_from_dt(&core->resources); + } else { + d_vpr_e("pdev node is NULL\n"); + rc = -EINVAL; + } + return rc; +} + +static int msm_vidc_initialize_core(struct platform_device *pdev, + struct msm_vidc_core *core) +{ + int i = 0; + int rc = 0; + + if (!core) + return -EINVAL; + rc = read_platform_resources(core, pdev); + if (rc) { + d_vpr_e("Failed to get platform resources\n"); + return rc; + } + + INIT_LIST_HEAD(&core->instances); + mutex_init(&core->lock); + mutex_init(&core->resources.cb_lock); + + core->state = VIDC_CORE_UNINIT; + for (i = SYS_MSG_INDEX(SYS_MSG_START); + i <= SYS_MSG_INDEX(SYS_MSG_END); i++) { + init_completion(&core->completions[i]); + } + + INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler); + INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler); + + msm_vidc_init_core_clk_ops(core); + return rc; +} + +static ssize_t link_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct msm_vidc_core *core = dev_get_drvdata(dev); + + if (core) + if (dev == &core->vdev[MSM_VIDC_DECODER].vdev.dev) + return snprintf(buf, PAGE_SIZE, "venus_dec"); + else if (dev == &core->vdev[MSM_VIDC_ENCODER].vdev.dev) + return snprintf(buf, PAGE_SIZE, "venus_enc"); + else if (dev == &core->vdev[MSM_VIDC_CVP].vdev.dev) + return snprintf(buf, PAGE_SIZE, "venus_cvp"); + else + return 0; + else + return 0; +} + +static DEVICE_ATTR_RO(link_name); + +static ssize_t pwr_collapse_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val = 0; + int rc = 0; + struct msm_vidc_core *core = NULL; + + rc = kstrtoul(buf, 0, &val); + if (rc) + return rc; + else if (!val) + return -EINVAL; + + core = get_vidc_core(MSM_VIDC_CORE_VENUS); + if (!core) + return -EINVAL; + core->resources.msm_vidc_pwr_collapse_delay = val; + return count; +} + +static ssize_t pwr_collapse_delay_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct msm_vidc_core *core = NULL; + + core = get_vidc_core(MSM_VIDC_CORE_VENUS); + if (!core) + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%u\n", + core->resources.msm_vidc_pwr_collapse_delay); +} + +static DEVICE_ATTR_RW(pwr_collapse_delay); + +static ssize_t thermal_level_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level); +} + +static ssize_t thermal_level_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc = 0, val = 0; + + rc = kstrtoint(buf, 0, &val); + if (rc || val < 0) { + d_vpr_e("Invalid thermal level value: %s\n", buf); + return -EINVAL; + } + d_vpr_h("Thermal level old %d new %d\n", + vidc_driver->thermal_level, val); + + if (val == vidc_driver->thermal_level) + return count; + vidc_driver->thermal_level = val; + + msm_comm_handle_thermal_event(); + return count; +} + +static DEVICE_ATTR_RW(thermal_level); + +static ssize_t sku_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d", + vidc_driver->sku_version); +} + +static DEVICE_ATTR_RO(sku_version); + +static struct attribute *msm_vidc_core_attrs[] = { + &dev_attr_pwr_collapse_delay.attr, + &dev_attr_thermal_level.attr, + &dev_attr_sku_version.attr, + NULL +}; + +static struct attribute_group msm_vidc_core_attr_group = { + .attrs = msm_vidc_core_attrs, +}; + +static const struct of_device_id msm_vidc_dt_match[] = { + {.compatible = "qcom,msm-vidc"}, + {.compatible = "qcom,msm-vidc,context-bank"}, + {.compatible = "qcom,msm-vidc,bus"}, + {.compatible = "qcom,msm-vidc,mem-cdsp"}, + {} +}; + +static int msm_vidc_register_video_device(enum session_type sess_type, + int nr, struct msm_vidc_core *core, struct device *dev) +{ + int rc = 0; + + core->vdev[sess_type].vdev.release = + msm_vidc_release_video_device; + core->vdev[sess_type].vdev.fops = &msm_v4l2_vidc_fops; + core->vdev[sess_type].vdev.ioctl_ops = &msm_v4l2_ioctl_ops; + core->vdev[sess_type].vdev.vfl_dir = VFL_DIR_M2M; + core->vdev[sess_type].type = sess_type; + core->vdev[sess_type].vdev.v4l2_dev = &core->v4l2_dev; + rc = video_register_device(&core->vdev[sess_type].vdev, + VFL_TYPE_GRABBER, nr); + if (rc) { + d_vpr_e("Failed to register the video device\n"); + return rc; + } + video_set_drvdata(&core->vdev[sess_type].vdev, core); + dev = &core->vdev[sess_type].vdev.dev; + rc = device_create_file(dev, &dev_attr_link_name); + if (rc) { + d_vpr_e("Failed to create video device file\n"); + video_unregister_device(&core->vdev[sess_type].vdev); + return rc; + } + return 0; +} +static int msm_vidc_probe_vidc_device(struct platform_device *pdev) +{ + int rc = 0; + struct msm_vidc_core *core; + struct device *dev = NULL; + int nr = BASE_DEVICE_NUMBER; + + if (!vidc_driver) { + d_vpr_e("Invalid vidc driver\n"); + return -EINVAL; + } + + core = kzalloc(sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + core->platform_data = vidc_get_drv_data(&pdev->dev); + dev_set_drvdata(&pdev->dev, core); + rc = msm_vidc_initialize_core(pdev, core); + if (rc) { + d_vpr_e("Failed to init core\n"); + goto err_core_init; + } + rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); + if (rc) { + d_vpr_e("Failed to create attributes\n"); + goto err_core_init; + } + + core->id = MSM_VIDC_CORE_VENUS; + + rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev); + if (rc) { + d_vpr_e("Failed to register v4l2 device\n"); + goto err_v4l2_register; + } + + /* setup the decoder device */ + rc = msm_vidc_register_video_device(MSM_VIDC_DECODER, + nr, core, dev); + if (rc) { + d_vpr_e("Failed to register video decoder\n"); + goto err_dec; + } + + /* setup the encoder device */ + rc = msm_vidc_register_video_device(MSM_VIDC_ENCODER, + nr + 1, core, dev); + if (rc) { + d_vpr_e("Failed to register video encoder\n"); + goto err_enc; + } + + /* setup the cvp device */ + if (core->resources.cvp_internal) { + rc = msm_vidc_register_video_device(MSM_VIDC_CVP, + nr + 2, core, dev); + if (rc) { + d_vpr_e("Failed to register video CVP\n"); + goto err_cvp; + } + } + + /* finish setting up the 'core' */ + mutex_lock(&vidc_driver->lock); + if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) { + mutex_unlock(&vidc_driver->lock); + d_vpr_e("Maximum cores already exist, core_no = %d\n", + vidc_driver->num_cores); + goto err_cores_exceeded; + } + vidc_driver->num_cores++; + mutex_unlock(&vidc_driver->lock); + + core->device = vidc_hfi_initialize(core->hfi_type, core->id, + &core->resources, &handle_cmd_response); + if (IS_ERR_OR_NULL(core->device)) { + mutex_lock(&vidc_driver->lock); + vidc_driver->num_cores--; + mutex_unlock(&vidc_driver->lock); + + rc = PTR_ERR(core->device) ? + PTR_ERR(core->device) : -EBADHANDLE; + if (rc != -EPROBE_DEFER) + d_vpr_e("Failed to create HFI device\n"); + else + d_vpr_h("msm_vidc: request probe defer\n"); + goto err_cores_exceeded; + } + + core->vidc_core_workq = create_singlethread_workqueue( + "vidc_core_workq"); + if (!core->vidc_core_workq) { + d_vpr_e("%s: create core workq failed\n", __func__); + goto err_core_workq; + } + mutex_lock(&vidc_driver->lock); + list_add_tail(&core->list, &vidc_driver->cores); + mutex_unlock(&vidc_driver->lock); + + core->debugfs_root = msm_vidc_debugfs_init_core( + core, vidc_driver->debugfs_root); + + vidc_driver->sku_version = core->resources.sku_version; + + d_vpr_h("populating sub devices\n"); + /* + * Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank. + * When msm_vidc_probe is called for each sub-device, parse the + * context-bank details and store it in core->resources.context_banks + * list. + */ + rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL, + &pdev->dev); + if (rc) { + d_vpr_e("Failed to trigger probe for sub-devices\n"); + goto err_fail_sub_device_probe; + } + + return rc; + +err_fail_sub_device_probe: + if (core->vidc_core_workq) + destroy_workqueue(core->vidc_core_workq); +err_core_workq: + vidc_hfi_deinitialize(core->hfi_type, core->device); +err_cores_exceeded: + if (core->resources.cvp_internal) { + device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, + &dev_attr_link_name); + video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + } +err_cvp: + device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev, + &dev_attr_link_name); + video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev); +err_enc: + device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev, + &dev_attr_link_name); + video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev); +err_dec: + v4l2_device_unregister(&core->v4l2_dev); +err_v4l2_register: + sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); +err_core_init: + dev_set_drvdata(&pdev->dev, NULL); + kfree(core); + return rc; +} + +static int msm_vidc_probe_mem_cdsp(struct platform_device *pdev) +{ + return read_mem_cdsp_resources_from_dt(pdev); +} + +static int msm_vidc_probe_context_bank(struct platform_device *pdev) +{ + return read_context_bank_resources_from_dt(pdev); +} + +static int msm_vidc_probe_bus(struct platform_device *pdev) +{ + return read_bus_resources_from_dt(pdev); +} + +static int msm_vidc_probe(struct platform_device *pdev) +{ + /* + * Sub devices probe will be triggered by of_platform_populate() towards + * the end of the probe function after msm-vidc device probe is + * completed. Return immediately after completing sub-device probe. + */ + if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) { + return msm_vidc_probe_vidc_device(pdev); + } else if (of_device_is_compatible(pdev->dev.of_node, + "qcom,msm-vidc,bus")) { + return msm_vidc_probe_bus(pdev); + } else if (of_device_is_compatible(pdev->dev.of_node, + "qcom,msm-vidc,context-bank")) { + return msm_vidc_probe_context_bank(pdev); + } else if (of_device_is_compatible(pdev->dev.of_node, + "qcom,msm-vidc,mem-cdsp")) { + return msm_vidc_probe_mem_cdsp(pdev); + } + + /* How did we end up here? */ + MSM_VIDC_ERROR(1); + return -EINVAL; +} + +static int msm_vidc_remove(struct platform_device *pdev) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!pdev) { + d_vpr_e("%s: invalid input %pK", __func__, pdev); + return -EINVAL; + } + + core = dev_get_drvdata(&pdev->dev); + if (!core) { + d_vpr_e("%s: invalid core", __func__); + return -EINVAL; + } + + if (core->vidc_core_workq) + destroy_workqueue(core->vidc_core_workq); + vidc_hfi_deinitialize(core->hfi_type, core->device); + if (core->resources.cvp_internal) { + device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, + &dev_attr_link_name); + video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev); + } + device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev, + &dev_attr_link_name); + video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev); + device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev, + &dev_attr_link_name); + video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev); + v4l2_device_unregister(&core->v4l2_dev); + + msm_vidc_free_platform_resources(&core->resources); + sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); + dev_set_drvdata(&pdev->dev, NULL); + mutex_destroy(&core->resources.cb_lock); + mutex_destroy(&core->lock); + kfree(core); + return rc; +} + +static int msm_vidc_pm_suspend(struct device *dev) +{ + int rc = 0; + struct msm_vidc_core *core; + + /* + * Bail out if + * - driver possibly not probed yet + * - not the main device. We don't support power management on + * subdevices (e.g. context banks) + */ + if (!dev || !dev->driver || + !of_device_is_compatible(dev->of_node, "qcom,msm-vidc")) + return 0; + + core = dev_get_drvdata(dev); + if (!core) { + d_vpr_e("%s: invalid core\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_suspend(core->id); + if (rc == -ENOTSUPP) + rc = 0; + else if (rc) + d_vpr_e("Failed to suspend: %d\n", rc); + + + return rc; +} + +static int msm_vidc_pm_resume(struct device *dev) +{ + d_vpr_h("%s\n", __func__); + return 0; +} + +static const struct dev_pm_ops msm_vidc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume) +}; + +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match); + +static struct platform_driver msm_vidc_driver = { + .probe = msm_vidc_probe, + .remove = msm_vidc_remove, + .driver = { + .name = "msm_vidc_v4l2", + .of_match_table = msm_vidc_dt_match, + .pm = &msm_vidc_pm_ops, + }, +}; + +static int __init msm_vidc_init(void) +{ + int rc = 0; + + vidc_driver = kzalloc(sizeof(*vidc_driver), + GFP_KERNEL); + if (!vidc_driver) { + d_vpr_e("Failed to allocate memroy for msm_vidc_drv\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&vidc_driver->cores); + mutex_init(&vidc_driver->lock); + vidc_driver->debugfs_root = msm_vidc_debugfs_init_drv(); + if (!vidc_driver->debugfs_root) + d_vpr_e("Failed to create debugfs for msm_vidc\n"); + + rc = platform_driver_register(&msm_vidc_driver); + if (rc) { + d_vpr_e("Failed to register platform driver\n"); + debugfs_remove_recursive(vidc_driver->debugfs_root); + kfree(vidc_driver); + vidc_driver = NULL; + } + + return rc; +} + +static void __exit msm_vidc_exit(void) +{ + platform_driver_unregister(&msm_vidc_driver); + debugfs_remove_recursive(vidc_driver->debugfs_root); + mutex_destroy(&vidc_driver->lock); + kfree(vidc_driver); + vidc_driver = NULL; +} + +module_init(msm_vidc_init); +module_exit(msm_vidc_exit); + +MODULE_LICENSE("GPL v2"); diff --git a/techpack/video/msm/vidc/msm_vdec.c b/techpack/video/msm/vidc/msm_vdec.c new file mode 100644 index 0000000000000000000000000000000000000000..54923e18b3a0f6d1a15571cd36f500653323d001 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vdec.c @@ -0,0 +1,1508 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/slab.h> +#include <soc/qcom/scm.h> +#include "msm_vdec.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "vidc_hfi.h" +#include "vidc_hfi_helper.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" +#include "msm_vidc_buffer_calculations.h" + +#define MIN_NUM_DEC_OUTPUT_BUFFERS 4 +#define MIN_NUM_DEC_CAPTURE_BUFFERS 4 +/* Y=16(0-9bits), Cb(10-19bits)=Cr(20-29bits)=128, black by default */ +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_VP9D_INST_COUNT 6 + +static const char *const vp8_profile_level[] = { + "Unused", + "0.0", + "1.0", + "2.0", + "3.0", + NULL +}; + +static const char *const vp9_level[] = { + "Unused", + "1.0", + "1.1", + "2.0", + "2.1", + "3.0", + "3.1", + "4.0", + "4.1", + "5.0", + "5.1", + "6.0", + "6.1", + NULL +}; + +static const char *const mpeg2_profile[] = { + "Simple", + "Main", + "High", + NULL +}; + +static const char *const mpeg2_level[] = { + "0", + "1", + "2", + "3", + NULL +}; + +static struct msm_vidc_ctrl msm_vdec_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDEO_UNKNOWN, + .name = "Invalid control", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_DECODE_ORDER, + .name = "Decode Order", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE, + .name = "Sync Frame Decode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE, + .name = "Secure mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA, + .name = "Extradata Type", + .type = V4L2_CTRL_TYPE_BITMASK, + .minimum = EXTRADATA_NONE, + .maximum = EXTRADATA_DEFAULT | EXTRADATA_ADVANCED, + .default_value = EXTRADATA_DEFAULT, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE, + .name = "Video decoder multi stream", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY, + .maximum = + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY, + .default_value = + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .name = "H264 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .name = "H264 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_6_2) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .name = "HEVC Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .name = "HEVC Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, + .name = "HEVC Tier", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_TIER_HIGH) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE, + .name = "VP8 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .maximum = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .default_value = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .menu_skip_mask = ~(1 << V4L2_MPEG_VIDEO_VP8_PROFILE_0), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + .name = "VP8 Profile Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3) + ), + .qmenu = vp8_profile_level, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + .name = "VP9 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .maximum = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .default_value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + (1 << V4L2_MPEG_VIDEO_VP9_PROFILE_1) | + (1 << V4L2_MPEG_VIDEO_VP9_PROFILE_2) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP9_LEVEL, + .name = "VP9 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_11) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_21) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_3) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_31) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_4) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61) + ), + .qmenu = vp9_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE, + .name = "MPEG2 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE, + .maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN, + .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE) | + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN) + ), + .qmenu = mpeg2_profile, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL, + .name = "MPEG2 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0, + .maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2, + .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2) + ), + .qmenu = mpeg2_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT, + .name = "Picture concealed color 8bit", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0x0, + .maximum = 0xff3fcff, + .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT, + .name = "Picture concealed color 10bit", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0x0, + .maximum = 0x3fffffff, + .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT, + .name = "Buffer size limit", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + .name = "CAPTURE Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = SINGLE_OUTPUT_BUFFER, + .maximum = MAX_NUM_OUTPUT_BUFFERS, + .default_value = SINGLE_OUTPUT_BUFFER, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + .name = "OUTPUT Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = SINGLE_INPUT_BUFFER, + .maximum = MAX_NUM_INPUT_BUFFERS, + .default_value = SINGLE_INPUT_BUFFER, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE, + .name = "Frame Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = (MINIMUM_FPS << 16), + .maximum = (MAXIMUM_FPS << 16), + .default_value = (DEFAULT_FPS << 16), + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY, + .name = "Session Priority", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_ENABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE, + .name = "Decoder Operating rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = (DEFAULT_FPS << 16),/* Power Vote min fps */ + .maximum = INT_MAX, + .default_value = (DEFAULT_FPS << 16), + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE, + .name = "Low Latency Mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_HINT, + .name = "Low Latency Hint", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_SUPERFRAME, + .name = "Superframe", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 1, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls) + + +struct msm_vidc_format_desc vdec_output_formats[] = { + { + .name = "YCbCr Semiplanar 4:2:0", + .description = "Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12, + }, + { + .name = "YCbCr Semiplanar 4:2:0 10bit", + .description = "Y/CbCr 4:2:0 10bit", + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + }, + { + .name = "UBWC YCbCr Semiplanar 4:2:0", + .description = "UBWC Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12_UBWC, + }, + { + .name = "UBWC YCbCr Semiplanar 4:2:0 10bit", + .description = "UBWC Y/CbCr 4:2:0 10bit", + .fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC, + }, +}; + +struct msm_vidc_format_desc vdec_input_formats[] = { + { + .name = "Mpeg2", + .description = "Mpeg2 compressed format", + .fourcc = V4L2_PIX_FMT_MPEG2, + }, + { + .name = "H264", + .description = "H264 compressed format", + .fourcc = V4L2_PIX_FMT_H264, + }, + { + .name = "HEVC", + .description = "HEVC compressed format", + .fourcc = V4L2_PIX_FMT_HEVC, + }, + { + .name = "VP8", + .description = "VP8 compressed format", + .fourcc = V4L2_PIX_FMT_VP8, + }, + { + .name = "VP9", + .description = "VP9 compressed format", + .fourcc = V4L2_PIX_FMT_VP9, + }, +}; + +struct msm_vidc_format_constraint dec_pix_format_constraints[] = { + { + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + .num_planes = 2, + .y_max_stride = 8192, + .y_buffer_alignment = 256, + .uv_max_stride = 8192, + .uv_buffer_alignment = 256, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .num_planes = 2, + .y_max_stride = 8192, + .y_buffer_alignment = 512, + .uv_max_stride = 8192, + .uv_buffer_alignment = 256, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .num_planes = 2, + .y_max_stride = 8192, + .y_buffer_alignment = 512, + .uv_max_stride = 8192, + .uv_buffer_alignment = 256, + }, +}; + +static bool msm_vidc_check_for_vp9d_overload(struct msm_vidc_core *core) +{ + u32 vp9d_instance_count = 0; + struct msm_vidc_inst *inst = NULL; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->session_type == MSM_VIDC_DECODER && + get_v4l2_codec(inst) == V4L2_PIX_FMT_VP9) + vp9d_instance_count++; + } + mutex_unlock(&core->lock); + + if (vp9d_instance_count > MAX_VP9D_INST_COUNT) + return true; + return false; +} + +int msm_vdec_update_stream_output_mode(struct msm_vidc_inst *inst) +{ + struct v4l2_format *f; + u32 format; + u32 stream_output_mode; + u32 fourcc; + + if (!inst) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + format = f->fmt.pix_mp.pixelformat; + stream_output_mode = HAL_VIDEO_DECODER_PRIMARY; + if ((format == V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS) || + (format == V4L2_PIX_FMT_NV12)) { + stream_output_mode = HAL_VIDEO_DECODER_SECONDARY; + } + + msm_comm_set_stream_output_mode(inst, + stream_output_mode); + + fourcc = V4L2_PIX_FMT_NV12_UBWC; + if (inst->bit_depth == MSM_VIDC_BIT_DEPTH_10) + fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC; + + inst->clk_data.dpb_fourcc = fourcc; + + return 0; +} + +int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + struct msm_vidc_format *fmt = NULL; + struct msm_vidc_format_desc *fmt_desc = NULL; + struct v4l2_pix_format_mplane *mplane = NULL; + int rc = 0; + u32 color_format; + + if (!inst || !f) { + d_vpr_e("%s: invalid parameters %pK %pK\n", __func__, inst, f); + return -EINVAL; + } + + /* + * First update inst format with new width/height/format + * Recalculate sizes/strides etc + * Perform necessary checks to continue with session + * Copy recalculated info into user format + */ + if (f->type == OUTPUT_MPLANE) { + fmt = &inst->fmts[OUTPUT_PORT]; + fmt_desc = msm_comm_get_pixel_fmt_fourcc(vdec_output_formats, + ARRAY_SIZE(vdec_output_formats), + f->fmt.pix_mp.pixelformat, inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(fmt->name, fmt_desc->name, sizeof(fmt->name)); + strlcpy(fmt->description, fmt_desc->description, + sizeof(fmt->description)); + + inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat; + + fmt->v4l2_fmt.type = f->type; + mplane = &fmt->v4l2_fmt.fmt.pix_mp; + mplane->width = f->fmt.pix_mp.width; + mplane->height = f->fmt.pix_mp.height; + mplane->pixelformat = f->fmt.pix_mp.pixelformat; + mplane->plane_fmt[0].sizeimage = + msm_vidc_calculate_dec_output_frame_size(inst); + + if (mplane->num_planes > 1) + mplane->plane_fmt[1].sizeimage = + msm_vidc_calculate_dec_output_extra_size(inst); + color_format = msm_comm_convert_color_fmt( + f->fmt.pix_mp.pixelformat, inst->sid); + mplane->plane_fmt[0].bytesperline = + VENUS_Y_STRIDE(color_format, f->fmt.pix_mp.width); + mplane->plane_fmt[0].reserved[0] = + VENUS_Y_SCANLINES(color_format, f->fmt.pix_mp.height); + inst->bit_depth = MSM_VIDC_BIT_DEPTH_8; + if ((f->fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_NV12_TP10_UBWC) || + (f->fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS)) { + inst->bit_depth = MSM_VIDC_BIT_DEPTH_10; + } + + rc = msm_vidc_check_session_supported(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: session not supported\n", __func__); + goto err_invalid_fmt; + } + + rc = msm_vdec_update_stream_output_mode(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed to update output stream mode\n", + __func__); + goto err_invalid_fmt; + } + + memcpy(f, &fmt->v4l2_fmt, sizeof(struct v4l2_format)); + } else if (f->type == INPUT_MPLANE) { + fmt = &inst->fmts[INPUT_PORT]; + fmt_desc = msm_comm_get_pixel_fmt_fourcc(vdec_input_formats, + ARRAY_SIZE(vdec_input_formats), + f->fmt.pix_mp.pixelformat, inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(fmt->name, fmt_desc->name, sizeof(fmt->name)); + strlcpy(fmt->description, fmt_desc->description, + sizeof(fmt->description)); + + if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_VP9) { + if (msm_vidc_check_for_vp9d_overload(inst->core)) { + s_vpr_e(inst->sid, "VP9 Decode overload\n"); + rc = -ENOMEM; + goto err_invalid_fmt; + } + } + + fmt->v4l2_fmt.type = f->type; + mplane = &fmt->v4l2_fmt.fmt.pix_mp; + mplane->width = f->fmt.pix_mp.width; + mplane->height = f->fmt.pix_mp.height; + mplane->pixelformat = f->fmt.pix_mp.pixelformat; + rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); + if (rc) { + s_vpr_e(inst->sid, "Failed to open instance\n"); + goto err_invalid_fmt; + } + + mplane->plane_fmt[0].sizeimage = + msm_vidc_calculate_dec_input_frame_size(inst); + + /* Driver can recalculate buffer count only for + * only for bitstream port. Decoder YUV port reconfig + * should not overwrite the FW calculated buffer + * count. + */ + rc = msm_vidc_calculate_buffer_counts(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s failed to calculate buffer count\n", + __func__); + return rc; + } + + rc = msm_vidc_check_session_supported(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: session not supported\n", __func__); + goto err_invalid_fmt; + } + update_log_ctxt(inst->sid, inst->session_type, + mplane->pixelformat); + memcpy(f, &fmt->v4l2_fmt, sizeof(struct v4l2_format)); + } + + inst->batch.enable = is_batching_allowed(inst); + msm_dcvs_try_enable(inst); + +err_invalid_fmt: + return rc; +} + +int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt; + + if (f->type == OUTPUT_MPLANE) { + fmt = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_dec_output_frame_size(inst); + if (fmt->fmt.pix_mp.num_planes > 1) + fmt->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_dec_output_extra_size(inst); + memcpy(f, fmt, sizeof(struct v4l2_format)); + } else if (f->type == INPUT_MPLANE) { + fmt = &inst->fmts[INPUT_PORT].v4l2_fmt; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_dec_input_frame_size(inst); + memcpy(f, fmt, sizeof(struct v4l2_format)); + } else { + s_vpr_e(inst->sid, "%s: Unsupported buf type: %d\n", + __func__, f->type); + return -EINVAL; + } + + return 0; +} + +int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + const struct msm_vidc_format_desc *fmt_desc = NULL; + int rc = 0; + + if (!inst || !f) { + d_vpr_e("Invalid input, inst = %pK, f = %pK\n", inst, f); + return -EINVAL; + } + if (f->type == OUTPUT_MPLANE) { + fmt_desc = msm_comm_get_pixel_fmt_index(vdec_output_formats, + ARRAY_SIZE(vdec_output_formats), f->index, inst->sid); + } else if (f->type == INPUT_MPLANE) { + fmt_desc = msm_comm_get_pixel_fmt_index(vdec_input_formats, + ARRAY_SIZE(vdec_input_formats), f->index, inst->sid); + f->flags = V4L2_FMT_FLAG_COMPRESSED; + } + + memset(f->reserved, 0, sizeof(f->reserved)); + if (fmt_desc) { + strlcpy(f->description, fmt_desc->description, + sizeof(f->description)); + f->pixelformat = fmt_desc->fourcc; + } else { + s_vpr_h(inst->sid, "No more formats found\n"); + rc = -EINVAL; + } + return rc; +} + +int msm_vdec_inst_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct msm_vidc_format_desc *fmt_desc = NULL; + struct v4l2_format *f = NULL; + + if (!inst || !inst->core) { + d_vpr_e("Invalid input = %pK\n", inst); + return -EINVAL; + } + core = inst->core; + + inst->prop.extradata_ctrls = EXTRADATA_DEFAULT; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12_UBWC; + f->fmt.pix_mp.num_planes = 2; + f->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_dec_output_frame_size(inst); + f->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_dec_output_extra_size(inst); + fmt_desc = msm_comm_get_pixel_fmt_fourcc(vdec_output_formats, + ARRAY_SIZE(vdec_output_formats), + f->fmt.pix_mp.pixelformat, inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set: %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(inst->fmts[OUTPUT_PORT].name, fmt_desc->name, + sizeof(inst->fmts[OUTPUT_PORT].name)); + strlcpy(inst->fmts[OUTPUT_PORT].description, fmt_desc->description, + sizeof(inst->fmts[OUTPUT_PORT].description)); + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_dec_input_frame_size(inst); + fmt_desc = msm_comm_get_pixel_fmt_fourcc(vdec_input_formats, + ARRAY_SIZE(vdec_input_formats), f->fmt.pix_mp.pixelformat, + inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set: %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(inst->fmts[INPUT_PORT].name, fmt_desc->name, + sizeof(inst->fmts[INPUT_PORT].name)); + strlcpy(inst->fmts[INPUT_PORT].description, fmt_desc->description, + sizeof(inst->fmts[INPUT_PORT].description)); + inst->buffer_mode_set[INPUT_PORT] = HAL_BUFFER_MODE_STATIC; + inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_DYNAMIC; + inst->stream_output_mode = HAL_VIDEO_DECODER_PRIMARY; + + + inst->clk_data.frame_rate = (DEFAULT_FPS << 16); + inst->clk_data.operating_rate = (DEFAULT_FPS << 16); + if (core->resources.decode_batching) { + inst->batch.enable = true; + inst->batch.size = MAX_DEC_BATCH_SIZE; + } + + inst->buff_req.buffer[1].buffer_type = HAL_BUFFER_INPUT; + inst->buff_req.buffer[1].buffer_count_min_host = + inst->buff_req.buffer[1].buffer_count_actual = + MIN_NUM_DEC_OUTPUT_BUFFERS; + inst->buff_req.buffer[2].buffer_type = HAL_BUFFER_OUTPUT; + inst->buff_req.buffer[2].buffer_count_min_host = + inst->buff_req.buffer[2].buffer_count_actual = + MIN_NUM_DEC_CAPTURE_BUFFERS; + inst->buff_req.buffer[3].buffer_type = HAL_BUFFER_OUTPUT2; + inst->buff_req.buffer[3].buffer_count_min_host = + inst->buff_req.buffer[3].buffer_count_actual = + MIN_NUM_DEC_CAPTURE_BUFFERS; + inst->buff_req.buffer[4].buffer_type = HAL_BUFFER_EXTRADATA_INPUT; + inst->buff_req.buffer[5].buffer_type = HAL_BUFFER_EXTRADATA_OUTPUT; + inst->buff_req.buffer[6].buffer_type = HAL_BUFFER_EXTRADATA_OUTPUT2; + inst->buff_req.buffer[7].buffer_type = HAL_BUFFER_INTERNAL_SCRATCH; + inst->buff_req.buffer[8].buffer_type = HAL_BUFFER_INTERNAL_SCRATCH_1; + inst->buff_req.buffer[9].buffer_type = HAL_BUFFER_INTERNAL_SCRATCH_2; + inst->buff_req.buffer[10].buffer_type = HAL_BUFFER_INTERNAL_PERSIST; + inst->buff_req.buffer[11].buffer_type = HAL_BUFFER_INTERNAL_PERSIST_1; + inst->buff_req.buffer[12].buffer_type = HAL_BUFFER_INTERNAL_CMD_QUEUE; + inst->buff_req.buffer[13].buffer_type = HAL_BUFFER_INTERNAL_RECON; + msm_vidc_init_buffer_size_calculators(inst); + + return rc; +} + +int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + s_vpr_h(inst->sid, "%s: control name = %s, id = 0x%x value = %d\n", + __func__, ctrl->name, ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE: + inst->profile = msm_comm_v4l2_to_hfi(ctrl->id, ctrl->val, + inst->sid); + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL: + inst->level = msm_comm_v4l2_to_hfi(ctrl->id, ctrl->val, + inst->sid); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + inst->level |= + (msm_comm_v4l2_to_hfi(ctrl->id, ctrl->val, + inst->sid) << 28); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_DECODE_ORDER: + case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT: + case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT: + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE: + inst->flags &= ~VIDC_THUMBNAIL; + if (ctrl->val) + inst->flags |= VIDC_THUMBNAIL; + + inst->batch.enable = is_batching_allowed(inst); + rc = msm_vidc_calculate_buffer_counts(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed to calculate thumbnail buffer count\n", + __func__); + return rc; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE: + inst->flags &= ~VIDC_SECURE; + if (ctrl->val) + inst->flags |= VIDC_SECURE; + if (msm_comm_check_for_inst_overload(inst->core)) { + s_vpr_e(inst->sid, + "%s: Instance count reached Max limit, rejecting session", + __func__); + return -ENOTSUPP; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE: + inst->clk_data.frame_rate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: + if (ctrl->val == EXTRADATA_NONE) + inst->prop.extradata_ctrls = 0; + else + inst->prop.extradata_ctrls |= ctrl->val; + /* + * nothing to do here as inst->bufq[OUTPUT_PORT].num_planes + * and inst->bufq[OUTPUT_PORT].plane_sizes[1] are already + * initialized to proper values + */ + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT: + inst->buffer_size_limit = ctrl->val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY: + break; + case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE: + if (!is_valid_operating_rate(inst, ctrl->val)) + break; + inst->flags &= ~VIDC_TURBO; + if (ctrl->val == INT_MAX) + inst->flags |= VIDC_TURBO; + else + inst->clk_data.operating_rate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE: + inst->clk_data.low_latency_mode = !!ctrl->val; + inst->batch.enable = is_batching_allowed(inst); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_HINT: + break; + default: + s_vpr_e(inst->sid, "Unknown control %#x\n", ctrl->id); + break; + } + + return rc; +} + +int msm_vdec_set_frame_size(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_frame_size frame_size; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + frame_size.buffer_type = HFI_BUFFER_INPUT; + frame_size.width = f->fmt.pix_mp.width; + frame_size.height = f->fmt.pix_mp.height; + s_vpr_h(inst->sid, "%s: input wxh %dx%d\n", __func__, + frame_size.width, frame_size.height); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_FRAME_SIZE, &frame_size, sizeof(frame_size)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_color_format(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct msm_vidc_format_constraint *fmt_constraint; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + rc = msm_comm_set_color_format(inst, + msm_comm_get_hal_output_buffer(inst), + inst->clk_data.opb_fourcc); + if (rc) { + s_vpr_e(inst->sid, "%s: set color format (%#x) failed\n", + __func__, inst->clk_data.opb_fourcc); + return rc; + } + fmt_constraint = msm_comm_get_pixel_fmt_constraints( + dec_pix_format_constraints, + ARRAY_SIZE(dec_pix_format_constraints), + inst->clk_data.opb_fourcc, inst->sid); + if (fmt_constraint) { + rc = msm_comm_set_color_format_constraints(inst, + msm_comm_get_hal_output_buffer(inst), + fmt_constraint); + if (rc) { + s_vpr_e(inst->sid, + "%s: Set constraints for color format %#x failed\n", + __func__, inst->clk_data.opb_fourcc); + return rc; + } + } + + return rc; +} + +int msm_vdec_set_input_buffer_counts(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct msm_vidc_format *fmt; + enum hal_buffer buffer_type; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + buffer_type = HAL_BUFFER_INPUT; + fmt = &inst->fmts[INPUT_PORT]; + rc = msm_comm_set_buffer_count(inst, + fmt->count_min, + fmt->count_actual, + buffer_type); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to set bufreqs(%#x)\n", + __func__, buffer_type); + return -EINVAL; + } + + return rc; +} + +int msm_vdec_set_output_buffer_counts(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct msm_vidc_format *fmt; + enum hal_buffer buffer_type; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + buffer_type = msm_comm_get_hal_output_buffer(inst); + /* Correct buffer counts is always stored in HAL_BUFFER_OUTPUT */ + fmt = &inst->fmts[OUTPUT_PORT]; + if (buffer_type == HAL_BUFFER_OUTPUT2) { + /* + * For split mode set DPB count as well + * For DPB actual count is same as min output count + */ + rc = msm_comm_set_buffer_count(inst, + fmt->count_min, + fmt->count_min, + HAL_BUFFER_OUTPUT); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed to set buffer count(%#x)\n", + __func__, buffer_type); + return -EINVAL; + } + } + rc = msm_comm_set_buffer_count(inst, + fmt->count_min, + fmt->count_actual, + buffer_type); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to set bufreqs(%#x)\n", + __func__, buffer_type); + return -EINVAL; + } + + return rc; +} + +int msm_vdec_set_profile_level(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_profile_level profile_level; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + profile_level.profile = inst->profile; + profile_level.level = inst->level; + + s_vpr_h(inst->sid, "%s: %#x %#x\n", __func__, + profile_level.profile, profile_level.level); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, &profile_level, + sizeof(profile_level)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_output_order(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + u32 output_order; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_DECODE_ORDER); + s_vpr_h(inst->sid, "%s: %d\n", __func__, ctrl->val); + if (ctrl->val == V4L2_MPEG_MSM_VIDC_ENABLE) + output_order = HFI_OUTPUT_ORDER_DECODE; + else + output_order = HFI_OUTPUT_ORDER_DISPLAY; + + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER, &output_order, + sizeof(u32)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_sync_frame_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_enable hfi_property; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE); + hfi_property.enable = (bool)ctrl->val; + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, hfi_property.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE, &hfi_property, + sizeof(hfi_property)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_secure_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_SECURE); + + codec = get_v4l2_codec(inst); + if (ctrl->val) { + if (!(codec == V4L2_PIX_FMT_HEVC || + codec == V4L2_PIX_FMT_H264 || + codec == V4L2_PIX_FMT_VP9 || + codec == V4L2_PIX_FMT_MPEG2)) { + s_vpr_e(inst->sid, + "%s: Secure allowed for HEVC/H264/VP9/MPEG2\n", + __func__); + return -EINVAL; + } + } + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, ctrl->val); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_SECURE_SESSION, &ctrl->val, sizeof(u32)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_output_stream_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_multi_stream multi_stream; + struct hfi_frame_size frame_sz; + struct v4l2_format *f; + u32 sid; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + sid = inst->sid; + + if (is_primary_output_mode(inst)) { + multi_stream.buffer_type = HFI_BUFFER_OUTPUT; + multi_stream.enable = true; + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, &multi_stream, + sizeof(multi_stream)); + if (rc) { + s_vpr_e(sid, + "%s: set prop multistream primary failed: %d\n", + __func__, rc); + return rc; + } + multi_stream.buffer_type = HFI_BUFFER_OUTPUT2; + multi_stream.enable = false; + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, &multi_stream, + sizeof(multi_stream)); + if (rc) { + s_vpr_e(sid, + "%s: set prop multistream primary2 failed : %d\n", + __func__, rc); + return rc; + } + } else { + rc = msm_comm_set_color_format(inst, + HAL_BUFFER_OUTPUT, inst->clk_data.dpb_fourcc); + if (rc) + return rc; + + multi_stream.buffer_type = HFI_BUFFER_OUTPUT2; + multi_stream.enable = true; + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, &multi_stream, + sizeof(multi_stream)); + if (rc) { + s_vpr_e(sid, + "%s: set prop multistream secondary failed : %d\n", + __func__, rc); + return rc; + } + multi_stream.buffer_type = HFI_BUFFER_OUTPUT; + multi_stream.enable = false; + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, &multi_stream, + sizeof(multi_stream)); + if (rc) { + s_vpr_e(sid, + "%s: set prop multistream secondary2 failed: %d\n", + __func__, rc); + return rc; + } + frame_sz.buffer_type = HFI_BUFFER_OUTPUT2; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + frame_sz.width = f->fmt.pix_mp.width; + frame_sz.height = f->fmt.pix_mp.height; + s_vpr_h(sid, + "frame_size: hal buffer type %d, width %d, height %d\n", + frame_sz.buffer_type, frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_FRAME_SIZE, &frame_sz, + sizeof(frame_sz)); + if (rc) { + s_vpr_e(sid, "%s: set prop frame_size failed\n", + __func__); + return rc; + } + } + + return rc; +} + +int msm_vdec_set_priority(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_enable hfi_property; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + hfi_property.enable = is_realtime_session(inst); + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, hfi_property.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_REALTIME, &hfi_property, + sizeof(hfi_property)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_seqchng_at_syncframe(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_enable hfi_property; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + hfi_property.enable = is_low_latency_hint(inst); + + if (!hfi_property.enable) + return 0; + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, hfi_property.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_SEQCHNG_AT_SYNCFRM, &hfi_property, + sizeof(hfi_property)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_vdec_set_conceal_color(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl_8b; + struct v4l2_ctrl *ctrl_10b; + struct hfi_conceal_color conceal_color; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl_8b = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT); + ctrl_10b = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT); + conceal_color.conceal_color_8bit = ctrl_8b->val; + conceal_color.conceal_color_10bit = ctrl_10b->val; + + s_vpr_h(inst->sid, "%s: %#x %#x\n", __func__, + conceal_color.conceal_color_8bit, + conceal_color.conceal_color_10bit); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR, &conceal_color, + sizeof(conceal_color)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + + +int msm_vdec_set_extradata(struct msm_vidc_inst *inst) +{ + uint32_t display_info = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA; + u32 value = 0x0; + u32 codec; + + codec = get_v4l2_codec(inst); + switch (codec) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + display_info = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA; + break; + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_VP9: + display_info = + HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA; + break; + case V4L2_PIX_FMT_MPEG2: + display_info = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA; + break; + } + + /* Enable Default Extradata */ + msm_comm_set_index_extradata(inst, + MSM_VIDC_EXTRADATA_OUTPUT_CROP, 0x1); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA, 0x1); + msm_comm_set_extradata(inst, display_info, 0x1); + + if (codec == V4L2_PIX_FMT_VP9 || codec == V4L2_PIX_FMT_HEVC) { + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_HDR10_HIST_EXTRADATA, 0x1); + } + + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB, 0x1); + if (codec == V4L2_PIX_FMT_HEVC) { + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_MASTER_DISP_COL_SEI_EXTRADATA, + 0x1); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_CLL_SEI_EXTRADATA, 0x1); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA, + 0x1); + } + + /* Enable / Disable Advanced Extradata */ + if (inst->prop.extradata_ctrls & EXTRADATA_ADVANCED) + value = 0x1; + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA, value); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA, value); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA, value); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA, value); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA, value); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA, value); + msm_comm_set_index_extradata(inst, + MSM_VIDC_EXTRADATA_ASPECT_RATIO, value); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA, value); + + return 0; +} + +int msm_vdec_set_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!in_port_reconfig(inst)) { + /* do not allow these settings in port reconfiration */ + rc = msm_vdec_set_frame_size(inst); + if (rc) + goto exit; + rc = msm_vdec_set_input_buffer_counts(inst); + if (rc) + goto exit; + rc = msm_vdec_set_profile_level(inst); + if (rc) + goto exit; + rc = msm_vdec_set_output_order(inst); + if (rc) + goto exit; + rc = msm_vdec_set_sync_frame_mode(inst); + if (rc) + goto exit; + rc = msm_vdec_set_secure_mode(inst); + if (rc) + goto exit; + rc = msm_vdec_set_extradata(inst); + if (rc) + goto exit; + rc = msm_vdec_set_priority(inst); + if (rc) + goto exit; + rc = msm_vdec_set_conceal_color(inst); + if (rc) + goto exit; + rc = msm_vdec_set_seqchng_at_syncframe(inst); + if (rc) + goto exit; + } + + rc = msm_vdec_set_color_format(inst); + if (rc) + goto exit; + rc = msm_vdec_set_output_stream_mode(inst); + if (rc) + goto exit; + rc = msm_vdec_set_output_buffer_counts(inst); + if (rc) + goto exit; + +exit: + if (rc) + s_vpr_e(inst->sid, "%s: failed with %d\n", __func__, rc); + else + s_vpr_h(inst->sid, "%s: set properties successful\n", __func__); + + return rc; +} + +int msm_vdec_ctrl_init(struct msm_vidc_inst *inst, + const struct v4l2_ctrl_ops *ctrl_ops) +{ + return msm_comm_ctrl_init(inst, msm_vdec_ctrls, + ARRAY_SIZE(msm_vdec_ctrls), ctrl_ops); +} diff --git a/techpack/video/msm/vidc/msm_vdec.h b/techpack/video/msm/vidc/msm_vdec.h new file mode 100644 index 0000000000000000000000000000000000000000..d2e8b28033ed8d2d6daefa6bad6a35fd5f1937a8 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vdec.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _MSM_VDEC_H_ +#define _MSM_VDEC_H_ + +#include "msm_vidc.h" +#include "msm_vidc_internal.h" +#define MSM_VDEC_DVC_NAME "msm_vidc_vdec" + +int msm_vdec_inst_init(struct msm_vidc_inst *inst); +int msm_vdec_ctrl_init(struct msm_vidc_inst *inst, + const struct v4l2_ctrl_ops *ctrl_ops); +int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, + struct v4l2_fmtdesc *f); +int msm_vdec_s_fmt(struct msm_vidc_inst *inst, + struct v4l2_format *f); +int msm_vdec_g_fmt(struct msm_vidc_inst *inst, + struct v4l2_format *f); +int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl); +int msm_vdec_g_ctrl(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl); +int msm_vdec_set_properties(struct msm_vidc_inst *inst); +#endif diff --git a/techpack/video/msm/vidc/msm_venc.c b/techpack/video/msm/vidc/msm_venc.c new file mode 100644 index 0000000000000000000000000000000000000000..0ad13a83343561fef877601cc9974b0eb37ce63f --- /dev/null +++ b/techpack/video/msm/vidc/msm_venc.c @@ -0,0 +1,4821 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ +#include <linux/slab.h> +#include "msm_venc.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "vidc_hfi.h" +#include "vidc_hfi_helper.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" +#include "msm_vidc_buffer_calculations.h" + +#define MIN_BIT_RATE 32000 +#define MAX_BIT_RATE 1200000000 +#define DEFAULT_BIT_RATE 64000 +#define MIN_BIT_RATE_RATIO 0 +#define MAX_BIT_RATE_RATIO 100 +#define MAX_HIER_CODING_LAYER 6 +#define BIT_RATE_STEP 1 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3) +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_MB_SIZE (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) +#define QP_ENABLE_I 0x1 +#define QP_ENABLE_P 0x2 +#define QP_ENABLE_B 0x4 +#define MIN_QP 0 +#define MAX_QP 0x7F +#define MAX_QP_PACKED 0x7F7F7F +#define DEFAULT_QP 0xA +#define DEFAULT_QP_PACKED 0xA0A0A +#define MAX_INTRA_REFRESH_MBS ((7680 * 4320) >> 8) +#define MAX_LTR_FRAME_COUNT 10 +#define MAX_NUM_B_FRAMES 1 +#define MIN_CBRPLUS_W 640 +#define MIN_CBRPLUS_H 480 +#define MAX_CBR_W 1280 +#define MAX_CBR_H 720 +#define LEGACY_CBR_BUF_SIZE 500 +#define CBR_PLUS_BUF_SIZE 1000 +#define MAX_GOP 0xFFFFFFF + +#define MIN_NUM_ENC_OUTPUT_BUFFERS 4 +#define MIN_NUM_ENC_CAPTURE_BUFFERS 5 + +static const char *const mpeg_video_rate_control[] = { + "VBR CFR", + "CBR CFR", + "MBR CFR", + "CBR VFR", + "MBR VFR", + "CQ", + NULL +}; + +static const char *const vp8_profile_level[] = { + "Unused", + "0.0", + "1.0", + "2.0", + "3.0", + NULL +}; + +static const char *const mpeg_video_stream_format[] = { + "NAL Format Start Codes", + "NAL Format One NAL Per Buffer", + "NAL Format One Byte Length", + "NAL Format Two Byte Length", + "NAL Format Four Byte Length", + NULL +}; + +static const char *const roi_map_type[] = { + "None", + "2-bit", + "2-bit", +}; + +static struct msm_vidc_ctrl msm_venc_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDEO_UNKNOWN, + .name = "Invalid control", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, + .name = "Intra Period for P frames", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_GOP, + .default_value = 2*DEFAULT_FPS-1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + .name = "HEVC I Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_QP, + .maximum = MAX_QP, + .default_value = DEFAULT_QP, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + .name = "HEVC P Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_QP, + .maximum = MAX_QP, + .default_value = DEFAULT_QP, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + .name = "HEVC B Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_QP, + .maximum = MAX_QP, + .default_value = DEFAULT_QP, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + .name = "HEVC Quantization Range Minimum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_QP, + .maximum = MAX_QP_PACKED, + .default_value = DEFAULT_QP_PACKED, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + .name = "HEVC Quantization Range Maximum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_QP, + .maximum = MAX_QP_PACKED, + .default_value = DEFAULT_QP_PACKED, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, + .name = "Intra Period for B frames", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_NUM_B_FRAMES, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + .name = "CAPTURE Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = SINGLE_OUTPUT_BUFFER, + .maximum = MAX_NUM_OUTPUT_BUFFERS, + .default_value = SINGLE_OUTPUT_BUFFER, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + .name = "OUTPUT Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = SINGLE_INPUT_BUFFER, + .maximum = MAX_NUM_INPUT_BUFFERS, + .default_value = SINGLE_INPUT_BUFFER, + .step = 1, + .qmenu = NULL, + }, + + { + .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + .name = "Request I Frame", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + .name = "Video Bitrate Control", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + .default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_MBR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + ), + .qmenu = mpeg_video_rate_control, + }, + { + .id = V4L2_CID_MPEG_VIDC_COMPRESSION_QUALITY, + .name = "Compression quality", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_FRAME_QUALITY, + .maximum = MAX_FRAME_QUALITY, + .default_value = DEFAULT_FRAME_QUALITY, + .step = FRAME_QUALITY_STEP, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_IMG_GRID_SIZE, + .name = "Image grid size", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = HEIC_GRID_DIMENSION, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE, + .name = "Frame Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = (MINIMUM_FPS << 16), + .maximum = (MAXIMUM_FPS << 16), + .default_value = (DEFAULT_FPS << 16), + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE, + .name = "Bit Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE, + .maximum = MAX_BIT_RATE, + .default_value = DEFAULT_BIT_RATE, + .step = BIT_RATE_STEP, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + .name = "Entropy Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + ), + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .name = "H264 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .name = "H264 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_6_2) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE, + .name = "VP8 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .maximum = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .default_value = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .menu_skip_mask = ~(1 << V4L2_MPEG_VIDEO_VP8_PROFILE_0), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + .name = "VP8 Profile Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3) + ), + .qmenu = vp8_profile_level, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .name = "HEVC Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .name = "HEVC Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .default_value = + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + (1 << V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, + .name = "HEVC Tier", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_TIER_HIGH) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_ROTATE, + .name = "Rotation", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 270, + .default_value = 0, + .step = 90, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + .name = "Slice Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, + .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) | + (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) + ), + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + .name = "Slice Byte Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_SLICE_BYTE_SIZE, + .maximum = MAX_SLICE_BYTE_SIZE, + .default_value = MIN_SLICE_BYTE_SIZE, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + .name = "Slice MB Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = MAX_SLICE_MB_SIZE, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM, + .name = "Random Intra Refresh MBs", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_INTRA_REFRESH_MBS, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, + .name = "Cyclic Intra Refresh MBs", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_INTRA_REFRESH_MBS, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, + .name = "H.264 Loop Filter Alpha Offset", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, + .name = "H.264 Loop Filter Beta Offset", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + .name = "H.264 Loop Filter Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + .maximum = DB_DISABLE_SLICE_BOUNDARY, + .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + (1 << DB_DISABLE_SLICE_BOUNDARY) + ), + }, + { + .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + .name = "Prepend SPS/PPS to IDR", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE, + .name = "Secure mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA, + .name = "Extradata Type", + .type = V4L2_CTRL_TYPE_BITMASK, + .minimum = EXTRADATA_NONE, + .maximum = EXTRADATA_ADVANCED | EXTRADATA_ENC_INPUT_ROI | + EXTRADATA_ENC_INPUT_HDR10PLUS | + EXTRADATA_ENC_INPUT_CVP, + .default_value = EXTRADATA_NONE, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VUI_TIMING_INFO, + .name = "H264 VUI Timing Info", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER, + .name = "AU Delimiter", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .step = 1, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME, + .name = "H264 Use LTR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = ((1 << MAX_LTR_FRAME_COUNT) - 1), + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT, + .name = "Ltr Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_LTR_FRAME_COUNT, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME, + .name = "H264 Mark LTR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (MAX_LTR_FRAME_COUNT - 1), + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + .name = "Set Hier layers", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_HIER_CODING_LAYER, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER, + .name = "Set Hier max layers", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_0, + .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_6, + .default_value = + V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_0, + .step = 1, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + .name = "Set Hier coding type", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P) + ), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + .name = "Set layer0 QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .default_value = 51, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + .name = "Set layer1 QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .default_value = 51, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + .name = "Set layer2 QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .default_value = 51, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + .name = "Set layer3 QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .default_value = 51, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + .name = "Set layer4 QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .default_value = 51, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + .name = "Set layer5 QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .default_value = 51, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + .name = "Set layer0 BR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE_RATIO, + .maximum = MAX_BIT_RATE_RATIO, + .default_value = MIN_BIT_RATE_RATIO, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + .name = "Set layer1 BR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE_RATIO, + .maximum = MAX_BIT_RATE_RATIO, + .default_value = MIN_BIT_RATE_RATIO, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + .name = "Set layer2 BR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE_RATIO, + .maximum = MAX_BIT_RATE_RATIO, + .default_value = MIN_BIT_RATE_RATIO, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + .name = "Set layer3 BR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE_RATIO, + .maximum = MAX_BIT_RATE_RATIO, + .default_value = MIN_BIT_RATE_RATIO, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + .name = "Set layer4 BR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE_RATIO, + .maximum = MAX_BIT_RATE_RATIO, + .default_value = MIN_BIT_RATE_RATIO, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + .name = "Set layer5 BR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE_RATIO, + .maximum = MAX_BIT_RATE_RATIO, + .default_value = MIN_BIT_RATE_RATIO, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE, + .name = "VP8 Error Resilience mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID, + .name = "Set Base Layer Priority ID for Hier-P", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_BASE_LAYER_PRIORITY_ID, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, + .name = "SAR Width", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 7680, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, + .name = "SAR Height", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 7680, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY, + .name = "Session Priority", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_ENABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE, + .name = "Encoder Operating rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = (DEFAULT_FPS << 16),/* Power Vote min fps */ + .maximum = INT_MAX, + .default_value = (DEFAULT_FPS << 16), + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC, + .name = "Set VPE Color space conversion coefficients", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE, + .name = "Low Latency Mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_DIMENSIONS, + .name = "Set Blur width/height", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = S32_MAX, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + .name = "Transform 8x8", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_ENABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE, + .name = "Set Color space", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_RESERVED_1, + .maximum = MSM_VIDC_BT2020, + .default_value = MSM_VIDC_RESERVED_1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE, + .name = "Set Color space range", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS, + .name = "Set Color space transfer characterstics", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_TRANSFER_BT709_5, + .maximum = MSM_VIDC_TRANSFER_HLG, + .default_value = MSM_VIDC_TRANSFER_601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS, + .name = "Set Color space matrix coefficients", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MSM_VIDC_MATRIX_BT_709_5, + .maximum = MSM_VIDC_MATRIX_BT_2020_CONST, + .default_value = MSM_VIDC_MATRIX_601_6_625, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, + .name = "Frame Rate based Rate Control", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 1, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_RC_TIMESTAMP_DISABLE, + .name = "RC Timestamp disable", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + .name = "Enable/Disable CSC Custom Matrix", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_HFLIP, + .name = "Enable/Disable Horizontal Flip", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_VFLIP, + .name = "Enable/Disable Vertical Flip", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_HDR_INFO, + .name = "HDR PQ information", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + .name = "NAL Format", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4, + .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + (1 << V4L2_MPEG_VIDEO_HEVC_SIZE_4) + ), + .qmenu = mpeg_video_stream_format, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_CVP_DISABLE, + .name = "CVP Disable", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_NATIVE_RECORDER, + .name = "Enable/Disable Native Recorder", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_MSM_VIDC_DISABLE, + .maximum = V4L2_MPEG_MSM_VIDC_ENABLE, + .default_value = V4L2_MPEG_MSM_VIDC_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS, + .name = "Enable/Disable bitrate savings", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 3, + .default_value = 3, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + .name = "Chroma QP Index Offset", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -12, + .maximum = 0, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VBV_DELAY, + .name = "Set Vbv Delay", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1000, + .default_value = 0, + .step = 500, + }, + { + .id = V4L2_CID_MPEG_VIDC_SUPERFRAME, + .name = "Superframe", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = VIDC_SUPERFRAME_MAX, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_CAPTURE_FRAME_RATE, + .name = "Capture Frame Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = (MINIMUM_FPS << 16), + .maximum = (MAXIMUM_FPS << 16), + .default_value = (DEFAULT_FPS << 16), + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_CVP_FRAME_RATE, + .name = "CVP Frame Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = (MINIMUM_FPS << 16), + .maximum = (MAXIMUM_FPS << 16), + .default_value = (DEFAULT_FPS << 16), + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE, + .name = "ROI Type", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_NONE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BYTE, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_NONE, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_NONE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BIT) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BYTE) + ), + .qmenu = roi_map_type, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) + +static struct msm_vidc_format_desc venc_input_formats[] = { + { + .name = "YCbCr Semiplanar 4:2:0", + .description = "Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12, + }, + { + .name = "UBWC YCbCr Semiplanar 4:2:0", + .description = "UBWC Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12_UBWC, + }, + { + .name = "YCrCb Semiplanar 4:2:0", + .description = "Y/CrCb 4:2:0", + .fourcc = V4L2_PIX_FMT_NV21, + }, + { + .name = "TP10 UBWC 4:2:0", + .description = "TP10 UBWC 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC, + }, + { + .name = "YCbCr Semiplanar 4:2:0 10bit", + .description = "Y/CbCr 4:2:0 10bit", + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + }, + { + .name = "YCbCr Semiplanar 4:2:0 512 aligned", + .description = "Y/CbCr 4:2:0 512 aligned", + .fourcc = V4L2_PIX_FMT_NV12_512, + }, +}; + +static struct msm_vidc_format_desc venc_output_formats[] = { + { + .name = "H264", + .description = "H264 compressed format", + .fourcc = V4L2_PIX_FMT_H264, + }, + { + .name = "VP8", + .description = "VP8 compressed format", + .fourcc = V4L2_PIX_FMT_VP8, + }, + { + .name = "HEVC", + .description = "HEVC compressed format", + .fourcc = V4L2_PIX_FMT_HEVC, + }, +}; + +struct msm_vidc_format_constraint enc_pix_format_constraints[] = { + { + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + .num_planes = 2, + .y_max_stride = 8192, + .y_buffer_alignment = 256, + .uv_max_stride = 8192, + .uv_buffer_alignment = 256, + }, + { + .fourcc = V4L2_PIX_FMT_NV12_512, + .num_planes = 2, + .y_max_stride = 16384, + .y_buffer_alignment = 512, + .uv_max_stride = 16384, + .uv_buffer_alignment = 256, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .num_planes = 2, + .y_max_stride = 16384, + .y_buffer_alignment = 512, + .uv_max_stride = 16384, + .uv_buffer_alignment = 256, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .num_planes = 2, + .y_max_stride = 8192, + .y_buffer_alignment = 512, + .uv_max_stride = 8192, + .uv_buffer_alignment = 256, + }, +}; + +u32 v4l2_to_hfi_flip(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *hflip = NULL; + struct v4l2_ctrl *vflip = NULL; + u32 flip = HFI_FLIP_NONE; + + hflip = get_ctrl(inst, V4L2_CID_HFLIP); + vflip = get_ctrl(inst, V4L2_CID_VFLIP); + + if ((hflip->val == V4L2_MPEG_MSM_VIDC_ENABLE) && + (vflip->val == V4L2_MPEG_MSM_VIDC_ENABLE)) + flip = HFI_FLIP_HORIZONTAL | HFI_FLIP_VERTICAL; + else if (hflip->val == V4L2_MPEG_MSM_VIDC_ENABLE) + flip = HFI_FLIP_HORIZONTAL; + else if (vflip->val == V4L2_MPEG_MSM_VIDC_ENABLE) + flip = HFI_FLIP_VERTICAL; + + return flip; +} + +inline bool vidc_scalar_enabled(struct msm_vidc_inst *inst) +{ + struct v4l2_format *f; + u32 output_height, output_width, input_height, input_width; + bool scalar_enable = false; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_height = f->fmt.pix_mp.height; + output_width = f->fmt.pix_mp.width; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + input_height = f->fmt.pix_mp.height; + input_width = f->fmt.pix_mp.width; + + if (output_height != input_height || output_width != input_width) + scalar_enable = true; + + return scalar_enable; +} + + +static int msm_venc_set_csc(struct msm_vidc_inst *inst, + u32 color_primaries, u32 custom_matrix); + +int msm_venc_inst_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_format_desc *fmt_desc = NULL; + struct v4l2_format *f = NULL; + uint32_t vpu; + + if (!inst) { + d_vpr_e("Invalid input = %pK\n", inst); + return -EINVAL; + } + vpu = inst->core->platform_data->vpu_ver; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_enc_output_frame_size(inst); + fmt_desc = msm_comm_get_pixel_fmt_fourcc(venc_output_formats, + ARRAY_SIZE(venc_output_formats), + f->fmt.pix_mp.pixelformat, inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(inst->fmts[OUTPUT_PORT].name, fmt_desc->name, + sizeof(inst->fmts[OUTPUT_PORT].name)); + strlcpy(inst->fmts[OUTPUT_PORT].description, fmt_desc->description, + sizeof(inst->fmts[OUTPUT_PORT].description)); + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12_UBWC; + f->fmt.pix_mp.num_planes = 1; + if (vpu == VPU_VERSION_IRIS2) + f->fmt.pix_mp.num_planes = 2; + f->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_enc_input_frame_size(inst); + f->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_input_extra_size(inst); + fmt_desc = msm_comm_get_pixel_fmt_fourcc(venc_input_formats, + ARRAY_SIZE(venc_input_formats), f->fmt.pix_mp.pixelformat, + inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(inst->fmts[INPUT_PORT].name, fmt_desc->name, + sizeof(inst->fmts[INPUT_PORT].name)); + strlcpy(inst->fmts[INPUT_PORT].description, fmt_desc->description, + sizeof(inst->fmts[INPUT_PORT].description)); + inst->prop.bframe_changed = false; + inst->prop.extradata_ctrls = EXTRADATA_NONE; + inst->buffer_mode_set[INPUT_PORT] = HAL_BUFFER_MODE_DYNAMIC; + inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC; + inst->clk_data.frame_rate = (DEFAULT_FPS << 16); + + inst->clk_data.operating_rate = (DEFAULT_FPS << 16); + inst->clk_data.is_legacy_cbr = false; + + inst->buff_req.buffer[1].buffer_type = HAL_BUFFER_INPUT; + inst->buff_req.buffer[1].buffer_count_min_host = + inst->buff_req.buffer[1].buffer_count_actual = + MIN_NUM_ENC_OUTPUT_BUFFERS; + inst->buff_req.buffer[2].buffer_type = HAL_BUFFER_OUTPUT; + inst->buff_req.buffer[2].buffer_count_min_host = + inst->buff_req.buffer[2].buffer_count_actual = + MIN_NUM_ENC_CAPTURE_BUFFERS; + inst->buff_req.buffer[3].buffer_type = HAL_BUFFER_OUTPUT2; + inst->buff_req.buffer[3].buffer_count_min_host = + inst->buff_req.buffer[3].buffer_count_actual = + MIN_NUM_ENC_CAPTURE_BUFFERS; + inst->buff_req.buffer[4].buffer_type = HAL_BUFFER_EXTRADATA_INPUT; + inst->buff_req.buffer[5].buffer_type = HAL_BUFFER_EXTRADATA_OUTPUT; + inst->buff_req.buffer[6].buffer_type = HAL_BUFFER_EXTRADATA_OUTPUT2; + inst->buff_req.buffer[7].buffer_type = HAL_BUFFER_INTERNAL_SCRATCH; + inst->buff_req.buffer[8].buffer_type = HAL_BUFFER_INTERNAL_SCRATCH_1; + inst->buff_req.buffer[9].buffer_type = HAL_BUFFER_INTERNAL_SCRATCH_2; + inst->buff_req.buffer[10].buffer_type = HAL_BUFFER_INTERNAL_PERSIST; + inst->buff_req.buffer[11].buffer_type = HAL_BUFFER_INTERNAL_PERSIST_1; + inst->buff_req.buffer[12].buffer_type = HAL_BUFFER_INTERNAL_CMD_QUEUE; + inst->buff_req.buffer[13].buffer_type = HAL_BUFFER_INTERNAL_RECON; + msm_vidc_init_buffer_size_calculators(inst); + inst->static_rotation_flip_enabled = false; + return rc; +} + +int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + const struct msm_vidc_format_desc *fmt_desc = NULL; + int rc = 0; + + if (!inst || !f) { + d_vpr_e("Invalid input, inst = %pK, f = %pK\n", inst, f); + return -EINVAL; + } + if (f->type == OUTPUT_MPLANE) { + fmt_desc = msm_comm_get_pixel_fmt_index(venc_output_formats, + ARRAY_SIZE(venc_output_formats), f->index, inst->sid); + } else if (f->type == INPUT_MPLANE) { + fmt_desc = msm_comm_get_pixel_fmt_index(venc_input_formats, + ARRAY_SIZE(venc_input_formats), f->index, inst->sid); + f->flags = V4L2_FMT_FLAG_COMPRESSED; + } + + memset(f->reserved, 0, sizeof(f->reserved)); + if (fmt_desc) { + strlcpy(f->description, fmt_desc->description, + sizeof(f->description)); + f->pixelformat = fmt_desc->fourcc; + } else { + s_vpr_h(inst->sid, "No more formats found\n"); + rc = -EINVAL; + } + return rc; +} + +static int msm_venc_set_csc(struct msm_vidc_inst *inst, + u32 color_primaries, u32 custom_matrix) +{ + int rc = 0; + int count = 0; + struct hfi_vpe_color_space_conversion vpe_csc; + struct msm_vidc_platform_resources *resources; + u32 *bias_coeff = NULL; + u32 *csc_limit = NULL; + u32 *csc_matrix = NULL; + struct hfi_device *hdev; + + hdev = inst->core->device; + resources = &(inst->core->resources); + bias_coeff = + resources->csc_coeff_data->vpe_csc_custom_bias_coeff; + csc_limit = + resources->csc_coeff_data->vpe_csc_custom_limit_coeff; + csc_matrix = + resources->csc_coeff_data->vpe_csc_custom_matrix_coeff; + + vpe_csc.input_color_primaries = color_primaries; + /* Custom bias, matrix & limit */ + vpe_csc.custom_matrix_enabled = custom_matrix ? 7 : 0; + + if (vpe_csc.custom_matrix_enabled && bias_coeff != NULL + && csc_limit != NULL && csc_matrix != NULL) { + while (count < HAL_MAX_MATRIX_COEFFS) { + if (count < HAL_MAX_BIAS_COEFFS) + vpe_csc.csc_bias[count] = + bias_coeff[count]; + if (count < HAL_MAX_LIMIT_COEFFS) + vpe_csc.csc_limit[count] = + csc_limit[count]; + vpe_csc.csc_matrix[count] = + csc_matrix[count]; + count = count + 1; + } + } + + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION, + &vpe_csc, sizeof(vpe_csc)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; +} + +int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct msm_vidc_format *fmt = NULL; + struct msm_vidc_format_desc *fmt_desc = NULL; + struct v4l2_pix_format_mplane *mplane = NULL; + u32 color_format; + + if (!inst || !f) { + d_vpr_e("Invalid input, inst = %pK, format = %pK\n", inst, f); + return -EINVAL; + } + + /* + * First update inst format with new width/height/format + * Recalculate sizes/strides etc + * Perform necessary checks to continue with session + * Copy recalculated info into user format + */ + if (f->type == OUTPUT_MPLANE) { + fmt = &inst->fmts[OUTPUT_PORT]; + fmt_desc = msm_comm_get_pixel_fmt_fourcc(venc_output_formats, + ARRAY_SIZE(venc_output_formats), + f->fmt.pix_mp.pixelformat, inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(fmt->name, fmt_desc->name, sizeof(fmt->name)); + strlcpy(fmt->description, fmt_desc->description, + sizeof(fmt->description)); + + fmt->v4l2_fmt.type = f->type; + mplane = &fmt->v4l2_fmt.fmt.pix_mp; + mplane->width = f->fmt.pix_mp.width; + mplane->height = f->fmt.pix_mp.height; + mplane->pixelformat = f->fmt.pix_mp.pixelformat; + + if (!inst->profile) { + rc = msm_venc_set_default_profile(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: Failed to set default profile type\n", + __func__); + goto exit; + } + } + + rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); + if (rc) { + s_vpr_e(inst->sid, "Failed to open instance\n"); + goto exit; + } + + mplane->plane_fmt[0].sizeimage = + msm_vidc_calculate_enc_output_frame_size(inst); + if (mplane->num_planes > 1) + mplane->plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_output_extra_size(inst); + + rc = msm_vidc_check_session_supported(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: session not supported\n", __func__); + goto exit; + } + update_log_ctxt(inst->sid, inst->session_type, + mplane->pixelformat); + memcpy(f, &fmt->v4l2_fmt, sizeof(struct v4l2_format)); + } else if (f->type == INPUT_MPLANE) { + fmt = &inst->fmts[INPUT_PORT]; + fmt_desc = msm_comm_get_pixel_fmt_fourcc(venc_input_formats, + ARRAY_SIZE(venc_input_formats), + f->fmt.pix_mp.pixelformat, inst->sid); + if (!fmt_desc) { + s_vpr_e(inst->sid, "Invalid fmt set : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + strlcpy(fmt->name, fmt_desc->name, sizeof(fmt->name)); + strlcpy(fmt->description, fmt_desc->description, + sizeof(fmt->description)); + + inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat; + + fmt->v4l2_fmt.type = f->type; + mplane = &fmt->v4l2_fmt.fmt.pix_mp; + mplane->width = f->fmt.pix_mp.width; + mplane->height = f->fmt.pix_mp.height; + mplane->pixelformat = f->fmt.pix_mp.pixelformat; + mplane->plane_fmt[0].sizeimage = + msm_vidc_calculate_enc_input_frame_size(inst); + if (mplane->num_planes > 1) + mplane->plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_input_extra_size(inst); + color_format = msm_comm_convert_color_fmt( + f->fmt.pix_mp.pixelformat, inst->sid); + mplane->plane_fmt[0].bytesperline = + VENUS_Y_STRIDE(color_format, f->fmt.pix_mp.width); + mplane->plane_fmt[0].reserved[0] = + VENUS_Y_SCANLINES(color_format, f->fmt.pix_mp.height); + inst->bit_depth = MSM_VIDC_BIT_DEPTH_8; + if ((f->fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_NV12_TP10_UBWC) || + (f->fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS)) { + inst->bit_depth = MSM_VIDC_BIT_DEPTH_10; + } + + rc = msm_vidc_calculate_buffer_counts(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s failed to calculate buffer count\n", + __func__); + return rc; + } + + rc = msm_vidc_check_session_supported(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: session not supported\n", __func__); + goto exit; + } + + memcpy(f, &fmt->v4l2_fmt, sizeof(struct v4l2_format)); + } else { + s_vpr_e(inst->sid, "%s: Unsupported buf type: %d\n", + __func__, f->type); + rc = -EINVAL; + goto exit; + } +exit: + return rc; +} + +int msm_venc_set_default_profile(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_HEVC) + inst->profile = HFI_HEVC_PROFILE_MAIN; + else if (get_v4l2_codec(inst) == V4L2_PIX_FMT_VP8) + inst->profile = HFI_VP8_PROFILE_MAIN; + else if (get_v4l2_codec(inst) == V4L2_PIX_FMT_H264) + inst->profile = HFI_H264_PROFILE_HIGH; + else + s_vpr_e(inst->sid, "%s: Invalid codec type %#x\n", + __func__, get_v4l2_codec(inst)); + return 0; +} + +int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt; + + if (f->type == OUTPUT_MPLANE) { + fmt = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_enc_output_frame_size(inst); + if (fmt->fmt.pix_mp.num_planes > 1) + fmt->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_output_extra_size(inst); + memcpy(f, fmt, sizeof(struct v4l2_format)); + } else if (f->type == INPUT_MPLANE) { + fmt = &inst->fmts[INPUT_PORT].v4l2_fmt; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = + msm_vidc_calculate_enc_input_frame_size(inst); + if (fmt->fmt.pix_mp.num_planes > 1) { + fmt->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_input_extra_size(inst); + } + memcpy(f, fmt, sizeof(struct v4l2_format)); + } else { + s_vpr_e(inst->sid, "%s: Unsupported buf type: %d\n", + __func__, f->type); + return -EINVAL; + } + + return 0; +} + +int msm_venc_ctrl_init(struct msm_vidc_inst *inst, + const struct v4l2_ctrl_ops *ctrl_ops) +{ + return msm_comm_ctrl_init(inst, msm_venc_ctrls, + ARRAY_SIZE(msm_venc_ctrls), ctrl_ops); +} + +static int msm_venc_resolve_rc_enable(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl) +{ + struct v4l2_ctrl *rc_mode; + u32 codec; + + if (!ctrl->val) { + s_vpr_h(inst->sid, "RC is not enabled. Setting RC OFF\n"); + inst->rc_type = RATE_CONTROL_OFF; + } else { + rc_mode = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + inst->rc_type = rc_mode->val; + } + + codec = get_v4l2_codec(inst); + if (msm_vidc_lossless_encode + && (codec == V4L2_PIX_FMT_HEVC || + codec == V4L2_PIX_FMT_H264)) { + s_vpr_h(inst->sid, + "Reset RC mode to RC_LOSSLESS for HEVC lossless encoding\n"); + inst->rc_type = RATE_CONTROL_LOSSLESS; + } + return 0; +} + +static int msm_venc_resolve_rate_control(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl) +{ + if (inst->rc_type == RATE_CONTROL_LOSSLESS) { + s_vpr_h(inst->sid, + "Skip RC mode when enabling lossless encoding\n"); + return 0; + } + + if (inst->rc_type == RATE_CONTROL_OFF) { + s_vpr_e(inst->sid, "RC is not enabled.\n"); + return -EINVAL; + } + + if ((ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) && + get_v4l2_codec(inst) != V4L2_PIX_FMT_HEVC) { + s_vpr_e(inst->sid, "CQ supported only for HEVC\n"); + return -EINVAL; + } + inst->rc_type = ctrl->val; + return 0; +} + +static int msm_venc_update_bitrate(struct msm_vidc_inst *inst) +{ + u32 cabac_max_bitrate = 0; + + if (!inst) { + d_vpr_e("%s: invalid params %pK\n", __func__); + return -EINVAL; + } + + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_H264) { + cabac_max_bitrate = inst->capability.cap[CAP_CABAC_BITRATE].max; + if ((inst->clk_data.bitrate > cabac_max_bitrate) && + (inst->entropy_mode == HFI_H264_ENTROPY_CABAC)) { + s_vpr_h(inst->sid, + "%s: update bitrate %u to max allowed cabac bitrate %u\n", + __func__, inst->clk_data.bitrate, + cabac_max_bitrate); + inst->clk_data.bitrate = cabac_max_bitrate; + } + } + return 0; +} + +int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + struct msm_vidc_mastering_display_colour_sei_payload *mdisp_sei = NULL; + struct msm_vidc_content_light_level_sei_payload *cll_sei = NULL; + u32 i_qp_min, i_qp_max, p_qp_min, p_qp_max, b_qp_min, b_qp_max; + struct v4l2_format *f; + u32 codec; + u32 sid; + + if (!inst || !inst->core || !inst->core->device || !ctrl) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + mdisp_sei = &(inst->hdr10_sei_params.disp_color_sei); + cll_sei = &(inst->hdr10_sei_params.cll_sei); + codec = get_v4l2_codec(inst); + sid = inst->sid; + + s_vpr_h(sid, "%s: name %s, id 0x%x value %d\n", + __func__, ctrl->name, ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + if (inst->state == MSM_VIDC_START_DONE) { + if (inst->all_intra) { + s_vpr_h(sid, + "%s: ignore dynamic gop size for all intra\n", + __func__); + break; + } + rc = msm_venc_set_intra_period(inst); + if (rc) + s_vpr_e(sid, "%s: set intra period failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_request_keyframe(inst); + if (rc) + s_vpr_e(sid, "%s: set bitrate failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + { + rc = msm_venc_resolve_rate_control(inst, ctrl); + if (rc) + s_vpr_e(sid, "%s: set bitrate mode failed\n", __func__); + if (inst->state < MSM_VIDC_LOAD_RESOURCES) + msm_vidc_calculate_buffer_counts(inst); + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE: + inst->clk_data.bitrate = ctrl->val; + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_update_bitrate(inst); + if (rc) + s_vpr_e(sid, "%s: Update bitrate failed\n", + __func__); + rc = msm_venc_set_bitrate(inst); + if (rc) + s_vpr_e(sid, "%s: set bitrate failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE: + inst->clk_data.frame_rate = ctrl->val; + /* For HEIC image encode, set fps to 1 */ + if (is_grid_session(inst)) { + s_vpr_h(sid, "%s: set fps to 1 for HEIC\n", + __func__); + inst->clk_data.frame_rate = 1 << 16; + } + if (inst->state < MSM_VIDC_LOAD_RESOURCES) + msm_vidc_calculate_buffer_counts(inst); + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_frame_rate(inst); + if (rc) + s_vpr_e(sid, "%s: set frame rate failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + if (codec != V4L2_PIX_FMT_HEVC && codec != V4L2_PIX_FMT_H264) { + s_vpr_e(sid, + "Slice mode not supported for encoder %#x\n", + codec); + rc = -ENOTSUPP; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE: + inst->flags &= ~VIDC_SECURE; + if (ctrl->val) + inst->flags |= VIDC_SECURE; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + f->fmt.pix_mp.num_planes = 1; + s_vpr_h(sid, "%s: num planes %d for secure sessions\n", + __func__, f->fmt.pix_mp.num_planes); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_ltr_useframe(inst); + if (rc) + s_vpr_e(sid, "%s: ltr useframe failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_ltr_markframe(inst); + if (rc) + s_vpr_e(sid, "%s: ltr markframe failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE: + if (!is_valid_operating_rate(inst, ctrl->val)) + break; + inst->flags &= ~VIDC_TURBO; + if (ctrl->val == INT_MAX) + inst->flags |= VIDC_TURBO; + else + inst->clk_data.operating_rate = ctrl->val; + /* For HEIC image encode, set operating rate to 1 */ + if (is_grid_session(inst)) { + s_vpr_h(sid, "%s: set operating rate to 1 for HEIC\n", + __func__); + inst->clk_data.operating_rate = 1 << 16; + } + if (inst->state < MSM_VIDC_LOAD_RESOURCES) + msm_vidc_calculate_buffer_counts(inst); + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_operating_rate(inst); + if (rc) + s_vpr_e(sid, "%s: set operating rate failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE: + inst->clk_data.low_latency_mode = !!ctrl->val; + break; + case V4L2_CID_MPEG_VIDC_VENC_HDR_INFO: { + u32 info_type = ((u32)ctrl->val >> 28) & 0xF; + u32 val = (ctrl->val & 0xFFFFFFF); + + s_vpr_h(sid, "Ctrl:%d, HDR Info with value %u (%#X)", + info_type, val, ctrl->val); + switch (info_type) { + case MSM_VIDC_RGB_PRIMARY_00: + mdisp_sei->nDisplayPrimariesX[0] = val; + break; + case MSM_VIDC_RGB_PRIMARY_01: + mdisp_sei->nDisplayPrimariesY[0] = val; + break; + case MSM_VIDC_RGB_PRIMARY_10: + mdisp_sei->nDisplayPrimariesX[1] = val; + break; + case MSM_VIDC_RGB_PRIMARY_11: + mdisp_sei->nDisplayPrimariesY[1] = val; + break; + case MSM_VIDC_RGB_PRIMARY_20: + mdisp_sei->nDisplayPrimariesX[2] = val; + break; + case MSM_VIDC_RGB_PRIMARY_21: + mdisp_sei->nDisplayPrimariesY[2] = val; + break; + case MSM_VIDC_WHITEPOINT_X: + mdisp_sei->nWhitePointX = val; + break; + case MSM_VIDC_WHITEPOINT_Y: + mdisp_sei->nWhitePointY = val; + break; + case MSM_VIDC_MAX_DISP_LUM: + mdisp_sei->nMaxDisplayMasteringLuminance = val; + break; + case MSM_VIDC_MIN_DISP_LUM: + mdisp_sei->nMinDisplayMasteringLuminance = val; + break; + case MSM_VIDC_RGB_MAX_CLL: + cll_sei->nMaxContentLight = val; + break; + case MSM_VIDC_RGB_MAX_FLL: + cll_sei->nMaxPicAverageLight = val; + break; + default: + s_vpr_e(sid, + "Unknown Ctrl:%d, not part of HDR Info with value %u", + info_type, val); + } + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: + if (ctrl->val == EXTRADATA_NONE) + inst->prop.extradata_ctrls = 0; + else + inst->prop.extradata_ctrls |= ctrl->val; + + if ((inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_ROI) || + (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_HDR10PLUS)) { + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + f->fmt.pix_mp.num_planes = 2; + f->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_input_extra_size(inst); + } + + if (inst->prop.extradata_ctrls & EXTRADATA_ADVANCED) { + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + f->fmt.pix_mp.num_planes = 2; + f->fmt.pix_mp.plane_fmt[1].sizeimage = + msm_vidc_calculate_enc_output_extra_size(inst); + } + + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + rc = msm_venc_resolve_rc_enable(inst, ctrl); + if (rc) + s_vpr_e(sid, "%s: set rc enable failed\n", __func__); + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + inst->profile = msm_comm_v4l2_to_hfi(ctrl->id, ctrl->val, sid); + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + inst->level = msm_comm_v4l2_to_hfi(ctrl->id, ctrl->val, sid); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + inst->level |= + (msm_comm_v4l2_to_hfi(ctrl->id, ctrl->val, sid) << 28); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + i_qp_min = inst->capability.cap[CAP_I_FRAME_QP].min; + i_qp_max = inst->capability.cap[CAP_I_FRAME_QP].max; + p_qp_min = inst->capability.cap[CAP_P_FRAME_QP].min; + p_qp_max = inst->capability.cap[CAP_P_FRAME_QP].max; + b_qp_min = inst->capability.cap[CAP_B_FRAME_QP].min; + b_qp_max = inst->capability.cap[CAP_B_FRAME_QP].max; + if ((ctrl->val & 0xff) < i_qp_min || + ((ctrl->val >> 8) & 0xff) < p_qp_min || + ((ctrl->val >> 16) & 0xff) < b_qp_min || + (ctrl->val & 0xff) > i_qp_max || + ((ctrl->val >> 8) & 0xff) > p_qp_max || + ((ctrl->val >> 16) & 0xff) > b_qp_max) { + s_vpr_e(sid, "Invalid QP %#x\n", ctrl->val); + return -EINVAL; + } + if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP) + inst->client_set_ctrls |= CLIENT_SET_MIN_QP; + else + inst->client_set_ctrls |= CLIENT_SET_MAX_QP; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + i_qp_min = inst->capability.cap[CAP_I_FRAME_QP].min; + i_qp_max = inst->capability.cap[CAP_I_FRAME_QP].max; + if (ctrl->val < i_qp_min || ctrl->val > i_qp_max) { + s_vpr_e(sid, "Invalid I QP %#x\n", ctrl->val); + return -EINVAL; + } + inst->client_set_ctrls |= CLIENT_SET_I_QP; + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_dyn_qp(inst, ctrl); + if (rc) + s_vpr_e(sid, + "%s: setting dyn frame QP failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + p_qp_min = inst->capability.cap[CAP_P_FRAME_QP].min; + p_qp_max = inst->capability.cap[CAP_P_FRAME_QP].max; + if (ctrl->val < p_qp_min || ctrl->val > p_qp_max) { + s_vpr_e(sid, "Invalid P QP %#x\n", ctrl->val); + return -EINVAL; + } + inst->client_set_ctrls |= CLIENT_SET_P_QP; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + b_qp_min = inst->capability.cap[CAP_B_FRAME_QP].min; + b_qp_max = inst->capability.cap[CAP_B_FRAME_QP].max; + if (ctrl->val < b_qp_min || ctrl->val > b_qp_max) { + s_vpr_e(sid, "Invalid B QP %#x\n", ctrl->val); + return -EINVAL; + } + inst->client_set_ctrls |= CLIENT_SET_B_QP; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_hp_layer(inst); + if (rc) + s_vpr_e(sid, "%s: set dyn hp layer failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_base_layer_priority_id(inst); + if (rc) + s_vpr_e(sid, "%s: set baselayer id failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_layer_bitrate(inst); + if (rc) + s_vpr_e(sid, "%s: set layer bitrate failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + if (inst->state == MSM_VIDC_START_DONE) { + s_vpr_e(sid, + "%s: Dynamic setting of Bframe is not supported\n", + __func__); + return -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_DIMENSIONS: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_blur_resolution(inst); + if (rc) + s_vpr_e(sid, "%s: set blur resolution failed\n", + __func__); + } + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_dynamic_flip(inst); + if (rc) + s_vpr_e(sid, "%s: set flip failed\n", __func__); + } + break; + case V4L2_CID_MPEG_VIDC_CVP_FRAME_RATE: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_cvp_skipratio(inst); + if (rc) + s_vpr_e(sid, + "%s: set cvp skip ratio failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_COMPRESSION_QUALITY: + if (inst->state == MSM_VIDC_START_DONE) { + rc = msm_venc_set_frame_quality(inst); + if (rc) + s_vpr_e(sid, + "%s: set frame quality failed\n", + __func__); + } + break; + case V4L2_CID_MPEG_VIDC_IMG_GRID_SIZE: + /* For HEIC image encode, set fps to 1 */ + if (ctrl->val) { + s_vpr_h(sid, "%s: set fps to 1 for HEIC\n", + __func__); + inst->clk_data.frame_rate = 1 << 16; + s_vpr_h(sid, "%s: set operating rate to 1 for HEIC\n", + __func__); + inst->clk_data.operating_rate = 1 << 16; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE: + inst->full_range = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + inst->entropy_mode = msm_comm_v4l2_to_hfi( + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + ctrl->val, inst->sid); + break; + case V4L2_CID_MPEG_VIDC_CAPTURE_FRAME_RATE: + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + case V4L2_CID_ROTATE: + case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT: + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + case V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER: + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + case V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: + case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE: + case V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS: + case V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS: + case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC: + case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX: + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + case V4L2_CID_MPEG_VIDC_VIDEO_VUI_TIMING_INFO: + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: + case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY: + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM: + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: + case V4L2_CID_MPEG_VIDC_VENC_CVP_DISABLE: + case V4L2_CID_MPEG_VIDC_VENC_NATIVE_RECORDER: + case V4L2_CID_MPEG_VIDC_VENC_RC_TIMESTAMP_DISABLE: + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: + case V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS: + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + case V4L2_CID_MPEG_VIDC_SUPERFRAME: + s_vpr_h(sid, "Control set: ID : 0x%x Val : %d\n", + ctrl->id, ctrl->val); + break; + default: + s_vpr_e(sid, "Unsupported index: 0x%x\n", ctrl->id); + rc = -ENOTSUPP; + break; + } + + return rc; +} + +int msm_venc_set_frame_size(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_frame_size frame_sz; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + frame_sz.buffer_type = HFI_BUFFER_INPUT; + frame_sz.width = f->fmt.pix_mp.width; + frame_sz.height = f->fmt.pix_mp.height; + s_vpr_h(inst->sid, "%s: input %d %d\n", __func__, + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_FRAME_SIZE, &frame_sz, sizeof(frame_sz)); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to set input frame size %d %d\n", + __func__, frame_sz.width, frame_sz.height); + return rc; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + frame_sz.buffer_type = HFI_BUFFER_OUTPUT; + frame_sz.width = f->fmt.pix_mp.width; + frame_sz.height = f->fmt.pix_mp.height; + /* firmware needs grid size in output where as + * client sends out full resolution in output port */ + if (is_grid_session(inst)) { + frame_sz.width = frame_sz.height = HEIC_GRID_DIMENSION; + } + s_vpr_h(inst->sid, "%s: output %d %d\n", __func__, + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_FRAME_SIZE, &frame_sz, sizeof(frame_sz)); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed to set output frame size %d %d\n", + __func__, frame_sz.width, frame_sz.height); + return rc; + } + + return rc; +} + +int msm_venc_set_frame_rate(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_frame_rate frame_rate; + struct msm_vidc_capability *capability; + u32 fps_max; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + capability = &inst->capability; + + /* Check frame rate */ + if (inst->all_intra) + fps_max = capability->cap[CAP_ALLINTRA_MAX_FPS].max; + else + fps_max = capability->cap[CAP_FRAMERATE].max; + + if (inst->clk_data.frame_rate >> 16 > fps_max) { + s_vpr_e(inst->sid, + "%s: Unsupported frame rate, fps %u, max_fps %u\n", + __func__, inst->clk_data.frame_rate >> 16, fps_max); + return -ENOTSUPP; + } + + frame_rate.buffer_type = HFI_BUFFER_OUTPUT; + frame_rate.frame_rate = inst->clk_data.frame_rate; + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, frame_rate.frame_rate); + + rc = call_hfi_op(hdev, session_set_property, + inst->session, HFI_PROPERTY_CONFIG_FRAME_RATE, + &frame_rate, sizeof(frame_rate)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_color_format(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_format_constraint *fmt_constraints; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + rc = msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, + f->fmt.pix_mp.pixelformat); + if (rc) + return rc; + + fmt_constraints = msm_comm_get_pixel_fmt_constraints( + enc_pix_format_constraints, + ARRAY_SIZE(enc_pix_format_constraints), + f->fmt.pix_mp.pixelformat, inst->sid); + if (fmt_constraints) { + rc = msm_comm_set_color_format_constraints(inst, + HAL_BUFFER_INPUT, + fmt_constraints); + if (rc) { + s_vpr_e(inst->sid, "Set constraints for %d failed\n", + f->fmt.pix_mp.pixelformat); + return rc; + } + } + + return rc; +} + +int msm_venc_set_buffer_counts(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_format *fmt; + enum hal_buffer buffer_type; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + buffer_type = HAL_BUFFER_INPUT; + fmt = &inst->fmts[INPUT_PORT]; + rc = msm_comm_set_buffer_count(inst, + fmt->count_min, + fmt->count_actual, + buffer_type); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to set bufcounts(%#x)\n", + __func__, buffer_type); + return -EINVAL; + } + + buffer_type = HAL_BUFFER_OUTPUT; + fmt = &inst->fmts[OUTPUT_PORT]; + rc = msm_comm_set_buffer_count(inst, + fmt->count_min, + fmt->count_actual, + buffer_type); + if (rc) { + s_vpr_e(inst->sid, "%s: failed to set buf counts(%#x)\n", + __func__, buffer_type); + return -EINVAL; + } + + return rc; +} + +int msm_venc_set_secure_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_enable enable; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_SECURE); + enable.enable = !!ctrl->val; + + if (enable.enable) { + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_H264 || + codec == V4L2_PIX_FMT_HEVC)) { + s_vpr_e(inst->sid, + "%s: Secure mode only allowed for HEVC/H264\n", + __func__); + return -EINVAL; + } + } + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_SECURE_SESSION, &enable, sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_priority(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_enable enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + enable.enable = is_realtime_session(inst); + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_REALTIME, &enable, sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_operating_rate(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_operating_rate op_rate; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + if (!inst->core->resources.cvp_internal) + return 0; + + hdev = inst->core->device; + op_rate.operating_rate = inst->clk_data.operating_rate; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, op_rate.operating_rate >> 16); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_OPERATING_RATE, &op_rate, sizeof(op_rate)); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +int msm_venc_set_profile_level(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_profile_level profile_level; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (!inst->profile) { + s_vpr_e(inst->sid, "%s: skip as client did not set profile\n", + __func__); + return -EINVAL; + } + profile_level.profile = inst->profile; + profile_level.level = inst->level; + + s_vpr_h(inst->sid, "%s: %#x %#x\n", __func__, + profile_level.profile, profile_level.level); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, &profile_level, + sizeof(profile_level)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_idr_period(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_idr_period idr_period; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_H264 && codec != V4L2_PIX_FMT_HEVC) + return 0; + + idr_period.idr_period = 1; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, idr_period.idr_period); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD, &idr_period, + sizeof(idr_period)); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +void msm_venc_decide_bframe(struct msm_vidc_inst *inst) +{ + u32 width; + u32 height; + u32 num_mbs_per_frame, num_mbs_per_sec; + struct v4l2_ctrl *ctrl; + struct v4l2_ctrl *bframe_ctrl; + struct msm_vidc_platform_resources *res; + struct v4l2_format *f; + + res = &inst->core->resources; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + bframe_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + num_mbs_per_frame = NUM_MBS_PER_FRAME(width, height); + if (num_mbs_per_frame > res->max_bframe_mbs_per_frame) + goto disable_bframe; + + num_mbs_per_sec = num_mbs_per_frame * + (inst->clk_data.frame_rate >> 16); + if (num_mbs_per_sec > res->max_bframe_mbs_per_sec) + goto disable_bframe; + + ctrl = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + if (ctrl->val > 1) + goto disable_bframe; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + if (ctrl->val) + goto disable_bframe; + + if (inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + goto disable_bframe; + + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_H264) { + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_PROFILE); + if ((ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) && + (ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)) + goto disable_bframe; + } else if (get_v4l2_codec(inst) != V4L2_PIX_FMT_HEVC) + goto disable_bframe; + + if (inst->clk_data.low_latency_mode) + goto disable_bframe; + + if (!bframe_ctrl->val) { + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VENC_NATIVE_RECORDER); + if (ctrl->val) { + /* + * Native recorder is enabled and bframe is not enabled + * Hence, forcefully enable bframe + */ + inst->prop.bframe_changed = true; + update_ctrl(bframe_ctrl, MAX_NUM_B_FRAMES, inst->sid); + s_vpr_h(inst->sid, "Bframe is forcefully enabled\n"); + } else { + /* + * Native recorder is not enabled + * B-Frame is not enabled by client + */ + goto disable_bframe; + } + } + + /* do not enable bframe if superframe is enabled */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + goto disable_bframe; + + s_vpr_h(inst->sid, "Bframe can be enabled!\n"); + + return; +disable_bframe: + if (bframe_ctrl->val) { + /* + * Client wanted to enable bframe but, + * conditions to enable are not met + * Hence, forcefully disable bframe + */ + inst->prop.bframe_changed = true; + update_ctrl(bframe_ctrl, 0, inst->sid); + s_vpr_h(inst->sid, "Bframe is forcefully disabled!\n"); + } else { + s_vpr_h(inst->sid, "Bframe is disabled\n"); + } +} + +int msm_venc_set_adaptive_bframes(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_enable enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + enable.enable = true; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_ADAPTIVE_B, &enable, sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +void msm_venc_adjust_gop_size(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *hier_ctrl; + struct v4l2_ctrl *bframe_ctrl; + struct v4l2_ctrl *gop_size_ctrl; + s32 val; + + gop_size_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_GOP_SIZE); + if (inst->prop.bframe_changed) { + /* + * BFrame size was explicitly change + * Hence, adjust GOP size accordingly + */ + bframe_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + if (!bframe_ctrl->val) + /* Forcefully disabled */ + val = gop_size_ctrl->val * (1 + MAX_NUM_B_FRAMES); + else + /* Forcefully enabled */ + val = gop_size_ctrl->val / (1 + MAX_NUM_B_FRAMES); + + update_ctrl(gop_size_ctrl, val, inst->sid); + } + + /* + * Layer encoding needs GOP size to be multiple of subgop size + * And subgop size is 2 ^ number of enhancement layers + */ + hier_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + if (hier_ctrl->val > 1) { + u32 min_gop_size; + u32 num_subgops; + + min_gop_size = (1 << (hier_ctrl->val - 1)); + num_subgops = (gop_size_ctrl->val + (min_gop_size >> 1)) / + min_gop_size; + if (num_subgops) + val = num_subgops * min_gop_size; + else + val = min_gop_size; + + update_ctrl(gop_size_ctrl, val, inst->sid); + } +} + +int msm_venc_set_intra_period(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_intra_period intra_period; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + msm_venc_adjust_gop_size(inst); + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_GOP_SIZE); + intra_period.pframes = ctrl->val; + + /* + * At this point we have already made decision on bframe + * Control value gives updated bframe value. + */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + intra_period.bframes = ctrl->val; + + if (inst->state == MSM_VIDC_START_DONE && + !intra_period.pframes && !intra_period.bframes) { + s_vpr_h(inst->sid, + "%s: Switch from IPPP to All Intra is not allowed\n", + __func__); + return rc; + } + + s_vpr_h(inst->sid, "%s: %d %d\n", __func__, intra_period.pframes, + intra_period.bframes); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD, &intra_period, + sizeof(intra_period)); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; + } + + if (intra_period.bframes) { + /* Enable adaptive bframes as nbframes!= 0 */ + rc = msm_venc_set_adaptive_bframes(inst); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", + __func__); + return rc; + } + } + return rc; +} + +int msm_venc_set_request_keyframe(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + s_vpr_h(inst->sid, "%s\n", __func__); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME, NULL, 0); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +int msm_venc_set_rate_control(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + u32 hfi_rc, codec; + u32 height, width, mbpf; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + codec = get_v4l2_codec(inst); + height = f->fmt.pix_mp.height; + width = f->fmt.pix_mp.width; + mbpf = NUM_MBS_PER_FRAME(height, width); + + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR) + inst->rc_type = V4L2_MPEG_VIDEO_BITRATE_MODE_MBR; + else if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + inst->clk_data.low_latency_mode) + inst->rc_type = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) + inst->clk_data.low_latency_mode = true; + + switch (inst->rc_type) { + case RATE_CONTROL_OFF: + case RATE_CONTROL_LOSSLESS: + hfi_rc = HFI_RATE_CONTROL_OFF; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: + hfi_rc = HFI_RATE_CONTROL_CBR_CFR; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: + hfi_rc = HFI_RATE_CONTROL_VBR_CFR; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_MBR: + hfi_rc = HFI_RATE_CONTROL_MBR_CFR; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR: + hfi_rc = HFI_RATE_CONTROL_CBR_VFR; + break; + case V4L2_MPEG_VIDEO_BITRATE_MODE_CQ: + hfi_rc = HFI_RATE_CONTROL_CQ; + break; + default: + hfi_rc = HFI_RATE_CONTROL_OFF; + s_vpr_e(inst->sid, + "Invalid Rate control setting: %d Default RCOFF\n", + inst->rc_type); + break; + } + s_vpr_h(inst->sid, "%s: %d\n", __func__, inst->rc_type); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_RATE_CONTROL, &hfi_rc, + sizeof(u32)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + + + +int msm_venc_set_vbv_delay(struct msm_vidc_inst *inst) +{ + int rc = 0; + bool is_legacy_cbr; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + u32 codec, height, width, buf_size; + struct hfi_vbv_hrd_buf_size hrd_buf_size; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + codec = get_v4l2_codec(inst); + height = f->fmt.pix_mp.height; + width = f->fmt.pix_mp.width; + + /* vbv delay is required for CBR_CFR and CBR_VFR only */ + if (inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) + return 0; + + /* vbv delay is not required for VP8 encoder */ + if (codec == V4L2_PIX_FMT_VP8) + return 0; + + /* Default behavior */ + is_legacy_cbr = false; + buf_size = CBR_PLUS_BUF_SIZE; + + /* + * Client can set vbv delay only when + * resolution is between VGA and 720p + */ + if (res_is_greater_than_or_equal_to(width, height, MIN_CBRPLUS_W, + MIN_CBRPLUS_H) && res_is_less_than_or_equal_to(width, height, + MAX_CBR_W, MAX_CBR_H)) { + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_VBV_DELAY); + if (ctrl->val == LEGACY_CBR_BUF_SIZE) { + is_legacy_cbr = true; + buf_size = LEGACY_CBR_BUF_SIZE; + goto set_vbv_delay; + } else if (ctrl->val == CBR_PLUS_BUF_SIZE) { + is_legacy_cbr = false; + buf_size = CBR_PLUS_BUF_SIZE; + goto set_vbv_delay; + } + } + + /* Enable legacy cbr if resolution < MIN_CBRPLUS (720p) */ + if (res_is_less_than(width, height, MAX_CBR_W, MAX_CBR_H)) { + is_legacy_cbr = true; + buf_size = LEGACY_CBR_BUF_SIZE; + goto set_vbv_delay; + } + +set_vbv_delay: + inst->clk_data.is_legacy_cbr = is_legacy_cbr; + hrd_buf_size.vbv_hrd_buf_size = buf_size; + s_vpr_h(inst->sid, "%s: %d\n", __func__, hrd_buf_size.vbv_hrd_buf_size); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HFI_PROPERTY_CONFIG_VENC_VBV_HRD_BUF_SIZE, + (void *)&hrd_buf_size, sizeof(hrd_buf_size)); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + } + return rc; +} + + +int msm_venc_set_input_timestamp_rc(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_enable enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VENC_RC_TIMESTAMP_DISABLE); + /* + * HFI values: + * 0 - time delta is calculated based on buffer timestamp + * 1 - ignores buffer timestamp and fw derives time delta based + * on input frame rate. + */ + enable.enable = !!ctrl->val; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP, &enable, + sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_bitrate(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_bitrate bitrate; + struct hfi_enable enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (inst->layer_bitrate) { + s_vpr_h(inst->sid, "%s: Layer bitrate is enabled\n", __func__); + return 0; + } + + enable.enable = 0; + s_vpr_h(inst->sid, "%s: bitrate type: %d\n", + __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE, &enable, + sizeof(enable)); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; + } + + bitrate.bit_rate = inst->clk_data.bitrate; + bitrate.layer_id = MSM_VIDC_ALL_LAYER_ID; + s_vpr_h(inst->sid, "%s: %d\n", __func__, bitrate.bit_rate); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE, &bitrate, + sizeof(bitrate)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_layer_bitrate(struct msm_vidc_inst *inst) +{ + int rc = 0, i = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *layer = NULL; + struct v4l2_ctrl *max_layer = NULL; + struct v4l2_ctrl *layer_br_ratios[MAX_HIER_CODING_LAYER] = {NULL}; + struct hfi_bitrate layer_br; + struct hfi_enable enable; + u32 bitrate; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + max_layer = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + layer = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER); + + if (!max_layer->val || !layer->val) { + s_vpr_h(inst->sid, + "%s: Hierp layer not set. Ignore layer bitrate\n", + __func__); + goto error; + } + + if (max_layer->val < layer->val) { + s_vpr_h(inst->sid, + "%s: Hierp layer greater than max isn't allowed\n", + __func__); + goto error; + } + + layer_br_ratios[0] = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR); + layer_br_ratios[1] = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR); + layer_br_ratios[2] = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR); + layer_br_ratios[3] = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR); + layer_br_ratios[4] = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR); + layer_br_ratios[5] = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR); + + /* Set layer bitrates only when highest layer br ratio is 100. */ + if (layer_br_ratios[layer->val-1]->val != MAX_BIT_RATE_RATIO || + layer_br_ratios[0]->val == 0) { + s_vpr_h(inst->sid, "%s: Improper layer bitrate ratio\n", + __func__); + goto error; + } + + for (i = layer->val - 1; i > 0; --i) { + if (layer_br_ratios[i]->val == 0) { + s_vpr_h(inst->sid, "%s: Layer ratio must be non-zero\n", + __func__); + goto error; + } + layer_br_ratios[i]->val -= layer_br_ratios[i-1]->val; + } + + enable.enable = 1; + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE, &enable, + sizeof(enable)); + if (rc) { + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + goto error; + } + + bitrate = inst->clk_data.bitrate; + for (i = 0; i < layer->val; ++i) { + layer_br.bit_rate = + bitrate * layer_br_ratios[i]->val / 100; + layer_br.layer_id = i; + s_vpr_h(inst->sid, "%s: Bitrate for Layer[%u]: [%u]\n", + __func__, layer_br.layer_id, layer_br.bit_rate); + + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE, &layer_br, + sizeof(layer_br)); + if (rc) { + s_vpr_e(inst->sid, + "%s: set property failed for layer: %u\n", + __func__, layer_br.layer_id); + goto error; + } + } + + inst->layer_bitrate = true; + return rc; + +error: + inst->layer_bitrate = false; + return rc; +} + +int msm_venc_set_frame_qp(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *i_qp = NULL; + struct v4l2_ctrl *p_qp = NULL; + struct v4l2_ctrl *b_qp = NULL; + struct hfi_quantization qp; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + qp.layer_id = MSM_VIDC_ALL_LAYER_ID; + qp.enable = 0; + qp.enable = QP_ENABLE_I | QP_ENABLE_P | QP_ENABLE_B; + + i_qp = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP); + p_qp = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP); + b_qp = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP); + + /* + * When RC is ON: + * Enable QP types which have been set by client. + * When RC is OFF: + * I_QP value must be set by client. + * If other QP value is invalid, then, assign I_QP value to it. + */ + if (inst->rc_type != RATE_CONTROL_OFF) { + if (!(inst->client_set_ctrls & CLIENT_SET_I_QP)) + qp.enable &= ~QP_ENABLE_I; + if (!(inst->client_set_ctrls & CLIENT_SET_P_QP)) + qp.enable &= ~QP_ENABLE_P; + if (!(inst->client_set_ctrls & CLIENT_SET_B_QP)) + qp.enable &= ~QP_ENABLE_B; + + if (!qp.enable) + return 0; + } else { + if (!(inst->client_set_ctrls & CLIENT_SET_I_QP)) { + s_vpr_e(inst->sid, + "%s: Client value is not valid\n", __func__); + return -EINVAL; + } + if (!(inst->client_set_ctrls & CLIENT_SET_P_QP)) + p_qp->val = i_qp->val; + if (!(inst->client_set_ctrls & CLIENT_SET_B_QP)) + b_qp->val = i_qp->val; + } + + /* B frame QP is not supported for VP8. */ + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_VP8) + qp.enable &= ~QP_ENABLE_B; + + qp.qp_packed = i_qp->val | p_qp->val << 8 | b_qp->val << 16; + + s_vpr_h(inst->sid, "%s: layers %#x frames %#x qp_packed %#x\n", + __func__, qp.layer_id, qp.enable, qp.qp_packed); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_FRAME_QP, &qp, sizeof(qp)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_qp_range(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_quantization_range qp_range; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (!(inst->client_set_ctrls & CLIENT_SET_MIN_QP) && + !(inst->client_set_ctrls & CLIENT_SET_MAX_QP)) { + s_vpr_h(inst->sid, + "%s: Client didn't set QP range\n", __func__); + return 0; + } + + qp_range.min_qp.layer_id = MSM_VIDC_ALL_LAYER_ID; + qp_range.max_qp.layer_id = MSM_VIDC_ALL_LAYER_ID; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP); + qp_range.min_qp.qp_packed = ctrl->val; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP); + qp_range.max_qp.qp_packed = ctrl->val; + + s_vpr_h(inst->sid, "%s: layers %#x qp_min %#x qp_max %#x\n", + __func__, qp_range.min_qp.layer_id, + qp_range.min_qp.qp_packed, qp_range.max_qp.qp_packed); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE, &qp_range, + sizeof(qp_range)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +static void set_all_intra_preconditions(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl = NULL, *ctrl_t = NULL; + + /* Disable multi slice */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + if (ctrl->val) { + d_vpr_h("Disable multi slice for all intra\n"); + update_ctrl(ctrl, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + inst->sid); + } + + /* Disable LTR */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + if (ctrl->val) { + s_vpr_h(inst->sid, "Disable LTR for all intra\n"); + update_ctrl(ctrl, 0, inst->sid); + } + + /* Disable Layer encoding */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER); + ctrl_t = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + if (ctrl->val || ctrl_t->val) { + s_vpr_h(inst->sid, "Disable layer encoding for all intra\n"); + update_ctrl(ctrl, 0, inst->sid); + update_ctrl(ctrl_t, 0, inst->sid); + } + + /* Disable IR */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM); + ctrl_t = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB); + if (ctrl->val || ctrl_t->val) { + s_vpr_h(inst->sid, "Disable IR for all intra\n"); + update_ctrl(ctrl, 0, inst->sid); + update_ctrl(ctrl_t, 0, inst->sid); + } + + return; +} + +static void set_heif_preconditions(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl = NULL; + + /* Reset PFrames */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_GOP_SIZE); + if (ctrl->val) { + d_vpr_h("Reset P-frame count for HEIF\n"); + update_ctrl(ctrl, 0, inst->sid); + } + + /* Reset BFrames */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + if (ctrl->val) { + s_vpr_h(inst->sid, "Reset B-frame count for HEIF\n"); + update_ctrl(ctrl, 0, inst->sid); + } + + return; +} + +int msm_venc_set_frame_quality(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_heic_frame_quality frame_quality; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_COMPRESSION_QUALITY); + frame_quality.frame_quality = ctrl->val; + + s_vpr_h(inst->sid, "%s: frame quality: %d\n", __func__, + frame_quality.frame_quality); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY, &frame_quality, + sizeof(frame_quality)); + if (rc) + s_vpr_e(inst->sid, "%s: set frame quality failed\n", __func__); + + return rc; +} + +int msm_venc_set_image_grid(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_heic_grid_enable grid_enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_IMG_GRID_SIZE); + + /* Need a change in HFI if we want to pass size */ + if (!ctrl->val) + grid_enable.grid_enable = false; + else + grid_enable.grid_enable = true; + + s_vpr_h(inst->sid, "%s: grid enable: %d\n", __func__, + grid_enable.grid_enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_HEIC_GRID_ENABLE, &grid_enable, + sizeof(grid_enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set grid enable failed\n", __func__); + + return rc; +} + +int msm_venc_set_image_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + if (!is_image_session(inst) && !is_grid_session(inst)) + return 0; + + if (inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) { + d_vpr_e("%s: invalid rate control mode\n", __func__); + return -EINVAL; + } + + rc = msm_venc_set_frame_quality(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: set image property failed\n", __func__); + return rc; + } + + rc = msm_venc_set_image_grid(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: set image property failed\n", __func__); + return rc; + } + + set_all_intra_preconditions(inst); + set_heif_preconditions(inst); + return rc; +} + +int msm_venc_set_entropy_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_h264_entropy_control entropy; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (get_v4l2_codec(inst) != V4L2_PIX_FMT_H264) + return 0; + + entropy.entropy_mode = inst->entropy_mode; + entropy.cabac_model = HFI_H264_CABAC_MODEL_2; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, entropy.entropy_mode); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL, &entropy, + sizeof(entropy)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_slice_control_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct v4l2_ctrl *ctrl_t; + struct hfi_multi_slice_control multi_slice_control; + struct v4l2_format *f; + int temp = 0; + u32 mb_per_frame, fps, mbps, bitrate, max_slices; + u32 slice_val, slice_mode, max_avg_slicesize; + u32 rc_mode, output_width, output_height; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_HEVC && codec != V4L2_PIX_FMT_H264) + return 0; + + slice_mode = HFI_MULTI_SLICE_OFF; + slice_val = 0; + + bitrate = inst->clk_data.bitrate; + fps = inst->clk_data.frame_rate >> 16; + rc_mode = inst->rc_type; + if (fps > 60 || (!(rc_mode == RATE_CONTROL_OFF || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR))) { + goto set_and_exit; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_width = f->fmt.pix_mp.width; + output_height = f->fmt.pix_mp.height; + if ((codec == V4L2_PIX_FMT_HEVC) && + (output_height < 128 || output_width < 384)) + goto set_and_exit; + + if ((codec == V4L2_PIX_FMT_H264) && + (output_height < 128 || output_width < 192)) + goto set_and_exit; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + if (ctrl->val == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB; + slice_mode = HFI_MULTI_SLICE_BY_MB_COUNT; + } else if (ctrl->val == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES; + slice_mode = HFI_MULTI_SLICE_BY_BYTE_COUNT; + } else { + goto set_and_exit; + } + + ctrl_t = get_ctrl(inst, temp); + slice_val = ctrl_t->val; + + /* Update Slice Config */ + mb_per_frame = NUM_MBS_PER_FRAME(output_height, output_width); + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); + + if (slice_mode == HFI_MULTI_SLICE_BY_MB_COUNT) { + if (output_width <= 4096 || output_height <= 4096 || + mb_per_frame <= NUM_MBS_PER_FRAME(4096, 2160) || + mbps <= NUM_MBS_PER_SEC(4096, 2160, 60)) { + max_slices = inst->capability.cap[CAP_SLICE_MB].max ? + inst->capability.cap[CAP_SLICE_MB].max : 1; + slice_val = max(slice_val, mb_per_frame / max_slices); + } + } else { + if (output_width <= 1920 || output_height <= 1920 || + mb_per_frame <= NUM_MBS_PER_FRAME(1088, 1920) || + mbps <= NUM_MBS_PER_SEC(1088, 1920, 60)) { + max_slices = inst->capability.cap[CAP_SLICE_BYTE].max ? + inst->capability.cap[CAP_SLICE_BYTE].max : 1; + if (rc_mode != RATE_CONTROL_OFF) { + max_avg_slicesize = + ((bitrate / fps) / 8) / max_slices; + slice_val = max(slice_val, max_avg_slicesize); + } + } + } + + if (slice_mode == HFI_MULTI_SLICE_OFF) { + update_ctrl(ctrl, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + inst->sid); + update_ctrl(ctrl_t, 0, inst->sid); + } + +set_and_exit: + multi_slice_control.multi_slice = slice_mode; + multi_slice_control.slice_size = slice_val; + + hdev = inst->core->device; + s_vpr_h(inst->sid, "%s: %d %d\n", __func__, + multi_slice_control.multi_slice, + multi_slice_control.slice_size); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL, + &multi_slice_control, sizeof(multi_slice_control)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_intra_refresh_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl = NULL; + struct hfi_intra_refresh intra_refresh; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (!(inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)) + return 0; + + /* Firmware supports only random mode */ + intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM); + intra_refresh.mbs = 0; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + if (ctrl->val) { + u32 num_mbs_per_frame = 0; + u32 width = f->fmt.pix_mp.width; + u32 height = f->fmt.pix_mp.height; + + num_mbs_per_frame = NUM_MBS_PER_FRAME(height, width); + intra_refresh.mbs = num_mbs_per_frame / ctrl->val; + if (num_mbs_per_frame % ctrl->val) { + intra_refresh.mbs++; + } + } else { + ctrl = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB); + intra_refresh.mbs = ctrl->val; + } + if (!intra_refresh.mbs) { + intra_refresh.mode = HFI_INTRA_REFRESH_NONE; + intra_refresh.mbs = 0; + } + + s_vpr_h(inst->sid, "%s: %d %d\n", __func__, + intra_refresh.mode, intra_refresh.mbs); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH, &intra_refresh, + sizeof(intra_refresh)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_bitrate_savings_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *cac; + struct v4l2_ctrl *profile; + struct hfi_enable enable; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + cac = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS); + codec = get_v4l2_codec(inst); + profile = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_PROFILE); + + /** + * Enable CAC control: + * 0x0 -> disabled, + * 0x1 -> enabled for 8 bit + * 0x2 -> enabled for 10 bit + * 0x3 -> enabled for 8 and 10 bits both + */ + enable.enable = !!cac->val; + if (cac->val == 0x1 && codec == V4L2_PIX_FMT_HEVC && + profile->val == V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) + enable.enable = 0; + else if (cac->val == 0x2 && !(codec == V4L2_PIX_FMT_HEVC && + profile->val == V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)) + enable.enable = 0; + + if (!cac->val && inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { + s_vpr_h(inst->sid, + "Can't disable bitrate savings for non-VBR_CFR\n"); + enable.enable = 1; + update_ctrl(cac, 3, inst->sid); + } + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_BITRATE_SAVINGS, &enable, + sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_chroma_qp_offset(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *chr; + struct v4l2_ctrl *ctrl_cs; + struct hfi_chroma_qp_offset chroma_qp; + struct v4l2_format *f; + u32 codec, width, height, mbpf; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + chr = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET); + if (chr->val != -12) + return 0; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + mbpf = NUM_MBS_PER_FRAME(width, height); + ctrl_cs = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + codec = get_v4l2_codec(inst); + + /** + * Set chroma qp offset to HEVC & VBR_CFR rc + * 10 bit: only BT2020 + * 8 bit: only mbpf >= num_mbs(7680, 3840) + */ + if (codec != V4L2_PIX_FMT_HEVC || + inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + return 0; + + if ((inst->bit_depth == MSM_VIDC_BIT_DEPTH_10 && + ctrl_cs->val != MSM_VIDC_BT2020) || + (inst->bit_depth == MSM_VIDC_BIT_DEPTH_8 && + mbpf < NUM_MBS_PER_FRAME(7680, 3840))) + return 0; + + /** + * client sets one chroma offset only in range [-12, 0] + * firmware expects chroma cb offset and cr offset in + * range [0, 12], firmware subtracts 12 from driver set values. + */ + chroma_qp.chroma_offset = (chr->val + 12) << 16 | (chr->val + 12); + s_vpr_h(inst->sid, "%s: %x\n", __func__, chroma_qp.chroma_offset); + + /* TODO: Remove this check after firmware support added for 8-bit */ + if (inst->bit_depth == MSM_VIDC_BIT_DEPTH_8) + return 0; + + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_HEVC_PPS_CB_CR_OFFSET, &chroma_qp, + sizeof(chroma_qp)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_loop_filter_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct v4l2_ctrl *ctrl_a; + struct v4l2_ctrl *ctrl_b; + struct hfi_h264_db_control h264_db_control; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_H264 && codec != V4L2_PIX_FMT_HEVC) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE); + ctrl_a = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA); + ctrl_b = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA); + h264_db_control.mode = msm_comm_v4l2_to_hfi( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + ctrl->val, inst->sid); + h264_db_control.slice_alpha_offset = ctrl_a->val; + h264_db_control.slice_beta_offset = ctrl_b->val; + + s_vpr_h(inst->sid, "%s: %d %d %d\n", __func__, + h264_db_control.mode, h264_db_control.slice_alpha_offset, + h264_db_control.slice_beta_offset); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL, &h264_db_control, + sizeof(h264_db_control)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_sequence_header_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_enable enable; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC)) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR); + if (ctrl->val) + enable.enable = true; + else + enable.enable = false; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER, &enable, + sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_au_delimiter_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_enable enable; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC)) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER); + enable.enable = !!ctrl->val; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL, &enable, + sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_enable_hybrid_hp(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl = NULL; + struct v4l2_ctrl *layer = NULL; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + if (get_v4l2_codec(inst) != V4L2_PIX_FMT_H264) + return 0; + + if (inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + if (ctrl->val) + return 0; + + ctrl = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + layer = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER); + if (ctrl->val == 0 || ctrl->val != layer->val) + return 0; + + /* + * Hybrid HP is enabled only for H264 when + * LTR and B-frame are both disabled, + * Layer encoding has higher priority over B-frame + * Hence, no need to check for B-frame + * Rate control type is VBR and + * Max layer equals layer count. + */ + + inst->hybrid_hp = true; + + return 0; +} + +int msm_venc_set_base_layer_priority_id(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl = NULL; + struct v4l2_ctrl *max_layer = NULL; + u32 baselayerid; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + max_layer = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + if (max_layer->val <= 0) { + s_vpr_h(inst->sid, "%s: Layer id can only be set with Hierp\n", + __func__); + return 0; + } + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID); + baselayerid = ctrl->val; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, baselayerid); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID, &baselayerid, + sizeof(baselayerid)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_hp_max_layer(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + u32 hp_layer = 0; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_H264 && codec != V4L2_PIX_FMT_HEVC) + return 0; + + ctrl = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + + rc = msm_venc_enable_hybrid_hp(inst); + if (rc) { + s_vpr_e(inst->sid, "%s: get hybrid hp decision failed\n", + __func__); + return rc; + } + + /* + * We send enhancement layer count to FW, + * hence, input 0/1 indicates absence of layer encoding. + */ + if (ctrl->val) + hp_layer = ctrl->val - 1; + + if (inst->hybrid_hp) { + s_vpr_h(inst->sid, "%s: Hybrid hierp layer: %d\n", + __func__, hp_layer); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE, + &hp_layer, sizeof(hp_layer)); + } else { + s_vpr_h(inst->sid, "%s: Hierp max layer: %d\n", + __func__, hp_layer); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER, + &hp_layer, sizeof(hp_layer)); + } + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + return rc; +} + +int msm_venc_set_hp_layer(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl = NULL; + struct v4l2_ctrl *max_layer = NULL; + u32 hp_layer = 0; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_H264 && codec != V4L2_PIX_FMT_HEVC) + return 0; + + if (inst->hybrid_hp) { + s_vpr_e(inst->sid, + "%s: Setting layer isn't allowed with hybrid hp\n", + __func__); + return 0; + } + + max_layer = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + ctrl = get_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER); + s_vpr_h(inst->sid, "%s: heir_layer: %d, max_hier_layer: %d\n", + __func__, ctrl->val, max_layer->val); + if (max_layer->val < ctrl->val) { + s_vpr_e(inst->sid, + "%s: HP layer count greater than max isn't allowed\n", + __func__); + return 0; + } + + /* + * We send enhancement layer count to FW, + * hence, input 0/1 indicates absence of layer encoding. + */ + if (ctrl->val) + hp_layer = ctrl->val - 1; + + s_vpr_h(inst->sid, "%s: Hierp enhancement layer: %d\n", + __func__, hp_layer); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER, + &hp_layer, sizeof(hp_layer)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_vpx_error_resilience(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_enable enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (get_v4l2_codec(inst) != V4L2_PIX_FMT_VP8) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE); + enable.enable = !!ctrl->val; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE, &enable, + sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_video_signal_info(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl_cs; + struct v4l2_ctrl *ctrl_fr; + struct v4l2_ctrl *ctrl_tr; + struct v4l2_ctrl *ctrl_mc; + struct hfi_video_signal_metadata signal_info; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC)) + return 0; + + ctrl_cs = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + ctrl_fr = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + ctrl_tr = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + ctrl_mc = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + + memset(&signal_info, 0, sizeof(struct hfi_video_signal_metadata)); + if (inst->full_range == COLOR_RANGE_UNSPECIFIED && + ctrl_cs->val == MSM_VIDC_RESERVED_1) + signal_info.enable = false; + else + signal_info.enable = true; + + if (signal_info.enable) { + signal_info.video_format = MSM_VIDC_NTSC; + signal_info.video_full_range = ctrl_fr->val; + if (ctrl_cs->val != MSM_VIDC_RESERVED_1) { + signal_info.color_description = 1; + signal_info.color_primaries = ctrl_cs->val; + signal_info.transfer_characteristics = ctrl_tr->val; + signal_info.matrix_coeffs = ctrl_mc->val; + } + } + + s_vpr_h(inst->sid, "%s: %d %d %d %d\n", __func__, + signal_info.color_primaries, signal_info.video_full_range, + signal_info.transfer_characteristics, + signal_info.matrix_coeffs); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO, &signal_info, + sizeof(signal_info)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_rotation(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_ctrl *rotation = NULL; + struct hfi_device *hdev; + struct hfi_vpe_rotation_type vpe_rotation; + + hdev = inst->core->device; + rotation = get_ctrl(inst, V4L2_CID_ROTATE); + + vpe_rotation.rotation = HFI_ROTATE_NONE; + if (rotation->val == 90) + vpe_rotation.rotation = HFI_ROTATE_90; + else if (rotation->val == 180) + vpe_rotation.rotation = HFI_ROTATE_180; + else if (rotation->val == 270) + vpe_rotation.rotation = HFI_ROTATE_270; + + vpe_rotation.flip = v4l2_to_hfi_flip(inst); + + s_vpr_h(inst->sid, "Set rotation = %d, flip = %d\n", + vpe_rotation.rotation, vpe_rotation.flip); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HFI_PROPERTY_PARAM_VPE_ROTATION, + &vpe_rotation, sizeof(vpe_rotation)); + if (rc) { + s_vpr_e(inst->sid, "Set rotation/flip failed\n"); + return rc; + } + + /* Mark static rotation/flip set */ + inst->static_rotation_flip_enabled = false; + if ((vpe_rotation.rotation != HFI_ROTATE_NONE || + vpe_rotation.flip != HFI_FLIP_NONE) && + inst->state < MSM_VIDC_START_DONE) + inst->static_rotation_flip_enabled = true; + + return rc; +} + +int msm_venc_check_dynamic_flip_constraints(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_ctrl *blur = NULL; + struct v4l2_format *f = NULL; + bool scalar_enable = false; + bool blur_enable = false; + u32 input_height, input_width; + + /* Dynamic flip is not allowed with scalar when static + * rotation/flip is disabled + */ + scalar_enable = vidc_scalar_enabled(inst); + + /* Check blur configs + * blur value = 0 -> enable auto blur + * blur value = 2 or input resolution -> disable all blur + * For other values -> enable external blur + * Dynamic flip is not allowed with external blur enabled + */ + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + input_height = f->fmt.pix_mp.height; + input_width = f->fmt.pix_mp.width; + + blur = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_BLUR_DIMENSIONS); + if (blur->val != 0 && blur->val != 2 && + ((blur->val & 0xFFFF) != input_height || + (blur->val & 0x7FFF0000) >> 16 != input_width)) + blur_enable = true; + s_vpr_h(inst->sid, "Blur = %u, height = %u, width = %u\n", + blur->val, input_height, input_width); + if (blur_enable) { + /* Reject dynamic flip with external blur enabled */ + s_vpr_e(inst->sid, + "Unsupported dynamic flip with external blur\n"); + rc = -EINVAL; + } else if (scalar_enable && !inst->static_rotation_flip_enabled) { + /* Reject dynamic flip with scalar enabled */ + s_vpr_e(inst->sid, "Unsupported dynamic flip with scalar\n"); + rc = -EINVAL; + } + + return rc; +} + +int msm_venc_set_dynamic_flip(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + u32 dynamic_flip; + + hdev = inst->core->device; + + rc = msm_venc_check_dynamic_flip_constraints(inst); + if (rc) { + d_vpr_e("%s: Dynamic flip unsupported\n", __func__); + return rc; + } + + /* Require IDR frame first */ + s_vpr_h(inst->sid, "Set dynamic IDR frame\n"); + rc = msm_venc_set_request_keyframe(inst); + if (rc) { + s_vpr_e(inst->sid, "%s: Dynamic IDR failed\n", __func__); + return rc; + } + + dynamic_flip = v4l2_to_hfi_flip(inst); + s_vpr_h(inst->sid, "Dynamic flip = %d\n", dynamic_flip); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HFI_PROPERTY_CONFIG_VPE_FLIP, + &dynamic_flip, sizeof(dynamic_flip)); + if (rc) { + s_vpr_e(inst->sid, "Set dynamic flip failed\n"); + return rc; + } + + return rc; +} + +int msm_venc_set_video_csc(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct v4l2_ctrl *ctrl_cs; + struct v4l2_ctrl *ctrl_cm; + u32 color_primaries, custom_matrix; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (get_v4l2_codec(inst) != V4L2_PIX_FMT_H264 && + get_v4l2_codec(inst) != V4L2_PIX_FMT_HEVC) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC); + if (ctrl->val == V4L2_MPEG_MSM_VIDC_DISABLE) + return 0; + + ctrl_cs = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + ctrl_cm = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX); + + color_primaries = ctrl_cs->val; + custom_matrix = ctrl_cm->val; + rc = msm_venc_set_csc(inst, color_primaries, custom_matrix); + if (rc) + s_vpr_e(inst->sid, "%s: msm_venc_set_csc failed\n", __func__); + + return rc; +} + +int msm_venc_set_8x8_transform(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl = NULL; + struct hfi_enable enable; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (get_v4l2_codec(inst) != V4L2_PIX_FMT_H264) { + s_vpr_h(inst->sid, "%s: skip as codec is not H264\n", + __func__); + return 0; + } + + if (inst->profile != HFI_H264_PROFILE_HIGH && + inst->profile != HFI_H264_PROFILE_CONSTRAINED_HIGH) { + s_vpr_h(inst->sid, "%s: skip due to %#x\n", + __func__, inst->profile); + return 0; + } + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM); + enable.enable = !!ctrl->val; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, enable.enable); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM, &enable, + sizeof(enable)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_vui_timing_info(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_vui_timing_info timing_info; + bool cfr; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_H264 && codec != V4L2_PIX_FMT_HEVC) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_VUI_TIMING_INFO); + if (ctrl->val == V4L2_MPEG_MSM_VIDC_DISABLE) + return 0; + + switch (inst->rc_type) { + case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: + case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: + case V4L2_MPEG_VIDEO_BITRATE_MODE_MBR: + cfr = true; + break; + default: + cfr = false; + break; + } + + timing_info.enable = 1; + timing_info.fixed_frame_rate = cfr; + timing_info.time_scale = NSEC_PER_SEC; + + s_vpr_h(inst->sid, "%s: %d %d\n", __func__, timing_info.enable, + timing_info.fixed_frame_rate); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_VUI_TIMING_INFO, &timing_info, + sizeof(timing_info)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_nal_stream_format(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_nal_stream_format_select stream_format; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (codec != V4L2_PIX_FMT_H264 && codec != V4L2_PIX_FMT_HEVC) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD); + stream_format.nal_stream_format_select = BIT(ctrl->val); + + /* + * Secure encode session supports 0x00000001 satrtcode based + * encoding only + */ + if (is_secure_session(inst) && + ctrl->val != V4L2_MPEG_VIDEO_HEVC_SIZE_0) { + s_vpr_e(inst->sid, + "%s: Invalid stream format setting for secure session\n", + __func__); + return -EINVAL; + } + + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_SIZE_0: + stream_format.nal_stream_format_select = + HFI_NAL_FORMAT_STARTCODES; + break; + case V4L2_MPEG_VIDEO_HEVC_SIZE_4: + stream_format.nal_stream_format_select = + HFI_NAL_FORMAT_FOUR_BYTE_LENGTH; + break; + default: + s_vpr_e(inst->sid, + "%s: Invalid stream format setting. Setting default\n", + __func__); + stream_format.nal_stream_format_select = + HFI_NAL_FORMAT_STARTCODES; + break; + } + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, + stream_format.nal_stream_format_select); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT, &stream_format, + sizeof(stream_format)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_ltr_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + bool is_ltr = true; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_ltr_mode ltr; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + if (!ctrl->val) + return 0; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_HEVC || codec == V4L2_PIX_FMT_H264)) { + is_ltr = false; + goto disable_ltr; + } + + if (!(inst->rc_type == RATE_CONTROL_OFF || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR)) { + is_ltr = false; + goto disable_ltr; + } + + if (ctrl->val > inst->capability.cap[CAP_LTR_COUNT].max) { + s_vpr_e(inst->sid, "%s: invalid ltr count %d, max %d\n", + __func__, ctrl->val, + inst->capability.cap[CAP_LTR_COUNT].max); + return -EINVAL; + } + ltr.ltr_count = ctrl->val; + ltr.ltr_mode = HFI_LTR_MODE_MANUAL; + ltr.trust_mode = 1; + s_vpr_h(inst->sid, "%s: %d %d\n", __func__, + ltr.ltr_mode, ltr.ltr_count); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_LTRMODE, <r, sizeof(ltr)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + +disable_ltr: + /* + * Forcefully setting LTR count to zero when + * client sets unsupported codec/rate control. + */ + if (!is_ltr) { + update_ctrl(ctrl, 0, inst->sid); + s_vpr_h(inst->sid, "LTR is forcefully disabled!\n"); + } + return rc; +} + +int msm_venc_set_ltr_useframe(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_ltr_use use_ltr; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + if (!ctrl->val) + return 0; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_HEVC || codec == V4L2_PIX_FMT_H264)) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME); + use_ltr.ref_ltr = ctrl->val; + use_ltr.use_constrnt = true; + use_ltr.frames = 0; + s_vpr_h(inst->sid, "%s: %d\n", __func__, use_ltr.ref_ltr); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_USELTRFRAME, &use_ltr, + sizeof(use_ltr)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_ltr_markframe(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_ltr_mark mark_ltr; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + if (!ctrl->val) + return 0; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_HEVC || codec == V4L2_PIX_FMT_H264)) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME); + mark_ltr.mark_frame = ctrl->val; + + s_vpr_h(inst->sid, "%s: %d\n", __func__, mark_ltr.mark_frame); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME, &mark_ltr, + sizeof(mark_ltr)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_dyn_qp(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_quantization qp; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (inst->rc_type != RATE_CONTROL_OFF) { + s_vpr_e(inst->sid, "%s: Dyn qp is set only when RC is OFF\n", + __func__); + return -EINVAL; + } + + qp.qp_packed = ctrl->val | ctrl->val << 8 | ctrl->val << 16; + qp.enable = QP_ENABLE_I | QP_ENABLE_P | QP_ENABLE_B; + qp.layer_id = MSM_VIDC_ALL_LAYER_ID; + + /* B frame QP is not supported for VP8. */ + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_VP8) + qp.enable &= ~QP_ENABLE_B; + + s_vpr_h(inst->sid, "%s: %#x\n", __func__, + ctrl->val); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_FRAME_QP, &qp, sizeof(qp)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_aspect_ratio(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_aspect_ratio sar; + u32 codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + codec = get_v4l2_codec(inst); + if (!(codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC)) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH); + if (!ctrl->val) + return 0; + sar.aspect_width = ctrl->val; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT); + if (!ctrl->val) + return 0; + sar.aspect_height = ctrl->val; + + s_vpr_h(inst->sid, "%s: %d %d\n", __func__, + sar.aspect_width, sar.aspect_height); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO, &sar, sizeof(sar)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_blur_resolution(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct v4l2_ctrl *ctrl; + struct hfi_frame_size frame_sz; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_BLUR_DIMENSIONS); + + frame_sz.buffer_type = HFI_BUFFER_INPUT; + frame_sz.height = ctrl->val & 0xFFFF; + frame_sz.width = (ctrl->val & 0x7FFF0000) >> 16; + + /* + * 0x0 is default value, internal blur enabled, external blur disabled + * 0x1 means dynamic external blur, blur resolution will be set + * after start, internal blur disabled + * 0x2 means disable both internal and external blur + */ + if (ctrl->val == 0x2) { + if (inst->state == MSM_VIDC_START_DONE) { + s_vpr_e(inst->sid, + "Dynamic disable all blur not supported\n"); + return -EINVAL; + } + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + /* + * Use original input width/height (before VPSS) to inform FW + * to disable all blur. + */ + frame_sz.width = f->fmt.pix_mp.width; + frame_sz.height = f->fmt.pix_mp.height; + s_vpr_h(inst->sid, "Disable both auto and external blur\n"); + } else if (ctrl->val != 0){ + if (check_blur_restrictions(inst)) { + /* reject external blur */ + s_vpr_e(inst->sid, + "External blur is unsupported with rotation/flip/scalar\n"); + return -EINVAL; + } + } + + s_vpr_h(inst->sid, "%s: type %u, height %u, width %u\n", __func__, + frame_sz.buffer_type, frame_sz.height, frame_sz.width); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE, &frame_sz, + sizeof(frame_sz)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_hdr_info(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_ctrl *profile = NULL; + struct hfi_device *hdev; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + + if (get_v4l2_codec(inst) != V4L2_PIX_FMT_HEVC) + return 0; + + profile = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_PROFILE); + if (profile->val != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) + return 0; + + /* No conversion to HFI needed as both structures are same */ + s_vpr_h(inst->sid, "%s: setting hdr info\n", __func__); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI, &inst->hdr10_sei_params, + sizeof(inst->hdr10_sei_params)); + if (rc) + s_vpr_e(inst->sid, "%s: set property failed\n", __func__); + + return rc; +} + +int msm_venc_set_extradata(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 codec; + + codec = get_v4l2_codec(inst); + if (inst->prop.extradata_ctrls == EXTRADATA_NONE) { + // Disable all Extradata + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_LTR_INFO, 0x0); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA, 0x0); + if (codec == V4L2_PIX_FMT_HEVC) { + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_HDR10PLUS_METADATA_EXTRADATA, + 0x0); + } + } + + if (inst->prop.extradata_ctrls & EXTRADATA_ADVANCED) { + // Enable Advanced Extradata - LTR Info + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_LTR_INFO, 0x1); + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA, 0x1); + } + + if (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_ROI) + // Enable ROIQP Extradata + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA, 0x1); + + if (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_HDR10PLUS) { + // Enable HDR10+ Extradata + if (codec == V4L2_PIX_FMT_HEVC) { + msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_HDR10PLUS_METADATA_EXTRADATA, + 0x1); + } + } + + if (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_CVP) { + struct v4l2_ctrl *max_layers = NULL; + u32 value = 0x1; + + max_layers = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + if (!msm_vidc_cvp_usage || max_layers->val > 1) { + inst->prop.extradata_ctrls &= ~EXTRADATA_ENC_INPUT_CVP; + value = 0x0; + } + s_vpr_h(inst->sid, "%s: CVP extradata %d\n", __func__, value); + rc = msm_comm_set_extradata(inst, + HFI_PROPERTY_PARAM_VENC_CVP_METADATA_EXTRADATA, value); + if (rc) + s_vpr_h(inst->sid, + "%s: set CVP extradata failed\n", __func__); + } else { + s_vpr_h(inst->sid, "%s: CVP extradata not enabled\n", __func__); + } + + return rc; +} + +int msm_venc_set_lossless(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_enable enable; + + hdev = inst->core->device; + + if (inst->rc_type != RATE_CONTROL_LOSSLESS) + return 0; + + s_vpr_h(inst->sid, "%s: enable lossless encoding\n", __func__); + enable.enable = 1; + rc = call_hfi_op(hdev, session_set_property, + inst->session, + HFI_PROPERTY_PARAM_VENC_LOSSLESS_ENCODING, + &enable, sizeof(enable)); + + if (rc) + s_vpr_e(inst->sid, "Failed to set lossless mode\n"); + + return rc; +} +int msm_venc_set_cvp_skipratio(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_ctrl *capture_rate_ctrl; + struct v4l2_ctrl *cvp_rate_ctrl; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + if (!msm_vidc_cvp_usage || + !(inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_CVP)) + return 0; + + capture_rate_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_CAPTURE_FRAME_RATE); + cvp_rate_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_CVP_FRAME_RATE); + + rc = msm_comm_set_cvp_skip_ratio(inst, + capture_rate_ctrl->val, cvp_rate_ctrl->val); + if (rc) + s_vpr_e(inst->sid, "Failed to set cvp skip ratio\n"); + + return rc; +} + +int msm_venc_update_entropy_mode(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_H264) { + if ((inst->profile == HFI_H264_PROFILE_BASELINE || + inst->profile == HFI_H264_PROFILE_CONSTRAINED_BASE) + && inst->entropy_mode == HFI_H264_ENTROPY_CABAC) { + inst->entropy_mode = HFI_H264_ENTROPY_CAVLC; + s_vpr_h(inst->sid, + "%s: profile %d entropy %d\n", + __func__, inst->profile, + inst->entropy_mode); + } + } + + return 0; +} + +int handle_all_intra_restrictions(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl = NULL; + u32 n_fps, fps_max; + struct msm_vidc_capability *capability; + struct v4l2_format *f; + enum hal_video_codec codec; + struct hfi_intra_period intra_period; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + return 0; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_GOP_SIZE); + intra_period.pframes = ctrl->val; + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + intra_period.bframes = ctrl->val; + + if (!intra_period.pframes && !intra_period.bframes) + inst->all_intra = true; + else + return 0; + + s_vpr_h(inst->sid, "All Intra(IDRs) Encoding\n"); + /* check codec and profile */ + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + codec = get_hal_codec(f->fmt.pix_mp.pixelformat, inst->sid); + if (codec != HAL_VIDEO_CODEC_HEVC && codec != HAL_VIDEO_CODEC_H264) { + s_vpr_e(inst->sid, "Unsupported codec for all intra\n"); + return -ENOTSUPP; + } + if (codec == HAL_VIDEO_CODEC_HEVC && + inst->profile == HFI_HEVC_PROFILE_MAIN10) { + s_vpr_e(inst->sid, "Unsupported HEVC profile for all intra\n"); + return -ENOTSUPP; + } + + /* CBR_CFR is one of the advertised rc mode for HEVC encoding. + * However, all-intra is intended for quality bitstream. Hence, + * fallback to VBR RC mode if client needs all-intra encoding. + */ + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + inst->rc_type = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; + + /* check supported bit rate mode and frame rate */ + capability = &inst->capability; + n_fps = inst->clk_data.frame_rate >> 16; + fps_max = capability->cap[CAP_ALLINTRA_MAX_FPS].max; + s_vpr_h(inst->sid, "%s: rc_type %u, fps %u, fps_max %u\n", + __func__, inst->rc_type, n_fps, fps_max); + if ((inst->rc_type != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + inst->rc_type != RATE_CONTROL_OFF && + inst->rc_type != RATE_CONTROL_LOSSLESS) || + n_fps > fps_max) { + s_vpr_e(inst->sid, "Unsupported bitrate mode or frame rate\n"); + return -ENOTSUPP; + } + + set_all_intra_preconditions(inst); + + return 0; +} + +int check_blur_restrictions(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *rotation = NULL; + struct v4l2_ctrl *hflip = NULL; + struct v4l2_ctrl *vflip = NULL; + struct v4l2_format *f; + u32 output_height, output_width, input_height, input_width; + bool scalar_enable = false; + bool rotation_enable = false; + bool flip_enable = false; + + /* Only need to check static VPSS conditions */ + if (inst->state == MSM_VIDC_START_DONE) + return 0; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_height = f->fmt.pix_mp.height; + output_width = f->fmt.pix_mp.width; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + input_height = f->fmt.pix_mp.height; + input_width = f->fmt.pix_mp.width; + + if (output_height != input_height || output_width != input_width) + scalar_enable = true; + + rotation = get_ctrl(inst, V4L2_CID_ROTATE); + if (rotation->val != 0) + rotation_enable = true; + + hflip = get_ctrl(inst, V4L2_CID_HFLIP); + vflip = get_ctrl(inst, V4L2_CID_VFLIP); + if ((hflip->val == V4L2_MPEG_MSM_VIDC_ENABLE) || + (vflip->val == V4L2_MPEG_MSM_VIDC_ENABLE)) + flip_enable = true; + + if (scalar_enable || rotation_enable || flip_enable) + return -ENOTSUPP; + else + return 0; +} + +int msm_venc_set_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_venc_update_entropy_mode(inst); + if (rc) + goto exit; + rc = msm_venc_update_bitrate(inst); + if (rc) + goto exit; + rc = handle_all_intra_restrictions(inst); + if (rc) + goto exit; + rc = msm_venc_set_frame_size(inst); + if (rc) + goto exit; + rc = msm_venc_set_frame_rate(inst); + if (rc) + goto exit; + rc = msm_venc_set_secure_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_priority(inst); + if (rc) + goto exit; + rc = msm_venc_set_color_format(inst); + if (rc) + goto exit; + rc = msm_venc_set_sequence_header_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_profile_level(inst); + if (rc) + goto exit; + rc = msm_venc_set_8x8_transform(inst); + if (rc) + goto exit; + rc = msm_venc_set_entropy_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_rate_control(inst); + if (rc) + goto exit; + rc = msm_venc_set_vbv_delay(inst); + if (rc) + goto exit; + rc = msm_venc_set_bitrate_savings_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_input_timestamp_rc(inst); + if (rc) + goto exit; + rc = msm_venc_set_frame_qp(inst); + if (rc) + goto exit; + rc = msm_venc_set_qp_range(inst); + if (rc) + goto exit; + rc = msm_venc_set_image_properties(inst); + if (rc) + goto exit; + rc = msm_venc_set_au_delimiter_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_vui_timing_info(inst); + if (rc) + goto exit; + rc = msm_venc_set_hdr_info(inst); + if (rc) + goto exit; + rc = msm_venc_set_vpx_error_resilience(inst); + if (rc) + goto exit; + rc = msm_venc_set_nal_stream_format(inst); + if (rc) + goto exit; + rc = msm_venc_set_slice_control_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_loop_filter_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_intra_refresh_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_ltr_mode(inst); + if (rc) + goto exit; + rc = msm_venc_set_hp_max_layer(inst); + if (rc) + goto exit; + rc = msm_venc_set_hp_layer(inst); + if (rc) + goto exit; + rc = msm_venc_set_base_layer_priority_id(inst); + if (rc) + goto exit; + msm_venc_decide_bframe(inst); + rc = msm_venc_set_idr_period(inst); + if (rc) + goto exit; + rc = msm_venc_set_intra_period(inst); + if (rc) + goto exit; + rc = msm_venc_set_aspect_ratio(inst); + if (rc) + goto exit; + rc = msm_venc_set_video_signal_info(inst); + if (rc) + goto exit; + /* + * Layer bitrate is preferred over cumulative bitrate. + * Cumulative bitrate is set only when we fall back. + */ + rc = msm_venc_set_layer_bitrate(inst); + if (rc) + goto exit; + rc = msm_venc_set_bitrate(inst); + if (rc) + goto exit; + rc = msm_venc_set_video_csc(inst); + if (rc) + goto exit; + rc = msm_venc_set_chroma_qp_offset(inst); + if (rc) + goto exit; + rc = msm_venc_set_blur_resolution(inst); + if (rc) + goto exit; + rc = msm_venc_set_extradata(inst); + if (rc) + goto exit; + rc = msm_venc_set_cvp_skipratio(inst); + if (rc) + goto exit; + rc = msm_venc_set_operating_rate(inst); + if (rc) + goto exit; + rc = msm_venc_set_buffer_counts(inst); + if (rc) + goto exit; + rc = msm_venc_set_rotation(inst); + if (rc) + goto exit; + rc = msm_venc_set_lossless(inst); + if (rc) + goto exit; + +exit: + if (rc) + s_vpr_e(inst->sid, "%s: failed with %d\n", __func__, rc); + else + s_vpr_h(inst->sid, "%s: set properties successful\n", __func__); + + return rc; +} diff --git a/techpack/video/msm/vidc/msm_venc.h b/techpack/video/msm/vidc/msm_venc.h new file mode 100644 index 0000000000000000000000000000000000000000..a9ff51824eba20db2efbfb3b19552f43e8ca1089 --- /dev/null +++ b/techpack/video/msm/vidc/msm_venc.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ +#ifndef _MSM_VENC_H_ +#define _MSM_VENC_H_ + +#include "msm_vidc.h" +#include "msm_vidc_internal.h" +#define MSM_VENC_DVC_NAME "msm_vidc_venc" + +int msm_venc_inst_init(struct msm_vidc_inst *inst); +int msm_venc_ctrl_init(struct msm_vidc_inst *inst, + const struct v4l2_ctrl_ops *ctrl_ops); +int msm_venc_enum_fmt(struct msm_vidc_inst *inst, + struct v4l2_fmtdesc *f); +int msm_venc_s_fmt(struct msm_vidc_inst *inst, + struct v4l2_format *f); +int msm_venc_g_fmt(struct msm_vidc_inst *inst, + struct v4l2_format *f); +int msm_venc_set_default_profile(struct msm_vidc_inst *inst); +int msm_venc_s_ctrl(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl); +int msm_venc_set_properties(struct msm_vidc_inst *inst); +int msm_venc_set_extradata(struct msm_vidc_inst *inst); +int msm_venc_set_frame_rate(struct msm_vidc_inst *inst); +int msm_venc_set_bitrate(struct msm_vidc_inst *inst); +int msm_venc_set_layer_bitrate(struct msm_vidc_inst *inst); +int msm_venc_set_operating_rate(struct msm_vidc_inst *inst); +int msm_venc_set_idr_period(struct msm_vidc_inst *inst); +int msm_venc_set_intra_period(struct msm_vidc_inst *inst); +int msm_venc_set_ltr_useframe(struct msm_vidc_inst *inst); +int msm_venc_set_ltr_markframe(struct msm_vidc_inst *inst); +int msm_venc_set_dyn_qp(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl); +int msm_venc_set_request_keyframe(struct msm_vidc_inst *inst); +int msm_venc_set_intra_refresh_mode(struct msm_vidc_inst *inst); +int msm_venc_set_hp_max_layer(struct msm_vidc_inst *inst); +int msm_venc_set_hp_layer(struct msm_vidc_inst *inst); +int msm_venc_set_base_layer_priority_id(struct msm_vidc_inst *inst); +int msm_venc_check_dynamic_flip_constraints(struct msm_vidc_inst *inst); +int msm_venc_set_dynamic_flip(struct msm_vidc_inst *inst); +int msm_venc_set_lossless(struct msm_vidc_inst *inst); +int msm_venc_set_blur_resolution(struct msm_vidc_inst *inst); +int msm_venc_set_cvp_skipratio(struct msm_vidc_inst *inst); +int handle_all_intra_restrictions(struct msm_vidc_inst *inst); +int check_blur_restrictions(struct msm_vidc_inst *inst); +int msm_venc_set_frame_quality(struct msm_vidc_inst *inst); +int msm_venc_set_image_grid(struct msm_vidc_inst *inst); +#endif diff --git a/techpack/video/msm/vidc/msm_vidc.c b/techpack/video/msm/vidc/msm_vidc.c new file mode 100644 index 0000000000000000000000000000000000000000..cbb46852cbb9c3278cc9a8473d6f14547ea3528a --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc.c @@ -0,0 +1,1782 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/dma-direction.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include "msm_vidc.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "msm_vdec.h" +#include "msm_venc.h" +#include "msm_cvp_internal.h" +#include "msm_vidc_common.h" +#include <linux/delay.h> +#include "vidc_hfi.h" +#include "vidc_hfi_helper.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_clocks.h" +#include "msm_vidc_buffer_calculations.h" +#include <linux/dma-buf.h> + +#define MAX_EVENTS 30 + +static int try_get_ctrl_for_instance(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl); + +static int get_poll_flags(void *instance) +{ + struct msm_vidc_inst *inst = instance; + struct vb2_queue *outq = &inst->bufq[INPUT_PORT].vb2_bufq; + struct vb2_queue *capq = &inst->bufq[OUTPUT_PORT].vb2_bufq; + struct vb2_buffer *out_vb = NULL; + struct vb2_buffer *cap_vb = NULL; + unsigned long flags = 0; + int rc = 0; + + if (v4l2_event_pending(&inst->event_handler)) + rc |= POLLPRI; + + spin_lock_irqsave(&capq->done_lock, flags); + if (!list_empty(&capq->done_list)) + cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer, + done_entry); + if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE + || cap_vb->state == VB2_BUF_STATE_ERROR)) + rc |= POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&capq->done_lock, flags); + + spin_lock_irqsave(&outq->done_lock, flags); + if (!list_empty(&outq->done_list)) + out_vb = list_first_entry(&outq->done_list, struct vb2_buffer, + done_entry); + if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE + || out_vb->state == VB2_BUF_STATE_ERROR)) + rc |= POLLOUT | POLLWRNORM; + spin_unlock_irqrestore(&outq->done_lock, flags); + + return rc; +} + +int msm_vidc_poll(void *instance, struct file *filp, + struct poll_table_struct *wait) +{ + struct msm_vidc_inst *inst = instance; + struct vb2_queue *outq = NULL; + struct vb2_queue *capq = NULL; + + if (!inst) + return -EINVAL; + + outq = &inst->bufq[INPUT_PORT].vb2_bufq; + capq = &inst->bufq[OUTPUT_PORT].vb2_bufq; + + poll_wait(filp, &inst->event_handler.wait, wait); + poll_wait(filp, &capq->done_wq, wait); + poll_wait(filp, &outq->done_wq, wait); + return get_poll_flags(inst); +} +EXPORT_SYMBOL(msm_vidc_poll); + +int msm_vidc_querycap(void *instance, struct v4l2_capability *cap) +{ + struct msm_vidc_inst *inst = instance; + + if (!inst || !cap) + return -EINVAL; + + strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver)); + cap->bus_info[0] = 0; + cap->version = MSM_VIDC_VERSION; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + memset(cap->reserved, 0, sizeof(cap->reserved)); + + if (inst->session_type == MSM_VIDC_DECODER) + strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card)); + else if (inst->session_type == MSM_VIDC_ENCODER) + strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card)); + else + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(msm_vidc_querycap); + +int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f) +{ + struct msm_vidc_inst *inst = instance; + + if (!inst || !f) + return -EINVAL; + + if (inst->session_type == MSM_VIDC_DECODER) + return msm_vdec_enum_fmt(instance, f); + else if (inst->session_type == MSM_VIDC_ENCODER) + return msm_venc_enum_fmt(instance, f); + return -EINVAL; +} +EXPORT_SYMBOL(msm_vidc_enum_fmt); + +int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *q_ctrl) +{ + int rc = 0; + struct msm_vidc_inst *inst = instance; + struct v4l2_ctrl *ctrl; + + if (!inst || !q_ctrl) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, q_ctrl); + return -EINVAL; + } + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, q_ctrl->id); + if (!ctrl) { + s_vpr_e(inst->sid, "%s: get_ctrl failed for id %d\n", + __func__, q_ctrl->id); + return -EINVAL; + } + q_ctrl->minimum = ctrl->minimum; + q_ctrl->maximum = ctrl->maximum; + q_ctrl->default_value = ctrl->default_value; + /* remove tier info for HEVC level */ + if (q_ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_LEVEL) { + q_ctrl->minimum &= ~(0xF << 28); + q_ctrl->maximum &= ~(0xF << 28); + } + if (ctrl->type == V4L2_CTRL_TYPE_MENU) { + q_ctrl->flags = ~(ctrl->menu_skip_mask); + } else { + q_ctrl->flags = 0; + q_ctrl->step = ctrl->step; + } + s_vpr_h(inst->sid, + "query ctrl: %s: min %d, max %d, default %d step %d flags %#x\n", + ctrl->name, q_ctrl->minimum, q_ctrl->maximum, + q_ctrl->default_value, q_ctrl->step, q_ctrl->flags); + return rc; +} +EXPORT_SYMBOL(msm_vidc_query_ctrl); + +int msm_vidc_query_menu(void *instance, struct v4l2_querymenu *qmenu) +{ + int rc = 0; + struct msm_vidc_inst *inst = instance; + struct v4l2_ctrl *ctrl; + + if (!inst || !qmenu) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, qmenu); + return -EINVAL; + } + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, qmenu->id); + if (!ctrl) { + s_vpr_e(inst->sid, "%s: get_ctrl failed for id %d\n", + __func__, qmenu->id); + return -EINVAL; + } + if (ctrl->type != V4L2_CTRL_TYPE_MENU) { + s_vpr_e(inst->sid, "%s: ctrl: %s: type (%d) is not MENU type\n", + __func__, ctrl->name, ctrl->type); + return -EINVAL; + } + if (qmenu->index < ctrl->minimum || qmenu->index > ctrl->maximum) + return -EINVAL; + + if (ctrl->menu_skip_mask & (1 << qmenu->index)) + rc = -EINVAL; + + s_vpr_h(inst->sid, + "%s: ctrl: %s: min %d, max %d, menu_skip_mask %#x, qmenu: id %d, index %d, %s\n", + __func__, ctrl->name, ctrl->minimum, ctrl->maximum, + ctrl->menu_skip_mask, qmenu->id, qmenu->index, + rc ? "not supported" : "supported"); + return rc; +} +EXPORT_SYMBOL(msm_vidc_query_menu); + +int msm_vidc_s_fmt(void *instance, struct v4l2_format *f) +{ + int rc = 0; + struct msm_vidc_inst *inst = instance; + + if (!inst || !f) + return -EINVAL; + + if (inst->session_type == MSM_VIDC_DECODER) + rc = msm_vdec_s_fmt(instance, f); + if (inst->session_type == MSM_VIDC_ENCODER) + rc = msm_venc_s_fmt(instance, f); + + s_vpr_h(inst->sid, + "s_fmt: type %d wxh %dx%d pixelfmt %#x num_planes %d size[0] %d size[1] %d in_reconfig %d\n", + f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.num_planes, + f->fmt.pix_mp.plane_fmt[0].sizeimage, + f->fmt.pix_mp.plane_fmt[1].sizeimage, inst->in_reconfig); + return rc; +} +EXPORT_SYMBOL(msm_vidc_s_fmt); + +int msm_vidc_g_fmt(void *instance, struct v4l2_format *f) +{ + int rc = 0; + struct msm_vidc_inst *inst = instance; + + if (!inst || !f) + return -EINVAL; + + if (inst->session_type == MSM_VIDC_DECODER) + rc = msm_vdec_g_fmt(instance, f); + if (inst->session_type == MSM_VIDC_ENCODER) + rc = msm_venc_g_fmt(instance, f); + + s_vpr_h(inst->sid, + "g_fmt: type %d wxh %dx%d pixelfmt %#x num_planes %d size[0] %d size[1] %d in_reconfig %d\n", + f->type, f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.num_planes, + f->fmt.pix_mp.plane_fmt[0].sizeimage, + f->fmt.pix_mp.plane_fmt[1].sizeimage, inst->in_reconfig); + return rc; +} +EXPORT_SYMBOL(msm_vidc_g_fmt); + +int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control) +{ + struct msm_vidc_inst *inst = instance; + + if (!inst || !control) + return -EINVAL; + + return msm_comm_s_ctrl(instance, control); +} +EXPORT_SYMBOL(msm_vidc_s_ctrl); + +int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control) +{ + struct msm_vidc_inst *inst = instance; + struct v4l2_ctrl *ctrl = NULL; + int rc = 0; + + if (!inst || !control) + return -EINVAL; + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, control->id); + if (ctrl) { + rc = try_get_ctrl_for_instance(inst, ctrl); + if (!rc) + control->value = ctrl->val; + } + + return rc; +} +EXPORT_SYMBOL(msm_vidc_g_ctrl); + +int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b) +{ + struct msm_vidc_inst *inst = instance; + struct buf_queue *q = NULL; + int rc = 0; + + if (!inst || !b) + return -EINVAL; + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + s_vpr_e(inst->sid, + "Failed to find buffer queue. type %d\n", b->type); + return -EINVAL; + } + + mutex_lock(&q->lock); + rc = vb2_reqbufs(&q->vb2_bufq, b); + mutex_unlock(&q->lock); + + if (rc) + s_vpr_e(inst->sid, "Failed to get reqbufs, %d\n", rc); + return rc; +} +EXPORT_SYMBOL(msm_vidc_reqbufs); + +static bool valid_v4l2_buffer(struct v4l2_buffer *b, + struct msm_vidc_inst *inst) +{ + struct v4l2_format *f; + enum vidc_ports port = + !V4L2_TYPE_IS_MULTIPLANAR(b->type) ? MAX_PORT_NUM : + b->type == OUTPUT_MPLANE ? OUTPUT_PORT : + b->type == INPUT_MPLANE ? INPUT_PORT : + MAX_PORT_NUM; + + f = &inst->fmts[port].v4l2_fmt; + return port != MAX_PORT_NUM && + f->fmt.pix_mp.num_planes == b->length; +} + +int msm_vidc_release_buffer(void *instance, int type, unsigned int index) +{ + int rc = 0; + struct msm_vidc_inst *inst = instance; + struct msm_vidc_buffer *mbuf, *dummy; + + if (!inst) { + d_vpr_e("%s: invalid inst\n", __func__); + return -EINVAL; + } + + if (!inst->in_reconfig && + inst->state > MSM_VIDC_LOAD_RESOURCES && + inst->state < MSM_VIDC_RELEASE_RESOURCES_DONE) { + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) { + s_vpr_e(inst->sid, + "%s: Failed to move inst: %pK to rel res done\n", + __func__, inst); + } + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(mbuf, dummy, &inst->registeredbufs.list, + list) { + struct vb2_buffer *vb2 = &mbuf->vvb.vb2_buf; + + if (vb2->type != type || vb2->index != index) + continue; + + if (mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING) { + print_vidc_buffer(VIDC_HIGH, + "skip rel buf (rbr pending)", inst, mbuf); + continue; + } + + print_vidc_buffer(VIDC_HIGH, "release buf", inst, mbuf); + msm_comm_unmap_vidc_buffer(inst, mbuf); + list_del(&mbuf->list); + kref_put_mbuf(mbuf); + } + mutex_unlock(&inst->registeredbufs.lock); + + return rc; +} +EXPORT_SYMBOL(msm_vidc_release_buffer); + +int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + unsigned int i = 0; + struct buf_queue *q = NULL; + u32 cr = 0; + + if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) { + d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b); + return -EINVAL; + } + + if (!IS_ALIGNED(b->m.planes[0].length, SZ_4K)) { + s_vpr_e(inst->sid, "qbuf: buffer size not 4K aligned - %u\n", + b->m.planes[0].length); + return -EINVAL; + } + + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + s_vpr_e(inst->sid, + "Failed to find buffer queue. type %d\n", b->type); + return -EINVAL; + } + + mutex_lock(&q->lock); + if ((inst->out_flush && b->type == OUTPUT_MPLANE) || inst->in_flush) { + s_vpr_e(inst->sid, + "%s: in flush, discarding qbuf, type %u, index %u\n", + __func__, b->type, b->index); + rc = -EINVAL; + goto unlock; + } + inst->last_qbuf_time_ns = ktime_get_ns(); + + for (i = 0; i < b->length; i++) { + b->m.planes[i].m.fd = + b->m.planes[i].reserved[MSM_VIDC_BUFFER_FD]; + b->m.planes[i].data_offset = + b->m.planes[i].reserved[MSM_VIDC_DATA_OFFSET]; + } + + /* Compression ratio is valid only for Encoder YUV buffers. */ + if (inst->session_type == MSM_VIDC_ENCODER && + b->type == INPUT_MPLANE) { + cr = b->m.planes[0].reserved[MSM_VIDC_COMP_RATIO]; + msm_comm_update_input_cr(inst, b->index, cr); + } + + if (b->type == INPUT_MPLANE) { + rc = msm_comm_store_input_tag(&inst->etb_data, b->index, + b->m.planes[0].reserved[MSM_VIDC_INPUT_TAG_1], + 0, inst->sid); + if (rc) { + s_vpr_e(inst->sid, "Failed to store input tag"); + rc = -EINVAL; + goto unlock; + } + } + + /* + * set perf mode for image and thumbnail session buffers + * so that they will be processed quickly + */ + if ((is_grid_session(inst) || is_thumbnail_session(inst)) + && b->type == INPUT_MPLANE) + b->flags |= V4L2_BUF_FLAG_PERF_MODE; + + rc = vb2_qbuf(&q->vb2_bufq, b); + if (rc) + s_vpr_e(inst->sid, "Failed to qbuf, %d\n", rc); +unlock: + mutex_unlock(&q->lock); + + return rc; +} +EXPORT_SYMBOL(msm_vidc_qbuf); + +int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + unsigned int i = 0; + struct buf_queue *q = NULL; + + if (!inst || !b || !valid_v4l2_buffer(b, inst)) { + d_vpr_e("%s: invalid params, %pK %pK\n", + __func__, inst, b); + return -EINVAL; + } + + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + s_vpr_e(inst->sid, "Failed to find buffer queue. type %d\n", + b->type); + return -EINVAL; + } + + mutex_lock(&q->lock); + rc = vb2_dqbuf(&q->vb2_bufq, b, true); + mutex_unlock(&q->lock); + if (rc == -EAGAIN) { + return rc; + } else if (rc) { + s_vpr_e(inst->sid, "Failed to dqbuf, %d\n", rc); + return rc; + } + + for (i = 0; i < b->length; i++) { + b->m.planes[i].reserved[MSM_VIDC_BUFFER_FD] = + b->m.planes[i].m.fd; + b->m.planes[i].reserved[MSM_VIDC_DATA_OFFSET] = + b->m.planes[i].data_offset; + } + if (b->type == OUTPUT_MPLANE) { + rc = msm_comm_fetch_input_tag(&inst->fbd_data, b->index, + &b->m.planes[0].reserved[MSM_VIDC_INPUT_TAG_1], + &b->m.planes[0].reserved[MSM_VIDC_INPUT_TAG_2], + inst->sid); + if (rc) { + s_vpr_e(inst->sid, "Failed to fetch input tag"); + return -EINVAL; + } + } + + return rc; +} +EXPORT_SYMBOL(msm_vidc_dqbuf); + +int msm_vidc_streamon(void *instance, enum v4l2_buf_type i) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + struct buf_queue *q; + + if (!inst) + return -EINVAL; + + q = msm_comm_get_vb2q(inst, i); + if (!q) { + d_vpr_e("Failed to find buffer queue. type %d\n", i); + return -EINVAL; + } + s_vpr_h(inst->sid, "Calling streamon\n"); + mutex_lock(&q->lock); + rc = vb2_streamon(&q->vb2_bufq, i); + mutex_unlock(&q->lock); + if (rc) { + s_vpr_e(inst->sid, "streamon failed on port: %d\n", i); + msm_comm_kill_session(inst); + } + return rc; +} +EXPORT_SYMBOL(msm_vidc_streamon); + +int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + struct buf_queue *q; + + if (!inst) + return -EINVAL; + + q = msm_comm_get_vb2q(inst, i); + if (!q) { + s_vpr_e(inst->sid, "Failed to find buffer queue. type %d\n", i); + return -EINVAL; + } + + if (!inst->in_reconfig) { + s_vpr_h(inst->sid, "%s: inst %pK release resources\n", + __func__, inst); + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + s_vpr_e(inst->sid, + "%s: inst %pK move to rel res done failed\n", + __func__, inst); + } + + s_vpr_h(inst->sid, "Calling streamoff\n"); + mutex_lock(&q->lock); + rc = vb2_streamoff(&q->vb2_bufq, i); + mutex_unlock(&q->lock); + if (rc) + s_vpr_e(inst->sid, "streamoff failed on port: %d\n", i); + return rc; +} +EXPORT_SYMBOL(msm_vidc_streamoff); + +int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize) +{ + struct msm_vidc_inst *inst = instance; + struct msm_vidc_capability *capability = NULL; + + if (!inst || !fsize) { + d_vpr_e("%s: invalid parameter: %pK %pK\n", + __func__, inst, fsize); + return -EINVAL; + } + if (!inst->core) + return -EINVAL; + + capability = &inst->capability; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = capability->cap[CAP_FRAME_WIDTH].min; + fsize->stepwise.max_width = capability->cap[CAP_FRAME_WIDTH].max; + fsize->stepwise.step_width = + capability->cap[CAP_FRAME_WIDTH].step_size; + fsize->stepwise.min_height = capability->cap[CAP_FRAME_HEIGHT].min; + fsize->stepwise.max_height = capability->cap[CAP_FRAME_HEIGHT].max; + fsize->stepwise.step_height = + capability->cap[CAP_FRAME_HEIGHT].step_size; + return 0; +} +EXPORT_SYMBOL(msm_vidc_enum_framesizes); + +static void *vidc_get_userptr(struct device *dev, unsigned long vaddr, + unsigned long size, enum dma_data_direction dma_dir) +{ + return (void *)0xdeadbeef; +} + +static void vidc_put_userptr(void *buf_priv) +{ +} + +static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = { + .get_userptr = vidc_get_userptr, + .put_userptr = vidc_put_userptr, +}; + +static void msm_vidc_cleanup_buffer(struct vb2_buffer *vb) +{ + int rc = 0; + struct buf_queue *q = NULL; + struct msm_vidc_inst *inst = NULL; + + if (!vb) { + d_vpr_e("%s: Invalid vb pointer", __func__); + return; + } + + inst = vb2_get_drv_priv(vb->vb2_queue); + if (!inst) { + d_vpr_e("%s: Invalid inst pointer", __func__); + return; + } + + q = msm_comm_get_vb2q(inst, vb->type); + if (!q) { + s_vpr_e(inst->sid, + "%s: Failed to find buffer queue. type %d\n", + __func__, vb->type); + return; + } + + if (q->vb2_bufq.streaming) { + s_vpr_h(inst->sid, "%d PORT is streaming\n", + vb->type); + return; + } + + rc = msm_vidc_release_buffer(inst, vb->type, vb->index); + if (rc) + s_vpr_e(inst->sid, "%s: Failed to release buffers: %d\n", + __func__, rc); +} + +static int msm_vidc_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct msm_vidc_inst *inst; + int rc = 0; + unsigned int i = 0; + struct msm_vidc_format *fmt; + struct v4l2_format *f; + + if (!q || !num_buffers || !num_planes + || !sizes || !q->drv_priv) { + d_vpr_e("Invalid input, q = %pK, %pK, %pK\n", + q, num_buffers, num_planes); + return -EINVAL; + } + inst = q->drv_priv; + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + switch (q->type) { + case INPUT_MPLANE: { + fmt = &inst->fmts[INPUT_PORT]; + if (*num_buffers < fmt->count_min_host) { + s_vpr_h(inst->sid, + "Client passed num buffers %d less than the min_host count %d\n", + *num_buffers, fmt->count_min_host); + } + f = &fmt->v4l2_fmt; + *num_planes = f->fmt.pix_mp.num_planes; + if (*num_buffers < SINGLE_INPUT_BUFFER || + *num_buffers > MAX_NUM_INPUT_BUFFERS) + fmt->count_actual = *num_buffers = + SINGLE_INPUT_BUFFER; + for (i = 0; i < *num_planes; i++) + sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; + + fmt->count_actual = *num_buffers; + } + break; + case OUTPUT_MPLANE: { + fmt = &inst->fmts[OUTPUT_PORT]; + if (inst->session_type != MSM_VIDC_DECODER && + inst->state > MSM_VIDC_LOAD_RESOURCES_DONE) { + if (*num_buffers < fmt->count_min_host) { + s_vpr_h(inst->sid, + "Client passed num buffers %d less than the min_host count %d\n", + *num_buffers, + fmt->count_min_host); + } + } + f = &fmt->v4l2_fmt; + *num_planes = f->fmt.pix_mp.num_planes; + if (*num_buffers < SINGLE_OUTPUT_BUFFER || + *num_buffers > MAX_NUM_OUTPUT_BUFFERS) + fmt->count_actual = *num_buffers = + SINGLE_OUTPUT_BUFFER; + + for (i = 0; i < *num_planes; i++) + sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; + + fmt->count_actual = *num_buffers; + } + break; + default: + s_vpr_e(inst->sid, "Invalid q type = %d\n", q->type); + rc = -EINVAL; + break; + } + + s_vpr_h(inst->sid, + "queue_setup:type %d num_buffers %d num_planes %d sizes[0] %d sizes[1] %d\n", + q->type, *num_buffers, *num_planes, sizes[0], sizes[1]); + return rc; +} + +static inline int msm_vidc_verify_buffer_counts(struct msm_vidc_inst *inst) +{ + int rc = 0, i = 0; + + /* For decoder No need to sanity till LOAD_RESOURCES */ + if (inst->session_type == MSM_VIDC_DECODER && + (inst->state < MSM_VIDC_LOAD_RESOURCES_DONE || + inst->state >= MSM_VIDC_RELEASE_RESOURCES_DONE)) { + s_vpr_h(inst->sid, "No need to verify buffer counts\n"); + return 0; + } + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements *req = &inst->buff_req.buffer[i]; + + if (req && (req->buffer_type == HAL_BUFFER_OUTPUT)) { + s_vpr_h(inst->sid, "Verifying Buffer : %d\n", + req->buffer_type); + if (req->buffer_count_actual < + req->buffer_count_min_host || + req->buffer_count_min_host < + req->buffer_count_min) { + + s_vpr_e(inst->sid, + "Invalid data : Counts mismatch\n"); + s_vpr_e(inst->sid, "Min Count = %d ", + req->buffer_count_min); + s_vpr_e(inst->sid, "Min Host Count = %d ", + req->buffer_count_min_host); + s_vpr_e(inst->sid, "Min Actual Count = %d\n", + req->buffer_count_actual); + rc = -EINVAL; + break; + } + } + } + return rc; +} + +static int msm_vidc_set_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (is_decode_session(inst)) + rc = msm_vdec_set_properties(inst); + else if (is_encode_session(inst)) + rc = msm_venc_set_properties(inst); + + return rc; +} + +static inline int start_streaming(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_buffer_size_minimum b; + struct v4l2_format *f; + + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + hdev = inst->core->device; + + rc = msm_vidc_set_properties(inst); + if (rc) { + s_vpr_e(inst->sid, "%s: set props failed\n", __func__); + goto fail_start; + } + + b.buffer_type = HFI_BUFFER_OUTPUT; + if (inst->session_type == MSM_VIDC_DECODER && + is_secondary_output_mode(inst)) { + b.buffer_type = HFI_BUFFER_OUTPUT2; + rc = msm_comm_update_dpb_bufreqs(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: set dpb bufreq failed\n", __func__); + goto fail_start; + } + } + + /* Check if current session is under HW capability */ + rc = msm_vidc_check_session_supported(inst); + if (rc) { + s_vpr_e(inst->sid, "This session is not supported\n"); + goto fail_start; + } + + rc = msm_vidc_check_scaling_supported(inst); + if (rc) { + s_vpr_e(inst->sid, "scaling is not supported\n"); + goto fail_start; + } + + /* Decide work mode for current session */ + rc = call_core_op(inst->core, decide_work_mode, inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to decide work mode\n"); + goto fail_start; + } + + /* Decide work route for current session */ + rc = call_core_op(inst->core, decide_work_route, inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to decide work route\n"); + goto fail_start; + } + + /* Assign Core and LP mode for current session */ + rc = call_core_op(inst->core, decide_core_and_power_mode, inst); + if (rc) { + s_vpr_e(inst->sid, + "This session can't be submitted to HW %pK\n", inst); + goto fail_start; + } + + rc = msm_comm_try_get_bufreqs(inst); + + rc = msm_comm_check_memory_supported(inst); + if (rc) { + s_vpr_e(inst->sid, + "Memory not sufficient to proceed current session\n"); + goto fail_start; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + b.buffer_size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM, + &b, sizeof(b)); + + /* Verify if buffer counts are correct */ + rc = msm_vidc_verify_buffer_counts(inst); + if (rc) { + s_vpr_e(inst->sid, + "This session has mis-match buffer counts%pK\n", inst); + goto fail_start; + } + + rc = msm_comm_set_scratch_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to set scratch buffers: %d\n", rc); + goto fail_start; + } + rc = msm_comm_set_persist_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to set persist buffers: %d\n", rc); + goto fail_start; + } + + rc = msm_comm_set_recon_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to set recon buffers: %d\n", rc); + goto fail_start; + } + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + rc = msm_comm_set_dpb_only_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed to set output buffers: %d\n", rc); + goto fail_start; + } + } + + inst->batch.enable = is_batching_allowed(inst); + s_vpr_hp(inst->sid, "%s: batching %s for inst %pK\n", + __func__, inst->batch.enable ? "enabled" : "disabled", inst); + + msm_dcvs_try_enable(inst); + + /* + * For seq_changed_insufficient, driver should set session_continue + * to firmware after the following sequence + * - driver raises insufficient event to v4l2 client + * - all output buffers have been flushed and freed + * - v4l2 client queries buffer requirements and splits/combines OPB-DPB + * - v4l2 client sets new set of buffers to firmware + * - v4l2 client issues CONTINUE to firmware to resume decoding of + * submitted ETBs. + */ + rc = msm_comm_session_continue(inst); + if (rc) + goto fail_start; + + msm_comm_scale_clocks_and_bus(inst, 1); + + rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE); + if (rc) { + s_vpr_e(inst->sid, + "Failed to move inst: %pK to start done state\n", inst); + goto fail_start; + } + + msm_clock_data_reset(inst); + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + rc = msm_comm_queue_dpb_only_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed to queue output buffers: %d\n", rc); + goto fail_start; + } + } + +fail_start: + if (rc) + s_vpr_e(inst->sid, "%s: inst %pK failed to start\n", + __func__, inst); + return rc; +} + +static int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct msm_vidc_inst *inst; + int rc = 0; + struct hfi_device *hdev; + + if (!q || !q->drv_priv) { + d_vpr_e("Invalid input, q = %pK\n", q); + return -EINVAL; + } + inst = q->drv_priv; + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + s_vpr_h(inst->sid, "Streamon called on: %d capability for inst: %pK\n", + q->type, inst); + switch (q->type) { + case INPUT_MPLANE: + if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) + rc = start_streaming(inst); + break; + case OUTPUT_MPLANE: + if (inst->bufq[INPUT_PORT].vb2_bufq.streaming) + rc = start_streaming(inst); + break; + default: + s_vpr_e(inst->sid, + "Queue type is not supported: %d\n", q->type); + rc = -EINVAL; + goto stream_start_failed; + } + if (rc) { + s_vpr_e(inst->sid, "Streamon failed: %d, inst: %pK\n", + q->type, inst); + goto stream_start_failed; + } + + rc = msm_comm_qbufs(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed to commit buffers queued before STREAM_ON: %d\n", + rc); + goto stream_start_failed; + } + + rc = msm_vidc_send_pending_eos_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, "Failed : Send pending EOS: %d\n", rc); + goto stream_start_failed; + } + +stream_start_failed: + if (rc) { + struct msm_vidc_buffer *temp, *next; + struct vb2_buffer *vb; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, + list) { + if (temp->vvb.vb2_buf.type != q->type) + continue; + /* + * queued_list lock is already acquired before + * vb2_stream so no need to acquire it again. + */ + list_for_each_entry(vb, &q->queued_list, queued_entry) { + if (msm_comm_compare_vb2_planes(inst, temp, + vb)) { + print_vb2_buffer("return vb", inst, vb); + vb2_buffer_done(vb, + VB2_BUF_STATE_QUEUED); + break; + } + } + msm_comm_unmap_vidc_buffer(inst, temp); + list_del(&temp->list); + kref_put_mbuf(temp); + } + mutex_unlock(&inst->registeredbufs.lock); + } + return rc; +} + +static inline int stop_streaming(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + s_vpr_e(inst->sid, "Failed to move inst: %pK to state %d\n", + inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + + if (is_encode_session(inst)) { + inst->all_intra = false; + } + + msm_clock_data_reset(inst); + + return rc; +} + +static void msm_vidc_stop_streaming(struct vb2_queue *q) +{ + struct msm_vidc_inst *inst; + int rc = 0; + + if (!q || !q->drv_priv) { + d_vpr_e("Invalid input, q = %pK\n", q); + return; + } + + inst = q->drv_priv; + s_vpr_h(inst->sid, "Streamoff called on: %d capability\n", q->type); + switch (q->type) { + case INPUT_MPLANE: + if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) + rc = stop_streaming(inst); + break; + case OUTPUT_MPLANE: + if (!inst->bufq[INPUT_PORT].vb2_bufq.streaming) + rc = stop_streaming(inst); + break; + default: + s_vpr_e(inst->sid, "Q-type is not supported: %d\n", q->type); + rc = -EINVAL; + break; + } + + msm_comm_scale_clocks_and_bus(inst, 1); + + if (rc) + s_vpr_e(inst->sid, + "Failed STOP Streaming inst = %pK on cap = %d\n", + inst, q->type); +} + +static int msm_vidc_queue_buf(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_buffer *mbuf; + + if (!inst || !vb2) { + d_vpr_e("%s: invalid params %pK, %pK\n", + __func__, inst, vb2); + return -EINVAL; + } + + mbuf = msm_comm_get_vidc_buffer(inst, vb2); + if (IS_ERR_OR_NULL(mbuf)) { + /* + * if the buffer has RBR_PENDING flag (-EEXIST) then don't queue + * it now, it will be queued via msm_comm_qbuf_rbr() as part of + * RBR event processing. + */ + if (PTR_ERR(mbuf) == -EEXIST) + return 0; + s_vpr_e(inst->sid, "%s: failed to get vidc-buf\n", __func__); + return -EINVAL; + } + if (!kref_get_mbuf(inst, mbuf)) { + s_vpr_e(inst->sid, "%s: mbuf not found\n", __func__); + return -EINVAL; + } + rc = msm_comm_qbuf(inst, mbuf); + if (rc) + s_vpr_e(inst->sid, "%s: failed qbuf\n", __func__); + kref_put_mbuf(mbuf); + + return rc; +} + +static int msm_vidc_queue_buf_decode_batch(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc; + struct msm_vidc_buffer *mbuf; + + if (!inst || !vb2) { + d_vpr_e("%s: invalid params %pK, %pK\n", + __func__, inst, vb2); + return -EINVAL; + } + + mbuf = msm_comm_get_vidc_buffer(inst, vb2); + if (IS_ERR_OR_NULL(mbuf)) { + s_vpr_e(inst->sid, "%s: failed to get vidc-buf\n", __func__); + return -EINVAL; + } + if (!kref_get_mbuf(inst, mbuf)) { + s_vpr_e(inst->sid, "%s: mbuf not found\n", __func__); + return -EINVAL; + } + /* + * If this buffer has RBR_EPNDING then it will not be queued + * but it may trigger full batch queuing in below function. + */ + rc = msm_comm_qbuf_decode_batch(inst, mbuf); + if (rc) + s_vpr_e(inst->sid, "%s: failed qbuf\n", __func__); + kref_put_mbuf(mbuf); + + return rc; +} + +static int msm_vidc_queue_buf_batch(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc; + + if (!inst || !vb2) { + d_vpr_e("%s: invalid params %pK, %pK\n", + __func__, inst, vb2); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_DECODER && + vb2->type == OUTPUT_MPLANE) + rc = msm_vidc_queue_buf_decode_batch(inst, vb2); + else + rc = msm_vidc_queue_buf(inst, vb2); + + return rc; +} + +static void msm_vidc_buf_queue(struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_inst *inst = NULL; + + inst = vb2_get_drv_priv(vb2->vb2_queue); + if (!inst) { + d_vpr_e("%s: invalid inst\n", __func__); + return; + } + + if (inst->batch.enable) + rc = msm_vidc_queue_buf_batch(inst, vb2); + else + rc = msm_vidc_queue_buf(inst, vb2); + + if (rc) { + print_vb2_buffer("failed vb2-qbuf", inst, vb2); + vb2_buffer_done(vb2, VB2_BUF_STATE_DONE); + msm_vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_SYS_ERROR); + } +} + +static const struct vb2_ops msm_vidc_vb2q_ops = { + .queue_setup = msm_vidc_queue_setup, + .start_streaming = msm_vidc_start_streaming, + .buf_queue = msm_vidc_buf_queue, + .buf_cleanup = msm_vidc_cleanup_buffer, + .stop_streaming = msm_vidc_stop_streaming, +}; + +static inline int vb2_bufq_init(struct msm_vidc_inst *inst, + enum v4l2_buf_type type, enum session_type sess) +{ + struct vb2_queue *q = NULL; + + if (type == OUTPUT_MPLANE) { + q = &inst->bufq[OUTPUT_PORT].vb2_bufq; + } else if (type == INPUT_MPLANE) { + q = &inst->bufq[INPUT_PORT].vb2_bufq; + } else { + s_vpr_e(inst->sid, "buf_type = %d not recognised\n", type); + return -EINVAL; + } + + q->type = type; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->ops = &msm_vidc_vb2q_ops; + + q->mem_ops = &msm_vidc_vb2_mem_ops; + q->drv_priv = inst; + q->allow_zero_bytesused = !V4L2_TYPE_IS_OUTPUT(type); + q->copy_timestamp = 1; + return vb2_queue_init(q); +} + +static int setup_event_queue(void *inst, + struct video_device *pvdev) +{ + struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst; + + v4l2_fh_init(&vidc_inst->event_handler, pvdev); + v4l2_fh_add(&vidc_inst->event_handler); + + return 0; +} + +int msm_vidc_subscribe_event(void *inst, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst; + + if (!inst || !sub) + return -EINVAL; + + rc = v4l2_event_subscribe(&vidc_inst->event_handler, + sub, MAX_EVENTS, NULL); + return rc; +} +EXPORT_SYMBOL(msm_vidc_subscribe_event); + +int msm_vidc_unsubscribe_event(void *inst, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst; + + if (!inst || !sub) + return -EINVAL; + + rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub); + return rc; +} +EXPORT_SYMBOL(msm_vidc_unsubscribe_event); + +int msm_vidc_dqevent(void *inst, struct v4l2_event *event) +{ + int rc = 0; + struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst; + + if (!inst || !event) + return -EINVAL; + + rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false); + return rc; +} +EXPORT_SYMBOL(msm_vidc_dqevent); + +int msm_vidc_private(void *vidc_inst, unsigned int cmd, + struct msm_vidc_arg *arg) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst; + + if (!inst || !arg) { + d_vpr_e("%s: invalid args\n", __func__); + return -EINVAL; + } + if (cmd != VIDIOC_VIDEO_CMD) { + s_vpr_e(inst->sid, + "%s: invalid private cmd %#x\n", __func__, cmd); + return -ENOIOCTLCMD; + } + + if (inst->session_type == MSM_VIDC_CVP) { + rc = msm_vidc_cvp(inst, arg); + } else { + s_vpr_e(inst->sid, + "%s: private cmd %#x not supported for session_type %d\n", + __func__, cmd, inst->session_type); + rc = -EINVAL; + } + + return rc; +} +EXPORT_SYMBOL(msm_vidc_private); + +static int msm_vidc_try_set_ctrl(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = instance; + + if (inst->session_type == MSM_VIDC_DECODER) + return msm_vdec_s_ctrl(instance, ctrl); + else if (inst->session_type == MSM_VIDC_ENCODER) + return msm_venc_s_ctrl(instance, ctrl); + return -EINVAL; +} + +static int msm_vidc_op_s_ctrl(struct v4l2_ctrl *ctrl) +{ + + int rc = 0; + struct msm_vidc_inst *inst; + const char *ctrl_name = NULL; + + if (!ctrl) { + d_vpr_e("%s: invalid parameters for ctrl\n", __func__); + return -EINVAL; + } + + inst = container_of(ctrl->handler, + struct msm_vidc_inst, ctrl_handler); + if (!inst) { + d_vpr_e("%s: invalid parameters for inst\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_try_set_ctrl(inst, ctrl); + if (rc) { + s_vpr_e(inst->sid, "Failed setting %x\n", ctrl->id); + ctrl_name = v4l2_ctrl_get_name(ctrl->id); + s_vpr_e(inst->sid, "Failed setting control: Inst = %pK (%s)\n", + inst, ctrl_name ? ctrl_name : "Invalid ctrl"); + } + + return rc; +} + +static int try_get_ctrl_for_instance(struct msm_vidc_inst *inst, + struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + ctrl->val = msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + inst->profile, inst->sid); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + ctrl->val = msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + inst->profile, inst->sid); + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + ctrl->val = msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + inst->level, inst->sid); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + ctrl->val = msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + inst->level, inst->sid); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + ctrl->val = msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + inst->level, inst->sid); + break; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + ctrl->val = inst->fmts[OUTPUT_PORT].count_min_host; + s_vpr_h(inst->sid, "g_min: hal_buffer %d min buffers %d\n", + HAL_BUFFER_OUTPUT, ctrl->val); + break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + ctrl->val = inst->fmts[INPUT_PORT].count_min_host; + s_vpr_h(inst->sid, "g_min: hal_buffer %d min buffers %d\n", + HAL_BUFFER_INPUT, ctrl->val); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: + ctrl->val = inst->prop.extradata_ctrls; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE: + { + uint32_t vpu_ver; + + if (!inst->core || !inst->core->platform_data) + return -EINVAL; + vpu_ver = inst->core->platform_data->vpu_ver; + ctrl->val = (vpu_ver == VPU_VERSION_IRIS1 || + vpu_ver == VPU_VERSION_IRIS2 || + vpu_ver == VPU_VERSION_IRIS2_1) ? + V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BYTE : + V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BIT; + break; + } + default: + break; + } + + return rc; +} + +static const struct v4l2_ctrl_ops msm_vidc_ctrl_ops = { + + .s_ctrl = msm_vidc_op_s_ctrl, +}; + +static struct msm_vidc_inst_smem_ops msm_vidc_smem_ops = { + .smem_map_dma_buf = msm_smem_map_dma_buf, + .smem_unmap_dma_buf = msm_smem_unmap_dma_buf, +}; + +void *msm_vidc_open(int core_id, int session_type) +{ + struct msm_vidc_inst *inst = NULL; + struct msm_vidc_core *core = NULL; + int rc = 0; + int i = 0; + + if (core_id >= MSM_VIDC_CORES_MAX || + session_type >= MSM_VIDC_MAX_DEVICES) { + d_vpr_e("Invalid input, core_id = %d, session = %d\n", + core_id, session_type); + goto err_invalid_core; + } + core = get_vidc_core(core_id); + if (!core) { + d_vpr_e("Failed to find core for core_id = %d\n", core_id); + goto err_invalid_core; + } + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) { + d_vpr_e("Failed to allocate memory\n"); + rc = -ENOMEM; + goto err_invalid_core; + } + mutex_lock(&core->lock); + rc = get_sid(&inst->sid, session_type); + mutex_unlock(&core->lock); + if (rc) { + d_vpr_e("Total instances count reached to max value\n"); + goto err_invalid_sid; + } + + pr_info(VIDC_DBG_TAG "Opening video instance: %pK, %d\n", + "high", inst->sid, get_codec_name(inst->sid), + inst, session_type); + mutex_init(&inst->sync_lock); + mutex_init(&inst->bufq[OUTPUT_PORT].lock); + mutex_init(&inst->bufq[INPUT_PORT].lock); + mutex_init(&inst->lock); + + INIT_MSM_VIDC_LIST(&inst->scratchbufs); + INIT_MSM_VIDC_LIST(&inst->input_crs); + INIT_MSM_VIDC_LIST(&inst->persistbufs); + INIT_MSM_VIDC_LIST(&inst->pending_getpropq); + INIT_MSM_VIDC_LIST(&inst->outputbufs); + INIT_MSM_VIDC_LIST(&inst->registeredbufs); + INIT_MSM_VIDC_LIST(&inst->cvpbufs); + INIT_MSM_VIDC_LIST(&inst->refbufs); + INIT_MSM_VIDC_LIST(&inst->eosbufs); + INIT_MSM_VIDC_LIST(&inst->etb_data); + INIT_MSM_VIDC_LIST(&inst->fbd_data); + INIT_MSM_VIDC_LIST(&inst->window_data); + + INIT_DELAYED_WORK(&inst->batch_work, msm_vidc_batch_handler); + kref_init(&inst->kref); + + inst->session_type = session_type; + inst->state = MSM_VIDC_CORE_UNINIT_DONE; + inst->core = core; + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; + inst->clk_data.dpb_fourcc = V4L2_PIX_FMT_NV12_UBWC; + inst->clk_data.opb_fourcc = V4L2_PIX_FMT_NV12_UBWC; + inst->bit_depth = MSM_VIDC_BIT_DEPTH_8; + inst->pic_struct = MSM_VIDC_PIC_STRUCT_PROGRESSIVE; + inst->colour_space = MSM_VIDC_BT601_6_525; + inst->smem_ops = &msm_vidc_smem_ops; + inst->rc_type = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; + inst->dpb_extra_binfo = NULL; + inst->all_intra = false; + inst->max_filled_len = 0; + inst->entropy_mode = HFI_H264_ENTROPY_CABAC; + inst->full_range = COLOR_RANGE_UNSPECIFIED; + inst->active = true; + + for (i = SESSION_MSG_INDEX(SESSION_MSG_START); + i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { + init_completion(&inst->completions[i]); + } + + if (session_type == MSM_VIDC_DECODER) { + msm_vdec_inst_init(inst); + rc = msm_vdec_ctrl_init(inst, &msm_vidc_ctrl_ops); + } else if (session_type == MSM_VIDC_ENCODER) { + msm_venc_inst_init(inst); + rc = msm_venc_ctrl_init(inst, &msm_vidc_ctrl_ops); + } else if (session_type == MSM_VIDC_CVP) { + msm_cvp_inst_init(inst); + rc = msm_cvp_ctrl_init(inst, &msm_vidc_ctrl_ops); + } + if (rc) { + s_vpr_e(inst->sid, "Failed control initialization\n"); + goto fail_bufq_capture; + } + + rc = vb2_bufq_init(inst, OUTPUT_MPLANE, session_type); + if (rc) { + s_vpr_e(inst->sid, + "Failed to initialize vb2 queue on capture port\n"); + goto fail_bufq_capture; + } + rc = vb2_bufq_init(inst, INPUT_MPLANE, session_type); + if (rc) { + s_vpr_e(inst->sid, + "Failed to initialize vb2 queue on capture port\n"); + goto fail_bufq_output; + } + + setup_event_queue(inst, &core->vdev[session_type].vdev); + + mutex_lock(&core->lock); + list_add_tail(&inst->list, &core->instances); + mutex_unlock(&core->lock); + + rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE); + if (rc) { + s_vpr_e(inst->sid, + "Failed to move video instance to init state\n"); + goto fail_init; + } + + if (msm_comm_check_for_inst_overload(core)) { + s_vpr_e(inst->sid, + "Instance count reached Max limit, rejecting session"); + goto fail_init; + } + + msm_comm_scale_clocks_and_bus(inst, 1); + + inst->debugfs_root = + msm_vidc_debugfs_init_inst(inst, core->debugfs_root); + + if (inst->session_type == MSM_VIDC_CVP) { + rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); + if (rc) { + s_vpr_e(inst->sid, + "Failed to move video instance to open done state\n"); + goto fail_init; + } + } + + return inst; +fail_init: + mutex_lock(&core->lock); + list_del(&inst->list); + mutex_unlock(&core->lock); + + v4l2_fh_del(&inst->event_handler); + v4l2_fh_exit(&inst->event_handler); + vb2_queue_release(&inst->bufq[INPUT_PORT].vb2_bufq); +fail_bufq_output: + vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); +fail_bufq_capture: + msm_comm_ctrl_deinit(inst); + mutex_destroy(&inst->sync_lock); + mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); + mutex_destroy(&inst->bufq[INPUT_PORT].lock); + mutex_destroy(&inst->lock); + + DEINIT_MSM_VIDC_LIST(&inst->scratchbufs); + DEINIT_MSM_VIDC_LIST(&inst->persistbufs); + DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq); + DEINIT_MSM_VIDC_LIST(&inst->outputbufs); + DEINIT_MSM_VIDC_LIST(&inst->cvpbufs); + DEINIT_MSM_VIDC_LIST(&inst->registeredbufs); + DEINIT_MSM_VIDC_LIST(&inst->eosbufs); + DEINIT_MSM_VIDC_LIST(&inst->input_crs); + DEINIT_MSM_VIDC_LIST(&inst->etb_data); + DEINIT_MSM_VIDC_LIST(&inst->fbd_data); + DEINIT_MSM_VIDC_LIST(&inst->window_data); + +err_invalid_sid: + put_sid(inst->sid); + kfree(inst); + inst = NULL; +err_invalid_core: + return inst; +} +EXPORT_SYMBOL(msm_vidc_open); + +static void msm_vidc_cleanup_instance(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffer *temp, *dummy; + struct getprop_buf *temp_prop, *dummy_prop; + struct list_head *ptr, *next; + enum vidc_ports ports[] = {INPUT_PORT, OUTPUT_PORT}; + int c = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + for (c = 0; c < ARRAY_SIZE(ports); ++c) { + enum vidc_ports port = ports[c]; + + mutex_lock(&inst->bufq[port].lock); + list_for_each_safe(ptr, next, + &inst->bufq[port].vb2_bufq.queued_list) { + struct vb2_buffer *vb = container_of(ptr, + struct vb2_buffer, queued_entry); + if (vb->state == VB2_BUF_STATE_ACTIVE) { + vb->planes[0].bytesused = 0; + print_vb2_buffer("undequeud vb2", inst, vb); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + } + } + mutex_unlock(&inst->bufq[port].lock); + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, dummy, &inst->registeredbufs.list, + list) { + print_vidc_buffer(VIDC_ERR, "undequeud buf", inst, temp); + msm_comm_unmap_vidc_buffer(inst, temp); + list_del(&temp->list); + kref_put_mbuf(temp); + } + mutex_unlock(&inst->registeredbufs.lock); + + cancel_batch_work(inst); + + msm_comm_free_input_cr_table(inst); + + if (msm_comm_release_scratch_buffers(inst, false)) + s_vpr_e(inst->sid, "Failed to release scratch buffers\n"); + + if (msm_comm_release_recon_buffers(inst)) + s_vpr_e(inst->sid, "Failed to release recon buffers\n"); + + if (msm_comm_release_persist_buffers(inst)) + s_vpr_e(inst->sid, "Failed to release persist buffers\n"); + + if (msm_comm_release_input_tag(inst)) + s_vpr_e(inst->sid, "Failed to release input_tag buffers\n"); + + msm_comm_release_window_data(inst); + + msm_comm_release_eos_buffers(inst); + + if (msm_comm_release_dpb_only_buffers(inst, true)) + s_vpr_e(inst->sid, "Failed to release output buffers\n"); + + if (inst->extradata_handle) + msm_comm_smem_free(inst, inst->extradata_handle); + + mutex_lock(&inst->pending_getpropq.lock); + if (!list_empty(&inst->pending_getpropq.list)) { + s_vpr_e(inst->sid, "pending_getpropq not empty\n"); + list_for_each_entry_safe(temp_prop, dummy_prop, + &inst->pending_getpropq.list, list) { + kfree(temp_prop->data); + list_del(&temp_prop->list); + kfree(temp_prop); + } + } + mutex_unlock(&inst->pending_getpropq.lock); +} + +int msm_vidc_destroy(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + int i = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + core = inst->core; + + for (i = 0; i < MAX_PORT_NUM; i++) + vb2_queue_release(&inst->bufq[i].vb2_bufq); + + mutex_lock(&core->lock); + /* inst->list lives in core->instances */ + list_del(&inst->list); + mutex_unlock(&core->lock); + + msm_comm_ctrl_deinit(inst); + + v4l2_fh_del(&inst->event_handler); + v4l2_fh_exit(&inst->event_handler); + + DEINIT_MSM_VIDC_LIST(&inst->scratchbufs); + DEINIT_MSM_VIDC_LIST(&inst->persistbufs); + DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq); + DEINIT_MSM_VIDC_LIST(&inst->outputbufs); + DEINIT_MSM_VIDC_LIST(&inst->cvpbufs); + DEINIT_MSM_VIDC_LIST(&inst->registeredbufs); + DEINIT_MSM_VIDC_LIST(&inst->eosbufs); + DEINIT_MSM_VIDC_LIST(&inst->input_crs); + DEINIT_MSM_VIDC_LIST(&inst->etb_data); + DEINIT_MSM_VIDC_LIST(&inst->fbd_data); + DEINIT_MSM_VIDC_LIST(&inst->window_data); + + mutex_destroy(&inst->sync_lock); + mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); + mutex_destroy(&inst->bufq[INPUT_PORT].lock); + mutex_destroy(&inst->lock); + + msm_vidc_debugfs_deinit_inst(inst); + + pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n", + "high", inst->sid, get_codec_name(inst->sid), + inst); + put_sid(inst->sid); + kfree(inst); + return 0; +} + +static void close_helper(struct kref *kref) +{ + struct msm_vidc_inst *inst = container_of(kref, + struct msm_vidc_inst, kref); + + msm_vidc_destroy(inst); +} + +int msm_vidc_close(void *instance) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* + * Make sure that HW stop working on these buffers that + * we are going to free. + */ + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + s_vpr_e(inst->sid, "Failed: move to rel resource done state\n"); + + /* + * deinit instance after REL_RES_DONE to ensure hardware + * released all buffers. + */ + if (inst->session_type == MSM_VIDC_CVP) + msm_cvp_inst_deinit(inst); + + msm_vidc_cleanup_instance(inst); + + rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT); + if (rc) { + s_vpr_e(inst->sid, + "Failed to move inst %pK to uninit state\n", inst); + rc = msm_comm_force_cleanup(inst); + } + + msm_comm_session_clean(inst); + + kref_put(&inst->kref, close_helper); + return 0; +} +EXPORT_SYMBOL(msm_vidc_close); + +int msm_vidc_suspend(int core_id) +{ + return msm_comm_suspend(core_id); +} +EXPORT_SYMBOL(msm_vidc_suspend); + diff --git a/techpack/video/msm/vidc/msm_vidc.h b/techpack/video/msm/vidc/msm_vidc.h new file mode 100644 index 0000000000000000000000000000000000000000..7fb249184c13109f76730759130cb120e27a6160 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_VIDC_H_ +#define _MSM_VIDC_H_ + +#include <linux/poll.h> +#include <linux/videodev2.h> +#include <linux/types.h> +#include <linux/msm_ion.h> +#include <media/msm_vidc_private.h> +#include <media/msm_vidc_utils.h> + +#define HAL_BUFFER_MAX 0xe + +#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 22) +enum v4l2_mpeg_vidc_video_decoder_multi_stream { + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY = 0, + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1, +}; + +enum smem_type { + SMEM_DMA = 1, +}; + +enum smem_prop { + SMEM_UNCACHED = 0x1, + SMEM_CACHED = 0x2, + SMEM_SECURE = 0x4, + SMEM_ADSP = 0x8, +}; + +/* NOTE: if you change this enum you MUST update the + * "buffer-type-tz-usage-table" for any affected target + * in arch/arm/boot/dts/<arch>.dtsi + */ +enum hal_buffer { + HAL_BUFFER_NONE = 0x0, + HAL_BUFFER_INPUT = 0x1, + HAL_BUFFER_OUTPUT = 0x2, + HAL_BUFFER_OUTPUT2 = 0x4, + HAL_BUFFER_EXTRADATA_INPUT = 0x8, + HAL_BUFFER_EXTRADATA_OUTPUT = 0x10, + HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20, + HAL_BUFFER_INTERNAL_SCRATCH = 0x40, + HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80, + HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100, + HAL_BUFFER_INTERNAL_PERSIST = 0x200, + HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400, + HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800, + HAL_BUFFER_INTERNAL_RECON = 0x1000, +}; + +struct dma_mapping_info { + struct device *dev; + struct iommu_domain *domain; + struct sg_table *table; + struct dma_buf_attachment *attach; + struct dma_buf *buf; + void *cb_info; +}; + +struct msm_smem { + u32 refcount; + int fd; + void *dma_buf; + void *kvaddr; + u32 device_addr; + dma_addr_t dma_handle; + unsigned int offset; + unsigned int size; + unsigned long flags; + enum hal_buffer buffer_type; + struct dma_mapping_info mapping_info; +}; + +enum smem_cache_ops { + SMEM_CACHE_CLEAN, + SMEM_CACHE_INVALIDATE, + SMEM_CACHE_CLEAN_INVALIDATE, +}; + +enum core_id { + MSM_VIDC_CORE_VENUS = 0, + MSM_VIDC_CORE_Q6, + MSM_VIDC_CORES_MAX, +}; +enum session_type { + MSM_VIDC_ENCODER = 0, + MSM_VIDC_DECODER, + MSM_VIDC_CVP, + MSM_VIDC_UNKNOWN, + MSM_VIDC_MAX_DEVICES = MSM_VIDC_UNKNOWN, +}; + +enum load_type { + MSM_VIDC_VIDEO = 0, + MSM_VIDC_IMAGE, +}; + +union msm_v4l2_cmd { + struct v4l2_decoder_cmd dec; + struct v4l2_encoder_cmd enc; +}; + +void *msm_vidc_open(int core_id, int session_type); +int msm_vidc_close(void *instance); +int msm_vidc_suspend(int core_id); +int msm_vidc_querycap(void *instance, struct v4l2_capability *cap); +int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f); +int msm_vidc_s_fmt(void *instance, struct v4l2_format *f); +int msm_vidc_g_fmt(void *instance, struct v4l2_format *f); +int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a); +int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a); +int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *a); +int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a); +int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b); +int msm_vidc_release_buffer(void *instance, int buffer_type, + unsigned int buffer_index); +int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b); +int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b); +int msm_vidc_streamon(void *instance, enum v4l2_buf_type i); +int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *ctrl); +int msm_vidc_query_menu(void *instance, struct v4l2_querymenu *qmenu); +int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i); +int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd); +int msm_vidc_poll(void *instance, struct file *filp, + struct poll_table_struct *pt); +int msm_vidc_subscribe_event(void *instance, + const struct v4l2_event_subscription *sub); +int msm_vidc_unsubscribe_event(void *instance, + const struct v4l2_event_subscription *sub); +int msm_vidc_dqevent(void *instance, struct v4l2_event *event); +int msm_vidc_g_crop(void *instance, struct v4l2_crop *a); +int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize); +int msm_vidc_private(void *vidc_inst, unsigned int cmd, + struct msm_vidc_arg *arg); +#endif diff --git a/techpack/video/msm/vidc/msm_vidc_buffer_calculations.c b/techpack/video/msm/vidc/msm_vidc_buffer_calculations.c new file mode 100644 index 0000000000000000000000000000000000000000..c7af4a27642135587b36c313f34115cdeba13721 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_buffer_calculations.c @@ -0,0 +1,1921 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_debug.h" +#include "msm_vidc_common.h" +#include "msm_vidc_buffer_calculations.h" +#include "msm_vidc_clocks.h" + +#define VP9_REFERENCE_COUNT 8 + +/* minimum number of input buffers */ +#define MIN_INPUT_BUFFERS 4 +/* Max number of PERF eligible sessions */ +#define MAX_PERF_ELIGIBLE_SESSIONS 4 + +/* Decoder buffer count macros */ +/* total input buffers in case of decoder batch */ +#define BATCH_DEC_TOTAL_INPUT_BUFFERS 6 + +/* total input buffers for decoder HFR usecase (fps capability > 480) */ +#define MAX_HFR_DEC_TOTAL_INPUT_BUFFERS 12 + +/* total input buffers for decoder HFR usecase (fps capablity <= 480) */ +#define MIN_HFR_DEC_TOTAL_INPUT_BUFFERS 8 + + +/* extra output buffers in case of decoder batch */ +#define BATCH_DEC_EXTRA_OUTPUT_BUFFERS 6 + +/* Encoder buffer count macros */ +/* total input buffers for encoder HFR usecase */ +#define HFR_ENC_TOTAL_INPUT_BUFFERS 16 + +/* minimum number of output buffers */ +#define MIN_ENC_OUTPUT_BUFFERS 4 + +/* extra output buffers for encoder HFR usecase */ +#define HFR_ENC_TOTAL_OUTPUT_BUFFERS 12 + +/* extra output buffers for encoder HEIF usecase */ +#define HEIF_ENC_TOTAL_OUTPUT_BUFFERS 12 + +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH 32 +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT 8 +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH 16 +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT 8 +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH 48 +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT 4 +#define BUFFER_ALIGNMENT_4096_BYTES 4096 +#define VENUS_METADATA_STRIDE_MULTIPLE 64 +#define VENUS_METADATA_HEIGHT_MULTIPLE 16 +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE \ + ((metadataStride, width, metadataStrideMultiple, tileWidthInPels) \ + metadataStride = ALIGN(((width + (tileWidthInPels - 1)) / \ + tileWidthInPels), metadataStrideMultiple)) +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT \ + ((metadataBufHeight, height, metadataHeightMultiple, tileHeightInPels) \ + metadataBufHeight = ALIGN(((height + (tileHeightInPels - 1)) / \ + tileHeightInPels), metadataHeightMultiple)) +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE \ + ((buffersize, MetadataStride, MetadataBufHeight) \ + buffersize = ALIGN(MetadataStride * MetadataBufHeight, \ + BUFFER_ALIGNMENT_4096_BYTES)) +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE \ + ((metadataStride, width, metadataStrideMultiple, tileWidthInPels) \ + metadataStride = ALIGN(((((width + 1) >> 1) + \ + (tileWidthInPels - 1)) / tileWidthInPels), \ + metadataStrideMultiple)) +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT \ + ((metadataBufHeight, height, metadataHeightMultiple, tileHeightInPels) \ + metadataBufHeight = ALIGN(((((height + 1) >> 1) + \ + (tileHeightInPels - 1)) / tileHeightInPels), \ + metadataHeightMultiple)) + +#define BUFFER_ALIGNMENT_SIZE(x) x + +#define VENUS_DMA_ALIGNMENT BUFFER_ALIGNMENT_SIZE(256) + +#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 +#define MAX_FE_NBR_DATA_CB_LINE_BUFFER_SIZE 320 +#define MAX_FE_NBR_DATA_CR_LINE_BUFFER_SIZE 320 + +#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8) + +#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE (64 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE (32 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE (16 * 2 * 3) + +#define MAX_TILE_COLUMNS 32 /* 8K/256 */ + +#define NUM_HW_PIC_BUF 10 +#define BIN_BUFFER_THRESHOLD (1280 * 736) +#define H264D_MAX_SLICE 1800 +#define SIZE_H264D_BUFTAB_T 256 // sizeof(h264d_buftab_t) aligned to 256 +#define SIZE_H264D_HW_PIC_T (1 << 11) // sizeof(h264d_hw_pic_t) 32 aligned +#define SIZE_H264D_BSE_CMD_PER_BUF (32 * 4) +#define SIZE_H264D_VPP_CMD_PER_BUF 512 + +// Line Buffer definitions +/* one for luma and 1/2 for each chroma */ +#define SIZE_H264D_LB_FE_TOP_DATA(width, height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * \ + ALIGN(width, 16) * 3) + +#define SIZE_H264D_LB_FE_TOP_CTRL(width, height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + ((width + 15) >> 4)) + +#define SIZE_H264D_LB_FE_LEFT_CTRL(width, height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + ((height + 15) >> 4)) + +#define SIZE_H264D_LB_SE_TOP_CTRL(width, height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + ((width + 15) >> 4)) + +#define SIZE_H264D_LB_SE_LEFT_CTRL(width, height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + ((height + 15) >> 4)) + +#define SIZE_H264D_LB_PE_TOP_DATA(width, height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * \ + ((width + 15) >> 4)) + +#define SIZE_H264D_LB_VSP_TOP(width, height) \ + ((((width + 15) >> 4) << 7)) + +#define SIZE_H264D_LB_RECON_DMA_METADATA_WR(width, height) \ + (ALIGN(height, 16) * 32) + +#define SIZE_H264D_QP(width, height) \ + (((width + 63) >> 6) * ((height + 63) >> 6) * 128) + +#define SIZE_HW_PIC(sizePerBuf) \ + (NUM_HW_PIC_BUF * sizePerBuf) + +#define H264_CABAC_HDR_RATIO_HD_TOT 1 +#define H264_CABAC_RES_RATIO_HD_TOT 3 + +/* + * some content need more bin buffer, but limit buffer + * size for high resolution + */ + + +#define NUM_SLIST_BUF_H264 (256 + 32) +#define SIZE_SLIST_BUF_H264 512 + +#define LCU_MAX_SIZE_PELS 64 +#define LCU_MIN_SIZE_PELS 16 + +#define H265D_MAX_SLICE 600 +#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T +#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(u32)) +#define SIZE_H265D_VPP_CMD_PER_BUF 256 + +#define SIZE_H265D_LB_FE_TOP_DATA(width, height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * \ + (ALIGN(width, 64) + 8) * 2) + +#define SIZE_H265D_LB_FE_TOP_CTRL(width, height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (ALIGN(width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_FE_LEFT_CTRL(width, height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (ALIGN(height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_SE_TOP_CTRL(width, height) \ + ((LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * \ + ((width + 15) >> 4)) + +#define SIZE_H265D_LB_SE_LEFT_CTRL(width, height) \ + (max(((height + 16 - 1) / 8) * MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE,\ + max(((height + 32 - 1) / 8) * MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((height + 64 - 1) / 8) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_H265D_LB_PE_TOP_DATA(width, height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * \ + (ALIGN(width, LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_VSP_TOP(width, height) \ + (((width + 63) >> 6) * 128) + +#define SIZE_H265D_LB_VSP_LEFT(width, height) \ + (((height + 63) >> 6) * 128) + +#define SIZE_H265D_LB_RECON_DMA_METADATA_WR(width, height) \ + SIZE_H264D_LB_RECON_DMA_METADATA_WR(width, height) + +#define SIZE_H265D_QP(width, height) SIZE_H264D_QP(width, height) + +#define H265_CABAC_HDR_RATIO_HD_TOT 2 +#define H265_CABAC_RES_RATIO_HD_TOT 2 + +/* + * some content need more bin buffer, but limit buffer size + * for high resolution + */ + +#define SIZE_SLIST_BUF_H265 (1 << 10) +#define NUM_SLIST_BUF_H265 (80 + 20) +#define H265_NUM_TILE_COL 32 +#define H265_NUM_TILE_ROW 128 +#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1) + +#define SIZE_VPXD_LB_FE_LEFT_CTRL(width, height) \ + max(((height + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + max(((height + 31) >> 5) * MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((height + 63) >> 6) * MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_FE_TOP_CTRL(width, height) \ + (((ALIGN(width, 64) + 8) * 10 * 2)) /* + small line */ +#define SIZE_VPXD_LB_SE_TOP_CTRL(width, height) \ + (((width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE) +#define SIZE_VPXD_LB_SE_LEFT_CTRL(width, height) \ + max(((height + 15) >> 4) * MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + max(((height + 31) >> 5) * MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((height + 63) >> 6) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_RECON_DMA_METADATA_WR(width, height) \ + ALIGN((ALIGN(height, 16) / (4 / 2)) * 64, BUFFER_ALIGNMENT_SIZE(32)) +#define SIZE_VP8D_LB_FE_TOP_DATA(width, height) \ + ((ALIGN(width, 16) + 8) * 10 * 2) +#define SIZE_VP9D_LB_FE_TOP_DATA(width, height) \ + ((ALIGN(ALIGN(width, 16), 64) + 8) * 10 * 2) +#define SIZE_VP8D_LB_PE_TOP_DATA(width, height) \ + ((ALIGN(width, 16) >> 4) * 64) +#define SIZE_VP9D_LB_PE_TOP_DATA(width, height) \ + ((ALIGN(ALIGN(width, 16), 64) >> 6) * 176) +#define SIZE_VP8D_LB_VSP_TOP(width, height) \ + (((ALIGN(width, 16) >> 4) * 64 / 2) + 256) +#define SIZE_VP9D_LB_VSP_TOP(width, height) \ + (((ALIGN(ALIGN(width, 16), 64) >> 6) * 64 * 8) + 256) + + +#define HFI_IRIS2_VP9D_COMV_SIZE \ + ((((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8)) + +#define VPX_DECODER_FRAME_CONCURENCY_LVL 2 +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO_NUM 1 +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO_DEN 2 +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO_NUM 3 +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO_DEN 2 + +#define VP8_NUM_FRAME_INFO_BUF (5 + 1) +#define VP9_NUM_FRAME_INFO_BUF (8 + 2 + 1 + 8) +#define VP8_NUM_PROBABILITY_TABLE_BUF (VP8_NUM_FRAME_INFO_BUF) +#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) +#define VP8_PROB_TABLE_SIZE 3840 +#define VP9_PROB_TABLE_SIZE 3840 + +#define VP9_UDC_HEADER_BUF_SIZE (3 * 128) +#define MAX_SUPERFRAME_HEADER_LEN (34) +#define CCE_TILE_OFFSET_SIZE ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_SIZE(32)) + +#define QMATRIX_SIZE (sizeof(u32) * 128 + 256) +#define MP2D_QPDUMP_SIZE 115200 + +#define HFI_IRIS2_ENC_PERSIST_SIZE 102400 + +#define HFI_MAX_COL_FRAME 6 +#define HFI_VENUS_VENC_TRE_WB_BUFF_SIZE (65 << 4) // bytes +#define HFI_VENUS_VENC_DB_LINE_BUFF_PER_MB 512 +#define HFI_VENUS_VPPSG_MAX_REGISTERS 2048 +#define HFI_VENUS_WIDTH_ALIGNMENT 128 +#define HFI_VENUS_WIDTH_TEN_BIT_ALIGNMENT 192 +#define HFI_VENUS_HEIGHT_ALIGNMENT 32 + +#define SYSTEM_LAL_TILE10 192 +#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4)) +#define NUM_MBS_4k (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) +#define MB_SIZE_IN_PIXEL (16 * 16) +#define HDR10PLUS_PAYLOAD_SIZE 1024 +#define HDR10_HIST_EXTRADATA_SIZE 4096 + +static int msm_vidc_get_extra_input_buff_count(struct msm_vidc_inst *inst); +static int msm_vidc_get_extra_output_buff_count(struct msm_vidc_inst *inst); + +static inline u32 calculate_h264d_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced); +static inline u32 calculate_h265d_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced); +static inline u32 calculate_vpxd_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced); +static inline u32 calculate_mpeg2d_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced); + +static inline u32 calculate_enc_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 lcu_size, u32 num_vpp_pipes); +static inline u32 calculate_h264e_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 num_vpp_pipes); +static inline u32 calculate_h265e_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 num_vpp_pipes); +static inline u32 calculate_vp8e_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 num_vpp_pipes); + +static inline u32 calculate_h264d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes); +static inline u32 calculate_h265d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes); +static inline u32 calculate_vp8d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes); +static inline u32 calculate_vp9d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes); +static inline u32 calculate_mpeg2d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes); + +static inline u32 calculate_h264e_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, u32 num_vpp_pipes); +static inline u32 calculate_h265e_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, u32 num_vpp_pipes); +static inline u32 calculate_vp8e_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, u32 num_vpp_pipes); + +static inline u32 calculate_enc_scratch2_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit); + +static inline u32 calculate_enc_persist_size(void); + +static inline u32 calculate_h264d_persist1_size(void); +static inline u32 calculate_h265d_persist1_size(void); +static inline u32 calculate_vp8d_persist1_size(void); +static inline u32 calculate_vp9d_persist1_size(void); +static inline u32 calculate_mpeg2d_persist1_size(void); + +static struct msm_vidc_dec_buff_size_calculators h264d_calculators = { + .calculate_scratch_size = calculate_h264d_scratch_size, + .calculate_scratch1_size = calculate_h264d_scratch1_size, + .calculate_persist1_size = calculate_h264d_persist1_size, +}; + +static struct msm_vidc_dec_buff_size_calculators h265d_calculators = { + .calculate_scratch_size = calculate_h265d_scratch_size, + .calculate_scratch1_size = calculate_h265d_scratch1_size, + .calculate_persist1_size = calculate_h265d_persist1_size, +}; + +static struct msm_vidc_dec_buff_size_calculators vp8d_calculators = { + .calculate_scratch_size = calculate_vpxd_scratch_size, + .calculate_scratch1_size = calculate_vp8d_scratch1_size, + .calculate_persist1_size = calculate_vp8d_persist1_size, +}; + +static struct msm_vidc_dec_buff_size_calculators vp9d_calculators = { + .calculate_scratch_size = calculate_vpxd_scratch_size, + .calculate_scratch1_size = calculate_vp9d_scratch1_size, + .calculate_persist1_size = calculate_vp9d_persist1_size, +}; + +static struct msm_vidc_dec_buff_size_calculators mpeg2d_calculators = { + .calculate_scratch_size = calculate_mpeg2d_scratch_size, + .calculate_scratch1_size = calculate_mpeg2d_scratch1_size, + .calculate_persist1_size = calculate_mpeg2d_persist1_size, +}; + +static struct msm_vidc_enc_buff_size_calculators h264e_calculators = { + .calculate_scratch_size = calculate_h264e_scratch_size, + .calculate_scratch1_size = calculate_h264e_scratch1_size, + .calculate_scratch2_size = calculate_enc_scratch2_size, + .calculate_persist_size = calculate_enc_persist_size, +}; + +static struct msm_vidc_enc_buff_size_calculators h265e_calculators = { + .calculate_scratch_size = calculate_h265e_scratch_size, + .calculate_scratch1_size = calculate_h265e_scratch1_size, + .calculate_scratch2_size = calculate_enc_scratch2_size, + .calculate_persist_size = calculate_enc_persist_size, +}; + +static struct msm_vidc_enc_buff_size_calculators vp8e_calculators = { + .calculate_scratch_size = calculate_vp8e_scratch_size, + .calculate_scratch1_size = calculate_vp8e_scratch1_size, + .calculate_scratch2_size = calculate_enc_scratch2_size, + .calculate_persist_size = calculate_enc_persist_size, +}; + +int msm_vidc_get_decoder_internal_buffer_sizes(struct msm_vidc_inst *inst) +{ + struct msm_vidc_dec_buff_size_calculators *dec_calculators; + u32 width, height, i, out_min_count, num_vpp_pipes; + struct v4l2_format *f; + + if (!inst || !inst->core || !inst->core->platform_data) { + d_vpr_e("%s: Instance is null!", __func__); + return -EINVAL; + } + + num_vpp_pipes = inst->core->platform_data->num_vpp_pipes; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + switch (f->fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_H264: + dec_calculators = &h264d_calculators; + break; + case V4L2_PIX_FMT_HEVC: + dec_calculators = &h265d_calculators; + break; + case V4L2_PIX_FMT_VP8: + dec_calculators = &vp8d_calculators; + break; + case V4L2_PIX_FMT_VP9: + dec_calculators = &vp9d_calculators; + break; + case V4L2_PIX_FMT_MPEG2: + dec_calculators = &mpeg2d_calculators; + break; + default: + s_vpr_e(inst->sid, + "Invalid pix format. Internal buffer cal not defined : %x\n", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements *curr_req; + bool valid_buffer_type = false; + + curr_req = &inst->buff_req.buffer[i]; + if (curr_req->buffer_type == HAL_BUFFER_INTERNAL_SCRATCH) { + bool is_interlaced = false; + + is_interlaced = (inst->pic_struct == + MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED); + curr_req->buffer_size = + dec_calculators->calculate_scratch_size( + inst, width, height, is_interlaced); + valid_buffer_type = true; + } else if (curr_req->buffer_type == + HAL_BUFFER_INTERNAL_SCRATCH_1) { + struct msm_vidc_format *fmt = NULL; + + fmt = &inst->fmts[OUTPUT_PORT]; + out_min_count = fmt->count_min; + curr_req->buffer_size = + dec_calculators->calculate_scratch1_size( + inst, width, height, out_min_count, + is_secondary_output_mode(inst), + num_vpp_pipes); + valid_buffer_type = true; + } else if (curr_req->buffer_type == + HAL_BUFFER_INTERNAL_PERSIST_1) { + curr_req->buffer_size = + dec_calculators->calculate_persist1_size(); + valid_buffer_type = true; + } + + if (valid_buffer_type) { + curr_req->buffer_alignment = 256; + curr_req->buffer_count_actual = + curr_req->buffer_count_min = + curr_req->buffer_count_min_host = 1; + } + } + return 0; +} + +int msm_vidc_get_num_ref_frames(struct msm_vidc_inst *inst) +{ + int num_ref = 1; + int num_bframes = -1, ltr_count = -1, num_hp_layers; + struct v4l2_ctrl *bframe_ctrl; + struct v4l2_ctrl *ltr_ctrl; + struct v4l2_ctrl *layer_ctrl; + u32 codec; + + bframe_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + num_bframes = bframe_ctrl->val; + if (num_bframes > 0) + num_ref = num_bframes + 1; + + ltr_ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT); + ltr_count = ltr_ctrl->val; + /* B and LTR can't be at same time */ + if (ltr_count > 0) + num_ref = num_ref + ltr_count; + + layer_ctrl = get_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); + num_hp_layers = layer_ctrl->val; + codec = get_v4l2_codec(inst); + if (num_hp_layers > 0) { + /* LTR and B - frame not supported with hybrid HP */ + if (inst->hybrid_hp) + num_ref = (num_hp_layers - 1); + else if (codec == V4L2_PIX_FMT_HEVC) + num_ref = ((num_hp_layers + 1) / 2) + ltr_count; + else if ((codec == V4L2_PIX_FMT_H264) && (num_hp_layers <= 4)) + num_ref = ((1 << (num_hp_layers - 1)) - 1) + ltr_count; + else + num_ref = ((num_hp_layers + 1) / 2) + ltr_count; + } + return num_ref; +} + +int msm_vidc_get_encoder_internal_buffer_sizes(struct msm_vidc_inst *inst) +{ + struct msm_vidc_enc_buff_size_calculators *enc_calculators; + u32 width, height, i, num_ref, num_vpp_pipes; + bool is_tenbit = false; + int num_bframes; + struct v4l2_ctrl *bframe; + struct v4l2_format *f; + + if (!inst || !inst->core || !inst->core->platform_data) { + d_vpr_e("%s: Instance is null!", __func__); + return -EINVAL; + } + + num_vpp_pipes = inst->core->platform_data->num_vpp_pipes; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + switch (f->fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_H264: + enc_calculators = &h264e_calculators; + break; + case V4L2_PIX_FMT_HEVC: + enc_calculators = &h265e_calculators; + break; + case V4L2_PIX_FMT_VP8: + enc_calculators = &vp8e_calculators; + break; + default: + s_vpr_e(inst->sid, + "Invalid pix format. Internal buffer cal not defined : %x ", + f->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + bframe = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES); + num_bframes = bframe->val; + if (num_bframes < 0) { + s_vpr_e(inst->sid, "%s: get num bframe failed\n", __func__); + return -EINVAL; + } + + num_ref = msm_vidc_get_num_ref_frames(inst); + is_tenbit = (inst->bit_depth == MSM_VIDC_BIT_DEPTH_10); + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements *curr_req; + bool valid_buffer_type = false; + + curr_req = &inst->buff_req.buffer[i]; + if (curr_req->buffer_type == HAL_BUFFER_INTERNAL_SCRATCH) { + curr_req->buffer_size = + enc_calculators->calculate_scratch_size( + inst, width, height, + inst->clk_data.work_mode, + num_vpp_pipes); + valid_buffer_type = true; + } else if (curr_req->buffer_type == + HAL_BUFFER_INTERNAL_SCRATCH_1) { + curr_req->buffer_size = + enc_calculators->calculate_scratch1_size( + inst, width, height, num_ref, + is_tenbit, num_vpp_pipes); + valid_buffer_type = true; + } else if (curr_req->buffer_type == + HAL_BUFFER_INTERNAL_SCRATCH_2) { + curr_req->buffer_size = + enc_calculators->calculate_scratch2_size( + inst, width, height, num_ref, + is_tenbit); + valid_buffer_type = true; + } else if (curr_req->buffer_type == + HAL_BUFFER_INTERNAL_PERSIST) { + curr_req->buffer_size = + enc_calculators->calculate_persist_size(); + } + + if (valid_buffer_type) { + curr_req->buffer_alignment = 256; + curr_req->buffer_count_actual = + curr_req->buffer_count_min = + curr_req->buffer_count_min_host = 1; + } + } + return 0; +} + +int msm_vidc_calculate_internal_buffer_sizes(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: Instance is null!", __func__); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_DECODER) + return msm_vidc_get_decoder_internal_buffer_sizes(inst); + else if (inst->session_type == MSM_VIDC_ENCODER) + return msm_vidc_get_encoder_internal_buffer_sizes(inst); + + return 0; +} + +void msm_vidc_init_buffer_size_calculators(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + uint32_t vpu; + + if (!inst) + return; + + inst->buffer_size_calculators = NULL; + core = inst->core; + vpu = core->platform_data->vpu_ver; + + /* Change this to IRIS2 when ready */ + if (vpu == VPU_VERSION_IRIS2 || vpu == VPU_VERSION_IRIS2_1) + inst->buffer_size_calculators = + msm_vidc_calculate_internal_buffer_sizes; +} + +int msm_vidc_calculate_input_buffer_count(struct msm_vidc_inst *inst) +{ + struct msm_vidc_format *fmt; + int extra_buff_count = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + fmt = &inst->fmts[INPUT_PORT]; + + if (!is_decode_session(inst) && !is_encode_session(inst)) + return 0; + + /* do not change buffer count while session is running */ + if (inst->state == MSM_VIDC_START_DONE) + return 0; + + if (is_thumbnail_session(inst)) { + fmt->count_min = fmt->count_min_host = fmt->count_actual = + SINGLE_INPUT_BUFFER; + return 0; + } + + if (is_grid_session(inst)) { + fmt->count_min = fmt->count_min_host = fmt->count_actual = + SINGLE_INPUT_BUFFER + 1; + return 0; + } + + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_INPUT); + fmt->count_min = MIN_INPUT_BUFFERS; + fmt->count_min_host = fmt->count_actual = + fmt->count_min + extra_buff_count; + + s_vpr_h(inst->sid, "%s: input min %d min_host %d actual %d\n", + __func__, fmt->count_min, + fmt->count_min_host, fmt->count_actual); + + return 0; +} + +int msm_vidc_calculate_output_buffer_count(struct msm_vidc_inst *inst) +{ + struct msm_vidc_format *fmt; + int extra_buff_count = 0; + u32 codec, output_min_count; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + fmt = &inst->fmts[OUTPUT_PORT]; + codec = get_v4l2_codec(inst); + + if (!is_decode_session(inst) && !is_encode_session(inst)) + return 0; + + /* do not change buffer count while session is running */ + if (inst->state == MSM_VIDC_START_DONE) + return 0; + + if (is_thumbnail_session(inst)) { + fmt->count_min = (codec == V4L2_PIX_FMT_VP9) ? + VP9_REFERENCE_COUNT : SINGLE_OUTPUT_BUFFER; + fmt->count_min_host = fmt->count_actual = fmt->count_min; + return 0; + } + + /* Update output buff count: Changes for decoder based on codec */ + if (is_decode_session(inst)) { + switch (codec) { + case V4L2_PIX_FMT_MPEG2: + case V4L2_PIX_FMT_VP8: + output_min_count = 6; + break; + case V4L2_PIX_FMT_VP9: + output_min_count = 9; + break; + default: + output_min_count = 8; //H264, HEVC + } + } else { + output_min_count = MIN_ENC_OUTPUT_BUFFERS; + } + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_OUTPUT); + fmt->count_min = output_min_count; + fmt->count_min_host = fmt->count_actual = + fmt->count_min + extra_buff_count; + + s_vpr_h(inst->sid, "%s: output min %d min_host %d actual %d\n", + __func__, fmt->count_min, fmt->count_min_host, + fmt->count_actual); + + return 0; +} + +int msm_vidc_calculate_buffer_counts(struct msm_vidc_inst *inst) +{ + int rc; + + rc = msm_vidc_calculate_input_buffer_count(inst); + if (rc) + return rc; + rc = msm_vidc_calculate_output_buffer_count(inst); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type) +{ + if (!inst || !inst->core) { + d_vpr_e("%s: Invalid args\n", __func__); + return 0; + } + + if (!is_decode_session(inst) && !is_encode_session(inst)) + return 0; + + if (buffer_type == HAL_BUFFER_OUTPUT) + return msm_vidc_get_extra_output_buff_count(inst); + else if (buffer_type == HAL_BUFFER_INPUT) + return msm_vidc_get_extra_input_buff_count(inst); + + return 0; +} + +static int msm_vidc_get_extra_input_buff_count(struct msm_vidc_inst *inst) +{ + unsigned int extra_input_count = 0; + struct msm_vidc_core *core; + struct v4l2_format *f; + int max_fps = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + core = inst->core; + + /* + * For a non-realtime session, extra buffers are not required. + * For thumbnail session, extra buffers are not required as + * neither dcvs nor batching will be enabled. + */ + if (!is_realtime_session(inst) || is_thumbnail_session(inst)) + return extra_input_count; + + if (is_decode_session(inst)) { + /* + * Batch mode and HFR not supported for resolution greater than + * UHD. Hence extra buffers are not required. + */ + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + if (res_is_greater_than(f->fmt.pix_mp.width, + f->fmt.pix_mp.height, 4096, 2160)) + goto exit; + + if (inst->batch.enable) + extra_input_count = (BATCH_DEC_TOTAL_INPUT_BUFFERS - + MIN_INPUT_BUFFERS); + + /* + * HFR decode session needs more buffers and we do not know + * whether a decode session is HFR or not until input buffers + * queued but by then input buffers are already allocated and + * we do not have option to increase input buffer count then. + * So have more buffers for initial 4 elgible sessions (and + * not for all sessions to avoid over memory usage issues). + */ + if (!is_secure_session(inst) && + msm_comm_get_num_perf_sessions(inst) < + MAX_PERF_ELIGIBLE_SESSIONS) { + max_fps = inst->capability.cap[CAP_FRAMERATE].max; + inst->is_perf_eligible_session = true; + if (max_fps > 480) + extra_input_count = + (MAX_HFR_DEC_TOTAL_INPUT_BUFFERS - + MIN_INPUT_BUFFERS); + else + extra_input_count = + (MIN_HFR_DEC_TOTAL_INPUT_BUFFERS - + MIN_INPUT_BUFFERS); + } + } else if (is_encode_session(inst)) { + /* add 4 extra buffers for dcvs */ + if (core->resources.dcvs) + extra_input_count = DCVS_ENC_EXTRA_INPUT_BUFFERS; + + /* Increase buffer count for HFR usecase */ + if (msm_comm_get_num_perf_sessions(inst) < + MAX_PERF_ELIGIBLE_SESSIONS && + msm_vidc_get_fps(inst) > 60) { + inst->is_perf_eligible_session = true; + extra_input_count = (HFR_ENC_TOTAL_INPUT_BUFFERS - + MIN_INPUT_BUFFERS); + } + } + +exit: + return extra_input_count; +} + +static int msm_vidc_get_extra_output_buff_count(struct msm_vidc_inst *inst) +{ + unsigned int extra_output_count = 0; + struct msm_vidc_core *core; + struct v4l2_format *f; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + core = inst->core; + + /* + * For a non-realtime session, extra buffers are not required. + * For thumbnail session, extra buffers are not required as + * neither dcvs nor batching will be enabled. + */ + if (!is_realtime_session(inst) || is_thumbnail_session(inst)) + return extra_output_count; + + /* For HEIF, we are increasing buffer count */ + if (is_image_session(inst) || is_grid_session(inst)) { + extra_output_count = (HEIF_ENC_TOTAL_OUTPUT_BUFFERS - + MIN_ENC_OUTPUT_BUFFERS); + return extra_output_count; + } + + if (is_decode_session(inst)) { + /* add 4 extra buffers for dcvs */ + if (core->resources.dcvs) + extra_output_count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; + /* + * Batch mode and HFR not supported for resolution greater than + * UHD. Hence extra buffers are not required. + */ + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + if (res_is_greater_than(f->fmt.pix_mp.width, + f->fmt.pix_mp.height, 4096, 2160)) + goto exit; + + /* + * Minimum number of decoder output buffers is codec specific. + * If platform supports decode batching ensure minimum 6 extra + * output buffers. Else add 4 extra output buffers for DCVS. + */ + if (inst->batch.enable) + extra_output_count = BATCH_DEC_EXTRA_OUTPUT_BUFFERS; + } else if (is_encode_session(inst)) { + /* + * Batching and DCVS are based on input. We assume that encoder + * output buffers can be re-cycled quickly. Hence it is assumed + * that output buffer count does not impact for DCVS/batching. + * For HFR, we are increasing buffer count to avoid latency/perf + * issue to re-cycle buffers. + */ + if (msm_comm_get_num_perf_sessions(inst) < + MAX_PERF_ELIGIBLE_SESSIONS && + msm_vidc_get_fps(inst) > 60) { + inst->is_perf_eligible_session = true; + extra_output_count = (HFR_ENC_TOTAL_OUTPUT_BUFFERS - + MIN_ENC_OUTPUT_BUFFERS); + } + } +exit: + return extra_output_count; +} + +u32 msm_vidc_calculate_dec_input_frame_size(struct msm_vidc_inst *inst) +{ + u32 frame_size, num_mbs; + u32 div_factor = 1; + u32 base_res_mbs = NUM_MBS_4k; + struct v4l2_format *f; + + /* + * Decoder input size calculation: + * If clip is 8k buffer size is calculated for 8k : 8k mbs/4 + * For 8k cases we expect width/height to be set always. + * In all other cases size is calculated for 4k: + * 4k mbs for VP8/VP9 and 4k/2 for remaining codecs + */ + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + num_mbs = msm_vidc_get_mbs_per_frame(inst); + if (num_mbs > NUM_MBS_4k) { + div_factor = 4; + base_res_mbs = inst->capability.cap[CAP_MBS_PER_FRAME].max; + } else { + base_res_mbs = NUM_MBS_4k; + if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_VP9) + div_factor = 1; + else + div_factor = 2; + } + + if (is_secure_session(inst) && num_mbs >= NUM_MBS_720P) + div_factor = div_factor << 1; + + /* For targets that doesn't support 4k, consider max mb's for that + * target and allocate max input buffer size for the same + */ + if (base_res_mbs > inst->capability.cap[CAP_MBS_PER_FRAME].max) { + base_res_mbs = inst->capability.cap[CAP_MBS_PER_FRAME].max; + div_factor = 1; + } + + frame_size = base_res_mbs * MB_SIZE_IN_PIXEL * 3 / 2 / div_factor; + + /* multiply by 10/8 (1.25) to get size for 10 bit case */ + if ((f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_VP9) || + (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC)) + frame_size = frame_size + (frame_size >> 2); + + if (inst->buffer_size_limit && + (inst->buffer_size_limit < frame_size)) { + frame_size = inst->buffer_size_limit; + s_vpr_h(inst->sid, "input buffer size limited to %d\n", + frame_size); + } else { + s_vpr_h(inst->sid, "set input buffer size to %d\n", + frame_size); + } + + return ALIGN(frame_size, SZ_4K); +} + +u32 msm_vidc_calculate_dec_output_frame_size(struct msm_vidc_inst *inst) +{ + u32 hfi_fmt; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + hfi_fmt = msm_comm_convert_color_fmt(f->fmt.pix_mp.pixelformat, + inst->sid); + return VENUS_BUFFER_SIZE(hfi_fmt, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); +} + +u32 msm_vidc_calculate_dec_output_extra_size(struct msm_vidc_inst *inst) +{ + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + return VENUS_EXTRADATA_SIZE(f->fmt.pix_mp.width, f->fmt.pix_mp.height); +} + +u32 msm_vidc_calculate_enc_input_frame_size(struct msm_vidc_inst *inst) +{ + u32 hfi_fmt; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + hfi_fmt = msm_comm_convert_color_fmt(f->fmt.pix_mp.pixelformat, + inst->sid); + return VENUS_BUFFER_SIZE(hfi_fmt, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); +} + +u32 msm_vidc_calculate_enc_output_frame_size(struct msm_vidc_inst *inst) +{ + u32 frame_size; + u32 mbs_per_frame; + u32 width, height; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + /* + * Encoder output size calculation: 32 Align width/height + * For resolution < 720p : YUVsize * 4 + * For resolution > 720p & <= 4K : YUVsize / 2 + * For resolution > 4k : YUVsize / 4 + * Initially frame_size = YUVsize * 2; + */ + + if (is_grid_session(inst)) { + f->fmt.pix_mp.width = f->fmt.pix_mp.height = HEIC_GRID_DIMENSION; + } + width = ALIGN(f->fmt.pix_mp.width, BUFFER_ALIGNMENT_SIZE(32)); + height = ALIGN(f->fmt.pix_mp.height, BUFFER_ALIGNMENT_SIZE(32)); + mbs_per_frame = NUM_MBS_PER_FRAME(width, height); + frame_size = (width * height * 3); + + if (mbs_per_frame < NUM_MBS_720P) + frame_size = frame_size << 1; + else if (mbs_per_frame <= NUM_MBS_4k) + frame_size = frame_size >> 2; + else + frame_size = frame_size >> 3; + + if ((inst->rc_type == RATE_CONTROL_OFF) || + (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)) + frame_size = frame_size << 1; + + if (inst->rc_type == RATE_CONTROL_LOSSLESS) + frame_size = (width * height * 9) >> 2; + + /* multiply by 10/8 (1.25) to get size for 10 bit case */ + if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC) + frame_size = frame_size + (frame_size >> 2); + + return ALIGN(frame_size, SZ_4K); +} + +static inline u32 ROI_EXTRADATA_SIZE( + u32 width, u32 height, u32 lcu_size) { + u32 lcu_width = 0; + u32 lcu_height = 0; + u32 n_shift = 0; + + while (lcu_size && !(lcu_size & 0x1)) { + n_shift++; + lcu_size = lcu_size >> 1; + } + lcu_width = (width + (lcu_size - 1)) >> n_shift; + lcu_height = (height + (lcu_size - 1)) >> n_shift; + + return (((lcu_width + 7) >> 3) << 3) * lcu_height * 2; +} + +u32 msm_vidc_calculate_enc_input_extra_size(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 extradata_count = 0; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + /* Add size for default extradata */ + size += sizeof(struct msm_vidc_enc_cvp_metadata_payload); + extradata_count++; + + if (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_ROI) { + u32 lcu_size = 16; + + if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC) + lcu_size = 32; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + size += ROI_EXTRADATA_SIZE(f->fmt.pix_mp.width, + f->fmt.pix_mp.height, lcu_size); + extradata_count++; + } + + if (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_HDR10PLUS) { + size += HDR10PLUS_PAYLOAD_SIZE; + extradata_count++; + } + + /* Add extradata header sizes including EXTRADATA_NONE */ + if (size) + size += sizeof(struct msm_vidc_extradata_header) * + (extradata_count + 1); + + return ALIGN(size, SZ_4K); +} + +u32 msm_vidc_calculate_enc_output_extra_size(struct msm_vidc_inst *inst) +{ + u32 size = 0; + + if (inst->prop.extradata_ctrls & EXTRADATA_ADVANCED) + size += sizeof(struct msm_vidc_metadata_ltr_payload); + + /* Add size for extradata none */ + if (size) + size += sizeof(struct msm_vidc_extradata_header); + + return ALIGN(size, SZ_4K); +} + +static inline u32 size_vpss_lb(u32 width, u32 height, u32 num_vpp_pipes) +{ + u32 vpss_4tap_top_buffer_size, vpss_div2_top_buffer_size; + u32 vpss_4tap_left_buffer_size, vpss_div2_left_buffer_size; + u32 opb_wr_top_line_luma_buf_size, opb_wr_top_line_chroma_buf_size; + u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size; + u32 macrotiling_size; + u32 size = 0; + + vpss_4tap_top_buffer_size = vpss_div2_top_buffer_size = + vpss_4tap_left_buffer_size = vpss_div2_left_buffer_size = 0; + macrotiling_size = 32; + opb_wr_top_line_luma_buf_size = ALIGN(width, macrotiling_size) / + macrotiling_size * 256; + opb_wr_top_line_luma_buf_size = ALIGN(opb_wr_top_line_luma_buf_size, + VENUS_DMA_ALIGNMENT) + (MAX_TILE_COLUMNS - 1) * 256; + opb_wr_top_line_luma_buf_size = max(opb_wr_top_line_luma_buf_size, + (32 * ALIGN(height, 16))); + opb_wr_top_line_chroma_buf_size = opb_wr_top_line_luma_buf_size; + opb_lb_wr_llb_uv_buffer_size = opb_lb_wr_llb_y_buffer_size = + ALIGN((ALIGN(height, 16) / 2) * + 64, BUFFER_ALIGNMENT_SIZE(32)); + size = num_vpp_pipes * 2 * (vpss_4tap_top_buffer_size + + vpss_div2_top_buffer_size) + + 2 * (vpss_4tap_left_buffer_size + + vpss_div2_left_buffer_size) + + opb_wr_top_line_luma_buf_size + + opb_wr_top_line_chroma_buf_size + + opb_lb_wr_llb_uv_buffer_size + + opb_lb_wr_llb_y_buffer_size; + + return size; +} + +static inline u32 hfi_iris2_h264d_comv_size(u32 width, u32 height, + u32 yuv_buf_min_count) +{ + u32 comv_size = 0; + u32 frame_width_in_mbs = ((width + 15) >> 4); + u32 frame_height_in_mbs = ((height + 15) >> 4); + u32 col_mv_aligned_width = (frame_width_in_mbs << 6); + u32 col_zero_aligned_width = (frame_width_in_mbs << 2); + u32 col_zero_size = 0, size_colloc = 0; + + col_mv_aligned_width = ALIGN(col_mv_aligned_width, + BUFFER_ALIGNMENT_SIZE(16)); + col_zero_aligned_width = ALIGN(col_zero_aligned_width, + BUFFER_ALIGNMENT_SIZE(16)); + col_zero_size = col_zero_aligned_width * + ((frame_height_in_mbs + 1) >> 1); + col_zero_size = ALIGN(col_zero_size, BUFFER_ALIGNMENT_SIZE(64)); + col_zero_size <<= 1; + col_zero_size = ALIGN(col_zero_size, BUFFER_ALIGNMENT_SIZE(512)); + size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + 1) >> 1); + size_colloc = ALIGN(size_colloc, BUFFER_ALIGNMENT_SIZE(64)); + size_colloc <<= 1; + size_colloc = ALIGN(size_colloc, BUFFER_ALIGNMENT_SIZE(512)); + size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2); + comv_size = size_colloc * yuv_buf_min_count; + comv_size += BUFFER_ALIGNMENT_SIZE(512); + + return comv_size; +} + +static inline u32 size_h264d_bse_cmd_buf(u32 height) +{ + u32 aligned_height = ALIGN(height, BUFFER_ALIGNMENT_SIZE(32)); + + return min_t(u32, (((aligned_height + 15) >> 4) * 3 * 4), + H264D_MAX_SLICE) * + SIZE_H264D_BSE_CMD_PER_BUF; +} + +static inline u32 size_h264d_vpp_cmd_buf(u32 height) +{ + u32 aligned_height = ALIGN(height, BUFFER_ALIGNMENT_SIZE(32)); + + return min_t(u32, (((aligned_height + 15) >> 4) * 3 * 4), + H264D_MAX_SLICE) * + SIZE_H264D_VPP_CMD_PER_BUF; +} + +static inline u32 hfi_iris2_h264d_non_comv_size(u32 width, u32 height, + u32 num_vpp_pipes) +{ + u32 size; + u32 size_bse, size_vpp; + + size_bse = size_h264d_bse_cmd_buf(height); + size_vpp = size_h264d_vpp_cmd_buf(height); + size = ALIGN(size_bse, VENUS_DMA_ALIGNMENT) + + ALIGN(size_vpp, VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H264D_LB_FE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H264D_LB_FE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H264D_LB_FE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_H264D_LB_SE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H264D_LB_SE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_H264D_LB_PE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H264D_LB_VSP_TOP(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H264D_LB_RECON_DMA_METADATA_WR(width, height), + VENUS_DMA_ALIGNMENT) * 2 + + ALIGN(SIZE_H264D_QP(width, height), VENUS_DMA_ALIGNMENT); + size = ALIGN(size, VENUS_DMA_ALIGNMENT); + return size; +} + +static inline u32 size_h264d_hw_bin_buffer(u32 width, u32 height) +{ + u32 size_yuv, size_bin_hdr, size_bin_res; + u32 size = 0; + u32 product; + + product = width * height; + size_yuv = (product <= BIN_BUFFER_THRESHOLD) ? + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : + ((product * 3) >> 1); + + size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT; + size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT; + size_bin_hdr = ALIGN(size_bin_hdr, VENUS_DMA_ALIGNMENT); + size_bin_res = ALIGN(size_bin_res, VENUS_DMA_ALIGNMENT); + size = size_bin_hdr + size_bin_res; + return size; +} + +static inline u32 calculate_h264d_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced) +{ + u32 aligned_width = ALIGN(width, BUFFER_ALIGNMENT_SIZE(16)); + u32 aligned_height = ALIGN(height, BUFFER_ALIGNMENT_SIZE(16)); + u32 size = 0; + + if (!is_interlaced) + size = size_h264d_hw_bin_buffer(aligned_width, aligned_height); + else + size = 0; + + return size; +} + +static inline u32 size_h265d_bse_cmd_buf(u32 width, u32 height) +{ + u32 size; + + size = (ALIGN(width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + (ALIGN(height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + NUM_HW_PIC_BUF; + size = min_t(u32, size, H265D_MAX_SLICE + 1); + size = 2 * size * SIZE_H265D_BSE_CMD_PER_BUF; + size = ALIGN(size, VENUS_DMA_ALIGNMENT); + + return size; +} + +static inline u32 size_h265d_vpp_cmd_buf(u32 width, u32 height) +{ + u32 size = 0; + + size = (ALIGN(width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + (ALIGN(height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + NUM_HW_PIC_BUF; + size = min_t(u32, size, H265D_MAX_SLICE + 1); + size = ALIGN(size, 4); + size = 2 * size * SIZE_H265D_VPP_CMD_PER_BUF; + size = ALIGN(size, VENUS_DMA_ALIGNMENT); + + return size; +} + +static inline u32 hfi_iris2_h265d_comv_size(u32 width, u32 height, + u32 yuv_buf_count_min) +{ + u32 size = 0; + + size = ALIGN(((((width + 15) >> 4) * ((height + 15) >> 4)) << 8), + BUFFER_ALIGNMENT_SIZE(512)); + size *= yuv_buf_count_min; + size += BUFFER_ALIGNMENT_SIZE(512); + + return size; +} + +static inline u32 hfi_iris2_h265d_non_comv_size(u32 width, u32 height, + u32 num_vpp_pipes) +{ + u32 size_bse, size_vpp; + u32 size = 0; + + size_bse = size_h265d_bse_cmd_buf(width, height); + size_vpp = size_h265d_vpp_cmd_buf(width, height); + size = ALIGN(size_bse, VENUS_DMA_ALIGNMENT) + + ALIGN(size_vpp, VENUS_DMA_ALIGNMENT) + + ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, VENUS_DMA_ALIGNMENT) + + ALIGN(2 * sizeof(u16) * + (ALIGN(width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * + (ALIGN(height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H265D_LB_FE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H265D_LB_FE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H265D_LB_FE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_H265D_LB_SE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_H265D_LB_SE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H265D_LB_PE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H265D_LB_VSP_TOP(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_H265D_LB_VSP_LEFT(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_H265D_LB_RECON_DMA_METADATA_WR(width, height), + VENUS_DMA_ALIGNMENT) * 4 + + ALIGN(SIZE_H265D_QP(width, height), VENUS_DMA_ALIGNMENT); + size = ALIGN(size, VENUS_DMA_ALIGNMENT); + return size; +} + +static inline u32 size_h265d_hw_bin_buffer(u32 width, u32 height) +{ + u32 size = 0; + u32 size_yuv, size_bin_hdr, size_bin_res; + u32 product; + + product = width * height; + size_yuv = (product <= BIN_BUFFER_THRESHOLD) ? + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : + ((product * 3) >> 1); + size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT; + size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT; + size_bin_hdr = ALIGN(size_bin_hdr, VENUS_DMA_ALIGNMENT); + size_bin_res = ALIGN(size_bin_res, VENUS_DMA_ALIGNMENT); + size = size_bin_hdr + size_bin_res; + + return size; +} + +static inline u32 calculate_h265d_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced) +{ + u32 aligned_width = ALIGN(width, BUFFER_ALIGNMENT_SIZE(16)); + u32 aligned_height = ALIGN(height, BUFFER_ALIGNMENT_SIZE(16)); + u32 size = 0; + + if (!is_interlaced) + size = size_h265d_hw_bin_buffer(aligned_width, aligned_height); + else + size = 0; + return size; +} + +static inline u32 calculate_vpxd_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced) +{ + u32 aligned_width = ALIGN(width, BUFFER_ALIGNMENT_SIZE(16)); + u32 aligned_height = ALIGN(height, BUFFER_ALIGNMENT_SIZE(16)); + u32 size = 0; + u32 size_yuv = aligned_width * aligned_height * 3 / 2; + + if (!is_interlaced) { + /* binbuffer1_size + binbufer2_size */ + u32 binbuffer1_size = 0, binbufer2_size = 0; + + binbuffer1_size = max_t(u32, size_yuv, + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * + VPX_DECODER_FRAME_CONCURENCY_LVL * + VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO_NUM / + VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO_DEN; + binbufer2_size = max_t(u32, size_yuv, + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * + VPX_DECODER_FRAME_CONCURENCY_LVL * + VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO_NUM / + VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO_DEN; + size = ALIGN(binbuffer1_size + binbufer2_size, + VENUS_DMA_ALIGNMENT); + } else { + size = 0; + } + + return size; +} + +static inline u32 calculate_mpeg2d_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, bool is_interlaced) +{ + return 0; +} + +static inline u32 calculate_enc_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 lcu_size, u32 num_vpp_pipes) +{ + u32 aligned_width, aligned_height, bitstream_size; + u32 total_bitbin_buffers = 0, size_singlePipe, bitbin_size = 0; + u32 sao_bin_buffer_size, padded_bin_size, size = 0; + + aligned_width = ALIGN(width, lcu_size); + aligned_height = ALIGN(height, lcu_size); + bitstream_size = msm_vidc_calculate_enc_output_frame_size(inst); + + bitstream_size = ALIGN(bitstream_size, VENUS_DMA_ALIGNMENT); + if (work_mode == HFI_WORKMODE_2) { + total_bitbin_buffers = 3; + bitbin_size = bitstream_size * 17 / 10; + bitbin_size = ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT); + } else { + total_bitbin_buffers = 1; + bitstream_size = aligned_width * aligned_height * 3; + bitbin_size = ALIGN(bitstream_size, VENUS_DMA_ALIGNMENT); + } + if (num_vpp_pipes > 2) + size_singlePipe = bitbin_size / 2; + else + size_singlePipe = bitbin_size; + if (inst->rc_type == RATE_CONTROL_LOSSLESS) + size_singlePipe <<= 1; + size_singlePipe = ALIGN(size_singlePipe, VENUS_DMA_ALIGNMENT); + sao_bin_buffer_size = (64 * (((width + BUFFER_ALIGNMENT_SIZE(32)) * + (height + BUFFER_ALIGNMENT_SIZE(32))) >> 10)) + 384; + padded_bin_size = ALIGN(size_singlePipe, VENUS_DMA_ALIGNMENT); + size_singlePipe = sao_bin_buffer_size + padded_bin_size; + size_singlePipe = ALIGN(size_singlePipe, VENUS_DMA_ALIGNMENT); + bitbin_size = size_singlePipe * num_vpp_pipes; + size = ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT) * total_bitbin_buffers + + 512; + + return size; +} + +static inline u32 calculate_h264e_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 num_vpp_pipes) +{ + return calculate_enc_scratch_size(inst, width, height, work_mode, 16, + num_vpp_pipes); +} + +static inline u32 calculate_h265e_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 num_vpp_pipes) +{ + return calculate_enc_scratch_size(inst, width, height, work_mode, 32, + num_vpp_pipes); +} + +static inline u32 calculate_vp8e_scratch_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 work_mode, u32 num_vpp_pipes) +{ + return calculate_enc_scratch_size(inst, width, height, work_mode, 16, + num_vpp_pipes); +} + +static inline u32 calculate_h264d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes) +{ + u32 co_mv_size = 0, nonco_mv_size = 0; + u32 vpss_lb_size = 0; + u32 size = 0; + + co_mv_size = hfi_iris2_h264d_comv_size(width, height, min_buf_count); + nonco_mv_size = hfi_iris2_h264d_non_comv_size(width, height, + num_vpp_pipes); + if (split_mode_enabled) + vpss_lb_size = size_vpss_lb(width, height, num_vpp_pipes); + size = co_mv_size + nonco_mv_size + vpss_lb_size; + return size; +} + +static inline u32 calculate_h265d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes) +{ + u32 co_mv_size = 0, nonco_mv_size = 0; + u32 vpss_lb_size = 0; + u32 size = 0; + + co_mv_size = hfi_iris2_h265d_comv_size(width, height, min_buf_count); + nonco_mv_size = + hfi_iris2_h265d_non_comv_size(width, height, num_vpp_pipes); + if (split_mode_enabled) + vpss_lb_size = size_vpss_lb(width, height, num_vpp_pipes); + + size = co_mv_size + nonco_mv_size + vpss_lb_size + + HDR10_HIST_EXTRADATA_SIZE; + return size; +} + +static inline u32 hfi_iris2_vp8d_comv_size(u32 width, u32 height, + u32 yuv_min_buf_count) +{ + return (((width + 15) >> 4) * ((height + 15) >> 4) * 8 * 2); +} + +static inline u32 calculate_vp8d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes) +{ + u32 vpss_lb_size = 0; + u32 size = 0; + + size = hfi_iris2_vp8d_comv_size(width, height, 0); + size += ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_VP8D_LB_VSP_TOP(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + 2 * ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VP8D_LB_PE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VP8D_LB_FE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT); + if (split_mode_enabled) + vpss_lb_size = size_vpss_lb(width, height, num_vpp_pipes); + + size += vpss_lb_size; + return size; +} + +static inline u32 calculate_vp9d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes) +{ + u32 vpss_lb_size = 0; + u32 size = 0; + + size = ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_VP9D_LB_VSP_TOP(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + 2 * ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VP9D_LB_PE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VP9D_LB_FE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT); + if (split_mode_enabled) + vpss_lb_size = size_vpss_lb(width, height, num_vpp_pipes); + + size += vpss_lb_size + HDR10_HIST_EXTRADATA_SIZE; + return size; +} + +static inline u32 calculate_mpeg2d_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes) +{ + u32 vpss_lb_size = 0; + u32 size = 0; + + size = ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(width, height), + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + + ALIGN(SIZE_VP8D_LB_VSP_TOP(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + 2 * ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VP8D_LB_PE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT) + + ALIGN(SIZE_VP8D_LB_FE_TOP_DATA(width, height), + VENUS_DMA_ALIGNMENT); + if (split_mode_enabled) + vpss_lb_size = size_vpss_lb(width, height, num_vpp_pipes); + + size += vpss_lb_size; + return size; +} + +static inline u32 calculate_enc_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 lcu_size, u32 num_ref, bool ten_bit, + u32 num_vpp_pipes, bool is_h265) +{ + u32 line_buf_ctrl_size, line_buf_data_size, leftline_buf_ctrl_size; + u32 line_buf_sde_size, sps_pps_slice_hdr, topline_buf_ctrl_size_FE; + u32 leftline_buf_ctrl_size_FE, line_buf_recon_pix_size; + u32 leftline_buf_recon_pix_size, lambda_lut_size, override_buffer_size; + u32 col_mv_buf_size, vpp_reg_buffer_size, ir_buffer_size; + u32 vpss_line_buf, leftline_buf_meta_recony, h265e_colrcbuf_size; + u32 h265e_framerc_bufsize, h265e_lcubitcnt_bufsize; + u32 h265e_lcubitmap_bufsize, se_stats_bufsize; + u32 bse_reg_buffer_size, bse_slice_cmd_buffer_size, slice_info_bufsize; + u32 line_buf_ctrl_size_buffid2, slice_cmd_buffer_size; + u32 width_lcu_num, height_lcu_num, width_coded, height_coded; + u32 frame_num_lcu, linebuf_meta_recon_uv, topline_bufsize_fe_1stg_sao; + u32 output_mv_bufsize = 0, temp_scratch_mv_bufsize = 0; + u32 size, bit_depth, num_LCUMB; + u32 vpss_lineBufferSize_1 = 0; + u32 width_mb_num = ((width + 15) >> 4); + u32 height_mb_num = ((height + 15) >> 4); + + width_lcu_num = ((width)+(lcu_size)-1) / (lcu_size); + height_lcu_num = ((height)+(lcu_size)-1) / (lcu_size); + frame_num_lcu = width_lcu_num * height_lcu_num; + width_coded = width_lcu_num * (lcu_size); + height_coded = height_lcu_num * (lcu_size); + num_LCUMB = (height_coded / lcu_size) * ((width_coded + lcu_size * 8) / lcu_size); + slice_info_bufsize = (256 + (frame_num_lcu << 4)); + slice_info_bufsize = ALIGN(slice_info_bufsize, VENUS_DMA_ALIGNMENT); + line_buf_ctrl_size = ALIGN(width_coded, VENUS_DMA_ALIGNMENT); + line_buf_ctrl_size_buffid2 = ALIGN(width_coded, VENUS_DMA_ALIGNMENT); + + bit_depth = ten_bit ? 10 : 8; + line_buf_data_size = (((((bit_depth * width_coded + 1024) + + (VENUS_DMA_ALIGNMENT - 1)) & (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + + (((((bit_depth * width_coded + 1024) >> 1) + + (VENUS_DMA_ALIGNMENT - 1)) & + (~(VENUS_DMA_ALIGNMENT - 1))) * 2)); + leftline_buf_ctrl_size = (is_h265) ? + ((height_coded + (BUFFER_ALIGNMENT_SIZE(32))) / + BUFFER_ALIGNMENT_SIZE(32) * 4 * 16) : + ((height_coded + 15) / 16 * 5 * 16); + if (num_vpp_pipes > 1) { + leftline_buf_ctrl_size += BUFFER_ALIGNMENT_SIZE(512); + leftline_buf_ctrl_size = ALIGN(leftline_buf_ctrl_size, + BUFFER_ALIGNMENT_SIZE(512)) * num_vpp_pipes; + } + leftline_buf_ctrl_size = ALIGN(leftline_buf_ctrl_size, + VENUS_DMA_ALIGNMENT); + leftline_buf_recon_pix_size = (((ten_bit + 1) * 2 * + (height_coded)+VENUS_DMA_ALIGNMENT) + + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes - 1)) - 1) & + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes - 1)) - 1)) * 1; + topline_buf_ctrl_size_FE = (is_h265) ? (64 * (width_coded >> 5)) : + (VENUS_DMA_ALIGNMENT + 16 * (width_coded >> 4)); + topline_buf_ctrl_size_FE = ALIGN(topline_buf_ctrl_size_FE, + VENUS_DMA_ALIGNMENT); + leftline_buf_ctrl_size_FE = (((VENUS_DMA_ALIGNMENT + 64 * + (height_coded >> 4)) + + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes - 1)) - 1) & + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes - 1)) - 1)) * 1) * + num_vpp_pipes; + leftline_buf_meta_recony = (VENUS_DMA_ALIGNMENT + 64 * + ((height_coded) / (8 * (ten_bit ? 4 : 8)))); + leftline_buf_meta_recony = ALIGN(leftline_buf_meta_recony, + VENUS_DMA_ALIGNMENT); + leftline_buf_meta_recony = leftline_buf_meta_recony * + num_vpp_pipes; + linebuf_meta_recon_uv = (VENUS_DMA_ALIGNMENT + 64 * + ((height_coded) / (4 * (ten_bit ? 4 : 8)))); + linebuf_meta_recon_uv = ALIGN(linebuf_meta_recon_uv, + VENUS_DMA_ALIGNMENT); + linebuf_meta_recon_uv = linebuf_meta_recon_uv * + num_vpp_pipes; + line_buf_recon_pix_size = ((ten_bit ? 3 : 2) * width_coded); + line_buf_recon_pix_size = ALIGN(line_buf_recon_pix_size, + VENUS_DMA_ALIGNMENT); + slice_cmd_buffer_size = ALIGN(20480, VENUS_DMA_ALIGNMENT); + sps_pps_slice_hdr = 2048 + 4096; + col_mv_buf_size = (is_h265) ? (16 * ((frame_num_lcu << 2) + + BUFFER_ALIGNMENT_SIZE(32))) : + (3 * 16 * (width_lcu_num * height_lcu_num + + BUFFER_ALIGNMENT_SIZE(32))); + col_mv_buf_size = ALIGN(col_mv_buf_size, VENUS_DMA_ALIGNMENT) + * (num_ref + 1); + h265e_colrcbuf_size = (((width_mb_num + 7) >> 3) * + 16 * 2 * height_mb_num); + if (num_vpp_pipes > 1) + h265e_colrcbuf_size = ALIGN(h265e_colrcbuf_size, + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; + h265e_colrcbuf_size = ALIGN(h265e_colrcbuf_size, + VENUS_DMA_ALIGNMENT) * HFI_MAX_COL_FRAME; + h265e_framerc_bufsize = (is_h265) ? (256 + 16 * + (14 + (((height_coded >> 5) + 7) >> 3))) : + (256 + 16 * (14 + (((height_coded >> 4) + 7) >> 3))); + h265e_framerc_bufsize *= 6; /* multiply by max numtilescol*/ + if (num_vpp_pipes > 1) + h265e_framerc_bufsize = ALIGN(h265e_framerc_bufsize, + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; + + h265e_framerc_bufsize = ALIGN(h265e_framerc_bufsize, + BUFFER_ALIGNMENT_SIZE(512)) * HFI_MAX_COL_FRAME; + h265e_lcubitcnt_bufsize = (256 + 4 * frame_num_lcu); + h265e_lcubitcnt_bufsize = ALIGN(h265e_lcubitcnt_bufsize, + VENUS_DMA_ALIGNMENT); + h265e_lcubitmap_bufsize = 256 + (frame_num_lcu >> 3); + h265e_lcubitmap_bufsize = ALIGN(h265e_lcubitmap_bufsize, + VENUS_DMA_ALIGNMENT); + line_buf_sde_size = 256 + 16 * (width_coded >> 4); + line_buf_sde_size = ALIGN(line_buf_sde_size, VENUS_DMA_ALIGNMENT); + if ((width_coded * height_coded) > (4096 * 2160)) + se_stats_bufsize = 0; + else if ((width_coded * height_coded) > (1920 * 1088)) + se_stats_bufsize = (40 * 4 * frame_num_lcu + 256 + 256); + else + se_stats_bufsize = (1024 * frame_num_lcu + 256 + 256); + + se_stats_bufsize = ALIGN(se_stats_bufsize, VENUS_DMA_ALIGNMENT) * 2; + bse_slice_cmd_buffer_size = ((((8192 << 2) + 7) & (~7)) * 6); + bse_reg_buffer_size = ((((512 << 3) + 7) & (~7)) * 4); + vpp_reg_buffer_size = ((((HFI_VENUS_VPPSG_MAX_REGISTERS << 3) + 31) & + (~31)) * 10); + lambda_lut_size = (256 * 11); + override_buffer_size = 16 * ((num_LCUMB + 7) >> 3); + override_buffer_size = ALIGN(override_buffer_size, + VENUS_DMA_ALIGNMENT) * 2; + ir_buffer_size = (((frame_num_lcu << 1) + 7) & (~7)) * 3; + vpss_lineBufferSize_1 = ((((8192) >> 2) << 5) * num_vpp_pipes) + 64; + vpss_line_buf = (((((max(width_coded, height_coded) + 3) >> 2) << 5) + 256) * 16) + + vpss_lineBufferSize_1; + topline_bufsize_fe_1stg_sao = (16 * (width_coded >> 5)); + topline_bufsize_fe_1stg_sao = ALIGN(topline_bufsize_fe_1stg_sao, + VENUS_DMA_ALIGNMENT); + size = line_buf_ctrl_size + line_buf_data_size + + line_buf_ctrl_size_buffid2 + leftline_buf_ctrl_size + + vpss_line_buf + col_mv_buf_size + topline_buf_ctrl_size_FE + + leftline_buf_ctrl_size_FE + line_buf_recon_pix_size + + leftline_buf_recon_pix_size + leftline_buf_meta_recony + + linebuf_meta_recon_uv + h265e_colrcbuf_size + + h265e_framerc_bufsize + h265e_lcubitcnt_bufsize + + h265e_lcubitmap_bufsize + line_buf_sde_size + + topline_bufsize_fe_1stg_sao + override_buffer_size + + bse_reg_buffer_size + vpp_reg_buffer_size + + sps_pps_slice_hdr + slice_cmd_buffer_size + + bse_slice_cmd_buffer_size + ir_buffer_size + slice_info_bufsize + + lambda_lut_size + se_stats_bufsize + temp_scratch_mv_bufsize + + output_mv_bufsize + 1024; + return size; +} + +static inline u32 calculate_h264e_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, u32 num_vpp_pipes) +{ + return calculate_enc_scratch1_size(inst, width, height, 16, + num_ref, ten_bit, num_vpp_pipes, false); +} + +static inline u32 calculate_h265e_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, u32 num_vpp_pipes) +{ + return calculate_enc_scratch1_size(inst, width, height, 32, + num_ref, ten_bit, num_vpp_pipes, true); +} + +static inline u32 calculate_vp8e_scratch1_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, u32 num_vpp_pipes) +{ + (void)num_vpp_pipes; + return calculate_enc_scratch1_size(inst, width, height, 16, + num_ref, ten_bit, 1, false); +} + + +static inline u32 hfi_ubwc_calc_metadata_plane_stride(u32 width, + u32 metadata_stride_multi, u32 tile_width_pels) +{ + return ALIGN(((width + (tile_width_pels - 1)) / tile_width_pels), + metadata_stride_multi); +} + +static inline u32 hfi_ubwc_metadata_plane_bufheight(u32 height, + u32 metadata_height_multi, u32 tile_height_pels) +{ + return ALIGN(((height + (tile_height_pels - 1)) / tile_height_pels), + metadata_height_multi); +} + +static inline u32 hfi_ubwc_metadata_plane_buffer_size(u32 metadata_stride, + u32 metadata_buf_height) +{ + return ALIGN(metadata_stride * metadata_buf_height, + BUFFER_ALIGNMENT_4096_BYTES); +} + +static inline u32 hfi_ubwc_uv_metadata_plane_stride(u32 width, + u32 metadata_stride_multi, u32 tile_width_pels) +{ + return ALIGN(((((width + 1) >> 1) + (tile_width_pels - 1)) / + tile_width_pels), metadata_stride_multi); +} + +static inline u32 hfi_ubwc_uv_metadata_plane_bufheight(u32 height, + u32 metadata_height_multi, u32 tile_height_pels) +{ + return ALIGN(((((height + 1) >> 1) + (tile_height_pels - 1)) / + tile_height_pels), metadata_height_multi); +} + +static inline u32 calculate_enc_scratch2_size(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit) +{ + u32 aligned_width, aligned_height, chroma_height, ref_buf_height; + u32 luma_size, chroma_size; + u32 metadata_stride, meta_buf_height, meta_size_y, meta_size_c; + u32 ref_luma_stride_bytes, ref_chroma_height_bytes; + u32 ref_buf_size = 0, ref_stride; + u32 size; + + if (!ten_bit) { + aligned_height = ALIGN(height, HFI_VENUS_HEIGHT_ALIGNMENT); + chroma_height = height >> 1; + chroma_height = ALIGN(chroma_height, + HFI_VENUS_HEIGHT_ALIGNMENT); + aligned_width = ALIGN(width, HFI_VENUS_WIDTH_ALIGNMENT); + metadata_stride = hfi_ubwc_calc_metadata_plane_stride(width, + 64, HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH); + meta_buf_height = hfi_ubwc_metadata_plane_bufheight(height, + 16, HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT); + meta_size_y = hfi_ubwc_metadata_plane_buffer_size( + metadata_stride, meta_buf_height); + meta_size_c = hfi_ubwc_metadata_plane_buffer_size( + metadata_stride, meta_buf_height); + size = (aligned_height + chroma_height) * aligned_width + + meta_size_y + meta_size_c; + size = (size * (num_ref+3)) + 4096; + } else { + ref_buf_height = (height + (HFI_VENUS_HEIGHT_ALIGNMENT - 1)) + & (~(HFI_VENUS_HEIGHT_ALIGNMENT - 1)); + ref_luma_stride_bytes = ((width + SYSTEM_LAL_TILE10 - 1) / + SYSTEM_LAL_TILE10) * SYSTEM_LAL_TILE10; + ref_stride = 4 * (ref_luma_stride_bytes / 3); + ref_stride = (ref_stride + (BUFFER_ALIGNMENT_SIZE(128) - 1)) & + (~(BUFFER_ALIGNMENT_SIZE(128) - 1)); + luma_size = ref_buf_height * ref_stride; + ref_chroma_height_bytes = (((height + 1) >> 1) + + (BUFFER_ALIGNMENT_SIZE(32) - 1)) & + (~(BUFFER_ALIGNMENT_SIZE(32) - 1)); + chroma_size = ref_stride * ref_chroma_height_bytes; + luma_size = (luma_size + (BUFFER_ALIGNMENT_4096_BYTES - 1)) & + (~(BUFFER_ALIGNMENT_4096_BYTES - 1)); + chroma_size = (chroma_size + + (BUFFER_ALIGNMENT_4096_BYTES - 1)) & + (~(BUFFER_ALIGNMENT_4096_BYTES - 1)); + ref_buf_size = luma_size + chroma_size; + metadata_stride = hfi_ubwc_calc_metadata_plane_stride( + width, + VENUS_METADATA_STRIDE_MULTIPLE, + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH); + meta_buf_height = hfi_ubwc_metadata_plane_bufheight( + height, + VENUS_METADATA_HEIGHT_MULTIPLE, + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT); + meta_size_y = hfi_ubwc_metadata_plane_buffer_size( + metadata_stride, meta_buf_height); + meta_size_c = hfi_ubwc_metadata_plane_buffer_size( + metadata_stride, meta_buf_height); + size = ref_buf_size + meta_size_y + meta_size_c; + size = (size * (num_ref+3)) + 4096; + } + return size; +} + +static inline u32 calculate_enc_persist_size(void) +{ + return HFI_IRIS2_ENC_PERSIST_SIZE; +} + +static inline u32 calculate_h264d_persist1_size(void) +{ + u32 size = 0; + + size = ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264), + VENUS_DMA_ALIGNMENT); + return size; +} + +static inline u32 calculate_h265d_persist1_size(void) +{ + u32 size = 0; + + size = ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + H265_NUM_TILE + * sizeof(u32)), VENUS_DMA_ALIGNMENT); + return size; +} + +static inline u32 calculate_vp8d_persist1_size(void) +{ + u32 size = 0; + + size = ALIGN(VP8_NUM_PROBABILITY_TABLE_BUF * VP8_PROB_TABLE_SIZE, + VENUS_DMA_ALIGNMENT); + return size; +} + +static inline u32 calculate_vp9d_persist1_size(void) +{ + u32 size = 0; + + size = ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, + VENUS_DMA_ALIGNMENT) + + ALIGN(HFI_IRIS2_VP9D_COMV_SIZE, VENUS_DMA_ALIGNMENT) + + ALIGN(MAX_SUPERFRAME_HEADER_LEN, VENUS_DMA_ALIGNMENT) + + ALIGN(VP9_UDC_HEADER_BUF_SIZE, VENUS_DMA_ALIGNMENT) + + ALIGN(VP9_NUM_FRAME_INFO_BUF * CCE_TILE_OFFSET_SIZE, + VENUS_DMA_ALIGNMENT); + return size; +} + +static inline u32 calculate_mpeg2d_persist1_size(void) +{ + return QMATRIX_SIZE + MP2D_QPDUMP_SIZE; +} diff --git a/techpack/video/msm/vidc/msm_vidc_buffer_calculations.h b/techpack/video/msm/vidc/msm_vidc_buffer_calculations.h new file mode 100644 index 0000000000000000000000000000000000000000..a94bc485e32be3032d7160caa1ffe77ca8f87ed2 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_buffer_calculations.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_BUFFER_MEM_DEFS_H__ +#define __H_MSM_VIDC_BUFFER_MEM_DEFS_H__ + +/* extra o/p buffers in case of dcvs */ +#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4 +#define DCVS_ENC_EXTRA_INPUT_BUFFERS DCVS_DEC_EXTRA_OUTPUT_BUFFERS + +struct msm_vidc_dec_buff_size_calculators { + u32 (*calculate_scratch_size)(struct msm_vidc_inst *inst, u32 width, + u32 height, bool is_interlaced); + u32 (*calculate_scratch1_size)(struct msm_vidc_inst *inst, u32 width, + u32 height, u32 min_buf_count, bool split_mode_enabled, + u32 num_vpp_pipes); + u32 (*calculate_persist1_size)(void); +}; + +struct msm_vidc_enc_buff_size_calculators { + u32 (*calculate_scratch_size)(struct msm_vidc_inst *inst, u32 width, + u32 height, u32 work_mode, u32 num_vpp_pipes); + u32 (*calculate_scratch1_size)(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit, + u32 num_vpp_pipes); + u32 (*calculate_scratch2_size)(struct msm_vidc_inst *inst, + u32 width, u32 height, u32 num_ref, bool ten_bit); + u32 (*calculate_persist_size)(void); +}; + +void msm_vidc_init_buffer_size_calculators(struct msm_vidc_inst *inst); +int msm_vidc_calculate_input_buffer_count(struct msm_vidc_inst *inst); +int msm_vidc_calculate_output_buffer_count(struct msm_vidc_inst *inst); +int msm_vidc_calculate_buffer_counts(struct msm_vidc_inst *inst); +int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type); +u32 msm_vidc_calculate_dec_input_frame_size(struct msm_vidc_inst *inst); +u32 msm_vidc_calculate_dec_output_frame_size(struct msm_vidc_inst *inst); +u32 msm_vidc_calculate_dec_output_extra_size(struct msm_vidc_inst *inst); +u32 msm_vidc_calculate_enc_input_frame_size(struct msm_vidc_inst *inst); +u32 msm_vidc_calculate_enc_output_frame_size(struct msm_vidc_inst *inst); +u32 msm_vidc_calculate_enc_input_extra_size(struct msm_vidc_inst *inst); +u32 msm_vidc_calculate_enc_output_extra_size(struct msm_vidc_inst *inst); + +#endif // __H_MSM_VIDC_BUFFER_MEM_DEFS_H__ diff --git a/techpack/video/msm/vidc/msm_vidc_bus.h b/techpack/video/msm/vidc/msm_vidc_bus.h new file mode 100644 index 0000000000000000000000000000000000000000..fd81eef11d5ec78a5e273a99bcd0b3211558dc18 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_bus.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_BUS_DEFS_H__ +#define __H_MSM_VIDC_BUS_DEFS_H__ + +#include "fixedpoint.h" +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" + +#define COMPRESSION_RATIO_MAX 5 + +enum vidc_bus_type { + PERF, + DDR, + LLCC, +}; + +/* + * Minimum dimensions for which to calculate bandwidth. + * This means that anything bandwidth(0, 0) == + * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height) + */ +static const struct { + int height, width; +} BASELINE_DIMENSIONS = { + .width = 1280, + .height = 720, +}; + +/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */ +#define kbps(__mbps) ((__mbps) * 1000) +#define bps(__mbps) (kbps(__mbps) * 1000) + +#define GENERATE_COMPRESSION_PROFILE(__bpp, __worst) { \ + .bpp = __bpp, \ + .ratio = __worst, \ +} + +/* + * The below table is a structural representation of the following table: + * Resolution | Bitrate | Compression Ratio | + * ............|............|.........................................| + * Width Height|Average High|Avg_8bpc Worst_8bpc Avg_10bpc Worst_10bpc| + * 1280 720| 7 14| 1.69 1.28 1.49 1.23| + * 1920 1080| 20 40| 1.69 1.28 1.49 1.23| + * 2560 1440| 32 64| 2.2 1.26 1.97 1.22| + * 3840 2160| 42 84| 2.2 1.26 1.97 1.22| + * 4096 2160| 44 88| 2.2 1.26 1.97 1.22| + * 4096 2304| 48 96| 2.2 1.26 1.97 1.22| + */ +static struct lut { + int frame_size; /* width x height */ + int frame_rate; + unsigned long bitrate; + struct { + int bpp; + fp_t ratio; + } compression_ratio[COMPRESSION_RATIO_MAX]; +} const LUT[] = { + { + .frame_size = 1280 * 720, + .frame_rate = 30, + .bitrate = 14, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 1280 * 720, + .frame_rate = 60, + .bitrate = 22, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 1920 * 1088, + .frame_rate = 30, + .bitrate = 40, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 1920 * 1088, + .frame_rate = 60, + .bitrate = 64, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 2560 * 1440, + .frame_rate = 30, + .bitrate = 64, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 2560 * 1440, + .frame_rate = 60, + .bitrate = 102, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 3840 * 2160, + .frame_rate = 30, + .bitrate = 84, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 3840 * 2160, + .frame_rate = 60, + .bitrate = 134, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2160, + .frame_rate = 30, + .bitrate = 88, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2160, + .frame_rate = 60, + .bitrate = 141, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2304, + .frame_rate = 30, + .bitrate = 96, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2304, + .frame_rate = 60, + .bitrate = 154, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, +}; + +static inline u32 get_type_frm_name(char *name) +{ + if (!strcmp(name, "venus-llcc")) + return LLCC; + else if (!strcmp(name, "venus-ddr")) + return DDR; + else + return PERF; +} + +#define DUMP_HEADER_MAGIC 0xdeadbeef +#define DUMP_FP_FMT "%FP" /* special format for fp_t */ + +struct dump { + char *key; + char *format; + size_t val; +}; + +struct msm_vidc_bus_data { + unsigned long total_bw_ddr; + unsigned long total_bw_llcc; +}; + +int calc_bw_ar50lt(struct vidc_bus_vote_data *vidc_data); + +int calc_bw_iris1(struct vidc_bus_vote_data *vidc_data); + +int calc_bw_iris2(struct vidc_bus_vote_data *vidc_data); + +struct lut const *__lut(int width, int height, int fps); +fp_t __compression_ratio(struct lut const *entry, int bpp); +void __dump(struct dump dump[], int len, u32 sid); + +static inline bool __ubwc(enum hal_uncompressed_format f) +{ + switch (f) { + case HAL_COLOR_FORMAT_NV12_UBWC: + case HAL_COLOR_FORMAT_NV12_TP10_UBWC: + return true; + default: + return false; + } +} + +static inline int __bpp(enum hal_uncompressed_format f, u32 sid) +{ + switch (f) { + case HAL_COLOR_FORMAT_NV12: + case HAL_COLOR_FORMAT_NV21: + case HAL_COLOR_FORMAT_NV12_UBWC: + return 8; + case HAL_COLOR_FORMAT_NV12_TP10_UBWC: + case HAL_COLOR_FORMAT_P010: + return 10; + default: + s_vpr_e(sid, "Unsupported colorformat (%x)", f); + return INT_MAX; + } +} + +#endif // __H_MSM_VIDC_BUS_DEFS_H__ diff --git a/techpack/video/msm/vidc/msm_vidc_bus_ar50lite.c b/techpack/video/msm/vidc/msm_vidc_bus_ar50lite.c new file mode 100644 index 0000000000000000000000000000000000000000..d98592703d6c2a0f1e0027e9adb54137e5fc2a85 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_bus_ar50lite.c @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_bus.h" +#include "msm_vidc_internal.h" + +static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d) +{ + /* Encoder Parameters */ + int width, height, fps, bitrate, lcu_size; + + /* Derived Parameter */ + int search_range, lcu_per_frame; + fp_t y_bw; + bool is_h264_category = true; + fp_t orig_read_factor, recon_write_factor, + ref_y_read_factor, ref_c_read_factor, lb_factor, + rest_factor, total_read_factor, total_write_factor, + total_factor, overhead_factor; + + /* Output parameters */ + fp_t orig_read, recon_write, + ref_y_read, ref_c_read, + lb_read, lb_write, + bse_read, bse_write, + total_read, total_write, + total; + + unsigned long ret = 0; + + /* Encoder Fixed Parameters */ + overhead_factor = FP(1, 3, 100); + orig_read_factor = FP(1, 50, 100); /* L + C */ + recon_write_factor = FP(1, 50, 100); /* L + C */ + ref_c_read_factor = FP(0, 75, 100); /* 1.5/2 ( 1.5 Cache efficiency )*/ + lb_factor = FP(1, 25, 100); /* Worst case : HEVC 720p = 1.25 */ + + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + bitrate = d->bitrate > 0 ? (d->bitrate + 1000000 - 1) / 1000000 : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + + /* Derived Parameters Setup*/ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + if (d->codec == HAL_VIDEO_CODEC_HEVC || + d->codec == HAL_VIDEO_CODEC_VP9) { + /* H264, VP8, MPEG2 use the same settings */ + /* HEVC, VP9 use the same setting */ + is_h264_category = false; + } + + search_range = 48; + + y_bw = fp_mult(fp_mult(FP_INT(width), FP_INT(height)), FP_INT(fps)); + y_bw = fp_div(y_bw, FP_INT(1000000)); + + ref_y_read_factor = fp_div(FP_INT(search_range * 2), FP_INT(lcu_size)); + ref_y_read_factor = ref_y_read_factor + FP_INT(1); + + rest_factor = FP_INT(bitrate) + fp_div(FP_INT(bitrate), FP_INT(8)); + rest_factor = fp_div(rest_factor, y_bw); + + total_read_factor = fp_div(rest_factor, FP_INT(2)) + + fp_div(lb_factor, FP_INT(2)); + total_read_factor = total_read_factor + orig_read_factor + + ref_y_read_factor + ref_c_read_factor; + + total_write_factor = fp_div(rest_factor, FP_INT(2)) + + fp_div(lb_factor, FP_INT(2)); + total_write_factor = total_write_factor + recon_write_factor; + + total_factor = total_read_factor + total_write_factor; + + orig_read = fp_mult(y_bw, orig_read_factor); + recon_write = fp_mult(y_bw, recon_write_factor); + ref_y_read = fp_mult(y_bw, ref_y_read_factor); + ref_c_read = fp_mult(y_bw, ref_c_read_factor); + lb_read = fp_div(fp_mult(y_bw, lb_factor), FP_INT(2)); + lb_write = lb_read; + bse_read = fp_mult(y_bw, fp_div(rest_factor, FP_INT(2))); + bse_write = bse_read; + + total_read = orig_read + ref_y_read + ref_c_read + + lb_read + bse_read; + total_write = recon_write + lb_write + bse_write; + + total = total_read + total_write; + total = fp_mult(total, overhead_factor); + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"lcu size", "%d", lcu_size}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu/frame", "%d", lcu_per_frame}, + {"Y BW", DUMP_FP_FMT, y_bw}, + {"search range", "%d", search_range}, + {"original read factor", DUMP_FP_FMT, orig_read_factor}, + {"recon write factor", DUMP_FP_FMT, recon_write_factor}, + {"ref read Y factor", DUMP_FP_FMT, ref_y_read_factor}, + {"ref read C factor", DUMP_FP_FMT, ref_c_read_factor}, + {"lb factor", DUMP_FP_FMT, lb_factor}, + {"rest factor", DUMP_FP_FMT, rest_factor}, + {"total_read_factor", DUMP_FP_FMT, total_read_factor}, + {"total_write_factor", DUMP_FP_FMT, total_write_factor}, + {"total_factor", DUMP_FP_FMT, total_factor}, + {"overhead_factor", DUMP_FP_FMT, overhead_factor}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"orig read", DUMP_FP_FMT, orig_read}, + {"recon write", DUMP_FP_FMT, recon_write}, + {"ref read Y", DUMP_FP_FMT, ref_y_read}, + {"ref read C", DUMP_FP_FMT, ref_c_read}, + {"lb read", DUMP_FP_FMT, lb_read}, + {"lb write", DUMP_FP_FMT, lb_write}, + {"bse read", DUMP_FP_FMT, bse_read}, + {"bse write", DUMP_FP_FMT, bse_write}, + {"total read", DUMP_FP_FMT, total_read}, + {"total write", DUMP_FP_FMT, total_write}, + {"total", DUMP_FP_FMT, total}, + }; + __dump(dump, ARRAY_SIZE(dump), d->sid); + } + + + d->calc_bw_ddr = kbps(fp_round(total)); + + return ret; +} + +static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d) +{ + /* Decoder parameters */ + int width, height, fps, bitrate, lcu_size; + + /* Derived parameters */ + int lcu_per_frame, motion_complexity; + fp_t y_bw; + bool is_h264_category = true; + fp_t recon_write_factor, ref_read_factor, lb_factor, + rest_factor, opb_factor, + total_read_factor, total_write_factor, + total_factor, overhead_factor; + + /* Output parameters */ + fp_t opb_write, recon_write, + ref_read, + lb_read, lb_write, + bse_read, bse_write, + total_read, total_write, + total; + + unsigned long ret = 0; + + /* Decoder Fixed Parameters */ + overhead_factor = FP(1, 3, 100); + recon_write_factor = FP(1, 50, 100); /* L + C */ + opb_factor = FP(1, 50, 100); /* L + C */ + lb_factor = FP(1, 13, 100); /* Worst case : H264 1080p = 1.125 */ + motion_complexity = 5; /* worst case complexity */ + + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + bitrate = d->bitrate > 0 ? (d->bitrate + 1000000 - 1) / 1000000 : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + + /* Derived Parameters Setup*/ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + if (d->codec == HAL_VIDEO_CODEC_HEVC || + d->codec == HAL_VIDEO_CODEC_VP9) { + /* H264, VP8, MPEG2 use the same settings */ + /* HEVC, VP9 use the same setting */ + is_h264_category = false; + } + + y_bw = fp_mult(fp_mult(FP_INT(width), FP_INT(height)), FP_INT(fps)); + y_bw = fp_div(y_bw, FP_INT(1000000)); + + ref_read_factor = FP(1, 50, 100); /* L + C */ + ref_read_factor = fp_mult(ref_read_factor, FP_INT(motion_complexity)); + + rest_factor = FP_INT(bitrate) + fp_div(FP_INT(bitrate), FP_INT(8)); + rest_factor = fp_div(rest_factor, y_bw); + + total_read_factor = fp_div(rest_factor, FP_INT(2)) + + fp_div(lb_factor, FP_INT(2)); + total_read_factor = total_read_factor + ref_read_factor; + + total_write_factor = fp_div(rest_factor, FP_INT(2)); + total_write_factor = total_write_factor + + recon_write_factor + opb_factor; + + total_factor = total_read_factor + total_write_factor; + + recon_write = fp_mult(y_bw, recon_write_factor); + ref_read = fp_mult(y_bw, ref_read_factor); + lb_read = fp_div(fp_mult(y_bw, lb_factor), FP_INT(2)); + lb_write = lb_read; + bse_read = fp_div(fp_mult(y_bw, rest_factor), FP_INT(2)); + bse_write = bse_read; + opb_write = fp_mult(y_bw, opb_factor); + + total_read = ref_read + lb_read + bse_read; + total_write = recon_write + lb_write + bse_write + opb_write; + + total = total_read + total_write; + total = fp_mult(total, overhead_factor); + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"lcu size", "%d", lcu_size}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu/frame", "%d", lcu_per_frame}, + {"Y BW", DUMP_FP_FMT, y_bw}, + {"motion complexity", "%d", motion_complexity}, + {"recon write factor", DUMP_FP_FMT, recon_write_factor}, + {"ref_read_factor", DUMP_FP_FMT, ref_read_factor}, + {"lb factor", DUMP_FP_FMT, lb_factor}, + {"rest factor", DUMP_FP_FMT, rest_factor}, + {"opb factor", DUMP_FP_FMT, opb_factor}, + {"total_read_factor", DUMP_FP_FMT, total_read_factor}, + {"total_write_factor", DUMP_FP_FMT, total_write_factor}, + {"total_factor", DUMP_FP_FMT, total_factor}, + {"overhead_factor", DUMP_FP_FMT, overhead_factor}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"recon write", DUMP_FP_FMT, recon_write}, + {"ref read", DUMP_FP_FMT, ref_read}, + {"lb read", DUMP_FP_FMT, lb_read}, + {"lb write", DUMP_FP_FMT, lb_write}, + {"bse read", DUMP_FP_FMT, bse_read}, + {"bse write", DUMP_FP_FMT, bse_write}, + {"opb write", DUMP_FP_FMT, opb_write}, + {"total read", DUMP_FP_FMT, total_read}, + {"total write", DUMP_FP_FMT, total_write}, + {"total", DUMP_FP_FMT, total}, + }; + __dump(dump, ARRAY_SIZE(dump), d->sid); + } + + d->calc_bw_ddr = kbps(fp_round(total)); + + return ret; +} + +static unsigned long __calculate(struct vidc_bus_vote_data *d) +{ + unsigned long value = 0; + + switch (d->domain) { + case HAL_VIDEO_DOMAIN_ENCODER: + value = __calculate_encoder(d); + break; + case HAL_VIDEO_DOMAIN_DECODER: + value = __calculate_decoder(d); + break; + default: + s_vpr_e(d->sid, "Unknown Domain %#x", d->domain); + } + + return value; +} + +int calc_bw_ar50lt(struct vidc_bus_vote_data *vidc_data) +{ + int ret = 0; + + if (!vidc_data) + return ret; + + ret = __calculate(vidc_data); + + return ret; +} diff --git a/techpack/video/msm/vidc/msm_vidc_bus_iris1.c b/techpack/video/msm/vidc/msm_vidc_bus_iris1.c new file mode 100644 index 0000000000000000000000000000000000000000..91c1f6f2ec69a734c96341af6e9483afcb9e1557 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_bus_iris1.c @@ -0,0 +1,652 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_bus.h" +#include "msm_vidc_internal.h" + +struct lut const *__lut(int width, int height, int fps) +{ + int frame_size = height * width, c = 0; + + do { + if (LUT[c].frame_size >= frame_size && LUT[c].frame_rate >= fps) + return &LUT[c]; + } while (++c < ARRAY_SIZE(LUT)); + + return &LUT[ARRAY_SIZE(LUT) - 1]; +} + +fp_t __compression_ratio(struct lut const *entry, int bpp) +{ + int c = 0; + + for (c = 0; c < COMPRESSION_RATIO_MAX; ++c) { + if (entry->compression_ratio[c].bpp == bpp) + return entry->compression_ratio[c].ratio; + } + + WARN(true, "Shouldn't be here, LUT possibly corrupted?\n"); + return FP_ZERO; /* impossible */ +} + +void __dump(struct dump dump[], int len, u32 sid) +{ + int c = 0; + + for (c = 0; c < len; ++c) { + char format_line[128] = "", formatted_line[128] = ""; + + if (dump[c].val == DUMP_HEADER_MAGIC) { + snprintf(formatted_line, sizeof(formatted_line), "%s\n", + dump[c].key); + } else { + bool fp_format = !strcmp(dump[c].format, DUMP_FP_FMT); + + if (!fp_format) { + snprintf(format_line, sizeof(format_line), + " %-35s: %s\n", dump[c].key, + dump[c].format); + snprintf(formatted_line, sizeof(formatted_line), + format_line, dump[c].val); + } else { + size_t integer_part, fractional_part; + + integer_part = fp_int(dump[c].val); + fractional_part = fp_frac(dump[c].val); + snprintf(formatted_line, sizeof(formatted_line), + " %-35s: %zd + %zd/%zd\n", + dump[c].key, integer_part, + fractional_part, + fp_frac_base()); + + + } + } + s_vpr_b(sid, "%s", formatted_line); + } +} + +static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d) +{ + return 0; +} + +static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d) +{ + return 0; +} + +static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Decoder parameters */ + int width, height, lcu_size, fps, dpb_bpp; + bool unified_dpb_opb, dpb_compression_enabled = true, + opb_compression_enabled = false, + llc_ref_read_l2_cache_enabled = false, + llc_top_line_buf_enabled = false; + fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio, + dpb_write_compression_factor, opb_write_compression_factor, + qsmmu_bw_overhead_factor; + bool is_h264_category = true; + + /* Derived parameters */ + int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu; + unsigned long bitrate; + + fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor, + dpb_factor, dpb_write_factor, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, y_bw_10bpp_p010, + motion_vector_complexity = 0; + fp_t dpb_total = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + dpb_read, dpb_write, opb_read, opb_write, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t dpb_read, line_buffer_read, line_buffer_write, total; + } llc = {0}; + + unsigned long ret = 0; + unsigned int integer_part, frac_part; + + width = max(d->input_width, BASELINE_DIMENSIONS.width); + height = max(d->input_height, BASELINE_DIMENSIONS.height); + + fps = d->fps; + + lcu_size = d->lcu_size; + + dpb_bpp = d->num_formats >= 1 ? + __bpp(d->color_formats[0], d->sid) : INT_MAX; + + unified_dpb_opb = d->num_formats == 1; + + dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + + opb_compression_enabled = d->num_formats >= 2 && + __ubwc(d->color_formats[1]); + + /* + * convert q16 number into integer and fractional part upto 2 places. + * ex : 105752 / 65536 = 1.61; 1.61 in q16 = 105752; + * integer part = 105752 / 65536 = 1; + * reminder = 105752 - 1 * 65536 = 40216; + * fractional part = 40216 * 100 / 65536 = 61; + * now converto to fp(1, 61, 100) for below code. + */ + + integer_part = d->compression_ratio >> 16; + frac_part = + ((d->compression_ratio - (integer_part << 16)) * 100) >> 16; + + dpb_read_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = d->complexity_factor >> 16; + frac_part = + ((d->complexity_factor - (integer_part << 16)) * 100) >> 16; + + motion_vector_complexity = FP(integer_part, frac_part, 100); + + dpb_write_compression_factor = dpb_read_compression_factor; + opb_write_compression_factor = opb_compression_enabled ? + dpb_write_compression_factor : FP_ONE; + + if (d->codec == HAL_VIDEO_CODEC_HEVC || + d->codec == HAL_VIDEO_CODEC_VP9) { + /* H264, VP8, MPEG2 use the same settings */ + /* HEVC, VP9 use the same setting */ + is_h264_category = false; + } + if (d->use_sys_cache) { + llc_ref_read_l2_cache_enabled = true; + if (is_h264_category) + llc_top_line_buf_enabled = true; + } + + /* Derived parameters setup */ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + bitrate = (d->bitrate + 1000000 - 1) / 1000000; + + bins_to_bit_factor = FP_INT(4); + vsp_write_factor = bins_to_bit_factor; + vsp_read_factor = bins_to_bit_factor + FP_INT(2); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + dpb_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 5, 100); + + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + /* .... For DDR & LLC ...... */ + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), + vsp_read_factor), FP_INT(8)); + ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate), + vsp_write_factor), FP_INT(8)); + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + ddr.collocated_write = ddr.collocated_read; + + y_bw_no_ubwc_8bpp = fp_div(fp_mult( + FP_INT((int)(width * height)), FP_INT((int)fps)), + FP_INT(1000 * 1000)); + y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)), + FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + + ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read, + fp_mult(dpb_factor, motion_vector_complexity)), + dpb_read_compression_factor); + + ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write, + fp_mult(dpb_factor, dpb_write_factor)), + dpb_write_compression_factor); + + dpb_total = ddr.dpb_read + ddr.dpb_write; + + if (llc_ref_read_l2_cache_enabled) { + ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ? + FP(1, 30, 100) : FP(1, 15, 100)); + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; + } + + ddr.opb_read = FP_ZERO; + ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : (opb_compression_enabled ? + y_bw_no_ubwc_10bpp : y_bw_10bpp_p010)); + ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write), + fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor)); + + ddr.line_buffer_read = FP_INT(tnbr_per_lcu * + lcu_per_frame * fps / bps(1)); + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer_read = ddr.line_buffer_read; + llc.line_buffer_write = ddr.line_buffer_write; + ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.dpb_read + ddr.dpb_write + + ddr.opb_read + ddr.opb_write + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.dpb_read + llc.line_buffer_read + + llc.line_buffer_write + ddr.total; + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"frame rate", "%d", fps}, + {"dpb/opb unified", "%d", unified_dpb_opb}, + {"dpb/opb downscaling ratio", DUMP_FP_FMT, + dpb_opb_scaling_ratio}, + {"dpb compression", "%d", dpb_compression_enabled}, + {"opb compression", "%d", opb_compression_enabled}, + {"dpb read compression factor", DUMP_FP_FMT, + dpb_read_compression_factor}, + {"dpb write compression factor", DUMP_FP_FMT, + dpb_write_compression_factor}, + {"frame width", "%d", width}, + {"frame height", "%d", height}, + {"llc ref read l2 cache enabled", "%d", + llc_ref_read_l2_cache_enabled}, + {"llc top line buf enabled", "%d", + llc_top_line_buf_enabled}, + + {"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC}, + {"lcus/frame", "%d", lcu_per_frame}, + {"bitrate (Mbit/sec)", "%d", bitrate}, + {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"dpb write factor", DUMP_FP_FMT, dpb_write_factor}, + {"vsp read factor", DUMP_FP_FMT, vsp_read_factor}, + {"vsp write factor", DUMP_FP_FMT, vsp_write_factor}, + {"tnbr/lcu", "%d", tnbr_per_lcu}, + {"collocated bytes/LCU", "%d", collocated_bytes_per_lcu}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, + {"mv complexity", DUMP_FP_FMT, motion_vector_complexity}, + {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, + qsmmu_bw_overhead_factor}, + + {"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"opb read", DUMP_FP_FMT, ddr.opb_read}, + {"opb write", DUMP_FP_FMT, ddr.opb_write}, + {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, + {"dpb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb total", DUMP_FP_FMT, dpb_total}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, + {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, + {"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write}, + + }; + __dump(dump, ARRAY_SIZE(dump), d->sid); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Encoder Parameters */ + int width, height, fps, lcu_size, bitrate, lcu_per_frame, + collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp, + original_color_format, vertical_tile_width; + bool work_mode_1, original_compression_enabled, + low_power, rotation, cropping_or_scaling, + b_frames_enabled = false, + llc_ref_chroma_cache_enabled = false, + llc_top_line_buf_enabled = false, + llc_vpss_rot_line_buf_enabled = false; + + fp_t bins_to_bit_factor, dpb_compression_factor, + original_compression_factor, + original_compression_factor_y, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, y_bw_10bpp_p010, + input_compression_factor, + downscaling_ratio, + ref_y_read_bw_factor, ref_cbcr_read_bw_factor, + recon_write_bw_factor, mese_read_factor, + total_ref_read_crcb, + qsmmu_bw_overhead_factor; + fp_t integer_part, frac_part; + unsigned long ret = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + ref_read_y, ref_read_crcb, ref_write, + ref_write_overlap, orig_read, + line_buffer_read, line_buffer_write, + mese_read, mese_write, + total; + } ddr = {0}; + + struct { + fp_t ref_read_crcb, line_buffer, total; + } llc = {0}; + + /* Encoder Parameters setup */ + rotation = d->rotation; + cropping_or_scaling = false; + vertical_tile_width = 960; + recon_write_bw_factor = FP(1, 8, 100); + ref_y_read_bw_factor = FP(1, 30, 100); + ref_cbcr_read_bw_factor = FP(1, 50, 100); + + + /* Derived Parameters */ + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + downscaling_ratio = max(downscaling_ratio, FP_ONE); + bitrate = d->bitrate > 0 ? (d->bitrate + 1000000 - 1) / 1000000 : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + tnbr_per_lcu = 16; + + y_bw_no_ubwc_8bpp = fp_div(fp_mult( + FP_INT((int)(width * height)), FP_INT(fps)), + FP_INT(1000 * 1000)); + y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, + FP_INT(256)), FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + + b_frames_enabled = d->b_frames_enabled; + original_color_format = d->num_formats >= 1 ? + d->color_formats[0] : HAL_UNUSED_COLOR; + + dpb_bpp = d->num_formats >= 1 ? + __bpp(d->color_formats[0], d->sid) : INT_MAX; + + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == HFI_WORKMODE_1; + low_power = d->power_mode == VIDC_POWER_LOW; + bins_to_bit_factor = FP_INT(4); + + if (d->use_sys_cache) { + llc_ref_chroma_cache_enabled = true; + llc_top_line_buf_enabled = true, + llc_vpss_rot_line_buf_enabled = true; + } + + /* + * Convert Q16 number into Integer and Fractional part upto 2 places. + * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752; + * Integer part = 105752 / 65536 = 1; + * Reminder = 105752 - 1 * 65536 = 40216; + * Fractional part = 40216 * 100 / 65536 = 61; + * Now converto to FP(1, 61, 100) for below code. + */ + + integer_part = d->compression_ratio >> 16; + frac_part = + ((d->compression_ratio - (integer_part * 65536)) * 100) >> 16; + + dpb_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = d->input_cr >> 16; + frac_part = + ((d->input_cr - (integer_part * 65536)) * 100) >> 16; + + input_compression_factor = FP(integer_part, frac_part, 100); + + original_compression_factor = original_compression_factor_y = + !original_compression_enabled ? FP_ONE : + __compression_ratio(__lut(width, height, fps), dpb_bpp); + /* use input cr if it is valid (not 1), otherwise use lut */ + if (original_compression_enabled && + input_compression_factor != FP_ONE) { + original_compression_factor = input_compression_factor; + /* Luma usually has lower compression factor than Chroma, + * input cf is overall cf, add 1.08 factor for Luma cf + */ + original_compression_factor_y = + input_compression_factor > FP(1, 8, 100) ? + fp_div(input_compression_factor, FP(1, 8, 100)) : + input_compression_factor; + } + + mese_read_factor = fp_div(FP_INT((width * height * fps)/4), + original_compression_factor_y); + mese_read_factor = fp_div(fp_mult(mese_read_factor, FP(2, 53, 100)), + FP_INT(1000 * 1000)); + + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), bins_to_bit_factor), + FP_INT(8)); + ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + + ddr.collocated_write = ddr.collocated_read; + + ddr.ref_read_y = ddr.ref_read_crcb = dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + + if (width != vertical_tile_width) { + ddr.ref_read_y = fp_mult(ddr.ref_read_y, + ref_y_read_bw_factor); + } + + ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor); + if (b_frames_enabled) + ddr.ref_read_y = fp_mult(ddr.ref_read_y, FP_INT(2)); + + ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP(0, 50, 100)); + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, dpb_compression_factor); + if (b_frames_enabled) + ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP_INT(2)); + + if (llc_ref_chroma_cache_enabled) { + total_ref_read_crcb = ddr.ref_read_crcb; + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, + ref_cbcr_read_bw_factor); + llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb; + } + + ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.ref_write = fp_mult(ddr.ref_write, + (fp_div(FP(1, 50, 100), dpb_compression_factor))); + + ddr.ref_write_overlap = fp_div(fp_mult(ddr.ref_write, + (recon_write_bw_factor - FP_ONE)), + recon_write_bw_factor); + + ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : + (original_compression_enabled ? y_bw_no_ubwc_10bpp : + y_bw_10bpp_p010); + ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)), + downscaling_ratio), original_compression_factor); + if (rotation == 90 || rotation == 270) + ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2; + + ddr.line_buffer_read = FP_INT(tnbr_per_lcu * lcu_per_frame * + fps / bps(1)); + + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO; + } + + ddr.mese_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.mese_read = fp_div(fp_mult(ddr.mese_read, FP(1, 37, 100)), + original_compression_factor_y) + mese_read_factor; + + ddr.mese_write = FP_INT((width * height)/512) + + fp_div(FP_INT((width * height)/4), + original_compression_factor_y) + + FP_INT((width * height)/128); + ddr.mese_write = fp_div(fp_mult(ddr.mese_write, FP_INT(fps)), + FP_INT(1000 * 1000)); + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.ref_read_y + ddr.ref_read_crcb + + ddr.ref_write + ddr.ref_write_overlap + + ddr.orig_read + + ddr.line_buffer_read + ddr.line_buffer_write + + ddr.mese_read + ddr.mese_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total; + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio}, + {"rotation", "%d", rotation}, + {"cropping or scaling", "%d", cropping_or_scaling}, + {"low power mode", "%d", low_power}, + {"work Mode", "%d", work_mode_1}, + {"B frame enabled", "%d", b_frames_enabled}, + {"original frame format", "%#x", original_color_format}, + {"original compression enabled", "%d", + original_compression_enabled}, + {"dpb compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"input compression factor", DUMP_FP_FMT, + input_compression_factor}, + {"llc ref chroma cache enabled", DUMP_FP_FMT, + llc_ref_chroma_cache_enabled}, + {"llc top line buf enabled", DUMP_FP_FMT, + llc_top_line_buf_enabled}, + {"llc vpss rot line buf enabled ", DUMP_FP_FMT, + llc_vpss_rot_line_buf_enabled}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"original compression factor y", DUMP_FP_FMT, + original_compression_factor_y}, + {"mese read factor", DUMP_FP_FMT, + mese_read_factor}, + {"qsmmu_bw_overhead_factor", + DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"ref read y", DUMP_FP_FMT, ddr.ref_read_y}, + {"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb}, + {"ref write", DUMP_FP_FMT, ddr.ref_write}, + {"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap}, + {"original read", DUMP_FP_FMT, ddr.orig_read}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"mese read", DUMP_FP_FMT, ddr.mese_read}, + {"mese write", DUMP_FP_FMT, ddr.mese_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb}, + {"llc line buffer", DUMP_FP_FMT, llc.line_buffer}, + }; + __dump(dump, ARRAY_SIZE(dump), d->sid); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static unsigned long __calculate(struct vidc_bus_vote_data *d) +{ + unsigned long value = 0; + + switch (d->domain) { + case HAL_VIDEO_DOMAIN_VPE: + value = __calculate_vpe(d); + break; + case HAL_VIDEO_DOMAIN_ENCODER: + value = __calculate_encoder(d); + break; + case HAL_VIDEO_DOMAIN_DECODER: + value = __calculate_decoder(d); + break; + case HAL_VIDEO_DOMAIN_CVP: + value = __calculate_cvp(d); + break; + default: + s_vpr_e(d->sid, "Unknown Domain %#x", d->domain); + } + + return value; +} + +int calc_bw_iris1(struct vidc_bus_vote_data *vidc_data) +{ + int ret = 0; + + if (!vidc_data) + return ret; + + ret = __calculate(vidc_data); + + return ret; +} + diff --git a/techpack/video/msm/vidc/msm_vidc_bus_iris2.c b/techpack/video/msm/vidc/msm_vidc_bus_iris2.c new file mode 100644 index 0000000000000000000000000000000000000000..0da868b57612d6bfe0f4aed182c8bb2db8d26f59 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_bus_iris2.c @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_bus.h" +#include "msm_vidc_internal.h" + +static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d) +{ + return 0; +} + +static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d) +{ + return 0; +} + +static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Decoder parameters */ + int width, height, lcu_size, fps, dpb_bpp; + bool unified_dpb_opb, dpb_compression_enabled = true, + opb_compression_enabled = false, + llc_ref_read_l2_cache_enabled = false, + llc_top_line_buf_enabled = false; + fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio, + dpb_write_compression_factor, opb_write_compression_factor, + qsmmu_bw_overhead_factor; + bool is_h264_category = true; + + /* Derived parameters */ + int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu; + unsigned long bitrate; + + fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor, + dpb_factor, dpb_write_factor, y_bw_no_ubwc_8bpp; + fp_t y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + motion_vector_complexity = 0; + fp_t dpb_total = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + dpb_read, dpb_write, opb_read, opb_write, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t dpb_read, line_buffer_read, line_buffer_write, total; + } llc = {0}; + + unsigned long ret = 0; + unsigned int integer_part, frac_part; + + width = max(d->input_width, BASELINE_DIMENSIONS.width); + height = max(d->input_height, BASELINE_DIMENSIONS.height); + + fps = d->fps; + + lcu_size = d->lcu_size; + + dpb_bpp = __bpp(d->color_formats[0], d->sid); + + unified_dpb_opb = d->num_formats == 1; + + dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + + opb_compression_enabled = d->num_formats >= 2 && + __ubwc(d->color_formats[1]); + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_read_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->complexity_factor); + frac_part = Q16_FRAC(d->complexity_factor); + motion_vector_complexity = FP(integer_part, frac_part, 100); + + dpb_write_compression_factor = dpb_read_compression_factor; + opb_write_compression_factor = opb_compression_enabled ? + dpb_write_compression_factor : FP_ONE; + + if (d->codec == HAL_VIDEO_CODEC_HEVC || + d->codec == HAL_VIDEO_CODEC_VP9) { + /* H264, VP8, MPEG2 use the same settings */ + /* HEVC, VP9 use the same setting */ + is_h264_category = false; + } + if (d->use_sys_cache) { + llc_ref_read_l2_cache_enabled = true; + if (is_h264_category) + llc_top_line_buf_enabled = true; + } + + /* Derived parameters setup */ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + bitrate = DIV_ROUND_UP(d->bitrate, 1000000); + + bins_to_bit_factor = FP_INT(4); + + vsp_write_factor = bins_to_bit_factor; + vsp_read_factor = bins_to_bit_factor + FP_INT(2); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + dpb_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 5, 100); + + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + /* .... For DDR & LLC ...... */ + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), + vsp_read_factor), FP_INT(8)); + ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate), + vsp_write_factor), FP_INT(8)); + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + ddr.collocated_write = ddr.collocated_read; + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = + fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)), + FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read, + fp_mult(dpb_factor, motion_vector_complexity)), + dpb_read_compression_factor); + + ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write, + fp_mult(dpb_factor, dpb_write_factor)), + dpb_write_compression_factor); + + dpb_total = ddr.dpb_read + ddr.dpb_write; + + if (llc_ref_read_l2_cache_enabled) { + ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ? + FP(1, 30, 100) : FP(1, 14, 100)); + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; + } + + ddr.opb_read = FP_ZERO; + ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : (opb_compression_enabled ? + y_bw_no_ubwc_10bpp : y_bw_10bpp_p010)); + ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write), + fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor)); + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer_read = ddr.line_buffer_read; + llc.line_buffer_write = ddr.line_buffer_write; + ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.dpb_read + ddr.dpb_write + + ddr.opb_read + ddr.opb_write + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.dpb_read + llc.line_buffer_read + + llc.line_buffer_write + ddr.total; + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"frame rate", "%d", fps}, + {"dpb/opb unified", "%d", unified_dpb_opb}, + {"dpb/opb downscaling ratio", DUMP_FP_FMT, + dpb_opb_scaling_ratio}, + {"dpb compression", "%d", dpb_compression_enabled}, + {"opb compression", "%d", opb_compression_enabled}, + {"dpb read compression factor", DUMP_FP_FMT, + dpb_read_compression_factor}, + {"dpb write compression factor", DUMP_FP_FMT, + dpb_write_compression_factor}, + {"frame width", "%d", width}, + {"frame height", "%d", height}, + {"llc ref read l2 cache enabled", "%d", + llc_ref_read_l2_cache_enabled}, + {"llc top line buf enabled", "%d", + llc_top_line_buf_enabled}, + + {"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC}, + {"lcus/frame", "%d", lcu_per_frame}, + {"bitrate (Mbit/sec)", "%d", bitrate}, + {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"dpb write factor", DUMP_FP_FMT, dpb_write_factor}, + {"vsp read factor", DUMP_FP_FMT, vsp_read_factor}, + {"vsp write factor", DUMP_FP_FMT, vsp_write_factor}, + {"tnbr/lcu", "%d", tnbr_per_lcu}, + {"collocated bytes/LCU", "%d", collocated_bytes_per_lcu}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, + {"mv complexity", DUMP_FP_FMT, motion_vector_complexity}, + {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, + qsmmu_bw_overhead_factor}, + + {"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"opb read", DUMP_FP_FMT, ddr.opb_read}, + {"opb write", DUMP_FP_FMT, ddr.opb_write}, + {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, + {"dpb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb total", DUMP_FP_FMT, dpb_total}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, + {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, + {"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write}, + + }; + __dump(dump, ARRAY_SIZE(dump), d->sid); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Encoder Parameters */ + int width, height, fps, lcu_size, bitrate, lcu_per_frame, + collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp, + original_color_format, vertical_tile_width, rotation; + bool work_mode_1, original_compression_enabled, + low_power, cropping_or_scaling, + b_frames_enabled = false, + llc_ref_chroma_cache_enabled = false, + llc_top_line_buf_enabled = false, + llc_vpss_rot_line_buf_enabled = false; + + unsigned int bins_to_bit_factor; + fp_t dpb_compression_factor, + original_compression_factor, + original_compression_factor_y, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + input_compression_factor, + downscaling_ratio, + ref_y_read_bw_factor, ref_cbcr_read_bw_factor, + recon_write_bw_factor, + total_ref_read_crcb, + qsmmu_bw_overhead_factor; + fp_t integer_part, frac_part; + unsigned long ret = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + ref_read_y, ref_read_crcb, ref_write, + ref_write_overlap, orig_read, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t ref_read_crcb, line_buffer, total; + } llc = {0}; + + /* Encoder Parameters setup */ + rotation = d->rotation; + cropping_or_scaling = false; + vertical_tile_width = 960; + /* + * recon_write_bw_factor varies according to resolution and bit-depth, + * here use 1.08(1.075) for worst case. + * Similar for ref_y_read_bw_factor, it can reach 1.375 for worst case, + * here use 1.3 for average case, and can somewhat balance the + * worst case assumption for UBWC CR factors. + */ + recon_write_bw_factor = FP(1, 8, 100); + ref_y_read_bw_factor = FP(1, 30, 100); + ref_cbcr_read_bw_factor = FP(1, 50, 100); + + + /* Derived Parameters */ + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + downscaling_ratio = max(downscaling_ratio, FP_ONE); + bitrate = d->bitrate > 0 ? DIV_ROUND_UP(d->bitrate, 1000000) : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + tnbr_per_lcu = 16; + + dpb_bpp = __bpp(d->color_formats[0], d->sid); + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, + FP_INT(256)), FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + b_frames_enabled = d->b_frames_enabled; + original_color_format = d->num_formats >= 1 ? + d->color_formats[0] : HAL_UNUSED_COLOR; + + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == HFI_WORKMODE_1; + low_power = d->power_mode == VIDC_POWER_LOW; + bins_to_bit_factor = 4; + + if (d->use_sys_cache) { + llc_ref_chroma_cache_enabled = true; + llc_top_line_buf_enabled = true, + llc_vpss_rot_line_buf_enabled = true; + } + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->input_cr); + frac_part = Q16_FRAC(d->input_cr); + input_compression_factor = FP(integer_part, frac_part, 100); + + original_compression_factor = original_compression_factor_y = + !original_compression_enabled ? FP_ONE : + __compression_ratio(__lut(width, height, fps), dpb_bpp); + /* use input cr if it is valid (not 1), otherwise use lut */ + if (original_compression_enabled && + input_compression_factor != FP_ONE) { + original_compression_factor = input_compression_factor; + /* Luma usually has lower compression factor than Chroma, + * input cf is overall cf, add 1.08 factor for Luma cf + */ + original_compression_factor_y = + input_compression_factor > FP(1, 8, 100) ? + fp_div(input_compression_factor, FP(1, 8, 100)) : + input_compression_factor; + } + + ddr.vsp_read = fp_div(FP_INT(bitrate * bins_to_bit_factor), FP_INT(8)); + ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + + ddr.collocated_write = ddr.collocated_read; + + ddr.ref_read_y = dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + if (b_frames_enabled) + ddr.ref_read_y = ddr.ref_read_y * 2; + ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor); + + ddr.ref_read_crcb = fp_mult((ddr.ref_read_y / 2), + ref_cbcr_read_bw_factor); + + if (width > vertical_tile_width) { + ddr.ref_read_y = fp_mult(ddr.ref_read_y, + ref_y_read_bw_factor); + } + + if (llc_ref_chroma_cache_enabled) { + total_ref_read_crcb = ddr.ref_read_crcb; + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, + ref_cbcr_read_bw_factor); + llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb; + } + + ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.ref_write = fp_div(fp_mult(ddr.ref_write, FP(1, 50, 100)), + dpb_compression_factor); + + if (width > vertical_tile_width) { + ddr.ref_write_overlap = fp_mult(ddr.ref_write, + (recon_write_bw_factor - FP_ONE)); + ddr.ref_write = fp_mult(ddr.ref_write, recon_write_bw_factor); + } + + ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : + (original_compression_enabled ? y_bw_no_ubwc_10bpp : + y_bw_10bpp_p010); + ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)), + downscaling_ratio), original_compression_factor); + if (rotation == 90 || rotation == 270) + ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2; + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.ref_read_y + ddr.ref_read_crcb + + ddr.ref_write + ddr.ref_write_overlap + + ddr.orig_read + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total; + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio}, + {"rotation", "%d", rotation}, + {"cropping or scaling", "%d", cropping_or_scaling}, + {"low power mode", "%d", low_power}, + {"work Mode", "%d", work_mode_1}, + {"B frame enabled", "%d", b_frames_enabled}, + {"original frame format", "%#x", original_color_format}, + {"original compression enabled", "%d", + original_compression_enabled}, + {"dpb compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"input compression factor", DUMP_FP_FMT, + input_compression_factor}, + {"llc ref chroma cache enabled", DUMP_FP_FMT, + llc_ref_chroma_cache_enabled}, + {"llc top line buf enabled", DUMP_FP_FMT, + llc_top_line_buf_enabled}, + {"llc vpss rot line buf enabled ", DUMP_FP_FMT, + llc_vpss_rot_line_buf_enabled}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"bins to bit factor", "%u", bins_to_bit_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"original compression factor y", DUMP_FP_FMT, + original_compression_factor_y}, + {"qsmmu_bw_overhead_factor", + DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"ref read y", DUMP_FP_FMT, ddr.ref_read_y}, + {"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb}, + {"ref write", DUMP_FP_FMT, ddr.ref_write}, + {"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap}, + {"original read", DUMP_FP_FMT, ddr.orig_read}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb}, + {"llc line buffer", DUMP_FP_FMT, llc.line_buffer}, + }; + __dump(dump, ARRAY_SIZE(dump), d->sid); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static unsigned long __calculate(struct vidc_bus_vote_data *d) +{ + unsigned long value = 0; + + switch (d->domain) { + case HAL_VIDEO_DOMAIN_VPE: + value = __calculate_vpe(d); + break; + case HAL_VIDEO_DOMAIN_ENCODER: + value = __calculate_encoder(d); + break; + case HAL_VIDEO_DOMAIN_DECODER: + value = __calculate_decoder(d); + break; + case HAL_VIDEO_DOMAIN_CVP: + value = __calculate_cvp(d); + break; + default: + s_vpr_e(d->sid, "Unknown Domain %#x", d->domain); + } + + return value; +} + +int calc_bw_iris2(struct vidc_bus_vote_data *vidc_data) +{ + int ret = 0; + + if (!vidc_data) + return ret; + + ret = __calculate(vidc_data); + + return ret; +} diff --git a/techpack/video/msm/vidc/msm_vidc_clocks.c b/techpack/video/msm/vidc/msm_vidc_clocks.c new file mode 100644 index 0000000000000000000000000000000000000000..5fdfe530d608df7745b2e44dfe330944c278929e --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_clocks.c @@ -0,0 +1,1836 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include "msm_vidc_common.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" +#include "msm_vidc_buffer_calculations.h" +#include "msm_vidc_bus.h" + +#define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR (1 << 16) +#define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR (4 << 16) + +#define MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO (1 << 16) +#define MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO (5 << 16) + +#define MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS 1000 + +static int msm_vidc_decide_work_mode_ar50(struct msm_vidc_inst *inst); +static unsigned long msm_vidc_calc_freq_ar50(struct msm_vidc_inst *inst, + u32 filled_len); +static unsigned long msm_vidc_calc_freq_iris1(struct msm_vidc_inst *inst, + u32 filled_len); +static unsigned long msm_vidc_calc_freq_iris2(struct msm_vidc_inst *inst, + u32 filled_len); + +struct msm_vidc_core_ops core_ops_ar50 = { + .calc_freq = msm_vidc_calc_freq_ar50, + .decide_work_route = NULL, + .decide_work_mode = msm_vidc_decide_work_mode_ar50, + .decide_core_and_power_mode = NULL, + .calc_bw = NULL, +}; + +struct msm_vidc_core_ops core_ops_ar50lt = { + .calc_freq = msm_vidc_calc_freq_ar50, + .decide_work_route = NULL, + .decide_work_mode = msm_vidc_decide_work_mode_ar50, + .decide_core_and_power_mode = + msm_vidc_decide_core_and_power_mode_ar50lt, + .calc_bw = calc_bw_ar50lt, +}; + +struct msm_vidc_core_ops core_ops_iris1 = { + .calc_freq = msm_vidc_calc_freq_iris1, + .decide_work_route = msm_vidc_decide_work_route_iris1, + .decide_work_mode = msm_vidc_decide_work_mode_iris1, + .decide_core_and_power_mode = msm_vidc_decide_core_and_power_mode_iris1, + .calc_bw = calc_bw_iris1, +}; + +struct msm_vidc_core_ops core_ops_iris2 = { + .calc_freq = msm_vidc_calc_freq_iris2, + .decide_work_route = msm_vidc_decide_work_route_iris2, + .decide_work_mode = msm_vidc_decide_work_mode_iris2, + .decide_core_and_power_mode = msm_vidc_decide_core_and_power_mode_iris2, + .calc_bw = calc_bw_iris2, +}; + +static inline unsigned long get_ubwc_compression_ratio( + struct ubwc_cr_stats_info_type ubwc_stats_info) +{ + unsigned long sum = 0, weighted_sum = 0; + unsigned long compression_ratio = 0; + + weighted_sum = + 32 * ubwc_stats_info.cr_stats_info0 + + 64 * ubwc_stats_info.cr_stats_info1 + + 96 * ubwc_stats_info.cr_stats_info2 + + 128 * ubwc_stats_info.cr_stats_info3 + + 160 * ubwc_stats_info.cr_stats_info4 + + 192 * ubwc_stats_info.cr_stats_info5 + + 256 * ubwc_stats_info.cr_stats_info6; + + sum = + ubwc_stats_info.cr_stats_info0 + + ubwc_stats_info.cr_stats_info1 + + ubwc_stats_info.cr_stats_info2 + + ubwc_stats_info.cr_stats_info3 + + ubwc_stats_info.cr_stats_info4 + + ubwc_stats_info.cr_stats_info5 + + ubwc_stats_info.cr_stats_info6; + + compression_ratio = (weighted_sum && sum) ? + ((256 * sum) << 16) / weighted_sum : compression_ratio; + + return compression_ratio; +} + +bool res_is_less_than(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs < NUM_MBS_PER_FRAME(ref_height, ref_width) && + width < max_side && + height < max_side) + return true; + else + return false; +} + +bool res_is_greater_than(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs > NUM_MBS_PER_FRAME(ref_height, ref_width) || + width > max_side || + height > max_side) + return true; + else + return false; +} + +bool res_is_greater_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs >= NUM_MBS_PER_FRAME(ref_height, ref_width) || + width >= max_side || + height >= max_side) + return true; + else + return false; +} + +bool res_is_less_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs <= NUM_MBS_PER_FRAME(ref_height, ref_width) || + width <= max_side || + height <= max_side) + return true; + else + return false; +} + +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst) +{ + int height, width; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + + out_f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + inp_f = &inst->fmts[INPUT_PORT].v4l2_fmt; + height = max(out_f->fmt.pix_mp.height, + inp_f->fmt.pix_mp.height); + width = max(out_f->fmt.pix_mp.width, + inp_f->fmt.pix_mp.width); + + return NUM_MBS_PER_FRAME(height, width); +} + +int msm_vidc_get_fps(struct msm_vidc_inst *inst) +{ + int fps; + + if (inst->clk_data.operating_rate > inst->clk_data.frame_rate) + fps = (inst->clk_data.operating_rate >> 16) ? + (inst->clk_data.operating_rate >> 16) : 1; + else + fps = inst->clk_data.frame_rate >> 16; + + return fps; +} + +static inline bool is_active_session(u64 prev, u64 curr) +{ + u64 ts_delta; + + if (!prev || !curr) + return true; + + ts_delta = (prev < curr) ? curr - prev : prev - curr; + + return ((ts_delta / NSEC_PER_MSEC) <= + MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS); +} + +void update_recon_stats(struct msm_vidc_inst *inst, + struct recon_stats_type *recon_stats) +{ + struct v4l2_ctrl *ctrl; + struct recon_buf *binfo; + u32 CR = 0, CF = 0; + u32 frame_size; + + /* do not consider recon stats in case of superframe */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + return; + + CR = get_ubwc_compression_ratio(recon_stats->ubwc_stats_info); + + frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2; + + if (frame_size) + CF = recon_stats->complexity_number / frame_size; + else + CF = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR; + mutex_lock(&inst->refbufs.lock); + list_for_each_entry(binfo, &inst->refbufs.list, list) { + if (binfo->buffer_index == + recon_stats->buffer_index) { + binfo->CR = CR; + binfo->CF = CF; + break; + } + } + mutex_unlock(&inst->refbufs.lock); +} + +static int fill_dynamic_stats(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vote_data) +{ + struct recon_buf *binfo, *nextb; + struct vidc_input_cr_data *temp, *next; + u32 max_cr = MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO; + u32 max_cf = MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR; + u32 max_input_cr = MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO; + u32 min_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR; + u32 min_input_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO; + u32 min_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO; + + mutex_lock(&inst->refbufs.lock); + list_for_each_entry_safe(binfo, nextb, &inst->refbufs.list, list) { + if (binfo->CR) { + min_cr = min(min_cr, binfo->CR); + max_cr = max(max_cr, binfo->CR); + } + if (binfo->CF) { + min_cf = min(min_cf, binfo->CF); + max_cf = max(max_cf, binfo->CF); + } + } + mutex_unlock(&inst->refbufs.lock); + + mutex_lock(&inst->input_crs.lock); + list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) { + min_input_cr = min(min_input_cr, temp->input_cr); + max_input_cr = max(max_input_cr, temp->input_cr); + } + mutex_unlock(&inst->input_crs.lock); + + /* Sanitize CF values from HW . */ + max_cf = min_t(u32, max_cf, MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR); + min_cf = max_t(u32, min_cf, MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR); + max_cr = min_t(u32, max_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO); + min_cr = max_t(u32, min_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO); + max_input_cr = min_t(u32, + max_input_cr, MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO); + min_input_cr = max_t(u32, + min_input_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO); + + vote_data->compression_ratio = min_cr; + vote_data->complexity_factor = max_cf; + vote_data->input_cr = min_input_cr; + + s_vpr_p(inst->sid, + "Input CR = %d Recon CR = %d Complexity Factor = %d\n", + vote_data->input_cr, vote_data->compression_ratio, + vote_data->complexity_factor); + + return 0; +} + +int msm_comm_set_buses(struct msm_vidc_core *core, u32 sid) +{ + int rc = 0; + struct msm_vidc_inst *inst = NULL; + struct hfi_device *hdev; + unsigned long total_bw_ddr = 0, total_bw_llcc = 0; + u64 curr_time_ns; + + if (!core || !core->device) { + s_vpr_e(sid, "%s: Invalid args: %pK\n", __func__, core); + return -EINVAL; + } + hdev = core->device; + curr_time_ns = ktime_get_ns(); + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + struct msm_vidc_buffer *temp, *next; + u32 filled_len = 0; + u32 device_addr = 0; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, next, + &inst->registeredbufs.list, list) { + if (temp->vvb.vb2_buf.type == INPUT_MPLANE) { + filled_len = max(filled_len, + temp->vvb.vb2_buf.planes[0].bytesused); + device_addr = temp->smem[0].device_addr; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + if ((!filled_len || !device_addr) && + (inst->session_type != MSM_VIDC_CVP)) { + s_vpr_l(sid, "%s: no input\n", __func__); + continue; + } + + /* skip inactive session bus bandwidth */ + if (!is_active_session(inst->last_qbuf_time_ns, curr_time_ns)) { + inst->active = false; + continue; + } + + if (inst->bus_data.power_mode == VIDC_POWER_TURBO) { + total_bw_ddr = total_bw_llcc = INT_MAX; + break; + } + total_bw_ddr += inst->bus_data.calc_bw_ddr; + total_bw_llcc += inst->bus_data.calc_bw_llcc; + } + mutex_unlock(&core->lock); + + rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data, + total_bw_ddr, total_bw_llcc, sid); + + return rc; +} + +int msm_comm_vote_bus(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct vidc_bus_vote_data *vote_data = NULL; + bool is_turbo = false; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + struct msm_vidc_buffer *temp, *next; + u32 filled_len = 0; + u32 device_addr = 0; + int codec = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: Invalid args: %pK\n", __func__, inst); + return -EINVAL; + } + core = inst->core; + vote_data = &inst->bus_data; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, next, + &inst->registeredbufs.list, list) { + if (temp->vvb.vb2_buf.type == INPUT_MPLANE) { + filled_len = max(filled_len, + temp->vvb.vb2_buf.planes[0].bytesused); + device_addr = temp->smem[0].device_addr; + } + if (inst->session_type == MSM_VIDC_ENCODER && + (temp->vvb.flags & V4L2_BUF_FLAG_PERF_MODE)) { + is_turbo = true; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + if ((!filled_len || !device_addr) && + (inst->session_type != MSM_VIDC_CVP)) { + s_vpr_l(inst->sid, "%s: no input\n", __func__); + return 0; + } + + vote_data->sid = inst->sid; + vote_data->domain = get_hal_domain(inst->session_type, inst->sid); + vote_data->power_mode = 0; + if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW && + inst->session_type != MSM_VIDC_CVP) + vote_data->power_mode = VIDC_POWER_TURBO; + if (msm_vidc_clock_voting || is_turbo || is_turbo_session(inst)) + vote_data->power_mode = VIDC_POWER_TURBO; + + if (inst->session_type == MSM_VIDC_CVP) { + vote_data->calc_bw_ddr= inst->clk_data.ddr_bw; + vote_data->calc_bw_llcc= inst->clk_data.sys_cache_bw; + } else if (vote_data->power_mode != VIDC_POWER_TURBO) { + out_f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + inp_f = &inst->fmts[INPUT_PORT].v4l2_fmt; + switch (inst->session_type) { + case MSM_VIDC_DECODER: + codec = inp_f->fmt.pix_mp.pixelformat; + break; + case MSM_VIDC_ENCODER: + codec = out_f->fmt.pix_mp.pixelformat; + break; + case MSM_VIDC_CVP: + codec = V4L2_PIX_FMT_CVP; + break; + default: + s_vpr_e(inst->sid, "%s: invalid session_type %#x\n", + __func__, inst->session_type); + break; + } + + vote_data->codec = get_hal_codec(codec, inst->sid); + vote_data->input_width = inp_f->fmt.pix_mp.width; + vote_data->input_height = inp_f->fmt.pix_mp.height; + vote_data->output_width = out_f->fmt.pix_mp.width; + vote_data->output_height = out_f->fmt.pix_mp.height; + vote_data->lcu_size = (codec == V4L2_PIX_FMT_HEVC || + codec == V4L2_PIX_FMT_VP9) ? 32 : 16; + + vote_data->fps = msm_vidc_get_fps(inst); + if (inst->session_type == MSM_VIDC_ENCODER) { + vote_data->bitrate = inst->clk_data.bitrate; + vote_data->rotation = + msm_comm_g_ctrl_for_id(inst, V4L2_CID_ROTATE); + vote_data->b_frames_enabled = + msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_B_FRAMES) != 0; + /* scale bitrate if operating rate is larger than fps */ + if (vote_data->fps > (inst->clk_data.frame_rate >> 16) + && (inst->clk_data.frame_rate >> 16)) { + vote_data->bitrate = vote_data->bitrate / + (inst->clk_data.frame_rate >> 16) * + vote_data->fps; + } + } else if (inst->session_type == MSM_VIDC_DECODER) { + vote_data->bitrate = + filled_len * vote_data->fps * 8; + } + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_PRIMARY) { + vote_data->color_formats[0] = + msm_comm_get_hal_uncompressed( + inst->clk_data.opb_fourcc); + vote_data->num_formats = 1; + } else { + vote_data->color_formats[0] = + msm_comm_get_hal_uncompressed( + inst->clk_data.dpb_fourcc); + vote_data->color_formats[1] = + msm_comm_get_hal_uncompressed( + inst->clk_data.opb_fourcc); + vote_data->num_formats = 2; + } + vote_data->work_mode = inst->clk_data.work_mode; + fill_dynamic_stats(inst, vote_data); + + if (core->resources.sys_cache_res_set) + vote_data->use_sys_cache = true; + + call_core_op(core, calc_bw, vote_data); + } + + rc = msm_comm_set_buses(core, inst->sid); + + return rc; +} + +static int msm_dcvs_scale_clocks(struct msm_vidc_inst *inst, + unsigned long freq) +{ + int rc = 0; + int bufs_with_fw = 0; + struct msm_vidc_format *fmt; + struct clock_data *dcvs; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + if (!inst->clk_data.dcvs_mode || inst->batch.enable) { + s_vpr_l(inst->sid, "Skip DCVS (dcvs %d, batching %d)\n", + inst->clk_data.dcvs_mode, inst->batch.enable); + inst->clk_data.dcvs_flags = 0; + return 0; + } + + dcvs = &inst->clk_data; + + if (is_decode_session(inst)) { + bufs_with_fw = msm_comm_num_queued_bufs(inst, OUTPUT_MPLANE); + fmt = &inst->fmts[OUTPUT_PORT]; + } else { + bufs_with_fw = msm_comm_num_queued_bufs(inst, INPUT_MPLANE); + fmt = &inst->fmts[INPUT_PORT]; + } + + /* +1 as one buffer is going to be queued after the function */ + bufs_with_fw += 1; + + /* + * DCVS decides clock level based on below algo + + * Limits : + * min_threshold : Buffers required for reference by FW. + * nom_threshold : Midpoint of Min and Max thresholds + * max_threshold : Min Threshold + DCVS extra buffers, allocated + * for smooth flow. + * 1) When buffers outside FW are reaching client's extra buffers, + * FW is slow and will impact pipeline, Increase clock. + * 2) When pending buffers with FW are less than FW requested, + * pipeline has cushion to absorb FW slowness, Decrease clocks. + * 3) When DCVS has engaged(Inc or Dec) and pending buffers with FW + * transitions past the nom_threshold, switch to calculated load. + * This smoothens the clock transitions. + * 4) Otherwise maintain previous Load config. + */ + + if (bufs_with_fw >= dcvs->max_threshold) { + dcvs->dcvs_flags = MSM_VIDC_DCVS_INCR; + } else if (bufs_with_fw < dcvs->min_threshold) { + dcvs->dcvs_flags = MSM_VIDC_DCVS_DECR; + } else if ((dcvs->dcvs_flags & MSM_VIDC_DCVS_DECR && + bufs_with_fw >= dcvs->nom_threshold) || + (dcvs->dcvs_flags & MSM_VIDC_DCVS_INCR && + bufs_with_fw <= dcvs->nom_threshold)) + dcvs->dcvs_flags = 0; + + s_vpr_p(inst->sid, "DCVS: bufs_with_fw %d Th[%d %d %d] Flag %#x\n", + bufs_with_fw, dcvs->min_threshold, + dcvs->nom_threshold, dcvs->max_threshold, + dcvs->dcvs_flags); + + return rc; +} + +static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core, u32 sid) +{ + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + unsigned long freq = 0; + + allowed_clks_tbl = core->resources.allowed_clks_tbl; + freq = allowed_clks_tbl[0].clock_rate; + s_vpr_l(sid, "Max rate = %lu\n", freq); + return freq; +} + +void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst) +{ + struct vidc_input_cr_data *temp, *next; + + mutex_lock(&inst->input_crs.lock); + list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) { + list_del(&temp->list); + kfree(temp); + } + INIT_LIST_HEAD(&inst->input_crs.list); + mutex_unlock(&inst->input_crs.lock); +} + +void msm_comm_update_input_cr(struct msm_vidc_inst *inst, + u32 index, u32 cr) +{ + struct vidc_input_cr_data *temp, *next; + bool found = false; + + mutex_lock(&inst->input_crs.lock); + list_for_each_entry_safe(temp, next, &inst->input_crs.list, list) { + if (temp->index == index) { + temp->input_cr = cr; + found = true; + break; + } + } + + if (!found) { + temp = kzalloc(sizeof(*temp), GFP_KERNEL); + if (!temp) { + s_vpr_e(inst->sid, "%s: malloc failure.\n", __func__); + goto exit; + } + temp->index = index; + temp->input_cr = cr; + list_add_tail(&temp->list, &inst->input_crs.list); + } +exit: + mutex_unlock(&inst->input_crs.lock); +} + +static unsigned long msm_vidc_calc_freq_ar50(struct msm_vidc_inst *inst, + u32 filled_len) +{ + u64 freq = 0, vpp_cycles = 0, vsp_cycles = 0; + u64 fw_cycles = 0, fw_vpp_cycles = 0; + u32 vpp_cycles_per_mb; + u32 mbs_per_second; + struct msm_vidc_core *core = NULL; + int i = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + u64 rate = 0, fps; + struct clock_data *dcvs = NULL; + + core = inst->core; + dcvs = &inst->clk_data; + + mbs_per_second = msm_comm_get_inst_load_per_core(inst, + LOAD_POWER); + + fps = msm_vidc_get_fps(inst); + + /* + * Calculate vpp, vsp cycles separately for encoder and decoder. + * Even though, most part is common now, in future it may change + * between them. + */ + + fw_cycles = fps * inst->core->resources.fw_cycles; + fw_vpp_cycles = fps * inst->core->resources.fw_vpp_cycles; + + if (inst->session_type == MSM_VIDC_ENCODER) { + vpp_cycles_per_mb = inst->flags & VIDC_LOW_POWER ? + inst->clk_data.entry->low_power_cycles : + inst->clk_data.entry->vpp_cycles; + + vpp_cycles = mbs_per_second * vpp_cycles_per_mb; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles; + + /* 10 / 7 is overhead factor */ + vsp_cycles += (inst->clk_data.bitrate * 10) / 7; + } else if (inst->session_type == MSM_VIDC_DECODER) { + vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles; + /* 10 / 7 is overhead factor */ + vsp_cycles += div_u64((fps * filled_len * 8 * 10), 7); + + } else { + s_vpr_e(inst->sid, "%s: Unknown session type\n", __func__); + return msm_vidc_max_freq(inst->core, inst->sid); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + s_vpr_l(inst->sid, "Update DCVS Load\n"); + allowed_clks_tbl = core->resources.allowed_clks_tbl; + for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) { + rate = allowed_clks_tbl[i].clock_rate; + if (rate >= freq) + break; + } + + if (i < 0) + i = 0; + + s_vpr_p(inst->sid, "%s: Inst %pK : Filled Len = %d Freq = %llu\n", + __func__, inst, filled_len, freq); + + return (unsigned long) freq; +} + +static unsigned long msm_vidc_calc_freq_iris1(struct msm_vidc_inst *inst, + u32 filled_len) +{ + u64 vsp_cycles = 0, vpp_cycles = 0, fw_cycles = 0, freq = 0; + u64 fw_vpp_cycles = 0; + u32 vpp_cycles_per_mb; + u32 mbs_per_second; + struct msm_vidc_core *core = NULL; + int i = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + u64 rate = 0, fps; + struct clock_data *dcvs = NULL; + u32 operating_rate, vsp_factor_num = 10, vsp_factor_den = 5; + + core = inst->core; + dcvs = &inst->clk_data; + + mbs_per_second = msm_comm_get_inst_load_per_core(inst, + LOAD_POWER); + + fps = msm_vidc_get_fps(inst); + + /* + * Calculate vpp, vsp, fw cycles separately for encoder and decoder. + * Even though, most part is common now, in future it may change + * between them. + */ + + fw_cycles = fps * inst->core->resources.fw_cycles; + fw_vpp_cycles = fps * inst->core->resources.fw_vpp_cycles; + + if (inst->session_type == MSM_VIDC_ENCODER) { + vpp_cycles_per_mb = inst->flags & VIDC_LOW_POWER ? + inst->clk_data.entry->low_power_cycles : + inst->clk_data.entry->vpp_cycles; + + vpp_cycles = mbs_per_second * vpp_cycles_per_mb / + inst->clk_data.work_route; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles; + + /* bitrate is based on fps, scale it using operating rate */ + operating_rate = inst->clk_data.operating_rate >> 16; + if (operating_rate > (inst->clk_data.frame_rate >> 16) && + (inst->clk_data.frame_rate >> 16)) { + vsp_factor_num *= operating_rate; + vsp_factor_den *= inst->clk_data.frame_rate >> 16; + } + vsp_cycles += div_u64(((u64)inst->clk_data.bitrate * + vsp_factor_num), vsp_factor_den); + + } else if (inst->session_type == MSM_VIDC_DECODER) { + vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles / + inst->clk_data.work_route; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles; + + /* vsp perf is about 0.5 bits/cycle */ + vsp_cycles += div_u64((fps * filled_len * 8 * 10), 5); + + } else { + s_vpr_e(inst->sid, "%s: Unknown session type\n", __func__); + return msm_vidc_max_freq(inst->core, inst->sid); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + allowed_clks_tbl = core->resources.allowed_clks_tbl; + for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) { + rate = allowed_clks_tbl[i].clock_rate; + if (rate >= freq) + break; + } + + if (i < 0) + i = 0; + + s_vpr_p(inst->sid, "%s: inst %pK: filled len %d required freq %llu\n", + __func__, inst, filled_len, freq); + + return (unsigned long) freq; +} + +static unsigned long msm_vidc_calc_freq_iris2(struct msm_vidc_inst *inst, + u32 filled_len) +{ + u64 vsp_cycles = 0, vpp_cycles = 0, fw_cycles = 0, freq = 0; + u64 fw_vpp_cycles = 0; + u32 vpp_cycles_per_mb; + u32 mbs_per_second; + struct msm_vidc_core *core = NULL; + u32 fps; + struct clock_data *dcvs = NULL; + u32 operating_rate, vsp_factor_num = 1, vsp_factor_den = 1; + u32 base_cycles = 0; + u32 codec = 0; + + core = inst->core; + dcvs = &inst->clk_data; + + mbs_per_second = msm_comm_get_inst_load_per_core(inst, + LOAD_POWER); + + fps = msm_vidc_get_fps(inst); + + /* + * Calculate vpp, vsp, fw cycles separately for encoder and decoder. + * Even though, most part is common now, in future it may change + * between them. + */ + + fw_cycles = fps * inst->core->resources.fw_cycles; + fw_vpp_cycles = fps * inst->core->resources.fw_vpp_cycles; + + if (inst->session_type == MSM_VIDC_ENCODER) { + vpp_cycles_per_mb = inst->flags & VIDC_LOW_POWER ? + inst->clk_data.entry->low_power_cycles : + inst->clk_data.entry->vpp_cycles; + + vpp_cycles = mbs_per_second * vpp_cycles_per_mb / + inst->clk_data.work_route; + /* 1.25 factor for IbP GOP structure */ + if (msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDEO_B_FRAMES)) + vpp_cycles += vpp_cycles / 4; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + /* 1.01 is multi-pipe overhead */ + if (inst->clk_data.work_route > 1) + vpp_cycles += div_u64(vpp_cycles, 100); + /* + * 1080p@480fps usecase needs exactly 338MHz + * without any margin left. Hence, adding 2 percent + * extra to bump it to next level (366MHz). + */ + if (fps == 480) + vpp_cycles += div_u64(vpp_cycles * 2, 100); + + /* VSP */ + /* bitrate is based on fps, scale it using operating rate */ + operating_rate = inst->clk_data.operating_rate >> 16; + if (operating_rate > (inst->clk_data.frame_rate >> 16) && + (inst->clk_data.frame_rate >> 16)) { + vsp_factor_num = operating_rate; + vsp_factor_den = inst->clk_data.frame_rate >> 16; + } + vsp_cycles = div_u64(((u64)inst->clk_data.bitrate * + vsp_factor_num), vsp_factor_den); + + codec = get_v4l2_codec(inst); + base_cycles = inst->clk_data.entry->vsp_cycles; + if (codec == V4L2_PIX_FMT_VP8 || codec == V4L2_PIX_FMT_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->entropy_mode == HFI_H264_ENTROPY_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + /* VSP FW Overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + } + + if (inst->clk_data.work_mode == HFI_WORKMODE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + } else if (inst->session_type == MSM_VIDC_DECODER) { + /* VPP */ + vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles / + inst->clk_data.work_route; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + /* 1.059 is multi-pipe overhead */ + if (inst->clk_data.work_route > 1) + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + + /* VSP */ + codec = get_v4l2_codec(inst); + base_cycles = inst->clk_data.entry->vsp_cycles; + vsp_cycles = fps * filled_len * 8; + + if (codec == V4L2_PIX_FMT_VP8 || codec == V4L2_PIX_FMT_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->entropy_mode == HFI_H264_ENTROPY_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + /* VSP FW Overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + } + + if (inst->clk_data.work_mode == HFI_WORKMODE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + } else { + s_vpr_e(inst->sid, "%s: Unknown session type\n", __func__); + return msm_vidc_max_freq(inst->core, inst->sid); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + s_vpr_p(inst->sid, "%s: inst %pK: filled len %d required freq %llu\n", + __func__, inst, filled_len, freq); + + return (unsigned long) freq; +} + +int msm_vidc_set_clocks(struct msm_vidc_core *core, u32 sid) +{ + struct hfi_device *hdev; + unsigned long freq_core_1 = 0, freq_core_2 = 0, rate = 0; + unsigned long freq_core_max = 0; + struct msm_vidc_inst *inst = NULL; + struct msm_vidc_buffer *temp, *next; + u32 device_addr, filled_len; + int rc = 0, i = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + bool increment, decrement; + u64 curr_time_ns; + + hdev = core->device; + curr_time_ns = ktime_get_ns(); + allowed_clks_tbl = core->resources.allowed_clks_tbl; + if (!allowed_clks_tbl) { + s_vpr_e(sid, "%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + mutex_lock(&core->lock); + increment = false; + decrement = true; + list_for_each_entry(inst, &core->instances, list) { + device_addr = 0; + filled_len = 0; + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, next, + &inst->registeredbufs.list, list) { + if (temp->vvb.vb2_buf.type == INPUT_MPLANE) { + filled_len = max(filled_len, + temp->vvb.vb2_buf.planes[0].bytesused); + device_addr = temp->smem[0].device_addr; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + if (!filled_len || !device_addr) { + s_vpr_l(sid, "%s: no input\n", __func__); + continue; + } + + /* skip inactive session clock rate */ + if (!is_active_session(inst->last_qbuf_time_ns, curr_time_ns)) { + inst->active = false; + continue; + } + + if (inst->clk_data.core_id == VIDC_CORE_ID_1) + freq_core_1 += inst->clk_data.min_freq; + else if (inst->clk_data.core_id == VIDC_CORE_ID_2) + freq_core_2 += inst->clk_data.min_freq; + else if (inst->clk_data.core_id == VIDC_CORE_ID_3) { + freq_core_1 += inst->clk_data.min_freq; + freq_core_2 += inst->clk_data.min_freq; + } + + freq_core_max = max_t(unsigned long, freq_core_1, freq_core_2); + + if (msm_vidc_clock_voting) { + s_vpr_l(sid, "msm_vidc_clock_voting %d\n", + msm_vidc_clock_voting); + freq_core_max = msm_vidc_clock_voting; + decrement = false; + break; + } + + /* increment even if one session requested for it */ + if (inst->clk_data.dcvs_flags & MSM_VIDC_DCVS_INCR) + increment = true; + /* decrement only if all sessions requested for it */ + if (!(inst->clk_data.dcvs_flags & MSM_VIDC_DCVS_DECR)) + decrement = false; + } + + /* + * keep checking from lowest to highest rate until + * table rate >= requested rate + */ + for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) { + rate = allowed_clks_tbl[i].clock_rate; + if (rate >= freq_core_max) + break; + } + + if (i < 0) + i = 0; + + if (increment) { + if (i > 0) + rate = allowed_clks_tbl[i-1].clock_rate; + } else if (decrement) { + if (i < (int) (core->resources.allowed_clks_tbl_size - 1)) + rate = allowed_clks_tbl[i+1].clock_rate; + } + + core->min_freq = freq_core_max; + core->curr_freq = rate; + mutex_unlock(&core->lock); + + s_vpr_p(sid, + "%s: clock rate %lu requested %lu increment %d decrement %d\n", + __func__, core->curr_freq, core->min_freq, + increment, decrement); + rc = call_hfi_op(hdev, scale_clocks, + hdev->hfi_device_data, core->curr_freq, sid); + + return rc; +} + +int msm_comm_scale_clocks(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffer *temp, *next; + unsigned long freq = 0; + u32 filled_len = 0; + u32 device_addr = 0; + bool is_turbo = false; + + if (!inst || !inst->core) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", __func__, inst); + return -EINVAL; + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, next, &inst->registeredbufs.list, list) { + if (temp->vvb.vb2_buf.type == INPUT_MPLANE) { + filled_len = max(filled_len, + temp->vvb.vb2_buf.planes[0].bytesused); + if (temp->vvb.flags & V4L2_BUF_FLAG_PERF_MODE) + is_turbo = true; + device_addr = temp->smem[0].device_addr; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + if (!filled_len || !device_addr) { + s_vpr_l(inst->sid, "%s: no input\n", __func__); + return 0; + } + + if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW || is_turbo || + is_turbo_session(inst)) { + inst->clk_data.min_freq = + msm_vidc_max_freq(inst->core, inst->sid); + inst->clk_data.dcvs_flags = 0; + } else if (msm_vidc_clock_voting) { + inst->clk_data.min_freq = msm_vidc_clock_voting; + inst->clk_data.dcvs_flags = 0; + } else { + freq = call_core_op(inst->core, calc_freq, inst, filled_len); + inst->clk_data.min_freq = freq; + msm_dcvs_scale_clocks(inst, freq); + } + + msm_vidc_set_clocks(inst->core, inst->sid); + + return 0; +} + +int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst, bool do_bw_calc) +{ + struct msm_vidc_core *core; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + core = inst->core; + hdev = core->device; + + if (!inst->active) { + /* do not skip bw voting for inactive -> active session */ + do_bw_calc = true; + inst->active = true; + } + + if (msm_comm_scale_clocks(inst)) { + s_vpr_e(inst->sid, + "Failed to scale clocks. May impact performance\n"); + } + + if (do_bw_calc) { + if (msm_comm_vote_bus(inst)) { + s_vpr_e(inst->sid, + "Failed to scale DDR bus. May impact perf\n"); + } + } + + return 0; +} + +int msm_dcvs_try_enable(struct msm_vidc_inst *inst) +{ + bool disable_hfr_dcvs = false; + + if (!inst || !inst->core) { + d_vpr_e("%s: Invalid args: %pK\n", __func__, inst); + return -EINVAL; + } + if (inst->core->platform_data->vpu_ver == VPU_VERSION_IRIS2_1) { + /* 720p@240 encode */ + if (is_encode_session(inst) && msm_vidc_get_fps(inst) >= 240 + && msm_vidc_get_mbs_per_frame(inst) >= 3600) + disable_hfr_dcvs = true; + } + + inst->clk_data.dcvs_mode = + !(msm_vidc_clock_voting || + !inst->core->resources.dcvs || + inst->flags & VIDC_THUMBNAIL || + is_low_latency_hint(inst) || + inst->clk_data.low_latency_mode || + inst->batch.enable || + is_turbo_session(inst) || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ || + disable_hfr_dcvs); + + s_vpr_hp(inst->sid, "DCVS %s: %pK\n", + inst->clk_data.dcvs_mode ? "enabled" : "disabled", inst); + + return 0; +} + +void msm_dcvs_reset(struct msm_vidc_inst *inst) +{ + struct msm_vidc_format *fmt; + struct clock_data *dcvs; + + if (!inst) { + d_vpr_e("%s: Invalid params\n", __func__); + return; + } + + dcvs = &inst->clk_data; + if (inst->session_type == MSM_VIDC_ENCODER) { + fmt = &inst->fmts[INPUT_PORT]; + } else if (inst->session_type == MSM_VIDC_DECODER) { + fmt = &inst->fmts[OUTPUT_PORT]; + } else { + s_vpr_e(inst->sid, "%s: invalid session type %#x\n", + __func__, inst->session_type); + return; + } + + dcvs->min_threshold = fmt->count_min; + dcvs->max_threshold = + min((fmt->count_min + DCVS_DEC_EXTRA_OUTPUT_BUFFERS), + fmt->count_actual); + + dcvs->dcvs_window = + dcvs->max_threshold < dcvs->min_threshold ? 0 : + dcvs->max_threshold - dcvs->min_threshold; + dcvs->nom_threshold = dcvs->min_threshold + + (dcvs->dcvs_window ? + (dcvs->dcvs_window / 2) : 0); +} + +int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst) +{ + int rc = 0, j = 0; + int fourcc, count; + + if (!inst || !inst->core) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_CVP) { + s_vpr_l(inst->sid, "%s: cvp session\n", __func__); + return 0; + } + + count = inst->core->resources.codec_data_count; + fourcc = get_v4l2_codec(inst); + + for (j = 0; j < count; j++) { + if (inst->core->resources.codec_data[j].session_type == + inst->session_type && + inst->core->resources.codec_data[j].fourcc == + fourcc) { + inst->clk_data.entry = + &inst->core->resources.codec_data[j]; + break; + } + } + + if (!inst->clk_data.entry) { + s_vpr_e(inst->sid, "%s: No match found\n", __func__); + rc = -EINVAL; + } + + return rc; +} + +void msm_clock_data_reset(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + int i = 0, rc = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + u64 total_freq = 0, rate = 0, load; + int cycles; + + if (!inst || !inst->core || !inst->clk_data.entry) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return; + } + s_vpr_h(inst->sid, "Init DCVS Load\n"); + + core = inst->core; + load = msm_comm_get_inst_load_per_core(inst, LOAD_POWER); + cycles = inst->clk_data.entry->vpp_cycles; + allowed_clks_tbl = core->resources.allowed_clks_tbl; + if (inst->session_type == MSM_VIDC_ENCODER && + inst->flags & VIDC_LOW_POWER) + cycles = inst->clk_data.entry->low_power_cycles; + + msm_dcvs_reset(inst); + + total_freq = cycles * load; + + for (i = core->resources.allowed_clks_tbl_size - 1; i >= 0; i--) { + rate = allowed_clks_tbl[i].clock_rate; + if (rate >= total_freq) + break; + } + + if (i < 0) + i = 0; + + inst->clk_data.buffer_counter = 0; + + rc = msm_comm_scale_clocks_and_bus(inst, 1); + + if (rc) + s_vpr_e(inst->sid, "%s: Failed to scale Clocks and Bus\n", + __func__); +} + +int msm_vidc_decide_work_route_iris1(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_video_work_route pdata; + struct v4l2_format *f; + u32 codec; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + + pdata.video_work_route = 2; + codec = get_v4l2_codec(inst); + if (inst->session_type == MSM_VIDC_DECODER) { + switch (codec) { + case V4L2_PIX_FMT_MPEG2: + pdata.video_work_route = 1; + break; + case V4L2_PIX_FMT_H264: + if (inst->pic_struct != + MSM_VIDC_PIC_STRUCT_PROGRESSIVE) + pdata.video_work_route = 1; + break; + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + u32 slice_mode = 0; + u32 output_width, output_height, fps, mbps; + + switch (codec) { + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_TME: + pdata.video_work_route = 1; + goto decision_done; + } + + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) { + pdata.video_work_route = 2; + goto decision_done; + } + slice_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_height = f->fmt.pix_mp.height; + output_width = f->fmt.pix_mp.width; + fps = inst->clk_data.frame_rate >> 16; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); + if (slice_mode == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES || + (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps <= CBR_MB_LIMIT) || + (inst->rc_type == + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR && + mbps <= CBR_VFR_MB_LIMIT)) { + pdata.video_work_route = 1; + s_vpr_h(inst->sid, "Configured work route = 1"); + } + } else { + return -EINVAL; + } + +decision_done: + + inst->clk_data.work_route = pdata.video_work_route; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HFI_PROPERTY_PARAM_WORK_ROUTE, + (void *)&pdata, sizeof(pdata)); + if (rc) + s_vpr_e(inst->sid, "Failed to configure work route\n"); + + return rc; +} + +int msm_vidc_decide_work_route_iris2(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_video_work_route pdata; + bool is_legacy_cbr; + u32 codec; + uint32_t vpu; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + vpu = inst->core->platform_data->vpu_ver; + hdev = inst->core->device; + is_legacy_cbr = inst->clk_data.is_legacy_cbr; + pdata.video_work_route = 4; + + if (vpu == VPU_VERSION_IRIS2_1) { + pdata.video_work_route = 1; + goto decision_done; + } + codec = get_v4l2_codec(inst); + if (inst->session_type == MSM_VIDC_DECODER) { + if (codec == V4L2_PIX_FMT_MPEG2 || + inst->pic_struct != MSM_VIDC_PIC_STRUCT_PROGRESSIVE) + pdata.video_work_route = 1; + } else if (inst->session_type == MSM_VIDC_ENCODER) { + u32 slice_mode, width, height; + struct v4l2_format *f; + + slice_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + height = f->fmt.pix_mp.height; + width = f->fmt.pix_mp.width; + + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES || + codec == V4L2_PIX_FMT_VP8 || is_legacy_cbr) { + pdata.video_work_route = 1; + } + } else { + return -EINVAL; + } + +decision_done: + s_vpr_h(inst->sid, "Configurng work route = %u", + pdata.video_work_route); + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HFI_PROPERTY_PARAM_WORK_ROUTE, + (void *)&pdata, sizeof(pdata)); + if (rc) + s_vpr_e(inst->sid, "Failed to configure work route\n"); + else + inst->clk_data.work_route = pdata.video_work_route; + + return rc; +} + +static int msm_vidc_decide_work_mode_ar50(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_video_work_mode pdata; + struct hfi_enable latency; + struct v4l2_format *f; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + if (inst->clk_data.low_latency_mode) { + pdata.video_work_mode = HFI_WORKMODE_1; + goto decision_done; + } + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + if (inst->session_type == MSM_VIDC_DECODER) { + pdata.video_work_mode = HFI_WORKMODE_2; + switch (f->fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_MPEG2: + pdata.video_work_mode = HFI_WORKMODE_1; + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + if (f->fmt.pix_mp.height * + f->fmt.pix_mp.width <= 1280 * 720) + pdata.video_work_mode = HFI_WORKMODE_1; + break; + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + pdata.video_work_mode = HFI_WORKMODE_1; + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR || + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + pdata.video_work_mode = HFI_WORKMODE_2; + } else { + return -EINVAL; + } + +decision_done: + + inst->clk_data.work_mode = pdata.video_work_mode; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HFI_PROPERTY_PARAM_WORK_MODE, + (void *)&pdata, sizeof(pdata)); + if (rc) + s_vpr_e(inst->sid, "Failed to configure Work Mode\n"); + + /* For WORK_MODE_1, set Low Latency mode by default to HW. */ + + if (inst->session_type == MSM_VIDC_ENCODER && + inst->clk_data.work_mode == HFI_WORKMODE_1) { + latency.enable = true; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE, + (void *)&latency, sizeof(latency)); + } + + rc = msm_comm_scale_clocks_and_bus(inst, 1); + + return rc; +} + +int msm_vidc_decide_work_mode_iris1(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_video_work_mode pdata; + struct hfi_enable latency; + u32 yuv_size = 0; + struct v4l2_format *f; + u32 codec; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + + if (inst->clk_data.low_latency_mode) { + pdata.video_work_mode = HFI_WORKMODE_1; + s_vpr_h(inst->sid, "Configured work mode = 1"); + goto decision_done; + } + + codec = get_v4l2_codec(inst); + if (inst->session_type == MSM_VIDC_DECODER) { + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + pdata.video_work_mode = HFI_WORKMODE_2; + switch (codec) { + case V4L2_PIX_FMT_MPEG2: + pdata.video_work_mode = HFI_WORKMODE_1; + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_VP9: + yuv_size = f->fmt.pix_mp.height * f->fmt.pix_mp.width; + if ((inst->pic_struct != + MSM_VIDC_PIC_STRUCT_PROGRESSIVE) || + (yuv_size <= 1280 * 720)) + pdata.video_work_mode = HFI_WORKMODE_1; + break; + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + pdata.video_work_mode = HFI_WORKMODE_2; + + switch (codec) { + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_TME: + pdata.video_work_mode = HFI_WORKMODE_1; + goto decision_done; + } + + } else { + return -EINVAL; + } + +decision_done: + + inst->clk_data.work_mode = pdata.video_work_mode; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HFI_PROPERTY_PARAM_WORK_MODE, + (void *)&pdata, sizeof(pdata)); + if (rc) + s_vpr_e(inst->sid, "Failed to configure Work Mode %u\n", + pdata.video_work_mode); + + /* For WORK_MODE_1, set Low Latency mode by default to HW. */ + + if (inst->session_type == MSM_VIDC_ENCODER && + inst->clk_data.work_mode == HFI_WORKMODE_1) { + latency.enable = true; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE, + (void *)&latency, sizeof(latency)); + } + + return rc; +} + +int msm_vidc_decide_work_mode_iris2(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hfi_video_work_mode pdata; + struct hfi_enable latency; + u32 width, height; + bool res_ok = false; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + pdata.video_work_mode = HFI_WORKMODE_2; + latency.enable = inst->clk_data.low_latency_mode; + out_f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + inp_f = &inst->fmts[INPUT_PORT].v4l2_fmt; + if (inst->session_type == MSM_VIDC_DECODER) { + height = out_f->fmt.pix_mp.height; + width = out_f->fmt.pix_mp.width; + res_ok = res_is_less_than(width, height, 1280, 720); + if (inp_f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_MPEG2 || + inst->pic_struct != MSM_VIDC_PIC_STRUCT_PROGRESSIVE || + inst->clk_data.low_latency_mode || res_ok) { + pdata.video_work_mode = HFI_WORKMODE_1; + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + height = inp_f->fmt.pix_mp.height; + width = inp_f->fmt.pix_mp.width; + res_ok = !res_is_greater_than(width, height, 4096, 2160); + if (res_ok && + (out_f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_VP8 || + inst->clk_data.low_latency_mode)) { + pdata.video_work_mode = HFI_WORKMODE_1; + /* For WORK_MODE_1, set Low Latency mode by default */ + latency.enable = true; + } + if (inst->rc_type == RATE_CONTROL_LOSSLESS || inst->all_intra) { + pdata.video_work_mode = HFI_WORKMODE_2; + latency.enable = false; + } + } else { + return -EINVAL; + } + + s_vpr_h(inst->sid, "Configuring work mode = %u low latency = %u", + pdata.video_work_mode, + latency.enable); + + if (inst->session_type == MSM_VIDC_ENCODER) { + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE, + (void *)&latency, sizeof(latency)); + if (rc) + s_vpr_e(inst->sid, "Failed to configure low latency\n"); + else + inst->clk_data.low_latency_mode = latency.enable; + } + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HFI_PROPERTY_PARAM_WORK_MODE, + (void *)&pdata, sizeof(pdata)); + if (rc) + s_vpr_e(inst->sid, "Failed to configure Work Mode\n"); + else + inst->clk_data.work_mode = pdata.video_work_mode; + + return rc; +} + +static inline int msm_vidc_power_save_mode_enable(struct msm_vidc_inst *inst, + bool enable) +{ + u32 rc = 0; + u32 prop_id = 0; + void *pdata = NULL; + struct hfi_device *hdev = NULL; + u32 hfi_perf_mode; + + hdev = inst->core->device; + if (inst->session_type != MSM_VIDC_ENCODER) { + s_vpr_l(inst->sid, + "%s: Not an encoder session. Nothing to do\n", + __func__); + return 0; + } + + prop_id = HFI_PROPERTY_CONFIG_VENC_PERF_MODE; + hfi_perf_mode = enable ? HFI_VENC_PERFMODE_POWER_SAVE : + HFI_VENC_PERFMODE_MAX_QUALITY; + pdata = &hfi_perf_mode; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, prop_id, pdata, + sizeof(hfi_perf_mode)); + if (rc) { + s_vpr_e(inst->sid, "%s: Failed to set power save mode\n", + __func__, inst); + return rc; + } + inst->flags = enable ? + inst->flags | VIDC_LOW_POWER : + inst->flags & ~VIDC_LOW_POWER; + + s_vpr_h(inst->sid, + "Power Save Mode for inst: %pK Enable = %d\n", inst, enable); + + return rc; +} + +static int msm_vidc_move_core_to_power_save_mode(struct msm_vidc_core *core, + u32 core_id, u32 sid) +{ + struct msm_vidc_inst *inst = NULL; + + s_vpr_h(sid, "Core %d : Moving all inst to LP mode\n", core_id); + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->clk_data.core_id == core_id && + inst->session_type == MSM_VIDC_ENCODER) + msm_vidc_power_save_mode_enable(inst, true); + } + mutex_unlock(&core->lock); + + return 0; +} + +static u32 get_core_load(struct msm_vidc_core *core, + u32 core_id, bool lp_mode, bool real_time) +{ + struct msm_vidc_inst *inst = NULL; + u32 current_inst_mbs_per_sec = 0, load = 0; + bool real_time_mode = false; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + u32 cycles, lp_cycles; + + real_time_mode = is_realtime_session(inst); + if (!(inst->clk_data.core_id & core_id)) + continue; + if (real_time_mode != real_time) + continue; + if (inst->session_type == MSM_VIDC_DECODER) { + cycles = lp_cycles = inst->clk_data.entry->vpp_cycles; + } else if (inst->session_type == MSM_VIDC_ENCODER) { + lp_mode |= inst->flags & VIDC_LOW_POWER; + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + lp_mode = false; + + cycles = lp_mode ? + inst->clk_data.entry->low_power_cycles : + inst->clk_data.entry->vpp_cycles; + } else { + continue; + } + current_inst_mbs_per_sec = msm_comm_get_inst_load_per_core(inst, + LOAD_POWER); + load += current_inst_mbs_per_sec * cycles / + inst->clk_data.work_route; + } + mutex_unlock(&core->lock); + + return load; +} + +int msm_vidc_decide_core_and_power_mode_ar50lt(struct msm_vidc_inst *inst) +{ + inst->clk_data.core_id = VIDC_CORE_ID_1; + return 0; +} + +int msm_vidc_decide_core_and_power_mode_iris1(struct msm_vidc_inst *inst) +{ + bool enable = false; + int rc = 0; + u32 core_load = 0, core_lp_load = 0; + u32 cur_inst_load = 0, cur_inst_lp_load = 0; + u32 mbpf, mbps, max_hq_mbpf, max_hq_mbps; + unsigned long max_freq, lp_cycles = 0; + struct msm_vidc_core *core; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + core = inst->core; + max_freq = msm_vidc_max_freq(inst->core, inst->sid); + inst->clk_data.core_id = 0; + + core_load = get_core_load(core, VIDC_CORE_ID_1, false, true); + core_lp_load = get_core_load(core, VIDC_CORE_ID_1, true, true); + + lp_cycles = inst->session_type == MSM_VIDC_ENCODER ? + inst->clk_data.entry->low_power_cycles : + inst->clk_data.entry->vpp_cycles; + + cur_inst_load = (msm_comm_get_inst_load(inst, LOAD_POWER) * + inst->clk_data.entry->vpp_cycles)/inst->clk_data.work_route; + + cur_inst_lp_load = (msm_comm_get_inst_load(inst, + LOAD_POWER) * lp_cycles)/inst->clk_data.work_route; + + mbpf = msm_vidc_get_mbs_per_frame(inst); + mbps = mbpf * msm_vidc_get_fps(inst); + max_hq_mbpf = core->resources.max_hq_mbs_per_frame; + max_hq_mbps = core->resources.max_hq_mbs_per_sec; + + s_vpr_h(inst->sid, "Core RT Load = %d LP Load = %d\n", + core_load, core_lp_load); + s_vpr_h(inst->sid, "Max Load = %lu\n", max_freq); + s_vpr_h(inst->sid, "Current Load = %d Current LP Load = %d\n", + cur_inst_load, cur_inst_lp_load); + + if (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ && + (core_load > max_freq || core_lp_load > max_freq)) { + s_vpr_e(inst->sid, + "CQ session - Core cannot support this load\n"); + return -EINVAL; + } + + /* Power saving always disabled for HEIF image sessions */ + if (is_image_session(inst)) + msm_vidc_power_save_mode_enable(inst, false); + else if (cur_inst_load + core_load <= max_freq) { + if (mbpf > max_hq_mbpf || mbps > max_hq_mbps) + enable = true; + msm_vidc_power_save_mode_enable(inst, enable); + } else if (cur_inst_lp_load + core_load <= max_freq) { + msm_vidc_power_save_mode_enable(inst, true); + } else if (cur_inst_lp_load + core_lp_load <= max_freq) { + s_vpr_h(inst->sid, "Moved all inst's to LP"); + msm_vidc_move_core_to_power_save_mode(core, + VIDC_CORE_ID_1, inst->sid); + } else { + s_vpr_e(inst->sid, "Core cannot support this load\n"); + return -EINVAL; + } + + inst->clk_data.core_id = VIDC_CORE_ID_1; + rc = msm_comm_scale_clocks_and_bus(inst, 1); + msm_print_core_status(core, VIDC_CORE_ID_1, inst->sid); + return rc; +} + +int msm_vidc_decide_core_and_power_mode_iris2(struct msm_vidc_inst *inst) +{ + u32 mbpf, mbps, max_hq_mbpf, max_hq_mbps; + bool enable = true; + int rc = 0; + + inst->clk_data.core_id = VIDC_CORE_ID_1; + + mbpf = msm_vidc_get_mbs_per_frame(inst); + mbps = mbpf * msm_vidc_get_fps(inst); + max_hq_mbpf = inst->core->resources.max_hq_mbs_per_frame; + max_hq_mbps = inst->core->resources.max_hq_mbs_per_sec; + + if (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps) + enable = false; + + rc = msm_vidc_power_save_mode_enable(inst, enable); + msm_print_core_status(inst->core, VIDC_CORE_ID_1, inst->sid); + + return rc; +} + +void msm_vidc_init_core_clk_ops(struct msm_vidc_core *core) +{ + uint32_t vpu; + + if (!core) + return; + + vpu = core->platform_data->vpu_ver; + + if (vpu == VPU_VERSION_AR50) + core->core_ops = &core_ops_ar50; + else if (vpu == VPU_VERSION_AR50_LITE) + core->core_ops = &core_ops_ar50lt; + else if (vpu == VPU_VERSION_IRIS1) + core->core_ops = &core_ops_iris1; + else + core->core_ops = &core_ops_iris2; +} + +void msm_print_core_status(struct msm_vidc_core *core, u32 core_id, u32 sid) +{ + struct msm_vidc_inst *inst = NULL; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + + s_vpr_p(sid, "Instances running on core %u", core_id); + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if ((inst->clk_data.core_id != core_id) && + (inst->clk_data.core_id != VIDC_CORE_ID_3)) + continue; + out_f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + inp_f = &inst->fmts[INPUT_PORT].v4l2_fmt; + s_vpr_p(sid, + "inst %pK (%4ux%4u) to (%4ux%4u) %3u %s %s %u %s %s %lu\n", + inst, + inp_f->fmt.pix_mp.width, + inp_f->fmt.pix_mp.height, + out_f->fmt.pix_mp.width, + out_f->fmt.pix_mp.height, + inst->clk_data.frame_rate >> 16, + inst->session_type == MSM_VIDC_ENCODER ? "ENC" : "DEC", + inst->clk_data.work_mode == HFI_WORKMODE_1 ? + "WORK_MODE_1" : "WORK_MODE_2", + inst->clk_data.work_route, + inst->flags & VIDC_LOW_POWER ? "LP" : "HQ", + is_realtime_session(inst) ? "RealTime" : "NonRTime", + inst->clk_data.min_freq); + } + mutex_unlock(&core->lock); +} diff --git a/techpack/video/msm/vidc/msm_vidc_clocks.h b/techpack/video/msm/vidc/msm_vidc_clocks.h new file mode 100644 index 0000000000000000000000000000000000000000..7515a4b49d686fdf1ccf33d356ef0ce63b6dd431 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_clocks.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_VIDC_CLOCKS_H_ +#define _MSM_VIDC_CLOCKS_H_ +#include "msm_vidc_internal.h" + +void msm_clock_data_reset(struct msm_vidc_inst *inst); +void msm_dcvs_reset(struct msm_vidc_inst *inst); +int msm_vidc_set_clocks(struct msm_vidc_core *core, u32 sid); +int msm_comm_vote_bus(struct msm_vidc_inst *inst); +int msm_dcvs_try_enable(struct msm_vidc_inst *inst); +bool res_is_less_than(u32 width, u32 height, u32 ref_width, u32 ref_height); +bool res_is_greater_than(u32 width, u32 height, u32 ref_width, u32 ref_height); +bool res_is_less_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool res_is_greater_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height); +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); +int msm_vidc_get_fps(struct msm_vidc_inst *inst); +int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst, bool do_bw_calc); +int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst); +int msm_vidc_decide_work_route_iris1(struct msm_vidc_inst *inst); +int msm_vidc_decide_work_mode_iris1(struct msm_vidc_inst *inst); +int msm_vidc_decide_work_route_iris2(struct msm_vidc_inst *inst); +int msm_vidc_decide_work_mode_iris2(struct msm_vidc_inst *inst); +int msm_vidc_decide_core_and_power_mode_ar50lt(struct msm_vidc_inst *inst); +int msm_vidc_decide_core_and_power_mode_iris1(struct msm_vidc_inst *inst); +int msm_vidc_decide_core_and_power_mode_iris2(struct msm_vidc_inst *inst); +void msm_print_core_status(struct msm_vidc_core *core, u32 core_id, u32 sid); +void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst); +void msm_comm_update_input_cr(struct msm_vidc_inst *inst, u32 index, + u32 cr); +void update_recon_stats(struct msm_vidc_inst *inst, + struct recon_stats_type *recon_stats); +void msm_vidc_init_core_clk_ops(struct msm_vidc_core *core); +bool res_is_greater_than(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool res_is_less_than(u32 width, u32 height, + u32 ref_width, u32 ref_height); +#endif diff --git a/techpack/video/msm/vidc/msm_vidc_common.c b/techpack/video/msm/vidc/msm_vidc_common.c new file mode 100644 index 0000000000000000000000000000000000000000..21adfe4d560e993ebd5b893ce93b21aac7f1cfa0 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_common.c @@ -0,0 +1,7631 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/jiffies.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <soc/qcom/subsystem_restart.h> +#include <asm/div64.h> +#include "msm_vidc_common.h" +#include "vidc_hfi_api.h" +#include "vidc_hfi.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" +#include "msm_cvp_internal.h" +#include "msm_vidc_buffer_calculations.h" + +#define IS_ALREADY_IN_STATE(__p, __d) (\ + (__p >= __d)\ +) + +#define V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT \ + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT +#define V4L2_EVENT_RELEASE_BUFFER_REFERENCE \ + V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE + +static void handle_session_error(enum hal_command_response cmd, void *data); +static void msm_vidc_print_running_insts(struct msm_vidc_core *core); + +#define V4L2_H264_LEVEL_UNKNOWN V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN +#define V4L2_HEVC_LEVEL_UNKNOWN V4L2_MPEG_VIDEO_HEVC_LEVEL_UNKNOWN +#define V4L2_VP9_LEVEL_61 V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 + +int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id) +{ + struct v4l2_ctrl *ctrl; + + ctrl = get_ctrl(inst, id); + return ctrl->val; +} + +int msm_comm_hfi_to_v4l2(int id, int value, u32 sid) +{ + switch (id) { + /* H264 */ + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (value) { + case HFI_H264_PROFILE_BASELINE: + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + case HFI_H264_PROFILE_CONSTRAINED_BASE: + return + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; + case HFI_H264_PROFILE_MAIN: + return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; + case HFI_H264_PROFILE_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + case HFI_H264_PROFILE_STEREO_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH; + case HFI_H264_PROFILE_MULTIVIEW_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH; + case HFI_H264_PROFILE_CONSTRAINED_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (value) { + case HFI_H264_LEVEL_1: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + case HFI_H264_LEVEL_1b: + return V4L2_MPEG_VIDEO_H264_LEVEL_1B; + case HFI_H264_LEVEL_11: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; + case HFI_H264_LEVEL_12: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; + case HFI_H264_LEVEL_13: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; + case HFI_H264_LEVEL_2: + return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; + case HFI_H264_LEVEL_21: + return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; + case HFI_H264_LEVEL_22: + return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; + case HFI_H264_LEVEL_3: + return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; + case HFI_H264_LEVEL_31: + return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; + case HFI_H264_LEVEL_32: + return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; + case HFI_H264_LEVEL_4: + return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + case HFI_H264_LEVEL_41: + return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + case HFI_H264_LEVEL_42: + return V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + case HFI_H264_LEVEL_5: + return V4L2_MPEG_VIDEO_H264_LEVEL_5_0; + case HFI_H264_LEVEL_51: + return V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + case HFI_H264_LEVEL_52: + return V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + case HFI_H264_LEVEL_6: + return V4L2_MPEG_VIDEO_H264_LEVEL_6_0; + case HFI_H264_LEVEL_61: + return V4L2_MPEG_VIDEO_H264_LEVEL_6_1; + case HFI_H264_LEVEL_62: + return V4L2_MPEG_VIDEO_H264_LEVEL_6_2; + default: + goto unknown_value; + } + + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + switch (value) { + case HFI_H264_ENTROPY_CAVLC: + return V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + case HFI_H264_ENTROPY_CABAC: + return V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (value) { + case HFI_HEVC_PROFILE_MAIN: + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + case HFI_HEVC_PROFILE_MAIN10: + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10; + case HFI_HEVC_PROFILE_MAIN_STILL_PIC: + return V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + switch (value) { + case HFI_HEVC_LEVEL_1: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_1; + case HFI_HEVC_LEVEL_2: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_2; + case HFI_HEVC_LEVEL_21: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1; + case HFI_HEVC_LEVEL_3: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_3; + case HFI_HEVC_LEVEL_31: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1; + case HFI_HEVC_LEVEL_4: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_4; + case HFI_HEVC_LEVEL_41: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1; + case HFI_HEVC_LEVEL_5: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_5; + case HFI_HEVC_LEVEL_51: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1; + case HFI_HEVC_LEVEL_52: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2; + case HFI_HEVC_LEVEL_6: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_6; + case HFI_HEVC_LEVEL_61: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1; + case HFI_HEVC_LEVEL_62: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2; + case HFI_LEVEL_UNKNOWN: + return V4L2_MPEG_VIDEO_HEVC_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + switch (value) { + case HFI_VP8_LEVEL_VERSION_0: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0; + case HFI_VP8_LEVEL_VERSION_1: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1; + case HFI_VP8_LEVEL_VERSION_2: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2; + case HFI_VP8_LEVEL_VERSION_3: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3; + case HFI_LEVEL_UNKNOWN: + return V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + switch (value) { + case HFI_VP9_PROFILE_P0: + return V4L2_MPEG_VIDEO_VP9_PROFILE_0; + case HFI_VP9_PROFILE_P2_10B: + return V4L2_MPEG_VIDEO_VP9_PROFILE_2; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_LEVEL: + switch (value) { + case HFI_VP9_LEVEL_1: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_1; + case HFI_VP9_LEVEL_11: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_11; + case HFI_VP9_LEVEL_2: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_2; + case HFI_VP9_LEVEL_21: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_21; + case HFI_VP9_LEVEL_3: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_3; + case HFI_VP9_LEVEL_31: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_31; + case HFI_VP9_LEVEL_4: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_4; + case HFI_VP9_LEVEL_41: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41; + case HFI_VP9_LEVEL_5: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5; + case HFI_VP9_LEVEL_51: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51; + case HFI_VP9_LEVEL_6: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6; + case HFI_VP9_LEVEL_61: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61; + case HFI_LEVEL_UNKNOWN: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE: + switch (value) { + case HFI_MPEG2_PROFILE_SIMPLE: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE; + case HFI_MPEG2_PROFILE_MAIN: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL: + /* This mapping is not defined properly in V4L2 */ + switch (value) { + case HFI_MPEG2_LEVEL_LL: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0; + case HFI_MPEG2_LEVEL_ML: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1; + case HFI_MPEG2_LEVEL_HL: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2; + default: + goto unknown_value; + } + } + +unknown_value: + s_vpr_e(sid, "Unknown control (%x, %d)\n", id, value); + return -EINVAL; +} + +static int h264_level_v4l2_to_hfi(int value, u32 sid) +{ + switch (value) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return HFI_H264_LEVEL_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return HFI_H264_LEVEL_1b; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return HFI_H264_LEVEL_11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return HFI_H264_LEVEL_12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return HFI_H264_LEVEL_13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return HFI_H264_LEVEL_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return HFI_H264_LEVEL_21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return HFI_H264_LEVEL_22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return HFI_H264_LEVEL_3; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return HFI_H264_LEVEL_31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return HFI_H264_LEVEL_32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return HFI_H264_LEVEL_4; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return HFI_H264_LEVEL_41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return HFI_H264_LEVEL_42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return HFI_H264_LEVEL_5; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return HFI_H264_LEVEL_51; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + return HFI_H264_LEVEL_52; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_0: + return HFI_H264_LEVEL_6; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_1: + return HFI_H264_LEVEL_61; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_2: + return HFI_H264_LEVEL_62; + case V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN: + return HFI_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + +unknown_value: + s_vpr_e(sid, "Unknown level (%d)\n", value); + return -EINVAL; +} + +static int hevc_level_v4l2_to_hfi(int value, u32 sid) +{ + switch (value) { + case V4L2_MPEG_VIDEO_HEVC_LEVEL_1: + return HFI_HEVC_LEVEL_1; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2: + return HFI_HEVC_LEVEL_2; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: + return HFI_HEVC_LEVEL_21; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3: + return HFI_HEVC_LEVEL_3; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: + return HFI_HEVC_LEVEL_31; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4: + return HFI_HEVC_LEVEL_4; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: + return HFI_HEVC_LEVEL_41; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5: + return HFI_HEVC_LEVEL_5; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: + return HFI_HEVC_LEVEL_51; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: + return HFI_HEVC_LEVEL_52; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6: + return HFI_HEVC_LEVEL_6; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: + return HFI_HEVC_LEVEL_61; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: + return HFI_HEVC_LEVEL_62; + case V4L2_MPEG_VIDEO_HEVC_LEVEL_UNKNOWN: + return HFI_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + +unknown_value: + s_vpr_e(sid, "Unknown level (%d)\n", value); + return -EINVAL; +} + +static int vp9_level_v4l2_to_hfi(int value, u32 sid) +{ + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_1: + return HFI_VP9_LEVEL_1; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_11: + return HFI_VP9_LEVEL_11; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_2: + return HFI_VP9_LEVEL_2; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_21: + return HFI_VP9_LEVEL_21; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_3: + return HFI_VP9_LEVEL_3; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_31: + return HFI_VP9_LEVEL_31; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_4: + return HFI_VP9_LEVEL_4; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41: + return HFI_VP9_LEVEL_41; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5: + return HFI_VP9_LEVEL_5; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51: + return HFI_VP9_LEVEL_51; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6: + return HFI_VP9_LEVEL_6; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61: + return HFI_VP9_LEVEL_61; + case V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED: + return HFI_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + +unknown_value: + s_vpr_e(sid, "Unknown level (%d)\n", value); + return -EINVAL; +} + +int msm_comm_v4l2_to_hfi(int id, int value, u32 sid) +{ + switch (id) { + /* H264 */ + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return HFI_H264_PROFILE_BASELINE; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + return HFI_H264_PROFILE_CONSTRAINED_BASE; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return HFI_H264_PROFILE_MAIN; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return HFI_H264_PROFILE_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: + return HFI_H264_PROFILE_STEREO_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: + return HFI_H264_PROFILE_MULTIVIEW_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + return HFI_H264_PROFILE_CONSTRAINED_HIGH; + default: + return HFI_H264_PROFILE_HIGH; + } + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + return h264_level_v4l2_to_hfi(value, sid); + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: + return HFI_H264_ENTROPY_CAVLC; + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: + return HFI_H264_ENTROPY_CABAC; + default: + return HFI_H264_ENTROPY_CABAC; + } + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_VP8_PROFILE_0: + return HFI_VP8_PROFILE_MAIN; + default: + return HFI_VP8_PROFILE_MAIN; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0: + return HFI_VP8_LEVEL_VERSION_0; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1: + return HFI_VP8_LEVEL_VERSION_1; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2: + return HFI_VP8_LEVEL_VERSION_2; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3: + return HFI_VP8_LEVEL_VERSION_3; + case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED: + return HFI_LEVEL_UNKNOWN; + default: + return HFI_LEVEL_UNKNOWN; + } + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_VP9_PROFILE_0: + return HFI_VP9_PROFILE_P0; + case V4L2_MPEG_VIDEO_VP9_PROFILE_2: + return HFI_VP9_PROFILE_P2_10B; + default: + return HFI_VP9_PROFILE_P0; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_LEVEL: + return vp9_level_v4l2_to_hfi(value, sid); + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + return HFI_HEVC_PROFILE_MAIN; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + return HFI_HEVC_PROFILE_MAIN10; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + return HFI_HEVC_PROFILE_MAIN_STILL_PIC; + default: + return HFI_HEVC_PROFILE_MAIN; + } + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + return hevc_level_v4l2_to_hfi(value, sid); + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + switch (value) { + case V4L2_MPEG_VIDEO_HEVC_TIER_MAIN: + return HFI_HEVC_TIER_MAIN; + case V4L2_MPEG_VIDEO_HEVC_TIER_HIGH: + return HFI_HEVC_TIER_HIGH; + default: + return HFI_HEVC_TIER_HIGH; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE: + return HFI_MPEG2_PROFILE_SIMPLE; + case V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN: + return HFI_MPEG2_PROFILE_MAIN; + default: + return HFI_MPEG2_PROFILE_MAIN; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL: + /* This mapping is not defined properly in V4L2 */ + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0: + return HFI_MPEG2_LEVEL_LL; + case V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1: + return HFI_MPEG2_LEVEL_ML; + case V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2: + return HFI_MPEG2_LEVEL_HL; + default: + return HFI_MPEG2_LEVEL_HL; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + return HFI_H264_DB_MODE_DISABLE; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + return HFI_H264_DB_MODE_ALL_BOUNDARY; + case DB_DISABLE_SLICE_BOUNDARY: + return HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY; + default: + return HFI_H264_DB_MODE_ALL_BOUNDARY; + } + } + s_vpr_e(sid, "Unknown control (%x, %d)\n", id, value); + return -EINVAL; +} + +int msm_comm_get_v4l2_profile(int fourcc, int profile, u32 sid) +{ + switch (fourcc) { + case V4L2_PIX_FMT_H264: + return msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + profile, sid); + case V4L2_PIX_FMT_HEVC: + return msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + profile, sid); + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_VP9: + case V4L2_PIX_FMT_MPEG2: + return 0; + default: + s_vpr_e(sid, "Unknown codec id %x\n", fourcc); + return 0; + } +} + +int msm_comm_get_v4l2_level(int fourcc, int level, u32 sid) +{ + switch (fourcc) { + case V4L2_PIX_FMT_H264: + return msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + level, sid); + case V4L2_PIX_FMT_HEVC: + level &= ~(0xF << 28); + return msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + level, sid); + case V4L2_PIX_FMT_VP8: + return msm_comm_hfi_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + level, sid); + case V4L2_PIX_FMT_VP9: + case V4L2_PIX_FMT_MPEG2: + return 0; + default: + s_vpr_e(sid, "Unknown codec id %x\n", fourcc); + return 0; + } +} + +int msm_comm_ctrl_init(struct msm_vidc_inst *inst, + struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls, + const struct v4l2_ctrl_ops *ctrl_ops) +{ + int idx = 0; + struct v4l2_ctrl_config ctrl_cfg = {0}; + int ret_val = 0; + + if (!inst || !drv_ctrls || !ctrl_ops || !num_ctrls) { + d_vpr_e("%s: invalid input\n", __func__); + return -EINVAL; + } + + inst->ctrls = kcalloc(num_ctrls, sizeof(struct v4l2_ctrl *), + GFP_KERNEL); + if (!inst->ctrls) { + s_vpr_e(inst->sid, "%s: failed to allocate ctrl\n", __func__); + return -ENOMEM; + } + + ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls); + + if (ret_val) { + s_vpr_e(inst->sid, "Control handler init failed, %d\n", + inst->ctrl_handler.error); + return ret_val; + } + + for (; idx < (int) num_ctrls; idx++) { + struct v4l2_ctrl *ctrl = NULL; + + if (IS_PRIV_CTRL(drv_ctrls[idx].id)) { + /*add private control*/ + ctrl_cfg.def = drv_ctrls[idx].default_value; + ctrl_cfg.flags = 0; + ctrl_cfg.id = drv_ctrls[idx].id; + ctrl_cfg.max = drv_ctrls[idx].maximum; + ctrl_cfg.min = drv_ctrls[idx].minimum; + ctrl_cfg.menu_skip_mask = + drv_ctrls[idx].menu_skip_mask; + ctrl_cfg.name = drv_ctrls[idx].name; + ctrl_cfg.ops = ctrl_ops; + ctrl_cfg.step = drv_ctrls[idx].step; + ctrl_cfg.type = drv_ctrls[idx].type; + ctrl_cfg.qmenu = drv_ctrls[idx].qmenu; + + ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler, + &ctrl_cfg, NULL); + } else { + if (drv_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) { + ctrl = v4l2_ctrl_new_std_menu( + &inst->ctrl_handler, + ctrl_ops, + drv_ctrls[idx].id, + (u8) drv_ctrls[idx].maximum, + drv_ctrls[idx].menu_skip_mask, + (u8) drv_ctrls[idx].default_value); + } else { + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, + ctrl_ops, + drv_ctrls[idx].id, + drv_ctrls[idx].minimum, + drv_ctrls[idx].maximum, + drv_ctrls[idx].step, + drv_ctrls[idx].default_value); + } + } + + if (!ctrl) { + s_vpr_e(inst->sid, "%s: invalid ctrl %s\n", __func__, + drv_ctrls[idx].name); + return -EINVAL; + } + + ret_val = inst->ctrl_handler.error; + if (ret_val) { + s_vpr_e(inst->sid, + "Error adding ctrl (%s) to ctrl handle, %d\n", + drv_ctrls[idx].name, inst->ctrl_handler.error); + return ret_val; + } + + ctrl->flags |= drv_ctrls[idx].flags; + ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + inst->ctrls[idx] = ctrl; + } + inst->num_ctrls = num_ctrls; + + return ret_val; +} + +int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + kfree(inst->ctrls); + v4l2_ctrl_handler_free(&inst->ctrl_handler); + + return 0; +} + +int msm_comm_set_stream_output_mode(struct msm_vidc_inst *inst, + enum multi_stream mode) +{ + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!is_decode_session(inst)) { + s_vpr_h(inst->sid, "%s: not a decode session\n", __func__); + return -EINVAL; + } + + if (mode == HAL_VIDEO_DECODER_SECONDARY) + inst->stream_output_mode = HAL_VIDEO_DECODER_SECONDARY; + else + inst->stream_output_mode = HAL_VIDEO_DECODER_PRIMARY; + + return 0; +} + +enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return HAL_VIDEO_DECODER_PRIMARY; + } + + if (!is_decode_session(inst)) + return HAL_VIDEO_DECODER_PRIMARY; + + if (inst->stream_output_mode == HAL_VIDEO_DECODER_SECONDARY) + return HAL_VIDEO_DECODER_SECONDARY; + else + return HAL_VIDEO_DECODER_PRIMARY; +} + +bool is_single_session(struct msm_vidc_inst *inst, u32 ignore_flags) +{ + bool single = true; + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return false; + } + core = inst->core; + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + /* ignore invalid session */ + if (temp->state == MSM_VIDC_CORE_INVALID) + continue; + if ((ignore_flags & VIDC_THUMBNAIL) && + is_thumbnail_session(temp)) + continue; + if (temp != inst) { + single = false; + break; + } + } + mutex_unlock(&core->lock); + + return single; +} + +int msm_comm_get_num_perf_sessions(struct msm_vidc_inst *inst) +{ + int count = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + goto exit; + } + core = inst->core; + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + if (temp->is_perf_eligible_session) + count++; + } + mutex_unlock(&core->lock); +exit: + return count; +} + +static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst, + enum load_calc_quirks quirks) +{ + int input_port_mbs, output_port_mbs; + int fps; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + input_port_mbs = NUM_MBS_PER_FRAME(f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_port_mbs = NUM_MBS_PER_FRAME(f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + + fps = inst->clk_data.frame_rate; + + /* For admission control operating rate is ignored */ + if (quirks == LOAD_POWER) + fps = max(inst->clk_data.operating_rate, + inst->clk_data.frame_rate); + + /* In case of fps < 1 we assume 1 */ + fps = max(fps >> 16, 1); + + return max(input_port_mbs, output_port_mbs) * fps; +} + +int msm_comm_get_inst_load(struct msm_vidc_inst *inst, + enum load_calc_quirks quirks) +{ + int load = 0; + + mutex_lock(&inst->lock); + + if (!(inst->state >= MSM_VIDC_OPEN_DONE && + inst->state < MSM_VIDC_STOP_DONE)) + goto exit; + + /* Clock and Load calculations for REALTIME/NON-REALTIME + * Operating rate will either Default or Client value. + * Session admission control will be based on Load. + * Power requests based of calculated Clock/Freq. + * ----------------|----------------------------| + * REALTIME | Admission Control Load = | + * | res * fps | + * | Power Request Load = | + * | res * max(op, fps)| + * ----------------|----------------------------| + * NON-REALTIME/ | Admission Control Load = 0 | + * THUMBNAIL | Power Request Load = | + * | res * max(op, fps)| + * ----------------|----------------------------| + */ + + if (is_thumbnail_session(inst) || + (!is_realtime_session(inst) && + quirks == LOAD_ADMISSION_CONTROL)) { + load = 0; + } else { + load = msm_comm_get_mbs_per_sec(inst, quirks); + } + +exit: + mutex_unlock(&inst->lock); + return load; +} + +int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst, + enum load_calc_quirks quirks) +{ + int load = msm_comm_get_inst_load(inst, quirks); + + if (inst->clk_data.core_id == VIDC_CORE_ID_3) + load = load / 2; + + return load; +} + +int msm_comm_get_device_load(struct msm_vidc_core *core, + enum session_type sess_type, enum load_type load_type, + enum load_calc_quirks quirks) +{ + struct msm_vidc_inst *inst = NULL; + int num_mbs_per_sec = 0; + + if (!core) { + d_vpr_e("Invalid args: %pK\n", core); + return -EINVAL; + } + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->session_type != sess_type) + continue; + + if (load_type == MSM_VIDC_VIDEO && !is_video_session(inst)) + continue; + else if (load_type == MSM_VIDC_IMAGE && !is_grid_session(inst)) + continue; + + num_mbs_per_sec += msm_comm_get_inst_load(inst, quirks); + } + mutex_unlock(&core->lock); + + return num_mbs_per_sec; +} + +enum hal_domain get_hal_domain(int session_type, u32 sid) +{ + enum hal_domain domain; + + switch (session_type) { + case MSM_VIDC_ENCODER: + domain = HAL_VIDEO_DOMAIN_ENCODER; + break; + case MSM_VIDC_DECODER: + domain = HAL_VIDEO_DOMAIN_DECODER; + break; + case MSM_VIDC_CVP: + domain = HAL_VIDEO_DOMAIN_CVP; + break; + default: + s_vpr_e(sid, "Wrong domain %d\n", session_type); + domain = HAL_UNUSED_DOMAIN; + break; + } + + return domain; +} + +enum hal_video_codec get_hal_codec(int fourcc, u32 sid) +{ + enum hal_video_codec codec; + + switch (fourcc) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_H264_NO_SC: + codec = HAL_VIDEO_CODEC_H264; + break; + case V4L2_PIX_FMT_H264_MVC: + codec = HAL_VIDEO_CODEC_MVC; + break; + case V4L2_PIX_FMT_MPEG1: + codec = HAL_VIDEO_CODEC_MPEG1; + break; + case V4L2_PIX_FMT_MPEG2: + codec = HAL_VIDEO_CODEC_MPEG2; + break; + case V4L2_PIX_FMT_VP8: + codec = HAL_VIDEO_CODEC_VP8; + break; + case V4L2_PIX_FMT_VP9: + codec = HAL_VIDEO_CODEC_VP9; + break; + case V4L2_PIX_FMT_HEVC: + codec = HAL_VIDEO_CODEC_HEVC; + break; + case V4L2_PIX_FMT_TME: + codec = HAL_VIDEO_CODEC_TME; + break; + case V4L2_PIX_FMT_CVP: + codec = HAL_VIDEO_CODEC_CVP; + break; + default: + s_vpr_e(sid, "Wrong codec: %#x\n", fourcc); + codec = HAL_UNUSED_CODEC; + break; + } + + return codec; +} + +enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc) +{ + enum hal_uncompressed_format format = HAL_UNUSED_COLOR; + + switch (fourcc) { + case V4L2_PIX_FMT_NV12: + format = HAL_COLOR_FORMAT_NV12; + break; + case V4L2_PIX_FMT_NV12_512: + format = HAL_COLOR_FORMAT_NV12_512; + break; + case V4L2_PIX_FMT_NV21: + format = HAL_COLOR_FORMAT_NV21; + break; + case V4L2_PIX_FMT_NV12_UBWC: + format = HAL_COLOR_FORMAT_NV12_UBWC; + break; + case V4L2_PIX_FMT_NV12_TP10_UBWC: + format = HAL_COLOR_FORMAT_NV12_TP10_UBWC; + break; + case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS: + format = HAL_COLOR_FORMAT_P010; + break; + default: + format = HAL_UNUSED_COLOR; + break; + } + + return format; +} + +u32 msm_comm_get_hfi_uncompressed(int fourcc, u32 sid) +{ + u32 format; + + switch (fourcc) { + case V4L2_PIX_FMT_NV12: + format = HFI_COLOR_FORMAT_NV12; + break; + case V4L2_PIX_FMT_NV12_512: + format = HFI_COLOR_FORMAT_NV12; + break; + case V4L2_PIX_FMT_NV21: + format = HFI_COLOR_FORMAT_NV21; + break; + case V4L2_PIX_FMT_NV12_UBWC: + format = HFI_COLOR_FORMAT_NV12_UBWC; + break; + case V4L2_PIX_FMT_NV12_TP10_UBWC: + format = HFI_COLOR_FORMAT_YUV420_TP10_UBWC; + break; + case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS: + format = HFI_COLOR_FORMAT_P010; + break; + default: + format = HFI_COLOR_FORMAT_NV12_UBWC; + s_vpr_e(sid, "Invalid format, defaulting to UBWC"); + break; + } + + return format; +} +struct msm_vidc_core *get_vidc_core(int core_id) +{ + struct msm_vidc_core *core; + int found = 0; + + if (core_id > MSM_VIDC_CORES_MAX) { + d_vpr_e("Core id = %d is greater than max = %d\n", + core_id, MSM_VIDC_CORES_MAX); + return NULL; + } + mutex_lock(&vidc_driver->lock); + list_for_each_entry(core, &vidc_driver->cores, list) { + if (core->id == core_id) { + found = 1; + break; + } + } + mutex_unlock(&vidc_driver->lock); + if (found) + return core; + return NULL; +} + +const struct msm_vidc_format_desc *msm_comm_get_pixel_fmt_index( + const struct msm_vidc_format_desc fmt[], int size, int index, u32 sid) +{ + int i, k = 0; + + if (!fmt || index < 0) { + s_vpr_e(sid, "Invalid inputs, fmt = %pK, index = %d\n", + fmt, index); + return NULL; + } + for (i = 0; i < size; i++) { + if (k == index) + break; + k++; + } + if (i == size) { + s_vpr_h(sid, "Format not found\n"); + return NULL; + } + return &fmt[i]; +} +struct msm_vidc_format_desc *msm_comm_get_pixel_fmt_fourcc( + struct msm_vidc_format_desc fmt[], int size, int fourcc, u32 sid) +{ + int i; + + if (!fmt) { + s_vpr_e(sid, "Invalid inputs, fmt = %pK\n", fmt); + return NULL; + } + for (i = 0; i < size; i++) { + if (fmt[i].fourcc == fourcc) + break; + } + if (i == size) { + s_vpr_h(sid, "Format not found\n"); + return NULL; + } + return &fmt[i]; +} + +struct msm_vidc_format_constraint *msm_comm_get_pixel_fmt_constraints( + struct msm_vidc_format_constraint fmt[], int size, int fourcc, u32 sid) +{ + int i; + + if (!fmt) { + s_vpr_e(sid, "Invalid inputs, fmt = %pK\n", fmt); + return NULL; + } + for (i = 0; i < size; i++) { + if (fmt[i].fourcc == fourcc) + break; + } + if (i == size) { + s_vpr_h(sid, "Format constraint not found.\n"); + return NULL; + } + return &fmt[i]; +} + +struct buf_queue *msm_comm_get_vb2q( + struct msm_vidc_inst *inst, enum v4l2_buf_type type) +{ + if (type == OUTPUT_MPLANE) + return &inst->bufq[OUTPUT_PORT]; + if (type == INPUT_MPLANE) + return &inst->bufq[INPUT_PORT]; + return NULL; +} + +static void update_capability(struct msm_vidc_codec_capability *in, + struct msm_vidc_capability *capability) +{ + if (!in || !capability) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, in, capability); + return; + } + if (in->capability_type < CAP_MAX) { + capability->cap[in->capability_type].capability_type = + in->capability_type; + capability->cap[in->capability_type].min = in->min; + capability->cap[in->capability_type].max = in->max; + capability->cap[in->capability_type].step_size = in->step_size; + capability->cap[in->capability_type].default_value = + in->default_value; + } else { + d_vpr_e("%s: invalid capability_type %d\n", + __func__, in->capability_type); + } +} + +static int msm_vidc_capabilities(struct msm_vidc_core *core) +{ + int rc = 0; + struct msm_vidc_codec_capability *platform_caps; + int i, j, num_platform_caps; + + if (!core || !core->capabilities) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return -EINVAL; + } + platform_caps = core->resources.codec_caps; + num_platform_caps = core->resources.codec_caps_count; + + d_vpr_h("%s: num caps %d\n", __func__, num_platform_caps); + /* loop over each platform capability */ + for (i = 0; i < num_platform_caps; i++) { + /* select matching core codec and update it */ + for (j = 0; j < core->resources.codecs_count; j++) { + if ((platform_caps[i].domains & + core->capabilities[j].domain) && + (platform_caps[i].codecs & + core->capabilities[j].codec)) { + /* update core capability */ + update_capability(&platform_caps[i], + &core->capabilities[j]); + } + } + } + + return rc; +} + +static void handle_sys_init_done(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_core *core; + + if (!IS_HAL_SYS_CMD(cmd)) { + d_vpr_e("%s: invalid cmd\n", __func__); + return; + } + if (!response) { + d_vpr_e("Failed to get valid response for sys init\n"); + return; + } + core = get_vidc_core(response->device_id); + if (!core) { + d_vpr_e("Wrong device_id received\n"); + return; + } + d_vpr_l("handled: SYS_INIT_DONE\n"); + complete(&(core->completions[SYS_MSG_INDEX(cmd)])); +} + +static void put_inst_helper(struct kref *kref) +{ + struct msm_vidc_inst *inst = container_of(kref, + struct msm_vidc_inst, kref); + + msm_vidc_destroy(inst); +} + +void put_inst(struct msm_vidc_inst *inst) +{ + if (!inst) + return; + + kref_put(&inst->kref, put_inst_helper); +} + +struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, + void *inst_id) +{ + struct msm_vidc_inst *inst = NULL; + bool matches = false; + + if (!core || !inst_id) + return NULL; + + mutex_lock(&core->lock); + /* + * This is as good as !list_empty(!inst->list), but at this point + * we don't really know if inst was kfree'd via close syscall before + * hardware could respond. So manually walk thru the list of active + * sessions + */ + list_for_each_entry(inst, &core->instances, list) { + if (inst == inst_id) { + /* + * Even if the instance is valid, we really shouldn't + * be receiving or handling callbacks when we've deleted + * our session with HFI + */ + matches = !!inst->session; + break; + } + } + + /* + * kref_* is atomic_int backed, so no need for inst->lock. But we can + * always acquire inst->lock and release it in put_inst for a stronger + * locking system. + */ + inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL; + mutex_unlock(&core->lock); + + return inst; +} + +static void handle_session_release_buf_done(enum hal_command_response cmd, + void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + struct internal_buf *buf; + struct list_head *ptr, *next; + struct hal_buffer_info *buffer; + u32 buf_found = false; + u32 address; + + if (!response) { + d_vpr_e("Invalid release_buf_done response\n"); + return; + } + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + buffer = &response->data.buffer_info; + address = buffer->buffer_addr; + + mutex_lock(&inst->scratchbufs.lock); + list_for_each_safe(ptr, next, &inst->scratchbufs.list) { + buf = list_entry(ptr, struct internal_buf, list); + if (address == buf->smem.device_addr) { + s_vpr_h(inst->sid, "releasing scratch: %x\n", + buf->smem.device_addr); + buf_found = true; + } + } + mutex_unlock(&inst->scratchbufs.lock); + + mutex_lock(&inst->persistbufs.lock); + list_for_each_safe(ptr, next, &inst->persistbufs.list) { + buf = list_entry(ptr, struct internal_buf, list); + if (address == buf->smem.device_addr) { + s_vpr_h(inst->sid, "releasing persist: %x\n", + buf->smem.device_addr); + buf_found = true; + } + } + mutex_unlock(&inst->persistbufs.lock); + + if (!buf_found) + s_vpr_e(inst->sid, "invalid buffer received from firmware"); + if (IS_HAL_SESSION_CMD(cmd)) + complete(&inst->completions[SESSION_MSG_INDEX(cmd)]); + else + s_vpr_e(inst->sid, "Invalid inst cmd response: %d\n", cmd); + + s_vpr_l(inst->sid, "handled: SESSION_RELEASE_BUFFER_DONE\n"); + put_inst(inst); +} + +static void handle_sys_release_res_done( + enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_core *core; + + if (!response) { + d_vpr_e("Failed to get valid response for sys init\n"); + return; + } + core = get_vidc_core(response->device_id); + if (!core) { + d_vpr_e("Wrong device_id received\n"); + return; + } + d_vpr_l("handled: SYS_RELEASE_RESOURCE_DONE\n"); + complete(&core->completions[ + SYS_MSG_INDEX(HAL_SYS_RELEASE_RESOURCE_DONE)]); +} + +void change_inst_state(struct msm_vidc_inst *inst, enum instance_state state) +{ + if (!inst) { + d_vpr_e("Invalid parameter %s\n", __func__); + return; + } + mutex_lock(&inst->lock); + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_h(inst->sid, + "Inst: %pK is in bad state can't change state to %d\n", + inst, state); + goto exit; + } + s_vpr_h(inst->sid, "Moved inst: %pK from state: %d to state: %d\n", + inst, inst->state, state); + inst->state = state; +exit: + mutex_unlock(&inst->lock); +} + +static int signal_session_msg_receipt(enum hal_command_response cmd, + struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("Invalid(%pK) instance id\n", inst); + return -EINVAL; + } + if (IS_HAL_SESSION_CMD(cmd)) { + complete(&inst->completions[SESSION_MSG_INDEX(cmd)]); + } else { + s_vpr_e(inst->sid, "Invalid inst cmd response: %d\n", cmd); + return -EINVAL; + } + return 0; +} + +static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst, + enum hal_command_response cmd) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst) { + d_vpr_e("Invalid(%pK) instance id\n", inst); + return -EINVAL; + } + if (!IS_HAL_SESSION_CMD(cmd)) { + s_vpr_e(inst->sid, "Invalid inst cmd response: %d\n", cmd); + return -EINVAL; + } + hdev = (struct hfi_device *)(inst->core->device); + rc = wait_for_completion_timeout( + &inst->completions[SESSION_MSG_INDEX(cmd)], + msecs_to_jiffies( + inst->core->resources.msm_vidc_hw_rsp_timeout)); + if (!rc) { + s_vpr_e(inst->sid, "Wait interrupted or timed out: %d\n", + SESSION_MSG_INDEX(cmd)); + msm_comm_kill_session(inst); + rc = -EIO; + } else { + rc = 0; + } + return rc; +} + +static int wait_for_state(struct msm_vidc_inst *inst, + enum instance_state flipped_state, + enum instance_state desired_state, + enum hal_command_response hal_cmd) +{ + int rc = 0; + + if (!inst) { + d_vpr_e("Invalid parameter %s\n", __func__); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto err_same_state; + } + s_vpr_h(inst->sid, "Waiting for hal_cmd: %d\n", hal_cmd); + rc = wait_for_sess_signal_receipt(inst, hal_cmd); + if (!rc) + change_inst_state(inst, desired_state); +err_same_state: + return rc; +} + +void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type) +{ + struct v4l2_event event = {.id = 0, .type = event_type}; + + v4l2_event_queue_fh(&inst->event_handler, &event); +} + +static void msm_comm_generate_max_clients_error(struct msm_vidc_inst *inst) +{ + enum hal_command_response cmd = HAL_SESSION_ERROR; + struct msm_vidc_cb_cmd_done response = {0}; + + if (!inst) { + d_vpr_e("%s: invalid input parameters\n", __func__); + return; + } + s_vpr_e(inst->sid, "%s: Too many clients\n", __func__); + response.inst_id = inst; + response.status = VIDC_ERR_MAX_CLIENTS; + handle_session_error(cmd, (void *)&response); +} + +static void print_cap(u32 sid, const char *type, + struct hal_capability_supported *cap) +{ + s_vpr_h(sid, "%-24s: %-10d %-10d %-10d %-10d\n", + type, cap->min, cap->max, cap->step_size, cap->default_value); +} + +static int msm_vidc_comm_update_ctrl(struct msm_vidc_inst *inst, + u32 id, struct hal_capability_supported *cap) +{ + struct v4l2_ctrl *ctrl = NULL; + int rc = 0; + bool is_menu = false; + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, id); + if (!ctrl) { + s_vpr_e(inst->sid, + "%s: Conrol id %d not found\n", __func__, id); + return -EINVAL; + } + + if (ctrl->type == V4L2_CTRL_TYPE_MENU) + is_menu = true; + + /** + * For menu controls the step value is interpreted + * as a menu_skip_mask. + */ + rc = v4l2_ctrl_modify_range(ctrl, cap->min, cap->max, + is_menu ? ctrl->menu_skip_mask : cap->step_size, + cap->default_value); + if (rc) { + s_vpr_e(inst->sid, + "%s: failed: control name %s, min %d, max %d, %s %x, default_value %d\n", + __func__, ctrl->name, cap->min, cap->max, + is_menu ? "menu_skip_mask" : "step", + is_menu ? ctrl->menu_skip_mask : cap->step_size, + cap->default_value); + goto error; + } + + s_vpr_h(inst->sid, + "Updated control: %s: min %lld, max %lld, %s %x, default value = %lld\n", + ctrl->name, ctrl->minimum, ctrl->maximum, + is_menu ? "menu_skip_mask" : "step", + is_menu ? ctrl->menu_skip_mask : ctrl->step, + ctrl->default_value); + +error: + return rc; +} + +static void msm_vidc_comm_update_ctrl_limits(struct msm_vidc_inst *inst) +{ + struct v4l2_format *f; + + if (inst->session_type == MSM_VIDC_ENCODER) { + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + if (get_hal_codec(f->fmt.pix_mp.pixelformat, + inst->sid) == + HAL_VIDEO_CODEC_TME) + return; + msm_vidc_comm_update_ctrl(inst, V4L2_CID_MPEG_VIDEO_BITRATE, + &inst->capability.cap[CAP_BITRATE]); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT, + &inst->capability.cap[CAP_LTR_COUNT]); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + &inst->capability.cap[CAP_BFRAME]); + } + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + &inst->capability.cap[CAP_H264_LEVEL]); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + &inst->capability.cap[CAP_HEVC_LEVEL]); + /* Default value of level is unknown, but since we are not using unknown value + while updating level controls, we need to reinitialize inst->level to HFI + unknown value */ + inst->level = HFI_LEVEL_UNKNOWN; +} + +static void handle_session_init_done(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst = NULL; + + if (!response) { + d_vpr_e("Failed to get valid response for session init\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + if (response->status) { + s_vpr_e(inst->sid, "Session init response from FW: %#x\n", + response->status); + goto error; + } + + s_vpr_l(inst->sid, "handled: SESSION_INIT_DONE\n"); + signal_session_msg_receipt(cmd, inst); + put_inst(inst); + return; + +error: + if (response->status == VIDC_ERR_MAX_CLIENTS) + msm_comm_generate_max_clients_error(inst); + else + msm_comm_generate_session_error(inst); + + signal_session_msg_receipt(cmd, inst); + put_inst(inst); +} + +static int msm_comm_update_capabilities(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct msm_vidc_capability *capability = NULL; + u32 i, codec; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_CVP) { + s_vpr_h(inst->sid, "%s: cvp session\n", __func__); + return 0; + } + + core = inst->core; + codec = get_v4l2_codec(inst); + + for (i = 0; i < core->resources.codecs_count; i++) { + if (core->capabilities[i].codec == + get_hal_codec(codec, inst->sid) && + core->capabilities[i].domain == + get_hal_domain(inst->session_type, inst->sid)) { + capability = &core->capabilities[i]; + break; + } + } + if (!capability) { + s_vpr_e(inst->sid, + "%s: capabilities not found for domain %#x codec %#x\n", + __func__, get_hal_domain(inst->session_type, inst->sid), + get_hal_codec(codec, inst->sid)); + return -EINVAL; + } + + s_vpr_h(inst->sid, "%s: capabilities for domain %#x codec %#x\n", + __func__, capability->domain, capability->codec); + memcpy(&inst->capability, capability, + sizeof(struct msm_vidc_capability)); + + s_vpr_h(inst->sid, + "Capability type : min max step_size default_value\n"); + print_cap(inst->sid, "width", &inst->capability.cap[CAP_FRAME_WIDTH]); + print_cap(inst->sid, "height", &inst->capability.cap[CAP_FRAME_HEIGHT]); + print_cap(inst->sid, "mbs_per_frame", + &inst->capability.cap[CAP_MBS_PER_FRAME]); + print_cap(inst->sid, "mbs_per_sec", + &inst->capability.cap[CAP_MBS_PER_SECOND]); + print_cap(inst->sid, "frame_rate", + &inst->capability.cap[CAP_FRAMERATE]); + print_cap(inst->sid, "bitrate", &inst->capability.cap[CAP_BITRATE]); + print_cap(inst->sid, "scale_x", &inst->capability.cap[CAP_SCALE_X]); + print_cap(inst->sid, "scale_y", &inst->capability.cap[CAP_SCALE_Y]); + print_cap(inst->sid, "hier_p", + &inst->capability.cap[CAP_HIER_P_NUM_ENH_LAYERS]); + print_cap(inst->sid, "ltr_count", &inst->capability.cap[CAP_LTR_COUNT]); + print_cap(inst->sid, "bframe", &inst->capability.cap[CAP_BFRAME]); + print_cap(inst->sid, "mbs_per_sec_low_power", + &inst->capability.cap[CAP_MBS_PER_SECOND_POWER_SAVE]); + print_cap(inst->sid, "i_qp", &inst->capability.cap[CAP_I_FRAME_QP]); + print_cap(inst->sid, "p_qp", &inst->capability.cap[CAP_P_FRAME_QP]); + print_cap(inst->sid, "b_qp", &inst->capability.cap[CAP_B_FRAME_QP]); + print_cap(inst->sid, "slice_bytes", + &inst->capability.cap[CAP_SLICE_BYTE]); + print_cap(inst->sid, "slice_mbs", &inst->capability.cap[CAP_SLICE_MB]); + print_cap(inst->sid, "max_videocores", + &inst->capability.cap[CAP_MAX_VIDEOCORES]); + /* Secure usecase specific */ + print_cap(inst->sid, "secure_width", + &inst->capability.cap[CAP_SECURE_FRAME_WIDTH]); + print_cap(inst->sid, "secure_height", + &inst->capability.cap[CAP_SECURE_FRAME_HEIGHT]); + print_cap(inst->sid, "secure_mbs_per_frame", + &inst->capability.cap[CAP_SECURE_MBS_PER_FRAME]); + print_cap(inst->sid, "secure_bitrate", + &inst->capability.cap[CAP_SECURE_BITRATE]); + /* Batch Mode Decode */ + print_cap(inst->sid, "batch_mbs_per_frame", + &inst->capability.cap[CAP_BATCH_MAX_MB_PER_FRAME]); + print_cap(inst->sid, "batch_frame_rate", + &inst->capability.cap[CAP_BATCH_MAX_FPS]); + /* Lossless encoding usecase specific */ + print_cap(inst->sid, "lossless_width", + &inst->capability.cap[CAP_LOSSLESS_FRAME_WIDTH]); + print_cap(inst->sid, "lossless_height", + &inst->capability.cap[CAP_LOSSLESS_FRAME_HEIGHT]); + print_cap(inst->sid, "lossless_mbs_per_frame", + &inst->capability.cap[CAP_LOSSLESS_MBS_PER_FRAME]); + /* All intra encoding usecase specific */ + print_cap(inst->sid, "all_intra_frame_rate", + &inst->capability.cap[CAP_ALLINTRA_MAX_FPS]); + + msm_vidc_comm_update_ctrl_limits(inst); + + return 0; +} + +static void msm_vidc_queue_rbr_event(struct msm_vidc_inst *inst, + int fd, u32 offset) +{ + struct v4l2_event buf_event = {0}; + u32 *ptr; + + buf_event.type = V4L2_EVENT_RELEASE_BUFFER_REFERENCE; + ptr = (u32 *)buf_event.u.data; + ptr[0] = fd; + ptr[1] = offset; + + v4l2_event_queue_fh(&inst->event_handler, &buf_event); +} + +static void handle_event_change(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_inst *inst = NULL; + struct msm_vidc_cb_event *event_notify = data; + int event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; + struct v4l2_event seq_changed_event = {0}; + int rc = 0; + struct hfi_device *hdev; + u32 *ptr = NULL; + struct msm_vidc_format *fmt; + int extra_buff_count = 0; + u32 codec; + + if (!event_notify) { + d_vpr_e("Got an empty event from hfi\n"); + return; + } + + inst = get_inst(get_vidc_core(event_notify->device_id), + event_notify->inst_id); + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("Got a response for an inactive session\n"); + goto err_bad_event; + } + hdev = inst->core->device; + codec = get_v4l2_codec(inst); + + switch (event_notify->hal_event_type) { + case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES: + { + /* + * Check if there is some parameter has changed + * If there is no change then no need to notify client + * If there is a change, then raise an insufficient event + */ + bool event_fields_changed = false; + + s_vpr_h(inst->sid, "seq: V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n"); + s_vpr_h(inst->sid, + "seq: event_notify->height = %d event_notify->width = %d\n", + event_notify->height, event_notify->width); + if (codec == V4L2_PIX_FMT_HEVC || codec == V4L2_PIX_FMT_VP9) + event_fields_changed |= (inst->bit_depth != + event_notify->bit_depth); + /* Check for change from hdr->non-hdr and vice versa */ + if (codec == V4L2_PIX_FMT_HEVC && + ((event_notify->colour_space == MSM_VIDC_BT2020 && + inst->colour_space != MSM_VIDC_BT2020) || + (event_notify->colour_space != MSM_VIDC_BT2020 && + inst->colour_space == MSM_VIDC_BT2020))) + event_fields_changed = true; + + /* + * Check for a change from progressive to interlace + * and vice versa + */ + if ((event_notify->pic_struct == MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED && + inst->pic_struct == MSM_VIDC_PIC_STRUCT_PROGRESSIVE) || + (event_notify->pic_struct == MSM_VIDC_PIC_STRUCT_PROGRESSIVE && + inst->pic_struct == MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED)) + event_fields_changed = true; + + fmt = &inst->fmts[OUTPUT_PORT]; + event_fields_changed |= + (fmt->v4l2_fmt.fmt.pix_mp.height != + event_notify->height); + event_fields_changed |= + (fmt->v4l2_fmt.fmt.pix_mp.width != event_notify->width); + + if (event_fields_changed) { + event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; + } else { + inst->entropy_mode = event_notify->entropy_mode; + + /* configure work mode considering low latency*/ + if (is_low_latency_hint(inst)) { + rc = call_core_op(inst->core, decide_work_mode, + inst); + if (rc) + s_vpr_e(inst->sid, + "%s: Failed to decide work mode\n", + __func__); + } + /* Update driver buffer count */ + fmt->count_min = event_notify->fw_min_cnt; + msm_dcvs_reset(inst); + s_vpr_h(inst->sid, + "seq: No parameter change continue session\n"); + rc = call_hfi_op(hdev, session_continue, + (void *)inst->session); + if (rc) { + s_vpr_e(inst->sid, + "failed to send session_continue\n"); + } + goto err_bad_event; + } + break; + } + case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES: + event = V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT; + break; + case HAL_EVENT_RELEASE_BUFFER_REFERENCE: + { + struct msm_vidc_buffer *mbuf; + u32 planes[VIDEO_MAX_PLANES] = {0}; + + s_vpr_l(inst->sid, + "rbr: data_buffer: %x extradata_buffer: %x\n", + event_notify->packet_buffer, + event_notify->extra_data_buffer); + + planes[0] = event_notify->packet_buffer; + planes[1] = event_notify->extra_data_buffer; + mbuf = msm_comm_get_buffer_using_device_planes(inst, + OUTPUT_MPLANE, planes); + if (!mbuf || !kref_get_mbuf(inst, mbuf)) { + s_vpr_e(inst->sid, + "%s: data_addr %x, extradata_addr %x not found\n", + __func__, planes[0], planes[1]); + } else { + handle_release_buffer_reference(inst, mbuf); + kref_put_mbuf(mbuf); + } + goto err_bad_event; + } + default: + break; + } + + /* Bit depth and pic struct changed event are combined into a single + * event (insufficient event) for the userspace. Currently bitdepth + * changes is only for HEVC and interlaced support is for all + * codecs except HEVC + * event data is now as follows: + * u32 *ptr = seq_changed_event.u.data; + * ptr[MSM_VIDC_HEIGHT] = height + * ptr[MSM_VIDC_WIDTH] = width + * ptr[MSM_VIDC_BIT_DEPTH] = bit depth + * ptr[MSM_VIDC_PIC_STRUCT] = pic struct (progressive or interlaced) + * ptr[MSM_VIDC_COLOR_SPACE] = colour space + * ptr[MSM_VIDC_FW_MIN_COUNT] = fw min count + */ + + inst->profile = event_notify->profile; + inst->level = event_notify->level; + inst->entropy_mode = event_notify->entropy_mode; + /* HW returns progressive_only flag in pic_struct. */ + inst->pic_struct = + event_notify->pic_struct ? + MSM_VIDC_PIC_STRUCT_PROGRESSIVE : + MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED; + inst->colour_space = event_notify->colour_space; + + ptr = (u32 *)seq_changed_event.u.data; + ptr[MSM_VIDC_HEIGHT] = event_notify->height; + ptr[MSM_VIDC_WIDTH] = event_notify->width; + ptr[MSM_VIDC_BIT_DEPTH] = event_notify->bit_depth; + ptr[MSM_VIDC_PIC_STRUCT] = event_notify->pic_struct; + ptr[MSM_VIDC_COLOR_SPACE] = event_notify->colour_space; + + s_vpr_h(inst->sid, "seq: height = %u width = %u\n", + event_notify->height, event_notify->width); + + s_vpr_h(inst->sid, + "seq: bit_depth = %u pic_struct = %u colour_space = %u\n", + event_notify->bit_depth, event_notify->pic_struct, + event_notify->colour_space); + + s_vpr_h(inst->sid, "seq: fw_min_count = %u\n", + event_notify->fw_min_cnt); + + mutex_lock(&inst->lock); + inst->in_reconfig = true; + fmt = &inst->fmts[INPUT_PORT]; + fmt->v4l2_fmt.fmt.pix_mp.height = event_notify->height; + fmt->v4l2_fmt.fmt.pix_mp.width = event_notify->width; + inst->bit_depth = event_notify->bit_depth; + + fmt = &inst->fmts[OUTPUT_PORT]; + fmt->v4l2_fmt.fmt.pix_mp.height = event_notify->height; + fmt->v4l2_fmt.fmt.pix_mp.width = event_notify->width; + mutex_unlock(&inst->lock); + + if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) { + s_vpr_h(inst->sid, + "seq: V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n"); + + /* decide batching as configuration changed */ + inst->batch.enable = is_batching_allowed(inst); + s_vpr_hp(inst->sid, "seq : batching %s\n", + inst->batch.enable ? "enabled" : "disabled"); + msm_dcvs_try_enable(inst); + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_OUTPUT); + fmt->count_min = event_notify->fw_min_cnt; + fmt->count_min_host = fmt->count_min + extra_buff_count; + s_vpr_h(inst->sid, + "seq: hal buffer[%d] count: min %d min_host %d\n", + HAL_BUFFER_OUTPUT, fmt->count_min, + fmt->count_min_host); + } + ptr[MSM_VIDC_FW_MIN_COUNT] = fmt->count_min_host; + + rc = msm_vidc_check_session_supported(inst); + if (!rc) { + seq_changed_event.type = event; + v4l2_event_queue_fh(&inst->event_handler, &seq_changed_event); + } else if (rc == -ENOTSUPP) { + msm_vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED); + } else if (rc == -EBUSY) { + msm_vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_HW_OVERLOAD); + } + s_vpr_l(inst->sid, "handled: SESSION_EVENT_CHANGE\n"); + +err_bad_event: + put_inst(inst); +} + +static void handle_session_prop_info(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct getprop_buf *getprop; + struct msm_vidc_inst *inst; + + if (!response) { + d_vpr_e("Failed to get valid response for prop info\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + getprop = kzalloc(sizeof(*getprop), GFP_KERNEL); + if (!getprop) { + s_vpr_e(inst->sid, "%s: getprop kzalloc failed\n", __func__); + goto err_prop_info; + } + + getprop->data = kmemdup((void *) (&response->data.property), + sizeof(union hal_get_property), GFP_KERNEL); + if (!getprop->data) { + s_vpr_e(inst->sid, "%s: kmemdup failed\n", __func__); + kfree(getprop); + goto err_prop_info; + } + + mutex_lock(&inst->pending_getpropq.lock); + list_add_tail(&getprop->list, &inst->pending_getpropq.list); + mutex_unlock(&inst->pending_getpropq.lock); + s_vpr_l(inst->sid, "handled: SESSION_PROPERTY_INFO\n"); + signal_session_msg_receipt(cmd, inst); + +err_prop_info: + put_inst(inst); +} + +static void handle_load_resource_done(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + + if (!response) { + d_vpr_e("Failed to get valid response for load resource\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + if (response->status) { + s_vpr_e(inst->sid, "Load resource response from FW : %#x\n", + response->status); + msm_comm_generate_session_error(inst); + } + + s_vpr_l(inst->sid, "handled: SESSION_LOAD_RESOURCE_DONE\n"); + put_inst(inst); +} + +static void handle_start_done(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + + if (!response) { + d_vpr_e("Failed to get valid response for start\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + s_vpr_l(inst->sid, "handled: SESSION_START_DONE\n"); + + signal_session_msg_receipt(cmd, inst); + put_inst(inst); +} + +static void handle_stop_done(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + + if (!response) { + d_vpr_e("Failed to get valid response for stop\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + s_vpr_l(inst->sid, "handled: SESSION_STOP_DONE\n"); + signal_session_msg_receipt(cmd, inst); + put_inst(inst); +} + +static void handle_release_res_done(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + + if (!response) { + d_vpr_e("Failed to get valid response for release resource\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + s_vpr_l(inst->sid, "handled: SESSION_RELEASE_RESOURCE_DONE\n"); + signal_session_msg_receipt(cmd, inst); + put_inst(inst); +} + +void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst) +{ + struct internal_buf *binfo; + u32 buffers_owned_by_driver = 0; + struct hal_buffer_requirements *dpb = NULL; + u32 i; + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + if (inst->buff_req.buffer[i].buffer_type == HAL_BUFFER_OUTPUT) { + dpb = &inst->buff_req.buffer[i]; + break; + } + } + if (!dpb) { + s_vpr_e(inst->sid, "Couldn't retrieve dpb buf req\n"); + return; + } + + mutex_lock(&inst->outputbufs.lock); + if (list_empty(&inst->outputbufs.list)) { + s_vpr_h(inst->sid, "%s: no OUTPUT buffers allocated\n", + __func__); + mutex_unlock(&inst->outputbufs.lock); + return; + } + list_for_each_entry(binfo, &inst->outputbufs.list, list) { + if (binfo->buffer_ownership != DRIVER) { + s_vpr_h(inst->sid, "This buffer is with FW %x\n", + binfo->smem.device_addr); + continue; + } + buffers_owned_by_driver++; + } + mutex_unlock(&inst->outputbufs.lock); + + if (buffers_owned_by_driver != dpb->buffer_count_actual) { + s_vpr_e(inst->sid, "OUTPUT Buffer count mismatch %d of %d\n", + buffers_owned_by_driver, + dpb->buffer_count_actual); + msm_vidc_handle_hw_error(inst->core); + } +} + +int msm_comm_queue_dpb_only_buffers(struct msm_vidc_inst *inst) +{ + struct internal_buf *binfo, *extra_info; + struct hfi_device *hdev; + struct vidc_frame_data frame_data = {0}; + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + extra_info = inst->dpb_extra_binfo; + mutex_lock(&inst->outputbufs.lock); + list_for_each_entry(binfo, &inst->outputbufs.list, list) { + if (binfo->buffer_ownership != DRIVER) + continue; + if (binfo->mark_remove) + continue; + frame_data.alloc_len = binfo->smem.size; + frame_data.filled_len = 0; + frame_data.offset = 0; + frame_data.device_addr = binfo->smem.device_addr; + frame_data.flags = 0; + frame_data.extradata_addr = + extra_info ? extra_info->smem.device_addr : 0; + frame_data.buffer_type = HAL_BUFFER_OUTPUT; + frame_data.extradata_size = + extra_info ? extra_info->smem.size : 0; + rc = call_hfi_op(hdev, session_ftb, + (void *) inst->session, &frame_data); + binfo->buffer_ownership = FIRMWARE; + } + mutex_unlock(&inst->outputbufs.lock); + + return rc; +} + +static void handle_session_flush(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + struct v4l2_event flush_event = {0}; + u32 *ptr = NULL; + enum hal_flush flush_type; + int rc; + + if (!response) { + d_vpr_e("Failed to get valid response for flush\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_lock(&inst->bufq[INPUT_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + + if (!(get_v4l2_codec(inst) == V4L2_PIX_FMT_VP9 && + inst->in_reconfig)) + msm_comm_validate_output_buffers(inst); + + if (!inst->in_reconfig) { + rc = msm_comm_queue_dpb_only_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed to queue output buffers\n"); + } + } + } + flush_event.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE; + ptr = (u32 *)flush_event.u.data; + + flush_type = response->data.flush_type; + switch (flush_type) { + case HAL_FLUSH_INPUT: + inst->in_flush = false; + ptr[0] = V4L2_CMD_FLUSH_OUTPUT; + break; + case HAL_FLUSH_OUTPUT: + inst->out_flush = false; + ptr[0] = V4L2_CMD_FLUSH_CAPTURE; + break; + case HAL_FLUSH_ALL: + inst->in_flush = false; + inst->out_flush = false; + ptr[0] |= V4L2_CMD_FLUSH_CAPTURE; + ptr[0] |= V4L2_CMD_FLUSH_OUTPUT; + break; + default: + s_vpr_e(inst->sid, "Invalid flush type received!"); + goto exit; + } + + if (flush_type == HAL_FLUSH_ALL) { + msm_comm_clear_window_data(inst); + inst->clk_data.buffer_counter = 0; + } + + s_vpr_h(inst->sid, + "Notify flush complete, flush_type: %x\n", flush_type); + v4l2_event_queue_fh(&inst->event_handler, &flush_event); + +exit: + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_unlock(&inst->bufq[INPUT_PORT].lock); + s_vpr_l(inst->sid, "handled: SESSION_FLUSH_DONE\n"); + put_inst(inst); +} + +static void handle_session_error(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct hfi_device *hdev = NULL; + struct msm_vidc_inst *inst = NULL; + int event = V4L2_EVENT_MSM_VIDC_SYS_ERROR; + + if (!response) { + d_vpr_e("Failed to get valid response for session error\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + hdev = inst->core->device; + s_vpr_e(inst->sid, "Session error received for inst %pK\n", inst); + + if (response->status == VIDC_ERR_MAX_CLIENTS) { + s_vpr_e(inst->sid, "Too many clients, rejecting %pK", inst); + event = V4L2_EVENT_MSM_VIDC_MAX_CLIENTS; + + /* + * Clean the HFI session now. Since inst->state is moved to + * INVALID, forward thread doesn't know FW has valid session + * or not. This is the last place driver knows that there is + * no session in FW. Hence clean HFI session now. + */ + + msm_comm_session_clean(inst); + } else if (response->status == VIDC_ERR_NOT_SUPPORTED) { + s_vpr_e(inst->sid, "Unsupported bitstream in %pK", inst); + event = V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED; + } else { + s_vpr_e(inst->sid, "Unknown session error (%d) for %pK\n", + response->status, inst); + event = V4L2_EVENT_MSM_VIDC_SYS_ERROR; + } + + /* change state before sending error to client */ + change_inst_state(inst, MSM_VIDC_CORE_INVALID); + msm_vidc_queue_v4l2_event(inst, event); + s_vpr_l(inst->sid, "handled: SESSION_ERROR\n"); + put_inst(inst); +} + +static void msm_comm_clean_notify_client(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *inst = NULL; + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + d_vpr_e("%s: Core %pK\n", __func__, core); + mutex_lock(&core->lock); + + list_for_each_entry(inst, &core->instances, list) { + mutex_lock(&inst->lock); + inst->state = MSM_VIDC_CORE_INVALID; + mutex_unlock(&inst->lock); + s_vpr_e(inst->sid, + "%s: Send sys error for inst %pK\n", __func__, inst); + msm_vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_SYS_ERROR); + } + mutex_unlock(&core->lock); +} + +static void handle_sys_error(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_core *core = NULL; + struct hfi_device *hdev = NULL; + struct msm_vidc_inst *inst = NULL; + int rc = 0; + + subsystem_crashed("venus"); + if (!response) { + d_vpr_e("Failed to get valid response for sys error\n"); + return; + } + + core = get_vidc_core(response->device_id); + if (!core) { + d_vpr_e("Got SYS_ERR but unable to identify core\n"); + return; + } + hdev = core->device; + + mutex_lock(&core->lock); + if (core->state == VIDC_CORE_UNINIT) { + d_vpr_e("%s: Core %pK already moved to state %d\n", + __func__, core, core->state); + mutex_unlock(&core->lock); + return; + } + + d_vpr_e("SYS_ERROR received for core %pK\n", core); + msm_vidc_noc_error_info(core); + call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); + list_for_each_entry(inst, &core->instances, list) { + s_vpr_e(inst->sid, + "%s: Send sys error for inst %pK\n", __func__, inst); + change_inst_state(inst, MSM_VIDC_CORE_INVALID); + msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); + if (!core->trigger_ssr) + msm_comm_print_inst_info(inst); + } + + /* handle the hw error before core released to get full debug info */ + msm_vidc_handle_hw_error(core); + if ((response->status == VIDC_ERR_NOC_ERROR && + (msm_vidc_err_recovery_disable & + VIDC_DISABLE_NOC_ERR_RECOV)) || + (msm_vidc_err_recovery_disable & + VIDC_DISABLE_NON_NOC_ERR_RECOV)) { + d_vpr_e("Got unrecoverable video fw error"); + MSM_VIDC_ERROR(true); + } + + d_vpr_e("Calling core_release\n"); + rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data); + if (rc) { + d_vpr_e("core_release failed\n"); + mutex_unlock(&core->lock); + return; + } + core->state = VIDC_CORE_UNINIT; + mutex_unlock(&core->lock); + + d_vpr_l("handled: SYS_ERROR\n"); +} + +void msm_comm_session_clean(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev = NULL; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return; + } + if (!inst->session) { + s_vpr_h(inst->sid, "%s: inst %pK session already cleaned\n", + __func__, inst); + return; + } + + hdev = inst->core->device; + mutex_lock(&inst->lock); + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_clean, + (void *)inst->session); + if (rc) { + s_vpr_e(inst->sid, "Session clean failed :%pK\n", inst); + } + inst->session = NULL; + mutex_unlock(&inst->lock); +} + +static void handle_session_close(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_cmd_done *response = data; + struct msm_vidc_inst *inst; + + if (!response) { + d_vpr_e("Failed to get valid response for session close\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + s_vpr_l(inst->sid, "handled: SESSION_END_DONE\n"); + signal_session_msg_receipt(cmd, inst); + show_stats(inst); + put_inst(inst); +} + +struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( + struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) +{ + u32 port = 0; + struct vb2_buffer *vb = NULL; + struct vb2_queue *q = NULL; + bool found = false; + + if (mbuf->vvb.vb2_buf.type == OUTPUT_MPLANE) { + port = OUTPUT_PORT; + } else if (mbuf->vvb.vb2_buf.type == INPUT_MPLANE) { + port = INPUT_PORT; + } else { + s_vpr_e(inst->sid, "%s: invalid type %d\n", + __func__, mbuf->vvb.vb2_buf.type); + return NULL; + } + + WARN_ON(!mutex_is_locked(&inst->bufq[port].lock)); + found = false; + q = &inst->bufq[port].vb2_bufq; + if (!q->streaming) { + s_vpr_e(inst->sid, "port %d is not streaming", port); + goto unlock; + } + list_for_each_entry(vb, &q->queued_list, queued_entry) { + if (vb->state != VB2_BUF_STATE_ACTIVE) + continue; + if (msm_comm_compare_vb2_planes(inst, mbuf, vb)) { + found = true; + break; + } + } +unlock: + if (!found) { + print_vidc_buffer(VIDC_ERR, "vb2 not found for", inst, mbuf); + return NULL; + } + + return vb; +} + +int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + struct vb2_buffer *vb2; + struct vb2_v4l2_buffer *vbuf; + u32 i, port; + int rc = 0; + + if (!inst || !mbuf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + + if (mbuf->vvb.vb2_buf.type == OUTPUT_MPLANE) + port = OUTPUT_PORT; + else if (mbuf->vvb.vb2_buf.type == INPUT_MPLANE) + port = INPUT_PORT; + else + return -EINVAL; + + /* + * access vb2 buffer under q->lock and if streaming only to + * ensure the buffer was not free'd by vb2 framework while + * we are accessing it here. + */ + mutex_lock(&inst->bufq[port].lock); + vb2 = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); + if (!vb2) { + s_vpr_e(inst->sid, "%s: port %d buffer not found\n", + __func__, port); + rc = -EINVAL; + goto unlock; + } + if (inst->bufq[port].vb2_bufq.streaming) { + vbuf = to_vb2_v4l2_buffer(vb2); + vbuf->flags = mbuf->vvb.flags; + vb2->timestamp = mbuf->vvb.vb2_buf.timestamp; + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + vb2->planes[i].bytesused = + mbuf->vvb.vb2_buf.planes[i].bytesused; + vb2->planes[i].data_offset = + mbuf->vvb.vb2_buf.planes[i].data_offset; + } + vb2_buffer_done(vb2, VB2_BUF_STATE_DONE); + } else { + s_vpr_e(inst->sid, "%s: port %d is not streaming\n", + __func__, port); + } +unlock: + mutex_unlock(&inst->bufq[port].lock); + + return rc; +} + +static bool is_eos_buffer(struct msm_vidc_inst *inst, u32 device_addr) +{ + struct eos_buf *temp, *next; + bool found = false; + + mutex_lock(&inst->eosbufs.lock); + list_for_each_entry_safe(temp, next, &inst->eosbufs.list, list) { + if (temp->smem.device_addr == device_addr) { + found = true; + temp->is_queued = 0; + list_del(&temp->list); + msm_comm_smem_free(inst, &temp->smem); + kfree(temp); + break; + } + } + mutex_unlock(&inst->eosbufs.lock); + + return found; +} + +static void handle_ebd(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_data_done *response = data; + struct msm_vidc_buffer *mbuf; + struct vb2_buffer *vb; + struct msm_vidc_inst *inst; + struct vidc_hal_ebd *empty_buf_done; + u32 planes[VIDEO_MAX_PLANES] = {0}; + struct v4l2_format *f; + struct v4l2_ctrl *ctrl; + + if (!response) { + d_vpr_e("Invalid response from vidc_hal\n"); + return; + } + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + empty_buf_done = (struct vidc_hal_ebd *)&response->input_done; + /* If this is internal EOS buffer, handle it in driver */ + if (is_eos_buffer(inst, empty_buf_done->packet_buffer)) { + s_vpr_h(inst->sid, "Received EOS buffer 0x%x\n", + empty_buf_done->packet_buffer); + goto exit; + } + + planes[0] = empty_buf_done->packet_buffer; + planes[1] = empty_buf_done->extra_data_buffer; + + mbuf = msm_comm_get_buffer_using_device_planes(inst, + INPUT_MPLANE, planes); + if (!mbuf || !kref_get_mbuf(inst, mbuf)) { + s_vpr_e(inst->sid, + "%s: data_addr %x, extradata_addr %x not found\n", + __func__, planes[0], planes[1]); + goto exit; + } + vb = &mbuf->vvb.vb2_buf; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val && empty_buf_done->offset + + empty_buf_done->filled_len < vb->planes[0].length) { + s_vpr_h(inst->sid, + "%s: addr (%#x): offset (%d) + filled_len (%d) < length (%d)\n", + __func__, empty_buf_done->packet_buffer, + empty_buf_done->offset, + empty_buf_done->filled_len, + vb->planes[0].length); + kref_put_mbuf(mbuf); + goto exit; + } + + mbuf->flags &= ~MSM_VIDC_FLAG_QUEUED; + vb->planes[0].bytesused = response->input_done.filled_len; + if (vb->planes[0].bytesused > vb->planes[0].length) + s_vpr_l(inst->sid, "bytesused overflow length\n"); + + vb->planes[0].data_offset = response->input_done.offset; + if (vb->planes[0].data_offset > vb->planes[0].length) + s_vpr_l(inst->sid, "data_offset overflow length\n"); + + if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) { + s_vpr_l(inst->sid, "Failed : Unsupported input stream\n"); + mbuf->vvb.flags |= V4L2_BUF_INPUT_UNSUPPORTED; + } + if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) { + s_vpr_l(inst->sid, "Failed : Corrupted input stream\n"); + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; + } + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + if (f->fmt.pix_mp.num_planes > 1) + vb->planes[1].bytesused = vb->planes[1].length; + + update_recon_stats(inst, &empty_buf_done->recon_stats); + inst->clk_data.buffer_counter++; + /* + * dma cache operations need to be performed before dma_unmap + * which is done inside msm_comm_put_vidc_buffer() + */ + msm_comm_dqbuf_cache_operations(inst, mbuf); + /* + * put_buffer should be done before vb2_buffer_done else + * client might queue the same buffer before it is unmapped + * in put_buffer. + */ + msm_comm_put_vidc_buffer(inst, mbuf); + msm_comm_vb2_buffer_done(inst, mbuf); + msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD); + kref_put_mbuf(mbuf); +exit: + s_vpr_l(inst->sid, "handled: SESSION_ETB_DONE\n"); + put_inst(inst); +} + +static int handle_multi_stream_buffers(struct msm_vidc_inst *inst, + u32 dev_addr) +{ + struct internal_buf *binfo; + struct msm_smem *smem; + bool found = false; + + mutex_lock(&inst->outputbufs.lock); + list_for_each_entry(binfo, &inst->outputbufs.list, list) { + smem = &binfo->smem; + if (smem && dev_addr == smem->device_addr) { + if (binfo->buffer_ownership == DRIVER) { + s_vpr_e(inst->sid, + "FW returned same buffer: %x\n", + dev_addr); + break; + } + binfo->buffer_ownership = DRIVER; + found = true; + break; + } + } + mutex_unlock(&inst->outputbufs.lock); + + if (!found) { + s_vpr_e(inst->sid, + "Failed to find output buffer in queued list: %x\n", + dev_addr); + } + + return 0; +} + +enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst) +{ + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) + return HAL_BUFFER_OUTPUT2; + else + return HAL_BUFFER_OUTPUT; +} + +static void handle_fbd(enum hal_command_response cmd, void *data) +{ + struct msm_vidc_cb_data_done *response = data; + struct msm_vidc_buffer *mbuf; + struct msm_vidc_inst *inst; + struct vb2_buffer *vb; + struct vidc_hal_fbd *fill_buf_done; + enum hal_buffer buffer_type; + u64 time_usec = 0; + u32 planes[VIDEO_MAX_PLANES] = {0}; + struct v4l2_format *f; + int rc = 0; + + if (!response) { + d_vpr_e("Invalid response from vidc_hal\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->inst_id); + if (!inst) { + d_vpr_e("Got a response for an inactive session\n"); + return; + } + + fill_buf_done = (struct vidc_hal_fbd *)&response->output_done; + planes[0] = fill_buf_done->packet_buffer1; + planes[1] = fill_buf_done->extra_data_buffer; + + buffer_type = msm_comm_get_hal_output_buffer(inst); + if (fill_buf_done->buffer_type == buffer_type) { + mbuf = msm_comm_get_buffer_using_device_planes(inst, + OUTPUT_MPLANE, planes); + if (!mbuf || !kref_get_mbuf(inst, mbuf)) { + s_vpr_e(inst->sid, + "%s: data_addr %x, extradata_addr %x not found\n", + __func__, planes[0], planes[1]); + goto exit; + } + } else { + if (handle_multi_stream_buffers(inst, + fill_buf_done->packet_buffer1)) + s_vpr_e(inst->sid, + "Failed : Output buffer not found %pa\n", + &fill_buf_done->packet_buffer1); + goto exit; + } + mbuf->flags &= ~MSM_VIDC_FLAG_QUEUED; + vb = &mbuf->vvb.vb2_buf; + + if (fill_buf_done->buffer_type == HAL_BUFFER_OUTPUT2 && + fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY) { + s_vpr_e(inst->sid, "%s: Read only buffer not allowed for OPB\n", + __func__); + goto exit; + } + + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DROP_FRAME) + fill_buf_done->filled_len1 = 0; + vb->planes[0].bytesused = fill_buf_done->filled_len1; + if (vb->planes[0].bytesused > vb->planes[0].length) + s_vpr_l(inst->sid, "fbd:Overflow bytesused = %d; length = %d\n", + vb->planes[0].bytesused, + vb->planes[0].length); + vb->planes[0].data_offset = fill_buf_done->offset1; + if (vb->planes[0].data_offset > vb->planes[0].length) + s_vpr_l(inst->sid, + "fbd:Overflow data_offset = %d; length = %d\n", + vb->planes[0].data_offset, vb->planes[0].length); + + time_usec = fill_buf_done->timestamp_hi; + time_usec = (time_usec << 32) | fill_buf_done->timestamp_lo; + + vb->timestamp = (time_usec * NSEC_PER_USEC); + + rc = msm_comm_store_input_tag(&inst->fbd_data, vb->index, + fill_buf_done->input_tag, + fill_buf_done->input_tag2, inst->sid); + if (rc) + s_vpr_e(inst->sid, "Failed to store input tag"); + + if (inst->session_type == MSM_VIDC_ENCODER) { + if (inst->max_filled_len < fill_buf_done->filled_len1) + inst->max_filled_len = fill_buf_done->filled_len1; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + if (f->fmt.pix_mp.num_planes > 1) + vb->planes[1].bytesused = vb->planes[1].length; + + mbuf->vvb.flags = 0; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY) + mbuf->vvb.flags |= V4L2_BUF_FLAG_READONLY; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS) + mbuf->vvb.flags |= V4L2_BUF_FLAG_EOS; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG) + mbuf->vvb.flags |= V4L2_BUF_FLAG_CODECCONFIG; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_SYNCFRAME) + mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_DATACORRUPT) + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_ENDOFSUBFRAME) + mbuf->vvb.flags |= V4L2_BUF_FLAG_END_OF_SUBFRAME; + switch (fill_buf_done->picture_type) { + case HFI_PICTURE_TYPE_P: + mbuf->vvb.flags |= V4L2_BUF_FLAG_PFRAME; + break; + case HFI_PICTURE_TYPE_B: + mbuf->vvb.flags |= V4L2_BUF_FLAG_BFRAME; + break; + case HFI_FRAME_NOTCODED: + case HFI_UNUSED_PICT: + /* Do we need to care about these? */ + case HFI_FRAME_YUV: + break; + default: + break; + } + + /* + * dma cache operations need to be performed before dma_unmap + * which is done inside msm_comm_put_vidc_buffer() + */ + msm_comm_dqbuf_cache_operations(inst, mbuf); + /* + * put_buffer should be done before vb2_buffer_done else + * client might queue the same buffer before it is unmapped + * in put_buffer. + */ + msm_comm_put_vidc_buffer(inst, mbuf); + msm_comm_vb2_buffer_done(inst, mbuf); + msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_FBD); + kref_put_mbuf(mbuf); + +exit: + s_vpr_l(inst->sid, "handled: SESSION_FTB_DONE\n"); + put_inst(inst); +} + +void handle_cmd_response(enum hal_command_response cmd, void *data) +{ + switch (cmd) { + case HAL_SYS_INIT_DONE: + handle_sys_init_done(cmd, data); + break; + case HAL_SYS_RELEASE_RESOURCE_DONE: + handle_sys_release_res_done(cmd, data); + break; + case HAL_SESSION_INIT_DONE: + handle_session_init_done(cmd, data); + break; + case HAL_SESSION_PROPERTY_INFO: + handle_session_prop_info(cmd, data); + break; + case HAL_SESSION_LOAD_RESOURCE_DONE: + handle_load_resource_done(cmd, data); + break; + case HAL_SESSION_START_DONE: + handle_start_done(cmd, data); + break; + case HAL_SESSION_ETB_DONE: + handle_ebd(cmd, data); + break; + case HAL_SESSION_FTB_DONE: + handle_fbd(cmd, data); + break; + case HAL_SESSION_STOP_DONE: + handle_stop_done(cmd, data); + break; + case HAL_SESSION_RELEASE_RESOURCE_DONE: + handle_release_res_done(cmd, data); + break; + case HAL_SESSION_END_DONE: + case HAL_SESSION_ABORT_DONE: + handle_session_close(cmd, data); + break; + case HAL_SESSION_EVENT_CHANGE: + handle_event_change(cmd, data); + break; + case HAL_SESSION_FLUSH_DONE: + handle_session_flush(cmd, data); + break; + case HAL_SYS_WATCHDOG_TIMEOUT: + case HAL_SYS_ERROR: + handle_sys_error(cmd, data); + break; + case HAL_SESSION_ERROR: + handle_session_error(cmd, data); + break; + case HAL_SESSION_RELEASE_BUFFER_DONE: + handle_session_release_buf_done(cmd, data); + break; + case HAL_SESSION_REGISTER_BUFFER_DONE: + handle_session_register_buffer_done(cmd, data); + break; + case HAL_SESSION_UNREGISTER_BUFFER_DONE: + handle_session_unregister_buffer_done(cmd, data); + break; + default: + d_vpr_l("response unhandled: %d\n", cmd); + break; + } +} + +static inline enum msm_vidc_thermal_level msm_comm_vidc_thermal_level(int level) +{ + switch (level) { + case 0: + return VIDC_THERMAL_NORMAL; + case 1: + return VIDC_THERMAL_LOW; + case 2: + return VIDC_THERMAL_HIGH; + default: + return VIDC_THERMAL_CRITICAL; + } +} + +static bool is_core_turbo(struct msm_vidc_core *core, unsigned long freq) +{ + unsigned int i = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + u32 max_freq = 0; + + allowed_clks_tbl = core->resources.allowed_clks_tbl; + for (i = 0; i < core->resources.allowed_clks_tbl_size; i++) { + if (max_freq < allowed_clks_tbl[i].clock_rate) + max_freq = allowed_clks_tbl[i].clock_rate; + } + return freq >= max_freq; +} + +static bool is_thermal_permissible(struct msm_vidc_core *core) +{ + enum msm_vidc_thermal_level tl; + unsigned long freq = 0; + bool is_turbo = false; + + if (!core->resources.thermal_mitigable) + return true; + + if (msm_vidc_thermal_mitigation_disabled) { + d_vpr_h("Thermal mitigation not enabled. debugfs %d\n", + msm_vidc_thermal_mitigation_disabled); + return true; + } + + tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level); + freq = core->curr_freq; + + is_turbo = is_core_turbo(core, freq); + d_vpr_h("Core freq %ld Thermal level %d Turbo mode %d\n", + freq, tl, is_turbo); + + if (is_turbo && tl >= VIDC_THERMAL_LOW) { + d_vpr_e( + "Video session not allowed. Turbo mode %d Thermal level %d\n", + is_turbo, tl); + return false; + } + return true; +} + +bool is_batching_allowed(struct msm_vidc_inst *inst) +{ + u32 op_pixelformat, fps, maxmbs, maxfps; + u32 ignore_flags = VIDC_THUMBNAIL; + + if (!inst || !inst->core) + return false; + + /* Enable decode batching based on below conditions */ + op_pixelformat = + inst->fmts[OUTPUT_PORT].v4l2_fmt.fmt.pix_mp.pixelformat; + fps = inst->clk_data.frame_rate >> 16; + maxmbs = inst->capability.cap[CAP_BATCH_MAX_MB_PER_FRAME].max; + maxfps = inst->capability.cap[CAP_BATCH_MAX_FPS].max; + + /* + * if batching enabled previously then you may chose + * to disable it based on recent configuration changes. + * if batching already disabled do not enable it again + * as sufficient extra buffers (required for batch mode + * on both ports) may not have been updated to client. + */ + return (inst->batch.enable && + inst->core->resources.decode_batching && + !is_low_latency_hint(inst) && + is_single_session(inst, ignore_flags) && + is_decode_session(inst) && + !is_thumbnail_session(inst) && + !inst->clk_data.low_latency_mode && + (op_pixelformat == V4L2_PIX_FMT_NV12_UBWC || + op_pixelformat == V4L2_PIX_FMT_NV12_TP10_UBWC) && + fps <= maxfps && + msm_vidc_get_mbs_per_frame(inst) <= maxmbs); +} + +static int msm_comm_session_abort(struct msm_vidc_inst *inst) +{ + int rc = 0, abort_completion = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + hdev = inst->core->device; + abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE); + + s_vpr_e(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_abort, (void *)inst->session); + if (rc) { + s_vpr_e(inst->sid, + "%s: session_abort failed rc: %d\n", __func__, rc); + goto exit; + } + rc = wait_for_completion_timeout( + &inst->completions[abort_completion], + msecs_to_jiffies( + inst->core->resources.msm_vidc_hw_rsp_timeout)); + if (!rc) { + s_vpr_e(inst->sid, "%s: session abort timed out\n", __func__); + msm_comm_generate_sys_error(inst); + rc = -EBUSY; + } else { + rc = 0; + } +exit: + return rc; +} + +static void handle_thermal_event(struct msm_vidc_core *core) +{ + int rc = 0; + struct msm_vidc_inst *inst; + + if (!core || !core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return; + } + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (!inst->session) + continue; + + mutex_unlock(&core->lock); + if (inst->state >= MSM_VIDC_OPEN_DONE && + inst->state < MSM_VIDC_CLOSE_DONE) { + s_vpr_e(inst->sid, "%s: abort inst %pK\n", + __func__, inst); + rc = msm_comm_session_abort(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: session_abort failed rc: %d\n", + __func__, rc); + goto err_sess_abort; + } + change_inst_state(inst, MSM_VIDC_CORE_INVALID); + s_vpr_e(inst->sid, "%s: Send sys error for inst %pK\n", + __func__, inst); + msm_vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_SYS_ERROR); + } else { + msm_comm_generate_session_error(inst); + } + mutex_lock(&core->lock); + } + mutex_unlock(&core->lock); + return; + +err_sess_abort: + msm_comm_clean_notify_client(core); +} + +void msm_comm_handle_thermal_event(void) +{ + struct msm_vidc_core *core; + + list_for_each_entry(core, &vidc_driver->cores, list) { + if (!is_thermal_permissible(core)) { + d_vpr_e( + "Thermal level critical, stop active sessions\n"); + handle_thermal_event(core); + } + } +} + +int msm_comm_check_core_init(struct msm_vidc_core *core, u32 sid) +{ + int rc = 0; + + mutex_lock(&core->lock); + if (core->state >= VIDC_CORE_INIT_DONE) { + s_vpr_h(sid, "Video core: %d is already in state: %d\n", + core->id, core->state); + goto exit; + } + s_vpr_h(sid, "Waiting for SYS_INIT_DONE\n"); + rc = wait_for_completion_timeout( + &core->completions[SYS_MSG_INDEX(HAL_SYS_INIT_DONE)], + msecs_to_jiffies(core->resources.msm_vidc_hw_rsp_timeout)); + if (!rc) { + s_vpr_e(sid, "%s: Wait interrupted or timed out: %d\n", + __func__, SYS_MSG_INDEX(HAL_SYS_INIT_DONE)); + rc = -EIO; + goto exit; + } else { + core->state = VIDC_CORE_INIT_DONE; + rc = 0; + } + s_vpr_h(sid, "SYS_INIT_DONE!!!\n"); +exit: + mutex_unlock(&core->lock); + return rc; +} + +static int msm_comm_init_core_done(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_comm_check_core_init(inst->core, inst->sid); + if (rc) { + d_vpr_e("%s: failed to initialize core\n", __func__); + msm_comm_generate_sys_error(inst); + return rc; + } + change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE); + return rc; +} + +static int msm_comm_init_core(struct msm_vidc_inst *inst) +{ + int rc, i; + struct hfi_device *hdev; + struct msm_vidc_core *core; + + if (!inst || !inst->core || !inst->core->device) + return -EINVAL; + + core = inst->core; + hdev = core->device; + mutex_lock(&core->lock); + if (core->state >= VIDC_CORE_INIT) { + s_vpr_h(inst->sid, "Video core: %d is already in state: %d\n", + core->id, core->state); + goto core_already_inited; + } + s_vpr_h(inst->sid, "%s: core %pK\n", __func__, core); + rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data); + if (rc) { + s_vpr_e(inst->sid, "Failed to init core, id = %d\n", + core->id); + goto fail_core_init; + } + + /* initialize core while firmware processing SYS_INIT cmd */ + core->state = VIDC_CORE_INIT; + core->smmu_fault_handled = false; + core->trigger_ssr = false; + core->resources.max_inst_count = MAX_SUPPORTED_INSTANCES; + core->resources.max_secure_inst_count = + core->resources.max_secure_inst_count ? + core->resources.max_secure_inst_count : + core->resources.max_inst_count; + s_vpr_h(inst->sid, "%s: codecs count %d, max inst count %d\n", + __func__, core->resources.codecs_count, + core->resources.max_inst_count); + if (!core->resources.codecs || !core->resources.codecs_count) { + s_vpr_e(inst->sid, "%s: invalid codecs\n", __func__); + rc = -EINVAL; + goto fail_core_init; + } + if (!core->capabilities) { + core->capabilities = kcalloc(core->resources.codecs_count, + sizeof(struct msm_vidc_capability), GFP_KERNEL); + if (!core->capabilities) { + s_vpr_e(inst->sid, + "%s: failed to allocate capabilities\n", + __func__); + rc = -ENOMEM; + goto fail_core_init; + } + } else { + s_vpr_e(inst->sid, + "%s: capabilities memory is expected to be freed\n", + __func__); + } + for (i = 0; i < core->resources.codecs_count; i++) { + core->capabilities[i].domain = + core->resources.codecs[i].domain; + core->capabilities[i].codec = + core->resources.codecs[i].codec; + } + rc = msm_vidc_capabilities(core); + if (rc) { + s_vpr_e(inst->sid, + "%s: default capabilities failed\n", __func__); + kfree(core->capabilities); + core->capabilities = NULL; + goto fail_core_init; + } + s_vpr_h(inst->sid, "%s: done\n", __func__); +core_already_inited: + change_inst_state(inst, MSM_VIDC_CORE_INIT); + mutex_unlock(&core->lock); + + rc = msm_comm_scale_clocks_and_bus(inst, 1); + return rc; + +fail_core_init: + core->state = VIDC_CORE_UNINIT; + mutex_unlock(&core->lock); + return rc; +} + +static int msm_vidc_deinit_core(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + core = inst->core; + hdev = core->device; + + mutex_lock(&core->lock); + if (core->state == VIDC_CORE_UNINIT) { + s_vpr_h(inst->sid, "Video core: %d is already in state: %d\n", + core->id, core->state); + goto core_already_uninited; + } + mutex_unlock(&core->lock); + + msm_comm_scale_clocks_and_bus(inst, 1); + + mutex_lock(&core->lock); + + if (!core->resources.never_unload_fw) { + cancel_delayed_work(&core->fw_unload_work); + + /* + * Delay unloading of firmware. This is useful + * in avoiding firmware download delays in cases where we + * will have a burst of back to back video playback sessions + * e.g. thumbnail generation. + */ + schedule_delayed_work(&core->fw_unload_work, + msecs_to_jiffies(core->state == VIDC_CORE_INIT_DONE ? + core->resources.msm_vidc_firmware_unload_delay : 0)); + + s_vpr_h(inst->sid, "firmware unload delayed by %u ms\n", + core->state == VIDC_CORE_INIT_DONE ? + core->resources.msm_vidc_firmware_unload_delay : 0); + } + +core_already_uninited: + change_inst_state(inst, MSM_VIDC_CORE_UNINIT); + mutex_unlock(&core->lock); + return 0; +} + +int msm_comm_force_cleanup(struct msm_vidc_inst *inst) +{ + msm_comm_kill_session(inst); + return msm_vidc_deinit_core(inst); +} + +static int msm_comm_session_init_done(int flipped_state, + struct msm_vidc_inst *inst) +{ + int rc; + + if (!inst) { + d_vpr_e("Invalid parameter %s\n", __func__); + return -EINVAL; + } + s_vpr_h(inst->sid, "waiting for session init done\n"); + rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE, + HAL_SESSION_INIT_DONE); + if (rc) { + s_vpr_e(inst->sid, "Session init failed for inst %pK\n", inst); + msm_comm_generate_sys_error(inst); + return rc; + } + + return rc; +} + +static int msm_comm_session_init(int flipped_state, + struct msm_vidc_inst *inst) +{ + int rc = 0; + int fourcc = 0; + struct hfi_device *hdev; + struct v4l2_format *f; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + if (inst->session_type == MSM_VIDC_DECODER) { + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + fourcc = f->fmt.pix_mp.pixelformat; + } else if (inst->session_type == MSM_VIDC_ENCODER) { + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + fourcc = f->fmt.pix_mp.pixelformat; + } else if (inst->session_type == MSM_VIDC_CVP) { + fourcc = V4L2_PIX_FMT_CVP; + } else { + s_vpr_e(inst->sid, "Invalid session\n"); + return -EINVAL; + } + + rc = msm_comm_init_clocks_and_bus_data(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed to initialize clocks and bus data\n"); + goto exit; + } + + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data, + inst, get_hal_domain(inst->session_type, inst->sid), + get_hal_codec(fourcc, inst->sid), + &inst->session, inst->sid); + if (rc || !inst->session) { + s_vpr_e(inst->sid, + "Failed to call session init for: %pK, %pK, %d, %d\n", + inst->core->device, inst, + inst->session_type, fourcc); + rc = -EINVAL; + goto exit; + } + rc = msm_comm_update_capabilities(inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to update capabilities\n"); + goto exit; + } + rc = msm_vidc_calculate_buffer_counts(inst); + if (rc) { + s_vpr_e(inst->sid, "Failed to initialize buff counts\n"); + goto exit; + } + change_inst_state(inst, MSM_VIDC_OPEN); + +exit: + return rc; +} + +int msm_comm_update_dpb_bufreqs(struct msm_vidc_inst *inst) +{ + struct hal_buffer_requirements *req = NULL; + struct msm_vidc_format *fmt; + struct v4l2_format *f; + u32 i, hfi_fmt, rc = 0; + + if (!inst) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + if (msm_comm_get_stream_output_mode(inst) != + HAL_VIDEO_DECODER_SECONDARY) + return 0; + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + if (inst->buff_req.buffer[i].buffer_type == HAL_BUFFER_OUTPUT) { + req = &inst->buff_req.buffer[i]; + break; + } + } + + if (!req) { + s_vpr_e(inst->sid, "%s: req not found\n", __func__); + return -EINVAL; + } + + fmt = &inst->fmts[OUTPUT_PORT]; + /* For DPB buffers, Always use min count */ + req->buffer_count_min = req->buffer_count_min_host = + req->buffer_count_actual = fmt->count_min; + + hfi_fmt = msm_comm_convert_color_fmt(inst->clk_data.dpb_fourcc, + inst->sid); + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + req->buffer_size = VENUS_BUFFER_SIZE(hfi_fmt, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + + return rc; +} + +static int msm_comm_get_dpb_bufreqs(struct msm_vidc_inst *inst, + struct hal_buffer_requirements *req) +{ + struct hal_buffer_requirements *dpb = NULL; + u32 i; + + if (!inst || !req) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + if (msm_comm_get_stream_output_mode(inst) != + HAL_VIDEO_DECODER_SECONDARY) + return 0; + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + if (inst->buff_req.buffer[i].buffer_type == HAL_BUFFER_OUTPUT) { + dpb = &inst->buff_req.buffer[i]; + break; + } + } + + if (!dpb) { + s_vpr_e(inst->sid, "%s: req not found\n", __func__); + return -EINVAL; + } + + memcpy(req, dpb, sizeof(struct hal_buffer_requirements)); + + return 0; +} + +static void msm_comm_print_mem_usage(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *inst; + struct msm_vidc_format *inp_f, *out_f; + u32 dpb_cnt, dpb_size, i = 0, rc = 0; + struct v4l2_pix_format_mplane *iplane, *oplane; + u32 sz_i, sz_i_e, sz_o, sz_o_e, sz_s, sz_s1, sz_s2, sz_p, sz_p1, sz_r; + u32 cnt_i, cnt_o, cnt_s, cnt_s1, cnt_s2, cnt_p, cnt_p1, cnt_r; + u64 total; + + d_vpr_e("Running instances - mem breakup:\n"); + d_vpr_e( + "%4s|%4s|%24s|%24s|%24s|%24s|%24s|%10s|%10s|%10s|%10s|%10s|%10s|%10s\n", + "w", "h", "in", "extra_in", "out", "extra_out", + "out2", "scratch", "scratch_1", "scratch_2", + "persist", "persist_1", "recon", "total_kb"); + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + dpb_cnt = dpb_size = total = 0; + sz_s = sz_s1 = sz_s2 = sz_p = sz_p1 = sz_r = 0; + cnt_s = cnt_s1 = cnt_s2 = cnt_p = cnt_p1 = cnt_r = 0; + + inp_f = &inst->fmts[INPUT_PORT]; + out_f = &inst->fmts[OUTPUT_PORT]; + iplane = &inp_f->v4l2_fmt.fmt.pix_mp; + oplane = &out_f->v4l2_fmt.fmt.pix_mp; + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + struct hal_buffer_requirements dpb = {0}; + + rc = msm_comm_get_dpb_bufreqs(inst, &dpb); + if (rc) { + s_vpr_e(inst->sid, + "%s: get dpb bufreq failed\n", + __func__); + goto error; + } + dpb_cnt = dpb.buffer_count_actual; + dpb_size = dpb.buffer_size; + } + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements *req; + + req = &inst->buff_req.buffer[i]; + switch (req->buffer_type) { + case HAL_BUFFER_INTERNAL_SCRATCH: + sz_s = req->buffer_size; + cnt_s = req->buffer_count_actual; + break; + case HAL_BUFFER_INTERNAL_SCRATCH_1: + sz_s1 = req->buffer_size; + cnt_s1 = req->buffer_count_actual; + break; + case HAL_BUFFER_INTERNAL_SCRATCH_2: + sz_s2 = req->buffer_size; + cnt_s2 = req->buffer_count_actual; + break; + case HAL_BUFFER_INTERNAL_PERSIST: + sz_p = req->buffer_size; + cnt_p = req->buffer_count_actual; + break; + case HAL_BUFFER_INTERNAL_PERSIST_1: + sz_p1 = req->buffer_size; + cnt_p1 = req->buffer_count_actual; + break; + case HAL_BUFFER_INTERNAL_RECON: + sz_r = req->buffer_size; + cnt_r = req->buffer_count_actual; + break; + default: + break; + } + } + sz_i = iplane->plane_fmt[0].sizeimage; + sz_i_e = iplane->plane_fmt[1].sizeimage; + cnt_i = inp_f->count_min_host; + + sz_o = oplane->plane_fmt[0].sizeimage; + sz_o_e = oplane->plane_fmt[1].sizeimage; + cnt_o = out_f->count_min_host; + + total = sz_i * cnt_i + sz_i_e * cnt_i + sz_o * cnt_o + + sz_o_e * cnt_o + dpb_cnt * dpb_size + sz_s * cnt_s + + sz_s1 * cnt_s1 + sz_s2 * cnt_s2 + sz_p * cnt_p + + sz_p1 * cnt_p1 + sz_r * cnt_r; + total = total >> 10; + + s_vpr_e(inst->sid, + "%4d|%4d|%11u(%8ux%2u)|%11u(%8ux%2u)|%11u(%8ux%2u)|%11u(%8ux%2u)|%11u(%8ux%2u)|%10u|%10u|%10u|%10u|%10u|%10u|%10llu\n", + max(iplane->width, oplane->width), + max(iplane->height, oplane->height), + sz_i * cnt_i, sz_i, cnt_i, + sz_i_e * cnt_i, sz_i_e, cnt_i, + sz_o * cnt_o, sz_o, cnt_o, + sz_o_e * cnt_o, sz_o_e, cnt_o, + dpb_size * dpb_cnt, dpb_size, dpb_cnt, + sz_s * cnt_s, sz_s1 * cnt_s1, + sz_s2 * cnt_s2, sz_p * cnt_p, sz_p1 * cnt_p1, + sz_r * cnt_r, total); + } +error: + mutex_unlock(&core->lock); + +} + +static void msm_vidc_print_running_insts(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *temp; + int op_rate = 0; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + + d_vpr_e("Running instances:\n"); + d_vpr_e("%4s|%4s|%4s|%4s|%4s|%4s\n", + "type", "w", "h", "fps", "opr", "prop"); + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + out_f = &temp->fmts[OUTPUT_PORT].v4l2_fmt; + inp_f = &temp->fmts[INPUT_PORT].v4l2_fmt; + if (temp->state >= MSM_VIDC_OPEN_DONE && + temp->state < MSM_VIDC_STOP_DONE) { + char properties[5] = ""; + + if (is_thumbnail_session(temp)) + strlcat(properties, "N", sizeof(properties)); + + if (is_turbo_session(temp)) + strlcat(properties, "T", sizeof(properties)); + + if (is_realtime_session(temp)) + strlcat(properties, "R", sizeof(properties)); + + if (is_grid_session(temp)) + strlcat(properties, "I", sizeof(properties)); + + if (temp->clk_data.operating_rate) + op_rate = temp->clk_data.operating_rate >> 16; + else + op_rate = temp->clk_data.frame_rate >> 16; + + s_vpr_e(temp->sid, "%4d|%4d|%4d|%4d|%4d|%4s\n", + temp->session_type, + max(out_f->fmt.pix_mp.width, + inp_f->fmt.pix_mp.width), + max(out_f->fmt.pix_mp.height, + inp_f->fmt.pix_mp.height), + temp->clk_data.frame_rate >> 16, + op_rate, properties); + } + } + mutex_unlock(&core->lock); +} + +static int msm_vidc_load_resources(int flipped_state, + struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct msm_vidc_core *core; + int max_video_load = 0, max_image_load = 0; + int video_load = 0, image_load = 0; + enum load_calc_quirks quirks = LOAD_ADMISSION_CONTROL; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst %pK is in invalid state\n", + __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + core = inst->core; + + image_load = msm_comm_get_device_load(core, + MSM_VIDC_ENCODER, MSM_VIDC_IMAGE, + quirks); + video_load = msm_comm_get_device_load(core, + MSM_VIDC_DECODER, MSM_VIDC_VIDEO, + quirks); + video_load += msm_comm_get_device_load(core, + MSM_VIDC_ENCODER, MSM_VIDC_VIDEO, + quirks); + + max_video_load = inst->core->resources.max_load + + inst->capability.cap[CAP_MBS_PER_FRAME].max; + max_image_load = inst->core->resources.max_image_load; + + if (video_load > max_video_load) { + s_vpr_e(inst->sid, + "H/W is overloaded. needed: %d max: %d\n", + video_load, max_video_load); + msm_vidc_print_running_insts(inst->core); + return -EBUSY; + } + + if (video_load + image_load > max_video_load + max_image_load) { + s_vpr_e(inst->sid, + "H/W is overloaded. needed: [video + image][%d + %d], max: [video + image][%d + %d]\n", + video_load, image_load, max_video_load, max_image_load); + msm_vidc_print_running_insts(inst->core); + return -EBUSY; + } + + hdev = core->device; + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_load_res, (void *) inst->session); + if (rc) { + s_vpr_e(inst->sid, "Failed to send load resources\n"); + goto exit; + } + change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES); +exit: + return rc; +} + +static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst %pK is in invalid\n", + __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_start, (void *) inst->session); + if (rc) { + s_vpr_e(inst->sid, "Failed to send start\n"); + goto exit; + } + change_inst_state(inst, MSM_VIDC_START); +exit: + return rc; +} + +static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst %pK is in invalid state\n", + __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_stop, (void *) inst->session); + if (rc) { + s_vpr_e(inst->sid, "%s: inst %pK session_stop failed\n", + __func__, inst); + goto exit; + } + change_inst_state(inst, MSM_VIDC_STOP); +exit: + return rc; +} + +static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst %pK is in invalid state\n", + __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_release_res, (void *) inst->session); + if (rc) { + s_vpr_e(inst->sid, "Failed to send release resources\n"); + goto exit; + } + change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES); +exit: + return rc; +} + +static int msm_comm_session_close(int flipped_state, + struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) { + s_vpr_h(inst->sid, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + s_vpr_h(inst->sid, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_end, (void *) inst->session); + if (rc) { + s_vpr_e(inst->sid, "Failed to send close\n"); + goto exit; + } + change_inst_state(inst, MSM_VIDC_CLOSE); +exit: + return rc; +} + +int msm_comm_suspend(int core_id) +{ + struct hfi_device *hdev; + struct msm_vidc_core *core; + int rc = 0; + + core = get_vidc_core(core_id); + if (!core) { + d_vpr_e("%s: Failed to find core for core_id = %d\n", + __func__, core_id); + return -EINVAL; + } + + hdev = (struct hfi_device *)core->device; + if (!hdev) { + d_vpr_e("%s: Invalid device handle\n", __func__); + return -EINVAL; + } + + rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data); + if (rc) + d_vpr_e("Failed to suspend\n"); + + return rc; +} + +static int get_flipped_state(int present_state, + int desired_state) +{ + int flipped_state = present_state; + + if (flipped_state < MSM_VIDC_STOP + && desired_state > MSM_VIDC_STOP) { + flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state); + flipped_state &= 0xFFFE; + flipped_state = flipped_state - 1; + } else if (flipped_state > MSM_VIDC_STOP + && desired_state < MSM_VIDC_STOP) { + flipped_state = MSM_VIDC_STOP - + (flipped_state - MSM_VIDC_STOP + 1); + flipped_state &= 0xFFFE; + flipped_state = flipped_state - 1; + } + return flipped_state; +} + +int msm_comm_reset_bufreqs(struct msm_vidc_inst *inst, enum hal_buffer buf_type) +{ + struct hal_buffer_requirements *bufreqs; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + bufreqs = get_buff_req_buffer(inst, buf_type); + if (!bufreqs) { + s_vpr_e(inst->sid, "%s: invalid buf type %d\n", + __func__, buf_type); + return -EINVAL; + } + bufreqs->buffer_size = bufreqs->buffer_region_size = + bufreqs->buffer_count_min = bufreqs->buffer_count_min_host = + bufreqs->buffer_count_actual = bufreqs->contiguous = + bufreqs->buffer_alignment = 0; + + return 0; +} + +struct hal_buffer_requirements *get_buff_req_buffer( + struct msm_vidc_inst *inst, enum hal_buffer buffer_type) +{ + int i; + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + if (inst->buff_req.buffer[i].buffer_type == buffer_type) + return &inst->buff_req.buffer[i]; + } + s_vpr_e(inst->sid, "Failed to get buff req for : %x", buffer_type); + return NULL; +} + +u32 msm_comm_convert_color_fmt(u32 v4l2_fmt, u32 sid) +{ + switch (v4l2_fmt) { + case V4L2_PIX_FMT_NV12: + return COLOR_FMT_NV12; + case V4L2_PIX_FMT_NV21: + return COLOR_FMT_NV21; + case V4L2_PIX_FMT_NV12_512: + return COLOR_FMT_NV12_512; + case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS: + return COLOR_FMT_P010; + case V4L2_PIX_FMT_NV12_UBWC: + return COLOR_FMT_NV12_UBWC; + case V4L2_PIX_FMT_NV12_TP10_UBWC: + return COLOR_FMT_NV12_BPP10_UBWC; + default: + s_vpr_e(sid, + "Invalid v4l2 color fmt FMT : %x, Set default(NV12)", + v4l2_fmt); + return COLOR_FMT_NV12; + } +} + +static u32 get_hfi_buffer(int hal_buffer, u32 sid) +{ + u32 buffer; + + switch (hal_buffer) { + case HAL_BUFFER_INPUT: + buffer = HFI_BUFFER_INPUT; + break; + case HAL_BUFFER_OUTPUT: + buffer = HFI_BUFFER_OUTPUT; + break; + case HAL_BUFFER_OUTPUT2: + buffer = HFI_BUFFER_OUTPUT2; + break; + case HAL_BUFFER_EXTRADATA_INPUT: + buffer = HFI_BUFFER_EXTRADATA_INPUT; + break; + case HAL_BUFFER_EXTRADATA_OUTPUT: + buffer = HFI_BUFFER_EXTRADATA_OUTPUT; + break; + case HAL_BUFFER_EXTRADATA_OUTPUT2: + buffer = HFI_BUFFER_EXTRADATA_OUTPUT2; + break; + case HAL_BUFFER_INTERNAL_SCRATCH: + buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH; + break; + case HAL_BUFFER_INTERNAL_SCRATCH_1: + buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1; + break; + case HAL_BUFFER_INTERNAL_SCRATCH_2: + buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2; + break; + case HAL_BUFFER_INTERNAL_PERSIST: + buffer = HFI_BUFFER_INTERNAL_PERSIST; + break; + case HAL_BUFFER_INTERNAL_PERSIST_1: + buffer = HFI_BUFFER_INTERNAL_PERSIST_1; + break; + default: + s_vpr_e(sid, "Invalid buffer: %#x\n", hal_buffer); + buffer = 0; + break; + } + return buffer; +} + +static int set_dpb_only_buffers(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type) +{ + int rc = 0; + struct internal_buf *binfo = NULL; + u32 smem_flags = SMEM_UNCACHED, buffer_size = 0, num_buffers = 0; + unsigned int i; + struct hfi_device *hdev; + struct hfi_buffer_size_minimum b; + struct v4l2_format *f; + struct hal_buffer_requirements dpb = {0}; + + hdev = inst->core->device; + + rc = msm_comm_get_dpb_bufreqs(inst, &dpb); + if (rc) { + s_vpr_e(inst->sid, "Couldn't retrieve dpb count & size\n"); + return -EINVAL; + } + num_buffers = dpb.buffer_count_actual; + buffer_size = dpb.buffer_size; + s_vpr_h(inst->sid, "dpb: cnt = %d, size = %d\n", + num_buffers, buffer_size); + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + + b.buffer_type = get_hfi_buffer(buffer_type, inst->sid); + if (!b.buffer_type) + return -EINVAL; + b.buffer_size = buffer_size; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM, + &b, sizeof(b)); + + if (f->fmt.pix_mp.num_planes == 1 || + !f->fmt.pix_mp.plane_fmt[1].sizeimage) { + s_vpr_h(inst->sid, + "This extradata buffer not required, buffer_type: %x\n", + buffer_type); + } else { + s_vpr_h(inst->sid, "extradata: num = 1, size = %d\n", + f->fmt.pix_mp.plane_fmt[1].sizeimage); + inst->dpb_extra_binfo = NULL; + inst->dpb_extra_binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!inst->dpb_extra_binfo) { + s_vpr_e(inst->sid, "%s: Out of memory\n", __func__); + rc = -ENOMEM; + goto fail_kzalloc; + } + rc = msm_comm_smem_alloc(inst, + f->fmt.pix_mp.plane_fmt[1].sizeimage, 1, smem_flags, + buffer_type, 0, &inst->dpb_extra_binfo->smem); + if (rc) { + s_vpr_e(inst->sid, + "Failed to allocate output memory\n"); + goto err_no_mem; + } + } + + if (inst->flags & VIDC_SECURE) + smem_flags |= SMEM_SECURE; + + if (buffer_size) { + for (i = 0; i < num_buffers; i++) { + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + s_vpr_e(inst->sid, "Out of memory\n"); + rc = -ENOMEM; + goto fail_kzalloc; + } + rc = msm_comm_smem_alloc(inst, + buffer_size, 1, smem_flags, + buffer_type, 0, &binfo->smem); + if (rc) { + s_vpr_e(inst->sid, + "Failed to allocate output memory\n"); + goto err_no_mem; + } + binfo->buffer_type = buffer_type; + binfo->buffer_ownership = DRIVER; + s_vpr_h(inst->sid, "Output buffer address: %#x\n", + binfo->smem.device_addr); + + if (inst->buffer_mode_set[OUTPUT_PORT] == + HAL_BUFFER_MODE_STATIC) { + struct vidc_buffer_addr_info buffer_info = {0}; + + buffer_info.buffer_size = buffer_size; + buffer_info.buffer_type = buffer_type; + buffer_info.num_buffers = 1; + buffer_info.align_device_addr = + binfo->smem.device_addr; + buffer_info.extradata_addr = + inst->dpb_extra_binfo->smem.device_addr; + buffer_info.extradata_size = + inst->dpb_extra_binfo->smem.size; + rc = call_hfi_op(hdev, session_set_buffers, + (void *) inst->session, &buffer_info); + if (rc) { + s_vpr_e(inst->sid, + "%s: session_set_buffers failed\n", + __func__); + goto fail_set_buffers; + } + } + mutex_lock(&inst->outputbufs.lock); + list_add_tail(&binfo->list, &inst->outputbufs.list); + mutex_unlock(&inst->outputbufs.lock); + } + } + return rc; +fail_set_buffers: + msm_comm_smem_free(inst, &binfo->smem); +err_no_mem: + kfree(binfo); +fail_kzalloc: + return rc; +} + +static inline char *get_buffer_name(enum hal_buffer buffer_type) +{ + switch (buffer_type) { + case HAL_BUFFER_INPUT: return "input"; + case HAL_BUFFER_OUTPUT: return "output"; + case HAL_BUFFER_OUTPUT2: return "output_2"; + case HAL_BUFFER_EXTRADATA_INPUT: return "input_extra"; + case HAL_BUFFER_EXTRADATA_OUTPUT: return "output_extra"; + case HAL_BUFFER_EXTRADATA_OUTPUT2: return "output2_extra"; + case HAL_BUFFER_INTERNAL_SCRATCH: return "scratch"; + case HAL_BUFFER_INTERNAL_SCRATCH_1: return "scratch_1"; + case HAL_BUFFER_INTERNAL_SCRATCH_2: return "scratch_2"; + case HAL_BUFFER_INTERNAL_PERSIST: return "persist"; + case HAL_BUFFER_INTERNAL_PERSIST_1: return "persist_1"; + case HAL_BUFFER_INTERNAL_CMD_QUEUE: return "queue"; + default: return "????"; + } +} + +static int set_internal_buf_on_fw(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, + struct msm_smem *handle, bool reuse) +{ + struct vidc_buffer_addr_info buffer_info; + struct hfi_device *hdev; + int rc = 0; + + if (!inst || !inst->core || !inst->core->device || !handle) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, handle); + return -EINVAL; + } + + hdev = inst->core->device; + + buffer_info.buffer_size = handle->size; + buffer_info.buffer_type = buffer_type; + buffer_info.num_buffers = 1; + buffer_info.align_device_addr = handle->device_addr; + s_vpr_h(inst->sid, "%s %s buffer : %x\n", + reuse ? "Reusing" : "Allocated", + get_buffer_name(buffer_type), + buffer_info.align_device_addr); + + rc = call_hfi_op(hdev, session_set_buffers, + (void *) inst->session, &buffer_info); + if (rc) { + s_vpr_e(inst->sid, "vidc_hal_session_set_buffers failed\n"); + return rc; + } + return 0; +} + +static bool reuse_internal_buffers(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, struct msm_vidc_list *buf_list) +{ + struct internal_buf *buf; + int rc = 0; + bool reused = false; + + if (!inst || !buf_list) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, buf_list); + return false; + } + + mutex_lock(&buf_list->lock); + list_for_each_entry(buf, &buf_list->list, list) { + if (buf->buffer_type != buffer_type) + continue; + + /* + * Persist buffer size won't change with resolution. If they + * are in queue means that they are already allocated and + * given to HW. HW can use them without reallocation. These + * buffers are not released as part of port reconfig. So + * driver no need to set them again. + */ + + if (buffer_type != HAL_BUFFER_INTERNAL_PERSIST + && buffer_type != HAL_BUFFER_INTERNAL_PERSIST_1) { + + rc = set_internal_buf_on_fw(inst, buffer_type, + &buf->smem, true); + if (rc) { + s_vpr_e(inst->sid, + "%s: session_set_buffers failed\n", + __func__); + reused = false; + break; + } + } + reused = true; + s_vpr_h(inst->sid, + "Re-using internal buffer type : %d\n", buffer_type); + } + mutex_unlock(&buf_list->lock); + return reused; +} + +static int allocate_and_set_internal_bufs(struct msm_vidc_inst *inst, + struct hal_buffer_requirements *internal_bufreq, + struct msm_vidc_list *buf_list) +{ + struct internal_buf *binfo; + u32 smem_flags = SMEM_UNCACHED; + int rc = 0; + unsigned int i = 0; + + if (!inst || !internal_bufreq || !buf_list) + return -EINVAL; + + if (!internal_bufreq->buffer_size) + return 0; + + if (inst->flags & VIDC_SECURE) + smem_flags |= SMEM_SECURE; + + for (i = 0; i < internal_bufreq->buffer_count_actual; i++) { + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + s_vpr_e(inst->sid, "%s: Out of memory\n", __func__); + rc = -ENOMEM; + goto fail_kzalloc; + } + rc = msm_comm_smem_alloc(inst, internal_bufreq->buffer_size, + 1, smem_flags, internal_bufreq->buffer_type, + 0, &binfo->smem); + if (rc) { + s_vpr_e(inst->sid, + "Failed to allocate scratch memory\n"); + goto err_no_mem; + } + + binfo->buffer_type = internal_bufreq->buffer_type; + + rc = set_internal_buf_on_fw(inst, internal_bufreq->buffer_type, + &binfo->smem, false); + if (rc) + goto fail_set_buffers; + + mutex_lock(&buf_list->lock); + list_add_tail(&binfo->list, &buf_list->list); + mutex_unlock(&buf_list->lock); + } + return rc; + +fail_set_buffers: + msm_comm_smem_free(inst, &binfo->smem); +err_no_mem: + kfree(binfo); +fail_kzalloc: + return rc; + +} + +static int set_internal_buffers(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, struct msm_vidc_list *buf_list) +{ + struct hal_buffer_requirements *internal_buf; + + internal_buf = get_buff_req_buffer(inst, buffer_type); + if (!internal_buf) { + s_vpr_h(inst->sid, + "This internal buffer not required, buffer_type: %x\n", + buffer_type); + return 0; + } + + s_vpr_h(inst->sid, "Buffer type %s: num = %d, size = %d\n", + get_buffer_name(buffer_type), + internal_buf->buffer_count_actual, internal_buf->buffer_size); + + /* + * Try reusing existing internal buffers first. + * If it's not possible to reuse, allocate new buffers. + */ + if (reuse_internal_buffers(inst, buffer_type, buf_list)) + return 0; + + return allocate_and_set_internal_bufs(inst, internal_buf, + buf_list); +} + +int msm_comm_try_state(struct msm_vidc_inst *inst, int state) +{ + int rc = 0; + int flipped_state; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + s_vpr_h(inst->sid, "Trying to move inst: %pK from: %#x to %#x\n", + inst, inst->state, state); + + mutex_lock(&inst->sync_lock); + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst %pK is in invalid\n", + __func__, inst); + rc = -EINVAL; + goto exit; + } + + flipped_state = get_flipped_state(inst->state, state); + s_vpr_h(inst->sid, "inst: %pK flipped_state = %#x\n", + inst, flipped_state); + switch (flipped_state) { + case MSM_VIDC_CORE_UNINIT_DONE: + case MSM_VIDC_CORE_INIT: + rc = msm_comm_init_core(inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_CORE_INIT_DONE: + rc = msm_comm_init_core_done(inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_OPEN: + rc = msm_comm_session_init(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_OPEN_DONE: + rc = msm_comm_session_init_done(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_LOAD_RESOURCES: + rc = msm_vidc_load_resources(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_LOAD_RESOURCES_DONE: + case MSM_VIDC_START: + rc = msm_vidc_start(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_START_DONE: + rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE, + HAL_SESSION_START_DONE); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_STOP: + rc = msm_vidc_stop(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_STOP_DONE: + rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE, + HAL_SESSION_STOP_DONE); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + s_vpr_h(inst->sid, "Moving to Stop Done state\n"); + case MSM_VIDC_RELEASE_RESOURCES: + rc = msm_vidc_release_res(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_RELEASE_RESOURCES_DONE: + rc = wait_for_state(inst, flipped_state, + MSM_VIDC_RELEASE_RESOURCES_DONE, + HAL_SESSION_RELEASE_RESOURCE_DONE); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + s_vpr_h(inst->sid, "Moving to release resources done state\n"); + case MSM_VIDC_CLOSE: + rc = msm_comm_session_close(flipped_state, inst); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + case MSM_VIDC_CLOSE_DONE: + rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE, + HAL_SESSION_END_DONE); + if (rc || state <= get_flipped_state(inst->state, state)) + break; + msm_comm_session_clean(inst); + case MSM_VIDC_CORE_UNINIT: + case MSM_VIDC_CORE_INVALID: + s_vpr_h(inst->sid, "Sending core uninit\n"); + rc = msm_vidc_deinit_core(inst); + if (rc || state == get_flipped_state(inst->state, state)) + break; + default: + s_vpr_e(inst->sid, "State not recognized\n"); + rc = -EINVAL; + break; + } + +exit: + mutex_unlock(&inst->sync_lock); + + if (rc) { + s_vpr_e(inst->sid, "Failed to move from state: %d to %d\n", + inst->state, state); + msm_comm_kill_session(inst); + } else { + trace_msm_vidc_common_state_change((void *)inst, + inst->state, state); + } + return rc; +} + +int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst) +{ + struct vidc_frame_data data = {0}; + struct hfi_device *hdev; + struct eos_buf *binfo = NULL, *temp = NULL; + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + mutex_lock(&inst->eosbufs.lock); + list_for_each_entry_safe(binfo, temp, &inst->eosbufs.list, list) { + if (binfo->is_queued) + continue; + + data.alloc_len = binfo->smem.size; + data.device_addr = binfo->smem.device_addr; + data.input_tag = 0; + data.buffer_type = HAL_BUFFER_INPUT; + data.filled_len = 0; + data.offset = 0; + data.flags = HAL_BUFFERFLAG_EOS; + data.timestamp = 0; + data.extradata_addr = 0; + data.extradata_size = 0; + s_vpr_h(inst->sid, "Queueing EOS buffer 0x%x\n", + data.device_addr); + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_etb, inst->session, + &data); + binfo->is_queued = 1; + } + mutex_unlock(&inst->eosbufs.lock); + + return rc; +} + +int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd) +{ + struct msm_vidc_inst *inst = instance; + struct v4l2_decoder_cmd *dec = NULL; + struct v4l2_encoder_cmd *enc = NULL; + struct msm_vidc_core *core; + int which_cmd = 0, flags = 0, rc = 0; + + if (!inst || !inst->core || !cmd) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, cmd); + return -EINVAL; + } + core = inst->core; + if (inst->session_type == MSM_VIDC_ENCODER) { + enc = (struct v4l2_encoder_cmd *)cmd; + which_cmd = enc->cmd; + flags = enc->flags; + } else if (inst->session_type == MSM_VIDC_DECODER) { + dec = (struct v4l2_decoder_cmd *)cmd; + which_cmd = dec->cmd; + flags = dec->flags; + } + + + switch (which_cmd) { + case V4L2_CMD_FLUSH: + rc = msm_comm_flush(inst, flags); + if (rc) { + s_vpr_e(inst->sid, "Failed to flush buffers: %d\n", rc); + } + break; + case V4L2_CMD_SESSION_CONTINUE: + { + rc = msm_comm_session_continue(inst); + break; + } + /* This case also for V4L2_ENC_CMD_STOP */ + case V4L2_DEC_CMD_STOP: + { + struct eos_buf *binfo = NULL; + u32 smem_flags = SMEM_UNCACHED; + + if (inst->state != MSM_VIDC_START_DONE) { + s_vpr_h(inst->sid, + "Inst = %pK is not ready for EOS\n", inst); + break; + } + + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + s_vpr_e(inst->sid, "%s: Out of memory\n", __func__); + rc = -ENOMEM; + break; + } + + if (inst->flags & VIDC_SECURE) + smem_flags |= SMEM_SECURE; + + rc = msm_comm_smem_alloc(inst, + SZ_4K, 1, smem_flags, + HAL_BUFFER_INPUT, 0, &binfo->smem); + if (rc) { + kfree(binfo); + s_vpr_e(inst->sid, + "Failed to allocate output memory\n"); + rc = -ENOMEM; + break; + } + + mutex_lock(&inst->eosbufs.lock); + list_add_tail(&binfo->list, &inst->eosbufs.list); + mutex_unlock(&inst->eosbufs.lock); + + rc = msm_vidc_send_pending_eos_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed pending_eos_buffers sending\n"); + list_del(&binfo->list); + kfree(binfo); + break; + } + break; + } + default: + s_vpr_e(inst->sid, "Unknown Command %d\n", which_cmd); + rc = -ENOTSUPP; + break; + } + return rc; +} + +static void populate_frame_data(struct vidc_frame_data *data, + struct msm_vidc_buffer *mbuf, struct msm_vidc_inst *inst) +{ + u64 time_usec; + struct v4l2_format *f = NULL; + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vbuf; + u32 itag = 0, itag2 = 0; + + if (!inst || !mbuf || !data) { + d_vpr_e("%s: invalid params %pK %pK %pK\n", + __func__, inst, mbuf, data); + return; + } + + vb = &mbuf->vvb.vb2_buf; + vbuf = to_vb2_v4l2_buffer(vb); + + time_usec = vb->timestamp; + do_div(time_usec, NSEC_PER_USEC); + + data->alloc_len = vb->planes[0].length; + data->device_addr = mbuf->smem[0].device_addr; + data->timestamp = time_usec; + data->flags = 0; + data->input_tag = 0; + + if (vb->type == INPUT_MPLANE) { + data->buffer_type = HAL_BUFFER_INPUT; + data->filled_len = vb->planes[0].bytesused; + data->offset = vb->planes[0].data_offset; + + if (vbuf->flags & V4L2_BUF_FLAG_EOS) + data->flags |= HAL_BUFFERFLAG_EOS; + + if (vbuf->flags & V4L2_BUF_FLAG_CODECCONFIG) + data->flags |= HAL_BUFFERFLAG_CODECCONFIG; + + if(msm_vidc_cvp_usage && (vbuf->flags & V4L2_BUF_FLAG_CVPMETADATA_SKIP)) + data->flags |= HAL_BUFFERFLAG_CVPMETADATA_SKIP; + + msm_comm_fetch_input_tag(&inst->etb_data, vb->index, + &itag, &itag2, inst->sid); + data->input_tag = itag; + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + } else if (vb->type == OUTPUT_MPLANE) { + data->buffer_type = msm_comm_get_hal_output_buffer(inst); + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + } + + if (f && f->fmt.pix_mp.num_planes > 1) { + data->extradata_addr = mbuf->smem[1].device_addr; + data->extradata_size = vb->planes[1].length; + data->flags |= HAL_BUFFERFLAG_EXTRADATA; + } +} + +enum hal_buffer get_hal_buffer_type(unsigned int type, + unsigned int plane_num) +{ + if (type == INPUT_MPLANE) { + if (plane_num == 0) + return HAL_BUFFER_INPUT; + else + return HAL_BUFFER_EXTRADATA_INPUT; + } else if (type == OUTPUT_MPLANE) { + if (plane_num == 0) + return HAL_BUFFER_OUTPUT; + else + return HAL_BUFFER_EXTRADATA_OUTPUT; + } else { + return -EINVAL; + } +} + +int msm_comm_num_queued_bufs(struct msm_vidc_inst *inst, u32 type) +{ + int count = 0; + struct msm_vidc_buffer *mbuf; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return 0; + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + if (mbuf->vvb.vb2_buf.type != type) + continue; + if (!(mbuf->flags & MSM_VIDC_FLAG_QUEUED)) + continue; + count++; + } + mutex_unlock(&inst->registeredbufs.lock); + + return count; +} + +static int num_pending_qbufs(struct msm_vidc_inst *inst, u32 type) +{ + int count = 0; + struct msm_vidc_buffer *mbuf; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return 0; + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + if (mbuf->vvb.vb2_buf.type != type) + continue; + /* Count only deferred buffers */ + if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED)) + continue; + count++; + } + mutex_unlock(&inst->registeredbufs.lock); + + return count; +} + +static int msm_comm_qbuf_to_hfi(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + struct hfi_device *hdev; + enum msm_vidc_debugfs_event e; + struct vidc_frame_data frame_data = {0}; + + if (!inst || !inst->core || !inst->core->device || !mbuf) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + populate_frame_data(&frame_data, mbuf, inst); + /* mbuf is not deferred anymore */ + mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + + if (mbuf->vvb.vb2_buf.type == INPUT_MPLANE) { + e = MSM_VIDC_DEBUGFS_EVENT_ETB; + rc = call_hfi_op(hdev, session_etb, inst->session, &frame_data); + } else if (mbuf->vvb.vb2_buf.type == OUTPUT_MPLANE) { + e = MSM_VIDC_DEBUGFS_EVENT_FTB; + rc = call_hfi_op(hdev, session_ftb, inst->session, &frame_data); + } else { + s_vpr_e(inst->sid, "%s: invalid qbuf type %d:\n", __func__, + mbuf->vvb.vb2_buf.type); + rc = -EINVAL; + } + if (rc) { + s_vpr_e(inst->sid, "%s: Failed to qbuf: %d\n", __func__, rc); + goto err_bad_input; + } + mbuf->flags |= MSM_VIDC_FLAG_QUEUED; + msm_vidc_debugfs_update(inst, e); + + if (mbuf->vvb.vb2_buf.type == INPUT_MPLANE && + is_decode_session(inst)) + rc = msm_comm_check_window_bitrate(inst, &frame_data); + +err_bad_input: + return rc; +} + +void msm_vidc_batch_handler(struct work_struct *work) +{ + int rc = 0; + struct msm_vidc_inst *inst; + + inst = container_of(work, struct msm_vidc_inst, batch_work.work); + inst = get_inst(get_vidc_core(MSM_VIDC_CORE_VENUS), inst); + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: invalid state\n", __func__); + goto exit; + } + + s_vpr_h(inst->sid, "%s: queue pending batch buffers\n", + __func__); + + rc = msm_comm_qbufs_batch(inst, NULL); + if (rc) + s_vpr_e(inst->sid, "%s: batch qbufs failed\n", __func__); + +exit: + put_inst(inst); +} + +static int msm_comm_qbuf_superframe_to_hfi(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc, i; + struct hfi_device *hdev; + struct v4l2_format *f; + struct v4l2_ctrl *ctrl; + u64 ts_delta_us; + struct vidc_frame_data *frames; + u32 num_etbs, superframe_count, frame_size, hfi_fmt; + bool skip_allowed = false; + + if (!inst || !inst->core || !inst->core->device || !mbuf) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + frames = inst->superframe_data; + + if (!is_input_buffer(mbuf)) + return msm_comm_qbuf_to_hfi(inst, mbuf); + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + superframe_count = ctrl->val; + if (superframe_count > VIDC_SUPERFRAME_MAX) { + s_vpr_e(inst->sid, "%s: wrong superframe count %d, max %d\n", + __func__, superframe_count, VIDC_SUPERFRAME_MAX); + return -EINVAL; + } + + ts_delta_us = 1000000 / (inst->clk_data.frame_rate >> 16); + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + hfi_fmt = msm_comm_convert_color_fmt(f->fmt.pix_mp.pixelformat, + inst->sid); + frame_size = VENUS_BUFFER_SIZE(hfi_fmt, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + if (frame_size * superframe_count != + mbuf->vvb.vb2_buf.planes[0].length) { + s_vpr_e(inst->sid, + "%s: invalid superframe length, pxlfmt %#x wxh %dx%d framesize %d count %d length %d\n", + __func__, f->fmt.pix_mp.pixelformat, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + frame_size, superframe_count, + mbuf->vvb.vb2_buf.planes[0].length); + return -EINVAL; + } + + num_etbs = 0; + populate_frame_data(&frames[0], mbuf, inst); + /* prepare superframe buffers */ + frames[0].filled_len = frame_size; + /* + * superframe logic updates extradata, cvpmetadata_skip and eos flags only, + * so ensure no other flags are populated in populate_frame_data() + */ + frames[0].flags &= ~HAL_BUFFERFLAG_EXTRADATA; + frames[0].flags &= ~HAL_BUFFERFLAG_EOS; + frames[0].flags &= ~HAL_BUFFERFLAG_CVPMETADATA_SKIP; + frames[0].flags &= ~HAL_BUFFERFLAG_ENDOFSUBFRAME; + if (frames[0].flags) + s_vpr_e(inst->sid, "%s: invalid flags %#x\n", + __func__, frames[0].flags); + frames[0].flags = 0; + + /* Add skip flag only if CVP metadata is enabled */ + if (inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_CVP) { + skip_allowed = true; + frames[0].flags |= HAL_BUFFERFLAG_CVPMETADATA_SKIP; + } + + for (i = 0; i < superframe_count; i++) { + if (i) + memcpy(&frames[i], &frames[0], + sizeof(struct vidc_frame_data)); + frames[i].offset += i * frame_size; + frames[i].timestamp += i * ts_delta_us; + if (!i) { + /* first frame */ + if (frames[0].extradata_addr) + frames[0].flags |= HAL_BUFFERFLAG_EXTRADATA; + + /* Add work incomplete flag for all etb's except the + * last one. For last frame, flag is cleared at the + * last frame iteration. + */ + frames[0].flags |= HAL_BUFFERFLAG_ENDOFSUBFRAME; + } else if (i == superframe_count - 1) { + /* last frame */ + if (mbuf->vvb.flags & V4L2_BUF_FLAG_EOS) + frames[i].flags |= HAL_BUFFERFLAG_EOS; + /* Clear Subframe flag just for the last frame to + * indicate the end of SuperFrame. + */ + frames[i].flags &= ~HAL_BUFFERFLAG_ENDOFSUBFRAME; + } + num_etbs++; + } + + /* If cvp metadata is enabled and metadata is available, + * do not add skip flag for only first frame */ + if (skip_allowed && !(mbuf->vvb.flags & V4L2_BUF_FLAG_CVPMETADATA_SKIP)) + frames[0].flags &= ~HAL_BUFFERFLAG_CVPMETADATA_SKIP; + + rc = call_hfi_op(hdev, session_process_batch, inst->session, + num_etbs, frames, 0, NULL); + if (rc) { + s_vpr_e(inst->sid, "%s: Failed to qbuf: %d\n", __func__, rc); + return rc; + } + /* update mbuf flags */ + mbuf->flags |= MSM_VIDC_FLAG_QUEUED; + mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_ETB); + + return 0; +} + +static int msm_comm_qbuf_in_rbr(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + + if (!inst || !mbuf) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst is in bad state\n", __func__); + return -EINVAL; + } + + rc = msm_comm_scale_clocks_and_bus(inst, 0); + if (rc) + s_vpr_e(inst->sid, "%s: scale clock failed\n", __func__); + + print_vidc_buffer(VIDC_HIGH|VIDC_PERF, "qbuf in rbr", inst, mbuf); + rc = msm_comm_qbuf_to_hfi(inst, mbuf); + if (rc) + s_vpr_e(inst->sid, + "%s: Failed qbuf to hfi: %d\n", __func__, rc); + + return rc; +} + +int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + struct v4l2_ctrl *ctrl; + int do_bw_calc = 0; + + if (!inst || !mbuf) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst is in bad state\n", __func__); + return -EINVAL; + } + + if (inst->state != MSM_VIDC_START_DONE) { + mbuf->flags |= MSM_VIDC_FLAG_DEFERRED; + print_vidc_buffer(VIDC_HIGH, "qbuf deferred", inst, mbuf); + return 0; + } + + do_bw_calc = mbuf->vvb.vb2_buf.type == INPUT_MPLANE; + rc = msm_comm_scale_clocks_and_bus(inst, do_bw_calc); + if (rc) + s_vpr_e(inst->sid, "%s: scale clock & bw failed\n", __func__); + + print_vidc_buffer(VIDC_HIGH|VIDC_PERF, "qbuf", inst, mbuf); + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + rc = msm_comm_qbuf_superframe_to_hfi(inst, mbuf); + else + rc = msm_comm_qbuf_to_hfi(inst, mbuf); + if (rc) + s_vpr_e(inst->sid, "%s: Failed qbuf to hfi: %d\n", + __func__, rc); + + return rc; +} + +int msm_comm_qbufs(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_buffer *mbuf; + bool found; + + if (!inst) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state != MSM_VIDC_START_DONE) { + s_vpr_h(inst->sid, "%s: inst not in start state: %d\n", + __func__, inst->state); + return 0; + } + + do { + mutex_lock(&inst->registeredbufs.lock); + found = false; + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + /* Queue only deferred buffers */ + if (mbuf->flags & MSM_VIDC_FLAG_DEFERRED) { + found = true; + break; + } + } + mutex_unlock(&inst->registeredbufs.lock); + if (!found) { + s_vpr_h(inst->sid, + "%s: no more deferred qbufs\n", __func__); + break; + } + + /* do not call msm_comm_qbuf() under registerbufs lock */ + if (!kref_get_mbuf(inst, mbuf)) { + s_vpr_e(inst->sid, "%s: mbuf not found\n", __func__); + rc = -EINVAL; + break; + } + rc = msm_comm_qbuf(inst, mbuf); + kref_put_mbuf(mbuf); + if (rc) { + s_vpr_e(inst->sid, "%s: failed qbuf\n", __func__); + break; + } + } while (found); + + return rc; +} + +int msm_comm_qbufs_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + struct msm_vidc_buffer *buf; + int do_bw_calc = 0; + + do_bw_calc = mbuf ? mbuf->vvb.vb2_buf.type == INPUT_MPLANE : 0; + rc = msm_comm_scale_clocks_and_bus(inst, do_bw_calc); + if (rc) + s_vpr_e(inst->sid, "%s: scale clock & bw failed\n", __func__); + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(buf, &inst->registeredbufs.list, list) { + /* Don't queue if buffer is not OUTPUT_MPLANE */ + if (buf->vvb.vb2_buf.type != OUTPUT_MPLANE) + goto loop_end; + /* Don't queue if buffer is not a deferred buffer */ + if (!(buf->flags & MSM_VIDC_FLAG_DEFERRED)) + goto loop_end; + /* Don't queue if RBR event is pending on this buffer */ + if (buf->flags & MSM_VIDC_FLAG_RBR_PENDING) + goto loop_end; + + print_vidc_buffer(VIDC_HIGH|VIDC_PERF, "batch-qbuf", inst, buf); + rc = msm_comm_qbuf_to_hfi(inst, buf); + if (rc) { + s_vpr_e(inst->sid, "%s: Failed batch qbuf to hfi: %d\n", + __func__, rc); + break; + } +loop_end: + /* Queue pending buffers till the current buffer only */ + if (buf == mbuf) + break; + } + mutex_unlock(&inst->registeredbufs.lock); + + return rc; +} + +/* + * msm_comm_qbuf_decode_batch - count the buffers which are not queued to + * firmware yet (count includes rbr pending buffers too) and + * queue the buffers at once if full batch count reached. + * Don't queue rbr pending buffers as they would be queued + * when rbr event arrived from firmware. + */ +int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + u32 count = 0; + + if (!inst || !inst->core || !mbuf) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "%s: inst is in bad state\n", __func__); + return -EINVAL; + } + + if (inst->state != MSM_VIDC_START_DONE) { + mbuf->flags |= MSM_VIDC_FLAG_DEFERRED; + print_vidc_buffer(VIDC_HIGH|VIDC_PERF, + "qbuf deferred", inst, mbuf); + return 0; + } + + /* + * Don't defer buffers initially to avoid startup latency increase + * due to batching + */ + if (inst->clk_data.buffer_counter > SKIP_BATCH_WINDOW) { + count = num_pending_qbufs(inst, OUTPUT_MPLANE); + if (count < inst->batch.size) { + print_vidc_buffer(VIDC_HIGH, + "batch-qbuf deferred", inst, mbuf); + schedule_batch_work(inst); + return 0; + } + + /* + * Batch completed - queing bufs to firmware. + * so cancel pending work if any. + */ + cancel_batch_work(inst); + } + + rc = msm_comm_qbufs_batch(inst, mbuf); + if (rc) + s_vpr_e(inst->sid, + "%s: Failed qbuf to hfi: %d\n", + __func__, rc); + + return rc; +} + +int schedule_batch_work(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct msm_vidc_platform_resources *res; + + if (!inst || !inst->core) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + core = inst->core; + res = &core->resources; + + cancel_delayed_work(&inst->batch_work); + queue_delayed_work(core->vidc_core_workq, &inst->batch_work, + msecs_to_jiffies(res->batch_timeout)); + + return 0; +} + +int cancel_batch_work(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + cancel_delayed_work(&inst->batch_work); + + return 0; +} + +int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst) +{ + int rc = -EINVAL, i = 0; + union hal_get_property hprop; + + memset(&hprop, 0x0, sizeof(hprop)); + /* + * First check if we can calculate bufffer sizes. + * If we can calculate then we do it within the driver. + * If we cannot then we get buffer requirements from firmware. + */ + if (inst->buffer_size_calculators) { + rc = inst->buffer_size_calculators(inst); + if (rc) + s_vpr_e(inst->sid, + "Failed calculating internal buffer sizes: %d", + rc); + } + + /* + * Fallback to get buffreq from firmware if internal calculation + * is not done or if it fails + */ + if (rc) { + rc = msm_comm_try_get_buff_req(inst, &hprop); + if (rc) { + s_vpr_e(inst->sid, + "Failed getting buffer requirements: %d", rc); + return rc; + } + + /* reset internal buffers */ + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements *req; + + req = &inst->buff_req.buffer[i]; + if (is_internal_buffer(req->buffer_type)) + msm_comm_reset_bufreqs(inst, req->buffer_type); + } + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements req; + struct hal_buffer_requirements *curr_req; + + req = hprop.buf_req.buffer[i]; + /* + * Firmware buffer requirements are needed for internal + * buffers only and all other buffer requirements are + * calculated in driver. + */ + curr_req = get_buff_req_buffer(inst, req.buffer_type); + if (!curr_req) + return -EINVAL; + + if (is_internal_buffer(req.buffer_type)) { + memcpy(curr_req, &req, + sizeof(struct hal_buffer_requirements)); + } + } + } + + s_vpr_h(inst->sid, "Buffer requirements :\n"); + s_vpr_h(inst->sid, "%15s %8s %8s %8s %8s %8s\n", + "buffer type", "count", "mincount_host", "mincount_fw", "size", + "alignment"); + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements req = inst->buff_req.buffer[i]; + + if (req.buffer_type != HAL_BUFFER_NONE) { + s_vpr_h(inst->sid, "%15s %8d %8d %8d %8d %8d\n", + get_buffer_name(req.buffer_type), + req.buffer_count_actual, + req.buffer_count_min_host, + req.buffer_count_min, req.buffer_size, + req.buffer_alignment); + } + } + return rc; +} + +int msm_comm_try_get_buff_req(struct msm_vidc_inst *inst, + union hal_get_property *hprop) +{ + int rc = 0; + struct hfi_device *hdev; + struct getprop_buf *buf; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + mutex_lock(&inst->sync_lock); + if (inst->state < MSM_VIDC_OPEN_DONE || + inst->state >= MSM_VIDC_CLOSE) { + + /* No need to check inst->state == MSM_VIDC_INVALID since + * INVALID is > CLOSE_DONE. When core went to INVALID state, + * we put all the active instances in INVALID. So > CLOSE_DONE + * is enough check to have. + */ + + s_vpr_e(inst->sid, + "In Wrong state to call Buf Req: Inst %pK or Core %pK\n", + inst, inst->core); + rc = -EAGAIN; + mutex_unlock(&inst->sync_lock); + goto exit; + } + mutex_unlock(&inst->sync_lock); + + rc = call_hfi_op(hdev, session_get_buf_req, inst->session); + if (rc) { + s_vpr_e(inst->sid, "Can't query hardware for property: %d\n", + rc); + goto exit; + } + + rc = wait_for_completion_timeout(&inst->completions[ + SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)], + msecs_to_jiffies( + inst->core->resources.msm_vidc_hw_rsp_timeout)); + if (!rc) { + s_vpr_e(inst->sid, + "%s: Wait interrupted or timed out [%pK]: %d\n", + __func__, inst, + SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)); + msm_comm_kill_session(inst); + rc = -ETIMEDOUT; + goto exit; + } else { + /* wait_for_completion_timeout returns jiffies before expiry */ + rc = 0; + } + + mutex_lock(&inst->pending_getpropq.lock); + if (!list_empty(&inst->pending_getpropq.list)) { + buf = list_first_entry(&inst->pending_getpropq.list, + struct getprop_buf, list); + *hprop = *(union hal_get_property *)buf->data; + kfree(buf->data); + list_del(&buf->list); + kfree(buf); + } else { + s_vpr_e(inst->sid, "%s: getprop list empty\n", __func__); + rc = -EINVAL; + } + mutex_unlock(&inst->pending_getpropq.lock); +exit: + return rc; +} + +int msm_comm_release_dpb_only_buffers(struct msm_vidc_inst *inst, + bool force_release) +{ + struct msm_smem *handle; + struct internal_buf *buf, *dummy; + struct vidc_buffer_addr_info buffer_info; + int rc = 0; + struct msm_vidc_core *core; + struct hfi_device *hdev; + + if (!inst) { + d_vpr_e("Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + mutex_lock(&inst->outputbufs.lock); + if (list_empty(&inst->outputbufs.list)) { + s_vpr_h(inst->sid, "%s: No OUTPUT buffers allocated\n", + __func__); + mutex_unlock(&inst->outputbufs.lock); + return 0; + } + mutex_unlock(&inst->outputbufs.lock); + + core = inst->core; + if (!core) { + s_vpr_e(inst->sid, "Invalid core pointer\n"); + return -EINVAL; + } + hdev = core->device; + if (!hdev) { + s_vpr_e(inst->sid, "Invalid device pointer\n"); + return -EINVAL; + } + mutex_lock(&inst->outputbufs.lock); + list_for_each_entry_safe(buf, dummy, &inst->outputbufs.list, list) { + handle = &buf->smem; + + if ((buf->buffer_ownership == FIRMWARE) && !force_release) { + s_vpr_h(inst->sid, "DPB is with f/w. Can't free it\n"); + /* + * mark this buffer to avoid sending it to video h/w + * again, this buffer belongs to old resolution and + * it will be removed when video h/w returns it. + */ + buf->mark_remove = true; + continue; + } + + buffer_info.buffer_size = handle->size; + buffer_info.buffer_type = buf->buffer_type; + buffer_info.num_buffers = 1; + buffer_info.align_device_addr = handle->device_addr; + if (inst->buffer_mode_set[OUTPUT_PORT] == + HAL_BUFFER_MODE_STATIC) { + buffer_info.response_required = false; + rc = call_hfi_op(hdev, session_release_buffers, + (void *)inst->session, &buffer_info); + if (rc) { + s_vpr_e(inst->sid, + "Rel output buf fail:%x, %d\n", + buffer_info.align_device_addr, + buffer_info.buffer_size); + } + } + + list_del(&buf->list); + msm_comm_smem_free(inst, &buf->smem); + kfree(buf); + } + + if (inst->dpb_extra_binfo) { + msm_comm_smem_free(inst, &inst->dpb_extra_binfo->smem); + kfree(inst->dpb_extra_binfo); + inst->dpb_extra_binfo = NULL; + } + + mutex_unlock(&inst->outputbufs.lock); + return rc; +} + +static enum hal_buffer scratch_buf_sufficient(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type) +{ + struct hal_buffer_requirements *bufreq = NULL; + struct internal_buf *buf; + int count = 0; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + goto not_sufficient; + } + + bufreq = get_buff_req_buffer(inst, buffer_type); + if (!bufreq) + goto not_sufficient; + + /* Check if current scratch buffers are sufficient */ + mutex_lock(&inst->scratchbufs.lock); + + list_for_each_entry(buf, &inst->scratchbufs.list, list) { + if (buf->buffer_type == buffer_type && + buf->smem.size >= bufreq->buffer_size) + count++; + } + mutex_unlock(&inst->scratchbufs.lock); + + if (count != bufreq->buffer_count_actual) + goto not_sufficient; + + s_vpr_h(inst->sid, + "Existing scratch buffer is sufficient for buffer type %#x\n", + buffer_type); + + return buffer_type; + +not_sufficient: + return HAL_BUFFER_NONE; +} + +int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst, + bool check_for_reuse) +{ + struct msm_smem *handle; + struct internal_buf *buf, *dummy; + struct vidc_buffer_addr_info buffer_info; + int rc = 0; + struct msm_vidc_core *core; + struct hfi_device *hdev; + enum hal_buffer sufficiency = HAL_BUFFER_NONE; + + if (!inst) { + d_vpr_e("Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + core = inst->core; + if (!core) { + s_vpr_e(inst->sid, "Invalid core pointer = %pK\n", core); + return -EINVAL; + } + hdev = core->device; + if (!hdev) { + s_vpr_e(inst->sid, "Invalid device pointer = %pK\n", hdev); + return -EINVAL; + } + + if (check_for_reuse) { + sufficiency |= scratch_buf_sufficient(inst, + HAL_BUFFER_INTERNAL_SCRATCH); + + sufficiency |= scratch_buf_sufficient(inst, + HAL_BUFFER_INTERNAL_SCRATCH_1); + + sufficiency |= scratch_buf_sufficient(inst, + HAL_BUFFER_INTERNAL_SCRATCH_2); + } + + mutex_lock(&inst->scratchbufs.lock); + list_for_each_entry_safe(buf, dummy, &inst->scratchbufs.list, list) { + handle = &buf->smem; + buffer_info.buffer_size = handle->size; + buffer_info.buffer_type = buf->buffer_type; + buffer_info.num_buffers = 1; + buffer_info.align_device_addr = handle->device_addr; + buffer_info.response_required = true; + rc = call_hfi_op(hdev, session_release_buffers, + (void *)inst->session, &buffer_info); + if (!rc) { + mutex_unlock(&inst->scratchbufs.lock); + rc = wait_for_sess_signal_receipt(inst, + HAL_SESSION_RELEASE_BUFFER_DONE); + if (rc) + s_vpr_e(inst->sid, + "%s: wait for signal failed, rc %d\n", + __func__, rc); + mutex_lock(&inst->scratchbufs.lock); + } else { + s_vpr_e(inst->sid, "Rel scrtch buf fail:%x, %d\n", + buffer_info.align_device_addr, + buffer_info.buffer_size); + } + + /*If scratch buffers can be reused, do not free the buffers*/ + if (sufficiency & buf->buffer_type) + continue; + + list_del(&buf->list); + msm_comm_smem_free(inst, handle); + kfree(buf); + } + + mutex_unlock(&inst->scratchbufs.lock); + return rc; +} + +void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst) +{ + struct eos_buf *buf, *next; + + if (!inst) { + d_vpr_e("Invalid instance pointer = %pK\n", inst); + return; + } + + mutex_lock(&inst->eosbufs.lock); + list_for_each_entry_safe(buf, next, &inst->eosbufs.list, list) { + list_del(&buf->list); + msm_comm_smem_free(inst, &buf->smem); + kfree(buf); + } + INIT_LIST_HEAD(&inst->eosbufs.list); + mutex_unlock(&inst->eosbufs.lock); +} + + +int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst) +{ + struct recon_buf *buf, *next; + + if (!inst) { + d_vpr_e("Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + + mutex_lock(&inst->refbufs.lock); + list_for_each_entry_safe(buf, next, &inst->refbufs.list, list) { + list_del(&buf->list); + kfree(buf); + } + INIT_LIST_HEAD(&inst->refbufs.list); + mutex_unlock(&inst->refbufs.lock); + + return 0; +} + +int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst) +{ + struct msm_smem *handle; + struct list_head *ptr, *next; + struct internal_buf *buf; + struct vidc_buffer_addr_info buffer_info; + int rc = 0; + struct msm_vidc_core *core; + struct hfi_device *hdev; + + if (!inst) { + d_vpr_e("Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + core = inst->core; + if (!core) { + s_vpr_e(inst->sid, "Invalid core pointer = %pK\n", core); + return -EINVAL; + } + hdev = core->device; + if (!hdev) { + s_vpr_e(inst->sid, "Invalid device pointer = %pK\n", hdev); + return -EINVAL; + } + + mutex_lock(&inst->persistbufs.lock); + list_for_each_safe(ptr, next, &inst->persistbufs.list) { + buf = list_entry(ptr, struct internal_buf, list); + handle = &buf->smem; + buffer_info.buffer_size = handle->size; + buffer_info.buffer_type = buf->buffer_type; + buffer_info.num_buffers = 1; + buffer_info.align_device_addr = handle->device_addr; + buffer_info.response_required = true; + rc = call_hfi_op(hdev, session_release_buffers, + (void *)inst->session, &buffer_info); + if (!rc) { + mutex_unlock(&inst->persistbufs.lock); + rc = wait_for_sess_signal_receipt(inst, + HAL_SESSION_RELEASE_BUFFER_DONE); + if (rc) + s_vpr_e(inst->sid, + "%s: wait for signal failed, rc %d\n", + __func__, rc); + mutex_lock(&inst->persistbufs.lock); + } else { + s_vpr_e(inst->sid, "Rel prst buf fail:%x, %d\n", + buffer_info.align_device_addr, + buffer_info.buffer_size); + } + list_del(&buf->list); + msm_comm_smem_free(inst, handle); + kfree(buf); + } + mutex_unlock(&inst->persistbufs.lock); + return rc; +} + +int msm_comm_set_buffer_count(struct msm_vidc_inst *inst, + int host_count, int act_count, enum hal_buffer type) +{ + int rc = 0; + struct v4l2_ctrl *ctrl; + struct hfi_device *hdev; + struct hfi_buffer_count_actual buf_count; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + buf_count.buffer_type = get_hfi_buffer(type, inst->sid); + buf_count.buffer_count_actual = act_count; + buf_count.buffer_count_min_host = host_count; + /* set total superframe buffers count */ + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_SUPERFRAME); + if (ctrl->val) + buf_count.buffer_count_actual = act_count * ctrl->val; + s_vpr_h(inst->sid, "%s: hal_buffer %d min_host %d actual %d\n", + __func__, type, host_count, act_count); + rc = call_hfi_op(hdev, session_set_property, + inst->session, HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, + &buf_count, sizeof(buf_count)); + if (rc) + s_vpr_e(inst->sid, + "Failed to set actual buffer count %d for buffer type %d\n", + act_count, type); + return rc; +} + +int msm_comm_set_dpb_only_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + bool force_release = true; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + if (get_v4l2_codec(inst) == V4L2_PIX_FMT_VP9) + force_release = false; + + if (msm_comm_release_dpb_only_buffers(inst, force_release)) + s_vpr_e(inst->sid, "Failed to release output buffers\n"); + + rc = set_dpb_only_buffers(inst, HAL_BUFFER_OUTPUT); + if (rc) + goto error; + return rc; +error: + msm_comm_release_dpb_only_buffers(inst, true); + return rc; +} + +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + if (msm_comm_release_scratch_buffers(inst, true)) + s_vpr_e(inst->sid, "Failed to release scratch buffers\n"); + + rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH, + &inst->scratchbufs); + if (rc) + goto error; + + rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_1, + &inst->scratchbufs); + if (rc) + goto error; + + rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_SCRATCH_2, + &inst->scratchbufs); + if (rc) + goto error; + + return rc; +error: + msm_comm_release_scratch_buffers(inst, false); + return rc; +} + +int msm_comm_set_recon_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + unsigned int i = 0, bufcount = 0; + struct recon_buf *binfo; + struct msm_vidc_list *buf_list = &inst->refbufs; + + if (!inst) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + if (inst->session_type != MSM_VIDC_ENCODER && + inst->session_type != MSM_VIDC_DECODER) { + s_vpr_h(inst->sid, "Recon buffs not req for cvp\n"); + return 0; + } + + bufcount = inst->fmts[OUTPUT_PORT].count_actual; + + msm_comm_release_recon_buffers(inst); + + for (i = 0; i < bufcount; i++) { + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + s_vpr_e(inst->sid, "%s: Out of memory\n", __func__); + rc = -ENOMEM; + goto fail_kzalloc; + } + + binfo->buffer_index = i; + mutex_lock(&buf_list->lock); + list_add_tail(&binfo->list, &buf_list->list); + mutex_unlock(&buf_list->lock); + } + +fail_kzalloc: + return rc; +} + +int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid parameters\n", __func__); + return -EINVAL; + } + + rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST, + &inst->persistbufs); + if (rc) + goto error; + + rc = set_internal_buffers(inst, HAL_BUFFER_INTERNAL_PERSIST_1, + &inst->persistbufs); + if (rc) + goto error; + return rc; +error: + msm_comm_release_persist_buffers(inst); + return rc; +} + +static void msm_comm_flush_in_invalid_state(struct msm_vidc_inst *inst) +{ + struct list_head *ptr, *next; + enum vidc_ports ports[] = {INPUT_PORT, OUTPUT_PORT}; + int c = 0; + + /* before flush ensure venus released all buffers */ + msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + + for (c = 0; c < ARRAY_SIZE(ports); ++c) { + enum vidc_ports port = ports[c]; + + mutex_lock(&inst->bufq[port].lock); + list_for_each_safe(ptr, next, + &inst->bufq[port].vb2_bufq.queued_list) { + struct vb2_buffer *vb = container_of(ptr, + struct vb2_buffer, queued_entry); + if (vb->state == VB2_BUF_STATE_ACTIVE) { + vb->planes[0].bytesused = 0; + print_vb2_buffer("flush in invalid", inst, vb); + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } else { + s_vpr_e(inst->sid, + "%s: VB is in state %d not in ACTIVE state\n", + __func__, vb->state); + } + } + mutex_unlock(&inst->bufq[port].lock); + } + msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_FLUSH_DONE); +} + +int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) +{ + unsigned int i = 0; + int rc = 0; + bool ip_flush = false; + bool op_flush = false; + struct msm_vidc_buffer *mbuf, *next; + struct msm_vidc_core *core; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("invalid params %pK\n", inst); + return -EINVAL; + } + + if (inst->state < MSM_VIDC_OPEN_DONE) { + s_vpr_e(inst->sid, + "Invalid state to call flush, inst %pK, state %#x\n", + inst, inst->state); + return -EINVAL; + } + + core = inst->core; + hdev = core->device; + + ip_flush = !!(flags & V4L2_CMD_FLUSH_OUTPUT); + op_flush = !!(flags & V4L2_CMD_FLUSH_CAPTURE); + if (ip_flush && !op_flush) { + s_vpr_e(inst->sid, + "Input only flush not supported, making it flush all\n"); + op_flush = true; + goto exit; + } + + if ((inst->in_flush && ip_flush) || (inst->out_flush && op_flush)) { + s_vpr_e(inst->sid, "%s: Already in flush\n", __func__); + goto exit; + } + + msm_clock_data_reset(inst); + + cancel_batch_work(inst); + if (inst->state == MSM_VIDC_CORE_INVALID) { + s_vpr_e(inst->sid, "Core %pK and inst %pK are in bad state\n", + core, inst); + msm_comm_flush_in_invalid_state(inst); + goto exit; + } + + if (ip_flush) + mutex_lock(&inst->bufq[INPUT_PORT].lock); + if (op_flush) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + /* enable in flush */ + inst->in_flush = ip_flush; + inst->out_flush = op_flush; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(mbuf, next, &inst->registeredbufs.list, list) { + /* don't flush input buffers if input flush is not requested */ + if (!ip_flush && mbuf->vvb.vb2_buf.type == INPUT_MPLANE) + continue; + + /* flush only deferred or rbr pending buffers */ + if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED || + mbuf->flags & MSM_VIDC_FLAG_RBR_PENDING)) + continue; + + /* + * flush buffers which are queued by client already, + * the refcount will be two or more for those buffers. + */ + if (!(mbuf->smem[0].refcount >= 2)) + continue; + + print_vidc_buffer(VIDC_HIGH, "flush buf", inst, mbuf); + msm_comm_flush_vidc_buffer(inst, mbuf); + + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (inst->smem_ops->smem_unmap_dma_buf(inst, + &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "dqbuf: unmap failed.", inst, mbuf); + if (inst->smem_ops->smem_unmap_dma_buf(inst, + &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "dqbuf: unmap failed..", inst, mbuf); + } + if (!mbuf->smem[0].refcount) { + list_del(&mbuf->list); + kref_put_mbuf(mbuf); + } else { + /* buffer is no more a deferred buffer */ + mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + hdev = inst->core->device; + if (ip_flush) { + s_vpr_h(inst->sid, "Send flush on all ports to firmware\n"); + rc = call_hfi_op(hdev, session_flush, inst->session, + HAL_FLUSH_ALL); + } else { + s_vpr_h(inst->sid, "Send flush on output port to firmware\n"); + rc = call_hfi_op(hdev, session_flush, inst->session, + HAL_FLUSH_OUTPUT); + } + if (op_flush) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + if (ip_flush) + mutex_unlock(&inst->bufq[INPUT_PORT].lock); + if (rc) { + s_vpr_e(inst->sid, + "Sending flush to firmware failed, flush out all buffers\n"); + msm_comm_flush_in_invalid_state(inst); + /* disable in_flush & out_flush */ + inst->in_flush = false; + inst->out_flush = false; + } + +exit: + return rc; +} + +int msm_vidc_noc_error_info(struct msm_vidc_core *core) +{ + struct hfi_device *hdev; + + if (!core || !core->device) { + d_vpr_e("%s: Invalid parameters: %pK\n", + __func__, core); + return -EINVAL; + } + + if (!core->resources.non_fatal_pagefaults) + return 0; + + if (!core->smmu_fault_handled) + return 0; + + hdev = core->device; + call_hfi_op(hdev, noc_error_info, hdev->hfi_device_data); + + return 0; +} + +int msm_vidc_trigger_ssr(struct msm_vidc_core *core, + enum hal_ssr_trigger_type type) +{ + if (!core) { + d_vpr_e("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + core->ssr_type = type; + schedule_work(&core->ssr_work); + return 0; +} + +void msm_vidc_ssr_handler(struct work_struct *work) +{ + int rc; + struct msm_vidc_core *core; + struct hfi_device *hdev; + + core = container_of(work, struct msm_vidc_core, ssr_work); + if (!core || !core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return; + } + hdev = core->device; + + mutex_lock(&core->lock); + if (core->state == VIDC_CORE_INIT_DONE) { + d_vpr_e("%s: ssr type %d\n", __func__, core->ssr_type); + /* + * In current implementation user-initiated SSR triggers + * a fatal error from hardware. However, there is no way + * to know if fatal error is due to SSR or not. Handle + * user SSR as non-fatal. + */ + core->trigger_ssr = true; + rc = call_hfi_op(hdev, core_trigger_ssr, + hdev->hfi_device_data, core->ssr_type); + if (rc) { + d_vpr_e("%s: trigger_ssr failed\n", __func__); + core->trigger_ssr = false; + } + } else { + d_vpr_e("%s: video core not initialized\n", __func__); + } + mutex_unlock(&core->lock); +} + +static int msm_vidc_check_mbpf_supported(struct msm_vidc_inst *inst) +{ + u32 mbpf = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + core = inst->core; + + if (!core->resources.max_mbpf) { + s_vpr_h(inst->sid, "%s: max mbpf not available\n", + __func__); + return 0; + } + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + /* ignore invalid and completed session */ + if (temp->state == MSM_VIDC_CORE_INVALID || + temp->state >= MSM_VIDC_STOP_DONE) + continue; + /* ignore thumbnail session */ + if (is_thumbnail_session(temp)) + continue; + /* ignore HEIF sessions */ + if (is_image_session(temp) || is_grid_session(temp)) + continue; + mbpf += NUM_MBS_PER_FRAME( + temp->fmts[INPUT_PORT].v4l2_fmt.fmt.pix_mp.height, + temp->fmts[INPUT_PORT].v4l2_fmt.fmt.pix_mp.width); + } + mutex_unlock(&core->lock); + + if (mbpf > core->resources.max_mbpf) { + msm_vidc_print_running_insts(inst->core); + return -EBUSY; + } + + return 0; +} + +static u32 msm_comm_get_memory_limit(struct msm_vidc_core *core) +{ + struct memory_limit_table *memory_limits_tbl; + u32 memory_limits_tbl_size = 0; + u32 memory_limit = 0, memory_size = 0; + u32 memory_limit_mbytes = 0; + int i = 0; + + memory_limits_tbl = core->resources.mem_limit_tbl; + memory_limits_tbl_size = core->resources.memory_limit_table_size; + memory_limit_mbytes = ((u64)totalram_pages * PAGE_SIZE) >> 20; + for (i = memory_limits_tbl_size - 1; i >= 0; i--) { + memory_size = memory_limits_tbl[i].ddr_size; + memory_limit = memory_limits_tbl[i].mem_limit; + if (memory_size >= memory_limit_mbytes) + break; + } + + return memory_limit; +} + +int msm_comm_check_memory_supported(struct msm_vidc_inst *vidc_inst) +{ + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; + struct msm_vidc_format *fmt; + struct v4l2_format *f; + struct hal_buffer_requirements *req; + struct context_bank_info *cb = NULL; + u32 i, dpb_cnt = 0, dpb_size = 0, rc = 0; + u32 inst_mem_size, non_sec_cb_size = 0; + u64 total_mem_size = 0, non_sec_mem_size = 0; + u32 memory_limit_mbytes; + + core = vidc_inst->core; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + inst_mem_size = 0; + /* input port buffers memory size */ + fmt = &inst->fmts[INPUT_PORT]; + f = &fmt->v4l2_fmt; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) + inst_mem_size += f->fmt.pix_mp.plane_fmt[i].sizeimage * + fmt->count_min_host; + + /* output port buffers memory size */ + fmt = &inst->fmts[OUTPUT_PORT]; + f = &fmt->v4l2_fmt; + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) + inst_mem_size += f->fmt.pix_mp.plane_fmt[i].sizeimage * + fmt->count_min_host; + + /* dpb buffers memory size */ + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + struct hal_buffer_requirements dpb = {0}; + + rc = msm_comm_get_dpb_bufreqs(inst, &dpb); + if (rc) { + s_vpr_e(inst->sid, + "Couldn't retrieve dpb count & size\n"); + mutex_unlock(&core->lock); + return rc; + } + dpb_cnt = dpb.buffer_count_actual; + dpb_size = dpb.buffer_size; + inst_mem_size += dpb_cnt * dpb_size; + } + + /* internal buffers memory size */ + for (i = 0; i < HAL_BUFFER_MAX; i++) { + req = &inst->buff_req.buffer[i]; + if (is_internal_buffer(req->buffer_type)) + inst_mem_size += req->buffer_size * + req->buffer_count_actual; + } + + if (!is_secure_session(inst)) + non_sec_mem_size += inst_mem_size; + total_mem_size += inst_mem_size; + } + mutex_unlock(&core->lock); + + memory_limit_mbytes = msm_comm_get_memory_limit(core); + + if ((total_mem_size >> 20) > memory_limit_mbytes) { + s_vpr_e(vidc_inst->sid, + "%s: video mem overshoot - reached %llu MB, max_limit %llu MB\n", + __func__, total_mem_size >> 20, memory_limit_mbytes); + msm_comm_print_insts_info(core); + return -EBUSY; + } + + if (!is_secure_session(vidc_inst)) { + mutex_lock(&core->resources.cb_lock); + list_for_each_entry(cb, &core->resources.context_banks, list) + if (!cb->is_secure) + non_sec_cb_size = cb->addr_range.size; + mutex_unlock(&core->resources.cb_lock); + + if (non_sec_mem_size > non_sec_cb_size) { + s_vpr_e(vidc_inst->sid, + "%s: insufficient device addr space, required %llu, available %llu\n", + __func__, non_sec_mem_size, non_sec_cb_size); + msm_comm_print_insts_info(core); + return -EINVAL; + } + } + + return 0; +} + +static int msm_vidc_check_mbps_supported(struct msm_vidc_inst *inst) +{ + int max_video_load = 0, max_image_load = 0; + int video_load = 0, image_load = 0; + enum load_calc_quirks quirks = LOAD_ADMISSION_CONTROL; + + if (inst->state == MSM_VIDC_OPEN_DONE) { + image_load = msm_comm_get_device_load(inst->core, + MSM_VIDC_ENCODER, MSM_VIDC_IMAGE, + quirks); + video_load = msm_comm_get_device_load(inst->core, + MSM_VIDC_DECODER, MSM_VIDC_VIDEO, + quirks); + video_load += msm_comm_get_device_load(inst->core, + MSM_VIDC_ENCODER, MSM_VIDC_VIDEO, + quirks); + + max_video_load = inst->core->resources.max_load; + max_image_load = inst->core->resources.max_image_load; + + if (video_load > max_video_load) { + s_vpr_e(inst->sid, + "H/W is overloaded. needed: %d max: %d\n", + video_load, max_video_load); + msm_vidc_print_running_insts(inst->core); + return -EBUSY; + } + + if (video_load + image_load > max_video_load + max_image_load) { + s_vpr_e(inst->sid, + "H/W is overloaded. needed: [video + image][%d + %d], max: [video + image][%d + %d]\n", + video_load, image_load, + max_video_load, max_image_load); + msm_vidc_print_running_insts(inst->core); + return -EBUSY; + } + } + return 0; +} + +int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) +{ + u32 x_min, x_max, y_min, y_max; + u32 input_height, input_width, output_height, output_width; + struct v4l2_format *f; + + if (is_grid_session(inst) || is_decode_session(inst)) { + s_vpr_h(inst->sid, "Skip scaling check\n"); + return 0; + } + + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + input_height = f->fmt.pix_mp.height; + input_width = f->fmt.pix_mp.width; + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_height = f->fmt.pix_mp.height; + output_width = f->fmt.pix_mp.width; + + if (!input_height || !input_width || !output_height || !output_width) { + s_vpr_e(inst->sid, "Invalid : Input height = %d width = %d", + input_height, input_width); + s_vpr_e(inst->sid, " output height = %d width = %d\n", + output_height, output_width); + return -ENOTSUPP; + } + + if (!inst->capability.cap[CAP_SCALE_X].min || + !inst->capability.cap[CAP_SCALE_X].max || + !inst->capability.cap[CAP_SCALE_Y].min || + !inst->capability.cap[CAP_SCALE_Y].max) { + + if (input_width * input_height != + output_width * output_height) { + s_vpr_e(inst->sid, + "%s: scaling is not supported (%dx%d != %dx%d)\n", + __func__, input_width, input_height, + output_width, output_height); + return -ENOTSUPP; + } + + s_vpr_h(inst->sid, "%s: supported WxH = %dx%d\n", + __func__, input_width, input_height); + return 0; + } + + x_min = (1<<16)/inst->capability.cap[CAP_SCALE_X].min; + y_min = (1<<16)/inst->capability.cap[CAP_SCALE_Y].min; + x_max = inst->capability.cap[CAP_SCALE_X].max >> 16; + y_max = inst->capability.cap[CAP_SCALE_Y].max >> 16; + + if (input_height > output_height) { + if (input_height > x_min * output_height) { + s_vpr_e(inst->sid, + "Unsupported height min height %d vs %d\n", + input_height / x_min, output_height); + return -ENOTSUPP; + } + } else { + if (output_height > x_max * input_height) { + s_vpr_e(inst->sid, + "Unsupported height max height %d vs %d\n", + x_max * input_height, output_height); + return -ENOTSUPP; + } + } + if (input_width > output_width) { + if (input_width > y_min * output_width) { + s_vpr_e(inst->sid, + "Unsupported width min width %d vs %d\n", + input_width / y_min, output_width); + return -ENOTSUPP; + } + } else { + if (output_width > y_max * input_width) { + s_vpr_e(inst->sid, + "Unsupported width max width %d vs %d\n", + y_max * input_width, output_width); + return -ENOTSUPP; + } + } + return 0; +} + +int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) +{ + struct msm_vidc_capability *capability; + int rc = 0; + struct hfi_device *hdev; + struct msm_vidc_core *core; + u32 output_height, output_width, input_height, input_width; + u32 width_min, width_max, height_min, height_max; + u32 mbpf_max; + struct v4l2_format *f; + u32 sid; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: Invalid parameter\n", __func__); + return -EINVAL; + } + capability = &inst->capability; + hdev = inst->core->device; + core = inst->core; + sid = inst->sid; + rc = msm_vidc_check_mbps_supported(inst); + if (rc) { + s_vpr_e(sid, "%s: Hardware is overloaded\n", __func__); + return rc; + } + + rc = msm_vidc_check_mbpf_supported(inst); + if (rc) + return rc; + + if (!is_thermal_permissible(core)) { + s_vpr_e(sid, + "Thermal level critical, stop all active sessions!\n"); + return -ENOTSUPP; + } + + if (is_secure_session(inst)) { + width_min = capability->cap[CAP_SECURE_FRAME_WIDTH].min; + width_max = capability->cap[CAP_SECURE_FRAME_WIDTH].max; + height_min = capability->cap[CAP_SECURE_FRAME_HEIGHT].min; + height_max = capability->cap[CAP_SECURE_FRAME_HEIGHT].max; + mbpf_max = capability->cap[CAP_SECURE_MBS_PER_FRAME].max; + } else { + width_min = capability->cap[CAP_FRAME_WIDTH].min; + width_max = capability->cap[CAP_FRAME_WIDTH].max; + height_min = capability->cap[CAP_FRAME_HEIGHT].min; + height_max = capability->cap[CAP_FRAME_HEIGHT].max; + mbpf_max = capability->cap[CAP_MBS_PER_FRAME].max; + } + + if (inst->session_type == MSM_VIDC_ENCODER && + inst->rc_type == RATE_CONTROL_LOSSLESS) { + width_min = capability->cap[CAP_LOSSLESS_FRAME_WIDTH].min; + width_max = capability->cap[CAP_LOSSLESS_FRAME_WIDTH].max; + height_min = capability->cap[CAP_LOSSLESS_FRAME_HEIGHT].min; + height_max = capability->cap[CAP_LOSSLESS_FRAME_HEIGHT].max; + mbpf_max = capability->cap[CAP_LOSSLESS_MBS_PER_FRAME].max; + } + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + output_height = f->fmt.pix_mp.height; + output_width = f->fmt.pix_mp.width; + f = &inst->fmts[INPUT_PORT].v4l2_fmt; + input_height = f->fmt.pix_mp.height; + input_width = f->fmt.pix_mp.width; + + if (is_image_session(inst)) { + if (is_secure_session(inst)) { + s_vpr_e(sid, "Secure image encode isn't supported!\n"); + return -ENOTSUPP; + } + + if (is_grid_session(inst)) { + if (inst->fmts[INPUT_PORT].v4l2_fmt.fmt.pix_mp.pixelformat != + V4L2_PIX_FMT_NV12 && + inst->fmts[INPUT_PORT].v4l2_fmt.fmt.pix_mp.pixelformat != + V4L2_PIX_FMT_NV12_512) + return -ENOTSUPP; + + width_min = + capability->cap[CAP_HEIC_IMAGE_FRAME_WIDTH].min; + width_max = + capability->cap[CAP_HEIC_IMAGE_FRAME_WIDTH].max; + height_min = + capability->cap[CAP_HEIC_IMAGE_FRAME_HEIGHT].min; + height_max = + capability->cap[CAP_HEIC_IMAGE_FRAME_HEIGHT].max; + mbpf_max = capability->cap[CAP_MBS_PER_FRAME].max; + + input_height = ALIGN(input_height, 512); + input_width = ALIGN(input_width, 512); + output_height = input_height; + output_width = input_width; + } else { + width_min = + capability->cap[CAP_HEVC_IMAGE_FRAME_WIDTH].min; + width_max = + capability->cap[CAP_HEVC_IMAGE_FRAME_WIDTH].max; + height_min = + capability->cap[CAP_HEVC_IMAGE_FRAME_HEIGHT].min; + height_max = + capability->cap[CAP_HEVC_IMAGE_FRAME_HEIGHT].max; + mbpf_max = capability->cap[CAP_MBS_PER_FRAME].max; + } + } + + if (inst->session_type == MSM_VIDC_ENCODER && (input_width % 2 != 0 || + input_height % 2 != 0 || output_width % 2 != 0 || + output_height % 2 != 0)) { + s_vpr_e(sid, + "Height and Width should be even numbers for NV12\n"); + s_vpr_e(sid, "Input WxH = (%u)x(%u), Output WxH = (%u)x(%u)\n", + input_width, input_height, + output_width, output_height); + rc = -ENOTSUPP; + } + + output_height = ALIGN(output_height, 16); + output_width = ALIGN(output_width, 16); + + if (!rc) { + if (output_width < width_min || + output_height < height_min) { + s_vpr_e(sid, + "Unsupported WxH (%u)x(%u), min supported is (%u)x(%u)\n", + output_width, output_height, + width_min, height_min); + rc = -ENOTSUPP; + } + if (!rc && output_width > width_max) { + s_vpr_e(sid, + "Unsupported width = %u supported max width = %u\n", + output_width, width_max); + rc = -ENOTSUPP; + } + + if (!rc && output_height * output_width > + width_max * height_max) { + s_vpr_e(sid, + "Unsupported WxH = (%u)x(%u), max supported is (%u)x(%u)\n", + output_width, output_height, + width_max, height_max); + rc = -ENOTSUPP; + } + /* Image size max capability has equal width and height, + * hence, don't check mbpf for image sessions. + */ + if (!rc && !(is_image_session(inst) || + is_grid_session(inst)) && + NUM_MBS_PER_FRAME(input_width, input_height) > + mbpf_max) { + s_vpr_e(sid, "Unsupported mbpf %d, max %d\n", + NUM_MBS_PER_FRAME(input_width, input_height), + mbpf_max); + rc = -ENOTSUPP; + } + if (!rc && inst->pic_struct != + MSM_VIDC_PIC_STRUCT_PROGRESSIVE && + (output_width > INTERLACE_WIDTH_MAX || + output_height > INTERLACE_HEIGHT_MAX || + (NUM_MBS_PER_FRAME(output_height, output_width) > + INTERLACE_MB_PER_FRAME_MAX))) { + s_vpr_e(sid, + "Unsupported interlace WxH = (%u)x(%u), max supported is (%u)x(%u)\n", + output_width, output_height, + INTERLACE_WIDTH_MAX, + INTERLACE_HEIGHT_MAX); + rc = -ENOTSUPP; + } + } + if (rc) { + s_vpr_e(sid, "%s: Resolution unsupported\n", __func__); + } + return rc; +} + +void msm_comm_generate_session_error(struct msm_vidc_inst *inst) +{ + enum hal_command_response cmd = HAL_SESSION_ERROR; + struct msm_vidc_cb_cmd_done response = {0}; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid input parameters\n", __func__); + return; + } + s_vpr_e(inst->sid, "%s: inst %pK\n", __func__, inst); + response.inst_id = inst; + response.status = VIDC_ERR_FAIL; + handle_session_error(cmd, (void *)&response); +} + +void msm_comm_generate_sys_error(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + enum hal_command_response cmd = HAL_SYS_ERROR; + struct msm_vidc_cb_cmd_done response = {0}; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid input parameters\n", __func__); + return; + } + s_vpr_e(inst->sid, "%s: inst %pK\n", __func__, inst); + core = inst->core; + response.device_id = (u32) core->id; + handle_sys_error(cmd, (void *) &response); + +} + +int msm_comm_kill_session(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid input parameters\n", __func__); + return -EINVAL; + } else if (!inst->session) { + s_vpr_e(inst->sid, "%s: no session to kill for inst %pK\n", + __func__, inst); + return 0; + } + + s_vpr_e(inst->sid, "%s: inst %pK, state %d\n", __func__, + inst, inst->state); + /* + * We're internally forcibly killing the session, if fw is aware of + * the session send session_abort to firmware to clean up and release + * the session, else just kill the session inside the driver. + */ + if ((inst->state >= MSM_VIDC_OPEN_DONE && + inst->state < MSM_VIDC_CLOSE_DONE) || + inst->state == MSM_VIDC_CORE_INVALID) { + rc = msm_comm_session_abort(inst); + if (rc) { + s_vpr_e(inst->sid, + "%s: inst %pK session abort failed\n", + __func__, inst); + change_inst_state(inst, MSM_VIDC_CORE_INVALID); + } + } + + change_inst_state(inst, MSM_VIDC_CLOSE_DONE); + msm_comm_session_clean(inst); + + s_vpr_e(inst->sid, "%s: inst %pK handled\n", __func__, + inst); + return rc; +} + +int msm_comm_smem_alloc(struct msm_vidc_inst *inst, + size_t size, u32 align, u32 flags, enum hal_buffer buffer_type, + int map_kernel, struct msm_smem *smem) +{ + int rc = 0; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid inst: %pK\n", __func__, inst); + return -EINVAL; + } + rc = msm_smem_alloc(size, align, flags, buffer_type, map_kernel, + &(inst->core->resources), inst->session_type, + smem, inst->sid); + return rc; +} + +void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem) +{ + if (!inst || !inst->core || !mem) { + d_vpr_e("%s: invalid params: %pK %pK\n", + __func__, inst, mem); + return; + } + msm_smem_free(mem, inst->sid); +} + +void msm_vidc_fw_unload_handler(struct work_struct *work) +{ + struct msm_vidc_core *core = NULL; + struct hfi_device *hdev = NULL; + int rc = 0; + + core = container_of(work, struct msm_vidc_core, fw_unload_work.work); + if (!core || !core->device) { + d_vpr_e("%s: invalid work or core handle\n", __func__); + return; + } + + hdev = core->device; + + mutex_lock(&core->lock); + if (list_empty(&core->instances) && + core->state != VIDC_CORE_UNINIT) { + if (core->state > VIDC_CORE_INIT) { + d_vpr_h("Calling vidc_hal_core_release\n"); + rc = call_hfi_op(hdev, core_release, + hdev->hfi_device_data); + if (rc) { + d_vpr_e("Failed to release core, id = %d\n", + core->id); + mutex_unlock(&core->lock); + return; + } + } + core->state = VIDC_CORE_UNINIT; + kfree(core->capabilities); + core->capabilities = NULL; + } + mutex_unlock(&core->lock); +} + +int msm_comm_set_color_format(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, int fourcc) +{ + struct hfi_uncompressed_format_select hfi_fmt = {0}; + u32 format = HFI_COLOR_FORMAT_NV12_UBWC; + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + format = msm_comm_get_hfi_uncompressed(fourcc, inst->sid); + hfi_fmt.buffer_type = get_hfi_buffer(buffer_type, inst->sid); + hfi_fmt.format = format; + s_vpr_h(inst->sid, "buffer_type %#x, format %#x\n", + hfi_fmt.buffer_type, hfi_fmt.format); + rc = call_hfi_op(hdev, session_set_property, inst->session, + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hfi_fmt, + sizeof(hfi_fmt)); + if (rc) + s_vpr_e(inst->sid, "Failed to set input color format\n"); + else + s_vpr_h(inst->sid, "Setting uncompressed colorformat to %#x\n", + format); + + return rc; +} + +void msm_comm_print_inst_info(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffer *mbuf; + struct msm_vidc_cvp_buffer *cbuf; + struct internal_buf *buf; + bool is_decode = false; + enum vidc_ports port; + bool is_secure = false; + struct v4l2_format *f; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + is_decode = inst->session_type == MSM_VIDC_DECODER; + port = is_decode ? INPUT_PORT : OUTPUT_PORT; + is_secure = inst->flags & VIDC_SECURE; + f = &inst->fmts[port].v4l2_fmt; + s_vpr_e(inst->sid, + "%s session, %s, Codec type: %s HxW: %d x %d fps: %d bitrate: %d bit-depth: %s\n", + is_decode ? "Decode" : "Encode", + is_secure ? "Secure" : "Non-Secure", + inst->fmts[port].name, + f->fmt.pix_mp.height, f->fmt.pix_mp.width, + inst->clk_data.frame_rate >> 16, inst->prop.bitrate, + !inst->bit_depth ? "8" : "10"); + s_vpr_e(inst->sid, "---Buffer details for inst: %pK of type: %d---\n", + inst, inst->session_type); + mutex_lock(&inst->registeredbufs.lock); + s_vpr_e(inst->sid, "registered buffer list:\n"); + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) + print_vidc_buffer(VIDC_ERR, "buf", inst, mbuf); + mutex_unlock(&inst->registeredbufs.lock); + + mutex_lock(&inst->scratchbufs.lock); + s_vpr_e(inst->sid, "scratch buffer list:\n"); + list_for_each_entry(buf, &inst->scratchbufs.list, list) + s_vpr_e(inst->sid, "type: %d addr: %x size: %u\n", + buf->buffer_type, buf->smem.device_addr, + buf->smem.size); + mutex_unlock(&inst->scratchbufs.lock); + + mutex_lock(&inst->persistbufs.lock); + s_vpr_e(inst->sid, "persist buffer list:\n"); + list_for_each_entry(buf, &inst->persistbufs.list, list) + s_vpr_e(inst->sid, "type: %d addr: %x size: %u\n", + buf->buffer_type, buf->smem.device_addr, + buf->smem.size); + mutex_unlock(&inst->persistbufs.lock); + + mutex_lock(&inst->outputbufs.lock); + s_vpr_e(inst->sid, "dpb buffer list:\n"); + list_for_each_entry(buf, &inst->outputbufs.list, list) + s_vpr_e(inst->sid, "type: %d addr: %x size: %u\n", + buf->buffer_type, buf->smem.device_addr, + buf->smem.size); + mutex_unlock(&inst->outputbufs.lock); + + mutex_lock(&inst->cvpbufs.lock); + s_vpr_e(inst->sid, "cvp buffer list:\n"); + list_for_each_entry(cbuf, &inst->cvpbufs.list, list) + s_vpr_e(inst->sid, + "index: %u fd: %u offset: %u size: %u addr: %x\n", + cbuf->buf.index, cbuf->buf.fd, cbuf->buf.offset, + cbuf->buf.size, cbuf->smem.device_addr); + mutex_unlock(&inst->cvpbufs.lock); +} + +void msm_comm_print_insts_info(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *inst = NULL; + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + msm_comm_print_mem_usage(core); + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) + msm_comm_print_inst_info(inst); + mutex_unlock(&core->lock); +} + +int msm_comm_session_continue(void *instance) +{ + struct msm_vidc_inst *inst = instance; + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) + return -EINVAL; + hdev = inst->core->device; + mutex_lock(&inst->lock); + if (inst->state >= MSM_VIDC_RELEASE_RESOURCES_DONE || + inst->state < MSM_VIDC_START_DONE) { + s_vpr_h(inst->sid, "Inst %pK : Not in valid state to call %s\n", + inst, __func__); + goto sess_continue_fail; + } + if (inst->session_type == MSM_VIDC_DECODER && inst->in_reconfig) { + s_vpr_h(inst->sid, "send session_continue\n"); + rc = call_hfi_op(hdev, session_continue, + (void *)inst->session); + if (rc) { + s_vpr_e(inst->sid, + "failed to send session_continue\n"); + rc = -EINVAL; + goto sess_continue_fail; + } + inst->in_reconfig = false; + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + rc = msm_comm_queue_dpb_only_buffers(inst); + if (rc) { + s_vpr_e(inst->sid, + "Failed to queue output buffers\n"); + goto sess_continue_fail; + } + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + s_vpr_h(inst->sid, + "session_continue not supported for encoder"); + } else { + s_vpr_e(inst->sid, + "session_continue called in wrong state for decoder"); + } + +sess_continue_fail: + mutex_unlock(&inst->lock); + return rc; +} + +void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + struct vb2_buffer *vb2 = NULL; + + if (!(tag & msm_vidc_debug) || !inst || !mbuf) + return; + + vb2 = &mbuf->vvb.vb2_buf; + + if (vb2->num_planes == 1) + dprintk(tag, inst->sid, + "%s: %s: idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x\n", + str, vb2->type == INPUT_MPLANE ? + "OUTPUT" : "CAPTURE", + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, mbuf->smem[0].device_addr, + vb2->planes[0].length, vb2->planes[0].bytesused, + mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp, + mbuf->smem[0].refcount, mbuf->flags); + else + dprintk(tag, inst->sid, + "%s: %s: idx %2d fd %d off %d daddr %x size %d filled %d flags 0x%x ts %lld refcnt %d mflags 0x%x, extradata: fd %d off %d daddr %x size %d filled %d refcnt %d\n", + str, vb2->type == INPUT_MPLANE ? + "OUTPUT" : "CAPTURE", + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, mbuf->smem[0].device_addr, + vb2->planes[0].length, vb2->planes[0].bytesused, + mbuf->vvb.flags, mbuf->vvb.vb2_buf.timestamp, + mbuf->smem[0].refcount, mbuf->flags, + vb2->planes[1].m.fd, vb2->planes[1].data_offset, + mbuf->smem[1].device_addr, vb2->planes[1].length, + vb2->planes[1].bytesused, mbuf->smem[1].refcount); +} + +void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + if (!inst || !vb2) + return; + + if (vb2->num_planes == 1) + s_vpr_e(inst->sid, + "%s: %s: idx %2d fd %d off %d size %d filled %d\n", + str, vb2->type == INPUT_MPLANE ? "OUTPUT" : "CAPTURE", + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, vb2->planes[0].length, + vb2->planes[0].bytesused); + else + s_vpr_e(inst->sid, + "%s: %s: idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n", + str, vb2->type == INPUT_MPLANE ? "OUTPUT" : "CAPTURE", + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, vb2->planes[0].length, + vb2->planes[0].bytesused, vb2->planes[1].m.fd, + vb2->planes[1].data_offset, vb2->planes[1].length, + vb2->planes[1].bytesused); +} + +bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2, u32 i) +{ + struct vb2_buffer *vb; + + if (!inst || !mbuf || !vb2) { + d_vpr_e("%s: invalid params, %pK %pK %pK\n", + __func__, inst, mbuf, vb2); + return false; + } + + vb = &mbuf->vvb.vb2_buf; + if (vb->planes[i].m.fd == vb2->planes[i].m.fd && + vb->planes[i].length == vb2->planes[i].length) { + return true; + } + + return false; +} + +bool msm_comm_compare_vb2_planes(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2) +{ + unsigned int i = 0; + struct vb2_buffer *vb; + + if (!inst || !mbuf || !vb2) { + d_vpr_e("%s: invalid params, %pK %pK %pK\n", + __func__, inst, mbuf, vb2); + return false; + } + + vb = &mbuf->vvb.vb2_buf; + + if (vb->num_planes != vb2->num_planes) + return false; + + for (i = 0; i < vb->num_planes; i++) { + if (!msm_comm_compare_vb2_plane(inst, mbuf, vb2, i)) + return false; + } + + return true; +} + +bool msm_comm_compare_dma_plane(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, unsigned long *dma_planes, u32 i) +{ + if (!inst || !mbuf || !dma_planes) { + d_vpr_e("%s: invalid params, %pK %pK %pK\n", + __func__, inst, mbuf, dma_planes); + return false; + } + + if ((unsigned long)mbuf->smem[i].dma_buf == dma_planes[i]) + return true; + + return false; +} + +bool msm_comm_compare_dma_planes(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, unsigned long *dma_planes) +{ + unsigned int i = 0; + struct vb2_buffer *vb; + + if (!inst || !mbuf || !dma_planes) { + d_vpr_e("%s: invalid params, %pK %pK %pK\n", + __func__, inst, mbuf, dma_planes); + return false; + } + + vb = &mbuf->vvb.vb2_buf; + for (i = 0; i < vb->num_planes; i++) { + if (!msm_comm_compare_dma_plane(inst, mbuf, dma_planes, i)) + return false; + } + + return true; +} + + +bool msm_comm_compare_device_plane(u32 sid, struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes, u32 i) +{ + if (!mbuf || !planes) { + s_vpr_e(sid, "%s: invalid params, %pK %pK\n", + __func__, mbuf, planes); + return false; + } + + if (mbuf->vvb.vb2_buf.type == type && + mbuf->smem[i].device_addr == planes[i]) + return true; + + return false; +} + +bool msm_comm_compare_device_planes(u32 sid, struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes) +{ + unsigned int i = 0; + + if (!mbuf || !planes) + return false; + + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (!msm_comm_compare_device_plane(sid, mbuf, type, planes, i)) + return false; + } + + return true; +} + +struct msm_vidc_buffer *msm_comm_get_buffer_using_device_planes( + struct msm_vidc_inst *inst, u32 type, u32 *planes) +{ + struct msm_vidc_buffer *mbuf; + bool found = false; + + mutex_lock(&inst->registeredbufs.lock); + found = false; + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + if (msm_comm_compare_device_planes(inst->sid, mbuf, + type, planes)) { + found = true; + break; + } + } + mutex_unlock(&inst->registeredbufs.lock); + if (!found) { + s_vpr_e(inst->sid, + "%s: data_addr %x, extradata_addr %x not found\n", + __func__, planes[0], planes[1]); + mbuf = NULL; + } + + return mbuf; +} + +int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + struct vb2_buffer *vb; + u32 port; + + if (!inst || !mbuf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + + vb = msm_comm_get_vb_using_vidc_buffer(inst, mbuf); + if (!vb) { + print_vidc_buffer(VIDC_ERR, + "vb not found for buf", inst, mbuf); + return -EINVAL; + } + + if (mbuf->vvb.vb2_buf.type == OUTPUT_MPLANE) + port = OUTPUT_PORT; + else if (mbuf->vvb.vb2_buf.type == INPUT_MPLANE) + port = INPUT_PORT; + else + return -EINVAL; + + if (inst->bufq[port].vb2_bufq.streaming) { + vb->planes[0].bytesused = 0; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } else { + s_vpr_e(inst->sid, "%s: port %d is not streaming\n", + __func__, port); + } + + return 0; +} + +int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + unsigned int i; + struct vb2_buffer *vb; + bool skip; + + if (!inst || !mbuf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + vb = &mbuf->vvb.vb2_buf; + + for (i = 0; i < vb->num_planes; i++) { + unsigned long offset, size; + enum smem_cache_ops cache_op; + + offset = vb->planes[i].data_offset; + size = vb->planes[i].length - offset; + cache_op = SMEM_CACHE_INVALIDATE; + skip = false; + + if (inst->session_type == MSM_VIDC_DECODER) { + if (vb->type == INPUT_MPLANE) { + if (!i) { /* bitstream */ + size = vb->planes[i].bytesused; + cache_op = SMEM_CACHE_CLEAN_INVALIDATE; + } + } else if (vb->type == OUTPUT_MPLANE) { + if (!i) { /* yuv */ + /* all values are correct */ + } + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + if (vb->type == INPUT_MPLANE) { + if (!i) { /* yuv */ + size = vb->planes[i].bytesused; + cache_op = SMEM_CACHE_CLEAN_INVALIDATE; + } else { /* extradata */ + cache_op = SMEM_CACHE_CLEAN_INVALIDATE; + } + } else if (vb->type == OUTPUT_MPLANE) { + if (!i && inst->max_filled_len) + size = inst->max_filled_len; + } + } + + if (!skip) { + rc = msm_smem_cache_operations(mbuf->smem[i].dma_buf, + cache_op, offset, size, inst->sid); + if (rc) + print_vidc_buffer(VIDC_ERR, + "qbuf cache ops failed", inst, mbuf); + } + } + + return rc; +} + +int msm_comm_dqbuf_cache_operations(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + unsigned int i; + struct vb2_buffer *vb; + bool skip; + + if (!inst || !mbuf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + vb = &mbuf->vvb.vb2_buf; + + for (i = 0; i < vb->num_planes; i++) { + unsigned long offset, size; + enum smem_cache_ops cache_op; + + offset = vb->planes[i].data_offset; + size = vb->planes[i].length - offset; + cache_op = SMEM_CACHE_INVALIDATE; + skip = false; + + if (inst->session_type == MSM_VIDC_DECODER) { + if (vb->type == INPUT_MPLANE) { + if (!i) /* bitstream */ + skip = true; + } else if (vb->type == OUTPUT_MPLANE) { + if (!i) { /* yuv */ + /* All values are correct */ + } + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + if (vb->type == INPUT_MPLANE) { + /* yuv and extradata */ + skip = true; + } else if (vb->type == OUTPUT_MPLANE) { + if (!i) { /* bitstream */ + /* + * Include vp8e header bytes as well + * by making offset equal to zero + */ + offset = 0; + size = vb->planes[i].bytesused + + vb->planes[i].data_offset; + } + } + } + + if (!skip) { + rc = msm_smem_cache_operations(mbuf->smem[i].dma_buf, + cache_op, offset, size, inst->sid); + if (rc) + print_vidc_buffer(VIDC_ERR, + "dqbuf cache ops failed", inst, mbuf); + } + } + + return rc; +} + +struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc = 0; + struct vb2_v4l2_buffer *vbuf; + struct vb2_buffer *vb; + unsigned long dma_planes[VB2_MAX_PLANES] = {0}; + struct msm_vidc_buffer *mbuf; + bool found = false; + unsigned int i; + + if (!inst || !vb2) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, vb2); + return NULL; + } + + for (i = 0; i < vb2->num_planes; i++) { + /* + * always compare dma_buf addresses which is guaranteed + * to be same across the processes (duplicate fds). + */ + dma_planes[i] = (unsigned long)msm_smem_get_dma_buf( + vb2->planes[i].m.fd, inst->sid); + if (!dma_planes[i]) + return NULL; + msm_smem_put_dma_buf((struct dma_buf *)dma_planes[i], + inst->sid); + } + + mutex_lock(&inst->registeredbufs.lock); + /* + * for encoder input, client may queue the same buffer with different + * fd before driver returned old buffer to the client. This buffer + * should be treated as new buffer Search the list with fd so that + * it will be treated as new msm_vidc_buffer. + */ + if (is_encode_session(inst) && vb2->type == INPUT_MPLANE) { + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + if (msm_comm_compare_vb2_planes(inst, mbuf, vb2)) { + found = true; + break; + } + } + } else { + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + if (msm_comm_compare_dma_planes(inst, mbuf, + dma_planes)) { + found = true; + break; + } + } + } + + if (!found) { + /* this is new vb2_buffer */ + mbuf = kzalloc(sizeof(struct msm_vidc_buffer), GFP_KERNEL); + if (!mbuf) { + s_vpr_e(inst->sid, "%s: alloc msm_vidc_buffer failed\n", + __func__); + rc = -ENOMEM; + goto exit; + } + kref_init(&mbuf->kref); + } + + /* Initially assume all the buffer are going to be deferred */ + mbuf->flags |= MSM_VIDC_FLAG_DEFERRED; + + vbuf = to_vb2_v4l2_buffer(vb2); + memcpy(&mbuf->vvb, vbuf, sizeof(struct vb2_v4l2_buffer)); + vb = &mbuf->vvb.vb2_buf; + + for (i = 0; i < vb->num_planes; i++) { + mbuf->smem[i].buffer_type = get_hal_buffer_type(vb->type, i); + mbuf->smem[i].fd = vb->planes[i].m.fd; + mbuf->smem[i].offset = vb->planes[i].data_offset; + mbuf->smem[i].size = vb->planes[i].length; + rc = inst->smem_ops->smem_map_dma_buf(inst, &mbuf->smem[i]); + if (rc) { + s_vpr_e(inst->sid, "%s: map failed.\n", __func__); + goto exit; + } + /* increase refcount as we get both fbd and rbr */ + rc = inst->smem_ops->smem_map_dma_buf(inst, &mbuf->smem[i]); + if (rc) { + s_vpr_e(inst->sid, "%s: map failed..\n", __func__); + goto exit; + } + } + /* dma cache operations need to be performed after dma_map */ + msm_comm_qbuf_cache_operations(inst, mbuf); + + /* special handling for decoder */ + if (inst->session_type == MSM_VIDC_DECODER) { + if (found) { + rc = -EEXIST; + } else { + bool found_plane0 = false; + struct msm_vidc_buffer *temp; + /* + * client might have queued same plane[0] but different + * plane[1] search plane[0] and if found don't queue the + * buffer, the buffer will be queued when rbr event + * arrived. + */ + list_for_each_entry(temp, &inst->registeredbufs.list, + list) { + if (msm_comm_compare_dma_plane(inst, temp, + dma_planes, 0)) { + found_plane0 = true; + break; + } + } + if (found_plane0) + rc = -EEXIST; + } + if (rc == -EEXIST) { + print_vidc_buffer(VIDC_HIGH, + "existing qbuf", inst, mbuf); + /* enable RBR pending */ + mbuf->flags |= MSM_VIDC_FLAG_RBR_PENDING; + } + } + + /* add the new buffer to list */ + if (!found) + list_add_tail(&mbuf->list, &inst->registeredbufs.list); + + mutex_unlock(&inst->registeredbufs.lock); + + /* + * Return mbuf if decode batching is enabled as this buffer + * may trigger queuing full batch to firmware, also this buffer + * will not be queued to firmware while full batch queuing, + * it will be queued when rbr event arrived from firmware. + */ + if (rc == -EEXIST && !inst->batch.enable) + return ERR_PTR(rc); + + return mbuf; + +exit: + s_vpr_e(inst->sid, "%s: %d\n", __func__, rc); + msm_comm_unmap_vidc_buffer(inst, mbuf); + if (!found) + kref_put_mbuf(mbuf); + mutex_unlock(&inst->registeredbufs.lock); + + return ERR_PTR(rc); +} + +void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + struct msm_vidc_buffer *temp; + bool found = false; + unsigned int i = 0; + + if (!inst || !mbuf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return; + } + + mutex_lock(&inst->registeredbufs.lock); + /* check if mbuf was not removed by any chance */ + list_for_each_entry(temp, &inst->registeredbufs.list, list) { + if (msm_comm_compare_vb2_planes(inst, mbuf, + &temp->vvb.vb2_buf)) { + found = true; + break; + } + } + if (!found) { + print_vidc_buffer(VIDC_ERR, "buf was removed", inst, mbuf); + goto unlock; + } + + print_vidc_buffer(VIDC_HIGH, "dqbuf", inst, mbuf); + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (inst->smem_ops->smem_unmap_dma_buf(inst, &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "dqbuf: unmap failed.", inst, mbuf); + + if (!(mbuf->vvb.flags & V4L2_BUF_FLAG_READONLY)) { + /* rbr won't come for this buffer */ + if (inst->smem_ops->smem_unmap_dma_buf(inst, + &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "dqbuf: unmap failed..", inst, mbuf); + } else { + /* RBR event expected */ + mbuf->flags |= MSM_VIDC_FLAG_RBR_PENDING; + } + } + /* + * remove the entry if plane[0].refcount is zero else + * don't remove as client queued same buffer that's why + * plane[0].refcount is not zero + */ + if (!mbuf->smem[0].refcount) { + list_del(&mbuf->list); + kref_put_mbuf(mbuf); + } +unlock: + mutex_unlock(&inst->registeredbufs.lock); +} + +void handle_release_buffer_reference(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + struct msm_vidc_buffer *temp; + bool found = false; + unsigned int i = 0; + u32 planes[VIDEO_MAX_PLANES] = {0}; + + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + mutex_lock(&inst->registeredbufs.lock); + found = false; + /* check if mbuf was not removed by any chance */ + list_for_each_entry(temp, &inst->registeredbufs.list, list) { + if (msm_comm_compare_vb2_planes(inst, mbuf, + &temp->vvb.vb2_buf)) { + found = true; + break; + } + } + if (found) { + /* save device_addr */ + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) + planes[i] = mbuf->smem[i].device_addr; + + /* send RBR event to client */ + msm_vidc_queue_rbr_event(inst, + mbuf->vvb.vb2_buf.planes[0].m.fd, + mbuf->vvb.vb2_buf.planes[0].data_offset); + + /* clear RBR_PENDING flag */ + mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING; + + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (inst->smem_ops->smem_unmap_dma_buf(inst, + &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "rbr unmap failed.", inst, mbuf); + } + /* refcount is not zero if client queued the same buffer */ + if (!mbuf->smem[0].refcount) { + list_del(&mbuf->list); + kref_put_mbuf(mbuf); + mbuf = NULL; + } + } else { + print_vidc_buffer(VIDC_ERR, "mbuf not found", inst, mbuf); + goto unlock; + } + + /* + * 1. client might have pushed same planes in which case mbuf will be + * same and refcounts are positive and buffer wouldn't have been + * removed from the registeredbufs list. + * 2. client might have pushed same planes[0] but different planes[1] + * in which case mbuf will be different. + * 3. in either case we can search mbuf->smem[0].device_addr in the list + * and if found queue it to video hw (if not flushing). + */ + found = false; + list_for_each_entry(temp, &inst->registeredbufs.list, list) { + if (msm_comm_compare_device_plane(inst->sid, temp, + OUTPUT_MPLANE, planes, 0)) { + mbuf = temp; + found = true; + break; + } + } + if (!found) + goto unlock; + + /* buffer found means client queued the buffer already */ + if (inst->in_reconfig || inst->out_flush) { + print_vidc_buffer(VIDC_HIGH, "rbr flush buf", inst, mbuf); + msm_comm_flush_vidc_buffer(inst, mbuf); + msm_comm_unmap_vidc_buffer(inst, mbuf); + /* remove from list */ + list_del(&mbuf->list); + kref_put_mbuf(mbuf); + + /* don't queue the buffer */ + found = false; + } + /* clear required flags as the buffer is going to be queued */ + if (found) { + mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING; + } + +unlock: + mutex_unlock(&inst->registeredbufs.lock); + + if (found) { + rc = msm_comm_qbuf_in_rbr(inst, mbuf); + if (rc) + print_vidc_buffer(VIDC_ERR, + "rbr qbuf failed", inst, mbuf); + } + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); +} + +int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + unsigned int i; + + if (!inst || !mbuf) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + if (mbuf->vvb.vb2_buf.num_planes > VIDEO_MAX_PLANES) { + s_vpr_e(inst->sid, "%s: invalid num_planes %d\n", __func__, + mbuf->vvb.vb2_buf.num_planes); + return -EINVAL; + } + + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + u32 refcount = mbuf->smem[i].refcount; + + while (refcount) { + if (inst->smem_ops->smem_unmap_dma_buf(inst, + &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "unmap failed for buf", inst, mbuf); + refcount--; + } + } + + return rc; +} + +static void kref_free_mbuf(struct kref *kref) +{ + struct msm_vidc_buffer *mbuf = container_of(kref, + struct msm_vidc_buffer, kref); + + kfree(mbuf); +} + +void kref_put_mbuf(struct msm_vidc_buffer *mbuf) +{ + if (!mbuf) + return; + + kref_put(&mbuf->kref, kref_free_mbuf); +} + +bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) +{ + struct msm_vidc_buffer *temp; + bool matches = false; + bool ret = false; + + if (!inst || !mbuf) + return false; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(temp, &inst->registeredbufs.list, list) { + if (temp == mbuf) { + matches = true; + break; + } + } + ret = (matches && kref_get_unless_zero(&mbuf->kref)) ? true : false; + mutex_unlock(&inst->registeredbufs.lock); + + return ret; +} + +int msm_comm_store_input_tag(struct msm_vidc_list *data_list, + u32 index, u32 itag, u32 itag2, u32 sid) +{ + struct msm_vidc_buf_data *pdata = NULL; + bool found = false; + int rc = 0; + + if (!data_list) { + s_vpr_e(sid, "%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&data_list->lock); + list_for_each_entry(pdata, &data_list->list, list) { + if (pdata->index == index) { + pdata->input_tag = itag; + pdata->input_tag2 = itag2; + found = true; + break; + } + } + + if (!found) { + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + s_vpr_e(sid, "%s: malloc failure.\n", __func__); + rc = -ENOMEM; + goto exit; + } + pdata->index = index; + pdata->input_tag = itag; + pdata->input_tag2 = itag2; + list_add_tail(&pdata->list, &data_list->list); + } + +exit: + mutex_unlock(&data_list->lock); + + return rc; +} + +int msm_comm_fetch_input_tag(struct msm_vidc_list *data_list, + u32 index, u32 *itag, u32 *itag2, u32 sid) +{ + struct msm_vidc_buf_data *pdata = NULL; + int rc = 0; + + if (!data_list || !itag || !itag2) { + s_vpr_e(sid, "%s: invalid params %pK %pK %pK\n", + __func__, data_list, itag, itag2); + return -EINVAL; + } + + *itag = *itag2 = 0; + mutex_lock(&data_list->lock); + list_for_each_entry(pdata, &data_list->list, list) { + if (pdata->index == index) { + *itag = pdata->input_tag; + *itag2 = pdata->input_tag2; + /* clear after fetch */ + pdata->input_tag = pdata->input_tag2 = 0; + break; + } + } + mutex_unlock(&data_list->lock); + + return rc; +} + +int msm_comm_release_input_tag(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buf_data *pdata, *next; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + mutex_lock(&inst->etb_data.lock); + list_for_each_entry_safe(pdata, next, &inst->etb_data.list, list) { + list_del(&pdata->list); + kfree(pdata); + } + mutex_unlock(&inst->etb_data.lock); + + mutex_lock(&inst->fbd_data.lock); + list_for_each_entry_safe(pdata, next, &inst->fbd_data.list, list) { + list_del(&pdata->list); + kfree(pdata); + } + mutex_unlock(&inst->fbd_data.lock); + + return 0; +} + +int msm_comm_set_color_format_constraints(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, + struct msm_vidc_format_constraint *pix_constraint) +{ + struct hfi_uncompressed_plane_actual_constraints_info + *pconstraint = NULL; + u32 num_planes = 2; + u32 size = 0; + int rc = 0; + struct hfi_device *hdev; + u32 hfi_fmt; + + if (!inst || !inst->core || !inst->core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + + size = 2 * sizeof(u32) + + num_planes + * sizeof(struct hfi_uncompressed_plane_constraints); + + pconstraint = kzalloc(size, GFP_KERNEL); + if (!pconstraint) { + s_vpr_e(inst->sid, "No memory cannot alloc constrain\n"); + rc = -ENOMEM; + goto exit; + } + + hfi_fmt = msm_comm_convert_color_fmt(pix_constraint->fourcc, inst->sid); + pconstraint->buffer_type = get_hfi_buffer(buffer_type, inst->sid); + pconstraint->num_planes = pix_constraint->num_planes; + //set Y plan constraints + s_vpr_h(inst->sid, "Set Y plan constraints.\n"); + pconstraint->rg_plane_format[0].stride_multiples = + VENUS_Y_STRIDE(hfi_fmt, 1); + pconstraint->rg_plane_format[0].max_stride = + pix_constraint->y_max_stride; + pconstraint->rg_plane_format[0].min_plane_buffer_height_multiple = + VENUS_Y_SCANLINES(hfi_fmt, 1); + pconstraint->rg_plane_format[0].buffer_alignment = + pix_constraint->y_buffer_alignment; + + //set UV plan constraints + s_vpr_h(inst->sid, "Set UV plan constraints.\n"); + pconstraint->rg_plane_format[1].stride_multiples = + VENUS_UV_STRIDE(hfi_fmt, 1); + pconstraint->rg_plane_format[1].max_stride = + pix_constraint->uv_max_stride; + pconstraint->rg_plane_format[1].min_plane_buffer_height_multiple = + VENUS_UV_SCANLINES(hfi_fmt, 1); + pconstraint->rg_plane_format[1].buffer_alignment = + pix_constraint->uv_buffer_alignment; + + rc = call_hfi_op(hdev, + session_set_property, + inst->session, + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, + pconstraint, + size); + if (rc) + s_vpr_e(inst->sid, + "Failed to set input color format constraint\n"); + else + s_vpr_h(inst->sid, "Set color format constraint success\n"); + +exit: + if (pconstraint) + kfree(pconstraint); + return rc; +} + +int msm_comm_set_index_extradata(struct msm_vidc_inst *inst, + uint32_t extradata_id, uint32_t value) +{ + int rc = 0; + struct hfi_index_extradata_config extradata; + struct hfi_device *hdev; + + hdev = inst->core->device; + + extradata.index_extra_data_id = extradata_id; + extradata.enable = value; + + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HFI_PROPERTY_PARAM_INDEX_EXTRADATA, &extradata, + sizeof(extradata)); + + return rc; +} + +int msm_comm_set_extradata(struct msm_vidc_inst *inst, + uint32_t extradata_id, uint32_t value) +{ + int rc = 0; + struct hfi_index_extradata_config extradata; + struct hfi_device *hdev; + + hdev = inst->core->device; + + extradata.index_extra_data_id = extradata_id; + extradata.enable = value; + + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, extradata_id, &extradata, + sizeof(extradata)); + + return rc; +} + +int msm_comm_set_cvp_skip_ratio(struct msm_vidc_inst *inst, + uint32_t capture_rate, uint32_t cvp_rate) +{ + int rc = 0; + struct hfi_cvp_skip_ratio cvp_data; + struct hfi_device *hdev; + u32 integral_part, fractional_part, skip_ratio; + + hdev = inst->core->device; + + skip_ratio = 0; + integral_part = ((capture_rate / cvp_rate) << 16); + fractional_part = capture_rate % cvp_rate; + if (fractional_part) { + fractional_part = (fractional_part * 100) / cvp_rate; + skip_ratio = integral_part | ((fractional_part << 16)/100) ; + } + else + skip_ratio = integral_part; + + cvp_data.cvp_skip_ratio = skip_ratio; + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HFI_PROPERTY_CONFIG_CVP_SKIP_RATIO, &cvp_data, + sizeof(cvp_data)); + + return rc; +} + + +bool msm_comm_check_for_inst_overload(struct msm_vidc_core *core) +{ + u32 instance_count = 0; + u32 secure_instance_count = 0; + struct msm_vidc_inst *inst = NULL; + bool overload = false; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + instance_count++; + if (inst->flags & VIDC_SECURE) + secure_instance_count++; + } + mutex_unlock(&core->lock); + + if (instance_count > core->resources.max_inst_count || + secure_instance_count > core->resources.max_secure_inst_count) { + overload = true; + d_vpr_e( + "%s: inst_count:%u max_inst:%u sec_inst_count:%u max_sec_inst:%u\n", + __func__, instance_count, + core->resources.max_inst_count, secure_instance_count, + core->resources.max_secure_inst_count); + } + return overload; +} + +int msm_comm_check_window_bitrate(struct msm_vidc_inst *inst, + struct vidc_frame_data *frame_data) +{ + struct msm_vidc_window_data *pdata, *temp = NULL; + u32 frame_size, window_size, window_buffer; + u32 max_avg_frame_size, max_frame_size; + int buf_cnt = 1, fps, window_start; + + if (!inst || !inst->core || !frame_data) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (!inst->core->resources.avsync_window_size || + inst->entropy_mode == HFI_H264_ENTROPY_CAVLC || + !frame_data->filled_len) + return 0; + + fps = inst->clk_data.frame_rate >> 16; + window_size = inst->core->resources.avsync_window_size * fps; + window_size = DIV_ROUND_CLOSEST(window_size, 1000); + window_buffer = inst->clk_data.work_mode == HFI_WORKMODE_2 ? 2 : 0; + + max_frame_size = + inst->core->resources.allowed_clks_tbl[0].clock_rate / fps - + inst->clk_data.entry->vsp_cycles * + msm_vidc_get_mbs_per_frame(inst); + max_avg_frame_size = div_u64((u64)max_frame_size * 100 * + (window_size + window_buffer), (window_size * 135)); + max_frame_size = div_u64((u64)max_frame_size * 100 * + (1 + window_buffer), 135); + + frame_size = frame_data->filled_len; + window_start = inst->count.etb; + + mutex_lock(&inst->window_data.lock); + list_for_each_entry(pdata, &inst->window_data.list, list) { + if (buf_cnt < window_size && pdata->frame_size) { + frame_size += pdata->frame_size; + window_start = pdata->etb_count; + buf_cnt++; + } else { + pdata->frame_size = 0; + temp = pdata; + } + } + + pdata = NULL; + if(!temp) { + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + s_vpr_e(inst->sid, "%s: malloc failure.\n", __func__); + mutex_unlock(&inst->window_data.lock); + return -ENOMEM; + } + } else { + pdata = temp; + list_del(&pdata->list); + } + pdata->frame_size = frame_data->filled_len; + pdata->etb_count = inst->count.etb; + list_add(&pdata->list, &inst->window_data.list); + mutex_unlock(&inst->window_data.lock); + + frame_size = DIV_ROUND_UP((frame_size * 8), window_size); + if (frame_size > max_avg_frame_size) { + s_vpr_p(inst->sid, + "Unsupported avg frame size %u max %u, window size %u [%u,%u]", + frame_size, max_avg_frame_size, window_size, + window_start, inst->count.etb); + } + if (frame_data->filled_len * 8 > max_frame_size) { + s_vpr_p(inst->sid, + "Unsupported frame size(bit) %u max %u [%u]", + frame_data->filled_len * 8, max_frame_size, + inst->count.etb); + } + + return 0; +} + +void msm_comm_clear_window_data(struct msm_vidc_inst *inst) +{ + struct msm_vidc_window_data *pdata; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + mutex_lock(&inst->window_data.lock); + list_for_each_entry(pdata, &inst->window_data.list, list) { + pdata->frame_size = 0; + } + mutex_unlock(&inst->window_data.lock); +} + +void msm_comm_release_window_data(struct msm_vidc_inst *inst) +{ + struct msm_vidc_window_data *pdata, *next; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + mutex_lock(&inst->window_data.lock); + list_for_each_entry_safe(pdata, next, &inst->window_data.list, list) { + list_del(&pdata->list); + kfree(pdata); + } + mutex_unlock(&inst->window_data.lock); +} diff --git a/techpack/video/msm/vidc/msm_vidc_common.h b/techpack/video/msm/vidc/msm_vidc_common.h new file mode 100644 index 0000000000000000000000000000000000000000..1c64e3ceeef9edf2acb62b876c1359c57c1c31a6 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_common.h @@ -0,0 +1,390 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_VIDC_COMMON_H_ +#define _MSM_VIDC_COMMON_H_ +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" + +#define MAX_DEC_BATCH_SIZE 6 +#define SKIP_BATCH_WINDOW 100 +#define MIN_FRAME_QUALITY 0 +#define MAX_FRAME_QUALITY 100 +#define DEFAULT_FRAME_QUALITY 95 +#define FRAME_QUALITY_STEP 1 +#define HEIC_GRID_DIMENSION 512 +#define CBR_MB_LIMIT (((1280+15)/16)*((720+15)/16)*30) +#define CBR_VFR_MB_LIMIT (((640+15)/16)*((480+15)/16)*30) +#define V4L2_CID_MPEG_VIDEO_UNKNOWN (V4L2_CID_MPEG_MSM_VIDC_BASE + 0xFFF) +#define MAX_BITRATE_DECODER_CAVLC 220000000 +#define MAX_BITRATE_DECODER_2STAGE_CABAC 200000000 +#define MAX_BITRATE_DECODER_1STAGE_CABAC 70000000 + +struct vb2_buf_entry { + struct list_head list; + struct vb2_buffer *vb; +}; + +struct getprop_buf { + struct list_head list; + void *data; +}; + +enum load_calc_quirks { + LOAD_POWER = 0, + LOAD_ADMISSION_CONTROL = 1, +}; + +enum client_set_controls { + CLIENT_SET_I_QP = 0x1, + CLIENT_SET_P_QP = 0x2, + CLIENT_SET_B_QP = 0x4, + CLIENT_SET_MIN_QP = 0x8, + CLIENT_SET_MAX_QP = 0x10, +}; + +static inline bool is_turbo_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_TURBO); +} + +static inline bool is_thumbnail_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_THUMBNAIL); +} + +static inline bool is_low_power_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_LOW_POWER); +} + +static inline struct v4l2_ctrl *get_ctrl(struct msm_vidc_inst *inst, + u32 id) +{ + int i; + + if (inst->session_type == MSM_VIDC_CVP && + inst->core->resources.cvp_internal) + return inst->ctrls[0]; + + for (i = 0; i < inst->num_ctrls; i++) { + if (inst->ctrls[i]->id == id) + return inst->ctrls[i]; + } + s_vpr_e(inst->sid, "%s: control id (%#x) not found\n", __func__, id); + MSM_VIDC_ERROR(true); + return inst->ctrls[0]; +} + +static inline void update_ctrl(struct v4l2_ctrl *ctrl, s32 val, u32 sid) +{ + switch (ctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + *ctrl->p_cur.p_s32 = val; + memcpy(ctrl->p_new.p, ctrl->p_cur.p, + ctrl->elems * ctrl->elem_size); + break; + default: + s_vpr_e(sid, "unhandled control type"); + } +} + +static inline u32 get_v4l2_codec(struct msm_vidc_inst *inst) +{ + struct v4l2_format *f; + u32 port; + + port = (inst->session_type == MSM_VIDC_DECODER) ? INPUT_PORT : + OUTPUT_PORT; + f = &inst->fmts[port].v4l2_fmt; + return f->fmt.pix_mp.pixelformat; +} + +static inline bool is_image_session(struct msm_vidc_inst *inst) +{ + /* Grid may or may not be enabled for an image encode session */ + return inst->session_type == MSM_VIDC_ENCODER && + get_v4l2_codec(inst) == V4L2_PIX_FMT_HEVC && + inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ; +} + +static inline bool is_grid_session(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl = NULL; + if (inst->session_type == MSM_VIDC_ENCODER && + get_v4l2_codec(inst) == V4L2_PIX_FMT_HEVC) { + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_IMG_GRID_SIZE); + return (ctrl->val > 0); + } + return 0; +} + +static inline bool is_video_session(struct msm_vidc_inst *inst) +{ + return !is_grid_session(inst); +} +static inline bool is_realtime_session(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl; + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY); + return !!ctrl->val; +} + +static inline bool is_low_latency_hint(struct msm_vidc_inst *inst) +{ + struct v4l2_ctrl *ctrl; + + if (inst->session_type != MSM_VIDC_DECODER) + return false; + + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_HINT); + return !!ctrl->val; +} + +static inline bool is_secure_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_SECURE); +} + +static inline bool is_decode_session(struct msm_vidc_inst *inst) +{ + return inst->session_type == MSM_VIDC_DECODER; +} + +static inline bool is_encode_session(struct msm_vidc_inst *inst) +{ + return inst->session_type == MSM_VIDC_ENCODER; +} + +static inline bool is_primary_output_mode(struct msm_vidc_inst *inst) +{ + return inst->stream_output_mode == HAL_VIDEO_DECODER_PRIMARY; +} + +static inline bool is_secondary_output_mode(struct msm_vidc_inst *inst) +{ + return inst->stream_output_mode == HAL_VIDEO_DECODER_SECONDARY; +} + +static inline bool in_port_reconfig(struct msm_vidc_inst *inst) +{ + return inst->in_reconfig && inst->bufq[INPUT_PORT].vb2_bufq.streaming; +} + +static inline bool is_input_buffer(struct msm_vidc_buffer *mbuf) +{ + return mbuf->vvb.vb2_buf.type == INPUT_MPLANE; +} + +static inline bool is_output_buffer(struct msm_vidc_buffer *mbuf) +{ + return mbuf->vvb.vb2_buf.type == OUTPUT_MPLANE; +} + +static inline bool is_internal_buffer(enum hal_buffer type) +{ + u32 buf_type = + HAL_BUFFER_INTERNAL_SCRATCH | + HAL_BUFFER_INTERNAL_SCRATCH_1 | + HAL_BUFFER_INTERNAL_SCRATCH_2 | + HAL_BUFFER_INTERNAL_PERSIST | + HAL_BUFFER_INTERNAL_PERSIST_1 | + HAL_BUFFER_INTERNAL_RECON; + return !!(buf_type & type); +} + +static inline int msm_comm_g_ctrl(struct msm_vidc_inst *inst, + struct v4l2_control *ctrl) +{ + return v4l2_g_ctrl(&inst->ctrl_handler, ctrl); +} + +static inline int msm_comm_s_ctrl(struct msm_vidc_inst *inst, + struct v4l2_control *ctrl) +{ + return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl); +} + +static inline bool is_valid_operating_rate(struct msm_vidc_inst *inst, s32 val) +{ + struct hal_capability_supported *cap; + + cap = &inst->capability.cap[CAP_OPERATINGRATE]; + + if (((val >> 16) < cap->min || (val >> 16) > cap->max) && + val != INT_MAX) { + s_vpr_e(inst->sid, + "Unsupported operating rate %d min %d max %d\n", + val >> 16, cap->min, cap->max); + return false; + } + return true; +} + +bool is_single_session(struct msm_vidc_inst *inst, u32 ignore_flags); +int msm_comm_get_num_perf_sessions(struct msm_vidc_inst *inst); +bool is_batching_allowed(struct msm_vidc_inst *inst); +enum hal_buffer get_hal_buffer_type(unsigned int type, + unsigned int plane_num); +void put_inst(struct msm_vidc_inst *inst); +struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, + void *inst_id); +void change_inst_state(struct msm_vidc_inst *inst, enum instance_state state); +struct msm_vidc_core *get_vidc_core(int core_id); +const struct msm_vidc_format_desc *msm_comm_get_pixel_fmt_index( + const struct msm_vidc_format_desc fmt[], int size, int index, u32 sid); +struct msm_vidc_format_desc *msm_comm_get_pixel_fmt_fourcc( + struct msm_vidc_format_desc fmt[], int size, int fourcc, u32 sid); +struct msm_vidc_format_constraint *msm_comm_get_pixel_fmt_constraints( + struct msm_vidc_format_constraint fmt[], int size, int fourcc, u32 sid); +int msm_comm_set_color_format_constraints(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, + struct msm_vidc_format_constraint *pix_constraint); +struct buf_queue *msm_comm_get_vb2q( + struct msm_vidc_inst *inst, enum v4l2_buf_type type); +int msm_comm_try_state(struct msm_vidc_inst *inst, int state); +int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst); +int msm_comm_try_get_buff_req(struct msm_vidc_inst *inst, + union hal_get_property *hprop); +int msm_comm_set_recon_buffers(struct msm_vidc_inst *inst); +int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst); +int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst); +int msm_comm_set_buffer_count(struct msm_vidc_inst *inst, + int host_count, int act_count, enum hal_buffer type); +int msm_comm_set_dpb_only_buffers(struct msm_vidc_inst *inst); +int msm_comm_queue_dpb_only_buffers(struct msm_vidc_inst *inst); +int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); +int msm_comm_qbufs(struct msm_vidc_inst *inst); +void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst); +int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags); +int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst, + bool check_for_reuse); +int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst); +int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst); +void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst); +int msm_comm_release_dpb_only_buffers(struct msm_vidc_inst *inst, + bool force_release); +void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst); +int msm_comm_force_cleanup(struct msm_vidc_inst *inst); +int msm_comm_suspend(int core_id); +int msm_comm_reset_bufreqs(struct msm_vidc_inst *inst, + enum hal_buffer buf_type); +struct hal_buffer_requirements *get_buff_req_buffer( + struct msm_vidc_inst *inst, u32 buffer_type); +#define IS_PRIV_CTRL(idx) (\ + (V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \ + V4L2_CTRL_DRIVER_PRIV(idx)) +void msm_comm_session_clean(struct msm_vidc_inst *inst); +int msm_comm_kill_session(struct msm_vidc_inst *inst); +void msm_comm_generate_session_error(struct msm_vidc_inst *inst); +void msm_comm_generate_sys_error(struct msm_vidc_inst *inst); +enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst); +int msm_comm_set_stream_output_mode(struct msm_vidc_inst *inst, + enum multi_stream mode); +enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst); +int msm_comm_smem_alloc(struct msm_vidc_inst *inst, size_t size, u32 align, + u32 flags, enum hal_buffer buffer_type, int map_kernel, + struct msm_smem *smem); +void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *smem); +int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst, + struct msm_smem *mem, enum smem_cache_ops cache_ops); +enum hal_video_codec get_hal_codec(int fourcc, u32 sid); +enum hal_domain get_hal_domain(int session_type, u32 sid); +int msm_comm_check_core_init(struct msm_vidc_core *core, u32 sid); +int msm_comm_get_inst_load(struct msm_vidc_inst *inst, + enum load_calc_quirks quirks); +int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst, + enum load_calc_quirks quirks); +int msm_comm_get_device_load(struct msm_vidc_core *core, + enum session_type sess_type, + enum load_type load_type, + enum load_calc_quirks quirks); +int msm_comm_set_color_format(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type, int fourcc); +int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl); +int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl); +int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id); +int msm_comm_ctrl_init(struct msm_vidc_inst *inst, + struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls, + const struct v4l2_ctrl_ops *ctrl_ops); +int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst); +void msm_comm_cleanup_internal_buffers(struct msm_vidc_inst *inst); +bool msm_comm_turbo_session(struct msm_vidc_inst *inst); +void msm_comm_print_inst_info(struct msm_vidc_inst *inst); +void msm_comm_print_insts_info(struct msm_vidc_core *core); +int msm_comm_v4l2_to_hfi(int id, int value, u32 sid); +int msm_comm_hfi_to_v4l2(int id, int value, u32 sid); +int msm_comm_get_v4l2_profile(int fourcc, int profile, u32 sid); +int msm_comm_get_v4l2_level(int fourcc, int level, u32 sid); +int msm_comm_session_continue(void *instance); +int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst); +enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc); +u32 msm_comm_get_hfi_uncompressed(int fourcc, u32 sid); +u32 msm_comm_convert_color_fmt(u32 v4l2_fmt, u32 sid); +struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer( + struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); +struct msm_vidc_buffer *msm_comm_get_buffer_using_device_planes( + struct msm_vidc_inst *inst, u32 type, u32 *planes); +struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +void handle_release_buffer_reference(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +bool msm_comm_compare_dma_plane(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, unsigned long *dma_planes, u32 i); +bool msm_comm_compare_dma_planes(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, unsigned long *dma_planes); +bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2, u32 i); +bool msm_comm_compare_vb2_planes(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2); +bool msm_comm_compare_device_plane(u32 sid, struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes, u32 i); +bool msm_comm_compare_device_planes(u32 sid, struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes); +int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +int msm_comm_dqbuf_cache_operations(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +void kref_put_mbuf(struct msm_vidc_buffer *mbuf); +bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); +int msm_comm_store_input_tag(struct msm_vidc_list *data_list, + u32 index, u32 itag, u32 itag2, u32 sid); +int msm_comm_fetch_input_tag(struct msm_vidc_list *data_list, + u32 index, u32 *itag, u32 *itag2, u32 sid); +int msm_comm_release_input_tag(struct msm_vidc_inst *inst); +int msm_comm_qbufs_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); +int schedule_batch_work(struct msm_vidc_inst *inst); +int cancel_batch_work(struct msm_vidc_inst *inst); +int msm_comm_num_queued_bufs(struct msm_vidc_inst *inst, u32 type); +int msm_comm_set_index_extradata(struct msm_vidc_inst *inst, + uint32_t extradata_id, uint32_t value); +int msm_comm_set_extradata(struct msm_vidc_inst *inst, uint32_t extradata_id, + uint32_t value); +bool msm_comm_check_for_inst_overload(struct msm_vidc_core *core); +void msm_vidc_batch_handler(struct work_struct *work); +int msm_comm_check_window_bitrate(struct msm_vidc_inst *inst, + struct vidc_frame_data *frame_data); +void msm_comm_clear_window_data(struct msm_vidc_inst *inst); +void msm_comm_release_window_data(struct msm_vidc_inst *inst); +int msm_comm_set_cvp_skip_ratio(struct msm_vidc_inst *inst, + uint32_t capture_rate, uint32_t cvp_rate); +int msm_comm_check_memory_supported(struct msm_vidc_inst *vidc_inst); +int msm_comm_update_dpb_bufreqs(struct msm_vidc_inst *inst); +#endif diff --git a/techpack/video/msm/vidc/msm_vidc_debug.c b/techpack/video/msm/vidc/msm_vidc_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..e803269aa6bd1147f2d588daac1ff4b4b769d4a6 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_debug.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#define CREATE_TRACE_POINTS +#define MAX_SSR_STRING_LEN 10 +#define MAX_DEBUG_LEVEL_STRING_LEN 15 +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" +#include <linux/of_fdt.h> + +int msm_vidc_debug = VIDC_ERR | VIDC_PRINTK | + FW_ERROR | FW_FATAL | FW_FTRACE; +EXPORT_SYMBOL(msm_vidc_debug); + +bool msm_vidc_lossless_encode = !true; +EXPORT_SYMBOL(msm_vidc_lossless_encode); + +int msm_vidc_fw_debug_mode = HFI_DEBUG_MODE_QUEUE; +bool msm_vidc_fw_coverage = !true; +bool msm_vidc_thermal_mitigation_disabled = !true; +int msm_vidc_clock_voting = !1; +bool msm_vidc_syscache_disable = !true; +bool msm_vidc_cvp_usage = true; +int msm_vidc_err_recovery_disable = !1; + +#define MAX_DBG_BUF_SIZE 4096 + +#define DYNAMIC_BUF_OWNER(__binfo) ({ \ + atomic_read(&__binfo->ref_count) >= 2 ? "video driver" : "firmware";\ +}) + +struct log_cookie ctxt[MAX_SUPPORTED_INSTANCES]; + +struct core_inst_pair { + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; +}; + +static u32 write_str(char *buffer, + size_t size, const char *fmt, ...) +{ + va_list args; + u32 len; + + va_start(args, fmt); + len = vscnprintf(buffer, size, fmt, args); + va_end(args); + return len; +} + +static ssize_t core_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct msm_vidc_core *core = file->private_data; + struct hfi_device *hdev; + struct hal_fw_info fw_info = { {0} }; + char *dbuf, *cur, *end; + int i = 0, rc = 0; + ssize_t len = 0; + + if (!core || !core->device) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return 0; + } + + dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL); + if (!dbuf) { + d_vpr_e("%s: Allocation failed!\n", __func__); + return -ENOMEM; + } + cur = dbuf; + end = cur + MAX_DBG_BUF_SIZE; + hdev = core->device; + + cur += write_str(cur, end - cur, "===============================\n"); + cur += write_str(cur, end - cur, "CORE %d: %pK\n", core->id, core); + cur += write_str(cur, end - cur, "===============================\n"); + cur += write_str(cur, end - cur, "Core state: %d\n", core->state); + rc = call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data, &fw_info); + if (rc) { + d_vpr_e("Failed to read FW info\n"); + goto err_fw_info; + } + + cur += write_str(cur, end - cur, + "FW version : %s\n", &fw_info.version); + cur += write_str(cur, end - cur, + "base addr: 0x%x\n", fw_info.base_addr); + cur += write_str(cur, end - cur, + "register_base: 0x%x\n", fw_info.register_base); + cur += write_str(cur, end - cur, + "register_size: %u\n", fw_info.register_size); + cur += write_str(cur, end - cur, "irq: %u\n", fw_info.irq); + cur += write_str(cur, end - cur, + "ddr_type: %d\n", of_fdt_get_ddrtype()); + +err_fw_info: + for (i = SYS_MSG_START; i < SYS_MSG_END; i++) { + cur += write_str(cur, end - cur, "completions[%d]: %s\n", i, + completion_done(&core->completions[SYS_MSG_INDEX(i)]) ? + "pending" : "done"); + } + len = simple_read_from_buffer(buf, count, ppos, + dbuf, cur - dbuf); + + kfree(dbuf); + return len; +} + +static const struct file_operations core_info_fops = { + .open = simple_open, + .read = core_info_read, +}; + +static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long ssr_trigger_val = 0; + int rc = 0; + struct msm_vidc_core *core = filp->private_data; + size_t size = MAX_SSR_STRING_LEN; + char kbuf[MAX_SSR_STRING_LEN + 1] = {0}; + + if (!buf) + return -EINVAL; + + if (!count) + goto exit; + + if (count < size) + size = count; + + if (copy_from_user(kbuf, buf, size)) { + d_vpr_e("%s: User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoul(kbuf, 0, &ssr_trigger_val); + if (rc) { + d_vpr_e("returning error err %d\n", rc); + rc = -EINVAL; + } else { + msm_vidc_trigger_ssr(core, ssr_trigger_val); + rc = count; + } +exit: + return rc; +} + +static const struct file_operations ssr_fops = { + .open = simple_open, + .write = trigger_ssr_write, +}; + +static ssize_t debug_level_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + int rc = 0; + struct msm_vidc_core *core = filp->private_data; + char kbuf[MAX_DEBUG_LEVEL_STRING_LEN] = {0}; + + /* filter partial writes and invalid commands */ + if (*ppos != 0 || count >= sizeof(kbuf) || count == 0) { + d_vpr_e("returning error - pos %d, count %d\n", *ppos, count); + rc = -EINVAL; + } + + rc = simple_write_to_buffer(kbuf, sizeof(kbuf) - 1, ppos, buf, count); + if (rc < 0) { + d_vpr_e("%s: User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoint(kbuf, 0, &msm_vidc_debug); + if (rc) { + d_vpr_e("returning error err %d\n", rc); + rc = -EINVAL; + goto exit; + } + core->resources.msm_vidc_hw_rsp_timeout = + ((msm_vidc_debug & 0xFF) > (VIDC_ERR | VIDC_HIGH)) ? 1500 : 1000; + rc = count; + d_vpr_h("debug timeout updated to - %d\n", + core->resources.msm_vidc_hw_rsp_timeout); + +exit: + return rc; +} + +static ssize_t debug_level_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + size_t len; + char kbuf[MAX_DEBUG_LEVEL_STRING_LEN]; + + len = scnprintf(kbuf, sizeof(kbuf), "0x%08x\n", msm_vidc_debug); + return simple_read_from_buffer(buf, count, ppos, kbuf, len); +} + +static const struct file_operations debug_level_fops = { + .open = simple_open, + .write = debug_level_write, + .read = debug_level_read, +}; + +struct dentry *msm_vidc_debugfs_init_drv(void) +{ + bool ok = false; + struct dentry *dir = NULL; + + dir = debugfs_create_dir("msm_vidc", NULL); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + goto failed_create_dir; + } + +#define __debugfs_create(__type, __name, __value) ({ \ + struct dentry *f = debugfs_create_##__type(__name, 0644, \ + dir, __value); \ + if (IS_ERR_OR_NULL(f)) { \ + d_vpr_e("Failed creating debugfs file '%pd/%s'\n", \ + dir, __name); \ + f = NULL; \ + } \ + f; \ +}) + + ok = + __debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) && + __debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) && + __debugfs_create(bool, "disable_thermal_mitigation", + &msm_vidc_thermal_mitigation_disabled) && + __debugfs_create(u32, "core_clock_voting", + &msm_vidc_clock_voting) && + __debugfs_create(bool, "disable_video_syscache", + &msm_vidc_syscache_disable) && + __debugfs_create(bool, "cvp_usage", &msm_vidc_cvp_usage) && + __debugfs_create(bool, "lossless_encoding", + &msm_vidc_lossless_encode) && + __debugfs_create(u32, "disable_err_recovery", + &msm_vidc_err_recovery_disable); + +#undef __debugfs_create + + if (!ok) + goto failed_create_dir; + + return dir; + +failed_create_dir: + if (dir) + debugfs_remove_recursive(vidc_driver->debugfs_root); + + return NULL; +} + +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, + struct dentry *parent) +{ + struct dentry *dir = NULL; + char debugfs_name[MAX_DEBUGFS_NAME]; + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + goto failed_create_dir; + } + + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id); + dir = debugfs_create_dir(debugfs_name, parent); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + d_vpr_e("Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) { + d_vpr_e("debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("trigger_ssr", 0200, + dir, core, &ssr_fops)) { + d_vpr_e("debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("debug_level", 0644, + parent, core, &debug_level_fops)) { + d_vpr_e("debugfs_create_file: fail\n"); + goto failed_create_dir; + } +failed_create_dir: + return dir; +} + +static int inst_info_open(struct inode *inode, struct file *file) +{ + d_vpr_l("Open inode ptr: %pK\n", inode->i_private); + file->private_data = inode->i_private; + return 0; +} + +static int publish_unreleased_reference(struct msm_vidc_inst *inst, + char **dbuf, char *end) +{ + struct msm_vidc_buffer *temp = NULL; + char *cur = *dbuf; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (inst->buffer_mode_set[OUTPUT_PORT] == HAL_BUFFER_MODE_DYNAMIC) { + cur += write_str(cur, end - cur, "Pending buffer references\n"); + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(temp, &inst->registeredbufs.list, list) { + struct vb2_buffer *vb2 = &temp->vvb.vb2_buf; + + if (vb2->type == OUTPUT_MPLANE) { + cur += write_str(cur, end - cur, + "\tbuffer: %#x fd[0] = %d size %d refcount = %d\n", + temp->smem[0].device_addr, + vb2->planes[0].m.fd, + vb2->planes[0].length, + temp->smem[0].refcount); + } + } + mutex_unlock(&inst->registeredbufs.lock); + } + + *dbuf = cur; + return 0; +} + +static void put_inst_helper(struct kref *kref) +{ + struct msm_vidc_inst *inst = container_of(kref, + struct msm_vidc_inst, kref); + + msm_vidc_destroy(inst); +} + +static ssize_t inst_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct core_inst_pair *idata = file->private_data; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst, *temp = NULL; + char *dbuf, *cur, *end; + int i, j; + ssize_t len = 0; + struct v4l2_format *f; + + if (!idata || !idata->core || !idata->inst) { + d_vpr_e("%s: invalid params %pK\n", __func__, idata); + return 0; + } + + core = idata->core; + inst = idata->inst; + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + if (temp == inst) + break; + } + inst = ((temp == inst) && kref_get_unless_zero(&inst->kref)) ? + inst : NULL; + mutex_unlock(&core->lock); + + if (!inst) { + d_vpr_e("%s: Instance has become obsolete", __func__); + return 0; + } + + dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL); + if (!dbuf) { + s_vpr_e(inst->sid, "%s: Allocation failed!\n", __func__); + len = -ENOMEM; + goto failed_alloc; + } + cur = dbuf; + end = cur + MAX_DBG_BUF_SIZE; + + f = &inst->fmts[OUTPUT_PORT].v4l2_fmt; + cur += write_str(cur, end - cur, "==============================\n"); + cur += write_str(cur, end - cur, "INSTANCE: %pK (%s)\n", inst, + inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder"); + cur += write_str(cur, end - cur, "==============================\n"); + cur += write_str(cur, end - cur, "core: %pK\n", inst->core); + cur += write_str(cur, end - cur, "height: %d\n", f->fmt.pix_mp.height); + cur += write_str(cur, end - cur, "width: %d\n", f->fmt.pix_mp.width); + cur += write_str(cur, end - cur, "fps: %d\n", + inst->clk_data.frame_rate >> 16); + cur += write_str(cur, end - cur, "state: %d\n", inst->state); + cur += write_str(cur, end - cur, "secure: %d\n", + !!(inst->flags & VIDC_SECURE)); + cur += write_str(cur, end - cur, "-----------Formats-------------\n"); + for (i = 0; i < MAX_PORT_NUM; i++) { + f = &inst->fmts[i].v4l2_fmt; + cur += write_str(cur, end - cur, "capability: %s\n", + i == INPUT_PORT ? "Output" : "Capture"); + cur += write_str(cur, end - cur, "name : %s\n", + inst->fmts[i].name); + cur += write_str(cur, end - cur, "planes : %d\n", + f->fmt.pix_mp.num_planes); + cur += write_str(cur, end - cur, + "type: %s\n", i == INPUT_PORT ? + "Output" : "Capture"); + switch (inst->buffer_mode_set[i]) { + case HAL_BUFFER_MODE_STATIC: + cur += write_str(cur, end - cur, + "buffer mode : %s\n", "static"); + break; + case HAL_BUFFER_MODE_DYNAMIC: + cur += write_str(cur, end - cur, + "buffer mode : %s\n", "dynamic"); + break; + default: + cur += write_str(cur, end - cur, + "buffer mode : unsupported\n"); + } + + cur += write_str(cur, end - cur, "count: %u\n", + inst->bufq[i].vb2_bufq.num_buffers); + + for (j = 0; j < f->fmt.pix_mp.num_planes; j++) + cur += write_str(cur, end - cur, + "size for plane %d: %u\n", + j, f->fmt.pix_mp.plane_fmt[j].sizeimage); + + if (i < MAX_PORT_NUM - 1) + cur += write_str(cur, end - cur, "\n"); + } + cur += write_str(cur, end - cur, "-------------------------------\n"); + for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) { + cur += write_str(cur, end - cur, "completions[%d]: %s\n", i, + completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ? + "pending" : "done"); + } + cur += write_str(cur, end - cur, "ETB Count: %d\n", inst->count.etb); + cur += write_str(cur, end - cur, "EBD Count: %d\n", inst->count.ebd); + cur += write_str(cur, end - cur, "FTB Count: %d\n", inst->count.ftb); + cur += write_str(cur, end - cur, "FBD Count: %d\n", inst->count.fbd); + + publish_unreleased_reference(inst, &cur, end); + len = simple_read_from_buffer(buf, count, ppos, + dbuf, cur - dbuf); + + kfree(dbuf); +failed_alloc: + kref_put(&inst->kref, put_inst_helper); + return len; +} + +static int inst_info_release(struct inode *inode, struct file *file) +{ + d_vpr_l("Release inode ptr: %pK\n", inode->i_private); + file->private_data = NULL; + return 0; +} + +static const struct file_operations inst_info_fops = { + .open = inst_info_open, + .read = inst_info_read, + .release = inst_info_release, +}; + +struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, + struct dentry *parent) +{ + struct dentry *dir = NULL, *info = NULL; + char debugfs_name[MAX_DEBUGFS_NAME]; + struct core_inst_pair *idata = NULL; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + goto exit; + } + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%d", inst->sid); + + idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL); + if (!idata) { + s_vpr_e(inst->sid, "%s: Allocation failed!\n", __func__); + goto exit; + } + + idata->core = inst->core; + idata->inst = inst; + + dir = debugfs_create_dir(debugfs_name, parent); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + s_vpr_e(inst->sid, "Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + + info = debugfs_create_file("info", 0444, dir, + idata, &inst_info_fops); + if (IS_ERR_OR_NULL(info)) { + s_vpr_e(inst->sid, "debugfs_create_file: fail\n"); + goto failed_create_file; + } + + dir->d_inode->i_private = info->d_inode->i_private; + inst->debug.pdata[FRAME_PROCESSING].sampling = true; + return dir; + +failed_create_file: + debugfs_remove_recursive(dir); + dir = NULL; +failed_create_dir: + kfree(idata); +exit: + return dir; +} + +void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst) +{ + struct dentry *dentry = NULL; + + if (!inst || !inst->debugfs_root) + return; + + dentry = inst->debugfs_root; + if (dentry->d_inode) { + s_vpr_l(inst->sid, "Destroy %pK\n", dentry->d_inode->i_private); + kfree(dentry->d_inode->i_private); + dentry->d_inode->i_private = NULL; + } + debugfs_remove_recursive(dentry); + inst->debugfs_root = NULL; +} + +void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, + enum msm_vidc_debugfs_event e) +{ + struct msm_vidc_debug *d = &inst->debug; + char a[64] = "Frame processing"; + + switch (e) { + case MSM_VIDC_DEBUGFS_EVENT_ETB: + inst->count.etb++; + trace_msm_v4l2_vidc_buffer_counter("ETB", + inst->count.etb, inst->count.ebd, + inst->count.ftb, inst->count.fbd); + if (inst->count.ebd && inst->count.ftb > inst->count.fbd) { + d->pdata[FRAME_PROCESSING].name[0] = '\0'; + tic(inst, FRAME_PROCESSING, a); + } + break; + case MSM_VIDC_DEBUGFS_EVENT_EBD: + inst->count.ebd++; + trace_msm_v4l2_vidc_buffer_counter("EBD", + inst->count.etb, inst->count.ebd, + inst->count.ftb, inst->count.fbd); + if (inst->count.ebd && inst->count.ebd == inst->count.etb) { + toc(inst, FRAME_PROCESSING); + s_vpr_p(inst->sid, "EBD: FW needs input buffers\n"); + } + if (inst->count.ftb == inst->count.fbd) + s_vpr_p(inst->sid, "EBD: FW needs output buffers\n"); + break; + case MSM_VIDC_DEBUGFS_EVENT_FTB: { + inst->count.ftb++; + trace_msm_v4l2_vidc_buffer_counter("FTB", + inst->count.etb, inst->count.ebd, + inst->count.ftb, inst->count.fbd); + if (inst->count.ebd && inst->count.etb > inst->count.ebd) { + d->pdata[FRAME_PROCESSING].name[0] = '\0'; + tic(inst, FRAME_PROCESSING, a); + } + } + break; + case MSM_VIDC_DEBUGFS_EVENT_FBD: + inst->count.fbd++; + inst->debug.samples++; + trace_msm_v4l2_vidc_buffer_counter("FBD", + inst->count.etb, inst->count.ebd, + inst->count.ftb, inst->count.fbd); + if (inst->count.fbd && + inst->count.fbd == inst->count.ftb) { + toc(inst, FRAME_PROCESSING); + s_vpr_p(inst->sid, "FBD: FW needs output buffers\n"); + } + if (inst->count.etb == inst->count.ebd) + s_vpr_p(inst->sid, "FBD: FW needs input buffers\n"); + break; + default: + s_vpr_e(inst->sid, "Invalid state in debugfs: %d\n", e); + break; + } +} + +int msm_vidc_check_ratelimit(void) +{ + static DEFINE_RATELIMIT_STATE(_rs, + VIDC_DBG_SESSION_RATELIMIT_INTERVAL, + VIDC_DBG_SESSION_RATELIMIT_BURST); + return __ratelimit(&_rs); +} + +/** + * get_sid() must be called under "&core->lock" + * to avoid race condition at occupying empty slot. + */ +int get_sid(u32 *sid, u32 session_type) +{ + int i; + + for (i = 0; i < MAX_SUPPORTED_INSTANCES; i++) { + if (!ctxt[i].used) { + ctxt[i].used = 1; + *sid = i+1; + update_log_ctxt(*sid, session_type, 0); + break; + } + } + + return (i == MAX_SUPPORTED_INSTANCES); +} + +inline void update_log_ctxt(u32 sid, u32 session_type, u32 fourcc) +{ + const char *codec; + char type; + u32 s_type = 0; + + if (!sid || sid > MAX_SUPPORTED_INSTANCES) { + d_vpr_e("%s: invalid sid %#x\n", + __func__, sid); + } + + switch (fourcc) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_H264_NO_SC: + codec = "h264"; + break; + case V4L2_PIX_FMT_H264_MVC: + codec = " mvc"; + break; + case V4L2_PIX_FMT_MPEG1: + codec = "mpg1"; + break; + case V4L2_PIX_FMT_MPEG2: + codec = "mpg2"; + break; + case V4L2_PIX_FMT_VP8: + codec = " vp8"; + break; + case V4L2_PIX_FMT_VP9: + codec = " vp9"; + break; + case V4L2_PIX_FMT_HEVC: + codec = "h265"; + break; + case V4L2_PIX_FMT_TME: + codec = " tme"; + break; + case V4L2_PIX_FMT_CVP: + codec = " cvp"; + break; + default: + codec = "...."; + break; + } + + switch (session_type) { + case MSM_VIDC_ENCODER: + type = 'e'; + s_type = VIDC_ENCODER; + break; + case MSM_VIDC_DECODER: + type = 'd'; + s_type = VIDC_DECODER; + break; + case MSM_VIDC_CVP: + type = 'c'; + s_type = VIDC_CVP; + default: + type = '.'; + break; + } + + ctxt[sid-1].session_type = s_type; + ctxt[sid-1].codec_type = fourcc; + memcpy(&ctxt[sid-1].name, codec, 4); + ctxt[sid-1].name[4] = type; + ctxt[sid-1].name[5] = '\0'; +} + diff --git a/techpack/video/msm/vidc/msm_vidc_debug.h b/techpack/video/msm/vidc/msm_vidc_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..7ddc7be76378cabf0acbc9d269d1734b0f5d1b46 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_debug.h @@ -0,0 +1,325 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __MSM_VIDC_DEBUG__ +#define __MSM_VIDC_DEBUG__ +#include <linux/debugfs.h> +#include <linux/delay.h> +#include <linux/types.h> +#include "msm_vidc_internal.h" +#include "trace/events/msm_vidc_events.h" + +#ifndef VIDC_DBG_LABEL +#define VIDC_DBG_LABEL "msm_vidc" +#endif + +/* + * This enforces a rate limit: not more than 6 messages + * in every 1s. + */ + +#define VIDC_DBG_SESSION_RATELIMIT_INTERVAL (1 * HZ) +#define VIDC_DBG_SESSION_RATELIMIT_BURST 6 + +#define VIDC_DBG_TAG VIDC_DBG_LABEL ": %6s: %08x: %5s: " +#define FW_DBG_TAG VIDC_DBG_LABEL ": %6s: " +#define DEFAULT_SID ((u32)-1) + +/* To enable messages OR these values and + * echo the result to debugfs file. + * + * To enable all messages set debug_level = 0x101F + */ + +enum vidc_msg_prio { + VIDC_ERR = 0x00000001, + VIDC_HIGH = 0x00000002, + VIDC_LOW = 0x00000004, + VIDC_PERF = 0x00000008, + VIDC_PKT = 0x00000010, + VIDC_BUS = 0x00000020, + VIDC_ENCODER = 0x00000100, + VIDC_DECODER = 0x00000200, + VIDC_CVP = 0x00000400, + VIDC_PRINTK = 0x00001000, + VIDC_FTRACE = 0x00002000, + FW_LOW = 0x00010000, + FW_MEDIUM = 0x00020000, + FW_HIGH = 0x00040000, + FW_ERROR = 0x00080000, + FW_FATAL = 0x00100000, + FW_PERF = 0x00200000, + FW_PRINTK = 0x10000000, + FW_FTRACE = 0x20000000, +}; +#define FW_LOGSHIFT 16 +#define FW_LOGMASK 0x0FFF0000 + +enum msm_vidc_debugfs_event { + MSM_VIDC_DEBUGFS_EVENT_ETB, + MSM_VIDC_DEBUGFS_EVENT_EBD, + MSM_VIDC_DEBUGFS_EVENT_FTB, + MSM_VIDC_DEBUGFS_EVENT_FBD, +}; + +enum vidc_err_recovery_disable { + VIDC_DISABLE_NOC_ERR_RECOV = 0x0001, + VIDC_DISABLE_NON_NOC_ERR_RECOV = 0x0002 +}; + +struct log_cookie { + u32 used; + u32 session_type; + u32 codec_type; + char name[20]; +}; + +extern int msm_vidc_debug; +extern int msm_vidc_fw_debug_mode; +extern bool msm_vidc_fw_coverage; +extern bool msm_vidc_thermal_mitigation_disabled; +extern int msm_vidc_clock_voting; +extern bool msm_vidc_syscache_disable; +extern bool msm_vidc_lossless_encode; +extern bool msm_vidc_cvp_usage; +extern int msm_vidc_err_recovery_disable; +extern struct log_cookie ctxt[MAX_SUPPORTED_INSTANCES]; + +#define dprintk(__level, sid, __fmt, ...) \ + do { \ + if (is_print_allowed(sid, __level)) { \ + if (msm_vidc_debug & VIDC_FTRACE) { \ + char trace_logbuf[MAX_TRACER_LOG_LENGTH]; \ + int log_length = snprintf(trace_logbuf, \ + MAX_TRACER_LOG_LENGTH, \ + VIDC_DBG_TAG __fmt, \ + get_debug_level_str(__level), \ + sid, \ + get_codec_name(sid), \ + ##__VA_ARGS__); \ + trace_msm_vidc_printf(trace_logbuf, \ + log_length); \ + } \ + if (msm_vidc_debug & VIDC_PRINTK) { \ + pr_info(VIDC_DBG_TAG __fmt, \ + get_debug_level_str(__level), \ + sid, \ + get_codec_name(sid), \ + ##__VA_ARGS__); \ + } \ + } \ + } while (0) + +#define s_vpr_e(sid, __fmt, ...) dprintk(VIDC_ERR, sid, __fmt, ##__VA_ARGS__) +#define s_vpr_h(sid, __fmt, ...) dprintk(VIDC_HIGH, sid, __fmt, ##__VA_ARGS__) +#define s_vpr_l(sid, __fmt, ...) dprintk(VIDC_LOW, sid, __fmt, ##__VA_ARGS__) +#define s_vpr_p(sid, __fmt, ...) dprintk(VIDC_PERF, sid, __fmt, ##__VA_ARGS__) +#define s_vpr_t(sid, __fmt, ...) dprintk(VIDC_PKT, sid, __fmt, ##__VA_ARGS__) +#define s_vpr_b(sid, __fmt, ...) dprintk(VIDC_BUS, sid, __fmt, ##__VA_ARGS__) +#define s_vpr_hp(sid, __fmt, ...) \ + dprintk(VIDC_HIGH|VIDC_PERF, sid, __fmt, ##__VA_ARGS__) + +#define d_vpr_e(__fmt, ...) \ + dprintk(VIDC_ERR, DEFAULT_SID, __fmt, ##__VA_ARGS__) +#define d_vpr_h(__fmt, ...) \ + dprintk(VIDC_HIGH, DEFAULT_SID, __fmt, ##__VA_ARGS__) +#define d_vpr_l(__fmt, ...) \ + dprintk(VIDC_LOW, DEFAULT_SID, __fmt, ##__VA_ARGS__) +#define d_vpr_p(__fmt, ...) \ + dprintk(VIDC_PERF, DEFAULT_SID, __fmt, ##__VA_ARGS__) +#define d_vpr_t(__fmt, ...) \ + dprintk(VIDC_PKT, DEFAULT_SID, __fmt, ##__VA_ARGS__) +#define d_vpr_b(__fmt, ...) \ + dprintk(VIDC_BUS, DEFAULT_SID, __fmt, ##__VA_ARGS__) + +#define dprintk_firmware(__level, __fmt, ...) \ + do { \ + if (__level & FW_FTRACE) { \ + char trace_logbuf[MAX_TRACER_LOG_LENGTH]; \ + int log_length = snprintf(trace_logbuf, \ + MAX_TRACER_LOG_LENGTH, \ + FW_DBG_TAG __fmt, \ + "fw", \ + ##__VA_ARGS__); \ + trace_msm_vidc_printf(trace_logbuf, \ + log_length); \ + } \ + if (__level & FW_PRINTK) { \ + pr_info(FW_DBG_TAG __fmt, \ + "fw", \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define dprintk_ratelimit(__level, __fmt, arg...) \ + do { \ + if (msm_vidc_check_ratelimit()) { \ + dprintk(__level, DEFAULT_SID, __fmt, arg); \ + } \ + } while (0) + +#define MSM_VIDC_ERROR(value) \ + do { if (value) \ + d_vpr_e("BugOn"); \ + BUG_ON(value); \ + } while (0) + +struct dentry *msm_vidc_debugfs_init_drv(void); +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core, + struct dentry *parent); +struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, + struct dentry *parent); +void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst); +void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, + enum msm_vidc_debugfs_event e); +int msm_vidc_check_ratelimit(void); +int get_sid(u32 *sid, u32 session_type); +void update_log_ctxt(u32 sid, u32 session_type, u32 fourcc); + +static inline char *get_debug_level_str(int level) +{ + switch (level) { + case VIDC_ERR: + return "err "; + case VIDC_HIGH|VIDC_PERF: + case VIDC_HIGH: + return "high"; + case VIDC_LOW: + return "low "; + case VIDC_PERF: + return "perf"; + case VIDC_PKT: + return "pkt "; + case VIDC_BUS: + return "bus "; + default: + return "????"; + } +} + +/** + * 0xx -> allow prints for all sessions + * 1xx -> allow only encoder prints + * 2xx -> allow only decoder prints + * 4xx -> allow only cvp prints + */ +static inline bool is_print_allowed(u32 sid, u32 level) +{ + if (!(msm_vidc_debug & level)) + return false; + + if (!((msm_vidc_debug >> 8) & 0xF)) + return true; + + if (!sid || sid > MAX_SUPPORTED_INSTANCES) + return true; + + if (ctxt[sid-1].session_type & msm_vidc_debug) + return true; + + return false; +} + +static inline char *get_codec_name(u32 sid) +{ + if (!sid || sid > MAX_SUPPORTED_INSTANCES) + return "....."; + + return ctxt[sid-1].name; +} + +static inline void put_sid(u32 sid) +{ + if (!sid || sid > MAX_SUPPORTED_INSTANCES) { + d_vpr_e("%s: invalid sid %#x\n", + __func__, sid); + return; + } + if (ctxt[sid-1].used) + ctxt[sid-1].used = 0; +} + +static inline void tic(struct msm_vidc_inst *i, enum profiling_points p, + char *b) +{ + struct timeval __ddl_tv; + + if (!i->debug.pdata[p].name[0]) + memcpy(i->debug.pdata[p].name, b, 64); + if ((msm_vidc_debug & VIDC_PERF) && + i->debug.pdata[p].sampling) { + do_gettimeofday(&__ddl_tv); + i->debug.pdata[p].start = + (__ddl_tv.tv_sec * 1000) + (__ddl_tv.tv_usec / 1000); + i->debug.pdata[p].sampling = false; + } +} + +static inline void toc(struct msm_vidc_inst *i, enum profiling_points p) +{ + struct timeval __ddl_tv; + + if ((msm_vidc_debug & VIDC_PERF) && + !i->debug.pdata[p].sampling) { + do_gettimeofday(&__ddl_tv); + i->debug.pdata[p].stop = (__ddl_tv.tv_sec * 1000) + + (__ddl_tv.tv_usec / 1000); + i->debug.pdata[p].cumulative += i->debug.pdata[p].stop - + i->debug.pdata[p].start; + i->debug.pdata[p].sampling = true; + } +} + +static inline void show_stats(struct msm_vidc_inst *i) +{ + int x; + + for (x = 0; x < MAX_PROFILING_POINTS; x++) { + if (i->debug.pdata[x].name[0] && + (msm_vidc_debug & VIDC_PERF)) { + if (i->debug.samples) { + s_vpr_p(i->sid, "%s averaged %d ms/sample\n", + i->debug.pdata[x].name, + i->debug.pdata[x].cumulative / + i->debug.samples); + } + + s_vpr_p(i->sid, "%s Samples: %d\n", + i->debug.pdata[x].name, i->debug.samples); + } + } +} + +static inline void msm_vidc_res_handle_fatal_hw_error( + struct msm_vidc_platform_resources *resources, + bool enable_fatal) +{ + enable_fatal &= resources->debug_timeout; + MSM_VIDC_ERROR(enable_fatal); +} + +static inline void msm_vidc_handle_hw_error(struct msm_vidc_core *core) +{ + bool enable_fatal = true; + + /* + * In current implementation user-initiated SSR triggers + * a fatal error from hardware. However, there is no way + * to know if fatal error is due to SSR or not. Handle + * user SSR as non-fatal. + */ + if (core->trigger_ssr) { + core->trigger_ssr = false; + enable_fatal = false; + } + + /* Video driver can decide FATAL handling of HW errors + * based on multiple factors. This condition check will + * be enhanced later. + */ + msm_vidc_res_handle_fatal_hw_error(&core->resources, enable_fatal); +} + +#endif diff --git a/techpack/video/msm/vidc/msm_vidc_internal.h b/techpack/video/msm/vidc/msm_vidc_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..8fdbf3434fcacc8a24ecd6806302d651a8d2e006 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_internal.h @@ -0,0 +1,634 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _MSM_VIDC_INTERNAL_H_ +#define _MSM_VIDC_INTERNAL_H_ + +#include <linux/atomic.h> +#include <linux/list.h> +#include <linux/time.h> +#include <linux/types.h> +#include <linux/completion.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/msm-bus.h> +#include <linux/msm-bus-board.h> +#include <linux/kref.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ctrls.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> +#include "msm_vidc.h" +#include <media/msm_media_info.h> +#include "vidc_hfi_api.h" +#include "vidc_hfi_helper.h" + +#define MSM_VIDC_DRV_NAME "msm_vidc_driver" + +/* kernel/msm-4.19 */ +#define MSM_VIDC_VERSION ((0 << 16) + (4 << 8) + 19) + +#define MAX_DEBUGFS_NAME 50 +#define DEFAULT_TIMEOUT 3 +#define DEFAULT_HEIGHT 240 +#define DEFAULT_WIDTH 320 +#define MIN_SUPPORTED_WIDTH 32 +#define MIN_SUPPORTED_HEIGHT 32 +#define DEFAULT_FPS 30 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 960 +#define SINGLE_INPUT_BUFFER 1 +#define SINGLE_OUTPUT_BUFFER 1 +#define MAX_NUM_INPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME +#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME + +#define MAX_SUPPORTED_INSTANCES 16 + +/* Maintains the number of FTB's between each FBD over a window */ +#define DCVS_FTB_WINDOW 16 +/* Superframe can have maximum of 32 frames */ +#define VIDC_SUPERFRAME_MAX 32 +#define COLOR_RANGE_UNSPECIFIED (-1) + +#define V4L2_EVENT_VIDC_BASE 10 +#define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE +#define OUTPUT_MPLANE V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE + +#define RATE_CONTROL_OFF (V4L2_MPEG_VIDEO_BITRATE_MODE_CQ + 1) +#define RATE_CONTROL_LOSSLESS (V4L2_MPEG_VIDEO_BITRATE_MODE_CQ + 2) +#define SYS_MSG_START HAL_SYS_INIT_DONE +#define SYS_MSG_END HAL_SYS_ERROR +#define SESSION_MSG_START HAL_SESSION_EVENT_CHANGE +#define SESSION_MSG_END HAL_SESSION_ERROR +#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START) +#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START) + +#define MAX_NAME_LENGTH 64 + +#define DB_DISABLE_SLICE_BOUNDARY \ + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY + +#define NUM_MBS_PER_SEC(__height, __width, __fps) \ + (NUM_MBS_PER_FRAME(__height, __width) * __fps) + +#define NUM_MBS_PER_FRAME(__height, __width) \ + ((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16)) + +#define call_core_op(c, op, ...) \ + (((c) && (c)->core_ops && (c)->core_ops->op) ? \ + ((c)->core_ops->op(__VA_ARGS__)) : 0) + +/* + * Convert Q16 number into Integer and Fractional part upto 2 places. + * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752; + * Integer part = 105752 / 65536 = 1; + * Reminder = 105752 * 0xFFFF = 40216; Last 16 bits. + * Fractional part = 40216 * 100 / 65536 = 61; + * Now convert to FP(1, 61, 100). + */ +#define Q16_INT(q) ((q) >> 16) +#define Q16_FRAC(q) ((((q) & 0xFFFF) * 100) >> 16) + +struct msm_vidc_inst; + +enum vidc_ports { + INPUT_PORT, + OUTPUT_PORT, + MAX_PORT_NUM +}; + +enum vidc_core_state { + VIDC_CORE_UNINIT = 0, + VIDC_CORE_INIT, + VIDC_CORE_INIT_DONE, +}; + +/* + * Do not change the enum values unless + * you know what you are doing + */ +enum instance_state { + MSM_VIDC_CORE_UNINIT_DONE = 0x0001, + MSM_VIDC_CORE_INIT, + MSM_VIDC_CORE_INIT_DONE, + MSM_VIDC_OPEN, + MSM_VIDC_OPEN_DONE, + MSM_VIDC_LOAD_RESOURCES, + MSM_VIDC_LOAD_RESOURCES_DONE, + MSM_VIDC_START, + MSM_VIDC_START_DONE, + MSM_VIDC_STOP, + MSM_VIDC_STOP_DONE, + MSM_VIDC_RELEASE_RESOURCES, + MSM_VIDC_RELEASE_RESOURCES_DONE, + MSM_VIDC_CLOSE, + MSM_VIDC_CLOSE_DONE, + MSM_VIDC_CORE_UNINIT, + MSM_VIDC_CORE_INVALID +}; + +struct buf_info { + struct list_head list; + struct vb2_buffer *buf; +}; + +struct msm_vidc_list { + struct list_head list; + struct mutex lock; +}; + +static inline void INIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist) +{ + mutex_init(&mlist->lock); + INIT_LIST_HEAD(&mlist->list); +} + +static inline void DEINIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist) +{ + mutex_destroy(&mlist->lock); +} + +enum buffer_owner { + DRIVER, + FIRMWARE, + CLIENT, + MAX_OWNER +}; + +struct vidc_freq_data { + struct list_head list; + u32 device_addr; + unsigned long freq; + bool turbo; +}; + +struct vidc_input_cr_data { + struct list_head list; + u32 index; + u32 input_cr; +}; + +struct recon_buf { + struct list_head list; + u32 buffer_index; + u32 CR; + u32 CF; +}; + +struct eos_buf { + struct list_head list; + struct msm_smem smem; + u32 is_queued; +}; + +struct internal_buf { + struct list_head list; + enum hal_buffer buffer_type; + struct msm_smem smem; + enum buffer_owner buffer_ownership; + bool mark_remove; +}; + +struct msm_vidc_csc_coeff { + u32 *vpe_csc_custom_matrix_coeff; + u32 *vpe_csc_custom_bias_coeff; + u32 *vpe_csc_custom_limit_coeff; +}; + +struct msm_vidc_buf_data { + struct list_head list; + u32 index; + u32 input_tag; + u32 input_tag2; +}; + +struct msm_vidc_window_data { + struct list_head list; + u32 frame_size; + u32 etb_count; +}; + +struct msm_vidc_common_data { + char key[128]; + int value; +}; + +struct msm_vidc_codec_data { + u32 fourcc; + enum session_type session_type; + int vpp_cycles; + int vsp_cycles; + int low_power_cycles; +}; + +struct msm_vidc_codec_capability { + enum hal_capability capability_type; + enum hal_domain domains; + enum hal_video_codec codecs; + u32 min; + u32 max; + u32 step_size; + u32 default_value; +}; + +struct msm_vidc_codec { + enum hal_domain domain; + enum hal_video_codec codec; +}; + +enum efuse_purpose { + SKU_VERSION = 0, +}; + +enum sku_version { + SKU_VERSION_0 = 0, + SKU_VERSION_1, + SKU_VERSION_2, +}; + +struct msm_vidc_efuse_data { + u32 start_address; + u32 size; + u32 mask; + u32 shift; + enum efuse_purpose purpose; +}; + +enum vpu_version { + VPU_VERSION_AR50 = 1, + VPU_VERSION_IRIS1, + VPU_VERSION_IRIS2, + VPU_VERSION_IRIS2_1, + VPU_VERSION_AR50_LITE, +}; + +struct msm_vidc_ubwc_config_data { + struct { + u32 max_channel_override : 1; + u32 mal_length_override : 1; + u32 hb_override : 1; + u32 bank_swzl_level_override : 1; + u32 bank_spreading_override : 1; + u32 reserved : 27; + } override_bit_info; + + u32 max_channels; + u32 mal_length; + u32 highest_bank_bit; + u32 bank_swzl_level; + u32 bank_spreading; +}; + +struct msm_vidc_platform_data { + struct msm_vidc_common_data *common_data; + unsigned int common_data_length; + struct msm_vidc_codec_data *codec_data; + unsigned int codec_data_length; + struct msm_vidc_codec *codecs; + uint32_t codecs_count; + struct msm_vidc_codec_capability *codec_caps; + uint32_t codec_caps_count; + struct msm_vidc_csc_coeff csc_data; + struct msm_vidc_efuse_data *efuse_data; + unsigned int efuse_data_length; + unsigned int sku_version; + uint32_t vpu_ver; + uint32_t num_vpp_pipes; + struct msm_vidc_ubwc_config_data *ubwc_config; +}; + +struct msm_vidc_format_desc { + char name[MAX_NAME_LENGTH]; + u8 description[32]; + u32 fourcc; +}; + +struct msm_vidc_format { + char name[MAX_NAME_LENGTH]; + u8 description[32]; + u32 count_min; + u32 count_min_host; + u32 count_actual; + struct v4l2_format v4l2_fmt; +}; + +struct msm_vidc_format_constraint { + u32 fourcc; + u32 num_planes; + u32 y_max_stride; + u32 y_buffer_alignment; + u32 uv_max_stride; + u32 uv_buffer_alignment; +}; + +struct msm_vidc_drv { + struct mutex lock; + struct list_head cores; + int num_cores; + struct dentry *debugfs_root; + int thermal_level; + u32 sku_version; +}; + +struct msm_video_device { + int type; + struct video_device vdev; +}; + +struct session_prop { + u32 fps; + u32 bitrate; + bool bframe_changed; + u32 extradata_ctrls; +}; + +struct buf_queue { + struct vb2_queue vb2_bufq; + struct mutex lock; +}; + +enum profiling_points { + SYS_INIT = 0, + SESSION_INIT, + LOAD_RESOURCES, + FRAME_PROCESSING, + FW_IDLE, + MAX_PROFILING_POINTS, +}; + +struct buf_count { + int etb; + int ftb; + int fbd; + int ebd; +}; + +struct batch_mode { + bool enable; + u32 size; +}; + +enum dcvs_flags { + MSM_VIDC_DCVS_INCR = BIT(0), + MSM_VIDC_DCVS_DECR = BIT(1), +}; + +struct clock_data { + int buffer_counter; + int min_threshold; + int nom_threshold; + int max_threshold; + bool dcvs_mode; + u32 dcvs_window; + unsigned long bitrate; + unsigned long min_freq; + unsigned long curr_freq; + u32 vpss_cycles; + u32 ise_cycles; + u32 ddr_bw; + u32 sys_cache_bw; + u32 operating_rate; + struct msm_vidc_codec_data *entry; + u32 core_id; + u32 dpb_fourcc; + u32 opb_fourcc; + u32 work_mode; + bool low_latency_mode; + bool is_legacy_cbr; + u32 work_route; + u32 dcvs_flags; + u32 frame_rate; +}; + +struct vidc_bus_vote_data { + u32 sid; + enum hal_domain domain; + enum hal_video_codec codec; + enum hal_uncompressed_format color_formats[2]; + int num_formats; /* 1 = DPB-OPB unified; 2 = split */ + int input_height, input_width, bitrate; + int output_height, output_width; + int rotation; + int compression_ratio; + int complexity_factor; + int input_cr; + unsigned int lcu_size; + unsigned int fps; + enum msm_vidc_power_mode power_mode; + u32 work_mode; + bool use_sys_cache; + bool b_frames_enabled; + unsigned long calc_bw_ddr; + unsigned long calc_bw_llcc; +}; + +struct profile_data { + int start; + int stop; + int cumulative; + char name[64]; + int sampling; + int average; +}; + +struct msm_vidc_debug { + struct profile_data pdata[MAX_PROFILING_POINTS]; + int profile; + int samples; +}; + +enum msm_vidc_modes { + VIDC_SECURE = BIT(0), + VIDC_TURBO = BIT(1), + VIDC_THUMBNAIL = BIT(2), + VIDC_LOW_POWER = BIT(3), +}; + +struct msm_vidc_core_ops { + unsigned long (*calc_freq)(struct msm_vidc_inst *inst, u32 filled_len); + int (*decide_work_route)(struct msm_vidc_inst *inst); + int (*decide_work_mode)(struct msm_vidc_inst *inst); + int (*decide_core_and_power_mode)(struct msm_vidc_inst *inst); + int (*calc_bw)(struct vidc_bus_vote_data *vidc_data); +}; + +struct msm_vidc_core { + struct list_head list; + struct mutex lock; + int id; + struct hfi_device *device; + struct msm_vidc_platform_data *platform_data; + struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES]; + struct v4l2_device v4l2_dev; + struct list_head instances; + struct dentry *debugfs_root; + enum vidc_core_state state; + struct completion completions[SYS_MSG_END - SYS_MSG_START + 1]; + enum msm_vidc_hfi_type hfi_type; + struct msm_vidc_platform_resources resources; + struct msm_vidc_capability *capabilities; + struct delayed_work fw_unload_work; + struct work_struct ssr_work; + struct workqueue_struct *vidc_core_workq; + enum hal_ssr_trigger_type ssr_type; + bool smmu_fault_handled; + bool trigger_ssr; + unsigned long min_freq; + unsigned long curr_freq; + struct msm_vidc_core_ops *core_ops; +}; + +struct msm_vidc_inst; +struct msm_vidc_inst_smem_ops { + int (*smem_map_dma_buf)(struct msm_vidc_inst *inst, + struct msm_smem *smem); + int (*smem_unmap_dma_buf)(struct msm_vidc_inst *inst, + struct msm_smem *smem); +}; + +struct msm_vidc_inst { + struct list_head list; + struct mutex sync_lock, lock; + struct msm_vidc_core *core; + enum session_type session_type; + void *session; + u32 sid; + struct session_prop prop; + enum instance_state state; + struct msm_vidc_format fmts[MAX_PORT_NUM]; + struct buf_queue bufq[MAX_PORT_NUM]; + struct msm_vidc_list input_crs; + struct msm_vidc_list scratchbufs; + struct msm_vidc_list persistbufs; + struct msm_vidc_list pending_getpropq; + struct msm_vidc_list outputbufs; + struct msm_vidc_list refbufs; + struct msm_vidc_list eosbufs; + struct msm_vidc_list registeredbufs; + struct msm_vidc_list cvpbufs; + struct msm_vidc_list etb_data; + struct msm_vidc_list fbd_data; + struct msm_vidc_list window_data; + struct msm_vidc_list client_data; + struct buffer_requirements buff_req; + struct vidc_frame_data superframe_data[VIDC_SUPERFRAME_MAX]; + struct v4l2_ctrl_handler ctrl_handler; + struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1]; + struct v4l2_fh event_handler; + struct msm_smem *extradata_handle; + bool in_reconfig; + struct dentry *debugfs_root; + void *priv; + struct msm_vidc_debug debug; + struct buf_count count; + struct clock_data clk_data; + struct vidc_bus_vote_data bus_data; + enum msm_vidc_modes flags; + struct msm_vidc_capability capability; + u32 buffer_size_limit; + enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM]; + enum multi_stream stream_output_mode; + struct v4l2_ctrl **ctrls; + u32 num_ctrls; + int bit_depth; + struct kref kref; + bool in_flush; + bool out_flush; + u32 pic_struct; + u32 colour_space; + u32 profile; + u32 level; + u32 entropy_mode; + u32 rc_type; + u32 hybrid_hp; + u32 layer_bitrate; + u32 client_set_ctrls; + bool static_rotation_flip_enabled; + struct internal_buf *dpb_extra_binfo; + struct msm_vidc_codec_data *codec_data; + struct hal_hdr10_pq_sei hdr10_sei_params; + struct batch_mode batch; + struct delayed_work batch_work; + struct msm_vidc_inst_smem_ops *smem_ops; + int (*buffer_size_calculators)(struct msm_vidc_inst *inst); + bool all_intra; + bool is_perf_eligible_session; + u32 max_filled_len; + int full_range; + u64 last_qbuf_time_ns; + bool active; +}; + +extern struct msm_vidc_drv *vidc_driver; + +struct msm_vidc_ctrl { + u32 id; + char name[MAX_NAME_LENGTH]; + enum v4l2_ctrl_type type; + s64 minimum; + s64 maximum; + s64 default_value; + u32 step; + u32 menu_skip_mask; + u32 flags; + const char * const *qmenu; +}; + +void handle_cmd_response(enum hal_command_response cmd, void *data); +int msm_vidc_trigger_ssr(struct msm_vidc_core *core, + enum hal_ssr_trigger_type type); +int msm_vidc_noc_error_info(struct msm_vidc_core *core); +int msm_vidc_check_session_supported(struct msm_vidc_inst *inst); +int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst); +void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type); + +enum msm_vidc_flags { + MSM_VIDC_FLAG_DEFERRED = BIT(0), + MSM_VIDC_FLAG_RBR_PENDING = BIT(1), + MSM_VIDC_FLAG_QUEUED = BIT(2), +}; + +struct msm_vidc_buffer { + struct list_head list; + struct kref kref; + struct msm_smem smem[VIDEO_MAX_PLANES]; + struct vb2_v4l2_buffer vvb; + enum msm_vidc_flags flags; +}; + +struct msm_vidc_cvp_buffer { + struct list_head list; + struct msm_smem smem; + struct msm_cvp_buffer buf; +}; + +void msm_comm_handle_thermal_event(void); +int msm_smem_alloc(size_t size, u32 align, u32 flags, + enum hal_buffer buffer_type, int map_kernel, + void *res, u32 session_type, struct msm_smem *smem, u32 sid); +int msm_smem_free(struct msm_smem *smem, u32 sid); + +struct context_bank_info *msm_smem_get_context_bank(u32 session_type, + bool is_secure, struct msm_vidc_platform_resources *res, + enum hal_buffer buffer_type, u32 sid); +int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem); +int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem); +struct dma_buf *msm_smem_get_dma_buf(int fd, u32 sid); +void msm_smem_put_dma_buf(void *dma_buf, u32 sid); +int msm_smem_cache_operations(struct dma_buf *dbuf, + enum smem_cache_ops cache_op, unsigned long offset, + unsigned long size, u32 sid); +void msm_vidc_fw_unload_handler(struct work_struct *work); +void msm_vidc_ssr_handler(struct work_struct *work); +/* + * XXX: normally should be in msm_vidc.h, but that's meant for public APIs, + * whereas this is private + */ +int msm_vidc_destroy(struct msm_vidc_inst *inst); +void *vidc_get_drv_data(struct device *dev); +#endif diff --git a/techpack/video/msm/vidc/msm_vidc_platform.c b/techpack/video/msm/vidc/msm_vidc_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..56f8d0e08e578cc261487ff8017b84db05ad80f5 --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_platform.c @@ -0,0 +1,2223 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + */ + +#include <linux/debugfs.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/ioctl.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/version.h> +#include <linux/io.h> +#include <linux/of_fdt.h> +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" + + +#define DDR_TYPE_LPDDR4 0x6 +#define DDR_TYPE_LPDDR4X 0x7 +#define DDR_TYPE_LPDDR5 0x8 +#define DDR_TYPE_LPDDR5X 0x9 + +#define CODEC_ENTRY(n, p, vsp, vpp, lp) \ +{ \ + .fourcc = n, \ + .session_type = p, \ + .vsp_cycles = vsp, \ + .vpp_cycles = vpp, \ + .low_power_cycles = lp \ +} + +#define EFUSE_ENTRY(sa, s, m, sh, p) \ +{ \ + .start_address = sa, \ + .size = s, \ + .mask = m, \ + .shift = sh, \ + .purpose = p \ +} + +#define UBWC_CONFIG(mco, mlo, hbo, bslo, bso, rs, mc, ml, hbb, bsl, bsp) \ +{ \ + .override_bit_info.max_channel_override = mco, \ + .override_bit_info.mal_length_override = mlo, \ + .override_bit_info.hb_override = hbo, \ + .override_bit_info.bank_swzl_level_override = bslo, \ + .override_bit_info.bank_spreading_override = bso, \ + .override_bit_info.reserved = rs, \ + .max_channels = mc, \ + .mal_length = ml, \ + .highest_bank_bit = hbb, \ + .bank_swzl_level = bsl, \ + .bank_spreading = bsp, \ +} + +static struct msm_vidc_codec_data default_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 125, 675, 320), +}; + +/* Update with lito data */ +static struct msm_vidc_codec_data lito_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 0, 200, 200), +}; + +/* Update with Kona data */ +static struct msm_vidc_codec_data kona_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 25, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 25, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 60, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 25, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 25, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 25, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 25, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 60, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 60, 200, 200), +}; + +static struct msm_vidc_codec_data lagoon_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 25, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 25, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 25, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 25, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 25, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 60, 200, 200), +}; + +/* Update with SM6150 data */ +static struct msm_vidc_codec_data sm6150_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200), +}; + +static struct msm_vidc_codec_data bengal_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 0, 440, 440), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 0, 440, 440), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 0, 440, 440), +}; + +static struct msm_vidc_codec_data scuba_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 0, 440, 440), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 0, 440, 440), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 0, 440, 440), +}; + +/* Update with 855 data */ +static struct msm_vidc_codec_data sm8150_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 0, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 0, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 0, 200, 200), +}; + +static struct msm_vidc_codec_data sdm845_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200), +}; + +static struct msm_vidc_codec_data sdm670_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 125, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 50, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 50, 200, 200), +}; + +#define ENC HAL_VIDEO_DOMAIN_ENCODER +#define DEC HAL_VIDEO_DOMAIN_DECODER +#define H264 HAL_VIDEO_CODEC_H264 +#define HEVC HAL_VIDEO_CODEC_HEVC +#define VP8 HAL_VIDEO_CODEC_VP8 +#define VP9 HAL_VIDEO_CODEC_VP9 +#define MPEG2 HAL_VIDEO_CODEC_MPEG2 +#define DOMAINS_ALL (HAL_VIDEO_DOMAIN_ENCODER | HAL_VIDEO_DOMAIN_DECODER) +#define CODECS_ALL (HAL_VIDEO_CODEC_H264 | HAL_VIDEO_CODEC_HEVC | \ + HAL_VIDEO_CODEC_VP8 | HAL_VIDEO_CODEC_VP9 | \ + HAL_VIDEO_CODEC_MPEG2) + +static struct msm_vidc_codec bengal_codecs[] = { + /* {domain, codec} */ + {DEC, H264}, {DEC, HEVC}, {DEC, VP9}, + {ENC, H264}, {ENC, HEVC}, +}; + +static struct msm_vidc_codec scuba_codecs[] = { + /* {domain, codec} */ + {DEC, H264}, {DEC, HEVC}, {DEC, VP9}, + {ENC, H264}, {ENC, HEVC}, +}; + +static struct msm_vidc_codec default_codecs[] = { + /* {domain, codec} */ + {DEC, H264}, {DEC, HEVC}, {DEC, VP8}, {DEC, VP9}, {DEC, MPEG2}, + {ENC, H264}, {ENC, HEVC}, {ENC, VP8}, +}; + +static struct msm_vidc_codec lagoon_codecs[] = { + /* {domain, codec} */ + {DEC, H264}, {DEC, HEVC}, {DEC, VP9}, {DEC, MPEG2}, + {ENC, H264}, {ENC, HEVC}, +}; + +static struct msm_vidc_codec_capability lito_capabilities_v0[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 96, 5760, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 96, 5760, 1, 1080}, + /* ((5760 * 2880) / 256) */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 36, 64800, 1, 8160}, + /* ((3840x2176)/256)@60fps */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 36, 1958400, 1, 1958400}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 480, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, 480, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 200000000, 1, 20000000}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 200000000, 1, 20000000}, + {CAP_SCALE_X, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_Y, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_X, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_SCALE_Y, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_BFRAME, ENC, H264|HEVC, 0, 1, 1, 0}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 4, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_I_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 20}, + {CAP_P_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 40}, + {CAP_B_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 40}, + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* VP8 specific */ + {CAP_FRAME_WIDTH, ENC|DEC, VP8, 96, 4096, 1, 1920}, + {CAP_FRAME_HEIGHT, ENC|DEC, VP8, 96, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_MBS_PER_FRAME, ENC|DEC, VP8, 36, 34816, 1, 8160}, + /* (3840 * 2176) / 256) * 30*/ + {CAP_MBS_PER_SECOND, ENC|DEC, VP8, 36, 979200, 1, 244800}, + {CAP_FRAMERATE, ENC|DEC, VP8, 1, 240, 1, 30}, + {CAP_BITRATE, ENC, VP8, 1, 100000000, 1, 20000000}, + {CAP_BITRATE, DEC, VP8, 1, 100000000, 1, 20000000}, + + /* Mpeg2 decoder specific */ + {CAP_FRAME_WIDTH, DEC, MPEG2, 96, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DEC, MPEG2, 96, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_MBS_PER_FRAME, DEC, MPEG2, 36, 8160, 1, 8160}, + /* ((1920 * 1088) / 256) * 30*/ + {CAP_MBS_PER_SECOND, DEC, MPEG2, 36, 244800, 1, 244800}, + {CAP_FRAMERATE, DEC, MPEG2, 1, 30, 1, 30}, + {CAP_BITRATE, DEC, MPEG2, 1, 40000000, 1, 20000000}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 96, 4096, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 96, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 36, 34816, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 40000000, 1, 20000000}, + + /* Batch Mode Decode */ + {CAP_BATCH_MAX_MB_PER_FRAME, DEC, CODECS_ALL, 36, 8160, 1, 8160}, + /* (1920 * 1080) / 256 */ + {CAP_BATCH_MAX_FPS, DEC, CODECS_ALL, 1, 30, 1, 30}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 240, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + Default for levels is UNKNOWN value. But if we use unknown + value here to set as default, max value needs to be set to + unknown as well, which creates a problem of allowing client + to set higher level than supported */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5}, +}; + +static struct msm_vidc_codec_capability lito_capabilities_v1[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 96, 4096, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 96, 4096, 1, 1080}, + /* ((4096 * 2176) / 256) */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 36, 34816, 1, 8160}, + /* UHD@30 decode + 1080@30 encode */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 36, 1224000, 1, 1224000}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 240, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, 240, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 100000000, 1, 20000000}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 100000000, 1, 20000000}, + {CAP_SCALE_X, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_Y, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_X, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_SCALE_Y, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_BFRAME, ENC, H264|HEVC, 0, 1, 1, 0}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 4, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_I_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 20}, + {CAP_P_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 40}, + {CAP_B_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 40}, + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* VP8 specific */ + {CAP_FRAME_WIDTH, ENC|DEC, VP8, 96, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, ENC|DEC, VP8, 96, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_MBS_PER_FRAME, ENC|DEC, VP8, 36, 8160, 1, 8160}, + /* ((1920 * 1088) / 256) * 60*/ + {CAP_MBS_PER_SECOND, ENC|DEC, VP8, 36, 489600, 1, 244800}, + {CAP_FRAMERATE, ENC|DEC, VP8, 1, 120, 1, 30}, + {CAP_BITRATE, ENC, VP8, 1, 40000000, 1, 20000000}, + {CAP_BITRATE, DEC, VP8, 1, 100000000, 1, 20000000}, + + /* Mpeg2 decoder specific */ + {CAP_FRAME_WIDTH, DEC, MPEG2, 96, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DEC, MPEG2, 96, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_MBS_PER_FRAME, DEC, MPEG2, 36, 8160, 1, 8160}, + /* ((1920 * 1088) / 256) * 30*/ + {CAP_MBS_PER_SECOND, DEC, MPEG2, 36, 244800, 1, 244800}, + {CAP_FRAMERATE, DEC, MPEG2, 1, 30, 1, 30}, + {CAP_BITRATE, DEC, MPEG2, 1, 40000000, 1, 20000000}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 96, 4096, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 96, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 36, 34816, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 40000000, 1, 20000000}, + + /* Batch Mode Decode */ + {CAP_BATCH_MAX_MB_PER_FRAME, DEC, CODECS_ALL, 36, 8160, 1, 8160}, + /* (1920 * 1080) / 256 */ + {CAP_BATCH_MAX_FPS, DEC, CODECS_ALL, 1, 30, 1, 30}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 240, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + Default for levels is UNKNOWN value. But if we use unknown + value here to set as default, max value needs to be set to + unknown as well, which creates a problem of allowing client + to set higher level than supported */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5}, +}; + +static struct msm_vidc_codec_capability lagoon_capabilities_v0[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value,} */ + /* Encode spec */ + {CAP_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + {CAP_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_MBS_PER_FRAME, ENC, CODECS_ALL, 64, 34816, 1, 8160}, + /* ((3840 * 2176) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND, ENC, CODECS_ALL, 64, 979200, 1, 244800}, + {CAP_FRAMERATE, ENC, CODECS_ALL, 1, 240, 1, 30}, + + /* Decode spec */ + {CAP_FRAME_WIDTH, DEC, CODECS_ALL, 128, 5760, 1, 1920}, + {CAP_FRAME_HEIGHT, DEC, CODECS_ALL, 128, 5760, 1, 1080}, + /* (5760 * 2880) / 256 */ + {CAP_MBS_PER_FRAME, DEC, CODECS_ALL, 64, 64800, 1, 8160}, + /* ((3840 * 2176) / 256) * 60 fps */ + {CAP_MBS_PER_SECOND, DEC, CODECS_ALL, 64, 1958400, 1, 244800}, + {CAP_FRAMERATE, DEC, CODECS_ALL, 1, 480, 1, 30}, + + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, INT_MAX, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 100000000, 1, 20000000}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 100000000, 1, 20000000}, + {CAP_SCALE_X, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_Y, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_X, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_SCALE_Y, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_BFRAME, ENC, H264|HEVC, 0, 1, 1, 0}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 2, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_I_FRAME_QP, DEC, VP9, 0, 127, 1, 20}, + {CAP_P_FRAME_QP, DEC, VP9, 0, 127, 1, 40}, + {CAP_B_FRAME_QP, DEC, VP9, 0, 127, 1, 40}, + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* Mpeg2 decoder specific */ + {CAP_FRAME_WIDTH, DEC, MPEG2, 128, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DEC, MPEG2, 128, 1920, 1, 1088}, + /* (1920 * 1088) / 256 */ + {CAP_MBS_PER_FRAME, DEC, MPEG2, 64, 8160, 1, 8160}, + /* ((1920 * 1088) / 256) * 30*/ + {CAP_MBS_PER_SECOND, DEC, MPEG2, 64, 244800, 1, 244800}, + {CAP_FRAMERATE, DEC, MPEG2, 1, 30, 1, 30}, + {CAP_BITRATE, DEC, MPEG2, 1, 40000000, 1, 20000000}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 34816, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 40000000, 1, 20000000}, + + /* Batch Mode Decode */ + {CAP_BATCH_MAX_MB_PER_FRAME, DEC, CODECS_ALL, 64, 8160, 1, 8160}, + /* (1920 * 1088) / 256 */ + {CAP_BATCH_MAX_FPS, DEC, CODECS_ALL, 1, 30, 1, 30}, + + /* Lossless encoding usecase specific */ + {CAP_LOSSLESS_FRAME_WIDTH, ENC, H264|HEVC, 128, 4096, 1, 1920}, + {CAP_LOSSLESS_FRAME_HEIGHT, ENC, H264|HEVC, 128, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_LOSSLESS_MBS_PER_FRAME, ENC, H264|HEVC, 64, 34816, 1, 8160}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 120, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + * Default for levels is UNKNOWN value. But if we use unknown + * value here to set as default, max value needs to be set to + * unknown as well, which creates a problem of allowing client + * to set higher level than supported + */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_0}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_0}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4}, +}; + +static struct msm_vidc_codec_capability lagoon_capabilities_v1[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value,} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 34816, 1, 8160}, + /* ((3840 * 2176) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 64, 979200, 1, 244800}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 240, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, INT_MAX, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 100000000, 1, 20000000}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 100000000, 1, 20000000}, + {CAP_SCALE_X, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_Y, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_X, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_SCALE_Y, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_BFRAME, ENC, H264|HEVC, 0, 1, 1, 0}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 2, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_I_FRAME_QP, DEC, VP9, 0, 127, 1, 20}, + {CAP_P_FRAME_QP, DEC, VP9, 0, 127, 1, 40}, + {CAP_B_FRAME_QP, DEC, VP9, 0, 127, 1, 40}, + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* Mpeg2 decoder specific */ + {CAP_FRAME_WIDTH, DEC, MPEG2, 128, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DEC, MPEG2, 128, 1920, 1, 1088}, + /* (1920 * 1088) / 256 */ + {CAP_MBS_PER_FRAME, DEC, MPEG2, 64, 8160, 1, 8160}, + /* ((1920 * 1088) / 256) * 30*/ + {CAP_MBS_PER_SECOND, DEC, MPEG2, 64, 244800, 1, 244800}, + {CAP_FRAMERATE, DEC, MPEG2, 1, 30, 1, 30}, + {CAP_BITRATE, DEC, MPEG2, 1, 40000000, 1, 20000000}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1080}, + /* (4096 * 2176) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 34816, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 40000000, 1, 20000000}, + + /* Batch Mode Decode */ + {CAP_BATCH_MAX_MB_PER_FRAME, DEC, CODECS_ALL, 64, 8160, 1, 8160}, + /* (1920 * 1088) / 256 */ + {CAP_BATCH_MAX_FPS, DEC, CODECS_ALL, 1, 30, 1, 30}, + + /* Lossless encoding usecase specific */ + {CAP_LOSSLESS_FRAME_WIDTH, ENC, H264|HEVC, 128, 4096, 1, 1920}, + {CAP_LOSSLESS_FRAME_HEIGHT, ENC, H264|HEVC, 128, 4096, 1, 1080}, + /* (4096 * 2176)/ 256 */ + {CAP_LOSSLESS_MBS_PER_FRAME, ENC, H264|HEVC, 64, 34816, 1, 8160}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 120, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + * Default for levels is UNKNOWN value. But if we use unknown + * value here to set as default, max value needs to be set to + * unknown as well, which creates a problem of allowing client + * to set higher level than supported + */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_0}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_0}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4}, +}; + +static struct msm_vidc_codec_capability bengal_capabilities_v0[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1080}, + /* ((1920 * 1088) / 256) */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 8160, 1, 8160}, + /* 1080@30 decode + 1080@30 encode */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 64, 489600, 1, 244800}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 120, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, INT_MAX, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 60000000, 1, 20000000}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 4, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 60000000, 1, 20000000}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 8160, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 35000000, 1, 20000000}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 30, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + * Default for levels is UNKNOWN value. But if we use unknown + * value here to set as default, max value needs to be set to + * unknown as well, which creates a problem of allowing client + * to set higher level than supported + */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, +}; + +static struct msm_vidc_codec_capability bengal_capabilities_v1[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1080}, + /* ((1920 * 1088) / 256) */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 8160, 1, 8160}, + /* 1920*1088 @30fps */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 64, 244800, 1, 244800}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 120, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, INT_MAX, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 60000000, 1, 20000000}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 4, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 60000000, 1, 20000000}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 8160, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 35000000, 1, 20000000}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 30, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + * Default for levels is UNKNOWN value. But if we use unknown + * value here to set as default, max value needs to be set to + * unknown as well, which creates a problem of allowing client + * to set higher level than supported + */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, +}; + +static struct msm_vidc_codec_capability scuba_capabilities[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1080}, + /* ((1920 * 1088) / 256) */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 8160, 1, 8160}, + /* 1920*1088 @30fps */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 64, 244800, 1, 244800}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 120, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, INT_MAX, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 60000000, 1, 20000000}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 4, 1, 0}, + /* ((1920 * 1088) / 256) * 30 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 244800, 1, 244800}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 60000000, 1, 20000000}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 8160, 1, 8160}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 35000000, 1, 20000000}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 30, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 8192, 1, 8192}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 8192, 1, 8192}, + + /* Level for AVC and HEVC encoder specific. + * Default for levels is UNKNOWN value. But if we use unknown + * value here to set as default, max value needs to be set to + * unknown as well, which creates a problem of allowing client + * to set higher level than supported + */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, +}; + +static struct msm_vidc_codec_capability kona_capabilities[] = { + /* {cap_type, domains, codecs, min, max, step_size, default_value,} */ + {CAP_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 8192, 1, 1920}, + {CAP_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 8192, 1, 1080}, + /* (8192 * 4320) / 256 */ + {CAP_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 138240, 1, 138240}, + /* ((1920 * 1088) / 256) * 960 fps */ + {CAP_MBS_PER_SECOND, DOMAINS_ALL, CODECS_ALL, 64, 7833600, 1, 7833600}, + {CAP_FRAMERATE, DOMAINS_ALL, CODECS_ALL, 1, 960, 1, 30}, + {CAP_OPERATINGRATE, DOMAINS_ALL, CODECS_ALL, 1, INT_MAX, 1, 30}, + {CAP_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 220000000, 1, 20000000}, + {CAP_BITRATE, ENC, HEVC, 1, 160000000, 1, 20000000}, + {CAP_CABAC_BITRATE, ENC, H264, 1, 160000000, 1, 20000000}, + {CAP_SCALE_X, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_Y, ENC, CODECS_ALL, 8192, 65536, 1, 8192}, + {CAP_SCALE_X, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_SCALE_Y, DEC, CODECS_ALL, 65536, 65536, 1, 65536}, + {CAP_BFRAME, ENC, H264|HEVC, 0, 1, 1, 0}, + {CAP_HIER_P_NUM_ENH_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0}, + {CAP_LTR_COUNT, ENC, H264|HEVC, 0, 2, 1, 0}, + /* ((4096 * 2304) / 256) * 60 fps */ + {CAP_MBS_PER_SECOND_POWER_SAVE, ENC, CODECS_ALL, + 0, 2211840, 1, 2211840}, + {CAP_I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10}, + {CAP_P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20}, + {CAP_I_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 20}, + {CAP_P_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 40}, + {CAP_B_FRAME_QP, ENC, VP8|VP9, 0, 127, 1, 40}, + /* 10 slices */ + {CAP_SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10}, + {CAP_MAX_VIDEOCORES, DOMAINS_ALL, CODECS_ALL, 0, 1, 1, 1}, + + /* VP8 specific */ + {CAP_FRAME_WIDTH, ENC|DEC, VP8, 128, 4096, 1, 1920}, + {CAP_FRAME_HEIGHT, ENC|DEC, VP8, 128, 4096, 1, 1080}, + /* (4096 * 2304) / 256 */ + {CAP_MBS_PER_FRAME, ENC|DEC, VP8, 64, 36864, 1, 8160}, + /* ((4096 * 2304) / 256) * 120 */ + {CAP_MBS_PER_SECOND, ENC|DEC, VP8, 64, 4423680, 1, 244800}, + {CAP_BFRAME, ENC, VP8, 0, 0, 1, 0}, + {CAP_FRAMERATE, ENC, VP8, 1, 60, 1, 30}, + {CAP_FRAMERATE, DEC, VP8, 1, 120, 1, 30}, + {CAP_BITRATE, ENC, VP8, 1, 74000000, 1, 20000000}, + {CAP_BITRATE, DEC, VP8, 1, 100000000, 1, 20000000}, + + /* Mpeg2 decoder specific */ + {CAP_FRAME_WIDTH, DEC, MPEG2, 128, 1920, 1, 1920}, + {CAP_FRAME_HEIGHT, DEC, MPEG2, 128, 1920, 1, 1080}, + /* (1920 * 1088) / 256 */ + {CAP_MBS_PER_FRAME, DEC, MPEG2, 64, 8160, 1, 8160}, + /* ((1920 * 1088) / 256) * 30*/ + {CAP_MBS_PER_SECOND, DEC, MPEG2, 64, 244800, 1, 244800}, + {CAP_FRAMERATE, DEC, MPEG2, 1, 30, 1, 30}, + {CAP_BITRATE, DEC, MPEG2, 1, 40000000, 1, 20000000}, + + /* Secure usecase specific */ + {CAP_SECURE_FRAME_WIDTH, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1920}, + {CAP_SECURE_FRAME_HEIGHT, DOMAINS_ALL, CODECS_ALL, 128, 4096, 1, 1080}, + /* (4096 * 2304) / 256 */ + {CAP_SECURE_MBS_PER_FRAME, DOMAINS_ALL, CODECS_ALL, 64, 36864, 1, 36864}, + {CAP_SECURE_BITRATE, DOMAINS_ALL, CODECS_ALL, 1, 40000000, 1, 20000000}, + + /* Batch Mode Decode */ + {CAP_BATCH_MAX_MB_PER_FRAME, DEC, CODECS_ALL, 64, 34816, 1, 34816}, + /* (4096 * 2176) / 256 */ + {CAP_BATCH_MAX_FPS, DEC, CODECS_ALL, 1, 120, 1, 120}, + + /* Lossless encoding usecase specific */ + {CAP_LOSSLESS_FRAME_WIDTH, ENC, H264|HEVC, 128, 4096, 1, 1920}, + {CAP_LOSSLESS_FRAME_HEIGHT, ENC, H264|HEVC, 128, 4096, 1, 1080}, + /* (4096 * 2304) / 256 */ + {CAP_LOSSLESS_MBS_PER_FRAME, ENC, H264|HEVC, 64, 36864, 1, 36864}, + + /* All intra encoding usecase specific */ + {CAP_ALLINTRA_MAX_FPS, ENC, H264|HEVC, 1, 240, 1, 30}, + + /* Image specific */ + {CAP_HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512}, + {CAP_HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 16384, 1, 16384}, + {CAP_HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 16384, 1, 16384}, + + /* Level for AVC and HEVC encoder specific. + Default for levels is UNKNOWN value. But if we use unknown + value here to set as default, max value needs to be set to + unknown as well, which creates a problem of allowing client + to set higher level than supported */ + {CAP_H264_LEVEL, ENC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0}, + {CAP_HEVC_LEVEL, ENC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6}, + + /* Level for AVC and HEVC decoder specific */ + {CAP_H264_LEVEL, DEC, H264, V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, 1, + V4L2_MPEG_VIDEO_H264_LEVEL_5_0}, + {CAP_HEVC_LEVEL, DEC, HEVC, V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, 1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5}, +}; + +/* + * Custom conversion coefficients for resolution: 176x144 negative + * coeffs are converted to s4.9 format + * (e.g. -22 converted to ((1 << 13) - 22) + * 3x3 transformation matrix coefficients in s4.9 fixed point format + */ +static u32 vpe_csc_custom_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = { + 440, 8140, 8098, 0, 460, 52, 0, 34, 463 +}; + +/* offset coefficients in s9 fixed point format */ +static u32 vpe_csc_custom_bias_coeff[HAL_MAX_BIAS_COEFFS] = { + 53, 0, 4 +}; + +/* clamping value for Y/U/V([min,max] for Y/U/V) */ +static u32 vpe_csc_custom_limit_coeff[HAL_MAX_LIMIT_COEFFS] = { + 16, 235, 16, 240, 16, 240 +}; + +static struct msm_vidc_common_data default_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, +}; + +/* Update with lito */ +static struct msm_vidc_common_data lito_common_data_v0[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 1958400, + /** + * ((3840x2176)/256)@60 + * UHD@30 decode + UHD@30 encode + */ + }, + { + .key = "qcom,max-image-load", + .value = 262144, /* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160,/* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800,/* ((1920x1088)/256) MBs@30fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160,/* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 244800,/* ((1920x1088)/256) MBs@30fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 130560,/* ((3840x2176)/256) x 4 */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,cvp-internal", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 760000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, +}; + +static struct msm_vidc_common_data lito_common_data_v1[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 1224000, + /** + * UHD@30 decode + 1080@30 encode + */ + }, + { + .key = "qcom,max-image-load", + .value = 262144, /* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160,/* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800,/* ((1920x1088)/256) MBs@30fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160,/* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 244800,/* ((1920x1088)/256) MBs@30fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 130560,/* ((3840x2176)/256) x 4 */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,cvp-internal", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 760000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, +}; + +static struct msm_vidc_common_data lagoon_common_data_v0[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 1958400, + /** + * ((3840x2176)/256)@60 + * UHD@30 decode + UHD@30 encode + */ + }, + { + .key = "qcom,max-image-load", + .value = 262144,/* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 130560, /* ((3840x2176)/256) x 4 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, /* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* ((1920x1088)/256)@30fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, /* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, /* ((1920x1088)/256) MBs@60fps */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 436000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, + { + .key = "qcom,avsync-window-size", + .value = 40, + }, +}; + +static struct msm_vidc_common_data lagoon_common_data_v1[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 1224000, + /** + * UHD@30 decode + 1080@30 encode + */ + }, + { + .key = "qcom,max-image-load", + .value = 262144, /* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 130560, /* ((3840x2176)/256) x 4 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, /* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* ((1920x1088)/256)@30fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, /* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, /* ((1920x1088)/256) MBs@60fps */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 436000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, + { + .key = "qcom,avsync-window-size", + .value = 40, + }, +}; + +static struct msm_vidc_common_data kona_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 7833600, + /** + * (7680x4320@60fps, 3840x2176@240fps + * Greater than 4096x2176@120fps, + * 8192x4320@48fps) + */ + + }, + { + .key = "qcom,max-image-load", + .value = 1048576, /* ((16384x16384)/256)@1fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 173056, /* (8192x4320)/256 + (4096x2176)/256*/ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, /* ((1920x1088)/256) */ + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 489600, /* ((1920x1088)/256)@60fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 32640, /* 3840x2176/256 */ + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 1958400, /* 3840x2176/256 MBs@60fps */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,cvp-external", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 326389, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 44156, + }, + { + .key = "qcom,avsync-window-size", + .value = 40, + }, +}; + +static struct msm_vidc_common_data sm6150_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 5, + }, + { + .key = "qcom,max-hw-load", + .value = 1216800, + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166666, + }, +}; + +static struct msm_vidc_common_data bengal_common_data_v0[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 489600, /* ((1088x1920)/256)@60fps */ + }, + { + .key = "qcom,max-image-load", + .value = 262144, /* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 65280,/* ((3840x2176)/256) x 2 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 225975, + }, +}; + +static struct msm_vidc_common_data bengal_common_data_v1[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 244800, /* ((1088x1920)/256)@30fps */ + }, + { + .key = "qcom,max-image-load", + .value = 262144, /* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 65280,/* ((3840x2176)/256) x 2 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 225975, + }, +}; + +static struct msm_vidc_common_data scuba_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 352800, + /* ((1088x1920)/256)@30fps + ((720x1280)/256)@30fps*/ + }, + { + .key = "qcom,max-image-load", + .value = 262144, /* ((8192x8192)/256)@1fps */ + }, + { + .key = "qcom,max-mbpf", + .value = 65280,/* ((3840x2176)/256) x 2 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 225975, + }, +}; + +static struct msm_vidc_common_data sm8150_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 2, /* + * As per design driver allows 3rd + * instance as well since the secure + * flags were updated later for the + * current instance. Hence total + * secure sessions would be + * max-secure-instances + 1. + */ + }, + { + .key = "qcom,max-hw-load", + .value = 3916800, /* + * 1920x1088/256 MBs@480fps. It is less + * any other usecases (ex: + * 3840x2176@120fps, 4096x2176@96ps, + * 7680x4320@30fps) + */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,cvp-internal", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 760000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, +}; + +static struct msm_vidc_common_data sdm845_common_data[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,domain-attr-cache-pagetables", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 5, + }, + { + .key = "qcom,max-hw-load", + .value = 3133440, /* 4096x2176@90 */ + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, + }, + { + .key = "qcom,power-collapse-delay", + .value = 500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 250, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, +}; + +static struct msm_vidc_common_data sdm670_common_data_v0[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 5, + }, + { + .key = "qcom,max-hw-load", + .value = 1944000, + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, + }, + { + .key = "qcom,power-collapse-delay", + .value = 500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 250, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, +}; + +static struct msm_vidc_common_data sdm670_common_data_v1[] = { + { + .key = "qcom,never-unload-fw", + .value = 1, + }, + { + .key = "qcom,sw-power-collapse", + .value = 1, + }, + { + .key = "qcom,domain-attr-non-fatal-faults", + .value = 1, + }, + { + .key = "qcom,max-secure-instances", + .value = 5, + }, + { + .key = "qcom,max-hw-load", + .value = 1216800, + }, + { + .key = "qcom,max-hq-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-hq-mbs-per-sec", + .value = 244800, /* 1920 x 1088 @ 30 fps */ + }, + { + .key = "qcom,max-b-frame-mbs-per-frame", + .value = 8160, + }, + { + .key = "qcom,max-b-frame-mbs-per-sec", + .value = 489600, + }, + { + .key = "qcom,power-collapse-delay", + .value = 500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 250, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, +}; + +static struct msm_vidc_efuse_data lito_efuse_data[] = { + EFUSE_ENTRY(0x00786008, 4, 0x00200000, 0x15, SKU_VERSION), +}; + +static struct msm_vidc_efuse_data lagoon_efuse_data[] = { + EFUSE_ENTRY(0x007801E8, 4, 0x00004000, 0x0E, SKU_VERSION), +}; + +static struct msm_vidc_efuse_data sdm670_efuse_data[] = { + EFUSE_ENTRY(0x007801A0, 4, 0x00008000, 0x0f, SKU_VERSION), +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data kona_ubwc_data[] = { + UBWC_CONFIG(1, 1, 1, 0, 0, 0, 8, 32, 16, 0, 0), +}; + +static struct msm_vidc_platform_data default_data = { + .codec_data = default_codec_data, + .codec_data_length = ARRAY_SIZE(default_codec_data), + .common_data = default_common_data, + .common_data_length = ARRAY_SIZE(default_common_data), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_IRIS2, + .num_vpp_pipes = 0x4, + .ubwc_config = 0x0, +}; + +static struct msm_vidc_platform_data lito_data = { + .codec_data = lito_codec_data, + .codec_data_length = ARRAY_SIZE(lito_codec_data), + .common_data = lito_common_data_v0, + .common_data_length = ARRAY_SIZE(lito_common_data_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = lito_efuse_data, + .efuse_data_length = ARRAY_SIZE(lito_efuse_data), + .sku_version = 0, + .vpu_ver = VPU_VERSION_IRIS1, + .num_vpp_pipes = 0x2, + .ubwc_config = 0x0, + .codecs = default_codecs, + .codecs_count = ARRAY_SIZE(default_codecs), + .codec_caps = lito_capabilities_v0, + .codec_caps_count = ARRAY_SIZE(lito_capabilities_v0), +}; + +static struct msm_vidc_platform_data kona_data = { + .codec_data = kona_codec_data, + .codec_data_length = ARRAY_SIZE(kona_codec_data), + .common_data = kona_common_data, + .common_data_length = ARRAY_SIZE(kona_common_data), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_IRIS2, + .num_vpp_pipes = 0x4, + .ubwc_config = kona_ubwc_data, + .codecs = default_codecs, + .codecs_count = ARRAY_SIZE(default_codecs), + .codec_caps = kona_capabilities, + .codec_caps_count = ARRAY_SIZE(kona_capabilities), +}; + +static struct msm_vidc_platform_data lagoon_data = { + .codec_data = lagoon_codec_data, + .codec_data_length = ARRAY_SIZE(lagoon_codec_data), + .common_data = lagoon_common_data_v0, + .common_data_length = ARRAY_SIZE(lagoon_common_data_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = lagoon_efuse_data, + .efuse_data_length = ARRAY_SIZE(lagoon_efuse_data), + .sku_version = 0, + .vpu_ver = VPU_VERSION_IRIS2_1, + .num_vpp_pipes = 0x1, + .ubwc_config = 0x0, + .codecs = lagoon_codecs, + .codecs_count = ARRAY_SIZE(lagoon_codecs), + .codec_caps = lagoon_capabilities_v0, + .codec_caps_count = ARRAY_SIZE(lagoon_capabilities_v0), +}; + +static struct msm_vidc_platform_data sm6150_data = { + .codec_data = sm6150_codec_data, + .codec_data_length = ARRAY_SIZE(sm6150_codec_data), + .common_data = sm6150_common_data, + .common_data_length = ARRAY_SIZE(sm6150_common_data), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_AR50, + .num_vpp_pipes = 0x1, + .ubwc_config = 0x0, +}; + +static struct msm_vidc_platform_data bengal_data = { + .codec_data = bengal_codec_data, + .codec_data_length = ARRAY_SIZE(bengal_codec_data), + .common_data = bengal_common_data_v0, + .common_data_length = ARRAY_SIZE(bengal_common_data_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_AR50_LITE, + .num_vpp_pipes = 0x1, + .ubwc_config = 0x0, + .codecs = bengal_codecs, + .codecs_count = ARRAY_SIZE(bengal_codecs), + .codec_caps = bengal_capabilities_v0, + .codec_caps_count = ARRAY_SIZE(bengal_capabilities_v0), +}; + +static struct msm_vidc_platform_data scuba_data = { + .codec_data = scuba_codec_data, + .codec_data_length = ARRAY_SIZE(scuba_codec_data), + .common_data = scuba_common_data, + .common_data_length = ARRAY_SIZE(scuba_common_data), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_AR50_LITE, + .num_vpp_pipes = 0x1, + .ubwc_config = 0x0, + .codecs = scuba_codecs, + .codecs_count = ARRAY_SIZE(scuba_codecs), + .codec_caps = scuba_capabilities, + .codec_caps_count = ARRAY_SIZE(scuba_capabilities), +}; + +static struct msm_vidc_platform_data sm8150_data = { + .codec_data = sm8150_codec_data, + .codec_data_length = ARRAY_SIZE(sm8150_codec_data), + .common_data = sm8150_common_data, + .common_data_length = ARRAY_SIZE(sm8150_common_data), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_IRIS1, + .num_vpp_pipes = 0x2, + .ubwc_config = 0x0, +}; + +static struct msm_vidc_platform_data sdm845_data = { + .codec_data = sdm845_codec_data, + .codec_data_length = ARRAY_SIZE(sdm845_codec_data), + .common_data = sdm845_common_data, + .common_data_length = ARRAY_SIZE(sdm845_common_data), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = NULL, + .efuse_data_length = 0, + .sku_version = 0, + .vpu_ver = VPU_VERSION_AR50, + .num_vpp_pipes = 0x1, + .ubwc_config = 0x0, +}; + +static struct msm_vidc_platform_data sdm670_data = { + .codec_data = sdm670_codec_data, + .codec_data_length = ARRAY_SIZE(sdm670_codec_data), + .common_data = sdm670_common_data_v0, + .common_data_length = ARRAY_SIZE(sdm670_common_data_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .efuse_data = sdm670_efuse_data, + .efuse_data_length = ARRAY_SIZE(sdm670_efuse_data), + .sku_version = 0, + .vpu_ver = VPU_VERSION_AR50, + .num_vpp_pipes = 0x1, + .ubwc_config = 0x0, +}; + +static const struct of_device_id msm_vidc_dt_match[] = { + { + .compatible = "qcom,lito-vidc", + .data = &lito_data, + }, + { + .compatible = "qcom,kona-vidc", + .data = &kona_data, + }, + { + .compatible = "qcom,sm6150-vidc", + .data = &sm6150_data, + }, + { + .compatible = "qcom,sm8150-vidc", + .data = &sm8150_data, + }, + { + .compatible = "qcom,sdm845-vidc", + .data = &sdm845_data, + }, + { + .compatible = "qcom,sdm670-vidc", + .data = &sdm670_data, + }, + { + .compatible = "qcom,bengal-vidc", + .data = &bengal_data, + }, + { + .compatible = "qcom,lagoon-vidc", + .data = &lagoon_data, + }, + { + .compatible = "qcom,scuba-vidc", + .data = &scuba_data, + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match); + +static int msm_vidc_read_efuse( + struct msm_vidc_platform_data *data, struct device *dev) +{ + void __iomem *base; + uint32_t i; + struct msm_vidc_efuse_data *efuse_data = data->efuse_data; + uint32_t efuse_data_count = data->efuse_data_length; + + if (!efuse_data) + return 0; + + for (i = 0; i < efuse_data_count; i++) { + switch ((efuse_data[i]).purpose) { + case SKU_VERSION: + base = devm_ioremap(dev, (efuse_data[i]).start_address, + (efuse_data[i]).size); + if (!base) { + d_vpr_e("failed efuse: start %#x, size %d\n", + (efuse_data[i]).start_address, + (efuse_data[i]).size); + return -EINVAL; + } else { + u32 efuse = 0; + + efuse = readl_relaxed(base); + data->sku_version = + (efuse & (efuse_data[i]).mask) >> + (efuse_data[i]).shift; + d_vpr_h("efuse 0x%x, platform version 0x%x\n", + efuse, data->sku_version); + + devm_iounmap(dev, base); + } + break; + default: + break; + } + } + return 0; +} + +static int msm_vidc_read_rank( + struct msm_vidc_platform_data *data, struct device *dev) +{ + uint32_t num_ranks = 0; + /*default channel is ch0 for bengal*/ + uint32_t channel = 0; + + /*default sku-version*/ + data->sku_version = SKU_VERSION_0; + num_ranks = of_fdt_get_ddrrank(channel); + + if (num_ranks == -ENOENT) { + d_vpr_e("Failed to get ddr rank of device\n"); + return num_ranks; + } else if (num_ranks == 1) + data->sku_version = SKU_VERSION_0; + + d_vpr_h("DDR Rank of device: %u", num_ranks); + + return 0; +} + +void *vidc_get_drv_data(struct device *dev) +{ + struct msm_vidc_platform_data *driver_data = NULL; + const struct of_device_id *match; + uint32_t ddr_type = DDR_TYPE_LPDDR5; + int rc = 0; + + if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) { + d_vpr_e("Using default_data\n"); + driver_data = &default_data; + goto exit; + } + + match = of_match_node(msm_vidc_dt_match, dev->of_node); + + if (match) + driver_data = (struct msm_vidc_platform_data *)match->data; + + if (!driver_data) + goto exit; + + /* Check for sku version */ + if (of_find_property(dev->of_node, "sku-index", NULL)) { + rc = msm_vidc_read_efuse(driver_data, dev); + if (rc) + goto exit; + } + + if (!strcmp(match->compatible, "qcom,sdm670-vidc")) { + if (driver_data->sku_version == SKU_VERSION_1) { + driver_data->common_data = sdm670_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(sdm670_common_data_v1); + } + } else if (!strcmp(match->compatible, "qcom,lito-vidc")) { + if (driver_data->sku_version == SKU_VERSION_1) { + driver_data->common_data = lito_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(lito_common_data_v1); + driver_data->codec_caps = lito_capabilities_v1; + driver_data->codec_caps_count = ARRAY_SIZE(lito_capabilities_v1); + } + } else if (!strcmp(match->compatible, "qcom,kona-vidc")) { + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type == -ENOENT) + d_vpr_e("Failed to get ddr type, use LPDDR5\n"); + + if (driver_data->ubwc_config && + (ddr_type == DDR_TYPE_LPDDR4 || + ddr_type == DDR_TYPE_LPDDR4X)) + driver_data->ubwc_config->highest_bank_bit = 0xf; + + d_vpr_h("DDR Type 0x%x hbb 0x%x\n", + ddr_type, driver_data->ubwc_config ? + driver_data->ubwc_config->highest_bank_bit : -1); + } else if (!strcmp(match->compatible, "qcom,bengal-vidc")) { + rc = msm_vidc_read_rank(driver_data, dev); + if (rc) { + d_vpr_e("Failed to get ddr rank, use Dual Rank DDR\n"); + goto exit; + } + if (driver_data->sku_version == SKU_VERSION_1) { + driver_data->common_data = bengal_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(bengal_common_data_v1); + driver_data->codec_caps = bengal_capabilities_v1; + driver_data->codec_caps_count = + ARRAY_SIZE(bengal_capabilities_v1); + } + } else if (!strcmp(match->compatible, "qcom,lagoon-vidc")) { + if (driver_data->sku_version == SKU_VERSION_1) { + driver_data->common_data = lagoon_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(lagoon_common_data_v1); + driver_data->codec_caps = lagoon_capabilities_v1; + driver_data->codec_caps_count = + ARRAY_SIZE(lagoon_capabilities_v1); + } + } + +exit: + return driver_data; +} diff --git a/techpack/video/msm/vidc/msm_vidc_res_parse.c b/techpack/video/msm/vidc/msm_vidc_res_parse.c new file mode 100644 index 0000000000000000000000000000000000000000..1b9e9942cb44333d8cf28d6b77597b0b6ad6cd8c --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_res_parse.c @@ -0,0 +1,1317 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#include <asm/dma-iommu.h> +#include <linux/dma-iommu.h> +#include <linux/iommu.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/sort.h> +#include "msm_vidc_debug.h" +#include "msm_vidc_resources.h" +#include "msm_vidc_res_parse.h" +#include "soc/qcom/secure_buffer.h" + +enum clock_properties { + CLOCK_PROP_HAS_SCALING = 1 << 0, + CLOCK_PROP_HAS_MEM_RETENTION = 1 << 1, +}; + +static struct memory_limit_table memory_limit_tbl_mbytes[] = { + /* target_memory_size - max_video_cap */ + {12288, 4096}, /* 12 GB - 4 Gb*/ + {8192, 3584}, /* 8 GB - 3.5 Gb*/ + {6144, 2560}, /* 6 GB - 2.5 Gb*/ + {4096, 1536}, /* 4 GB - 1.5 Gb*/ + {2048, 768}, /* 2 GB - 0.75 Gb*/ +}; + +static inline struct device *msm_iommu_get_ctx(const char *ctx_name) +{ + return NULL; +} + +static int msm_vidc_populate_legacy_context_bank( + struct msm_vidc_platform_resources *res); + +static size_t get_u32_array_num_elements(struct device_node *np, + char *name) +{ + int len; + size_t num_elements = 0; + + if (!of_get_property(np, name, &len)) { + d_vpr_e("Failed to read %s from device tree\n", name); + goto fail_read; + } + + num_elements = len / sizeof(u32); + if (num_elements <= 0) { + d_vpr_e("%s not specified in device tree\n", name); + goto fail_read; + } + return num_elements; + +fail_read: + return 0; +} + +static inline void msm_vidc_free_allowed_clocks_table( + struct msm_vidc_platform_resources *res) +{ + res->allowed_clks_tbl = NULL; +} + +static inline void msm_vidc_free_cycles_per_mb_table( + struct msm_vidc_platform_resources *res) +{ + res->clock_freq_tbl.clk_prof_entries = NULL; +} + +static inline void msm_vidc_free_reg_table( + struct msm_vidc_platform_resources *res) +{ + res->reg_set.reg_tbl = NULL; +} + +static inline void msm_vidc_free_qdss_addr_table( + struct msm_vidc_platform_resources *res) +{ + res->qdss_addr_set.addr_tbl = NULL; +} + +static inline void msm_vidc_free_bus_vectors( + struct msm_vidc_platform_resources *res) +{ + kfree(res->bus_set.bus_tbl); + res->bus_set.bus_tbl = NULL; + res->bus_set.count = 0; +} + +static inline void msm_vidc_free_buffer_usage_table( + struct msm_vidc_platform_resources *res) +{ + res->buffer_usage_set.buffer_usage_tbl = NULL; +} + +static inline void msm_vidc_free_regulator_table( + struct msm_vidc_platform_resources *res) +{ + int c = 0; + + for (c = 0; c < res->regulator_set.count; ++c) { + struct regulator_info *rinfo = + &res->regulator_set.regulator_tbl[c]; + + rinfo->name = NULL; + } + + res->regulator_set.regulator_tbl = NULL; + res->regulator_set.count = 0; +} + +static inline void msm_vidc_free_clock_table( + struct msm_vidc_platform_resources *res) +{ + res->clock_set.clock_tbl = NULL; + res->clock_set.count = 0; +} + +static inline void msm_vidc_free_cx_ipeak_context( + struct msm_vidc_platform_resources *res) +{ + cx_ipeak_unregister(res->cx_ipeak_context); + res->cx_ipeak_context = NULL; +} + +void msm_vidc_free_platform_resources( + struct msm_vidc_platform_resources *res) +{ + msm_vidc_free_clock_table(res); + msm_vidc_free_regulator_table(res); + msm_vidc_free_allowed_clocks_table(res); + msm_vidc_free_reg_table(res); + msm_vidc_free_qdss_addr_table(res); + msm_vidc_free_bus_vectors(res); + msm_vidc_free_buffer_usage_table(res); + msm_vidc_free_cx_ipeak_context(res); +} + +static int msm_vidc_load_reg_table(struct msm_vidc_platform_resources *res) +{ + struct reg_set *reg_set; + struct platform_device *pdev = res->pdev; + int i; + int rc = 0; + + if (!of_find_property(pdev->dev.of_node, "qcom,reg-presets", NULL)) { + /* + * qcom,reg-presets is an optional property. It likely won't be + * present if we don't have any register settings to program + */ + d_vpr_h("reg-presets not found\n"); + return 0; + } + + reg_set = &res->reg_set; + reg_set->count = get_u32_array_num_elements(pdev->dev.of_node, + "qcom,reg-presets"); + reg_set->count /= sizeof(*reg_set->reg_tbl) / sizeof(u32); + + if (!reg_set->count) { + d_vpr_h("no elements in reg set\n"); + return rc; + } + + reg_set->reg_tbl = devm_kzalloc(&pdev->dev, reg_set->count * + sizeof(*(reg_set->reg_tbl)), GFP_KERNEL); + if (!reg_set->reg_tbl) { + d_vpr_e("%s: Failed to alloc register table\n", __func__); + return -ENOMEM; + } + + if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets", + (u32 *)reg_set->reg_tbl, reg_set->count * 2)) { + d_vpr_e("Failed to read register table\n"); + msm_vidc_free_reg_table(res); + return -EINVAL; + } + for (i = 0; i < reg_set->count; i++) { + d_vpr_h("reg = %x, value = %x\n", + reg_set->reg_tbl[i].reg, reg_set->reg_tbl[i].value + ); + } + return rc; +} +static int msm_vidc_load_qdss_table(struct msm_vidc_platform_resources *res) +{ + struct addr_set *qdss_addr_set; + struct platform_device *pdev = res->pdev; + int i; + int rc = 0; + + if (!of_find_property(pdev->dev.of_node, "qcom,qdss-presets", NULL)) { + /* + * qcom,qdss-presets is an optional property. It likely won't be + * present if we don't have any register settings to program + */ + d_vpr_h("qdss-presets not found\n"); + return rc; + } + + qdss_addr_set = &res->qdss_addr_set; + qdss_addr_set->count = get_u32_array_num_elements(pdev->dev.of_node, + "qcom,qdss-presets"); + qdss_addr_set->count /= sizeof(*qdss_addr_set->addr_tbl) / sizeof(u32); + + if (!qdss_addr_set->count) { + d_vpr_h("no elements in qdss reg set\n"); + return rc; + } + + qdss_addr_set->addr_tbl = devm_kzalloc(&pdev->dev, + qdss_addr_set->count * sizeof(*qdss_addr_set->addr_tbl), + GFP_KERNEL); + if (!qdss_addr_set->addr_tbl) { + d_vpr_e("%s: Failed to alloc register table\n", __func__); + rc = -ENOMEM; + goto err_qdss_addr_tbl; + } + + rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,qdss-presets", + (u32 *)qdss_addr_set->addr_tbl, qdss_addr_set->count * 2); + if (rc) { + d_vpr_e("Failed to read qdss address table\n"); + msm_vidc_free_qdss_addr_table(res); + rc = -EINVAL; + goto err_qdss_addr_tbl; + } + + for (i = 0; i < qdss_addr_set->count; i++) { + d_vpr_h("qdss addr = %x, value = %x\n", + qdss_addr_set->addr_tbl[i].start, + qdss_addr_set->addr_tbl[i].size); + } +err_qdss_addr_tbl: + return rc; +} + +static int msm_vidc_load_subcache_info(struct msm_vidc_platform_resources *res) +{ + int rc = 0, num_subcaches = 0, c; + struct platform_device *pdev = res->pdev; + struct subcache_set *subcaches = &res->subcache_set; + + num_subcaches = of_property_count_strings(pdev->dev.of_node, + "cache-slice-names"); + if (num_subcaches <= 0) { + d_vpr_h("No subcaches found\n"); + goto err_load_subcache_table_fail; + } + + subcaches->subcache_tbl = devm_kzalloc(&pdev->dev, + sizeof(*subcaches->subcache_tbl) * num_subcaches, GFP_KERNEL); + if (!subcaches->subcache_tbl) { + d_vpr_e("Failed to allocate memory for subcache tbl\n"); + rc = -ENOMEM; + goto err_load_subcache_table_fail; + } + + subcaches->count = num_subcaches; + d_vpr_h("Found %d subcaches\n", num_subcaches); + + for (c = 0; c < num_subcaches; ++c) { + struct subcache_info *vsc = &res->subcache_set.subcache_tbl[c]; + + of_property_read_string_index(pdev->dev.of_node, + "cache-slice-names", c, &vsc->name); + } + + res->sys_cache_present = true; + + return 0; + +err_load_subcache_table_fail: + res->sys_cache_present = false; + subcaches->count = 0; + subcaches->subcache_tbl = NULL; + + return rc; +} + +/** + * msm_vidc_load_u32_table() - load dtsi table entries + * @pdev: A pointer to the platform device. + * @of_node: A pointer to the device node. + * @table_name: A pointer to the dtsi table entry name. + * @struct_size: The size of the structure which is nothing but + * a single entry in the dtsi table. + * @table: A pointer to the table pointer which needs to be + * filled by the dtsi table entries. + * @num_elements: Number of elements pointer which needs to be filled + * with the number of elements in the table. + * + * This is a generic implementation to load single or multiple array + * table from dtsi. The array elements should be of size equal to u32. + * + * Return: Return '0' for success else appropriate error value. + */ +int msm_vidc_load_u32_table(struct platform_device *pdev, + struct device_node *of_node, char *table_name, int struct_size, + u32 **table, u32 *num_elements) +{ + int rc = 0, num_elemts = 0; + u32 *ptbl = NULL; + + if (!of_find_property(of_node, table_name, NULL)) { + d_vpr_h("%s not found\n", table_name); + return 0; + } + + num_elemts = get_u32_array_num_elements(of_node, table_name); + if (!num_elemts) { + d_vpr_e("no elements in %s\n", table_name); + return 0; + } + num_elemts /= struct_size / sizeof(u32); + + ptbl = devm_kzalloc(&pdev->dev, num_elemts * struct_size, GFP_KERNEL); + if (!ptbl) { + d_vpr_e("Failed to alloc table %s\n", table_name); + return -ENOMEM; + } + + if (of_property_read_u32_array(of_node, table_name, ptbl, + num_elemts * struct_size / sizeof(u32))) { + d_vpr_e("Failed to read %s\n", table_name); + return -EINVAL; + } + + *table = ptbl; + if (num_elements) + *num_elements = num_elemts; + + return rc; +} +EXPORT_SYMBOL(msm_vidc_load_u32_table); + +/* A comparator to compare loads (needed later on) */ +static int cmp(const void *a, const void *b) +{ + /* want to sort in reverse so flip the comparison */ + return ((struct allowed_clock_rates_table *)b)->clock_rate - + ((struct allowed_clock_rates_table *)a)->clock_rate; +} + +static int msm_vidc_load_allowed_clocks_table( + struct msm_vidc_platform_resources *res) +{ + int rc = 0; + struct platform_device *pdev = res->pdev; + + if (!of_find_property(pdev->dev.of_node, + "qcom,allowed-clock-rates", NULL)) { + d_vpr_h("allowed-clock-rates not found\n"); + return 0; + } + + rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node, + "qcom,allowed-clock-rates", + sizeof(*res->allowed_clks_tbl), + (u32 **)&res->allowed_clks_tbl, + &res->allowed_clks_tbl_size); + if (rc) { + d_vpr_e("%s: failed to read allowed clocks table\n", __func__); + return rc; + } + + sort(res->allowed_clks_tbl, res->allowed_clks_tbl_size, + sizeof(*res->allowed_clks_tbl), cmp, NULL); + + return 0; +} + +static int msm_vidc_populate_mem_cdsp(struct device *dev, + struct msm_vidc_platform_resources *res) +{ + res->mem_cdsp.dev = dev; + + return 0; +} + +static int msm_vidc_populate_bus(struct device *dev, + struct msm_vidc_platform_resources *res) +{ + struct bus_set *buses = &res->bus_set; + const char *temp_name = NULL; + struct bus_info *bus = NULL, *temp_table; + u32 range[2]; + int rc = 0; + + temp_table = krealloc(buses->bus_tbl, sizeof(*temp_table) * + (buses->count + 1), GFP_KERNEL); + if (!temp_table) { + d_vpr_e("%s: Failed to allocate memory", __func__); + rc = -ENOMEM; + goto err_bus; + } + + buses->bus_tbl = temp_table; + bus = &buses->bus_tbl[buses->count]; + + memset(bus, 0x0, sizeof(struct bus_info)); + + rc = of_property_read_string(dev->of_node, "label", &temp_name); + if (rc) { + d_vpr_e("'label' not found in node\n"); + goto err_bus; + } + /* need a non-const version of name, hence copying it over */ + bus->name = devm_kstrdup(dev, temp_name, GFP_KERNEL); + if (!bus->name) { + rc = -ENOMEM; + goto err_bus; + } + + rc = of_property_read_u32(dev->of_node, "qcom,bus-master", + &bus->master); + if (rc) { + d_vpr_e("'bus-master' not found in node\n"); + goto err_bus; + } + + rc = of_property_read_u32(dev->of_node, "qcom,bus-slave", &bus->slave); + if (rc) { + d_vpr_e("'bus-slave' not found in node\n"); + goto err_bus; + } + + rc = of_property_read_string(dev->of_node, "qcom,mode", + &bus->mode); + + if (!rc && !strcmp(bus->mode, "performance")) + bus->is_prfm_mode = true; + + rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps", + range, ARRAY_SIZE(range)); + if (rc) { + rc = 0; + d_vpr_h("'bus-range' not found defaulting to <0 INT_MAX>\n"); + range[0] = 0; + range[1] = INT_MAX; + } + + bus->range[0] = range[0]; /* min */ + bus->range[1] = range[1]; /* max */ + + buses->count++; + bus->dev = dev; + d_vpr_h("Found bus %s [%d->%d] with mode %s\n", + bus->name, bus->master, bus->slave, bus->mode); +err_bus: + return rc; +} + +static int msm_vidc_load_buffer_usage_table( + struct msm_vidc_platform_resources *res) +{ + int rc = 0; + struct platform_device *pdev = res->pdev; + struct buffer_usage_set *buffer_usage_set = &res->buffer_usage_set; + + if (!of_find_property(pdev->dev.of_node, + "qcom,buffer-type-tz-usage-table", NULL)) { + /* + * qcom,buffer-type-tz-usage-table is an optional property. It + * likely won't be present if the core doesn't support content + * protection + */ + d_vpr_h("buffer-type-tz-usage-table not found\n"); + return 0; + } + + buffer_usage_set->count = get_u32_array_num_elements( + pdev->dev.of_node, "qcom,buffer-type-tz-usage-table"); + buffer_usage_set->count /= + sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32); + if (!buffer_usage_set->count) { + d_vpr_h("no elements in buffer usage set\n"); + return 0; + } + + buffer_usage_set->buffer_usage_tbl = devm_kzalloc(&pdev->dev, + buffer_usage_set->count * + sizeof(*buffer_usage_set->buffer_usage_tbl), + GFP_KERNEL); + if (!buffer_usage_set->buffer_usage_tbl) { + d_vpr_e("%s: Failed to alloc buffer usage table\n", + __func__); + rc = -ENOMEM; + goto err_load_buf_usage; + } + + rc = of_property_read_u32_array(pdev->dev.of_node, + "qcom,buffer-type-tz-usage-table", + (u32 *)buffer_usage_set->buffer_usage_tbl, + buffer_usage_set->count * + sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32)); + if (rc) { + d_vpr_e("Failed to read buffer usage table\n"); + goto err_load_buf_usage; + } + + return 0; +err_load_buf_usage: + msm_vidc_free_buffer_usage_table(res); + return rc; +} + +static int msm_vidc_load_regulator_table( + struct msm_vidc_platform_resources *res) +{ + int rc = 0; + struct platform_device *pdev = res->pdev; + struct regulator_set *regulators = &res->regulator_set; + struct device_node *domains_parent_node = NULL; + struct property *domains_property = NULL; + int reg_count = 0; + + regulators->count = 0; + regulators->regulator_tbl = NULL; + + domains_parent_node = pdev->dev.of_node; + for_each_property_of_node(domains_parent_node, domains_property) { + const char *search_string = "-supply"; + char *supply; + bool matched = false; + + /* check if current property is possibly a regulator */ + supply = strnstr(domains_property->name, search_string, + strlen(domains_property->name) + 1); + matched = supply && (*(supply + strlen(search_string)) == '\0'); + if (!matched) + continue; + + reg_count++; + } + + regulators->regulator_tbl = devm_kzalloc(&pdev->dev, + sizeof(*regulators->regulator_tbl) * + reg_count, GFP_KERNEL); + + if (!regulators->regulator_tbl) { + rc = -ENOMEM; + d_vpr_e("Failed to alloc memory for regulator table\n"); + goto err_reg_tbl_alloc; + } + + for_each_property_of_node(domains_parent_node, domains_property) { + const char *search_string = "-supply"; + char *supply; + bool matched = false; + struct device_node *regulator_node = NULL; + struct regulator_info *rinfo = NULL; + + /* check if current property is possibly a regulator */ + supply = strnstr(domains_property->name, search_string, + strlen(domains_property->name) + 1); + matched = supply && (supply[strlen(search_string)] == '\0'); + if (!matched) + continue; + + /* make sure prop isn't being misused */ + regulator_node = of_parse_phandle(domains_parent_node, + domains_property->name, 0); + if (IS_ERR(regulator_node)) { + d_vpr_e("%s is not a phandle\n", + domains_property->name); + continue; + } + regulators->count++; + + /* populate regulator info */ + rinfo = ®ulators->regulator_tbl[regulators->count - 1]; + rinfo->name = devm_kzalloc(&pdev->dev, + (supply - domains_property->name) + 1, GFP_KERNEL); + if (!rinfo->name) { + rc = -ENOMEM; + d_vpr_e("Failed to alloc memory for regulator name\n"); + goto err_reg_name_alloc; + } + strlcpy(rinfo->name, domains_property->name, + (supply - domains_property->name) + 1); + + rinfo->has_hw_power_collapse = of_property_read_bool( + regulator_node, "qcom,support-hw-trigger"); + + d_vpr_h("Found regulator %s: h/w collapse = %s\n", + rinfo->name, + rinfo->has_hw_power_collapse ? "yes" : "no"); + } + + if (!regulators->count) + d_vpr_h("No regulators found"); + + return 0; + +err_reg_name_alloc: +err_reg_tbl_alloc: + msm_vidc_free_regulator_table(res); + return rc; +} + +static int msm_vidc_load_clock_table( + struct msm_vidc_platform_resources *res) +{ + int rc = 0, num_clocks = 0, c = 0; + struct platform_device *pdev = res->pdev; + int *clock_props = NULL; + struct clock_set *clocks = &res->clock_set; + + num_clocks = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if (num_clocks <= 0) { + d_vpr_h("No clocks found\n"); + clocks->count = 0; + rc = 0; + goto err_load_clk_table_fail; + } + + clock_props = devm_kzalloc(&pdev->dev, num_clocks * + sizeof(*clock_props), GFP_KERNEL); + if (!clock_props) { + d_vpr_e("No memory to read clock properties\n"); + rc = -ENOMEM; + goto err_load_clk_table_fail; + } + + rc = of_property_read_u32_array(pdev->dev.of_node, + "qcom,clock-configs", clock_props, + num_clocks); + if (rc) { + d_vpr_e("Failed to read clock properties: %d\n", rc); + goto err_load_clk_prop_fail; + } + + clocks->clock_tbl = devm_kzalloc(&pdev->dev, sizeof(*clocks->clock_tbl) + * num_clocks, GFP_KERNEL); + if (!clocks->clock_tbl) { + d_vpr_e("Failed to allocate memory for clock tbl\n"); + rc = -ENOMEM; + goto err_load_clk_prop_fail; + } + + clocks->count = num_clocks; + d_vpr_h("Found %d clocks\n", num_clocks); + + for (c = 0; c < num_clocks; ++c) { + struct clock_info *vc = &res->clock_set.clock_tbl[c]; + + of_property_read_string_index(pdev->dev.of_node, + "clock-names", c, &vc->name); + + if (clock_props[c] & CLOCK_PROP_HAS_SCALING) { + vc->has_scaling = true; + } else { + vc->has_scaling = false; + } + + if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION) + vc->has_mem_retention = true; + else + vc->has_mem_retention = false; + + d_vpr_h("Found clock %s: scale-able = %s\n", vc->name, + vc->has_scaling ? "yes" : "no"); + } + + + return 0; + +err_load_clk_prop_fail: +err_load_clk_table_fail: + return rc; +} + +static int msm_vidc_load_reset_table( + struct msm_vidc_platform_resources *res) +{ + struct platform_device *pdev = res->pdev; + struct reset_set *rst = &res->reset_set; + int num_clocks = 0, c = 0; + + num_clocks = of_property_count_strings(pdev->dev.of_node, + "reset-names"); + if (num_clocks <= 0) { + d_vpr_h("No reset clocks found\n"); + rst->count = 0; + return 0; + } + + rst->reset_tbl = devm_kcalloc(&pdev->dev, num_clocks, + sizeof(*rst->reset_tbl), GFP_KERNEL); + if (!rst->reset_tbl) + return -ENOMEM; + + rst->count = num_clocks; + d_vpr_h("Found %d reset clocks\n", num_clocks); + + for (c = 0; c < num_clocks; ++c) { + struct reset_info *rc = &res->reset_set.reset_tbl[c]; + + of_property_read_string_index(pdev->dev.of_node, + "reset-names", c, &rc->name); + } + + return 0; +} + +static int msm_decide_dt_node( + struct msm_vidc_platform_resources *res) +{ + struct platform_device *pdev = res->pdev; + int rc = 0; + u32 sku_index = 0; + + rc = of_property_read_u32(pdev->dev.of_node, "sku-index", + &sku_index); + if (rc) { + d_vpr_h("'sku_index' not found in node\n"); + return 0; + } + + if (sku_index != res->sku_version) { + d_vpr_h("Failed to parse dt: sku_index %d sku_version %d\n", + sku_index, res->sku_version); + return -EINVAL; + } + + return 0; +} + +static int find_key_value(struct msm_vidc_platform_data *platform_data, + const char *key) +{ + int i = 0; + struct msm_vidc_common_data *common_data = platform_data->common_data; + int size = platform_data->common_data_length; + + for (i = 0; i < size; i++) { + if (!strcmp(common_data[i].key, key)) + return common_data[i].value; + } + return 0; +} + +int read_platform_resources_from_drv_data( + struct msm_vidc_core *core) +{ + struct msm_vidc_platform_data *platform_data; + struct msm_vidc_platform_resources *res; + int rc = 0; + + if (!core || !core->platform_data) { + d_vpr_e("%s: Invalid data\n", __func__); + return -ENOENT; + } + platform_data = core->platform_data; + res = &core->resources; + + res->codecs = platform_data->codecs; + res->codecs_count = platform_data->codecs_count; + res->codec_caps = platform_data->codec_caps; + res->codec_caps_count = platform_data->codec_caps_count; + res->codec_data_count = platform_data->codec_data_length; + res->codec_data = platform_data->codec_data; + + res->sku_version = platform_data->sku_version; + res->mem_limit_tbl = memory_limit_tbl_mbytes; + res->memory_limit_table_size = + ARRAY_SIZE(memory_limit_tbl_mbytes); + + res->fw_name = "venus"; + + d_vpr_h("Firmware filename: %s\n", res->fw_name); + + res->max_load = find_key_value(platform_data, + "qcom,max-hw-load"); + + res->max_image_load = find_key_value(platform_data, + "qcom,max-image-load"); + + res->max_mbpf = find_key_value(platform_data, + "qcom,max-mbpf"); + + res->max_hq_mbs_per_frame = find_key_value(platform_data, + "qcom,max-hq-mbs-per-frame"); + + res->max_hq_mbs_per_sec = find_key_value(platform_data, + "qcom,max-hq-mbs-per-sec"); + + res->max_bframe_mbs_per_frame = find_key_value(platform_data, + "qcom,max-b-frame-mbs-per-frame"); + + res->max_bframe_mbs_per_sec = find_key_value(platform_data, + "qcom,max-b-frame-mbs-per-sec"); + + res->sw_power_collapsible = find_key_value(platform_data, + "qcom,sw-power-collapse"); + + res->never_unload_fw = find_key_value(platform_data, + "qcom,never-unload-fw"); + + res->debug_timeout = find_key_value(platform_data, + "qcom,debug-timeout"); + + res->pm_qos_latency_us = find_key_value(platform_data, + "qcom,pm-qos-latency-us"); + + res->max_secure_inst_count = find_key_value(platform_data, + "qcom,max-secure-instances"); + + res->slave_side_cp = find_key_value(platform_data, + "qcom,slave-side-cp"); + res->thermal_mitigable = find_key_value(platform_data, + "qcom,enable-thermal-mitigation"); + res->msm_vidc_pwr_collapse_delay = find_key_value(platform_data, + "qcom,power-collapse-delay"); + res->msm_vidc_firmware_unload_delay = find_key_value(platform_data, + "qcom,fw-unload-delay"); + res->msm_vidc_hw_rsp_timeout = find_key_value(platform_data, + "qcom,hw-resp-timeout"); + res->cvp_internal = find_key_value(platform_data, + "qcom,cvp-internal"); + res->cvp_external = find_key_value(platform_data, + "qcom,cvp-external"); + res->non_fatal_pagefaults = find_key_value(platform_data, + "qcom,domain-attr-non-fatal-faults"); + res->cache_pagetables = find_key_value(platform_data, + "qcom,domain-attr-cache-pagetables"); + res->decode_batching = find_key_value(platform_data, + "qcom,decode-batching"); + res->batch_timeout = find_key_value(platform_data, + "qcom,batch-timeout"); + res->dcvs = find_key_value(platform_data, + "qcom,dcvs"); + res->fw_cycles = find_key_value(platform_data, + "qcom,fw-cycles"); + res->fw_vpp_cycles = find_key_value(platform_data, + "qcom,fw-vpp-cycles"); + res->avsync_window_size = find_key_value(platform_data, + "qcom,avsync-window-size"); + + res->csc_coeff_data = &platform_data->csc_data; + + res->vpu_ver = platform_data->vpu_ver; + res->ubwc_config = platform_data->ubwc_config; + + return rc; + +} + +static int msm_vidc_populate_cx_ipeak_context( + struct msm_vidc_platform_resources *res) +{ + struct platform_device *pdev = res->pdev; + int rc = 0; + + if (of_find_property(pdev->dev.of_node, + "qcom,cx-ipeak-data", NULL)) + res->cx_ipeak_context = cx_ipeak_register( + pdev->dev.of_node, "qcom,cx-ipeak-data"); + else + return rc; + + if (IS_ERR(res->cx_ipeak_context)) { + rc = PTR_ERR(res->cx_ipeak_context); + if (rc == -EPROBE_DEFER) + d_vpr_h("cx-ipeak register failed. Deferring probe!"); + else + d_vpr_e("cx-ipeak register failed. rc: %d", rc); + + res->cx_ipeak_context = NULL; + return rc; + } + + if (res->cx_ipeak_context) + d_vpr_h("cx-ipeak register successful"); + else + d_vpr_h("cx-ipeak register not implemented"); + + of_property_read_u32(pdev->dev.of_node, + "qcom,clock-freq-threshold", + &res->clk_freq_threshold); + d_vpr_h("cx ipeak threshold frequency = %u\n", + res->clk_freq_threshold); + + return rc; +} + +int read_platform_resources_from_dt( + struct msm_vidc_platform_resources *res) +{ + struct platform_device *pdev = res->pdev; + struct resource *kres = NULL; + int rc = 0; + uint32_t firmware_base = 0; + + if (!pdev->dev.of_node) { + d_vpr_e("DT node not found\n"); + return -ENOENT; + } + + rc = msm_decide_dt_node(res); + if (rc) + return rc; + + INIT_LIST_HEAD(&res->context_banks); + + res->firmware_base = (phys_addr_t)firmware_base; + + kres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res->register_base = kres ? kres->start : -1; + res->register_size = kres ? (kres->end + 1 - kres->start) : -1; + + kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + res->irq = kres ? kres->start : -1; + + rc = msm_vidc_load_subcache_info(res); + if (rc) + d_vpr_e("Failed to load subcache info: %d\n", rc); + + rc = msm_vidc_load_qdss_table(res); + if (rc) + d_vpr_e("Failed to load qdss reg table: %d\n", rc); + + rc = msm_vidc_load_reg_table(res); + if (rc) { + d_vpr_e("Failed to load reg table: %d\n", rc); + goto err_load_reg_table; + } + + rc = msm_vidc_load_buffer_usage_table(res); + if (rc) { + d_vpr_e("Failed to load buffer usage table: %d\n", rc); + goto err_load_buffer_usage_table; + } + + rc = msm_vidc_load_regulator_table(res); + if (rc) { + d_vpr_e("Failed to load list of regulators %d\n", rc); + goto err_load_regulator_table; + } + + rc = msm_vidc_load_clock_table(res); + if (rc) { + d_vpr_e("Failed to load clock table: %d\n", rc); + goto err_load_clock_table; + } + + rc = msm_vidc_load_allowed_clocks_table(res); + if (rc) { + d_vpr_e("Failed to load allowed clocks table: %d\n", rc); + goto err_load_allowed_clocks_table; + } + + rc = msm_vidc_load_reset_table(res); + if (rc) { + d_vpr_e("Failed to load reset table: %d\n", rc); + goto err_load_reset_table; + } + + rc = msm_vidc_populate_legacy_context_bank(res); + if (rc) { + d_vpr_e("Failed to setup context banks %d\n", rc); + goto err_setup_legacy_cb; + } + + rc = msm_vidc_populate_cx_ipeak_context(res); + if (rc) { + d_vpr_e("Failed to setup cx-ipeak %d\n", rc); + goto err_register_cx_ipeak; + } + +return rc; + +err_register_cx_ipeak: + msm_vidc_free_cx_ipeak_context(res); +err_setup_legacy_cb: +err_load_reset_table: + msm_vidc_free_allowed_clocks_table(res); +err_load_allowed_clocks_table: + msm_vidc_free_clock_table(res); +err_load_clock_table: + msm_vidc_free_regulator_table(res); +err_load_regulator_table: + msm_vidc_free_buffer_usage_table(res); +err_load_buffer_usage_table: + msm_vidc_free_reg_table(res); +err_load_reg_table: + return rc; +} + +static int msm_vidc_setup_context_bank(struct msm_vidc_platform_resources *res, + struct context_bank_info *cb, struct device *dev) +{ + int rc = 0; + struct bus_type *bus; + + if (!dev || !cb || !res) { + d_vpr_e("%s: Invalid Input params\n", __func__); + return -EINVAL; + } + cb->dev = dev; + + bus = cb->dev->bus; + if (IS_ERR_OR_NULL(bus)) { + d_vpr_e("%s: failed to get bus type\n", __func__); + rc = PTR_ERR(bus) ? PTR_ERR(bus) : -ENODEV; + goto remove_cb; + } + + cb->domain = iommu_get_domain_for_dev(cb->dev); + + /* + * When memory is fragmented, below configuration increases the + * possibility to get a mapping for buffer in the configured CB. + */ + if (!strcmp(cb->name, "venus_ns")) + iommu_dma_enable_best_fit_algo(cb->dev); + + /* + * configure device segment size and segment boundary to ensure + * iommu mapping returns one mapping (which is required for partial + * cache operations) + */ + if (!dev->dma_parms) + dev->dma_parms = + devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64)); + + d_vpr_h("Attached %s and created mapping\n", dev_name(dev)); + d_vpr_h( + "Context bank: %s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, domain: %pK", + cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start, + cb->addr_range.size, cb->dev, cb->domain); + +remove_cb: + return rc; +} + +int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *token) +{ + struct msm_vidc_core *core = token; + + if (!domain || !core) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, domain, core); + return -EINVAL; + } + + if (core->smmu_fault_handled) { + if (core->resources.non_fatal_pagefaults) { + dprintk_ratelimit(VIDC_ERR, + "%s: non-fatal pagefault address: %lx\n", + __func__, iova); + return 0; + } + } + + d_vpr_e("%s: faulting address: %lx\n", __func__, iova); + + core->smmu_fault_handled = true; + msm_comm_print_insts_info(core); + /* + * Return -EINVAL to elicit the default behaviour of smmu driver. + * If we return -EINVAL, then smmu driver assumes page fault handler + * is not installed and prints a list of useful debug information like + * FAR, SID etc. This information is not printed if we return 0. + */ + return -EINVAL; +} + +static int msm_vidc_populate_context_bank(struct device *dev, + struct msm_vidc_core *core) +{ + int rc = 0; + struct context_bank_info *cb = NULL; + struct device_node *np = NULL; + + if (!dev || !core) { + d_vpr_e("%s: invalid inputs\n", __func__); + return -EINVAL; + } + + np = dev->of_node; + cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); + if (!cb) { + d_vpr_e("%s: Failed to allocate cb\n", __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&cb->list); + + mutex_lock(&core->resources.cb_lock); + list_add_tail(&cb->list, &core->resources.context_banks); + mutex_unlock(&core->resources.cb_lock); + + rc = of_property_read_string(np, "label", &cb->name); + if (rc) { + d_vpr_h("Failed to read cb label from device tree\n"); + rc = 0; + } + + d_vpr_h("%s: context bank has name %s\n", __func__, cb->name); + rc = of_property_read_u32_array(np, "virtual-addr-pool", + (u32 *)&cb->addr_range, 2); + if (rc) { + d_vpr_e("Could not read addr pool: context bank: %s %d\n", + cb->name, rc); + goto err_setup_cb; + } + + cb->is_secure = of_property_read_bool(np, "qcom,secure-context-bank"); + d_vpr_h("context bank %s: secure = %d\n", + cb->name, cb->is_secure); + + /* setup buffer type for each sub device*/ + rc = of_property_read_u32(np, "buffer-types", &cb->buffer_type); + if (rc) { + d_vpr_e("failed to load buffer_type info %d\n", rc); + rc = -ENOENT; + goto err_setup_cb; + } + d_vpr_h("context bank %s address start %x size %x buffer_type %x\n", + cb->name, cb->addr_range.start, + cb->addr_range.size, cb->buffer_type); + + rc = msm_vidc_setup_context_bank(&core->resources, cb, dev); + if (rc) { + d_vpr_e("Cannot setup context bank %d\n", rc); + goto err_setup_cb; + } + + iommu_set_fault_handler(cb->domain, + msm_vidc_smmu_fault_handler, (void *)core); + + return 0; + +err_setup_cb: + list_del(&cb->list); + return rc; +} + +static int msm_vidc_populate_legacy_context_bank( + struct msm_vidc_platform_resources *res) +{ + int rc = 0; + struct platform_device *pdev = NULL; + struct device_node *domains_parent_node = NULL; + struct device_node *domains_child_node = NULL; + struct device_node *ctx_node = NULL; + struct context_bank_info *cb; + + if (!res || !res->pdev) { + d_vpr_e("%s: invalid inputs\n", __func__); + return -EINVAL; + } + pdev = res->pdev; + + domains_parent_node = of_find_node_by_name(pdev->dev.of_node, + "qcom,vidc-iommu-domains"); + if (!domains_parent_node) { + d_vpr_h("%s: legacy iommu domains not present\n", __func__); + return 0; + } + + /* set up each context bank for legacy DT bindings*/ + for_each_child_of_node(domains_parent_node, + domains_child_node) { + cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL); + if (!cb) { + d_vpr_e("%s: Failed to allocate cb\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&cb->list); + + mutex_lock(&res->cb_lock); + list_add_tail(&cb->list, &res->context_banks); + mutex_unlock(&res->cb_lock); + + ctx_node = of_parse_phandle(domains_child_node, + "qcom,vidc-domain-phandle", 0); + if (!ctx_node) { + d_vpr_e("%s: Unable to parse pHandle\n", __func__); + rc = -EBADHANDLE; + goto err_setup_cb; + } + + rc = of_property_read_string(ctx_node, "label", &(cb->name)); + if (rc) { + d_vpr_e("%s: Could not find label\n", __func__); + goto err_setup_cb; + } + + rc = of_property_read_u32_array(ctx_node, + "qcom,virtual-addr-pool", (u32 *)&cb->addr_range, 2); + if (rc) { + d_vpr_e("%s: Could not read addr pool: %s (%d)\n", + __func__, cb->name, rc); + goto err_setup_cb; + } + + cb->is_secure = + of_property_read_bool(ctx_node, "qcom,secure-domain"); + + rc = of_property_read_u32(domains_child_node, + "qcom,vidc-buffer-types", &cb->buffer_type); + if (rc) { + d_vpr_e("%s: Could not read buffer type (%d)\n", + __func__, rc); + goto err_setup_cb; + } + + cb->dev = msm_iommu_get_ctx(cb->name); + if (IS_ERR_OR_NULL(cb->dev)) { + d_vpr_e("%s: could not get device for cb %s\n", + __func__, cb->name); + rc = -ENOENT; + goto err_setup_cb; + } + + rc = msm_vidc_setup_context_bank(res, cb, cb->dev); + if (rc) { + d_vpr_e("Cannot setup context bank %d\n", rc); + goto err_setup_cb; + } + d_vpr_h( + "context bank %s secure %d addr start = %#x size = %#x buffer_type = %#x\n", + cb->name, cb->is_secure, cb->addr_range.start, + cb->addr_range.size, cb->buffer_type); + } + return rc; + +err_setup_cb: + list_del(&cb->list); + return rc; +} + +int read_context_bank_resources_from_dt(struct platform_device *pdev) +{ + struct msm_vidc_core *core; + int rc = 0; + + if (!pdev) { + d_vpr_e("Invalid platform device\n"); + return -EINVAL; + } else if (!pdev->dev.parent) { + d_vpr_e("Failed to find a parent for %s\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + core = dev_get_drvdata(pdev->dev.parent); + if (!core) { + d_vpr_e("Failed to find cookie in parent device %s", + dev_name(pdev->dev.parent)); + return -EINVAL; + } + + rc = msm_vidc_populate_context_bank(&pdev->dev, core); + if (rc) + d_vpr_e("Failed to probe context bank\n"); + else + d_vpr_h("Successfully probed context bank\n"); + + return rc; +} + +int read_bus_resources_from_dt(struct platform_device *pdev) +{ + struct msm_vidc_core *core; + + if (!pdev) { + d_vpr_e("Invalid platform device\n"); + return -EINVAL; + } else if (!pdev->dev.parent) { + d_vpr_e("Failed to find a parent for %s\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + core = dev_get_drvdata(pdev->dev.parent); + if (!core) { + d_vpr_e("Failed to find cookie in parent device %s", + dev_name(pdev->dev.parent)); + return -EINVAL; + } + + return msm_vidc_populate_bus(&pdev->dev, &core->resources); +} + +int read_mem_cdsp_resources_from_dt(struct platform_device *pdev) +{ + struct msm_vidc_core *core; + + if (!pdev) { + d_vpr_e("%s: invalid platform device\n", __func__); + return -EINVAL; + } else if (!pdev->dev.parent) { + d_vpr_e("Failed to find a parent for %s\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + core = dev_get_drvdata(pdev->dev.parent); + if (!core) { + d_vpr_e("Failed to find cookie in parent device %s", + dev_name(pdev->dev.parent)); + return -EINVAL; + } + + return msm_vidc_populate_mem_cdsp(&pdev->dev, &core->resources); +} diff --git a/techpack/video/msm/vidc/msm_vidc_res_parse.h b/techpack/video/msm/vidc/msm_vidc_res_parse.h new file mode 100644 index 0000000000000000000000000000000000000000..5254d2900c0736b6a6b016f4726f97dd2e7708da --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_res_parse.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + */ + +#ifndef DT_PARSE +#define DT_PARSE +#include <linux/of.h> +#include "msm_vidc_resources.h" +#include "msm_vidc_common.h" +void msm_vidc_free_platform_resources( + struct msm_vidc_platform_resources *res); + +int read_hfi_type(struct platform_device *pdev); + +int read_platform_resources_from_drv_data( + struct msm_vidc_core *core); +int read_platform_resources_from_dt( + struct msm_vidc_platform_resources *res); + +int read_context_bank_resources_from_dt(struct platform_device *pdev); + +int read_bus_resources_from_dt(struct platform_device *pdev); +int read_mem_cdsp_resources_from_dt(struct platform_device *pdev); + +int msm_vidc_load_u32_table(struct platform_device *pdev, + struct device_node *of_node, char *table_name, int struct_size, + u32 **table, u32 *num_elements); + +#endif diff --git a/techpack/video/msm/vidc/msm_vidc_resources.h b/techpack/video/msm/vidc/msm_vidc_resources.h new file mode 100644 index 0000000000000000000000000000000000000000..6e1f46f095bc0d3c421779ca3abdd459b71a5e1c --- /dev/null +++ b/techpack/video/msm/vidc/msm_vidc_resources.h @@ -0,0 +1,217 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __MSM_VIDC_RESOURCES_H__ +#define __MSM_VIDC_RESOURCES_H__ + +#include <linux/platform_device.h> +#include "msm_vidc.h" +#include <linux/soc/qcom/llcc-qcom.h> +#include "soc/qcom/cx_ipeak.h" + +#define MAX_BUFFER_TYPES 32 + +struct reg_value_pair { + u32 reg; + u32 value; +}; + +struct reg_set { + struct reg_value_pair *reg_tbl; + int count; +}; + +struct addr_range { + u32 start; + u32 size; +}; + +struct addr_set { + struct addr_range *addr_tbl; + int count; +}; + +struct context_bank_info { + struct list_head list; + const char *name; + u32 buffer_type; + bool is_secure; + struct addr_range addr_range; + struct device *dev; + struct iommu_domain *domain; +}; + +struct buffer_usage_table { + u32 buffer_type; + u32 tz_usage; +}; + +struct buffer_usage_set { + struct buffer_usage_table *buffer_usage_tbl; + u32 count; +}; + +struct regulator_info { + struct regulator *regulator; + bool has_hw_power_collapse; + char *name; +}; + +struct regulator_set { + struct regulator_info *regulator_tbl; + u32 count; +}; + +struct clock_info { + const char *name; + struct clk *clk; + u32 count; + bool has_scaling; + bool has_mem_retention; +}; + +struct clock_set { + struct clock_info *clock_tbl; + u32 count; +}; + +struct bus_info { + char *name; + int master; + int slave; + unsigned int range[2]; + struct device *dev; + struct msm_bus_client_handle *client; + bool is_prfm_mode; + const char *mode; +}; + +struct bus_set { + struct bus_info *bus_tbl; + u32 count; +}; + +struct reset_info { + struct reset_control *rst; + const char *name; +}; + +struct reset_set { + struct reset_info *reset_tbl; + u32 count; +}; + +struct allowed_clock_rates_table { + u32 clock_rate; +}; + +struct memory_limit_table { + u32 ddr_size; /* mega bytes */ + u32 mem_limit; /* mega bytes */ +}; + +struct clock_profile_entry { + u32 codec_mask; + u32 vpp_cycles; + u32 vsp_cycles; + u32 low_power_cycles; +}; + +struct clock_freq_table { + struct clock_profile_entry *clk_prof_entries; + u32 count; +}; + +struct subcache_info { + const char *name; + bool isactive; + bool isset; + struct llcc_slice_desc *subcache; +}; + +struct subcache_set { + struct subcache_info *subcache_tbl; + u32 count; +}; + +struct msm_vidc_mem_cdsp { + struct device *dev; +}; + +struct msm_vidc_platform_resources { + phys_addr_t firmware_base; + phys_addr_t register_base; + uint32_t register_size; + uint32_t irq; + uint32_t sku_version; + struct allowed_clock_rates_table *allowed_clks_tbl; + u32 allowed_clks_tbl_size; + struct clock_freq_table clock_freq_tbl; + struct memory_limit_table *mem_limit_tbl; + u32 memory_limit_table_size; + bool sys_cache_present; + bool sys_cache_res_set; + struct subcache_set subcache_set; + struct reg_set reg_set; + struct addr_set qdss_addr_set; + struct buffer_usage_set buffer_usage_set; + uint32_t max_load; + uint32_t max_image_load; + uint32_t max_mbpf; + uint32_t max_hq_mbs_per_frame; + uint32_t max_hq_mbs_per_sec; + uint32_t max_bframe_mbs_per_frame; + uint32_t max_bframe_mbs_per_sec; + struct platform_device *pdev; + struct regulator_set regulator_set; + struct clock_set clock_set; + struct bus_set bus_set; + struct reset_set reset_set; + bool sw_power_collapsible; + bool slave_side_cp; + struct list_head context_banks; + struct mutex cb_lock; + bool thermal_mitigable; + const char *fw_name; + const char *hfi_version; + bool never_unload_fw; + bool debug_timeout; + uint32_t pm_qos_latency_us; + uint32_t max_inst_count; + uint32_t max_secure_inst_count; + int msm_vidc_hw_rsp_timeout; + int msm_vidc_firmware_unload_delay; + uint32_t msm_vidc_pwr_collapse_delay; + bool cvp_internal; + bool cvp_external; + bool non_fatal_pagefaults; + bool cache_pagetables; + bool decode_batching; + uint32_t batch_timeout; + bool dcvs; + struct msm_vidc_codec_data *codec_data; + int codec_data_count; + struct msm_vidc_codec *codecs; + uint32_t codecs_count; + struct msm_vidc_codec_capability *codec_caps; + uint32_t codec_caps_count; + struct msm_vidc_csc_coeff *csc_coeff_data; + struct msm_vidc_mem_cdsp mem_cdsp; + uint32_t vpu_ver; + uint32_t fw_cycles; + uint32_t fw_vpp_cycles; + uint32_t avsync_window_size; + struct msm_vidc_ubwc_config_data *ubwc_config; + uint32_t clk_freq_threshold; + struct cx_ipeak_client *cx_ipeak_context; +}; + +static inline bool is_iommu_present(struct msm_vidc_platform_resources *res) +{ + return !list_empty(&res->context_banks); +} + +#endif + diff --git a/techpack/video/msm/vidc/vidc_hfi.c b/techpack/video/msm/vidc/vidc_hfi.c new file mode 100644 index 0000000000000000000000000000000000000000..111965e6e4579980b28c9befa405821e5b7ded8c --- /dev/null +++ b/techpack/video/msm/vidc/vidc_hfi.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. + */ +#include <linux/slab.h> +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" +#include "hfi_common.h" + +struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, + u32 device_id, struct msm_vidc_platform_resources *res, + hfi_cmd_response_callback callback) +{ + struct hfi_device *hdev = NULL; + int rc = 0; + + hdev = kzalloc(sizeof(struct hfi_device), GFP_KERNEL); + if (!hdev) { + d_vpr_e("%s: failed to allocate hdev\n", __func__); + return NULL; + } + + switch (hfi_type) { + case VIDC_HFI_VENUS: + rc = venus_hfi_initialize(hdev, device_id, res, callback); + break; + default: + d_vpr_e("Unsupported host-firmware interface\n"); + goto err_hfi_init; + } + + if (rc) { + if (rc != -EPROBE_DEFER) + d_vpr_e("%s: device init failed rc = %d", + __func__, rc); + goto err_hfi_init; + } + + return hdev; + +err_hfi_init: + kfree(hdev); + return ERR_PTR(rc); +} + +void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type, + struct hfi_device *hdev) +{ + if (!hdev) { + d_vpr_e("%s: invalid device %pK", __func__, hdev); + return; + } + + switch (hfi_type) { + case VIDC_HFI_VENUS: + venus_hfi_delete_device(hdev->hfi_device_data); + break; + default: + d_vpr_e("Unsupported host-firmware interface\n"); + } + + kfree(hdev); +} + diff --git a/techpack/video/msm/vidc/vidc_hfi.h b/techpack/video/msm/vidc/vidc_hfi.h new file mode 100644 index 0000000000000000000000000000000000000000..5fd937757e50b04195c558b462b0664487158400 --- /dev/null +++ b/techpack/video/msm/vidc/vidc_hfi.h @@ -0,0 +1,843 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ +#ifndef __H_VIDC_HFI_H__ +#define __H_VIDC_HFI_H__ + +#include <media/msm_media_info.h> +#include "vidc_hfi_helper.h" +#include "vidc_hfi_api.h" + +#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3) +#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4) +#define HFI_EVENT_SESSION_LTRUSE_FAILED (HFI_OX_BASE + 0x5) +#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6) + +#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \ + (HFI_OX_BASE + 0x1) +#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES \ + (HFI_OX_BASE + 0x2) + +#define HFI_BUFFERFLAG_EOS 0x00000001 +#define HFI_BUFFERFLAG_STARTTIME 0x00000002 +#define HFI_BUFFERFLAG_DECODEONLY 0x00000004 +#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 +#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010 +#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020 +#define HFI_BUFFERFLAG_EXTRADATA 0x00000040 +#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080 +#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100 +#define HFI_BUFFERFLAG_READONLY 0x00000200 +#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400 +#define HFI_BUFFERFLAG_EOSEQ 0x00200000 +#define HFI_BUFFER_FLAG_MBAFF 0x08000000 +#define HFI_BUFFERFLAG_VPE_YUV_601_709_CSC_CLAMP \ + 0x10000000 +#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HFI_BUFFERFLAG_TEI 0x40000000 +#define HFI_BUFFERFLAG_DISCONTINUITY 0x80000000 +#define HFI_BUFFERFLAG_CVPMETADATA_REPEAT 0x00000800 + + +#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \ + (HFI_OX_BASE + 0x1001) +#define HFI_ERR_SESSION_SAME_STATE_OPERATION \ + (HFI_OX_BASE + 0x1002) +#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED \ + (HFI_OX_BASE + 0x1003) +#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \ + (HFI_OX_BASE + 0x1004) + + +#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3) + +#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1) +#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2) +#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4) + +#define HFI_EXTRADATA_NONE 0x00000000 +#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001 +#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002 +#define HFI_EXTRADATA_TIMESTAMP 0x00000005 +#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006 +#define HFI_EXTRADATA_FRAME_RATE 0x00000007 +#define HFI_EXTRADATA_PANSCAN_WINDOW 0x00000008 +#define HFI_EXTRADATA_RECOVERY_POINT_SEI 0x00000009 +#define HFI_EXTRADATA_MPEG2_SEQDISP 0x0000000D +#define HFI_EXTRADATA_STREAM_USERDATA 0x0000000E +#define HFI_EXTRADATA_FRAME_QP 0x0000000F +#define HFI_EXTRADATA_FRAME_BITS_INFO 0x00000010 +#define HFI_EXTRADATA_VPX_COLORSPACE 0x00000014 +#define HFI_EXTRADATA_UBWC_CR_STAT_INFO 0x00000019 +#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000 +#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001 +#define HFI_EXTRADATA_INDEX 0x7F100002 +#define HFI_EXTRADATA_METADATA_LTR 0x7F100004 +#define HFI_EXTRADATA_METADATA_FILLER 0x7FE00002 + +#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000E +#define HFI_INDEX_EXTRADATA_OUTPUT_CROP 0x0700000F +#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003 + +struct hfi_buffer_alloc_mode { + u32 buffer_type; + u32 buffer_mode; +}; + + +struct hfi_index_extradata_config { + int enable; + u32 index_extra_data_id; +}; + +struct hfi_extradata_header { + u32 size; + u32 version; + u32 port_index; + u32 type; + u32 data_size; + u8 rg_data[1]; +}; + +#define HFI_INTERLACE_FRAME_PROGRESSIVE 0x01 +#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02 +#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04 +#define HFI_INTERLACE_FRAME_TOPFIELDFIRST 0x08 +#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10 +#define HFI_INTERLACE_FRAME_MBAFF 0x20 + +#define HFI_PROPERTY_SYS_OX_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000) + +#define HFI_PROPERTY_PARAM_OX_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000) +#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL \ + (HFI_PROPERTY_PARAM_OX_START + 0x001) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \ + (HFI_PROPERTY_PARAM_OX_START + 0x002) +#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \ + (HFI_PROPERTY_PARAM_OX_START + 0x006) +#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \ + (HFI_PROPERTY_PARAM_OX_START + 0x009) +#define HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM \ + (HFI_PROPERTY_PARAM_OX_START + 0x00C) +#define HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT \ + (HFI_PROPERTY_PARAM_OX_START + 0x00E) + +#define HFI_PROPERTY_CONFIG_OX_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000) +#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS \ + (HFI_PROPERTY_CONFIG_OX_START + 0x001) +#define HFI_PROPERTY_CONFIG_REALTIME \ + (HFI_PROPERTY_CONFIG_OX_START + 0x002) +#define HFI_PROPERTY_CONFIG_PRIORITY \ + (HFI_PROPERTY_CONFIG_OX_START + 0x003) +#define HFI_PROPERTY_PARAM_VDEC_OX_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000) +#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001) +#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003) +#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004) +#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005) +#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006) +#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007) +#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A) +#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B) +#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C) +#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D) +#define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E) +#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013) +#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014) +#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015) +#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016) +#define HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x017) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x018) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019) +#define HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01B) +#define HFI_PROPERTY_PARAM_VDEC_VQZIP_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001C) +#define HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001D) +#define HFI_PROPERTY_PARAM_VDEC_MASTER_DISP_COL_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E) +#define HFI_PROPERTY_PARAM_VDEC_CLL_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001F) +#define HFI_PROPERTY_PARAM_VDEC_COLOUR_REMAPPING_INFO_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0020) +#define HFI_PROPERTY_PARAM_VDEC_DOWN_SCALAR \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0021) +#define HFI_PROPERTY_PARAM_VDEC_UBWC_CR_STAT_INFO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0022) +#define HFI_PROPERTY_PARAM_VDEC_HDR10_HIST_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0023) +#define HFI_PROPERTY_PARAM_VDEC_SEQCHNG_AT_SYNCFRM \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0025) + +#define HFI_PROPERTY_CONFIG_VDEC_OX_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000) +#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \ + (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002) +#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \ + (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003) +#define HFI_PROPERTY_CONFIG_VDEC_ENTROPY \ + (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x004) + +#define HFI_PROPERTY_PARAM_VENC_OX_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000) +#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x001) +#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x002) +#define HFI_PROPERTY_PARAM_VENC_LTR_INFO \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x003) +#define HFI_PROPERTY_PARAM_VENC_MBI_DUMPING \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x005) +#define HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x006) +#define HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x008) +#define HFI_PROPERTY_PARAM_VENC_HDR10PLUS_METADATA_EXTRADATA \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x00A) +#define HFI_PROPERTY_PARAM_VENC_CVP_METADATA_EXTRADATA \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x00B) + +#define HFI_PROPERTY_CONFIG_VENC_OX_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000) +#define HFI_PROPERTY_PARAM_VPE_OX_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000) + +#define HFI_PROPERTY_CONFIG_VPE_OX_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000) + +struct hfi_batch_info { + u32 input_batch_count; + u32 output_batch_count; +}; + +struct hfi_buffer_count_actual { + u32 buffer_type; + u32 buffer_count_actual; + u32 buffer_count_min_host; +}; + +struct hfi_buffer_size_minimum { + u32 buffer_type; + u32 buffer_size; +}; + +struct hfi_buffer_requirements { + u32 buffer_type; + u32 buffer_size; + u32 buffer_region_size; + u32 buffer_count_min; + u32 buffer_count_min_host; + u32 buffer_count_actual; + u32 contiguous; + u32 buffer_alignment; +}; + +struct hfi_data_payload { + u32 size; + u8 rg_data[1]; +}; + +struct hfi_mb_error_map { + u32 error_map_size; + u8 rg_error_map[1]; +}; + +struct hfi_metadata_pass_through { + int enable; + u32 size; +}; + +struct hfi_multi_view_select { + u32 view_index; +}; + +struct hfi_hybrid_hierp { + u32 layers; +}; + +#define HFI_PRIORITY_LOW 10 +#define HFI_PRIOIRTY_MEDIUM 20 +#define HFI_PRIORITY_HIGH 30 + +#define HFI_OUTPUT_ORDER_DISPLAY (HFI_OX_BASE + 0x1) +#define HFI_OUTPUT_ORDER_DECODE (HFI_OX_BASE + 0x2) + +#define HFI_RATE_CONTROL_OFF (HFI_OX_BASE + 0x1) +#define HFI_RATE_CONTROL_VBR_VFR (HFI_OX_BASE + 0x2) +#define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3) +#define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4) +#define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5) +#define HFI_RATE_CONTROL_MBR_CFR (HFI_OX_BASE + 0x6) +#define HFI_RATE_CONTROL_MBR_VFR (HFI_OX_BASE + 0x7) +#define HFI_RATE_CONTROL_CQ (HFI_OX_BASE + 0x8) + + +struct hfi_uncompressed_plane_actual_constraints_info { + u32 buffer_type; + u32 num_planes; + struct hfi_uncompressed_plane_constraints rg_plane_format[1]; +}; + +#define HFI_CMD_SYS_OX_START \ +(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x0000) +#define HFI_CMD_SYS_SESSION_ABORT (HFI_CMD_SYS_OX_START + 0x001) + +#define HFI_CMD_SESSION_OX_START \ +(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_CMD_START_OFFSET + 0x1000) +#define HFI_CMD_SESSION_LOAD_RESOURCES (HFI_CMD_SESSION_OX_START + 0x001) +#define HFI_CMD_SESSION_START (HFI_CMD_SESSION_OX_START + 0x002) +#define HFI_CMD_SESSION_STOP (HFI_CMD_SESSION_OX_START + 0x003) +#define HFI_CMD_SESSION_EMPTY_BUFFER (HFI_CMD_SESSION_OX_START + 0x004) +#define HFI_CMD_SESSION_FILL_BUFFER (HFI_CMD_SESSION_OX_START + 0x005) +#define HFI_CMD_SESSION_SUSPEND (HFI_CMD_SESSION_OX_START + 0x006) +#define HFI_CMD_SESSION_RESUME (HFI_CMD_SESSION_OX_START + 0x007) +#define HFI_CMD_SESSION_FLUSH (HFI_CMD_SESSION_OX_START + 0x008) +#define HFI_CMD_SESSION_GET_PROPERTY (HFI_CMD_SESSION_OX_START + 0x009) +#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER \ + (HFI_CMD_SESSION_OX_START + 0x00A) +#define HFI_CMD_SESSION_RELEASE_BUFFERS \ + (HFI_CMD_SESSION_OX_START + 0x00B) +#define HFI_CMD_SESSION_RELEASE_RESOURCES \ + (HFI_CMD_SESSION_OX_START + 0x00C) +#define HFI_CMD_SESSION_CONTINUE (HFI_CMD_SESSION_OX_START + 0x00D) +#define HFI_CMD_SESSION_SYNC (HFI_CMD_SESSION_OX_START + 0x00E) + +#define HFI_CMD_SESSION_CVP_START \ + (HFI_DOMAIN_BASE_CVP + HFI_ARCH_COMMON_OFFSET + \ + HFI_CMD_START_OFFSET + 0x1000) +#define HFI_CMD_SESSION_REGISTER_BUFFERS \ + (HFI_CMD_SESSION_CVP_START + 0x0A0) +#define HFI_CMD_SESSION_UNREGISTER_BUFFERS \ + (HFI_CMD_SESSION_CVP_START + 0x0A1) + +#define HFI_MSG_SYS_OX_START \ +(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000) +#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4) + +#define HFI_MSG_SESSION_OX_START \ +(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x1000) +#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0x1) +#define HFI_MSG_SESSION_START_DONE (HFI_MSG_SESSION_OX_START + 0x2) +#define HFI_MSG_SESSION_STOP_DONE (HFI_MSG_SESSION_OX_START + 0x3) +#define HFI_MSG_SESSION_SUSPEND_DONE (HFI_MSG_SESSION_OX_START + 0x4) +#define HFI_MSG_SESSION_RESUME_DONE (HFI_MSG_SESSION_OX_START + 0x5) +#define HFI_MSG_SESSION_FLUSH_DONE (HFI_MSG_SESSION_OX_START + 0x6) +#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x7) +#define HFI_MSG_SESSION_FILL_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x8) +#define HFI_MSG_SESSION_PROPERTY_INFO (HFI_MSG_SESSION_OX_START + 0x9) +#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE \ + (HFI_MSG_SESSION_OX_START + 0xA) +#define HFI_MSG_SESSION_RELEASE_BUFFERS_DONE \ + (HFI_MSG_SESSION_OX_START + 0xC) + +#define HFI_MSG_SESSION_CVP_START \ + (HFI_DOMAIN_BASE_CVP + HFI_ARCH_COMMON_OFFSET + \ + HFI_MSG_START_OFFSET + 0x1000) +#define HFI_MSG_SESSION_REGISTER_BUFFERS_DONE \ + (HFI_MSG_SESSION_CVP_START + 0x0A0) +#define HFI_MSG_SESSION_UNREGISTER_BUFFERS_DONE \ + (HFI_MSG_SESSION_CVP_START + 0x0A1) + +#define VIDC_IFACEQ_MAX_PKT_SIZE 1024 +#define VIDC_IFACEQ_MED_PKT_SIZE 768 +#define VIDC_IFACEQ_MIN_PKT_SIZE 8 +#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE 100 +#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE 512 +#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE (1024*12) + + +struct hfi_cmd_sys_session_abort_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_session_load_resources_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_session_start_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_session_stop_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_session_empty_buffer_compressed_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; /* not used anywhere */ + u32 mark_data; /* not used anywhere */ + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 input_tag; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[1]; +}; + +struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 view_id; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; /* not used anywhere */ + u32 mark_data; /* not used anywhere */ + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 input_tag; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[1]; +}; + +struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer2; + u32 rgData[1]; +}; + +struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer3; + u32 rgData[1]; +}; + +struct hfi_cmd_session_fill_buffer_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 stream_id; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 output_tag; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[1]; +}; + +struct hfi_cmd_session_flush_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 flush_type; +}; + +struct hfi_cmd_session_suspend_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_session_resume_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_session_get_property_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_session_release_buffer_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 buffer_type; + u32 buffer_size; + u32 extra_data_size; + int response_req; + u32 num_buffers; + u32 rg_buffer_info[1]; +}; + +struct hfi_cmd_session_release_resources_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_msg_sys_session_abort_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_sys_property_info_packet { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_load_resources_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_session_start_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_session_stop_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_session_suspend_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_session_resume_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_session_flush_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; + u32 flush_type; +}; + +struct hfi_ubwc_cr_stats_info_type { + u32 cr_stats_info0; + u32 cr_stats_info1; + u32 cr_stats_info2; + u32 cr_stats_info3; + u32 cr_stats_info4; + u32 cr_stats_info5; + u32 cr_stats_info6; +}; + +struct hfi_frame_cr_stats_type { + u32 frame_index; + struct hfi_ubwc_cr_stats_info_type ubwc_stats_info; + u32 complexity_number; +}; + +struct hfi_msg_session_empty_buffer_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; + u32 offset; + u32 filled_len; + u32 input_tag; + u32 packet_buffer; + u32 extra_data_buffer; + u32 flags; + struct hfi_frame_cr_stats_type ubwc_cr_stats; + /* no usage of sync_frame flag in EBD, rgData[1] is not used */ + u32 rgData[1]; +}; + +struct hfi_msg_session_fill_buffer_done_compressed_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 error_type; + u32 flags; + u32 mark_target; /* not used anywhere */ + u32 mark_data; /* not used anywhere */ + u32 stats; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 input_tag; + u32 output_tag; + u32 picture_type; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[0]; +}; + +struct hfi_msg_session_fbd_uncompressed_plane0_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 stream_id; + u32 view_id; + u32 error_type; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; /* not used anywhere */ + u32 mark_data; /* not used anywhere */ + u32 stats; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 frame_width; + u32 frame_height; + u32 start_x_coord; + u32 start_y_coord; + u32 input_tag; + u32 input_tag2; + u32 output_tag; + u32 picture_type; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[0]; +}; + +struct hfi_msg_session_fill_buffer_done_uncompressed_plane1_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer2; + u32 rgData[0]; +}; + +struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer3; + u32 rgData[0]; +}; + +struct hfi_msg_session_property_info_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_release_resources_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_session_release_buffers_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; + u32 num_buffers; + u32 rg_buffer_info[1]; +}; + +struct hfi_msg_session_register_buffers_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 client_data; + u32 error_type; +}; + +struct hfi_msg_session_unregister_buffers_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 client_data; + u32 error_type; +}; + +struct hfi_extradata_mb_quantization_payload { + u8 rg_mb_qp[1]; +}; + +struct hfi_extradata_timestamp_payload { + u32 time_stamp_low; + u32 time_stamp_high; +}; + + +struct hfi_extradata_s3d_frame_packing_payload { + u32 fpa_id; + int cancel_flag; + u32 fpa_type; + int quin_cunx_flag; + u32 content_interprtation_type; + int spatial_flipping_flag; + int frame0_flipped_flag; + int field_views_flag; + int current_frame_isFrame0_flag; + int frame0_self_contained_flag; + int frame1_self_contained_flag; + u32 frame0_graid_pos_x; + u32 frame0_graid_pos_y; + u32 frame1_graid_pos_x; + u32 frame1_graid_pos_y; + u32 fpa_reserved_byte; + u32 fpa_repetition_period; + int fpa_extension_flag; +}; + +struct hfi_extradata_interlace_video_payload { + u32 format; +}; + +struct hfi_conceal_color_type { + u32 value_8bit; + u32 value_10bit; +}; + +struct hfi_extradata_num_concealed_mb_payload { + u32 num_mb_concealed; +}; + +struct hfi_extradata_sliceinfo { + u32 offset_in_stream; + u32 slice_length; +}; + +struct hfi_extradata_multislice_info_payload { + u32 num_slices; + struct hfi_extradata_sliceinfo rg_slice_info[1]; +}; + +struct hfi_index_extradata_input_crop_payload { + u32 size; + u32 version; + u32 port_index; + u32 left; + u32 top; + u32 width; + u32 height; +}; + +struct hfi_index_extradata_output_crop_payload { + u32 size; + u32 version; + u32 port_index; + u32 left; + u32 top; + u32 display_width; + u32 display_height; + u32 width; + u32 height; +}; + +struct hfi_index_extradata_digital_zoom_payload { + u32 size; + u32 version; + u32 port_index; + int width; + int height; +}; + +struct hfi_index_extradata_aspect_ratio_payload { + u32 size; + u32 version; + u32 port_index; + u32 aspect_width; + u32 aspect_height; +}; + +struct hfi_extradata_frame_type_payload { + u32 frame_rate; +}; + +struct hfi_extradata_recovery_point_sei_payload { + u32 flag; +}; + +struct hfi_cmd_session_continue_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +enum session_flags { + SESSION_PAUSE = BIT(1), +}; + +struct hal_session { + struct list_head list; + void *inst_id; + bool is_decoder; + enum hal_video_codec codec; + enum hal_domain domain; + u32 flags; + u32 sid; +}; + +struct hal_device_data { + struct list_head dev_head; + int dev_count; +}; + +struct msm_vidc_fw { + void *cookie; +}; + +int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + struct msm_vidc_cb_info *info); + +#endif + diff --git a/techpack/video/msm/vidc/vidc_hfi_api.h b/techpack/video/msm/vidc/vidc_hfi_api.h new file mode 100644 index 0000000000000000000000000000000000000000..212b227b182135d5f25bf613173311a565dd4bc1 --- /dev/null +++ b/techpack/video/msm/vidc/vidc_hfi_api.h @@ -0,0 +1,740 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __VIDC_HFI_API_H__ +#define __VIDC_HFI_API_H__ + +#include <linux/log2.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/hash.h> +#include "msm_vidc.h" +#include "msm_vidc_resources.h" + +#define CONTAINS(__a, __sz, __t) (\ + (__t >= __a) && \ + (__t < __a + __sz) \ +) + +#define OVERLAPS(__t, __tsz, __a, __asz) (\ + (__t <= __a) && \ + (__t + __tsz >= __a + __asz) \ +) + +#define HAL_BUFFERFLAG_EOS 0x00000001 +#define HAL_BUFFERFLAG_STARTTIME 0x00000002 +#define HAL_BUFFERFLAG_DATACORRUPT 0x00000008 +#define HAL_BUFFERFLAG_ENDOFFRAME 0x00000010 +#define HAL_BUFFERFLAG_SYNCFRAME 0x00000020 +#define HAL_BUFFERFLAG_EXTRADATA 0x00000040 +#define HAL_BUFFERFLAG_CODECCONFIG 0x00000080 +#define HAL_BUFFERFLAG_READONLY 0x00000200 +#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400 +#define HAL_BUFFERFLAG_MBAFF 0x08000000 +#define HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP 0x10000000 +#define HAL_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HAL_BUFFERFLAG_TS_DISCONTINUITY 0x40000000 +#define HAL_BUFFERFLAG_TS_ERROR 0x80000000 +#define HAL_BUFFERFLAG_CVPMETADATA_SKIP 0x00000800 + + +#define HAL_DEBUG_MSG_LOW 0x00000001 +#define HAL_DEBUG_MSG_MEDIUM 0x00000002 +#define HAL_DEBUG_MSG_HIGH 0x00000004 +#define HAL_DEBUG_MSG_ERROR 0x00000008 +#define HAL_DEBUG_MSG_FATAL 0x00000010 +#define MAX_PROFILE_COUNT 16 + +#define HAL_MAX_MATRIX_COEFFS 9 +#define HAL_MAX_BIAS_COEFFS 3 +#define HAL_MAX_LIMIT_COEFFS 6 +#define VENUS_VERSION_LENGTH 128 + +#define IDR_PERIOD 1 + +/* 16 video sessions */ +#define VIDC_MAX_SESSIONS 16 + +enum vidc_status { + VIDC_ERR_NONE = 0x0, + VIDC_ERR_FAIL = 0x80000000, + VIDC_ERR_ALLOC_FAIL, + VIDC_ERR_ILLEGAL_OP, + VIDC_ERR_BAD_PARAM, + VIDC_ERR_BAD_HANDLE, + VIDC_ERR_NOT_SUPPORTED, + VIDC_ERR_BAD_STATE, + VIDC_ERR_MAX_CLIENTS, + VIDC_ERR_IFRAME_EXPECTED, + VIDC_ERR_HW_FATAL, + VIDC_ERR_BITSTREAM_ERR, + VIDC_ERR_INDEX_NOMORE, + VIDC_ERR_SEQHDR_PARSE_FAIL, + VIDC_ERR_INSUFFICIENT_BUFFER, + VIDC_ERR_BAD_POWER_STATE, + VIDC_ERR_NO_VALID_SESSION, + VIDC_ERR_TIMEOUT, + VIDC_ERR_CMDQFULL, + VIDC_ERR_START_CODE_NOT_FOUND, + VIDC_ERR_NOC_ERROR, + VIDC_ERR_CLIENT_PRESENT = 0x90000001, + VIDC_ERR_CLIENT_FATAL, + VIDC_ERR_CMD_QUEUE_FULL, + VIDC_ERR_UNUSED = 0x10000000 +}; + +enum hal_domain { + HAL_VIDEO_DOMAIN_VPE = BIT(0), + HAL_VIDEO_DOMAIN_ENCODER = BIT(1), + HAL_VIDEO_DOMAIN_DECODER = BIT(2), + HAL_VIDEO_DOMAIN_CVP = BIT(3), + HAL_UNUSED_DOMAIN = 0x10000000, +}; + +enum multi_stream { + HAL_VIDEO_DECODER_NONE = 0x00000000, + HAL_VIDEO_DECODER_PRIMARY = 0x00000001, + HAL_VIDEO_DECODER_SECONDARY = 0x00000002, + HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004, + HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000, +}; + +enum hal_core_capabilities { + HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001, + HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002, + HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY = 0x00000004, + HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY = 0x00000008, + HAL_VIDEO_UNUSED_CAPABILITY = 0x10000000, +}; + +enum hal_default_properties { + HAL_VIDEO_DYNAMIC_BUF_MODE = 0x00000001, + HAL_VIDEO_CONTINUE_DATA_TRANSFER = 0x00000002, +}; + +enum hal_video_codec { + HAL_VIDEO_CODEC_UNKNOWN = 0x00000000, + HAL_VIDEO_CODEC_MVC = 0x00000001, + HAL_VIDEO_CODEC_H264 = 0x00000002, + HAL_VIDEO_CODEC_H263 = 0x00000004, + HAL_VIDEO_CODEC_MPEG1 = 0x00000008, + HAL_VIDEO_CODEC_MPEG2 = 0x00000010, + HAL_VIDEO_CODEC_MPEG4 = 0x00000020, + HAL_VIDEO_CODEC_DIVX_311 = 0x00000040, + HAL_VIDEO_CODEC_DIVX = 0x00000080, + HAL_VIDEO_CODEC_VC1 = 0x00000100, + HAL_VIDEO_CODEC_SPARK = 0x00000200, + HAL_VIDEO_CODEC_VP6 = 0x00000400, + HAL_VIDEO_CODEC_VP7 = 0x00000800, + HAL_VIDEO_CODEC_VP8 = 0x00001000, + HAL_VIDEO_CODEC_HEVC = 0x00002000, + HAL_VIDEO_CODEC_VP9 = 0x00004000, + HAL_VIDEO_CODEC_TME = 0x00008000, + HAL_VIDEO_CODEC_CVP = 0x00010000, + HAL_VIDEO_CODEC_HEVC_HYBRID = 0x80000000, + HAL_UNUSED_CODEC = 0x10000000, +}; + +enum hal_uncompressed_format { + HAL_COLOR_FORMAT_MONOCHROME = 0x00000001, + HAL_COLOR_FORMAT_NV12 = 0x00000002, + HAL_COLOR_FORMAT_NV21 = 0x00000004, + HAL_COLOR_FORMAT_NV12_4x4TILE = 0x00000008, + HAL_COLOR_FORMAT_NV21_4x4TILE = 0x00000010, + HAL_COLOR_FORMAT_YUYV = 0x00000020, + HAL_COLOR_FORMAT_YVYU = 0x00000040, + HAL_COLOR_FORMAT_UYVY = 0x00000080, + HAL_COLOR_FORMAT_VYUY = 0x00000100, + HAL_COLOR_FORMAT_RGB565 = 0x00000200, + HAL_COLOR_FORMAT_BGR565 = 0x00000400, + HAL_COLOR_FORMAT_RGB888 = 0x00000800, + HAL_COLOR_FORMAT_BGR888 = 0x00001000, + HAL_COLOR_FORMAT_NV12_UBWC = 0x00002000, + HAL_COLOR_FORMAT_NV12_TP10_UBWC = 0x00004000, + HAL_COLOR_FORMAT_RGBA8888 = 0x00008000, + HAL_COLOR_FORMAT_RGBA8888_UBWC = 0x00010000, + HAL_COLOR_FORMAT_P010 = 0x00020000, + HAL_COLOR_FORMAT_NV12_512 = 0x00040000, + HAL_UNUSED_COLOR = 0x10000000, +}; + +enum hal_ssr_trigger_type { + SSR_ERR_FATAL = 1, + SSR_SW_DIV_BY_ZERO, + SSR_HW_WDOG_IRQ, +}; + +struct hal_profile_level { + u32 profile; + u32 level; +}; + +struct hal_profile_level_supported { + u32 profile_count; + struct hal_profile_level profile_level[MAX_PROFILE_COUNT]; +}; + +enum hal_intra_refresh_mode { + HAL_INTRA_REFRESH_NONE = 0x1, + HAL_INTRA_REFRESH_CYCLIC = 0x2, + HAL_INTRA_REFRESH_RANDOM = 0x5, + HAL_UNUSED_INTRA = 0x10000000, +}; + +struct hal_intra_refresh { + enum hal_intra_refresh_mode mode; + u32 ir_mbs; +}; + +struct hal_buffer_requirements { + enum hal_buffer buffer_type; + u32 buffer_size; + u32 buffer_region_size; + u32 buffer_count_min; + u32 buffer_count_min_host; + u32 buffer_count_actual; + u32 contiguous; + u32 buffer_alignment; +}; + +enum hal_priority {/* Priority increases with number */ + HAL_PRIORITY_LOW = 10, + HAL_PRIOIRTY_MEDIUM = 20, + HAL_PRIORITY_HIGH = 30, + HAL_UNUSED_PRIORITY = 0x10000000, +}; + +struct hal_batch_info { + u32 input_batch_count; + u32 output_batch_count; +}; + +struct hal_uncompressed_format_supported { + enum hal_buffer buffer_type; + u32 format_entries; + u32 rg_format_info[1]; +}; + +enum hal_interlace_format { + HAL_INTERLACE_FRAME_PROGRESSIVE = 0x01, + HAL_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02, + HAL_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04, + HAL_INTERLACE_FRAME_TOPFIELDFIRST = 0x08, + HAL_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10, + HAL_UNUSED_INTERLACE = 0x10000000, +}; + +struct hal_interlace_format_supported { + enum hal_buffer buffer_type; + enum hal_interlace_format format; +}; + +enum hal_chroma_site { + HAL_CHROMA_SITE_0, + HAL_CHROMA_SITE_1, + HAL_UNUSED_CHROMA = 0x10000000, +}; + +enum hal_capability { + CAP_FRAME_WIDTH = 0x1, + CAP_FRAME_HEIGHT, + CAP_MBS_PER_FRAME, + CAP_MBS_PER_SECOND, + CAP_FRAMERATE, + CAP_OPERATINGRATE, + CAP_SCALE_X, + CAP_SCALE_Y, + CAP_BITRATE, + CAP_CABAC_BITRATE, + CAP_BFRAME, + CAP_PEAKBITRATE, + CAP_HIER_P_NUM_ENH_LAYERS, + CAP_LTR_COUNT, + CAP_SECURE_OUTPUT2_THRESHOLD, + CAP_HIER_B_NUM_ENH_LAYERS, + CAP_LCU_SIZE, + CAP_HIER_P_HYBRID_NUM_ENH_LAYERS, + CAP_MBS_PER_SECOND_POWER_SAVE, + CAP_EXTRADATA, + CAP_PROFILE, + CAP_LEVEL, + CAP_I_FRAME_QP, + CAP_P_FRAME_QP, + CAP_B_FRAME_QP, + CAP_RATE_CONTROL_MODES, + CAP_BLUR_WIDTH, + CAP_BLUR_HEIGHT, + CAP_SLICE_BYTE, + CAP_SLICE_MB, + CAP_SECURE, + CAP_MAX_NUM_B_FRAMES, + CAP_MAX_VIDEOCORES, + CAP_MAX_WORKMODES, + CAP_UBWC_CR_STATS, + CAP_SECURE_FRAME_WIDTH, + CAP_SECURE_FRAME_HEIGHT, + CAP_SECURE_MBS_PER_FRAME, + CAP_SECURE_BITRATE, + CAP_BATCH_MAX_MB_PER_FRAME, + CAP_BATCH_MAX_FPS, + CAP_LOSSLESS_FRAME_WIDTH, + CAP_LOSSLESS_FRAME_HEIGHT, + CAP_LOSSLESS_MBS_PER_FRAME, + CAP_ALLINTRA_MAX_FPS, + CAP_HEVC_IMAGE_FRAME_WIDTH, + CAP_HEVC_IMAGE_FRAME_HEIGHT, + CAP_HEIC_IMAGE_FRAME_WIDTH, + CAP_HEIC_IMAGE_FRAME_HEIGHT, + CAP_H264_LEVEL, + CAP_HEVC_LEVEL, + CAP_MAX, +}; + +struct hal_capability_supported { + enum hal_capability capability_type; + u32 min; + u32 max; + u32 step_size; + u32 default_value; +}; + +struct hal_nal_stream_format_supported { + u32 nal_stream_format_supported; +}; + +struct hal_nal_stream_format_select { + u32 nal_stream_format_select; +}; + +struct hal_multi_view_format { + u32 views; + u32 rg_view_order[1]; +}; + +enum hal_buffer_layout_type { + HAL_BUFFER_LAYOUT_TOP_BOTTOM, + HAL_BUFFER_LAYOUT_SEQ, + HAL_UNUSED_BUFFER_LAYOUT = 0x10000000, +}; + +struct hal_codec_supported { + u32 decoder_codec_supported; + u32 encoder_codec_supported; +}; + +enum hal_core_id { + VIDC_CORE_ID_DEFAULT = 0, + VIDC_CORE_ID_1 = 1, /* 0b01 */ + VIDC_CORE_ID_2 = 2, /* 0b10 */ + VIDC_CORE_ID_3 = 3, /* 0b11 */ + VIDC_CORE_ID_UNUSED = 0x10000000, +}; + +enum vidc_resource_id { + VIDC_RESOURCE_NONE, + VIDC_RESOURCE_SYSCACHE, + VIDC_UNUSED_RESOURCE = 0x10000000, +}; + +struct vidc_resource_hdr { + enum vidc_resource_id resource_id; + void *resource_handle; +}; + +struct vidc_register_buffer { + enum hal_buffer type; + u32 index; + u32 size; + u32 device_addr; + u32 response_required; + u32 client_data; +}; + +struct vidc_unregister_buffer { + enum hal_buffer type; + u32 index; + u32 size; + u32 device_addr; + u32 response_required; + u32 client_data; +}; + +struct vidc_buffer_addr_info { + enum hal_buffer buffer_type; + u32 buffer_size; + u32 num_buffers; + u32 align_device_addr; + u32 extradata_addr; + u32 extradata_size; + u32 response_required; +}; + +/* Needs to be exactly the same as hfi_buffer_info */ +struct hal_buffer_info { + u32 buffer_addr; + u32 extra_data_addr; +}; + +struct vidc_frame_plane_config { + u32 left; + u32 top; + u32 width; + u32 height; + u32 stride; + u32 scan_lines; +}; + +struct vidc_uncompressed_frame_config { + struct vidc_frame_plane_config luma_plane; + struct vidc_frame_plane_config chroma_plane; +}; + +struct vidc_frame_data { + enum hal_buffer buffer_type; + u32 device_addr; + u32 extradata_addr; + int64_t timestamp; + u32 flags; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 input_tag; + u32 extradata_size; +}; + +struct hal_fw_info { + char version[VENUS_VERSION_LENGTH]; + phys_addr_t base_addr; + int register_base; + int register_size; + int irq; +}; + +enum hal_flush { + HAL_FLUSH_INPUT = BIT(0), + HAL_FLUSH_OUTPUT = BIT(1), + HAL_FLUSH_ALL = HAL_FLUSH_INPUT | HAL_FLUSH_OUTPUT, +}; + +enum hal_event_type { + HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES, + HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES, + HAL_EVENT_RELEASE_BUFFER_REFERENCE, + HAL_UNUSED_SEQCHG = 0x10000000, +}; + +enum buffer_mode_type { + HAL_BUFFER_MODE_DYNAMIC = 0x100, + HAL_BUFFER_MODE_STATIC = 0x001, +}; + +struct hal_buffer_alloc_mode { + enum hal_buffer buffer_type; + enum buffer_mode_type buffer_mode; +}; + +enum ltr_mode { + HAL_LTR_MODE_DISABLE, + HAL_LTR_MODE_MANUAL, +}; + +struct buffer_requirements { + struct hal_buffer_requirements buffer[HAL_BUFFER_MAX]; +}; + +struct hal_conceal_color { + u32 conceal_color_8bit; + u32 conceal_color_10bit; +}; + +union hal_get_property { + struct hal_batch_info batch_info; + struct hal_uncompressed_format_supported uncompressed_format_supported; + struct hal_interlace_format_supported interlace_format_supported; + struct hal_nal_stream_format_supported nal_stream_format_supported; + struct hal_nal_stream_format_select nal_stream_format_select; + struct hal_multi_view_format multi_view_format; + struct hal_buffer_info buffer_info; + struct hal_buffer_alloc_mode buffer_alloc_mode; + struct buffer_requirements buf_req; + struct hal_conceal_color conceal_color; +}; + +/* HAL Response */ +#define IS_HAL_SYS_CMD(cmd) ((cmd) >= HAL_SYS_INIT_DONE && \ + (cmd) <= HAL_SYS_ERROR) +#define IS_HAL_SESSION_CMD(cmd) ((cmd) >= HAL_SESSION_EVENT_CHANGE && \ + (cmd) <= HAL_SESSION_ERROR) +enum hal_command_response { + /* SYSTEM COMMANDS_DONE*/ + HAL_SYS_INIT_DONE, + HAL_SYS_SET_RESOURCE_DONE, + HAL_SYS_RELEASE_RESOURCE_DONE, + HAL_SYS_PC_PREP_DONE, + HAL_SYS_IDLE, + HAL_SYS_DEBUG, + HAL_SYS_WATCHDOG_TIMEOUT, + HAL_SYS_ERROR, + /* SESSION COMMANDS_DONE */ + HAL_SESSION_EVENT_CHANGE, + HAL_SESSION_LOAD_RESOURCE_DONE, + HAL_SESSION_INIT_DONE, + HAL_SESSION_END_DONE, + HAL_SESSION_ABORT_DONE, + HAL_SESSION_START_DONE, + HAL_SESSION_STOP_DONE, + HAL_SESSION_ETB_DONE, + HAL_SESSION_FTB_DONE, + HAL_SESSION_FLUSH_DONE, + HAL_SESSION_SUSPEND_DONE, + HAL_SESSION_RESUME_DONE, + HAL_SESSION_SET_PROP_DONE, + HAL_SESSION_GET_PROP_DONE, + HAL_SESSION_RELEASE_BUFFER_DONE, + HAL_SESSION_REGISTER_BUFFER_DONE, + HAL_SESSION_UNREGISTER_BUFFER_DONE, + HAL_SESSION_RELEASE_RESOURCE_DONE, + HAL_SESSION_PROPERTY_INFO, + HAL_SESSION_ERROR, + HAL_RESPONSE_UNUSED = 0x10000000, +}; + +struct ubwc_cr_stats_info_type { + u32 cr_stats_info0; + u32 cr_stats_info1; + u32 cr_stats_info2; + u32 cr_stats_info3; + u32 cr_stats_info4; + u32 cr_stats_info5; + u32 cr_stats_info6; +}; + +struct recon_stats_type { + u32 buffer_index; + u32 complexity_number; + struct ubwc_cr_stats_info_type ubwc_stats_info; +}; + +struct vidc_hal_ebd { + u32 timestamp_hi; + u32 timestamp_lo; + u32 flags; + enum vidc_status status; + u32 input_tag; + u32 stats; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 picture_type; + struct recon_stats_type recon_stats; + u32 packet_buffer; + u32 extra_data_buffer; +}; + +struct vidc_hal_fbd { + u32 stream_id; + u32 view_id; + u32 timestamp_hi; + u32 timestamp_lo; + u32 flags1; + u32 stats; + u32 alloc_len1; + u32 filled_len1; + u32 offset1; + u32 frame_width; + u32 frame_height; + u32 start_x_coord; + u32 start_y_coord; + u32 input_tag; + u32 input_tag2; + u32 picture_type; + u32 packet_buffer1; + u32 extra_data_buffer; + u32 flags2; + u32 alloc_len2; + u32 filled_len2; + u32 offset2; + u32 packet_buffer2; + u32 flags3; + u32 alloc_len3; + u32 filled_len3; + u32 offset3; + u32 packet_buffer3; + enum hal_buffer buffer_type; +}; + +struct msm_vidc_capability { + enum hal_domain domain; + enum hal_video_codec codec; + struct hal_capability_supported cap[CAP_MAX]; +}; + +struct vidc_hal_sys_init_done { + u32 dec_codec_supported; + u32 enc_codec_supported; + u32 max_sessions_supported; +}; + +struct msm_vidc_cb_cmd_done { + u32 device_id; + void *inst_id; + enum vidc_status status; + u32 size; + union { + struct vidc_resource_hdr resource_hdr; + struct vidc_buffer_addr_info buffer_addr_info; + struct vidc_frame_plane_config frame_plane_config; + struct vidc_uncompressed_frame_config uncompressed_frame_config; + struct vidc_frame_data frame_data; + struct vidc_hal_ebd ebd; + struct vidc_hal_fbd fbd; + struct vidc_hal_sys_init_done sys_init_done; + struct hal_buffer_info buffer_info; + struct vidc_register_buffer regbuf; + struct vidc_unregister_buffer unregbuf; + union hal_get_property property; + enum hal_flush flush_type; + } data; +}; + +struct msm_vidc_cb_event { + u32 device_id; + void *inst_id; + enum vidc_status status; + u32 height; + u32 width; + int bit_depth; + u32 hal_event_type; + u32 packet_buffer; + u32 extra_data_buffer; + u32 pic_struct; + u32 colour_space; + u32 profile; + u32 level; + u32 entropy_mode; + u32 max_dpb_count; + u32 max_ref_frames; + u32 max_dec_buffering; + u32 max_reorder_frames; + u32 fw_min_cnt; +}; + +struct msm_vidc_cb_data_done { + u32 device_id; + void *inst_id; + enum vidc_status status; + u32 size; + union { + struct vidc_hal_ebd input_done; + struct vidc_hal_fbd output_done; + }; +}; + +struct msm_vidc_cb_info { + enum hal_command_response response_type; + union { + struct msm_vidc_cb_cmd_done cmd; + struct msm_vidc_cb_event event; + struct msm_vidc_cb_data_done data; + } response; +}; + +enum msm_vidc_hfi_type { + VIDC_HFI_VENUS, +}; + +enum msm_vidc_thermal_level { + VIDC_THERMAL_NORMAL = 0, + VIDC_THERMAL_LOW, + VIDC_THERMAL_HIGH, + VIDC_THERMAL_CRITICAL +}; + +enum msm_vidc_power_mode { + VIDC_POWER_NORMAL = 0, + VIDC_POWER_LOW, + VIDC_POWER_TURBO +}; + +struct hal_cmd_sys_get_property_packet { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hal_hdr10_pq_sei { + struct msm_vidc_mastering_display_colour_sei_payload disp_color_sei; + struct msm_vidc_content_light_level_sei_payload cll_sei; +}; + +struct hal_vbv_hdr_buf_size { + u32 vbv_hdr_buf_size; +}; + +#define call_hfi_op(q, op, ...) \ + (((q) && (q)->op) ? ((q)->op(__VA_ARGS__)) : 0) + +struct hfi_device { + void *hfi_device_data; + + /*Add function pointers for all the hfi functions below*/ + int (*core_init)(void *device); + int (*core_release)(void *device); + int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type); + int (*session_init)(void *device, void *inst_id, + enum hal_domain session_type, enum hal_video_codec codec_type, + void **new_session, u32 sid); + int (*session_end)(void *session); + int (*session_abort)(void *session); + int (*session_set_buffers)(void *sess, + struct vidc_buffer_addr_info *buffer_info); + int (*session_release_buffers)(void *sess, + struct vidc_buffer_addr_info *buffer_info); + int (*session_register_buffer)(void *sess, + struct vidc_register_buffer *buffer); + int (*session_unregister_buffer)(void *sess, + struct vidc_unregister_buffer *buffer); + int (*session_load_res)(void *sess); + int (*session_release_res)(void *sess); + int (*session_start)(void *sess); + int (*session_continue)(void *sess); + int (*session_stop)(void *sess); + int (*session_etb)(void *sess, struct vidc_frame_data *input_frame); + int (*session_ftb)(void *sess, struct vidc_frame_data *output_frame); + int (*session_process_batch)(void *sess, + int num_etbs, struct vidc_frame_data etbs[], + int num_ftbs, struct vidc_frame_data ftbs[]); + int (*session_get_buf_req)(void *sess); + int (*session_flush)(void *sess, enum hal_flush flush_mode); + int (*session_set_property)(void *sess, u32 ptype, + void *pdata, u32 size); + int (*session_pause)(void *sess); + int (*session_resume)(void *sess); + int (*scale_clocks)(void *dev, u32 freq, u32 sid); + int (*vote_bus)(void *dev, unsigned long bw_ddr, + unsigned long bw_llcc, u32 sid); + int (*get_fw_info)(void *dev, struct hal_fw_info *fw_info); + int (*session_clean)(void *sess); + int (*get_core_capabilities)(void *dev); + int (*suspend)(void *dev); + int (*flush_debug_queue)(void *dev); + int (*noc_error_info)(void *dev); + enum hal_default_properties (*get_default_properties)(void *dev); +}; + +typedef void (*hfi_cmd_response_callback) (enum hal_command_response cmd, + void *data); +typedef void (*msm_vidc_callback) (u32 response, void *callback); + +struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type, + u32 device_id, struct msm_vidc_platform_resources *res, + hfi_cmd_response_callback callback); +void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type, + struct hfi_device *hdev); +u32 vidc_get_hfi_domain(enum hal_domain hal_domain, u32 sid); +u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec, u32 sid); +#endif /*__VIDC_HFI_API_H__ */ diff --git a/techpack/video/msm/vidc/vidc_hfi_helper.h b/techpack/video/msm/vidc/vidc_hfi_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..1448d4aad56152dbef18c6f0de8710ea55a72129 --- /dev/null +++ b/techpack/video/msm/vidc/vidc_hfi_helper.h @@ -0,0 +1,1107 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __H_VIDC_HFI_HELPER_H__ +#define __H_VIDC_HFI_HELPER_H__ + +#include <linux/types.h> +#include <media/msm_vidc_utils.h> +#define HFI_COMMON_BASE (0) +#define HFI_OX_BASE (0x01000000) + +#define HFI_VIDEO_DOMAIN_ENCODER (HFI_COMMON_BASE + 0x1) +#define HFI_VIDEO_DOMAIN_DECODER (HFI_COMMON_BASE + 0x2) +#define HFI_VIDEO_DOMAIN_VPE (HFI_COMMON_BASE + 0x4) +#define HFI_VIDEO_DOMAIN_CVP (HFI_COMMON_BASE + 0x8) + +#define HFI_DOMAIN_BASE_COMMON (HFI_COMMON_BASE + 0) +#define HFI_DOMAIN_BASE_VDEC (HFI_COMMON_BASE + 0x01000000) +#define HFI_DOMAIN_BASE_VENC (HFI_COMMON_BASE + 0x02000000) +#define HFI_DOMAIN_BASE_VPE (HFI_COMMON_BASE + 0x03000000) +#define HFI_DOMAIN_BASE_CVP (HFI_COMMON_BASE + 0x04000000) + +#define HFI_VIDEO_ARCH_OX (HFI_COMMON_BASE + 0x1) + +#define HFI_ARCH_COMMON_OFFSET (0) +#define HFI_ARCH_OX_OFFSET (0x00200000) + +#define HFI_CMD_START_OFFSET (0x00010000) +#define HFI_MSG_START_OFFSET (0x00020000) + +#define HFI_ERR_NONE HFI_COMMON_BASE +#define HFI_ERR_SYS_FATAL (HFI_COMMON_BASE + 0x1) +#define HFI_ERR_SYS_INVALID_PARAMETER (HFI_COMMON_BASE + 0x2) +#define HFI_ERR_SYS_VERSION_MISMATCH (HFI_COMMON_BASE + 0x3) +#define HFI_ERR_SYS_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x4) +#define HFI_ERR_SYS_MAX_SESSIONS_REACHED (HFI_COMMON_BASE + 0x5) +#define HFI_ERR_SYS_UNSUPPORTED_CODEC (HFI_COMMON_BASE + 0x6) +#define HFI_ERR_SYS_SESSION_IN_USE (HFI_COMMON_BASE + 0x7) +#define HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE (HFI_COMMON_BASE + 0x8) +#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN (HFI_COMMON_BASE + 0x9) +#define HFI_ERR_SYS_NOC_ERROR (HFI_COMMON_BASE + 0x11) +#define HFI_ERR_SESSION_FATAL (HFI_COMMON_BASE + 0x1001) +#define HFI_ERR_SESSION_INVALID_PARAMETER (HFI_COMMON_BASE + 0x1002) +#define HFI_ERR_SESSION_BAD_POINTER (HFI_COMMON_BASE + 0x1003) +#define HFI_ERR_SESSION_INVALID_SESSION_ID (HFI_COMMON_BASE + 0x1004) +#define HFI_ERR_SESSION_INVALID_STREAM_ID (HFI_COMMON_BASE + 0x1005) +#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION \ + (HFI_COMMON_BASE + 0x1006) +#define HFI_ERR_SESSION_UNSUPPORTED_PROPERTY (HFI_COMMON_BASE + 0x1007) + +#define HFI_ERR_SESSION_UNSUPPORTED_SETTING (HFI_COMMON_BASE + 0x1008) + +#define HFI_ERR_SESSION_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x1009) + +#define HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED \ + (HFI_COMMON_BASE + 0x100A) + +#define HFI_ERR_SESSION_STREAM_CORRUPT (HFI_COMMON_BASE + 0x100B) +#define HFI_ERR_SESSION_ENC_OVERFLOW (HFI_COMMON_BASE + 0x100C) +#define HFI_ERR_SESSION_UNSUPPORTED_STREAM (HFI_COMMON_BASE + 0x100D) +#define HFI_ERR_SESSION_CMDSIZE (HFI_COMMON_BASE + 0x100E) +#define HFI_ERR_SESSION_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x100F) +#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE (HFI_COMMON_BASE + 0x1010) +#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL (HFI_COMMON_BASE + 0x1011) +#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR (HFI_COMMON_BASE + 0x1012) +#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED (HFI_COMMON_BASE + 0x1013) + +#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1) +#define HFI_EVENT_SESSION_ERROR (HFI_COMMON_BASE + 0x2) + +#define HFI_VIDEO_CODEC_H264 0x00000002 +#define HFI_VIDEO_CODEC_MPEG1 0x00000008 +#define HFI_VIDEO_CODEC_MPEG2 0x00000010 +#define HFI_VIDEO_CODEC_VP8 0x00001000 +#define HFI_VIDEO_CODEC_HEVC 0x00002000 +#define HFI_VIDEO_CODEC_VP9 0x00004000 +#define HFI_VIDEO_CODEC_TME 0x00008000 +#define HFI_VIDEO_CODEC_CVP 0x00010000 + +#define HFI_PROFILE_UNKNOWN 0x00000000 +#define HFI_LEVEL_UNKNOWN 0x00000000 + +#define HFI_H264_PROFILE_BASELINE 0x00000001 +#define HFI_H264_PROFILE_MAIN 0x00000002 +#define HFI_H264_PROFILE_HIGH 0x00000004 +#define HFI_H264_PROFILE_STEREO_HIGH 0x00000008 +#define HFI_H264_PROFILE_MULTIVIEW_HIGH 0x00000010 +#define HFI_H264_PROFILE_CONSTRAINED_BASE 0x00000020 +#define HFI_H264_PROFILE_CONSTRAINED_HIGH 0x00000040 + +#define HFI_LEVEL_UNKNOWN 0x00000000 +#define HFI_H264_LEVEL_1 0x00000001 +#define HFI_H264_LEVEL_1b 0x00000002 +#define HFI_H264_LEVEL_11 0x00000004 +#define HFI_H264_LEVEL_12 0x00000008 +#define HFI_H264_LEVEL_13 0x00000010 +#define HFI_H264_LEVEL_2 0x00000020 +#define HFI_H264_LEVEL_21 0x00000040 +#define HFI_H264_LEVEL_22 0x00000080 +#define HFI_H264_LEVEL_3 0x00000100 +#define HFI_H264_LEVEL_31 0x00000200 +#define HFI_H264_LEVEL_32 0x00000400 +#define HFI_H264_LEVEL_4 0x00000800 +#define HFI_H264_LEVEL_41 0x00001000 +#define HFI_H264_LEVEL_42 0x00002000 +#define HFI_H264_LEVEL_5 0x00004000 +#define HFI_H264_LEVEL_51 0x00008000 +#define HFI_H264_LEVEL_52 0x00010000 +#define HFI_H264_LEVEL_6 0x00020000 +#define HFI_H264_LEVEL_61 0x00040000 +#define HFI_H264_LEVEL_62 0x00080000 + +#define HFI_MPEG2_PROFILE_SIMPLE 0x00000001 +#define HFI_MPEG2_PROFILE_MAIN 0x00000002 + +#define HFI_MPEG2_LEVEL_LL 0x00000001 +#define HFI_MPEG2_LEVEL_ML 0x00000002 +#define HFI_MPEG2_LEVEL_HL 0x00000004 + +#define HFI_VP8_PROFILE_MAIN 0x00000001 + +#define HFI_VP8_LEVEL_VERSION_0 0x00000001 +#define HFI_VP8_LEVEL_VERSION_1 0x00000002 +#define HFI_VP8_LEVEL_VERSION_2 0x00000004 +#define HFI_VP8_LEVEL_VERSION_3 0x00000008 + +#define HFI_VP9_PROFILE_P0 0x00000001 +#define HFI_VP9_PROFILE_P2_10B 0x00000004 + +#define HFI_VP9_LEVEL_1 0x00000001 +#define HFI_VP9_LEVEL_11 0x00000002 +#define HFI_VP9_LEVEL_2 0x00000004 +#define HFI_VP9_LEVEL_21 0x00000008 +#define HFI_VP9_LEVEL_3 0x00000010 +#define HFI_VP9_LEVEL_31 0x00000020 +#define HFI_VP9_LEVEL_4 0x00000040 +#define HFI_VP9_LEVEL_41 0x00000080 +#define HFI_VP9_LEVEL_5 0x00000100 +#define HFI_VP9_LEVEL_51 0x00000200 +#define HFI_VP9_LEVEL_6 0x00000400 +#define HFI_VP9_LEVEL_61 0x00000800 + +#define HFI_HEVC_PROFILE_MAIN 0x00000001 +#define HFI_HEVC_PROFILE_MAIN10 0x00000002 +#define HFI_HEVC_PROFILE_MAIN_STILL_PIC 0x00000004 + +#define HFI_HEVC_LEVEL_1 0x00000001 +#define HFI_HEVC_LEVEL_2 0x00000002 +#define HFI_HEVC_LEVEL_21 0x00000004 +#define HFI_HEVC_LEVEL_3 0x00000008 +#define HFI_HEVC_LEVEL_31 0x00000010 +#define HFI_HEVC_LEVEL_4 0x00000020 +#define HFI_HEVC_LEVEL_41 0x00000040 +#define HFI_HEVC_LEVEL_5 0x00000080 +#define HFI_HEVC_LEVEL_51 0x00000100 +#define HFI_HEVC_LEVEL_52 0x00000200 +#define HFI_HEVC_LEVEL_6 0x00000400 +#define HFI_HEVC_LEVEL_61 0x00000800 +#define HFI_HEVC_LEVEL_62 0x00001000 + +#define HFI_HEVC_TIER_MAIN 0x1 +#define HFI_HEVC_TIER_HIGH 0x2 + +#define HFI_TME_PROFILE_DEFAULT 0x00000001 +#define HFI_TME_PROFILE_FRC 0x00000002 +#define HFI_TME_PROFILE_ASW 0x00000004 +#define HFI_TME_PROFILE_DFS_BOKEH 0x00000008 + +#define HFI_TME_LEVEL_INTEGER 0x00000001 + +#define HFI_BUFFER_INPUT (HFI_COMMON_BASE + 0x1) +#define HFI_BUFFER_OUTPUT (HFI_COMMON_BASE + 0x2) +#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3) +#define HFI_BUFFER_INTERNAL_PERSIST (HFI_COMMON_BASE + 0x4) +#define HFI_BUFFER_INTERNAL_PERSIST_1 (HFI_COMMON_BASE + 0x5) +#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH (HFI_COMMON_BASE + 0x6) +#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1 (HFI_COMMON_BASE + 0x7) +#define HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2 (HFI_COMMON_BASE + 0x8) +#define HFI_BUFFER_COMMON_INTERNAL_RECON (HFI_COMMON_BASE + 0x9) +#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_COMMON_BASE + 0xA) +#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_COMMON_BASE + 0xB) +#define HFI_BUFFER_EXTRADATA_INPUT (HFI_COMMON_BASE + 0xC) + +#define HFI_BITDEPTH_8 (HFI_COMMON_BASE + 0x0) +#define HFI_BITDEPTH_9 (HFI_COMMON_BASE + 0x1) +#define HFI_BITDEPTH_10 (HFI_COMMON_BASE + 0x2) + +#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1 +#define HFI_VENC_PERFMODE_POWER_SAVE 0x2 + +#define HFI_WORKMODE_1 (HFI_COMMON_BASE + 0x1) +#define HFI_WORKMODE_2 (HFI_COMMON_BASE + 0x2) + +struct hfi_buffer_info { + u32 buffer_addr; + u32 extra_data_addr; +}; + +#define HFI_PROPERTY_SYS_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000) +#define HFI_PROPERTY_SYS_DEBUG_CONFIG \ + (HFI_PROPERTY_SYS_COMMON_START + 0x001) +#define HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO \ + (HFI_PROPERTY_SYS_COMMON_START + 0x002) +#define HFI_PROPERTY_SYS_CONFIG_VCODEC_CLKFREQ \ + (HFI_PROPERTY_SYS_COMMON_START + 0x003) +#define HFI_PROPERTY_SYS_IDLE_INDICATOR \ + (HFI_PROPERTY_SYS_COMMON_START + 0x004) +#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL \ + (HFI_PROPERTY_SYS_COMMON_START + 0x005) +#define HFI_PROPERTY_SYS_IMAGE_VERSION \ + (HFI_PROPERTY_SYS_COMMON_START + 0x006) +#define HFI_PROPERTY_SYS_CONFIG_COVERAGE \ + (HFI_PROPERTY_SYS_COMMON_START + 0x007) +#define HFI_PROPERTY_SYS_UBWC_CONFIG \ + (HFI_PROPERTY_SYS_COMMON_START + 0x008) + +#define HFI_PROPERTY_PARAM_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000) +#define HFI_PROPERTY_PARAM_FRAME_SIZE \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x002) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x003) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x004) +#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x005) +#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x006) +#define HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x007) +#define HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x008) +#define HFI_PROPERTY_PARAM_CODEC_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x009) +#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00A) +#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00B) +#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00C) +#define HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00E) +#define HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x010) +#define HFI_PROPERTY_PARAM_SECURE_SESSION \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x011) +#define HFI_PROPERTY_PARAM_WORK_MODE \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x015) +#define HFI_PROPERTY_TME_VERSION_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x016) +#define HFI_PROPERTY_PARAM_WORK_ROUTE \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x017) + +#define HFI_PROPERTY_CONFIG_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000) +#define HFI_PROPERTY_CONFIG_FRAME_RATE \ + (HFI_PROPERTY_CONFIG_COMMON_START + 0x001) +#define HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE \ + (HFI_PROPERTY_CONFIG_COMMON_START + 0x002) +#define HFI_PROPERTY_CONFIG_OPERATING_RATE \ + (HFI_PROPERTY_CONFIG_COMMON_START + 0x003) + +#define HFI_PROPERTY_PARAM_VDEC_COMMON_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000) +#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x002) +#define HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x007) +#define HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x009) +#define HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00A) + + +#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000) + +#define HFI_PROPERTY_PARAM_VENC_COMMON_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x5000) +#define HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x002) +#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003) +#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004) +#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009) +#define HFI_PROPERTY_PARAM_VENC_OPEN_GOP \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00C) +#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00D) +#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00E) +#define HFI_PROPERTY_PARAM_VENC_VBV_HRD_BUF_SIZE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00F) +#define HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010) +#define HFI_PROPERTY_PARAM_VENC_H264_SPS_ID \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014) +#define HFI_PROPERTY_PARAM_VENC_H264_PPS_ID \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x015) +#define HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x016) +#define HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x017) +#define HFI_PROPERTY_PARAM_VENC_NUMREF \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018) +#define HFI_PROPERTY_PARAM_VENC_LTRMODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01C) +#define HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01D) +#define HFI_PROPERTY_PARAM_VENC_VUI_TIMING_INFO \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E) +#define HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x022) +#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x023) +#define HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x025) +#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026) +#define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x027) +#define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029) +#define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02C) +#define HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02F) +#define HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x031) +#define HFI_PROPERTY_PARAM_VENC_IFRAMESIZE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x034) +#define HFI_PROPERTY_PARAM_VENC_SEND_OUTPUT_FOR_SKIPPED_FRAMES \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x035) +#define HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x036) +#define HFI_PROPERTY_PARAM_VENC_ADAPTIVE_B \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x037) +#define HFI_PROPERTY_PARAM_VENC_BITRATE_SAVINGS \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x038) +#define HFI_PROPERTY_PARAM_VENC_LOSSLESS_ENCODING \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x039) +#define HFI_PROPERTY_PARAM_HEVC_PPS_CB_CR_OFFSET \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x040) + +#define HFI_PROPERTY_CONFIG_VENC_COMMON_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000) +#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x001) +#define HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x002) +#define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003) +#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004) +#define HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005) +#define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008) +#define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009) +#define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00A) +#define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00B) +#define HFI_PROPERTY_CONFIG_VENC_VBV_HRD_BUF_SIZE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00D) +#define HFI_PROPERTY_CONFIG_VENC_PERF_MODE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00E) +#define HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00F) +#define HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x010) +#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x012) +#define HFI_PROPERTY_CONFIG_HEIC_FRAME_CROP_INFO \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x013) +#define HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x014) +#define HFI_PROPERTY_CONFIG_HEIC_GRID_ENABLE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x015) +#define HFI_PROPERTY_CONFIG_CVP_SKIP_RATIO \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x016) + +#define HFI_PROPERTY_PARAM_VPE_COMMON_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000) +#define HFI_PROPERTY_PARAM_VPE_ROTATION \ + (HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION \ + (HFI_PROPERTY_PARAM_VPE_COMMON_START + 0x002) + +#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000) + +#define HFI_PROPERTY_CONFIG_VPE_FLIP \ + (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x001) + +struct hfi_cvp_skip_ratio { + u32 cvp_skip_ratio; +}; + +struct hfi_pic_struct { + u32 progressive_only; +}; + +struct hfi_bitrate { + u32 bit_rate; + u32 layer_id; +}; + +struct hfi_colour_space { + u32 colour_space; +}; + +#define HFI_CAPABILITY_FRAME_WIDTH (HFI_COMMON_BASE + 0x1) +#define HFI_CAPABILITY_FRAME_HEIGHT (HFI_COMMON_BASE + 0x2) +#define HFI_CAPABILITY_MBS_PER_FRAME (HFI_COMMON_BASE + 0x3) +#define HFI_CAPABILITY_MBS_PER_SECOND (HFI_COMMON_BASE + 0x4) +#define HFI_CAPABILITY_FRAMERATE (HFI_COMMON_BASE + 0x5) +#define HFI_CAPABILITY_SCALE_X (HFI_COMMON_BASE + 0x6) +#define HFI_CAPABILITY_SCALE_Y (HFI_COMMON_BASE + 0x7) +#define HFI_CAPABILITY_BITRATE (HFI_COMMON_BASE + 0x8) +#define HFI_CAPABILITY_BFRAME (HFI_COMMON_BASE + 0x9) +#define HFI_CAPABILITY_PEAKBITRATE (HFI_COMMON_BASE + 0xa) +#define HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x10) +#define HFI_CAPABILITY_ENC_LTR_COUNT (HFI_COMMON_BASE + 0x11) +#define HFI_CAPABILITY_CP_OUTPUT2_THRESH (HFI_COMMON_BASE + 0x12) +#define HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x13) +#define HFI_CAPABILITY_LCU_SIZE (HFI_COMMON_BASE + 0x14) +#define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x15) +#define HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE (HFI_COMMON_BASE + 0x16) +#define HFI_CAPABILITY_EXTRADATA (HFI_COMMON_BASE + 0X17) +#define HFI_CAPABILITY_PROFILE (HFI_COMMON_BASE + 0X18) +#define HFI_CAPABILITY_LEVEL (HFI_COMMON_BASE + 0X19) +#define HFI_CAPABILITY_I_FRAME_QP (HFI_COMMON_BASE + 0X20) +#define HFI_CAPABILITY_P_FRAME_QP (HFI_COMMON_BASE + 0X21) +#define HFI_CAPABILITY_B_FRAME_QP (HFI_COMMON_BASE + 0X22) +#define HFI_CAPABILITY_RATE_CONTROL_MODES (HFI_COMMON_BASE + 0X23) +#define HFI_CAPABILITY_BLUR_WIDTH (HFI_COMMON_BASE + 0X24) +#define HFI_CAPABILITY_BLUR_HEIGHT (HFI_COMMON_BASE + 0X25) +#define HFI_CAPABILITY_SLICE_DELIVERY_MODES (HFI_COMMON_BASE + 0X26) +#define HFI_CAPABILITY_SLICE_BYTE (HFI_COMMON_BASE + 0X27) +#define HFI_CAPABILITY_SLICE_MB (HFI_COMMON_BASE + 0X28) +#define HFI_CAPABILITY_SECURE (HFI_COMMON_BASE + 0X29) +#define HFI_CAPABILITY_MAX_NUM_B_FRAMES (HFI_COMMON_BASE + 0X2A) +#define HFI_CAPABILITY_MAX_VIDEOCORES (HFI_COMMON_BASE + 0X2B) +#define HFI_CAPABILITY_MAX_WORKMODES (HFI_COMMON_BASE + 0X2C) +#define HFI_CAPABILITY_UBWC_CR_STATS (HFI_COMMON_BASE + 0X2D) +#define HFI_CAPABILITY_MAX_WORKROUTES (HFI_COMMON_BASE + 0X31) +#define HFI_CAPABILITY_CQ_QUALITY_LEVEL (HFI_COMMON_BASE + 0X32) + + +#define HFI_DEBUG_MSG_LOW 0x00000001 +#define HFI_DEBUG_MSG_MEDIUM 0x00000002 +#define HFI_DEBUG_MSG_HIGH 0x00000004 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +#define HFI_DEBUG_MSG_PERF 0x00000020 + +#define HFI_DEBUG_MODE_QUEUE 0x00000001 +#define HFI_DEBUG_MODE_QDSS 0x00000002 + +struct hfi_debug_config { + u32 debug_config; + u32 debug_mode; +}; + +struct hfi_enable { + u32 enable; +}; + +#define HFI_H264_DB_MODE_DISABLE (HFI_COMMON_BASE + 0x1) +#define HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY \ + (HFI_COMMON_BASE + 0x2) +#define HFI_H264_DB_MODE_ALL_BOUNDARY (HFI_COMMON_BASE + 0x3) + +struct hfi_h264_db_control { + u32 mode; + u32 slice_alpha_offset; + u32 slice_beta_offset; +}; + +#define HFI_H264_ENTROPY_CAVLC (HFI_COMMON_BASE + 0x1) +#define HFI_H264_ENTROPY_CABAC (HFI_COMMON_BASE + 0x2) + +#define HFI_H264_CABAC_MODEL_0 (HFI_COMMON_BASE + 0x1) +#define HFI_H264_CABAC_MODEL_1 (HFI_COMMON_BASE + 0x2) +#define HFI_H264_CABAC_MODEL_2 (HFI_COMMON_BASE + 0x3) + +struct hfi_h264_entropy_control { + u32 entropy_mode; + u32 cabac_model; +}; + +struct hfi_frame_rate { + u32 buffer_type; + u32 frame_rate; +}; + +struct hfi_heic_frame_quality { + u32 frame_quality; + u32 reserved[3]; +}; + +struct hfi_heic_grid_enable { + u32 grid_enable; +}; + +struct hfi_operating_rate { + u32 operating_rate; +}; + +struct hfi_chroma_qp_offset { + u32 chroma_offset; + u32 reserved; +}; + +#define HFI_INTRA_REFRESH_NONE (HFI_COMMON_BASE + 0x1) +#define HFI_INTRA_REFRESH_CYCLIC (HFI_COMMON_BASE + 0x2) +#define HFI_INTRA_REFRESH_RANDOM (HFI_COMMON_BASE + 0x5) + +struct hfi_intra_refresh { + u32 mode; + u32 mbs; +}; + +struct hfi_idr_period { + u32 idr_period; +}; + +struct hfi_vpe_rotation_type { + u32 rotation; + u32 flip; +}; + +struct hfi_conceal_color { + u32 conceal_color_8bit; + u32 conceal_color_10bit; +}; + +struct hfi_intra_period { + u32 pframes; + u32 bframes; +}; + +struct hfi_multi_stream { + u32 buffer_type; + u32 enable; +}; + +#define HFI_MULTI_SLICE_OFF (HFI_COMMON_BASE + 0x1) +#define HFI_MULTI_SLICE_BY_MB_COUNT (HFI_COMMON_BASE + 0x2) +#define HFI_MULTI_SLICE_BY_BYTE_COUNT (HFI_COMMON_BASE + 0x3) + +struct hfi_multi_slice_control { + u32 multi_slice; + u32 slice_size; +}; + +#define HFI_NAL_FORMAT_STARTCODES 0x00000001 +#define HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER 0x00000002 +#define HFI_NAL_FORMAT_ONE_BYTE_LENGTH 0x00000004 +#define HFI_NAL_FORMAT_TWO_BYTE_LENGTH 0x00000008 +#define HFI_NAL_FORMAT_FOUR_BYTE_LENGTH 0x00000010 + +struct hfi_nal_stream_format_supported { + u32 nal_stream_format_supported; +}; + +struct hfi_nal_stream_format_select { + u32 nal_stream_format_select; +}; +#define HFI_PICTURE_TYPE_I 0x01 +#define HFI_PICTURE_TYPE_P 0x02 +#define HFI_PICTURE_TYPE_B 0x04 +#define HFI_PICTURE_TYPE_IDR 0x08 +#define HFI_PICTURE_TYPE_CRA 0x10 +#define HFI_FRAME_NOTCODED 0x7F002000 +#define HFI_FRAME_YUV 0x7F004000 +#define HFI_UNUSED_PICT 0x10000000 + +struct hfi_profile_level { + u32 profile; + u32 level; +}; + +struct hfi_dpb_counts { + u32 max_dpb_count; + u32 max_ref_frames; + u32 max_dec_buffering; + u32 max_reorder_frames; + u32 fw_min_cnt; +}; + +struct hfi_profile_level_supported { + u32 profile_count; + struct hfi_profile_level rg_profile_level[1]; +}; + +struct hfi_quality_vs_speed { + u32 quality_vs_speed; +}; + +struct hfi_quantization { + u32 qp_packed; + u32 layer_id; + u32 enable; + u32 reserved[3]; +}; + +struct hfi_quantization_range { + struct hfi_quantization min_qp; + struct hfi_quantization max_qp; + u32 reserved[4]; +}; + +#define HFI_LTR_MODE_DISABLE 0x0 +#define HFI_LTR_MODE_MANUAL 0x1 + +struct hfi_ltr_mode { + u32 ltr_mode; + u32 ltr_count; + u32 trust_mode; +}; + +struct hfi_ltr_use { + u32 ref_ltr; + u32 use_constrnt; + u32 frames; +}; + +struct hfi_ltr_mark { + u32 mark_frame; +}; + +struct hfi_frame_size { + u32 buffer_type; + u32 width; + u32 height; +}; + +struct hfi_videocores_usage_type { + u32 video_core_enable_mask; +}; + +struct hfi_video_work_mode { + u32 video_work_mode; +}; + +struct hfi_video_work_route { + u32 video_work_route; +}; + +struct hfi_video_signal_metadata { + u32 enable; + u32 video_format; + u32 video_full_range; + u32 color_description; + u32 color_primaries; + u32 transfer_characteristics; + u32 matrix_coeffs; +}; + +struct hfi_vui_timing_info { + u32 enable; + u32 fixed_frame_rate; + u32 time_scale; +}; + +struct hfi_bit_depth { + u32 buffer_type; + u32 bit_depth; +}; + +/* Base Offset for UBWC color formats */ +#define HFI_COLOR_FORMAT_UBWC_BASE (0x8000) +/* Base Offset for 10-bit color formats */ +#define HFI_COLOR_FORMAT_10_BIT_BASE (0x4000) + +#define HFI_COLOR_FORMAT_NV12 (HFI_COMMON_BASE + 0x2) +#define HFI_COLOR_FORMAT_NV21 (HFI_COMMON_BASE + 0x3) +#define HFI_COLOR_FORMAT_RGBA8888 (HFI_COMMON_BASE + 0x10) + +#define HFI_COLOR_FORMAT_YUV420_TP10 \ + (HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12) +#define HFI_COLOR_FORMAT_P010 \ + (HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12 + 0x1) + +#define HFI_COLOR_FORMAT_NV12_UBWC \ + (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_NV12) + +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC \ + (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_YUV420_TP10) + +#define HFI_COLOR_FORMAT_RGBA8888_UBWC \ + (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_RGBA8888) + +#define HFI_MAX_MATRIX_COEFFS 9 +#define HFI_MAX_BIAS_COEFFS 3 +#define HFI_MAX_LIMIT_COEFFS 6 + +struct hfi_uncompressed_format_select { + u32 buffer_type; + u32 format; +}; + +struct hfi_uncompressed_format_supported { + u32 buffer_type; + u32 format_entries; + u32 rg_format_info[1]; +}; + +struct hfi_uncompressed_plane_actual { + u32 actual_stride; + u32 actual_plane_buffer_height; +}; + +struct hfi_uncompressed_plane_actual_info { + u32 buffer_type; + u32 num_planes; + struct hfi_uncompressed_plane_actual rg_plane_format[1]; +}; + +struct hfi_uncompressed_plane_constraints { + u32 stride_multiples; + u32 max_stride; + u32 min_plane_buffer_height_multiple; + u32 buffer_alignment; +}; + +struct hfi_uncompressed_plane_info { + u32 format; + u32 num_planes; + struct hfi_uncompressed_plane_constraints rg_plane_format[1]; +}; + +struct hfi_vpe_color_space_conversion { + u32 input_color_primaries; + u32 custom_matrix_enabled; + u32 csc_matrix[HFI_MAX_MATRIX_COEFFS]; + u32 csc_bias[HFI_MAX_BIAS_COEFFS]; + u32 csc_limit[HFI_MAX_LIMIT_COEFFS]; +}; + +#define HFI_ROTATE_NONE (HFI_COMMON_BASE + 0x1) +#define HFI_ROTATE_90 (HFI_COMMON_BASE + 0x2) +#define HFI_ROTATE_180 (HFI_COMMON_BASE + 0x3) +#define HFI_ROTATE_270 (HFI_COMMON_BASE + 0x4) + +#define HFI_FLIP_NONE (HFI_COMMON_BASE + 0x1) +#define HFI_FLIP_HORIZONTAL (HFI_COMMON_BASE + 0x2) +#define HFI_FLIP_VERTICAL (HFI_COMMON_BASE + 0x4) + +#define HFI_RESOURCE_SYSCACHE 0x00000002 + +struct hfi_resource_subcache_type { + u32 size; + u32 sc_id; +}; + +struct hfi_resource_syscache_info_type { + u32 num_entries; + struct hfi_resource_subcache_type rg_subcache_entries[1]; +}; + +struct hfi_property_sys_image_version_info_type { + u32 string_size; + u8 str_image_version[1]; +}; + +struct hfi_vbv_hrd_bufsize { + u32 buffer_size; +}; + +struct hfi_codec_mask_supported { + u32 codecs; + u32 video_domains; +}; + +struct hfi_aspect_ratio { + u32 aspect_width; + u32 aspect_height; +}; + +#define HFI_CMD_SYS_COMMON_START \ +(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \ + + 0x0000) +#define HFI_CMD_SYS_INIT (HFI_CMD_SYS_COMMON_START + 0x001) +#define HFI_CMD_SYS_PC_PREP (HFI_CMD_SYS_COMMON_START + 0x002) +#define HFI_CMD_SYS_SET_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x003) +#define HFI_CMD_SYS_RELEASE_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x004) +#define HFI_CMD_SYS_SET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x005) +#define HFI_CMD_SYS_GET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x006) +#define HFI_CMD_SYS_SESSION_INIT (HFI_CMD_SYS_COMMON_START + 0x007) +#define HFI_CMD_SYS_SESSION_END (HFI_CMD_SYS_COMMON_START + 0x008) +#define HFI_CMD_SYS_SET_BUFFERS (HFI_CMD_SYS_COMMON_START + 0x009) +#define HFI_CMD_SYS_TEST_START (HFI_CMD_SYS_COMMON_START + 0x100) + +#define HFI_CMD_SESSION_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \ + HFI_CMD_START_OFFSET + 0x1000) +#define HFI_CMD_SESSION_SET_PROPERTY \ + (HFI_CMD_SESSION_COMMON_START + 0x001) +#define HFI_CMD_SESSION_SET_BUFFERS \ + (HFI_CMD_SESSION_COMMON_START + 0x002) +#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER \ + (HFI_CMD_SESSION_COMMON_START + 0x003) + +#define HFI_MSG_SYS_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \ + HFI_MSG_START_OFFSET + 0x0000) +#define HFI_MSG_SYS_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x1) +#define HFI_MSG_SYS_PC_PREP_DONE (HFI_MSG_SYS_COMMON_START + 0x2) +#define HFI_MSG_SYS_RELEASE_RESOURCE (HFI_MSG_SYS_COMMON_START + 0x3) +#define HFI_MSG_SYS_DEBUG (HFI_MSG_SYS_COMMON_START + 0x4) +#define HFI_MSG_SYS_SESSION_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x6) +#define HFI_MSG_SYS_SESSION_END_DONE (HFI_MSG_SYS_COMMON_START + 0x7) +#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_COMMON_START + 0x8) +#define HFI_MSG_SYS_COV (HFI_MSG_SYS_COMMON_START + 0x9) +#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_COMMON_START + 0xA) +#define HFI_MSG_SESSION_SYNC_DONE (HFI_MSG_SESSION_OX_START + 0xD) + +#define HFI_MSG_SESSION_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + \ + HFI_MSG_START_OFFSET + 0x1000) +#define HFI_MSG_EVENT_NOTIFY (HFI_MSG_SESSION_COMMON_START + 0x1) +#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE \ + (HFI_MSG_SESSION_COMMON_START + 0x2) + +#define HFI_CMD_SYS_TEST_SSR (HFI_CMD_SYS_TEST_START + 0x1) +#define HFI_TEST_SSR_SW_ERR_FATAL 0x1 +#define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2 +#define HFI_TEST_SSR_HW_WDOG_IRQ 0x3 + +struct vidc_hal_cmd_pkt_hdr { + u32 size; + u32 packet_type; +}; + +struct vidc_hal_msg_pkt_hdr { + u32 size; + u32 packet; +}; + +struct vidc_hal_session_cmd_pkt { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_packet_header { + u32 size; + u32 packet_type; +}; + +struct hfi_cmd_sys_init_packet { + u32 size; + u32 packet_type; + u32 arch_type; +}; + +struct hfi_cmd_sys_pc_prep_packet { + u32 size; + u32 packet_type; +}; + +struct hfi_cmd_sys_set_resource_packet { + u32 size; + u32 packet_type; + u32 resource_handle; + u32 resource_type; + u32 rg_resource_data[1]; +}; + +struct hfi_cmd_sys_release_resource_packet { + u32 size; + u32 packet_type; + u32 resource_type; + u32 resource_handle; +}; + +struct hfi_cmd_sys_set_property_packet { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_sys_get_property_packet { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_sys_session_init_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 session_domain; + u32 session_codec; +}; + +struct hfi_cmd_sys_session_end_packet { + u32 size; + u32 packet_type; + u32 sid; +}; + +struct hfi_cmd_sys_set_buffers_packet { + u32 size; + u32 packet_type; + u32 buffer_type; + u32 buffer_size; + u32 num_buffers; + u32 rg_buffer_addr[1]; +}; + +struct hfi_cmd_sys_set_ubwc_config_packet_type { + u32 size; + u32 packet_type; + struct { + u32 max_channel_override : 1; + u32 mal_length_override : 1; + u32 hb_override : 1; + u32 bank_swzl_level_override : 1; + u32 bank_spreading_override : 1; + u32 reserved : 27; + } override_bit_info; + u32 max_channels; + u32 mal_length; + u32 highest_bank_bit; + u32 bank_swzl_level; + u32 bank_spreading; + u32 reserved[2]; +}; + +struct hfi_cmd_session_set_property_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_session_set_buffers_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 buffer_type; + u32 buffer_size; + u32 extra_data_size; + u32 min_buffer_size; + u32 num_buffers; + u32 rg_buffer_info[1]; +}; + +struct hfi_buffer_mapping_type { + u32 index; + u32 device_addr; + u32 size; +}; + +struct hfi_cmd_session_register_buffers_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 client_data; + u32 response_req; + u32 num_buffers; + struct hfi_buffer_mapping_type buffer[1]; +}; + +struct hfi_cmd_session_unregister_buffers_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 client_data; + u32 response_req; + u32 num_buffers; + struct hfi_buffer_mapping_type buffer[1]; +}; + +struct hfi_cmd_session_sync_process_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 sync_id; + u32 rg_data[1]; +}; + +struct hfi_msg_event_notify_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 event_id; + u32 event_data1; + u32 event_data2; + u32 rg_ext_event_data[1]; +}; + +struct hfi_msg_release_buffer_ref_event_packet { + u32 packet_buffer; + u32 extra_data_buffer; + u32 output_tag; +}; + +struct hfi_msg_sys_init_done_packet { + u32 size; + u32 packet_type; + u32 error_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_sys_pc_prep_done_packet { + u32 size; + u32 packet_type; + u32 error_type; +}; + +struct hfi_msg_sys_release_resource_done_packet { + u32 size; + u32 packet_type; + u32 resource_handle; + u32 error_type; +}; + +struct hfi_msg_sys_session_init_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_sys_session_end_done_packet { + u32 size; + u32 packet_type; + u32 sid; + u32 error_type; +}; + +struct hfi_msg_sys_debug_packet { + u32 size; + u32 packet_type; + u32 msg_type; + u32 msg_size; + u32 time_stamp_hi; + u32 time_stamp_lo; + u8 rg_msg_data[1]; +}; + +struct hfi_msg_sys_coverage_packet { + u32 size; + u32 packet_type; + u32 msg_size; + u32 time_stamp_hi; + u32 time_stamp_lo; + u8 rg_msg_data[1]; +}; + +enum HFI_VENUS_QTBL_STATUS { + HFI_VENUS_QTBL_DISABLED = 0x00, + HFI_VENUS_QTBL_ENABLED = 0x01, + HFI_VENUS_QTBL_INITIALIZING = 0x02, + HFI_VENUS_QTBL_DEINITIALIZING = 0x03 +}; + +enum HFI_VENUS_CTRL_INIT_STATUS { + HFI_VENUS_CTRL_NOT_INIT = 0x0, + HFI_VENUS_CTRL_READY = 0x1, + HFI_VENUS_CTRL_ERROR_FATAL = 0x2 +}; + +struct hfi_sfr_struct { + u32 bufSize; + u8 rg_data[1]; +}; + +struct hfi_cmd_sys_test_ssr_packet { + u32 size; + u32 packet_type; + u32 trigger_type; +}; + +struct hfi_hdr10_pq_sei { + struct msm_vidc_mastering_display_colour_sei_payload mdisp_info; + struct msm_vidc_content_light_level_sei_payload cll_info; +}; + +struct hfi_vbv_hrd_buf_size { + u32 vbv_hrd_buf_size; +}; + +#endif